diff -rNu linux-2.4.7/CVS/Entries linux-2.4-xfs/CVS/Entries --- linux-2.4.7/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/CVS/Entries Thu Jul 5 11:43:36 2001 @@ -0,0 +1 @@ +D diff -rNu linux-2.4.7/CVS/Entries.Log linux-2.4-xfs/CVS/Entries.Log --- linux-2.4.7/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/CVS/Entries.Log Thu Jul 5 11:46:04 2001 @@ -0,0 +1,2 @@ +A D/cmd//// +A D/linux//// diff -rNu linux-2.4.7/CVS/Repository linux-2.4-xfs/CVS/Repository --- linux-2.4.7/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/CVS/Repository Thu Jul 5 11:43:36 2001 @@ -0,0 +1 @@ +linux-2.4-xfs diff -rNu linux-2.4.7/CVS/Root linux-2.4-xfs/CVS/Root --- linux-2.4.7/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/CVS/Root Thu Jul 5 11:43:36 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/CVS/Entries linux-2.4-xfs/cmd/CVS/Entries --- linux-2.4.7/cmd/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/CVS/Entries Thu Jul 5 11:43:37 2001 @@ -0,0 +1 @@ +D diff -rNu linux-2.4.7/cmd/CVS/Entries.Log linux-2.4-xfs/cmd/CVS/Entries.Log --- linux-2.4.7/cmd/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/CVS/Entries.Log Thu Jul 5 11:44:59 2001 @@ -0,0 +1,7 @@ +A D/acl//// +A D/attr//// +A D/dmapi//// +A D/xfsdump//// +A D/xfsmisc//// +A D/xfsprogs//// +A D/xfstests//// diff -rNu linux-2.4.7/cmd/CVS/Repository linux-2.4-xfs/cmd/CVS/Repository --- linux-2.4.7/cmd/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/CVS/Repository Thu Jul 5 11:43:37 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd diff -rNu linux-2.4.7/cmd/CVS/Root linux-2.4-xfs/cmd/CVS/Root --- linux-2.4.7/cmd/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/CVS/Root Thu Jul 5 11:43:37 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/acl/CVS/Entries linux-2.4-xfs/cmd/acl/CVS/Entries --- linux-2.4.7/cmd/acl/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/CVS/Entries Thu Jul 5 11:43:37 2001 @@ -0,0 +1,7 @@ +/Makefile/1.1/Mon Jan 15 10:28:46 2001/-ko/ +/Makepkgs/1.2/Thu Mar 29 06:30:35 2001/-ko/ +/README/1.1/Mon Jan 15 10:28:46 2001/-ko/ +/VERSION/1.9/Mon Jul 2 03:31:14 2001/-ko/ +/configure.in/1.5/Wed Jun 13 01:49:41 2001/-ko/ +/install-sh/1.1/Mon Jan 15 10:28:46 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/acl/CVS/Entries.Log linux-2.4-xfs/cmd/acl/CVS/Entries.Log --- linux-2.4.7/cmd/acl/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/CVS/Entries.Log Thu Jul 5 11:43:40 2001 @@ -0,0 +1,7 @@ +A D/build//// +A D/chacl//// +A D/debian//// +A D/doc//// +A D/include//// +A D/libacl//// +A D/man//// diff -rNu linux-2.4.7/cmd/acl/CVS/Repository linux-2.4-xfs/cmd/acl/CVS/Repository --- linux-2.4.7/cmd/acl/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/CVS/Repository Thu Jul 5 11:43:37 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/acl diff -rNu linux-2.4.7/cmd/acl/CVS/Root linux-2.4-xfs/cmd/acl/CVS/Root --- linux-2.4.7/cmd/acl/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/CVS/Root Thu Jul 5 11:43:37 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/acl/Makefile linux-2.4-xfs/cmd/acl/Makefile --- linux-2.4.7/cmd/acl/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/Makefile Mon Jan 15 04:28:46 2001 @@ -0,0 +1,73 @@ +# +# Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = . +HAVE_BUILDDEFS = $(shell test -f $(TOPDIR)/include/builddefs && echo yes || echo no) + +ifeq ($(HAVE_BUILDDEFS), yes) +include $(TOPDIR)/include/builddefs +endif + +LSRCFILES = configure configure.in Makepkgs install-sh README VERSION +LDIRT = config.* conftest* Logs/* built install.* install-dev.* *.gz + +SUBDIRS = include libacl chacl man doc debian build + +default: configure +ifeq ($(HAVE_BUILDDEFS), no) + $(MAKE) -C . $@ +else + $(SUBDIRS_MAKERULE) +endif + +ifeq ($(HAVE_BUILDDEFS), yes) +include $(BUILDRULES) +else +clean: # if configure hasn't run, nothing to clean +endif + +configure: configure.in include/builddefs.in VERSION + rm -f config.cache + autoconf + ./configure + +install: default + $(SUBDIRS_MAKERULE) + $(INSTALL) -m 755 -d $(PKG_DOC_DIR) + $(INSTALL) -m 644 README $(PKG_DOC_DIR) + +install-dev: default + $(SUBDIRS_MAKERULE) + +realclean distclean: clean + rm -f $(LDIRT) configure include/builddefs + [ ! -d Logs ] || rmdir Logs diff -rNu linux-2.4.7/cmd/acl/Makepkgs linux-2.4-xfs/cmd/acl/Makepkgs --- linux-2.4.7/cmd/acl/Makepkgs Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/Makepkgs Thu Mar 29 00:30:35 2001 @@ -0,0 +1,109 @@ +#! /bin/sh +# +# Make whichever packages have been requested. +# Defaults to RPMs. +# +LOGDIR=Logs + +type=rpm +verbose=false + +MAKE=${MAKE:-make} +test ! -z "$MAKE" && make=$MAKE + +for opt in $* +do + case "$opt" in + clean) + ;; # ignored, kept for backward compatibility + rpm) + type=rpm ;; + debian) + type=debian ;; + verbose) + verbose=true ;; + *) + echo "Usage: Makepkgs [verbose] [debian|rpm]"; exit 1 ;; + esac +done + +# start with a clean manifest +test -f files.rpm && rm -f files.rpm +test -f filesdevel.rpm && rm -f filesdevel.rpm + +test ! -d $LOGDIR && mkdir $LOGDIR +rm -rf $LOGDIR/* > /dev/null 2>&1 + +# build Debian packages, cleans itself before starting +SUDO=${SUDO:-sudo} +test ! -z "$SUDO" && sudo=$SUDO +if [ $type = debian ] ; then + LOGDEB=`pwd` + LOGDEB=../`basename $LOGDEB`.log + echo "== Debian build, log is $LOGDEB"; echo + if $verbose ; then + dpkg-buildpackage -r$SUDO | tee $LOGDEB + else + dpkg-buildpackage -r$SUDO > $LOGDEB + fi + exit 0 +fi + +# build RPM packages - manual clean before starting +echo "== clean, log is $LOGDIR/clean" +if $verbose ; then + $MAKE clean 2>&1 | tee $LOGDIR/clean +else + $MAKE clean > $LOGDIR/clean 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"$MAKE clean\" failed, see log in $LOGDIR/clean + tail $LOGDIR/clean + exit 1 +fi + +echo +echo "== configure, log is $LOGDIR/configure" +if $verbose ; then + autoconf 2>&1 | tee $LOGDIR/configure + ./configure 2>&1 | tee -a $LOGDIR/configure +else + autoconf > $LOGDIR/configure 2>&1 + ./configure >> $LOGDIR/configure 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"configure\" failed, see log in $LOGDIR/configure + tail $LOGDIR/configure + exit 1 +fi + +echo +echo "== default, log is $LOGDIR/default" +if $verbose ; then + $MAKE default 2>&1 | tee $LOGDIR/default +else + $MAKE default > $LOGDIR/default 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"$MAKE default\" failed, see log in $LOGDIR/default + tail $LOGDIR/default + exit 1 +fi + +echo +echo "== dist, log is $LOGDIR/dist" +[ ! -f .census ] && touch .census +if $verbose ; then + $MAKE -C build dist 2>&1 | tee $LOGDIR/dist +else + $MAKE -C build dist > $LOGDIR/dist 2>&1 +fi +if [ $? -ne 0 ] ; then + echo $MAKE dist failed, see log in $LOGDIR/dist + tail $LOGDIR/dist + exit 1 +else + grep '^Wrote:' $LOGDIR/dist | sed -e 's/\.\.\/\.\.\///' +fi + +exit 0 diff -rNu linux-2.4.7/cmd/acl/README linux-2.4-xfs/cmd/acl/README --- linux-2.4.7/cmd/acl/README Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/README Mon Jan 15 04:28:46 2001 @@ -0,0 +1,15 @@ +Access Control List package README +__________________________________ + +See the file doc/INSTALL for build, installation and post- +install configuration steps. + +Refer to the acl(5) manual page for general access control list +(ACL) information and references to other ACL manual pages. + +For more information and details on how to contribute to the +XFS project see the web pages at: + http://oss.sgi.com/projects/xfs/ + +For more information on the build process, please refer to +the doc/PORTING document. diff -rNu linux-2.4.7/cmd/acl/VERSION linux-2.4-xfs/cmd/acl/VERSION --- linux-2.4.7/cmd/acl/VERSION Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/VERSION Sun Jul 1 22:31:14 2001 @@ -0,0 +1,7 @@ +# +# This file is used by configure to get version information +# +PKG_MAJOR=1 +PKG_MINOR=0 +PKG_REVISION=8 +PKG_BUILD=0 diff -rNu linux-2.4.7/cmd/acl/build/CVS/Entries linux-2.4-xfs/cmd/acl/build/CVS/Entries --- linux-2.4.7/cmd/acl/build/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/CVS/Entries Thu Jul 5 11:43:37 2001 @@ -0,0 +1,2 @@ +/Makefile/1.2/Thu Mar 1 01:31:21 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/acl/build/CVS/Entries.Log linux-2.4-xfs/cmd/acl/build/CVS/Entries.Log --- linux-2.4.7/cmd/acl/build/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/CVS/Entries.Log Thu Jul 5 11:43:37 2001 @@ -0,0 +1,2 @@ +A D/rpm//// +A D/tar//// diff -rNu linux-2.4.7/cmd/acl/build/CVS/Repository linux-2.4-xfs/cmd/acl/build/CVS/Repository --- linux-2.4.7/cmd/acl/build/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/CVS/Repository Thu Jul 5 11:43:37 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/acl/build diff -rNu linux-2.4.7/cmd/acl/build/CVS/Root linux-2.4-xfs/cmd/acl/build/CVS/Root --- linux-2.4.7/cmd/acl/build/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/CVS/Root Thu Jul 5 11:43:37 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/acl/build/Makefile linux-2.4-xfs/cmd/acl/build/Makefile --- linux-2.4.7/cmd/acl/build/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/Makefile Wed Feb 28 19:31:21 2001 @@ -0,0 +1,76 @@ +# +# Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +MANIFEST=src-manifest +SRCTAR=$(PKG_NAME)-$(PKG_VERSION).src.tar.gz + +LDIRT = *-manifest *.gz $(TOPDIR)/$(PKG_NAME)-* + +# for clean and clobber +SUBDIRS = tar rpm + +# nothing to build here (it's all packaging) +default install install-dev : + +include $(BUILDRULES) + +# Symlink in the TOPDIR is used to pack files relative to +# product-version directory. +$(MANIFEST) : $(_FORCE) + @if [ ! -L $(TOPDIR)/$(PKG_NAME)-$(PKG_VERSION) ] ; then \ + $(LN_S) . $(TOPDIR)/$(PKG_NAME)-$(PKG_VERSION) ; \ + fi + @CDIR=`pwd`; cd $(TOPDIR); \ + $(MAKE) --no-print-directory source | \ + sed -e 's/^\./$(PKG_NAME)-$(PKG_VERSION)/' > $$CDIR/$@ ;\ + if [ $$? -ne 0 ] ; then \ + exit 1; \ + else \ + unset TAPE; \ + $(TAR) -T $$CDIR/$@ -cf - | $(ZIP) --best > $$CDIR/$(SRCTAR); \ + fi + +dist : default $(MANIFEST) + @DIST_MANIFEST=`pwd`/bin-manifest; DIST_ROOT=/tmp/$$$$; \ + export DIST_MANIFEST DIST_ROOT; \ + rm -f $$DIST_MANIFEST; \ + echo === install === && $(MAKE) -C $(TOPDIR) install || exit $$?; \ + if [ -x $(TAR) ]; then \ + ( echo "=== tar ===" && $(MAKEF) -C tar $@ || exit $$? ); \ + fi; \ + if [ -x $(RPM) ]; then \ + ( echo "=== rpm ===" && $(MAKEF) -C rpm $@ || exit $$? ); \ + fi; \ + test -z "$$KEEP_DIST_ROOT" || rm -rf $$DIST_ROOT; echo Done diff -rNu linux-2.4.7/cmd/acl/build/rpm/CVS/Entries linux-2.4-xfs/cmd/acl/build/rpm/CVS/Entries --- linux-2.4.7/cmd/acl/build/rpm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/rpm/CVS/Entries Thu Jul 5 11:43:37 2001 @@ -0,0 +1,5 @@ +/Makefile/1.3/Tue Mar 20 19:36:13 2001/-ko/ +/acl.spec.in/1.2/Tue Jan 30 05:42:55 2001/-ko/ +/macros.template/1.1/Mon Jan 15 10:28:46 2001/-ko/ +/rpm-2.rc.template/1.1/Mon Jan 15 10:28:46 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/acl/build/rpm/CVS/Repository linux-2.4-xfs/cmd/acl/build/rpm/CVS/Repository --- linux-2.4.7/cmd/acl/build/rpm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/rpm/CVS/Repository Thu Jul 5 11:43:37 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/acl/build/rpm diff -rNu linux-2.4.7/cmd/acl/build/rpm/CVS/Root linux-2.4-xfs/cmd/acl/build/rpm/CVS/Root --- linux-2.4.7/cmd/acl/build/rpm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/rpm/CVS/Root Thu Jul 5 11:43:37 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/acl/build/rpm/Makefile linux-2.4-xfs/cmd/acl/build/rpm/Makefile --- linux-2.4.7/cmd/acl/build/rpm/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/rpm/Makefile Tue Mar 20 13:36:13 2001 @@ -0,0 +1,78 @@ +# +# Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +TREEROOT = $(shell cd ${TOPDIR}; pwd) +include $(TOPDIR)/include/builddefs + +SPECF = $(PKG_NAME).spec +LDIRT = $(PKG_NAME)*.rpm $(SPECF) rpmmacros rpm-*.rc $(TOPDIR)/files*.rpm + +LSRCFILES = macros.template $(SPECF).in rpm-2.rc.template + +default install install-dev : + +include $(BUILDRULES) + +# generate a binary rpm file +dist : default $(SPECF) rpm-$(RPM_VERSION).rc + $(RPM) -ba --rcfile ./rpm-$(RPM_VERSION).rc $(SPECF) + +# Because rpm prior to v.2.90 does not support macros and old style config +# is not supported by rpm v.3, we have to resort to such ugly hacks +ifneq ($RPM_VERSION,2) +rpm-$(RPM_VERSION).rc : rpmmacros + sed -e '/^macrofiles:/s|~/.rpmmacros|rpmmacros|' $@ + +rpmmacros : macros.template + @sed -e 's|%topdir%|$(TREEROOT)|g' < $< > $@ +else +rpm-2.rc: rpm-2.rc.template + @sed -e 's|%topdir%|$(TOPDIR)|g' < $< > $@ +endif + +.PHONY: $(SPECF) +${SPECF} : ${SPECF}.in + sed -e's|@pkg_name@|$(PKG_NAME)|g' \ + -e's|@pkg_version@|$(PKG_VERSION)|g' \ + -e's|@pkg_release@|$(PKG_RELEASE)|g' \ + -e's|@pkg_distribution@|$(PKG_DISTRIBUTION)|g' \ + -e's|@pkg_builder@|$(PKG_BUILDER)|g' \ + -e's|@build_root@|$(DIST_ROOT)|g' \ + -e'/^BuildRoot: *$$/d' \ + -e's|@pkg_var_dir@|$(PKG_VAR_DIR)|g' \ + -e's|@pkg_share_dir@|$(PKG_SHARE_DIR)|g' \ + -e's|@pkg_log_dir@|$(PKG_LOG_DIR)|g' \ + -e's|@pkg_doc_dir@|$(PKG_DOC_DIR)|g' \ + -e's|@pkg_man_dir@|$(PKG_MAN_DIR)|g' \ + -e's|@pkg_tmp_dir@|$(PKG_TMP_DIR)|g' \ + -e's|@make@|$(MAKE)|g' < $< > $@ diff -rNu linux-2.4.7/cmd/acl/build/rpm/acl.spec.in linux-2.4-xfs/cmd/acl/build/rpm/acl.spec.in --- linux-2.4.7/cmd/acl/build/rpm/acl.spec.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/rpm/acl.spec.in Mon Jan 29 23:42:55 2001 @@ -0,0 +1,86 @@ +Summary: Command for manipulating access control lists +Name: @pkg_name@ +Version: @pkg_version@ +Release: @pkg_release@ +Distribution: @pkg_distribution@ +Packager: @pkg_builder@ +BuildRoot: @build_root@ +Prereq: /sbin/ldconfig +Source: @pkg_name@-@pkg_version@.src.tar.gz +Copyright: Copyright (C) 2000 Silicon Graphics, Inc. +Vendor: Silicon Graphics, Inc. +URL: http://oss.sgi.com/projects/xfs/ +Group: System Environment/Base + +%description +A command (chacl) to manipulate POSIX access control lists +under Linux. + +%package devel +Summary: Access control list static libraries and headers. +Group: Development/Libraries +Requires: @pkg_name@ + +%description devel +acl-devel contains the libraries and header files needed to +develop programs which make use of POSIX access control lists. + +You should install acl-devel if you want to develop programs +which make use of ACLs. If you install acl-devel, you'll +also want to install acl. + +# If .census exists, then no setup is necessary, just go and do the build, +# otherwise run setup +%prep +if [ -f .census ] ; then + if [ ! -d ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION} ] ; then + ln -s . ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION} + fi +else +%setup +touch .census +./configure +fi + +%build +@make@ + +%install +DIST_ROOT="$RPM_BUILD_ROOT" +DIST_INSTALL=`pwd`/install.manifest +DIST_INSTALL_DEV=`pwd`/install-dev.manifest +export DIST_ROOT DIST_INSTALL DIST_INSTALL_DEV +@make@ install DIST_MANIFEST="$DIST_INSTALL" +@make@ install-dev DIST_MANIFEST="$DIST_INSTALL_DEV" +files() +{ + sort | uniq | awk ' +$1 == "d" { printf ("%%%%dir %%%%attr(%s,%s,%s) %s\n", $2, $3, $4, $5); } +$1 == "f" { if (match ($6, "@pkg_man_dir@") || match ($6, "@pkg_doc_dir@")) + printf ("%%%%doc "); + if (match ($6, "@pkg_man_dir@")) + printf ("%%%%attr(%s,%s,%s) %s*\n", $2, $3, $4, $6); + else + printf ("%%%%attr(%s,%s,%s) %s\n", $2, $3, $4, $6); } +$1 == "l" { if (match ($3, "@pkg_man_dir@") || match ($3, "@pkg_doc_dir@")) + printf ("%%%%doc "); + if (match ($3, "@pkg_man_dir@")) + printf ("%attr(0777,root,root) %s*\n", $3); + else + printf ("%attr(0777,root,root) %s\n", $3); }' +} +set +x +files < "$DIST_INSTALL" > files.rpm +files < "$DIST_INSTALL_DEV" > filesdevel.rpm +set -x + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files -f files.rpm + +%files devel -f filesdevel.rpm diff -rNu linux-2.4.7/cmd/acl/build/rpm/macros.template linux-2.4-xfs/cmd/acl/build/rpm/macros.template --- linux-2.4.7/cmd/acl/build/rpm/macros.template Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/rpm/macros.template Mon Jan 15 04:28:46 2001 @@ -0,0 +1,30 @@ +# +# rpmrc.template +# +# Template to fudge rpm directory structure inside IRIX-like build +# environment + +# Force 386 build on all platforms +%_target i386-pc-linux +%_target_cpu i386 +%_target_os linux + +# topdir == $(WORKAREA) +%_topdir %topdir% + +# Following directories are specific to the topdir +# This is where build is done. In our case it's the same as $WORKAREA +%_builddir %topdir% + +# This is where foo.1.99.tar.gz is living in the real world. +# Be careful not to run full rpm build as it will override the sources +%_sourcedir %topdir%/build + +# This is where binary RPM and source RPM would end up +%_rpmdir %topdir%/build/rpm +%_srcrpmdir %topdir%/build/rpm +%_specdir %topdir%/build/rpm + +# Leave RPM files in the same directory - we're not building for +# multiple architectures +%_rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm diff -rNu linux-2.4.7/cmd/acl/build/rpm/rpm-2.rc.template linux-2.4-xfs/cmd/acl/build/rpm/rpm-2.rc.template --- linux-2.4.7/cmd/acl/build/rpm/rpm-2.rc.template Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/rpm/rpm-2.rc.template Mon Jan 15 04:28:46 2001 @@ -0,0 +1,25 @@ +# +# rpmrc.template +# +# Template to fudge rpm directory structure inside IRIX-like build +# environment + +# topdir == $(WORKAREA) +topdir: %topdir% + +# Following directories are specific to the topdir +# This is where build is done. In out case it's the same as $WORKAREA +# Be careful not to run full rpm build as it will override the sources +builddir: %topdir% + +# This is where foo.1.99.tar.gz is living in the real world. +sourcedir: %topdir%/build + +# This is where binary RPM and source RPM would end up +rpmdir: %topdir%/build/rpm +srcrpmdir: %topdir%/build/rpm +specdir: %topdir%/build/rpm + +# Leave RPM files in the same directory - we're not building for +# multiple architectures +rpmfilename: %{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm diff -rNu linux-2.4.7/cmd/acl/build/tar/CVS/Entries linux-2.4-xfs/cmd/acl/build/tar/CVS/Entries --- linux-2.4.7/cmd/acl/build/tar/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/tar/CVS/Entries Thu Jul 5 11:43:37 2001 @@ -0,0 +1,2 @@ +/Makefile/1.2/Thu Mar 1 01:48:49 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/acl/build/tar/CVS/Repository linux-2.4-xfs/cmd/acl/build/tar/CVS/Repository --- linux-2.4.7/cmd/acl/build/tar/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/tar/CVS/Repository Thu Jul 5 11:43:37 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/acl/build/tar diff -rNu linux-2.4.7/cmd/acl/build/tar/CVS/Root linux-2.4-xfs/cmd/acl/build/tar/CVS/Root --- linux-2.4.7/cmd/acl/build/tar/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/tar/CVS/Root Thu Jul 5 11:43:37 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/acl/build/tar/Makefile linux-2.4-xfs/cmd/acl/build/tar/Makefile --- linux-2.4.7/cmd/acl/build/tar/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/build/tar/Makefile Wed Feb 28 19:48:49 2001 @@ -0,0 +1,50 @@ +# +# Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +BINTAR=$(PKG_NAME)-$(PKG_VERSION).tar.gz +LDIRT = *.gz + +default install install-dev : + +include $(BUILDRULES) + +dist : default + @HERE=`pwd`; cd $${DIST_ROOT:-/}; \ + sort $$HERE/../bin-manifest | uniq | $(AWK) ' \ + $$1 == "f" { printf (".%s\n", $$6); } \ + $$1 == "d" { next; } \ + $$1 == "l" { printf (".%s\n", $$3); }' \ + | $(TAR) -T - -cf - | $(ZIP) --best > $$HERE/$(BINTAR) + @echo Wrote: `pwd`/$(BINTAR) diff -rNu linux-2.4.7/cmd/acl/chacl/CVS/Entries linux-2.4-xfs/cmd/acl/chacl/CVS/Entries --- linux-2.4.7/cmd/acl/chacl/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/chacl/CVS/Entries Thu Jul 5 11:43:38 2001 @@ -0,0 +1,3 @@ +/Makefile/1.1/Mon Jan 15 10:28:46 2001/-ko/ +/chacl.c/1.5/Mon Jun 11 20:48:59 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/acl/chacl/CVS/Repository linux-2.4-xfs/cmd/acl/chacl/CVS/Repository --- linux-2.4.7/cmd/acl/chacl/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/chacl/CVS/Repository Thu Jul 5 11:43:37 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/acl/chacl diff -rNu linux-2.4.7/cmd/acl/chacl/CVS/Root linux-2.4-xfs/cmd/acl/chacl/CVS/Root --- linux-2.4.7/cmd/acl/chacl/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/chacl/CVS/Root Thu Jul 5 11:43:37 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/acl/chacl/Makefile linux-2.4-xfs/cmd/acl/chacl/Makefile --- linux-2.4.7/cmd/acl/chacl/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/chacl/Makefile Mon Jan 15 04:28:46 2001 @@ -0,0 +1,48 @@ +# +# Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = chacl +CFILES = chacl.c +LLDLIBS = $(LIBACL) +LLDFLAGS = -L$(TOPDIR)/libacl + +default: $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_SBIN_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/acl/chacl/chacl.c linux-2.4-xfs/cmd/acl/chacl/chacl.c --- linux-2.4.7/cmd/acl/chacl/chacl.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/chacl/chacl.c Mon Jun 11 15:48:59 2001 @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * + * chacl - change/delete/list file Access Control List + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static int acl_delete_file (const char * path, acl_type_t type); +static int list_acl(char *file); +static char *program; + +static void +usage (void) +{ + fprintf (stderr, "%s: usage: \n", program); + fprintf (stderr, "\t%s acl pathname ...\n", program); + fprintf (stderr, "\t%s -d dacl pathname ...\n", program); + fprintf (stderr, "\t%s -b acl dacl pathname ...\n", program); + fprintf (stderr, "\t%s -R pathname ...\n", program); + fprintf (stderr, "\t%s -D pathname ...\n", program); + fprintf (stderr, "\t%s -B pathname ...\n", program); + fprintf (stderr, "\t%s -l pathname ...\n", program); + exit (1); +} + +int +main (int argc, char *argv[]) +{ + const char *inv_acl = "%s: \"%s\" is an invalid ACL specification.\n"; + char *p; + int switch_flag = 0; /* ensure only one switch is used */ + int args_required = 1; + int failed = 0; /* exit status */ + int c; /* For use by getopt(3) */ + int dflag = 0; /* a Default ACL is desired */ + int bflag = 0; /* a both ACLs are desired */ + int Rflag = 0; /* set to true to remove an acl */ + int Dflag = 0; /* set to true to remove default acls */ + int Bflag = 0; /* set to true to remove both acls */ + int lflag = 0; /* set to true to list acls */ + acl_t acl = NULL; /* File ACL */ + acl_t dacl = NULL; /* Directory Default ACL */ + + /* create program name */ + p = strrchr (argv[0], '/'); + program = p != NULL ? p + 1 : argv[0]; + + acl_set_compat(ACL_COMPAT_IRIXGET); + + /* parse arguments */ + while ((c = getopt (argc, argv, "bdlRDB")) != -1) + { + if (switch_flag) usage(); + switch_flag=1; + + switch (c) + { + case 'b': + bflag = 1; + args_required=3; + break; + case 'd': + dflag = 1; + args_required=2; + break; + case 'R': + Rflag = 1; + break; + case 'D': + Dflag = 1; + break; + case 'B': + Bflag = 1; + break; + case 'l': + lflag = 1; + break; + default: + usage (); + break; + } + } + + /* if not enough arguments quit */ + if ((argc-optind) < args_required) + usage (); + + /* list the acls */ + if ( lflag ) + { + for (;optind < argc;optind++) + { + char *file = argv[optind]; + if (!list_acl(file)) + { + failed++; + } + } + return (failed); + } + + /* remove the acls */ + if ( Rflag || Dflag || Bflag ) + { + for (;optind < argc;optind++) + { + if (!Dflag && acl_delete_file (argv[optind], ACL_TYPE_ACCESS) == -1) + { + fprintf (stderr,"%s: error removing access acl on \"%s\": %s\n", + program, argv[optind],strerror(errno)); + failed++; + } + if (!Rflag && acl_delete_file (argv[optind], ACL_TYPE_DEFAULT) == -1) + { + fprintf (stderr,"%s: error removing default acl on \"%s\": %s\n", + program, argv[optind],strerror(errno)); + failed++; + } + } + return (failed); + } + + + /* file access acl */ + if (! dflag) { + acl = acl_from_text (argv[optind]); + if (acl == NULL || acl_valid(acl) == -1) + { + fprintf (stderr, inv_acl, program, argv[optind]); + return (1); + } + optind++; + } + + + /* directory default acl */ + if (bflag || dflag) { + dacl = acl_from_text (argv[optind]); + if (dacl == NULL || acl_valid(dacl) == -1) + { + fprintf (stderr, inv_acl, program, argv[optind]); + return (1); + } + optind++; + } + + + /* place acls on files */ + for (;optind < argc;optind++) + { + /* set regular acl */ + if (acl && + acl_set_file (argv[optind], ACL_TYPE_ACCESS, acl) == -1) + { + fprintf (stderr,"%s: error setting access acl on \"%s\": %s\n", + program, argv[optind],strerror(errno)); + failed++; + } + /* set default acl */ + if (dacl && + acl_set_file (argv[optind], ACL_TYPE_DEFAULT, dacl) == -1) + { + fprintf (stderr,"%s: error setting default acl on \"%s\": %s\n", + program, argv[optind],strerror(errno)); + failed++; + } + } + + if (acl) + acl_free (acl); + if (dacl) + acl_free (dacl); + + return (failed); +} + +/* + * deletes an access acl or directory default acl if one exists + */ +static int +acl_delete_file (const char * path, acl_type_t type) +{ + struct acl acl; + int error=0; + + acl.acl_cnt = ACL_NOT_PRESENT; + + error = acl_set_file( path,type,&acl) ; + + return(error); +} + +/* + * lists the acl for a file/dir in short text form + * return 0 on failure + * return 1 on success + */ +static int +list_acl(char *file) +{ + acl_t acl = NULL; + acl_t dacl = NULL; + char *buf_acl = NULL; + char *buf_dacl = NULL; + + acl = acl_get_file(file, ACL_TYPE_ACCESS); + if (acl == NULL) { + fprintf (stderr, "%s: error getting ACL on \"%s\": %s\n", + program, file, strerror(errno)); + return 0; + } + if (acl->acl_cnt != ACL_NOT_PRESENT) { + buf_acl = acl_to_short_text (acl, (ssize_t *) NULL); + if (buf_acl == NULL) { + fprintf (stderr, "%s: error converting ACL to short text " + "for file \"%s\": %s\n", + program, file, strerror(errno)); + return 0; + } + } + + dacl = acl_get_file(file, ACL_TYPE_DEFAULT); + if (dacl == NULL) { + fprintf (stderr, "%s: error getting default ACL on \"%s\": %s\n", + program, file, strerror(errno)); + return 0; + } + if (dacl->acl_cnt > 0) { + buf_dacl = acl_to_short_text (dacl, (ssize_t *) NULL); + if (buf_dacl == NULL) { + fprintf (stderr, "%s: error converting default ACL to short text " + "for file \"%s\": %s\n", + program, file, strerror(errno)); + return 0; + } + } + + printf("%s [", file); + if (buf_acl) + { + printf("%s", buf_acl); + } + if (buf_dacl) + { + printf("/%s", buf_dacl); + } + printf("]\n"); + + if (acl) + acl_free(acl); + if (dacl) + acl_free(dacl); + if (buf_acl) + acl_free(buf_acl); + if (buf_dacl) + acl_free(buf_dacl); + + return(1); +} diff -rNu linux-2.4.7/cmd/acl/configure.in linux-2.4-xfs/cmd/acl/configure.in --- linux-2.4.7/cmd/acl/configure.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/configure.in Tue Jun 12 20:49:41 2001 @@ -0,0 +1,156 @@ +dnl unpacking check - this file must exist +AC_INIT(include/acl.h) +pkg_name="acl" +AC_SUBST(pkg_name) + +# +# Note: the following environment variables may be set to override the +# defaults (to change paths and/or executables, build parameters, etc): +# +# DEBUG OPTIMIZER MAKE CC LD TAR ZIP RPM AWK SED ECHO +# MALLOCLIB DISTRIBUTION PACKAGE_BUILDER PREFIX ROOT_PREFIX +# + +DEBUG=${DEBUG:-'-DDEBUG'} # -DNDEBUG +OPTIMIZER=${OPTIMIZER:-'-g'} # -O2 +MALLOCLIB=${MALLOCLIB:-''} # /usr/lib/libefence.a + +dnl Debug build? +debug_build="$DEBUG" +AC_SUBST(debug_build) + +dnl Optimization options? +opt_build="$OPTIMIZER" +AC_SUBST(opt_build) + +dnl Alternate malloc library? +malloc_lib="$MALLOCLIB" +AC_SUBST(malloc_lib) + +dnl Set version +. ./VERSION + +pkg_version=${PKG_MAJOR}.${PKG_MINOR}.${PKG_REVISION} +pkg_release=$PKG_BUILD +AC_SUBST(pkg_version) +AC_SUBST(pkg_release) + +pkg_distribution="SGI ProPack" +test -z "$DISTRIBUTION" || pkg_distribution="$DISTRIBUTION" +AC_SUBST(pkg_distribution) + +pkg_builder=`id -u -n`@`hostname -f` +test -z "$PACKAGE_BUILDER" || pkg_builder="$PACKAGE_BUILDER" +AC_SUBST(pkg_builder) + +dnl check if user wants their own C compiler +test -z "$CC" && AC_PROG_CC +cc=$CC +AC_SUBST(cc) + +dnl check if users wants their own make +test -z "$MAKE" && AC_PATH_PROG(MAKE, make, /usr/bin/make) +make=$MAKE +AC_SUBST(make) + +dnl check if users wants their own linker +test -z "$LD" && AC_PATH_PROG(LD, ld, /usr/bin/ld) +ld=$LD +AC_SUBST(ld) + +dnl check if the tar program is available +test -z "$TAR" && AC_PATH_PROG(TAR, tar) +tar=$TAR +AC_SUBST(tar) + +dnl check if the gzip program is available +test -z "$ZIP" && AC_PATH_PROG(ZIP, gzip, /bin/gzip) +zip=$ZIP +AC_SUBST(zip) + +dnl check if the rpm program is available +test -z "$RPM" && AC_PATH_PROG(RPM, rpm, /bin/rpm) +rpm=$RPM +AC_SUBST(rpm) + +dnl .. and what version is rpm +rpm_version=0 +test -x $RPM && \ + rpm_version=`$RPM --version | awk '{print $NF}' | awk -F. '{print $1}'` +AC_SUBST(rpm_version) + +dnl check if the makedepend program is available +test -z "$MAKEDEPEND" && AC_PATH_PROG(MAKEDEPEND, makedepend, /bin/true) +makedepend=$MAKEDEPEND +AC_SUBST(makedepend) + +dnl check if symbolic links are supported +AC_PROG_LN_S + +dnl check if user wants their own awk, sed and echo +test -z "$AWK" && AC_PATH_PROG(AWK, awk, /bin/awk) +awk=$AWK +AC_SUBST(awk) +test -z "$SED" && AC_PATH_PROG(SED, sed, /bin/sed) +sed=$SED +AC_SUBST(sed) +test -z "$ECHO" && AC_PATH_PROG(ECHO, echo, /bin/echo) +echo=$ECHO +AC_SUBST(echo) + + +dnl alternate root and usr prefixes +test -z "$ROOT_PREFIX" && ROOT_PREFIX="" +root_prefix="$ROOT_PREFIX" +test -z "$PREFIX" && PREFIX="/usr" +prefix="$PREFIX" + +dnl man pages (source) +dnl also check if man page source is gzipped +dnl (usually on Debian, but not Redhat pre-7.0) +pkg_man_dir=${prefix}/share/man +have_zipped_manpages=false +for d in ${prefix}/share/man ${prefix}/man ; do + if test -f $d/man1/man.1.gz + then + pkg_man_dir=$d + have_zipped_manpages=true + break + fi +done +AC_SUBST(pkg_man_dir) +AC_SUBST(have_zipped_manpages) + +dnl binaries +pkg_bin_dir=${prefix}/bin +AC_SUBST(pkg_bin_dir) + +dnl static libraries +pkg_lib_dir="${prefix}/lib" +AC_SUBST(pkg_lib_dir) + +dnl runtime shared system libraries +pkg_slib_dir="${root_prefix}/lib" +AC_SUBST(pkg_slib_dir) + +dnl system binaries +pkg_sbin_dir=${root_prefix}/bin +AC_SUBST(pkg_sbin_dir) + +dnl include files +pkg_inc_dir=${prefix}/include/sys +AC_SUBST(pkg_inc_dir) + +dnl doc directory +pkg_doc_dir=${prefix}/share/doc/${pkg_name} +AC_SUBST(pkg_doc_dir) + + +dnl +dnl output files +dnl + +AC_OUTPUT( \ +dnl Build definitions for use in Makefiles + include/builddefs \ +) diff -rNu linux-2.4.7/cmd/acl/debian/CVS/Entries linux-2.4-xfs/cmd/acl/debian/CVS/Entries --- linux-2.4.7/cmd/acl/debian/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/debian/CVS/Entries Thu Jul 5 11:43:38 2001 @@ -0,0 +1,6 @@ +/Makefile/1.1/Mon Jan 15 10:28:46 2001/-ko/ +/changelog/1.3/Mon Jul 2 03:31:14 2001/-ko/ +/control/1.1/Mon Jan 15 10:28:46 2001/-ko/ +/copyright/1.1/Mon Jan 15 10:28:46 2001/-ko/ +/rules/1.3/Thu Jan 25 06:56:37 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/acl/debian/CVS/Repository linux-2.4-xfs/cmd/acl/debian/CVS/Repository --- linux-2.4.7/cmd/acl/debian/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/debian/CVS/Repository Thu Jul 5 11:43:38 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/acl/debian diff -rNu linux-2.4.7/cmd/acl/debian/CVS/Root linux-2.4-xfs/cmd/acl/debian/CVS/Root --- linux-2.4.7/cmd/acl/debian/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/debian/CVS/Root Thu Jul 5 11:43:38 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/acl/debian/Makefile linux-2.4-xfs/cmd/acl/debian/Makefile --- linux-2.4.7/cmd/acl/debian/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/debian/Makefile Mon Jan 15 04:28:46 2001 @@ -0,0 +1,40 @@ +# +# Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LSRCFILES = changelog control copyright rules + +default install install-dev: + +include $(BUILDRULES) diff -rNu linux-2.4.7/cmd/acl/debian/changelog linux-2.4-xfs/cmd/acl/debian/changelog --- linux-2.4.7/cmd/acl/debian/changelog Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/debian/changelog Sun Jul 1 22:31:14 2001 @@ -0,0 +1,24 @@ +acl (1.0.8) unstable; urgency=low + + * Work around syscall number collision on recent ia64 kernels + * Numerous API changes to more closely follow the draft POSIX ACL + standard, and to help with its use within Samba + + -- Nathan Scott Mon, 2 Jul 2001 13:02:02 +1000 + +acl (1.0.2) unstable; urgency=low + + * Updates to man pages. + * Minor rpm and deb packaging work. + + -- Nathan Scott Fri, 18 May 2001 15:47:54 +1000 + +acl (1.0.0) unstable; urgency=low + + * Initial release. + + -- Nathan Scott Thu, 4 Jan 2001 11:15:11 -0500 + +Local variables: +mode: debian-changelog +End: diff -rNu linux-2.4.7/cmd/acl/debian/control linux-2.4-xfs/cmd/acl/debian/control --- linux-2.4.7/cmd/acl/debian/control Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/debian/control Mon Jan 15 04:28:46 2001 @@ -0,0 +1,24 @@ +Source: acl +Section: admin +Priority: optional +Maintainer: Nathan Scott +Build-Depends: autoconf, debmake +Standards-Version: 3.1.1 + +Package: acl +Depends: ${shlibs:Depends} +Architecture: any +Description: Experimental chacl utility for manipulating POSIX ACLs + An *experimental* command (chacl) to manipulate access control + lists according to the (draft) POSIX 1003 standard. + +Package: acl-dev +Section: devel +Priority: extra +Depends: libc6-dev, acl +Architecture: any +Description: POSIX ACL static libraries and headers + acl-dev contains the libraries and header files needed to + develop programs which make use of access control lists. + This is an *experimental* interface, currently only XFS is + supported, and the interface may change. diff -rNu linux-2.4.7/cmd/acl/debian/copyright linux-2.4-xfs/cmd/acl/debian/copyright --- linux-2.4.7/cmd/acl/debian/copyright Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/debian/copyright Mon Jan 15 04:28:46 2001 @@ -0,0 +1,14 @@ +This package was debianized by Nathan Scott nathans@debian.org on +Sun, 19 Nov 2000 07:37:09 -0500. + +It can be downloaded from ftp://oss.sgi.com/projects/xfs/download/ + +Copyright: + +Copyright (C) 2000 Silicon Graphics, Inc. + +You are free to distribute this software under the terms of +the GNU General Public License. +On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL file. + diff -rNu linux-2.4.7/cmd/acl/debian/rules linux-2.4-xfs/cmd/acl/debian/rules --- linux-2.4.7/cmd/acl/debian/rules Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/debian/rules Thu Jan 25 00:56:37 2001 @@ -0,0 +1,61 @@ +#!/usr/bin/make -f + +package = acl +develop = $(package)-dev + +dirtmp = debian/tmp +dirdev = debian/$(develop) +doctmp = /usr/share/doc/$(package) +docdev = /usr/share/doc/$(develop) +pkgtmp = DIST_ROOT=`pwd`/$(dirtmp); export DIST_ROOT; +pkgdev = DIST_ROOT=`pwd`/$(dirdev); export DIST_ROOT; +stdenv = GZIP=-q; export GZIP; + +options = DEBUG="-DNDEBUG"; OPTIMIZER="-O1 -g"; DISTRIBUTION="debian"; \ + export DEBUG OPTIMIZER DISTRIBUTION; +checkdir = test -f debian/rules + +build: built +built: + @echo "== dpkg-buildpackage: build" 1>&2 + $(checkdir) + autoconf + $(options) ./configure + $(MAKE) default + touch built + +clean: + @echo "== dpkg-buildpackage: clean" 1>&2 + $(checkdir) + -rm -f built + $(MAKE) distclean + -rm -rf $(dirtmp) $(dirdev) debian/*substvars debian/files* + +binary-indep: + +binary-arch: checkroot built + @echo "== dpkg-buildpackage: binary-arch" 1>&2 + $(checkdir) + -rm -rf $(dirtmp) $(dirdev) + $(pkgtmp) $(MAKE) -C . install + $(pkgdev) $(MAKE) -C . install-dev + $(pkgtmp) $(MAKE) -C build src-manifest + $(pkgdev) ./install-sh -m 755 -d $(doctmp) + $(pkgdev) ./install-sh -m 755 -d $(docdev) + $(pkgdev) ./install-sh -m 644 debian/copyright $(docdev) + $(pkgdev) ./install-sh -m 644 debian/changelog $(docdev) + @echo "== dpkg-buildpackage: debstd" 1>&2 + $(stdenv) debstd -m + dpkg-gencontrol -isp -p$(package) -P$(dirtmp) + dpkg-gencontrol -isp -p$(develop) -P$(dirdev) + chown -R root.root $(dirtmp) $(dirdev) + chmod -R go=rX $(dirtmp) $(dirdev) + dpkg --build $(dirtmp) .. + dpkg --build $(dirdev) .. + +binary: binary-indep binary-arch + +checkroot: + test 0 -eq `id -u` + +.PHONY: binary binary-arch binary-indep clean checkroot diff -rNu linux-2.4.7/cmd/acl/doc/CHANGES linux-2.4-xfs/cmd/acl/doc/CHANGES --- linux-2.4.7/cmd/acl/doc/CHANGES Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/doc/CHANGES Sun Jul 1 22:31:14 2001 @@ -0,0 +1,58 @@ +acl-1.0.8 (02 Jul 2001) + - Work around syscall number collision on recent ia64 kernels + +acl-1.0.7 (20 June 2001) + - Change acl_get_qualifier() to dynamically allocate + the returned qualifier so that acl_free() can be + used to free the qualifier as decreed in the + withdrawn Posix standard. + This change was suggested by Juergen Hasch when + using code with Samba. + +acl-1.0.6 (13 June 2001) + - Move acl/acl.h --to--> sys/acl.h which makes + it satisfy the Posix ACL standard. + This was also what was used in IRIX. + - A fix was also done on June 11 for "chacl -b" and + "chacl -d" where the default ACL is being given. + The code was checking the validity of the access ACL + instead of the default ACL. This is a real problem for + the -d option which doesn't have an access ACL specified ! + +acl-1.0.5 (6 June 2001) + - Fix up acl_to_text and acl_to_short_text so that if it is + given an empty ACL then an empty string is returned. + Suggestion made by Juergen Hasch where comparing with + the ext2 Posix ACL patch of Andreas Gruenbacher. + - Update acl.h to define ACL_OTHER (same as ACL_OTHER_OBJ). + +acl-1.0.4 (29 May 2001) + - Fix up acl_get_file, acl_get_fd bug for non-IRIX semantics + which I introduced in 1.0.3 (thanks Juergen Hasch). + - Make acl_get_entry match Posix 23.4.13.3 semantics. + - Make acl_create_entry match Posix 23.4.7.2 semantics. + - add acl_get_perm() for the Samba work + +acl-1.0.3 (24 May 2001) + - Update libacl functions of acl_get_file, acl_get_fd, + so that they can do ext2 P1003.1e style semantics by default + or IRIX P1003.1e semantics. + The change affects what is returned for a file if an + ACL is requested and no ACL has been explicitly set. + For ext2 P1003.1e style on an access ACL, + a 3 entry mininum ACL based on the file's mode is returned + wheras for IRIX an special empty ACL is returned. + - Add new function, acl_set_compat, to allow IRIX compatibility + if needed + +acl-1.0.2 (18 May 2001) + - updates to man pages + +acl-1.0.1 (30 January 2001) + - minor rpm and deb packaging work + +acl-1.0.0 (15 January 2001) + - access control list code abstracted from xfs-cmds package + - completed Debian packaging + - late beta code + diff -rNu linux-2.4.7/cmd/acl/doc/COPYING linux-2.4-xfs/cmd/acl/doc/COPYING --- linux-2.4.7/cmd/acl/doc/COPYING Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/doc/COPYING Mon Jan 15 04:28:46 2001 @@ -0,0 +1,860 @@ +All the libraries in "acl" are licensed under Version 2.1 +of the GNU Lesser General Public License. + +All other "acl" components are licensed under Version 2 of +the GNU General Public License. + +---------------------------------------------------------------------- + + + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + +---------------------------------------------------------------------- + + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +---------------------------------------------------------------------- diff -rNu linux-2.4.7/cmd/acl/doc/CVS/Entries linux-2.4-xfs/cmd/acl/doc/CVS/Entries --- linux-2.4.7/cmd/acl/doc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/doc/CVS/Entries Thu Jul 5 11:43:40 2001 @@ -0,0 +1,6 @@ +/CHANGES/1.9/Mon Jul 2 03:31:14 2001/-ko/ +/COPYING/1.1/Mon Jan 15 10:28:46 2001/-ko/ +/INSTALL/1.1/Mon Jan 15 10:28:46 2001/-ko/ +/Makefile/1.2/Thu Jan 25 06:56:37 2001/-ko/ +/PORTING/1.1/Mon Jan 15 10:28:46 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/acl/doc/CVS/Repository linux-2.4-xfs/cmd/acl/doc/CVS/Repository --- linux-2.4.7/cmd/acl/doc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/doc/CVS/Repository Thu Jul 5 11:43:38 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/acl/doc diff -rNu linux-2.4.7/cmd/acl/doc/CVS/Root linux-2.4-xfs/cmd/acl/doc/CVS/Root --- linux-2.4.7/cmd/acl/doc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/doc/CVS/Root Thu Jul 5 11:43:38 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/acl/doc/INSTALL linux-2.4-xfs/cmd/acl/doc/INSTALL --- linux-2.4.7/cmd/acl/doc/INSTALL Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/doc/INSTALL Mon Jan 15 04:28:46 2001 @@ -0,0 +1,48 @@ +This document describes how to configure and build the access control +list (ACL) library and utility from source, and how to install them. + +0. If you have the binary rpm, simply install it and skip to step 2 (below). + The rpm command to do this is: + # rpm -Uvh acl + + The Debian command to do this is: + # dpkg -i acl + or, if you have apt configured (don't need the binary package): + # apt-get install acl + +1. Configure, build and install the package + + The "acl" package uses autoconf/configure and expects a GNU build + environment (your platform must at least have both autoconf and gmake). + + If you just want to spin an RPM and/or tar file, use the Makepkgs + script in the top level directory. This will configure and build + the package and leave binary and src RPMs in the build/rpm + directory. It will also leave a tar file in the build/tar + directory. + + # ./Makepkgs verbose + + If you want to build the package and install it manually, use the + following steps: + + # make configure (or run autoconf; ./configure) + # make + # su root + # make install + + Note that there are so many "install" variants out there that we + wrote our own script (see "install-sh" in the top level directory). + + If you wish to turn off debugging asserts in the command build and + turn on the optimizer then set the shell environment variables: + + OPTIMIZER=-O + DEBUG=-DNDEBUG + + before running make configure or Makepkgs. + +2. How to Contribute + + See the README file in this directory for details about how to + contribute to the XFS project. diff -rNu linux-2.4.7/cmd/acl/doc/Makefile linux-2.4-xfs/cmd/acl/doc/Makefile --- linux-2.4.7/cmd/acl/doc/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/doc/Makefile Thu Jan 25 00:56:37 2001 @@ -0,0 +1,52 @@ +# +# Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LSRCFILES = INSTALL PORTING CHANGES COPYING +LDIRT = *.gz + +default: $(CMDTARGET) CHANGES.gz + +include $(BUILDRULES) + +CHANGES.gz: + $(ZIP) --best -c < CHANGES > $@ + +install: default + $(INSTALL) -m 755 -d $(PKG_DOC_DIR) +ifneq ($(PKG_DISTRIBUTION), debian) + $(INSTALL) -m 644 COPYING $(PKG_DOC_DIR) +endif + $(INSTALL) -m 644 PORTING CHANGES.gz $(PKG_DOC_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/acl/doc/PORTING linux-2.4-xfs/cmd/acl/doc/PORTING --- linux-2.4.7/cmd/acl/doc/PORTING Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/doc/PORTING Mon Jan 15 04:28:46 2001 @@ -0,0 +1,86 @@ + +1. unpack the source tarball and cd to the resulting dir + +2. # autoconf + this reads configure.in and generates the ./configure script + +3. # ./configure + this probes your system and then, for each "file" named + in the AC_OUTPUT() macro near the end of configure.in, + read "file".in and generate "file". Variables named @somevariable@ + will be substituted with literal values. + +4. step (3) produces several files. These files are generated by + configure from their respective .in file in the same directory. + You should have a read of these generated files and diff them + against their respective .in files to see what was substituted + by configure. + + src/include/builddefs + common definitions for the build environment. This is included + by all Makefiles, in conjunction with src/include/buildrules. + Note that most autoconf/configure build environments generate + Makefile (from Makefile.in) in every src dir. Instead, we + generate builddefs, and then include it in every Makefile. + + src/include/platform_defs.h + header containing conditional macros defining the C run-time + environment discovered by the configure script. + +5. read some or all of the GNU tool chain documentation + gmake Table Of Contents : + http://www.delorie.com/gnu/docs/make/make_toc.html + gmake Quick Reference section : + http://www.delorie.com/gnu/docs/make/make_120.html + Autoconf : + http://www.delorie.com/gnu/docs/autoconf/autoconf_toc.html + gcc/g++ : + http://www.delorie.com/gnu/docs/gcc/gcc_toc.html + +6. Makefiles and build environment + First have a look at some Makefiles + + example using SUBDIRS : acl/Makefile + example static library: acl/libacl/Makefile + example command : acl/chacl/Makefile + + All Makefiles must define TOPDIR as the root of the project. This + allows other stuff to be found relative to $(TOPDIR). + + All Makefiles should have the following structure, which is + much like commondefs and commonrules in the IRIX build environment, e.g. + + # ---------------------------------------------------------------------- + # TOPDIR must point to the root of the project + # The builddefs file defines lots of things. Read it. + TOPDIR = .. + include $(TOPDIR)/include/builddefs + + # first rule should always be "default" + default : sometarget + commands to build targets, if necessary + + # $(BUILDRULES) is defined in builddefs and includes rules for + # descending subdirs, building targets and installation rules + include $(BUILDRULES) + + install : default + $(INSTALL) sometargets somewhere + # ---------------------------------------------------------------------- + +7. packaging + + # ./Makepkgs + this script generates all of the packages supported - each has a + subdirectory below acl/build where knowledge specific to each + package type is maintained. + + The script produces logs of each stage of the build (this info is + also echoed to the screen when the "verbose" option is provided): + + acl/Logs/configure - `autoconf; ./configure' output + acl/Logs/default - `make default' output + acl/Logs/dist - `make build dist' output + + On successful completion, the script echoes the names of packages + successfully generated. diff -rNu linux-2.4.7/cmd/acl/include/CVS/Entries linux-2.4-xfs/cmd/acl/include/CVS/Entries --- linux-2.4.7/cmd/acl/include/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/include/CVS/Entries Thu Jul 5 11:43:40 2001 @@ -0,0 +1,5 @@ +/Makefile/1.1/Mon Jan 15 10:28:46 2001/-ko/ +/acl.h/1.6/Wed Jun 6 04:55:01 2001/-ko/ +/builddefs.in/1.2/Wed May 9 05:39:03 2001/-ko/ +/buildrules/1.1/Mon Jan 15 10:28:46 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/acl/include/CVS/Repository linux-2.4-xfs/cmd/acl/include/CVS/Repository --- linux-2.4.7/cmd/acl/include/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/include/CVS/Repository Thu Jul 5 11:43:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/acl/include diff -rNu linux-2.4.7/cmd/acl/include/CVS/Root linux-2.4-xfs/cmd/acl/include/CVS/Root --- linux-2.4.7/cmd/acl/include/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/include/CVS/Root Thu Jul 5 11:43:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/acl/include/Makefile linux-2.4-xfs/cmd/acl/include/Makefile --- linux-2.4.7/cmd/acl/include/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/include/Makefile Mon Jan 15 04:28:46 2001 @@ -0,0 +1,45 @@ +# +# Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +HFILES = acl.h +LSRCFILES = builddefs.in buildrules + +default install : + +include $(BUILDRULES) + +install-dev: default + $(INSTALL) -m 755 -d $(PKG_INC_DIR) + $(INSTALL) -m 644 $(HFILES) $(PKG_INC_DIR) diff -rNu linux-2.4.7/cmd/acl/include/acl.h linux-2.4-xfs/cmd/acl/include/acl.h --- linux-2.4.7/cmd/acl/include/acl.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/include/acl.h Tue Jun 5 23:55:01 2001 @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef __ACL_H__ +#define __ACL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Data types for Access Control Lists (ACLs) + */ +#define SGI_ACL_FILE "SGI_ACL_FILE" +#define SGI_ACL_DEFAULT "SGI_ACL_DEFAULT" + +#define SGI_ACL_FILE_SIZE 12 +#define SGI_ACL_DEFAULT_SIZE 15 + +/* + * An IRIX defined macro not in P1003.1e + * With ACL_COMPAT_IRIXGET set + * it used to signify an empty ACL. + * It is also used to delete an ACL. + */ +#define ACL_NOT_PRESENT -1 + +/* + * Number of "base" ACL entries + * (USER_OBJ, GROUP_OBJ, MASK, & OTHER_OBJ) + */ +#define NACLBASE 4 +#define ACL_MAX_ENTRIES 25 /* Arbitrarily chosen number */ + +/* + * Data types required by POSIX P1003.1eD15 + */ +typedef ushort acl_perm_t; +typedef int acl_type_t; +typedef int acl_tag_t; + +/* + * On-disk representation of an ACL. + */ +struct acl_entry { + acl_tag_t ae_tag; + uid_t ae_id; + acl_perm_t ae_perm; +}; +typedef struct acl_entry * acl_entry_t; + +struct acl { + int acl_cnt; /* Number of entries */ + struct acl_entry acl_entry[ACL_MAX_ENTRIES]; +}; + +/* + * Values for acl_get_entry + */ +#define ACL_FIRST_ENTRY 0x00 +#define ACL_NEXT_ENTRY 0x01 + +/* + * Values for acl_tag_t + */ +#define ACL_UNDEFINED_TAG 0x00 /* undefined tag */ +#define ACL_USER_OBJ 0x01 /* owner */ +#define ACL_USER 0x02 /* additional users */ +#define ACL_GROUP_OBJ 0x04 /* group */ +#define ACL_GROUP 0x08 /* additional groups */ +#define ACL_MASK 0x10 /* mask entry */ +#define ACL_OTHER_OBJ 0x20 /* other entry */ +#define ACL_OTHER 0x20 /* POSIX other entry */ +/* + * Values for acl_type_t + */ +#define ACL_TYPE_ACCESS 0 +#define ACL_TYPE_DEFAULT 1 +/* + * Values for acl_perm_t + */ +#define ACL_PERM_NONE 00 +#define ACL_READ 04 +#define ACL_WRITE 02 +#define ACL_EXECUTE 01 + +/* + * Values for qualifiers + */ +#define ACL_UNDEFINED_ID ((unsigned int)-1) + +/* + * Values for acl compatibility + */ +#define ACL_COMPAT_DEFAULT 0x00 +#define ACL_COMPAT_IRIXGET 0x01 + +typedef struct acl * acl_t; +typedef acl_perm_t * acl_permset_t; +typedef unsigned int acl_compat_t; + +/* + * User-space POSIX data types and functions. + */ +#ifndef __KERNEL__ + +extern void acl_set_compat(acl_compat_t); +extern int acl_add_perm(acl_permset_t, acl_perm_t); +extern int acl_clear_perms(acl_permset_t); +extern ssize_t acl_copy_ext(void *, acl_t, ssize_t); +extern acl_t acl_copy_int(const void *); +extern int acl_create_entry(acl_t *, acl_entry_t *); +extern int acl_delete_def_file(const char *); +extern int acl_delete_entry(acl_t, acl_entry_t); +extern int acl_delete_perm(acl_permset_t, acl_perm_t); +extern acl_t acl_dup(acl_t); +extern void acl_entry_sort(acl_t); +extern int acl_free(void *); +extern acl_t acl_from_text(const char *); +extern int acl_get_entry(acl_t, int, acl_entry_t *); +extern acl_t acl_get_fd(int); +extern acl_t acl_get_file(const char *, acl_type_t); +extern int acl_get_perm(acl_permset_t, acl_perm_t); +extern int acl_get_permset(acl_entry_t, acl_permset_t *); +extern void *acl_get_qualifier(acl_entry_t); +extern int acl_get_tag_type(acl_entry_t, acl_tag_t *); +extern acl_t acl_init(int); +extern int acl_set_fd(int, acl_t); +extern int acl_set_file(const char *, acl_type_t, acl_t); +extern int acl_set_permset(acl_entry_t, acl_permset_t); +extern int acl_set_qualifier(acl_entry_t,const void *); +extern int acl_set_tag_type(acl_entry_t, acl_tag_t); +extern ssize_t acl_size(acl_t); +extern char *acl_to_short_text(acl_t, ssize_t *); +extern char *acl_to_text(acl_t, ssize_t *); +extern int acl_valid(acl_t); + +/* system calls */ +extern int acl_get(const char *, int, struct acl *, struct acl *); +extern int acl_set(const char *, int, struct acl *, struct acl *); + +#endif /* __KERNEL__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ACL_H__ */ diff -rNu linux-2.4.7/cmd/acl/include/builddefs.in linux-2.4-xfs/cmd/acl/include/builddefs.in --- linux-2.4.7/cmd/acl/include/builddefs.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/include/builddefs.in Wed May 9 00:39:03 2001 @@ -0,0 +1,167 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# @configure_input@ +# + +ifndef _BUILDDEFS_INCLUDED_ +_BUILDDEFS_INCLUDED_ = 1 + +DEBUG = @debug_build@ +OPTIMIZER = @opt_build@ +MALLOCLIB = @malloc_lib@ + +#LIBACL = -lacl +LIBACL = $(TOPDIR)/libacl/libacl.a + +BUILDRULES = $(TOPDIR)/include/buildrules + +# General package information +PKG_NAME = @pkg_name@ +PKG_RELEASE = @pkg_release@ +PKG_VERSION = @pkg_version@ +PKG_DISTRIBUTION = @pkg_distribution@ +PKG_BUILDER = @pkg_builder@ +PKG_BIN_DIR = @pkg_bin_dir@ +PKG_LIB_DIR = @pkg_lib_dir@ +PKG_SBIN_DIR = @pkg_sbin_dir@ +PKG_SLIB_DIR = @pkg_slib_dir@ +PKG_INC_DIR = @pkg_inc_dir@ +PKG_MAN_DIR = @pkg_man_dir@ +PKG_DOC_DIR = @pkg_doc_dir@ + +# LCFLAGS, LLDFLAGS, LLDLIBS, LSRCFILES and LDIRT may be specified in +# user Makefiles. Note: LSRCFILES is anything other than Makefile, $(CFILES) +# $(CXXFILES), or $(HFILES) and is used to construct the manifest list +# during the "dist" phase (packaging). + +CFLAGS += $(OPTIMIZER) $(DEBUG) -funsigned-char -Wall -D_GNU_SOURCE \ + $(LCFLAGS) -I$(TOPDIR)/include '-DVERSION="$(PKG_VERSION)"' \ + -D_FILE_OFFSET_BITS=64 + +LDFLAGS = $(LLDFLAGS) +LDLIBS = $(LLDLIBS) $(MALLOCLIB) + +MAKEOPTS = --no-print-directory +SRCFILES = Makefile $(HFILES) $(CFILES) $(LSRCFILES) $(LFILES) $(YFILES) +DIRT = $(LDIRT) dep dep.bak $(OBJECTS) $(CMDTARGET) $(LIBTARGET) \ + $(STATICLIBTARGET) *.[1-9].gz + +OBJECTS = $(ASFILES:.s=.o) \ + $(CFILES:.c=.o) \ + $(LFILES:.l=.o) \ + $(YFILES:%.y=%.tab.o) + +MAKE = @make@ +CC = @cc@ +LD = @ld@ +AWK = @awk@ +SED = @sed@ +INSTALL = $(TOPDIR)/install-sh -o root -g root +ECHO = @echo@ +LN_S = @LN_S@ + +CCF = $(CC) $(CFLAGS) +MAKEF = $(MAKE) $(MAKEOPTS) +CXXF = $(CXX) $(CXXFLAGS) +LDF = $(LD) $(LDFLAGS) +MAKEDEPEND = @makedepend@ + +ZIP = @zip@ +TAR = @tar@ +RPM = @rpm@ +RPM_VERSION = @rpm_version@ + +HAVE_ZIPPED_MANPAGES = @have_zipped_manpages@ + +SHELL = /bin/sh +IMAGES_DIR = $(TOPDIR)/all-images +DIST_DIR = $(TOPDIR)/dist + +SUBDIRS_MAKERULE = \ + @for d in $(SUBDIRS) ""; do \ + if test -d "$$d" -a ! -z "$$d"; then \ + $(ECHO) === $$d ===; \ + $(MAKEF) -C $$d $@ || exit $$?; \ + fi; \ + done + +MAN_MAKERULE = \ + @for f in *.[12345678] ""; do \ + if test ! -z "$$f"; then \ + $(ZIP) --best -c < $$f > $$f.gz; \ + fi; \ + done + +INSTALL_MAN = \ + @for d in $(MAN_PAGES); do \ + first=true; \ + for m in `$(AWK) '/^\.SH NAME/ {ok=1; next} ok {print; exit}' $$d \ + | sed -e 's/,/ /g' -e 's/\\-.*//' -e 's/\\\f[0-9]//g' -e 's/ / /g;q'`; \ + do \ + [ -z "$$m" -o "$$m" = "\\" ] && continue; \ + t=$(MAN_DEST)/$$m.$(MAN_SECTION); \ + if $$first; then \ + if $(HAVE_ZIPPED_MANPAGES); then \ + $(ZIP) --best -c $$d > $$d.gz; _sfx=.gz; \ + fi; \ + u=$$m.$(MAN_SECTION)$$_sfx; \ + echo $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ + $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ + else \ + echo $(INSTALL) -S $$u $${t}$$_sfx; \ + $(INSTALL) -S $$u $${t}$$_sfx; \ + fi; \ + first=false; \ + done; \ + done + +DIST_MAKERULE = \ + $(MAKEF) -C build dist + +SOURCE_MAKERULE = \ + @test -z "$$DIR" && DIR="."; \ + for f in $(SRCFILES) ""; do \ + if test ! -z "$$f"; then $(ECHO) $$DIR/$$f; fi;\ + done; \ + for d in `echo $(SUBDIRS)` ; do \ + if test -d "$$d" -a ! -z "$$d"; then \ + $(MAKEF) DIR=$$DIR/$$d -C $$d $@ || exit $$?; \ + fi; \ + done + +endif + +# +# For targets that should always be rebuilt, +# define a target that is never up-to-date. +# Targets needing this should depend on $(_FORCE) +_FORCE = __force_build diff -rNu linux-2.4.7/cmd/acl/include/buildrules linux-2.4-xfs/cmd/acl/include/buildrules --- linux-2.4.7/cmd/acl/include/buildrules Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/include/buildrules Mon Jan 15 04:28:46 2001 @@ -0,0 +1,77 @@ +# +# Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Fondation. +# +# This program is distributed in the hope that it would be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. Further, any license provided herein, +# whether implied or otherwise, is limited to this program in accordance with +# the express provisions of the GNU General Public License. Patent licenses, +# if any, provided herein do not apply to combinations of this program with +# other product or programs, or any other product whatsoever. This program is +# distributed without any warranty that the program is delivered free of the +# rightful claim of any third person by way of infringement or the like. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write the Free Software Foundation, Inc., 59 Temple +# Place - Suite 330, Boston MA 02111-1307, USA. +# Common build rules for gmake +# +ifndef _BUILDRULES_INCLUDED_ +_BUILDRULES_INCLUDED_ = 1 + +include $(TOPDIR)/include/builddefs + +# +# Standard targets +# +ifdef CMDTARGET +$(CMDTARGET) : $(SUBDIRS) $(OBJECTS) + $(CCF) -o $(CMDTARGET) $(LDFLAGS) $(OBJECTS) $(LDLIBS) +$(CMDTARGET).static : $(SUBDIRS) $(OBJECTS) + $(CCF) -static -o $(CMDTARGET).static $(LDFLAGS) $(OBJECTS) $(LDLIBS) +endif + +ifdef LIBTARGET +$(LIBTARGET) : $(SUBDIRS) $(OBJECTS) + $(CC) $(LDFLAGS) -fPIC -shared -Wl,-soname,$(LIBTARGET) -o $(LIBTARGET) $(OBJECTS) $(LDLIBS) +endif + +ifdef STATICLIBTARGET +$(STATICLIBTARGET) : $(SUBDIRS) $(OBJECTS) + $(AR) crf $(STATICLIBTARGET) $? +endif + +clean clobber : $(SUBDIRS) + rm -f $(DIRT) + $(SUBDIRS_MAKERULE) + +# Never blow away subdirs +ifdef SUBDIRS +.PRECIOUS: $(SUBDIRS) +$(SUBDIRS): + $(SUBDIRS_MAKERULE) +endif + +source : + $(SOURCE_MAKERULE) + +endif + +$(_FORCE): + +.PHONY : depend + +depend : $(CFILES) $(HFILES) + $(SUBDIRS_MAKERULE) + touch dep + $(MAKEDEPEND) -fdep -- $(CFLAGS) -- $(CFILES) + +# Include dep, but only if it exists +ifeq ($(shell test -f dep && echo dep), dep) +include dep +endif diff -rNu linux-2.4.7/cmd/acl/install-sh linux-2.4-xfs/cmd/acl/install-sh --- linux-2.4.7/cmd/acl/install-sh Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/install-sh Mon Jan 15 04:28:46 2001 @@ -0,0 +1,273 @@ +#! /bin/sh +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +# +# This script emulates bsd install and also recognises +# two environment variables, with the following semantics :- +# +# $DIST_MANIFEST - if set, the name of the file to append manifest +# information in the following format: +# File : f mode owner group src target +# Directory: d mode owner group target +# Symlink : l linkval target +# +# $DIST_ROOT - if set, prepend to target +# +# The sematics of all combinations of these two variables +# are as follows: +# +# $DIST_MANIFEST? $DIST_ROOT? | Copy? Append Manifest? +# -----------------------------+-------------------------- +# not set not set | yes no +# not set set | yes no +# set not set | no yes +# set set | yes yes +# +_usage() { + echo "Usage: $prog [-o owner] [-g group] [-m mode] -d directory" + echo "or $prog [-D] [-o owner] [-g group] [-m mode] file directory/file" + echo "or $prog [-o owner] [-g group] [-m mode] file [file ...] directory" + echo "or $prog -S file target (creates \"target\" symlink)" + echo "" + echo "The \$DIST_MANIFEST and \$DIST_ROOT environment variables affect the" + echo "behaviour of this command - see comments in the script." + echo "The -D flag is only available for the second usage, and causes" + echo "the target directory to be created before installing the file." + echo "" + exit 1 +} + +_chown () +{ + _st=255 + if [ $# -eq 3 ] ; then + chown $1:$2 $3 + _st=$? + if [ $_st -ne 0 ] ; then + if [ $REAL_UID != '0' ] ; then + if [ ! -f $DIST_ROOT/.chown.quite ] ; then + echo '===============================================' + echo Ownership of files under ${DIST_ROOT:-/} + echo cannot be changed + echo '===============================================' + if [ -n "$DIST_ROOT" ] ; then + touch $DIST_ROOT/.chown.quite + fi + fi + _st=0 + fi + fi + fi + + return $_st +} + + +_manifest () +{ + echo $* | sed -e 's/\/\//\//g' >>${DIST_MANIFEST:-/dev/null} +} + +prog=`basename $0` +HERE=`pwd` +dflag=false +Dflag=false +Sflag=false +DIRMODE=755 +FILEMODE=644 +OWNER=`id -u` +GROUP=`id -g` +REAL_UID=$OWNER + +# default is to install and don't append manifest +INSTALL=true +MANIFEST=: + +[ -n "$DIST_MANIFEST" -a -z "$DIST_ROOT" ] && INSTALL=false +[ -n "$DIST_MANIFEST" ] && MANIFEST="_manifest" + +[ $# -eq 0 ] && _usage + +if $INSTALL +then + CP=cp; LN=ln; MKDIR=mkdir; CHMOD=chmod; CHOWN=_chown +else + CP=true; LN=true; MKDIR=true; CHMOD=true; CHOWN=true +fi + +[ -n "$DIST_ROOT" -a $REAL_UID -ne 0 ] && CHOWN=true + +while getopts "Dcm:d:S:o:g:" c $* +do + case $c in + c) + ;; + g) + GROUP=$OPTARG + ;; + o) + OWNER=$OPTARG + ;; + m) + DIRMODE=`expr $OPTARG` + FILEMODE=$DIRMODE + ;; + D) + Dflag=true + ;; + S) + symlink=$OPTARG + Sflag=true + ;; + d) + dir=$DIST_ROOT/$OPTARG + dflag=true + ;; + *) + _usage + ;; + esac +done + +shift `expr $OPTIND - 1` + +status=0 +if $dflag +then + # + # first usage + # + $MKDIR -p $dir + status=$? + if [ $status -eq 0 ] + then + $CHMOD $DIRMODE $dir + status=$? + fi + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir + status=$? + fi + $MANIFEST d $DIRMODE $OWNER $GROUP ${dir#$DIST_ROOT} +elif $Sflag +then + # + # fourth usage (symlink) + # + if [ $# -ne 1 ] + then + _usage + else + target=$DIST_ROOT/$1 + fi + $LN -s -f $symlink $target + status=$? + $MANIFEST l $symlink ${target#$DIST_ROOT} +else + list="" + dir="" + if [ $# -eq 2 ] + then + # + # second usage + # + f=$1 + dir=$DIST_ROOT/$2 + if $Dflag + then + mkdir -p `dirname $dir` + fi + $CP $f $dir + status=$? + if [ $status -eq 0 ] + then + if [ -f $dir/$f ] + then + $CHMOD $FILEMODE $dir/$f + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir/$f + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f + else + $CHMOD $FILEMODE $dir + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$dir ${dir#$DIST_ROOT} + fi + fi + else + # + # third usage + # + n=1 + while [ $# -gt 0 ] + do + if [ $# -gt 1 ] + then + list="$list $1" + else + dir=$DIST_ROOT/$1 + fi + shift + done + + # echo DIR=$dir list=\"$list\" + for f in $list + do + $CP $f $dir + status=$? + if [ $status -eq 0 ] + then + $CHMOD $FILEMODE $dir/$f + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir/$f + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f + fi + [ $status -ne 0 ] && break + done + fi +fi + +exit $status diff -rNu linux-2.4.7/cmd/acl/libacl/CVS/Entries linux-2.4-xfs/cmd/acl/libacl/CVS/Entries --- linux-2.4.7/cmd/acl/libacl/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/libacl/CVS/Entries Thu Jul 5 11:43:40 2001 @@ -0,0 +1,3 @@ +/Makefile/1.1/Mon Jan 15 10:28:46 2001/-ko/ +/acl.c/1.12/Mon Jul 2 03:31:14 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/acl/libacl/CVS/Repository linux-2.4-xfs/cmd/acl/libacl/CVS/Repository --- linux-2.4.7/cmd/acl/libacl/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/libacl/CVS/Repository Thu Jul 5 11:43:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/acl/libacl diff -rNu linux-2.4.7/cmd/acl/libacl/CVS/Root linux-2.4-xfs/cmd/acl/libacl/CVS/Root --- linux-2.4.7/cmd/acl/libacl/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/libacl/CVS/Root Thu Jul 5 11:43:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/acl/libacl/Makefile linux-2.4-xfs/cmd/acl/libacl/Makefile --- linux-2.4.7/cmd/acl/libacl/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/libacl/Makefile Mon Jan 15 04:28:46 2001 @@ -0,0 +1,57 @@ +# +# Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +#LIBTARGET = libacl.so.1 +STATICLIBTARGET = libacl.a + +CFILES = acl.c +LCFLAGS = -D_REENTRANT + +default: $(STATICLIBTARGET) + +include $(BUILDRULES) + +#install: default +# $(INSTALL) -m 755 -d $(PKG_SLIB_DIR) +# $(INSTALL) -m 755 $(LIBTARGET) $(PKG_SLIB_DIR) +#install-dev: default +# ... +# $(INSTALL) -S $(PKG_SLIB_DIR)/$(LIBTARGET) $(PKG_LIB_DIR)/libacl.so + +install: default + +install-dev: default + $(INSTALL) -m 755 -d $(PKG_LIB_DIR) + $(INSTALL) -m 644 $(STATICLIBTARGET) $(PKG_LIB_DIR) diff -rNu linux-2.4.7/cmd/acl/libacl/acl.c linux-2.4-xfs/cmd/acl/libacl/acl.c --- linux-2.4.7/cmd/acl/libacl/acl.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/libacl/acl.c Sun Jul 1 22:31:14 2001 @@ -0,0 +1,1187 @@ +/* + * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. + * + * Copyright (c) 2001 Connex, Inc. for portions of the code relating to + * particular Access Control List functionality. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define LONG_FORM 0 +#define SHORT_FORM 1 + +#define TAG 0 +#define UID 1 +#define PERM 2 + +#define MAX_ENTRY_SIZE 30 + +#define setoserror(E) errno = (E) + +/* + * Compatibility flag for IRIX functionality + * Default is to support common Linux/Posix ACL functionality + * and thus is set to zero. + */ +static acl_compat_t acl_compat = 0; + +static char * +skip_white(char *s) +{ + char *cp; + + if (*s != ' ') + return s; + for (cp = s; *cp == ' '; cp++) + ; + *s = '\0'; + return cp; +} + +static char * +skip_to_white(char *s) +{ + while (*s != '\0' && *s != ' ') + s++; + return s; +} + +static char * +skip_separator(char *s) +{ + char *cp; + + for (cp = s; *cp == ' '; cp++) + ; + + if (*cp++ != ':') + return NULL; + + for (; *cp == ' '; cp++) + ; + + *s = '\0'; + return cp; +} + +static char * +skip_to_separator(char *s) +{ + while (*s != '\0' && *s != ' ' && *s != ':') + s++; + return s; +} + +/* + * Translate "rwx" into internal representations + */ +static int +get_perm (char *perm, acl_perm_t *p) +{ + *p = (acl_perm_t)0; + if (perm == NULL) + return 0; + + while (*perm) { + switch (*perm++) { + case '-': + break; + case 'r': + *p |= ACL_READ; + break; + case 'w': + *p |= ACL_WRITE; + break; + case 'x': + *p |= ACL_EXECUTE; + break; + default: + return -1; + } + } + return 0; +} + +static void +acl_error (void *b0, void *b1, int e) +{ + + if (b0) + free (b0); + if (b1) + free (b1); + setoserror (e); +} + +/* + * Converts either long or short text form of ACL into internal representations + * Input long text form lines are either + * #.....\n + * or + * [][]:[][]:[][][#....]\n + * short text form is + * :: + * returns a pointer to ACL + */ +struct acl * +acl_from_text (const char *buf_p) +{ + struct passwd *pw; + struct group *gr; + struct acl *aclbuf; + char *bp, *fp; + char c; + + /* check args for bogosity */ + if (buf_p == NULL || *buf_p == '\0') { + acl_error (NULL, NULL, EINVAL); + return (NULL); + } + + /* allocate copy of acl text */ + if ((bp = strdup(buf_p)) == NULL) { + acl_error (NULL, NULL, ENOMEM); + return (NULL); + } + + /* allocate ourselves an acl */ + if ((aclbuf = (acl_t)malloc(sizeof (*aclbuf))) == NULL) { + acl_error(bp, NULL, ENOMEM); + return (NULL); + } + aclbuf->acl_cnt = 0; + + /* Clear out comment lines and translate newlines to blanks */ + for (fp = bp, c = '\0'; *fp != '\0'; fp++) { + if (*fp == '\t' || *fp == ',') + *fp = ' '; + else if (*fp == '#' || *fp == '\n') + c = *fp; + if (c) { + *fp = ' '; + if (c == '\n') + c = '\0'; + } + } + + /* while not at the end of the text buffer */ + for (fp = skip_white(bp); fp != NULL && *fp != '\0'; ) { + acl_entry_t entry; + char *tag, *qa, *perm; + + if (aclbuf->acl_cnt > ACL_MAX_ENTRIES) { + acl_error (bp, aclbuf, EINVAL); + return (NULL); + } + + /* get tag */ + tag = fp; + fp = skip_to_separator(tag); + + if (*fp == '\0' && aclbuf->acl_cnt != 0) + break; + + /* get qualifier */ + if ((qa = skip_separator(fp)) == NULL) { + acl_error (bp, aclbuf, EINVAL); + return (NULL); + } + if (*qa == ':') { + /* e.g. u::rwx */ + fp = qa; + qa = NULL; + } + else { + /* e.g. u:fred:rwx */ + fp = skip_to_separator(qa); + } + + /* get permissions */ + if ((perm = skip_separator(fp)) == NULL) { + acl_error (bp, aclbuf, EINVAL); + return (NULL); + } + fp = skip_to_white(perm); + fp = skip_white(fp); + + + entry = &aclbuf->acl_entry[aclbuf->acl_cnt++]; + entry->ae_id = 0; + entry->ae_tag = -1; + + /* Process "user" tag keyword */ + if (!strcmp(tag, "user") || !strcmp(tag, "u")) { + if (qa == NULL || *qa == '\0') + entry->ae_tag = ACL_USER_OBJ; + else { + entry->ae_tag = ACL_USER; + if ((pw = getpwnam(qa))) + entry->ae_id = pw->pw_uid; + else if (isdigit(*qa)) + entry->ae_id = atoi(qa); + else { + acl_error (bp, aclbuf, EINVAL); + return (NULL); + } + } + } + + /* Process "group" tag keyword */ + if (!strcmp(tag, "group") || !strcmp(tag, "g")) { + if (qa == NULL || *qa == '\0') + entry->ae_tag = ACL_GROUP_OBJ; + else { + entry->ae_tag = ACL_GROUP; + if ((gr = getgrnam (qa))) + entry->ae_id = gr->gr_gid; + else if (isdigit (*qa)) + entry->ae_id = atoi(qa); + else { + acl_error (bp, aclbuf, EINVAL); + return (NULL); + } + } + } + + /* Process "other" tag keyword */ + if (!strcmp(tag, "other") || !strcmp(tag, "o")) { + entry->ae_tag = ACL_OTHER_OBJ; + if (qa != NULL && *qa != '\0') { + acl_error (bp, aclbuf, EINVAL); + return (NULL); + } + } + + /* Process "mask" tag keyword */ + if (!strcmp(tag, "mask") || !strcmp(tag, "m")) { + entry->ae_tag = ACL_MASK; + if (qa != NULL && *qa != '\0') { + acl_error (bp, aclbuf, EINVAL); + return (NULL); + } + } + + /* Process invalid tag keyword */ + if (entry->ae_tag == -1) { + acl_error(bp, aclbuf, EINVAL); + return (NULL); + } + + if (get_perm (perm, &entry->ae_perm) == -1) { + acl_error ((void *) bp, (void *) aclbuf, EINVAL); + return (NULL); + } + } + free (bp); + return (aclbuf); +} + +enum acl_tt {TT_USER, TT_GROUP, TT_OTHER, TT_MASK}; + +static char * +acl_to_text_internal (struct acl *aclp, ssize_t *len_p, const char *strs[], + int isshort) +{ + int i, buflen, s; + char *buf, *c, delim; + acl_entry_t entry; + + /* acl must be empty or valid else return */ + if (!aclp || (acl_valid(aclp) == -1 && aclp->acl_cnt != 0)) + return (char *) 0; + + buflen = aclp->acl_cnt * MAX_ENTRY_SIZE + 1; + if (!(c = buf = (char *) malloc (buflen))) + { + acl_error ((void *) 0, (void *) 0, ENOMEM); + return (char *) 0; + } + + /* empty ACLs convert to empty strings - follow Linux AG code */ + if (buflen==1) + { + *c = '\0'; + goto done; + } + + for (i = 0, delim = (isshort ? ',' : '\n'); i < aclp->acl_cnt; i++) + { + if (buflen - (c - buf) < MAX_ENTRY_SIZE) + { + acl_error ((void *) buf, (void *) 0, ENOMEM); + return (char *) 0; + } + + entry = &aclp->acl_entry[i]; + + switch (entry->ae_tag) + { + case ACL_USER_OBJ: + s = sprintf (c, "%s:", strs[TT_USER]); + break; + case ACL_USER: { + struct passwd *pw; + if ((pw = getpwuid (entry->ae_id))) + s = sprintf (c, "%s%s:", strs[TT_USER], + pw->pw_name); + else + s = sprintf (c, "%s%d:", strs[TT_USER], + entry->ae_id); + break; + } + case ACL_GROUP_OBJ: + s = sprintf (c, "%s:", strs[TT_GROUP]); + break; + case ACL_GROUP: { + struct group *gr; + if ((gr = getgrgid (entry->ae_id))) + s = sprintf (c, "%s%s:", + strs[TT_GROUP], + gr->gr_name); + else + s = sprintf (c, "%s%d:", + strs[TT_GROUP], + entry->ae_id); + break; + } + case ACL_OTHER_OBJ: + s = sprintf (c, "%s:", strs[TT_OTHER]); + break; + case ACL_MASK: + s = sprintf (c, "%s:", strs[TT_MASK]); + break; + default: + acl_error ((void *) buf, (void *) 0, EINVAL); + return (char *) 0; + } + c += s; + *c++ = (entry->ae_perm & ACL_READ) ? 'r' : '-'; + *c++ = (entry->ae_perm & ACL_WRITE) ? 'w' : '-'; + *c++ = (entry->ae_perm & ACL_EXECUTE) ? 'x' : '-'; + *c++ = delim; + } + if (isshort) + *--c = '\0'; + else + *c = '\0'; +done: + if (len_p) + *len_p = (ssize_t) (c - buf); + return buf; +} + +/* + * Translate an ACL to short text form. + * Inputs are a pointer to an ACL + * a pointer to the converted text buffer size + * Output is the pointer to the text buffer + */ +char * +acl_to_short_text (struct acl *aclp, ssize_t *len_p) +{ + static const char *strs[] = {"u:", "g:", "o:", "m:"}; + return acl_to_text_internal (aclp, len_p, strs, 1); +} + +/* + * Translate an ACL to long text form. + * Inputs are a pointer to an ACL + * a pointer to the converted text buffer size + * Output is the pointer to the text buffer + */ +char * +acl_to_text (struct acl *aclp, ssize_t *len_p) +{ + static const char *strs[] = {"user:", "group:", "other:", "mask:"}; + return acl_to_text_internal (aclp, len_p, strs, 0); +} + +ssize_t +acl_size (struct acl *aclp) +{ + if (aclp == NULL) + { + setoserror (EINVAL); + return ((ssize_t) (-1)); + } + return (sizeof (*aclp)); +} + +/* + * For now, the internal and external ACL are the same. + */ +ssize_t +acl_copy_ext (void *buf_p, struct acl *acl, ssize_t size) +{ + if (size <= 0 || !acl || !buf_p) + { + acl_error ((void *) 0, (void *) 0, EINVAL); + return (ssize_t) - 1; + } + + if (size < sizeof (struct acl)) + { + acl_error ((void *) 0, (void *) 0, ERANGE); + return (ssize_t) - 1; + } + + *(struct acl *) buf_p = *acl; + return (sizeof (*acl)); +} + +/* + * For now, the internal and external ACL are the same. + */ +struct acl * +acl_copy_int (const void *buf_p) +{ + struct acl *aclp; + + if (buf_p == NULL) + { + acl_error ((void *) NULL, (void *) NULL, EINVAL); + return (NULL); + } + + aclp = (struct acl *) malloc (sizeof (*aclp)); + if (aclp == NULL) + { + acl_error ((void *) NULL, (void *) NULL, ENOMEM); + return (aclp); + } + + *aclp = *(struct acl *) buf_p; + return aclp; +} + +int +acl_free (void *objp) +{ + if (objp) + free (objp); + return 0; +} + +/* + * Validate an ACL + */ +int +acl_valid (struct acl *aclp) +{ + struct acl_entry *entry, *e; + int user = 0, group = 0, other = 0, mask = 0, mask_required = 0; + int i, j; + + if (aclp == NULL) + goto acl_invalid; + + if (aclp->acl_cnt == ACL_NOT_PRESENT) + return 0; + + if (aclp->acl_cnt < 0 || aclp->acl_cnt > ACL_MAX_ENTRIES) + goto acl_invalid; + + for (i = 0; i < aclp->acl_cnt; i++) + { + + entry = &aclp->acl_entry[i]; + + switch (entry->ae_tag) + { + case ACL_USER_OBJ: + if (user++) + goto acl_invalid; + break; + case ACL_GROUP_OBJ: + if (group++) + goto acl_invalid; + break; + case ACL_OTHER_OBJ: + if (other++) + goto acl_invalid; + break; + case ACL_USER: + case ACL_GROUP: + for (j = i + 1; j < aclp->acl_cnt; j++) + { + e = &aclp->acl_entry[j]; + if (e->ae_id == entry->ae_id && e->ae_tag == entry->ae_tag) + goto acl_invalid; + } + mask_required++; + break; + case ACL_MASK: + if (mask++) + goto acl_invalid; + break; + default: + goto acl_invalid; + } + } + if (!user || !group || !other || (mask_required && !mask)) + goto acl_invalid; + else + return 0; +acl_invalid: + setoserror (EINVAL); + return (-1); +} + +/* + * Delete a default ACL by filename. + */ +int +acl_delete_def_file (const char *path_p) +{ + struct acl acl; + + acl.acl_cnt = ACL_NOT_PRESENT; + if (acl_set (path_p, -1, 0, &acl) < 0) + return (-1); + else + return 0; +} + +void +acl_set_compat(acl_compat_t compat_bits) +{ + if (compat_bits) + acl_compat |= compat_bits; + else + acl_compat = 0; +} + +static void +acl_from_mode(acl_t aclp, uid_t uid, gid_t gid, mode_t mode) +{ + aclp->acl_cnt = 3; + aclp->acl_entry[0].ae_tag = ACL_USER_OBJ; + aclp->acl_entry[0].ae_id = uid; + aclp->acl_entry[0].ae_perm = (mode & S_IRWXU) >> 6; + + aclp->acl_entry[1].ae_tag = ACL_GROUP_OBJ; + aclp->acl_entry[1].ae_id = gid; + aclp->acl_entry[1].ae_perm = (mode & S_IRWXG) >> 3; + + aclp->acl_entry[2].ae_tag = ACL_OTHER_OBJ; + aclp->acl_entry[2].ae_id = ACL_UNDEFINED_ID; + aclp->acl_entry[2].ae_perm = (mode & S_IRWXO); +} + +/* + * Get an ACL by file descriptor. + */ +struct acl * +acl_get_fd (int fd) +{ + struct acl *aclp = (struct acl *) malloc (sizeof (*aclp)); + + if (aclp == NULL) + { + setoserror (ENOMEM); + return (aclp); + } + + if (acl_get (0, fd, aclp, 0) < 0) + { + free ((void *) aclp); + return (NULL); + } + else if (! (acl_compat & ACL_COMPAT_IRIXGET) && + (aclp->acl_cnt == ACL_NOT_PRESENT)) { + /* copy over a minimum ACL from mode bits */ + struct stat st; + if (fstat(fd, &st) != 0) + return NULL; + acl_from_mode(aclp, st.st_uid, st.st_gid, st.st_mode); + } + return aclp; +} + +/* + * Get an ACL by filename. + */ +struct acl * +acl_get_file (const char *path_p, acl_type_t type) +{ + struct acl *aclp = (struct acl *) malloc (sizeof (*aclp)); + int acl_get_error; + + if (aclp == NULL) + { + setoserror (ENOMEM); + return (NULL); + } + + switch (type) + { + case ACL_TYPE_ACCESS: + acl_get_error = (int) acl_get (path_p, -1, + aclp, + (struct acl *) NULL); + break; + case ACL_TYPE_DEFAULT: + acl_get_error = (int) acl_get (path_p, -1, + (struct acl *) NULL, + aclp); + break; + default: + setoserror (EINVAL); + acl_get_error = -1; + } + + if (acl_get_error < 0) + { + free ((void *) aclp); + return (NULL); + } + else if (!(acl_compat & ACL_COMPAT_IRIXGET) && + (aclp->acl_cnt == ACL_NOT_PRESENT)) { + if (type == ACL_TYPE_ACCESS) { + /* copy over a minimum ACL from mode bits */ + struct stat st; + if (stat(path_p, &st) != 0) + return NULL; + acl_from_mode(aclp, st.st_uid, st.st_gid, st.st_mode); + } + else { /* default ACL */ + /* empty ACL and NOT ACL_NOT_PRESENT */ + aclp->acl_cnt = 0; + } + } + return aclp; +} + +/* + * Set an ACL by file descriptor. + */ +int +acl_set_fd (int fd, struct acl *aclp) +{ + if (acl_valid (aclp) == -1) + { + setoserror (EINVAL); + return (-1); + } + + if (aclp->acl_cnt > ACL_MAX_ENTRIES) + { +/* setoserror(EACL2BIG); until EACL2BIG is defined */ + setoserror (EINVAL); + return (-1); + } + + if (acl_set (0, fd, aclp, (struct acl *) NULL) < 0) { + return (-1); + } + else + return 0; +} + +/* + * Set an ACL by filename. + */ +int +acl_set_file (const char *path_p, acl_type_t type, struct acl *aclp) +{ + int acl_set_error; + + if (acl_valid (aclp) == -1) + { + setoserror (EINVAL); + return (-1); + } + + if (aclp->acl_cnt > ACL_MAX_ENTRIES) + { +/* setoserror(EACL2BIG); until EACL2BIG is defined */ + setoserror (EINVAL); + return (-1); + } + + switch (type) + { + case ACL_TYPE_ACCESS: + acl_set_error = (int) acl_set (path_p, -1, + aclp, + (struct acl *) NULL); + break; + case ACL_TYPE_DEFAULT: + acl_set_error = (int) acl_set (path_p, -1, + (struct acl *) NULL, + aclp); + break; + default: + setoserror (EINVAL); + return (-1); + } + if (acl_set_error < 0) { + return (-1); + } + else + return 0; +} + +acl_t +acl_dup (acl_t acl) +{ + acl_t dup = (acl_t) NULL; + + if (acl != (acl_t) NULL) + { + dup = (acl_t) malloc (sizeof (*acl)); + if (dup != (acl_t) NULL) + *dup = *acl; + else + setoserror (ENOMEM); + } + else + setoserror (EINVAL); + return (dup); +} + + +/* + * Get an ACE - 23.4.14.3 + */ +int +acl_get_entry (acl_t acl, int which, acl_entry_t *acep) +{ + int ne; + + if (acl == NULL) + goto bad_exit; + + if (acl->acl_cnt == 0) /* no entries */ + return 0; + + switch(which) { + case ACL_FIRST_ENTRY : + *acep = acl->acl_entry; + break; + case ACL_NEXT_ENTRY : + ne = 1 + *acep - acl->acl_entry; + if( (ne < 1) || (ne > acl->acl_cnt) ) /* outside range */ + goto bad_exit; + else if (ne == acl->acl_cnt) /* already at end */ + return 0; + (*acep)++; + break; + default: + goto bad_exit; + } + + return 1; + +bad_exit: + setoserror(EINVAL); + *acep = NULL; + return -1; +} + +/* + * Remove an ACE from an ACL + */ +int +acl_delete_entry (acl_t acl, acl_entry_t ace) +{ + int i, nd, cnt; + + if (acl == NULL) + goto bad_exit; + + nd = ace - acl->acl_entry; + cnt = acl->acl_cnt; + if((nd < 0) || (nd >= cnt)) + goto bad_exit; + + cnt--; /* reduce the entry count & close the hole */ + for(i=nd; iacl_cnt = cnt; + + return 0; + +bad_exit: + setoserror(EINVAL); + return -1; +} + +/* + * Add a new ACE to an ACL - 23.4.7.2 + */ +int +acl_create_entry (acl_t *aclp, acl_entry_t *acep) +{ + int cnt, erc; + acl_t acl; + acl_entry_t ace; + + erc = EINVAL; + if ((aclp == NULL) || (acep == NULL)) + goto bad_exit; + + ace = *acep; + acl = *aclp; + if (acl == NULL) + goto bad_exit; + + cnt = acl->acl_cnt; + if (cnt < 0) + goto bad_exit; + + erc = ENOMEM; + if (cnt >= ACL_MAX_ENTRIES) + goto bad_exit; + + ace = &acl->acl_entry[cnt]; + ace->ae_tag = ACL_UNDEFINED_TAG; + ace->ae_id = ACL_UNDEFINED_ID; + ace->ae_perm = ACL_PERM_NONE; + acl->acl_cnt++; + *acep = ace; + + return 0; + +bad_exit: + setoserror(erc); + if (acep) + *acep = NULL; + return -1; +} + +/* acl_entry_compare --- called from qsort(3), primary key is ae_tag, +** secondary key is ae_id. Thus the order will be: +** ACL_USER_OBJ +** ACL_USER +** ACL_GROUP_OBJ +** ACL_GROUP +** ACL_MASK +** ACL_OTHER_OBJ +*/ + +static int +acl_entry_compare (const void *va, const void *vb) +{ + const acl_entry_t a = (acl_entry_t) va, + b = (acl_entry_t) vb; + + if (a->ae_tag == b->ae_tag) + return (a->ae_id - b->ae_id); + + return (a->ae_tag - b->ae_tag); +} + +/* acl_entry_sort --- sort the acl entries so that we're at least consistent. +** No validity checks are done. Use acl_valid() for that. +*/ + +void +acl_entry_sort (acl_t acl) +{ + /* is there anything to do? */ + if (acl->acl_cnt <= 1) + return; + + qsort (acl->acl_entry, acl->acl_cnt, sizeof (acl->acl_entry[0]), + acl_entry_compare); +} + +int +acl_add_perm (acl_permset_t permset_d, acl_perm_t perm) +{ + if (perm != ACL_READ && perm != ACL_WRITE && perm != ACL_EXECUTE) { + setoserror(EINVAL); + return -1; + } + + if(permset_d == NULL) { + setoserror(EINVAL); + return -1; + } + + *permset_d |= perm; + return 0; +} + +int +acl_clear_perms (acl_permset_t permset_d) +{ + if(permset_d == NULL) { + setoserror(EINVAL); + return -1; + } + *permset_d = 0; + return 0; +} + +int +acl_delete_perm(acl_permset_t permset_d, acl_perm_t perm) +{ + if (perm != ACL_READ && perm != ACL_WRITE && perm != ACL_EXECUTE) { + setoserror(EINVAL); + return -1; + } + + if(permset_d == NULL) { + setoserror(EINVAL); + return -1; + } + + *permset_d &= ~perm; + return 0; +} + +int +acl_get_perm(acl_permset_t permset, acl_perm_t perm) +{ + return (*permset & perm); +} + + +int +acl_get_permset (acl_entry_t entry_d, acl_permset_t *permset_p) +{ + if(entry_d == NULL){ + setoserror(EINVAL); + return -1; + } + + *permset_p = &entry_d->ae_perm; + return 0; +} + +/* + * Extract ae_id and dynamically allocate memory for it. + * This is so that a call to acl_free() on the returned + * qualifier will work as the Posix standard suggests. + */ +void * +acl_get_qualifier (acl_entry_t entry_d) +{ + uid_t *retval; + + if(entry_d == NULL){ + setoserror(EINVAL); + return NULL; + } + + if ( entry_d->ae_tag != ACL_USER && + entry_d->ae_tag != ACL_GROUP ) { + setoserror(EINVAL); + return NULL; + } + + retval = malloc(sizeof(uid_t)); + if (retval == NULL) { + setoserror(ENOMEM); + return NULL; + } + *retval = entry_d->ae_id; + return retval; +} + +int +acl_get_tag_type (acl_entry_t entry_d, acl_tag_t *tag_p) +{ + if(entry_d == NULL){ + setoserror(EINVAL); + return -1; + } + + switch ( entry_d->ae_tag ) { + case ACL_USER: + case ACL_USER_OBJ: + case ACL_GROUP: + case ACL_GROUP_OBJ: + case ACL_OTHER_OBJ: + case ACL_MASK: + // only change the value if it is valid + *tag_p = entry_d->ae_tag; + return 0; + break; + default: + setoserror(EINVAL); + return -1; + } +} + +acl_t +acl_init (int count) +{ + acl_t a; + if((count > ACL_MAX_ENTRIES) || (count < 0)) { + setoserror(EINVAL); + return NULL; + } + else { + if( (a = (struct acl *)malloc(sizeof(struct acl))) == NULL){ + setoserror(ENOMEM); + return NULL; + } + a->acl_cnt = 0; + return a; + } + +} + +int +acl_set_permset (acl_entry_t entry_d, acl_permset_t permset_d) +{ + if( (entry_d == NULL) || (permset_d == NULL) ){ + setoserror(EINVAL); + return -1; + } + + if(*permset_d & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE)) { + setoserror(EINVAL); + return -1; + } + + entry_d->ae_perm = *permset_d; + return 0; +} + +int +acl_set_qualifier (acl_entry_t entry_d, const void *qual_p) +{ + if(entry_d == NULL || qual_p == NULL){ + setoserror(EINVAL); + return -1; + } + + if(entry_d->ae_tag != ACL_GROUP && + entry_d->ae_tag != ACL_USER) { + setoserror(EINVAL); + return -1; + } + entry_d->ae_id = *((uid_t *)qual_p); + return 0; +} + +int +acl_set_tag_type (acl_entry_t entry_d, acl_tag_t tag_type) +{ + if(entry_d == NULL){ + setoserror(EINVAL); + return -1; + } + + switch (tag_type) { + case ACL_USER: + case ACL_USER_OBJ: + case ACL_GROUP: + case ACL_GROUP_OBJ: + case ACL_OTHER_OBJ: + case ACL_MASK: + entry_d->ae_tag = tag_type; + break; + default: + setoserror(EINVAL); + return -1; + } + return 0; +} + + +/* + * system calls + * + * NOTE: + * This is a temporary solution until a suitable call is + * supported in libc. + * The code needs to be extended for different system call + * numberings for different architectures. + */ + +#include + +/* Need to use the kernel system call numbering + * for the particular architecture. + * Assumes ia32 library not used on ia64. + */ +#if __i386__ +# define HAVE_ACL_SYSCALL 1 +# ifndef SYS__acl_get +# define SYS__acl_get 251 +# endif +# ifndef SYS__acl_set +# define SYS__acl_set 252 +# endif +#elif __ia64__ +# define HAVE_ACL_SYSCALL 1 +# ifndef SYS__acl_get +# define SYS__acl_get 1261 +# endif +# ifndef SYS__acl_set +# define SYS__acl_set 1262 +# endif +#else +# define HAVE_ACL_SYSCALL 0 +#endif + +int +acl_get(const char *path, int fdes, struct acl *acl, struct acl *dacl) +{ +#if HAVE_ACL_SYSCALL + return syscall(SYS__acl_get, path, fdes, acl, dacl); +#else + fprintf(stderr, "libacl: acl_get system call not defined " + "for this architecture\n"); + return 0; +#endif +} + +int +acl_set(const char *path, int fdes, struct acl *acl, struct acl *dacl) +{ +#if HAVE_ACL_SYSCALL + return syscall(SYS__acl_set, path, fdes, acl, dacl); +#else + fprintf(stderr, "libacl: acl_set system call not defined " + "for this architecture\n"); + return 0; +#endif +} diff -rNu linux-2.4.7/cmd/acl/man/CVS/Entries linux-2.4-xfs/cmd/acl/man/CVS/Entries --- linux-2.4.7/cmd/acl/man/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/CVS/Entries Thu Jul 5 11:43:40 2001 @@ -0,0 +1,2 @@ +/Makefile/1.1/Mon Jan 15 10:28:46 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/acl/man/CVS/Entries.Log linux-2.4-xfs/cmd/acl/man/CVS/Entries.Log --- linux-2.4.7/cmd/acl/man/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/CVS/Entries.Log Thu Jul 5 11:43:41 2001 @@ -0,0 +1,4 @@ +A D/man1//// +A D/man2//// +A D/man3//// +A D/man5//// diff -rNu linux-2.4.7/cmd/acl/man/CVS/Repository linux-2.4-xfs/cmd/acl/man/CVS/Repository --- linux-2.4.7/cmd/acl/man/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/CVS/Repository Thu Jul 5 11:43:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/acl/man diff -rNu linux-2.4.7/cmd/acl/man/CVS/Root linux-2.4-xfs/cmd/acl/man/CVS/Root --- linux-2.4.7/cmd/acl/man/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/CVS/Root Thu Jul 5 11:43:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/acl/man/Makefile linux-2.4-xfs/cmd/acl/man/Makefile --- linux-2.4.7/cmd/acl/man/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/Makefile Mon Jan 15 04:28:46 2001 @@ -0,0 +1,41 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +SUBDIRS = man1 man2 man3 man5 + +default install install-dev : $(SUBDIRS) + $(SUBDIRS_MAKERULE) + +include $(BUILDRULES) diff -rNu linux-2.4.7/cmd/acl/man/man1/CVS/Entries linux-2.4-xfs/cmd/acl/man/man1/CVS/Entries --- linux-2.4.7/cmd/acl/man/man1/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man1/CVS/Entries Thu Jul 5 11:43:40 2001 @@ -0,0 +1,3 @@ +/Makefile/1.1/Mon Jan 15 10:28:46 2001/-ko/ +/chacl.1/1.2/Thu Apr 26 06:38:30 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/acl/man/man1/CVS/Repository linux-2.4-xfs/cmd/acl/man/man1/CVS/Repository --- linux-2.4.7/cmd/acl/man/man1/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man1/CVS/Repository Thu Jul 5 11:43:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/acl/man/man1 diff -rNu linux-2.4.7/cmd/acl/man/man1/CVS/Root linux-2.4-xfs/cmd/acl/man/man1/CVS/Root --- linux-2.4.7/cmd/acl/man/man1/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man1/CVS/Root Thu Jul 5 11:43:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/acl/man/man1/Makefile linux-2.4-xfs/cmd/acl/man/man1/Makefile --- linux-2.4.7/cmd/acl/man/man1/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man1/Makefile Mon Jan 15 04:28:46 2001 @@ -0,0 +1,49 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +MAN_SECTION = 1 + +MAN_PAGES = $(shell echo *.$(MAN_SECTION)) +MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) +LSRCFILES = $(MAN_PAGES) + +default : $(MAN_PAGES) + +include $(BUILDRULES) + +install : default + $(INSTALL) -m 755 -d $(MAN_DEST) + $(INSTALL_MAN) +install-dev: diff -rNu linux-2.4.7/cmd/acl/man/man1/chacl.1 linux-2.4-xfs/cmd/acl/man/man1/chacl.1 --- linux-2.4.7/cmd/acl/man/man1/chacl.1 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man1/chacl.1 Thu Apr 26 01:38:30 2001 @@ -0,0 +1,94 @@ +.TH chacl 1 +.SH NAME +chacl \- change or list the access control list of a file or directory +.SH SYNOPSIS +.B chacl acl pathname... +.br +.B chacl -b acl dacl pathname... +.br +.B chacl -d dacl pathname... +.br +.B chacl -R pathname... +.br +.B chacl -D pathname... +.br +.B chacl -B pathname... +.br +.B chacl -l pathname... +.br +.SH DESCRIPTION +.I chacl\^ +changes or lists the Access Control List(s) for a file or directory. +The \f4-b\f1 flag indicates that there are two ACLs to change, +the first is the +file access ACL and the second the directory default ACL. The \f4-d\f1 flag is +used to set only the default ACL of a directory. +The ACL(s) specified are applied to each file in the \f4pathname\f1 arguments. +The \f4-R\f1 and \f4-D\f1 +flags are used to remove the file access ACL and directory default ACL respectively, +the \f4-B\f1 flag will remove all ACLs. +The \f4-l\f1 flag is used to list the access ACL and possibly the +default ACL associated with the specified files or directories. +.P +Each ACL is a string which is processed via \f4acl_from_text\fP(3). +These strings are made up of comma separated clauses each of which +is of the form, tag:name:perm. Where \f4tag\fP can be +.TP +"user" (or "u") +indicating that the entry is a user ACL entry. +.TP +"group" (or "g") +indicating that the entry is a group ACL entry. +.TP +"other" (or "o") +indicating that the entry is an other ACL entry. +.TP +"mask" (or "m") +indicating that the entry is a mask ACL entry. +.P +\f4name\fP is a string which is the user or group name for the ACL entry. +A null \f4name\fP in a user or group ACL entry indicates the file's +owner or file's group. +\f4perm\fP is the string "rwx" where each of the entries may be replaced +by a "-" indicating no access of that type, e.g. "r-x", "--x", "---". +.SH EXAMPLES + +A minimum ACL: +\f3chacl u::rwx,g::r-x,o::r-- file\fP +.br +The file ACL is set so that the file's owner has rwx, the file's +group has read and execute, and others have read only access to the file. +.P +An ACL that is not a minimum ACL, that is, one that specifies +a user or group other than the file's owner or owner's group, +must contain a mask entry: +\f4chacl u::rwx,g::r-x,o::r--,u:guest:r--,m::r-x file1 file2\fP +.P +To set the default and access ACLs on newdir to be the +same as on oldir, you could type: +.P +\f4chacl -b `chacl -l olddir | sed -e 's/.*\\[//' -e 's#/# #' -e 's/]$//'` newdir +\fP +.SH CAUTIONS +\f4chacl\fP can replace the existing ACL. To add or delete entries, you +must first do \f4chacl -l\fP to get the existing ACL, and use the output +to form the arguments to \f4chacl\fP. +.P + +Changing the permission bits of a file will change the file access ACL settings +(see \f4chmod\fP(1)). However, file-creation mode masks (\f4umask\fP(1)) will +not affect the access ACL settings of files created using directory +default ACLs. +.P +ACLs are filesystem extended attributes and are not typically archived +or restored using conventional archiving utilities. +See \f4attr\fP(1) for more information +about Extended Attributes and see \f4xfsdump\fP(8) +for a method to back them up. +.SH SEE ALSO +acl_from_text(3), +umask(1), +xfsdump(8). +.SH CAVEATS +This command is likely to be deprecated when a standard file-system +independent ACL library is available. diff -rNu linux-2.4.7/cmd/acl/man/man2/CVS/Entries linux-2.4-xfs/cmd/acl/man/man2/CVS/Entries --- linux-2.4.7/cmd/acl/man/man2/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man2/CVS/Entries Thu Jul 5 11:43:40 2001 @@ -0,0 +1,4 @@ +/Makefile/1.2/Tue Jan 30 05:42:55 2001/-ko/ +/acl_get.2/1.3/Wed Jun 13 01:49:41 2001/-ko/ +/acl_set.2/1.3/Wed Jun 13 01:49:41 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/acl/man/man2/CVS/Repository linux-2.4-xfs/cmd/acl/man/man2/CVS/Repository --- linux-2.4.7/cmd/acl/man/man2/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man2/CVS/Repository Thu Jul 5 11:43:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/acl/man/man2 diff -rNu linux-2.4.7/cmd/acl/man/man2/CVS/Root linux-2.4-xfs/cmd/acl/man/man2/CVS/Root --- linux-2.4.7/cmd/acl/man/man2/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man2/CVS/Root Thu Jul 5 11:43:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/acl/man/man2/Makefile linux-2.4-xfs/cmd/acl/man/man2/Makefile --- linux-2.4.7/cmd/acl/man/man2/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man2/Makefile Mon Jan 29 23:42:55 2001 @@ -0,0 +1,48 @@ +# +# Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +MAN_SECTION = 2 + +MAN_PAGES = $(shell echo *.$(MAN_SECTION)) +MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) +LSRCFILES = $(MAN_PAGES) + +default install : $(MAN_PAGES) + +include $(BUILDRULES) + +install-dev : default + $(INSTALL) -m 755 -d $(MAN_DEST) + $(INSTALL_MAN) diff -rNu linux-2.4.7/cmd/acl/man/man2/acl_get.2 linux-2.4-xfs/cmd/acl/man/man2/acl_get.2 --- linux-2.4.7/cmd/acl/man/man2/acl_get.2 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man2/acl_get.2 Tue Jun 12 20:49:41 2001 @@ -0,0 +1,64 @@ +'\"macro stdmacro +.TH ACL_GET 2 +.SH NAME +acl_get \- get an XFS access or default ACL +.Op c p a +.SH C SYNOPSIS +.PP +.sp +.nf +.B #include +.sp +.B "int acl_get (const char *path, int fd, struct acl *acl," +.B " struct acl *dacl);" +.Op +.SH DESCRIPTION +The +.I acl_get +system call allows a user to retrieve an access or default ACL for +a file/directory given either a file descriptor or path name. +The +.I path +argument and +.I fd +argument provide alternate ways to specify the same file. +The +.I acl +argument refers to the access ACL and should be preallocated. +The +.I dacl +argument refers to the default ACL and should be preallocated. +.P +This system call is called from the POSIX ACL functions +of +.br +acl_get_fd (3) +and +.br +acl_get_file (3). +Therefore, direct calling of this system call is not necessary +or suggested. +.SH CAVEAT +This ACL system call can be considered a temporary prototype solution +and may be altered for a more generic ACL solution in the future. +.SH DIAGNOSTICS +.I acl_get +will return 0 on success, and a negated error code on any failure. +.PP +.B -EINVAL +.IP +Invalid arguments such as +.I acl +and +.I dacl +both being NULL, or +.I fd +and +.I path +either both NULL or both not NULL. +.SH "SEE ALSO" +acl(5), +.br +acl_get_fd(3), acl_get_file(3), +.br +chacl(1). diff -rNu linux-2.4.7/cmd/acl/man/man2/acl_set.2 linux-2.4-xfs/cmd/acl/man/man2/acl_set.2 --- linux-2.4.7/cmd/acl/man/man2/acl_set.2 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man2/acl_set.2 Tue Jun 12 20:49:41 2001 @@ -0,0 +1,64 @@ +'\"macro stdmacro +.TH ACL_SET 2 +.SH NAME +acl_set \- set an XFS access or default ACL +.Op c p a +.SH C SYNOPSIS +.PP +.sp +.nf +.B #include +.sp +.B "int acl_set (const char *path, int fd, struct acl *acl," +.B " struct acl *dacl);" +.Op +.SH DESCRIPTION +The +.I acl_set +system call allows a user to store an access or default ACL for +a file/directory given either a file descriptor or path name. +The +.I path +argument and +.I fd +argument provide alternate ways to specify the same file. +The +.I acl +argument refers to the access ACL and should be preallocated. +The +.I dacl +argument refers to the default ACL and should be preallocated. +.P +This system call is called from the POSIX ACL functions +of +.br +acl_set_fd (3) +and +.br +acl_set_file (3). +Therefore, direct calling of this system call is not necessary +or suggested. +.SH CAVEAT +This ACL system call can be considered a temporary prototype solution +and may be altered for a more generic ACL solution in the future. +.SH DIAGNOSTICS +.I acl_set +will return 0 on success, and a negated error code on any failure. +.PP +.B -EINVAL +.IP +Invalid arguments such as +.I acl +and +.I dacl +both being NULL, or +.I fd +and +.I path +either both NULL or both not NULL. +.SH "SEE ALSO" +acl(5), +.br +acl_set_fd(3), acl_set_file(3), +.br +chacl(1). diff -rNu linux-2.4.7/cmd/acl/man/man3/CVS/Entries linux-2.4-xfs/cmd/acl/man/man3/CVS/Entries --- linux-2.4.7/cmd/acl/man/man3/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man3/CVS/Entries Thu Jul 5 11:43:40 2001 @@ -0,0 +1,12 @@ +/Makefile/1.2/Tue Jan 30 05:42:55 2001/-ko/ +/acl_copy_ext.3/1.3/Wed Jun 13 01:49:41 2001/-ko/ +/acl_delete_def_file.3/1.3/Wed Jun 13 01:49:41 2001/-ko/ +/acl_dup.3/1.3/Wed Jun 13 01:49:41 2001/-ko/ +/acl_free.3/1.3/Wed Jun 13 01:49:41 2001/-ko/ +/acl_from_text.3/1.3/Wed Jun 13 01:49:41 2001/-ko/ +/acl_get_fd.3/1.4/Wed Jun 13 01:49:41 2001/-ko/ +/acl_get_file.3/1.4/Wed Jun 13 01:49:41 2001/-ko/ +/acl_set_compat.3/1.2/Wed Jun 13 01:49:41 2001/-ko/ +/acl_size.3/1.3/Wed Jun 13 01:49:41 2001/-ko/ +/acl_valid.3/1.3/Wed Jun 13 01:49:41 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/acl/man/man3/CVS/Repository linux-2.4-xfs/cmd/acl/man/man3/CVS/Repository --- linux-2.4.7/cmd/acl/man/man3/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man3/CVS/Repository Thu Jul 5 11:43:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/acl/man/man3 diff -rNu linux-2.4.7/cmd/acl/man/man3/CVS/Root linux-2.4-xfs/cmd/acl/man/man3/CVS/Root --- linux-2.4.7/cmd/acl/man/man3/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man3/CVS/Root Thu Jul 5 11:43:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/acl/man/man3/Makefile linux-2.4-xfs/cmd/acl/man/man3/Makefile --- linux-2.4.7/cmd/acl/man/man3/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man3/Makefile Mon Jan 29 23:42:55 2001 @@ -0,0 +1,48 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +MAN_SECTION = 3 + +MAN_PAGES = $(shell echo *.$(MAN_SECTION)) +MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) +LSRCFILES = $(MAN_PAGES) + +default install : $(MAN_PAGES) + +include $(BUILDRULES) + +install-dev : default + $(INSTALL) -m 755 -d $(MAN_DEST) + $(INSTALL_MAN) diff -rNu linux-2.4.7/cmd/acl/man/man3/acl_copy_ext.3 linux-2.4-xfs/cmd/acl/man/man3/acl_copy_ext.3 --- linux-2.4.7/cmd/acl/man/man3/acl_copy_ext.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man3/acl_copy_ext.3 Tue Jun 12 20:49:41 2001 @@ -0,0 +1,44 @@ +.TH ACL_COPY_EXT 3 +.SH NAME +acl_copy_ext, acl_copy_int \- copy ACL from system to user space or from user to system space +.SH SYNOPSIS +.B #include +.PP +.B "ssize_t acl_copy_ext(void *bufp, struct acl *aclp, ssize_t size);" +.br +.B struct acl *acl_copy_int(void *bufp); +.SH DESCRIPTION +\f2acl_copy_ext\fP sets \f2*bufp\fP to \f2*aclp\fP if the arguments are valid. +\f2acl_copy_int\fP allocates a \f2struct acl\fP and copies the \f2struct acl\fP +pointed to by +\f2*bufp\fP into it, if the arguments are valid. The storage should +be freed by calling \f2acl_free\fP(3) when no longer needed. +.PP +In the +POSIX specifications, the internal form of an ACL may be different from the +external form, hence the need for these functions. In IRIX, both forms are +the same. +.SH RETURN VALUES +.I acl_copy_ext +returns \f2sizeof(struct acl)\fP in the normal case, +or -1 if \f2aclp\fP is null. +.PP +.I acl_copy_int +returns \f2aclp\fP in the normal case or \f2(struct acl *)0\fP if the +arguments are invalid. +.SH ERRORS +.I acl_copy_ext: +.TP 16 +EINVAL +\f2aclp\fP is null or \f2bufp\fP is null or \f2size\fP is 0 or negative. +.TP 16 +ERANGE +\f2size\fP is less than \f2sizeof(struct acl)\fP +.PP +.I acl_copy_int: +.TP 16 +EINVAL +\f2bufp\fP is null +.TP 16 +ENOMEM +memory allocation failure diff -rNu linux-2.4.7/cmd/acl/man/man3/acl_delete_def_file.3 linux-2.4-xfs/cmd/acl/man/man3/acl_delete_def_file.3 --- linux-2.4.7/cmd/acl/man/man3/acl_delete_def_file.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man3/acl_delete_def_file.3 Tue Jun 12 20:49:41 2001 @@ -0,0 +1,53 @@ +.TH ACL_DELETE_DEF_FILE 3 +.SH NAME +acl_delete_def_file \- delete the default ACL for a named directory +.SH SYNOPSIS +.B #include +.PP +.B int acl_delete_def_file(const char *path); +.SH DESCRIPTION +Deletes the default ACL associated with the directory specified in \f2path\fP. +The effective UID of the process must match the owner of the directory +or the process must have appropriate privilege to delete the +default ACL from +\f2path_p\fP. +If capabilities are not enabled, only the superuser can delete the +default ACL from a directory not owned by the effective UID. +If +.B _POSIX_CAP +is in effect, then the appropriate capability shall include CAP_FOWNER. +In addition, if +.B _POSIX_MAC +is in effect, then the process must have MAC write access to +the directory. +.P +If the argument +\f2path\fP +is not a directory, then the function fails. +.SH RETURN VALUES +.I acl_delete_def_file +returns 0 if successful, -1 otherwise. +.SH ERRORS +.TP 16 +EACCESS +Search permission is denied for a component +of the path prefix or the object exists and the process does not have +appropriate access rights. +.TP 16 +ENAMETOOLONG +The length of the pathname argument is greater than PATH_MAX, or some +component of it is greater than NAME_MAX. +.TP 16 +ENOENT +The directory does not exist or \f2path\fP points to an empty string. +.TP 16 +ENOTDIR +\f2path\fP is not a directory. +.TP 16 +EPERM +The process does not have appropriate privilege to +perform the operation to delete the default ACL. +.TP 16 +EROFS +This function requires modification of a file system which is currently +read-only. diff -rNu linux-2.4.7/cmd/acl/man/man3/acl_dup.3 linux-2.4-xfs/cmd/acl/man/man3/acl_dup.3 --- linux-2.4.7/cmd/acl/man/man3/acl_dup.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man3/acl_dup.3 Tue Jun 12 20:49:41 2001 @@ -0,0 +1,19 @@ +.TH ACL_DUP 3 +.SH NAME +acl_dup \- make a copy of an ACL +.SH SYNOPSIS +.B #include +.PP +.B acl_t acl_dup( acl_t acl); +.SH DESCRIPTION +Returns a pointer to an allocated ACL that is a copy of the ACL supplied +as an argument. +.SH RETURN VALUES +Returns a pointer or null. +.SH ERRORS +.TP 16 +EINVAL +\f2aclp\fP is null. +.TP 16 +ENOMEM +allocation of the \f2struct acl\fP failed. diff -rNu linux-2.4.7/cmd/acl/man/man3/acl_free.3 linux-2.4-xfs/cmd/acl/man/man3/acl_free.3 --- linux-2.4.7/cmd/acl/man/man3/acl_free.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man3/acl_free.3 Tue Jun 12 20:49:41 2001 @@ -0,0 +1,14 @@ +.TH ACL_FREE 3 +.SH NAME +acl_free \- free allocated memory +.SH SYNOPSIS +.B #include +.PP +.B int acl_free( void *obj_p); +.SH DESCRIPTION +Free memory allocated by ACL interface calls. +This routine is present for POSIX compliance, it is simply a wrapper +for \f2free\fP(3c). +.SH RETURN VALUES +.I acl_free +returns 0. diff -rNu linux-2.4.7/cmd/acl/man/man3/acl_from_text.3 linux-2.4-xfs/cmd/acl/man/man3/acl_from_text.3 --- linux-2.4.7/cmd/acl/man/man3/acl_from_text.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man3/acl_from_text.3 Tue Jun 12 20:49:41 2001 @@ -0,0 +1,62 @@ +.TH ACL_FROM_TEXT 3 +.SH NAME +acl_from_text, acl_to_short_text, acl_to_text \- convert a POSIX ACL string to a struct acl or +a struct acl to a POSIX ACL string +.SH SYNOPSIS +.B #include +.PP +.B acl_t acl_from_text(const char *argp); +.br +.B char * acl_to_short_text(struct acl * aclp, ssize_t *len_p); +.br +.B char * acl_to_text(struct acl * aclp, ssize_t *len_p); +.SH DESCRIPTION +These routines convert strings defined by the POSIX P1003.1e specifications +(see +.IR xfs_acl (1)) +to/from +.IR "struct acl" , +which is the internal +format for an +Access Control List. +.SH RETURN VALUES +\f2acl_from_text\fP returns a pointer to a \f2struct acl\fP +allocated by the routine or a NULL pointer in the case of a failure. +The acl should be freed when no longer needed by calling +.IR acl_free (3). +.PP +\f2acl_to_text\fP returns a pointer to a null terminated +character string allocated by the routine which is +a long form representation of the ACL, or a NULL pointer if an error +occurred. This string +should be freed when no longer needed by calling +.IR acl_free (3). +If the \f2len_p\fP argument is not NULL, then the length of the string +is returned in \f2ssize_t\fP pointed to by \f2len_p\fP. +.PP +\f2acl_to_short_text\fP is identical to \f2acl_to_text\fP, except that a +short form representation of the ACL is returned. +.SH ERRORS +.I acl_from_text: +.TP 16 +EINVAL +input text is invalid +.TP 16 +ENOMEM +could not allocate space for new acl +.PP +.I acl_to_short_text: +.TP 16 +EINVAL +input acl is invalid +.TP 16 +ENOMEM +could not allocate space for the return string +.PP +.I acl_to_text: +.TP 16 +EINVAL +input acl is invalid +.TP 16 +ENOMEM +could not allocate space for the return string diff -rNu linux-2.4.7/cmd/acl/man/man3/acl_get_fd.3 linux-2.4-xfs/cmd/acl/man/man3/acl_get_fd.3 --- linux-2.4.7/cmd/acl/man/man3/acl_get_fd.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man3/acl_get_fd.3 Tue Jun 12 20:49:41 2001 @@ -0,0 +1,97 @@ +.TH ACL_GET_FD 3 +.SH NAME +acl_get_fd, acl_set_fd \- get or set the ACL associated with an open file +.SH SYNOPSIS +.B #include +.PP +.B struct acl * acl_get_fd(int fd); +.br +.B int acl_set_fd(int fd, struct acl *aclp); +.SH DESCRIPTION +.I acl_get_fd +returns a pointer to an allocated \f2struct acl\fP associated with the +open file referred to by \f2fd\fP. +If +.B _POSIX_MAC +is in effect, then the process must have MAC read access to the object. +If no access ACL is associated with the \f2fd\fP, then the resultant ACL +is dependent on the ACL compatibility mode (see +.BR acl_set_compat (8) +). If \f2ACL_COMPAT_IRIXGET\f1 is +set then an ACL with a count of ACL_NOT_PRESENT is returned. Otherwise, +when no compatibility mode has been set, a mininum 3 ACE ACL based on the +file's mode is returned. +.PP +.I acl_set_fd +sets the ACL for the open file referred to by \f2fd\fP from the \f2struct acl\fP +pointed to by \f2aclp\fP. +The effective UID of the process must match the owner of the object or the +process must have appropriate privilege to set the access ACL on the +object. If +.B _POSIX_CAP +is in effect, then the appropriate capability must include CAP_FOWNER. +In addition, if +.B _POSIX_MAC +is in effect, then the process must have MAC write access to the object. +\f2acl_set_fd\fP +function will succeed only if the ACL +is valid as defined by the +\f2acl_valid\fP(3) +function. +.SH RETURN VALUES +.I acl_get_fd +returns a pointer to an allocated \f2struct acl\fP if successful, NULL otherwise. +The storage should be freed with a call to \f2acl_free\fP with the returned +pointer as an argument when it is no longer needed. +.PP +.I acl_set_fd +returns 0 if successful, -1 otherwise. +.SH ERRORS +.I acl_get_fd: +.TP 16 +EACCESS +Access to the object is denied. +.TP 16 +EBADF +\f2fd\fP is not a valid file descriptor. +.TP 16 +ENOMEM +allocation of the \f2struct acl\fP failed. +.TP 16 +ENOSYS +ACL support is not configured in kernel. +.TP 16 +EOPNOTSUPP (ENOTSUP) +ACL support is not available for given filesystem. +.PP +.I acl_set_fd: +.TP 16 +EACCESS +Access to the object is denied. +.TP 16 +EBADF +\f2fd\fP is not a valid file descriptor. +.TP 16 +EINVAL +The ACL is not valid or too large (too many entries). +.TP 16 +ENOSPC +The file system is full or some other resource needed for the ACL storage +is not available. +.TP 16 +ENOSYS +ACL support is not configured in kernel. +.TP 16 +EOPNOTSUPP (ENOTSUP) +ACL support is not available for given filesystem. +.TP 16 +EPERM +The process does not have appropriate privilege to +perform the operation to set the ACL. +.TP 16 +EROFS +This function requires modification of a file system which is currently +read-only. +.SH SEE ALSO +.BR acl_get_file (8), +.BR acl_set_compat (8). diff -rNu linux-2.4.7/cmd/acl/man/man3/acl_get_file.3 linux-2.4-xfs/cmd/acl/man/man3/acl_get_file.3 --- linux-2.4.7/cmd/acl/man/man3/acl_get_file.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man3/acl_get_file.3 Tue Jun 12 20:49:41 2001 @@ -0,0 +1,121 @@ +.TH ACL_GET_FILE 3 +.SH NAME +acl_get_file, acl_set_file \- get or set the ACL for a pathname +.SH SYNOPSIS +.B #include +.PP +.B struct acl * acl_get_file(const char *path, acl_type_t type); +.br +.B "int acl_set_file(const char *path, acl_type_t type, struct acl *aclp);" +.SH DESCRIPTION +.I acl_get_file +returns a pointer to an allocated \f2struct acl\fP associated with the +pathname pointed to by \f2path\fP. \f2type\fP determines whether the +default ACL (\f2type == ACL_TYPE_DEFAULT\fP) or access ACL (\f2type == ACL_TYPE_ACCESS\fP) is returned. The default ACL is available only for directories. +If +.B _POSIX_MAC +is in effect, then the process must have MAC read access to the object. +If no ACL is associated with the \f2path\fP, then the resultant ACL +is dependent on the ACL compatibility mode (see +.BR acl_set_compat (8) +). If \f2ACL_COMPAT_IRIXGET\f1 is +set then an ACL with a count of ACL_NOT_PRESENT is returned. +If no compatibility mode has been set and the ACL is an access ACL then +a mininum 3 ACE ACL based on the file's mode is returned. +If no compatibility mode has been set and the ACL is a default ACL then +an ACL with a count of zero entries is returned. +.PP +.I acl_set_file +sets the ACL of the specified pathname. \f2type\fP indicates which ACL, +default or access, is to be set. Only directories can have a default ACL. +If \f2type\fP is not valid, the call fails. +The ACL is first checked for validity by +\f2acl_valid\fP(3). +The effective UID of the process must match the owner of the object +or the process must have appropriate privilege to set the access ACL +or the default ACL on +\f2path\fP. +If +.B _POSIX_CAP +is in effect, then the appropriate capability must include CAP_FOWNER. +In addition, if +.B _POSIX_MAC +is in effect, then the process must have MAC write access to the object. +.SH RETURN VALUES +.I acl_get_file +a pointer to an allocated \f2struct acl\fP if successful, NULL otherwise. +The storage should be freed with a call to \f2acl_free\fP with the returned +pointer as an argument when it is no longer needed. +.PP +.I acl_set_file +returns 0 if successful, -1 otherwise. +.SH ERRORS +.I acl_get_file: +.TP 16 +EACCESS +Search permission is denied for a component +of the path prefix or the object exists and the process does not have +appropriate access rights. +.TP 16 +EINVAL +\f2type\fP is not valid +.TP 16 +ENAMETOLONG +The pathname or one of its components is too long. +.TP 16 +ENOENT +The named object does not exist or \f2path\fP points to an empty string. +.TP 16 +ENOMEM +allocation of the \f2struct acl\fP failed. +.TP 16 +ENOSYS +ACL support is not configured in kernel. +.TP 16 +EOPNOTSUPP (ENOTSUP) +ACL support is not available for given filesystem. +.TP 16 +ENOTDIR +A component of the path prefix is not a directory. +.PP +.I acl_set_file: +.TP 16 +EACCESS +Search permission is denied for a component +of the path prefix or the object exists and the process does not have +appropriate access rights. +.TP 16 +EINVAL +\f2aclp\fP points to an invalid ACL. +\f2type\fP is not either ACL_TYPE_ACCESS, or ACL_TYPE_DEFAULT. +The ACL is too large (too many entries). +.TP 16 +ENAMETOLONG +The pathname or one of its components is too long. +.TP 16 +ENOENT +The named object does not exist or \f2path\fP points to an empty string. +.TP 16 +ENOSPC +The file system is full or some other resource needed for the ACL storage +is not available. +.TP 16 +ENOSYS +ACL support is not configured in kernel. +.TP 16 +EOPNOTSUPP (ENOTSUP) +ACL support is not available for given filesystem. +.TP 16 +ENOTDIR +A component of the path prefix is not a directory. +.TP 16 +EPERM +The process does not have appropriate privilege to +perform the operation to set the ACL. +.TP 16 +EROFS +This function requires modification of a file system which is currently +read-only. +.SH SEE ALSO +.BR acl_get_fd (8), +.BR acl_set_compat (8). diff -rNu linux-2.4.7/cmd/acl/man/man3/acl_set_compat.3 linux-2.4-xfs/cmd/acl/man/man3/acl_set_compat.3 --- linux-2.4.7/cmd/acl/man/man3/acl_set_compat.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man3/acl_set_compat.3 Tue Jun 12 20:49:41 2001 @@ -0,0 +1,34 @@ +.TH ACL_SET_COMPAT 3 +.SH NAME +acl_set_compat \- set compatibility mode for ACL library +.SH SYNOPSIS +.B #include +.PP +.B void acl_set_compat(acl_compat_t compat_bits); +.SH DESCRIPTION +.I acl_set_compat +sets the compatibility mode for various IRIX and Linux ACL functionality. +The ACL semantics for IRIX even though they are based on the Posix 1003.1e +withdrawn ACL standard, are subtly different from the semantics of +ext2 ACLs and BSD ACLs. The default semantics used are that of the ext2 +Posix ACLs and a call to this function should only be made to gain +IRIX compatibility. +.PP +\f2Compat_bits\f1 is a bit-vector formed by or'ing compatiblity macros +with the prefix of \f2ACL_COMPAT_\f1. Each call to this function will +add to the current compatibility vector. Given a \f2compat_bits\f1 value +of zero will reset it. +If \f2compat_bits\f1 is set to \f2ACL_COMPAT_IRIXGET\f1 then the semantics for +.BR acl_get_fd (8) +and +.BR acl_get_file (8) +are changed in the cases where no ACL was ever explicitly set for +a file or directory. +Please refer to +.BR acl_get_fd (8) +and +.BR acl_get_file (8) +for a description of the differing semantics. +.SH SEE ALSO +.BR acl_get_fd (8), +.BR acl_get_file (8). diff -rNu linux-2.4.7/cmd/acl/man/man3/acl_size.3 linux-2.4-xfs/cmd/acl/man/man3/acl_size.3 --- linux-2.4.7/cmd/acl/man/man3/acl_size.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man3/acl_size.3 Tue Jun 12 20:49:41 2001 @@ -0,0 +1,18 @@ +.TH ACL_SIZE 3 +.SH NAME +acl_size \- return the size of an ACL +.SH SYNOPSIS +.B #include +.PP +.B ssize_t acl_size(struct acl *aclp); +.SH DESCRIPTION +Returns the size of an ACL pointed to by \f2aclp\fP. In IRIX ACLs are all +a fixed size, but the POSIX specifications allow for the possibility of +variable sized structures. +.SH RETURN VALUES +.I acl_size +returns \f2sizeof(struct acl)\fP or -1 if \f2aclp\fP is null. +.SH ERRORS +.TP 16 +EINVAL +\f2aclp\fP is null diff -rNu linux-2.4.7/cmd/acl/man/man3/acl_valid.3 linux-2.4-xfs/cmd/acl/man/man3/acl_valid.3 --- linux-2.4.7/cmd/acl/man/man3/acl_valid.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man3/acl_valid.3 Tue Jun 12 20:49:41 2001 @@ -0,0 +1,26 @@ +.TH ACL_VALID 3 +.SH NAME +acl_valid \- validate an ACL +.SH SYNOPSIS +.B #include +.PP +.B int acl_valid( struct acl *aclp); +.SH DESCRIPTION +Check that the format of an ACL is valid. +.PP +First, \f2aclp\fP must be non null. +The three required entries (ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER_OBJ) must +exist exactly once in the ACL. +If the ACL contains any ACL_USER, ACL_GROUP, or any implementation-defined +entries in the file group class, then one ACL_MASK entry is +required. The ACL may contain at most one ACL_MASK entry. +.PP +The qualifier field must be unique among all entries of the same +type. +.SH RETURN VALUES +.I acl_valid +returns 0 if the ACL is valid, -1 otherwise. +.SH ERRORS +.TP 16 +EINVAL +ACL is not valid. diff -rNu linux-2.4.7/cmd/acl/man/man5/CVS/Entries linux-2.4-xfs/cmd/acl/man/man5/CVS/Entries --- linux-2.4.7/cmd/acl/man/man5/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man5/CVS/Entries Thu Jul 5 11:43:41 2001 @@ -0,0 +1,3 @@ +/Makefile/1.1/Mon Jan 15 10:28:46 2001/-ko/ +/acl.5/1.4/Fri Jun 15 14:25:43 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/acl/man/man5/CVS/Repository linux-2.4-xfs/cmd/acl/man/man5/CVS/Repository --- linux-2.4.7/cmd/acl/man/man5/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man5/CVS/Repository Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/acl/man/man5 diff -rNu linux-2.4.7/cmd/acl/man/man5/CVS/Root linux-2.4-xfs/cmd/acl/man/man5/CVS/Root --- linux-2.4.7/cmd/acl/man/man5/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man5/CVS/Root Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/acl/man/man5/Makefile linux-2.4-xfs/cmd/acl/man/man5/Makefile --- linux-2.4.7/cmd/acl/man/man5/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man5/Makefile Mon Jan 15 04:28:46 2001 @@ -0,0 +1,50 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +MAN_SECTION = 5 + +MAN_PAGES = $(shell echo *.$(MAN_SECTION)) +MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) +LSRCFILES = $(MAN_PAGES) + + +default : $(MAN_PAGES) + +include $(BUILDRULES) + +install : default + $(INSTALL) -m 755 -d $(MAN_DEST) + $(INSTALL_MAN) +install-dev : diff -rNu linux-2.4.7/cmd/acl/man/man5/acl.5 linux-2.4-xfs/cmd/acl/man/man5/acl.5 --- linux-2.4.7/cmd/acl/man/man5/acl.5 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/acl/man/man5/acl.5 Fri Jun 15 09:25:43 2001 @@ -0,0 +1,122 @@ +.TH acl 5 +.SH NAME +acl \- Access Control Lists +.SH SYNOPSIS +\f3#include \fP +.SH DESCRIPTION +This desciption is for Access Control Lists (ACLs) as supported on +XFS file systems. +.P +ACLs provide a mechanism for finer grained access control than the traditional +UNIX discretionary access control mechanism. +An ACL is a list of users and/or groups and their access rights, which +is associated with a file or directory. ACLs are optional. In addition to +the ACL used to mediate access, a directory may have a second ACL which +defines the default initial ACL for files created in that directory. Files +have only the single access control ACL. +.P +At the interface to the library routines, ACLs are represented in a +\f2struct acl\fP which is defined in \f2\fP. +.Ex +.nf + #define ACL_MAX_ENTRIES 25 + + typedef ushort acl_perm_t; + typedef int acl_type_t; + typedef int acl_tag_t; + + struct acl_entry { + acl_tag_t ae_tag; + uid_t ae_id; + acl_perm_t ae_perm; + }; + typedef struct acl_entry * acl_entry_t; + + struct acl { + int acl_cnt; + struct acl_entry acl_entry[ACL_MAX_ENTRIES]; + }; +.fi +.Ee + +This is a fixed size structure with a variable number +of active \f2struct acl_entry\fP entries. The maximum number of entries is +\f2ACL_MAX_ENTRIES\fP which is currently defined to be 25. The number of +active entries is indicated in \f2acl_cnt\fP. +.P +A \f2struct acl_entry\fP consists of three fields, \f2ae_tag\fP, which +identifies the type of the entry, and is one of the following values (all +other values are invalid): +.TP 15 +\f2ACL_USER_OBJ\fP (0x01) +access permissions for the file's owner. +.TP 15 +\f2ACL_USER\fP (0x02) +access permissions for a user other than the owner. +.TP 15 +\f2ACL_GROUP_OBJ\fP (0x04) +access permissions for users with the same group as the file's group +.TP 15 +\f2ACL_GROUP\fP (0x08) +access permissions for other groups +.TP 15 +\f2ACL_MASK\fP (0x10) +mask entry +.TP 15 +\f2ACL_OTHER_OBJ\fP (0x20) +other entry. +.sp +The \f2ae_id\fP field of \f2struct acl_entry\fP specifies the UID or GID +for the entry. The \f2ae_perm\fP field specifies the permissions using +the following defined values: +.TP 15 +\f2ACL_READ\fP (0x04) +read access permitted +.TP 15 +\f2ACL_WRITE\fP (0x02) +write access permitted +.TP 15 +\f2ACL_EXECUTE\fP (0x01) +execute (search for directories) access permitted +.P +As with the basic permissions for a file, these may be or'ed together. +.P +Two types of ACLs are defined. \f2ACL_TYPE_ACCESS\fP (0) indicates that +the ACL is to be used in making access control decisions for the file +or directory with which it is associated. \f2ACL_TYPE_DEFAULT\fP (1) indicates +that the ACL is a default ACL. Default ACLs are associated only with +directories, and supply the initial ACL for a file created in that +directory. Note that file-creation mode masks do not affect the ACLs of +files created as a result of using directory default ACLs (see \f2umask\fP(1)). +ACLs are supplied using the \f2acl_get_file\fP(3c) and +\f2acl_set_file\fP(3c) calls. +.SH EXTERNAL REPRESENTATION +ACLs are represented in a standard format for human readable input / output. +Each ACL entry is specified as three colon separated fields. +ACL entries are separated by white space or new lines. +Everything after a "#" character +is considered a comment and is ignored to the end of the line. +The first field of an ACL entry is the entry type, which can be one of the following: +"user", "group", "other", "mask", "u", "g", "o", "m". +.P +The second field is a user name, numeric UID, group name, or numeric GID, depending +on the value of the first field. (\fIacl_from_text\fP(3c) supports only +the strings, not the numeric UID/GID values.) +If the second field is empty, it implies +that the ACL entry is for the owning user or group of the file. Mask and +other entries must have an empty second field. The third field is +the discretionary access permissions for this ACL entry. This may be +represented in two forms. The first is the string "rwx" where each letter +may be replaced by a "-" indicating no access of that type. +The parsing of this string by \f2acl_from_text\fP(3c) requires that +it be exactly as shown and not be reordered, e.g. rxw is not valid. +.P +Some programs allow a +second +form, the relative symbolic form (used for input). +The relative symbolic form is preceded by a ``+'' to indicate +additional access or a ``^'' to indicate that access is to be removed, +similarly to the inputs to the \fIchmod\fP(1) command. +The relative symbolic string is at least one character. +The symbolic string contains at most one each of the following +characters in any order: "r", "w", and "x". diff -rNu linux-2.4.7/cmd/attr/CVS/Entries linux-2.4-xfs/cmd/attr/CVS/Entries --- linux-2.4.7/cmd/attr/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/CVS/Entries Thu Jul 5 11:43:41 2001 @@ -0,0 +1,7 @@ +/Makefile/1.1/Mon Jan 15 03:18:30 2001/-ko/ +/Makepkgs/1.3/Thu Mar 29 06:30:35 2001/-ko/ +/README/1.1/Mon Jan 15 03:18:30 2001/-ko/ +/VERSION/1.5/Mon Jul 2 03:31:14 2001/-ko/ +/configure.in/1.4/Tue Jun 12 07:20:31 2001/-ko/ +/install-sh/1.1/Mon Jan 15 03:18:30 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/attr/CVS/Entries.Log linux-2.4-xfs/cmd/attr/CVS/Entries.Log --- linux-2.4.7/cmd/attr/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/CVS/Entries.Log Thu Jul 5 11:43:42 2001 @@ -0,0 +1,7 @@ +A D/attr//// +A D/build//// +A D/debian//// +A D/doc//// +A D/include//// +A D/libattr//// +A D/man//// diff -rNu linux-2.4.7/cmd/attr/CVS/Repository linux-2.4-xfs/cmd/attr/CVS/Repository --- linux-2.4.7/cmd/attr/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/CVS/Repository Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/attr diff -rNu linux-2.4.7/cmd/attr/CVS/Root linux-2.4-xfs/cmd/attr/CVS/Root --- linux-2.4.7/cmd/attr/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/CVS/Root Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/attr/Makefile linux-2.4-xfs/cmd/attr/Makefile --- linux-2.4.7/cmd/attr/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/Makefile Sun Jan 14 21:18:30 2001 @@ -0,0 +1,74 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = . +HAVE_BUILDDEFS = $(shell test -f $(TOPDIR)/include/builddefs && echo yes || echo no) + +ifeq ($(HAVE_BUILDDEFS), yes) +include $(TOPDIR)/include/builddefs +endif + +CONFIGURE = configure include/builddefs +LSRCFILES = configure configure.in Makepkgs install-sh README VERSION +LDIRT = config.* conftest* Logs/* built install.* install-dev.* *.gz + +SUBDIRS = include libattr attr man doc debian build + +default: $(CONFIGURE) +ifeq ($(HAVE_BUILDDEFS), no) + $(MAKE) -C . $@ +else + $(SUBDIRS_MAKERULE) +endif + +ifeq ($(HAVE_BUILDDEFS), yes) +include $(BUILDRULES) +else +clean: # if configure hasn't run, nothing to clean +endif + +$(CONFIGURE): configure.in include/builddefs.in VERSION + rm -f config.cache + autoconf + ./configure + +install: default + $(SUBDIRS_MAKERULE) + $(INSTALL) -m 755 -d $(PKG_DOC_DIR) + $(INSTALL) -m 644 README $(PKG_DOC_DIR) + +install-dev: default + $(SUBDIRS_MAKERULE) + +realclean distclean: clean + rm -f $(LDIRT) $(CONFIGURE) + [ ! -d Logs ] || rmdir Logs diff -rNu linux-2.4.7/cmd/attr/Makepkgs linux-2.4-xfs/cmd/attr/Makepkgs --- linux-2.4.7/cmd/attr/Makepkgs Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/Makepkgs Thu Mar 29 00:30:35 2001 @@ -0,0 +1,109 @@ +#! /bin/sh +# +# Make whichever packages have been requested. +# Defaults to RPMs. +# +LOGDIR=Logs + +type=rpm +verbose=false + +MAKE=${MAKE:-make} +test ! -z "$MAKE" && make=$MAKE + +for opt in $* +do + case "$opt" in + clean) + ;; # ignored, kept for backward compatibility + rpm) + type=rpm ;; + debian) + type=debian ;; + verbose) + verbose=true ;; + *) + echo "Usage: Makepkgs [verbose] [debian|rpm]"; exit 1 ;; + esac +done + +# start with a clean manifest +test -f files.rpm && rm -f files.rpm +test -f filesdevel.rpm && rm -f filesdevel.rpm + +test ! -d $LOGDIR && mkdir $LOGDIR +rm -rf $LOGDIR/* > /dev/null 2>&1 + +# build Debian packages, cleans itself before starting +SUDO=${SUDO:-sudo} +test ! -z "$SUDO" && sudo=$SUDO +if [ $type = debian ] ; then + LOGDEB=`pwd` + LOGDEB=../`basename $LOGDEB`.log + echo "== Debian build, log is $LOGDEB"; echo + if $verbose ; then + dpkg-buildpackage -r$SUDO | tee $LOGDEB + else + dpkg-buildpackage -r$SUDO > $LOGDEB + fi + exit 0 +fi + +# build RPM packages - manual clean before starting +echo "== clean, log is $LOGDIR/clean" +if $verbose ; then + $MAKE clean 2>&1 | tee $LOGDIR/clean +else + $MAKE clean > $LOGDIR/clean 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"$MAKE clean\" failed, see log in $LOGDIR/clean + tail $LOGDIR/clean + exit 1 +fi + +echo +echo "== configure, log is $LOGDIR/configure" +if $verbose ; then + autoconf 2>&1 | tee $LOGDIR/configure + ./configure 2>&1 | tee -a $LOGDIR/configure +else + autoconf > $LOGDIR/configure 2>&1 + ./configure >> $LOGDIR/configure 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"configure\" failed, see log in $LOGDIR/configure + tail $LOGDIR/configure + exit 1 +fi + +echo +echo "== default, log is $LOGDIR/default" +if $verbose ; then + $MAKE default 2>&1 | tee $LOGDIR/default +else + $MAKE default > $LOGDIR/default 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"$MAKE default\" failed, see log in $LOGDIR/default + tail $LOGDIR/default + exit 1 +fi + +echo +echo "== dist, log is $LOGDIR/dist" +[ ! -f .census ] && touch .census +if $verbose ; then + $MAKE -C build dist 2>&1 | tee $LOGDIR/dist +else + $MAKE -C build dist > $LOGDIR/dist 2>&1 +fi +if [ $? -ne 0 ] ; then + echo $MAKE dist failed, see log in $LOGDIR/dist + tail $LOGDIR/dist + exit 1 +else + grep '^Wrote:' $LOGDIR/dist | sed -e 's/\.\.\/\.\.\///' +fi + +exit 0 diff -rNu linux-2.4.7/cmd/attr/README linux-2.4-xfs/cmd/attr/README --- linux-2.4.7/cmd/attr/README Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/README Sun Jan 14 21:18:30 2001 @@ -0,0 +1,15 @@ +Extended attribute package README +_________________________________ + +See the file doc/INSTALL for build, installation and post- +install configuration steps. + +Refer to the attr(1) manual page for general extended attribute +(EA) information and references to other EA manual pages. + +For more information and details on how to contribute to the +XFS project see the web pages at: + http://oss.sgi.com/projects/xfs/ + +For more information on the build process, please refer to +the doc/PORTING document. diff -rNu linux-2.4.7/cmd/attr/VERSION linux-2.4-xfs/cmd/attr/VERSION --- linux-2.4.7/cmd/attr/VERSION Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/VERSION Sun Jul 1 22:31:14 2001 @@ -0,0 +1,7 @@ +# +# This file is used by configure to get version information +# +PKG_MAJOR=1 +PKG_MINOR=0 +PKG_REVISION=4 +PKG_BUILD=0 diff -rNu linux-2.4.7/cmd/attr/attr/CVS/Entries linux-2.4-xfs/cmd/attr/attr/CVS/Entries --- linux-2.4.7/cmd/attr/attr/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/attr/CVS/Entries Thu Jul 5 11:43:41 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Mon Jan 15 03:18:30 2001/-ko/ +/attr.c/1.1/Mon Jan 15 02:54:15 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/attr/attr/CVS/Repository linux-2.4-xfs/cmd/attr/attr/CVS/Repository --- linux-2.4.7/cmd/attr/attr/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/attr/CVS/Repository Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/attr/attr diff -rNu linux-2.4.7/cmd/attr/attr/CVS/Root linux-2.4-xfs/cmd/attr/attr/CVS/Root --- linux-2.4.7/cmd/attr/attr/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/attr/CVS/Root Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/attr/attr/Makefile linux-2.4-xfs/cmd/attr/attr/Makefile --- linux-2.4.7/cmd/attr/attr/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/attr/Makefile Sun Jan 14 21:18:30 2001 @@ -0,0 +1,48 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = attr +CFILES = attr.c +LLDLIBS = $(LIBATTR) +LLDFLAGS = -L$(TOPDIR)/libattr + +default: $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_SBIN_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/attr/attr/attr.c linux-2.4-xfs/cmd/attr/attr/attr.c --- linux-2.4.7/cmd/attr/attr/attr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/attr/attr.c Sun Jan 14 20:54:15 2001 @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Exercise the attribute storage mechanism in the kernel. + */ + +#define SETOP 1 /* do a SET operation */ +#define GETOP 2 /* do a GET operation */ +#define REMOVEOP 3 /* do a REMOVE operation */ +#define LISTOP 4 /* do a LIST operation */ + +#define BUFSIZE (64*1024) /* buffer size for LIST operations */ + +void +usage(char *progname) +{ + fprintf(stderr, "usage:\t%s [-LRq] -s attrname [-V attrvalue] pathname\t# set value\n", + progname); + fprintf(stderr, "\t%s [-LRq] -g attrname pathname\t\t\t# get value\n", + progname); + fprintf(stderr, "\t%s [-LRq] -r attrname pathname\t\t\t# remove attr\n", + progname); + fprintf(stderr, "\t%s [-LRq] -l pathname\t\t\t\t# list attrs \n", + progname); + fprintf(stderr, "\t-s accepts a value from stdin and -g writes a value to stdout\n"); + exit(1); +} + + +int +main(int argc, char **argv) +{ + char *attrname, *attrvalue, *filename, *buffer; + int attrlength; + int opflag, ch, error, follow, verbose, rootflag, i; + attrlist_t *alist; + attrlist_ent_t *aep; + attrlist_cursor_t cursor; + + /* + * Pick up and validate the arguments. + */ + verbose = 1; + follow = opflag = rootflag = 0; + attrname = attrvalue = NULL; + while ((ch = getopt(argc, argv, "s:V:g:r:lqLR")) != EOF) { + switch (ch) { + case 's': + if ((opflag != 0) && (opflag != SETOP)) { + fprintf(stderr, + "Only one of -s, -g, -r, or -l allowed\n"); + usage(argv[0]); + } + opflag = SETOP; + attrname = optarg; + break; + case 'V': + if ((opflag != 0) && (opflag != SETOP)) { + fprintf(stderr, + "-V only allowed with -s\n"); + usage(argv[0]); + } + opflag = SETOP; + attrvalue = optarg; + break; + case 'g': + if (opflag) { + fprintf(stderr, + "Only one of -s, -g, -r, or -l allowed\n"); + usage(argv[0]); + } + opflag = GETOP; + attrname = optarg; + break; + case 'r': + if (opflag) { + fprintf(stderr, + "Only one of -s, -g, -r, or -l allowed\n"); + usage(argv[0]); + } + opflag = REMOVEOP; + attrname = optarg; + break; + case 'l': + if (opflag) { + fprintf(stderr, + "Only one of -s, -g, -r, or -l allowed\n"); + usage(argv[0]); + } + opflag = LISTOP; + break; + case 'L': + follow++; + break; + case 'R': + rootflag++; + break; + case 'q': + verbose = 0; + break; + default: + fprintf(stderr, "Unrecognized option: %c\n", (char)ch); + usage(argv[0]); + break; + } + } + if (optind != argc-1) { + fprintf(stderr, "A filename to operate on is required\n"); + usage(argv[0]); + } + filename = argv[optind]; + + /* + * Break out into option-specific processing. + */ + switch (opflag) { + case SETOP: + if (attrvalue == NULL) { + attrvalue = malloc(ATTR_MAX_VALUELEN); + if (attrvalue == NULL) { + perror("malloc"); + exit(1); + } + attrlength = + fread(attrvalue, 1, ATTR_MAX_VALUELEN, stdin); + } else { + attrlength = strlen(attrvalue); + } + error = attr_set(filename, attrname, attrvalue, + attrlength, + (!follow ? ATTR_DONTFOLLOW : 0) | + (rootflag ? ATTR_ROOT : 0)); + if (error) { + perror("attr_set"); + fprintf(stderr, "Could not set \"%s\" for %s\n", + attrname, filename); + exit(1); + } + if (verbose) { + printf("Attribute \"%s\" set to a %d byte value " + "for %s:\n", + attrname, attrlength, filename); + fwrite(attrvalue, 1, attrlength, stdout); + printf("\n"); + } + break; + + case GETOP: + attrvalue = malloc(ATTR_MAX_VALUELEN); + if (attrvalue == NULL) { + perror("malloc"); + exit(1); + } + attrlength = ATTR_MAX_VALUELEN; + error = attr_get(filename, attrname, attrvalue, + &attrlength, + (!follow ? ATTR_DONTFOLLOW : 0) | + (rootflag ? ATTR_ROOT : 0)); + if (error) { + perror("attr_get"); + fprintf(stderr, "Could not get \"%s\" for %s\n", + attrname, filename); + exit(1); + } + if (verbose) { + printf("Attribute \"%s\" had a %d byte value for %s:\n", + attrname, attrlength, filename); + } + fwrite(attrvalue, 1, attrlength, stdout); + if (verbose) { + printf("\n"); + } + break; + + case REMOVEOP: + error = attr_remove(filename, attrname, + (!follow ? ATTR_DONTFOLLOW : 0) | + (rootflag ? ATTR_ROOT : 0)); + if (error) { + perror("attr_remove"); + fprintf(stderr, "Could not remove \"%s\" for %s\n", + attrname, filename); + exit(1); + } + break; + + case LISTOP: + if ((buffer = malloc(BUFSIZE)) == NULL) { + perror("malloc"); + exit(1); + } + + memset((char *)&cursor, 0, sizeof(cursor)); + + do { + error = attr_list(filename, buffer, BUFSIZE, + (!follow ? ATTR_DONTFOLLOW : 0) | + (rootflag ? ATTR_ROOT : 0), + &cursor); + if (error) { + perror("attr_list"); + fprintf(stderr, "Could not list attributes for %s\n", + filename); + exit(1); + } + + alist = (attrlist_t *)buffer; + for (i = 0; i < alist->al_count; i++) { + aep = (attrlist_ent_t *)&buffer[ alist->al_offset[i] ]; + if (verbose) { + printf("Attribute \"%s\" has a %d byte value for %s\n", + aep->a_name, + aep->a_valuelen, + filename); + } else { + printf("%s\n", aep->a_name); + } + } + } while (alist->al_more); + break; + + default: + fprintf(stderr, + "At least one of -s, -g, -r, or -l is required\n"); + usage(argv[0]); + break; + } + + return(0); +} diff -rNu linux-2.4.7/cmd/attr/build/CVS/Entries linux-2.4-xfs/cmd/attr/build/CVS/Entries --- linux-2.4.7/cmd/attr/build/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/CVS/Entries Thu Jul 5 11:43:41 2001 @@ -0,0 +1,2 @@ +/Makefile/1.2/Thu Mar 1 01:31:21 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/attr/build/CVS/Entries.Log linux-2.4-xfs/cmd/attr/build/CVS/Entries.Log --- linux-2.4.7/cmd/attr/build/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/CVS/Entries.Log Thu Jul 5 11:43:41 2001 @@ -0,0 +1,2 @@ +A D/rpm//// +A D/tar//// diff -rNu linux-2.4.7/cmd/attr/build/CVS/Repository linux-2.4-xfs/cmd/attr/build/CVS/Repository --- linux-2.4.7/cmd/attr/build/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/CVS/Repository Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/attr/build diff -rNu linux-2.4.7/cmd/attr/build/CVS/Root linux-2.4-xfs/cmd/attr/build/CVS/Root --- linux-2.4.7/cmd/attr/build/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/CVS/Root Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/attr/build/Makefile linux-2.4-xfs/cmd/attr/build/Makefile --- linux-2.4.7/cmd/attr/build/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/Makefile Wed Feb 28 19:31:21 2001 @@ -0,0 +1,76 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +MANIFEST=src-manifest +SRCTAR=$(PKG_NAME)-$(PKG_VERSION).src.tar.gz + +LDIRT = *-manifest *.gz $(TOPDIR)/$(PKG_NAME)-* + +# for clean and clobber +SUBDIRS = tar rpm + +# nothing to build here (it's all packaging) +default install install-dev : + +include $(BUILDRULES) + +# Symlink in the TOPDIR is used to pack files relative to +# product-version directory. +$(MANIFEST) : $(_FORCE) + @if [ ! -L $(TOPDIR)/$(PKG_NAME)-$(PKG_VERSION) ] ; then \ + $(LN_S) . $(TOPDIR)/$(PKG_NAME)-$(PKG_VERSION) ; \ + fi + @CDIR=`pwd`; cd $(TOPDIR); \ + $(MAKE) --no-print-directory source | \ + sed -e 's/^\./$(PKG_NAME)-$(PKG_VERSION)/' > $$CDIR/$@ ;\ + if [ $$? -ne 0 ] ; then \ + exit 1; \ + else \ + unset TAPE; \ + $(TAR) -T $$CDIR/$@ -cf - | $(ZIP) --best > $$CDIR/$(SRCTAR); \ + fi + +dist : default $(MANIFEST) + @DIST_MANIFEST=`pwd`/bin-manifest; DIST_ROOT=/tmp/$$$$; \ + export DIST_MANIFEST DIST_ROOT; \ + rm -f $$DIST_MANIFEST; \ + echo === install === && $(MAKE) -C $(TOPDIR) install || exit $$?; \ + if [ -x $(TAR) ]; then \ + ( echo "=== tar ===" && $(MAKEF) -C tar $@ || exit $$? ); \ + fi; \ + if [ -x $(RPM) ]; then \ + ( echo "=== rpm ===" && $(MAKEF) -C rpm $@ || exit $$? ); \ + fi; \ + test -z "$$KEEP_DIST_ROOT" || rm -rf $$DIST_ROOT; echo Done diff -rNu linux-2.4.7/cmd/attr/build/rpm/CVS/Entries linux-2.4-xfs/cmd/attr/build/rpm/CVS/Entries --- linux-2.4.7/cmd/attr/build/rpm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/rpm/CVS/Entries Thu Jul 5 11:43:41 2001 @@ -0,0 +1,5 @@ +/Makefile/1.3/Tue Mar 20 19:36:13 2001/-ko/ +/attr.spec.in/1.3/Wed Apr 25 05:09:42 2001/-ko/ +/macros.template/1.1/Mon Jan 15 03:18:30 2001/-ko/ +/rpm-2.rc.template/1.1/Mon Jan 15 03:18:30 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/attr/build/rpm/CVS/Repository linux-2.4-xfs/cmd/attr/build/rpm/CVS/Repository --- linux-2.4.7/cmd/attr/build/rpm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/rpm/CVS/Repository Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/attr/build/rpm diff -rNu linux-2.4.7/cmd/attr/build/rpm/CVS/Root linux-2.4-xfs/cmd/attr/build/rpm/CVS/Root --- linux-2.4.7/cmd/attr/build/rpm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/rpm/CVS/Root Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/attr/build/rpm/Makefile linux-2.4-xfs/cmd/attr/build/rpm/Makefile --- linux-2.4.7/cmd/attr/build/rpm/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/rpm/Makefile Tue Mar 20 13:36:13 2001 @@ -0,0 +1,78 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +TREEROOT = $(shell cd ${TOPDIR}; pwd) +include $(TOPDIR)/include/builddefs + +SPECF = $(PKG_NAME).spec +LDIRT = $(PKG_NAME)*.rpm $(SPECF) rpmmacros rpm-*.rc $(TOPDIR)/files*.rpm + +LSRCFILES = macros.template $(SPECF).in rpm-2.rc.template + +default install install-dev : + +include $(BUILDRULES) + +# generate a binary rpm file +dist : default $(SPECF) rpm-$(RPM_VERSION).rc + $(RPM) -ba --rcfile ./rpm-$(RPM_VERSION).rc $(SPECF) + +# Because rpm prior to v.2.90 does not support macros and old style config +# is not supported by rpm v.3, we have to resort to such ugly hacks +ifneq ($RPM_VERSION,2) +rpm-$(RPM_VERSION).rc : rpmmacros + sed -e '/^macrofiles:/s|~/.rpmmacros|rpmmacros|' $@ + +rpmmacros : macros.template + @sed -e 's|%topdir%|$(TREEROOT)|g' < $< > $@ +else +rpm-2.rc: rpm-2.rc.template + @sed -e 's|%topdir%|$(TOPDIR)|g' < $< > $@ +endif + +.PHONY: $(SPECF) +${SPECF} : ${SPECF}.in + sed -e's|@pkg_name@|$(PKG_NAME)|g' \ + -e's|@pkg_version@|$(PKG_VERSION)|g' \ + -e's|@pkg_release@|$(PKG_RELEASE)|g' \ + -e's|@pkg_distribution@|$(PKG_DISTRIBUTION)|g' \ + -e's|@pkg_builder@|$(PKG_BUILDER)|g' \ + -e's|@build_root@|$(DIST_ROOT)|g' \ + -e'/^BuildRoot: *$$/d' \ + -e's|@pkg_var_dir@|$(PKG_VAR_DIR)|g' \ + -e's|@pkg_share_dir@|$(PKG_SHARE_DIR)|g' \ + -e's|@pkg_log_dir@|$(PKG_LOG_DIR)|g' \ + -e's|@pkg_doc_dir@|$(PKG_DOC_DIR)|g' \ + -e's|@pkg_man_dir@|$(PKG_MAN_DIR)|g' \ + -e's|@pkg_tmp_dir@|$(PKG_TMP_DIR)|g' \ + -e's|@make@|$(MAKE)|g' < $< > $@ diff -rNu linux-2.4.7/cmd/attr/build/rpm/attr.spec.in linux-2.4-xfs/cmd/attr/build/rpm/attr.spec.in --- linux-2.4.7/cmd/attr/build/rpm/attr.spec.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/rpm/attr.spec.in Wed Apr 25 00:09:42 2001 @@ -0,0 +1,93 @@ +Summary: Utility for managing filesystem extended attributes. +Name: @pkg_name@ +Version: @pkg_version@ +Release: @pkg_release@ +Distribution: @pkg_distribution@ +Packager: @pkg_builder@ +BuildRoot: @build_root@ +Prereq: /sbin/ldconfig +Source: @pkg_name@-@pkg_version@.src.tar.gz +Copyright: Copyright (C) 2000 Silicon Graphics, Inc. +Vendor: Silicon Graphics, Inc. +URL: http://oss.sgi.com/projects/xfs/ +Group: System Environment/Base + +%description +A utility for manipulating extended attributes on filesystem +objects, compatible with the SGI IRIX tool of the same name. + +%package devel +Summary: Extended attribute static libraries and headers. +Group: Development/Libraries +Requires: @pkg_name@ + +%description devel +attr-devel contains the libraries and header files needed to +develop programs which make use of extended attributes. This +interface is compatible with the SGI IRIX extended attribute +interface, and makes use of an unofficial Linux system call. + +Currently only XFS is supported, and the (experimental, unofficial) +system call interface is likely to change in the future. However, +the API built above this system call is unlikely to change and is +used by programs such as xfsdump(8), xfsrestore(8) and xfs_fsr(8). + +You should install attr-devel if you want to develop programs +which make use of extended attributes. If you install attr-devel, +you'll also want to install attr. + +# If .census exists, then no setup is necessary, just go and do the build, +# otherwise run setup +%prep +if [ -f .census ] ; then + if [ ! -d ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION} ] ; then + ln -s . ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION} + fi +else +%setup +touch .census +./configure +fi + +%build +@make@ + +%install +DIST_ROOT="$RPM_BUILD_ROOT" +DIST_INSTALL=`pwd`/install.manifest +DIST_INSTALL_DEV=`pwd`/install-dev.manifest +export DIST_ROOT DIST_INSTALL DIST_INSTALL_DEV +@make@ install DIST_MANIFEST="$DIST_INSTALL" +@make@ install-dev DIST_MANIFEST="$DIST_INSTALL_DEV" +files() +{ + sort | uniq | awk ' +$1 == "d" { printf ("%%%%dir %%%%attr(%s,%s,%s) %s\n", $2, $3, $4, $5); } +$1 == "f" { if (match ($6, "@pkg_man_dir@") || match ($6, "@pkg_doc_dir@")) + printf ("%%%%doc "); + if (match ($6, "@pkg_man_dir@")) + printf ("%%%%attr(%s,%s,%s) %s*\n", $2, $3, $4, $6); + else + printf ("%%%%attr(%s,%s,%s) %s\n", $2, $3, $4, $6); } +$1 == "l" { if (match ($3, "@pkg_man_dir@") || match ($3, "@pkg_doc_dir@")) + printf ("%%%%doc "); + if (match ($3, "@pkg_man_dir@")) + printf ("%attr(0777,root,root) %s*\n", $3); + else + printf ("%attr(0777,root,root) %s\n", $3); }' +} +set +x +files < "$DIST_INSTALL" > files.rpm +files < "$DIST_INSTALL_DEV" > filesdevel.rpm +set -x + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files -f files.rpm + +%files devel -f filesdevel.rpm diff -rNu linux-2.4.7/cmd/attr/build/rpm/macros.template linux-2.4-xfs/cmd/attr/build/rpm/macros.template --- linux-2.4.7/cmd/attr/build/rpm/macros.template Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/rpm/macros.template Sun Jan 14 21:18:30 2001 @@ -0,0 +1,30 @@ +# +# rpmrc.template +# +# Template to fudge rpm directory structure inside IRIX-like build +# environment + +# Force 386 build on all platforms +%_target i386-pc-linux +%_target_cpu i386 +%_target_os linux + +# topdir == $(WORKAREA) +%_topdir %topdir% + +# Following directories are specific to the topdir +# This is where build is done. In our case it's the same as $WORKAREA +%_builddir %topdir% + +# This is where foo.1.99.tar.gz is living in the real world. +# Be careful not to run full rpm build as it will override the sources +%_sourcedir %topdir%/build + +# This is where binary RPM and source RPM would end up +%_rpmdir %topdir%/build/rpm +%_srcrpmdir %topdir%/build/rpm +%_specdir %topdir%/build/rpm + +# Leave RPM files in the same directory - we're not building for +# multiple architectures +%_rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm diff -rNu linux-2.4.7/cmd/attr/build/rpm/rpm-2.rc.template linux-2.4-xfs/cmd/attr/build/rpm/rpm-2.rc.template --- linux-2.4.7/cmd/attr/build/rpm/rpm-2.rc.template Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/rpm/rpm-2.rc.template Sun Jan 14 21:18:30 2001 @@ -0,0 +1,25 @@ +# +# rpmrc.template +# +# Template to fudge rpm directory structure inside IRIX-like build +# environment + +# topdir == $(WORKAREA) +topdir: %topdir% + +# Following directories are specific to the topdir +# This is where build is done. In out case it's the same as $WORKAREA +# Be careful not to run full rpm build as it will override the sources +builddir: %topdir% + +# This is where foo.1.99.tar.gz is living in the real world. +sourcedir: %topdir%/build + +# This is where binary RPM and source RPM would end up +rpmdir: %topdir%/build/rpm +srcrpmdir: %topdir%/build/rpm +specdir: %topdir%/build/rpm + +# Leave RPM files in the same directory - we're not building for +# multiple architectures +rpmfilename: %{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm diff -rNu linux-2.4.7/cmd/attr/build/tar/CVS/Entries linux-2.4-xfs/cmd/attr/build/tar/CVS/Entries --- linux-2.4.7/cmd/attr/build/tar/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/tar/CVS/Entries Thu Jul 5 11:43:41 2001 @@ -0,0 +1,2 @@ +/Makefile/1.2/Thu Mar 1 01:48:49 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/attr/build/tar/CVS/Repository linux-2.4-xfs/cmd/attr/build/tar/CVS/Repository --- linux-2.4.7/cmd/attr/build/tar/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/tar/CVS/Repository Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/attr/build/tar diff -rNu linux-2.4.7/cmd/attr/build/tar/CVS/Root linux-2.4-xfs/cmd/attr/build/tar/CVS/Root --- linux-2.4.7/cmd/attr/build/tar/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/tar/CVS/Root Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/attr/build/tar/Makefile linux-2.4-xfs/cmd/attr/build/tar/Makefile --- linux-2.4.7/cmd/attr/build/tar/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/build/tar/Makefile Wed Feb 28 19:48:49 2001 @@ -0,0 +1,50 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +BINTAR=$(PKG_NAME)-$(PKG_VERSION).tar.gz +LDIRT = *.gz + +default install install-dev : + +include $(BUILDRULES) + +dist : default + @HERE=`pwd`; cd $${DIST_ROOT:-/}; \ + sort $$HERE/../bin-manifest | uniq | $(AWK) ' \ + $$1 == "f" { printf (".%s\n", $$6); } \ + $$1 == "d" { next; } \ + $$1 == "l" { printf (".%s\n", $$3); }' \ + | $(TAR) -T - -cf - | $(ZIP) --best > $$HERE/$(BINTAR) + @echo Wrote: `pwd`/$(BINTAR) diff -rNu linux-2.4.7/cmd/attr/configure.in linux-2.4-xfs/cmd/attr/configure.in --- linux-2.4.7/cmd/attr/configure.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/configure.in Tue Jun 12 02:20:31 2001 @@ -0,0 +1,156 @@ +dnl unpacking check - this file must exist +AC_INIT(include/attributes.h) +pkg_name="attr" +AC_SUBST(pkg_name) + +# +# Note: the following environment variables may be set to override the +# defaults (to change paths and/or executables, build parameters, etc): +# +# DEBUG OPTIMIZER MAKE CC LD TAR ZIP RPM AWK SED ECHO +# MALLOCLIB DISTRIBUTION PACKAGE_BUILDER PREFIX ROOT_PREFIX +# + +DEBUG=${DEBUG:-'-DDEBUG'} # -DNDEBUG +OPTIMIZER=${OPTIMIZER:-'-g'} # -O2 +MALLOCLIB=${MALLOCLIB:-''} # /usr/lib/libefence.a + +dnl Debug build? +debug_build="$DEBUG" +AC_SUBST(debug_build) + +dnl Optimization options? +opt_build="$OPTIMIZER" +AC_SUBST(opt_build) + +dnl Alternate malloc library? +malloc_lib="$MALLOCLIB" +AC_SUBST(malloc_lib) + +dnl Set version +. ./VERSION + +pkg_version=${PKG_MAJOR}.${PKG_MINOR}.${PKG_REVISION} +pkg_release=$PKG_BUILD +AC_SUBST(pkg_version) +AC_SUBST(pkg_release) + +pkg_distribution="SGI ProPack" +test -z "$DISTRIBUTION" || pkg_distribution="$DISTRIBUTION" +AC_SUBST(pkg_distribution) + +pkg_builder=`id -u -n`@`hostname -f` +test -z "$PACKAGE_BUILDER" || pkg_builder="$PACKAGE_BUILDER" +AC_SUBST(pkg_builder) + +dnl check if user wants their own C compiler +test -z "$CC" && AC_PROG_CC +cc=$CC +AC_SUBST(cc) + +dnl check if users wants their own make +test -z "$MAKE" && AC_PATH_PROG(MAKE, make, /usr/bin/make) +make=$MAKE +AC_SUBST(make) + +dnl check if users wants their own linker +test -z "$LD" && AC_PATH_PROG(LD, ld, /usr/bin/ld) +ld=$LD +AC_SUBST(ld) + +dnl check if the tar program is available +test -z "$TAR" && AC_PATH_PROG(TAR, tar) +tar=$TAR +AC_SUBST(tar) + +dnl check if the gzip program is available +test -z "$ZIP" && AC_PATH_PROG(ZIP, gzip, /bin/gzip) +zip=$ZIP +AC_SUBST(zip) + +dnl check if the rpm program is available +test -z "$RPM" && AC_PATH_PROG(RPM, rpm, /bin/rpm) +rpm=$RPM +AC_SUBST(rpm) + +dnl .. and what version is rpm +rpm_version=0 +test -x $RPM && \ + rpm_version=`$RPM --version | awk '{print $NF}' | awk -F. '{print $1}'` +AC_SUBST(rpm_version) + +dnl check if the makedepend program is available +test -z "$MAKEDEPEND" && AC_PATH_PROG(MAKEDEPEND, makedepend, /bin/true) +makedepend=$MAKEDEPEND +AC_SUBST(makedepend) + +dnl check if symbolic links are supported +AC_PROG_LN_S + +dnl check if user wants their own awk, sed and echo +test -z "$AWK" && AC_PATH_PROG(AWK, awk, /bin/awk) +awk=$AWK +AC_SUBST(awk) +test -z "$SED" && AC_PATH_PROG(SED, sed, /bin/sed) +sed=$SED +AC_SUBST(sed) +test -z "$ECHO" && AC_PATH_PROG(ECHO, echo, /bin/echo) +echo=$ECHO +AC_SUBST(echo) + + +dnl alternate root and usr prefixes +test -z "$ROOT_PREFIX" && ROOT_PREFIX="" +root_prefix="$ROOT_PREFIX" +test -z "$PREFIX" && PREFIX="/usr" +prefix="$PREFIX" + +dnl man pages (source) +dnl also check if man page source is gzipped +dnl (usually on Debian, but not Redhat pre-7.0) +pkg_man_dir=${prefix}/share/man +have_zipped_manpages=false +for d in ${prefix}/share/man ${prefix}/man ; do + if test -f $d/man1/man.1.gz + then + pkg_man_dir=$d + have_zipped_manpages=true + break + fi +done +AC_SUBST(pkg_man_dir) +AC_SUBST(have_zipped_manpages) + +dnl binaries +pkg_bin_dir=${prefix}/bin +AC_SUBST(pkg_bin_dir) + +dnl static libraries +pkg_lib_dir=${prefix}/lib +AC_SUBST(pkg_lib_dir) + +dnl runtime shared system libraries +pkg_slib_dir=${root_prefix}/lib +AC_SUBST(pkg_slib_dir) + +dnl system binaries +pkg_sbin_dir=${root_prefix}/bin +AC_SUBST(pkg_sbin_dir) + +dnl include files +pkg_inc_dir=${prefix}/include/attr +AC_SUBST(pkg_inc_dir) + +dnl doc directory +pkg_doc_dir=${prefix}/share/doc/${pkg_name} +AC_SUBST(pkg_doc_dir) + + +dnl +dnl output files +dnl + +AC_OUTPUT( \ +dnl Build definitions for use in Makefiles + include/builddefs \ +) diff -rNu linux-2.4.7/cmd/attr/debian/CVS/Entries linux-2.4-xfs/cmd/attr/debian/CVS/Entries --- linux-2.4.7/cmd/attr/debian/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/debian/CVS/Entries Thu Jul 5 11:43:41 2001 @@ -0,0 +1,6 @@ +/Makefile/1.1/Mon Jan 15 03:18:30 2001/-ko/ +/changelog/1.4/Mon Jul 2 03:31:14 2001/-ko/ +/control/1.2/Wed Apr 25 05:09:42 2001/-ko/ +/copyright/1.1/Mon Jan 15 03:18:30 2001/-ko/ +/rules/1.3/Thu Jan 25 06:56:37 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/attr/debian/CVS/Repository linux-2.4-xfs/cmd/attr/debian/CVS/Repository --- linux-2.4.7/cmd/attr/debian/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/debian/CVS/Repository Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/attr/debian diff -rNu linux-2.4.7/cmd/attr/debian/CVS/Root linux-2.4-xfs/cmd/attr/debian/CVS/Root --- linux-2.4.7/cmd/attr/debian/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/debian/CVS/Root Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/attr/debian/Makefile linux-2.4-xfs/cmd/attr/debian/Makefile --- linux-2.4.7/cmd/attr/debian/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/debian/Makefile Sun Jan 14 21:18:30 2001 @@ -0,0 +1,40 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LSRCFILES = changelog control copyright rules + +default install install-dev: + +include $(BUILDRULES) diff -rNu linux-2.4.7/cmd/attr/debian/changelog linux-2.4-xfs/cmd/attr/debian/changelog --- linux-2.4.7/cmd/attr/debian/changelog Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/debian/changelog Sun Jul 1 22:31:14 2001 @@ -0,0 +1,21 @@ +attr (1.0.4) unstable; urgency=low + + * Work around syscall number collision on recent ia64 kernels + + -- Nathan Scott Mon, 2 Jul 2001 13:02:02 +1000 + +attr (1.0.3) unstable; urgency=low + + * Updates to man pages. + + -- Nathan Scott Fri, 18 May 2001 15:47:54 +1000 + +attr (1.0.2) unstable; urgency=low + + * Initial release. + + -- Nathan Scott Wed, 25 Apr 2001 12:19:15 +1000 + +Local variables: +mode: debian-changelog +End: diff -rNu linux-2.4.7/cmd/attr/debian/control linux-2.4-xfs/cmd/attr/debian/control --- linux-2.4.7/cmd/attr/debian/control Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/debian/control Wed Apr 25 00:09:42 2001 @@ -0,0 +1,30 @@ +Source: attr +Section: utils +Priority: optional +Maintainer: Nathan Scott +Build-Depends: autoconf, debmake +Standards-Version: 3.1.1 + +Package: attr +Depends: ${shlibs:Depends} +Architecture: any +Description: Utility for manipulating filesystem extended attributes + A utility for manipulating extended attributes on filesystem + objects, compatible with the SGI IRIX tool of the same name. + +Package: attr-dev +Section: devel +Priority: extra +Depends: libc6-dev, attr +Architecture: any +Description: Extended attribute static libraries and headers. + attr-dev contains the libraries and header files needed to develop + programs which make use of extended attributes. + . + This interface is compatible with the SGI IRIX extended attribute + interface, and makes use of an unofficial Linux system call. + . + Currently only XFS is supported, and the (experimental, unofficial) + system call interface is likely to change in the future. However, + the API built above this system call is unlikely to change and is + used by programs such as xfsdump(8), xfsrestore(8) and xfs_fsr(8). diff -rNu linux-2.4.7/cmd/attr/debian/copyright linux-2.4-xfs/cmd/attr/debian/copyright --- linux-2.4.7/cmd/attr/debian/copyright Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/debian/copyright Sun Jan 14 21:18:30 2001 @@ -0,0 +1,14 @@ +This package was debianized by Nathan Scott nathans@debian.org on +Sun, 19 Nov 2000 07:37:09 -0500. + +It can be downloaded from ftp://oss.sgi.com/projects/xfs/download/ + +Copyright: + +Copyright (C) 2000 Silicon Graphics, Inc. + +You are free to distribute this software under the terms of +the GNU General Public License. +On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL file. + diff -rNu linux-2.4.7/cmd/attr/debian/rules linux-2.4-xfs/cmd/attr/debian/rules --- linux-2.4.7/cmd/attr/debian/rules Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/debian/rules Thu Jan 25 00:56:37 2001 @@ -0,0 +1,61 @@ +#!/usr/bin/make -f + +package = attr +develop = $(package)-dev + +dirtmp = debian/tmp +dirdev = debian/$(develop) +doctmp = /usr/share/doc/$(package) +docdev = /usr/share/doc/$(develop) +pkgtmp = DIST_ROOT=`pwd`/$(dirtmp); export DIST_ROOT; +pkgdev = DIST_ROOT=`pwd`/$(dirdev); export DIST_ROOT; +stdenv = GZIP=-q; export GZIP; + +options = DEBUG="-DNDEBUG"; OPTIMIZER="-O1 -g"; DISTRIBUTION="debian"; \ + export DEBUG OPTIMIZER DISTRIBUTION; +checkdir = test -f debian/rules + +build: built +built: + @echo "== dpkg-buildpackage: build" 1>&2 + $(checkdir) + autoconf + $(options) ./configure + $(MAKE) default + touch built + +clean: + @echo "== dpkg-buildpackage: clean" 1>&2 + $(checkdir) + -rm -f built + $(MAKE) distclean + -rm -rf $(dirtmp) $(dirdev) debian/*substvars debian/files* + +binary-indep: + +binary-arch: checkroot built + @echo "== dpkg-buildpackage: binary-arch" 1>&2 + $(checkdir) + -rm -rf $(dirtmp) $(dirdev) + $(pkgtmp) $(MAKE) -C . install + $(pkgdev) $(MAKE) -C . install-dev + $(pkgtmp) $(MAKE) -C build src-manifest + $(pkgdev) ./install-sh -m 755 -d $(doctmp) + $(pkgdev) ./install-sh -m 755 -d $(docdev) + $(pkgdev) ./install-sh -m 644 debian/copyright $(docdev) + $(pkgdev) ./install-sh -m 644 debian/changelog $(docdev) + @echo "== dpkg-buildpackage: debstd" 1>&2 + $(stdenv) debstd -m + dpkg-gencontrol -isp -p$(package) -P$(dirtmp) + dpkg-gencontrol -isp -p$(develop) -P$(dirdev) + chown -R root.root $(dirtmp) $(dirdev) + chmod -R go=rX $(dirtmp) $(dirdev) + dpkg --build $(dirtmp) .. + dpkg --build $(dirdev) .. + +binary: binary-indep binary-arch + +checkroot: + test 0 -eq `id -u` + +.PHONY: binary binary-arch binary-indep clean checkroot diff -rNu linux-2.4.7/cmd/attr/doc/CHANGES linux-2.4-xfs/cmd/attr/doc/CHANGES --- linux-2.4.7/cmd/attr/doc/CHANGES Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/doc/CHANGES Sun Jul 1 22:31:14 2001 @@ -0,0 +1,18 @@ +attr-1.0.4 (02 Jul 2001) + - work around syscall number collision on recent ia64 kernels + +attr-1.0.3 (18 May 2001) + - man page corrections + +attr-1.0.2 (24 April 2001) + - rearrange headers to make system call internals private + - update package descriptions + +attr-1.0.1 (30 January 2001) + - minor rpm and deb packaging work + +attr-1.0.0 (15 January 2001) + - extended attribute code abstracted from xfs-cmds package + - completed Debian packaging + - late beta code + diff -rNu linux-2.4.7/cmd/attr/doc/COPYING linux-2.4-xfs/cmd/attr/doc/COPYING --- linux-2.4.7/cmd/attr/doc/COPYING Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/doc/COPYING Sun Jan 14 21:18:30 2001 @@ -0,0 +1,860 @@ +All the libraries in "attr" are licensed under Version 2.1 +of the GNU Lesser General Public License. + +All other "attr" components are licensed under Version 2 of +the GNU General Public License. + +---------------------------------------------------------------------- + + + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + +---------------------------------------------------------------------- + + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +---------------------------------------------------------------------- diff -rNu linux-2.4.7/cmd/attr/doc/CVS/Entries linux-2.4-xfs/cmd/attr/doc/CVS/Entries --- linux-2.4.7/cmd/attr/doc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/doc/CVS/Entries Thu Jul 5 11:43:41 2001 @@ -0,0 +1,6 @@ +/CHANGES/1.5/Mon Jul 2 03:31:14 2001/-ko/ +/COPYING/1.1/Mon Jan 15 03:18:30 2001/-ko/ +/INSTALL/1.1/Mon Jan 15 03:18:30 2001/-ko/ +/Makefile/1.2/Thu Jan 25 06:56:37 2001/-ko/ +/PORTING/1.1/Mon Jan 15 03:18:30 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/attr/doc/CVS/Repository linux-2.4-xfs/cmd/attr/doc/CVS/Repository --- linux-2.4.7/cmd/attr/doc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/doc/CVS/Repository Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/attr/doc diff -rNu linux-2.4.7/cmd/attr/doc/CVS/Root linux-2.4-xfs/cmd/attr/doc/CVS/Root --- linux-2.4.7/cmd/attr/doc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/doc/CVS/Root Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/attr/doc/INSTALL linux-2.4-xfs/cmd/attr/doc/INSTALL --- linux-2.4.7/cmd/attr/doc/INSTALL Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/doc/INSTALL Sun Jan 14 21:18:30 2001 @@ -0,0 +1,48 @@ +This document describes how to configure and build the extended +attribute library and utility from source, and how to install them. + +0. If you have the binary rpm, simply install it and skip to step 2 (below). + The rpm command to do this is: + # rpm -Uvh attr + + The Debian command to do this is: + # dpkg -i attr + or, if you have apt configured (don't need the binary package): + # apt-get install attr + +1. Configure, build and install the package + + The "attr" package uses autoconf/configure and expects a GNU build + environment (your platform must at least have both autoconf and gmake). + + If you just want to spin an RPM and/or tar file, use the Makepkgs + script in the top level directory. This will configure and build + the package and leave binary and src RPMs in the build/rpm + directory. It will also leave a tar file in the build/tar + directory. + + # ./Makepkgs verbose + + If you want to build the package and install it manually, use the + following steps: + + # make configure (or run autoconf; ./configure) + # make + # su root + # make install + + Note that there are so many "install" variants out there that we + wrote our own script (see "install-sh" in the top level directory). + + If you wish to turn off debugging asserts in the command build and + turn on the optimizer then set the shell environment variables: + + OPTIMIZER=-O + DEBUG=-DNDEBUG + + before running make configure or Makepkgs. + +2. How to Contribute + + See the README file in this directory for details about how to + contribute to the XFS project. diff -rNu linux-2.4.7/cmd/attr/doc/Makefile linux-2.4-xfs/cmd/attr/doc/Makefile --- linux-2.4.7/cmd/attr/doc/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/doc/Makefile Thu Jan 25 00:56:37 2001 @@ -0,0 +1,52 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LSRCFILES = INSTALL PORTING CHANGES COPYING +LDIRT = *.gz + +default: $(CMDTARGET) CHANGES.gz + +include $(BUILDRULES) + +CHANGES.gz: + $(ZIP) --best -c < CHANGES > $@ + +install: default + $(INSTALL) -m 755 -d $(PKG_DOC_DIR) +ifneq ($(PKG_DISTRIBUTION), debian) + $(INSTALL) -m 644 COPYING $(PKG_DOC_DIR) +endif + $(INSTALL) -m 644 PORTING CHANGES.gz $(PKG_DOC_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/attr/doc/PORTING linux-2.4-xfs/cmd/attr/doc/PORTING --- linux-2.4.7/cmd/attr/doc/PORTING Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/doc/PORTING Sun Jan 14 21:18:30 2001 @@ -0,0 +1,86 @@ + +1. unpack the source tarball and cd to the resulting dir + +2. # autoconf + this reads configure.in and generates the ./configure script + +3. # ./configure + this probes your system and then, for each "file" named + in the AC_OUTPUT() macro near the end of configure.in, + read "file".in and generate "file". Variables named @somevariable@ + will be substituted with literal values. + +4. step (3) produces several files. These files are generated by + configure from their respective .in file in the same directory. + You should have a read of these generated files and diff them + against their respective .in files to see what was substituted + by configure. + + src/include/builddefs + common definitions for the build environment. This is included + by all Makefiles, in conjunction with src/include/buildrules. + Note that most autoconf/configure build environments generate + Makefile (from Makefile.in) in every src dir. Instead, we + generate builddefs, and then include it in every Makefile. + + src/include/platform_defs.h + header containing conditional macros defining the C run-time + environment discovered by the configure script. + +5. read some or all of the GNU tool chain documentation + gmake Table Of Contents : + http://www.delorie.com/gnu/docs/make/make_toc.html + gmake Quick Reference section : + http://www.delorie.com/gnu/docs/make/make_120.html + Autoconf : + http://www.delorie.com/gnu/docs/autoconf/autoconf_toc.html + gcc/g++ : + http://www.delorie.com/gnu/docs/gcc/gcc_toc.html + +6. Makefiles and build environment + First have a look at some Makefiles + + example using SUBDIRS : attr/Makefile + example static library: attr/libattr/Makefile + example command : attr/attr/Makefile + + All Makefiles must define TOPDIR as the root of the project. This + allows other stuff to be found relative to $(TOPDIR). + + All Makefiles should have the following structure, which is + much like commondefs and commonrules in the IRIX build environment, e.g. + + # ---------------------------------------------------------------------- + # TOPDIR must point to the root of the project + # The builddefs file defines lots of things. Read it. + TOPDIR = .. + include $(TOPDIR)/include/builddefs + + # first rule should always be "default" + default : sometarget + commands to build targets, if necessary + + # $(BUILDRULES) is defined in builddefs and includes rules for + # descending subdirs, building targets and installation rules + include $(BUILDRULES) + + install : default + $(INSTALL) sometargets somewhere + # ---------------------------------------------------------------------- + +7. packaging + + # ./Makepkgs + this script generates all of the packages supported - each has a + subdirectory below attr/build where knowledge specific to each + package type is maintained. + + The script produces logs of each stage of the build (this info is + also echoed to the screen when the "verbose" option is provided): + + attr/Logs/configure - `autoconf; ./configure' output + attr/Logs/default - `make default' output + attr/Logs/dist - `make build dist' output + + On successful completion, the script echoes the names of packages + successfully generated. diff -rNu linux-2.4.7/cmd/attr/include/CVS/Entries linux-2.4-xfs/cmd/attr/include/CVS/Entries --- linux-2.4.7/cmd/attr/include/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/include/CVS/Entries Thu Jul 5 11:43:42 2001 @@ -0,0 +1,6 @@ +/Makefile/1.2/Wed Apr 25 05:09:42 2001/-ko/ +/attr_kern.h/1.1/Wed Apr 25 05:09:42 2001/-ko/ +/attributes.h/1.3/Wed Apr 25 05:09:42 2001/-ko/ +/builddefs.in/1.2/Wed May 9 05:32:28 2001/-ko/ +/buildrules/1.1/Mon Jan 15 03:18:30 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/attr/include/CVS/Repository linux-2.4-xfs/cmd/attr/include/CVS/Repository --- linux-2.4.7/cmd/attr/include/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/include/CVS/Repository Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/attr/include diff -rNu linux-2.4.7/cmd/attr/include/CVS/Root linux-2.4-xfs/cmd/attr/include/CVS/Root --- linux-2.4.7/cmd/attr/include/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/include/CVS/Root Thu Jul 5 11:43:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/attr/include/Makefile linux-2.4-xfs/cmd/attr/include/Makefile --- linux-2.4.7/cmd/attr/include/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/include/Makefile Wed Apr 25 00:09:42 2001 @@ -0,0 +1,45 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +HFILES = attributes.h +LSRCFILES = builddefs.in buildrules attr_kern.h + +default install : + +include $(BUILDRULES) + +install-dev: default + $(INSTALL) -m 755 -d $(PKG_INC_DIR) + $(INSTALL) -m 644 $(HFILES) $(PKG_INC_DIR) diff -rNu linux-2.4.7/cmd/attr/include/attr_kern.h linux-2.4-xfs/cmd/attr/include/attr_kern.h --- linux-2.4.7/cmd/attr/include/attr_kern.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/include/attr_kern.h Wed Apr 25 00:09:42 2001 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __ATTR_KERN_H__ +#define __ATTR_KERN_H__ + +/* + * The (experimental) Linux generic attribute syscall - attrctl(2) + */ + +typedef union attr_obj { + char *path; + int fd; + pid_t pid; +} attr_obj_t; + +/* + * attr_obj_t type identifiers + */ +#define ATTR_TYPE_FD 1 /* file descriptor */ +#define ATTR_TYPE_PATH 2 /* path - follow symlinks */ +#define ATTR_TYPE_LPATH 3 /* path - don't follow symlinks */ +#define ATTR_TYPE_PID 4 /* process id */ + +/* + * Kernel-internal version of the attrlist cursor. + */ +typedef struct attrlist_cursor_kern { + __u32 hashval; /* hash value of next entry to add */ + __u32 blkno; /* block containing entry (suggestion)*/ + __u32 offset; /* offset in list of equal-hashvals */ + __u16 pad1; /* padding to match user-level */ + __u8 pad2; /* padding to match user-level */ + __u8 initted; /* T/F: cursor has been initialized */ +} attrlist_cursor_kern_t; + +#endif /* __ATTR_KERN_H__ */ diff -rNu linux-2.4.7/cmd/attr/include/attributes.h linux-2.4-xfs/cmd/attr/include/attributes.h --- linux-2.4.7/cmd/attr/include/attributes.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/include/attributes.h Wed Apr 25 00:09:42 2001 @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __ATTRIBUTES_H__ +#define __ATTRIBUTES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * An IRIX-compatible extended attributes API + */ + +/* + * Valid command flags, may be used with all API calls. + * Multiple flags should be bitwise OR'ed together. + */ +#define ATTR_ROOT 0x0001 /* use attrs in root namespace, not user */ +#define ATTR_CREATE 0x0002 /* pure create: fail if attr already exists */ +#define ATTR_REPLACE 0x0004 /* pure set: fail if attr does not exist */ +#define ATTR_SHIFT 16 /* for supporting extensions */ + +/* + * Additional API specific opcodes & flags + */ +#define ATTR_DONTFOLLOW (0x0001 << ATTR_SHIFT) /* do not follow symlinks */ +#define ATTR_TRUST (0x0002 << ATTR_SHIFT) + /* tell server we are trusted to properly handle extended attributes */ + +#define ATTR_KERNOTIME (0x0004 << ATTR_SHIFT) + /* don't update inode timestamps. + * The DMI needs a way to update attributes without affecting the + * inode timestamps. Note that this flag is not set-able from user + * mode - it is kernel internal only, but it must not conflict with + * the user flags either. + */ + +/* + * Generic extended attribute operation structure + */ +typedef struct attr_op { + int opcode; /* which operation to perform */ + int error; /* result (an errno) of this operation [out] */ + char *name; /* attribute name */ + char *value; /* attribute value [in/out] */ + int length; /* value length [in/out] */ + int flags; /* bitwise OR of #defines below */ + void *aux; /* optional cmd specific data */ +} attr_op_t; + +/* + * Valid attr_op, attr_multi_op opcodes + */ +#define ATTR_OP_GET 1 /* return the indicated attr's value */ +#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */ +#define ATTR_OP_REMOVE 3 /* remove the indicated attr */ +#define ATTR_OP_LIST 4 /* list attributes associated with a file */ + +#define ATTR_OP_EXT 32 /* for supporting extensions */ +#define ATTR_OP_IRIX_LIST (ATTR_OP_EXT + 0) /* IRIX attr_list semantics */ + +/* + * The maximum size (into the kernel or returned from the kernel) of an + * attribute value or the buffer used for an attr_list() call. Larger + * sizes will result in an E2BIG return code. + */ +#define ATTR_MAX_VALUELEN (64*1024) /* max length of a value */ + +/* + * Define how lists of attribute names are returned to the user from + * the attr_list() call. A large, 32bit aligned, buffer is passed in + * along with its size. We put an array of offsets at the top that each + * reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom. + */ +typedef struct attrlist { + __s32 al_count; /* number of entries in attrlist */ + __s32 al_more; /* T/F: more attrs (do call again) */ + __s32 al_offset[1]; /* byte offsets of attrs [var-sized] */ +} attrlist_t; + +/* + * Show the interesting info about one attribute. This is what the + * al_offset[i] entry points to. + */ +typedef struct attrlist_ent { /* data from attr_list() */ + __u32 a_valuelen; /* number bytes in value of attr */ + char a_name[1]; /* attr name (NULL terminated) */ +} attrlist_ent_t; + +/* + * Given a pointer to the (char*) buffer containing the attr_list() result, + * and an index, return a pointer to the indicated attribute in the buffer. + */ +#define ATTR_ENTRY(buffer, index) \ + ((attrlist_ent_t *) \ + &((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ]) + + +/* + * Implement a "cursor" for use in successive attr_list() calls. + * It provides a way to find the last attribute that was returned in the + * last attr_list() call so that we can get the next one without missing + * any. This should be bzero()ed before use and whenever it is desired to + * start over from the beginning of the attribute list. The only valid + * operation on a cursor is to bzero() it. + */ +typedef struct attrlist_cursor { + __u32 opaque[4]; /* an opaque cookie */ +} attrlist_cursor_t; + +/* + * Multi-attribute operation vector. + */ +typedef struct attr_multiop { + int am_opcode; /* operation to perform (ATTR_OP_GET, etc.) */ + int am_error; /* [out arg] result of this sub-op (an errno) */ + char *am_attrname; /* attribute name to work with */ + char *am_attrvalue; /* [in/out arg] attribute value (raw bytes) */ + int am_length; /* [in/out arg] length of value */ + int am_flags; /* bitwise OR of attr API flags defined above */ +} attr_multiop_t; +#define ATTR_MAX_MULTIOPS 128 /* max number ops in an oplist array */ + +/* + * Get the value of an attribute. + * Valuelength must be set to the maximum size of the value buffer, it will + * be set to the actual number of bytes used in the value buffer upon return. + * The return value is -1 on error (w/errno set appropriately), 0 on success. + */ +extern int attr_get (const char *__path, const char *__attrname, + char *__attrvalue, int *__valuelength, int __flags); +extern int attr_getf (int __fd, const char *__attrname, char *__attrvalue, + int *__valuelength, int __flags); + +/* + * Set the value of an attribute, creating the attribute if necessary. + * The return value is -1 on error (w/errno set appropriately), 0 on success. + */ +extern int attr_set (const char *__path, const char *__attrname, + const char *__attrvalue, const int __valuelength, + int __flags); +extern int attr_setf (int __fd, const char *__attrname, + const char *__attrvalue, const int __valuelength, + int __flags); + +/* + * Remove an attribute. + * The return value is -1 on error (w/errno set appropriately), 0 on success. + */ +extern int attr_remove (const char *__path, const char *__attrname, + int __flags); +extern int attr_removef (int __fd, const char *__attrname, int __flags); + +/* + * List the names and sizes of the values of all the attributes of an object. + * "Cursor" must be allocated and zeroed before the first call, it is used + * to maintain context between system calls if all the attribute names won't + * fit into the buffer on the first system call. + * The return value is -1 on error (w/errno set appropriately), 0 on success. + */ +extern int attr_list (const char *__path, char *__buffer, + const int __buffersize, int __flags, + attrlist_cursor_t *__cursor); +extern int attr_listf (int __fd, char *__buffer, const int __buffersize, + int __flags, attrlist_cursor_t *__cursor); + +/* + * Operate on multiple attributes of the same object simultaneously. + * + * This call will save on system call overhead when many attributes are + * going to be operated on. + * + * The return value is -1 on error (w/errno set appropriately), 0 on success. + * Note that this call will not return -1 as a result of failure of any + * of the sub-operations, their return value is stored in each element + * of the operation array. This call will return -1 for a failure of the + * call as a whole, eg: if the pathname doesn't exist, or the fd is bad. + * + * The semantics and allowable values for the fields in a attr_multiop_t + * are the same as the semantics and allowable values for the arguments to + * the corresponding "simple" attribute interface. For example: the args + * to a ATTR_OP_GET are the same as the args to an attr_get() call. + */ +extern int attr_multi (const char *__path, attr_multiop_t *__oplist, + int __count, int __flags); +extern int attr_multif (int __fd, attr_multiop_t *__oplist, + int __count, int __flags); + +#ifdef __cplusplus +} +#endif + +#endif /* __ATTRIBUTES_H__ */ diff -rNu linux-2.4.7/cmd/attr/include/builddefs.in linux-2.4-xfs/cmd/attr/include/builddefs.in --- linux-2.4.7/cmd/attr/include/builddefs.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/include/builddefs.in Wed May 9 00:32:28 2001 @@ -0,0 +1,167 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# @configure_input@ +# + +ifndef _BUILDDEFS_INCLUDED_ +_BUILDDEFS_INCLUDED_ = 1 + +DEBUG = @debug_build@ +OPTIMIZER = @opt_build@ +MALLOCLIB = @malloc_lib@ + +#LIBATTR = -lattr +LIBATTR = $(TOPDIR)/libattr/libattr.a + +BUILDRULES = $(TOPDIR)/include/buildrules + +# General package information +PKG_NAME = @pkg_name@ +PKG_RELEASE = @pkg_release@ +PKG_VERSION = @pkg_version@ +PKG_DISTRIBUTION = @pkg_distribution@ +PKG_BUILDER = @pkg_builder@ +PKG_BIN_DIR = @pkg_bin_dir@ +PKG_LIB_DIR = @pkg_lib_dir@ +PKG_SBIN_DIR = @pkg_sbin_dir@ +PKG_SLIB_DIR = @pkg_slib_dir@ +PKG_INC_DIR = @pkg_inc_dir@ +PKG_MAN_DIR = @pkg_man_dir@ +PKG_DOC_DIR = @pkg_doc_dir@ + +# LCFLAGS, LLDFLAGS, LLDLIBS, LSRCFILES and LDIRT may be specified in +# user Makefiles. Note: LSRCFILES is anything other than Makefile, $(CFILES) +# $(CXXFILES), or $(HFILES) and is used to construct the manifest list +# during the "dist" phase (packaging). + +CFLAGS += $(OPTIMIZER) $(DEBUG) -funsigned-char -Wall -D_GNU_SOURCE \ + $(LCFLAGS) -I$(TOPDIR)/include '-DVERSION="$(PKG_VERSION)"' \ + -D_FILE_OFFSET_BITS=64 + +LDFLAGS = $(LLDFLAGS) +LDLIBS = $(LLDLIBS) $(MALLOCLIB) + +MAKEOPTS = --no-print-directory +SRCFILES = Makefile $(HFILES) $(CFILES) $(LSRCFILES) $(LFILES) $(YFILES) +DIRT = $(LDIRT) dep dep.bak $(OBJECTS) $(CMDTARGET) $(LIBTARGET) \ + $(STATICLIBTARGET) *.[1-9].gz + +OBJECTS = $(ASFILES:.s=.o) \ + $(CFILES:.c=.o) \ + $(LFILES:.l=.o) \ + $(YFILES:%.y=%.tab.o) + +MAKE = @make@ +CC = @cc@ +LD = @ld@ +AWK = @awk@ +SED = @sed@ +INSTALL = $(TOPDIR)/install-sh -o root -g root +ECHO = @echo@ +LN_S = @LN_S@ + +CCF = $(CC) $(CFLAGS) +MAKEF = $(MAKE) $(MAKEOPTS) +CXXF = $(CXX) $(CXXFLAGS) +LDF = $(LD) $(LDFLAGS) +MAKEDEPEND = @makedepend@ + +ZIP = @zip@ +TAR = @tar@ +RPM = @rpm@ +RPM_VERSION = @rpm_version@ + +HAVE_ZIPPED_MANPAGES = @have_zipped_manpages@ + +SHELL = /bin/sh +IMAGES_DIR = $(TOPDIR)/all-images +DIST_DIR = $(TOPDIR)/dist + +SUBDIRS_MAKERULE = \ + @for d in $(SUBDIRS) ""; do \ + if test -d "$$d" -a ! -z "$$d"; then \ + $(ECHO) === $$d ===; \ + $(MAKEF) -C $$d $@ || exit $$?; \ + fi; \ + done + +MAN_MAKERULE = \ + @for f in *.[12345678] ""; do \ + if test ! -z "$$f"; then \ + $(ZIP) --best -c < $$f > $$f.gz; \ + fi; \ + done + +INSTALL_MAN = \ + @for d in $(MAN_PAGES); do \ + first=true; \ + for m in `$(AWK) '/^\.SH NAME/ {ok=1; next} ok {print; exit}' $$d \ + | sed -e 's/,/ /g' -e 's/\\-.*//' -e 's/\\\f[0-9]//g' -e 's/ / /g;q'`; \ + do \ + [ -z "$$m" -o "$$m" = "\\" ] && continue; \ + t=$(MAN_DEST)/$$m.$(MAN_SECTION); \ + if $$first; then \ + if $(HAVE_ZIPPED_MANPAGES); then \ + $(ZIP) --best -c $$d > $$d.gz; _sfx=.gz; \ + fi; \ + u=$$m.$(MAN_SECTION)$$_sfx; \ + echo $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ + $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ + else \ + echo $(INSTALL) -S $$u $${t}$$_sfx; \ + $(INSTALL) -S $$u $${t}$$_sfx; \ + fi; \ + first=false; \ + done; \ + done + +DIST_MAKERULE = \ + $(MAKEF) -C build dist + +SOURCE_MAKERULE = \ + @test -z "$$DIR" && DIR="."; \ + for f in $(SRCFILES) ""; do \ + if test ! -z "$$f"; then $(ECHO) $$DIR/$$f; fi;\ + done; \ + for d in `echo $(SUBDIRS)` ; do \ + if test -d "$$d" -a ! -z "$$d"; then \ + $(MAKEF) DIR=$$DIR/$$d -C $$d $@ || exit $$?; \ + fi; \ + done + +endif + +# +# For targets that should always be rebuilt, +# define a target that is never up-to-date. +# Targets needing this should depend on $(_FORCE) +_FORCE = __force_build diff -rNu linux-2.4.7/cmd/attr/include/buildrules linux-2.4-xfs/cmd/attr/include/buildrules --- linux-2.4.7/cmd/attr/include/buildrules Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/include/buildrules Sun Jan 14 21:18:30 2001 @@ -0,0 +1,77 @@ +# +# Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Fondation. +# +# This program is distributed in the hope that it would be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. Further, any license provided herein, +# whether implied or otherwise, is limited to this program in accordance with +# the express provisions of the GNU General Public License. Patent licenses, +# if any, provided herein do not apply to combinations of this program with +# other product or programs, or any other product whatsoever. This program is +# distributed without any warranty that the program is delivered free of the +# rightful claim of any third person by way of infringement or the like. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write the Free Software Foundation, Inc., 59 Temple +# Place - Suite 330, Boston MA 02111-1307, USA. +# Common build rules for gmake +# +ifndef _BUILDRULES_INCLUDED_ +_BUILDRULES_INCLUDED_ = 1 + +include $(TOPDIR)/include/builddefs + +# +# Standard targets +# +ifdef CMDTARGET +$(CMDTARGET) : $(SUBDIRS) $(OBJECTS) + $(CCF) -o $(CMDTARGET) $(LDFLAGS) $(OBJECTS) $(LDLIBS) +$(CMDTARGET).static : $(SUBDIRS) $(OBJECTS) + $(CCF) -static -o $(CMDTARGET).static $(LDFLAGS) $(OBJECTS) $(LDLIBS) +endif + +ifdef LIBTARGET +$(LIBTARGET) : $(SUBDIRS) $(OBJECTS) + $(CC) $(LDFLAGS) -fPIC -shared -Wl,-soname,$(LIBTARGET) -o $(LIBTARGET) $(OBJECTS) $(LDLIBS) +endif + +ifdef STATICLIBTARGET +$(STATICLIBTARGET) : $(SUBDIRS) $(OBJECTS) + $(AR) crf $(STATICLIBTARGET) $? +endif + +clean clobber : $(SUBDIRS) + rm -f $(DIRT) + $(SUBDIRS_MAKERULE) + +# Never blow away subdirs +ifdef SUBDIRS +.PRECIOUS: $(SUBDIRS) +$(SUBDIRS): + $(SUBDIRS_MAKERULE) +endif + +source : + $(SOURCE_MAKERULE) + +endif + +$(_FORCE): + +.PHONY : depend + +depend : $(CFILES) $(HFILES) + $(SUBDIRS_MAKERULE) + touch dep + $(MAKEDEPEND) -fdep -- $(CFLAGS) -- $(CFILES) + +# Include dep, but only if it exists +ifeq ($(shell test -f dep && echo dep), dep) +include dep +endif diff -rNu linux-2.4.7/cmd/attr/install-sh linux-2.4-xfs/cmd/attr/install-sh --- linux-2.4.7/cmd/attr/install-sh Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/install-sh Sun Jan 14 21:18:30 2001 @@ -0,0 +1,273 @@ +#! /bin/sh +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +# +# This script emulates bsd install and also recognises +# two environment variables, with the following semantics :- +# +# $DIST_MANIFEST - if set, the name of the file to append manifest +# information in the following format: +# File : f mode owner group src target +# Directory: d mode owner group target +# Symlink : l linkval target +# +# $DIST_ROOT - if set, prepend to target +# +# The sematics of all combinations of these two variables +# are as follows: +# +# $DIST_MANIFEST? $DIST_ROOT? | Copy? Append Manifest? +# -----------------------------+-------------------------- +# not set not set | yes no +# not set set | yes no +# set not set | no yes +# set set | yes yes +# +_usage() { + echo "Usage: $prog [-o owner] [-g group] [-m mode] -d directory" + echo "or $prog [-D] [-o owner] [-g group] [-m mode] file directory/file" + echo "or $prog [-o owner] [-g group] [-m mode] file [file ...] directory" + echo "or $prog -S file target (creates \"target\" symlink)" + echo "" + echo "The \$DIST_MANIFEST and \$DIST_ROOT environment variables affect the" + echo "behaviour of this command - see comments in the script." + echo "The -D flag is only available for the second usage, and causes" + echo "the target directory to be created before installing the file." + echo "" + exit 1 +} + +_chown () +{ + _st=255 + if [ $# -eq 3 ] ; then + chown $1:$2 $3 + _st=$? + if [ $_st -ne 0 ] ; then + if [ $REAL_UID != '0' ] ; then + if [ ! -f $DIST_ROOT/.chown.quite ] ; then + echo '===============================================' + echo Ownership of files under ${DIST_ROOT:-/} + echo cannot be changed + echo '===============================================' + if [ -n "$DIST_ROOT" ] ; then + touch $DIST_ROOT/.chown.quite + fi + fi + _st=0 + fi + fi + fi + + return $_st +} + + +_manifest () +{ + echo $* | sed -e 's/\/\//\//g' >>${DIST_MANIFEST:-/dev/null} +} + +prog=`basename $0` +HERE=`pwd` +dflag=false +Dflag=false +Sflag=false +DIRMODE=755 +FILEMODE=644 +OWNER=`id -u` +GROUP=`id -g` +REAL_UID=$OWNER + +# default is to install and don't append manifest +INSTALL=true +MANIFEST=: + +[ -n "$DIST_MANIFEST" -a -z "$DIST_ROOT" ] && INSTALL=false +[ -n "$DIST_MANIFEST" ] && MANIFEST="_manifest" + +[ $# -eq 0 ] && _usage + +if $INSTALL +then + CP=cp; LN=ln; MKDIR=mkdir; CHMOD=chmod; CHOWN=_chown +else + CP=true; LN=true; MKDIR=true; CHMOD=true; CHOWN=true +fi + +[ -n "$DIST_ROOT" -a $REAL_UID -ne 0 ] && CHOWN=true + +while getopts "Dcm:d:S:o:g:" c $* +do + case $c in + c) + ;; + g) + GROUP=$OPTARG + ;; + o) + OWNER=$OPTARG + ;; + m) + DIRMODE=`expr $OPTARG` + FILEMODE=$DIRMODE + ;; + D) + Dflag=true + ;; + S) + symlink=$OPTARG + Sflag=true + ;; + d) + dir=$DIST_ROOT/$OPTARG + dflag=true + ;; + *) + _usage + ;; + esac +done + +shift `expr $OPTIND - 1` + +status=0 +if $dflag +then + # + # first usage + # + $MKDIR -p $dir + status=$? + if [ $status -eq 0 ] + then + $CHMOD $DIRMODE $dir + status=$? + fi + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir + status=$? + fi + $MANIFEST d $DIRMODE $OWNER $GROUP ${dir#$DIST_ROOT} +elif $Sflag +then + # + # fourth usage (symlink) + # + if [ $# -ne 1 ] + then + _usage + else + target=$DIST_ROOT/$1 + fi + $LN -s -f $symlink $target + status=$? + $MANIFEST l $symlink ${target#$DIST_ROOT} +else + list="" + dir="" + if [ $# -eq 2 ] + then + # + # second usage + # + f=$1 + dir=$DIST_ROOT/$2 + if $Dflag + then + mkdir -p `dirname $dir` + fi + $CP $f $dir + status=$? + if [ $status -eq 0 ] + then + if [ -f $dir/$f ] + then + $CHMOD $FILEMODE $dir/$f + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir/$f + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f + else + $CHMOD $FILEMODE $dir + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$dir ${dir#$DIST_ROOT} + fi + fi + else + # + # third usage + # + n=1 + while [ $# -gt 0 ] + do + if [ $# -gt 1 ] + then + list="$list $1" + else + dir=$DIST_ROOT/$1 + fi + shift + done + + # echo DIR=$dir list=\"$list\" + for f in $list + do + $CP $f $dir + status=$? + if [ $status -eq 0 ] + then + $CHMOD $FILEMODE $dir/$f + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir/$f + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f + fi + [ $status -ne 0 ] && break + done + fi +fi + +exit $status diff -rNu linux-2.4.7/cmd/attr/libattr/CVS/Entries linux-2.4-xfs/cmd/attr/libattr/CVS/Entries --- linux-2.4.7/cmd/attr/libattr/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/libattr/CVS/Entries Thu Jul 5 11:43:42 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Mon Jan 15 03:18:30 2001/-ko/ +/attr.c/1.7/Mon Jul 2 03:31:14 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/attr/libattr/CVS/Repository linux-2.4-xfs/cmd/attr/libattr/CVS/Repository --- linux-2.4.7/cmd/attr/libattr/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/libattr/CVS/Repository Thu Jul 5 11:43:42 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/attr/libattr diff -rNu linux-2.4.7/cmd/attr/libattr/CVS/Root linux-2.4-xfs/cmd/attr/libattr/CVS/Root --- linux-2.4.7/cmd/attr/libattr/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/libattr/CVS/Root Thu Jul 5 11:43:42 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/attr/libattr/Makefile linux-2.4-xfs/cmd/attr/libattr/Makefile --- linux-2.4.7/cmd/attr/libattr/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/libattr/Makefile Sun Jan 14 21:18:30 2001 @@ -0,0 +1,57 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +STATICLIBTARGET = libattr.a + +CFILES = attr.c +LCFLAGS = -D_REENTRANT + +default: $(STATICLIBTARGET) + +include $(BUILDRULES) + +install: default + +install-dev: default + $(INSTALL) -m 755 -d $(PKG_LIB_DIR) + $(INSTALL) -m 644 $(STATICLIBTARGET) $(PKG_LIB_DIR) + +#LIBTARGET = libattr.so.1 +#install: default +# $(INSTALL) -m 755 -d $(PKG_SLIB_DIR) +# $(INSTALL) -m 755 $(LIBTARGET) $(PKG_SLIB_DIR) +#install-dev: default +# ... +# $(INSTALL) -S $(PKG_SLIB_DIR)/$(LIBTARGET) $(PKG_LIB_DIR)/libattr.so diff -rNu linux-2.4.7/cmd/attr/libattr/attr.c linux-2.4-xfs/cmd/attr/libattr/attr.c --- linux-2.4.7/cmd/attr/libattr/attr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/libattr/attr.c Sun Jul 1 22:31:14 2001 @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* Experimental system call interface for Linux */ +static int attrctl(attr_obj_t, int, attr_op_t *, int); + +/* Other local function prototypes */ +static int _attr_get(attr_obj_t, int, const char *, char *, int *, int); +static int _attr_set(attr_obj_t, int, const char *, const char *, const int, int); +static int _attr_remove(attr_obj_t, int, const char *, int); +static int _attr_listf(attr_obj_t, int, char *, const int, int, + attrlist_cursor_t *); +static int _attr_multif(attr_obj_t, int, attr_multiop_t *, int, int); + + +/* + * Get the value of an attribute. + */ +int +attr_get(const char *path, const char *attrname, char *attrvalue, + int *valuelength, int flags ) +{ + attr_obj_t obj; + int follow; + obj.path = (char *) path; + follow = (flags & ATTR_DONTFOLLOW) ? ATTR_TYPE_LPATH : ATTR_TYPE_PATH; + return _attr_get(obj, follow, attrname, attrvalue, valuelength, flags); +} + +int +attr_getf(int fd, const char *attrname, char *attrvalue, + int *valuelength, int flags ) +{ + attr_obj_t obj; + obj.fd = fd; + return _attr_get(obj, ATTR_TYPE_FD, attrname, attrvalue, + valuelength, flags); +} + +static int +_attr_get(attr_obj_t obj, int type, const char *attrname, char *attrvalue, + int *valuelength, int flags) +{ + attr_op_t op; + memset(&op, 0, sizeof(attr_op_t)); + op.opcode = ATTR_OP_GET; + op.name = (char *) attrname; + op.value = (char *) attrvalue; /* buffer to fill */ + op.length = *valuelength; /* buffer size */ + op.flags = flags; + + if (attrctl(obj, type, &op, 1) < 0) + return -1; + errno = op.error; + *valuelength = op.length; + return (errno ? -1 : 0); +} + + +/* + * Set the value of an attribute, creating the attribute if necessary. + */ +int +attr_set(const char *path, const char *attrname, const char *attrvalue, + const int valuelength, int flags) +{ + attr_obj_t obj; + int follow; + obj.path = (char *) path; + follow = (flags & ATTR_DONTFOLLOW) ? ATTR_TYPE_LPATH : ATTR_TYPE_PATH; + return _attr_set(obj, follow, attrname, attrvalue, valuelength, flags); +} + +int +attr_setf(int fd, const char *attrname, + const char *attrvalue, const int valuelength, int flags) +{ + attr_obj_t obj; + obj.fd = fd; + return _attr_set(obj, ATTR_TYPE_FD, attrname, attrvalue, + valuelength, flags); +} + +static int +_attr_set(attr_obj_t obj, int type, const char *attrname, + const char *attrvalue, const int valuelength, int flags) +{ + attr_op_t op; + memset(&op, 0, sizeof(attr_op_t)); + op.opcode = ATTR_OP_SET; + op.name = (char *) attrname; + op.value = (char *) attrvalue; + op.length = valuelength; + op.flags = flags; + + if (attrctl(obj, type, &op, 1) < 0) + return -1; + errno = op.error; + return (errno ? -1 : 0); +} + + +/* + * Remove an attribute. + */ +int +attr_remove(const char *path, const char *attrname, int flags) +{ + attr_obj_t obj; + int follow; + obj.path = (char *) path; + follow = (flags & ATTR_DONTFOLLOW) ? ATTR_TYPE_LPATH : ATTR_TYPE_PATH; + return _attr_remove(obj, follow, attrname, flags); +} + +int +attr_removef(int fd, const char *attrname, int flags) +{ + attr_obj_t obj; + obj.fd = fd; + return _attr_remove(obj, ATTR_TYPE_FD, attrname, flags); +} + +static int +_attr_remove(attr_obj_t obj, int type, const char *attrname, int flags) +{ + attr_op_t op; + memset(&op, 0, sizeof(attr_op_t)); + op.opcode = ATTR_OP_REMOVE; + op.name = (char *) attrname; + op.flags = flags; + + if (attrctl(obj, type, &op, 1) < 0) + return -1; + errno = op.error; + return (errno ? -1 : 0); +} + + +/* + * List the names and sizes of the values of all the attributes of an object. + */ +int +attr_list(const char *path, char *buffer, const int buffersize, + int flags, attrlist_cursor_t *cursor) +{ + attr_obj_t obj; + int follow; + obj.path = (char *) path; + follow = (flags & ATTR_DONTFOLLOW) ? ATTR_TYPE_LPATH : ATTR_TYPE_PATH; + return _attr_listf(obj, follow, buffer, buffersize, flags, cursor); +} + +int +attr_listf(int fd, char *buffer, const int buffersize, + int flags, attrlist_cursor_t *cursor) +{ + attr_obj_t obj; + obj.fd = fd; + return _attr_listf(obj, ATTR_TYPE_FD, buffer, buffersize, + flags, cursor); +} + +static int +_attr_listf(attr_obj_t obj, int type, char *buffer, const int buffersize, + int flags, attrlist_cursor_t *cursor) +{ + attr_op_t op; + memset(&op, 0, sizeof(attr_op_t)); + op.opcode = ATTR_OP_IRIX_LIST; + op.value = (char *) buffer; + op.length = buffersize; + op.flags = flags; + op.aux = cursor; + + if (attrctl(obj, type, &op, 1) < 0) + return -1; + errno = op.error; + return (errno ? -1 : 0); +} + +/* + * Operate on multiple attributes of the same object simultaneously + */ +int +attr_multi(const char *path, attr_multiop_t *multiops, int count, int flags) +{ + attr_obj_t obj; + int follow; + obj.path = (char *) path; + follow = (flags & ATTR_DONTFOLLOW) ? ATTR_TYPE_LPATH : ATTR_TYPE_PATH; + return _attr_multif(obj, follow, multiops, count, flags); +} + +int +attr_multif(int fd, attr_multiop_t *multiops, int count, int flags) +{ + attr_obj_t obj; + obj.fd = fd; + return _attr_multif(obj, ATTR_TYPE_FD, multiops, count, flags); +} + +static int +_attr_multif(attr_obj_t obj, int type, attr_multiop_t *multiops, int count, + int flags) +{ + int i; + int error = 0; + attr_op_t *ops; + + /* From the manpage: "attr_multi will fail if ... A bit other than */ + /* ATTR_DONTFOLLOW was set in the flag argument." flags must be */ + /* checked here as they are not passed into the kernel. */ + /* All other flags are checked in the kernel (linvfs_attrctl). */ + + if ((flags & ATTR_DONTFOLLOW) != flags) { + errno = EINVAL; + return -1; + } + + if (! (ops = malloc(count * sizeof (attr_op_t)))) { + errno = ENOMEM; + return -1; + } + + for (i = 0; i < count; i++) { + ops[i].opcode = multiops[i].am_opcode; + ops[i].name = multiops[i].am_attrname; + ops[i].value = multiops[i].am_attrvalue; + ops[i].length = multiops[i].am_length; + ops[i].flags = multiops[i].am_flags; + } + + if (attrctl(obj, type, ops, 1) < 0) { + error = -1; + goto free_mem; + } + + /* copy return vals */ + for (i = 0; i < count; i++) { + multiops[i].am_error = ops[i].error; + if (ops[i].opcode == ATTR_OP_GET) + multiops[i].am_length = ops[i].length; + } + + free_mem: + free(ops); + return error; +} + + +/* + * attrctl(2) experimental system call function definition. + */ + +#if __i386__ +# define HAVE_ACL_SYSCALL 1 +# ifndef SYS__attrctl +# define SYS__attrctl 250 +# endif +#elif __ia64__ +# define HAVE_ACL_SYSCALL 1 +# ifndef SYS__attrctl +# define SYS__attrctl 1260 +# endif +#else +# define HAVE_ACL_SYSCALL 0 +#endif + +static int +attrctl(attr_obj_t obj, int type, attr_op_t *ops, int count) +{ +#if HAVE_ACL_SYSCALL + return syscall(SYS__attrctl, * (long *) &obj, type, ops, count); +#else + errno = ENOSYS; + return -1; +#endif +} diff -rNu linux-2.4.7/cmd/attr/man/CVS/Entries linux-2.4-xfs/cmd/attr/man/CVS/Entries --- linux-2.4.7/cmd/attr/man/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/CVS/Entries Thu Jul 5 11:43:42 2001 @@ -0,0 +1,2 @@ +/Makefile/1.1/Mon Jan 15 03:18:30 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/attr/man/CVS/Entries.Log linux-2.4-xfs/cmd/attr/man/CVS/Entries.Log --- linux-2.4.7/cmd/attr/man/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/CVS/Entries.Log Thu Jul 5 11:43:42 2001 @@ -0,0 +1,3 @@ +A D/man1//// +A D/man2//// +A D/man3//// diff -rNu linux-2.4.7/cmd/attr/man/CVS/Repository linux-2.4-xfs/cmd/attr/man/CVS/Repository --- linux-2.4.7/cmd/attr/man/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/CVS/Repository Thu Jul 5 11:43:42 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/attr/man diff -rNu linux-2.4.7/cmd/attr/man/CVS/Root linux-2.4-xfs/cmd/attr/man/CVS/Root --- linux-2.4.7/cmd/attr/man/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/CVS/Root Thu Jul 5 11:43:42 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/attr/man/Makefile linux-2.4-xfs/cmd/attr/man/Makefile --- linux-2.4.7/cmd/attr/man/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/Makefile Sun Jan 14 21:18:30 2001 @@ -0,0 +1,41 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +SUBDIRS = man1 man2 man3 + +default install install-dev : $(SUBDIRS) + $(SUBDIRS_MAKERULE) + +include $(BUILDRULES) diff -rNu linux-2.4.7/cmd/attr/man/man1/CVS/Entries linux-2.4-xfs/cmd/attr/man/man1/CVS/Entries --- linux-2.4.7/cmd/attr/man/man1/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man1/CVS/Entries Thu Jul 5 11:43:42 2001 @@ -0,0 +1,3 @@ +/Makefile/1.1/Mon Jan 15 03:18:30 2001/-ko/ +/attr.1/1.2/Wed Apr 25 05:09:42 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/attr/man/man1/CVS/Repository linux-2.4-xfs/cmd/attr/man/man1/CVS/Repository --- linux-2.4.7/cmd/attr/man/man1/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man1/CVS/Repository Thu Jul 5 11:43:42 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/attr/man/man1 diff -rNu linux-2.4.7/cmd/attr/man/man1/CVS/Root linux-2.4-xfs/cmd/attr/man/man1/CVS/Root --- linux-2.4.7/cmd/attr/man/man1/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man1/CVS/Root Thu Jul 5 11:43:42 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/attr/man/man1/Makefile linux-2.4-xfs/cmd/attr/man/man1/Makefile --- linux-2.4.7/cmd/attr/man/man1/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man1/Makefile Sun Jan 14 21:18:30 2001 @@ -0,0 +1,49 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +MAN_SECTION = 1 + +MAN_PAGES = $(shell echo *.$(MAN_SECTION)) +MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) +LSRCFILES = $(MAN_PAGES) + +default : $(MAN_PAGES) + +include $(BUILDRULES) + +install : default + $(INSTALL) -m 755 -d $(MAN_DEST) + $(INSTALL_MAN) +install-dev: diff -rNu linux-2.4.7/cmd/attr/man/man1/attr.1 linux-2.4-xfs/cmd/attr/man/man1/attr.1 --- linux-2.4.7/cmd/attr/man/man1/attr.1 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man1/attr.1 Wed Apr 25 00:09:42 2001 @@ -0,0 +1,164 @@ +.TH attr 1 +.SH NAME +attr \- manipulate Extended Attributes on filesystem objects +.SH SYNOPSIS +.nf +\f3attr\f1 [ \f3\-LRq\f1 ] \f3\-s attrname\f1 [ \f3\-V attrvalue\f1 ] \c +\f3pathname\f1 +.sp .8v +\f3attr\f1 [ \f3\-LRq\f1 ] \f3\-g attrname pathname\f1 +.sp .8v +\f3attr\f1 [ \f3\-LRq\f1 ] \f3\-r attrname pathname\f1 +.sp .8v +\f3attr\f1 [ \f3\-LRq\f1 ] \f3\-l pathname\f1 +.sp .8v +.fi +.SH OVERVIEW +Extended Attributes implement the ability for a user to attach +name/value pairs to objects within the filesystem. +.P +They could be used to store meta-information about the file. +For example "character-set=kanji" could tell a document browser to +use the Kanji character set when displaying that document +and "thumbnail=..." could provide a reduced resolution overview of a +high resolution graphic image. +.P +The +.I names +can be up to 256 bytes in length, terminated by the first 0 byte. +The intent is that they be printable ASCII (or other character set) +names for the attribute. +.P +The +.I values +can be up to 256KB of arbitrary binary data. +.P +Attributes can be attached to all types of inodes: +regular files, directories, symbolic links, device nodes, etc. +.P +There are 2 disjoint attribute name spaces associated with every +filesystem object. +They are the +.B root +and +.B user +address spaces. +The +.B root +address space is accessable only to the superuser, +and then only by specifying a flag argument to the function call. +Other users will not see or be able to modify attributes in the +.B root +address space. +The +.B user +address space is protected by the normal file permissions mechanism, +so the owner of the file can decide who is able to see and/or modify +the value of attributes on any particular file. +.SH DESCRIPTION +The +.I attr +utility allows the manipulation of Extended Attributes associated with +filesystem objects from within shell scripts. +.PP +There are four main operations that +.I attr +can perform: +.TP +.B GET +The +.B \-g attrname +option tells +.I attr +to search the named object and print (to \f4stdout\fP) the value +associated with that attribute name. +With the +.B \-q +flag, \f4stdout\fP will be exactly and only the value of the attribute, +suitable for storage directly into a file or processing via a piped command. +.TP +.B LIST +The +.B \-l +option tells +.I attr +to list the names of all the attributes that are associated with the object, +and the number of bytes in the value of each of those attributes. +With the +.B \-q +flag, \f4stdout\fP will be a simple list of only the attribute names, +one per line, suitable for input into a script. +.TP +.B REMOVE +The +.B \-r attrname +option tells +.I attr +to remove an attribute with the given name from the object if the +attribute exists. +There is no output on sucessful completion. +.TP +.B SET/CREATE +The +.B \-s attrname +option tells +.I attr +to set the named attribute of the object to the value read from \f4stdin\fP. +If an attribute with that name already exists, +its value will be replaced with this one. +If an attribute with that name does not already exist, +one will be created with this value. +With the +.B \-V attrvalue +flag, the attribute will be set to have a value of +.B attrvalue +and \f4stdin\fP will not be read. +With the +.B \-q +flag, \f4stdout\fP will not be used. +Without the +.B \-q +flag, a message showing the attribute name and the entire value +will be printed. +.PP +When the +.B \-L +option is given and the named object is a symbolic link, +operate on the attributes of the object referenced by the symbolic link. +Without this option, operate on the attributes of the symbolic link itself. +.PP +When the +.B \-R +option is given and the process has appropriate privileges, +operate in the +.I root +attribute namespace rather that the +.I USER +attribute namespace. +.PP +When the +.B \-q +option is given +.I attr +will try to keep quiet. +It will output error messages (to \f4stderr\fP) +but will not print status messages (to \f4stdout\fP). +.SH "NOTES" +The standard file interchange/archive programs +.IR tar (1), +and +.IR cpio (1) +will not archive or restore Extended Attributes, +while the +.IR xfsdump (8) +program will. +.SH "SEE ALSO" +attr_get(2), attr_getf(2), +attr_list(2), attr_listf(2), +attr_multi(2), attr_multif(2), +attr_remove(2), attr_removef(2), +attr_set(2), attr_setf(2), +xfsdump(8). +.SH BUGS +The extended attributes system call used by this program is +experimental and is currently only supported by the XFS filesystem. diff -rNu linux-2.4.7/cmd/attr/man/man2/CVS/Entries linux-2.4-xfs/cmd/attr/man/man2/CVS/Entries --- linux-2.4.7/cmd/attr/man/man2/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man2/CVS/Entries Thu Jul 5 11:43:42 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Tue Jan 30 05:42:55 2001/-ko/ +/attrctl.2/1.1/Mon Jan 15 03:18:30 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/attr/man/man2/CVS/Repository linux-2.4-xfs/cmd/attr/man/man2/CVS/Repository --- linux-2.4.7/cmd/attr/man/man2/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man2/CVS/Repository Thu Jul 5 11:43:42 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/attr/man/man2 diff -rNu linux-2.4.7/cmd/attr/man/man2/CVS/Root linux-2.4-xfs/cmd/attr/man/man2/CVS/Root --- linux-2.4.7/cmd/attr/man/man2/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man2/CVS/Root Thu Jul 5 11:43:42 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/attr/man/man2/Makefile linux-2.4-xfs/cmd/attr/man/man2/Makefile --- linux-2.4.7/cmd/attr/man/man2/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man2/Makefile Mon Jan 29 23:42:55 2001 @@ -0,0 +1,48 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +MAN_SECTION = 2 + +MAN_PAGES = $(shell echo *.$(MAN_SECTION)) +MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) +LSRCFILES = $(MAN_PAGES) + +default install : $(MAN_PAGES) + +include $(BUILDRULES) + +install-dev : default + $(INSTALL) -m 755 -d $(MAN_DEST) + $(INSTALL_MAN) diff -rNu linux-2.4.7/cmd/attr/man/man2/attrctl.2 linux-2.4-xfs/cmd/attr/man/man2/attrctl.2 --- linux-2.4.7/cmd/attr/man/man2/attrctl.2 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man2/attrctl.2 Sun Jan 14 21:18:30 2001 @@ -0,0 +1,350 @@ +.TH ATTRCTL 2 +.SH NAME +attrctl \- manipulate (extended) attributes of system objects +.SH C SYNOPSIS +.PP +.sp +.nf +.B #include +.sp +.B "int attrctl (attr_obj_t obj, int type, attr_op_t *ops," +.B " int count);" +.Op +.SH OVERVIEW +The +.I attrctl +system call allows a user to attach name/value pairs to system +objects - typically filesystem objects (inodes). +.P +This is a first draft proposal which may well *not* be the final +interface - it has been implemented to address some immediate +issues with the current XFS implementation and is the first attempt +at an interface which could allow both XFS and EXT2 extended attributes +implementations to coexist. +.P +Extended attributes can be used to store meta-information about a +file, for example "character-set=kanji" could tell a document browser +to use the Kanji character set when displaying that document +and "thumbnail=..." could provide a reduced resolution overview of a +high resolution graphic image. +.P +The +.B names +can be up to MAXNAMELEN bytes in length, terminated by the first \e0 byte. +The intent is that they be printable ASCII (or other character set) +names for the attribute. +.P +The +.B values +can be up to ATTR_MAX_VALUELEN (currently 64KB) of arbitrary binary data. +.P +Attributes can be attached to all types of inodes: +regular files, directories, symbolic links, device nodes, etc. +.P +There are 2 disjoint attribute name spaces associated with every +filesystem object. +They are the +.B root +and +.B user +address spaces. +The +.B root +address space is accessible only to the super-user, +and then only by specifying a flag to the operation request. +Non-root users will not see or be able to modify attributes in the +.B root +address space. +The +.B user +address space is protected by the normal file permissions mechanism, +so the owner of the file can decide who is able to see and/or modify +the value of attributes on any particular file. The attribute get/list +operations require read permission, and attribute set/remove require +write permission. +.P +Attributes are currently supported only in the XFS and EXT2 filesystem +types. However, this system call has been designed to be generic +and extensible, such that other filesystems should be able to make +use of it. +.SH DESCRIPTION +The +.I attrctl +system call provides a way to access arbitrary extended attributes. +.P +.I Obj\^ +indicates the system object whose extended attributes are to be +manipulated. +The contents of the \f4attr_obj_t\f1 union are as follows: +.P +typedef union { +.RS 3 +.nf +.ft 4 +.ta 9n 22n +char *path; +int fd; +pid_t pid; +.ft 1 +.fi +.RE +} attr_obj_t; +.PP +.I type\^ +identifies the type of +.I obj\^ +- currently only file descriptors and path names are implemented +(ATTR_TYPE_NAME and ATTR_TYPE_FD), but processes have also been +proposed (ATTR_TYPE_PID). +.P +.I Ops\^ +refers to an array of one or more input/output structures containing +control information related to attribute operations and those +operations' results. +.PP +The +.I count +argument indicates the number of structures in the +.I ops +array. +.PP +.Op c p a +The contents of an \f4attr_op_t\fP structure are as follows: +.P +typedef struct { +.RS 3 +.nf +.ft 4 +.ta 9n 22n +int opcode; /* which operation to perform (see below) */ +int error; /* [out arg] result of this sub-op (an errno) */ +char *name; /* attribute name to work with */ +char *value; /* [in/out arg] attribute value (raw bytes) */ +int length; /* [in/out arg] length of value */ +int flags; /* flags (bit-wise OR of #defines below) */ +void *aux; /* optional command-specific data */ +.ft 1 +.fi +.RE +} attr_op_t; +.PP +The +.I opcode +field defines how the remaining fields are to be interpreted +and can take on one of the following +.B ATTR_OP +values. +.PP +.B ATTR_OP_GET +returns the +.I value +associated with attribute +.IR name . +The size of the user buffer is passed in as +.IR length , +and the size of the attribute value is returned in the same field. +Valid flags are ATTR_ROOT and ATTR_DONTFOLLOW. +.P +.B ATTR_OP_SET +sets (possibly creating a new attribute) the value of the +attribute specified by +.I name +to +.IR value . +The +.I length +parameter specifies the size of the new value, and the valid +.I flags +are ATTR_ROOT, ATTR_DONTFOLLOW, ATTR_CREATE, and ATTR_REPLACE. +.P +.B ATTR_OP_REMOVE +provides a way to remove previously created attributes. +If the attribute +.I name +exists, the attribute name and its associated value will be +removed. +Valid +.I flags +are ATTR_ROOT and ATTR_DONTFOLLOW. +.P +.B ATTR_OP_LIST +is used to list the existing attributes associated with an object. +The +.I name +field is ignored \- +.I value +and +.I size +specify the buffer to be filled with at least a portion of the +attributes associated with the given object. +An +.B attrlist_t +structure will be written into the +.I value +buffer, containing a list of the attributes associated with the +object, up to a maximum of +.I size +bytes. +The +.B attrlist_t +structure contains the following elements: +.P +typedef struct { +.RS 3 +.nf +.ft 4 +.ta 9n 22n +__s32 count; /* number of entries in attribute list */ +__s32 more; /* [in/out arg] more attrs (call again) */ +__s32 offset[1]; /* byte offsets of attrs [var-sized] */ +.ft 1 +.fi +.RE +} attrlist_t; +.PP +The +.I count +field shows the number of attributes represented in this buffer, +which is also the number of elements in the +.I offset +array. +The +.I more +field will be non-zero if another +.B ATTR_OP_LIST +call would retrieve more attributes. +The +.I offset +array contains the byte offset within the +.I value +buffer of the structure describing each of the attributes, an +.B attrlist_ent_t +structure. +The +.B "ATTR_ENTRY(buffer, index)" +macro will help with decoding the list. +It takes a pointer to the +.I value +and an index into the +.I offset +array, and returns a pointer to the corresponding +.I attrlist_ent_t +structure. +.P +typedef struct { +.RS 3 +.nf +.ft 4 +.ta 9n 22n +__u32 valuelen; /* number of bytes in attribute value */ +char name[]; /* attribute name (NULL terminated) */ +.ft 1 +.fi +.RE +} attrlist_ent_t; +.PP +The +.I valuelen +field shows the size in bytes of the value associated +with the attribute whose name is stored in the +.I name +field. +.P +Valid +.I flags +for the +.B ATTR_LIST +command are ATTR_ROOT and ATTR_DONTFOLLOW. +The +.I aux +pointer is used to reference an opaque cursor (type +.BR attrlist_cursor_t ), +which the kernel uses to track the calling process's position +in the attribute list. +The only valid operations on this cursor are to pass it into the +operation or to zero it out (it should be zeroed before the +first +.B attrctl +call. +Note that multi-threaded applications may keep more than one +cursor in order to serve multiple contexts (i.e. the +.B ATTR_LIST +operation is "thread-safe"). +.P +All operations will set +.I error +to an error code if the operation fails, otherwise it will +contain zero indicating success. The set of valid +.I flags +field values (combined using bitwise OR) is as follows: +.TP +.SM +\%ATTR_ROOT +Look for attribute +.I name +in the +.B root +address space, not in the +.B user +address space (limited to use by the super-user only). +.TP +.SM +\%ATTR_DONTFOLLOW +Do not follow symbolic links when resolving a +.I path +on an +.I attr_set +function call. +The default is to follow symbolic links. +.TP +.SM +\%ATTR_CREATE +Set +.I error +field (EEXIST) if an attribute of the given name already +exists on the indicated object. +This flag is used to implement a pure create operation, +without this flag +.B ATTR_SET +will create the attribute if it does not already exist. +.TP +.SM +\%ATTR_REPLACE +Set +.I error +field (ENOENT) if an attribute of the given name +does not already exist on the indicated object, +otherwise replace the existing attribute\'s value with the +given value. +This flag is used to implement a pure replacement operation, +without this flag +.B ATTR_SET +will create the attribute if it does not already exist. +.PP +The +.I error +field will be set (EINVAL) if both ATTR_CREATE and ATTR_REPLACE +are requested in the same operation. +.SH DIAGNOSTICS +.I attrctl +will return 0 on success, and an error code on any failure. +Since the +.I attrctl +system call is arbitrarily extensible, and the intention is that it +will always be used through an overlying API, refer to the manual +pages for overlying API calls for specific error code values. +.P +.I attrctl +will always attempt to perform all operations, and a set of +operations are not atomic (failure of one operation does not +necessarily cause prior successful operations to be undone). +.SH "SEE ALSO" +attr(1), +.br +attr_list(3), attr_listf(3), +.br +attr_multi(3), attr_multif(3), +.br +attr_remove(3), attr_removef(3), +.br +attr_set(3), attr_setf(3). diff -rNu linux-2.4.7/cmd/attr/man/man3/CVS/Entries linux-2.4-xfs/cmd/attr/man/man3/CVS/Entries --- linux-2.4.7/cmd/attr/man/man3/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man3/CVS/Entries Thu Jul 5 11:43:42 2001 @@ -0,0 +1,7 @@ +/Makefile/1.2/Tue Jan 30 05:42:55 2001/-ko/ +/attr_get.3/1.2/Mon May 21 00:39:09 2001/-ko/ +/attr_list.3/1.2/Mon May 21 00:39:09 2001/-ko/ +/attr_multi.3/1.2/Mon May 21 00:39:09 2001/-ko/ +/attr_remove.3/1.2/Mon May 21 00:39:09 2001/-ko/ +/attr_set.3/1.2/Mon May 21 00:39:09 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/attr/man/man3/CVS/Repository linux-2.4-xfs/cmd/attr/man/man3/CVS/Repository --- linux-2.4.7/cmd/attr/man/man3/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man3/CVS/Repository Thu Jul 5 11:43:42 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/attr/man/man3 diff -rNu linux-2.4.7/cmd/attr/man/man3/CVS/Root linux-2.4-xfs/cmd/attr/man/man3/CVS/Root --- linux-2.4.7/cmd/attr/man/man3/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man3/CVS/Root Thu Jul 5 11:43:42 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/attr/man/man3/Makefile linux-2.4-xfs/cmd/attr/man/man3/Makefile --- linux-2.4.7/cmd/attr/man/man3/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man3/Makefile Mon Jan 29 23:42:55 2001 @@ -0,0 +1,48 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +MAN_SECTION = 3 + +MAN_PAGES = $(shell echo *.$(MAN_SECTION)) +MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) +LSRCFILES = $(MAN_PAGES) + +default install : $(MAN_PAGES) + +include $(BUILDRULES) + +install-dev : default + $(INSTALL) -m 755 -d $(MAN_DEST) + $(INSTALL_MAN) diff -rNu linux-2.4.7/cmd/attr/man/man3/attr_get.3 linux-2.4-xfs/cmd/attr/man/man3/attr_get.3 --- linux-2.4.7/cmd/attr/man/man3/attr_get.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man3/attr_get.3 Sun May 20 19:39:09 2001 @@ -0,0 +1,190 @@ +.TH ATTR_GET 3 +.SH NAME +attr_get, attr_getf \- get the value of a user attribute of a filesystem object +.SH C SYNOPSIS +.PP +.sp +.nf +.B #include +.sp +.B "int attr_get (const char \(**path, const char \(**attrname, " +.B " char \(**attrvalue, int \(**valuelength, int flags);" +.PP +.B "int attr_getf (int fd, const char \(**attrname, " +.B " char \(**attrvalue, int \(**valuelength, int flags);" +.Op +.SH DESCRIPTION +The +.I attr_get +and +.I attr_getf +functions provide a way to retrieve the value of an attribute. +.P +.I Path\^ +points to a path name for a filesystem object, and +.I fd\^ +refers to the file descriptor associated with a file. +If the attribute +.I attrname +exists, the value associated with it will be copied into the +.I attrvalue +buffer. +The +.I valuelength +argument is an input/output argument that on the call to +.I attr_get +should contain the maximum size of attribute value the +process is willing to accept. +On return, the +.I valuelength +will have been modified to show the actual size of the +attribute value returned. +The +.I flags +argument can contain the following symbols bitwise OR\'ed together: +.TP +.SM +\%ATTR_ROOT +Look for +.I attrname +in the +.B root +address space, not in the +.B user +address space. +(limited to use by super-user only) +.TP +.SM +\%ATTR_DONTFOLLOW +Do not follow symbolic links when resolving a +.I path +on an +.I attr_get +function call. +The default is to follow symbolic links. +.PP +.I attr_get +will fail if one or more of the following are true: +.TP 17 +.SM +\%[ENOATTR] +The attribute name given is not associated with the indicated +filesystem object. +.TP +.SM +\%[E2BIG] +The value of the given attribute is too large to fit into the buffer. +The integer that the +.I valuelength +argument points to has been modified to show the actual number +of bytes that would be required to store the value of that attribute. +.TP +.SM +\%[ENOENT] +The named file does not exist. +.TP +.SM +\%[EPERM] +The effective user +.SM ID +does not match the owner of the file +and the effective user +.SM ID +is not super-user. +.TP +.SM +\%[ENOTDIR] +A component of the +path prefix +is not a directory. +.TP +.SM +\%[EACCES] +Search permission is denied on a +component of the +path prefix. +.TP +.SM +\%[EINVAL] +A bit was set in the +.I flag +argument that is not defined for this system call. +.TP +.SM +\%[EFAULT] +.I Path, +.I attrname, +.I attrvalue, +or +.I valuelength +points outside the allocated address space of the process. +.TP +.SM +\%[ELOOP] +A path name lookup involved too many symbolic links. +.TP +.SM +\%[ENAMETOOLONG] +The length of +.I path +exceeds +.SM +.RI { MAXPATHLEN }, +or a pathname component is longer than +.SM +.RI { MAXNAMELEN }. +.PP +.I attr_getf\^ +will fail if: +.TP 15 +.SM +\%[ENOATTR] +The attribute name given is not associated with the indicated +filesystem object. +.TP +.SM +\%[E2BIG] +The value of the given attribute is too large to fit into the buffer. +The integer that the +.I valuelength +argument points to has been modified to show the actual numnber +of bytes that would be required to store the value of that attribute. +.TP +.SM +\%[EINVAL] +A bit was set in the +.I flag +argument that is not defined for this system call, +or +.I fd\^ +refers to a socket, not a file. +.TP +.SM +\%[EFAULT] +.I Attrname, +.I attrvalue, +or +.I valuelength +points outside the allocated address space of the process. +.TP +.SM +\%[EBADF] +.I Fd\^ +does not refer to a valid descriptor. +.SH "SEE ALSO" +attr(1), +.br +attrctl(2), +.br +attr_list(3), attr_listf(3) +.br +attr_multi(3), attr_multif(3) +.br +attr_remove(3), attr_removef(3), +.br +attr_set(3), attr_setf(3), +.SH "DIAGNOSTICS" +Upon successful completion, a value of 0 is returned. +Otherwise, a value of \-1 is returned and +.I errno\^ +is set to indicate the error. diff -rNu linux-2.4.7/cmd/attr/man/man3/attr_list.3 linux-2.4-xfs/cmd/attr/man/man3/attr_list.3 --- linux-2.4.7/cmd/attr/man/man3/attr_list.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man3/attr_list.3 Sun May 20 19:39:09 2001 @@ -0,0 +1,269 @@ +.TH ATTR_LIST 3 +.SH NAME +attr_list, attr_listf \- list the names of the user attributes of a filesystem object +.SH C SYNOPSIS +.PP +.sp +.nf +.B #include +.sp +.B "int attr_list (const char \(**path, char \(**buffer, " +.B " const int buffersize, int flags," +.B " attrlist_cursor_t \(**cursor);" +.PP +.B "int attr_listf (int fd, char \(**buffer, " +.B " const int buffersize, int flags," +.B " attrlist_cursor_t \(**cursor);" +.Op +.SH DESCRIPTION +The +.I attr_list +and +.I attr_listf +functions provide a way to list the existing attributes of a +filesystem object. +.P +.I Path\^ +points to a path name for a filesystem object, and +.I fd\^ +refers to the file descriptor associated with a file. +The +.I buffer +will be filled with a structure describing at least a portion of the +attributes associated with the given filesystem object. +.I Buffer +will be overwritten with an \f4attrlist_t\fP structure +containing a list of the attributes associated with +that filesystem object, up to a maximum of +.I buffersize +bytes. +The +.I buffer +must be sufficiently large to hold the appropriate data structures +plus at least one maximally sized attribute name, +but cannot be more than ATTR_MAX_VALUELEN (currently 64KB) bytes in length. +.PP +.Op c p a +The contents of an \f4attrlist_t\fP structure include the following members: +.P +.RS 3 +.nf +.ft 4 +.ta 9n 22n +__int32_t al_count; /\(** number of entries in attrlist \(**/ +__int32_t al_more; /\(** T/F: more attrs (do syscall again) \(**/ +__int32_t al_offset[1]; /\(** byte offsets of attrs [var-sized] \(**/ +.ft 1 +.fi +.RE +.PP +The +.I al_count +field shows the number of attributes represented in this buffer, +which is also the number of elements in the +.I al_offset +array. +The +.I al_more +field will be non-zero if another +.I attr_list +call would result in more attributes. +The +.I al_offset +array contains the byte offset within the +.I buffer +of the structure describing each of the attributes, +an \f4attrlist_ent_t\fP structure. +The \f4ATTR_ENTRY(buffer, index)\fP macro will help with decoding the list. +It takes a pointer to the +.I buffer +and an +.I index +into the +.I al_offset +array and returns a pointer to the corresponding +\f4attrlist_ent_t\fP structure. +.PP +The contents of an \f4attrlist_ent_t\fP structure +include the following members: +.P +.RS 3 +.nf +.ft 4 +.ta 9n 22n +u_int32_t a_valuelen; /\(** number bytes in value of attr \(**/ +char a_name[]; /\(** attr name (NULL terminated) \(**/ +.ft 1 +.fi +.Op +.RE +.PP +The +.I a_valuelen +field shows the size in bytes of the value +associated with the attribute whose name is stored in the +.I a_name +field. +The name is a NULL terminated string. +.PP +Note that the value of the attribute cannot be obtained through +this interface, the +.I attr_get +call should be used to get the value. +The +.I attr_list +interface tells the calling process how large of a buffer +it must have in order to get the attribute\'s value. +.PP +The +.I flags +argument can contain the following symbols bitwise OR\'ed together: +.TP +.SM +\%ATTR_ROOT +List the attributes that are in the +.B root +address space, not in the +.B user +address space. +(limited to use by super-user only) +.TP +.SM +\%ATTR_DONTFOLLOW +Do not follow symbolic links when resolving a +.I path +on an +.I attr_list +function call. +The default is to follow symbolic links. +.PP +The +.I cursor +argument is a pointer to an opaque data structure that the kernel uses +to track the calling process\'s position in the attribute list. +The only valid operations on a +.I cursor +are to pass it into an +.I attr_list +function call or to zero it out. +It should be zero\'ed out before the first +.I attr_list +call. +Note that multi-threaded applications may keep more than one +.I cursor +in order to serve multiple contexts, ie: the +.I attr_list +call is "thread-safe". +.PP +.I attr_list +will fail if one or more of the following are true: +.TP 17 +.SM +\%[ENOENT] +The named file does not exist. +.TP +.SM +\%[EPERM] +The effective user +.SM ID +does not match the owner of the file +and the effective user +.SM ID +is not super-user. +.TP +.SM +\%[ENOTDIR] +A component of the +path prefix +is not a directory. +.TP +.SM +\%[EACCES] +Search permission is denied on a +component of the +path prefix. +.TP +.SM +\%[EINVAL] +A bit was set in the +.I flag +argument that is not defined for this system call, +or the buffer was too small or too large. +.TP +.SM +\%[EFAULT] +Either +.I Path +or +.I buffer +points outside the allocated address space of the process, or +.I buffer +or +.I bufsize +are not 32bit aligned. +.TP +.SM +\%[ELOOP] +A path name lookup involved too many symbolic links. +.TP +.SM +\%[ENAMETOOLONG] +The length of +.I path +exceeds +.SM +.RI { MAXPATHLEN }, +or a pathname component is longer than +.SM +.RI { MAXNAMELEN }. +.TP +.SM +\%[ENOATTR] +.I attribute\^ +does not exist for this file. +.PP +.I attr_listf\^ +will fail if: +.TP 15 +.SM +\%[EINVAL] +A bit was set in the +.I flag +argument that is not defined for this system call, or +.I fd\^ +refers to a socket, not a file, +or the buffer was too small or too large. +.TP +.SM +\%[EFAULT] +Either +.I Path +or +.I buffer +points outside the allocated address space of the process, or +.I buffer +or +.I bufsize +are not 32bit aligned. +.TP +.SM +\%[EBADF] +.I Fd\^ +does not refer to a valid descriptor. +.SH "SEE ALSO" +attr(1), +.br +attrctl(2), +.br +attr_get(3), attr_getf(3), +.br +attr_multi(3), attr_multif(3) +.br +attr_remove(3), attr_removef(3), +.br +attr_set(3), attr_set(3) +.SH "DIAGNOSTICS" +Upon successful completion, a value of 0 is returned. +Otherwise, a value of \-1 is returned and +.I errno\^ +is set to indicate the error. diff -rNu linux-2.4.7/cmd/attr/man/man3/attr_multi.3 linux-2.4-xfs/cmd/attr/man/man3/attr_multi.3 --- linux-2.4.7/cmd/attr/man/man3/attr_multi.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man3/attr_multi.3 Sun May 20 19:39:09 2001 @@ -0,0 +1,279 @@ +.TH ATTR_MULTI 3 +.SH NAME +attr_multi, attr_multif \- manipulate multiple user attributes on a filesystem object at once +.SH C SYNOPSIS +.PP +.sp +.nf +.B #include +.sp +.B "int attr_multi (const char \(**path, attr_multiop_t \(**oplist, " +.B " int count, int flags);" +.PP +.B "int attr_multif (int fd, attr_multiop_t \(**oplist, " +.B " int count, int flags);" +.Op +.SH DESCRIPTION +The +.I attr_multi +and +.I attr_multif +functions provide a way to operate on multiple attributes of a +filesystem object at once. +.P +.I Path +points to a path name for a filesystem object, and +.I fd +refers to the file descriptor associated with a file. +The +.I oplist +is an array of \f4attr_multiop_t\fP structures. +Each element in that array describes a single attribute operation +and provides all the information required to carry out that operation +and to check for success or failure of that operation. +.I Count +tells how many elements are in the +.I oplist +array. +.PP +.Op c p a +The contents of an \f4attr_multiop_t\fP structure include +the following members: +.P +.RS 3 +.nf +.ft 4 +.ta 9n 22n +int am_opcode; /* which operation to perform (see below) */ +int am_error; /* [out arg] result of this sub-op (an errno) */ +char *am_attrname; /* attribute name to work with */ +char *am_attrvalue; /* [in/out arg] attribute value (raw bytes) */ +int am_length; /* [in/out arg] length of value */ +int am_flags; /* flags (bit-wise OR of #defines below) */ +.ft 1 +.fi +.RE +.PP +The +.I am_opcode +field defines how the remaining fields are to be interpreted +and can take on one of the following values: +.P +.RS 3 +.nf +.ft 4 +.ta 9n 22n +ATTR_OP_GET /* return the indicated attr's value */ +ATTR_OP_SET /* set/create the indicated attr/value pair */ +ATTR_OP_REMOVE /* remove the indicated attr */ +.ft 1 +.fi +.RE +.PP +The +.I am_error +field will contain the appropriate error result code +if that sub-operation fails. +The result codes for a given sub-operation are a subset of +the result codes that are possible from the corresponding +single-attribute function call. +For example, the result code possible from an \f4ATTR_OP_GET\fP +sub-operation are a subset of those that can be returned from an +.I attr_get +function call. +.PP +The +.I am_attrname +field is a pointer to a NULL terminated string giving the attribute name +that the sub-operation should operate on. +.PP +The +.I am_attrvalue, +.I am_length +and +.I am_flags +fields are used to store the value of the named attribute, +and some control flags for that sub-operation, respectively. +Their use varies depending on the value of the +.I am_opcode +field. +.TP +.SM +.B \%ATTR_OP_GET +The +.I am_attrvalue +field is a pointer to a empty buffer that will be overwritten +with the value of the named attribute. +The +.I am_length +field is initially the total size of the memory buffer that the +.I am_attrvalue +field points to. +After the operation, the +.I am_length +field contains the actual size of the attribute\'s value. +The +.I am_flags +field may be set to the \f4ATTR_ROOT\fP flag. +If the process has appropriate priviledges, +the ROOT namespace will be searched for the named attribute, +otherwise the USER namespace will be searched. +.TP +.SM +.B \%ATTR_OP_SET +The +.I am_attrvalue +and +.I am_length +fields contain the new value for the given attribute name and its length. +The \f4ATTR_ROOT\fP flag may be set in the +.I am_flags +field. +If the process has appropriate priviledges, +the ROOT namespace will be searched for the named attribute, +otherwise the USER namespace will be searched. +The \f4ATTR_CREATE\fP and the \f4ATTR_REPLACE\fP flags +may also be set in the +.I am_flags +field (but not simultaneously). +If the \f4ATTR_CREATE\fP flag is set, +the sub-operation will set the +.I am_error +field to EEXIST if the named attribute already exists. +If the \f4ATTR_REPLACE\fP flag is set, +the sub-operation will set the +.I am_error +field to ENOATTR if the named attribute does not already exist. +If neither of those two flags are set and the attribute does not exist, +then the attribute will be created with the given value. +If neither of those two flags are set and the attribute already exists, +then the value will be replaced with the given value. +.TP +.SM +.B \%ATTR_OP_REMOVE +The +.I am_attrvalue +and +.I am_length +fields are not used and are ignored. +The +.I am_flags +field may be set to the \f4ATTR_ROOT\fP flag. +If the process has appropriate priviledges, +the ROOT namespace will be searched for the named attribute, +otherwise the USER namespace will be searched. +.PP +The +.I flags +argument to the +.I attr_multi +call is used to control following of symbolic links in the +.I path +argument. +The default is to follow symbolic links, +.I flags +should be set to ATTR_DONTFOLLOW to not follow symbolic links. +.PP +.I attr_multi +will fail if one or more of the following are true: +.TP 17 +.SM +\%[ENOENT] +The named file does not exist. +.TP +.SM +\%[EPERM] +The effective user +.SM ID +does not match the owner of the file +and the effective user +.SM ID +is not super-user. +.TP +.SM +\%[ENOTDIR] +A component of the +path prefix +is not a directory. +.TP +.SM +\%[EACCES] +Search permission is denied on a +component of the +path prefix. +.TP +.SM +\%[EINVAL] +A bit other than ATTR_DONTFOLLOW was set in the +.I flag +argument. +.TP +.SM +\%[EFAULT] +.I Path, +or +.I oplist +points outside the allocated address space of the process. +.TP +.SM +\%[ELOOP] +A path name lookup involved too many symbolic links. +.TP +.SM +\%[ENAMETOOLONG] +The length of +.I path +exceeds +.SM +.RI { MAXPATHLEN }, +or a pathname component is longer than +.SM +.RI { MAXNAMELEN }. +.PP +.I attr_multif +will fail if: +.TP 15 +.SM +\%[EINVAL] +A bit was set in the +.I flag +argument, or +.I fd\^ +refers to a socket, not a file. +.TP +.SM +\%[EFAULT] +.I Oplist +points outside the allocated address space of the process. +.TP +.SM +\%[EBADF] +.I Fd\^ +does not refer to a valid descriptor. +.SH "SEE ALSO" +attr(1), +.br +attrctl(2), +.br +attr_get(3), attr_getf(3), +.br +attr_list(3), attr_list(3) +.br +attr_remove(3), attr_removef(3), +.br +attr_set(3), attr_set(3) +.SH "DIAGNOSTICS" +Upon successful completion of the +.I attr_multi +call, a value of 0 is returned. +Otherwise, a value of \-1 is returned and +.I errno +is set to indicate the error. +Note that the individual operations listed in the +.I oplist +array each have their own error return fields. +The +.I errno +variable only records the result of the +.I attr_multi +call itself, not the result of any of the sub-operations. diff -rNu linux-2.4.7/cmd/attr/man/man3/attr_remove.3 linux-2.4-xfs/cmd/attr/man/man3/attr_remove.3 --- linux-2.4.7/cmd/attr/man/man3/attr_remove.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man3/attr_remove.3 Sun May 20 19:39:09 2001 @@ -0,0 +1,155 @@ +.TH ATTR_REMOVE 3 +.SH NAME +attr_remove, attr_removef \- remove a user attribute of a filesystem object +.SH C SYNOPSIS +.PP +.sp +.nf +.B #include +.sp +.B "int attr_remove (const char \(**path, const char \(**attrname, int flags);" +.PP +.B "int attr_removef (int fd, const char \(**attrname, int flags);" +.Op +.SH DESCRIPTION +The +.I attr_remove +and +.I attr_removef +functions provide a way to remove previously created attributes +from filesystem objects. +.P +.I Path\^ +points to a path name for a filesystem object, and +.I fd\^ +refers to the file descriptor associated with a file. +If the attribute +.I attrname +exists, the attribute name and value will be removed from the +fileystem object. +The +.I flags +argument can contain the following symbols bitwise OR\'ed together: +.TP +.SM +\%ATTR_ROOT +Look for +.I attrname +in the +.B root +address space, not in the +.B user +address space. +(limited to use by super-user only) +.TP +.SM +\%ATTR_DONTFOLLOW +Do not follow symbolic links when resolving a +.I path +on an +.I attr_remove +function call. +The default is to follow symbolic links. +.PP +.I attr_remove +will fail if one or more of the following are true: +.TP 17 +.SM +\%[ENOATTR] +The attribute name given is not associated with the indicated +filesystem object. +.TP +.SM +\%[ENOENT] +The named file does not exist. +.TP +.SM +\%[EPERM] +The effective user +.SM ID +does not match the owner of the file +and the effective user +.SM ID +is not super-user. +.TP +.SM +\%[ENOTDIR] +A component of the +path prefix +is not a directory. +.TP +.SM +\%[EACCES] +Search permission is denied on a +component of the +path prefix. +.TP +.SM +\%[EINVAL] +A bit was set in the +.I flag +argument that is not defined for this system call. +.TP +.SM +\%[EFAULT] +.I Path +points outside the allocated address space of the process. +.TP +.SM +\%[ELOOP] +A path name lookup involved too many symbolic links. +.TP +.SM +\%[ENAMETOOLONG] +The length of +.I path +exceeds +.SM +.RI { MAXPATHLEN }, +or a pathname component is longer than +.SM +.RI { MAXNAMELEN }. +.PP +.I attr_removef\^ +will fail if: +.TP 15 +.SM +\%[ENOATTR] +The attribute name given is not associated with the indicated +filesystem object. +.TP +.SM +\%[EINVAL] +A bit was set in the +.I flag +argument that is not defined for this system call, +or +.I fd\^ +refers to a socket, not a file. +.TP +.SM +\%[EFAULT] +.I Attrname +points outside the allocated address space of the process. +.TP +.SM +\%[EBADF] +.I Fd\^ +does not refer to a valid descriptor. +.SH "SEE ALSO" +attr(1), +.br +attrctl(2), +.br +attr_get(3), attr_getf(3), +.br +attr_list(3), attr_listf(3) +.br +attr_multi(3), attr_multif(3) +.br +attr_set(3), attr_setf(3), +.SH "DIAGNOSTICS" +Upon successful completion, a value of 0 is returned. +Otherwise, a value of \-1 is returned and +.I errno\^ +is set to indicate the error. diff -rNu linux-2.4.7/cmd/attr/man/man3/attr_set.3 linux-2.4-xfs/cmd/attr/man/man3/attr_set.3 --- linux-2.4.7/cmd/attr/man/man3/attr_set.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/attr/man/man3/attr_set.3 Sun May 20 19:39:09 2001 @@ -0,0 +1,215 @@ +.TH ATTR_SET 3 +.SH NAME +attr_set, attr_setf \- set the value of a user attribute of a filesystem object +.SH C SYNOPSIS +.PP +.sp +.nf +.B #include +.sp +.B "int attr_set (const char \(**path, const char \(**attrname, " +.B " const char \(**attrvalue, const int valuelength," +.B " int flags);" +.PP +.B "int attr_setf (int fd, const char \(**attrname, " +.B " const char \(**attrvalue, const int valuelength," +.B " int flags);" +.Op +.SH DESCRIPTION +The +.I attr_set +and +.I attr_setf +functions provide a way to create attributes and set/change their values. +.P +.I Path\^ +points to a path name for a filesystem object, and +.I fd\^ +refers to the file descriptor associated with a file. +If the attribute +.I attrname +does not exist, an attribute with the given name and value will be created +and associated with that indicated filesystem object. +If an attribute with that name already exists on that filesystem object, +the existing value is replaced with the new value given in this call. +The new attribute value is copied from the +.I attrvalue +buffer for a total of +.I valuelength +bytes. +The +.I flags +argument can contain the following symbols bitwise OR\'ed together: +.TP +.SM +\%ATTR_ROOT +Look for +.I attrname +in the +.B root +address space, not in the +.B user +address space. +(limited to use by super-user only) +.TP +.SM +\%ATTR_DONTFOLLOW +Do not follow symbolic links when resolving a +.I path +on an +.I attr_set +function call. +The default is to follow symbolic links. +.TP +.SM +\%ATTR_CREATE +Return an error (EEXIST) if an attribute of the given name +already exists on the indicated filesystem object, +otherwise create an attribute with the given name and value. +This flag is used to implement a pure create operation, +without this flag +.I attr_set +will create the attribute if it does not already exist. +An error (EINVAL) will be returned if both ATTR_CREATE and ATTR_REPLACE +are set in the same call. +.TP +.SM +\%ATTR_REPLACE +Return an error (ENOATTR) if an attribute of the given name +does not already exist on the indicated filesystem object, +otherwise replace the existing attribute\'s value with the given value. +This flag is used to implement a pure replacement operation, +without this flag +.I attr_set +will create the attribute if it does not already exist. +An error (EINVAL) will be returned if both ATTR_CREATE and ATTR_REPLACE +are set in the same call. +.PP +.I attr_set +will fail if one or more of the following are true: +.TP 17 +.SM +\%[ENOATTR] +The attribute name given is not associated with the indicated +filesystem object and the ATTR_REPLACE flag bit was set. +.TP +.SM +\%[E2BIG] +The value of the given attribute is too large, it exceeds the +maximum allowable size of an attribute value. +.TP +.SM +\%[EEXIST] +The attribute name given is already associated with the indicated +filesystem object and the ATTR_CREATE flag bit was set. +.TP +.SM +\%[ENOENT] +The named file does not exist. +.TP +.SM +\%[EPERM] +The effective user +.SM ID +does not match the owner of the file +and the effective user +.SM ID +is not super-user. +.TP +.SM +\%[ENOTDIR] +A component of the +path prefix +is not a directory. +.TP +.SM +\%[EACCES] +Search permission is denied on a +component of the +path prefix. +.TP +.SM +\%[EINVAL] +A bit was set in the +.I flag +argument that is not defined for this system call, +or both the ATTR_CREATE and ATTR_REPLACE flags bits were set. +.TP +.SM +\%[EFAULT] +.I Path, +.I attrname, +or +.I attrvalue +points outside the allocated address space of the process. +.TP +.SM +\%[ELOOP] +A path name lookup involved too many symbolic links. +.TP +.SM +\%[ENAMETOOLONG] +The length of +.I path +exceeds +.SM +.RI { MAXPATHLEN }, +or a pathname component is longer than +.SM +.RI { MAXNAMELEN }. +.PP +.I attr_setf\^ +will fail if: +.TP 15 +.SM +\%[ENOATTR] +The attribute name given is not associated with the indicated +filesystem object and the ATTR_REPLACE flag bit was set. +.TP +.SM +\%[E2BIG] +The value of the given attribute is too large, it exceeds the +maximum allowable size of an attribute value. +.TP +.SM +\%[EEXIST] +The attribute name given is already associated with the indicated +filesystem object and the ATTR_CREATE flag bit was set. +.TP +.SM +\%[EINVAL] +A bit was set in the +.I flag +argument that is not defined for this system call, +or both the ATTR_CREATE and ATTR_REPLACE flags bits were set, or +.I fd\^ +refers to a socket, not a file. +.TP +.SM +\%[EFAULT] +.I Attrname, +or +.I attrvalue +points outside the allocated address space of the process. +.TP +.SM +\%[EBADF] +.I Fd\^ +does not refer to a valid descriptor. +.SH "SEE ALSO" +attr(1), +.br +attrctl(2), +.br +attr_get(3), attr_getf(3), +.br +attr_list(3), attr_listf(3) +.br +attr_multi(3), attr_multif(3) +.br +attr_remove(3), attr_removef(3), +.SH "DIAGNOSTICS" +Upon successful completion, a value of 0 is returned. +Otherwise, a value of \-1 is returned and +.I errno\^ +is set to indicate the error. diff -rNu linux-2.4.7/cmd/dmapi/CVS/Entries linux-2.4-xfs/cmd/dmapi/CVS/Entries --- linux-2.4.7/cmd/dmapi/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/CVS/Entries Thu Jul 5 11:43:46 2001 @@ -0,0 +1,12 @@ +/Makefile/1.2/Wed Jun 13 18:06:23 2001/-ko/ +/Makepkgs/1.3/Thu Mar 29 06:30:35 2001/-ko/ +/README/1.1/Wed Jan 17 01:36:55 2001/-ko/ +/VERSION/1.3/Wed Jun 13 18:06:23 2001/-ko/ +/aclocal.m4/1.1/Wed Jun 13 18:06:23 2001/-ko/ +/config.guess/1.1/Wed Jun 13 18:06:23 2001/-ko/ +/config.sub/1.1/Wed Jun 13 18:06:23 2001/-ko/ +/configure.in/1.7/Wed Jun 13 18:06:23 2001/-ko/ +/install-sh/1.2/Wed Jun 13 18:06:23 2001/-ko/ +/ltconfig/1.1/Wed Jun 13 18:06:23 2001/-ko/ +/ltmain.sh/1.1/Wed Jun 13 18:06:23 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/dmapi/CVS/Entries.Log linux-2.4-xfs/cmd/dmapi/CVS/Entries.Log --- linux-2.4.7/cmd/dmapi/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/CVS/Entries.Log Thu Jul 5 11:43:48 2001 @@ -0,0 +1,6 @@ +A D/build//// +A D/debian//// +A D/doc//// +A D/include//// +A D/libdm//// +A D/man//// diff -rNu linux-2.4.7/cmd/dmapi/CVS/Repository linux-2.4-xfs/cmd/dmapi/CVS/Repository --- linux-2.4.7/cmd/dmapi/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/CVS/Repository Thu Jul 5 11:43:42 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/dmapi diff -rNu linux-2.4.7/cmd/dmapi/CVS/Root linux-2.4-xfs/cmd/dmapi/CVS/Root --- linux-2.4.7/cmd/dmapi/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/CVS/Root Thu Jul 5 11:43:42 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/dmapi/Makefile linux-2.4-xfs/cmd/dmapi/Makefile --- linux-2.4.7/cmd/dmapi/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/Makefile Wed Jun 13 13:06:23 2001 @@ -0,0 +1,80 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = . +HAVE_BUILDDEFS = $(shell test -f $(TOPDIR)/include/builddefs && echo yes || echo no) + +ifeq ($(HAVE_BUILDDEFS), yes) +include $(TOPDIR)/include/builddefs +endif + +CONFIGURE = configure include/builddefs +LIBTOOL_LSRCFILES = config.guess config.sub ltmain.sh ltconfig \ + aclocal.m4 +LIBTOOL_DIRT = libtool +LSRCFILES = configure configure.in Makepkgs install-sh README VERSION +LSRCFILES += $(LIBTOOL_LSRCFILES) +LDIRT = config.log config.status config.cache confdefs.h conftest* \ + configure Logs/* built install.* install-dev.* *.gz \ + $(LIBTOOL_DIRT) + +SUBDIRS = include libdm man doc debian build + +default: $(CONFIGURE) +ifeq ($(HAVE_BUILDDEFS), no) + $(MAKE) -C . $@ +else + $(SUBDIRS_MAKERULE) +endif + +ifeq ($(HAVE_BUILDDEFS), yes) +include $(BUILDRULES) +else +clean: # if configure hasn't run, nothing to clean +endif + +$(CONFIGURE): configure.in include/builddefs.in VERSION + rm -f config.cache + autoconf + ./configure + +install: default + $(SUBDIRS_MAKERULE) + $(INSTALL) -m 755 -d $(PKG_DOC_DIR) + $(INSTALL) -m 644 README $(PKG_DOC_DIR) + +install-dev: default + $(SUBDIRS_MAKERULE) + +realclean distclean: clean + rm -f $(LDIRT) $(CONFIGURE) + [ ! -d Logs ] || rmdir Logs diff -rNu linux-2.4.7/cmd/dmapi/Makepkgs linux-2.4-xfs/cmd/dmapi/Makepkgs --- linux-2.4.7/cmd/dmapi/Makepkgs Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/Makepkgs Thu Mar 29 00:30:35 2001 @@ -0,0 +1,109 @@ +#! /bin/sh +# +# Make whichever packages have been requested. +# Defaults to RPMs. +# +LOGDIR=Logs + +type=rpm +verbose=false + +MAKE=${MAKE:-make} +test ! -z "$MAKE" && make=$MAKE + +for opt in $* +do + case "$opt" in + clean) + ;; # ignored, kept for backward compatibility + rpm) + type=rpm ;; + debian) + type=debian ;; + verbose) + verbose=true ;; + *) + echo "Usage: Makepkgs [verbose] [debian|rpm]"; exit 1 ;; + esac +done + +# start with a clean manifest +test -f files.rpm && rm -f files.rpm +test -f filesdevel.rpm && rm -f filesdevel.rpm + +test ! -d $LOGDIR && mkdir $LOGDIR +rm -rf $LOGDIR/* > /dev/null 2>&1 + +# build Debian packages, cleans itself before starting +SUDO=${SUDO:-sudo} +test ! -z "$SUDO" && sudo=$SUDO +if [ $type = debian ] ; then + LOGDEB=`pwd` + LOGDEB=../`basename $LOGDEB`.log + echo "== Debian build, log is $LOGDEB"; echo + if $verbose ; then + dpkg-buildpackage -r$SUDO | tee $LOGDEB + else + dpkg-buildpackage -r$SUDO > $LOGDEB + fi + exit 0 +fi + +# build RPM packages - manual clean before starting +echo "== clean, log is $LOGDIR/clean" +if $verbose ; then + $MAKE clean 2>&1 | tee $LOGDIR/clean +else + $MAKE clean > $LOGDIR/clean 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"$MAKE clean\" failed, see log in $LOGDIR/clean + tail $LOGDIR/clean + exit 1 +fi + +echo +echo "== configure, log is $LOGDIR/configure" +if $verbose ; then + autoconf 2>&1 | tee $LOGDIR/configure + ./configure 2>&1 | tee -a $LOGDIR/configure +else + autoconf > $LOGDIR/configure 2>&1 + ./configure >> $LOGDIR/configure 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"configure\" failed, see log in $LOGDIR/configure + tail $LOGDIR/configure + exit 1 +fi + +echo +echo "== default, log is $LOGDIR/default" +if $verbose ; then + $MAKE default 2>&1 | tee $LOGDIR/default +else + $MAKE default > $LOGDIR/default 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"$MAKE default\" failed, see log in $LOGDIR/default + tail $LOGDIR/default + exit 1 +fi + +echo +echo "== dist, log is $LOGDIR/dist" +[ ! -f .census ] && touch .census +if $verbose ; then + $MAKE -C build dist 2>&1 | tee $LOGDIR/dist +else + $MAKE -C build dist > $LOGDIR/dist 2>&1 +fi +if [ $? -ne 0 ] ; then + echo $MAKE dist failed, see log in $LOGDIR/dist + tail $LOGDIR/dist + exit 1 +else + grep '^Wrote:' $LOGDIR/dist | sed -e 's/\.\.\/\.\.\///' +fi + +exit 0 diff -rNu linux-2.4.7/cmd/dmapi/README linux-2.4-xfs/cmd/dmapi/README --- linux-2.4.7/cmd/dmapi/README Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/README Tue Jan 16 19:36:55 2001 @@ -0,0 +1,15 @@ +DMAPI package README +____________________ + +See the file doc/INSTALL for build, installation and post- +install configuration steps. + +Refer to the dmapi(3) manual page for general Data Management +API (DMAPI) information. + +For more information and details on how to contribute to the +XFS project see the web pages at: + http://oss.sgi.com/projects/xfs/ + +For more information on the build process, please refer to +the doc/PORTING document. diff -rNu linux-2.4.7/cmd/dmapi/VERSION linux-2.4-xfs/cmd/dmapi/VERSION --- linux-2.4.7/cmd/dmapi/VERSION Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/VERSION Wed Jun 13 13:06:23 2001 @@ -0,0 +1,16 @@ +# +# This file is used by configure to get version information +# +PKG_MAJOR=0 +PKG_MINOR=1 +PKG_REVISION=1 +PKG_BUILD=0 + + + +# Libtool versioning . +# These numbers refer to the library's interface, and have nothing to do with +# the version of the package. See chapter 6 of the Libtool manual. +PKG_LT_CURRENT=0 +PKG_LT_REVISION=0 +PKG_LT_AGE=0 diff -rNu linux-2.4.7/cmd/dmapi/aclocal.m4 linux-2.4-xfs/cmd/dmapi/aclocal.m4 --- linux-2.4.7/cmd/dmapi/aclocal.m4 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/aclocal.m4 Wed Jun 13 13:06:23 2001 @@ -0,0 +1,430 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + + +# serial 40 AC_PROG_LIBTOOL +AC_DEFUN(AC_PROG_LIBTOOL, +[AC_REQUIRE([AC_LIBTOOL_SETUP])dnl + +# Save cache, so that ltconfig can load it +AC_CACHE_SAVE + +# Actually configure libtool. ac_aux_dir is where install-sh is found. +CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ +LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \ +LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" \ +DLLTOOL="$DLLTOOL" AS="$AS" OBJDUMP="$OBJDUMP" \ +${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \ +$libtool_flags --no-verify $ac_aux_dir/ltmain.sh $lt_target \ +|| AC_MSG_ERROR([libtool configure failed]) + +# Reload cache, that may have been modified by ltconfig +AC_CACHE_LOAD + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ac_aux_dir/ltconfig $ac_aux_dir/ltmain.sh" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +# Redirect the config.log output again, so that the ltconfig log is not +# clobbered by the next message. +exec 5>>./config.log +]) + +AC_DEFUN(AC_LIBTOOL_SETUP, +[AC_PREREQ(2.13)dnl +AC_REQUIRE([AC_ENABLE_SHARED])dnl +AC_REQUIRE([AC_ENABLE_STATIC])dnl +AC_REQUIRE([AC_ENABLE_FAST_INSTALL])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([AC_PROG_RANLIB])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_LD])dnl +AC_REQUIRE([AC_PROG_NM])dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +dnl + +case "$target" in +NONE) lt_target="$host" ;; +*) lt_target="$target" ;; +esac + +# Check for any special flags to pass to ltconfig. +# +# the following will cause an existing older ltconfig to fail, so +# we ignore this at the expense of the cache file... Checking this +# will just take longer ... bummer! +#libtool_flags="--cache-file=$cache_file" +# +test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared" +test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static" +test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install" +test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc" +test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" +ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN], +[libtool_flags="$libtool_flags --enable-dlopen"]) +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +[libtool_flags="$libtool_flags --enable-win32-dll"]) +AC_ARG_ENABLE(libtool-lock, + [ --disable-libtool-lock avoid locking (might break parallel builds)]) +test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock" +test x"$silent" = xyes && libtool_flags="$libtool_flags --silent" + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case "$lt_target" in +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case "`/usr/bin/file conftest.o`" in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_TRY_LINK([],[],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; + +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +]) +esac +]) + +# AC_LIBTOOL_DLOPEN - enable checks for dlopen support +AC_DEFUN(AC_LIBTOOL_DLOPEN, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])]) + +# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's +AC_DEFUN(AC_LIBTOOL_WIN32_DLL, [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])]) + +# AC_ENABLE_SHARED - implement the --enable-shared flag +# Usage: AC_ENABLE_SHARED[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN(AC_ENABLE_SHARED, [dnl +define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(shared, +changequote(<<, >>)dnl +<< --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case "$enableval" in +yes) enable_shared=yes ;; +no) enable_shared=no ;; +*) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl +]) + +# AC_DISABLE_SHARED - set the default shared flag to --disable-shared +AC_DEFUN(AC_DISABLE_SHARED, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no)]) + +# AC_ENABLE_STATIC - implement the --enable-static flag +# Usage: AC_ENABLE_STATIC[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN(AC_ENABLE_STATIC, [dnl +define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(static, +changequote(<<, >>)dnl +<< --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case "$enableval" in +yes) enable_static=yes ;; +no) enable_static=no ;; +*) + enable_static=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_static=AC_ENABLE_STATIC_DEFAULT)dnl +]) + +# AC_DISABLE_STATIC - set the default static flag to --disable-static +AC_DEFUN(AC_DISABLE_STATIC, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no)]) + + +# AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag +# Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)] +# Where DEFAULT is either `yes' or `no'. If omitted, it defaults to +# `yes'. +AC_DEFUN(AC_ENABLE_FAST_INSTALL, [dnl +define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_ARG_ENABLE(fast-install, +changequote(<<, >>)dnl +<< --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT], +changequote([, ])dnl +[p=${PACKAGE-default} +case "$enableval" in +yes) enable_fast_install=yes ;; +no) enable_fast_install=no ;; +*) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:," + for pkg in $enableval; do + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$ac_save_ifs" + ;; +esac], +enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl +]) + +# AC_ENABLE_FAST_INSTALL - set the default to --disable-fast-install +AC_DEFUN(AC_DISABLE_FAST_INSTALL, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no)]) + +# AC_PROG_LD - find the path to the GNU or non-GNU linker +AC_DEFUN(AC_PROG_LD, +[AC_ARG_WITH(gnu-ld, +[ --with-gnu-ld assume the C compiler uses GNU ld [default=no]], +test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no) +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +ac_prog=ld +if test "$ac_cv_prog_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. +changequote(,)dnl + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' +changequote([,])dnl + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(ac_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + ac_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$ac_cv_path_LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" +else + ac_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$ac_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_PROG_LD_GNU +]) + +AC_DEFUN(AC_PROG_LD_GNU, +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], ac_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + ac_cv_prog_gnu_ld=yes +else + ac_cv_prog_gnu_ld=no +fi]) +]) + +# AC_PROG_NM - find the path to a BSD-compatible name lister +AC_DEFUN(AC_PROG_NM, +[AC_MSG_CHECKING([for BSD-compatible nm]) +AC_CACHE_VAL(ac_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + ac_cv_path_NM="$NM" +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -B" + break + elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + ac_cv_path_NM="$ac_dir/nm -p" + break + else + ac_cv_path_NM=${ac_cv_path_NM="$ac_dir/nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm +fi]) +NM="$ac_cv_path_NM" +AC_MSG_RESULT([$NM]) +]) + +# AC_CHECK_LIBM - check for math library +AC_DEFUN(AC_CHECK_LIBM, +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case "$lt_target" in +*-*-beos* | *-*-cygwin*) + # These system don't have libm + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, main, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, main, LIBM="-lm") + ;; +esac +]) + +# AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl convenience library and INCLTDL to the include flags for +# the libltdl header and adds --enable-ltdl-convenience to the +# configure arguments. Note that LIBLTDL and INCLTDL are not +# AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If DIR is not +# provided, it is assumed to be `libltdl'. LIBLTDL will be prefixed +# with '${top_builddir}/' and INCLTDL will be prefixed with +# '${top_srcdir}/' (note the single quotes!). If your package is not +# flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +AC_DEFUN(AC_LIBLTDL_CONVENIENCE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + case "$enable_ltdl_convenience" in + no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; + "") enable_ltdl_convenience=yes + ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; + esac + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la + INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) +]) + +# AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for +# the libltdl installable library and INCLTDL to the include flags for +# the libltdl header and adds --enable-ltdl-install to the configure +# arguments. Note that LIBLTDL and INCLTDL are not AC_SUBSTed, nor is +# AC_CONFIG_SUBDIRS called. If DIR is not provided and an installed +# libltdl is not found, it is assumed to be `libltdl'. LIBLTDL will +# be prefixed with '${top_builddir}/' and INCLTDL will be prefixed +# with '${top_srcdir}/' (note the single quotes!). If your package is +# not flat and you're not using automake, define top_builddir and +# top_srcdir appropriately in the Makefiles. +# In the future, this macro may have to be called after AC_PROG_LIBTOOL. +AC_DEFUN(AC_LIBLTDL_INSTALLABLE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, main, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi + ]) + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" + LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la + INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + INCLTDL= + fi +]) + +dnl old names +AC_DEFUN(AM_PROG_LIBTOOL, [indir([AC_PROG_LIBTOOL])])dnl +AC_DEFUN(AM_ENABLE_SHARED, [indir([AC_ENABLE_SHARED], $@)])dnl +AC_DEFUN(AM_ENABLE_STATIC, [indir([AC_ENABLE_STATIC], $@)])dnl +AC_DEFUN(AM_DISABLE_SHARED, [indir([AC_DISABLE_SHARED], $@)])dnl +AC_DEFUN(AM_DISABLE_STATIC, [indir([AC_DISABLE_STATIC], $@)])dnl +AC_DEFUN(AM_PROG_LD, [indir([AC_PROG_LD])])dnl +AC_DEFUN(AM_PROG_NM, [indir([AC_PROG_NM])])dnl + +dnl This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL])dnl + diff -rNu linux-2.4.7/cmd/dmapi/build/CVS/Entries linux-2.4-xfs/cmd/dmapi/build/CVS/Entries --- linux-2.4.7/cmd/dmapi/build/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/CVS/Entries Thu Jul 5 11:43:46 2001 @@ -0,0 +1,2 @@ +/Makefile/1.2/Thu Mar 1 01:31:21 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/dmapi/build/CVS/Entries.Log linux-2.4-xfs/cmd/dmapi/build/CVS/Entries.Log --- linux-2.4.7/cmd/dmapi/build/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/CVS/Entries.Log Thu Jul 5 11:43:47 2001 @@ -0,0 +1,2 @@ +A D/rpm//// +A D/tar//// diff -rNu linux-2.4.7/cmd/dmapi/build/CVS/Repository linux-2.4-xfs/cmd/dmapi/build/CVS/Repository --- linux-2.4.7/cmd/dmapi/build/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/CVS/Repository Thu Jul 5 11:43:46 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/dmapi/build diff -rNu linux-2.4.7/cmd/dmapi/build/CVS/Root linux-2.4-xfs/cmd/dmapi/build/CVS/Root --- linux-2.4.7/cmd/dmapi/build/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/CVS/Root Thu Jul 5 11:43:46 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/dmapi/build/Makefile linux-2.4-xfs/cmd/dmapi/build/Makefile --- linux-2.4.7/cmd/dmapi/build/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/Makefile Wed Feb 28 19:31:21 2001 @@ -0,0 +1,76 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +MANIFEST=src-manifest +SRCTAR=$(PKG_NAME)-$(PKG_VERSION).src.tar.gz + +LDIRT = *-manifest *.gz $(TOPDIR)/$(PKG_NAME)-* + +# for clean and clobber +SUBDIRS = tar rpm + +# nothing to build here (it's all packaging) +default install install-dev : + +include $(BUILDRULES) + +# Symlink in the TOPDIR is used to pack files relative to +# product-version directory. +$(MANIFEST) : $(_FORCE) + @if [ ! -L $(TOPDIR)/$(PKG_NAME)-$(PKG_VERSION) ] ; then \ + $(LN_S) . $(TOPDIR)/$(PKG_NAME)-$(PKG_VERSION) ; \ + fi + @CDIR=`pwd`; cd $(TOPDIR); \ + $(MAKE) --no-print-directory source | \ + sed -e 's/^\./$(PKG_NAME)-$(PKG_VERSION)/' > $$CDIR/$@ ;\ + if [ $$? -ne 0 ] ; then \ + exit 1; \ + else \ + unset TAPE; \ + $(TAR) -T $$CDIR/$@ -cf - | $(ZIP) --best > $$CDIR/$(SRCTAR); \ + fi + +dist : default $(MANIFEST) + @DIST_MANIFEST=`pwd`/bin-manifest; DIST_ROOT=/tmp/$$$$; \ + export DIST_MANIFEST DIST_ROOT; \ + rm -f $$DIST_MANIFEST; \ + echo === install === && $(MAKE) -C $(TOPDIR) install || exit $$?; \ + if [ -x $(TAR) ]; then \ + ( echo "=== tar ===" && $(MAKEF) -C tar $@ || exit $$? ); \ + fi; \ + if [ -x $(RPM) ]; then \ + ( echo "=== rpm ===" && $(MAKEF) -C rpm $@ || exit $$? ); \ + fi; \ + test -z "$$KEEP_DIST_ROOT" || rm -rf $$DIST_ROOT; echo Done diff -rNu linux-2.4.7/cmd/dmapi/build/rpm/CVS/Entries linux-2.4-xfs/cmd/dmapi/build/rpm/CVS/Entries --- linux-2.4.7/cmd/dmapi/build/rpm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/rpm/CVS/Entries Thu Jul 5 11:43:47 2001 @@ -0,0 +1,5 @@ +/Makefile/1.3/Tue Mar 20 19:36:13 2001/-ko/ +/dmapi.spec.in/1.4/Wed Jun 13 18:06:23 2001/-ko/ +/macros.template/1.1/Wed Jan 17 01:36:55 2001/-ko/ +/rpm-2.rc.template/1.1/Wed Jan 17 01:36:55 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/dmapi/build/rpm/CVS/Repository linux-2.4-xfs/cmd/dmapi/build/rpm/CVS/Repository --- linux-2.4.7/cmd/dmapi/build/rpm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/rpm/CVS/Repository Thu Jul 5 11:43:46 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/dmapi/build/rpm diff -rNu linux-2.4.7/cmd/dmapi/build/rpm/CVS/Root linux-2.4-xfs/cmd/dmapi/build/rpm/CVS/Root --- linux-2.4.7/cmd/dmapi/build/rpm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/rpm/CVS/Root Thu Jul 5 11:43:46 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/dmapi/build/rpm/Makefile linux-2.4-xfs/cmd/dmapi/build/rpm/Makefile --- linux-2.4.7/cmd/dmapi/build/rpm/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/rpm/Makefile Tue Mar 20 13:36:13 2001 @@ -0,0 +1,78 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +TREEROOT = $(shell cd ${TOPDIR}; pwd) +include $(TOPDIR)/include/builddefs + +SPECF = $(PKG_NAME).spec +LDIRT = $(PKG_NAME)*.rpm $(SPECF) rpmmacros rpm-*.rc $(TOPDIR)/files*.rpm + +LSRCFILES = macros.template $(SPECF).in rpm-2.rc.template + +default install install-dev : + +include $(BUILDRULES) + +# generate a binary rpm file +dist : default $(SPECF) rpm-$(RPM_VERSION).rc + $(RPM) -ba --rcfile ./rpm-$(RPM_VERSION).rc $(SPECF) + +# Because rpm prior to v.2.90 does not support macros and old style config +# is not supported by rpm v.3, we have to resort to such ugly hacks +ifneq ($RPM_VERSION,2) +rpm-$(RPM_VERSION).rc : rpmmacros + sed -e '/^macrofiles:/s|~/.rpmmacros|rpmmacros|' $@ + +rpmmacros : macros.template + @sed -e 's|%topdir%|$(TREEROOT)|g' < $< > $@ +else +rpm-2.rc: rpm-2.rc.template + @sed -e 's|%topdir%|$(TOPDIR)|g' < $< > $@ +endif + +.PHONY: $(SPECF) +${SPECF} : ${SPECF}.in + sed -e's|@pkg_name@|$(PKG_NAME)|g' \ + -e's|@pkg_version@|$(PKG_VERSION)|g' \ + -e's|@pkg_release@|$(PKG_RELEASE)|g' \ + -e's|@pkg_distribution@|$(PKG_DISTRIBUTION)|g' \ + -e's|@pkg_builder@|$(PKG_BUILDER)|g' \ + -e's|@build_root@|$(DIST_ROOT)|g' \ + -e'/^BuildRoot: *$$/d' \ + -e's|@pkg_var_dir@|$(PKG_VAR_DIR)|g' \ + -e's|@pkg_share_dir@|$(PKG_SHARE_DIR)|g' \ + -e's|@pkg_log_dir@|$(PKG_LOG_DIR)|g' \ + -e's|@pkg_doc_dir@|$(PKG_DOC_DIR)|g' \ + -e's|@pkg_man_dir@|$(PKG_MAN_DIR)|g' \ + -e's|@pkg_tmp_dir@|$(PKG_TMP_DIR)|g' \ + -e's|@make@|$(MAKE)|g' < $< > $@ diff -rNu linux-2.4.7/cmd/dmapi/build/rpm/dmapi.spec.in linux-2.4-xfs/cmd/dmapi/build/rpm/dmapi.spec.in --- linux-2.4.7/cmd/dmapi/build/rpm/dmapi.spec.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/rpm/dmapi.spec.in Wed Jun 13 13:06:23 2001 @@ -0,0 +1,87 @@ +Summary: Data Management API runtime environment. +Name: @pkg_name@ +Version: @pkg_version@ +Release: @pkg_release@ +Distribution: @pkg_distribution@ +Packager: @pkg_builder@ +BuildRoot: @build_root@ +Prereq: /sbin/ldconfig /usr/bin/libtool +Source: @pkg_name@-@pkg_version@.src.tar.gz +Copyright: Copyright (C) 2000 Silicon Graphics, Inc. +Vendor: Silicon Graphics, Inc. +URL: http://oss.sgi.com/projects/xfs/ +Group: System Environment/Base + +%description +Files required by system software using the Data Management API +(DMAPI). This is used to implement the interface defined in the +X/Open document: Systems Management: Data Storage Managment +(XDSM) API dated February 1997. This interface is implemented +by the libdm library. + +%package devel +Summary: Data Management API static libraries and headers. +Group: Development/Libraries +Requires: @pkg_name@ + +%description devel +dmapi-devel contains the libraries and header files needed to +develop programs which make use of the Data Management API +(DMAPI). If you install dmapi-devel, you'll also want to install +the dmapi (runtime) package and the xfsprogs-devel package. + +# If .census exists, then no setup is necessary, just go and do the build, +# otherwise run setup +%prep +if [ -f .census ] ; then + if [ ! -d ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION} ] ; then + ln -s . ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION} + fi +else +%setup +touch .census +./configure +fi + +%build +@make@ + +%install +DIST_ROOT="$RPM_BUILD_ROOT" +DIST_INSTALL=`pwd`/install.manifest +DIST_INSTALL_DEV=`pwd`/install-dev.manifest +export DIST_ROOT DIST_INSTALL DIST_INSTALL_DEV +@make@ install DIST_MANIFEST="$DIST_INSTALL" +@make@ install-dev DIST_MANIFEST="$DIST_INSTALL_DEV" +files() +{ + sort | uniq | awk ' +$1 == "d" { printf ("%%%%dir %%%%attr(%s,%s,%s) %s\n", $2, $3, $4, $5); } +$1 == "f" { if (match ($6, "@pkg_man_dir@") || match ($6, "@pkg_doc_dir@")) + printf ("%%%%doc "); + if (match ($6, "@pkg_man_dir@")) + printf ("%%%%attr(%s,%s,%s) %s*\n", $2, $3, $4, $6); + else + printf ("%%%%attr(%s,%s,%s) %s\n", $2, $3, $4, $6); } +$1 == "l" { if (match ($3, "@pkg_man_dir@") || match ($3, "@pkg_doc_dir@")) + printf ("%%%%doc "); + if (match ($3, "@pkg_man_dir@")) + printf ("%attr(0777,root,root) %s*\n", $3); + else + printf ("%attr(0777,root,root) %s\n", $3); }' +} +set +x +files < "$DIST_INSTALL" > files.rpm +files < "$DIST_INSTALL_DEV" > filesdevel.rpm +set -x + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files -f files.rpm + +%files devel -f filesdevel.rpm diff -rNu linux-2.4.7/cmd/dmapi/build/rpm/macros.template linux-2.4-xfs/cmd/dmapi/build/rpm/macros.template --- linux-2.4.7/cmd/dmapi/build/rpm/macros.template Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/rpm/macros.template Tue Jan 16 19:36:55 2001 @@ -0,0 +1,30 @@ +# +# rpmrc.template +# +# Template to fudge rpm directory structure inside IRIX-like build +# environment + +# Force 386 build on all platforms +%_target i386-pc-linux +%_target_cpu i386 +%_target_os linux + +# topdir == $(WORKAREA) +%_topdir %topdir% + +# Following directories are specific to the topdir +# This is where build is done. In our case it's the same as $WORKAREA +%_builddir %topdir% + +# This is where foo.1.99.tar.gz is living in the real world. +# Be careful not to run full rpm build as it will override the sources +%_sourcedir %topdir%/build + +# This is where binary RPM and source RPM would end up +%_rpmdir %topdir%/build/rpm +%_srcrpmdir %topdir%/build/rpm +%_specdir %topdir%/build/rpm + +# Leave RPM files in the same directory - we're not building for +# multiple architectures +%_rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm diff -rNu linux-2.4.7/cmd/dmapi/build/rpm/rpm-2.rc.template linux-2.4-xfs/cmd/dmapi/build/rpm/rpm-2.rc.template --- linux-2.4.7/cmd/dmapi/build/rpm/rpm-2.rc.template Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/rpm/rpm-2.rc.template Tue Jan 16 19:36:55 2001 @@ -0,0 +1,25 @@ +# +# rpmrc.template +# +# Template to fudge rpm directory structure inside IRIX-like build +# environment + +# topdir == $(WORKAREA) +topdir: %topdir% + +# Following directories are specific to the topdir +# This is where build is done. In out case it's the same as $WORKAREA +# Be careful not to run full rpm build as it will override the sources +builddir: %topdir% + +# This is where foo.1.99.tar.gz is living in the real world. +sourcedir: %topdir%/build + +# This is where binary RPM and source RPM would end up +rpmdir: %topdir%/build/rpm +srcrpmdir: %topdir%/build/rpm +specdir: %topdir%/build/rpm + +# Leave RPM files in the same directory - we're not building for +# multiple architectures +rpmfilename: %{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm diff -rNu linux-2.4.7/cmd/dmapi/build/tar/CVS/Entries linux-2.4-xfs/cmd/dmapi/build/tar/CVS/Entries --- linux-2.4.7/cmd/dmapi/build/tar/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/tar/CVS/Entries Thu Jul 5 11:43:47 2001 @@ -0,0 +1,2 @@ +/Makefile/1.2/Thu Mar 1 01:48:49 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/dmapi/build/tar/CVS/Repository linux-2.4-xfs/cmd/dmapi/build/tar/CVS/Repository --- linux-2.4.7/cmd/dmapi/build/tar/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/tar/CVS/Repository Thu Jul 5 11:43:47 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/dmapi/build/tar diff -rNu linux-2.4.7/cmd/dmapi/build/tar/CVS/Root linux-2.4-xfs/cmd/dmapi/build/tar/CVS/Root --- linux-2.4.7/cmd/dmapi/build/tar/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/tar/CVS/Root Thu Jul 5 11:43:47 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/dmapi/build/tar/Makefile linux-2.4-xfs/cmd/dmapi/build/tar/Makefile --- linux-2.4.7/cmd/dmapi/build/tar/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/build/tar/Makefile Wed Feb 28 19:48:49 2001 @@ -0,0 +1,50 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +BINTAR=$(PKG_NAME)-$(PKG_VERSION).tar.gz +LDIRT = *.gz + +default install install-dev : + +include $(BUILDRULES) + +dist : default + @HERE=`pwd`; cd $${DIST_ROOT:-/}; \ + sort $$HERE/../bin-manifest | uniq | $(AWK) ' \ + $$1 == "f" { printf (".%s\n", $$6); } \ + $$1 == "d" { next; } \ + $$1 == "l" { printf (".%s\n", $$3); }' \ + | $(TAR) -T - -cf - | $(ZIP) --best > $$HERE/$(BINTAR) + @echo Wrote: `pwd`/$(BINTAR) diff -rNu linux-2.4.7/cmd/dmapi/config.guess linux-2.4-xfs/cmd/dmapi/config.guess --- linux-2.4.7/cmd/dmapi/config.guess Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/config.guess Wed Jun 13 13:06:23 2001 @@ -0,0 +1,1183 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 +# Free Software Foundation, Inc. +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner . +# Please send patches to . +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +# Use $HOST_CC if defined. $CC may point to a cross-compiler +if test x"$CC_FOR_BUILD" = x; then + if test x"$HOST_CC" != x; then + CC_FOR_BUILD="$HOST_CC" + else + if test x"$CC" != x; then + CC_FOR_BUILD="$CC" + else + CC_FOR_BUILD=cc + fi + fi +fi + + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +dummy=dummy-$$ +trap 'rm -f $dummy.c $dummy.o $dummy; exit 1' 1 2 15 + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # Netbsd (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # Determine the machine/vendor (is the vendor relevant). + case "${UNAME_MACHINE}" in + amiga) machine=m68k-cbm ;; + arm32) machine=arm-unknown ;; + atari*) machine=m68k-atari ;; + sun3*) machine=m68k-sun ;; + mac68k) machine=m68k-apple ;; + macppc) machine=powerpc-apple ;; + hp3[0-9][05]) machine=m68k-hp ;; + ibmrt|romp-ibm) machine=romp-ibm ;; + *) machine=${UNAME_MACHINE}-unknown ;; + esac + # The Operating System including object format. + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + # The OS release + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit 0 ;; + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <$dummy.s + .data +\$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main +main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + case `./$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + esac + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-cbm-sysv4 + exit 0;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy \ + && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i?86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:4) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` + if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=4.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy` + rm -f $dummy.c $dummy + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + *9??*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i?86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + hppa*:OpenBSD:*:*) + echo hppa-unknown-openbsd + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + i?86:BSD/386:*:* | i?86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i386-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:Linux:*:*) + + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + ld_help_string=`cd /; ld --help 2>&1` + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + *ia64) + echo "${UNAME_MACHINE}-unknown-linux" + exit 0 + ;; + i?86linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit 0 + ;; + elf_i?86) + echo "${UNAME_MACHINE}-pc-linux" + exit 0 + ;; + i?86coff) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 + ;; + sparclinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + armlinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + elf32arm*) + echo "${UNAME_MACHINE}-unknown-linux-gnuoldld" + exit 0 + ;; + armelf_linux*) + echo "${UNAME_MACHINE}-unknown-linux-gnu" + exit 0 + ;; + m68klinux) + echo "${UNAME_MACHINE}-unknown-linux-gnuaout" + exit 0 + ;; + elf32ppc | elf32ppclinux) + # Determine Lib Version + cat >$dummy.c < +#if defined(__GLIBC__) +extern char __libc_version[]; +extern char __libc_release[]; +#endif +main(argc, argv) + int argc; + char *argv[]; +{ +#if defined(__GLIBC__) + printf("%s %s\n", __libc_version, __libc_release); +#else + printf("unkown\n"); +#endif + return 0; +} +EOF + LIBC="" + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null + if test "$?" = 0 ; then + ./$dummy | grep 1\.99 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f $dummy.c $dummy + echo powerpc-unknown-linux-gnu${LIBC} + exit 0 + ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + cat <$dummy.s + .data + \$Lformat: + .byte 37,100,45,37,120,10,0 # "%d-%x\n" + + .text + .globl main + .align 4 + .ent main + main: + .frame \$30,16,\$26,0 + ldgp \$29,0(\$27) + .prologue 1 + .long 0x47e03d80 # implver \$0 + lda \$2,-1 + .long 0x47e20c21 # amask \$2,\$1 + lda \$16,\$Lformat + mov \$0,\$17 + not \$1,\$18 + jsr \$26,printf + ldgp \$29,0(\$26) + mov 0,\$16 + jsr \$26,exit + .end main +EOF + LIBC="" + $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null + if test "$?" = 0 ; then + case `./$dummy` in + 0-0) + UNAME_MACHINE="alpha" + ;; + 1-0) + UNAME_MACHINE="alphaev5" + ;; + 1-1) + UNAME_MACHINE="alphaev56" + ;; + 1-101) + UNAME_MACHINE="alphapca56" + ;; + 2-303) + UNAME_MACHINE="alphaev6" + ;; + 2-307) + UNAME_MACHINE="alphaev67" + ;; + esac + + objdump --private-headers $dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f $dummy.s $dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >$dummy.c < /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif +#ifdef __MIPSEB__ + printf ("%s-unknown-linux-gnu\n", argv[1]); +#endif +#ifdef __MIPSEL__ + printf ("%sel-unknown-linux-gnu\n", argv[1]); +#endif + return 0; +} +EOF + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + elif test "${UNAME_MACHINE}" = "s390"; then + echo s390-ibm-linux && exit 0 + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" + test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >$dummy.c < +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm $dummy.c $dummy && exit 0 + rm -f $dummy.c $dummy + fi ;; +# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions +# are messed up and put the nodename in both sysname and nodename. + i?86:DYNIX/ptx:4*:*) + echo i386-sequent-sysv4 + exit 0 ;; + i?86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit 0 ;; + i?86:*:5:7*) + # Fixed at (any) Pentium or better + UNAME_MACHINE=i586 + if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then + echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + i?86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:*:6*) + echo mips-sony-newsos6 + exit 0 ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + echo `uname -p`-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + if test "${UNAME_MACHINE}" = "x86pc"; then + UNAME_MACHINE=pc + fi + echo `uname -p`-${UNAME_MACHINE}-nto-qnx + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-W:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +#if !defined (ultrix) + printf ("vax-dec-bsd\n"); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm $dummy.c $dummy && exit 0 +rm -f $dummy.c $dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +#echo '(Unable to guess system type)' 1>&2 + +exit 1 diff -rNu linux-2.4.7/cmd/dmapi/config.sub linux-2.4-xfs/cmd/dmapi/config.sub --- linux-2.4.7/cmd/dmapi/config.sub Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/config.sub Wed Jun 13 13:06:23 2001 @@ -0,0 +1,1268 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 +# Free Software Foundation, Inc. +# +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner . +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +if [ x$1 = x ] +then + echo Configuration name missing. 1>&2 + echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 + echo "or $0 ALIAS" 1>&2 + echo where ALIAS is a recognized configuration type. 1>&2 + exit 1 +fi + +# First pass through any local machine types. +case $1 in + *local*) + echo $1 + exit 0 + ;; + *) + ;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \ + | 580 | i960 | h8300 \ + | x86 | ppcbe | mipsbe | mipsle | shbe | shle | armbe | armle \ + | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \ + | hppa64 \ + | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \ + | alphaev6[78] \ + | we32k | ns16k | clipper | i370 | sh | powerpc | powerpcle \ + | 1750a | dsp16xx | pdp11 | mips16 | mips64 | mipsel | mips64el \ + | mips64orion | mips64orionel | mipstx39 | mipstx39el \ + | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \ + | mips64vr5000 | miprs64vr5000el | mcore \ + | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \ + | thumb | d10v | fr30 | avr) + basic_machine=$basic_machine-unknown + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | h8500 | w65 | pj | pjl) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i[34567]86) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + # FIXME: clean up the formatting here. + vax-* | tahoe-* | i[34567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \ + | xmp-* | ymp-* \ + | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* | armbe-* | armle-* \ + | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \ + | hppa2.0n-* | hppa64-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \ + | alphaev6[78]-* \ + | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \ + | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \ + | mipstx39-* | mipstx39el-* | mcore-* \ + | f301-* | armv*-* | s390-* | sv1-* | t3e-* \ + | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \ + | thumb-* | v850-* | d30v-* | tic30-* | c30-* | fr30-* \ + | bs2000-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-cbm + ;; + amigaos | amigados) + basic_machine=m68k-cbm + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-cbm + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[34567]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[34567]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[34567]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[34567]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + i386-go32 | go32) + basic_machine=i386-unknown + os=-go32 + ;; + i386-mingw32 | mingw32) + basic_machine=i386-unknown + os=-mingw32 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + mmix*) + basic_machine=mmix-knuth + os=-mmixware + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + msdos) + basic_machine=i386-unknown + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86) + basic_machine=i686-pc + ;; + pentiumii | pentium2) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexen-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sparclite-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=t3e-cray + os=-unicos + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sparc | sparcv9) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + c4x*) + basic_machine=c4x-none + os=-coff + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i[34567]86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto*) + os=-nto-qnx + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -*MiNT) + os=-mint + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f301-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -*MiNT) + vendor=atari + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os diff -rNu linux-2.4.7/cmd/dmapi/configure.in linux-2.4-xfs/cmd/dmapi/configure.in --- linux-2.4.7/cmd/dmapi/configure.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/configure.in Wed Jun 13 13:06:23 2001 @@ -0,0 +1,181 @@ +dnl unpacking check - this file must exist +AC_INIT(include/dmapi.h) +pkg_name="dmapi" +AC_SUBST(pkg_name) + +# For libtool +AC_PROG_LIBTOOL +AC_SUBST(LIBTOOL_DEPS) +AC_SUBST(enable_shared) + +# +# Note: the following environment variables may be set to override the +# defaults (to change paths and/or executables, build parameters, etc): +# +# DEBUG OPTIMIZER MAKE CC LD TAR ZIP RPM AWK SED ECHO +# MALLOCLIB DISTRIBUTION PACKAGE_BUILDER PREFIX ROOT_PREFIX +# + +DEBUG=${DEBUG:-'-DDEBUG'} # -DNDEBUG +OPTIMIZER=${OPTIMIZER:-'-g'} # -O2 +MALLOCLIB=${MALLOCLIB:-''} # /usr/lib/libefence.a + +dnl Debug build? +debug_build="$DEBUG" +AC_SUBST(debug_build) + +dnl Optimization options? +opt_build="$OPTIMIZER" +AC_SUBST(opt_build) + +dnl Alternate malloc library? +malloc_lib="$MALLOCLIB" +AC_SUBST(malloc_lib) + +dnl Set version +. ./VERSION + +pkg_version=${PKG_MAJOR}.${PKG_MINOR}.${PKG_REVISION} +pkg_release=$PKG_BUILD +AC_SUBST(pkg_version) +AC_SUBST(pkg_release) + +# For libtool versioning. +pkg_lt_version=${PKG_LT_CURRENT}.${PKG_LT_REVISION}.${PKG_LT_AGE} +pkg_lt_current=$PKG_LT_CURRENT +AC_SUBST(pkg_lt_version) +AC_SUBST(pkg_lt_current) + +pkg_distribution="SGI ProPack" +test -z "$DISTRIBUTION" || pkg_distribution="$DISTRIBUTION" +AC_SUBST(pkg_distribution) + +pkg_builder=`id -u -n`@`hostname -f` +test -z "$PACKAGE_BUILDER" || pkg_builder="$PACKAGE_BUILDER" +AC_SUBST(pkg_builder) + +dnl check if user wants their own C compiler +test -z "$CC" && AC_PROG_CC +cc=$CC +AC_SUBST(cc) + +dnl check if users wants their own make +test -z "$MAKE" && AC_PATH_PROG(MAKE, make, /usr/bin/make) +make=$MAKE +AC_SUBST(make) + +dnl check if users wants their own linker +test -z "$LD" && AC_PATH_PROG(LD, ld, /usr/bin/ld) +ld=$LD +AC_SUBST(ld) + +dnl check if the tar program is available +test -z "$TAR" && AC_PATH_PROG(TAR, tar) +tar=$TAR +AC_SUBST(tar) + +dnl check if the gzip program is available +test -z "$ZIP" && AC_PATH_PROG(ZIP, gzip, /bin/gzip) +zip=$ZIP +AC_SUBST(zip) + +dnl check if the rpm program is available +test -z "$RPM" && AC_PATH_PROG(RPM, rpm, /bin/rpm) +rpm=$RPM +AC_SUBST(rpm) + +dnl .. and what version is rpm +rpm_version=0 +test -x $RPM && \ + rpm_version=`$RPM --version | awk '{print $NF}' | awk -F. '{print $1}'` +AC_SUBST(rpm_version) + +dnl check if the makedepend program is available +test -z "$MAKEDEPEND" && AC_PATH_PROG(MAKEDEPEND, makedepend, /bin/true) +makedepend=$MAKEDEPEND +AC_SUBST(makedepend) + +dnl check if symbolic links are supported +AC_PROG_LN_S + +dnl check if user wants their own awk, sed and echo +test -z "$AWK" && AC_PATH_PROG(AWK, awk, /bin/awk) +awk=$AWK +AC_SUBST(awk) +test -z "$SED" && AC_PATH_PROG(SED, sed, /bin/sed) +sed=$SED +AC_SUBST(sed) +test -z "$ECHO" && AC_PATH_PROG(ECHO, echo, /bin/echo) +echo=$ECHO +AC_SUBST(echo) + +AC_CHECK_HEADER(xfs/handle.h,, [ + echo + echo 'FATAL ERROR: could not find a valid XFS handle header.' + echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.' + exit 1 +]) + + +dnl alternate root and usr prefixes +test -z "$ROOT_PREFIX" && ROOT_PREFIX="" +root_prefix="$ROOT_PREFIX" +test -z "$PREFIX" && PREFIX="/usr" +prefix="$PREFIX" + +dnl man pages (source) +dnl also check if man page source is gzipped +dnl (usually on Debian, but not Redhat pre-7.0) +pkg_man_dir=${prefix}/share/man +have_zipped_manpages=false +for d in ${prefix}/share/man ${prefix}/man ; do + if test -f $d/man1/man.1.gz + then + pkg_man_dir=$d + have_zipped_manpages=true + break + fi +done +AC_SUBST(pkg_man_dir) +AC_SUBST(have_zipped_manpages) + +dnl binaries +pkg_bin_dir=${prefix}/bin +AC_SUBST(pkg_bin_dir) + +dnl static libraries +pkg_lib_dir=${prefix}/lib +AC_SUBST(pkg_lib_dir) + +dnl runtime shared system libraries +pkg_slib_dir=${root_prefix}/lib +AC_SUBST(pkg_slib_dir) + +dnl system binaries +pkg_sbin_dir=${root_prefix}/bin +AC_SUBST(pkg_sbin_dir) + +dnl include files +pkg_inc_dir=${prefix}/include/xfs +AC_SUBST(pkg_inc_dir) + +dnl doc directory +pkg_doc_dir=${prefix}/share/doc/${pkg_name} +AC_SUBST(pkg_doc_dir) + + +dnl +dnl output files +dnl + +#For libtool, from section 5.4.2 of the libtool manual. Just in +# case we ever need them. +LTLIBOBJS=`echo "$LIBOBJS" | sed 's/\.[^.]* /.lo /g;s/\.[^.]*$/.lo/'` +AC_SUBST(LTLIBOBJS) +LTALLOCA=`echo "$ALLOCA" | sed 's/\.[^.]* /.lo /g;s/\.[^.]*$/.lo/'` +AC_SUBST(LTALLOCA) + +AC_OUTPUT( \ +dnl Build definitions for use in Makefiles + include/builddefs \ +) diff -rNu linux-2.4.7/cmd/dmapi/debian/CVS/Entries linux-2.4-xfs/cmd/dmapi/debian/CVS/Entries --- linux-2.4.7/cmd/dmapi/debian/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/debian/CVS/Entries Thu Jul 5 11:43:47 2001 @@ -0,0 +1,6 @@ +/Makefile/1.1/Wed Jan 17 01:36:55 2001/-ko/ +/changelog/1.1/Wed Jan 17 01:36:55 2001/-ko/ +/control/1.2/Wed Feb 28 23:07:10 2001/-ko/ +/copyright/1.1/Wed Jan 17 01:36:55 2001/-ko/ +/rules/1.3/Thu Jan 25 06:56:37 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/dmapi/debian/CVS/Repository linux-2.4-xfs/cmd/dmapi/debian/CVS/Repository --- linux-2.4.7/cmd/dmapi/debian/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/debian/CVS/Repository Thu Jul 5 11:43:47 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/dmapi/debian diff -rNu linux-2.4.7/cmd/dmapi/debian/CVS/Root linux-2.4-xfs/cmd/dmapi/debian/CVS/Root --- linux-2.4.7/cmd/dmapi/debian/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/debian/CVS/Root Thu Jul 5 11:43:47 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/dmapi/debian/Makefile linux-2.4-xfs/cmd/dmapi/debian/Makefile --- linux-2.4.7/cmd/dmapi/debian/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/debian/Makefile Tue Jan 16 19:36:55 2001 @@ -0,0 +1,40 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LSRCFILES = changelog control copyright rules + +default install install-dev: + +include $(BUILDRULES) diff -rNu linux-2.4.7/cmd/dmapi/debian/changelog linux-2.4-xfs/cmd/dmapi/debian/changelog --- linux-2.4.7/cmd/dmapi/debian/changelog Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/debian/changelog Tue Jan 16 19:36:55 2001 @@ -0,0 +1,9 @@ +dmapi (0.1.0) unstable; urgency=low + + * Initial release. + + -- Nathan Scott Thu, 4 Jan 2001 11:15:11 -0500 + +Local variables: +mode: debian-changelog +End: diff -rNu linux-2.4.7/cmd/dmapi/debian/control linux-2.4-xfs/cmd/dmapi/debian/control --- linux-2.4.7/cmd/dmapi/debian/control Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/debian/control Wed Feb 28 17:07:10 2001 @@ -0,0 +1,27 @@ +Source: dmapi +Section: admin +Priority: optional +Maintainer: Nathan Scott +Build-Depends: autoconf, debmake, xfsprogs-dev +Standards-Version: 3.1.1 + +Package: dmapi +Depends: ${shlibs:Depends} +Architecture: any +Description: Data Management API runtime environment + Files required by system software using the Data Management API + (DMAPI). This is used to implement the interface defined in the + X/Open document: Systems Management: Data Storage Management + (XDSM) API dated February 1997. This interface is implemented + by the libdm library. + +Package: dmapi-dev +Section: devel +Priority: extra +Depends: libc6-dev, dmapi, xfslibs-dev +Architecture: any +Description: Data Management API static libraries and headers + dmapi-dev contains the libraries and header files needed to + develop programs which make use of the Data Management API + (DMAPI). You must install the xfslibs-dev package with + dmapi-dev. diff -rNu linux-2.4.7/cmd/dmapi/debian/copyright linux-2.4-xfs/cmd/dmapi/debian/copyright --- linux-2.4.7/cmd/dmapi/debian/copyright Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/debian/copyright Tue Jan 16 19:36:55 2001 @@ -0,0 +1,14 @@ +This package was debianized by Nathan Scott nathans@debian.org on +Sun, 19 Nov 2000 07:37:09 -0500. + +It can be downloaded from ftp://oss.sgi.com/projects/xfs/download/ + +Copyright: + +Copyright (C) 2000 Silicon Graphics, Inc. + +You are free to distribute this software under the terms of +the GNU General Public License. +On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL file. + diff -rNu linux-2.4.7/cmd/dmapi/debian/rules linux-2.4-xfs/cmd/dmapi/debian/rules --- linux-2.4.7/cmd/dmapi/debian/rules Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/debian/rules Thu Jan 25 00:56:37 2001 @@ -0,0 +1,61 @@ +#!/usr/bin/make -f + +package = dmapi +develop = $(package)-dev + +dirtmp = debian/tmp +dirdev = debian/$(develop) +doctmp = /usr/share/doc/$(package) +docdev = /usr/share/doc/$(develop) +pkgtmp = DIST_ROOT=`pwd`/$(dirtmp); export DIST_ROOT; +pkgdev = DIST_ROOT=`pwd`/$(dirdev); export DIST_ROOT; +stdenv = GZIP=-q; export GZIP; + +options = DEBUG="-DNDEBUG"; OPTIMIZER="-O1 -g"; DISTRIBUTION="debian"; \ + export DEBUG OPTIMIZER DISTRIBUTION; +checkdir = test -f debian/rules + +build: built +built: + @echo "== dpkg-buildpackage: build" 1>&2 + $(checkdir) + autoconf + $(options) ./configure + $(MAKE) default + touch built + +clean: + @echo "== dpkg-buildpackage: clean" 1>&2 + $(checkdir) + -rm -f built + $(MAKE) distclean + -rm -rf $(dirtmp) $(dirdev) debian/*substvars debian/files* + +binary-indep: + +binary-arch: checkroot built + @echo "== dpkg-buildpackage: binary-arch" 1>&2 + $(checkdir) + -rm -rf $(dirtmp) $(dirdev) + $(pkgtmp) $(MAKE) -C . install + $(pkgdev) $(MAKE) -C . install-dev + $(pkgtmp) $(MAKE) -C build src-manifest + $(pkgdev) ./install-sh -m 755 -d $(doctmp) + $(pkgdev) ./install-sh -m 755 -d $(docdev) + $(pkgdev) ./install-sh -m 644 debian/copyright $(docdev) + $(pkgdev) ./install-sh -m 644 debian/changelog $(docdev) + @echo "== dpkg-buildpackage: debstd" 1>&2 + $(stdenv) debstd -m + dpkg-gencontrol -isp -p$(package) -P$(dirtmp) + dpkg-gencontrol -isp -p$(develop) -P$(dirdev) + chown -R root.root $(dirtmp) $(dirdev) + chmod -R go=rX $(dirtmp) $(dirdev) + dpkg --build $(dirtmp) .. + dpkg --build $(dirdev) .. + +binary: binary-indep binary-arch + +checkroot: + test 0 -eq `id -u` + +.PHONY: binary binary-arch binary-indep clean checkroot diff -rNu linux-2.4.7/cmd/dmapi/doc/CHANGES linux-2.4-xfs/cmd/dmapi/doc/CHANGES --- linux-2.4.7/cmd/dmapi/doc/CHANGES Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/doc/CHANGES Mon Jan 29 23:42:55 2001 @@ -0,0 +1,8 @@ + +dmapi-0.1.1 (30 January 2001) + - minor rpm and deb packaging work + +dmapi-0.1.0 (15 January 2001) + - initial version of package + - early alpha code + diff -rNu linux-2.4.7/cmd/dmapi/doc/COPYING linux-2.4-xfs/cmd/dmapi/doc/COPYING --- linux-2.4.7/cmd/dmapi/doc/COPYING Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/doc/COPYING Tue Jan 16 19:36:55 2001 @@ -0,0 +1,860 @@ +All the libraries in "dmapi" are licensed under Version 2.1 +of the GNU Lesser General Public License. + +All other "dmapi" components are licensed under Version 2 of +the GNU General Public License. + +---------------------------------------------------------------------- + + + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + +---------------------------------------------------------------------- + + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +---------------------------------------------------------------------- diff -rNu linux-2.4.7/cmd/dmapi/doc/CVS/Entries linux-2.4-xfs/cmd/dmapi/doc/CVS/Entries --- linux-2.4.7/cmd/dmapi/doc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/doc/CVS/Entries Thu Jul 5 11:43:47 2001 @@ -0,0 +1,6 @@ +/CHANGES/1.2/Tue Jan 30 05:42:55 2001/-ko/ +/COPYING/1.1/Wed Jan 17 01:36:55 2001/-ko/ +/INSTALL/1.1/Wed Jan 17 01:36:55 2001/-ko/ +/Makefile/1.2/Thu Jan 25 06:56:37 2001/-ko/ +/PORTING/1.1/Wed Jan 17 01:36:55 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/dmapi/doc/CVS/Repository linux-2.4-xfs/cmd/dmapi/doc/CVS/Repository --- linux-2.4.7/cmd/dmapi/doc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/doc/CVS/Repository Thu Jul 5 11:43:47 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/dmapi/doc diff -rNu linux-2.4.7/cmd/dmapi/doc/CVS/Root linux-2.4-xfs/cmd/dmapi/doc/CVS/Root --- linux-2.4.7/cmd/dmapi/doc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/doc/CVS/Root Thu Jul 5 11:43:47 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/dmapi/doc/INSTALL linux-2.4-xfs/cmd/dmapi/doc/INSTALL --- linux-2.4.7/cmd/dmapi/doc/INSTALL Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/doc/INSTALL Tue Jan 16 19:36:55 2001 @@ -0,0 +1,48 @@ +This document describes how to configure and build the libdm +library from source, and how to install it. + +0. If you have the binary rpm, simply install it and skip to step 2 (below). + The rpm command to do this is: + # rpm -Uvh dmapi + + The Debian command to do this is: + # dpkg -i dmapi + or, if you have apt configured (don't need the binary package): + # apt-get install dmapi + +1. Configure, build and install the package + + The "dmapi" package uses autoconf/configure and expects a GNU build + environment (your platform must at least have both autoconf and gmake). + + If you just want to spin an RPM and/or tar file, use the Makepkgs + script in the top level directory. This will configure and build + the package and leave binary and src RPMs in the build/rpm + directory. It will also leave a tar file in the build/tar + directory. + + # ./Makepkgs verbose + + If you want to build the package and install it manually, use the + following steps: + + # make configure (or run autoconf; ./configure) + # make + # su root + # make install + + Note that there are so many "install" variants out there that we + wrote our own script (see "install-sh" in the top level directory). + + If you wish to turn off debugging asserts in the command build and + turn on the optimizer then set the shell environment variables: + + OPTIMIZER=-O + DEBUG=-DNDEBUG + + before running make configure or Makepkgs. + +2. How to Contribute + + See the README file in this directory for details about how to + contribute to the XFS project. diff -rNu linux-2.4.7/cmd/dmapi/doc/Makefile linux-2.4-xfs/cmd/dmapi/doc/Makefile --- linux-2.4.7/cmd/dmapi/doc/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/doc/Makefile Thu Jan 25 00:56:37 2001 @@ -0,0 +1,52 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LSRCFILES = INSTALL PORTING CHANGES COPYING +LDIRT = *.gz + +default: $(CMDTARGET) CHANGES.gz + +include $(BUILDRULES) + +CHANGES.gz: + $(ZIP) --best -c < CHANGES > $@ + +install: default + $(INSTALL) -m 755 -d $(PKG_DOC_DIR) +ifneq ($(PKG_DISTRIBUTION), debian) + $(INSTALL) -m 644 COPYING $(PKG_DOC_DIR) +endif + $(INSTALL) -m 644 PORTING CHANGES.gz $(PKG_DOC_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/dmapi/doc/PORTING linux-2.4-xfs/cmd/dmapi/doc/PORTING --- linux-2.4.7/cmd/dmapi/doc/PORTING Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/doc/PORTING Tue Jan 16 19:36:55 2001 @@ -0,0 +1,85 @@ + +1. unpack the source tarball and cd to the resulting dir + +2. # autoconf + this reads configure.in and generates the ./configure script + +3. # ./configure + this probes your system and then, for each "file" named + in the AC_OUTPUT() macro near the end of configure.in, + read "file".in and generate "file". Variables named @somevariable@ + will be substituted with literal values. + +4. step (3) produces several files. These files are generated by + configure from their respective .in file in the same directory. + You should have a read of these generated files and diff them + against their respective .in files to see what was substituted + by configure. + + src/include/builddefs + common definitions for the build environment. This is included + by all Makefiles, in conjunction with src/include/buildrules. + Note that most autoconf/configure build environments generate + Makefile (from Makefile.in) in every src dir. Instead, we + generate builddefs, and then include it in every Makefile. + + src/include/platform_defs.h + header containing conditional macros defining the C run-time + environment discovered by the configure script. + +5. read some or all of the GNU tool chain documentation + gmake Table Of Contents : + http://www.delorie.com/gnu/docs/make/make_toc.html + gmake Quick Reference section : + http://www.delorie.com/gnu/docs/make/make_120.html + Autoconf : + http://www.delorie.com/gnu/docs/autoconf/autoconf_toc.html + gcc/g++ : + http://www.delorie.com/gnu/docs/gcc/gcc_toc.html + +6. Makefiles and build environment + First have a look at some Makefiles + + example using SUBDIRS : dmapi/Makefile + example .so/.a library: dmapi/libdm/Makefile + + All Makefiles must define TOPDIR as the root of the project. This + allows other stuff to be found relative to $(TOPDIR). + + All Makefiles should have the following structure, which is + much like commondefs and commonrules in the IRIX build environment, e.g. + + # ---------------------------------------------------------------------- + # TOPDIR must point to the root of the project + # The builddefs file defines lots of things. Read it. + TOPDIR = .. + include $(TOPDIR)/include/builddefs + + # first rule should always be "default" + default : sometarget + commands to build targets, if necessary + + # $(BUILDRULES) is defined in builddefs and includes rules for + # descending subdirs, building targets and installation rules + include $(BUILDRULES) + + install : default + $(INSTALL) sometargets somewhere + # ---------------------------------------------------------------------- + +7. packaging + + # ./Makepkgs + this script generates all of the packages supported - each has a + subdirectory below dmapi/build where knowledge specific to each + package type is maintained. + + The script produces logs of each stage of the build (this info is + also echoed to the screen when the "verbose" option is provided): + + dmapi/Logs/configure - `autoconf; ./configure' output + dmapi/Logs/default - `make default' output + dmapi/Logs/dist - `make build dist' output + + On successful completion, the script echoes the names of packages + successfully generated. diff -rNu linux-2.4.7/cmd/dmapi/include/CVS/Entries linux-2.4-xfs/cmd/dmapi/include/CVS/Entries --- linux-2.4.7/cmd/dmapi/include/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/include/CVS/Entries Thu Jul 5 11:43:48 2001 @@ -0,0 +1,6 @@ +/Makefile/1.1/Wed Jan 17 01:36:55 2001/-ko/ +/builddefs.in/1.3/Wed Jun 13 18:06:23 2001/-ko/ +/buildrules/1.2/Wed Jun 13 18:06:23 2001/-ko/ +/dmapi.h/1.1/Wed Jan 17 01:36:55 2001/-ko/ +/dmapi_kern.h/1.1/Wed Jan 17 01:36:55 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/dmapi/include/CVS/Repository linux-2.4-xfs/cmd/dmapi/include/CVS/Repository --- linux-2.4.7/cmd/dmapi/include/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/include/CVS/Repository Thu Jul 5 11:43:47 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/dmapi/include diff -rNu linux-2.4.7/cmd/dmapi/include/CVS/Root linux-2.4-xfs/cmd/dmapi/include/CVS/Root --- linux-2.4.7/cmd/dmapi/include/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/include/CVS/Root Thu Jul 5 11:43:47 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/dmapi/include/Makefile linux-2.4-xfs/cmd/dmapi/include/Makefile --- linux-2.4.7/cmd/dmapi/include/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/include/Makefile Tue Jan 16 19:36:55 2001 @@ -0,0 +1,45 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +HFILES = dmapi.h +LSRCFILES = builddefs.in buildrules dmapi_kern.h + +default install : + +include $(BUILDRULES) + +install-dev: default + $(INSTALL) -m 755 -d $(PKG_INC_DIR) + $(INSTALL) -m 644 $(HFILES) $(PKG_INC_DIR) diff -rNu linux-2.4.7/cmd/dmapi/include/builddefs.in linux-2.4-xfs/cmd/dmapi/include/builddefs.in --- linux-2.4.7/cmd/dmapi/include/builddefs.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/include/builddefs.in Wed Jun 13 13:06:23 2001 @@ -0,0 +1,216 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# @configure_input@ +# + +ifndef _BUILDDEFS_INCLUDED_ +_BUILDDEFS_INCLUDED_ = 1 + +DEBUG = @debug_build@ +OPTIMIZER = @opt_build@ +MALLOCLIB = @malloc_lib@ + +CPPFLAGS = -I$(TOPDIR)/include +BUILDRULES = $(TOPDIR)/include/buildrules + +# General package information +PKG_NAME = @pkg_name@ +PKG_RELEASE = @pkg_release@ +PKG_VERSION = @pkg_version@ +PKG_DISTRIBUTION = @pkg_distribution@ +PKG_BUILDER = @pkg_builder@ +PKG_BIN_DIR = @pkg_bin_dir@ +PKG_LIB_DIR = @pkg_lib_dir@ +PKG_SBIN_DIR = @pkg_sbin_dir@ +PKG_SLIB_DIR = @pkg_slib_dir@ +PKG_INC_DIR = @pkg_inc_dir@ +PKG_MAN_DIR = @pkg_man_dir@ +PKG_DOC_DIR = @pkg_doc_dir@ +PKG_LT_VERSION = @pkg_lt_version@ +PKG_LT_CURRENT = @pkg_lt_current@ + +# LCFLAGS, LLDFLAGS, LLDLIBS, LSRCFILES and LDIRT may be specified in +# user Makefiles. Note: LSRCFILES is anything other than Makefile, $(CFILES) +# $(CXXFILES), or $(HFILES) and is used to construct the manifest list +# during the "dist" phase (packaging). + +CFLAGS += $(OPTIMIZER) $(DEBUG) -funsigned-char -Wall -D_GNU_SOURCE \ + $(LCFLAGS) $(CPPFLAGS) '-DVERSION="$(PKG_VERSION)"' \ + -D_FILE_OFFSET_BITS=64 + +LDFLAGS = $(LLDFLAGS) +LDLIBS = $(LLDLIBS) $(MALLOCLIB) + +MAKEOPTS = --no-print-directory +SRCFILES = Makefile $(HFILES) $(CFILES) $(LSRCFILES) $(LFILES) $(YFILES) +DIRT = $(LDIRT) dep dep.bak $(OBJECTS) $(CMDTARGET) $(LIBTARGET) \ + $(STATICLIBTARGET) *.[1-9].gz + +OBJECTS = $(ASFILES:.s=.o) \ + $(CFILES:.c=.o) \ + $(LFILES:.l=.o) \ + $(YFILES:%.y=%.tab.o) + +MAKE = @make@ +CC = @cc@ +LD = @ld@ +AWK = @awk@ +SED = @sed@ +INSTALL = $(TOPDIR)/install-sh -o root -g root +ECHO = @echo@ +LN_S = @LN_S@ + +CCF = $(CC) $(CFLAGS) +MAKEF = $(MAKE) $(MAKEOPTS) +CXXF = $(CXX) $(CXXFLAGS) +LDF = $(LD) $(LDFLAGS) +MAKEDEPEND = @makedepend@ + +ZIP = @zip@ +TAR = @tar@ +RPM = @rpm@ +RPM_VERSION = @rpm_version@ + +HAVE_ZIPPED_MANPAGES = @have_zipped_manpages@ + +SHELL = /bin/sh +IMAGES_DIR = $(TOPDIR)/all-images +DIST_DIR = $(TOPDIR)/dist + +# For libtool. Pieces from Automake, slightly modified. +top_builddir = $(TOPDIR) +LIBTOOL = @LIBTOOL@ +LINK = $(LIBTOOL) --mode=link $(CC) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CCF) +LIBTOOL_DEPS = @LIBTOOL_DEPS@ +LTOBJECTS = $(OBJECTS:.o=.lo) +DIRT += $(LTOBJECTS) $(LTLIBRARY) .libs/* +ENABLE_SHARED = @enable_shared@ +ifeq ($(ENABLE_SHARED),yes) +LDFLAGS += -rpath $(PKG_LIB_DIR) +LDFLAGS += -version-info $(subst .,:,$(PKG_LT_VERSION)) +endif +LIBNAME = $(basename $(LTLIBRARY)) + +# Remove things from the manifest that do not belong in the normal install. +# This is cleanup after libtool --mode=install. +LT_INSTALL_FILTER = \ + if test "$(DIST_MANIFEST)" != ""; then \ + perl -i -ne 'print unless /$(LIBNAME).(so|a|la)$$/' $(DIST_MANIFEST); \ + fi + + +# Remove things from the manifest that do not belong in the devel install. +# This is cleanup after libtool --mode=install. +LT_DEV_INSTALL_FILTER = \ + if test "$(DIST_MANIFEST)" != ""; then \ + perl -i -ane 'print unless $$F[-1] =~ /$(LIBNAME).so./' $(DIST_MANIFEST); \ + fi + + +# Update manifest with the symlinks that libtool made for us. +LT_INSTALL_SYMLINKS = \ + if test "$(DIST_MANIFEST)" != "" && \ + test -f $(DIST_ROOT)$(PKG_LIB_DIR)/$(LIBNAME).so.$(PKG_LT_VERSION); then \ + $(INSTALL) -S $(LIBNAME).so.$(PKG_LT_VERSION) $(PKG_LIB_DIR)/$(LIBNAME).so.$(PKG_LT_CURRENT); \ + $(INSTALL) -S $(LIBNAME).so.$(PKG_LT_VERSION) $(PKG_LIB_DIR)/$(LIBNAME).so; \ + fi + + +# Tell libtool to install the library. +LT_INSTALL = \ + @list='$(LTLIBRARY)'; for p in $$list; do \ + if test -f $$p; then \ + echo $(LIBTOOL) --mode=install $(INSTALL) $$p $(DIST_ROOT)$(PKG_LIB_DIR)/$$p; \ + $(LIBTOOL) --mode=install $(INSTALL) $$p $(DIST_ROOT)$(PKG_LIB_DIR)/$$p; \ + fi; \ + done + +SUBDIRS_MAKERULE = \ + @for d in $(SUBDIRS) ""; do \ + if test -d "$$d" -a ! -z "$$d"; then \ + $(ECHO) === $$d ===; \ + $(MAKEF) -C $$d $@ || exit $$?; \ + fi; \ + done + +MAN_MAKERULE = \ + @for f in *.[12345678] ""; do \ + if test ! -z "$$f"; then \ + $(ZIP) --best -c < $$f > $$f.gz; \ + fi; \ + done + +INSTALL_MAN = \ + @for d in $(MAN_PAGES); do \ + first=true; \ + for m in `$(AWK) '/^\.SH NAME/ {ok=1; next} ok {print; exit}' $$d \ + | sed -e 's/,/ /g' -e 's/\\-.*//' -e 's/\\\f[0-9]//g' -e 's/ / /g;q'`; \ + do \ + [ -z "$$m" -o "$$m" = "\\" ] && continue; \ + t=$(MAN_DEST)/$$m.$(MAN_SECTION); \ + if $$first; then \ + if $(HAVE_ZIPPED_MANPAGES); then \ + $(ZIP) --best -c $$d > $$d.gz; _sfx=.gz; \ + fi; \ + u=$$m.$(MAN_SECTION)$$_sfx; \ + echo $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ + $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ + else \ + echo $(INSTALL) -S $$u $${t}$$_sfx; \ + $(INSTALL) -S $$u $${t}$$_sfx; \ + fi; \ + first=false; \ + done; \ + done + +DIST_MAKERULE = \ + $(MAKEF) -C build dist + +SOURCE_MAKERULE = \ + @test -z "$$DIR" && DIR="."; \ + for f in $(SRCFILES) ""; do \ + if test ! -z "$$f"; then $(ECHO) $$DIR/$$f; fi;\ + done; \ + for d in `echo $(SUBDIRS)` ; do \ + if test -d "$$d" -a ! -z "$$d"; then \ + $(MAKEF) DIR=$$DIR/$$d -C $$d $@ || exit $$?; \ + fi; \ + done + +endif + +# +# For targets that should always be rebuilt, +# define a target that is never up-to-date. +# Targets needing this should depend on $(_FORCE) +_FORCE = __force_build diff -rNu linux-2.4.7/cmd/dmapi/include/buildrules linux-2.4-xfs/cmd/dmapi/include/buildrules --- linux-2.4.7/cmd/dmapi/include/buildrules Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/include/buildrules Wed Jun 13 13:06:23 2001 @@ -0,0 +1,88 @@ +# +# Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Fondation. +# +# This program is distributed in the hope that it would be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. Further, any license provided herein, +# whether implied or otherwise, is limited to this program in accordance with +# the express provisions of the GNU General Public License. Patent licenses, +# if any, provided herein do not apply to combinations of this program with +# other product or programs, or any other product whatsoever. This program is +# distributed without any warranty that the program is delivered free of the +# rightful claim of any third person by way of infringement or the like. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write the Free Software Foundation, Inc., 59 Temple +# Place - Suite 330, Boston MA 02111-1307, USA. +# Common build rules for gmake +# +ifndef _BUILDRULES_INCLUDED_ +_BUILDRULES_INCLUDED_ = 1 + +include $(TOPDIR)/include/builddefs + +# +# Standard targets +# +ifdef CMDTARGET +$(CMDTARGET) : $(SUBDIRS) $(OBJECTS) + $(CCF) -o $(CMDTARGET) $(LDFLAGS) $(OBJECTS) $(LDLIBS) +$(CMDTARGET).static : $(SUBDIRS) $(OBJECTS) + $(CCF) -static -o $(CMDTARGET).static $(LDFLAGS) $(OBJECTS) $(LDLIBS) +endif + +ifdef LIBTARGET +$(LIBTARGET) : $(SUBDIRS) $(OBJECTS) + $(CC) $(LDFLAGS) -fPIC -shared -Wl,-soname,$(LIBTARGET) -o $(LIBTARGET) $(OBJECTS) $(LDLIBS) +endif + +ifdef STATICLIBTARGET +$(STATICLIBTARGET) : $(SUBDIRS) $(OBJECTS) + $(AR) crf $(STATICLIBTARGET) $? +endif + +# For libtool. Pieces from Automake, slightly modified. +ifdef LTLIBRARY + +$(LTLIBRARY) : $(SUBDIRS) $(LTOBJECTS) + $(LINK) $(LDFLAGS) -o $(LTLIBRARY) $(LTOBJECTS) $(LDLIBS) + +%.lo: %.c + $(LTCOMPILE) -c $< + +endif # LTLIBRARY + +clean clobber : $(SUBDIRS) + rm -f $(DIRT) + $(SUBDIRS_MAKERULE) + +# Never blow away subdirs +ifdef SUBDIRS +.PRECIOUS: $(SUBDIRS) +$(SUBDIRS): + $(SUBDIRS_MAKERULE) +endif + +source : + $(SOURCE_MAKERULE) + +endif + +$(_FORCE): + +.PHONY : depend + +depend : $(CFILES) $(HFILES) + $(SUBDIRS_MAKERULE) + touch dep + $(MAKEDEPEND) -fdep -- $(CFLAGS) -- $(CFILES) + +# Include dep, but only if it exists +ifeq ($(shell test -f dep && echo dep), dep) +include dep +endif diff -rNu linux-2.4.7/cmd/dmapi/include/dmapi.h linux-2.4-xfs/cmd/dmapi/include/dmapi.h --- linux-2.4.7/cmd/dmapi/include/dmapi.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/include/dmapi.h Tue Jan 16 19:36:55 2001 @@ -0,0 +1,1033 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef _SYS_DMAPI_H +#define _SYS_DMAPI_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/************************************************************************** + * * + * The SGI implementation of DMAPI is based upon the X/Open document * + * Systems Management: Data Storage Managment (XDSM) API * + * dated February 1997. Not all DMAPI functions and structure fields * + * have been implemented. Most importantly, the DMAPI functions * + * dm_request_right, dm_release_right, dm_query_right, dm_upgrade_right * + * and dm_downgrade_right do not work as described in the specification. * + * * + * The XFS filesystem currently does not allow its locking mechanisms to * + * be externally accessed from user space. While the above-mentioned * + * dm_xxx_right functions exist and can be called by applications, they * + * always return successfully without actually obtaining any locks * + * within the filesystem. * + * * + * Applications which do not need full rights support and which only * + * make dm_xxx_right calls in order to satisfy the input requirements of * + * other DMAPI calls should be able to use these routines to avoid * + * having to implement special-case code for SGI platforms. Applications * + * which truely need the capabilities of a full implementation of rights * + * will unfortunately have to come up with alternate software solutions * + * until such time as rights can be completely implemented. * + * * + * Functions and structure fields defined within this file which are not * + * supported in the SGI implementation of DMAPI are indicated by comments * + * following their definitions such as "not supported", or "not * + * completely supported". Any function or field not so marked may be * + * assumed to work exactly according to the spec. * + * * + **************************************************************************/ + + + +/* The first portion of this file contains defines and typedefs that are + DMAPI implementation-dependent, and could be different on other platforms. +*/ + +typedef __s64 dm_attrloc_t; +typedef unsigned int dm_boolean_t; +typedef __u64 dm_eventset_t; +typedef __u64 dm_fsid_t; +typedef __u64 dm_ino_t; +typedef __u32 dm_igen_t; +typedef __s64 dm_off_t; +typedef unsigned int dm_sequence_t; +typedef int dm_sessid_t; +typedef __u64 dm_size_t; +typedef __s64 dm_ssize_t; +typedef int dm_token_t; + +/* XXX dev_t, mode_t, and nlink_t are not the same size in kernel space + and user space. This affects the field offsets for dm_stat_t. + The following solution is temporary. + + user space sizes: dev_t=8 mode_t=4 nlink_t=4 + kernel space : dev_t=2 mode_t=2 nlink_t=2 + +*/ +typedef __s64 dm_dev_t; +typedef int dm_mode_t; +typedef int dm_nlink_t; + + +#define DM_REGION_NOEVENT 0x0 +#define DM_REGION_READ 0x1 +#define DM_REGION_WRITE 0x2 +#define DM_REGION_TRUNCATE 0x4 + +/* Values for the mask argument used with dm_get_fileattr, dm_get_bulkattr, + dm_get_dirattrs, and dm_set_fileattr. +*/ + +#define DM_AT_MODE 0x0001 +#define DM_AT_UID 0x0002 +#define DM_AT_GID 0x0004 +#define DM_AT_ATIME 0x0008 +#define DM_AT_MTIME 0x0010 +#define DM_AT_CTIME 0x0020 +#define DM_AT_SIZE 0x0040 +#define DM_AT_DTIME 0x0080 +#define DM_AT_HANDLE 0x0100 +#define DM_AT_EMASK 0x0200 +#define DM_AT_PMANR 0x0400 +#define DM_AT_PATTR 0x0800 +#define DM_AT_STAT 0x1000 +#define DM_AT_CFLAG 0x2000 + +#define DM_EV_WAIT 0x1 /* used in dm_get_events() */ + +#define DM_MOUNT_RDONLY 0x1 /* me_mode field in dm_mount_event_t */ + +#define DM_RR_WAIT 0x1 + +#define DM_UNMOUNT_FORCE 0x1 /* ne_mode field in dm_namesp_event_t */ + +#define DM_WRITE_SYNC 0x1 /* used in dm_write_invis() */ + +#define DM_SESSION_INFO_LEN 256 +#define DM_NO_SESSION 0 +#define DM_TRUE 1 +#define DM_FALSE 0 +#define DM_INVALID_TOKEN 0 +#define DM_NO_TOKEN (-1) +#define DM_INVALID_HANP NULL +#define DM_INVALID_HLEN 0 +#define DM_GLOBAL_HANP ((void *)(1LL)) +#define DM_GLOBAL_HLEN ((size_t)(1)) +#define DM_VER_STR_CONTENTS "SGI DMAPI (XDSM) API, Release 1.0." + + +#define DMEV_SET(event_type, event_list) \ + ((event_list) |= (1 << (event_type))) +#define DMEV_CLR(event_type, event_list) \ + ((event_list) &= ~(1 << (event_type))) +#define DMEV_ISSET(event_type, event_list) \ + (int)(((event_list) & (1 << (event_type))) != 0) +#define DMEV_ZERO(event_list) \ + (event_list) = 0 + + +typedef struct { + int vd_offset; /* offset from start of containing struct */ + unsigned int vd_length; /* length of data starting at vd_offset */ +} dm_vardata_t; + +#define DM_GET_VALUE(p, field, type) \ + ((type) ((char *)(p) + (p)->field.vd_offset)) + +#define DM_GET_LEN(p, field) \ + ((p)->field.vd_length) + +#define DM_STEP_TO_NEXT(p, type) \ + ((type) ((p)->_link ? (char *)(p) + (p)->_link : NULL)) + + + + +/* The remainder of this include file contains defines, typedefs, and + structures which are strictly defined by the DMAPI 2.3 specification. + + (The _link field which appears in several structures is an + implementation-specific way to implement DM_STEP_TO_NEXT, and + should not be referenced directly by application code.) +*/ + + +#define DM_ATTR_NAME_SIZE 8 + + +struct dm_attrname { + unsigned char an_chars[DM_ATTR_NAME_SIZE]; +}; +typedef struct dm_attrname dm_attrname_t; + + +struct dm_attrlist { + int _link; + dm_attrname_t al_name; + dm_vardata_t al_data; +}; +typedef struct dm_attrlist dm_attrlist_t; + + +typedef enum { + DM_CONFIG_INVALID, + DM_CONFIG_BULKALL, + DM_CONFIG_CREATE_BY_HANDLE, + DM_CONFIG_DTIME_OVERLOAD, + DM_CONFIG_LEGACY, + DM_CONFIG_LOCK_UPGRADE, + DM_CONFIG_MAX_ATTR_ON_DESTROY, + DM_CONFIG_MAX_ATTRIBUTE_SIZE, + DM_CONFIG_MAX_HANDLE_SIZE, + DM_CONFIG_MAX_MANAGED_REGIONS, + DM_CONFIG_MAX_MESSAGE_DATA, + DM_CONFIG_OBJ_REF, + DM_CONFIG_PENDING, + DM_CONFIG_PERS_ATTRIBUTES, + DM_CONFIG_PERS_EVENTS, + DM_CONFIG_PERS_INHERIT_ATTRIBS, + DM_CONFIG_PERS_MANAGED_REGIONS, + DM_CONFIG_PUNCH_HOLE, + DM_CONFIG_TOTAL_ATTRIBUTE_SPACE, + DM_CONFIG_WILL_RETRY +} dm_config_t; + + +struct dm_dioinfo { /* non-standard SGI addition */ + unsigned int d_mem; + unsigned int d_miniosz; + unsigned int d_maxiosz; + dm_boolean_t d_dio_only; +}; +typedef struct dm_dioinfo dm_dioinfo_t; + + +struct dm_dispinfo { + int _link; + unsigned int di_pad1; /* reserved; do not reference */ + dm_vardata_t di_fshandle; + dm_eventset_t di_eventset; +}; +typedef struct dm_dispinfo dm_dispinfo_t; + + +typedef enum { + DM_EVENT_INVALID = -1, + DM_EVENT_CANCEL = 0, /* not supported */ + DM_EVENT_MOUNT = 1, + DM_EVENT_PREUNMOUNT = 2, + DM_EVENT_UNMOUNT = 3, + DM_EVENT_DEBUT = 4, /* not supported */ + DM_EVENT_CREATE = 5, + DM_EVENT_CLOSE = 6, /* not supported */ + DM_EVENT_POSTCREATE = 7, + DM_EVENT_REMOVE = 8, + DM_EVENT_POSTREMOVE = 9, + DM_EVENT_RENAME = 10, + DM_EVENT_POSTRENAME = 11, + DM_EVENT_LINK = 12, + DM_EVENT_POSTLINK = 13, + DM_EVENT_SYMLINK = 14, + DM_EVENT_POSTSYMLINK = 15, + DM_EVENT_READ = 16, + DM_EVENT_WRITE = 17, + DM_EVENT_TRUNCATE = 18, + DM_EVENT_ATTRIBUTE = 19, + DM_EVENT_DESTROY = 20, + DM_EVENT_NOSPACE = 21, + DM_EVENT_USER = 22, + DM_EVENT_MAX = 23 +} dm_eventtype_t; + + +struct dm_eventmsg { + int _link; + dm_eventtype_t ev_type; + dm_token_t ev_token; + dm_sequence_t ev_sequence; + dm_vardata_t ev_data; +}; +typedef struct dm_eventmsg dm_eventmsg_t; + + +struct dm_cancel_event { /* not supported */ + dm_sequence_t ce_sequence; + dm_token_t ce_token; +}; +typedef struct dm_cancel_event dm_cancel_event_t; + + +struct dm_data_event { + dm_vardata_t de_handle; + dm_off_t de_offset; + dm_size_t de_length; +}; +typedef struct dm_data_event dm_data_event_t; + +struct dm_destroy_event { + dm_vardata_t ds_handle; + dm_attrname_t ds_attrname; + dm_vardata_t ds_attrcopy; +}; +typedef struct dm_destroy_event dm_destroy_event_t; + +struct dm_mount_event { + mode_t me_mode; + dm_vardata_t me_handle1; + dm_vardata_t me_handle2; + dm_vardata_t me_name1; + dm_vardata_t me_name2; + dm_vardata_t me_roothandle; +}; +typedef struct dm_mount_event dm_mount_event_t; + +struct dm_namesp_event { + mode_t ne_mode; + dm_vardata_t ne_handle1; + dm_vardata_t ne_handle2; + dm_vardata_t ne_name1; + dm_vardata_t ne_name2; + int ne_retcode; +}; +typedef struct dm_namesp_event dm_namesp_event_t; + + +typedef enum { + DM_EXTENT_INVALID, + DM_EXTENT_RES, + DM_EXTENT_HOLE +} dm_extenttype_t; + + +struct dm_extent { + dm_extenttype_t ex_type; + unsigned int ex_pad1; /* reserved; do not reference */ + dm_off_t ex_offset; + dm_size_t ex_length; +}; +typedef struct dm_extent dm_extent_t; + +struct dm_fileattr { + mode_t fa_mode; + uid_t fa_uid; + gid_t fa_gid; + time_t fa_atime; + time_t fa_mtime; + time_t fa_ctime; + time_t fa_dtime; + unsigned int fa_pad1; /* reserved; do not reference */ + dm_off_t fa_size; +}; +typedef struct dm_fileattr dm_fileattr_t; + + +struct dm_inherit { /* not supported */ + dm_attrname_t ih_name; + mode_t ih_filetype; +}; +typedef struct dm_inherit dm_inherit_t; + + +typedef enum { + DM_MSGTYPE_INVALID, + DM_MSGTYPE_SYNC, + DM_MSGTYPE_ASYNC +} dm_msgtype_t; + + +struct dm_region { + dm_off_t rg_offset; + dm_size_t rg_size; + unsigned int rg_flags; + unsigned int rg_pad1; /* reserved; do not reference */ +}; +typedef struct dm_region dm_region_t; + + +typedef enum { + DM_RESP_INVALID, + DM_RESP_CONTINUE, + DM_RESP_ABORT, + DM_RESP_DONTCARE +} dm_response_t; + + +typedef enum { + DM_RIGHT_NULL, + DM_RIGHT_SHARED, + DM_RIGHT_EXCL +} dm_right_t; + + +struct dm_stat { + int _link; + dm_vardata_t dt_handle; + dm_vardata_t dt_compname; + int dt_nevents; + dm_eventset_t dt_emask; + int dt_pers; /* field not supported */ + int dt_pmanreg; + time_t dt_dtime; + unsigned int dt_change; /* field not supported */ + unsigned int dt_pad1; /* reserved; do not reference */ + dm_dev_t dt_dev; + dm_ino_t dt_ino; + dm_mode_t dt_mode; + dm_nlink_t dt_nlink; + uid_t dt_uid; + gid_t dt_gid; + dm_dev_t dt_rdev; + unsigned int dt_pad2; /* reserved; do not reference */ + dm_off_t dt_size; + time_t dt_atime; + time_t dt_mtime; + time_t dt_ctime; + unsigned int dt_blksize; + dm_size_t dt_blocks; + + /* Non-standard filesystem-specific fields. Currently XFS is the only + supported filesystem type. + */ + + __u64 dt_pad3; /* reserved; do not reference */ + int dt_fstype; /* filesystem index; see sysfs(2) */ + union { + struct { + dm_igen_t igen; + unsigned int xflags; + unsigned int extsize; + unsigned int extents; + unsigned short aextents; + unsigned short dmstate; + } sgi_xfs; + } fsys_dep; +}; +typedef struct dm_stat dm_stat_t; + +#define dt_xfs_igen fsys_dep.sgi_xfs.igen +#define dt_xfs_xflags fsys_dep.sgi_xfs.xflags +#define dt_xfs_extsize fsys_dep.sgi_xfs.extsize +#define dt_xfs_extents fsys_dep.sgi_xfs.extents +#define dt_xfs_aextents fsys_dep.sgi_xfs.aextents +#define dt_xfs_dmstate fsys_dep.sgi_xfs.dmstate + +/* Flags for the non-standard dt_xfs_xflags field. */ + +#define DM_XFLAG_REALTIME 0x1 +#define DM_XFLAG_PREALLOC 0x2 +#define DM_XFLAG_HASATTR 0x80000000 + + +struct dm_timestruct { + time_t dm_tv_sec; + int dm_tv_nsec; +}; +typedef struct dm_timestruct dm_timestruct_t; + + +struct dm_xstat { /* not supported */ + dm_stat_t dx_statinfo; + dm_vardata_t dx_attrdata; +}; +typedef struct dm_xstat dm_xstat_t; + + + +/* The following list provides the prototypes for all functions defined in + the DMAPI interface. +*/ + +extern int +dm_clear_inherit( /* not supported */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep); + +extern int +dm_create_by_handle( /* not supported */ + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname); + +extern int +dm_create_session( + dm_sessid_t oldsid, + char *sessinfop, + dm_sessid_t *newsidp); + +extern int +dm_create_userevent( + dm_sessid_t sid, + size_t msglen, + void *msgdatap, + dm_token_t *tokenp); + +extern int +dm_destroy_session( + dm_sessid_t sid); + +extern int +dm_downgrade_right( /* not completely supported; see caveat above */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern int +dm_fd_to_handle( + int fd, + void **hanpp, + size_t *hlenp); + +extern int +dm_find_eventmsg( + dm_sessid_t sid, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_allocinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t *offp, + unsigned int nelem, + dm_extent_t *extentp, + unsigned int *nelemp); + +extern int +dm_get_bulkall( /* not supported */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int mask, + dm_attrname_t *attrnamep, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_bulkattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_config( + void *hanp, + size_t hlen, + dm_config_t flagname, + dm_size_t *retvalp); + +extern int +dm_get_config_events( + void *hanp, + size_t hlen, + unsigned int nelem, + dm_eventset_t *eventsetp, + unsigned int *nelemp); + +extern int +dm_get_dirattrs( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int nelem, + dm_eventset_t *eventsetp, + unsigned int *nelemp); + +extern int +dm_get_events( + dm_sessid_t sid, + unsigned int maxmsgs, + unsigned int flags, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_fileattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int mask, + dm_stat_t *statp); + +extern int +dm_get_mountinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_region( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int nelem, + dm_region_t *regbufp, + unsigned int *nelemp); + +extern int +dm_getall_disp( + dm_sessid_t sid, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_getall_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_getall_inherit( /* not supported */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int nelem, + dm_inherit_t *inheritbufp, + unsigned int *nelemp); + +extern int +dm_getall_sessions( + unsigned int nelem, + dm_sessid_t *sidbufp, + unsigned int *nelemp); + +extern int +dm_getall_tokens( + dm_sessid_t sid, + unsigned int nelem, + dm_token_t *tokenbufp, + unsigned int *nelemp); + +extern int +dm_handle_cmp( + void *hanp1, + size_t hlen1, + void *hanp2, + size_t hlen2); + +extern void +dm_handle_free( + void *hanp, + size_t hlen); + +extern u_int +dm_handle_hash( + void *hanp, + size_t hlen); + +extern dm_boolean_t +dm_handle_is_valid( + void *hanp, + size_t hlen); + +extern int +dm_handle_to_fshandle( + void *hanp, + size_t hlen, + void **fshanpp, + size_t *fshlenp); + +extern int +dm_handle_to_fsid( + void *hanp, + size_t hlen, + dm_fsid_t *fsidp); + +extern int +dm_handle_to_igen( + void *hanp, + size_t hlen, + dm_igen_t *igenp); + +extern int +dm_handle_to_ino( + void *hanp, + size_t hlen, + dm_ino_t *inop); + +extern int +dm_handle_to_path( + void *dirhanp, + size_t dirhlen, + void *targhanp, + size_t targhlen, + size_t buflen, + char *pathbufp, + size_t *rlenp); + +extern int +dm_init_attrloc( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrloc_t *locp); + +extern int +dm_init_service( + char **versionstrpp); + +extern int +dm_make_handle( + dm_fsid_t *fsidp, + dm_ino_t *inop, + dm_igen_t *igenp, + void **hanpp, + size_t *hlenp); + +extern int +dm_make_fshandle( + dm_fsid_t *fsidp, + void **hanpp, + size_t *hlenp); + +extern int +dm_mkdir_by_handle( /* not supported */ + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname); + +extern int +dm_move_event( + dm_sessid_t srcsid, + dm_token_t token, + dm_sessid_t targetsid, + dm_token_t *rtokenp); + +extern int +dm_obj_ref_hold( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +extern int +dm_obj_ref_query( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +extern int +dm_obj_ref_rele( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +extern int +dm_path_to_fshandle( + char *path, + void **hanpp, + size_t *hlenp); + +extern int +dm_path_to_handle( + char *path, + void **hanpp, + size_t *hlenp); + +extern int +dm_pending( + dm_sessid_t sid, + dm_token_t token, + dm_timestruct_t *delay); + +extern int +dm_probe_hole( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + dm_off_t *roffp, + dm_size_t *rlenp); + +extern int +dm_punch_hole( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len); + +extern int +dm_query_right( /* not completely supported; see caveat above */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_right_t *rightp); + +extern int +dm_query_session( + dm_sessid_t sid, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern dm_ssize_t +dm_read_invis( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + void *bufp); + +extern int +dm_release_right( /* not completely supported; see caveat above */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern int +dm_remove_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int setdtime, + dm_attrname_t *attrnamep); + +extern int +dm_request_right( /* not completely supported; see caveat above */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int flags, + dm_right_t right); + +extern int +dm_respond_event( + dm_sessid_t sid, + dm_token_t token, + dm_response_t response, + int reterror, + size_t buflen, + void *respbufp); + +extern int +dm_send_msg( + dm_sessid_t targetsid, + dm_msgtype_t msgtype, + size_t buflen, + void *bufp); + +extern int +dm_set_disp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + unsigned int maxevent); + +extern int +dm_set_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + int setdtime, + size_t buflen, + void *bufp); + +extern int +dm_set_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + unsigned int maxevent); + +extern int +dm_set_fileattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int mask, + dm_fileattr_t *attrp); + +extern int +dm_set_inherit( /* not supported */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + mode_t mode); + +extern int +dm_set_region( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int nelem, + dm_region_t *regbufp, + dm_boolean_t *exactflagp); + +extern int +dm_set_return_on_destroy( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + dm_boolean_t enable); + +extern int +dm_symlink_by_handle( /* not supported */ + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname, + char *path); + +extern int +dm_sync_by_handle( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern int +dm_upgrade_right( /* not completely supported; see caveat above */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern dm_ssize_t +dm_write_invis( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int flags, + dm_off_t off, + dm_size_t len, + void *bufp); + +/* Non-standard SGI additions to the DMAPI interface. */ + +extern int +dm_get_dioinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_dioinfo_t *diop); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_DMAPI_H */ + diff -rNu linux-2.4.7/cmd/dmapi/include/dmapi_kern.h linux-2.4-xfs/cmd/dmapi/include/dmapi_kern.h --- linux-2.4.7/cmd/dmapi/include/dmapi_kern.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/include/dmapi_kern.h Tue Jan 16 19:36:55 2001 @@ -0,0 +1,575 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef __DMAPI_KERN_H__ +#define __DMAPI_KERN_H__ + + +struct sys_dmapi_args { + long arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11; +}; +typedef struct sys_dmapi_args sys_dmapi_args_t; + + +#ifdef __KERNEL__ + +struct xfs_handle_t; + +/* The first group of definitions and prototypes define the filesystem's + interface into the DMAPI code. +*/ + + +/* Definitions used for the flags field on dm_send_data_event(), + dm_send_unmount_event(), and dm_send_namesp_event() calls. +*/ + +#define DM_FLAGS_NDELAY 0x001 /* return EAGAIN after dm_pending() */ +#define DM_FLAGS_UNWANTED 0x002 /* event not in fsys dm_eventset_t */ + +/* Possible code levels reported by dm_code_level(). */ + +#define DM_CLVL_INIT 0 /* DMAPI prior to X/Open compliance */ +#define DM_CLVL_XOPEN 1 /* X/Open compliant DMAPI */ + + +/* Prototypes used outside of the DMI module/directory. */ + +int dm_send_data_event( + dm_eventtype_t event, + struct bhv_desc *bdp, + dm_right_t vp_right, + off_t off, + size_t len, + int flags); + +int dm_send_destroy_event( + struct bhv_desc *bdp, + dm_right_t vp_right); + +int dm_send_mount_event( + struct vfs *vfsp, + dm_right_t vfsp_right, + struct bhv_desc *bdp, + dm_right_t vp_right, + struct bhv_desc *rootbdp, + dm_right_t rootvp_right, + char *name1, + char *name2); + +int dm_send_namesp_event( + dm_eventtype_t event, + struct bhv_desc *bdp1, + dm_right_t vp1_right, + struct bhv_desc *bdp2, + dm_right_t vp2_right, + char *name1, + char *name2, + mode_t mode, + int retcode, + int flags); + +void dm_send_unmount_event( + struct vfs *vfsp, + struct vnode *vp, + dm_right_t vfsp_right, + mode_t mode, + int retcode, + int flags); + +int dm_code_level(void); + +int dm_vp_to_handle ( + struct vnode *vp, + xfs_handle_t *handlep); + +/* The following prototypes and definitions are used by DMAPI as its + interface into the filesystem code. Communication between DMAPI and the + filesystem are established as follows: + 1. DMAPI uses the F_DMAPI command in VOP_FCNTL() to ask for the addresses + of all the functions within the filesystem that it may need to call. + 2. The filesystem returns an array of function name/address pairs which + DMAPI builds into a function vector. + The VOP_FCNTL() call is only made one time for a particular filesystem + type. From then on, DMAPI uses its function vector to call the filesystem + functions directly. Functions in the array which DMAPI doesn't recognize + are ignored. A dummy function which returns ENOSYS is used for any function + that DMAPI needs but which was not provided by the filesystem. If XFS + doesn't recognize the F_DMAPI fcntl, DMAPI assumes that it doesn't have the + X/Open support code; in this case DMAPI uses the XFS-code originally bundled + within DMAPI. + + The goal of this interface is allow incremental changes to be made to + both the filesystem and to DMAPI while minimizing inter-patch dependencies, + and to eventually allow DMAPI to support multiple filesystem types at the + same time should that become necessary. +*/ + +typedef enum { + DM_FSYS_CLEAR_INHERIT = 0, + DM_FSYS_CREATE_BY_HANDLE = 1, + DM_FSYS_DOWNGRADE_RIGHT = 2, + DM_FSYS_GET_ALLOCINFO_RVP = 3, + DM_FSYS_GET_BULKALL_RVP = 4, + DM_FSYS_GET_BULKATTR_RVP = 5, + DM_FSYS_GET_CONFIG = 6, + DM_FSYS_GET_CONFIG_EVENTS = 7, + DM_FSYS_GET_DESTROY_DMATTR = 8, + DM_FSYS_GET_DIOINFO = 9, + DM_FSYS_GET_DIRATTRS_RVP = 10, + DM_FSYS_GET_DMATTR = 11, + DM_FSYS_GET_EVENTLIST = 12, + DM_FSYS_GET_FILEATTR = 13, + DM_FSYS_GET_REGION = 14, + DM_FSYS_GETALL_DMATTR = 15, + DM_FSYS_GETALL_INHERIT = 16, + DM_FSYS_INIT_ATTRLOC = 17, + DM_FSYS_MKDIR_BY_HANDLE = 18, + DM_FSYS_PROBE_HOLE = 19, + DM_FSYS_PUNCH_HOLE = 20, + DM_FSYS_READ_INVIS_RVP = 21, + DM_FSYS_RELEASE_RIGHT = 22, + DM_FSYS_REMOVE_DMATTR = 23, + DM_FSYS_REQUEST_RIGHT = 24, + DM_FSYS_SET_DMATTR = 25, + DM_FSYS_SET_EVENTLIST = 26, + DM_FSYS_SET_FILEATTR = 27, + DM_FSYS_SET_INHERIT = 28, + DM_FSYS_SET_REGION = 29, + DM_FSYS_SYMLINK_BY_HANDLE = 30, + DM_FSYS_SYNC_BY_HANDLE = 31, + DM_FSYS_UPGRADE_RIGHT = 32, + DM_FSYS_WRITE_INVIS_RVP = 33, + DM_FSYS_MAX = 34 +} dm_fsys_switch_t; + + +#define DM_FSYS_OBJ 0x1 /* object refers to a fsys handle */ + + +/* + * Prototypes for filesystem-specific functions. + */ + +typedef int (*dm_fsys_clear_inherit_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrname_t *attrnamep); + +typedef int (*dm_fsys_create_by_handle_t)( + bhv_desc_t *bdp, + dm_right_t right, + void *hanp, + size_t hlen, + char *cname); + +typedef int (*dm_fsys_downgrade_right_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int type); /* DM_FSYS_OBJ or zero */ + +typedef int (*dm_fsys_get_allocinfo_rvp_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_off_t *offp, + u_int nelem, + dm_extent_t *extentp, + u_int *nelemp, + int *rvalp); + +typedef int (*dm_fsys_get_bulkall_rvp_t)( + bhv_desc_t *bdp, /* root vnode */ + dm_right_t right, + u_int mask, + dm_attrname_t *attrnamep, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvalp); + +typedef int (*dm_fsys_get_bulkattr_rvp_t)( + bhv_desc_t *bdp, /* root vnode */ + dm_right_t right, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvalp); + +typedef int (*dm_fsys_get_config_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_config_t flagname, + dm_size_t *retvalp); + +typedef int (*dm_fsys_get_config_events_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp); + +typedef int (*dm_fsys_get_destroy_dmattr_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrname_t *attrnamep, + char **valuepp, + int *vlenp); + +typedef int (*dm_fsys_get_dioinfo_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_dioinfo_t *diop); + +typedef int (*dm_fsys_get_dirattrs_rvp_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvalp); + +typedef int (*dm_fsys_get_dmattr_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrname_t *attrnamep, + size_t buflen, + void *bufp, + size_t *rlenp); + +typedef int (*dm_fsys_get_eventlist_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int type, + u_int nelem, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int *nelemp); /* in kernel space! */ + +typedef int (*dm_fsys_get_fileattr_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int mask, + dm_stat_t *statp); + +typedef int (*dm_fsys_get_region_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_region_t *regbufp, + u_int *nelemp); + +typedef int (*dm_fsys_getall_dmattr_t)( + bhv_desc_t *bdp, + dm_right_t right, + size_t buflen, + void *bufp, + size_t *rlenp); + +typedef int (*dm_fsys_getall_inherit_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_inherit_t *inheritbufp, + u_int *nelemp); + +typedef int (*dm_fsys_init_attrloc_t)( + bhv_desc_t *bdp, /* sometimes root vnode */ + dm_right_t right, + dm_attrloc_t *locp); + +typedef int (*dm_fsys_mkdir_by_handle_t)( + bhv_desc_t *bdp, + dm_right_t right, + void *hanp, + size_t hlen, + char *cname); + +typedef int (*dm_fsys_probe_hole_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_off_t off, + dm_size_t len, + dm_off_t *roffp, + dm_size_t *rlenp); + +typedef int (*dm_fsys_punch_hole_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_off_t off, + dm_size_t len); + +typedef int (*dm_fsys_read_invis_rvp_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp); + +typedef int (*dm_fsys_release_right_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int type); + +typedef int (*dm_fsys_remove_dmattr_t)( + bhv_desc_t *bdp, + dm_right_t right, + int setdtime, + dm_attrname_t *attrnamep); + +typedef int (*dm_fsys_request_right_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int type, /* DM_FSYS_OBJ or zero */ + u_int flags, + dm_right_t newright); + +typedef int (*dm_fsys_set_dmattr_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrname_t *attrnamep, + int setdtime, + size_t buflen, + void *bufp); + +typedef int (*dm_fsys_set_eventlist_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int type, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int maxevent); + +typedef int (*dm_fsys_set_fileattr_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int mask, + dm_fileattr_t *attrp); + +typedef int (*dm_fsys_set_inherit_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrname_t *attrnamep, + mode_t mode); + +typedef int (*dm_fsys_set_region_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_region_t *regbufp, + dm_boolean_t *exactflagp); + +typedef int (*dm_fsys_symlink_by_handle_t)( + bhv_desc_t *bdp, + dm_right_t right, + void *hanp, + size_t hlen, + char *cname, + char *path); + +typedef int (*dm_fsys_sync_by_handle_t)( + bhv_desc_t *bdp, + dm_right_t right); + +typedef int (*dm_fsys_upgrade_right_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int type); /* DM_FSYS_OBJ or zero */ + +typedef int (*dm_fsys_write_invis_rvp_t)( + bhv_desc_t *bdp, + dm_right_t right, + int flags, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp); + +/* Structure definitions used by the F_DMAPI fcntl() call. */ + +typedef struct { + dm_fsys_switch_t func_no; /* function number */ + union { + dm_fsys_clear_inherit_t clear_inherit; + dm_fsys_create_by_handle_t create_by_handle; + dm_fsys_downgrade_right_t downgrade_right; + dm_fsys_get_allocinfo_rvp_t get_allocinfo_rvp; + dm_fsys_get_bulkall_rvp_t get_bulkall_rvp; + dm_fsys_get_bulkattr_rvp_t get_bulkattr_rvp; + dm_fsys_get_config_t get_config; + dm_fsys_get_config_events_t get_config_events; + dm_fsys_get_destroy_dmattr_t get_destroy_dmattr; + dm_fsys_get_dioinfo_t get_dioinfo; + dm_fsys_get_dirattrs_rvp_t get_dirattrs_rvp; + dm_fsys_get_dmattr_t get_dmattr; + dm_fsys_get_eventlist_t get_eventlist; + dm_fsys_get_fileattr_t get_fileattr; + dm_fsys_get_region_t get_region; + dm_fsys_getall_dmattr_t getall_dmattr; + dm_fsys_getall_inherit_t getall_inherit; + dm_fsys_init_attrloc_t init_attrloc; + dm_fsys_mkdir_by_handle_t mkdir_by_handle; + dm_fsys_probe_hole_t probe_hole; + dm_fsys_punch_hole_t punch_hole; + dm_fsys_read_invis_rvp_t read_invis_rvp; + dm_fsys_release_right_t release_right; + dm_fsys_remove_dmattr_t remove_dmattr; + dm_fsys_request_right_t request_right; + dm_fsys_set_dmattr_t set_dmattr; + dm_fsys_set_eventlist_t set_eventlist; + dm_fsys_set_fileattr_t set_fileattr; + dm_fsys_set_inherit_t set_inherit; + dm_fsys_set_region_t set_region; + dm_fsys_symlink_by_handle_t symlink_by_handle; + dm_fsys_sync_by_handle_t sync_by_handle; + dm_fsys_upgrade_right_t upgrade_right; + dm_fsys_write_invis_rvp_t write_invis_rvp; + } u_fc; +} fsys_function_vector_t; + +typedef struct { + int code_level; + int count; /* Number of functions in the vector */ + fsys_function_vector_t *vecp; +} dm_fcntl_vector_t; + +typedef struct { + size_t length; /* length of transfer */ + dm_eventtype_t max_event; /* Maximum (WRITE or READ) event */ + int error; /* returned error code */ +} dm_fcntl_mapevent_t; + +typedef struct { + size_t length; /* length of transfer */ + dm_eventtype_t max_event; /* Maximum (WRITE or READ) event */ + dm_eventtype_t issue_event; /* Event needed to be issued */ + int error; /* returned error code */ +} dm_fcntl_testevent_t; + +typedef struct { + int fsd_dmevmask; /* di_devmask */ + unsigned short fsd_padding; + unsigned short fsd_dmstate; /* di_dmstate */ +} dm_fcntl_fssetdm_t; + +typedef struct dm_fcntl { + int dmfc_subfunc; + union { + dm_fcntl_vector_t vecrq; + dm_fcntl_mapevent_t maprq; + dm_fcntl_testevent_t testrq; + dm_fcntl_fssetdm_t setdmrq; + } u_fcntl; +} dm_fcntl_t; + +#define DM_FCNTL_FSYSVECTOR 1 +#define DM_FCNTL_MAPEVENT 2 +#define DM_FCNTL_TESTEVENT 3 +#define DM_FCNTL_FSSETDM 4 + + +#endif /* __KERNEL__ */ + + +/* The following definitions are needed both by the kernel and by the + library routines. +*/ + +#define DM_MAX_HANDLE_SIZE 56 /* maximum size for a file handle */ + + +/* + * Opcodes for dmapi ioctl. + */ + +#define DM_CLEAR_INHERIT 1 +#define DM_CREATE_BY_HANDLE 2 +#define DM_CREATE_SESSION 3 +#define DM_CREATE_USEREVENT 4 +#define DM_DESTROY_SESSION 5 +#define DM_DOWNGRADE_RIGHT 6 +#define DM_FD_TO_HANDLE 7 +#define DM_FIND_EVENTMSG 8 +#define DM_GET_ALLOCINFO 9 +#define DM_GET_BULKALL 10 +#define DM_GET_BULKATTR 11 +#define DM_GET_CONFIG 12 +#define DM_GET_CONFIG_EVENTS 13 +#define DM_GET_DIOINFO 14 +#define DM_GET_DIRATTRS 15 +#define DM_GET_DMATTR 16 +#define DM_GET_EVENTLIST 17 +#define DM_GET_EVENTS 18 +#define DM_GET_FILEATTR 19 +#define DM_GET_MOUNTINFO 20 +#define DM_GET_REGION 21 +#define DM_GETALL_DISP 22 +#define DM_GETALL_DMATTR 23 +#define DM_GETALL_INHERIT 24 +#define DM_GETALL_SESSIONS 25 +#define DM_GETALL_TOKENS 26 +#define DM_INIT_ATTRLOC 27 +#define DM_MKDIR_BY_HANDLE 28 +#define DM_MOVE_EVENT 29 +#define DM_OBJ_REF_HOLD 30 +#define DM_OBJ_REF_QUERY 31 +#define DM_OBJ_REF_RELE 32 +#define DM_PATH_TO_FSHANDLE 33 +#define DM_PATH_TO_HANDLE 34 +#define DM_PENDING 35 +#define DM_PROBE_HOLE 36 +#define DM_PUNCH_HOLE 37 +#define DM_QUERY_RIGHT 38 +#define DM_QUERY_SESSION 39 +#define DM_READ_INVIS 40 +#define DM_RELEASE_RIGHT 41 +#define DM_REMOVE_DMATTR 42 +#define DM_REQUEST_RIGHT 43 +#define DM_RESPOND_EVENT 44 +#define DM_SEND_MSG 45 +#define DM_SET_DISP 46 +#define DM_SET_DMATTR 47 +#define DM_SET_EVENTLIST 48 +#define DM_SET_FILEATTR 49 +#define DM_SET_INHERIT 50 +#define DM_SET_REGION 51 +#define DM_SET_RETURN_ON_DESTROY 52 +#define DM_SYMLINK_BY_HANDLE 53 +#define DM_SYNC_BY_HANDLE 54 +#define DM_UPGRADE_RIGHT 55 +#define DM_WRITE_INVIS 56 + + +#endif /* __DMAPI_KERN_H__ */ diff -rNu linux-2.4.7/cmd/dmapi/install-sh linux-2.4-xfs/cmd/dmapi/install-sh --- linux-2.4.7/cmd/dmapi/install-sh Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/install-sh Wed Jun 13 13:06:23 2001 @@ -0,0 +1,276 @@ +#! /bin/sh +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +# +# This script emulates bsd install and also recognises +# two environment variables, with the following semantics :- +# +# $DIST_MANIFEST - if set, the name of the file to append manifest +# information in the following format: +# File : f mode owner group src target +# Directory: d mode owner group target +# Symlink : l linkval target +# +# $DIST_ROOT - if set, prepend to target +# +# The sematics of all combinations of these two variables +# are as follows: +# +# $DIST_MANIFEST? $DIST_ROOT? | Copy? Append Manifest? +# -----------------------------+-------------------------- +# not set not set | yes no +# not set set | yes no +# set not set | no yes +# set set | yes yes +# +_usage() { + echo "Usage: $prog [-o owner] [-g group] [-m mode] -d directory" + echo "or $prog [-D] [-o owner] [-g group] [-m mode] file directory/file" + echo "or $prog [-o owner] [-g group] [-m mode] file [file ...] directory" + echo "or $prog -S file target (creates \"target\" symlink)" + echo "" + echo "The \$DIST_MANIFEST and \$DIST_ROOT environment variables affect the" + echo "behaviour of this command - see comments in the script." + echo "The -D flag is only available for the second usage, and causes" + echo "the target directory to be created before installing the file." + echo "" + exit 1 +} + +_chown () +{ + _st=255 + if [ $# -eq 3 ] ; then + chown $1:$2 $3 + _st=$? + if [ $_st -ne 0 ] ; then + if [ $REAL_UID != '0' ] ; then + if [ ! -f $DIST_ROOT/.chown.quite ] ; then + echo '===============================================' + echo Ownership of files under ${DIST_ROOT:-/} + echo cannot be changed + echo '===============================================' + if [ -n "$DIST_ROOT" ] ; then + touch $DIST_ROOT/.chown.quite + fi + fi + _st=0 + fi + fi + fi + + return $_st +} + + +_manifest () +{ + echo $* | sed -e 's/\/\//\//g' >>${DIST_MANIFEST:-/dev/null} +} + +prog=`basename $0` +HERE=`pwd` +dflag=false +Dflag=false +Sflag=false +DIRMODE=755 +FILEMODE=644 +OWNER=`id -u` +GROUP=`id -g` +REAL_UID=$OWNER + +# default is to install and don't append manifest +INSTALL=true +MANIFEST=: + +[ -n "$DIST_MANIFEST" -a -z "$DIST_ROOT" ] && INSTALL=false +[ -n "$DIST_MANIFEST" ] && MANIFEST="_manifest" + +[ $# -eq 0 ] && _usage + +if $INSTALL +then + CP=cp; LN=ln; MKDIR=mkdir; CHMOD=chmod; CHOWN=_chown +else + CP=true; LN=true; MKDIR=true; CHMOD=true; CHOWN=true +fi + +[ -n "$DIST_ROOT" -a $REAL_UID -ne 0 ] && CHOWN=true + +while getopts "Dcm:d:S:o:g:" c $* +do + case $c in + c) + ;; + g) + GROUP=$OPTARG + ;; + o) + OWNER=$OPTARG + ;; + m) + DIRMODE=`expr $OPTARG` + FILEMODE=$DIRMODE + ;; + D) + Dflag=true + ;; + S) + symlink=$OPTARG + Sflag=true + ;; + d) + dir=$DIST_ROOT/$OPTARG + dflag=true + ;; + *) + _usage + ;; + esac +done + +shift `expr $OPTIND - 1` + +status=0 +if $dflag +then + # + # first usage + # + $MKDIR -p $dir + status=$? + if [ $status -eq 0 ] + then + $CHMOD $DIRMODE $dir + status=$? + fi + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir + status=$? + fi + $MANIFEST d $DIRMODE $OWNER $GROUP ${dir#$DIST_ROOT} +elif $Sflag +then + # + # fourth usage (symlink) + # + if [ $# -ne 1 ] + then + _usage + else + target=$DIST_ROOT/$1 + fi + $LN -s -f $symlink $target + status=$? + $MANIFEST l $symlink ${target#$DIST_ROOT} +else + list="" + dir="" + if [ $# -eq 2 ] + then + # + # second usage + # + f=$1 + case "$2" in + $DIST_ROOT/*) dir=$2 ;; + *) dir=$DIST_ROOT/$2 ;; + esac + if $Dflag + then + mkdir -p `dirname $dir` + fi + $CP $f $dir + status=$? + if [ $status -eq 0 ] + then + if [ -f $dir/$f ] + then + $CHMOD $FILEMODE $dir/$f + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir/$f + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f + else + $CHMOD $FILEMODE $dir + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$dir ${dir#$DIST_ROOT} + fi + fi + else + # + # third usage + # + n=1 + while [ $# -gt 0 ] + do + if [ $# -gt 1 ] + then + list="$list $1" + else + dir=$DIST_ROOT/$1 + fi + shift + done + + # echo DIR=$dir list=\"$list\" + for f in $list + do + $CP $f $dir + status=$? + if [ $status -eq 0 ] + then + $CHMOD $FILEMODE $dir/$f + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir/$f + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f + fi + [ $status -ne 0 ] && break + done + fi +fi + +exit $status diff -rNu linux-2.4.7/cmd/dmapi/libdm/CVS/Entries linux-2.4-xfs/cmd/dmapi/libdm/CVS/Entries --- linux-2.4.7/cmd/dmapi/libdm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/CVS/Entries Thu Jul 5 11:43:48 2001 @@ -0,0 +1,17 @@ +/Makefile/1.3/Wed Jun 13 18:06:23 2001/-ko/ +/dm_attr.c/1.2/Wed Jan 17 01:36:55 2001/-ko/ +/dm_bulkattr.c/1.2/Wed Jan 17 01:36:55 2001/-ko/ +/dm_config.c/1.2/Wed Jan 17 01:36:55 2001/-ko/ +/dm_dmattr.c/1.2/Wed Jan 17 01:36:55 2001/-ko/ +/dm_event.c/1.2/Wed Jan 17 01:36:55 2001/-ko/ +/dm_handle.c/1.2/Wed Jan 17 01:36:55 2001/-ko/ +/dm_handle2path.c/1.4/Thu Mar 29 06:25:56 2001/-ko/ +/dm_hole.c/1.2/Wed Jan 17 01:36:55 2001/-ko/ +/dm_mountinfo.c/1.2/Wed Jan 17 01:36:55 2001/-ko/ +/dm_rdwr.c/1.2/Wed Jan 17 01:36:55 2001/-ko/ +/dm_region.c/1.2/Wed Jan 17 01:36:55 2001/-ko/ +/dm_right.c/1.2/Wed Jan 17 01:36:55 2001/-ko/ +/dm_session.c/1.2/Wed Jan 17 01:36:55 2001/-ko/ +/dmapi_lib.c/1.3/Mon Feb 19 00:38:02 2001/-ko/ +/dmapi_lib.h/1.1/Wed Jan 17 01:28:43 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/dmapi/libdm/CVS/Repository linux-2.4-xfs/cmd/dmapi/libdm/CVS/Repository --- linux-2.4.7/cmd/dmapi/libdm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/CVS/Repository Thu Jul 5 11:43:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/dmapi/libdm diff -rNu linux-2.4.7/cmd/dmapi/libdm/CVS/Root linux-2.4-xfs/cmd/dmapi/libdm/CVS/Root --- linux-2.4.7/cmd/dmapi/libdm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/CVS/Root Thu Jul 5 11:43:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/dmapi/libdm/Makefile linux-2.4-xfs/cmd/dmapi/libdm/Makefile --- linux-2.4.7/cmd/dmapi/libdm/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/Makefile Wed Jun 13 13:06:23 2001 @@ -0,0 +1,58 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LTLIBRARY = libdm.la +LDLIBS = -lhandle + +HFILES = dmapi_lib.h +CFILES = dmapi_lib.c dm_attr.c dm_bulkattr.c dm_config.c dm_dmattr.c \ + dm_event.c dm_handle.c dm_handle2path.c dm_hole.c dm_mountinfo.c \ + dm_region.c dm_right.c dm_rdwr.c dm_session.c +LCFLAGS = -D_REENTRANT + +default: $(LTLIBRARY) + +include $(BUILDRULES) + +install: install-libLTLIBRARY + $(LT_INSTALL_FILTER) + +install-dev: install-libLTLIBRARY + $(LT_DEV_INSTALL_FILTER) + +install-libLTLIBRARY: $(LTLIBRARY) + $(INSTALL) -m 755 -d $(PKG_LIB_DIR) + $(LT_INSTALL) + $(LT_INSTALL_SYMLINKS) diff -rNu linux-2.4.7/cmd/dmapi/libdm/dm_attr.c linux-2.4-xfs/cmd/dmapi/libdm/dm_attr.c --- linux-2.4.7/cmd/dmapi/libdm/dm_attr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/dm_attr.c Tue Jan 16 19:36:55 2001 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "dmapi_lib.h" + + +extern int +dm_get_fileattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_stat_t *statp) +{ + return dmi(DM_GET_FILEATTR, sid, hanp, hlen, token, mask, statp); +} + + +extern int +dm_set_fileattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_fileattr_t *attrp) +{ + return dmi(DM_SET_FILEATTR, sid, hanp, hlen, token, mask, attrp); +} diff -rNu linux-2.4.7/cmd/dmapi/libdm/dm_bulkattr.c linux-2.4-xfs/cmd/dmapi/libdm/dm_bulkattr.c --- linux-2.4.7/cmd/dmapi/libdm/dm_bulkattr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/dm_bulkattr.c Tue Jan 16 19:36:55 2001 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "dmapi_lib.h" + + +extern int +dm_init_attrloc( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrloc_t *locp) +{ + return dmi(DM_INIT_ATTRLOC, sid, hanp, hlen, token, locp); +} + +extern int +dm_get_bulkattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + return dmi(DM_GET_BULKATTR, sid, hanp, hlen, token, mask, locp, buflen, bufp, rlenp); +} + +extern int +dm_get_dirattrs( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + return dmi(DM_GET_DIRATTRS, sid, hanp, hlen, token, mask, locp, buflen, bufp, rlenp); +} + +extern int +dm_get_bulkall( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrname_t *attrnamep, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + return dmi(DM_GET_BULKALL, sid, hanp, hlen, token, mask, + attrnamep, locp, buflen, bufp, rlenp); +} diff -rNu linux-2.4.7/cmd/dmapi/libdm/dm_config.c linux-2.4-xfs/cmd/dmapi/libdm/dm_config.c --- linux-2.4.7/cmd/dmapi/libdm/dm_config.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/dm_config.c Tue Jan 16 19:36:55 2001 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "dmapi_lib.h" + + +extern int +dm_get_config( + void *hanp, + size_t hlen, + dm_config_t flagname, + dm_size_t *retvalp) +{ + return dmi(DM_GET_CONFIG, hanp, hlen, flagname, retvalp); +} + + +extern int +dm_get_config_events( + void *hanp, + size_t hlen, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp) +{ + return dmi(DM_GET_CONFIG_EVENTS, hanp, hlen, nelem, eventsetp, nelemp); +} diff -rNu linux-2.4.7/cmd/dmapi/libdm/dm_dmattr.c linux-2.4-xfs/cmd/dmapi/libdm/dm_dmattr.c --- linux-2.4.7/cmd/dmapi/libdm/dm_dmattr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/dm_dmattr.c Tue Jan 16 19:36:55 2001 @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "dmapi_lib.h" + + +extern int +dm_clear_inherit( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep) +{ + return dmi(DM_CLEAR_INHERIT, sid, hanp, hlen, token, attrnamep); +} + + +extern int +dm_get_dmattr ( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + return dmi(DM_GET_DMATTR, sid, hanp, hlen, token, attrnamep, + buflen, bufp, rlenp); +} + + +extern int +dm_getall_dmattr ( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + return dmi(DM_GETALL_DMATTR, sid, hanp, hlen, token, buflen, + bufp, rlenp); +} + + +extern int +dm_getall_inherit( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_inherit_t *inheritbufp, + u_int *nelemp) +{ + return dmi(DM_GETALL_INHERIT, sid, hanp, hlen, token, nelem, + inheritbufp, nelemp); +} + + +extern int +dm_remove_dmattr ( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int setdtime, + dm_attrname_t *attrnamep) +{ + return dmi(DM_REMOVE_DMATTR, sid, hanp, hlen, token, setdtime, + attrnamep); +} + + +extern int +dm_set_dmattr ( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + int setdtime, + size_t buflen, + void *bufp) +{ + return dmi(DM_SET_DMATTR, sid, hanp, hlen, token, attrnamep, + setdtime, buflen, bufp); +} + + +extern int +dm_set_inherit( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + mode_t mode) +{ + return dmi(DM_SET_INHERIT, sid, hanp, hlen, token, attrnamep, mode); +} + + +extern int +dm_set_return_on_destroy ( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + dm_boolean_t enable) +{ + return dmi(DM_SET_RETURN_ON_DESTROY, sid, hanp, hlen, token, + attrnamep, enable); +} diff -rNu linux-2.4.7/cmd/dmapi/libdm/dm_event.c linux-2.4-xfs/cmd/dmapi/libdm/dm_event.c --- linux-2.4.7/cmd/dmapi/libdm/dm_event.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/dm_event.c Tue Jan 16 19:36:55 2001 @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "dmapi_lib.h" + + +extern int +dm_get_events( + dm_sessid_t sid, + u_int maxmsgs, + u_int flags, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + return dmi(DM_GET_EVENTS, sid, maxmsgs, flags, buflen, bufp, rlenp); +} + +extern int +dm_respond_event( + dm_sessid_t sid, + dm_token_t token, + dm_response_t response, + int reterror, + size_t buflen, + void *respbufp) +{ + return dmi(DM_RESPOND_EVENT, sid, token, response, reterror, + buflen, respbufp); +} + + +extern int +dm_get_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp) +{ + return dmi(DM_GET_EVENTLIST, sid, hanp, hlen, token, nelem, + eventsetp, nelemp); +} + +extern int +dm_set_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + u_int maxevent) +{ + return dmi(DM_SET_EVENTLIST, sid, hanp, hlen, token, + eventsetp, maxevent); +} + +extern int +dm_set_disp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + u_int maxevent) +{ + return dmi(DM_SET_DISP, sid, hanp, hlen, token, eventsetp, maxevent); +} + +extern int +dm_create_userevent( + dm_sessid_t sid, + size_t msglen, + void *msgdatap, + dm_token_t *tokenp) +{ + return dmi(DM_CREATE_USEREVENT, sid, msglen, msgdatap, tokenp); +} + +extern int +dm_send_msg( + dm_sessid_t targetsid, + dm_msgtype_t msgtype, + size_t buflen, + void *bufp) +{ + return dmi(DM_SEND_MSG, targetsid, msgtype, buflen, bufp); +} + +extern int +dm_move_event( + dm_sessid_t srcsid, + dm_token_t token, + dm_sessid_t targetsid, + dm_token_t *rtokenp) +{ + return dmi(DM_MOVE_EVENT, srcsid, token, targetsid, rtokenp); +} + +extern int +dm_pending( + dm_sessid_t sid, + dm_token_t token, + dm_timestruct_t *delay) +{ + return dmi(DM_PENDING, sid, token, delay); +} + +extern int +dm_getall_disp( + dm_sessid_t sid, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + return dmi(DM_GETALL_DISP, sid, buflen, bufp, rlenp); +} diff -rNu linux-2.4.7/cmd/dmapi/libdm/dm_handle.c linux-2.4-xfs/cmd/dmapi/libdm/dm_handle.c --- linux-2.4.7/cmd/dmapi/libdm/dm_handle.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/dm_handle.c Tue Jan 16 19:36:55 2001 @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include + +#include +#include +#include "dmapi_lib.h" + +#ifdef linux +#include +#include +#else +#include +#endif + +typedef enum { + DM_HANDLE_GLOBAL, + DM_HANDLE_FILESYSTEM, + DM_HANDLE_FILE, + DM_HANDLE_BAD +} dm_handletype_t; + + +extern int +dm_path_to_handle ( + char *path, + void **hanpp, + size_t *hlenp) +{ + char hbuf[DM_MAX_HANDLE_SIZE]; + + if (dmi(DM_PATH_TO_HANDLE, path, hbuf, hlenp)) + return(-1); + + if ((*hanpp = malloc(*hlenp)) == NULL) { + errno = ENOMEM; + return -1; + } + memcpy(*hanpp, hbuf, *hlenp); + return(0); +} + + +extern int +dm_path_to_fshandle ( + char *path, + void **hanpp, + size_t *hlenp) +{ + char hbuf[DM_MAX_HANDLE_SIZE]; + + if (dmi(DM_PATH_TO_FSHANDLE, path, hbuf, hlenp)) + return(-1); + + if ((*hanpp = malloc(*hlenp)) == NULL) { + errno = ENOMEM; + return -1; + } + memcpy(*hanpp, hbuf, *hlenp); + return(0); +} + + +extern int +dm_fd_to_handle ( + int fd, + void **hanpp, + size_t *hlenp) +{ + char hbuf[DM_MAX_HANDLE_SIZE]; + + if (dmi(DM_FD_TO_HANDLE, fd, hbuf, hlenp)) + return(-1); + + if ((*hanpp = malloc(*hlenp)) == NULL) { + errno = ENOMEM; + return -1; + } + memcpy(*hanpp, hbuf, *hlenp); + return(0); +} + + +extern int +dm_handle_to_fshandle ( + void *hanp, + size_t hlen, + void **fshanp, + size_t *fshlen) +{ + dm_fsid_t fsid; + + if (dm_handle_to_fsid(hanp, hlen, &fsid)) + return(-1); + + *fshlen = sizeof(fsid); + if ((*fshanp = malloc(*fshlen)) == NULL) { + errno = ENOMEM; + return(-1); + } + memcpy(*fshanp, &fsid, *fshlen); + return(0); +} + + +/* ARGSUSED */ +extern void +dm_handle_free( + void *hanp, + size_t hlen) +{ + free(hanp); +} + + +static dm_handletype_t +parse_handle( + void *hanp, + size_t hlen, + dm_fsid_t *fsidp, + dm_ino_t *inop, + dm_igen_t *igenp) +{ +/* XXX */ + xfs_handle_t handle; + xfs_fid2_t *xfid2; + fid_t *fidp; + + if (hanp == DM_GLOBAL_HANP && hlen == DM_GLOBAL_HLEN) + return(DM_HANDLE_GLOBAL); + + if (hlen < sizeof(handle.ha_fsid) || hlen > sizeof(handle)) + return(DM_HANDLE_BAD); + + memcpy(&handle, hanp, hlen); + if (!handle.ha_fsid.val[0] || !handle.ha_fsid.val[1]) + return(DM_HANDLE_BAD); + if (fsidp) + memcpy(fsidp, &handle.ha_fsid, sizeof(handle.ha_fsid)); + if (hlen == sizeof(handle.ha_fsid)) + return(DM_HANDLE_FILESYSTEM); + +#if 0 + if (handle.ha_fid.fid_len != (hlen - sizeof(handle.ha_fsid) - sizeof(handle.ha_fid.fid_len))) + return(DM_HANDLE_BAD); +#else + fidp = (fid_t*)&handle.ha_fid; + if (fidp->fid_len != (hlen - sizeof(handle.ha_fsid) - sizeof(fidp->fid_len))) + return(DM_HANDLE_BAD); +#endif + + xfid2 = (struct xfs_fid2 *)&handle.ha_fid; + if (xfid2->fid_len == sizeof *xfid2 - sizeof xfid2->fid_len) { + if (xfid2->fid_pad) + return(DM_HANDLE_BAD); + if (inop) + *inop = xfid2->fid_ino; + if (igenp) + *igenp = xfid2->fid_gen; + } else { + return(DM_HANDLE_BAD); + } + return(DM_HANDLE_FILE); +} + + +extern dm_boolean_t +dm_handle_is_valid( + void *hanp, + size_t hlen) +{ + if (parse_handle(hanp, hlen, NULL, NULL, NULL) != DM_HANDLE_BAD) + return(DM_TRUE); + return(DM_FALSE); +} + + +extern int +dm_handle_cmp( + void *hanp1, + size_t hlen1, + void *hanp2, + size_t hlen2) +{ + int diff; + + /* If the handles don't have the same length, then this is an + apples-and-oranges comparison. For lack of a better option, + use the handle lengths to sort them into an arbitrary order. + */ + if ((diff = (int)(hlen1 - hlen2)) != 0) + return diff; + return(memcmp(hanp1, hanp2, hlen1)); +} + + +extern u_int +dm_handle_hash( + void *hanp, + size_t hlen) +{ + size_t i; + u_int hash = 0; + u_char *ip = (u_char *)hanp; + + for (i = 0; i < hlen; i++) { + hash += *ip++; + } + return(hash); +} + + +extern int +dm_handle_to_fsid( + void *hanp, + size_t hlen, + dm_fsid_t *fsidp) +{ + dm_handletype_t htype; + + htype = parse_handle(hanp, hlen, fsidp, NULL, NULL); + if (htype == DM_HANDLE_FILE || htype == DM_HANDLE_FILESYSTEM) + return(0); + errno = EBADF; + return(-1); +} + + +extern int +dm_handle_to_ino( + void *hanp, + size_t hlen, + dm_ino_t *inop) +{ + if (parse_handle(hanp, hlen, NULL, inop, NULL) == DM_HANDLE_FILE) + return(0); + errno = EBADF; + return(-1); +} + + +extern int +dm_handle_to_igen( + void *hanp, + size_t hlen, + dm_igen_t *igenp) +{ + if (parse_handle(hanp, hlen, NULL, NULL, igenp) == DM_HANDLE_FILE) + return(0); + errno = EBADF; + return(-1); +} + + +extern int +dm_make_handle( + dm_fsid_t *fsidp, + dm_ino_t *inop, + dm_igen_t *igenp, + void **hanpp, + size_t *hlenp) +{ + xfs_fid2_t *xfid2; +/* XXX */ + xfs_handle_t handle; + + memcpy(&handle.ha_fsid, fsidp, sizeof(handle.ha_fsid)); + xfid2 = (struct xfs_fid2 *)&handle.ha_fid; + xfid2->fid_pad = 0; + xfid2->fid_gen = (__u32)*igenp; + xfid2->fid_ino = *inop; + xfid2->fid_len = sizeof(*xfid2) - sizeof(xfid2->fid_len); + *hlenp = sizeof(*xfid2) + sizeof(handle.ha_fsid); + if ((*hanpp = malloc(*hlenp)) == NULL) { + errno = ENOMEM; + return -1; + } + memcpy(*hanpp, &handle, *hlenp); + return(0); +} + + +extern int +dm_make_fshandle( + dm_fsid_t *fsidp, + void **hanpp, + size_t *hlenp) +{ +/* XXX */ +#if 0 + *hlenp = sizeof(fsid_t); +#else + *hlenp = sizeof(__kernel_fsid_t); +#endif + if ((*hanpp = malloc(*hlenp)) == NULL) { + errno = ENOMEM; + return -1; + } + memcpy(*hanpp, fsidp, *hlenp); + return(0); +} + + +extern int +dm_create_by_handle( + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname) +{ + return dmi(DM_CREATE_BY_HANDLE, sid, dirhanp, dirhlen, token, + hanp, hlen, cname); +} + + +extern int +dm_mkdir_by_handle( + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname) +{ + return dmi(DM_MKDIR_BY_HANDLE, sid, dirhanp, dirhlen, token, hanp, + hlen, cname); +} + + +extern int +dm_symlink_by_handle( + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname, + char *path) +{ + return dmi(DM_SYMLINK_BY_HANDLE, sid, dirhanp, dirhlen, token, hanp, + hlen, cname, path); +} diff -rNu linux-2.4.7/cmd/dmapi/libdm/dm_handle2path.c linux-2.4-xfs/cmd/dmapi/libdm/dm_handle2path.c --- linux-2.4.7/cmd/dmapi/libdm/dm_handle2path.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/dm_handle2path.c Thu Mar 29 00:25:56 2001 @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef linux +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include "dmapi_lib.h" + + +/* Originally this routine called SGI_OPEN_BY_HANDLE on the target object, did + a fstat on it, then searched for the matching inode number in the directory + pointed to by dirhanp. There were a couple of problems with this. + 1. dm_handle_to_path is supposed to work for symlink target objects, but + didn't because SGI_OPEN_BY_HANDLE only works for files and directories. + 2. The wrong pathname was sometimes returned if dirhanp and targhanp pointed + to the same directory (a common request) because ".", ".." and/or various + subdirectories could all be mount points and therefore all have the same + inode number of 128. + 3. dm_handle_to_path wouldn't work if targhanp was a mount point because + routine getcomp() sees only the mounted-on directory, not the mount point. + + This rework of dm_handle_to_path fixes all these problems, but at a price, + because routine getcomp() must make one system call per directory entry. + Someday these two methods should be combined. If an SGI_OPEN_BY_HANDLE of + targhanp works and if both dirhanp and targhanp have the same dev_t, then + use the old method, otherwise use the current method. This will remove + the system call overhead in nearly all cases. +*/ + +static int getcomp(int dirfd, void *targhanp, size_t targhlen, + char *bufp, size_t buflen, size_t *rlenp); + + +extern int +dm_handle_to_path( + void *dirhanp, /* parent directory handle and length */ + size_t dirhlen, + void *targhanp, /* target object handle and length */ + size_t targhlen, + size_t buflen, /* length of pathbufp */ + char *pathbufp, /* buffer in which name is returned */ + size_t *rlenp) /* length of resultant pathname */ +{ + int dirfd = -1; /* fd for parent directory */ + int origfd = -1; /* fd for current working directory */ + int err; /* a place to save errno */ + + if (buflen == 0) { + errno = EINVAL; + return -1; + } + if (pathbufp == NULL || rlenp == NULL) { + errno = EFAULT; + return -1; + } + if ((origfd = open(".", O_RDONLY)) < 0) + return -1; /* leave errno set from open */ + +#if 0 + dirfd = (int)syssgi(SGI_OPEN_BY_HANDLE, dirhanp, dirhlen, O_RDONLY); +#else + dirfd = open_by_handle(dirhanp, dirhlen, O_RDONLY); +#endif + if (dirfd < 0) { + err = errno; + } else if (fchdir(dirfd)) { + err = errno; + } else { + /* From here on the fchdir must always be undone! */ + + if (!getcwd(pathbufp, buflen)) { + if ((err = errno) == ERANGE) /* buffer too small */ + err = E2BIG; + } else { + err = getcomp(dirfd, targhanp, targhlen, pathbufp, + buflen, rlenp); + } + (void) fchdir(origfd); /* can't do anything about a failure */ + } + + if (origfd >= 0) + (void)close(origfd); + if (dirfd >= 0) + (void)close(dirfd); + if (!err) + return(0); + + if (err == E2BIG) + *rlenp = 2 * buflen; /* guess since we don't know */ + errno = err; + return(-1); +} + + +/* Append the basename of the open file referenced by targfd found in the + directory dirfd to dirfd's pathname in bufp. The length of the entire + path (including the NULL) is returned in *rlenp. + + Returns zero if successful, an appropriate errno if not. +*/ + +#define READDIRSZ 16384 /* 6.x kernels use 16k buffer */ + +static int +getcomp( + int dirfd, + void *targhanp, + size_t targhlen, + char *bufp, + size_t buflen, + size_t *rlenp) +{ + char buf[READDIRSZ]; /* directory entry data buffer */ + int loc = 0; /* byte offset of entry in the buffer */ + int size = 0; /* number of bytes of data in buffer */ + int eof = 0; /* did last ngetdents exhaust dir.? */ +#if 0 +/* XXX */ + struct dirent64 *dp; /* pointer to directory entry */ +#else + struct dirent *dp; +#endif + char hbuf[DM_MAX_HANDLE_SIZE]; + size_t hlen; + size_t dirlen; /* length of dirfd's pathname */ + size_t totlen; /* length of targfd's pathname */ + dm_ino_t ino; /* target object's inode # */ + + if (dm_handle_to_ino(targhanp, targhlen, &ino)) + return -1; /* leave errno set from dm_handle_to_ino */ + + /* Append a "/" to the directory name unless the directory is root. */ + + dirlen = strlen(bufp); + if (dirlen > 1) { + if (buflen < dirlen + 1 + 1) + return(E2BIG); + bufp[dirlen++] = '/'; + } + + /* Examine each entry in the directory looking for one with a + matching target handle. + */ + + for(;;) { + if (size > 0) { + dp = (struct dirent *)&buf[loc]; + loc += dp->d_reclen; + } + if (loc >= size) { + if (eof) { + return(ENOENT); + } + loc = size = 0; + } + if (size == 0) { /* refill buffer */ +#ifdef linux + int cnt; + + do { + cnt = syscall(SYS_getdents, dirfd, + (struct dirent *)buf, + sizeof(buf)); + if (cnt > 0 ) + size += cnt; + if (cnt < 0) + size = cnt; + } while( cnt > 0 ); + +#else + size = ngetdents64(dirfd, (struct dirent *)buf, + sizeof(buf), &eof); +#endif + if (size == 0) { /* This also means EOF */ + return(ENOENT); + } + if (size < 0) { /* error */ + return(errno); + } + } + dp = (struct dirent *)&buf[loc]; + + if (dp->d_ino != ino) + continue; /* wrong inode; try again */ + totlen = dirlen + strlen(dp->d_name) + 1; + if (buflen < totlen) + return(E2BIG); + (void)strcpy(bufp + dirlen, dp->d_name); + + if (dmi(DM_PATH_TO_HANDLE, bufp, hbuf, &hlen)) + continue; /* must have been removed/renamed */ + if (!dm_handle_cmp(targhanp, targhlen, hbuf, hlen)) + break; + } + + /* We have a match based upon the target handle. Clean up the end + cases before returning the path to the caller. + */ + + if (!strcmp(dp->d_name, ".")) { /* the directory itself */ + if (dirlen > 1) + dirlen--; + bufp[dirlen] = '\0'; /* trim the trailing "/." */ + *rlenp = dirlen + 1; + return(0); + } + if (!strcmp(dp->d_name, "..")) { /* the parent directory */ + char *slash; + + if (dirlen > 1) + dirlen--; + bufp[dirlen] = '\0'; + if ((slash = strrchr(bufp, '/')) == NULL) + return(ENXIO); /* getcwd screwed up */ + if (slash == bufp) /* don't whack "/" */ + slash++; + *slash = '\0'; /* remove the last component */ + *rlenp = strlen(bufp) + 1; + return(0); + } + + *rlenp = totlen; /* success! */ + return(0); +} diff -rNu linux-2.4.7/cmd/dmapi/libdm/dm_hole.c linux-2.4-xfs/cmd/dmapi/libdm/dm_hole.c --- linux-2.4.7/cmd/dmapi/libdm/dm_hole.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/dm_hole.c Tue Jan 16 19:36:55 2001 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "dmapi_lib.h" + + +extern int +dm_get_allocinfo ( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t *offp, + u_int nelem, + dm_extent_t *extentp, + u_int *nelemp) +{ + return dmi(DM_GET_ALLOCINFO, sid, hanp, hlen, token, offp, nelem, + extentp, nelemp); +} + +extern int +dm_probe_hole( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + dm_off_t *roffp, + dm_size_t *rlenp) +{ + return dmi(DM_PROBE_HOLE, sid, hanp, hlen, token, off, len, roffp, rlenp); +} + +extern int +dm_punch_hole( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len) +{ + return dmi(DM_PUNCH_HOLE, sid, hanp, hlen, token, off, len); +} diff -rNu linux-2.4.7/cmd/dmapi/libdm/dm_mountinfo.c linux-2.4-xfs/cmd/dmapi/libdm/dm_mountinfo.c --- linux-2.4.7/cmd/dmapi/libdm/dm_mountinfo.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/dm_mountinfo.c Tue Jan 16 19:36:55 2001 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "dmapi_lib.h" + + +extern int +dm_get_mountinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + return dmi(DM_GET_MOUNTINFO, sid, hanp, hlen, token, buflen, + bufp, rlenp); +} diff -rNu linux-2.4.7/cmd/dmapi/libdm/dm_rdwr.c linux-2.4-xfs/cmd/dmapi/libdm/dm_rdwr.c --- linux-2.4.7/cmd/dmapi/libdm/dm_rdwr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/dm_rdwr.c Tue Jan 16 19:36:55 2001 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "dmapi_lib.h" + + +extern dm_ssize_t +dm_read_invis( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + void *bufp) +{ + return dmi(DM_READ_INVIS, sid, hanp, hlen, token, off, len, bufp); +} + +extern dm_ssize_t +dm_write_invis( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int flags, + dm_off_t off, + dm_size_t len, + void *bufp) +{ + return dmi(DM_WRITE_INVIS, sid, hanp, hlen, token, flags, off, len, bufp); +} + +extern int +dm_sync_by_handle( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ + return dmi(DM_SYNC_BY_HANDLE, sid, hanp, hlen, token); +} + + +extern int +dm_get_dioinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_dioinfo_t *diop) +{ + return dmi(DM_GET_DIOINFO, sid, hanp, hlen, token, diop); +} diff -rNu linux-2.4.7/cmd/dmapi/libdm/dm_region.c linux-2.4-xfs/cmd/dmapi/libdm/dm_region.c --- linux-2.4.7/cmd/dmapi/libdm/dm_region.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/dm_region.c Tue Jan 16 19:36:55 2001 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "dmapi_lib.h" + + +extern int +dm_get_region( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_region_t *regbufp, + u_int *nelemp) +{ + return dmi(DM_GET_REGION, sid, hanp, hlen, token, nelem, + regbufp, nelemp); +} + +extern int +dm_set_region( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_region_t *regbufp, + dm_boolean_t *exactflagp) +{ + return dmi(DM_SET_REGION, sid, hanp, hlen, token, nelem, + regbufp, exactflagp); +} diff -rNu linux-2.4.7/cmd/dmapi/libdm/dm_right.c linux-2.4-xfs/cmd/dmapi/libdm/dm_right.c --- linux-2.4.7/cmd/dmapi/libdm/dm_right.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/dm_right.c Tue Jan 16 19:36:55 2001 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "dmapi_lib.h" + + +extern int +dm_downgrade_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ + return dmi(DM_DOWNGRADE_RIGHT, sid, hanp, hlen, token); +} + + +extern int +dm_obj_ref_hold( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen) +{ + return dmi(DM_OBJ_REF_HOLD, sid, token, hanp, hlen); +} + + +extern int +dm_obj_ref_query( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen) +{ + return dmi(DM_OBJ_REF_QUERY, sid, token, hanp, hlen); +} + + +extern int +dm_obj_ref_rele( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen) +{ + return dmi(DM_OBJ_REF_RELE, sid, token, hanp, hlen); +} + + +extern int +dm_query_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_right_t *rightp) +{ + return dmi(DM_QUERY_RIGHT, sid, hanp, hlen, token, rightp); +} + + +extern int +dm_release_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ + return dmi(DM_RELEASE_RIGHT, sid, hanp, hlen, token); +} + + +extern int +dm_request_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int flags, + dm_right_t right) +{ + return dmi(DM_REQUEST_RIGHT, sid, hanp, hlen, token, flags, right); +} + + +extern int +dm_upgrade_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ + return dmi(DM_UPGRADE_RIGHT, sid, hanp, hlen, token); +} diff -rNu linux-2.4.7/cmd/dmapi/libdm/dm_session.c linux-2.4-xfs/cmd/dmapi/libdm/dm_session.c --- linux-2.4.7/cmd/dmapi/libdm/dm_session.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/dm_session.c Tue Jan 16 19:36:55 2001 @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "dmapi_lib.h" + + +extern int +dm_init_service( + char **versionstrpp) +{ + int ret; + + *versionstrpp = DM_VER_STR_CONTENTS; + ret = dmi_init_service( *versionstrpp ); + return(ret); +} + +extern int +dm_create_session( + dm_sessid_t oldsid, + char *sessinfop, + dm_sessid_t *newsidp) +{ + return dmi(DM_CREATE_SESSION, oldsid, sessinfop, newsidp); +} + +extern int +dm_destroy_session( + dm_sessid_t sid) +{ + return dmi(DM_DESTROY_SESSION, sid); +} + +extern int +dm_getall_sessions( + u_int nelem, + dm_sessid_t *sidbufp, + u_int *nelemp) +{ + return dmi(DM_GETALL_SESSIONS, nelem, sidbufp, nelemp); +} + +extern int +dm_query_session( + dm_sessid_t sid, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + return dmi(DM_QUERY_SESSION, sid, buflen, bufp, rlenp); +} + +extern int +dm_getall_tokens( + dm_sessid_t sid, + u_int nelem, + dm_token_t *tokenbufp, + u_int *nelemp) +{ + return dmi(DM_GETALL_TOKENS, sid, nelem, tokenbufp, nelemp); +} + +extern int +dm_find_eventmsg( + dm_sessid_t sid, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + return dmi(DM_FIND_EVENTMSG, sid, token, buflen, bufp, rlenp); +} diff -rNu linux-2.4.7/cmd/dmapi/libdm/dmapi_lib.c linux-2.4-xfs/cmd/dmapi/libdm/dmapi_lib.c --- linux-2.4.7/cmd/dmapi/libdm/dmapi_lib.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/dmapi_lib.c Sun Feb 18 18:38:02 2001 @@ -0,0 +1,519 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include + +#include +#include +#include "dmapi_lib.h" + +#define ARG(y) (long)va_arg(ap,y) + +static int dmapi_fd = -1; + +int +dmi_init_service( char *versionstr ) +{ + dmapi_fd = open( "/dev/dmapi", O_RDWR ); + if( dmapi_fd == -1 ) + return -1; + return 0; +} + + +int +dmi( int opcode, ... ) +{ + va_list ap; + sys_dmapi_args_t u; + int ret = 0; + + if( dmapi_fd == -1 ){ + /* dm_init_service wasn't called, or failed. The spec + * says my behavior is undefined. + */ + errno = ENOSYS; + return -1; + } + + va_start(ap, opcode); + switch( opcode ){ +/* dm_session */ + case DM_CREATE_SESSION: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(char*); + u.arg3 = ARG(dm_sessid_t*); + break; + case DM_QUERY_SESSION: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(size_t); + u.arg3 = ARG(void*); + u.arg4 = ARG(size_t*); + break; + case DM_GETALL_SESSIONS: + u.arg1 = ARG(u_int); + u.arg2 = ARG(dm_sessid_t*); + u.arg3 = ARG(u_int*); + break; + case DM_DESTROY_SESSION: + u.arg1 = ARG(dm_sessid_t); + break; + case DM_GETALL_TOKENS: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(u_int); + u.arg3 = ARG(dm_token_t*); + u.arg4 = ARG(u_int*); + break; + case DM_FIND_EVENTMSG: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(dm_token_t); + u.arg3 = ARG(size_t); + u.arg4 = ARG(void*); + u.arg5 = ARG(size_t*); + break; +/* dm_config */ + case DM_GET_CONFIG: + u.arg1 = ARG(void*); + u.arg2 = ARG(size_t); + u.arg3 = ARG(dm_config_t); + u.arg4 = ARG(dm_size_t*); + break; + case DM_GET_CONFIG_EVENTS: + u.arg1 = ARG(void*); + u.arg2 = ARG(size_t); + u.arg3 = ARG(u_int); + u.arg4 = ARG(dm_eventset_t*); + u.arg5 = ARG(u_int*); + break; +/* dm_attr */ + case DM_GET_FILEATTR: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(u_int); + u.arg6 = ARG(dm_stat_t*); + break; + case DM_SET_FILEATTR: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(u_int); + u.arg6 = ARG(dm_fileattr_t*); + break; +/* dm_bulkattr */ + case DM_INIT_ATTRLOC: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(dm_attrloc_t*); + break; + case DM_GET_BULKATTR: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(u_int); + u.arg6 = ARG(dm_attrloc_t*); + u.arg7 = ARG(size_t); + u.arg8 = ARG(void*); + u.arg9 = ARG(size_t*); + break; + case DM_GET_DIRATTRS: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(u_int); + u.arg6 = ARG(dm_attrloc_t*); + u.arg7 = ARG(size_t); + u.arg8 = ARG(void*); + u.arg9 = ARG(size_t*); + break; + case DM_GET_BULKALL: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(u_int); + u.arg6 = ARG(dm_attrname_t*); + u.arg7 = ARG(dm_attrloc_t*); + u.arg8 = ARG(size_t); + u.arg9 = ARG(void*); + u.arg10 = ARG(size_t*); + break; +/* dm_dmattr */ + case DM_CLEAR_INHERIT: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(dm_attrname_t*); + break; + case DM_GET_DMATTR: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(dm_attrname_t*); + u.arg6 = ARG(size_t); + u.arg7 = ARG(void*); + u.arg8 = ARG(size_t*); + break; + case DM_GETALL_DMATTR: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(size_t); + u.arg6 = ARG(void*); + u.arg7 = ARG(size_t*); + break; + case DM_GETALL_INHERIT: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(u_int); + u.arg6 = ARG(dm_inherit_t*); + u.arg7 = ARG(u_int*); + break; + case DM_REMOVE_DMATTR: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(int); + u.arg6 = ARG(dm_attrname_t*); + break; + case DM_SET_DMATTR: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(dm_attrname_t*); + u.arg6 = ARG(int); + u.arg7 = ARG(size_t); + u.arg8 = ARG(void*); + break; + case DM_SET_INHERIT: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(dm_attrname_t*); + u.arg6 = ARG(mode_t); + break; + case DM_SET_RETURN_ON_DESTROY: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(dm_attrname_t*); + u.arg6 = ARG(dm_boolean_t); + break; +/* dm_event */ + case DM_GET_EVENTS: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(u_int); + u.arg3 = ARG(u_int); + u.arg4 = ARG(size_t); + u.arg5 = ARG(void*); + u.arg6 = ARG(size_t*); + break; + case DM_RESPOND_EVENT: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(dm_token_t); + u.arg3 = ARG(dm_response_t); + u.arg4 = ARG(int); + u.arg5 = ARG(size_t); + u.arg6 = ARG(void*); + break; + case DM_GET_EVENTLIST: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(u_int); + u.arg6 = ARG(dm_eventset_t*); + u.arg7 = ARG(u_int*); + break; + case DM_SET_EVENTLIST: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(dm_eventset_t*); + u.arg6 = ARG(u_int); + break; + case DM_SET_DISP: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(dm_eventset_t*); + u.arg6 = ARG(u_int); + break; + case DM_CREATE_USEREVENT: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(size_t); + u.arg3 = ARG(void*); + u.arg4 = ARG(dm_token_t*); + break; + case DM_SEND_MSG: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(dm_msgtype_t); + u.arg3 = ARG(size_t); + u.arg4 = ARG(void*); + break; + case DM_MOVE_EVENT: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(dm_token_t); + u.arg3 = ARG(dm_sessid_t); + u.arg4 = ARG(dm_token_t*); + break; + case DM_PENDING: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(dm_token_t); + u.arg3 = ARG(dm_timestruct_t*); + break; + case DM_GETALL_DISP: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(size_t); + u.arg3 = ARG(void*); + u.arg4 = ARG(size_t*); + break; +/* dm_handle */ + case DM_PATH_TO_HANDLE: + u.arg1 = ARG(char*); + u.arg2 = ARG(char*); + u.arg3 = ARG(size_t*); + break; + case DM_PATH_TO_FSHANDLE: + u.arg1 = ARG(char*); + u.arg2 = ARG(char*); + u.arg3 = ARG(size_t*); + break; + case DM_FD_TO_HANDLE: + u.arg1 = ARG(int); + u.arg2 = ARG(char*); + u.arg3 = ARG(size_t*); + break; + case DM_CREATE_BY_HANDLE: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(void*); + u.arg6 = ARG(size_t); + u.arg7 = ARG(char*); + break; + case DM_MKDIR_BY_HANDLE: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(void*); + u.arg6 = ARG(size_t); + u.arg7 = ARG(char*); + break; + case DM_SYMLINK_BY_HANDLE: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(void*); + u.arg6 = ARG(size_t); + u.arg7 = ARG(char*); + u.arg8 = ARG(char*); + break; +/* dm_hole */ + case DM_GET_ALLOCINFO: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(dm_off_t*); + u.arg6 = ARG(u_int); + u.arg7 = ARG(dm_extent_t*); + u.arg8 = ARG(u_int*); + break; + case DM_PROBE_HOLE: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(dm_off_t); + u.arg6 = ARG(dm_size_t); + u.arg7 = ARG(dm_off_t*); + u.arg8 = ARG(dm_size_t*); + break; + case DM_PUNCH_HOLE: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(dm_off_t); + u.arg6 = ARG(dm_size_t); + break; +/* dm_mountinfo */ + case DM_GET_MOUNTINFO: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(size_t); + u.arg6 = ARG(void*); + u.arg7 = ARG(size_t*); + break; +/* dm_rdwr */ + case DM_READ_INVIS: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(dm_off_t); + u.arg6 = ARG(dm_size_t); + u.arg7 = ARG(void*); + break; + case DM_WRITE_INVIS: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(int); + u.arg6 = ARG(dm_off_t); + u.arg7 = ARG(dm_size_t); + u.arg8 = ARG(void*); + break; + case DM_SYNC_BY_HANDLE: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + break; + case DM_GET_DIOINFO: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(dm_dioinfo_t*); + break; +/* dm_region */ + case DM_GET_REGION: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(u_int); + u.arg6 = ARG(dm_region_t*); + u.arg7 = ARG(u_int*); + break; + case DM_SET_REGION: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(u_int); + u.arg6 = ARG(dm_region_t*); + u.arg7 = ARG(dm_boolean_t*); + break; +/* dm_right */ + case DM_DOWNGRADE_RIGHT: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + break; + case DM_OBJ_REF_HOLD: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(dm_token_t); + u.arg3 = ARG(void*); + u.arg4 = ARG(size_t); + break; + case DM_OBJ_REF_QUERY: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(dm_token_t); + u.arg3 = ARG(void*); + u.arg4 = ARG(size_t); + break; + case DM_OBJ_REF_RELE: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(dm_token_t); + u.arg3 = ARG(void*); + u.arg4 = ARG(size_t); + break; + case DM_QUERY_RIGHT: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(dm_right_t*); + break; + case DM_RELEASE_RIGHT: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + break; + case DM_REQUEST_RIGHT: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + u.arg5 = ARG(u_int); + u.arg6 = ARG(dm_right_t); + break; + case DM_UPGRADE_RIGHT: + u.arg1 = ARG(dm_sessid_t); + u.arg2 = ARG(void*); + u.arg3 = ARG(size_t); + u.arg4 = ARG(dm_token_t); + break; + default: + errno = ENOSYS; + ret = -1; + break; + } + va_end(ap); + + if( ret != -1 ) + ret = ioctl( dmapi_fd, opcode, &u ); + + return(ret); +} diff -rNu linux-2.4.7/cmd/dmapi/libdm/dmapi_lib.h linux-2.4-xfs/cmd/dmapi/libdm/dmapi_lib.h --- linux-2.4.7/cmd/dmapi/libdm/dmapi_lib.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/libdm/dmapi_lib.h Tue Jan 16 19:28:43 2001 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#include + +int dmi( int opcode, ... ); + +int dmi_init_service( char *versionstr ); diff -rNu linux-2.4.7/cmd/dmapi/ltconfig linux-2.4-xfs/cmd/dmapi/ltconfig --- linux-2.4.7/cmd/dmapi/ltconfig Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/ltconfig Wed Jun 13 13:06:23 2001 @@ -0,0 +1,3114 @@ +#! /bin/sh + +# ltconfig - Create a system-specific libtool. +# Copyright (C) 1996-1999 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# A lot of this script is taken from autoconf-2.10. + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} +echo=echo +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec "$SHELL" "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat </dev/null`} + case X$UNAME in + *-DOS) PATH_SEPARATOR=';' ;; + *) PATH_SEPARATOR=':' ;; + esac +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +if test "X${echo_test_string+set}" != Xset; then + # find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string="`eval $cmd`") 2>/dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null; then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" != 'X\t' || + test "X`($echo "$echo_test_string") 2>/dev/null`" != X"$echo_test_string"; then + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for dir in $PATH /usr/ucb; do + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + test "X`($dir/echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + test "X`(print -r "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running ltconfig again with it. + ORIGINAL_CONFIG_SHELL="${CONFIG_SHELL-/bin/sh}" + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + echo='printf "%s\n"' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + test "X`($echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then + # Cool, printf works + : + elif test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' && + test "X`("$ORIGINAL_CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then + CONFIG_SHELL="$ORIGINAL_CONFIG_SHELL" + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL $0 --fallback-echo" + elif test "X`("$CONFIG_SHELL" "$0" --fallback-echo '\t') 2>/dev/null`" = 'X\t' && + test "X`("$CONFIG_SHELL" "$0" --fallback-echo "$echo_test_string") 2>/dev/null`" = X"$echo_test_string"; then + echo="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null; then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec "${ORIGINAL_CONFIG_SHELL}" "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e s/^X//' +sed_quote_subst='s/\([\\"\\`$\\\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([\\"\\`\\\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# The name of this program. +progname=`$echo "X$0" | $Xsed -e 's%^.*/%%'` + +# Constants: +PROGRAM=ltconfig +PACKAGE=libtool +VERSION=1.3.5 +TIMESTAMP=" (1.385.2.206 2000/05/27 11:12:27)" +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +rm="rm -f" + +help="Try \`$progname --help' for more information." + +# Global variables: +default_ofile=libtool +can_build_shared=yes +enable_shared=yes +# All known linkers require a `.a' archive for static linking (except M$VC, +# which needs '.lib'). +enable_static=yes +enable_fast_install=yes +enable_dlopen=unknown +enable_win32_dll=no +ltmain= +silent= +srcdir= +ac_config_guess= +ac_config_sub= +host= +nonopt= +ofile="$default_ofile" +verify_host=yes +with_gcc=no +with_gnu_ld=no +need_locks=yes +ac_ext=c +objext=o +libext=a +exeext= +cache_file= + +old_AR="$AR" +old_CC="$CC" +old_CFLAGS="$CFLAGS" +old_CPPFLAGS="$CPPFLAGS" +old_LDFLAGS="$LDFLAGS" +old_LD="$LD" +old_LN_S="$LN_S" +old_LIBS="$LIBS" +old_NM="$NM" +old_RANLIB="$RANLIB" +old_DLLTOOL="$DLLTOOL" +old_OBJDUMP="$OBJDUMP" +old_AS="$AS" + +# Parse the command line options. +args= +prev= +for option +do + case "$option" in + -*=*) optarg=`echo "$option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + eval "$prev=\$option" + prev= + continue + fi + + case "$option" in + --help) cat <&2 + echo "$help" 1>&2 + exit 1 + ;; + + *) + if test -z "$ltmain"; then + ltmain="$option" + elif test -z "$host"; then +# This generates an unnecessary warning for sparc-sun-solaris4.1.3_U1 +# if test -n "`echo $option| sed 's/[-a-z0-9.]//g'`"; then +# echo "$progname: warning \`$option' is not a valid host type" 1>&2 +# fi + host="$option" + else + echo "$progname: too many arguments" 1>&2 + echo "$help" 1>&2 + exit 1 + fi ;; + esac +done + +if test -z "$ltmain"; then + echo "$progname: you must specify a LTMAIN file" 1>&2 + echo "$help" 1>&2 + exit 1 +fi + +if test ! -f "$ltmain"; then + echo "$progname: \`$ltmain' does not exist" 1>&2 + echo "$help" 1>&2 + exit 1 +fi + +# Quote any args containing shell metacharacters. +ltconfig_args= +for arg +do + case "$arg" in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ltconfig_args="$ltconfig_args '$arg'" ;; + *) ltconfig_args="$ltconfig_args $arg" ;; + esac +done + +# A relevant subset of AC_INIT. + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 5 compiler messages saved in config.log +# 6 checking for... messages and results +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>>./config.log + +# NLS nuisances. +# Only set LANG and LC_ALL to C if already set. +# These must not be set unconditionally because not all systems understand +# e.g. LANG=C (notably SCO). +if test "X${LC_ALL+set}" = Xset; then LC_ALL=C; export LC_ALL; fi +if test "X${LANG+set}" = Xset; then LANG=C; export LANG; fi + +if test -n "$cache_file" && test -r "$cache_file"; then + echo "loading cache $cache_file within ltconfig" + . $cache_file +fi + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + +if test -z "$srcdir"; then + # Assume the source directory is the same one as the path to LTMAIN. + srcdir=`$echo "X$ltmain" | $Xsed -e 's%/[^/]*$%%'` + test "$srcdir" = "$ltmain" && srcdir=. +fi + +trap "$rm conftest*; exit 1" 1 2 15 +if test "$verify_host" = yes; then + # Check for config.guess and config.sub. + ac_aux_dir= + for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/config.guess; then + ac_aux_dir=$ac_dir + break + fi + done + if test -z "$ac_aux_dir"; then + echo "$progname: cannot find config.guess in $srcdir $srcdir/.. $srcdir/../.." 1>&2 + echo "$help" 1>&2 + exit 1 + fi + ac_config_guess=$ac_aux_dir/config.guess + ac_config_sub=$ac_aux_dir/config.sub + + # Make sure we can run config.sub. + if $SHELL $ac_config_sub sun4 >/dev/null 2>&1; then : + else + echo "$progname: cannot run $ac_config_sub" 1>&2 + echo "$help" 1>&2 + exit 1 + fi + + echo $ac_n "checking host system type""... $ac_c" 1>&6 + + host_alias=$host + case "$host_alias" in + "") + if host_alias=`$SHELL $ac_config_guess`; then : + else + echo "$progname: cannot guess host type; you must specify one" 1>&2 + echo "$help" 1>&2 + exit 1 + fi ;; + esac + host=`$SHELL $ac_config_sub $host_alias` + echo "$ac_t$host" 1>&6 + + # Make sure the host verified. + test -z "$host" && exit 1 + +elif test -z "$host"; then + echo "$progname: you must specify a host type if you use \`--no-verify'" 1>&2 + echo "$help" 1>&2 + exit 1 +else + host_alias=$host +fi + +# Transform linux* to *-*-linux-gnu*, to support old configure scripts. +case "$host_os" in +linux-gnu*) ;; +linux*) host=`echo $host | sed 's/^\(.*-.*-linux\)\(.*\)$/\1-gnu\2/'` +esac + +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + +case "$host_os" in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR cru $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +# Set a sane default for `AR'. +test -z "$AR" && AR=ar + +# Set a sane default for `OBJDUMP'. +test -z "$OBJDUMP" && OBJDUMP=objdump + +# If RANLIB is not set, then run the test. +if test "${RANLIB+set}" != "set"; then + result=no + + echo $ac_n "checking for ranlib... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/ranlib || test -f $dir/ranlib$ac_exeext; then + RANLIB="ranlib" + result="ranlib" + break + fi + done + IFS="$save_ifs" + + echo "$ac_t$result" 1>&6 +fi + +if test -n "$RANLIB"; then + old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" + old_postinstall_cmds="\$RANLIB \$oldlib~$old_postinstall_cmds" +fi + +# Set sane defaults for `DLLTOOL', `OBJDUMP', and `AS', used on cygwin. +test -z "$DLLTOOL" && DLLTOOL=dlltool +test -z "$OBJDUMP" && OBJDUMP=objdump +test -z "$AS" && AS=as + +# Check to see if we are using GCC. +if test "$with_gcc" != yes || test -z "$CC"; then + # If CC is not set, then try to find GCC or a usable CC. + if test -z "$CC"; then + echo $ac_n "checking for gcc... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/gcc || test -f $dir/gcc$ac_exeext; then + CC="gcc" + break + fi + done + IFS="$save_ifs" + + if test -n "$CC"; then + echo "$ac_t$CC" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + fi + + # Not "gcc", so try "cc", rejecting "/usr/ucb/cc". + if test -z "$CC"; then + echo $ac_n "checking for cc... $ac_c" 1>&6 + IFS="${IFS= }"; save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + cc_rejected=no + for dir in $PATH; do + test -z "$dir" && dir=. + if test -f $dir/cc || test -f $dir/cc$ac_exeext; then + if test "$dir/cc" = "/usr/ucb/cc"; then + cc_rejected=yes + continue + fi + CC="cc" + break + fi + done + IFS="$save_ifs" + if test $cc_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same name, so the bogon will be chosen + # first if we set CC to just the name; use the full file name. + shift + set dummy "$dir/cc" "$@" + shift + CC="$@" + fi + fi + + if test -n "$CC"; then + echo "$ac_t$CC" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + + if test -z "$CC"; then + echo "$progname: error: no acceptable cc found in \$PATH" 1>&2 + exit 1 + fi + fi + + # Now see if the compiler is really GCC. + with_gcc=no + echo $ac_n "checking whether we are using GNU C... $ac_c" 1>&6 + echo "$progname:581: checking whether we are using GNU C" >&5 + + $rm conftest.c + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + with_gcc=yes + fi + $rm conftest.c + echo "$ac_t$with_gcc" 1>&6 +fi + +# Allow CC to be a program name with arguments. +set dummy $CC +compiler="$2" + +echo $ac_n "checking for object suffix... $ac_c" 1>&6 +$rm conftest* +echo 'int i = 1;' > conftest.c +echo "$progname:603: checking for object suffix" >& 5 +if { (eval echo $progname:604: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; }; then + # Append any warnings to the config.log. + cat conftest.err 1>&5 + + for ac_file in conftest.*; do + case $ac_file in + *.c) ;; + *) objext=`echo $ac_file | sed -e s/conftest.//` ;; + esac + done +else + cat conftest.err 1>&5 + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 +fi +$rm conftest* +echo "$ac_t$objext" 1>&6 + +echo $ac_n "checking for executable suffix... $ac_c" 1>&6 +if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_exeext="no" + $rm conftest* + echo 'main () { return 0; }' > conftest.c + echo "$progname:629: checking for executable suffix" >& 5 + if { (eval echo $progname:630: \"$ac_link\") 1>&5; (eval $ac_link) 2>conftest.err; }; then + # Append any warnings to the config.log. + cat conftest.err 1>&5 + + for ac_file in conftest.*; do + case $ac_file in + *.c | *.err | *.$objext ) ;; + *) ac_cv_exeext=.`echo $ac_file | sed -e s/conftest.//` ;; + esac + done + else + cat conftest.err 1>&5 + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 + fi + $rm conftest* +fi +if test "X$ac_cv_exeext" = Xno; then + exeext="" +else + exeext="$ac_cv_exeext" +fi +echo "$ac_t$ac_cv_exeext" 1>&6 + +echo $ac_n "checking for $compiler option to produce PIC... $ac_c" 1>&6 +pic_flag= +special_shlib_compile_flags= +wl= +link_static_flag= +no_builtin_flag= + +if test "$with_gcc" = yes; then + wl='-Wl,' + link_static_flag='-static' + + case "$host_os" in + beos* | irix5* | irix6* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + aix*) + # Below there is a dirty hack to force normal static linking with -ldl + # The problem is because libdl dynamically linked with both libc and + # libC (AIX C++ library), which obviously doesn't included in libraries + # list by gcc. This cause undefined symbols with -static flags. + # This hack allows C programs to be linked with "-static -ldl", but + # we not sure about C++ programs. + link_static_flag="$link_static_flag ${wl}-lC" + ;; + cygwin* | mingw* | os2*) + # We can build DLLs from non-PIC. + ;; + amigaos*) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + pic_flag='-m68020 -resident32 -malways-restore-a4' + ;; + sysv4*MP*) + if test -d /usr/nec; then + pic_flag=-Kconform_pic + fi + ;; + *) + pic_flag='-fPIC' + ;; + esac +else + # PORTME Check for PIC flags for the system compiler. + case "$host_os" in + aix3* | aix4*) + # All AIX code is PIC. + link_static_flag='-bnso -bI:/lib/syscalls.exp' + ;; + + hpux9* | hpux10* | hpux11*) + # Is there a better link_static_flag that works with the bundled CC? + wl='-Wl,' + link_static_flag="${wl}-a ${wl}archive" + pic_flag='+Z' + ;; + + irix5* | irix6*) + wl='-Wl,' + link_static_flag='-non_shared' + # PIC (with -KPIC) is the default. + ;; + + cygwin* | mingw* | os2*) + # We can build DLLs from non-PIC. + ;; + + osf3* | osf4* | osf5*) + # All OSF/1 code is PIC. + wl='-Wl,' + link_static_flag='-non_shared' + ;; + + sco3.2v5*) + pic_flag='-Kpic' + link_static_flag='-dn' + special_shlib_compile_flags='-belf' + ;; + + solaris*) + pic_flag='-KPIC' + link_static_flag='-Bstatic' + wl='-Wl,' + ;; + + sunos4*) + pic_flag='-PIC' + link_static_flag='-Bstatic' + wl='-Qoption ld ' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + pic_flag='-KPIC' + link_static_flag='-Bstatic' + wl='-Wl,' + ;; + + uts4*) + pic_flag='-pic' + link_static_flag='-Bstatic' + ;; + sysv4*MP*) + if test -d /usr/nec ;then + pic_flag='-Kconform_pic' + link_static_flag='-Bstatic' + fi + ;; + *) + can_build_shared=no + ;; + esac +fi + +if test -n "$pic_flag"; then + echo "$ac_t$pic_flag" 1>&6 + + # Check to make sure the pic_flag actually works. + echo $ac_n "checking if $compiler PIC flag $pic_flag works... $ac_c" 1>&6 + $rm conftest* + echo "int some_variable = 0;" > conftest.c + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $pic_flag -DPIC" + echo "$progname:776: checking if $compiler PIC flag $pic_flag works" >&5 + if { (eval echo $progname:777: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.$objext; then + # Append any warnings to the config.log. + cat conftest.err 1>&5 + + case "$host_os" in + hpux9* | hpux10* | hpux11*) + # On HP-UX, both CC and GCC only warn that PIC is supported... then they + # create non-PIC objects. So, if there were any warnings, we assume that + # PIC is not supported. + if test -s conftest.err; then + echo "$ac_t"no 1>&6 + can_build_shared=no + pic_flag= + else + echo "$ac_t"yes 1>&6 + pic_flag=" $pic_flag" + fi + ;; + *) + echo "$ac_t"yes 1>&6 + pic_flag=" $pic_flag" + ;; + esac + else + # Append any errors to the config.log. + cat conftest.err 1>&5 + can_build_shared=no + pic_flag= + echo "$ac_t"no 1>&6 + fi + CFLAGS="$save_CFLAGS" + $rm conftest* +else + echo "$ac_t"none 1>&6 +fi + +# Check to see if options -o and -c are simultaneously supported by compiler +echo $ac_n "checking if $compiler supports -c -o file.o... $ac_c" 1>&6 +$rm -r conftest 2>/dev/null +mkdir conftest +cd conftest +$rm conftest* +echo "int some_variable = 0;" > conftest.c +mkdir out +# According to Tom Tromey, Ian Lance Taylor reported there are C compilers +# that will create temporary files in the current directory regardless of +# the output directory. Thus, making CWD read-only will cause this test +# to fail, enabling locking or at least warning the user not to do parallel +# builds. +chmod -w . +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -o out/conftest2.o" +echo "$progname:829: checking if $compiler supports -c -o file.o" >&5 +if { (eval echo $progname:830: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.o; then + + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s out/conftest.err; then + echo "$ac_t"no 1>&6 + compiler_c_o=no + else + echo "$ac_t"yes 1>&6 + compiler_c_o=yes + fi +else + # Append any errors to the config.log. + cat out/conftest.err 1>&5 + compiler_c_o=no + echo "$ac_t"no 1>&6 +fi +CFLAGS="$save_CFLAGS" +chmod u+w . +$rm conftest* out/* +rmdir out +cd .. +rmdir conftest +$rm -r conftest 2>/dev/null + +if test x"$compiler_c_o" = x"yes"; then + # Check to see if we can write to a .lo + echo $ac_n "checking if $compiler supports -c -o file.lo... $ac_c" 1>&6 + $rm conftest* + echo "int some_variable = 0;" > conftest.c + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -c -o conftest.lo" + echo "$progname:862: checking if $compiler supports -c -o file.lo" >&5 +if { (eval echo $progname:863: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.lo; then + + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + echo "$ac_t"no 1>&6 + compiler_o_lo=no + else + echo "$ac_t"yes 1>&6 + compiler_o_lo=yes + fi + else + # Append any errors to the config.log. + cat conftest.err 1>&5 + compiler_o_lo=no + echo "$ac_t"no 1>&6 + fi + CFLAGS="$save_CFLAGS" + $rm conftest* +else + compiler_o_lo=no +fi + +# Check to see if we can do hard links to lock some files if needed +hard_links="nottested" +if test "$compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + echo $ac_n "checking if we can lock with hard links... $ac_c" 1>&6 + hard_links=yes + $rm conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + echo "$ac_t$hard_links" 1>&6 + $rm conftest* + if test "$hard_links" = no; then + echo "*** WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2 + need_locks=warn + fi +else + need_locks=no +fi + +if test "$with_gcc" = yes; then + # Check to see if options -fno-rtti -fno-exceptions are supported by compiler + echo $ac_n "checking if $compiler supports -fno-rtti -fno-exceptions ... $ac_c" 1>&6 + $rm conftest* + echo "int some_variable = 0;" > conftest.c + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fno-rtti -fno-exceptions -c conftest.c" + echo "$progname:914: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 + if { (eval echo $progname:915: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>conftest.err; } && test -s conftest.o; then + + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + echo "$ac_t"no 1>&6 + compiler_rtti_exceptions=no + else + echo "$ac_t"yes 1>&6 + compiler_rtti_exceptions=yes + fi + else + # Append any errors to the config.log. + cat conftest.err 1>&5 + compiler_rtti_exceptions=no + echo "$ac_t"no 1>&6 + fi + CFLAGS="$save_CFLAGS" + $rm conftest* + + if test "$compiler_rtti_exceptions" = "yes"; then + no_builtin_flag=' -fno-builtin -fno-rtti -fno-exceptions' + else + no_builtin_flag=' -fno-builtin' + fi + +fi + +# Check for any special shared library compilation flags. +if test -n "$special_shlib_compile_flags"; then + echo "$progname: warning: \`$CC' requires \`$special_shlib_compile_flags' to build shared libraries" 1>&2 + if echo "$old_CC $old_CFLAGS " | egrep -e "[ ]$special_shlib_compile_flags[ ]" >/dev/null; then : + else + echo "$progname: add \`$special_shlib_compile_flags' to the CC or CFLAGS env variable and reconfigure" 1>&2 + can_build_shared=no + fi +fi + +echo $ac_n "checking if $compiler static flag $link_static_flag works... $ac_c" 1>&6 +$rm conftest* +echo 'main(){return(0);}' > conftest.c +save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS $link_static_flag" +echo "$progname:958: checking if $compiler static flag $link_static_flag works" >&5 +if { (eval echo $progname:959: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + echo "$ac_t$link_static_flag" 1>&6 +else + echo "$ac_t"none 1>&6 + link_static_flag= +fi +LDFLAGS="$save_LDFLAGS" +$rm conftest* + +if test -z "$LN_S"; then + # Check to see if we can use ln -s, or we need hard links. + echo $ac_n "checking whether ln -s works... $ac_c" 1>&6 + $rm conftest.dat + if ln -s X conftest.dat 2>/dev/null; then + $rm conftest.dat + LN_S="ln -s" + else + LN_S=ln + fi + if test "$LN_S" = "ln -s"; then + echo "$ac_t"yes 1>&6 + else + echo "$ac_t"no 1>&6 + fi +fi + +# Make sure LD is an absolute path. +if test -z "$LD"; then + ac_prog=ld + if test "$with_gcc" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + echo $ac_n "checking for ld used by GCC... $ac_c" 1>&6 + echo "$progname:991: checking for ld used by GCC" >&5 + ac_prog=`($CC -print-prog-name=ld) 2>&5` + case "$ac_prog" in + # Accept absolute paths. + [\\/]* | [A-Za-z]:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we are not using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac + elif test "$with_gnu_ld" = yes; then + echo $ac_n "checking for GNU ld... $ac_c" 1>&6 + echo "$progname:1015: checking for GNU ld" >&5 + else + echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 + echo "$progname:1018: checking for non-GNU ld" >&5 + fi + + if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + if "$LD" -v 2>&1 < /dev/null | egrep '(GNU|with BFD)' > /dev/null; then + test "$with_gnu_ld" != no && break + else + test "$with_gnu_ld" != yes && break + fi + fi + done + IFS="$ac_save_ifs" + fi + + if test -n "$LD"; then + echo "$ac_t$LD" 1>&6 + else + echo "$ac_t"no 1>&6 + fi + + if test -z "$LD"; then + echo "$progname: error: no acceptable ld found in \$PATH" 1>&2 + exit 1 + fi +fi + +# Check to see if it really is or is not GNU ld. +echo $ac_n "checking if the linker ($LD) is GNU ld... $ac_c" 1>&6 +# I'd rather use --version here, but apparently some GNU ld's only accept -v. +if $LD -v 2>&1 &5; then + with_gnu_ld=yes +else + with_gnu_ld=no +fi +echo "$ac_t$with_gnu_ld" 1>&6 + +# See if the linker supports building shared libraries. +echo $ac_n "checking whether the linker ($LD) supports shared libraries... $ac_c" 1>&6 + +allow_undefined_flag= +no_undefined_flag= +need_lib_prefix=unknown +need_version=unknown +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +archive_cmds= +archive_expsym_cmds= +old_archive_from_new_cmds= +export_dynamic_flag_spec= +whole_archive_flag_spec= +thread_safe_flag_spec= +hardcode_libdir_flag_spec= +hardcode_libdir_separator= +hardcode_direct=no +hardcode_minus_L=no +hardcode_shlibpath_var=unsupported +runpath_var= +always_export_symbols=no +export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | sed '\''s/.* //'\'' | sort | uniq > $export_symbols' +# include_expsyms should be a list of space-separated symbols to be *always* +# included in the symbol list +include_expsyms= +# exclude_expsyms can be an egrep regular expression of symbols to exclude +# it will be wrapped by ` (' and `)$', so one must not match beginning or +# end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', +# as well as any symbol that contains `d'. +exclude_expsyms="_GLOBAL_OFFSET_TABLE_" +# Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out +# platforms (ab)use it in PIC code, but their linkers get confused if +# the symbol is explicitly referenced. Since portable code cannot +# rely on this symbol name, it's probably fine to never include it in +# preloaded symbol tables. + +case "$host_os" in +cygwin* | mingw*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$with_gcc" != yes; then + with_gnu_ld=no + fi + ;; + +esac + +ld_shlibs=yes +if test "$with_gnu_ld" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # See if GNU ld supports shared libraries. + case "$host_os" in + aix3* | aix4*) + # On AIX, the GNU linker is very broken + ld_shlibs=no + cat <&2 + +*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to modify your PATH +*** so that a non-GNU linker is found, and then restart. + +EOF + ;; + + amigaos*) + archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + + # Samuel A. Falvo II reports + # that the semantics of dynamic libraries on AmigaOS, at least up + # to version 4, is to share data among multiple programs linked + # with the same dynamic library. Since this doesn't match the + # behavior of shared libraries on other platforms, we can use + # them. + ld_shlibs=no + ;; + + beos*) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw*) + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + allow_undefined_flag=unsupported + always_export_symbols=yes + + # Extract the symbol export list from an `--export-all' def file, + # then regenerate the def file from the symbol export list, so that + # the compiled dll only exports the symbol export list. + # Be careful not to strip the DATA tag left by newer dlltools. + export_symbols_cmds='test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~ + test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~ + $DLLTOOL --export-all --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --output-def $objdir/$soname-def $objdir/$soname-ltdll.$objext $libobjs $convenience~ + sed -e "1,/EXPORTS/d" -e "s/ @ [0-9]*//" -e "s/ *;.*$//" < $objdir/$soname-def > $export_symbols' + + # If DATA tags from a recent dlltool are present, honour them! + archive_expsym_cmds='echo EXPORTS > $objdir/$soname-def~ + _lt_hint=1; + cat $export_symbols | while read symbol; do + set dummy \$symbol; + case \$# in + 2) echo " \$2 @ \$_lt_hint ; " >> $objdir/$soname-def;; + *) echo " \$2 @ \$_lt_hint \$3 ; " >> $objdir/$soname-def;; + esac; + _lt_hint=`expr 1 + \$_lt_hint`; + done~ + test -f $objdir/$soname-ltdll.c || sed -e "/^# \/\* ltdll\.c starts here \*\//,/^# \/\* ltdll.c ends here \*\// { s/^# //; p; }" -e d < $0 > $objdir/$soname-ltdll.c~ + test -f $objdir/$soname-ltdll.$objext || (cd $objdir && $CC -c $soname-ltdll.c)~ + $CC -Wl,--base-file,$objdir/$soname-base -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~ + $CC -Wl,--base-file,$objdir/$soname-base $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts~ + $DLLTOOL --as=$AS --dllname $soname --exclude-symbols DllMain@12,_cygwin_dll_entry@12,_cygwin_noncygwin_dll_entry@12 --def $objdir/$soname-def --base-file $objdir/$soname-base --output-exp $objdir/$soname-exp~ + $CC $objdir/$soname-exp -Wl,--dll -nostartfiles -Wl,-e,__cygwin_dll_entry@12 -o $lib $objdir/$soname-ltdll.$objext $libobjs $deplibs $linkopts' + + old_archive_from_new_cmds='$DLLTOOL --as=$AS --dllname $soname --def $objdir/$soname-def --output-lib $objdir/$libname.a' + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + archive_cmds='$LD -Bshareable $libobjs $deplibs $linkopts -o $lib' + # can we support soname and/or expsyms with a.out? -oliva + fi + ;; + + solaris* | sysv5*) + if $LD -v 2>&1 | egrep 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +EOF + elif $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linkopts' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = yes; then + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + case $host_os in + cygwin* | mingw*) + # dlltool doesn't understand --whole-archive et. al. + whole_archive_flag_spec= + ;; + *) + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | egrep 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + ;; + esac + fi +else + # PORTME fill in a description of your system's linker (not GNU ld) + case "$host_os" in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $objdir/$soname $libobjs $deplibs $linkopts -bE:$export_symbols -T512 -H512 -bM:SRE~$AR cru $lib $objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$with_gcc" = yes && test -z "$link_static_flag"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix4*) + hardcode_libdir_flag_spec='${wl}-b ${wl}nolibpath ${wl}-b ${wl}libpath:$libdir:/usr/lib:/lib' + hardcode_libdir_separator=':' + if test "$with_gcc" = yes; then + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && \ + strings "$collect2name" | grep resolve_lib_name >/dev/null + then + # We have reworked collect2 + hardcode_direct=yes + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + shared_flag='-shared' + else + shared_flag='${wl}-bM:SRE' + hardcode_direct=yes + fi + allow_undefined_flag=' ${wl}-berok' + archive_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bexpall ${wl}-bnoentry${allow_undefined_flag}' + archive_expsym_cmds="\$CC $shared_flag"' -o $objdir/$soname $libobjs $deplibs $linkopts ${wl}-bE:$export_symbols ${wl}-bnoentry${allow_undefined_flag}' + case "$host_os" in aix4.[01]|aix4.[01].*) + # According to Greg Wooledge, -bexpall is only supported from AIX 4.2 on + always_export_symbols=yes ;; + esac + ;; + + amigaos*) + archive_cmds='$rm $objdir/a2ixlibrary.data~$echo "#define NAME $libname" > $objdir/a2ixlibrary.data~$echo "#define LIBRARY_ID 1" >> $objdir/a2ixlibrary.data~$echo "#define VERSION $major" >> $objdir/a2ixlibrary.data~$echo "#define REVISION $revision" >> $objdir/a2ixlibrary.data~$AR cru $lib $libobjs~$RANLIB $lib~(cd $objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + # see comment about different semantics on the GNU ld section + ld_shlibs=no + ;; + + cygwin* | mingw*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $linkopts `echo "$deplibs" | sed -e '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib /OUT:$oldlib$oldobjs' + fix_srcfile_path='`cygpath -w $srcfile`' + ;; + + freebsd1*) + ld_shlibs=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd*) + archive_cmds='$CC -shared -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9* | hpux10* | hpux11*) + case "$host_os" in + hpux9*) archive_cmds='$rm $objdir/$soname~$LD -b +b $install_libdir -o $objdir/$soname $libobjs $deplibs $linkopts~test $objdir/$soname = $lib || mv $objdir/$soname $lib' ;; + *) archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linkopts' ;; + esac + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_minus_L=yes # Not in the search PATH, but as the default + # location of the library. + export_dynamic_flag_spec='${wl}-E' + ;; + + irix5* | irix6*) + if test "$with_gcc" = yes; then + archive_cmds='$CC -shared $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + archive_cmds='$LD -shared $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linkopts' # ELF + fi + hardcode_libdir_flag_spec='${wl}-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + openbsd*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$echo "LIBRARY $libname INITINSTANCE" > $objdir/$libname.def~$echo "DESCRIPTION \"$libname\"" >> $objdir/$libname.def~$echo DATA >> $objdir/$libname.def~$echo " SINGLE NONSHARED" >> $objdir/$libname.def~$echo EXPORTS >> $objdir/$libname.def~emxexp $libobjs >> $objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $linkopts $objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $objdir/$libname.a $objdir/$libname.def' + ;; + + osf3*) + if test "$with_gcc" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $linkopts ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linkopts -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # As osf3* with the addition of the -msym flag + if test "$with_gcc" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $linkopts ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$LD -shared${allow_undefined_flag} $libobjs $deplibs $linkopts -msym -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${objdir}/so_locations -o $lib' + fi + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + rhapsody*) + archive_cmds='$CC -bundle -undefined suppress -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flags_spec='-L$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + sco3.2v5*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ;; + + solaris*) + no_undefined_flag=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linkopts' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linkopts~$rm $lib.exp' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case "$host_os" in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $linkopts' + else + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + fi + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv5*) + no_undefined_flag=' -z text' + # $CC -shared without GNU ld will not create a library from C++ + # object files and a static libstdc++, better avoid it by now + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linkopts' + archive_expsym_cmds='$echo "{ global:" > $lib.exp~cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $lib.exp~$echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linkopts~$rm $lib.exp' + hardcode_libdir_flag_spec= + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4.2uw2*) + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linkopts' + hardcode_direct=yes + hardcode_minus_L=no + hardcode_shlibpath_var=no + hardcode_runpath_var=yes + runpath_var=LD_RUN_PATH + ;; + + unixware7*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts' + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac +fi +echo "$ac_t$ld_shlibs" 1>&6 +test "$ld_shlibs" = no && can_build_shared=no + +if test -z "$NM"; then + echo $ac_n "checking for BSD-compatible nm... $ac_c" 1>&6 + case "$NM" in + [\\/]* | [A-Za-z]:[\\/]*) ;; # Let the user override the test with a path. + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR}" + for ac_dir in $PATH /usr/ucb /usr/ccs/bin /bin; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + NM="$ac_dir/nm -B" + break + elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then + NM="$ac_dir/nm -p" + break + else + NM=${NM="$ac_dir/nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + fi + fi + done + IFS="$ac_save_ifs" + test -z "$NM" && NM=nm + ;; + esac + echo "$ac_t$NM" 1>&6 +fi + +# Check for command to grab the raw symbol name followed by C symbol from nm. +echo $ac_n "checking command to parse $NM output... $ac_c" 1>&6 + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Transform the above into a raw symbol and a C symbol. +symxfrm='\1 \2\3 \3' + +# Transform an extracted symbol line into a proper C declaration +global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" + +# Define system-specific variables. +case "$host_os" in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw*) + symcode='[ABCDGISTW]' + ;; +hpux*) # Its linker distinguishes data from code symbols + global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^. .* \(.*\)$/extern char \1;/p'" + ;; +irix*) + symcode='[BCDEGRST]' + ;; +solaris*) + symcode='[BDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then + symcode='[ABCDGISTW]' +fi + +# Try without a prefix undercore, then with it. +for ac_symprfx in "" "_"; do + + # Write the raw and C identifiers. + global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode\)[ ][ ]*\($ac_symprfx\)$sympat$/$symxfrm/p'" + + # Check to see that the pipe works correctly. + pipe_works=no + $rm conftest* + cat > conftest.c <&5 + if { (eval echo $progname:1654: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; } && test -s conftest.$objext; then + # Now try to grab the symbols. + nlist=conftest.nm + if { echo "$progname:1657: eval \"$NM conftest.$objext | $global_symbol_pipe > $nlist\"" >&5; eval "$NM conftest.$objext | $global_symbol_pipe > $nlist 2>&5"; } && test -s "$nlist"; then + + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if egrep ' nm_test_var$' "$nlist" >/dev/null; then + if egrep ' nm_test_func$' "$nlist" >/dev/null; then + cat < conftest.c +#ifdef __cplusplus +extern "C" { +#endif + +EOF + # Now generate the symbol file. + eval "$global_symbol_to_cdecl"' < "$nlist" >> conftest.c' + + cat <> conftest.c +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[] = +{ +EOF + sed 's/^. \(.*\) \(.*\)$/ {"\2", (lt_ptr_t) \&\2},/' < "$nlist" >> conftest.c + cat <<\EOF >> conftest.c + {0, (lt_ptr_t) 0} +}; + +#ifdef __cplusplus +} +#endif +EOF + # Now try linking the two files. + mv conftest.$objext conftstm.$objext + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="conftstm.$objext" + CFLAGS="$CFLAGS$no_builtin_flag" + if { (eval echo $progname:1709: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + pipe_works=yes + else + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 + fi + LIBS="$save_LIBS" + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.c >&5 + fi + $rm conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + global_symbol_pipe= + fi +done +if test "$pipe_works" = yes; then + echo "${ac_t}ok" 1>&6 +else + echo "${ac_t}failed" 1>&6 +fi + +if test -z "$global_symbol_pipe"; then + global_symbol_to_cdecl= +fi + +# Check hardcoding attributes. +echo $ac_n "checking how to hardcode library paths into programs... $ac_c" 1>&6 +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || \ + test -n "$runpath_var"; then + + # We can hardcode non-existant directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$hardcode_shlibpath_var" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +echo "$ac_t$hardcode_action" 1>&6 + + +reload_flag= +reload_cmds='$LD$reload_flag -o $output$reload_objs' +echo $ac_n "checking for $LD option to reload object files... $ac_c" 1>&6 +# PORTME Some linkers may need a different reload flag. +reload_flag='-r' +echo "$ac_t$reload_flag" 1>&6 +test -n "$reload_flag" && reload_flag=" $reload_flag" + +# PORTME Fill in your ld.so characteristics +library_names_spec= +libname_spec='lib$name' +soname_spec= +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +file_magic_cmd= +file_magic_test_file= +deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [regex]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given egrep regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. +echo $ac_n "checking dynamic linker characteristics... $ac_c" 1>&6 +case "$host_os" in +aix3*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}.so$major' + ;; + +aix4*) + version_type=linux + # AIX has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + # We preserve .a as extension for shared libraries though AIX4.2 + # and later linker supports .so + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.a' + shlibpath_var=LIBPATH + deplibs_check_method=pass_all + ;; + +amigaos*) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$echo "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $rm /sys/libs/${libname}_ixlibrary.a; $show "(cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a)"; (cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a) || exit 1; done' + ;; + +beos*) + library_names_spec='${libname}.so' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + deplibs_check_method=pass_all + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + +bsdi4*) + version_type=linux + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + file_magic_cmd=/usr/bin/file + file_magic_test_file=/shlib/libc.so + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + export_dynamic_flag_spec=-rdynamic + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw*) + version_type=windows + need_version=no + need_lib_prefix=no + if test "$with_gcc" = yes; then + library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.a' + else + library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll $libname.lib' + fi + dynamic_linker='Win32 ld.exe' + deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + file_magic_cmd='${OBJDUMP} -f' + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + +freebsd1*) + dynamic_linker=no + ;; + +freebsd*) + objformat=`test -x /usr/bin/objformat && /usr/bin/objformat || echo aout` + version_type=freebsd-$objformat + case "$version_type" in + freebsd-elf*) + deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB shared object' + file_magic_cmd=/usr/bin/file + file_magic_test_file=`echo /usr/lib/libc.so*` + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + deplibs_check_method=unknown + library_names_spec='${libname}${release}.so$versuffix $libname.so$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case "$host_os" in + freebsd2* | freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + ;; + *) # from 3.2 on + shlibpath_overrides_runpath=no + ;; + esac + ;; + +gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so${major} ${libname}.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + dynamic_linker="$host_os dld.sl" + version_type=sunos + need_lib_prefix=no + need_version=no + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}.sl$versuffix ${libname}${release}.sl$major $libname.sl' + soname_spec='${libname}${release}.sl$major' + # HP-UX runs *really* slowly unless shared libraries are mode 555. + postinstall_cmds='chmod 555 $lib' + case "$host_os" in + hpux10.20*) + # TODO: Does this work for hpux-11 too? + deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + file_magic_cmd=/usr/bin/file + file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +irix5* | irix6*) + version_type=irix + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}.so.$major' + library_names_spec='${libname}${release}.so.$versuffix ${libname}${release}.so.$major ${libname}${release}.so $libname.so' + case "$host_os" in + irix5*) + libsuff= shlibsuff= + # this will be overridden with pass_all, but let us keep it just in case + deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" + ;; + *) + case "$LD" in # libtool.m4 will add one of these switches to LD + *-32|*"-32 ") libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 ") libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + file_magic_cmd=/usr/bin/file + file_magic_test_file=`echo /lib${libsuff}/libc.so*` + deplibs_check_method='pass_all' + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux-gnuoldld* | linux-gnuaout* | linux-gnucoff*) + dynamic_linker=no + ;; + +# This must be Linux ELF. +linux-gnu*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + deplibs_check_method=pass_all + + if test -f /lib/ld.so.1; then + dynamic_linker='GNU ld.so' + else + # Only the GNU ld.so supports shared libraries on MkLinux. + case "$host_cpu" in + powerpc*) dynamic_linker=no ;; + *) dynamic_linker='Linux ld.so' ;; + esac + fi + ;; + +netbsd*) + version_type=sunos + if echo __ELF__ | $CC -E - | grep __ELF__ >/dev/null; then + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so ${libname}.so' + soname_spec='${libname}${release}.so$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + ;; + +openbsd*) + version_type=sunos + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + need_version=no + fi + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + ;; + +os2*) + libname_spec='$name' + need_lib_prefix=no + library_names_spec='$libname.dll $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_version=no + soname_spec='${libname}${release}.so' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + shlibpath_var=LD_LIBRARY_PATH + # this will be overridden with pass_all, but let us keep it just in case + deplibs_check_method='file_magic COFF format alpha shared library' + file_magic_cmd=/usr/bin/file + file_magic_test_file=/shlib/libc.so + deplibs_check_method='pass_all' + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rhapsody*) + version_type=sunos + library_names_spec='${libname}.so' + soname_spec='${libname}.so' + shlibpath_var=DYLD_LIBRARY_PATH + deplibs_check_method=pass_all + ;; + +sco3.2v5*) + version_type=osf + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + shlibpath_var=LD_LIBRARY_PATH + ;; + +solaris*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + deplibs_check_method="file_magic ELF [0-9][0-9]-bit [LM]SB dynamic lib" + file_magic_cmd=/usr/bin/file + file_magic_test_file=/lib/libc.so + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}.so$versuffix ${libname}.so$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + case "$host_vendor" in + sequent) + file_magic_cmd='/bin/file' + deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + ncr) + deplibs_check_method='pass_all' + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + file_magic_cmd=/usr/bin/file + file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + esac + ;; + +uts4*) + version_type=linux + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +dgux*) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' + soname_spec='${libname}${release}.so$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux + library_names_spec='$libname.so.$versuffix $libname.so.$major $libname.so' + soname_spec='$libname.so.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +*) + dynamic_linker=no + ;; +esac +echo "$ac_t$dynamic_linker" 1>&6 +test "$dynamic_linker" = no && can_build_shared=no + +# Report the final consequences. +echo "checking if libtool supports shared libraries... $can_build_shared" 1>&6 + +# Only try to build win32 dlls if AC_LIBTOOL_WIN32_DLL was used in +# configure.in, otherwise build static only libraries. +case "$host_os" in +cygwin* | mingw* | os2*) + if test x$can_build_shared = xyes; then + test x$enable_win32_dll = xno && can_build_shared=no + echo "checking if package supports dlls... $can_build_shared" 1>&6 + fi +;; +esac + +if test -n "$file_magic_test_file" && test -n "$file_magic_cmd"; then + case "$deplibs_check_method" in + "file_magic "*) + file_magic_regex="`expr \"$deplibs_check_method\" : \"file_magic \(.*\)\"`" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + egrep "$file_magic_regex" > /dev/null; then + : + else + cat <&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +EOF + fi ;; + esac +fi + +echo $ac_n "checking whether to build shared libraries... $ac_c" 1>&6 +test "$can_build_shared" = "no" && enable_shared=no + +# On AIX, shared libraries and static libraries use the same namespace, and +# are all built from PIC. +case "$host_os" in +aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + +aix4*) + test "$enable_shared" = yes && enable_static=no + ;; +esac + +echo "$ac_t$enable_shared" 1>&6 + +# Make sure either enable_shared or enable_static is yes. +test "$enable_shared" = yes || enable_static=yes + +echo "checking whether to build static libraries... $enable_static" 1>&6 + +if test "$hardcode_action" = relink; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + +echo $ac_n "checking for objdir... $ac_c" 1>&6 +rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + objdir=_libs +fi +rmdir .libs 2>/dev/null +echo "$ac_t$objdir" 1>&6 + +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else +if eval "test \"`echo '$''{'lt_cv_dlopen'+set}'`\" != set"; then + lt_cv_dlopen=no lt_cv_dlopen_libs= +echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 +echo "$progname:2248: checking for dlopen in -ldl" >&5 +ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldl $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for dlopen""... $ac_c" 1>&6 +echo "$progname:2288: checking for dlopen" >&5 +if eval "test \"`echo '$''{'ac_cv_func_dlopen'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_dlopen) || defined (__stub___dlopen) +choke me +#else +dlopen(); +#endif + +; return 0; } +EOF +if { (eval echo $progname:2318: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_dlopen=yes" +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_dlopen=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_func_'dlopen`\" = yes"; then + echo "$ac_t""yes" 1>&6 + lt_cv_dlopen="dlopen" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for dld_link in -ldld""... $ac_c" 1>&6 +echo "$progname:2335: checking for dld_link in -ldld" >&5 +ac_lib_var=`echo dld'_'dld_link | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldld $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for shl_load""... $ac_c" 1>&6 +echo "$progname:2375: checking for shl_load" >&5 +if eval "test \"`echo '$''{'ac_cv_func_shl_load'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_shl_load) || defined (__stub___shl_load) +choke me +#else +shl_load(); +#endif + +; return 0; } +EOF +if { (eval echo $progname:2405: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_shl_load=yes" +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_shl_load=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'shl_load`\" = yes"; then + echo "$ac_t""yes" 1>&6 + lt_cv_dlopen="shl_load" +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for shl_load in -ldld""... $ac_c" 1>&6 +echo "$progname:2423: checking for shl_load in -ldld" >&5 +ac_lib_var=`echo dld'_'shl_load | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldld $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + echo "$ac_t""no" 1>&6 +fi + + +fi + + +fi + + +fi + + +fi + +fi + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + fi + + case "$lt_cv_dlopen" in + dlopen) +for ac_hdr in dlfcn.h; do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "$progname:2488: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +int fnord = 0; +EOF +ac_try="$ac_compile >/dev/null 2>conftest.out" +{ (eval echo $progname:2498: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi +done + + if test "x$ac_cv_header_dlfcn_h" = xyes; then + CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + fi + eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + LIBS="$lt_cv_dlopen_libs $LIBS" + + echo $ac_n "checking whether a program can dlopen itself""... $ac_c" 1>&6 +echo "$progname:2526: checking whether a program can dlopen itself" >&5 +if test "${lt_cv_dlopen_self+set}" = set; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + lt_cv_dlopen_self=cross + else + cat > conftest.c < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LTDL_GLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LTDL_GLOBAL DL_GLOBAL +# else +# define LTDL_GLOBAL 0 +# endif +#endif + +/* We may have to define LTDL_LAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LTDL_LAZY_OR_NOW +# ifdef RTLD_LAZY +# define LTDL_LAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LTDL_LAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LTDL_LAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LTDL_LAZY_OR_NOW DL_NOW +# else +# define LTDL_LAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +fnord() { int i=42;} +main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW); + if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord"); + if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); } + +EOF +if { (eval echo $progname:2580: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + lt_cv_dlopen_self=yes +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + lt_cv_dlopen_self=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$lt_cv_dlopen_self" 1>&6 + + if test "$lt_cv_dlopen_self" = yes; then + LDFLAGS="$LDFLAGS $link_static_flag" + echo $ac_n "checking whether a statically linked program can dlopen itself""... $ac_c" 1>&6 +echo "$progname:2599: checking whether a statically linked program can dlopen itself" >&5 +if test "${lt_cv_dlopen_self_static+set}" = set; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + lt_cv_dlopen_self_static=cross + else + cat > conftest.c < +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LTDL_GLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LTDL_GLOBAL DL_GLOBAL +# else +# define LTDL_GLOBAL 0 +# endif +#endif + +/* We may have to define LTDL_LAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LTDL_LAZY_OR_NOW +# ifdef RTLD_LAZY +# define LTDL_LAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LTDL_LAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LTDL_LAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LTDL_LAZY_OR_NOW DL_NOW +# else +# define LTDL_LAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +fnord() { int i=42;} +main() { void *self, *ptr1, *ptr2; self=dlopen(0,LTDL_GLOBAL|LTDL_LAZY_OR_NOW); + if(self) { ptr1=dlsym(self,"fnord"); ptr2=dlsym(self,"_fnord"); + if(ptr1 || ptr2) { dlclose(self); exit(0); } } exit(1); } + +EOF +if { (eval echo $progname:2653: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + lt_cv_dlopen_self_static=yes +else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + lt_cv_dlopen_self_static=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$lt_cv_dlopen_self_static" 1>&6 +fi + ;; + esac + + case "$lt_cv_dlopen_self" in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case "$lt_cv_dlopen_self_static" in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + +# Copy echo and quote the copy, instead of the original, because it is +# used later. +ltecho="$echo" +if test "X$ltecho" = "X$CONFIG_SHELL $0 --fallback-echo"; then + ltecho="$CONFIG_SHELL \$0 --fallback-echo" +fi +LTSHELL="$SHELL" + +LTCONFIG_VERSION="$VERSION" + +# Only quote variables if we're using ltmain.sh. +case "$ltmain" in +*.sh) + # Now quote all the things that may contain metacharacters. + for var in ltecho old_CC old_CFLAGS old_CPPFLAGS \ + old_LD old_LDFLAGS old_LIBS \ + old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS \ + AR CC LD LN_S NM LTSHELL LTCONFIG_VERSION \ + reload_flag reload_cmds wl \ + pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \ + thread_safe_flag_spec whole_archive_flag_spec libname_spec \ + library_names_spec soname_spec \ + RANLIB old_archive_cmds old_archive_from_new_cmds old_postinstall_cmds \ + old_postuninstall_cmds archive_cmds archive_expsym_cmds postinstall_cmds postuninstall_cmds \ + file_magic_cmd export_symbols_cmds deplibs_check_method allow_undefined_flag no_undefined_flag \ + finish_cmds finish_eval global_symbol_pipe global_symbol_to_cdecl \ + hardcode_libdir_flag_spec hardcode_libdir_separator \ + sys_lib_search_path_spec sys_lib_dlsearch_path_spec \ + compiler_c_o compiler_o_lo need_locks exclude_expsyms include_expsyms; do + + case "$var" in + reload_cmds | old_archive_cmds | old_archive_from_new_cmds | \ + old_postinstall_cmds | old_postuninstall_cmds | \ + export_symbols_cmds | archive_cmds | archive_expsym_cmds | \ + postinstall_cmds | postuninstall_cmds | \ + finish_cmds | sys_lib_search_path_spec | sys_lib_dlsearch_path_spec) + # Double-quote double-evaled strings. + eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$double_quote_subst\" -e \"\$sed_quote_subst\" -e \"\$delay_variable_subst\"\`\\\"" + ;; + *) + eval "$var=\\\"\`\$echo \"X\$$var\" | \$Xsed -e \"\$sed_quote_subst\"\`\\\"" + ;; + esac + done + + case "$ltecho" in + *'\$0 --fallback-echo"') + ltecho=`$echo "X$ltecho" | $Xsed -e 's/\\\\\\\$0 --fallback-echo"$/$0 --fallback-echo"/'` + ;; + esac + + trap "$rm \"$ofile\"; exit 1" 1 2 15 + echo "creating $ofile" + $rm "$ofile" + cat < "$ofile" +#! $SHELL + +# `$echo "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +# NOTE: Changes made to this file will be lost: look at ltconfig or ltmain.sh. +# +# Copyright (C) 1996-1999 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="sed -e s/^X//" + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X\${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +### BEGIN LIBTOOL CONFIG +EOF + cfgfile="$ofile" + ;; + +*) + # Double-quote the variables that need it (for aesthetics). + for var in old_CC old_CFLAGS old_CPPFLAGS \ + old_LD old_LDFLAGS old_LIBS \ + old_NM old_RANLIB old_LN_S old_DLLTOOL old_OBJDUMP old_AS; do + eval "$var=\\\"\$var\\\"" + done + + # Just create a config file. + cfgfile="$ofile.cfg" + trap "$rm \"$cfgfile\"; exit 1" 1 2 15 + echo "creating $cfgfile" + $rm "$cfgfile" + cat < "$cfgfile" +# `$echo "$cfgfile" | sed 's%^.*/%%'` - Libtool configuration file. +# Generated automatically by $PROGRAM (GNU $PACKAGE $VERSION$TIMESTAMP) +EOF + ;; +esac + +cat <> "$cfgfile" +# Libtool was configured as follows, on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# CC=$old_CC CFLAGS=$old_CFLAGS CPPFLAGS=$old_CPPFLAGS \\ +# LD=$old_LD LDFLAGS=$old_LDFLAGS LIBS=$old_LIBS \\ +# NM=$old_NM RANLIB=$old_RANLIB LN_S=$old_LN_S \\ +# DLLTOOL=$old_DLLTOOL OBJDUMP=$old_OBJDUMP AS=$old_AS \\ +# $0$ltconfig_args +# +# Compiler and other test output produced by $progname, useful for +# debugging $progname, is in ./config.log if it exists. + +# The version of $progname that generated this script. +LTCONFIG_VERSION=$LTCONFIG_VERSION + +# Shell to use when invoking shell scripts. +SHELL=$LTSHELL + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# The host system. +host_alias=$host_alias +host=$host + +# An echo program that does not interpret backslashes. +echo=$ltecho + +# The archiver. +AR=$AR + +# The default C compiler. +CC=$CC + +# The linker used to build libraries. +LD=$LD + +# Whether we need hard or soft links. +LN_S=$LN_S + +# A BSD-compatible nm program. +NM=$NM + +# Used on cygwin: DLL creation program. +DLLTOOL="$DLLTOOL" + +# Used on cygwin: object dumper. +OBJDUMP="$OBJDUMP" + +# Used on cygwin: assembler. +AS="$AS" + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# How to create reloadable object files. +reload_flag=$reload_flag +reload_cmds=$reload_cmds + +# How to pass a linker flag through the compiler. +wl=$wl + +# Object file suffix (normally "o"). +objext="$objext" + +# Old archive suffix (normally "a"). +libext="$libext" + +# Executable file suffix (normally ""). +exeext="$exeext" + +# Additional compiler flags for building library objects. +pic_flag=$pic_flag + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$compiler_c_o + +# Can we write directly to a .lo ? +compiler_o_lo=$compiler_o_lo + +# Must we lock files when doing compilation ? +need_locks=$need_locks + +# Do we need the lib prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Whether dlopen is supported. +dlopen=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Compiler flag to prevent dynamic linking. +link_static_flag=$link_static_flag + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$no_builtin_flag + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$whole_archive_flag_spec + +# Compiler flag to generate thread-safe objects. +thread_safe_flag_spec=$thread_safe_flag_spec + +# Library versioning type. +version_type=$version_type + +# Format of library name prefix. +libname_spec=$libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME. +library_names_spec=$library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$soname_spec + +# Commands used to build and install an old-style archive. +RANLIB=$RANLIB +old_archive_cmds=$old_archive_cmds +old_postinstall_cmds=$old_postinstall_cmds +old_postuninstall_cmds=$old_postuninstall_cmds + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$old_archive_from_new_cmds + +# Commands used to build and install a shared archive. +archive_cmds=$archive_cmds +archive_expsym_cmds=$archive_expsym_cmds +postinstall_cmds=$postinstall_cmds +postuninstall_cmds=$postuninstall_cmds + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$deplibs_check_method + +# Command to use when deplibs_check_method == file_magic. +file_magic_cmd=$file_magic_cmd + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$allow_undefined_flag + +# Flag that forces no undefined symbols. +no_undefined_flag=$no_undefined_flag + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$finish_cmds + +# Same as above, but a single script fragment to be evaled but not shown. +finish_eval=$finish_eval + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$global_symbol_pipe + +# Transform the output of nm in a proper C declaration +global_symbol_to_cdecl=$global_symbol_to_cdecl + +# This is the shared library runtime path variable. +runpath_var=$runpath_var + +# This is the shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist. +hardcode_libdir_flag_spec=$hardcode_libdir_flag_spec + +# Whether we need a single -rpath flag with a separated argument. +hardcode_libdir_separator=$hardcode_libdir_separator + +# Set to yes if using DIR/libNAME.so during linking hardcodes DIR into the +# resulting binary. +hardcode_direct=$hardcode_direct + +# Set to yes if using the -LDIR flag during linking hardcodes DIR into the +# resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into +# the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Compile-time system search path for libraries +sys_lib_search_path_spec=$sys_lib_search_path_spec + +# Run-time system search path for libraries +sys_lib_dlsearch_path_spec=$sys_lib_dlsearch_path_spec + +# Fix the shell variable \$srcfile for the compiler. +fix_srcfile_path="$fix_srcfile_path" + +# Set to yes if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$include_expsyms + +EOF + +case "$ltmain" in +*.sh) + echo '### END LIBTOOL CONFIG' >> "$ofile" + echo >> "$ofile" + case "$host_os" in + aix3*) + cat <<\EOF >> "$ofile" + +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +EOF + ;; + esac + + # Append the ltmain.sh script. + sed '$q' "$ltmain" >> "$ofile" || (rm -f "$ofile"; exit 1) + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + + chmod +x "$ofile" + ;; + +*) + # Compile the libtool program. + echo "FIXME: would compile $ltmain" + ;; +esac + +test -n "$cache_file" || exit 0 + +# AC_CACHE_SAVE +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff -rNu linux-2.4.7/cmd/dmapi/ltmain.sh linux-2.4-xfs/cmd/dmapi/ltmain.sh --- linux-2.4.7/cmd/dmapi/ltmain.sh Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/ltmain.sh Wed Jun 13 13:06:23 2001 @@ -0,0 +1,4028 @@ +# ltmain.sh - Provide generalized library-building support services. +# NOTE: Changing this file will not affect anything until you rerun ltconfig. +# +# Copyright (C) 1996-1999 Free Software Foundation, Inc. +# Originally by Gordon Matzigkeit , 1996 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Check that we have a working $echo. +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell, and then maybe $echo will work. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + echo "$modename: not configured to build any kind of library" 1>&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 +fi + +# Global variables. +mode=$default_mode +nonopt= +prev= +prevopt= +run= +show="$echo" +show_help= +execute_dlfiles= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" + +# Parse our command line options once, thoroughly. +while test $# -gt 0 +do + arg="$1" + shift + + case "$arg" in + -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;; + *) optarg= ;; + esac + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case "$prev" in + execute_dlfiles) + eval "$prev=\"\$$prev \$arg\"" + ;; + *) + eval "$prev=\$arg" + ;; + esac + + prev= + prevopt= + continue + fi + + # Have we seen a non-optional argument yet? + case "$arg" in + --help) + show_help=yes + ;; + + --version) + echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP" + exit 0 + ;; + + --config) + sed -e '1,/^### BEGIN LIBTOOL CONFIG/d' -e '/^### END LIBTOOL CONFIG/,$d' $0 + exit 0 + ;; + + --debug) + echo "$progname: enabling shell trace mode" + set -x + ;; + + --dry-run | -n) + run=: + ;; + + --features) + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + exit 0 + ;; + + --finish) mode="finish" ;; + + --mode) prevopt="--mode" prev=mode ;; + --mode=*) mode="$optarg" ;; + + --quiet | --silent) + show=: + ;; + + -dlopen) + prevopt="-dlopen" + prev=execute_dlfiles + ;; + + -*) + $echo "$modename: unrecognized option \`$arg'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + *) + nonopt="$arg" + break + ;; + esac +done + +if test -n "$prevopt"; then + $echo "$modename: option \`$prevopt' requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 +fi + +if test -z "$show_help"; then + + # Infer the operation mode. + if test -z "$mode"; then + case "$nonopt" in + *cc | *++ | gcc* | *-gcc*) + mode=link + for arg + do + case "$arg" in + -c) + mode=compile + break + ;; + esac + done + ;; + *db | *dbx | *strace | *truss) + mode=execute + ;; + *install*|cp|mv) + mode=install + ;; + *rm) + mode=uninstall + ;; + *) + # If we have no mode, but dlfiles were specified, then do execute mode. + test -n "$execute_dlfiles" && mode=execute + + # Just use the default operation mode. + if test -z "$mode"; then + if test -n "$nonopt"; then + $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2 + else + $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2 + fi + fi + ;; + esac + fi + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$execute_dlfiles" && test "$mode" != execute; then + $echo "$modename: unrecognized option \`-dlopen'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$modename --help --mode=$mode' for more information." + + # These modes are in order of execution frequency so that they run quickly. + case "$mode" in + # libtool compile mode + compile) + modename="$modename: compile" + # Get the compilation command and the source file. + base_compile= + lastarg= + srcfile="$nonopt" + suppress_output= + + user_target=no + for arg + do + # Accept any command-line options. + case "$arg" in + -o) + if test "$user_target" != "no"; then + $echo "$modename: you cannot specify \`-o' more than once" 1>&2 + exit 1 + fi + user_target=next + ;; + + -static) + build_old_libs=yes + continue + ;; + esac + + case "$user_target" in + next) + # The next one is the -o target name + user_target=yes + continue + ;; + yes) + # We got the output file + user_target=set + libobj="$arg" + continue + ;; + esac + + # Accept the current argument as the source file. + lastarg="$srcfile" + srcfile="$arg" + + # Aesthetically quote the previous argument. + + # Backslashify any backslashes, double quotes, and dollar signs. + # These are the only characters that are still specially + # interpreted inside of double-quoted scrings. + lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"` + + # Double-quote args containing other shell metacharacters. + # Many Bourne shells cannot handle close brackets correctly in scan + # sets, so we specify it separately. + case "$lastarg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + lastarg="\"$lastarg\"" + ;; + esac + + # Add the previous argument to base_compile. + if test -z "$base_compile"; then + base_compile="$lastarg" + else + base_compile="$base_compile $lastarg" + fi + done + + case "$user_target" in + set) + ;; + no) + # Get the name of the library object. + libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'` + ;; + *) + $echo "$modename: you must specify a target with \`-o'" 1>&2 + exit 1 + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + xform='[cCFSfmso]' + case "$libobj" in + *.ada) xform=ada ;; + *.adb) xform=adb ;; + *.ads) xform=ads ;; + *.asm) xform=asm ;; + *.c++) xform=c++ ;; + *.cc) xform=cc ;; + *.cpp) xform=cpp ;; + *.cxx) xform=cxx ;; + *.f90) xform=f90 ;; + *.for) xform=for ;; + esac + + libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"` + + case "$libobj" in + *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;; + *) + $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2 + exit 1 + ;; + esac + + if test -z "$base_compile"; then + $echo "$modename: you must specify a compilation command" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $libobj" + else + removelist="$libobj" + fi + + $run $rm $removelist + trap "$run $rm $removelist; exit 1" 1 2 15 + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\..*$%%'`.${objext} + lockfile="$output_obj.lock" + removelist="$removelist $output_obj $lockfile" + trap "$run $rm $removelist; exit 1" 1 2 15 + else + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until ln "$0" "$lockfile" 2>/dev/null; do + $show "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + echo "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + echo $srcfile > "$lockfile" + fi + + if test -n "$fix_srcfile_path"; then + eval srcfile=\"$fix_srcfile_path\" + fi + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + # All platforms use -DPIC, to notify preprocessed assembler code. + command="$base_compile $srcfile $pic_flag -DPIC" + if test "$build_old_libs" = yes; then + lo_libobj="$libobj" + dir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$libobj"; then + dir="$objdir" + else + dir="$dir/$objdir" + fi + libobj="$dir/"`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` + + if test -d "$dir"; then + $show "$rm $libobj" + $run $rm $libobj + else + $show "$mkdir $dir" + $run $mkdir $dir + status=$? + if test $status -ne 0 && test ! -d $dir; then + exit $status + fi + fi + fi + if test "$compiler_o_lo" = yes; then + output_obj="$libobj" + command="$command -o $output_obj" + elif test "$compiler_c_o" = yes; then + output_obj="$obj" + command="$command -o $output_obj" + fi + + $run $rm "$output_obj" + $show "$command" + if $run eval "$command"; then : + else + test -n "$output_obj" && $run $rm $removelist + exit 1 + fi + + if test "$need_locks" = warn && + test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then + echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + + # Just move the object if needed, then go on to compile the next one + if test x"$output_obj" != x"$libobj"; then + $show "$mv $output_obj $libobj" + if $run $mv $output_obj $libobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # If we have no pic_flag, then copy the object into place and finish. + if test -z "$pic_flag" && test "$build_old_libs" = yes; then + # Rename the .lo from within objdir to obj + if test -f $obj; then + $show $rm $obj + $run $rm $obj + fi + + $show "$mv $libobj $obj" + if $run $mv $libobj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$obj" | $Xsed -e "s%.*/%%"` + libobj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` + # Now arrange that obj and lo_libobj become the same file + $show "(cd $xdir && $LN_S $baseobj $libobj)" + if $run eval '(cd $xdir && $LN_S $baseobj $libobj)'; then + exit 0 + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Allow error messages only from the first compilation. + suppress_output=' >/dev/null 2>&1' + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + command="$base_compile $srcfile" + if test "$compiler_c_o" = yes; then + command="$command -o $obj" + output_obj="$obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + command="$command$suppress_output" + $run $rm "$output_obj" + $show "$command" + if $run eval "$command"; then : + else + $run $rm $removelist + exit 1 + fi + + if test "$need_locks" = warn && + test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then + echo "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $run $rm $removelist + exit 1 + fi + + # Just move the object if needed + if test x"$output_obj" != x"$obj"; then + $show "$mv $output_obj $obj" + if $run $mv $output_obj $obj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + + # Create an invalid libtool object if no PIC, so that we do not + # accidentally link it into a program. + if test "$build_libtool_libs" != yes; then + $show "echo timestamp > $libobj" + $run eval "echo timestamp > \$libobj" || exit $? + else + # Move the .lo from within objdir + $show "$mv $libobj $lo_libobj" + if $run $mv $libobj $lo_libobj; then : + else + error=$? + $run $rm $removelist + exit $error + fi + fi + fi + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + $rm "$lockfile" + fi + + exit 0 + ;; + + # libtool link mode + link) + modename="$modename: link" + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-os2*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invokation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + + # This is a source program that is used to create dlls on Windows + # Don't remove nor modify the starting and closing comments +# /* ltdll.c starts here */ +# #define WIN32_LEAN_AND_MEAN +# #include +# #undef WIN32_LEAN_AND_MEAN +# #include +# +# #ifndef __CYGWIN__ +# # ifdef __CYGWIN32__ +# # define __CYGWIN__ __CYGWIN32__ +# # endif +# #endif +# +# #ifdef __cplusplus +# extern "C" { +# #endif +# BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved); +# #ifdef __cplusplus +# } +# #endif +# +# #ifdef __CYGWIN__ +# #include +# DECLARE_CYGWIN_DLL( DllMain ); +# #endif +# HINSTANCE __hDllInstance_base; +# +# BOOL APIENTRY +# DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved) +# { +# __hDllInstance_base = hInst; +# return TRUE; +# } +# /* ltdll.c ends here */ + # This is a source program that is used to create import libraries + # on Windows for dlls which lack them. Don't remove nor modify the + # starting and closing comments +# /* impgen.c starts here */ +# /* Copyright (C) 1999 Free Software Foundation, Inc. +# +# This file is part of GNU libtool. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# */ +# +# #include /* for printf() */ +# #include /* for open(), lseek(), read() */ +# #include /* for O_RDONLY, O_BINARY */ +# #include /* for strdup() */ +# +# static unsigned int +# pe_get16 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[2]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 2); +# return b[0] + (b[1]<<8); +# } +# +# static unsigned int +# pe_get32 (fd, offset) +# int fd; +# int offset; +# { +# unsigned char b[4]; +# lseek (fd, offset, SEEK_SET); +# read (fd, b, 4); +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# static unsigned int +# pe_as32 (ptr) +# void *ptr; +# { +# unsigned char *b = ptr; +# return b[0] + (b[1]<<8) + (b[2]<<16) + (b[3]<<24); +# } +# +# int +# main (argc, argv) +# int argc; +# char *argv[]; +# { +# int dll; +# unsigned long pe_header_offset, opthdr_ofs, num_entries, i; +# unsigned long export_rva, export_size, nsections, secptr, expptr; +# unsigned long name_rvas, nexp; +# unsigned char *expdata, *erva; +# char *filename, *dll_name; +# +# filename = argv[1]; +# +# dll = open(filename, O_RDONLY|O_BINARY); +# if (!dll) +# return 1; +# +# dll_name = filename; +# +# for (i=0; filename[i]; i++) +# if (filename[i] == '/' || filename[i] == '\\' || filename[i] == ':') +# dll_name = filename + i +1; +# +# pe_header_offset = pe_get32 (dll, 0x3c); +# opthdr_ofs = pe_header_offset + 4 + 20; +# num_entries = pe_get32 (dll, opthdr_ofs + 92); +# +# if (num_entries < 1) /* no exports */ +# return 1; +# +# export_rva = pe_get32 (dll, opthdr_ofs + 96); +# export_size = pe_get32 (dll, opthdr_ofs + 100); +# nsections = pe_get16 (dll, pe_header_offset + 4 +2); +# secptr = (pe_header_offset + 4 + 20 + +# pe_get16 (dll, pe_header_offset + 4 + 16)); +# +# expptr = 0; +# for (i = 0; i < nsections; i++) +# { +# char sname[8]; +# unsigned long secptr1 = secptr + 40 * i; +# unsigned long vaddr = pe_get32 (dll, secptr1 + 12); +# unsigned long vsize = pe_get32 (dll, secptr1 + 16); +# unsigned long fptr = pe_get32 (dll, secptr1 + 20); +# lseek(dll, secptr1, SEEK_SET); +# read(dll, sname, 8); +# if (vaddr <= export_rva && vaddr+vsize > export_rva) +# { +# expptr = fptr + (export_rva - vaddr); +# if (export_rva + export_size > vaddr + vsize) +# export_size = vsize - (export_rva - vaddr); +# break; +# } +# } +# +# expdata = (unsigned char*)malloc(export_size); +# lseek (dll, expptr, SEEK_SET); +# read (dll, expdata, export_size); +# erva = expdata - export_rva; +# +# nexp = pe_as32 (expdata+24); +# name_rvas = pe_as32 (expdata+32); +# +# printf ("EXPORTS\n"); +# for (i = 0; i&2 + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + else + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + fi + build_libtool_libs=no + build_old_libs=yes + prefer_static_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test $# -gt 0; do + arg="$1" + shift + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case "$prev" in + output) + compile_command="$compile_command @OUTPUT@" + finalize_command="$finalize_command @OUTPUT@" + ;; + esac + + case "$prev" in + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + compile_command="$compile_command @SYMFILE@" + finalize_command="$finalize_command @SYMFILE@" + preload=yes + fi + case "$arg" in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + else + dlprefiles="$dlprefiles $arg" + fi + prev= + ;; + esac + ;; + expsyms) + export_symbols="$arg" + if test ! -f "$arg"; then + $echo "$modename: symbol file \`$arg' does not exist" + exit 1 + fi + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case "$arg" in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit 1 + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) rpath="$rpath $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) xrpath="$xrpath $arg" ;; + esac + fi + prev= + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi + + prevarg="$arg" + + case "$arg" in + -all-static) + if test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2 + continue + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: not more than one -exported-symbols argument allowed" + exit 1 + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -L*) + dir=`$echo "X$arg" | $Xsed -e 's/^-L//'` + # We need an absolute path. + case "$dir" in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + absdir="$dir" + fi + dir="$absdir" + ;; + esac + case " $deplibs " in + *" $arg "*) ;; + *) deplibs="$deplibs $arg";; + esac + case " $lib_search_path " in + *" $dir "*) ;; + *) lib_search_path="$lib_search_path $dir";; + esac + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-os2*) + dllsearchdir=`cd "$dir" && pwd || echo "$dir"` + case ":$dllsearchpath:" in + ::) dllsearchpath="$dllsearchdir";; + *":$dllsearchdir:"*) ;; + *) dllsearchpath="$dllsearchpath:$dllsearchdir";; + esac + ;; + esac + ;; + + -l*) + if test "$arg" = "-lc"; then + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*) + # These systems don't actually have c library (as such) + continue + ;; + esac + elif test "$arg" = "-lm"; then + case "$host" in + *-*-cygwin* | *-*-beos*) + # These systems don't actually have math library (as such) + continue + ;; + esac + fi + deplibs="$deplibs $arg" + ;; + + -module) + module=yes + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -o) prev=output ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + dir=`$echo "X$arg" | $Xsed -e 's/^-R//'` + # We need an absolute path. + case "$dir" in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + $echo "$modename: only absolute run-paths are allowed" 1>&2 + exit 1 + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) xrpath="$xrpath $dir" ;; + esac + continue + ;; + + -static) + # If we have no pic_flag, then this is the same as -all-static. + if test -z "$pic_flag" && test -n "$link_static_flag"; then + compile_command="$compile_command $link_static_flag" + finalize_command="$finalize_command $link_static_flag" + fi + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + # Some other compiler flag. + -* | +*) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + ;; + + *.o | *.obj | *.a | *.lib) + # A standard object. + objs="$objs $arg" + ;; + + *.lo) + # A library object. + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + if test "$build_libtool_libs" = yes && test "$dlopen" = yes; then + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + if test "$prev" = dlprefiles; then + # Preload the old-style object. + dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e "$lo2o"` + prev= + fi + libobjs="$libobjs $arg" + ;; + + *.la) + # A libtool-controlled library. + + dlname= + libdir= + library_names= + old_library= + + # Check to see that this really is a libtool archive. + if (sed -e '2q' $arg | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$arg' is not a valid libtool archive" 1>&2 + exit 1 + fi + + # If the library was installed with an old release of libtool, + # it will not redefine variable installed. + installed=yes + + # Read the .la file + # If there is no directory component, then add one. + case "$arg" in + */* | *\\*) . $arg ;; + *) . ./$arg ;; + esac + + # Get the name of the library we link against. + linklib= + for l in $old_library $library_names; do + linklib="$l" + done + + if test -z "$linklib"; then + $echo "$modename: cannot find name of link library for \`$arg'" 1>&2 + exit 1 + fi + + # Find the relevant object directory and library name. + name=`$echo "X$arg" | $Xsed -e 's%^.*/%%' -e 's/\.la$//' -e 's/^lib//'` + + if test "X$installed" = Xyes; then + dir="$libdir" + else + dir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'` + if test "X$dir" = "X$arg"; then + dir="$objdir" + else + dir="$dir/$objdir" + fi + fi + + if test -n "$dependency_libs"; then + # Extract -R and -L from dependency_libs + temp_deplibs= + for deplib in $dependency_libs; do + case "$deplib" in + -R*) temp_xrpath=`$echo "X$deplib" | $Xsed -e 's/^-R//'` + case " $rpath $xrpath " in + *" $temp_xrpath "*) ;; + *) xrpath="$xrpath $temp_xrpath";; + esac;; + -L*) case "$compile_command $temp_deplibs " in + *" $deplib "*) ;; + *) temp_deplibs="$temp_deplibs $deplib";; + esac + temp_dir=`$echo "X$deplib" | $Xsed -e 's/^-L//'` + case " $lib_search_path " in + *" $temp_dir "*) ;; + *) lib_search_path="$lib_search_path $temp_dir";; + esac + ;; + *) temp_deplibs="$temp_deplibs $deplib";; + esac + done + dependency_libs="$temp_deplibs" + fi + + if test -z "$libdir"; then + # It is a libtool convenience library, so add in its objects. + convenience="$convenience $dir/$old_library" + old_convenience="$old_convenience $dir/$old_library" + deplibs="$deplibs$dependency_libs" + compile_command="$compile_command $dir/$old_library$dependency_libs" + finalize_command="$finalize_command $dir/$old_library$dependency_libs" + continue + fi + + # This library was specified with -dlopen. + if test "$prev" = dlfiles; then + dlfiles="$dlfiles $arg" + if test -z "$dlname" || test "$dlopen" != yes || test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking statically, + # we need to preload. + prev=dlprefiles + else + # We should not create a dependency on this library, but we + # may need any libraries it requires. + compile_command="$compile_command$dependency_libs" + finalize_command="$finalize_command$dependency_libs" + prev= + continue + fi + fi + + # The library was specified with -dlpreopen. + if test "$prev" = dlprefiles; then + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + dlprefiles="$dlprefiles $dir/$old_library" + else + dlprefiles="$dlprefiles $dir/$linklib" + fi + prev= + fi + + if test -n "$library_names" && + { test "$prefer_static_libs" = no || test -z "$old_library"; }; then + link_against_libtool_libs="$link_against_libtool_libs $arg" + if test -n "$shlibpath_var"; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath " in + *" $dir "*) ;; + *) temp_rpath="$temp_rpath $dir" ;; + esac + fi + + # We need an absolute path. + case "$dir" in + [\\/] | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2 + $echo "$modename: passing it literally to the linker, although it might fail" 1>&2 + absdir="$dir" + fi + ;; + esac + + # This is the magic to use -rpath. + # Skip directories that are in the system default run-time + # search path, unless they have been requested with -R. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) compile_rpath="$compile_rpath $absdir" + esac + ;; + esac + + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" + esac + ;; + esac + + lib_linked=yes + case "$hardcode_action" in + immediate | unsupported) + if test "$hardcode_direct" = no; then + compile_command="$compile_command $dir/$linklib" + deplibs="$deplibs $dir/$linklib" + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-os2*) + dllsearchdir=`cd "$dir" && pwd || echo "$dir"` + if test -n "$dllsearchpath"; then + dllsearchpath="$dllsearchpath:$dllsearchdir" + else + dllsearchpath="$dllsearchdir" + fi + ;; + esac + elif test "$hardcode_minus_L" = no; then + case "$host" in + *-*-sunos*) + compile_shlibpath="$compile_shlibpath$dir:" + ;; + esac + case "$compile_command " in + *" -L$dir "*) ;; + *) compile_command="$compile_command -L$dir";; + esac + compile_command="$compile_command -l$name" + deplibs="$deplibs -L$dir -l$name" + elif test "$hardcode_shlibpath_var" = no; then + case ":$compile_shlibpath:" in + *":$dir:"*) ;; + *) compile_shlibpath="$compile_shlibpath$dir:";; + esac + compile_command="$compile_command -l$name" + deplibs="$deplibs -l$name" + else + lib_linked=no + fi + ;; + + relink) + if test "$hardcode_direct" = yes; then + compile_command="$compile_command $absdir/$linklib" + deplibs="$deplibs $absdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + case "$compile_command " in + *" -L$absdir "*) ;; + *) compile_command="$compile_command -L$absdir";; + esac + compile_command="$compile_command -l$name" + deplibs="$deplibs -L$absdir -l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case ":$compile_shlibpath:" in + *":$absdir:"*) ;; + *) compile_shlibpath="$compile_shlibpath$absdir:";; + esac + compile_command="$compile_command -l$name" + deplibs="$deplibs -l$name" + else + lib_linked=no + fi + ;; + + *) + lib_linked=no + ;; + esac + + if test "$lib_linked" != yes; then + $echo "$modename: configuration error: unsupported hardcode properties" + exit 1 + fi + + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes; then + finalize_command="$finalize_command $libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + case "$finalize_command " in + *" -L$libdir "*) ;; + *) finalize_command="$finalize_command -L$libdir";; + esac + finalize_command="$finalize_command -l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case ":$finalize_shlibpath:" in + *":$libdir:"*) ;; + *) finalize_shlibpath="$finalize_shlibpath$libdir:";; + esac + finalize_command="$finalize_command -l$name" + else + # We cannot seem to hardcode it, guess we'll fake it. + case "$finalize_command " in + *" -L$dir "*) ;; + *) finalize_command="$finalize_command -L$libdir";; + esac + finalize_command="$finalize_command -l$name" + fi + else + # Transform directly to old archives if we don't build new libraries. + if test -n "$pic_flag" && test -z "$old_library"; then + $echo "$modename: cannot find static library for \`$arg'" 1>&2 + exit 1 + fi + + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_command="$compile_command $dir/$linklib" + finalize_command="$finalize_command $dir/$linklib" + else + case "$compile_command " in + *" -L$dir "*) ;; + *) compile_command="$compile_command -L$dir";; + esac + compile_command="$compile_command -l$name" + case "$finalize_command " in + *" -L$dir "*) ;; + *) finalize_command="$finalize_command -L$dir";; + esac + finalize_command="$finalize_command -l$name" + fi + fi + + # Add in any libraries that this one depends upon. + compile_command="$compile_command$dependency_libs" + finalize_command="$finalize_command$dependency_libs" + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + ;; + esac + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + done + + if test -n "$prev"; then + $echo "$modename: the \`$prevarg' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + compile_command="$compile_command $arg" + finalize_command="$finalize_command $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'` + libobjs_save="$libobjs" + + case "$output" in + "") + $echo "$modename: you must specify an output file" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + + *.a | *.lib) + if test -n "$link_against_libtool_libs"; then + $echo "$modename: error: cannot link libtool libraries into archives" 1>&2 + exit 1 + fi + + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for archives" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for archives" 1>&2 + fi + + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2 + fi + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + ;; + + *.la) + # Make sure we only generate libraries of the form `libNAME.la'. + case "$outputname" in + lib*) + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'` + eval libname=\"$libname_spec\" + ;; + *) + if test "$module" = no; then + $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + eval libname=\"$libname_spec\" + else + libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'` + fi + ;; + esac + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + + if test -n "$objs"; then + $echo "$modename: cannot build libtool library \`$output' from non-libtool objects:$objs" 2>&1 + exit 1 + fi + + # How the heck are we supposed to write a wrapper for a shared library? + if test -n "$link_against_libtool_libs"; then + $echo "$modename: error: cannot link shared libraries into libtool libraries" 1>&2 + exit 1 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for libtool libraries" 1>&2 + fi + + set dummy $rpath + if test $# -gt 2; then + $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2 + fi + install_libdir="$2" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + libext=al + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + dependency_libs="$deplibs" + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2 + fi + else + + # Parse the version information argument. + IFS="${IFS= }"; save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + IFS="$save_ifs" + + if test -n "$8"; then + $echo "$modename: too many parameters to \`-version-info'" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + current="$2" + revision="$3" + age="$4" + + # Check that each of the things are valid numbers. + case "$current" in + [0-9]*) ;; + *) + $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case "$revision" in + [0-9]*) ;; + *) + $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + case "$age" in + [0-9]*) ;; + *) + $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + ;; + esac + + if test $age -gt $current; then + $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2 + $echo "$modename: \`$vinfo' is not valid version information" 1>&2 + exit 1 + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case "$version_type" in + none) ;; + + irix) + major=`expr $current - $age + 1` + versuffix="$major.$revision" + verstring="sgi$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test $loop != 0; do + iface=`expr $revision - $loop` + loop=`expr $loop - 1` + verstring="sgi$major.$iface:$verstring" + done + ;; + + linux) + major=.`expr $current - $age` + versuffix="$major.$age.$revision" + ;; + + osf) + major=`expr $current - $age` + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test $loop != 0; do + iface=`expr $current - $loop` + loop=`expr $loop - 1` + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + verstring="$verstring:${current}.0" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current"; + ;; + + windows) + # Like Linux, but with '-' rather than '.', since we only + # want one extension on Windows 95. + major=`expr $current - $age` + versuffix="-$major-$age-$revision" + ;; + + *) + $echo "$modename: unknown library version type \`$version_type'" 1>&2 + echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2 + exit 1 + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + verstring="0.0" + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2 + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + dependency_libs="$deplibs" + case "$host" in + *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody*) + # rhapsody is a little odd... + deplibs="$deplibs -framework System" + ;; + *) + # Add libc to deplibs on all other systems. + deplibs="$deplibs -lc" + ;; + esac + fi + + # Create the output directory, or remove our outputs if we need to. + if test -d $output_objdir; then + $show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*" + $run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.* + else + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + status=$? + if test $status -ne 0 && test ! -d $output_objdir; then + exit $status + fi + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + oldlibs="$oldlibs $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + fi + + if test "$build_libtool_libs" = yes; then + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case "$deplibs_check_method" in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behaviour. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $rm conftest.c + cat > conftest.c </dev/null` + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null \ + | grep " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | sed 's/.* -> //'` + case "$potliblink" in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \ + | sed 10q \ + | egrep "$file_magic_regex" > /dev/null; then + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 + fi + done + done + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + echo "*** Warning: This library needs some functionality provided by $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + fi + else + # Add a -L argument. + newdeplibs="$newdeplibs $a_deplib" + fi + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \ + -e 's/ -[LR][^ ]*//g' -e 's/[ ]//g' | + grep . >/dev/null; then + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + fi + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + echo "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + # Get the real and link names of the library. + eval library_names=\"$library_names_spec\" + set dummy $library_names + realname="$2" + shift; shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + lib="$output_objdir/$realname" + for link + do + linknames="$linknames $link" + done + + # Ensure that we have .o objects for linkers which dislike .lo + # (e.g. aix) in case we are running --disable-static + for obj in $libobjs; do + xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$obj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$obj" | $Xsed -e 's%^.*/%%'` + oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` + if test ! -f $xdir/$oldobj; then + $show "(cd $xdir && ${LN_S} $baseobj $oldobj)" + $run eval '(cd $xdir && ${LN_S} $baseobj $oldobj)' || exit $? + fi + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + $show "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $run $rm $export_symbols + eval cmds=\"$export_symbols_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + if test -n "$export_symbols_regex"; then + $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\"" + $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + $show "$mv \"${export_symbols}T\" \"$export_symbols\"" + $run eval '$mv "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"' + fi + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case "$xlib" in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + libobjs="$libobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + linkopts="$linkopts $flag" + fi + + # Do each of the archive commands. + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval cmds=\"$archive_expsym_cmds\" + else + eval cmds=\"$archive_cmds\" + fi + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $? + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + *.lo | *.o | *.obj) + if test -n "$link_against_libtool_libs"; then + $echo "$modename: error: cannot link libtool libraries into objects" 1>&2 + exit 1 + fi + + if test -n "$deplibs"; then + $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2 + fi + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2 + fi + + if test -n "$rpath"; then + $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2 + fi + + if test -n "$xrpath"; then + $echo "$modename: warning: \`-R' is ignored for objects" 1>&2 + fi + + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for objects" 1>&2 + fi + + case "$output" in + *.lo) + if test -n "$objs"; then + $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2 + exit 1 + fi + libobj="$output" + obj=`$echo "X$output" | $Xsed -e "$lo2o"` + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $run $rm $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\" + else + gentop="$output_objdir/${obj}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + for xlib in $convenience; do + # Extract the objects. + case "$xlib" in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + reload_conv_objs="$reload_objs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP` + done + fi + fi + + # Create the old-style object. + reload_objs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" + + output="$obj" + eval cmds=\"$reload_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit 0 + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + $show "echo timestamp > $libobj" + $run eval "echo timestamp > $libobj" || exit $? + exit 0 + fi + + if test -n "$pic_flag"; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + eval cmds=\"$reload_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + else + # Just create a symlink. + $show $rm $libobj + $run $rm $libobj + xdir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$libobj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$libobj" | $Xsed -e 's%^.*/%%'` + oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"` + $show "(cd $xdir && $LN_S $oldobj $baseobj)" + $run eval '(cd $xdir && $LN_S $oldobj $baseobj)' || exit $? + fi + + if test -n "$gentop"; then + $show "${rm}r $gentop" + $run ${rm}r $gentop + fi + + exit 0 + ;; + + # Anything else should be a program. + *) + if test -n "$vinfo"; then + $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2 + fi + + if test -n "$release"; then + $echo "$modename: warning: \`-release' is ignored for programs" 1>&2 + fi + + if test "$preload" = yes; then + if test "$dlopen" = unknown && test "$dlopen_self" = unknown && + test "$dlopen_self_static" = unknown; then + $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support." + fi + fi + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$compile_rpath " in + *" $libdir "*) ;; + *) compile_rpath="$compile_rpath $libdir" ;; + esac + case "$finalize_rpath " in + *" $libdir "*) ;; + *) finalize_rpath="$finalize_rpath $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) perm_rpath="$perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case "$hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator" in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + rpath="$rpath $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'` + if test "X$output_objdir" = "X$output"; then + output_objdir="$objdir" + else + output_objdir="$output_objdir/$objdir" + fi + + # Create the binary in the object directory, then wrap it. + if test ! -d $output_objdir; then + $show "$mkdir $output_objdir" + $run $mkdir $output_objdir + status=$? + if test $status -ne 0 && test ! -d $output_objdir; then + exit $status + fi + fi + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + fi + + dlsyms= + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + dlsyms="${outputname}S.c" + else + $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2 + fi + fi + + if test -n "$dlsyms"; then + case "$dlsyms" in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${outputname}.nm" + + $show "$rm $nlist ${nlist}S ${nlist}T" + $run $rm "$nlist" "${nlist}S" "${nlist}T" + + # Parse the name list into a source file. + $show "creating $output_objdir/$dlsyms" + + test -z "$run" && $echo > "$output_objdir/$dlsyms" "\ +/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */ +/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +/* Prevent the only kind of declaration conflicts we can make. */ +#define lt_preloaded_symbols some_other_symbol + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + $show "generating symbol list for \`$output'" + + test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$echo "X$objs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + for arg in $progfiles; do + $show "extracting global C symbols from \`$arg'" + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + if test -n "$export_symbols_regex"; then + $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T' + $run eval '$mv "$nlist"T "$nlist"' + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$output.exp" + $run $rm $export_symbols + $run eval "sed -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + else + $run eval "sed -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"' + $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T' + $run eval 'mv "$nlist"T "$nlist"' + fi + fi + + for arg in $dlprefiles; do + $show "extracting global C symbols from \`$arg'" + name=`echo "$arg" | sed -e 's%^.*/%%'` + $run eval 'echo ": $name " >> "$nlist"' + $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'" + done + + if test -z "$run"; then + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $mv "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if grep -v "^: " < "$nlist" | sort +2 | uniq > "$nlist"S; then + : + else + grep -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$dlsyms" + fi + + $echo >> "$output_objdir/$dlsyms" "\ + +#undef lt_preloaded_symbols + +#if defined (__STDC__) && __STDC__ +# define lt_ptr_t void * +#else +# define lt_ptr_t char * +# define const +#endif + +/* The mapping between symbol names and symbols. */ +const struct { + const char *name; + lt_ptr_t address; +} +lt_preloaded_symbols[] = +{\ +" + + sed -n -e 's/^: \([^ ]*\) $/ {\"\1\", (lt_ptr_t) 0},/p' \ + -e 's/^. \([^ ]*\) \([^ ]*\)$/ {"\2", (lt_ptr_t) \&\2},/p' \ + < "$nlist" >> "$output_objdir/$dlsyms" + + $echo >> "$output_objdir/$dlsyms" "\ + {0, (lt_ptr_t) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + fi + + pic_flag_for_symtable= + case "$host" in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DPIC -DFREEBSD_WORKAROUND";; + esac;; + *-*-hpux*) + case "$compile_command " in + *" -static "*) ;; + *) pic_flag_for_symtable=" $pic_flag -DPIC";; + esac + esac + + # Now compile the dynamic symbol file. + $show "(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")" + $run eval '(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $? + + # Clean up the generated files. + $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T" + $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T" + + # Transform the symbol file into the correct name. + compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"` + ;; + *) + $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2 + exit 1 + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` + finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + fi + + if test -z "$link_against_libtool_libs" || test "$build_libtool_libs" != yes; then + # Replace the output file specification. + compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + $show "$link_command" + $run eval "$link_command" + status=$? + + # Delete the generated files. + if test -n "$dlsyms"; then + $show "$rm $output_objdir/${outputname}S.${objext}" + $run $rm "$output_objdir/${outputname}S.${objext}" + fi + + exit $status + fi + + if test -n "$shlibpath_var"; then + # We should set the shlibpath_var + rpath= + for dir in $temp_rpath; do + case "$dir" in + [\\/]* | [A-Za-z]:[\\/]*) + # Absolute path. + rpath="$rpath$dir:" + ;; + *) + # Relative path: add a thisdir entry. + rpath="$rpath\$thisdir/$dir:" + ;; + esac + done + temp_rpath="$rpath" + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + rpath="$rpath$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + rpath="$rpath$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2 + $echo "$modename: \`$output' will be relinked during installation" 1>&2 + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname + + $show "$link_command" + $run eval "$link_command" || exit $? + + # Now create the wrapper script. + $show "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"` + fi + + # Quote $echo for shipping. + if test "X$echo" = "X$SHELL $0 --fallback-echo"; then + case "$0" in + [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";; + *) qecho="$SHELL `pwd`/$0 --fallback-echo";; + esac + qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"` + else + qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"` + fi + + # Only actually do things if our run command is non-null. + if test -z "$run"; then + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) output=`echo $output|sed 's,.exe$,,'` ;; + esac + $rm $output + trap "$rm $output; exit 1" 1 2 15 + + $echo > $output "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed='sed -e 1s/^X//' +sed_quote_subst='$sed_quote_subst' + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variable: + link_against_libtool_libs='$link_against_libtool_libs' +else + # When we are sourced in execute mode, \$file and \$echo are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + echo=\"$qecho\" + file=\"\$0\" + # Make sure echo works. + if test \"X\$1\" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift + elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then + # Yippee, \$echo works! + : + else + # Restart under the correct shell, and then maybe \$echo will work. + exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} + fi + fi\ +" + $echo >> $output "\ + + # Find the directory that this script lives in. + thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\/]* | [A-Za-z]:[\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\` + done + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + echo >> $output "\ + program=lt-'$outputname' + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || \\ + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | sed 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $mkdir \"\$progdir\" + else + $rm \"\$progdir/\$file\" + fi" + + echo >> $output "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if (cd \"\$thisdir\" && eval \$relink_command); then : + else + $rm \"\$progdir/\$file\" + exit 1 + fi + fi + + $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $rm \"\$progdir/\$program\"; + $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $rm \"\$progdir/\$file\" + fi" + else + echo >> $output "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + echo >> $output "\ + + if test -f \"\$progdir/\$program\"; then" + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $echo >> $output "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + + export $shlibpath_var +" + fi + + # fixup the dll searchpath if we need to. + if test -n "$dllsearchpath"; then + $echo >> $output "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + $echo >> $output "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. +" + case $host in + # win32 systems need to use the prog path for dll + # lookup to work + *-*-cygwin*) + $echo >> $output "\ + exec \$progdir/\$program \${1+\"\$@\"} +" + ;; + + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2*) + $echo >> $output "\ + exec \$progdir\\\\\$program \${1+\"\$@\"} +" + ;; + + *) + $echo >> $output "\ + # Export the path to the program. + PATH=\"\$progdir:\$PATH\" + export PATH + + exec \$program \${1+\"\$@\"} +" + ;; + esac + $echo >> $output "\ + \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\" + exit 1 + fi + else + # The program doesn't exist. + \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2 + \$echo \"This script is just a wrapper for \$program.\" 1>&2 + echo \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" + chmod +x $output + fi + exit 0 + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$objs "`$echo "X$libobjs_save" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP` + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + $show "${rm}r $gentop" + $run ${rm}r "$gentop" + $show "mkdir $gentop" + $run mkdir "$gentop" + status=$? + if test $status -ne 0 && test ! -d "$gentop"; then + exit $status + fi + generated="$generated $gentop" + + # Add in members from convenience archives. + for xlib in $addlibs; do + # Extract the objects. + case "$xlib" in + [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;; + *) xabs=`pwd`"/$xlib" ;; + esac + xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'` + xdir="$gentop/$xlib" + + $show "${rm}r $xdir" + $run ${rm}r "$xdir" + $show "mkdir $xdir" + $run mkdir "$xdir" + status=$? + if test $status -ne 0 && test ! -d "$xdir"; then + exit $status + fi + $show "(cd $xdir && $AR x $xabs)" + $run eval "(cd \$xdir && $AR x \$xabs)" || exit $? + + oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP` + done + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + eval cmds=\"$old_archive_from_new_cmds\" + else + # Ensure that we have .o objects in place in case we decided + # not to build a shared library, and have fallen back to building + # static libs even though --disable-static was passed! + for oldobj in $oldobjs; do + if test ! -f $oldobj; then + xdir=`$echo "X$oldobj" | $Xsed -e 's%/[^/]*$%%'` + if test "X$xdir" = "X$oldobj"; then + xdir="." + else + xdir="$xdir" + fi + baseobj=`$echo "X$oldobj" | $Xsed -e 's%^.*/%%'` + obj=`$echo "X$baseobj" | $Xsed -e "$o2lo"` + $show "(cd $xdir && ${LN_S} $obj $baseobj)" + $run eval '(cd $xdir && ${LN_S} $obj $baseobj)' || exit $? + fi + done + + eval cmds=\"$old_archive_cmds\" + fi + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$generated"; then + $show "${rm}r$generated" + $run ${rm}r$generated + fi + + # Now create the libtool archive. + case "$output" in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + $show "creating $output" + + if test -n "$xrpath"; then + temp_xrpath= + for libdir in $xrpath; do + temp_xrpath="$temp_xrpath -R$libdir" + done + dependency_libs="$temp_xrpath $dependency_libs" + fi + + # Only create the output if not a dry run. + if test -z "$run"; then + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + fi + $rm $output + $echo > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$dlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Directory that this library needs to be installed in: +libdir='$install_libdir'\ +" + done + fi + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" + $run eval "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)" || exit $? + ;; + esac + exit 0 + ;; + + # libtool install mode + install) + modename="$modename: install" + + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh; then + # Aesthetically quote it. + arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$arg " + arg="$1" + shift + else + install_prog= + arg="$nonopt" + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog$arg" + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + for arg + do + if test -n "$dest"; then + files="$files $dest" + dest="$arg" + continue + fi + + case "$arg" in + -d) isdir=yes ;; + -f) prev="-f" ;; + -g) prev="-g" ;; + -m) prev="-m" ;; + -o) prev="-o" ;; + -s) + stripme=" -s" + continue + ;; + -*) ;; + + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + prev= + else + dest="$arg" + continue + fi + ;; + esac + + # Aesthetically quote the argument. + arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"` + case "$arg" in + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*) + arg="\"$arg\"" + ;; + esac + install_prog="$install_prog $arg" + done + + if test -z "$install_prog"; then + $echo "$modename: you must specify an install program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -n "$prev"; then + $echo "$modename: the \`$prev' option requires an argument" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + if test -z "$files"; then + if test -z "$dest"; then + $echo "$modename: no file or destination specified" 1>&2 + else + $echo "$modename: you must specify a destination" 1>&2 + fi + $echo "$help" 1>&2 + exit 1 + fi + + # Strip any trailing slash from the destination. + dest=`$echo "X$dest" | $Xsed -e 's%/$%%'` + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'` + test "X$destdir" = "X$dest" && destdir=. + destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'` + + # Not a directory, so check to see that there is only one file specified. + set dummy $files + if test $# -gt 2; then + $echo "$modename: \`$dest' is not a directory" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + fi + case "$destdir" in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case "$file" in + *.lo) ;; + *) + $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case "$file" in + *.a | *.lib) + # Do the static libraries later. + staticlibs="$staticlibs $file" + ;; + + *.la) + # Check to see that this really is a libtool archive. + if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$file' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + library_names= + old_library= + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) current_libdirs="$current_libdirs $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) future_libdirs="$future_libdirs $libdir" ;; + esac + fi + + dir="`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/" + test "X$dir" = "X$file/" && dir= + dir="$dir$objdir" + + # See the names of the shared library. + set dummy $library_names + if test -n "$2"; then + realname="$2" + shift + shift + + # Install the shared library and build the symlinks. + $show "$install_prog $dir/$realname $destdir/$realname" + $run eval "$install_prog $dir/$realname $destdir/$realname" || exit $? + + if test $# -gt 0; then + # Delete the old symlinks, and create new ones. + for linkname + do + if test "$linkname" != "$realname"; then + $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)" + fi + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + eval cmds=\"$postinstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + fi + + # Install the pseudo-library for information purposes. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + instname="$dir/$name"i + $show "$install_prog $instname $destdir/$name" + $run eval "$install_prog $instname $destdir/$name" || exit $? + + # Maybe install the static library, too. + test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case "$destfile" in + *.lo) + staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"` + ;; + *.o | *.obj) + staticdest="$destfile" + destfile= + ;; + *) + $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; + esac + + # Install the libtool object if requested. + if test -n "$destfile"; then + $show "$install_prog $file $destfile" + $run eval "$install_prog $file $destfile" || exit $? + fi + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + staticobj=`$echo "X$file" | $Xsed -e "$lo2o"` + + $show "$install_prog $staticobj $staticdest" + $run eval "$install_prog \$staticobj \$staticdest" || exit $? + fi + exit 0 + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + destfile="$destdir/$destfile" + fi + + # Do a test to see if this is really a libtool program. + if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + link_against_libtool_libs= + relink_command= + + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Check the variables that should have been set. + if test -z "$link_against_libtool_libs"; then + $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2 + exit 1 + fi + + finalize=yes + for lib in $link_against_libtool_libs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + # If there is no directory component, then add one. + case "$lib" in + */* | *\\*) . $lib ;; + *) . ./$lib ;; + esac + fi + libfile="$libdir/`$echo "X$lib" | $Xsed -e 's%^.*/%%g'`" + if test -n "$libdir" && test ! -f "$libfile"; then + $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2 + finalize=no + fi + done + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + if test "$finalize" = yes && test -z "$run"; then + tmpdir="/tmp" + test -n "$TMPDIR" && tmpdir="$TMPDIR" + tmpdir=`mktemp -d $tmpdir/libtool-XXXXXX 2> /dev/null` + if test $? = 0 ; then : + else + tmpdir="$tmpdir/libtool-$$" + fi + if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then : + else + $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2 + continue + fi + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + + $show "$relink_command" + if $run eval "$relink_command"; then : + else + $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2 + ${rm}r "$tmpdir" + continue + fi + file="$outputname" + else + $echo "$modename: warning: cannot relink \`$file'" 1>&2 + fi + else + # Install the binary that we compiled earlier. + file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + $show "$install_prog$stripme $file $destfile" + $run eval "$install_prog\$stripme \$file \$destfile" || exit $? + test -n "$outputname" && ${rm}r "$tmpdir" + ;; + esac + done + + for file in $staticlibs; do + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + + $show "$install_prog $file $oldlib" + $run eval "$install_prog \$file \$oldlib" || exit $? + + # Do each command in the postinstall commands. + eval cmds=\"$old_postinstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || exit $? + done + IFS="$save_ifs" + done + + if test -n "$future_libdirs"; then + $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2 + fi + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + test -n "$run" && current_libdirs=" -n$current_libdirs" + exec $SHELL $0 --finish$current_libdirs + exit 1 + fi + + exit 0 + ;; + + # libtool finish mode + finish) + modename="$modename: finish" + libdirs="$nonopt" + admincmds= + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for dir + do + libdirs="$libdirs $dir" + done + + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + eval cmds=\"$finish_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" || admincmds="$admincmds + $cmd" + done + IFS="$save_ifs" + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $run eval "$cmds" || admincmds="$admincmds + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + test "$show" = : && exit 0 + + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + echo " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + echo " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + echo " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + echo "See any operating system documentation about shared libraries for" + echo "more information, such as the ld(1) and ld.so(8) manual pages." + echo "----------------------------------------------------------------------" + exit 0 + ;; + + # libtool execute mode + execute) + modename="$modename: execute" + + # The first argument is the command name. + cmd="$nonopt" + if test -z "$cmd"; then + $echo "$modename: you must specify a COMMAND" 1>&2 + $echo "$help" + exit 1 + fi + + # Handle -dlopen flags immediately. + for file in $execute_dlfiles; do + if test ! -f "$file"; then + $echo "$modename: \`$file' is not a file" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + dir= + case "$file" in + *.la) + # Check to see that this really is a libtool archive. + if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then : + else + $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + # Read the libtool library. + dlname= + library_names= + + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'" + continue + fi + + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + + if test -f "$dir/$objdir/$dlname"; then + dir="$dir/$objdir" + else + $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2 + exit 1 + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + ;; + + *) + $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2 + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case "$file" in + -*) ;; + *) + # Do a test to see if this is really a libtool program. + if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + # If there is no directory component, then add one. + case "$file" in + */* | *\\*) . $file ;; + *) . ./$file ;; + esac + + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"` + args="$args \"$file\"" + done + + if test -z "$run"; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved enviroment variables + if test "${save_LC_ALL+set}" = set; then + LC_ALL="$save_LC_ALL"; export LC_ALL + fi + if test "${save_LANG+set}" = set; then + LANG="$save_LANG"; export LANG + fi + + # Now actually exec the command. + eval "exec \$cmd$args" + + $echo "$modename: cannot exec \$cmd$args" + exit 1 + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\"" + $echo "export $shlibpath_var" + fi + $echo "$cmd$args" + exit 0 + fi + ;; + + # libtool uninstall mode + uninstall) + modename="$modename: uninstall" + rm="$nonopt" + files= + + for arg + do + case "$arg" in + -*) rm="$rm $arg" ;; + *) files="$files $arg" ;; + esac + done + + if test -z "$rm"; then + $echo "$modename: you must specify an RM program" 1>&2 + $echo "$help" 1>&2 + exit 1 + fi + + for file in $files; do + dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'` + test "X$dir" = "X$file" && dir=. + name=`$echo "X$file" | $Xsed -e 's%^.*/%%'` + + rmfiles="$file" + + case "$name" in + *.la) + # Possibly a libtool archive, so verify it. + if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then + . $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + rmfiles="$rmfiles $dir/$n" + done + test -n "$old_library" && rmfiles="$rmfiles $dir/$old_library" + + $show "$rm $rmfiles" + $run $rm $rmfiles + + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + eval cmds=\"$postuninstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + done + IFS="$save_ifs" + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + eval cmds=\"$old_postuninstall_cmds\" + IFS="${IFS= }"; save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + $show "$cmd" + $run eval "$cmd" + done + IFS="$save_ifs" + fi + + # FIXME: should reinstall the best remaining shared library. + fi + ;; + + *.lo) + if test "$build_old_libs" = yes; then + oldobj=`$echo "X$name" | $Xsed -e "$lo2o"` + rmfiles="$rmfiles $dir/$oldobj" + fi + $show "$rm $rmfiles" + $run $rm $rmfiles + ;; + + *) + $show "$rm $rmfiles" + $run $rm $rmfiles + ;; + esac + done + exit 0 + ;; + + "") + $echo "$modename: you must specify a MODE" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 + ;; + esac + + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$generic_help" 1>&2 + exit 1 +fi # test -z "$show_help" + +# We need to display help for each of the modes. +case "$mode" in +"") $echo \ +"Usage: $modename [OPTION]... [MODE-ARG]... + +Provide generalized library-building support services. + + --config show all configuration variables + --debug enable verbose shell tracing +-n, --dry-run display commands without modifying any files + --features display basic configuration information and exit + --finish same as \`--mode=finish' + --help display this help message and exit + --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS] + --quiet same as \`--silent' + --silent don't print informational messages + --version print version information + +MODE must be one of the following: + + compile compile a source file into a libtool object + execute automatically set library path, then run a program + finish complete the installation of libtool libraries + install install libraries or executables + link create a library or an executable + uninstall remove libraries from an installed directory + +MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for +a more detailed description of MODE." + exit 0 + ;; + +compile) + $echo \ +"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -static always build a \`.o' file suitable for static linking + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + +execute) + $echo \ +"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + +finish) + $echo \ +"Usage: $modename [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + +install) + $echo \ +"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + +link) + $echo \ +"Usage: $modename [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -static do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + +uninstall) + $echo \ +"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + +*) + $echo "$modename: invalid operation mode \`$mode'" 1>&2 + $echo "$help" 1>&2 + exit 1 + ;; +esac + +echo +$echo "Try \`$modename --help' for more information about other modes." + +exit 0 + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: diff -rNu linux-2.4.7/cmd/dmapi/man/CVS/Entries linux-2.4-xfs/cmd/dmapi/man/CVS/Entries --- linux-2.4.7/cmd/dmapi/man/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/man/CVS/Entries Thu Jul 5 11:43:48 2001 @@ -0,0 +1,2 @@ +/Makefile/1.1/Wed Jan 17 01:36:55 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/dmapi/man/CVS/Entries.Log linux-2.4-xfs/cmd/dmapi/man/CVS/Entries.Log --- linux-2.4.7/cmd/dmapi/man/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/man/CVS/Entries.Log Thu Jul 5 11:43:48 2001 @@ -0,0 +1 @@ +A D/man3//// diff -rNu linux-2.4.7/cmd/dmapi/man/CVS/Repository linux-2.4-xfs/cmd/dmapi/man/CVS/Repository --- linux-2.4.7/cmd/dmapi/man/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/man/CVS/Repository Thu Jul 5 11:43:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/dmapi/man diff -rNu linux-2.4.7/cmd/dmapi/man/CVS/Root linux-2.4-xfs/cmd/dmapi/man/CVS/Root --- linux-2.4.7/cmd/dmapi/man/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/man/CVS/Root Thu Jul 5 11:43:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/dmapi/man/Makefile linux-2.4-xfs/cmd/dmapi/man/Makefile --- linux-2.4.7/cmd/dmapi/man/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/man/Makefile Tue Jan 16 19:36:55 2001 @@ -0,0 +1,41 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +SUBDIRS = man3 + +default install install-dev : $(SUBDIRS) + $(SUBDIRS_MAKERULE) + +include $(BUILDRULES) diff -rNu linux-2.4.7/cmd/dmapi/man/man3/CVS/Entries linux-2.4-xfs/cmd/dmapi/man/man3/CVS/Entries --- linux-2.4.7/cmd/dmapi/man/man3/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/man/man3/CVS/Entries Thu Jul 5 11:43:48 2001 @@ -0,0 +1,3 @@ +/Makefile/1.1/Wed Jan 17 01:36:55 2001/-ko/ +/dmapi.3/1.2/Wed Feb 28 23:07:10 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/dmapi/man/man3/CVS/Repository linux-2.4-xfs/cmd/dmapi/man/man3/CVS/Repository --- linux-2.4.7/cmd/dmapi/man/man3/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/man/man3/CVS/Repository Thu Jul 5 11:43:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/dmapi/man/man3 diff -rNu linux-2.4.7/cmd/dmapi/man/man3/CVS/Root linux-2.4-xfs/cmd/dmapi/man/man3/CVS/Root --- linux-2.4.7/cmd/dmapi/man/man3/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/man/man3/CVS/Root Thu Jul 5 11:43:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/dmapi/man/man3/Makefile linux-2.4-xfs/cmd/dmapi/man/man3/Makefile --- linux-2.4.7/cmd/dmapi/man/man3/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/man/man3/Makefile Tue Jan 16 19:36:55 2001 @@ -0,0 +1,48 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +MAN_SECTION = 3 + +MAN_PAGES = $(shell echo *.$(MAN_SECTION)) +MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) +LSRCFILES = $(MAN_PAGES) + +default install : $(MAN_PAGES) + +include $(BUILDRULES) + +install-dev : default + $(INSTALL) -m 755 -d $(MAN_DEST) + $(INSTALL_MAN) diff -rNu linux-2.4.7/cmd/dmapi/man/man3/dmapi.3 linux-2.4-xfs/cmd/dmapi/man/man3/dmapi.3 --- linux-2.4.7/cmd/dmapi/man/man3/dmapi.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/dmapi/man/man3/dmapi.3 Wed Feb 28 17:07:10 2001 @@ -0,0 +1,24 @@ +.TH DMAPI 3 +.SH NAME +dmapi \- \&DMAPI library +.SH SYNOPSIS +.nf +\f3#include \f1 +.sp .8v +\f3cc ... -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -ldm -lhandle +.fi +.SH DESCRIPTION +\f2DMAPI\f1, or \f2XDSM\f1, is an implementation of +the X/Open document: +\f3Systems Management: Data Storage Management (XDSM) API\f1 +dated February 1997. +This interface is made available for the XFS filesystem +by means of the \f3libdm\f1 library. +.PP +See the XDSM manual at +http://www.opengroup.org/onlinepubs/9657099/toc.htm for a +description of the functions offered by libdm library. +.PP +For more information and details on how to contribute to the +XFS project see the web pages at: +http://oss.sgi.com/projects/xfs/ diff -rNu linux-2.4.7/cmd/xfsdump/CVS/Entries linux-2.4-xfs/cmd/xfsdump/CVS/Entries --- linux-2.4.7/cmd/xfsdump/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/CVS/Entries Thu Jul 5 11:43:48 2001 @@ -0,0 +1,7 @@ +/Makefile/1.3/Thu Mar 22 01:29:53 2001/-ko/ +/Makepkgs/1.2/Thu Mar 29 06:30:35 2001/-ko/ +/README/1.1/Mon Jan 15 04:35:39 2001/-ko/ +/VERSION/1.10/Thu Jul 5 08:42:14 2001/-ko/ +/configure.in/1.6/Tue Jun 12 07:20:31 2001/-ko/ +/install-sh/1.1/Mon Jan 15 04:35:39 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/CVS/Entries.Log linux-2.4-xfs/cmd/xfsdump/CVS/Entries.Log --- linux-2.4.7/cmd/xfsdump/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/CVS/Entries.Log Thu Jul 5 11:44:09 2001 @@ -0,0 +1,15 @@ +A D/build//// +A D/common//// +A D/copy//// +A D/debian//// +A D/doc//// +A D/dump//// +A D/estimate//// +A D/fsr//// +A D/include//// +A D/inventory//// +A D/invutil//// +A D/librmt//// +A D/man//// +A D/quota//// +A D/restore//// diff -rNu linux-2.4.7/cmd/xfsdump/CVS/Repository linux-2.4-xfs/cmd/xfsdump/CVS/Repository --- linux-2.4.7/cmd/xfsdump/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/CVS/Repository Thu Jul 5 11:43:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump diff -rNu linux-2.4.7/cmd/xfsdump/CVS/Root linux-2.4-xfs/cmd/xfsdump/CVS/Root --- linux-2.4.7/cmd/xfsdump/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/CVS/Root Thu Jul 5 11:43:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/Makefile linux-2.4-xfs/cmd/xfsdump/Makefile --- linux-2.4.7/cmd/xfsdump/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/Makefile Wed Mar 21 19:29:53 2001 @@ -0,0 +1,76 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = . +HAVE_BUILDDEFS = $(shell test -f $(TOPDIR)/include/builddefs && echo yes || echo no) + +ifeq ($(HAVE_BUILDDEFS), yes) +include $(TOPDIR)/include/builddefs +endif + +CONFIGURE = configure include/builddefs +LSRCFILES = configure configure.in Makepkgs install-sh README VERSION +LDIRT = config.* conftest* Logs/* built install.* install-dev.* *.gz + +SUBDIRS = include librmt \ + common estimate fsr inventory invutil quota dump restore \ + man doc debian build + +default: $(CONFIGURE) +ifeq ($(HAVE_BUILDDEFS), no) + $(MAKE) -C . $@ +else + $(SUBDIRS_MAKERULE) +endif + +ifeq ($(HAVE_BUILDDEFS), yes) +include $(BUILDRULES) +else +clean: # if configure hasn't run, nothing to clean +endif + +$(CONFIGURE): configure.in include/builddefs.in VERSION + rm -f config.cache + autoconf + ./configure + +install: default + $(SUBDIRS_MAKERULE) + $(INSTALL) -m 755 -d $(PKG_DOC_DIR) + $(INSTALL) -m 644 README $(PKG_DOC_DIR) + +install-dev: default + $(SUBDIRS_MAKERULE) + +realclean distclean: clean + rm -f $(LDIRT) $(CONFIGURE) + [ ! -d Logs ] || rmdir Logs diff -rNu linux-2.4.7/cmd/xfsdump/Makepkgs linux-2.4-xfs/cmd/xfsdump/Makepkgs --- linux-2.4.7/cmd/xfsdump/Makepkgs Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/Makepkgs Thu Mar 29 00:30:35 2001 @@ -0,0 +1,109 @@ +#! /bin/sh +# +# Make whichever packages have been requested. +# Defaults to RPMs. +# +LOGDIR=Logs + +type=rpm +verbose=false + +MAKE=${MAKE:-make} +test ! -z "$MAKE" && make=$MAKE + +for opt in $* +do + case "$opt" in + clean) + ;; # ignored, kept for backward compatibility + rpm) + type=rpm ;; + debian) + type=debian ;; + verbose) + verbose=true ;; + *) + echo "Usage: Makepkgs [verbose] [debian|rpm]"; exit 1 ;; + esac +done + +# start with a clean manifest +test -f files.rpm && rm -f files.rpm +test -f filesdevel.rpm && rm -f filesdevel.rpm + +test ! -d $LOGDIR && mkdir $LOGDIR +rm -rf $LOGDIR/* > /dev/null 2>&1 + +# build Debian packages, cleans itself before starting +SUDO=${SUDO:-sudo} +test ! -z "$SUDO" && sudo=$SUDO +if [ $type = debian ] ; then + LOGDEB=`pwd` + LOGDEB=../`basename $LOGDEB`.log + echo "== Debian build, log is $LOGDEB"; echo + if $verbose ; then + dpkg-buildpackage -r$SUDO | tee $LOGDEB + else + dpkg-buildpackage -r$SUDO > $LOGDEB + fi + exit 0 +fi + +# build RPM packages - manual clean before starting +echo "== clean, log is $LOGDIR/clean" +if $verbose ; then + $MAKE clean 2>&1 | tee $LOGDIR/clean +else + $MAKE clean > $LOGDIR/clean 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"$MAKE clean\" failed, see log in $LOGDIR/clean + tail $LOGDIR/clean + exit 1 +fi + +echo +echo "== configure, log is $LOGDIR/configure" +if $verbose ; then + autoconf 2>&1 | tee $LOGDIR/configure + ./configure 2>&1 | tee -a $LOGDIR/configure +else + autoconf > $LOGDIR/configure 2>&1 + ./configure >> $LOGDIR/configure 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"configure\" failed, see log in $LOGDIR/configure + tail $LOGDIR/configure + exit 1 +fi + +echo +echo "== default, log is $LOGDIR/default" +if $verbose ; then + $MAKE default 2>&1 | tee $LOGDIR/default +else + $MAKE default > $LOGDIR/default 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"$MAKE default\" failed, see log in $LOGDIR/default + tail $LOGDIR/default + exit 1 +fi + +echo +echo "== dist, log is $LOGDIR/dist" +[ ! -f .census ] && touch .census +if $verbose ; then + $MAKE -C build dist 2>&1 | tee $LOGDIR/dist +else + $MAKE -C build dist > $LOGDIR/dist 2>&1 +fi +if [ $? -ne 0 ] ; then + echo $MAKE dist failed, see log in $LOGDIR/dist + tail $LOGDIR/dist + exit 1 +else + grep '^Wrote:' $LOGDIR/dist | sed -e 's/\.\.\/\.\.\///' +fi + +exit 0 diff -rNu linux-2.4.7/cmd/xfsdump/README linux-2.4-xfs/cmd/xfsdump/README --- linux-2.4.7/cmd/xfsdump/README Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/README Sun Jan 14 22:35:39 2001 @@ -0,0 +1,15 @@ +XFS Dump Tools README +_____________________ + +See the file doc/INSTALL for build, installation and post- +install configuration steps. + +Refer to the xfs(5) manual page for general XFS information +and references to other XFS manual pages. + +For more information and details on how to contribute to the +XFS project see the web pages at: + http://oss.sgi.com/projects/xfs/ + +For more information on the build process, please refer to +the doc/PORTING document. diff -rNu linux-2.4.7/cmd/xfsdump/VERSION linux-2.4-xfs/cmd/xfsdump/VERSION --- linux-2.4.7/cmd/xfsdump/VERSION Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/VERSION Thu Jul 5 03:42:14 2001 @@ -0,0 +1,7 @@ +# +# This file is used by configure to get version information +# +PKG_MAJOR=1 +PKG_MINOR=0 +PKG_REVISION=10 +PKG_BUILD=0 diff -rNu linux-2.4.7/cmd/xfsdump/build/CVS/Entries linux-2.4-xfs/cmd/xfsdump/build/CVS/Entries --- linux-2.4.7/cmd/xfsdump/build/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/CVS/Entries Thu Jul 5 11:43:49 2001 @@ -0,0 +1,2 @@ +/Makefile/1.2/Thu Mar 1 01:31:21 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/build/CVS/Entries.Log linux-2.4-xfs/cmd/xfsdump/build/CVS/Entries.Log --- linux-2.4.7/cmd/xfsdump/build/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/CVS/Entries.Log Thu Jul 5 11:43:49 2001 @@ -0,0 +1,2 @@ +A D/rpm//// +A D/tar//// diff -rNu linux-2.4.7/cmd/xfsdump/build/CVS/Repository linux-2.4-xfs/cmd/xfsdump/build/CVS/Repository --- linux-2.4.7/cmd/xfsdump/build/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/CVS/Repository Thu Jul 5 11:43:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/build diff -rNu linux-2.4.7/cmd/xfsdump/build/CVS/Root linux-2.4-xfs/cmd/xfsdump/build/CVS/Root --- linux-2.4.7/cmd/xfsdump/build/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/CVS/Root Thu Jul 5 11:43:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/build/Makefile linux-2.4-xfs/cmd/xfsdump/build/Makefile --- linux-2.4.7/cmd/xfsdump/build/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/Makefile Wed Feb 28 19:31:21 2001 @@ -0,0 +1,76 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +MANIFEST=src-manifest +SRCTAR=$(PKG_NAME)-$(PKG_VERSION).src.tar.gz + +LDIRT = *-manifest *.gz $(TOPDIR)/$(PKG_NAME)-* + +# for clean and clobber +SUBDIRS = tar rpm + +# nothing to build here (it's all packaging) +default install install-dev : + +include $(BUILDRULES) + +# Symlink in the TOPDIR is used to pack files relative to +# product-version directory. +$(MANIFEST) : $(_FORCE) + @if [ ! -L $(TOPDIR)/$(PKG_NAME)-$(PKG_VERSION) ] ; then \ + $(LN_S) . $(TOPDIR)/$(PKG_NAME)-$(PKG_VERSION) ; \ + fi + @CDIR=`pwd`; cd $(TOPDIR); \ + $(MAKE) --no-print-directory source | \ + sed -e 's/^\./$(PKG_NAME)-$(PKG_VERSION)/' > $$CDIR/$@ ;\ + if [ $$? -ne 0 ] ; then \ + exit 1; \ + else \ + unset TAPE; \ + $(TAR) -T $$CDIR/$@ -cf - | $(ZIP) --best > $$CDIR/$(SRCTAR); \ + fi + +dist : default $(MANIFEST) + @DIST_MANIFEST=`pwd`/bin-manifest; DIST_ROOT=/tmp/$$$$; \ + export DIST_MANIFEST DIST_ROOT; \ + rm -f $$DIST_MANIFEST; \ + echo === install === && $(MAKE) -C $(TOPDIR) install || exit $$?; \ + if [ -x $(TAR) ]; then \ + ( echo "=== tar ===" && $(MAKEF) -C tar $@ || exit $$? ); \ + fi; \ + if [ -x $(RPM) ]; then \ + ( echo "=== rpm ===" && $(MAKEF) -C rpm $@ || exit $$? ); \ + fi; \ + test -z "$$KEEP_DIST_ROOT" || rm -rf $$DIST_ROOT; echo Done diff -rNu linux-2.4.7/cmd/xfsdump/build/rpm/CVS/Entries linux-2.4-xfs/cmd/xfsdump/build/rpm/CVS/Entries --- linux-2.4.7/cmd/xfsdump/build/rpm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/rpm/CVS/Entries Thu Jul 5 11:43:49 2001 @@ -0,0 +1,5 @@ +/Makefile/1.3/Tue Mar 20 19:36:13 2001/-ko/ +/macros.template/1.1/Mon Jan 15 04:35:39 2001/-ko/ +/rpm-2.rc.template/1.1/Mon Jan 15 04:35:39 2001/-ko/ +/xfsdump.spec.in/1.4/Tue Mar 20 04:26:48 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/build/rpm/CVS/Repository linux-2.4-xfs/cmd/xfsdump/build/rpm/CVS/Repository --- linux-2.4.7/cmd/xfsdump/build/rpm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/rpm/CVS/Repository Thu Jul 5 11:43:49 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/build/rpm diff -rNu linux-2.4.7/cmd/xfsdump/build/rpm/CVS/Root linux-2.4-xfs/cmd/xfsdump/build/rpm/CVS/Root --- linux-2.4.7/cmd/xfsdump/build/rpm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/rpm/CVS/Root Thu Jul 5 11:43:49 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/build/rpm/Makefile linux-2.4-xfs/cmd/xfsdump/build/rpm/Makefile --- linux-2.4.7/cmd/xfsdump/build/rpm/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/rpm/Makefile Tue Mar 20 13:36:13 2001 @@ -0,0 +1,78 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +TREEROOT = $(shell cd ${TOPDIR}; pwd) +include $(TOPDIR)/include/builddefs + +SPECF = $(PKG_NAME).spec +LDIRT = $(PKG_NAME)*.rpm $(SPECF) rpmmacros rpm-*.rc $(TOPDIR)/files*.rpm + +LSRCFILES = macros.template $(SPECF).in rpm-2.rc.template + +default install install-dev : + +include $(BUILDRULES) + +# generate a binary rpm file +dist : default $(SPECF) rpm-$(RPM_VERSION).rc + $(RPM) -ba --rcfile ./rpm-$(RPM_VERSION).rc $(SPECF) + +# Because rpm prior to v.2.90 does not support macros and old style config +# is not supported by rpm v.3, we have to resort to such ugly hacks +ifneq ($RPM_VERSION,2) +rpm-$(RPM_VERSION).rc : rpmmacros + sed -e '/^macrofiles:/s|~/.rpmmacros|rpmmacros|' $@ + +rpmmacros : macros.template + @sed -e 's|%topdir%|$(TREEROOT)|g' < $< > $@ +else +rpm-2.rc: rpm-2.rc.template + @sed -e 's|%topdir%|$(TOPDIR)|g' < $< > $@ +endif + +.PHONY: $(SPECF) +${SPECF} : ${SPECF}.in + sed -e's|@pkg_name@|$(PKG_NAME)|g' \ + -e's|@pkg_version@|$(PKG_VERSION)|g' \ + -e's|@pkg_release@|$(PKG_RELEASE)|g' \ + -e's|@pkg_distribution@|$(PKG_DISTRIBUTION)|g' \ + -e's|@pkg_builder@|$(PKG_BUILDER)|g' \ + -e's|@build_root@|$(DIST_ROOT)|g' \ + -e'/^BuildRoot: *$$/d' \ + -e's|@pkg_var_dir@|$(PKG_VAR_DIR)|g' \ + -e's|@pkg_share_dir@|$(PKG_SHARE_DIR)|g' \ + -e's|@pkg_log_dir@|$(PKG_LOG_DIR)|g' \ + -e's|@pkg_doc_dir@|$(PKG_DOC_DIR)|g' \ + -e's|@pkg_man_dir@|$(PKG_MAN_DIR)|g' \ + -e's|@pkg_tmp_dir@|$(PKG_TMP_DIR)|g' \ + -e's|@make@|$(MAKE)|g' < $< > $@ diff -rNu linux-2.4.7/cmd/xfsdump/build/rpm/macros.template linux-2.4-xfs/cmd/xfsdump/build/rpm/macros.template --- linux-2.4.7/cmd/xfsdump/build/rpm/macros.template Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/rpm/macros.template Sun Jan 14 22:35:39 2001 @@ -0,0 +1,30 @@ +# +# rpmrc.template +# +# Template to fudge rpm directory structure inside IRIX-like build +# environment + +# Force 386 build on all platforms +%_target i386-pc-linux +%_target_cpu i386 +%_target_os linux + +# topdir == $(WORKAREA) +%_topdir %topdir% + +# Following directories are specific to the topdir +# This is where build is done. In our case it's the same as $WORKAREA +%_builddir %topdir% + +# This is where foo.1.99.tar.gz is living in the real world. +# Be careful not to run full rpm build as it will override the sources +%_sourcedir %topdir%/build + +# This is where binary RPM and source RPM would end up +%_rpmdir %topdir%/build/rpm +%_srcrpmdir %topdir%/build/rpm +%_specdir %topdir%/build/rpm + +# Leave RPM files in the same directory - we're not building for +# multiple architectures +%_rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm diff -rNu linux-2.4.7/cmd/xfsdump/build/rpm/rpm-2.rc.template linux-2.4-xfs/cmd/xfsdump/build/rpm/rpm-2.rc.template --- linux-2.4.7/cmd/xfsdump/build/rpm/rpm-2.rc.template Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/rpm/rpm-2.rc.template Sun Jan 14 22:35:39 2001 @@ -0,0 +1,25 @@ +# +# rpmrc.template +# +# Template to fudge rpm directory structure inside IRIX-like build +# environment + +# topdir == $(WORKAREA) +topdir: %topdir% + +# Following directories are specific to the topdir +# This is where build is done. In out case it's the same as $WORKAREA +# Be careful not to run full rpm build as it will override the sources +builddir: %topdir% + +# This is where foo.1.99.tar.gz is living in the real world. +sourcedir: %topdir%/build + +# This is where binary RPM and source RPM would end up +rpmdir: %topdir%/build/rpm +srcrpmdir: %topdir%/build/rpm +specdir: %topdir%/build/rpm + +# Leave RPM files in the same directory - we're not building for +# multiple architectures +rpmfilename: %{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm diff -rNu linux-2.4.7/cmd/xfsdump/build/rpm/xfsdump.spec.in linux-2.4-xfs/cmd/xfsdump/build/rpm/xfsdump.spec.in --- linux-2.4.7/cmd/xfsdump/build/rpm/xfsdump.spec.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/rpm/xfsdump.spec.in Mon Mar 19 22:26:48 2001 @@ -0,0 +1,77 @@ +Summary: Administrative utilities for the XFS filesystem. +Name: @pkg_name@ +Version: @pkg_version@ +Release: @pkg_release@ +Distribution: @pkg_distribution@ +Packager: @pkg_builder@ +BuildRoot: @build_root@ +Requires: xfsprogs +Source: @pkg_name@-@pkg_version@.src.tar.gz +Copyright: Copyright (C) 2000 Silicon Graphics, Inc. +Vendor: Silicon Graphics, Inc. +URL: http://oss.sgi.com/projects/xfs/ +Group: Applications/Archiving + +%description +The xfsdump package contains xfsdump, xfsrestore and a number of +other utilities for administering XFS filesystems. + +xfsdump examines files in a filesystem, determines which need to be +backed up, and copies those files to a specified disk, tape or other +storage medium. It uses XFS-specific directives for optimizing the +dump of an XFS filesystem, and also knows how to backup XFS extended +attributes. Backups created with xfsdump are "endian safe" and can +thus be transfered between Linux machines of different architectures +and also between IRIX machines. + +xfsrestore performs the inverse function of xfsdump; it can restore a +full backup of a filesystem. Subsequent incremental backups can then +be layered on top of the full backup. Single files and directory +subtrees may be restored from full or partial backups. + +# If .census exists, then no setup is necessary, just go and do the build, +# otherwise run setup +%prep +if [ -f .census ] ; then + if [ ! -d ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION} ] ; then + ln -s . ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION} + fi +else +%setup +touch .census +./configure +fi + +%build +@make@ + +%install +DIST_ROOT="$RPM_BUILD_ROOT" +DIST_INSTALL=`pwd`/install.manifest +export DIST_ROOT DIST_INSTALL +@make@ install DIST_MANIFEST="$DIST_INSTALL" +files() +{ + sort | uniq | awk ' +$1 == "d" { printf ("%%%%dir %%%%attr(%s,%s,%s) %s\n", $2, $3, $4, $5); } +$1 == "f" { if (match ($6, "@pkg_man_dir@") || match ($6, "@pkg_doc_dir@")) + printf ("%%%%doc "); + if (match ($6, "@pkg_man_dir@")) + printf ("%%%%attr(%s,%s,%s) %s*\n", $2, $3, $4, $6); + else + printf ("%%%%attr(%s,%s,%s) %s\n", $2, $3, $4, $6); } +$1 == "l" { if (match ($3, "@pkg_man_dir@") || match ($3, "@pkg_doc_dir@")) + printf ("%%%%doc "); + if (match ($3, "@pkg_man_dir@")) + printf ("%attr(0777,root,root) %s*\n", $3); + else + printf ("%attr(0777,root,root) %s\n", $3); }' +} +set +x +files < "$DIST_INSTALL" > files.rpm +set -x + +%clean +rm -rf $RPM_BUILD_ROOT + +%files -f files.rpm diff -rNu linux-2.4.7/cmd/xfsdump/build/tar/CVS/Entries linux-2.4-xfs/cmd/xfsdump/build/tar/CVS/Entries --- linux-2.4.7/cmd/xfsdump/build/tar/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/tar/CVS/Entries Thu Jul 5 11:43:49 2001 @@ -0,0 +1,2 @@ +/Makefile/1.2/Thu Mar 1 01:48:49 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/build/tar/CVS/Repository linux-2.4-xfs/cmd/xfsdump/build/tar/CVS/Repository --- linux-2.4.7/cmd/xfsdump/build/tar/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/tar/CVS/Repository Thu Jul 5 11:43:49 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/build/tar diff -rNu linux-2.4.7/cmd/xfsdump/build/tar/CVS/Root linux-2.4-xfs/cmd/xfsdump/build/tar/CVS/Root --- linux-2.4.7/cmd/xfsdump/build/tar/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/tar/CVS/Root Thu Jul 5 11:43:49 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/build/tar/Makefile linux-2.4-xfs/cmd/xfsdump/build/tar/Makefile --- linux-2.4.7/cmd/xfsdump/build/tar/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/build/tar/Makefile Wed Feb 28 19:48:49 2001 @@ -0,0 +1,50 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +BINTAR=$(PKG_NAME)-$(PKG_VERSION).tar.gz +LDIRT = *.gz + +default install install-dev : + +include $(BUILDRULES) + +dist : default + @HERE=`pwd`; cd $${DIST_ROOT:-/}; \ + sort $$HERE/../bin-manifest | uniq | $(AWK) ' \ + $$1 == "f" { printf (".%s\n", $$6); } \ + $$1 == "d" { next; } \ + $$1 == "l" { printf (".%s\n", $$3); }' \ + | $(TAR) -T - -cf - | $(ZIP) --best > $$HERE/$(BINTAR) + @echo Wrote: `pwd`/$(BINTAR) diff -rNu linux-2.4.7/cmd/xfsdump/common/CVS/Entries linux-2.4-xfs/cmd/xfsdump/common/CVS/Entries --- linux-2.4.7/cmd/xfsdump/common/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/CVS/Entries Thu Jul 5 11:44:00 2001 @@ -0,0 +1,63 @@ +/Makefile/1.3/Mon Apr 30 03:51:30 2001/-ko/ +/arch_xlate.c/1.4/Tue May 15 04:05:35 2001/-ko/ +/arch_xlate.h/1.2/Mon Jan 15 04:32:19 2001/-ko/ +/archdep.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/archdep.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/attr.c/1.2/Fri Feb 9 07:45:14 2001/-ko/ +/attr.h/1.2/Fri Feb 9 07:45:14 2001/-ko/ +/cldmgr.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/cldmgr.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/cleanup.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/cleanup.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/content.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/content.h/1.2/Tue Apr 3 03:57:58 2001/-ko/ +/content_common.c/1.2/Mon Apr 9 06:32:28 2001/-ko/ +/content_common.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/content_inode.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/dlog.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/dlog.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/drive.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/drive.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/drive_minrmt.c/1.2/Mon Apr 9 06:32:28 2001/-ko/ +/drive_scsitape.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/drive_simple.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/exit.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/fs.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/fs.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/getdents.c/1.3/Mon Apr 9 06:32:28 2001/-ko/ +/getdents.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/global.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/global.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/inventory.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/inventory.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/inventory_priv.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/inventory_priv.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/lock.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/lock.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/main.c/1.4/Thu Jul 5 08:42:14 2001/-ko/ +/media.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/media.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/media_rmvtape.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/mlog.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/mlog.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/namreg.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/namreg.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/openutil.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/openutil.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/path.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/path.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/qlock.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/qlock.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/rec_hdr.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/ring.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/ring.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/sproc.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/sproc.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/stkchk.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/stkchk.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/stream.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/stream.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/types.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/util.c/1.2/Tue Apr 3 03:57:58 2001/-ko/ +/util.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/common/CVS/Repository linux-2.4-xfs/cmd/xfsdump/common/CVS/Repository --- linux-2.4.7/cmd/xfsdump/common/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/CVS/Repository Thu Jul 5 11:43:49 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/common diff -rNu linux-2.4.7/cmd/xfsdump/common/CVS/Root linux-2.4-xfs/cmd/xfsdump/common/CVS/Root --- linux-2.4.7/cmd/xfsdump/common/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/CVS/Root Thu Jul 5 11:43:49 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/common/Makefile linux-2.4-xfs/cmd/xfsdump/common/Makefile --- linux-2.4.7/cmd/xfsdump/common/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/Makefile Sun Apr 29 22:51:30 2001 @@ -0,0 +1,49 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LSRCFILES = arch_xlate.c arch_xlate.h archdep.c archdep.h attr.c attr.h \ + cldmgr.c cldmgr.h cleanup.c cleanup.h content.c content.h \ + content_common.c content_common.h content_inode.h dlog.c dlog.h \ + drive.c drive.h drive_minrmt.c drive_scsitape.c drive_simple.c \ + exit.h fs.c fs.h getdents.c getdents.h global.c global.h \ + inventory.c inventory.h inventory_priv.c inventory_priv.h \ + lock.c lock.h main.c media.c media.h media_rmvtape.h mlog.c mlog.h \ + namreg.c namreg.h openutil.c openutil.h path.c path.h qlock.c qlock.h \ + rec_hdr.h ring.c ring.h sproc.c sproc.h stkchk.c stkchk.h stream.c \ + stream.h types.h util.c util.h + +default install install-dev : + +include $(BUILDRULES) diff -rNu linux-2.4.7/cmd/xfsdump/common/arch_xlate.c linux-2.4-xfs/cmd/xfsdump/common/arch_xlate.c --- linux-2.4.7/cmd/xfsdump/common/arch_xlate.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/arch_xlate.c Mon May 14 23:05:35 2001 @@ -0,0 +1,660 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include "arch_xlate.h" +#include "types.h" +#include "global.h" +#include "content.h" +#include "content_inode.h" +#include "drive.h" +#include "media.h" +#include "inomap.h" +#include "rec_hdr.h" +#include "inv_priv.h" +#include "mlog.h" + +#define IXLATE(a1,a2,MEMBER) \ + INT_XLATE((a1)->MEMBER, (a2)->MEMBER, dir, ARCH_CONVERT) +#define BXLATE(MEMBER) \ + bcopy(&(ptr1)->MEMBER, &(ptr2)->MEMBER, sizeof((ptr1)->MEMBER)) + +/* + * xlate_global_hdr - endian convert struct global_hdr + * + * Note: gh_upper field is not converted. This must be done elsewhere + * at the time of assignment, because its contents are unknown. + */ +void +xlate_global_hdr(global_hdr_t *gh1, global_hdr_t *gh2, int dir) +{ + global_hdr_t *ptr1 = gh1; + global_hdr_t *ptr2 = gh2; + + IXLATE(gh1, gh2, gh_version); + IXLATE(gh1, gh2, gh_timestamp); + IXLATE(gh1, gh2, gh_ipaddr); + IXLATE(gh1, gh2, gh_checksum); + + if (dir < 0) { + ptr1 = gh2; + ptr2 = gh1; + } + + BXLATE(gh_magic); + BXLATE(gh_dumpid); + BXLATE(gh_hostname); + BXLATE(gh_dumplabel); + BXLATE(gh_upper); + BXLATE(gh_pad1); + BXLATE(gh_pad2); + BXLATE(gh_pad3); + + mlog(MLOG_NITTY, "xlate_global_hdr: pre-xlate\n" + "\tgh_magic %.100s\n" + "\tgh_version %u\n" + "\tgh_checksum %u\n" + "\tgh_timestamp %u\n" + "\tgh_ipaddr %llu\n" + "\tgh_hostname %.100s\n" + "\tgh_dumplabel %.100s\n", + ptr1->gh_magic, + ptr1->gh_version, + ptr1->gh_checksum, + ptr1->gh_timestamp, + ptr1->gh_ipaddr, + ptr1->gh_hostname, + ptr1->gh_dumplabel); + + mlog(MLOG_NITTY, "xlate_global_hdr: post-xlate\n" + "\tgh_magic %.100s\n" + "\tgh_version %u\n" + "\tgh_checksum %u\n" + "\tgh_timestamp %u\n" + "\tgh_ipaddr %llu\n" + "\tgh_hostname %.100s\n" + "\tgh_dumplabel %.100s\n", + ptr2->gh_magic, + ptr2->gh_version, + ptr2->gh_checksum, + ptr2->gh_timestamp, + ptr2->gh_ipaddr, + ptr2->gh_hostname, + ptr2->gh_dumplabel); + +} + +/* + * xlate_drive_hdr - endian convert struct xlate_drive_hdr + * which is loaded into global_hdr.gh_upper + */ +void +xlate_drive_hdr(drive_hdr_t *dh1, drive_hdr_t *dh2, int dir) +{ + drive_hdr_t *ptr1 = dh1; + drive_hdr_t *ptr2 = dh2; + + IXLATE(dh1, dh2, dh_drivecnt); + IXLATE(dh1, dh2, dh_driveix); + IXLATE(dh1, dh2, dh_strategyid); + + if (dir < 0) { + ptr1 = dh2; + ptr2 = dh1; + } + + BXLATE(dh_pad1); + BXLATE(dh_specific); + BXLATE(dh_upper); + + mlog(MLOG_NITTY, "xlate_drive_hdr: pre-xlate\n" + "\tdh_drivecnt %u\n" + "\tdh_driveix %u\n" + "\tdh_strategyid %d\n" + "\tdh_pad1 %s\n" + "\tdh_specific %s\n" + "\tdh_upper %s\n", + ptr1->dh_drivecnt, + ptr1->dh_driveix, + ptr1->dh_strategyid, + ptr1->dh_pad1, + ptr1->dh_specific, + ptr1->dh_upper); + + mlog(MLOG_NITTY, "xlate_drive_hdr: post-xlate\n" + "\tdh_drivecnt %u\n" + "\tdh_driveix %u\n" + "\tdh_strategyid %d\n" + "\tdh_pad1 %s\n" + "\tdh_specific %s\n" + "\tdh_upper %s\n", + ptr2->dh_drivecnt, + ptr2->dh_driveix, + ptr2->dh_strategyid, + ptr2->dh_pad1, + ptr2->dh_specific, + ptr2->dh_upper); +} + +/* + * xlate_media_hdr - endian convert struct media_hdr + * which is loaded into drive_hdr.dh_upper + */ +void +xlate_media_hdr(media_hdr_t *mh1, media_hdr_t *mh2, int dir) +{ + media_hdr_t *ptr1 = mh1; + media_hdr_t *ptr2 = mh2; + + mlog(MLOG_NITTY, "xlate_media_hdr\n"); + + IXLATE(mh1, mh2, mh_mediaix); + IXLATE(mh1, mh2, mh_mediafileix); + IXLATE(mh1, mh2, mh_dumpfileix); + IXLATE(mh1, mh2, mh_dumpmediafileix); + IXLATE(mh1, mh2, mh_dumpmediaix); + IXLATE(mh1, mh2, mh_strategyid); + + if (dir < 0) { + ptr1 = mh2; + ptr2 = mh1; + } + + BXLATE(mh_medialabel); + BXLATE(mh_prevmedialabel); + BXLATE(mh_pad1); + BXLATE(mh_mediaid); + BXLATE(mh_prevmediaid); + BXLATE(mh_pad2); + BXLATE(mh_pad3); + BXLATE(mh_specific); + BXLATE(mh_upper); +} + +/* + * xlate_content_hdr - endian convert struct content_hdr + * which is loaded into media_hdr.mh_upper + */ +void +xlate_content_hdr(content_hdr_t *ch1, content_hdr_t *ch2, int dir) +{ + content_hdr_t *ptr1 = ch1; + content_hdr_t *ptr2 = ch2; + + mlog(MLOG_NITTY, "xlate_content_hdr\n"); + + IXLATE(ch1, ch2, ch_strategyid); + + if (dir < 0) { + ptr1 = ch2; + ptr2 = ch1; + } + + BXLATE(ch_mntpnt); + BXLATE(ch_fsdevice); + BXLATE(ch_pad1); + BXLATE(ch_fstype); + BXLATE(ch_fsid); + BXLATE(ch_pad2); + BXLATE(ch_pad3); + BXLATE(ch_pad4); + BXLATE(ch_specific); +} + +/* + * xlate_content_inode_hdr - endian convert struct content_inode_hdr + * which is loaded into content_hdr.ch_specific + */ +void +xlate_content_inode_hdr(content_inode_hdr_t *cih1, content_inode_hdr_t *cih2, int dir) +{ + content_inode_hdr_t *ptr1 = cih1; + content_inode_hdr_t *ptr2 = cih2; + + mlog(MLOG_NITTY, "xlate_content_inode_hdr\n"); + + IXLATE(cih1, cih2, cih_mediafiletype); + IXLATE(cih1, cih2, cih_dumpattr); + IXLATE(cih1, cih2, cih_level); + IXLATE(cih1, cih2, cih_last_time); + IXLATE(cih1, cih2, cih_resume_time); + IXLATE(cih1, cih2, cih_rootino); + IXLATE(cih1, cih2, cih_inomap_hnkcnt); + IXLATE(cih1, cih2, cih_inomap_segcnt); + IXLATE(cih1, cih2, cih_inomap_dircnt); + IXLATE(cih1, cih2, cih_inomap_nondircnt); + IXLATE(cih1, cih2, cih_inomap_firstino); + IXLATE(cih1, cih2, cih_inomap_lastino); + IXLATE(cih1, cih2, cih_inomap_datasz); + + if (dir < 0) { + ptr1 = cih2; + ptr2 = cih1; + } + + BXLATE(pad1); + BXLATE(cih_last_id); + BXLATE(cih_resume_id); + BXLATE(cih_pad2); + + xlate_startpt(&cih1->cih_startpt, &cih2->cih_startpt, dir); + xlate_startpt(&cih1->cih_endpt, &cih2->cih_endpt, dir); +} + +/* + * xlate_startpt - endian convert struct startpt + */ +void +xlate_startpt(startpt_t *sp1, startpt_t *sp2, int dir) +{ + mlog(MLOG_NITTY, "xlate_startpt\n"); + + IXLATE(sp1, sp2, sp_ino); + IXLATE(sp1, sp2, sp_offset); + IXLATE(sp1, sp2, sp_flags); + IXLATE(sp1, sp2, sp_pad1); +} + +/* + * xlate_hnk - endian convert struct hnk + * Note: struct hnk is defined in 3 different inomap.c files but they're + * all the same. + */ +void +xlate_hnk(hnk_t *h1, hnk_t *h2, int dir) +{ + hnk_t *ptr1 = h1; + hnk_t *ptr2 = h2; + int i; + + mlog(MLOG_NITTY, "pre - xlate_hnk\n"); + + for(i = 0; i < SEGPERHNK; i++) { + IXLATE(h1, h2, seg[i].base); + IXLATE(h1, h2, seg[i].lobits); + IXLATE(h1, h2, seg[i].mebits); + IXLATE(h1, h2, seg[i].hibits); + } + + IXLATE(h1, h2, maxino); + h2->nextp = NULL; + + if (dir < 0) { + ptr1 = h2; + ptr2 = h1; + } + + BXLATE(pad); + + mlog(MLOG_NITTY, "post - xlate_hnk\n"); +} + +/* + * xlate_filehdr - endian convert struct filehdr + */ +void +xlate_filehdr(filehdr_t *fh1, filehdr_t *fh2, int dir) +{ + filehdr_t *ptr1 = fh1; + filehdr_t *ptr2 = fh2; + + IXLATE(fh1, fh2, fh_offset); + IXLATE(fh1, fh2, fh_flags); + IXLATE(fh1, fh2, fh_checksum); + xlate_bstat(&fh1->fh_stat, &fh2->fh_stat, dir); + + if (dir < 0) { + ptr1 = fh2; + ptr2 = fh1; + } + + BXLATE(fh_pad2); + + mlog(MLOG_NITTY, "xlate_filehdr: pre-xlate\n" + "\tfh_offset %llu\n" + "\tfh_flags %llu\n" + "\tfh_checksum %llu\n", + ptr1->fh_offset, + ptr1->fh_flags, + ptr1->fh_checksum); + + mlog(MLOG_NITTY, "xlate_filehdr: post-xlate\n" + "\tfh_offset %llu\n" + "\tfh_flags %llu\n" + "\tfh_checksum %llu\n", + ptr2->fh_offset, + ptr2->fh_flags, + ptr2->fh_checksum); +} + +/* + * xlate_bstat - endian convert struct bstat + */ +void +xlate_bstat(bstat_t *bs1, bstat_t *bs2, int dir) +{ + bstat_t *ptr1 = bs1; + bstat_t *ptr2 = bs2; + + mlog(MLOG_NITTY, "xlate_bstat\n"); + + IXLATE(bs1, bs2, bs_ino); + IXLATE(bs1, bs2, bs_mode); + IXLATE(bs1, bs2, bs_nlink); + IXLATE(bs1, bs2, bs_uid); + IXLATE(bs1, bs2, bs_gid); + IXLATE(bs1, bs2, bs_rdev); + IXLATE(bs1, bs2, bs_blksize); + IXLATE(bs1, bs2, bs_size); + + IXLATE(bs1, bs2, bs_atime.tv_sec); + IXLATE(bs1, bs2, bs_atime.tv_nsec); + IXLATE(bs1, bs2, bs_mtime.tv_sec); + IXLATE(bs1, bs2, bs_mtime.tv_nsec); + IXLATE(bs1, bs2, bs_ctime.tv_sec); + IXLATE(bs1, bs2, bs_ctime.tv_nsec); + + IXLATE(bs1, bs2, bs_blocks); + IXLATE(bs1, bs2, bs_xflags); + IXLATE(bs1, bs2, bs_extsize); + IXLATE(bs1, bs2, bs_extents); + IXLATE(bs1, bs2, bs_gen); + IXLATE(bs1, bs2, bs_dmevmask); + IXLATE(bs1, bs2, bs_dmstate); + + if (dir < 0) { + ptr1 = bs2; + ptr2 = bs1; + } + + BXLATE(bs_uuid); + BXLATE(bs_pad1); + + mlog(MLOG_NITTY, "xlate_bstat: pre-xlate\n" + "\tbs_ino %llu\n" + "\tbs_mode %lo\n", + ptr1->bs_ino, + ptr1->bs_mode); + + mlog(MLOG_NITTY, "xlate_bstat: post-xlate\n" + "\tbs_ino %llu\n" + "\tbs_mode %lo\n", + ptr2->bs_ino, + ptr2->bs_mode); + +} + +/* + * xlate_extenthdr - endian convert struct extenthdr + */ +void +xlate_extenthdr(extenthdr_t *eh1, extenthdr_t *eh2, int dir) +{ + extenthdr_t *ptr1 = eh1; + extenthdr_t *ptr2 = eh2; + + mlog(MLOG_NITTY, "xlate_extenthdr\n"); + + IXLATE(eh1, eh2, eh_sz); + IXLATE(eh1, eh2, eh_offset); + IXLATE(eh1, eh2, eh_type); + IXLATE(eh1, eh2, eh_flags); + IXLATE(eh1, eh2, eh_checksum); + + if (dir < 0) { + ptr1 = eh2; + ptr2 = eh1; + } + + BXLATE(eh_pad); +} + +/* + * xlate_direnthdr - endian convert struct direnthdr + */ +void +xlate_direnthdr(direnthdr_t *dh1, direnthdr_t *dh2, int dir) +{ + direnthdr_t *ptr1 = dh1; + direnthdr_t *ptr2 = dh2; + + IXLATE(dh1, dh2, dh_ino); + IXLATE(dh1, dh2, dh_gen); + IXLATE(dh1, dh2, dh_sz); + IXLATE(dh1, dh2, dh_checksum); + + if (dir < 0) { + ptr1 = dh2; + ptr2 = dh1; + } + + BXLATE(dh_name); + + mlog(MLOG_NITTY, "xlate_direnthdr: pre-xlate\n" + "\tdh_ino %llu\n" + "\tdh_gen %d\n" + "\tdh_sz %d\n" + "\tdh_checksum %d\n" + "\tdh_name %.8s\n", + ptr1->dh_ino, + ptr1->dh_gen, + ptr1->dh_sz, + ptr1->dh_checksum, + ptr1->dh_name ); + + mlog(MLOG_NITTY, "xlate_direnthdr: post-xlate\n" + "\tdh_ino %llu\n" + "\tdh_gen %d\n" + "\tdh_sz %d\n" + "\tdh_checksum %d\n" + "\tdh_name %.8s\n", + ptr2->dh_ino, + ptr2->dh_gen, + ptr2->dh_sz, + ptr2->dh_checksum, + ptr2->dh_name ); +} + +#ifdef EXTATTR +/* + * xlate_extattrhdr - endian convert struct extattrhdr + */ +void +xlate_extattrhdr(extattrhdr_t *eh1, extattrhdr_t *eh2, int dir) +{ + mlog(MLOG_NITTY, "xlate_extattrhdr\n"); + + IXLATE(eh1, eh2, ah_sz); + IXLATE(eh1, eh2, ah_valoff); + IXLATE(eh1, eh2, ah_flags); + IXLATE(eh1, eh2, ah_valsz); + IXLATE(eh1, eh2, ah_checksum); +} +#endif /* EXTATTR */ + +/* + * xlate_rec_hdr - endian convert struct rec_hdr + */ +void +xlate_rec_hdr(rec_hdr_t *rh1, rec_hdr_t *rh2, int dir) +{ + rec_hdr_t *ptr1 = rh1; + rec_hdr_t *ptr2 = rh2; + + mlog(MLOG_NITTY, "xlate_rec_hdr\n"); + + IXLATE(rh1, rh2, magic); + IXLATE(rh1, rh2, version); + IXLATE(rh1, rh2, blksize); + IXLATE(rh1, rh2, recsize); + IXLATE(rh1, rh2, capability); + IXLATE(rh1, rh2, file_offset); + IXLATE(rh1, rh2, first_mark_offset); + IXLATE(rh1, rh2, rec_used); + IXLATE(rh1, rh2, checksum); + IXLATE(rh1, rh2, ischecksum); + + if (dir < 0) { + ptr1 = rh2; + ptr2 = rh1; + } + + BXLATE(pad1); + BXLATE(dump_uuid); + BXLATE(pad2); +} + +/* + * endian convert inventory structures + */ +void +xlate_invt_seshdr(invt_seshdr_t *ish1, invt_seshdr_t *ish2, int dir) +{ + invt_seshdr_t *ptr1 = ish1; + invt_seshdr_t *ptr2 = ish2; + + mlog(MLOG_NITTY, "xlate_invt_seshdr\n"); + + IXLATE(ish1, ish2, sh_sess_off); + IXLATE(ish1, ish2, sh_streams_off); + IXLATE(ish1, ish2, sh_time); + IXLATE(ish1, ish2, sh_flag); + + if (dir < 0) { + ptr1 = ish2; + ptr2 = ish1; + } + + BXLATE(sh_level); + BXLATE(sh_pruned); + BXLATE(sh_padding); +} + +void +xlate_invt_session(invt_session_t *is1, invt_session_t *is2, int dir) +{ + invt_session_t *ptr1 = is1; + invt_session_t *ptr2 = is2; + + mlog(MLOG_NITTY, "xlate_invt_session\n"); + + IXLATE(is1, is2, s_cur_nstreams); + IXLATE(is1, is2, s_max_nstreams); + + if (dir < 0) { + ptr1 = is2; + ptr2 = is1; + } + + BXLATE(s_sesid); + BXLATE(s_fsid); + BXLATE(s_label); + BXLATE(s_mountpt); + BXLATE(s_devpath); + BXLATE(s_padding); + + mlog(MLOG_NITTY, "xlate_invt_session: pre-xlate\n" + "\ts_cur_nstreams %u\n" + "\ts_max_nstreams %u\n", + ptr1->s_cur_nstreams, + ptr1->s_max_nstreams); + + mlog(MLOG_NITTY, "xlate_invt_session: post-xlate\n" + "\ts_cur_nstreams %u\n" + "\ts_max_nstreams %u\n", + ptr2->s_cur_nstreams, + ptr2->s_max_nstreams); + +} + +void +xlate_invt_breakpt(invt_breakpt_t *ib1, invt_breakpt_t *ib2, int dir) +{ + mlog(MLOG_NITTY, "xlate_invt_breakpt\n"); + + IXLATE(ib1, ib2, ino); + IXLATE(ib1, ib2, offset); +} + +void +xlate_invt_stream(invt_stream_t *ist1, invt_stream_t *ist2, int dir) +{ + invt_stream_t *ptr1 = ist1; + invt_stream_t *ptr2 = ist2; + + mlog(MLOG_NITTY, "xlate_invt_stream\n"); + + IXLATE(ist1, ist2, st_firstmfile); + IXLATE(ist1, ist2, st_lastmfile); + IXLATE(ist1, ist2, st_nmediafiles); + IXLATE(ist1, ist2, st_interrupted); + + if (dir < 0) { + ptr1 = ist2; + ptr2 = ist1; + } + + BXLATE(st_cmdarg); + BXLATE(st_padding); + + xlate_invt_breakpt(&ist1->st_startino, &ist2->st_startino, dir); + xlate_invt_breakpt(&ist1->st_endino, &ist2->st_endino, dir); +} + +void +xlate_invt_mediafile(invt_mediafile_t *im1, invt_mediafile_t *im2, int dir) +{ + invt_mediafile_t *ptr1 = im1; + invt_mediafile_t *ptr2 = im2; + + mlog(MLOG_NITTY, "xlate_invt_mediafile\n"); + + IXLATE(im1, im2, mf_nextmf); + IXLATE(im1, im2, mf_prevmf); + IXLATE(im1, im2, mf_mfileidx); + IXLATE(im1, im2, mf_size); + + if (dir < 0) { + ptr1 = im2; + ptr2 = im1; + } + + BXLATE(mf_moid); + BXLATE(mf_label); + BXLATE(mf_flag); + BXLATE(mf_padding); + + xlate_invt_breakpt(&im1->mf_startino, &im2->mf_startino, dir); + xlate_invt_breakpt(&im1->mf_endino, &im2->mf_endino, dir); +} diff -rNu linux-2.4.7/cmd/xfsdump/common/arch_xlate.h linux-2.4-xfs/cmd/xfsdump/common/arch_xlate.h --- linux-2.4.7/cmd/xfsdump/common/arch_xlate.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/arch_xlate.h Sun Jan 14 22:32:19 2001 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef ARCH_XLATE_H +#define ARCH_XLATE_H + +#include +#include +#include + +#include "types.h" +#include "global.h" +#include "content.h" +#include "content_inode.h" +#include "drive.h" +#include "media.h" +#include "inomap.h" +#include "rec_hdr.h" +#include "inv_priv.h" + + +/* + * xlate_global_hdr - endian convert struct global_hdr + * + * Note: gh_upper field is not converted. This must be done elsewhere + * at the time of assignment, because its contents are unknown. + */ +void xlate_global_hdr(global_hdr_t *gh1, global_hdr_t *gh2, int dir); + +/* + * xlate_drive_hdr - endian convert struct xlate_drive_hdr + * which is loaded as the gh_upper field on the global header + */ +void xlate_drive_hdr(drive_hdr_t *dh1, drive_hdr_t *dh2, int dir); + +/* + * xlate_media_hdr - endian convert struct media_hdr + * which is loaded into drive_hdr.dh_upper + */ +void xlate_media_hdr(media_hdr_t *mh1, media_hdr_t *mh2, int dir); + +/* + * xlate_content_hdr - endian convert struct content_hdr + * which is loaded into media_hdr.mh_upper + */ +void xlate_content_hdr(content_hdr_t *ch1, content_hdr_t *ch2, int dir); + +/* + * xlate_content_inode_hdr - endian convert struct content_inode_hdr + * which is loaded into content_hdr.ch_specific + */ +void xlate_content_inode_hdr(content_inode_hdr_t *cih1, content_inode_hdr_t *cih2, int dir); + +/* + * xlate_startpt - endian convert struct startpt + */ +void xlate_startpt(startpt_t *sp1, startpt_t *sp2, int dir); + +/* + * xlate_hnk - endian convert struct hnk + * Note: struct hnk is defined in 3 different inomap.h files but they're + * all the same. Bad things will happen if they're not... + */ +void xlate_hnk(hnk_t *h1, hnk_t *h2, int dir); + +/* + * xlate_filehdr - endian convert struct filehdr + */ +void xlate_filehdr(filehdr_t *fh1, filehdr_t *fh2, int dir); + +/* + * xlate_bstat - endian convert struct bstat + */ +void xlate_bstat(bstat_t *bs1, bstat_t *bs2, int dir); + +/* + * xlate_extenthdr - endian convert struct extenthdr + */ +void xlate_extenthdr(extenthdr_t *eh1, extenthdr_t *eh2, int dir); + +/* + * xlate_direnthdr - endian convert struct direnthdr + */ +void xlate_direnthdr(direnthdr_t *dh1, direnthdr_t *dh2, int dir); + +#ifdef EXTATTR +/* + * xlate_extattrhdr - endian convert struct extattrhdr + */ +void xlate_extattrhdr(extattrhdr_t *eh1, extattrhdr_t *eh2, int dir); +#endif /* EXTATTR */ + +/* + * xlate_rec_hdr - endian convert struct rec_hdr + */ +void xlate_rec_hdr(rec_hdr_t *rh1, rec_hdr_t *rh2, int dir); + +/* + * endian convert inventory structures + */ +void xlate_invt_seshdr(invt_seshdr_t *ish1, invt_seshdr_t *ish2, int dir); +void xlate_invt_session(invt_session_t *is1, invt_session_t *is2, int dir); +void xlate_invt_breakpt(invt_breakpt_t *ib1, invt_breakpt_t *ib2, int dir); +void xlate_invt_stream(invt_stream_t *ist1, invt_stream_t *ist2, int dir); +void xlate_invt_mediafile(invt_mediafile_t *im1, invt_mediafile_t *im2, int dir); + +#endif /* ARCH_XLATE_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/archdep.c linux-2.4-xfs/cmd/xfsdump/common/archdep.c --- linux-2.4.7/cmd/xfsdump/common/archdep.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/archdep.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,837 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "archdep.h" +#include "util.h" +#include "cleanup.h" +#include "mlog.h" +#include "namreg.h" + +extern char *homedir; + +/* template for the name of the tmp file containing the simulation tree + */ +#define NAMETEMPLATE "xfssimmap" + +/* node for internal simulation + */ +struct node { + xfs_ino_t n_ino; + namreg_ix_t n_namreg_ix; + intgen_t n_lnkcnt; + struct node *n_parp; +}; + +typedef struct node node_t; + +static void ino2path_init( fshandle_t, char * ); +static char * ino2path( xfs_ino_t, char *, size_t ); +static intgen_t ino2path_count_cb( void *, fshandle_t, xfs_bstat_t * ); +static intgen_t ino2path_init_cb( void *, fshandle_t, xfs_bstat_t * ); +static void ino2path_init_recurse( node_t * ); +static char * ino2path_recurse( node_t *, char *, size_t ); +static node_t * ino2path_i2n( xfs_ino_t ); +static void ino2path_abort_cleanup( void *, void * ); + +fshandle_t +archdep_getfshandle( char *mntpnt ) +{ + int fd; + fd = open( mntpnt, O_RDONLY ); + if ( fd < 0 ) { + mlog( MLOG_NORMAL, + "unable to open %s: %s\n", + mntpnt, + strerror( errno )); + return ( fshandle_t )FSHANDLE_NULL; + } + + /* create the ino2path abstraction + */ + ino2path_init( ( fshandle_t )fd, mntpnt ); + + return ( fshandle_t )fd; +} + + +archdep_getdents_context_t * +archdep_getdents_context_alloc( fshandle_t fshandle, xfs_bstat_t *statp ) +{ + archdep_getdents_context_t *contextp; + char pathbuf[ 257 ]; + char *pathp; + + /* allocate a context + */ + contextp = ( archdep_getdents_context_t * ) + calloc( 1, sizeof( archdep_getdents_context_t )); + ASSERT( contextp ); + + + /* first get a pathname to the directory + */ + ASSERT( ( statp->bs_mode & S_IFMT ) == S_IFDIR ); + pathp = ino2path( statp->bs_ino, pathbuf, sizeof( pathbuf )); + + /* if can't find path, must be a new directory not present + * when the simulator was initialized. print a warning, and + * pretend it is an empty directory. + */ + if ( ! pathp ) { + mlog( MLOG_NORMAL, + "getdents sim: directory ino %llu not in sim map\n", + statp->bs_ino ); + contextp->gd_dirp = 0; + return contextp; + } + + /* prepare the kernel's readdir() context + */ + contextp->gd_dirp = opendir( pathp ); + ASSERT( contextp->gd_dirp ); + contextp->gd_cached = BOOL_FALSE; + + return contextp; +} + +void +archdep_getdents_context_free( archdep_getdents_context_t *contextp ) +{ + intgen_t rval; + + if ( contextp->gd_dirp ) { + rval = closedir( contextp->gd_dirp ); + ASSERT( rval == 0 ); + } + + free( contextp ); +} + +#ifdef OBSOLETE +intgen_t +archdep_getdents( archdep_getdents_context_t *contextp, + char *bufp, + size_t bufsz ) +{ + char debuf[ 2 * sizeof( struct dirent ) + NAME_MAX + 1 ]; + /* temp. hold system dirents */ + struct dirent *dep = ( struct dirent * )debuf; + size_t donesz; /* number of bytes placed in caller's buffer */ + + donesz = 0; + + /* if dir not in simulator map, + * just return 0 (pretend no dirents ). + */ + if ( ! contextp->gd_dirp ) { + return 0; + } + + /* if one in the cache, use it first + */ + if ( contextp->gd_cached ) { + size_t namesz; + size_t recsz; + register archdep_getdents_entry_t *p; + register char *cp; + register char *ep; + + /* overlay a getdents_t on the caller's buffer + */ + p = ( archdep_getdents_entry_t * )bufp; + + /* check if the remaining space in the caller's buffer + * is sufficient + */ + namesz = contextp->gd_cachedsz; + recsz = sizeof( archdep_getdents_entry_t ) + + + namesz + + + 1 + - + sizeof( p->ge_name ); + recsz = ( recsz + ARCHDEP_GETDENTS_ALIGN - 1 ) + & + ~( ARCHDEP_GETDENTS_ALIGN - 1 ); + if ( bufsz < recsz ) { + return -1; + } + + mlog( MLOG_NITTY, + "cached dirent ino = %llu len == %d name == %s\n", + contextp->gd_cachedino, + contextp->gd_cachedsz, + contextp->gd_cachedname ); + + /* copy the entry into the caller's buffer + */ + p->ge_ino = contextp->gd_cachedino; + p->ge_sz = recsz; + ( void )strcpy( p->ge_name, contextp->gd_cachedname ); + + /* null the padding (not necessary, good for debugging) + */ + cp = p->ge_name + + + contextp->gd_cachedsz + + + 1; + ep = ( char * )p + recsz; + for ( ; cp < ep ; cp++ ) { + *cp = 0; + } + + bufsz -= recsz; + donesz += recsz; + bufp += recsz; + + contextp->gd_cached = BOOL_FALSE; + } + + /* loop until we've exhausted the directory, or used up the caller's + * buffer + */ + errno = 0; /* to detect when readdir_r returns zero due to error */ + while ( ( dep = readdir64_r( contextp->gd_dirp, dep )) != 0 ) { + size_t namesz; + size_t recsz; + register archdep_getdents_entry_t *p; + register char *cp; + register char *ep; + + ASSERT( dep == ( struct dirent * )debuf ); + + /* skip "." and ".." + */ + if ( *( dep->d_name + 0 ) == '.' + && + ( *( dep->d_name + 1 ) == 0 + || + ( *( dep->d_name + 1 ) == '.' + && + *( dep->d_name + 2 ) == 0 ))) { + errno = 0; + continue; + } + + /* overlay a getdents_t on the caller's buffer + */ + p = ( archdep_getdents_entry_t * )bufp; + + /* check if the remaining space in the caller's buffer + * is sufficient. if not, cache the entry and return. + */ + namesz = ( size_t )strlen( dep->d_name ); + recsz = sizeof( archdep_getdents_entry_t ) + + + namesz + + + 1 + - + sizeof( p->ge_name ); + recsz = ( recsz + ARCHDEP_GETDENTS_ALIGN - 1 ) + & + ~( ARCHDEP_GETDENTS_ALIGN - 1 ); + if ( bufsz < recsz ) { + contextp->gd_cachedino = ( xfs_ino_t )dep->d_ino; + ASSERT( namesz < sizeof( contextp->gd_cachedname )); + contextp->gd_cachedsz = namesz; + strcpy( contextp->gd_cachedname, dep->d_name ); + contextp->gd_cached = BOOL_TRUE; + if ( donesz == 0 ) { + return -1; + } else { + errno = 0; + break; + } + } + + mlog( MLOG_NITTY, + "dirent ino = %d len == %d name == %s\n", + dep->d_ino, + dep->d_reclen, + dep->d_name ); + + /* copy the entry into the caller's buffer + */ + p->ge_ino = ( xfs_ino_t )dep->d_ino; + p->ge_sz = recsz; + ( void )strcpy( p->ge_name, dep->d_name ); + + /* null the padding (not necessary, good for debugging) + */ + cp = p->ge_name + + + strlen( dep->d_name ) + + + 1; + ep = ( char * )p + recsz; + for ( ; cp < ep ; cp++ ) { + *cp = 0; + } + + bufsz -= recsz; + donesz += recsz; + bufp += recsz; + errno = 0; + } + if ( errno ) { + mlog( MLOG_NORMAL, + "getdir_r sets errno to %s\n", + strerror( errno )); + } + ASSERT( errno == 0 ); + + ASSERT( donesz < ( size_t )INTGENMAX ); + return ( intgen_t )donesz; +} +#endif /* OBSOLETE */ + +archdep_getbmap_context_t * +archdep_getbmap_context_alloc( fshandle_t fshandle, xfs_bstat_t *statp ) +{ + archdep_getbmap_context_t *contextp; + char pathbuf[ 257 ]; + char *pathp; + + contextp = ( archdep_getbmap_context_t * ) + calloc( 1, sizeof( archdep_getbmap_context_t )); + ASSERT( contextp ); + + ASSERT( ( statp->bs_mode & S_IFMT ) == S_IFREG ); + + /* first get a pathname to the file + */ + pathp = ino2path( statp->bs_ino, pathbuf, sizeof( pathbuf )); + + /* if there is no path, return NULL. we will simulate this + * file by assuming it has no extents. + */ + if ( ! pathp ) { + mlog( MLOG_DEBUG, + "WARNING: bmap sim: no pathname(s) for ino %llu\n", + statp->bs_ino ); + contextp->gb_fd = -1; + return contextp; + } + + /* open the file for reading + */ + contextp->gb_fd = open( pathp, O_RDONLY ); + ASSERT( contextp->gb_fd > 0 ); + + return contextp; +} + +void +archdep_getbmap_context_free( archdep_getbmap_context_t *ctxp ) +{ + intgen_t rval; + if ( ctxp->gb_fd != -1 ) { + rval = close( ctxp->gb_fd ); + ASSERT( rval == 0 ); + } + free( ( void * )ctxp ); +} + +intgen_t +archdep_getbmap( archdep_getbmap_context_t *ctxp, getbmap_t *bmapp ) +{ + intgen_t rval; + + if ( ctxp->gb_fd == -1 ) { + ( void )memset( ( void * )bmapp, 0, sizeof( *bmapp )); + return 0; + } + rval = fcntl( ctxp->gb_fd, F_GETBMAP, bmapp ); + return rval; +} + +intgen_t +archdep_read( archdep_getbmap_context_t *contextp, + off64_t off, + char *bufp, + size_t sz ) +{ + off64_t new_off; + intgen_t nread; + + new_off = lseek64( contextp->gb_fd, off, SEEK_SET ); + + if ( new_off == ( off64_t )( -1 )) { + return -1; + } + + nread = read( contextp->gb_fd, bufp, sz ); + return nread; +} + +intgen_t +archdep_readlink( fshandle_t fshandle, + xfs_bstat_t *statp, + char *bufp, + size_t bufsz ) +{ + char pathbuf[ 257 ]; + char *pathp; + intgen_t rval; + + /* first get a pathname to the file + */ + pathp = ino2path( statp->bs_ino, pathbuf, sizeof( pathbuf )); + + /* if we can't find a path to this ino, return -1; the caller will + * handle it. + */ + if ( ! pathp ) { + mlog( MLOG_DEBUG, + "WARNING: readlink sim: no pathname(s) for ino %llu\n", + statp->bs_ino ); + return -1; + } + + /* call readlink(2) to get the link + */ + ASSERT( bufsz <= INTGENMAX ); /* readlink() proto wrong in unistd.h! */ + rval = readlink( pathp, ( void * )bufp, ( int )bufsz ); + + return rval; +} + +/* below is the ino - to - pathname map, needed to simulated ino-oriented + * system calls not yet implemented + */ +static node_t *i2p_nodep; +static size_t i2p_len; +static namreg_t *i2p_namregp; +static node_t *i2p_rootp; +static char *i2p_mntpnt; +static intgen_t i2p_fd; + +static void +ino2path_init( fshandle_t fshandle, char *mntpnt ) +{ + size_t ix; + intgen_t stat; + struct stat64 statbuf; + char namebuf[ 32 ]; + intgen_t rval; + + mlog( MLOG_VERBOSE, + "initializing ino-based syscall simulator ...\n" ); + + /* save the mount point: it will be prepended to all + * pathnames. + */ + i2p_mntpnt = mntpnt; + + /* use a namreg abstraction to hold the directory entry names + */ + i2p_namregp = namreg_init( BOOL_FALSE, + BOOL_FALSE, + homedir ); + + /* use bigstat_iter() to count the number of inos + */ + mlog( MLOG_VERBOSE, + "phase 1: counting inos\n" ); + i2p_len = 0; + rval = bigstat_iter( fshandle, + BIGSTAT_ITER_ALL, + 0, + ino2path_count_cb, + 0, + &stat ); + ASSERT( ! rval ); + + /* allocate space for that many inos + i2p_nodep = ( node_t * )calloc( i2p_len, sizeof( node_t )); + ASSERT( i2p_nodep ); + */ + + /* create the tmp file, first unlinking any older version laying around + */ + sprintf( namebuf, NAMETEMPLATE ); + ASSERT( strlen( namebuf ) < sizeof( namebuf )); + rval = unlink( namebuf ); + ASSERT( rval == 0 || errno == ENOENT ); + i2p_fd = open( namebuf, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR ); + if ( i2p_fd < 0 ) { + mlog( MLOG_NORMAL, + "creat of simulator file %s failed: %s\n", + namebuf, + strerror( errno )); + ASSERT( 0 ); + } + + ( void )cleanup_register( ino2path_abort_cleanup, + ( void * )homedir, + 0 ); + + /* mmap(2) the sim tmp file: NOTE: problem here with BIG files. + */ + ASSERT(( int64_t )i2p_len * ( int64_t )sizeof( node_t ) <= UINTGENMAX ); + i2p_nodep = ( node_t * )mmap( 0, + i2p_len * sizeof( node_t ), + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_AUTOGROW, + i2p_fd, + 0 ); + if ( i2p_nodep == ( node_t * )-1 ) { + mlog( MLOG_NORMAL, + "mmap of sim file %s failed: %s\n", + namebuf, + strerror( errno )); + ASSERT( 0 ); + } + + /* fill in the ino field of each node_t + */ + mlog( MLOG_VERBOSE, + "phase 2: initializing %d nodes\n", + i2p_len ); + ix = 0; + rval = bigstat_iter( fshandle, + BIGSTAT_ITER_ALL, + 0, + ino2path_init_cb, + ( void * )&ix, + &stat ); + ASSERT( ! rval ); + + /* if the second bigstat pass came up with fewer inos, + * the remaining nodes aren't initialized: don't use them + */ + if ( ix < i2p_len ) { + i2p_len = ix; + } + + + /* stat the mount point, to get the root ino + */ + rval = stat64( mntpnt, &statbuf ); + ASSERT( ! rval ); + i2p_rootp = ino2path_i2n( statbuf.st_ino ); + ASSERT( i2p_rootp ); + ASSERT( i2p_rootp->n_ino == statbuf.st_ino ); + i2p_rootp->n_lnkcnt = 1; + + /* cd to the mount point + */ + rval = chdir( mntpnt ); + ASSERT( ! rval ); + + /* recursively descend the fs tree, identifying the parent of + * each inode. + */ + mlog( MLOG_VERBOSE, + "phase 3: building tree (%d nodes)\n", + i2p_len ); + ino2path_init_recurse( i2p_rootp ); + + /* return to the original directory + */ + rval = chdir( homedir ); + ASSERT( ! rval ); + + mlog( MLOG_VERBOSE, + "initialization of ino-based syscall simulator complete\n" ); +} + +/* builds a null terminated pathname to the ino in the caller-supplied + * buffer. returns a pointer to somewhere in the buffer, not necessarily + * the beginning. + */ +static char * +ino2path( xfs_ino_t ino, char *bufp, size_t bufsz ) +{ + node_t *np; + char *p; + + mlog( MLOG_NITTY, + "simulator: mapping in %llu to pathname\n", + ino ); + + /* find the ino in the map. return 0 if not found + */ + np = ino2path_i2n( ino ); + if ( ! np ) { + return 0; + } + + /* null-terminate the caller-supplied buffer + */ + bufp[ bufsz - 1 ] = 0; + + /* ascend up the tree, building the pathname in reverse. + * the recursion function returns the head of the pathname, + * which may be anywhere within the caller-supplied buffer. + */ + p = ino2path_recurse( np, bufp, bufsz - 1 ); + + mlog( MLOG_NITTY, + "simulator: ino %llu is %s\n", + ino, + p ); + + return p; +} + +static char * +ino2path_recurse( node_t *np, char *bufp, size_t bufsz ) +{ + intgen_t rval; + size_t namsz; + + /* if this node has no links, return NULL: there is no + * corresponding pathname. + */ + if ( np->n_lnkcnt == 0 ) { + return 0; + } + + /* if this is the root, we are done: prepend the mount point, + * unless the mntpnt is "/", and at least one path element is + * already present in the buffer. + */ + if ( np == i2p_rootp ) { + ASSERT( bufsz >= strlen( i2p_mntpnt )); + if ( strcmp( i2p_mntpnt, "/" ) || bufp[ bufsz ] == 0 ) { + ( void )memcpy( ( void * )&bufp[ bufsz + - + strlen( i2p_mntpnt ) ], + ( void * )i2p_mntpnt, + strlen( i2p_mntpnt )); + bufsz -= strlen( i2p_mntpnt ); + } + return bufp + bufsz; + } + + /* load the node name into beginning of the buffer + */ + rval = namreg_get( i2p_namregp, np->n_namreg_ix, bufp, bufsz ); + ASSERT( rval >= 0 ); + namsz = ( size_t )rval; + ASSERT( namsz <= bufsz ); + + /* move the name to the tail of the buffer + */ + ( void )memmove( ( void * )( bufp + bufsz - namsz ), + ( void * )bufp, + namsz ); + bufsz -= namsz; + + /* pre-pend a 'slash' + */ + ASSERT( bufsz >= 1 ); + bufp[ bufsz - 1 ] = '/'; + bufsz--; + + /* ascend up the tree, building the pathname in reverse. + * the recursion function returns the head of the pathname, + * which may be anywhere within the caller-supplied buffer. + */ + ASSERT( np->n_parp ); + return ino2path_recurse( np->n_parp, bufp, bufsz ); +} + +static intgen_t +ino2path_count_cb( void *arg1, fshandle_t fshandle, xfs_bstat_t *statp ) +{ + i2p_len++; + return 0; +} + +static intgen_t +ino2path_init_cb( void *arg1, fshandle_t fshandle, xfs_bstat_t *statp ) +{ + size_t ix; + node_t *p; + + ix = *( size_t * )arg1; + if ( ix >= i2p_len ) { + /* ran out of room: more inos became active */ + return 1; + } + p = i2p_nodep + ix; + p->n_ino = statp->bs_ino; + p->n_namreg_ix = NAMREG_IX_NULL; + ix++; + ( * ( size_t * )arg1 )++; + return 0; +} + +static void +ino2path_init_recurse( node_t *parp ) +{ + DIR *dirp; + struct dirent *direntp; + intgen_t rval; + + /* open the current directory + */ + dirp = opendir( "." ); + ASSERT( dirp ); + + /* process each directory entry + */ + errno = 0; + while ( ( direntp = readdir64( dirp )) != 0 ) { + struct stat64 statbuf; + node_t *np; + xfs_ino_t ino; + bool_t isdir; + intgen_t rval; + + /* skip "." and ".." + */ + if ( ! strcmp( direntp->d_name, "." )) { + continue; + } + if ( ! strcmp( direntp->d_name, ".." )) { + continue; + } + + /* stat64() for the ino and type + */ + ASSERT( errno == 0 ); + rval = lstat64( direntp->d_name, &statbuf ); + ASSERT( ! rval ); + ino = statbuf.st_ino; + isdir = ( statbuf.st_mode & S_IFMT ) == S_IFDIR + ? + BOOL_TRUE + : + BOOL_FALSE; + + /* look the ino up in the map. if not there, must be + * a recent creation, so skip. + */ + np = ino2path_i2n( ino ); + if ( ! np ) { + continue; + } + + /* if already linked, forget it. only need one path to a + * given ino for simulation. + */ + np->n_lnkcnt++; + if ( np->n_lnkcnt > 1 ) { + ASSERT( ! isdir ); + continue; + } + np->n_parp = parp; + np->n_namreg_ix = namreg_add( i2p_namregp, + direntp->d_name, + strlen( direntp->d_name )); + + /* recurse for directories + */ + if ( isdir ) { + rval = chdir( direntp->d_name ); + ASSERT( ! rval ); + ino2path_init_recurse( np ); + rval = chdir( ".." ); + ASSERT( ! rval ); + } + + /* clear errno to detect if readdir() sets it + */ + errno = 0; + } + ASSERT( errno == 0 ); + + rval = closedir( dirp ); + ASSERT( rval == 0 ); +} + +/* binary search + */ +static node_t * +ino2path_i2n( xfs_ino_t ino ) +{ + register node_t *p; + register node_t *lop; + register node_t *hip; + + p = i2p_nodep + i2p_len / 2; + lop = i2p_nodep - 1; + hip = i2p_nodep + i2p_len; + + for ( ; ; ) { + if ( p->n_ino == ino ) { + return p; + } + if ( p->n_ino < ino ) { + lop = p; + p = hip - ( hip - p ) / 2; + if ( p >= hip ) { + return 0; + } + } else { + hip = p; + p = lop + ( p - lop ) / 2; + if ( p <= lop ) { + return 0; + } + } + } + + /* not reached */ + ASSERT( 0 ); + return 0; +} + +static void +ino2path_abort_cleanup( void *arg1, void *arg2 ) +{ + ( void )chdir( ( char * )arg1 ); + ( void )unlink( NAMETEMPLATE ); +} diff -rNu linux-2.4.7/cmd/xfsdump/common/archdep.h linux-2.4-xfs/cmd/xfsdump/common/archdep.h --- linux-2.4.7/cmd/xfsdump/common/archdep.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/archdep.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef ARCHDEP_H +#define ARCHDEP_H + +/* archdep.[hc] - machine, fs, and os - dependent interfaces + * + * lumped here for ease of porting and updating + */ + +/* fundamental page size - probably should not be hardwired, but + * for now we will + */ +#define PGSZLOG2 12 +#define PGSZ ( 1 << PGSZLOG2 ) +#define PGMASK ( PGSZ - 1 ) + + +/* fshandle_t - I just made this up, as a placeholder until + * the real interfaces ae defined. I do know that the xfs_bigstat_t + * is not succifient or the following interfaces; the fs must + * be identified as well. + */ +typedef intgen_t fshandle_t; +#define FSHANDLE_NULL ( -1 ) + + +/* archdep_getfshandle - given a pathname to a mount point, + * returns a fshandle_t. as a side-effect, initialize simulation environment + * for the following functions. need to map a xfs_bstat_t to a pathname, + * so the file can be examined. this uses a lot of memory. + */ +extern fshandle_t archdep_getfshandle( char *mntpnt ); + + +/* getdents equivalent: loads the caller's buffer with raw directory entries. + * each entry begins with the getdententry_t described below (12 bytes). it + * is followed by ge_namelen + 1 bytes. these contain the entry name string, + * NULL-terminated. hence each entry occupies sizeof( archdep_getdents_entry_t ) + * + ge_namelen + 1 bytes. only complete directory entries will be supplied. + * returns number of bytes loaded into the caller's buffer, zero + * if done, -1 if buffer to small to fit the next dirent. + */ +struct archdep_getdents_context { + DIR *gd_dirp; + bool_t gd_cached; + char gd_cachedname[ 2 * sizeof( struct dirent ) + 256 ]; + size_t gd_cachedsz; + xfs_ino_t gd_cachedino; +}; + +typedef struct archdep_getdents_context archdep_getdents_context_t; + +extern archdep_getdents_context_t * + archdep_getdents_context_alloc( fshandle_t fhhandle, xfs_bstat_t *statp ); + +/* archdep_getdents_entry_t - dirent header + * archdep_getdents( ) fills a caller-supplied buffer with variable-length + * directory entry descriptors. Each descriptor begins with this header. + * the overall length of the descriptor is indicated by ge_sz; this is + * guaranteed to be a multiple of 8 bytes. the ge_name field + * will be a NULL-terminated string, the dirent name. + */ +#define ARCHDEP_GETDENTS_ALIGN 8 + +struct archdep_getdents_entry { + xfs_ino_t ge_ino; + u_int32_t ge_sz; + char ge_name[ 4 ]; +}; + +typedef struct archdep_getdents_entry archdep_getdents_entry_t; + +/* fills the caller's buffer with directory entry records. returns + * number of bytes used. if buffer too small to fit the next record, + * return's -1. returns 0 if the directory is depleted. subsequent calls + * after the directory is first depleted will also return 0. + * + * NOTE: skips "." and "..". + */ +extern intgen_t archdep_getdents( archdep_getdents_context_t *ctxp, + char *buf, + size_t bufsz ); + +extern void archdep_getdents_context_free( archdep_getdents_context_t *ctxp ); + + +/* iterative interface for retrieving a file's extent map + */ +struct archdep_getbmap_context { + intgen_t gb_fd; +}; + +typedef struct archdep_getbmap_context archdep_getbmap_context_t; + +extern archdep_getbmap_context_t * + archdep_getbmap_context_alloc( fshandle_t fshandle, xfs_bstat_t *statp ); + +extern intgen_t archdep_getbmap( archdep_getbmap_context_t *ctxp, + getbmap_t *bmapp ); + +extern void archdep_getbmap_context_free( archdep_getbmap_context_t *ctxp ); + + +/* quietly reads the file indicated by the getbmap context. returns actual bytes + * read, or -1 if error with errno set. + */ +extern intgen_t archdep_read( archdep_getbmap_context_t *ctxp, + off64_t off, + char *bufp, + size_t sz ); + +/* quietly reads the symlink indicated by the xfs_bstat_t. returns actual bytes + * read, or -1 if error with errno set. + */ +extern intgen_t archdep_readlink( fshandle_t fshandle, + xfs_bstat_t *statp, + char *bufp, + size_t bufsz ); + +#endif /* ARCHDEP_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/attr.c linux-2.4-xfs/cmd/xfsdump/common/attr.c --- linux-2.4.7/cmd/xfsdump/common/attr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/attr.c Fri Feb 9 01:45:14 2001 @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#include +#include +#include +#include + +#include +#include +#include +#include "attr.h" + +/* These functions implement the IRIX style extended attribute interfaces, */ +/* both of these functions are based on attr_list/attr_multi defined in */ +/* libattr/attr.c and will need to be updated when we have a more */ +/* permanent replacement for attrctl. */ + +int +attr_multi_by_handle( jdm_filehandle_t *hanp, /* handle pointer (fshandle_t) */ + size_t hlen, /* handle length */ + void *buf, /* attr_multiops */ + int count, /* # of attr_multiops */ + int flags) +{ + int error; + attr_multiop_t *multiops; + attr_op_t *ops; + int fsfd; + xfs_fsop_handlereq_t hreq; + xfs_fsop_attr_handlereq_t attr_hreq; + int i; + + if (! (ops = malloc(count * sizeof (attr_op_t)))) { + errno = ENOMEM; + return -1; + } + + if ((flags & ATTR_DONTFOLLOW) != flags) { + errno = EINVAL; + return -1; + } + + /* convert input array to attrctl form - see attr_multi */ + multiops = (attr_multiop_t *) buf; + for (i = 0; i < count; i++) { + ops[i].opcode = multiops[i].am_opcode; + ops[i].name = multiops[i].am_attrname; + ops[i].value = multiops[i].am_attrvalue; + ops[i].length = multiops[i].am_length; + ops[i].flags = multiops[i].am_flags; + } + + if ((fsfd = handle_to_fsfd(hanp)) < 0) { + errno = EBADF; + return -1; + } + + hreq.fd = 0; + hreq.path = NULL; + hreq.oflags = 0; + hreq.ihandle = hanp; + hreq.ihandlen = hlen; + hreq.ohandle = NULL; + hreq.ohandlen = NULL; + + attr_hreq.hreq = &hreq; + attr_hreq.ops = ops; + attr_hreq.count = count; + + error = ioctl(fsfd, XFS_IOC_ATTRCTL_BY_HANDLE, &attr_hreq); + + if (error > 0) { + /* copy return vals */ + for (i = 0; i < count; i++) { + multiops[i].am_error = ops[i].error; + if (ops[i].opcode == ATTR_OP_GET) + multiops[i].am_length = ops[i].length; + } + } + + free(ops); + return error; +} + +int +attr_list_by_handle( jdm_filehandle_t *hanp, /* handle pointer (fshandle_t) */ + size_t hlen, /* handle length */ + char *buf, /* attr output buffer */ + size_t bufsiz, /* buffer size */ + int flags, + struct attrlist_cursor *cursor) /* opaque cursor type */ +{ + attr_op_t op; + int fsfd; + xfs_fsop_handlereq_t hreq; + xfs_fsop_attr_handlereq_t attr_hreq; + + memset(&op, 0, sizeof(attr_op_t)); + op.opcode = ATTR_OP_IRIX_LIST; + op.value = (char *) buf; + op.length = bufsiz; + op.flags = flags; + op.aux = cursor; + + if ((fsfd = handle_to_fsfd(hanp)) < 0) { + errno = EBADF; + return -1; + } + + hreq.fd = 0; + hreq.path = NULL; + hreq.oflags = 0; + hreq.ihandle = hanp; + hreq.ihandlen = hlen; + hreq.ohandle = NULL; + hreq.ohandlen = NULL; + + attr_hreq.hreq = &hreq; + attr_hreq.ops = &op; + attr_hreq.count = 1; + + return ioctl(fsfd, XFS_IOC_ATTRCTL_BY_HANDLE, &attr_hreq); +} + +intgen_t +jdm_attr_multi( jdm_fshandle_t *fshp, /* filesystem handle */ + xfs_bstat_t *statp, /* bulkstate info */ + char *bufp, /* attr_multiops */ + int count, /* # of attr_multiops */ + int flags) +{ + jdm_filehandle_t *filehandle; + size_t hlen; + intgen_t rval; + + jdm_new_filehandle(&filehandle, &hlen, (jdm_fshandle_t *) fshp, statp); + rval = attr_multi_by_handle(filehandle, hlen, (void *) bufp, count, flags); + jdm_delete_filehandle(filehandle, hlen); + return rval; +} + +intgen_t +jdm_attr_list( jdm_fshandle_t *fshp, + xfs_bstat_t *statp, + char *bufp, /* attr list */ + size_t bufsz, /* buffer size */ + int flags, + struct attrlist_cursor *cursor) /* opaque attr_list cursor */ +{ + jdm_filehandle_t *filehandle; + size_t hlen; + intgen_t rval; + + jdm_new_filehandle(&filehandle, &hlen, (jdm_fshandle_t *) fshp, statp); + rval = attr_list_by_handle(filehandle, hlen, bufp, bufsz, flags, cursor); + jdm_delete_filehandle(filehandle, hlen); + return rval; +} diff -rNu linux-2.4.7/cmd/xfsdump/common/attr.h linux-2.4-xfs/cmd/xfsdump/common/attr.h --- linux-2.4.7/cmd/xfsdump/common/attr.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/attr.h Fri Feb 9 01:45:14 2001 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef ATTR_H +#define ATTR_H + +#include +#include + +struct xfs_bstat; +struct attrlist_cursor; + +extern int +attr_multi_by_handle( jdm_filehandle_t *__hanp, /* handle pointer (fshandle_t) */ + size_t __hlen, /* handle length */ + void *__buf, /* attr_multiops */ + int __count, /* # of attr_multips */ + int __flags); + +extern int +attr_list_by_handle( jdm_filehandle_t *__hanp, /* handle pointer (fshandle_t) */ + size_t __hlen, /* handle length */ + char *__buf, /* attr output buf */ + size_t __bufsiz, /* buffer size */ + int __flags, + struct attrlist_cursor *__cursor); /* opaque cursor type */ + +extern intgen_t +jdm_attr_multi( jdm_fshandle_t *__fsh, /* filesystem handle */ + struct xfs_bstat *__statp, /* bulkstat info */ + char *__bufp, /* attr_multops */ + int __count, /* # of attr_multops */ + int __flags); + +extern intgen_t +jdm_attr_list( jdm_fshandle_t *__fsh, /* filesystem handle */ + struct xfs_bstat *__statp, /* bulkstat info */ + char *__bufp, /* attr output buf */ + size_t __bufsz, /* buffer size */ + int __flags, + struct attrlist_cursor *__cursor); + +#endif /* ATTR_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/cldmgr.c linux-2.4-xfs/cmd/xfsdump/common/cldmgr.c --- linux-2.4.7/cmd/xfsdump/common/cldmgr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/cldmgr.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "stkchk.h" +#include "types.h" +#include "lock.h" +#include "qlock.h" +#include "stream.h" +#include "mlog.h" +#include "cldmgr.h" +#include "sproc.h" + +extern size_t pgsz; + +#define CLD_MAX ( STREAM_SIMMAX * 2 ) +struct cld { + bool_t c_busy; + pid_t c_pid; + ix_t c_streamix; + int ( * c_entry )( void *arg1 ); + void * c_arg1; +}; + +typedef struct cld cld_t; + +static cld_t cld[ CLD_MAX ]; +static bool_t cldmgr_stopflag; + +static cld_t *cldmgr_getcld( void ); +static cld_t * cldmgr_findbypid( pid_t ); +static int cldmgr_entry( void * ); +/* REFERENCED */ +static pid_t cldmgr_parentpid; + +bool_t +cldmgr_init( void ) +{ + /* REFERENCED */ + intgen_t rval; + + ( void )memset( ( void * )cld, 0, sizeof( cld )); + cldmgr_stopflag = BOOL_FALSE; + cldmgr_parentpid = getpid( ); + + rval = atexit( cldmgr_killall ); + ASSERT( ! rval ); + + return BOOL_TRUE; +} + +bool_t +cldmgr_create( int ( * entry )( void *arg1 ), + u_intgen_t inh, + ix_t streamix, + char *descstr, + void *arg1 ) +{ + cld_t *cldp; + pid_t cldpid; + + ASSERT( getpid( ) == cldmgr_parentpid ); + + cldp = cldmgr_getcld( ); + if ( ! cldp ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_PROC, + "cannot create %s thread for stream %u: " + "too many child threads (max allowed is %d)\n", + descstr, + streamix, + CLD_MAX ); + return BOOL_FALSE; + } + + cldp->c_streamix = streamix; + cldp->c_entry = entry; + cldp->c_arg1 = arg1; + cldpid = ( pid_t )sproc( cldmgr_entry, inh, ( void * )cldp ); + if ( cldpid < 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_PROC, + "sproc failed creating %s thread for stream %u: %s\n", + descstr, + streamix, + strerror( errno )); + } else { + mlog( MLOG_NITTY | MLOG_PROC, + "%s thread created for stream %u: pid %d\n", + descstr, + streamix, + cldpid ); + } + + return cldpid < 0 ? BOOL_FALSE : BOOL_TRUE; +} + +void +cldmgr_stop( void ) +{ + /* must NOT mlog here! + * locked up by main loop dialog + */ + cldmgr_stopflag = BOOL_TRUE; +} + +/* cldmgr_killall() + * + */ +void +cldmgr_killall( void ) +{ + cld_t *p = cld; + cld_t *ep = cld + sizeof( cld ) / sizeof( cld[ 0 ] ); + + signal( SIGCLD, SIG_IGN ); + for ( ; p < ep ; p++ ) { + if ( p->c_busy ) { + mlog( MLOG_NITTY | MLOG_PROC, + "sending SIGKILL to pid %d\n", + p->c_pid ); + kill( p->c_pid, SIGKILL ); + cldmgr_died( p->c_pid ); + } + } +} + +void +cldmgr_died( pid_t pid ) +{ + cld_t *cldp = cldmgr_findbypid( pid ); + + if ( ! cldp ) { + return; + } + cldp->c_busy = BOOL_FALSE; + if ( ( intgen_t )( cldp->c_streamix ) >= 0 ) { + stream_unregister( pid ); + } +} + +bool_t +cldmgr_stop_requested( void ) +{ + return cldmgr_stopflag; +} + +size_t +cldmgr_remainingcnt( void ) +{ + cld_t *p = cld; + cld_t *ep = cld + sizeof( cld ) / sizeof( cld[ 0 ] ); + size_t cnt; + + cnt = 0; + lock( ); + for ( ; p < ep ; p++ ) { + if ( p->c_busy ) { + cnt++; + } + } + unlock( ); + + return cnt; +} + +bool_t +cldmgr_otherstreamsremain( ix_t streamix ) +{ + cld_t *p = cld; + cld_t *ep = cld + sizeof( cld ) / sizeof( cld[ 0 ] ); + + lock( ); + for ( ; p < ep ; p++ ) { + if ( p->c_busy && p->c_streamix != streamix ) { + unlock( ); + return BOOL_TRUE; + } + } + unlock( ); + + return BOOL_FALSE; +} + +static cld_t * +cldmgr_getcld( void ) +{ + cld_t *p = cld; + cld_t *ep = cld + sizeof( cld ) / sizeof( cld[ 0 ] ); + + lock(); + for ( ; p < ep ; p++ ) { + if ( ! p->c_busy ) { + p->c_busy = BOOL_TRUE; + break; + } + } + unlock(); + + return ( p < ep ) ? p : 0; +} + +static cld_t * +cldmgr_findbypid( pid_t pid ) +{ + cld_t *p = cld; + cld_t *ep = cld + sizeof( cld ) / sizeof( cld[ 0 ] ); + + for ( ; p < ep ; p++ ) { + if ( p->c_busy && p->c_pid == pid ) { + break; + } + } + + return ( p < ep ) ? p : 0; +} + +static int +cldmgr_entry( void *arg1 ) +{ + cld_t *cldp = ( cld_t * )arg1; + pid_t pid = getpid( ); + /* REFERENCED */ + bool_t ok; + + signal( SIGHUP, SIG_IGN ); + signal( SIGINT, SIG_IGN ); + signal( SIGQUIT, SIG_IGN ); + signal( SIGCLD, SIG_DFL ); + alarm( 0 ); + cldp->c_pid = pid; + ok = qlock_thrdinit( ); + ASSERT( ok ); + if ( ( intgen_t )( cldp->c_streamix ) >= 0 ) { + stream_register( pid, ( intgen_t )cldp->c_streamix ); + } + mlog( MLOG_DEBUG | MLOG_PROC, + "child %d created for stream %d\n", + pid, + cldp->c_streamix ); + stkchk_register( ); + return ( * cldp->c_entry )( cldp->c_arg1 ); +} diff -rNu linux-2.4.7/cmd/xfsdump/common/cldmgr.h linux-2.4-xfs/cmd/xfsdump/common/cldmgr.h --- linux-2.4.7/cmd/xfsdump/common/cldmgr.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/cldmgr.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef CLDMGR_H +#define CLDMGR_H + +/* cldmgr.[hc] - manages all child threads + */ + +/* cldmgr_init - initializes child management + * returns FALSE if trouble encountered. + */ +extern bool_t cldmgr_init( void ); + +/* cldmgr_create - creates a child thread. returns FALSE if trouble + * encountered + */ +extern bool_t cldmgr_create( int ( * entry )( void *arg1 ), + u_intgen_t inh, + ix_t streamix, + char *descstr, + void *arg1 ); + +/* cldmgr_stop - asks all children to gracefully terminate, at the next + * convenient point in their normal processing loop. + */ +extern void cldmgr_stop( void ); + +/* cldmgr_killall - kills all children + */ +extern void cldmgr_killall( void ); + +/* cldmgr_died - tells the child manager that the child died + */ +extern void cldmgr_died( pid_t pid ); + +/* cldmgr_stop_requested - returns TRUE if the child should gracefully + * terminate. + */ +extern bool_t cldmgr_stop_requested( void ); + +/* cldmgr_pid2streamix - retrieves the stream index. returns -1 if + * not associated with any stream. + */ +extern intgen_t cldmgr_pid2streamix( pid_t pid ); + +/* cldmgr_remainingcnt - returns number of children remaining + */ +extern size_t cldmgr_remainingcnt( void ); + +/* checks if any children serving any other streams are still alive + */ +extern bool_t cldmgr_otherstreamsremain( ix_t streamix ); + +#endif /* CLDMGR_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/cleanup.c linux-2.4-xfs/cmd/xfsdump/common/cleanup.c --- linux-2.4.7/cmd/xfsdump/common/cleanup.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/cleanup.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include "cleanup.h" + +struct cu { + void ( * cu_funcp )( void *arg1, void *arg2 ); + void *cu_arg1; + void *cu_arg2; + int cu_flags; + struct cu *cu_nextp; +}; + +/* Cleanup structure flags + */ +#define CU_EARLY 0x00000001 + /* call cleanup routine before calling killall */ + +typedef struct cu cu_t; + +static cu_t *cu_rootp; + +void +cleanup_init( void ) +{ + cu_rootp = 0; +} + +static cleanup_t * +cleanup_register_base( void ( * funcp )( void *arg1, void *arg2 ), + void *arg1, + void *arg2 ) +{ + cu_t *p; + + p = ( cu_t * )calloc( 1, sizeof( cu_t )); + ASSERT( p ); + p->cu_funcp = funcp; + p->cu_arg1 = arg1; + p->cu_arg2 = arg2; + p->cu_flags = 0; + p->cu_nextp = cu_rootp; + cu_rootp = p; + + return ( cleanup_t *)p; +} + +cleanup_t * +cleanup_register( void ( * funcp )( void *arg1, void *arg2 ), + void *arg1, + void *arg2 ) +{ + cu_t *p; + + p = cleanup_register_base( funcp, arg1, arg2 ); + + return ( cleanup_t *)p; +} + +cleanup_t * +cleanup_register_early( void ( * funcp )( void *arg1, void *arg2 ), + void *arg1, + void *arg2 ) +{ + cu_t *p; + + p = cleanup_register_base( funcp, arg1, arg2 ); + p->cu_flags = CU_EARLY; + + return ( cleanup_t *)p; +} + +void +cleanup_cancel( cleanup_t *cleanupp ) +{ + cu_t *p = ( cu_t *)cleanupp; + cu_t *nextp; + cu_t *prevp; + + ASSERT( cu_rootp ); + + for ( prevp = 0, nextp = cu_rootp + ; + nextp && nextp != p + ; + prevp = nextp, nextp = nextp->cu_nextp ) + ; + + ASSERT( nextp ); + if ( prevp ) { + prevp->cu_nextp = p->cu_nextp; + } else { + cu_rootp = p->cu_nextp; + } + free( ( void * )p ); +} + +void +cleanup( void ) +{ + while ( cu_rootp ) { + cu_t *p = cu_rootp; + ( * p->cu_funcp )( p->cu_arg1, p->cu_arg2 ); + cu_rootp = p->cu_nextp; + free( ( void * )p ); + } +} + +void +cleanup_early( void ) +{ + cu_t *cuptr, *cuprevp; + + cuptr = cu_rootp; + cuprevp = NULL; + + while ( cuptr ) { + cu_t *cunextp = cuptr->cu_nextp; + + if ( cuptr->cu_flags & CU_EARLY) { + ( * cuptr->cu_funcp )( cuptr->cu_arg1, cuptr->cu_arg2 ); + free( ( void * )cuptr ); + if ( cuprevp ) { + cuprevp->cu_nextp = cunextp; + } else { + cu_rootp = cunextp; + } + cuptr = cunextp; + } else { + cuprevp = cuptr; + cuptr = cunextp; + } + } +} diff -rNu linux-2.4.7/cmd/xfsdump/common/cleanup.h linux-2.4-xfs/cmd/xfsdump/common/cleanup.h --- linux-2.4.7/cmd/xfsdump/common/cleanup.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/cleanup.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef CLEANUP_H +#define CLEANUP_H + +/* cleanup.[hc] - allows registration of callbacks to be invoked + * on exit + */ + +typedef void cleanup_t; + +extern void cleanup_init( void ); + +extern cleanup_t *cleanup_register( void ( *funcp )( void *arg1, void *arg2 ), + void *arg1, + void *arg2 ); + +extern cleanup_t *cleanup_register_early( + void ( *funcp )( void *arg1, void *arg2 ), + void *arg1, + void *arg2 ); + +extern void cleanup_cancel( cleanup_t *cleanupp ); + +extern void cleanup( void ); +extern void cleanup_early( void ); + +#endif /* CLEANUP_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/content.c linux-2.4-xfs/cmd/xfsdump/common/content.c --- linux-2.4.7/cmd/xfsdump/common/content.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/content.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include + +#include "path.h" +#include "types.h" +#include "util.h" +#include "mlog.h" +#include "dlog.h" +#include "getopt.h" +#include "stream.h" +#include "fs.h" +#include "global.h" +#include "drive.h" +#include "media.h" +#include "content.h" + +#define FS_DEFAULT "xfs" +#define OVERWRITE_PROMPT_TIMEOUT 60 /* seconds */ + +/* content.c - selects and initializes a content strategy + */ + + +/* structure definitions used locally ****************************************/ + + +/* declarations of externally defined global symbols *************************/ + +extern void usage( void ); +extern char *homedir; + +/* declare all content strategies here + */ +extern content_strategy_t content_strategy_inode; + + +/* forward declarations of locally defined static functions ******************/ + +static content_t *content_alloc( media_t *, + char * +#ifdef DUMP + ,char *, + char *, + uuid_t * +#endif /* DUMP */ + ); + +/* definition of locally defined global variables ****************************/ + + +/* definition of locally defined static variables *****************************/ + +/* content strategy array - ordered by precedence + */ +static content_strategy_t *strategyp[] = { + &content_strategy_inode, +}; + + +/* definition of locally defined global functions ****************************/ + +/* content_create - select and initialize a content strategy, + * and create and initialize content managers for each stream. + */ +content_strategy_t * +content_create( int argc, char *argv[ ], media_strategy_t *msp ) +{ + int c; +#ifdef DUMP + char *srcname; +#endif /* DUMP */ +#ifdef DUMP + char mntpnt[ GLOBAL_HDR_STRING_SZ ]; + char fsdevice[ GLOBAL_HDR_STRING_SZ ]; + char fstype[ CONTENT_HDR_FSTYPE_SZ ]; + uuid_t fsid; +#endif /* DUMP */ +#ifdef RESTORE + char *mntpnt; +#endif /* RESTORE */ + size_t contentix; + size_t contentcnt; + content_t **contentpp; + intgen_t id; + content_strategy_t **spp = strategyp; + content_strategy_t **epp = strategyp + sizeof( strategyp ) + / + sizeof( strategyp[ 0 ] ); + content_strategy_t *chosen_sp; +#ifdef RESTORE + bool_t toc; + bool_t cumulative; + bool_t resume; + bool_t existing; + bool_t newer; + bool_t prompt; + bool_t changed; + time_t newertime; + struct stat statbuf; +#endif /* RESTORE */ +bool_t ok; + + /* sanity check asserts + */ + ASSERT( sizeof( content_hdr_t ) == CONTENT_HDR_SZ ); + + /* scan the command line for a dump label and source + * file system name / destination directory + */ + optind = 1; + opterr = 0; +#ifdef RESTORE + toc = BOOL_FALSE; + cumulative = BOOL_FALSE; + resume = BOOL_FALSE; + existing = BOOL_FALSE; + newer = BOOL_FALSE; + prompt = BOOL_FALSE; + changed = BOOL_FALSE; +#endif /* RESTORE */ + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + switch ( c ) { +#ifdef RESTORE + case GETOPT_TOC: + toc = BOOL_TRUE; + break; + case GETOPT_CUMULATIVE: + cumulative = BOOL_TRUE; + break; + case GETOPT_RESUME: + resume = BOOL_TRUE; + break; + case GETOPT_EXISTING: + existing = BOOL_TRUE; + break; + case GETOPT_NEWER: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL, + "-%c argument missing\n", + optopt ); + usage( ); + return 0; + } + if ( stat( optarg, &statbuf )) { + mlog( MLOG_NORMAL, + "unable to get status of -%c argument %s:" + " %s\n", + optopt, + optarg, + strerror( errno )); + return 0; + } + newer = BOOL_TRUE; + newertime = statbuf.st_mtime; + break; +#ifdef NOTYET + case GETOPT_PROMPT: + if ( dlog_allowed( )) { + prompt = BOOL_TRUE; + } + break; +#endif /* NOTYET */ + case GETOPT_CHANGED: + changed = BOOL_TRUE; + break; +#endif /* RESTORE */ + } + } + +#ifdef RESTORE + if ( cumulative && toc ) { + mlog( MLOG_NORMAL, + "-%c and -%c option cannot be used together\n", + GETOPT_TOC, + GETOPT_CUMULATIVE ); + usage( ); + return 0; + } + if ( resume && toc ) { + mlog( MLOG_NORMAL, + "-%c and -%c option cannot be used together\n", + GETOPT_TOC, + GETOPT_RESUME ); + usage( ); + return 0; + } +#endif /* RESTORE */ + + /* the user may specify stdout as the destination / stdin as + * the source, by a single dash ('-') with no option letter. + * This must appear between all lettered arguments and the + * source file system / destination directory pathname. + */ + if ( optind < argc && ! strcmp( argv[ optind ], "-" )) { + optind++; + } + + /* DUMP: the last argument must be either the mount point or the + * device pathname of the file system to be dumped. + * RESTORE: the last argument must be a destination directory + */ +#ifdef DUMP + if ( optind >= argc ) { + mlog( MLOG_NORMAL, + "source file system " + "not specified\n" ); + usage( ); + return 0; + } + srcname = argv[ optind ]; +#endif /* DUMP */ + +#ifdef RESTORE + if ( ! toc ) { + struct stat statbuf; + intgen_t rval; + + if ( optind >= argc ) { + mlog( MLOG_NORMAL, + "destination directory " + "not specified\n" ); + usage( ); + return 0; + } + mntpnt = path_reltoabs( argv[ optind ], homedir ); + if ( ! mntpnt ) { + mlog( MLOG_NORMAL, + "destination directory %s " + "invalid pathname\n" ); + usage( ); + return 0; + } + mlog( MLOG_DEBUG, + "restore destination path converted from %s to %s\n", + argv[ optind ], + mntpnt ); + if ( mntpnt[ 0 ] != '/' ) { + mlog( MLOG_NORMAL, + "destination directory %s " + "must be an absolute pathname\n", + mntpnt ); + usage( ); + return 0; + } + rval = lstat( mntpnt, &statbuf ); + if ( rval ) { + mlog( MLOG_NORMAL, + "cannot stat destination directory %s: %s\n", + mntpnt, + strerror( errno )); + usage( ); + return 0; + } + if ( ( statbuf.st_mode & S_IFMT ) != S_IFDIR ) { + mlog( MLOG_NORMAL, + "specified destination %s is not a directory\n", + mntpnt ); + usage( ); + return 0; + } + } else { + mntpnt = "."; + } +#endif /* RESTORE */ + +#ifdef DUMP + /* call a magic function to figure out if the last argument is + * a mount point or a device pathname, and retrieve the file + * system type, full pathname of the character special device + * containing the file system, the latest mount point, and the file + * system ID (uuid). returns BOOL_FALSE if the last + * argument doesn't look like a file system. + */ + if ( ! fs_info( fstype, + sizeof( fstype ), + FS_DEFAULT, + fsdevice, + sizeof( fsdevice ), + mntpnt, + sizeof( mntpnt ), + &fsid, + srcname )) { + + mlog( MLOG_NORMAL, + "%s does not identify a file system\n", + srcname ); + usage( ); + return 0; + } + + /* verify that the file system is mounted. This must be enhanced + * to mount an unmounted file system on a temporary mount point, + * if it is not currently mounted. + */ + if ( ! fs_mounted( fstype, fsdevice, mntpnt, &fsid )) { + mlog( MLOG_NORMAL, + "%s must be mounted to be dumped\n", + srcname ); + return 0; + } + +#endif /* DUMP */ + + /* create a content_t array and a content_ts for each media stream. + * Initialize each content_t's writehdr and generic portions. these + * will be lended to each content strategy during the strategy + * match phase, and given to the winning strategy. + * + * RESTORE: NOTE that the destination is saved in the writehdr mntpnt + * field; a slight misnomer, since the restore destination does not + * need to be the root of a file system. + */ + contentcnt = msp->ms_mediacnt; + contentpp = ( content_t ** )calloc( contentcnt, + sizeof( content_t * )); + ASSERT( contentpp ); + for ( contentix = 0 ; contentix < contentcnt ; contentix++ ) { + contentpp[ contentix ] = + content_alloc( msp->ms_mediap[ contentix ], + mntpnt +#ifdef DUMP + , fsdevice, + fstype, + &fsid +#endif /* DUMP */ + ); + } + + /* choose the first strategy which claims appropriateness. + * if none match, return null. Also, initialize the strategy ID + * and pointer to the media strategy. the ID is simply the index + * of the strategy in the strategy array. it is placed in the + * content_strategy_t as well as the write headers. + */ + chosen_sp = 0; + for ( id = 0 ; spp < epp ; spp++, id++ ) { + (*spp)->cs_id = id; + if ( ! chosen_sp ) { + /* lend the content_t array to the strategy + */ + (*spp)->cs_contentp = contentpp; + (*spp)->cs_msp = msp; + (*spp)->cs_contentcnt = contentcnt; + for ( contentix = 0 ; contentix < contentcnt ; + contentix++ ) { + content_t *contentp = contentpp[ contentix ]; + contentp->c_strategyp = *spp; + contentp->c_writehdrp->ch_strategyid = id; + } + if ( ( * (*spp)->cs_match )( argc, argv, msp )) { + chosen_sp = *spp; + } + } + } +#ifdef DUMP + if ( ! chosen_sp ) { + mlog( MLOG_NORMAL, + "do not know how to dump selected " + "source file system's (%s) type (%s)\n", + mntpnt, + fstype ); +#endif /* DUMP */ +#ifdef RESTORE + if ( ! chosen_sp ) { + mlog( MLOG_NORMAL, + "do not know how to restore into selected " + "destination file system (%s)\n", + mntpnt ); +#endif /* RESTORE */ + usage( ); + return 0; + } + + /* give the content_t array to the chosen strategy + */ + for ( contentix = 0 ; contentix < contentcnt ; contentix++ ) { + content_t *contentp = contentpp[ contentix ]; + contentp->c_strategyp = chosen_sp; + contentp->c_writehdrp->ch_strategyid = chosen_sp->cs_id; + } + +#ifdef RESTORE + /* set global content strategy flags + */ + if ( toc ) { + chosen_sp->cs_flags |= CONTENT_STRATEGY_FLAGS_TOC; + } + if ( cumulative ) { + chosen_sp->cs_flags |= CONTENT_STRATEGY_FLAGS_CUMULATIVE; + } + if ( resume ) { + chosen_sp->cs_flags |= CONTENT_STRATEGY_FLAGS_RESUME; + } + if ( existing ) { + chosen_sp->cs_flags |= CONTENT_STRATEGY_FLAGS_EXISTING; + } + if ( newer ) { + chosen_sp->cs_flags |= CONTENT_STRATEGY_FLAGS_NEWER; + chosen_sp->cs_newertime = newertime; + } + if ( prompt ) { + chosen_sp->cs_flags |= CONTENT_STRATEGY_FLAGS_PROMPT; + } + if ( changed ) { + chosen_sp->cs_flags |= CONTENT_STRATEGY_FLAGS_CHANGED; + } +#endif /* RESTORE */ + + /* call strategy-specific create operator. + */ + ok = ( * chosen_sp->cs_create )( chosen_sp, argc, argv ); + if ( !ok ) { + return 0; + } + + /* return the selected strategy + */ + return chosen_sp; +} + +bool_t +content_init( content_strategy_t *csp, int argc, char *argv[] ) +{ + bool_t ok; + + ok = ( * csp->cs_init )( csp, argc, argv ); + + return ok; +} + +void +content_complete( content_strategy_t *csp ) +{ + ( * csp->cs_complete )( csp ); +} + +#ifdef RESTORE +bool_t +content_overwrite_ok( content_strategy_t *csp, + char *path, + int32_t ctime, + int32_t mtime, + char **reasonstrp ) +{ + register intgen_t flags = csp->cs_flags; + struct stat statbuf; + + /* if no overwrite inhibit directives, allow + + if ( ! ( flags + & + ( CONTENT_STRATEGY_FLAGS_EXISTING + | + CONTENT_STRATEGY_FLAGS_NEWER + | + CONTENT_STRATEGY_FLAGS_PROMPT + | + CONTENT_STRATEGY_FLAGS_CHANGED ))) { + *reasonstrp = 0; + return BOOL_TRUE; + } + + * if file doesn't exist, allow + */ + if ( lstat( path, &statbuf )) { + *reasonstrp = 0; + return BOOL_TRUE; + } + + /* if overwrites absolutely inhibited, disallow + */ + if ( flags & CONTENT_STRATEGY_FLAGS_EXISTING ) { + *reasonstrp = "overwrites inhibited"; + return BOOL_FALSE; + } + + /* if newer time specified, compare + */ + if ( flags & CONTENT_STRATEGY_FLAGS_NEWER ) { + if ( ( time_t )ctime < csp->cs_newertime ) { + *reasonstrp = "too old"; + return BOOL_FALSE; + } + } + + /* don't overwrite changed files + */ + if ( flags & CONTENT_STRATEGY_FLAGS_CHANGED ) { + if ( statbuf.st_ctime >= ( time_t )ctime ) { + *reasonstrp = "existing version is newer"; + return BOOL_FALSE; + } + } + + /* prompt to allow overwrite + */ + if ( flags & CONTENT_STRATEGY_FLAGS_PROMPT ) { + char buf[ MAXPATHLEN + 100 ]; + sprintf( buf, "overwrite %s?", path ); + if ( dlog_yesno( buf, + "overwriting", + "skipping", + "skipping", + BOOL_FALSE, + OVERWRITE_PROMPT_TIMEOUT ) != BOOL_TRUE ) { + *reasonstrp = "overwrite declined"; + return BOOL_FALSE; + } + } + + *reasonstrp = 0; + return BOOL_TRUE; +} +#endif /* RESTORE */ + + +/* definition of locally defined static functions ****************************/ + +/* content_alloc - allocate and initialize the generic portions of a content + * descriptor and read and write content media headers + */ +static content_t * +content_alloc( media_t *mediap, + char *mntpnt +#ifdef DUMP + ,char *fsdevice, + char *fstype, + uuid_t *fsidp +#endif /* DUMP */ + ) +{ + content_t *contentp; + global_hdr_t *grhdrp; + global_hdr_t *gwhdrp; + content_hdr_t *crhdrp; + content_hdr_t *cwhdrp; + size_t crhdrsz; + size_t cwhdrsz; + + contentp = ( content_t * )calloc( 1, sizeof( content_t )); + ASSERT( contentp ); + + grhdrp = 0; + gwhdrp = 0; + crhdrp = 0; + cwhdrp = 0; + media_get_upper_hdrs( mediap, + &grhdrp, + ( char ** )&crhdrp, + &crhdrsz, + &gwhdrp, + ( char ** )&cwhdrp, + &cwhdrsz ); + ASSERT( grhdrp ); + ASSERT( gwhdrp ); + ASSERT( crhdrp ); + ASSERT( cwhdrp ); + ASSERT( crhdrsz == CONTENT_HDR_SZ ); + ASSERT( cwhdrsz == CONTENT_HDR_SZ ); + + contentp->c_greadhdrp = grhdrp; + contentp->c_gwritehdrp = gwhdrp; + contentp->c_readhdrp = crhdrp; + contentp->c_writehdrp = cwhdrp; + contentp->c_mediap = mediap; + +#ifdef RESTORE + ASSERT( strlen( mntpnt ) < sizeof( cwhdrp->ch_mntpnt )); +#endif /* RESTORE */ + ( void )strncpyterm( cwhdrp->ch_mntpnt, + mntpnt, + sizeof( cwhdrp->ch_mntpnt )); +#ifdef DUMP + ( void )strncpyterm( cwhdrp->ch_fsdevice, + fsdevice, + sizeof( cwhdrp->ch_fsdevice )); + ( void )strncpyterm( cwhdrp->ch_fstype, + fstype, + sizeof( cwhdrp->ch_fstype )); + uuid_copy(cwhdrp->ch_fsid, *fsidp); +#endif /* DUMP */ + + return contentp; +} diff -rNu linux-2.4.7/cmd/xfsdump/common/content.h linux-2.4-xfs/cmd/xfsdump/common/content.h --- linux-2.4.7/cmd/xfsdump/common/content.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/content.h Mon Apr 2 22:57:58 2001 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef CONTENT_H +#define CONTENT_H + +/* content.[hc] - dump/restore content strategy abstraction + */ + + +/* content_hdr_t - content file header + * + * This header structure will be placed at the beginning of the + * content media files by the media manager mo_begin_write() operator, + * and will be extracted from the beginning of the media object files by + * the mo_begin_read() operator. A content header_t has three parts: generally + * useful info, content strategy-specific info, and upper layer info. The hdr + * argument of the co_begin_write() operator will be stuffed into the + * upper layer info, and extracted for the upper layer by co_begin_read(). + */ +#define CONTENT_HDR_SZ sizeofmember( media_hdr_t, mh_upper ) +#define CONTENT_HDR_FSTYPE_SZ 16 +#define CONTENT_STATSZ 160 /* must match dlog.h DLOG_MULTI_STATSZ */ +#define CONTENT_QUOTAFILE "xfsdump_quotas" +#define CONTENT_GQUOTAFILE "xfsdump_quotas_group" + +struct content_hdr { + char ch_mntpnt[ GLOBAL_HDR_STRING_SZ ]; /* 100 100 */ + /* full pathname of fs mount point */ + char ch_fsdevice[ GLOBAL_HDR_STRING_SZ ]; /* 100 200 */ + /* full pathname of char device containing fs */ + char ch_pad1[GLOBAL_HDR_STRING_SZ]; /* 100 300 */ + /* in case another label is needed */ + char ch_fstype[ CONTENT_HDR_FSTYPE_SZ ]; /* 10 310 */ + /* from fsid.h */ + uuid_t ch_fsid; /* 10 320 */ + /* file system uuid */ + char ch_pad2[ GLOBAL_HDR_UUID_SZ ]; /* 10 330 */ + /* in case another id is needed */ + char ch_pad3[ 8 ]; /* 8 338 */ + /* padding */ + int32_t ch_strategyid; /* 4 33c */ + /* ID of the content strategy used to produce this dump */ + char ch_pad4[ 4 ]; /* 4 340 */ + /* alignment */ + char ch_specific[ 0xc0 ]; /* c0 400 */ + /* content strategy-specific info */ +}; + +typedef struct content_hdr content_hdr_t; + +struct quota_info { + char * desc; /* Quotas type (user, group, etc) */ + bool_t savequotas; /* Quotas saved OK */ + char * quotafile; /* Filename quota info is stored in */ + char quotapath[MAXPATHLEN]; /* Full path to quotafile */ + char * repquotaargs; /* Args to repquota to create this quotafile */ + int statflag; /* quota stats flag for this type */ +}; + +typedef struct quota_info quota_info_t; + + +#ifdef DUMP +extern bool_t content_init( intgen_t argc, + char *argv[ ], + global_hdr_t *gwhdrtemplatep ); + /* prepares for multi-stream dump + */ + +extern intgen_t content_stream_dump( ix_t strmix ); + /* does stream dump + */ + +#endif /* DUMP */ +#ifdef RESTORE +extern size_t perssz; + +extern bool_t content_init( intgen_t argc, char *argv[ ], size64_t vmsz ); + /* prepares for multi-thread restore + */ + +extern intgen_t content_stream_restore( ix_t thrdix ); + /* does thread restore + */ + +extern bool_t content_overwrite_ok( char *path, + int32_t ctime, + int32_t mtime, + char **reasonstrp ); + /* called by tree to ask if ok to overwrite file + */ + +extern void content_showinv( void ); + /* displays inventory of dump session being restored, + * in the context of a second-level dialog + */ + +extern void content_showremainingobjects( void ); + /* displays info on media objects remaining to be restored. + */ +#endif /* RESTORE */ + +extern bool_t content_complete( void ); + /* cleanup: called from main thread. returns TRUE if complete + */ + +extern size_t content_statline( char **lines[ ] ); + /* supplies status line for main keyboard intr dialog + * returns by ref an array of character strings, and the length + * of the array is returned by value. + */ + +extern bool_t content_media_change_needed; + /* queried by main thread to decide if interupt dialog needed + * for media change confirmation. + */ +extern char *content_mediachange_query( void ); + /* invoked by main thread sigint dialog to allow operator to + * confirm media changes and ask what media objects remain + */ + +#endif /* CONTENT_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/content_common.c linux-2.4-xfs/cmd/xfsdump/common/content_common.c --- linux-2.4.7/cmd/xfsdump/common/content_common.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/content_common.c Mon Apr 9 01:32:28 2001 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "types.h" +#include "util.h" +#include "mlog.h" +#include "dlog.h" +#include "cldmgr.h" +#include "global.h" +#include "drive.h" + +#define PREAMBLEMAX 3 +#define QUERYMAX 1 +#define CHOICEMAX 2 +#define ACKMAX 3 +#define POSTAMBLEMAX 3 +#define DLOG_TIMEOUT 3600 + +bool_t +Media_prompt_change( drive_t *drivep ) +{ + fold_t fold; + char question[ 100 ]; + char *preamblestr[ PREAMBLEMAX ]; + size_t preamblecnt; + char *querystr[ QUERYMAX ]; + size_t querycnt; + char *choicestr[ CHOICEMAX ]; + size_t choicecnt; + char *ackstr[ ACKMAX ]; + size_t ackcnt; + char *postamblestr[ POSTAMBLEMAX ]; + size_t postamblecnt; + ix_t doix; + ix_t dontix; + ix_t responseix; + ix_t sigintix; + +retry: + preamblecnt = 0; + fold_init( fold, "change media dialog", '=' ); + preamblestr[ preamblecnt++ ] = "\n"; + preamblestr[ preamblecnt++ ] = fold; + preamblestr[ preamblecnt++ ] = "\n\n"; + ASSERT( preamblecnt <= PREAMBLEMAX ); + dlog_begin( preamblestr, preamblecnt ); + + /* query: ask if media changed or declined + */ + sprintf( question, + "please change media in " + "drive %u\n", + (unsigned int)drivep->d_index ); + querycnt = 0; + querystr[ querycnt++ ] = question; + ASSERT( querycnt <= QUERYMAX ); + choicecnt = 0; + dontix = choicecnt; + choicestr[ choicecnt++ ] = "media change declined"; + doix = choicecnt; + choicestr[ choicecnt++ ] = "media changed"; + ASSERT( choicecnt <= CHOICEMAX ); + sigintix = IXMAX - 1; + + responseix = dlog_multi_query( querystr, + querycnt, + choicestr, + choicecnt, + 0, /* hilitestr */ + IXMAX, /* hiliteix */ + 0, /* defaultstr */ + doix, /* defaultix */ + DLOG_TIMEOUT, + dontix, /* timeout ix */ + sigintix, /* sigint ix */ + dontix, /* sighup ix */ + dontix ); /* sigquit ix */ + ackcnt = 0; + if ( responseix == doix ) { + ackstr[ ackcnt++ ] = "examining new media\n"; + } else if ( responseix == dontix ) { + ackstr[ ackcnt++ ] = "media change aborted\n"; + } else { + ASSERT( responseix == sigintix ); + ackstr[ ackcnt++ ] = "keyboard interrupt\n"; + } + + ASSERT( ackcnt <= ACKMAX ); + dlog_multi_ack( ackstr, + ackcnt ); + + postamblecnt = 0; + fold_init( fold, "end dialog", '-' ); + postamblestr[ postamblecnt++ ] = "\n"; + postamblestr[ postamblecnt++ ] = fold; + postamblestr[ postamblecnt++ ] = "\n\n"; + ASSERT( postamblecnt <= POSTAMBLEMAX ); + dlog_end( postamblestr, + postamblecnt ); + + if ( responseix == sigintix ) { + if ( cldmgr_stop_requested( )) { + return BOOL_FALSE; + } + sleep( 1 ); /* to allow main thread to begin dialog */ + mlog( MLOG_NORMAL | MLOG_BARE, + "" ); /* to block until main thread dialog complete */ + sleep( 1 ); /* to allow main thread to request children die */ + if ( cldmgr_stop_requested( )) { + return BOOL_FALSE; + } + mlog( MLOG_DEBUG, + "retrying media change dialog\n" ); + goto retry; + } + + return responseix == doix; +} diff -rNu linux-2.4.7/cmd/xfsdump/common/content_common.h linux-2.4-xfs/cmd/xfsdump/common/content_common.h --- linux-2.4.7/cmd/xfsdump/common/content_common.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/content_common.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef CONTENT_COMMON_H +#define CONTENT_COMMON_H + +extern bool_t Media_prompt_change( drive_t *drivep ); + +#endif /* CONTENT_COMMON_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/content_inode.h linux-2.4-xfs/cmd/xfsdump/common/content_inode.h --- linux-2.4.7/cmd/xfsdump/common/content_inode.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/content_inode.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef CONTENT_INODE_H +#define CONTENT_INODE_H + +/* content_inode.h - inode-style content strategy-specific header structure + */ + +/* dump startpoint: identifies dump stream boundaries + * NOTE: sp_offset is not a position within a file; it is a quantity of + * bytes to skip. holes do not count. + */ +struct startpt { + xfs_ino_t sp_ino; /* first inode to dump */ + off64_t sp_offset; /* bytes to skip in file data fork */ + int32_t sp_flags; + int32_t sp_pad1; +}; + +typedef struct startpt startpt_t; + +#define STARTPT_FLAGS_END ( 1 << 0 ) + /* this startpt indicates that all extents of all files in + * the stream were completely dumped. the other fields + * are meaningless. this will appear only once per dump + * stream, even if the stream spans multiple media files. + * + * also used in the strategy-specific portion of the + * content header to qualify the ending point. + */ +#define STARTPT_FLAGS_NULL ( 1 << 1 ) + /* used to detect if the null file header makes it onto + * media. only necessary after the last file in the stream, + * to allow the end-of-stream flag in the null header to + * be seen. + */ + + +/* drange_t - describes a range of ino/offset values + */ +struct drange { + startpt_t dr_begin; + startpt_t dr_end; +}; + +typedef struct drange drange_t; + + +/* inode-style specific media file header section + */ +#define CONTENT_INODE_HDR_SZ sizeofmember( content_hdr_t, ch_specific ) + +struct content_inode_hdr { + int32_t cih_mediafiletype; /* 4 4 */ + /* dump media file type: see #defines below */ + int32_t cih_dumpattr; /* 4 8 */ + /* dump attributes: see #defines below */ + int32_t cih_level; /* 4 c */ + /* dump level */ + char pad1[ 4 ]; /* 4 10 */ + /* alignment */ + time_t cih_last_time; /* 4 14 */ + /* if an incremental,time of previous dump at a lesser level */ + time_t cih_resume_time; /* 4 18 */ + /* if a resumed dump, time of interrupted dump */ + xfs_ino_t cih_rootino; /* 8 20 */ + /* root inode number */ + uuid_t cih_last_id; /* 10 30 */ + /* if an incremental, uuid of prev dump */ + uuid_t cih_resume_id; /* 10 40 */ + /* if a resumed dump, uuid of interrupted dump */ + startpt_t cih_startpt; /* 18 58 */ + /* starting point of media file contents */ + startpt_t cih_endpt; /* 18 70 */ + /* starting point of next stream */ + u_int64_t cih_inomap_hnkcnt; /* 8 78 */ + + u_int64_t cih_inomap_segcnt; /* 8 80 */ + + u_int64_t cih_inomap_dircnt; /* 8 88 */ + + u_int64_t cih_inomap_nondircnt; /* 8 90 */ + + xfs_ino_t cih_inomap_firstino; /* 8 98 */ + + xfs_ino_t cih_inomap_lastino; /* 8 a0 */ + + u_int64_t cih_inomap_datasz; /* 8 a8 */ + /* bytes of non-metadata dumped */ + char cih_pad2[ CONTENT_INODE_HDR_SZ - 0xa8 ]; /* 18 c0 */ + /* padding */ +}; + +typedef struct content_inode_hdr content_inode_hdr_t; + +/* media file types + */ +#define CIH_MEDIAFILETYPE_DATA 0 +#define CIH_MEDIAFILETYPE_INVENTORY 1 +#define CIH_MEDIAFILETYPE_INDEX 2 + +/* dump attributes + */ +#define CIH_DUMPATTR_SUBTREE ( 1 << 0 ) +#define CIH_DUMPATTR_INDEX ( 1 << 1 ) +#define CIH_DUMPATTR_INVENTORY ( 1 << 2 ) +#define CIH_DUMPATTR_INCREMENTAL ( 1 << 3 ) +#define CIH_DUMPATTR_RETRY ( 1 << 4 ) +#define CIH_DUMPATTR_RESUME ( 1 << 5 ) +#define CIH_DUMPATTR_INOMAP ( 1 << 6 ) +#define CIH_DUMPATTR_DIRDUMP ( 1 << 7 ) +#define CIH_DUMPATTR_FILEHDR_CHECKSUM ( 1 << 8 ) +#define CIH_DUMPATTR_EXTENTHDR_CHECKSUM ( 1 << 9 ) +#define CIH_DUMPATTR_DIRENTHDR_CHECKSUM ( 1 << 10 ) +#define CIH_DUMPATTR_DIRENTHDR_GEN ( 1 << 11 ) +#ifdef EXTATTR +#define CIH_DUMPATTR_EXTATTR ( 1 << 12 ) +#define CIH_DUMPATTR_EXTATTRHDR_CHECKSUM ( 1 << 13 ) +#endif /* EXTATTR */ + + +/* timestruct_t - time structure + * + * used in bstat_t below. derived from timestruc_t, to achieve independence + * from changes to timestruc_t. carefully crafted to make conversion from one + * to the other as quick as possible. + */ +#define TIMESTRUCT_SZ 8 + +struct timestruct { /* bytes accum */ + int32_t tv_sec; /* seconds 4 4 */ + int32_t tv_nsec; /* and nanoseconds 4 8 */ +}; + +typedef struct timestruct timestruct_t; + + +/* bstat_t - bulk stat structure + * + * used in filehdr_t below. derived from xfs_bstat_t, to achieve independence + * from changes to xfs_bstat_t. carefully crafted to make conversion from one + * to the other as quick as possible. + */ +#define BSTAT_SZ 128 +#define MODE_SZ 4 + +struct bstat { /* bytes accum */ + xfs_ino_t bs_ino; /* inode number 8 8 */ + u_int32_t bs_mode; /* type and mode 4 c */ + u_int32_t bs_nlink; /* number of links 4 10 */ + int32_t bs_uid; /* user id 4 14 */ + int32_t bs_gid; /* group id 4 18 */ + u_int32_t bs_rdev; /* device value 4 1c */ + int32_t bs_blksize; /* block size 4 20 */ + off64_t bs_size; /* file size 8 28 */ + timestruct_t bs_atime; /* access time 8 30 */ + timestruct_t bs_mtime; /* modify time 8 38 */ + timestruct_t bs_ctime; /* inode change time 8 40 */ + int64_t bs_blocks; /* number of blocks 8 48 */ + u_int32_t bs_xflags; /* extended flags 4 4c */ + int32_t bs_extsize; /* extent size 4 50 */ + int32_t bs_extents; /* number of extents 4 54 */ + u_int32_t bs_gen; /* generation count 4 58 */ + uuid_t bs_uuid; /* unique id of file 10 68 */ + u_int32_t bs_dmevmask; /* DMI event mask 4 6c */ + u_int16_t bs_dmstate; /* DMI state info 2 6e */ + char bs_pad1[ 18 ]; /* for expansion 12 80 */ +}; + +typedef struct bstat bstat_t; + +/* filehdr_t - header placed at the beginning of every dumped file. + * + * each fs file placed on dump media begins with a FILEHDR_SZ-byte header. + * following that are one or more variable-length content extents. + * the content extents contain the actual data associated with the fs file. + */ +#define FILEHDR_SZ 256 + +struct filehdr { + int64_t fh_offset; + int32_t fh_flags; + u_int32_t fh_checksum; + bstat_t fh_stat; + char fh_pad2[ FILEHDR_SZ + - sizeof( int64_t ) + - sizeof( int32_t ) + - sizeof( u_int32_t ) + - sizeof( bstat_t ) ]; +}; + +typedef struct filehdr filehdr_t; + +#define FILEHDR_FLAGS_NULL ( 1 << 0 ) + /* identifies a dummy file header. every media file + * is terminated with a dummy file header, unless + * terminated by end of media. + */ +#define FILEHDR_FLAGS_CHECKSUM ( 1 << 1 ) + /* indicates the header checksum is valid + */ +#define FILEHDR_FLAGS_END ( 1 << 2 ) + /* the last media file in the stream is always terminated by + * a dummy file header, with this flag set. + */ +#ifdef EXTATTR +#define FILEHDR_FLAGS_EXTATTR ( 1 << 3 ) + /* special file header followed by one file's (dir or nondir) + * extended attributes. + */ +#endif /* EXTATTR */ + + +/* extenthdr_t - a header placed at the beginning of every dumped + * content extent. + * + * a dumped file consists of a filehdr_t followed by zero or more + * extents. for regular files the last extent is always of type LAST. + * for symbolic link files, only one extent is dumped, and it contains the + * symlink path. + */ +#define EXTENTHDR_SZ 32 + +struct extenthdr { + off64_t eh_sz; /* length of extent, NOT including header, in bytes */ + off64_t eh_offset; + int32_t eh_type; + int32_t eh_flags; + u_int32_t eh_checksum; + char eh_pad[ 4 ]; +}; + +typedef struct extenthdr extenthdr_t; + +#define EXTENTHDR_TYPE_LAST 0 + /* always the last extent. sz is always 0 + */ +#define EXTENTHDR_TYPE_ALIGN 1 + /* used for alignment. sz is the number of bytes to skip, + * in addition to the hdr + */ +#define EXTENTHDR_TYPE_DATA 4 + /* heads an extent of ordinary file data. sz is the data + * extent length in bytes, NOT including the hdr. offset + * indicates the byte position of the extent within the file. + * also heads the path in a symlink dump. + */ +#define EXTENTHDR_TYPE_HOLE 8 + /* used to encode a hole extent. Offset indicates the byte + * position of the hole within the file and sz is the + * hole extent length. + */ + +#define EXTENTHDR_FLAGS_CHECKSUM ( 1 << 0 ) + + +/* direnthdr_t - placed at the beginning of every dumped directory entry. + * a directory entry consists of the fixed size header followed by a variable + * length NULL-terminated name string, followed by enough padding to make the + * overall record size a multiple of 8 bytes. the name string begins + * at the dh_name field. the total number of bytes occupied by + * each directory entry on media is dh_sz. + * + * a sequence of directory entries is always terminated with a null direnthdr_t. + * this is detected by looking for a zero ino. + */ +#define DIRENTHDR_ALIGN 8 + +#define DIRENTHDR_SZ 24 + +struct direnthdr { + xfs_ino_t dh_ino; + u_int16_t dh_gen; /* generation count & DENTGENMASK of ref'ed inode */ + u_int16_t dh_sz; /* overall size of record */ + u_int32_t dh_checksum; + char dh_name[ 8 ]; +}; + +typedef struct direnthdr direnthdr_t; + +/* truncated generation count + */ +#define DENTGENSZ 12 /* leave 4 bits for future flags */ +#define DENTGENMASK (( 1 << DENTGENSZ ) - 1 ) +typedef u_int16_t gen_t; +#define GEN_NULL ( ( gen_t )UINT16MAX ) +#define BIGGEN2GEN( bg ) ( ( gen_t )( bg & DENTGENMASK )) + + + +/* symbolic links will be dumped using an extent header. the extent + * will always be a multiple of SYMLINK_ALIGN bytes. the symlink character + * string will always be null-terminated. + */ +#define SYMLINK_ALIGN 8 + +#ifdef EXTATTR + +/* extattr_hdr_t - hdr for an extended attribute. the first byte of the + * attribute name immediately follows the header. the name is terminated + * with a NULL byte. Each extattr record will be aligned; there may + * be padding at the end of each record to achieve this. NOTE: ah_sz + * includes the hdr sz; adding ah_sz to the offset of one extattr + * gives the offset of the next. + */ +#define EXTATTRHDR_SZ 16 +#define EXTATTRHDR_ALIGN 8 + +struct extattrhdr { + u_int32_t ah_sz; /* overall size of extended attribute record */ + u_int16_t ah_valoff; /* byte offset within record of value */ + u_int16_t ah_flags; /* see EXTATTRHDR_FLAGS_... below */ + u_int32_t ah_valsz; /* size of value */ + u_int32_t ah_checksum; /* hdr checksum */ +}; + +typedef struct extattrhdr extattrhdr_t; + +#define EXTATTRHDR_FLAGS_ROOT ( 1 << 0 ) + /* a "root" mode attribute + */ +#define EXTATTRHDR_FLAGS_NULL ( 1 << 1 ) + /* marks the end of the attributes associated with the leading filehdr_t + */ +#define EXTATTRHDR_FLAGS_CHECKSUM ( 1 << 2 ) + /* checksum is present + */ + +#endif /* EXTATTR */ + +#endif /* CONTENT_INODE_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/dlog.c linux-2.4-xfs/cmd/xfsdump/common/dlog.c --- linux-2.4.7/cmd/xfsdump/common/dlog.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/dlog.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,530 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "types.h" +#include "mlog.h" +#include "dlog.h" +#include "getopt.h" + +extern bool_t miniroot; +extern pid_t parentpid; + +static int dlog_ttyfd = -1; +static bool_t dlog_allowed_flag = BOOL_FALSE; +static bool_t dlog_timeouts_flag = BOOL_FALSE; +static char *promptstr = " -> "; + +static bool_t promptinput( char *buf, + size_t bufsz, + ix_t *exceptionixp, + time_t timeout, + ix_t timeoutix, + ix_t sigintix, + ix_t sighupix, + ix_t sigquitix, + char *fmt, ... ); +static void dlog_string_query_print( void *ctxp, char *fmt, ... ); +static void sighandler( int ); + +bool_t +dlog_init( int argc, char *argv[ ] ) +{ + intgen_t c; + + /* can only call once + */ + ASSERT( dlog_ttyfd == -1 ); + + /* initially allow dialog, use stdin fd + */ + dlog_ttyfd = 0; /* stdin */ + dlog_allowed_flag = BOOL_TRUE; + dlog_timeouts_flag = BOOL_TRUE; + + /* look for command line option claiming the operator knows + * what's up. + */ + optind = 1; + opterr = 0; + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + switch ( c ) { + case GETOPT_FORCE: + dlog_ttyfd = -1; + dlog_allowed_flag = BOOL_FALSE; + break; + case GETOPT_NOTIMEOUTS: + dlog_timeouts_flag = BOOL_FALSE; + break; + } + } +#ifdef RESTORE + /* look to see if restore source coming in on + * stdin. If so , try to open /dev/tty for dialogs. + */ + if ( optind < argc && ! strcmp( argv[ optind ], "-" )) { + dlog_ttyfd = open( "/dev/tty", O_RDWR ); + if ( dlog_ttyfd < 0 ) { + perror("/dev/tty"); + dlog_ttyfd = -1; + dlog_allowed_flag = BOOL_FALSE; + } + } +#endif /* RESTORE */ + +#ifdef CHKSTDIN + /* if stdin is not a tty, don't allow dialogs + */ + if ( dlog_allowed_flag ) { + struct stat statbuf; + int rval; + + ASSERT( dlog_ttyfd >= 0 ); + rval = fstat( dlog_ttyfd, &statbuf ); + if ( rval ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "could not fstat stdin (fd %d): %s (%d)\n", + dlog_ttyfd, + strerror( errno ), + errno ); + } else { + mlog( MLOG_DEBUG, + "stdin mode 0x%x\n", + statbuf.st_mode ); + } + } +#endif /* CHKSTDIN */ + + return BOOL_TRUE; +} + +bool_t +dlog_allowed( void ) +{ + return dlog_allowed_flag; +} + +void +dlog_desist( void ) +{ + dlog_allowed_flag = BOOL_FALSE; + dlog_ttyfd = -1; +} + +intgen_t +dlog_fd( void ) +{ + return dlog_ttyfd; +} + +void +dlog_begin( char *preamblestr[ ], size_t preamblecnt ) +{ + size_t ix; + + mlog_lock( ); + for ( ix = 0 ; ix < preamblecnt ; ix++ ) { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + preamblestr[ ix ] ); + } +} + +void +dlog_end( char *postamblestr[ ], size_t postamblecnt ) +{ + size_t ix; + + for ( ix = 0 ; ix < postamblecnt ; ix++ ) { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + postamblestr[ ix ] ); + } + mlog_unlock( ); +} + +ix_t +dlog_multi_query( char *querystr[ ], + size_t querycnt, + char *choicestr[ ], + size_t choicecnt, + char *hilitestr, + size_t hiliteix, + char *defaultstr, + ix_t defaultix, + time_t timeout, + ix_t timeoutix, + ix_t sigintix, + ix_t sighupix, + ix_t sigquitix ) +{ + size_t ix; + char buf[ 100 ]; + char *prepromptstr; + + /* sanity + */ + ASSERT( dlog_allowed_flag ); + ASSERT( choicecnt < 9 ); + + /* display query description strings + */ + for ( ix = 0 ; ix < querycnt ; ix++ ) { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + querystr[ ix ] ); + } + + /* display the choices: NOTE: display is 1-based, code intfs 0-based! + */ + for ( ix = 0 ; ix < choicecnt ; ix++ ) { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + "%u: %s", + ix + 1, + choicestr[ ix ] ); + if ( ix == hiliteix ) { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + "%s", + hilitestr ? hilitestr : " *" ); + } + if ( ix == defaultix ) { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + "%s", + defaultstr ? defaultstr : " (default)" ); + } + if ( dlog_timeouts_flag + && + timeoutix != IXMAX + && + ix == timeoutix ) { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + " (timeout in %u sec)", + timeout ); + } + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + "\n" ); + } + + /* read the tty until we get a proper answer or are interrupted + */ + prepromptstr = ""; + for ( ; ; ) { + ix_t exceptionix; + bool_t ok; + + /* prompt and accept input + */ + ok = promptinput( buf, + sizeof( buf ), + &exceptionix, + timeout, + timeoutix, + sigintix, + sighupix, + sigquitix, + prepromptstr, + choicecnt ); + if ( ok ) { + if ( ! strlen( buf )) { + return defaultix; + } + if ( strlen( buf ) != 1 ) { + prepromptstr = + "please enter a single " + "digit response (1 to %d)"; + continue; + } + if ( buf[ 0 ] < '1' + || + buf[ 0 ] >= '1' + ( u_char_t )choicecnt ) { + prepromptstr = + "please enter a single digit " + "between 1 and %d inclusive "; + continue; + } + return ( size_t )( buf[ 0 ] - '1' ); + } else { + return exceptionix; + } + } + /* NOTREACHED */ +} + +void +dlog_multi_ack( char *ackstr[ ], size_t ackcnt ) +{ + size_t ix; + + for ( ix = 0 ; ix < ackcnt ; ix++ ) { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + ackstr[ ix ] ); + } +} + +ix_t +dlog_string_query( dlog_ucbp_t ucb, /* user's print func */ + void *uctxp, /* user's context for above */ + char *bufp, /* typed string returned in */ + size_t bufsz, /* buffer size */ + time_t timeout, /* secs b4 giving up */ + ix_t timeoutix, + ix_t sigintix, + ix_t sighupix, + ix_t sigquitix, + ix_t okix ) +{ + ix_t exceptionix; + bool_t ok; + + /* call the caller's callback with his context, print context, and + * print operator + */ + ( * ucb )( uctxp, dlog_string_query_print, 0 ); + + /* if called for, print the timeout and a newline. + * if not, print just a newline + */ + if ( dlog_timeouts_flag && timeoutix != IXMAX ) { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + " (timeout in %u sec)\n", + timeout ); + } else { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + "\n" ); + } + + /* prompt and accept input + */ + ok = promptinput( bufp, + bufsz, + &exceptionix, + timeout, + timeoutix, + sigintix, + sighupix, + sigquitix, + "" ); + if ( ok ) { + return okix; + } else { + return exceptionix; + } +} + +void +dlog_string_ack( char *ackstr[ ], size_t ackcnt ) +{ + dlog_multi_ack( ackstr, ackcnt ); +} + +/* ok that this is a static, since used under mutual exclusion lock + */ +static int dlog_signo_received; + +static void +sighandler( int signo ) +{ + dlog_signo_received = signo; +} + +/* ARGSUSED */ +static void +dlog_string_query_print( void *ctxp, char *fmt, ... ) +{ + va_list args; + + ASSERT( ! ctxp ); + + va_start( args, fmt ); + mlog_va( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, fmt, args ); + va_end( args ); +} + +static bool_t +promptinput( char *buf, + size_t bufsz, + ix_t *exceptionixp, + time_t timeout, + ix_t timeoutix, + ix_t sigintix, + ix_t sighupix, + ix_t sigquitix, + char *fmt, + ... ) +{ + va_list args; + u_intgen_t alarm_save = 0; + void (* sigalrm_save)(int) = NULL; + void (* sigint_save)(int) = NULL; + void (* sighup_save)(int) = NULL; + void (* sigterm_save)(int) = NULL; + void (* sigquit_save)(int) = NULL; + intgen_t nread; + pid_t pid = getpid( ); + + /* display the pre-prompt + */ + va_start( args, fmt ); + mlog_va( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, fmt, args ); + va_end( args ); + + /* display standard prompt + */ +#ifdef NOTYET + if ( dlog_timeouts_flag && timeoutix != IXMAX ) { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + "(timeout in %d sec)", + timeout ); + } +#endif /* NOTYET */ + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, promptstr ); + + /* set up signal handling + */ + dlog_signo_received = -1; + if ( dlog_timeouts_flag && timeoutix != IXMAX ) { + if ( pid == parentpid && ! miniroot ) { + ( void )sigrelse( SIGALRM ); + } + sigalrm_save = sigset( SIGALRM, sighandler ); + alarm_save = alarm( ( u_intgen_t )timeout ); + } + if ( sigintix != IXMAX ) { + if ( pid == parentpid && ! miniroot ) { + ( void )sigrelse( SIGINT ); + } + sigint_save = sigset( SIGINT, sighandler ); + } + if ( sighupix != IXMAX ) { + if ( pid == parentpid && ! miniroot ) { + ( void )sigrelse( SIGHUP ); + } + sighup_save = sigset( SIGHUP, sighandler ); + if ( pid == parentpid && ! miniroot ) { + ( void )sigrelse( SIGTERM ); + } + sigterm_save = sigset( SIGTERM, sighandler ); + } + if ( sigquitix != IXMAX ) { + if ( pid == parentpid && ! miniroot ) { + ( void )sigrelse( SIGQUIT ); + } + sigquit_save = sigset( SIGQUIT, sighandler ); + } + + /* wait for input, timeout, or interrupt + */ + ASSERT( dlog_ttyfd >= 0 ); + nread = read( dlog_ttyfd, buf, bufsz - 1 ); + + /* restore signal handling + */ + if ( sigquitix != IXMAX ) { + ( void )sigset( SIGQUIT, sigquit_save ); + if ( pid == parentpid && ! miniroot ) { + ( void )sighold( SIGQUIT ); + } + } + if ( sighupix != IXMAX ) { + ( void )sigset( SIGHUP, sighup_save ); + if ( pid == parentpid && ! miniroot ) { + ( void )sighold( SIGHUP ); + } + ( void )sigset( SIGTERM, sigterm_save ); + if ( pid == parentpid && ! miniroot ) { + ( void )sighold( SIGTERM ); + } + } + if ( sigintix != IXMAX ) { + ( void )sigset( SIGINT, sigint_save ); + if ( pid == parentpid && ! miniroot ) { + ( void )sighold( SIGINT ); + } + } + if ( dlog_timeouts_flag && timeoutix != IXMAX ) { + ( void )alarm( alarm_save ); + ( void )sigset( SIGALRM, sigalrm_save ); + if ( pid == parentpid && ! miniroot ) { + ( void )sighold( SIGALRM ); + } + } + + /* check for timeout or interrupt + */ + if ( nread < 0 ) { + if ( dlog_signo_received == SIGALRM ) { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + "timeout\n" ); + *exceptionixp = timeoutix; + } else if ( dlog_signo_received == SIGINT ) { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + "keyboard interrupt\n" ); + *exceptionixp = sigintix; + } else if ( dlog_signo_received == SIGHUP ) { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + "hangup\n" ); + *exceptionixp = sighupix; + } else if ( dlog_signo_received == SIGTERM ) { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + "terminate\n" ); + *exceptionixp = sighupix; + } else if ( dlog_signo_received == SIGQUIT ) { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + "keyboard quit\n" ); + *exceptionixp = sigquitix; + } else { + mlog( MLOG_NORMAL | MLOG_NOLOCK | MLOG_BARE, + "unknown signal during dialog: %d\n", + dlog_signo_received ); + *exceptionixp = sigquitix; + } + return BOOL_FALSE; + } else if ( nread == 0 ) { + *exceptionixp = timeoutix; + if ( bufsz > 0 ) { + buf[ 0 ] = 0; + } + return BOOL_FALSE; + } else { + ASSERT( dlog_signo_received == -1 ); + ASSERT( ( size_t )nread < bufsz ); + ASSERT( buf[ nread - 1 ] == '\n' ); + buf[ nread - 1 ] = 0; + *exceptionixp = 0; + return BOOL_TRUE; + } +} diff -rNu linux-2.4.7/cmd/xfsdump/common/dlog.h linux-2.4-xfs/cmd/xfsdump/common/dlog.h --- linux-2.4.7/cmd/xfsdump/common/dlog.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/dlog.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef DLOG_H +#define DLOG_H + +/* dlog.[hc] - operator dialog abstraction + * + * abstracts dialogs with the operator + */ + +extern bool_t dlog_init( int argc, char *argv[ ] ); + + +/* tells if dialogs are allowed; + * will be false if invoked to right of unnamed pipe, + * or if pipe to left breaks. + */ +extern bool_t dlog_allowed( void ); + + +/* allows signal handler to notify dlog of broken write pipe + */ +extern void dlog_desist( void ); + +/* returns the dialog tty file descriptor. returns -1 if none + */ +extern intgen_t dlog_fd( void ); + + +/* bracket a dialog session + */ +extern void dlog_begin( char *preamblestr[ ], size_t preamblecnt ); +extern void dlog_end( char *postamblestr[ ], size_t postamblecnt ); + + +/* multiple choice question abstraction. if any exception event index + * set to IXMAX, that event will be ignored. returns index of selected + * choice, or exception index if exception occured. + */ +extern ix_t dlog_multi_query( char *querystr[ ], /* pre-choices output */ + size_t querycnt, /* length of above */ + char *choicestr[ ], /* choices */ + size_t choicecnt, /* length of above */ + char *hilitestr, /* to distinguish */ + ix_t hiliteix, /* highlighted choice */ + char *defaultstr, /* to distinguish */ + ix_t defaultix, /* return if cr */ + time_t timeout, /* secs b4 giving up */ + ix_t timeoutix, /* return if timeout */ + ix_t sigintix, /* return if SIGINT */ + ix_t sighupix, /* return if SIGHUP */ + ix_t sigquitix ); /* return if SIGQUIT */ +extern void dlog_multi_ack( char *ackstr[ ], size_t ackcnt ); + +/* call the caller's callback to display whatever, using provided print + * function, then prompt for and return an arbitrary string. two types + * defined: pointer to the caller's function to print, and pointer to + * function used by that function to do output. returns okix if successful, + * timeoutix if times out, sigintix if SIGINT recieved, sighupix if SIGHUP + * received, sigquitix if SIGQUIT received. if any of the exception indices + * are set to IXMAX by the caller, those events will be ignored. + */ +typedef void ( * dlog_pcbp_t )( void *pctxp, char *s, ... ); +typedef void ( * dlog_ucbp_t )( void *uctxp, dlog_pcbp_t pcb, void *pctxp ); +extern ix_t dlog_string_query( dlog_ucbp_t ucb, /* user's print func */ + void *uctxp, /* user's context for above */ + char *bufp, /* typed string returned in */ + size_t bufsz, /* buffer size */ + time_t timeout, /* secs b4 giving up */ + ix_t timeoutix, /* return if timeout */ + ix_t sigintix, /* return if SIGINT */ + ix_t sighupix, /* return if SIGHUP */ + ix_t sigquitix, /* return if SIGQUIT */ + ix_t okix ); /* return if successful */ +extern void dlog_string_ack( char *ackstr[ ], size_t ackcnt ); + +#endif /* DLOG_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/drive.c linux-2.4-xfs/cmd/xfsdump/common/drive.c --- linux-2.4.7/cmd/xfsdump/common/drive.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/drive.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include + +#include "types.h" +#include "util.h" +#include "mlog.h" +#include "dlog.h" +#include "path.h" +#include "getopt.h" +#include "global.h" +#include "drive.h" + +/* drive.c - selects and initializes a drive strategy + */ + + +/* structure definitions used locally ****************************************/ + + +/* declarations of externally defined global symbols *************************/ + +extern void usage( void ); +extern char *homedir; + +/* declare all drive strategies here + */ +extern drive_strategy_t drive_strategy_simple; +extern drive_strategy_t drive_strategy_scsitape; +extern drive_strategy_t drive_strategy_rmt; + + +/* forward declarations of locally defined static functions ******************/ + +static drive_t *drive_alloc( char *, size_t ); +static void drive_allochdrs( drive_t *drivep, + global_hdr_t *gwhdrtemplatep, + ix_t driveix ); + + +/* definition of locally defined global variables ****************************/ + +drive_t **drivepp; +size_t drivecnt; +size_t partialmax; + +/* definition of locally defined static variables *****************************/ + +/* drive strategy array - ordered by precedence + */ +static drive_strategy_t *strategypp[] = { + &drive_strategy_simple, + &drive_strategy_scsitape, + &drive_strategy_rmt, +}; + + +/* definition of locally defined global functions ****************************/ + +/* drive_init1 - select and instantiate a drive manager for each drive + * specified on the command line. + */ +bool_t +drive_init1( int argc, char *argv[ ], bool_t singlethreaded ) +{ + intgen_t c; + ix_t driveix; + + /* sanity check asserts + */ + ASSERT( sizeof( drive_hdr_t ) == DRIVE_HDR_SZ ); + + /* count drive arguments + */ + optind = 1; + opterr = 0; + drivecnt = 0; + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + switch ( c ) { + case GETOPT_DUMPDEST: + drivecnt++; + break; + } + } + + /* validate drive count + */ + if ( singlethreaded && drivecnt > 1 ) { + mlog( MLOG_NORMAL, + "too many -%c arguments: " + "maximum is %d when running in miniroot\n", + optopt, + 1 ); + usage( ); + return BOOL_FALSE; + } + + /* allocate an array to hold ptrs to drive descriptors + */ + if (drivecnt > 0) { + drivepp = ( drive_t ** )calloc( drivecnt, sizeof( drive_t * )); + ASSERT( drivepp ); + } + + /* initialize the partialmax value. Each drive can be completing a file + * started in another drive (except for drive 0) and leave one file to + * be completed by another drive. This value is used to limit the + * search in the list of partially completed files shared between all + * restore streams. Note, if drivecnt is one, then partialmax is zero + * to indicate no partial files can span streams. + */ + partialmax = (drivecnt <= 1 ? 0 : (drivecnt * 2) - 1); + + /* initialize drive descriptors from command line arguments + */ + optind = 1; + opterr = 0; + driveix = 0; + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + char optarray[100]; + char *devname; + char *token; + + switch ( c ) { + case GETOPT_DUMPDEST: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL, + "-%c argument missing\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + + /* remove the device name from the rest of the + * parameter string. note that strdup malloc()s + * a string; important since optarray is an auto. + */ + ASSERT( strlen( optarg ) < sizeof( optarray )); + strncpy( optarray, optarg, sizeof( optarray )); + optarray[ sizeof( optarray ) - 1 ] = 0; + if ( ( token = strtok( optarray, "," )) == NULL ) { + token = optarray; + } + devname = strdup( token ); + + /* allocate a drive descriptor + */ + drivepp[ driveix ] = drive_alloc( devname, driveix ); + driveix++; + break; + } + } + ASSERT( driveix == drivecnt ); + + /* the user may specify stdin as the source, by + * a single dash ('-') with no option letter. This must appear + * between all lettered arguments and the file system pathname. + */ + if ( optind < argc && ! strcmp( argv[ optind ], "-" )) { + if ( driveix > 0 ) { + mlog( MLOG_NORMAL, + "cannot specify source files and standard " +#ifdef DUMP + "out " +#endif /* DUMP */ +#ifdef RESTORE + "in " +#endif /* RESTORE */ + "together\n" ); + usage( ); + return BOOL_FALSE; + } + + drivecnt = 1; + + /* Adding this alloc to fix malloc corruption. + * Bug #393618 - prasadb 04/16/97 + * allocate an array to hold ptrs to drive descriptors + */ + drivepp = ( drive_t ** )calloc( drivecnt, sizeof( drive_t * )); + ASSERT( drivepp ); + + drivepp[ 0 ] = drive_alloc( "stdio", 0 ); + +#ifdef DUMP /* ifdef added around dlog_desist() by prasadb to fix 435626 */ + dlog_desist( ); +#endif + } + + /* verify that some dump destination(s) / restore source(s) specified + */ + if ( drivecnt == 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "no " +#ifdef DUMP + "destination " +#endif /* DUMP */ +#ifdef RESTORE + "source " +#endif /* RESTORE */ + "file(s) specified\n" ); + usage( ); + return BOOL_FALSE; + } + + /* run each drive past each strategy, pick the best match + * and instantiate a drive manager. + */ + for ( driveix = 0 ; driveix < drivecnt ; driveix++ ) { + drive_t *drivep = drivepp[ driveix ]; + intgen_t bestscore = 0 - INTGENMAX; + ix_t six; + ix_t scnt = sizeof( strategypp ) / sizeof( strategypp[ 0 ] ); + drive_strategy_t *bestsp = 0; + bool_t ok; + + for ( six = 0 ; six < scnt ; six++ ) { + drive_strategy_t *sp = strategypp[ six ]; + intgen_t score; + score = ( * sp->ds_match )( argc, + argv, + drivep, + singlethreaded ); + if ( ! bestsp || score > bestscore ) { + bestsp = sp; + bestscore = score; + } + } + ASSERT( bestsp ); + drivep->d_strategyp = bestsp; + drivep->d_recmarksep = bestsp->ds_recmarksep; + drivep->d_recmfilesz = bestsp->ds_recmfilesz; + mlog( MLOG_DEBUG, + "instantiating %s\n", + bestsp->ds_description ); + ok = ( * bestsp->ds_instantiate )( argc, + argv, + drivep, + singlethreaded ); + if ( ! ok ) { + return BOOL_FALSE; + } + } + + return BOOL_TRUE; +} + + +/* drive_init2 - second phase strategy initialization. + * allocates global read and write hdrs, copying global hdr template + * into the write hdrs (DUMP only). kicks off async init for each drive, + * which will be synchronized with drive_init3. + */ +/* ARGSUSED */ +bool_t +drive_init2( int argc, + char *argv[ ], + global_hdr_t *gwhdrtemplatep ) +{ + ix_t driveix; + + for ( driveix = 0 ; driveix < drivecnt ; driveix++ ) { + drive_t *drivep = drivepp[ driveix ]; + bool_t ok; + + drive_allochdrs( drivep, gwhdrtemplatep, driveix ); + ok = ( * drivep->d_opsp->do_init )( drivep ); + if ( ! ok ) { + return BOOL_FALSE; + } + } + + return BOOL_TRUE; +} + + +/* drive_init3 - third phase strategy initialization. + * synchronizes with async operations begun by drive_init2. + */ +bool_t +drive_init3( void ) +{ + ix_t driveix; + + for ( driveix = 0 ; driveix < drivecnt ; driveix++ ) { + drive_t *drivep = drivepp[ driveix ]; + bool_t ok; + + ok = ( * drivep->d_opsp->do_sync )( drivep ); + if ( ! ok ) { + return BOOL_FALSE; + } + } + + return BOOL_TRUE; +} + + +/* drive_mark_commit - commits and unlinks all accumulated marks with + * offsets less than or equal to the offset of the next (as yet unwritten) + * byte in the media file. + * utility function for use by drive-specific strategies. + */ +void +drive_mark_commit( drive_t *drivep, off64_t ncommitted ) +{ + drive_markrec_t *dmp; + + for ( dmp = drivep->d_markrecheadp + ; + dmp && dmp->dm_log <= ( drive_mark_t )ncommitted + ; + ) { + drivep->d_markrecheadp = dmp->dm_nextp; + ( * dmp->dm_cbfuncp )( dmp->dm_cbcontextp, dmp, BOOL_TRUE ); + dmp = drivep->d_markrecheadp; + } +} + +/* drive_mark_discard - unlinks all accumulated marks, calling their callbacks + * indicating the mark was NOT committed. + * utility function for use by drive-specific strategies. + */ +void +drive_mark_discard( drive_t *drivep ) +{ + drive_markrec_t *dmp; + + for ( dmp = drivep->d_markrecheadp + ; + dmp + ; + drivep->d_markrecheadp = dmp->dm_nextp, dmp = dmp->dm_nextp ) { + + ( * dmp->dm_cbfuncp )( dmp->dm_cbcontextp, dmp, BOOL_FALSE ); + } +} + +/* drive_display_metrics - called by main thread during interactive dialog + * to print drive throughput and streaming metrics. + */ +void +drive_display_metrics( void ) +{ + ix_t driveix; + + for ( driveix = 0 ; driveix < drivecnt ; driveix++ ) { + drive_t *drivep = drivepp[ driveix ]; + drive_ops_t *dop = drivep->d_opsp; + if ( dop->do_display_metrics ) { + ( * dop->do_display_metrics )( drivep ); + } + } +} + + +/* definition of locally defined static functions ****************************/ + +/* drive_alloc - allocate and initialize the generic portions of a drive + * descriptor. do NOT allocate hdr buffers. + */ +static drive_t * +drive_alloc( char *pathname, ix_t driveix ) +{ + drive_t *drivep; + struct stat64 statbuf; + + /* allocate the descriptor + */ + drivep = ( drive_t * )calloc( 1, sizeof( drive_t )); + ASSERT( drivep ); + + /* convert the pathname to an absolute pathname + * NOTE: string "stdio" is reserved to mean send to standard out + */ + if ( strcmp( pathname, "stdio" )) { + pathname = path_reltoabs( pathname, homedir ); + } + + /* set pipe flags + */ + if ( ! strcmp( pathname, "stdio" )) { + drivep->d_isunnamedpipepr = BOOL_TRUE; + } else if ( ! stat64( pathname, &statbuf ) + && + ( statbuf.st_mode & S_IFMT ) == S_IFIFO ) { + drivep->d_isnamedpipepr = BOOL_TRUE; + } + + /* complete the drive manager + */ + drivep->d_pathname = pathname; + drivep->d_index = driveix; + + return drivep; +} + +/* drive_allochdrs - allocate and initialize the drive read and write + * hdrs, and ptrs into the hdrs. + */ +static void +drive_allochdrs( drive_t *drivep, global_hdr_t *gwhdrtemplatep, ix_t driveix ) +{ + global_hdr_t *grhdrp; + drive_hdr_t *drhdrp; + global_hdr_t *gwhdrp; + drive_hdr_t *dwhdrp; + + /* allocate the read header + */ + grhdrp = ( global_hdr_t * )calloc( 1, sizeof( global_hdr_t )); + ASSERT( grhdrp ); + gwhdrp = NULL; + dwhdrp = NULL; + + /* calculate pointer to the drive portion of the read header + */ + drhdrp = ( drive_hdr_t * )grhdrp->gh_upper; + + /* global write hdr used only for dumps. will be NULL for restore + */ + if ( gwhdrtemplatep ) { + /* allocate the write header + */ + gwhdrp = ( global_hdr_t * )calloc( 1, sizeof( global_hdr_t )); + ASSERT( gwhdrp ); + + /* copy the template + */ + *gwhdrp = *gwhdrtemplatep; + + /* calculate pointer to the drive portion of the read header + */ + dwhdrp = ( drive_hdr_t * )gwhdrp->gh_upper; + + /* fill in generic drive fields of write hdr + */ + dwhdrp->dh_strategyid = drivep->d_strategyp->ds_id; + dwhdrp->dh_driveix = driveix; + dwhdrp->dh_drivecnt = drivecnt; + } + + /* complete the drive manager + */ + drivep->d_greadhdrp = grhdrp; + drivep->d_readhdrp = drhdrp; + drivep->d_gwritehdrp = gwhdrp; + drivep->d_writehdrp = dwhdrp; +} diff -rNu linux-2.4.7/cmd/xfsdump/common/drive.h linux-2.4-xfs/cmd/xfsdump/common/drive.h --- linux-2.4.7/cmd/xfsdump/common/drive.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/drive.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,709 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef DRIVE_H +#define DRIVE_H + +/* drive.[hc] - drive abstraction + * + * drive_t provides a framework for device-independent drive abstraction, + * as well as initialization of appropriate drive handlers. + * + * A drive_t is a drive manager providing capabilities for reading, writing, + * and manipulating media objects (e.g., tape cartridges). + * + * All writing and reading is done within the scope of a media file. Writes + * may be cut short due to media events (e.g., EOM). The mark + * mechanism allows the caller to determine what portion of the write data + * stream is guaranteed to have been committed to media. + * + * Marks may be placed in the stream during writes. During subsequent + * reads of the data stream, the media object may be positioned at a + * specific mark, or to the next mark in the stream. + * + * To accomodate end-of-media uncertainty, the marks are set in two steps. + * First the caller asks to set a mark at a position within the write stream, + * providing a callback function. The callback will be invoked when the data + * prior to that mark has been committed to media. + * + * The caller must re-position the media (e.g., change media objects or + * begin a new media file) and re-write any portion of the data written + * after the last committed mark. It is entirely possible for part of that + * data to have made it onto the previous media file, due to the uncertainty + * of end-of-media handling of some drives. Thus the caller must be prepared + * for portions of data read from the end of one media file to be duplicated + * at the beginning of the next media file. + * + * To allow repositioning the stream in the above scenarios, + * drive_t supplies forward-space-file, backward-space-file, rewind, + * seek_mark, and get_mark operators. + * + * A call to the end_read or end_write operator virtually positions the + * media at the beginning of the next media file. Thus if a caller calls + * begin read, looks at the header and decides to overwrite the media + * file, a call to the bsf operator must be made prior to the call to + * begin_write. However, if the media is positioned at EOD and the caller calls + * begin_read, EOD will be returned and no repositioning is needed. A call + * to begin_write will append a new media file after the last media file. + * + * Drive_init1 selects and instantiates a drive manager for each drive + * identified on the command line. This is done by showing the drive + * successively to each drive strategy module. The drive strategies + * supply a match score. The strategy with the highest score gets to + * instantiate a drive manager for that drive. + * + * Drive_init2 allocates and initializes read and write header buffers for + * each drive, and calls each drive manager's init operator, which begins async + * initialization of the drive. This includes determining if a media object + * is currently mounted in that drive. + * + * Drive_init3 synchronizes with the async initializations kicked off by + * drive_init2. + * + * Each drive strategy is defined by a drive_strategy_t. This supplies + * a match function, and an instantiate function. + * + * The match function lets the given strategy determine if it is the correct + * strategy to choose. The instantiate function creates a driver manager. + * + * The I/O write model presents the user with a function to get a write buffer, + * or get a page-aligned write buffer, and a function to take back the buffer + * and commit part or all of that buffer to media. The read model is similar; + * the caller may ask for a buffer filled with read data, and gives the buffer + * back after the data is used. These models facilitate high-performance + * operation, since the buffers can be used in direct I/O. + */ + +/* drive_hdr_t - drive media file header + * + * A drive media file header is imbedded in the global media file header + * structure, which is in turn placed at the beginning of each media file. The + * drive hdr has three parts: generally useful drive-related info, info + * specific to the selected drive strategy, and upper layer info. Each drive + * handler contains two drive header images; a read hdr and a write hdr. + * + * CAUTION! the various components of the media file header are carefully + * crafted to fit in DRIVE_HDR_SZ bytes. + */ +#define DRIVE_HDR_SZ sizeofmember( global_hdr_t, gh_upper ) + +struct drive_hdr { + u_int32_t dh_drivecnt; /* 4 4 */ + /* number of drives used to dump the fs */ + u_int32_t dh_driveix; /* 4 8 */ + /* 0-based index of the drive used to dump this stream */ + int32_t dh_strategyid; /* 4 c */ + /* ID of the drive strategy used to produce this dump */ + char dh_pad1[ 0x1f4 ]; /* 1f4 200 */ + /* padding */ + char dh_specific[ 0x200 ]; /* 200 400 */ + /* drive strategy-specific info */ + char dh_upper[ DRIVE_HDR_SZ - 0x400 ]; /* 800 c00 */ + /* header info private to upper software layers */ +}; + +typedef struct drive_hdr drive_hdr_t; + +/* drive_strategy_t - drive strategy + * + * The drive strategy has two operators, ds_match() and ds_instantiate(). + * ds_match() returns an integer indicating the degree of match of the + * strategy to the drives indicated on the command line. ds_init() + * initializes the drive strategy, creates and initializes a drive manager + * for each drive, and if possible positions each drive at the beginning of + * the current file and reads the file header into d_readhdr. ds_drivep + * points to an array of drive managers, and ds_drivecnt indicates + * the length of that array. + */ +struct drive; /* forward declaration */ + +struct drive_strategy { + intgen_t ds_id; + /* strategy ID + */ + char *ds_description; + /* a short char string describing strategy + */ + intgen_t ( * ds_match )( intgen_t argc, + char *argv[ ], + struct drive *drivep, + bool_t singlethreaded ); + /* returns degree of match. drivep has been pre-allocated + * and initialized with generic info. + */ + bool_t ( * ds_instantiate )( intgen_t argc, + char *argv[ ], + struct drive *drivep, + bool_t singlethreaded ); + /* creates a drive manager instance, by filling in the + * blanks of the pre-allocated drive descriptor + * returns FALSE on failure. + */ + off64_t ds_recmarksep; + /* recommended maximum separation (in bytes) + * between marks. can be observed when sending + * long data streams to the drive. this field is + * transfered to d_recmarksep during instantiation. + */ + off64_t ds_recmfilesz; + /* recommended maximum length of media files. + * transfered to d_recmarksep during instantiation. + */ +}; + +typedef struct drive_strategy drive_strategy_t; + +/* definitions of strategy ids + */ +#define DRIVE_STRATEGY_SCSITAPE 0 +#define DRIVE_STRATEGY_SIMPLE 1 +#define DRIVE_STRATEGY_RMT 0 /* same as SCSITAPE for now */ + + +/* drive_mark_t - token identifying a mark within a media object file + * + * 64 bit cookie, the structure of which is known only to the drive manager + * which generated it. generated by do_get_mark, given to do_seek_mark. + */ +typedef off64_t drive_mark_t; + +/* drive mark callback function + * invoked for each mark registered with do_set_mark, in the same order. + * committed is TRUE if the data up to the mark was committed to media. + * committed is FALSE if it is POSSIBLE that some data prior to the mark + * was NOT committed. + */ +struct drive_markrec; /* forward decl */ +typedef void ( * drive_mcbfp_t )( void *context_t, + struct drive_markrec *markrecp, + bool_t committed ); + +/* drive_markrec_t - context for set mark callback function + * + * caller allocates and passes ptr to do_set_mark, along with a callback func. + * callback returns the record, which must be freed by the original caller. + * + */ +struct drive_markrec { + drive_mark_t dm_log; /* identifies position within mfile */ + drive_mcbfp_t dm_cbfuncp; /* caller's callback function */ + void *dm_cbcontextp; /* caller's context */ + struct drive_markrec *dm_nextp; /* for linked list */ +}; + +typedef struct drive_markrec drive_markrec_t; + +/* drive_t - drive manager + * + * A drive manager is described by a set of generic parameters + * and operators. + */ +struct drive_ops; /* forward declaration */ + +struct drive { + drive_strategy_t *d_strategyp; + /* back ptr to strategy + */ + struct drive_ops *d_opsp; + /* pointer to drive operations + */ + void *d_contextp; + /* manager-specific data + */ + global_hdr_t *d_greadhdrp; + /* global portion of media file header of + * media file drive currently positioned. + */ + drive_hdr_t *d_readhdrp; + /* drive portion of media file header of + * media file drive currently positioned. + */ + global_hdr_t *d_gwritehdrp; + /* global portion of media file header to + * be written by the next begin_write op. + */ + drive_hdr_t *d_writehdrp; + /* drive portion of media file header to + * be written by the next begin_write op. + */ + char *d_pathname; /* e.g., /dev/tape */ + ix_t d_index; /* e.g., 0, 1, 2, ... */ + bool_t d_isnamedpipepr; /* is a named pipe */ + bool_t d_isunnamedpipepr;/* is an unnamed pipe */ + intgen_t d_capabilities;/* see DRIVE_CAP_xxx below */ + off64_t d_cap_est; /* capacity estimate in bytes; -1 if unknown */ + intgen_t d_rate_est; /* bytes per second; -1 if unknown */ + drive_markrec_t *d_markrecheadp; /* linked list of mark records */ + drive_markrec_t *d_markrectailp; /* yet to be committed */ + off64_t d_recmarksep; /* transfered from strategy on instantiation */ + off64_t d_recmfilesz; /* transfered from strategy on instantiation */ +}; + +typedef struct drive drive_t; + +struct drive_ops { + bool_t ( * do_init )( drive_t *drivep ); + /* initializes drive, and begins async + * determination of media object presence + * returns FALSE if session should be aborted. + */ + bool_t ( * do_sync )( drive_t *drivep ); + /* synchronizes with the activity kicked off + * by do_init. returns FALSE if session should + * be aborted. + */ + intgen_t ( * do_begin_read )( drive_t *drivep ); + /* prepares the drive manager for reading. + * if the media is positioned at BOM or just + * after a file mark, current media file is + * begun. Otherwise, the drive will advance + * media to just after the next file mark first. + * loads the read header buffer with the + * header at the beginning of the media file. + * return value will be set non zero: + * BLANK - blank tape, positioned + * at BOT and ready for a + * do_begin_write; + * FOREIGN - unrecognized data at + * BOT, positioned + * at BOT and ready for a + * do_begin_write; + * EOD - tried to read past end of + * recorded data; + * EOM - tried to read past end of media + * object; + * MEDIA - no media object in drive; + * FORMAT - unrecognized media file header; + * VERSION - unsupported media file header; + * CORRUPTION - encountered corrupt data + * at beginning of media file; + * DEVICE - drive hardware error, other + * than missing media; + * INVAL - operator error; + * CORE - driver wants core dump; + * STOP - upper level asked lengthy + * drive op to give up. + * OVERWRITE - overwrite option to dump + * specified by user. Assume tape + * positioned and ready for write. + * if not successful (non-zero return), caller + * must NOT call end_read prior to next + * begin_read. if successful, caller MUST call + * end_read prior to next begin_read. + */ + char * ( * do_read )( drive_t *drivep, + size_t wanted_bufsz, + size_t *actual_bufszp, + intgen_t *statp ); + /* asks the drive manager for a buffered filled + * with the next read stream data. + * the actual buffer size supplied may + * be shorter than requested; it will never + * be longer than requested. the buffer + * should be returned to the drive manager as + * soon as possible, to facilitate drive + * streaming. the actual buffer size may + * be short due to the internal buffering + * mechanism, or due to media events; in + * the latter case, *statp will explain why: + * EOD - tried to read past end of + * recorded data; this is semant- + * ically equiv. to EOF, but + * occurs on last media file only. + * EOF - hit end of media file prior + * to completing read; probably + * due to a write fail during dump, + * or were near end of tape (e.g., + * early warning). + * EOM - tried to read past end of media + * object; + * MEDIA - no media object in drive; + * CORRUPTION - encountered corrupt data; + * DEVICE - drive hardware error, other + * than missing media; + * CORE - driver wants core dump; + * in all cases, the buffer returned contains + * valid data (although the buffer size may + * be zero!). + */ + void ( * do_return_read_buf )( drive_t *drivep, + char *bufp, + size_t bufsz ); + /* returns the buffer obtained + * from the previous do_read() call. + * the entire buffer must be returned + * in one shot. + */ + void ( * do_get_mark )( drive_t *drivep, + drive_mark_t *drivemarkp ); + /* returns (by reference) a mark corresponding + * to the next byte which will be read by a + * call to do_read(). will be used in a later + * session to seek to that position. + */ + intgen_t ( * do_seek_mark )( drive_t *drivep, + drive_mark_t *drivemarkp ); + /* searches for the specified mark within the + * current file. returns zero if the mark + * was found, or an error explaining why not: + * EOF - end of file was encountered; + * EOD - end of recorded date encountered; + * EOM - end of media encountered; + * CORRUPTION - encountered corrupt data; + * DEVICE - device error; + */ + intgen_t ( * do_next_mark )( drive_t *drivep ); + /* if d_capabilities has DRIVE_CAP_NEXTMARK set, + * drive has the capability to + * seek forward to the next mark. returns + * zero if a mark was found, or an error code: + * EOF - end of file was encountered; + * EOD - end of recorded date encountered; + * EOM - end of media encountered; + * DEVICE - device error; + * if currently at a mark, will go to the next. + */ + void ( *do_end_read )( drive_t *drivep ); + /* ends the file read. must be called prior + * to beginning another read or write session. + * ensures that the next call to begin_read + * will position the media at the next media + * file. + */ + intgen_t ( * do_begin_write )( drive_t *drivep ); + /* begins a write media file for writing. + * asserts the media is positioned at BOM or + * just after a file mark. write header will + * be placed at the head of the file. + * same return codes as do_write(): + * EOM - end of media object encountered; + * MEDIA - media object missing or broken; + * DEVICE - device error; + * CORE - driver error + */ + void ( * do_set_mark )( drive_t *drivep, + drive_mcbfp_t cbfuncp, + void *cbcontextp, + drive_markrec_t *markrecp ); + /* marks the position in the write stream + * where the next write will occur. + * At the time the data written + * prior to the mark is committed to media, + * the callback will be invoked, with + * the context and markrec pointers. The caller + * append his mark context to the drive markrec + * buffer pointed to by markrecp. the drive + * manager will use the drive_markrec_t + * to track the progress of the mark. + * If EOM is encountered before the + * mark is committed to media, the mark + * callback for all uncommitted marks will + * be called, but with the committed flag + * set to FALSE. it is up to the + * caller to free the mark buffers he previously + * allocated. note the drive strategy member + * d_recmarksep, the recommended maximum + * separation between marks. This is a hint + * based on underlying drive characteristics. + * the caller should record the committed + * marks; when do_write() fails due to + * EOM, the caller can resume writing after + * last committed marked point in the write + * stream. + */ + char * ( * do_get_write_buf )( drive_t *drivep, + size_t wanted_bufsz, + size_t *actual_bufszp ); + /* asks the drive manager for a buffer. + * returns a pointer to a buffer, and its + * size. must call do_write() before + * calling do_get_write_buf() again. By asking + * the drive manager for a buffer, buffer + * copying can be avoided. This facilitates + * achieving streaming performance on tape + * media. Also, the drive manager can implement + * a double-buffering scheme, causing source + * reads and drive writes to occur + * simultaneously. note that the buffer can + * be larger or smaller than the wanted bufsz, + * but will be at least 1 byte in length. + */ + intgen_t ( * do_write )( drive_t *drivep, + char *bufp, + size_t bufsz ); + /* asks the drive manager to write bufsz + * bytes from the buffer, which was acquired + * from a previous call to do_get_write_buf(). + * returns the following status values: + * EOM - end of media object encountered; + * MEDIA - media object missing or broken; + * DEVICE - device error; + * CORE - driver error; + * in the case of a non-zero return status, + * the caller must refer to the last mark + * callback received, to know the last data + * guaranteed to have been committed to media. + * any writes subsequent to the placement of + * that mark may or may not be on media. + * the caller should therefore be prepared + * to see the same data twice when crossing + * a media file boundary while reading. + * note that no indication of the actual + * number of bytes written is returned. + * even if only part of the buffer + * obtained from do_get_write_buf() + * is used, the do_write() call returns the + * entire buffer to the drive manager; it + * is not available for subsequent writes. + * instead, the caller must get another buffer + * using do_get_write_buf(). + */ + size_t ( * do_get_align_cnt )( drive_t *drivep ); + /* used during writing. returns the number + * of bytes which should be written to + * page-align the next do_get_write_buf() + * call. NOTE: the caller can assume that + * alignment will be maintained after the + * initial alignment done using this info. + */ + intgen_t ( * do_end_write )( drive_t *drivep, off64_t *ncommittedp ); + /* terminates a media file write sequence. + * flushes any buffered data not yet committed + * to media, and calls callbacks for all marks + * not yet returned. just like do_write(), can + * encounter EOM, in which case the + * last affirmative mark callback received will + * indicate what portion of the write data + * stream may have not been committed to media. + * EOM - end of media object encountered; + * MEDIA - media object missing or broken; + * DEVICE - device error; + * returns by reference number of bytes + * committed to media for the media file. + * this is the number of bytes written to + * media, which may be greater than what the + * client wrote due to record padding. + * NOTE: if last call to do_write returned + * an error, do_end_write will not do any + * I/O, and will return 0. + */ + intgen_t ( * do_fsf )( drive_t *drivep, + intgen_t count, + intgen_t *statp ); + /* if d_capabilities has DRIVE_CAP_FSF set, + * drive has the capability to + * forward space count files. returns the + * number of actual files forwarded to. for + * example, if count is one, and there is a + * file after the current file, positions to + * the beginning of that file and returns 1. + * if the current file is the last one on the + * medium, returns 0, and leaves position at + * the end of recorded data, after the file + * mark. if there is a following file, + * positions such that the next read will + * retrieve the first data in that file. + * furthermore, *statp will be set in the + * following cases: + * EOD - encountered end of recorded data + * EOM - encountered end of media + * DEVICE - device error; + * NOTE: if media is positioned anywhere other + * than at the beginning of a media file, + * behaves as if position is at most recent + * file mark or BOT. + */ + intgen_t ( * do_bsf )( drive_t *drivep, + intgen_t count, + intgen_t *statp ); + /* if d_capabilities has DRIVE_CAP_BSF set, + * drive has the capability to backward space + * count files. returns the number of actual + * files backed to. + * can only be invoked when not reading or + * writing (i.e., only after calling end_read + * or end_write, or prior to calling begin_read + * or begin_write). if count is zero, backs + * up to the beginning of the last media file + * read or written. if count is 1, backs up to + * the media file preceeding that one. returns + * the number of media files skipped. if + * the current file is the first one on the + * medium, returns 0, and leaves position + * at the beginning of recorded data. if count + * is one and there is a preceeding file, + * positions such that the next read will + * retrieve the first data in that file. + * furthermore, *statp will be set in the + * following cases: + * BOM - hit beginning of recorded data; + * DEVICE - device error; + */ + intgen_t ( * do_rewind )( drive_t *drivep ); + /* if d_capabilities has DRIVE_CAP_REWIND set, + * drive has the capability to + * position at beginning of recorded data + * DEVICE - device error; + */ + intgen_t ( * do_erase )( drive_t *drivep ); + /* if d_capabilities has DRIVE_CAP_ERASE set, + * drive has the capability to + * erase: all content of media object is + * eradicated. + * DEVICE - device error; + */ + intgen_t ( * do_eject_media )( drive_t *drivep ); + /* if d_capabilities has DRIVE_CAP_EJECT set, + * drive has capability + * to eject media, and will do so when called. + * DEVICE - device error; + */ + intgen_t ( * do_get_device_class )( drive_t *drivep ); + /* returns the media class of the device + * (see below). + */ + void ( * do_display_metrics )( drive_t *drivep ); + /* use BARE mlog to print useful throughput + * and performance info. set to NULL if + * nothing to say. + */ + void ( * do_quit )( drive_t * drivep ); + /* tells the drive manager to de-allocate + * resources, INCLUDING the slave process. + */ +}; + +typedef struct drive_ops drive_ops_t; + +/* the drive managers are visible globally, but should be accessed sparingly. + * valid after drive_init1() returns successfully + */ +extern drive_t **drivepp; +extern size_t drivecnt; +extern size_t partialmax; + +/* drive capabilities - bit positions in the capabilities mask + * DO NOT CHANGE: used in dh_capabilities field of scsi drive hdr. + */ +#define DRIVE_CAP_BSF ( 1 << 0 ) /* can backspace files */ +#define DRIVE_CAP_FSF ( 1 << 1 ) /* can forwardspace files */ +#define DRIVE_CAP_REWIND ( 1 << 2 ) /* can rewind */ +#define DRIVE_CAP_FILES ( 1 << 4 ) /* supports multiple files */ +#define DRIVE_CAP_APPEND ( 1 << 5 ) /* can append to end of rec. data */ +#define DRIVE_CAP_OVERWRITE ( 1 << 6 ) /* can overwrite recorded data */ +#define DRIVE_CAP_ERASE ( 1 << 6 ) /* can erase media */ +#define DRIVE_CAP_NEXTMARK ( 1 << 8 ) /* can seek to a next good mark */ +#define DRIVE_CAP_EJECT ( 1 << 12 ) /* can eject media */ +#define DRIVE_CAP_AUTOREWIND ( 1 << 13 ) /* rewinds on media insertion */ +#define DRIVE_CAP_READ ( 1 << 14 ) /* can read media */ +#define DRIVE_CAP_REMOVABLE ( 1 << 15 ) /* can change media */ + +/* drive manager error codes - interpretation specific to and described + * in context of use. + */ +#define DRIVE_ERROR_CORRUPTION 1 +#define DRIVE_ERROR_EOF 2 +#define DRIVE_ERROR_EOD 3 +#define DRIVE_ERROR_EOM 4 +#define DRIVE_ERROR_BOM 5 +#define DRIVE_ERROR_DEVICE 6 +#define DRIVE_ERROR_FORMAT 7 +#define DRIVE_ERROR_MEDIA 8 +#define DRIVE_ERROR_VERSION 9 +#define DRIVE_ERROR_CORE 10 +#define DRIVE_ERROR_TIMEOUT 11 +#define DRIVE_ERROR_STOP 12 +#define DRIVE_ERROR_INVAL 13 +#define DRIVE_ERROR_BLANK 14 +#define DRIVE_ERROR_FOREIGN 15 +#define DRIVE_ERROR_OVERWRITE 16 + + +/* drive_init1 - select and instantiate a drive manager for each drive + * specified on the command line. + * + * Highly heuristic, using all avalable sources of information, including + * the command line (command name and parameters), experimentation, and + * drive-specific media functions, but excluding time-consuming operations + * such as tape motion. + * + * sets globals drivepp and drivecnt. + * + * Returns FALSE if utility should be aborted. + */ +extern bool_t drive_init1( int argc, char *argv[], bool_t singlethreaded ); + + +/* drive_init2 - allocate and initialize read and write hdr buffers, + * and cause each drive manager to asynchronously determine if + * drive has media object mounted. + * + * Returns FALSE if the session should be aborted. + */ +extern bool_t drive_init2( int argc, + char *argv[], + global_hdr_t *gwhdrtemplatep ); + + +/* drive_init3 - synchronize with async activity kicked off by drive_init3. + * + * Returns FALSE if the session should be aborted. + */ +extern bool_t drive_init3( void ); + +/* drive_mark_commit - invokes callback for all drive marks committed + * to media. ncommitted is the number of bytes actually committed to + * media so far. mark records with a mark offset less than or equal to + * ncommitted will have their callbacks invoked. + */ +extern void drive_mark_commit( drive_t *drivep, off64_t ncommitted ); + + +/* drive_mark_discard - invokes callback of all uncommitted marks, + * indicating the commit did not occur. + */ +extern void drive_mark_discard( drive_t *drivep ); + + +/* drive_display_metrics - display drive throughput and streaming metrics + * for all drives + */ +extern void drive_display_metrics( void ); + + +/* device classes + * used for determining which media driver to employ + */ +#define DEVICE_NONREMOVABLE 1 +#define DEVICE_TAPE_REMOVABLE 2 +#define DEVICE_DISK_REMOVABLE 3 + +#endif /* DRIVE_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/drive_minrmt.c linux-2.4-xfs/cmd/xfsdump/common/drive_minrmt.c --- linux-2.4.7/cmd/xfsdump/common/drive_minrmt.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/drive_minrmt.c Mon Apr 9 01:32:28 2001 @@ -0,0 +1,4041 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "util.h" +#include "qlock.h" +#include "cldmgr.h" +#include "mlog.h" +#include "dlog.h" +#include "global.h" +#include "drive.h" +#include "media.h" +#include "getopt.h" +#include "stream.h" +#include "ring.h" +#include "rec_hdr.h" +#include "arch_xlate.h" + + +/* drive_minrmt.c - drive strategy for non-SGI rmt tape devices + * This strategy is derived from the scsitape strategy. It is designed + * so that tapes written using this strategy can be read with the + * scsitape strategy and vice versa. + */ + +/* structure definitions used locally ****************************************/ + +/* remote tape protocol debug + */ +#ifdef OPENMASKED +static intgen_t open_masked_signals( char *path, int oflags ); +#else /* OPENMASKED */ +#define open_masked_signals(p,f) open(p,f) +#endif /* OPENMASKED */ + +#ifdef RMT +#ifdef RMTDBG +#define open(p,f) dbgrmtopen(p,f) +#define close(fd) dbgrmtclose(fd) +#define ioctl(fd,op,arg) dbgrmtioctl(fd,op,arg) +#define read(fd,p,sz) dbgrmtread(fd,p,sz) +#define write(fd,p,sz) dbgrmtwrite(fd,p,sz) +#else /* RMTDBG */ +#define open rmtopen +#define close rmtclose +#define ioctl rmtioctl +#define read rmtread +#define write rmtwrite +#endif /* RMTDBG */ +#endif /* RMT */ + +/* if the media file header structure changes, this number must be + * bumped, and STAPE_VERSION_1 must be defined and recognized. + */ +#define STAPE_VERSION 1 + +/* a bizarre number to help reduce the odds of mistaking random data + * for a media file or record header + */ +#define STAPE_MAGIC 0x13579bdf02468acell + +/* this much of each record is reserved for header info: the user + * data always begins at this offset from the beginning of each + * record. be sure global_hdr_t fits. + */ +#define STAPE_HDR_SZ PGSZ + +/* maximum tape record size. this is the max size of I/O buffers sent to drive. + * note that for variable block devices this determines the block size as well. + */ +#define STAPE_MAX_RECSZ 0x200000 /* 2M */ + +/* this is the smallest maximum block size for any tape device + * supported by xfsdump/xfsrestore. we use this when it is not possible + * to ask the driver for block size info. + */ +#define STAPE_MIN_MAX_BLKSZ 0x3c000 /* 240K, 245760 */ + +/* QIC tapes always use 512 byte blocks + */ +#define QIC_BLKSZ 512 + +/* number of record buffers in the I/O ring + */ +#define RINGLEN_MIN 1 +#define RINGLEN_MAX 10 +#define RINGLEN_DEFAULT 3 + +/* tape i/o request retry limit + */ +#define MTOP_TRIES_MAX 10 + +/* operational mode. can be reading or writing, but not both + */ +typedef enum { OM_NONE, OM_READ, OM_WRITE } om_t; + +/* drive_context - control state + * + * NOTE: ring used only if not singlethreaded + */ +struct drive_context { + om_t dc_mode; + /* current mode of operation (READ or WRITE) + */ + size_t dc_ringlen; + /* number of tape_recsz buffers in ring. only used + * for displaying ring info + */ + bool_t dc_ringpinnedpr; + /* are the ring buffers pinned down + */ + ring_t *dc_ringp; + /* handle to ring + */ + ring_msg_t *dc_msgp; + /* currently held ring message + */ + char *dc_bufp; + /* pre-allocated record buffer (only if ring not used) + */ + char *dc_recp; + /* pointer to current record buffer. once the current + * record is completely read or written by client, + * set to NULL. + */ + char *dc_recendp; + /* always set to point to just off the end of the + * current record buffer pointed to by dc_recp. valid + * only when dc_recp non-NULL. + */ + char *dc_dataendp; + /* same as dc_recendp, except for first and last + * records in media file. the first record is all + * pads after the header page. the last record may + * have been padded (as indicated by the rec_used + * field of the record header). in either case + * dc_dataendp points to first padding byte. + */ + char *dc_ownedp; + /* first byte in current buffer owned by caller. + * given to caller by do_read or do_get_write_buf + * set to null by do_return_read_buf or do_write. + */ + char *dc_nextp; + /* next byte available in current buffer to give + * to do_get_write_buf for writing or do_read for + * reading. + */ + off64_t dc_reccnt; + /* count of the number of records completely read or + * written by client, and therefore not represented + * by current dc_recp. valid initially and after + * each call to do_return_read_buf or do_write. + * NOT valid after a call to do_read or + * do_get_write_buf. always bumped regardless of + * read or write error status. + */ + off64_t dc_iocnt; + /* count of the number of records read or written + * to media without error. includes media file header + * record. this is incremented when the actual I/O is + * done. dc_reccnt is different, indicating what has + * been seen by client. slave may have read ahead / + * written behind. + */ + int dc_fd; + /* drive file descriptor. -1 when not open + */ + bool_t dc_isQICpr; + /* fixed 512 byte block size device. + */ + bool_t dc_canfsrpr; + /* can seek forward records at a time + */ + size_t dc_blksz; + /* actual tape blksize selected + */ + size_t dc_recsz; + /* actual tape record size selected + */ + off64_t dc_lostrecmax; + /* maximum number of records written without error + * which may be lost due to a near end-of-tape + * experience. a function of drive type and + * compression + */ + bool_t dc_singlethreadedpr; + /* single-threaded operation (no slave) + */ + bool_t dc_errorpr; + /* TRUE if error encountered during reading or writing. + * used to detect attempts to read or write after + * error reported. + */ + bool_t dc_recchksumpr; + /* TRUE if records should be checksumed + */ + bool_t dc_unloadokpr; + /* ok to issue unload command when do_eject invoked. + */ + bool_t dc_overwritepr; + /* overwrite tape without checking whats on it + */ + bool_t dc_singlemfilepr; + /* use only one media file + */ +}; + +typedef struct drive_context drive_context_t; + +/* macros for shortcut references to context. assumes a local variable named + * 'contextp'. + */ +#define tape_recsz ( contextp->dc_recsz ) +#define tape_blksz ( contextp->dc_blksz ) + +/* declarations of externally defined global variables ***********************/ + +extern void usage( void ); + +/* remote tape protocol declarations (should be a system header file) + */ +#ifdef RMT +extern int rmtopen( char *, int, ... ); +extern int rmtclose( int ); +extern int rmtfstat( int, struct stat * ); +extern int rmtioctl( int, int, ... ); +extern int rmtread( int, void*, uint); +extern int rmtwrite( int, const void *, uint); +#endif /* RMT */ + + +/* forward declarations of locally defined static functions ******************/ + +/* strategy functions + */ +static intgen_t ds_match( int, char *[], drive_t *, bool_t ); +static intgen_t ds_instantiate( int, char *[], drive_t *, bool_t ); + +/* manager operations + */ +static bool_t do_init( drive_t * ); +static bool_t do_sync( drive_t * ); +static intgen_t do_begin_read( drive_t * ); +static char *do_read( drive_t *, size_t , size_t *, intgen_t * ); +static void do_return_read_buf( drive_t *, char *, size_t ); +static void do_get_mark( drive_t *, drive_mark_t * ); +static intgen_t do_seek_mark( drive_t *, drive_mark_t * ); +static intgen_t do_next_mark( drive_t * ); +static void do_get_mark( drive_t *, drive_mark_t * ); +static void do_end_read( drive_t * ); +static intgen_t do_begin_write( drive_t * ); +static void do_set_mark( drive_t *, drive_mcbfp_t, void *, drive_markrec_t * ); +static char * do_get_write_buf( drive_t *, size_t , size_t * ); +static intgen_t do_write( drive_t *, char *, size_t ); +static size_t do_get_align_cnt( drive_t * ); +static intgen_t do_end_write( drive_t *, off64_t * ); +static intgen_t do_fsf( drive_t *, intgen_t , intgen_t *); +static intgen_t do_bsf( drive_t *, intgen_t , intgen_t *); +static intgen_t do_rewind( drive_t * ); +static intgen_t do_erase( drive_t * ); +static intgen_t do_eject_media( drive_t * ); +static intgen_t do_get_device_class( drive_t * ); +static void do_display_metrics( drive_t *drivep ); +static void do_quit( drive_t * ); + +/* misc. local utility funcs + */ +static intgen_t mt_op(intgen_t , intgen_t , intgen_t ); +static intgen_t determine_write_error( int, int ); +static intgen_t read_label( drive_t *); +static bool_t tape_rec_checksum_check( drive_context_t *, char * ); +static void set_recommended_sizes( drive_t *, int ); +static void display_access_failed_message( drive_t *); +static bool_t get_tpcaps( drive_t * ); +static intgen_t prepare_drive( drive_t *drivep ); +static bool_t Open( drive_t *drivep ); +static void Close( drive_t *drivep ); +static intgen_t Read( drive_t *drivep, + char *bufp, + size_t cnt, + intgen_t *errnop ); +static intgen_t Write( drive_t *drivep, + char *bufp, + size_t cnt, + intgen_t *saved_errnop ); +static intgen_t record_hdr_validate( drive_t *drivep, + char *bufp, + bool_t chkoffpr ); +static void ring_thread( void *clientctxp, + int ( * entryp )( void *ringctxp ), + void *ringctxp ); +static int ring_read( void *clientctxp, char *bufp ); +static int ring_write( void *clientctxp, char *bufp ); +static double percent64( off64_t num, off64_t denom ); +static intgen_t getrec( drive_t *drivep ); +static intgen_t write_record( drive_t *drivep, char *bufp, bool_t chksumpr ); +static ring_msg_t * Ring_get( ring_t *ringp ); +static void Ring_reset( ring_t *ringp, ring_msg_t *msgp ); +static void Ring_put( ring_t *ringp, ring_msg_t *msgp ); +static intgen_t validate_media_file_hdr( drive_t *drivep ); +static void calc_max_lost( drive_t *drivep ); +static void display_ring_metrics( drive_t *drivep, intgen_t mlog_flags ); +#ifdef CLRMTAUD +static u_int32_t rewind_and_verify( drive_t *drivep ); +static u_int32_t erase_and_verify( drive_t *drivep ); +static u_int32_t bsf_and_verify( drive_t *drivep ); +static u_int32_t fsf_and_verify( drive_t *drivep ); +#else /* CLRMTAUD */ +static short rewind_and_verify( drive_t *drivep ); +static short erase_and_verify( drive_t *drivep ); +static short bsf_and_verify( drive_t *drivep ); +static short fsf_and_verify( drive_t *drivep ); +#endif /* CLRMTAUD */ +static bool_t set_best_blk_and_rec_sz( drive_t *drivep ); +static bool_t isefsdump( drive_t *drivep ); +static bool_t isxfsdumperasetape( drive_t *drivep ); + +/* RMT trace stubs + */ +#ifdef RMT +#ifdef RMTDBG +static int dbgrmtopen( char *, int, ... ); +static int dbgrmtclose( int ); +static int dbgrmtioctl( int, int, ... ); +static int dbgrmtread( int, void*, uint); +static int dbgrmtwrite( int, const void *, uint); +#endif /* RMTDBG */ +#endif /* RMT */ + +#define ERASE_MAGIC "$^*@++! This tape was quick erased by SGI xfsdump $^*@++!" + +/* definition of locally defined global variables ****************************/ + +/* rmt drive strategy. referenced by drive.c + */ +drive_strategy_t drive_strategy_rmt = { + DRIVE_STRATEGY_RMT, /* ds_id */ + "drive_minrmt", /* ds_description */ + ds_match, /* ds_match */ + ds_instantiate, /* ds_instantiate */ + 0x1000000ll, /* ds_recmarksep 16 MB */ + 0x10000000ll, /* ds_recmfilesz 256 MB */ +}; + + +/* definition of locally defined static variables *****************************/ + +/* drive operators + */ +static drive_ops_t drive_ops = { + do_init, /* do_init */ + do_sync, /* do_sync */ + do_begin_read, /* do_begin_read */ + do_read, /* do_read */ + do_return_read_buf, /* do_return_read_buf */ + do_get_mark, /* do_get_mark */ + do_seek_mark, /* do_seek_mark */ + do_next_mark, /* do_next_mark */ + do_end_read, /* do_end_read */ + do_begin_write, /* do_begin_write */ + do_set_mark, /* do_set_mark */ + do_get_write_buf, /* do_get_write_buf */ + do_write, /* do_write */ + do_get_align_cnt, /* do_get_align_cnt */ + do_end_write, /* do_end_write */ + do_fsf, /* do_fsf */ + do_bsf, /* do_bsf */ + do_rewind, /* do_rewind */ + do_erase, /* do_erase */ + do_eject_media, /* do_eject_media */ + do_get_device_class, /* do_get_device_class */ + do_display_metrics, /* do_display_metrics */ + do_quit, /* do_quit */ +}; + +static u_int32_t cmdlineblksize = 0; + +/* definition of locally defined global functions ****************************/ + + +/* definition of locally defined static functions ****************************/ + +/* strategy match - determines if this is the right strategy + */ +/* ARGSUSED */ +static intgen_t +ds_match( int argc, char *argv[], drive_t *drivep, bool_t singlethreaded ) +{ + intgen_t fd; + intgen_t c; + bool_t minrmt = BOOL_FALSE; + + /* heuristics to determine if this is a drive. + */ + + if ( ! strcmp( drivep->d_pathname, "stdio" )) { + return -10; + } + + /* Check if the min rmt flag and block size have + * been specified. + * If so , this is a non-SGI drive and this is the right + * strategy. + */ + { + optind = 1; + opterr = 0; + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + switch (c) { + case GETOPT_BLOCKSIZE: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "-%c argument missing\n", + optopt ); + return -10; + } + cmdlineblksize = ( u_int32_t )atoi( optarg ); + errno = 0; + fd = open_masked_signals( drivep->d_pathname, O_RDONLY ); + if ( fd < 0 ) + return -10; + close( fd ); + break; + case GETOPT_MINRMT: + minrmt = BOOL_TRUE; + break; + } + } + + if (minrmt == BOOL_TRUE) { + if (cmdlineblksize != 0) + return 20; + else + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "Minimal rmt cannot be used without specifying blocksize. Use -%c\n", + GETOPT_BLOCKSIZE ); + } + } + /* catch all */ + return -10; +} + +/* strategy instantiate - initializes the pre-allocated drive descriptor + */ +/*ARGSUSED*/ +static bool_t +ds_instantiate( int argc, char *argv[], drive_t *drivep, bool_t singlethreaded ) +{ + drive_context_t *contextp; + intgen_t c; + + /* opportunity for sanity checking + */ + ASSERT( sizeof( global_hdr_t ) <= STAPE_HDR_SZ ); + ASSERT( sizeof( rec_hdr_t ) + == + sizeofmember( drive_hdr_t, dh_specific )); + ASSERT( ! ( STAPE_MAX_RECSZ % PGSZ )); + + /* hook up the drive ops + */ + drivep->d_opsp = &drive_ops; + + /* allocate context for the drive manager + */ + contextp = ( drive_context_t * )calloc( 1, sizeof( drive_context_t )); + ASSERT( contextp ); + memset( ( void * )contextp, 0, sizeof( *contextp )); + + /* transfer indication of singlethreadedness to context + */ + contextp->dc_singlethreadedpr = singlethreaded; + + /* scan the command line for the I/O buffer ring length + * and record checksum request + */ + contextp->dc_ringlen = RINGLEN_DEFAULT; + contextp->dc_ringpinnedpr = BOOL_FALSE; + contextp->dc_recchksumpr = BOOL_FALSE; + contextp->dc_unloadokpr = BOOL_FALSE; + contextp->dc_isQICpr = BOOL_FALSE; + optind = 1; + opterr = 0; + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + switch ( c ) { + case GETOPT_RINGLEN: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "-%c argument missing\n", + optopt ); + return BOOL_FALSE; + } + contextp->dc_ringlen = ( size_t )atoi( optarg ); + if ( contextp->dc_ringlen < RINGLEN_MIN + || + contextp->dc_ringlen > RINGLEN_MAX ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "-%c argument must be " + "between %u and %u: ignoring %u\n", + optopt, + RINGLEN_MIN, + RINGLEN_MAX, + contextp->dc_ringlen ); + return BOOL_FALSE; + } + break; + case GETOPT_RINGPIN: + contextp->dc_ringpinnedpr = BOOL_TRUE; + break; + case GETOPT_RECCHKSUM: + contextp->dc_recchksumpr = BOOL_TRUE; + break; + case GETOPT_UNLOAD: + contextp->dc_unloadokpr = BOOL_TRUE; + break; + case GETOPT_QIC: + contextp->dc_isQICpr = BOOL_TRUE; + break; +#ifdef DUMP + case GETOPT_OVERWRITE: + contextp->dc_overwritepr = BOOL_TRUE; + mlog( MLOG_DEBUG | MLOG_DRIVE, + "Overwrite command line option \n" ); + break; + case GETOPT_SINGLEMFILE: + contextp->dc_singlemfilepr = BOOL_TRUE; + mlog( MLOG_DEBUG | MLOG_DRIVE, + "Single media file command line option \n" ); + break; +#endif + } + } + + /* set drive file descriptor to null value + */ + contextp->dc_fd = -1; + + /* record location of context descriptor in drive descriptor + */ + drivep->d_contextp = (void *)contextp; + + /* indicate neither capacity nor rate estimates available + */ + drivep->d_cap_est = -1; + drivep->d_rate_est = -1; + + /* if sproc not allowed, allocate a record buffer. otherwise + * create a ring, from which buffers will be taken. + */ + if ( singlethreaded ) { + contextp->dc_bufp = ( char * )memalign( PGSZ, STAPE_MAX_RECSZ ); + ASSERT( contextp->dc_bufp ); + } else { + intgen_t rval; + mlog( (MLOG_NITTY + 1) | MLOG_DRIVE, + "ring op: create: ringlen == %u\n", + contextp->dc_ringlen ); + contextp->dc_ringp = ring_create( contextp->dc_ringlen, + STAPE_MAX_RECSZ, + contextp->dc_ringpinnedpr, + ring_thread, + ring_read, + ring_write, + ( void * )drivep, + &rval ); + if ( ! contextp->dc_ringp ) { + if ( rval == ENOMEM ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "unable to allocate memory " + "for I/O buffer ring\n" ); + } else if ( rval == E2BIG ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "not enough physical memory " + "to pin down I/O buffer ring\n" ); + } else if ( rval == EPERM ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "not allowed " + "to pin down I/O buffer ring\n" ); + } else { + ASSERT( 0 ); + } + return BOOL_FALSE; + } + } + + /* several of contextp predicates cannot yet be determined. + * mark them as unknown for now. however, if this is an RMT + * access, we know immediately some capabilities are missing. + */ + + /* specify that we are currently neither reading nor writing + */ + contextp->dc_mode = OM_NONE; + + /* set the capabilities flags advertised in the drive_t d_capabilities + * field that we know a priori to be true. later additional flags + * may be set + */ + drivep->d_capabilities = 0 + | + DRIVE_CAP_BSF + | + DRIVE_CAP_FSF + | + DRIVE_CAP_REWIND + | + DRIVE_CAP_FILES + | + DRIVE_CAP_NEXTMARK + | + DRIVE_CAP_READ + | + DRIVE_CAP_REMOVABLE + | + DRIVE_CAP_ERASE + | + DRIVE_CAP_EJECT + ; + + return BOOL_TRUE; +} + +/* drive op init - do more time-consuming init/checking here. read and + * write headers are available now. + * + * NOTE: + * When using a RMT device, the MTIOCGETBLKINFO, MTCAPABILITY and + * MTSPECOP ioctl calls are not supported. This means that we have + * to assume that the drive does not support the MTCAN_APPEND capability. + */ +/* ARGSUSED */ +static bool_t +do_init( drive_t *drivep ) +{ +#ifdef DUMP + drive_hdr_t *dwhdrp = drivep->d_writehdrp; + media_hdr_t *mwhdrp = ( media_hdr_t * )dwhdrp->dh_upper; +#endif /* DUMP */ + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: init\n" ); + +#ifdef DUMP + /* fill in media strategy id: artifact of first version of xfsdump + */ + mwhdrp->mh_strategyid = MEDIA_STRATEGY_RMVTAPE; +#endif /* DUMP */ + + return BOOL_TRUE; +} + +/* wait here for slave to complete initialization. + * set drive capabilities flags. NOTE: currently don't make use of this + * feature: drive initialization done whenever block/record sizes unknown. + */ +/* ARGSUSED */ +static bool_t +do_sync( drive_t *drivep ) +{ + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: sync\n" ); + + return BOOL_TRUE; +} + +/* begin_read + * Set up the tape device and read the media file header. + * if allowed, begin read-ahead. + * + * RETURNS: + * 0 on success + * DRIVE_ERROR_* on failure + * + */ +static intgen_t +do_begin_read( drive_t *drivep ) +{ + drive_context_t *contextp; + intgen_t rval; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: begin read\n" ); + + /* get drive context + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + /* verify protocol being followed + */ + ASSERT( drivep->d_capabilities & DRIVE_CAP_READ ); + ASSERT( contextp->dc_mode == OM_NONE ); + ASSERT( ! contextp->dc_recp ); + + /* get a record buffer to use during initialization. + */ + if ( contextp->dc_singlethreadedpr ) { + contextp->dc_recp = contextp->dc_bufp; + } else { + ASSERT( contextp->dc_ringp ); + contextp->dc_msgp = Ring_get( contextp->dc_ringp ); + ASSERT( contextp->dc_msgp->rm_stat == RING_STAT_INIT ); + contextp->dc_recp = contextp->dc_msgp->rm_bufp; + } + + /* if the tape is not open, open, determine the record size, and + * read the first record. otherwise read a record using the record + * size previously determined. + */ + contextp->dc_iocnt = 0; + if ( contextp->dc_fd < 0 ) { + ASSERT( contextp->dc_fd == -1 ); + rval = prepare_drive( drivep ); + if ( rval ) { + if ( ! contextp->dc_singlethreadedpr ) { + Ring_reset( contextp->dc_ringp, contextp->dc_msgp ); + } + contextp->dc_msgp = 0; + contextp->dc_recp = 0; + return rval; + } + } else { + rval = read_label( drivep ) ; + if ( rval ) { + if ( ! contextp->dc_singlethreadedpr ) { + Ring_reset( contextp->dc_ringp, contextp->dc_msgp ); + } + contextp->dc_msgp = 0; + contextp->dc_recp = 0; + return rval; + } + } + ASSERT( contextp->dc_iocnt == 1 ); + /* set by prepare_drive or read_label */ + + /* all is well. adjust context. don't kick off read-aheads just yet; + * the client may not want this media file. + */ + if ( ! contextp->dc_singlethreadedpr ) { + contextp->dc_msgp->rm_op = RING_OP_NOP; + contextp->dc_msgp->rm_user = 0; /* do diff. use in do_seek */ + Ring_put( contextp->dc_ringp, contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_recp = 0; + contextp->dc_recendp = 0; + contextp->dc_dataendp = 0; + contextp->dc_ownedp = 0; + contextp->dc_nextp = 0; + contextp->dc_reccnt = 1; + + /* used to detect attempt to read after an error was reported + */ + contextp->dc_errorpr = BOOL_FALSE; + + /* successfully entered read mode. must do end_read to get out. + */ + contextp->dc_mode = OM_READ; + + return 0; +} + +/* do_read + * Supply the caller with all or a portion of the current buffer, + * filled with data from a record. + * + * RETURNS: + * a pointer to a buffer containing "*actual_bufszp" bytes of data + * or 0 on failure with "*rvalp" containing the error (DRIVE_ERROR_...) + * + */ +static char * +do_read( drive_t *drivep, + size_t wantedcnt, + size_t *actualcntp, + intgen_t *rvalp ) +{ + drive_context_t *contextp; + size_t availcnt; + size_t actualcnt; + intgen_t rval; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: read: wanted %u (0x%x)\n", + wantedcnt, + wantedcnt ); + + /* get context ptrs + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + /* assert protocol being followed + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( ! contextp->dc_ownedp ); + ASSERT( wantedcnt > 0 ); + + /* clear the return status field + */ + *rvalp = 0; + + /* read a new record if necessary + */ + rval = getrec( drivep ); + if ( rval ) { + mlog( MLOG_NITTY | MLOG_DRIVE, + "rmt drive op read returning error rval=%d\n", + rval ); + *rvalp = rval; + return 0; + } + + /* figure how much data is available, and how much should be supplied + */ + availcnt = ( size_t )( contextp->dc_dataendp - contextp->dc_nextp ); + actualcnt = min( wantedcnt, availcnt ); + + /* adjust the context + */ + contextp->dc_ownedp = contextp->dc_nextp; + contextp->dc_nextp += actualcnt; + ASSERT( contextp->dc_nextp <= contextp->dc_dataendp ); + + mlog( MLOG_NITTY | MLOG_DRIVE, + "rmt drive op read actual == %d (0x%x)\n", + actualcnt, + actualcnt ); + + *actualcntp = actualcnt; + return contextp->dc_ownedp; +} + +/* do_return_read_buf - + * Lets the caller give back the buffer portion obtained from the preceding + * call to do_read(). + * + * RETURNS: + * void + */ +/* ARGSUSED */ +static void +do_return_read_buf( drive_t *drivep, char *bufp, size_t retcnt ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + /* REFERENCED */ + size_t ownedcnt; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: return read buf: sz %d (0x%x)\n", + retcnt, + retcnt ); + + /* assert protocol being followed + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( contextp->dc_ownedp ); + ASSERT( bufp == contextp->dc_ownedp ); + + /* calculate how much the caller owns + */ + ASSERT( contextp->dc_nextp >= contextp->dc_ownedp ); + ownedcnt = ( size_t )( contextp->dc_nextp - contextp->dc_ownedp ); + ASSERT( ownedcnt == retcnt ); + + /* take possession of buffer portion + */ + contextp->dc_ownedp = 0; + + /* if caller is done with this record, take the buffer back + * and (if ring in use) give buffer to ring for read-ahead. + */ + if ( contextp->dc_nextp >= contextp->dc_dataendp ) { + ASSERT( contextp->dc_nextp == contextp->dc_dataendp ); + if ( ! contextp->dc_singlethreadedpr ) { + contextp->dc_msgp->rm_op = RING_OP_READ; + Ring_put( contextp->dc_ringp, contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_recp = 0; + contextp->dc_recendp = 0; + contextp->dc_dataendp = 0; + contextp->dc_nextp = 0; + contextp->dc_reccnt++; + } +} + +/* do_get_mark + * Get the current read tape location. + * + * RETURNS: + * void + */ +static void +do_get_mark( drive_t *drivep, drive_mark_t *markp ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + off64_t offset; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: get mark\n" ); + + /* assert protocol being followed + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( ! contextp->dc_ownedp ); + + /* the mark is simply the offset into the media file of the + * next byte to be read. + */ + offset = contextp->dc_reccnt * ( off64_t )tape_recsz; + if ( contextp->dc_recp ) { + offset += ( off64_t )( contextp->dc_nextp - contextp->dc_recp ); + } + + *markp = ( drive_mark_t )offset; + + return; +} + +typedef enum { SEEKMODE_BUF, SEEKMODE_RAW } seekmode_t; + +/* do_seek_mark + * Advance the tape to the given mark. does dummy reads to + * advance tape, as well as FSR if supported. + * + * RETURNS: + * 0 on success + * DRIVE_ERROR_* on failure + * + */ +static intgen_t +do_seek_mark( drive_t *drivep, drive_mark_t *markp ) +{ + drive_context_t *contextp; + off64_t wantedoffset; + off64_t currentoffset; + + /* get the drive context + */ + contextp = (drive_context_t *)drivep->d_contextp; + + /* assert protocol being followed + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( ! contextp->dc_ownedp ); + + + /* the desired mark is passed by reference, and is really just an + * offset into the raw (incl rec hdrs) read stream + */ + wantedoffset = *( off64_t * )markp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: seek mark: %lld (0x%llx)\n", + wantedoffset, + wantedoffset ); + + /* determine the current offset. assert that the wanted offset is + * not less than the current offset. + */ + currentoffset = contextp->dc_reccnt * ( off64_t )tape_recsz; + if ( contextp->dc_recp ) { + u_int32_t recoff; +#ifdef DEBUG + rec_hdr_t *rechdrp = ( rec_hdr_t * )contextp->dc_recp; +#endif + + ASSERT( contextp->dc_nextp >= contextp->dc_recp ); + recoff = ( u_int32_t )( contextp->dc_nextp + - + contextp->dc_recp ); + ASSERT( recoff <= tape_recsz ); + ASSERT( rechdrp->rec_used <= tape_recsz ); + ASSERT( recoff >= STAPE_HDR_SZ ); + ASSERT( rechdrp->rec_used >= STAPE_HDR_SZ ); + ASSERT( recoff <= rechdrp->rec_used ); + currentoffset += ( off64_t )recoff; + } + ASSERT( wantedoffset >= currentoffset ); + + /* if we are currently holding a record and the desired offset + * is not within the current record, eat the current record. + */ + if ( contextp->dc_recp ) { + off64_t nextrecoffset; + rec_hdr_t *rechdrp = ( rec_hdr_t * )contextp->dc_recp; + + nextrecoffset = contextp->dc_reccnt * ( off64_t )tape_recsz + + + ( off64_t )rechdrp->rec_used; + if ( wantedoffset >= nextrecoffset ) { + u_int32_t recoff; + size_t wantedcnt; + char *dummybufp; + size_t actualcnt; + intgen_t rval; + + /* if this is the last record, the wanted offset + * must be just after it. + */ + if ( rechdrp->rec_used < tape_recsz ) { + ASSERT( wantedoffset == nextrecoffset ); + } + + /* figure how much to ask for + */ + ASSERT( contextp->dc_nextp >= contextp->dc_recp ); + recoff = ( u_int32_t )( contextp->dc_nextp + - + contextp->dc_recp ); + wantedcnt = ( size_t )( rechdrp->rec_used + - + recoff ); + + /* eat that much tape + */ + rval = 0; + dummybufp = do_read( drivep, + wantedcnt, + &actualcnt, + &rval ); + if ( rval ) { + return rval; + } + ASSERT( actualcnt == wantedcnt ); + do_return_read_buf( drivep, dummybufp, actualcnt ); + currentoffset += ( off64_t )actualcnt; + ASSERT( currentoffset == nextrecoffset ); + ASSERT( wantedoffset >= currentoffset ); + ASSERT( ! contextp->dc_recp ); + ASSERT( currentoffset + == + contextp->dc_reccnt * ( off64_t )tape_recsz ); + } + } + + /* if FSR is supported, while the desired offset is more than a record + * away, eat records. this is tricky. if read-ahead has already read + * to the desired point, no need to FSR: fall through to next code block + * where we get there by eating excess records. if read-ahead has not + * made it there, suspend read-ahead, eat those readahead records, + * FSR the remaining, and resume readahead. + */ + if ( contextp->dc_canfsrpr + && + wantedoffset - currentoffset >= ( off64_t )tape_recsz ) { + off64_t wantedreccnt; + seekmode_t seekmode; + + ASSERT( ! contextp->dc_recp ); + wantedreccnt = wantedoffset / ( off64_t )tape_recsz; + if ( contextp->dc_singlethreadedpr ) { + seekmode = SEEKMODE_RAW; + } else { + seekmode = SEEKMODE_BUF; + } + ASSERT( wantedreccnt != 0 ); /* so NOP below can be + * distinguished from use + * in do_begin_read + */ + while ( contextp->dc_reccnt < wantedreccnt ) { + off64_t recskipcnt64; + off64_t recskipcnt64remaining; + + if ( seekmode == SEEKMODE_BUF ) { + ring_stat_t rs; + ASSERT( ! contextp->dc_msgp ); + contextp->dc_msgp = + Ring_get( contextp->dc_ringp ); + rs = contextp->dc_msgp->rm_stat; + if ( rs == RING_STAT_ERROR ) { + contextp->dc_errorpr = BOOL_TRUE; + return contextp->dc_msgp->rm_rval; + } + if ( rs != RING_STAT_OK + && + rs != RING_STAT_INIT + && + rs != RING_STAT_NOPACK ) { + ASSERT( 0 ); + contextp->dc_errorpr = BOOL_TRUE; + return DRIVE_ERROR_CORE; + } + if ( rs == RING_STAT_OK ) { + contextp->dc_reccnt++; + } + if ( rs == RING_STAT_NOPACK + && + contextp->dc_msgp->rm_user + == + wantedreccnt ) { + seekmode = SEEKMODE_RAW; + } + contextp->dc_msgp->rm_op = RING_OP_NOP; + contextp->dc_msgp->rm_user = wantedreccnt; + Ring_put( contextp->dc_ringp, + contextp->dc_msgp ); + contextp->dc_msgp = 0; + continue; + } + + ASSERT( contextp->dc_reccnt == contextp->dc_iocnt ); + ASSERT( wantedreccnt > contextp->dc_reccnt ); + recskipcnt64 = wantedreccnt - contextp->dc_reccnt; + recskipcnt64remaining = recskipcnt64; + while ( recskipcnt64remaining ) { + intgen_t recskipcnt; + intgen_t saved_errno; + intgen_t rval; + + ASSERT( recskipcnt64remaining > 0 ); + if ( recskipcnt64remaining > INTGENMAX ) { + recskipcnt = INTGENMAX; + } else { + recskipcnt = ( intgen_t ) + recskipcnt64remaining; + } + ASSERT( recskipcnt > 0 ); + rval = mt_op( contextp->dc_fd, + MTFSR, + recskipcnt ); + saved_errno = errno; + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "could not forward space %d " + "tape blocks: " + "rval == %d, errno == %d (%s)\n", + rval, + saved_errno, + strerror( saved_errno )); + return DRIVE_ERROR_MEDIA; + } + recskipcnt64remaining -= ( off64_t )recskipcnt; + } + contextp->dc_reccnt += recskipcnt64; + contextp->dc_iocnt += recskipcnt64; + currentoffset = contextp->dc_reccnt + * + ( off64_t )tape_recsz; + ASSERT( wantedoffset >= currentoffset ); + ASSERT( wantedoffset - currentoffset + < + ( off64_t )tape_recsz ); + } + } + + /* remove excess records by eating them. won't be any if + * FSR supported + */ + while ( wantedoffset - currentoffset >= ( off64_t )tape_recsz ) { + size_t wantedcnt; + char *dummybufp; + size_t actualcnt; + intgen_t rval; + + ASSERT( ! contextp->dc_recp ); + + /* figure how much to ask for. to eat an entire record, + * ask for a record sans the header. do_read will eat + * the header, we eat the rest. + */ + wantedcnt = ( size_t )( tape_recsz - STAPE_HDR_SZ ); + + /* eat that much tape + */ + rval = 0; + dummybufp = do_read( drivep, wantedcnt, &actualcnt, &rval ); + if ( rval ) { + return rval; + } + ASSERT( actualcnt == wantedcnt ); + do_return_read_buf( drivep, dummybufp, actualcnt ); + ASSERT( ! contextp->dc_recp ); + currentoffset += ( off64_t )tape_recsz; + ASSERT( currentoffset + == + contextp->dc_reccnt * ( off64_t )tape_recsz ); + } + + /* eat that portion of the next record leading up to the + * desired offset. + */ + if ( wantedoffset != currentoffset ) { + size_t wantedcnt; + char *dummybufp; + size_t actualcnt; + + ASSERT( wantedoffset > currentoffset ); + ASSERT( wantedoffset - currentoffset < ( off64_t )tape_recsz ); + wantedcnt = ( size_t )( wantedoffset - currentoffset ); + if ( contextp->dc_recp ) { + u_int32_t recoff; +#ifdef DEBUG + rec_hdr_t *rechdrp = ( rec_hdr_t * )contextp->dc_recp; +#endif + recoff = ( u_int32_t )( contextp->dc_nextp + - + contextp->dc_recp ); + ASSERT( recoff <= tape_recsz ); + ASSERT( rechdrp->rec_used <= tape_recsz ); + ASSERT( recoff >= STAPE_HDR_SZ ); + ASSERT( rechdrp->rec_used >= STAPE_HDR_SZ ); + ASSERT( recoff <= rechdrp->rec_used ); + ASSERT( recoff + wantedcnt <= rechdrp->rec_used ); + } else { + ASSERT( wantedcnt >= STAPE_HDR_SZ ); + wantedcnt -= STAPE_HDR_SZ; + } + + /* eat that much tape + */ + if ( wantedcnt > 0 ) { + intgen_t rval; + rval = 0; + dummybufp = do_read( drivep, wantedcnt, &actualcnt, &rval ); + if ( rval ) { + return rval; + } + ASSERT( actualcnt == wantedcnt ); + do_return_read_buf( drivep, dummybufp, actualcnt ); + } + } + + /* as a sanity check, refigure the current offset and make sure + * it is equal to the wanted offset + */ + currentoffset = contextp->dc_reccnt * ( off64_t )tape_recsz; + if ( contextp->dc_recp ) { + u_int32_t recoff; +#ifdef DEBUG + rec_hdr_t *rechdrp = ( rec_hdr_t * )contextp->dc_recp; +#endif + + ASSERT( contextp->dc_nextp >= contextp->dc_recp ); + recoff = ( u_int32_t )( contextp->dc_nextp + - + contextp->dc_recp ); + ASSERT( recoff <= tape_recsz ); + ASSERT( rechdrp->rec_used <= tape_recsz ); + ASSERT( recoff >= STAPE_HDR_SZ ); + ASSERT( rechdrp->rec_used >= STAPE_HDR_SZ ); + ASSERT( recoff <= rechdrp->rec_used ); + currentoffset += ( off64_t )recoff; + } + ASSERT( wantedoffset == currentoffset ); + + return 0; +} + +/* do_next_mark + * Advance the tape position to the next valid mark. if in + * error mode, first attempt to move past error by re-reading. if + * that fails, try to FSR. also deals with QIC possibility of + * reading a block not at a record boundary. + * + * RETURNS: + * 0 on success + * DRIVE_ERROR_* on failure + */ +static intgen_t +do_next_mark( drive_t *drivep ) +{ + drive_context_t *contextp = (drive_context_t *)drivep->d_contextp; + rec_hdr_t *rechdrp; + char *p; + ix_t trycnt; + const ix_t maxtrycnt = 5; + intgen_t nread; + off64_t markoff; + intgen_t saved_errno; + size_t tailsz; + intgen_t rval; + + /* assert protocol being followed. + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( ! contextp->dc_ownedp ); + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: next mark\n" ); + + trycnt = 0; + + if ( contextp->dc_errorpr ) { + goto resetring; + } else { + goto noerrorsearch; + } + +noerrorsearch: + for ( ; ; ) { + rval = getrec( drivep ); + if ( rval == DRIVE_ERROR_CORRUPTION ) { + goto resetring; + } else if ( rval ) { + return rval; + } + rechdrp = ( rec_hdr_t * )contextp->dc_recp; + + ASSERT( rechdrp->first_mark_offset != 0 ); + if ( rechdrp->first_mark_offset > 0 ) { + off64_t markoff = rechdrp->first_mark_offset + - + rechdrp->file_offset; + off64_t curoff = ( off64_t )( contextp->dc_nextp + - + contextp->dc_recp ); + ASSERT( markoff > 0 ); + ASSERT( curoff > 0 ); + if ( markoff >= curoff ) { + break; + } + } + + if ( ! contextp->dc_singlethreadedpr ) { + Ring_put( contextp->dc_ringp, + contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_recp = 0; + contextp->dc_reccnt++; + } + + ASSERT( rechdrp->first_mark_offset - rechdrp->file_offset + <= + ( off64_t )tape_recsz ); + contextp->dc_nextp = contextp->dc_recp + + + ( size_t )( rechdrp->first_mark_offset + - + rechdrp->file_offset ); + ASSERT( contextp->dc_nextp <= contextp->dc_dataendp ); + ASSERT( contextp->dc_nextp >= contextp->dc_recp + STAPE_HDR_SZ ); + if ( contextp->dc_nextp == contextp->dc_dataendp ) { + if ( ! contextp->dc_singlethreadedpr ) { + Ring_put( contextp->dc_ringp, + contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_recp = 0; + contextp->dc_reccnt++; + } + + return 0; + +resetring: + if ( ! contextp->dc_singlethreadedpr ) { + Ring_reset( contextp->dc_ringp, contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_recp = 0; + + /* get a record buffer and cast a record header pointer + */ + if ( contextp->dc_singlethreadedpr ) { + contextp->dc_recp = contextp->dc_bufp; + } else { + contextp->dc_msgp = Ring_get( contextp->dc_ringp ); + ASSERT( contextp->dc_msgp->rm_stat == RING_STAT_INIT ); + contextp->dc_recp = contextp->dc_msgp->rm_bufp; + } + rechdrp = ( rec_hdr_t * )contextp->dc_recp; + goto readrecord; + +readrecord: + trycnt++; + if ( trycnt > maxtrycnt ) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "unable to locate next mark in media file\n" ); + return DRIVE_ERROR_MEDIA; + } + + nread = Read( drivep, contextp->dc_recp, tape_recsz, &saved_errno ); + goto validateread; + +validateread: + if ( nread == ( intgen_t )tape_recsz ) { + goto validatehdr; + } + + if ( nread >= 0 ) { + ASSERT( ( size_t )nread <= tape_recsz ); + mlog( MLOG_DEBUG | MLOG_DRIVE, + "short read (nread == %d, record size == %d)\n", + nread, + tape_recsz ); + goto getbeyonderror; + } + + /* some other error + */ + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "unexpected error attempting to read record: " + "read returns %d, errno %s (%s)\n", + nread, + errno, + strerror( errno )); + + goto getbeyonderror; + +validatehdr: + rval = record_hdr_validate( drivep, contextp->dc_recp, BOOL_FALSE ); + + if ( rval + && + ( contextp->dc_isQICpr == BOOL_TRUE + || + contextp->dc_isQICpr == BOOL_UNKNOWN )) { + goto huntQIC; + } + + if ( rval ) { + goto readrecord; + } + + contextp->dc_reccnt = rechdrp->file_offset / ( off64_t )tape_recsz; + contextp->dc_iocnt = contextp->dc_reccnt + 1; + if ( rechdrp->first_mark_offset < 0 ) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "valid record %lld but no mark\n", + contextp->dc_iocnt - 1 ); + goto readrecord; + } + + ASSERT( ! ( rechdrp->file_offset % ( off64_t )tape_recsz )); + markoff = rechdrp->first_mark_offset - rechdrp->file_offset; + ASSERT( markoff >= ( off64_t )STAPE_HDR_SZ ); + ASSERT( markoff < ( off64_t )tape_recsz ); + ASSERT( rechdrp->rec_used > STAPE_HDR_SZ ); + ASSERT( rechdrp->rec_used < tape_recsz ); + + goto alliswell; + +alliswell: + contextp->dc_nextp = contextp->dc_recp + ( size_t )markoff; + ASSERT( ! ( rechdrp->file_offset % ( off64_t )tape_recsz )); + contextp->dc_reccnt = rechdrp->file_offset / ( off64_t )tape_recsz; + contextp->dc_iocnt = contextp->dc_reccnt + 1; + contextp->dc_recendp = contextp->dc_recp + tape_recsz; + contextp->dc_dataendp = contextp->dc_recp + rechdrp->rec_used; + ASSERT( contextp->dc_dataendp <= contextp->dc_recendp ); + ASSERT( contextp->dc_nextp < contextp->dc_dataendp ); + contextp->dc_errorpr = BOOL_FALSE; + + mlog( MLOG_NORMAL | MLOG_DRIVE, + "resynchronized at record %lld " + "offset %u\n", + contextp->dc_iocnt - 1, + contextp->dc_nextp + - + contextp->dc_recp ); + return 0; + +getbeyonderror: + rval = mt_op( contextp->dc_fd, MTFSR, 1 ); + saved_errno = errno; + + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "could not forward space one tape block beyond " + "read error: rval == %d, errno == %d (%s)\n", + rval, + saved_errno, + strerror( saved_errno )); + return DRIVE_ERROR_MEDIA; + } + + goto readrecord; + +huntQIC: + /* we have a full tape_recsz record. look for the magic number at the + * beginning of each 512 byte block. If we find one, shift that and + * the following blocks to the head of the record buffer, and try + * to read the remaining blocks in the record. + */ + for ( p = contextp->dc_recp + QIC_BLKSZ + ; + p < contextp->dc_recendp + ; + p += QIC_BLKSZ ) { + if ( *( u_int64_t * )p == STAPE_MAGIC ) { + goto adjustQIC; + } + } + + goto readrecord; + +adjustQIC: + tailsz = ( size_t )( contextp->dc_recendp - p ); + memcpy( ( void * )contextp->dc_recp, + ( void * )p, + tailsz ); + nread = Read( drivep, + contextp->dc_recp + tailsz, + tape_recsz - tailsz, + &saved_errno ); + + goto validateread; +} + +/* do_end_read + * Discard any buffered reads. + * Tell the reader/writer process to wait. + * + * RETURNS: + * void + */ +static void +do_end_read( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: end read\n" ); + + /* assert protocol being followed + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_ownedp ); + + /* In the scsi version, read_label() does a status command to the + * drive to then decide if doing a 'fsf' is appropriate. For minrmt, + * we don't have the status command so we need to space forward at + * the moment we know we need to go forward... which is here. + */ + ( void )fsf_and_verify( drivep ); + + if ( ! contextp->dc_singlethreadedpr ) { + Ring_reset( contextp->dc_ringp, contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + + contextp->dc_recp = 0; + contextp->dc_mode = OM_NONE; +} + +/* do_begin_write + * prepare drive for writing. set up drive context. write a header record. + * + * RETURNS: + * 0 on success + * DRIVE_ERROR_... on failure + */ +static intgen_t +do_begin_write( drive_t *drivep ) +{ + drive_context_t *contextp; + drive_hdr_t *dwhdrp; + global_hdr_t *gwhdrp; + rec_hdr_t *tpwhdrp; + rec_hdr_t rechdr; + rec_hdr_t *rechdrp = &rechdr; + intgen_t rval; + media_hdr_t *mwhdrp; + content_hdr_t *ch; + content_inode_hdr_t *cih; + + global_hdr_t *tmpgh; + drive_hdr_t *tmpdh; + media_hdr_t *tmpmh; + rec_hdr_t *tmprh; + content_hdr_t *tmpch; + content_inode_hdr_t *tmpcih; + + /* get drive context + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: begin write\n" ); + + /* verify protocol being followed + */ + ASSERT( contextp->dc_mode == OM_NONE ); + ASSERT( ! drivep->d_markrecheadp ); + ASSERT( ! contextp->dc_recp ); + + /* get pointers into global write header + */ + gwhdrp = drivep->d_gwritehdrp; + dwhdrp = drivep->d_writehdrp; + tpwhdrp = ( rec_hdr_t * )dwhdrp->dh_specific; + + /* must already be open. The only way to open is to do a begin_read. + * so all interaction with tape requires reading first. + */ + ASSERT( contextp->dc_fd != -1 ); + + /* fill in write header's drive specific info + */ + tpwhdrp->magic = STAPE_MAGIC; + tpwhdrp->version = STAPE_VERSION; + tpwhdrp->blksize = ( int32_t )tape_blksz; + tpwhdrp->recsize = ( int32_t )tape_recsz; + tpwhdrp->rec_used = 0; + tpwhdrp->file_offset = 0; + tpwhdrp->first_mark_offset= 0; + tpwhdrp->capability = drivep->d_capabilities; + + /* get a record buffer. will be used for the media file header, + * and is needed to "prime the pump" for first call to do_write. + */ + ASSERT( ! contextp->dc_recp ); + if ( contextp->dc_singlethreadedpr ) { + ASSERT( contextp->dc_bufp ); + contextp->dc_recp = contextp->dc_bufp; + } else { + ASSERT( contextp->dc_ringp ); + ASSERT( ! contextp->dc_msgp ); + contextp->dc_msgp = Ring_get( contextp->dc_ringp ); + ASSERT( contextp->dc_msgp->rm_stat == RING_STAT_INIT ); + contextp->dc_recp = contextp->dc_msgp->rm_bufp; + } + + /* write the record. be sure to prevent a record checksum from + * being produced! + */ + contextp->dc_iocnt = 0; + memset( ( void * )contextp->dc_recp, 0, tape_recsz ); + + tmpgh = (global_hdr_t *)contextp->dc_recp; + tmpdh = (drive_hdr_t *)tmpgh->gh_upper; + tmpmh = (media_hdr_t *)tmpdh->dh_upper; + tmprh = (rec_hdr_t *)tmpdh->dh_specific; + tmpch = (content_hdr_t *)tmpmh->mh_upper; + tmpcih = (content_inode_hdr_t *)tmpch->ch_specific; + + mwhdrp = (media_hdr_t *)dwhdrp->dh_upper; + ch = (content_hdr_t *)mwhdrp->mh_upper; + cih = (content_inode_hdr_t *)ch->ch_specific; + + xlate_global_hdr(gwhdrp, tmpgh, 1); + xlate_drive_hdr(dwhdrp, tmpdh, 1); + xlate_media_hdr(mwhdrp, tmpmh, 1); + xlate_content_hdr(ch, tmpch, 1); + xlate_content_inode_hdr(cih, tmpcih, 1); + xlate_rec_hdr(tpwhdrp, tmprh, 1); + + /* checksum the global header + */ + global_hdr_checksum_set( tmpgh ); + + rval = write_record( drivep, contextp->dc_recp, BOOL_TRUE ); + if ( rval ) { + if ( ! contextp->dc_singlethreadedpr ) { + Ring_reset( contextp->dc_ringp, contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_recp = 0; + return rval; + } + + /* prepare the drive context. must have a record buffer ready to + * go, header initialized. + */ + ASSERT( ! contextp->dc_ownedp ); + contextp->dc_reccnt = 1; /* count the header record */ + contextp->dc_recendp = contextp->dc_recp + tape_recsz; + contextp->dc_nextp = contextp->dc_recp + STAPE_HDR_SZ; + + /* intialize header in new record + */ + rechdrp->magic = STAPE_MAGIC; + rechdrp->version = STAPE_VERSION; + rechdrp->file_offset = contextp->dc_reccnt * ( off64_t )tape_recsz; + rechdrp->blksize = ( int32_t )tape_blksz; + rechdrp->recsize = ( int32_t )tape_recsz; + rechdrp->capability = drivep->d_capabilities; + rechdrp->first_mark_offset = -1LL; + uuid_copy( rechdrp->dump_uuid, gwhdrp->gh_dumpid ); + + xlate_rec_hdr(rechdrp, ( rec_hdr_t * )contextp->dc_recp, 1); + /* set mode now so operators will work + */ + contextp->dc_mode = OM_WRITE; + + contextp->dc_errorpr = BOOL_FALSE; + + return 0; +} + +/* do_set_mark - queue a mark request. if first mark set in record, record + * in record. + */ +static void +do_set_mark( drive_t *drivep, + drive_mcbfp_t cbfuncp, + void *cbcontextp, + drive_markrec_t *markrecp ) +{ + drive_context_t *contextp; + off64_t nextoff; + rec_hdr_t *rechdrp; + + /* get drive context + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + /* verify protocol being followed + */ + ASSERT( contextp->dc_mode == OM_WRITE ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( ! contextp->dc_ownedp ); + ASSERT( contextp->dc_recp ); + ASSERT( contextp->dc_nextp ); + + /* calculate and fill in the mark record offset + */ + ASSERT( contextp->dc_recp ); + nextoff = contextp->dc_reccnt * ( off64_t )tape_recsz + + + ( off64_t )( contextp->dc_nextp - contextp->dc_recp ); + markrecp->dm_log = ( drive_mark_t )nextoff; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: set mark: %lld (0x%llx)\n", + nextoff, + nextoff ); + + /* note the location of the first mark in this tape record. + */ + rechdrp = ( rec_hdr_t * )contextp->dc_recp; + if ( rechdrp->first_mark_offset == -1LL ) { + ASSERT( nextoff != -1LL ); + rechdrp->first_mark_offset = nextoff; + } + + /* put the mark on the tail of the queue. + */ + markrecp->dm_cbfuncp = cbfuncp; + markrecp->dm_cbcontextp = cbcontextp; + markrecp->dm_nextp = 0; + if ( drivep->d_markrecheadp == 0 ) { + drivep->d_markrecheadp = markrecp; + drivep->d_markrectailp = markrecp; + } else { + ASSERT( drivep->d_markrectailp ); + drivep->d_markrectailp->dm_nextp = markrecp; + drivep->d_markrectailp = markrecp; + } +} + +/* do_get_write_buf - supply the caller with some or all of the current record + * buffer. the supplied buffer must be fully returned (via a single call to + * do_write) prior to the next call to do_get_write_buf. + * + * RETURNS: + * the address of a buffer + * "actual_bufszp" points to the size of the buffer + */ +static char * +do_get_write_buf( drive_t *drivep, size_t wantedcnt, size_t *actualcntp ) +{ + drive_context_t *contextp; + size_t remainingcnt; + size_t actualcnt; + + /* get drive context + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + /* verify protocol being followed + */ + ASSERT( contextp->dc_mode == OM_WRITE ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( ! contextp->dc_ownedp ); + ASSERT( contextp->dc_recp ); + ASSERT( contextp->dc_nextp ); + ASSERT( contextp->dc_nextp < contextp->dc_recendp ); + + /* figure how much is available; supply the min of what is + * available and what is wanted. + */ + remainingcnt = ( size_t )( contextp->dc_recendp - contextp->dc_nextp ); + actualcnt = min( remainingcnt, wantedcnt ); + *actualcntp = actualcnt; + contextp->dc_ownedp = contextp->dc_nextp; + contextp->dc_nextp += actualcnt; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: get write buf: wanted %u (0x%x) actual %u (0x%x)\n", + wantedcnt, + wantedcnt, + actualcnt, + actualcnt ); + + return contextp->dc_ownedp; +} + +/* do_write - accept ownership of the portion of the current record buffer + * being returned by the caller. if returned portion includes end of record + * buffer, write the buffer and get and prepare a new one in anticipation of + * the next call to do_get_write_buf. also, process any queued marks which + * are guaranteed to be committed to media. NOTE: the caller must return + * everything obtained with the preceeding call to do_get_write_buf. + * + * RETURNS: + * 0 on success + * non 0 on error + */ +/* ARGSUSED */ +static intgen_t +do_write( drive_t *drivep, char *bufp, size_t retcnt ) +{ + drive_context_t *contextp; + rec_hdr_t rechdr; + rec_hdr_t *rechdrp = &rechdr; + global_hdr_t *gwhdrp; + size_t heldcnt; + off64_t last_rec_wrtn_wo_err; /* zero-based index */ + intgen_t rval; + + /* get drive context and pointer to global write hdr + */ + contextp = ( drive_context_t * )drivep->d_contextp; + gwhdrp = drivep->d_gwritehdrp; + + /* calculate how many bytes we believe caller is holding + */ + heldcnt = ( size_t )( contextp->dc_nextp - contextp->dc_ownedp ); + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: write: retcnt %u (0x%x) heldcnt %u (0x%x)\n", + retcnt, + retcnt, + heldcnt, + heldcnt ); + + /* verify protocol being followed + */ + ASSERT( contextp->dc_mode == OM_WRITE ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( contextp->dc_ownedp ); + ASSERT( contextp->dc_recp ); + ASSERT( contextp->dc_nextp ); + ASSERT( contextp->dc_nextp <= contextp->dc_recendp ); + + /* verify the caller is returning exactly what is held + */ + ASSERT( bufp == contextp->dc_ownedp ); + ASSERT( retcnt == heldcnt ); + + /* take it back + */ + contextp->dc_ownedp = 0; + + /* if some portion of the record buffer has not yet been + * held by the client, just return. + */ + if ( contextp->dc_nextp < contextp->dc_recendp ) { + return 0; + } + + /* record in record header that entire record is used + */ + rechdrp = ( rec_hdr_t * )contextp->dc_recp; + INT_SET(rechdrp->rec_used, ARCH_CONVERT, tape_recsz); + + /* write out the record buffer and get a new one. + */ + if ( contextp->dc_singlethreadedpr ) { + rval = write_record( drivep, contextp->dc_recp, BOOL_TRUE ); + last_rec_wrtn_wo_err = contextp->dc_reccnt; /* conv cnt to ix */ + } else { + contextp->dc_msgp->rm_op = RING_OP_WRITE; + contextp->dc_msgp->rm_user = contextp->dc_reccnt; + Ring_put( contextp->dc_ringp, + contextp->dc_msgp ); + contextp->dc_msgp = 0; + contextp->dc_msgp = Ring_get( contextp->dc_ringp ); + contextp->dc_recp = contextp->dc_msgp->rm_bufp; + last_rec_wrtn_wo_err = contextp->dc_msgp->rm_user; + switch( contextp->dc_msgp->rm_stat ) { + case RING_STAT_OK: + case RING_STAT_INIT: + rval = 0; + break; + case RING_STAT_ERROR: + rval = contextp->dc_msgp->rm_rval; + break; + default: + ASSERT( 0 ); + return DRIVE_ERROR_CORE; + } + } + + /* check for errors. if none, commit all marks before a safety margin + * before the no error offset. + */ + if ( rval ) { + contextp->dc_errorpr = BOOL_TRUE; + } else { + off64_t recs_wrtn_wo_err; + off64_t recs_committed; + off64_t bytes_committed; + recs_wrtn_wo_err = last_rec_wrtn_wo_err + 1; + recs_committed = recs_wrtn_wo_err - contextp->dc_lostrecmax; + bytes_committed = recs_committed * ( off64_t )tape_recsz; + drive_mark_commit( drivep, bytes_committed ); + } + + /* adjust context + */ + contextp->dc_reccnt++; + contextp->dc_recendp = contextp->dc_recp + tape_recsz; + contextp->dc_nextp = contextp->dc_recp + + + STAPE_HDR_SZ; + + /* intialize header in new record + */ + rechdrp = &rechdr; + rechdrp->magic = STAPE_MAGIC; + rechdrp->version = STAPE_VERSION; + rechdrp->file_offset = contextp->dc_reccnt * ( off64_t )tape_recsz; + rechdrp->blksize = ( int32_t )tape_blksz; + rechdrp->recsize = ( int32_t )tape_recsz; + rechdrp->capability = drivep->d_capabilities; + rechdrp->first_mark_offset = -1LL; + uuid_copy( rechdrp->dump_uuid, gwhdrp->gh_dumpid ); + xlate_rec_hdr(rechdrp, ( rec_hdr_t * )contextp->dc_recp, 1); + + return rval; +} + +/* do_get_align_cnt - + * Returns the number of bytes which must be written to + * cause the next call to get_write_buf() to be page-aligned. + * + * RETURNS: + * the number of bytes to next alignment + */ +static size_t +do_get_align_cnt( drive_t * drivep ) +{ + char *next_alignment_point; + __psint_t next_alignment_off; + drive_context_t *contextp; + + contextp = ( drive_context_t * )drivep->d_contextp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: get align cnt\n" ); + + /* verify protocol being followed + */ + ASSERT( contextp->dc_mode == OM_WRITE ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( ! contextp->dc_ownedp ); + ASSERT( contextp->dc_recp ); + ASSERT( contextp->dc_nextp ); + ASSERT( contextp->dc_nextp < contextp->dc_recendp ); + + /* calculate the next alignment point at or beyond the current nextp. + * the following algorithm works because all buffers are page-aligned + * and a multiple of PGSZ. + */ + next_alignment_off = ( __psint_t )contextp->dc_nextp; + next_alignment_off += PGMASK; + next_alignment_off &= ~PGMASK; + next_alignment_point = ( char * )next_alignment_off; + ASSERT( next_alignment_point <= contextp->dc_recendp ); + + /* return the number of bytes to the next alignment offset + */ + ASSERT( next_alignment_point >= contextp->dc_nextp ); + return ( size_t )( next_alignment_point - contextp->dc_nextp ); +} + +/* do_end_write - pad and write pending record if any client data in it. + * flush all pending writes. write a file mark. figure how many records are + * guaranteed to be on media, and commit/discard marks accordingly. + * RETURNS: + * 0 on success + * DRIVE_ERROR_* on failure + */ +static intgen_t +do_end_write( drive_t *drivep, off64_t *ncommittedp ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + off64_t first_rec_w_err; /* zero-based index */ + off64_t recs_wtn_wo_err; + off64_t recs_guaranteed; + off64_t bytes_committed; + + intgen_t rval; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: end write\n" ); + + /* verify protocol being followed + */ + ASSERT( contextp->dc_mode == OM_WRITE ); + ASSERT( ! contextp->dc_ownedp ); + ASSERT( contextp->dc_recp ); + ASSERT( contextp->dc_nextp ); + ASSERT( contextp->dc_nextp >= contextp->dc_recp + STAPE_HDR_SZ ); + ASSERT( contextp->dc_nextp < contextp->dc_recendp ); + + /* pre-initialize return of count of bytes committed to media + */ + *ncommittedp = 0; + + /* if in error mode, a write error occured earlier. don't bother + * to do anymore writes, just cleanup and return 0. don't need to + * do commits, already done when error occured. + */ + if ( contextp->dc_errorpr ) { + if ( ! contextp->dc_singlethreadedpr ) { + Ring_reset( contextp->dc_ringp, contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_mode = OM_NONE; + drive_mark_discard( drivep ); + *ncommittedp = ( contextp->dc_iocnt - contextp->dc_lostrecmax ) + * + ( off64_t )tape_recsz; + contextp->dc_recp = 0; + return 0; + } + + /* if any user data in current record buffer, send it out. + */ + if ( contextp->dc_nextp > contextp->dc_recp + STAPE_HDR_SZ ) { + rec_hdr_t *rechdrp; + size_t bufusedcnt; + + rechdrp = ( rec_hdr_t * )contextp->dc_recp; + bufusedcnt = ( size_t )( contextp->dc_nextp + - + contextp->dc_recp ); + INT_SET(rechdrp->rec_used, ARCH_CONVERT, bufusedcnt); + mlog( MLOG_DEBUG | MLOG_DRIVE, + "writing padded last record\n" ); + if ( contextp->dc_singlethreadedpr ) { + rval = write_record( drivep, + contextp->dc_recp, + BOOL_TRUE ); + } else { + ASSERT( contextp->dc_msgp ); + contextp->dc_msgp->rm_op = RING_OP_WRITE; + contextp->dc_msgp->rm_user = contextp->dc_reccnt; + Ring_put( contextp->dc_ringp, + contextp->dc_msgp ); + contextp->dc_msgp = 0; + contextp->dc_msgp = Ring_get( contextp->dc_ringp ); + switch( contextp->dc_msgp->rm_stat ) { + case RING_STAT_OK: + case RING_STAT_INIT: + rval = 0; + break; + case RING_STAT_ERROR: + rval = contextp->dc_msgp->rm_rval; + break; + default: + ASSERT( 0 ); + contextp->dc_recp = 0; + return DRIVE_ERROR_CORE; + } + } + contextp->dc_reccnt++; + } else { + rval = 0; + } + + /* now flush the ring until error or tracer bullet seen. + * note the record index in the first msg received with + * an error indication. this will be used to calculate + * the number of records guaranteed to have made it onto + * media, and that will be used to select which marks + * to commit and which to discard. + */ + if ( rval ) { + first_rec_w_err = contextp->dc_iocnt; + /* because dc_iocnt bumped by write_record + * only if no error + */ + } else { + first_rec_w_err = -1L; + } + if ( ! contextp->dc_singlethreadedpr ) { + while ( ! rval ) { + ASSERT( contextp->dc_msgp ); + contextp->dc_msgp->rm_op = RING_OP_TRACE; + Ring_put( contextp->dc_ringp, + contextp->dc_msgp ); + contextp->dc_msgp = 0; + contextp->dc_msgp = Ring_get( contextp->dc_ringp ); + if ( contextp->dc_msgp->rm_op == RING_OP_TRACE ) { + break; + } + switch( contextp->dc_msgp->rm_stat ) { + case RING_STAT_OK: + case RING_STAT_INIT: + ASSERT( rval == 0 ); + break; + case RING_STAT_ERROR: + rval = contextp->dc_msgp->rm_rval; + first_rec_w_err = contextp->dc_msgp->rm_user; + break; + default: + ASSERT( 0 ); + contextp->dc_recp = 0; + return DRIVE_ERROR_CORE; + } + } + } + + /* the ring is now flushed. reset + */ + if ( ! contextp->dc_singlethreadedpr ) { + Ring_reset( contextp->dc_ringp, contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_recp = 0; + + /* if no error so far, write a file mark. this will have the + * side-effect of flushing the driver/drive of pending writes, + * exposing any write errors. + */ + if ( ! rval ) { + intgen_t weofrval; + + weofrval = mt_op( contextp->dc_fd, MTWEOF, 1 ); + if ( weofrval ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "MTWEOF returned %d: errno == %d (%s)\n", + weofrval, + errno, + strerror( errno )); + rval = DRIVE_ERROR_EOM; + } + } + + /* if an error occured, first_rec_w_err now contains + * the count of records written without error, all of which + * were full records. subtract from this dc_lostrecmax, + * and we have the number of records guaranteed to have made + * it to media. + * + * if no errors have occured, all I/O has been committed. + * we can use dc_iocnt, which is the count of records actually + * written without error. + * + * commit marks contained in committed records, discard the rest, + * and return rval. return by reference the number of bytes committed + * to tape. + */ + if ( rval ) { + ASSERT( first_rec_w_err >= 0 ); + recs_wtn_wo_err = first_rec_w_err; + recs_guaranteed = recs_wtn_wo_err - contextp->dc_lostrecmax; + } else { + ASSERT( first_rec_w_err == -1 ); + recs_wtn_wo_err = contextp->dc_iocnt; + recs_guaranteed = recs_wtn_wo_err; + } + bytes_committed = recs_guaranteed * ( off64_t )tape_recsz; + drive_mark_commit( drivep, bytes_committed ); + drive_mark_discard( drivep ); + contextp->dc_mode = OM_NONE; + *ncommittedp = bytes_committed; + return rval; +} + +/* do_fsf + * Advance the tape by count files. + * + * RETURNS: + * number of media files skipped + * *statp set to zero or DRIVE_ERROR_... + */ +static intgen_t +do_fsf( drive_t *drivep, intgen_t count, intgen_t *statp ) +{ + int i, done, op_failed, opcount; + drive_context_t *contextp; + + /* get drive context + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + /* verify protocol being followed + */ + ASSERT( contextp->dc_mode == OM_NONE ); + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: fsf: count %d\n", + count ); + + ASSERT( count ); + ASSERT( contextp->dc_mode == OM_NONE ); + + for ( i = 0 ; i < count; i++ ) { + done = 0; + opcount = 2; + + /* the tape may encounter errors will trying to + * reach the next file. + */ + while ( !done ) { + + /* advance the tape to the next file mark + * NOTE: + * ignore return code + */ + mlog( MLOG_VERBOSE | MLOG_DRIVE, + "advancing tape to next media file\n"); + + op_failed = 0; + ASSERT( contextp->dc_fd >= 0 ); + if ( mt_op( contextp->dc_fd, MTFSF, 1 ) ) { + op_failed = 1; + } + + + /* Check for a file mark to + * determine if the fsf command worked. + */ + if (!op_failed) { + done = 1; + } + + /* If the FSF command has been issued multiple + * times, and a file mark has not been reached, + * return an error. + */ + if ( --opcount < 0 ) { + mlog( MLOG_VERBOSE | MLOG_DRIVE, + "FSF tape command failed\n"); + + *statp = DRIVE_ERROR_DEVICE; + return i; + } + } + } + + return count; +} + +/* do_bsf + * Backup the tape by count files. zero means just back up to the beginning + * of the last media file read or written. + * + * RETURNS: + * number of media files skipped + * *statp set to zero or DRIVE_ERROR_... + */ +static intgen_t +do_bsf( drive_t *drivep, intgen_t count, intgen_t *statp ) +{ +#ifdef DEBUG + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; +#endif + intgen_t skipped; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: bsf: count %d\n", + count ); + + ASSERT( contextp->dc_mode == OM_NONE ); + + *statp = 0; + + /* first move to the left of the last file mark. + * if BOT encountered, return 0. also check for + * being at BOT or file mark and count == 0: no motion needed + */ + + /* back space - places us to left of previous file mark + */ + ASSERT( drivep->d_capabilities & DRIVE_CAP_BSF ); + ( void )bsf_and_verify( drivep ); + + /* now loop, skipping media files + */ + for ( skipped = 0 ; skipped < count ; skipped++ ) { + + /* move to the left of the next file mark on the left. + * check for BOT. + */ + ( void )bsf_and_verify( drivep ); + } + + /* finally, move to the right side of the file mark + */ + ( void )fsf_and_verify( drivep ); + + /* indicate the number of media files skipped + */ + return skipped; +} + +/* do_rewind + * Position the tape at the beginning of the recorded media. + * + * RETURNS: + * 0 on sucess + * DRIVE_ERROR_* on failure + */ +static intgen_t +do_rewind( drive_t *drivep ) +{ +#ifdef DEBUG + drive_context_t *contextp = (drive_context_t *)drivep->d_contextp; +#endif + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: rewind\n" ); + + ASSERT( contextp->dc_mode == OM_NONE ); + ASSERT( contextp->dc_fd >= 0 ); + + /* use validating tape rewind util func + */ + ( void )rewind_and_verify( drivep ); + return 0; +} + +/* do_erase + * erase media from beginning + * + * RETURNS: + * 0 on sucess + * DRIVE_ERROR_* on failure + */ +static intgen_t +do_erase( drive_t *drivep ) +{ +#ifdef DEBUG + drive_context_t *contextp = (drive_context_t *)drivep->d_contextp; +#endif + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: erase\n" ); + + ASSERT( contextp->dc_mode == OM_NONE ); + ASSERT( contextp->dc_fd >= 0 ); + + /* use validating tape rewind util func + */ + (void )rewind_and_verify( drivep ); + + /* use validating tape erase util func + */ + ( void )erase_and_verify( drivep ); + + /* rewind again + */ + ( void )rewind_and_verify( drivep ); + + /* close the drive so we start from scratch + */ + Close( drivep ); + return 0; +} + +/* do_eject + * pop the tape out - may be a nop on some drives + * + * RETURNS: + * 0 on sucess + * DRIVE_ERROR_DEVICE on failure + */ +static intgen_t +do_eject_media( drive_t *drivep ) +{ + drive_context_t *contextp = (drive_context_t *)drivep->d_contextp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: eject media\n" ); + + /* drive must be open + */ + ASSERT( contextp->dc_fd >= 0 ); + ASSERT( contextp->dc_mode == OM_NONE ); + + /* issue tape unload + */ + if ( contextp->dc_unloadokpr ) { + ( void )mt_op( contextp->dc_fd, MTUNLOAD, 0 ); + } + + /* close the device driver + */ + Close( drivep ); + + return 0; +} + +/* do_get_device_class + * Return the device class + * + * RETURNS: + * always returns DEVICE_TAPE_REMOVABLE + */ +/* ARGSUSED */ +static intgen_t +do_get_device_class( drive_t *drivep) +{ + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: get device class\n" ); + + return DEVICE_TAPE_REMOVABLE; +} + +/* do_display_metrics - print ring stats if using I/O ring + */ +static void +do_display_metrics( drive_t *drivep ) +{ + drive_context_t *contextp = (drive_context_t *)drivep->d_contextp; + ring_t *ringp = contextp->dc_ringp; + + if ( ringp ) { + if ( drivecnt > 1 ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_DRIVE, + "drive %u ", + drivep->d_index ); + } + display_ring_metrics( drivep, + MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK ); + } +} + +/* do_quit + */ +static void +do_quit( drive_t *drivep ) +{ + drive_context_t *contextp = (drive_context_t *)drivep->d_contextp; + ring_t *ringp = contextp->dc_ringp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op: quit\n" ); + + /* print the ring metrics and kill the ring + */ + if ( ringp ) { + display_ring_metrics( drivep, MLOG_VERBOSE ); + + /* tell slave to die + */ + mlog( (MLOG_NITTY + 1) | MLOG_DRIVE, + "ring op: destroy\n" ); + ring_destroy( ringp ); + } + + Close(drivep); + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt drive op quit complete\n" ); +} + +static double +percent64( off64_t num, off64_t denom ) +{ + return ( double )( num * 100 ) / ( double )denom; +} + + +/* read_label + * responsible for reading and validating the first record from a + * media file. can assume that prepare_drive has already been run + * on this tape. if read fails due to an encounter with a file mark, + * end of media, or end of data, position the media to allow an + * append. + * + * RETURNS: + * 0 on success + * DRIVE_ERROR_* on failure + */ +static intgen_t +read_label( drive_t *drivep ) +{ + drive_context_t *contextp; + intgen_t nread; + intgen_t saved_errno; + intgen_t rval; + + /* initialize context ptr + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + /* read the first record of the media file directly + */ + nread = Read( drivep, + contextp->dc_recp, + tape_recsz, + &saved_errno ); + + /* if a read error, get status + */ + if ( nread != ( intgen_t )tape_recsz ) { + ASSERT( nread < ( intgen_t )tape_recsz ); + } + + /* check for an unexpected errno + */ + if ( nread < 0 && saved_errno != ENOSPC ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "could not read from drive: %s (%d)\n", + strerror( errno ), + errno ); + return DRIVE_ERROR_DEVICE; + } + + /* check for a blank tape/EOD. + */ + if (( nread == 0 ) /* takes care of sun */ + || /* now handle SGI */ + (nread < 0 && saved_errno == ENOSPC )) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "encountered EOD : " +#ifdef DUMP + "assuming blank media\n" ); +#endif +#ifdef RESTORE + "end of data\n" ); +#endif + ( void )rewind_and_verify( drivep ); +#ifdef DUMP + return DRIVE_ERROR_BLANK; +#endif +#ifdef RESTORE + return DRIVE_ERROR_EOD; +#endif + } + + + /* dc_iocnt is count of number of records read without error + */ + contextp->dc_iocnt = 1; + + rval = validate_media_file_hdr( drivep ); + + return rval; +} + +static intgen_t +validate_media_file_hdr( drive_t *drivep ) +{ + global_hdr_t *grhdrp = drivep->d_greadhdrp; + drive_hdr_t *drhdrp = drivep->d_readhdrp; + rec_hdr_t *tprhdrp = (rec_hdr_t *)drhdrp->dh_specific; + media_hdr_t *mrhdrp = (media_hdr_t *)drhdrp->dh_upper; + content_hdr_t *ch = (content_hdr_t *)mrhdrp->mh_upper; + content_inode_hdr_t *cih = (content_inode_hdr_t *)ch->ch_specific; + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + char tmpbuf[GLOBAL_HDR_SZ]; + global_hdr_t *tmpgh = (global_hdr_t *)&tmpbuf[0]; + drive_hdr_t *tmpdh = (drive_hdr_t *)tmpgh->gh_upper; + media_hdr_t *tmpmh = (media_hdr_t *)tmpdh->dh_upper; + rec_hdr_t *tmprh = (rec_hdr_t *)tmpdh->dh_specific; + content_hdr_t *tmpch = (content_hdr_t *)tmpmh->mh_upper; + content_inode_hdr_t *tmpcih = (content_inode_hdr_t *)tmpch->ch_specific; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "validating media file header\n" ); + + memcpy( tmpbuf, contextp->dc_recp, GLOBAL_HDR_SZ ); + + /* check the checksum + */ + if ( ! global_hdr_checksum_check( tmpgh )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "bad media file header checksum\n"); + return DRIVE_ERROR_CORRUPTION; + } + + if ( ! tape_rec_checksum_check( contextp, contextp->dc_recp )) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "tape record checksum error\n"); + return DRIVE_ERROR_CORRUPTION; + + } + + xlate_global_hdr(tmpgh, grhdrp, 1); + xlate_drive_hdr(tmpdh, drhdrp, 1); + xlate_media_hdr(tmpmh, mrhdrp, 1); + xlate_content_hdr(tmpch, ch, 1); + xlate_content_inode_hdr(tmpcih, cih, 1); + xlate_rec_hdr(tmprh, tprhdrp, 1); + + memcpy( contextp->dc_recp, grhdrp, GLOBAL_HDR_SZ ); + + /* check the magic number + */ + if ( strncmp( grhdrp->gh_magic, GLOBAL_HDR_MAGIC,GLOBAL_HDR_MAGIC_SZ)) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "missing magic number in tape label\n"); + return DRIVE_ERROR_FORMAT; + } + + /* check the version + */ + if ( global_version_check( grhdrp->gh_version ) != BOOL_TRUE ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "invalid version number (%d) in tape label\n", + grhdrp->gh_version ); + return DRIVE_ERROR_VERSION; + } + + /* check the strategy id + */ + if ( drhdrp->dh_strategyid != drivep->d_strategyp->ds_id ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "unrecognized drive strategy ID (%d)\n", + drivep->d_readhdrp->dh_strategyid ); + return DRIVE_ERROR_FORMAT; + } + + /* check the record magic number + */ + if ( tprhdrp->magic != STAPE_MAGIC ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "invalid record magic number in tape label\n"); + return DRIVE_ERROR_FORMAT; + } + + /* check the record version number + */ + if ( tprhdrp->version != STAPE_VERSION ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "invalid record version number in tape label\n"); + return DRIVE_ERROR_VERSION; + } + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "media file header valid: " + "media file ix %d\n", + mrhdrp->mh_mediafileix ); + + return 0; +} + + +/* get_tpcaps + * Get the specific tape drive capabilities. Set the + * d_capabilities field of the driver structure. + * set the blksz limits and tape type in the context structure. + * + * RETURNS: + * TRUE on success + * FALSE on error + */ +static bool_t +get_tpcaps( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + ASSERT( contextp->dc_fd >= 0 ); + + /* can't ask about blksz, can't set blksz, can't ask about + * drive types/caps. assume a drive which can overwrite. + * assume NOT QIC, since fixed blksz devices not supported + * via RMT. + */ + drivep->d_capabilities |= DRIVE_CAP_OVERWRITE; + drivep->d_capabilities |= DRIVE_CAP_BSF; + + set_recommended_sizes( drivep, contextp->dc_isQICpr); + + return BOOL_TRUE; +} + +/* set_recommended_sizes + * Determine the recommended tape file size and mark separation + * based on tape device type. + * + * RETURNS: + * void + */ +static void +set_recommended_sizes( drive_t *drivep, int isQICpr ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + off64_t fsize = drive_strategy_rmt.ds_recmfilesz; + off64_t marksep = drive_strategy_rmt.ds_recmarksep; + + if (isQICpr == BOOL_TRUE) + { + fsize = 0x3200000ll; /* 50 MB */ + } + + if ( contextp->dc_singlemfilepr ) /* use only one media file */ + { + fsize = OFF64MAX; /* hence set fsize to max */ + mlog( MLOG_DEBUG | MLOG_DRIVE, + "Single media file specified. " + "Set media file size to 0x%llx bytes\n", + OFF64MAX ); + } + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "recommended tape media file size set to 0x%llx bytes\n", + fsize ); + mlog( MLOG_DEBUG | MLOG_DRIVE, + "recommended tape media mark separation set to 0x%llx bytes\n", + marksep ); + + drivep->d_recmfilesz = fsize; + drivep->d_recmarksep = marksep; + + return; +} + + + +/* mt_op + * Issue MTIOCTOP ioctl operation to the tape device. + * + * RETURNS: + * 0 on sucess + * -1 on failure + */ +static intgen_t +mt_op(intgen_t fd, intgen_t sub_op, intgen_t param ) +{ + struct mtop mop; + char *printstr; + intgen_t rval; + + mop.mt_op = (short )sub_op; + mop.mt_count = param; + + ASSERT( fd >= 0 ); + + switch ( sub_op ) { + case MTSEEK: + printstr = "seek"; + break; + case MTBSF: /* 2 */ + printstr = "back space file"; + break; + case MTWEOF: /* 0 */ + printstr = "write file mark"; + break; + case MTFSF: /* 1 */ + printstr = "forward space file"; + break; + case MTREW: /* 5 */ + printstr = "rewind"; + break; + case MTUNLOAD: + printstr = "unload"; + break; + case MTEOM: + printstr = "advance to EOD"; + break; + case MTFSR: /* 3 */ + printstr = "forward space block"; + break; + case MTERASE: + printstr = "erase"; + break; +#ifdef CLRMTAUD +#ifdef MTAUD + case MTAUD: + printstr = "audio"; + break; +#endif /* MTAUD */ +#endif /* CLRMTAUD */ + default: + printstr = "???"; + break; + } + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape op: %s %d\n", + printstr, + param ); + + rval = ioctl( fd, MTIOCTOP, &mop ); + if ( rval < 0 ) { + /* failure + */ + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape op %s %d returns %d: errno == %d (%s)\n", + printstr, + param, + rval, + errno, + strerror( errno )); + return -1; + } + + /* success + */ + return 0; +} + +/* determine_write_error() + * Using the errno and the tape status information, determine the + * type of tape write error that has occured. + * + * RETURNS: + * DRIVE_ERROR_* + */ +static intgen_t +determine_write_error( int nwritten, int saved_errno ) +{ + intgen_t ret = 0; + + if ( saved_errno == EACCES ) { + mlog(MLOG_NORMAL, + "tape is write protected\n"); + + ret = DRIVE_ERROR_DEVICE; + } else if ( + ( saved_errno == ENOSPC ) + || + ( saved_errno == EIO ) + || + (( saved_errno == 0 ) && ( nwritten >= 0 )) /* short + write indicates EOM */ + ) { + mlog(MLOG_NORMAL, + "tape media error on write operation\n"); + + mlog(MLOG_NORMAL, + "no more data can be written to this tape\n"); + + ret = DRIVE_ERROR_EOM; + } else if ( saved_errno != 0 ) { + ret = DRIVE_ERROR_CORE; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape unknown error on write operation: " + "%d, %d\n", + nwritten, saved_errno); + } + + mlog( MLOG_NITTY | MLOG_DRIVE, + "tape write operation nwritten %d, errno %d\n", + nwritten, + saved_errno); + + return ( ret ); + +} + +static void +tape_rec_checksum_set( drive_context_t *contextp, char *bufp ) +{ + rec_hdr_t *rechdrp = ( rec_hdr_t * )bufp; + u_int32_t *beginp = ( u_int32_t * )bufp; + u_int32_t *endp = ( u_int32_t * )( bufp + tape_recsz ); + u_int32_t *p; + u_int32_t accum; + + if ( ! contextp->dc_recchksumpr ) { + return; + } + + INT_SET(rechdrp->ischecksum, ARCH_CONVERT, 1); + rechdrp->checksum = 0; + accum = 0; + for ( p = beginp ; p < endp ; p++ ) { + accum += INT_GET(*p, ARCH_CONVERT); + } + INT_SET(rechdrp->checksum, ARCH_CONVERT, ( int32_t )( ~accum + 1 )); +} + +static bool_t +tape_rec_checksum_check( drive_context_t *contextp, char *bufp ) +{ + rec_hdr_t *rechdrp = ( rec_hdr_t * )bufp; + u_int32_t *beginp = ( u_int32_t * )bufp; + u_int32_t *endp = ( u_int32_t * )( bufp + tape_recsz ); + u_int32_t *p; + u_int32_t accum; + + if ( contextp->dc_recchksumpr && INT_GET(rechdrp->ischecksum, ARCH_CONVERT) ) { + accum = 0; + for ( p = beginp ; p < endp ; p++ ) { + accum += INT_GET(*p, ARCH_CONVERT); + } + return accum == 0 ? BOOL_TRUE : BOOL_FALSE; + } else { + return BOOL_TRUE; + } +} + +/* to trace rmt operations + */ +#ifdef RMT +#ifdef RMTDBG +static int +dbgrmtopen( char *path, int flags ) +{ + int rval; + rval = rmtopen( path, flags ); + mlog( MLOG_NORMAL | MLOG_DRIVE, + "RMTOPEN( %s, %d ) returns %d: errno=%d (%s)\n", + path, + flags, + rval, + errno, + strerror( errno )); + return rval; +} +static int +dbgrmtclose( int fd ) +{ + int rval; + rval = rmtclose( fd ); + mlog( MLOG_NORMAL | MLOG_DRIVE, + "RMTCLOSE( %d ) returns %d: errno=%d (%s)\n", + fd, + rval, + errno, + strerror( errno )); + return rval; +} +static int +dbgrmtioctl( int fd, int op, void *arg ) +{ + int rval; + rval = rmtioctl( fd, op, arg ); + mlog( MLOG_NORMAL | MLOG_DRIVE, + "RMTIOCTL( %d, %d, 0x%x ) returns %d: errno=%d (%s)\n", + fd, + op, + arg, + rval, + errno, + strerror( errno )); + return rval; +} +static int +dbgrmtread( int fd, void *p, uint sz ) +{ + int rval; + rval = rmtread( fd, p, sz ); + mlog( MLOG_NORMAL | MLOG_DRIVE, + "RMTREAD( %d, 0x%x, %u ) returns %d: errno=%d (%s)\n", + fd, + p, + sz, + rval, + errno, + strerror( errno )); + return rval; +} +static int +dbgrmtwrite( int fd, void *p, uint sz ) +{ + int rval; + rval = rmtwrite( fd, p, sz ); + mlog( MLOG_NORMAL | MLOG_DRIVE, + "RMTWRITE( %d, 0x%x, %u ) returns %d: errno=%d (%s)\n", + fd, + p, + sz, + rval, + errno, + strerror( errno )); + return rval; +} +#endif /* RMTDBG */ +#endif /* RMT */ + +/* display_access_failed_message() + * Print tape device open/access failed message. + * + * RETURNS: + * void + */ +static void +display_access_failed_message( drive_t *drivep ) +{ + mlog( MLOG_NORMAL | MLOG_DRIVE, + "attempt to access/open remote " + "tape drive %s failed: %d (%s)\n", + drivep->d_pathname, + errno, + strerror( errno )); + return; +} + +/* prepare_drive - called by begin_read if drive device not open. + * determines record size and sets block size if fixed block device. + * determines other drive attributes. determines if any previous + * xfsdumps on media. + */ +static intgen_t +prepare_drive( drive_t *drivep ) +{ + drive_context_t *contextp; + bool_t ok; + ix_t try; + ix_t maxtries; + bool_t changedblkszpr; + intgen_t rval; + + /* get pointer to drive context + */ + contextp = ( drive_context_t * )drivep->d_contextp; + +/* retry: */ + if ( cldmgr_stop_requested( )) { + return DRIVE_ERROR_STOP; + } + + /* shouldn't be here if drive is open + */ + ASSERT( contextp->dc_fd == -1 ); + + mlog( MLOG_VERBOSE | MLOG_DRIVE, + "preparing drive\n" ); + + /* determine if tape is present or write protected. try several times. + * if not present or write-protected during dump, return. + */ + maxtries = 15; + for ( try = 1 ; ; sleep( 10 ), try++ ) { + if ( cldmgr_stop_requested( )) { + return DRIVE_ERROR_STOP; + } + + /* open the drive + */ + ok = Open( drivep ); + if ( ! ok ) { + if ( errno != EBUSY ) { + display_access_failed_message( drivep ); + return DRIVE_ERROR_DEVICE; + } else { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "open drive returns EBUSY\n" ); + if ( try >= maxtries ) { + mlog( MLOG_TRACE | MLOG_DRIVE, + "giving up waiting for drive " + "to indicate online\n" ); + return DRIVE_ERROR_MEDIA; + } + Close( drivep ); + continue; + } + } else + break; + } + + /* determine tape capabilities. this will set the drivep->d_capabilities + * and contextp->dc_{...}blksz and dc_isQICpr, as well as recommended + * mark separation and media file size. + */ + ok = get_tpcaps( drivep ); + if ( ! ok ) { + return DRIVE_ERROR_DEVICE; + } + + + /* establish the initial block and record sizes we will try. + * if unable to ask drive about fixed block sizes, we will + * guess. + */ + tape_blksz = cmdlineblksize; + if ( tape_blksz > STAPE_MAX_RECSZ ) { + tape_blksz = STAPE_MAX_RECSZ; + } + if ( contextp->dc_isQICpr == BOOL_TRUE ) + tape_recsz = STAPE_MIN_MAX_BLKSZ; + else + tape_recsz = tape_blksz; + + /* if the overwrite option was specified , return. + */ + if ( contextp->dc_overwritepr ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "Overwrite option specified.\n" ); + return DRIVE_ERROR_OVERWRITE; + } + + /* loop trying to read a record. begin with the record size + * calculated above. if it appears we have selected the wrong + * block size and if we are able to alter the fixed block size, + * and the record size we tried initially was not less than + * the minmax block size, change the block size to minmax and + * try to read a one block record again. + */ + maxtries = 5; + changedblkszpr = BOOL_FALSE; + + for ( try = 1 ; ; try++ ) { + intgen_t nread; + intgen_t saved_errno; + + if ( cldmgr_stop_requested( )) { + return DRIVE_ERROR_STOP; + } + + /* bail out if we've tried too many times + */ + if ( try > maxtries ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "giving up attempt to determining " + "tape record size\n" ); + return DRIVE_ERROR_MEDIA; + } + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "determining tape record size: trying %d (0x%x) bytes\n", + tape_recsz, + tape_recsz ); + + /* read a record. use the first ring buffer + */ + saved_errno = 0; + nread = Read( drivep, + contextp->dc_recp, + tape_recsz, + &saved_errno ); + ASSERT( saved_errno == 0 || nread < 0 ); + + /* RMT can require a retry + */ + if ( saved_errno == EAGAIN ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "read returned EAGAIN: retrying\n" ); + continue; + } + + /* block size is bigger than buffer; should never happen + */ + if ( saved_errno == EINVAL ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "read returned EINVAL: " + "trying new record size\n" ); + goto largersize; + } + + /* block size is bigger than buffer; should never happen + */ + if ( saved_errno == ENOMEM ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "read returned ENOMEM: " + "trying new record size\n" ); + goto largersize; + } + + + /* I/O error + */ + if ( saved_errno == EIO ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "read returned EIO: will reopen, " + "and try again\n" ); + Close( drivep ); + ok = Open( drivep ); + if ( ! ok ) { + display_access_failed_message( drivep ); + return DRIVE_ERROR_DEVICE; + } +#ifdef RESTORE + continue; +#endif +#ifdef DUMP + if (3 == try) + return DRIVE_ERROR_BLANK; /* sun rmt returns EIO for blank media */ + else + continue; +#endif + } + + /* ENOSPC + */ + if ( saved_errno == ENOSPC ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "read returned ENOSPC: will reopen, " + "and try again\n" ); + Close( drivep ); + ok = Open( drivep ); + if ( ! ok ) { + display_access_failed_message( drivep ); + return DRIVE_ERROR_DEVICE; + } +#ifdef RESTORE + continue; +#endif +#ifdef DUMP + if (3 == try) + /* IRIX rmt returns ENOSPC for blank media */ + /* It reads to the EOD */ + return DRIVE_ERROR_BLANK; + else + continue; +#endif + } + + if ( nread == ( intgen_t )tape_recsz ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "nread == selected blocksize " + "indicates correct blocksize found\n" ); + goto checkhdr; + } + + /* short read */ + if (( saved_errno == 0 ) && ( nread < (intgen_t)tape_recsz)) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "nread < selected blocksize " + "indicates incorrect blocksize found " + "or foreign media\n" ); + return DRIVE_ERROR_FOREIGN; + } + + + /* if we fell through the seive, code is wrong. + * display useful info and abort + */ + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "unexpected tape error: " + "errno %d " + "nread %d " + "blksz %d " + "recsz %d " + "\n", + saved_errno, + nread, + tape_blksz, + tape_recsz, + 0 ); + + + + /*return DRIVE_ERROR_CORE; */ + return DRIVE_ERROR_MEDIA; + +checkhdr: + rval = validate_media_file_hdr( drivep ); + if ( rval ) { + if ( rval == DRIVE_ERROR_VERSION ) { + global_hdr_t *grhdrp = drivep->d_greadhdrp; + mlog( MLOG_NORMAL | MLOG_DRIVE, + "media file header version (%d) " + "invalid: advancing\n", + grhdrp->gh_version ); + continue; + } else { + if ( isefsdump( drivep )) { + mlog( MLOG_NORMAL + | + MLOG_WARNING + | + MLOG_DRIVE, + "may be an EFS dump at BOT\n" ); + } else + /* Check if the tape was erased by us */ + if ( isxfsdumperasetape( drivep )) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "This tape was erased earlier " + "by xfsdump.\n" ); + ( void )rewind_and_verify( drivep ); + return DRIVE_ERROR_BLANK; + } else { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "bad media file header at BOT " + "indicates foreign or " + "corrupted tape\n" ); + } + ( void )rewind_and_verify( drivep ); + ok = set_best_blk_and_rec_sz( drivep ); + if ( ! ok ) { + return DRIVE_ERROR_DEVICE; + } + return DRIVE_ERROR_FOREIGN; + } + } else { + drive_hdr_t *drhdrp; + rec_hdr_t *tprhdrp; + drhdrp = drivep->d_readhdrp; + tprhdrp = ( rec_hdr_t * )drhdrp->dh_specific; + ASSERT( tprhdrp->recsize >= 0 ); + tape_recsz = ( size_t )tprhdrp->recsize; + break; + } + +largersize: + /* we end up here if we want to try a new larger record size + * because the last one was not big enough for the tape block + */ + if ( changedblkszpr ) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "cannot determine tape block size " + "after two tries\n" ); + mlog( MLOG_NORMAL | MLOG_DRIVE, + "assuming media is corrupt " + "or contains non-xfsdump data\n" ); + ok = set_best_blk_and_rec_sz( drivep ); + if ( ! ok ) { + return DRIVE_ERROR_DEVICE; + } + return DRIVE_ERROR_FOREIGN; + } + /* Make it as large as we can go + */ + if ( tape_recsz != STAPE_MAX_RECSZ ) { + tape_recsz = STAPE_MAX_RECSZ; + if ( ! contextp->dc_isQICpr ) { + tape_blksz = tape_recsz;; + } + changedblkszpr = BOOL_TRUE; + } else { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "cannot determine tape block size\n" ); + return DRIVE_ERROR_MEDIA; + } + continue; + + } + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "read first record of first media file encountered on media: " + "recsz == %u\n", + tape_recsz ); + + /* calculate maximum bytes lost without error at end of tape + */ + calc_max_lost( drivep ); + + contextp->dc_iocnt = 1; + return 0; +} + +/* if BOOL_FALSE returned, errno is valid + */ +static bool_t +Open( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + intgen_t oflags; + +#ifdef DUMP + oflags = O_RDWR; +#endif /* DUMP */ +#ifdef RESTORE + oflags = O_RDONLY; +#endif /* RESTORE */ + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape op: opening drive\n" ); + + ASSERT( contextp->dc_fd == -1 ); + + errno = 0; + contextp->dc_fd = open_masked_signals( drivep->d_pathname, oflags ); + + if ( contextp->dc_fd <= 0 ) { + return BOOL_FALSE; + } + + return BOOL_TRUE; +} + +static void +Close( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape op: closing drive\n" ); + + ASSERT( contextp->dc_fd >= 0 ); + + ( void )close( contextp->dc_fd ); + + contextp->dc_fd = -1; +} + +static intgen_t +Read( drive_t *drivep, char *bufp, size_t cnt, intgen_t *errnop ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + intgen_t nread; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape op: reading %u bytes\n", + cnt ); + + ASSERT( contextp->dc_fd >= 0 ); + ASSERT( bufp ); + *errnop = 0; + errno = 0; + nread = read( contextp->dc_fd, ( void * )bufp, cnt ); + if ( nread < 0 ) { + *errnop = errno; + mlog( MLOG_NITTY | MLOG_DRIVE, + "tape op read of %u bytes failed: errno == %d (%s)\n", + cnt, + errno, + strerror( errno )); + } else if ( nread != ( intgen_t )cnt ) { + mlog( MLOG_NITTY | MLOG_DRIVE, + "tape op read of %u bytes short: nread == %d\n", + cnt, + nread ); + } else { + mlog( MLOG_NITTY | MLOG_DRIVE, + "tape op read of %u bytes successful\n", + cnt ); + } + + return nread; +} + +static intgen_t +Write( drive_t *drivep, char *bufp, size_t cnt, intgen_t *errnop ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + intgen_t nwritten; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape op: writing %u bytes\n", + cnt ); + + ASSERT( contextp->dc_fd >= 0 ); + ASSERT( bufp ); + *errnop = 0; + errno = 0; + nwritten = write( contextp->dc_fd, ( void * )bufp, cnt ); + if ( nwritten < 0 ) { + *errnop = errno; + mlog( MLOG_NITTY | MLOG_DRIVE, + "tape op write of %u bytes failed: errno == %d (%s)\n", + cnt, + errno, + strerror( errno )); + } else if ( nwritten != ( intgen_t )cnt ) { + mlog( MLOG_NITTY | MLOG_DRIVE, + "tape op write of %u bytes short: nwritten == %d\n", + cnt, + nwritten ); + } else { + mlog( MLOG_NITTY | MLOG_DRIVE, + "tape op write of %u bytes successful\n", + cnt ); + } + + return nwritten; +} + +/* validate a record header, log any anomolies, and return appropriate + * indication. + */ +static intgen_t +record_hdr_validate( drive_t *drivep, char *bufp, bool_t chkoffpr ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + global_hdr_t *grhdrp = drivep->d_greadhdrp; + rec_hdr_t rechdr; + rec_hdr_t *rechdrp = &rechdr; + rec_hdr_t *tmprh = ( rec_hdr_t * )bufp; + + if ( ! tape_rec_checksum_check( contextp, bufp )) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: bad record checksum\n", + contextp->dc_iocnt - 1 ); + return DRIVE_ERROR_CORRUPTION; + + } + + xlate_rec_hdr(tmprh, rechdrp, 1); + + if ( rechdrp->magic != STAPE_MAGIC ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: bad magic number\n", + contextp->dc_iocnt - 1 ); + return DRIVE_ERROR_CORRUPTION; + } + + if ( uuid_is_null( rechdrp->dump_uuid )) { + + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: null dump id\n", + contextp->dc_iocnt - 1 ); + return DRIVE_ERROR_CORRUPTION; + } + + if ( uuid_compare( grhdrp->gh_dumpid, + rechdrp->dump_uuid ) != 0) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: dump id mismatch\n", + contextp->dc_iocnt - 1 ); + return DRIVE_ERROR_CORRUPTION; + } + + /* can't check size field of record header, since + * 5.3 version of xfsdump did not set it properly. + */ +#ifdef RECSZCHK + if ( ( size_t )rechdrp->recsize != tape_recsz ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: incorrect record size in header\n", + contextp->dc_iocnt - 1 ); + return DRIVE_ERROR_CORRUPTION; + } +#else /* RECSZCHK */ + mlog( (MLOG_NITTY + 1) | MLOG_NOTE | MLOG_DRIVE, + "record %lld header record size %d (0x%x)\n", + contextp->dc_iocnt - 1, + rechdrp->recsize, + rechdrp->recsize ); +#endif /* RECSZCHK */ + + if ( rechdrp->file_offset % ( off64_t )tape_recsz ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: record offset in header " + "not a multiple of record size\n", + contextp->dc_iocnt - 1 ); + return DRIVE_ERROR_CORRUPTION; + } + + if ( chkoffpr + && + rechdrp->file_offset + != + ( contextp->dc_iocnt - 1 ) * ( off64_t )tape_recsz ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: " + "incorrect record offset in header (0x%llx)\n", + contextp->dc_iocnt - 1, + rechdrp->file_offset ); + return DRIVE_ERROR_CORRUPTION; + } + + if ( rechdrp->rec_used > tape_recsz + || + rechdrp->rec_used < STAPE_HDR_SZ ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: " + "incorrect record padding offset in header\n", + contextp->dc_iocnt - 1 ); + return DRIVE_ERROR_CORRUPTION; + } + + memcpy(tmprh, rechdrp, sizeof(*rechdrp)); + + return 0; +} + +/* do a read, determine DRIVE_ERROR_... if failure, and return failure code. + * return 0 on success. + */ +static intgen_t +read_record( drive_t *drivep, char *bufp ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + intgen_t nread; + intgen_t saved_errno; + intgen_t rval; + + nread = Read( drivep, bufp, tape_recsz, &saved_errno ); + + if ( nread == ( intgen_t )tape_recsz ) { + contextp->dc_iocnt++; + rval = record_hdr_validate( drivep, bufp, BOOL_TRUE ); + return rval; + } + + /* check for a blank tape/EOD. + */ + if (( nread == 0 ) /* takes care of sun */ + || /* now handle SGI */ + (nread < 0 && saved_errno == ENOSPC )) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "read_record encountered EOD : " +#ifdef DUMP + "assuming blank media\n" ); +#endif +#ifdef RESTORE + "end of data\n" ); +#endif +#ifdef DUMP + return DRIVE_ERROR_BLANK; +#endif +#ifdef RESTORE + return DRIVE_ERROR_EOD; +#endif + } + + /* some other error + */ + if ( saved_errno == EIO ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "unexpected EIO error attempting to read record \n"); +#ifdef RESTORE + return DRIVE_ERROR_EOM; +#endif +#ifdef DUMP + return DRIVE_ERROR_CORRUPTION; +#endif + } + + /* short read + */ + if ( nread >= 0 ) { + ASSERT( nread <= ( intgen_t )tape_recsz ); + mlog( MLOG_DEBUG | MLOG_DRIVE, + "short read record %lld (nread == %d)\n", + contextp->dc_iocnt, + nread ); + return DRIVE_ERROR_CORRUPTION; + } + + /* some other error + */ + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "unexpected error attempting to read record %lld: " + "read returns %d, errno %d (%s)\n", + contextp->dc_iocnt, + nread, + saved_errno, + strerror( saved_errno )); + return DRIVE_ERROR_CORRUPTION; +} + +static int +ring_read( void *clientctxp, char *bufp ) +{ + return read_record( ( drive_t * )clientctxp, bufp ); +} + +/* gets another record IF dc_recp is NULL + */ +static intgen_t +getrec( drive_t *drivep ) +{ + drive_context_t *contextp; + contextp = ( drive_context_t * )drivep->d_contextp; + + while ( ! contextp->dc_recp ) { + rec_hdr_t *rechdrp; + if ( contextp->dc_singlethreadedpr ) { + intgen_t rval; + contextp->dc_recp = contextp->dc_bufp; + rval = read_record( drivep, contextp->dc_recp ); + if ( rval ) { + contextp->dc_errorpr = BOOL_TRUE; + return rval; + } + } else { + contextp->dc_msgp = Ring_get( contextp->dc_ringp ); + switch( contextp->dc_msgp->rm_stat ) { + case RING_STAT_OK: + contextp->dc_recp = contextp->dc_msgp->rm_bufp; + break; + case RING_STAT_INIT: + case RING_STAT_NOPACK: + case RING_STAT_IGNORE: + contextp->dc_msgp->rm_op = RING_OP_READ; + Ring_put( contextp->dc_ringp, + contextp->dc_msgp ); + contextp->dc_msgp = 0; + continue; + case RING_STAT_ERROR: + contextp->dc_errorpr = BOOL_TRUE; + return contextp->dc_msgp->rm_rval; + default: + ASSERT( 0 ); + contextp->dc_errorpr = BOOL_TRUE; + return DRIVE_ERROR_CORE; + } + } + rechdrp = ( rec_hdr_t * )contextp->dc_recp; + contextp->dc_recendp = contextp->dc_recp + tape_recsz; + contextp->dc_dataendp = contextp->dc_recp + + + rechdrp->rec_used; + contextp->dc_nextp = contextp->dc_recp + + + STAPE_HDR_SZ; + ASSERT( contextp->dc_nextp <= contextp->dc_dataendp ); + } + + return 0; +} + +/* do a write, determine DRIVE_ERROR_... if failure, and return failure code. + * return 0 on success. + */ +/*ARGSUSED*/ +static intgen_t +write_record( drive_t *drivep, char *bufp, bool_t chksumpr ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + intgen_t nwritten; + intgen_t saved_errno; + intgen_t rval; + + if ( chksumpr ) { + tape_rec_checksum_set( contextp, bufp ); + } + + nwritten = Write( drivep, bufp, tape_recsz, &saved_errno ); + + if ( nwritten == ( intgen_t )tape_recsz ) { + contextp->dc_iocnt++; + return 0; + } + + rval = determine_write_error( nwritten, saved_errno ); + ASSERT(rval); + + return rval; +} + +static int +ring_write( void *clientctxp, char *bufp ) +{ + return write_record( ( drive_t * )clientctxp, bufp, BOOL_TRUE ); +} + +static void +ring_thread( void *clientctxp, + int ( * entryp )( void *ringctxp ), + void *ringctxp ) +{ + drive_t *drivep = ( drive_t * )clientctxp; + /* REFERENCED */ + bool_t ok; + + ok = cldmgr_create( entryp, + CLONE_VM, + drivep->d_index, + "slave", + ringctxp ); + ASSERT( ok ); +} + + +static ring_msg_t * +Ring_get( ring_t *ringp ) +{ + ring_msg_t *msgp; + + mlog( (MLOG_NITTY + 1) | MLOG_DRIVE, + "ring op: get\n" ); + + msgp = ring_get( ringp ); + return msgp; +} + +static void +Ring_put( ring_t *ringp, ring_msg_t *msgp ) +{ + mlog( (MLOG_NITTY + 1) | MLOG_DRIVE, + "ring op: put %d\n", + msgp->rm_op ); + + ring_put( ringp, msgp ); +} + +static void +Ring_reset( ring_t *ringp, ring_msg_t *msgp ) +{ + mlog( (MLOG_NITTY + 1) | MLOG_DRIVE, + "ring op: reset\n" ); + + ASSERT( ringp ); + + ring_reset( ringp, msgp ); +} + +/* a simple heuristic to calculate the maximum uncertainty + * of how much data actually was written prior to encountering + * end of media. + */ +static void +calc_max_lost( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + if ( contextp->dc_isQICpr ) { + contextp->dc_lostrecmax = 1; + } else { + contextp->dc_lostrecmax = 2; + } + +} + +static void +display_ring_metrics( drive_t *drivep, intgen_t mlog_flags ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + ring_t *ringp = contextp->dc_ringp; + char bufszbuf[ 16 ]; + char *bufszsfxp; + + if ( tape_recsz == STAPE_MIN_MAX_BLKSZ ) { + ASSERT( ! ( STAPE_MIN_MAX_BLKSZ % 0x400 )); + sprintf( bufszbuf, "%u", STAPE_MIN_MAX_BLKSZ / 0x400 ); + ASSERT( strlen( bufszbuf ) < sizeof( bufszbuf )); + bufszsfxp = "KB"; + } else if ( tape_recsz == STAPE_MAX_RECSZ ) { + ASSERT( ! ( STAPE_MAX_RECSZ % 0x100000 )); + sprintf( bufszbuf, "%u", STAPE_MAX_RECSZ / 0x100000 ); + ASSERT( strlen( bufszbuf ) < sizeof( bufszbuf )); + bufszsfxp = "MB"; + } else { + sprintf( bufszbuf, "%u", (unsigned int)(tape_recsz / 0x400) ); + bufszsfxp = "KB"; + } + + mlog( mlog_flags, + "I/O metrics: " + "%u by %s%s %sring; " + "%lld/%lld (%.0lf%%) records streamed; " + "%.0lfB/s\n", + contextp->dc_ringlen, + bufszbuf, + bufszsfxp, + contextp->dc_ringpinnedpr ? "pinned " : "", + ringp->r_slave_msgcnt - ringp->r_slave_blkcnt, + ringp->r_slave_msgcnt, + percent64( ringp->r_slave_msgcnt - ringp->r_slave_blkcnt, + ringp->r_slave_msgcnt ), + ( double )( ringp->r_all_io_cnt ) + * + ( double )tape_recsz + / + ( double )( time( 0 ) - ringp->r_first_io_time )); +} + +#ifdef CLRMTAUD +static u_int32_t +#else /* CLRMTAUD */ +static short +#endif /* CLRMTAUD */ +rewind_and_verify( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + ix_t try; + intgen_t rval; + + rval = mt_op( contextp->dc_fd, MTREW, 0 ); + for ( try = 1 ; ; try++ ) { + if ( rval ) { + sleep( 1 ); + rval = mt_op( contextp->dc_fd, MTREW, 0 ); + } else + return 0; + + if ( try >= MTOP_TRIES_MAX ) { + return 0; + } + sleep( 1 ); + } + /* NOTREACHED */ +} + +#ifdef CLRMTAUD +static u_int32_t +#else /* CLRMTAUD */ +static short +#endif /* CLRMTAUD */ +erase_and_verify( drive_t *drivep ) +{ + char *tempbufp; + intgen_t saved_errno; + + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "rmt : erase_and_verify\n" ); + + /* Erase is not standard rmt. So we cannot use the line below. + + ( void )mt_op( contextp->dc_fd, MTERASE, 0 ); + + * So write a record of zeros to fake erase . Poor man's erase! + * We put the ERASE_MAGIC string at the beginning so we can + * detect if we have erased the tape. + */ + + tempbufp = (char *) calloc( 1 , ( size_t )tape_recsz ); + strcpy( tempbufp, ERASE_MAGIC ); + Write( drivep, tempbufp, tape_recsz, &saved_errno ); + free(tempbufp); + + return 0; +} + +#ifdef CLRMTAUD +static u_int32_t +#else /* CLRMTAUD */ +static short +#endif /* CLRMTAUD */ +bsf_and_verify( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + ( void )mt_op( contextp->dc_fd, MTBSF, 1 ); + return 0; +} + +#ifdef CLRMTAUD +static u_int32_t +#else /* CLRMTAUD */ +static short +#endif /* CLRMTAUD */ +fsf_and_verify( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + ( void )mt_op( contextp->dc_fd, MTFSF, 1 ); + + return 0; +} + +static bool_t +set_best_blk_and_rec_sz( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + if ( contextp->dc_isQICpr == BOOL_TRUE ) + tape_recsz = STAPE_MIN_MAX_BLKSZ; + else + tape_recsz = cmdlineblksize; + + return BOOL_TRUE; +} + +static bool_t +isefsdump( drive_t *drivep ) +{ + int32_t *efshdrp = ( int32_t * )drivep->d_greadhdrp; + int32_t efsmagic = efshdrp[ 6 ]; + if ( efsmagic == 60011 + || + efsmagic == 60012 ) { + return BOOL_TRUE; + } else { + return BOOL_FALSE; + } +} + +static bool_t +isxfsdumperasetape( drive_t *drivep ) +{ + if ( !strcmp( ( char * )drivep->d_greadhdrp, ERASE_MAGIC ) ) + return BOOL_TRUE; + else + return BOOL_FALSE; +} + +#ifdef OPENMASKED + +static intgen_t +open_masked_signals( char *pathname, int oflags ) +{ + bool_t isrmtpr; + SIG_PF sigalrm_save; + SIG_PF sigint_save; + SIG_PF sighup_save; + SIG_PF sigquit_save; + SIG_PF sigcld_save; + intgen_t rval; + intgen_t saved_errno; + + if ( strchr( pathname, ':') ) { + isrmtpr = BOOL_TRUE; + } else { + isrmtpr = BOOL_FALSE; + } + + if ( isrmtpr ) { + sigalrm_save = sigset( SIGALRM, SIG_IGN ); + sigint_save = sigset( SIGINT, SIG_IGN ); + sighup_save = sigset( SIGHUP, SIG_IGN ); + sigquit_save = sigset( SIGQUIT, SIG_IGN ); + sigcld_save = sigset( SIGCLD, SIG_IGN ); + } + + errno = 0; + rval = open( pathname, oflags ); + saved_errno = errno; + + if ( isrmtpr ) { + ( void )sigset( SIGCLD, sigcld_save ); + ( void )sigset( SIGQUIT, sigquit_save ); + ( void )sigset( SIGHUP, sighup_save ); + ( void )sigset( SIGINT, sigint_save ); + ( void )sigset( SIGALRM, sigalrm_save ); + } + + errno = saved_errno; + return rval; +} + +#endif /* OPENMASKED */ diff -rNu linux-2.4.7/cmd/xfsdump/common/drive_scsitape.c linux-2.4-xfs/cmd/xfsdump/common/drive_scsitape.c --- linux-2.4.7/cmd/xfsdump/common/drive_scsitape.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/drive_scsitape.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,5381 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "util.h" +#include "qlock.h" +#include "cldmgr.h" +#include "mlog.h" +#include "dlog.h" +#include "global.h" +#include "drive.h" +#include "media.h" +#include "getopt.h" +#include "stream.h" +#include "ring.h" +#include "rec_hdr.h" +#include "arch_xlate.h" + +/* drive_scsitape.c - drive strategy for all scsi tape devices + */ + +/* structure definitions used locally ****************************************/ + +/* remote tape protocol debug + */ +#ifdef OPENMASKED +static intgen_t open_masked_signals( char *path, int oflags ); +#else /* OPENMASKED */ +#define open_masked_signals(p,f) open(p,f) +#endif /* OPENMASKED */ + +#ifdef RMT +#ifdef RMTDBG +#define open(p,f) dbgrmtopen(p,f) +#define close(fd) dbgrmtclose(fd) +#define ioctl(fd,op,arg) dbgrmtioctl(fd,op,arg) +#define read(fd,p,sz) dbgrmtread(fd,p,sz) +#define write(fd,p,sz) dbgrmtwrite(fd,p,sz) +#else /* RMTDBG */ +#define open rmtopen +#define close rmtclose +#define ioctl rmtioctl +#define read rmtread +#define write rmtwrite +#endif /* RMTDBG */ +#endif /* RMT */ + +/* if the media file header structure changes, this number must be + * bumped, and STAPE_VERSION_1 must be defined and recognized. + */ +#define STAPE_VERSION 1 + +/* a bizarre number to help reduce the odds of mistaking random data + * for a media file or record header + */ +#define STAPE_MAGIC 0x13579bdf02468acell + +/* this much of each record is reserved for header info: the user + * data always begins at this offset from the beginning of each + * record. be sure global_hdr_t fits. + */ +#define STAPE_HDR_SZ PGSZ + +/* maximum tape record size. this is the max size of I/O buffers sent to drive. + * note that for variable block devices this determines the block size as well. + */ +#define STAPE_MAX_RECSZ 0x200000 /* 2Mb */ + +/* this is the smallest maximum block size for any tape device + * supported by xfsdump/xfsrestore. we use this when it is not possible + * to ask the driver for block size info. + * i.e. we use this in the remote case. + */ +#define STAPE_MIN_MAX_BLKSZ 0x3c000 /* 240K, 245760 */ + +/* On linux, not all kernels can handle block sizes of 2Mb + * so we use a reduced amount. + */ +#define STAPE_MAX_LINUX_RECSZ 0x100000 + +/* QIC tapes always use 512 byte blocks + */ +#define QIC_BLKSZ 512 + +/* number of record buffers in the I/O ring + */ +#define RINGLEN_MIN 1 +#define RINGLEN_MAX 10 +#define RINGLEN_DEFAULT 3 + +/* tape i/o request retry limit + */ +#define MTOP_TRIES_MAX 10 + +/* operational mode. can be reading or writing, but not both + */ +typedef enum { OM_NONE, OM_READ, OM_WRITE } om_t; + +/* drive_context - control state + * + * NOTE: ring used only if not singlethreaded + */ +struct drive_context { + om_t dc_mode; + /* current mode of operation (READ or WRITE) + */ + size_t dc_ringlen; + /* number of tape_recsz buffers in ring. only used + * for displaying ring info + */ + bool_t dc_ringpinnedpr; + /* are the ring buffers pinned down + */ + ring_t *dc_ringp; + /* handle to ring + */ + ring_msg_t *dc_msgp; + /* currently held ring message + */ + char *dc_bufp; + /* pre-allocated record buffer (only if ring not used) + */ + char *dc_recp; + /* pointer to current record buffer. once the current + * record is completely read or written by client, + * set to NULL. + */ + char *dc_recendp; + /* always set to point to just off the end of the + * current record buffer pointed to by dc_recp. valid + * only when dc_recp non-NULL. + */ + char *dc_dataendp; + /* same as dc_recendp, except for first and last + * records in media file. the first record is all + * pads after the header page. the last record may + * have been padded (as indicated by the rec_used + * field of the record header). in either case + * dc_dataendp points to first padding byte. + */ + char *dc_ownedp; + /* first byte in current buffer owned by caller. + * given to caller by do_read or do_get_write_buf + * set to null by do_return_read_buf or do_write. + */ + char *dc_nextp; + /* next byte available in current buffer to give + * to do_get_write_buf for writing or do_read for + * reading. + */ + off64_t dc_reccnt; + /* count of the number of records completely read or + * written by client, and therefore not represented + * by current dc_recp. valid initially and after + * each call to do_return_read_buf or do_write. + * NOT valid after a call to do_read or + * do_get_write_buf. always bumped regardless of + * read or write error status. + */ + off64_t dc_iocnt; + /* count of the number of records read or written + * to media without error. includes media file header + * record. this is incremented when the actual I/O is + * done. dc_reccnt is different, indicating what has + * been seen by client. slave may have read ahead / + * written behind. + */ + int dc_fd; + /* drive file descriptor. -1 when not open + */ + bool_t dc_isrmtpr; + /* TRUE if drive being accessed via RMT + */ + bool_t dc_isvarpr; + /* TRUE if variable block size device + */ + bool_t dc_cangetblkszpr; + /* TRUE if can get blksz info from driver + */ + bool_t dc_cansetblkszpr; + /* TRUE if can set blksz info to driver + */ + size_t dc_maxblksz; + /* maximum block size. + */ + size_t dc_origcurblksz; + /* Save original curblksz to restore on quit. + */ + bool_t dc_isQICpr; + /* fixed 512 byte block size device. + */ + bool_t dc_canfsrpr; + /* can seek forward records at a time + */ + size_t dc_blksz; + /* actual tape blksize selected + */ + size_t dc_recsz; + /* actual tape record size selected + */ + off64_t dc_lostrecmax; + /* maximum number of records written without error + * which may be lost due to a near end-of-tape + * experience. a function of drive type and + * compression + */ + bool_t dc_singlethreadedpr; + /* single-threaded operation (no slave) + */ + bool_t dc_errorpr; + /* TRUE if error encountered during reading or writing. + * used to detect attempts to read or write after + * error reported. + */ + bool_t dc_recchksumpr; + /* TRUE if records should be checksumed + */ + bool_t dc_unloadokpr; + /* ok to issue unload command when do_eject invoked. + */ + bool_t dc_overwritepr; + /* overwrite tape without checking whats on it + */ + off64_t dc_filesz; + /* file size given as argument + */ +}; + +typedef struct drive_context drive_context_t; + +/* macros for shortcut references to context. assumes a local variable named + * 'contextp'. + */ +#define tape_recsz ( contextp->dc_recsz ) +#define tape_blksz ( contextp->dc_blksz ) + +/* macros to interpret tape status information returned by reference from + * mt_get_status( ). + */ + /* tape is positioned at end-of-tape */ +#define IS_EOT(mtstat) GMT_EOT(mtstat) + /* tape is positioned at beginning-of-tape */ +#define IS_BOT(mtstat) GMT_BOT(mtstat) + /* the tape is write protected */ +#define IS_WPROT(mtstat) GMT_WR_PROT(mtstat) + /* the tape drive is online */ +#define IS_ONL(mtstat) GMT_ONLINE(mtstat) + /* the tape is positioned at the end of user data */ +#define IS_EOD(mtstat) GMT_EOD(mtstat) + /* the tape is positioned at at file mark */ +#define IS_FMK(mtstat) GMT_EOF(mtstat) + /* tape is positioned at early warning */ + /* not supported by linux tape drivers */ +#define IS_EW(mtstat) (0) + +/* needed for Linux */ +struct mtblkinfo { + unsigned maxblksz; /* maximum block size */ + unsigned curblksz; /* current block size */ +}; + +typedef long mtstat_t; + + +/* declarations of externally defined global variables ***********************/ + +extern void usage( void ); + +/* remote tape protocol declarations (should be a system header file) + */ +#ifdef RMT +extern int rmtopen( char *, int, ... ); +extern int rmtclose( int ); +extern int rmtfstat( int, struct stat * ); +extern int rmtioctl( int, int, ... ); +extern int rmtread( int, void*, uint); +extern int rmtwrite( int, const void *, uint); +#endif /* RMT */ + + +/* forward declarations of locally defined static functions ******************/ + +/* strategy functions + */ +static intgen_t ds_match( int, char *[], drive_t *, bool_t ); +static intgen_t ds_instantiate( int, char *[], drive_t *, bool_t ); + +/* manager operations + */ +static bool_t do_init( drive_t * ); +static bool_t do_sync( drive_t * ); +static intgen_t do_begin_read( drive_t * ); +static char *do_read( drive_t *, size_t , size_t *, intgen_t * ); +static void do_return_read_buf( drive_t *, char *, size_t ); +static void do_get_mark( drive_t *, drive_mark_t * ); +static intgen_t do_seek_mark( drive_t *, drive_mark_t * ); +static intgen_t do_next_mark( drive_t * ); +static void do_get_mark( drive_t *, drive_mark_t * ); +static void do_end_read( drive_t * ); +static intgen_t do_begin_write( drive_t * ); +static void do_set_mark( drive_t *, drive_mcbfp_t, void *, drive_markrec_t * ); +static char * do_get_write_buf( drive_t *, size_t , size_t * ); +static intgen_t do_write( drive_t *, char *, size_t ); +static size_t do_get_align_cnt( drive_t * ); +static intgen_t do_end_write( drive_t *, off64_t * ); +static intgen_t do_fsf( drive_t *, intgen_t , intgen_t *); +static intgen_t do_bsf( drive_t *, intgen_t , intgen_t *); +static intgen_t do_rewind( drive_t * ); +static intgen_t do_erase( drive_t * ); +static intgen_t do_eject_media( drive_t * ); +static intgen_t do_get_device_class( drive_t * ); +static void do_display_metrics( drive_t *drivep ); +static void do_quit( drive_t * ); + +/* misc. local utility funcs + */ +static intgen_t mt_op(intgen_t , intgen_t , intgen_t ); +static intgen_t mt_blkinfo(intgen_t , struct mtblkinfo * ); +static bool_t mt_get_fileno( drive_t *, long *); +static bool_t mt_get_status( drive_t *, mtstat_t *); +static intgen_t determine_write_error( drive_t *, int, int ); +static intgen_t read_label( drive_t *); +static bool_t tape_rec_checksum_check( drive_context_t *, char * ); +static void set_recommended_sizes( drive_t * ); +static void display_access_failed_message( drive_t *); +static void status_failed_message( drive_t *); +static bool_t get_tpcaps( drive_t * ); +static bool_t set_fixed_blksz( drive_t *, size_t ); +static intgen_t prepare_drive( drive_t *drivep ); +static bool_t Open( drive_t *drivep ); +static void Close( drive_t *drivep ); +static intgen_t Read( drive_t *drivep, + char *bufp, + size_t cnt, + intgen_t *errnop ); +static intgen_t Write( drive_t *drivep, + char *bufp, + size_t cnt, + intgen_t *saved_errnop ); +static intgen_t quick_backup( drive_t *drivep, + drive_context_t *contextp, + ix_t skipcnt ); +static intgen_t record_hdr_validate( drive_t *drivep, + char *bufp, + bool_t chkoffpr ); +static void ring_thread( void *clientctxp, + int ( * entryp )( void *ringctxp ), + void *ringctxp ); +static int ring_read( void *clientctxp, char *bufp ); +static int ring_write( void *clientctxp, char *bufp ); +static double percent64( off64_t num, off64_t denom ); +static intgen_t getrec( drive_t *drivep ); +static intgen_t write_record( drive_t *drivep, char *bufp, bool_t chksumpr ); +static ring_msg_t * Ring_get( ring_t *ringp ); +static void Ring_reset( ring_t *ringp, ring_msg_t *msgp ); +static void Ring_put( ring_t *ringp, ring_msg_t *msgp ); +static intgen_t validate_media_file_hdr( drive_t *drivep ); +static void calc_max_lost( drive_t *drivep ); +static void display_ring_metrics( drive_t *drivep, intgen_t mlog_flags ); +static mtstat_t rewind_and_verify( drive_t *drivep ); +static mtstat_t erase_and_verify( drive_t *drivep ); +static mtstat_t bsf_and_verify( drive_t *drivep ); +static mtstat_t fsf_and_verify( drive_t *drivep ); +static void calc_best_blk_and_rec_sz( drive_t *drivep ); +static bool_t set_best_blk_and_rec_sz( drive_t *drivep ); +static bool_t isefsdump( drive_t *drivep ); + +/* RMT trace stubs + */ +#ifdef RMT +#ifdef RMTDBG +static int dbgrmtopen( char *, int, ... ); +static int dbgrmtclose( int ); +static int dbgrmtioctl( int, int, ... ); +static int dbgrmtread( int, void*, uint); +static int dbgrmtwrite( int, const void *, uint); +#endif /* RMTDBG */ +#endif /* RMT */ + +/* definition of locally defined global variables ****************************/ + +/* scsitape drive strategy. referenced by drive.c + */ +drive_strategy_t drive_strategy_scsitape = { + DRIVE_STRATEGY_SCSITAPE,/* ds_id */ + "drive_scsitape", /* ds_description */ + ds_match, /* ds_match */ + ds_instantiate, /* ds_instantiate */ + 0x1000000ll, /* ds_recmarksep 16 MB */ + 0x10000000ll, /* ds_recmfilesz 256 MB */ +}; + + +/* definition of locally defined static variables *****************************/ + +/* drive operators + */ +static drive_ops_t drive_ops = { + do_init, /* do_init */ + do_sync, /* do_sync */ + do_begin_read, /* do_begin_read */ + do_read, /* do_read */ + do_return_read_buf, /* do_return_read_buf */ + do_get_mark, /* do_get_mark */ + do_seek_mark, /* do_seek_mark */ + do_next_mark, /* do_next_mark */ + do_end_read, /* do_end_read */ + do_begin_write, /* do_begin_write */ + do_set_mark, /* do_set_mark */ + do_get_write_buf, /* do_get_write_buf */ + do_write, /* do_write */ + do_get_align_cnt, /* do_get_align_cnt */ + do_end_write, /* do_end_write */ + do_fsf, /* do_fsf */ + do_bsf, /* do_bsf */ + do_rewind, /* do_rewind */ + do_erase, /* do_erase */ + do_eject_media, /* do_eject_media */ + do_get_device_class, /* do_get_device_class */ + do_display_metrics, /* do_display_metrics */ + do_quit, /* do_quit */ +}; + +static u_int32_t cmdlineblksize = 0; + +/* definition of locally defined global functions ****************************/ + + +/* definition of locally defined static functions ****************************/ + +static bool_t +is_scsi_driver(char *pathname) +{ + char rp[PATH_MAX]; + + if (realpath(pathname, rp) == NULL) { + return BOOL_FALSE; + } + + /* following what is in Documentation/devices.txt for Linux */ + if (strstr(rp, "/nst") != NULL || strstr(rp, "/st") != NULL) + return BOOL_TRUE; + else + return BOOL_FALSE; +} + +/* strategy match - determines if this is the right strategy + */ +/* ARGSUSED */ +static intgen_t +ds_match( int argc, char *argv[], drive_t *drivep, bool_t singlethreaded ) +{ + struct mtget mt_stat; + intgen_t fd; + + /* heuristics to determine if this is a drive. + */ + + if ( ! strcmp( drivep->d_pathname, "stdio" )) { + return -10; + } + + if ( strchr( drivep->d_pathname, ':')) { + errno = 0; + fd = open_masked_signals( drivep->d_pathname, O_RDONLY ); + if ( fd < 0 ) { + return -10; + } + if ( ioctl( fd, MTIOCGET, &mt_stat ) < 0 ) { + close( fd ); + return -10; + } + close( fd ); + return 10; + } else { + if (is_scsi_driver(drivep->d_pathname)) { + return 10; + } + return -10; + } +} + +/* strategy instantiate - initializes the pre-allocated drive descriptor + */ +/*ARGSUSED*/ +static bool_t +ds_instantiate( int argc, char *argv[], drive_t *drivep, bool_t singlethreaded ) +{ + drive_context_t *contextp; + intgen_t c; + + /* opportunity for sanity checking + */ + ASSERT( sizeof( global_hdr_t ) <= STAPE_HDR_SZ ); + ASSERT( sizeof( rec_hdr_t ) + == + sizeofmember( drive_hdr_t, dh_specific )); + ASSERT( ! ( STAPE_MAX_RECSZ % PGSZ )); + + /* hook up the drive ops + */ + drivep->d_opsp = &drive_ops; + + /* allocate context for the drive manager + */ + contextp = ( drive_context_t * )calloc( 1, sizeof( drive_context_t )); + ASSERT( contextp ); + memset( ( void * )contextp, 0, sizeof( *contextp )); + + /* transfer indication of singlethreadedness to context + */ + contextp->dc_singlethreadedpr = singlethreaded; + + /* scan the command line for the I/O buffer ring length + * and record checksum request + */ + contextp->dc_ringlen = RINGLEN_DEFAULT; + contextp->dc_ringpinnedpr = BOOL_FALSE; + contextp->dc_recchksumpr = BOOL_FALSE; + contextp->dc_isQICpr = BOOL_FALSE; +#ifdef DUMP + contextp->dc_filesz = 0; +#endif + optind = 1; + opterr = 0; + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + switch ( c ) { + case GETOPT_RINGLEN: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "-%c argument missing\n", + optopt ); + return BOOL_FALSE; + } + contextp->dc_ringlen = ( size_t )atoi( optarg ); + if ( contextp->dc_ringlen < RINGLEN_MIN + || + contextp->dc_ringlen > RINGLEN_MAX ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "-%c argument must be " + "between %u and %u: ignoring %u\n", + optopt, + RINGLEN_MIN, + RINGLEN_MAX, + contextp->dc_ringlen ); + return BOOL_FALSE; + } + break; + case GETOPT_RINGPIN: + contextp->dc_ringpinnedpr = BOOL_TRUE; + break; + case GETOPT_RECCHKSUM: + contextp->dc_recchksumpr = BOOL_TRUE; + break; + case GETOPT_UNLOAD: + contextp->dc_unloadokpr = BOOL_TRUE; + break; + case GETOPT_QIC: + contextp->dc_isQICpr = BOOL_TRUE; + break; + case GETOPT_BLOCKSIZE: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "-%c argument missing\n", + optopt ); + return -10; + } + cmdlineblksize = ( u_int32_t )atoi( optarg ); + break; +#ifdef DUMP + case GETOPT_FILESZ: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "-%c argument missing\n", + optopt ); + return BOOL_FALSE; + } + /* given in Mb */ + contextp->dc_filesz = (off64_t)atoi( optarg ) * 1024 * 1024; + if (contextp->dc_filesz <= 0) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "-%c argument must be " + "positive number (Mb): ignoring %u\n", + optopt, + contextp->dc_filesz ); + return BOOL_FALSE; + } + break; + case GETOPT_OVERWRITE: + contextp->dc_overwritepr = BOOL_TRUE; + break; +#endif + } + } + + /* set drive file descriptor to null value + */ + contextp->dc_fd = -1; + + /* record location of context descriptor in drive descriptor + */ + drivep->d_contextp = (void *)contextp; + + /* indicate neither capacity nor rate estimates available + */ + drivep->d_cap_est = -1; + drivep->d_rate_est = -1; + + /* if sproc not allowed, allocate a record buffer. otherwise + * create a ring, from which buffers will be taken. + */ + if ( singlethreaded ) { + contextp->dc_bufp = ( char * )memalign( PGSZ, STAPE_MAX_RECSZ ); + ASSERT( contextp->dc_bufp ); + } else { + intgen_t rval; + mlog( (MLOG_NITTY + 1) | MLOG_DRIVE, + "ring op: create: ringlen == %u\n", + contextp->dc_ringlen ); + contextp->dc_ringp = ring_create( contextp->dc_ringlen, + STAPE_MAX_RECSZ, + contextp->dc_ringpinnedpr, + ring_thread, + ring_read, + ring_write, + ( void * )drivep, + &rval ); + if ( ! contextp->dc_ringp ) { + if ( rval == ENOMEM ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "unable to allocate memory " + "for I/O buffer ring\n" ); + } else if ( rval == E2BIG ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "not enough physical memory " + "to pin down I/O buffer ring\n" ); + } else if ( rval == EPERM ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "not allowed " + "to pin down I/O buffer ring\n" ); + } else { + ASSERT( 0 ); + } + return BOOL_FALSE; + } + } + + /* scan drive device pathname to see if remote tape + */ + if ( strchr( drivep->d_pathname, ':') ) { + contextp->dc_isrmtpr = BOOL_TRUE; + } else { + contextp->dc_isrmtpr = BOOL_FALSE; + } + + /* several of contextp predicates cannot yet be determined. + * mark them as unknown for now. however, if this is an RMT + * access, we know immediately some capabilities are missing. + */ + if ( contextp->dc_isrmtpr ) { + contextp->dc_cangetblkszpr = BOOL_FALSE; + contextp->dc_cansetblkszpr = BOOL_FALSE; + contextp->dc_isvarpr = BOOL_TRUE; + contextp->dc_isQICpr = BOOL_FALSE; + } else { + contextp->dc_cangetblkszpr = BOOL_UNKNOWN; + contextp->dc_cansetblkszpr = BOOL_UNKNOWN; + contextp->dc_isvarpr = BOOL_UNKNOWN; + } + /* specify that we are currently neither reading nor writing + */ + contextp->dc_mode = OM_NONE; + + /* set the capabilities flags advertised in the drive_t d_capabilities + * field that we know a priori to be true. later additional flags + * may be set + */ + drivep->d_capabilities = 0 + | + DRIVE_CAP_BSF + | + DRIVE_CAP_FSF + | + DRIVE_CAP_REWIND + | + DRIVE_CAP_FILES + | + DRIVE_CAP_APPEND + | + DRIVE_CAP_NEXTMARK + | + DRIVE_CAP_EJECT + | + DRIVE_CAP_READ + | + DRIVE_CAP_REMOVABLE + | + DRIVE_CAP_ERASE + ; + + /* initialize origcurblksz so we only save it once + */ + contextp->dc_origcurblksz = 0; + + return BOOL_TRUE; +} + +/* drive op init - do more time-consuming init/checking here. read and + * write headers are available now. + * + * NOTE: + * When using a RMT device, the MTIOCGETBLKINFO, MTCAPABILITY and + * MTSPECOP ioctl calls are not supported. This means that we have + * to assume that the drive does not support the MTCAN_APPEND capability. + */ +/* ARGSUSED */ +static bool_t +do_init( drive_t *drivep ) +{ +#ifdef DUMP + drive_hdr_t *dwhdrp = drivep->d_writehdrp; + media_hdr_t *mwhdrp = ( media_hdr_t * )dwhdrp->dh_upper; +#endif /* DUMP */ + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: init\n" ); + +#ifdef DUMP + /* fill in media strategy id: artifact of first version of xfsdump + */ + mwhdrp->mh_strategyid = MEDIA_STRATEGY_RMVTAPE; +#endif /* DUMP */ + + return BOOL_TRUE; +} + +/* wait here for slave to complete initialization. + * set drive capabilities flags. NOTE: currently don't make use of this + * feature: drive initialization done whenever block/record sizes unknown. + */ +/* ARGSUSED */ +static bool_t +do_sync( drive_t *drivep ) +{ + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: sync\n" ); + + return BOOL_TRUE; +} + +/* begin_read + * Set up the tape device and read the media file header. + * if allowed, begin read-ahead. + * + * RETURNS: + * 0 on success + * DRIVE_ERROR_* on failure + * + */ +static intgen_t +do_begin_read( drive_t *drivep ) +{ + drive_context_t *contextp; + intgen_t rval; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: begin read\n" ); + + /* get drive context + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + /* verify protocol being followed + */ + ASSERT( drivep->d_capabilities & DRIVE_CAP_READ ); + ASSERT( contextp->dc_mode == OM_NONE ); + ASSERT( ! contextp->dc_recp ); + + /* get a record buffer to use during initialization. + */ + if ( contextp->dc_singlethreadedpr ) { + contextp->dc_recp = contextp->dc_bufp; + } else { + ASSERT( contextp->dc_ringp ); + contextp->dc_msgp = Ring_get( contextp->dc_ringp ); + ASSERT( contextp->dc_msgp->rm_stat == RING_STAT_INIT ); + contextp->dc_recp = contextp->dc_msgp->rm_bufp; + } + + /* if the tape is not open, open, determine the record size, and + * read the first record. otherwise read a record using the record + * size previously determined. + */ + contextp->dc_iocnt = 0; + if ( contextp->dc_fd < 0 ) { + ASSERT( contextp->dc_fd == -1 ); + rval = prepare_drive( drivep ); + if ( rval ) { + if ( ! contextp->dc_singlethreadedpr ) { + Ring_reset( contextp->dc_ringp, contextp->dc_msgp ); + } + contextp->dc_msgp = 0; + contextp->dc_recp = 0; + return rval; + } + } else { + rval = read_label( drivep ); + if ( rval ) { + if ( ! contextp->dc_singlethreadedpr ) { + Ring_reset( contextp->dc_ringp, contextp->dc_msgp ); + } + contextp->dc_msgp = 0; + contextp->dc_recp = 0; + return rval; + } + } + ASSERT( contextp->dc_iocnt == 1 ); + /* set by prepare_drive or read_label */ + + /* all is well. adjust context. don't kick off read-aheads just yet; + * the client may not want this media file. + */ + if ( ! contextp->dc_singlethreadedpr ) { + contextp->dc_msgp->rm_op = RING_OP_NOP; + contextp->dc_msgp->rm_user = 0; /* do diff. use in do_seek */ + Ring_put( contextp->dc_ringp, contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_recp = 0; + contextp->dc_recendp = 0; + contextp->dc_dataendp = 0; + contextp->dc_ownedp = 0; + contextp->dc_nextp = 0; + contextp->dc_reccnt = 1; + + /* used to detect attempt to read after an error was reported + */ + contextp->dc_errorpr = BOOL_FALSE; + + /* successfully entered read mode. must do end_read to get out. + */ + contextp->dc_mode = OM_READ; + + return 0; +} + +/* do_read + * Supply the caller with all or a portion of the current buffer, + * filled with data from a record. + * + * RETURNS: + * a pointer to a buffer containing "*actual_bufszp" bytes of data + * or 0 on failure with "*rvalp" containing the error (DRIVE_ERROR_...) + * + */ +static char * +do_read( drive_t *drivep, + size_t wantedcnt, + size_t *actualcntp, + intgen_t *rvalp ) +{ + drive_context_t *contextp; + size_t availcnt; + size_t actualcnt; + intgen_t rval; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: read: wanted %u (0x%x)\n", + wantedcnt, + wantedcnt ); + + /* get context ptrs + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + /* assert protocol being followed + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( ! contextp->dc_ownedp ); + ASSERT( wantedcnt > 0 ); + + /* clear the return status field + */ + *rvalp = 0; + + /* read a new record if necessary + */ + rval = getrec( drivep ); + if ( rval ) { + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive op read returning error rval=%d\n", + rval ); + *rvalp = rval; + return 0; + } + + /* figure how much data is available, and how much should be supplied + */ + availcnt = ( size_t )( contextp->dc_dataendp - contextp->dc_nextp ); + actualcnt = min( wantedcnt, availcnt ); + + /* adjust the context + */ + contextp->dc_ownedp = contextp->dc_nextp; + contextp->dc_nextp += actualcnt; + ASSERT( contextp->dc_nextp <= contextp->dc_dataendp ); + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive op read actual == %d (0x%x)\n", + actualcnt, + actualcnt ); + + *actualcntp = actualcnt; + return contextp->dc_ownedp; +} + +/* do_return_read_buf - + * Lets the caller give back the buffer portion obtained from the preceding + * call to do_read(). + * + * RETURNS: + * void + */ +/* ARGSUSED */ +static void +do_return_read_buf( drive_t *drivep, char *bufp, size_t retcnt ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + /* REFERENCED */ + size_t ownedcnt; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: return read buf: sz %d (0x%x)\n", + retcnt, + retcnt ); + + /* assert protocol being followed + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( contextp->dc_ownedp ); + ASSERT( bufp == contextp->dc_ownedp ); + + /* calculate how much the caller owns + */ + ASSERT( contextp->dc_nextp >= contextp->dc_ownedp ); + ownedcnt = ( size_t )( contextp->dc_nextp - contextp->dc_ownedp ); + ASSERT( ownedcnt == retcnt ); + + /* take possession of buffer portion + */ + contextp->dc_ownedp = 0; + + /* if caller is done with this record, take the buffer back + * and (if ring in use) give buffer to ring for read-ahead. + */ + if ( contextp->dc_nextp >= contextp->dc_dataendp ) { + ASSERT( contextp->dc_nextp == contextp->dc_dataendp ); + if ( ! contextp->dc_singlethreadedpr ) { + contextp->dc_msgp->rm_op = RING_OP_READ; + Ring_put( contextp->dc_ringp, contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_recp = 0; + contextp->dc_recendp = 0; + contextp->dc_dataendp = 0; + contextp->dc_nextp = 0; + contextp->dc_reccnt++; + } +} + +/* do_get_mark + * Get the current read tape location. + * + * RETURNS: + * void + */ +static void +do_get_mark( drive_t *drivep, drive_mark_t *markp ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + off64_t offset; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: get mark\n" ); + + /* assert protocol being followed + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( ! contextp->dc_ownedp ); + + /* the mark is simply the offset into the media file of the + * next byte to be read. + */ + offset = contextp->dc_reccnt * ( off64_t )tape_recsz; + if ( contextp->dc_recp ) { + offset += ( off64_t )( contextp->dc_nextp - contextp->dc_recp ); + } + + *markp = ( drive_mark_t )offset; + + return; +} + +typedef enum { SEEKMODE_BUF, SEEKMODE_RAW } seekmode_t; + +/* do_seek_mark + * Advance the tape to the given mark. does dummy reads to + * advance tape, as well as FSR if supported. + * + * RETURNS: + * 0 on success + * DRIVE_ERROR_* on failure + * + */ +static intgen_t +do_seek_mark( drive_t *drivep, drive_mark_t *markp ) +{ + drive_context_t *contextp; + off64_t wantedoffset; + off64_t currentoffset; + + /* get the drive context + */ + contextp = (drive_context_t *)drivep->d_contextp; + + /* assert protocol being followed + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( ! contextp->dc_ownedp ); + + + /* the desired mark is passed by reference, and is really just an + * offset into the raw (incl rec hdrs) read stream + */ + wantedoffset = *( off64_t * )markp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: seek mark: %lld (0x%llx)\n", + wantedoffset, + wantedoffset ); + + /* determine the current offset. assert that the wanted offset is + * not less than the current offset. + */ + currentoffset = contextp->dc_reccnt * ( off64_t )tape_recsz; + if ( contextp->dc_recp ) { + u_int32_t recoff; +#ifdef DEBUG + rec_hdr_t *rechdrp = ( rec_hdr_t * )contextp->dc_recp; +#endif + + ASSERT( contextp->dc_nextp >= contextp->dc_recp ); + recoff = ( u_int32_t )( contextp->dc_nextp + - + contextp->dc_recp ); + ASSERT( recoff <= tape_recsz ); + ASSERT( rechdrp->rec_used <= tape_recsz ); + ASSERT( recoff >= STAPE_HDR_SZ ); + ASSERT( rechdrp->rec_used >= STAPE_HDR_SZ ); + ASSERT( recoff <= rechdrp->rec_used ); + currentoffset += ( off64_t )recoff; + } + ASSERT( wantedoffset >= currentoffset ); + + /* if we are currently holding a record and the desired offset + * is not within the current record, eat the current record. + */ + if ( contextp->dc_recp ) { + off64_t nextrecoffset; + rec_hdr_t *rechdrp = ( rec_hdr_t * )contextp->dc_recp; + + nextrecoffset = contextp->dc_reccnt * ( off64_t )tape_recsz + + + ( off64_t )rechdrp->rec_used; + if ( wantedoffset >= nextrecoffset ) { + u_int32_t recoff; + size_t wantedcnt; + char *dummybufp; + size_t actualcnt; + intgen_t rval; + + /* if this is the last record, the wanted offset + * must be just after it. + */ + if ( rechdrp->rec_used < tape_recsz ) { + ASSERT( wantedoffset == nextrecoffset ); + } + + /* figure how much to ask for + */ + ASSERT( contextp->dc_nextp >= contextp->dc_recp ); + recoff = ( u_int32_t )( contextp->dc_nextp + - + contextp->dc_recp ); + wantedcnt = ( size_t )( rechdrp->rec_used + - + recoff ); + + /* eat that much tape + */ + rval = 0; + dummybufp = do_read( drivep, + wantedcnt, + &actualcnt, + &rval ); + if ( rval ) { + return rval; + } + ASSERT( actualcnt == wantedcnt ); + do_return_read_buf( drivep, dummybufp, actualcnt ); + currentoffset += ( off64_t )actualcnt; + ASSERT( currentoffset == nextrecoffset ); + ASSERT( wantedoffset >= currentoffset ); + ASSERT( ! contextp->dc_recp ); + ASSERT( currentoffset + == + contextp->dc_reccnt * ( off64_t )tape_recsz ); + } + } + + /* if FSR is supported, while the desired offset is more than a record + * away, eat records. this is tricky. if read-ahead has already read + * to the desired point, no need to FSR: fall through to next code block + * where we get there by eating excess records. if read-ahead has not + * made it there, suspend read-ahead, eat those readahead records, + * FSR the remaining, and resume readahead. + */ + if ( contextp->dc_canfsrpr + && + wantedoffset - currentoffset >= ( off64_t )tape_recsz ) { + off64_t wantedreccnt; + seekmode_t seekmode; + + ASSERT( ! contextp->dc_recp ); + wantedreccnt = wantedoffset / ( off64_t )tape_recsz; + if ( contextp->dc_singlethreadedpr ) { + seekmode = SEEKMODE_RAW; + } else { + seekmode = SEEKMODE_BUF; + } + ASSERT( wantedreccnt != 0 ); /* so NOP below can be + * distinguished from use + * in do_begin_read + */ + while ( contextp->dc_reccnt < wantedreccnt ) { + off64_t recskipcnt64; + off64_t recskipcnt64remaining; + + if ( seekmode == SEEKMODE_BUF ) { + ring_stat_t rs; + ASSERT( ! contextp->dc_msgp ); + contextp->dc_msgp = + Ring_get( contextp->dc_ringp ); + rs = contextp->dc_msgp->rm_stat; + if ( rs == RING_STAT_ERROR ) { + contextp->dc_errorpr = BOOL_TRUE; + return contextp->dc_msgp->rm_rval; + } + if ( rs != RING_STAT_OK + && + rs != RING_STAT_INIT + && + rs != RING_STAT_NOPACK ) { + ASSERT( 0 ); + contextp->dc_errorpr = BOOL_TRUE; + return DRIVE_ERROR_CORE; + } + if ( rs == RING_STAT_OK ) { + contextp->dc_reccnt++; + } + if ( rs == RING_STAT_NOPACK + && + contextp->dc_msgp->rm_user + == + wantedreccnt ) { + seekmode = SEEKMODE_RAW; + } + contextp->dc_msgp->rm_op = RING_OP_NOP; + contextp->dc_msgp->rm_user = wantedreccnt; + Ring_put( contextp->dc_ringp, + contextp->dc_msgp ); + contextp->dc_msgp = 0; + continue; + } + + ASSERT( contextp->dc_reccnt == contextp->dc_iocnt ); + ASSERT( wantedreccnt > contextp->dc_reccnt ); + recskipcnt64 = wantedreccnt - contextp->dc_reccnt; + recskipcnt64remaining = recskipcnt64; + while ( recskipcnt64remaining ) { + intgen_t recskipcnt; + intgen_t saved_errno; + intgen_t rval; + + ASSERT( recskipcnt64remaining > 0 ); + if ( recskipcnt64remaining > INTGENMAX ) { + recskipcnt = INTGENMAX; + } else { + recskipcnt = ( intgen_t ) + recskipcnt64remaining; + } + ASSERT( recskipcnt > 0 ); + rval = mt_op( contextp->dc_fd, + MTFSR, + recskipcnt ); + saved_errno = errno; + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "could not forward space %d " + "tape blocks: " + "rval == %d, errno == %d (%s)\n", + rval, + saved_errno, + strerror( saved_errno )); + return DRIVE_ERROR_MEDIA; + } + recskipcnt64remaining -= ( off64_t )recskipcnt; + } + contextp->dc_reccnt += recskipcnt64; + contextp->dc_iocnt += recskipcnt64; + currentoffset = contextp->dc_reccnt + * + ( off64_t )tape_recsz; + ASSERT( wantedoffset >= currentoffset ); + ASSERT( wantedoffset - currentoffset + < + ( off64_t )tape_recsz ); + } + } + + /* remove excess records by eating them. won't be any if + * FSR supported + */ + while ( wantedoffset - currentoffset >= ( off64_t )tape_recsz ) { + size_t wantedcnt; + char *dummybufp; + size_t actualcnt; + intgen_t rval; + + ASSERT( ! contextp->dc_recp ); + + /* figure how much to ask for. to eat an entire record, + * ask for a record sans the header. do_read will eat + * the header, we eat the rest. + */ + wantedcnt = ( size_t )( tape_recsz - STAPE_HDR_SZ ); + + /* eat that much tape + */ + rval = 0; + dummybufp = do_read( drivep, wantedcnt, &actualcnt, &rval ); + if ( rval ) { + return rval; + } + ASSERT( actualcnt == wantedcnt ); + do_return_read_buf( drivep, dummybufp, actualcnt ); + ASSERT( ! contextp->dc_recp ); + currentoffset += ( off64_t )tape_recsz; + ASSERT( currentoffset + == + contextp->dc_reccnt * ( off64_t )tape_recsz ); + } + + /* eat that portion of the next record leading up to the + * desired offset. + */ + if ( wantedoffset != currentoffset ) { + size_t wantedcnt; + char *dummybufp; + size_t actualcnt; + + ASSERT( wantedoffset > currentoffset ); + ASSERT( wantedoffset - currentoffset < ( off64_t )tape_recsz ); + wantedcnt = ( size_t )( wantedoffset - currentoffset ); + if ( contextp->dc_recp ) { + u_int32_t recoff; +#ifdef DEBUG + rec_hdr_t *rechdrp = ( rec_hdr_t * )contextp->dc_recp; +#endif + recoff = ( u_int32_t )( contextp->dc_nextp + - + contextp->dc_recp ); + ASSERT( recoff <= tape_recsz ); + ASSERT( rechdrp->rec_used <= tape_recsz ); + ASSERT( recoff >= STAPE_HDR_SZ ); + ASSERT( rechdrp->rec_used >= STAPE_HDR_SZ ); + ASSERT( recoff <= rechdrp->rec_used ); + ASSERT( recoff + wantedcnt <= rechdrp->rec_used ); + } else { + ASSERT( wantedcnt >= STAPE_HDR_SZ ); + wantedcnt -= STAPE_HDR_SZ; + } + + /* eat that much tape + */ + if ( wantedcnt > 0 ) { + intgen_t rval; + rval = 0; + dummybufp = do_read( drivep, wantedcnt, &actualcnt, &rval ); + if ( rval ) { + return rval; + } + ASSERT( actualcnt == wantedcnt ); + do_return_read_buf( drivep, dummybufp, actualcnt ); + } + } + + /* as a sanity check, refigure the current offset and make sure + * it is equal to the wanted offset + */ + currentoffset = contextp->dc_reccnt * ( off64_t )tape_recsz; + if ( contextp->dc_recp ) { + u_int32_t recoff; +#ifdef DEBUG + rec_hdr_t *rechdrp = ( rec_hdr_t * )contextp->dc_recp; +#endif + + ASSERT( contextp->dc_nextp >= contextp->dc_recp ); + recoff = ( u_int32_t )( contextp->dc_nextp + - + contextp->dc_recp ); + ASSERT( recoff <= tape_recsz ); + ASSERT( rechdrp->rec_used <= tape_recsz ); + ASSERT( recoff >= STAPE_HDR_SZ ); + ASSERT( rechdrp->rec_used >= STAPE_HDR_SZ ); + ASSERT( recoff <= rechdrp->rec_used ); + currentoffset += ( off64_t )recoff; + } + ASSERT( wantedoffset == currentoffset ); + + return 0; +} + +/* do_next_mark + * Advance the tape position to the next valid mark. if in + * error mode, first attempt to move past error by re-reading. if + * that fails, try to FSR. also deals with QIC possibility of + * reading a block not at a record boundary. + * + * RETURNS: + * 0 on success + * DRIVE_ERROR_* on failure + */ +static intgen_t +do_next_mark( drive_t *drivep ) +{ + drive_context_t *contextp = (drive_context_t *)drivep->d_contextp; + rec_hdr_t *rechdrp; + char *p; + ix_t trycnt; + const ix_t maxtrycnt = 5; + intgen_t nread; + off64_t markoff; + intgen_t saved_errno; + mtstat_t mtstat; + size_t tailsz; + intgen_t rval; + bool_t ok; + + /* assert protocol being followed. + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( ! contextp->dc_ownedp ); + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: next mark\n" ); + + trycnt = 0; + + if ( contextp->dc_errorpr ) { + goto resetring; + } else { + goto noerrorsearch; + } + +noerrorsearch: + for ( ; ; ) { + rval = getrec( drivep ); + if ( rval == DRIVE_ERROR_CORRUPTION ) { + goto resetring; + } else if ( rval ) { + return rval; + } + rechdrp = ( rec_hdr_t * )contextp->dc_recp; + + ASSERT( rechdrp->first_mark_offset != 0 ); + if ( rechdrp->first_mark_offset > 0 ) { + off64_t markoff = rechdrp->first_mark_offset + - + rechdrp->file_offset; + off64_t curoff = ( off64_t )( contextp->dc_nextp + - + contextp->dc_recp ); + ASSERT( markoff > 0 ); + ASSERT( curoff > 0 ); + if ( markoff >= curoff ) { + break; + } + } + + if ( ! contextp->dc_singlethreadedpr ) { + Ring_put( contextp->dc_ringp, + contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_recp = 0; + contextp->dc_reccnt++; + } + + ASSERT( rechdrp->first_mark_offset - rechdrp->file_offset + <= + ( off64_t )tape_recsz ); + contextp->dc_nextp = contextp->dc_recp + + + ( size_t )( rechdrp->first_mark_offset + - + rechdrp->file_offset ); + ASSERT( contextp->dc_nextp <= contextp->dc_dataendp ); + ASSERT( contextp->dc_nextp >= contextp->dc_recp + STAPE_HDR_SZ ); + if ( contextp->dc_nextp == contextp->dc_dataendp ) { + if ( ! contextp->dc_singlethreadedpr ) { + Ring_put( contextp->dc_ringp, + contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_recp = 0; + contextp->dc_reccnt++; + } + + return 0; + +resetring: + if ( ! contextp->dc_singlethreadedpr ) { + Ring_reset( contextp->dc_ringp, contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_recp = 0; + + /* get a record buffer and cast a record header pointer + */ + if ( contextp->dc_singlethreadedpr ) { + contextp->dc_recp = contextp->dc_bufp; + } else { + contextp->dc_msgp = Ring_get( contextp->dc_ringp ); + ASSERT( contextp->dc_msgp->rm_stat == RING_STAT_INIT ); + contextp->dc_recp = contextp->dc_msgp->rm_bufp; + } + rechdrp = ( rec_hdr_t * )contextp->dc_recp; + goto readrecord; + +readrecord: + trycnt++; + if ( trycnt > maxtrycnt ) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "unable to locate next mark in media file\n" ); + return DRIVE_ERROR_MEDIA; + } + + nread = Read( drivep, contextp->dc_recp, tape_recsz, &saved_errno ); + goto validateread; + +validateread: + if ( nread == ( intgen_t )tape_recsz ) { + goto validatehdr; + } + ok = mt_get_status( drivep, &mtstat ); + if ( ! ok ) { + status_failed_message( drivep ); + return DRIVE_ERROR_DEVICE; + } + + if ( IS_FMK( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "encountered EOF attempting to read record\n" ); + return DRIVE_ERROR_EOF; + } + + if ( IS_EOD( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "encountered EOD attempting to read record\n" ); + return DRIVE_ERROR_EOD; + } + + if ( IS_EOT( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "encountered EOM attempting to read record\n" ); + return DRIVE_ERROR_EOM; + } + + if ( IS_EW( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "encountered EW attempting to read record\n" ); + return DRIVE_ERROR_EOM; + } + + if ( nread >= 0 ) { + ASSERT( ( size_t )nread <= tape_recsz ); + mlog( MLOG_DEBUG | MLOG_DRIVE, + "short read (nread == %d, record size == %d)\n", + nread, + tape_recsz ); + goto getbeyonderror; + } + + /* some other error + */ + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "unexpected error attempting to read record: " + "read returns %d, errno %d (%s)\n", + nread, + errno, + strerror( errno )); + + goto getbeyonderror; + +validatehdr: + rval = record_hdr_validate( drivep, contextp->dc_recp, BOOL_FALSE ); + + if ( rval + && + ( contextp->dc_isQICpr == BOOL_TRUE + || + contextp->dc_isQICpr == BOOL_UNKNOWN )) { + goto huntQIC; + } + + if ( rval ) { + goto readrecord; + } + + contextp->dc_reccnt = rechdrp->file_offset / ( off64_t )tape_recsz; + contextp->dc_iocnt = contextp->dc_reccnt + 1; + if ( rechdrp->first_mark_offset < 0 ) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "valid record %lld but no mark\n", + contextp->dc_iocnt - 1 ); + goto readrecord; + } + + ASSERT( ! ( rechdrp->file_offset % ( off64_t )tape_recsz )); + markoff = rechdrp->first_mark_offset - rechdrp->file_offset; + ASSERT( markoff >= ( off64_t )STAPE_HDR_SZ ); + ASSERT( markoff < ( off64_t )tape_recsz ); + ASSERT( rechdrp->rec_used > STAPE_HDR_SZ ); + ASSERT( rechdrp->rec_used < tape_recsz ); + + goto alliswell; + +alliswell: + contextp->dc_nextp = contextp->dc_recp + ( size_t )markoff; + ASSERT( ! ( rechdrp->file_offset % ( off64_t )tape_recsz )); + contextp->dc_reccnt = rechdrp->file_offset / ( off64_t )tape_recsz; + contextp->dc_iocnt = contextp->dc_reccnt + 1; + contextp->dc_recendp = contextp->dc_recp + tape_recsz; + contextp->dc_dataendp = contextp->dc_recp + rechdrp->rec_used; + ASSERT( contextp->dc_dataendp <= contextp->dc_recendp ); + ASSERT( contextp->dc_nextp < contextp->dc_dataendp ); + contextp->dc_errorpr = BOOL_FALSE; + + mlog( MLOG_NORMAL | MLOG_DRIVE, + "resynchronized at record %lld " + "offset %u\n", + contextp->dc_iocnt - 1, + contextp->dc_nextp + - + contextp->dc_recp ); + return 0; + +getbeyonderror: + rval = mt_op( contextp->dc_fd, MTFSR, 1 ); + saved_errno = errno; + + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "could not forward space one tape block beyond " + "read error: rval == %d, errno == %d (%s)\n", + rval, + saved_errno, + strerror( saved_errno )); + return DRIVE_ERROR_MEDIA; + } + + goto readrecord; + +huntQIC: + /* we have a full tape_recsz record. look for the magic number at the + * beginning of each 512 byte block. If we find one, shift that and + * the following blocks to the head of the record buffer, and try + * to read the remaining blocks in the record. + */ + for ( p = contextp->dc_recp + QIC_BLKSZ + ; + p < contextp->dc_recendp + ; + p += QIC_BLKSZ ) { + if ( *( u_int64_t * )p == STAPE_MAGIC ) { + goto adjustQIC; + } + } + + goto readrecord; + +adjustQIC: + tailsz = ( size_t )( contextp->dc_recendp - p ); + memcpy( ( void * )contextp->dc_recp, + ( void * )p, + tailsz ); + nread = Read( drivep, + contextp->dc_recp + tailsz, + tape_recsz - tailsz, + &saved_errno ); + + goto validateread; +} + +/* do_end_read + * Discard any buffered reads. + * Tell the reader/writer process to wait. + * + * RETURNS: + * void + */ +static void +do_end_read( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: end read\n" ); + + /* assert protocol being followed + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_ownedp ); + + if ( ! contextp->dc_singlethreadedpr ) { + Ring_reset( contextp->dc_ringp, contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + + contextp->dc_recp = 0; + contextp->dc_mode = OM_NONE; +} + +/* do_begin_write + * prepare drive for writing. set up drive context. write a header record. + * + * RETURNS: + * 0 on success + * DRIVE_ERROR_... on failure + */ +static intgen_t +do_begin_write( drive_t *drivep ) +{ + drive_context_t *contextp; + drive_hdr_t *dwhdrp; + global_hdr_t *gwhdrp; + rec_hdr_t *tpwhdrp; + rec_hdr_t rechdr; + rec_hdr_t *rechdrp = &rechdr; + mtstat_t mtstat; + intgen_t rval; + media_hdr_t *mwhdrp; + content_hdr_t *ch; + content_inode_hdr_t *cih; + + global_hdr_t *tmpgh; + drive_hdr_t *tmpdh; + media_hdr_t *tmpmh; + rec_hdr_t *tmprh; + content_hdr_t *tmpch; + content_inode_hdr_t *tmpcih; + + /* get drive context + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: begin write\n" ); + + /* verify protocol being followed + */ + ASSERT( contextp->dc_mode == OM_NONE ); + ASSERT( ! drivep->d_markrecheadp ); + ASSERT( ! contextp->dc_recp ); + + /* get pointers into global write header + */ + gwhdrp = drivep->d_gwritehdrp; + dwhdrp = drivep->d_writehdrp; + tpwhdrp = ( rec_hdr_t * )dwhdrp->dh_specific; + + /* must already be open. The only way to open is to do a begin_read. + * so all interaction with scsi tape requires reading first. + */ + ASSERT( contextp->dc_fd != -1 ); + + /* get tape device status. verify tape is positioned + */ + if ( ! mt_get_status( drivep, &mtstat )) { + status_failed_message( drivep ); + return DRIVE_ERROR_DEVICE; + } + if ( IS_EOT( mtstat )) { + return DRIVE_ERROR_EOM; + } + if ( IS_EW( mtstat ) && !(IS_BOT(mtstat)) ) { + return DRIVE_ERROR_EOM; + } + + /* fill in write header's drive specific info + */ + tpwhdrp->magic = STAPE_MAGIC; + tpwhdrp->version = STAPE_VERSION; + tpwhdrp->blksize = ( int32_t )tape_blksz; + tpwhdrp->recsize = ( int32_t )tape_recsz; + tpwhdrp->rec_used = 0; + tpwhdrp->file_offset = 0; + tpwhdrp->first_mark_offset= 0; + tpwhdrp->capability = drivep->d_capabilities; + + /* get a record buffer. will be used for the media file header, + * and is needed to "prime the pump" for first call to do_write. + */ + ASSERT( ! contextp->dc_recp ); + if ( contextp->dc_singlethreadedpr ) { + ASSERT( contextp->dc_bufp ); + contextp->dc_recp = contextp->dc_bufp; + } else { + ASSERT( contextp->dc_ringp ); + ASSERT( ! contextp->dc_msgp ); + contextp->dc_msgp = Ring_get( contextp->dc_ringp ); + ASSERT( contextp->dc_msgp->rm_stat == RING_STAT_INIT ); + contextp->dc_recp = contextp->dc_msgp->rm_bufp; + } + + /* write the record. be sure to prevent a record checksum from + * being produced! + */ + contextp->dc_iocnt = 0; + memset( ( void * )contextp->dc_recp, 0, tape_recsz ); + + tmpgh = (global_hdr_t *)contextp->dc_recp; + tmpdh = (drive_hdr_t *)tmpgh->gh_upper; + tmpmh = (media_hdr_t *)tmpdh->dh_upper; + tmprh = (rec_hdr_t *)tmpdh->dh_specific; + tmpch = (content_hdr_t *)tmpmh->mh_upper; + tmpcih = (content_inode_hdr_t *)tmpch->ch_specific; + + mwhdrp = (media_hdr_t *)dwhdrp->dh_upper; + ch = (content_hdr_t *)mwhdrp->mh_upper; + cih = (content_inode_hdr_t *)ch->ch_specific; + + xlate_global_hdr(gwhdrp, tmpgh, 1); + xlate_drive_hdr(dwhdrp, tmpdh, 1); + xlate_media_hdr(mwhdrp, tmpmh, 1); + xlate_content_hdr(ch, tmpch, 1); + xlate_content_inode_hdr(cih, tmpcih, 1); + xlate_rec_hdr(tpwhdrp, tmprh, 1); + + /* checksum the global header + */ + global_hdr_checksum_set( tmpgh ); + + rval = write_record( drivep, contextp->dc_recp, BOOL_TRUE ); + if ( rval ) { + if ( ! contextp->dc_singlethreadedpr ) { + Ring_reset( contextp->dc_ringp, contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_recp = 0; + return rval; + } + + /* prepare the drive context. must have a record buffer ready to + * go, header initialized. + */ + ASSERT( ! contextp->dc_ownedp ); + contextp->dc_reccnt = 1; /* count the header record */ + contextp->dc_recendp = contextp->dc_recp + tape_recsz; + contextp->dc_nextp = contextp->dc_recp + STAPE_HDR_SZ; + + /* intialize header in new record + */ + rechdrp->magic = STAPE_MAGIC; + rechdrp->version = STAPE_VERSION; + rechdrp->file_offset = contextp->dc_reccnt * ( off64_t )tape_recsz; + rechdrp->blksize = ( int32_t )tape_blksz; + rechdrp->recsize = ( int32_t )tape_recsz; + rechdrp->capability = drivep->d_capabilities; + rechdrp->first_mark_offset = -1LL; + uuid_copy( rechdrp->dump_uuid, gwhdrp->gh_dumpid ); + + xlate_rec_hdr(rechdrp, ( rec_hdr_t * )contextp->dc_recp, 1); + /* set mode now so operators will work + */ + contextp->dc_mode = OM_WRITE; + + contextp->dc_errorpr = BOOL_FALSE; + + return 0; +} + +/* do_set_mark - queue a mark request. if first mark set in record, record + * in record. + */ +static void +do_set_mark( drive_t *drivep, + drive_mcbfp_t cbfuncp, + void *cbcontextp, + drive_markrec_t *markrecp ) +{ + drive_context_t *contextp; + off64_t nextoff; + rec_hdr_t *rechdrp; + + /* get drive context + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + /* verify protocol being followed + */ + ASSERT( contextp->dc_mode == OM_WRITE ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( ! contextp->dc_ownedp ); + ASSERT( contextp->dc_recp ); + ASSERT( contextp->dc_nextp ); + + /* calculate and fill in the mark record offset + */ + ASSERT( contextp->dc_recp ); + nextoff = contextp->dc_reccnt * ( off64_t )tape_recsz + + + ( off64_t )( contextp->dc_nextp - contextp->dc_recp ); + markrecp->dm_log = ( drive_mark_t )nextoff; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: set mark: %lld (0x%llx)\n", + nextoff, + nextoff ); + + /* note the location of the first mark in this tape record. + */ + rechdrp = ( rec_hdr_t * )contextp->dc_recp; + if ( rechdrp->first_mark_offset == -1LL ) { + ASSERT( nextoff != -1LL ); + rechdrp->first_mark_offset = nextoff; + } + + /* put the mark on the tail of the queue. + */ + markrecp->dm_cbfuncp = cbfuncp; + markrecp->dm_cbcontextp = cbcontextp; + markrecp->dm_nextp = 0; + if ( drivep->d_markrecheadp == 0 ) { + drivep->d_markrecheadp = markrecp; + drivep->d_markrectailp = markrecp; + } else { + ASSERT( drivep->d_markrectailp ); + drivep->d_markrectailp->dm_nextp = markrecp; + drivep->d_markrectailp = markrecp; + } +} + +/* do_get_write_buf - supply the caller with some or all of the current record + * buffer. the supplied buffer must be fully returned (via a single call to + * do_write) prior to the next call to do_get_write_buf. + * + * RETURNS: + * the address of a buffer + * "actual_bufszp" points to the size of the buffer + */ +static char * +do_get_write_buf( drive_t *drivep, size_t wantedcnt, size_t *actualcntp ) +{ + drive_context_t *contextp; + size_t remainingcnt; + size_t actualcnt; + + /* get drive context + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + /* verify protocol being followed + */ + ASSERT( contextp->dc_mode == OM_WRITE ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( ! contextp->dc_ownedp ); + ASSERT( contextp->dc_recp ); + ASSERT( contextp->dc_nextp ); + ASSERT( contextp->dc_nextp < contextp->dc_recendp ); + + /* figure how much is available; supply the min of what is + * available and what is wanted. + */ + remainingcnt = ( size_t )( contextp->dc_recendp - contextp->dc_nextp ); + actualcnt = min( remainingcnt, wantedcnt ); + *actualcntp = actualcnt; + contextp->dc_ownedp = contextp->dc_nextp; + contextp->dc_nextp += actualcnt; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: get write buf: wanted %u (0x%x) actual %u (0x%x)\n", + wantedcnt, + wantedcnt, + actualcnt, + actualcnt ); + + return contextp->dc_ownedp; +} + +/* do_write - accept ownership of the portion of the current record buffer + * being returned by the caller. if returned portion includes end of record + * buffer, write the buffer and get and prepare a new one in anticipation of + * the next call to do_get_write_buf. also, process any queued marks which + * are guaranteed to be committed to media. NOTE: the caller must return + * everything obtained with the preceeding call to do_get_write_buf. + * + * RETURNS: + * 0 on success + * non 0 on error + */ +/* ARGSUSED */ +static intgen_t +do_write( drive_t *drivep, char *bufp, size_t retcnt ) +{ + drive_context_t *contextp; + rec_hdr_t rechdr; + rec_hdr_t *rechdrp = &rechdr; + global_hdr_t *gwhdrp; + size_t heldcnt; + off64_t last_rec_wrtn_wo_err; /* zero-based index */ + intgen_t rval; + + /* get drive context and pointer to global write hdr + */ + contextp = ( drive_context_t * )drivep->d_contextp; + gwhdrp = drivep->d_gwritehdrp; + + /* calculate how many bytes we believe caller is holding + */ + heldcnt = ( size_t )( contextp->dc_nextp - contextp->dc_ownedp ); + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: write: retcnt %u (0x%x) heldcnt %u (0x%x)\n", + retcnt, + retcnt, + heldcnt, + heldcnt ); + + /* verify protocol being followed + */ + ASSERT( contextp->dc_mode == OM_WRITE ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( contextp->dc_ownedp ); + ASSERT( contextp->dc_recp ); + ASSERT( contextp->dc_nextp ); + ASSERT( contextp->dc_nextp <= contextp->dc_recendp ); + + /* verify the caller is returning exactly what is held + */ + ASSERT( bufp == contextp->dc_ownedp ); + ASSERT( retcnt == heldcnt ); + + /* take it back + */ + contextp->dc_ownedp = 0; + + /* if some portion of the record buffer has not yet been + * held by the client, just return. + */ + if ( contextp->dc_nextp < contextp->dc_recendp ) { + return 0; + } + + /* record in record header that entire record is used + */ + rechdrp = ( rec_hdr_t * )contextp->dc_recp; + INT_SET(rechdrp->rec_used, ARCH_CONVERT, tape_recsz); + + /* write out the record buffer and get a new one. + */ + if ( contextp->dc_singlethreadedpr ) { + rval = write_record( drivep, contextp->dc_recp, BOOL_TRUE ); + last_rec_wrtn_wo_err = contextp->dc_reccnt; /* conv cnt to ix */ + } else { + contextp->dc_msgp->rm_op = RING_OP_WRITE; + contextp->dc_msgp->rm_user = contextp->dc_reccnt; + Ring_put( contextp->dc_ringp, + contextp->dc_msgp ); + contextp->dc_msgp = 0; + contextp->dc_msgp = Ring_get( contextp->dc_ringp ); + contextp->dc_recp = contextp->dc_msgp->rm_bufp; + last_rec_wrtn_wo_err = contextp->dc_msgp->rm_user; + switch( contextp->dc_msgp->rm_stat ) { + case RING_STAT_OK: + case RING_STAT_INIT: + rval = 0; + break; + case RING_STAT_ERROR: + rval = contextp->dc_msgp->rm_rval; + break; + default: + ASSERT( 0 ); + return DRIVE_ERROR_CORE; + } + } + + /* check for errors. if none, commit all marks before a safety margin + * before the no error offset. + */ + if ( rval ) { + contextp->dc_errorpr = BOOL_TRUE; + } else { + off64_t recs_wrtn_wo_err; + off64_t recs_committed; + off64_t bytes_committed; + recs_wrtn_wo_err = last_rec_wrtn_wo_err + 1; + recs_committed = recs_wrtn_wo_err - contextp->dc_lostrecmax; + bytes_committed = recs_committed * ( off64_t )tape_recsz; + drive_mark_commit( drivep, bytes_committed ); + } + + /* adjust context + */ + contextp->dc_reccnt++; + contextp->dc_recendp = contextp->dc_recp + tape_recsz; + contextp->dc_nextp = contextp->dc_recp + + + STAPE_HDR_SZ; + + /* intialize header in new record + */ + rechdrp = &rechdr; + rechdrp->magic = STAPE_MAGIC; + rechdrp->version = STAPE_VERSION; + rechdrp->file_offset = contextp->dc_reccnt * ( off64_t )tape_recsz; + rechdrp->blksize = ( int32_t )tape_blksz; + rechdrp->recsize = ( int32_t )tape_recsz; + rechdrp->capability = drivep->d_capabilities; + rechdrp->first_mark_offset = -1LL; + uuid_copy( rechdrp->dump_uuid, gwhdrp->gh_dumpid ); + xlate_rec_hdr(rechdrp, ( rec_hdr_t * )contextp->dc_recp, 1); + + return rval; +} + +/* do_get_align_cnt - + * Returns the number of bytes which must be written to + * cause the next call to get_write_buf() to be page-aligned. + * + * RETURNS: + * the number of bytes to next alignment + */ +static size_t +do_get_align_cnt( drive_t * drivep ) +{ + char *next_alignment_point; + __psint_t next_alignment_off; + drive_context_t *contextp; + + contextp = ( drive_context_t * )drivep->d_contextp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: get align cnt\n" ); + + /* verify protocol being followed + */ + ASSERT( contextp->dc_mode == OM_WRITE ); + ASSERT( ! contextp->dc_errorpr ); + ASSERT( ! contextp->dc_ownedp ); + ASSERT( contextp->dc_recp ); + ASSERT( contextp->dc_nextp ); + ASSERT( contextp->dc_nextp < contextp->dc_recendp ); + + /* calculate the next alignment point at or beyond the current nextp. + * the following algorithm works because all buffers are page-aligned + * and a multiple of PGSZ. + */ + next_alignment_off = ( __psint_t )contextp->dc_nextp; + next_alignment_off += PGMASK; + next_alignment_off &= ~PGMASK; + next_alignment_point = ( char * )next_alignment_off; + ASSERT( next_alignment_point <= contextp->dc_recendp ); + + /* return the number of bytes to the next alignment offset + */ + ASSERT( next_alignment_point >= contextp->dc_nextp ); + return ( size_t )( next_alignment_point - contextp->dc_nextp ); +} + +/* do_end_write - pad and write pending record if any client data in it. + * flush all pending writes. write a file mark. figure how many records are + * guaranteed to be on media, and commit/discard marks accordingly. + * RETURNS: + * 0 on success + * DRIVE_ERROR_* on failure + */ +static intgen_t +do_end_write( drive_t *drivep, off64_t *ncommittedp ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + off64_t first_rec_w_err; /* zero-based index */ + off64_t recs_wtn_wo_err; + off64_t recs_guaranteed; + off64_t bytes_committed; + + intgen_t rval; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: end write\n" ); + + /* verify protocol being followed + */ + ASSERT( contextp->dc_mode == OM_WRITE ); + ASSERT( ! contextp->dc_ownedp ); + ASSERT( contextp->dc_recp ); + ASSERT( contextp->dc_nextp ); + ASSERT( contextp->dc_nextp >= contextp->dc_recp + STAPE_HDR_SZ ); + ASSERT( contextp->dc_nextp < contextp->dc_recendp ); + + /* pre-initialize return of count of bytes committed to media + */ + *ncommittedp = 0; + + /* if in error mode, a write error occured earlier. don't bother + * to do anymore writes, just cleanup and return 0. don't need to + * do commits, already done when error occured. + */ + if ( contextp->dc_errorpr ) { + if ( ! contextp->dc_singlethreadedpr ) { + Ring_reset( contextp->dc_ringp, contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_mode = OM_NONE; + drive_mark_discard( drivep ); + *ncommittedp = ( contextp->dc_iocnt - contextp->dc_lostrecmax ) + * + ( off64_t )tape_recsz; + contextp->dc_recp = 0; + return 0; + } + + /* if any user data in current record buffer, send it out. + */ + if ( contextp->dc_nextp > contextp->dc_recp + STAPE_HDR_SZ ) { + rec_hdr_t *rechdrp; + size_t bufusedcnt; + + rechdrp = ( rec_hdr_t * )contextp->dc_recp; + bufusedcnt = ( size_t )( contextp->dc_nextp + - + contextp->dc_recp ); + INT_SET(rechdrp->rec_used, ARCH_CONVERT, bufusedcnt); + mlog( MLOG_DEBUG | MLOG_DRIVE, + "writing padded last record\n" ); + if ( contextp->dc_singlethreadedpr ) { + rval = write_record( drivep, + contextp->dc_recp, + BOOL_TRUE ); + } else { + ASSERT( contextp->dc_msgp ); + contextp->dc_msgp->rm_op = RING_OP_WRITE; + contextp->dc_msgp->rm_user = contextp->dc_reccnt; + Ring_put( contextp->dc_ringp, + contextp->dc_msgp ); + contextp->dc_msgp = 0; + contextp->dc_msgp = Ring_get( contextp->dc_ringp ); + switch( contextp->dc_msgp->rm_stat ) { + case RING_STAT_OK: + case RING_STAT_INIT: + rval = 0; + break; + case RING_STAT_ERROR: + rval = contextp->dc_msgp->rm_rval; + break; + default: + ASSERT( 0 ); + contextp->dc_recp = 0; + return DRIVE_ERROR_CORE; + } + } + contextp->dc_reccnt++; + } else { + rval = 0; + } + + /* now flush the ring until error or tracer bullet seen. + * note the record index in the first msg received with + * an error indication. this will be used to calculate + * the number of records guaranteed to have made it onto + * media, and that will be used to select which marks + * to commit and which to discard. + */ + if ( rval ) { + first_rec_w_err = contextp->dc_iocnt; + /* because dc_iocnt bumped by write_record + * only if no error + */ + } else { + first_rec_w_err = -1L; + } + if ( ! contextp->dc_singlethreadedpr ) { + while ( ! rval ) { + ASSERT( contextp->dc_msgp ); + contextp->dc_msgp->rm_op = RING_OP_TRACE; + Ring_put( contextp->dc_ringp, + contextp->dc_msgp ); + contextp->dc_msgp = 0; + contextp->dc_msgp = Ring_get( contextp->dc_ringp ); + if ( contextp->dc_msgp->rm_op == RING_OP_TRACE ) { + break; + } + switch( contextp->dc_msgp->rm_stat ) { + case RING_STAT_OK: + case RING_STAT_INIT: + ASSERT( rval == 0 ); + break; + case RING_STAT_ERROR: + rval = contextp->dc_msgp->rm_rval; + first_rec_w_err = contextp->dc_msgp->rm_user; + break; + default: + ASSERT( 0 ); + contextp->dc_recp = 0; + return DRIVE_ERROR_CORE; + } + } + } + + /* the ring is now flushed. reset + */ + if ( ! contextp->dc_singlethreadedpr ) { + Ring_reset( contextp->dc_ringp, contextp->dc_msgp ); + contextp->dc_msgp = 0; + } + contextp->dc_recp = 0; + + /* if no error so far, write a file mark. this will have the + * side-effect of flushing the driver/drive of pending writes, + * exposing any write errors. + */ + if ( ! rval ) { + intgen_t weofrval; + mtstat_t mtstat; + bool_t ok; + + weofrval = mt_op( contextp->dc_fd, MTWEOF, 1 ); + if ( ! weofrval ) { + ok = mt_get_status( drivep, &mtstat ); + if ( ! ok ) { + status_failed_message( drivep ); + mtstat = 0; + rval = DRIVE_ERROR_DEVICE; + } + } else { + mtstat = 0; + mlog( MLOG_DEBUG | MLOG_DRIVE, + "MTWEOF returned %d: errno == %d (%s)\n", + weofrval, + errno, + strerror( errno )); + } + if ( weofrval || IS_EW( mtstat ) || IS_EOT( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "hit EOM trying to write file mark\n" ); + rval = DRIVE_ERROR_EOM; + } + } + + /* if an error occured, first_rec_w_err now contains + * the count of records written without error, all of which + * were full records. subtract from this dc_lostrecmax, + * and we have the number of records guaranteed to have made + * it to media. + * + * if no errors have occured, all I/O has been committed. + * we can use dc_iocnt, which is the count of records actually + * written without error. + * + * commit marks contained in committed records, discard the rest, + * and return rval. return by reference the number of bytes committed + * to tape. + */ + if ( rval ) { + ASSERT( first_rec_w_err >= 0 ); + recs_wtn_wo_err = first_rec_w_err; + recs_guaranteed = recs_wtn_wo_err - contextp->dc_lostrecmax; + } else { + ASSERT( first_rec_w_err == -1 ); + recs_wtn_wo_err = contextp->dc_iocnt; + recs_guaranteed = recs_wtn_wo_err; + } + bytes_committed = recs_guaranteed * ( off64_t )tape_recsz; + drive_mark_commit( drivep, bytes_committed ); + drive_mark_discard( drivep ); + contextp->dc_mode = OM_NONE; + *ncommittedp = bytes_committed; + return rval; +} + +/* do_fsf + * Advance the tape by count files. + * + * RETURNS: + * number of media files skipped + * *statp set to zero or DRIVE_ERROR_... + */ +static intgen_t +do_fsf( drive_t *drivep, intgen_t count, intgen_t *statp ) +{ + int i, done, op_failed, opcount; + mtstat_t mtstat; + drive_context_t *contextp; + + /* get drive context + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + /* verify protocol being followed + */ + ASSERT( contextp->dc_mode == OM_NONE ); + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: fsf: count %d\n", + count ); + + ASSERT( count ); + ASSERT( contextp->dc_mode == OM_NONE ); + + /* get tape status + */ + if ( ! mt_get_status( drivep, &mtstat) ) { + status_failed_message( drivep ); + *statp = DRIVE_ERROR_DEVICE; + return 0; + } + + for ( i = 0 ; i < count; i++ ) { + done = 0; + opcount = 2; + + /* the tape may encounter errors will trying to + * reach the next file. + */ + while ( !done ) { + /* check for end-of-data and end-of-tape conditions + */ + if ( IS_EOT( mtstat ) ) { + *statp = DRIVE_ERROR_EOM; + return i; + + } else if ( IS_EOD( mtstat ) ) { + *statp = DRIVE_ERROR_EOD; + return i; + } + + /* advance the tape to the next file mark + * NOTE: + * ignore return code + */ + mlog( MLOG_VERBOSE | MLOG_DRIVE, + "advancing tape to next media file\n"); + + op_failed = 0; + ASSERT( contextp->dc_fd >= 0 ); + if ( mt_op( contextp->dc_fd, MTFSF, 1 ) ) { + op_failed = 1; + } + + if ( ! mt_get_status( drivep, &mtstat) ) { + status_failed_message( drivep ); + *statp = DRIVE_ERROR_DEVICE; + return i; + } + + /* Check for a file mark to + * determine if the fsf command worked. + */ + if ( (!op_failed) && (IS_FMK(mtstat)) ) { + done = 1; + } + + /* If the FSF command has been issued multiple + * times, and a file mark has not been reached, + * return an error. + */ + if ( --opcount < 0 ) { + mlog( MLOG_VERBOSE | MLOG_DRIVE, + "FSF tape command failed\n"); + + *statp = DRIVE_ERROR_DEVICE; + return i; + } + } + } + + return count; +} + +/* do_bsf + * Backup the tape by count files. zero means just back up to the beginning + * of the last media file read or written. + * + * RETURNS: + * number of media files skipped + * *statp set to zero or DRIVE_ERROR_... + */ +static intgen_t +do_bsf( drive_t *drivep, intgen_t count, intgen_t *statp ) +{ +#ifdef DEBUG + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; +#endif + intgen_t skipped; + mtstat_t mtstat; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: bsf: count %d\n", + count ); + + ASSERT( contextp->dc_mode == OM_NONE ); + + *statp = 0; + + /* first move to the left of the last file mark. + * if BOT encountered, return 0. also check for + * being at BOT or file mark and count == 0: no motion needed + */ + + /* get tape status + */ + if ( ! mt_get_status( drivep, &mtstat )) { + status_failed_message( drivep ); + *statp = DRIVE_ERROR_DEVICE; + return 0; + } + + /* check for beginning-of-tape condition. close/reopen hack here + */ + if ( IS_BOT( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "reopening drive while at BOT\n" ); + Close( drivep ); + if ( ! Open( drivep )) { + display_access_failed_message( drivep ); + *statp = DRIVE_ERROR_DEVICE; + return 0; + } + if ( ! mt_get_status( drivep, &mtstat )) { + status_failed_message( drivep ); + *statp = DRIVE_ERROR_DEVICE; + return 0; + } + ASSERT( IS_BOT(mtstat )); + + + *statp = DRIVE_ERROR_BOM; + return 0; + } + + /* check if already at (and to right of) file mark and + * count is zero. + */ + if ( IS_FMK( mtstat ) && count == 0 ) { + return 0; + } + + /* back space - places us to left of previous file mark + */ + ASSERT( drivep->d_capabilities & DRIVE_CAP_BSF ); + mtstat = bsf_and_verify( drivep ); + + /* check again for beginning-of-tape condition + */ + if ( IS_BOT( mtstat )) { + *statp = DRIVE_ERROR_BOM; + return 0; + } + +#ifdef HAVE_2WAYFMK + /* should be to the left of a file mark. drive status indicates + * file mark whether to left or right. + * THIS IS TRUE IN IRIX, BUT NOT IN LINUX ! + * IN LINUX, GMT_EOF only happens to the right of the filemark. + */ + if ( ! IS_FMK( mtstat )) { + *statp = DRIVE_ERROR_DEVICE; + return 0; + } +#endif + + /* now loop, skipping media files + */ + for ( skipped = 0 ; skipped < count ; skipped++ ) { + + /* move to the left of the next file mark on the left. + * check for BOT. + */ + mtstat = bsf_and_verify( drivep ); + if ( IS_BOT( mtstat )) { + *statp = DRIVE_ERROR_BOM; + return skipped + 1; + } +#ifdef HAVE_2WAYFMK + if ( ! IS_FMK( mtstat )) { + *statp = DRIVE_ERROR_DEVICE; + return 0; + } +#endif + } + + /* finally, move to the right side of the file mark + */ + mtstat = fsf_and_verify( drivep ); + if( IS_EOT( mtstat )) { + *statp = DRIVE_ERROR_EOM; + } + if ( ! IS_FMK( mtstat )) { + *statp = DRIVE_ERROR_DEVICE; + } + + /* indicate the number of media files skipped + */ + return skipped; +} + +/* do_rewind + * Position the tape at the beginning of the recorded media. + * + * RETURNS: + * 0 on sucess + * DRIVE_ERROR_* on failure + */ +static intgen_t +do_rewind( drive_t *drivep ) +{ +#ifdef DEBUG + drive_context_t *contextp = (drive_context_t *)drivep->d_contextp; +#endif + mtstat_t mtstat; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: rewind\n" ); + + ASSERT( contextp->dc_mode == OM_NONE ); + ASSERT( contextp->dc_fd >= 0 ); + + /* use validating tape rewind util func + */ + mtstat = rewind_and_verify( drivep ); + if ( ! IS_BOT( mtstat )) { + return DRIVE_ERROR_DEVICE; + } else { + return 0; + } +} + +/* do_erase + * erase media from beginning + * + * RETURNS: + * 0 on sucess + * DRIVE_ERROR_* on failure + */ +static intgen_t +do_erase( drive_t *drivep ) +{ +#ifdef DEBUG + drive_context_t *contextp = (drive_context_t *)drivep->d_contextp; +#endif + mtstat_t mtstat; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: erase\n" ); + + ASSERT( contextp->dc_mode == OM_NONE ); + ASSERT( contextp->dc_fd >= 0 ); + + /* use validating tape rewind util func + */ + mtstat = rewind_and_verify( drivep ); + if ( ! IS_BOT( mtstat )) { + return DRIVE_ERROR_DEVICE; + } + + /* use validating tape erase util func + */ + ( void )erase_and_verify( drivep ); + + /* rewind again + */ + mtstat = rewind_and_verify( drivep ); + if ( ! IS_BOT( mtstat )) { + return DRIVE_ERROR_DEVICE; + } + + /* close the drive so we start from scratch + */ + Close( drivep ); + return 0; +} + +/* do_eject + * pop the tape out - may be a nop on some drives + * + * RETURNS: + * 0 on sucess + * DRIVE_ERROR_DEVICE on failure + */ +static intgen_t +do_eject_media( drive_t *drivep ) +{ + drive_context_t *contextp = (drive_context_t *)drivep->d_contextp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: eject media\n" ); + + /* drive must be open + */ + ASSERT( contextp->dc_fd >= 0 ); + ASSERT( contextp->dc_mode == OM_NONE ); + + /* issue tape unload + */ + if ( contextp->dc_unloadokpr ) { + ( void )mt_op( contextp->dc_fd, MTUNLOAD, 0 ); + } + + /* close the device driver + */ + Close( drivep ); + + return 0; +} + +/* do_get_device_class + * Return the device class + * + * RETURNS: + * always returns DEVICE_TAPE_REMOVABLE + */ +/* ARGSUSED */ +static intgen_t +do_get_device_class( drive_t *drivep) +{ + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: get device class\n" ); + + return DEVICE_TAPE_REMOVABLE; +} + +/* do_display_metrics - print ring stats if using I/O ring + */ +static void +do_display_metrics( drive_t *drivep ) +{ + drive_context_t *contextp = (drive_context_t *)drivep->d_contextp; + ring_t *ringp = contextp->dc_ringp; + + if ( ringp ) { + if ( drivecnt > 1 ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_DRIVE, + "drive %u ", + drivep->d_index ); + } + display_ring_metrics( drivep, + MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK ); + } +} + +/* do_quit + */ +static void +do_quit( drive_t *drivep ) +{ + drive_context_t *contextp = (drive_context_t *)drivep->d_contextp; + ring_t *ringp = contextp->dc_ringp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op: quit\n" ); + + /* print the ring metrics and kill the ring + */ + if ( ringp ) { + display_ring_metrics( drivep, MLOG_VERBOSE ); + + /* tell slave to die + */ + mlog( (MLOG_NITTY + 1) | MLOG_DRIVE, + "ring op: destroy\n" ); + ring_destroy( ringp ); + } + + if ( ! contextp->dc_isvarpr + && + ! contextp->dc_isQICpr + && + contextp->dc_cansetblkszpr + && + ( contextp->dc_origcurblksz != 0 ) ) { + ( void )set_fixed_blksz( drivep, contextp->dc_origcurblksz ); + } + + /* issue tape unload + */ + if ( contextp->dc_unloadokpr ) { + ( void )mt_op( contextp->dc_fd, MTUNLOAD, 0 ); + } + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "drive op quit complete\n" ); +} + +static double +percent64( off64_t num, off64_t denom ) +{ + return ( double )( num * 100 ) / ( double )denom; +} + + +/* read_label + * responsible for reading and validating the first record from a + * media file. can assume that prepare_drive has already been run + * on this tape. if read fails due to an encounter with a file mark, + * end of media, or end of data, position the media to allow an + * append. + * + * RETURNS: + * 0 on success + * DRIVE_ERROR_* on failure + */ + +/* + * Notes for restoring in Linux/IRIX. + * These are the assumption being made about the scsi tape drivers + * in IRIX and Linux. + * The 1st read() below is made prior to calling read_label(). + * The 2nd read() is the one made inside read_label(). + * Extraneous status flags, such as online, are not mentioned. + * + * ----------------------------------------- + * Full tape (incomplete dump - over >1 tapes) + * + * Linux + * read->0 + * read->0 <<<**** caused my problem + * + * IRIX + * read->0 + * read->-1 (ENOSPC) + * ----------------------------------------- + * Partial tape (complete dump - just 1 tape) + * + * Linux + * read->0 + * read->0 + * + * IRIX + * read->0 + * read->-1 (ENOSPC) + * ----------------------------------------- + */ + + +static intgen_t +read_label( drive_t *drivep ) +{ + drive_context_t *contextp; + intgen_t nread; + intgen_t saved_errno; + mtstat_t mtstat; + bool_t wasatbotpr; + intgen_t rval; + bool_t ok; + + /* initialize context ptr + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + /* if not at BOT or a file mark, advance to right of next file mark + */ + ok = mt_get_status( drivep, &mtstat ); + if ( ! ok ) { + status_failed_message( drivep ); + return DRIVE_ERROR_DEVICE; + } + if ( ! IS_BOT( mtstat ) && ! IS_FMK( mtstat )) { + mtstat = fsf_and_verify( drivep ); + } + + /* if we hit EOM or early warning, just return + */ + if ( IS_EOT( mtstat ) || IS_EW( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "begin read hit EOM/EW\n" ); + return DRIVE_ERROR_EOM; + } + + /* if we hit EOD, a file mark is missing + */ + if ( IS_EOD( mtstat )) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "file mark missing from tape (hit EOD)\n" ); +#ifdef DUMP + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "writing file mark at EOD\n" ); + rval = mt_op( contextp->dc_fd, MTWEOF, 1 ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "unable to write file mark at eod: %s (%d)\n", + strerror( errno ), + errno ); + return DRIVE_ERROR_MEDIA; + } + ok = mt_get_status( drivep, &mtstat ); + if ( ! ok ) { + status_failed_message( drivep ); + return DRIVE_ERROR_DEVICE; + } +#endif /* DUMP */ + } + + /* verify we are either at BOT or a file mark + */ + if ( ! IS_BOT( mtstat ) && ! IS_FMK( mtstat )) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "file mark missing from tape\n" ); +#ifdef DUMP + return DRIVE_ERROR_MEDIA; +#endif + } + + /* remember if we were at BOT, so we know how to reposition if EOD + * encountered + */ + if ( IS_BOT( mtstat )) { + wasatbotpr = BOOL_TRUE; + } else { + wasatbotpr = BOOL_FALSE; + } + + /* read the first record of the media file directly + */ + nread = Read( drivep, + contextp->dc_recp, + tape_recsz, + &saved_errno ); + + /* if a read error, get status + */ + if ( nread != ( intgen_t )tape_recsz ) { + ASSERT( nread < ( intgen_t )tape_recsz ); + ok = mt_get_status( drivep, &mtstat ); + if ( ! ok ) { + status_failed_message( drivep ); + return DRIVE_ERROR_DEVICE; + } + } else { + mtstat = 0; + } + + /* check for an unexpected errno + */ + if ( nread < 0 && saved_errno != ENOSPC ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "could not read from drive: %s (%d)\n", + strerror( errno ), + errno ); + return DRIVE_ERROR_DEVICE; + } + + /* check for a blank tape. NOTE: shouldn't get here! + */ + if ( nread == 0 && wasatbotpr ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "unexpectedly encountered EOD at BOT: " + "assuming corrupted media\n" ); + ( void )rewind_and_verify( drivep ); + return DRIVE_ERROR_MEDIA; + } + + /* if we hit end of tape or early warning, indicate EOM + */ + if ( IS_EOT( mtstat ) || IS_EW( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "hit EOM\n" ); + return DRIVE_ERROR_EOM; + } + + +#ifdef DUMP + /* if we hit EOD, re-position in anticipation of appending. + */ + if ( IS_EOD( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "hit EOD: repositioning for append\n" ); + if ( drivep->d_capabilities & DRIVE_CAP_BSF ) { + ( void )bsf_and_verify( drivep ); + } + ( void )fsf_and_verify( drivep ); + return DRIVE_ERROR_EOD; + } +#endif /* DUMP */ +#ifdef RESTORE + + /* Linux case */ + if ( IS_EOD( mtstat ) && IS_FMK( mtstat ) ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "hit EOM\n" ); + return DRIVE_ERROR_EOM; + } + + + if ( IS_EOD( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "hit EOD\n" ); + return DRIVE_ERROR_EOD; + } +#endif /* RESTORE */ + + /* if we hit a file mark, this is very bad. + * indicates the media has been corrupted + */ + if ( IS_FMK( mtstat )) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "unexpectedly encountered a file mark: " + "assuming corrupted media\n" ); + ( void )rewind_and_verify( drivep ); + return DRIVE_ERROR_MEDIA; + } + + /* dc_iocnt is count of number of records read without error + */ + contextp->dc_iocnt = 1; + + rval = validate_media_file_hdr( drivep ); + + return rval; +} + +static intgen_t +validate_media_file_hdr( drive_t *drivep ) +{ + global_hdr_t *grhdrp = drivep->d_greadhdrp; + drive_hdr_t *drhdrp = drivep->d_readhdrp; + rec_hdr_t *tprhdrp = (rec_hdr_t *)drhdrp->dh_specific; + media_hdr_t *mrhdrp = (media_hdr_t *)drhdrp->dh_upper; + content_hdr_t *ch = (content_hdr_t *)mrhdrp->mh_upper; + content_inode_hdr_t *cih = (content_inode_hdr_t *)ch->ch_specific; + drive_context_t *contextp = (drive_context_t *)drivep->d_contextp; + char tmpbuf[GLOBAL_HDR_SZ]; + global_hdr_t *tmpgh = (global_hdr_t *)&tmpbuf[0]; + drive_hdr_t *tmpdh = (drive_hdr_t *)tmpgh->gh_upper; + media_hdr_t *tmpmh = (media_hdr_t *)tmpdh->dh_upper; + rec_hdr_t *tmprh = (rec_hdr_t *)tmpdh->dh_specific; + content_hdr_t *tmpch = (content_hdr_t *)tmpmh->mh_upper; + content_inode_hdr_t *tmpcih = (content_inode_hdr_t *)tmpch->ch_specific; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "validating media file header\n" ); + + memcpy( tmpbuf, contextp->dc_recp, GLOBAL_HDR_SZ ); + + mlog(MLOG_NITTY, "validate_media_file_hdr\n" + "\tgh_magic %.100s\n" + "\tgh_version %u\n" + "\tgh_checksum %u\n" + "\tgh_timestamp %u\n" + "\tgh_ipaddr %llu\n" + "\tgh_hostname %.100s\n" + "\tgh_dumplabel %.100s\n", + tmpgh->gh_magic, + tmpgh->gh_version, + tmpgh->gh_checksum, + tmpgh->gh_timestamp, + tmpgh->gh_ipaddr, + tmpgh->gh_hostname, + tmpgh->gh_dumplabel); + + /* check the checksum + */ + if ( ! global_hdr_checksum_check( tmpgh )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "bad media file header checksum\n"); + return DRIVE_ERROR_CORRUPTION; + } + + if ( ! tape_rec_checksum_check( contextp, contextp->dc_recp )) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "tape record checksum error\n"); + return DRIVE_ERROR_CORRUPTION; + + } + + xlate_global_hdr(tmpgh, grhdrp, 1); + xlate_drive_hdr(tmpdh, drhdrp, 1); + xlate_media_hdr(tmpmh, mrhdrp, 1); + xlate_content_hdr(tmpch, ch, 1); + xlate_content_inode_hdr(tmpcih, cih, 1); + xlate_rec_hdr(tmprh, tprhdrp, 1); + + memcpy( contextp->dc_recp, grhdrp, GLOBAL_HDR_SZ ); + + /* check the magic number + */ + if ( strncmp( grhdrp->gh_magic, GLOBAL_HDR_MAGIC,GLOBAL_HDR_MAGIC_SZ)) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "missing magic number in tape label\n"); + return DRIVE_ERROR_FORMAT; + } + + /* check the version + */ + if ( global_version_check( grhdrp->gh_version ) != BOOL_TRUE ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "invalid version number (%d) in tape label\n", + grhdrp->gh_version ); + return DRIVE_ERROR_VERSION; + } + + /* check the strategy id + */ + if ( drhdrp->dh_strategyid != drivep->d_strategyp->ds_id ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "unrecognized drive strategy ID (%d)\n", + drivep->d_readhdrp->dh_strategyid ); + return DRIVE_ERROR_FORMAT; + } + + /* check the record magic number + */ + if ( tprhdrp->magic != STAPE_MAGIC ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "invalid record magic number in tape label\n"); + return DRIVE_ERROR_FORMAT; + } + + /* check the record version number + */ + if ( tprhdrp->version != STAPE_VERSION ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "invalid record version number in tape label\n"); + return DRIVE_ERROR_VERSION; + } + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "media file header valid: " + "media file ix %d\n", + mrhdrp->mh_mediafileix ); + + return 0; +} + + +/* set_fixed_blksz() + * Issue the MTSETBLK ioctl to set the tape block size. + * Before issuing the call, close/reopen the device. + * if fails, rewind and try again. This is done to set the tape to BOT + * and to turn the CT_MOTION flag off so that the MTSETBLK call will + * succeed. If the call still fails, print an error but keep running. + * + * RETURNS: + * TRUE on success + * FALSE on failure + */ +static bool_t +set_fixed_blksz( drive_t *drivep, size_t blksz ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + ix_t try; + + /* sanity checks + */ + ASSERT( blksz ); + ASSERT( contextp->dc_isvarpr == BOOL_FALSE ); + ASSERT( contextp->dc_cansetblkszpr ); + ASSERT( contextp->dc_fd >= 0 ); + + /* give it two tries: first without rewinding, second with rewinding + */ + for ( try = 1 ; try <= 2 ; try++ ) { + struct mtblkinfo mtinfo; + + /* set the tape block size. requires re-open + */ + mlog( MLOG_DEBUG | MLOG_DRIVE, + "setting fixed block size to %d\n", + blksz ); + + /* close and re-open + */ + Close( drivep ); + if ( ! Open( drivep )) { + display_access_failed_message( drivep ); + return BOOL_FALSE; + } + + /* issue call to set block size + */ + if ( mt_op( contextp->dc_fd, + MTSETBLK, + ( intgen_t )blksz ) ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "MTSETBLK %u failed: %s (%d)\n", + blksz, + strerror( errno ), + errno); + } + + + + /* see if we were successful (can't look if RMT, so assume + * it worked) + */ + if ( ! contextp->dc_isrmtpr ) { + bool_t ok; + ok = mt_blkinfo( contextp->dc_fd, &mtinfo ); + if ( ! ok ) { + return BOOL_FALSE; + } + if ( mtinfo.curblksz == blksz ) { + return BOOL_TRUE; + } + } else { + return BOOL_TRUE; + } + + /* so rewind and try again + */ + ( void )rewind_and_verify( drivep ); + } + + mlog( MLOG_NORMAL | MLOG_DRIVE, + "unable to set block size to %d\n", + blksz ); + + return BOOL_FALSE; +} + +/* get_tpcaps + * Get the specific tape drive capabilities. Set the + * d_capabilities field of the driver structure. + * set the blksz limits and tape type in the context structure. + * + * RETURNS: + * TRUE on success + * FALSE on error + */ +static bool_t +get_tpcaps( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + ASSERT( contextp->dc_fd >= 0 ); + + if ( contextp->dc_isrmtpr ) { + /* can't ask about blksz, can't set blksz, can't ask about + * drive types/caps. assume a drive which can overwrite. + * assume NOT QIC, since fixed blksz devices not supported + * via RMT. + */ + contextp->dc_maxblksz = 0; + contextp->dc_isQICpr = BOOL_FALSE; + contextp->dc_cangetblkszpr = BOOL_FALSE; + contextp->dc_cansetblkszpr = BOOL_FALSE; + drivep->d_capabilities |= DRIVE_CAP_OVERWRITE; + drivep->d_capabilities |= DRIVE_CAP_BSF; + } else { + /* not remote, so we can ask the driver + */ + struct mtblkinfo mtinfo; + bool_t ok; + ok = mt_blkinfo( contextp->dc_fd, &mtinfo ); + if ( ! ok ) { + return BOOL_FALSE; + } + + contextp->dc_canfsrpr = BOOL_FALSE; + + if (contextp->dc_isQICpr) { + contextp->dc_cangetblkszpr = BOOL_FALSE; + contextp->dc_cansetblkszpr = BOOL_FALSE; + contextp->dc_maxblksz = QIC_BLKSZ; + drivep->d_capabilities &= ~DRIVE_CAP_OVERWRITE; + drivep->d_capabilities &= ~DRIVE_CAP_BSF; + } + else { + contextp->dc_cangetblkszpr = BOOL_TRUE; + contextp->dc_cansetblkszpr = BOOL_TRUE; + contextp->dc_maxblksz = mtinfo.maxblksz; + if ( contextp->dc_origcurblksz == 0 ) + contextp->dc_origcurblksz = mtinfo.curblksz; + drivep->d_capabilities |= DRIVE_CAP_OVERWRITE; + drivep->d_capabilities |= DRIVE_CAP_BSF; +#ifdef HIDDEN +Need to find equivalent in Linux. + if ( mtcapablity & MTCAN_SEEK ) { + contextp->dc_canfsrpr = BOOL_TRUE; + } +#endif + } + } + + set_recommended_sizes( drivep ); + + return BOOL_TRUE; +} + +/* set_recommended_sizes + * Determine the recommended tape file size and mark separation + * based on tape device type. + * + * RETURNS: + * void + */ +static void +set_recommended_sizes( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + off64_t fsize = drive_strategy_scsitape.ds_recmfilesz; + off64_t marksep = drive_strategy_scsitape.ds_recmarksep; + + if (contextp->dc_isQICpr) { + fsize = 0x3200000ll; /* 50 MB */ + } + +#ifdef DUMP + /* override with argument given */ + if (contextp->dc_filesz > 0) { + fsize = contextp->dc_filesz; + } +#endif + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "recommended tape media file size set to 0x%llx bytes\n", + fsize ); + mlog( MLOG_DEBUG | MLOG_DRIVE, + "recommended tape media mark separation set to 0x%llx bytes\n", + marksep ); + + drivep->d_recmfilesz = fsize; + drivep->d_recmarksep = marksep; + + return; +} + + +/* mt_blkinfo + * In IRIX, issue MTIOGETBLKINFO ioctl operation to the tape device. + * There is no equivalent call in Linux at the moment. + * However, the minblks and maxblks are stored internally in + * the scsi/st.c driver and may be exported in the future. + * The current blk size comes from the mt_dsreg field. + * + * RETURNS: + * TRUE on sucess + * FALSE on failure + */ +static bool_t +mt_blkinfo( intgen_t fd, struct mtblkinfo *minfo ) +{ + struct mtget mt_stat; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape op: get block size info\n" ); + + + if ( ioctl(fd, MTIOCGET, &mt_stat) < 0 ) { + /* failure + */ + mlog(MLOG_DEBUG, + "tape command MTIOCGET failed : %d (%s)\n", + errno, + strerror( errno )); + return BOOL_FALSE; + } + + minfo->curblksz = (mt_stat.mt_dsreg >> MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK; + + minfo->maxblksz = STAPE_MAX_LINUX_RECSZ; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "max=%u cur=%u\n", + minfo->maxblksz, + minfo->curblksz); + + /* success + */ + return BOOL_TRUE; +} + +/* mt_op + * Issue MTIOCTOP ioctl operation to the tape device. + * + * RETURNS: + * 0 on sucess + * -1 on failure + */ +static intgen_t +mt_op(intgen_t fd, intgen_t sub_op, intgen_t param ) +{ + struct mtop mop; + char *printstr; + intgen_t rval; + + mop.mt_op = (short )sub_op; + mop.mt_count = param; + + ASSERT( fd >= 0 ); + + switch ( sub_op ) { + case MTSEEK: + printstr = "seek"; + break; + case MTBSF: + printstr = "back space file"; + break; + case MTWEOF: + printstr = "write file mark"; + break; + case MTFSF: + printstr = "forward space file"; + break; + case MTREW: + printstr = "rewind"; + break; + case MTUNLOAD: + printstr = "unload"; + break; + case MTEOM: + printstr = "advance to EOD"; + break; + case MTFSR: + printstr = "forward space block"; + break; + case MTERASE: + printstr = "erase"; + break; + case MTSETBLK: + printstr = "set block size"; + break; + default: + printstr = "???"; + break; + } + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape op: %s %d\n", + printstr, + param ); + + rval = ioctl( fd, MTIOCTOP, &mop ); + if ( rval < 0 ) { + /* failure + */ + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape op %s %d returns %d: errno == %d (%s)\n", + printstr, + param, + rval, + errno, + strerror( errno )); + return -1; + } + + /* success + */ + return 0; +} + +static bool_t +mt_get_fileno( drive_t *drivep, long *fileno) +{ + struct mtget mt_stat; + drive_context_t *contextp; + + contextp = ( drive_context_t * )drivep->d_contextp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape op: get fileno\n" ); + + ASSERT( contextp->dc_fd >= 0 ); + + if ( ioctl(contextp->dc_fd, MTIOCGET, &mt_stat) < 0 ) { + /* failure + */ + mlog(MLOG_DEBUG, + "tape command MTIOCGET failed : %d (%s)\n", + errno, + strerror( errno )); + return BOOL_FALSE; + } + *fileno = mt_stat.mt_fileno; + return BOOL_TRUE; +} + +/* mt_get_status + * Get the current status of the tape device. + * + * RETURNS: + * TRUE if status was obtained + * FALSE if not + */ +static bool_t +mt_get_status( drive_t *drivep, long *status) +{ + struct mtget mt_stat; + drive_context_t *contextp; + + contextp = ( drive_context_t * )drivep->d_contextp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape op: get status\n" ); + + ASSERT( contextp->dc_fd >= 0 ); + + if ( ioctl(contextp->dc_fd, MTIOCGET, &mt_stat) < 0 ) { + /* failure + */ + mlog(MLOG_DEBUG, + "tape command MTIOCGET failed : %d (%s)\n", + errno, + strerror( errno )); + return BOOL_FALSE; + } + + /* success + */ + *status = mt_stat.mt_gstat; + + /* print out symbolic form of tape status */ + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape status = %s%s%s%s%s%s%s\n", + IS_BOT(*status)? "bot ":"", + IS_FMK(*status)? "fmk ":"", + IS_EOD(*status)? "eod ":"", + IS_EOT(*status)? "eot ":"", + IS_EW(*status)? "ew ":"", + IS_WPROT(*status)? "wprot ":"", + IS_ONL(*status)? "onl ":""); + + return BOOL_TRUE; +} + +/* determine_write_error() + * Using the errno and the tape status information, determine the + * type of tape write error that has occured. + * + * RETURNS: + * DRIVE_ERROR_* + */ +static intgen_t +determine_write_error( drive_t *drivep, int nwritten, int saved_errno ) +{ + mtstat_t mtstat; + intgen_t ret; + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + /* get tape device status + */ + if ( ! mt_get_status( drivep, &mtstat) ) { + status_failed_message( drivep ); + ret = DRIVE_ERROR_DEVICE; + } else if ( IS_WPROT(mtstat) && (saved_errno == EROFS)) { + + mlog(MLOG_NORMAL, + "tape is write protected\n"); + + ret = DRIVE_ERROR_DEVICE; + } else if ( (!IS_BOT(mtstat)) && + (IS_EOT( mtstat ) || IS_EW( mtstat) || + (saved_errno == ENOSPC))) { + ret = DRIVE_ERROR_EOM; + } else if (saved_errno == EIO ) { + + mlog(MLOG_NORMAL, + "tape media error on write operation\n"); + + mlog(MLOG_NORMAL, + "no more data can be written to this tape\n"); + + ret = DRIVE_ERROR_EOM; + } else if ( (saved_errno == 0) && + (nwritten > 0) && + contextp->dc_isQICpr ) { + /* short write on one of this devices indicates + * early warning for end-of-media. + */ + ret = DRIVE_ERROR_EOM; + } else { + ret = DRIVE_ERROR_CORE; + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape unknown error on write operation: " + "0x%x, %d, %d\n", + mtstat, nwritten, saved_errno); + } + + mlog( MLOG_NITTY | MLOG_DRIVE, + "tape write operation status 0x%x, nwritten %d, errno %d\n", + mtstat, + nwritten, + saved_errno); + + return ( ret ); + +} + +static void +tape_rec_checksum_set( drive_context_t *contextp, char *bufp ) +{ + rec_hdr_t *rechdrp = ( rec_hdr_t * )bufp; + u_int32_t *beginp = ( u_int32_t * )bufp; + u_int32_t *endp = ( u_int32_t * )( bufp + tape_recsz ); + u_int32_t *p; + u_int32_t accum; + + if ( ! contextp->dc_recchksumpr ) { + return; + } + + INT_SET(rechdrp->ischecksum, ARCH_CONVERT, 1); + rechdrp->checksum = 0; + accum = 0; + for ( p = beginp ; p < endp ; p++ ) { + accum += INT_GET(*p, ARCH_CONVERT); + } + INT_SET(rechdrp->checksum, ARCH_CONVERT, ( int32_t )( ~accum + 1 )); +} + +static bool_t +tape_rec_checksum_check( drive_context_t *contextp, char *bufp ) +{ + rec_hdr_t *rechdrp = ( rec_hdr_t * )bufp; + u_int32_t *beginp = ( u_int32_t * )bufp; + u_int32_t *endp = ( u_int32_t * )( bufp + tape_recsz ); + u_int32_t *p; + u_int32_t accum; + + if ( contextp->dc_recchksumpr && INT_GET(rechdrp->ischecksum, ARCH_CONVERT)) { + accum = 0; + for ( p = beginp ; p < endp ; p++ ) { + accum += INT_GET(*p, ARCH_CONVERT); + } + return accum == 0 ? BOOL_TRUE : BOOL_FALSE; + } else { + return BOOL_TRUE; + } +} + +/* to trace rmt operations + */ +#ifdef RMT +#ifdef RMTDBG +static int +dbgrmtopen( char *path, int flags ) +{ + int rval; + rval = rmtopen( path, flags ); + mlog( MLOG_NORMAL | MLOG_DRIVE, + "RMTOPEN( %s, %d ) returns %d: errno=%d (%s)\n", + path, + flags, + rval, + errno, + strerror( errno )); + return rval; +} +static int +dbgrmtclose( int fd ) +{ + int rval; + rval = rmtclose( fd ); + mlog( MLOG_NORMAL | MLOG_DRIVE, + "RMTCLOSE( %d ) returns %d: errno=%d (%s)\n", + fd, + rval, + errno, + strerror( errno )); + return rval; +} +static int +dbgrmtioctl( int fd, int op, void *arg ) +{ + int rval; + rval = rmtioctl( fd, op, arg ); + mlog( MLOG_NORMAL | MLOG_DRIVE, + "RMTIOCTL( %d, %d, 0x%x ) returns %d: errno=%d (%s)\n", + fd, + op, + arg, + rval, + errno, + strerror( errno )); + return rval; +} +static int +dbgrmtread( int fd, void *p, uint sz ) +{ + int rval; + rval = rmtread( fd, p, sz ); + mlog( MLOG_NORMAL | MLOG_DRIVE, + "RMTREAD( %d, 0x%x, %u ) returns %d: errno=%d (%s)\n", + fd, + p, + sz, + rval, + errno, + strerror( errno )); + return rval; +} +static int +dbgrmtwrite( int fd, void *p, uint sz ) +{ + int rval; + rval = rmtwrite( fd, p, sz ); + mlog( MLOG_NORMAL | MLOG_DRIVE, + "RMTWRITE( %d, 0x%x, %u ) returns %d: errno=%d (%s)\n", + fd, + p, + sz, + rval, + errno, + strerror( errno )); + return rval; +} +#endif /* RMTDBG */ +#endif /* RMT */ + +/* display_access_failed_message() + * Print tape device open/access failed message. + * + * RETURNS: + * void + */ +static void +display_access_failed_message( drive_t *drivep ) +{ + drive_context_t *contextp; + + /* get pointer to drive context + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + if ( contextp->dc_isrmtpr ) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "attempt to access/open remote " + "tape drive %s failed: %d (%s)\n", + drivep->d_pathname, + errno, + strerror( errno )); + } else { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "attempt to access/open device %s failed: %d (%s)\n", + drivep->d_pathname, + errno, + strerror( errno )); + } + return; +} + +/* status_failed_message() + * Print tape status device failed message. + * + * RETURNS: + * one + */ +static void +status_failed_message( drive_t *drivep ) +{ + drive_context_t *contextp; + + /* get pointer to drive context + */ + contextp = ( drive_context_t * )drivep->d_contextp; + + /* the get status call could have failed due to the + * tape device being closed by a CTLR-\ from the operator. + */ + if ( contextp->dc_fd != -1 ) { + if ( contextp->dc_isrmtpr ) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "attempt to get status of remote " + "tape drive %s failed: %d (%s)\n", + drivep->d_pathname, + errno, + strerror( errno )); + } else { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "attempt to get status of " + "tape drive %s failed: %d (%s)\n", + drivep->d_pathname, + errno, + strerror( errno )); + } + } + return; +} + +static bool_t +is_variable( drive_t *drivep, bool_t *varblk ) +{ + bool_t ok; + struct mtblkinfo minfo; + drive_context_t *contextp; + + contextp = ( drive_context_t * )drivep->d_contextp; + + ok = mt_blkinfo(contextp->dc_fd, &minfo); + if ( ! ok ) { + /* failure + */ + return BOOL_FALSE; + } + + /* for Linux scsi driver the blksize == 0 if variable */ + if (minfo.curblksz == 0) { + *varblk = BOOL_TRUE; + } + else { + *varblk = BOOL_FALSE; + } + return BOOL_TRUE; +} + + +/* prepare_drive - called by begin_read if drive device not open. + * determines record size and sets block size if fixed block device. + * determines other drive attributes. determines if any previous + * xfsdumps on media. + */ +static intgen_t +prepare_drive( drive_t *drivep ) +{ + drive_context_t *contextp; + mtstat_t mtstat; + bool_t ok; + ix_t try; + ix_t maxtries; + bool_t changedblkszpr; + intgen_t rval; + int varblk; + + /* get pointer to drive context + */ + contextp = ( drive_context_t * )drivep->d_contextp; + +retry: + if ( cldmgr_stop_requested( )) { + return DRIVE_ERROR_STOP; + } + + /* shouldn't be here if drive is open + */ + ASSERT( contextp->dc_fd == -1 ); + + mlog( MLOG_VERBOSE | MLOG_DRIVE, + "preparing drive\n" ); + + + /* determine if tape is present or write protected. try several times. + * if not present or write-protected during dump, return. + */ + maxtries = 15; + for ( try = 1 ; ; sleep( 10 ), try++ ) { + if ( cldmgr_stop_requested( )) { + return DRIVE_ERROR_STOP; + } + + /* open the drive + */ + ok = Open( drivep ); + if ( ! ok ) { + if ( errno != EBUSY ) { + display_access_failed_message( drivep ); + return DRIVE_ERROR_DEVICE; + } else { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "open drive returns EBUSY\n" ); + if ( try >= maxtries ) { + mlog( MLOG_TRACE | MLOG_DRIVE, + "giving up waiting for drive " + "to indicate online\n" ); + return DRIVE_ERROR_MEDIA; + } + continue; + } + } + + /* read device status (uses an ioctl) + */ + mtstat = 0; + ok = mt_get_status( drivep, &mtstat ); + if ( ! ok ) { + status_failed_message( drivep ); + return DRIVE_ERROR_DEVICE; + } + + /* look at status to check if the device is online. + * also check if write-protected (DUMP only), and give up + * after a few tries. + */ + if ( IS_ONL( mtstat )) { +#ifdef DUMP + if ( IS_WPROT( mtstat )) { + mlog(MLOG_NORMAL, + "tape is write protected\n" ); + return DRIVE_ERROR_MEDIA; + } +#endif /* DUMP */ + /* populate a struct stat. NOTE: this may do a temporary open/close + * NOTE: may do this only on local drives: rmt does not support! + */ + if ( contextp->dc_isrmtpr ) { + contextp->dc_isvarpr = BOOL_FALSE; + } else { + /* check for special device dev_t for fixed or variable type + * of device. set context and drive flags accordingly. + */ + + if (is_variable(drivep, &varblk) == BOOL_FALSE) + return DRIVE_ERROR_DEVICE; + + if (varblk) { + contextp->dc_isvarpr = BOOL_TRUE; + mlog( MLOG_TRACE | MLOG_DRIVE, + "variable block size " + "tape drive at %s\n", + drivep->d_pathname ); + } else { + contextp->dc_isvarpr = BOOL_FALSE; + mlog( MLOG_TRACE | MLOG_DRIVE, + "fixed block size tape " + "drive at %s\n", + drivep->d_pathname ); + } + } + + break; + } else if ( try >= maxtries ) { + mlog( MLOG_VERBOSE | MLOG_DRIVE, + "giving up waiting for drive " + "to indicate online\n" ); + return DRIVE_ERROR_MEDIA; + } + + /* drive is not ready. sleep for a while and try again + */ + mlog( MLOG_VERBOSE | MLOG_DRIVE, + "tape drive %s is not ready (0x%x): " + "retrying ...\n", + drivep->d_pathname, + mtstat ); + + Close( drivep ); + } + ASSERT( IS_ONL( mtstat )); + + /* determine tape capabilities. this will set the drivep->d_capabilities + * and contextp->dc_{...}blksz and dc_isQICpr, as well as recommended + * mark separation and media file size. + */ + ok = get_tpcaps( drivep ); + if ( ! ok ) { + return DRIVE_ERROR_DEVICE; + } + + /* disallow access of QIC via variable + */ + if ( contextp->dc_isvarpr && contextp->dc_isQICpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "use of QIC drives via variable blocksize device nodes " + "is not supported\n" ); + return DRIVE_ERROR_INVAL; + } + + /* if the overwrite option was specified , set the best blocksize + * we can and return. + */ + if ( contextp->dc_overwritepr ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "Overwrite option specified. " + "Trying best blocksize\n" ); + ok = set_best_blk_and_rec_sz( drivep ); + if ( ! ok ) { + return DRIVE_ERROR_DEVICE; + } + return DRIVE_ERROR_OVERWRITE; + } + + /* establish the initial block and record sizes we will try. + * if unable to ask drive about fixed block sizes, we will + * guess. + */ + calc_best_blk_and_rec_sz(drivep); + + /* if the drive status says we are at a file mark, there is + * an ambiguity: we could be positioned just before or just + * after the file mark. we want to always be positioned just after + * file marks. To disambiguate and force positioning after, + * we will use tape motion. back up two file marks, because + * typically we will be positioned after last file mark at EOD. + */ + if ( ! IS_BOT( mtstat ) && IS_FMK( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape positioned at file mark, " + "but do not know if before or after: " + "forcing tape motion to disambiguate\n" ); +#ifdef RESTORE + ( void )fsf_and_verify( drivep ); +#endif /* RESTORE */ + rval = quick_backup( drivep, contextp, 0 ); + if ( rval ) { + return rval; + } + } + + /* loop trying to read a record. begin with the record size + * calculated above. if it appears we have selected the wrong + * block size and if we are able to alter the fixed block size, + * and the record size we tried initially was not less than + * the minmax block size, change the block size to minmax and + * try to read a one block record again. + * + * ************** + * LINUX WARNING: + * ************** + * This code has a lot of conditionals on the current status + * and error result from the read. + * Under Linux using the scsi tape driver, as opposed to IRIX, + * the semantics may well be different for some error codes. + * For example, it seems on Linux if we use an erased tape + * then the first read returns an EIO, whereas on IRIX we would + * get an ENOSPC. + */ + maxtries = 5; + changedblkszpr = BOOL_FALSE; + for ( try = 1 ; ; try++ ) { + bool_t wasatbotpr; + intgen_t nread; + intgen_t saved_errno; + + if ( cldmgr_stop_requested( )) { + return DRIVE_ERROR_STOP; + } + + /* bail out if we've tried too many times + */ + if ( try > maxtries ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "giving up attempt to determining " + "tape record size\n" ); + return DRIVE_ERROR_MEDIA; + } + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "determining tape record size: trying %d (0x%x) bytes\n", + tape_recsz, + tape_recsz ); + + /* if a fixed device, but not QIC, and possible to set the block + * size, do so. + */ + if ( ! contextp->dc_isvarpr + && + ! contextp->dc_isQICpr + && + contextp->dc_cansetblkszpr ) { + ok = set_fixed_blksz( drivep, tape_blksz ); + if ( ! ok ) { + return DRIVE_ERROR_DEVICE; + } + } + + /* refresh the tape status + */ + mtstat = 0; + ok = mt_get_status( drivep, &mtstat ); + if ( ! ok ) { + status_failed_message( drivep ); + return DRIVE_ERROR_DEVICE; + } + + /* first ensure we are positioned at BOT or just after + * a file mark. if the drive says we are at a file mark, we + * don't know if we are just before or just after the file mark. + * so we must either bsf or rewind to eliminate the uncertainty. + * if BSF is not supported, must rewind. + */ + if ( ! IS_BOT( mtstat ) && ! IS_FMK( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape position unknown: searching backward " + "for file mark or BOT\n" ); + rval = quick_backup( drivep, contextp, 0 ); + if ( rval ) { + return rval; + } + mtstat = 0; + ok = mt_get_status( drivep, &mtstat ); + if ( ! ok ) { + status_failed_message( drivep ); + return DRIVE_ERROR_DEVICE; + } + } + + /* if we can't position the tape, call it a media error + */ + if ( ! IS_BOT( mtstat ) && ! IS_FMK( mtstat )) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "unable to backspace/rewind media\n" ); + return DRIVE_ERROR_MEDIA; + } + if ( IS_BOT( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape positioned at BOT: " + "doing redundant rewind\n" ); + mtstat = rewind_and_verify( drivep ); + if ( ! IS_BOT( mtstat )) { + return DRIVE_ERROR_DEVICE; + } + } + if ( IS_FMK( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape positioned at file mark\n" ); + } + + /* determine if we are at BOT. remember, so if read fails + * we can make a better decision on what to do next. + */ + if ( IS_BOT( mtstat )) { + wasatbotpr = BOOL_TRUE; + } else if ( IS_FMK( mtstat )) { + wasatbotpr = BOOL_FALSE; + } else { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "unable to backspace/rewind media\n" ); + return DRIVE_ERROR_MEDIA; + } + + /* read a record. use the first ring buffer + */ + saved_errno = 0; + nread = Read( drivep, + contextp->dc_recp, + tape_recsz, + &saved_errno ); + ASSERT( saved_errno == 0 || nread < 0 ); + + /* RMT can require a retry + */ + if ( saved_errno == EAGAIN ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "read returned EAGAIN: retrying\n" ); + continue; + } + + /* block size is bigger than buffer; should never happen + */ + if ( saved_errno == EINVAL ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "read returned EINVAL: " + "trying new record size\n" ); + goto largersize; + } + + /* block size is bigger than buffer; should never happen + */ + if ( saved_errno == ENOMEM ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "read returned ENOMEM: " + "trying new record size\n" ); + goto largersize; + } + + /* tried to read past EOD and was at BOT + */ + if ( saved_errno == ENOSPC + && + wasatbotpr ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "errno ENOSPC while at BOT " + "indicates blank tape: returning\n" ); + ( void )rewind_and_verify( drivep ); + ok = set_best_blk_and_rec_sz( drivep ); + if ( ! ok ) { + return DRIVE_ERROR_DEVICE; + } + return DRIVE_ERROR_BLANK; + } + + /* was at BOT and got EIO on read + * On Linux, using the scsi tape driver this + * seems to happen with an erased/blank tape + */ + if ( saved_errno == EIO + && + wasatbotpr ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "errno EIO while at BOT " + "indicates blank tape: returning\n" ); + ( void )rewind_and_verify( drivep ); + ok = set_best_blk_and_rec_sz( drivep ); + if ( ! ok ) { + return DRIVE_ERROR_DEVICE; + } + return DRIVE_ERROR_BLANK; + } + + /* tried to read past EOD and NOT at BOT + */ + if ( saved_errno == ENOSPC + && + ! wasatbotpr ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "errno ENOSPC while not at BOT " + "indicates EOD: retrying\n" ); + rval = quick_backup( drivep, contextp, 1 ); + if ( rval ) { + return rval; + } + continue; + } + + /* I/O error + */ + if ( saved_errno == EIO ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "read returned EIO: will reopen, rewind, " + "and try again\n" ); + Close( drivep ); + ok = Open( drivep ); + if ( ! ok ) { + display_access_failed_message( drivep ); + return DRIVE_ERROR_DEVICE; + } + ( void )rewind_and_verify( drivep ); + continue; + } + + /* freshen up the tape status. useful in decision-making + * done below. + */ + mtstat = 0; + ok = mt_get_status( drivep, &mtstat ); + if ( ! ok ) { + status_failed_message( drivep ); + return DRIVE_ERROR_DEVICE; + } + + if ( nread == 0 + && + ! contextp->dc_isvarpr + && + IS_EOD( mtstat ) + && + wasatbotpr ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "nread == 0 and EOD while at BOT on " + "fixed blocksize drive " + "indicates blank tape: returning\n" ); + ( void )rewind_and_verify( drivep ); + ok = set_best_blk_and_rec_sz( drivep ); + if ( ! ok ) { + return DRIVE_ERROR_DEVICE; + } + return DRIVE_ERROR_BLANK; + } + + if ( nread == 0 + && + ! contextp->dc_isvarpr + && + IS_EOD( mtstat ) + && + ! wasatbotpr ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "nread == 0 and EOD while not at BOT on " + "fixed blocksize drive " + "indicates EOD: backing up and retrying\n" ); + rval = quick_backup( drivep, contextp, 1 ); + if ( rval ) { + return rval; + } + continue; + } + + if ( nread == 0 + && + ! contextp->dc_isvarpr + && + IS_EOT( mtstat ) + && + ! wasatbotpr ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "nread == 0 and EOT while not at BOT on " + "fixed blocksize drive " + "indicates EOD: backing up and retrying\n" ); + rval = quick_backup( drivep, contextp, 1 ); + if ( rval ) { + return rval; + } + continue; + } + + if ( nread == 0 + && + ! contextp->dc_isvarpr + && + ! IS_EOD( mtstat ) + && + ! IS_FMK( mtstat ) + && + ! IS_EOT( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "nread == 0 and not EOD, not EOT, " + "and not at a file mark on fixed blocksize drive " + "indicates wrong blocksize\n" ); + goto newsize; + } + + if ( nread == 0 + && + contextp->dc_isvarpr + && + IS_EOD( mtstat ) + && + wasatbotpr ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "nread == 0 and EOD indication at BOT " + "on variable tape " + "indicates blank tape: returning\n" ); + ( void )rewind_and_verify( drivep ); + ok = set_best_blk_and_rec_sz( drivep ); + if ( ! ok ) { + return DRIVE_ERROR_DEVICE; + } + return DRIVE_ERROR_BLANK; + } + + if ( nread == 0 + && + contextp->dc_isvarpr + && + IS_EOD( mtstat ) + && + ! wasatbotpr ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "nread == 0 and EOD while not at BOT on " + "variable blocksize drive " + "indicates EOD: backing up and retrying\n" ); + rval = quick_backup( drivep, contextp, 1 ); + if ( rval ) { + return rval; + } + continue; + } + + if ( nread == 0 + && + contextp->dc_isvarpr + && + IS_EOT( mtstat ) + && + ! wasatbotpr ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "nread == 0 and EOT while not at BOT on " + "variable blocksize drive " + "indicates EOT: backing up and retrying\n" ); + rval = quick_backup( drivep, contextp, 1 ); + if ( rval ) { + return rval; + } + continue; + } + + if ( nread == 0 + && + contextp->dc_isvarpr + && + IS_FMK( mtstat ) + && + wasatbotpr ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "nread == 0 at BOT and at a file mark " + "on variable blocksize drive " + "indicates foreign tape: returning\n" ); + ( void )rewind_and_verify( drivep ); + ok = set_best_blk_and_rec_sz( drivep ); + if ( ! ok ) { + return DRIVE_ERROR_DEVICE; + } + return DRIVE_ERROR_FOREIGN; + } + + if ( nread > 0 + && + contextp->dc_isvarpr + && + ! IS_EOD( mtstat ) + && + ! IS_FMK( mtstat ) + && + ! IS_EOT( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "nread > 0 and not EOD, not EOT, " + "and not at a file mark on variable blocksize drive " + "indicates correct blocksize found\n" ); + goto checkhdr; + } + + if ( nread < ( intgen_t )tape_recsz + && + ! contextp->dc_isvarpr ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "nread less than selected record size on " + "fixed blocksize drive " + "indicates wrong blocksize\n" ); + goto newsize; + } + + if ( nread == ( intgen_t )tape_recsz + && + ! contextp->dc_isvarpr ) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "nread == selected blocksize " + "on fixed blocksize drive " + "indicates correct blocksize found\n" ); + goto checkhdr; + } + + /* if we fell through the seive, code is wrong. + * display useful info and abort + */ + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "unexpected tape error: " + "errno %d " + "nread %d " + "blksz %d " + "recsz %d " + "isvar %d " + "wasatbot %d " + "eod %d " + "fmk %d " + "eot %d " + "onl %d " + "wprot %d " + "ew %d " + "\n", + saved_errno, + nread, + tape_blksz, + tape_recsz, + !! contextp->dc_isvarpr, + wasatbotpr, + IS_EOD( mtstat ) > 0, + IS_FMK( mtstat ) > 0, + IS_EOT( mtstat ) > 0, + IS_ONL( mtstat ) > 0, + IS_WPROT( mtstat ) > 0, + IS_EW( mtstat ) > 0, + 0 ); + + /* Common Linux Problem */ + if (errno == EOVERFLOW) { + mlog( MLOG_NORMAL | MLOG_NOTE | MLOG_DRIVE, + "likely problem is that the block size, %d, " + "is too large for Linux\n", tape_blksz); + mlog( MLOG_NORMAL | MLOG_NOTE | MLOG_DRIVE, + "either try using a smaller block size with " + "the -b option, or increase max_sg_segs for " + "the scsi tape driver\n"); + } + + + return DRIVE_ERROR_CORE; + + +checkhdr: + rval = validate_media_file_hdr( drivep ); + if ( rval ) { + if ( rval == DRIVE_ERROR_VERSION ) { + global_hdr_t *grhdrp = drivep->d_greadhdrp; + mlog( MLOG_NORMAL | MLOG_DRIVE, + "media file header version (%d) " + "invalid: advancing\n", + grhdrp->gh_version ); + continue; + } else if ( wasatbotpr ) { + if ( isefsdump( drivep )) { + mlog( MLOG_NORMAL + | + MLOG_WARNING + | + MLOG_DRIVE, + "may be an EFS dump at BOT\n" ); + } else { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "bad media file header at BOT " + "indicates foreign or " + "corrupted tape\n" ); + } + ( void )rewind_and_verify( drivep ); + ok = set_best_blk_and_rec_sz( drivep ); + if ( ! ok ) { + return DRIVE_ERROR_DEVICE; + } + return DRIVE_ERROR_FOREIGN; + } else { + /* back up and try again. + */ + mlog( MLOG_DEBUG | MLOG_DRIVE, + "media file header invalid: " + "backing up " + "to try a previous media file\n" ); + rval = quick_backup( drivep, contextp, 1 ); + if ( rval ) { + return rval; + } + continue; + } + } else { + drive_hdr_t *drhdrp; + rec_hdr_t *tprhdrp; + drhdrp = drivep->d_readhdrp; + tprhdrp = ( rec_hdr_t * )drhdrp->dh_specific; + ASSERT( tprhdrp->recsize >= 0 ); + tape_recsz = ( size_t )tprhdrp->recsize; + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape record size set to header's " + "record size = %d\n", tape_recsz); + break; + } + +newsize: + /* we end up here if we want to try a new record size. + * only do this once. + */ + if ( changedblkszpr ) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "cannot determine tape block size " + "after two tries\n" ); + if ( ! wasatbotpr ) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "will rewind and try again\n" ); + ( void )rewind_and_verify( drivep ); + Close( drivep ); + goto retry; + } else { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "assuming media is corrupt " + "or contains non-xfsdump data\n" ); + ( void )rewind_and_verify( drivep ); + ok = set_best_blk_and_rec_sz( drivep ); + if ( ! ok ) { + return DRIVE_ERROR_DEVICE; + } + return DRIVE_ERROR_FOREIGN; + } + } + if ( tape_recsz > STAPE_MIN_MAX_BLKSZ ) { + tape_recsz = STAPE_MIN_MAX_BLKSZ; + if ( ! contextp->dc_isQICpr ) { + tape_blksz = tape_recsz;; + } + changedblkszpr = BOOL_TRUE; + } else { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "cannot determine tape block size\n" ); + return DRIVE_ERROR_MEDIA; + } + continue; + +largersize: + /* we end up here if we want to try a new larger record size + * because the last one was not big enough for the tape block + */ + if ( changedblkszpr ) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "cannot determine tape block size " + "after two tries\n" ); + if ( ! wasatbotpr ) { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "will rewind and try again\n" ); + ( void )rewind_and_verify( drivep ); + Close( drivep ); + goto retry; + } else { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "assuming media is corrupt " + "or contains non-xfsdump data\n" ); + ( void )rewind_and_verify( drivep ); + ok = set_best_blk_and_rec_sz( drivep ); + if ( ! ok ) { + return DRIVE_ERROR_DEVICE; + } + return DRIVE_ERROR_FOREIGN; + } + } + /* Make it as large as we can go + */ + if ( tape_recsz != STAPE_MAX_RECSZ ) { + tape_recsz = STAPE_MAX_RECSZ; + if ( ! contextp->dc_isQICpr ) { + tape_blksz = tape_recsz;; + } + changedblkszpr = BOOL_TRUE; + } else { + mlog( MLOG_NORMAL | MLOG_DRIVE, + "cannot determine tape block size\n" ); + return DRIVE_ERROR_MEDIA; + } + continue; + + } /* loop reading 1st record 'til get correct blksz */ + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "read first record of first media file encountered on media: " + "recsz == %u\n", + tape_recsz ); + + /* calculate maximum bytes lost without error at end of tape + */ + calc_max_lost( drivep ); + + contextp->dc_iocnt = 1; + return 0; +} + +/* if BOOL_FALSE returned, errno is valid + */ +static bool_t +Open( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + intgen_t oflags; + +#ifdef DUMP + oflags = O_RDWR; +#endif /* DUMP */ +#ifdef RESTORE + oflags = O_RDONLY; +#endif /* RESTORE */ + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape op: opening drive\n" ); + + ASSERT( contextp->dc_fd == -1 ); + + errno = 0; + contextp->dc_fd = open_masked_signals( drivep->d_pathname, oflags ); + + if ( contextp->dc_fd <= 0 ) { + return BOOL_FALSE; + } + + + return BOOL_TRUE; +} + +static void +Close( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape op: closing drive\n" ); + + ASSERT( contextp->dc_fd >= 0 ); + + ( void )close( contextp->dc_fd ); + + contextp->dc_fd = -1; +} + +static intgen_t +Read( drive_t *drivep, char *bufp, size_t cnt, intgen_t *errnop ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + intgen_t nread; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape op: reading %u bytes\n", + cnt ); + + ASSERT( contextp->dc_fd >= 0 ); + ASSERT( bufp ); + *errnop = 0; + errno = 0; + nread = read( contextp->dc_fd, ( void * )bufp, cnt ); + if ( nread < 0 ) { + *errnop = errno; + mlog( MLOG_NITTY | MLOG_DRIVE, + "tape op read of %u bytes failed: errno == %d (%s)\n", + cnt, + errno, + strerror( errno )); + } else if ( nread != ( intgen_t )cnt ) { + mlog( MLOG_NITTY | MLOG_DRIVE, + "tape op read of %u bytes short: nread == %d\n", + cnt, + nread ); + } else { + mlog( MLOG_NITTY | MLOG_DRIVE, + "tape op read of %u bytes successful\n", + cnt ); + } + + return nread; +} + +static intgen_t +Write( drive_t *drivep, char *bufp, size_t cnt, intgen_t *errnop ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + intgen_t nwritten; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "tape op: writing %u bytes\n", + cnt ); + + ASSERT( contextp->dc_fd >= 0 ); + ASSERT( bufp ); + *errnop = 0; + errno = 0; + nwritten = write( contextp->dc_fd, ( void * )bufp, cnt ); + if ( nwritten < 0 ) { + *errnop = errno; + mlog( MLOG_NITTY | MLOG_DRIVE, + "tape op write of %u bytes failed: errno == %d (%s)\n", + cnt, + errno, + strerror( errno )); + } else if ( nwritten != ( intgen_t )cnt ) { + mlog( MLOG_NITTY | MLOG_DRIVE, + "tape op write of %u bytes short: nwritten == %d\n", + cnt, + nwritten ); + } else { + mlog( MLOG_NITTY | MLOG_DRIVE, + "tape op write of %u bytes successful\n", + cnt ); + } + + return nwritten; +} + +/* probably should use do_bsf instead. + * backs up and positions tape after previous file mark. + * skips skipcnt media files. + */ +/* ARGSUSED */ +static intgen_t +quick_backup( drive_t *drivep, drive_context_t *contextp, ix_t skipcnt ) +{ + if ( drivep->d_capabilities & DRIVE_CAP_BSF ) { + do { + mtstat_t mtstat; + mtstat = bsf_and_verify( drivep ); + if ( IS_BOT( mtstat )) { + return 0; + } +#ifdef HAVE_2WAYFMK + if ( ! IS_FMK( mtstat )) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "unable to backspace tape: " + "assuming media error\n" ); + return DRIVE_ERROR_MEDIA; + } +#endif + } while ( skipcnt-- ); + ( void )fsf_and_verify( drivep ); + } else { + ( void )rewind_and_verify( drivep ); + } + + return 0; +} + +/* validate a record header, log any anomolies, and return appropriate + * indication. + */ +static intgen_t +record_hdr_validate( drive_t *drivep, char *bufp, bool_t chkoffpr ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + global_hdr_t *grhdrp = drivep->d_greadhdrp; + rec_hdr_t rechdr; + rec_hdr_t *rechdrp = &rechdr; + rec_hdr_t *tmprh = ( rec_hdr_t * )bufp; + + if ( ! tape_rec_checksum_check( contextp, bufp )) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: bad record checksum\n", + contextp->dc_iocnt - 1 ); + return DRIVE_ERROR_CORRUPTION; + + } + + xlate_rec_hdr(tmprh, rechdrp, 1); + + if ( rechdrp->magic != STAPE_MAGIC ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: bad magic number\n", + contextp->dc_iocnt - 1 ); + return DRIVE_ERROR_CORRUPTION; + } + + if ( uuid_is_null( rechdrp->dump_uuid )) { + + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: null dump id\n", + contextp->dc_iocnt - 1 ); + return DRIVE_ERROR_CORRUPTION; + } + + if ( uuid_compare( grhdrp->gh_dumpid, + rechdrp->dump_uuid ) != 0) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: dump id mismatch\n", + contextp->dc_iocnt - 1 ); + return DRIVE_ERROR_CORRUPTION; + } + + if ( ( size_t )rechdrp->recsize != tape_recsz ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: incorrect record size in header\n", + contextp->dc_iocnt - 1 ); + return DRIVE_ERROR_CORRUPTION; + } + + if ( rechdrp->file_offset % ( off64_t )tape_recsz ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: record offset in header " + "not a multiple of record size\n", + contextp->dc_iocnt - 1 ); + return DRIVE_ERROR_CORRUPTION; + } + + if ( chkoffpr + && + rechdrp->file_offset + != + ( contextp->dc_iocnt - 1 ) * ( off64_t )tape_recsz ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: " + "incorrect record offset in header (0x%llx)\n", + contextp->dc_iocnt - 1, + rechdrp->file_offset ); + return DRIVE_ERROR_CORRUPTION; + } + + if ( rechdrp->rec_used > tape_recsz + || + rechdrp->rec_used < STAPE_HDR_SZ ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "record %lld corrupt: " + "incorrect record padding offset in header\n", + contextp->dc_iocnt - 1 ); + return DRIVE_ERROR_CORRUPTION; + } + + memcpy(tmprh, rechdrp, sizeof(*rechdrp)); + + return 0; +} + +/* do a read, determine DRIVE_ERROR_... if failure, and return failure code. + * return 0 on success. + */ +static intgen_t +read_record( drive_t *drivep, char *bufp ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + intgen_t nread; + intgen_t saved_errno; + mtstat_t mtstat; + intgen_t rval; + bool_t ok; + + nread = Read( drivep, bufp, tape_recsz, &saved_errno ); + if ( nread == ( intgen_t )tape_recsz ) { + contextp->dc_iocnt++; + rval = record_hdr_validate( drivep, bufp, BOOL_TRUE ); + return rval; + } + + /* get drive status + */ + ok = mt_get_status( drivep, &mtstat ); + if ( ! ok ) { + status_failed_message( drivep ); + return DRIVE_ERROR_DEVICE; + } + + /* encountered a file mark + */ + if ( IS_FMK( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "encountered EOF attempting to read record %lld\n", + contextp->dc_iocnt ); + return DRIVE_ERROR_EOF; + } + + /* encountered a end of recorded data + */ + if ( IS_EOD( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "encountered EOD attempting to read record %lld\n", + contextp->dc_iocnt ); + return DRIVE_ERROR_EOD; + } + + /* encountered a end of media + */ + if ( IS_EOT( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "encountered EOM attempting to read record %lld\n", + contextp->dc_iocnt ); + return DRIVE_ERROR_EOM; + } + + /* encountered a end of media (early warning indicated) + */ + if ( IS_EW( mtstat )) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "encountered EW attempting to read record %lld\n", + contextp->dc_iocnt ); + return DRIVE_ERROR_EOM; + } + + /* short read + */ + if ( nread >= 0 ) { + ASSERT( nread <= ( intgen_t )tape_recsz ); + mlog( MLOG_DEBUG | MLOG_DRIVE, + "short read record %lld (nread == %d)\n", + contextp->dc_iocnt, + nread ); + return DRIVE_ERROR_CORRUPTION; + } + + /* some other error + */ + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "unexpected error attempting to read record %lld: " + "read returns %d, errno %d (%s)\n", + contextp->dc_iocnt, + nread, + errno, + strerror( errno )); + return DRIVE_ERROR_CORRUPTION; +} + +static int +ring_read( void *clientctxp, char *bufp ) +{ + return read_record( ( drive_t * )clientctxp, bufp ); +} + +/* gets another record IF dc_recp is NULL + */ +static intgen_t +getrec( drive_t *drivep ) +{ + drive_context_t *contextp; + contextp = ( drive_context_t * )drivep->d_contextp; + + while ( ! contextp->dc_recp ) { + rec_hdr_t *rechdrp; + if ( contextp->dc_singlethreadedpr ) { + intgen_t rval; + contextp->dc_recp = contextp->dc_bufp; + rval = read_record( drivep, contextp->dc_recp ); + if ( rval ) { + contextp->dc_errorpr = BOOL_TRUE; + return rval; + } + } else { + contextp->dc_msgp = Ring_get( contextp->dc_ringp ); + switch( contextp->dc_msgp->rm_stat ) { + case RING_STAT_OK: + contextp->dc_recp = contextp->dc_msgp->rm_bufp; + break; + case RING_STAT_INIT: + case RING_STAT_NOPACK: + case RING_STAT_IGNORE: + contextp->dc_msgp->rm_op = RING_OP_READ; + Ring_put( contextp->dc_ringp, + contextp->dc_msgp ); + contextp->dc_msgp = 0; + continue; + case RING_STAT_ERROR: + contextp->dc_errorpr = BOOL_TRUE; + return contextp->dc_msgp->rm_rval; + default: + ASSERT( 0 ); + contextp->dc_errorpr = BOOL_TRUE; + return DRIVE_ERROR_CORE; + } + } + rechdrp = ( rec_hdr_t * )contextp->dc_recp; + contextp->dc_recendp = contextp->dc_recp + tape_recsz; + contextp->dc_dataendp = contextp->dc_recp + + + rechdrp->rec_used; + contextp->dc_nextp = contextp->dc_recp + + + STAPE_HDR_SZ; + ASSERT( contextp->dc_nextp <= contextp->dc_dataendp ); + } + + return 0; +} + +/* do a write, determine DRIVE_ERROR_... if failure, and return failure code. + * return 0 on success. + */ +/*ARGSUSED*/ +static intgen_t +write_record( drive_t *drivep, char *bufp, bool_t chksumpr ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + intgen_t nwritten; + intgen_t saved_errno; + intgen_t rval; + + if ( chksumpr ) { + tape_rec_checksum_set( contextp, bufp ); + } + + nwritten = Write( drivep, bufp, tape_recsz, &saved_errno ); + + if ( nwritten == ( intgen_t )tape_recsz ) { + contextp->dc_iocnt++; + return 0; + } + + rval = determine_write_error( drivep, nwritten, saved_errno ); + ASSERT( rval ); + + return rval; +} + +static int +ring_write( void *clientctxp, char *bufp ) +{ + return write_record( ( drive_t * )clientctxp, bufp, BOOL_TRUE ); +} + +static void +ring_thread( void *clientctxp, + int ( * entryp )( void *ringctxp ), + void *ringctxp ) +{ + drive_t *drivep = ( drive_t * )clientctxp; + /* REFERENCED */ + bool_t ok; + + ok = cldmgr_create( entryp, + CLONE_VM, + drivep->d_index, + "slave", + ringctxp ); + ASSERT( ok ); +} + + +static ring_msg_t * +Ring_get( ring_t *ringp ) +{ + ring_msg_t *msgp; + + mlog( (MLOG_NITTY + 1) | MLOG_DRIVE, + "ring op: get\n" ); + + msgp = ring_get( ringp ); + return msgp; +} + +static void +Ring_put( ring_t *ringp, ring_msg_t *msgp ) +{ + mlog( (MLOG_NITTY + 1) | MLOG_DRIVE, + "ring op: put %d\n", + msgp->rm_op ); + + ring_put( ringp, msgp ); +} + +static void +Ring_reset( ring_t *ringp, ring_msg_t *msgp ) +{ + mlog( (MLOG_NITTY + 1) | MLOG_DRIVE, + "ring op: reset\n" ); + + ASSERT( ringp ); + + ring_reset( ringp, msgp ); +} + +/* a simple heuristic to calculate the maximum uncertainty + * of how much data actually was written prior to encountering + * end of media. + */ +static void +calc_max_lost( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + if ( contextp->dc_isQICpr ) { + contextp->dc_lostrecmax = 1; + } else { + contextp->dc_lostrecmax = 2; + } + +} + +static void +display_ring_metrics( drive_t *drivep, intgen_t mlog_flags ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + ring_t *ringp = contextp->dc_ringp; + char bufszbuf[ 16 ]; + char *bufszsfxp; + + if ( tape_recsz == STAPE_MIN_MAX_BLKSZ ) { + ASSERT( ! ( STAPE_MIN_MAX_BLKSZ % 0x400 )); + sprintf( bufszbuf, "%u", STAPE_MIN_MAX_BLKSZ / 0x400 ); + ASSERT( strlen( bufszbuf ) < sizeof( bufszbuf )); + bufszsfxp = "KB"; + } else if ( tape_recsz == STAPE_MAX_RECSZ ) { + ASSERT( ! ( STAPE_MAX_RECSZ % 0x100000 )); + sprintf( bufszbuf, "%u", STAPE_MAX_RECSZ / 0x100000 ); + ASSERT( strlen( bufszbuf ) < sizeof( bufszbuf )); + bufszsfxp = "MB"; + } else if ( tape_recsz == STAPE_MAX_LINUX_RECSZ ) { + ASSERT( ! ( STAPE_MAX_LINUX_RECSZ % 0x100000 )); + sprintf( bufszbuf, "%u", STAPE_MAX_LINUX_RECSZ / 0x100000 ); + ASSERT( strlen( bufszbuf ) < sizeof( bufszbuf )); + bufszsfxp = "MB"; + } else { + bufszsfxp = ""; + } + + mlog( mlog_flags, + "I/O metrics: " + "%u by %s%s %sring; " + "%lld/%lld (%.0lf%%) records streamed; " + "%.0lfB/s\n", + contextp->dc_ringlen, + bufszbuf, + bufszsfxp, + contextp->dc_ringpinnedpr ? "pinned " : "", + ringp->r_slave_msgcnt - ringp->r_slave_blkcnt, + ringp->r_slave_msgcnt, + percent64( ringp->r_slave_msgcnt - ringp->r_slave_blkcnt, + ringp->r_slave_msgcnt ), + ( double )( ringp->r_all_io_cnt ) + * + ( double )tape_recsz + / + ( double )( time( 0 ) - ringp->r_first_io_time )); +} + +static mtstat_t +rewind_and_verify( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + ix_t try; + intgen_t rval; + + rval = mt_op( contextp->dc_fd, MTREW, 0 ); + for ( try = 1 ; ; try++ ) { + mtstat_t mtstat; + bool_t ok; + + if ( rval ) { + sleep( 1 ); + rval = mt_op( contextp->dc_fd, MTREW, 0 ); + } + ok = mt_get_status( drivep, &mtstat ); + if ( ! ok ) { + mtstat = 0; + status_failed_message( drivep ); + if ( try > 1 ) { + return 0; + } + } + if ( IS_BOT( mtstat )) { + return mtstat; + } + if ( try >= MTOP_TRIES_MAX ) { + return mtstat; + } + if ( rval ) { + return mtstat; + } + sleep( 1 ); + } + /* NOTREACHED */ +} + +static mtstat_t +erase_and_verify( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + mtstat_t mtstat; + bool_t ok; + + ( void )mt_op( contextp->dc_fd, MTERASE, 0 ); + ok = mt_get_status( drivep, &mtstat ); + if ( ! ok ) { + mtstat = 0; + status_failed_message( drivep ); + } + return mtstat; +} + +static mtstat_t +bsf_and_verify( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + ix_t try; + long fileno; + bool_t ok; + + /* + * Workaround for linux st driver bug. + * Don't do a bsf if still in the first file. + * Do a rewind instead because the status won't be + * set correctly otherwise. [TS:Oct/2000] + */ + ok = mt_get_fileno( drivep, &fileno ); + if ( ! ok ) { + status_failed_message( drivep ); + return 0; + } + if (fileno == 0) { + mlog( MLOG_DEBUG | MLOG_DRIVE, + "In first file, do a rewind to achieve bsf\n"); + return rewind_and_verify( drivep ); + } + + ( void )mt_op( contextp->dc_fd, MTBSF, 1 ); +#ifdef HAVE_2WAYFMK /* Can't do in LINUX as GMT_EOF never set for left of fmk */ + for ( try = 1 ; ; try++ ) { + mtstat_t mtstat; + + ok = mt_get_status( drivep, &mtstat ); + if ( ! ok ) { + mtstat = 0; + status_failed_message( drivep ); + if ( try > 1 ) { + return 0; + } + } + if ( IS_FMK( mtstat )) { + return mtstat; + } + if ( IS_BOT( mtstat )) { + return mtstat; + } + if ( try >= MTOP_TRIES_MAX ) { + return mtstat; + } + sleep( 1 ); + } +#else + { + mtstat_t mtstat; + bool_t ok; + + try = 1; +status: ok = mt_get_status( drivep, &mtstat ); + if ( ! ok ) { + mtstat = 0; + status_failed_message( drivep ); + if ( try > 1 ) { + return 0; + } + try++; + sleep( 1 ); + goto status; + } + return mtstat; + } +#endif + /* NOTREACHED */ +} + +static mtstat_t +fsf_and_verify( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + ix_t try; + + ( void )mt_op( contextp->dc_fd, MTFSF, 1 ); + for ( try = 1 ; ; try++ ) { + mtstat_t mtstat; + bool_t ok; + + ok = mt_get_status( drivep, &mtstat ); + if ( ! ok ) { + mtstat = 0; + status_failed_message( drivep ); + if ( try > 1 ) { + return 0; + } + } + if ( IS_FMK( mtstat )) { + return mtstat; + } + if ( IS_EOD( mtstat )) { + return mtstat; + } + if ( IS_EOT( mtstat )) { + return mtstat; + } + if ( try >= MTOP_TRIES_MAX ) { + return mtstat; + } + sleep( 1 ); + } + /* NOTREACHED */ +} + +static void +calc_best_blk_and_rec_sz( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + if ( ! contextp->dc_isrmtpr ) { + if ( cmdlineblksize > 0 ) { + tape_blksz = cmdlineblksize; + } else { + tape_blksz = contextp->dc_maxblksz; + } + if ( tape_blksz > STAPE_MAX_RECSZ ) { + tape_blksz = STAPE_MAX_RECSZ; + } + if ( contextp->dc_isQICpr ) { + tape_recsz = STAPE_MAX_RECSZ; + } else { + tape_recsz = tape_blksz; + } + } else { + tape_recsz = STAPE_MIN_MAX_BLKSZ; + } +} + +static bool_t +set_best_blk_and_rec_sz( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + calc_best_blk_and_rec_sz(drivep); + + if ( ! contextp->dc_isvarpr + && + ! contextp->dc_isQICpr + && + contextp->dc_cansetblkszpr ) { + bool_t ok; + ok = set_fixed_blksz( drivep, tape_blksz ); + if ( ! ok ) { + return BOOL_FALSE; + } + } + + return BOOL_TRUE; +} + +static bool_t +isefsdump( drive_t *drivep ) +{ + int32_t *efshdrp = ( int32_t * )drivep->d_greadhdrp; + int32_t efsmagic = efshdrp[ 6 ]; + if ( efsmagic == 60011 + || + efsmagic == 60012 ) { + return BOOL_TRUE; + } else { + return BOOL_FALSE; + } +} + +#ifdef OPENMASKED + +static intgen_t +open_masked_signals( char *pathname, int oflags ) +{ + bool_t isrmtpr; + SIG_PF sigalrm_save; + SIG_PF sigint_save; + SIG_PF sighup_save; + SIG_PF sigquit_save; + SIG_PF sigcld_save; + intgen_t rval; + intgen_t saved_errno; + + if ( strchr( pathname, ':') ) { + isrmtpr = BOOL_TRUE; + } else { + isrmtpr = BOOL_FALSE; + } + + if ( isrmtpr ) { + sigalrm_save = sigset( SIGALRM, SIG_IGN ); + sigint_save = sigset( SIGINT, SIG_IGN ); + sighup_save = sigset( SIGHUP, SIG_IGN ); + sigquit_save = sigset( SIGQUIT, SIG_IGN ); + sigcld_save = sigset( SIGCLD, SIG_IGN ); + } + + errno = 0; + rval = open( pathname, oflags ); + saved_errno = errno; + + if ( isrmtpr ) { + ( void )sigset( SIGCLD, sigcld_save ); + ( void )sigset( SIGQUIT, sigquit_save ); + ( void )sigset( SIGHUP, sighup_save ); + ( void )sigset( SIGINT, sigint_save ); + ( void )sigset( SIGALRM, sigalrm_save ); + } + + errno = saved_errno; + return rval; +} + +#endif /* OPENMASKED */ diff -rNu linux-2.4.7/cmd/xfsdump/common/drive_simple.c linux-2.4-xfs/cmd/xfsdump/common/drive_simple.c --- linux-2.4.7/cmd/xfsdump/common/drive_simple.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/drive_simple.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,1534 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "util.h" +#include "stream.h" +#include "mlog.h" +#include "global.h" +#include "drive.h" +#include "media.h" +#include "arch_xlate.h" + +#ifdef RMT +/* this rmt junk is here because the rmt protocol supports writing ordinary + * (non-device) files in the remote /dev directory! yuck! + */ +#define open rmtopen +#define creat rmtcreat +#define close rmtclose +#define ioctl rmtioctl +#define read rmtread +#define write rmtwrite + +extern int rmtclose( int ); +extern int rmtcreat (char *path, int mode); +extern int rmtioctl( int, int, ... ); +extern int rmtopen( char *, int, ... ); +extern int rmtread( int, void*, uint); +extern int rmtwrite( int, const void *, uint); +#endif + + +/* drive_simple.c - drive strategy for standard in or a file + */ + + +/* structure definitions used locally ****************************************/ + +/* drive context - drive-specific context + * buf must be page-aligned and at least 1 page in size + */ +#define PGPERBUF 64 /* private read buffer */ +#define BUFSZ ( PGPERBUF * PGSZ ) + +/* operational mode + */ +typedef enum { OM_NONE, OM_READ, OM_WRITE } om_t; + +struct drive_context { + char dc_buf[ BUFSZ ]; /* input/output buffer */ + om_t dc_mode; /* current mode of operation */ + ix_t dc_fmarkcnt; /* how many file marks to the left */ + char *dc_ownedp; /* first byte owned by caller */ + size_t dc_ownedsz; /* how much owned by caller (write only) */ + char *dc_nextp; /* next byte avail. to read/write */ + char *dc_emptyp; /* first empty slot in buffer */ + off64_t dc_bufstroff; /* offset in stream of top of buf */ + intgen_t dc_fd; /* input/output file descriptor */ + drive_mark_t dc_firstmark;/* first mark's offset within mfile (dump) */ + ix_t dc_markcnt; /* count of marks set (dump) */ + bool_t dc_rampr; /* can randomly access file (not a pipe) */ + bool_t dc_isrmtpr; /* is accessed via rmt */ + bool_t dc_israwdevpr; /* is a raw disk partition */ +}; + +typedef struct drive_context drive_context_t; + + +/* declarations of externally defined global variables ***********************/ + +extern size_t pgsz; + + +/* forward declarations of locally defined static functions ******************/ + +/* strategy functions + */ +static intgen_t ds_match( int, char *[], drive_t *, bool_t ); +static intgen_t ds_instantiate( int, char *[], drive_t *, bool_t ); + +/* declare manager operators + */ +static bool_t do_init( drive_t * ); +static bool_t do_sync( drive_t * ); +static intgen_t do_begin_read( drive_t * ); +static char *do_read( drive_t *, size_t , size_t *, intgen_t * ); +static void do_return_read_buf( drive_t *, char *, size_t ); +static void do_get_mark( drive_t *, drive_mark_t * ); +static intgen_t do_seek_mark( drive_t *, drive_mark_t * ); +static intgen_t do_next_mark( drive_t * ); +static void do_get_mark( drive_t *, drive_mark_t * ); +static void do_end_read( drive_t * ); +static intgen_t do_begin_write( drive_t * ); +static void do_set_mark( drive_t *, drive_mcbfp_t, void *, drive_markrec_t * ); +static char * do_get_write_buf( drive_t *, size_t , size_t * ); +static intgen_t do_write( drive_t *, char *, size_t ); +static size_t do_get_align_cnt( drive_t * ); +static intgen_t do_end_write( drive_t *, off64_t * ); +static intgen_t do_rewind( drive_t * ); +static intgen_t do_erase( drive_t * ); +static intgen_t do_get_device_class( drive_t * ); +static void do_quit( drive_t * ); + + +/* definition of locally defined global variables ****************************/ + +/* simple drive strategy for file or stdin. referenced by drive.c + */ +drive_strategy_t drive_strategy_simple = { + DRIVE_STRATEGY_SIMPLE, /* ds_id */ + "drive_simple", /* ds_description */ + ds_match, /* ds_match */ + ds_instantiate, /* ds_instantiate */ + 0x1000000ll, /* ds_recmarksep */ + OFF64MAX /* ds_recmfilesz */ +}; + + +/* definition of locally defined static variables *****************************/ + +/* drive operators + */ +static drive_ops_t drive_ops = { + do_init, /* do_init */ + do_sync, /* do_sync */ + do_begin_read, /* do_begin_read */ + do_read, /* do_read */ + do_return_read_buf, /* do_return_read_buf */ + do_get_mark, /* do_get_mark */ + do_seek_mark, /* do_seek_mark */ + do_next_mark, /* do_next_mark */ + do_end_read, /* do_end_read */ + do_begin_write, /* do_begin_write */ + do_set_mark, /* do_set_mark */ + do_get_write_buf, /* do_get_write_buf */ + do_write, /* do_write */ + do_get_align_cnt, /* do_get_align_cnt */ + do_end_write, /* do_end_write */ + 0, /* do_fsf */ + 0, /* do_bsf */ + do_rewind, /* do_rewind */ + do_erase, /* do_erase */ + 0, /* do_eject_media */ + do_get_device_class, /* do_get_device_class */ + 0, /* do_display_metrics */ + do_quit, /* do_quit */ +}; + +/* definition of locally defined global functions ****************************/ + + +/* definition of locally defined static functions ****************************/ + +/* strategy match - determines if this is the right strategy + */ +/* ARGSUSED */ +static intgen_t +ds_match( int argc, char *argv[], drive_t *drivep, bool_t singlethreaded ) +{ + bool_t isrmtpr; + struct stat64 statbuf; + + /* sanity checks + */ + ASSERT( ! ( sizeofmember( drive_context_t, dc_buf ) % PGSZ )); + + /* determine if this is an rmt file. if so, give a weak match: + * might be an ordinary file accessed via the rmt protocol. + */ + if ( strchr( drivep->d_pathname, ':') ) { + isrmtpr = BOOL_TRUE; + } else { + isrmtpr = BOOL_FALSE; + } + if ( isrmtpr ) { + return 1; + } + + /* willing to pick up anything not picked up by other strategies, + * as long as it exists and is not a directory + */ + if ( ! strcmp( drivep->d_pathname, "stdio" )) { + return 1; + } + + if ( stat64( drivep->d_pathname, &statbuf )) { + return -1; + } + + if ( ( statbuf.st_mode & S_IFMT ) == S_IFDIR ) { + return -1; + } + + return 1; +} + +/* strategy instantiate - initializes the pre-allocated drive descriptor + */ +/*ARGSUSED*/ +static bool_t +ds_instantiate( int argc, char *argv[], drive_t *drivep, bool_t singlethreaded ) +{ + drive_context_t *contextp; + + /* hook up the drive ops + */ + drivep->d_opsp = &drive_ops; + + /* initialize the drive context - allocate a page-aligned + * structure, so the buffer is page-aligned. + */ + contextp = ( drive_context_t * )memalign( PGSZ, + sizeof( drive_context_t )); + ASSERT( contextp ); + ASSERT( ! ( ( intgen_t )contextp & PGMASK )); + ASSERT( ( void * )contextp->dc_buf == ( void * )contextp ); + memset( ( void * )contextp, 0, sizeof( *contextp )); + + /* scan drive device pathname to see if remote tape + */ + if ( strchr( drivep->d_pathname, ':') ) { + contextp->dc_isrmtpr = BOOL_TRUE; + } else { + contextp->dc_isrmtpr = BOOL_FALSE; + } + + /* determine drive capabilities of and open the named file. + */ + drivep->d_capabilities = 0; + drivep->d_capabilities |= DRIVE_CAP_AUTOREWIND; + if ( ! strcmp( drivep->d_pathname, "stdio" )) { +#ifdef DUMP + contextp->dc_fd = 1; +#endif /* DUMP */ +#ifdef RESTORE + drivep->d_capabilities |= DRIVE_CAP_READ; + contextp->dc_fd = 0; +#endif /* RESTORE */ + } else if ( contextp->dc_isrmtpr ) { + intgen_t oflags; +#ifdef DUMP + oflags = O_WRONLY | O_CREAT | O_TRUNC; +#endif /* DUMP */ +#ifdef RESTORE + oflags = O_RDONLY; + drivep->d_capabilities |= DRIVE_CAP_READ; +#endif /* RESTORE */ + contextp->dc_rampr = BOOL_FALSE; + contextp->dc_fd = open( drivep->d_pathname, + oflags, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); + if ( contextp->dc_fd < 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "unable to open %s: %s\n", + drivep->d_pathname, + strerror( errno )); + return BOOL_FALSE; + } + } else { + intgen_t oflags = 0; + struct stat statbuf; + intgen_t rval; + rval = stat( drivep->d_pathname, &statbuf ); +#ifdef DUMP + if ( rval ) { + if ( errno != ENOENT ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "stat of %s failed: %s\n", + drivep->d_pathname, + strerror( errno )); + return BOOL_FALSE; + } + drivep->d_capabilities |= DRIVE_CAP_REWIND; + drivep->d_capabilities |= DRIVE_CAP_READ; + drivep->d_capabilities |= DRIVE_CAP_ERASE; + contextp->dc_rampr = BOOL_TRUE; + oflags = O_RDWR | O_CREAT; + + } else { + switch( statbuf.st_mode & S_IFMT ) { + case S_IFREG: + drivep->d_capabilities |= DRIVE_CAP_ERASE; + drivep->d_capabilities |= DRIVE_CAP_REWIND; + drivep->d_capabilities |= DRIVE_CAP_READ; + contextp->dc_rampr = BOOL_TRUE; + oflags = O_RDWR; + break; + case S_IFCHR: + contextp->dc_israwdevpr = BOOL_TRUE; + /* intentional fall-through */ + case S_IFBLK: + /* intentional fall-through */ + case S_IFIFO: + oflags = O_WRONLY; + break; + default: + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "cannot dump to %s " + "file type %x\n", + drivep->d_pathname, + statbuf.st_mode & S_IFMT ); + return BOOL_FALSE; + } + } +#endif /* DUMP */ +#ifdef RESTORE + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "stat of %s failed: %s\n", + drivep->d_pathname, + strerror( errno )); + return BOOL_FALSE; + + } + oflags = O_RDONLY; + switch( statbuf.st_mode & S_IFMT ) { + case S_IFREG: + case S_IFCHR: + case S_IFBLK: + drivep->d_capabilities |= DRIVE_CAP_REWIND; + drivep->d_capabilities |= DRIVE_CAP_READ; + break; + case S_IFIFO: + drivep->d_capabilities |= DRIVE_CAP_READ; + break; + default: + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "cannot restore from %s " + "file type %x\n", + drivep->d_pathname, + statbuf.st_mode & S_IFMT ); + return BOOL_FALSE; + } +#endif /* RESTORE */ + contextp->dc_fd = open( drivep->d_pathname, + oflags, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ); + if ( contextp->dc_fd < 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "unable to open %s: %s\n", + drivep->d_pathname, + strerror( errno )); + return BOOL_FALSE; + } + } + + /* initialize the operational mode. fmarkcnt is bumped on each + * end_read and end_write, set back to 0 on rewind. + */ + contextp->dc_mode = OM_NONE; + contextp->dc_fmarkcnt = 0; + + drivep->d_contextp = ( void * )contextp; + + drivep->d_cap_est = -1; + drivep->d_rate_est = -1; + + return BOOL_TRUE; +} + +/* drive op init - second pass drive manager init - nothing to do, + * since async I/O not used. + */ +/* ARGSUSED */ +static bool_t +do_init( drive_t *drivep ) +{ +#ifdef DUMP + drive_hdr_t *dwhdrp = drivep->d_writehdrp; + media_hdr_t *mwhdrp = ( media_hdr_t * )dwhdrp->dh_upper; +#endif /* DUMP */ + +#ifdef DUMP + /* fill in media strategy id: artifact of first version of xfsdump + */ + mwhdrp->mh_strategyid = MEDIA_STRATEGY_SIMPLE; +#endif /* DUMP */ + + return BOOL_TRUE; +} + +/* drive op init - third pass drive manager init - nothing to do, + * since async I/O not used. + */ +/* ARGSUSED */ +static bool_t +do_sync( drive_t *drivep ) +{ + return BOOL_TRUE; +} + +/* drive op begin_read - prepare file for reading - main job is to + * read the media hdr + */ +static intgen_t +do_begin_read( drive_t *drivep ) +{ +#ifdef DEBUG + intgen_t dcaps = drivep->d_capabilities; +#endif + global_hdr_t *grhdrp = drivep->d_greadhdrp; + drive_hdr_t *drhdrp = drivep->d_readhdrp; + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + intgen_t nread; + intgen_t rval; + global_hdr_t *tmphdr = (global_hdr_t *)malloc(GLOBAL_HDR_SZ); + drive_hdr_t *tmpdh = (drive_hdr_t *)tmphdr->gh_upper; + media_hdr_t *tmpmh = (media_hdr_t *)tmpdh->dh_upper; + content_hdr_t *tmpch = (content_hdr_t *)tmpmh->mh_upper; + content_inode_hdr_t *tmpcih = (content_inode_hdr_t *)tmpch->ch_specific; + drive_hdr_t *dh = (drive_hdr_t *)grhdrp->gh_upper; + media_hdr_t *mh = (media_hdr_t *)dh->dh_upper; + content_hdr_t *ch = (content_hdr_t *)mh->mh_upper; + content_inode_hdr_t *cih = (content_inode_hdr_t *)ch->ch_specific; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple begin_read( )\n" ); + + /* verify protocol being followed + */ + ASSERT( dcaps & DRIVE_CAP_READ ); + ASSERT( contextp->dc_fd >= 0 ); + ASSERT( contextp->dc_mode == OM_NONE ); + + /* can only read one media file + */ + if ( contextp->dc_fmarkcnt > 0 ) { + return DRIVE_ERROR_EOM; + } + + /* prepare the drive context + */ + contextp->dc_ownedp = 0; + contextp->dc_emptyp = &contextp->dc_buf[ 0 ]; + contextp->dc_nextp = contextp->dc_emptyp; + contextp->dc_bufstroff = 0; + + /* read the global header using the read_buf() utility function and + * my own read and return_read_buf operators. spoof the mode + */ + contextp->dc_mode = OM_READ; + + nread = read_buf( ( char * )tmphdr, + GLOBAL_HDR_SZ, + ( void * )drivep, + ( rfp_t )drivep->d_opsp->do_read, + ( rrbfp_t )drivep->d_opsp->do_return_read_buf, + &rval ); + contextp->dc_mode = OM_NONE; + + /* if EOD and nread is zero, there is no data after the file mark + */ + if ( rval == DRIVE_ERROR_EOD ) { + if ( nread == 0 ) { + free(tmphdr); + return DRIVE_ERROR_BLANK; + } else { + free(tmphdr); + return DRIVE_ERROR_FORMAT; + } + } + if ( rval ) { + free(tmphdr); + return rval; + } + ASSERT( ( size_t )nread == GLOBAL_HDR_SZ ); + + mlog(MLOG_NITTY, "do_begin_read: global_hdr\n" + "\tgh_magic %.100s\n" + "\tgh_version %u\n" + "\tgh_checksum %u\n" + "\tgh_timestamp %u\n" + "\tgh_ipaddr %llu\n" + "\tgh_hostname %.100s\n" + "\tgh_dumplabel %.100s\n", + tmphdr->gh_magic, + tmphdr->gh_version, + tmphdr->gh_checksum, + tmphdr->gh_timestamp, + tmphdr->gh_ipaddr, + tmphdr->gh_hostname, + tmphdr->gh_dumplabel); + + /* check the checksum + */ + if ( ! global_hdr_checksum_check( tmphdr )) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "media file header checksum error\n" ); + free(tmphdr); + return DRIVE_ERROR_CORRUPTION; + } + + xlate_global_hdr(tmphdr, grhdrp, 1); + xlate_drive_hdr(tmpdh, dh, 1); + *(( drive_mark_t * )dh->dh_specific) = + INT_GET(*(( drive_mark_t * )tmpdh->dh_specific), ARCH_CONVERT); + xlate_media_hdr(tmpmh, mh, 1); + xlate_content_hdr(tmpch, ch, 1); + xlate_content_inode_hdr(tmpcih, cih, 1); + free(tmphdr); + + /* check the magic number + */ + if ( strncmp( grhdrp->gh_magic, GLOBAL_HDR_MAGIC, GLOBAL_HDR_MAGIC_SZ)) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "media file header magic number mismatch: %s, %s\n", + grhdrp->gh_magic, + GLOBAL_HDR_MAGIC); + return DRIVE_ERROR_FORMAT; + } + + /* check the version + */ + if ( global_version_check( grhdrp->gh_version ) != BOOL_TRUE ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "unrecognized media file header version (%d)\n", + grhdrp->gh_version ); + return DRIVE_ERROR_VERSION; + } + + /* check the strategy id + */ + if ( drhdrp->dh_strategyid != drive_strategy_simple.ds_id ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "unrecognized drive strategy ID " + "(media says %d, expected %d)\n", + drhdrp->dh_strategyid, drive_strategy_simple.ds_id ); + return DRIVE_ERROR_FORMAT; + } + + /* record the offset of the first mark + */ + contextp->dc_firstmark = *( drive_mark_t * )drhdrp->dh_specific; + + /* adjust the drive capabilities based on presence of first mark. + * this is a hack workaround for a bug in xfsdump which causes the + * first mark offset to not always be placed in the hdr. + */ + if ( contextp->dc_firstmark ) { + drivep->d_capabilities |= DRIVE_CAP_NEXTMARK; + } + + /* note that a successful begin_read ocurred + */ + contextp->dc_mode = OM_READ; + return 0; +} + +/* read - supply the caller with some filled buffer + */ +static char * +do_read( drive_t *drivep, + size_t wantedcnt, + size_t *actualcntp, + intgen_t *rvalp ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + size_t remainingcnt; + size_t actualcnt; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple read( want %u )\n", + wantedcnt ); + + /* assert protocol + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_ownedp ); + ASSERT( wantedcnt > 0 ); + + /* pre-initialize reference return + */ + *rvalp = 0; + + /* count number of unread bytes in buffer + */ + ASSERT( contextp->dc_emptyp >= contextp->dc_nextp ); + remainingcnt = ( size_t )( contextp->dc_emptyp - contextp->dc_nextp ); + + /* if no unread bytes in buffer, refill + */ + if ( remainingcnt == 0 ) { + size_t bufhowfullcnt; + int nread; + + /* calculate how many bytes were in the buffer. this will + * be used to adjust the recorded offset (relative to the + * beginning of the media file) of the top of the buffer + * after we refill the buffer. + */ + bufhowfullcnt = ( size_t ) + ( contextp->dc_emptyp - contextp->dc_buf ); + + /* attempt to fill the buffer. nread may be less if at EOF + */ + nread = read( contextp->dc_fd, contextp->dc_buf, BUFSZ ); + if ( nread < 0 ) { + *rvalp = DRIVE_ERROR_DEVICE; + return 0; + } + + /* adjust the recorded offset of the top of the buffer + * relative to the beginning of the media file + */ + contextp->dc_bufstroff += ( off64_t )bufhowfullcnt; + + /* record the ptrs to the first empty byte and the next + * byte to be read + */ + ASSERT( nread <= BUFSZ ); + contextp->dc_emptyp = contextp->dc_buf + nread; + contextp->dc_nextp = contextp->dc_buf; + + /* if no bytes were read, the caller has seen all bytes. + */ + if ( nread == 0 ) { + *rvalp = DRIVE_ERROR_EOD; + return 0; + } + + /* adjust the remaining count + */ + remainingcnt = ( size_t )nread; + } + + /* the caller specified at most how many bytes he wants. if less + * than that remain unread in buffer, just return that many. + */ + actualcnt = min( wantedcnt, remainingcnt ); + + /* set the owned ptr to the first byte to be supplied + */ + contextp->dc_ownedp = contextp->dc_nextp; + + /* advance the next ptr to the next byte to be supplied + */ + contextp->dc_nextp += actualcnt; + ASSERT( contextp->dc_nextp <= contextp->dc_emptyp ); + + /* return the actual number of bytes supplied, and a ptr to the first + */ + *actualcntp = actualcnt; + return contextp->dc_ownedp; +} + +/* return_read_buf - lets the caller give back all of the + * buffer obtained from a call to do_read(). + */ +/* ARGSUSED */ +static void +do_return_read_buf( drive_t *drivep, char *retp, size_t retcnt ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + /* REFERENCED */ + size_t ownedcnt; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple return_read_buf( returning %u )\n", + retcnt ); + + /* verify protocol + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( contextp->dc_ownedp ); + + /* verify returning right buffer + */ + ASSERT( retp == contextp->dc_ownedp ); + + /* verify all of buffer provided is being returned + */ + ownedcnt = ( size_t )( contextp->dc_nextp - contextp->dc_ownedp ); + ASSERT( retcnt == ownedcnt ); + + /* indicate nothing now owned by caller + */ + contextp->dc_ownedp = 0; +} + +/* the mark is simply the offset into the media file of the + * next byte to be read + */ +static void +do_get_mark( drive_t *drivep, drive_mark_t *markp ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + off64_t nextoff; + off64_t strmoff; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple get_mark( )\n" ); + + /* assert protocol + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_ownedp ); + + /* calculate the offset of the next byte to be supplied relative to + * the beginning of the buffer and relative to the beginning of + * ther media file. + */ + nextoff = ( off64_t )( contextp->dc_nextp - contextp->dc_buf ); + strmoff = contextp->dc_bufstroff + nextoff; + *markp = ( drive_mark_t )strmoff; +} + +/* seek forward to the specified mark. the caller must not have already read + * past that point. + */ +static intgen_t +do_seek_mark( drive_t *drivep, drive_mark_t *markp ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + off64_t mark = *( off64_t * )markp; + off64_t nextoff; + off64_t strmoff; + /* REFERENCED */ + intgen_t nread; + off64_t nreadneeded64; + intgen_t nreadneeded; + intgen_t rval; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple seek_mark( )\n" ); + + /* assert protocol + */ + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_ownedp ); + + /* calculate the current offset within the media file + * of the next byte to be read + */ + nextoff = ( off64_t )( contextp->dc_nextp - contextp->dc_buf ); + strmoff = contextp->dc_bufstroff + nextoff; + + /* if the caller attempts to seek past the current offset, + * this is really bad + */ + if ( strmoff > mark ) { + return DRIVE_ERROR_CORE; + } + + /* use read_buf util func to eat up difference + */ + nreadneeded64 = mark - strmoff; + ASSERT( nreadneeded64 <= INTGENMAX ); + nreadneeded = ( intgen_t )nreadneeded64; + nread = read_buf( 0, + ( size_t )nreadneeded, + ( void * )drivep, + ( rfp_t )drivep->d_opsp->do_read, + ( rrbfp_t )drivep->d_opsp->do_return_read_buf, + &rval ); + if ( rval ) { + return rval; + } + ASSERT( nread == nreadneeded ); + + /* verify we are on the mark + */ + nextoff = ( off64_t )( contextp->dc_nextp - contextp->dc_buf ); + strmoff = contextp->dc_bufstroff + nextoff; + ASSERT( strmoff == mark ); + + return 0; +} + +/* seek forward to the next mark. we only know of one mark, the first + * mark in the media file (recorded in the header). if the caller + * has already read past that mark, blow up. + */ +static intgen_t +do_next_mark( drive_t *drivep ) +{ +#ifdef DEBUG + intgen_t dcaps = drivep->d_capabilities; +#endif + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + drive_mark_t mark = contextp->dc_firstmark; + intgen_t rval; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple next_mark( )\n" ); + + /* assert protocol + */ + ASSERT( dcaps & DRIVE_CAP_NEXTMARK ); + ASSERT( contextp->dc_mode == OM_READ ); + ASSERT( ! contextp->dc_ownedp ); + + if ( ! mark ) { + return DRIVE_ERROR_EOF; + } + + rval = do_seek_mark( drivep, ( drive_mark_t * )&mark ); + if ( rval ) { + return rval; + } + + return 0; +} + +/* end_read - tell the drive we are done reading the media file + * just discards any buffered data + */ +void +do_end_read( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple end_read( )\n" ); + + /* be sure we are following protocol + */ + ASSERT( contextp->dc_mode == OM_READ ); + contextp->dc_mode = OM_NONE; + + /* bump the file mark cnt + */ + contextp->dc_fmarkcnt++; + ASSERT( contextp->dc_fmarkcnt == 1 ); +} + +/* begin_write - prepare file for writing + */ +static intgen_t +do_begin_write( drive_t *drivep ) +{ + intgen_t dcaps = drivep->d_capabilities; + global_hdr_t *gwhdrp = drivep->d_gwritehdrp; + drive_hdr_t *dwhdrp = drivep->d_writehdrp; + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + int rval; + global_hdr_t *tmphdr; + drive_hdr_t *tmpdh; + media_hdr_t *tmpmh; + content_hdr_t *tmpch; + content_inode_hdr_t *tmpcih; + drive_hdr_t *dh = (drive_hdr_t *)gwhdrp->gh_upper; + media_hdr_t *mh = (media_hdr_t *)dh->dh_upper; + content_hdr_t *ch = (content_hdr_t *)mh->mh_upper; + content_inode_hdr_t *cih = (content_inode_hdr_t *)ch->ch_specific; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple begin_write( )\n" ); + + /* sanity checks + */ + ASSERT( dwhdrp->dh_strategyid == DRIVE_STRATEGY_SIMPLE ); + + /* assert protocol + */ + ASSERT( contextp->dc_fd >= 0 ); + ASSERT( contextp->dc_mode == OM_NONE ); + + /* only one media file may be written + */ + if ( contextp->dc_fmarkcnt > 0 ) { + return DRIVE_ERROR_EOM; + } + + /* indicate in the header that there is no recorded mark. + */ + *( ( off64_t * )dwhdrp->dh_specific ) = 0; + + /* prepare the drive context. initially the caller does not own + * any of the write buffer, so the next portion of the buffer to + * be supplied is the top of the buffer. emptyp never changes; + * it always points to the byte after the end of the buffer. markcnt + * keeps track of the number marks the caller has set in the media file. + */ + contextp->dc_ownedp = 0; + contextp->dc_nextp = contextp->dc_buf; + contextp->dc_emptyp = contextp->dc_buf + sizeof( contextp->dc_buf ); + contextp->dc_bufstroff = 0; + contextp->dc_markcnt = 0; + + /* truncate the destination if it supports read. + */ + if ( dcaps & DRIVE_CAP_READ ) { + rval = ftruncate( contextp->dc_fd, 0 ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "attempt to truncate %s failed: " + "%d (%s)\n", + drivep->d_pathname, + errno, + strerror( errno )); + } + } + + /* set the mode + */ + contextp->dc_mode = OM_WRITE; + + tmphdr = (global_hdr_t *)malloc(GLOBAL_HDR_SZ); + ASSERT(tmphdr); + memset(tmphdr, 0, GLOBAL_HDR_SZ); + tmpdh = (drive_hdr_t *)tmphdr->gh_upper; + tmpmh = (media_hdr_t *)tmpdh->dh_upper; + tmpch = (content_hdr_t *)tmpmh->mh_upper; + tmpcih = (content_inode_hdr_t *)tmpch->ch_specific; + + xlate_global_hdr(gwhdrp, tmphdr, 1); + xlate_drive_hdr(dh, tmpdh, 1); + INT_SET(*(( drive_mark_t * )tmpdh->dh_specific), + ARCH_CONVERT, + *(( drive_mark_t * )dh->dh_specific)); + xlate_media_hdr(mh, tmpmh, 1); + xlate_content_hdr(ch, tmpch, 1); + xlate_content_inode_hdr(cih, tmpcih, 1); + + /* checksum the header + */ + global_hdr_checksum_set( tmphdr ); + + mlog(MLOG_NITTY, "do_begin_write: global_hdr\n" + "\tgh_magic %.100s\n" + "\tgh_version %u\n" + "\tgh_checksum %u\n" + "\tgh_timestamp %u\n" + "\tgh_ipaddr %llu\n" + "\tgh_hostname %.100s\n" + "\tgh_dumplabel %.100s\n", + tmphdr->gh_magic, + tmphdr->gh_version, + tmphdr->gh_checksum, + tmphdr->gh_timestamp, + tmphdr->gh_ipaddr, + tmphdr->gh_hostname, + tmphdr->gh_dumplabel); + + if ( ! global_hdr_checksum_check( tmphdr )) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_DRIVE, + "media file header checksum error\n" ); + } + else { + mlog( MLOG_NITTY, "media file header checksum OK!\n" ); + } + + /* write the header using the write_buf() utility function and + * my own get_write_buf and write operators. + */ + rval = write_buf( ( char * )tmphdr, + GLOBAL_HDR_SZ, + ( void * )drivep, + ( gwbfp_t )drivep->d_opsp->do_get_write_buf, + ( wfp_t )drivep->d_opsp->do_write ); + + free(tmphdr); + + /* if error while writing hdr, undo mode + */ + if ( rval ) { + contextp->dc_mode = OM_NONE; + } + + return rval; +} + +/* do_set_mark - record a markrecord and callback + */ +static void +do_set_mark( drive_t *drivep, + drive_mcbfp_t cbfuncp, + void *cbcontextp, + drive_markrec_t *markrecp ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + drive_mark_t mark; + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple set_mark( )\n" ); + + /* assert protocol + */ + ASSERT( contextp->dc_mode == OM_WRITE ); + ASSERT( ! contextp->dc_ownedp ); + ASSERT( contextp->dc_nextp ); + + /* calculate the mark offset + */ + mark = ( drive_mark_t )( contextp->dc_bufstroff + + + ( off64_t ) + ( contextp->dc_nextp - contextp->dc_buf )); + + /* fill in the mark field of the mark record + */ + markrecp->dm_log = mark; + + /* bump the mark count. if this is the first mark, record it + * in the drive strategy-specific header. this allows multiple + * media object restores to work. NOTE that the mark will not + * be recorded if the destination does not support random access + * and the write buffer has been flushed at least once. + * this is hidden by save_first_mark, and detected during restore + * by noting the first mark offset is NULL. to do this, must seek + * back to the header, rewrite and rechecksum the header, + * and seek back to the current position. HOWEVER, if the write + * buffer has not yet been flushed, we can just edit the buffer. + */ + contextp->dc_markcnt++; + if ( contextp->dc_markcnt == 1 ) { + if ( contextp->dc_bufstroff == 0 ) { + /* cast the write buffer into a media file hdr + */ + global_hdr_t *gwhdrp = + ( global_hdr_t * )contextp->dc_buf; + drive_hdr_t *dwhdrp = ( drive_hdr_t * )gwhdrp->gh_upper; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "re-writing media file header with first mark " + "(in buffer)\n" ); + + /* record mark in hdr + */ + INT_SET(*( ( drive_mark_t * )dwhdrp->dh_specific ), ARCH_CONVERT, mark); + + /* adjust header checksum + */ + global_hdr_checksum_set( gwhdrp ); + + } else if ( contextp->dc_rampr ) { + global_hdr_t *gwhdrp = drivep->d_gwritehdrp; + drive_hdr_t *dwhdrp = drivep->d_writehdrp; + off64_t newoff; + /* REFERENCED */ + intgen_t nwritten; + + /* assert the header has been flushed + */ + ASSERT( contextp->dc_bufstroff >= sizeof( *gwhdrp )); + + /* record mark in hdr + */ + INT_SET(*( ( drive_mark_t * )dwhdrp->dh_specific ), ARCH_CONVERT, mark); + + /* adjust header checksum + */ + global_hdr_checksum_set( gwhdrp ); + + /* seek to beginning + */ + newoff = lseek64( contextp->dc_fd, ( off64_t )0, SEEK_SET ); + if ( newoff < 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "could not save first mark: %d (%s)\n", + errno, + strerror( errno )); + } else { + global_hdr_t *tmphdr; + drive_hdr_t *tmpdh; + media_hdr_t *tmpmh; + content_hdr_t *tmpch; + content_inode_hdr_t *tmpcih; + drive_hdr_t *dh = (drive_hdr_t *)gwhdrp->gh_upper; + media_hdr_t *mh = (media_hdr_t *)dh->dh_upper; + content_hdr_t *ch = (content_hdr_t *)mh->mh_upper; + content_inode_hdr_t *cih = (content_inode_hdr_t *)ch->ch_specific; + + ASSERT( newoff == 0 ); + + /* write and seek back to current offset + */ + mlog( MLOG_NITTY | MLOG_DRIVE, + "re-writing media file header " + "with first mark " + "(on media)\n" ); + + tmphdr = (global_hdr_t *)malloc(GLOBAL_HDR_SZ); + ASSERT(tmphdr); + tmpdh = (drive_hdr_t *)tmphdr->gh_upper; + tmpmh = (media_hdr_t *)tmpdh->dh_upper; + tmpch = (content_hdr_t *)tmpmh->mh_upper; + tmpcih = (content_inode_hdr_t *)tmpch->ch_specific; + xlate_global_hdr(gwhdrp, tmphdr, 1); + xlate_drive_hdr(dh, tmpdh, 1); + INT_SET(*(( drive_mark_t * )tmpdh->dh_specific), + ARCH_CONVERT, + *(( drive_mark_t * )dh->dh_specific)); + xlate_media_hdr(mh, tmpmh, 1); + xlate_content_hdr(ch, tmpch, 1); + xlate_content_inode_hdr(cih, tmpcih, 1); + + /* adjust header checksum + */ + global_hdr_checksum_set( tmphdr ); + + mlog(MLOG_NITTY, "do_set_mark: global_hdr\n" + "\tgh_magic %.100s\n" + "\tgh_version %u\n" + "\tgh_checksum %u\n" + "\tgh_timestamp %u\n" + "\tgh_ipaddr %llu\n" + "\tgh_hostname %.100s\n" + "\tgh_dumplabel %.100s\n", + tmphdr->gh_magic, + tmphdr->gh_version, + tmphdr->gh_checksum, + tmphdr->gh_timestamp, + tmphdr->gh_ipaddr, + tmphdr->gh_hostname, + tmphdr->gh_dumplabel); + + nwritten = write( contextp->dc_fd, + tmphdr, + sizeof( *tmphdr )); + ASSERT( ( size_t )nwritten == sizeof( *tmphdr )); + free(tmphdr); + + newoff = lseek64( contextp->dc_fd, + contextp->dc_bufstroff, + SEEK_SET ); + ASSERT( newoff == contextp->dc_bufstroff ); + } + } + } + + /* if all written are committed, send the mark back immediately. + * otherwise put the mark record on the tail of the queue. + */ + if ( contextp->dc_nextp == contextp->dc_buf ) { + ASSERT( drivep->d_markrecheadp == 0 ); + ( * cbfuncp )( cbcontextp, markrecp, BOOL_TRUE ); + return; + } else { + markrecp->dm_cbfuncp = cbfuncp; + markrecp->dm_cbcontextp = cbcontextp; + markrecp->dm_nextp = 0; + if ( drivep->d_markrecheadp == 0 ) { + drivep->d_markrecheadp = markrecp; + drivep->d_markrectailp = markrecp; + } else { + ASSERT( drivep->d_markrectailp ); + drivep->d_markrectailp->dm_nextp = markrecp; + drivep->d_markrectailp = markrecp; + } + } +} + +/* get_write_buf - supply the caller with buffer space. the caller + * will fill the space with data, then call write() to request that + * some or all of the buffer be written and to return the buffer space. + */ +/*ARGSUSED*/ +static char * +do_get_write_buf( drive_t *drivep, size_t wanted_bufsz, size_t *actual_bufszp ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + size_t remaining_bufsz; + size_t actual_bufsz; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple get_write_buf( want %u )\n", + wanted_bufsz ); + + /* assert protocol + */ + ASSERT( contextp->dc_mode == OM_WRITE ); + ASSERT( ! contextp->dc_ownedp ); + ASSERT( contextp->dc_nextp ); + ASSERT( contextp->dc_nextp < contextp->dc_emptyp ); + ASSERT( contextp->dc_ownedsz == 0 ); + + /* calculate how much buffer remains + */ + remaining_bufsz =( size_t )( contextp->dc_emptyp - contextp->dc_nextp ); + + /* give the caller the lesser of what he wants and what is available + */ + actual_bufsz = min( wanted_bufsz, remaining_bufsz ); + + /* caller will own that portion of buffer + */ + contextp->dc_ownedp = contextp->dc_nextp; + contextp->dc_ownedsz = actual_bufsz; + + /* won't know nextp until write + */ + contextp->dc_nextp = 0; + + /* return the portion of the buffer to the caller + */ + *actual_bufszp = actual_bufsz; + return contextp->dc_ownedp; +} + +/* write - write and accept ownership of the portion of the buffer owned by the + * caller. + */ +/*ARGSUSED*/ +static intgen_t +do_write( drive_t *drivep, char *bufp, size_t writesz ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + off64_t ownedstroff = contextp->dc_bufstroff + + + ( off64_t ) + ( contextp->dc_ownedp - contextp->dc_buf ); + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple write( " + "offset %lld (0x%llx 0%llo) " + "size %u (0x%x 0%o) " + ")\n", + ownedstroff, + ownedstroff, + ownedstroff, + writesz, + writesz, + writesz, + 0 ); + + /* assert protocol + */ + ASSERT( contextp->dc_mode == OM_WRITE ); + ASSERT( contextp->dc_ownedp ); + ASSERT( bufp == contextp->dc_ownedp ); + ASSERT( ! contextp->dc_nextp ); + ASSERT( contextp->dc_ownedp < contextp->dc_emptyp ); + ASSERT( writesz == contextp->dc_ownedsz ); + + /* calculate next portion of buffer available for get_write_buf, + * and indicate no portion is owned. + */ + contextp->dc_nextp = contextp->dc_ownedp + writesz; + ASSERT( contextp->dc_nextp <= contextp->dc_emptyp ); + contextp->dc_ownedp = 0; + contextp->dc_ownedsz = 0; + + if ( writesz == 0 ) { + return 0; /* returning unused buffer */ + } + + /* if buffer is full, flush it + */ + if ( contextp->dc_nextp == contextp->dc_emptyp ) { + intgen_t nwritten; + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "flushing write buf addr 0x%x size 0x%x\n", + contextp->dc_buf, + sizeof( contextp->dc_buf )); + + contextp->dc_nextp = 0; + nwritten = write( contextp->dc_fd, + contextp->dc_buf, + sizeof( contextp->dc_buf )); + if ( nwritten < 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "write to %s failed: %d (%s)\n", + drivep->d_pathname, + errno, + strerror( errno )); + nwritten = 0; + } + contextp->dc_bufstroff += ( off64_t )nwritten; + drive_mark_commit( drivep, contextp->dc_bufstroff ); + contextp->dc_nextp = contextp->dc_buf; + if ( ( size_t )nwritten < sizeof( contextp->dc_buf )) { + return DRIVE_ERROR_EOM; + } + } + + return 0; +} + +/* get_align_cnt - returns the number of bytes which must be written to + * cause the next call to get_write_buf() to be page-aligned. + */ +static size_t +do_get_align_cnt( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + __psint_t next_alignment_off; + char *next_alignment_point; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple get_align_cnt( )\n" ); + + /* assert protocol + */ + ASSERT( contextp->dc_mode == OM_WRITE ); + ASSERT( ! contextp->dc_ownedp ); + ASSERT( contextp->dc_nextp ); + ASSERT( contextp->dc_nextp < contextp->dc_emptyp ); + + /* calculate the next alignment point at or beyond the current nextp. + * the following algorithm works because dc_buf is page-aligned and + * a multiple of PGSZ. + */ + next_alignment_off = ( __psint_t )contextp->dc_nextp; + next_alignment_off += PGMASK; + next_alignment_off &= ~PGMASK; + next_alignment_point = ( char * )next_alignment_off; + ASSERT( next_alignment_point <= contextp->dc_emptyp ); + + /* return the number of bytes to the next alignment point + */ + return ( size_t )( next_alignment_point - contextp->dc_nextp ); +} + +/* end_write - flush any buffered data, and return by reference how many + * bytes were committed. + */ +static intgen_t +do_end_write( drive_t *drivep, off64_t *ncommittedp ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + size_t remaining_bufsz; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple end_write( )\n" ); + + /* assert protocol + */ + ASSERT( contextp->dc_mode == OM_WRITE ); + ASSERT( ! contextp->dc_ownedp ); + ASSERT( contextp->dc_nextp ); + ASSERT( contextp->dc_nextp < contextp->dc_emptyp ); + + /* calculate length of un-written portion of buffer + */ + ASSERT( contextp->dc_nextp >= contextp->dc_buf ); + remaining_bufsz = ( size_t )( contextp->dc_nextp - contextp->dc_buf ); + + if ( remaining_bufsz ) { + int nwritten; + if ( contextp->dc_israwdevpr ) { + remaining_bufsz = ( remaining_bufsz + ( BBSIZE - 1 )) + & + ~( BBSIZE - 1 ); + } + + mlog( MLOG_DEBUG | MLOG_DRIVE, + "flushing write buf addr 0x%x size 0x%x\n", + contextp->dc_buf, + remaining_bufsz ); + + nwritten = write( contextp->dc_fd, + contextp->dc_buf, + remaining_bufsz ); + if ( nwritten < 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "write to %s failed: %d (%s)\n", + drivep->d_pathname, + errno, + strerror( errno )); + drive_mark_discard( drivep ); + *ncommittedp = contextp->dc_bufstroff; + contextp->dc_mode = OM_NONE; + return DRIVE_ERROR_DEVICE; + } + contextp->dc_bufstroff += ( off64_t )nwritten; + drive_mark_commit( drivep, contextp->dc_bufstroff ); + if ( ( size_t )nwritten < remaining_bufsz ) { + *ncommittedp = contextp->dc_bufstroff; + contextp->dc_mode = OM_NONE; + return DRIVE_ERROR_EOM; + } + } + + /* bump the file mark cnt + */ + contextp->dc_fmarkcnt++; + ASSERT( contextp->dc_fmarkcnt == 1 ); + + *ncommittedp = contextp->dc_bufstroff; + contextp->dc_mode = OM_NONE; + return 0; +} + +/* rewind - return the current file offset to the beginning + */ +intgen_t +do_rewind( drive_t *drivep ) +{ +#ifdef DEBUG + intgen_t dcaps = drivep->d_capabilities; +#endif + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + off64_t newoff; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple rewind( )\n" ); + + /* assert protocol + */ + ASSERT( contextp->dc_mode == OM_NONE ); + ASSERT( dcaps & DRIVE_CAP_REWIND ); + ASSERT( contextp->dc_fd >= 0 ); + + /* seek to beginning of file + */ + newoff = lseek64( contextp->dc_fd, ( off64_t )0, SEEK_SET ); + if ( newoff ) { + ASSERT( newoff < 0 ); + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "could not rewind %s: %s\n", + drivep->d_pathname, + strerror( errno )); + return DRIVE_ERROR_DEVICE; + } + + return 0; +} + +/* erase - truncate to zero length + */ +intgen_t +do_erase( drive_t *drivep ) +{ +#ifdef DEBUG + intgen_t dcaps = drivep->d_capabilities; +#endif + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + off64_t newoff; + intgen_t rval; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple erase( )\n" ); + + /* assert protocol + */ + ASSERT( contextp->dc_mode == OM_NONE ); + ASSERT( dcaps & DRIVE_CAP_ERASE ); + ASSERT( contextp->dc_fd >= 0 ); + + /* seek to beginning of file + */ + newoff = lseek64( contextp->dc_fd, ( off64_t )0, SEEK_SET ); + if ( newoff ) { + ASSERT( newoff < 0 ); + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "could not rewind %s in prep for erase: %s\n", + drivep->d_pathname, + strerror( errno )); + return DRIVE_ERROR_DEVICE; + } + + /* erase to beginning of file + */ + rval = ftruncate64( contextp->dc_fd, ( off64_t )0 ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_DRIVE, + "could not erase %s: %s (%d)\n", + drivep->d_pathname, + strerror( errno ), + errno ); + return DRIVE_ERROR_DEVICE; + } + contextp->dc_fmarkcnt = 0; + + return 0; +} + +/* get_media_class() + */ +/* ARGSUSED */ +static intgen_t +do_get_device_class( drive_t *drivep ) +{ + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple get_device_class( )\n" ); + ASSERT( drivep ); + return DEVICE_NONREMOVABLE; +} + +static void +do_quit( drive_t *drivep ) +{ + drive_context_t *contextp = ( drive_context_t * )drivep->d_contextp; + + mlog( MLOG_NITTY | MLOG_DRIVE, + "drive_simple quit( )\n" ); + + /* assert protocol + */ + ASSERT( contextp->dc_mode == OM_NONE ); + ASSERT( contextp ); + + /* close file + */ + if ( contextp->dc_fd > 1 ) { + close( contextp->dc_fd ); + } + contextp->dc_fd = -1; + + /* free context + */ + free( ( void * )contextp ); + drivep->d_contextp = 0; +} diff -rNu linux-2.4.7/cmd/xfsdump/common/exit.h linux-2.4-xfs/cmd/xfsdump/common/exit.h --- linux-2.4.7/cmd/xfsdump/common/exit.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/exit.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef EXIT_H +#define EXIT_H + +/* exit codes for main and child processes + */ +#define EXIT_NORMAL 0 /* normal completion / don't exit */ +#define EXIT_ERROR 1 /* resource error or resource exhaustion */ +#define EXIT_INTERRUPT 2 /* interrupted (operator or device error) */ +#define EXIT_FAULT 4 /* code fault */ + +typedef size_t exit_t; + +#endif /* EXIT_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/fs.c linux-2.4-xfs/cmd/xfsdump/common/fs.c --- linux-2.4.7/cmd/xfsdump/common/fs.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/fs.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "mlog.h" +#include "fs.h" + + +/* fs_info - a magic, highly heuristic function to convert a user-supplied + * string into a file system type, character special device pathname, + * a mount point, and file system ID (uuid). The primary source of information + * is the getmntent(3) routines. Correspondence between "standard" disk + * block and character device pathnames is used. The fstyp(1) utility + * may be invoked as well. + * + * returns BOOL_TRUE on success, BOOL_FALSE on failure. + * + * coding rules: to make this very complex and lengthy decision tree + * more graspable, some very strict coding rules were followed: + * + * 1) function arguments are ordered reference returns first, input + * parameters second. + * + * 2) all buffer-like refence return arguments are followed by a + * caller-supplied buffer size. + * + * 3) wherever possible functions return the result buffer pointer. + * + * 4) boolean functions return TRUE on success, FALSE on failure. + * + * all variables, parameters, and structure members are named as follows: + * object types: + * usr - user-specified mystery + * typ - file system type + * mnt - mount point pathname + * blk - block device pathname + * chr - character device pathname + * id - file system ID + * stat - stat buffer + * te - file system table entry + * object modifiers: appended to object type: + * b - buffer + * s - string + * d - default string + * p - pointer + * object size indication modifiers: appended to a modified object type: + * z - buffer size + * l - string length + */ + +/* declarations of externally defined global variables + */ + + +/* definitions used locally + */ +struct fs_tab_ent { + char *fte_blks; + char *fte_mnts; + char *fte_typs; + struct fs_tab_ent *fte_nextp; +}; + +typedef struct fs_tab_ent fs_tab_ent_t; + +static fs_tab_ent_t *fs_tabp; + +/* forward declarations + */ +static void fs_tab_build( void ); +static void fs_tab_free( void ); +static fs_tab_ent_t *fs_tab_ent_build( struct mntent * ); +static void fs_tab_ent_free( fs_tab_ent_t * ); +static fs_tab_ent_t *fs_tab_lookup_blk( char * ); +static fs_tab_ent_t *fs_tab_lookup_mnt( char * ); + +/* ARGSUSED */ +bool_t +fs_info( char *typb, /* out */ + intgen_t typbz, + char *typd, + char *blkb, /* out */ + intgen_t blkbz, + char *mntb, /* out */ + intgen_t mntbz, + uuid_t *idb, /* out */ + char *usrs ) /* in */ +{ + struct stat64 statb; + fs_tab_ent_t *tep; + char *blks; + char *mnts; + char *typs; + bool_t canstat; + bool_t ok = BOOL_UNKNOWN; + + fs_tab_build( ); + + canstat = ( stat64( usrs, &statb ) == 0 ); + if ( canstat && ( statb.st_mode & S_IFMT ) == S_IFBLK ) { + if ( ( tep = fs_tab_lookup_blk( usrs )) != 0 ) { + blks = tep->fte_blks; + ASSERT( strlen( blks ) < ( size_t )blkbz ); + strcpy( blkb, blks ); + mnts = tep->fte_mnts; + if ( mnts ) { + ASSERT( strlen( mnts ) < ( size_t )mntbz ); + strcpy( mntb, mnts ); + } else { + mntb[ 0 ] = 0; + } + if ( ( typs = tep->fte_typs ) == 0 ) { + typs = typd; + } + ASSERT( strlen( typs ) < ( size_t )typbz ); + strcpy( typb, typs ); + ok = BOOL_TRUE; + } else { + ok = BOOL_FALSE; + } + } else if ( ( tep = fs_tab_lookup_mnt( usrs )) != 0 ) { + blks = tep->fte_blks; + ASSERT( strlen( blks ) < ( size_t )blkbz ); + strcpy( blkb, blks ); + mnts = tep->fte_mnts; + ASSERT( strlen( mnts ) < ( size_t )mntbz ); + strcpy( mntb, mnts ); + typs = tep->fte_typs; + ASSERT( strlen( typs ) < ( size_t )typbz ); + strcpy( typb, typs ); + ok = BOOL_TRUE; + } else { + ok = BOOL_FALSE; + } + + fs_tab_free( ); + ASSERT( ok != BOOL_UNKNOWN ); + + if ( ok == BOOL_TRUE ) { + intgen_t rval = fs_getid( mntb, idb ); + if ( rval ) { + mlog( MLOG_NORMAL, + "unable to determine uuid of fs mounted at %s: " + "%s\n", + mntb, + strerror( errno )); + } + { + u_char_t string_uuid[37]; + uuid_unparse( *idb, string_uuid ); + mlog( MLOG_DEBUG, + "fs %s uuid [%s]\n", + mntb, + string_uuid ); + } + } + + return ok; +} + +/* fs_mounted - a predicate determining if the specified file system + * is actually currently mounted at its mount point. + * will not take time to code this now - just check if mntpt is non-NULL. + */ +/* ARGSUSED */ +bool_t +fs_mounted( char *typs, char *chrs, char *mnts, uuid_t *idp ) +{ + return strlen( mnts ) > 0 ? BOOL_TRUE : BOOL_FALSE; +} + +intgen_t +fs_getid( char *mnts, uuid_t *idb ) +{ + uuid_t uuid; + int fd; + + fd = open( mnts, O_RDONLY ); + if ( fd < 0 ) { + uuid_clear( *idb ); + return -1; + } + if ( ioctl(fd, XFS_IOC_GETFSUUID, &uuid ) ) { + uuid_clear( *idb ); + close(fd); + return -1; + } + close(fd); + uuid_copy( *idb, uuid ); + + return 0; +} + +size_t +fs_getinocnt( char *mnts ) +{ + struct statvfs vfsstat; + intgen_t rval; + + rval = statvfs( mnts, &vfsstat ); + if ( rval ) { + return 0; + } + + if ( vfsstat.f_files < vfsstat.f_ffree ) { + return 0; + } + + return ( size_t )( vfsstat.f_files - vfsstat.f_ffree ); +} + +static void +fs_tab_build( void ) +{ + register struct mntent *mntentp; + fs_tab_ent_t *tep; + FILE *fp; + + fs_tabp = 0; + fp = setmntent( MOUNTED, "r" ); + if ( fp == NULL ) { + mlog( MLOG_NORMAL, + "Can't open %s for mount information\n", + MOUNTED ); + return; + } + while ( ( mntentp = getmntent( fp )) != 0 ) { + tep = fs_tab_ent_build( mntentp ); + tep->fte_nextp = fs_tabp; + fs_tabp = tep; + } + endmntent( fp ); +} + +static void +fs_tab_free( void ) +{ + fs_tab_ent_t *tep; + fs_tab_ent_t *otep; + + for ( tep = fs_tabp + ; + tep + ; + otep = tep, tep = tep->fte_nextp, fs_tab_ent_free( otep ) ) + + ; +} + +static fs_tab_ent_t * +fs_tab_ent_build( struct mntent *mntentp ) +{ + fs_tab_ent_t *tep; + char *cp; + + tep = ( fs_tab_ent_t * )calloc( 1, sizeof( fs_tab_ent_t )); + ASSERT( tep ); + + if ( mntentp->mnt_dir ) { + cp = calloc( 1, strlen( mntentp->mnt_dir ) + 1 ); + ASSERT( cp ); + ( void )strcpy( cp, mntentp->mnt_dir ); + tep->fte_mnts = cp; + } else { + tep->fte_mnts = 0; + } + + if ( mntentp->mnt_type ) { + cp = calloc( 1, strlen( mntentp->mnt_type ) + 1 ); + ASSERT( cp ); + ( void )strcpy( cp, mntentp->mnt_type ); + tep->fte_typs = cp; + } else { + tep->fte_typs = 0; + } + + if ( mntentp->mnt_fsname ) { + cp = calloc( 1, strlen( mntentp->mnt_fsname ) + 1 ); + ASSERT( cp ); + ( void )strcpy( cp, mntentp->mnt_fsname ); + tep->fte_blks = cp; + } else { + tep->fte_blks = 0; + } + + return tep; +} + +static void +fs_tab_ent_free( fs_tab_ent_t *tep ) +{ + if ( tep->fte_blks ) free( tep->fte_blks ); + if ( tep->fte_mnts ) free( tep->fte_mnts ); + if ( tep->fte_typs ) free( tep->fte_typs ); + memset( ( void * )tep, 0, sizeof( *tep )); /* bug catcher */ + free( tep ); +} + +static fs_tab_ent_t * +fs_tab_lookup_blk( char *blks ) +{ + fs_tab_ent_t *tep; + + for ( tep = fs_tabp ; tep ; tep = tep->fte_nextp ) { + struct stat64 stata; + bool_t aok; + struct stat64 statb; + bool_t bok; + + if ( ! tep->fte_blks ) { + continue; + } + + if ( ! strcmp( tep->fte_blks, blks )) { + return tep; + } + + aok = ! stat64( blks, &stata ); + bok = ! stat64( tep->fte_blks, &statb ); + if ( aok && bok && stata.st_rdev == statb.st_rdev ) { + return tep; + } + } + return 0; +} + +static fs_tab_ent_t * +fs_tab_lookup_mnt( char *mnts ) +{ + fs_tab_ent_t *tep; + + for ( tep = fs_tabp ; tep ; tep = tep->fte_nextp ) { + if ( tep->fte_mnts && ! strcmp( tep->fte_mnts, mnts )) { + return tep; + } + } + return 0; +} diff -rNu linux-2.4.7/cmd/xfsdump/common/fs.h linux-2.4-xfs/cmd/xfsdump/common/fs.h --- linux-2.4.7/cmd/xfsdump/common/fs.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/fs.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef FS_H +#define FS_H + +/* fs - utilities for examining and manipulating file systems + */ + +/* default maximim path and name lengths + */ +#define FS_MAXNAMELEN_DEFAULT 256 +#define FS_MAXPATHLEN_DEFAULT 1024 + +/* fs_info - decides if a source name describes a file system, and if + * so returns useful information about that file system. + * + * returns BOOL_FALSE if srcname does not describe a file system. + */ +extern bool_t fs_info( char *fstype, /* out: fs type (fsid.h) */ + intgen_t fstypesz, /* in: buffer size */ + char *fstypedef, /* in: default fs type */ + char *fsdevice, /* out: blk spec. dev. file */ + intgen_t fsdevicesz, /* in: buffer size */ + char *mntpt, /* out: where fs mounted */ + intgen_t mntptsz, /* in: buffer size */ + uuid_t *fsid, /* out: fs uuid */ + char *srcname ); /* in: how user named the fs */ + +/* fs_mounted - checks if a file system is mounted at its mount point + */ +extern bool_t fs_mounted( char *fstype, + char *fsdevice, + char *mntpt, + uuid_t *fsid ); + +/* fs_getid - retrieves the uuid of the file system containing the named + * file. returns -1 with errno set on error. + */ +extern intgen_t fs_getid( char *fullpathname, uuid_t *fsidp ); + +/* tells how many inos in use + */ +extern size_t fs_getinocnt( char *mnts ); + +#endif /* FS_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/getdents.c linux-2.4-xfs/cmd/xfsdump/common/getdents.c --- linux-2.4.7/cmd/xfsdump/common/getdents.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/getdents.c Mon Apr 9 01:32:28 2001 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Copyright (C) 1993, 95, 96, 97, 98, 99 Free Software Foundation, Inc. + * This file is based almost entirely on a file in the GNU C Library. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "getdents.h" + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif /* offsetof */ + +/* For Linux we need a special version of this file since the + definition of `struct dirent' is not the same for the kernel and + the libc. There is one additional field which might be introduced + in the kernel structure in the future. + + Here is the kernel definition of `struct dirent' as of 2.1.20: */ + +struct kernel_dirent +{ + long int d_ino; + __kernel_off_t d_off; + unsigned short int d_reclen; + char d_name[256]; +}; + +int getdents(unsigned int fd, struct dirent *dirp, unsigned int count) +{ + return syscall(SYS_getdents, fd, dirp, count); +} + +/* The problem here is that we cannot simply read the next NBYTES + bytes. We need to take the additional field into account. We use + some heuristic. Assuming the directory contains names with 14 + characters on average we can compute an estimated number of entries + which fit in the buffer. Taking this number allows us to specify a + reasonable number of bytes to read. If we should be wrong, we can + reset the file descriptor. In practice the kernel is limiting the + amount of data returned much more then the reduced buffer size. */ + +int +getdents_wrap (int fd, char *buf, size_t nbytes) +{ + off_t last_offset = 0; + size_t red_nbytes; + struct kernel_dirent *skdp, *kdp; + struct dirent *dp; + int retval; + const size_t size_diff = (offsetof (struct dirent, d_name) + - offsetof (struct kernel_dirent, d_name)); + + red_nbytes = nbytes - ((nbytes / (offsetof (struct dirent, d_name) + 14)) + * size_diff); + + dp = (struct dirent *) buf; + skdp = kdp = malloc (red_nbytes); + + retval = getdents (fd, (struct dirent *) kdp, red_nbytes); + + if (retval == -1) + return -1; + + while ((char *) kdp < (char *) skdp + retval) + { + size_t new_reclen = (kdp->d_reclen + size_diff); + if ((char *) dp + new_reclen > buf + nbytes) + { + /* Our heuristic failed. We read too many entries. Reset + the stream. `last_offset' contains the last known + position. If it is zero this is the first record we are + reading. In this case do a relative search. */ + if (last_offset == 0) + lseek (fd, -retval, SEEK_CUR); + else + lseek (fd, last_offset, SEEK_SET); + break; + } + + last_offset = kdp->d_off; + dp->d_ino = kdp->d_ino; + dp->d_off = kdp->d_off; + dp->d_reclen = new_reclen; + dp->d_type = DT_UNKNOWN; + memcpy (dp->d_name, kdp->d_name, + kdp->d_reclen - offsetof (struct kernel_dirent, d_name) + 1); + + dp = (struct dirent *) ((char *) dp + new_reclen); + kdp = (struct kernel_dirent *) (((char *) kdp) + kdp->d_reclen); + } + + free(skdp); + return (char *) dp - buf; +} diff -rNu linux-2.4.7/cmd/xfsdump/common/getdents.h linux-2.4-xfs/cmd/xfsdump/common/getdents.h --- linux-2.4.7/cmd/xfsdump/common/getdents.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/getdents.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef GETDENTS_H +#define GETDENTS_H + +int getdents_wrap (int fd, char *buf, size_t nbytes); + +#endif /* GETDENTS_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/global.c linux-2.4-xfs/cmd/xfsdump/common/global.c --- linux-2.4.7/cmd/xfsdump/common/global.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/global.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include + +#include "types.h" +#include "util.h" +#include "mlog.h" +#include "dlog.h" +#include "global.h" +#include "getopt.h" + + +/* declarations of externally defined global symbols *************************/ + +extern void usage( void ); +extern bool_t pipeline; + + +/* forward declarations of locally defined static functions ******************/ + +#ifdef DUMP +static char * prompt_label( char *bufp, size_t bufsz ); +#endif /* DUMP */ + +/* definition of locally defined global variables ****************************/ + + +/* definition of locally defined static variables *****************************/ + + +/* definition of locally defined global functions ****************************/ + +global_hdr_t * +global_hdr_alloc( intgen_t argc, char *argv[ ] ) +{ + global_hdr_t *ghdrp; + int c; + char *dumplabel; +#ifdef DUMP + char labelbuf[ GLOBAL_HDR_STRING_SZ ]; +#endif /* DUMP */ + + intgen_t rval; + + /* sanity checks + */ + ASSERT( sizeof( time_t ) == GLOBAL_HDR_TIME_SZ ); + ASSERT( sizeof( uuid_t ) == GLOBAL_HDR_UUID_SZ ); + + /* allocate a global hdr + */ + ghdrp = ( global_hdr_t * )calloc( 1, sizeof( global_hdr_t )); + ASSERT( ghdrp ); + + /* fill in the magic number + */ + strncpy( ghdrp->gh_magic, GLOBAL_HDR_MAGIC, GLOBAL_HDR_MAGIC_SZ ); + + /* fill in the hdr version + */ + ghdrp->gh_version = GLOBAL_HDR_VERSION; + + /* fill in the timestamp: all changes made at or after this moment + * will be included in increments on this base. + */ + ghdrp->gh_timestamp = time( ( time_t )0 ); + + /* fill in the host id: typecast to fit into a 64 bit field + */ + ghdrp->gh_ipaddr = ( u_int64_t )( unsigned long )gethostid( ); + +#ifdef DUMP + uuid_generate( ghdrp->gh_dumpid ); +#endif /* DUMP */ +#ifdef RESTORE + uuid_clear( ghdrp->gh_dumpid ); +#endif /* RESTORE */ + + /* fill in the hostname + */ + rval = gethostname( ghdrp->gh_hostname, GLOBAL_HDR_STRING_SZ ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "unable to determine hostname: %s\n", + strerror( errno )); + return 0; + } + if ( ! strlen( ghdrp->gh_hostname )) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "hostname length is zero\n" ); + return 0; + } + + /* scan the command line for the dump session label + */ + dumplabel = 0; + optind = 1; + opterr = 0; + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + switch ( c ) { + case GETOPT_DUMPLABEL: + if ( dumplabel ) { + mlog( MLOG_NORMAL, + "too many -%c arguments: " + "\"-%c %s\" already given\n", + optopt, + optopt, + dumplabel ); + usage( ); + return 0; + } + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument missing\n", + optopt ); + usage( ); + return 0; + } + dumplabel = optarg; + break; +#ifdef RESTORE + case GETOPT_SESSIONID: + if ( ! uuid_is_null( ghdrp->gh_dumpid )) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "too many -%c arguments\n", + optopt ); + usage( ); + return 0; + } + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument missing\n", + optopt ); + usage( ); + return 0; + } + + if ( ! uuid_parse( optarg, ghdrp->gh_dumpid ) ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument not a valid uuid\n", + optopt ); + usage( ); + return 0; + } + break; +#endif /* RESTORE */ +#ifdef DUMP +#ifdef EXTATTR + case GETOPT_NOEXTATTR: + /* if this is the version which dumps extended + * file attributes and the option to not do so + * has been specified, then we can regress the + * header version number. + */ + ghdrp->gh_version = GLOBAL_HDR_VERSION_0; + break; +#endif /* EXTATTR */ +#endif /* DUMP */ + } + } + +#ifdef DUMP + /* if no dump label specified, no pipes in use, and dialogs + * are allowed, prompt for one + */ + if ( ! dumplabel && dlog_allowed( )) { + dumplabel = prompt_label( labelbuf, sizeof( labelbuf )); + } +#endif /* DUMP */ + + if ( ! dumplabel || ! strlen( dumplabel )) { +#ifdef DUMP + if ( ! pipeline ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "no session label specified\n" ); + } +#endif /* DUMP */ + dumplabel = ""; + } + + strncpyterm( ghdrp->gh_dumplabel, + dumplabel, + sizeof( ghdrp->gh_dumplabel )); + + return ghdrp; +} + + +void +global_hdr_free( global_hdr_t *ghdrp ) +{ + free( ( void * )ghdrp ); +} + +/* global_hdr_checksum_set - fill in the global media file header checksum. + * utility function for use by drive-specific strategies. + */ +void +global_hdr_checksum_set( global_hdr_t *hdrp ) +{ + u_int32_t *beginp = ( u_int32_t * )&hdrp[ 0 ]; + u_int32_t *endp = ( u_int32_t * )&hdrp[ 1 ]; + u_int32_t *p; + u_int32_t accum; + + hdrp->gh_checksum = 0; + accum = 0; + for ( p = beginp ; p < endp ; p++ ) { + accum += INT_GET(*p, ARCH_CONVERT); + } + INT_SET(hdrp->gh_checksum, ARCH_CONVERT, (int32_t)(~accum + 1)); +} + +/* global_hdr_checksum_check - check the global media file header checksum. + * utility function for use by drive-specific strategies. + * returns BOOL_TRUE if ok, BOOL_FALSE if bad + */ +bool_t +global_hdr_checksum_check( global_hdr_t *hdrp ) +{ + u_int32_t *beginp = ( u_int32_t * )&hdrp[ 0 ]; + u_int32_t *endp = ( u_int32_t * )&hdrp[ 1 ]; + u_int32_t *p; + u_int32_t accum; + + accum = 0; + for ( p = beginp ; p < endp ; p++ ) { + accum += INT_GET(*p, ARCH_CONVERT); + } + return accum == 0 ? BOOL_TRUE : BOOL_FALSE; +} + +/* global_version_check - if we know this version number, return BOOL_TRUE + * else return BOOL_FALSE + */ +bool_t +global_version_check( u_int32_t version ) +{ + switch (version) { + case GLOBAL_HDR_VERSION_0: + case GLOBAL_HDR_VERSION_1: + case GLOBAL_HDR_VERSION_2: + return BOOL_TRUE; + default: + return BOOL_FALSE; + } +} + +/* definition of locally defined static functions ****************************/ + +#ifdef DUMP +#define PREAMBLEMAX 3 +#define QUERYMAX 1 +#define CHOICEMAX 1 +#define ACKMAX 3 +#define POSTAMBLEMAX 3 +#define DLOG_TIMEOUT 300 + +/* ARGSUSED */ +static void +prompt_label_cb( void *uctxp, dlog_pcbp_t pcb, void *pctxp ) +{ + /* query: ask for a dump label + */ + ( * pcb )( pctxp, + "please enter label for this dump session" ); +} + +static char * +prompt_label( char *bufp, size_t bufsz ) +{ + fold_t fold; + char *preamblestr[ PREAMBLEMAX ]; + size_t preamblecnt; + char *ackstr[ ACKMAX ]; + size_t ackcnt; + char *postamblestr[ POSTAMBLEMAX ]; + size_t postamblecnt; + const ix_t abortix = 1; + const ix_t okix = 2; + ix_t responseix; + + preamblecnt = 0; + fold_init( fold, "dump label dialog", '=' ); + preamblestr[ preamblecnt++ ] = "\n"; + preamblestr[ preamblecnt++ ] = fold; + preamblestr[ preamblecnt++ ] = "\n\n"; + ASSERT( preamblecnt <= PREAMBLEMAX ); + dlog_begin( preamblestr, preamblecnt ); + + responseix = dlog_string_query( prompt_label_cb, + 0, + bufp, + bufsz, + DLOG_TIMEOUT, + abortix,/* timeout ix */ + IXMAX, /* sigint ix */ + IXMAX, /* sighup ix */ + IXMAX, /* sigquit ix */ + okix ); /* ok ix */ + ackcnt = 0; + if ( responseix == okix ) { + ackstr[ ackcnt++ ] = "session label entered: \""; + ackstr[ ackcnt++ ] = bufp; + ackstr[ ackcnt++ ] = "\"\n"; + } else { + ackstr[ ackcnt++ ] = "session label left blank\n"; + } + + ASSERT( ackcnt <= ACKMAX ); + dlog_string_ack( ackstr, + ackcnt ); + + postamblecnt = 0; + fold_init( fold, "end dialog", '-' ); + postamblestr[ postamblecnt++ ] = "\n"; + postamblestr[ postamblecnt++ ] = fold; + postamblestr[ postamblecnt++ ] = "\n\n"; + ASSERT( postamblecnt <= POSTAMBLEMAX ); + dlog_end( postamblestr, + postamblecnt ); + + if ( responseix == okix ) { + return bufp; + } else { + return 0; + } +} +#endif /* DUMP */ diff -rNu linux-2.4.7/cmd/xfsdump/common/global.h linux-2.4-xfs/cmd/xfsdump/common/global.h --- linux-2.4.7/cmd/xfsdump/common/global.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/global.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef GLOBAL_H +#define GLOBAL_H + +/* global_hdr_t - first page of every media file + */ +#define GLOBAL_HDR_SZ PGSZ +#define GLOBAL_HDR_MAGIC "xFSdump0" +#define GLOBAL_HDR_MAGIC_SZ 8 + +#define GLOBAL_HDR_VERSION_0 0 +#define GLOBAL_HDR_VERSION_1 1 +#define GLOBAL_HDR_VERSION_2 2 + /* version 2 adds encoding of holes and a change to on-tape inventory format. + * version 1 adds extended file attribute dumping. + * version 0 xfsrestore can't handle media produced + * by version 1 xfsdump. + */ +#define GLOBAL_HDR_VERSION GLOBAL_HDR_VERSION_2 +#define GLOBAL_HDR_VERSION_PREV 1 + +#define GLOBAL_HDR_STRING_SZ 0x100 +#define GLOBAL_HDR_TIME_SZ 4 +#define GLOBAL_HDR_UUID_SZ 0x10 + +struct global_hdr { + char gh_magic[ GLOBAL_HDR_MAGIC_SZ ]; /* 8 8 */ + /* unique signature of xfsdump */ + u_int32_t gh_version; /* 4 c */ + /* header version */ + u_int32_t gh_checksum; /* 4 10 */ + /* 32-bit unsigned additive inverse of entire header */ + time_t gh_timestamp; /* 4 14 */ + /* time_t of dump */ + char gh_pad1[ 4 ]; /* 4 18 */ + /* alignment */ + u_int64_t gh_ipaddr; /* 8 20 */ + /* from gethostid(2), room for expansion */ + uuid_t gh_dumpid; /* 10 30 */ + /* ID of dump session */ + char gh_pad2[ 0xd0 ]; /* d0 100 */ + /* alignment */ + char gh_hostname[ GLOBAL_HDR_STRING_SZ ]; /* 100 200 */ + /* from gethostname(2) */ + char gh_dumplabel[ GLOBAL_HDR_STRING_SZ ]; /* 100 300 */ + /* label of dump session */ + char gh_pad3[ 0x100 ]; /* 100 400 */ + /* padding */ + char gh_upper[ GLOBAL_HDR_SZ - 0x400 ]; /* c00 1000 */ + /* header info private to upper software layers */ +}; + +typedef struct global_hdr global_hdr_t; + + +/* used by main( ) to allocate and populate a global header template. + * drive managers will copy this into the write header. + */ +extern global_hdr_t * global_hdr_alloc( intgen_t argc, char *argv[ ] ); + + +/* used by main( ) to free the global header template after drive ini. + */ +extern void global_hdr_free( global_hdr_t *ghdrp ); + + +/* global_hdr_checksum_set - fill in the global media file header checksum. + * utility function for use by drive-specific strategies. + */ +extern void global_hdr_checksum_set( global_hdr_t *hdrp ); + + +/* global_hdr_checksum_check - check the global media file header checksum. + * utility function for use by drive-specific strategies. + * returns BOOL_TRUE if ok, BOOL_FALSE if bad + */ +extern bool_t global_hdr_checksum_check( global_hdr_t *hdrp ); + +/* global_version_check - if we know this version number, return BOOL_TRUE + * else return BOOL_FALSE + */ + +extern bool_t global_version_check( u_int32_t version ); + + +#endif /* GLOBAL_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/inventory.c linux-2.4-xfs/cmd/xfsdump/common/inventory.c --- linux-2.4.7/cmd/xfsdump/common/inventory.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/inventory.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,671 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "inventory_priv.h" + +int sesslock_fd = -1; + + +/*----------------------------------------------------------------------*/ +/* inventory_open */ +/* */ +/* INV_BY_MOUNTPT, INV_BY_UUID or INV_BY_DEVPATH */ +/*----------------------------------------------------------------------*/ + +inv_idbtoken_t +inv_open( inv_predicate_t bywhat, void *pred ) +{ + + int fd, stobjfd, num; + char uuname[ INV_STRLEN ]; + inv_idbtoken_t tok = INV_TOKEN_NULL; + invt_sescounter_t *sescnt = 0; + + int index = 0; + + ASSERT ( pred ); + if ((fd = init_idb ( pred, bywhat, uuname, &tok )) < 0 ) + return tok; + + /* XXX also, see if it is too full. if so, make another and leave a + reference to the new file in the old one */ + + stobjfd = get_storageobj( fd, &index ); + if ( stobjfd < 0 ) { + close( fd ); + close( sesslock_fd ); + sesslock_fd = -1; + return INV_TOKEN_NULL; + } + + ASSERT ( index > 0 ); + + /* Now we need to make sure that this has enough space */ + num = GET_SESCOUNTERS( stobjfd, &sescnt ); + if ( num < 0 ) { + close( fd ); + close( stobjfd ); + close( sesslock_fd ); + sesslock_fd = -1; + return INV_TOKEN_NULL; + } + /* create another storage object ( and, an inv_index entry for it too ) + if we've filled this one up */ + if ( (u_int) num >= sescnt->ic_maxnum ) { +#ifdef INVT_DEBUG + printf("$ creating a new storage obj & index entry. \n" ); +#endif + close (stobjfd); + + stobjfd = create_invindex_entry( &tok, fd, uuname, BOOL_FALSE ); + free ( sescnt ); + if ( stobjfd < 0 ) { + close( fd ); + close( sesslock_fd ); + sesslock_fd = -1; + return INV_TOKEN_NULL; + } + return tok; + } + + free ( sescnt ); + tok = get_token( fd, stobjfd ); + tok->d_invindex_off = INVINDEX_HDR_OFFSET( index - 1 ); + + return tok; + +} + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + + +bool_t +inv_close( inv_idbtoken_t tok ) +{ + close ( tok->d_invindex_fd ); + close ( tok->d_stobj_fd ); + destroy_token( tok ); + close( sesslock_fd ); + sesslock_fd = -1; + + return BOOL_TRUE; +} + + + + +/*----------------------------------------------------------------------*/ +/* inventory_lasttime_level_lessthan */ +/* */ +/* Given a token that refers to a file system, and a level, this returns*/ +/* the last time when a session of a lesser level was done. */ +/* */ +/* returns -1 on error. */ +/*----------------------------------------------------------------------*/ + +bool_t +inv_lasttime_level_lessthan( + inv_idbtoken_t tok, + u_char level, + time_t **tm ) +{ + int rval; + ASSERT ( tok != INV_TOKEN_NULL ); + + rval = search_invt( tok, level, (void **) tm, + (search_callback_t) tm_level_lessthan ); + + return ( rval < 0) ? BOOL_FALSE: BOOL_TRUE; +} + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +bool_t +inv_lastsession_level_lessthan( + inv_idbtoken_t tok, + u_char level, + inv_session_t **ses ) +{ + int rval; + ASSERT ( tok != INV_TOKEN_NULL ); + + rval = search_invt( tok, level, (void **) ses, + (search_callback_t) lastsess_level_lessthan ); + + return ( rval < 0) ? BOOL_FALSE: BOOL_TRUE; + +} + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* Return FALSE on an error, TRUE if not. If (*ses) is NULL, then the */ +/* search failed. */ +/*----------------------------------------------------------------------*/ + + +bool_t +inv_lastsession_level_equalto( + inv_idbtoken_t tok, + u_char level, + inv_session_t **ses ) +{ + int rval; + ASSERT ( tok != INV_TOKEN_NULL ); + rval = search_invt( tok, level, (void **) ses, + (search_callback_t) lastsess_level_equalto ); + + return ( rval < 0) ? BOOL_FALSE: BOOL_TRUE; + +} + + + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +inv_sestoken_t +inv_writesession_open( + inv_idbtoken_t tok, /* token obtained by inventory_open() */ + uuid_t *fsid, + uuid_t *sesid, + char *label, + u_char level, + u_int nstreams, + time_t time, + char *mntpt, + char *devpath ) +{ + invt_session_t *ses; + int fd; + intgen_t rval; + invt_sescounter_t *sescnt = NULL; + invt_seshdr_t hdr; + inv_sestoken_t sestok; + + ASSERT ( tok != INV_TOKEN_NULL ); + ASSERT ( sesid && fsid && mntpt && devpath ); + + if ( ! ( tok->d_update_flag & FSTAB_UPDATED ) ) { + if ( put_fstab_entry( fsid, mntpt, devpath ) < 0 ) { + printf ("put_fstab_entry :(\n"); + return INV_TOKEN_NULL; + } + tok->d_update_flag |= FSTAB_UPDATED; + } + + + + ses = (invt_session_t *) calloc( 1, sizeof( invt_session_t ) ); + + /* copy the session information to store */ + memcpy( &ses->s_sesid, sesid, sizeof( uuid_t ) ); + memcpy( &ses->s_fsid, fsid, sizeof( uuid_t ) ); + strcpy( ses->s_label, label ); + strcpy( ses->s_mountpt, mntpt ); + strcpy( ses->s_devpath, devpath ); + ses->s_max_nstreams = nstreams; + + + /* s_curstream_off will be set in create_session() */ + + fd = tok->d_stobj_fd; + + ASSERT ( fd > 0 ); + + hdr.sh_time = time; + hdr.sh_level = level; + /* sh_streams_off and sh_sess_off will be set in create_session() */ + + sestok = get_sesstoken( tok ); + + /* we need to put the new session in the appropriate place in + storage object. So first find out howmany sessions are there */ + + INVLOCK( fd, LOCK_EX ); + if ( GET_SESCOUNTERS( fd, &sescnt) < 0 ) { + free ( ses ); + free ( sestok ); + INVLOCK( fd, LOCK_UN ); + return INV_TOKEN_NULL; + } + + /* create the writesession, and get ready for the streams to come + afterwards */ + rval = create_session( sestok, fd, sescnt, ses, &hdr ); + ASSERT (rval > 0); + + + INVLOCK( fd, LOCK_UN ); + + sestok->sd_sesstime = time; + + if ( tok->d_update_flag & NEW_INVINDEX ) { + if ( put_sesstime( sestok, INVT_STARTTIME ) < 0 ) { + printf ("put_starttime :(\n"); + return INV_TOKEN_NULL; + } + tok->d_update_flag &= ~(NEW_INVINDEX); + } + + free ( ses ); + free ( sescnt ); + + + return ( rval < 0 )? INV_TOKEN_NULL: sestok; +} + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + + +bool_t +inv_writesession_close( inv_sestoken_t tok ) +{ + int rval; + + ASSERT ( tok != INV_TOKEN_NULL ); + + /* now update end_time in the inv index header */ + rval = put_sesstime( tok, INVT_ENDTIME ); + + memset( tok, 0, sizeof( invt_sesdesc_entry_t ) ); + + free ( tok ); + + return ( rval < 0 ) ? BOOL_FALSE: BOOL_TRUE; + +} + + + +/*----------------------------------------------------------------------*/ +/* inventory_stream_open */ +/* */ +/* Opens a stream for mediafiles to be put in. */ +/*----------------------------------------------------------------------*/ +inv_stmtoken_t +inv_stream_open( + inv_sestoken_t tok ) +{ + inv_stmtoken_t stok; + invt_stream_t stream; + invt_session_t ses; + invt_seshdr_t seshdr; + int fd; + + ASSERT ( tok != INV_TOKEN_NULL ); + + stream.st_nmediafiles = 0; + stream.st_interrupted = BOOL_FALSE; + + + /* XXX yukk... make the token descriptors not pointers */ + stok = ( inv_stmtoken_t ) malloc( sizeof( invt_strdesc_entry_t ) ); + + stok->md_sesstok = tok; + stok->md_lastmfile = 0; + + /* get the session to find out where the stream is going to go */ + fd = tok->sd_invtok->d_stobj_fd; + + sess_lock(); + + INVLOCK( fd, LOCK_SH ); + /* get the session header first */ + if ( GET_REC_NOLOCK( fd, &seshdr, sizeof( invt_seshdr_t ), + tok->sd_sesshdr_off ) <= 0 ) { + free ( stok ); + INVLOCK( fd, LOCK_UN ); + sess_unlock(); + return INV_TOKEN_NULL; + } + + + + /* XXX Have one func that gives both seshdr and session */ + if ( GET_REC_NOLOCK( fd, &ses, sizeof( invt_session_t ), + tok->sd_session_off ) <= 0 ) { + free ( stok ); + INVLOCK( fd, LOCK_UN ); + sess_unlock(); + return INV_TOKEN_NULL; + } + INVLOCK( fd, LOCK_UN ); + + if ( ses.s_cur_nstreams < ses.s_max_nstreams ) { + /* this is where this stream header will be written to */ + stok->md_stream_off = (off64_t) (sizeof( invt_stream_t ) * + ses.s_cur_nstreams ) + + seshdr.sh_streams_off; + ses.s_cur_nstreams++; + + /* write it back. this locks and unlocks fd EXclusively */ + if ( PUT_REC( fd, &ses, sizeof( ses ), + tok->sd_session_off ) < 0 ) { + free ( stok ); + sess_unlock(); + return INV_TOKEN_NULL; + } + } else { + fprintf(stderr, "Cant create more than %d streams. Max'd out..\n", + ses.s_cur_nstreams ); + free ( stok ); + sess_unlock(); + return INV_TOKEN_NULL; + } + sess_unlock(); + + stream.st_firstmfile = stream.st_lastmfile = stok->md_stream_off; + + /* now put the stream header on to the disk */ + if ( PUT_REC( fd, &stream, sizeof( invt_stream_t ), + stok->md_stream_off ) < 0 ) { + free ( stok ); + return INV_TOKEN_NULL; + } + + return stok; +} + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +bool_t +inv_stream_close( + inv_stmtoken_t tok, + bool_t wasinterrupted ) +{ + invt_stream_t strm; + int fd = tok->md_sesstok->sd_invtok->d_stobj_fd; + int rval; + bool_t dowrite = BOOL_FALSE; + + INVLOCK( fd, LOCK_EX ); + if ((rval = GET_REC_NOLOCK( fd, &strm, sizeof( invt_stream_t ), + tok->md_stream_off )) < 0 ) + goto end; /* eek :-) */ + + if ( strm.st_interrupted != wasinterrupted ) { + strm.st_interrupted = wasinterrupted; + dowrite = BOOL_TRUE; + } + + /* get the last media file to figure out what our last ino was. + we have a pointer to that in the stream token */ + if ( tok->md_lastmfile ){ + if ( strm.st_endino.ino != tok->md_lastmfile->mf_endino.ino || + strm.st_endino.offset != tok->md_lastmfile->mf_endino.offset){ + printf("Warning: endinos dont match ! \n"); + dowrite = BOOL_TRUE; + strm.st_endino = tok->md_lastmfile->mf_endino; + } + } + + if (dowrite) { + rval = PUT_REC_NOLOCK_SEEKCUR( fd, &strm, sizeof( invt_stream_t ), + (off64_t) -(sizeof( invt_stream_t )) ); + } + end: + INVLOCK( fd, LOCK_UN ); + + free ( tok->md_lastmfile ); + memset( tok, 0, sizeof( invt_strdesc_entry_t ) ); + free ( tok ); + + return ( rval < 0 ) ? BOOL_FALSE: BOOL_TRUE; +} + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +bool_t +inv_put_mediafile( + inv_stmtoken_t tok, + uuid_t *moid, + char *label, + xfs_ino_t startino, + off64_t startino_offset, + xfs_ino_t endino, + off64_t endino_offset ) +{ + invt_mediafile_t *mf; + int rval; + + + ASSERT ( tok != INV_TOKEN_NULL ); + ASSERT ( tok->md_sesstok->sd_invtok->d_update_flag & FSTAB_UPDATED ); + ASSERT ( tok->md_sesstok->sd_invtok->d_stobj_fd >= 0 ); + + mf = (invt_mediafile_t *) calloc( 1, sizeof( invt_mediafile_t ) ); + + /* copy the media file information */ + memcpy( &mf->mf_moid, moid, sizeof( uuid_t ) ); + strcpy( mf->mf_label, label ); + mf->mf_startino.ino = startino; + mf->mf_startino.offset = startino_offset; + mf->mf_endino.ino = endino; + mf->mf_endino.offset = endino_offset; + + INVLOCK( tok->md_sesstok->sd_invtok->d_stobj_fd, LOCK_EX ); + rval = put_mediafile( tok, mf ); + INVLOCK( tok->md_sesstok->sd_invtok->d_stobj_fd, LOCK_UN ); + + /* we dont free the mfile here. we always keep the last mfile + around, inside the inv_stmtoken, and when we add a new mfile, + we free the previous one. The last one is freed in stream_close() + */ + + return ( rval < 0 ) ? BOOL_FALSE: BOOL_TRUE; + +} + + + +/*----------------------------------------------------------------------*/ +/* inv_get_inolist */ +/* */ +/* This returns all the database files that belong to the inventory, so */ +/* that the client (dump) knows that these shouldn't be dumped alongwith*/ +/* regular files. */ +/* */ +/* foreach ( fs in fstab ) */ +/* foreach ( index in InvIndex ) */ +/* get */ +/*----------------------------------------------------------------------*/ + +intgen_t +inv_get_inolist( + inv_inolist_t **inolist ) +{ + invt_entry_t *iarr = NULL; + invt_counter_t *icnt = NULL; + int nindices, i; + struct stat64 statbuf; + inv_inolist_t *curitem; + +#ifdef NOTDEF + *inolist = NULL; + curitem = malloc( sizeof( inv_inolist_t ) ); + + /* get the array of all indices in the invindex */ + if ( ( nindices = GET_ALLHDRS_N_CNTS( invfd, (void **)&iarr, + (void **)&icnt, + sizeof( invt_entry_t ), + sizeof( invt_counter_t )) + ) <= 0 ) { + return -1; + } + free( icnt ); + + /* attach all the StObjs */ + for (i = nindices - 1; i >= 0; i--) { + if ( stat64( iarr[i].ie_filename, &statbuf ) < 0 ) { + perror( iarr[i].ie_filename ); + return -1; + } + + create_inolist_item( curitem, statbuf.st_ino ); + } + /* The inventory index */ + if ( fstat64( invfd, &statbuf ) ){ + perror( "InvIndex file" ); + return -1; + } + create_inolist_item( curitem, statbuf.st_ino ); + + /* fstab */ + if ( stat64( INV_FSTAB, &statbuf ) < 0 ) { + perror( INV_FSTAB ); + return -1; + } + create_inolist_item( curitem, statbuf.st_ino ); + + /* sesslock file */ + if ( stat64( SESSLOCK_FILE, &statbuf ) < 0 ) { + perror( SESSLOCK_FILE ); + return -1; + } + create_inolist_item( curitem, statbuf.st_ino ); +#endif + + return 1; + +} + + + + + +/*----------------------------------------------------------------------*/ +/* inv_get_session */ +/* */ +/* This is to be called after a write-session is complete, but before it*/ +/* is closed. ie. the token must still be valid, and all the streams */ +/* and their mediafiles put in the inventory. */ +/* */ +/* On return, the buffer will be filled with all the data pertinent to */ +/* the session referred to by the session token. The application of this*/ +/* is to dump the inventory of a session to a media object. */ +/*----------------------------------------------------------------------*/ + +bool_t +inv_get_session( + inv_sestoken_t tok, + void **bufpp, /* buf to fill */ + size_t *bufszp )/* size of that buffer */ +{ + ASSERT( tok != INV_TOKEN_NULL ); + ASSERT( tok->sd_invtok ); + + /* First get the session header, and the session information. Then + we can figure out how much space to allocate */ + +} + + + + +#ifdef DEBUG + +/* This prints out all the sessions of a filesystem that are in the inventory */ +bool_t +inv_DEBUG_printallsessions( + inv_idbtoken_t tok, + inv_session_t **ses ) +{ + int rval; + rval = search_invt( tok, 0, (void **) ses, + (search_callback_t) DEBUG_displayallsessions ); + + return ( rval < 0) ? BOOL_FALSE: BOOL_TRUE; + +} + +#endif diff -rNu linux-2.4.7/cmd/xfsdump/common/inventory.h linux-2.4-xfs/cmd/xfsdump/common/inventory.h --- linux-2.4.7/cmd/xfsdump/common/inventory.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/inventory.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef INVENTORY_H +#define INVENTORY_H + +/* abstract interface to the inventory sub system of xfsdump + * + * the inventory contains a description of every xfsdump ever + * done, unless explicitly deleted. It provides simple and specific + * storage and query facilities. + * + * This was not an attempt to write a generic database. The inventory does have + * knowledge of the functionalities, some abstractions, and even typical queries + * of dump() and restore() and uses this knowledge in formulating its storage + * structure on disk. All these things, of course, are completely abstract with + * respect to the clients of the inventory. + * + */ + + +#define INV_DIRPATH "/var/xfsdump/inventory" /*"./test/invt" /* */ +#define INV_TOKEN_NULL NULL +#define INV_FSTAB INV_DIRPATH"/fstab" +#define INV_INVINDEX_PREFIX ".InvIndex" +#define INV_STOBJ_PREFIX ".StObj" +#define INV_STRLEN 128 /* length of labels, mntpts, etc */ + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* Users are first supposed to call inventory_open() specifying what */ +/* type of handle s/he would like to supply. This can be BY_MOUNTPT, */ +/* BY_DEVPATH, or BY_UUID. The inventory maintains its own table of file*/ +/* systems and their uuids, mountpts, and device paths. (XXX host). */ +/* The current implementation requires that a uuid be present for all */ +/* its fs table entries. However, once the entry is there, caller can */ +/* query by any of the other handles. */ +/* */ +/* For a read-session, ie. just querying, like in restore(), the token */ +/* from inventory_open() must always be passed. */ +/* */ +/* This inventory has a hierarchical token scheme. */ +/* For write-sessions, the caller should obtain a session_token */ +/* by calling inventory_session_open() with the original token. */ +/* In order to start writing media files, the caller must */ +/* then obtain a stream_token via inventory_stream_open() using that */ +/* session_token. */ +/* */ +/* Once, done, stream_close(), session_close() and inventory_close() */ +/* must be called in that order. */ +/* */ +/*----------------------------------------------------------------------*/ + +/* Caller can open the inventory by any of these handles */ +typedef enum { + INV_BY_UUID, + INV_BY_MOUNTPT, + INV_BY_DEVPATH +} inv_predicate_t; + + +typedef struct inv_stream { + bool_t st_interrupted; /* was this stream interrupted ? */ + + /* duplicate info from mediafiles for speed */ + xfs_ino_t st_startino; /* the starting pt */ + off64_t st_startino_off; + xfs_ino_t st_endino; /* where we actually ended up. this means + we've written upto but not including + this breakpoint. */ + off64_t st_endino_off; + int st_nmediafiles; /* number of mediafiles */ +} inv_stream_t; + + +/* + * inventory_session_t + * all the information that is kept on a single dump session of a single + * file system in the inventory. + * + */ + +typedef struct inv_session { + uuid_t s_fsid; /* file system */ + uuid_t s_sesid; /* this dump session's id: 16 bytes*/ + u_int s_nstreams; /* number of media streams recorded */ + inv_stream_t *s_streams; /* array of streams */ + time_t s_time; /* time of the dump */ + u_char s_level; /* dump level */ + char s_label[INV_STRLEN]; /* session label, assigned by the + operator */ + char s_mountpt[INV_STRLEN];/* path to the mount point */ + char s_devpath[INV_STRLEN];/* path to the device */ +} inv_session_t; + + +/* Is there anything else that you need here, Chuck? */ +typedef struct inv_mediafile { + uuid_t m_moid; /* media object id */ + xfs_ino_t m_startino; /* file that we started out with */ + off64_t m_startino_off; + xfs_ino_t m_endino; /* the dump file we ended this .. */ + off64_t m_endino_off; /* .. media file with. */ + char m_label[INV_STRLEN]; /* media file label */ +} inv_mediafile_t; + + +/* the list of inos returned by inv_get_inolist() */ +typedef struct inolist { + xfs_ino_t i_ino; + struct inolist *i_next; /* NULL if last element */ +} inv_inolist_t; + + +struct invt_desc_entry; +struct invt_sesdesc_entry; +struct invt_strdesc_entry; + +/* The three kinds of access tokens for the inventory */ +typedef struct invt_desc_entry *inv_idbtoken_t; +typedef struct invt_sesdesc_entry *inv_sestoken_t; +typedef struct invt_strdesc_entry *inv_stmtoken_t; + + + + +/* inventory_open - initializes access to the inventory + */ +extern inv_idbtoken_t +inv_open( + inv_predicate_t bywhat, /* BY_UUID, BY_MOUNTPT, BY_DEVPATH */ + void *pred );/* uuid_t *,char * mntpt, or char *dev */ + + +extern bool_t +inv_close( + inv_idbtoken_t tok ); + + +extern inv_sestoken_t +inv_writesession_open( + inv_idbtoken_t tok, /* token obtained by inventory_init() */ + uuid_t *fsid, + uuid_t *sesid, + char *label, + u_char level, + u_int nstreams, + time_t time, + char *mntpt, + char *devpath ); + +extern bool_t +inv_writesession_close( + inv_sestoken_t tok ); + +extern inv_stmtoken_t +inv_stream_open( + inv_sestoken_t tok ); + +extern bool_t +inv_stream_close( + inv_stmtoken_t tok, + bool_t wasinterrupted ); + +extern bool_t +inv_put_mediafile( + inv_stmtoken_t tok, + uuid_t *moid, + char *label, + xfs_ino_t startino, + off64_t startino_offset, + xfs_ino_t endino, + off64_t endino_offset ); + +/* lasttime_level_lessthan - finds the time of the last dump of the + * specified file system at a level less than the specified level. + * if never dumped below the current level, *time is set to NULL. + * + */ +extern bool_t +inv_lasttime_level_lessthan( + inv_idbtoken_t tok, + u_char level, + time_t **time );/* out */ + +extern bool_t +inv_lastsession_level_lessthan( + inv_idbtoken_t tok, + u_char level, + inv_session_t **ses );/* out */ + +extern bool_t +inv_lastsession_level_equalto( + inv_idbtoken_t tok, + u_char level, + inv_session_t **ses );/* out */ + +extern bool_t +inv_get_inolist( + inv_inolist_t **inolist ); + +/* For dumping the inventory once a dump is done. */ +extern bool_t +inv_get_session( + inv_sestoken_t tok, + void **bufpp, /* out */ + size_t *bufszp ); /* out */ + +/* To reconstruct a compelete inventory from dumped inventories */ +extern bool_t +inv_put_session( + inv_idbtoken_t tok, + void *bufp, + size_t bufsz ); + +#ifdef DEBUG + +bool_t +inv_DEBUG_printallsessions( + inv_idbtoken_t tok, + inv_session_t **ses ); + +#endif /* ifdef DEBUG */ + +#endif /* INVENTORY_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/inventory_priv.c linux-2.4-xfs/cmd/xfsdump/common/inventory_priv.c --- linux-2.4.7/cmd/xfsdump/common/inventory_priv.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/inventory_priv.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,1338 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "types.h" +#include "inventory_priv.h" + +extern int sesslock_fd; + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +inv_idbtoken_t +create_invindex( int fd, char *fname, char *uuname ) +{ + int stobjfd; + inv_idbtoken_t tok; + + if ((fd = open ( fname , O_RDWR | O_CREAT ) ) < 0 ) { + perror ( fname ); + return INV_TOKEN_NULL; + } + + INVLOCK( fd, LOCK_EX ); + fchmod( fd, INV_PERMS ); + +#ifdef INVT_DEBUG + printf ("creating InvIndex %s\n", fname); +#endif + + /* create the first entry in the new inv_index */ + stobjfd = create_invindex_entry( &tok, fd, uuname, BOOL_TRUE ); + + INVLOCK( fd, LOCK_UN ); + + if ( stobjfd < 0 ) + return INV_TOKEN_NULL; + return tok; +} + + + + + + +/*----------------------------------------------------------------------*/ +/* put_sesstime */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +put_sesstime( inv_sestoken_t tok, bool_t whichtime) +{ + int rval; + invt_entry_t ent; + int fd = tok->sd_invtok->d_invindex_fd; + + INVLOCK( fd, LOCK_EX ); + + rval = GET_REC_NOLOCK( fd, &ent, sizeof( invt_entry_t ), + tok->sd_invtok->d_invindex_off); + if ( rval < 0 ) + return -1; + + ent.ie_timeperiod.tp_end = tok->sd_sesstime; + + if ( whichtime == INVT_STARTTIME ) { + ent.ie_timeperiod.tp_start = tok->sd_sesstime; + } + + rval = PUT_REC_NOLOCK_SEEKCUR( fd, &ent, sizeof( invt_entry_t ), + (off64_t) -(sizeof( invt_entry_t ))); + + INVLOCK( fd, LOCK_UN ); + return rval; +} + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +put_counters( int fd, void *cntp, size_t sz ) +{ + ASSERT( cntp ); + + return PUT_REC( fd, cntp, sz, (off64_t) 0 ); +} + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +get_counters( int fd, void **cntpp, size_t cntsz ) +{ + /* file must be locked at least SHARED by caller */ + + *cntpp = calloc( 1, cntsz); + + /* find the number of sessions and the max possible */ + if ( GET_REC_NOLOCK( fd, (void *) *cntpp, cntsz, (off64_t) 0 ) < 0 ) { + free( *cntpp ); + *cntpp = NULL; + return -1; + } + + return ((invt_counter_t *)(*cntpp))->ic_curnum; +} + + + + + + + +/*----------------------------------------------------------------------*/ +/* get_headers */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +get_headers( int fd, void **hdrs, size_t bufsz, size_t off ) +{ + + *hdrs = malloc( bufsz ); + + /* file must be locked at least SHARED by caller */ + + /* get the array of hdrs */ + if ( GET_REC_NOLOCK( fd, (void *) *hdrs, bufsz, (off64_t)off ) < 0 ) { + free ( *hdrs ); + *hdrs = NULL; + return -1; + } + + return 1; +} + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +int +get_curnum( int fd ) +{ + invt_counter_t *cnt = NULL; + + int curnum = GET_COUNTERS( fd, &cnt ); + free ( cnt ); + return curnum; +} + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +get_invtrecord( int fd, void *buf, size_t bufsz, off64_t off, + int whence, bool_t dolock ) +{ + int nread; + + ASSERT ( fd >= 0 ); + + if ( dolock ) + INVLOCK( fd, LOCK_SH ); + + if ( lseek( fd, (off_t)off, whence ) < 0 ) { + perror( "lseek: get_invtrecord sez - " ); + if ( dolock ) + INVLOCK( fd, LOCK_UN ); + return -1; + } + + nread = read( fd, buf, bufsz ); + + if ( nread != (int) bufsz ) { +#ifdef INVT_DEBUG + printf ("read failed on fd %d (%d of %d) %x\n", + fd, nread, bufsz, (long) buf); +#endif + perror("get_invtrecord sez - "); + if ( dolock ) + INVLOCK( fd, LOCK_UN ); + return -1; + } + + if ( dolock ) + INVLOCK( fd, LOCK_UN ); + + return nread; +} + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +put_invtrecord( int fd, void *buf, size_t bufsz, off64_t off, + int whence, bool_t dolock ) +{ + int nwritten; + + if ( dolock ) + INVLOCK( fd, LOCK_EX ); + + if ( lseek( fd, (off_t)off, whence ) < 0 ) { + perror( "lseek: put_invtrecord sez - " ); + if ( dolock ) + INVLOCK( fd, LOCK_UN ); + return -1; + } + + if (( nwritten = write( fd, buf, bufsz ) ) != (int) bufsz ) { + perror( "Error in writing inventory record :" ); + if ( dolock ) + INVLOCK( fd, LOCK_UN ); + return -1; + } + + if ( dolock ) + INVLOCK( fd, LOCK_UN ); + return nwritten; +} + + + + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + + +intgen_t +get_headerinfo( int fd, void **hdrs, void **cnt, + size_t hdrsz, size_t cntsz, bool_t dolock ) +{ + int num; + + /* get a lock on the table for reading */ + if ( dolock ) INVLOCK( fd, LOCK_SH ); + + num = get_counters( fd, cnt, cntsz ); + + /* If there are no sessions recorded yet, we're done too */ + if ( num > 0 ) { + if ( get_headers( fd, hdrs, hdrsz * (size_t)num, cntsz ) < 0 ) { + free ( *cnt ); + num = -1; + } + } + + if ( dolock ) INVLOCK( fd, LOCK_UN ); + return num; +} + + + + + + + + +/* an inventory index entry keeps track of a single storage object; + it knows about its name (ie filename) and the timeperiod that the + it contains dump sessions for. + note that each file system has its own (set of) inventory indices. +*/ + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +create_invindex_entry( + inv_idbtoken_t *tok, + int invfd, char *uuname, + bool_t firstentry ) +{ + invt_entry_t ent; + int fd; + off64_t hoff; + + + memset ( &ent, 0, sizeof( ent ) ); + + /* initialize the start and end times to be the same */ + ent.ie_timeperiod.tp_start = ent.ie_timeperiod.tp_end = (time_t)0; + + if ( firstentry ) { + + invt_counter_t cnt; + + cnt.ic_maxnum = INVT_MAX_INVINDICES; + cnt.ic_curnum = 1; + + + fd = create_storageobj( uuname, ent.ie_filename, 1 ); + if ( fd < 0 ) { + return -1; + } + + if ( PUT_REC_NOLOCK( invfd, &cnt, sizeof( cnt ), (off64_t) 0 ) < 0 ) + return -1; + + /* XXX we need put_header(), put_counters() */ + hoff = sizeof( invt_counter_t ); + + if ( PUT_REC_NOLOCK( invfd, &ent, sizeof( ent ), hoff ) < 0) + return -1; + } else { + invt_counter_t *cnt = NULL; + + if ( GET_COUNTERS( invfd, &cnt ) < 0 ) { + return -1; + } + + /* XXX check if there are too many indices. if so, create + another and leave a pointer to that in here */ + + /* create the new storage object */ + fd = create_storageobj( uuname, ent.ie_filename, + ++(cnt->ic_curnum) ); + if ( fd < 0 ) { + return -1; + } + + if ( PUT_COUNTERS( invfd, cnt ) < 0 ) { + return -1; + } + + /* add the new index entry to the array, at the end */ + + hoff = INVINDEX_HDR_OFFSET( cnt->ic_curnum - 1 ); + free (cnt); +#ifdef INVT_DEBUG + printf("new stobj name %s @ offset %d\n",ent.ie_filename,(int)hoff); +#endif + if ( PUT_REC_NOLOCK( invfd, &ent, sizeof( ent ), hoff ) < 0 ) + return -1; + + } + + *tok = get_token( invfd, fd ); + (*tok)->d_invindex_off = hoff; + (*tok)->d_update_flag |= NEW_INVINDEX; + return fd; + +} + + + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + + +/* NOTE: this doesnt update counters or headers in the inv_index */ +int +create_storageobj( char *uuname, char *fname, int index) +{ + char buf[7]; /* upto 009999 */ + int fd; + invt_sescounter_t sescnt; + + + /* come up with a new unique name */ + sprintf( buf, "XX%d\0", index ); + strcpy( fname, uuname ); + strcat( fname, buf ); + strcat( fname, INV_STOBJ_PREFIX ); + +#ifdef INVT_DEBUG + printf( "creating storage obj %s\n", fname); +#endif + ASSERT( (int) strlen( fname ) < INV_STRLEN ); + + + /* create the new storage object */ + if (( fd = open( fname, O_RDWR | O_EXCL | O_CREAT )) < 0 ) { + perror ( fname ); + memset( fname, 0, INV_STRLEN ); + return -1; + } + + INVLOCK( fd, LOCK_EX ); + fchmod( fd, INV_PERMS ); + + sescnt.ic_curnum = 0; /* there are no sessions as yet */ + sescnt.ic_maxnum = INVT_STOBJ_MAXSESSIONS; + + sess_lock(); + sescnt.ic_eof = SC_EOF_INITIAL_POS; + sess_unlock(); + + if ( PUT_SESCOUNTERS ( fd, &sescnt ) < 0 ) { + memset( fname, 0, INV_STRLEN ); + INVLOCK( fd, LOCK_UN ); + return -1; + } + + INVLOCK( fd, LOCK_UN ); + return fd; +} + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + + +intgen_t +create_session( + inv_sestoken_t tok, + int fd, + invt_sescounter_t *sescnt, + invt_session_t *ses, + invt_seshdr_t *hdr ) +{ + off64_t hoff; + + /* figure out the place where the header will go */ + hoff = (off64_t) sizeof( invt_sescounter_t ) + + (size_t) sescnt->ic_curnum * sizeof( invt_seshdr_t ) ; + + /* figure out where the session information is going to go. */ + hdr->sh_sess_off = sizeof( invt_sescounter_t ) + + sescnt->ic_maxnum * sizeof( invt_seshdr_t ) + + sescnt->ic_curnum * sizeof( invt_session_t ) ; + + sescnt->ic_curnum++; + +#ifdef INVT_DEBUG + printf ( "create sess #%d @ offset %d ic_eof = %d\n", + sescnt->ic_curnum, (int) hdr->sh_sess_off, (int) sescnt->ic_eof ); +#endif + ses->s_cur_nstreams = 0; + + /* we need to know where the streams begin, and where the media files will + begin, at the end of the streams */ + sess_lock(); + hdr->sh_streams_off = sescnt->ic_eof; + sescnt->ic_eof += (off64_t)( ses->s_max_nstreams * sizeof( invt_stream_t ) ); + sess_unlock(); + + /* XXX Have a vector'd write do these 3 writes */ + /* we write back the counters of this storage object first */ + if ( PUT_SESCOUNTERS( fd, sescnt ) < 0 ) + return -1; + + /* write the header next; lseek to the right position */ + if ( PUT_REC_NOLOCK( fd, hdr, sizeof( invt_seshdr_t ), hoff ) < 0 ) { + return -1; + } + + /* write the header information to the storage object */ + if ( PUT_REC_NOLOCK( fd, ses, sizeof( invt_session_t ), + hdr->sh_sess_off ) < 0 ) { + return -1; + } + + tok->sd_sesshdr_off = hoff; + tok->sd_session_off = hdr->sh_sess_off; + + return 1; +} + + + + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +put_mediafile( inv_stmtoken_t tok, invt_mediafile_t *mf ) +{ + int rval; + invt_sescounter_t *sescnt = NULL; + invt_stream_t stream; + inv_sestoken_t sestok = tok->md_sesstok; + int fd = sestok->sd_invtok->d_stobj_fd; + off64_t pos; + + + /* first we need to find out where the current write-position is. + so, we first read the sescounter that is at the top of this + storage object */ + sess_lock(); + rval = GET_SESCOUNTERS( fd, &sescnt ); + if ( rval < 0 ) { + sess_unlock(); + return -1; + } + + pos = sescnt->ic_eof; + + /* increment the pointer to give space for this media file */ + sescnt->ic_eof += (off64_t) sizeof( invt_mediafile_t ); + rval = PUT_SESCOUNTERS( fd, sescnt ); + sess_unlock(); + + if ( rval < 0 ) + return -1; + + /* get the stream information, and update number of mediafiles. + we also need to link the new mediafile into the linked-list of + media files of this stream */ + + rval = GET_REC_NOLOCK( fd, &stream, sizeof( stream ), tok->md_stream_off ); + if ( rval < 0 ) { + return -1; + } + /* We need to update the last ino of this STREAM, which is now the + last ino of the new mediafile. If this is the first mediafile, we + have to update the startino as well. Note that ino is a + tuple */ + if ( stream.st_nmediafiles == 0 ) + stream.st_startino = mf->mf_startino; + stream.st_endino = mf->mf_endino; + + stream.st_nmediafiles++; +#ifdef INVT_DEBUG + printf ("#################### mediafile #%d ###################\n", + stream.st_nmediafiles); +#endif + /* add the new mediafile at the tail of the list */ + + mf->mf_nextmf = tok->md_stream_off; + mf->mf_prevmf = stream.st_lastmfile; + + if ( tok->md_lastmfile ) + tok->md_lastmfile->mf_nextmf = pos; + else { + stream.st_firstmfile = pos; + } + + stream.st_lastmfile = pos; + + + /* write the stream to disk */ + rval = PUT_REC_NOLOCK( fd, &stream, sizeof( stream ), tok->md_stream_off ); + if ( rval < 0 ) { + return -1; + } + + /* write the prev media file to disk too */ + if ( tok->md_lastmfile ) { + rval = PUT_REC_NOLOCK( fd, tok->md_lastmfile, + sizeof( invt_mediafile_t ), mf->mf_prevmf ); + free ( tok->md_lastmfile ); + if ( rval < 0 ) { + return -1; + } + } + + tok->md_lastmfile = mf; + + /* at last, write the new media file to disk */ + rval = PUT_REC_NOLOCK( fd, mf, sizeof( invt_mediafile_t ), pos ); + if ( rval < 0 ) { + return -1; + } + + return rval; +} + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +int +get_storageobj( int invfd, int *index ) +{ + invt_entry_t *ent = 0; + int fd; + + /* if there's space anywhere at all, then it must be in the last + entry */ + if ((*index = get_lastheader( invfd, (void **)&ent, + sizeof(invt_entry_t), + sizeof(invt_counter_t) ) ) < 0 ) + return -1; + /* what if there arent any headers, and get_lastheader rets 0 ? */ + ASSERT ( ent != NULL ); + ASSERT ( ent->ie_filename ); + + fd = open( ent->ie_filename, O_RDWR ); + if ( fd < 0 ) + perror( ent->ie_filename ); + free ( ent ); + + return fd; +} + +intgen_t +get_lastheader( int fd, void **ent, size_t hdrsz, size_t cntsz ) +{ + int nindices; + void *arr = NULL; + invt_counter_t *cnt = NULL; + char *pos; + /* get the entries in the inv_index */ + if ( ( nindices = GET_ALLHDRS_N_CNTS( fd, &arr, (void **)&cnt, + hdrsz, cntsz )) <= 0 ) { + return -1; + } + + /* if there's space anywhere at all, then it must be in the last + entry */ + *ent = malloc( hdrsz ); + pos = (char *) arr + ( (u_int)nindices - 1 ) * hdrsz; + memcpy( *ent, pos, hdrsz ); + free ( arr ); + free ( cnt ); + + return nindices; +} + + + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + + +intgen_t +get_fstab( invt_fstab_t **arr, invt_counter_t **cnt, int *numfs ) +{ + int fd; + + fd = open (INV_FSTAB, O_RDWR); + + if ( fd < 0 ) { + return -1; + } + + INVLOCK( fd, LOCK_EX ); + if (( *numfs = GET_ALLHDRS_N_CNTS_NOLOCK( fd, (void**) arr, + (void **)cnt, + sizeof( invt_fstab_t ), + sizeof( invt_counter_t ) ) + ) < 0 ) { + printf("hdrs :( \n"); + } +#ifdef INVT_DEBUG + printf(" number of filesystems in fstab %d\n", *numfs ); +#endif + return fd; +} + + + +intgen_t +make_invdirectory( void ) +{ + DIR *dr; + + if (( dr = opendir( INV_DIRPATH )) == 0 ) { + + if ( mkdirp( INV_DIRPATH, (mode_t)0755 ) < 0 ) { + perror( INV_DIRPATH ); + return -1; + } + + printf("new dir created\n"); + return 1; + } + + + closedir ( dr); + return 1; + + +} + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* caller takes the responsibility of calling this only when the FSTAB_ */ +/* UPDATED flag in the inv_idbtoken is off, and also of updating the */ +/* flag upon successful return from put_fstab_entry. */ +/*----------------------------------------------------------------------*/ + + +intgen_t +put_fstab_entry( uuid_t *fsidp, char *mntpt, char *dev ) +{ + int numfs, i, fd; + invt_counter_t *cnt; + invt_fstab_t *arr; + int rval = 1; + + /* fd is locked on return */ + fd = get_fstab( &arr, &cnt, &numfs ); + if ( fd < 0 ) { + if ( errno != ENOENT) { + return -1; + } + if ((fd = open( INV_FSTAB, O_RDWR | O_CREAT )) < 0 ) { + perror ( INV_FSTAB ); + return -1; + } + + INVLOCK( fd, LOCK_EX ); + fchmod( fd, INV_PERMS ); + + cnt = (invt_counter_t *) malloc( sizeof ( invt_counter_t ) ); + + cnt->ic_maxnum = -1; + cnt->ic_curnum = 0; + + } else if ( numfs > 0 ) { + + for (i = 0; i < numfs; i++) { + if ( uuid_compare( fsidp, &arr[ i ].ft_uuid ) == 0 ) { + ASSERT( ( strcmp( arr[i].ft_mountpt, mntpt ) == 0 ) && + ( strcmp( arr[i].ft_devpath, dev ) == 0 ) ); + free ( arr ); + free ( cnt ); + close( fd ); + return 1; + } + } + /* entry not found. just follow thru to create a new one */ + free ( arr ); + } + + + + /* make a new fstab entry and insert it at the end. the tabel is locked + EXclusively at this point */ + { + invt_fstab_t ent; + off64_t hoff; + + memcpy( &ent.ft_uuid, fsidp, sizeof( uuid_t ) ); + strcpy( ent.ft_mountpt, mntpt ); + strcpy( ent.ft_devpath, dev ); + + /* increase the number of entries first */ +#ifdef INVT_DEBUG + printf("$ putting new fstab entry for %s ..........\n", mntpt); +#endif + cnt->ic_curnum++; + hoff = (off64_t) ( sizeof( invt_counter_t ) + + (size_t)( cnt->ic_curnum - 1 ) * + sizeof( invt_fstab_t ) ); + + rval = PUT_COUNTERS( fd, cnt ); + if ( rval > 0 ) { + rval = PUT_REC_NOLOCK( fd, &ent, sizeof( ent ), hoff ); + } + + } + INVLOCK( fd, LOCK_UN ); + free ( cnt ); + close ( fd ); + return rval; +} + + + + + + + +intgen_t +get_fname( void *pred, char *fname, inv_predicate_t bywhat ) +{ + uuid_t *uuidp = 0; + char uuidstr[UUID_STR_LEN + 1]; + unsigned int stat; + invt_fstab_t *arr; + + + if (bywhat != INV_BY_UUID) { + int numfs, i, fd; + invt_counter_t *cnt; + + /* on sucessful return fd is locked */ + fd = get_fstab( &arr, &cnt, &numfs ); + if (fd < 0) + return -1; + ASSERT( numfs >= 0 ); + + INVLOCK( fd, LOCK_UN ); + close ( fd ); + free ( cnt ); /* we dont need it */ + + /* first get hold of the uuid for this mount point / device */ + + for (i = 0; i < numfs; i++) { + if ( ( bywhat == INV_BY_MOUNTPT && + ( strcmp( arr[i].ft_mountpt, pred ) == 0 )) || + ( bywhat == INV_BY_DEVPATH && + ( strcmp( arr[i].ft_devpath, pred ) == 0 )) ) { + + uuidp = &arr[i].ft_uuid; + break; + } + } +#ifdef INVT_DEBUG + if (! uuidp ) + fprintf( stderr, "INV get_fname: unable to find %s" + " in the inventory\n", (char *)pred); +#endif + + } else { + uuidp = (uuid_t *)pred; + } + + if (! uuidp ) + return -1; + + uuid_unparse( *uuidp, uuidstr ); + + strncpy ( fname, INV_DIRPATH, INV_STRLEN ); + strcat ( fname, "/" ); + strcat ( fname, uuidstr); + + if ( bywhat != INV_BY_UUID ) + free ( arr ); + + ASSERT( (int) strlen( fname ) < INV_STRLEN ); + return 1; +} + + +/*---------------------------------------------------------------------------*/ +/* */ +/* */ +/* Returns -1 if we are done with initialization, the fd if not. */ +/* The idb_token indicates whether there was an error or not. */ +/*---------------------------------------------------------------------------*/ + +int +init_idb( void *pred, inv_predicate_t bywhat, char *uuname, inv_idbtoken_t *tok ) +{ + char fname[ INV_STRLEN ]; + int fd; + + *tok = INV_TOKEN_NULL; + /* make sure INV_DIRPATH exists, and is writable */ + if ( make_invdirectory( ) < 0 ) + return -1; + + /* we need this for locking */ + if ( sesslock_fd < 0 ) { + if (( sesslock_fd = open( SESSLOCK_FILE, O_RDWR | O_CREAT ))<0 ){ + perror( SESSLOCK_FILE ); + return -1; + } + fchmod( sesslock_fd, INV_PERMS ); + } + /* come up with the unique file suffix that refers this filesystem */ + if ( get_fname( pred, uuname, bywhat ) < 0 ) { + close( sesslock_fd ); + sesslock_fd = -1; + return -1; + } + + ( void )strcpy( fname, uuname ); + strcat ( fname, INV_INVINDEX_PREFIX ); + + /* first check if the inv_index file exists: if not create it */ + if ( ( fd = open( fname, O_RDWR ) ) == -1 ) { + if (errno != ENOENT) { + perror ( fname ); + close( sesslock_fd ); + sesslock_fd = -1; + return -1; + } + *tok = create_invindex( fd, fname, uuname ); + return -1; /* we are done whether token's NULL or not */ + } + + /* we've got to do more housekeeping stuff. so signal that */ + return fd; +} + + + + + +inv_idbtoken_t +get_token( int invfd, int stobjfd ) +{ + invt_desc_entry_t *desc; + + desc = (invt_desc_entry_t *) malloc + ( sizeof( invt_desc_entry_t ) ); + + desc->d_invindex_fd = invfd; + desc->d_stobj_fd = stobjfd; + desc->d_update_flag = 0; + desc->d_invindex_off = -1; + + if ( invfd < 0 || stobjfd < 0 ) { + fprintf(stderr, "get_token warning: " + "invfd = %d stobjfd = %d\n", invfd, stobjfd ); + } + + return (inv_idbtoken_t) desc; /* yukky, but ok for the time being */ +} + + + + + + +void +destroy_token( inv_idbtoken_t tok ) +{ + free ( (invt_sesdesc_entry_t *) tok ); +} + + + +inv_sestoken_t +get_sesstoken( inv_idbtoken_t tok ) +{ + inv_sestoken_t stok; + + stok = (inv_sestoken_t) malloc( sizeof( invt_sesdesc_entry_t ) ); + stok->sd_invtok = tok; + stok->sd_session_off = stok->sd_sesshdr_off = -1; + stok->sd_sesstime = (time_t) 0; + return stok; +} + + + + +intgen_t +open_invindex( void *pred, inv_predicate_t bywhat ) +{ + char fname[INV_STRLEN]; + int invfd; + + if ( get_fname( pred, fname, bywhat ) < 0 ) + return -1; + strcat ( fname, ".InvIndex" ); + + invfd = open (fname, O_RDONLY); + + return invfd; +} + + + + +void +sess_lock( void ) +{ + INVLOCK( sesslock_fd, LOCK_EX ); + +} + + + + +void +sess_unlock( void ) +{ + INVLOCK( sesslock_fd, LOCK_UN ); + +} + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +search_invt( + inv_idbtoken_t tok, + u_char level, + void **buf, + search_callback_t do_chkcriteria ) +{ + + int fd, i; + invt_entry_t *iarr = NULL; + invt_counter_t *icnt = NULL; + int nindices; + + + ASSERT ( tok->d_invindex_fd >= 0 ); + *buf = NULL; + + if ( ( nindices = GET_ALLHDRS_N_CNTS( tok->d_invindex_fd, (void **)&iarr, + (void **)&icnt, + sizeof( invt_entry_t ), + sizeof( invt_counter_t )) + ) <= 0 ) { + return -1; + } + + free( icnt ); + + /* we need to get all the invindex headers and seshdrs in reverse order */ + for (i = nindices - 1; i >= 0; i--) { + int nsess; + invt_sescounter_t *scnt = NULL; + invt_seshdr_t *sarr = NULL; + bool_t found; + + fd = open (iarr[i].ie_filename, O_RDONLY ); + if (fd < 0) { + perror( iarr[i].ie_filename ); + continue; + } + INVLOCK( fd, LOCK_SH ); + + /* Now see if we can find the session that we're looking for */ + if (( nsess = GET_ALLHDRS_N_CNTS_NOLOCK( fd, (void **)&sarr, + (void **)&scnt, + sizeof( invt_seshdr_t ), + sizeof( invt_sescounter_t )) + ) < 0 ) { + perror( iarr[i].ie_filename ); + INVLOCK( fd, LOCK_UN ); + close( fd ); + continue; + } + free ( scnt ); + while ( nsess ) { + /* fd is kept locked until we return from the callback + routine */ + found = (* do_chkcriteria ) ( fd, &sarr[ --nsess ], + level, buf ); + if (! found ) continue; + + /* we found what we need; just return */ + INVLOCK( fd, LOCK_UN ); + close( fd ); + free( sarr ); + return found; /* == -1 or 1 */ + } + + INVLOCK( fd, LOCK_UN ); + close( fd ); + } + + printf( "$ Search not succeeded.\n"); + + return 0; +} + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +tm_level_lessthan( int fd, invt_seshdr_t *hdr, u_char level, + void **tm ) +{ + if (hdr->sh_level < level ) { +#ifdef INVT_DEBUG + printf( "$ found level %d < %d\n", hdr->sh_level, level ); +#endif + *tm = calloc( 1, sizeof( time_t ) ); + memcpy( *tm, &hdr->sh_time, sizeof( time_t ) ); + return 1; + } + return 0; +} + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +lastsess_level_lessthan( int fd, invt_seshdr_t *hdr, u_char level, + void **buf ) +{ + if (hdr->sh_level < level ) { +#ifdef INVT_DEBUG + printf( "$ found (ses) level %d < %d \n", hdr->sh_level, level ); +#endif + return make_invsess( fd, (inv_session_t **) buf, hdr ); + } + return 0; + +} + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +lastsess_level_equalto( int fd, invt_seshdr_t *hdr, u_char level, void **buf ) +{ + if (hdr->sh_level == level ) { +#ifdef INVT_DEBUG + printf( "$ found (ses) level %d == %d \n", hdr->sh_level, level ); +#endif + return make_invsess( fd, (inv_session_t **) buf, hdr ); + } + return 0; + + +} + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +make_invsess( int fd, inv_session_t **buf, invt_seshdr_t *hdr ) +{ + invt_session_t ses; + inv_session_t *ises; + invt_stream_t *strms; + int i; + + + /* load in the rest of the session */ + if ( GET_REC_NOLOCK( fd, &ses, sizeof(ses), hdr->sh_sess_off ) + < 0 ) { + return -1; + } + + strms = calloc ( ses.s_cur_nstreams, sizeof( invt_stream_t ) ); + + /* load in all the stream-headers */ + if ( GET_REC_NOLOCK( fd, strms, + ses.s_cur_nstreams * sizeof( invt_stream_t ), + hdr->sh_streams_off ) < 0 ) { + free (strms); + return -1; + } + + ises = calloc( 1, sizeof( inv_session_t ) ); + ises->s_streams = calloc( ses.s_cur_nstreams, sizeof( inv_stream_t ) ); + ises->s_time = hdr->sh_time; + ises->s_level = hdr->sh_level; + ises->s_nstreams = ses.s_cur_nstreams; + memcpy( &ises->s_sesid, &ses.s_sesid, sizeof( uuid_t ) ); + memcpy( &ises->s_fsid, &ses.s_fsid, sizeof( uuid_t ) ); + strcpy( ises->s_mountpt, ses.s_mountpt ); + strcpy( ises->s_devpath, ses.s_devpath ); + strcpy( ises->s_label, ses.s_label ); + + /* fill in the stream structures too */ + i = (int) ses.s_cur_nstreams; + while ( i-- ) { + ises->s_streams[i].st_interrupted = strms[i].st_interrupted; + ises->s_streams[i].st_startino = strms[i].st_startino.ino; + ises->s_streams[i].st_startino_off = strms[i].st_startino.offset; + ises->s_streams[i].st_endino = strms[i].st_endino.ino; + ises->s_streams[i].st_endino_off = strms[i].st_endino.offset; + ises->s_streams[i].st_nmediafiles = strms[i].st_nmediafiles; + } + + + free( strms ); + *buf = ises; + + return 1; +} + + +void +create_inolist_item( inv_inolist_t *cur, xfs_ino_t ino ) +{ + cur->i_next = malloc( sizeof( inv_inolist_t ) ); + cur->i_next->i_next = NULL; + cur->i_next->i_ino = ino; +} + + + +intgen_t +DEBUG_displayallsessions( int fd, invt_seshdr_t *hdr, u_char level, void **buf ) +{ + inv_session_t **ses = (inv_session_t **) buf; + if ( make_invsess( fd, ses, hdr ) < 1 ) + return -1; + + DEBUG_sessionprint( *ses ); + free( (*ses)->s_streams ); + free( *ses ); + *ses = NULL; + + return 0; +} + + +void +DEBUG_sessionprint( inv_session_t *ses ) +{ + int i; + printf("-------- session -------------\n"); + printf("label\t%s\n", ses->s_label); + printf("mount\t%s\n", ses->s_mountpt); + printf("devpath\t%s\n", ses->s_devpath); + printf("level\t%d\n", ses->s_level); + printf("strms\t%d\n", ses->s_nstreams ); + + for (i = 0; i < (int) ses->s_nstreams; i++ ) { + printf("STR %d (%llu-%llu) nmedia %d\n",i+1, + ses->s_streams[i].st_startino, + ses->s_streams[i].st_endino, + ses->s_streams[i].st_nmediafiles); + } + printf("-------- end -------------\n"); +} + + diff -rNu linux-2.4.7/cmd/xfsdump/common/inventory_priv.h linux-2.4-xfs/cmd/xfsdump/common/inventory_priv.h --- linux-2.4.7/cmd/xfsdump/common/inventory_priv.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/inventory_priv.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef _INVT_PRIV_H_ +#define _INVT_PRIV_H_ + +#include "inventory.h" + + +/* given a file system find that file that tells us where the sessions + for the period of time in question are kept. */ +#define SESSLOCK_FILE INV_DIRPATH"/sesslock" + +#define INVT_STOBJ_MAXSESSIONS 5 +#define INVT_MAX_INVINDICES -1 +#define FSTAB_UPDATED 1 +#define NEW_INVINDEX 2 + +#define INVT_ENDTIME BOOL_FALSE +#define INVT_STARTTIME BOOL_TRUE +#define INVT_DOLOCK BOOL_TRUE +#define INVT_DONTLOCK BOOL_FALSE + +#define INVLOCK( fd, m ) flock( fd, m ) +#define INV_PERMS S_IRWXU | S_IRWXG | S_IRWXO + +#define IS_WITHIN(ttpe, tm) ( tm >= ttpe->tp_start && tm <= ttpe->tp_end ) +#define INVINDEX_HDR_OFFSET(n) (off64_t) ( sizeof( invt_entry_t ) * (size_t) (n)\ + + sizeof( invt_counter_t ) ) + + + +#define GET_COUNTERS( fd, cnt ) get_counters( fd, (void **)(cnt), \ + sizeof(invt_counter_t) ) +#define GET_SESCOUNTERS( fd, cnt ) get_counters( fd, (void **)(cnt), \ + sizeof(invt_sescounter_t) ) + +#define PUT_COUNTERS( fd, cnt ) put_counters( fd, (void *)(cnt), \ + sizeof( invt_counter_t ) ) + +#define PUT_SESCOUNTERS( fd, cnt ) put_counters( fd, (void *)(cnt), \ + sizeof( invt_sescounter_t ) ) + +#define SC_EOF_INITIAL_POS (off64_t) (sizeof( invt_sescounter_t ) + \ + INVT_STOBJ_MAXSESSIONS * \ + ( sizeof( invt_seshdr_t ) + \ + sizeof( invt_session_t ) ) ) + + +typedef struct invt_session { + uuid_t s_sesid; /* this dump session's id: 16 bytes*/ + uuid_t s_fsid; /* file system id */ + char s_label[INV_STRLEN]; /* session label, assigned by the + operator */ + char s_mountpt[INV_STRLEN];/* path to the mount point */ + char s_devpath[INV_STRLEN];/* path to the device */ + u_int s_cur_nstreams;/* number of streams created under this + session so far; protected by lock */ + u_int s_max_nstreams;/* number of media streams in the session */ + +} invt_session_t; + +typedef struct invt_seshdr { + time_t sh_time; /* time of the dump */ + u_char sh_level; /* dump level */ + off64_t sh_sess_off; /* offset to the rest of the session info */ + off64_t sh_streams_off; /* offset to start of the set of stream + hdrs */ +} invt_seshdr_t; + + + + +/* Each session consists of a number of media streams. While it is given that + there won't be multiple writesessions (ie. dumpsessions) concurrently, + there can be multiple media streams operating on a single file system, + each writing media files within its own stream. Hence, we have a linked + list of media files, that the stream keeps track of. */ + + +typedef struct invt_breakpt { + xfs_ino_t ino; /* the 64bit inumber */ + off64_t offset; /* offset into the file */ +} invt_breakpt_t; + +typedef struct invt_stream { + bool_t st_interrupted; /* was this stream interrupted ? */ + + /* duplicate info from mediafiles for speed */ + invt_breakpt_t st_startino; /* the starting pt */ + invt_breakpt_t st_endino; /* where we actually ended up. this means + we've written upto but not including + this breakpoint. */ + int st_nmediafiles; /* number of mediafiles */ + off64_t st_firstmfile; /* offsets to the start and end of the ..*/ + off64_t st_lastmfile; /* .. linked list of mediafiles */ +} invt_stream_t; + + + +typedef struct invt_mediafile { + uuid_t mf_moid; /* media object id */ + char mf_label[INV_STRLEN]; /* media file label */ + invt_breakpt_t mf_startino; /* file that we started out with */ + invt_breakpt_t mf_endino; /* the dump file we ended this + media file with */ + off64_t mf_nextmf; /* links to other mfiles */ + off64_t mf_prevmf; +} invt_mediafile_t; + + +/* XXX tmp */ +typedef invt_mediafile_t invt_mediafileinfo_t; + + +typedef struct invt_desc_entry { + int d_invindex_fd; /* open file descriptor of inv index */ + int d_stobj_fd; /* fd of storage object */ + u_char d_update_flag; /* indicates whether fstab was updated with + this file system or not and also if + we had to create a new invindex file */ + off64_t d_invindex_off; /* for every session, we need a reference + to its invindex entry, so that when we + close a session, we know which one */ + +} invt_desc_entry_t; + + +typedef struct invt_sesdesc_entry { + invt_desc_entry_t *sd_invtok; /* generic inventory token */ + off64_t sd_session_off; + off64_t sd_sesshdr_off; + time_t sd_sesstime; /* time that session started. + needed for closing the session */ +} invt_sesdesc_entry_t; + +struct invt_mediafile; + +typedef struct invt_strdesc_entry { + invt_sesdesc_entry_t *md_sesstok; /* the session token */ + off64_t md_stream_off;/* offset to the media stream + header */ + struct invt_mediafile *md_lastmfile; /* just so that we dont have + to get it back from disk + when we add the next mfile + to the linked list */ + +} invt_strdesc_entry_t; + + +typedef struct invt_timeperiod { + time_t tp_start; + time_t tp_end; +} invt_timeperiod_t; + +typedef struct invt_entry { + invt_timeperiod_t ie_timeperiod; + char ie_filename[INV_STRLEN]; +} invt_entry_t; + +typedef struct invt_counter { + int ic_curnum; /* number of sessions/inv_indices recorded so far + = -1 if there're aren't any */ + int ic_maxnum; /* maximum number of sessions/inv_indices that + we can record on this storage object */ +} invt_counter_t; + +typedef struct invt_sess_metahdr { + u_int ic_curnum; /* number of sessions/inv_indices recorded so far */ + u_int ic_maxnum; /* maximum number of sessions/inv_indices that + we can record on this storage object */ + off64_t ic_eof; /* current end of the file, where the next + media file or stream will be written to */ +} invt_sescounter_t; + + +typedef struct invt_fstab { + uuid_t ft_uuid; + char ft_mountpt[INV_STRLEN]; + char ft_devpath[INV_STRLEN]; +} invt_fstab_t; + +typedef bool_t (*search_callback_t) (int, invt_seshdr_t *, u_char, void *); + + +#define GET_REC( fd, buf, sz, off ) \ + get_invtrecord( fd, buf, sz, off, SEEK_SET, INVT_DOLOCK ) + +#define GET_REC_NOLOCK( fd, buf, sz, off ) \ + get_invtrecord( fd, buf, sz, off, SEEK_SET, INVT_DONTLOCK ) + +#define GET_REC_SEEKCUR( fd, buf, sz, off ) \ + get_invtrecord( fd, buf, sz, off, SEEK_CUR, INVT_DOLOCK ) + +#define GET_ALLHDRS_N_CNTS( fd, h, c, hsz, csz ) \ + get_headerinfo( fd, h, c, hsz, csz, INVT_DOLOCK ) + +#define GET_ALLHDRS_N_CNTS_NOLOCK( fd, h, c, hsz, csz ) \ + get_headerinfo( fd, h, c, hsz, csz, INVT_DONTLOCK ) + +#define PUT_REC( fd, buf, sz, off ) \ + put_invtrecord( fd, buf, sz, off, SEEK_SET, INVT_DOLOCK ) + +#define PUT_REC_NOLOCK( fd, buf, sz, off ) \ + put_invtrecord( fd, buf, sz, off, SEEK_SET, INVT_DONTLOCK ) + +#define PUT_REC_SEEKCUR( fd, buf, sz, off ) \ + put_invtrecord( fd, buf, sz, off, SEEK_CUR, INVT_DOLOCK ) + +#define PUT_REC_NOLOCK_SEEKCUR( fd, buf, sz, off ) \ + put_invtrecord( fd, buf, sz, off, SEEK_CUR, INVT_DONTLOCK ) + + + +/*---------------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*---------------------------------------------------------------------------*/ +inv_idbtoken_t +create_invindex( int fd, char *fname, char *mntpt ); + +intgen_t +get_invtentry( char *fname, time_t tm, invt_entry_t *buf, size_t bufsz ); + +intgen_t +get_invtrecord( int fd, void *buf, size_t bufsz, off64_t off, int, bool_t dolock ); + +intgen_t +put_invtrecord( int fd, void *buf, size_t bufsz, off64_t off, int, bool_t dolock ); + +intgen_t +get_fname( void *pred, char *fname, inv_predicate_t bywhat ); + +inv_idbtoken_t +get_token( int fd, int objfd ); + +void +destroy_token( inv_idbtoken_t tok ); + +int +get_storageobj( int invfd, int *index ); + +int +create_storageobj( char *mntpt, char *fname, int index); + +intgen_t +create_invindex_entry( inv_idbtoken_t *tok, int invfd, char *mntpt, + bool_t firstentry ); + +intgen_t +create_session( inv_sestoken_t tok, int fd, invt_sescounter_t *sescnt, + invt_session_t *ses, invt_seshdr_t *hdr ); + +int +get_curnum( int fd ); + +intgen_t +get_headers( int fd, void **hdrs, size_t bufsz, size_t cntsz ); + +intgen_t +get_counters( int fd, void **cntpp, size_t sz ); + +intgen_t +get_sescounters( int fd, invt_sescounter_t **cntpp ); + +intgen_t +get_lastheader( int fd, void **ent, size_t hdrsz, size_t cntsz ); + +intgen_t +put_fstab_entry( uuid_t *fsidp, char *mntpt, char *dev ); + +intgen_t +get_fstab( invt_fstab_t **arr, invt_counter_t **cnt, int *numfs ); + +intgen_t +put_mediafile( inv_stmtoken_t tok, invt_mediafile_t *mf ); + +intgen_t +put_sesstime( inv_sestoken_t tok, bool_t whichtime); + +intgen_t +open_invindex( void *pred, inv_predicate_t bywhat ); + +int +MY_FLOCK( int f, int k ); + +inv_sestoken_t +get_sesstoken( inv_idbtoken_t tok ); + +intgen_t +put_counters( int fd, void *cntp, size_t sz ); + +intgen_t +get_headerinfo( int fd, void **hdrs, void **cnt, + size_t hdrsz, size_t cntsz, bool_t doblock ); + +void +sess_lock( void ); + +void +sess_unlock( void ); + + +intgen_t +search_invt( + inv_idbtoken_t tok, + u_char level, + void **buf, + search_callback_t do_chkcriteria ); + +intgen_t +tm_level_lessthan( int fd, invt_seshdr_t *hdr, u_char level, + void **tm ); + +intgen_t +lastsess_level_lessthan( int fd, invt_seshdr_t *hdr, u_char level, + void **buf ); + +intgen_t +lastsess_level_equalto( int fd, invt_seshdr_t *hdr, u_char level, void **buf ); + +intgen_t +make_invsess( int fd, inv_session_t **buf, invt_seshdr_t *hdr ); + +void +DEBUG_sessionprint( inv_session_t *ses ); + +intgen_t +DEBUG_displayallsessions( int fd, invt_seshdr_t *hdr, u_char level, void **buf ); + +intgen_t +make_invdirectory( void ); + +bool_t +init_idb( void *pred, inv_predicate_t bywhat, char *uuname,inv_idbtoken_t *tok ); + +void +create_inolist_item( inv_inolist_t *cur, xfs_ino_t ino ); + + +#endif diff -rNu linux-2.4.7/cmd/xfsdump/common/lock.c linux-2.4-xfs/cmd/xfsdump/common/lock.c --- linux-2.4.7/cmd/xfsdump/common/lock.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/lock.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include "types.h" +#include "qlock.h" +#include "mlog.h" + +static qlockh_t lock_qlockh = QLOCKH_NULL; + +bool_t +lock_init( void ) +{ + /* initialization sanity checks + */ + ASSERT( lock_qlockh == QLOCKH_NULL ); + + /* allocate a qlock + */ + lock_qlockh = qlock_alloc( QLOCK_ORD_CRIT ); + + return BOOL_TRUE; +} + +void +lock( void ) +{ + qlock_lock( lock_qlockh ); +} + +void +unlock( void ) +{ + qlock_unlock( lock_qlockh ); +} diff -rNu linux-2.4.7/cmd/xfsdump/common/lock.h linux-2.4-xfs/cmd/xfsdump/common/lock.h --- linux-2.4.7/cmd/xfsdump/common/lock.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/lock.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef LOCK_H +#define LOCK_H + +extern bool_t lock_init( void ); + +extern void lock( void ); + +extern void unlock( void ); + +#endif /* LOCK_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/main.c linux-2.4-xfs/cmd/xfsdump/common/main.c --- linux-2.4.7/cmd/xfsdump/common/main.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/main.c Thu Jul 5 03:42:14 2001 @@ -0,0 +1,2613 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stkchk.h" +#include "exit.h" +#include "types.h" +#include "stream.h" +#include "cldmgr.h" +#include "util.h" +#include "getopt.h" +#include "mlog.h" +#include "qlock.h" +#include "lock.h" +#include "dlog.h" +#include "global.h" +#include "drive.h" +#include "media.h" +#include "content.h" +#include "inventory.h" + +#ifdef DUMP +/* main.c - main for dump + */ +#endif /* DUMP */ +#ifdef RESTORE +/* main.c - main for restore + */ +#endif /* RESTORE */ + + +/* structure definitions used locally ****************************************/ + +#ifdef RESTORE +#define VMSZ_PER 4 /* proportion of available vm to use in tree */ +#endif /* RESTORE */ +#define DLOG_TIMEOUT 60 /* time out operator dialog */ +#define STOP_TIMEOUT 600 /* seconds after stop req. before abort */ +#define ABORT_TIMEOUT 10 /* seconds after abort req. before abort */ +#define MINSTACKSZ 0x02000000 +#define MAXSTACKSZ 0x08000000 + + +/* declarations of externally defined global symbols *************************/ + +extern void rmt_turnonmsgs(int); + +/* forward declarations of locally defined global functions ******************/ + +void usage( void ); +bool_t preemptchk( int ); + + +/* forward declarations of locally defined static functions ******************/ + +static bool_t loadoptfile( int *argcp, char ***argvp ); +static char * stripquotes( char *p ); +static void shiftleftby1( char *p, char *endp ); +static bool_t in_miniroot_heuristic( void ); +#ifdef HIDDEN +static void mrh_sighandler( int ); +#endif +static void sighandler( int ); +static int childmain( void * ); +static bool_t sigint_dialog( void ); +static char *sigintstr( void ); +#ifdef DUMP +static bool_t set_rlimits( void ); +#endif /* DUMP */ +#ifdef RESTORE +static bool_t set_rlimits( size64_t * ); +#endif /* RESTORE */ +static char *exit_codestring( intgen_t code ); +static char *sig_numstring( intgen_t num ); +static char *strpbrkquotes( char *p, const char *sep ); + + +/* definition of locally defined global variables ****************************/ + +intgen_t version = 3; +intgen_t subversion = 0; +char *progname = 0; /* used in all error output */ +char *homedir = 0; /* directory invoked from */ +#ifdef HIDDEN +bool_t miniroot = BOOL_FALSE; +#else +bool_t miniroot = BOOL_TRUE; +#endif /* HIDDEN */ +bool_t pipeline = BOOL_FALSE; +bool_t stdoutpiped = BOOL_FALSE; +pid_t parentpid; +char *sistr; +size_t pgsz; +size_t pgmask; + + +/* definition of locally defined static variables *****************************/ + +static rlim64_t minstacksz; +static rlim64_t maxstacksz; +#ifdef RESTORE +static size64_t vmsz; +#endif /* RESTORE */ +static time_t stop_deadline; +static bool_t stop_in_progress; +static bool_t sighup_received; +static bool_t sigterm_received; +static bool_t sigpipe_received; +static bool_t sigquit_received; +static bool_t sigint_received; +static size_t prbcld_cnt; +static pid_t prbcld_pid; +static intgen_t prbcld_xc; +static intgen_t prbcld_signo; +/* REFERENCED */ +static intgen_t sigstray_received; +static bool_t progrpt_enabledpr; +static time_t progrpt_interval; +static time_t progrpt_deadline; + + +/* definition of locally defined global functions ****************************/ + +#ifdef NEVER +void +stkplay( int level ) +{ + intgen_t rval; + + char dummy[ 4096 ]; + mlog( MLOG_DEBUG | MLOG_PROC, + "stkplay( %d )\n", + level ); + rval = stkchk( ); + if ( rval > 1 ) { + return; + } + stkplay( level + 1 ); +} +#endif /* NEVER */ + +int +main( int argc, char *argv[] ) +{ + int c; +#ifdef DUMP + uid_t euid; +#endif /* DUMP */ + ix_t stix; /* stream index */ + bool_t infoonly; +#ifdef DUMP + global_hdr_t *gwhdrtemplatep; +#endif /* DUMP */ + bool_t init_error; + bool_t coredump_requested = BOOL_FALSE; + intgen_t exitcode; + rlim64_t tmpstacksz; + bool_t ok; + + /* sanity checks + */ + ASSERT( sizeof( char_t ) == 1 ); + ASSERT( sizeof( u_char_t ) == 1 ); + ASSERT( sizeof( int32_t ) == 4 ); + ASSERT( sizeof( u_int32_t ) == 4 ); + ASSERT( sizeof( size32_t ) == 4 ); + ASSERT( sizeof( int64_t ) == 8 ); + ASSERT( sizeof( u_int64_t ) == 8 ); + ASSERT( sizeof( size64_t ) == 8 ); + + /* record the command name used to invoke + */ + progname = argv[ 0 ]; + + /* pre-scan the command line for the option file option. + * if found, create a new argv. + */ + ok = loadoptfile( &argc, &argv ); + if ( ! ok ) { + return EXIT_ERROR; + } + + /* initialize message logging (stage 1) + */ + ok = mlog_init1( argc, argv ); + if ( ! ok ) { + return EXIT_ERROR; + } + /* scan the command line for the miniroot, info, progress + * report options, and stacksz. + */ + minstacksz = MINSTACKSZ; + maxstacksz = MAXSTACKSZ; +#ifdef HIDDEN + miniroot = BOOL_FALSE; +#else + miniroot = BOOL_TRUE; +#endif /* HIDDEN */ + infoonly = BOOL_FALSE; + progrpt_enabledpr = BOOL_FALSE; + optind = 1; + opterr = 0; + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + switch ( c ) { + case GETOPT_MINSTACKSZ: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_NOLOCK, + "-%c argument missing\n", + optopt ); + usage( ); + return EXIT_ERROR; + } + errno = 0; + tmpstacksz = strtoull( optarg, 0, 0 ); + if ( tmpstacksz == UINT64_MAX + || + errno == ERANGE ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_NOLOCK, + "-%c argument (%s) invalid\n", + optopt, + optarg ); + usage( ); + return EXIT_ERROR; + } + minstacksz = tmpstacksz; + break; + case GETOPT_MAXSTACKSZ: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_NOLOCK, + "-%c argument missing\n", + optopt ); + usage( ); + return EXIT_ERROR; + } + errno = 0; + tmpstacksz = strtoull( optarg, 0, 0 ); + if ( tmpstacksz == UINT64_MAX + || + errno == ERANGE ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_NOLOCK, + "-%c argument (%s) invalid\n", + optopt, + optarg ); + usage( ); + return EXIT_ERROR; + } + maxstacksz = tmpstacksz; + break; + case GETOPT_MINIROOT: + miniroot = BOOL_TRUE; + break; + case GETOPT_HELP: + infoonly = BOOL_TRUE; + break; + case GETOPT_PROGRESS: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_NOLOCK, + "-%c argument missing\n", + optopt ); + usage( ); + return EXIT_ERROR; + } + progrpt_interval = ( time_t )atoi( optarg ); + if ( progrpt_interval > 0 ) { + progrpt_enabledpr = BOOL_TRUE; + } else { + progrpt_enabledpr = BOOL_FALSE; + } + break; + } + } + + /* sanity check resultant stack size limits + */ + if ( minstacksz > maxstacksz ) { + mlog( MLOG_NORMAL + | + MLOG_ERROR + | + MLOG_NOLOCK + | + MLOG_PROC, + "specified minimum stack size is larger than maximum: " + "min is 0x%llx, max is 0x%llx\n", + minstacksz, + maxstacksz ); + return EXIT_ERROR; + } + + if ( argc == 1 ) { + infoonly = BOOL_TRUE; + } + + /* set a progress report deadline to allow preemptchk() to + * report + */ + if ( progrpt_enabledpr ) { + progrpt_deadline = time( 0 ) + progrpt_interval; + } + + /* intitialize the stream manager + */ + stream_init( ); + +#ifdef DUMP + /* set the memory limits to their appropriate values. + */ + ok = set_rlimits( ); +#endif /* DUMP */ +#ifdef RESTORE + /* set the memory limits to their appropriate values. this is necessary + * to accomodate the tree abstraction and some recursive functions. + * also determines maximum vm, which will be budgeted among the + * various abstractions. + */ + ok = set_rlimits( &vmsz ); +#endif /* RESTORE */ + if ( ! ok ) { + return EXIT_ERROR; + } + + /* perform an experiment to determine if we are in the miniroot. + * various features will be disallowed if in miniroot. + */ + if ( ! miniroot && in_miniroot_heuristic( )) { + miniroot = BOOL_TRUE; + } + + /* initialize the spinlock allocator + */ + ok = qlock_init( miniroot ); + if ( ! ok ) { + return EXIT_ERROR; + } + + /* initialize message logging (stage 2) + */ + ok = mlog_init2( ); + if ( ! ok ) { + return EXIT_ERROR; + } + + rmt_turnonmsgs(1); /* turn on WARNING msgs for librmt */ + + mlog( MLOG_NITTY + 1, "INTGENMAX == %ld (0x%lx)\n", INTGENMAX, INTGENMAX ); + mlog( MLOG_NITTY + 1, "UINTGENMAX == %lu (0x%lx)\n", UINTGENMAX, UINTGENMAX ); + mlog( MLOG_NITTY + 1, "OFF64MAX == %lld (0x%llx)\n", OFF64MAX, OFF64MAX ); + mlog( MLOG_NITTY + 1, "OFFMAX == %ld (0x%lx)\n", OFFMAX, OFFMAX ); + mlog( MLOG_NITTY + 1, "SIZEMAX == %lu (0x%lx)\n", SIZEMAX, SIZEMAX ); + mlog( MLOG_NITTY + 1, "INOMAX == %lu (0x%lx)\n", INOMAX, INOMAX ); + mlog( MLOG_NITTY + 1, "TIMEMAX == %ld (0x%lx)\n", TIMEMAX, TIMEMAX ); + mlog( MLOG_NITTY + 1, "SIZE64MAX == %llu (0x%llx)\n", SIZE64MAX, SIZE64MAX ); + mlog( MLOG_NITTY + 1, "INO64MAX == %llu (0x%llx)\n", INO64MAX, INO64MAX ); + mlog( MLOG_NITTY + 1, "UINT64MAX == %llu (0x%llx)\n", UINT64MAX, UINT64MAX ); + mlog( MLOG_NITTY + 1, "INT64MAX == %lld (0x%llx)\n", INT64MAX, INT64MAX ); + mlog( MLOG_NITTY + 1, "UINT32MAX == %u (0x%x)\n", UINT32MAX, UINT32MAX ); + mlog( MLOG_NITTY + 1, "INT32MAX == %d (0x%x)\n", INT32MAX, INT32MAX ); + mlog( MLOG_NITTY + 1, "INT16MAX == %d (0x%x)\n", INT16MAX, INT16MAX ); + mlog( MLOG_NITTY + 1, "UINT16MAX == %u (0x%x)\n", UINT16MAX, UINT16MAX ); + + /* ask the system for the true vm page size, which must be used + * in all mmap calls + */ + pgsz = ( size_t )getpagesize( ); + mlog( MLOG_DEBUG | MLOG_PROC, + "getpagesize( ) returns %u\n", + pgsz ); + ASSERT( ( intgen_t )pgsz > 0 ); + pgmask = pgsz - 1; + + /* initialize the critical region lock + */ + lock_init( ); + + /* Get the parent's pid. will be used in signal handling + * to differentiate parent from children. + */ + parentpid = getpid( ); + mlog( MLOG_DEBUG | MLOG_PROC, + "parent pid is %d\n", + parentpid ); + + /* get the current working directory: this is where we will dump + * core, if necessary. some tmp files may be placed here as well. + */ + homedir = getcwd( 0, MAXPATHLEN ); + if ( ! homedir ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "unable to determine current directory: %s\n", + strerror( errno )); + return EXIT_ERROR; + } + + /* if just looking for info, oblige + */ + if ( infoonly ) { + mlog( MLOG_NORMAL, + "version %d.%d\n", + version, + subversion ); + usage( ); + return EXIT_NORMAL; /* normal termination */ + } + + /* if an inventory display is requested, do it and exit + */ + if ( ! inv_DEBUG_print( argc, argv )) { + return EXIT_NORMAL; /* normal termination */ + } + +#ifdef DUMP + /* insist that the effective user id is root. + * this must appear after inv_DEBUG_print(), + * so it may be done without root privilege. + */ + euid = geteuid( ); + mlog( MLOG_DEBUG | MLOG_PROC, + "effective user id is %d\n", + euid ); + if ( euid != 0 ) { + mlog( MLOG_NORMAL, + "effective user ID must be root\n" ); + return EXIT_ERROR; + } +#endif /* DUMP */ + + /* initialize operator dialog capability + */ + ok = dlog_init( argc, argv ); + if ( ! ok ) { + return EXIT_ERROR; + } + + /* initialize the stack checking abstraction + */ + stkchk_init( STREAM_SIMMAX * 2 + 1 ); + stkchk_register( ); + + /* initialize the child process manager + */ + ok = cldmgr_init( ); + if ( ! ok ) { + return EXIT_ERROR; + } + + /* select and instantiate a drive manager for each stream. this + * is the first pass at initialization, so don't do anything + * terribly time-consuming here. A second initialization pass + * will be done shortly. + */ + ok = drive_init1( argc, argv, miniroot ); + if ( ! ok ) { + cldmgr_killall( ); + return EXIT_ERROR; + } + + /* check the drives to see if we're in a pipeline. + * if not, check stdout anyway, in case someone is trying to pipe + * the log messages into more, tee, ... + */ + if ( drivepp[ 0 ]->d_isunnamedpipepr ) { + mlog( MLOG_DEBUG | MLOG_NOTE, + "pipeline detected\n" ); + pipeline = BOOL_TRUE; + } else { + struct stat64 statbuf; + if ( fstat64( 1, &statbuf ) == 0 + && + ( statbuf.st_mode & S_IFMT ) == S_IFIFO ) { + stdoutpiped = BOOL_TRUE; + } + } + +#ifdef NEVER + stkplay( 0 ); +#endif /* NEVER */ + + /* announce version and instructions + */ + sistr = sigintstr( ); + mlog( MLOG_VERBOSE, + "version %d.%d", + version, + subversion ); + if ( miniroot ) { + mlog( MLOG_VERBOSE | MLOG_BARE, + " - " + "Running single-threaded\n" ); + } else if ( ! pipeline && ! stdoutpiped && sistr && dlog_allowed( )) { + mlog( MLOG_VERBOSE | MLOG_BARE, + " - " + "type %s for status and control\n", + sistr ); + } else { + mlog( MLOG_VERBOSE | MLOG_BARE, + "\n" ); + } + +#ifdef DUMP + /* build a global write header template + */ + gwhdrtemplatep = global_hdr_alloc( argc, argv ); + if ( ! gwhdrtemplatep ) { + return EXIT_ERROR; + } +#endif /* DUMP */ + + /* tell mlog how many streams there are. the format of log messages + * depends on whether there are one or many. + */ + mlog_tell_streamcnt( drivecnt ); + + /* initialize the state of signal processing. if miniroot or + * pipeline, just want to exit when a signal is received. otherwise, + * hold signals so they don't interfere with sys calls; they will + * be released at pre-emption points and upon pausing in the main + * loop. + */ + if ( ! miniroot && ! pipeline ) { + stop_in_progress = BOOL_FALSE; + coredump_requested = BOOL_FALSE; + sighup_received = BOOL_FALSE; + sigterm_received = BOOL_FALSE; + sigint_received = BOOL_FALSE; + sigpipe_received = BOOL_FALSE; + sigquit_received = BOOL_FALSE; + sigstray_received = BOOL_FALSE; + prbcld_cnt = 0; + sigset( SIGINT, sighandler ); + sighold( SIGINT ); + sigset( SIGHUP, sighandler ); + sighold( SIGHUP ); + sigset( SIGTERM, sighandler ); + sighold( SIGTERM ); + sigset( SIGPIPE, sighandler ); + sighold( SIGPIPE ); + sigset( SIGQUIT, sighandler ); + sighold( SIGQUIT ); + alarm( 0 ); + sigset( SIGALRM, sighandler ); + sighold( SIGALRM ); + sigset( SIGCLD, sighandler ); + sighold( SIGCLD ); + } + + /* do content initialization. + */ +#ifdef DUMP + ok = content_init( argc, argv, gwhdrtemplatep ); +#endif /* DUMP */ +#ifdef RESTORE + ok = content_init( argc, argv, vmsz / VMSZ_PER ); +#endif /* RESTORE */ + if ( ! ok ) { + cldmgr_killall( ); + return EXIT_ERROR; + } + + /* if miniroot or a pipeline, go single-threaded + * with just one stream. + */ + if ( miniroot || pipeline ) { + intgen_t exitcode; + + sigset( SIGINT, sighandler ); + sigset( SIGHUP, sighandler ); + sigset( SIGTERM, sighandler ); + sigset( SIGPIPE, sighandler ); + + ok = drive_init2( argc, + argv, +#ifdef DUMP + gwhdrtemplatep ); +#endif /* DUMP */ +#ifdef RESTORE + ( global_hdr_t * )0 ); +#endif /* RESTORE */ + if ( ! ok ) { + return EXIT_ERROR; + } + ok = drive_init3( ); + if ( ! ok ) { + return EXIT_ERROR; + } +#ifdef DUMP + exitcode = content_stream_dump( 0 ); +#endif /* DUMP */ +#ifdef RESTORE + exitcode = content_stream_restore( 0 ); +#endif /* RESTORE */ + if ( exitcode != EXIT_NORMAL ) { + ( void )content_complete( ); + /* for cleanup side-effect */ + return exitcode; + } else if ( content_complete( )) { + return EXIT_NORMAL; + } else { + return EXIT_INTERRUPT; + } + } + + /* used to skip to end if errors occur during any + * stage of initialization. + */ + init_error = BOOL_FALSE; + + /* now do the second and third passes of drive initialization. + * allocate per-stream write and read headers. if a drive + * manager uses a slave process, it should be created now, + * using cldmgr_create( ). each drive manager may use the slave to + * asynchronously read the media file header, typically a very + * time-consuming chore. drive_init3 will synchronize with each slave. + */ + if ( ! init_error ) { + ok = drive_init2( argc, + argv, +#ifdef DUMP + gwhdrtemplatep ); +#endif /* DUMP */ +#ifdef RESTORE + ( global_hdr_t * )0 ); +#endif /* RESTORE */ + if ( ! ok ) { + init_error = BOOL_TRUE; + } + } + if ( ! init_error ) { + ok = drive_init3( ); + if ( ! ok ) { + init_error = BOOL_TRUE; + } + } + + /* create a child thread for each stream. drivecnt global from + * drive.h, initialized by drive_init[12] + */ + if ( ! init_error ) { + for ( stix = 0 ; stix < drivecnt ; stix++ ) { + ok = cldmgr_create( childmain, + CLONE_VM, + stix, + "child", + ( void * )stix ); + if ( ! ok ) { + init_error = BOOL_TRUE; + } + } + } + + /* loop here, waiting for children to die, processing operator + * signals. + */ + if ( progrpt_enabledpr ) { + ( void )alarm( ( u_intgen_t )progrpt_interval ); + } + for ( ; ; ) { + time_t now; + bool_t stop_requested = BOOL_FALSE; + intgen_t stop_timeout = -1; + + /* if there was an initialization error, + * immediately stop all children. + */ + if ( init_error ) { + stop_timeout = STOP_TIMEOUT; + stop_requested = BOOL_TRUE; + } + + /* if one or more children died abnormally, request a + * stop. furthermore, note that core should be dumped if + * the child explicitly exited with EXIT_FAULT. + */ + if ( prbcld_cnt ) { + if ( prbcld_xc == EXIT_FAULT || prbcld_signo != 0 ) { + coredump_requested = BOOL_TRUE; + stop_timeout = ABORT_TIMEOUT; + } else { + stop_timeout = STOP_TIMEOUT; + } + stop_requested = BOOL_TRUE; + if ( prbcld_xc != EXIT_NORMAL ) { + mlog( MLOG_DEBUG | MLOG_PROC, + "child (pid %d) requested stop: " + "exit code %d (%s)\n", + prbcld_pid, + prbcld_xc, + exit_codestring( prbcld_xc )); + } else if ( prbcld_signo ) { + ASSERT( prbcld_signo ); + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_PROC, + "child (pid %d) faulted: " + "signal number %d (%s)\n", + prbcld_pid, + prbcld_signo, + sig_numstring( prbcld_signo )); + } + prbcld_cnt = 0; + } + + /* all children died normally. break out. + */ + if ( cldmgr_remainingcnt( ) == 0 ) { + mlog( MLOG_DEBUG, + "all children have exited\n" ); + break; + } + + /* get the current time + */ + now = time( 0 ); + + /* check for stop timeout. request a core dump and bail + */ + if ( stop_in_progress && now >= stop_deadline ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "session interrupt timeout\n" ); + coredump_requested = BOOL_TRUE; + break; + } + + /* operator sent SIGINT. if dialog allowed, enter dialog. + * otherwise treat as a hangup and request a stop. + */ + if ( sigint_received ) { + mlog( MLOG_DEBUG | MLOG_PROC, + "SIGINT received\n" ); + if ( stop_in_progress ) { + if ( dlog_allowed( )) { + ( void )sigint_dialog( ); + } + /* + mlog( MLOG_NORMAL, + "session interrupt in progress: " + "please wait\n" ); + */ + } else { + if ( dlog_allowed( )) { + stop_requested = sigint_dialog( ); + } else { + stop_requested = BOOL_TRUE; + } + stop_timeout = STOP_TIMEOUT; + } + + /* important that this appear after dialog. + * allows dialog to be terminated with SIGINT, + * without infinite loop. + */ + sigint_received = BOOL_FALSE; + } + + /* refresh the current time in case in dialog for a while + */ + now = time( 0 ); + + /* request a stop on hangup + */ + if ( sighup_received ) { + mlog( MLOG_DEBUG | MLOG_PROC, + "SIGHUP received\n" ); + stop_requested = BOOL_TRUE; + stop_timeout = STOP_TIMEOUT; + sighup_received = BOOL_FALSE; + } + + /* request a stop on termination request + */ + if ( sigterm_received ) { + mlog( MLOG_DEBUG | MLOG_PROC, + "SIGTERM received\n" ); + stop_requested = BOOL_TRUE; + stop_timeout = STOP_TIMEOUT; + sigterm_received = BOOL_FALSE; + } + + /* request a stop on loss of write pipe + */ + if ( sigpipe_received ) { + mlog( MLOG_DEBUG | MLOG_PROC, + "SIGPIPE received\n" ); + stop_requested = BOOL_TRUE; + stop_timeout = STOP_TIMEOUT; + sigpipe_received = BOOL_FALSE; + } + + /* operator send SIGQUIT. treat like an interrupt, + * but force a core dump + */ + if ( sigquit_received ) { + mlog( MLOG_NORMAL | MLOG_PROC, + "SIGQUIT received\n" ); + if ( stop_in_progress ) { + mlog( MLOG_NORMAL, + "session interrupt in progress: " + "please wait\n" ); + stop_deadline = now; + } else { + stop_requested = BOOL_TRUE; + stop_timeout = ABORT_TIMEOUT; + sigquit_received = BOOL_FALSE; + coredump_requested = BOOL_TRUE; + } + } + + /* see if need to initiate a stop + */ + if ( stop_requested && ! stop_in_progress ) { + mlog( MLOG_NORMAL, + "initiating session interrupt\n" ); + stop_in_progress = BOOL_TRUE; + cldmgr_stop( ); + ASSERT( stop_timeout >= 0 ); + stop_deadline = now + ( time_t )stop_timeout; + } + + /* set alarm if needed (note time stands still during dialog) + */ + if ( stop_in_progress ) { + intgen_t timeout = ( intgen_t )( stop_deadline - now ); + if ( timeout < 0 ) { + timeout = 0; + } + mlog( MLOG_DEBUG | MLOG_PROC, + "setting alarm for %d second%s\n", + timeout, + timeout == 1 ? "" : "s" ); + ( void )alarm( ( u_intgen_t )timeout ); + if ( timeout == 0 ) { + continue; + } + } + + if ( progrpt_enabledpr && ! stop_in_progress ) { + bool_t need_progrptpr = BOOL_FALSE; + while ( now >= progrpt_deadline ) { + need_progrptpr = BOOL_TRUE; + progrpt_deadline += progrpt_interval; + } + if ( need_progrptpr ) { + size_t statlinecnt; + char **statline; + ix_t i; + statlinecnt = content_statline( &statline ); + for ( i = 0 ; i < statlinecnt ; i++ ) { + mlog( MLOG_NORMAL, + statline[ i ] ); + } + } + ( void )alarm( ( u_intgen_t )( progrpt_deadline + - + now )); + } + + /* sleep until next signal + */ + sigrelse( SIGINT ); + sigrelse( SIGHUP ); + sigrelse( SIGTERM ); + sigrelse( SIGPIPE ); + sigrelse( SIGQUIT ); + sigrelse( SIGALRM ); + ( void )sigpause( SIGCLD ); + sighold( SIGCLD ); + sighold( SIGALRM ); + sighold( SIGQUIT ); + sighold( SIGPIPE ); + sighold( SIGTERM ); + sighold( SIGHUP ); + sighold( SIGINT ); + ( void )alarm( 0 ); + } + + /* check if core dump requested + */ + if ( coredump_requested ) { + mlog( MLOG_DEBUG | MLOG_PROC, + "killing all remaining children\n" ); + cldmgr_killall( ); + sleep( 1 ); + mlog( MLOG_DEBUG | MLOG_PROC, + "parent sending SIGQUIT to self (pid %d)\n", + parentpid ); + sigrelse( SIGQUIT ); + sigset( SIGQUIT, SIG_DFL ); + kill( parentpid, SIGQUIT ); + for ( ; ; ) { + sleep( 1 ); + } + } + + /* determine if dump or restore was interrupted + * or an initialization error occurred. + */ + if ( init_error ) { + ( void )content_complete( ); + exitcode = EXIT_ERROR; + } else { + exitcode = content_complete( ) ? EXIT_NORMAL : EXIT_INTERRUPT; + } + return exitcode; +} + +#define ULO( f, o ) fprintf( stderr, \ + "%*s[ -%c " f " ]\n", \ + ps, \ + ns, \ + o ), \ + ps = pfxsz + +#define ULN( f ) fprintf( stderr, \ + "%*s[ " f " ]\n", \ + ps, \ + ns ), \ + ps = pfxsz + +void +usage( void ) +{ + char linebuf[ 200 ]; + int pfxsz; + int ps; + char *ns = ""; + + sprintf( linebuf, + "%s: usage: %s ", + progname, + basename( progname )); + pfxsz = strlen( linebuf ); + ASSERT( pfxsz < sizeof( linebuf )); + ps = 0; + + fprintf( stderr, linebuf ); + +#ifdef DUMP + ULO( "(dump DMF dualstate files as offline)", GETOPT_DUMPASOFFLINE ); + ULO( "", GETOPT_BLOCKSIZE ); + ULO( " ", GETOPT_ALERTPROG ); + ULO( " ...", GETOPT_DUMPDEST ); + ULO( "(help)", GETOPT_HELP ); + ULO( "", GETOPT_LEVEL ); + ULO( "", GETOPT_MINRMT ); + ULO( "", GETOPT_OVERWRITE ); + ULO( "", GETOPT_PROGRESS ); + ULO( " ...", GETOPT_SUBTREE ); + ULO( "", GETOPT_VERBOSITY ); +#ifdef EXTATTR + ULO( "(don't dump extended file attributes)", GETOPT_NOEXTATTR ); +#endif /* EXTATTR */ +#ifdef DMEXTATTR + ULO( "(restore DMAPI event settings)", GETOPT_SETDM ); +#endif /* DMEXTATTR */ +#ifdef BASED + ULO( "", GETOPT_BASED ); +#endif /* BASED */ +#ifdef REVEAL + ULO( "(generate tape record checksums)", GETOPT_RECCHKSUM ); +#endif /* REVEAL */ + ULO( "(pre-erase media)", GETOPT_ERASE ); + ULO( "(don't prompt)", GETOPT_FORCE ); +#ifdef REVEAL + ULO( "", GETOPT_MINSTACKSZ ); + ULO( "", GETOPT_MAXSTACKSZ ); +#endif /* REVEAL */ + ULO( "(display dump inventory)", GETOPT_INVPRINT ); + ULO( "(inhibit inventory update)", GETOPT_NOINVUPDATE ); + ULO( "", GETOPT_DUMPLABEL ); + ULO( " ...", GETOPT_MEDIALABEL ); +#ifdef REVEAL + ULO( "(timestamp messages)", GETOPT_TIMESTAMP ); +#endif /* REVEAL */ + ULO( "", GETOPT_OPTFILE ); +#ifdef REVEAL + ULO( "(pin down I/O buffers)", GETOPT_RINGPIN ); +#endif /* REVEAL */ + ULO( "(resume)", GETOPT_RESUME ); +#ifdef REVEAL + ULO( "(generate single media file)", GETOPT_SINGLEMFILE ); +#endif /* REVEAL */ + ULO( "(don't timeout dialogs)", GETOPT_NOTIMEOUTS ); +#ifdef REVEAL + ULO( "(unload media when change needed)", GETOPT_UNLOAD ); + ULO( "(show subsystem in messages)", GETOPT_SHOWLOGSS ); + ULO( "(show verbosity in messages)", GETOPT_SHOWLOGLEVEL ); +#endif /* REVEAL */ + ULO( "", GETOPT_RINGLEN ); +#ifdef REVEAL + ULO( "(miniroot restrictions)", GETOPT_MINIROOT ); +#endif /* REVEAL */ + ULN( "- (stdout)" ); + ULN( "" ); +#endif /* DUMP */ +#ifdef RESTORE + ULO( " ...", GETOPT_WORKSPACE ); + ULO( "", GETOPT_BLOCKSIZE ); + ULO( " ", GETOPT_ALERTPROG ); + ULO( "(don't overwrite existing files)", GETOPT_EXISTING ); + ULO( " ...", GETOPT_DUMPDEST ); + ULO( "(help)", GETOPT_HELP ); + ULO( "(interactive)", GETOPT_INTERACTIVE ); + ULO( "", GETOPT_MINRMT ); + ULO( " (restore only if newer than)", GETOPT_NEWER ); + ULO( "(restore owner/group even if not root)", GETOPT_OWNER ); + ULO( "", GETOPT_PROGRESS ); + ULO( "(cumulative restore)", GETOPT_CUMULATIVE ); + ULO( " ...", GETOPT_SUBTREE ); + ULO( "(contents only)", GETOPT_TOC ); + ULO( "", GETOPT_VERBOSITY ); +#ifdef EXTATTR + ULO( "(don't restore extended file attributes)",GETOPT_NOEXTATTR ); +#endif /* EXTATTR */ +#ifdef REVEAL + ULO( "(check tape record checksums)", GETOPT_RECCHKSUM ); +#endif /* REVEAL */ + ULO( "(don't overwrite if changed)", GETOPT_CHANGED ); + ULO( "(don't prompt)", GETOPT_FORCE ); + ULO( "(display dump inventory)", GETOPT_INVPRINT ); + ULO( "(inhibit inventory update)", GETOPT_NOINVUPDATE ); + ULO( "", GETOPT_DUMPLABEL ); +#ifdef REVEAL + ULO( "(timestamp messages)", GETOPT_TIMESTAMP ); +#endif /* REVEAL */ + ULO( "", GETOPT_OPTFILE ); +#ifdef REVEAL + ULO( "(pin down I/O buffers)", GETOPT_RINGPIN ); +#endif /* REVEAL */ +#ifdef SESSCPLT + ULO( "(force interrupted session completion)", GETOPT_SESSCPLT ); +#endif /* SESSCPLT */ + ULO( "(resume)", GETOPT_RESUME ); + ULO( "", GETOPT_SESSIONID ); + ULO( "(don't timeout dialogs)", GETOPT_NOTIMEOUTS ); +#ifdef REVEAL + ULO( "(unload media when change needed)", GETOPT_UNLOAD ); + ULO( "(show subsystem in messages)", GETOPT_SHOWLOGSS ); + ULO( "(show verbosity in messages)", GETOPT_SHOWLOGLEVEL ); +#endif /* REVEAL */ + ULO( " ...", GETOPT_NOSUBTREE ); + ULO( "", GETOPT_RINGLEN ); +#ifdef REVEAL + ULO( "(miniroot restrictions)", GETOPT_MINIROOT ); +#endif /* REVEAL */ + ULN( "- (stdin)" ); + ULN( "" ); +#endif /* RESTORE */ +} + +/* returns TRUE if preemption + */ +bool_t +preemptchk( int flg ) +{ + bool_t preempt_requested; + + /* see if a progress report needed + */ + if ( progrpt_enabledpr ) { + time_t now = time( 0 ); + bool_t need_progrptpr = BOOL_FALSE; + while ( now >= progrpt_deadline ) { + need_progrptpr = BOOL_TRUE; + progrpt_deadline += progrpt_interval; + } + if ( need_progrptpr ) { + size_t statlinecnt; + char **statline; + ix_t i; + statlinecnt = content_statline( &statline ); + for ( i = 0 ; i < statlinecnt ; i++ ) { + mlog( MLOG_NORMAL, + statline[ i ] ); + } + } + } + + /* Progress report only */ + if (flg == PREEMPT_PROGRESSONLY) { + return BOOL_FALSE; + } + + /* signals not caught in these cases + */ + if ( miniroot || pipeline ) { + return BOOL_FALSE; + } + + /* release signals momentarily to let any pending ones + * invoke signal handler and set flags + */ + sigrelse( SIGINT ); + sigrelse( SIGHUP ); + sigrelse( SIGTERM ); + sigrelse( SIGPIPE ); + sigrelse( SIGQUIT ); + + sighold( SIGQUIT ); + sighold( SIGPIPE ); + sighold( SIGTERM ); + sighold( SIGHUP ); + sighold( SIGINT ); + + preempt_requested = BOOL_FALSE; + + if ( sigint_received ) { + mlog( MLOG_DEBUG | MLOG_PROC, + "SIGINT received (preempt)\n" ); + if ( dlog_allowed( )) { + preempt_requested = sigint_dialog( ); + } else { + preempt_requested = BOOL_TRUE; + } + /* important that this appear after dialog. + * allows dialog to be terminated with SIGINT, + * without infinite loop. + */ + sigint_received = BOOL_FALSE; + } + + if ( sighup_received ) { + mlog( MLOG_DEBUG | MLOG_PROC, + "SIGHUP received (prempt)\n" ); + preempt_requested = BOOL_TRUE; + sighup_received = BOOL_FALSE; + } + + if ( sigterm_received ) { + mlog( MLOG_DEBUG | MLOG_PROC, + "SIGTERM received (prempt)\n" ); + preempt_requested = BOOL_TRUE; + sigterm_received = BOOL_FALSE; + } + + if ( sigpipe_received ) { + mlog( MLOG_DEBUG | MLOG_PROC, + "SIGPIPE received\n" ); + preempt_requested = BOOL_TRUE; + sigpipe_received = BOOL_FALSE; + } + + if ( sigquit_received ) { + mlog( MLOG_NORMAL | MLOG_PROC, + "SIGQUIT received (preempt)\n" ); + preempt_requested = BOOL_TRUE; + sigquit_received = BOOL_FALSE; + } + + return preempt_requested; +} + +/* definition of locally defined static functions ****************************/ + +static bool_t +loadoptfile( intgen_t *argcp, char ***argvp ) +{ + char *optfilename; + ix_t optfileix = 0; + intgen_t fd; + size_t sz; + intgen_t i; + struct stat64 stat; + char *argbuf; + char *p; + size_t tokencnt; + intgen_t nread; + const char *sep = " \t\n\r"; + char **newargv; + intgen_t c; + intgen_t rval; + + /* see if option specified + */ + optind = 1; + opterr = 0; + optfilename = 0; + while ( ( c = getopt( *argcp, *argvp, GETOPT_CMDSTRING )) != EOF ) { + switch ( c ) { + case GETOPT_OPTFILE: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_NOLOCK, + "-%c argument missing\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + if ( optfilename ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_NOLOCK, + "-%c allowed only once\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + optfilename = optarg; + ASSERT( optind > 2 ); + optfileix = ( ix_t )optind - 2; + break; + } + } + if ( ! optfilename ) { + return BOOL_TRUE; + } + + /* attempt to open the option file + */ + errno = 0; + fd = open( optfilename, O_RDONLY ); + if ( fd < 0 ) { + mlog( MLOG_ERROR | MLOG_NOLOCK, + "cannot open option file %s: %s (%d)\n", + optfilename, + strerror( errno ), + errno ); + return BOOL_FALSE; + } + + /* get file status + */ + rval = fstat64( fd, &stat ); + if ( rval ) { + mlog( MLOG_ERROR | MLOG_NOLOCK, + "cannot stat option file %s: %s (%d)\n", + optfilename, + strerror( errno ), + errno ); + close( fd ); + return BOOL_FALSE; + } + + /* ensure the file is ordinary + */ + if ( ( stat.st_mode & S_IFMT ) != S_IFREG ) { + mlog( MLOG_ERROR | MLOG_NOLOCK, + "given option file %s is not ordinary file\n", + optfilename ); + close( fd ); + return BOOL_FALSE; + } + + /* calculate the space required for the cmd line options. + * skip the GETOPT_OPTFILE option which put us here! + */ + sz = 0; + for ( i = 0 ; i < *argcp ; i++ ) { + if ( i == ( intgen_t )optfileix ) { + i++; /* to skip option argument */ + continue; + } + sz += strlen( ( * argvp )[ i ] ) + 1; + } + + /* add in the size of the option file (plus one byte in case + * option file ends without newline, and one NULL for safety) + */ + sz += ( size_t )stat.st_size + 2; + + /* allocate an argument buffer + */ + argbuf = ( char * )malloc( sz ); + ASSERT( argbuf ); + + /* copy arg0 (the executable's name ) in first + */ + p = argbuf; + i = 0; + sprintf( p, "%s ", ( * argvp )[ i ] ); + p += strlen( ( * argvp )[ i ] ) + 1; + i++; + + /* copy the options file into the buffer after the given args + */ + nread = read( fd, ( void * )p, ( size_t )stat.st_size ); + if ( nread < 0 ) { + mlog( MLOG_ERROR | MLOG_NOLOCK, + "read of option file %s failed: %s (%d)\n", + optfilename, + strerror( errno ), + errno ); + close( fd ); + return BOOL_FALSE; + } + ASSERT( ( off64_t )nread == stat.st_size ); + p += ( size_t )stat.st_size; + *p++ = ' '; + + /* copy the remaining command line args into the buffer + */ + for ( ; i < *argcp ; i++ ) { + if ( i == ( intgen_t )optfileix ) { + i++; /* to skip option argument */ + continue; + } + sprintf( p, "%s ", ( * argvp )[ i ] ); + p += strlen( ( * argvp )[ i ] ) + 1; + } + + /* null-terminate the entire buffer + */ + *p++ = 0; + ASSERT( ( size_t )( p - argbuf ) <= sz ); + + /* change newlines and carriage returns into spaces + */ + for ( p = argbuf ; *p ; p++ ) { + if ( strchr( "\n\r", ( intgen_t )( *p ))) { + *p = ' '; + } + } + + /* count the tokens in the buffer + */ + tokencnt = 0; + p = argbuf; + for ( ; ; ) { + /* start at the first non-separator character + */ + while ( *p && strchr( sep, ( intgen_t )( *p ))) { + p++; + } + + /* done when NULL encountered + */ + if ( ! *p ) { + break; + } + + /* we have a token + */ + tokencnt++; + + /* find the end of the first token + */ + p = strpbrkquotes( p, sep ); + + /* if no more separators, all tokens seen + */ + if ( ! p ) { + break; + } + } + + /* if no arguments, can return now + */ + if ( ! tokencnt ) { + close( fd ); + return BOOL_TRUE; + } + + /* allocate a new argv array to hold the tokens + */ + newargv = ( char ** )calloc( tokencnt, sizeof( char * )); + ASSERT( newargv ); + + /* null-terminate tokens and place in new argv, after + * extracting quotes and escapes + */ + p = argbuf; + for ( i = 0 ; ; i++ ) { + char *endp = 0; + + /* start at the first non-separator character + */ + while ( *p && strchr( sep, ( intgen_t )*p )) { + p++; + } + + /* done when NULL encountered + */ + if ( ! *p ) { + break; + } + + /* better not disagree with counting scan! + */ + ASSERT( i < ( intgen_t )tokencnt ); + + /* find the end of the first token + */ + endp = strpbrkquotes( p, sep ); + + /* null-terminate if needed + */ + if ( endp ) { + *endp = 0; + } + + /* strip quotes and escapes + */ + p = stripquotes( p ); + + /* stick result in new argv array + */ + newargv[ i ] = p; + + /* if no more separators, all tokens seen + */ + if ( ! endp ) { + break; + } + + p = endp + 1; + } + + /* return new argc anr argv + */ + close( fd ); + *argcp = ( intgen_t )tokencnt; + *argvp = newargv; + return BOOL_TRUE; +} + +#ifdef HIDDEN +static pid_t mrh_cid; +#endif + +static bool_t +in_miniroot_heuristic( void ) +{ + return BOOL_TRUE; + +#ifdef HIDDEN + SIG_PF prev_handler_hup; + SIG_PF prev_handler_term; + SIG_PF prev_handler_int; + SIG_PF prev_handler_quit; + SIG_PF prev_handler_cld; + bool_t in_miniroot; + + /* attempt to call sproc. + */ + prev_handler_hup = sigset( SIGHUP, SIG_IGN ); + prev_handler_term = sigset( SIGTERM, SIG_IGN ); + prev_handler_int = sigset( SIGINT, SIG_IGN ); + prev_handler_quit = sigset( SIGQUIT, SIG_IGN ); + prev_handler_cld = sigset( SIGCLD, mrh_sighandler ); + ( void )sighold( SIGCLD ); + mrh_cid = ( pid_t )sproc( ( void ( * )( void * ))exit, PR_SALL, 0 ); + if ( mrh_cid < 0 ) { + in_miniroot = BOOL_TRUE; + } else { + while ( mrh_cid >= 0 ) { + ( void )sigpause( SIGCLD ); + } + in_miniroot = BOOL_FALSE; + } + ( void )sigset( SIGHUP, prev_handler_hup ); + ( void )sigset( SIGTERM, prev_handler_term ); + ( void )sigset( SIGINT, prev_handler_int ); + ( void )sigset( SIGQUIT, prev_handler_quit ); + ( void )sigset( SIGCLD, prev_handler_cld ); + + return in_miniroot; +#endif /* HIDDEN */ +} + +#ifdef HIDDEN +static void +mrh_sighandler( int signo ) +{ + if ( signo == SIGCLD ) { + pid_t cid; + intgen_t stat; + + cid = wait( &stat ); + if ( cid == mrh_cid ) { + mrh_cid = -1; + } + } +} +#endif + +/* parent and children share this handler. + */ +static void +sighandler( int signo ) +{ + /* get the pid and stream index + */ + pid_t pid = getpid( ); + intgen_t stix = stream_getix( pid ); + + /* if in miniroot, don't do anything risky. just quit. + */ + if ( miniroot || pipeline ) { + intgen_t rval; + + mlog( MLOG_TRACE | MLOG_NOTE | MLOG_NOLOCK | MLOG_PROC, + "received signal %d (%s): cleanup and exit\n", + signo, + sig_numstring( signo )); + + if ( content_complete( )) { + rval = EXIT_NORMAL; + } else { + rval = EXIT_INTERRUPT; + } + exit( rval ); + } + + /* if death of a child of a child, bury the child and return. + * probably rmt. + */ + if ( pid != parentpid && signo == SIGCLD ) { + intgen_t stat; + ( void )wait( &stat ); + ( void )sigset( signo, sighandler ); + return; + } + + /* if niether parent nor managed child nor slave, exit + */ + if ( pid != parentpid && stix == -1 ) { + exit( 0 ); + } + + /* parent signal handling + */ + if ( pid == parentpid ) { + pid_t cid; + intgen_t stat; + switch ( signo ) { + case SIGCLD: + /* bury the child and notify the child manager + * abstraction of its death, and record death stats + */ + cid = wait( &stat ); + stix = stream_getix( cid ); + cldmgr_died( cid ); + if ( WIFSIGNALED( stat ) || WEXITSTATUS( stat ) > 0 ) { + if ( prbcld_cnt == 0 ) { + if ( WIFSIGNALED( stat )) { + prbcld_pid = cid; + prbcld_xc = 0; + prbcld_signo = WTERMSIG( stat ); + } else if ( WEXITSTATUS( stat ) > 0 ) { + prbcld_pid = cid; + prbcld_xc = WEXITSTATUS( stat ); + prbcld_signo = 0; + } + } + prbcld_cnt++; + } + ( void )sigset( signo, sighandler ); + return; + case SIGHUP: + /* immediately disable further dialogs + */ + dlog_desist( ); + sighup_received = BOOL_TRUE; + return; + case SIGTERM: + /* immediately disable further dialogs + */ + dlog_desist( ); + sigterm_received = BOOL_TRUE; + return; + case SIGINT: + sigint_received = BOOL_TRUE; + return; + case SIGQUIT: + /* immediately disable further dialogs + */ + dlog_desist( ); + sigquit_received = BOOL_TRUE; + return; + case SIGPIPE: + /* immediately disable further dialogs, + * and ignore subsequent signals + */ + dlog_desist( ); + sigpipe_received = BOOL_TRUE; + ( void )sigset( signo, SIG_IGN ); + return; + case SIGALRM: + return; + default: + sigstray_received = signo; + return; + } + } + + /* managed child handling + */ + if ( stream_getix( pid ) != -1 ) { + switch ( signo ) { + case SIGHUP: + /* can get SIGHUP during dialog: just dismiss + */ + return; + case SIGTERM: + /* can get SIGTERM during dialog: just dismiss + */ + return; + case SIGINT: + /* can get SIGINT during dialog: just dismiss + */ + return; + case SIGQUIT: + /* can get SIGQUIT during dialog: just dismiss + */ + return; + case SIGPIPE: + /* forward write pipe failures to parent, + * and ignore subsequent failures + */ + dlog_desist( ); + kill( parentpid, SIGPIPE ); + ( void )sigset( signo, SIG_IGN ); + return; + case SIGALRM: + /* accept and do nothing about alarm signals + */ + return; + default: + /* should not be any other captured signals: + * request a core dump + */ + exit( EXIT_FAULT ); + return; + } + } + + /* if some other child, just exit + */ + exit( 0 ); +} + +static int +childmain( void *arg1 ) +{ + ix_t stix; + intgen_t exitcode; + drive_t *drivep; + + /* ignore signals + */ + sigset( SIGHUP, SIG_IGN ); + sigset( SIGTERM, SIG_IGN ); + sigset( SIGINT, SIG_IGN ); + sigset( SIGQUIT, SIG_IGN ); + sigset( SIGPIPE, SIG_IGN ); + sigset( SIGALRM, SIG_IGN ); + sigset( SIGCLD, SIG_IGN ); + + /* Determine which stream I am. + */ + stix = ( ix_t )arg1; + + /* tell the content manager to begin. + */ +#ifdef DUMP + exitcode = content_stream_dump( stix ); +#endif /* DUMP */ +#ifdef RESTORE + exitcode = content_stream_restore( stix ); +#endif /* RESTORE */ + + /* let the drive manager shut down its slave thread + */ + drivep = drivepp[ stix ]; + ( * drivep->d_opsp->do_quit )( drivep ); + + exit( exitcode ); +} + + +/* ARGSUSED */ +static void +prompt_prog_cb( void *uctxp, dlog_pcbp_t pcb, void *pctxp ) +{ + /* query: ask for a dump label + */ + ( * pcb )( pctxp, + progrpt_enabledpr + ? + "please enter seconds between progress reports, " + "or 0 to disable" + : + "please enter seconds between progress reports" ); +} + +/* SIGINTR dialog + * + * side affect is to change verbosity level. + * return code of BOOL_TRUE indicates a stop was requested. + */ +#define PREAMBLEMAX ( 7 + 2 * STREAM_SIMMAX ) +#define QUERYMAX 3 +#define CHOICEMAX 9 +#define ACKMAX 7 +#define POSTAMBLEMAX 3 + +static bool_t +sigint_dialog( void ) +{ + fold_t fold; + char **statline; + ix_t i; + size_t statlinecnt; + char *preamblestr[ PREAMBLEMAX ]; + size_t preamblecnt; + char *querystr[ QUERYMAX ]; + size_t querycnt; + char *choicestr[ CHOICEMAX ]; + size_t choicecnt; + char *ackstr[ ACKMAX ]; + size_t ackcnt; + char *postamblestr[ POSTAMBLEMAX ]; + size_t postamblecnt; + size_t interruptix; + size_t verbosityix; + size_t metricsix; + size_t controlix; + size_t ioix; + size_t mediachangeix; +#ifdef RESTORE + size_t piix; + size_t roix; +#endif /* RESTORE */ + size_t progix; + size_t mllevix; + size_t mlssix; + size_t mltsix; + size_t continueix; + size_t allix; + size_t nochangeix; + size_t responseix; + intgen_t ssselected = 0; + bool_t stop_requested = BOOL_FALSE; + + /* preamble: the content status line, indicate if interrupt happening + */ + fold_init( fold, "status and control dialog", '=' ); + statlinecnt = content_statline( &statline ); + preamblecnt = 0; + preamblestr[ preamblecnt++ ] = "\n"; + preamblestr[ preamblecnt++ ] = fold; + preamblestr[ preamblecnt++ ] = "\n"; + preamblestr[ preamblecnt++ ] = "\n"; + for ( i = 0 ; i < statlinecnt ; i++ ) { + preamblestr[ preamblecnt++ ] = statline[ i ]; + } + if ( stop_in_progress ) { + preamblestr[ preamblecnt++ ] = + "\nsession interrupt in progress\n"; + } + preamblestr[ preamblecnt++ ] = "\n"; + ASSERT( preamblecnt <= PREAMBLEMAX ); + dlog_begin( preamblestr, preamblecnt ); + + /* top-level query: a function of session interrupt status + */ + querycnt = 0; + querystr[ querycnt++ ] = "please select one of " + "the following operations\n"; + ASSERT( querycnt <= QUERYMAX ); + choicecnt = 0; + if ( ! stop_in_progress ) { + interruptix = choicecnt; + choicestr[ choicecnt++ ] = "interrupt this session"; + } else { + interruptix = SIZEMAX; /* never happen */ + } + + verbosityix = choicecnt; + choicestr[ choicecnt++ ] = "change verbosity"; + metricsix = choicecnt; + choicestr[ choicecnt++ ] = "display metrics"; + if ( content_media_change_needed ) { + mediachangeix = choicecnt; + choicestr[ choicecnt++ ] = "confirm media change"; + } else { + mediachangeix = SIZEMAX; /* never happen */ + } + controlix = choicecnt; + choicestr[ choicecnt++ ] = "other controls"; + continueix = choicecnt; + choicestr[ choicecnt++ ] = "continue"; + ASSERT( choicecnt <= CHOICEMAX ); + + responseix = dlog_multi_query( querystr, + querycnt, + choicestr, + choicecnt, + 0, /* hilitestr */ + IXMAX, /* hiliteix */ + 0, /* defaultstr */ + continueix, /* defaultix */ + DLOG_TIMEOUT, /* timeout */ + continueix, /* timeout ix */ + continueix, /* sigint ix */ + continueix, /* sighup ix */ + continueix ); /* sigquit ix */ + if ( responseix == interruptix ) { + ackcnt = 0; + ackstr[ ackcnt++ ] = "\n"; + dlog_multi_ack( ackstr, + ackcnt ); + querycnt = 0; + querystr[ querycnt++ ] = "please confirm\n"; + ASSERT( querycnt <= QUERYMAX ); + choicecnt = 0; + interruptix = choicecnt; + choicestr[ choicecnt++ ] = "interrupt this session"; + nochangeix = choicecnt; + choicestr[ choicecnt++ ] = "continue"; + ASSERT( choicecnt <= CHOICEMAX ); + responseix = dlog_multi_query( querystr, + querycnt, + choicestr, + choicecnt, + 0, /* hilitestr */ + IXMAX, /* hiliteix */ + 0, /* defaultstr */ + nochangeix, /* defaultix */ + DLOG_TIMEOUT,/* timeout */ + nochangeix, /* timeout ix */ + nochangeix, /* sigint ix */ + nochangeix, /* sighup ix */ + nochangeix);/* sigquit ix */ + ackcnt = 0; + if ( responseix == nochangeix ) { + ackstr[ ackcnt++ ] = "continuing\n"; + } else { + ackstr[ ackcnt++ ] = "interrupt request accepted\n"; + stop_requested = BOOL_TRUE; + } + dlog_multi_ack( ackstr, + ackcnt ); + } else if ( responseix == verbosityix ) { + ackcnt = 0; + ackstr[ ackcnt++ ] = "\n"; + dlog_multi_ack( ackstr, + ackcnt ); + querycnt = 0; + querystr[ querycnt++ ] = "please select one of " + "the following subsystems\n"; + ASSERT( querycnt <= QUERYMAX ); + choicecnt = 0; + /* number of lines must match number of subsystems + */ + for ( choicecnt = 0 ; choicecnt < MLOG_SS_CNT ; choicecnt++ ) { + choicestr[ choicecnt ] = mlog_ss_names[ choicecnt ]; + } + allix = choicecnt; + choicestr[ choicecnt++ ] = "all of the above"; + nochangeix = choicecnt; + choicestr[ choicecnt++ ] = "no change"; + ASSERT( choicecnt <= CHOICEMAX ); + responseix = dlog_multi_query( querystr, + querycnt, + choicestr, + choicecnt, + 0, /* hilitestr */ + IXMAX, /* hiliteix */ + 0, /* defaultstr */ + allix, /* defaultix */ + DLOG_TIMEOUT,/* timeout */ + nochangeix, /* timeout ix */ + nochangeix, /* sigint ix */ + nochangeix, /* sighup ix */ + nochangeix);/* sigquit ix */ + ackcnt = 0; + if ( responseix == nochangeix ) { + ackstr[ ackcnt++ ] = "no change\n"; + } else if ( responseix == allix ) { + ssselected = -1; + ackstr[ ackcnt++ ] = "all subsystems selected\n\n"; + } else { + ssselected = ( intgen_t )responseix; + ackstr[ ackcnt++ ] = "\n"; + } + dlog_multi_ack( ackstr, + ackcnt ); + if ( responseix != nochangeix ) { + querycnt = 0; + querystr[ querycnt++ ] = "please select one of the " + "following verbosity levels\n"; + ASSERT( querycnt <= QUERYMAX ); + choicecnt = 0; + choicestr[ choicecnt++ ] = "silent"; + choicestr[ choicecnt++ ] = "verbose"; + choicestr[ choicecnt++ ] = "trace"; + choicestr[ choicecnt++ ] = "debug"; + choicestr[ choicecnt++ ] = "nitty"; + choicestr[ choicecnt++ ] = "nitty + 1"; + nochangeix = choicecnt; + choicestr[ choicecnt++ ] = "no change"; + ASSERT( choicecnt <= CHOICEMAX ); + responseix = dlog_multi_query( querystr, + querycnt, + choicestr, + choicecnt, + ssselected == -1 + ? + 0 + : + " (current)",/* hilitestr */ + ssselected == -1 + ? + IXMAX + : + ( ix_t )mlog_level_ss[ ssselected ], /* hiliteix */ + 0, /* defaultstr */ + nochangeix,/* defaultix */ + DLOG_TIMEOUT,/* timeout */ + nochangeix, /* timeout ix */ + nochangeix, /* sigint ix */ + nochangeix, /* sighup ix */ + nochangeix);/* sigquit ix */ + ackcnt = 0; + if ( responseix == nochangeix + || + ( ssselected >= 0 + && + responseix + == + ( ix_t )mlog_level_ss[ ssselected ] )) { + ackstr[ ackcnt++ ] = "no change\n"; + } else { + if ( ssselected < 0 ) { + ix_t ssix; + ASSERT( ssselected == -1 ); + for ( ssix = 0 + ; + ssix < MLOG_SS_CNT + ; + ssix++ ) { + mlog_level_ss[ ssix ] = + ( intgen_t )responseix; + } + } else { + mlog_level_ss[ ssselected ] = + ( intgen_t )responseix; + } + ackstr[ ackcnt++ ] = "level changed\n"; + } + dlog_multi_ack( ackstr, + ackcnt ); + } + } else if ( responseix == metricsix ) { + ackcnt = 0; + ackstr[ ackcnt++ ] = "\n"; + dlog_multi_ack( ackstr, + ackcnt ); + querycnt = 0; + querystr[ querycnt++ ] = "please select one of " + "the following metrics\n"; + ASSERT( querycnt <= QUERYMAX ); + choicecnt = 0; + ioix = choicecnt; + choicestr[ choicecnt++ ] = "I/O"; +#ifdef RESTORE + piix = choicecnt; + choicestr[ choicecnt++ ] = "media inventory status"; + roix = choicecnt; + choicestr[ choicecnt++ ] = "needed media objects"; +#endif /* RESTORE */ + nochangeix = choicecnt; + choicestr[ choicecnt++ ] = "continue"; + ASSERT( choicecnt <= CHOICEMAX ); + responseix = dlog_multi_query( querystr, + querycnt, + choicestr, + choicecnt, + 0, /* hilitestr */ + IXMAX, /* hiliteix */ + 0, /* defaultstr */ + nochangeix, /* defaultix */ + DLOG_TIMEOUT, + nochangeix, /* timeout ix */ + nochangeix, /* sigint ix */ + nochangeix, /* sighup ix */ + nochangeix);/* sigquit ix */ + if ( responseix != nochangeix ) { + ackcnt = 0; + ackstr[ ackcnt++ ] = "\n"; + dlog_multi_ack( ackstr, + ackcnt ); + } + if ( responseix == ioix ) { + drive_display_metrics( ); +#ifdef RESTORE + } else if ( responseix == piix ) { + content_showinv( ); + } else if ( responseix == roix ) { + content_showremainingobjects( ); +#endif /* RESTORE */ + } + + if ( responseix != nochangeix ) { + querycnt = 0; + querystr[ querycnt++ ] = "\n"; + ASSERT( querycnt <= QUERYMAX ); + choicecnt = 0; + nochangeix = choicecnt; + choicestr[ choicecnt++ ] = "continue"; + ASSERT( choicecnt <= CHOICEMAX ); + responseix = dlog_multi_query( querystr, + querycnt, + choicestr, + choicecnt, + 0, /* hilitestr */ + IXMAX, /* hiliteix */ + 0, /* defaultstr */ + nochangeix,/* defaultix*/ + DLOG_TIMEOUT, + nochangeix,/*timeout ix*/ + nochangeix,/* sigint ix*/ + nochangeix,/* sighup ix*/ + nochangeix);/*sigquitix*/ + } + ackcnt = 0; + ackstr[ ackcnt++ ] = "continuing\n"; + dlog_multi_ack( ackstr, + ackcnt ); + } else if ( responseix == mediachangeix ) { + ackcnt = 0; + dlog_multi_ack( ackstr, + ackcnt ); + ackcnt = 0; + ackstr[ ackcnt++ ] = content_mediachange_query( ); + dlog_multi_ack( ackstr, + ackcnt ); + } else if ( responseix == controlix ) { + ackcnt = 0; + ackstr[ ackcnt++ ] = "\n"; + dlog_multi_ack( ackstr, + ackcnt ); + querycnt = 0; + querystr[ querycnt++ ] = "please select one of " + "the following controls\n"; + ASSERT( querycnt <= QUERYMAX ); + choicecnt = 0; + progix = choicecnt; + if ( progrpt_enabledpr ) { + choicestr[ choicecnt++ ] = "change interval of " + "or disable progress reports"; + } else { + choicestr[ choicecnt++ ] = "enable progress reports"; + } + mllevix = choicecnt; + if ( mlog_showlevel ) { + choicestr[ choicecnt++ ] = "hide log message levels"; + } else { + choicestr[ choicecnt++ ] = "show log message levels"; + } + mlssix = choicecnt; + if ( mlog_showss ) { + choicestr[ choicecnt++ ] ="hide log message subsystems"; + } else { + choicestr[ choicecnt++ ] ="show log message subsystems"; + } + mltsix = choicecnt; + if ( mlog_timestamp ) { + choicestr[ choicecnt++ ] ="hide log message timestamps"; + } else { + choicestr[ choicecnt++ ] ="show log message timestamps"; + } + nochangeix = choicecnt; + choicestr[ choicecnt++ ] = "continue"; + ASSERT( choicecnt <= CHOICEMAX ); + responseix = dlog_multi_query( querystr, + querycnt, + choicestr, + choicecnt, + 0, /* hilitestr */ + IXMAX, /* hiliteix */ + 0, /* defaultstr */ + nochangeix, /* defaultix */ + DLOG_TIMEOUT, + nochangeix, /* timeout ix */ + nochangeix, /* sigint ix */ + nochangeix, /* sighup ix */ + nochangeix);/* sigquit ix */ + ackcnt = 0; + if ( responseix == progix ) { + char buf[ 10 ]; + const size_t ncix = 1; + const size_t okix = 2; + + ackstr[ ackcnt++ ] = "\n"; + dlog_multi_ack( ackstr, + ackcnt ); + ackcnt = 0; + responseix = dlog_string_query( prompt_prog_cb, + 0, + buf, + sizeof( buf ), + DLOG_TIMEOUT, + ncix,/* timeout ix */ + ncix, /* sigint ix */ + ncix, /* sighup ix */ + ncix, /* sigquit ix */ + okix ); + if ( responseix == okix ) { + intgen_t newinterval; + newinterval = atoi( buf ); + if ( ! strlen( buf )) { + ackstr[ ackcnt++ ] = "no change\n"; + } else if ( newinterval > 0 ) { + time_t newdeadline; + char intervalbuf[ 64 ]; + newdeadline = time( 0 ) + ( time_t )newinterval; + if ( progrpt_enabledpr ) { + if ( ( time_t )newinterval == progrpt_interval ) { + ackstr[ ackcnt++ ] = "no change\n"; + } else { + ackstr[ ackcnt++ ] = "changing progress report interval to "; + sprintf( intervalbuf, + "%d seconds\n", + newinterval ); + ASSERT( strlen( intervalbuf ) + < + sizeof( intervalbuf )); + ackstr[ ackcnt++ ] = intervalbuf; + if ( progrpt_deadline > newdeadline ) { + progrpt_deadline = newdeadline; + } + } + } else { + ackstr[ ackcnt++ ] = "enabling progress reports at "; + sprintf( intervalbuf, + "%d second intervals\n", + newinterval ); + ASSERT( strlen( intervalbuf ) + < + sizeof( intervalbuf )); + ackstr[ ackcnt++ ] = intervalbuf; + progrpt_enabledpr = BOOL_TRUE; + progrpt_deadline = newdeadline; + } + progrpt_interval = ( time_t )newinterval; + } else { + if ( progrpt_enabledpr ) { + ackstr[ ackcnt++ ] = "disabling progress reports\n"; + } else { + ackstr[ ackcnt++ ] = "no change\n"; + } + progrpt_enabledpr = BOOL_FALSE; + } + } else { + ackstr[ ackcnt++ ] = "no change\n"; + } + } else if ( responseix == mllevix ) { + mlog_showlevel = ! mlog_showlevel; + if ( mlog_showlevel ) { + ackstr[ ackcnt++ ] = "showing log message levels\n"; + } else { + ackstr[ ackcnt++ ] = "hiding log message levels\n"; + } + } else if ( responseix == mlssix ) { + mlog_showss = ! mlog_showss; + if ( mlog_showss ) { + ackstr[ ackcnt++ ] = "showing log message subsystems\n"; + } else { + ackstr[ ackcnt++ ] = "hiding log message subsystems\n"; + } + } else if ( responseix == mltsix ) { + mlog_timestamp = ! mlog_timestamp; + if ( mlog_timestamp ) { + ackstr[ ackcnt++ ] = "showing log message timestamps\n"; + } else { + ackstr[ ackcnt++ ] = "hiding log message timestamps\n"; + } + } + dlog_multi_ack( ackstr, + ackcnt ); + } else { + ackcnt = 0; + ackstr[ ackcnt++ ] = "continuing\n"; + dlog_multi_ack( ackstr, + ackcnt ); + } + + fold_init( fold, "end dialog", '-' ); + postamblecnt = 0; + postamblestr[ postamblecnt++ ] = "\n"; + postamblestr[ postamblecnt++ ] = fold; + postamblestr[ postamblecnt++ ] = "\n\n"; + ASSERT( postamblecnt <= POSTAMBLEMAX ); + dlog_end( postamblestr, + postamblecnt ); + + return stop_requested; +} + +static char * +sigintstr( void ) +{ + intgen_t ttyfd; + static char buf[ 20 ]; + struct termios termios; + cc_t intchr; + intgen_t rval; + + ttyfd = dlog_fd( ); + if ( ttyfd == -1 ) { + return 0; + } + + rval = tcgetattr( ttyfd, &termios ); + if ( rval ) { + mlog( MLOG_NITTY | MLOG_PROC, + "could not get controlling terminal information: %s\n", + strerror( errno )); + return 0; + } + + intchr = termios.c_cc[ VINTR ]; + mlog( MLOG_NITTY | MLOG_PROC, + "tty fd: %d; terminal interrupt character: %c (0%o)\n", + ttyfd, + intchr, + intchr ); + + if ( intchr < ' ' ) { + sprintf( buf, "^%c", intchr + '@' ); + } else if ( intchr == 0177 ) { + sprintf( buf, "DEL" ); + } else { + sprintf( buf, "%c", intchr ); + } + ASSERT( strlen( buf ) < sizeof( buf )); + + return buf; +} + +#ifdef DUMP +static bool_t +set_rlimits( void ) +#endif /* DUMP */ +#ifdef RESTORE +static bool_t +set_rlimits( size64_t *vmszp ) +#endif /* RESTORE */ +{ + struct rlimit64 rlimit64; +#ifdef RESTORE + size64_t vmsz; +#endif /* RESTORE */ + /* REFERENCED */ + intgen_t rval; + + ASSERT( minstacksz <= maxstacksz ); + + rval = getrlimit64( RLIMIT_AS, &rlimit64 ); + + ASSERT( ! rval ); + mlog( MLOG_NITTY | MLOG_NOLOCK | MLOG_PROC, + "RLIMIT_AS org cur 0x%llx max 0x%llx\n", + rlimit64.rlim_cur, + rlimit64.rlim_max ); +#ifdef RESTORE + vmsz = ( size64_t )rlimit64.rlim_cur; +#endif /* RESTORE */ + + ASSERT( minstacksz <= maxstacksz ); + rval = getrlimit64( RLIMIT_STACK, &rlimit64 ); + ASSERT( ! rval ); + mlog( MLOG_NITTY | MLOG_NOLOCK | MLOG_PROC, + "RLIMIT_STACK org cur 0x%llx max 0x%llx\n", + rlimit64.rlim_cur, + rlimit64.rlim_max ); + if ( rlimit64.rlim_cur < minstacksz ) { + if ( rlimit64.rlim_max < minstacksz ) { + mlog( MLOG_DEBUG + | + MLOG_NOLOCK + | + MLOG_PROC, + "raising stack size hard limit " + "from 0x%llx to 0x%llx\n", + rlimit64.rlim_max, + minstacksz ); + rlimit64.rlim_cur = minstacksz; + rlimit64.rlim_max = minstacksz; + ( void )setrlimit64( RLIMIT_STACK, &rlimit64 ); + rval = getrlimit64( RLIMIT_STACK, &rlimit64 ); + ASSERT( ! rval ); + if ( rlimit64.rlim_cur < minstacksz ) { + mlog( MLOG_NORMAL + | + MLOG_WARNING + | + MLOG_NOLOCK + | + MLOG_PROC, + "unable to raise stack size hard limit " + "from 0x%llx to 0x%llx\n", + rlimit64.rlim_max, + minstacksz ); + } + } else { + mlog( MLOG_DEBUG + | + MLOG_NOLOCK + | + MLOG_PROC, + "raising stack size soft limit " + "from 0x%llx to 0x%llx\n", + rlimit64.rlim_cur, + minstacksz ); + rlimit64.rlim_cur = minstacksz; + ( void )setrlimit64( RLIMIT_STACK, &rlimit64 ); + rval = getrlimit64( RLIMIT_STACK, &rlimit64 ); + ASSERT( ! rval ); + if ( rlimit64.rlim_cur < minstacksz ) { + mlog( MLOG_NORMAL + | + MLOG_WARNING + | + MLOG_NOLOCK + | + MLOG_PROC, + "unable to raise stack size soft limit " + "from 0x%llx to 0x%llx\n", + rlimit64.rlim_cur, + minstacksz ); + } + } + } else if ( rlimit64.rlim_cur > maxstacksz ) { + mlog( MLOG_DEBUG + | + MLOG_NOLOCK + | + MLOG_PROC, + "lowering stack size soft limit " + "from 0x%llx to 0x%llx\n", + rlimit64.rlim_cur, + maxstacksz ); + rlimit64.rlim_cur = maxstacksz; + ( void )setrlimit64( RLIMIT_STACK, &rlimit64 ); + rval = getrlimit64( RLIMIT_STACK, &rlimit64 ); + ASSERT( ! rval ); + if ( rlimit64.rlim_cur > maxstacksz ) { + mlog( MLOG_NORMAL + | + MLOG_WARNING + | + MLOG_NOLOCK + | + MLOG_PROC, + "unable to lower stack size soft limit " + "from 0x%llx to 0x%llx\n", + rlimit64.rlim_cur, + maxstacksz ); + } + } + mlog( MLOG_NITTY | MLOG_NOLOCK | MLOG_PROC, + "RLIMIT_STACK new cur 0x%llx max 0x%llx\n", + rlimit64.rlim_cur, + rlimit64.rlim_max ); + + rval = getrlimit64( RLIMIT_DATA, &rlimit64 ); + ASSERT( ! rval ); + mlog( MLOG_NITTY | MLOG_NOLOCK | MLOG_PROC, + "RLIMIT_DATA org cur 0x%llx max 0x%llx\n", + rlimit64.rlim_cur, + rlimit64.rlim_max ); + + rval = getrlimit64( RLIMIT_FSIZE, &rlimit64 ); + ASSERT( ! rval ); + mlog( MLOG_NITTY | MLOG_NOLOCK | MLOG_PROC, + "RLIMIT_FSIZE org cur 0x%llx max 0x%llx\n", + rlimit64.rlim_cur, + rlimit64.rlim_max ); + rlimit64.rlim_cur = rlimit64.rlim_max; + ( void )setrlimit64( RLIMIT_FSIZE, &rlimit64 ); + rlimit64.rlim_cur = RLIM64_INFINITY; + ( void )setrlimit64( RLIMIT_FSIZE, &rlimit64 ); + rval = getrlimit64( RLIMIT_FSIZE, &rlimit64 ); + ASSERT( ! rval ); + mlog( MLOG_NITTY | MLOG_NOLOCK | MLOG_PROC, + "RLIMIT_FSIZE now cur 0x%llx max 0x%llx\n", + rlimit64.rlim_cur, + rlimit64.rlim_max ); + + rval = getrlimit64( RLIMIT_CPU, &rlimit64 ); + ASSERT( ! rval ); + mlog( MLOG_NITTY | MLOG_NOLOCK | MLOG_PROC, + "RLIMIT_CPU cur 0x%llx max 0x%llx\n", + rlimit64.rlim_cur, + rlimit64.rlim_max ); + rlimit64.rlim_cur = rlimit64.rlim_max; + ( void )setrlimit64( RLIMIT_CPU, &rlimit64 ); + rval = getrlimit64( RLIMIT_CPU, &rlimit64 ); + ASSERT( ! rval ); + mlog( MLOG_NITTY | MLOG_NOLOCK | MLOG_PROC, + "RLIMIT_CPU now cur 0x%llx max 0x%llx\n", + rlimit64.rlim_cur, + rlimit64.rlim_max ); + +#ifdef RESTORE + *vmszp = vmsz; +#endif /* RESTORE */ + return BOOL_TRUE; +} + +struct exit_printmap { + intgen_t code; + char *string; +}; + +typedef struct exit_printmap exit_printmap_t; + +static exit_printmap_t exit_printmap[ ] = { + {EXIT_NORMAL, "EXIT_NORMAL"}, + {EXIT_ERROR, "EXIT_ERROR"}, + {EXIT_INTERRUPT, "EXIT_INTERRUPT"}, + {EXIT_FAULT, "EXIT_FAULT"} +}; + +static char * +exit_codestring( intgen_t code ) +{ + exit_printmap_t *p = exit_printmap; + exit_printmap_t *endp = exit_printmap + + + ( sizeof( exit_printmap ) + / + sizeof( exit_printmap[ 0 ] )); + for ( ; p < endp ; p++ ) { + if ( p->code == code ) { + return p->string; + } + } + + return "???"; +} + +struct sig_printmap { + intgen_t num; + char *string; +}; + +typedef struct sig_printmap sig_printmap_t; + +static sig_printmap_t sig_printmap[ ] = { + {SIGHUP, "SIGHUP"}, + {SIGINT, "SIGINT"}, + {SIGQUIT, "SIGQUIT"}, + {SIGILL, "SIGILL"}, + {SIGABRT, "SIGABRT"}, + {SIGFPE, "SIGFPE"}, + {SIGBUS, "SIGBUS"}, + {SIGSEGV, "SIGSEGV"}, +#ifdef SIGSYS + {SIGSYS, "SIGSYS"}, +#endif + {SIGPIPE, "SIGPIPE"}, + {SIGALRM, "SIGALRM"}, + {SIGTERM, "SIGTERM"}, + {SIGUSR1, "SIGUSR1"}, + {SIGUSR2, "SIGUSR2"}, + {SIGCLD, "SIGCLD"}, + {SIGPWR, "SIGPWR"}, + {SIGURG, "SIGURG"}, + {SIGPOLL, "SIGPOLL"}, + {SIGXCPU, "SIGXCPU"}, + {SIGXFSZ, "SIGXFSZ"}, +#if HIDDEN + {SIGRTMIN, "SIGRTMIN"}, + {SIGRTMAX, "SIGRTMAX"}, +#endif + {0, "no signal"} +}; + +static char * +sig_numstring( intgen_t num ) +{ + sig_printmap_t *p = sig_printmap; + sig_printmap_t *endp = sig_printmap + + + ( sizeof( sig_printmap ) + / + sizeof( sig_printmap[ 0 ] )); + for ( ; p < endp ; p++ ) { + if ( p->num == num ) { + return p->string; + } + } + + return "???"; +} + +static char * +strpbrkquotes( char *p, const char *sep ) +{ + bool_t prevcharwasbackslash = BOOL_FALSE; + bool_t inquotes = BOOL_FALSE; + + for ( ; ; p++ ) { + if ( *p == 0 ) { + return 0; + } + + if ( *p == '\\' ) { + if ( ! prevcharwasbackslash ) { + prevcharwasbackslash = BOOL_TRUE; + } else { + prevcharwasbackslash = BOOL_FALSE; + } + continue; + } + + if ( *p == '"' ) { + if ( prevcharwasbackslash ) { + prevcharwasbackslash = BOOL_FALSE; + continue; + } + if ( inquotes ) { + inquotes = BOOL_FALSE; + } else { + inquotes = BOOL_TRUE; + } + continue; + } + + if ( ! inquotes ) { + if ( strchr( sep, ( intgen_t )( *p ))) { + return p; + } + } + + prevcharwasbackslash = BOOL_FALSE; + } + /* NOTREACHED */ +} + +static char * +stripquotes( char *p ) +{ + size_t len = strlen( p ); + char *endp; + char *nextp; + bool_t justremovedbackslash; + + if ( len > 2 && p[ 0 ] == '"' ) { + p++; + len--; + if ( len && p[ len - 1 ] == '"' ) { + p[ len - 1 ] = 0; + len--; + } + } + + endp = p + len; + justremovedbackslash = BOOL_FALSE; + + for ( nextp = p ; nextp < endp ; ) { + if ( *nextp == '\\' && ! justremovedbackslash ) { + shiftleftby1( nextp, endp ); + endp--; + justremovedbackslash = BOOL_TRUE; + } else { + justremovedbackslash = BOOL_FALSE; + nextp++; + } + } + + return p; +} + +static void +shiftleftby1( char *p, char *endp ) +{ + for ( ; p < endp ; p++ ) { + *p = p[ 1 ]; + } +} diff -rNu linux-2.4.7/cmd/xfsdump/common/media.c linux-2.4-xfs/cmd/xfsdump/common/media.c --- linux-2.4.7/cmd/xfsdump/common/media.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/media.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "util.h" +#include "mlog.h" +#include "getopt.h" +#include "stream.h" +#include "global.h" +#include "drive.h" +#include "media.h" + +/* media.c - selects and initializes a media strategy + */ + + +/* declarations of externally defined global symbols *************************/ + +extern void usage( void ); + +/* declare all media strategies here + */ +extern media_strategy_t media_strategy_simple; +extern media_strategy_t media_strategy_rmvtape; + + +/* forward declarations of locally defined static functions ******************/ + +static media_t *media_alloc( drive_t *, char * ); + + +/* definition of locally defined global variables ****************************/ + + +/* definition of locally defined static variables *****************************/ + +/* media strategy array - ordered by precedence + */ +static media_strategy_t *strategyp[] = { + &media_strategy_simple, + &media_strategy_rmvtape, +}; + + +/* definition of locally defined global functions ****************************/ + +/* media_create - select and initialize a media strategy. + * and create and initialize media managers for each stream. + */ +media_strategy_t * +media_create( int argc, char *argv[ ], drive_strategy_t *dsp ) +{ + int c; + size_t mediaix; + size_t mediacnt; + media_t **mediapp; + char *medialabel; + media_strategy_t **spp = strategyp; + media_strategy_t **epp = strategyp + sizeof( strategyp ) + / + sizeof( strategyp[ 0 ] ); + media_strategy_t *chosen_sp; + intgen_t id; + bool_t ok; + + /* sanity check asserts + */ + ASSERT( sizeof( media_hdr_t ) == MEDIA_HDR_SZ ); + ASSERT( MEDIA_MARKLOG_SZ == sizeof( media_marklog_t )); + + /* scan the command line for a media label + */ + medialabel = 0; + optind = 1; + opterr = 0; + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + switch ( c ) { +#ifdef DUMP + case GETOPT_MEDIALABEL: + if ( medialabel ) { + mlog( MLOG_NORMAL, + "too many -%c arguments: " + "\"-%c %s\" already given\n", + optopt, + optopt, + medialabel ); + usage( ); + return 0; + } + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL, + "-%c argument missing\n", + optopt ); + usage( ); + return 0; + } + medialabel = optarg; + break; +#endif /* DUMP */ + } + } + + /* if no media label specified, synthesize one + */ + if ( ! medialabel ) { + /* not useful + mlog( MLOG_VERBOSE, + "WARNING: no media label specified\n" ); + */ + medialabel = ""; + } + + /* create a media_t array, and a media_ts for each drive. + * Initialize each media_t's generic portions. these will + * be lended to each media strategy during the strategy + * match phase, and given to the winning strategy. + */ + mediacnt = dsp->ds_drivecnt; + mediapp = ( media_t ** )calloc( mediacnt, sizeof( media_t * )); + ASSERT( mediapp ); + for ( mediaix = 0 ; mediaix < mediacnt ; mediaix++ ) { + mediapp[ mediaix ] = media_alloc( dsp->ds_drivep[ mediaix ], + medialabel ); + } + + /* choose the first strategy which claims appropriateness. + * if none match, return null. Also, initialize the strategy ID + * and pointer to the drive strategy. the ID is simply the index + * of the strategy in the strategy array. it is placed in the + * media_strategy_t as well as the write headers. + */ + chosen_sp = 0; + for ( id = 0 ; spp < epp ; spp++, id++ ) { + (*spp)->ms_id = id; + if ( ! chosen_sp ) { + /* lend the media_t array to the strategy + */ + (*spp)->ms_mediap = mediapp; + (*spp)->ms_dsp = dsp; + (*spp)->ms_mediacnt = mediacnt; + for ( mediaix = 0 ; mediaix < mediacnt ; mediaix++ ) { + media_t *mediap = mediapp[ mediaix ]; + mediap->m_strategyp = *spp; + mediap->m_writehdrp->mh_strategyid = id; + } + if ( ( * (*spp)->ms_match )( argc, argv, dsp )) { + chosen_sp = *spp; + } + } + } + if ( ! chosen_sp ) { + mlog( MLOG_NORMAL, + "no media strategy available for selected " +#ifdef DUMP + "dump destination" +#endif /* DUMP */ +#ifdef RESTORE + "restore source" +#endif /* RESTORE */ + "(s)\n" ); + usage( ); + return 0; + } + + /* give the media_t array to the chosen strategy + */ + for ( mediaix = 0 ; mediaix < mediacnt ; mediaix++ ) { + media_t *mediap = mediapp[ mediaix ]; + mediap->m_strategyp = chosen_sp; + mediap->m_writehdrp->mh_strategyid = chosen_sp->ms_id; + } + + /* initialize the strategy. this will cause each of the managers + * to be initialized as well. if error, return 0. + */ + ok = ( * chosen_sp->ms_create )( chosen_sp, argc, argv ); + if ( ! ok ) { + return 0; + } + + /* return the selected strategy + */ + return chosen_sp; +} + +bool_t +media_init( media_strategy_t *msp, int argc, char *argv[] ) +{ + bool_t ok; + + ok = ( * msp->ms_init )( msp, argc, argv ); + + return ok; +} + +void +media_complete( media_strategy_t *msp ) +{ + ( * msp->ms_complete )( msp ); +} + +/* media_get_upper_hdrs - supply pointers to portion of media file headers + * set aside for upper software layers, as well as to the global hdrs + */ +void +media_get_upper_hdrs( media_t *mediap, + global_hdr_t **grhdrpp, + char **rhdrpp, + size_t *rhdrszp, + global_hdr_t **gwhdrpp, + char **whdrpp, + size_t *whdrszp ) +{ + *grhdrpp = mediap->m_greadhdrp; + *rhdrpp = mediap->m_readhdrp->mh_upper; + *rhdrszp = sizeof( mediap->m_readhdrp->mh_upper ); + + *gwhdrpp = mediap->m_gwritehdrp; + *whdrpp = mediap->m_writehdrp->mh_upper; + *whdrszp = sizeof( mediap->m_writehdrp->mh_upper ); +} + + +/* definition of locally defined static functions ****************************/ + +/* media_alloc - allocate and initialize the generic portions of a media + * descriptor and read and write media headers + */ +static media_t * +media_alloc( drive_t *drivep, + char *medialabel ) +{ + media_t *mediap; + global_hdr_t *grhdrp; + global_hdr_t *gwhdrp; + media_hdr_t *mrhdrp; + media_hdr_t *mwhdrp; + size_t mrhdrsz; + size_t mwhdrsz; + + mediap = ( media_t * )calloc( 1, sizeof( media_t )); + ASSERT( mediap ); + + grhdrp = 0; + gwhdrp = 0; + mrhdrp = 0; + mwhdrp = 0; + drive_get_upper_hdrs( drivep, + &grhdrp, + ( char ** )&mrhdrp, + &mrhdrsz, + &gwhdrp, + ( char ** )&mwhdrp, + &mwhdrsz ); + ASSERT( grhdrp ); + ASSERT( gwhdrp ); + ASSERT( mrhdrp ); + ASSERT( mwhdrp ); + ASSERT( mrhdrsz == MEDIA_HDR_SZ ); + ASSERT( mwhdrsz == MEDIA_HDR_SZ ); + + mediap->m_greadhdrp = grhdrp; + mediap->m_gwritehdrp = gwhdrp; + mediap->m_readhdrp = mrhdrp; + mediap->m_writehdrp = mwhdrp; + mediap->m_drivep = drivep; + + strncpyterm( mwhdrp->mh_medialabel, + medialabel, + sizeof( mwhdrp->mh_medialabel )); + +#ifdef DUMP + uuid_create( mwhdrp->mh_mediaid ); +#else /* DUMP */ + uuid_clear( mwhdrp->mh_mediaid ); +#endif /* DUMP */ + + return mediap; +} diff -rNu linux-2.4.7/cmd/xfsdump/common/media.h linux-2.4-xfs/cmd/xfsdump/common/media.h --- linux-2.4.7/cmd/xfsdump/common/media.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/media.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef MEDIA_H +#define MEDIA_H + +/* media.[hc] - media abstraction + */ + +/* media_hdr_t - media file header + * + * This header structure will be placed at the beginning of the + * media object files by the drive manager do_begin_write() operator, + * and will be extracted from the beginnining of the media object files by + * the do_begin_read() operator. A media header_t has three parts: generally + * useful info, media strategy-specific info, and upper layer info. The hdr + * argument of the mo_begin_write() operator will be stuffed into the + * upper layer info, and extracted for the upper layer by mo_begin_read(). + */ +#define MEDIA_HDR_SZ sizeofmember( drive_hdr_t, dh_upper ) + +struct media_hdr { + char mh_medialabel[ GLOBAL_HDR_STRING_SZ ]; /* 100 100 */ + /* label of media object containing file */ + char mh_prevmedialabel[ GLOBAL_HDR_STRING_SZ ]; /* 100 200 */ + /* label of upstream media object */ + char mh_pad1[ GLOBAL_HDR_STRING_SZ ]; /* 100 300 */ + /* in case more labels needed */ + uuid_t mh_mediaid; /* 10 310 */ + /* ID of media object */ + uuid_t mh_prevmediaid; /* 10 320 */ + /* ID of upstream media object */ + char mh_pad2[ GLOBAL_HDR_UUID_SZ ]; /* 10 330 */ + /* in case more IDs needed */ + u_int32_t mh_mediaix; /* 4 334 */ + /* 0-based index of this media object within the dump stream */ + u_int32_t mh_mediafileix; /* 4 338 */ + /* 0-based index of this file within this media object */ + u_int32_t mh_dumpfileix; /* 4 33c */ + /* 0-based index of this file within this dump stream */ + u_int32_t mh_dumpmediafileix; /* 4 340 */ + /* 0-based index of file within dump stream and media object */ + u_int32_t mh_dumpmediaix; /* 4 344 */ + /* 0-based index of this dump within the media object */ + int32_t mh_strategyid; /* 4 348 */ + /* ID of the media strategy used to produce this dump */ + char mh_pad3[ 0x38 ]; /* 38 380 */ + /* padding */ + char mh_specific[ 0x80 ]; /* 80 400 */ + /* media strategy-specific info */ + char mh_upper[ MEDIA_HDR_SZ - 0x400 ]; /* 400 800 */ + /* header info private to upper software layers */ +}; + +typedef struct media_hdr media_hdr_t; + +/* macros to mark a media file as a terminator. artifact of original + * media_rmvtape media strategy + */ +#define MEDIA_TERMINATOR_CHK( mrhp ) ( mrhp->mh_specific[ 0 ] & 1 ) +#define MEDIA_TERMINATOR_SET( mwhp ) ( mwhp->mh_specific[ 0 ] |= 1 ) + +/* media strategy IDs. artifactis of first version of xfsdump + */ +#define MEDIA_STRATEGY_SIMPLE 0 +#define MEDIA_STRATEGY_RMVTAPE 1 + +#endif /* MEDIA_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/media_rmvtape.h linux-2.4-xfs/cmd/xfsdump/common/media_rmvtape.h --- linux-2.4.7/cmd/xfsdump/common/media_rmvtape.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/media_rmvtape.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef MEDIA_RMVTAPE_H +#define MEDIA_RMVTAPE_H + +/* media_rmvtape.h - removalable tape media abstraction + */ + +/* This structure is overlayed on the mh_specific field of the media_hdr + * structure. If is a maximum of 128 byptes long. + */ +struct media_rmvtape_spec { + int32_t mrmv_flags; /* 4 0 */ + /* flags field for the rmv media layer */ + char mrmv_pad[124]; /* 124 4 */ + /* remainder of media specific header */ +}; + +typedef struct media_rmvtape_spec media_rmvtape_spec_t; + +/* media context specific to the rmvtape media driver + * + */ +struct media_context { + uuid_t mc_mediaid; + uuid_t mc_dumpid; + char mc_medialabel[GLOBAL_HDR_STRING_SZ]; + char mc_dumplabel[GLOBAL_HDR_STRING_SZ]; +}; + +typedef struct media_context media_context_t; + +/* flags defined in the rmv media layer + * + */ +#define RMVMEDIA_TERMINATOR_BLOCK 0x00000001 + +#define TERM_IS_SET(rmv_hdrp) (rmv_hdrp->mrmv_flags & RMVMEDIA_TERMINATOR_BLOCK) + + +#define CAN_OVERWRITE( drivep ) (drivep->d_capabilities & DRIVE_CAP_OVERWRITE) +#define CAN_APPEND( drivep ) (drivep->d_capabilities & DRIVE_CAP_APPEND) +#define CAN_BSF( drivep ) (drivep->d_capabilities & DRIVE_CAP_BSF) + +#endif diff -rNu linux-2.4.7/cmd/xfsdump/common/mlog.c linux-2.4-xfs/cmd/xfsdump/common/mlog.c --- linux-2.4.7/cmd/xfsdump/common/mlog.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/mlog.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "qlock.h" +#include "stream.h" +#include "mlog.h" +#include "cldmgr.h" +#include "getopt.h" + +extern char *progname; +extern void usage( void ); + +#ifdef DUMP +static FILE *mlog_fp = NULL; /* stderr */; +#endif /* DUMP */ +#ifdef RESTORE +static FILE *mlog_fp = NULL; /* stdout */; +#endif /* RESTORE */ + +intgen_t mlog_level_ss[ MLOG_SS_CNT ] = { + MLOG_VERBOSE, + MLOG_VERBOSE, + MLOG_VERBOSE, + MLOG_VERBOSE, +#ifdef RESTORE + MLOG_VERBOSE, +#endif /* RESTORE */ + MLOG_VERBOSE +}; + +intgen_t mlog_showlevel = BOOL_FALSE; + +intgen_t mlog_showss = BOOL_FALSE; + +intgen_t mlog_timestamp = BOOL_FALSE; + +static intgen_t mlog_sym_lookup( char * ); + +static size_t mlog_streamcnt; + +static char mlog_levelstr[ 3 ]; + +#define MLOG_SS_NAME_MAX 10 + +static char mlog_ssstr[ MLOG_SS_NAME_MAX + 2 ]; + +static char mlog_tsstr[ 10 ]; + +struct mlog_sym { + char *sym; + intgen_t level; +}; + +typedef struct mlog_sym mlog_sym_t; + +char *mlog_ss_names[ MLOG_SS_CNT ] = { + "general", /* MLOG_SS_GEN */ + "proc", /* MLOG_SS_PROC */ + "drive", /* MLOG_SS_DRIVE */ + "media", /* MLOG_SS_MEDIA */ + "inventory", /* MLOG_SS_INV */ +#ifdef DUMP + "inomap" /* MLOG_SS_INOMAP */ +#endif /* DUMP */ +#ifdef RESTORE + "tree" /* MLOG_SS_TREE */ +#endif /* RESTORE */ +}; + +static mlog_sym_t mlog_sym[ ] = { + {"0", MLOG_SILENT}, + {"1", MLOG_VERBOSE}, + {"2", MLOG_TRACE}, + {"3", MLOG_DEBUG}, + {"4", MLOG_NITTY}, + {"5", MLOG_NITTY + 1}, + {"silent", MLOG_SILENT}, + {"verbose", MLOG_VERBOSE}, + {"trace", MLOG_TRACE}, + {"debug", MLOG_DEBUG}, + {"nitty", MLOG_NITTY} +}; + +static qlockh_t mlog_qlockh; + +bool_t +mlog_init1( intgen_t argc, char *argv[ ] ) +{ + char **suboptstrs; + ix_t ssix; + ix_t soix; + size_t vsymcnt; + intgen_t c; + +#ifdef DUMP + mlog_fp = stderr; +#endif /* DUMP */ +#ifdef RESTORE + mlog_fp = stdout; +#endif /* RESTORE */ + + /* initialize stream count. will be updated later by call to + * mlog_tell_streamcnt( ), after drive layer has counted drives + */ + mlog_streamcnt = 1; + + /* prepare an array of suboption token strings. this will be the + * concatenation of the subsystem names with the verbosity symbols. + * this array of char pts must be null terminated for getsubopt( 3 ). + */ + vsymcnt = sizeof( mlog_sym ) / sizeof( mlog_sym[ 0 ] ); + suboptstrs = ( char ** )calloc( MLOG_SS_CNT + vsymcnt + 1, + sizeof( char * )); + ASSERT( suboptstrs ); + for ( soix = 0 ; soix < MLOG_SS_CNT ; soix++ ) { + ASSERT( strlen( mlog_ss_names[ soix ] ) <= MLOG_SS_NAME_MAX ); + /* unrelated, but opportunity to chk */ + suboptstrs[ soix ] = mlog_ss_names[ soix ]; + } + for ( ; soix < MLOG_SS_CNT + vsymcnt ; soix++ ) { + suboptstrs[ soix ] = mlog_sym[ soix - MLOG_SS_CNT ].sym; + } + suboptstrs[ soix ] = 0; + + /* set all of the subsystem log levels to -1, so we can see which + * subsystems where explicitly called out. those which weren't will + * be given the "general" level. + */ + for ( ssix = 0 ; ssix < MLOG_SS_CNT ; ssix++ ) { + mlog_level_ss[ ssix ] = -1; + } + mlog_level_ss[ MLOG_SS_GEN ] = MLOG_VERBOSE; + + /* get command line options + */ + optind = 1; + opterr = 0; + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + char *options; + + switch ( c ) { + case GETOPT_VERBOSITY: + if ( ! optarg || optarg[ 0 ] == '-' ) { + fprintf( stderr, + "%s: -%c argument missing\n", + progname, + optopt ); + usage( ); + return BOOL_FALSE; + } + options = optarg; + while ( *options ) { + intgen_t suboptix; + char *valstr; + + suboptix = getsubopt( &options, + (constpp)suboptstrs, + &valstr ); + if ( suboptix < 0 ) { + fprintf( stderr, + "%s: -%c argument invalid\n", + progname, + optopt ); + usage( ); + return BOOL_FALSE; + } + ASSERT( ( ix_t )suboptix + < + MLOG_SS_CNT + vsymcnt ); + if ( suboptix < MLOG_SS_CNT ) { + if ( ! valstr ) { + fprintf( stderr, + "%s: -%c subsystem " + "subargument " + "%s requires a " + "verbosity value\n", + progname, + optopt, + mlog_ss_names[ suboptix ] ); + usage( ); + return BOOL_FALSE; + } + ssix = ( ix_t )suboptix; + mlog_level_ss[ ssix ] = + mlog_sym_lookup( valstr ); + } else { + if ( valstr ) { + fprintf( stderr, + "%s: -%c argument " + "does not require " + "a value\n", + progname, + optopt ); + usage( ); + return BOOL_FALSE; + } + ssix = MLOG_SS_GEN; + mlog_level_ss[ ssix ] = + mlog_sym_lookup( suboptstrs[ suboptix ] ); + } + if ( mlog_level_ss[ ssix ] < 0 ) { + fprintf( stderr, + "%s: -%c argument " + "invalid\n", + progname, + optopt ); + usage( ); + return BOOL_FALSE; + } + } + break; + case GETOPT_SHOWLOGLEVEL: + mlog_showlevel = BOOL_TRUE; + break; + case GETOPT_SHOWLOGSS: + mlog_showss = BOOL_TRUE; + break; + case GETOPT_TIMESTAMP: + mlog_timestamp = BOOL_TRUE; + break; + } + } + + free( ( void * )suboptstrs ); + + /* give subsystems not explicitly called out the "general" verbosity + */ + for ( ssix = 0 ; ssix < MLOG_SS_CNT ; ssix++ ) { + if ( mlog_level_ss[ ssix ] < 0 ) { + ASSERT( mlog_level_ss[ ssix ] == -1 ); + ASSERT( mlog_level_ss[ MLOG_SS_GEN ] >= 0 ); + mlog_level_ss[ ssix ] = mlog_level_ss[ MLOG_SS_GEN ]; + } + } + + /* prepare a string for optionally displaying the log level + */ + mlog_levelstr[ 0 ] = 0; + mlog_levelstr[ 1 ] = 0; + mlog_levelstr[ 2 ] = 0; + if ( mlog_showlevel ) { + mlog_levelstr[ 0 ] = ':'; + } + +#ifdef DUMP + /* note if dump going to stdout. if so, can't + * send mlog output there. since at compile time + * mlog_fd set to stderr, see if we can switch + * to stdout. + */ + if ( optind >= argc || strcmp( argv[ optind ], "-" )) { + mlog_fp = stdout; + } +#endif /* DUMP */ + + mlog_qlockh = QLOCKH_NULL; + + return BOOL_TRUE; +} + +bool_t +mlog_init2( void ) +{ + /* allocate a qlock + */ + mlog_qlockh = qlock_alloc( QLOCK_ORD_MLOG ); + + return BOOL_TRUE; +} + +void +mlog_tell_streamcnt( size_t streamcnt ) +{ + mlog_streamcnt = streamcnt; +} + +void +mlog_lock( void ) +{ + qlock_lock( mlog_qlockh ); +} + +void +mlog_unlock( void ) +{ + qlock_unlock( mlog_qlockh ); +} + +void +mlog( intgen_t levelarg, char *fmt, ... ) +{ + va_list args; + va_start( args, fmt ); + mlog_va( levelarg, fmt, args ); + va_end( args ); +} + +void +mlog_va( intgen_t levelarg, char *fmt, va_list args ) +{ + intgen_t level; + ix_t ss; + + level = levelarg & MLOG_LEVELMASK; + ss = ( ix_t )( ( levelarg & MLOG_SS_MASK ) >> MLOG_SS_SHIFT ); + + ASSERT( ss < MLOG_SS_CNT ); + if ( level > mlog_level_ss[ ss ] ) { + return; + } + + if ( ! ( levelarg & MLOG_NOLOCK )) { + mlog_lock( ); + } + + if ( ! ( levelarg & MLOG_BARE )) { + intgen_t streamix; + streamix = stream_getix( getpid() ); + + if ( mlog_showss ) { + sprintf( mlog_ssstr, ":%s", mlog_ss_names[ ss ] ); + } else { + mlog_ssstr[ 0 ] = 0; + } + + if ( mlog_timestamp ) { + time_t now = time( 0 ); + struct tm *tmp = localtime( &now ); + sprintf( mlog_tsstr, + ":%02d.%02d.%02d", + tmp->tm_hour, + tmp->tm_min, + tmp->tm_sec ); + ASSERT( strlen( mlog_tsstr ) < sizeof( mlog_tsstr )); + } else { + mlog_tsstr[ 0 ] = 0; + } + + if ( mlog_showlevel ) { + mlog_levelstr[ 0 ] = ':'; + if ( level > 9 ) { + mlog_levelstr[ 1 ] = '?'; + } else { + mlog_levelstr[ 1 ] = ( char ) + ( level + + + ( intgen_t )'0' ); + } + } else { + mlog_levelstr[ 0 ] = 0; + } + if ( streamix != -1 && mlog_streamcnt > 1 ) { + fprintf( mlog_fp, + "%s%s%s%s: " +#ifdef DUMP + "drive " +#endif /* DUMP */ +#ifdef RESTORE + "drive " +#endif /* RESTORE */ + "%d: ", + progname, + mlog_tsstr, + mlog_ssstr, + mlog_levelstr, + streamix ); + } else { + fprintf( mlog_fp, + "%s%s%s%s: ", + progname, + mlog_tsstr, + mlog_ssstr, + mlog_levelstr ); + } + if ( levelarg & MLOG_NOTE ) { + fprintf( mlog_fp, + "NOTE: " ); + } + if ( levelarg & MLOG_WARNING ) { + fprintf( mlog_fp, + "WARNING: " ); + } + if ( levelarg & MLOG_ERROR ) { + fprintf( mlog_fp, + "ERROR: " ); + } + } + + vfprintf( mlog_fp, fmt, args ); + fflush( mlog_fp ); + + if ( ! ( levelarg & MLOG_NOLOCK )) { + mlog_unlock( ); + } +} + +static intgen_t +mlog_sym_lookup( char *sym ) +{ + mlog_sym_t *p = mlog_sym; + mlog_sym_t *ep = mlog_sym + + + sizeof( mlog_sym ) / sizeof( mlog_sym[ 0 ] ); + + for ( ; p < ep ; p++ ) { + if ( ! strcmp( sym, p->sym )) { + return p->level; + } + } + + return -1; +} diff -rNu linux-2.4.7/cmd/xfsdump/common/mlog.h linux-2.4-xfs/cmd/xfsdump/common/mlog.h --- linux-2.4.7/cmd/xfsdump/common/mlog.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/mlog.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef MLOG_H +#define MLOG_H + +/* mlog.[hc] - message logging abstraction + */ +#include + +/* defined log levels - msg will be logged only if cmdline -v arg + * is greater than or equal to its level. + */ +#define MLOG_NORMAL 0 /* OLD */ +#define MLOG_SILENT 0 /* NEW */ +#define MLOG_VERBOSE 1 +#define MLOG_TRACE 2 +#define MLOG_DEBUG 3 +#define MLOG_NITTY 4 +#define MLOG_LEVELMASK 0xff + +/* modifier flags for the level - only the first is generally exported + */ +#define MLOG_BARE 0x010000 /* don't print preamble */ +#define MLOG_NOTE 0x020000 /* use NOTE format */ +#define MLOG_WARNING 0x040000 /* use WARNING format */ +#define MLOG_ERROR 0x080000 /* use ERROR format */ +#define MLOG_NOLOCK 0x100000 /* do not attempt to obtain mlog lock */ + +/* subsystem ids: allows per-subsystem control of log level. + * use to index mlog_level_ss. + */ +#define MLOG_SS_GEN 0 /* default if no subsystem specified */ +#define MLOG_SS_PROC 1 /* process/thread-related */ +#define MLOG_SS_DRIVE 2 /* I/O-related */ +#define MLOG_SS_MEDIA 3 /* media-related */ +#define MLOG_SS_INV 4 /* media inventory */ +#ifdef DUMP +#define MLOG_SS_INOMAP 5 /* dump inode number map */ +#endif /* DUMP */ +#ifdef RESTORE +#define MLOG_SS_TREE 5 /* restore tree */ +#endif /* RESTORE */ +#define MLOG_SS_CNT 6 /* NOTE! bump this when adding ss */ + +#define MLOG_SS_SHIFT 8 +#define MLOG_SS_MASK ( 0xff << MLOG_SS_SHIFT ) + +/* subsystem flags - NOTE! only one may be specified! use in mlog( first arg ) + */ +#define MLOG_ALL ( MLOG_SS_GEN << MLOG_SS_SHIFT ) +#define MLOG_PROC ( MLOG_SS_PROC << MLOG_SS_SHIFT ) +#define MLOG_DRIVE ( MLOG_SS_DRIVE << MLOG_SS_SHIFT ) +#define MLOG_MEDIA ( MLOG_SS_MEDIA << MLOG_SS_SHIFT ) +#define MLOG_INV ( MLOG_SS_INV << MLOG_SS_SHIFT ) +#ifdef DUMP +#define MLOG_INOMAP ( MLOG_SS_INOMAP << MLOG_SS_SHIFT ) +#endif /* DUMP */ +#ifdef RESTORE +#define MLOG_TREE ( MLOG_SS_TREE << MLOG_SS_SHIFT ) +#endif /* RESTORE */ + +/* mlog_level - set during initialization, exported to facilitate + * message logging decisions. one per subsystem (see above) + */ +extern intgen_t mlog_level_ss[ MLOG_SS_CNT ]; + +/* made external so main.c sigint dialog can change + */ +extern intgen_t mlog_showlevel; +extern intgen_t mlog_showss; +extern intgen_t mlog_timestamp; + +/* mlog_ss_name - so main.c sigint dialog can allow changes + */ +extern char *mlog_ss_names[ MLOG_SS_CNT ]; + +/* initializes the mlog abstraction. split into two phases to + * unravel some initialization sequencing problems. + */ +extern bool_t mlog_init1( intgen_t argc, char *argv[ ] ); +extern bool_t mlog_init2( void ); + +/* post-initialization, to tell mlog how many streams + */ +extern void mlog_tell_streamcnt( size_t streamcnt ); + +/* vprintf-based message format + */ +extern void mlog( intgen_t level, char *fmt, ... ); +extern void mlog_va( intgen_t levelarg, char *fmt, va_list args ); + +/* the following calls are exported ONLY to dlog.c! + */ +extern void mlog_lock( void ); +extern void mlog_unlock( void ); + +#endif /* MLOG_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/namreg.c linux-2.4-xfs/cmd/xfsdump/common/namreg.c --- linux-2.4.7/cmd/xfsdump/common/namreg.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/namreg.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "mlog.h" +#include "namreg.h" +#include "openutil.h" +#include "cleanup.h" + +/* structure definitions used locally ****************************************/ + +/* template for the name of the tmp file containing the names + */ +#define NAMETEMPLATE "namreg" + +/* context for a namreg - allocated by and pointer to returned by namreg_init() + */ +struct namreg_context { + int nc_fd; /* file descriptor of tmp file */ + bool_t nc_not_at_end; + off64_t nc_nextoff; + char *nc_pathname; +}; + +typedef struct namreg_context namreg_context_t; + + +/* declarations of externally defined global symbols *************************/ + + +/* forward declarations of locally defined static functions ******************/ + +static void namreg_abort_cleanup( void *, void * ); + + +/* definition of locally defined global variables ****************************/ + + +/* definition of locally defined static variables *****************************/ + + +/* definition of locally defined global functions ****************************/ + +namreg_t * +namreg_init( bool_t cumulative, + bool_t delta, + char *housekeepingdir ) +{ + namreg_context_t *ncp; + + /* allocate and initialize context + */ + ncp = ( namreg_context_t * )calloc( 1, sizeof( namreg_context_t )); + ASSERT( ncp ); + + /* generate a string containing the pathname of the namreg file + */ + ncp->nc_pathname = open_pathalloc( housekeepingdir, NAMETEMPLATE, 0 ); + + /* if not a cumulative restore, be sure the name registry gets removed + * on exit. + */ + if ( ! cumulative ) { + ( void )cleanup_register( namreg_abort_cleanup, + ( void * )ncp, + 0 ); + } + + /* if this is a delta during a cumulative restore, the namreg file must + * already exist. if not, create/truncate. + */ + if ( cumulative && delta ) { + ncp->nc_fd = open_rwp( ncp->nc_pathname ); + if ( ncp->nc_fd < 0 ) { + mlog( MLOG_NORMAL, + "could not open %s: %s\n", + ncp->nc_pathname, + strerror( errno )); + return 0; + } + } else { + ncp->nc_fd = open_trwp( ncp->nc_pathname ); + if ( ncp->nc_fd < 0 ) { + return 0; + } + } + + return ( namreg_t * )ncp; +} + +namreg_ix_t +namreg_add( namreg_t *namregp, char *name, size_t namelen ) +{ + register namreg_context_t *ncp = ( namreg_context_t *)namregp; + off64_t oldoff; + intgen_t nwritten; + unsigned char c; + + /* make sure file pointer is positioned to write at end of file + */ + if ( ncp->nc_not_at_end ) { + off64_t new_off; + new_off = lseek64( ncp->nc_fd, ( off64_t )0, SEEK_END ); + if ( new_off == ( off64_t )-1 ) { + mlog( MLOG_NORMAL, + "lseek of namreg failed: %s\n", + strerror( errno )); + ASSERT( 0 ); + return NAMREG_IX_NULL; + } + ncp->nc_nextoff = new_off; + ncp->nc_not_at_end = BOOL_FALSE; + } + + /* save the current offset + */ + oldoff = ncp->nc_nextoff; + + /* write a one byte unsigned string length + */ + ASSERT( namelen < 256 ); + c = ( unsigned char )( namelen & 0xff ); + nwritten = write( ncp->nc_fd, ( void * )&c, 1 ); + if ( nwritten != 1 ) { + mlog( MLOG_NORMAL, + "write of namreg failed: %s\n", + strerror( errno )); + ASSERT( 0 ); + return NAMREG_IX_NULL; + } + + /* write the name string + */ + nwritten = write( ncp->nc_fd, ( void * )name, namelen ); + if ( ( size_t )nwritten != namelen ) { + mlog( MLOG_NORMAL, + "write of namreg failed: %s\n", + strerror( errno )); + ASSERT( 0 ); + return NAMREG_IX_NULL; + } + + ncp->nc_nextoff += ( off64_t )( 1 + namelen ); + return ( namreg_ix_t )oldoff; +} + +/* ARGSUSED */ +void +namreg_del( namreg_t *namregp, namreg_ix_t namreg_ix ) +{ + /* currently not implemented - grows, never shrinks + */ +} + +intgen_t +namreg_get( namreg_t *namregp, + namreg_ix_t namreg_ix, + char *bufp, + size_t bufsz ) +{ + register namreg_context_t *ncp = ( namreg_context_t *)namregp; + off64_t new_off; + intgen_t nread; + size_t len; + unsigned char c; + + /* convert the ix into the offset + */ + new_off = ( off64_t )namreg_ix; + + /* seek to the name + */ + ASSERT( namreg_ix != NAMREG_IX_NULL ); + new_off = lseek64( ncp->nc_fd, new_off, SEEK_SET ); + if ( new_off == ( off64_t )-1 ) { + mlog( MLOG_NORMAL, + "lseek of namreg failed: %s\n", + strerror( errno )); + return -3; + } + + /* read the name length + */ + c = 0; /* unnecessary, but keeps lint happy */ + nread = read( ncp->nc_fd, ( void * )&c, 1 ); + if ( nread != 1 ) { + mlog( MLOG_NORMAL, + "read of namreg failed: %s (nread = %d)\n", + strerror( errno ), + nread ); + return -3; + } + + /* deal with a short caller-supplied buffer + */ + len = ( size_t )c; + if ( bufsz < len + 1 ) { + return -1; + } + + /* read the name + */ + nread = read( ncp->nc_fd, ( void * )bufp, len ); + if ( ( size_t )nread != len ) { + mlog( MLOG_NORMAL, + "read of namreg failed: %s\n", + strerror( errno )); + return -3; + } + + /* null-terminate the string if room + */ + bufp[ len ] = 0; + + ncp->nc_not_at_end = BOOL_TRUE; + + return ( intgen_t )len; +} + + +/* definition of locally defined static functions ****************************/ + +static void +namreg_abort_cleanup( void *arg1, void *arg2 ) +{ + namreg_context_t *ncp = ( namreg_context_t * )arg1; + ( void )unlink( ncp->nc_pathname ); +} diff -rNu linux-2.4.7/cmd/xfsdump/common/namreg.h linux-2.4-xfs/cmd/xfsdump/common/namreg.h --- linux-2.4.7/cmd/xfsdump/common/namreg.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/namreg.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef NAMREG_H +#define NAMREG_H + +/* namreg.[hc] - directory entry registry + * + * provides unique directory entry ID's and storage for the entry + * name. + */ + +/* namreg_t - external handle; internally typecast to something more useful + */ +typedef void namreg_t; + + +/* namreg_ix_t - abstract index of a registered name + */ +typedef size_t namreg_ix_t; +#define NAMREG_IX_NULL ( ( namreg_ix_t )( -1 )) +#define NAMREG_IX_MAX SIZEMAX + + +/* namreg_init - creates a name registry. returns namreg_t pointer + */ +extern namreg_t *namreg_init( bool_t cumulative, + bool_t delta, + char *housekeepingdir ); + + +/* namreg_add - registers a name. name does not need to be null-terminated. + * returns abstract index for use with namreg_get(). + */ +extern namreg_ix_t namreg_add( namreg_t *namregp, char *name, size_t namelen ); + + +/* namreg_del - remove a name from the registry + */ +extern void namreg_del( namreg_t *namregp, namreg_ix_t namreg_ix ); + + +/* namreg_get - retrieves the name identified by the index. + * fills the buffer with the null-terminated name from the registry. + * returns the strlen() of the name. returns -1 if the buffer is too + * small to fit the null-terminated name. return -2 if the name + * not in the registry. return -3 if a system call fails. + */ +extern intgen_t namreg_get( namreg_t *namregp, + namreg_ix_t namreg_ix, + char *bufp, + size_t bufsz ); + + +#endif /* NAMREG_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/openutil.c linux-2.4-xfs/cmd/xfsdump/common/openutil.c --- linux-2.4.7/cmd/xfsdump/common/openutil.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/openutil.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#include +#include + +#include +#include +#include +#include + +#include "types.h" +#include "mlog.h" + +char * +open_pathalloc( char *dirname, char *basename, pid_t pid ) +{ + size_t dirlen; + size_t pidlen; + char *namebuf; + + if ( strcmp( dirname, "/" )) { + dirlen = strlen( dirname ); + } else { + dirlen = 0; + dirname = ""; + } + + if ( pid ) { + pidlen = 1 + 6; + } else { + pidlen = 0; + } + namebuf = ( char * )calloc( 1, + dirlen + + + 1 + + + strlen( basename ) + + + pidlen + + + 1 ); + ASSERT( namebuf ); + + if ( pid ) { + ( void )sprintf( namebuf, "%s/%s.%d", dirname, basename, pid ); + } else { + ( void )sprintf( namebuf, "%s/%s", dirname, basename ); + } + + return namebuf; +} + +intgen_t +open_trwp( char *pathname ) +{ + intgen_t fd; + + fd = open( pathname, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR ); + if ( fd < 0 ) { + mlog( MLOG_NORMAL, + "could not create %s: %s\n", + pathname, + strerror( errno )); + } + + return fd; +} + +intgen_t +open_erwp( char *pathname ) +{ + intgen_t fd; + + fd = open( pathname, O_EXCL | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR ); + if ( fd < 0 ) { + mlog( MLOG_DEBUG, + "could not create %s: %s\n", + pathname, + strerror( errno )); + } + + return fd; +} + +intgen_t +open_rwp( char *pathname ) +{ + intgen_t fd; + + fd = open( pathname, O_RDWR ); + + return fd; +} + +intgen_t +mkdir_tp( char *pathname ) +{ + intgen_t rval; + + rval = mkdir( pathname, S_IRWXU ); + + return rval; +} + +intgen_t +open_trwdb( char *dirname, char *basename, pid_t pid ) +{ + char *pathname; + intgen_t fd; + + pathname = open_pathalloc( dirname, basename, pid ); + fd = open_trwp( pathname ); + free( ( void * )pathname ); + + return fd; +} + +intgen_t +open_erwdb( char *dirname, char *basename, pid_t pid ) +{ + char *pathname; + intgen_t fd; + + pathname = open_pathalloc( dirname, basename, pid ); + fd = open_erwp( pathname ); + free( ( void * )pathname ); + + return fd; +} + +intgen_t +open_rwdb( char *dirname, char *basename, pid_t pid ) +{ + char *pathname; + intgen_t fd; + + pathname = open_pathalloc( dirname, basename, pid ); + fd = open_rwp( pathname ); + free( ( void * )pathname ); + + return fd; +} diff -rNu linux-2.4.7/cmd/xfsdump/common/openutil.h linux-2.4-xfs/cmd/xfsdump/common/openutil.h --- linux-2.4.7/cmd/xfsdump/common/openutil.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/openutil.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef OPENUTIL_H +#define OPENUTIL_H + +/* openutil.[hc] - useful functions for opening tmp and housekeeping + * files. + */ + + +/* allocate and fill a character sting buffer with a pathname generated + * by catenating the dir and base args. if pid is non-zero, the decimal + * representation of the pid will be appended to the pathname, beginning + * with a '.'. + */ +extern char *open_pathalloc( char *dirname, char *basename, pid_t pid ); + +/* create the specified file, creating or truncating as necessary, + * with read and write permissions, given a directory and base. + * return the file descriptor, or -1 with errno set. uses mlog( MLOG_NORMAL... + * if the creation fails. + */ +extern intgen_t open_trwdb( char *dirname, char *basename, pid_t pid ); +extern intgen_t open_trwp( char *pathname ); + + +/* open the specified file, with read and write permissions, given a + * directory and base.* return the file descriptor, or -1 with errno set. + * uses mlog( MLOG_NORMAL... if the open fails. + */ +extern intgen_t open_rwdb( char *dirname, char *basename, pid_t pid ); +extern intgen_t open_rwp( char *pathname ); + + +/* create and open the specified file, failing if already exists + */ +extern intgen_t open_erwp( char *pathname ); +extern intgen_t open_erwdb( char *dirname, char *basename, pid_t pid ); + + +/* create the specified directory, guaranteed to be initially empty. returns + * 0 on success, -1 if trouble. uses mlog( MLOG_NORMAL... if the creation fails. + */ +extern intgen_t mkdir_tp( char *pathname ); + + +#endif /* UTIL_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/path.c linux-2.4-xfs/cmd/xfsdump/common/path.c --- linux-2.4.7/cmd/xfsdump/common/path.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/path.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include "path.h" + +struct pem { + char *pem_head; + char *pem_next; +}; + +typedef struct pem pem_t; + +static pem_t * pem_alloc( char *path ); +static void pem_free( pem_t *pemp ); +static char * pem_next( pem_t *pemp ); + +#define PAMAX 1024 + +struct pa { + char *pa_array[ PAMAX ]; + int pa_cnt; +}; + +typedef struct pa pa_t; + +static pa_t * pa_alloc( void ); +static void pa_free( pa_t *pap ); +static void pa_append( pa_t *pap, char *pep ); +static int pa_peel( pa_t *pap ); +static char * pa_gen( pa_t *pap ); + +char * +path_diff( char *path, char *base ) +{ + char *diff; + + ASSERT( *base == '/' ); + ASSERT( *path == '/' ); + + if ( ! path_beginswith( path, base )) { + return 0; + } + + for ( ; *base && *path == *base ; path++, base++ ) + ; + + if ( *path == 0 ) { + return 0; + } + + if ( *path == '/' ) { + path++; + } + + diff = ( char * )calloc( 1, strlen( path ) + 1 ); + ASSERT( diff ); + strcpy( diff, path ); + + return diff; +} + +int +path_beginswith( char *path, char *base ) +{ + if ( ! base ) { + return 0; + } + return ! strncmp( base, path, strlen( base )); +} + +char * +path_reltoabs( char *dir, char *basedir ) +{ + char *absdir; + + /* check if the path starts with a / or + * is a remote path (i.e. contains machine:/path/name ). + */ + if ( ( *dir != '/' ) && ( strchr(dir, ':') == 0 ) ) { + char *absdir; + absdir = ( char * )malloc( strlen( basedir ) + + + 1 + + + strlen( dir ) + + + 1 ); + ASSERT( absdir ); + + ( void )sprintf( absdir, "%s/%s", basedir, dir ); + + dir = absdir; + } + + if ( strchr(dir, ':') == 0 ) { + absdir = path_normalize( dir ); + } else { + absdir = ( char * )malloc( strlen( dir ) + 1); + ( void )sprintf( absdir, "%s", dir); + } + + return absdir; +} + +char * +path_normalize( char *path ) +{ + pem_t *pemp = pem_alloc( path ); + pa_t *pap = pa_alloc( ); + char *pep; + char *npath; + + ASSERT( path[ 0 ] == '/' ); + + while ( ( pep = pem_next( pemp )) != 0 ) { + if ( ! strcmp( pep, "" )) { + free( ( void * )pep ); + continue; + } + if ( ! strcmp( pep, "." )) { + free( ( void * )pep ); + continue; + } + if ( ! strcmp( pep, ".." )) { + int ok; + free( ( void * )pep ); + ok = pa_peel( pap ); + if ( ! ok ) { + pa_free( pap ); + pem_free( pemp ); + return 0; + } + continue; + } + pa_append( pap, pep ); + } + + npath = pa_gen( pap ); + pa_free( pap ); + pem_free( pemp ); + + return npath; +} + +static pem_t * +pem_alloc( char *path ) +{ + pem_t *pemp = ( pem_t * )calloc( 1, sizeof( pem_t )); + ASSERT( pemp ); + pemp->pem_head = path; + pemp->pem_next = pemp->pem_head; + + return pemp; +} + +static void +pem_free( pem_t *pemp ) +{ + free( ( void * )pemp ); +} + +static char * +pem_next( pem_t *pemp ) +{ + char *nextnext; + size_t len; + char *p; + + /* no more left + */ + if ( *pemp->pem_next == 0 ) { + return 0; + } + + /* find the following slash + */ + nextnext = strchr( pemp->pem_next + 1, '/' ); + + /* if end of string encountered, place next next at end of string + */ + if ( ! nextnext ) { + for ( nextnext = pemp->pem_next ; *nextnext ; nextnext++ ) + ; + } + + /* determine the length of the path element, sans the leading slash + */ + len = ( size_t )( nextnext - pemp->pem_next - 1 ); + + /* allocate buffer to hold the path element, incl null termination + */ + p = ( char * )malloc( len + 1 ); + ASSERT( p ); + + /* copy the path element into the buffer + */ + strncpy( p, pemp->pem_next + 1, len ); + + /* null-terminate + */ + p[ len ] = 0; + + /* update next + */ + pemp->pem_next = nextnext; + + /* return the allocated buffer to the caller + */ + return p; +} + +static pa_t * +pa_alloc( void ) +{ + pa_t *pap = ( pa_t * )calloc( 1, sizeof( pa_t )); + ASSERT( pap ); + + return pap; +} + +static void +pa_free( pa_t *pap ) +{ + int i; + + for ( i = 0 ; i < pap->pa_cnt ; i++ ) { + free( ( void * )pap->pa_array[ i ] ); + } + + free( ( void * )pap ); +} + +static void +pa_append( pa_t *pap, char *pep ) +{ + ASSERT( pap->pa_cnt < PAMAX ); + + pap->pa_array[ pap->pa_cnt ] = pep; + + pap->pa_cnt++; +} + +static int +pa_peel( pa_t *pap ) +{ + if ( pap->pa_cnt <= 0 ) { + ASSERT( pap->pa_cnt == 0 ); + return 0; + } + + pap->pa_cnt--; + ASSERT( pap->pa_array[ pap->pa_cnt ] ); + free( ( void * )pap->pa_array[ pap->pa_cnt ] ); + pap->pa_array[ pap->pa_cnt ] = 0; + + return 1; +} + +static char * +pa_gen( pa_t *pap ) +{ + size_t sz; + int i; + char *retp; + char *p; + + sz = 0; + for ( i = 0 ; i < pap->pa_cnt ; i++ ) { + sz += strlen( pap->pa_array[ i ] ) + 1; + } + sz++; + + retp = ( char * )malloc( sz ); + + if ( pap->pa_cnt <= 0 ) { + ASSERT( pap->pa_cnt == 0 ); + sprintf( retp, "/" ); + } else { + p = retp; + for ( i = 0 ; i < pap->pa_cnt ; i++ ) { + sprintf( p, "/%s", pap->pa_array[ i ] ); + p += strlen( p ); + } + } + + return retp; +} diff -rNu linux-2.4.7/cmd/xfsdump/common/path.h linux-2.4-xfs/cmd/xfsdump/common/path.h --- linux-2.4.7/cmd/xfsdump/common/path.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/path.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef PATH_H +#define PATH_H + +/* various pathname helpers + */ +extern char * path_reltoabs( char *dir, char *basedir ); +extern char *path_normalize( char *path ); +extern char * path_diff( char *path, char *base ); +extern int path_beginswith( char *path, char *base ); + +#endif /* PATH_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/qlock.c linux-2.4-xfs/cmd/xfsdump/common/qlock.c --- linux-2.4.7/cmd/xfsdump/common/qlock.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/qlock.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,671 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include "types.h" +#include "qlock.h" +#include "mlog.h" + +struct qlock { + ix_t ql_ord; + /* ordinal position of this lock + */ + pid_t ql_owner; + /* who owns this lock + */ +#ifdef HIDDEN + ulock_t ql_uslockh; + /* us lock handle + */ +#endif /* HIDDEN */ +}; + +typedef struct qlock qlock_t; + /* internal qlock + */ + +#define QLOCK_SPINS 0x1000 + /* how many times to spin on lock before sleeping for it + */ + +#define QLOCK_THRDCNTMAX 256 + /* arbitrary limit on number of threads supported + */ + +static size_t qlock_thrdcnt; + /* how many threads have checked in + */ + +typedef size_t ordmap_t; + /* bitmap of ordinals. used to track what ordinals have + * been allocated. + */ + +#define ORDMAX ( 8 * sizeof( ordmap_t )) + /* ordinals must fit into a wordsize bitmap + */ + +static ordmap_t qlock_ordalloced; + /* to enforce allocation of only one lock to each ordinal value + */ + +struct thrddesc { + pid_t td_pid; + ordmap_t td_ordmap; +}; +typedef struct thrddesc thrddesc_t; +#ifdef HIDDEN +static thrddesc_t qlock_thrddesc[ QLOCK_THRDCNTMAX ]; + /* holds the ordmap for each thread + */ +#endif + +#define QLOCK_ORDMAP_SET( ordmap, ord ) ( ordmap |= 1U << ord ) + /* sets the ordinal bit in an ordmap + */ + +#define QLOCK_ORDMAP_CLR( ordmap, ord ) ( ordmap &= ~( 1U << ord )) + /* clears the ordinal bit in an ordmap + */ + +#define QLOCK_ORDMAP_GET( ordmap, ord ) ( ordmap & ( 1U << ord )) + /* checks if ordinal set in ordmap + */ + +#define QLOCK_ORDMAP_CHK( ordmap, ord ) ( ordmap & (( 1U << ord ) - 1U )) + /* checks if any bits less than ord are set in the ordmap + */ + +#ifdef HIDDEN +static usptr_t *qlock_usp; +#else +static void *qlock_usp; +#endif /* HIDDEN */ + + /* pointer to shared arena from which locks are allocated + */ + +#ifdef HIDDEN +static char *qlock_arenaroot = "xfsrestoreqlockarena"; + /* shared arena file name root + */ +#endif + +/* REFERENCED */ +static bool_t qlock_inited = BOOL_FALSE; + /* to sanity check initialization + */ + +/* forward declarations + */ +#ifdef HIDDEN +static void qlock_ordmap_add( pid_t pid ); +static ordmap_t *qlock_ordmapp_get( pid_t pid ); +static ix_t qlock_thrdix_get( pid_t pid ); +#endif + +bool_t +qlock_init( bool_t miniroot ) +{ +#ifdef HIDDEN + char arenaname[ 100 ]; + /* REFERENCED */ + intgen_t nwritten; + intgen_t rval; +#endif + + /* sanity checks + */ + ASSERT( ! qlock_inited ); + + /* initially no threads checked in + */ + qlock_thrdcnt = 0; + + /* initially no ordinals allocated + */ + qlock_ordalloced = 0; + + /* if miniroot, fake it + */ + if ( miniroot ) { + qlock_inited = BOOL_TRUE; + qlock_usp = 0; + return BOOL_TRUE; + } +#ifdef HIDDEN + + /* generate the arena name + */ + nwritten = sprintf( arenaname, + "/tmp/%s.%d", + qlock_arenaroot, + get_pid() ); + ASSERT( nwritten > 0 ); + ASSERT( ( size_t )nwritten < sizeof( arenaname )); + + /* configure shared arenas to automatically unlink on last close + */ + rval = usconfig( CONF_ARENATYPE, ( u_intgen_t )US_SHAREDONLY ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_NOLOCK, + "unable to configure shared arena for auto unlink: %s\n", + strerror( errno )); + return BOOL_FALSE; + } + + /* allocate a shared arena for the locks + */ + qlock_usp = usinit( arenaname ); + if ( ! qlock_usp ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_NOLOCK, + "unable to allocate shared arena for thread locks: %s\n", + strerror( errno )); + return BOOL_FALSE; + } + + /* now say we are initialized + */ + qlock_inited = BOOL_TRUE; + + /* add the parent thread to the thread list + */ + if ( ! qlock_thrdinit( )) { + qlock_inited = BOOL_FALSE; + return BOOL_FALSE; + } +#endif /* HIDDEN */ + + return BOOL_TRUE; +} + +bool_t +qlock_thrdinit( void ) +{ +#ifdef HIDDEN + intgen_t rval; + + /* sanity checks + */ + ASSERT( qlock_inited ); + ASSERT( qlock_usp ); + + /* add thread to shared arena + */ + rval = usadd( qlock_usp ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_NOLOCK, + "unable to add thread to shared arena: %s\n", + strerror( errno )); + return BOOL_FALSE; + } + + /* add thread to ordmap list + */ + qlock_ordmap_add( get_pid() ); +#endif /* HIDDEN */ + + return BOOL_TRUE; +} + +qlockh_t +qlock_alloc( ix_t ord ) +{ + qlock_t *qlockp; + + /* sanity checks + */ + ASSERT( qlock_inited ); + + /* verify the ordinal is not already taken, and mark as taken + */ + ASSERT( ! QLOCK_ORDMAP_GET( qlock_ordalloced, ord )); + QLOCK_ORDMAP_SET( qlock_ordalloced, ord ); + + /* allocate lock memory + */ + qlockp = ( qlock_t * )calloc( 1, sizeof( qlock_t )); + ASSERT( qlockp ); + +#ifdef HIDDEN + /* allocate a us lock: bypass if miniroot + */ + if ( qlock_usp ) { + qlockp->ql_uslockh = usnewlock( qlock_usp ); + ASSERT( qlockp->ql_uslockh ); + } +#endif /* HIDDEN */ + + /* assign the ordinal position + */ + qlockp->ql_ord = ord; + + return ( qlockh_t )qlockp; +} + +void +qlock_lock( qlockh_t qlockh ) +{ +#ifdef HIDDEN + qlock_t *qlockp = ( qlock_t * )qlockh; + pid_t pid; + ix_t thrdix; + ordmap_t *ordmapp; + /* REFERENCED */ + bool_t lockacquired; +#endif + + /* sanity checks + */ + ASSERT( qlock_inited ); + + /* bypass if miniroot + */ + if ( ! qlock_usp ) { + return; + } + +#ifdef HIDDEN + + /* get the caller's pid and thread index + */ + pid = get_pid(); + + thrdix = qlock_thrdix_get( pid ); + + /* get the ordmap for this thread + */ + ordmapp = qlock_ordmapp_get( pid ); + + /* assert that this lock not already held + */ + if ( QLOCK_ORDMAP_GET( *ordmapp, qlockp->ql_ord )) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_NOLOCK, + "lock already held: thrd %d pid %d ord %d map %x\n", + thrdix, + pid, + qlockp->ql_ord, + *ordmapp ); + } + ASSERT( ! QLOCK_ORDMAP_GET( *ordmapp, qlockp->ql_ord )); + + /* assert that no locks with a lesser ordinal are held by this thread + */ + if ( QLOCK_ORDMAP_CHK( *ordmapp, qlockp->ql_ord )) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_NOLOCK, + "lock ordinal violation: thrd %d pid %d ord %d map %x\n", + thrdix, + pid, + qlockp->ql_ord, + *ordmapp ); + } + ASSERT( ! QLOCK_ORDMAP_CHK( *ordmapp, qlockp->ql_ord )); + + /* acquire the us lock + */ + lockacquired = uswsetlock( qlockp->ql_uslockh, QLOCK_SPINS ); + ASSERT( lockacquired ); + + /* verify lock is not already held + */ + ASSERT( ! qlockp->ql_owner ); + + /* add ordinal to this threads ordmap + */ + QLOCK_ORDMAP_SET( *ordmapp, qlockp->ql_ord ); + + /* indicate the lock's owner + */ + qlockp->ql_owner = pid; +#endif /* HIDDEN */ +} + +void +qlock_unlock( qlockh_t qlockh ) +{ +#ifdef HIDDEN + qlock_t *qlockp = ( qlock_t * )qlockh; + pid_t pid; + ordmap_t *ordmapp; + /* REFERENCED */ + intgen_t rval; +#endif + + /* sanity checks + */ + ASSERT( qlock_inited ); + + /* bypass if miniroot + */ + if ( ! qlock_usp ) { + return; + } + +#ifdef HIDDEN + /* get the caller's pid + */ + pid = get_pid(); + + /* get the ordmap for this thread + */ + ordmapp = qlock_ordmapp_get( pid ); + + /* verify lock is held by this thread + */ + ASSERT( QLOCK_ORDMAP_GET( *ordmapp, qlockp->ql_ord )); + ASSERT( qlockp->ql_owner == pid ); + + /* clear lock owner + */ + qlockp->ql_owner = 0; + + /* clear lock's ord from thread's ord map + */ + QLOCK_ORDMAP_CLR( *ordmapp, qlockp->ql_ord ); + + /* release the us lock + */ + rval = usunsetlock( qlockp->ql_uslockh ); + ASSERT( ! rval ); +#endif /* HIDDEN */ +} + +qsemh_t +qsem_alloc( ix_t cnt ) +{ +#ifdef HIDDEN + usema_t *usemap; + + /* sanity checks + */ + ASSERT( qlock_inited ); + ASSERT( qlock_usp ); + + /* allocate a us semaphore + */ + usemap = usnewsema( qlock_usp, ( intgen_t )cnt ); + ASSERT( usemap ); + + return ( qsemh_t )usemap; +#else + return 0; +#endif /* HIDDEN */ +} + +void +qsem_free( qsemh_t qsemh ) +{ +#ifdef HIDDEN + usema_t *usemap = ( usema_t * )qsemh; + + /* sanity checks + */ + ASSERT( qlock_inited ); + ASSERT( qlock_usp ); + + /* free the us semaphore + */ + usfreesema( usemap, qlock_usp ); +#endif /* HIDDEN */ +} + +void +qsemP( qsemh_t qsemh ) +{ +#ifdef HIDDEN + usema_t *usemap = ( usema_t * )qsemh; + intgen_t rval; + + /* sanity checks + */ + ASSERT( qlock_inited ); + ASSERT( qlock_usp ); + + /* "P" the semaphore + */ + rval = uspsema( usemap ); + if ( rval != 1 ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_NOLOCK, + "unable to \"P\" semaphore: " + "rval == %d, errno == %d (%s)\n", + rval, + errno, + strerror( errno )); + } + ASSERT( rval == 1 ); +#endif /* HIDDEN */ +} + +void +qsemV( qsemh_t qsemh ) +{ +#ifdef HIDDEN + usema_t *usemap = ( usema_t * )qsemh; + intgen_t rval; + + /* sanity checks + */ + ASSERT( qlock_inited ); + ASSERT( qlock_usp ); + + /* "V" the semaphore + */ + rval = usvsema( usemap ); + if ( rval != 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_NOLOCK, + "unable to \"V\" semaphore: " + "rval == %d, errno == %d (%s)\n", + rval, + errno, + strerror( errno )); + } + ASSERT( rval == 0 ); +#endif /* HIDDEN */ +} + +bool_t +qsemPwouldblock( qsemh_t qsemh ) +{ +#ifdef HIDDEN + usema_t *usemap = ( usema_t * )qsemh; + intgen_t rval; + + /* sanity checks + */ + ASSERT( qlock_inited ); + ASSERT( qlock_usp ); + + /* check the semaphore + */ + rval = ustestsema( usemap ); + + /* if equal to zero, no tokens left. if less than zero, other thread(s) + * currently waiting. + */ + if ( rval <= 0 ) { + return BOOL_TRUE; + } else { + return BOOL_FALSE; + } +#else +return BOOL_FALSE; +#endif /* HIDDEN */ +} + +size_t +qsemPavail( qsemh_t qsemh ) +{ +#ifdef HIDDEN + usema_t *usemap = ( usema_t * )qsemh; + intgen_t rval; + + /* sanity checks + */ + ASSERT( qlock_inited ); + ASSERT( qlock_usp ); + + /* check the semaphore + */ + rval = ustestsema( usemap ); + + /* if greater or equal to zero, no one is blocked and that is the number + * of resources available. if less than zero, absolute value is the + * number of blocked threads. + */ + if ( rval < 0 ) { + return 0; + } else { + return ( size_t )rval; + } +#else +return 0; +#endif /* HIDDEN */ +} + +size_t +qsemPblocked( qsemh_t qsemh ) +{ +#ifdef HIDDEN + usema_t *usemap = ( usema_t * )qsemh; + intgen_t rval; + + /* sanity checks + */ + ASSERT( qlock_inited ); + ASSERT( qlock_usp ); + + /* check the semaphore + */ + rval = ustestsema( usemap ); + + /* if greater or equal to zero, no one is blocked. if less than zero, + * absolute value is the number of blocked threads. + */ + if ( rval < 0 ) { + return ( size_t )( 0 - rval ); + } else { + return 0; + } +#else +return 0; +#endif /* HIDDEN */ +} + +qbarrierh_t +qbarrier_alloc( void ) +{ +#ifdef HIDDEN + barrier_t *barrierp; + + /* sanity checks + */ + ASSERT( qlock_inited ); + ASSERT( qlock_usp ); + + /* allocate a us barrier + */ + barrierp = new_barrier( qlock_usp ); + ASSERT( barrierp ); + + return ( qbarrierh_t )barrierp; +#else +return 0; +#endif /* HIDDEN */ +} + +void +qbarrier( qbarrierh_t qbarrierh, size_t thrdcnt ) +{ +#ifdef HIDDEN + barrier_t *barrierp = ( barrier_t * )qbarrierh; + + /* sanity checks + */ + ASSERT( qlock_inited ); + ASSERT( qlock_usp ); + + barrier( barrierp, thrdcnt ); +#endif /* HIDDEN */ +} + +/* internal ordinal map abstraction + */ +#ifdef HIDDEN +static void +qlock_ordmap_add( pid_t pid ) +{ + ASSERT( qlock_thrdcnt < QLOCK_THRDCNTMAX ); + qlock_thrddesc[ qlock_thrdcnt ].td_pid = pid; + qlock_thrddesc[ qlock_thrdcnt ].td_ordmap = 0; + qlock_thrdcnt++; +} + +static thrddesc_t * +qlock_thrddesc_get( pid_t pid ) +{ + thrddesc_t *p; + thrddesc_t *endp; + + for ( p = &qlock_thrddesc[ 0 ], + endp = &qlock_thrddesc[ qlock_thrdcnt ] + ; + p < endp + ; + p++ ) { + if ( p->td_pid == pid ) { + return p; + } + } + + ASSERT( 0 ); + return 0; +} + +static ordmap_t * +qlock_ordmapp_get( pid_t pid ) +{ + thrddesc_t *p; + p = qlock_thrddesc_get( pid ); + return &p->td_ordmap; +} + +static ix_t +qlock_thrdix_get( pid_t pid ) +{ + thrddesc_t *p; + p = qlock_thrddesc_get( pid ); + ASSERT( p >= &qlock_thrddesc[ 0 ] ); + return ( ix_t )( p - &qlock_thrddesc[ 0 ] ); +} +#endif diff -rNu linux-2.4.7/cmd/xfsdump/common/qlock.h linux-2.4-xfs/cmd/xfsdump/common/qlock.h --- linux-2.4.7/cmd/xfsdump/common/qlock.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/qlock.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef QLOCK_H +#define QLOCK_H + +/* qlock - quick locks abstraction + * + * threads may allocate quick locks using qlock_alloc, and free them with + * qlock_free. the abstraction is initialized with qlock_init. the underlying + * mechanism is the IRIX us lock primitive. in order to use this, a temporary + * shared arena is created in /tmp. this will be automatically unlinked + * when the last thread exits. + * + * deadlock detection is accomplished by giving an ordinal number to each + * lock allocated, and record all locks held by each thread. locks may not + * be acquired out of order. that is, subsequently acquired locks must have + * a lower ordinal than all locks currently held. for convenience, the ordinals + * of all locks to be allocated will be defined in this file. + * + * ADDITION: added counting semaphores. simpler to do here since same + * shared arena can be used. + */ + +#define QLOCK_ORD_CRIT 0 + /* ordinal for global critical region lock + */ +#define QLOCK_ORD_WIN 1 + /* ordinal for win abstraction critical regions + */ +#define QLOCK_ORD_PI 2 + /* ordinal for persistent inventory abstraction critical regions + */ +#define QLOCK_ORD_MLOG 3 + /* ordinal for mlog lock + */ + +typedef void *qlockh_t; +#define QLOCKH_NULL 0 + /* opaque handle + */ + +extern bool_t qlock_init( bool_t miniroot ); + /* called by main to initialize abstraction. returns FALSE if + * utility should abort. + */ + +extern bool_t qlock_thrdinit( void ); + /* called by each thread to prepare it for participation + */ + +extern qlockh_t qlock_alloc( ix_t ord ); + /* allocates a qlock with the specified ordinal. returns + * NULL if lock can't be allocated. + */ +extern void qlock_lock( qlockh_t qlockh ); + /* acquires the specified lock. + */ +extern void qlock_unlock( qlockh_t qlockh ); + /* releases the specified lock. + */ + +typedef void *qsemh_t; +#define QSEMH_NULL 0 + /* opaque handle + */ + +extern qsemh_t qsem_alloc( size_t cnt ); + /* allocates a counting semaphore initialized to the specified + * count. returns a qsem handle + */ +extern void qsem_free( qsemh_t qsemh ); + /* frees the counting semaphore + */ +extern void qsemP( qsemh_t qsemh ); + /* "P" (decrement) op + */ +extern void qsemV( qsemh_t qsemh ); + /* "V" (increment) op + */ +extern bool_t qsemPwouldblock( qsemh_t qsemh ); + /* returns true if a qsemP op would block + */ +extern size_t qsemPavail( qsemh_t qsemh ); + /* number of resources available + */ +extern size_t qsemPblocked( qsemh_t qsemh ); + /* number of threads currently blocked on this semaphore + */ + +typedef void *qbarrierh_t; +#define QBARRIERH_NULL 0 + /* opaque handle + */ +extern qbarrierh_t qbarrier_alloc( void ); + /* allocates a rendezvous barrier + */ +extern void qbarrier( qbarrierh_t barrierh, size_t thrdcnt ); + /* causes thrdcnt threads to rendezvous + */ + +#endif /* QLOCK_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/rec_hdr.h linux-2.4-xfs/cmd/xfsdump/common/rec_hdr.h --- linux-2.4.7/cmd/xfsdump/common/rec_hdr.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/rec_hdr.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef REC_HDR_H +#define REC_HDR_H + + +/* this is the drive-specific portion of the drive header defined + * in drive.h (dh_specific). the first record in a media file begins + * with a global_hdr_t with this embedded in dh_specific. all subsequent + * records begin with one of these. note that the first page (STAPE_HDR_SZ) + * bytes are always reserved for the header; the user data begins at + * record offset STAPE_HDR_SZ. Note also that the first record of each + * media file is unused except for the header; user data begins STAPE_HDR_SZ + * bytes into the second record. + */ + +/* + * This structure is used by both drive_minrmt and drive_scsi. New + * strategies should define their own here if they need a different + * structure, and add a endian conversion function to arch_xlate.c + */ +struct rec_hdr { + u_int64_t magic; /* 8 8 */ + /* magic number STAPE_MAGIC (see above) + */ + int32_t version; /* 4 c */ + /* version number STAPE_VERSION (see above) + */ + int32_t blksize; /* 4 10 */ + /* size of tape block in bytes + */ + int32_t recsize; /* 4 14 */ + /* size of this record in bytes, including 4k header + */ + int32_t capability; /* 4 18 */ + /* tape drive capabilities (from drive.h) + */ + char pad1[ 8 ]; /* 8 20 */ + /* padding + */ + off64_t file_offset; /* 8 28 */ + /* this record's byte offset into the media file. + * raw, includes header. + */ + off64_t first_mark_offset; /* 8 30 */ + /* raw media file byte offset of first mark set + * in this record. set to -1 if no marks in record + */ + u_int32_t rec_used; /* 4 34 */ + /* portion of record containing user data plus rec hdr (bytes). + * normally set to record size. last record written may + * indicate smaller value. includes record header. + */ + int32_t checksum; /* 4 38 */ + + int32_t ischecksum; /* 4 3c */ + + uuid_t dump_uuid; /* 10 4c */ + + char pad2[ 0x1b4 ]; /* 1b4 200 */ +}; /* pad to sizeof drive_hdr_t dh_specific */ + +typedef struct rec_hdr rec_hdr_t; + +#endif /* REC_HDR_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/ring.c linux-2.4-xfs/cmd/xfsdump/common/ring.c --- linux-2.4.7/cmd/xfsdump/common/ring.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/ring.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "qlock.h" +#include "ring.h" + +static int ring_slave_entry( void *ringctxp ); + +ring_t * +ring_create( size_t ringlen, + size_t bufsz, + bool_t pinpr, + void ( *threadfunc )( void *clientctxp, + int ( * entry )( void *ringctxp ), + void *ringctxp ), + int ( *readfunc )( void *clientctxp, char *bufp ), + int ( *writefunc )( void *clientctxp, char *bufp ), + void *clientctxp, + intgen_t *rvalp ) +{ + ring_t *ringp; + size_t mix; + + /* pre-initialize return value + */ + *rvalp = 0; + + /* allocate a ring descriptor + */ + ringp = ( ring_t * )calloc( 1, sizeof( ring_t )); + ASSERT( ringp ); + ringp->r_len = ringlen; + ringp->r_clientctxp = clientctxp; + ringp->r_readfunc = readfunc; + ringp->r_writefunc = writefunc; + + /* allocate counting semaphores for the ready and active queues, + * and initialize the queue input and output indices. + */ + ringp->r_ready_qsemh = qsem_alloc( ringlen ); + ringp->r_active_qsemh = qsem_alloc( 0 ); + ringp->r_ready_in_ix = 0; + ringp->r_ready_out_ix = 0; + ringp->r_active_in_ix = 0; + ringp->r_active_out_ix = 0; + ringp->r_client_cnt = 0; + ringp->r_slave_cnt = 0; + + /* initialize the meters + */ + ringp->r_client_msgcnt = 0; + ringp->r_slave_msgcnt = 0; + ringp->r_client_blkcnt = 0; + ringp->r_slave_blkcnt = 0; + ringp->r_first_io_time = 0; + ringp->r_all_io_cnt = 0; + + /* allocate the ring messages + */ + ringp->r_msgp = ( ring_msg_t * )calloc( ringlen, sizeof( ring_msg_t )); + ASSERT( ringp->r_msgp ); + + /* allocate the buffers and initialize the messages + */ + for ( mix = 0 ; mix < ringlen ; mix++ ) { + ring_msg_t *msgp = &ringp->r_msgp[ mix ]; + msgp->rm_mix = mix; + msgp->rm_op = RING_OP_NONE; + msgp->rm_stat = RING_STAT_INIT; + msgp->rm_user = 0; + msgp->rm_loc = RING_LOC_READY; + + msgp->rm_bufp = ( char * )memalign( PGSZ, bufsz ); + if ( ! msgp->rm_bufp ) { + *rvalp = ENOMEM; + return 0; + } + if ( pinpr ) { + intgen_t rval; + rval = mlock( ( void * )msgp->rm_bufp, bufsz ); + if ( rval ) { + if ( errno == ENOMEM ) { + *rvalp = E2BIG; + return 0; + } + if ( errno == EPERM ) { + *rvalp = EPERM; + return 0; + } + ASSERT( 0 ); + } + } + } + + /* kick off the slave thread + */ + ( *threadfunc )( clientctxp, ring_slave_entry, ( void * )ringp ); + + return ringp; +} + +ring_msg_t * +ring_get( ring_t *ringp ) +{ + ring_msg_t *msgp; + + /* assert client currently holds no messages + */ + ASSERT( ringp->r_client_cnt == 0 ); + + /* bump client message count and note if client needs to block + */ + ringp->r_client_msgcnt++; + if ( qsemPwouldblock( ringp->r_ready_qsemh )) { + ringp->r_client_blkcnt++; + } + + /* block until msg available on ready queue ("P") + */ + qsemP( ringp->r_ready_qsemh ); + + /* get a pointer to the next msg on the queue + */ + msgp = &ringp->r_msgp[ ringp->r_ready_out_ix ]; + + /* assert the message is where it belongs + */ + ASSERT( msgp->rm_loc == RING_LOC_READY ); + + /* verify the message index has not become corrupted + */ + ASSERT( msgp->rm_mix == ringp->r_ready_out_ix ); + + /* bump the output index + */ + ringp->r_ready_out_ix = ( ringp->r_ready_out_ix + 1 ) + % + ringp->r_len; + + /* update the message location + */ + msgp->rm_loc = RING_LOC_CLIENT; + + /* bump the count of messages held by the client + */ + ringp->r_client_cnt++; + + /* return the msg to the client + */ + return msgp; +} + +void +ring_put( ring_t *ringp, ring_msg_t *msgp ) +{ + /* assert the client holds exactly one message + */ + ASSERT( ringp->r_client_cnt == 1 ); + + /* assert the client is returning the right message + */ + ASSERT( msgp->rm_mix == ringp->r_active_in_ix ); + + /* assert the message is where it belongs + */ + ASSERT( msgp->rm_loc == RING_LOC_CLIENT ); + + /* decrement the count of messages held by the client + */ + ringp->r_client_cnt--; + + /* update the message location + */ + msgp->rm_loc = RING_LOC_ACTIVE; + + /* bump the active queue input ix + */ + ringp->r_active_in_ix = ( ringp->r_active_in_ix + 1 ) + % + ringp->r_len; + + /* bump the semaphore for the active queue ("V") + */ + qsemV( ringp->r_active_qsemh ); +} + +void +ring_reset( ring_t *ringp, ring_msg_t *msgp ) +{ + size_t mix; + + /* if the client is not holding a message, get the next message + */ + if ( ringp->r_client_cnt == 0 ) { + ASSERT( ! msgp ); + msgp = ring_get( ringp ); + ASSERT( msgp ); + ASSERT( ringp->r_client_cnt == 1 ); + } else { + ASSERT( msgp ); + ASSERT( ringp->r_client_cnt == 1 ); + } + + /* tell the slave to abort + */ + msgp->rm_op = RING_OP_RESET; + ring_put( ringp, msgp ); + + /* wait for the reset to be acknowledged + */ + ASSERT( ringp->r_client_cnt == 0 ); + do { + /* pull a message from the ready queue + */ + qsemP( ringp->r_ready_qsemh ); + msgp = &ringp->r_msgp[ ringp->r_ready_out_ix ]; + ASSERT( msgp->rm_loc == RING_LOC_READY ); + ringp->r_ready_out_ix = ( ringp->r_ready_out_ix + 1 ) + % + ringp->r_len; + ringp->r_client_cnt++; + } while ( msgp->rm_stat != RING_STAT_RESETACK ); + ASSERT( ringp->r_client_cnt == ringp->r_len ); + + /* re-initialize the ring + */ + ASSERT( qsemPavail( ringp->r_ready_qsemh ) == 0 ); + ASSERT( qsemPblocked( ringp->r_ready_qsemh ) == 0 ); + ASSERT( qsemPavail( ringp->r_active_qsemh ) == 0 ); + ASSERT( qsemPblocked( ringp->r_active_qsemh ) <= 1 ); + ringp->r_ready_in_ix = 0; + ringp->r_ready_out_ix = 0; + ringp->r_active_in_ix = 0; + ringp->r_active_out_ix = 0; + ringp->r_client_cnt = 0; + ringp->r_slave_cnt = 0; + for ( mix = 0 ; mix < ringp->r_len ; mix++ ) { + ring_msg_t *msgp = &ringp->r_msgp[ mix ]; + msgp->rm_mix = mix; + msgp->rm_op = RING_OP_NONE; + msgp->rm_stat = RING_STAT_INIT; + msgp->rm_user = 0; + msgp->rm_loc = RING_LOC_READY; + qsemV( ringp->r_ready_qsemh ); + } + ASSERT( qsemPavail( ringp->r_ready_qsemh ) == ringp->r_len ); + ASSERT( qsemPblocked( ringp->r_ready_qsemh ) == 0 ); + ASSERT( qsemPavail( ringp->r_active_qsemh ) == 0 ); + ASSERT( qsemPblocked( ringp->r_active_qsemh ) <= 1 ); +} + +void +ring_destroy( ring_t *ringp ) +{ + ring_msg_t *msgp; + + /* the client must not be holding a message + */ + ASSERT( ringp->r_client_cnt == 0 ); + + /* get a message + */ + msgp = ring_get( ringp ); + + /* tell the slave to exit + */ + msgp->rm_op = RING_OP_DIE; + ring_put( ringp, msgp ); + + /* wait for the die to be acknowledged + */ + do { + /* pull a message from the ready queue + */ + qsemP( ringp->r_ready_qsemh ); + msgp = &ringp->r_msgp[ ringp->r_ready_out_ix ]; + ASSERT( msgp->rm_loc == RING_LOC_READY ); + ringp->r_ready_out_ix = ( ringp->r_ready_out_ix + 1 ) + % + ringp->r_len; + } while ( msgp->rm_stat != RING_STAT_DIEACK ); + + /* the slave is dead. + */ + qsem_free( ringp->r_ready_qsemh ); + qsem_free( ringp->r_active_qsemh ); + free( ( void * )ringp ); +} + + +static ring_msg_t * +ring_slave_get( ring_t *ringp ) +{ + ring_msg_t *msgp; + + /* assert slave currently holds no messages + */ + ASSERT( ringp->r_slave_cnt == 0 ); + + /* bump slave message count and note if slave needs to block + */ + ringp->r_slave_msgcnt++; + if ( qsemPwouldblock( ringp->r_active_qsemh )) { + ringp->r_slave_blkcnt++; + } + + /* block until msg available on active queue ("P") + */ + qsemP( ringp->r_active_qsemh ); + + /* get a pointer to the next msg on the queue + */ + msgp = &ringp->r_msgp[ ringp->r_active_out_ix ]; + + /* assert the message is where it belongs + */ + ASSERT( msgp->rm_loc == RING_LOC_ACTIVE ); + + /* verify the message index has not become corrupted + */ + ASSERT( msgp->rm_mix == ringp->r_active_out_ix ); + + /* bump the output index + */ + ringp->r_active_out_ix = ( ringp->r_active_out_ix + 1 ) + % + ringp->r_len; + + /* update the message location + */ + msgp->rm_loc = RING_LOC_SLAVE; + + /* bump the count of messages held by the slave + */ + ringp->r_slave_cnt++; + + /* return the msg to the slave + */ + return msgp; +} + +static void +ring_slave_put( ring_t *ringp, ring_msg_t *msgp ) +{ + /* assert the slave holds exactly one message + */ + ASSERT( ringp->r_slave_cnt == 1 ); + + /* assert the slave is returning the right message + */ + ASSERT( msgp->rm_mix == ringp->r_ready_in_ix ); + + /* assert the message is where it belongs + */ + ASSERT( msgp->rm_loc == RING_LOC_SLAVE ); + + /* decrement the count of messages held by the slave + */ + ringp->r_slave_cnt--; + + /* update the message location + */ + msgp->rm_loc = RING_LOC_READY; + + /* bump the ready queue input ix + */ + ringp->r_ready_in_ix = ( ringp->r_ready_in_ix + 1 ) + % + ringp->r_len; + + /* bump the semaphore for the ready queue ("V") + */ + qsemV( ringp->r_ready_qsemh ); +} + +static int +ring_slave_entry( void *ringctxp ) +{ + ring_t *ringp = ( ring_t * )ringctxp; + enum { LOOPMODE_NORMAL, LOOPMODE_IGNORE, LOOPMODE_DIE } loopmode; + + /* ignore signals + */ + sigset( SIGHUP, SIG_IGN ); + sigset( SIGINT, SIG_IGN ); + sigset( SIGQUIT, SIG_IGN ); + sigset( SIGPIPE, SIG_IGN ); + sigset( SIGALRM, SIG_IGN ); + sigset( SIGCLD, SIG_IGN ); + + /* record slave pid to be used to kill slave + */ + ringp->r_slavepid = getpid( ); + + /* loop reading and precessing messages until told to die + */ + for ( loopmode = LOOPMODE_NORMAL ; loopmode != LOOPMODE_DIE ; ) { + ring_msg_t *msgp; + int rval; + + msgp = ring_slave_get( ringp ); + msgp->rm_rval = 0; + + switch( msgp->rm_op ) { + case RING_OP_READ: + if ( loopmode == LOOPMODE_IGNORE ) { + msgp->rm_stat = RING_STAT_IGNORE; + break; + } + if ( ! ringp->r_first_io_time ) { + ringp->r_first_io_time = time( 0 ); + ASSERT( ringp->r_first_io_time ); + } + rval = ( ringp->r_readfunc )( ringp->r_clientctxp, + msgp->rm_bufp ); + msgp->rm_rval = rval; + ringp->r_all_io_cnt++; + if ( msgp->rm_rval == 0 ) { + msgp->rm_stat = RING_STAT_OK; + } else { + msgp->rm_stat = RING_STAT_ERROR; + loopmode = LOOPMODE_IGNORE; + } + break; + case RING_OP_WRITE: + if ( loopmode == LOOPMODE_IGNORE ) { + msgp->rm_stat = RING_STAT_IGNORE; + break; + } + if ( ! ringp->r_first_io_time ) { + ringp->r_first_io_time = time( 0 ); + ASSERT( ringp->r_first_io_time ); + } + rval = ( ringp->r_writefunc )( ringp->r_clientctxp, + msgp->rm_bufp ); + msgp->rm_rval = rval; + ringp->r_all_io_cnt++; + if ( msgp->rm_rval == 0 ) { + msgp->rm_stat = RING_STAT_OK; + } else { + msgp->rm_stat = RING_STAT_ERROR; + loopmode = LOOPMODE_IGNORE; + } + break; + case RING_OP_NOP: + msgp->rm_stat = RING_STAT_NOPACK; + break; + case RING_OP_TRACE: + msgp->rm_stat = RING_STAT_IGNORE; + break; + case RING_OP_RESET: + loopmode = LOOPMODE_NORMAL; + msgp->rm_stat = RING_STAT_RESETACK; + break; + case RING_OP_DIE: + msgp->rm_stat = RING_STAT_DIEACK; + loopmode = LOOPMODE_DIE; + break; + default: + msgp->rm_stat = RING_STAT_IGNORE; + break; + } + ring_slave_put( ringp, msgp ); + } + + exit( 0 ); +} diff -rNu linux-2.4.7/cmd/xfsdump/common/ring.h linux-2.4-xfs/cmd/xfsdump/common/ring.h --- linux-2.4.7/cmd/xfsdump/common/ring.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/ring.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef RING_H +#define RING_H + +/* ring - readahead/writeahead abstraction + * + * the ring is conceptually an ordered set of messages circulating between the + * client thread and the I/O slave thread. a message can be in one of four + * places: on the ready queue, held by the client, on the active queue, or held + * by the slave. The client and slave can each hold at most one message at a + * time. all others must be on one of the two queues. the messages must + * circulate in that order: ready, client, active, slave, ready, ... + * initially all messages are on the ready queue, with status set to + * INIT. The client uses ring_get to remove a message from the ready queue. + * the client can then use the message to read or write. to read, the client + * sets the op field to READ, and places the message on the active queue. the + * slave will remove messages from the active queue, invoke the client-supplied + * read function with the message's buffer, record the read function's return + * value in the message, set the message status to OK (read function returned 0) + * or ERROR (read returned non-zero), and place the message on the ready queue. + * the client will see the message after removing all messages ahead of it on + * the ready queue. to write, the client follows almost the same procedure, + * except the client fills the buffer and sets the op to WRITE prior to placing + * the message on the active queue. + * + * if the client-supplied read or write function returns an error, the slave + * will set the message status to ERROR. the slave will pass all subsequent + * messages appearing on the active queue directly to the ready queue with + * no I/O done and the message status set to IGNORE. the slave will remain + * in this state until a reset is performed (see below). + * + * The client may at anytime place a NOP msg on the ring. the slave does + * nothing with this mmessage other than to place it back on the ready queue + * with NOPACK status. This is useful for inhibiting read-ahead. + * + * To flush the ring, the client must repetatively place TRACE messages on the + * active queue until it sees an IGNORE msg on the ready queue. the slave will + * simply transfer TRACErs from active to ready with no other action taken + * (other than to set the message status to IGNORE). + * + * the client may at any time reset the ring. the reset will return to the + * client when the current I/O being executed by the slave completes, and + * all messages have been wiped clean and placed on the ready queue with + * status set to INIT. the ring_reset function accomplishes this internally by + * placing a RESET message on the active QUEUE, and continuing to remove + * messages from the ready queue (without placing them on the active queue) + * until the RESET message is seen the slave responds to a reset message by + * setting the status to RESETACK, queueing the message on the ready queue, and + * waiting for a message from the active queue. ring_reset will then re- + * initialize the ring and return. note that the client may be holding one + * message at the time the reset is called. if so, it must pass a pointer to + * that message into the reset call. otherwise it must pass in NULL. + * + * the ring_destroy function may be invoked to shut down the ring and kill the + * slave thread. it simply places a DIE message on the active queue, and waits + * for a DIEACK response. it then de-allocates all semaphores memory allocated + * by ring_create. + * + * the message structure includes a 64 bit field for the convenience + * of the client. it is not perturbed during any ring operations. + * + * the ring maintains four performance metering values: the number of times + * the slave and client attempted to get a message, and the number of times + * those attempts resulting in blocking. + */ + + +/* ring_msg - structure of messages managed by ring + */ +enum ring_op { RING_OP_NONE, + RING_OP_READ, + RING_OP_WRITE, + RING_OP_NOP, + RING_OP_TRACE, + RING_OP_RESET, + RING_OP_DIE }; + +typedef enum ring_op ring_op_t; + +enum ring_stat { RING_STAT_INIT, + RING_STAT_OK, + RING_STAT_ERROR, + RING_STAT_NOPACK, + RING_STAT_IGNORE, + RING_STAT_RESETACK, + RING_STAT_DIEACK }; + +typedef enum ring_stat ring_stat_t; + +enum ring_loc { RING_LOC_READY, + RING_LOC_ACTIVE, + RING_LOC_CLIENT, + RING_LOC_SLAVE }; + +typedef enum ring_loc ring_loc_t; + +struct ring_msg { + ring_op_t rm_op; + ring_stat_t rm_stat; + intgen_t rm_rval; + off64_t rm_user; + char *rm_bufp; +/* ALL BELOW PRIVATE!!! */ + size_t rm_mix; + ring_loc_t rm_loc; +}; + +typedef struct ring_msg ring_msg_t; + + +/* ring - instantiation of a ring + */ +struct ring { + off64_t r_client_msgcnt; + off64_t r_slave_msgcnt; + off64_t r_client_blkcnt; + off64_t r_slave_blkcnt; + time_t r_first_io_time; + off64_t r_all_io_cnt; +/* ALL BELOW PRIVATE!!! */ + pid_t r_slavepid; + size_t r_len; + ring_msg_t *r_msgp; + size_t r_ready_in_ix; + size_t r_ready_out_ix; + qsemh_t r_ready_qsemh; + size_t r_active_in_ix; + size_t r_active_out_ix; + qsemh_t r_active_qsemh; + size_t r_client_cnt; + size_t r_slave_cnt; + int ( *r_readfunc )( void *contextp, char *bufp ); + int ( *r_writefunc )( void *contextp, char *bufp ); + void *r_clientctxp; +}; + +typedef struct ring ring_t; + + +/* ring_create - creates a ring. parameters supply the length of the ring, + * the read/write buffer size, a function for creating a thread, a function + * for reading, a function for writing, and a pointer to client context for the + * read and write functions. returns a pointer to a ring if successful, a NULL + * pointer if not. the read and write functions should return 0 on success, + * or an error code on failure which will be recorded in the rm_rval field + * of the message invoking the failed operation. if null pointer returned, + * the location pointed to by rvalp will contain one of the following: + * ENOMEM - could not allocate some portion of the ring memory; + * E2BIG - insufficient physical memory available for pinning; + * EPERM - exceeds allowed amount of pinned down memory. + */ +extern ring_t *ring_create( size_t ringlen, + size_t bufsz, + bool_t pinpr, + void ( * threadfunc )( void *clientctxp, + int ( * entryp )( void *ringctxp ), + void *ringctxp ), + int ( * readfunc )( void *clientctxp, char *bufp ), + int ( * writefunc )( void *clientctxp, char *bufp ), + void *clientctxp, + intgen_t *rvalp ); + + +/* ring_get - get a message off the ready queue + */ +extern ring_msg_t *ring_get( ring_t *ringp ); + + +/* ring_put - put a message on the active queue + */ +extern void ring_put( ring_t *ringp, ring_msg_t *msgp ); + + +/* ring_reset - re-initialize the ring, after the current I/O completes. + * msgp must be NULL if the client is not currently holding a ring message. + * otherwise it must point to that message. + */ +extern void ring_reset( ring_t *ringp, ring_msg_t *msgp ); + +/* ring_destroy - de-allocates ring + */ +extern void ring_destroy( ring_t *ringp ); + +#endif /* RING_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/sproc.c linux-2.4-xfs/cmd/xfsdump/common/sproc.c --- linux-2.4.7/cmd/xfsdump/common/sproc.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/sproc.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include + +#define STACKSIZE 65536 + +int +sproc (int (*entry) (void *), int flags, void *arg) +{ + int retval = -1; +#ifdef HIDDEN + void *newstack; + + if ( (newstack = calloc (1, STACKSIZE)) != NULL ) { + void ** stackp = ((void **)newstack)+(STACKSIZE -1)/sizeof(void*); + + flags |= SIGCHLD; + + retval = clone (entry, stackp, flags, arg); + } +#endif + + return retval; +} diff -rNu linux-2.4.7/cmd/xfsdump/common/sproc.h linux-2.4-xfs/cmd/xfsdump/common/sproc.h --- linux-2.4.7/cmd/xfsdump/common/sproc.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/sproc.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef SPROC_H +#define SPROC_H + +int sproc (int (*) (void *), int, void *); + +#endif /* SPROC_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/stkchk.c linux-2.4-xfs/cmd/xfsdump/common/stkchk.c --- linux-2.4.7/cmd/xfsdump/common/stkchk.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/stkchk.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#include +#include + +#include +#include +#include +#include + +#include "types.h" +#include "mlog.h" + +#define STACKFUDGE ( 8 * pgsz ) +#define STACKMARGIN ( 8 * pgsz ) + +struct stkchk { + pid_t sc_pid; + char *sc_initsp; + char *sc_minsp; + int sc_sz; +}; + +typedef struct stkchk stkchk_t; + +/* REFERENCED */ +static size_t stkchk_pidcntmax = 0; + +static stkchk_t *stkchk_list; + +static size_t stkchk_pidcnt = 0; + +static int get_stacksz( void ); + +extern size_t pgsz; + +void +stkchk_init( size_t maxpidcnt ) +{ + ASSERT( maxpidcnt > 0 ); + ASSERT( stkchk_pidcntmax == 0 ); + stkchk_list = ( stkchk_t * )calloc( maxpidcnt, sizeof( stkchk_t )); + ASSERT( stkchk_list ); + stkchk_pidcntmax = maxpidcnt; + ASSERT( stkchk_pidcnt == 0 ); +} + +void +stkchk_register( void ) +{ + char dummy; + pid_t pid; + stkchk_t *stkchkp; + + ASSERT( stkchk_pidcntmax ); + pid = getpid( ); + ASSERT( stkchk_pidcnt < stkchk_pidcntmax ); + stkchkp = &stkchk_list[ stkchk_pidcnt++ ]; + stkchkp->sc_pid = getpid( ); + stkchkp->sc_initsp = &dummy; + stkchkp->sc_sz = get_stacksz( ); + ASSERT( stkchkp->sc_initsp >= (char *)stkchkp->sc_sz ); + stkchkp->sc_minsp = stkchkp->sc_initsp - stkchkp->sc_sz; + mlog( MLOG_DEBUG | MLOG_PROC, + "stack pid %u: " + "sz 0x%lx min 0x%lx max 0x%lx\n", + pid, + stkchkp->sc_sz, + stkchkp->sc_minsp, + stkchkp->sc_initsp ); +} + +int +stkchk( void ) +{ + char dummy = 1; /* keep lint happy */ + pid_t pid; + size_t pidix; + stkchk_t *stkchkp = NULL; + + ASSERT( stkchk_pidcntmax ); + pid = getpid( ); + + for ( pidix = 0 ; pidix < stkchk_pidcnt ; pidix++ ) { + stkchkp = &stkchk_list[ pidix ]; + if ( stkchkp->sc_pid == pid ) { + break; + } + } + ASSERT( pidix < stkchk_pidcnt ); + + if ( &dummy > stkchkp->sc_initsp ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_PROC, + "stack underrun pid %d " + "sp 0x%lx min 0x%lx max 0x%lx\n", + pid, + &dummy, + stkchkp->sc_minsp, + stkchkp->sc_initsp ); + return 3; + } else if ( &dummy < stkchkp->sc_minsp + STACKFUDGE ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_PROC, + "stack overrun pid %d " + "sp 0x%lx min 0x%lx max 0x%lx\n", + pid, + &dummy, + stkchkp->sc_minsp, + stkchkp->sc_initsp ); + return 2; + } else if ( &dummy < stkchkp->sc_minsp + STACKFUDGE + STACKMARGIN ) { + mlog( MLOG_VERBOSE | MLOG_WARNING | MLOG_PROC, + "stack near overrun pid %d " + "sp 0x%lx min 0x%lx max 0x%lx\n", + pid, + &dummy, + stkchkp->sc_minsp, + stkchkp->sc_initsp ); + return 1; + } + + mlog( MLOG_DEBUG | MLOG_PROC, + "stack ok pid %d " + "sp 0x%lx min 0x%lx max 0x%lx\n", + pid, + &dummy, + stkchkp->sc_minsp, + stkchkp->sc_initsp ); + return 0; +} + +static int +get_stacksz( void ) +{ + struct rlimit rlimit; + /* REFERENCED */ + intgen_t rval; + + rval = getrlimit( RLIMIT_STACK, &rlimit ); + ASSERT( ! rval ); + return rlimit.rlim_cur; +} diff -rNu linux-2.4.7/cmd/xfsdump/common/stkchk.h linux-2.4-xfs/cmd/xfsdump/common/stkchk.h --- linux-2.4.7/cmd/xfsdump/common/stkchk.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/stkchk.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef STKCHK_H +#define STKCHK_H + +/* initializes the abstraction. must tell it how many pids to expect + */ +extern void stkchk_init( size_t maxpidcnt ); + +/* each process which wants to make use of stack checking must register + * upon entry (main() or sproc entrypt). + */ +extern void stkchk_register( void ); + +/* called to validate the current stack pointer. + * returns 0 if ok, 1 if close, 2 if over, 3 if under. + */ +extern int stkchk( void ); + +#endif /* STKCHK_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/stream.c linux-2.4-xfs/cmd/xfsdump/common/stream.c --- linux-2.4.7/cmd/xfsdump/common/stream.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/stream.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include "types.h" +#include "stream.h" +#include "lock.h" + +#define PROCMAX ( STREAM_SIMMAX * 2 + 1 ) + +struct spm { + bool_t s_busy; + pid_t s_pid; + intgen_t s_ix; +}; + +typedef struct spm spm_t; + +static spm_t spm[ STREAM_SIMMAX * 3 ]; + +void +stream_init( void ) +{ +#ifdef HIDDEN + /* REFERENCED */ + intgen_t rval; + + rval = ( intgen_t )usconfig( CONF_INITUSERS, PROCMAX ); + ASSERT( rval >= 0 ); +#endif /* HIDDEN */ + + ( void )memset( ( void * )spm, 0, sizeof( spm )); + +} + +void +stream_register( pid_t pid, intgen_t streamix ) +{ + spm_t *p = spm; + spm_t *ep = spm + sizeof( spm ) / sizeof( spm[ 0 ] ); + + ASSERT( streamix < STREAM_SIMMAX ); + + lock( ); + for ( ; p < ep ; p++ ) { + if ( ! p->s_busy ) { + p->s_busy = BOOL_TRUE; + break; + } + } + unlock(); + + ASSERT( p < ep ); + if ( p >= ep ) return; + + p->s_pid = pid; + p->s_ix = streamix; +} + +void +stream_unregister( pid_t pid ) +{ + spm_t *p = spm; + spm_t *ep = spm + sizeof( spm ) / sizeof( spm[ 0 ] ); + + lock( ); + for ( ; p < ep ; p++ ) { + if ( p->s_pid == pid ) { + p->s_pid = 0; + p->s_ix = -1; + p->s_busy = BOOL_FALSE; + break; + } + } + unlock(); + + ASSERT( p < ep ); +} + +intgen_t +stream_getix( pid_t pid ) +{ + spm_t *p = spm; + spm_t *ep = spm + sizeof( spm ) / sizeof( spm[ 0 ] ); + + for ( ; p < ep ; p++ ) { + if ( p->s_pid == pid ) { + break; + } + } + + return ( p >= ep ) ? -1 : p->s_ix; +} + +size_t +stream_cnt( void ) +{ + spm_t *p = spm; + spm_t *ep = spm + sizeof( spm ) / sizeof( spm[ 0 ] ); + size_t ixmap = 0; + size_t ixcnt; + size_t bitix; + + ASSERT( sizeof( ixmap ) * NBBY >= STREAM_SIMMAX ); + + lock( ); + for ( ; p < ep ; p++ ) { + if ( p->s_busy ) { + ixmap |= ( size_t )1 << p->s_ix; + } + } + unlock(); + + ixcnt = 0; + for ( bitix = 0 ; bitix < STREAM_SIMMAX ; bitix++ ) { + if ( ixmap & ( ( size_t )1 << bitix )) { + ixcnt++; + } + } + + return ixcnt; +} diff -rNu linux-2.4.7/cmd/xfsdump/common/stream.h linux-2.4-xfs/cmd/xfsdump/common/stream.h --- linux-2.4.7/cmd/xfsdump/common/stream.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/stream.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef STREAM_H +#define STREAM_H + +/* stream.h definitions pertaining to the dump/restore streams + */ + +#define STREAM_SIMMAX 20 + /* maximum number of simultaneous streams. + */ + +/* stream exit codes + */ +#define STREAM_EXIT_SUCCESS 0 /* stream completed successfully */ +#define STREAM_EXIT_STOP 1 /* thread requests a stop */ +#define STREAM_EXIT_ABORT 2 /* thread requests an abort */ +#define STREAM_EXIT_CORE 3 /* thread requests a core dump */ + +extern void stream_init( void ); + +extern void stream_register( pid_t pid, intgen_t streamix ); + +extern void stream_unregister( pid_t pid ); + +extern intgen_t stream_getix( pid_t pid ); + +extern size_t stream_cnt( void ); + +#endif /* STREAM_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/types.h linux-2.4-xfs/cmd/xfsdump/common/types.h --- linux-2.4.7/cmd/xfsdump/common/types.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/types.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef TYPES_H +#define TYPES_H + +#define XFSDUMP_DIRPATH "/var/xfsdump" + +/* + * Should be, but isn't, defined in uuid/uuid.h + */ +#define UUID_STR_LEN 36 + +/* fundamental page size - probably should not be hardwired, but + * for now we will + */ +#define PGSZLOG2 12 +#define PGSZ ( 1 << PGSZLOG2 ) +#define PGMASK ( PGSZ - 1 ) + +/* integers + */ +typedef u_int32_t size32_t; +typedef u_int64_t size64_t; +typedef char char_t; +typedef unsigned char u_char_t; +typedef unsigned int u_intgen_t; +typedef long long_t; +typedef unsigned long u_long_t; +typedef size_t ix_t; + +/* limits + */ +#define MKMAX( t, s ) ( ( t ) \ + ( ( ( 1ull \ + << \ + ( ( unsigned long long )sizeof( t ) \ + * \ + ( unsigned long long )NBBY \ + - \ + ( s + 1ull ))) \ + - \ + 1ull ) \ + * \ + 2ull \ + + \ + 1ull )) +#define MKSMAX( t ) MKMAX( t, 1ull ) +#define MKUMAX( t ) MKMAX( t, 0ull ) +#define INT32MAX MKSMAX( int32_t ) +#define UINT32MAX MKUMAX( u_int32_t ) +#define SIZE32MAX MKUMAX( size32_t ) +#define INT64MAX MKSMAX( int64_t ) +#define UINT64MAX MKUMAX( u_int64_t ) +#define SIZE64MAX MKUMAX( size64_t ) +#define INO64MAX MKUMAX( xfs_ino_t ) +#define OFF64MAX MKSMAX( off64_t ) +#define INTGENMAX MKSMAX( intgen_t ) +#define UINTGENMAX MKUMAX( u_intgen_t ) +#define OFFMAX MKSMAX( off_t ) +#define SIZEMAX MKUMAX( size_t ) +#define IXMAX MKUMAX( size_t ) +#define INOMAX MKUMAX( ino_t ) +#define TIMEMAX MKSMAX( time_t ) +#define INT16MAX 0x7fff +#define UINT16MAX 0xffff + +/* boolean + */ +typedef int bool_t; +#define BOOL_TRUE 1 +#define BOOL_FALSE 0 +#define BOOL_UNKNOWN ( -1 ) +#define BOOL_ERROR ( -2 ) + +/* useful return code scheme + */ +typedef enum { RV_OK, /* mission accomplished */ + RV_NOTOK, /* request denied */ + RV_NOMORE, /* no more work to do */ + RV_EOD, /* ran out of data */ + RV_EOF, /* hit end of media file */ + RV_EOM, /* hit end of media object */ + RV_ERROR, /* operator error or resource exhaustion */ + RV_DONE, /* return early because someone else did work */ + RV_INTR, /* cldmgr_stop_requested( ) */ + RV_CORRUPT, /* stopped because corrupt data encountered */ + RV_QUIT, /* stop using resource */ + RV_DRIVE, /* drive quit working */ + RV_TIMEOUT, /* operation timed out */ + RV_MEDIA, /* no media object in drive */ + RV_WRITEPOTECTED,/* want to write but write-protected */ + RV_CORE /* really bad - dump core! */ +} rv_t; + +/* typedefs I'd like to see ... + */ +typedef struct getbmapx getbmapx_t; +typedef struct fsdmidata fsdmidata_t; + +#endif /* TYPES_H */ diff -rNu linux-2.4.7/cmd/xfsdump/common/util.c linux-2.4-xfs/cmd/xfsdump/common/util.c --- linux-2.4.7/cmd/xfsdump/common/util.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/util.c Mon Apr 2 22:57:58 2001 @@ -0,0 +1,582 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "util.h" +#include "mlog.h" +#include "getdents.h" + +extern size_t pgsz; + +intgen_t +write_buf( char *bufp, + size_t bufsz, + void *contextp, + gwbfp_t get_write_buf_funcp, + wfp_t write_funcp ) +{ + char *mbufp; /* buffer obtained from manager */ + size_t mbufsz;/* size of buffer obtained from manager */ + + while ( bufsz ) { + int rval; + + ASSERT( bufsz > 0 ); + mbufp = ( *get_write_buf_funcp )( contextp, bufsz, &mbufsz ); + ASSERT( mbufsz <= bufsz ); + if ( bufp ) { + (void)memcpy( ( void * )mbufp, ( void * )bufp, mbufsz ); + } else { + (void)memset( ( void * )mbufp, 0, mbufsz ); + } + rval = ( * write_funcp )( contextp, mbufp, mbufsz ); + if ( rval ) { + return rval; + } + if ( bufp ) { + bufp += mbufsz; + } + bufsz -= mbufsz; + } + + return 0; +} + +intgen_t +read_buf( char *bufp, + size_t bufsz, + void *contextp, + rfp_t read_funcp, + rrbfp_t return_read_buf_funcp, + intgen_t *statp ) +{ + char *mbufp; /* manager's buffer pointer */ + size_t mbufsz; /* size of manager's buffer */ + intgen_t nread; + + nread = 0; + *statp = 0; + while ( bufsz ) { + mbufp = ( * read_funcp )( contextp, bufsz, &mbufsz, statp ); + if ( *statp ) { + break; + } + ASSERT( mbufsz <= bufsz ); + if ( bufp ) { + ( void )memcpy( (void *)bufp, (void *)mbufp, mbufsz ); + bufp += mbufsz; + } + bufsz -= mbufsz; + nread += ( intgen_t )mbufsz; + ( * return_read_buf_funcp )( contextp, mbufp, mbufsz ); + } + + return nread; +} + +char +*strncpyterm( char *s1, char *s2, size_t n ) +{ + char *rval; + + if ( n < 1 ) return 0; + rval = strncpy( s1, s2, n ); + s1[ n - 1 ] = 0; + return rval; +} + +void +stat64_to_xfsbstat( xfs_bstat_t *dstp, struct stat64 *srcp ) +{ + memset( ( void * )dstp, 0, sizeof( *dstp )); + + dstp->bs_ino = srcp->st_ino; /* TODO XXX PORT */ + dstp->bs_mode = srcp->st_mode; + dstp->bs_nlink = srcp->st_nlink; + dstp->bs_uid = srcp->st_uid; + dstp->bs_gid = srcp->st_gid; + dstp->bs_rdev = srcp->st_rdev; + dstp->bs_blksize = ( int32_t )srcp->st_blksize; + dstp->bs_size = srcp->st_size; + dstp->bs_atime.tv_sec = srcp->st_atime; + dstp->bs_atime.tv_nsec = 0; + dstp->bs_mtime.tv_sec = srcp->st_mtime; + dstp->bs_mtime.tv_nsec = 0; + dstp->bs_ctime.tv_sec = srcp->st_ctime; + dstp->bs_ctime.tv_nsec = 0; + dstp->bs_blocks = srcp->st_blocks; +} + +intgen_t +bigstat_iter( jdm_fshandle_t *fshandlep, + intgen_t fsfd, + intgen_t selector, + xfs_ino_t start_ino, + intgen_t ( * fp )( void *arg1, + jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp ), + void * arg1, + intgen_t *statp, + bool_t ( pfp )( int ), + xfs_bstat_t *buf, + size_t buflenin ) +{ + size_t buflenout; + xfs_ino_t lastino; + intgen_t saved_errno; + + xfs_fsop_bulkreq_t bulkreq; +#ifdef XFS_IOC_FSBULKSTAT_SINGLE + xfs_fsop_bulkreq_t sbulkreq; +#endif + + /* stat set with return from callback func + */ + *statp = 0; + + /* NOT COOL: open will affect root dir's access time + */ + + mlog( MLOG_NITTY, + "bulkstat iteration initiated: start_ino == %llu\n", + start_ino ); + + /* quirk of the interface: I want to play in terms of the + * ino to begin with, and ino 0 is not used. so, ... + */ + if ( start_ino > 0 ) { + lastino = start_ino - 1; + } else { + lastino = 0; + } + mlog( MLOG_NITTY + 1, + "calling bulkstat\n" ); + + bulkreq.lastip = (__u64 *)&lastino; /* TODO XXX PORT */ + bulkreq.icount = buflenin; + bulkreq.ubuffer = buf; + bulkreq.ocount = &buflenout; + while (!ioctl(fsfd, XFS_IOC_FSBULKSTAT, &bulkreq)) { + xfs_bstat_t *p; + xfs_bstat_t *endp; + + if ( buflenout == 0 ) { + mlog( MLOG_NITTY + 1, + "bulkstat returns buflen %d\n", + buflenout ); + return 0; + } + mlog( MLOG_NITTY + 1, + "bulkstat returns buflen %d ino %llu\n", + buflenout, + buf->bs_ino ); + for ( p = buf, endp = buf + buflenout ; p < endp ; p++ ) { + intgen_t rval; + +#ifdef XFS_IOC_FSBULKSTAT_SINGLE + if ( (!p->bs_nlink || !p->bs_mode) && p->bs_ino != 0 ) { + /* inode being modified, get synced data */ + mlog( MLOG_NITTY + 1, + "ino %llu needed second bulkstat\n", + p->bs_ino ); + sbulkreq.lastip = &p->bs_ino; + sbulkreq.icount = 1; + sbulkreq.ubuffer = p; + sbulkreq.ocount = NULL; + ioctl(fsfd, XFS_IOC_FSBULKSTAT_SINGLE, &sbulkreq); + } +#endif + + if ( ( p->bs_mode & S_IFMT ) == S_IFDIR ) { + if ( ! ( selector & BIGSTAT_ITER_DIR )){ + continue; + } + } else { + if ( ! ( selector & BIGSTAT_ITER_NONDIR )){ + continue; + } + } + rval = ( * fp )( arg1, fshandlep, fsfd, p ); + if ( rval ) { + *statp = rval; + return 0; + } + if ( pfp ) ( pfp )( PREEMPT_PROGRESSONLY ); + } + + if ( pfp && ( pfp )( PREEMPT_FULL )) { + return EINTR; + } + + mlog( MLOG_NITTY + 1, + "calling bulkstat\n" ); + } + + saved_errno = errno; + + mlog( MLOG_NORMAL, + "syssgi( SGI_FS_BULKSTAT ) on fsroot failed: %s\n", + strerror( saved_errno )); + + return saved_errno; +} + +/* ARGSUSED */ +intgen_t +bigstat_one( jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_ino_t ino, + xfs_bstat_t *statp ) +{ + xfs_fsop_bulkreq_t bulkreq; + +#ifdef SGI_FS_BULKSTAT_SINGLE + ASSERT( ino > 0 ); + return syssgi( SGI_FS_BULKSTAT_SINGLE, fsfd, &ino, statp ); +#else + xfs_ino_t lastino; + intgen_t count = 0; + intgen_t rval; + + ASSERT( ino > 0 ); + lastino = ino - 1; + bulkreq.lastip = (__u64 *)&lastino; + bulkreq.icount = 1; + bulkreq.ubuffer = statp; + bulkreq.ocount = &count; + rval = ioctl(fsfd, XFS_IOC_FSBULKSTAT, &bulkreq); + if ( count == 0 || lastino != ino ) { + return EINVAL; + } + return rval; +#endif +} + +/* calls the callback for every entry in the directory specified + * by the stat buffer. supplies the callback with a file system + * handle and a stat buffer, and the name from the dirent. + * + * NOTE: does NOT invoke callback for "." or ".."! + * + * if the callback returns non-zero, returns 1 with cbrval set to the + * callback's return value. if syscall fails, returns -1 with errno set. + * otherwise returns 0. + * + * caller may supply a dirent buffer. if not, will malloc one + */ +intgen_t +diriter( jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp, + intgen_t ( *cbfp )( void *arg1, + jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp, + char *namep ), + void *arg1, + intgen_t *cbrvalp, + char *usrgdp, + size_t usrgdsz ) +{ + size_t gdsz; + struct dirent *gdp; + intgen_t fd; + intgen_t gdcnt; + intgen_t scrval; + intgen_t cbrval; + + if ( usrgdp ) { + ASSERT( usrgdsz >= sizeof( struct dirent ) ); + gdsz = usrgdsz; + gdp = ( struct dirent * )usrgdp; + } else { + gdsz = pgsz; + gdp = ( struct dirent * )malloc( gdsz ); + ASSERT( gdp ); + } + + /* open the directory + */ + fd = jdm_open( fshandlep, statp, O_RDONLY ); + if ( fd < 0 ) { + mlog( MLOG_NORMAL, + "WARNING: unable to open directory ino %llu: %s\n", + statp->bs_ino, + strerror( errno )); + *cbrvalp = 0; + if ( ! usrgdp ) { + free( ( void * )gdp ); + } + return -1; + } + ASSERT( ( statp->bs_mode & S_IFMT ) == S_IFDIR ); + + /* lots of buffering done here, to achieve OS-independence. + * if proves to be to much overhead, can streamline. + */ + scrval = 0; + cbrval = 0; + for ( gdcnt = 1 ; ; gdcnt++ ) { + struct dirent *p; + intgen_t nread; + register size_t reclen; + + ASSERT( scrval == 0 ); + ASSERT( cbrval == 0 ); + + nread = getdents_wrap( fd, (char *)gdp, gdsz ); + + /* negative count indicates something very bad happened; + * try to gracefully end this dir. + */ + if ( nread < 0 ) { + mlog( MLOG_NORMAL, + "WARNING: unable to read dirents (%d) for " + "directory ino %llu: %s\n", + gdcnt, + statp->bs_ino, + strerror( errno )); + nread = 0; /* pretend we are done */ + } + + /* no more directory entries: break; + */ + if ( nread == 0 ) { + break; + } + + /* translate and invoke cb each entry: skip "." and "..". + */ + for ( p = gdp, + reclen = ( size_t )p->d_reclen + ; + nread > 0 + ; + nread -= ( intgen_t )reclen, + ASSERT( nread >= 0 ), + p = ( struct dirent * )( ( char * )p + reclen ), + reclen = ( size_t )p->d_reclen ) { + xfs_bstat_t statbuf; + ASSERT( scrval == 0 ); + ASSERT( cbrval == 0 ); + + /* skip "." and ".." + */ + if ( *( p->d_name + 0 ) == '.' + && + ( *( p->d_name + 1 ) == 0 + || + ( *( p->d_name + 1 ) == '.' + && + *( p->d_name + 2 ) == 0 ))) { + continue; + } + + /* use bigstat + */ + scrval = bigstat_one( fshandlep, + fsfd, + p->d_ino, + &statbuf ); + if ( scrval ) { + mlog( MLOG_NORMAL, + "WARNING: could not stat " + "dirent %s ino %llu: %s\n", + p->d_name, + ( xfs_ino_t )p->d_ino, + strerror( errno )); + scrval = 0; + continue; + } + + /* if getdents64() not yet available, and ino + * occupied more than 32 bits, warn and skip. + */ +#ifndef __USE_LARGEFILE64 + if ( statbuf.bs_ino > ( xfs_ino_t )INOMAX ) { + mlog( MLOG_NORMAL, + "WARNING: unable to process dirent %s: " + "ino %llu too large\n", + p->d_name, + ( xfs_ino_t )p->d_ino ); + continue; + } +#endif + + /* invoke the callback + */ + cbrval = ( * cbfp )( arg1, + fshandlep, + fsfd, + &statbuf, + p->d_name ); + + /* abort the iteration if the callback returns non-zero + */ + if ( cbrval ) { + break; + } + } + + if ( scrval || cbrval ) { + break; + } + } + + ( void )close( fd ); + if ( ! usrgdp ) { + free( ( void * )gdp ); + } + + if ( scrval ) { + *cbrvalp = 0; + return -1; + } else if ( cbrval ) { + *cbrvalp = cbrval; + return 1; + } else { + *cbrvalp = 0; + return 0; + } +} + +char * +ctimennl( const time_t *clockp ) +{ + char *p = ctime( clockp ); + + if ( p && strlen( p ) > 0 ) { + p[ strlen( p ) - 1 ] = 0; + } + + return p; +} + +int +cvtnum( int blocksize, char *s ) +{ + int i; + char *sp; + + i = (int)strtoll(s, &sp, 0); + if (i == 0 && sp == s) + return -1; + if (*sp == '\0') + return i; + if (*sp == 'b' && blocksize && sp[1] == '\0') + return i * blocksize; + if (*sp == 'k' && sp[1] == '\0') + return 1024 * i; + if (*sp == 'm' && sp[1] == '\0') + return 1024 * 1024 * i; + return -1; +} + +bool_t +isinxfs( char *path ) +{ + intgen_t fd; + xfs_fsop_geom_t geo; + intgen_t rval; + + fd = open( path, O_RDONLY ); + if ( fd < 0 ) { + mlog( MLOG_NORMAL, + "WARNING: could not open %s " + "to determine fs type: assuming non-xfs\n", + path ); + return BOOL_FALSE; + } + rval = ioctl(fd, XFS_IOC_FSGEOMETRY, &geo); + + if ( rval < 0 ) { + return BOOL_FALSE; + } else { + return BOOL_TRUE; + } +} + +void +fold_init( fold_t fold, char *infostr, char c ) +{ + size_t infolen; + size_t dashlen; + size_t predashlen; + size_t postdashlen; + char *p; + char *endp; + ix_t cnt; + + ASSERT( sizeof( fold_t ) == FOLD_LEN + 1 ); + + infolen = strlen( infostr ); + if ( infolen > FOLD_LEN - 4 ) { + infolen = FOLD_LEN - 4; + } + dashlen = FOLD_LEN - infolen - 3; + predashlen = dashlen / 2; + postdashlen = dashlen - predashlen; + + p = &fold[ 0 ]; + endp = &fold[ sizeof( fold_t ) - 1 ]; + + ASSERT( p < endp ); + *p++ = ' '; + for ( cnt = 0 ; cnt < predashlen && p < endp ; cnt++, p++ ) { + *p = c; + } + ASSERT( p < endp ); + *p++ = ' '; + ASSERT( p < endp ); + ASSERT( p + infolen < endp ); + strcpy( p, infostr ); + p += infolen; + ASSERT( p < endp ); + *p++ = ' '; + ASSERT( p < endp ); + for ( cnt = 0 ; cnt < postdashlen && p < endp ; cnt++, p++ ) { + *p = c; + } + ASSERT( p <= endp ); + *p = 0; +} diff -rNu linux-2.4.7/cmd/xfsdump/common/util.h linux-2.4-xfs/cmd/xfsdump/common/util.h --- linux-2.4.7/cmd/xfsdump/common/util.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/common/util.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef UTIL_H +#define UTIL_H + + +/* util.[hc] - generally useful functions + */ + +/* write_buf - converts the normal manager write method into something simpler + * + * the managers present a somewhat complicated write interface, for performance + * reasons, which eliminates buffer copying. however, there are times when + * the data to be written is already buffered, such as when writing out + * header structures. This function takes care of the details of writing + * the contents of such a buffer using the manager operators. + * + * if bufp is null, writes bufsz zeros. + */ +typedef char * ( * gwbfp_t )( void *contextp, size_t wantedsz, size_t *szp); +typedef intgen_t ( * wfp_t )( void *contextp, char *bufp, size_t bufsz ); + +extern intgen_t write_buf( char *bufp, + size_t bufsz, + void *contextp, + gwbfp_t get_write_buf_funcp, + wfp_t write_funcp ); + + +/* read_buf - converts the normal manager read method into something simpler + * + * the managers present a somewhat complicated read interface, for performance + * reasons, which eliminates buffer copying. however, there are times when + * the caller wants his buffer to be filled completely, such as when reading + * header structures. This function takes care of the details of filling + * such a buffer using the manager operators. + * + * if bufp is null, discards read data. + * + * returns number of bytes successfully read. returns by reference the + * status of the first failure of the read funcp. if no read failures occur, + * *statp will be zero. + */ +typedef char * ( *rfp_t )( void *contextp, size_t wantedsz, size_t *szp, intgen_t *statp ); +typedef void ( * rrbfp_t )( void *contextp, char *bufp, size_t bufsz ); + +extern intgen_t read_buf( char *bufp, + size_t bufsz, + void *contextp, + rfp_t read_funcp, + rrbfp_t return_read_buf_funcp, + intgen_t *statp ); + + +#define min( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) +#define max( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) + + +/* strncpyterm - like strncpy, but guarantees the destination is null-terminated + */ +extern char *strncpyterm( char *s1, char *s2, size_t n ); + +/* determines if the file specified is contained in an xfs file system + */ +extern bool_t isinxfs( char *path ); + +/* converts a struct stat64 into a xfs_bstat_t. does not fill in fields + * where info cannot be extracted from struct stat64. + */ +extern void stat64_to_xfsbstat( xfs_bstat_t *xfsstatp, struct stat64 *statp ); + +/* bigstat - efficient file status gatherer. presents an iterative + * callback interface, invoking the caller's callback for each in-use + * inode. the caller can specify the first ino, and can limit the callbacks + * to just dirs, just non-dirs, or both. if the callback returns non-zero, + * aborts the iteration and sets stat to the callback's return; otherwise, + * stat is set to zero. return value set to errno if the system call fails, + * or EINTR if optional pre-emption func returns TRUE. + */ +#define BIGSTAT_ITER_DIR ( 1 << 0 ) +#define BIGSTAT_ITER_NONDIR ( 1 << 1 ) +#define BIGSTAT_ITER_ALL ( ~0 ) + +extern intgen_t bigstat_iter( jdm_fshandle_t *fshandlep, + intgen_t fsid, + intgen_t selector, + xfs_ino_t start_ino, + intgen_t ( * fp )( void *arg1, + jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp ), + void * arg1, + intgen_t *statp, + bool_t ( pfp )( int ), /* preemption chk func */ + xfs_bstat_t *buf, + size_t buflen ); + +extern intgen_t bigstat_one( jdm_fshandle_t *fshandlep, + intgen_t fsid, + xfs_ino_t ino, + xfs_bstat_t *statp ); + + +/* calls the callback for every entry in the directory specified + * by the stat buffer. supplies the callback with a file system + * handler and a stat buffer, and the name from the dirent. + * + * NOTE: does NOT invoke callback for "." or ".."! + * + * caller may supply getdents buffer. size must be >= sizeof( dirent_t ) + * + MAXPATHLEN. if not supplied (usrgdp NULL), one will be malloc()ed. + * + * if the callback returns non-zero, returns 1 with cbrval set to the + * callback's return value. if syscall fails, returns -1 with errno set. + * otherwise returns 0. + */ +extern intgen_t diriter( jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp, + intgen_t ( *cbfp )( void *arg1, + jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp, + char *namep ), + void *arg1, + intgen_t *cbrvalp, + char *usrgdp, + size_t usrgdsz ); + + + +/* ctimennl - ctime(3C) with newline removed + */ +extern char *ctimennl( const time_t *clockp ); + + +/* fold_t - a character string made to look like a "fold here" + */ +#define FOLD_LEN 79 +typedef char fold_t[ FOLD_LEN + 1 ]; +extern void fold_init( fold_t fold, char *infostr, char c ); + + +/* macro to copy uuid structures + */ +#define COPY_LABEL( lab1, lab2) ( bcopy( lab1, lab2, GLOBAL_HDR_STRING_SZ) ) + +/* flg definitions for preemptchk + */ +#define PREEMPT_FULL 0 +#define PREEMPT_PROGRESSONLY 1 + +/* + * Align pointer up to alignment + */ +#define ALIGN_PTR(p,a) \ + (((__psint_t)(p) & ((a)-1)) ? \ + ((void *)(((__psint_t)(p) + ((a)-1)) & ~((a)-1))) : \ + ((void *)(p))) + +#endif /* UTIL_H */ diff -rNu linux-2.4.7/cmd/xfsdump/configure.in linux-2.4-xfs/cmd/xfsdump/configure.in --- linux-2.4.7/cmd/xfsdump/configure.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/configure.in Tue Jun 12 02:20:31 2001 @@ -0,0 +1,221 @@ +dnl unpacking check - this file must exist +AC_INIT(common/main.c) +pkg_name="xfsdump" +AC_SUBST(pkg_name) + +# +# Note: the following environment variables may be set to override the +# defaults (to change paths and/or executables, build parameters, etc): +# +# DEBUG OPTIMIZER MAKE CC LD TAR ZIP RPM AWK SED ECHO +# MALLOCLIB DISTRIBUTION PACKAGE_BUILDER PREFIX ROOT_PREFIX +# + +DEBUG=${DEBUG:-'-DDEBUG'} # -DNDEBUG +OPTIMIZER=${OPTIMIZER:-'-g'} # (-O1 enforced default) +MALLOCLIB=${MALLOCLIB:-''} # /usr/lib/libefence.a + +dnl Debug build? +debug_build="$DEBUG" +AC_SUBST(debug_build) + +dnl Optimization options? +opt_build="$OPTIMIZER" +AC_SUBST(opt_build) + +dnl Alternate malloc library? +malloc_lib="$MALLOCLIB" +AC_SUBST(malloc_lib) + +dnl Set version +. ./VERSION + +pkg_version=${PKG_MAJOR}.${PKG_MINOR}.${PKG_REVISION} +pkg_release=$PKG_BUILD +AC_SUBST(pkg_version) +AC_SUBST(pkg_release) + +pkg_distribution="SGI ProPack" +test -z "$DISTRIBUTION" || pkg_distribution="$DISTRIBUTION" +AC_SUBST(pkg_distribution) + +pkg_builder=`id -u -n`@`hostname -f` +test -z "$PACKAGE_BUILDER" || pkg_builder="$PACKAGE_BUILDER" +AC_SUBST(pkg_builder) + +dnl check if user wants their own C compiler +test -z "$CC" && AC_PROG_CC +cc=$CC +AC_SUBST(cc) + +dnl check if users wants their own make +test -z "$MAKE" && AC_PATH_PROG(MAKE, make, /usr/bin/make) +make=$MAKE +AC_SUBST(make) + +dnl check if users wants their own linker +test -z "$LD" && AC_PATH_PROG(LD, ld, /usr/bin/ld) +ld=$LD +AC_SUBST(ld) + +dnl check if the tar program is available +test -z "$TAR" && AC_PATH_PROG(TAR, tar) +tar=$TAR +AC_SUBST(tar) + +dnl check if the gzip program is available +test -z "$ZIP" && AC_PATH_PROG(ZIP, gzip, /bin/gzip) +zip=$ZIP +AC_SUBST(zip) + +dnl check if the rpm program is available +test -z "$RPM" && AC_PATH_PROG(RPM, rpm, /bin/rpm) +rpm=$RPM +AC_SUBST(rpm) + +dnl .. and what version is rpm +rpm_version=0 +test -x $RPM && \ + rpm_version=`$RPM --version | awk '{print $NF}' | awk -F. '{print $1}'` +AC_SUBST(rpm_version) + +dnl check if the makedepend program is available +test -z "$MAKEDEPEND" && AC_PATH_PROG(MAKEDEPEND, makedepend, /bin/true) +makedepend=$MAKEDEPEND +AC_SUBST(makedepend) + +dnl check if symbolic links are supported +AC_PROG_LN_S + +dnl check if user wants their own awk, sed and echo +test -z "$AWK" && AC_PATH_PROG(AWK, awk, /bin/awk) +awk=$AWK +AC_SUBST(awk) +test -z "$SED" && AC_PATH_PROG(SED, sed, /bin/sed) +sed=$SED +AC_SUBST(sed) +test -z "$ECHO" && AC_PATH_PROG(ECHO, echo, /bin/echo) +echo=$ECHO +AC_SUBST(echo) + +CPPFLAGS="-I/usr/include/xfs" +AC_SUBST(CPPFLAGS) + +dnl Checks for UUID header and library. +AC_CHECK_HEADER(uuid/uuid.h,, [ + echo + echo 'FATAL ERROR: could not find a valid UUID header.' + echo 'Install either the e2fsprogs-devel (rpm) or the uuid-dev (deb) package.' + exit 1 +]) +AC_CHECK_LIB(uuid, uuid_generate,, [ + echo + echo 'FATAL ERROR: could not find a valid UUID library.' + echo 'Install either the e2fsprogs-devel (rpm) or the uuid-dev (deb) package.' + exit 1 +]) +libuuid="/usr/lib/libuuid.a" +AC_SUBST(libuuid) + +dnl Checks for base XFS headers and libraries. +AC_CHECK_HEADER(xfs/libxfs.h,, [ + echo + echo 'FATAL ERROR: could not find a valid XFS library header.' + echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.' + exit 1 +]) +AC_CHECK_LIB(xfs, libxfs_init,, [ + echo + echo 'FATAL ERROR: could not find a valid XFS base library.' + echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.' + exit 1 +]) +AC_CHECK_HEADER(xfs/handle.h,, [ + echo + echo 'FATAL ERROR: could not find a valid XFS handle header.' + echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.' + exit 1 +]) +AC_CHECK_LIB(handle, path_to_handle,, [ + echo + echo 'FATAL ERROR: could not find a valid XFS handle library.' + echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.' + exit 1 +]) +libxfs="-lxfs" +libhdl="-lhandle" +AC_SUBST(libxfs) +AC_SUBST(libhdl) + +dnl Checks for Extended Attributes header and library. +AC_CHECK_HEADER(attr/attributes.h,, [ + echo + echo 'FATAL ERROR: could not find a valid Extended Attributes header.' + echo 'Install either the attr-devel (rpm) or the attr-dev (deb) package.' + exit 1 +]) +AC_CHECK_LIB(attr, attr_get,, [ + echo + echo 'FATAL ERROR: could not find a valid Extended Attributes library.' + echo 'Install either the attr-devel (rpm) or the attr-dev (deb) package.' + exit 1 +]) +libattr="/usr/lib/libattr.a" +AC_SUBST(libattr) + + +dnl alternate root and usr prefixes +test -z "$ROOT_PREFIX" && ROOT_PREFIX="" +root_prefix="$ROOT_PREFIX" +test -z "$PREFIX" && PREFIX="/usr" +prefix="$PREFIX" + +dnl man pages (source) +dnl also check if man page source is gzipped +dnl (usually on Debian, but not Redhat pre-7.0) +pkg_man_dir=${prefix}/share/man +have_zipped_manpages=false +for d in ${prefix}/share/man ${prefix}/man ; do + if test -f $d/man1/man.1.gz + then + pkg_man_dir=$d + have_zipped_manpages=true + break + fi +done +AC_SUBST(pkg_man_dir) +AC_SUBST(have_zipped_manpages) + +dnl binaries +pkg_bin_dir=${prefix}/sbin +AC_SUBST(pkg_bin_dir) + +dnl static libraries +pkg_lib_dir=${prefix}/lib +AC_SUBST(pkg_lib_dir) + +dnl runtime shared system libraries +pkg_slib_dir=${root_prefix}/lib +AC_SUBST(pkg_slib_dir) + +dnl system binaries +pkg_sbin_dir=${root_prefix}/sbin +AC_SUBST(pkg_sbin_dir) + +dnl include files +pkg_inc_dir=${prefix}/include/xfs +AC_SUBST(pkg_inc_dir) + +dnl doc directory +pkg_doc_dir=${prefix}/share/doc/${pkg_name} +AC_SUBST(pkg_doc_dir) + + +dnl +dnl output files +dnl + +AC_OUTPUT( \ +dnl Build definitions for use in Makefiles + include/builddefs \ +) diff -rNu linux-2.4.7/cmd/xfsdump/copy/CVS/Entries linux-2.4-xfs/cmd/xfsdump/copy/CVS/Entries --- linux-2.4.7/cmd/xfsdump/copy/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/copy/CVS/Entries Thu Jul 5 11:44:00 2001 @@ -0,0 +1,5 @@ +/Makefile/1.2/Mon Jan 15 04:32:19 2001// +/locks.c/1.1/Mon Jan 15 04:07:45 2001// +/locks.h/1.1/Mon Jan 15 04:07:45 2001// +/xfs_copy.c/1.1/Mon Jan 15 04:07:45 2001// +D diff -rNu linux-2.4.7/cmd/xfsdump/copy/CVS/Repository linux-2.4-xfs/cmd/xfsdump/copy/CVS/Repository --- linux-2.4.7/cmd/xfsdump/copy/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/copy/CVS/Repository Thu Jul 5 11:44:00 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/copy diff -rNu linux-2.4.7/cmd/xfsdump/copy/CVS/Root linux-2.4-xfs/cmd/xfsdump/copy/CVS/Root --- linux-2.4.7/cmd/xfsdump/copy/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/copy/CVS/Root Thu Jul 5 11:44:00 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/copy/Makefile linux-2.4-xfs/cmd/xfsdump/copy/Makefile --- linux-2.4.7/cmd/xfsdump/copy/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/copy/Makefile Sun Jan 14 22:32:19 2001 @@ -0,0 +1,49 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = xfs_copy + +CFILES = xfs_copy.c locks.c +HFILES = locks.h +LLDLIBS = $(LIBXFS) $(LIBUUID) + +default: $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_BIN_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/xfsdump/copy/locks.c linux-2.4-xfs/cmd/xfsdump/copy/locks.c --- linux-2.4.7/cmd/xfsdump/copy/locks.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/copy/locks.c Sun Jan 14 22:07:45 2001 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "locks.h" + +extern usptr_t *arena; + +thread_control * +thread_control_init(thread_control *mask, int num_threads) +{ + if ((mask->mutex = usnewsema(arena, 1)) == NULL) + return(NULL); + + mask->num_working = 0; + + return(mask); +} + +wbuf * +wbuf_init(wbuf *buf, int data_size, int data_alignment, int min_io_size, int id) +{ + buf->id = id; + + if ((buf->data = memalign(data_alignment, data_size)) == NULL) + return(NULL); + + assert(min_io_size % BBSIZE == 0); + + buf->min_io_size = min_io_size; + buf->size = MAX(data_size, 2*min_io_size); + + return(buf); +} + +void +buf_read_start(void) +{ +} + +void +buf_read_end(thread_control *tmask, usema_t *mainwait) +{ + uspsema(tmask->mutex); + + tmask->num_working--; + + if (tmask->num_working == 0) { + usvsema(mainwait); + } + + usvsema(tmask->mutex); +} + +/* + * me should be set to (1 << (thread_id%32)), + * the tmask bit is already set to INACTIVE (1) + */ + +void +buf_read_error(thread_control *tmask, usema_t *mainwait, thread_id id) +{ + uspsema(tmask->mutex); + + tmask->num_working--; + target_states[id] = INACTIVE; + + if (tmask->num_working == 0) { + usvsema(mainwait); + } + + usvsema(tmask->mutex); + +} + +void +buf_write_start(void) +{ +} + +void +buf_write_end(thread_control *tmask, usema_t *mainwait) +{ + uspsema(tmask->mutex); + + tmask->num_working--; + + if (tmask->num_working == 0) { + usvsema(mainwait); + } + + usvsema(tmask->mutex); +} + diff -rNu linux-2.4.7/cmd/xfsdump/copy/locks.h linux-2.4-xfs/cmd/xfsdump/copy/locks.h --- linux-2.4.7/cmd/xfsdump/copy/locks.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/copy/locks.h Sun Jan 14 22:07:45 2001 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#define usema_t char /* TODO - port to pthreads */ +#define usptr_t char /* TODO - port to pthreads */ +#define CONF_ARENATYPE 0 /* TODO - port to pthreads */ +#define US_SHAREDONLY 0 /* TODO - port to pthreads */ +#define CONF_INITUSERS 0 /* TODO - port to pthreads */ +#define PR_SALL 0 /* TODO - port to pthreads */ +#define F_DIOINFO 0 /* TODO - port to Linux */ + +/* TODO - port to pthreads... */ +static inline usptr_t *usinit (const char *f) { ASSERT(0); } +static inline int uspsema (usema_t *sema) { ASSERT(0); } +static inline int usvsema (usema_t *sema) { ASSERT(0); } +static inline pid_t wait (int *statptr) { ASSERT(0); } +static inline int usconfig (int cmd, ...) { ASSERT(0); } +static inline usema_t *usnewsema (usptr_t *handle, int val) { ASSERT(0); } +static inline pid_t sprocsp (void (*entry) (void *, size_t), + uint inh, void *arg, char *sp, size_t len) { ASSERT(0); } + + +#define ACTIVE 1 +#define INACTIVE 2 +#define UNUSED 0 + +extern int *target_states; + +/* + * ugh. the position/buf_position, length/buf_length, data/buffer pairs + * exist because of alignment constraints for direct i/o and dealing + * with scenarios where either the source or target or both is a file + * and the blocksize of the filesystem where file resides is different + * from that of the filesystem image being duplicated. You can get + * alignment problems resulting in things like ag's starting on + * non-aligned points in the filesystem. So you have to be able + * to read from points "before" the requested starting point and + * read in more data than requested. + */ + +typedef struct working_buffer { + int id; /* buffer id */ + size_t size; /* size of buffer -- fixed */ + size_t min_io_size; /* for direct i/o */ + xfs_off_t position; /* requested position */ + size_t length; /* length of buffer (bytes) */ + char *data; /* pointer to data buffer */ +} wbuf; + +typedef struct thread_state_control { + usema_t *mutex; +/* int num_threads; */ + int num_working; + wbuf *buffer; +} thread_control; + +typedef int thread_id; +typedef int tm_index; /* index into thread mask array */ +typedef __uint32_t thread_mask; /* a thread mask */ + +/* function declarations */ + +thread_control * +thread_control_init(thread_control *mask, int num_threads); + +wbuf * +wbuf_init(wbuf *buf, int data_size, int data_alignment, int min_io_size, int id); + +void +buf_read_start(void); + +void +buf_read_end(thread_control *tmask, usema_t *mainwait); + +void +buf_read_error(thread_control *tmask, usema_t *wait, thread_id id); + +void +buf_write_start(void); + +void +buf_write_end(thread_control *tmask, usema_t *mainwait); + diff -rNu linux-2.4.7/cmd/xfsdump/copy/xfs_copy.c linux-2.4-xfs/cmd/xfsdump/copy/xfs_copy.c --- linux-2.4.7/cmd/xfsdump/copy/xfs_copy.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/copy/xfs_copy.c Sun Jan 14 22:07:45 2001 @@ -0,0 +1,1524 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#define ustat __kernel_ustat +#include +#include +#include +#include +#include +#undef ustat +#include + +#include "locks.h" + +#define rounddown(x, y) (((x)/(y))*(y)) + +/* private */ + +#define ARENA_NAME "/usr/tmp/xfs_copy.arenaXXXXXX" +#define LOGFILE_NAME "/usr/tmp/xfs_copy.log.XXXXXX" +#define MAX_TARGETS 100 +#define MAX_THREADS (MAX_TARGETS + 2) +#define T_STACKSIZE (1024*16) + +char *arena_name; + +/* globals */ + +int duplicate_uuids; +pid_t parent_pid; + +int logfd; +char *logfile_name; +FILE *logerr = NULL; + +int source_is_file; /* is source a file? */ +int target_is_file; /* is target a file? */ + +int direct_io; + +char *source_name, *old_source_name, *tmp_name; +int source_fd; + +__uint64_t source_blocks; /* rough count of # to be copied */ +__uint64_t bytes_copied = 0; /* exact count of bytes copied */ + +int source_blocksize; /* source filesystem blocksize */ +int source_sectorsize; /* source disk sectorsize */ + +struct stat64 statbuf; + +int num_targets = 35; +char **target_names; +int *target_fds; +xfs_off_t *target_positions; +pid_t *target_pids; +int *target_states; +int *target_errors; +int *target_err_types; + +typedef struct thread_args { + int id; + usema_t *wait; + int fd; +} t_args; + +usptr_t *arena; +#define ANYCHILD -1 +#define NUM_BUFS 1 + +wbuf w_buf; +wbuf btree_buf; + +thread_control glob_masks; + +t_args *targ; +/* +t_args warg; + +pid_t source_pid; +int source_state; +*/ + +usema_t *mainwait; + + +/* + * An on-disk allocation group header is composed of 4 structures, + * each of which is 1 disk sector long where the sector size is at + * least 512 bytes long (BBSIZE). + * + * Note that presently the 4 structures are laid out in sequence + * (sb, agf, agi, agfl) but there's no guarantee they'll stay that + * way. + * + * There's one ag_header per ag and the superblock in the first ag + * is the contains the real data for the entire filesystem (although + * most of the relevant data won't change anyway even on a growfs). + * + * The filesystem superblock specifies the number of ag's and + * the ag size. That splits the filesystem up into N pieces, + * each of which is an ag and has an ag_header at the beginning. + * + * When I want an ag_header, I read in the first chunk of an ag and + * set the pointers to point to the right places in the buffer. + */ + +typedef struct ag_header { + /* superblock for filesystem or aggregate group */ + + xfs_sb_t *xfs_sb; + + /* free space info */ + + xfs_agf_t *xfs_agf; + + /* free inode info */ + + xfs_agi_t *xfs_agi; + + /* + * allocator freelist -- freelist blocks reserved + * for use by the btree allocation code and also the + * freeblocks of last resort for the ag + */ + + xfs_agfl_t *xfs_agfl; + + char *residue; + int residue_length; +} ag_header_t; + +/* first fs block that contains real (non-ag-header) data */ + +xfs_agblock_t first_agbno = 0; + +void +check_errors(void) +{ + int i, first_error = 0; + + /* now check for errors */ + + for (i = 0; i < num_targets; i++) { + if (target_states[i] == INACTIVE) { + if (first_error == 0) { + first_error++; + fprintf(logerr, + "THE FOLLOWING COPIES FAILED TO COMPLETE.\n"); + fprintf(stderr, + "THE FOLLOWING COPIES FAILED TO COMPLETE.\n"); + } + fprintf(logerr, " %s -- ", target_names[i]); + fprintf(stderr, " %s -- ", target_names[i]); + if (target_err_types[i] == 0) { + fprintf(logerr, "write error"); + fprintf(stderr, "write error"); + } else { + fprintf(logerr, "lseek64 error"); + fprintf(stderr, "lseek64 error"); + } + + fprintf(logerr, + " at offset %lld\n", target_positions[i]); + fprintf(stderr, + " at offset %lld\n", target_positions[i]); + } + } + if (first_error == 0) { + fprintf(stdout, "All copies completed.\n"); + fflush(NULL); + } else { + fprintf(stderr, "See \"%s\" for more details.\n", + logfile_name); + exit(1); + } +} + +/* the prefix should be relatively *short* */ + +void +do_error2(char *prefix, int errornum, int finalmsg) +{ + size_t tot_len; + char *errstring, *errstring2; + char buffer[1024]; + + errstring = strerror(errornum); + + tot_len = sprintf(buffer, "%s: \"%s\"\n", prefix, errstring); + + if (tot_len == 0) + goto broken; + + /* log an exit message to logfile and stderr, too */ + + if (fprintf(logerr, "%s", buffer) == tot_len) { + fprintf(stderr, "%s: \"%s\"\n", prefix, errstring); + if (finalmsg) + fprintf(stderr, + "Check logfile \"%s\" for more details\n", + logfile_name); + return; + } + +broken: + /* crap, logfile is broken, have to write to stderr */ + + fprintf(stderr, "%s: could not write to logfile \"%s\".\n", + progname, logfile_name); + fprintf(stderr, "%s message was -- %s: %s\n", + progname, prefix, errstring); + + errstring2 = strerror(errno); + + fprintf(stderr, "Aborting XFS copy -- logfile error -- reason: %s\n", + errstring2); + exit(1); +} + +void +do_error(char *prefix) +{ + do_error2(prefix, errno, 1); +} + +/* + * don't have to worry about alignment and mins because those + * are taken care of when the buffer's read in + */ + +/* ARGSUSED */ +void +begin_reader(void *arg, size_t ignore) +{ + t_args *args = arg; + int res; + int error = 0; + + /*usadd(arena);*/ + usinit(arena); + + for (;;) { + uspsema(args->wait); + + buf_read_start(); + + /* write */ + if (target_positions[args->id] != w_buf.position) { + if (lseek64(args->fd, w_buf.position, SEEK_SET) < 0) { + error = 1; + target_err_types[args->id] = 1; + } else { + target_positions[args->id] = w_buf.position; + } + } + + if ((res = write(target_fds[args->id], w_buf.data, + w_buf.length)) == w_buf.length) { + target_positions[args->id] += res; + } else { + error = 2; + } + + if (error) { + goto handle_error; + } + + buf_read_end(&glob_masks, mainwait); + } + /* NOTREACHED */ + +handle_error: + /* error will be logged by primary thread */ + + target_errors[args->id] = errno; + target_positions[args->id] = w_buf.position; + + buf_read_error(&glob_masks, mainwait, args->id); + exit(1); +} + +int kids; + +void +killall(void) +{ + int i; + + /* only the parent gets to kill things */ + + if (getpid() != parent_pid) + return; + + for (i = 0; i < num_targets; i++) { + if (target_states[i] == ACTIVE) { + /* kill up target threads */ + kill(target_pids[i], SIGKILL); + usvsema(targ[i].wait); + } + } +} + +void +handler() +{ + pid_t pid = getpid(); + int status, i; + char buf[512]; + + pid = wait(&status); + + kids--; + + for (i = 0; i < num_targets; i++) { + if (target_pids[i] == pid) { + if (target_states[i] == INACTIVE) { + /* thread got an I/O error */ + + if (target_err_types[i] == 0) { + fprintf(logerr, + "%s: write error on target %d \"%s\" at offset %lld\n", + progname, i, target_names[i], + target_positions[i]); + } else { + fprintf(logerr, + "%s: lseek64 error on target %d \"%s\" at offset %lld\n", + progname, i, target_names[i], + target_positions[i]); + } + + sprintf(buf, "Aborting target %d - reason", i); + do_error2(buf, target_errors[i], 0); + + if (kids == 0) { + fprintf(logerr, "Aborting XFS copy - no more targets.\n"); + fprintf(stderr, "Aborting XFS copy - no more targets.\n"); + check_errors(); + exit(1); + } + + sigset(SIGCLD, handler); + return; + } else { + /* it just croaked it bigtime, log it */ + + fprintf(logerr, + "%s: thread %d died unexpectedly, target \"%s\" incomplete\n", + progname, i, target_names[i]); + + fprintf(logerr, + "%s: offset was probably %lld\n", + progname, target_positions[i]); + do_error2("Aborting XFS copy - reason", + target_errors[i], 1); + exit(1); + } + } + } + + /* unknown child -- something very wrong */ + + fprintf(logerr, "%s: UNKNOWN CHILD DIED - THIS SHOULD NEVER HAPPEN!\n", + progname); + do_error("Aborting XFS copy - reason"); + exit(1); + + sigset(SIGCLD, handler); +} + +void +usage(void) +{ + fprintf(stderr, + "Usage: %s [-d] fromdev|fromfile todev [todev todev ...]\n" + " %s [-d] fromdev|fromfile tofile\n", progname, progname); + exit(1); +} + +__uint64_t barcount[11]; +int howfar = 0; +char *bar[11] = { + " 0% ", + " ... 10% ", + " ... 20% ", + " ... 30% ", + " ... 40% ", + " ... 50% ", + " ... 60% ", + " ... 70% ", + " ... 80% ", + " ... 90% ", + " ... 100%\nDone.\n", +}; + +void +bump_bar(int tenths) +{ + printf("%s", bar[tenths]); + fflush(stdout); +} + +static xfs_off_t source_position = -1; + +void +read_wbuf(int fd, wbuf *buf, xfs_mount_t *mp) +{ + int res = 0; + xfs_off_t lres = 0; + xfs_off_t newpos; + size_t diff; + + newpos = rounddown(buf->position, (xfs_off_t) buf->min_io_size); + + if (newpos != buf->position) { + diff = buf->position - newpos; + buf->position = newpos; + + buf->length += diff; + } + + if (source_position != buf->position) { + lres = lseek64(fd, buf->position, SEEK_SET); + if (lres < 0LL) { + fprintf(logerr, + "%s: lseek64 failure at offset %lld\n", + progname, source_position); + do_error("Aborting XFS copy - reason"); + exit(1); + } + source_position = buf->position; + } + + ASSERT(source_position % source_sectorsize == 0); + + /* round up length for direct i/o if necessary */ + + if (buf->length % buf->min_io_size != 0) + buf->length = roundup(buf->length, buf->min_io_size); + + if (buf->length > buf->size) { + fprintf(stderr, + "assert error: buf->length = %d, buf->size = %d\n", + buf->length, buf->size); + killall(); + abort(); + } + + if ((res = read(fd, buf->data, buf->length)) < 0) { + fprintf(logerr, "%s: read failure at offset %lld\n", + progname, source_position); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if (res < buf->length && + source_position + res == mp->m_sb.sb_dblocks * source_blocksize) + res = buf->length; + else + ASSERT(res == buf->length); + source_position += res; + buf->length = res; +} + +int +read_ag_header(int fd, xfs_agnumber_t agno, wbuf *buf, ag_header_t *ag, + xfs_mount_t *mp, int blocksize, int sectorsize) +{ + xfs_daddr_t off; + int length; + xfs_off_t newpos; + size_t diff; + + /* initial settings */ + + diff = 0; + off = XFS_AG_DADDR(mp, agno, XFS_SB_DADDR); + buf->position = (xfs_off_t) off * (xfs_off_t) BBSIZE; + length = buf->length = first_agbno * blocksize; + + /* handle alignment stuff */ + + newpos = rounddown(buf->position, (xfs_off_t) buf->min_io_size); + + if (newpos != buf->position) { + diff = buf->position - newpos; + buf->position = newpos; + + buf->length += diff; + } + + /* round up length for direct i/o if necessary */ + + if (buf->length % buf->min_io_size != 0) + buf->length = roundup(buf->length, buf->min_io_size); + + ASSERT(length != 0); + + read_wbuf(fd, buf, mp); + + ASSERT(buf->length >= length); + + ag->xfs_sb = (xfs_sb_t *) (buf->data + diff); + + ASSERT(ag->xfs_sb->sb_magicnum == XFS_SB_MAGIC); + + ag->xfs_agf = (xfs_agf_t *) (buf->data + diff + sectorsize); + + ASSERT(ag->xfs_agf->agf_magicnum == XFS_AGF_MAGIC); + + ag->xfs_agi = (xfs_agi_t *) (buf->data + diff + 2*sectorsize); + + ASSERT(ag->xfs_agi->agi_magicnum == XFS_AGI_MAGIC); + + ag->xfs_agfl = (xfs_agfl_t *) (buf->data + diff + 3*sectorsize); + + return(1); +} + +void +write_wbuf(void) +{ + int i; + + /* verify target threads */ + + for (i = 0; i < num_targets; i++) { + if (target_states[i] != INACTIVE) { + glob_masks.num_working++; + } + } + + /* release target threads */ + + for (i = 0; i < num_targets; i++) { + if (target_states[i] != INACTIVE) { + /* wake up target threads */ + + usvsema(targ[i].wait); + } + } + + sigrelse(SIGCLD); + uspsema(mainwait); + sighold(SIGCLD); +} + + +#define findrawpath(x) x + +int +main(int argc, char **argv) +{ + int i, write_last_block = 0; + int open_flags; + xfs_off_t pos; + size_t length; + int c, size, sizeb, first_residue, tmp_residue; + __uint64_t numblocks = 0; + int wblocks = 0; + int num_threads = 0; + struct dioattr d_info; + int wbuf_size; + int wbuf_align; + int wbuf_miniosize; + uuid_t fsid; + uint btree_levels, current_level; + ag_header_t ag_hdr; + xfs_mount_t *mp; + xfs_mount_t mbuf; + xfs_buf_t *sbp; + xfs_sb_t *sb; + xfs_agnumber_t num_ags, agno; + xfs_agblock_t bno; + xfs_daddr_t begin, next_begin, ag_begin, new_begin, ag_end; + xfs_alloc_block_t *block; + xfs_alloc_ptr_t *ptr; + xfs_alloc_rec_t *rec_ptr; + extern char *optarg; + extern int optind; + libxfs_init_t xargs; + t_args *tcarg; + struct ustat ustat_buf; + + progname = basename(argv[0]); + + /* open up log file */ + logfile_name = mktemp(LOGFILE_NAME); + if (*logfile_name == '\0') { + fprintf(stderr, "%s: could not generate unique logfile name\n", + progname); + fprintf(stderr, "%s: check /usr/tmp for xfs_copy.log.* files\n", + progname); + perror("Aborting XFS copy - reason"); + exit(1); + } + + if ((logfd = open(logfile_name, O_CREAT|O_TRUNC|O_APPEND|O_WRONLY, + 0644)) < 0) { + fprintf(stderr, "%s: couldn't open log file \"%s\"\n", + progname, logfile_name); + perror("Aborting XFS copy - reason"); + exit(1); + } + + if ((logerr = fdopen(logfd, "w")) == NULL) { + fprintf(stderr, "%s: couldn't set up logfile stream\n", + progname); + perror("Aborting XFS copy - reason"); + exit(1); + } + + /* argument processing */ + + duplicate_uuids = 0; + + while ((c = getopt(argc, argv, "dV")) != EOF) { + switch (c) { + case 'd': + duplicate_uuids = 1; + break; + case 'V': + printf("%s version %s\n", progname, VERSION); + break; + case '?': + usage(); + } + } + + if (argc - optind < 2) + usage(); + + source_name = argv[optind]; + source_fd = -1; + + optind++; + + /* set up fd and name array */ + + num_targets = argc - optind; + + if (num_targets > MAX_TARGETS) { + fprintf(logerr, "%s: number of targets exceeds maximum of %d\n" + "Aborting XFS copy.\n", progname, MAX_TARGETS); + fprintf(stderr, "%s: number of targets exceeds maximum of %d\n" + "Aborting XFS copy.\n", progname, MAX_TARGETS); + exit(1); + } + + if ((target_names = malloc(sizeof(char *)*num_targets)) == NULL) { + fprintf(logerr, "Couldn't allocate target name array\n"); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if ((target_positions = malloc(sizeof(xfs_off_t)*num_targets)) == NULL) { + fprintf(logerr, "Couldn't allocate target position array\n"); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if ((target_pids = malloc(sizeof(pid_t) * num_targets)) == NULL) { + fprintf(logerr, "Couldn't allocate target pid array\n"); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if ((target_states = malloc(sizeof(int) * num_targets)) == NULL) { + fprintf(logerr, "Couldn't allocate target state array\n"); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if ((target_errors = malloc(sizeof(int) * num_targets)) == NULL) { + fprintf(logerr, "Couldn't allocate target errno array\n"); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if ((target_err_types = malloc(sizeof(int) * num_targets)) == NULL) { + fprintf(logerr, "Couldn't allocate target error type array\n"); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + for (i = 0; i < num_targets; i++) { + target_positions[i] = -1; + target_states[i] = INACTIVE; + target_errors[i] = 0; + target_err_types[i] = 0; + } + + if ((target_fds = malloc(sizeof(int)*num_targets)) == NULL) { + fprintf(logerr, "%s: couldn't malloc target fd array\n", + progname); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + for (i = 0; optind < argc; i++, optind++) { + target_names[i] = argv[optind]; + target_fds[i] = -1; + } + + parent_pid = getpid(); + + if (atexit(killall)) { + fprintf(logerr, "%s: couldn't register atexit function.\n", + progname); + do_error("Aborting XFS copy -- reason"); + exit(1); + } + + /* open up source -- is it a file? */ + + open_flags = O_RDONLY; + + if ((source_fd = open(source_name, open_flags)) < 0) { + fprintf(logerr, "%s: couldn't open source \"%s\"\n", + progname, source_name); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if (fstat64(source_fd, &statbuf) < 0) { + fprintf(logerr, "%s: couldn't stat source \"%s\"\n", + progname, source_name); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if (S_ISREG(statbuf.st_mode)) { + source_is_file = 1; + open_flags |= O_DIRECT; + + /* close and reopen for direct i/o */ + + if (close(source_fd) < 0) { + fprintf(logerr, + "Couldn't close fd to set up direct i/o.\n"); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if ((source_fd = open(source_name, open_flags)) < 0) { + fprintf(logerr, "%s: couldn't re-open source \"%s\"\n", + progname, source_name); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + /* set direct i/o parameters */ + + if (fcntl(source_fd, F_DIOINFO, &d_info) < 0) { + fprintf(logerr, "%s: fcntl on file \"%s\" failed.\n", + progname, source_name); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + wbuf_align = d_info.d_mem; + wbuf_size = d_info.d_maxiosz; + wbuf_miniosize = d_info.d_miniosz; + } else { + source_is_file = 0; + + /* set arbitrary i/o params, miniosize at least 1 disk block */ + + wbuf_align = 4096*4; + wbuf_size = 1024 * 4000; + wbuf_miniosize = -1; /* set after mounting source fs */ + + /* + * check to make sure a filesystem isn't mounted + * on the device + */ + if (ustat(statbuf.st_rdev, &ustat_buf) == 0) { + fprintf(stderr, +"%s: Warning -- a filesystem is mounted on the source device.\n", progname); + fprintf(logerr, +"%s: Warning -- a filesystem is mounted on the source device.\n", progname); + +fprintf(stderr, "\t\tGenerated copies may be corrupt unless the source is\n"); +fprintf(logerr, "\t\tGenerated copies may be corrupt unless the source is\n"); +fprintf(stderr, "\t\tunmounted or mounted read-only. Copy proceeding...\n"); +fprintf(logerr, "\t\tunmounted or mounted read-only. Copy proceeding...\n"); + } + if (S_ISBLK(statbuf.st_mode)) { + fprintf(logerr, "%s: source \"%s\" not a raw device.\n", + progname, source_name); + + old_source_name = source_name; + + source_name = findrawpath(old_source_name); + if (source_name == NULL) { + fprintf(logerr, "%s: cannot locate raw device" + " for \"%s\"\nAborting XFS copy.\n", + progname, old_source_name); + fprintf(stderr, "%s: cannot locate raw device" + " for \"%s\"\nAborting XFS copy.\n", + progname, old_source_name); + exit(1); + } + + /* close and reopen raw device */ + + if (close(source_fd) < 0) { + fprintf(logerr, "Couldn't close raw device.\n"); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if ((source_fd = open(source_name, open_flags)) < 0) { + fprintf(logerr, "%s: couldn't open source" + " \"%s\"\n", progname, source_name); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + fprintf(logerr, "%s: using \"%s\" instead.\n", + progname, source_name); + fprintf(logerr, "%s: continuing...\n", progname); + } + } + + /* prepare the libxfs_init structure */ + memset(&xargs, 0, sizeof(xargs)); + xargs.notvolmsg = "oh no %s"; + xargs.isreadonly = LIBXFS_ISREADONLY; + xargs.notvolok = 1; + + if (source_is_file) { + xargs.dname = source_name; + xargs.disfile = 1; + } else + xargs.volname = source_name; + + if (!libxfs_init(&xargs)) { + fprintf(logerr, "%s: couldn't initialize XFS library\n" + "%s: Aborting.\n", progname, progname); + fprintf(stderr, "%s: couldn't initialize XFS library\n" + "%s: Aborting.\n", progname, progname); + exit(1); + } + + /* prepare the mount structure */ + sbp = libxfs_readbuf(xargs.ddev, XFS_SB_DADDR, 1, 0); + memset(&mbuf, 0, sizeof(xfs_mount_t)); + sb = &mbuf.m_sb; + libxfs_xlate_sb(XFS_BUF_PTR(sbp), sb, 1, ARCH_CONVERT, XFS_SB_ALL_BITS); + + mp = libxfs_mount(&mbuf, sb, xargs.ddev, xargs.logdev, xargs.rtdev, 1); + + if (mp == NULL || mp->m_sb.sb_inprogress) { + fprintf(logerr, "%s: %s is not a valid filesystem.\n" + "%s: Aborting.\n", progname, source_name, progname); + fprintf(stderr, "%s: %s is not a valid filesystem.\n" + "%s: Aborting.\n", progname, source_name, progname); + exit(1); + } + + if (mp->m_sb.sb_logstart == 0) { + /* source has an external log */ + + fprintf(logerr, "%s: %s has an external log.\n%s: Aborting.\n", + progname, source_name, progname); + fprintf(stderr, "%s: %s has an external log.\n%s: Aborting.\n", + progname, source_name, progname); + exit(1); + } + + if (mp->m_sb.sb_rextents != 0) { + /* source has a real-time section */ + + fprintf(logerr, "%s: %s has a real-time section.\n" + "%s: Aborting.\n", progname, source_name, progname); + fprintf(stderr, "%s: %s has a real-time section.\n" + "%s: Aborting.\n", progname, source_name, progname); + exit(1); + } + + source_blocksize = mp->m_sb.sb_blocksize; + source_sectorsize = mp->m_sb.sb_sectsize; + + if (wbuf_miniosize == -1) + wbuf_miniosize = source_sectorsize; + + ASSERT(source_blocksize % source_sectorsize == 0); + ASSERT(source_sectorsize % BBSIZE == 0); + + if (source_blocksize > source_sectorsize) { + /* get number of leftover sectors in last block of ag header */ + + tmp_residue = ((XFS_AGFL_DADDR + 1) * source_sectorsize) + % source_blocksize; + first_residue = (tmp_residue == 0) ? 0 : + source_blocksize - tmp_residue; + ASSERT(first_residue % source_sectorsize == 0); + } else if (source_blocksize == source_sectorsize) { + first_residue = 0; + } else { + fprintf(logerr, + "Error: filesystem block size is smaller than the disk" + " sectorsize.\nAborting XFS copy now.\n"); + exit(1); + } + + first_agbno = (((XFS_AGFL_DADDR + 1) * source_sectorsize) + + first_residue) / source_blocksize; + ASSERT(first_agbno != 0); + ASSERT( ((((XFS_AGFL_DADDR + 1) * source_sectorsize) + + first_residue) % source_blocksize) == 0); + + if (!duplicate_uuids) { + uuid_generate(fsid); + } + + /* now open targets */ + + open_flags = O_RDWR; + + if (num_targets > 1) { + /* just open them all */ + + for (i = 0; i < num_targets; i++) { + if ((target_fds[i] = open(target_names[i], + open_flags)) < 0) { + fprintf(logerr, + "%s: couldn't open target \"%s\"\n", + progname, target_names[i]); + do_error("Aborting XFS copy - reason"); + exit(1); + } + if (fstat64(target_fds[i], &statbuf) < 0) { + fprintf(logerr, + "%s: couldn't stat target \"%s\"\n", + progname, target_names[i]); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if (S_ISREG(statbuf.st_mode)) { + fprintf(logerr, + "%s: target \"%s\" is a regular file.\n", + progname, target_names[i]); + fprintf(stderr, + "%s: target \"%s\" is a regular file.\n", + progname, target_names[i]); + usage(); + } + /* + * check to make sure a filesystem isn't mounted + * on the device + */ + if (ustat(statbuf.st_rdev, &ustat_buf) == 0) { + fprintf(stderr, "%s: target device contains a " + "mounted filesystem.\n%s " + "cannot copy onto mounted filesystems." + " Aborting.\n", progname, progname); + fprintf(logerr, "%s: target device contains a " + "mounted filesystem.\n%s " + "cannot copy onto mounted filesystems." + " Aborting.\n", progname, progname); + exit(1); + } + if (S_ISBLK(statbuf.st_mode)) { + fprintf(logerr, + "%s: target \"%s\" is not a raw device.\n", + progname, target_names[i]); + tmp_name = target_names[i]; + if ((target_names[i] = findrawpath(tmp_name)) + == NULL) { + fprintf(logerr, + "%s: cannot locate raw device for \"%s\"\n", + progname, tmp_name); + fprintf(stderr, + "%s: cannot locate raw device for \"%s\"\n", + progname, tmp_name); + fprintf(logerr, "Aborting XFS copy.\n"); + fprintf(stderr, "Aborting XFS copy.\n"); + exit(1); + } + + /* close and reopen raw device */ + + if (close(target_fds[i]) < 0) { + fprintf(logerr, + "Couldn't close fd to open raw device.\n"); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if ((target_fds[i] = open(target_names[i], + open_flags)) < 0) { + fprintf(logerr, + "%s: couldn't open target \"%s\"\n", + progname, target_names[i]); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + fprintf(logerr, + "%s: using raw device \"%s\" instead\n", + progname, target_names[0]); + fprintf(logerr, "%s: continuing...\n", + progname); + } + } + } else { + /* see if it's a file */ + + if (stat64(target_names[0], &statbuf) < 0) { + /* ok, assume it's a file and create it */ + + printf("Creating file %s\n", target_names[0]); + fprintf(logerr, "Creating file %s\n", target_names[0]); + + open_flags |= O_CREAT|O_DIRECT; + write_last_block = 1; + } else if (S_ISREG(statbuf.st_mode)) { + open_flags |= O_TRUNC|O_DIRECT; + write_last_block = 1; + } else { + /* + * check to make sure a filesystem isn't mounted + * on the device + */ + if (ustat(statbuf.st_rdev, &ustat_buf) == 0) { + fprintf(stderr, "%s: a filesystem is mounted " + "on the target device.\n" + "%s cannot copy to mounted filesystems." + " Aborting\n", progname, progname); + fprintf(logerr, "%s: a filesystem is mounted " + "on the target device.\n" + "%s cannot copy to mounted filesystems." + " Aborting\n", progname, progname); + exit(1); + } + if (S_ISBLK(statbuf.st_mode)) { + fprintf(logerr, + "%s: target \"%s\" is not a raw device.\n", + progname, target_names[0]); + + tmp_name = target_names[0]; + if ((target_names[0] = findrawpath(tmp_name)) + == NULL) { + fprintf(logerr, + "%s: cannot locate raw device for \"%s\"\n", + progname, tmp_name); + fprintf(stderr, + "%s: cannot locate raw device for \"%s\"\n", + progname, tmp_name); + fprintf(logerr, "Aborting XFS copy.\n"); + fprintf(stderr, "Aborting XFS copy.\n"); + exit(1); + } + + fprintf(logerr, "%s: using raw device \"%s\"\n", + progname, target_names[i]); + fprintf(logerr, "%s: continuing...\n", progname); + } + } + + if ((target_fds[0] = open(target_names[0], + open_flags, 0644)) < 0) { + fprintf(logerr, + "%s: couldn't open target \"%s\"\n", + progname, target_names[0]); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if (write_last_block) { + if (fcntl(target_fds[0], F_DIOINFO, &d_info) < 0) { + fprintf(logerr, + "%s: fcntl on file \"%s\" failed.\n", + progname, target_names[0]); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + wbuf_align = MAX(wbuf_align, d_info.d_mem); + wbuf_size = MIN(d_info.d_maxiosz, wbuf_size); + wbuf_miniosize = MAX(d_info.d_miniosz, wbuf_miniosize); + } + } + + direct_io = (source_is_file && write_last_block) ? 1 : 0; + + /* initialize shared semaphore arena */ + + if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0) { + do_error("Error setting up semaphore area"); + exit(1); + } + + if (usconfig(CONF_INITUSERS, MAX_THREADS) < 0) { + do_error("Error setting up semaphore area"); + exit(1); + } + + arena_name = mktemp(ARENA_NAME); + + if (*arena_name == '\0') { + fprintf(logerr, "%s: cannot generate unique arena filename.", + progname); + fprintf(logerr, + "%s: check /usr/tmp for xfs_copy.arena* files.", + progname); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if ((arena = usinit(arena_name)) == NULL) { + fprintf(logerr, "%s: could not initialize arena.", progname); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + /* initialize locks and bufs */ + + if (thread_control_init(&glob_masks, num_targets+1) == NULL) { + fprintf(logerr, "Couldn't initialize global thread mask\n"); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if (wbuf_init(&w_buf, wbuf_size, wbuf_align, + wbuf_miniosize, 0) == NULL) { + fprintf(logerr, "Error initializing wbuf 0\n"); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + wblocks = wbuf_size / BBSIZE; + + if (wbuf_init(&btree_buf, MAX(MAX(source_blocksize, source_sectorsize), + wbuf_miniosize), wbuf_align, + wbuf_miniosize, 1) == NULL) { + fprintf(logerr, "Error initializing btree buf 1\n"); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + if ((mainwait = usnewsema(arena, 0)) == NULL) { + fprintf(logerr, "Error creating first semaphore.\n"); + fprintf(logerr, "Something's really wrong.\n"); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + /* set up sigchild signal handler */ + + sigset(SIGCLD, handler); + sighold(SIGCLD); + + /* make children */ + + if ((targ = malloc(num_targets * sizeof(t_args))) == NULL) { + fprintf(logerr, "Couldn't malloc space for thread args\n"); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + for (i = 0, tcarg = targ; i < num_targets; i++, tcarg++) { + if ((tcarg->wait = usnewsema(arena, 0)) == NULL) { + fprintf(logerr, + "error creating sproc semaphore %d\n", i); + fprintf(logerr, "Try a smaller number of targets\n"); + do_error("Aborting XFS copy - reason"); + exit(1); + } + } + + for (i = 0, tcarg = targ; i < num_targets; i++, tcarg++) { + tcarg->id = i; + tcarg->fd = target_fds[i]; + + target_states[i] = ACTIVE; + + num_threads++; + + target_pids[i] = sprocsp(begin_reader, PR_SALL, tcarg, + NULL, T_STACKSIZE); + + if ((target_pids[i]) < 0) { + fprintf(logerr, + "error creating sproc for target %d\n", i); + do_error("Aborting XFS copy - reason"); + exit(1); + } + } + + ASSERT(num_targets == num_threads); + + /* set up statistics */ + + num_ags = mp->m_sb.sb_agcount; + + source_blocks = mp->m_sb.sb_blocksize / BBSIZE + * ((__uint64_t)mp->m_sb.sb_dblocks + - (__uint64_t)mp->m_sb.sb_fdblocks + 10 * num_ags); + + for (i = 0; i < 11; i++) + barcount[i] = (source_blocks/10)*i; + + kids = num_targets; + block = (xfs_alloc_block_t *) btree_buf.data; + + for (agno = 0; agno < num_ags && kids > 0; agno++) { + /* read in first blocks of the ag */ + + read_ag_header(source_fd, agno, &w_buf, &ag_hdr, mp, + source_blocksize, source_sectorsize); + + /* reset uuid and if applicable the in_progress bit */ + + if (!duplicate_uuids) + uuid_copy(ag_hdr.xfs_sb->sb_uuid, fsid); + + if (agno == 0) { + ag_hdr.xfs_sb->sb_inprogress = 1; + } + + /* save what we need (agf) in the btree buffer */ + + bcopy(ag_hdr.xfs_agf, btree_buf.data, source_sectorsize); + ag_hdr.xfs_agf = (xfs_agf_t *) btree_buf.data; + btree_buf.length = source_blocksize; + + /* write the ag header out */ + + write_wbuf(); + + /* traverse btree until we get to the leftmost leaf node */ + + bno = ag_hdr.xfs_agf->agf_roots[XFS_BTNUM_BNOi]; + current_level = 0; + btree_levels = ag_hdr.xfs_agf->agf_levels[XFS_BTNUM_BNOi]; + + ag_end = XFS_AGB_TO_DADDR(mp, agno, + ag_hdr.xfs_agf->agf_length - 1) + + source_blocksize/BBSIZE; + + for (;;) { + /* none of this touches the w_buf buffer */ + + ASSERT(current_level < btree_levels); + + current_level++; + + btree_buf.position = pos = + (xfs_off_t)XFS_AGB_TO_DADDR(mp,agno,bno) << BBSHIFT; + btree_buf.length = source_blocksize; + + read_wbuf(source_fd, &btree_buf, mp); + block = (xfs_alloc_block_t *) ((char *) btree_buf.data + + pos - btree_buf.position); + + ASSERT(block->bb_magic == XFS_ABTB_MAGIC); + + if (block->bb_level == 0) + break;; + + ptr = XFS_BTREE_PTR_ADDR(sourceb_blocksize, xfs_alloc, + block, 1, mp->m_alloc_mxr[1]), + + bno = *ptr; + } + + /* align first data copy but don't overwrite ag header */ + + pos = w_buf.position >> BBSHIFT; + length = w_buf.length >> BBSHIFT; +#if 0 + /* + * we know pos and length are aligned, now calculate + * address of the first real ag blocks in the ag and + * make sure it's aligned properly + */ + + next_begin = XFS_AG_DADDR(mp, agno, first_agbno); + + if (next_begin % (w_buf.min_io_size >> BBSHIFT) != 0) { + /* have to align -- duplicate read_ag_header actions */ + + next_begin = rounddown(next_begin, + w_buf.min_io_size >> BBSHIFT); + + if (next_begin < pos) { + /* + * bump it back up to next boundary, + * the ag header write already copied + * the first few disk blocks + */ + + next_begin = roundup(next_begin+1, + w_buf.min_io_size >> BBSHIFT); + } + } +#else + next_begin = pos + length; +#endif + ag_begin = next_begin; + + ASSERT(w_buf.position % source_sectorsize == 0); + + /* handle the rest of the ag */ + + for (;;) { + if (block->bb_level != 0) { + fprintf(logerr, "WARNING: source filesystem inconsistent.\n"); + fprintf(stderr, "WARNING: source filesystem inconsistent.\n"); + fprintf(logerr, + " A leaf btree rec isn't a leaf. Aborting now.\n"); + fprintf(stderr, + " A leaf btree rec isn't a leaf. Aborting now.\n"); + exit(1); + } + + rec_ptr = XFS_BTREE_REC_ADDR(source_blocksize, xfs_alloc, + block, 1, mp->m_alloc_mxr[0]); + + for (i = 0; i < block->bb_numrecs; i++, rec_ptr++) { + /* calculate in daddr's */ + + begin = next_begin; + + /* + * protect against pathological case of a + * hole right after the ag header in a + * mis-aligned case + */ + + if (begin < ag_begin) + begin = ag_begin; + + /* + * round size up to ensure we copy a + * range bigger than required + */ + + sizeb = XFS_AGB_TO_DADDR(mp, agno, + rec_ptr->ar_startblock) - begin; + size = roundup(sizeb << BBSHIFT, wbuf_miniosize); + +#if 0 + if (w_buf.min_io_size != wbuf_miniosize) { + fprintf(stderr, + "assert error: w_buf.min_io_size = %d, wbuf_miniosize = %d\n", + w_buf.min_io_size, + wbuf_miniosize); + killall(); + abort(); + } +#endif + if (size > 0) { + /* copy extent */ + + w_buf.position = (xfs_off_t) begin + << BBSHIFT; + + while (size > 0) { + /* + * let lower layer do alignment + */ + if (size > w_buf.size) { + w_buf.length = w_buf.size; + size -= w_buf.size; + sizeb -= wblocks; + numblocks += wblocks; + } else { + w_buf.length = size; + numblocks += sizeb; + size = 0; + } + + read_wbuf(source_fd, &w_buf, mp); +#ifndef NO_COPY + write_wbuf(); +#endif + w_buf.position += w_buf.length; + + while (howfar < 10 && numblocks + > barcount[howfar]) { + bump_bar(howfar); + howfar++; + } + } + } + + /* round next starting point down */ + + new_begin = XFS_AGB_TO_DADDR(mp, agno, + rec_ptr->ar_startblock + + rec_ptr->ar_blockcount); + next_begin = rounddown(new_begin, + w_buf.min_io_size >> BBSHIFT); + } + + if (block->bb_rightsib == NULLAGBLOCK) + break; + + /* read in next btree record block */ + + btree_buf.position = pos = (xfs_off_t)XFS_AGB_TO_DADDR(mp, + agno, block->bb_rightsib) << BBSHIFT; + btree_buf.length = source_blocksize; + + /* let read_wbuf handle alignment */ + + read_wbuf(source_fd, &btree_buf, mp); + + block = (xfs_alloc_block_t *) ((char *) btree_buf.data + + pos - btree_buf.position); + + ASSERT(block->bb_magic == XFS_ABTB_MAGIC); + } + + /* + * write out range of used blocks after last range + * of free blocks in AG + */ + if (next_begin < ag_end) { + begin = next_begin; + + sizeb = ag_end - begin; + size = roundup(sizeb << BBSHIFT, wbuf_miniosize); + + if (size > 0) { + /* copy extent */ + + w_buf.position = (xfs_off_t) begin + << BBSHIFT; + + while (size > 0) { + /* + * let lower layer do alignment + */ + if (size > w_buf.size) { + w_buf.length = w_buf.size; + size -= w_buf.size; + sizeb -= wblocks; + numblocks += wblocks; + } else { + w_buf.length = size; + numblocks += sizeb; + size = 0; + } + + read_wbuf(source_fd, &w_buf, mp); +#ifndef NO_COPY + write_wbuf(); +#endif + w_buf.position += w_buf.length; + + while (howfar < 10 && numblocks + > barcount[howfar]) { + bump_bar(howfar); + howfar++; + } + } + } + } + } + + if (kids > 0) { + if (write_last_block) + if (ftruncate64(target_fds[0], mp->m_sb.sb_dblocks * + source_blocksize)) { + fprintf(logerr, "%s: cannot grow data section.\n", progname); + fprintf(stderr, "%s: cannot grow data section.\n", progname); + do_error("Aborting XFS copy - reason"); + exit(1); + } + + /* reread and rewrite the first ag */ + + read_ag_header(source_fd, 0, &w_buf, &ag_hdr, mp, + source_blocksize, source_sectorsize); + + ag_hdr.xfs_sb->sb_inprogress = 0; + + if (!duplicate_uuids) + uuid_copy(ag_hdr.xfs_sb->sb_uuid, fsid); + + write_wbuf(); + bump_bar(10); + } + + check_errors(); + killall(); + + return 0; +} diff -rNu linux-2.4.7/cmd/xfsdump/debian/CVS/Entries linux-2.4-xfs/cmd/xfsdump/debian/CVS/Entries --- linux-2.4.7/cmd/xfsdump/debian/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/debian/CVS/Entries Thu Jul 5 11:44:00 2001 @@ -0,0 +1,6 @@ +/Makefile/1.1/Mon Jan 15 04:35:39 2001/-ko/ +/changelog/1.6/Tue May 15 04:59:22 2001/-ko/ +/control/1.5/Tue May 15 04:59:22 2001/-ko/ +/copyright/1.1/Mon Jan 15 04:35:39 2001/-ko/ +/rules/1.4/Wed May 9 07:18:58 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/debian/CVS/Repository linux-2.4-xfs/cmd/xfsdump/debian/CVS/Repository --- linux-2.4.7/cmd/xfsdump/debian/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/debian/CVS/Repository Thu Jul 5 11:44:00 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/debian diff -rNu linux-2.4.7/cmd/xfsdump/debian/CVS/Root linux-2.4-xfs/cmd/xfsdump/debian/CVS/Root --- linux-2.4.7/cmd/xfsdump/debian/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/debian/CVS/Root Thu Jul 5 11:44:00 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/debian/Makefile linux-2.4-xfs/cmd/xfsdump/debian/Makefile --- linux-2.4.7/cmd/xfsdump/debian/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/debian/Makefile Sun Jan 14 22:35:39 2001 @@ -0,0 +1,40 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LSRCFILES = changelog control copyright rules + +default install install-dev: + +include $(BUILDRULES) diff -rNu linux-2.4.7/cmd/xfsdump/debian/changelog linux-2.4-xfs/cmd/xfsdump/debian/changelog --- linux-2.4.7/cmd/xfsdump/debian/changelog Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/debian/changelog Mon May 14 23:59:22 2001 @@ -0,0 +1,36 @@ +xfsdump (1.0.9) unstable; urgency=low + + * Correctly [xfs]restore the suid and guid mode bits + + -- Nathan Scott Tue, 15 May 2001 14:40:03 +1000 + +xfsdump (1.0.8) unstable; urgency=low + + * Add a build dependency on xfslibs-dev 1.2.5 (closes: #97097) + + -- Nathan Scott Sat, 12 May 2001 08:52:27 +1000 + +xfsdump (1.0.7) unstable; urgency=low + + * Fix numerous warnings, remove last -Wall filter + * Support realtime files in dump/restore + * Cleanup arch-specific code, esp. the byteswab routines + * Fix bug dumping to remote tape device with given user + + -- Nathan Scott Wed, 9 May 2001 15:23:23 +1000 + +xfsdump (1.0.6) unstable; urgency=low + + * Remove spurious warnings when dumping quota information. + + -- Nathan Scott Tue, 1 May 2001 15:32:24 +1000 + +xfsdump (1.0.5) unstable; urgency=low + + * Initial release (closes: #83832). + + -- Nathan Scott Wed, 25 Apr 2001 12:19:15 +1000 + +Local variables: +mode: debian-changelog +End: diff -rNu linux-2.4.7/cmd/xfsdump/debian/control linux-2.4-xfs/cmd/xfsdump/debian/control --- linux-2.4.7/cmd/xfsdump/debian/control Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/debian/control Mon May 14 23:59:22 2001 @@ -0,0 +1,27 @@ +Source: xfsdump +Section: admin +Priority: optional +Maintainer: Nathan Scott +Build-Depends: uuid-dev, xfslibs-dev (>= 1.2.5), attr-dev, autoconf, debmake +Standards-Version: 3.1.1 + +Package: xfsdump +Depends: ${shlibs:Depends} +Suggests: xfsprogs, attr +Architecture: any +Description: Administrative utilities for the XFS filesystem + The xfsdump package contains xfsdump, xfsrestore and a number of + other administrative utilities for managing XFS filesystems. + . + xfsdump examines files in a filesystem, determines which need to be + backed up, and copies those files to a specified disk, tape or other + storage medium. It uses XFS-specific directives for optimizing the + dump of an XFS filesystem, and also knows how to backup XFS extended + attributes. Backups created with xfsdump are "endian safe" and can + thus be transfered between Linux machines of different architectures + and also between IRIX machines. + . + xfsrestore performs the inverse function of xfsdump; it can restore a + full backup of a filesystem. Subsequent incremental backups can then + be layered on top of the full backup. Single files and directory + subtrees may be restored from full or partial backups. diff -rNu linux-2.4.7/cmd/xfsdump/debian/copyright linux-2.4-xfs/cmd/xfsdump/debian/copyright --- linux-2.4.7/cmd/xfsdump/debian/copyright Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/debian/copyright Sun Jan 14 22:35:39 2001 @@ -0,0 +1,14 @@ +This package was debianized by Nathan Scott nathans@debian.org on +Sun, 19 Nov 2000 07:37:09 -0500. + +It was downloaded from ftp://oss.sgi.com/projects/xfs/download/ + +Copyright: + +Copyright (C) 2000 Silicon Graphics, Inc. + +You are free to distribute this software under the terms of +the GNU General Public License. +On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL file. + diff -rNu linux-2.4.7/cmd/xfsdump/debian/rules linux-2.4-xfs/cmd/xfsdump/debian/rules --- linux-2.4.7/cmd/xfsdump/debian/rules Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/debian/rules Wed May 9 02:18:58 2001 @@ -0,0 +1,47 @@ +#!/usr/bin/make -f + +package=xfsdump + +dirtmp = debian/tmp +pkgtmp = DIST_ROOT=`pwd`/$(dirtmp); export DIST_ROOT; +stdenv = GZIP=-q; export GZIP; +options = DEBUG=-DNDEBUG; DISTRIBUTION=debian; export DEBUG DISTRIBUTION; +checkdir = test -f debian/rules + +build: built +built: + @echo "== dpkg-buildpackage: build" 1>&2 + $(checkdir) + autoconf + $(options) ./configure + $(MAKE) default + touch built + +clean: + @echo "== dpkg-buildpackage: clean" 1>&2 + $(checkdir) + -rm -f built + $(MAKE) distclean + -rm -rf $(dirtmp) debian/*substvars debian/files* + +binary-indep: + +binary-arch: checkroot built + @echo "== dpkg-buildpackage: binary-arch" 1>&2 + $(checkdir) + -rm -rf $(dirtmp) $(dirdev) + $(pkgtmp) $(MAKE) -C . install + $(pkgtmp) $(MAKE) -C build src-manifest + @echo "== dpkg-buildpackage: debstd" 1>&2 + $(stdenv) debstd -m + dpkg-gencontrol -isp -p$(package) + chown -R root.root $(dirtmp) + chmod -R go=rX $(dirtmp) + dpkg --build $(dirtmp) .. + +binary: binary-indep binary-arch + +checkroot: + test 0 -eq `id -u` + +.PHONY: binary binary-arch binary-indep clean checkroot diff -rNu linux-2.4.7/cmd/xfsdump/doc/CHANGES linux-2.4-xfs/cmd/xfsdump/doc/CHANGES --- linux-2.4.7/cmd/xfsdump/doc/CHANGES Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/doc/CHANGES Thu Jul 5 03:42:14 2001 @@ -0,0 +1,43 @@ +xfsdump-1.0.10 (5 July 2001) + - produce librmt warning messages from xfsdump/xfsrestore + without needing to set an environment variable + +xfsdump-1.0.9 (15 May 2001) + - correctly [xfs]restore the suid and guid mode bits + +xfsdump-1.0.8 (12 May 2001) + - added build dependency for Debian on latest devel package + +xfsdump-1.0.7 (07 May 2001) + - fix warnings, remove last -Wall filter + - configure script default man path now /usr/share/man + - support realtime files in dump/restore + - cleanup arch-specific code, esp. the byteswab routines + - as a result, move to -O1 as default for extern inlines + - fix bug dumping to remote tape device with given user + +xfsdump-1.0.6 (01 May 2001) + - remove spurious warnings when dumping quota information + +xfsdump-1.0.5 (09 April 2001) + - fix use of an uninitialised variable in dump + - fix a number of compiler warnings + +xfsdump-1.0.4 (03 April 2001) + - added xfsdump support for dumping quota information + +xfsdump-1.0.3 (28 March 2001) + - minor rpm spec file changes + - added xfsdq and xfsrq for dumping quota information + +xfsdump-1.0.2 (10 January 2001) + - support extended attributes in xfsdump and xfsrestore + +xfsdump-1.0.1 (30 January 2001) + - minor rpm and deb packaging work + +xfsdump-1.0.0 (15 January 2001) + - dump, restore, fsr and co. abstracted from xfs-cmds package + - completed Debian packaging + - late beta code + diff -rNu linux-2.4.7/cmd/xfsdump/doc/COPYING linux-2.4-xfs/cmd/xfsdump/doc/COPYING --- linux-2.4.7/cmd/xfsdump/doc/COPYING Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/doc/COPYING Sun Jan 14 22:35:39 2001 @@ -0,0 +1,346 @@ +---------------------------------------------------------------------- + + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +---------------------------------------------------------------------- diff -rNu linux-2.4.7/cmd/xfsdump/doc/CVS/Entries linux-2.4-xfs/cmd/xfsdump/doc/CVS/Entries --- linux-2.4.7/cmd/xfsdump/doc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/doc/CVS/Entries Thu Jul 5 11:44:01 2001 @@ -0,0 +1,7 @@ +/CHANGES/1.11/Thu Jul 5 08:42:14 2001/-ko/ +/COPYING/1.1/Mon Jan 15 04:35:39 2001/-ko/ +/INSTALL/1.1/Mon Jan 15 04:35:39 2001/-ko/ +/Makefile/1.2/Thu Jan 25 06:56:37 2001/-ko/ +/PORTING/1.1/Mon Jan 15 04:35:39 2001/-ko/ +/README.xfsdump/1.3/Thu Jul 5 08:42:14 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/doc/CVS/Repository linux-2.4-xfs/cmd/xfsdump/doc/CVS/Repository --- linux-2.4.7/cmd/xfsdump/doc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/doc/CVS/Repository Thu Jul 5 11:44:00 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/doc diff -rNu linux-2.4.7/cmd/xfsdump/doc/CVS/Root linux-2.4-xfs/cmd/xfsdump/doc/CVS/Root --- linux-2.4.7/cmd/xfsdump/doc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/doc/CVS/Root Thu Jul 5 11:44:00 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/doc/INSTALL linux-2.4-xfs/cmd/xfsdump/doc/INSTALL --- linux-2.4.7/cmd/xfsdump/doc/INSTALL Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/doc/INSTALL Sun Jan 14 22:35:39 2001 @@ -0,0 +1,52 @@ +This document describes how to configure and build the open source XFS +commands and utilites ("xfsdump") from source, and how to install and +run them. + +0. If you have the binary rpm, simply install it and skip to step 2 (below). + The rpm command to do this is: + # rpm -Uvh xfsdump + + The Debian command to do this is: + # dpkg -i xfsdump + or, if you have apt configured (don't need the binary package): + # apt-get install xfsdump + +1. Configure, build and install the package + + The xfsdump package uses autoconf/configure and expects a GNU build + environment (your platform must at least have both autoconf and gmake). + You will also need to have installed either the e2fsprogs-devel package + (on an RPM based system) or the uuid-dev package (on a Debian system) + as some of the commands make use of the UUID library provided by these. + + If you just want to spin an RPM and/or tar file, use the Makepkgs + script in the top level directory. This will configure and build + the package and leave binary and src RPMs in the build/rpm + directory. It will also leave a tar file in the build/tar + directory. + + # ./Makepkgs verbose + + If you want to build the package and install it manually, use the + following steps : + + # make configure (or run autoconf; ./configure) + # make + # su root + # make install + + Note that there are so many "install" variants out there that we + wrote our own script (see "install-sh" in the top level directory). + + If you wish to turn off debugging asserts in the command build and + turn on the optimizer then set the shell environment variables: + + OPTIMIZER=-O + DEBUG=-DNDEBUG + + before running make configure or Makepkgs. + +2. How to Contribute + + See the README file in this directory for details about how to + contribute to the XFS project. diff -rNu linux-2.4.7/cmd/xfsdump/doc/Makefile linux-2.4-xfs/cmd/xfsdump/doc/Makefile --- linux-2.4.7/cmd/xfsdump/doc/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/doc/Makefile Thu Jan 25 00:56:37 2001 @@ -0,0 +1,52 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LSRCFILES = INSTALL PORTING CHANGES COPYING README.xfsdump +LDIRT = *.gz + +default: $(CMDTARGET) CHANGES.gz + +include $(BUILDRULES) + +CHANGES.gz: + $(ZIP) --best -c < CHANGES > $@ + +install: default + $(INSTALL) -m 755 -d $(PKG_DOC_DIR) +ifneq ($(PKG_DISTRIBUTION), debian) + $(INSTALL) -m 644 COPYING $(PKG_DOC_DIR) +endif + $(INSTALL) -m 644 PORTING CHANGES.gz README.xfsdump $(PKG_DOC_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/xfsdump/doc/PORTING linux-2.4-xfs/cmd/xfsdump/doc/PORTING --- linux-2.4.7/cmd/xfsdump/doc/PORTING Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/doc/PORTING Sun Jan 14 22:35:39 2001 @@ -0,0 +1,86 @@ + +1. unpack the source tarball and cd to the resulting dir + +2. # autoconf + this reads configure.in and generates the ./configure script + +3. # ./configure + this probes your system and then, for each "file" named + in the AC_OUTPUT() macro near the end of configure.in, + read "file".in and generate "file". Variables named @somevariable@ + will be substituted with literal values. + +4. step (3) produces several files. These files are generated by + configure from their respective .in file in the same directory. + You should have a read of these generated files and diff them + against their respective .in files to see what was substituted + by configure. + + src/include/builddefs + common definitions for the build environment. This is included + by all Makefiles, in conjunction with src/include/buildrules. + Note that most autoconf/configure build environments generate + Makefile (from Makefile.in) in every src dir. Instead, we + generate builddefs, and then include it in every Makefile. + + src/include/platform_defs.h + header containing conditional macros defining the C run-time + environment discovered by the configure script. + +5. read some or all of the GNU tool chain documentation + gmake Table Of Contents : + http://www.delorie.com/gnu/docs/make/make_toc.html + gmake Quick Reference section : + http://www.delorie.com/gnu/docs/make/make_120.html + Autoconf : + http://www.delorie.com/gnu/docs/autoconf/autoconf_toc.html + gcc/g++ : + http://www.delorie.com/gnu/docs/gcc/gcc_toc.html + +6. Makefiles and build environment + First have a look at some Makefiles + + example using SUBDIRS : xfsdump/Makefile + example static library: xfsdump/librmt/Makefile + example command : xfsdump/fsr/Makefile + + All Makefiles must define TOPDIR as the root of the project. This + allows other stuff to be found relative to $(TOPDIR). + + All Makefiles should have the following structure, which is + much like commondefs and commonrules in the IRIX build environment, e.g. + + # ---------------------------------------------------------------------- + # TOPDIR must point to the root of the project + # The builddefs file defines lots of things. Read it. + TOPDIR = .. + include $(TOPDIR)/include/builddefs + + # first rule should always be "default" + default : sometarget + commands to build targets, if necessary + + # $(BUILDRULES) is defined in builddefs and includes rules for + # descending subdirs, building targets and installation rules + include $(BUILDRULES) + + install : default + $(INSTALL) sometargets somewhere + # ---------------------------------------------------------------------- + +7. packaging + + # ./Makepkgs + this script generates all of the packages supported - each has a + subdirectory below xfsdump/build where knowledge specific to + each package type is maintained. + + The script produces logs of each stage of the build (this info is + also echoed to the screen when the "verbose" option is provided): + + xfsdump/Logs/configure - `autoconf; ./configure' output + xfsdump/Logs/default - `make default' output + xfsdump/Logs/dist - `make build dist' output + + On successful completion, the script echoes the names of packages + successfully generated. diff -rNu linux-2.4.7/cmd/xfsdump/doc/README.xfsdump linux-2.4-xfs/cmd/xfsdump/doc/README.xfsdump --- linux-2.4.7/cmd/xfsdump/doc/README.xfsdump Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/doc/README.xfsdump Thu Jul 5 03:42:14 2001 @@ -0,0 +1,150 @@ +--------------------------------- +Notes on using xfsdump/xfsrestore +--------------------------------- + +Contents +---------- +Disclaimer +Example usage +Testing of xfsdump +Command Option Changes from IRIX xfsdump to Linux +Notes on tape block sizes +Restoring an IRIX dump tape onto a Linux xfs filesystem +TODO List + + +Disclaimer +---------- +Testing of this software has been done using the Linux +scsi tape driver only. If one is using a different tape +driver one may need to use the -m option which makes +less assumptions about the tape driver's capabilities. + +Example usage +------------- + +1. Dumping a filesystem to a dump file: + xfsdump -f dump_file -L session_label -M media_label file_system + e.g. xfsdump -f ./mydump -L 'session1' -M 'media1" /mnt/xfs0 + +2. Restoring a filesystem from a dump file: + xfsrestore -f ./mydump -L session_label dest_dir + e.g. xfsrestore -f ./mydump -L 'session1' ./myfilesystem + +3. Dumping a filesystem to a dump tape: + xfsdump -f tapedevice -L session_label -M media_label file_system + e.g. xfsdump -f /dev/st0 -L 'session1' -M 'media1" /mnt/xfs0 + +4. Restoring a filesystem from a dump tape: + xfsrestore -f tapedevice -L session_label dest_dir + e.g. xfsrestore -f /dev/st0 -L 'session1' ./myfilesystem + + +Testing of xfsdump +------------------ + +There are scripts in the stress directory which +verify that xfsdump and xfsrestore are working. +Use "grep xfsdump group" to see which tests they are. + +Stress/common.config needs to be updated for one's host with: + SCRATCH_DEV - device for test filesystem + SCRATCH_MNT - mount point for test filesystem + TAPE_DEV - tape device e.g. /dev/st0 + RMT_TAPE_DEV - remote tape device + RMT_IRIXTAPE_DEV - remote IRIX tape device + RMT_TAPE_USER - remote user for tape device +The first two above are absolutely necessary. +The tape device variables are only needed if one wants +to test out that particular functionality of xfsdump/xfsrestore. +The RMT_* variables are needed for testing remote tape capability. + +With the common.config updated one should be able to run +as root: +# ./check -g xfsdump + + +Command Option Changes from IRIX xfsdump to Linux +------------------------------------------------- + +Xfsdump on Linux has been changed (from the IRIX version) +to allow the -b option to be used without the -m option. +In IRIX, the block size could only be specified if one selected +the minimum remote (-m) option. This means that one can now +override the block size to use for dumping and restoring +from tape, with an upper limit of 2Mb. + +The semantics of the -m option has also changed. In IRIX, this +option would only take effect for remote tape specifications. +In the Linux version, the -m option can be used for local tapes +where the tape device only has a restricted set of mt(1) commands. + +The -q option has been added to tell xfsdump/xfsrestore explicitly +that a QIC tape drive is being used. In IRIX, an i/o control system +call is issued which returns the subtype of tape device being used; +for example "TPQIC*". However, there is no direct equivalent in Linux. + + +Notes on tape block sizes +------------------------- +The IRIX version of xfsdump has typically used 2Mb tape blocks +for writing local dumps to tape. The size is actually calculated by +getting the maximum block size supported from the tape device +($mt blksize) and capping it at 2Mb (i.e. min(2Mb, blk-size-max)). +On Linux, the maximum block size is not exported by the scsi tape driver, +and has been set to have a default of 1Mb. + +In some experiments with a 2Mb block size, we found that sometimes +read and writes using the scsi tape driver would fail: + /tmp/xfsdump: tape op: writing 2097152 bytes + /tmp/xfsdump: tape op write of 2097152 bytes failed: errno == 75 (Value too large for defined data type) +It apparently fails when scsi_init_malloc() fails with EOVERFLOW. +According to Kai Makisara, the tape drive supports scatter/gather +and has a default of 16 segments of 128K or 256K with the +first segment of only 32K. So with 128K segments we have, +15 * 128k + 32 K = 1952K (short of 2Mb). +Thus in order to use large block buffers requires one +to increase the number of segments, "max_sg_segs". +A suggested number to use is 64 segments (it apparently depends +on the scsi adapter, but it has been suggested that most should +handle at least 64). +This can be done by either: + - insmod st max_sg_segs=64 + - add to /etc/modules.conf: + options st max_sg_segs=64 + - add to boot command line: + st=max_sg_segs:64 + +The IRIX version of xfsdump has typically used 240K tape blocks +for writing remote dumps to tape. + +The Linux ext2 dump program and tar(1) would not have this problem +as they use 10K default blocks which can be increased using the +-b option (up to a maximum of 64K blocks for dump(1)). + + +Restoring an IRIX dump tape onto a Linux xfs filesystem +------------------------------------------------------- + +To restore an IRIX xfs dump tape, one will need to specify +the blocksize that was used by giving a -b option. + +Examples: + +For 2Mb blocks: +xfsrestore -f /dev/st0 -b 2097152 -L 'session1' dest_dir + +For 240K blocks (a remotely dumped tape): +xfsrestore -f /dev/st0 -b 245760 -L 'session1' dest_dir + +If errors such as: + /tmp/xfsdump: tape op write of 2097152 bytes failed: errno == 75 (Value too large for defined data type) +occur, then one may need to increase the number of segments used +by the scsi tape driver (max_sg_segs) as mentioned above. + + +TODO List +--------- + +* turn on dmapi handling when dmapi supported +* fix up running multi-threaded diff -rNu linux-2.4.7/cmd/xfsdump/dump/CVS/Entries linux-2.4-xfs/cmd/xfsdump/dump/CVS/Entries --- linux-2.4.7/cmd/xfsdump/dump/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/dump/CVS/Entries Thu Jul 5 11:44:03 2001 @@ -0,0 +1,10 @@ +/Makefile/1.3/Fri Feb 9 07:45:14 2001/-ko/ +/content.c/1.5/Wed May 9 07:18:58 2001/-ko/ +/getopt.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/hsmapi.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/hsmapi.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/inomap.c/1.3/Thu Jul 5 08:42:14 2001/-ko/ +/inomap.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/var.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/var.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/dump/CVS/Repository linux-2.4-xfs/cmd/xfsdump/dump/CVS/Repository --- linux-2.4.7/cmd/xfsdump/dump/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/dump/CVS/Repository Thu Jul 5 11:44:01 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/dump diff -rNu linux-2.4.7/cmd/xfsdump/dump/CVS/Root linux-2.4-xfs/cmd/xfsdump/dump/CVS/Root --- linux-2.4.7/cmd/xfsdump/dump/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/dump/CVS/Root Thu Jul 5 11:44:01 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/dump/Makefile linux-2.4-xfs/cmd/xfsdump/dump/Makefile --- linux-2.4.7/cmd/xfsdump/dump/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/dump/Makefile Fri Feb 9 01:45:14 2001 @@ -0,0 +1,140 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LIBRMT = $(TOPDIR)/librmt/librmt.a + +COMMINCL = \ + arch_xlate.h \ + cldmgr.h \ + content.h \ + content_common.h \ + content_inode.h \ + dlog.h \ + drive.h \ + exit.h \ + fs.h \ + getdents.h \ + global.h \ + lock.h \ + media.h \ + mlog.h \ + openutil.h \ + path.h \ + qlock.h \ + ring.h \ + stkchk.h \ + stream.h \ + types.h \ + util.h \ + sproc.h \ + attr.h \ + rec_hdr.h + +INVINCL = \ + inventory.h \ + inv_priv.h + +INVCOMMON = \ + inv_api.c \ + inv_core.c \ + inv_fstab.c \ + inv_idx.c \ + inv_mgr.c \ + inv_stobj.c + +COMMON = \ + arch_xlate.c \ + cldmgr.c \ + content_common.c \ + dlog.c \ + drive.c \ + drive_scsitape.c \ + drive_simple.c \ + drive_minrmt.c \ + fs.c \ + getdents.c \ + global.c \ + lock.c \ + main.c \ + mlog.c \ + openutil.c \ + qlock.c \ + path.c \ + ring.c \ + stkchk.c \ + stream.c \ + util.c \ + sproc.c \ + attr.c + +LOCALS = \ + content.c \ + inomap.c \ + var.c + +#LOCALS += hsmapi.c +#LOCALINCL += hsmapi.h + +LOCALINCL = \ + getopt.h \ + inomap.h \ + var.h + +CMDTARGET = xfsdump +CMDDEPS = $(LIBHANDLE) $(LIBATTR) + +CFILES = $(COMMON) $(INVCOMMON) $(LOCALS) +HFILES = $(LOCALINCL) +LINKS = $(COMMINCL) $(COMMON) $(INVINCL) $(INVCOMMON) +LDIRT = $(LINKS) +LLDLIBS = $(LIBHANDLE) $(LIBUUID) $(LIBRMT) $(LIBATTR) + +LCFLAGS = -DDUMP -DRMT -DBASED -DDOSOCKS -DINVCONVFIX -DSIZEEST -DPIPEINVFIX -DEXTATTR +#LCFLAGS += -DDMEXTATTR + +default: $(LINKS) $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_BIN_DIR) +install-dev: + +$(COMMINCL) $(COMMON): + @$(RM) $@; $(LN_S) ../common/$@ $@ + +$(INVINCL) $(INVCOMMON): + @$(RM) $@; $(LN_S) ../inventory/$@ $@ diff -rNu linux-2.4.7/cmd/xfsdump/dump/content.c linux-2.4-xfs/cmd/xfsdump/dump/content.c --- linux-2.4.7/cmd/xfsdump/dump/content.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/dump/content.c Wed May 9 02:18:58 2001 @@ -0,0 +1,6676 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef EXTATTR +#include +#include "attr.h" +#endif /* EXTATTR */ + +#ifdef DMEXTATTR +#include "hsmapi.h" +#endif /* DMEXTATTR */ + +#include "exit.h" +#include "types.h" +#include "path.h" +#include "util.h" +#include "lock.h" +#include "qlock.h" +#include "mlog.h" +#include "dlog.h" +#include "getopt.h" +#include "stream.h" +#include "cldmgr.h" +#include "global.h" +#include "drive.h" +#include "media.h" +#include "content.h" +#include "content_common.h" +#include "content_inode.h" +#include "fs.h" +#include "inomap.h" +#include "var.h" +#include "inventory.h" +#include "getdents.h" +#include "arch_xlate.h" + +#undef SYNCDIR +#define SYNCDIR + +/* legal range of dump levels + */ +#define LEVEL_DEFAULT 0 +#define LEVEL_MAX 9 + +/* ordinary files as big or bigger than this many pages will be + * preceeded in the dump by enough padding to align the first byte + * of that file's data to a page boundary + */ +#define PGALIGNTHRESH 8 + + +/* structure definitions used locally ****************************************/ + +/* number of bstats bstat_iter fetches at a time + */ +#define BSTATBUFLEN 4096 + +/* if the source file system type can't be determined, assume it is this + */ +#define FS_DEFAULT "xfs" + +/* marks consist of a opaque drive layer cookie and a startpoint. + * the drive layer requires that it be passed a pointer to a drive_markrec_t. + * we tack on content-specific baggage (startpt_t). this works because we + * allocate and free mark_t's here. + */ +struct mark { + drive_markrec_t dm; + startpt_t startpt; +}; + +typedef struct mark mark_t; + +/* Media_mfile_begin( ) entry state. + */ +enum bes { BES_INIT, /* in the beginning */ + BES_ENDOK, /* last media file successfully flushed to media */ + BES_ENDEOM, /* hit EOM while writing last media file */ + BES_INVAL }; /* to assert protocol being followed */ + +typedef enum bes bes_t; + +/* per-stream context + */ +struct context { + filehdr_t *cc_filehdrp; + /* pre-allocated buffer: heads each dumped file + */ + extenthdr_t *cc_extenthdrp; + /* pre-allocated buffer: heads each dumped file extent + */ + void *cc_inomap_state_contextp; + /* pre-allocated context to speed inomap iteration + */ + char *cc_getdentsbufp; + size_t cc_getdentsbufsz; + /* pre-allocated buffer for getdents() syscall + */ + char *cc_mdirentbufp; + size_t cc_mdirentbufsz; + /* pre-allocated buffer for on-media dirent + */ +#ifdef EXTATTR + char *cc_extattrlistbufp; + size_t cc_extattrlistbufsz; + /* pre-allocated buffer for retrieving a + * list of extended file attributes + */ + attr_multiop_t *cc_extattrrtrvarrayp; + size_t cc_extattrrtrvarraylen; + /* pre-allocated array of ops for retrieving the + * values for a list of extended file attributes + */ + char *cc_extattrdumpbufp; + size_t cc_extattrdumpbufsz; + /* pre-allocated buffer for dumping the names and + * values for a list of extended file attributes + */ +#endif EXTATTR +#ifdef DMEXTATTR + hsm_f_ctxt_t *cc_hsm_f_ctxtp; + /* pre-allocated HSM context used for holding HSM + state information about a file across subroutine + calls. + */ +#endif /* DMEXTATTR */ + char *cc_readlinkbufp; + size_t cc_readlinkbufsz; + /* pre-allocated buffer for readlink() + */ + off64_t cc_mfilesz; + /* total bytes dumped to media file + */ + size_t cc_markscommitted; + /* number of marks committed in mfile. only useful + * info is if greater than zero. + */ + xfs_ino_t cc_stat_lastino; + /* monotonic strm nondir ino dumped + */ + bool_t cc_completepr; + /* set if stream completely dumped. useful for + * determining if dump was interrupted + */ + bool_t cc_Media_useterminatorpr; + /* true if stream terminators are expected and + * will be used + */ + char *cc_Media_firstlabel; + /* optional command line media label. only used + * for first media object in stream, and only if + * media object does not already have a label + */ + bes_t cc_Media_begin_entrystate; + /* Media_mfile_begin context entry state + */ +}; + +typedef struct context context_t; + +/* extent group context, used by dump_file() + */ +#define BMAP_LEN 512 + +struct extent_group_context { + getbmapx_t eg_bmap[ BMAP_LEN ]; + getbmapx_t *eg_nextbmapp; /* ptr to the next extent to dump */ + getbmapx_t *eg_endbmapp; /* to detect extent exhaustion */ + intgen_t eg_fd; /* file desc. */ + intgen_t eg_bmapix; /* debug info only, not used */ + intgen_t eg_gbmcnt; /* debug, counts getbmapx calls for ino*/ +}; + +typedef struct extent_group_context extent_group_context_t; + + +/* minimum getdents( ) buffer size + */ +#define GETDENTSBUF_SZ_MIN ( 2 * pgsz ) + + +#ifdef EXTATTR +/* minimum sizes for extended attributes buffers + */ +#define EXTATTR_LISTBUF_SZ ( 4 * pgsz ) +#define EXTATTR_RTRVARRAY_LEN ( 1 * pgsz ) +#define EXTATTR_DUMPBUF_SZ ( 4 * pgsz ) +#endif /* EXTATTR */ + +/* per-drive status descriptor + */ +struct pds { + enum { PDS_NULL, /* per-drive activity not begun */ + PDS_INOMAP, /* dumping inomap */ + PDS_DIRRENDEZVOUS, /* waiting to dump dirs */ + PDS_DIRDUMP, /* dumping dirs */ + PDS_NONDIR, /* dumping nondirs */ + PDS_INVSYNC, /* waiting for inventory */ + PDS_INVDUMP, /* dumping session inventory */ + PDS_TERMDUMP /* writing stream terminator */ + } pds_phase; + size64_t pds_dirdone; /* number of directories done */ +}; + +typedef struct pds pds_t; + +/* declarations of externally defined global symbols *************************/ + +extern void usage( void ); +extern bool_t preemptchk( int ); +extern char *homedir; +extern bool_t miniroot; +extern bool_t pipeline; +extern bool_t stdoutpiped; +extern char *sistr; +extern size_t pgsz; + + +/* forward declarations of locally defined static functions ******************/ + +/* file dumpers + */ +static rv_t dump_dirs( ix_t strmix, + xfs_bstat_t *bstatbufp, + size_t bstatbuflen ); +#ifdef SYNCDIR +static rv_t dump_dirs_rendezvous( void ); +#endif /* SYNCDIR */ +static rv_t dump_dir( ix_t strmix, + jdm_fshandle_t *, + intgen_t, + xfs_bstat_t * ); +static rv_t dump_file( void *, + jdm_fshandle_t *, + intgen_t, + xfs_bstat_t * ); +static rv_t dump_file_reg( drive_t *drivep, + context_t *contextp, + content_inode_hdr_t *scwhdrp, + jdm_fshandle_t *, + xfs_bstat_t * ); +static rv_t dump_file_spec( drive_t *drivep, + context_t *contextp, + jdm_fshandle_t *, + xfs_bstat_t * ); +static rv_t dump_filehdr( drive_t *drivep, + context_t *contextp, + xfs_bstat_t *, + off64_t, + intgen_t ); +static rv_t dump_extenthdr( drive_t *drivep, + context_t *contextp, + int32_t, + int32_t, + off64_t, + off64_t ); +static rv_t dump_dirent( drive_t *drivep, + context_t *contextp, + xfs_bstat_t *, + xfs_ino_t, + u_int32_t, + char *, + size_t ); +static rv_t init_extent_group_context( jdm_fshandle_t *, + xfs_bstat_t *, + extent_group_context_t * ); +static void cleanup_extent_group_context( extent_group_context_t * ); +static rv_t dump_extent_group( drive_t *drivep, + context_t *contextp, + xfs_bstat_t *, + extent_group_context_t *, + off64_t, + off64_t, + bool_t, + off64_t *, + off64_t *, + bool_t * ); +static bool_t dump_session_inv( drive_t *drivep, + context_t *contextp, + media_hdr_t *mwhdrp, + content_inode_hdr_t *scwhdrp ); +static rv_t write_pad( drive_t *drivep, size_t ); + +static void mark_callback( void *, drive_markrec_t *, bool_t ); + +static void inv_cleanup( void ); +static void dump_terminator( drive_t *drivep, + context_t *contextp, + media_hdr_t *mwhdrp ); +static rv_t Media_mfile_begin( drive_t *drivep, + context_t *contextp, + bool_t intr_allowed ); +static rv_t Media_mfile_end( drive_t *drivep, + context_t *contextp, + media_hdr_t *mwhdrp, + off64_t *ncommittedp, + bool_t hit_eom ); +static bool_t Media_prompt_overwrite( drive_t *drivep ); +static rv_t Media_erasechk( drive_t *drivep, + intgen_t dcaps, + bool_t intr_allowed, + bool_t prevmediapresentpr ); +static bool_t Media_prompt_erase( drive_t *drivep ); +static char *Media_prompt_label( drive_t *drivep, char *bufp, size_t bufsz ); +static void update_cc_Media_useterminatorpr( drive_t *drivep, + context_t *contextp ); +static void set_mcflag( ix_t thrdix ); +static void clr_mcflag( ix_t thrdix ); + +static bool_t check_complete_flags( void ); + +#ifdef EXTATTR +static rv_t dump_extattrs( drive_t *drivep, + context_t *contextp, + jdm_fshandle_t *fshandlep, + xfs_bstat_t *statp); +static rv_t dump_extattr_list( drive_t *drivep, + context_t *contextp, + jdm_fshandle_t *fshandlep, + xfs_bstat_t *statp, + attrlist_t *listp, + bool_t isrootpr, + bool_t *abortprp ); +static char *dump_extattr_buildrecord( xfs_bstat_t *statp, + char *dumpbufp, + char *dumpbufendp, + char *namesrcp, + u_int32_t valuesz, + bool_t isrootpr, + char **valuepp ); +static rv_t dump_extattrhdr( drive_t *drivep, + context_t *contextp, + xfs_bstat_t *statp, + size_t recsz, + size_t valoff, + ix_t flags, + u_int32_t valsz ); +#endif /* EXTATTR */ +static bool_t save_quotas( char *mntpnt, + quota_info_t *quotainfo ); +static int getxfsqstat( char *fsname ); + + + +/* definition of locally defined global variables ****************************/ + +bool_t content_media_change_needed; +char *media_change_alert_program = NULL; +#ifdef DMEXTATTR +hsm_fs_ctxt_t *hsm_fs_ctxtp = NULL; +#endif /* DMEXTATTR */ + +/* definition of locally defined static variables *****************************/ + +static bool_t sc_preerasepr = BOOL_FALSE; + /* pre-erase media + */ +static inv_idbtoken_t sc_inv_idbtoken = INV_TOKEN_NULL; + /* handle to inventory + */ +static inv_sestoken_t sc_inv_sestoken = INV_TOKEN_NULL; + /* handle to inventory session + */ +static inv_stmtoken_t *sc_inv_stmtokenp = 0; + /* array of inventory session stream handles + */ +static bool_t sc_inv_updatepr = BOOL_TRUE; + /* set if ok to update online inventory with stats of this dump + */ +static ix_t sc_level = LEVEL_DEFAULT; + /* dump level requested + */ +static bool_t sc_incrpr = BOOL_FALSE; +static time_t sc_incrbasetime; +static ix_t sc_incrbaselevel; +static uuid_t sc_incrbaseid; + /* if an incremental dump, the base, level and time of the incremental + * base dump. TRICKY: if resuming an incremental dump, this is the + * base of the original incremental. + */ +static bool_t sc_resumepr = BOOL_FALSE; +static time_t sc_resumebasetime = 0; +static uuid_t sc_resumebaseid; +static size_t sc_resumerangecnt = 0; +static drange_t *sc_resumerangep = 0; + /* if a resumed dump, the id, time and undumped ino/offset ranges + * of the interrupted dump being resumed. + */ +static jdm_fshandle_t *sc_fshandlep = 0; + /* dmi file system handle + */ +static int sc_fsfd = -1; + /* open file descriptor for root directory + */ +static xfs_bstat_t *sc_rootxfsstatp = 0; + /* pointer to loaded bulkstat for root directory + */ +static startpt_t *sc_startptp = 0; + /* an array of stream ino/offset start points + */ +static time_t sc_stat_starttime = 0; + /* for cacluating elapsed time + */ +static ix_t sc_stat_inomapphase = 0; +static ix_t sc_stat_inomappass = 0; +static size64_t sc_stat_inomapcnt; +static size64_t sc_stat_inomapdone; +static size64_t sc_stat_dircnt = 0; + /* total number of directory inodes to be dumped (strm 0) + */ +static pds_t sc_stat_pds[ STREAM_SIMMAX ]; + /* per-drive stream status + */ +static size64_t sc_stat_nondircnt = 0; + /* total number of non-directory inodes to be dumped (all strms) + */ +static size64_t sc_stat_nondirdone = 0; + /* total number of non-directory inodes dumped (all strms) + */ +static size64_t sc_stat_datasz = 0; + /* total size in bytes of non-dirs to be dumped (all strms) + */ +static size64_t sc_stat_datadone = 0; + /* total size in bytes of non-dirs dumped (all strms) + */ +static size_t sc_thrdsarrivedcnt = 0; + /* each thread checks in by bumping this count under lock. + * used to decide when its ok to begin waiting for all threads + * to arrive at sync pt for session inventory dump. + */ +static size_t sc_thrdsdonecnt = 0; + /* number of threads which are ready to dump the session inventory. + * when equal to the number of streams remaining (stream_cnt( )), + * can proceed with inventory dumps + */ +static context_t *sc_contextp; + /* an array of per-stream context descriptors + */ +static bool_t sc_mcflag[ STREAM_SIMMAX ]; + /* media change flag + */ +#ifdef EXTATTR +static bool_t sc_dumpextattrpr = BOOL_TRUE; + /* dump extended attributes + */ +static bool_t sc_brokenioctl = BOOL_FALSE; + /* attr_*_by_handle appears to be missing + */ +#endif EXTATTR +#ifdef DMEXTATTR +static bool_t sc_dumpasoffline = BOOL_FALSE; + /* dump dual-residency HSM files as offline + */ +#endif /* DMEXTATTR */ +#ifdef SYNCDIR +static size_t sc_thrdsdirdumpsynccnt = 0; +static size_t sc_thrdswaitingdirdumpsync1 = 0; +static size_t sc_thrdswaitingdirdumpsync2 = 0; +static qbarrierh_t sc_barrierh; +#endif /* SYNCDIR */ + +static bool_t sc_savequotas = BOOL_TRUE; + /* save quota information in dump + */ +static quota_info_t quotas[] = { + { "user quota", BOOL_TRUE, CONTENT_QUOTAFILE, "", "-u", XFS_QUOTA_UDQ_ACCT }, + { "group quota", BOOL_TRUE, CONTENT_GQUOTAFILE, "", "-g", XFS_QUOTA_GDQ_ACCT } +}; + +/* definition of locally defined global functions ****************************/ + + +/* definition of locally defined static functions ****************************/ + + +bool_t +content_init( intgen_t argc, + char *argv[ ], + global_hdr_t *gwhdrtemplatep ) +{ + + inv_idbtoken_t inv_idbt; + inv_session_t *sessp = 0; + drive_hdr_t *dwhdrtemplatep; + media_hdr_t *mwhdrtemplatep; + content_hdr_t *cwhdrtemplatep; + content_inode_hdr_t *scwhdrtemplatep; + ix_t subtreecnt; + char **subtreep; + ix_t subtreeix; + bool_t resumereqpr = BOOL_FALSE; + char *srcname; + char mntpnt[ GLOBAL_HDR_STRING_SZ ]; + char fsdevice[ GLOBAL_HDR_STRING_SZ ]; + char fstype[ CONTENT_HDR_FSTYPE_SZ ]; + uuid_t fsid; + bool_t underfoundpr; + ix_t underlevel = ( ix_t )( -1 ); + time_t undertime = 0; + uuid_t underid; + bool_t underpartialpr = BOOL_FALSE; + bool_t underinterruptedpr = BOOL_FALSE; + bool_t samefoundpr; + time_t sametime = 0; + uuid_t sameid; + bool_t samepartialpr = BOOL_FALSE; + bool_t sameinterruptedpr = BOOL_FALSE; + size_t strmix; + intgen_t c; + intgen_t i; + intgen_t qstat; + intgen_t rval; + bool_t ok; + extern char *optarg; + extern int optind, opterr, optopt; +#ifdef BASED + char *baseuuidstr = NULL; + uuid_t baseuuid; + bool_t baseuuidvalpr; +#endif /* BASED */ +#ifdef SIZEEST + u_int64_t dircnt; + u_int64_t nondircnt; + u_int64_t datasz; + u_int64_t inocnt; + u_int64_t size_estimate; +#endif /* SIZEEST */ + + /* basic sanity checks + */ + ASSERT( sizeof( mode_t ) == MODE_SZ ); + ASSERT( sizeof( timestruct_t ) == TIMESTRUCT_SZ ); + ASSERT( sizeof( bstat_t ) == BSTAT_SZ ); + ASSERT( sizeof( xfs_bstat_t ) <= sizeof( bstat_t )); + ASSERT( sizeof( filehdr_t ) == FILEHDR_SZ ); + ASSERT( sizeof( extenthdr_t ) == EXTENTHDR_SZ ); + ASSERT( sizeof( direnthdr_t ) == DIRENTHDR_SZ ); + ASSERT( DIRENTHDR_SZ % DIRENTHDR_ALIGN == 0 ); + ASSERT( sizeofmember( content_hdr_t, ch_specific ) + >= + sizeof( content_inode_hdr_t )); +#ifdef EXTATTR + ASSERT( sizeof( extattrhdr_t ) == EXTATTRHDR_SZ ); +#endif /* EXTATTR */ + + /* calculate offsets of portions of the write hdr template + */ + dwhdrtemplatep = ( drive_hdr_t * )gwhdrtemplatep->gh_upper; + mwhdrtemplatep = ( media_hdr_t * )dwhdrtemplatep->dh_upper; + cwhdrtemplatep = ( content_hdr_t * )mwhdrtemplatep->mh_upper; + scwhdrtemplatep = ( content_inode_hdr_t * ) cwhdrtemplatep->ch_specific; + + /* process command line args + */ + optind = 1; + opterr = 0; + subtreecnt = 0; +#ifdef BASED + baseuuidvalpr = BOOL_FALSE; +#endif /* BASED */ + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + switch ( c ) { + case GETOPT_LEVEL: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument missing\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + sc_level = ( ix_t )atoi( optarg ); + if ( sc_level > LEVEL_MAX ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument must be " + "between 0 and %d\n", + optopt, + LEVEL_MAX ); + usage( ); + return BOOL_FALSE; + } + break; + case GETOPT_SUBTREE: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument missing\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + if ( optarg[ 0 ] == '/' ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument (subtree) " + "must be a relative pathname\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + subtreecnt++; + break; + case GETOPT_RESUME: + resumereqpr = BOOL_TRUE; + break; + case GETOPT_NOINVUPDATE: + sc_inv_updatepr = BOOL_FALSE; + break; + case GETOPT_ERASE: + sc_preerasepr = BOOL_TRUE; + break; + case GETOPT_ALERTPROG: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument missing\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + media_change_alert_program = optarg; + break; + +#ifdef EXTATTR + case GETOPT_NOEXTATTR: + sc_dumpextattrpr = BOOL_FALSE; + break; +#endif /* EXTATTR */ +#ifdef DMEXTATTR + case GETOPT_DUMPASOFFLINE: + sc_dumpasoffline = BOOL_TRUE; + break; +#endif /* DMEXTATTR */ +#ifdef BASED + case GETOPT_BASED: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument missing\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + baseuuidstr = optarg; + + if ( uuid_parse( baseuuidstr, baseuuid ) < 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument not a valid " + "dump session id\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + baseuuidvalpr = BOOL_TRUE; +#endif /* BASED */ + } + } + +#ifdef BASED + if ( resumereqpr && baseuuidvalpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "may not specify both -%c and -%c\n", + GETOPT_BASED, + GETOPT_RESUME ); + return BOOL_FALSE; + } +#endif /* BASED */ + + /* the user may specify stdout as the destination, by a single + * dash ('-') with no option letter. This must appear between + * all lettered arguments and the source file system pathname. + */ + if ( optind < argc && ! strcmp( argv[ optind ], "-" )) { + optind++; + } + + /* the last argument must be either the mount point or a + * device pathname of the file system to be dumped. + */ + if ( optind >= argc ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "source file system " + "not specified\n" ); + usage( ); + return BOOL_FALSE; + } + srcname = argv[ optind ]; + + if ( preemptchk( PREEMPT_FULL )) { + return BOOL_FALSE; + } + + /* allocate space for the subtree pointer array and load it + */ + if ( subtreecnt ) { + subtreep = ( char ** )calloc( subtreecnt, sizeof( char * )); + ASSERT( subtreep ); + optind = 1; + opterr = 0; + subtreeix = 0; + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + switch ( c ) { + case GETOPT_SUBTREE: + ASSERT( subtreeix < subtreecnt ); + ASSERT( optarg && optarg[ 0 ] != '-' ); + subtreep[ subtreeix++ ] = optarg; + break; + } + } + ASSERT( subtreeix == subtreecnt ); + } else { + subtreep = 0; + } + + /* call a magic function to figure out if the last argument is + * a mount point or a device pathname, and retrieve the file + * system type, full pathname of the character special device + * containing the file system, the latest mount point, and the file + * system ID (uuid). returns BOOL_FALSE if the last + * argument doesn't look like a file system. + */ + if ( ! fs_info( fstype, + sizeof( fstype ), + FS_DEFAULT, + fsdevice, + sizeof( fsdevice ), + mntpnt, + sizeof( mntpnt ), + &fsid, + srcname )) { + + mlog( MLOG_NORMAL | MLOG_ERROR, + "%s does not identify a file system\n", + srcname ); + usage( ); + return BOOL_FALSE; + } + + /* verify that the file system is mounted. This must be enhanced + * to mount an unmounted file system on a temporary mount point, + * if it is not currently mounted. + */ + if ( ! fs_mounted( fstype, fsdevice, mntpnt, &fsid )) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "%s must be mounted to be dumped\n", + srcname ); + return BOOL_FALSE; + } + + /* place the fs info in the write hdr template + */ + ( void )strncpyterm( cwhdrtemplatep->ch_mntpnt, + mntpnt, + sizeof( cwhdrtemplatep->ch_mntpnt )); + ( void )strncpyterm( cwhdrtemplatep->ch_fsdevice, + fsdevice, + sizeof( cwhdrtemplatep->ch_fsdevice )); + ( void )strncpyterm( cwhdrtemplatep->ch_fstype, + fstype, + sizeof( cwhdrtemplatep->ch_fstype )); + uuid_copy( cwhdrtemplatep->ch_fsid, fsid ); + + +#ifndef PIPEINVFIX + + /* use of any pipes precludes inventory update + */ + for ( strmix = 0 ; strmix < drivecnt ; strmix++ ) { + if ( drivepp[ strmix ]->d_isnamedpipepr + || + drivepp[ strmix ]->d_isunnamedpipepr ) { + sc_inv_updatepr = BOOL_FALSE; + } + } +#endif /* ! PIPEINVFIX */ + + /* write quota information */ + if( sc_savequotas ) { + sc_savequotas = BOOL_FALSE; + for(i = 0; i < (sizeof(quotas) / sizeof(quotas[0])); i++) { + quotas[i].savequotas = BOOL_FALSE; + qstat = getxfsqstat( fsdevice ); + if (qstat > 0 && (qstat & quotas[i].statflag) ) { + sprintf( quotas[i].quotapath, "%s/%s", mntpnt, quotas[i].quotafile ); + if( save_quotas( mntpnt, "as[i] )) { + if( subtreecnt ) { + subtreecnt++; + subtreep = (char **) realloc( subtreep, + subtreecnt * sizeof(char *)); + assert( subtreep ); + subtreep[ subtreecnt - 1 ] = quotas[i].quotafile; + } + sc_savequotas = BOOL_TRUE; + quotas[i].savequotas = BOOL_TRUE; + } else { + mlog( MLOG_NORMAL | MLOG_ERROR, + "failed to save %s information, continuing\n", + quotas[i].desc ); + } + } + } + } + + + /* create my /var directory if it doesn't already exist. + */ + var_create( ); + + /* get two session descriptors from the inventory: one for the last + * dump at this level, and one for the last dump at a lower level. + * the former will be used to check if the last dump at this level + * was prematurely terminated; if so, for those inos already dumped + * then, we will look only for changes since that dump. the latter + * will give us a change date for all other inos. + */ + + if ( preemptchk( PREEMPT_FULL )) { + return BOOL_FALSE; + } + + /* briefly open the online dump inventory, so it can be used + * to calculate incremental and resumed dumps. + */ + inv_idbt = inv_open( ( inv_predicate_t )INV_BY_UUID, + INV_SEARCH_ONLY, + ( void * )&fsid ); + +#ifdef BASED + /* if a based request, look for the indicated session. + * if found, and not interrupted, this will be used as an + * incremental base. if interrupted, will be used as + * resume base. + */ + if ( baseuuidvalpr ) { + ix_t strix; + ix_t strcnt; + inv_stream_t *bsp; + bool_t interruptedpr; + + underfoundpr = BOOL_FALSE; + samefoundpr = BOOL_FALSE; + underinterruptedpr = BOOL_FALSE; + sameinterruptedpr = BOOL_FALSE; + interruptedpr = BOOL_FALSE; + + ok = inv_get_session_byuuid( &baseuuid, &sessp ); + if ( ! ok ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "could not find specified base dump (%s) " + "in inventory\n", + baseuuidstr ); + return BOOL_FALSE; + } + strcnt = ( ix_t )sessp->s_nstreams; + for ( strix = 0 ; strix < strcnt ; strix++ ) { + bsp = &sessp->s_streams[ strix ]; + if ( bsp->st_interrupted ) { + interruptedpr = BOOL_TRUE; + break; + } + } + + if ( interruptedpr ) { + sc_level = ( ix_t )sessp->s_level; + resumereqpr = BOOL_TRUE; + samefoundpr = BOOL_TRUE; + sametime = sessp->s_time; + uuid_copy (sameid, sessp->s_sesid); + samepartialpr = sessp->s_ispartial; + sameinterruptedpr = BOOL_TRUE; + sc_resumerangecnt = ( size_t )sessp->s_nstreams; + sc_resumerangep = ( drange_t * )calloc( sc_resumerangecnt, + sizeof( drange_t )); + ASSERT( sc_resumerangep ); + for ( strmix = 0 ; strmix < sc_resumerangecnt ; strmix++ ) { + inv_stream_t *bsp; + inv_stream_t *esp; + drange_t *p = &sc_resumerangep[ strmix ]; + bsp = &sessp->s_streams[ strmix ]; + esp = ( strmix < sc_resumerangecnt - 1 ) + ? + bsp + 1 + : + 0; + if ( bsp->st_interrupted ) { + sameinterruptedpr = BOOL_TRUE; + p->dr_begin.sp_ino = bsp->st_endino; + p->dr_begin.sp_offset = bsp->st_endino_off; + if ( esp ) { + p->dr_end.sp_ino = esp->st_startino; + p->dr_end.sp_offset = + esp->st_startino_off; + mlog( MLOG_DEBUG, + "resume range stream %u " + "ino %llu:%lld to " + "%llu:%lld\n", + strmix, + p->dr_begin.sp_ino, + p->dr_begin.sp_offset, + p->dr_end.sp_ino, + p->dr_end.sp_offset ); + } else { + p->dr_end.sp_flags = STARTPT_FLAGS_END; + mlog( MLOG_DEBUG, + "resume range stream %u " + "ino %llu:%lld to " + "end\n", + strmix, + p->dr_begin.sp_ino, + p->dr_begin.sp_offset ); + } + } else { + /* set the range start pt's END flag to + * indicate the range was not interrupted. + */ + p->dr_begin.sp_flags = STARTPT_FLAGS_END; + } + } + } else { + if ( sessp->s_level >= LEVEL_MAX ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "cannot select dump session %s as base " + "for incremental dump: " + "level must be less than %d\n", + LEVEL_MAX ); + return BOOL_FALSE; + } + sc_level = ( ix_t )sessp->s_level + 1; + undertime = sessp->s_time; + underlevel = ( ix_t )sessp->s_level; + uuid_copy (underid, sessp->s_sesid); + underpartialpr = sessp->s_ispartial; + underinterruptedpr = BOOL_FALSE; + underfoundpr = BOOL_TRUE; + } + inv_free_session( &sessp ); + sessp = 0; + ok = inv_close( inv_idbt ); + ASSERT( ok ); + inv_idbt = INV_TOKEN_NULL; + goto baseuuidbypass; + } +#endif /* BASED */ + + /* look for the most recent dump at a level less than the level + * of this dump. extract the time, level, id, and predicates partial + * and interrupted. + */ + underfoundpr = BOOL_FALSE; + if ( sc_level > 0 ) { + if ( inv_idbt == INV_TOKEN_NULL ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "cannot calculate incremental dump: " + "online inventory not available\n" ); + return BOOL_FALSE; + } + ok = inv_lastsession_level_lessthan( inv_idbt, + ( u_char_t )sc_level, + &sessp ); + if ( ! ok ) { + sessp = 0; + } + + if ( sessp ) { + ix_t strix; + ix_t strcnt; + inv_stream_t *bsp; + + undertime = sessp->s_time; + underlevel = ( ix_t )sessp->s_level; + uuid_copy (underid, sessp->s_sesid); + underpartialpr = sessp->s_ispartial; + underinterruptedpr = BOOL_FALSE; + strcnt = ( ix_t )sessp->s_nstreams; + for ( strix = 0 ; strix < strcnt ; strix++ ) { + bsp = &sessp->s_streams[ strix ]; + if ( bsp->st_interrupted ) { + underinterruptedpr = BOOL_TRUE; + break; + } + } + underfoundpr = BOOL_TRUE; + inv_free_session( & sessp ); + sessp = 0; + } + } + + /* look for the most recent dump at a level equal to the level + * of this dump. extract the time, level, id, and predicates partial + * and interrupted, and for each stream the range of ino/offset + * values not dumped. + */ + if ( inv_idbt != INV_TOKEN_NULL ) { + /* REFERENCED */ + bool_t ok1; + ok = inv_lastsession_level_equalto( inv_idbt, + ( u_char_t )sc_level, + &sessp ); + ok1 = inv_close( inv_idbt ); + ASSERT( ok1 ); + if ( ! ok ) { + sessp = 0; + } + inv_idbt = INV_TOKEN_NULL; + } else { + sessp = 0; + } + + samefoundpr = BOOL_FALSE; + if ( sessp ) { + sametime = sessp->s_time; + uuid_copy(sameid, sessp->s_sesid); + samepartialpr = sessp->s_ispartial; + sameinterruptedpr = BOOL_FALSE; + sc_resumerangecnt = ( size_t )sessp->s_nstreams; + sc_resumerangep = ( drange_t * )calloc( sc_resumerangecnt, + sizeof( drange_t )); + ASSERT( sc_resumerangep ); + for ( strmix = 0 ; strmix < sc_resumerangecnt ; strmix++ ) { + inv_stream_t *bsp; + inv_stream_t *esp; + drange_t *p = &sc_resumerangep[ strmix ]; + bsp = &sessp->s_streams[ strmix ]; + esp = ( strmix < sc_resumerangecnt - 1 ) + ? + bsp + 1 + : + 0; + if ( bsp->st_interrupted ) { + sameinterruptedpr = BOOL_TRUE; + p->dr_begin.sp_ino = bsp->st_endino; + p->dr_begin.sp_offset = bsp->st_endino_off; + if ( esp ) { + p->dr_end.sp_ino = esp->st_startino; + p->dr_end.sp_offset = + esp->st_startino_off; + mlog( MLOG_DEBUG, + "resume range stream %u " + "ino %llu:%lld to " + "%llu:%lld\n", + strmix, + p->dr_begin.sp_ino, + p->dr_begin.sp_offset, + p->dr_end.sp_ino, + p->dr_end.sp_offset ); + } else { + p->dr_end.sp_flags = STARTPT_FLAGS_END; + mlog( MLOG_DEBUG, + "resume range stream %u " + "ino %llu:%lld to " + "end\n", + strmix, + p->dr_begin.sp_ino, + p->dr_begin.sp_offset ); + } + } else { + /* set the range start pt's END flag to + * indicate the range was not interrupted. + */ + p->dr_begin.sp_flags = STARTPT_FLAGS_END; + } + } + inv_free_session( & sessp ); + sessp = 0; + samefoundpr = BOOL_TRUE; + } + +#ifdef BASED +baseuuidbypass: +#endif /* BASED */ + + /* now determine the incremental and resume bases, if any. + */ + if ( samefoundpr && ! sameinterruptedpr ) { + free( ( void * )sc_resumerangep ); + sc_resumerangep = 0; + samefoundpr = BOOL_FALSE; + } + if ( samefoundpr && ! resumereqpr ) { + if ( ! underfoundpr || undertime <= sametime ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "most recent level %d dump " + "was interrupted, " + "but not resuming that dump since " + "resume (-R) option not specified\n", + sc_level ); + } + free( ( void * )sc_resumerangep ); + sc_resumerangep = 0; + samefoundpr = BOOL_FALSE; + } + if ( underfoundpr ) { + ASSERT( underlevel <= LEVEL_MAX ); + ASSERT( undertime ); + if ( samefoundpr ) { + if ( undertime >= sametime ) { + if ( underinterruptedpr ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "most recent base for " + "incremental dump was " + "interrupted (level %u): " + "must resume or redump " + "at or below level %d\n", + underlevel, + sc_level ); + return BOOL_FALSE; + } + if ( subtreecnt && ! underpartialpr ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "level %u incremental " + "subtree dump " + "will be based on non-subtree " + "level %u dump\n", + sc_level, + underlevel ); + } + if ( ! subtreecnt && underpartialpr ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "level %u incremental " + "non-subtree dump " + "will be based on subtree " + "level %u dump\n", + sc_level, + underlevel ); + } + sc_incrpr = BOOL_TRUE; + sc_incrbasetime = undertime; + sc_incrbaselevel = underlevel; + uuid_copy(sc_incrbaseid, underid); + sc_resumepr = BOOL_FALSE; + ASSERT( sc_resumerangep ); + free( ( void * )sc_resumerangep ); + sc_resumerangep = 0; + } else { + if ( subtreecnt && ! samepartialpr ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "level %u incremental " + "subtree dump " + "will be based on non-subtree " + "level %u resumed dump\n", + sc_level, + sc_level ); + } + if ( ! subtreecnt && samepartialpr ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "level %u incremental " + "non-subtree dump " + "will be based on subtree " + "level %u resumed dump\n", + sc_level, + sc_level ); + } + ASSERT( sametime ); + sc_incrpr = BOOL_TRUE; + sc_incrbasetime = undertime; + sc_incrbaselevel = underlevel; + sc_resumepr = BOOL_TRUE; + sc_resumebasetime = sametime; + uuid_copy(sc_resumebaseid, sameid); + ASSERT( sc_resumerangep ); + } + } else { + if ( underinterruptedpr ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "most recent base for " + "incremental dump was " + "interrupted (level %u): " + "must resume or redump " + "at or below level %d\n", + underlevel, + sc_level ); + return BOOL_FALSE; + } + if ( subtreecnt && ! underpartialpr ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "level %u incremental " + "subtree dump " + "will be based on non-subtree " + "level %u dump\n", + sc_level, + underlevel ); + } + if ( ! subtreecnt && underpartialpr ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "level %u incremental " + "non-subtree dump " + "will be based on subtree " + "level %u dump\n", + sc_level, + underlevel ); + } + sc_incrpr = BOOL_TRUE; + sc_incrbasetime = undertime; + sc_incrbaselevel = underlevel; + uuid_copy(sc_incrbaseid, underid); + sc_resumepr = BOOL_FALSE; + ASSERT( ! sc_resumerangep ); + } + } else { + if ( samefoundpr ) { + ASSERT( sametime ); + if ( subtreecnt && ! samepartialpr ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "level %u " + "subtree dump " + "will be based on non-subtree " + "level %u resumed dump\n", + sc_level, + sc_level ); + } + if ( ! subtreecnt && samepartialpr ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "level %u " + "non-subtree dump " + "will be based on subtree " + "level %u resumed dump\n", + sc_level, + sc_level ); + } + sc_incrpr = BOOL_FALSE; + sc_resumepr = BOOL_TRUE; + sc_resumebasetime = sametime; + uuid_copy(sc_resumebaseid, sameid); + ASSERT( sc_resumerangep ); + } else { + sc_incrpr = BOOL_FALSE; + sc_resumepr = BOOL_FALSE; + ASSERT( ! sc_resumerangep ); + if ( sc_level > 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "cannot find earlier dump " + "to base level %d increment upon\n", + sc_level ); + return BOOL_FALSE; + } + } + } + + /* don't allow interrupted dumps of a lesser level to be bases + */ + if ( sc_incrpr && underinterruptedpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "most recent base dump (level %d begun %s) " + "was interrupted: aborting\n", + sc_incrbaselevel, + ctimennl( &sc_incrbasetime )); + return BOOL_FALSE; + } + + /* reject if resume (-R) specified, but base was not interrupted + */ + if ( ! sc_resumepr && resumereqpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "resume (-R) option inappropriate: " + "no interrupted level %d dump to resume\n", + sc_level ); + return BOOL_FALSE; + } + + /* announce the dump characteristics + */ + if ( sc_incrpr ) { + if ( sc_resumepr ) { + char restimestr[ 30 ]; + char incrtimestr[ 30 ]; + + strcpy( restimestr, ctimennl( &sc_resumebasetime )); + ASSERT( strlen( restimestr ) < sizeof( restimestr )); + strcpy( incrtimestr, ctimennl( &sc_incrbasetime )); + ASSERT( strlen( incrtimestr ) < sizeof( incrtimestr )); + + mlog( MLOG_VERBOSE, + "resuming level %d incremental dump of %s:%s " + "begun %s " + "(incremental base level %d begun %s)\n", + sc_level, + gwhdrtemplatep->gh_hostname, + mntpnt, + restimestr, + sc_incrbaselevel, + incrtimestr ); + } else { + mlog( MLOG_VERBOSE, + "level %d incremental dump of %s:%s " + "based on level %d dump begun %s\n", + sc_level, + gwhdrtemplatep->gh_hostname, + mntpnt, + sc_incrbaselevel, + ctimennl( &sc_incrbasetime )); + } + } else { + if ( sc_resumepr ) { + mlog( MLOG_VERBOSE, + "resuming level %d dump of %s:%s begun %s\n", + sc_level, + gwhdrtemplatep->gh_hostname, + mntpnt, + ctimennl( &sc_resumebasetime )); + } else { + mlog( MLOG_VERBOSE, + "level %d dump of %s:%s\n", + sc_level, + gwhdrtemplatep->gh_hostname, + mntpnt ); + } + } + + if ( preemptchk( PREEMPT_FULL )) { + return BOOL_FALSE; + } + + /* announce the dump time + */ + mlog( MLOG_VERBOSE, + "dump date: %s\n", + ctimennl( &gwhdrtemplatep->gh_timestamp )); + + /* display the session UUID + */ + { + char string_uuid[UUID_STR_LEN + 1]; + uuid_unparse( gwhdrtemplatep->gh_dumpid, string_uuid ); + mlog( MLOG_VERBOSE, + "session id: %s\n", + string_uuid ); + } + + /* display the session label + */ + mlog( MLOG_VERBOSE, + "session label: \"%s\"\n", + gwhdrtemplatep->gh_dumplabel ); + + /* get a file descriptor for the file system. any file + * contained in the file system will do; use the mntpnt. + * needed by bigstat. + */ + sc_fsfd = open( mntpnt, O_RDONLY ); + if ( sc_fsfd < 0 ) { + mlog( MLOG_NORMAL, + "unable to open %s: %s\n", + mntpnt, + strerror( errno )); + return BOOL_FALSE; + } + + /* figure out the ino for the root directory of the fs + * translate the struct stat64 into a xfs_bstat_t, + * since that is what is expected by inomap_build() + */ + { + struct stat64 rootstat; + rval = fstat64( sc_fsfd, &rootstat ); + if ( rval ) { + mlog( MLOG_NORMAL, + "could not stat %s\n", + mntpnt ); + return BOOL_FALSE; + } + sc_rootxfsstatp = + ( xfs_bstat_t * )calloc( 1, sizeof( xfs_bstat_t )); + ASSERT( sc_rootxfsstatp ); + stat64_to_xfsbstat( sc_rootxfsstatp, &rootstat ); + } + + /* alloc a file system handle, to be used with the jdm_open() + * functions. + */ + sc_fshandlep = jdm_getfshandle( mntpnt ); + if ( ! sc_fshandlep ) { + mlog( MLOG_NORMAL, + "unable to construct a file system handle for %s: %s\n", + mntpnt, + strerror( errno )); + return BOOL_FALSE; + } + + /* ask var to ask inomap to skip files under var if var is in + * the fs being dumped + */ + var_skip( &fsid, inomap_skip ); + + if ( preemptchk( PREEMPT_FULL )) { + return BOOL_FALSE; + } + +#ifdef DMEXTATTR + /* If GETOPT_DUMPASOFFLINE was specified, allocate a filesystem context + * for use by the HSM routines. + */ + + if (sc_dumpasoffline) { + hsm_fs_ctxtp = HsmInitFsysContext(mntpnt, HSM_API_VERSION_1); + } +#endif /* DMEXTATTR */ + + /* set now so statline can be displayed + */ + sc_stat_starttime = gwhdrtemplatep->gh_timestamp; + + /* allocate storage for the stream startpoints, and build inomap. + * inomap_build() also fills in the start points. storage only needed + * until the startpoints are copied into each streams header. will + * be freed at the end of this function. + */ + sc_stat_inomapcnt = ( size64_t )fs_getinocnt( mntpnt ); + + sc_startptp = ( startpt_t * )calloc( drivecnt, sizeof( startpt_t )); + ASSERT( sc_startptp ); + ok = inomap_build( sc_fshandlep, + sc_fsfd, + sc_rootxfsstatp, + sc_incrpr, + sc_incrbasetime, + sc_resumepr, + sc_resumebasetime, + sc_resumerangecnt, + sc_resumerangep, + subtreep, + subtreecnt, + sc_startptp, + drivecnt, + &sc_stat_inomapphase, + &sc_stat_inomappass, + sc_stat_inomapcnt, + &sc_stat_inomapdone ); + free( ( void * )subtreep ); + subtreep = 0; + if ( ! ok ) { + return BOOL_FALSE; + } + + /* fill in write header template content info. always produce + * an inomap and dir dump for each media file. flag the checksums + * available if so compiled (see -D...CHECKSUM in Makefile). + */ + ASSERT( sizeof( cwhdrtemplatep->ch_specific ) >= sizeof( *scwhdrtemplatep )); + scwhdrtemplatep->cih_mediafiletype = CIH_MEDIAFILETYPE_DATA; + scwhdrtemplatep->cih_level = ( int32_t )sc_level; + scwhdrtemplatep->cih_dumpattr = CIH_DUMPATTR_INOMAP + | + CIH_DUMPATTR_DIRDUMP; + if ( subtreep ) { + scwhdrtemplatep->cih_dumpattr |= CIH_DUMPATTR_SUBTREE; + } + if ( sc_inv_updatepr ) { + scwhdrtemplatep->cih_dumpattr |= CIH_DUMPATTR_INVENTORY; + } +#ifdef FILEHDR_CHECKSUM + scwhdrtemplatep->cih_dumpattr |= CIH_DUMPATTR_FILEHDR_CHECKSUM; +#endif /* FILEHDR_CHECKSUM */ +#ifdef EXTENTHDR_CHECKSUM + scwhdrtemplatep->cih_dumpattr |= CIH_DUMPATTR_EXTENTHDR_CHECKSUM; +#endif /* EXTENTHDR_CHECKSUM */ +#ifdef DIRENTHDR_CHECKSUM + scwhdrtemplatep->cih_dumpattr |= CIH_DUMPATTR_DIRENTHDR_CHECKSUM; +#endif /* DIRENTHDR_CHECKSUM */ + scwhdrtemplatep->cih_dumpattr |= CIH_DUMPATTR_DIRENTHDR_GEN; + if ( sc_incrpr ) { + scwhdrtemplatep->cih_dumpattr |= CIH_DUMPATTR_INCREMENTAL; + scwhdrtemplatep->cih_last_time = sc_incrbasetime; + uuid_copy(scwhdrtemplatep->cih_last_id, sc_incrbaseid); + } + if ( sc_resumepr ) { + scwhdrtemplatep->cih_dumpattr |= CIH_DUMPATTR_RESUME; + scwhdrtemplatep->cih_resume_time = sc_resumebasetime; + uuid_copy(scwhdrtemplatep->cih_resume_id, sc_resumebaseid); + } +#ifdef EXTATTR + if ( sc_dumpextattrpr ) { + scwhdrtemplatep->cih_dumpattr |= CIH_DUMPATTR_EXTATTR; +#ifdef EXTATTRHDR_CHECKSUM + scwhdrtemplatep->cih_dumpattr |= + CIH_DUMPATTR_EXTATTRHDR_CHECKSUM; +#endif /* EXTATTRHDR_CHECKSUM */ + } + +#endif /* EXTATTR */ + + scwhdrtemplatep->cih_rootino = sc_rootxfsstatp->bs_ino; + inomap_writehdr( scwhdrtemplatep ); + +#ifdef SIZEEST + /* log the dump size. just a rough approx. + */ + dircnt = scwhdrtemplatep->cih_inomap_dircnt; + nondircnt = scwhdrtemplatep->cih_inomap_nondircnt; + datasz = scwhdrtemplatep->cih_inomap_datasz; + inocnt = dircnt + nondircnt; + size_estimate = GLOBAL_HDR_SZ + + + inomap_getsz( ) + + + inocnt * ( u_int64_t )( FILEHDR_SZ + EXTENTHDR_SZ ) + + + inocnt * ( u_int64_t )( DIRENTHDR_SZ + 8 ) + + + datasz; + mlog( MLOG_VERBOSE, + "estimated dump size: %llu bytes\n", + size_estimate ); +#endif /* SIZEEST */ + + /* extract the progress stat denominators from the write hdr + * template. placed there by inomap_writehdr( ) + */ + sc_stat_dircnt = scwhdrtemplatep->cih_inomap_dircnt; + sc_stat_nondircnt = scwhdrtemplatep->cih_inomap_nondircnt; + sc_stat_datasz = scwhdrtemplatep->cih_inomap_datasz; + + /* allocate and populate per-stream context descriptors + */ + sc_contextp = ( context_t * )calloc( drivecnt, sizeof( context_t )); + ASSERT( sc_contextp ); + for ( strmix = 0 ; strmix < drivecnt ; strmix++ ) { + context_t *contextp = &sc_contextp[ strmix ]; + + contextp->cc_filehdrp = + ( filehdr_t * )calloc( 1, sizeof( filehdr_t )); + ASSERT( contextp->cc_filehdrp ); + + contextp->cc_extenthdrp = + ( extenthdr_t * )calloc( 1, sizeof( extenthdr_t )); + ASSERT( contextp->cc_extenthdrp ); + + contextp->cc_getdentsbufsz = sizeof( struct dirent ) + + + NAME_MAX; + if ( contextp->cc_getdentsbufsz < GETDENTSBUF_SZ_MIN ) { + contextp->cc_getdentsbufsz = GETDENTSBUF_SZ_MIN; + } + contextp->cc_getdentsbufp = + ( char * ) calloc( 1, contextp->cc_getdentsbufsz ); + ASSERT( contextp->cc_getdentsbufp ); + + contextp->cc_mdirentbufsz = sizeof( direnthdr_t ) + + + NAME_MAX + + + DIRENTHDR_ALIGN; + contextp->cc_mdirentbufp = + ( char * ) calloc( 1, contextp->cc_mdirentbufsz ); + ASSERT( contextp->cc_mdirentbufp ); + +#ifdef EXTATTR + contextp->cc_extattrlistbufsz = EXTATTR_LISTBUF_SZ; + contextp->cc_extattrrtrvarraylen = EXTATTR_RTRVARRAY_LEN; + contextp->cc_extattrdumpbufsz = 2 * ATTR_MAX_VALUELEN; + if ( contextp->cc_extattrdumpbufsz < EXTATTR_DUMPBUF_SZ ) { + contextp->cc_extattrdumpbufsz = EXTATTR_DUMPBUF_SZ; + } + contextp->cc_extattrlistbufp = + ( char * )calloc( 1, contextp->cc_extattrlistbufsz ); + ASSERT( contextp->cc_extattrlistbufp ); + contextp->cc_extattrrtrvarrayp = + ( attr_multiop_t * )calloc( contextp->cc_extattrrtrvarraylen, + sizeof( attr_multiop_t )); + ASSERT( contextp->cc_extattrrtrvarrayp ); + contextp->cc_extattrdumpbufp = + ( char * )memalign( sizeof( extattrhdr_t ), + contextp->cc_extattrdumpbufsz ); + ASSERT( contextp->cc_extattrdumpbufp ); +#endif /* EXTATTR */ +#ifdef DMEXTATTR + if (hsm_fs_ctxtp) { + contextp->cc_hsm_f_ctxtp = HsmAllocateFileContext( + hsm_fs_ctxtp); + } else { + contextp->cc_hsm_f_ctxtp = NULL; + } +#endif /* DMEXTATTR */ + + contextp->cc_readlinkbufsz = MAXPATHLEN + SYMLINK_ALIGN; + contextp->cc_readlinkbufp = + ( char * ) calloc( 1, contextp->cc_readlinkbufsz ); + ASSERT( contextp->cc_readlinkbufp ); + + contextp->cc_inomap_state_contextp = inomap_state_getcontext( ); + } + + /* look for command line media labels. these will be assigned + * to each stream as found. this label is only for the media + * object currently in the drive. subsequently inserted media + * objects must get a label via prompting. + */ + + { + context_t *cp = sc_contextp; + context_t *ep = sc_contextp + drivecnt; + + optind = 1; + opterr = 0; + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + switch ( c ) { + case GETOPT_MEDIALABEL: + if ( cp >= ep ) { + mlog( MLOG_NORMAL, + "more -%c arguments " + "than number of drives\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL, + "-%c argument missing\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + cp->cc_Media_firstlabel = optarg; + cp++; + break; + } + } + + if ( cp > sc_contextp && cp < ep ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "media labels given for only %d out of %d " + "drives\n", + cp - sc_contextp, + drivecnt ); + } + } + + if ( preemptchk( PREEMPT_FULL )) { + return BOOL_FALSE; + } + + /* open the dump inventory and a dump inventory write session + * if an inventory update is to be done. first create a cleanup + * handler, to close the inventory on exit. + */ + if ( sc_inv_updatepr ) { + char *qmntpnt; + char *qfsdevice; + + rval = atexit( inv_cleanup ); + ASSERT( ! rval ); + sc_inv_idbtoken = inv_open( ( inv_predicate_t )INV_BY_UUID, + INV_SEARCH_N_MOD, + ( void * )&fsid ); + if ( sc_inv_idbtoken == INV_TOKEN_NULL ) { + return BOOL_FALSE; + } + qmntpnt = ( char * )calloc( 1, strlen( gwhdrtemplatep->gh_hostname ) + + + 1 + + + strlen( mntpnt ) + + + 1 ); + ASSERT( qmntpnt ); + ASSERT( strlen( gwhdrtemplatep->gh_hostname )); + ( void )sprintf( qmntpnt, + "%s:%s", + gwhdrtemplatep->gh_hostname, + mntpnt ); + qfsdevice = ( char * )calloc( 1, strlen( gwhdrtemplatep->gh_hostname ) + + + 1 + + + strlen( fsdevice ) + + + 1 ); + ASSERT( qfsdevice ); + ( void )sprintf( qfsdevice, + "%s:%s", + gwhdrtemplatep->gh_hostname, + fsdevice ); + + /* hold tty signals while creating a new inventory session + */ + ( void )sighold( SIGINT ); + ( void )sighold( SIGQUIT ); + ( void )sighold( SIGHUP ); + + sc_inv_sestoken = inv_writesession_open( sc_inv_idbtoken, + &fsid, + &gwhdrtemplatep->gh_dumpid, + gwhdrtemplatep->gh_dumplabel, + subtreecnt ? BOOL_TRUE + : BOOL_FALSE, + sc_resumepr, + ( u_char_t )sc_level, + drivecnt, + gwhdrtemplatep->gh_timestamp, + qmntpnt, + qfsdevice ); + if( sc_inv_sestoken == INV_TOKEN_NULL ) { + ( void )sigrelse( SIGINT ); + ( void )sigrelse( SIGQUIT ); + ( void )sigrelse( SIGHUP ); + return BOOL_FALSE; + } + + /* open an inventory stream for each stream + */ + sc_inv_stmtokenp = ( inv_stmtoken_t * )calloc( drivecnt, + sizeof( inv_stmtoken_t )); + ASSERT( sc_inv_stmtokenp ); + for ( strmix = 0 ; strmix < drivecnt ; strmix++ ) { + drive_t *drivep = drivepp[ strmix ]; + char *drvpath; + + if ( strcmp( drivep->d_pathname, "stdio" )) { + drvpath = path_reltoabs( drivep->d_pathname, + homedir ); + } else { + drvpath = drivep->d_pathname; + } + sc_inv_stmtokenp[ strmix ] = inv_stream_open( sc_inv_sestoken, + drvpath ); + if ( strcmp( drivep->d_pathname, "stdio" )) { + free( ( void * )drvpath ); + } + if ( sc_inv_stmtokenp[ strmix ] == INV_TOKEN_NULL ) { + ( void )sigrelse( SIGINT ); + ( void )sigrelse( SIGQUIT ); + ( void )sigrelse( SIGHUP ); + return BOOL_FALSE; + } + } + + ( void )sigrelse( SIGINT ); + ( void )sigrelse( SIGQUIT ); + ( void )sigrelse( SIGHUP ); + } + + /* set media change flags to FALSE; + */ + { + ix_t ix; + ix_t endix = sizeof( sc_mcflag ) + / + sizeof( sc_mcflag[ 0 ] ); + for ( ix = 0 ; ix < endix ; ix++ ) { + sc_mcflag[ ix ] = BOOL_FALSE; + } + } + content_media_change_needed = BOOL_FALSE; + + /* initialize the per-drive status + */ + { + ix_t driveix; + for ( driveix = 0 ; driveix < STREAM_SIMMAX ; driveix++ ) { + sc_stat_pds[ driveix ].pds_phase = PDS_NULL; + } + } + +#ifdef SYNCDIR + /* allocate a barrier to synchronize directory dumping + */ + if ( drivecnt > 1 ) { + sc_barrierh = qbarrier_alloc( ); + } + + /* initialize the number of players in the synchronized dir dump. + * they drop out when last media file complete. MUST be modified + * under lock( ). + */ + sc_thrdsdirdumpsynccnt = drivecnt; + +#endif /* SYNCDIR */ + + + return BOOL_TRUE; +} + +#define STATLINESZ 160 + +size_t +content_statline( char **linespp[ ] ) +{ + static char statlinebuf[ STREAM_SIMMAX + 1 ][ STATLINESZ ]; + static char *statline[ STREAM_SIMMAX + 1 ]; + size_t statlinecnt; + size64_t nondirdone; + size64_t datadone; + double percent; + time_t elapsed; + time_t now; + struct tm *tmp; + ix_t i; + + /* build and supply the line array + */ + for ( i = 0 ; i < STREAM_SIMMAX + 1 ; i++ ) { + statline[ i ] = &statlinebuf[ i ][ 0 ]; + } + *linespp = statline; + statlinecnt = 0; + + /* if start time not initialized, return no strings + */ + if ( ! sc_stat_starttime ) { + return 0; + } + + /* calculate the elapsed time + */ + elapsed = time( 0 ) - sc_stat_starttime; + + /* get local time + */ + now = time( 0 ); + tmp = localtime( &now ); + + /* if inomap phase indicated, report on that + */ + if ( sc_stat_inomapphase && sc_stat_inomapcnt ) { + if ( sc_stat_inomappass ) { + sprintf( statline[ 0 ], + "status at %02d:%02d:%02d: " + "inomap phase %u pass %u " + "%llu/%llu inos scanned, " + "%lu seconds elapsed\n", + tmp->tm_hour, + tmp->tm_min, + tmp->tm_sec, + (unsigned int)sc_stat_inomapphase, + (unsigned int)sc_stat_inomappass, + (unsigned long long)sc_stat_inomapdone, + (unsigned long long)sc_stat_inomapcnt, + elapsed ); + ASSERT( strlen( statline[ 0 ] ) < STATLINESZ ); + } else { + sprintf( statline[ 0 ], + "status at %02d:%02d:%02d: " + "inomap phase %u " + "%llu/%llu inos scanned, " + "%lu seconds elapsed\n", + tmp->tm_hour, + tmp->tm_min, + tmp->tm_sec, + (unsigned int)sc_stat_inomapphase, + (unsigned long long)sc_stat_inomapdone, + (unsigned long long)sc_stat_inomapcnt, + elapsed ); + ASSERT( strlen( statline[ 0 ] ) < STATLINESZ ); + } + return 1; + } + + /* if stats not initialized, just display elapsed time + */ + if ( ! sc_stat_datasz ) { + sprintf( statline[ 0 ], + "status at %02d:%02d:%02d: " + "%lu seconds elapsed\n", + tmp->tm_hour, + tmp->tm_min, + tmp->tm_sec, + elapsed ); + ASSERT( strlen( statline[ 0 ] ) < STATLINESZ ); + return 1; + } + + /* get the accumulated totals for non-dir inos and data bytes dumped + */ + lock( ); + nondirdone = sc_stat_nondirdone; + datadone = sc_stat_datadone; + unlock( ); + + /* calculate percentage of data dumped + */ + if ( sc_stat_datasz ) { + percent = ( double )datadone + / + ( double )sc_stat_datasz; + percent *= 100.0; + } else { + percent = 100.0; + } + if ( percent > 100.0 ) { + percent = 100.0; + } + + /* format the status line in a local static buffer (non-re-entrant!) + */ + sprintf( statline[ 0 ], + "status at %02d:%02d:%02d: %llu/%llu files dumped, " + "%.1f%%%% complete, " + "%lu seconds elapsed\n", + tmp->tm_hour, + tmp->tm_min, + tmp->tm_sec, + (unsigned long long)nondirdone, + (unsigned long long)sc_stat_nondircnt, + percent, + elapsed ); + ASSERT( strlen( statline[ 0 ] ) < STATLINESZ ); + + /* optionally create stat lines for each drive + */ + statlinecnt = 1; + for ( i = 0 ; i < drivecnt ; i++ ) { + pds_t *pdsp = &sc_stat_pds[ i ]; + if ( pdsp->pds_phase == PDS_NULL + || + pdsp->pds_phase == PDS_NONDIR ) { + continue; + } + statline[ i + 1 ][ 0 ] = 0; + if ( drivecnt > 1 ) { + sprintf( statline[ i + 1 ], + "drive %u: ", + (unsigned int)i ); + } + switch( pdsp->pds_phase ) { + case PDS_INOMAP: + strcat( statline[ i + 1 ], + "dumping inomap" ); + break; + case PDS_DIRRENDEZVOUS: + strcat( statline[ i + 1 ], + "waiting for synchronized directory dump" ); + break; + case PDS_DIRDUMP: + sprintf( &statline[ i + 1 ] + [ strlen( statline[ i + 1 ] ) ], + "%llu/%llu directories dumped", + (unsigned long long)pdsp->pds_dirdone, + (unsigned long long)sc_stat_dircnt ); + break; + case PDS_INVSYNC: + strcat( statline[ i + 1 ], + "waiting to dump inventory" ); + break; + case PDS_INVDUMP: + strcat( statline[ i + 1 ], + "dumping inventory" ); + break; + case PDS_TERMDUMP: + strcat( statline[ i + 1 ], + "dumping stream terminator" ); + break; + default: + break; + } + sprintf( &statline[ i + 1 ] + [ strlen( statline[ i + 1 ] ) ], + "\n" ); + ASSERT( strlen( statline[ i + 1 ] ) < STATLINESZ ); + statlinecnt++; + } + + return statlinecnt; +} + +static void +mark_set( drive_t *drivep, xfs_ino_t ino, off64_t offset, int32_t flags ) +{ + drive_ops_t *dop = drivep->d_opsp; + mark_t *markp = ( mark_t * )calloc( 1, sizeof( mark_t )); + ASSERT( markp ); + + if ( flags & STARTPT_FLAGS_NULL ) { + mlog( MLOG_DEBUG, + "setting media NULL mark\n" ); + } else if ( flags & STARTPT_FLAGS_END ) { + mlog( MLOG_DEBUG, + "setting media END mark\n" ); + } else { + mlog( MLOG_DEBUG, + "setting media mark" + " for ino %llu offset %lld\n", + ino, + offset ); + } + + markp->startpt.sp_ino = ino; + markp->startpt.sp_offset = offset; + markp->startpt.sp_flags = flags; + ( * dop->do_set_mark )( drivep, + mark_callback, + ( void * )drivep->d_index, + ( drive_markrec_t * )markp ); +} + +static void +mark_callback( void *p, drive_markrec_t *dmp, bool_t committed ) +{ + /* get context + */ + ix_t strmix = ( ix_t )p; + context_t *contextp = &sc_contextp[ strmix ]; + drive_t *drivep = drivepp[ strmix ]; + drive_hdr_t *dwhdrp = drivep->d_writehdrp; + media_hdr_t *mwhdrp = ( media_hdr_t * )dwhdrp->dh_upper; + content_hdr_t *cwhdrp = ( content_hdr_t * )mwhdrp->mh_upper; + content_inode_hdr_t *scwhdrp = ( content_inode_hdr_t * ) + ( void * ) + cwhdrp->ch_specific; + + /* this is really a mark_t, allocated by mark_set() + */ + mark_t *markp = ( mark_t * )dmp; + + if ( committed ) { + /* bump the per-mfile mark committed count + */ + contextp->cc_markscommitted++; + + /* copy the mark into the write header: this establishes the + * starting point should we need to retry the non-dir portion + * of the dump + */ + + /* log the mark commit + */ + if ( markp->startpt.sp_flags & STARTPT_FLAGS_NULL ) { + mlog( MLOG_DEBUG, + "media NULL mark committed" + " in media file %d\n", + mwhdrp->mh_dumpfileix ); + scwhdrp->cih_startpt.sp_flags |= STARTPT_FLAGS_NULL; + } else if ( markp->startpt.sp_flags & STARTPT_FLAGS_END ) { + mlog( MLOG_DEBUG, + "media END mark committed" + " in media file %d\n", + mwhdrp->mh_dumpfileix ); + if ( scwhdrp->cih_endpt.sp_flags & STARTPT_FLAGS_END ) { + scwhdrp->cih_startpt.sp_ino++; + scwhdrp->cih_startpt.sp_offset = 0; + } else { + scwhdrp->cih_startpt = scwhdrp->cih_endpt; + } + scwhdrp->cih_startpt.sp_flags |= STARTPT_FLAGS_END; + } else { + mlog( MLOG_DEBUG, + "media mark committed" + " for ino %llu offset %lld" + " in media file %d\n", + markp->startpt.sp_ino, + markp->startpt.sp_offset, + mwhdrp->mh_dumpfileix ); + scwhdrp->cih_startpt = markp->startpt; + } + } else { + /* note the mark was not committed + */ + if ( markp->startpt.sp_flags & STARTPT_FLAGS_NULL ) { + mlog( MLOG_DEBUG, + "media NULL mark -NOT- committed\n" ); + } else if ( markp->startpt.sp_flags & STARTPT_FLAGS_END ) { + mlog( MLOG_DEBUG, + "media END mark -NOT- committed\n" ); + } else { + mlog( MLOG_DEBUG, + "media mark -NOT- committed" + " for ino %llu offset %lld\n", + markp->startpt.sp_ino, + markp->startpt.sp_offset ); + } + } + + /* get rid of this mark (it was allocated by mark_set()) + */ + free( ( void * )markp ); +} + +/* begin - called by stream process to invoke the dump stream + */ +intgen_t +content_stream_dump( ix_t strmix ) +{ + context_t *contextp = &sc_contextp[ strmix ]; + drive_t *drivep = drivepp[ strmix ]; + drive_hdr_t *dwhdrp = drivep->d_writehdrp; + media_hdr_t *mwhdrp = ( media_hdr_t * )dwhdrp->dh_upper; + content_hdr_t *cwhdrp = ( content_hdr_t * )mwhdrp->mh_upper; + content_inode_hdr_t *scwhdrp = ( content_inode_hdr_t * ) + cwhdrp->ch_specific; + bool_t all_nondirs_committed; + bool_t empty_mediafile; + time_t elapsed; + inv_stmtoken_t inv_stmt; + xfs_bstat_t *bstatbufp; + const size_t bstatbuflen = BSTATBUFLEN; + intgen_t rval; + rv_t rv; + + /* sanity checks + */ + ASSERT( RV_OK == 0 ); /* bigstat_iter depends on this */ + + /* allocate a buffer for use by bstat_iter + */ + bstatbufp = ( xfs_bstat_t * )calloc( bstatbuflen, + sizeof( xfs_bstat_t )); + ASSERT( bstatbufp ); + + /* determine if stream terminators will be used and are expected. + * this will be revised each time a new media file is begun. + */ + update_cc_Media_useterminatorpr( drivep, contextp ); + + /* check in + */ + lock( ); + sc_thrdsarrivedcnt++; + unlock( ); + + /* fill in write hdr stream start and end points + */ + scwhdrp->cih_startpt = sc_startptp[ strmix ]; + if ( strmix < drivecnt - 1 ) { + scwhdrp->cih_endpt = sc_startptp[ strmix + 1 ]; + } else { + scwhdrp->cih_endpt.sp_flags = STARTPT_FLAGS_END; + } + + /* fill in inomap fields of write hdr + */ + inomap_writehdr( scwhdrp ); + + /* used to decide if any non-dirs not yet on media + */ + all_nondirs_committed = BOOL_FALSE; + + /* used to guarantee we don't count the same ino more than once + * in the progress stats + */ + contextp->cc_stat_lastino = 0; + + /* used to detect generation of an empty media file; + * contains at most an inomap and dirdump and null file hdr. + */ + empty_mediafile = BOOL_FALSE; + + /* get the inventory stream token + */ + if ( sc_inv_stmtokenp ) { + inv_stmt = sc_inv_stmtokenp[ strmix ]; + } else { + inv_stmt = INV_TOKEN_NULL; + } + + /* loop, dumping media files, until the entire stream is dumped. + * each time we hit EOM/EOF, repeat the inomap and directory dump. + * dump the non-dirs beginning with the current startpoint. + * The current startpoint will be updated each time a media mark + * is committed. + */ + for ( ; ; ) { + xfs_ino_t startino; + bool_t stop_requested; + bool_t hit_eom; + bool_t all_dirs_committed; + bool_t all_nondirs_sent; + off64_t startoffset; + off64_t ncommitted; + bool_t done; + + /* used to decide whether or not to go back for more. + */ + stop_requested = BOOL_FALSE; + + /* TRUE if hit EOM while dumping + */ + hit_eom = BOOL_FALSE; + + /* used to decide if the media file contains all + * of the inomap and dirdump. + */ + all_dirs_committed = BOOL_FALSE; + + /* used to decide if all non-dirs were sent (not necessarily + * committed) + */ + all_nondirs_sent = BOOL_FALSE; + + /* always clear the NULL flag from the stream startpoint + * before beginning the media file. allows detection + * of null file hdr commit. + */ + scwhdrp->cih_startpt.sp_flags &= ~STARTPT_FLAGS_NULL; + + /* save the original start points, to be given to + * the inventory at the end of each media file. + */ + startino = scwhdrp->cih_startpt.sp_ino; + startoffset = scwhdrp->cih_startpt.sp_offset; + + /* set the accumulated file size to zero. + * this will be monitored by dump_file() to decide + * if the current dump file is too long. if so, + * it will set a startpoint and spoof an EOF. + * this will cause a new dump file to be started, + * beginning at the startpoint. + */ + contextp->cc_mfilesz = 0; + + /* tell the Media abstraction to position a media object + * and begin a new media file. This will dump the media + * file header if successful. + */ + rv = Media_mfile_begin( drivep, contextp, BOOL_TRUE ); + if ( rv == RV_INTR ) { + return EXIT_INTERRUPT; + } + if ( rv == RV_TIMEOUT ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "media change timeout will be treated as " + "a request to stop using drive: " + "can resume later\n" ); + return EXIT_NORMAL; + } + if ( rv == RV_QUIT ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "media change decline will be treated as " + "a request to stop using drive: " + "can resume later\n" ); + return EXIT_NORMAL; + } + if ( rv == RV_DRIVE ) { + return EXIT_NORMAL; + } + if ( rv == RV_ERROR ) { + return EXIT_ERROR; + } + if ( rv == RV_CORE ) { + return EXIT_FAULT; + } + ASSERT( rv == RV_OK ); + if ( rv != RV_OK ) { + return EXIT_FAULT; + } + + /* sync up here with other streams if reasonable + */ + mlog( MLOG_VERBOSE, + "creating dump session media file %u " + "(media %u, file %u)\n", + mwhdrp->mh_dumpfileix, + mwhdrp->mh_mediaix, + mwhdrp->mh_mediafileix ); + + /* initialize the count of marks committed in the media file. + * will be bumped by mark_callback(). + */ + contextp->cc_markscommitted = 0; + + /* first dump the inomap + */ + mlog( MLOG_VERBOSE, + "dumping ino map\n" ); + sc_stat_pds[ strmix ].pds_phase = PDS_INOMAP; + rv = inomap_dump( drivep ); + if ( rv == RV_INTR ) { + stop_requested = BOOL_TRUE; + goto decision_more; + } + if ( rv == RV_EOM ) { + hit_eom = BOOL_TRUE; + goto decision_more; + } + if ( rv == RV_DRIVE ) { + free( ( void * )bstatbufp ); + return EXIT_NORMAL; + } + if ( rv == RV_ERROR ) { + free( ( void * )bstatbufp ); + return EXIT_ERROR; + } + if ( rv == RV_CORE ) { + free( ( void * )bstatbufp ); + return EXIT_FAULT; + } + ASSERT( rv == RV_OK ); + if ( rv != RV_OK ) { + free( ( void * )bstatbufp ); + return EXIT_FAULT; + } + + /* now dump the directories. use the bigstat iterator + * capability to call my dump_dir function + * for each directory in the bitmap. + */ + sc_stat_pds[ strmix ].pds_dirdone = 0; + rv = dump_dirs( strmix, bstatbufp, bstatbuflen ); + if ( rv == RV_INTR ) { + stop_requested = BOOL_TRUE; + goto decision_more; + } + if ( rv == RV_EOM ) { + hit_eom = BOOL_TRUE; + goto decision_more; + } + if ( rv == RV_DRIVE ) { + free( ( void * )bstatbufp ); + return EXIT_NORMAL; + } + if ( rv == RV_ERROR ) { + free( ( void * )bstatbufp ); + return EXIT_ERROR; + } + if ( rv == RV_CORE ) { + free( ( void * )bstatbufp ); + return EXIT_FAULT; + } + ASSERT( rv == RV_OK ); + if ( rv != RV_OK ) { + free( ( void * )bstatbufp ); + return EXIT_FAULT; + } + + /* finally, dump the non-directory files beginning with this + * stream's startpoint. Note that dump_file will set one or + * more media marks; the callback will update the hdr's + * startpoint; thus each time a demarcated portion of a + * non-directory file is fully committed to media, + * the starting point for the next media file will be advanced. + */ + if ( ! all_nondirs_committed ) { + mlog( MLOG_VERBOSE, + "dumping non-directory files\n" ); + sc_stat_pds[ strmix ].pds_phase = PDS_NONDIR; + rv = RV_OK; + rval = bigstat_iter( sc_fshandlep, + sc_fsfd, + BIGSTAT_ITER_NONDIR, + scwhdrp->cih_startpt.sp_ino, + ( intgen_t ( * )( void *, jdm_fshandle_t *, intgen_t, xfs_bstat_t * )) + dump_file, + ( void * )strmix, + ( intgen_t * )&rv, + ( miniroot || pipeline ) ? + (bool_t (*)(int))preemptchk : 0, + bstatbufp, + bstatbuflen ); + if ( rval ) { + free( ( void * )bstatbufp ); + return EXIT_FAULT; + } + if ( rv == RV_INTR ) { + stop_requested = BOOL_TRUE; + goto decision_more; + } + if ( rv == RV_EOM ) { + hit_eom = BOOL_TRUE; + goto decision_more; + } + if ( rv == RV_EOF ) { + goto decision_more; + } + if ( rv == RV_DRIVE ) { + free( ( void * )bstatbufp ); + return EXIT_NORMAL; + } + if ( rv == RV_ERROR ) { + free( ( void * )bstatbufp ); + return EXIT_ERROR; + } + if ( rv == RV_CORE ) { + free( ( void * )bstatbufp ); + return EXIT_FAULT; + } + ASSERT( rv == RV_OK || rv == RV_NOMORE ); + if ( rv != RV_OK && rv != RV_NOMORE ) { + free( ( void * )bstatbufp ); + return EXIT_FAULT; + } + } + + /* if we got here, all files were sent without hitting + * the end of the current media object, or hitting the + * media file size limit. send the special END mark. + * this is only send at the end of the last media file in the + * dump session. if it actually gets committed to media, + * we know the last data written to media all made it. + * we won't know if this mark is committed to media until + * we attempt to end the write stream. + */ + all_nondirs_sent = BOOL_TRUE; + mark_set( drivep, + INO64MAX, + OFF64MAX, + STARTPT_FLAGS_END ); + +decision_more: + /* write a null file hdr, to let restore recognize + * the end of the media file. the flags indicate + * whether or not this is intended to be the last + * media file in the stream. don't bother if we hit + * EOM. + */ + if ( ! hit_eom ) { + rv = dump_filehdr( drivep, + contextp, + 0, + 0, + all_nondirs_sent + ? + ( FILEHDR_FLAGS_NULL + | + FILEHDR_FLAGS_END ) + : + FILEHDR_FLAGS_NULL ); + if ( rv == RV_DRIVE ) { + free( ( void * )bstatbufp ); + return EXIT_NORMAL; + } + if ( rv == RV_CORE ) { + free( ( void * )bstatbufp ); + return EXIT_FAULT; + } + if ( rv == RV_ERROR ) { + free( ( void * )bstatbufp ); + return EXIT_ERROR; + } + + /* send a mark to detect if the null file header made + * it. mark callback will adjust start pt before this + * call returns if the null file header made it. + */ + mark_set( drivep, + INO64MAX, + OFF64MAX, + all_nondirs_sent + ? + STARTPT_FLAGS_NULL | STARTPT_FLAGS_END + : + STARTPT_FLAGS_NULL ); + } + + /* tell the Media abstraction to end the media file. + * this is done before the inventory update, to + * see how much was actually committed to media. + * will invoke drive end_write, which will flush + * all pending marks. + */ + mlog( MLOG_VERBOSE, + "ending media file\n" ); + ncommitted = 0; + rv = Media_mfile_end( drivep, + contextp, + mwhdrp, + &ncommitted, + hit_eom ); + if ( rv == RV_DRIVE ) { + free( ( void * )bstatbufp ); + return EXIT_NORMAL; + } + if ( rv == RV_CORE ) { + free( ( void * )bstatbufp ); + return EXIT_FAULT; + } + mlog( MLOG_VERBOSE, + "media file size %lld bytes\n", + ncommitted ); + + /* if at least one mark committed, we know all of + * the inomap and dirdump was committed. + */ + all_dirs_committed = ( contextp->cc_markscommitted > 0 ); + + /* at this point we can check the new start point + * to determine if all nondirs have been committed. + * if this flag was already set, then this is a + * inomap and dirdump-only media file. + */ + if ( scwhdrp->cih_startpt.sp_flags & STARTPT_FLAGS_END ) { + if ( all_nondirs_committed ) { + empty_mediafile = BOOL_TRUE; + } + all_nondirs_committed = BOOL_TRUE; + } + + /* we are done if all nondirs have been committed. + * it is not necessary for the null file header to have + * been committed. + */ + done = all_nondirs_committed; + +#ifdef SYNCDIR + /* drop out of the synchronous dump game if done + */ + if ( done ) { + /* REFERENCED */ + size_t tmpthrdsdirdumpsynccnt; + lock( ); + tmpthrdsdirdumpsynccnt = sc_thrdsdirdumpsynccnt; + sc_thrdsdirdumpsynccnt--; + unlock( ); + ASSERT( tmpthrdsdirdumpsynccnt > 0 ); + } +#endif /* SYNCDIR */ + + /* tell the inventory about the media file + */ + if ( inv_stmt != INV_TOKEN_NULL ) { + bool_t ok; + + if ( ! all_dirs_committed ) { + mlog( MLOG_DEBUG, + "giving inventory " + "partial dirdump media file\n" ); + } else if ( done && empty_mediafile ) { + mlog( MLOG_DEBUG, + "giving inventory " + "empty last media file: " + "%llu:%lld\n", + startino, + startoffset ); + } else if ( empty_mediafile ) { + mlog( MLOG_DEBUG, + "giving inventory " + "empty media file: " + "%llu:%lld\n", + startino, + startoffset ); + } else if ( done ) { + mlog( MLOG_DEBUG, + "giving inventory " + "last media file: " + "%llu:%lld\n", + startino, + startoffset ); + } else { + mlog( MLOG_DEBUG, + "giving inventory " + "media file: " + "%llu:%lld - %llu:%lld\n", + startino, + startoffset, + scwhdrp->cih_startpt.sp_ino, + scwhdrp->cih_startpt.sp_offset ); + } + + /* already thread-safe, don't need to lock + */ + ok = inv_put_mediafile( inv_stmt, + &mwhdrp->mh_mediaid, + mwhdrp->mh_medialabel, + ( u_intgen_t )mwhdrp->mh_mediafileix, + startino, + startoffset, + scwhdrp->cih_startpt.sp_ino, + scwhdrp->cih_startpt.sp_offset, + ncommitted, + all_dirs_committed + && + ! empty_mediafile, + BOOL_FALSE ); + if ( ! ok ) { + mlog( MLOG_NORMAL, + "inventory media file put failed\n" ); + } + } + if ( done ) { + contextp->cc_completepr = BOOL_TRUE; + /* so inv_end_stream and main will know + */ + } + + /* don't go back for more if done or stop was requested + */ + if ( done || stop_requested ) { + break; + } + } + + /* check in + */ + lock( ); + sc_thrdsdonecnt++; + unlock( ); + + /* dump the session inventory and terminator here, if the drive + * supports multiple media files. must wait until all + * streams have completed or given up, so all media files + * from all streams have been registered. + */ + if ( drivep->d_capabilities & DRIVE_CAP_FILES ) { + if ( ! miniroot ) { + if ( stream_cnt( ) > 1 ) { + mlog( MLOG_VERBOSE, + "waiting for synchonized " + "session inventory dump\n" ); + sc_stat_pds[ strmix ].pds_phase = PDS_INVSYNC; + } + + /* first be sure all threads have begun + */ + while ( sc_thrdsarrivedcnt < drivecnt ) { + sleep( 1 ); + } + /* now wait for survivors to checkin + */ + while ( sc_thrdsdonecnt < stream_cnt( )) { + sleep( 1 ); + } + } + /* proceeed + */ + sc_stat_pds[ strmix ].pds_phase = PDS_INVDUMP; + if ( dump_session_inv( drivep, contextp, mwhdrp, scwhdrp )) { + sc_stat_pds[ strmix ].pds_phase = PDS_TERMDUMP; + dump_terminator( drivep, contextp, mwhdrp ); + } + } + + sc_stat_pds[ strmix ].pds_phase = PDS_NULL; + + free( ( void * )bstatbufp ); + + elapsed = time( 0 ) - sc_stat_starttime; + + mlog( MLOG_TRACE, + "ending stream: %u seconds elapsed\n", + elapsed ); + + return EXIT_NORMAL; +} + +/* indicates if the dump was complete. + * easy to tell: initially contextp->cc_completepr is false for each stream. + * only set true if stream complete. if any stream NOT complete, + * dump is not complete. + */ +bool_t +content_complete( void ) +{ + time_t elapsed; + bool_t completepr; + intgen_t i; + + completepr = check_complete_flags( ); + + elapsed = time( 0 ) - sc_stat_starttime; + + mlog( MLOG_VERBOSE, + "dump size (non-dir files) : %llu bytes\n", + sc_stat_datadone ); + + if ( completepr ) { + if( sc_savequotas ) { + for(i = 0; i < (sizeof(quotas) / sizeof(quotas[0])); i++) { + if( quotas[i].savequotas && unlink( quotas[i].quotapath ) < 0 ) { + mlog( MLOG_ERROR, + "unable to remove %s: %s\n", + quotas[i].quotapath, + strerror ( errno )); + } + } + } + + mlog( MLOG_VERBOSE, + "dump complete" + ": %u seconds elapsed" + "\n", + elapsed ); + } else { + if ( sc_inv_updatepr ) { + mlog( MLOG_VERBOSE | MLOG_NOTE, + "dump interrupted" + ": %u seconds elapsed" + ": may resume later using -%c option" + "\n", + elapsed, + GETOPT_RESUME ); + } else { + mlog( MLOG_VERBOSE | MLOG_NOTE, + "dump interrupted" + ": %u seconds elapsed" + "\n", + elapsed ); + } + } + return completepr; +} + +#define PREAMBLEMAX 3 +#define QUERYMAX 1 +#define CHOICEMAX 30 +#define ACKMAX 3 +#define POSTAMBLEMAX 3 +#define DLOG_TIMEOUT 300 +#define DLOG_TIMEOUT_MEDIA 3600 + +#define CHOICESTRSZ 10 +typedef struct { ix_t thrdix; char choicestr[ CHOICESTRSZ ]; } cttm_t; + +char * +content_mediachange_query( void ) +{ + cttm_t choicetothrdmap[ STREAM_SIMMAX ]; + char *querystr[ QUERYMAX ]; + size_t querycnt; + char *choicestr[ CHOICEMAX ]; + size_t choicecnt; + size_t maxdrvchoiceix; + size_t nochangeix; + size_t responseix; + ix_t thrdix; + + querycnt = 0; + querystr[ querycnt++ ] = "select a drive to acknowledge media change\n"; + choicecnt = 0; + maxdrvchoiceix = 0; + for ( thrdix = 0 ; thrdix < STREAM_SIMMAX ; thrdix++ ) { + if ( sc_mcflag[ thrdix ] ) { + choicetothrdmap[ choicecnt ].thrdix = thrdix; + sprintf( choicetothrdmap[ choicecnt ].choicestr, + "drive %u", + (unsigned int)thrdix ); + choicestr[ choicecnt ] = + choicetothrdmap[ choicecnt ].choicestr; + maxdrvchoiceix = choicecnt; + choicecnt++; + } + } + nochangeix = choicecnt; + choicestr[ choicecnt++ ] = "continue"; + ASSERT( choicecnt <= CHOICEMAX ); + responseix = dlog_multi_query( querystr, + querycnt, + choicestr, + choicecnt, + 0, /* hilitestr */ + IXMAX, /* hiliteix */ + 0, /* defaultstr */ + nochangeix, /* defaultix */ + DLOG_TIMEOUT_MEDIA, + nochangeix, /* timeout ix */ + nochangeix, /* sigint ix */ + nochangeix, /* sighup ix */ + nochangeix);/* sigquit ix */ + if ( responseix <= maxdrvchoiceix ) { + clr_mcflag( choicetothrdmap[ responseix ].thrdix ); + return "media change acknowledged\n"; + } + ASSERT( responseix == nochangeix ); + return "continuing\n"; +} + + +static void +update_cc_Media_useterminatorpr( drive_t *drivep, context_t *contextp ) +{ + intgen_t dcaps = drivep->d_capabilities; + + contextp->cc_Media_useterminatorpr = BOOL_TRUE; + if ( ! ( dcaps & DRIVE_CAP_FILES )) { + contextp->cc_Media_useterminatorpr = BOOL_FALSE; + } + if ( ! ( dcaps & DRIVE_CAP_OVERWRITE )) { + contextp->cc_Media_useterminatorpr = BOOL_FALSE; + } + if ( ! ( dcaps & DRIVE_CAP_BSF )) { + contextp->cc_Media_useterminatorpr = BOOL_FALSE; + } + if ( ! ( dcaps & DRIVE_CAP_APPEND )) { + contextp->cc_Media_useterminatorpr = BOOL_FALSE; + } +} + +static rv_t +dump_dirs( ix_t strmix, xfs_bstat_t *bstatbufp, size_t bstatbuflen ) +{ + xfs_ino_t lastino; + size_t bulkstatcallcnt; + xfs_fsop_bulkreq_t bulkreq, sbulkreq; + + /* begin iteration at ino zero + */ + lastino = 0; + for ( bulkstatcallcnt = 0 ; ; bulkstatcallcnt++ ) { + xfs_bstat_t *p; + xfs_bstat_t *endp; + size_t buflenout; + intgen_t rval; + +#ifdef SYNCDIR + /* have all threads rendezvous + */ + if ( sc_thrdsdirdumpsynccnt > 1 && stream_cnt( ) > 1 ) { + rv_t rv; + mlog( bulkstatcallcnt == 0 ? MLOG_VERBOSE : MLOG_NITTY, + "waiting for synchronized directory dump\n" ); + sc_stat_pds[ strmix ].pds_phase = PDS_DIRRENDEZVOUS; + rv = dump_dirs_rendezvous( ); + if ( rv == RV_INTR ) { + return RV_INTR; + } + ASSERT( rv == RV_OK ); + } +#endif /* SYNCDIR */ + + if ( bulkstatcallcnt == 0 ) { + mlog( MLOG_VERBOSE, + "dumping directories\n" ); + } + sc_stat_pds[ strmix ].pds_phase = PDS_DIRDUMP; + + /* check for interruption + */ + if ( cldmgr_stop_requested( )) { + return RV_INTR; + } + + /* get a bunch of bulkstats + */ + mlog( MLOG_NITTY, + "dump_dirs SGI_FS_BULKSTAT %u buf len %u\n", + bulkstatcallcnt, + bstatbuflen ); + + bulkreq.lastip = &lastino; + bulkreq.icount = bstatbuflen; + bulkreq.ubuffer = bstatbufp; + bulkreq.ocount = (__s32 *)&buflenout; + + rval = ioctl(sc_fsfd, XFS_IOC_FSBULKSTAT, &bulkreq); + + if ( rval ) { + mlog( MLOG_NORMAL, + "SGI_FS_BULKSTAT failed: " + "%s (%d)\n", + strerror( errno ), + errno ); + return RV_ERROR; + } + mlog( MLOG_NITTY, + "dump_dirs SGI_FS_BULKSTAT returns %u entries\n", + buflenout ); + + /* check if done + */ + if ( buflenout == 0 ) { + return RV_OK; + } + + /* step through each node, dumping if + * appropriate + */ + for ( p = bstatbufp, endp = bstatbufp + buflenout + ; + p < endp + ; + p++ ) { + rv_t rv; + if ( (!p->bs_nlink || !p->bs_mode) && p->bs_ino != 0 ) { + /* inode being modified, get synced data */ + mlog( MLOG_NITTY, + "ino %llu needs second bulkstat\n", + p->bs_ino ); + + sbulkreq.lastip = &p->bs_ino; + sbulkreq.icount = 1; + sbulkreq.ubuffer = p; + sbulkreq.ocount = NULL; + ioctl(sc_fsfd, XFS_IOC_FSBULKSTAT_SINGLE, &sbulkreq); + } + if ( ( p->bs_mode & S_IFMT ) != S_IFDIR ) { + continue; + } + + + rv = dump_dir( strmix, sc_fshandlep, sc_fsfd, p ); + if ( rv != RV_OK ) { + return rv; + } + } + } + /* NOTREACHED */ +} + +#ifdef SYNCDIR +static rv_t +dump_dirs_rendezvous( void ) +{ + static size_t localsync1; + static size_t localsync2; + + sc_thrdswaitingdirdumpsync2 = 0; + lock( ); + sc_thrdswaitingdirdumpsync1++; + localsync1 = sc_thrdswaitingdirdumpsync1; + localsync2 = sc_thrdswaitingdirdumpsync2; + unlock( ); + while ( localsync2 == 0 + && + localsync1 < min( stream_cnt( ), sc_thrdsdirdumpsynccnt )) { + sleep( 1 ); + if ( cldmgr_stop_requested( )) { + lock( ); + sc_thrdswaitingdirdumpsync1--; + unlock( ); + return RV_INTR; + } + lock( ); + localsync1 = sc_thrdswaitingdirdumpsync1; + localsync2 = sc_thrdswaitingdirdumpsync2; + unlock( ); + } + lock( ); + sc_thrdswaitingdirdumpsync1--; + sc_thrdswaitingdirdumpsync2++; + localsync2 = sc_thrdswaitingdirdumpsync2; + unlock( ); + while ( localsync2 < min( stream_cnt( ), sc_thrdsdirdumpsynccnt )) { + sleep( 1 ); + if ( cldmgr_stop_requested( )) { + return RV_INTR; + } + lock( ); + localsync2 = sc_thrdswaitingdirdumpsync2; + unlock( ); + } + if ( cldmgr_stop_requested( )) { + return RV_INTR; + } + + qbarrier( sc_barrierh, min( stream_cnt( ), sc_thrdsdirdumpsynccnt )); + + return RV_OK; +} +#endif /* SYNCDIR */ + +static rv_t +dump_dir( ix_t strmix, + jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp ) +{ + context_t *contextp = &sc_contextp[ strmix ]; + drive_t *drivep = drivepp[ strmix ]; + void *inomap_state_contextp = contextp->cc_inomap_state_contextp; + intgen_t state; + intgen_t fd; + struct dirent *gdp = ( struct dirent *)contextp->cc_getdentsbufp; + size_t gdsz = contextp->cc_getdentsbufsz; + intgen_t gdcnt; + u_int32_t gen; + rv_t rv; + + /* no way this can be non-dir, but check anyway + */ + ASSERT( ( statp->bs_mode & S_IFMT ) == S_IFDIR ); + if ( ( statp->bs_mode & S_IFMT ) != S_IFDIR ) { + return RV_OK; + } + + /* skip if no links + */ + if ( statp->bs_nlink < 1 ) { + return RV_OK; + } + + /* see what the inomap says about this ino + */ + state = inomap_state( inomap_state_contextp, statp->bs_ino ); + + /* skip if not in inomap + */ + if ( state == MAP_INO_UNUSED + || + state == MAP_DIR_NOCHNG + || + state == MAP_NDR_NOCHNG ) { + if ( state == MAP_NDR_NOCHNG ) { + mlog( MLOG_DEBUG, + "inomap inconsistency ino %llu: " + "map says is non-dir but is dir: skipping\n", + statp->bs_ino ); + } + return RV_OK; + } + + /* note if map says a non-dir + */ + if ( state == MAP_NDR_CHANGE ) { + mlog( MLOG_DEBUG, + "inomap inconsistency ino %llu: " + "map says non-dir but is dir: skipping\n", + statp->bs_ino ); + return RV_OK; + } + + /* bump the stats now. a bit early, but fewer lines of code + */ + sc_stat_pds[ strmix ].pds_dirdone++; + + /* if bulkstat ino# occupied more than 32 bits and + * linux ino# for getdents is 32 bits then + * warn and skip. + */ + if ( statp->bs_ino > ( xfs_ino_t )INOMAX ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "unable to dump directory: ino %llu too large\n", + statp->bs_ino ); + return RV_OK; /* continue anyway */ + } + + mlog( MLOG_TRACE, + "dumping directory ino %llu\n", + statp->bs_ino ); + + /* open the directory named by statp + */ + fd = jdm_open( fshandlep, statp, O_RDONLY ); + if ( fd < 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "unable to open directory: ino %llu: %s\n", + statp->bs_ino, strerror( errno ) ); + return RV_OK; /* continue anyway */ + } + + /* dump the file header. + */ + rv = dump_filehdr( drivep, contextp, statp, 0, 0 ); + if ( rv != RV_OK ) { + close( fd ); + return rv; + } + + /* dump dirents - lots of buffering done here, to achieve OS- + * independence. if proves to be to much overhead, can streamline. + */ + for ( gdcnt = 1, rv = RV_OK ; rv == RV_OK ; gdcnt++ ) { + struct dirent *p; + intgen_t nread; + register size_t reclen; + + nread = getdents_wrap( fd, (char *)gdp, gdsz ); + + /* negative count indicates something very bad happened; + * try to gracefully end this dir. + */ + if ( nread < 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "unable to read dirents (%d) for " + "directory ino %llu: %s\n", + gdcnt, + statp->bs_ino, + strerror( errno )); + /* !!! curtis looked at this, and pointed out that + * we could take some recovery action here. if the + * errno is appropriate, lseek64 to the value of + * doff field of the last dirent successfully + * obtained, and contiue the loop. + */ + nread = 0; /* pretend we are done */ + } + + /* no more directory entries: break; + */ + if ( nread == 0 ) { + break; + } + + /* translate and dump each entry: skip "." and ".." + * and null entries. + */ + for ( p = gdp, + reclen = ( size_t )p->d_reclen + ; + nread > 0 + ; + nread -= ( intgen_t )reclen, + ASSERT( nread >= 0 ), + p = ( struct dirent * )( ( char * )p + reclen ), + reclen = ( size_t )p->d_reclen ) { + xfs_ino_t ino; + register size_t namelen = strlen( p->d_name ); +#ifdef DEBUG + register size_t nameszmax = ( size_t )reclen + - + offsetofmember( struct dirent, + d_name ); + + /* getdents(2) guarantees that the string will + * be null-terminated, but the record may have + * padding after the null-termination. + */ + ASSERT( namelen < nameszmax ); +#endif + + /* skip "." and ".." + */ + if ( *( p->d_name + 0 ) == '.' + && + ( *( p->d_name + 1 ) == 0 + || + ( *( p->d_name + 1 ) == '.' + && + *( p->d_name + 2 ) == 0 ))) { + continue; + } + + ino = (xfs_ino_t)p->d_ino; + + if ( ino == 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "encountered 0 ino (%s) in " + "directory ino %llu: NOT dumping\n", + p->d_name, + statp->bs_ino ); + continue; + } + + { + xfs_bstat_t statbuf; + intgen_t scrval; + + scrval = bigstat_one( fshandlep, + fsfd, + p->d_ino, + &statbuf ); + if ( scrval ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not stat " + "dirent %s ino %llu: %s: " + "using null generation count " + "in directory entry\n", + p->d_name, + ( xfs_ino_t )p->d_ino, + strerror( errno )); + gen = 0; + } else { + gen = statbuf.bs_gen; + } + } + + rv = dump_dirent( drivep, + contextp, + statp, + ino, + gen, + p->d_name, + namelen ); + if ( rv != RV_OK ) { + break; + } + } + } + + /* write a null dirent hdr, unless trouble encountered in the loop + */ + if ( rv == RV_OK ) { + rv = dump_dirent( drivep, contextp, statp, 0, 0, 0, 0 ); + } + +#ifdef EXTATTR + if ( rv == RV_OK + && + sc_dumpextattrpr + && + ( statp->bs_xflags & XFS_XFLAG_HASATTR )) { + rv = dump_extattrs( drivep, contextp, fshandlep, statp); + } +#endif /* EXTATTR */ + + close( fd ); + + /* if an error occurred, just return the error + */ + return rv; +} + +#ifdef EXTATTR +static rv_t +dump_extattrs( drive_t *drivep, + context_t *contextp, + jdm_fshandle_t *fshandlep, + xfs_bstat_t *statp) +{ + ix_t pass; + int flag; + attrlist_cursor_t cursor; + rv_t rv; + + /* dump a file header specially marked as heading extended attributes + */ + mlog( MLOG_NITTY, + "dumping %s ino %llu extended attributes filehdr\n", + ( statp->bs_mode & S_IFMT ) == S_IFDIR ? "dir" : "nondir", + statp->bs_ino ); + + rv = dump_filehdr( drivep, contextp, statp, 0, FILEHDR_FLAGS_EXTATTR ); + if ( rv != RV_OK ) { + return rv; + } + + /* loop twice: once for the non-root and again for the root + * attributes. + */ + for ( pass = 0, flag = 0 ; pass < 2 ; pass++, flag = ATTR_ROOT ) { + bool_t more; + + mlog( MLOG_NITTY, + "dumping %s extended attributes for %s ino %llu\n", + ( flag & ATTR_ROOT ) ? "root" : "non-root", + ( statp->bs_mode & S_IFMT ) == S_IFDIR ? "dir" : "nondir", + statp->bs_ino ); + + /* loop dumping the extended attributes from the namespace + * selected by the outer loop + */ + memset( &cursor, 0, sizeof( cursor )); + more = BOOL_FALSE; + do { + attrlist_t *listp; + bool_t abort; + int rval; + + if (! sc_brokenioctl) { + rval = jdm_attr_list(fshandlep, statp, + contextp->cc_extattrlistbufp, + ( int )contextp->cc_extattrlistbufsz, + flag, &cursor ); + + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not get list of %s " + "attributes for " + "%s ino %llu: %s (%d)\n", + ( flag & ATTR_ROOT ) + ? "root" : "non-root", + (( statp->bs_mode & S_IFMT ) + == S_IFDIR) ? "dir" : "nondir", + statp->bs_ino, + strerror( errno ), + errno ); + + /* assume kernel is missing the ioctl + * don't log any more errors + */ + if (rval == EINVAL) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "ioctl returned EINVAL: " + "disabling extended " + "attribute operations (only " + "one warning will be " + "printed)\n"); + sc_brokenioctl = BOOL_TRUE; + } + } + } + + if (sc_brokenioctl || rval) + break; + + listp = ( attrlist_t * )contextp->cc_extattrlistbufp; + more = listp->al_more; + + abort = BOOL_FALSE; + rv = dump_extattr_list( drivep, + contextp, + fshandlep, + statp, + listp, + flag, + &abort ); + if ( rv != RV_OK ) { + return rv; + } + } while ( more && ! abort ); + } + + /* finally, dump a dummy extattr hdr so restore will know + * we're done. + */ + /*DBG*/mlog( MLOG_NITTY, + "dumping NULL extattrhdr\n" ); + rv = dump_extattrhdr( drivep, + contextp, + statp, + EXTATTRHDR_SZ, + 0, + EXTATTRHDR_FLAGS_NULL, + 0 ); + return rv; +} + +static rv_t +dump_extattr_list( drive_t *drivep, + context_t *contextp, + jdm_fshandle_t *fshandlep, + xfs_bstat_t *statp, + attrlist_t *listp, + bool_t isrootpr, + bool_t *abortprp ) +{ + size_t listlen = ( size_t )listp->al_count; + ix_t nameix; + char *dumpbufp; + char *endp; + size_t bufsz; + intgen_t rval; + rv_t rv; + char *dumpbufendp = contextp->cc_extattrdumpbufp + + + contextp->cc_extattrdumpbufsz; + + /* sanity checks + */ + ASSERT( listp->al_count >= 0 ); + + /* fill up a retrieve array and build a dump buffer; + * can run out of entries in the name list, space in the + * retrieve buffer, or space in the dump buffer + */ + dumpbufp = contextp->cc_extattrdumpbufp; + endp = dumpbufp; + for ( nameix = 0 ; nameix < listlen ; ) { + ix_t rtrvix; + size_t rtrvcnt; + + rtrvix = 0; + while (nameix < listlen && rtrvix < EXTATTR_RTRVARRAY_LEN) { + attrlist_ent_t *entp; + char *valuep; + attr_multiop_t *opp; + + entp = ATTR_ENTRY( listp, nameix ); + opp = &contextp->cc_extattrrtrvarrayp[ rtrvix ]; +#ifdef DMEXTATTR + + /* Offer the HSM a chance to avoid dumping certain + * attributes. + */ + + if (hsm_fs_ctxtp) { + int skip_entry; + + if (!HsmFilterExistingAttribute( + contextp->cc_hsm_f_ctxtp, entp->a_name, + entp->a_valuelen, (isrootpr ? 1 : 0), + &skip_entry)) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "HSM could not filter %s " + "attribute %s for %s ino %llu\n", + isrootpr ? "root" : "non-root", + entp->a_name, + (statp->bs_mode & S_IFMT) == S_IFDIR ? "dir" : "nondir", + statp->bs_ino); + *abortprp = BOOL_TRUE; + return RV_OK; + } + if (skip_entry) { + nameix++; + continue; + } + } +#endif /* DMEXTATTR */ + + dumpbufp = dump_extattr_buildrecord( statp, + dumpbufp, + dumpbufendp, + entp->a_name, + entp->a_valuelen, + isrootpr, + &valuep ); + if ( dumpbufp > dumpbufendp ) { + break; /* won't fit in buffer */ + } + if (valuep != NULL) { /* if added to dump buffer */ + endp = dumpbufp; + opp->am_attrname = entp->a_name; + opp->am_attrvalue = valuep; + opp->am_length = ( int )entp->a_valuelen; + opp->am_flags = isrootpr ? ATTR_ROOT : 0; + opp->am_error = 0; + opp->am_opcode = ATTR_OP_GET; + rtrvix++; + } + nameix++; + } + + /* Either the retrieve buffer is full, the dump buffer is full, + * or we just put the last attribute into the dump buffer. In + * any case, fill in the values for any attributes added so far. + */ + + rtrvcnt = rtrvix; + if (rtrvcnt > 0) { + if (! sc_brokenioctl) { + rval = jdm_attr_multi( fshandlep, statp, + (void *)contextp->cc_extattrrtrvarrayp, + ( int )rtrvcnt, + 0 ); + + if (rval) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not retrieve %s " + "attributes for " + "%s ino %llu: %s (%d)\n", + isrootpr ? "root" : "non-root", + ( statp->bs_mode & S_IFMT ) + == S_IFDIR ? "dir" : "nondir", + statp->bs_ino, + strerror( errno ), + errno ); + + if (rval == EINVAL) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "ioctl returned EINVAL: " + "disabling extended attribute " + "operations (only one warning " + "will be printed)\n"); + sc_brokenioctl = BOOL_TRUE; + } + } + + } + + if (sc_brokenioctl || rval) { + *abortprp = BOOL_TRUE; + return RV_OK; + } + + for ( rtrvix = 0 ; rtrvix < rtrvcnt ; rtrvix++ ) { + attr_multiop_t *opp; + opp = &contextp->cc_extattrrtrvarrayp[ rtrvix ]; + if ( opp->am_error ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "attr_multi indicates error while " + "retrieving %s attribute [%s] for " + "%s ino %llu: %s (%d)\n", + isrootpr ? "root" : "non-root", + opp->am_attrname, + ( statp->bs_mode & S_IFMT ) == S_IFDIR ? "dir" : "nondir", + statp->bs_ino, + strerror( opp->am_error ), + opp->am_error ); + } + } + } + + /* The values for all attributes in the dump buffer have been + * filled in. If the dump buffer isn't full yet, let's wait + * and put some more attributes in. + */ + + if (dumpbufp <= dumpbufendp) + continue; /* no buffer overflow yet */ + + ASSERT( endp > contextp->cc_extattrdumpbufp ); + bufsz = ( size_t )( endp - contextp->cc_extattrdumpbufp ); + + rval = write_buf( contextp->cc_extattrdumpbufp, + bufsz, + ( void * )drivep, + ( gwbfp_t )drivep->d_opsp->do_get_write_buf, + ( wfp_t )drivep->d_opsp->do_write ); + switch ( rval ) { + case 0: + rv = RV_OK; + break; + case DRIVE_ERROR_MEDIA: + case DRIVE_ERROR_EOM: + rv = RV_EOM; + break; + case DRIVE_ERROR_DEVICE: + rv = RV_DRIVE; + break; + case DRIVE_ERROR_CORE: + default: + rv = RV_CORE; + break; + } + if ( rv != RV_OK ) { + *abortprp = BOOL_FALSE; + return rv; + } + dumpbufp = contextp->cc_extattrdumpbufp; + endp = dumpbufp; + } + +#ifdef DMEXTATTR + /* All existing attributes are in the dump buffer. See if the HSM + * needs to add any addtional attributes. + */ + + if (!listp->al_more && hsm_fs_ctxtp) { + int hsmcursor = 0; + for (;;) { + char *hsmnamep; + char *hsmvaluep; + char *valuep; + u_int32_t hsmvaluesz; + + if (!HsmAddNewAttribute(contextp->cc_hsm_f_ctxtp, + hsmcursor, + (isrootpr ? 1 : 0), + &hsmnamep, + &hsmvaluep, + &hsmvaluesz)) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "HSM could not add new %s attribute " + "#%d for %s ino %llu\n", + isrootpr ? "root" : "non-root", + hsmcursor, + (statp->bs_mode & S_IFMT) == S_IFDIR ? "dir" : "nondir", + statp->bs_ino); + *abortprp = BOOL_TRUE; + return RV_OK; + } + if (hsmnamep == NULL) { + break; /* No more attributes to add */ + } + + dumpbufp = dump_extattr_buildrecord( statp, + dumpbufp, + dumpbufendp, + hsmnamep, + hsmvaluesz, + isrootpr, + &valuep ); + + if ( dumpbufp < dumpbufendp ) { /* if fits in buffer */ + endp = dumpbufp; + (void)memcpy(valuep, hsmvaluep, hsmvaluesz); + hsmcursor++; + continue; + } + + ASSERT( endp > contextp->cc_extattrdumpbufp ); + bufsz = ( size_t )( endp - contextp->cc_extattrdumpbufp ); + + rval = write_buf( contextp->cc_extattrdumpbufp, + bufsz, + ( void * )drivep, + ( gwbfp_t )drivep->d_opsp->do_get_write_buf, + ( wfp_t )drivep->d_opsp->do_write ); + switch ( rval ) { + case 0: + rv = RV_OK; + break; + case DRIVE_ERROR_MEDIA: + case DRIVE_ERROR_EOM: + rv = RV_EOM; + break; + case DRIVE_ERROR_DEVICE: + rv = RV_DRIVE; + break; + case DRIVE_ERROR_CORE: + default: + rv = RV_CORE; + break; + } + if ( rv != RV_OK ) { + *abortprp = BOOL_FALSE; + return rv; + } + dumpbufp = contextp->cc_extattrdumpbufp; + endp = dumpbufp; + } + } +#endif /* DMEXTATTR */ + + + /* If any attributes remain unwritten in the dump buffer, write them + * now. + */ + + if (endp > contextp->cc_extattrdumpbufp) { + bufsz = ( size_t )( endp - contextp->cc_extattrdumpbufp ); + + rval = write_buf( contextp->cc_extattrdumpbufp, + bufsz, + ( void * )drivep, + ( gwbfp_t )drivep->d_opsp->do_get_write_buf, + ( wfp_t )drivep->d_opsp->do_write ); + switch ( rval ) { + case 0: + rv = RV_OK; + break; + case DRIVE_ERROR_MEDIA: + case DRIVE_ERROR_EOM: + rv = RV_EOM; + break; + case DRIVE_ERROR_DEVICE: + rv = RV_DRIVE; + break; + case DRIVE_ERROR_CORE: + default: + rv = RV_CORE; + break; + } + if ( rv != RV_OK ) { + *abortprp = BOOL_FALSE; + return rv; + } + } + + *abortprp = BOOL_FALSE; + return RV_OK; +} + +static char * +dump_extattr_buildrecord( xfs_bstat_t *statp, + char *dumpbufp, + char *dumpbufendp, + char *namesrcp, + u_int32_t valuesz, + bool_t isrootpr, + char **valuepp ) +{ + extattrhdr_t *ahdrp = ( extattrhdr_t * )dumpbufp; + char *namep = dumpbufp + EXTATTRHDR_SZ; + u_int32_t namelen = strlen( namesrcp ); + u_int32_t namesz = namelen + 1; + char *valuep = namep + namesz; + u_int32_t recsz = EXTATTRHDR_SZ + namesz + valuesz; + extattrhdr_t tmpah; + + recsz = ( recsz + ( EXTATTRHDR_ALIGN - 1 )) + & + ~( EXTATTRHDR_ALIGN - 1 ); + + if ( dumpbufp + recsz > dumpbufendp ) { + *valuepp = 0; + return dumpbufp + recsz; + } + + if ( namelen > NAME_MAX ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "%s extended attribute name for %s ino %llu too long: " + "%u, max is %u: skipping\n", + isrootpr ? "root" : "non-root", + ( statp->bs_mode & S_IFMT ) == S_IFDIR ? "dir" : "nondir", + statp->bs_ino, + namelen, + NAME_MAX ); + *valuepp = 0; + return dumpbufp; + } + + if ( valuesz > ATTR_MAX_VALUELEN ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "%s extended attribute value for %s ino %llu too long: " + "%u, max is %u: skipping\n", + isrootpr ? "root" : "non-root", + ( statp->bs_mode & S_IFMT ) == S_IFDIR ? "dir" : "nondir", + statp->bs_ino, + valuesz, + ATTR_MAX_VALUELEN ); + *valuepp = 0; + return dumpbufp; + } + + /*DBG*/mlog( MLOG_NITTY, + "building extattr " + "record sz %u " + "hdrsz %u " + "namesz %u (%s) " + "valsz %u\n", + recsz, + EXTATTRHDR_SZ, + namesz, namesrcp, + valuesz ); + ( void )strcpy( namep, namesrcp ); + tmpah.ah_sz = recsz; + ASSERT( EXTATTRHDR_SZ + namesz < UINT16MAX ); + tmpah.ah_valoff = ( u_int16_t )( EXTATTRHDR_SZ + namesz ); + tmpah.ah_flags = ( u_int16_t )( isrootpr ? EXTATTRHDR_FLAGS_ROOT : 0); + tmpah.ah_valsz = valuesz; + tmpah.ah_checksum = 0; +#ifdef EXTATTRHDR_CHECKSUM + { + register u_int32_t *sump = ( u_int32_t * )ahdrp; + register u_int32_t *endp = ( u_int32_t * )( ahdrp + 1 ); + register u_int32_t sum; + tmpah.ah_flags |= EXTATTRHDR_FLAGS_CHECKSUM; + for ( sum = 0 ; sump < endp ; sum += *sump++ ) ; + tmpah.ah_checksum = ~sum + 1; + } +#endif /* EXTATTRHDR_CHECKSUM */ + + xlate_extattrhdr(ahdrp, &tmpah, -1); + *valuepp = valuep; + return dumpbufp + recsz; +} + +/* ARGSUSED */ +static rv_t +dump_extattrhdr( drive_t *drivep, + context_t *contextp, + xfs_bstat_t *statp, + size_t recsz, + size_t valoff, + ix_t flags, + u_int32_t valsz ) +{ + extattrhdr_t ahdr; + extattrhdr_t tmpahdr; + intgen_t rval; + rv_t rv; + + ahdr.ah_sz = recsz; + ASSERT( valoff < UINT16MAX ); + ahdr.ah_valoff = ( u_int16_t )valoff; + ahdr.ah_flags = ( u_int16_t )flags; + ahdr.ah_valsz = valsz; + ahdr.ah_checksum = 0; + +#ifdef EXTATTRHDR_CHECKSUM + { + register u_int32_t *sump = ( u_int32_t * )&ahdr; + register u_int32_t *endp = ( u_int32_t * )( &ahdr + 1 ); + register u_int32_t sum; + ahdr.ah_flags |= EXTATTRHDR_FLAGS_CHECKSUM; + for ( sum = 0 ; sump < endp ; sum += *sump++ ) ; + ahdr.ah_checksum = ~sum + 1; + } +#endif /* EXTATTRHDR_CHECKSUM */ + + xlate_extattrhdr(&ahdr, &tmpahdr, 1); + rval = write_buf( ( char * )&tmpahdr, + EXTATTRHDR_SZ, + ( void * )drivep, + ( gwbfp_t )drivep->d_opsp->do_get_write_buf, + ( wfp_t )drivep->d_opsp->do_write ); + switch ( rval ) { + case 0: + rv = RV_OK; + break; + case DRIVE_ERROR_MEDIA: + case DRIVE_ERROR_EOM: + rv = RV_EOM; + break; + case DRIVE_ERROR_DEVICE: + rv = RV_DRIVE; + break; + case DRIVE_ERROR_CORE: + default: + rv = RV_CORE; + break; + } + + return rv; +} +#endif /* EXTATTR */ + +/* this function is called by the bigstat iterator for all non-directory + * files. it passes the buck to file type-specific dump functions. + * return value is RV_EOF if the media file is getting too big, + * RV_... if trouble encountered with the media/drive, + * 0 if file completely dumped, RV_NOMORE if we've encountered the stream + * endpt, RV_INTR if operator interrupted the dump. + */ +/* ARGSUSED */ +static rv_t +dump_file( void *arg1, + jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp ) +{ + ix_t strmix = ( ix_t )arg1; + context_t *contextp = &sc_contextp[ strmix ]; + drive_t *drivep = drivepp[ strmix ]; + drive_hdr_t *dwhdrp = drivep->d_writehdrp; + media_hdr_t *mwhdrp = ( media_hdr_t * )dwhdrp->dh_upper; + content_hdr_t *cwhdrp = ( content_hdr_t * )mwhdrp->mh_upper; + content_inode_hdr_t *scwhdrp = ( content_inode_hdr_t * ) + ( void * ) + cwhdrp->ch_specific; + startpt_t *startptp = &scwhdrp->cih_startpt; + startpt_t *endptp = &scwhdrp->cih_endpt; + intgen_t state; + rv_t rv; + + /* skip if no links + */ + if ( statp->bs_nlink < 1 ) { + if ( statp->bs_ino > contextp->cc_stat_lastino ) { + contextp->cc_stat_lastino = statp->bs_ino; + } + return RV_OK; + } + + /* skip if prior to startpoint + */ + if ( statp->bs_ino < startptp->sp_ino ) { + if ( statp->bs_ino > contextp->cc_stat_lastino ) { + contextp->cc_stat_lastino = statp->bs_ino; + } + return RV_OK; + } + + /* skip if at or beyond next startpoint. return non-zero to + * abort iteration. + */ + if ( ! ( endptp->sp_flags & STARTPT_FLAGS_END )) { + if ( endptp->sp_offset == 0 ) { + if ( statp->bs_ino >= endptp->sp_ino ) { + if ( statp->bs_ino > contextp->cc_stat_lastino ) { + contextp->cc_stat_lastino = statp->bs_ino; + } + return RV_NOMORE; + } + } else { + if ( statp->bs_ino > endptp->sp_ino ) { + if ( statp->bs_ino > contextp->cc_stat_lastino ) { + contextp->cc_stat_lastino = statp->bs_ino; + } + return RV_NOMORE; + } + } + } + + /* see what the inomap says about this ino + */ + state = inomap_state( contextp->cc_inomap_state_contextp, + statp->bs_ino ); + + /* skip if not in inomap + */ + if ( state == MAP_INO_UNUSED + || + state == MAP_DIR_NOCHNG + || + state == MAP_NDR_NOCHNG ) { + if ( state == MAP_DIR_NOCHNG ) { + mlog( MLOG_DEBUG, + "inomap inconsistency ino %llu: " + "MAP_DIR_NOCHNG but is non-dir: skipping\n", + statp->bs_ino ); + } + if ( statp->bs_ino > contextp->cc_stat_lastino ) { + contextp->cc_stat_lastino = statp->bs_ino; + } + return RV_OK; + } + + /* note if map says a dir + */ + if ( state == MAP_DIR_CHANGE || state == MAP_DIR_SUPPRT ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "inomap inconsistency ino %llu: " + "%s but is now non-dir: NOT dumping\n", + statp->bs_ino, + state == MAP_DIR_CHANGE + ? + "map says changed dir" + : + "map says unchanged dir" ); + } + +#ifdef DMEXTATTR + /* if GETOPT_DUMPASOFFLINE was specified, initialize the HSM's file + * context for use in other routines. If the context can't be + * initialized, don't dump the file. + */ + + if (hsm_fs_ctxtp) { + if (HsmInitFileContext(contextp->cc_hsm_f_ctxtp, statp)) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "inomap inconsistency ino %llu: " + "hsm detected error: NOT dumping\n", + statp->bs_ino); + if ( statp->bs_ino > contextp->cc_stat_lastino ) { + contextp->cc_stat_lastino = statp->bs_ino; + } + return RV_OK; + } + } +#endif /* DMEXTATTR */ + + /* pass on to specific dump function + */ + switch( statp->bs_mode & S_IFMT ) { + case S_IFREG: + /* ordinary file + */ + rv = dump_file_reg( drivep, + contextp, + scwhdrp, + fshandlep, + statp ); + if ( statp->bs_ino > contextp->cc_stat_lastino ) { + lock( ); + sc_stat_nondirdone++; + unlock( ); + contextp->cc_stat_lastino = statp->bs_ino; + } + break; /* drop out of switch to extattr dump */ + case S_IFCHR: + case S_IFBLK: + case S_IFIFO: +#ifdef S_IFNAM + case S_IFNAM: +#endif + case S_IFLNK: +#ifdef DOSOCKS + case S_IFSOCK: +#endif /* DOSOCKS */ + /* only need a filehdr_t; no data + */ + rv = dump_file_spec( drivep, contextp, fshandlep, statp ); + if ( statp->bs_ino > contextp->cc_stat_lastino ) { + lock( ); + sc_stat_nondirdone++; + unlock( ); + contextp->cc_stat_lastino = statp->bs_ino; + } + break; /* drop out of switch to extattr dump */ +#ifndef DOSOCKS + case S_IFSOCK: + /* don't dump these + */ + if ( statp->bs_ino > contextp->cc_stat_lastino ) { + lock( ); + sc_stat_nondirdone++; + unlock( ); + contextp->cc_stat_lastino = statp->bs_ino; + } + return RV_OK; +#endif /* ! DOSOCKS */ + case S_IFDIR: + default: + /* don't know how to dump these + */ + mlog( MLOG_VERBOSE, + "don't know how to dump ino %llu: mode %08x\n", + statp->bs_ino, + statp->bs_mode ); + if ( statp->bs_ino > contextp->cc_stat_lastino ) { + lock( ); + sc_stat_nondirdone++; + unlock( ); + contextp->cc_stat_lastino = statp->bs_ino; + } + return RV_OK; + /* not yet implemented + case S_IFMNT: + */ + } +#ifdef EXTATTR + if ( rv == RV_OK + && + sc_dumpextattrpr + && + ( statp->bs_xflags & XFS_XFLAG_HASATTR )) { + rv = dump_extattrs( drivep, contextp, fshandlep, statp); + } +#endif /* EXTATTR */ + return rv; +} + +/* a regular file may be broken into several portions if its size + * is large. Each portion begins with a filehdr_t and is followed by + * several extents. each extent begins with an extenthdr_t. returns RV_OK + * if all extents dumped, RV_... on drive errors, or RV_INTR if + * operator requested stop. + */ +static rv_t +dump_file_reg( drive_t *drivep, + context_t *contextp, + content_inode_hdr_t *scwhdrp, + jdm_fshandle_t *fshandlep, + xfs_bstat_t *statp ) +{ + startpt_t *startptp = &scwhdrp->cih_startpt; + startpt_t *endptp = &scwhdrp->cih_endpt; + extent_group_context_t extent_group_context; + bool_t cmpltflg; + off64_t offset; + off64_t stopoffset; + bool_t sosig; /* stop offset is significant */ + off64_t maxextentcnt; + rv_t rv; + + /* determine the offset within the file where the dump should begin. + * it must have been aligned to the basic fs block size by the + * startpoint calculations done during strategy initialization. + */ + if ( statp->bs_ino == startptp->sp_ino ) { + offset = startptp->sp_offset; + ASSERT( ( offset & ( off64_t )( BBSIZE - 1 )) == 0 ); + } else { + offset = 0; + } + + /* if this is a resumed dump and the resumption begins somewhere + * within this file, and that point is greater than offset set + * above, and that file hasn't changed since the resumed dump, + * modify offset. + */ + if ( sc_resumepr ) { + drange_t *drangep = sc_resumerangep; + size_t drangecnt = sc_resumerangecnt; + size_t drangeix; + + for ( drangeix = 0 ; drangeix < drangecnt ; drangeix++ ) { + drange_t *rp = &drangep[ drangeix ]; + if ( statp->bs_ino == rp->dr_begin.sp_ino ) { + register time_t mtime = statp->bs_mtime.tv_sec; + register time_t ctime = statp->bs_ctime.tv_sec; + register time_t ltime = max( mtime, ctime ); + if ( ltime < sc_resumebasetime ) { + if ( rp->dr_begin.sp_offset > offset ){ + offset =rp->dr_begin.sp_offset; + } + } + break; + } + } + ASSERT( ( offset & ( off64_t )( BBSIZE - 1 )) == 0 ); + } + + /* determine the offset within the file where the dump should end. + * only significant if this is an inode spanning a startpoint. + */ + if ( endptp->sp_flags & STARTPT_FLAGS_END ) { + sosig = BOOL_FALSE; + stopoffset = 0; + } else if ( statp->bs_ino == endptp->sp_ino ) { + sosig = BOOL_TRUE; + stopoffset = endptp->sp_offset; + } else { + sosig = BOOL_FALSE; + stopoffset = 0; + } + + mlog( MLOG_TRACE, + "dumping regular file ino %llu " + "offset %lld " + "to offset %lld " + "(size %lld)\n", + statp->bs_ino, + offset, + sosig ? stopoffset : statp->bs_size, + statp->bs_size ); + + /* calculate the maximum extent group size. files larger than this + * will be broken into multiple extent groups, each with its own + * filehdr_t. + */ + maxextentcnt = drivep->d_recmarksep; + + /* initialize the extent group context. if fails, just return, + * pretending the dump succeeded. + */ + rv = init_extent_group_context( fshandlep, + statp, + &extent_group_context ); + if ( rv != RV_OK ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not open regular file ino %llu mode 0x%08x: " + "%s: not dumped\n", + statp->bs_ino, + statp->bs_mode, + strerror( errno )); + return RV_OK; + } + + /* loop here, dumping marked groups of extents. each extent group + * is preceeded by a filehdr_t. this is required so that the + * recovery side can identify the fs file at each marked point + * in the stream. it sets by reference offset, bytecnt, and cmpltflg. + * it is important to understand that if a fs file is real big, + * it will be dumped in parts (extent groups), each beginning with + * an identical filehdr_t. + */ + cmpltflg = BOOL_FALSE; + + rv = RV_OK; + for ( ; ; ) { + off64_t bytecnt = 0; + off64_t bc; + + /* see if we are done. + */ + if ( cmpltflg ) { + ASSERT( rv == RV_OK ); + break; + } + + /* set a mark - important to do this now, before deciding + * the media file is to big or the operator asked to + * interrupt the dump. this mark, if committed, indicates + * the previous fs file / extent group was completely dumped. + */ + mark_set( drivep, statp->bs_ino, offset, 0 ); + + /* spoof EOF if the media file size is getting too big. + * note that the most we can go over is d_recmarksep. + */ + if ( contextp->cc_mfilesz >= drivep->d_recmfilesz ){ + rv = RV_EOF; + break; + } + + /* check if the operator has requested to interrupt the dump. + */ + if ( cldmgr_stop_requested( )) { + mlog( MLOG_NORMAL, + "dump interrupted prior to ino %llu offset %lld\n", + statp->bs_ino, + offset ); + rv = RV_INTR; + break; + } + + /* dump the file header + */ + mlog( MLOG_DEBUG, + "dumping extent group ino %llu offset %lld\n", + statp->bs_ino, + offset ); + rv = dump_filehdr( drivep, contextp, statp, offset, 0 ); + if ( rv != RV_OK ) { + break; + } + bytecnt += sizeof( filehdr_t ); + + /* dump a group of extents. returns by reference + * the offset of the next extent group (to be placed + * in the next mark), the total number of bytes written + * to media (headers and all), and a flag indicating + * all extents have been dumped. + */ + bc = 0; /* for lint */ + rv = dump_extent_group( drivep, + contextp, + statp, + &extent_group_context, + maxextentcnt, + stopoffset, + sosig, + &offset, + &bc, + &cmpltflg ); + ASSERT( bc >= 0 ); + bytecnt += bc; + if ( rv != RV_OK ) { + break; + } + + /* update global stat + */ + lock( ); + sc_stat_datadone += ( size64_t )bc; + unlock( ); + + /* dump LAST extent hdr. one of these is placed at the + * end of each dumped file. necessary to detect the + * end of the file. + */ + rv = dump_extenthdr( drivep, + contextp, + EXTENTHDR_TYPE_LAST, + 0, + 0, + 0 ); + if ( rv != RV_OK ) { + break; + } + bytecnt += sizeof( extenthdr_t ); + + /* update the media file size + */ + contextp->cc_mfilesz += bytecnt; + + } + + cleanup_extent_group_context( &extent_group_context ); + return rv; +} + +/* dumps character, block, and fifo - special files. no data, just meta-data, + * all contained within the filehdr_t. also handles symbolic link files: + * appends a variable-length string after the filehdr_t. + */ +static rv_t +dump_file_spec( drive_t *drivep, + context_t *contextp, + jdm_fshandle_t *fshandlep, + xfs_bstat_t *statp ) +{ + intgen_t rval; + rv_t rv; + + mlog( MLOG_TRACE, + "dumping special file ino %llu mode 0x%04x\n", + statp->bs_ino, + statp->bs_mode ); + + /* set a mark - important to do this now, before deciding + * the media file is to big. this mark, if committed, + * indicates the previous fs file was completely dumped. + */ + mark_set( drivep, statp->bs_ino, 0, 0 ); + + /* dump the file header + */ + rv = dump_filehdr( drivep, contextp, statp, 0, 0 ); + if ( rv != RV_OK ) { + return rv; + } + + /* update the media file size + */ + contextp->cc_mfilesz += sizeof( filehdr_t ); + + /* if a symbolic link, also dump the link pathname. + * use an extent header to represent the pathname. the + * extent sz will always be a multiple of SYMLINK_ALIGN. + * the symlink pathname char string will always be NULL-terminated. + */ + if ( ( statp->bs_mode & S_IFMT ) == S_IFLNK ) { + intgen_t nread; + size_t extentsz; + + /* read the link path. if error, dump a zero-length + * extent. in any case, nread will contain the number of + * bytes to dump, and contextp->cc_direntbufp will contain + * the bytes. + */ + nread = jdm_readlink( fshandlep, + statp, + contextp->cc_readlinkbufp, + contextp->cc_readlinkbufsz ); + if ( nread < 0 ) { + mlog( MLOG_DEBUG, + "could not read symlink ino %llu\n", + statp->bs_ino ); + nread = 0; + } + + /* null-terminate the string + */ + ASSERT( ( size_t )nread < contextp->cc_readlinkbufsz ); + contextp->cc_readlinkbufp[ nread ] = 0; + + /* calculate the extent size - be sure to include room + * for the null-termination. + */ + extentsz = ( ( size_t )nread + 1 + ( SYMLINK_ALIGN - 1 )) + & + ~ ( SYMLINK_ALIGN - 1 ); + ASSERT( extentsz <= contextp->cc_readlinkbufsz ); + + /* dump an extent header + */ + rv = dump_extenthdr( drivep, + contextp, + EXTENTHDR_TYPE_DATA, + 0, + 0, + ( off64_t )extentsz ); + if ( rv != RV_OK ) { + return rv; + } + + /* dump the link path extent + */ + rval = write_buf( contextp->cc_readlinkbufp, + extentsz, + ( void * )drivep, + ( gwbfp_t )drivep->d_opsp->do_get_write_buf, + ( wfp_t )drivep->d_opsp->do_write ); + switch ( rval ) { + case 0: + rv = RV_OK; + break; + case DRIVE_ERROR_MEDIA: + case DRIVE_ERROR_EOM: + rv = RV_EOM; + break; + case DRIVE_ERROR_DEVICE: + rv = RV_DRIVE; + break; + case DRIVE_ERROR_CORE: + default: + rv = RV_CORE; + break; + } + if ( rv != RV_OK ) { + return rv; + } + } + + return RV_OK; +} + +/* contrives the initial state of the extent group context such that + * dump_extent_group() will fetch some extents from the kernel before it + * does anything else. + */ +static rv_t +init_extent_group_context( jdm_fshandle_t *fshandlep, + xfs_bstat_t *statp, + extent_group_context_t *gcp ) +{ + bool_t isrealtime; + intgen_t oflags; + struct flock fl; + + isrealtime = ( bool_t )(statp->bs_xflags & XFS_XFLAG_REALTIME ); + oflags = O_RDONLY; + if ( isrealtime ) { + oflags |= O_DIRECT; + } + ( void )memset( ( void * )gcp, 0, sizeof( *gcp )); + gcp->eg_bmap[ 0 ].bmv_offset = 0; + gcp->eg_bmap[ 0 ].bmv_length = -1; + gcp->eg_bmap[ 0 ].bmv_count = BMAP_LEN; + gcp->eg_bmap[ 0 ].bmv_iflags = BMV_IF_NO_DMAPI_READ; + gcp->eg_nextbmapp = &gcp->eg_bmap[ 1 ]; + gcp->eg_endbmapp = &gcp->eg_bmap[ 1 ]; + gcp->eg_bmapix = 0; + gcp->eg_gbmcnt = 0; + gcp->eg_fd = jdm_open( fshandlep, statp, oflags ); + if ( gcp->eg_fd < 0 ) { + return RV_ERROR; + } + + /* Check if a mandatory lock is set on the file to try and + * avoid blocking indefinitely on the reads later. Note that + * someone could still set a mandatory lock and hose xfsdump + * after this check but before all reads have completed. + * This change just closes the window a bit. + */ + if ( (statp->bs_mode & S_ISGID) && ( ! (statp->bs_mode&S_IXOTH) ) ) { + fl.l_type = F_RDLCK; + fl.l_whence = SEEK_SET; + fl.l_start = (off_t)0; + fl.l_len = 0; + if ((fcntl(gcp->eg_fd, F_GETLK, &fl)) < 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "locking check failed ino %llu\n", + statp->bs_ino ); + close(gcp->eg_fd); + return RV_ERROR; + } + if (fl.l_type != F_UNLCK) { + /* Mandatory lock is set */ + close(gcp->eg_fd); + errno = EBUSY; + return RV_ERROR; + } + } + return RV_OK; +} + +static void +cleanup_extent_group_context( extent_group_context_t *gcp ) +{ + ( void )close( gcp->eg_fd ); +} + +static rv_t +dump_extent_group( drive_t *drivep, + context_t *contextp, + xfs_bstat_t *statp, + extent_group_context_t *gcp, + off64_t maxcnt, + off64_t stopoffset, + bool_t sosig, + off64_t *nextoffsetp, + off64_t *bytecntp, + bool_t *cmpltflgp ) +{ + struct dioattr da; + drive_ops_t *dop = drivep->d_opsp; + bool_t isrealtime = ( bool_t )( statp->bs_xflags + & + XFS_XFLAG_REALTIME ); + off64_t nextoffset; + off64_t bytecnt; /* accumulates total bytes sent to media */ + intgen_t rval; + rv_t rv; + + /* + * Setup realtime I/O size. + */ + if ( isrealtime ) { + if ( (ioctl(gcp->eg_fd, XFS_IOC_DIOINFO, &da) < 0) ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "dioinfo failed ino %llu\n", + statp->bs_ino ); + da.d_miniosz = PGSZ; + } + } + + /* dump extents until the recommended extent length is achieved + */ + nextoffset = *nextoffsetp; + bytecnt = 0; + ASSERT( ( nextoffset & ( BBSIZE - 1 )) == 0 ); + + for ( ; ; ) { + off64_t offset; + off64_t extsz; + + /* if we've dumped to the stop point return. + */ + if ( sosig && nextoffset >= stopoffset ) { + mlog( MLOG_NITTY, + "dumped to stop offset\n" ); + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + *cmpltflgp = BOOL_TRUE; + return RV_OK; + } + + /* if we've dumped the entire file, return + */ + if ( nextoffset >= statp->bs_size ) { + mlog( MLOG_NITTY, + "dumped to end of file\n" ); + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + *cmpltflgp = BOOL_TRUE; + return RV_OK; + } + + /* if we've exceeded the desired per-extent group byte count, + * call it quits. we'll be called back for more because the + * completion flag is set FALSE. + */ + if ( bytecnt >= maxcnt ) { + mlog( MLOG_NITTY, + "reached per-extent group byte count\n" ); + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + *cmpltflgp = BOOL_FALSE; + return RV_OK; + } + + /* if we are not looking at a valid bmap entry, + * get one. + */ + if ( gcp->eg_nextbmapp >= gcp->eg_endbmapp ) { + intgen_t entrycnt; /* entries in new bmap */ + + ASSERT( gcp->eg_nextbmapp == gcp->eg_endbmapp ); + + /* get a new extent block + */ + mlog( MLOG_NITTY, + "calling getbmapx for ino %llu\n", + statp->bs_ino ); + rval = ioctl( gcp->eg_fd, XFS_IOC_GETBMAPX, gcp->eg_bmap ); + gcp->eg_gbmcnt++; + entrycnt = gcp->eg_bmap[ 0 ].bmv_entries; + if ( entrycnt < 0 ) { /* workaround for getbmap bug */ + mlog( MLOG_DEBUG | MLOG_WARNING, + "getbmapx %d ino %lld mode 0x%08x " + "offset %lld ix %d " + "returns negative entry count\n", + gcp->eg_gbmcnt, + statp->bs_ino, + statp->bs_mode, + nextoffset, + gcp->eg_bmapix ); + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + *cmpltflgp = BOOL_TRUE; + return RV_OK; + } + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "getbmapx %d ino %lld mode 0x%08x " + "offset %lld failed: %s\n", + gcp->eg_gbmcnt, + statp->bs_ino, + statp->bs_mode, + nextoffset, + strerror( errno )); + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + *cmpltflgp = BOOL_TRUE; + return RV_OK; + } +#ifdef DMEXTATTR + + /* The F_GETBMAPX call succeeded. Give the HSM a chance + * to massage the extents. (It can change the number + * of extents remaining, even setting them to zero. + */ + + if (hsm_fs_ctxtp) { + if (!HsmModifyExtentMap(contextp->cc_hsm_f_ctxtp, + &gcp->eg_bmap[0])) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "hsm detected an extent map " + "error in ino %lld, skipping\n", + statp->bs_ino); + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + *cmpltflgp = BOOL_TRUE; + return RV_OK; + } + entrycnt = gcp->eg_bmap[ 0 ].bmv_entries; + } +#endif /* DMEXTATTR */ + if ( entrycnt <= 0 ) { + mlog( MLOG_NITTY, + "all extent groups dumped\n" ); + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + *cmpltflgp = BOOL_TRUE; + return RV_OK; + } + gcp->eg_nextbmapp = &gcp->eg_bmap[ 1 ]; + gcp->eg_endbmapp = &gcp->eg_bmap[ entrycnt + 1 ]; + mlog( MLOG_NITTY, + "getbmapx supplied %d extent entries\n", + entrycnt ); + } + + mlog( MLOG_NITTY, + "bmap entry %d ix %d block %lld offset %lld length %lld\n", + gcp->eg_nextbmapp - &gcp->eg_bmap[ 0 ], + gcp->eg_bmapix, + gcp->eg_nextbmapp->bmv_block, + gcp->eg_nextbmapp->bmv_offset, + gcp->eg_nextbmapp->bmv_length ); + + /* if the next bmap entry represents a hole, go to the next + * one in the bmap, and rescan to check above assumptions. + * bump nextoffset to after the hole, if beyond current value. + */ + if ( gcp->eg_nextbmapp->bmv_block == -1 ) { + off64_t tmpoffset; + +#ifdef EXTATTR + /* holes are not dumped if no extattrs are dumped + * because Irix 5.3 and 6.1 xfsrestores does not + * know how to handle extattrs or holes. + */ + if ( sc_dumpextattrpr ) { + /* extract the offset and extent size from this + * entry + */ + offset = gcp->eg_nextbmapp->bmv_offset + * ( off64_t )BBSIZE; + extsz = gcp->eg_nextbmapp->bmv_length + * ( off64_t )BBSIZE; + + mlog( MLOG_NITTY, + "hole extent offset = %lld size = %lld\n", + offset, extsz ); + + /* Encode the hole - dump the extent header + * with the right extent type. + */ + rv = dump_extenthdr( drivep, + contextp, + EXTENTHDR_TYPE_HOLE, + 0, + offset, + extsz ); + if ( rv != RV_OK ) { + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + *cmpltflgp = BOOL_TRUE; /*moot since + rv != OK */ + return rv; + } + bytecnt += sizeof( extenthdr_t ); + } +#endif /* EXTATTR */ + + tmpoffset = ( gcp->eg_nextbmapp->bmv_offset + + + gcp->eg_nextbmapp->bmv_length ) + * + ( off64_t )BBSIZE; + if ( tmpoffset > nextoffset ) { + nextoffset = tmpoffset; + } + gcp->eg_nextbmapp++; + gcp->eg_bmapix++; + continue; + } + + /* if the next bmap entry has a zero size, go to the next + * one in the bmap, and rescan to check above assumptions. + */ + if ( gcp->eg_nextbmapp->bmv_length <= 0 ) { + off64_t tmpoffset; + + mlog( MLOG_NITTY, + "non-positive extent\n" ); + tmpoffset = gcp->eg_nextbmapp->bmv_offset + * + ( off64_t )BBSIZE; + if ( tmpoffset > nextoffset ) { + nextoffset = tmpoffset; + } + gcp->eg_nextbmapp++; + gcp->eg_bmapix++; + continue; + } + + /* extract the offset and extent size from this + * entry + */ + offset = gcp->eg_nextbmapp->bmv_offset * ( off64_t )BBSIZE; + extsz = gcp->eg_nextbmapp->bmv_length * ( off64_t )BBSIZE; + mlog( MLOG_NITTY, + "extent offset %lld sz %lld; nextoffset %lld\n", + offset, + extsz, + nextoffset ); + + /* if the new bmap entry begins below the stop offset + * but does not contain any data above the current + * offset, go to the next one and rescan. + */ + if ( ! sosig || offset < stopoffset ) { + if ( offset + extsz <= nextoffset ) { + mlog( MLOG_NITTY, + "extent ends before nextoffset\n" ); + gcp->eg_nextbmapp++; + gcp->eg_bmapix++; + continue; + } + } + + /* if the new bmap entry begins beyond the end of the file, + * we are done. + */ + if ( offset >= statp->bs_size ) { + mlog( MLOG_NITTY, + "extent beyond end of file\n" ); + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + *cmpltflgp = BOOL_TRUE; + return RV_OK; + } + + /* if the new bmap entry begins at or above the stop offset, + * stop. we are done. + */ + if ( sosig && offset >= stopoffset ) { + mlog( MLOG_NITTY, + "extent beyond stop offset\n" ); + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + *cmpltflgp = BOOL_TRUE; + return RV_OK; + } + + /* if the new entry begins below the range of + * interest, modify offset to begin at the + * beginning of the range of interest, and shorten + * extsz accordingly. + */ + if ( offset < nextoffset ) { + extsz -= nextoffset - offset; + offset = nextoffset; + mlog( MLOG_NITTY, + "adjusted bottom of extent to nextoffset: " + "offset %lld, sz %lld; nextoffset %lld\n", + offset, + extsz, + nextoffset ); + } + ASSERT( extsz > 0 ); + + /* if the resultant extent would put us over maxcnt, + * shorten it, and round up to the next BBSIZE (round + * upto d_miniosz for realtime). + */ + if ( extsz > maxcnt - ( bytecnt + sizeof( extenthdr_t ))) { + int iosz; + + if (isrealtime) + iosz = da.d_miniosz; + else + iosz = BBSIZE; + extsz = maxcnt - ( bytecnt + sizeof( extenthdr_t )); + extsz = ( extsz + ( off64_t )( iosz - 1 )) + & + ~( off64_t )( iosz - 1 ); + mlog( MLOG_NITTY, + "adjusted top of extent to honor maxcnt " + "(rounded up %d): " + "offset %lld, sz %lld; maxcnt %lld\n", + iosz, + offset, + extsz, + maxcnt ); + } + + /* if the shortened extent is too small, return; we'll + * pick it up next time around. exception: if the file + * size is zero, indicate we are done. + * !!! I don't believe this rule can ever fire! + */ + if ( extsz <= 0 ) { + mlog( MLOG_NITTY, + "adjusted extent size is non-positive: " + "%lld (bs_size %lld)\n", + extsz, + statp->bs_size ); + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + if ( statp->bs_size == 0 ) { + *cmpltflgp = BOOL_TRUE; + } else { + *cmpltflgp = BOOL_FALSE; + } + return RV_OK; + } + + /* if the resultant extent extends beyond the end of the + * file, shorten the extent to the nearest BBSIZE alignment + * at or beyond EOF. (Shorten to d_miniosz for realtime + * files). + */ + if ( extsz > statp->bs_size - offset ) { + int iosz; + + if (isrealtime) + iosz = da.d_miniosz; + else + iosz = BBSIZE; + extsz = statp->bs_size - offset; + extsz = ( extsz + ( off64_t )( iosz - 1 )) + & + ~( off64_t )( iosz - 1 ); + mlog( MLOG_NITTY, + "adjusted top of extent to match file size " + "(rounded up %d): " + "offset %lld, sz %lld; bs_size %lld\n", + iosz, + offset, + extsz, + statp->bs_size ); + } + + /* if the extent extends beyond the stop offset, + * shorten it to the stop offset. + */ + if ( sosig && ( extsz > stopoffset - offset )) { + extsz = stopoffset - offset; + ASSERT( extsz >= 0 ); + ASSERT( ! ( extsz & ( off64_t )( BBSIZE - 1 ))); + mlog( MLOG_NITTY, + "adjusted top of extent " + "to adhere to stop offset: " + "offset %lld, sz %lld; bs_size %lld\n", + offset, + extsz, + statp->bs_size ); + } + + /* I/O performance is better if we align the media write + * buffer to a page boundary. do this if the extent is + * at least a page in length. Also, necessary for real time + * files + */ + if ( isrealtime || extsz >= PGALIGNTHRESH * PGSZ ) { + size_t cnt_to_align; + cnt_to_align = ( * dop->do_get_align_cnt )( drivep ); + if ( ( size_t )cnt_to_align < 2*sizeof( extenthdr_t )) { + cnt_to_align += PGSZ; + } + + /* account for the DATA header following the alignment + */ + cnt_to_align -= sizeof( extenthdr_t ); + + rv = dump_extenthdr( drivep, + contextp, + EXTENTHDR_TYPE_ALIGN, + 0, + 0, + ( off64_t ) + ( ( size_t )cnt_to_align + - + sizeof(extenthdr_t))); + if ( rv != RV_OK ) { + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + *cmpltflgp = BOOL_TRUE; + return rv; + } + bytecnt += sizeof( extenthdr_t ); + cnt_to_align -= sizeof( extenthdr_t ); + rv = write_pad( drivep, cnt_to_align ); + if ( rv != RV_OK ) { + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + *cmpltflgp = BOOL_TRUE; /* moot: rv != OK */ + return rv; + } + bytecnt += ( off64_t )cnt_to_align; + } + /* adjust the next offset + */ + ASSERT( ( offset & ( off64_t )( BBSIZE - 1 )) == 0 ); + ASSERT( ( extsz & ( off64_t )( BBSIZE - 1 )) == 0 ); + nextoffset = offset + extsz; + + /* dump the extent header + */ + rv = dump_extenthdr( drivep, + contextp, + EXTENTHDR_TYPE_DATA, + 0, + offset, + extsz ); + if ( rv != RV_OK ) { + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + *cmpltflgp = BOOL_TRUE; /* moot since rv != OK */ + return rv; + } + bytecnt += sizeof( extenthdr_t ); + + /* dump the extent. if read fails to return all + * asked for, pad out the extent with zeros. necessary + * because the extent hdr is already out there! + */ + while ( extsz ) { + off64_t new_off; + intgen_t nread; + size_t reqsz; + size_t actualsz; + char *bufp; + + reqsz = extsz > ( off64_t )INTGENMAX + ? + INTGENMAX + : + ( size_t )extsz; + bufp = ( * dop->do_get_write_buf )( drivep, + reqsz, + &actualsz ); + ASSERT( actualsz <= reqsz ); + new_off = lseek64( gcp->eg_fd, offset, SEEK_SET ); + if ( new_off == ( off64_t )( -1 )) { + mlog( MLOG_NORMAL, + "can't lseek ino %llu\n", + statp->bs_ino ); + nread = 0; + } else { + nread = read( gcp->eg_fd, bufp, actualsz); + } + if ( nread < 0 ) { +#ifdef HIDDEN + struct statvfs64 s; + + /* Be quiet if this is a swap file - #510197 */ + if ( (fstatvfs64(gcp->eg_fd, &s) < 0 ) || + ((s.f_flag & ST_LOCAL) != 0) ) + mlog( MLOG_NORMAL, + "can't read ino %llu at offset %d (act=%d req=%d) rt=%d\n", + statp->bs_ino, new_off, actualsz , reqsz, isrealtime ); +#endif /* HIDDEN */ + + nread = 0; + } + ASSERT( ( size_t )nread <= actualsz ); + mlog( MLOG_NITTY, + "read ino %llu offset %lld sz %d actual %d\n", + statp->bs_ino, + offset, + actualsz, + nread ); + + /* must return entire buffer supplied by call to + * do_get_write_buf; so pad end with zeros. below + * we assume the short read implies EOF, so will + * then pad out remainder of extent as well. + */ + if ( ( size_t )nread < actualsz ) { + memset( ( void * )( bufp + nread ), + 0, + actualsz - ( size_t )nread ); + } + + rval = ( * dop->do_write )( drivep, + bufp, + actualsz ); + switch ( rval ) { + case 0: + rv = RV_OK; + break; + case DRIVE_ERROR_MEDIA: + case DRIVE_ERROR_EOM: + rv = RV_EOM; + break; + case DRIVE_ERROR_DEVICE: + rv = RV_DRIVE; + break; + case DRIVE_ERROR_CORE: + default: + rv = RV_CORE; + break; + } + if ( rv != RV_OK ) { + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + *cmpltflgp = BOOL_TRUE; /* moot: rv != OK */ + return rv; + } + bytecnt += ( off64_t )actualsz; + extsz -= ( off64_t )actualsz; + offset += ( off64_t )actualsz; + + /* if we got a short read, assume we are at the + * end of the file; pad out the remainder of the + * extent to match the header. + */ + if ( ( size_t )nread < actualsz ) { + mlog( MLOG_NITTY, + "padding remaind %lld bytes of extent\n", + extsz ); + while ( extsz ) { + reqsz = extsz > ( off64_t )INTGENMAX + ? + INTGENMAX + : + ( size_t )extsz; + rv = write_pad( drivep, + ( size_t )reqsz ); + if ( rv != RV_OK ) { + *nextoffsetp = nextoffset; + *bytecntp = bytecnt; + *cmpltflgp = BOOL_TRUE; + return rv; + } + bytecnt += ( off64_t )reqsz; + extsz -= ( off64_t )reqsz; + offset += ( off64_t )reqsz; + } + } + } + + /* made it! advance to the next extent if the current + * extent is completely dumped. + * !!! not be necessary, taken care of near the + * !!! top of the loop. + */ + if ( nextoffset + >= + gcp->eg_nextbmapp->bmv_offset * ( off64_t )BBSIZE + + + gcp->eg_nextbmapp->bmv_length * ( off64_t )BBSIZE ) { + mlog( MLOG_NITTY, + "advancing to next extent in bmap\n" ); + gcp->eg_nextbmapp++; + gcp->eg_bmapix++; + } + } + /* NOTREACHED */ +} + +static void +copy_xfs_bstat(bstat_t *dst, xfs_bstat_t *src) +{ + dst->bs_ino = src->bs_ino; + dst->bs_mode = src->bs_mode; + dst->bs_nlink = src->bs_nlink; + dst->bs_uid = src->bs_uid; + dst->bs_gid = src->bs_gid; + dst->bs_rdev = src->bs_rdev; + dst->bs_blksize = src->bs_blksize; + dst->bs_size = src->bs_size; + dst->bs_atime.tv_sec = src->bs_atime.tv_sec; + dst->bs_atime.tv_nsec = src->bs_atime.tv_nsec; + dst->bs_mtime.tv_sec = src->bs_mtime.tv_sec; + dst->bs_mtime.tv_nsec = src->bs_mtime.tv_nsec; + dst->bs_ctime.tv_sec = src->bs_ctime.tv_sec; + dst->bs_ctime.tv_nsec = src->bs_ctime.tv_nsec; + dst->bs_blocks = src->bs_blocks; + dst->bs_xflags = src->bs_xflags; + dst->bs_extsize = src->bs_extsize; + dst->bs_extents = src->bs_extents; + dst->bs_gen = src->bs_gen; + uuid_clear(dst->bs_uuid); /* dunno */ + dst->bs_dmevmask = src->bs_dmevmask; + dst->bs_dmstate = (u_int16_t) 0; /* dunno */ +} + +static rv_t +dump_filehdr( drive_t *drivep, + context_t *contextp, + xfs_bstat_t *statp, + off64_t offset, + intgen_t flags ) +{ + drive_ops_t *dop = drivep->d_opsp; + register filehdr_t *fhdrp = contextp->cc_filehdrp; + filehdr_t tmpfhdrp; +#ifdef FILEHDR_CHECKSUM + register u_int32_t *sump = ( u_int32_t * )fhdrp; + register u_int32_t *endp = ( u_int32_t * )( fhdrp + 1 ); + register u_int32_t sum; +#endif /* FILEHDR_CHECKSUM */ + intgen_t rval; + rv_t rv; + + ( void )memset( ( void * )fhdrp, 0, sizeof( *fhdrp )); + if ( statp ) { + copy_xfs_bstat(&fhdrp->fh_stat, statp); +#ifdef DMEXTATTR + if (hsm_fs_ctxtp) { + HsmModifyInode(contextp->cc_hsm_f_ctxtp, + (xfs_bstat_t *)&fhdrp->fh_stat); + } +#endif /* DMEXTATTR */ + } + fhdrp->fh_offset = offset; + fhdrp->fh_flags = flags; + +#ifdef FILEHDR_CHECKSUM + fhdrp->fh_flags |= FILEHDR_FLAGS_CHECKSUM; + for ( sum = 0 ; sump < endp ; sum += *sump++ ) ; + fhdrp->fh_checksum = ~sum + 1; +#endif /* FILEHDR_CHECKSUM */ + + xlate_filehdr(fhdrp, &tmpfhdrp, 1); + rval = write_buf( ( char * )&tmpfhdrp, + sizeof( tmpfhdrp ), + ( void * )drivep, + ( gwbfp_t )dop->do_get_write_buf, + ( wfp_t )dop->do_write ); + + switch ( rval ) { + case 0: + rv = RV_OK; + break; + case DRIVE_ERROR_MEDIA: + case DRIVE_ERROR_EOM: + rv = RV_EOM; + break; + case DRIVE_ERROR_DEVICE: + rv = RV_DRIVE; + break; + case DRIVE_ERROR_CORE: + default: + rv = RV_CORE; + break; + } + + return rv; +} + +static rv_t +dump_extenthdr( drive_t *drivep, + context_t *contextp, + int32_t type, + int32_t flags, + off64_t offset, + off64_t sz ) +{ + drive_ops_t *dop = drivep->d_opsp; + register extenthdr_t *ehdrp = contextp->cc_extenthdrp; + extenthdr_t tmpehdrp; +#ifdef EXTENTHDR_CHECKSUM + register u_int32_t *sump = ( u_int32_t * )ehdrp; + register u_int32_t *endp = ( u_int32_t * )( ehdrp + 1 ); + register u_int32_t sum; +#endif /* EXTENTHDR_CHECKSUM */ + intgen_t rval; + rv_t rv; + char typestr[20]; + + switch( type ) { + case EXTENTHDR_TYPE_LAST: + strcpy( typestr, "LAST" ); + break; + case EXTENTHDR_TYPE_ALIGN: + strcpy( typestr, "ALIGN" ); + break; + case EXTENTHDR_TYPE_DATA: + strcpy( typestr, "DATA" ); + break; + case EXTENTHDR_TYPE_HOLE: + strcpy( typestr, "HOLE" ); + break; + default: + strcpy( typestr, "UNKNOWN" ); + } + + mlog( MLOG_DEBUG, + "dumping extent type = %s offset = %lld size = %lld\n", + typestr, + offset, + sz ); + + ( void )memset( ( void * )ehdrp, 0, sizeof( *ehdrp )); + ehdrp->eh_type = type; + ehdrp->eh_flags = flags; + ehdrp->eh_offset = offset; + ehdrp->eh_sz = sz; + +#ifdef EXTENTHDR_CHECKSUM + ehdrp->eh_flags |= EXTENTHDR_FLAGS_CHECKSUM; + for ( sum = 0 ; sump < endp ; sum += *sump++ ) ; + ehdrp->eh_checksum = ~sum + 1; +#endif /* EXTENTHDR_CHECKSUM */ + + xlate_extenthdr(ehdrp, &tmpehdrp, 1); + rval = write_buf( ( char * )&tmpehdrp, + sizeof( tmpehdrp ), + ( void * )drivep, + ( gwbfp_t )dop->do_get_write_buf, + ( wfp_t )dop->do_write ); + + switch ( rval ) { + case 0: + rv = RV_OK; + break; + case DRIVE_ERROR_MEDIA: + case DRIVE_ERROR_EOM: + rv = RV_EOM; + break; + case DRIVE_ERROR_DEVICE: + rv = RV_DRIVE; + break; + case DRIVE_ERROR_CORE: + default: + rv = RV_CORE; + break; + } + + return rv; +} + +static rv_t +dump_dirent( drive_t *drivep, + context_t *contextp, + xfs_bstat_t *statp, + xfs_ino_t ino, + u_int32_t gen, + char *name, + size_t namelen ) +{ + drive_ops_t *dop = drivep->d_opsp; + direnthdr_t *dhdrp = ( direnthdr_t * )contextp->cc_mdirentbufp; + direnthdr_t *tmpdhdrp; + size_t direntbufsz = contextp->cc_mdirentbufsz; + size_t sz; +#ifdef DIRENTHDR_CHECKSUM + register u_int32_t *sump = ( u_int32_t * )dhdrp; + register u_int32_t *endp = ( u_int32_t * )( dhdrp + 1 ); + register u_int32_t sum; +#endif /* DIRENTHDR_CHECKSUM */ + intgen_t rval; + rv_t rv; + + sz = offsetofmember( direnthdr_t, dh_name ) + + + namelen + + + 1; + sz = ( sz + DIRENTHDR_ALIGN - 1 ) + & + ~( DIRENTHDR_ALIGN - 1 ); + + if ( sz > direntbufsz ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "unable to dump " + "directory %llu entry %s (%llu): " + "name too long\n", + statp->bs_ino, + name, + ino ); + return RV_OK; + } + + ASSERT( sz <= UINT16MAX ); + ASSERT( sz >= DIRENTHDR_SZ ); + + memset( ( void * )dhdrp, 0, sz ); + dhdrp->dh_ino = ino; + dhdrp->dh_sz = ( u_int16_t )sz; + dhdrp->dh_gen = ( u_int16_t )( gen & DENTGENMASK ); + + if ( name ) { + strcpy( dhdrp->dh_name, name ); + } + +#ifdef DIRENTHDR_CHECKSUM + for ( sum = 0 ; sump < endp ; sum += *sump++ ) ; + dhdrp->dh_checksum = ~sum + 1; +#endif /* DIRENTHDR_CHECKSUM */ + + tmpdhdrp = malloc(sz); + xlate_direnthdr(dhdrp, tmpdhdrp, 1); + if ( name ) { + strcpy( tmpdhdrp->dh_name, name ); + } + rval = write_buf( ( char * )tmpdhdrp, + sz, + ( void * )drivep, + ( gwbfp_t )dop->do_get_write_buf, + ( wfp_t )dop->do_write ); + free(tmpdhdrp); + switch ( rval ) { + case 0: + rv = RV_OK; + break; + case DRIVE_ERROR_MEDIA: + case DRIVE_ERROR_EOM: + rv = RV_EOM; + break; + case DRIVE_ERROR_DEVICE: + rv = RV_DRIVE; + break; + case DRIVE_ERROR_CORE: + default: + rv = RV_CORE; + break; + } + + return rv; +} + +static bool_t +dump_session_inv( drive_t *drivep, + context_t *contextp, + media_hdr_t *mwhdrp, + content_inode_hdr_t *scwhdrp ) +{ + drive_ops_t *dop = drivep->d_opsp; + ix_t strmix = drivep->d_index; + inv_stmtoken_t inv_stmt; + char *inv_sbufp; + size_t inv_sbufsz; + off64_t ncommitted; + bool_t ok; + bool_t done; + + /* if the inventory session token is null, skip + */ + if ( sc_inv_sestoken == INV_TOKEN_NULL ) { + return BOOL_TRUE; + } + + mlog( MLOG_VERBOSE, + "dumping session inventory\n" ); + + /* get a buffer from the inventory manager + */ + inv_sbufp = 0; + inv_sbufsz = 0; + ok = inv_get_sessioninfo( sc_inv_sestoken, ( void * )&inv_sbufp, &inv_sbufsz ); + if ( ! ok ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "unable to get session inventory to dump\n" ); + return BOOL_TRUE; + } + ASSERT( inv_sbufp ); + + /* modify the write header to indicate the media file type. + */ + scwhdrp->cih_mediafiletype = CIH_MEDIAFILETYPE_INVENTORY; + + /* loop attempting to write a complete media file, + * until we are successful or until the media layer + * tells us to give up. + */ + for ( done = BOOL_FALSE ; ! done ; ) { + uuid_t mediaid; + char medialabel[ GLOBAL_HDR_STRING_SZ ]; + bool_t partial; + intgen_t mediafileix; + intgen_t rval; + rv_t rv; + + mlog( MLOG_VERBOSE, + "beginning inventory media file\n" ); + + partial = BOOL_FALSE; + rv = Media_mfile_begin( drivep, contextp, BOOL_FALSE ); + switch( rv ) { + case RV_OK: + break; + case RV_TIMEOUT: + mlog( MLOG_VERBOSE | MLOG_WARNING, + "media change timeout: " + "session inventory not dumped\n" ); + return BOOL_FALSE; + case RV_QUIT: + mlog( MLOG_VERBOSE | MLOG_WARNING, + "media change declined: " + "session inventory not dumped\n" ); + return BOOL_FALSE; + case RV_DRIVE: + case RV_ERROR: + case RV_CORE: + default: + return BOOL_FALSE; + } + + mlog( MLOG_VERBOSE, + "media file %u (media %u, file %u)\n", + mwhdrp->mh_dumpfileix, + mwhdrp->mh_mediaix, + mwhdrp->mh_mediafileix ); + + uuid_copy(mediaid, mwhdrp->mh_mediaid); + strcpy( medialabel, mwhdrp->mh_medialabel ); + mediafileix = ( intgen_t )mwhdrp->mh_mediafileix; + + rval = write_buf( inv_sbufp, + inv_sbufsz, + ( void * )drivep, + ( gwbfp_t )dop->do_get_write_buf, + ( wfp_t )dop->do_write ); + switch ( rval ) { + case 0: + break; + case DRIVE_ERROR_MEDIA: + case DRIVE_ERROR_EOM: + partial = BOOL_TRUE; + break; + case DRIVE_ERROR_DEVICE: + case DRIVE_ERROR_CORE: + default: + return BOOL_FALSE; + } + + mlog( MLOG_VERBOSE, + "ending inventory media file\n" ); + ncommitted = 0; + rv = Media_mfile_end( drivep, + contextp, + mwhdrp, + &ncommitted, + partial ); + switch( rv ) { + case RV_OK: + break; + case RV_EOM: + partial = BOOL_TRUE; + break; + default: + return BOOL_FALSE; + } + + if ( partial ) { + mlog( MLOG_VERBOSE, + "encountered EOM while writing " + "inventory media file size %lld bytes\n", + ncommitted ); + } else { + mlog( MLOG_VERBOSE, + "inventory media file size %lld bytes\n", + ncommitted ); + } + if ( sc_inv_stmtokenp ) { + inv_stmt = sc_inv_stmtokenp[ strmix ]; + } else { + inv_stmt = INV_TOKEN_NULL; + } + + if ( inv_stmt != INV_TOKEN_NULL ) { + mlog( MLOG_DEBUG, + "giving inventory " + "session dump media file\n" ); + ok = inv_put_mediafile( inv_stmt, + &mediaid, + medialabel, + ( u_intgen_t )mediafileix, + (xfs_ino_t )0, + ( off64_t )0, + (xfs_ino_t )0, + ( off64_t )0, + ncommitted, + ! partial, + BOOL_TRUE ); + if ( ! ok ) { + mlog( MLOG_NORMAL, + "inventory session media file " + "put failed\n" ); + return BOOL_FALSE; + } + } + + done = ! partial; + } + + return BOOL_TRUE; +} + +static void +dump_terminator( drive_t *drivep, context_t *contextp, media_hdr_t *mwhdrp ) +{ + off64_t ncommitted; + bool_t done; + + /* if the drive doesn't support use of stream terminators, don't bother + */ + if ( ! contextp->cc_Media_useterminatorpr ) { + return; + } + + mlog( MLOG_VERBOSE, + "writing stream terminator\n" ); + + /* modify the write header to indicate a terminator + */ + MEDIA_TERMINATOR_SET( mwhdrp ); + + /* loop attempting to write a complete media file header + * until we are successful or until the media layer + * tells us to give up. + */ + for ( done = BOOL_FALSE ; ! done ; ) { + bool_t partial; + rv_t rv; + + mlog( MLOG_VERBOSE, + "beginning media stream terminator\n" ); + + partial = BOOL_FALSE; + rv = Media_mfile_begin( drivep, contextp, BOOL_FALSE ); + switch( rv ) { + case RV_OK: + break; + case RV_TIMEOUT: + mlog( MLOG_VERBOSE | MLOG_WARNING, + "media change timeout: " + "media stream terminator not written\n" ); + return; + case RV_QUIT: + mlog( MLOG_VERBOSE | MLOG_WARNING, + "media change declined: " + "media stream terminator not written\n" ); + return; + case RV_DRIVE: + case RV_ERROR: + case RV_CORE: + default: + return; + } + + mlog( MLOG_VERBOSE, + "media file %u (media %u, file %u)\n", + mwhdrp->mh_dumpfileix, + mwhdrp->mh_mediaix, + mwhdrp->mh_mediafileix ); + + mlog( MLOG_VERBOSE, + "ending media stream terminator\n" ); + ncommitted = 0; + rv = Media_mfile_end( drivep, + contextp, + mwhdrp, + &ncommitted, + BOOL_FALSE ); + switch( rv ) { + case RV_OK: + break; + case RV_EOM: + partial = BOOL_TRUE; + break; + default: + return; + } + + if ( partial ) { + mlog( MLOG_VERBOSE, + "encountered EOM while writing " + "media stream terminator size %lld bytes\n", + ncommitted ); + } else { + mlog( MLOG_VERBOSE, + "media stream terminator size %lld bytes\n", + ncommitted ); + } + + done = ! partial; + } +} + +static rv_t +write_pad( drive_t *drivep, size_t sz ) +{ + drive_ops_t *dop = drivep->d_opsp; + intgen_t rval; + rv_t rv; + + rval = write_buf( 0, + sz, + ( void * )drivep, + ( gwbfp_t )dop->do_get_write_buf, + ( wfp_t )dop->do_write ); + + switch ( rval ) { + case 0: + rv = RV_OK; + break; + case DRIVE_ERROR_MEDIA: + case DRIVE_ERROR_EOM: + rv = RV_EOM; + break; + case DRIVE_ERROR_DEVICE: + rv = RV_DRIVE; + break; + case DRIVE_ERROR_CORE: + default: + rv = RV_CORE; + break; + } + + return rv; +} + +static void +inv_cleanup( void ) +{ + /* REFERENCED */ + bool_t ok; + + if ( sc_inv_stmtokenp && sc_contextp ) { + size_t strmix; + inv_stmtoken_t *inv_stmtp; + context_t *contextp; + for ( strmix = 0, + inv_stmtp = sc_inv_stmtokenp, + contextp = sc_contextp + ; + strmix < drivecnt + ; + strmix++, + inv_stmtp++, + contextp++ ) { + bool_t interrupted; + interrupted = ! contextp->cc_completepr; + if ( *inv_stmtp == INV_TOKEN_NULL ) { + continue; + } + mlog( MLOG_DEBUG, + "closing inventory stream %d%s\n", + strmix, + interrupted ? ": interrupted" : "" ); + ok = inv_stream_close( *inv_stmtp, interrupted ); + ASSERT( ok ); + } + } + + if ( sc_inv_sestoken != INV_TOKEN_NULL ) { + ok = inv_writesession_close( sc_inv_sestoken ); + ASSERT( ok ); + } + + if ( sc_inv_idbtoken != INV_TOKEN_NULL ) { + ok = inv_close( sc_inv_idbtoken ); + ASSERT( ok ); + } +} + +/* This function returns with the proper media positioned at the proper place + * in the specified drive, with a write header layed down. The caller can + * immediately dump. The caller is expected to call Media_mfile_end when + * the media file is complete or EOM is encountered. + * + * Media_mfile_begin is partitioned into 4 coroutines, between which it + * readily jumps back and forth using gotos. So be careful about the scope + * of automatic variables. + */ +static rv_t +Media_mfile_begin( drive_t *drivep, context_t *contextp, bool_t intr_allowed ) +{ + drive_ops_t *dop = drivep->d_opsp; + intgen_t dcaps = drivep->d_capabilities; + global_hdr_t *gwhdrp = drivep->d_gwritehdrp; + drive_hdr_t *dwhdrp = drivep->d_writehdrp; + media_hdr_t *mwhdrp = ( media_hdr_t * )dwhdrp->dh_upper; + drive_hdr_t *drhdrp = drivep->d_readhdrp; + media_hdr_t *mrhdrp = ( media_hdr_t * )drhdrp->dh_upper; + char *cmdlinemedialabel; + bool_t virginmediapr; + bool_t mediapresentpr; + bool_t prevmediapresentpr; + bool_t mediawrittentopr; + global_hdr_t saved_gwhdr; + intgen_t rval; + bool_t ok; + + /* sanity checks + */ + ASSERT( BES_INIT == 0 ); + + mlog( MLOG_DEBUG | MLOG_MEDIA, + "Media op: begin media file\n" ); + + /* the command line-specified media label is good only for the + * first media object written to. after that, the operator will + * be prompted for a label. To enforce this, cc_Media_firstlabel + * is saved in a temp var and NULLed. + */ + cmdlinemedialabel = contextp->cc_Media_firstlabel; + contextp->cc_Media_firstlabel = 0; + + /* dispatch based on entry state. invalidate entry state to assert + * each Media_mfile_begin is followed by and Media_mfile_end. + */ + prevmediapresentpr = BOOL_UNKNOWN; + { + bes_t entrystate; + entrystate = contextp->cc_Media_begin_entrystate; + contextp->cc_Media_begin_entrystate = BES_INVAL; + switch ( entrystate ) { + case BES_INIT: + mediawrittentopr = BOOL_FALSE; + mwhdrp->mh_mediaix = ( u_int32_t )( -1 ); + mwhdrp->mh_dumpfileix = ( u_int32_t )( -1 ); + if ( dcaps & DRIVE_CAP_READ ) { + mediapresentpr = BOOL_UNKNOWN; + virginmediapr = BOOL_UNKNOWN; + goto position; + } else { + mediapresentpr = BOOL_TRUE; + virginmediapr = BOOL_TRUE; + goto write; + } + case BES_ENDOK: + mediapresentpr = BOOL_TRUE; + virginmediapr = BOOL_FALSE; + mediawrittentopr = BOOL_TRUE; + goto write; + case BES_ENDEOM: + mediapresentpr = BOOL_TRUE; + virginmediapr = BOOL_FALSE; + mediawrittentopr = BOOL_TRUE; + goto changemedia; + default: + ASSERT( 0 ); + return RV_CORE; + } + } + +position: + /* loop until we are positioned either at end of recorded data + * or at a terminator, as appropriate, of some media object, or hit EOM. + * goto write or changemedia to get out of loop (or return on + * catastrophic condition). ensure that all but the first media file + * of a stream begins on virgin media. that is, dump streams may + * be concatenated but not jumbled. a dump stream must be virtually + * contiguous. + */ + for ( ; ; ) { + /* check if a stop has been requested + */ + if ( intr_allowed && cldmgr_stop_requested( )) { + return RV_INTR; + } + + /* do a begin_read to see the disposition of the drive/media. + */ + rval = ( * dop->do_begin_read )( drivep ); + + /* update cc_Media_useterminatorpr after every begin_read, + * since begin_read will cause some unknown drive params + * to be resolved. + */ + update_cc_Media_useterminatorpr( drivep, contextp ); + + switch( rval ) { + case 0: + mlog_lock( ); + mlog( MLOG_VERBOSE | MLOG_NOLOCK | MLOG_MEDIA, + "positioned at media file %u: " + "dump %u, " + "stream %u\n", + mrhdrp->mh_mediafileix, + mrhdrp->mh_dumpmediaix, + drhdrp->dh_driveix ); + mlog( MLOG_TRACE | MLOG_NOLOCK | MLOG_MEDIA, + "stream media file %u (%u in object), " + "stream media object %d\n", + mrhdrp->mh_dumpfileix, + mrhdrp->mh_dumpmediafileix, + mrhdrp->mh_mediaix ); + mlog_unlock( ); + + /* successfully read media file header. + * we know media must be present in drive, and + * contains at least one valid xfsdump, hence + * is not virgin. + */ + prevmediapresentpr = mediapresentpr; + mediapresentpr = BOOL_TRUE; + virginmediapr = BOOL_FALSE; + + /* do an end_read. the next begin_read will + * position in preparation for appending. + * if terminator, back up, we'll overwrite it. + * also be sure we can append dumps. + * if we back over a terminator which is the + * first media file on the media object, make the + * media object a virgin. + * also, check for erase option. + */ + ( * dop->do_end_read )( drivep ); + + switch( Media_erasechk( drivep, + dcaps, + intr_allowed, + prevmediapresentpr )) { + case RV_OK: + goto erasemedia; + case RV_INTR: + return RV_INTR; + default: + break; + } + + if ( ( int32_t )mwhdrp->mh_mediaix >= 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_MEDIA, + "cannot interleave dump streams: " + "must supply a blank media object\n" ); + goto changemedia; + } + if ( ! ( dcaps & DRIVE_CAP_APPEND )) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_MEDIA, + "media contains valid xfsdump " + "but does not support append\n" ); + goto changemedia; + } + if ( MEDIA_TERMINATOR_CHK( mrhdrp )) { + intgen_t status; + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "stream terminator found\n" ); + ASSERT( contextp->cc_Media_useterminatorpr ); + ASSERT( dcaps & DRIVE_CAP_BSF ); /* redundant */ + status = 0; + rval = ( * dop->do_bsf )( drivep, 0, &status ); + ASSERT( rval == 0 ); + if ( status == DRIVE_ERROR_DEVICE ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_MEDIA, + "encountered media error " + "attempting BSF\n" ); + goto changemedia; + } + if ( mrhdrp->mh_mediafileix == 0 ) { + virginmediapr = BOOL_TRUE; + } + goto write; + } + continue; + case DRIVE_ERROR_FOREIGN: + prevmediapresentpr = mediapresentpr; + mediapresentpr = BOOL_TRUE; + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_MEDIA, + "media contains non-xfsdump data " + "or a corrupt xfsdump media file header " + "at beginning of media\n" ); + + switch( Media_erasechk( drivep, + dcaps, + intr_allowed, + prevmediapresentpr )) { + case RV_OK: + goto erasemedia; + case RV_INTR: + return RV_INTR; + default: + break; + } + + if ( dlog_allowed( )) { + bool_t ok; + ok = Media_prompt_overwrite( drivep ); + if ( intr_allowed && cldmgr_stop_requested( )) { + return RV_INTR; + } + if ( ! ok ) { + goto changemedia; + } + } + virginmediapr = BOOL_TRUE; /* like a virgin */ + goto write; + case DRIVE_ERROR_OVERWRITE: + prevmediapresentpr = mediapresentpr; + mediapresentpr = BOOL_TRUE; + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_MEDIA, + "media may contain data. " + "Overwrite option specified\n" ); + + if ( dlog_allowed( )) { + bool_t ok; + ok = Media_prompt_overwrite( drivep ); + if ( intr_allowed && cldmgr_stop_requested( )) { + return RV_INTR; + } + if ( ! ok ) { + goto changemedia; + } + } + virginmediapr = BOOL_TRUE; /* like a virgin */ + goto write; + case DRIVE_ERROR_BLANK: + prevmediapresentpr = mediapresentpr; + mediapresentpr = BOOL_TRUE; + virginmediapr = BOOL_TRUE; + goto write; + case DRIVE_ERROR_MEDIA: + prevmediapresentpr = mediapresentpr; + mediapresentpr = BOOL_TRUE; + goto changemedia; + case DRIVE_ERROR_DEVICE: + return RV_DRIVE; + case DRIVE_ERROR_EOD: + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "at end of data\n" ); + prevmediapresentpr = mediapresentpr; + mediapresentpr = BOOL_TRUE; + virginmediapr = BOOL_FALSE; + + switch( Media_erasechk( drivep, + dcaps, + intr_allowed, + prevmediapresentpr )) { + case RV_OK: + goto erasemedia; + case RV_INTR: + return RV_INTR; + default: + break; + } + + if ( contextp->cc_Media_useterminatorpr ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_MEDIA, + "encountered EOD but expecting a media " + "stream terminator: " + "assuming full media\n" ); + goto changemedia; + } else { + goto write; + } + case DRIVE_ERROR_EOM: + prevmediapresentpr = mediapresentpr; + mediapresentpr = BOOL_TRUE; + virginmediapr = BOOL_FALSE; + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_MEDIA, + "encountered EOM: media is full\n" ); + + switch( Media_erasechk( drivep, + dcaps, + intr_allowed, + prevmediapresentpr )) { + case RV_OK: + goto erasemedia; + case RV_INTR: + return RV_INTR; + default: + break; + } + + goto changemedia; + case DRIVE_ERROR_CORRUPTION: + case DRIVE_ERROR_VERSION: + case DRIVE_ERROR_FORMAT: + prevmediapresentpr = mediapresentpr; + mediapresentpr = BOOL_TRUE; + virginmediapr = BOOL_FALSE; + + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_MEDIA, + "encountered corrupt or foreign data: " + "assuming corrupted media\n" ); + + switch( Media_erasechk( drivep, + dcaps, + intr_allowed, + prevmediapresentpr )) { + case RV_OK: + goto erasemedia; + case RV_INTR: + return RV_INTR; + default: + break; + } + + if ( contextp->cc_Media_useterminatorpr ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_MEDIA, + "encountered corrupt or foreign data " + "but expecting a media " + "stream terminator: " + "assuming corrupted media\n" ); + goto changemedia; + } else if ( ! ( dcaps & DRIVE_CAP_OVERWRITE )) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_MEDIA, + "encountered corrupt or foreign data: " + "unable to overwrite: " + "assuming corrupted media\n" ); + goto changemedia; + } else { + intgen_t status; + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_MEDIA, + "encountered corrupt or foreign data: " + "repositioning to overwrite\n" ); + ASSERT( dcaps & DRIVE_CAP_BSF ); + status = 0; + rval = ( * dop->do_bsf )( drivep, 0, &status ); + ASSERT( rval == 0 ); + if ( status == DRIVE_ERROR_DEVICE ) { + return RV_DRIVE; + } + goto write; + } + case DRIVE_ERROR_STOP: + return RV_INTR; + case DRIVE_ERROR_INVAL: + return RV_ERROR; + case DRIVE_ERROR_EOF: + default: + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_MEDIA, + "unexpected error from do_begin_read: %d\n", + rval ); + return RV_CORE; + } + } + /* NOTREACHED */ + +erasemedia: + mlog( MLOG_VERBOSE | MLOG_WARNING | MLOG_MEDIA, + "erasing media\n" ); + rval = ( * dop->do_erase )( drivep ); + if ( rval ) { + return RV_DRIVE; + } + prevmediapresentpr = mediapresentpr; + mediapresentpr = BOOL_UNKNOWN; + virginmediapr = BOOL_UNKNOWN; + mediawrittentopr = BOOL_FALSE; + goto position; + +changemedia: + /* if the drive does not support media change, quit. + */ + if ( ! ( dcaps & DRIVE_CAP_REMOVABLE )) { + return RV_ERROR; + } + + /* first eject the current media object if capability supported + */ + ASSERT( mediapresentpr != BOOL_UNKNOWN ); + if ( mediapresentpr == BOOL_TRUE ) { + if ( dcaps & DRIVE_CAP_EJECT ) { + rval = ( * dop->do_eject_media )( drivep ); + if ( rval ) { + return RV_DRIVE; + } + } + } + + /* if dialogs not allowed, we are done. + */ + if ( ! dlog_allowed( )) { + return RV_QUIT; /* this return value will cause approp. msg */ + } + + /* If an alert program has been specified , run it + */ + if (media_change_alert_program != NULL) + system(media_change_alert_program); + + /* if media change prompt declined or times out, + * we are done + */ + if ( drivecnt > 1 && ! stdoutpiped ) { + ix_t thrdix = drivep->d_index; + ASSERT( sistr ); + mlog( MLOG_NORMAL | MLOG_NOTE | MLOG_MEDIA, + "please change media: " + "type %s to confirm media change\n", + sistr ); + set_mcflag( thrdix ); + while ( sc_mcflag[ thrdix ] ) { + sleep( 2 ); + if ( cldmgr_stop_requested( )) { + clr_mcflag( thrdix ); + return RV_INTR; + } + } + ok = BOOL_TRUE; + } else { + ok = Media_prompt_change( drivep ); + } + if ( intr_allowed && cldmgr_stop_requested( )) { + return RV_INTR; + } + if ( ! ok ) { + return RV_QUIT; + } + + /* we know nothing about the media after a media change + */ + prevmediapresentpr = mediapresentpr; + mediapresentpr = BOOL_UNKNOWN; + virginmediapr = BOOL_UNKNOWN; + mediawrittentopr = BOOL_FALSE; + + goto position; + +write: + ASSERT( mediapresentpr == BOOL_TRUE ); + ASSERT( virginmediapr != BOOL_UNKNOWN ); + + if ( intr_allowed && cldmgr_stop_requested( )) { + return RV_INTR; + } + + /* bump the media header indices here. NOTE: will rescind these + * if the subsequent do_begin_write fails. this will be done by + * making a copy of the global write header, and copying it + * back on failure. + */ + saved_gwhdr = *gwhdrp; + + if ( mediawrittentopr ) { + mwhdrp->mh_dumpmediafileix++; + } else { + mwhdrp->mh_dumpmediafileix = 0; + } + mwhdrp->mh_dumpfileix++; /* pre-initialized to -1 */ + if ( virginmediapr ) { + mwhdrp->mh_mediafileix = 0; + mwhdrp->mh_dumpmediaix = 0; + } else { + if ( mwhdrp->mh_dumpmediafileix == 0 ) { + mwhdrp->mh_dumpmediaix = mrhdrp->mh_dumpmediaix + 1; + } + if ( mediawrittentopr ) { + mwhdrp->mh_mediafileix++; + } else { + mwhdrp->mh_mediafileix = mrhdrp->mh_mediafileix; + if ( ! MEDIA_TERMINATOR_CHK( mrhdrp )) { + mwhdrp->mh_mediafileix++; + } + } + } + + if ( ! mediawrittentopr ) { + mwhdrp->mh_mediaix++; /* pre-initialized to -1 */ + } + + ASSERT( mwhdrp->mh_mediaix != ( u_int32_t )( -1 )); + ASSERT( mwhdrp->mh_dumpfileix != ( u_int32_t )( -1 )); + + /* do not allow interleaving of media files from different xfsdumps. + */ + if ( mwhdrp->mh_mediaix != 0 + && + mwhdrp->mh_dumpmediafileix == 0 + && + ! virginmediapr ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_MEDIA, + "cannot interleave dump streams: must supply a blank " + "media object\n" ); + *gwhdrp = saved_gwhdr; + goto changemedia; + } + + /* update the media object previous id and label + */ + if ( ! mediawrittentopr && mwhdrp->mh_dumpfileix != 0 ) { + uuid_copy(mwhdrp->mh_prevmediaid, mwhdrp->mh_mediaid); + ( void )strncpyterm( mwhdrp->mh_prevmedialabel, + mwhdrp->mh_medialabel, + sizeof( mwhdrp->mh_medialabel )); + } + + /* update the media object current id and label + */ + if ( ! mediawrittentopr ) { + if ( mwhdrp->mh_mediafileix == 0 ) { + char labelbuf[ GLOBAL_HDR_STRING_SZ ]; + + uuid_generate( mwhdrp->mh_mediaid ); + + if ( ! cmdlinemedialabel + && + ! drivep->d_isnamedpipepr + && + ! drivep->d_isunnamedpipepr + && + dlog_allowed( )) { + cmdlinemedialabel = Media_prompt_label( drivep, + labelbuf, + sizeof( labelbuf )); + if ( intr_allowed && cldmgr_stop_requested( )) { + return RV_INTR; + } + } + if ( cmdlinemedialabel && strlen( cmdlinemedialabel )) { + ( void )strncpyterm( mwhdrp->mh_medialabel, + cmdlinemedialabel, + sizeof( mwhdrp->mh_medialabel )); + } else { + ( void )memset( ( void * )mwhdrp->mh_medialabel, + 0, + sizeof( mwhdrp->mh_medialabel )); + if ( ! pipeline ) { + mlog( MLOG_VERBOSE + | + MLOG_WARNING + | + MLOG_MEDIA, + "no media label specified\n" ); + } + } + } else { + ASSERT( ! virginmediapr ); + uuid_copy(mwhdrp->mh_mediaid, mrhdrp->mh_mediaid); + ( void )strncpyterm( mwhdrp->mh_medialabel, + mrhdrp->mh_medialabel, + sizeof( mwhdrp->mh_medialabel )); + } + } + + mediawrittentopr = BOOL_TRUE; + + /* write hdr is prepared. place it on media + */ + if ( intr_allowed && cldmgr_stop_requested( )) { + return RV_INTR; + } + rval = ( * dop->do_begin_write )( drivep ); + switch( rval ) { + case 0: + return RV_OK; + case DRIVE_ERROR_EOM: + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "encountered end of media " + "while attempting to begin new media file\n" ); + *gwhdrp = saved_gwhdr; + goto changemedia; + case DRIVE_ERROR_MEDIA: + *gwhdrp = saved_gwhdr; + goto changemedia; + case DRIVE_ERROR_DEVICE: + return RV_DRIVE; + default: + return RV_CORE; + } +} + +/* ARGSUSED */ +static rv_t +Media_mfile_end( drive_t *drivep, + context_t *contextp, + media_hdr_t *mwhdrp, + off64_t *ncommittedp, + bool_t hit_eom ) +{ + drive_ops_t *dop = drivep->d_opsp; + intgen_t rval; + + mlog( MLOG_DEBUG | MLOG_MEDIA, + "Media op: end media file\n" ); + + ASSERT( contextp->cc_Media_begin_entrystate == BES_INVAL ); + + /* call drive's end_write op to flush the tail of the media file + * if has previously hit EOM, this is moot. + */ + rval = ( dop->do_end_write )( drivep, ncommittedp ); + if ( hit_eom ) { + ASSERT( ! rval ); + contextp->cc_Media_begin_entrystate = BES_ENDEOM; + return RV_EOM; + } + switch( rval ) { + case 0: + contextp->cc_Media_begin_entrystate = BES_ENDOK; + return RV_OK; + case DRIVE_ERROR_MEDIA: + case DRIVE_ERROR_EOM: + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "encountered end of media " + "while ending media file\n" ); + contextp->cc_Media_begin_entrystate = BES_ENDEOM; + return RV_EOM; + case DRIVE_ERROR_DEVICE: + contextp->cc_Media_begin_entrystate = BES_INVAL; + return RV_DRIVE; + default: + contextp->cc_Media_begin_entrystate = BES_INVAL; + return RV_CORE; + } + +} + +static bool_t +Media_prompt_overwrite( drive_t *drivep ) +{ + fold_t fold; + char question[ 100 ]; + char *preamblestr[ PREAMBLEMAX ]; + size_t preamblecnt; + char *querystr[ QUERYMAX ]; + size_t querycnt; + char *choicestr[ CHOICEMAX ]; + size_t choicecnt; + char *ackstr[ ACKMAX ]; + size_t ackcnt; + char *postamblestr[ POSTAMBLEMAX ]; + size_t postamblecnt; + ix_t doix; + ix_t dontix; + ix_t responseix; + ix_t sigintix; + +retry: + preamblecnt = 0; + fold_init( fold, "media overwrite dialog", '=' ); + preamblestr[ preamblecnt++ ] = "\n"; + preamblestr[ preamblecnt++ ] = fold; + preamblestr[ preamblecnt++ ] = "\n\n"; + ASSERT( preamblecnt <= PREAMBLEMAX ); + dlog_begin( preamblestr, preamblecnt ); + + /* query: ask if overwrite ok + */ + sprintf( question, + "overwrite data on media in " + "drive %u?\n", + (unsigned int)drivep->d_index ); + querycnt = 0; + querystr[ querycnt++ ] = question; + ASSERT( querycnt <= QUERYMAX ); + choicecnt = 0; + dontix = choicecnt; + choicestr[ choicecnt++ ] = "don't overwrite"; + doix = choicecnt; + choicestr[ choicecnt++ ] = "overwrite"; + ASSERT( choicecnt <= CHOICEMAX ); + sigintix = IXMAX - 1; + + responseix = dlog_multi_query( querystr, + querycnt, + choicestr, + choicecnt, + 0, /* hilitestr */ + IXMAX, /* hiliteix */ + 0, /* defaultstr */ + doix, /* defaultix */ + DLOG_TIMEOUT_MEDIA, + dontix, /* timeout ix */ + sigintix, /* sigint ix */ + dontix, /* sighup ix */ + dontix ); /* sigquit ix */ + ackcnt = 0; + if ( responseix == doix ) { + ackstr[ ackcnt++ ] = "media will be overwritten\n"; + } else if ( responseix == dontix ) { + ackstr[ ackcnt++ ] = "media will NOT be overwritten\n"; + } else { + ackstr[ ackcnt++ ] = "keyboard interrupt\n"; + } + ASSERT( ackcnt <= ACKMAX ); + dlog_multi_ack( ackstr, + ackcnt ); + + postamblecnt = 0; + fold_init( fold, "end dialog", '-' ); + postamblestr[ postamblecnt++ ] = "\n"; + postamblestr[ postamblecnt++ ] = fold; + postamblestr[ postamblecnt++ ] = "\n\n"; + ASSERT( postamblecnt <= POSTAMBLEMAX ); + dlog_end( postamblestr, + postamblecnt ); + + if ( responseix == sigintix ) { + if ( cldmgr_stop_requested( )) { + return BOOL_FALSE; + } + sleep( 1 ); /* to allow main thread to begin dialog */ + mlog( MLOG_NORMAL | MLOG_BARE, + "" ); /* to block until main thread dialog complete */ + sleep( 1 ); /* to allow main thread to request children die */ + if ( cldmgr_stop_requested( )) { + return BOOL_FALSE; + } + mlog( MLOG_DEBUG, + "retrying media overwrite dialog\n" ); + goto retry; + } + + + return responseix == doix; +} + +static rv_t +Media_erasechk( drive_t *drivep, + intgen_t dcaps, + bool_t intr_allowed, + bool_t prevmediapresentpr ) +{ + if ( prevmediapresentpr == BOOL_TRUE ) { + return RV_NOTOK; + } + + if ( sc_preerasepr ) { + if ( dcaps & DRIVE_CAP_ERASE ) { + if ( dlog_allowed( )) { + bool_t ok; + ok = Media_prompt_erase( drivep ); + if ( intr_allowed && cldmgr_stop_requested( )) { + return RV_INTR; + } + if ( ok ) { + return RV_OK; + } else { + return RV_NOTOK; + } + } else { + return RV_OK; + } + } else { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_MEDIA, + "drive does not support media erase: " + "ignoring -%c option\n", + GETOPT_ERASE ); + return RV_NOTOK; + } + } else { + return RV_NOTOK; + } +} + +static bool_t +Media_prompt_erase( drive_t *drivep ) +{ + fold_t fold; + char question[ 100 ]; + char *preamblestr[ PREAMBLEMAX ]; + size_t preamblecnt; + char *querystr[ QUERYMAX ]; + size_t querycnt; + char *choicestr[ CHOICEMAX ]; + size_t choicecnt; + char *ackstr[ ACKMAX ]; + size_t ackcnt; + char *postamblestr[ POSTAMBLEMAX ]; + size_t postamblecnt; + ix_t doix; + ix_t dontix; + ix_t responseix; + ix_t sigintix; + +retry: + preamblecnt = 0; + fold_init( fold, "media erase dialog", '=' ); + preamblestr[ preamblecnt++ ] = "\n"; + preamblestr[ preamblecnt++ ] = fold; + preamblestr[ preamblecnt++ ] = "\n\n"; + ASSERT( preamblecnt <= PREAMBLEMAX ); + dlog_begin( preamblestr, preamblecnt ); + + /* query: ask if overwrite ok + */ + sprintf( question, + "pre-erase (-%c) option specified " + "and non-blank media encountered:\n" + "please confirm media erase " + "drive %u\n", + GETOPT_ERASE, + (unsigned int)drivep->d_index ); + querycnt = 0; + querystr[ querycnt++ ] = question; + ASSERT( querycnt <= QUERYMAX ); + choicecnt = 0; + dontix = choicecnt; + choicestr[ choicecnt++ ] = "don't erase"; + doix = choicecnt; + choicestr[ choicecnt++ ] = "erase"; + ASSERT( choicecnt <= CHOICEMAX ); + sigintix = IXMAX - 1; + + responseix = dlog_multi_query( querystr, + querycnt, + choicestr, + choicecnt, + 0, /* hilitestr */ + IXMAX, /* hiliteix */ + 0, /* defaultstr */ + doix, /* defaultix */ + DLOG_TIMEOUT_MEDIA, + dontix, /* timeout ix */ + sigintix, /* sigint ix */ + dontix, /* sighup ix */ + dontix ); /* sigquit ix */ + ackcnt = 0; + if ( responseix == doix ) { + ackstr[ ackcnt++ ] = "media will be erased\n"; + } else if ( responseix == dontix ) { + ackstr[ ackcnt++ ] = "media will NOT be erased\n"; + } else { + ackstr[ ackcnt++ ] = "keyboard interrupt\n"; + } + ASSERT( ackcnt <= ACKMAX ); + dlog_multi_ack( ackstr, + ackcnt ); + + postamblecnt = 0; + fold_init( fold, "end dialog", '-' ); + postamblestr[ postamblecnt++ ] = "\n"; + postamblestr[ postamblecnt++ ] = fold; + postamblestr[ postamblecnt++ ] = "\n\n"; + ASSERT( postamblecnt <= POSTAMBLEMAX ); + dlog_end( postamblestr, + postamblecnt ); + + if ( responseix == sigintix ) { + if ( cldmgr_stop_requested( )) { + return BOOL_FALSE; + } + sleep( 1 ); /* to allow main thread to begin dialog */ + mlog( MLOG_NORMAL | MLOG_BARE, + "" ); /* to block until main thread dialog complete */ + sleep( 1 ); /* to allow main thread to request children die */ + if ( cldmgr_stop_requested( )) { + return BOOL_FALSE; + } + mlog( MLOG_DEBUG, + "retrying media erase dialog\n" ); + goto retry; + } + + + return responseix == doix; +} + +static void +Media_prompt_label_cb( void *uctxp, dlog_pcbp_t pcb, void *pctxp ) +{ + drive_t *drivep = ( drive_t * )uctxp; + + /* query: ask for a label + */ + ( * pcb )( pctxp, + "please enter label for media in " + "drive %u", + drivep->d_index ); +} + +static char * +Media_prompt_label( drive_t *drivep, char *bufp, size_t bufsz ) +{ + fold_t fold; + char *preamblestr[ PREAMBLEMAX ]; + size_t preamblecnt; + char *ackstr[ ACKMAX ]; + size_t ackcnt; + char *postamblestr[ POSTAMBLEMAX ]; + size_t postamblecnt; + const ix_t timeoutix = 1; + const ix_t abortix = 2; + const ix_t sigintix = 3; + const ix_t okix = 4; + ix_t responseix; + +retry: + preamblecnt = 0; + fold_init( fold, "media label dialog", '=' ); + preamblestr[ preamblecnt++ ] = "\n"; + preamblestr[ preamblecnt++ ] = fold; + preamblestr[ preamblecnt++ ] = "\n\n"; + ASSERT( preamblecnt <= PREAMBLEMAX ); + dlog_begin( preamblestr, preamblecnt ); + + responseix = dlog_string_query( Media_prompt_label_cb, + ( void * )drivep, + bufp, + bufsz, + DLOG_TIMEOUT, + timeoutix,/* timeout ix */ + sigintix, /* sigint ix */ + abortix, /* sighup ix */ + abortix, /* sigquit ix */ + okix ); /* ok ix */ + ackcnt = 0; + if ( responseix == okix ) { + ackstr[ ackcnt++ ] = "media label entered: \""; + ackstr[ ackcnt++ ] = bufp; + ackstr[ ackcnt++ ] = "\"\n"; + } else if ( responseix == timeoutix ) { + ackstr[ ackcnt++ ] = "timeout: media label left blank\n"; + } else if ( responseix == sigintix ) { + ackstr[ ackcnt++ ] = "keyboard interrupt\n"; + } else { + ackstr[ ackcnt++ ] = "abort\n"; + } + + ASSERT( ackcnt <= ACKMAX ); + dlog_string_ack( ackstr, + ackcnt ); + + postamblecnt = 0; + fold_init( fold, "end dialog", '-' ); + postamblestr[ postamblecnt++ ] = "\n"; + postamblestr[ postamblecnt++ ] = fold; + postamblestr[ postamblecnt++ ] = "\n\n"; + ASSERT( postamblecnt <= POSTAMBLEMAX ); + dlog_end( postamblestr, + postamblecnt ); + + if ( responseix == sigintix ) { + if ( cldmgr_stop_requested( )) { + return 0; + } + sleep( 1 ); /* to allow main thread to begin dialog */ + mlog( MLOG_NORMAL | MLOG_BARE, + "" ); /* to block until main thread dialog complete */ + sleep( 1 ); /* to allow main thread to request children die */ + if ( cldmgr_stop_requested( )) { + return 0; + } + mlog( MLOG_DEBUG, + "retrying media label dialog\n" ); + goto retry; + } + + + if ( responseix == okix ) { + return bufp; + } else { + return 0; + } +} + +static void +set_mcflag( ix_t thrdix ) +{ + lock( ); + sc_mcflag[ thrdix ] = BOOL_TRUE; + content_media_change_needed = BOOL_TRUE; + unlock( ); +} + +static void +clr_mcflag( ix_t thrdix ) +{ + lock( ); + sc_mcflag[ thrdix ] = BOOL_FALSE; + for ( thrdix = 0 ; thrdix < drivecnt ; thrdix++ ) { + if ( sc_mcflag[ thrdix ] ) { + unlock( ); + return; + } + } + content_media_change_needed = BOOL_FALSE; + unlock( ); +} + +static bool_t +check_complete_flags( void ) +{ + ix_t strmix; + bool_t completepr = BOOL_TRUE; + + for ( strmix = 0 ; strmix < drivecnt ; strmix++ ) { + context_t *contextp = &sc_contextp[ strmix ]; + if ( ! contextp->cc_completepr ) { + completepr = BOOL_FALSE; + break; + } + } + + return completepr; +} + +/* on linux we use xfsdq instead of repquota */ +#define REPQUOTA "xfsdq" + +static bool_t +save_quotas( char *mntpnt, quota_info_t *quotainfo ) +{ + int sts = 0; + char buf[1024] = ""; + int fd; + char tmp; + + mlog( MLOG_VERBOSE, "saving %s information for: %s\n", quotainfo->desc, mntpnt ); + + if( unlink( quotainfo->quotapath ) == 0 ) { + mlog( MLOG_WARNING, "overwriting: %s\n", quotainfo->quotapath); + } + else { + if( errno != ENOENT ) { + mlog( MLOG_ERROR, + "unable to remove %s: %s\n", + quotainfo->quotapath, + strerror( errno )); + return BOOL_FALSE; + } + } + + sprintf( buf, + "%s %s %s > %s", + REPQUOTA, + quotainfo->repquotaargs, + mntpnt, + quotainfo->quotapath ); + + mlog( MLOG_NITTY, "saving quotas: %s\n", buf ); + + sts = system( buf ); + if( sts != 0 ) { + mlog( MLOG_ERROR, + "%s failed with exit status: %d\n", REPQUOTA, sts); + return BOOL_FALSE; + } + if((fd = open( quotainfo->quotapath, O_RDONLY|O_DSYNC)) < 0) { + mlog( MLOG_ERROR, + "open failed %s: %s\n", + quotainfo->quotapath, + strerror( errno )); + return BOOL_FALSE; + } + /* open and read dump file to ensure it is in the dump */ + read(fd, &tmp, 1); + close(fd); + return BOOL_TRUE; +} + +static int +getxfsqstat(char *fsname) +{ + fs_quota_stat_t qstat; + + /* + * See if quotas is on. If not, nada. + */ + memset(&qstat, 0, sizeof(fs_quota_stat_t)); + if (quotactl(QCMD(Q_XGETQSTAT, 0), fsname, 0, + (caddr_t)&qstat) < 0) { + return (-1); + } + return ((int)qstat.qs_flags); +} diff -rNu linux-2.4.7/cmd/xfsdump/dump/getopt.h linux-2.4-xfs/cmd/xfsdump/dump/getopt.h --- linux-2.4.7/cmd/xfsdump/dump/getopt.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/dump/getopt.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef GETOPT_H +#define GETOPT_H + +/* getopt.h common getopt command string + * + * several modules parse the command line looking for arguments specific to + * that module. Unfortunately, each of the getopt(3) calls needs the + * complete command string, to know how to parse. This file's purpose is + * to contain that command string. It also abstracts the option letters, + * facilitating easy changes. + */ + +#define GETOPT_CMDSTRING "ab:c:d:f:hl:mop:qs:v:AB:CEFG:H:I:JL:M:NO:PRSTUVWY:Z" + +#define GETOPT_DUMPASOFFLINE 'a' /* dump DMF dualstate files as offline */ +#define GETOPT_BLOCKSIZE 'b' /* blocksize for rmt */ +#define GETOPT_ALERTPROG 'c' /* Media Change Alert prog(content.c) */ +#define GETOPT_FILESZ 'd' /* Media file size to use in Mb */ +#define GETOPT_DUMPDEST 'f' /* dump dest. file (drive.c) */ +#define GETOPT_HELP 'h' /* display version and usage */ +#define GETOPT_LEVEL 'l' /* dump level (content_inode.c) */ +#define GETOPT_MINRMT 'm' /* use minimal rmt protocol */ +#define GETOPT_OVERWRITE 'o' /* overwrite data on tape */ +#define GETOPT_PROGRESS 'p' /* interval between progress reports */ +#define GETOPT_SUBTREE 's' /* subtree dump (content_inode.c) */ +#define GETOPT_VERBOSITY 'v' /* verbosity level (0 to 4 ) */ +#define GETOPT_NOEXTATTR 'A' /* do not dump ext. file attributes */ +#define GETOPT_BASED 'B' /* specify session to base increment */ +#define GETOPT_RECCHKSUM 'C' /* use record checksums */ +#define GETOPT_ERASE 'E' /* pre-erase media */ +#define GETOPT_FORCE 'F' /* don't prompt (getopt.c) */ +#define GETOPT_MINSTACKSZ 'G' /* minimum stack size (bytes) */ +#define GETOPT_MAXSTACKSZ 'H' /* maximum stack size (bytes) */ +#define GETOPT_INVPRINT 'I' /* just display the inventory */ +#define GETOPT_NOINVUPDATE 'J' /* do not update the dump inventory */ +#define GETOPT_DUMPLABEL 'L' /* dump session label (global.c) */ +#define GETOPT_MEDIALABEL 'M' /* media object label (media.c) */ +#define GETOPT_TIMESTAMP 'N' /* show timestamps in log msgs */ +#define GETOPT_OPTFILE 'O' /* specifycmd line options file */ +#define GETOPT_RINGPIN 'P' /* pin down I/O buffer ring */ +#define GETOPT_QIC 'q' /* option to tell dump it's a QIC tape */ +#define GETOPT_RESUME 'R' /* resume intr dump (content_inode.c) */ +#define GETOPT_SINGLEMFILE 'S' /* don't use multiple media files */ +#define GETOPT_NOTIMEOUTS 'T' /* don't timeout dialogs */ +#define GETOPT_UNLOAD 'U' /* unload media when change needed */ +#define GETOPT_SHOWLOGSS 'V' /* show subsystem of log messages */ +#define GETOPT_SHOWLOGLEVEL 'W' /* show level of log messages */ +#define GETOPT_RINGLEN 'Y' /* specify I/O buffer ring length */ +#define GETOPT_MINIROOT 'Z' /* apply miniroot restrictions */ + +#endif /* GETOPT_H */ diff -rNu linux-2.4.7/cmd/xfsdump/dump/hsmapi.c linux-2.4-xfs/cmd/xfsdump/dump/hsmapi.c --- linux-2.4.7/cmd/xfsdump/dump/hsmapi.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/dump/hsmapi.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,622 @@ +/************************************************************************** + * * + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + * * + **************************************************************************/ + +#include + +#include + +#include +#include +#include + +#include "hsmapi.h" + +/* XXX PORT */ +#ifdef HIDDEN + +/* This version of the HSM API currently only supports the DMF attribute + format used in the initial release. +*/ + +/* DMF attribute name, size, and format as stored within XFS. (Stolen directly + from "dmfsapi/dmf_dmapi.h". +*/ + +#define DMF_ATTR_NAME "SGI_DMI_DMFATTR" /* attribute used by DMF */ +#define DMF_ATTR_LEN 22 /* length of the attribute */ + +typedef struct { + u_char version; /* attribute format version */ + u_char pad; + u_char state[2]; /* dm_state in MSB form */ + u_char flags[2]; /* dm_flags in MSB form */ + u_char bfid[16]; /* Bitfile ID in MSB form */ +} XFSattrvalue1_t; + +#define XFS_ATTR_VERSION_1 1 /* only supported version field value */ + +/* Interesting state field values (bottom byte). */ + +#define DMF_ST_DUALSTATE 2 /* file has backups plus online data */ +#define DMF_ST_OFFLINE 3 /* file has backups, no online data */ +#define DMF_ST_UNMIGRATING 4 /* file data is being staged in */ + +/* Interesting bit combinations within the bs_dmevmask field of xfs_bstat_t. */ + +#define DUALSTATE_BITS ( (1<dumpversion = dumpversion; + dmf_fs_ctxtp->fsid = fsid; + + return (hsm_fs_ctxt_t *)dmf_fs_ctxtp; +} + + +/****************************************************************************** +* Name +* HsmDeleteFsysContext - delete an HSM filesystem context +* +* Description +* HsmDeleteFsysContext releases all storage previously allocated to a +* HSM filesystem context via HsmInitFsysContext. +* +* Returns +* None. +******************************************************************************/ + +extern void +HsmDeleteFsysContext( + hsm_fs_ctxt_t *contextp) +{ + free(contextp); +} + + +/****************************************************************************** +* Name +* HsmEstimateFileSpace - return estimated offline file size +* +* Description +* HsmEstimateFileSpace is called from within estimate_dump_space() only +* if -a is selected. It estimates the number of bytes needed to dump +* the file assuming that all dual-residency data will be dumped as holes. +* +* Returns +* != 0, then *bytes contains the estimated size of the file in bytes. +* == 0, then no estimate made. Caller should use his default estimator. +******************************************************************************/ + +extern int +HsmEstimateFileSpace( + hsm_fs_ctxt_t *contextp, +const xfs_bstat_t *statp, + off64_t *bytes) +{ + dmf_fs_ctxt_t *dmf_fs_ctxtp = (dmf_fs_ctxt_t *)contextp; + dmf_f_ctxt_t dmf_f_ctxt; + + /* This is an implicit HsmAllocateFileContext call. */ + + dmf_f_ctxt.fsys = *dmf_fs_ctxtp; + dmf_f_ctxt.candidate = 0; + + /* Initialize the file context to determine the file's state. */ + + if (HsmInitFileContext((hsm_f_ctxt_t *)&dmf_f_ctxt, statp)) { + return 0; + } + + /* If the file is dualstate, make it appear offline. */ + + if (dmf_f_ctxt.candidate) { + *bytes = 0; /* treat the entire file as offline */ + return 1; + } else { + return 0; + } +} + + +/****************************************************************************** +* Name +* HsmEstimateFileOffset - return estimated file offset +* +* Description +* HsmEstimateFileOffset is called from within quantity2offset() only +* if -a is selected. It estimates the offset within the file that has +* 'bytecount' bytes of physical data preceding it assuming that all +* dual-residency data in the file will be dumped as holes. +* +* Returns +* != 0, then *byteoffset contains the estimated offset within the file. +* == 0, then no estimate made. Caller should use his default estimator. +******************************************************************************/ + +/* ARGSUSED */ +extern int +HsmEstimateFileOffset( + hsm_fs_ctxt_t *contextp, +const xfs_bstat_t *statp, + off64_t bytecount, + off64_t *byteoffset) +{ + dmf_fs_ctxt_t *dmf_fs_ctxtp = (dmf_fs_ctxt_t *)contextp; + dmf_f_ctxt_t dmf_f_ctxt; + + /* This is an implicit HsmAllocateFileContext call. */ + + dmf_f_ctxt.fsys = *dmf_fs_ctxtp; + dmf_f_ctxt.candidate = 0; + + /* Initialize the file context to determine the file's state. */ + + if (HsmInitFileContext((hsm_f_ctxt_t *)&dmf_f_ctxt, statp)) { + return 0; + } + + /* If the file is dualstate, make it appear offline. */ + + if (dmf_f_ctxt.candidate) { + *byteoffset = statp->bs_size; + return 1; + } else { + return 0; + } +} + + +/****************************************************************************** +* Name +* HsmAllocateFileContext - allocate an HSM file context +* +* Description +* HsmAllocateFileContext mallocs the maximum-sized file context that +* might later needed by HsmInitFileContext(). The context is +* read-write. Each xfsdump stream must have its own file context. This +* context should eventually be freed by calling HsmDeleteFileContext(). +* The caller must provide the HSM filesystem context for the filesystem +* being dumped. +* +* Returns +* != NULL, then a pointer to the file context that was allocated. +******************************************************************************/ + +extern hsm_f_ctxt_t * +HsmAllocateFileContext( + hsm_fs_ctxt_t *contextp) +{ + dmf_f_ctxt_t *dmf_f_ctxtp; + + if ((dmf_f_ctxtp = malloc(sizeof(dmf_f_ctxt_t))) == NULL) { + return NULL; + } + + /* Save the filesystem information in the file context. */ + + dmf_f_ctxtp->fsys = *(dmf_fs_ctxt_t *)contextp; + dmf_f_ctxtp->candidate = 0; + + return (hsm_f_ctxt_t *)dmf_f_ctxtp; +} + + +/****************************************************************************** +* Name +* HsmDeleteFileContext - delete a previously created HSM file context +* +* Description +* HsmDeleteFileContext releases all storage previously allocated to a +* HSM file context via HsmAllocateFileContext. +* +* Returns +* None. +******************************************************************************/ + +extern void +HsmDeleteFileContext( + hsm_f_ctxt_t *contextp) +{ + free(contextp); +} + + +/****************************************************************************** +* Name +* HsmInitFileContext - initialize the HSM context for a particular file +* +* Description +* HsmInitFileContext initializes an existing HSM file context for +* subsequent operations on a particular regular file. Other HSM routines +* use the context to access information collected by HsmInitFileContext +* about the file rather than having to recollect the file's information +* on each call. +* +* Returns +* == 0, context was created. +* != 0, if something is wrong with the file and it should not be dumped. +******************************************************************************/ + +extern int +HsmInitFileContext( + hsm_f_ctxt_t *contextp, +const xfs_bstat_t *statp) +{ + dmf_f_ctxt_t *dmf_f_ctxtp = (dmf_f_ctxt_t *)contextp; + XFSattrvalue1_t *dmfattrp; + int attrlen; + void *hanp; + size_t hlen; + dm_ino_t ino; + dm_igen_t igen; + int fd; + int error; + + dmf_f_ctxtp->candidate = 0; /* assume file will NOT be of interest */ + + /* Try and rule out a dualstate inode by doing some quick tests. */ + + if ((statp->bs_mode & S_IFMT) != S_IFREG) { + return 0; /* not a regular file */ + } + if ((statp->bs_xflags & XFS_XFLAG_HASATTR) == 0) { + return 0; /* no DMF attribute exists */ + } + if ((statp->bs_dmevmask & DUALSTATE_BITS) != DUALSTATE_BITS) { + return 0; /* non-dualstate managed region bits */ + } + + /* We have a likely candidate, so we have to pay the price and look + for the DMF attribute. (It could be in a disk block separate from + the inode.) + */ + + ino = (dm_ino_t)statp->bs_ino; + igen = (dm_igen_t)statp->bs_gen; + if (dm_make_handle(&dmf_f_ctxtp->fsys.fsid, &ino, &igen, &hanp, &hlen) != 0) { + return 0; /* can't make a proper handle */ + } + + /* The following code should eventually be replaced with the + attr_multif-by-handle call when it is available. + */ + + fd = open_by_handle(hanp, hlen, O_RDONLY); + dm_handle_free(hanp, hlen); + if (fd < 0) { + return 0; + } + attrlen = sizeof(dmf_f_ctxtp->attrval); + error = attr_getf(fd, DMF_ATTR_NAME, dmf_f_ctxtp->attrval, + &attrlen, ATTR_ROOT); + (void)close(fd); + if (error) { + return 0; + } + + if (attrlen != DMF_ATTR_LEN) { + return 0; /* not the right length to be the attribute */ + } + + dmfattrp = (XFSattrvalue1_t *)dmf_f_ctxtp->attrval; + if (dmfattrp->version != XFS_ATTR_VERSION_1) { + return 0; /* we don't support this version */ + } + if (dmfattrp->state[0] != '\0') { + return 0; /* should be zero */ + } + if (dmfattrp->state[1] != DMF_ST_DUALSTATE && + dmfattrp->state[1] != DMF_ST_UNMIGRATING) { + return 0; + } + + /* We have a DMF dual state file. */ + + dmf_f_ctxtp->candidate = 1; + dmf_f_ctxtp->filesize = BTOBB(statp->bs_size); + return 0; +} + + +/****************************************************************************** +* Name +* HsmModifyInode - modify a xfs_bstat_t to make a file appear offline +* +* Description +* HsmModifyInode uses the context provided by a previous +* HsmInitFileContext call to determine how to modify a xfs_bstat_t +* structure to make a dual-residency HSM file appear to be offline. +* +* Returns +* != 0, xfs_bstat_t structure was modified. +* == 0, if something is wrong with the file and it should not be dumped. +******************************************************************************/ + +extern int +HsmModifyInode( + hsm_f_ctxt_t *contextp, + xfs_bstat_t *statp) +{ + dmf_f_ctxt_t *dmf_f_ctxtp = (dmf_f_ctxt_t *)contextp; + + if (dmf_f_ctxtp->candidate) { + statp->bs_dmevmask |= (1<candidate) { + return 1; /* not a dualstate file; dump as normal */ + } + + /* We are dumping a dualstate file. Make it look like there is only + one getbmapx extent and that it contains a hole which extends from + the current offset to the end of the file. The bmap[1].bmv_offset + should already be correct. + */ + + length = dmf_f_ctxtp->filesize - bmap[1].bmv_offset; + + if (length > 0) { + bmap[0].bmv_entries = 1; /* rest of file is one extent */ + + bmap[1].bmv_block = -1; /* convert to a hole */ + bmap[1].bmv_length = length; + } else { + bmap[0].bmv_entries = 0; /* indicate at EOF */ + } + + return 1; +} + + +/****************************************************************************** +* Name +* HsmFilterExistingAttribute - filter out unwanted extended attributes +* +* Description +* HsmFilterExistingAttribute uses the context provided by a previous +* HsmInitFileContext call to determine whether or not the extended +* attribute with name 'namep' should be included in a file's dump image. +* (An extended attribute can be modified within the dump by filtering +* it out with this routine, then adding the new version of the attribute +* back with HsmAddNewAttribute.) +* +* Note: this routine must be idempotent. It is possible that xfsdump +* will call this routine a second time for the same attribute if after +* the first call it discovers that there isn't room in its buffer to +* hold the attribute value. +* +* Returns +* != 0, the attribute was successfully examined. If '*skip_entry' is +* non-zero, xfsdump will not add this attribute to the dump. +* == 0, if something is wrong with the file and it should not be dumped. +******************************************************************************/ + +extern int +HsmFilterExistingAttribute( + hsm_f_ctxt_t *hsm_f_ctxtp, +const char *namep, /* attribute name */ + u_int32_t valuesz, /* value size */ + int isroot, + int *skip_entry) +{ + dmf_f_ctxt_t *dmf_f_ctxtp = (dmf_f_ctxt_t *)hsm_f_ctxtp; + + *skip_entry = 0; /* assume we will not remove this attribute */ + + if (!dmf_f_ctxtp->candidate) { + return 1; /* not a dualstate file */ + } + if (!isroot) { + return 1; /* not a root attribute */ + } + if (strcmp(namep, DMF_ATTR_NAME)) { + return 1; /* not the right attribute */ + } + + if (valuesz != DMF_ATTR_LEN) { + return 0; /* attribute is corrupt */ + } + + /* Remove the existing DMF attribute, as we will later replace it with + our own version. + */ + + *skip_entry = 1; + return 1; +} + + +/****************************************************************************** +* Name +* HsmAddNewAttribute - add zero or more HSM attributes to a file's dump +* +* Description +* HsmAddNewAttribute uses the context provided by a previous +* HsmInitFileContext call to determine whether or not additional HSM +* extended attributes need to be added to a file's dump image. On the +* first call for a file, 'cursor' will be zero. xfsdump will increment +* 'cursor' by one each time it asks for a new attribute. When no more +* attributes are to be added, '*namepp' should be set to NULL. +* +* Note: this routine must be idempotent. It is possible that xfsdump +* will call this routine a second time using the same cursor value if +* it discovers that there isn't room in its buffer to hold the attribute +* value it was given in the first call. +* +* Returns +* != 0, call was successful. If '*namepp' is non-NULL, then it is the +* name of an attribute to be added to the file's dump. '*valuep' +* points the the value of the attribute, and '*valueszp' is the +* value's size. If '*namep* is NULL, then there are no more +* attributes to be added. +* == 0, if something is wrong with the file and it should not be dumped. +******************************************************************************/ + +extern int +HsmAddNewAttribute( + hsm_f_ctxt_t *hsm_f_ctxtp, + int cursor, + int isroot, + char **namepp, /* pointer to new attribute name */ + char **valuepp, /* pointer to its value */ + u_int32_t *valueszp) /* pointer to the value size */ +{ + dmf_f_ctxt_t *dmf_f_ctxtp = (dmf_f_ctxt_t *)hsm_f_ctxtp; + XFSattrvalue1_t *dmfattrp = (XFSattrvalue1_t *)dmf_f_ctxtp->attrval; + + *namepp = NULL; /* assume we won't add an attribute */ + + if (!dmf_f_ctxtp->candidate) { + return 1; /* not a dualstate file */ + } + if (!isroot) { + return 1; /* not in the root attribute section */ + } + + if (cursor > 0) { + return 1; /* there is only one attribute to add */ + } + + dmfattrp->state[1] = DMF_ST_OFFLINE; + *valuepp = (char *)dmfattrp; + *namepp = DMF_ATTR_NAME; + *valueszp = DMF_ATTR_LEN; + + return 1; +} +#endif diff -rNu linux-2.4.7/cmd/xfsdump/dump/hsmapi.h linux-2.4-xfs/cmd/xfsdump/dump/hsmapi.h --- linux-2.4.7/cmd/xfsdump/dump/hsmapi.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/dump/hsmapi.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,299 @@ +/************************************************************************** + * * + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + * * + **************************************************************************/ + +#ifndef HSMAPI_H +#define HSMAPI_H + +#define HSM_API_VERSION_1 1 /* only version supported so far */ + +typedef void hsm_fs_ctxt_t; /* opaque HSM filesystem context */ +typedef void hsm_f_ctxt_t; /* opaque HSM file context */ + + +/****************************************************************************** +* Name +* HsmInitFsysContext - allocate and initialize an HSM filesystem context +* +* Description +* HsmInitFsysContext allocates and initializes an HSM filesystem +* context to hold all filesystem information that might later be needed +* by the other HSM routines. The context is read-only, and can be shared +* by multiple xfsdump dump streams. It should eventually be freed by +* calling HsmDeleteFsysContext(). The caller must provide the mount +* point of the filesystem to be dumped and the HSM API version that +* xfsdump was compiled with. +* +* Returns +* != NULL, then a pointer to the filesystem context that was allocated. +* == NULL, either the HSM libary is not compatible with xfsdump, or +* the filesystem is not under HSM management. +******************************************************************************/ + +extern hsm_fs_ctxt_t * +HsmInitFsysContext( +const char *mountpoint, + int dumpversion); + + +/****************************************************************************** +* Name +* HsmDeleteFsysContext - delete an HSM filesystem context +* +* Description +* HsmDeleteFsysContext releases all storage previously allocated to a +* HSM filesystem context via HsmInitFsysContext. +* +* Returns +* None. +******************************************************************************/ + +extern void +HsmDeleteFsysContext( + hsm_fs_ctxt_t *contextp); + + +/****************************************************************************** +* Name +* HsmEstimateFileSpace - return estimated offline file size +* +* Description +* HsmEstimateFileSpace is called from within estimate_dump_space() only +* if -a is selected. It estimates the number of bytes needed to dump +* the file assuming that all dual-residency data will be dumped as holes. +* +* Returns +* != 0, then *bytes contains the estimated size of the file in bytes. +* == 0, then no estimate made. Caller should use his default estimator. +******************************************************************************/ + +extern int +HsmEstimateFileSpace( + hsm_fs_ctxt_t *contextp, +const xfs_bstat_t *statp, + off64_t *bytes); + + +/****************************************************************************** +* Name +* HsmEstimateFileOffset - return estimated file offset +* +* Description +* HsmEstimateFileOffset is called from within quantity2offset() only +* if -a is selected. It estimates the offset within the file that has +* 'bytecount' bytes of physical data preceding it assuming that all +* dual-residency data in the file will be dumped as holes. +* +* Returns +* != 0, then *byteoffset contains the estimated offset within the file. +* == 0, then no estimate made. Caller should use his default estimator. +******************************************************************************/ + +extern int +HsmEstimateFileOffset( + hsm_fs_ctxt_t *contextp, +const xfs_bstat_t *statp, + off64_t bytecount, + off64_t *byteoffset); + + +/****************************************************************************** +* Name +* HsmAllocateFileContext - allocate an HSM file context +* +* Description +* HsmAllocateFileContext mallocs the maximum-sized file context that +* might later be needed by HsmInitFileContext(). The context is +* read-write. Each xfsdump stream must have its own file context. This +* context should eventually be freed by calling HsmDeleteFileContext(). +* The caller must provide the HSM filesystem context for the filesystem +* being dumped. +* +* Returns +* != NULL, then a pointer to the file context that was allocated. +******************************************************************************/ + +extern hsm_f_ctxt_t * +HsmAllocateFileContext( + hsm_fs_ctxt_t *contextp); + + +/****************************************************************************** +* Name +* HsmDeleteFileContext - delete a previously created HSM file context +* +* Description +* HsmDeleteFileContext releases all storage previously allocated to a +* HSM file context via HsmAllocateFileContext. +* +* Returns +* None. +******************************************************************************/ + +extern void +HsmDeleteFileContext( + hsm_f_ctxt_t *contextp); + + +/****************************************************************************** +* Name +* HsmInitFileContext - initialize the HSM context for a particular file +* +* Description +* HsmInitFileContext initializes an existing HSM file context for +* subsequent operations on a particular regular file. Other HSM routines +* use the context to access information collected by HsmInitFileContext +* about the file rather than having to recollect the file's information +* on each call. +* +* Returns +* != 0, context was created. +* == 0, if something is wrong with the file and it should not be dumped. +******************************************************************************/ + +extern int +HsmInitFileContext( + hsm_f_ctxt_t *contextp, +const xfs_bstat_t *statp); + + +/****************************************************************************** +* Name +* HsmModifyInode - modify a xfs_bstat_t to make a file appear offline +* +* Description +* HsmModifyInode uses the context provided by a previous +* HsmInitFileContext call to determine how to modify a xfs_bstat_t +* structure to make a dual-residency HSM file appear to be offline. +* +* Returns +* != 0, xfs_bstat_t structure was modified. +* == 0, if something is wrong with the file and it should not be dumped. +******************************************************************************/ + +extern int +HsmModifyInode( + hsm_f_ctxt_t *contextp, + xfs_bstat_t *statp); + + +/****************************************************************************** +* Name +* HsmModifyExtentMap - modify getbmapx array to make file appear offline +* +* Description +* HsmModifyExtentMap uses the context provided by a previous +* HsmInitFileContext call to determine how to modify a contiguous array +* of getbmapx structures to make a dual-residency HSM file appear to +* be offline. +* +* Returns +* != 0, getbmapx array was successfully modified. +* == 0, if something is wrong with the file and it should not be dumped. +******************************************************************************/ + +extern int +HsmModifyExtentMap( + hsm_f_ctxt_t *contextp, + struct getbmapx *bmap); + + +/****************************************************************************** +* Name +* HsmFilterExistingAttribute - filter out unwanted extended attributes +* +* Description +* HsmFilterExistingAttribute uses the context provided by a previous +* HsmInitFileContext call to determine whether or not the extended +* attribute with name 'namep' should be included in a file's dump image. +* (An extended attribute can be modified within the dump by filtering +* it out with this routine, then adding the new version of the attribute +* back with HsmAddNewAttribute.) +* +* Note: this routine must be idempotent. It is possible that xfsdump +* will call this routine a second time for the same attribute if after +* the first call it discovers that there isn't room in its buffer to +* hold the attribute value. +* +* Returns +* != 0, the attribute was successfully examined. If '*skip_entry' is +* non-zero, xfsdump will not add this attribute to the dump. +* == 0, if something is wrong with the file and it should not be dumped. +******************************************************************************/ + +extern int +HsmFilterExistingAttribute( + hsm_f_ctxt_t *hsm_f_ctxtp, +const char *namep, /* name of attribute to filter */ + u_int32_t valuesz, /* attribute's current value size */ + int isroot, /* != 0, an ATTR_ROOT attribute */ + int *skip_entry); + + +/****************************************************************************** +* Name +* HsmAddNewAttribute - add zero or more HSM attributes to a file's dump +* +* Description +* HsmAddNewAttribute uses the context provided by a previous +* HsmInitFileContext call to determine whether or not additional HSM +* extended attributes need to be added to a file's dump image. On the +* first call for a file, 'cursor' will be zero. xfsdump will increment +* 'cursor' by one each time it asks for a new attribute. When no more +* attributes are to be added, '*namepp' should be set to NULL. +* +* Note: this routine must be idempotent. It is possible that xfsdump +* will call this routine a second time using the same cursor value if +* it discovers that there isn't room in its buffer to hold the attribute +* value it was given in the first call. +* +* Returns +* != 0, call was successful. If '*namepp' is non-NULL, then it is the +* name of an attribute to be added to the file's dump. '*valuep' +* points the the value of the attribute, and '*valueszp' is the +* value's size. If '*namep* is NULL, then there are no more +* attributes to be added. +* == 0, if something is wrong with the file and it should not be dumped. +******************************************************************************/ + +extern int +HsmAddNewAttribute( + hsm_f_ctxt_t *hsm_f_ctxtp, + int cursor, + int isroot, /* != 0, wants ATTR_ROOT attributes */ + char **namepp, /* pointer to new attribute name */ + char **valuepp, /* pointer to its value */ + u_int32_t *valueszp); /* pointer to the value size */ + + +#endif /* HSMAPI_H */ diff -rNu linux-2.4.7/cmd/xfsdump/dump/inomap.c linux-2.4-xfs/cmd/xfsdump/dump/inomap.c --- linux-2.4.7/cmd/xfsdump/dump/inomap.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/dump/inomap.c Thu Jul 5 03:42:14 2001 @@ -0,0 +1,2054 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "types.h" +#include "util.h" +#include "mlog.h" +#include "global.h" +#include "drive.h" +#include "media.h" +#include "content.h" +#include "content_inode.h" +#ifdef DMEXTATTR +#include "hsmapi.h" +#endif /* DMEXTATTR */ + +#define MACROBITS +#include "inomap.h" +#include "arch_xlate.h" +#include "exit.h" + +/* structure definitions used locally ****************************************/ + +#define BSTATBUFLEN pgsz + /* length (in bstat_t's) of buf passed to bigstat_iter + */ + +#define GETDENTBUFSZ pgsz + /* size (in bytes) of buf passed to diriter (when not recursive) + */ + +/* declarations of externally defined global symbols *************************/ + +extern bool_t preemptchk( int ); +extern size_t pgsz; +#ifdef DMEXTATTR +extern hsm_fs_ctxt_t *hsm_fs_ctxtp; +#endif /* DMEXTATTR */ + + +/* forward declarations of locally defined static functions ******************/ + +/* inomap construction callbacks + */ +static void cb_context( bool_t last, + time_t, + bool_t, + time_t, + size_t, + drange_t *, + size_t, + startpt_t *, + size_t, + char *, + size_t ); +static void cb_postmortem( void ); +static intgen_t cb_add( void *, jdm_fshandle_t *, intgen_t, xfs_bstat_t * ); +static bool_t cb_inoinresumerange( xfs_ino_t ); +static bool_t cb_inoresumed( xfs_ino_t ); +static intgen_t cb_prune( void *, jdm_fshandle_t *, intgen_t, xfs_bstat_t * ); +static intgen_t cb_count_in_subtreelist( void *, + jdm_fshandle_t *, + intgen_t, + xfs_bstat_t *, + char * ); +static intgen_t cb_count_needed_children( void *, + jdm_fshandle_t *, + intgen_t, + xfs_bstat_t *, + char * ); +static void gdrecursearray_init( void ); +static void gdrecursearray_free( void ); +static intgen_t cb_cond_del( void *, + jdm_fshandle_t *, + intgen_t, + xfs_bstat_t *, + char * ); +static intgen_t cb_del( void *, + jdm_fshandle_t *, + intgen_t, + xfs_bstat_t *, + char * ); +static void cb_accuminit_sz( void ); +static void cb_accuminit_ctx( void * ); +static intgen_t cb_accumulate( void *, + jdm_fshandle_t *, + intgen_t, + xfs_bstat_t * ); +static void cb_spinit( void ); +static intgen_t cb_startpt( void *, + jdm_fshandle_t *, + intgen_t, + xfs_bstat_t * ); +static off64_t quantity2offset( jdm_fshandle_t *, xfs_bstat_t *, off64_t ); +static off64_t estimate_dump_space( xfs_bstat_t * ); + +/* inomap primitives + */ +static void map_init( void ); +static void map_add( xfs_ino_t ino, intgen_t ); +static intgen_t map_getset( xfs_ino_t, intgen_t, bool_t ); +static intgen_t map_get( xfs_ino_t ); +static intgen_t map_set( xfs_ino_t ino, intgen_t ); + +/* subtree abstraction + */ +static void subtreelist_add( xfs_ino_t ); +static intgen_t subtreelist_parse_cb( void *, + jdm_fshandle_t *, + intgen_t fsfd, + xfs_bstat_t *, + char * ); +static bool_t subtreelist_parse( jdm_fshandle_t *, + intgen_t, + xfs_bstat_t *, + char *[], + ix_t ); +static void subtreelist_free( void ); +static bool_t subtreelist_contains( xfs_ino_t ); + +/* multiply linked (mln) abstraction + */ +static void mln_init( void ); +static nlink_t mln_register( xfs_ino_t, nlink_t ); +static void mln_free( void ); + + +/* definition of locally defined global variables ****************************/ + + +/* definition of locally defined static variables *****************************/ + +static ix_t *inomap_statphasep; +static ix_t *inomap_statpassp; +static size64_t *inomap_statdonep; + +/* definition of locally defined global functions ****************************/ + +/* inomap_build - build an in-core image of the inode map for the + * specified file system. identify startpoints in the non-dir inodes, + * such that the total dump media required is divided into startptcnt segments. + */ +/* ARGSUSED */ +bool_t +inomap_build( jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *rootstatp, + bool_t last, + time_t lasttime, + bool_t resume, + time_t resumetime, + size_t resumerangecnt, + drange_t *resumerangep, + char *subtreebuf[], + ix_t subtreecnt, + startpt_t *startptp, + size_t startptcnt, + ix_t *statphasep, + ix_t *statpassp, + size64_t statcnt, + size64_t *statdonep ) +{ + xfs_bstat_t *bstatbufp; + size_t bstatbuflen; + char *getdentbufp; + bool_t pruneneeded; + bool_t rescanneeded; + ix_t scancnt; + intgen_t stat; + void *inomap_state_contextp; + intgen_t rval; + + /* copy stat ptrs + */ + inomap_statphasep = statphasep; + inomap_statpassp = statpassp; + inomap_statdonep = statdonep; + + /* allocate a bulkstat buf + */ + bstatbuflen = BSTATBUFLEN; + bstatbufp = ( xfs_bstat_t * )malloc( bstatbuflen * sizeof( xfs_bstat_t )); + ASSERT( bstatbufp ); + + /* allocate a getdent buf + */ + getdentbufp = ( char * )malloc( GETDENTBUFSZ ); + ASSERT( getdentbufp ); + + /* parse the subtree list, if any subtrees specified. + * this will be used during the tree pruning phase. + */ + if ( subtreecnt ) { + mlog( MLOG_VERBOSE | MLOG_INOMAP, + "ino map phase 1: " + "parsing subtree selections\n" ); + if ( ! subtreelist_parse( fshandlep, + fsfd, + rootstatp, + subtreebuf, + subtreecnt )) { + free( ( void * )bstatbufp ); + free( ( void * )getdentbufp ); + return BOOL_FALSE; + } + } else { + mlog( MLOG_VERBOSE | MLOG_INOMAP, + "ino map phase 1: " + "skipping (no subtrees specified)\n" ); + } + + if ( preemptchk( PREEMPT_FULL )) { + free( ( void * )bstatbufp ); + free( ( void * )getdentbufp ); + return BOOL_FALSE; + } + + /* initialize the callback context + */ + cb_context( last, + lasttime, + resume, + resumetime, + resumerangecnt, + resumerangep, + subtreecnt, + startptp, + startptcnt, + getdentbufp, + GETDENTBUFSZ ); + + /* construct the ino map, based on the last dump time, resumed + * dump info, and subtree list. place all unchanged directories + * in the "needed for children" state (MAP_DIR_SUPPRT). these will be + * dumped even though they have not changed. a later pass will move + * some of these to "not dumped", such that only those necessary + * to represent the minimal tree containing only changes will remain. + * the bigstat iterator is used here, along with a inomap constructor + * callback. set a flag if any ino not put in a dump state. This will + * be used to decide if any pruning can be done. + */ + mlog( MLOG_VERBOSE | MLOG_INOMAP, + "ino map phase 2: " + "constructing initial dump list\n" ); + *inomap_statdonep = 0; + *inomap_statphasep = 2; + pruneneeded = BOOL_FALSE; + stat = 0; + cb_accuminit_sz( ); + rval = bigstat_iter( fshandlep, + fsfd, + BIGSTAT_ITER_ALL, + ( xfs_ino_t )0, + cb_add, + ( void * )&pruneneeded, + &stat, + preemptchk, + bstatbufp, + bstatbuflen ); + *inomap_statphasep = 0; + if ( rval ) { + free( ( void * )bstatbufp ); + free( ( void * )getdentbufp ); + return BOOL_FALSE; + } + + if ( preemptchk( PREEMPT_FULL )) { + free( ( void * )bstatbufp ); + free( ( void * )getdentbufp ); + return BOOL_FALSE; + } + + /* prune subtrees not called for in the subtree list, and + * directories unchanged since the last dump and containing + * no children needing dumping. Each time the latter pruning + * occurs at least once, repeat. + */ + if ( pruneneeded || subtreecnt > 0 ) { + /* setup the list of multiply-linked pruned nodes + */ + mln_init( ); + gdrecursearray_init( ); + + scancnt = 0; + rescanneeded = BOOL_FALSE; /* not needed, keeps lint happy */ + do { + scancnt++; + if ( scancnt <= 1 ) { + mlog( MLOG_VERBOSE | MLOG_INOMAP, + "ino map phase 3: " + "pruning unneeded subtrees\n" ); + } else { + mlog( MLOG_VERBOSE | MLOG_INOMAP, + "ino map phase 3: " + "pass %d\n", + scancnt ); + } + *inomap_statdonep = 0; + *inomap_statpassp = scancnt; + *inomap_statphasep = 3; + rescanneeded = BOOL_FALSE; + stat = 0; + rval = bigstat_iter( fshandlep, + fsfd, + BIGSTAT_ITER_DIR, + ( xfs_ino_t )0, + cb_prune, + ( void * )&rescanneeded, + &stat, + preemptchk, + bstatbufp, + bstatbuflen ); + *inomap_statphasep = 0; + *inomap_statpassp = 0; + if ( rval ) { + gdrecursearray_free( ); + free( ( void * )bstatbufp ); + free( ( void * )getdentbufp ); + return BOOL_FALSE; + } + + if ( preemptchk( PREEMPT_FULL )) { + gdrecursearray_free( ); + free( ( void * )bstatbufp ); + free( ( void * )getdentbufp ); + return BOOL_FALSE; + } + + } while ( rescanneeded ); + + gdrecursearray_free( ); + mln_free( ); + + cb_postmortem( ); + + } else { + mlog( MLOG_VERBOSE | MLOG_INOMAP, + "ino map phase 3: " + "skipping (no pruning necessary)\n" ); + } + + /* free the subtree list memory + */ + if ( subtreecnt ) { + subtreelist_free( ); + } + + /* allocate a map iterator to allow us to skip inos that have + * been pruned from the map. + */ + inomap_state_contextp = inomap_state_getcontext( ); + + cb_accuminit_ctx( inomap_state_contextp ); + + /* calculate the total dump space needed for non-directories. + * no needed if no pruning was done, since already done during + * phase 2. + */ + if ( pruneneeded || subtreecnt > 0 ) { + cb_accuminit_sz( ); + + mlog( MLOG_VERBOSE | MLOG_INOMAP, + "ino map phase 4: " + "estimating dump size\n" ); + *inomap_statdonep = 0; + *inomap_statphasep = 4; + stat = 0; + rval = bigstat_iter( fshandlep, + fsfd, + BIGSTAT_ITER_NONDIR, + ( xfs_ino_t )0, + cb_accumulate, + 0, + &stat, + preemptchk, + bstatbufp, + bstatbuflen ); + *inomap_statphasep = 0; + if ( rval ) { + inomap_state_freecontext( inomap_state_contextp ); + free( ( void * )bstatbufp ); + free( ( void * )getdentbufp ); + return BOOL_FALSE; + } + + if ( preemptchk( PREEMPT_FULL )) { + inomap_state_freecontext( inomap_state_contextp ); + free( ( void * )bstatbufp ); + free( ( void * )getdentbufp ); + return BOOL_FALSE; + } + + inomap_state_postaccum( inomap_state_contextp ); + } else { + mlog( MLOG_VERBOSE | MLOG_INOMAP, + "ino map phase 4: " + "skipping (size estimated in phase 2)\n" ); + } + + /* initialize the callback context for startpoint calculation + */ + cb_spinit( ); + + /* identify dump stream startpoints + */ + if ( startptcnt > 1 ) { + mlog( MLOG_VERBOSE | MLOG_INOMAP, + "ino map phase 5: " + "identifying stream starting points\n" ); + } else { + mlog( MLOG_VERBOSE | MLOG_INOMAP, + "ino map phase 5: " + "skipping (only one dump stream)\n" ); + } + stat = 0; + *inomap_statdonep = 0; + *inomap_statphasep = 5; + rval = bigstat_iter( fshandlep, + fsfd, + BIGSTAT_ITER_NONDIR, + ( xfs_ino_t )0, + cb_startpt, + 0, + &stat, + preemptchk, + bstatbufp, + bstatbuflen ); + *inomap_statphasep = 0; + + inomap_state_postaccum( inomap_state_contextp ); + + inomap_state_freecontext( inomap_state_contextp ); + + if ( rval ) { + free( ( void * )bstatbufp ); + free( ( void * )getdentbufp ); + return BOOL_FALSE; + } + + if ( startptcnt > 1 ) { + ix_t startptix; + for ( startptix = 0 ; startptix < startptcnt ; startptix++ ) { + startpt_t *p; + startpt_t *ep; + + p = &startptp[ startptix ]; + if ( startptix == startptcnt - 1 ) { + ep = 0; + } else { + ep = &startptp[ startptix + 1 ]; + } + ASSERT( ! p->sp_flags ); + mlog( MLOG_VERBOSE | MLOG_INOMAP, + "stream %u: ino %llu offset %lld to ", + startptix, + p->sp_ino, + p->sp_offset ); + if ( ! ep ) { + mlog( MLOG_VERBOSE | MLOG_BARE | MLOG_INOMAP, + "end\n" ); + } else { + mlog( MLOG_VERBOSE | MLOG_BARE | MLOG_INOMAP, + "ino %llu offset %lld\n", + ep->sp_ino, + ep->sp_offset ); + } + } + } + + free( ( void * )bstatbufp ); + free( ( void * )getdentbufp ); + mlog( MLOG_VERBOSE | MLOG_INOMAP, + "ino map construction complete\n" ); + return BOOL_TRUE; +} + +void +inomap_skip( xfs_ino_t ino ) +{ + intgen_t oldstate; + + oldstate = map_get( ino ); + if ( oldstate == MAP_NDR_CHANGE) { + ( void )map_set( ino, MAP_NDR_NOCHNG ); + } + + if ( oldstate == MAP_DIR_CHANGE + || + oldstate == MAP_DIR_SUPPRT ) { + ( void )map_set( ino, MAP_DIR_NOCHNG ); + } +} + + +/* definition of locally defined static functions ****************************/ + +/* callback context and operators - inomap_build makes extensive use + * of iterators. below are the callbacks given to these iterators. + */ +static bool_t cb_last; /* set by cb_context() */ +static time_t cb_lasttime; /* set by cb_context() */ +static bool_t cb_resume; /* set by cb_context() */ +static time_t cb_resumetime; /* set by cb_context() */ +static size_t cb_resumerangecnt;/* set by cb_context() */ +static drange_t *cb_resumerangep;/* set by cb_context() */ +static ix_t cb_subtreecnt; /* set by cb_context() */ +static void *cb_inomap_state_contextp; +static startpt_t *cb_startptp; /* set by cb_context() */ +static size_t cb_startptcnt; /* set by cb_context() */ +static size_t cb_startptix; /* set by cb_spinit(), incr. by cb_startpt */ +static off64_t cb_datasz; /* set by cb_context() */ +static off64_t cb_accum; /* set by cb_context(), cb_spinit() */ +static off64_t cb_incr; /* set by cb_spinit(), used by cb_startpt() */ +static off64_t cb_target; /* set by cb_spinit(), used by cb_startpt() */ +static off64_t cb_dircnt; /* number of dirs CHANGED or PRUNE */ +static off64_t cb_nondircnt; /* number of non-dirs CHANGED */ +static char *cb_getdentbufp; +static size_t cb_getdentbufsz; +static size_t cb_maxrecursionlevel; + +/* cb_context - initializes the call back context for the add and prune + * phases of inomap_build(). + */ +static void +cb_context( bool_t last, + time_t lasttime, + bool_t resume, + time_t resumetime, + size_t resumerangecnt, + drange_t *resumerangep, + ix_t subtreecnt, + startpt_t *startptp, + size_t startptcnt, + char *getdentbufp, + size_t getdentbufsz ) +{ + cb_last = last; + cb_lasttime = lasttime; + cb_resume = resume; + cb_resumetime = resumetime; + cb_resumerangecnt = resumerangecnt; + cb_resumerangep = resumerangep; + cb_subtreecnt = subtreecnt; + cb_startptp = startptp; + cb_startptcnt = startptcnt; + cb_accum = 0; + cb_dircnt = 0; + cb_nondircnt = 0; + cb_getdentbufp = getdentbufp; + cb_getdentbufsz = getdentbufsz; + cb_maxrecursionlevel = 0; + + map_init( ); +} + +static void +cb_postmortem( void ) +{ + mlog( MLOG_DEBUG | MLOG_NOTE | MLOG_INOMAP, + "maximum subtree pruning recursion depth: %u\n", + cb_maxrecursionlevel ); +} + +/* cb_add - called for all inodes in the file system. checks + * mod and create times to decide if should be dumped. sets all + * unmodified directories to be dumped for supprt. notes if any + * files or directories have not been modified. + */ +/* ARGSUSED */ +static intgen_t +cb_add( void *arg1, + jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp ) +{ + register time_t mtime = statp->bs_mtime.tv_sec; + register time_t ctime = statp->bs_ctime.tv_sec; + register time_t ltime = max( mtime, ctime ); + register mode_t mode = statp->bs_mode & S_IFMT; + xfs_ino_t ino = statp->bs_ino; + bool_t changed; + bool_t resumed; + + ( *inomap_statdonep )++; + + /* skip if no links + */ + if ( statp->bs_nlink == 0 ) { + return 0; + } + + /* if no portion of this ino is in the resume range, + * then only dump it if it has changed since the interrupted + * dump. + * + * otherwise, if some or all of this ino is in the resume range, + * and has changed since the base dump upon which the original + * increment was based, dump it if it has changed since that + * original base dump. + */ + if ( cb_resume && ! cb_inoinresumerange( ino )) { + if ( ltime >= cb_resumetime ) { + changed = BOOL_TRUE; + } else { + changed = BOOL_FALSE; + } + } else if ( cb_last ) { + if ( ltime >= cb_lasttime ) { + changed = BOOL_TRUE; + } else { + changed = BOOL_FALSE; + } + } else { + changed = BOOL_TRUE; + } + + /* this is redundant: make sure any ino partially dumped + * is completed. + */ + if ( cb_resume && cb_inoresumed( ino )) { + resumed = BOOL_TRUE; + } else { + resumed = BOOL_FALSE; + } + + if ( changed ) { + if ( mode == S_IFDIR ) { + map_add( ino, MAP_DIR_CHANGE ); + cb_dircnt++; + } else { + map_add( ino, MAP_NDR_CHANGE ); + cb_nondircnt++; + cb_datasz += estimate_dump_space( statp ); + } + } else if ( resumed ) { + ASSERT( mode != S_IFDIR ); + ASSERT( changed ); + } else { + if ( mode == S_IFDIR ) { + register bool_t *pruneneededp = ( bool_t * )arg1; + *pruneneededp = BOOL_TRUE; + map_add( ino, MAP_DIR_SUPPRT ); + cb_dircnt++; + } else { + map_add( ino, MAP_NDR_NOCHNG ); + } + } + + return 0; +} + +static bool_t +cb_inoinresumerange( xfs_ino_t ino ) +{ + register size_t streamix; + + for ( streamix = 0 ; streamix < cb_resumerangecnt ; streamix++ ) { + register drange_t *rp = &cb_resumerangep[ streamix ]; + if ( ! ( rp->dr_begin.sp_flags & STARTPT_FLAGS_END ) + && + ino >= rp->dr_begin.sp_ino + && + ( ( rp->dr_end.sp_flags & STARTPT_FLAGS_END ) + || + ino < rp->dr_end.sp_ino + || + ( ino == rp->dr_end.sp_ino + && + rp->dr_end.sp_offset != 0 ))) { + return BOOL_TRUE; + } + } + + return BOOL_FALSE; +} + +static bool_t +cb_inoresumed( xfs_ino_t ino ) +{ + size_t streamix; + + for ( streamix = 0 ; streamix < cb_resumerangecnt ; streamix++ ) { + drange_t *rp = &cb_resumerangep[ streamix ]; + if ( ! ( rp->dr_begin.sp_flags & STARTPT_FLAGS_END ) + && + ino == rp->dr_begin.sp_ino + && + rp->dr_begin.sp_offset != 0 ) { + return BOOL_TRUE; + } + } + + return BOOL_FALSE; +} + +/* cb_prune - does subtree and incremental pruning. + * calls cb_cond_del() to do dirty work on subtrees. + */ +static intgen_t +cb_prune( void *arg1, + jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp ) +{ + register bool_t *rescanneededp = ( bool_t * )arg1; + xfs_ino_t ino = statp->bs_ino; + + ASSERT( ( statp->bs_mode & S_IFMT ) == S_IFDIR ); + + if ( cb_subtreecnt > 0 ) { + if ( subtreelist_contains( ino )) { + intgen_t n = 0; + intgen_t cbrval = 0; + ( void )diriter( fshandlep, + fsfd, + statp, + cb_count_in_subtreelist, + ( void * )&n, + &cbrval, + cb_getdentbufp, + cb_getdentbufsz ); + if ( n > 0 ) { + ( void )diriter( fshandlep, + fsfd, + statp, + cb_cond_del, + 0, + &cbrval, + cb_getdentbufp, + cb_getdentbufsz ); + } + } + } + if ( map_get( ino ) == MAP_DIR_SUPPRT ) { + intgen_t n = 0; + intgen_t cbrval = 0; + ( void )diriter( fshandlep, + fsfd, + statp, + cb_count_needed_children, + ( void * )&n, + &cbrval, + cb_getdentbufp, + cb_getdentbufsz ); + if ( n == 0 ) { + ( void )map_set( ino, MAP_DIR_NOCHNG ); + cb_dircnt--; + ( *rescanneededp )++; + } + } + + ( *inomap_statdonep )++; + + return 0; +} + +/* cb_count_in_subtreelist - used by cb_prune() to look for possible + * subtree pruning. + */ +/* ARGSUSED */ +static intgen_t +cb_count_in_subtreelist( void *arg1, + jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp, + char *namep ) +{ + if ( subtreelist_contains( statp->bs_ino )) { + intgen_t *np = ( intgen_t * )arg1; + ( *np )++; + } + + return 0; +} + +/* ARGSUSED */ +static intgen_t +cb_count_needed_children( void *arg1, + jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp, + char *namep ) +{ + intgen_t state = map_get( statp->bs_ino ); + + if ( state != MAP_INO_UNUSED + && + state != MAP_DIR_NOCHNG + && + state != MAP_NDR_NOCHNG ) { + register intgen_t *np = ( intgen_t * )arg1; + ( *np )++; + } + + return 0; +} + +/* cb_cond_del - usd by cb_prune to check and do subtree pruning + */ +/* ARGSUSED */ +static intgen_t +cb_cond_del( void *arg1, + jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp, + char *namep ) +{ + xfs_ino_t ino = statp->bs_ino; + + if ( ! subtreelist_contains( ino )) { + cb_del( 0, fshandlep, fsfd, statp, namep ); + } + + return 0; +} + +#define GDRECURSEDEPTHMAX 32 + +static char *gdrecursearray[ GDRECURSEDEPTHMAX ]; + +static void +gdrecursearray_init( void ) +{ + ix_t level; + + for ( level = 0 ; level < GDRECURSEDEPTHMAX ; level++ ) { + gdrecursearray[ level ] = 0; + } +} + +static void +gdrecursearray_free( void ) +{ + ix_t level; + + for ( level = 0 ; level < GDRECURSEDEPTHMAX ; level++ ) { + if ( gdrecursearray[ level ] ) { + free( ( void * )gdrecursearray[ level ] ); + gdrecursearray[ level ] = 0; + } + } +} + +/* cb_del - used by cb_cond_del() to actually delete a subtree. + * recursive. + */ +/* ARGSUSED */ +static intgen_t +cb_del( void *arg1, + jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp, + char *namep ) +{ + xfs_ino_t ino = statp->bs_ino; + intgen_t oldstate; + register size_t recursion_level = ( size_t )arg1; + + if ( recursion_level >= GDRECURSEDEPTHMAX ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_INOMAP, + "subtree pruning recursion depth exceeds max (%d): " + "some unselected subtrees may be included in dump\n", + GDRECURSEDEPTHMAX ); + return 0; + } + + if ( cb_maxrecursionlevel < recursion_level ) { + cb_maxrecursionlevel = recursion_level; + } + + oldstate = MAP_INO_UNUSED; + + if ( ( statp->bs_mode & S_IFMT ) == S_IFDIR ) { + intgen_t cbrval = 0; + oldstate = map_set( ino, MAP_DIR_NOCHNG ); + if ( ! gdrecursearray[ recursion_level ] ) { + char *getdentbufp; + getdentbufp = ( char * )malloc( GETDENTBUFSZ ); + ASSERT( getdentbufp ); + gdrecursearray[ recursion_level ] = getdentbufp; + } + ( void )diriter( fshandlep, + fsfd, + statp, + cb_del, + ( void * )( recursion_level + 1 ), + &cbrval, + gdrecursearray[ recursion_level ], + GETDENTBUFSZ ); + mlog( MLOG_DEBUG | MLOG_INOMAP, + "pruning dir ino %llu\n", + ino ); + } else if ( statp->bs_nlink <= 1 ) { + mlog( MLOG_DEBUG | MLOG_INOMAP, + "pruning non-dir ino %llu\n", + ino ); + oldstate = map_set( ino, MAP_NDR_NOCHNG ); + } else if ( mln_register( ino, statp->bs_nlink ) == 0 ) { + mlog( MLOG_DEBUG | MLOG_INOMAP, + "pruning non-dir ino %llu\n", + ino ); + oldstate = map_set( ino, MAP_NDR_NOCHNG ); + } + + if ( oldstate == MAP_DIR_CHANGE || oldstate == MAP_DIR_SUPPRT ){ + cb_dircnt--; + } else if ( oldstate == MAP_NDR_CHANGE ) { + cb_nondircnt--; + } + + return 0; +} + +static void +cb_accuminit_sz( void ) +{ + cb_datasz = 0; +} + +static void +cb_accuminit_ctx( void *inomap_state_contextp ) +{ + cb_inomap_state_contextp = inomap_state_contextp; +} + +/* used by inomap_build() to add up the dump space needed for + * all non-directory files. + */ +/* ARGSUSED */ +static intgen_t +cb_accumulate( void *arg1, + jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp ) +{ + register intgen_t state; + + ( *inomap_statdonep )++; + + /* skip if no links + */ + if ( statp->bs_nlink == 0 ) { + return 0; + } + + state = inomap_state( cb_inomap_state_contextp, statp->bs_ino ); + if ( state == MAP_NDR_CHANGE ) { + cb_datasz += estimate_dump_space( statp ); + } + + return 0; +} + +/* cb_spinit - initializes context for the startpoint calculation phase of + * inomap_build. cb_startptix is the index of the next startpoint to + * record. cb_incr is the dump space distance between each startpoint. + * cb_target is the target accum value for the next startpoint. + * cb_accum accumulates the dump space. + */ +static void +cb_spinit( void ) +{ + cb_startptix = 0; + cb_incr = cb_datasz / ( off64_t )cb_startptcnt; + cb_target = 0; /* so first ino will push us over the edge */ + cb_accum = 0; +} + +/* cb_startpt - called for each non-directory inode. accumulates the + * require dump space, and notes startpoints. encodes a heuristic for + * selecting startpoints. decides for each file whether to include it + * in the current stream, start a new stream beginning with that file, + * or split the file between the old and new streams. in the case of + * a split decision, always split at a BBSIZE boundary. + */ +#define TOO_SHY 1000000 /* max accept. accum short of target */ +#define TOO_BOLD 1000000 /* max accept. accum beyond target */ + +typedef enum { + HOLD, /* don't change */ + BUMP, /* set a new start point and put this file after it */ + SPLIT, /* set a new start point and split this file across it */ + YELL /* impossible condition; complain */ +} action_t; + +/* ARGSUSED */ +static intgen_t +cb_startpt( void *arg1, + jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp ) +{ + register intgen_t state; + + off64_t estimate; + off64_t old_accum = cb_accum; + off64_t qty; /* amount of a SPLIT file to skip */ + action_t action; + + ( *inomap_statdonep )++; + + /* skip if no links + */ + if ( statp->bs_nlink == 0 ) { + return 0; + } + + /* skip if not in inomap or not a non-dir + */ + state = inomap_state( cb_inomap_state_contextp, statp->bs_ino ); + if ( state != MAP_NDR_CHANGE ) { + return 0; + } + + ASSERT( cb_startptix < cb_startptcnt ); + + estimate = estimate_dump_space( statp ); + cb_accum += estimate; + + /* loop until no new start points found. loop is necessary + * to handle the pathological case of a huge file so big it + * spans several streams. + */ + action = ( action_t )HOLD; /* irrelevant, but demanded by lint */ + do { + /* decide what to do: hold, bump, or split. there are + * 8 valid cases to consider: + * 1) accum prior to this file is way too short of the + * target, and accum incl. this file is also shy: HOLD; + * 2) accum prior to this file is way too short of the + * target, and accum incl. this file is close to but + * still short of target: HOLD; + * 3) accum prior to this file is way too short of the + * target, and accum incl. this file is a little beyond + * the target: HOLD; + * 4) accum prior to this file is way too short of the + * target, and accum incl. this file is way beyond + * the target: SPLIT; + * 5) accum prior to this file is close to target, and + * accum incl. this file is still short of target: HOLD; + * 6) accum prior to this file is close to target, and + * accum incl. this file is a little beyond the target, + * and excluding this file would be less short of target + * than including it would be beyond the target: BUMP; + * 7) accum prior to this file is close to target, and + * accum incl. this file is a little beyond the target, + * and including this file would be less beyond target + * than excluding it would be short of target: HOLD; + * 8) accum prior to this file is close to target, and + * accum incl. this file is would be way beyond the + * target: HOLD. + */ + if ( cb_target - old_accum >= TOO_SHY ) { + if ( cb_target - cb_accum >= TOO_SHY ) { + action = ( action_t )HOLD; + } else if ( cb_accum <= cb_target ) { + action = ( action_t )HOLD; + } else if ( cb_accum - cb_target < TOO_BOLD ) { + action = ( action_t )HOLD; + } else { + action = ( action_t )SPLIT; + } + } else { + if ( cb_target - cb_accum >= TOO_SHY ) { + action = ( action_t )YELL; + } else if ( cb_accum < cb_target ) { + action = ( action_t )HOLD; + } else if ( cb_accum - cb_target < TOO_BOLD ) { + if ( cb_accum - cb_target >= + cb_target - old_accum ) { + action = ( action_t )BUMP; + } else { + action = ( action_t )HOLD; + } + } else { + action = ( action_t )BUMP; + } + } + + /* perform the action selected above + */ + switch ( action ) { + case ( action_t )HOLD: + break; + case ( action_t )BUMP: + cb_startptp->sp_ino = statp->bs_ino; + cb_startptp->sp_offset = 0; + cb_startptix++; + cb_startptp++; + cb_target += cb_incr; + if ( cb_startptix == cb_startptcnt ) { + return 1; /* done; abort the iteration */ + } + break; + case ( action_t )SPLIT: + cb_startptp->sp_ino = statp->bs_ino; + qty = ( cb_target - old_accum ) + & + ~( off64_t )( BBSIZE - 1 ); + cb_startptp->sp_offset = + quantity2offset( fshandlep, + statp, + qty ); + cb_startptix++; + cb_startptp++; + cb_target += cb_incr; + if ( cb_startptix == cb_startptcnt ) { + return 1; /* done; abort the iteration */ + } + break; + default: + ASSERT( 0 ); + return 1; + } + } while ( action == ( action_t )BUMP || action == ( action_t )SPLIT ); + + return 0; +} + +/* + * The converse on MACROBITS are the macros defined in inomap.h + */ +#ifndef OLDCODE +#ifndef MACROBITS +static void +SEG_ADD_BITS( seg_t *segp, xfs_ino_t ino, intgen_t state ) +{ + register xfs_ino_t relino; + register u_int64_t mask; + relino = ino - segp->base; + mask = ( u_int64_t )1 << relino; + switch( state ) { + case 0: + break; + case 1: + segp->lobits |= mask; + break; + case 2: + segp->mebits |= mask; + break; + case 3: + segp->lobits |= mask; + segp->mebits |= mask; + break; + case 4: + segp->hibits |= mask; + break; + case 5: + segp->lobits |= mask; + segp->hibits |= mask; + break; + case 6: + segp->mebits |= mask; + segp->hibits |= mask; + break; + case 7: + segp->lobits |= mask; + segp->mebits |= mask; + segp->hibits |= mask; + break; + } +} + +static void +SEG_SET_BITS( seg_t *segp, xfs_ino_t ino, intgen_t state ) +{ + register xfs_ino_t relino; + register u_int64_t mask; + register u_int64_t clrmask; + relino = ino - segp->base; + mask = ( u_int64_t )1 << relino; + clrmask = ~mask; + switch( state ) { + case 0: + segp->lobits &= clrmask; + segp->mebits &= clrmask; + segp->hibits &= clrmask; + break; + case 1: + segp->lobits |= mask; + segp->mebits &= clrmask; + segp->hibits &= clrmask; + break; + case 2: + segp->lobits &= clrmask; + segp->mebits |= mask; + segp->hibits &= clrmask; + break; + case 3: + segp->lobits |= mask; + segp->mebits |= mask; + segp->hibits &= clrmask; + break; + case 4: + segp->lobits &= clrmask; + segp->mebits &= clrmask; + segp->hibits |= mask; + break; + case 5: + segp->lobits |= mask; + segp->mebits &= clrmask; + segp->hibits |= mask; + break; + case 6: + segp->lobits &= clrmask; + segp->mebits |= mask; + segp->hibits |= mask; + break; + case 7: + segp->lobits |= mask; + segp->mebits |= mask; + segp->hibits |= mask; + break; + } +} + +static intgen_t +SEG_GET_BITS( seg_t *segp, xfs_ino_t ino ) +{ + intgen_t state; + register xfs_ino_t relino; + register u_int64_t mask; + relino = ino - segp->base; + mask = ( u_int64_t )1 << relino; + if ( segp->lobits & mask ) { + state = 1; + } else { + state = 0; + } + if ( segp->mebits & mask ) { + state |= 2; + } + if ( segp->hibits & mask ) { + state |= 4; + } + + return state; +} +#endif /* MACROBITS */ +#endif /* OLDCODE */ + +/* context for inomap construction - initialized by map_init + */ +static u_int64_t hnkcnt; +static u_int64_t segcnt; +static hnk_t *roothnkp; +static hnk_t *tailhnkp; +static seg_t *lastsegp; +static xfs_ino_t last_ino_added; + +/*DBGstatic void +showhnk( void ) +{ + int segix; + mlog( MLOG_NORMAL, "roothnkp == 0x%x\n", roothnkp ); + mlog( MLOG_NORMAL, "maxino == %llu\n", roothnkp->maxino ); + mlog( MLOG_NORMAL, "nextp == 0x%x\n", roothnkp->nextp ); + for ( segix = 0 ; segix < 2 ; segix++ ) { + mlog( MLOG_NORMAL, + "seg[%d] %llu 0x%llx 0x%llx 0x%llx\n", + segix, + roothnkp->seg[ segix ].base, + roothnkp->seg[ segix ].lobits, + roothnkp->seg[ segix ].mebits, + roothnkp->seg[ segix ].hibits ); + } +}*/ + +static void +map_init( void ) +{ + ASSERT( sizeof( hnk_t ) == HNKSZ ); + + roothnkp = 0; + hnkcnt = 0; + segcnt = 0; +} + +#ifdef SIZEEST +u_int64_t +inomap_getsz( void ) +{ + return hnkcnt * HNKSZ; +} +#endif /* SIZEEST */ + +/* called for every ino to be added to the map. assumes the ino in + * successive calls will be increasing monotonically. + */ +static void +map_add( xfs_ino_t ino, intgen_t state ) +{ + hnk_t *newtailp; + + if ( roothnkp == 0 ) { + roothnkp = ( hnk_t * )calloc( 1, sizeof( hnk_t )); + ASSERT( roothnkp ); + tailhnkp = roothnkp; + hnkcnt++; + lastsegp = &tailhnkp->seg[ 0 ]; + SEG_SET_BASE( lastsegp, ino ); + SEG_ADD_BITS( lastsegp, ino, state ); + tailhnkp->maxino = ino; + last_ino_added = ino; + segcnt++; + return; + } + + if (ino <= last_ino_added) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_INOMAP, + "map_add(%llu, %d): ino(%llu) <= last_ino(%llu)\n", + ino, state, ino, last_ino_added); + exit(EXIT_ERROR); + } + + if ( ino >= lastsegp->base + INOPERSEG ) { + lastsegp++; + if ( lastsegp >= tailhnkp->seg + SEGPERHNK ) { + ASSERT( lastsegp == tailhnkp->seg + SEGPERHNK ); + newtailp = ( hnk_t * )calloc( 1, sizeof( hnk_t )); + ASSERT( newtailp ); + tailhnkp->nextp = newtailp; + tailhnkp = newtailp; + hnkcnt++; + lastsegp = &tailhnkp->seg[ 0 ]; + } + SEG_SET_BASE( lastsegp, ino ); + segcnt++; + } + + SEG_ADD_BITS( lastsegp, ino, state ); + tailhnkp->maxino = ino; + last_ino_added = ino; +} + +/* map_getset - locates and gets the state of the specified ino, + * and optionally sets the state to a new value. + */ +static intgen_t +map_getset( xfs_ino_t ino, intgen_t newstate, bool_t setflag ) +{ + hnk_t *hnkp; + seg_t *segp; + + if ( ino > last_ino_added ) { + return MAP_INO_UNUSED; + } + for ( hnkp = roothnkp ; hnkp != 0 ; hnkp = hnkp->nextp ) { + if ( ino > hnkp->maxino ) { + continue; + } + for ( segp = hnkp->seg; segp < hnkp->seg + SEGPERHNK ; segp++ ){ + if ( hnkp == tailhnkp && segp > lastsegp ) { + return MAP_INO_UNUSED; + } + if ( ino < segp->base ) { + return MAP_INO_UNUSED; + } + if ( ino < segp->base + INOPERSEG ) { + intgen_t state; +#ifdef MACROBITS + SEG_GET_BITS( segp, ino, state ); +#else /* MACROBITS */ + state = SEG_GET_BITS( segp, ino ); +#endif /* MACROBITS */ + if ( setflag ) { + SEG_SET_BITS( segp, ino, newstate ); + } + return state; + } + } + return MAP_INO_UNUSED; + } + return MAP_INO_UNUSED; +} + +static intgen_t +map_get( xfs_ino_t ino ) +{ + return map_getset( ino, MAP_INO_UNUSED, BOOL_FALSE ); +} + +static intgen_t +map_set( xfs_ino_t ino, intgen_t state ) +{ + intgen_t oldstate; + + oldstate = map_getset( ino, state, BOOL_TRUE ); + return oldstate; +} + +/* returns the map state of the specified ino. optimized for monotonically + * increasing ino argument in successive calls. caller must supply context, + * since this may be called from several threads. + */ +struct inomap_state_context { + hnk_t *currhnkp; + seg_t *currsegp; + xfs_ino_t last_ino_requested; + size64_t backupcnt; +}; + +typedef struct inomap_state_context inomap_state_context_t; + +void * +inomap_state_getcontext( void ) +{ + inomap_state_context_t *cp; + cp = ( inomap_state_context_t * ) + calloc( 1, sizeof( inomap_state_context_t )); + ASSERT( cp ); + ASSERT( roothnkp ); + + cp->currhnkp = roothnkp; + cp->currsegp = roothnkp->seg; + + return ( void * )cp; +} + +intgen_t +inomap_state( void *p, xfs_ino_t ino ) +{ + register inomap_state_context_t *cp = ( inomap_state_context_t * )p; + register intgen_t state; + + /* if we go backwards, re-initialize the context + */ + if( ino <= cp->last_ino_requested ) { + ASSERT( roothnkp ); + cp->currhnkp = roothnkp; + cp->currsegp = roothnkp->seg; + cp->backupcnt++; + } + cp->last_ino_requested = ino; + + if ( cp->currhnkp == 0 ) { + return MAP_INO_UNUSED; + } + + if ( ino > last_ino_added ) { + return MAP_INO_UNUSED; + } + + while ( ino > cp->currhnkp->maxino ) { + cp->currhnkp = cp->currhnkp->nextp; + ASSERT( cp->currhnkp ); + cp->currsegp = cp->currhnkp->seg; + } + while ( ino >= cp->currsegp->base + INOPERSEG ) { + cp->currsegp++; + if ( cp->currsegp >= cp->currhnkp->seg + SEGPERHNK ) { + ASSERT( 0 ); /* can't be here! */ + return MAP_INO_UNUSED; + } + } + + if ( ino < cp->currsegp->base ) { + return MAP_INO_UNUSED; + } + +#ifdef MACROBITS + SEG_GET_BITS( cp->currsegp, ino, state ); +#else /* MACROBITS */ + state = SEG_GET_BITS( cp->currsegp, ino ); +#endif /* MACROBITS */ + return state; +} + +void +inomap_state_postaccum( void *p ) +{ + register inomap_state_context_t *cp = ( inomap_state_context_t * )p; + + mlog( MLOG_DEBUG | MLOG_INOMAP, + "inomap_state backed up %llu times\n", + cp->backupcnt ); + cp->backupcnt = 0; +} + +void +inomap_state_freecontext( void *p ) +{ + free( p ); +} + +void +inomap_writehdr( content_inode_hdr_t *scwhdrp ) +{ + ASSERT( roothnkp ); + + /* update the inomap info in the content header + */ + scwhdrp->cih_inomap_hnkcnt = hnkcnt; + scwhdrp->cih_inomap_segcnt = segcnt; + scwhdrp->cih_inomap_dircnt = ( u_int64_t )cb_dircnt; + scwhdrp->cih_inomap_nondircnt = ( u_int64_t )cb_nondircnt; + scwhdrp->cih_inomap_firstino = roothnkp->seg[ 0 ].base; + scwhdrp->cih_inomap_lastino = last_ino_added; + scwhdrp->cih_inomap_datasz = ( u_int64_t )cb_datasz; +} + +rv_t +inomap_dump( drive_t *drivep ) +{ + hnk_t *hnkp; + hnk_t tmphnkp; + + /* use write_buf to dump the hunks + */ + for ( hnkp = roothnkp ; hnkp != 0 ; hnkp = hnkp->nextp ) { + intgen_t rval; + rv_t rv; + drive_ops_t *dop = drivep->d_opsp; + + xlate_hnk(hnkp, &tmphnkp, 1); + rval = write_buf( ( char * )&tmphnkp, + sizeof( tmphnkp ), + ( void * )drivep, + ( gwbfp_t )dop->do_get_write_buf, + ( wfp_t )dop->do_write ); + switch ( rval ) { + case 0: + rv = RV_OK; + break; + case DRIVE_ERROR_MEDIA: + case DRIVE_ERROR_EOM: + rv = RV_EOM; + break; + case DRIVE_ERROR_EOF: + rv = RV_EOF; + break; + case DRIVE_ERROR_DEVICE: + rv = RV_DRIVE; + break; + case DRIVE_ERROR_CORE: + default: + rv = RV_CORE; + break; + } + if ( rv != RV_OK ) { + return rv; + } + } + + return RV_OK; +} + +#ifdef NOTUSED +bool_t +inomap_iter_cb( void *contextp, + intgen_t statemask, + bool_t ( *funcp )( void *contextp, + xfs_ino_t ino, + intgen_t state )) +{ + hnk_t *hnkp; + + ASSERT( ! ( statemask & ( 1 << MAP_INO_UNUSED ))); + + for ( hnkp = roothnkp ; hnkp != 0 ; hnkp = hnkp->nextp ) { + seg_t *segp = hnkp->seg; + seg_t *endsegp = hnkp->seg + SEGPERHNK; + for ( ; segp < endsegp ; segp++ ) { + xfs_ino_t ino; + xfs_ino_t endino; + + if ( hnkp == tailhnkp && segp > lastsegp ) { + return BOOL_TRUE; + } + ino = segp->base; + endino = segp->base + INOPERSEG; + for ( ; ino < endino ; ino++ ) { + intgen_t st; +#ifdef MACROBITS + SEG_GET_BITS( segp, ino, st ); +#else /* MACROBITS */ + st = SEG_GET_BITS( segp, ino ); +#endif /* MACROBITS */ + if ( statemask & ( 1 << st )) { + bool_t ok; + ok = ( * funcp )( contextp, ino, st ); + if ( ! ok ) { + return BOOL_FALSE; + } + } + } + } + } + + /* should not get here + */ + ASSERT( 0 ); + return BOOL_FALSE; +} +#endif /* NOTUSED */ + +/* mln - the list of ino's pruned but linked to more than one directory. + * each time one of those is pruned, increment the cnt for that ino in + * this list. when the seen cnt equals the link count, the ino can + * be pruned. + */ +struct mln { + xfs_ino_t ino; + nlink_t cnt; +}; + +typedef struct mln mln_t; + +#define MLNGRPSZ PGSZ +#define MLNGRPLEN ( ( PGSZ / sizeof( mln_t )) - 1 ) + +struct mlngrp { + mln_t grp[ MLNGRPLEN ]; + struct mlngrp *nextp; + char pad1[ MLNGRPSZ + - + MLNGRPLEN * sizeof( mln_t ) + - + sizeof( struct mlngrp * ) ]; +}; + +typedef struct mlngrp mlngrp_t; + +static mlngrp_t *mlngrprootp; +static mlngrp_t *mlngrpnextp; +static mln_t *mlnnextp; + +static void +mln_init( void ) +{ + ASSERT( sizeof( mlngrp_t ) == MLNGRPSZ ); + + mlngrprootp = ( mlngrp_t * )calloc( 1, sizeof( mlngrp_t )); + ASSERT( mlngrprootp ); + mlngrpnextp = mlngrprootp; + mlnnextp = &mlngrpnextp->grp[ 0 ]; +} + +/* finds and increments the mln count for the ino. + * returns nlink minus number of nlink_register calls made so + * far for this ino, including the current call: hence returns + * zero if all links seen. + */ +static nlink_t +mln_register( xfs_ino_t ino, nlink_t nlink ) +{ + mlngrp_t *grpp; + mln_t *mlnp; + + /* first see if ino already registered + */ + for ( grpp = mlngrprootp ; grpp != 0 ; grpp = grpp->nextp ) { + for ( mlnp = grpp->grp; mlnp < grpp->grp + MLNGRPLEN; mlnp++ ){ + if ( mlnp == mlnnextp ) { + mlnnextp->ino = ino; + mlnnextp->cnt = 0; + mlnnextp++; + if ( mlnnextp >= mlngrpnextp->grp + MLNGRPLEN){ + mlngrpnextp->nextp = ( mlngrp_t * ) + calloc( 1, sizeof( mlngrp_t)); + ASSERT( mlngrpnextp->nextp ); + mlngrpnextp = mlngrpnextp->nextp; + mlnnextp = &mlngrpnextp->grp[ 0 ]; + } + } + if ( mlnp->ino == ino ) { + mlnp->cnt++; + ASSERT( nlink >= mlnp->cnt ); + return ( nlink - mlnp->cnt ); + } + } + } + /* should never get here: loops terminated by mlnnextp + */ + ASSERT( 0 ); + return 0; +} + +static void +mln_free( void ) +{ + mlngrp_t *p; + + p = mlngrprootp; + while ( p ) { + mlngrp_t *oldp = p; + p = p->nextp; + free( ( void * )oldp ); + } +} + +/* the subtreelist is simply the ino's of the elements of each of the + * subtree pathnames in subtreebuf. the list needs to be arranged + * in a way advantageous for searching. + */ +#define INOGRPSZ PGSZ +#define INOGRPLEN (( PGSZ / sizeof( xfs_ino_t )) - 1 ) + +struct inogrp { + xfs_ino_t grp[ INOGRPLEN ]; + struct inogrp *nextp; + char pad[ sizeof( xfs_ino_t ) - sizeof( struct inogrp * ) ]; +}; + +typedef struct inogrp inogrp_t; + +static inogrp_t *inogrprootp; +static inogrp_t *nextgrpp; +static xfs_ino_t *nextinop; +static char *currentpath; + +static bool_t +subtreelist_parse( jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *rootstatp, + char *subtreebuf[], + ix_t subtreecnt ) +{ + ix_t subtreeix; + + ASSERT( sizeof( inogrp_t ) == INOGRPSZ ); + + /* initialize the list; it will be added to by the + * callback; + */ + inogrprootp = ( inogrp_t * )calloc( 1, sizeof( inogrp_t )); + ASSERT( inogrprootp ); + nextgrpp = inogrprootp; + nextinop = &nextgrpp->grp[ 0 ]; + + /* add the root ino to the subtree list + */ + subtreelist_add( rootstatp->bs_ino ); + + /* do a recursive descent for each subtree specified + */ + for ( subtreeix = 0 ; subtreeix < subtreecnt ; subtreeix++ ) { + intgen_t cbrval = 0; + currentpath = subtreebuf[ subtreeix ]; + ASSERT( *currentpath != '/' ); + ( void )diriter( fshandlep, + fsfd, + rootstatp, + subtreelist_parse_cb, + ( void * )currentpath, + &cbrval, + cb_getdentbufp, + cb_getdentbufsz ); + if ( cbrval != 1 ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_INOMAP, + "%s: %s\n", + cbrval == 0 ? "subtree not present" + : "invalid subtree specified", + currentpath ); + return BOOL_FALSE; + } + } + + return BOOL_TRUE; +} + +static void +subtreelist_add( xfs_ino_t ino ) +{ + *nextinop++ = ino; + if ( nextinop >= nextgrpp->grp + INOGRPLEN ) { + ASSERT( nextinop == nextgrpp->grp + INOGRPLEN ); + nextgrpp->nextp = ( inogrp_t * )calloc( 1, sizeof( inogrp_t )); + ASSERT( nextgrpp->nextp ); + nextgrpp = nextgrpp->nextp; + nextinop = &nextgrpp->grp[ 0 ]; + } +} + +/* for debugger work only +static void +subtreelist_print( void ) +{ + inogrp_t *grpp = inogrprootp; + xfs_ino_t *inop = &grpp->grp[ 0 ]; + + while ( inop != nextinop ) { + printf( "%llu\n", *inop ); + inop++; + if ( inop >= grpp->grp + INOGRPLEN ) { + ASSERT( inop == grpp->grp + INOGRPLEN ); + grpp = grpp->nextp; + ASSERT( grpp ); + inop = &grpp->grp[ 0 ]; + } + } +} + */ + +static bool_t +subtreelist_contains( xfs_ino_t ino ) +{ + inogrp_t *grpp; + xfs_ino_t *inop; + + for ( grpp = inogrprootp ; grpp != 0 ; grpp = grpp->nextp ) { + for ( inop = grpp->grp; inop < grpp->grp + INOGRPLEN; inop++ ) { + if ( inop == nextinop ) { + return BOOL_FALSE; + } + if ( *inop == ino ) { + return BOOL_TRUE; + } + } + } + /* should never get here; loops terminated by nextinop + */ + ASSERT( 0 ); + return BOOL_FALSE; +} + +static void +subtreelist_free( void ) +{ + inogrp_t *p; + + p = inogrprootp; + while ( p ) { + inogrp_t *oldp = p; + p = p->nextp; + free( ( void * )oldp ); + } +} + +static intgen_t +subtreelist_parse_cb( void *arg1, + jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *statp, + char *name ) +{ + intgen_t cbrval = 0; + + /* arg1 is used to carry the tail of the subtree path + */ + char *subpath = ( char * )arg1; + + /* temporarily terminate the subpath at the next slash + */ + char *nextslash = strchr( subpath, '/' ); + if ( nextslash ) { + *nextslash = 0; + } + + /* if the first element of the subpath doesn't match this + * directory entry, try the next entry. + */ + if ( strcmp( subpath, name )) { + if ( nextslash ) { + *nextslash = '/'; + } + return 0; + } + + /* it matches, so add ino to list and continue down the path + */ + subtreelist_add( statp->bs_ino ); + + /* if we've reached the end of the path, abort the iteration + * in a successful way. + */ + if ( ! nextslash ) { + return 1; + } + + /* if we're not at the end of the path, yet the current + * path element is not a directory, complain and abort the + * iteration in a way which terminates the application + */ + if ( ( statp->bs_mode & S_IFMT ) != S_IFDIR ) { + *nextslash = '/'; + return 2; + } + + /* repair the subpath + */ + *nextslash = '/'; + + /* peel the first element of the subpath and recurse + */ + ( void )diriter( fshandlep, + fsfd, + statp, + subtreelist_parse_cb, + ( void * )( nextslash + 1 ), + &cbrval, + 0, + 0 ); + return cbrval; +} + +/* uses the extent map to figure the first offset in the file + * with qty real (non-hole) bytes behind it + */ +#define BMAP_LEN 512 + +static off64_t +quantity2offset( jdm_fshandle_t *fshandlep, xfs_bstat_t *statp, off64_t qty ) +{ + intgen_t fd; + getbmapx_t bmap[ BMAP_LEN ]; + off64_t offset; + off64_t offset_next; + off64_t qty_accum; + +#ifdef DMEXTATTR + /* If GETOPT_DUMPASOFFLINE was specified and the HSM provided an + * estimate, then use it. + */ + + if (hsm_fs_ctxtp) { + if (HsmEstimateFileOffset(hsm_fs_ctxtp, statp, qty, &offset)) + return offset; + } +#endif /* DMEXTATTR */ + + offset = 0; + offset_next = 0; + qty_accum = 0; + bmap[ 0 ].bmv_offset = 0; + bmap[ 0 ].bmv_length = -1; + bmap[ 0 ].bmv_count = BMAP_LEN; + bmap[ 0 ].bmv_iflags = BMV_IF_NO_DMAPI_READ; + bmap[ 0 ].bmv_entries = -1; + fd = jdm_open( fshandlep, statp, O_RDONLY ); + if ( fd < 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_INOMAP, + "could not open ino %llu to read extent map: %s\n", + statp->bs_ino, + strerror( errno )); + return 0; + } + + for ( ; ; ) { + intgen_t eix; + intgen_t rval; + + rval = ioctl( fd, XFS_IOC_GETBMAPX, bmap ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_INOMAP, + "could not read extent map for ino %llu: %s\n", + statp->bs_ino, + strerror( errno )); + ( void )close( fd ); + return 0; + } + + if ( bmap[ 0 ].bmv_entries <= 0 ) { + ASSERT( bmap[ 0 ].bmv_entries == 0 ); + ( void )close( fd ); + return offset_next; + } + + for ( eix = 1 ; eix <= bmap[ 0 ].bmv_entries ; eix++ ) { + getbmapx_t *bmapp = &bmap[ eix ]; + off64_t qty_new; + if ( bmapp->bmv_block == -1 ) { + continue; /* hole */ + } + offset = bmapp->bmv_offset * BBSIZE; + qty_new = qty_accum + bmapp->bmv_length * BBSIZE; + if ( qty_new >= qty ) { + ( void )close( fd ); + return offset + ( qty - qty_accum ); + } + offset_next = offset + bmapp->bmv_length * BBSIZE; + qty_accum = qty_new; + } + } + /* NOTREACHED */ +} + + +static off64_t +estimate_dump_space( xfs_bstat_t *statp ) +{ + switch ( statp->bs_mode & S_IFMT ) { + case S_IFREG: + /* very rough: must improve this. If GETOPT_DUMPASOFFLINE was + * specified and the HSM provided an estimate, then use it. + */ +#ifdef DMEXTATTR + if (hsm_fs_ctxtp) { + off64_t bytes; + + if (HsmEstimateFileSpace(hsm_fs_ctxtp, statp, &bytes)) + return bytes; + } +#endif /* DMEXTATTR */ + return statp->bs_blocks * ( off64_t )statp->bs_blksize; + case S_IFIFO: + case S_IFCHR: + case S_IFDIR: +#ifdef S_IFNAM + case S_IFNAM: +#endif + case S_IFBLK: + case S_IFSOCK: + case S_IFLNK: + /* not yet + case S_IFUUID: + */ + return 0; + default: + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_INOMAP, + "unknown inode type: ino=%llu, mode=0x%04x 0%06o\n", + statp->bs_ino, + statp->bs_mode, + statp->bs_mode ); + return 0; + } +} diff -rNu linux-2.4.7/cmd/xfsdump/dump/inomap.h linux-2.4-xfs/cmd/xfsdump/dump/inomap.h --- linux-2.4.7/cmd/xfsdump/dump/inomap.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/dump/inomap.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef INOMAP_H +#define INOMAP_H + +/* inomap.[hc] - inode map abstraction + * + * an inode map describes the inode numbers (inos) in a file system dump. + * the map identifies which inos are in-use by the fs, which of those are + * directories, and which are dumped. + * + * the map is represented as a list of map segments. a map segment is + * a 64-bit starting ino and two 64-bit bitmaps. the bitmaps describe + * the 64 inos beginning with the starting ino. two bits are available + * for each ino. + */ + +/* inomap_build - this function allocates and constructs an in-memory + * representation of the bitmap. it prunes from the map inos of files not + * changed since the last dump, inos not identified by the subtree list, + * and directories not needed to represent a hierarchy containing + * changed inodes. it handles hard links; a file linked to multiple + * directory entries will not be pruned if at least one of those + * directories has an ancestor in the subtree list. + * + * it returns by reference an array of startpoints in the non-directory + * portion of the dump, as well as the count of dir and nondir inos + * makred as present and to be dumped. A startpoint identifies a non-dir ino, + * and a non-hole accumulated size position within that file. only very large + * files will contain a startpoint; in all other cases the startpoints will + * fall at file boundaries. returns BOOL_FALSE if error encountered (should + * abort the dump; else returns BOOL_TRUE. + */ +extern bool_t inomap_build( jdm_fshandle_t *fshandlep, + intgen_t fsfd, + xfs_bstat_t *rootstatp, + bool_t last, + time_t lasttime, + bool_t resume, + time_t resumetime, + size_t resumerangecnt, + drange_t *resumerangep, + char *subtreebuf[], + ix_t subtreecnt, + startpt_t startptp[], + size_t startptcnt, + ix_t *statphasep, + ix_t *statpassp, + size64_t statcnt, + size64_t *statdonep ); + +#ifdef SIZEEST +extern u_int64_t inomap_getsz( void ); +#endif /* SIZEEST */ + +/* inomap_skip - tell inomap about inodes to skip in the dump + */ +extern void inomap_skip( xfs_ino_t ino ); + + +/* inomap_writehdr - updates the write header with inomap-private info + * to be communicated to the restore side + */ +extern void inomap_writehdr( content_inode_hdr_t *scwhdrp ); + + +/* inomap_dump - dumps the map to media - content-abstraction-knowledgable + * + * returns error from media write op + */ +extern rv_t inomap_dump( drive_t *drivep ); + + +/* map state values + */ +#define MAP_INO_UNUSED 0 /* ino not in use by fs */ +#define MAP_DIR_NOCHNG 1 /* dir, ino in use by fs, but not dumped */ +#define MAP_NDR_NOCHNG 2 /* non-dir, ino in use by fs, but not dumped */ +#define MAP_DIR_CHANGE 3 /* dir, changed since last dump */ +#define MAP_NDR_CHANGE 4 /* non-dir, changed since last dump */ +#define MAP_DIR_SUPPRT 5 /* dir, unchanged but needed for hierarchy */ +#define MAP_RESERVED1 6 /* this state currently not used */ +#define MAP_RESERVED2 7 /* this state currently not used */ + + +/* map context and operators + */ + +/* the inomap is implimented as a linked list of chunks. each chunk contains + * an array of map segments. a map segment contains a start ino and a + * bitmap of 64 3-bit state values (see MAP_... in inomap.h). the SEG_macros + * index and manipulate the 3-bit state values. + */ +struct seg { + xfs_ino_t base; + u_int64_t lobits; + u_int64_t mebits; + u_int64_t hibits; +}; + +typedef struct seg seg_t; + +#define SEG_SET_BASE( segp, ino ) \ + { \ + segp->base = ino; \ + } + +#ifdef OLDCODE +#define SEG_ADD_BITS( segp, ino, state ) \ + { \ + register xfs_ino_t relino; \ + relino = ino - segp->base; \ + segp->lobits |= ( u_int64_t )( ( state >> 0 ) & 1 ) << relino; \ + segp->mebits |= ( u_int64_t )( ( state >> 1 ) & 1 ) << relino; \ + segp->hibits |= ( u_int64_t )( ( state >> 2 ) & 1 ) << relino; \ + } + +#define SEG_SET_BITS( segp, ino, state ) \ + { \ + register xfs_ino_t relino; \ + register u_int64_t clrmask; \ + relino = ino - segp->base; \ + clrmask = ~( ( u_int64_t )1 << relino ); \ + segp->lobits &= clrmask; \ + segp->mebits &= clrmask; \ + segp->hibits &= clrmask; \ + segp->lobits |= ( u_int64_t )( ( state >> 0 ) & 1 ) << relino; \ + segp->mebits |= ( u_int64_t )( ( state >> 1 ) & 1 ) << relino; \ + segp->hibits |= ( u_int64_t )( ( state >> 2 ) & 1 ) << relino; \ + } + +#define SEG_GET_BITS( segp, ino, state ) \ + { \ + register xfs_ino_t relino; \ + relino = ino - segp->base; \ + state = 0; \ + state |= ( intgen_t )((( segp->lobits >> relino ) & 1 ) * 1 );\ + state |= ( intgen_t )((( segp->mebits >> relino ) & 1 ) * 2 );\ + state |= ( intgen_t )((( segp->hibits >> relino ) & 1 ) * 4 );\ + } +#else /* OLDCODE */ +/* + * The converse on MACROBITS are the functions defined in inomap.c + */ +#ifdef MACROBITS +#define SEG_ADD_BITS( segp, ino, state ) \ + { \ + register xfs_ino_t relino; \ + register u_int64_t mask; \ + relino = ino - segp->base; \ + mask = ( u_int64_t )1 << relino; \ + switch( state ) { \ + case 0: \ + break; \ + case 1: \ + segp->lobits |= mask; \ + break; \ + case 2: \ + segp->mebits |= mask; \ + break; \ + case 3: \ + segp->lobits |= mask; \ + segp->mebits |= mask; \ + break; \ + case 4: \ + segp->hibits |= mask; \ + break; \ + case 5: \ + segp->lobits |= mask; \ + segp->hibits |= mask; \ + break; \ + case 6: \ + segp->mebits |= mask; \ + segp->hibits |= mask; \ + break; \ + case 7: \ + segp->lobits |= mask; \ + segp->mebits |= mask; \ + segp->hibits |= mask; \ + break; \ + } \ + } + +#define SEG_SET_BITS( segp, ino, state ) \ + { \ + register xfs_ino_t relino; \ + register u_int64_t mask; \ + register u_int64_t clrmask; \ + relino = ino - segp->base; \ + mask = ( u_int64_t )1 << relino; \ + clrmask = ~mask; \ + switch( state ) { \ + case 0: \ + segp->lobits &= clrmask; \ + segp->mebits &= clrmask; \ + segp->hibits &= clrmask; \ + break; \ + case 1: \ + segp->lobits |= mask; \ + segp->mebits &= clrmask; \ + segp->hibits &= clrmask; \ + break; \ + case 2: \ + segp->lobits &= clrmask; \ + segp->mebits |= mask; \ + segp->hibits &= clrmask; \ + break; \ + case 3: \ + segp->lobits |= mask; \ + segp->mebits |= mask; \ + segp->hibits &= clrmask; \ + break; \ + case 4: \ + segp->lobits &= clrmask; \ + segp->mebits &= clrmask; \ + segp->hibits |= mask; \ + break; \ + case 5: \ + segp->lobits |= mask; \ + segp->mebits &= clrmask; \ + segp->hibits |= mask; \ + break; \ + case 6: \ + segp->lobits &= clrmask; \ + segp->mebits |= mask; \ + segp->hibits |= mask; \ + break; \ + case 7: \ + segp->lobits |= mask; \ + segp->mebits |= mask; \ + segp->hibits |= mask; \ + break; \ + } \ + } + +#define SEG_GET_BITS( segp, ino, state ) \ + { \ + register xfs_ino_t relino; \ + register u_int64_t mask; \ + relino = ino - segp->base; \ + mask = ( u_int64_t )1 << relino; \ + if ( segp->lobits & mask ) { \ + state = 1; \ + } else { \ + state = 0; \ + } \ + if ( segp->mebits & mask ) { \ + state |= 2; \ + } \ + if ( segp->hibits & mask ) { \ + state |= 4; \ + } \ + } +#endif /* MACROBITS */ +#endif /* OLDCODE */ + +#define INOPERSEG ( sizeof( (( seg_t * )0 )->lobits ) * NBBY ) + +#define HNKSZ ( 4 * PGSZ ) +#define SEGPERHNK ( ( HNKSZ / sizeof( seg_t )) - 1 ) + +struct hnk { + seg_t seg[ SEGPERHNK ]; + xfs_ino_t maxino; + struct hnk *nextp; + char pad[sizeof( seg_t ) - sizeof( xfs_ino_t ) - sizeof( struct hnk * )]; +}; + +typedef struct hnk hnk_t; + + +/* inomap_state - returns the map state of the given ino. + * highly optimized for monotonically increasing arguments to + * successive calls. requires a pointer to a context block, obtained from + * inomap_state_getcontext(), and released by inomap_state_freecontext(). + */ +extern void *inomap_state_getcontext( void ); +extern intgen_t inomap_state( void *contextp, xfs_ino_t ino ); +extern void inomap_state_freecontext( void *contextp ); +void inomap_state_postaccum( void *p ); + + +#ifdef NOTUSED +/* inomap_iter_cb - will call the supplied function for each ino in + * the map matching a state in the state mask. if the callback returns + * FALSE, the iteration will be aborted and inomap_iter_cb() will + * return FALSE. the state mask is constructed by OR'ing bits in bit + * positions corresponding to the state values. + */ +extern bool_t inomap_iter_cb( void *contextp, + intgen_t statemask, + bool_t ( *funcp )( void *contextp, + xfs_ino_t ino, + intgen_t state )); +#endif /* NOTUSED */ + +#endif /* INOMAP_H */ diff -rNu linux-2.4.7/cmd/xfsdump/dump/var.c linux-2.4-xfs/cmd/xfsdump/dump/var.c --- linux-2.4.7/cmd/xfsdump/dump/var.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/dump/var.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include + +#include "types.h" +#include "fs.h" +#include "openutil.h" +#include "mlog.h" + +#define VAR_PATH "/var" +#define VAR_MODE 0755 +#define VAR_OWNER 0 +#define VAR_GROUP 0 + +#define XFSDUMP_PATH "/var/xfsdump" +#define XFSDUMP_MODE 0755 +#define XFSDUMP_OWNER 0 +#define XFSDUMP_GROUP 0 + +static char *var_path = VAR_PATH; +static char *xfsdump_path = XFSDUMP_PATH; + +static void var_skip_recurse( char *, void ( * )( xfs_ino_t )); + +void +var_create( void ) +{ + intgen_t rval; + + mlog( MLOG_DEBUG, + "creating directory %s\n", + XFSDUMP_PATH ); + + /* first make /var + */ + rval = mkdir( var_path, VAR_MODE ); + if ( rval && errno != EEXIST ) { + mlog( MLOG_NORMAL, + "unable to create %s: %s\n", + var_path, + strerror( errno )); + return; + } + if ( rval == 0 ) { + rval = chown( var_path, VAR_OWNER, VAR_GROUP ); + if ( rval ) { + mlog( MLOG_NORMAL, + "unable to chmown %s: %s\n", + var_path, + strerror( errno )); + } + } + + /* next make /var/xfsdump + */ + rval = mkdir( xfsdump_path, XFSDUMP_MODE ); + if ( rval && errno != EEXIST ) { + mlog( MLOG_NORMAL, + "unable to create %s: %s\n", + xfsdump_path, + strerror( errno )); + return; + } + if ( rval == 0 ) { + rval = chown( xfsdump_path, XFSDUMP_OWNER, XFSDUMP_GROUP ); + if ( rval ) { + mlog( MLOG_NORMAL, + "unable to chmown %s: %s\n", + xfsdump_path, + strerror( errno )); + } + } +} + + +void +var_skip( uuid_t *dumped_fsidp, void ( *cb )( xfs_ino_t ino )) +{ + uuid_t fsid; + intgen_t rval; + + /* see if the fs uuid's match + */ + rval = fs_getid( var_path, &fsid ); + if ( rval ) { +#ifdef HIDDEN + /* NOTE: this will happen for non-XFS file systems */ + /* and is expected, so no msg */ + mlog( MLOG_NORMAL, + "unable to determine uuid of fs containing %s: " + "%s\n", + var_path, + strerror( errno )); +#endif + return; + } + + if ( uuid_compare( *dumped_fsidp, fsid ) != 0) { + return; + } + + /* traverse the xfsdump directory, getting inode numbers of it + * and all of its children, and reporting those to the callback. + */ + var_skip_recurse( xfsdump_path, cb ); +} + +static void +var_skip_recurse( char *base, void ( *cb )( xfs_ino_t ino )) +{ + struct stat64 statbuf; + DIR *dirp; + struct dirent *direntp; + intgen_t rval; + + rval = lstat64( base, &statbuf ); + if ( rval ) { + mlog( MLOG_NORMAL, + "unable to get status of %s: %s\n", + base, + strerror( errno )); + return; + } + + mlog( MLOG_DEBUG, + "excluding %s from dump\n", + base ); + + ( * cb )( statbuf.st_ino ); + + if ( ( statbuf.st_mode & S_IFMT ) != S_IFDIR ) { + return; + } + + dirp = opendir( base ); + if ( ! dirp ) { + mlog( MLOG_NORMAL, + "unable to open directory %s\n", + base ); + return; + } + + while ( ( direntp = readdir( dirp )) != NULL ) { + char *path; + + /* skip "." and ".." + */ + if ( *( direntp->d_name + 0 ) == '.' + && + ( *( direntp->d_name + 1 ) == 0 + || + ( *( direntp->d_name + 1 ) == '.' + && + *( direntp->d_name + 2 ) == 0 ))) { + continue; + } + + path = open_pathalloc( base, direntp->d_name, 0 ); + var_skip_recurse( path, cb ); + free( ( void * )path ); + } + + closedir( dirp ); +} diff -rNu linux-2.4.7/cmd/xfsdump/dump/var.h linux-2.4-xfs/cmd/xfsdump/dump/var.h --- linux-2.4.7/cmd/xfsdump/dump/var.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/dump/var.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef VAR_H +#define VAR_H + +/* var.[ch] - abstraction dealing with /var/xfsdump/ + */ + +extern void var_create( void ); + +extern void var_skip( uuid_t *dumped_fsidp, void ( *cb )( xfs_ino_t ino )); + +#endif /* VAR_H */ diff -rNu linux-2.4.7/cmd/xfsdump/estimate/CVS/Entries linux-2.4-xfs/cmd/xfsdump/estimate/CVS/Entries --- linux-2.4.7/cmd/xfsdump/estimate/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/estimate/CVS/Entries Thu Jul 5 11:44:03 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Mon Jan 15 04:32:19 2001/-ko/ +/xfs_estimate.c/1.1/Mon Jan 15 04:10:30 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/estimate/CVS/Repository linux-2.4-xfs/cmd/xfsdump/estimate/CVS/Repository --- linux-2.4.7/cmd/xfsdump/estimate/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/estimate/CVS/Repository Thu Jul 5 11:44:03 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/estimate diff -rNu linux-2.4.7/cmd/xfsdump/estimate/CVS/Root linux-2.4-xfs/cmd/xfsdump/estimate/CVS/Root --- linux-2.4.7/cmd/xfsdump/estimate/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/estimate/CVS/Root Thu Jul 5 11:44:03 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/estimate/Makefile linux-2.4-xfs/cmd/xfsdump/estimate/Makefile --- linux-2.4.7/cmd/xfsdump/estimate/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/estimate/Makefile Sun Jan 14 22:32:19 2001 @@ -0,0 +1,46 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = xfs_estimate +CFILES = xfs_estimate.c + +default: $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_BIN_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/xfsdump/estimate/xfs_estimate.c linux-2.4-xfs/cmd/xfsdump/estimate/xfs_estimate.c --- linux-2.4.7/cmd/xfsdump/estimate/xfs_estimate.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/estimate/xfs_estimate.c Sun Jan 14 22:10:30 2001 @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Estimate space of an XFS filesystem + */ +#include +#include +#include + +unsigned long long +cvtnum(char *s) +{ + unsigned long long i; + char *sp; + + i = strtoll(s, &sp, 0); + if (i == 0 && sp == s) + return 0LL; + if (*sp == '\0') + return i; + if (*sp =='k' && sp[1] == '\0') + return 1024LL * i; + if (*sp =='m' && sp[1] == '\0') + return 1024LL * 1024LL * i; + if (*sp =='g' && sp[1] == '\0') + return 1024LL * 1024LL * 1024LL * i; + return 0LL; +} + +int ffn(const char *, const struct stat64 *, int, struct FTW *); + +#define BLOCKSIZE 4096 +#define INODESIZE 256 +#define PERDIRENTRY \ + (sizeof(xfs_dir_leaf_entry_t) + sizeof(xfs_dir_leaf_name_t)) +#define LOGSIZE 1000 + +#define FBLOCKS(n) ((n)/blocksize) +#define RFBYTES(n) ((n) - (FBLOCKS(n) * blocksize)) + +unsigned long long dirsize=0; /* bytes */ +unsigned long long logsize=LOGSIZE*BLOCKSIZE; /* bytes */ +unsigned long long fullblocks=0; /* FS blocks */ +unsigned long long isize=0; /* inodes bytes */ +unsigned long long blocksize=BLOCKSIZE; +unsigned long long nslinks=0; /* number of symbolic links */ +unsigned long long nfiles=0; /* number of regular files */ +unsigned long long ndirs=0; /* number of directories */ +unsigned long long nspecial=0; /* number of special files */ +unsigned long long verbose=0; /* verbose mode TRUE/FALSE */ + +int __debug = 0; +int ilog = 0; +int elog = 0; + +void +usage(char *progname) +{ + fprintf(stderr, "Usage: %s [opts] directory [directory ...]\n\ +\t-b blocksize (fundamental filesystem blocksize)\n\ +\t-i logsize (internal log size)\n\ +\t-e logsize (external log size)\n\ +\t-v prints more verbose messages\n\ +\t-h prints this usage message\n\n\ +Note:\tblocksize may have 'k' appended to indicate x1024\n\ +\tlogsize may also have 'm' appended to indicate (1024 x 1024)\n", + basename(progname)); + exit(1); +} + +int +main(int argc, char **argv) +{ + unsigned long long est; + extern int optind; + extern char *optarg; + char dname[40]; + int c; + + while ((c = getopt (argc, argv, "b:hdve:i:V")) != EOF) { + switch (c) { + case 'b': + blocksize=cvtnum(optarg); + if (blocksize <= 0LL) { + fprintf(stderr, "blocksize %llu too small\n", + blocksize); + usage(argv[0]); + } + else if (blocksize > 64LL * 1024LL) { + fprintf(stderr, "blocksize %llu too large\n", + blocksize); + usage(argv[0]); + } + break; + case 'i': + if (elog) { + fprintf(stderr, "already have external log " + "noted, can't have both\n"); + usage(argv[0]); + } + logsize=cvtnum(optarg); + ilog++; + break; + case 'e': + if (ilog) { + fprintf(stderr, "already have internal log " + "noted, can't have both\n"); + usage(argv[0]); + } + logsize=cvtnum(optarg); + elog++; + break; + case 'v': + verbose = 1; + break; + case 'd': + __debug++; + break; + case 'V': + printf("%s version %s\n", basename(argv[0]), VERSION); + break; + default: + case 'h': + usage(argv[0]); + } + } + + if (optind == argc) + usage(argv[0]); + + if (!elog && !ilog) { + ilog=1; + logsize=LOGSIZE * blocksize; + } + if (verbose) + printf( +"directory bsize blocks megabytes logsize\n"); + + for ( ; optind < argc; optind++) { + dirsize=0LL; /* bytes */ + fullblocks=0LL; /* FS blocks */ + isize=0LL; /* inodes bytes */ + nslinks=0LL; /* number of symbolic links */ + nfiles=0LL; /* number of regular files */ + ndirs=0LL; /* number of directories */ + nspecial=0LL; /* number of special files */ + + nftw64(argv[optind], ffn, 40, FTW_PHYS | FTW_MOUNT); + + if (__debug) { + printf("dirsize=%llu\n", dirsize); + printf("fullblocks=%llu\n", fullblocks); + printf("isize=%llu\n", isize); + + printf("%llu regular files\n", nfiles); + printf("%llu symbolic links\n", nslinks); + printf("%llu directories\n", ndirs); + printf("%llu special files\n", nspecial); + } + + est = FBLOCKS(isize) + 8 /* blocks for inodes */ + + FBLOCKS(dirsize) + 1 /* blocks for directories */ + + fullblocks /* blocks for file contents */ + + (8 * 16) /* fudge for overhead blks (per ag) */ + + FBLOCKS(isize / INODESIZE); /* 1 byte/inode for map */ + + if (ilog) + est += (logsize / blocksize); + + if (!verbose) { + printf("%s will take about %.1f megabytes\n", + argv[optind], + (double)est*(double)blocksize/(1024.0*1024.0)); + } else { + /* avoid running over 39 characters in field */ + strncpy(dname, argv[optind], 40); + dname[39] = '\0'; + printf("%-39s %5llu %8llu %10.1fMB %10llu\n", + dname, blocksize, est, + (double)est*(double)blocksize/(1024.0*1024.0), logsize); + } + + if (!verbose && elog) { + printf("\twith the external log using %llu blocks ", + logsize/blocksize); + printf("or about %.1f megabytes\n", + (double)logsize/(1024.0*1024.0)); + } + } + return 0; +} + +int +ffn(const char *path, const struct stat64 *stb, int flags, struct FTW *f) +{ + /* cases are in most-encountered to least-encountered order */ + dirsize+=PERDIRENTRY+strlen(path); + isize+=INODESIZE; + switch (S_IFMT & stb->st_mode) { + case S_IFREG: /* regular files */ + fullblocks+=FBLOCKS(stb->st_blocks * 512 + blocksize-1); + if (stb->st_blocks * 512 < stb->st_size) + fullblocks++; /* add one bmap block here */ + nfiles++; + break; + case S_IFLNK: /* symbolic links */ + if (stb->st_size >= (INODESIZE - (sizeof(xfs_dinode_t)+4))) + fullblocks+=FBLOCKS(stb->st_size + blocksize-1); + nslinks++; + break; + case S_IFDIR: /* directories */ + dirsize+=blocksize; /* fudge upwards */ + if (stb->st_size >= blocksize) + dirsize+=blocksize; + ndirs++; + break; + case S_IFIFO: /* named pipes */ + case S_IFCHR: /* Character Special device */ + case S_IFBLK: /* Block Special device */ + case S_IFSOCK: /* socket */ + nspecial++; + break; + } + return 0; +} diff -rNu linux-2.4.7/cmd/xfsdump/fsr/CVS/Entries linux-2.4-xfs/cmd/xfsdump/fsr/CVS/Entries --- linux-2.4.7/cmd/xfsdump/fsr/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/fsr/CVS/Entries Thu Jul 5 11:44:04 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Mon Jan 15 04:21:44 2001/-ko/ +/xfs_fsr.c/1.5/Thu May 3 21:57:52 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/fsr/CVS/Repository linux-2.4-xfs/cmd/xfsdump/fsr/CVS/Repository --- linux-2.4.7/cmd/xfsdump/fsr/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/fsr/CVS/Repository Thu Jul 5 11:44:03 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/fsr diff -rNu linux-2.4.7/cmd/xfsdump/fsr/CVS/Root linux-2.4-xfs/cmd/xfsdump/fsr/CVS/Root --- linux-2.4.7/cmd/xfsdump/fsr/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/fsr/CVS/Root Thu Jul 5 11:44:03 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/fsr/Makefile linux-2.4-xfs/cmd/xfsdump/fsr/Makefile --- linux-2.4.7/cmd/xfsdump/fsr/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/fsr/Makefile Sun Jan 14 22:21:44 2001 @@ -0,0 +1,49 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = xfs_fsr +CMDDEPS = $(LIBHANDLE) $(LIBATTR) + +CFILES = xfs_fsr.c +LLDLIBS = $(LIBHANDLE) $(LIBATTR) + +default: $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_BIN_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/xfsdump/fsr/xfs_fsr.c linux-2.4-xfs/cmd/xfsdump/fsr/xfs_fsr.c --- linux-2.4.7/cmd/xfsdump/fsr/xfs_fsr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/fsr/xfs_fsr.c Thu May 3 16:57:52 2001 @@ -0,0 +1,1563 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * fsr - file system reorganizer + * + * fsr [-d] [-v] [-n] [-s] [-g] [-t mins] [-f leftf] [-m mtab] + * fsr [-d] [-v] [-n] [-s] [-g] xfsdev | dir | file ... + * + * If invoked in the first form fsr does the following: starting with the + * dev/inum specified in /etc/fsrlast this reorgs each reg file in each file + * system found in /etc/mtab. After 2 hours of this we record the current + * dev/inum in /etc/fsrlast. If there is no /etc/fsrlast fsr starts at the + * top of /etc/mtab. + * + * -g print to syslog (default if stdout not a tty) + * -m mtab use something other than /etc/mtab + * -t time how long to run + * -f leftoff use this instead of /etc/fsrlast + * + * -v verbose. more -v's more verbose + * -d debug. print even more + * -n do nothing. only interesting with -v. Not + * effective with in mtab mode. + * -s print statistics only. + * -p passes Number of passes before terminating global re-org. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int vflag; +int gflag; +static int Mflag; +/* static int nflag; */ +int dflag = 0; +/* static int sflag; */ +int argv_blksz_dio; +extern int max_ext_size; +static int npasses = 10; +static int startpass = 0; + +struct getbmap *outmap = NULL; +int outmap_size = 0; +int RealUid; +int tmp_agi; +static __int64_t minimumfree = 2048; + +#define MNTTYPE_XFS "xfs" + +#define SMBUFSZ 1024 +#define ROOT 0 +#define GRABSZ 64 +#define TARGETRANGE 10 +#define V_NONE 0 +#define V_OVERVIEW 1 +#define V_ALL 2 +#define BUFFER_SIZE (1<<16) +#define BUFFER_MAX (1<<24) +#define min(x, y) ((x) < (y) ? (x) : (y)) + +static time_t howlong = 7200; /* default seconds of reorganizing */ +static char *leftofffile = "/var/tmp/.fsrlast_xfs";/* where we left off last */ +static char *mtab = MOUNTED; +static char *progname; +static time_t endtime; +static time_t starttime; +static xfs_ino_t leftoffino = 0; +static int pagesize; + +void usage(int ret); +static int fsrfile(char *fname, xfs_ino_t ino); +static int fsrfile_common( char *fname, char *tname, char *mnt, + int fd, xfs_bstat_t *statp); +static int packfile(char *fname, char *tname, int fd, + xfs_bstat_t *statp, int flag); +static void fsrdir(char *dirname); +static int fsrfs(char *mntdir, xfs_ino_t ino, int targetrange); +static void initallfs(char *mtab); +static void fsrallfs(int howlong, char *leftofffile); +static void fsrall_cleanup(int timeout); +static int getnextents(int); +int xfsrtextsize(int fd); +int xfs_getrt(int fd, struct statvfs64 *sfbp); +char * gettmpname(char *fname); +char * getparent(char *fname); +int fsrprintf(const char *fmt, ...); +int read_fd_bmap(int, xfs_bstat_t *, int *); +int cmp(const void *, const void *); +static void tmp_init(char *mnt); +static char * tmp_next(char *mnt); +static void tmp_close(char *mnt); +int xfs_getgeom(int , xfs_fsop_geom_t * ); +static int getmntany (FILE *, struct mntent *, struct mntent *); + +xfs_fsop_geom_t fsgeom; /* geometry of active mounted system */ + +#define NMOUNT 64 +static int numfs; + +typedef struct fsdesc { + char *dev; + char *mnt; + int npass; +} fsdesc_t; + +fsdesc_t *fs, *fsbase, *fsend; +int fsbufsize = 10; /* A starting value */ +int nfrags = 0; /* Debug option: Coerse into specific number + * of extents */ +int openopts = O_CREAT|O_EXCL|O_RDWR|O_DIRECT; + +int +xfs_fsgeometry(int fd, xfs_fsop_geom_t *geom) +{ + return ioctl(fd, XFS_IOC_FSGEOMETRY, geom); +} + +int +xfs_bulkstat_single(int fd, xfs_ino_t *lastip, xfs_bstat_t *ubuffer) +{ + xfs_fsop_bulkreq_t bulkreq; + + bulkreq.lastip = lastip; + bulkreq.icount = 1; + bulkreq.ubuffer = ubuffer; + bulkreq.ocount = NULL; + return ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq); +} + +int +xfs_bulkstat(int fd, xfs_ino_t *lastip, int icount, + xfs_bstat_t *ubuffer, size_t *ocount) +{ + xfs_fsop_bulkreq_t bulkreq; + + bulkreq.lastip = lastip; + bulkreq.icount = icount; + bulkreq.ubuffer = ubuffer; + bulkreq.ocount = (__s32 *)ocount; + return ioctl(fd, XFS_IOC_FSBULKSTAT, &bulkreq); +} + +int +xfs_swapext(int fd, xfs_swapext_t *sx) +{ + return ioctl(fd, XFS_IOC_SWAPEXT, sx); +} + +int +xfs_fscounts(int fd, xfs_fsop_counts_t *counts) +{ + return ioctl(fd, XFS_IOC_FSCOUNTS, counts); +} + +void +aborter(int unused) +{ + fsrall_cleanup(1); + exit(1); +} + +int +main(int argc, char **argv) +{ + struct stat sb, sb2; + char *argname; + char *cp; + int c; + struct mntent mntpref; + register struct mntent *mntp; + struct mntent mntent; + register FILE *mtabp; + + setlinebuf(stdout); + progname = basename(argv[0]); + + gflag = ! isatty(0); + + while ((c = getopt(argc, argv, "C:p:e:MgsdnvTt:f:m:b:N:FV")) != -1 ) + switch (c) { + case 'M': + Mflag = 1; + break; + case 'g': + gflag = 1; + break; + case 'n': + /* nflag = 1; */ + break; + case 'v': + ++vflag; + break; + case 'd': + dflag = 1; + break; + case 's': /* frag stats only */ + /* sflag = 1; */ + fprintf(stderr, "%s: Stats not yet supported for XFS\n", + progname); + usage(1); + break; + case 't': + howlong = atoi(optarg); + break; + case 'f': + leftofffile = optarg; + break; + case 'm': + mtab = optarg; + break; + case 'b': + argv_blksz_dio = atoi(optarg); + break; + case 'p': + npasses = atoi(optarg); + break; + case 'V': + printf("%s version %s\n", progname, VERSION); + break; + default: + usage(1); + } + if (vflag) + setbuf(stdout, NULL); + + starttime = time(0); + + /* Save the caller's real uid */ + RealUid = getuid(); + + pagesize = getpagesize(); + + if (optind < argc) { + for (; optind < argc; optind++) { + argname = argv[optind]; + mntp = NULL; + if (lstat(argname, &sb) < 0) { + fprintf(stderr, "%s: could not stat: %s: %s\n", + progname, argname, strerror(errno)); + continue; + } + if (S_ISLNK(sb.st_mode) && stat(argname, &sb2) == 0 && + (S_ISBLK(sb2.st_mode) || S_ISCHR(sb2.st_mode))) + sb = sb2; + if (S_ISBLK(sb.st_mode) || (S_ISDIR(sb.st_mode))) { + if ((mtabp = setmntent(mtab, "r")) == NULL) { + fprintf(stderr, + "%s: failed reading mtab: %s\n", + progname, mtab); + exit(1); + } + bzero(&mntpref, sizeof(mntpref)); + if (S_ISDIR(sb.st_mode)) + mntpref.mnt_dir = argname; + else + mntpref.mnt_fsname = argname; + + if ((getmntany(mtabp, &mntent, &mntpref) == 0) + && + (strcmp(mntent.mnt_type, MNTTYPE_XFS) == 0)) + { + mntp = &mntent; + if (S_ISBLK(sb.st_mode)) { + cp = mntp->mnt_dir; + if (cp == NULL || + stat(cp, &sb2) < 0) { + fprintf(stderr, + "%s: could not stat: %s: %s\n", + progname, argname, + strerror(errno)); + continue; + } + sb = sb2; + argname = cp; + } + } + } + if (mntp != NULL) { + fsrfs(mntp->mnt_dir, 0, 100); + } else if (S_ISCHR(sb.st_mode)) { + fprintf(stderr, + "%s: char special not supported: %s\n", + progname, argname); + exit(1); + } else if (S_ISDIR(sb.st_mode) || S_ISREG(sb.st_mode)) { + struct statfs fs; + + statfs(argname, &fs); + if (fs.f_type != XFS_SB_MAGIC) { + fprintf(stderr, + "%s: cannot defragment: %s: Not XFS\n", + progname, argname); + continue; + } + if (S_ISDIR(sb.st_mode)) + fsrdir(argname); + else + fsrfile(argname, sb.st_ino); + } else { + printf( + "%s: not fsys dev, dir, or reg file, ignoring\n", + argname); + } + } + } else { + initallfs(mtab); + fsrallfs(howlong, leftofffile); + } + return 0; +} + +void +usage(int ret) +{ + fprintf(stderr, "Usage: %s [xfsfile] ...\n", progname); + exit(ret); +} + +/* + * initallfs -- read the mount table and set up an internal form + */ +static void +initallfs(char *mtab) +{ + FILE *fp; + struct mntent *mp; + int mi; + char *cp; + struct stat sb; + + fp = setmntent(mtab, "r"); + if (fp == NULL) { + fsrprintf("could not open mtab file: %s\n", mtab); + exit(1); + } + + /* malloc a number of descriptors, increased later if needed */ + if ((fsbase = (fsdesc_t *)malloc(fsbufsize * sizeof(fsdesc_t))) == NULL) { + fsrprintf("out of memory: %s\n", strerror(errno)); + exit(1); + } + fsend = (fsbase + fsbufsize - 1); + + /* find all rw xfs file systems */ + mi = 0; + fs = fsbase; + while ((mp = getmntent(fp))) { + int rw = 0; + + if (strcmp(mp->mnt_type, MNTTYPE_XFS ) != 0 || + stat(mp->mnt_fsname, &sb) == -1 || + !S_ISBLK(sb.st_mode)) + continue; + + cp = strtok(mp->mnt_opts,","); + do { + if (strcmp("rw", cp) == 0) + rw++; + } while ((cp = strtok(NULL, ",")) != NULL); + if (rw == 0) { + if (dflag) + fsrprintf("Skipping %s: not mounted rw\n", + mp->mnt_fsname); + continue; + } + + if (mi == fsbufsize) { + fsbufsize += NMOUNT; + if ((fsbase = (fsdesc_t *)realloc((char *)fsbase, + fsbufsize * sizeof(fsdesc_t))) == NULL) { + fsrprintf("out of memory: %s\n", strerror(errno)); + exit(1); + } + if (!fsbase) { + fsrprintf("out of memory on realloc: %s\n", + strerror(errno)); + exit(1); + } + fs = (fsbase + mi); /* Needed ? */ + } + + fs->dev = strdup(mp->mnt_fsname); + fs->mnt = strdup(mp->mnt_dir); + + if (fs->mnt == NULL || fs->mnt == NULL) { + fsrprintf("strdup(%s) failed\n",mp->mnt_fsname); + exit(1); + } + mi++; + fs++; + } + numfs = mi; + fsend = (fsbase + numfs); + endmntent(fp); + if (numfs == 0) { + fsrprintf("no rw xfs file systems in mtab: %s\n", mtab); + exit(0); + } + if (vflag || dflag) { + fsrprintf("Found %d mounted, writable, XFS filesystems\n", + numfs); + if (dflag) + for (fs = fsbase; fs < fsend; fs++) + fsrprintf("\t%-30.30s%-30.30s\n", fs->dev, fs->mnt); + } +} + +static void +fsrallfs(int howlong, char *leftofffile) +{ + int fd; + int error; + int found = 0; + char *fsname; + char buf[SMBUFSZ]; + int mdonly = Mflag; + char *ptr; + xfs_ino_t startino = 0; + fsdesc_t *fsp; + + fsrprintf("xfs_fsr -m %s -t %d -f %s ...\n", mtab, howlong, leftofffile); + + endtime = starttime + howlong; + fs = fsbase; + + /* where'd we leave off last time? */ + fd = open(leftofffile, O_RDONLY); + if (fd == -1) { + if (errno != ENOENT) + fsrprintf( + "open(%s, O_RDONLY) failed: %s, starting with %s\n", + leftofffile, strerror(errno), *fs->dev); + } else { + if (read(fd, buf, SMBUFSZ) == -1) { + fs = fsbase; + fsrprintf("could not read %s, starting with %s\n", + leftofffile, *fs->dev); + + } else { + for (fs = fsbase; fs < fsend; fs++) { + fsname = fs->dev; + if ((strncmp(buf,fsname,strlen(fsname)) == 0) + && buf[strlen(fsname)] == ' ') { + found = 1; + break; + } + } + if (! found) + fs = fsbase; + + ptr = strchr(buf, ' '); + if (ptr) { + startpass = atoi(++ptr); + ptr = strchr(ptr, ' '); + if (ptr) { + startino = strtoll(++ptr, + (char **)NULL, + 10); + } + } + + /* Init pass counts */ + for (fsp = fsbase; fsp < fs; fsp++) { + fsp->npass = startpass + 1; + } + for (fsp = fs; fsp <= fsend; fsp++) { + fsp->npass = startpass; + } + } + close(fd); + } + + if (vflag) { + fsrprintf("START: pass=%d ino=%llu %s %s\n", + fs->npass, (unsigned long long)startino, + fs->dev, fs->mnt); + } + + signal(SIGABRT, aborter); + signal(SIGHUP, aborter); + signal(SIGINT, aborter); + signal(SIGQUIT, aborter); + signal(SIGTERM, aborter); + + /* reorg for 'howlong' -- checked in 'fsrfs' */ + while (endtime > time(0)) { + pid_t pid; + if (fs == fsend) + fs = fsbase; + if (fs->npass == npasses) { + fsrprintf("Completed all %d passes\n", npasses); + break; + } + if (npasses > 1 && !fs->npass) + Mflag = 1; + else + Mflag = mdonly; + pid = fork(); + switch(pid) { + case -1: + fsrprintf("couldn't fork sub process:"); + exit(1); + break; + case 0: + error = fsrfs(fs->mnt, startino, TARGETRANGE); + exit (error); + break; + case 'C': + /* Testing opt: coerses frag count in result */ + if (getenv("FSRXFSTEST") != NULL) { + nfrags = atoi(optarg); + openopts |= O_SYNC; + } + break; + default: + wait(&error); + close(fd); + if (WIFEXITED(error) && WEXITSTATUS(error) == 1) { + /* child timed out & did fsrall_cleanup */ + exit(0); + } + break; + } + startino = 0; /* reset after the first time through */ + fs->npass++; + fs++; + } + fsrall_cleanup(endtime <= time(0)); +} + +/* + * fsrall_cleanup -- close files, print next starting location, etc. + */ +static void +fsrall_cleanup(int timeout) +{ + int fd; + int ret; + char buf[SMBUFSZ]; + + /* record where we left off */ + fd = open(leftofffile, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (fd == -1) + fsrprintf("open(%s) failed: %s\n", + leftofffile, strerror(errno)); + else { + if (timeout) { + ret = sprintf(buf, "%s %d %llu\n", fs->dev, + fs->npass, (unsigned long long)leftoffino); + if (write(fd, buf, ret) < strlen(buf)) + fsrprintf("write(%s) failed: %s\n", leftofffile, + strerror(errno)); + close(fd); + } + } + + if (timeout) + fsrprintf("xfs_fsr startpass %d, endpass %d, time %d seconds\n", + startpass, fs->npass, time(0) - endtime + howlong); +} + +/* + * fsrfs -- reorganize a file system + */ +static int +fsrfs(char *mntdir, xfs_ino_t startino, int targetrange) +{ + + int fsfd, fd; + int count = 0; + int ret; + size_t buflenout; + xfs_bstat_t buf[GRABSZ]; + char fname[64]; + char *tname; + jdm_fshandle_t *fshandlep; + xfs_ino_t lastino = startino; + + fsrprintf("%s startino=%llu\n", mntdir, (unsigned long long)startino); + + fshandlep = jdm_getfshandle( mntdir ); + if ( ! fshandlep ) { + fsrprintf("unable to get handle: %s: %s\n", + mntdir, strerror( errno )); + return -1; + } + + if ((fsfd = open(mntdir, O_RDONLY)) < 0) { + fsrprintf("unable to open: %s: %s\n", + mntdir, strerror( errno )); + return -1; + } + + if (xfs_getgeom(fsfd, &fsgeom) < 0 ) { + fsrprintf("Skipping %s: could not get XFS geom\n", + mntdir); + return -1; + } + + tmp_init(mntdir); + + sync(); + while (! xfs_bulkstat(fsfd, &lastino, GRABSZ, &buf[0], &buflenout)) { + xfs_bstat_t *p; + xfs_bstat_t *endp; + + if (buflenout == 0 ) + goto out0; + + + + + /* Each loop through, defrag targetrange percent of the files */ + count = (buflenout * targetrange) / 100; + + qsort((char *)buf, buflenout, sizeof(struct xfs_bstat), cmp); + + for ( p = buf, endp = (buf + buflenout); p < endp ; p++ ) { + /* Do some obvious checks now */ + if (((p->bs_mode & S_IFMT) != S_IFREG) || + (p->bs_extents < 2)) + continue; + + if((fd = jdm_open(fshandlep, p, O_RDWR)) < 0) { + /* This probably means the file was + * removed while in progress of handling + * it. Just quietly ignore this file. + */ + if (dflag) + fsrprintf("could not open: ino %llu\n", + p->bs_ino); + continue; + } + + /* Don't know the pathname, so make up something */ + sprintf(fname, "ino=%llu", (unsigned long long)p->bs_ino); + + /* Get a tmp file name */ + tname = tmp_next(mntdir); + + ret = fsrfile_common(fname, tname, mntdir, fd, p); + + leftoffino = p->bs_ino; + + close(fd); + + if (ret == 0) { + if (--count <= 0) + break; + } + } + if (endtime && endtime < time(0)) { + tmp_close(mntdir); + close(fsfd); + fsrall_cleanup(1); + exit(1); + } + } +out0: + tmp_close(mntdir); + close(fsfd); + return 0; +} + +/* + * To compare bstat structs for qsort. + */ +int +cmp(const void *s1, const void *s2) +{ + return( ((xfs_bstat_t *)s2)->bs_extents - + ((xfs_bstat_t *)s1)->bs_extents); + +} + +/* + * reorganize by directory hierarchy. + * Stay in dev (a restriction based on structure of this program -- either + * call efs_{n,u}mount() around each file, something smarter or this) + */ +static void +fsrdir(char *dirname) +{ + fsrprintf("%s: Directory defragmentation not supported\n", dirname); +} + +/* + * Sets up the defragmentation of a file based on the + * filepath. It collects the bstat information, does + * an open on the file and passes this all to fsrfile_common. + */ +static int +fsrfile(char *fname, xfs_ino_t ino) +{ + xfs_bstat_t statbuf; + jdm_fshandle_t *fshandlep; + int fd, fsfd; + int error = 0; + char *tname; + + fshandlep = jdm_getfshandle(getparent (fname) ); + if (! fshandlep) { + fsrprintf( + "unable to construct sys handle for %s: %s\n", + fname, strerror(errno)); + return -1; + } + + /* + * Need to open something on the same filesystem as the + * file. Open the parent. + */ + fsfd = open(getparent(fname), O_RDONLY); + if (fsfd < 0) { + fsrprintf( + "unable to open sys handle for %s: %s\n", + fname, strerror(errno)); + return -1; + } + + if ((xfs_bulkstat_single(fsfd, &ino, &statbuf)) < 0) { + fsrprintf( + "unable to get bstat on %s: %s\n", + fname, strerror(errno)); + close(fsfd); + return -1; + } + + fd = jdm_open( fshandlep, &statbuf, O_RDWR); + if (fd < 0) { + fsrprintf( + "unable to open handle %s: %s\n", + fname, strerror(errno)); + close(fsfd); + return -1; + } + + /* Get the fs geometry */ + if (xfs_getgeom(fsfd, &fsgeom) < 0 ) { + fsrprintf("Unable to get geom on fs for: %s\n", fname); + close(fsfd); + return -1; + } + + close(fsfd); + + tname = gettmpname(fname); + + if (tname) + error = fsrfile_common(fname, tname, NULL, fd, &statbuf); + + close(fd); + + return error; +} + + +/* + * This is the common defrag code for either a full fs + * defragmentation or a single file. Check as much as + * possible with the file, fork a process to setuid to the + * target file owner's uid and defragment the file. + * This is done so the new extents created in a tmp file are + * reflected in the owners' quota without having to do any + * special code in the kernel. When the existing extents + * are removed, the quotas will be correct. It's ugly but + * it saves us from doing some quota re-construction in + * the extent swap. The price is that the defragmentation + * will fail if the owner of the target file is already at + * their quota limit. + */ +static int +fsrfile_common( + char *fname, + char *tname, + char *fsname, + int fd, + xfs_bstat_t *statp) +{ + int pid; + int error; + struct statvfs64 vfss; + struct fsxattr fsx; + int do_rt = 0; + unsigned long bsize; +#ifdef HAVE_CAPABILITIES + cap_t ocap; + cap_value_t cap_setuid = CAP_SETUID; +#endif + + if (vflag) + fsrprintf("%s\n", fname); + + if (fsync(fd) < 0) { + fsrprintf("sync failed: %s: %s\n", fname, strerror(errno)); + return -1; + } + + if (statp->bs_size == 0) { + if (vflag) + fsrprintf("%s: zero size, ignoring\n", fname); + return(0); + } + + /* Check if a mandatory lock is set on the file to try and + * avoid blocking indefinitely on the reads later. Note that + * someone could still set a mandatory lock after this check + * but before all reads have completed to block fsr reads. + * This change just closes the window a bit. + */ + if ( (statp->bs_mode & S_ISGID) && ( ! (statp->bs_mode&S_IXGRP) ) ) { + struct flock fl; + + fl.l_type = F_RDLCK; + fl.l_whence = SEEK_SET; + fl.l_start = (off_t)0; + fl.l_len = 0; + if ((fcntl(fd, F_GETLK, &fl)) < 0 ) { + if (vflag) + fsrprintf("locking check failed: %s\n", fname); + return(-1); + } + if (fl.l_type != F_UNLCK) { + /* Mandatory lock is set */ + if (vflag) + fsrprintf("mandatory lock: %s: ignoring\n", + fname); + return(-1); + } + } + + /* Check if there is room to copy the file */ + if ( statvfs64( (fsname == NULL ? fname : fsname), &vfss) < 0) { + fsrprintf( + "unable to get fs stat on %s: %s\n", + fname, strerror(errno)); + return (-1); + } + bsize = vfss.f_frsize ? vfss.f_frsize : vfss.f_bsize; + + if (statp->bs_size > ((vfss.f_bfree * bsize) - minimumfree)) { + fsrprintf( + "insufficient freespace for: %s: size=%lld: ignoring\n", + fname, statp->bs_size); + return 1; + } + + /* Check realtime info */ + if ((ioctl(fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) { + fsrprintf("failed to get attrs: %s\n", fname); + return(-1); + } + if (fsx.fsx_xflags == XFS_XFLAG_REALTIME) { + if (xfs_getrt(fd, &vfss) < 0) { + fsrprintf("could not get rt geom for: %s\n", fname); + return(-1); + } + if (statp->bs_size > ((vfss.f_bfree * bsize) - minimumfree)) { + fsrprintf("low on rt free space: %s: ignoring file\n", + fname); + return(-1); + } + do_rt = 1; + } + + if ((RealUid != ROOT) && (RealUid != statp->bs_uid)) { + fsrprintf("cannot open: %s: Permission denied\n", fname); + return -1; + } + + pid = fork(); + if (pid < 0) { + fsrprintf("fork failed: %s\n", strerror(errno)); + close(fd); + exit(1); + } else if (pid == 0) { + /* + * Already checked ownership so we're either + * root or our realuid owns the file and can safely + * setuid to the file owner. This is done so + * quotas are maintained for the user. (No group + * quotas so no setgid). + */ +#ifdef HAVE_CAPABILITIES + ocap = cap_acquire(1, &cap_setuid); +#endif + if (setuid(statp->bs_uid) < 0) { + fsrprintf("setuid failed: uid=%d %s: %s\n", + statp->bs_uid, fname, strerror(errno)); +#ifdef HAVE_CAPABILITIES + cap_surrender(ocap); +#endif + exit(1); + } +#ifdef HAVE_CAPABILITIES + cap_surrender(ocap); +#endif + + error = packfile(fname, tname, fd, statp, do_rt); + exit(error); + } else if (pid > 0) { + wait(&error); + close(fd); + if (WIFEXITED(error)) + return(WEXITSTATUS(error)); + return -1; + } + /* NOTREACHED */ + return 0; +} + + +/* + * Do the defragmentation of a single file. + * We already are pretty sure we can and want to + * defragment the file. Create the tmp file, copy + * the data (maintaining holes) and call the kernel + * extent swap routinte. + */ +static int +packfile(char *fname, char *tname, int fd, xfs_bstat_t *statp, int do_rt) +{ + int tfd; + int srval; + int nextents, extent, cur_nextents, new_nextents; + unsigned blksz_dio; + unsigned dio_min; + struct dioattr dio; + static xfs_swapext_t sx; + struct xfs_flock64 space; + off64_t cnt, pos; + void *fbuf; + int ct, wc, wc_b4; + struct fsxattr tfsx; + char ffname[SMBUFSZ]; + int ffd = 0; + + /* + * Work out the extent map - nextents will be set to the + * minimum number of extents needed for the file (taking + * into account holes), cur_nextents is the current number + * of extents. + */ + nextents = read_fd_bmap(fd, statp, &cur_nextents); + + if ( cur_nextents == 1 || cur_nextents <= nextents ) { + if (vflag) + fsrprintf("%s already fully defragmented.\n", fname); + return 1; /* indicates no change/no error */ + } + + if (dflag) + fsrprintf("%s extents=%d can_save=%d tmp=%s\n", + fname, cur_nextents, (cur_nextents - nextents), + tname); + + if ((tfd = open(tname, openopts, 0666)) < 0) { + if (vflag) + fsrprintf("could not open tmp as uid %d: %s: %s\n", + statp->bs_uid,tname, strerror(errno)); + return -1; + } + unlink(tname); + + /* Setup extended attributes */ + if( statp->bs_xflags & XFS_XFLAG_HASATTR ) { + if (attr_setf(tfd, "X", "X", 1, ATTR_CREATE) != 0) { + fsrprintf("could not set ATTR on tmp: %s:\n", tname); + close(tfd); + return -1; + } + if (dflag) + fsrprintf("%s set temp attr\n", tname); + } + + if ((ioctl(tfd, XFS_IOC_DIOINFO, &dio)) < 0 ) { + fsrprintf("could not get I/O info on tmp: %s\n", tname); + close(tfd); + return -1; + } + + if (do_rt) { + int rt_textsize = fsgeom.rtextsize * fsgeom.blocksize; + + tfsx.fsx_xflags = XFS_XFLAG_REALTIME; + + if ((tfsx.fsx_extsize = rt_textsize) <= 0 ) { + fsrprintf("realtime geom not avail for tmp: %s\n", fname); + close(tfd); + return -1; + } + + if (ioctl( tfd, XFS_IOC_FSSETXATTR, &tfsx) < 0) { + fsrprintf("could not set rt on tmp: %s\n", tname); + close(tfd); + return -1; + } + } + + dio_min = dio.d_miniosz; + if (statp->bs_size <= dio_min) + blksz_dio = dio_min; + else { + blksz_dio = min(dio.d_maxiosz, BUFFER_MAX - pagesize); + if (argv_blksz_dio != 0) + blksz_dio = min(argv_blksz_dio, blksz_dio); + blksz_dio = (min(statp->bs_size, blksz_dio) / dio_min) * dio_min; + } + + if (dflag) { + fsrprintf("DEBUG: fsize=%lld blsz_dio=%d d_min=%d d_max=%d pgsz=%d\n", + statp->bs_size, blksz_dio, dio.d_miniosz, dio.d_maxiosz, pagesize); + } + + /* Malloc a buffer */ + if (! (fbuf = (char *)memalign(dio.d_mem, blksz_dio))) { + fsrprintf("could not allocate buf: %s\n", tname); + close(tfd); + return -1; + } + + if (nfrags) { + /* Create new tmp file in same AG as first */ + sprintf(ffname, "%s.frag", tname); + + /* Open the new file for sync writes */ + if ((ffd = open(ffname, openopts, 0666)) + < 0) { + fsrprintf("could not open fragfile: %s : %s\n", + ffname, strerror(errno)); + return -1; + } + unlink(ffname); + } + + /* Loop through block map copying the file. */ + for (extent = 0; extent < nextents; extent++) { + pos = outmap[extent].bmv_offset; + if (outmap[extent].bmv_block == -1) { + space.l_whence = 0; + space.l_start = pos; + space.l_len = outmap[extent].bmv_length; + if (ioctl(tfd, XFS_IOC_UNRESVSP64, &space) < 0) { + fsrprintf("could not trunc tmp %s\n", + tname); + } + lseek64(tfd, outmap[extent].bmv_length, SEEK_CUR); + lseek64(fd, outmap[extent].bmv_length, SEEK_CUR); + continue; + } else if (outmap[extent].bmv_length == 0) { + /* to catch holes at the beginning of the file */ + continue; + } + if (! nfrags) { + space.l_whence = SEEK_CUR; + space.l_start = 0; + space.l_len = outmap[extent].bmv_length; + + if (ioctl(tfd, XFS_IOC_RESVSP64, &space) < 0) { + fsrprintf("could not pre-alloc tmp space: %s\n", + tname); + close(tfd); + free(fbuf); + return -1; + } + } + for (cnt = outmap[extent].bmv_length; cnt > 0; + cnt -= ct, pos += ct) { + if (nfrags && --nfrags) { + ct = min(cnt, dio_min); + } else if (cnt % dio_min == 0) { + ct = min(cnt, blksz_dio); + } else { + ct = min(cnt + dio_min - (cnt % dio_min), + blksz_dio); + } + ct = read(fd, fbuf, ct); + if (ct == 0) { + /* EOF, stop trying to read */ + extent = nextents; + break; + } + /* Ensure we do direct I/O to correct block + * boundaries. + */ + if (ct % dio_min != 0) { + wc = ct + dio_min - (ct % dio_min); + } else { + wc = ct; + } + wc_b4 = wc; + if (ct < 0 || ((wc = write(tfd, fbuf, wc)) != wc_b4)) { + if (ct < 0) + fsrprintf("bad read of %d bytes from %s:%s\n", + wc_b4, fname, strerror(errno)); + else if (wc < 0) + fsrprintf("bad write of %d bytes to %s: %s\n", + wc_b4, tname, strerror(errno)); + else { + /* + * Might be out of space + * + * Try to finish write + */ + int resid = ct-wc; + + if ((wc = write(tfd, ((char *)fbuf)+wc, + resid)) == resid) { + /* worked on second attempt? */ + continue; + } + else + if (wc < 0) { + fsrprintf("bad write2 of %d bytes to %s: %s\n", + resid, tname, strerror(errno)); + } else { + fsrprintf("bad copy to %s\n", + tname); + } + } + free(fbuf); + return -1; + } + if (nfrags) { + /* Do a matching write to the tmp file */ + wc = wc_b4; + if (((wc = write(ffd, fbuf, wc)) != wc_b4)) { fsrprintf("bad write of %d bytes " + "to %s: %s\n", + wc_b4, ffname, strerror(errno)); + } + } + } + } + ftruncate64(tfd, statp->bs_size); + if (ffd) close(ffd); + fsync(tfd); + + free(fbuf); + + sx.sx_stat = *statp; /* struct copy */ + sx.sx_version = XFS_SX_VERSION; + sx.sx_fdtarget = fd; + sx.sx_fdtmp = tfd; + sx.sx_offset = 0; + sx.sx_length = statp->bs_size; + + /* Check if the extent count improved */ + new_nextents = getnextents(tfd); + if (cur_nextents <= new_nextents) { + if (vflag) + fsrprintf("No improvement made: %s\n", fname); + close(tfd); + return 1; /* no change/no error */ + } + + /* Swap the extents */ + srval = xfs_swapext(fd, &sx); + if (srval < 0) { + if (errno == ENOTSUP) { + if (vflag || dflag) + fsrprintf("%s: file type not supported\n", fname); + } else if (errno == EFAULT) { + /* The file has changed since we started the copy */ + if (vflag || dflag) + fsrprintf("%s:file modified defrag aborted\n", + fname); + } else if (errno == EBUSY) { + /* Timestamp has changed or mmap'ed file */ + if (vflag || dflag) + fsrprintf("%s: file busy \n", fname); + } else { + fsrprintf("XFS_IOC_SWAPEXT failed: %s: %s\n", + fname, strerror(errno)); + } + close(tfd); + return -1; + } + + /* Report progress */ + if (vflag) + fsrprintf("extents before:%d after:%d %s %s\n", + cur_nextents, new_nextents, + (new_nextents <= nextents ? "DONE" : " " ), + fname); + close(tfd); + return 0; +} + +char * +gettmpname(char *fname) +{ + static char buf[PATH_MAX+1]; + char sbuf[SMBUFSZ]; + char *ptr; + + sprintf(sbuf, "/.fsr%d", getpid()); + + strcpy(buf, fname); + ptr = strrchr(buf, '/'); + if (ptr) { + *ptr = '\0'; + } else { + strcpy(buf, "."); + } + + if ((strlen(buf) + strlen (sbuf)) > PATH_MAX) { + fsrprintf("tmp file name too long: %s\n", fname); + return(NULL); + } + + strcat(buf, sbuf); + + return(buf); +} + +char * +getparent(char *fname) +{ + static char buf[PATH_MAX+1]; + char *ptr; + + strcpy(buf, fname); + ptr = strrchr(buf, '/'); + if (ptr) { + if (ptr == &buf[0]) + ++ptr; + *ptr = '\0'; + } else { + strcpy(buf, "."); + } + + return(buf); +} + +/* + * Read in block map of the input file, coalesce contiguous + * extents into a single range, keep all holes. Convert from 512 byte + * blocks to bytes. + * + * This code was borrowed from mv.c with some minor mods. + */ +#define MAPSIZE 128 +#define OUTMAP_SIZE_INCREMENT MAPSIZE + +int read_fd_bmap(int fd, xfs_bstat_t *sin, int *cur_nextents) +{ + int i, cnt; + struct getbmap map[MAPSIZE]; + +#define BUMP_CNT \ + if (++cnt >= outmap_size) { \ + outmap_size += OUTMAP_SIZE_INCREMENT; \ + outmap = (struct getbmap *)realloc(outmap, \ + outmap_size*sizeof(*outmap)); \ + if (outmap == NULL) { \ + fsrprintf("realloc failed: %s\n", \ + strerror(errno)); \ + exit(1); \ + } \ + } + + /* Initialize the outmap array. It always grows - never shrinks. + * Left-over memory allocation is saved for the next files. + */ + if (outmap_size == 0) { + outmap_size = OUTMAP_SIZE_INCREMENT; /* Initial size */ + outmap = (struct getbmap *)malloc(outmap_size*sizeof(*outmap)); + if (!outmap) { + fsrprintf("malloc failed: %s\n", + strerror(errno)); + exit(1); + } + } + + outmap[0].bmv_block = 0; + outmap[0].bmv_offset = 0; + outmap[0].bmv_length = sin->bs_size; + + /* + * If a non regular file is involved then forget holes + */ + + if (!S_ISREG(sin->bs_mode)) + return(1); + + outmap[0].bmv_length = 0; + + map[0].bmv_offset = 0; + map[0].bmv_block = 0; + map[0].bmv_entries = 0; + map[0].bmv_count = MAPSIZE; + map[0].bmv_length = -1; + + cnt = 0; + *cur_nextents = 0; + + do { + if (ioctl(fd, XFS_IOC_GETBMAP, map) < 0) { + fsrprintf("failed reading extents: inode %llu", + (unsigned long long)sin->bs_ino); + exit(1); + } + + /* Concatenate extents together and replicate holes into + * the output map. + */ + *cur_nextents += map[0].bmv_entries; + for (i = 0; i < map[0].bmv_entries; i++) { + if (map[i + 1].bmv_block == -1) { + BUMP_CNT; + outmap[cnt] = map[i+1]; + } else if (outmap[cnt].bmv_block == -1) { + BUMP_CNT; + outmap[cnt] = map[i+1]; + } else { + outmap[cnt].bmv_length += map[i + 1].bmv_length; + } + } + } while (map[0].bmv_entries == (MAPSIZE-1)); + for (i = 0; i <= cnt; i++) { + outmap[i].bmv_offset = BBTOB(outmap[i].bmv_offset); + outmap[i].bmv_length = BBTOB(outmap[i].bmv_length); + } + + outmap[cnt].bmv_length = sin->bs_size - outmap[cnt].bmv_offset; + + return(cnt+1); +} + +/* + * Read the block map and return the number of extents. + */ +static int +getnextents(int fd) +{ + int nextents; + struct getbmap map[MAPSIZE]; + + map[0].bmv_offset = 0; + map[0].bmv_block = 0; + map[0].bmv_entries = 0; + map[0].bmv_count = MAPSIZE; + map[0].bmv_length = -1; + + nextents = 0; + + do { + if (ioctl(fd,XFS_IOC_GETBMAP, map) < 0) { + fsrprintf("failed reading extents"); + exit(1); + } + + nextents += map[0].bmv_entries; + } while (map[0].bmv_entries == (MAPSIZE-1)); + return(nextents); +} + +/* + * Get the fs geometry + */ +int +xfs_getgeom(int fd, xfs_fsop_geom_t * fsgeom) +{ + if (xfs_fsgeometry(fd, fsgeom) < 0) { + return -1; + } + return 0; +} + +/* + * Get xfs realtime space information + */ +int +xfs_getrt(int fd, struct statvfs64 *sfbp) +{ + unsigned long bsize; + unsigned long factor; + xfs_fsop_counts_t cnt; + + if (!fsgeom.rtblocks) + return -1; + + if (xfs_fscounts(fd, &cnt) < 0) { + close(fd); + return -1; + } + bsize = (sfbp->f_frsize ? sfbp->f_frsize : sfbp->f_bsize); + factor = fsgeom.blocksize / bsize; /* currently this is == 1 */ + sfbp->f_bfree = (cnt.freertx * fsgeom.rtextsize) * factor; + return 0; +} + +int +fsrprintf(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (gflag) { + static int didopenlog; + if (!didopenlog) { + openlog("fsr", LOG_PID, LOG_USER); + didopenlog = 1; + } + vsyslog(LOG_INFO, fmt, ap); + } else + vprintf(fmt, ap); + va_end(ap); + return 0; +} + +/* + * emulate getmntany + */ +static int +getmntany (FILE *filep, struct mntent *mp, struct mntent *mpref) +{ + int match = 0; + struct mntent *t; + + while (!match && (t = getmntent(filep)) != 0) { + if (mpref->mnt_fsname != NULL && + strcmp(mpref->mnt_fsname, t->mnt_fsname) != 0) continue; + if (mpref->mnt_dir != NULL && + strcmp(mpref->mnt_dir, t->mnt_dir) != 0) continue; + match++; + } + if (match) *mp = *t; + return !match; +} + + +/* + * Initialize a directory for tmp file use. This is used + * by the full filesystem defragmentation when we're walking + * the inodes and do not know the path for the individual + * files. Multiple directories are used to spread out the + * tmp data around to different ag's (since file data is + * usually allocated to the same ag as the directory and + * directories allocated round robin from the same + * parent directory). + */ +static void +tmp_init(char *mnt) +{ + int i; + static char buf[SMBUFSZ]; + mode_t mask; + + tmp_agi = 0; + sprintf(buf, "%s/.fsr", mnt); + + mask = umask(0); + if (mkdir(buf, 0777) < 0) { + if (errno == EEXIST) { + if (dflag) + fsrprintf("tmpdir already exists: %s\n", buf); + } else { + fsrprintf("could not create tmpdir: %s: %s\n", + buf, strerror(errno)); + exit(-1); + } + } + for (i=0; i < fsgeom.agcount; i++) { + sprintf(buf, "%s/.fsr/ag%d", mnt, i); + if (mkdir(buf, 0777) < 0) { + if (errno == EEXIST) { + if (dflag) + fsrprintf("tmpdir already exists: %s\n",buf); + } else { + fsrprintf("could not create tmpdir: %s: %s\n", + buf, strerror(errno)); + exit(-1); + } + } + } + (void)umask(mask); + return; +} + +static char * +tmp_next(char *mnt) +{ + static char buf[SMBUFSZ]; + + sprintf(buf, "%s/.fsr/ag%d/tmp%d", + ( (strcmp(mnt, "/") == 0) ? "" : mnt), + tmp_agi, + getpid()); + + if (++tmp_agi == fsgeom.agcount) + tmp_agi = 0; + + return(buf); +} + +static void +tmp_close(char *mnt) +{ + static char buf[SMBUFSZ]; + int i; + + /* No data is ever actually written so we can just do rmdir's */ + for (i=0; i < fsgeom.agcount; i++) { + sprintf(buf, "%s/.fsr/ag%d", mnt, i); + if (rmdir(buf) < 0) { + if (errno != ENOENT) { + fsrprintf("could not remove tmpdir: %s: %s\n", + buf, strerror(errno)); + } + } + } + sprintf(buf, "%s/.fsr", mnt); + if (rmdir(buf) < 0) { + if (errno != ENOENT) { + fsrprintf("could not remove tmpdir: %s: %s\n", + buf, strerror(errno)); + } + } +} diff -rNu linux-2.4.7/cmd/xfsdump/include/CVS/Entries linux-2.4-xfs/cmd/xfsdump/include/CVS/Entries --- linux-2.4.7/cmd/xfsdump/include/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/include/CVS/Entries Thu Jul 5 11:44:04 2001 @@ -0,0 +1,4 @@ +/Makefile/1.1/Mon Jan 15 04:42:23 2001/-ko/ +/builddefs.in/1.2/Wed May 9 07:18:58 2001/-ko/ +/buildrules/1.1/Mon Jan 15 04:42:23 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/include/CVS/Repository linux-2.4-xfs/cmd/xfsdump/include/CVS/Repository --- linux-2.4.7/cmd/xfsdump/include/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/include/CVS/Repository Thu Jul 5 11:44:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/include diff -rNu linux-2.4.7/cmd/xfsdump/include/CVS/Root linux-2.4-xfs/cmd/xfsdump/include/CVS/Root --- linux-2.4.7/cmd/xfsdump/include/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/include/CVS/Root Thu Jul 5 11:44:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/include/Makefile linux-2.4-xfs/cmd/xfsdump/include/Makefile --- linux-2.4.7/cmd/xfsdump/include/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/include/Makefile Sun Jan 14 22:42:23 2001 @@ -0,0 +1,40 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LSRCFILES = builddefs.in buildrules + +default install install-dev : + +include $(BUILDRULES) diff -rNu linux-2.4.7/cmd/xfsdump/include/builddefs.in linux-2.4-xfs/cmd/xfsdump/include/builddefs.in --- linux-2.4.7/cmd/xfsdump/include/builddefs.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/include/builddefs.in Wed May 9 02:18:58 2001 @@ -0,0 +1,170 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# @configure_input@ +# + +ifndef _BUILDDEFS_INCLUDED_ +_BUILDDEFS_INCLUDED_ = 1 + +DEBUG = @debug_build@ +OPTIMIZER = @opt_build@ +MALLOCLIB = @malloc_lib@ + +LIBXFS = @libxfs@ +LIBATTR = @libattr@ +LIBUUID = @libuuid@ +LIBHANDLE = @libhdl@ +CPPFLAGS = -I/usr/include/xfs -I/usr/include/attr + +BUILDRULES = $(TOPDIR)/include/buildrules + +# General package information +PKG_NAME = @pkg_name@ +PKG_RELEASE = @pkg_release@ +PKG_VERSION = @pkg_version@ +PKG_DISTRIBUTION = @pkg_distribution@ +PKG_BUILDER = @pkg_builder@ +PKG_BIN_DIR = @pkg_bin_dir@ +PKG_LIB_DIR = @pkg_lib_dir@ +PKG_SBIN_DIR = @pkg_sbin_dir@ +PKG_SLIB_DIR = @pkg_slib_dir@ +PKG_INC_DIR = @pkg_inc_dir@ +PKG_MAN_DIR = @pkg_man_dir@ +PKG_DOC_DIR = @pkg_doc_dir@ + +# LCFLAGS, LLDFLAGS, LLDLIBS, LSRCFILES and LDIRT may be specified in +# user Makefiles. Note: LSRCFILES is anything other than Makefile, $(CFILES) +# $(CXXFILES), or $(HFILES) and is used to construct the manifest list +# during the "dist" phase (packaging). + +CFLAGS += -O1 $(OPTIMIZER) $(DEBUG) -funsigned-char -Wall $(LCFLAGS) \ + $(CPPFLAGS) '-DVERSION="$(PKG_VERSION)"' -D_FILE_OFFSET_BITS=64 \ + -D_GNU_SOURCE -DXFS_BIG_FILES=1 -DXFS_BIG_FILESYSTEMS=1 + +LDFLAGS = $(LLDFLAGS) +LDLIBS = $(LLDLIBS) $(MALLOCLIB) + +MAKEOPTS = --no-print-directory +SRCFILES = Makefile $(HFILES) $(CFILES) $(LSRCFILES) $(LFILES) $(YFILES) +DIRT = $(LDIRT) dep dep.bak $(OBJECTS) $(CMDTARGET) $(LIBTARGET) \ + $(STATICLIBTARGET) *.[1-9].gz + +OBJECTS = $(ASFILES:.s=.o) \ + $(CFILES:.c=.o) \ + $(LFILES:.l=.o) \ + $(YFILES:%.y=%.tab.o) + +MAKE = @make@ +CC = @cc@ +LD = @ld@ +AWK = @awk@ +SED = @sed@ +INSTALL = $(TOPDIR)/install-sh -o root -g root +ECHO = @echo@ +LN_S = @LN_S@ + +CCF = $(CC) $(CFLAGS) +MAKEF = $(MAKE) $(MAKEOPTS) +CXXF = $(CXX) $(CXXFLAGS) +LDF = $(LD) $(LDFLAGS) +MAKEDEPEND = @makedepend@ + +ZIP = @zip@ +TAR = @tar@ +RPM = @rpm@ +RPM_VERSION = @rpm_version@ + +HAVE_ZIPPED_MANPAGES = @have_zipped_manpages@ + +SHELL = /bin/sh +IMAGES_DIR = $(TOPDIR)/all-images +DIST_DIR = $(TOPDIR)/dist + +SUBDIRS_MAKERULE = \ + @for d in $(SUBDIRS) ""; do \ + if test -d "$$d" -a ! -z "$$d"; then \ + $(ECHO) === $$d ===; \ + $(MAKEF) -C $$d $@ || exit $$?; \ + fi; \ + done + +MAN_MAKERULE = \ + @for f in *.[12345678] ""; do \ + if test ! -z "$$f"; then \ + $(ZIP) --best -c < $$f > $$f.gz; \ + fi; \ + done + +INSTALL_MAN = \ + @for d in $(MAN_PAGES); do \ + first=true; \ + for m in `$(AWK) '/^\.SH NAME/ {ok=1; next} ok {print; exit}' $$d \ + | sed -e 's/,/ /g' -e 's/\\-.*//' -e 's/\\\f[0-9]//g' -e 's/ / /g;q'`; \ + do \ + [ -z "$$m" -o "$$m" = "\\" ] && continue; \ + t=$(MAN_DEST)/$$m.$(MAN_SECTION); \ + if $$first; then \ + if $(HAVE_ZIPPED_MANPAGES); then \ + $(ZIP) --best -c $$d > $$d.gz; _sfx=.gz; \ + fi; \ + u=$$m.$(MAN_SECTION)$$_sfx; \ + echo $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ + $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ + else \ + echo $(INSTALL) -S $$u $${t}$$_sfx; \ + $(INSTALL) -S $$u $${t}$$_sfx; \ + fi; \ + first=false; \ + done; \ + done + +DIST_MAKERULE = \ + $(MAKEF) -C build dist + +SOURCE_MAKERULE = \ + @test -z "$$DIR" && DIR="."; \ + for f in $(SRCFILES) ""; do \ + if test ! -z "$$f"; then $(ECHO) $$DIR/$$f; fi;\ + done; \ + for d in `echo $(SUBDIRS)` ; do \ + if test -d "$$d" -a ! -z "$$d"; then \ + $(MAKEF) DIR=$$DIR/$$d -C $$d $@ || exit $$?; \ + fi; \ + done + +endif + +# +# For targets that should always be rebuilt, +# define a target that is never up-to-date. +# Targets needing this should depend on $(_FORCE) +_FORCE = __force_build diff -rNu linux-2.4.7/cmd/xfsdump/include/buildrules linux-2.4-xfs/cmd/xfsdump/include/buildrules --- linux-2.4.7/cmd/xfsdump/include/buildrules Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/include/buildrules Sun Jan 14 22:42:23 2001 @@ -0,0 +1,77 @@ +# +# Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Fondation. +# +# This program is distributed in the hope that it would be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. Further, any license provided herein, +# whether implied or otherwise, is limited to this program in accordance with +# the express provisions of the GNU General Public License. Patent licenses, +# if any, provided herein do not apply to combinations of this program with +# other product or programs, or any other product whatsoever. This program is +# distributed without any warranty that the program is delivered free of the +# rightful claim of any third person by way of infringement or the like. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write the Free Software Foundation, Inc., 59 Temple +# Place - Suite 330, Boston MA 02111-1307, USA. +# Common build rules for gmake +# +ifndef _BUILDRULES_INCLUDED_ +_BUILDRULES_INCLUDED_ = 1 + +include $(TOPDIR)/include/builddefs + +# +# Standard targets +# +ifdef CMDTARGET +$(CMDTARGET) : $(SUBDIRS) $(OBJECTS) + $(CCF) -o $(CMDTARGET) $(LDFLAGS) $(OBJECTS) $(LDLIBS) +$(CMDTARGET).static : $(SUBDIRS) $(OBJECTS) + $(CCF) -static -o $(CMDTARGET).static $(LDFLAGS) $(OBJECTS) $(LDLIBS) +endif + +ifdef LIBTARGET +$(LIBTARGET) : $(SUBDIRS) $(OBJECTS) + $(CC) $(LDFLAGS) -fPIC -shared -Wl,-soname,$(LIBTARGET) -o $(LIBTARGET) $(OBJECTS) $(LDLIBS) +endif + +ifdef STATICLIBTARGET +$(STATICLIBTARGET) : $(SUBDIRS) $(OBJECTS) + $(AR) crf $(STATICLIBTARGET) $? +endif + +clean clobber : $(SUBDIRS) + rm -f $(DIRT) + $(SUBDIRS_MAKERULE) + +# Never blow away subdirs +ifdef SUBDIRS +.PRECIOUS: $(SUBDIRS) +$(SUBDIRS): + $(SUBDIRS_MAKERULE) +endif + +source : + $(SOURCE_MAKERULE) + +endif + +$(_FORCE): + +.PHONY : depend + +depend : $(CFILES) $(HFILES) + $(SUBDIRS_MAKERULE) + touch dep + $(MAKEDEPEND) -fdep -- $(CFLAGS) -- $(CFILES) + +# Include dep, but only if it exists +ifeq ($(shell test -f dep && echo dep), dep) +include dep +endif diff -rNu linux-2.4.7/cmd/xfsdump/install-sh linux-2.4-xfs/cmd/xfsdump/install-sh --- linux-2.4.7/cmd/xfsdump/install-sh Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/install-sh Sun Jan 14 22:35:39 2001 @@ -0,0 +1,273 @@ +#! /bin/sh +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +# +# This script emulates bsd install and also recognises +# two environment variables, with the following semantics :- +# +# $DIST_MANIFEST - if set, the name of the file to append manifest +# information in the following format: +# File : f mode owner group src target +# Directory: d mode owner group target +# Symlink : l linkval target +# +# $DIST_ROOT - if set, prepend to target +# +# The sematics of all combinations of these two variables +# are as follows: +# +# $DIST_MANIFEST? $DIST_ROOT? | Copy? Append Manifest? +# -----------------------------+-------------------------- +# not set not set | yes no +# not set set | yes no +# set not set | no yes +# set set | yes yes +# +_usage() { + echo "Usage: $prog [-o owner] [-g group] [-m mode] -d directory" + echo "or $prog [-D] [-o owner] [-g group] [-m mode] file directory/file" + echo "or $prog [-o owner] [-g group] [-m mode] file [file ...] directory" + echo "or $prog -S file target (creates \"target\" symlink)" + echo "" + echo "The \$DIST_MANIFEST and \$DIST_ROOT environment variables affect the" + echo "behaviour of this command - see comments in the script." + echo "The -D flag is only available for the second usage, and causes" + echo "the target directory to be created before installing the file." + echo "" + exit 1 +} + +_chown () +{ + _st=255 + if [ $# -eq 3 ] ; then + chown $1:$2 $3 + _st=$? + if [ $_st -ne 0 ] ; then + if [ $REAL_UID != '0' ] ; then + if [ ! -f $DIST_ROOT/.chown.quite ] ; then + echo '===============================================' + echo Ownership of files under ${DIST_ROOT:-/} + echo cannot be changed + echo '===============================================' + if [ -n "$DIST_ROOT" ] ; then + touch $DIST_ROOT/.chown.quite + fi + fi + _st=0 + fi + fi + fi + + return $_st +} + + +_manifest () +{ + echo $* | sed -e 's/\/\//\//g' >>${DIST_MANIFEST:-/dev/null} +} + +prog=`basename $0` +HERE=`pwd` +dflag=false +Dflag=false +Sflag=false +DIRMODE=755 +FILEMODE=644 +OWNER=`id -u` +GROUP=`id -g` +REAL_UID=$OWNER + +# default is to install and don't append manifest +INSTALL=true +MANIFEST=: + +[ -n "$DIST_MANIFEST" -a -z "$DIST_ROOT" ] && INSTALL=false +[ -n "$DIST_MANIFEST" ] && MANIFEST="_manifest" + +[ $# -eq 0 ] && _usage + +if $INSTALL +then + CP=cp; LN=ln; MKDIR=mkdir; CHMOD=chmod; CHOWN=_chown +else + CP=true; LN=true; MKDIR=true; CHMOD=true; CHOWN=true +fi + +[ -n "$DIST_ROOT" -a $REAL_UID -ne 0 ] && CHOWN=true + +while getopts "Dcm:d:S:o:g:" c $* +do + case $c in + c) + ;; + g) + GROUP=$OPTARG + ;; + o) + OWNER=$OPTARG + ;; + m) + DIRMODE=`expr $OPTARG` + FILEMODE=$DIRMODE + ;; + D) + Dflag=true + ;; + S) + symlink=$OPTARG + Sflag=true + ;; + d) + dir=$DIST_ROOT/$OPTARG + dflag=true + ;; + *) + _usage + ;; + esac +done + +shift `expr $OPTIND - 1` + +status=0 +if $dflag +then + # + # first usage + # + $MKDIR -p $dir + status=$? + if [ $status -eq 0 ] + then + $CHMOD $DIRMODE $dir + status=$? + fi + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir + status=$? + fi + $MANIFEST d $DIRMODE $OWNER $GROUP ${dir#$DIST_ROOT} +elif $Sflag +then + # + # fourth usage (symlink) + # + if [ $# -ne 1 ] + then + _usage + else + target=$DIST_ROOT/$1 + fi + $LN -s -f $symlink $target + status=$? + $MANIFEST l $symlink ${target#$DIST_ROOT} +else + list="" + dir="" + if [ $# -eq 2 ] + then + # + # second usage + # + f=$1 + dir=$DIST_ROOT/$2 + if $Dflag + then + mkdir -p `dirname $dir` + fi + $CP $f $dir + status=$? + if [ $status -eq 0 ] + then + if [ -f $dir/$f ] + then + $CHMOD $FILEMODE $dir/$f + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir/$f + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f + else + $CHMOD $FILEMODE $dir + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$dir ${dir#$DIST_ROOT} + fi + fi + else + # + # third usage + # + n=1 + while [ $# -gt 0 ] + do + if [ $# -gt 1 ] + then + list="$list $1" + else + dir=$DIST_ROOT/$1 + fi + shift + done + + # echo DIR=$dir list=\"$list\" + for f in $list + do + $CP $f $dir + status=$? + if [ $status -eq 0 ] + then + $CHMOD $FILEMODE $dir/$f + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir/$f + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f + fi + [ $status -ne 0 ] && break + done + fi +fi + +exit $status diff -rNu linux-2.4.7/cmd/xfsdump/inventory/CVS/Entries linux-2.4-xfs/cmd/xfsdump/inventory/CVS/Entries --- linux-2.4.7/cmd/xfsdump/inventory/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/CVS/Entries Thu Jul 5 11:44:06 2001 @@ -0,0 +1,14 @@ +/Makefile/1.2/Mon Jan 15 04:32:19 2001/-ko/ +/getopt.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/inv_api.c/1.2/Fri Apr 6 09:38:59 2001/-ko/ +/inv_core.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/inv_fstab.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/inv_idx.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/inv_mgr.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/inv_oref.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/inv_oref.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/inv_priv.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/inv_stobj.c/1.3/Mon May 7 02:37:12 2001/-ko/ +/inventory.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/testmain.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/inventory/CVS/Repository linux-2.4-xfs/cmd/xfsdump/inventory/CVS/Repository --- linux-2.4.7/cmd/xfsdump/inventory/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/CVS/Repository Thu Jul 5 11:44:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/inventory diff -rNu linux-2.4.7/cmd/xfsdump/inventory/CVS/Root linux-2.4-xfs/cmd/xfsdump/inventory/CVS/Root --- linux-2.4.7/cmd/xfsdump/inventory/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/CVS/Root Thu Jul 5 11:44:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/inventory/Makefile linux-2.4-xfs/cmd/xfsdump/inventory/Makefile --- linux-2.4.7/cmd/xfsdump/inventory/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/Makefile Sun Jan 14 22:32:19 2001 @@ -0,0 +1,41 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LSRCFILES = inv_api.c inv_core.c inv_fstab.c inv_idx.c inv_mgr.c \ + inv_oref.c inv_oref.h inv_priv.h inv_stobj.c inventory.h + +default install install-dev: + +include $(BUILDRULES) diff -rNu linux-2.4.7/cmd/xfsdump/inventory/getopt.h linux-2.4-xfs/cmd/xfsdump/inventory/getopt.h --- linux-2.4.7/cmd/xfsdump/inventory/getopt.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/getopt.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef GETOPT_H +#define GETOPT_H + +/* getopt.h common getopt command string + * + * several modules parse the command line looking for arguments specific to + * that module. Unfortunately, each of the getopt(3) calls needs the + * complete command string, to know how to parse. This file's purpose is + * to contain that command string. It also abstracts the option letters, + * facilitating easy changes. + */ + +#define GETOPT_CMDSTRING "gwrqdL:u:l:s:t:v:m:f:i" + +#define GETOPT_DUMPDEST 'f' /* dump dest. file (drive.c) */ +#define GETOPT_LEVEL 'l' /* dump level (content_inode.c) */ +#define GETOPT_SUBTREE 's' /* subtree dump (content_inode.c) */ +#define GETOPT_VERBOSITY 'v' /* verbosity level (0 to 4 ) */ +#define GETOPT_DUMPLABEL 'L' /* dump session label (global.c) */ +#define GETOPT_MEDIALABEL 'M' /* media object label (content.c) */ +#define GETOPT_RESUME 'R' /* resume intr dump (content_inode.c) */ +#define GETOPT_INVPRINT 'i' /* just display the inventory */ +/* + * f - dump destination: drive.c + * l - dump level content_inode.c + * s - subtree content.c + * v - verbosity mlog.c + * L - dump session label global.c + * M - media object label media.c + * R - resume interrupted dump content_inode.c + */ + +#endif /* GETOPT_H */ diff -rNu linux-2.4.7/cmd/xfsdump/inventory/inv_api.c linux-2.4-xfs/cmd/xfsdump/inventory/inv_api.c --- linux-2.4.7/cmd/xfsdump/inventory/inv_api.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/inv_api.c Fri Apr 6 04:38:59 2001 @@ -0,0 +1,1134 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "mlog.h" +#include "inv_priv.h" +#include "getopt.h" + + +/*----------------------------------------------------------------------*/ +/* inventory_open */ +/* */ +/* INV_BY_MOUNTPT, INV_BY_UUID or INV_BY_DEVPATH */ +/*----------------------------------------------------------------------*/ + +inv_idbtoken_t +inv_open( inv_predicate_t bywhat, inv_oflag_t forwhat, void *pred ) +{ + int fd, stobjfd, num, retval; + inv_idbtoken_t tok = INV_TOKEN_NULL; + invt_sescounter_t *sescnt = 0; + + int index = 0; + + ASSERT ( pred ); + fd = retval = init_idb ( pred, bywhat, forwhat, &tok ); + + if ( retval == I_DONE ) + return tok; + + /* if we just want to search the db, all we need is the invidx. + at this point, we know that a tok wasnt created in init_idb() */ + if ( forwhat == INV_SEARCH_ONLY ) { + /* fd == I_EMPTYINV or fd == valid fd */ + tok = get_token( fd, -1); + tok->d_oflag = forwhat; + return tok; + } + + /* XXX also, see if it is too full. if so, make another and leave a + reference to the new file in the old one */ + + stobjfd = idx_get_stobj( fd, forwhat, &index ); + if ( stobjfd < 0 ) { + close( fd ); + return INV_TOKEN_NULL; + } + + ASSERT ( index > 0 ); + + /* Now we need to make sure that this has enough space */ + INVLOCK( stobjfd, LOCK_SH ); + + num = GET_SESCOUNTERS( stobjfd, &sescnt ); + if ( num < 0 ) { + close( fd ); + INVLOCK( stobjfd, LOCK_UN ); + close( stobjfd ); + return INV_TOKEN_NULL; + } + + /* create another storage object ( and, an inv_index entry for it + too ) if we've filled this one up */ + + if ( (u_int) num >= sescnt->ic_maxnum ) { + mlog( MLOG_DEBUG | MLOG_INV, "$ INV: creating a new storage obj & " + "index entry. \n" ); + INVLOCK( stobjfd, LOCK_UN ); + close (stobjfd); + + INVLOCK( fd, LOCK_EX ); + stobjfd = idx_create_entry( &tok, fd, BOOL_FALSE ); + INVLOCK( fd, LOCK_UN ); + + free ( sescnt ); + if ( stobjfd < 0 ) { + close( fd ); + return INV_TOKEN_NULL; + } + return tok; + } + + INVLOCK( stobjfd, LOCK_UN ); + + free ( sescnt ); + tok = get_token( fd, stobjfd ); + tok->d_invindex_off = IDX_HDR_OFFSET( index - 1 ); + tok->d_oflag = forwhat; + return tok; + +} + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + + +bool_t +inv_close( inv_idbtoken_t tok ) +{ + close ( tok->d_invindex_fd ); + if ( tok->d_stobj_fd >= 0 ) + close ( tok->d_stobj_fd ); + destroy_token( tok ); + return BOOL_TRUE; +} + + + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +inv_sestoken_t +inv_writesession_open( + inv_idbtoken_t tok, /* token obtained by inventory_open() */ + uuid_t *fsid, + uuid_t *sesid, + char *label, + bool_t ispartial, + bool_t isresumed, + u_char level, + u_int nstreams, + time_t time, + char *mntpt, + char *devpath ) +{ + invt_session_t ses; + int fd; + intgen_t rval; + invt_sescounter_t *sescnt = NULL; + invt_seshdr_t hdr; + inv_sestoken_t sestok; + inv_oflag_t forwhat; + + ASSERT ( tok != INV_TOKEN_NULL ); + ASSERT ( sesid && fsid && mntpt && devpath ); + forwhat = tok->d_oflag; + fd = tok->d_stobj_fd; + ASSERT ( forwhat != INV_SEARCH_ONLY ); + ASSERT ( fd > 0 ); + + if ( ! ( tok->d_update_flag & FSTAB_UPDATED ) ) { + if ( fstab_put_entry( fsid, mntpt, devpath, forwhat ) < 0 ) { + mlog( MLOG_NORMAL | MLOG_INV, "INV: put_fstab_entry failed.\n"); + return INV_TOKEN_NULL; + } + tok->d_update_flag |= FSTAB_UPDATED; + } + + + /* copy the session information to store */ + memset( (void *)&ses, 0, sizeof( ses ) ); /* paranoia */ + memcpy( &ses.s_sesid, sesid, sizeof( uuid_t ) ); + memcpy( &ses.s_fsid, fsid, sizeof( uuid_t ) ); + strcpy( ses.s_label, label ); + strcpy( ses.s_mountpt, mntpt ); + strcpy( ses.s_devpath, devpath ); + ses.s_max_nstreams = nstreams; + + hdr.sh_pruned = 0; /* session is not pruned by invutil */ + hdr.sh_time = time; + hdr.sh_level = level; + hdr.sh_flag = (ispartial) ? INVT_PARTIAL: 0; + hdr.sh_flag |= (isresumed) ? INVT_RESUMED : 0; + /* sh_streams_off and sh_sess_off will be set in create_session() */ + + sestok = get_sesstoken( tok ); + + /* we need to put the new session in the appropriate place in + storage object. So first find out howmany sessions are there */ + + INVLOCK( fd, LOCK_EX ); + if ( GET_SESCOUNTERS( fd, &sescnt) < 0 ) { + free ( sestok ); + INVLOCK( fd, LOCK_UN ); + return INV_TOKEN_NULL; + } + + /* create the writesession, and get ready for the streams to come + afterwards */ + rval = stobj_create_session( sestok, fd, sescnt, &ses, &hdr ); + ASSERT (rval > 0); + + + INVLOCK( fd, LOCK_UN ); + + sestok->sd_sesstime = time; + + if ( tok->d_update_flag & NEW_INVINDEX ) { + if ( idx_put_sesstime( sestok, INVT_STARTTIME ) < 0 ) { + mlog( MLOG_NORMAL | MLOG_INV, "INV: put_starttime failed.\n"); + return INV_TOKEN_NULL; + } + tok->d_update_flag &= ~(NEW_INVINDEX); + } + + free ( sescnt ); + + + return ( rval < 0 )? INV_TOKEN_NULL: sestok; +} + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + + +bool_t +inv_writesession_close( inv_sestoken_t tok ) +{ + int rval; + + ASSERT ( tok != INV_TOKEN_NULL ); + + /* now update end_time in the inv index header */ + rval = idx_put_sesstime( tok, INVT_ENDTIME ); + + memset( tok, 0, sizeof( invt_sesdesc_entry_t ) ); + free ( tok ); + + return ( rval < 0 ) ? BOOL_FALSE: BOOL_TRUE; + +} + + + +/*----------------------------------------------------------------------*/ +/* inventory_stream_open */ +/* */ +/* Opens a stream for mediafiles to be put in. */ +/*----------------------------------------------------------------------*/ +inv_stmtoken_t +inv_stream_open( + inv_sestoken_t tok, + char *cmdarg ) +{ + inv_stmtoken_t stok; + invt_stream_t stream; + invt_session_t ses; + invt_seshdr_t seshdr; + int fd; + bool_t err = BOOL_FALSE; + + ASSERT ( tok != INV_TOKEN_NULL ); + + /* this memset is needed as a dump interrupted/crashed very soon + * after starting results in an inventory with exteremely large + * starting/ending inodes or offsets. This can be misleading. + * See bug #463702 for an example. + */ + memset( (void *)&stream, 0 , sizeof(invt_stream_t) ); + + stream.st_nmediafiles = 0; + stream.st_interrupted = BOOL_TRUE; /* fix for 353197 */ + strcpy( stream.st_cmdarg, cmdarg ); + + /* XXX yukk... make the token descriptors not pointers */ + stok = ( inv_stmtoken_t ) malloc( sizeof( invt_strdesc_entry_t ) ); + + stok->md_sesstok = tok; + stok->md_lastmfile = 0; + + /* get the session to find out where the stream is going to go */ + fd = tok->sd_invtok->d_stobj_fd; + + INVLOCK( fd, LOCK_EX ); + + /* get the session header and the session */ + if ( stobj_get_sessinfo( tok, &seshdr, &ses ) <= 0 ) + err = BOOL_TRUE; + + if ( ( ! err ) && ses.s_cur_nstreams < ses.s_max_nstreams ) { + /* this is where this stream header will be written to */ + stok->md_stream_off = (off64_t) (sizeof( invt_stream_t ) * + ses.s_cur_nstreams ) + + seshdr.sh_streams_off; + ses.s_cur_nstreams++; + + /* write it back. */ + if ( PUT_REC_NOLOCK( fd, &ses, sizeof( ses ), + tok->sd_session_off ) < 0 ) + err = BOOL_TRUE; + } else if ( ! err ) { + mlog ( MLOG_NORMAL, "INV: cant create more than %d streams." + " Max'd out..\n", ses.s_cur_nstreams ); + err = BOOL_TRUE; + } + + if ( ! err ) { + stream.st_firstmfile = stream.st_lastmfile = + stok->md_stream_off; + + /* now write the stream header on to the disk */ + if ( PUT_REC_NOLOCK( fd, &stream, sizeof( invt_stream_t ), + stok->md_stream_off ) > 0 ) { + /* we're all set */ + INVLOCK( fd, LOCK_UN ); + return stok; + } + } + + /* error occured somewhere */ + free ( stok ); + INVLOCK( fd, LOCK_UN ); + return INV_TOKEN_NULL; + +} + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +bool_t +inv_stream_close( + inv_stmtoken_t tok, + bool_t wasinterrupted ) +{ + invt_stream_t strm; + int fd = tok->md_sesstok->sd_invtok->d_stobj_fd; + int rval; + bool_t dowrite = BOOL_FALSE; + + rval = idx_put_sesstime( tok->md_sesstok, INVT_ENDTIME ); + if (rval < 0) + mlog( MLOG_NORMAL | MLOG_INV, "INV: idx_put_sesstime failed in " + "inv_stream_close() \n"); + INVLOCK( fd, LOCK_EX ); + if ((rval = GET_REC_NOLOCK( fd, &strm, sizeof( invt_stream_t ), + tok->md_stream_off )) > 0 ) { + + if ( strm.st_interrupted != wasinterrupted ) { + strm.st_interrupted = wasinterrupted; + dowrite = BOOL_TRUE; + } + + /* get the last media file to figure out what our last + ino was. we have a pointer to that in the stream token */ + if ( tok->md_lastmfile ){ + if ( strm.st_endino.ino != + tok->md_lastmfile->mf_endino.ino || + strm.st_endino.offset != + tok->md_lastmfile->mf_endino.offset) { + + mlog( MLOG_DEBUG | MLOG_INV, "INV: stream_close() " + " - endinos dont match ! \n"); + dowrite = BOOL_TRUE; + strm.st_endino = tok->md_lastmfile->mf_endino; + } + } + + if (dowrite) { + rval = PUT_REC_NOLOCK_SEEKCUR( fd, &strm, + sizeof( invt_stream_t ), + -(off64_t)(sizeof( invt_stream_t )) ); + } + } + + INVLOCK( fd, LOCK_UN ); + + if ( tok->md_lastmfile ) { + free ( tok->md_lastmfile ); + } + memset( tok, 0, sizeof( invt_strdesc_entry_t ) ); + free ( tok ); + + return ( rval < 0 ) ? BOOL_FALSE: BOOL_TRUE; +} + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +bool_t +inv_put_mediafile( + inv_stmtoken_t tok, + uuid_t *moid, + char *label, + u_int mfileindex, + xfs_ino_t startino, + off64_t startino_offset, + xfs_ino_t endino, + off64_t endino_offset, + off64_t size, + bool_t isgood, + bool_t isinvdump) +{ + invt_mediafile_t *mf; + int rval; + + + ASSERT ( tok != INV_TOKEN_NULL ); + ASSERT ( tok->md_sesstok->sd_invtok->d_update_flag & FSTAB_UPDATED ); + ASSERT ( tok->md_sesstok->sd_invtok->d_stobj_fd >= 0 ); + + mf = (invt_mediafile_t *) calloc( 1, sizeof( invt_mediafile_t ) ); + + /* copy the media file information */ + memcpy( &mf->mf_moid, moid, sizeof( uuid_t ) ); + strcpy( mf->mf_label, label ); + mf->mf_mfileidx = mfileindex; + mf->mf_startino.ino = startino; + mf->mf_startino.offset = startino_offset; + mf->mf_endino.ino = endino; + mf->mf_endino.offset = endino_offset; + mf->mf_size = size; + mf->mf_flag = 0; + if ( isgood ) + mf->mf_flag |= INVT_MFILE_GOOD; + + /* This flag is used to indicate the media file that contains the + dump of the sessioninfo structure that contains all but this + media file */ + if ( isinvdump ) + mf->mf_flag |= INVT_MFILE_INVDUMP; + + INVLOCK( tok->md_sesstok->sd_invtok->d_stobj_fd, LOCK_EX ); + rval = stobj_put_mediafile( tok, mf ); + INVLOCK( tok->md_sesstok->sd_invtok->d_stobj_fd, LOCK_UN ); + + /* we dont free the mfile here. we always keep the last mfile + around, inside the inv_stmtoken, and when we add a new mfile, + we free the previous one. The last one is freed in stream_close() + */ + + return ( rval < 0 ) ? BOOL_FALSE: BOOL_TRUE; + +} + + + + + +/*----------------------------------------------------------------------*/ +/* inv_get_sessioninfo */ +/* */ +/* This is to be called after a write-session is complete, but before it*/ +/* is closed. ie. the token must still be valid, and all the streams */ +/* and their mediafiles put in the inventory. */ +/* */ +/* On return, the buffer will be filled with all the data pertinent to */ +/* the session referred to by the session token. The application of this*/ +/* is to dump the inventory of a session to a media object. */ +/*----------------------------------------------------------------------*/ + +bool_t +inv_get_sessioninfo( + inv_sestoken_t tok, + void **bufpp, /* buf to fill */ + size_t *bufszp )/* size of that buffer */ +{ + invt_session_t ses; + invt_seshdr_t hdr; + bool_t rval; + int fd; + + + ASSERT( tok != INV_TOKEN_NULL ); + ASSERT( tok->sd_invtok ); + *bufpp = NULL; + *bufszp = 0; + fd = tok->sd_invtok->d_stobj_fd; + + INVLOCK( fd, LOCK_SH ); + + /* Next we get the session header, and the session information. Then + we can figure out how much space to allocate */ + if ( stobj_get_sessinfo( tok, &hdr, &ses ) <= 0 ) { + INVLOCK( fd, LOCK_UN ); + return BOOL_FALSE; + } + + rval = stobj_pack_sessinfo( fd, &ses, &hdr, bufpp, bufszp ); + INVLOCK( fd, LOCK_UN ); + + + return rval; +} + + + + +/*----------------------------------------------------------------------*/ +/* inv_put_sessioninfo */ +/* */ +/* This is used in reconstructing an inventory from dumped media objects*/ +/* */ +/* Most importantly, note that this is not in anyway an alternative to */ +/* inv_open_writesession() - that is called while the dump is in progr- */ +/* ess. This is really inv_put_dumpedsession(); We just didn't want to */ +/* be *that* dump-specific :) */ +/*----------------------------------------------------------------------*/ + +bool_t +inv_put_sessioninfo( invt_sessinfo_t *s ) +{ + static bool_t invdir_ok = BOOL_FALSE; + + if ( !invdir_ok ) { + if ( make_invdirectory( INV_SEARCH_N_MOD ) < 0 ) + return BOOL_FALSE; + else + invdir_ok = BOOL_TRUE; + } + + return insert_session( s ); + +} + + + + +/*----------------------------------------------------------------------*/ +/* inv_free_session */ +/* */ +/* free the inv_session structure allocated as a result of calls to */ +/* inv_get_session_byuuid, etc. */ +/*----------------------------------------------------------------------*/ +void +inv_free_session( + inv_session_t **ses) +{ + uint i; + + ASSERT(ses); + ASSERT(*ses); + + for ( i = 0; i < (*ses)->s_nstreams; i++ ) { + /* the array of mediafiles is contiguous */ + free ((*ses)->s_streams[i].st_mediafiles); + } + + /* all streams are contiguous too */ + free ((*ses)->s_streams); + + free (*ses); + *ses = NULL; +} + + +/*----------------------------------------------------------------------*/ +/* inventory_lasttime_level_lessthan */ +/* */ +/* Given a token that refers to a file system, and a level, this returns*/ +/* the last time when a session of a lesser level was done. */ +/* */ +/* returns -1 on error. */ +/*----------------------------------------------------------------------*/ + +bool_t +inv_lasttime_level_lessthan( + inv_idbtoken_t tok, + u_char level, + time_t **tm ) +{ + int rval; + if ( tok != INV_TOKEN_NULL ) { + rval = search_invt( tok->d_invindex_fd, &level, (void **) tm, + (search_callback_t) tm_level_lessthan ); + + return ( rval < 0) ? BOOL_FALSE: BOOL_TRUE; + } + + return invmgr_query_all_sessions((void *) &level, /* in */ + (void **) tm, /* out */ + (search_callback_t) tm_level_lessthan); +} + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +bool_t +inv_lastsession_level_lessthan( + inv_idbtoken_t tok, + u_char level, + inv_session_t **ses ) +{ + int rval; + if ( tok != INV_TOKEN_NULL ) { + rval = search_invt( tok->d_invindex_fd, &level, (void **) ses, + (search_callback_t) lastsess_level_lessthan ); + + return ( rval < 0) ? BOOL_FALSE: BOOL_TRUE; + } + + return invmgr_query_all_sessions((void *) &level, /* in */ + (void **) ses, /* out */ + (search_callback_t) lastsess_level_lessthan); + +} + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* Return FALSE on an error, TRUE if not. If (*ses) is NULL, then the */ +/* search failed. */ +/*----------------------------------------------------------------------*/ + + +bool_t +inv_lastsession_level_equalto( + inv_idbtoken_t tok, + u_char level, + inv_session_t **ses ) +{ + int rval; + if ( tok != INV_TOKEN_NULL ) { + rval = search_invt( tok->d_invindex_fd, &level, (void **) ses, + (search_callback_t) lastsess_level_equalto ); + + return ( rval < 0) ? BOOL_FALSE: BOOL_TRUE; + } + + return invmgr_query_all_sessions((void *) &level, /* in */ + (void **) ses, /* out */ + (search_callback_t) lastsess_level_equalto); + +} + + +/*----------------------------------------------------------------------*/ +/* inv_getsession_byuuid */ +/* */ +/*----------------------------------------------------------------------*/ + +bool_t +inv_get_session_byuuid( + uuid_t *sesid, + inv_session_t **ses) +{ + + return (invmgr_query_all_sessions((void *)sesid, /* in */ + (void **) ses, /* out */ + (search_callback_t) stobj_getsession_byuuid)); +} + + + +/*----------------------------------------------------------------------*/ +/* inv_getsession_byuuid */ +/* */ +/*----------------------------------------------------------------------*/ + +bool_t +inv_get_session_bylabel( + char *session_label, + inv_session_t **ses) +{ + + return (invmgr_query_all_sessions((void *)session_label, /* in */ + (void **) ses, /* out */ + (search_callback_t) stobj_getsession_bylabel)); +} + + +/*----------------------------------------------------------------------*/ +/* inv_delete_mediaobj */ +/* */ +/* We delete all the media files that are stored in the given mobj, and */ +/* delete them one by one. We delete the session information only when */ +/* all its mediafiles are deleted. This is because a single session can */ +/* be striped across multiple mediaobjects. */ +/*----------------------------------------------------------------------*/ + +bool_t +inv_delete_mediaobj( uuid_t *moid ) +{ + inv_oflag_t forwhat = INV_SEARCH_N_MOD; + + /* forall fsids (fs) in fstab { + open invindex table (t) + forall indices (i) in t { + open stobj (st) + forall sessions (s) in st { + forall streams (strm) in s { + forall mediafiles (m) in strm { + if (m.mediaobj == moid) { + // delete m + if ( --strm.nmediafiles == 0 ) + if ( --s.nstreams == 0 ) + delete-session (s) + } + } + } + } + } + */ + + invt_counter_t *cnt; + invt_fstab_t *arr; + int numfs, i, fd, invfd; + char fname[INV_STRLEN]; + + fd = fstab_getall( &arr, &cnt, &numfs, forwhat ); + if ( fd < 0 || numfs <= 0 ) { + mlog( MLOG_NORMAL | MLOG_INV, "INV: Error in fstab\n" ); + return BOOL_FALSE; + } + + close( fd ); + + for ( i = 0; i < numfs; i++) { + if ( fstab_get_fname( &arr[i].ft_uuid, + fname, + (inv_predicate_t)INV_BY_UUID, + forwhat + ) + < 0 ) { + mlog( MLOG_NORMAL | MLOG_INV, + "INV: Cant get inv-name for uuid\n" + ); + return BOOL_FALSE; + } + strcat( fname, INV_INVINDEX_PREFIX ); + invfd = open( fname, INV_OFLAG(forwhat)); + if ( invfd < 0 ) { + mlog( MLOG_NORMAL | MLOG_INV, + "INV: Open failed on %s\n", + fname + ); + return BOOL_FALSE; + } + + if ( search_invt( invfd, NULL, (void **)&moid, + (search_callback_t) stobj_delete_mobj ) + < 0 ) + return BOOL_FALSE; + /* we have to delete the session, etc */ + close( invfd ); + } + + return BOOL_TRUE; +} + + + +#define I_IFOUND 0x01 +#define I_IDONE 0x02 +#define I_IERR 0x04 + + +static const char *myopts[] = { +#define OPT_MNT 0 + "mnt", + +#define OPT_FSID 1 + "fsid", + +#define OPT_DEV 2 + "dev", + +#define OPT_DEPTH 3 + "depth", + +#define OPT_MOBJID 4 + "mobjid", + +#define OPT_MOBJLABEL 5 + "mobjlabel", + +#define OPT_FSTAB 6 + "fstab", + +#define OPT_INVIDX 7 + "invidx", + +#define OPT_INVCHECK 8 + "check", + +#define OPT_INVLEVEL 9 + "level", + + NULL +}; + + +intgen_t +inv_getopt(int argc, char **argv, invt_pr_ctx_t *prctx) +{ + intgen_t rval = 0; + void *fs = 0; + char *options, *value; + extern char *optarg; + extern int optind, opterr; + + inv_predicate_t bywhat = -1; + int c, d; + uuid_t fsid; + int npreds = 0; + int npreds2 = 0; + char invoptstring[128], *rptr, *wptr; + optind = 1; + opterr = 0; + + /* + * getopt doesn't handle both '-I' and '-I w/subopts' so... + * First set I_IFOUND if -I is set at all (with or without + * any suboptions). Do this by taking out the ':' so getopt + * accepts it. Later, reset opts and go through again to + * pick off any subopts. + */ + strcpy(invoptstring, GETOPT_CMDSTRING); + wptr = strchr(invoptstring, 'I'); + if (wptr != NULL) { + wptr++; + rptr = wptr + 1; + while (*wptr != '\0') + *wptr++ = *rptr++; + while ( ( c = getopt( argc, argv, invoptstring)) != EOF ) { + switch ( c ) { + case GETOPT_INVPRINT: + prctx->depth = 0; + rval |= I_IFOUND ; + break; + } + } + optind = 1; + opterr = 0; + optarg = NULL; + } + + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + switch ( c ) { + case GETOPT_INVPRINT: + rval |= I_IFOUND ; + if ((options = optarg) == NULL) + break; + + while (*options != '\0') { + d = getsubopt(&options,(constpp)myopts,&value); + if (value == NULL && d != OPT_FSTAB && + d != OPT_INVIDX && d != OPT_INVCHECK) + continue; + switch( d ) { + /* process mntpt option */ + case OPT_MNT: + bywhat = (inv_predicate_t) INV_BY_MOUNTPT; + fs = value; + npreds++; + break; + + /* process fsid option */ + case OPT_FSID: + bywhat = (inv_predicate_t) INV_BY_UUID; + npreds++; + + uuid_unparse(value, fsid); + break; + + case OPT_DEV: /* process dev option */ + bywhat = (inv_predicate_t) INV_BY_DEVPATH; + fs = value; + npreds++; + break; + + case OPT_DEPTH: + prctx->depth = atoi(value); + if (prctx->depth < 0 || + prctx->depth > 4 ) + prctx->depth = 0; + break; + + case OPT_MOBJID: + { + uuid_t *u; + u = malloc ( sizeof( uuid_t ) ); + uuid_unparse(value, *u); + prctx->mobj.type = INVT_MOID; + uuid_copy(prctx->mobj.value, *u); + } + npreds2++; + break; + + case OPT_MOBJLABEL: + prctx->mobj.type = INVT_LABEL; + prctx->mobj.value = (void *)value; + npreds2++; + break; + + case OPT_FSTAB: + prctx->fstab = BOOL_TRUE; + break; + + case OPT_INVIDX: + prctx->invidx = BOOL_TRUE; + break; + + case OPT_INVCHECK: + prctx->invcheck = BOOL_TRUE; + break; + + case OPT_INVLEVEL: + prctx->level = atoi(value); + break; + + default: + if ( strlen(value) == 1 && + atoi(value) < PR_MAXDEPTH ) + prctx->depth = atoi(value); + else { + mlog( MLOG_NORMAL | MLOG_INV, + "INV: invalid sub-option %s" + " for -I option\n", value ); + rval |= I_IERR; + } + break; + } + } + break; /* case GETOPT_INVPRINT */ + } + + } + + if (npreds > 1) { + mlog( MLOG_NORMAL | MLOG_INV, + "INV: Only one of mnt=,dev= and fsid=value can be used.\n" + ); + rval |= I_IERR; + } + else if (npreds2 > 1) { + mlog( MLOG_NORMAL | MLOG_INV, + "INV: Only one of mobjid= and mobjlabel= can be used.\n" + ); + rval |= I_IERR; + } + else if ( (rval & I_IFOUND) && !(rval & I_IERR) && fs + && ! prctx->fstab && ! prctx->invcheck) { + inv_idbtoken_t tok; + + /* A filesystem could be backed up, mkfs'ed then restored + * to a new UUID value. Therefore, we can't simply stop + * when we find the first matching mount point (pv564234). + * This code loops through all filesystems and does the + * comparison by hand. */ + if (bywhat == INV_BY_MOUNTPT) { + int fd, numfs, i; + invt_fstab_t *arr = NULL; + invt_counter_t *cnt = NULL; + inv_oflag_t forwhat = INV_SEARCH_ONLY; + + fd = fstab_getall( &arr, &cnt, &numfs, forwhat ); + free( cnt ); + + rval |= I_IERR; /* Cleared if successful */ + + if ( fd >= 0 ) { + for ( i = 0; i < numfs; i++ ) { + tok = inv_open( + (inv_predicate_t )INV_BY_UUID, + INV_SEARCH_ONLY, + &arr[i].ft_uuid ); + if ( tok == INV_TOKEN_NULL ) + break; + if ( STREQL( arr[i].ft_mountpt, fs) ) { + prctx->index = i; + invmgr_inv_print( + tok->d_invindex_fd, + prctx ); + rval &= ~(I_IERR); + } + inv_close( tok ); + } + free ( arr ); + rval |= I_IDONE; + } + if ( (rval&I_IERR) ) { + mlog( MLOG_NORMAL | MLOG_INV, + "INV: open failed on mount point \"%s\"\n", + fs); + } + return rval; + } + + /* We have to print only one file system to print by UUID */ + tok = inv_open( bywhat, INV_SEARCH_ONLY, fs); + if ( tok != INV_TOKEN_NULL ) { + prctx->index = 0; + invmgr_inv_print(tok->d_invindex_fd, prctx); + inv_close( tok ); + rval |= I_IDONE; + } else { + mlog( MLOG_NORMAL | MLOG_INV, + "INV: open failed on file system id \"%s\"\n", fs); + rval |= I_IERR; + } + } + + return rval; +} + +/* This prints out all the sessions of a filesystem that are in the inventory */ +bool_t +inv_DEBUG_print( int argc, char **argv ) +{ + invt_counter_t *cnt = NULL; + invt_fstab_t *arr = NULL; + int fd, numfs, i; + inv_idbtoken_t tok; + int rval; + invt_pr_ctx_t prctx; + inv_oflag_t forwhat = INV_SEARCH_ONLY; + prctx.mobj.type = INVT_NULLTYPE; + prctx.fstab = prctx.invidx = prctx.invcheck = BOOL_FALSE; + prctx.level = PR_MAXLEVEL; + + /* If user didnt indicate -i option, we can't do anything */ + rval = inv_getopt( argc, argv, &prctx ); + + if (!prctx.invcheck && ! prctx.fstab) { + if (! (rval & I_IFOUND)) { + return BOOL_TRUE; + } else if ( rval & I_IERR || rval & I_IDONE ) { + return BOOL_FALSE; + } + } + + fd = fstab_getall( &arr, &cnt, &numfs, forwhat ); + free( cnt ); + + if ( fd >= 0 ) { + if (prctx.fstab) { + fstab_DEBUG_print( arr, numfs ); + if (! prctx.invidx) + return BOOL_FALSE; + } + + for ( i = 0; i < numfs; i++ ) { + tok = inv_open( ( inv_predicate_t )INV_BY_UUID, + forwhat, + &arr[i].ft_uuid ); + if ( tok == INV_TOKEN_NULL ) { + free ( arr ); + return BOOL_FALSE; + } + + if (prctx.invcheck) { + mlog( MLOG_VERBOSE | MLOG_INV, + "INV: checking fs \"%s\"\n", + &arr[i].ft_mountpt + ); + invmgr_inv_check(tok->d_invindex_fd); + } + else { + prctx.index = i; + invmgr_inv_print( tok->d_invindex_fd, + &prctx ); + } + inv_close( tok ); + } + } + + return BOOL_FALSE; +} + +#undef I_IFOUND +#undef I_IDONE +#undef I_IERR diff -rNu linux-2.4.7/cmd/xfsdump/inventory/inv_core.c linux-2.4-xfs/cmd/xfsdump/inventory/inv_core.c --- linux-2.4.7/cmd/xfsdump/inventory/inv_core.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/inv_core.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include "types.h" +#include "inv_priv.h" + + + +/*----------------------------------------------------------------------*/ +/* get_counters, get_headers, get_invtrecord, put_invtrecord, ... */ +/* */ +/* These implement low level routines that take care of disk I/Os. */ +/* In most cases, the caller has the option of locking before calling */ +/* the routine. */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +get_counters( int fd, void **cntpp, size_t cntsz ) +{ + /* object must be locked at least SHARED by caller */ + u_int num; + ASSERT( cntsz >= sizeof( invt_counter_t ) ); + + *cntpp = calloc( 1, cntsz); + + /* find the number of sessions and the max possible */ + if ( GET_REC_NOLOCK( fd, (void *) *cntpp, cntsz, (off64_t) 0 ) < 0 ) { + free( *cntpp ); + *cntpp = NULL; + return -1; + } + + num = ((invt_counter_t *)(*cntpp))->ic_curnum; + + if ( ( (invt_counter_t *)(*cntpp))->ic_vernum != INV_VERSION ) { + mlog( MLOG_NORMAL | MLOG_INV, + "INV : Unknown version %d - Expected version %d \n", + (int) ( (invt_counter_t *)(*cntpp))->ic_vernum, + (int) INV_VERSION ); + ASSERT ( ((invt_counter_t *)(*cntpp))->ic_vernum == + INV_VERSION ); + } + + return (intgen_t) num; +} + + + + + +/*----------------------------------------------------------------------*/ +/* get_headers */ +/*----------------------------------------------------------------------*/ + +intgen_t +get_headers( int fd, void **hdrs, size_t bufsz, size_t off ) +{ + + *hdrs = malloc( bufsz ); + if ( *hdrs == NULL ) { + INV_PERROR( "get_headers() - malloc(seshdrs)\n" ); + return -1; + } + /* file must be locked at least SHARED by caller */ + + /* get the array of hdrs */ + if ( GET_REC_NOLOCK( fd, (void *) *hdrs, bufsz, (off64_t)off ) < 0 ) { + free ( *hdrs ); + *hdrs = NULL; + return -1; + } + + return 1; +} + + + +/*----------------------------------------------------------------------*/ +/* get_invtrecord */ +/*----------------------------------------------------------------------*/ + +intgen_t +get_invtrecord( int fd, void *buf, size_t bufsz, off64_t off, + int whence, bool_t dolock ) +{ + int nread; + + ASSERT ( fd >= 0 ); + + if ( dolock ) + INVLOCK( fd, LOCK_SH ); + + if ( lseek( fd, (off_t)off, whence ) < 0 ) { + INV_PERROR( "Error in reading inventory record " + "(lseek failed): " ); + if ( dolock ) + INVLOCK( fd, LOCK_UN ); + return -1; + } + + nread = read( fd, buf, bufsz ); + + if ( nread != (int) bufsz ) { + INV_PERROR( "Error in reading inventory record :" ); + if ( dolock ) + INVLOCK( fd, LOCK_UN ); + return -1; + } + + if ( dolock ) + INVLOCK( fd, LOCK_UN ); + + return nread; +} + + + + + + +/*----------------------------------------------------------------------*/ +/* put_invtrecord */ +/*----------------------------------------------------------------------*/ + +intgen_t +put_invtrecord( int fd, void *buf, size_t bufsz, off64_t off, + int whence, bool_t dolock ) +{ + int nwritten; + + if ( dolock ) + INVLOCK( fd, LOCK_EX ); + + if ( lseek( fd, (off_t)off, whence ) < 0 ) { + INV_PERROR( "Error in writing inventory record " + "(lseek failed): " ); + if ( dolock ) + INVLOCK( fd, LOCK_UN ); + return -1; + } + + if (( nwritten = write( fd, buf, bufsz ) ) != (int) bufsz ) { + INV_PERROR( "Error in writing inventory record :" ); + if ( dolock ) + INVLOCK( fd, LOCK_UN ); + return -1; + } + + if ( dolock ) + INVLOCK( fd, LOCK_UN ); + return nwritten; +} + + + + + + + +/*----------------------------------------------------------------------*/ +/* get_headerinfo */ +/*----------------------------------------------------------------------*/ + + +intgen_t +get_headerinfo( int fd, void **hdrs, void **cnt, + size_t hdrsz, size_t cntsz, bool_t dolock ) +{ + int num; + + /* get a lock on the table for reading */ + if ( dolock ) INVLOCK( fd, LOCK_SH ); + + num = get_counters( fd, cnt, cntsz ); + + /* If there are no sessions recorded yet, we're done too */ + if ( num > 0 ) { + if ( get_headers( fd, hdrs, hdrsz * (size_t)num, cntsz ) < 0 ) { + free ( *cnt ); + num = -1; + } + } + + if ( dolock ) INVLOCK( fd, LOCK_UN ); + return num; +} + + + +/*----------------------------------------------------------------------*/ +/* get_lastheader */ +/*----------------------------------------------------------------------*/ + +intgen_t +get_lastheader( int fd, void **ent, size_t hdrsz, size_t cntsz ) +{ + int nindices; + void *arr = NULL; + invt_counter_t *cnt = NULL; + char *pos; + /* get the entries in the inv_index */ + if ( ( nindices = GET_ALLHDRS_N_CNTS( fd, &arr, (void **)&cnt, + hdrsz, cntsz )) <= 0 ) { + return -1; + } + + /* if there's space anywhere at all, then it must be in the last + entry */ + *ent = malloc( hdrsz ); + pos = (char *) arr + ( (u_int)nindices - 1 ) * hdrsz; + memcpy( *ent, pos, hdrsz ); + free ( arr ); + free ( cnt ); + + return nindices; +} + + + + + + + + + + + + + + + + + + diff -rNu linux-2.4.7/cmd/xfsdump/inventory/inv_fstab.c linux-2.4-xfs/cmd/xfsdump/inventory/inv_fstab.c --- linux-2.4.7/cmd/xfsdump/inventory/inv_fstab.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/inv_fstab.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "mlog.h" +#include "inv_priv.h" + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + + +intgen_t +fstab_getall( invt_fstab_t **arr, invt_counter_t **cnt, int *numfs, + inv_oflag_t forwhat ) +{ + int fd; + + fd = open ( INV_FSTAB, INV_OFLAG(forwhat) ); + + if ( fd < 0 ) + return -1; /* if ENOENT, fstab_put_entry will CREAT */ + + INVLOCK( fd, LOCK_EX ); + if (( *numfs = GET_ALLHDRS_N_CNTS_NOLOCK( fd, (void**) arr, + (void **)cnt, + sizeof( invt_fstab_t ), + sizeof( invt_counter_t ) ) + ) < 0 ) { + mlog( MLOG_NORMAL | MLOG_INV, "INV: couldn't get fstab headers\n"); + } +#ifdef INVT_DEBUG + mlog( MLOG_NITTY | MLOG_INV, "INV: number of filesystems in fstab %d\n", + *numfs ); +#endif + /* fstab is left locked EX on exit. The caller takes does + the unlocking */ + return fd; +} + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* caller takes the responsibility of calling this only when the FSTAB_ */ +/* UPDATED flag in the inv_idbtoken is off, and also of updating the */ +/* flag upon successful return from put_fstab_entry. */ +/*----------------------------------------------------------------------*/ + + +intgen_t +fstab_put_entry( uuid_t *fsidp, char *mntpt, char *dev, inv_oflag_t forwhat ) +{ + int numfs, i, fd; + invt_counter_t *cnt; + invt_fstab_t *arr; + int rval = 1; + + ASSERT( forwhat != INV_SEARCH_ONLY ); + + /* fd is locked on succesful return */ + fd = fstab_getall( &arr, &cnt, &numfs, forwhat ); + if ( fd < 0 ) { + if ( errno != ENOENT ) { + return -1; + } + if ((fd = open( INV_FSTAB, INV_OFLAG(forwhat) | O_CREAT )) + < 0 ) { + INV_PERROR ( INV_FSTAB ); + return -1; + } + + INVLOCK( fd, LOCK_EX ); + fchmod( fd, INV_PERMS ); + + cnt = (invt_counter_t *) malloc( sizeof ( invt_counter_t ) ); + + cnt->ic_maxnum = -1; + cnt->ic_curnum = 0; + cnt->ic_vernum = INV_VERSION; + + } else if ( numfs > 0 ) { + + for (i = 0; i < numfs; i++) { + if ( uuid_compare( *fsidp, arr[ i ].ft_uuid ) == 0 ) { + +/* if ( ( STREQL( arr[i].ft_mountpt, mntpt ) ) && + ( STREQL( arr[i].ft_devpath, dev ) ) ) +*/ + free ( arr ); + free ( cnt ); + close( fd ); + return 1; + + } + } + /* entry not found. just follow thru to create a new one */ + free ( arr ); + } + + /* make a new fstab entry and insert it at the end. the table + is locked EXclusively at this point */ + { + invt_fstab_t ent; + off64_t hoff; + + memcpy( &ent.ft_uuid, fsidp, sizeof( uuid_t ) ); + strcpy( ent.ft_mountpt, mntpt ); + strcpy( ent.ft_devpath, dev ); + + /* increase the number of entries first */ +#ifdef INVT_DEBUG + mlog( MLOG_NITTY | MLOG_INV,"INV: putting new fstab entry for %s ....\n", + mntpt); +#endif + cnt->ic_curnum++; + hoff = (off64_t) ( sizeof( invt_counter_t ) + + (size_t)( cnt->ic_curnum - 1 ) * + sizeof( invt_fstab_t ) ); + + rval = PUT_COUNTERS( fd, cnt ); + if ( rval > 0 ) { + rval = PUT_REC_NOLOCK( fd, &ent, sizeof( ent ), hoff ); + } + + } + INVLOCK( fd, LOCK_UN ); + free ( cnt ); + close ( fd ); + return rval; +} + + + + + +intgen_t +fstab_get_fname( void *pred, + char *fname, + inv_predicate_t bywhat, + inv_oflag_t forwhat) +{ + uuid_t *uuidp = 0; + char uuidstr[UUID_STR_LEN + 1]; + invt_fstab_t *arr; + + + if (bywhat != INV_BY_UUID) { + int numfs, i, fd; + invt_counter_t *cnt; + + /* on sucessful return fd is locked */ + fd = fstab_getall( &arr, &cnt, &numfs, forwhat ); + if ( fd < 0 ) + return -1; + if ( numfs <= 0 ) { + mlog( MLOG_NORMAL | MLOG_INV, "INV: No recorded filesystems in" + " inventory's fstab.\n" ); + return -1; + } + INVLOCK( fd, LOCK_UN ); + close ( fd ); + free ( cnt ); /* we dont need it */ + + /* first get hold of the uuid for this mount point/device */ + + for (i = 0; i < numfs; i++) { + if ( ( bywhat == INV_BY_MOUNTPT && + ( STREQL( arr[i].ft_mountpt, pred ) )) || + ( bywhat == INV_BY_DEVPATH && + ( STREQL( arr[i].ft_devpath, pred ) )) ) { + + uuidp = &arr[i].ft_uuid; + break; + } + } +#ifdef INVT_DEBUG + if (! uuidp ) + mlog( MLOG_NORMAL | MLOG_INV,"INV: get_fname: unable to find %s" + " in the inventory\n", (char *)pred); +#endif + + } else { + uuidp = (uuid_t *)pred; + } + + if (! uuidp ) + return -1; + + uuid_unparse( *uuidp, uuidstr ); + + strncpy ( fname, INV_DIRPATH, INV_STRLEN ); + strcat ( fname, "/" ); + strcat ( fname, uuidstr); + + if ( bywhat != INV_BY_UUID ) + free ( arr ); + + ASSERT( (int) strlen( fname ) < INV_STRLEN ); + return 1; +} + + +void +fstab_DEBUG_print( invt_fstab_t *arr, int num ) +{ + int i; + char str[UUID_STR_LEN + 1]; + + mlog( MLOG_NORMAL | MLOG_INV, "\n\n--------- fstab ------------\n" ); + for ( i = 0; i < num; i++ ) { + printf( "Mount\t%s\n", arr[i].ft_mountpt ); + printf( "Dev\t%s\n", arr[i].ft_devpath ); + uuid_unparse( arr[i].ft_uuid, str ); + printf( "FSid\t%s\n\n", str ); + } + mlog( MLOG_NORMAL | MLOG_INV, "\n---------========------------\n" ); +} diff -rNu linux-2.4.7/cmd/xfsdump/inventory/inv_idx.c linux-2.4-xfs/cmd/xfsdump/inventory/inv_idx.c --- linux-2.4.7/cmd/xfsdump/inventory/inv_idx.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/inv_idx.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,567 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include "types.h" +#include "mlog.h" +#include "inv_priv.h" + + + +/*----------------------------------------------------------------------*/ +/* insert_invindexentry */ +/* */ +/* given a time, find the invindex that has the time-period it can fit */ +/* into. */ +/*----------------------------------------------------------------------*/ +u_int +idx_insert_newentry( int fd, /* kept locked EX by caller */ + int *stobjfd, /* OUT */ + invt_entry_t *iarr, invt_counter_t *icnt, + time_t tm ) +{ + u_int i; + inv_oflag_t forwhat = INV_SEARCH_N_MOD; +/* invt_entry_t ient; + ient.ie_timeperiod.tp_start = ient.ie_timeperiod.tp_end = tm; */ + + /* If time period of the new entry is before our first invindex, + we have to insert a new invindex in the first slot */ + if ( iarr[0].ie_timeperiod.tp_start > tm ) { + /* *stobjfd = idx_put_newentry( fd, 0, iarr, icnt, &ient );*/ + *stobjfd = open( iarr[0].ie_filename, INV_OFLAG(forwhat) ); + return 0; + } + + for ( i = 0; i < icnt->ic_curnum; i++ ) { + /* if our time is nicely within an existing entry's time + period, hellalujah */ + if ( IS_WITHIN( &iarr[i].ie_timeperiod, tm ) ) { +#ifdef INVT_DEBUG + mlog( MLOG_DEBUG | MLOG_INV, "INV: is_within %d\n",i ); +#endif + *stobjfd = open( iarr[i].ie_filename, INV_OFLAG(forwhat) ); + return i; + } + if ( iarr[i].ie_timeperiod.tp_end == 0 && + iarr[i].ie_timeperiod.tp_start == 0 ) { +#ifdef INVT_DEBUG + mlog( MLOG_DEBUG | MLOG_INV, "INV: end = start \n" ); + mlog( MLOG_DEBUG | MLOG_INV,"BEF: st %ld end %ld\n", + iarr[i].ie_timeperiod.tp_start, + iarr[i].ie_timeperiod.tp_end ); +#endif + + iarr[i].ie_timeperiod.tp_start = + iarr[i].ie_timeperiod.tp_end = tm; + PUT_REC_NOLOCK( fd, iarr, + icnt->ic_curnum * sizeof(invt_entry_t), + (off64_t) sizeof( invt_counter_t ) ); +#ifdef INVT_DEBUG + mlog( MLOG_DEBUG | MLOG_INV,"AFT: st %ld end %ld\n", + iarr[i].ie_timeperiod.tp_start, + iarr[i].ie_timeperiod.tp_end ); +#endif + *stobjfd = open( iarr[i].ie_filename, INV_OFLAG(forwhat) ); + return i; + } + + + + /* if it is beyond the end of this timeperiod, see if we + belong to a timeperiod that doesn't have an entry */ + if ( iarr[i].ie_timeperiod.tp_end < tm ) { + /* see if we're the last entry here */ + if ( i == icnt->ic_curnum - 1 ) { + /* our slot is (i+1)th entry. Make the + timeperiod's the same as it was. As far + as I can see there is no way that + timeperiods can overlap. + + insert the new entry and write back + icnt and invindex entry */ + /* *stobjfd = idx_put_newentry( fd, i+1, iarr, + icnt, &ient );*/ + *stobjfd = open( iarr[i].ie_filename, INV_OFLAG(forwhat) ); + return i; + } + /* see if the next entry starts later than us */ + if ( iarr[i+1].ie_timeperiod.tp_start > tm ) { + + + /* We have the option of pushing entries + after (i) forward by one slot, and + taking the (i+1)th slot, OR just hooking + up with the next entry. + We choose the former. */ + + /* the timeperiods had better not overlap */ + ASSERT(( tm > iarr[i].ie_timeperiod.tp_end ) && + ( tm < iarr[i+1].ie_timeperiod.tp_start )); + + /* shift everything from (i+1) onwards by + one. Then insert the new entry and write + back icnt and invindex entries */ + /* *stobjfd = idx_put_newentry( fd, i+1, iarr, + icnt, &ient );*/ + *stobjfd = open( iarr[i].ie_filename, INV_OFLAG(forwhat) ); + return i; + } + } + } + + /* We couldnt find anything that fits */ + ASSERT( 0 ); /* We can't get here ! */ + return -1; + + +} + + +/*----------------------------------------------------------------------*/ +/* idx_put_newentry */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +idx_put_newentry( + invt_idxinfo_t *idx, + invt_entry_t *ient ) +{ + invt_entry_t *idxarr; + int stobjfd; + + int fd = idx->invfd; /* kept locked EX by caller */ + u_int index = idx->index + 1; + invt_entry_t *iarr = idx->iarr; + invt_counter_t *icnt = idx->icnt; + + stobj_makefname( ient->ie_filename ); + if ( ( stobjfd = stobj_create( ient->ie_filename ) ) < 0 ) + return -1; + + icnt->ic_curnum++; /* there is no maximum */ + + idxarr = ( invt_entry_t * ) calloc ( icnt->ic_curnum, + sizeof( invt_entry_t ) ); + memcpy( idxarr, iarr, ( size_t ) ( sizeof( invt_entry_t ) * index ) ); + + /* shift everything from (i+1) onwards by one */ + if ( index < icnt->ic_curnum - 1 ) + memcpy( &idxarr[ index + 1 ], &iarr[ index ], + ( size_t ) ( ( icnt->ic_curnum - index - 1 ) * + sizeof( invt_entry_t ) ) ); + /* insert the new entry */ + memcpy( &idxarr[ index ], ient, sizeof( invt_entry_t ) ); + + + if ( ( PUT_COUNTERS( fd, icnt ) < 0 ) || + ( PUT_REC_NOLOCK( fd, idxarr, + icnt->ic_curnum * sizeof( invt_entry_t ), + sizeof( invt_counter_t ) ) < 0 ) ) { + /* XXX delete the stobj that we just created */ + + memset( ient->ie_filename, 0 , INV_STRLEN ); + free( idxarr ); + return -1; + } + + free( iarr ); + idx->iarr = idxarr; + return stobjfd; + +} + + + + +/*----------------------------------------------------------------------*/ +/* idx_find_stobj */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + + +int +idx_find_stobj( invt_idxinfo_t *idx, + time_t tm ) +{ + + int stobjfd; + + /* since sessions can be inserted in random order, the invindex + table can contain time-periods that don't have corresponding + entries for */ + if ( GET_ALLHDRS_N_CNTS_NOLOCK( idx->invfd, (void **)&idx->iarr, + (void **)&idx->icnt, + sizeof( invt_entry_t ), + sizeof( invt_counter_t ) ) < 0 ) { + return -1; + } + +#ifdef INVT_DEBUG + printf( "idx_find_stobj Time: %ld\n", tm ); + idx_DEBUG_printinvindices( idx->iarr, idx->icnt->ic_curnum ); +#endif + + /* Now figure out where we are going to insert this stobj among the + invindices and put it there */ + idx->index = idx_insert_newentry( idx->invfd, &stobjfd, idx->iarr, + idx->icnt, tm ); + + return stobjfd; +} + + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +inv_idbtoken_t +idx_create( char *fname, inv_oflag_t forwhat ) +{ + int stobjfd, fd; + inv_idbtoken_t tok; + + /* This is not to be called when the user wants to open + the db for SEARCH_ONLY. */ + ASSERT( forwhat != INV_SEARCH_ONLY ); + + if ((fd = open ( fname , INV_OFLAG(forwhat) | O_CREAT ) ) < 0 ) { + INV_PERROR ( fname ); + return INV_TOKEN_NULL; + } + + INVLOCK( fd, LOCK_EX ); + fchmod( fd, INV_PERMS ); + +#ifdef INVT_DEBUG + mlog( MLOG_NITTY | MLOG_INV, "creating InvIndex %s\n", fname); +#endif + + /* create the first entry in the new inv_index */ + stobjfd = idx_create_entry( &tok, fd, BOOL_TRUE ); + + INVLOCK( fd, LOCK_UN ); + + if ( stobjfd < 0 ) + return INV_TOKEN_NULL; + return tok; +} + + +/*----------------------------------------------------------------------*/ +/* idx_recons_time */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ +intgen_t +idx_recons_time( time_t tm, invt_idxinfo_t *idx ) +{ + invt_timeperiod_t *tp = &idx->iarr[idx->index].ie_timeperiod; + if ( tp->tp_start && IS_WITHIN( tp, tm ) ) + return 1; + + if ( tm > tp->tp_end || tp->tp_end == 0 ) + tp->tp_end = tm; + if ( tm < tp->tp_start || tp->tp_start == 0 ) + tp->tp_start = tm; + PUT_REC_NOLOCK( idx->invfd, &idx->iarr[idx->index], + sizeof( invt_entry_t ), IDX_HDR_OFFSET(idx->index) ); + return 1; +} + + + + +/*----------------------------------------------------------------------*/ +/* put_sesstime */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +idx_put_sesstime( inv_sestoken_t tok, bool_t whichtime) +{ + int rval; + invt_entry_t ent; + int fd = tok->sd_invtok->d_invindex_fd; + + INVLOCK( fd, LOCK_EX ); + + rval = GET_REC_NOLOCK( fd, &ent, sizeof( invt_entry_t ), + tok->sd_invtok->d_invindex_off); + if ( rval < 0 ) { + INVLOCK( fd, LOCK_UN ); + return -1; + } + ent.ie_timeperiod.tp_end = tok->sd_sesstime; + + if ( whichtime == INVT_STARTTIME || ent.ie_timeperiod.tp_start == 0 ) { + ent.ie_timeperiod.tp_start = tok->sd_sesstime; + } +#ifdef INVT_DEBUG + mlog( MLOG_DEBUG | MLOG_INV,"Putsestime: st %ld end %ld\n", + ent.ie_timeperiod.tp_start, + ent.ie_timeperiod.tp_end ); +#endif + rval = PUT_REC_NOLOCK_SEEKCUR( fd, &ent, sizeof( invt_entry_t ), + -(off64_t)(sizeof( invt_entry_t ))); + +#ifdef INVT_DEBUG + { + int nindices; + invt_entry_t *iarr = NULL; + invt_counter_t *icnt = NULL; + if ( ( nindices = GET_ALLHDRS_N_CNTS_NOLOCK( fd, + (void **)&iarr, + (void **)&icnt, + sizeof( invt_entry_t ), + sizeof( invt_counter_t ))) < 0 ) { + return -1; + } + idx_DEBUG_printinvindices( iarr, (u_int) nindices ); + free( iarr ); + free( icnt ); + } +#endif + + INVLOCK( fd, LOCK_UN ); + return rval; +} + + + +/* an inventory index entry keeps track of a single storage object; + it knows about its name (ie filename) and the timeperiod that the + it contains dump sessions for. + note that each file system has its own (set of) inventory indices. +*/ + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +idx_create_entry( + inv_idbtoken_t *tok, + int invfd, /* kept locked EX by caller */ + bool_t firstentry ) +{ + invt_entry_t ent; + int fd; + off64_t hoff; + + + memset ( &ent, 0, sizeof( ent ) ); + + /* initialize the start and end times to be the same */ + ent.ie_timeperiod.tp_start = ent.ie_timeperiod.tp_end = (time_t)0; + stobj_makefname( ent.ie_filename ); + + if ( firstentry ) { + invt_counter_t cnt; + + cnt.ic_maxnum = INVT_MAX_INVINDICES; + cnt.ic_curnum = 1; + cnt.ic_vernum = INV_VERSION; + + fd = stobj_create( ent.ie_filename ); + if ( fd < 0 ) { + return -1; + } + + if ( PUT_REC_NOLOCK( invfd, &cnt, sizeof(cnt), (off64_t)0 ) < 0 ) + return -1; + + hoff = sizeof( invt_counter_t ); + + if ( PUT_REC_NOLOCK( invfd, &ent, sizeof( ent ), hoff ) < 0) + return -1; + } else { + invt_counter_t *cnt = NULL; + + if ( GET_COUNTERS( invfd, &cnt ) < 0 ) { + return -1; + } + + /* XXX check if there are too many indices. if so, create + another and leave a pointer to that in here */ + + /* create the new storage object */ + fd = stobj_create( ent.ie_filename ); + if ( fd < 0 ) { + return -1; + } + ++(cnt->ic_curnum); + if ( PUT_COUNTERS( invfd, cnt ) < 0 ) { + return -1; + } + + /* add the new index entry to the array, at the end */ + + hoff = IDX_HDR_OFFSET( cnt->ic_curnum - 1 ); + free (cnt); +#ifdef INVT_DEBUG + mlog( MLOG_NITTY | MLOG_INV, "new stobj name %s @ offset %d\n", + ent.ie_filename,(int)hoff ); +#endif + if (PUT_REC_NOLOCK( invfd, &ent, sizeof( ent ), hoff) < 0 ) + return -1; + + } + + *tok = get_token( invfd, fd ); + (*tok)->d_invindex_off = hoff; + (*tok)->d_update_flag |= NEW_INVINDEX; + (*tok)->d_oflag = INV_SEARCH_N_MOD; + return fd; + +} + + + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +int +idx_get_stobj( int invfd, inv_oflag_t forwhat, int *index ) +{ + invt_entry_t *ent = 0; + int fd; + + /* if there's space anywhere at all, then it must be in the last + entry. get_lastheader() does the locking */ + + if ((*index = get_lastheader( invfd, (void **)&ent, + sizeof(invt_entry_t), + sizeof(invt_counter_t) ) ) < 0 ) + return -1; + /* at this point we know that there should be at least one invindex + entry present */ + ASSERT ( ent != NULL ); + ASSERT ( ent->ie_filename ); + + fd = open( ent->ie_filename, INV_OFLAG(forwhat) ); + if ( fd < 0 ) + INV_PERROR( ent->ie_filename ); + free ( ent ); + + return fd; +} + + +intgen_t +idx_DEBUG_printinvindices( invt_entry_t *iarr, u_int num ) +{ + u_int i; + u_int k; + + char s[9]; + printf( "\n ==================================\n" + " InvIndex\n # StObjs\t%d\n", num ); +#define INV_UUID_STR_LEN 36 /* not exported via uuid.h */ + for ( i = 0; i < num; i++ ) { + k = strlen( iarr[i].ie_filename ); + strncpy( s, (char *) iarr[i].ie_filename + k - + ( INV_UUID_STR_LEN + strlen(INV_STOBJ_PREFIX)), 8 ); + s[8]= 0; + printf("%d. %s \t( %ld - %ld )\n", i, s, + iarr[i].ie_timeperiod.tp_start, + iarr[i].ie_timeperiod.tp_end ); + } +#undef INV_UUID_STR_LEN + printf( "\n ==================================\n"); + return 1; + +} + +intgen_t +idx_DEBUG_print ( int fd ) +{ + int nindices; + invt_entry_t *iarr = NULL; + invt_counter_t *icnt = NULL; + if ( ( nindices = GET_ALLHDRS_N_CNTS_NOLOCK( fd, + (void **)&iarr, + (void **)&icnt, + sizeof( invt_entry_t ), + sizeof( invt_counter_t ))) < 0 ) { + return -1; + } + idx_DEBUG_printinvindices( iarr, (u_int) nindices ); + free( iarr ); + free( icnt ); + + return 1; +} + + + +intgen_t +DEBUG_displayallsessions( int fd, invt_seshdr_t *hdr, u_int ref, + invt_pr_ctx_t *prctx) +{ + inv_session_t *ses; + if ( stobj_make_invsess( fd, &ses, hdr ) < 1 ) + return -1; + + DEBUG_sessionprint( ses, ref, prctx); + free( ses->s_streams ); + free( ses ); + + return 0; +} + diff -rNu linux-2.4.7/cmd/xfsdump/inventory/inv_mgr.c linux-2.4-xfs/cmd/xfsdump/inventory/inv_mgr.c --- linux-2.4.7/cmd/xfsdump/inventory/inv_mgr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/inv_mgr.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,743 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include "types.h" +#include "mlog.h" +#include "inv_priv.h" + + +/*----------------------------------------------------------------------*/ +/* init_idb */ +/* */ +/* Returns -1 if we are done with initialization, the fd if not. */ +/* The idb_token indicates whether there was an error or not, if the */ +/* return value is -1. */ +/*----------------------------------------------------------------------*/ + +int +init_idb( void *pred, inv_predicate_t bywhat, inv_oflag_t forwhat, + inv_idbtoken_t *tok ) +{ + char fname[ INV_STRLEN ]; + char uuname[ INV_STRLEN ]; + int fd; + + *tok = INV_TOKEN_NULL; + /* make sure INV_DIRPATH exists, and is writable */ + if ( make_invdirectory( forwhat ) < 0 ) + return I_DONE; + + /* come up with the unique file suffix that refers to this + filesystem */ + if ( fstab_get_fname( pred, uuname, bywhat, forwhat ) < 0 ) { + return I_DONE; + } + + ( void )strcpy( fname, uuname ); + strcat ( fname, INV_INVINDEX_PREFIX ); + + /* first check if the inv_index file exists: if not create it */ + if ( ( fd = open( fname, INV_OFLAG(forwhat) ) ) == -1 ) { + if (errno != ENOENT) { + INV_PERROR ( fname ); + } else if (forwhat == INV_SEARCH_N_MOD) { + *tok = idx_create( fname, forwhat ); + } else { + /* this happens when the inv is empty and the user + wants to do a search. this is legal - not an error */ + return I_EMPTYINV; + } + return I_DONE; /* we are done whether token's NULL or not */ + } + + /* we've got to do more housekeeping stuff. so signal that */ + return fd; +} + + + + + +inv_idbtoken_t +get_token( int invfd, int stobjfd ) +{ + invt_desc_entry_t *desc; + + desc = (invt_desc_entry_t *) malloc + ( sizeof( invt_desc_entry_t ) ); + + desc->d_invindex_fd = invfd; + desc->d_stobj_fd = stobjfd; + desc->d_update_flag = 0; + desc->d_invindex_off = -1; + + return (inv_idbtoken_t) desc; /* yukky, but ok for the time being */ +} + + + + + + +void +destroy_token( inv_idbtoken_t tok ) +{ + free ( (invt_desc_entry_t *) tok ); +} + + + +inv_sestoken_t +get_sesstoken( inv_idbtoken_t tok ) +{ + inv_sestoken_t stok; + + stok = (inv_sestoken_t) malloc( sizeof( invt_sesdesc_entry_t ) ); + stok->sd_invtok = tok; + stok->sd_session_off = stok->sd_sesshdr_off = -1; + stok->sd_sesstime = (time_t) 0; + return stok; +} + + + + + + +/*---------------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*---------------------------------------------------------------------------*/ +bool_t +invmgr_query_all_sessions ( + void *inarg, + void **outarg, + search_callback_t func) +{ + invt_counter_t *cnt; + invt_fstab_t *arr; + int numfs, i, fd, invfd; + char fname[INV_STRLEN]; + int result; + inv_oflag_t forwhat = INV_SEARCH_ONLY; + void *objectfound; + + /* if on return, this is still null, the search failed */ + *outarg = NULL; + ASSERT(inarg); + + fd = fstab_getall( &arr, &cnt, &numfs, forwhat ); + /* special case missing file: ok, outarg says zero */ + if ( fd < 0 && errno == ENOENT ) { + return BOOL_TRUE; + } + if ( fd < 0 || numfs <= 0 ) { + mlog( MLOG_NORMAL | MLOG_INV, "INV: Error in fstab\n" ); + return BOOL_FALSE; + } + + close( fd ); + + for ( i = 0; i < numfs; i++) { + if ( fstab_get_fname( &arr[i].ft_uuid, fname, + (inv_predicate_t)INV_BY_UUID, + forwhat) < 0 ) { + mlog( MLOG_NORMAL | MLOG_INV, + "INV: Cant get inv-name for uuid\n" + ); + return BOOL_FALSE; + } + strcat( fname, INV_INVINDEX_PREFIX ); + invfd = open( fname, INV_OFLAG(forwhat) ); + if ( invfd < 0 ) { + mlog( MLOG_NORMAL | MLOG_INV, + "INV: Open failed on %s\n", + fname + ); + return BOOL_FALSE; + } + result = search_invt( invfd, inarg, &objectfound, func ); + close(invfd); + + /* if error return BOOL_FALSE */ + if (result < 0) { + return BOOL_FALSE; + } else if ((result == 1) && *outarg) { + /* multiple entries found, more info needed */ + *outarg = NULL; + return BOOL_TRUE; + } else if (result == 1) { + *outarg = objectfound; + } + } + + /* return val indicates if there was an error or not. *buf + says whether the search was successful */ + return BOOL_TRUE; +} + + + + +/*----------------------------------------------------------------------*/ +/* search_invt */ +/* */ +/* Used by the toplevel (inv layer ) to do common searches on the inven-*/ +/* tory. Caller supplies a callback routine that performs the real */ +/* comparison/check. */ +/*----------------------------------------------------------------------*/ + +intgen_t +search_invt( + int invfd, + void *arg, + void **buf, + search_callback_t do_chkcriteria ) +{ + + int fd, i; + invt_entry_t *iarr = NULL; + invt_counter_t *icnt = NULL; + int nindices; + + + if (invfd == I_EMPTYINV) + return -1; + + /* set the caller's buffer pointer to NULL initially. + * if no session found, the caller will expect to see + * NULL. + */ + *( char ** )buf = NULL; + + if ( ( nindices = GET_ALLHDRS_N_CNTS( invfd, (void **)&iarr, + (void **)&icnt, + sizeof( invt_entry_t ), + sizeof( invt_counter_t )) + ) <= 0 ) { + return -1; + } + + free( icnt ); + + /* we need to get all the invindex headers and seshdrs in reverse + order */ + for (i = nindices - 1; i >= 0; i--) { + int nsess; + invt_sescounter_t *scnt = NULL; + invt_seshdr_t *harr = NULL; + bool_t found; + + fd = open (iarr[i].ie_filename, O_RDONLY ); + if (fd < 0) { + INV_PERROR( iarr[i].ie_filename ); + continue; + } + INVLOCK( fd, LOCK_SH ); + + /* Now see if we can find the session we're looking for */ + if (( nsess = GET_ALLHDRS_N_CNTS_NOLOCK( fd, (void **)&harr, + (void **)&scnt, + sizeof( invt_seshdr_t ), + sizeof( invt_sescounter_t )) + ) < 0 ) { + INV_PERROR( iarr[i].ie_filename ); + INVLOCK( fd, LOCK_UN ); + close( fd ); + continue; + } + free ( scnt ); + + while ( nsess ) { + /* fd is kept locked until we return from the + callback routine */ + + /* Check to see if this session has been pruned + * by xfsinvutil before checking it. + */ + if ( harr[nsess - 1].sh_pruned ) { + --nsess; + continue; + } + found = (* do_chkcriteria ) ( fd, &harr[ --nsess ], + arg, buf ); + if (! found ) continue; + + /* we found what we need; just return */ + INVLOCK( fd, LOCK_UN ); + close( fd ); + free( harr ); + + return found; /* == -1 or 1 */ + } + + INVLOCK( fd, LOCK_UN ); + close( fd ); + } + + return 0; +} + + + +/*---------------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*---------------------------------------------------------------------------*/ + + +intgen_t +invmgr_inv_print( + int invfd, + invt_pr_ctx_t *prctx) +{ + + int fd, i; + invt_entry_t *iarr = NULL; + invt_counter_t *icnt = NULL; + int nindices; + u_int ref = 0; + + if (invfd == I_EMPTYINV) + return 0; + + + if ( ( nindices = GET_ALLHDRS_N_CNTS( invfd, (void **)&iarr, + (void **)&icnt, + sizeof( invt_entry_t ), + sizeof( invt_counter_t )) + ) <= 0 ) { + return -1; + } + + free( icnt ); + + if (prctx->invidx) { + idx_DEBUG_printinvindices( iarr, (u_int) nindices ); + free(iarr); + return (0); + } + + + + for ( i = 0; i < nindices; i++ ) { + int nsess; + invt_sescounter_t *scnt = NULL; + invt_seshdr_t *harr = NULL; + int s; + + fd = open (iarr[i].ie_filename, O_RDONLY ); + if (fd < 0) { + INV_PERROR( iarr[i].ie_filename ); + continue; + } + INVLOCK( fd, LOCK_SH ); + + /* Now see if we can find the session we're looking for */ + if (( nsess = GET_ALLHDRS_N_CNTS_NOLOCK( fd, (void **)&harr, + (void **)&scnt, + sizeof( invt_seshdr_t ), + sizeof( invt_sescounter_t )) + ) < 0 ) { + INV_PERROR( iarr[i].ie_filename ); + INVLOCK( fd, LOCK_UN ); + close( fd ); + continue; + } + free ( scnt ); + for( s = 0; s < nsess; s++ ) { + /* fd is kept locked until we return from the + callback routine */ + + /* Check to see if this session has been pruned + * by xfsinvutil before returning it. + */ + if ( harr[s].sh_pruned ) { + continue; + } + + (void)DEBUG_displayallsessions( fd, &harr[ s ], + ref++, prctx); + } + + INVLOCK( fd, LOCK_UN ); + close( fd ); + } + + free (iarr); + return 0; +} + + + +/*---------------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*---------------------------------------------------------------------------*/ + + +intgen_t +invmgr_inv_check( + int invfd) +{ + + int fd, i; + invt_entry_t *iarr = NULL; + invt_counter_t *icnt = NULL; + int nindices; + + if (invfd == I_EMPTYINV) + return 0; + + if ( ( nindices = GET_ALLHDRS_N_CNTS( invfd, (void **)&iarr, + (void **)&icnt, + sizeof( invt_entry_t ), + sizeof( invt_counter_t )) + ) <= 0 ) { + return -1; + } + + free( icnt ); + + + for ( i = 0; i < nindices; i++ ) { + int nsess; + invt_sescounter_t *scnt = NULL; + invt_seshdr_t *harr = NULL; + int s; + + fd = open (iarr[i].ie_filename, O_RDONLY ); + if (fd < 0) { + INV_PERROR( iarr[i].ie_filename ); + continue; + } + INVLOCK( fd, LOCK_SH ); + + /* Now see if we can find the session we're looking for */ + if (( nsess = GET_ALLHDRS_N_CNTS_NOLOCK( fd, (void **)&harr, + (void **)&scnt, + sizeof( invt_seshdr_t ), + sizeof( invt_sescounter_t )) + ) < 0 ) { + INV_PERROR( iarr[i].ie_filename ); + INVLOCK( fd, LOCK_UN ); + close( fd ); + continue; + } + free ( scnt ); + + if ((iarr[i].ie_timeperiod.tp_start != harr[0].sh_time) || + (iarr[i].ie_timeperiod.tp_end != harr[nsess-1].sh_time)) { + printf("INV: Check %d failed.\n", i+1); + printf("invidx (%d)\t%ld - %ld\n", + i+1, + iarr[i].ie_timeperiod.tp_start, + iarr[i].ie_timeperiod.tp_end); + for( s = 0; s < nsess; s++ ) { + printf("tm (%d)\t%ld\n", s, harr[s].sh_time); + } + } + else { + printf("INV: Check %d out of %d succeeded\n", + i+1, nindices); + + } + INVLOCK( fd, LOCK_UN ); + close( fd ); + } + + return 0; +} + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +/* ARGSUSED */ +bool_t +tm_level_lessthan( int fd, invt_seshdr_t *hdr, void *arg, + void **tm ) +{ + u_char level = *(u_char *)arg; + *tm = NULL; + if ( IS_PARTIAL_SESSION( hdr ) ) + return 0; + if (hdr->sh_level < level ) { +#ifdef INVT_DEBUG + mlog( MLOG_DEBUG | MLOG_INV, "$ found level %d < %d\n", hdr->sh_level, + level ); +#endif + *tm = calloc( 1, sizeof( time_t ) ); + memcpy( *tm, &hdr->sh_time, sizeof( time_t ) ); + return 1; + } + return 0; +} + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +bool_t +lastsess_level_lessthan( int fd, invt_seshdr_t *hdr, void *arg, + void **buf ) +{ + u_char level = *(u_char *)arg; + *buf = NULL; + if ( IS_PARTIAL_SESSION( hdr ) ) + return 0; + if (hdr->sh_level < level ) { +#ifdef INVT_DEBUG + mlog( MLOG_DEBUG | MLOG_INV, "$ found (ses) level %d < %d \n", + hdr->sh_level, level ); +#endif + return stobj_make_invsess( fd, (inv_session_t **) buf, hdr ); + } + return 0; + +} + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +bool_t +lastsess_level_equalto( int fd, invt_seshdr_t *hdr, + void *arg, void **buf ) +{ + u_char level = *(u_char *)arg; + *buf = NULL; + if ( IS_PARTIAL_SESSION( hdr ) ) + return 0; + if (hdr->sh_level == level ) { +#ifdef INVT_DEBUG + mlog( MLOG_DEBUG | MLOG_INV, "$ found (ses) level %d == %d \n", hdr->sh_level, + level ); +#endif + return stobj_make_invsess( fd, (inv_session_t **) buf, hdr ); + } + return 0; + + +} + + + + + + +/*----------------------------------------------------------------------*/ +/* insert_session */ +/* */ +/* insert a session that may or may not be already in the inventory. */ +/* this is used in reconstructing the database. */ +/*----------------------------------------------------------------------*/ +bool_t +insert_session( invt_sessinfo_t *s) +{ + inv_idbtoken_t tok = INV_TOKEN_NULL; + int invfd, stobjfd = -1; + invt_idxinfo_t idx; + bool_t ret = BOOL_FALSE; + inv_oflag_t forwhat = INV_SEARCH_N_MOD; + + /* initialize the inventory */ + if ( ( invfd = init_idb ( (void *) s->ses->s_fsid, + (inv_predicate_t) INV_BY_UUID, + forwhat, + &tok ) ) < 0 ) { + if ( tok == INV_TOKEN_NULL ) { +#ifdef INVT_DEBUG + mlog( MLOG_NORMAL | MLOG_INV, "INV: insert_session: init_db " + "failed\n" ); +#endif + return BOOL_FALSE; + } + + invfd = tok->d_invindex_fd; + close( tok->d_stobj_fd ); + destroy_token( tok ); + } + + /* at this point we know that invindex has at least one entry + + First we need to find out if this session is in the inventory + already. To find the storage object that can possibly + contain this session, it suffices to sequentially search the + inventory indices of this filesystem for the particular invt-entry + */ + INVLOCK( invfd, LOCK_EX ); + idx.invfd = invfd; + stobjfd = idx_find_stobj( &idx, s->seshdr->sh_time ); + if (stobjfd < 0) { + INVLOCK( invfd, LOCK_UN ); + free( idx.icnt ); + free( idx.iarr ); + return BOOL_FALSE; + } + + /* Now put the session in the storage-object */ + INVLOCK( stobjfd, LOCK_EX ); + if ( ( stobj_insert_session( &idx, stobjfd, s ) < 0 ) || + ( idx_recons_time ( s->seshdr->sh_time, &idx ) < 0 ) ) + ret = BOOL_TRUE; + + INVLOCK( stobjfd, LOCK_UN ); + INVLOCK( invfd, LOCK_UN ); + + free( idx.icnt ); + free( idx.iarr ); + + if (ret) return BOOL_FALSE; + + /* make sure the fstab is uptodate too */ + if ( fstab_put_entry( &s->ses->s_fsid, s->ses->s_mountpt, s->ses->s_devpath, + forwhat ) < 0 ) + return BOOL_FALSE; + + /* and we are done */ + return BOOL_TRUE; + +} + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +make_invdirectory( inv_oflag_t forwhat ) +{ + struct stat64 st; + + if ( stat64( INV_DIRPATH, &st ) < 0 ) { + + if ( forwhat == INV_SEARCH_ONLY || errno != ENOENT ) { + return -1; + } + + if ( mkdir( XFSDUMP_DIRPATH, (mode_t)0755 ) < 0 ) { + if ( errno != EEXIST ) { + INV_PERROR( XFSDUMP_DIRPATH ); + return -1; + } + } + + if ( mkdir( INV_DIRPATH, (mode_t)0755 ) < 0 ) { + INV_PERROR( INV_DIRPATH ); + return -1; + } + + mlog( MLOG_VERBOSE | MLOG_INV, "%s created\n", INV_DIRPATH); + return 1; + } + + return 1; + + +} + +#ifdef NOTDEF + +bool_t +invmgr_lockinit( void ) +{ + if ( invlock_fd == -1 ) { + if (( invlock_fd = open( INV_LOCKFILE, + O_RDONLY | O_CREAT )) < 0 ) { + INV_PERROR( INV_LOCKFILE ); + return BOOL_FALSE; + } + fchmod ( invlock_fd, INV_PERMS ); + } + return BOOL_TRUE; +} + + +bool_t +invmgr_trylock( invt_mode_t mode ) +{ + int md; + ASSERT( invlock_fd >= 0 ); + + md = (mode == INVT_RECONSTRUCT) ? LOCK_EX: LOCK_SH; + + if (INVLOCK( invlock_fd, md | LOCK_NB ) < 0) + return BOOL_FALSE; + + return BOOL_TRUE; +} + +void +invmgr_unlock( void ) +{ + ASSERT( invlock_fd >= 0 ); + + INVLOCK( invlock_fd, LOCK_UN ); + +} + +#endif + + + + + + + + diff -rNu linux-2.4.7/cmd/xfsdump/inventory/inv_oref.c linux-2.4-xfs/cmd/xfsdump/inventory/inv_oref.c --- linux-2.4.7/cmd/xfsdump/inventory/inv_oref.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/inv_oref.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,541 @@ +/************************************************************************** + * * + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + * * + **************************************************************************/ + +#include +#include + +#include "inv_priv.h" +#include "inv_oref.h" + + +/* + * Resolve a stobj, invidx or fstab + */ +intgen_t +oref_resolve_( + invt_oref_t *obj, + invt_objtype_t type) +{ + intgen_t rval; + + type &= INVT_OTYPE_MASK; + ASSERT(type); + ASSERT(! OREF_ISRESOLVED(obj, INVT_OTYPE_MASK)); + + switch (type) { + case INVT_OTYPE_INVIDX: + rval = oref_resolve_invidx(obj); + break; + + case INVT_OTYPE_STOBJ: + rval = oref_resolve_stobj(obj); + break; + + case INVT_OTYPE_FSTAB: + rval = oref_resolve_fstab(obj); + break; + + default: + ASSERT(0); + break; + } + + return rval; +} + + + + + +/* + * Resolve an object reference upto a specified point + */ + +intgen_t +oref_resolve_upto( + invt_oref_t *obj, + invt_objtype_t type) +{ + intgen_t rval = INV_OK; + + ASSERT (OREF_ISRESOLVED(obj, INVT_OTYPE_MASK)); + ASSERT (OREF_ISLOCKED(obj)); + + /* we arent interested in anything else */ + type &= INVT_RES_MASK; + ASSERT(type); + + if (type >= INVT_RES_COUNTERS) { + rval = oref_resolve_counters(obj); + } + if (type >= INVT_RES_ENTRIES && rval != INV_ERR) { + rval = oref_resolve_entries(obj); + } + if (type >= INVT_RES_HDRS && rval != INV_ERR) { + rval = oref_resolve_hdrs(obj); + } + if (type >= INVT_RES_SESSIONS && rval != INV_ERR) { + rval = oref_resolve_sessions(obj); + } + if (type >= INVT_RES_STRMS && rval != INV_ERR) { + rval = oref_resolve_strms(obj); + } + if (type >= INVT_RES_MFILES && rval != INV_ERR) { + rval = oref_resolve_mfiles(obj); + } + + return rval; +} + + + +intgen_t +oref_resolve_entries( + invt_oref_t *obj) +{ + if (OREF_ISRESOLVED(obj, INVT_RES_ENTRIES)) + return INV_OK; + + ASSERT(! OREF_ISRESOLVED(INVT_OTYPE_STOBJ)); + + if (OREF_ISRESOLVED(INVT_OTYPE_INVIDX)) { + invt_entry_t *ent; + ASSERT(OREF_CNT_CURNUM(obj)); + + if (GET_ENTRIES(obj->fd, &ent, OREF_CNT_CURNUM(obj), + sizeof(invt_entry_t)) < 0){ + return INV_ERR; + } + obj->eu_ent = ent; + } + else { + invt_fstab_t *ent; + ASSERT(OREF_CNT_CURNUM(obj)); + if (GET_ENTRIES(obj->fd, &ent, OREF_CNT_CURNUM(obj), + sizeof(invt_fstab_t)) < 0){ + return INV_ERR; + } + obj->eu_fstabent = ent; + } + + OREF_SET_TYPE(obj, INVT_RES_COUNTERS); + + return INV_OK; +} + + + + + + +intgen_t +oref_resolve_counters( + invt_oref_t *obj) +{ + if (OREF_ISRESOLVED(obj, INVT_RES_COUNTERS)) + return INV_OK; + + if (OREF_ISRESOLVED(INVT_OTYPE_STOBJ)) { + invt_sescounter_t *sescnt; + sescnt = calloc(1, sizeof(invt_sescounter_t)); + if (GET_SESCOUNTERS(obj->fd, sescnt) < 0){ + free(sescnt); + return INV_ERR; + } + obj->cu_sescnt = sescnt; + } + else { + invt_counter_t *cnt; + cnt = calloc(1, sizeof(invt_counter_t)); + if (GET_COUNTERS(obj->fd, cnt) < 0){ + free(cnt); + return INV_ERR; + } + obj->cu_cnt = cnt; + } + + OREF_SET_TYPE(obj, INVT_RES_COUNTERS); + + return INV_OK; +} + + + +intgen_t +oref_sync( + invt_oref_t *obj, + invt_objtype_t type) +{ + intgen_t rval; + + type &= INVT_RES_MASK; + ASSERT(type); + ASSERT(OREF_ISRESOLVED(obj, INVT_OTYPE_MASK)); + ASSERT(OREF_ISRESOLVED(obj, type)); + ASSERT(OREF_ISLOCKED(obj)); + + switch (type) { + case INVT_RES_COUNTERS: + rval = PUT_REC_NOLOCK(obj->fd, + OREF_CNT(obj), + sizeof(*OREF_CNT(obj)), + (off64_t) 0); + + break; + + case INVT_RES_ENTRIES: + ASSERT(! OREF_ISRESOLVED(obj, INVT_OTYPE_STOBJ)); + + rval = PUT_REC_NOLOCK(obj->fd, + OREF_ENTRIES(obj), + sizeof(*OREF_ENTRIES(obj)), + (off64_t) sizeof(*OREF_CNT(obj))); + + break; + + default: + ASSERT(0); + break; + } + + return rval; +} + +intgen_t +oref_sync_append( + invt_oref_t *obj, + invt_objtype_t type, + void *entry, + size_t entsz) +{ + intgen_t rval; + + type &= INVT_RES_MASK; + ASSERT(type); + ASSERT(OREF_ISRESOLVED(obj, INVT_OTYPE_MASK)); + ASSERT(OREF_ISLOCKED(obj)); + + switch (type) { + case INVT_RES_ENTRIES: + ASSERT(! OREF_ISRESOLVED(obj, INVT_OTYPE_STOBJ)); + + rval = PUT_REC_NOLOCK(obj->fd, + entry, + entsz, + IDX_HDR_OFFSET(OREF_CNT_CURNUM(obj) - 1)); + if (OREF_ISRESOLVED(obj, INVT_RES_ENTRIES)) + free((oref)->eu_ent); + OREF_UNSET_TYPE(obj, INVT_RES_ENTRIES); + + break; + + default: + ASSERT(0); + break; + } + + return rval; +} + + + +void +_oref_free( + invt_oref_t *obj, + bool_t freethis) +{ + /* + * Unlock the object *if* it is locked. + * We dont want to actually close the fd because, + * the tokens still need it. + */ + OREF_UNLOCK(obj); + + if (OREF_ISRESOLVED(obj, INVT_OTYPE_STOBJ) ){ + if (OREF_ISRESOLVED(obj, INVT_RES_COUNTERS)) + free((oref)->cu_sescnt); + if (OREF_ISRESOLVED(obj, INVT_RES_HDRS)) + free((oref)->eu_hdr); + if (OREF_ISRESOLVED(obj, INVT_RES_SESSIONS)) + free((oref)->eu_ses); + if (OREF_ISRESOLVED(obj, INVT_RES_STRMS)) + free((oref)->eu_strm); + if (OREF_ISRESOLVED(obj, INVT_RES_MFILES)) + free((oref)->eu_mfile); + } + else if (OREF_ISRESOLVED(obj, INVT_OTYPE_INVIDX)) { + if (OREF_ISRESOLVED(obj, INVT_RES_COUNTERS)) + free((oref)->cu_cnt); + if (OREF_ISRESOLVED(obj, INVT_RES_ENTRIES)) + free((oref)->eu_ent); + } + else if (OREF_ISRESOLVED(obj, INVT_OTYPE_FSTAB)) { + if (OREF_ISRESOLVED(obj, INVT_RES_COUNTERS)) + free((oref)->cu_cnt); + if (OREF_ISRESOLVED(obj, INVT_RES_ENTRIES)) + free((oref)->eu_fstabent); + } + OREF_INIT(obj); + if (freethis) + free(obj); +} + + + +/* + * Resolve the invidx and a suitable stobj. + * Also resolves an idb_token as a side effect. + */ + +intgen_t +oref_resolve( + invt_oref_t *invidx, + inv_predicate_t bywhat, + void *pred) +{ + char fname[ INV_STRLEN ]; + char uuname[ INV_STRLEN ]; + int fd; + invt_oref_t *stobj; + int index; + + ASSERT(! OREF_ISRESOLVED(invidx, INVT_OTYPE_MASK)); + + OREF_SET_TYPE(invidx, INVT_OTYPE_INVIDX); + + /* come up with the unique file suffix that refers to this + filesystem */ + if (fstab_get_fname(pred, uuname, bywhat) < 0) { + return INV_ERR; + } + (void) strcpy(fname, uuname); + strcat(fname, INV_INVINDEX_PREFIX); + + /* first check if the inv_index file exists: if not create it */ + if ((fd = open(fname, O_RDWR)) == -1) { + if (errno != ENOENT) { + INV_PERROR (fname); + return INV_ERR; + } + /* create the invidx */ + return oref_resolve_new_invidx(invidx, fname); + } + + invidx->fd = fd; + OREF_LOCK(invidx, LOCK_EX); + + if (oref_resolve_child(invidx, &index) == INV_ERR) { + OREF_UNLOCK(invidx); + return INV_ERR; + } + + stobj = OREF_CHILD(invidx); + + /* Now we need to make sure that this has enough space */ + OREF_LOCK(stobj, LOCK_SH); + + if (oref_resolve_upto(stobj, INVT_RES_COUNTERS) == INV_ERR) { + OREF_UNLOCK(stobj); + OREF_UNLOCK(invidx); + return INV_ERR; + } + + /* create another storage object ( and, an inv_index entry for it + too ) if we've filled this one up */ + if (OREF_CNT_CURNUM(stobj) >= OREF_CNT_MAXNUM(stobj)) { + intgen_t rval; +#ifdef INVT_DEBUG + mlog( MLOG_DEBUG | MLOG_INV, "$ INV: creating a new storage obj & " + "index entry. \n" ); +#endif + /* Close(), Destroy() and mark unresolved */ + OREF_UNRESOLVE_CHILD(invidx); + rval = oref_resolve_new_stobj(invidx, BOOL_FALSE); + /* rval = oref_idx_create_entry(invidx, BOOL_FALSE); */ + OREF_UNLOCK(invidx); + + return rval; + } + + OREF_UNLOCK(stobj); + OREF_UNLOCK(invidx); + + tok = get_token(invidx->fd, stobj->fd); + tok->d_invindex_off = IDX_HDR_OFFSET(index - 1); + + OREF_SET_TOKEN(tok); + return INV_OK; + +} + +/* + * Resolve the invidx entirely, and open the StObj. + * Invidx is kept locked by caller + */ +intgen_t +oref_resolve_child( + invt_oref_t *invidx, + int *index) +{ + invt_entry_t *ent; + ASSERT(OREF_IS_LOCKED(invidx)); + + if (oref_resolve_upto(invidx, INVT_RES_ENTRIES) == INV_ERR) + return INV_ERR; + + ent = OREF_ENTRIES(invidx); + + /* at this point we know that there should be at least one invindex + entry present */ + ASSERT ( ent != NULL ); + ASSERT ( ent->ie_filename ); + + fd = open( ent->ie_filename, O_RDWR ); + if ( fd < 0 ) { + INV_PERROR( ent->ie_filename ); + return INV_ERR; + } + + stobj = calloc(1, sizeof(invt_oref_t)); + OREF_SET_CHILD(invidx, stobj); + stobj->fd = fd; + + return INV_OK; +} + + + +/* used to be idx_create */ +intgen_t +oref_resolve_new_invidx( + invt_oref_t *invidx, + char *fname) +{ + int stobjfd, fd; + inv_idbtoken_t tok; + + if ((fd = open ( fname , O_RDWR | O_CREAT ) ) < 0 ) { + INV_PERROR ( fname ); + return INV_ERR; + } + invidx->fd = fd; + OREF_LOCK(invidx, LOCK_EX); + fchmod(fd, INV_PERMS); + +#ifdef INVT_DEBUG + mlog( MLOG_NITTY | MLOG_INV, "creating InvIndex %s\n", fname); +#endif + /* create the new stobj as its first entry */ + rval = oref_resolve_new_stobj(invidx, IS_EMPTY); + + OREF_UNLOCK(invidx); + return rval; + +} + + + +/* formerly idx_create_entry() */ +intgen_t +oref_resolve_new_stobj( + invt_oref_t *invidx, + bool_t firstentry) +{ + invt_entry_t ent; + int fd; + off64_t hoff; + invt_oref_t *stobj; + inv_idbtoken_t tok; + + ASSERT(OREF_ISLOCKED(invidx)); + + memset ( &ent, 0, sizeof( ent ) ); + stobj = calloc(1, sizeof(invt_oref_t)); + OREF_SET_CHILD(invidx, stobj); + + /* initialize the start and end times to be the same */ + ent.ie_timeperiod.tp_start = ent.ie_timeperiod.tp_end = (time_t)0; + stobj_makefname( ent.ie_filename ); + + if ( firstentry ) { + invt_counter_t *cnt; + cnt = malloc(sizeof(invt_counter_t)); + + cnt->ic_maxnum = INVT_MAX_INVINDICES; + cnt->ic_curnum = 1; + cnt->ic_vernum = INV_VERSION; + + fd = stobj_create( ent.ie_filename ); + if ( fd < 0 ) { + free(cnt); + return INV_ERR; + } + stobj->fd = fd; + OREF_SET_COUNTERS(invidx, cnt); + OREF_SET_ENTRIES(invidx, &ent); + if ((oref_sync(invidx, INVT_RES_COUNTERS) == INV_ERR) + || + (oref_sync(invidx, INVT_RES_ENTRIES) == INV_ERR)) + return INV_ERR; + } + else { + if (oref_resolve_upto(invidx, INVT_RES_COUNTERS) == INV_ERR) + return INV_ERR; + + /* create the new storage object */ + fd = stobj_create( ent.ie_filename ); + if ( fd < 0 ) { + return -1; + } + + stobj->fd = fd; + OREF_CNT_CURNUM(invidx)++; + + if ((oref_sync(invidx, INVT_RES_COUNTERS) == INV_ERR) + || + (oref_sync_append(invidx, INVT_RES_ENTRIES, + &ent, sizeof(ent)) == INV_ERR)) + return INV_ERR; + + } + tok = get_token( invfd, fd ); + tok->d_invindex_off = IDX_HDR_OFFSET(OREF_CNT_CURNUM(invidx) - 1); + tok->d_update_flag |= NEW_INVINDEX; + + OREF_SET_TOKEN(invidx, tok); + return INV_OK; + +} + + diff -rNu linux-2.4.7/cmd/xfsdump/inventory/inv_oref.h linux-2.4-xfs/cmd/xfsdump/inventory/inv_oref.h --- linux-2.4.7/cmd/xfsdump/inventory/inv_oref.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/inv_oref.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,348 @@ +/************************************************************************** + * * + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + * * + **************************************************************************/ +#ifndef _INV_OREF_H__ +#define _INV_OREF_H__ + +#include "inv_priv.h" + + +#define INVT_OTYPE_INVIDX 0x0001 +#define INVT_OTYPE_FSTAB 0x0002 +#define INVT_OTYPE_STOBJ 0x0004 + +#define INVT_OTYPE_MASK INVT_OTYPE_INVIDX | INVT_OTYPE_FSTAB | \ + INVT_OTYPE_STOBJ + +#define INVT_RES_COUNTERS 0x0010 +#define INVT_RES_ENTRIES 0x0020 + +#define INVT_STOBJ_RES_HDRS 0x0040 +#define INVT_STOBJ_RES_SESSIONS 0x0080 +#define INVT_STOBJ_RES_STRMS 0x0100 +#define INVT_STOBJ_RES_MFILES 0x0200 + +#define INVT_RES_MASK 0x0FF0 + +/* Indicates if either its child or its parent has been resolved. + Only one kin per object can exist. i.e. a child cant have children.*/ +#define INVT_RES_CHILD 0x1000 +#define INVT_RES_PARENT 0x2000 +#define INVT_RES_KIN INVT_RES_PARENT | INVT_RES_CHILD + + + +typedef __uint32_t invt_objtype_t; + +#define INVT_LOCKED 0x0001 + +typedef struct invt_oref { + int fd; + + /* counters - contains curnum, maxnum, etc */ + union { + invt_sescounter_t *sescnt; + invt_counter_t *cnt; + } oref_cnt_u; + + /* entries pointing at other invt objects */ + union { + invt_entry_t *ent; + invt_fstab_t *fstabent; + struct { + invt_seshdr_t *hdr; + invt_session_t *ses; + invt_stream_t *strm; + invt_mediafile_t *mfile; + } eu_sessent; + } oref_ent_u; + + union { + struct invt_oref *invidx; /* parent */ + struct invt_oref *stobj; /* child */ + } oref_kin_u; + + /* indicates level of depth this has been resolved to */ + invt_objtype_t type; + intgen_t lockflag; + void *token; +} invt_oref_t; + +#define eu_hdr oref_ent_u.eu_sessent.hdr +#define eu_ses oref_ent_u.eu_sessent.ses +#define eu_strm oref_ent_u.eu_sessent.strm +#define eu_mfile oref_ent_u.eu_sessent.mfile + +#define cu_cnt oref_cnt_u.cnt +#define cu_sescnt oref_sescnt_u.sescnt + +#define ku_invidx oref_kin_u.invidx +#define ku_stobj oref_kin_u.stobj + +/* + * See if the object has been resolved to the given level. + */ + +#define OREF_ISRESOLVED(oref, to_this_type) \ + ((oref)->type & (to_this_type)) + +#define OREF_INIT(oref) \ + { bzero((oref), sizeof(invt_oref_t)); \ + (oref)->fd = -1; } + +#define OREF_DESTROY(oref) \ + { if (OREF_ISRESOLVED(oref, INVT_RES_CHILD))\ + _oref_free((oref)->ku_stobj, BOOL_TRUE); \ + else if (OREF_ISRESOLVED(oref, INVT_RES_PARENT)) \ + _oref_free((oref)->ku_invidx, BOOL_TRUE); \ + _oref_free(oref, BOOL_FALSE); } + +#define OREF_COPY(src_oref, dst_oref) \ + (bcopy((src_oref), (dst_oref), sizeof(invt_oref_t))) + + + +/* + * For locking/unlocking orefs - mode { LOCK_SH, LOCK_EX, LOCK_UN } + */ + +#define OREF_LOCKMODE_EQL(oref, mode) ((oref)->lockflag == mode ) +#define OREF_ISLOCKED(oref) ((oref)->lockflag == 0 || + (oref)->lockflag == LOCK_UN) + +#define OREF_LOCK(oref, mode) \ + { if (! OREF_LOCKMODE_EQL(oref,mode)) \ + { INVLOCK((oref)->fd, mode); \ + (oref)->lockflag = mode; } \ + } +#define OREF_UNLOCK(oref) OREF_LOCK(oref, LOCK_UN) + +#define OREF_INVIDX_LOCK(oref, mode) \ + { if (OREF_ISRESOLVED(oref, INVT_OTYPE_INVIDX)) \ + OREF_LOCK(oref, mode); \ + else if (OREF_ISRESOLVED(oref, INVT_OTYPE_STOBJ)) \ + OREF_LOCK((oref)->invidx, mode); } + +#define OREF_STOBJ_LOCK(oref, mode) \ + { if (OREF_ISRESOLVED(oref, INVT_OTYPE_STOBJ)) \ + OREF_LOCK(oref, mode); \ + else if (OREF_ISRESOLVED(oref, INVT_OTYPE_INVIDX)) \ + OREF_LOCK((oref)->stobj, mode); } + + + + +#define OREF_SET_TYPE(oref, type) \ + { (oref)->type |= (type); } + +#define OREF_UNSET_TYPE(oref, type) \ + { (oref)->type &= ~(type); } + + + +#define OREF_SET_TOKEN(oref, tok) \ + { (oref)->token = tok; } + +#define OREF_SET_CNT(oref, cnt) \ + { ASSERT (OREF_ISRESOLVED(oref, INVT_OTYPE_MASK)); \ + ((oref)->type & INVT_OTYPE_STOBJ) ? \ + (oref)->cu_sescnt = (cnt): (oref)->cu_cnt = (cnt); \ + (oref)->type |= INVT_RES_COUNTERS; } + +#define OREF_SET_ENTRIES(oref, ents) \ + { ASSERT ((oref)->type & (INVT_OTYPE_INVIDX | INVT_OTYPE_FSTAB));\ + ASSERT ((oref)->type & INVT_RES_COUNTERS); \ + ((oref)->type & INVT_OTYPE_INVIDX) ? \ + (oref)->eu_ent = ents : (oref)->eu_fstabent = ents; \ + (oref)->type |= INVT_RES_ENTRIES; } + +#define OREF_SET_HDRS(oref, hdrs) \ + { ASSERT ((oref)->type & INVT_OTYPE_STOBJ); \ + ASSERT ((oref)->type & INVT_RES_COUNTERS); \ + (oref)->eu_hdr = hdrs; \ + (oref)->type |= INVT_STOBJ_RES_HDRS; } + +#define OREF_SET_SESSIONS(oref, ses) \ + { ASSERT ((oref)->type & INVT_OTYPE_STOBJ); \ + ASSERT ((oref)->type & INVT_RES_COUNTERS); \ + (oref)->eu_ses = ses; \ + (oref)->type |= INVT_STOBJ_RES_SESSIONS; } + +#define OREF_SET_STRMS(oref, strms) \ + { ASSERT ((oref)->type & INVT_OTYPE_STOBJ); \ + ASSERT ((oref)->type & INVT_RES_COUNTERS); \ + (oref)->eu_strm = strms; \ + (oref)->type |= INVT_STOBJ_RES_STRMS; } + +#define OREF_SET_CHILD(oref, stobjref) \ + { ASSERT (! OREF_ISRESOLVED(oref, INVT_RES_KIN)); \ + (oref)->ku_child = stobjref; \ + (oref)->type |= INVT_RES_CHILD; } + +#define OREF_SET_PARENT(oref, invidxref) \ + { ASSERT (! OREF_ISRESOLVED(oref, INVT_RES_KIN)); \ + (oref)->ku_parent = invidxref; \ + (oref)->type |= INVT_RES_PARENT; } + +#define OREF_UNRESOLVE_CHILD(oref) \ + { ASSERT (OREF_ISRESOLVED(oref, INVT_RES_CHILD)); \ + close((oref)->ku_child->fd); \ + OREF_DESTROY((oref)->ku_child); \ + (oref)->ku_child = 0; \ + OREF_UNSET_TYPE(oref, INVT_RES_CHILD); } + +#define OREF_TYPE(oref) ((oref)->type) + +#define OREF_CNT_CURNUM(oref) \ + ((oref)->type & INVT_OTYPE_STOBJ) ? \ + (oref)->cu_sescnt->ic_curnum : (oref)->cu_cnt->ic_curnum + +#define OREF_CNT_MAXNUM(oref) \ + ((oref)->type & INVT_OTYPE_STOBJ) ? \ + (oref)->cu_sescnt->ic_maxnum : (oref)->cu_cnt->ic_maxnum + +#define OREF_ENTRIES(oref) \ + ((oref)->type & INVT_OTYPE_INVIDX) ? \ + (oref)->eu_ent : (oref)->eu_fstabent + +#define OREF_HDRS(oref) ((oref)->eu_hdr) +#define OREF_SESSIONS(oref) ((oref)->eu_ses) +#define OREF_STRMS(oref) ((oref)->eu_strm) +#define OREF_MEDIAFILES(oref) ((oref)->eu_mfile) +#define OREF_TOKEN(oref) ((oref)->token) + +/*----------------------------------------------------------------------*/ +/* Function Prototypes */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +oref_resolve( + invt_oref_t *invidx, + inv_predicate_t bywhat, + void *pred); + +intgen_t +oref_resolve_upto( + invt_oref_t *obj, + invt_objtype_t type); + +intgen_t +oref_resolve_entries( + invt_oref_t *obj); + +intgen_t +oref_resolve_counters( + invt_oref_t *obj); + +void +_oref_free( + invt_oref_t *obj, + bool_t freethis); + + + + + + + + + + + + + + + + + + + + + + + +#ifdef NOTDEF + +extern int xlv_oref_resolve ( + xlv_oref_t *oref, xlv_tab_vol_entry_t *tab_vol_entry); + +extern int xlv_oref_resolve_from_list ( + xlv_oref_t *oref, xlv_oref_t *oref_list); + + +/* + * Prints out the object referenced by an oref. + */ + +extern void xlv_oref_print (xlv_oref_t *oref, int p_mode); + +/* + * An iterator that applies a user-supplied function and arg + * to every volume element that makes up an object. + * The user-supplied function returns 0 to continue with the + * iteration. Return 1 to stop. + */ +typedef int (*XLV_OREF_PF) (xlv_oref_t *, void *); + +extern void xlv_for_each_ve_in_obj ( + xlv_oref_t *oref, + XLV_OREF_PF operation, + void *arg); + +extern void xlv_for_each_ve_in_vol ( + xlv_oref_t *oref, + XLV_OREF_PF operation, + void *arg); + +extern int xlv_for_each_ve_in_subvol ( + xlv_oref_t *oref, + XLV_OREF_PF operation, + void *arg); + +extern int xlv_for_each_ve_in_plex ( + xlv_oref_t *oref, + XLV_OREF_PF operation, + void *arg); + + +/* + * Returns 1 if the oref is a null reference; i.e., it has just + * been XLV_OREF_INIT'ed and no new fields have been set. + */ +extern int xlv_oref_is_null (xlv_oref_t *oref); +#endif /* NOTDEF */ + + +#endif /* _INV_OREF_H_ */ diff -rNu linux-2.4.7/cmd/xfsdump/inventory/inv_priv.h linux-2.4-xfs/cmd/xfsdump/inventory/inv_priv.h --- linux-2.4.7/cmd/xfsdump/inventory/inv_priv.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/inv_priv.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,609 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef _INV_PRIV_H_ +#define _INV_PRIV_H_ + +#include /* for flock */ +#include "global.h" +#include "inventory.h" +#include "mlog.h" + + +/*----------------------------------------------------------------------*/ +/* The Inventory stores its data in a hierarchical manner. */ +/* */ +/* At the first level is the Fstab, which maintains a table of unique */ +/* file system ids for all file systems that it knows of. From this fsid*/ +/* we can derive the Inventory Index for that file system. */ +/* */ +/* Inventory Index contains references to all the Storage Objects that */ +/* carry data associated with (its) file system. The Storage Objects, */ +/* the third level (of indirection) are reserved for certain (variable) */ +/* time periods, and the inv-index keeps track of those timeperiods */ +/* in its table. In other words, for a given time, there is a unique */ +/* stobj that exists to contain a session that occured at that time.. */ +/* */ +/*----------------------------------------------------------------------*/ + +#define INV_LOCKFILE INV_DIRPATH"/invlock" +#define INVTSESS_COOKIE "idbsess0" +#define INVT_STOBJ_MAXSESSIONS 5 +#define INVT_MAX_INVINDICES -1 /* unlimited */ +#define FSTAB_UPDATED 1 +#define NEW_INVINDEX 2 + +/* session flags ( seshdr.sh_flag ) */ +#define INVT_PARTIAL (u_int)0x0001 +#define INVT_RESUMED (u_int)0x0002 + +/* media file flags ( mfile.mf_flag ) */ +#define INVT_MFILE_GOOD (u_char)0x01 +#define INVT_MFILE_INVDUMP (u_char)0x02 + +#define INVT_ENDTIME BOOL_FALSE +#define INVT_STARTTIME BOOL_TRUE +#define INVT_DOLOCK BOOL_TRUE +#define INVT_DONTLOCK BOOL_FALSE + +#define INVLOCK( fd, m ) flock( fd, m ) + +/* return values */ +#define INV_OK (intgen_t) 1 +#define INV_ERR (intgen_t) -1 + +#define I_DONE (int) -1 +#define I_EMPTYINV (int) -2 + +/* flags to oref_resolve_new_stobj() */ +#define IS_EMPTY BOOL_TRUE +#define IS_NOT_EMPTY BOOL_FALSE + +#define INV_PERMS S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH + +#define IS_WITHIN(ttpe, tm) ( tm >= (ttpe)->tp_start && \ + tm <= (ttpe)->tp_end ) +#define IDX_HDR_OFFSET(n) (off64_t) ( sizeof( invt_entry_t ) * \ + (size_t) (n)\ + + sizeof( invt_counter_t ) ) +#define STOBJ_OFFSET( nhdrs, nsess ) (off64_t) ( \ + sizeof( invt_sescounter_t ) + \ + (size_t) nhdrs * sizeof( invt_seshdr_t ) + \ + (size_t) nsess * sizeof( invt_session_t ) ) + +#define STREQL( n,m ) ( strcmp((n),(m)) == 0 ) +#define UUID_EQL( n,m,t ) ( uuid_compare( n, m, t ) == 0 ) +#define IS_PARTIAL_SESSION( h ) ( (h)->sh_flag & INVT_PARTIAL ) +#define IS_RESUMED_SESSION( h ) ( (h)->sh_flag & INVT_RESUMED ) +#define SC_EOF_INITIAL_POS (off64_t) (sizeof( invt_sescounter_t ) + \ + INVT_STOBJ_MAXSESSIONS * \ + ( sizeof( invt_seshdr_t ) + \ + sizeof( invt_session_t ) ) ) + +#define INV_PERROR(s) mlog( MLOG_NORMAL,"INV: %s %s\n", s,strerror(errno) ) +#define INV_OFLAG(f) ( f == INV_SEARCH_ONLY ) ? O_RDONLY: O_RDWR + +/*----------------------------------------------------------------------*/ +/* On Disk Data Structures */ +/* */ +/*----------------------------------------------------------------------*/ + +typedef struct invt_session { + uuid_t s_sesid; /* this session's id: 16 bytes*/ + uuid_t s_fsid; /* file system id */ + char s_label[INV_STRLEN]; /* session label */ + char s_mountpt[INV_STRLEN];/* path to the mount point */ + char s_devpath[INV_STRLEN];/* path to the device */ + u_int s_cur_nstreams;/* number of streams created under + this session so far */ + u_int s_max_nstreams;/* number of media streams in + the session */ + char s_padding[16]; +} invt_session_t; + +typedef struct invt_seshdr { + off64_t sh_sess_off; /* offset to rest of the sessioninfo */ + off64_t sh_streams_off; /* offset to start of the set of + stream hdrs */ + time_t sh_time; /* time of the dump */ + __uint32_t sh_flag; /* for misc flags */ + u_char sh_level; /* dump level */ + u_char sh_pruned; /* pruned by invutil flag */ + char sh_padding[22]; +} invt_seshdr_t; + + +/* Each session consists of a number of media streams. While it is given that + there won't be multiple writesessions (ie. dumpsessions) concurrently, + there can be multiple media streams operating on a single file system, + each writing media files within its own stream. Hence, we have a linked + list of media files, that the stream keeps track of. */ + + +typedef struct invt_breakpt { + xfs_ino_t ino; /* the 64bit inumber */ + off64_t offset; /* offset into the file */ +} invt_breakpt_t; + +typedef struct invt_stream { + /* duplicate info from mediafiles for speed */ + invt_breakpt_t st_startino; /* the starting pt */ + invt_breakpt_t st_endino; /* where we actually ended up. this + means we've written upto but not + including this breakpoint. */ + off64_t st_firstmfile; /*offsets to the start and end of*/ + off64_t st_lastmfile; /* .. linked list of mediafiles */ + char st_cmdarg[INV_STRLEN]; /* drive path */ + u_int st_nmediafiles; /* number of mediafiles */ + bool_t st_interrupted; /* was this stream interrupted ? */ + char st_padding[16]; +} invt_stream_t; + + + +typedef struct invt_mediafile { + uuid_t mf_moid; /* media object id */ + char mf_label[INV_STRLEN]; /* media file label */ + invt_breakpt_t mf_startino; /* file that we started out with */ + invt_breakpt_t mf_endino; /* the dump file we ended this + media file with */ + off64_t mf_nextmf; /* links to other mfiles */ + off64_t mf_prevmf; + u_int mf_mfileidx; /* index within the media object */ + u_char mf_flag; /* Currently MFILE_GOOD, INVDUMP */ + off64_t mf_size; /* size of the media file */ + char mf_padding[15]; +} invt_mediafile_t; + + + +typedef struct invt_timeperiod { + time_t tp_start; + time_t tp_end; +} invt_timeperiod_t; + +typedef struct invt_entry { + invt_timeperiod_t ie_timeperiod; + char ie_filename[INV_STRLEN]; + char ie_padding[16]; +} invt_entry_t; + +/* Cheap Inheritance, and an attempt to avoid a nested type */ +#define INVT_COUNTER_FIELDS \ + __uint32_t ic_vernum;/* on disk version number for posterity */\ + u_int ic_curnum;/* number of sessions/invindices recorded \ + so far */ \ + u_int ic_maxnum;/* maximum number of sessions/inv_indices \ + that we can record on this stobj */ +#define INVT_COUNTER_FIELDS_SIZE 0xc + +typedef struct invt_counter { + INVT_COUNTER_FIELDS + char ic_padding[0x20 - INVT_COUNTER_FIELDS_SIZE]; +} invt_counter_t; + +typedef struct invt_sescounter { + INVT_COUNTER_FIELDS + off64_t ic_eof; /* current end of the file, where the next + media file or stream will be written to */ + char ic_padding[0x20 - ( INVT_COUNTER_FIELDS_SIZE + + sizeof( off64_t) )]; +} invt_sescounter_t; + + +typedef struct invt_fstab { + uuid_t ft_uuid; + char ft_mountpt[INV_STRLEN]; + char ft_devpath[INV_STRLEN]; + char ft_padding[16]; +} invt_fstab_t; + + + +/*----------------------------------------------------------------------*/ +/* The Tokens */ +/* */ +/*----------------------------------------------------------------------*/ +typedef struct invt_desc_entry { + int d_invindex_fd; /* open file descriptor of inv index */ + int d_stobj_fd; /* fd of storage object */ + u_char d_update_flag; /* indicates whether fstab was updated with + this file system or not and also if + we had to create a new invindex file */ + inv_oflag_t d_oflag; /* the open mode (SEARCH_ONLY, SEARCH_N_MOD) */ + off64_t d_invindex_off; /* for every session, we need a reference + to its invindex entry, so that when we + close a session, we know which one */ +} invt_desc_entry_t; + + +typedef struct invt_sesdesc_entry { + invt_desc_entry_t *sd_invtok; /* generic inventory token */ + off64_t sd_session_off; + off64_t sd_sesshdr_off; + time_t sd_sesstime; /* time that session started. + needed for closing the session */ +} invt_sesdesc_entry_t; + +struct invt_mediafile; + +typedef struct invt_strdesc_entry { + invt_sesdesc_entry_t *md_sesstok; /* the session token */ + off64_t md_stream_off;/* offset to the media stream + header */ + struct invt_mediafile *md_lastmfile; /* just so that we dont have + to get it back from disk + when we add the next mfile + to the linked list */ + +} invt_strdesc_entry_t; + + + + +/*----------------------------------------------------------------------*/ +/* Info Structures - simple logical containers for sessions and indices */ +/* */ +/*----------------------------------------------------------------------*/ + +typedef struct invt_sessinfo { + int stobjfd; + invt_seshdr_t *seshdr; + invt_session_t *ses; + invt_stream_t *strms; + invt_mediafile_t *mfiles; +} invt_sessinfo_t; + +typedef struct invt_idxinfo { + int invfd; + invt_counter_t *icnt; + invt_entry_t *iarr; + u_int index; +}invt_idxinfo_t; + +#define INVT_MOID 1 +#define INVT_LABEL 2 +#define INVT_NULLTYPE -1 +typedef struct invt_mobjinfo { + int type; + void *value; +} invt_mobjinfo_t; + + +typedef struct invt_pr_ctx { + int index; + int depth; + bool_t fstab; + bool_t invidx; + bool_t invcheck; + invt_mobjinfo_t mobj; + u_char level; +} invt_pr_ctx_t; + +typedef bool_t (*search_callback_t) (int, invt_seshdr_t *, void *, void *); + + +#define GET_REC( fd, buf, sz, off ) \ + get_invtrecord( fd, buf, sz, off, SEEK_SET, INVT_DOLOCK ) + +#define GET_REC_NOLOCK( fd, buf, sz, off ) \ + get_invtrecord( fd, buf, sz, off, SEEK_SET, INVT_DONTLOCK ) + +#define GET_REC_SEEKCUR( fd, buf, sz, off ) \ + get_invtrecord( fd, buf, sz, off, SEEK_CUR, INVT_DOLOCK ) + +#define GET_ALLHDRS_N_CNTS( fd, h, c, hsz, csz ) \ + get_headerinfo( fd, h, c, hsz, csz, INVT_DOLOCK ) + +#define GET_ALLHDRS_N_CNTS_NOLOCK( fd, h, c, hsz, csz ) \ + get_headerinfo( fd, h, c, hsz, csz, INVT_DONTLOCK ) + +#define PUT_REC( fd, buf, sz, off ) \ + put_invtrecord( fd, buf, sz, off, SEEK_SET, INVT_DOLOCK ) + +#define PUT_REC_NOLOCK( fd, buf, sz, off ) \ + put_invtrecord( fd, buf, sz, off, SEEK_SET, INVT_DONTLOCK ) + +#define PUT_REC_SEEKCUR( fd, buf, sz, off ) \ + put_invtrecord( fd, buf, sz, off, SEEK_CUR, INVT_DOLOCK ) + +#define PUT_REC_NOLOCK_SEEKCUR( fd, buf, sz, off ) \ + put_invtrecord( fd, buf, sz, off, SEEK_CUR, INVT_DONTLOCK ) + + +#define GET_COUNTERS( fd, cnt ) get_counters( fd, (void **)(cnt), \ + sizeof(invt_counter_t) ) +#define GET_SESCOUNTERS( fd, cnt ) get_counters( fd, (void **)(cnt), \ + sizeof(invt_sescounter_t) ) + +#define PUT_COUNTERS( fd, cnt ) PUT_REC_NOLOCK( fd, (void *)(cnt), \ + sizeof( invt_counter_t ), \ + (off64_t) 0 ) + +#define PUT_SESCOUNTERS( fd, cnt ) PUT_REC_NOLOCK( fd, (void *)(cnt), \ + sizeof( invt_sescounter_t ), \ + (off64_t) 0 ) + +#define GET_SESHEADERS( fd, hdrs, n ) get_headers( fd, (void**)(hdrs), \ + (size_t) ( n * sizeof(invt_seshdr_t ) ),\ + sizeof( invt_sescounter_t ) ) + +#define GET_ENTRIES(fd, hdrs, n, sz) get_headers(fd, (void**)(hdrs), \ + (size_t) (n * sz), sizeof(invt_counter_t)) + +/*----------------------------------------------------------------------*/ +/* Function Prototypes */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + + +/*----------------------------------------------------------------------*/ +inv_idbtoken_t +idx_create( char *fname, inv_oflag_t forwhat ); + +intgen_t +idx_create_entry( inv_idbtoken_t *tok, int invfd, bool_t firstentry ); + +intgen_t +idx_put_sesstime( inv_sestoken_t tok, bool_t whichtime); + + +int +idx_find_stobj( invt_idxinfo_t *idx, time_t tm ); + +u_int +idx_insert_newentry( int fd, int *stobjfd, invt_entry_t *iarr, + invt_counter_t *icnt, + time_t tm ); +intgen_t +idx_put_newentry( invt_idxinfo_t *idx, invt_entry_t *ient ); + +int +idx_get_stobj( int invfd, inv_oflag_t forwhat, int *index ); + +intgen_t +idx_recons_time( time_t tm, invt_idxinfo_t *idx ); + +intgen_t +idx_DEBUG_printinvindices( invt_entry_t *iarr, u_int num ); + +intgen_t +idx_DEBUG_print ( int fd ); + +/*----------------------------------------------------------------------*/ + +int +stobj_create( char *fname ); + +intgen_t +stobj_create_session( inv_sestoken_t tok, int fd, invt_sescounter_t *sescnt, + invt_session_t *ses, invt_seshdr_t *hdr ); + +intgen_t +stobj_put_mediafile( inv_stmtoken_t tok, invt_mediafile_t *mf ); + +off64_t +stobj_put_session( + int fd, + invt_sescounter_t *sescnt, + invt_session_t *ses, + invt_seshdr_t *hdr, + invt_stream_t *strms, + invt_mediafile_t *mfiles ); + +intgen_t +stobj_put_streams( int fd, invt_seshdr_t *hdr, invt_session_t *ses, + invt_stream_t *strms, + invt_mediafile_t *mfiles ); + +int +stobj_hdrcmp( const void *h1, const void *h2 ); + +intgen_t +stobj_sortheaders( int fd, u_int num ); + +u_int +stobj_find_splitpoint( int fd, invt_seshdr_t *harr, u_int ns, time_t tm ); + +intgen_t +stobj_split( invt_idxinfo_t *idx, int fd, invt_sescounter_t *sescnt, + invt_sessinfo_t *newsess ); +bool_t +stobj_replace_session( int fd, invt_sescounter_t *sescnt, invt_session_t *ses, + invt_seshdr_t *hdr, invt_sessinfo_t *newsess ); + +intgen_t +stobj_delete_mfile( int fd, inv_stream_t *strm, invt_mediafile_t *mf, + off64_t mfileoff ); + +bool_t +stobj_pack_sessinfo( int fd, invt_session_t *ses, invt_seshdr_t *hdr, + void **bufpp, size_t *bufszp ); + +bool_t +stobj_unpack_sessinfo( + void *bufp, + size_t bufsz, + invt_sessinfo_t *s ); + +bool_t +stobj_delete_sessinfo( int fd, invt_sescounter_t *sescnt, + invt_session_t *ses, invt_seshdr_t *hdr ); + +bool_t +stobj_delete_mobj( int fd, invt_seshdr_t *hdr, void *arg, + void **buf ); + +intgen_t +stobj_get_sessinfo ( inv_sestoken_t tok, invt_seshdr_t *hdr, invt_session_t *ses ); + +void +stobj_makefname( char *fname ); + +intgen_t +stobj_insert_session( invt_idxinfo_t *idx, int fd, + invt_sessinfo_t *s ); + +intgen_t +stobj_make_invsess( int fd, inv_session_t **buf, invt_seshdr_t *hdr ); + +intgen_t +stobj_copy_invsess( int fd, invt_seshdr_t *hdr, invt_session_t *ses, + inv_session_t **buf); + +void +DEBUG_sessionprint( inv_session_t *ses, u_int ref, invt_pr_ctx_t *prctx); + +void +DEBUG_sessprint( invt_session_t *ses ); + +bool_t +stobj_getsession_byuuid(int fd, invt_seshdr_t *hdr, void *sesid, void **buf); + +bool_t +stobj_getsession_bylabel(int fd, invt_seshdr_t *hdr, void *label, void **buf); + + +void +stobj_convert_session(inv_session_t *ises, invt_session_t *ses, + invt_seshdr_t *hdr); + +void +stobj_convert_strm(inv_stream_t *expstrm, invt_stream_t *strm); + +void +stobj_convert_mfile(inv_mediafile_t *expmf, invt_mediafile_t *mf); + +void +stobj_convert_sessinfo(inv_session_t **buf, invt_sessinfo_t *sinfo); + +/*----------------------------------------------------------------------*/ + +intgen_t +fstab_get_fname( void *pred, char *fname, inv_predicate_t bywhat, + inv_oflag_t forwhat ); + +intgen_t +fstab_put_entry( uuid_t *fsidp, char *mntpt, char *dev, inv_oflag_t forwhat ); + +intgen_t +fstab_getall( invt_fstab_t **arr, invt_counter_t **cnt, int *numfs, + inv_oflag_t forwhat ); + +void +fstab_DEBUG_print( invt_fstab_t *arr, int num ); + + +/*----------------------------------------------------------------------*/ + +intgen_t +get_invtentry( char *fname, time_t tm, invt_entry_t *buf, size_t bufsz ); + +intgen_t +get_invtrecord( int fd, void *buf, size_t bufsz, off64_t off, int, bool_t dolock ); + +intgen_t +put_invtrecord( int fd, void *buf, size_t bufsz, off64_t off, int, bool_t dolock ); + +inv_idbtoken_t +get_token( int fd, int objfd ); + +void +destroy_token( inv_idbtoken_t tok ); + + +intgen_t +get_headers( int fd, void **hdrs, size_t bufsz, size_t cntsz ); + +intgen_t +get_counters( int fd, void **cntpp, size_t sz ); + +intgen_t +get_sescounters( int fd, invt_sescounter_t **cntpp ); + +intgen_t +get_lastheader( int fd, void **ent, size_t hdrsz, size_t cntsz ); + + +inv_sestoken_t +get_sesstoken( inv_idbtoken_t tok ); + +intgen_t +get_headerinfo( int fd, void **hdrs, void **cnt, + size_t hdrsz, size_t cntsz, bool_t doblock ); + +bool_t +invmgr_query_all_sessions (void *inarg, void **outarg, search_callback_t func); + +intgen_t +search_invt( int invfd, void *arg, void **buf, + search_callback_t do_chkcriteria ); +intgen_t +invmgr_inv_print( int invfd, invt_pr_ctx_t *prctx); + +intgen_t +invmgr_inv_check( int invfd ); + +bool_t +tm_level_lessthan( int fd, invt_seshdr_t *hdr, void *arg, + void **tm ); + +bool_t +lastsess_level_lessthan( int fd, invt_seshdr_t *hdr, void *arg, + void **buf ); + +bool_t +lastsess_level_equalto( int fd, invt_seshdr_t *hdr, void *arg, void **buf ); + +intgen_t +DEBUG_displayallsessions( int fd, invt_seshdr_t *hdr, u_int ref, + invt_pr_ctx_t *prctx); + +intgen_t +make_invdirectory( inv_oflag_t forwhat ); + +bool_t +init_idb( void *pred, inv_predicate_t bywhat, inv_oflag_t forwhat, + inv_idbtoken_t *tok ); + +intgen_t +inv_getopt( int argc, char **argv, invt_pr_ctx_t *prctx); + +bool_t +insert_session( invt_sessinfo_t *s); + +/* To reconstruct a complete inventory from dumped inventories */ +extern bool_t +inv_put_sessioninfo( invt_sessinfo_t *s ); + + +#endif diff -rNu linux-2.4.7/cmd/xfsdump/inventory/inv_stobj.c linux-2.4-xfs/cmd/xfsdump/inventory/inv_stobj.c --- linux-2.4.7/cmd/xfsdump/inventory/inv_stobj.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/inv_stobj.c Sun May 6 21:37:12 2001 @@ -0,0 +1,1501 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "mlog.h" +#include "inv_priv.h" +#include "arch_xlate.h" + + + +/*----------------------------------------------------------------------*/ +/* stobj_insert_session */ +/* */ +/* Used in reconstruction of the inventory. We add a session to this */ +/* storage object whether or not it has reached its maximum. */ +/*----------------------------------------------------------------------*/ +intgen_t +stobj_insert_session( invt_idxinfo_t *idx, + int fd, /* kept locked EX by caller */ + invt_sessinfo_t *s ) +{ + invt_sescounter_t *sescnt = NULL; + + if ( GET_SESCOUNTERS( fd, &sescnt ) < 0 ) { + INVLOCK( fd, LOCK_UN ); + return -1; + } + + /* Check the existing sessions to make sure that we're not + duplicating this session */ + if ( sescnt->ic_curnum > 0 ) { + u_int i; + invt_session_t *sessions = calloc( sescnt->ic_curnum, + sizeof( invt_session_t ) ); + if ( GET_REC_NOLOCK( fd, sessions, sescnt->ic_curnum * + sizeof( invt_session_t ), + (off64_t) ( sizeof( *sescnt ) + + sescnt->ic_maxnum * sizeof( invt_seshdr_t ))) < 0 ) { + free ( sescnt ); + free ( sessions ); + return -1; + } + + for( i = 0; i < sescnt->ic_curnum; i++ ) { + if ( uuid_compare( sessions[i].s_sesid, + s->ses->s_sesid ) == 0 ) + break; + + } + free ( sessions ); + if ( i < sescnt->ic_curnum ) { + mlog( MLOG_DEBUG | MLOG_INV, + "INV: attempt to insert an " + "existing session.\n" + ); + free ( sescnt ); + return 1; + } + + } + + if ( sescnt->ic_curnum >= sescnt->ic_maxnum ) { + if ( stobj_split( idx, fd, sescnt, s ) < 0 ) { + free( sescnt ); + return -1; + } + free( sescnt ); + return 1; + + } + + if ( stobj_put_session( fd, sescnt, s->ses, s->seshdr, s->strms, + s->mfiles ) < 0 ){ + free ( sescnt); + return -1; + } + + free ( sescnt); + return 1; +} + + +/*----------------------------------------------------------------------*/ +/* stobj_find_splitpoint */ +/* */ +/* Load in all the session headers, and go thru them, one by one, */ +/* beginning with last seshdr. We return once we find one with a */ +/* different sh_time from the previous one. */ +/*----------------------------------------------------------------------*/ + + +/* ARGSUSED */ +u_int +stobj_find_splitpoint( int fd, invt_seshdr_t *harr, u_int ns, time_t tm ) +{ + u_int i; + + if ( harr[ns-1].sh_time < tm ) + return ns; + /* since ns > 1, our split point > 0 */ + for ( i = ns - 1; i > 0; i-- ) { + /* these are ordered in ascending order */ + if ( harr[i].sh_time > harr[i-1].sh_time ) + return i; + } + + + /* All the entries have the same sh_time. It's not clear if that's + really possible, but either way, we split at the last entry. + This will impact the guarantee that invindex tries to give - that + there's always a unique stobj for every session. */ + mlog( MLOG_VERBOSE | MLOG_INV, + "INV: failed to find a different sh_time to split\n" + ); + + return ns - 1; + + + +} + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +stobj_split( invt_idxinfo_t *idx, int fd, invt_sescounter_t *sescnt, + invt_sessinfo_t *newsess ) +{ + invt_seshdr_t *harr = NULL; + u_int i, ix, ns = sescnt->ic_curnum; + void *bufpp; + size_t bufszp; + invt_sessinfo_t sesinfo; + invt_entry_t ient; + + if ( GET_SESHEADERS( fd, &harr, ns ) < 0 ) + return -1; + + ASSERT( harr != NULL ); + + if ( ( ix = stobj_find_splitpoint( fd, harr, ns, + newsess->seshdr->sh_time ) ) == 0 ) + return -1; + + if ( ix == ns ) { + ient.ie_timeperiod.tp_start = ient.ie_timeperiod.tp_end = + newsess->seshdr->sh_time; + } else { + ient.ie_timeperiod.tp_start = ient.ie_timeperiod.tp_end = + harr[ix].sh_time; + if ( harr[ix - 1].sh_time > newsess->seshdr->sh_time ) + idx->iarr[idx->index].ie_timeperiod.tp_end + = harr[ix - 1].sh_time; + else + idx->iarr[idx->index].ie_timeperiod.tp_end + = newsess->seshdr->sh_time; + } + + /* Get the new stobj to put the 'spilling' sessinfo in. We know the + idx of the current stobj, and by definition, the new stobj + should come right afterwards. */ + newsess->stobjfd = idx_put_newentry( idx, &ient ); + if ( newsess->stobjfd < 0 ) + return -1; + + if ( ix == ns ) { + invt_sescounter_t *scnt = NULL; + off64_t rval; + + /* We dont need to split. So, just put the new session in + the new stobj, and rest in peace */ + idx->index++; + + if ( GET_SESCOUNTERS( newsess->stobjfd, &scnt ) < 0 ) + return -1; + + rval = stobj_put_session( newsess->stobjfd, scnt, + newsess->ses, + newsess->seshdr, newsess->strms, + newsess->mfiles ); + free( scnt ); + return (rval < 0)? -1: 1; + } + + + + for ( i = ix; i < ns; i++ ) { + invt_session_t session; + bufpp = NULL; + bufszp = 0; + + newsess->seshdr->sh_sess_off = harr[i].sh_sess_off; + + if ( GET_REC_NOLOCK( fd, &session, sizeof( invt_session_t ), + harr[i].sh_sess_off ) < 0 ) + return -1; + if (! stobj_pack_sessinfo( fd, &session, &harr[i], &bufpp, + &bufszp )) + return -1; + /* Now we need to put this in the new StObj. So, first + unpack it. */ + if (! stobj_unpack_sessinfo( bufpp, bufszp, &sesinfo ) ) + return -1; + + /* There is no chance of a recursion here */ + if ( stobj_insert_session( idx, newsess->stobjfd, &sesinfo ) + < 0 ) + return -1; + + /* Now delete that session from this StObj */ + if (! stobj_delete_sessinfo( fd, sescnt, &session, + &harr[i] ) ) + return -1; + free( bufpp ); + } + /* Put the new session in the stobj that we just split. Make + sure that we use the updated sescnt and not the stale stuff + from disk. stobj_put_session() writes sescnt and sessinfo to + disk */ + if ( stobj_put_session( fd, sescnt, newsess->ses, newsess->seshdr, + newsess->strms, newsess->mfiles ) < 0 ) { + free ( sescnt); + return -1; + } + + + return 1; +} + + + + +/* ARGSUSED */ +intgen_t +stobj_delete_mfile( int fd, inv_stream_t *strm, invt_mediafile_t *mf, + off64_t mfileoff ) +{ + + return 1; + +} + + + + +/* ARGSUSED */ +bool_t +stobj_delete_sessinfo( int fd, /* kept locked EX by caller */ + invt_sescounter_t *sescnt, + invt_session_t *ses, invt_seshdr_t *hdr ) +{ + /* we change the sescnt here, but dont write it back to disk + until later */ + sescnt->ic_curnum--; + + /* there is really no need to take out / zero out the deleted + session. The seshdr and session will be over-written, but + space taken by the streams and mediafiles will be wasted. */ + return BOOL_TRUE; +} + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + + +off64_t +stobj_put_session( + int fd, + invt_sescounter_t *sescnt, + invt_session_t *ses, + invt_seshdr_t *hdr, + invt_stream_t *strms, + invt_mediafile_t *mfiles ) +{ + off64_t hoff; + + /* figure out the place where the header will go */ + hoff = STOBJ_OFFSET( sescnt->ic_curnum, 0 ); + + /* figure out where the session information is going to go. */ + if ( hdr->sh_sess_off < 0 ) + hdr->sh_sess_off = STOBJ_OFFSET( sescnt->ic_maxnum, + sescnt->ic_curnum ); + sescnt->ic_curnum++; + +#ifdef INVT_DEBUG + mlog ( MLOG_VERBOSE, + "INV: create sess #%d @ offset %d ic_eof = %d\n", + sescnt->ic_curnum, (int) hdr->sh_sess_off, + (int) sescnt->ic_eof ); +#endif + + /* we need to know where the streams begin, and where the + media files will begin, at the end of the streams */ + hdr->sh_streams_off = sescnt->ic_eof; + + if ( strms == NULL ) { + sescnt->ic_eof += (off64_t)( ses->s_max_nstreams * + sizeof( invt_stream_t ) ); + } else { + u_int i; + size_t nmf = 0; + sescnt->ic_eof += (off64_t)( ses->s_cur_nstreams * + sizeof( invt_stream_t ) ); + for (i=0; is_cur_nstreams; i++) + nmf += ( size_t ) strms[i].st_nmediafiles; + + sescnt->ic_eof += (off64_t)( sizeof( invt_mediafile_t ) + * nmf ); + if ( stobj_put_streams( fd, hdr, ses, strms, mfiles ) < 0 ) + return -1; + + } + + /* we write back the counters of this storage object first */ + if ( PUT_SESCOUNTERS( fd, sescnt ) < 0 ) + return -1; + + /* write the header next; lseek to the right position */ + if ( PUT_REC_NOLOCK( fd, hdr, sizeof( invt_seshdr_t ), hoff ) < 0 ) { + return -1; + } + + /* write the header information to the storage object */ + if ( PUT_REC_NOLOCK( fd, ses, sizeof( invt_session_t ), + hdr->sh_sess_off ) < 0 ) { + return -1; + } + + if ( strms != NULL ) + stobj_sortheaders( fd, sescnt->ic_curnum ); + + return hoff; +} + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +stobj_sortheaders( int fd, u_int num ) +{ + size_t sz = sizeof( invt_seshdr_t ) * num; + invt_seshdr_t *hdrs; +#ifdef INVT_DEBUG + int i; +#endif + if ( num < 2 ) return 1; + + hdrs = malloc( sz ); + ASSERT( hdrs ); + + if ( GET_REC_NOLOCK( fd, hdrs, sz, STOBJ_OFFSET( 0, 0 ) ) < 0 ) { + free ( hdrs ); + return -1; + } +#ifdef INVT_DEBUG + printf("\nBEF\n" ); + for (i=0; i<(int)num; i++) + printf("%ld\n", (long) hdrs[i].sh_time ); +#endif + qsort( (void*) hdrs, (size_t) num, + sizeof( invt_seshdr_t ), stobj_hdrcmp ); + +#ifdef INVT_DEBUG + printf("\n\nAFT\n" ); + for (i=0; i<(int)num; i++) + printf("%ld\n", (long) hdrs[i].sh_time ); +#endif + if ( PUT_REC_NOLOCK( fd, hdrs, sz, STOBJ_OFFSET( 0, 0 ) ) < 0 ) { + free ( hdrs ); + return -1; + } + + free ( hdrs ); + return 1; + +} + + + +/*----------------------------------------------------------------------*/ +/* stobj_put_streams */ +/* */ +/* used only in reconstruction. */ +/* puts the array of streams and the array of mediafiles in the stobj, */ +/* after adjusting their offsets. */ +/*----------------------------------------------------------------------*/ + +intgen_t +stobj_put_streams( int fd, invt_seshdr_t *hdr, invt_session_t *ses, + invt_stream_t *strms, + invt_mediafile_t *mfiles ) +{ + u_int nstm = ses->s_cur_nstreams; + off64_t off = hdr->sh_streams_off; + off64_t mfileoff = off + (off64_t)( nstm * sizeof( invt_stream_t ) ); + u_int nmfiles = 0; + u_int i,j; + + /* fix the offsets in streams */ + for ( i = 0; i < nstm; i++ ) { + strms[i].st_firstmfile = mfileoff + + (off64_t) ((size_t) nmfiles * sizeof( invt_mediafile_t ) ); + /* now fix the offsets in mediafiles */ + for ( j = 0; j < strms[i].st_nmediafiles; j++ ) { + + /* no need to fix the last element's next ptr */ + if ( j < strms[i].st_nmediafiles - 1 ) + mfiles[ nmfiles + j ].mf_nextmf = + strms[i].st_firstmfile + + (off64_t) ((j+1) * sizeof( invt_mediafile_t )); + + /* no need to fix the first element's prev ptr */ + if ( j ) + mfiles[ nmfiles + j ].mf_prevmf = + strms[i].st_firstmfile + + (off64_t) ((j-1) * sizeof( invt_mediafile_t )); + } + + /* adjust the offsets of the first and the last elements + in the mediafile chain */ + mfiles[ nmfiles ].mf_prevmf = 0; + nmfiles += strms[i].st_nmediafiles; + mfiles[ nmfiles - 1 ].mf_nextmf = 0; + + } + + /* first put the streams. hdr already points at the right place */ + if ( PUT_REC_NOLOCK( fd, strms, nstm * sizeof( invt_stream_t ), + off ) < 0 ) + return -1; + + if ( PUT_REC_NOLOCK( fd, mfiles, nmfiles * sizeof( invt_mediafile_t ), + mfileoff ) < 0 ) + return -1; + + return 1; + +} + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +void +stobj_makefname( char *fname ) +{ + /* come up with a new unique name */ + uuid_t fn; + char str[UUID_STR_LEN + 1]; + + uuid_generate( fn ); + uuid_unparse( fn, str ); + + strcpy( fname, INV_DIRPATH ); + strcat( fname, "/" ); + strcat( fname, str ); + strcat( fname, INV_STOBJ_PREFIX ); + + ASSERT( (int) strlen( fname ) < INV_STRLEN ); +} + + + + + + + +/* NOTE: this doesnt update counters or headers in the inv_index */ +int +stobj_create( char *fname ) +{ + int fd; + invt_sescounter_t sescnt; + inv_oflag_t forwhat = INV_SEARCH_N_MOD; + +#ifdef INVT_DEBUG + mlog( MLOG_VERBOSE | MLOG_INV, "INV: creating storage obj %s\n", fname); +#endif + + /* create the new storage object */ + if (( fd = open( fname, INV_OFLAG(forwhat) | O_EXCL | O_CREAT )) < 0 ) { + INV_PERROR ( fname ); + memset( fname, 0, INV_STRLEN ); + return -1; + } + + INVLOCK( fd, LOCK_EX ); + fchmod( fd, INV_PERMS ); + + sescnt.ic_vernum = INV_VERSION; + sescnt.ic_curnum = 0; /* there are no sessions as yet */ + sescnt.ic_maxnum = INVT_STOBJ_MAXSESSIONS; + sescnt.ic_eof = SC_EOF_INITIAL_POS; + + if ( PUT_SESCOUNTERS ( fd, &sescnt ) < 0 ) { + memset( fname, 0, INV_STRLEN ); + INVLOCK( fd, LOCK_UN ); + close( fd ); + return -1; + } + + INVLOCK( fd, LOCK_UN ); + return fd; +} + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + + +intgen_t +stobj_create_session( + inv_sestoken_t tok, + int fd, /* kept locked EX by caller */ + invt_sescounter_t *sescnt, + invt_session_t *ses, + invt_seshdr_t *hdr ) +{ + off64_t hoff; + + ASSERT( tok && sescnt && ses && hdr ); + + hdr->sh_sess_off = -1; + ses->s_cur_nstreams = 0; + + if ((hoff = stobj_put_session( fd, sescnt, ses, hdr, NULL, NULL )) + < 0) { + return -1; + } + + tok->sd_sesshdr_off = hoff; + tok->sd_session_off = hdr->sh_sess_off; + + return 1; +} + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* The stobj_fd in the stream token is kept locked EX by caller. */ +/*----------------------------------------------------------------------*/ + +intgen_t +stobj_put_mediafile( inv_stmtoken_t tok, invt_mediafile_t *mf ) +{ + int rval; + invt_sescounter_t *sescnt = NULL; + invt_stream_t stream; + inv_sestoken_t sestok = tok->md_sesstok; + int fd = sestok->sd_invtok->d_stobj_fd; + off64_t pos; + + /* first we need to find out where the current write-position is. + so, we first read the sescounter that is at the top of this + storage object */ + if ( GET_SESCOUNTERS( fd, &sescnt ) < 0 ) + return -1; + + pos = sescnt->ic_eof; + + /* increment the pointer to give space for this media file */ + sescnt->ic_eof += (off64_t) sizeof( invt_mediafile_t ); + + if ( PUT_SESCOUNTERS( fd, sescnt ) < 0 ) + return -1; + + /* get the stream information, and update number of mediafiles. + we also need to link the new mediafile into the linked-list of + media files of this stream */ + + if ( GET_REC_NOLOCK( fd, &stream, sizeof( stream ), + tok->md_stream_off ) < 0 ) + return -1; + + /* We need to update the last ino of this STREAM, which is now the + last ino of the new mediafile. If this is the first mediafile, we + have to update the startino as well. Note that ino is a + tuple */ + if ( ! ( mf->mf_flag & INVT_MFILE_INVDUMP )) { + if ( stream.st_nmediafiles == 0 ) + stream.st_startino = mf->mf_startino; + stream.st_endino = mf->mf_endino; + } + + stream.st_nmediafiles++; +#ifdef INVT_DEBUG + mlog (MLOG_VERBOSE, "#################### mediafile #%d " + "###################\n", stream.st_nmediafiles); +#endif + /* add the new mediafile at the tail of the list */ + + mf->mf_nextmf = tok->md_stream_off; + mf->mf_prevmf = stream.st_lastmfile; + + + if ( tok->md_lastmfile ) + tok->md_lastmfile->mf_nextmf = pos; + else { + stream.st_firstmfile = pos; + } + + stream.st_lastmfile = pos; + + + /* write the stream to disk */ + if ( PUT_REC_NOLOCK( fd, &stream, sizeof( stream ), + tok->md_stream_off ) < 0 ) + return -1; + + /* write the prev media file to disk too */ + if ( tok->md_lastmfile ) { + rval = PUT_REC_NOLOCK( fd, tok->md_lastmfile, + sizeof( invt_mediafile_t ), + mf->mf_prevmf ); + free ( tok->md_lastmfile ); + if ( rval < 0 ) + return -1; + } + + if ( ! ( mf->mf_flag & INVT_MFILE_INVDUMP )) { + tok->md_lastmfile = mf; + } else { + tok->md_lastmfile = NULL; + } + + /* at last, write the new media file to disk */ + rval = PUT_REC_NOLOCK( fd, mf, sizeof( invt_mediafile_t ), pos ); + if ( rval < 0 ) { + return -1; + } + + return rval; +} + + + + + + + + +/*----------------------------------------------------------------------*/ +/* get_sessinfo */ +/* */ +/* get both the seshdr and session infomation. */ +/* caller takes the responsibility of locking. */ +/*----------------------------------------------------------------------*/ + +intgen_t +stobj_get_sessinfo ( inv_sestoken_t tok, invt_seshdr_t *hdr, + invt_session_t *ses ) +{ + int rval; + int fd = tok->sd_invtok->d_stobj_fd; + + /* get the session header first */ + if ( ( rval = GET_REC_NOLOCK( fd, hdr, sizeof( invt_seshdr_t ), + tok->sd_sesshdr_off ) ) > 0 ) { + rval = GET_REC_NOLOCK( fd, ses, sizeof( invt_session_t ), + tok->sd_session_off ); + } + + return rval; +} + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +bool_t +stobj_pack_sessinfo( int fd, invt_session_t *ses, invt_seshdr_t *hdr, + void **bufpp, size_t *bufszp ) +{ + size_t stmsz; + u_int i, j; + size_t sessz; + invt_stream_t *strms; + char *sesbuf, *sesbufcp; + off64_t off; + invt_mediafile_t mf; + + stmsz = sizeof( invt_stream_t ) * ses->s_cur_nstreams; + + /* the initial size without the mediafiles */ + sessz = strlen( INVTSESS_COOKIE ) * sizeof( char ) + + sizeof( inv_version_t ) + + sizeof( inv_version_t ) + /* added to fix 64 bit alignment prob */ + sizeof( invt_session_t) + sizeof( invt_seshdr_t ) + stmsz; + + /* now get all the streams of this session */ + strms = calloc ( ses->s_cur_nstreams, sizeof( invt_stream_t ) ); + if ( GET_REC_NOLOCK( fd, strms, stmsz, hdr->sh_streams_off ) < 0 ) { + free ( strms ); + return BOOL_FALSE; + } + + for ( i = 0; i < ses->s_cur_nstreams; i++ ) + sessz += sizeof( invt_mediafile_t ) * + (size_t) strms[i].st_nmediafiles; + + /* Now we know how big this entire thing is going to be */ + sesbufcp = sesbuf = calloc( 1, sessz ); + ASSERT( sesbuf ); + + /* Copy everything. Note that we don't bother to adjust the offsets + either in the seshdr or in the mediafiles, because we don't need + those in order to restore this session ( since everything's + contiguous ) */ + + /* magic cookie that we put for sanity checking in case of an + earthquake or something :) */ + strcpy( sesbuf, INVTSESS_COOKIE ); + sesbuf += (size_t)( strlen( INVTSESS_COOKIE ) * sizeof( char ) ); + + /* This was originally INV_VERSION. Changed it to mean packed inventory + * version number and added another inv_version_t to contain the INV_VERSION. + * The primary intent of this change was to make everything 64 bit aligned, + * but we also got the advantage of separating the packed inv version from + * the general inventory version + */ + *(inv_version_t *)sesbuf = INT_GET(PACKED_INV_VERSION, ARCH_CONVERT); + sesbuf += sizeof( inv_version_t ); + + /* This has the INV_VERSION */ + *(inv_version_t *)sesbuf = INT_GET(INV_VERSION, ARCH_CONVERT); + sesbuf += sizeof( inv_version_t ); + + xlate_invt_seshdr(hdr, (invt_seshdr_t *)sesbuf, 1); + sesbuf += sizeof( invt_seshdr_t ); + + xlate_invt_session( ses, (invt_session_t *)sesbuf, 1 ); + sesbuf += sizeof( invt_session_t ); + + for ( i = 0; i < ses->s_cur_nstreams; i++ ) { + xlate_invt_stream( strms, (invt_stream_t *)sesbuf, 1 ); + sesbuf += sizeof( invt_stream_t ); + } + + /* now append all the mediafiles */ + for ( i = 0; i < ses->s_cur_nstreams; i++ ) { + off = strms[i].st_firstmfile; + for ( j = 0; j < strms[i].st_nmediafiles; + j++, + off = mf.mf_nextmf ) { + ASSERT( off ); + if ( GET_REC_NOLOCK( fd, &mf, + sizeof( invt_mediafile_t ), + off ) <= 0 ) { + free( strms ); + free( sesbuf ); + return BOOL_FALSE; + } + xlate_invt_mediafile(&mf, (invt_mediafile_t *)sesbuf, 1); + sesbuf += sizeof( invt_mediafile_t ); + } + } + + free( strms ); + *bufpp = sesbufcp; + *bufszp = sessz; + + return BOOL_TRUE; +} + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +bool_t +stobj_getsession_byuuid( + int fd, + invt_seshdr_t *hdr, + void *sesid, + void **buf ) +{ + invt_session_t ses; + + /* retrieve the session */ + if ( GET_REC_NOLOCK( fd, &ses, sizeof( invt_session_t ), + hdr->sh_sess_off ) < 0 ) + return -1; + + /* now see if this is the one that caller is askin for */ + if (uuid_compare(ses.s_sesid, *((uuid_t *)sesid))) { + return BOOL_FALSE; + } + + /* yay. we found the session. so, make the session struct and + put it in the buffer */ + stobj_copy_invsess(fd, hdr, &ses, (inv_session_t **)buf); + + return BOOL_TRUE; + +} + + + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +bool_t +stobj_getsession_bylabel( + int fd, + invt_seshdr_t *hdr, + void *seslabel, + void **buf ) +{ + invt_session_t ses; + + /* retrieve the session */ + if ( GET_REC_NOLOCK( fd, &ses, sizeof( invt_session_t ), + hdr->sh_sess_off ) < 0 ) + return -1; + + /* now see if this is the one that caller is askin for */ + if (! STREQL(ses.s_label, (char *)seslabel)) { + return BOOL_FALSE; + } + + /* yay. we found the session. so, make the session struct and + put it in the buffer */ + stobj_copy_invsess(fd, hdr, &ses, (inv_session_t **)buf); + + return BOOL_TRUE; + +} + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +/* ARGSUSED */ +bool_t +stobj_delete_mobj(int fd, + invt_seshdr_t *hdr, + void *arg , + void **buf ) +{ + /* XXX fd needs to be locked EX, not SH */ + uuid_t *moid = *buf; + invt_session_t ses; + invt_stream_t *strms; + off64_t off; + invt_mediafile_t *mf, *mfiles; + u_int nmfiles; + u_int i, j; + bool_t dirty; + + if ( GET_REC_NOLOCK( fd, &ses, sizeof( invt_session_t ), + hdr->sh_sess_off ) < 0 ) + return -1; + + /* now get all the streams of this session */ + strms = calloc ( ses.s_cur_nstreams, sizeof( invt_stream_t ) ); + if ( GET_REC_NOLOCK( fd, strms, + sizeof( invt_stream_t ) * ses.s_cur_nstreams, + hdr->sh_streams_off ) < 0 ) { + free ( strms ); + return BOOL_FALSE; + } + + /* now look at all the mediafiles in all the streams */ + for ( i = 0; i < ses.s_cur_nstreams; i++ ) { + off = strms[i].st_firstmfile; + nmfiles = strms[i].st_nmediafiles; + mfiles = mf = calloc( nmfiles, sizeof( invt_mediafile_t ) ); + for ( j = 0; j < nmfiles; + j++, + off = mf->mf_nextmf, + mf++ ) { + +/* The prob is that we need to keep track of where we got these mfiles from + as we get them, or we wont know how to put them back if they are dirty. +*/ + ASSERT( off ); + if ( GET_REC_NOLOCK( fd, mf, + sizeof( invt_mediafile_t ), + off ) <= 0 ) { + free( strms ); + free( mfiles ); + return BOOL_FALSE; + } + } + + /* We have all the media files of this stream. Make another + pass, checking to see if we need to remove any mfiles */ + dirty = BOOL_FALSE; + + for ( j = 0; j < nmfiles; j++ ) { + mf = &mfiles[j]; + if ( !uuid_compare( mf->mf_moid, *moid ) ) { + printf(" found one\n" ); + +/* dirty = BOOL_TRUE; + + if ( j == 0 ) + strms[i].st_firstmfile = mf->mf_nextmf; + else + mfiles[j-1].mf_nextmf = mf->mf_nextmf; + + if ( j == nmfiles - 1 ) + strms[i].st_lastmfile = ; +*/ + } + + } + free ( mfiles ); + if ( dirty ); + } + + free ( strms ); + + return BOOL_FALSE; /* ret FALSE, or it'll stop iteration */ +} + + + + + + +/*----------------------------------------------------------------------*/ +/* stobj_unpack_sessinfo */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +bool_t +stobj_unpack_sessinfo( + void *bufp, + size_t bufsz, + invt_sessinfo_t *s ) +{ + u_int i; + char *tmpbuf; + char *p = (char *)bufp; + + ASSERT ( bufp ); + + tmpbuf = (char *)malloc(bufsz); + + /* first make sure that the magic cookie at the beginning is right. + this isn't null-terminated */ + if (strncmp( p, INVTSESS_COOKIE, strlen( INVTSESS_COOKIE ) ) != 0) { + mlog( MLOG_NORMAL | MLOG_INV,"INV: inv_put_session: unknown cookie\n"); + return BOOL_FALSE; + } + /* skip the cookie */ + p += strlen( INVTSESS_COOKIE ) * sizeof( char ); + + /* Check the packing version number. In version 1 , this was the only version number. + * see the comment in stobj_pack_sessinfo(). + */ + if ( INT_GET(*( inv_version_t *) p, ARCH_CONVERT) == PACKED_INV_VERSION_1 ) { + char *temp_p; + size_t tempsz; + + mlog( MLOG_DEBUG | MLOG_INV,"INV: packed inventory version = 1\n" ); + + p += sizeof( inv_version_t ); + + /* We hit a 64 bit alignment issue at this point leading to a + * SIGBUS and core dump. The best way to handle it is to + * bcopy the remaining part of bufp to a new malloc'ed area + * which will be 64 bit aligned. This is a memory leak , but not much. + * Have to do this because xfsrestore does another round of + * unpack later , so can't disturb the original data. + * This is fixed in PACKED_INV_VERSION_2 by adding another (inv_version_t) to + * have the INV_VERSION. This makes everything 64 bit aligned. + */ + + tempsz = bufsz - (strlen( INVTSESS_COOKIE ) * sizeof( char )) + - sizeof( inv_version_t ) ; + temp_p = calloc(1, tempsz); + bcopy(p, temp_p, tempsz); + p = temp_p; + } else if ( INT_GET(*( inv_version_t *) p, ARCH_CONVERT) == PACKED_INV_VERSION_2 ) { + mlog( MLOG_DEBUG | MLOG_INV,"INV: packed inventory version = 2\n" ); + + p += sizeof( inv_version_t ); /* skip the packed inventory version */ + /* At this point , don't care about the INV_VERSION. Maybe in future */ + p += sizeof( inv_version_t ); /* skip the inventory version */ + } else { + mlog( MLOG_NORMAL | MLOG_INV,"INV: inv_put_session: unknown packed inventory version" + " %d\n", *( inv_version_t *) p); + return BOOL_FALSE; + } + + xlate_invt_seshdr((invt_seshdr_t *)p, (invt_seshdr_t *)tmpbuf, 1); + bcopy(tmpbuf, p, sizeof(invt_seshdr_t)); + + /* get the seshdr and then, the remainder of the session */ + s->seshdr = (invt_seshdr_t *)p; + s->seshdr->sh_sess_off = -1; + p += sizeof( invt_seshdr_t ); + + + xlate_invt_session((invt_session_t *)p, (invt_session_t *)tmpbuf, 1); + bcopy (tmpbuf, p, sizeof(invt_session_t)); + s->ses = (invt_session_t *)p; + p += sizeof( invt_session_t ); + + /* the array of all the streams belonging to this session */ + xlate_invt_stream((invt_stream_t *)p, (invt_stream_t *)tmpbuf, 1); + bcopy(tmpbuf, p, sizeof(invt_stream_t)); + s->strms = (invt_stream_t *)p; + p += s->ses->s_cur_nstreams * sizeof( invt_stream_t ); + + /* all the media files */ + s->mfiles = (invt_mediafile_t *)p; + +#ifdef INVT_DELETION + { + int tmpfd = open( "moids", O_RDWR | O_CREAT ); + u_int j; + invt_mediafile_t *mmf = s->mfiles; + for (i=0; i< s->ses->s_cur_nstreams; i++ ) { + for (j=0; j< s->strms[ i ].st_nmediafiles; + j++, mmf++ ) + xlate_invt_mediafile((invt_mediafile_t *)mmf, (invt_mediafile_t *)tmpbuf, 1); + bcopy(tmpbuf, mmf, sizeof(invt_mediafile_t)); + put_invtrecord( tmpfd, &mmf->mf_moid, + sizeof( uuid_t ), 0, SEEK_END, 0 ); + } + close( tmpfd ); + } +#endif + for ( i = 0; i < s->ses->s_cur_nstreams; i++ ) { + p += (size_t) ( s->strms[ i ].st_nmediafiles ) + * sizeof( invt_mediafile_t ); + } + + /* sanity check the size of the buffer given to us vs. the size it + should be */ + if ( (size_t) ( p - (char *) bufp ) != bufsz ) { + mlog( MLOG_DEBUG | MLOG_INV, "p-bufp %d != bufsz %d entsz %d\n", + (int)( p - (char *) bufp ), (int) bufsz, + (int) ( sizeof( invt_entry_t ) ) ); + } + ASSERT( (size_t) ( p - (char *) bufp ) == bufsz ); + + return BOOL_TRUE; +} + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +stobj_make_invsess( int fd, inv_session_t **buf, invt_seshdr_t *hdr ) +{ + invt_session_t ses; + + /* load in the rest of the session, but not the streams */ + if ( GET_REC_NOLOCK( fd, &ses, sizeof(ses), hdr->sh_sess_off ) + < 0 ) { + return -1; + } + + return stobj_copy_invsess(fd, hdr, &ses, buf); +} + + +void +stobj_convert_mfile(inv_mediafile_t *expmf, invt_mediafile_t *mf) +{ + /* copy the mediafile into the exported structure */ + memcpy( &expmf->m_moid, &mf->mf_moid, sizeof( uuid_t ) ); + strcpy( expmf->m_label, mf->mf_label ); + expmf->m_mfile_index = mf->mf_mfileidx; + expmf->m_startino = mf->mf_startino.ino; + expmf->m_startino_off = mf->mf_startino.offset; + expmf->m_endino = mf->mf_endino.ino; + expmf->m_endino_off = mf->mf_endino.offset; + expmf->m_size = mf->mf_size; + expmf->m_isgood = (mf->mf_flag & INVT_MFILE_GOOD ) ? + BOOL_TRUE : BOOL_FALSE; + expmf->m_isinvdump = (mf->mf_flag & INVT_MFILE_INVDUMP)? + BOOL_TRUE : BOOL_FALSE; + +} + +void +stobj_convert_strm(inv_stream_t *expstrm, invt_stream_t *strm) +{ + + expstrm->st_interrupted = strm->st_interrupted; + expstrm->st_startino = strm->st_startino.ino; + expstrm->st_startino_off = + strm->st_startino.offset; + expstrm->st_endino = strm->st_endino.ino; + expstrm->st_endino_off = strm->st_endino.offset; + strcpy( expstrm->st_cmdarg, strm->st_cmdarg ); + + expstrm->st_nmediafiles = strm->st_nmediafiles; + + /* caller is responsible for initializing this */ + expstrm->st_mediafiles = NULL; +} + +void +stobj_convert_session(inv_session_t *ises, invt_session_t *ses, + invt_seshdr_t *hdr) +{ + ises->s_time = hdr->sh_time; + ises->s_level = hdr->sh_level; + ises->s_ispartial = IS_PARTIAL_SESSION( hdr )? BOOL_TRUE: BOOL_FALSE; + ises->s_isresumed = IS_RESUMED_SESSION( hdr )? BOOL_TRUE: BOOL_FALSE; + ises->s_nstreams = ses->s_cur_nstreams; + memcpy( &ises->s_sesid, &ses->s_sesid, sizeof( uuid_t ) ); + memcpy( &ises->s_fsid, &ses->s_fsid, sizeof( uuid_t ) ); + strcpy( ises->s_mountpt, ses->s_mountpt ); + strcpy( ises->s_devpath, ses->s_devpath ); + strcpy( ises->s_label, ses->s_label ); + + /* caller is responsible for initializing this */ + ises->s_streams = NULL; + +} + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +stobj_copy_invsess(int fd, + invt_seshdr_t *hdr, + invt_session_t *ses, + inv_session_t **buf) +{ + inv_session_t *ises; + invt_stream_t *strms; + int i; + invt_mediafile_t mf; + + strms = calloc ( ses->s_cur_nstreams, sizeof( invt_stream_t ) ); + + /* load in all the stream-headers */ + if ( GET_REC_NOLOCK( fd, strms, + ses->s_cur_nstreams * sizeof( invt_stream_t ), + hdr->sh_streams_off ) < 0 ) { + free (strms); + return -1; + } + + ises = calloc( 1, sizeof( inv_session_t ) ); + stobj_convert_session(ises, ses, hdr); + ises->s_streams = calloc(ses->s_cur_nstreams, sizeof( inv_stream_t )); + + /* fill in the stream structures too */ + i = (int) ses->s_cur_nstreams; + while ( i-- ) { + off64_t off; + u_int j, nmf; + + stobj_convert_strm(&ises->s_streams[i], &strms[i]); + nmf = strms[i].st_nmediafiles; + off = strms[i].st_firstmfile; + + if (nmf) + ises->s_streams[i].st_mediafiles = calloc( nmf, + sizeof( inv_mediafile_t ) ); + ASSERT( !nmf || ises->s_streams[i].st_mediafiles ); + + for ( j = 0; j < nmf; + j++, + off = mf.mf_nextmf ) { + ASSERT( off ); + if ( GET_REC_NOLOCK( fd, &mf, + sizeof( invt_mediafile_t ), + off ) <= 0 ) { + INV_PERROR( "stobj::make_invsess\n" ); + free( strms ); + free( ises ); + return -1; + } + + /* copy the mediafile into the exported structure */ + stobj_convert_mfile( &ises->s_streams[i].st_mediafiles[j], + &mf); + + } + + } + + + free( strms ); + *buf = ises; + + return 1; +} + + +/*----------------------------------------------------------------------*/ +/* Given a sessinfo structure, this makes an exportable inv_session. */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +void +stobj_convert_sessinfo(inv_session_t **buf, invt_sessinfo_t *sinfo) +{ + inv_session_t *ises; + int i, j, nmf; +#ifdef INVCONVFIX + int nstreams; + invt_mediafile_t *mf; +#endif /* INVCONVFIX */ + + ises = calloc( 1, sizeof( inv_session_t ) ); + + stobj_convert_session(ises, sinfo->ses, sinfo->seshdr); + ises->s_streams = calloc( ises->s_nstreams, sizeof( inv_stream_t ) ); +#ifdef INVCONVFIX + mf = sinfo->mfiles; + nstreams = (int) ises->s_nstreams; + for ( i = 0 ; i < nstreams ; i++ ) { +#else /* INVCONVFIX */ + i = (int) ises->s_nstreams; + while ( i-- ) { +#endif /* INVCONVFIX */ + stobj_convert_strm(&ises->s_streams[i], &sinfo->strms[i]); + nmf = (int) ises->s_streams[i].st_nmediafiles; + ises->s_streams[i].st_mediafiles = calloc( (u_int) nmf, + sizeof( inv_mediafile_t ) ); + + for ( j = 0; j < nmf; j++ ) { + stobj_convert_mfile( &ises->s_streams[i].st_mediafiles[j], +#ifdef INVCONVFIX + mf++ ); +#else /* INVCONVFIX */ + sinfo->mfiles); +#endif /* INVCONVFIX */ + } + } + + *buf = ises; +} + + + +int +stobj_hdrcmp( const void *h1, const void *h2 ) +{ + return (int) ( ((invt_seshdr_t *)h1)->sh_time - + ((invt_seshdr_t *)h2)->sh_time ); +} + + + + + + + + +void +DEBUG_sessprint( invt_session_t *ses ) +{ + char str[UUID_STR_LEN + 1]; + uuid_unparse( ses->s_fsid, str ); + + printf("-------- session -------------\n"); + printf("label\t%s\n", ses->s_label); + printf("mount\t%s\n", ses->s_mountpt); + printf("devpath\t%s\n", ses->s_devpath); + printf("strms\t%d\n", ses->s_cur_nstreams ); + printf("fsid\t%s\n", str); + printf("-------- end -------------\n"); +} + +bool_t +mobj_eql ( inv_mediafile_t *mfp, invt_mobjinfo_t *mobj ) +{ + + if ( mobj->type == INVT_MOID ) { + if ( !uuid_compare( *((uuid_t*) mobj->value), + mfp->m_moid) ) { + return BOOL_TRUE; + } + } else { + if ( STREQL( (char*) mobj->value, + mfp->m_label ) ) { + return BOOL_TRUE; + } + } + + return BOOL_FALSE; +} + + +bool_t +check_for_mobj ( inv_session_t *ses, invt_mobjinfo_t *mobj ) +{ + int i; + u_int j; + inv_mediafile_t *mfp; + + for (i = 0; i < (int) ses->s_nstreams; i++ ) { + for ( j = 0 ; j < ses->s_streams[i].st_nmediafiles ; j++ ) { + mfp = &ses->s_streams[i].st_mediafiles[j]; + if (mobj_eql( mfp, mobj )) + return BOOL_TRUE; + } + } + + return BOOL_FALSE; /* There are no matching media objects to print */ +} + + + + +void +DEBUG_sessionprint( inv_session_t *ses, u_int ref, invt_pr_ctx_t *prctx) +{ + char str[UUID_STR_LEN + 1]; + int i; + inv_mediafile_t *mfp; + static u_int fsidxprinted = -1; + + invt_mobjinfo_t *mobj = &prctx->mobj; + + bool_t moidsearch = ( mobj && mobj->type != INVT_NULLTYPE ); + if ( moidsearch ){ + if (!check_for_mobj (ses, mobj)) + return; + } + + if ( ref == 0 || fsidxprinted != (u_int) prctx->index ) { + fsidxprinted = (u_int) prctx->index; + + printf("file system %d:\n", prctx->index); + uuid_unparse( ses->s_fsid, str ); + printf("\tfs id:\t\t%s\n", str); + } + + if (prctx->depth == PR_FSONLY) + return; + + if ((prctx->level != PR_MAXLEVEL) && (prctx->level != ses->s_level)) + return; + + printf("\tsession %d:\n", ref); + printf("\t\tmount point:\t%s\n", ses->s_mountpt); + printf("\t\tdevice:\t\t%s\n", ses->s_devpath); + printf("\t\ttime:\t\t%s", ctime( &ses->s_time )); + printf("\t\tsession label:\t\"%s\"\n", ses->s_label); + uuid_unparse( ses->s_sesid, str ); + printf("\t\tsession id:\t%s\n", str); + printf("\t\tlevel:\t\t%d\n", ses->s_level); + printf("\t\tresumed:\t%s\n", ses->s_isresumed ? "YES" : "NO" ); + printf( "\t\tsubtree:\t%s\n", ses->s_ispartial ? "YES" : "NO" ); + printf("\t\tstreams:\t%d\n", ses->s_nstreams ); + + if (prctx->depth == PR_SESSONLY ) + return; + + for (i = 0; i < (int) ses->s_nstreams; i++ ) { + u_int j; + printf("\t\tstream %d:\n", i ); + printf( "\t\t\tpathname:\t%s\n", ses->s_streams[i].st_cmdarg ); + printf( "\t\t\tstart:\t\tino %llu offset %lld\n", + (unsigned long long)ses->s_streams[i].st_startino, + (long long)ses->s_streams[i].st_startino_off ); + printf( "\t\t\tend:\t\tino %llu offset %lld\n", + (unsigned long long)ses->s_streams[i].st_endino, + (long long)ses->s_streams[i].st_endino_off ); + printf( "\t\t\tinterrupted:\t%s\n", + ses->s_streams[i].st_interrupted ? "YES" : "NO" ); + printf( "\t\t\tmedia files:\t%d\n", + ses->s_streams[i].st_nmediafiles); + + if (prctx->depth == PR_STRMSONLY ) + continue; + + for ( j = 0 ; j < ses->s_streams[i].st_nmediafiles ; j++ ) { + mfp = &ses->s_streams[i].st_mediafiles[j]; + if ( moidsearch ) { + if (! mobj_eql( mfp, mobj ) ) + continue; + } + printf( "\t\t\tmedia file %d:", j ); + /* + if (mfp->m_isinvdump) + printf(" SESSION INVENTORY"); + */ + printf( "\n"); + printf( "\t\t\t\tmfile index:\t%d\n", mfp->m_mfile_index ); + printf( "\t\t\t\tmfile type:\t" ); + if (mfp->m_isinvdump) { + printf( "inventory\n" ); + } else { + printf( "data\n" ); + } + printf( "\t\t\t\tmfile size:\t%llu\n", + (unsigned long long)mfp->m_size); + + if (! mfp->m_isinvdump) { + printf( "\t\t\t\tmfile start:" + "\tino %llu offset %lld\n", + (unsigned long long)mfp->m_startino, + (long long)mfp->m_startino_off ); + printf( "\t\t\t\tmfile end:" + "\tino %llu offset %lld\n", + (unsigned long long)mfp->m_endino, + (long long)mfp->m_endino_off ); + } + + printf( "\t\t\t\tmedia label:\t\"%s\"\n", + mfp->m_label); + uuid_unparse( mfp->m_moid, str ); + printf( "\t\t\t\tmedia id:\t%s\n", str ); + } + } +} diff -rNu linux-2.4.7/cmd/xfsdump/inventory/inventory.h linux-2.4-xfs/cmd/xfsdump/inventory/inventory.h --- linux-2.4.7/cmd/xfsdump/inventory/inventory.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/inventory.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef INVENTORY_H +#define INVENTORY_H + +#include "types.h" + +/* abstract interface to the inventory sub system of xfsdump + * + * the inventory contains a description of every xfsdump ever + * done, unless explicitly deleted. It provides simple and specific + * storage and query facilities. + * + * This was not an attempt to write a generic database. The inventory does have + * knowledge of the functionalities, some abstractions, and even typical queries + * of dump() and restore() and uses this knowledge in formulating its storage + * structure on disk. All these things, of course, are completely abstract with + * respect to the clients of the inventory. + * + */ + +#define INV_DIRPATH XFSDUMP_DIRPATH"/inventory" + +#define INV_TOKEN_NULL NULL +#define INV_FSTAB INV_DIRPATH"/fstab" +#define INV_INVINDEX_PREFIX ".InvIndex" +#define INV_STOBJ_PREFIX ".StObj" + +/* length of labels, mntpts, etc */ +#define INV_STRLEN GLOBAL_HDR_STRING_SZ + +typedef __uint32_t inv_version_t; + +/* This is the general inventory version. + */ +#define INV_VERSION (inv_version_t) 1 + +/* This is the version of the on-tape (packed) inventory. + * version 2 has an extra inv_version_t in it to make everything + * 64 bit aligned. + */ +#define PACKED_INV_VERSION_1 (inv_version_t) 1 +#define PACKED_INV_VERSION_2 (inv_version_t) 2 +#define PACKED_INV_VERSION PACKED_INV_VERSION_2 + +/* Print [-I] suboption -depth */ +#define PR_DEFAULT 0 +#define PR_FSONLY 1 +#define PR_SESSONLY 2 +#define PR_STRMSONLY 3 +#define PR_ALL 4 +#define PR_MAXDEPTH 5 +#define PR_MAXLEVEL 255 + +/*----------------------------------------------------------------------*/ +/* Inventory */ +/* */ +/* Users are first supposed to call inventory_open() specifying what */ +/* type of handle s/he would like to supply. This can be BY_MOUNTPT, */ +/* BY_DEVPATH, or BY_UUID. The inventory maintains its own table of file*/ +/* systems and their uuids, mountpts, and device paths. */ +/* The current implementation requires that a uuid be present for all */ +/* its fs table entries. However, once the entry is there, caller can */ +/* query by any of the other handles. */ +/* */ +/* For a read-session, ie. just querying, like in restore(), the token */ +/* from inv_open() must always be passed. */ +/* */ +/* This inventory has a hierarchical token scheme. */ +/* For write-sessions, the caller should obtain a session_token */ +/* by calling inv_writesession_open() with the original token. */ +/* In order to start writing media files, the caller must */ +/* then obtain a stream-token via inv_stream_open() using that */ +/* session-token. */ +/* */ +/* Once, done, stream_close(), writesession_close() and inv_close() */ +/* must be called in that order. To obtain all the data written during */ +/* the course of a single write-session, the user can call inv_get_ */ +/* sessioninfo() while still holding the session-token. For inventory */ +/* reconstruction, inv_put_sessioninfo() may be used, and there is no */ +/* requirement to hold a token for that. */ +/* */ +/* inv_delete_mediaobj() is, of course, for deletion of all the media */ +/* files contained in a media object. */ +/* */ +/*----------------------------------------------------------------------*/ + +/* Caller can open the inventory by any of these handles */ +typedef enum { + INV_BY_UUID, + INV_BY_MOUNTPT, + INV_BY_DEVPATH +} inv_predicate_t; + + +typedef enum { + INV_SEARCH_ONLY, + INV_SEARCH_N_MOD +} inv_oflag_t; + + +typedef struct inv_mediafile { + uuid_t m_moid; /* media object id */ + u_int m_mfile_index; /* index within the media object */ + xfs_ino_t m_startino; /* file that we started out with */ + off64_t m_startino_off; + xfs_ino_t m_endino; /* the dump file we ended this .. */ + off64_t m_endino_off; /* .. media file with. */ + off64_t m_size; /* size of mediafile in bytes */ + bool_t m_isgood; /* distinguishes good mfiles */ + bool_t m_isinvdump; /* is this the mfile that has the dump + of the rest of the session? */ + char m_label[INV_STRLEN]; /* media file label */ +} inv_mediafile_t; + + +typedef struct inv_stream { + bool_t st_interrupted; /* was this stream interrupted ? */ + + /* duplicate info from mediafiles for speed */ + xfs_ino_t st_startino; /* the starting pt */ + off64_t st_startino_off; + xfs_ino_t st_endino; /* where we actually ended up. this + means we've written upto but not + including this breakpoint. */ + off64_t st_endino_off; + char st_cmdarg[INV_STRLEN]; /* the driver path user entered */ + u_int st_nmediafiles; /* number of mediafiles */ + inv_mediafile_t *st_mediafiles; /* array of all media files */ +} inv_stream_t; + + +/* + * inventory_session_t + * all the information that is kept on a single dump session of a single + * file system in the inventory. + * + */ + +typedef struct inv_session { + uuid_t s_fsid; /* file system */ + uuid_t s_sesid; /* this session's id:16 bytes*/ + time_t s_time; /* time of the dump */ + bool_t s_ispartial; /* was this a partial (dump) ? */ + bool_t s_isresumed; /* was this a resumed (dump) ? */ + u_char s_level; /* dump level */ + char s_label[INV_STRLEN]; /* session label */ + char s_mountpt[INV_STRLEN];/* path to the mount point */ + char s_devpath[INV_STRLEN];/* path to the device */ + u_int s_nstreams; /* num of media streams recorded */ + inv_stream_t *s_streams; /* array of streams */ + u_int s_refnum; /* storage location dependent ref. + used in displaying the session and + nowhere else */ + +} inv_session_t; + + + +struct invt_desc_entry; +struct invt_sesdesc_entry; +struct invt_strdesc_entry; + +/* The three kinds of access tokens for the inventory */ +typedef struct invt_desc_entry *inv_idbtoken_t; +typedef struct invt_sesdesc_entry *inv_sestoken_t; +typedef struct invt_strdesc_entry *inv_stmtoken_t; + + + + +/* inventory_open - initializes access to the inventory + */ +extern inv_idbtoken_t +inv_open( + inv_predicate_t bywhat, /* BY_UUID, BY_MOUNTPT, BY_DEVPATH */ + inv_oflag_t forwhat,/* SEARCH_ONLY, SEARCH_N_MOD */ + void *pred );/* uuid_t *,char * mntpt, or char *dev */ + + +extern bool_t +inv_close( + inv_idbtoken_t tok ); + + +extern inv_sestoken_t +inv_writesession_open( + inv_idbtoken_t tok, /* token obtained by inventory_init() */ + uuid_t *fsid, + uuid_t *sesid, + char *label, + bool_t ispartial, + bool_t isresumed, + u_char level, + u_int nstreams, + time_t time, + char *mntpt, + char *devpath ); + +extern bool_t +inv_writesession_close( + inv_sestoken_t tok ); + +extern inv_stmtoken_t +inv_stream_open( + inv_sestoken_t tok, + char *cmdarg ); + +extern bool_t +inv_stream_close( + inv_stmtoken_t tok, + bool_t wasinterrupted ); + +extern bool_t +inv_put_mediafile( + inv_stmtoken_t tok, + uuid_t *moid, + char *label, + u_int mfileindex, + xfs_ino_t startino, + off64_t startino_offset, + xfs_ino_t endino, + off64_t endino_offset, + off64_t size, /* size of the mediafile in bytes */ + bool_t isgood, /* to distinguish unimportant media + files from others */ + bool_t isinv_dump); + +/* lasttime_level_lessthan - finds the time of the last dump of the + * specified file system at a level less than the specified level. + * if never dumped below the current level, *time is set to NULL. + * + */ +extern bool_t +inv_lasttime_level_lessthan( + inv_idbtoken_t tok, + u_char level, + time_t **time );/* out */ + +extern bool_t +inv_lastsession_level_lessthan( + inv_idbtoken_t tok, + u_char level, + inv_session_t **ses );/* out */ + +extern bool_t +inv_lastsession_level_equalto( + inv_idbtoken_t tok, + u_char level, + inv_session_t **ses );/* out */ + +/* Given a uuid of a session, return the session structure.*/ +extern bool_t +inv_get_session_byuuid( + uuid_t *sesid, + inv_session_t **ses); + +extern bool_t +inv_get_session_bylabel( + char *session_label, + inv_session_t **ses); + + +/* on return, *ses is NULL */ +extern void +inv_free_session( + inv_session_t **ses); + + +/* For dumping the inventory once a dump is done. */ +extern bool_t +inv_get_sessioninfo( + inv_sestoken_t tok, + void **bufpp, /* out */ + size_t *bufszp ); /* out */ + + +extern bool_t +inv_delete_mediaobj( uuid_t *moid ); + +extern bool_t +inv_DEBUG_print( int argc, char **argv ); + + +#endif /* INVENTORY_H */ diff -rNu linux-2.4.7/cmd/xfsdump/inventory/testmain.c linux-2.4-xfs/cmd/xfsdump/inventory/testmain.c --- linux-2.4.7/cmd/xfsdump/inventory/testmain.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/inventory/testmain.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,514 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include "types.h" +#include "mlog.h" +#include "getopt.h" +#include "inv_priv.h" + + + +/*----------------------------------------------------------------------*/ +/* These are hacked up routines meant ONLY for low-level debugging */ +/* purposes. These are mostly unused since most the debugging code */ +/* was ported to xfsdump and xfsrestore as formal suboptions of -I. */ +/*----------------------------------------------------------------------*/ + + +static char *mnt_str[] = { "/usr/lib", "/usr", "/u/sw/courses", "/pro/leda", + "/root", "/a/xfs/xlv/e", "/dana/hates/me", "/the/krays" }; + +static char *dev_str[] = { "/dev/usr/lib", "/dev/usr", "/dev/u/sw/courses", + "/dev/pro/leda", + "/dev/root", "/dev/a/xfs/xlv/e", "/dev/dana/hates/me", + "/dev/the/krays" }; + +typedef enum { BULL = -1, WRI, REC, QUE, DEL, MP, QUE2 } hi; + +void usage( void ); +char *progname; +char *sesfile; + + +void +CREAT_mfiles( inv_stmtoken_t tok, uuid_t *moid, ino_t f, ino_t n ) +{ + uuid_t labelid; + char label[128], strbuf[20]; + char *str; + unsigned int stat; + + uuid_create( &labelid, &stat ); + uuid_to_string( &labelid, &str, &stat ); + strncpy( strbuf, str, 8 ); + free (str); + strbuf[8] = '\0'; + sprintf(label,"%s_%s (%d-%d)\0","MEDIA_FILE", strbuf, (int)f, (int)n ); + + inv_put_mediafile( tok, moid, label, 12, f, 0, n, 0, 0xffff, + BOOL_TRUE, BOOL_FALSE ); + +} + +typedef struct ses{ + uuid_t fsid; + size_t sz; + char *buf; +} ses; + +#define SESLIM 240 + +intgen_t +recons_test( int howmany ) +{ + int fd, i, rval = 1; + + ses sarr[ SESLIM]; + + fd = open( sesfile, O_RDONLY ); + + for ( i=0; i 0 ); + ASSERT( sarr[i].sz > 0 ); + sarr[i].buf = calloc( 1, sarr[i].sz ); + rval = get_invtrecord( fd, sarr[i].buf, sarr[i].sz, 0, SEEK_CUR, + BOOL_FALSE ); + ASSERT( rval > 0 ); + } + + + + for ( i=0; id_invindex_fd); + return 1; + } + + for (i = 7; i<8; i++) { + printf("\n\n\n----------------------------------\n" + "$ Searching fs %s\n", mnt_str[7-i] ); + tok = inv_open( INV_BY_MOUNTPT, INV_SEARCH_ONLY, mnt_str[7-i] ); + if (! tok ) return -1; + + prctx.index = i; + if (level == -1 ) + invmgr_inv_print( tok->d_invindex_fd, &prctx ); + else { + if (inv_lasttime_level_lessthan( tok, level, &tm ) && tm) { + printf("\n\nTIME %s %ld\n", ctime(tm), (long) *tm ); + free (tm); + } + if (inv_lastsession_level_lessthan( tok, level, &ses ) && ses) { + DEBUG_sessionprint( ses, 99, &prctx); + free ( ses->s_streams ); + free ( ses ); + } + + if (inv_lastsession_level_equalto( tok, level, &ses ) && ses) { + printf("Gotcha\n"); + DEBUG_sessionprint( ses, 99, &prctx ); + free ( ses->s_streams ); + free ( ses ); + } + } + inv_close( tok ); + } + return 1; +} + + +/*----------------------------------------------------------------------*/ +/* */ +/* */ +/* */ +/*----------------------------------------------------------------------*/ + +intgen_t +write_test( int nsess, int nstreams, int nmedia, int dumplevel ) +{ + int i,j,k,m,fd; + unsigned int stat; + uuid_t *fsidp; + inv_idbtoken_t tok1; + inv_sestoken_t tok2; + inv_stmtoken_t tok3; + char *dev, *mnt; + char label[120]; + uuid_t fsidarr[8], labelid; + uuid_t sesidarr[8]; + char *str; + char strbuf[128]; + void *bufp; + size_t sz; + int rfd; + +#ifdef FIRSTTIME + printf("first time!\n"); + for (i=0; i<8; i++) { + uuid_create( &fsidarr[i], &stat ); + ASSERT ( stat == uuid_s_ok ); + uuid_create( &sesidarr[i], &stat ); + ASSERT ( stat == uuid_s_ok ); + } + fd = open( "uuids", O_RDWR | O_CREAT ); + PUT_REC(fd, (void *)fsidarr, sizeof (uuid_t) * 8, 0L ); + PUT_REC(fd, (void *)sesidarr, sizeof (uuid_t) * 8, sizeof (uuid_t) * 8 ); + close(fd); +#endif + fd = open("uuids", O_RDONLY ); + GET_REC( fd, fsidarr, sizeof (uuid_t) * 8, 0L ); + GET_REC( fd, sesidarr, sizeof (uuid_t) * 8, sizeof (uuid_t) * 8 ); + close(fd); +#ifdef RECONS + rfd = open( sesfile, O_RDWR | O_CREAT ); + fchmod( rfd, INV_PERMS ); +#endif + + for ( i = 0; i < nsess; i++ ) { + j = i % 8; + /*mnt = mnt_str[j]; + dev = dev_str[7-j];*/ + mnt = mnt_str[0]; + dev = dev_str[7]; + fsidp = &fsidarr[0]; /* j */ + tok1 = inv_open( INV_BY_UUID, INV_SEARCH_N_MOD, fsidp ); + ASSERT (tok1 != INV_TOKEN_NULL ); + + uuid_create( &labelid, &stat ); + uuid_to_string( &labelid, &str, &stat ); + strncpy( strbuf, str, 8 ); + free (str); + strbuf[8] = '\0'; + sprintf(label,"%s_%s (%d)\0","SESSION_LABEL", strbuf, i ); + + tok2 = inv_writesession_open(tok1, fsidp, + &labelid, + label, + (bool_t)i%2, + (bool_t)i%2, + dumplevel, nstreams, + time(NULL), + mnt, dev ); + ASSERT (tok2 != INV_TOKEN_NULL ); + for (m = 0; m -s " + "-t -m \n", optarg ); +} + + +int +mp_test(int nstreams) +{ +#if 0 + tok1 = inv_open( INV_BY_UUID, fsidp ); + ASSERT (tok1 != INV_TOKEN_NULL ); + + tok2 = inv_writesession_open(tok1, fsidp, + &labelid, + label, + (bool_t)i%2, + (bool_t)i%2, + dumplevel, nstreams, + time(NULL), + mnt, dev ); + ASSERT (tok2 != INV_TOKEN_NULL ); + + for (m = 0; m 1 ); + + mlog_init( argc, argv ); + + if (! inv_DEBUG_print(argc, argv)) + return 0; + + optind = 1; + optarg = 0; + + while( ( cc = getopt( argc, argv, GETOPT_CMDSTRING)) != EOF ) { + switch ( cc ) { + case 'w': + op = WRI; + break; + case 'r': + op = REC; + break; + + case 'q': + op = QUE; + break; + + case 'd': + op = DEL; + break; + + case 'z': + op = MP; + break; + + case 'g': + op = QUE2; + break; + + case 'u': + uuid = optarg; + break; + + case 'L': + label = optarg; + break; + + case 's': + nsess = atoi(optarg); + break; + + case 'l': + level = atoi(optarg); + break; + + case 't': + nstreams = atoi(optarg); + break; + + case 'm': + nmedia = atoi( optarg ); + break; + case 'v': + break; + + case 'f': + sesfile = optarg; + break; + + default: + usage(); + break; + } + } + + + if ( op == WRI ) + rval = write_test( nsess, nstreams, nmedia, level ); + else if ( op == QUE ) + rval = query_test( level ); + else if ( op == REC ) + rval = recons_test( nsess ); + else if ( op == DEL ) + rval = delete_test( nsess ); + else if ( op == MP ) + rval = mp_test (nstreams); + else if ( op == QUE2 ) { + if (uuid) + rval = sess_queries_byuuid(uuid); + else if (label) + rval = sess_queries_bylabel(label); + } + else + usage(); + + if (rval < 0 ) + printf( "aborted\n"); + else + printf( "done\n" ); + + +} + diff -rNu linux-2.4.7/cmd/xfsdump/invutil/CVS/Entries linux-2.4-xfs/cmd/xfsdump/invutil/CVS/Entries --- linux-2.4.7/cmd/xfsdump/invutil/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/invutil/CVS/Entries Thu Jul 5 11:44:06 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Mon Jan 15 04:32:19 2001/-ko/ +/invutil.c/1.3/Tue Jul 3 07:36:42 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/invutil/CVS/Repository linux-2.4-xfs/cmd/xfsdump/invutil/CVS/Repository --- linux-2.4.7/cmd/xfsdump/invutil/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/invutil/CVS/Repository Thu Jul 5 11:44:06 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/invutil diff -rNu linux-2.4.7/cmd/xfsdump/invutil/CVS/Root linux-2.4-xfs/cmd/xfsdump/invutil/CVS/Root --- linux-2.4.7/cmd/xfsdump/invutil/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/invutil/CVS/Root Thu Jul 5 11:44:06 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/invutil/Makefile linux-2.4-xfs/cmd/xfsdump/invutil/Makefile --- linux-2.4.7/cmd/xfsdump/invutil/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/invutil/Makefile Sun Jan 14 22:32:19 2001 @@ -0,0 +1,77 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +COMMINCL = \ + global.h \ + mlog.h \ + util.h \ + types.h + +INVINCL = \ + inventory.h \ + inv_priv.h + +INVCOMMON = + +COMMON = + +LOCALS = invutil.c + + +CMDTARGET = xfsinvutil +CFILES = $(COMMON) $(INVCOMMON) $(LOCALS) +LINKS = $(COMMINCL) $(COMMON) $(INVINCL) $(INVCOMMON) +LDIRT = $(LINKS) +LLDLIBS = $(LIBUUID) + +#LCFLAGS = -DDUMP -DRMT -DEXTATTR -DBASED -DDOSOCKS -DINVCONVFIX -DSIZEEST -DPIPEINVFIX +LCFLAGS = -DDUMP -DBASED -DDOSOCKS -DINVCONVFIX -DSIZEEST -DPIPEINVFIX +#LCFLAGS = -DINV_DEBUG -DDUMP -DBASED -DDOSOCKS -DINVCONVFIX -DSIZEEST -DPIPEINVFIX + + +default: $(LINKS) $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_BIN_DIR) +install-dev: + +$(COMMINCL) $(COMMON): + @$(RM) $@; $(LN_S) ../common/$@ $@ + +$(INVINCL) $(INVCOMMON): + @$(RM) $@; $(LN_S) ../inventory/$@ $@ diff -rNu linux-2.4.7/cmd/xfsdump/invutil/invutil.c linux-2.4-xfs/cmd/xfsdump/invutil/invutil.c --- linux-2.4.7/cmd/xfsdump/invutil/invutil.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/invutil/invutil.c Tue Jul 3 02:36:42 2001 @@ -0,0 +1,696 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#include +#include + +#include +#include +#include +#include +#include + +#include "types.h" +#include "mlog.h" +#include "inv_priv.h" + +#define STR_LEN INV_STRLEN+32 +#define GEN_STRLEN 32 + +static char *g_programName; +static bool_t debug = BOOL_FALSE; +static bool_t nonInteractive = BOOL_FALSE; + +char *GetFstabFullPath(void); +char *GetNameOfInvIndex (uuid_t); +void PruneByMountPoint(int, char **); +void CheckAndPruneFstab(bool_t , char *, time_t ); +int CheckAndPruneInvIndexFile( bool_t , char *, time_t ); +int CheckAndPruneStObjFile( bool_t , char *, time_t ); +void usage (void); +time_t ParseDate(char *); + +int +main (int argc, char *argv[]) +{ + int c; + bool_t c_option = BOOL_FALSE; + bool_t m_option = BOOL_FALSE; + char *mntPoint = NULL; + + g_programName = argv[0]; + + + while ((c = getopt(argc, argv, "CdM:n")) != EOF) { + switch (c) { + case 'd': + debug = BOOL_TRUE; + break; + case 'n': + nonInteractive = BOOL_TRUE; + break; + case 'C': + c_option = BOOL_TRUE; + break; + case 'M': + m_option = BOOL_TRUE; + mntPoint = optarg; + break; + case '?': + usage(); + } + } + + if (c_option && m_option) { + fprintf( stderr, "%s: Cannot use -M and -C option together\n", + g_programName ); + usage(); + } + if (c_option) { + char *tempstr = "test"; + time_t temptime = 0; + CheckAndPruneFstab(BOOL_TRUE,tempstr,temptime); + } + else if (m_option) { + char *dateStr; + time_t timeSecs; + + if (optind != (argc - 1) ) { + fprintf( stderr, "%s: Date missing for -M option\n", + g_programName ); + usage(); + } + dateStr = argv[optind]; + timeSecs = ParseDate(dateStr); + CheckAndPruneFstab(BOOL_FALSE , mntPoint , timeSecs); + } + else { + usage(); + } + + return(0); +} + +time_t +ParseDate(char *strDate) +{ + struct tm tm; + time_t date = 0; + char **fmt; + char *templateStr[] = { + "%m/%d/%Y %I:%M:%S %p", + "%m/%d/%Y %H:%M:%S", + "%m/%d/%Y %I:%M %p", + "%m/%d/%Y %H:%M", + "%m/%d/%Y %I %p", + "%m/%d/%Y %H", + "%m/%d/%Y", + "%m/%d/%y %I:%M:%S %p", + "%m/%d/%y %H:%M:%S", + "%m/%d/%y %I:%M %p", + "%m/%d/%y %H:%M", + "%m/%d/%y %I %p", + "%m/%d/%y %H", + "%m/%d/%y", + "%m/%d", + "%b %d, %Y %H:%M:%S %p", + "%b %d, %Y %I:%M:%S", + "%B %d, %Y %H:%M:%S %p", + "%B %d, %Y %I:%M:%S", + "%b %d, %Y %H:%M %p", + "%b %d, %Y %I:%M", + "%B %d, %Y %H:%M %p", + "%B %d, %Y %I:%M", + "%b %d, %Y %H %p", + "%b %d, %Y %I", + "%B %d, %Y %H %p", + "%B %d, %Y %I", + "%b %d, %Y", + "%B %d, %Y", + "%b %d", + "%B %d", + "%m%d%H", + "%m%d", + 0}; + + for (fmt = &templateStr[0]; *fmt != NULL; fmt++) { + memset (&tm, 0, sizeof (struct tm)); /* ensure fields init'ed */ + if (strptime(strDate, *fmt, &tm) != NULL) + break; + } + +#ifdef INV_DEBUG + printf("the date entered is %s\n", strDate); + printf("the hour parsed from string is %d\n", tm.tm_hour); +#endif + + if (*fmt == NULL || (date = mktime(&tm)) < 0) { + fprintf(stderr, "%s: bad date, \"%s\" for -M option\n", + g_programName, strDate ); + usage(); + } + + /* HACK to ensure tm_isdst is set BEFORE calling mktime(3) */ + if (tm.tm_isdst) { + int dst = tm.tm_isdst; + (void)strptime(strDate, *fmt, &tm); + tm.tm_isdst = dst; + date = mktime(&tm); + } + + +#ifdef INV_DEBUG + printf("the date entered is %s\n", strDate); + printf("the hour parsed from string is %d\n", tm.tm_hour); + printf("the date entered in secs is %ld\n", date); +#endif /* INV_DEBUG */ + + return date; +} + + +char * +GetNameOfInvIndex (uuid_t uuid) +{ + char *name; + char str[UUID_STR_LEN + 1]; + + uuid_unparse( uuid, str ); + + name = (char *) malloc( strlen( INV_DIRPATH ) + 1 + strlen( str ) + + strlen( INV_INVINDEX_PREFIX ) + 1); + strcpy( name, INV_DIRPATH ); + strcat( name, "/" ); + strcat( name, str ); + strcat( name, INV_INVINDEX_PREFIX ); + + return(name); +} + +char * +GetFstabFullPath(void) +{ + char *fstabname; + + fstabname = (char *) malloc( strlen(INV_DIRPATH) + 1 /* one for the "/" */ + + strlen("fstab") + 1 ); + strcpy( fstabname, INV_DIRPATH ); + strcat( fstabname, "/" ); + strcat( fstabname, "fstab" ); + return(fstabname); +} + +void +CheckAndPruneFstab(bool_t checkonly, char *mountPt, time_t prunetime) +{ + char *fstabname, *mapaddr, *invname; + int fstabEntries,nEntries; + int fd,i,j; + bool_t removeflag; + invt_fstab_t *fstabentry; + invt_counter_t *counter,cnt; + + fstabname = GetFstabFullPath(); + fd = open( fstabname, O_RDWR ); + if (fd == -1) + { + fprintf( stderr, "%s: unable to open file %s: %s\n", + g_programName, + fstabname, + strerror(errno) ); + if(errno == ENOENT) { + fprintf( stderr, "%s: there doesn't seem to be an inventory to process\n", g_programName); + } + exit(1); + } + + read(fd,&cnt,sizeof(invt_counter_t) ); + nEntries = cnt.ic_curnum; + + lseek( fd, 0, SEEK_SET ); + mapaddr = (char *) mmap( 0, (nEntries*sizeof(invt_fstab_t)) + + sizeof(invt_counter_t), + (PROT_READ|PROT_WRITE), MAP_SHARED, fd, 0 ); + + if (mapaddr == (char *)-1) + { + fprintf( stderr, + "%s: error in mmap at %d with errno %d for file %s\n", + g_programName, __LINE__, errno, fstabname ); + fprintf( stderr, "%s: abnormal termination\n", g_programName ); + perror( "mmap" ); + exit(1); + } + + counter = (invt_counter_t *)mapaddr; + fstabentry = (invt_fstab_t *)(mapaddr + sizeof(invt_counter_t)); + + printf("Processing file %s\n",fstabname); + + /* check each entry in fstab for mount pt match */ + for (i = 0; i < counter->ic_curnum; ) + { + removeflag = BOOL_FALSE; + + printf(" Found entry for %s\n" , fstabentry[i].ft_mountpt); + + for (j = i +1 ; j < counter->ic_curnum ; j++ ) + if (uuid_compare(fstabentry[i].ft_uuid, fstabentry[j].ft_uuid) == 0) + { + printf(" duplicate fstab entry\n"); + removeflag = BOOL_TRUE; + break; + } + + if (!removeflag) + { + bool_t IdxCheckOnly = BOOL_TRUE; + + invname = GetNameOfInvIndex(fstabentry[i].ft_uuid); + +#ifdef INV_DEBUG + printf("ft_mountpt = %s, mountPt = %s\n", + fstabentry[i].ft_mountpt, mountPt); +#endif + if (( checkonly == BOOL_FALSE ) && + (strcmp( fstabentry[i].ft_mountpt, mountPt ) == 0)) + { + IdxCheckOnly = BOOL_FALSE; + } + + if ( CheckAndPruneInvIndexFile( IdxCheckOnly, invname , prunetime ) + == -1 ) + removeflag = BOOL_TRUE; + + free( invname ); + + } + + if (removeflag == BOOL_TRUE) + { + printf(" removing fstab entry %s\n", fstabentry[i].ft_mountpt); + if ( counter->ic_curnum > 1 ) + bcopy((void *)&fstabentry[i + 1], (void *)&fstabentry[i], + (sizeof(invt_fstab_t) * (counter->ic_curnum - i - 1))); + counter->ic_curnum--; + } + else + i++; /* next entry if this entry not removed */ + } + + fstabEntries = counter->ic_curnum; + + munmap( mapaddr, (nEntries*sizeof(invt_fstab_t)) + + sizeof(invt_counter_t) ); + + if ((fstabEntries != 0) && (fstabEntries != nEntries)) + ftruncate(fd, sizeof(invt_counter_t) + + (sizeof(invt_fstab_t) * fstabEntries)); + + close(fd); + + if (fstabEntries == 0) + { + unlink( fstabname ); + } + + free( fstabname ); +} + +int +CheckAndPruneInvIndexFile( bool_t checkonly, char *idxFileName , + time_t prunetime ) +{ + char *temp; + int fd; + int i, validEntries,nEntries; + bool_t removeflag; + + invt_entry_t *invIndexEntry; + invt_counter_t *counter,header; + bool_t IdxCheckOnly = BOOL_TRUE; + + printf(" processing index file \n" + " %s\n",idxFileName); + errno=0; + fd = open( idxFileName, O_RDWR ); + if (fd == -1) + { + fprintf( stderr, " %s: open of %s failed with errno %d\n", + g_programName, idxFileName, errno ); + perror( "open" ); + return(-1); + } + + read( fd, &header, sizeof(invt_counter_t) ); + nEntries = header.ic_curnum; + + lseek( fd, 0, SEEK_SET ); + errno = 0; + temp = (char *) mmap( NULL, (nEntries*sizeof(invt_entry_t)) + + sizeof(invt_counter_t), + (PROT_READ|PROT_WRITE), MAP_SHARED, fd, + 0 ); + + if (temp == (char *)-1) + { + fprintf( stderr, + "%s: error in mmap at %d with errno %d for file %s\n", + g_programName, __LINE__, errno, idxFileName ); + fprintf( stderr, "%s: abnormal termination\n", g_programName ); + perror( "mmap" ); + exit(1); + } + + counter = (invt_counter_t *)temp; + invIndexEntry = (invt_entry_t *)( temp + sizeof(invt_counter_t)); + + for (i=0; i < counter->ic_curnum; ) + { + removeflag = BOOL_FALSE; + errno = 0; + printf(" Checking access for\n" + " %s\n", invIndexEntry[i].ie_filename); + if (debug) { + printf(" Time:\tbegin %s\t\tend %s", + ctime(&(invIndexEntry[i].ie_timeperiod.tp_start)), + ctime(&(invIndexEntry[i].ie_timeperiod.tp_end))); + } + + if (( access( invIndexEntry[i].ie_filename, R_OK | W_OK ) == -1) && + (errno == ENOENT)) + { + printf(" Unable to access %s referred in %s\n", + invIndexEntry[i].ie_filename, idxFileName); + printf(" removing index entry \n"); + removeflag = BOOL_TRUE; + } + + if (( !removeflag ) && (checkonly == BOOL_FALSE) && + ( invIndexEntry[i].ie_timeperiod.tp_start < prunetime)) + { + IdxCheckOnly = BOOL_FALSE; + + printf(" Mount point match\n"); + } + if (CheckAndPruneStObjFile( IdxCheckOnly, + invIndexEntry[i].ie_filename, prunetime) == -1) { + removeflag = BOOL_TRUE; /* The StObj is gone */ + } + + if (removeflag == BOOL_TRUE) + { + if ( counter->ic_curnum > 1 ) + bcopy((void *)&invIndexEntry[i + 1], (void *)&invIndexEntry[i], + (sizeof(invt_entry_t) * (counter->ic_curnum - i - 1))); + counter->ic_curnum--; + } + else + i++; /* next entry if this entry not removed */ + } + + validEntries = counter->ic_curnum; + + munmap( temp, (nEntries*sizeof(invt_entry_t)) + sizeof(invt_counter_t) ); + + if ((validEntries != 0) && (validEntries != nEntries)) + ftruncate( fd, sizeof(invt_counter_t) + + (validEntries * sizeof(invt_entry_t)) ); + + if (debug) + printf(" pruned %d entries from this index file, %d remaining\n", + (nEntries - validEntries), validEntries); + + close( fd ); + + if (validEntries == 0) + { + unlink( idxFileName ); + return(-1); + } + + return(0); +} + +int +CheckAndPruneStObjFile( bool_t checkonly, char *StObjFileName , + time_t prunetime ) +{ + char response[GEN_STRLEN]; + char *temp; + int fd; + int i, validEntries; + bool_t removeflag; + int prunedcount = 0; + int removedcount = 0; + + invt_seshdr_t *StObjhdr; + invt_session_t *StObjses; + struct stat sb; + char str[UUID_STR_LEN + 1]; + int sescount; + + invt_sescounter_t *counter,header; + + errno=0; + fd = open( StObjFileName, O_RDWR ); + if (fd == -1) + { + fprintf( stderr, " %s: open of %s failed with errno %d\n", + g_programName, StObjFileName, errno ); + perror( "open" ); + return(-1); + } + + read( fd, &header, sizeof(invt_sescounter_t) ); + + lseek( fd, 0, SEEK_SET ); + errno = 0; + + if (fstat(fd, &sb) < 0) { + fprintf(stderr, "Could not get stat info on %s\n", StObjFileName); + perror("fstat"); + exit(1); + } + + temp = (char *) mmap( NULL, sb.st_size, (PROT_READ|PROT_WRITE), + MAP_SHARED, fd, 0 ); + + if (temp == (char *)-1) + { + fprintf( stderr, + "%s: error in mmap at %d with errno %d for file %s\n", + g_programName, __LINE__, errno, StObjFileName ); + fprintf( stderr, "%s: abnormal termination\n", g_programName ); + perror( "mmap" ); + exit(1); + } + + counter = (invt_sescounter_t *)temp; + + StObjhdr = (invt_seshdr_t *)( temp + sizeof(invt_sescounter_t)); + StObjses = (invt_session_t *)(temp + StObjhdr->sh_sess_off); + + sescount = 0; + for (i=0; i < counter->ic_curnum; ) + { + removeflag = BOOL_FALSE; + if (StObjhdr->sh_pruned) + prunedcount++; + + errno = 0; + if (! StObjhdr->sh_pruned) { + printf(" Session %d: %s %s", + sescount++, + StObjses->s_mountpt, + ctime( &StObjhdr->sh_time )); + } + if (debug) { + /* Note that the DMF people use some of this debug + * output for their interface to the inventory. + * They care about the following fields: + * media label: + * interrupted: + * session label: + * level: + * Do not change these fields w/out talking to + * them first. + */ + int i; + int j; + invt_stream_t *StObjstrm; + invt_mediafile_t *StObjmed; + + if (StObjhdr->sh_pruned) + printf(" Pruned Session: %s %s", + StObjses->s_mountpt, + ctime( &StObjhdr->sh_time )); + printf("\t\tdevice:\t\t%s\n", StObjses->s_devpath); + printf("\t\tsession label:\t\"%s\"\n", StObjses->s_label); + uuid_unparse(StObjses->s_sesid, str); + printf("\t\tsession id:\t%s\n", str); + printf("\t\tlevel:\t\t%d\n", StObjhdr->sh_level); + printf("\t\tstreams:\t%d\n", StObjses->s_cur_nstreams ); + for ( i = 0; i < (int) StObjses->s_cur_nstreams; i++ ) { + printf( "\t\tstream %d:\n", i); + StObjstrm = (invt_stream_t *)(temp + + StObjhdr->sh_streams_off + + (i * sizeof(invt_stream_t))); + printf( "\t\t\tpathname:\t%s\n", + StObjstrm->st_cmdarg); + printf( "\t\t\tinode start:\t%lld\n", + (long long)StObjstrm->st_startino.ino); + printf( "\t\t\tinode end:\t%lld\n", + (long long)StObjstrm->st_endino.ino); + printf( "\t\t\tinterrupted:\t%s\n", + StObjstrm->st_interrupted ? "YES" : "NO" ); + printf( "\t\t\tmedia files:\t%d\n", + StObjstrm->st_nmediafiles); + for ( j = 0; j < StObjstrm->st_nmediafiles; j++) { + StObjmed = (invt_mediafile_t *)(temp + + StObjstrm->st_firstmfile + + (j * sizeof(invt_mediafile_t))); + printf( "\t\t\tmfile file %d:\n", j); + printf( "\t\t\t\tmfile size:\t%lld\n", + (long long)StObjmed->mf_size); + printf( "\t\t\t\tmfile start:\t%lld\n", + (long long)StObjmed->mf_startino.ino); + printf( "\t\t\t\tmfile end:\t%lld\n", + (long long)StObjmed->mf_endino.ino); + printf( "\t\t\t\tmedia label:\t\"%s\"\n", + StObjmed->mf_label); + } + } + } + +#ifdef INV_DEBUG + printf("sh_time = %ld, prunetime = %ld\n", + StObjhdr->sh_time, prunetime); + printf("checkonly = %d, sh_pruned = %d\n", + checkonly, StObjhdr->sh_pruned); +#endif + + if ((checkonly == BOOL_FALSE) && (! StObjhdr->sh_pruned) && + (StObjhdr->sh_time < prunetime)) { + bool_t GotResponse = BOOL_FALSE; + + uuid_unparse(StObjses->s_sesid, str); + if (nonInteractive) { + printf("-------------------------------------------------\n"); + printf("Pruning this matching entry:\n"); + printf( "UUID\t\t:\t%s\nMOUNT POINT\t:\t%s\n" + "DEV PATH\t:\t%s\n" + "LABEL\t\t:\t%s\n" + "TIME OF DUMP\t:\t%s", + str, StObjses->s_mountpt, StObjses->s_devpath, + StObjses->s_label, ctime( &StObjhdr->sh_time )); + removeflag = BOOL_TRUE; + } + else { + printf("-------------------------------------------------\n"); + printf("An entry matching the mount point/time is :\n"); + printf( "UUID\t\t:\t%s\nMOUNT POINT\t:\t%s\n" + "DEV PATH\t:\t%s\nTIME OF DUMP\t:\t%s", + str, StObjses->s_mountpt, StObjses->s_devpath, + ctime( &StObjhdr->sh_time )); + while ( GotResponse == BOOL_FALSE ) + { + char *chp; + + printf("\nDo you want to prune this entry: [y/n] "); + fgets( response, GEN_STRLEN, stdin ); + chp = strchr( response, '\n'); + if (chp) *chp = '\0'; + if (strcasecmp( response, "Y" ) == 0) + { + removeflag = BOOL_TRUE; + GotResponse = BOOL_TRUE; + } + else if (strcasecmp( response, "N" ) == 0) + { + GotResponse = BOOL_TRUE; + } + } + } + printf("-------------------------------------------------\n\n"); + } + + if (removeflag == BOOL_TRUE) + { + /* Mark this entry as pruned */ + StObjhdr->sh_pruned = 1; + removedcount++; + } + + i++; + + StObjhdr = (invt_seshdr_t *) + ( temp + sizeof(invt_sescounter_t) + + (i * sizeof(invt_seshdr_t)) ); + StObjses = (invt_session_t *)(temp + StObjhdr->sh_sess_off); + } + + validEntries = counter->ic_curnum - prunedcount - removedcount; + + munmap( temp, sb.st_size); + + if (debug && removedcount) + printf(" pruned %d entries from this StObj file," + " %d remaining\n", removedcount, validEntries); + + close( fd ); + + if (validEntries == 0) + { + if (debug) + printf("Removing: %s\n", StObjFileName); + unlink( StObjFileName ); + return(-1); + } + + return(0); +} + +void +usage (void) +{ + fprintf( stderr, "%s: version 1.0\n", g_programName ); + fprintf( stderr, "check or prune the xfsdump inventory\n" ); + fprintf( stderr, "usage: \n" ); + fprintf( stderr, "xfsinvutil [ -M mountPt mm/dd/yyyy ] ( prune all entries\n" + " older than specified date\n" + " for the specified mount point )\n" ); + fprintf( stderr, " [ -C ] ( check and fix xfsdump inventory\n" + " database inconsistencies ) \n" ); + fprintf( stderr, " [ -n ] ( don't ask questions )\n" ); + exit(1); +} + diff -rNu linux-2.4.7/cmd/xfsdump/librmt/CVS/Entries linux-2.4-xfs/cmd/xfsdump/librmt/CVS/Entries --- linux-2.4.7/cmd/xfsdump/librmt/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/CVS/Entries Thu Jul 5 11:44:07 2001 @@ -0,0 +1,19 @@ +/Makefile/1.3/Thu Jul 5 08:42:14 2001/-ko/ +/isrmt.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/rmtabort.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/rmtaccess.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/rmtclose.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/rmtcommand.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/rmtcreat.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/rmtdev.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/rmtfstat.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/rmtioctl.c/1.3/Thu Jul 5 08:42:14 2001/-ko/ +/rmtisatty.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/rmtlib.h/1.2/Thu Jul 5 08:42:14 2001/-ko/ +/rmtlseek.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/rmtmsg.c/1.1/Thu Jul 5 08:42:14 2001/-ko/ +/rmtopen.c/1.4/Thu Jul 5 08:42:14 2001/-ko/ +/rmtread.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/rmtstatus.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/rmtwrite.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/librmt/CVS/Repository linux-2.4-xfs/cmd/xfsdump/librmt/CVS/Repository --- linux-2.4.7/cmd/xfsdump/librmt/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/CVS/Repository Thu Jul 5 11:44:06 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/librmt diff -rNu linux-2.4.7/cmd/xfsdump/librmt/CVS/Root linux-2.4-xfs/cmd/xfsdump/librmt/CVS/Root --- linux-2.4.7/cmd/xfsdump/librmt/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/CVS/Root Thu Jul 5 11:44:06 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/librmt/Makefile linux-2.4-xfs/cmd/xfsdump/librmt/Makefile --- linux-2.4.7/cmd/xfsdump/librmt/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/Makefile Thu Jul 5 03:42:14 2001 @@ -0,0 +1,54 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in +# certain portions may be held by third parties as indicated herein. +# All Rights Reserved. +# +# The code in this source file represents an aggregation of work from +# Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon +# Graphics engineers over the period 1985-2000. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +STATICLIBTARGET = librmt.a +HFILES = rmtlib.h +CFILES = \ + isrmt.c rmtclose.c rmtdev.c rmtisatty.c rmtread.c \ + rmtabort.c rmtcommand.c rmtfstat.c rmtlseek.c rmtstatus.c \ + rmtaccess.c rmtcreat.c rmtioctl.c rmtopen.c rmtwrite.c \ + rmtmsg.c + +default: $(STATICLIBTARGET) + +include $(BUILDRULES) + +install install-dev: default diff -rNu linux-2.4.7/cmd/xfsdump/librmt/isrmt.c linux-2.4-xfs/cmd/xfsdump/librmt/isrmt.c --- linux-2.4.7/cmd/xfsdump/librmt/isrmt.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/isrmt.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Header: /proj/irix6.5m-melb/isms/eoe/lib/librmt/src/RCS/isrmt.c,v 1.1 1988/12/07 16:33:17 lindy Exp $" + +#include "rmtlib.h" + +/* + * Isrmt. Let a programmer know he has a remote device. + */ + +int isrmt (fd) +int fd; +{ + return (fd >= REM_BIAS); +} diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtabort.c linux-2.4-xfs/cmd/xfsdump/librmt/rmtabort.c --- linux-2.4.7/cmd/xfsdump/librmt/rmtabort.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtabort.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Header: /proj/irix6.5m-melb/isms/eoe/lib/librmt/src/RCS/rmtabort.c,v 1.2 1992/08/02 20:54:07 ism Exp $" + +#include "rmtlib.h" + +/* + * abort --- close off a remote tape connection + */ + +void _rmt_abort(int fildes) +{ + close(READ(fildes)); + close(WRITE(fildes)); + READ(fildes) = -1; + WRITE(fildes) = -1; + RMTHOST(fildes) = -1; +} diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtaccess.c linux-2.4-xfs/cmd/xfsdump/librmt/rmtaccess.c --- linux-2.4.7/cmd/xfsdump/librmt/rmtaccess.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtaccess.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Header: /proj/irix6.5m-melb/isms/eoe/lib/librmt/src/RCS/rmtaccess.c,v 1.1 1988/12/07 16:33:19 lindy Exp $" + +#include +#include "rmtlib.h" + +/* + * Test pathname for specified access. Looks just like access(2) + * to caller. + */ + +int rmtaccess (path, amode) +char *path; +int amode; +{ + if (_rmt_dev (path)) + { + return (0); /* Let /etc/rmt find out */ + } + else + { + return (access (path, amode)); + } +} + + diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtclose.c linux-2.4-xfs/cmd/xfsdump/librmt/rmtclose.c --- linux-2.4.7/cmd/xfsdump/librmt/rmtclose.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtclose.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Header: /proj/irix6.5m-melb/isms/eoe/lib/librmt/src/RCS/rmtclose.c,v 1.2 1992/08/02 20:54:13 ism Exp $" + +#include "rmtlib.h" + +static int _rmt_close(int); +/* + * Close a file. Looks just like close(2) to caller. + */ + +int rmtclose (fildes) +int fildes; +{ + if (isrmt (fildes)) + { + /* no longer know what host we have for this fildes */ + RMTHOST(fildes - REM_BIAS) = UNAME_UNKNOWN; + + return (_rmt_close (fildes - REM_BIAS)); + } + else + { + return (close (fildes)); + } +} + +/* + * _rmt_close --- close a remote magtape unit and shut down + */ + +static int _rmt_close(int fildes) +{ + int rc; + + if (_rmt_command(fildes, "C\n") != -1) + { + rc = _rmt_status(fildes); + + _rmt_abort(fildes); + return(rc); + } + + return(-1); +} + + diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtcommand.c linux-2.4-xfs/cmd/xfsdump/librmt/rmtcommand.c --- linux-2.4.7/cmd/xfsdump/librmt/rmtcommand.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtcommand.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Header: /proj/irix6.5m-melb/isms/eoe/lib/librmt/src/RCS/rmtcommand.c,v 1.3 1995/03/15 17:55:18 tap Exp $" + +#include +#include + +#include "rmtlib.h" + + +/* + * _rmt_command --- attempt to perform a remote tape command + */ + +int _rmt_command(fildes, buf) +int fildes; +char *buf; +{ + register int blen; + void (*pstat)(); + +/* + * save current pipe status and try to make the request + */ + + blen = strlen(buf); + pstat = signal(SIGPIPE, SIG_IGN); + if (write(WRITE(fildes), buf, blen) == blen) + { + signal(SIGPIPE, pstat); + return(0); + } + +/* + * something went wrong. close down and go home + */ + + signal(SIGPIPE, pstat); + _rmt_abort(fildes); + + setoserror( EIO ); + return(-1); +} + + + diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtcreat.c linux-2.4-xfs/cmd/xfsdump/librmt/rmtcreat.c --- linux-2.4.7/cmd/xfsdump/librmt/rmtcreat.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtcreat.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Header: /proj/irix6.5m-melb/isms/eoe/lib/librmt/src/RCS/rmtcreat.c,v 1.1 1988/12/07 16:33:20 lindy Exp $" + +/* + * Create a file from scratch. Looks just like creat(2) to the caller. + */ + +#include +#include +#include /* use this one for S5 with remote stuff */ +#include "rmtlib.h" + +extern int rmtopen(char*, int, int); + +int rmtcreat (path, mode) +char *path; +int mode; +{ + if (_rmt_dev (path)) + { + return (rmtopen (path, 1 | O_CREAT, mode)); + } + else + { + return (creat (path, mode)); + } +} + + diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtdev.c linux-2.4-xfs/cmd/xfsdump/librmt/rmtdev.c --- linux-2.4.7/cmd/xfsdump/librmt/rmtdev.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtdev.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Header: /proj/irix6.5m-melb/isms/eoe/lib/librmt/src/RCS/rmtdev.c,v 1.1 1988/12/07 16:33:21 lindy Exp $" + +#include + +/* + * Test pathname to see if it is local or remote. A remote device + * is any string that contains ":/dev/". Returns 1 if remote, + * 0 otherwise. + */ + +int _rmt_dev (path) +register char *path; +{ + if ((path = strchr (path, ':')) != (char *)0) + { + if (strncmp (path + 1, "/dev/", 5) == 0) + { + return (1); + } + } + return (0); +} + + diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtfstat.c linux-2.4-xfs/cmd/xfsdump/librmt/rmtfstat.c --- linux-2.4.7/cmd/xfsdump/librmt/rmtfstat.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtfstat.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Header: /proj/irix6.5m-melb/isms/eoe/lib/librmt/src/RCS/rmtfstat.c,v 1.9 1997/08/06 23:34:40 prasadb Exp $" + +#include "rmtlib.h" + +#include +#include +#include + +static int _rmt_fstat(int, char *); + +/* + * Get file status. Looks just like fstat(2) to caller. + */ + +int rmtfstat (fildes, buf) +int fildes; +struct stat *buf; +{ + if (isrmt (fildes)) + { + return (_rmt_fstat (fildes - REM_BIAS, (char *)buf)); + } + else + { + int i; + i = fstat(fildes, buf); + return i; + } +} + +static int +_rmt_fstat(int fildes, char *arg) +{ + char buffer[ BUFMAGIC ]; + int rc, cnt, adj_rc; + + sprintf( buffer, "Z%d\n", fildes ); + + /* + * grab the status and read it directly into the structure + * this assumes that the status buffer is (hopefully) not + * padded and that 2 shorts fit in a long without any word + * alignment problems, ie - the whole struct is contiguous + * NOTE - this is probably NOT a good assumption. + */ + + if (_rmt_command(fildes, buffer) == -1 || + (rc = _rmt_status(fildes)) == -1) + return(-1); + + /* adjust read count to prevent overflow */ + + adj_rc = (rc > sizeof(struct stat)) ? sizeof(struct stat) : rc ; + rc -= adj_rc; + + for (; adj_rc > 0; adj_rc -= cnt, arg += cnt) + { + cnt = read(READ(fildes), arg, adj_rc); + if (cnt <= 0) + { +abortit: + _rmt_abort(fildes); + setoserror( EIO ); + return(-1); + } + } + + /* handle any bytes we didn't know what to do with */ + while (rc-- > 0) + if (read(READ(fildes), buffer, 1) <= 0) + goto abortit; + + return(0); +} diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtioctl.c linux-2.4-xfs/cmd/xfsdump/librmt/rmtioctl.c --- linux-2.4.7/cmd/xfsdump/librmt/rmtioctl.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtioctl.c Thu Jul 5 03:42:14 2001 @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include "rmtlib.h" + +#include +#include +#include +#include + +struct irix_mtget { + short mt_type; /* type of magtape device */ + unsigned short mt_dposn; /* status of tape position */ + unsigned short mt_dsreg; /* ``drive status'' register */ + short mt_erreg; /* ``error'' register */ + short mt_resid; /* residual count */ + short pad; + int mt_fileno; /* file number of current position */ + int mt_blkno; /* block number of current position */ +}; + +/* IRIX tape device status values */ +#define IRIX_MT_EOT 0x01 /* tape is at end of media */ +#define IRIX_MT_BOT 0x02 /* tape is at beginning of media */ +#define IRIX_MT_WPROT 0x04 /* tape is write-protected */ +#define IRIX_MT_EW 0x08 /* hit early warning marker */ +#define IRIX_MT_ONL 0x40 /* drive is online */ +#define IRIX_MT_EOD 0x4000 /* tape is at end of data */ +#define IRIX_MT_FMK 0x8000 /* tape is at file mark */ + +/* IRIX mt operations (mt_op values for MTIOCTOP) */ +#define IRIX_MTWEOF 0 /* write an end-of-file record */ +#define IRIX_MTFSF 1 /* forward space file */ +#define IRIX_MTBSF 2 /* backward space file */ +#define IRIX_MTFSR 3 /* forward space record */ +#define IRIX_MTBSR 4 /* backward space record */ +#define IRIX_MTREW 5 /* rewind */ +#define IRIX_MTOFFL 6 /* rewind and put the drive offline */ +#define IRIX_MTERASE 12 /* erase tape from current position to EOT */ +#define IRIX_MTUNLOAD 13 /* unload tape from drive */ + +/* std (common) mt op codes */ +#define STD_MTWEOF 0 /* write an end-of-file record */ +#define STD_MTFSF 1 /* forward space file */ +#define STD_MTBSF 2 /* backward space file */ +#define STD_MTFSR 3 /* forward space record */ +#define STD_MTBSR 4 /* backward space record */ +#define STD_MTREW 5 /* rewind */ +#define STD_MTOFFL 6 /* rewind and put the drive offline */ + +#define MT_MAX 40 /* encompass potential range of mt_op values */ +static int mtop_irixmap[MT_MAX] = {-1}; +static int mtop_stdmap[MT_MAX] = {-1}; + +static void +init_mtop_map(void) +{ + /* set all other values to sentinel (-1) */ + + /* only map the ones which xfsdump/restore are interested in */ + mtop_irixmap[MTWEOF] = IRIX_MTWEOF; + mtop_irixmap[MTFSF] = IRIX_MTFSF; + mtop_irixmap[MTBSF] = IRIX_MTBSF; + mtop_irixmap[MTFSR] = IRIX_MTFSR; + mtop_irixmap[MTBSR] = IRIX_MTBSR; + mtop_irixmap[MTREW] = IRIX_MTREW; + mtop_irixmap[MTOFFL] = IRIX_MTOFFL; + mtop_irixmap[MTERASE] = IRIX_MTERASE; + mtop_irixmap[MTUNLOAD] = IRIX_MTUNLOAD; + + mtop_stdmap[MTWEOF] = STD_MTWEOF; + mtop_stdmap[MTFSF] = STD_MTFSF; + mtop_stdmap[MTBSF] = STD_MTBSF; + mtop_stdmap[MTFSR] = STD_MTFSR; + mtop_stdmap[MTBSR] = STD_MTBSR; + mtop_stdmap[MTREW] = STD_MTREW; + mtop_stdmap[MTOFFL] = STD_MTOFFL; + mtop_stdmap[MTUNLOAD] = STD_MTOFFL; +} + + +static int _rmt_ioctl(int, unsigned int, void *); + +/* + * Do ioctl on file. Looks just like ioctl(2) to caller. + */ + +int +rmtioctl(int fildes, unsigned int request, void *arg) +{ + if (isrmt (fildes)) { + return (_rmt_ioctl (fildes - REM_BIAS, request, arg)); + } + else { + return (ioctl (fildes, request, arg)); + } +} + + +/* + * _rmt_ioctl --- perform raw tape operations remotely + */ + +/* + * WARNING: MTIOCGET code is highly dependent on the format + * of mtget on different platforms + * We only support Linux or IRIX for this case. + * We use the result of uname(1) (in rmtopen()) if it works or + * the size of the mtget structure to determine which host it is. + */ + +static int +_rmt_ioctl(int fildes, unsigned int op, void *arg) +{ + char buffer[BUFMAGIC]; + int rc, cnt, ssize; + char *p = NULL, *irixget = NULL; + struct irix_mtget irix_mtget; + static int onetrip = 0; + + if (!onetrip) { + onetrip = 1; + init_mtop_map(); + } + +/* + * MTIOCTOP is the easy one. nothing is transfered in binary + */ + + if (op == MTIOCTOP) { + int mt_op = ((struct mtop *) arg)->mt_op; + int mt_count = ((struct mtop *) arg)->mt_count; + + if (RMTHOST(fildes) == UNAME_UNDEFINED) { + _rmt_msg(RMTWARN, "rmtioctl: remote host type not supported for MTIOCTOP\n"); + setoserror( EPROTONOSUPPORT ); + return(-1); + } + + /* map the linux op code to the irix op code */ + if (RMTHOST(fildes) == UNAME_IRIX) { + mt_op = mtop_irixmap[mt_op]; + if (mt_op == -1) { + setoserror( EINVAL ); + return(-1); + } + } + else if (RMTHOST(fildes) != UNAME_LINUX) { + /* map the linux op code to the standard/fallback op code */ + mt_op = mtop_stdmap[mt_op]; + if (mt_op == -1) { + setoserror( EINVAL ); + return(-1); + } + } + + sprintf(buffer, "I%d\n%d\n", mt_op, mt_count); + if (_rmt_command(fildes, buffer) == -1) { + return(-1); + } + return(_rmt_status(fildes)); + } + else if (op == MTIOCGET) { + + /* + * Grab the status and read it directly into the structure. + * Since the data is binary data, and the other machine might + * be IRIX or Linux of a different byte-order, + * we have to be careful in converting the data. + * + * NOTE: the original /etc/rmt did NOT support a newline after + * the S command, and Sun still does not. Neither does the + * current bsd source, all the way through the tahoe release. + * So do NOT add the \n to this! The sgi rmt command will + * work either way. Olson, 4/91 + */ + if (_rmt_command(fildes, "S") == -1 || + (rc = _rmt_status(fildes)) == -1) + return(-1); + + + /* If undefined then try and define it by looking + * and the size of the get structure. + * If we know our rmt host, then verify that the + * structure is the correct size for the supported ones + */ + switch (RMTHOST(fildes)) { + case UNAME_UNDEFINED: + _rmt_msg(RMTWARN, "rmtioctl: remote host type not supported for MTIOCGET\n"); + setoserror( EPROTONOSUPPORT ); + return(-1); + case UNAME_IRIX: + if (sizeof(struct irix_mtget) != rc) { + _rmt_msg(RMTWARN, "rmtioctl: IRIX mtget structure of wrong size\n"); + setoserror( EPROTONOSUPPORT ); + return(-1); + } + break; + case UNAME_LINUX: + if (sizeof(struct mtget) != rc) { + _rmt_msg(RMTWARN, "rmtioctl: Linux mtget structure of wrong size\n"); + setoserror( EPROTONOSUPPORT ); + return(-1); + } + break; + default: + setoserror( EPROTONOSUPPORT ); + return(-1); + } + + + assert(RMTHOST(fildes)==UNAME_LINUX || RMTHOST(fildes)==UNAME_IRIX); + + + if (RMTHOST(fildes) == UNAME_LINUX) + p = arg; + else + p = irixget = (char *)&irix_mtget; + + + /* read in all the data */ + ssize = rc; + for (; ssize > 0; ssize -= cnt, p += cnt) { + cnt = read(READ(fildes), p, ssize); + if (cnt <= 0) { + _rmt_abort(fildes); + setoserror( EIO ); + return(-1); + } + } + + + /* + * May need to byteswap + */ + if (RMTHOST(fildes) == UNAME_IRIX) { + struct irix_mtget *irixp = (struct irix_mtget *)irixget; + + if (irixp->mt_type > 0xff) { + /* assume that mt_type should fit in 1 byte */ + + irixp->mt_type = INT_SWAP(irixp->mt_type, irixp->mt_type); + irixp->mt_dsreg = INT_SWAP(irixp->mt_dsreg, irixp->mt_dsreg); + irixp->mt_erreg = INT_SWAP(irixp->mt_erreg, irixp->mt_erreg); + irixp->mt_resid = INT_SWAP(irixp->mt_resid, irixp->mt_resid); + irixp->mt_fileno = INT_SWAP(irixp->mt_fileno, irixp->mt_fileno); + irixp->mt_blkno = INT_SWAP(irixp->mt_blkno, irixp->mt_blkno); + irixp->mt_dposn = INT_SWAP(irixp->mt_dposn, irixp->mt_dposn); + } + } + else { /* LINUX */ + struct mtget *linuxp = (struct mtget *)arg; + + if (linuxp->mt_type > 0xffff) { + /* assume that mt_type should fit in 2 bytes */ + + linuxp->mt_type = INT_SWAP(linuxp->mt_type, linuxp->mt_type); + linuxp->mt_dsreg = INT_SWAP(linuxp->mt_dsreg, linuxp->mt_dsreg); + linuxp->mt_erreg = INT_SWAP(linuxp->mt_erreg, linuxp->mt_erreg); + linuxp->mt_resid = INT_SWAP(linuxp->mt_resid, linuxp->mt_resid); + linuxp->mt_fileno = INT_SWAP(linuxp->mt_fileno, linuxp->mt_fileno); + linuxp->mt_blkno = INT_SWAP(linuxp->mt_blkno, linuxp->mt_blkno); + linuxp->mt_gstat = INT_SWAP(linuxp->mt_gstat, linuxp->mt_gstat); + + } + } + + /* + * now mtget has the correct (byte-swapped if needed) + * data, if we are talking to irix then lets convert + * the data into something that we can use + * else all done + */ + if (RMTHOST(fildes) == UNAME_IRIX) { + struct mtget *dstp = (struct mtget *)arg; + struct irix_mtget *srcp = (struct irix_mtget *)irixget; + short status = srcp->mt_dsreg; + + dstp->mt_type = srcp->mt_type; + dstp->mt_erreg = srcp->mt_erreg; + dstp->mt_resid = srcp->mt_resid; + dstp->mt_fileno = srcp->mt_fileno; + dstp->mt_blkno = srcp->mt_blkno; + dstp->mt_dsreg = srcp->mt_dsreg; /* different semantics */ + + /* need to do tape status conversions */ + dstp->mt_gstat = 0; + if (status & IRIX_MT_EOT) + dstp->mt_gstat |= GMT_EOT(0xffffffff); + if (status & IRIX_MT_BOT) + dstp->mt_gstat |= GMT_BOT(0xffffffff); + if (status & IRIX_MT_WPROT) + dstp->mt_gstat |= GMT_WR_PROT(0xffffffff); + if (status & IRIX_MT_ONL) + dstp->mt_gstat |= GMT_ONLINE(0xffffffff); + if (status & IRIX_MT_EOD) + dstp->mt_gstat |= GMT_EOD(0xffffffff); + if (status & IRIX_MT_FMK) + dstp->mt_gstat |= GMT_EOF(0xffffffff); + if (status & IRIX_MT_EW) + ;/* No GMT_ to map it to */ + } + + return(0); + + } + else { + setoserror( EINVAL ); + return(-1); + } +} diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtisatty.c linux-2.4-xfs/cmd/xfsdump/librmt/rmtisatty.c --- linux-2.4.7/cmd/xfsdump/librmt/rmtisatty.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtisatty.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Header: /proj/irix6.5m-melb/isms/eoe/lib/librmt/src/RCS/rmtisatty.c,v 1.1 1988/12/07 16:33:23 lindy Exp $" + +#include +#include "rmtlib.h" + +/* + * Rmtisatty. Do the isatty function. + */ + +int rmtisatty (fd) +int fd; +{ + if (isrmt (fd)) + { + return (0); + } + else + { + return (isatty (fd)); + } +} diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtlib.h linux-2.4-xfs/cmd/xfsdump/librmt/rmtlib.h --- linux-2.4.7/cmd/xfsdump/librmt/rmtlib.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtlib.h Thu Jul 5 03:42:14 2001 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * This file is only included by the library routines. It is not + * required for user code. + * + */ + + +#include + +#define LIBRMT_VERSION 2 +extern int server_version; + +/* + * Note that local vs remote file descriptors are distinquished + * by adding a bias to the remote descriptors. This is a quick + * and dirty trick that may not be portable to some systems. + * It should be greater than the largest open filedescriptor + * than can be returned by the OS, and should be a power of 2. + */ + +#define REM_BIAS 8192 + + +/* + * BUFMAGIC --- Magic buffer size + * MAXUNIT --- Maximum number of remote tape file units + */ + +#define BUFMAGIC 64 +#define MAXUNIT 4 + +/* + * Useful macros. + * + * READ --- Return the number of the read side file descriptor + * WRITE --- Return the number of the write side file descriptor + * RMTHOST --- Return an id which says host type from uname + */ + +/* rmt msg types */ +#define RMTWARN 1 +#define RMTDBG 2 /* includes warning */ + +#define READ(fd) (_rmt_Ctp[fd][0]) +#define WRITE(fd) (_rmt_Ptc[fd][1]) +#define RMTHOST(fd) (_rmt_host[fd]) + +#define RSH_PATH "/usr/bin/rsh" +#define RMT_PATH "/etc/rmt" + +#define UNAME_UNDEFINED -1 +#define UNAME_LINUX 0 +#define UNAME_IRIX 1 +#define UNAME_UNKNOWN 2 + +extern int _rmt_Ctp[MAXUNIT][2]; +extern int _rmt_Ptc[MAXUNIT][2]; +extern int _rmt_host[MAXUNIT]; + +#define setoserror(err) (errno = err) /* TODO: multithread check */ + +/* prototypes */ +int isrmt (int); +void _rmt_abort(int); +int _rmt_command(int, char *); +int _rmt_dev (char *); +int _rmt_status(int); +int _rmt_msgson(void); +void _rmt_msg(int level, const char *msg, ...); +void _rmt_turnonmsgsbyenv(void); +void rmt_turnonmsgs(int code); diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtlseek.c linux-2.4-xfs/cmd/xfsdump/librmt/rmtlseek.c --- linux-2.4.7/cmd/xfsdump/librmt/rmtlseek.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtlseek.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Header: /proj/irix6.5m-melb/isms/eoe/lib/librmt/src/RCS/rmtlseek.c,v 1.5 1995/08/22 03:58:19 doucette Exp $" + +#include +#include "rmtlib.h" + +static off_t _rmt_lseek(int, off_t, int); + +/* + * Perform lseek on file. Looks just like lseek(2) to caller. + */ + +off_t rmtlseek (fildes, offset, whence) +int fildes; +off_t offset; +int whence; +{ + if (isrmt (fildes)) + { + return (_rmt_lseek (fildes - REM_BIAS, offset, whence)); + } + else + { + return (lseek (fildes, offset, whence)); + } +} + + +/* + * _rmt_lseek --- perform an imitation lseek operation remotely + */ + +static off_t _rmt_lseek(int fildes, off_t offset, int whence) +{ + char buffer[BUFMAGIC]; + + sprintf(buffer, "L%ld\n%d\n", (long)offset, whence); + if (_rmt_command(fildes, buffer) == -1) + return(-1); + + return(_rmt_status(fildes)); +} + + diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtmsg.c linux-2.4-xfs/cmd/xfsdump/librmt/rmtmsg.c --- linux-2.4.7/cmd/xfsdump/librmt/rmtmsg.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtmsg.c Thu Jul 5 03:42:14 2001 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "rmtlib.h" + +/* + * Provide functions for warning and debug messages. + */ + +static int rmt_debug_code = 0; + +static void +checkcode(void) +{ + if (rmt_debug_code != RMTWARN && + rmt_debug_code != RMTDBG) { + rmt_debug_code = 0; + } +} + +void +_rmt_turnonmsgsbyenv(void) +{ + char *rmt_debug_str = getenv("RMTDEBUG"); + + if (rmt_debug_str != NULL) { + rmt_debug_code = atoi(rmt_debug_str); + checkcode(); + } +} + +void +rmt_turnonmsgs(int code) +{ + rmt_debug_code = code; + checkcode(); +} + +int +_rmt_msgson(void) +{ + return (rmt_debug_code != 0); +} + +#define RMT_MAX_MSG_STR 256 + +void +_rmt_msg(int level, const char *msg, ...) +{ + static char msg_str[RMT_MAX_MSG_STR]; + va_list arg; + + if (rmt_debug_code >= level) { + va_start(arg, msg); + vsprintf(msg_str, msg, arg); + va_end(arg); + + fprintf(stderr, "%s%s", level==RMTWARN ? "WARNING: ":"", msg_str); + } +} diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtopen.c linux-2.4-xfs/cmd/xfsdump/librmt/rmtopen.c --- linux-2.4.7/cmd/xfsdump/librmt/rmtopen.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtopen.c Thu Jul 5 03:42:14 2001 @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Revision: 1.6 $" + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "rmtlib.h" + +static int _rmt_open(char *, int, int); + +int _rmt_Ctp[MAXUNIT][2] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1} }; +int _rmt_Ptc[MAXUNIT][2] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1} }; +int _rmt_host[MAXUNIT] = { -1, -1, -1, -1}; + +struct uname_table +{ + int id; + char *name; +}; + +struct uname_table uname_table[] = +{ {UNAME_LINUX, "Linux"}, {UNAME_IRIX, "IRIX"}, {0,0} }; + + +/* + * Open a local or remote file. Looks just like open(2) to + * caller. + */ + +int rmtopen (path, oflag, mode) +char *path; +int oflag; +int mode; +{ + if (_rmt_dev (path)) + { + return (_rmt_open (path, oflag, mode) | REM_BIAS); + } + else + { + return (open (path, oflag, mode)); + } +} + +/* + * _rmt_open --- open a magtape device on system specified, as given user + * + * file name has the form system[.user]:/dev/???? + */ + +#define MAXHOSTLEN 257 +#define MAXDBGPATH 100 + +/* ARGSUSED */ +static int _rmt_open (char *path, int oflag, int mode) +{ + int i, rc; + char buffer[BUFMAGIC]; + char system[MAXHOSTLEN]; + char device[BUFMAGIC]; + char login[BUFMAGIC]; + int failed_once = 0; + char *sys, *dev, *user; + char *rsh_path; + char *rmt_path; + char rmt_cmd[MAXDBGPATH]; + + + sys = system; + dev = device; + user = login; + + if ((rsh_path = getenv("RSH")) == NULL) { + rsh_path = RSH_PATH; + } + + if ((rmt_path = getenv("RMT")) == NULL) { + rmt_path = RMT_PATH; + } + + + +/* + * first, find an open pair of file descriptors + */ + + for (i = 0; i < MAXUNIT; i++) + if (READ(i) == -1 && WRITE(i) == -1) + break; + + if (i == MAXUNIT) + { + setoserror( EMFILE ); + return(-1); + } + +/* + * pull apart system and device, and optional user + * don't munge original string + */ + while (*path != '@' && *path != ':') { + *user++ = *path++; + } + *user = '\0'; + path++; + + if (*(path - 1) == '@') + { + while (*path != ':') { + *sys++ = *path++; + } + *sys = '\0'; + path++; + } + else + { + for ( user = login; (*sys = *user); user++, sys++ ) + ; + user = login; + } + + while (*path) { + *dev++ = *path++; + } + *dev = '\0'; + + _rmt_turnonmsgsbyenv(); + + /* try to find out the uname of the remote host */ + { +#define MAX_UNAMECMD MAXHOSTLEN+40 +#define MAX_UNAME 20 + FILE *rmt_f; + char cmd[MAX_UNAMECMD]; + char uname[MAX_UNAME]; + struct uname_table *p; + + if (user != login) { + snprintf(cmd, sizeof(cmd), "rsh -l %s %s uname", login, system); + } + else { + snprintf(cmd, sizeof(cmd), "rsh %s uname", system); + } + + rmt_f = popen(cmd, "r"); + if (rmt_f < 0) { + _rmt_msg(RMTWARN, "rmtopen: failed to detect remote host type using \"%s\"\n", cmd); + RMTHOST(i) = UNAME_UNDEFINED; + goto again; + } + else { + int len; + char *c = fgets(uname, sizeof(uname), rmt_f); + pclose(rmt_f); + + if (c < 0) { + _rmt_msg(RMTWARN, "rmtopen: failed to detect remote host type reading \"%s\"\n", cmd); + RMTHOST(i) = UNAME_UNDEFINED; + goto again; + } + len = strlen(uname); + if (len > 0 && uname[len-1] == '\n') + uname[len-1] = '\0'; /* chomp the '\n' */ + } + + for(p = &uname_table[0]; p->name != 0; p++) { + if (strncmp(p->name, uname, strlen(p->name)) == 0) + break; + } + if (p->name == 0) { + RMTHOST(i) = UNAME_UNKNOWN; + _rmt_msg(RMTWARN, "rmtopen: remote host type, \"%s\", is unknown to librmt\n", uname); + } + else { + RMTHOST(i) = p->id; + _rmt_msg(RMTDBG, "rmtopen: RMTHOST(%d) = %s\n", i, p->name); + } + } + + +/* + * setup the pipes for the 'rsh' command and fork + */ +again: + if (pipe(_rmt_Ptc[i]) == -1 || pipe(_rmt_Ctp[i]) == -1) + return(-1); + + if ((rc = fork()) == -1) + return(-1); + + if (rc == 0) + { + close(0); + dup(_rmt_Ptc[i][0]); + close(_rmt_Ptc[i][0]); close(_rmt_Ptc[i][1]); + close(1); + dup(_rmt_Ctp[i][1]); + close(_rmt_Ctp[i][0]); close(_rmt_Ctp[i][1]); + (void) setuid (getuid ()); + (void) setgid (getgid ()); + if (_rmt_msgson()) { + snprintf(rmt_cmd, sizeof(rmt_cmd), "%s server.%d", + rmt_path, getpid()); + } + else { + strncpy(rmt_cmd, rmt_path, sizeof(rmt_cmd)); + } + if (user != login) + { + execl(rsh_path, "rsh", system, "-l", login, + rmt_cmd, (char *) 0); + } + else + { + execl(rsh_path, "rsh", system, + rmt_cmd, (char *) 0); + } + +/* + * bad problems if we get here + */ + + perror("can't find rsh(1) or rmt(1)"); + exit(1); + } + + close(_rmt_Ptc[i][0]); close(_rmt_Ctp[i][1]); + +/* + * now attempt to open the tape device + */ + + sprintf(buffer, "O%s\n%d\n", device, oflag); + if (_rmt_command(i, buffer) == -1 || _rmt_status(i) == -1) + return(-1); + + /* + * old version of /etc/rmt does not understand 'V' + */ + if (failed_once == 0) { + int rv; + + sprintf(buffer, "V%d\n", LIBRMT_VERSION); + if (_rmt_command(i, buffer) == -1 || (rv=_rmt_status(i)) == -1 ) + { + failed_once++; + close(READ(i)); + close(WRITE(i)); + READ(i) = -1; + WRITE(i) = -1; + if (kill(rc, SIGKILL)) + fprintf(stderr,"remote shell program that invoked /etc/rmt does not exist\n"); + goto again; + } + if ( rv != LIBRMT_VERSION ) { + setoserror( EPROTONOSUPPORT ); + fprintf (stderr, "Remote tape protocol version mismatch (/etc/rmt)\n"); + exit(1); + } + } + + return(i); +} diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtread.c linux-2.4-xfs/cmd/xfsdump/librmt/rmtread.c --- linux-2.4.7/cmd/xfsdump/librmt/rmtread.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtread.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Header: /proj/irix6.5m-melb/isms/eoe/lib/librmt/src/RCS/rmtread.c,v 1.3 1995/03/15 17:56:11 tap Exp $" + +#include + +#include "rmtlib.h" + +static int _rmt_read(int, char *, unsigned int); + +/* + * Read from stream. Looks just like read(2) to caller. + */ + +int rmtread (fildes, buf, nbyte) +int fildes; +char *buf; +unsigned int nbyte; +{ + if (isrmt (fildes)) + { + return (_rmt_read (fildes - REM_BIAS, buf, nbyte)); + } + else + { + return (read (fildes, buf, nbyte)); + } +} + + +/* + * _rmt_read --- read a buffer from a remote tape + */ + +static int _rmt_read(int fildes, char *buf, unsigned int nbyte) +{ + int rc, i; + char buffer[BUFMAGIC]; + + sprintf(buffer, "R%d\n", nbyte); + if (_rmt_command(fildes, buffer) == -1 || (rc = _rmt_status(fildes)) == -1) + return(-1); + + for (i = 0; i < rc; i += nbyte, buf += nbyte) + { + nbyte = read(READ(fildes), buf, rc); + if (nbyte <= 0) + { + _rmt_abort(fildes); + setoserror(EIO); + return(-1); + } + } + + return(rc); +} diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtstatus.c linux-2.4-xfs/cmd/xfsdump/librmt/rmtstatus.c --- linux-2.4.7/cmd/xfsdump/librmt/rmtstatus.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtstatus.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Header: /proj/irix6.5m-melb/isms/eoe/lib/librmt/src/RCS/rmtstatus.c,v 1.2 1995/03/15 17:56:21 tap Exp $" + +#include + +#include "rmtlib.h" + +/* + * _rmt_status --- retrieve the status from the pipe + */ + +int _rmt_status(fildes) +int fildes; +{ + int i; + char c, *cp; + char buffer[BUFMAGIC]; + +/* + * read the reply command line + */ + + for (i = 0, cp = buffer; i < BUFMAGIC; i++, cp++) + { + if (read(READ(fildes), cp, 1) != 1) + { + _rmt_abort(fildes); + setoserror( EIO ); + return(-1); + } + if (*cp == '\n') + { + *cp = 0; + break; + } + } + + if (i == BUFMAGIC) + { + _rmt_abort(fildes); + setoserror( EIO ); + return(-1); + } + +/* + * check the return status + */ + + for (cp = buffer; *cp; cp++) + if (*cp != ' ') + break; + + if (*cp == 'E' || *cp == 'F') + { + setoserror( atoi(cp + 1) ); + while (read(READ(fildes), &c, 1) == 1) + if (c == '\n') + break; + + if (*cp == 'F') + _rmt_abort(fildes); + + return(-1); + } + +/* + * check for mis-synced pipes + */ + + if (*cp != 'A') + { + _rmt_abort(fildes); + setoserror( EIO ); + return(-1); + } + + return(atoi(cp + 1)); +} + + + diff -rNu linux-2.4.7/cmd/xfsdump/librmt/rmtwrite.c linux-2.4-xfs/cmd/xfsdump/librmt/rmtwrite.c --- linux-2.4.7/cmd/xfsdump/librmt/rmtwrite.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/librmt/rmtwrite.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc.; provided copyright in + * certain portions may be held by third parties as indicated herein. + * All Rights Reserved. + * + * The code in this source file represents an aggregation of work from + * Georgia Tech, Fred Fish, Jeff Lee, Arnold Robbins and other Silicon + * Graphics engineers over the period 1985-2000. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Header: /proj/irix6.5m-melb/isms/eoe/lib/librmt/src/RCS/rmtwrite.c,v 1.3 1995/03/15 17:56:34 tap Exp $" + +#include +#include + +#include "rmtlib.h" + +static int _rmt_write(int, char *, unsigned int); + +/* + * Write to stream. Looks just like write(2) to caller. + */ + +int rmtwrite (fildes, buf, nbyte) +int fildes; +char *buf; +unsigned int nbyte; +{ + if (isrmt (fildes)) + { + return (_rmt_write (fildes - REM_BIAS, buf, nbyte)); + } + else + { + return (write (fildes, buf, nbyte)); + } +} + + +/* + * _rmt_write --- write a buffer to the remote tape + */ + +static int _rmt_write(int fildes, char *buf, unsigned int nbyte) +{ + char buffer[BUFMAGIC]; + void (*pstat)(); + + sprintf(buffer, "W%d\n", nbyte); + if (_rmt_command(fildes, buffer) == -1) + return(-1); + + pstat = signal(SIGPIPE, SIG_IGN); + if (write(WRITE(fildes), buf, nbyte) == nbyte) + { + signal (SIGPIPE, pstat); + return(_rmt_status(fildes)); + } + + signal (SIGPIPE, pstat); + _rmt_abort(fildes); + setoserror( EIO ); + return(-1); +} diff -rNu linux-2.4.7/cmd/xfsdump/man/CVS/Entries linux-2.4-xfs/cmd/xfsdump/man/CVS/Entries --- linux-2.4.7/cmd/xfsdump/man/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/CVS/Entries Thu Jul 5 11:44:07 2001 @@ -0,0 +1,2 @@ +/Makefile/1.1/Mon Jan 15 04:35:39 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/man/CVS/Entries.Log linux-2.4-xfs/cmd/xfsdump/man/CVS/Entries.Log --- linux-2.4.7/cmd/xfsdump/man/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/CVS/Entries.Log Thu Jul 5 11:44:07 2001 @@ -0,0 +1 @@ +A D/man8//// diff -rNu linux-2.4.7/cmd/xfsdump/man/CVS/Repository linux-2.4-xfs/cmd/xfsdump/man/CVS/Repository --- linux-2.4.7/cmd/xfsdump/man/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/CVS/Repository Thu Jul 5 11:44:07 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/man diff -rNu linux-2.4.7/cmd/xfsdump/man/CVS/Root linux-2.4-xfs/cmd/xfsdump/man/CVS/Root --- linux-2.4.7/cmd/xfsdump/man/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/CVS/Root Thu Jul 5 11:44:07 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/man/Makefile linux-2.4-xfs/cmd/xfsdump/man/Makefile --- linux-2.4.7/cmd/xfsdump/man/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/Makefile Sun Jan 14 22:35:39 2001 @@ -0,0 +1,41 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +SUBDIRS = man8 + +default install install-dev : $(SUBDIRS) + $(SUBDIRS_MAKERULE) + +include $(BUILDRULES) diff -rNu linux-2.4.7/cmd/xfsdump/man/man8/CVS/Entries linux-2.4-xfs/cmd/xfsdump/man/man8/CVS/Entries --- linux-2.4.7/cmd/xfsdump/man/man8/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/man8/CVS/Entries Thu Jul 5 11:44:09 2001 @@ -0,0 +1,9 @@ +/Makefile/1.1/Mon Jan 15 04:35:39 2001/-ko/ +/xfs_copy.8/1.1/Mon Jan 15 04:35:39 2001/-ko/ +/xfs_estimate.8/1.1/Mon Jan 15 04:35:39 2001/-ko/ +/xfs_fsr.8/1.2/Thu May 3 21:19:45 2001/-ko/ +/xfsdq.8/1.2/Thu Mar 22 02:50:27 2001/-ko/ +/xfsdump.8/1.4/Tue Jun 12 04:22:25 2001/-ko/ +/xfsinvutil.8/1.1/Mon Jan 15 04:35:39 2001/-ko/ +/xfsrestore.8/1.2/Tue Jun 12 04:22:25 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/man/man8/CVS/Repository linux-2.4-xfs/cmd/xfsdump/man/man8/CVS/Repository --- linux-2.4.7/cmd/xfsdump/man/man8/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/man8/CVS/Repository Thu Jul 5 11:44:07 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/man/man8 diff -rNu linux-2.4.7/cmd/xfsdump/man/man8/CVS/Root linux-2.4-xfs/cmd/xfsdump/man/man8/CVS/Root --- linux-2.4.7/cmd/xfsdump/man/man8/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/man8/CVS/Root Thu Jul 5 11:44:07 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/man/man8/Makefile linux-2.4-xfs/cmd/xfsdump/man/man8/Makefile --- linux-2.4.7/cmd/xfsdump/man/man8/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/man8/Makefile Sun Jan 14 22:35:39 2001 @@ -0,0 +1,50 @@ +#! gmake +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +MAN_SECTION = 8 + +MAN_PAGES = $(shell echo *.$(MAN_SECTION)) +MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) +LSRCFILES = $(MAN_PAGES) + +default : $(MAN_PAGES) + +include $(BUILDRULES) + +install : default + $(INSTALL) -m 755 -d $(MAN_DEST) + $(INSTALL_MAN) +install-dev: diff -rNu linux-2.4.7/cmd/xfsdump/man/man8/xfs_copy.8 linux-2.4-xfs/cmd/xfsdump/man/man8/xfs_copy.8 --- linux-2.4.7/cmd/xfsdump/man/man8/xfs_copy.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/man8/xfs_copy.8 Sun Jan 14 22:35:39 2001 @@ -0,0 +1,174 @@ +.TH xfs_copy 8 +.SH NAME +xfs_copy \- copy the contents of an XFS filesystem +.SH SYNOPSIS +.nf +\f3xfs_copy\f1 [ \f3\-d\f1 ] device|file device1 [ device2 device3 ... ] +\f3xfs_copy\f1 [ \f3\-d\f1 ] device|file file1 +.fi +.SH DESCRIPTION +.I xfs_copy +copies an XFS filesystem to one or more targets in parallel +(see +.IR xfs (8)). +The +first (source) +argument must be the pathname of the device or file +containing the XFS filesystem. +The remaining arguments specify one or more target devices +or a filename. +If the pathnames specify devices, a copy of the source +XFS filesystem is created on each device. +If any of the source or target device names specify devices +that are not raw devices, +.I xfs_copy +attempts to locate the raw device corresponding to the +specified device and use the raw device instead. +.PP +If there is only one target, that target can be the name of a +regular file in which case an image of the source XFS filesystem is +created in that file. +If the file does not exist, +.I xfs_copy +creates the file. +The length of the resulting file is equal to the size +of the source filesystem. +However, if the file is created on an XFS filesystem, +the file consumes roughly the amount of space actually +used in the source filesystem by the filesystem and the XFS log. +The space saving is because +.I xfs_copy +seeks over free blocks instead of copying them +and the XFS filesystem supports sparse files efficiently. +.PP +.I xfs_copy +can only be used to copy unmounted filesystems. +Otherwise, the generated filesystem(s) would be inconsistent +or corrupt. Some versions of +.I xfs_copy +may print a message that they have detected a mounted filesystem, +but are continuing the attempt to copy, and then issue a message +that they are aborting. This is misleading, but not incorrect. +Unmount the filesystem and then issue the command. This means +that if you want to copy the root (/) filesystem, you must first +load the miniroot, then unmount the root with the +.I inst +command +.Ex +admin umount /root +.Ee +and then do the copy. +.PP +.I xfs_copy +does not alter the source filesystem in any way. +Each new (target) filesystem is identical to the original +filesystem except that new filesystems each have a new unique +filesystem identifier (UUID). +Therefore, +if both the old and new filesystems will be used as +separate distinct filesystems, +.I xfs_copy +or +.IR xfsdump / xfsrestore +should be used to generate the new filesystem(s) instead of +.IR dd (1) +or other programs that do block-by-block disk copying. +.PP +The +.B \-d +(duplicate) option can be used if a true clone is +desired. +This should be done only if the new filesystem +will be used as a replacement for the original +filesystem (such as in the case of disk replacement). +.PP +.I xfs_copy +uses synchronous writes to ensure that write errors are +detected. +.I xfs_copy +also uses +\f2sproc\f1s (see \f2sproc\f1(2)) +to perform simultaneous parallel writes. +Therefore, +.IR ps (1) +reports multiple copies of +.I xfs_copy +while the copy is in progress. +.I xfs_copy +creates one additional \f2sproc\f1 for each target to be written. +All \f2sproc\f1s die if +.I xfs_copy +terminates or aborts. +.PP +.I xfs_copy +does not copy XFS filesystems that have a real-time section +or XFS filesystems with external logs. +In both cases, +.I xfs_copy +aborts with an error message. +.SH DIAGNOSTICS +.I xfs_copy +reports errors to both stderr and +in more detailed form to a generated +log file whose name is of the form +.I /usr/tmp/xfs_copy.log.??????. +If +.I xfs_copy +detects a write error on a target, +the copy of that one target is aborted and an error +message is issued to both stderr and the logfile, but +the rest of the copies continue. +When +.I xfs_copy +terminates, all aborted targets are reported to both stderr and +the logfile. +In some cases, +.I xfs_copy +may report the message +.Ex +xfs_copy: couldn't initialize simulation library +.Ee +following another error message. This message is sometimes of use when +debugging problems, and should normally be ignored. +.PP +If all targets abort or if there is an error reading the source filesystem, +.I xfs_copy +immediately aborts. +.PP +.I xfs_copy +returns an exit code of 0 if all targets are successfully +copied and an exit code of 1 if any target fails. +.SH BUGS +When moving filesystems from one disk to another, +if the original filesystem is less than 4 Gbytes long +and the new filesystem will larger, we +recommend that +.I +mkfs +and +.I xfsdump/xfsrestore +be used instead of using +.I xfs_copy +and +.I xfs_growfs. +The filesystem layout resulting from using +.I xfs_copy/xfs_growfs +is almost always worse than the result of using +.I mkfs/xfsdump/xfsrestore +but in the case of small filesystems, the +differences can have a significant performance +impact. +.PP +.I xfs_copy +does not copy XFS filesystems with real-time partitions +or external logs. +.PP +If the source filesystem is bigger than the target partition, +the copy may succeed if the blocks at the end of the +source filesystem are not in use but the generated copy will +not be a valid filesystem. +.SH SEE ALSO +mkfs.xfs(8), +xfsdump(8), +xfsrestore(8), +xfs(5). diff -rNu linux-2.4.7/cmd/xfsdump/man/man8/xfs_estimate.8 linux-2.4-xfs/cmd/xfsdump/man/man8/xfs_estimate.8 --- linux-2.4.7/cmd/xfsdump/man/man8/xfs_estimate.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/man8/xfs_estimate.8 Sun Jan 14 22:35:39 2001 @@ -0,0 +1,98 @@ +.TH xfs_estimate 8 +.SH NAME +xfs_estimate \- estimate the space that an XFS filesystem will take +.SH SYNOPSIS +.nf +\f3xfs_estimate\f1 [ \f3\-h?\f1 ] [ \f3\-b\f1 blocksize ] \c +[ \f3\-i\f1 logsize ] [ \f3\-e\f1 logsize ] [ \f3\-v\f1 ] \c +directory ... +.fi +.SH DESCRIPTION +For each \f2directory\f1 argument, +.I xfs_estimate +estimates the space that directory would take if it were copied to an XFS +filesystem. +.I xfs_estimate +does not cross mount points. +The following definitions +are used: +.PD 0 +.IP +KB = *1024 +.IP +MB = *1024*1024 +.IP +GB = *1024*1024*1024 +.PD +.PP +The +.I xfs_estimate +options are: +.TP +\f3\-b\f1 \f2blocksize\f1 +Use +.I blocksize +instead of the default blocksize of 4096 bytes. +The modifier +.B k +can be used +after the number to indicate multiplication by 1024. +For example, +.sp .8v +.RS + \f4xfs_estimate -b 64k /\f1 +.RE +.IP +requests an estimate of the space required by the directory / on an +XFS filesystem using a blocksize of 64K (65536) bytes. +.TP +.B \-v +Display more information, formatted. +.TP +.B \-h +Display usage message. +.TP +.B \-? +Display usage message. +.TP +\f3\-i, \-e\f1 \f2logsize\f1 +Use +.I logsize +instead of the default log size of 10 MB. +.B \-i +refers to an internal log, while +.B \-e +refers to an external log. +The modifiers +.B k +or +.B m +can be used +after the number to indicate multiplication by 1024 or 1048576, respectively. +.IP +For example, +.sp .8v +.RS + \f4xfs_estimate -i 1m /\f1 +.RE +.IP +requests an estimate of the space required by the directory / on an +XFS filesystem using an internal log of 1 megabyte. +.SH EXAMPLES +.Ex +% \f4xfs_estimate -e 10m /var/tmp\f1\f7 +/var/tmp will take about 4.2 megabytes + with the external log using 2560 blocks or about 10.0 megabytes +.sp .8v +.ne 3 +% \f4xfs_estimate -v -e 10m /var/tmp\f1\f7 +directory bsize blocks megabytes logsize +/var/tmp 4096 792 4.0MB 10485760 +.sp .8v +% \f4xfs_estimate -v /var/tmp\f1\f7 +directory bsize blocks megabytes logsize +/var/tmp 4096 3352 14.0MB 10485760 +.sp .8v +% \f4xfs_estimate /var/tmp\f1\f7 +/var/tmp will take about 14.0 megabytes +.Ee diff -rNu linux-2.4.7/cmd/xfsdump/man/man8/xfs_fsr.8 linux-2.4-xfs/cmd/xfsdump/man/man8/xfs_fsr.8 --- linux-2.4.7/cmd/xfsdump/man/man8/xfs_fsr.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/man8/xfs_fsr.8 Thu May 3 16:19:45 2001 @@ -0,0 +1,172 @@ +.TH xfs_fsr 8 +.SH NAME +xfs_fsr \- filesystem reorganizer for XFS +.SH SYNOPSIS +.nf +\f3xfs_fsr\f1 [\f3\-v\f1] \c +[\f3\-t\f1 seconds] [\f3\-f\f1 leftoff] [\f3\-m\f1 mtab] +\f3xfs_fsr\f1 [\f3\-v\f1] \c +[xfsdev | file] ... +.fi +.SH DESCRIPTION +.I xfs_fsr +is applicable only to XFS filesystems. +.PP +.I xfs_fsr +improves the organization of mounted filesystems. +The reorganization algorithm operates on one file at a time, +compacting or otherwise improving the layout of +the file extents (contiguous blocks of file data). +.PP +The following options are accepted by +.IR xfs_fsr . +The +.BR \-m , +.BR \-t , +and +.B \-f +options have no meaning if any filesystems +or files are specified on the command line. +.TP 13 +.BI \-m " mtab" +Use this file for the list of filesystems to reorganize. +The default is to use +.IR /etc/mtab . +.TP +.BI \-t " seconds" +How long to reorganize. +The default is 7200 (2 hours). +.TP +.BI \-f " leftoff" +Use this file instead of +.I /var/tmp/.fsrlast +to read the state of where to start and as the file +to store the state of where reorganization left off. +.TP +.B \-v +Verbose. +Print cryptic information about +each file being reorganized. +.PP +The intended usage is to regularly run the +.I fsr +command which in turn invokes +.I xfs_fsr +when it encounters XFS filesystems. +By default this is done from +.I crontab +once per week. +.PP +When invoked with no arguments +.I xfs_fsr +reorganizes all regular files in all mounted filesystems. +.I xfs_fsr +makes many cycles over +.I /etc/mtab +each time making a single pass over each XFS filesystem. +Each pass goes through and selects files +that have the largest number of extents. It attempts +to defragment the top 10% of these files on each pass. +.PP +It runs for up to two hours after which it records the filesystem +where it left off, so it can start there the next time. +This information is stored in the file +.I /var/tmp/.fsrlast_xfs. +If the information found here +is somehow inconsistent or out of date +it is ignored +and reorganization starts at the beginning of the first +filesystem found in +.IR /etc/mtab . +.PP +.I xfs_fsr +can be called with one or more arguments +naming filesystems (block device name), +and files to reorganize. +In this mode +.I xfs_fsr +does not read or write +.I /var/tmp/.fsrlast_xfs +nor does it run for a fixed time interval. +It makes one pass through each specified regular file and +all regular files in each specified filesystem. +A command line name referring to a symbolic link +(except to a file system device), +FIFO, or UNIX domain socket +generates a warning message, but is otherwise ignored. +While traversing the filesystem these types +of files are silently skipped. +.SH FILES +.PD 0 +.TP 21 +/etc/mtab +contains default list of filesystems to reorganize. +.TP 21 +/var/tmp/.fsrlast_xfs +records the state where reorganization left off. +.PD +.SH "SEE ALSO" +xfs_fsr(8), +mkfs.xfs(8), +xfs_ncheck(8), +xfs(5). +.SH "NOTES" +.I xfs_fsr +improves the layout of extents for each file by copying the entire +file to a temporary location and then interchanging the data extents +of the target and temporary files in an atomic manner. +This method requires that enough free disk space be available to copy +any given file and that the space be less fragmented then the original +file. +It also requires the owner of the file to have enough remaining +filespace quota to do the copy on systems running quotas. +.I xfs_fsr +generates a warning message if space is not sufficient to improve +the target file. +.PP +A temporary file used in improving a file given on the command line +is created in the same parent directory of the target file and +is prefixed by the string '\f3.fsr\f1'. +The temporary files used in improving an entire XFS device are stored +in a directory at the root of the target device and use the same +naming scheme. +The temporary files are unlinked upon creation so data will not be +readable by any other process. +.PP +.I xfs_fsr +does not operate on files that are currently mapped in memory. +A 'file busy' error can be seen for these files if the verbose +flag (\f3-v\f1) is set. +.PP +An entry in +.I /etc/mtab +or the file specified using the +.B \-m +option must have the +.B rw +option specified for read and write access. +If this option is not present, then +.I xfs_fsr +skips the +filesystem described by that line. +See the +.IR fstab (5) +reference page for +more details. +.PP +In general we do not foresee the need to run +.I xfs_fsr +on system partitions such as +.IR / , +.I /boot +and +.I /usr +as in general these will not suffer from fragmentation. +There are also issues with defragmenting files +.IR lilo (8) +uses to boot your system. +Should these files be moved by +.I xfs_fsr +then you must rerun +.I lilo +before you reboot or you may have an unbootable system. diff -rNu linux-2.4.7/cmd/xfsdump/man/man8/xfsdq.8 linux-2.4-xfs/cmd/xfsdump/man/man8/xfsdq.8 --- linux-2.4.7/cmd/xfsdump/man/man8/xfsdq.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/man8/xfsdq.8 Wed Mar 21 20:50:27 2001 @@ -0,0 +1,116 @@ +.TH xfsdq 8 +.SH NAME +xfsdq, xfsrq \- XFS dump and restore quota +.SH SYNOPSIS +.nf +\f3xfsdq\f1 [ \f3\-g\f1|\f3-u\f1 ] filesystem +\f3xfsrq\f1 [ \f3\-g\f1|\f3-u\f1 ] xfsdump_quotas +.fi +.SH DESCRIPTION +.B xfsdq +outputs a summary of the disk quotas for the specified XFS filesystem +for either all users declared in the local +.I /etc/passwd +file, or all groups declared in the local +.I /etc/group +file. +.PP +The output format exactly matches that produced by the IRIX +.I repquota +command, given the +.B \-e +option. +The format contains two lines for each user/group - the +first line contains the filesystem device file, the second +contains the uid/gid, block soft limit, block hard limit, +inode soft limit, and finally the inode hard limit (in that +order). +.PP +.B xfsdump +runs +.B xfsdq +on those filesystems with quota enabled, and redirects the +output (from standard output stream) to a file which is +subsequently stored on the dump device. +For user quota, this file is named +.IR xfsdump_quotas , +for group quota it is named +.IR xfsdump_quotas_group . +Thus, +the primary purpose of +.B xfsdq +is to maintain this dump file format between IRIX and Linux, +such that +.B xfsdump +backups remain interchangable. +.PP +.B xfsrq +is a simple wrapper around +.BR setquota (8) +which automates the restoration of quota information +using this +.I xfsdump_quotas +file. +.PP +The +.B \-u +(user) option specifies user quota should be reported. +This is the default. +.PP +The +.B \-g +(group) option specifies that group quota are to be reported. +.PP +The +.I filesystem +argument should be the filesystem mount point, and not the device. +.SH RESTORE +In order to restore quota information using the output from +.BR xfsdq , +one must first restore a copy of the +.I xfsdump_quotas +file from the dump device. +.PP +On Linux, user quota can then be restored using: +.PP +.nf + # xfsrq -u xfsdump_quotas +.fi +.PP +On IRIX, the equivalent command is: +.PP +.nf + # edquota -i xfsdump_quotas +.fi +.SH NOTES +Only user quota are supported by both Linux and IRIX. +Group quota are not supported on IRIX and project quota +are not supported on Linux. +.PP +The soft and hard block limits reported by +.B xfsdq +are in units of 512 bytes for compatibility with IRIX. +The Linux quota utilities, e.g. +.BR quota (1) +and +.BR repquota (8), +report blocks in units of 1024 bytes - +.B xfsrq +performs the necessary conversions automatically. +.SH FILES +.PD 0 +.TP 20 +.B /etc/mtab +default filesystems +.TP +.B /etc/passwd +default set of users +.TP +.B /etc/passwd +default set of groups +.SH SEE ALSO +quota(1), +repquota(8), +setquota(8), +xfsdump(8), +xfs(5). diff -rNu linux-2.4.7/cmd/xfsdump/man/man8/xfsdump.8 linux-2.4-xfs/cmd/xfsdump/man/man8/xfsdump.8 --- linux-2.4.7/cmd/xfsdump/man/man8/xfsdump.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/man8/xfsdump.8 Mon Jun 11 23:22:25 2001 @@ -0,0 +1,580 @@ +.TH xfsdump 8 +.SH NAME +xfsdump \- \&XFS filesystem incremental dump utility +.SH SYNOPSIS +.nf +\f3xfsdump\f1 \c +[ \f3-a\f1 ] \c +[ \f3\-b\f1 blocksize ] + [ \f3\-c\f1 media_change_alert_program ] \c +[ \f3\-f\f1 destination ... ] + [ \f3\-l\f1 level ] \c +[ \f3\-m\f1 force usage of minimal tape strategy ] + [ \f3\-o\f1 overwrite tape ] \c +[ \f3\-p\f1 report_interval ] + [ \f3\-s\f1 pathname ... ] \c +[ \f3\-v\f1 verbosity ] \c +[ \f3\-A\f1 ] + [ \f3\-B\f1 base_id ] \c +[ \f3\-E\f1 ] \c +[ \f3\-F\f1 ] \c +[ \f3\-I\f1 [ subopt=value ... ] ] + [ \f3\-J\f1 ] \c +[ \f3\-L\f1 session_label ] \c +[ \f3\-M\f1 media_label ... ] + [ \f3\-O\f1 options_file ] \c +[ \f3\-R\f1 ] \c +[ \f3\-T\f1 ] \c +[ \f3\-Y\f1 io_ring_length ] + [ \f3\-\f1 ] \c +filesystem +.fi +.SH DESCRIPTION +.I xfsdump +backs up files and their attributes in a filesystem. +The files are dumped to +storage media, +a regular file, +or standard output. +Options allow the operator to have all files dumped, +just files that have changed since a previous dump, +or just files contained in a list of pathnames. +.P +The +.IR xfsrestore (8) +utility re-populates a filesystem with the contents of the dump. +.P +Each invocation of +.I xfsdump +dumps just one filesystem. +That invocation is termed a dump session. +The dump session splits the filesystem into one or more +dump streams, +one per destination. +The split is done in filesystem inode number (ino) order, +at boundaries selected to equalize the size of each stream. +Furthermore, the breakpoints between streams may be in the +middle of very large files (at extent boundaries) if necessary +to achieve reasonable stream size equalization. +Each dump stream can span several media objects, +and a single media object can contain several dump streams. +The typical media object is a tape cartridge. +The media object records the dump stream as one or more media files. +A media file is a self-contained partial dump. +The portion of a dump stream contained on a media object can +be split into several media files. +This minimizes the impact of media +dropouts on the entire dump stream, +and speeds subtree restores. +.P +However, the current implementation in Linux only supports one destination +and running single threaded. Therefore, the above comments +regarding multiple streams describe the possible future capabilities. +.P +.I xfsdump +maintains an online dump inventory in \f2/var/xfsdump/inventory\f1. +The +.B \-I +option displays the inventory contents hierarchically. +The levels of the hierarchy are: +filesystem, +dump session, +stream, and +media file. +.P +.TP 5 +.B \-a +Specifies that files for which the Data Migration +Facility (DMF) has complete offline copies +be dumped as DMF state offline (OFL). +This means that the file data will not be dumped by +xfsdump, resulting in a smaller dump file. +If the file is later restored the file data is still accessible through DMF. +However, the current implementation in Linux does not yet support the +\f3\-a\f1 option. +.TP 5 +\f3\-b\f1 \f2blocksize\f1 +Specifies the blocksize, in bytes, to be used for the dump. +The same blocksize must be specified to restore the tape. +If the \f3\-m\f1 option is not used, then \f3\-b\f1 does not need +to be specified. Instead, a default blocksize of 1Mb will be used. +.TP 5 +\f3\-c\f1 \f2media_change_alert_program\f1 +Use the specified program to alert the operator when a media change is +required. The alert program is typically a script to send a mail or +flash a window to draw the operator's attention. +.TP 5 +\f3\-d\f1 \f2filesize\f1 +Specifies the size, in megabytes, of dump media files. xfsdump will +dump data to tape in one or more media files. It will attempt to +estimate the ideal media file size based on the tape device being +used, and the amount of data to be written. The media file size may +need to be adjusted if, for example, xfsdump cannot fit a media file +onto a single tape. +.TP 5 +\f3\-f\f1 \f2destination\f1 +Specifies a dump destination. +A dump destination can be the pathname of a device (such as a tape drive), +a regular file or a remote tape drive (see \f2rmt\f1(8)). +This option must be omitted if the standard output option +(a lone +.B \- +preceding the source filesystem specification) +is specified. +.TP 5 +\f3\-l\f1 \f2level\f1 +Specifies a dump level of 0 to 9. +The dump level determines the base dump to which this +dump is relative. +The base dump is the most recent dump at a lesser level. +A level 0 dump is absolute \- all files are dumped. +A dump level where 1 <= \f2level\f1 <= 9 is referred to as an incremental dump. +Only files that have been changed since the base dump are dumped. +Subtree dumps +(see the +.B \-s +option below) +cannot be used as the +base for incremental dumps. +.TP 5 +.B \-m +Use the minimal tape protocol for non-scsi tape destinations or +remote tape destinations which are not scsi Linux tape drives +nor IRIX tape drives. +This option cannot be used without specifying a blocksize to be used (see +.B \-b +option above). +.TP 5 +.B \-o +Overwrite the tape. With this option, +.I xfsdump +does not read the tape first to check the contents. This option may +be used if +.I xfsdump +is unable to determine the block size of a tape . +.TP 5 +\f3\-p\f1 \f2interval\f1 +Causes progress reports to be printed at the specified interval. +.I +interval is given in seconds. +The progress report indicates +how many files have been dumped, +the total number of files to dump, +the percentage of data dumped, +and +the elapsed time. +.TP 5 +\f3\-s\f1 \f2pathname\f1 ... +Restricts the dump to files contained in the specified pathnames +(subtrees). +Up to 100 pathnames can be specified. +A \f2pathname\f1 must be relative to the mount point of the filesystem. +For example, if a filesystem is mounted at \f2/d2\f1, the \f2pathname\f1 +argument for the directory \f2/d2/users\f1 is ``users''. +A \f2pathname\f1 can be a file or a directory; if it is a directory, +the entire hierarchy of files and subdirectories rooted at that directory +is dumped. +Subtree dumps cannot be used as the base for incremental dumps +(see the +.B \-l +option above). +.TP 5 +\f3\-v\f1 \f2verbosity_level\f1 +Specifies the level of detail of the messages displayed during the course +of the dump. +The argument can be \f3silent\f1, \f3verbose\f1, or \f3trace\f1. +The default is \f3verbose\f1. +.TP 5 +.B \-A +Do not dump extended file attributes. +Unless this option is specified, +extended file attributes are dumped. +Note that dumps containing extended file attributes +cannot be restored with older versions of \f2xfsrestore\f1(8). +.TP 5 +\f3\-B\f1 \f2base_id\f1 +Specifies the ID +of the dump session upon which this dump session is to be based. +If this option is specified, the +.B \-l +(level) +and +.B \-R +(resume) options +are not allowed. +Instead, +.B xfsdump +determines if the current dump session should be incremental +and/or resumed, +by looking at the base session's level and interrupted attributes. +If the base session was interrupted, +the current dump session is a resumption of that base at the same level. +Otherwise, the current dump session is an incremental dump with a level +one greater than that of the base session. +This option allows incremental +and resumed dumps to be based on any previous dump, +rather than just the most recent. +.TP 5 +.B \-E +Pre-erase media. +If this option is specified, media is erased prior to use. +The operator is prompted for confirmation, +unless the +.B \-F +option is also specified. +.TP 5 +.B \-F +Don't prompt the operator. +When +.I xfsdump +encounters a media object containing non-xfsdump data, +.I xfsdump +normally asks the operator for permission to overwrite. +With this option the overwrite is performed, no questions asked. +When +.I xfsdump +encounters end-of-media during a dump, +.I xfsdump +normally asks the operator if another media object will be provided. +With this option the dump is instead interrupted. +.TP 5 +.B \-I +Displays the \f2xfsdump\f1 inventory +(no dump is performed). +.I xfsdump +records each dump session in an online inventory +in \f2/var/xfsdump/inventory\f1. +.I xfsdump +uses this inventory to determine the base for incremental dumps. +It is also useful for manually identifying a dump session to be restored. +Suboptions to filter the inventory display are described later. +.TP 5 +.B \-J +Inhibits the normal update of the inventory. +This is useful when the media being dumped to +will be discarded or overwritten. +.TP 5 +\f3\-L\f1 \f2session_label\f1 +Specifies a label +for the dump session. +It can be any arbitrary string up to 255 characters long. +.TP 5 +\f3\-M\f1 \f2media_label\f1 +Specifies a label +for the first media object (for example, tape cartridge) +written on the corresponding destination during the session. +It can be any arbitrary string up to 255 characters long. +Multiple media object labels can be specified, +one for each destination. +.TP 5 +\f3\-O\f1 \f2options_file\f1 +Insert the options contained in \f2options_file\f1 +into the beginning of the command line. +The options are specified just as they would appear if typed into the +command line. +In addition, newline characters (\\n) can be used as whitespace. +The options are placed before all options actually given +on the command line, +just after the command name. +Only one \f3\-O\f1 option can be used. +Recursive use is ignored. +The source filesystem cannot be specified in \f2options_file\f1. +.TP 5 +.B \-R +Resumes a previously interrupted dump session. +If the most recent dump at this dump's level (\f3\-l\f1 option) +was interrupted, +this dump contains only files not in the interrupted dump +and consistent with the incremental level. +However, +files contained in the interrupted dump that have been subsequently +modified are re-dumped. +.TP 5 +.B \-T +Inhibits interactive dialogue timeouts. +When the +.B \-F +option is not specified, +.I xfsdump +prompts the operator for labels and media changes. +Each dialogue normally times out if no response is supplied. +This option prevents the timeout. +.TP 5 +\f3\-Y\f1 \f2io_ring_length\f1 +Specify I/O buffer ring length. +.I xfsdump +uses a ring of output buffers to achieve maximum throughput +when dumping to tape drives. +The default ring length is 3. +However, this is only supported when running multi-threaded +which has not been done for Linux yet - making this option benign. +.TP 5 +.B \- +A lone +.B \- +causes the dump stream to be sent to +the standard output, +where it can be piped to another utility such as \f2xfsrestore\f1(8) +or redirected to a file. +This option cannot be used with the +.B \-f +option. +The +.B \- +must follow all other options and precede the filesystem specification. +.P +The filesystem, \f2filesystem\f1, can be specified either as a mount point or as +a special device file (for example, \f2/dev/dsk/dks0d1s0\f1). +The filesystem must be mounted to be dumped. +.SH NOTES +.SS Dump Interruption +A dump can be interrupted at any time and later resumed. +To interrupt, type control-C +(or the current terminal interrupt character). +The operator is prompted to select one of several operations, +including dump interruption. +After the operator selects dump interruption, +the dump continues until a convenient break point is +encountered (typically the end of the current file). +Very large files are broken into smaller subfiles, +so the wait for the end of the current file is brief. +.SS Dump Resumption +A previously interrupted dump can be resumed +by specifying the +.B \-R +option. +If the most recent dump at the specified level was interrupted, +the new dump does not include files already dumped, +unless they have changed since the interrupted dump. +.SS Media Management +A single media object can contain many dump streams. +Conversely, a single dump stream can span multiple media objects. +If a dump stream is sent to a media object already containing one or more dumps, +.I xfsdump +appends the new dump stream after the last dump stream. +Media files are never overwritten. +If end-of-media is encountered during the course of a dump, +the operator is prompted to insert a new media object +into the drive. +The dump stream continuation is appended after the last media file +on the new media object. +.SS Inventory +Each dump session updates an inventory database in \f2/var/xfsdump/inventory\f1. +.I xfsdump +uses the inventory to determine the base of incremental +and resumed dumps. +.P +This database can be displayed by invoking +.I xfsdump +with the +.B \-I +option. +The display uses tabbed indentation to present the inventory +hierarchically. +The first level is filesystem. +The second level is session. +The third level is media stream (currently only one stream is supported). +The fourth level lists the media files sequentially composing the stream. +.P +The following suboptions are available to filter the display. +.TP5 +\f3\-I depth=\f1\f2n\f1 +(where +.I n +is 1, 2, or 3) limits the hierarchical depth of the display. When +.I n +is 1, only the filesystem information from the inventory is displayed. When +.I n +is 2, only filesystem and session information are displayed. When +.I n +is 3, only filesystem, session and stream information are displayed. +.TP5 +\f3\-I level=\f1\f2n\f1 +(where +.I n +is the dump level) limits the display to dumps of that particular dump level. +.P +The display may be restricted to media files contained in a specific +media object. +.TP5 +\f3\-I mobjid=\f1\f2value\f1 +(where +.I value +is a media ID) specifies the media object by its media ID. +.TP5 +\f3\-I mobjlabel=\f1\f2value\f1 +(where +.I value +is a media label) specifies the media object by its media label. +.P +Similarly, the display can be restricted to a specific filesystem. +.TP5 +\f3\-I mnt=\f1\f2host-qualified_mount_point_pathname\f1 +(that is, hostname:pathname), identifies the filesystem by mountpoint. +.TP5 +\f3\-I fsid=\f1\f2filesystem_id\f1 +identifies the filesystem by filesystem ID. +.TP5 +\f3\-I dev=\f1\f2host-qualified_device_pathname\f1 +(that is, hostname:device_pathname) identifies the filesystem by device. +.P +More than one of these suboptions, separated by commas, may be specified +at the same time to limit the display of the inventory to +those dumps of interest. +However, at most four suboptions can be specified at once: +one to constrain the display hierarchy depth, +one to constrain the dump level, +one to constrain the media object, +and one to constrain the filesystem. +.P +For example, +.B \-I depth=1,mobjlabel="tape 1",mnt=host1:/test_mnt +would display only the filesystem information (depth=1) for +those filesystems that were mounted on \f2host1:/test_mnt\f1 +at the time of the dump, +and only those filesystems dumped to the media object labeled "tape 1". +.P +Dump records may be removed (pruned) from the inventory using the +.I xfsinvutil +program. +.P +An additional media file is placed +at the end of each dump stream. +This media file contains the inventory information for the +current dump session. +This is currently unused. +.P +When operating in the miniroot environment, +.I xfsdump +does not create and does not reference the inventory database. +Thus incremental and resumed dumps are not allowed. +.SS Labels +The operator can specify a label to identify the dump +session +and a label to identify a media object. +The session label is placed in every media file produced +in the course of the dump, +and is recorded in the inventory. +.P +The media label is used to identify media objects, +and is independent of the session label. +Each media file on the media object contains a copy of the +media label. +An error is returned if the operator specifies a +media label that does not match the media label on a +media object containing valid media files. +Media labels are recorded in the inventory. +.SS UUIDs +UUIDs (Universally Unique Identifiers) are used in three places: +to identify the filesystem being dumped (using the filesystem UUID, +see +.IR xfs (5) +for more details), +to identify the dump session, +and to identify each media object. +The inventory display (\f3\-I\f1) includes all of these. +.SS Dump Level Usage +The dump level mechanism provides a structured form of incremental +dumps. +A dump of level \f2level\f1 includes only files that have changed since +the most recent dump at a level less than \f2level\f1. +For example, the operator can establish a dump schedule that involves +a full dump every Friday +and a daily incremental dump containing only files that +have changed since the previous dump. +In this case Friday's dump would be at level 0, +Saturday's at level 1, +Sunday's at level 2, +and so on, +up to the Thursday dump at level 6. +.P +The above schedule results in a very tedious restore procedure to +fully reconstruct the Thursday version of the filesystem; +\f2xfsrestore\f1 would need to be fed all 7 dumps in sequence. +A compromise schedule is to use level 1 on Saturday, Monday, +and Wednesday, +and level 2 on Sunday, Tuesday, and Thursday. +The Monday and Wednesday dumps would take longer, +but the worst case restore requires the +accumulation of just three dumps, one each at level 0, level 1, and level 2. +.SS Quotas +If the filesystem being dumped contains quotas, +.I xfsdump +will use +.IR xfsdq (8) +to store the quotas in a file called +.I xfsdump_quotas +in the root of the filesystem to be dumped. This file will then be +included in the dump. Upon restoration, +.I xfsrq (8) +can be used to reactivate the quotas for the filesystem. Note, +however, that the +.I xfsdump_quotas +file will probably require modification to change the filesystem or +UIDs if the filesystem has been restored to a different partition or +system. +.SH FILES +.TP 25 +/var/xfsdump/inventory +dump inventory database +.SH SEE ALSO +rmt(8), +xfsdq(8), +xfsrestore(8), +xfsinvutil(8), +xfsdq(8), +xfsrq(8), +attr_get(2). +.SH DIAGNOSTICS +The exit code is 0 on normal completion, non-zero if an error +occurs or the dump is terminated by the operator. +.PP +The message +``xfsdump: WARNING: unable to open directory: ino N: Invalid argument'' +can occur with filesystems which are actively being modified while +.I xfsdump +is running. +This can happen to either directory or regular file inodes \- affected +files will not end up in the dump, files below affected directories will +be placed in the +.I orphanage +directory by +.IR xfsrestore . +.SH BUGS +.I xfsdump +does not dump unmounted filesystems. +.PP +The dump frequency field of \f2/etc/fstab\f1 is not supported. +.PP +.I xfsdump +uses the alert program only when a media change is required. +.PP +.I xfsdump +requires root privilege (except for inventory display). +.PP +.I xfsdump +can only dump XFS filesystems. +.PP +The media format used by \f2xfsdump\f1 can only be understood +by \f2xfsrestore\f1. +.PP +\f2xfsdump\f1 does not know how to manage CD-ROM or other removable +disk drives. +.PP +\f2xfsdump\f1 can become confused when doing incremental or +resumed dumps +if on the same machine you dump two XFS filesystems and both +filesystems have the same filesystem identifier (UUID). +Since \f2xfsdump\f1 uses the filesystem identifier to identify +filesystems, +\f2xfsdump\f1 maintains one combined set of dump inventories +for both filesystems instead of two sets of dump inventories. +This scenario can happen only if +.I dd +or some other block-by-block copy program was used to make +a copy of an XFS filesystem. +See +.IR xfs_copy (8) +and +.IR xfs (5) +for more details. diff -rNu linux-2.4.7/cmd/xfsdump/man/man8/xfsinvutil.8 linux-2.4-xfs/cmd/xfsdump/man/man8/xfsinvutil.8 --- linux-2.4.7/cmd/xfsdump/man/man8/xfsinvutil.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/man8/xfsinvutil.8 Sun Jan 14 22:35:39 2001 @@ -0,0 +1,95 @@ +.TH xfsinvutil 8 +.SH NAME +xfsinvutil \- \&xfsdump inventory database checking and pruning utility +.SH SYNOPSIS +.nf +\f3xfsinvutil\f1 \c +[ \f3\-M\f1 mountpoint mm/dd/yyyy (prune all entries older than + specified date for the specified mount point) ] + [ \f3\-C\f1 (check and fix xfsdump inventory database \c +inconsistencies)] + [ \f3-n\f1 (no questions)] +.fi +.SH DESCRIPTION +.I xfsdump +maintains an online dump inventory in \f2/var/xfsdump/inventory\f1. +The +.B \-I +option of xfsdump displays the inventory contents hierarchically. +The levels of the hierarchy are: +filesystem, +dump session, +stream, and +media file. +.P +Over time, this database may grow too large as xfsdump and xfsrestore do +not remove entries from the inventory. The database may also develop +inconsistencies due to various reasons such as operator errors etc., +causing xfsdump or xfsrestore to print error or warning messages. +.P +.I xfsinvutil +is an utility to check this inventory database for consistency and +to remove entries of dump sessions which may no longer be of relevance. +.P +The following command line options are available: +.P +.TP 5 +\f3\-M\f1 \f2mountpoint mm/dd/yyyy\f1 +Specifies the mount point and cut-off date of inventory entries to +be selected for pruning. +xfsinvutil prompts the operator when a dump session in the inventory +is identified by the mount point and was created prior to the specified +date. +The operator can then select specific dump sessions for removal from +the inventory database. +This prompt will not happen if the \f3\-n\f1 option is used; it will +be assumed that the pruning is wanted. +.I xfsinvutil +also performs consistency checks on other inventory database entries when +invoked with this option. +.RS +.PP +The \f2mountpoint\f1 must match the mount point as specified in +the inventory shown using +.I xfsdump +with the \f3\-I\f1 option. +This includes the host name and the mount path. +.RE +.TP 5 +.B \-C +With this option, +.I xfsinvutil +performs consistency checks for all entries in the inventory database. +It fixes any problems found. If no consistent entries are found , the +corresponding inventory database file is removed. +.TP 5 +.B \-n +With this option, +.I xfsinvutil +will not ask any confirmation questions regarding sessions to prune. +(It is the "Nike" option). +.SH NOTES +.SS Inventory +Each dump session updates an inventory database in \f2/var/xfsdump/inventory\f1. +.I xfsdump +uses the inventory to determine the base of incremental +and resumed dumps. +.P +This database can be displayed by invoking +.I xfsdump +with the +.B \-I +option. +The display uses tabbed indentation to present the inventory +hierarchically. +The first level is filesystem. +The second level is session. +The third level is media stream (currently only one stream is supported). +The fourth level lists the media files sequentially composing the stream. +.SH FILES +.TP 25 +/var/xfsdump/inventory +dump inventory database +.SH SEE ALSO +xfsdump(8), +xfsrestore(8). diff -rNu linux-2.4.7/cmd/xfsdump/man/man8/xfsrestore.8 linux-2.4-xfs/cmd/xfsdump/man/man8/xfsrestore.8 --- linux-2.4.7/cmd/xfsdump/man/man8/xfsrestore.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/man/man8/xfsrestore.8 Mon Jun 11 23:22:25 2001 @@ -0,0 +1,672 @@ +.TH xfsrestore 8 +.SH NAME +xfsrestore \- \&XFS filesystem incremental restore utility +.SH SYNOPSIS +.nf +\f3xfsrestore\f1 \c +[ \f3\-a\f1 housekeeping ] \c +[ \f3\-b\f1 blocksize ] + [ \f3\-c\f1 media_change_alert_program ] \c +[ \f3-e\f1 ] + [ \f3\-f\f1 source ... ] \c +[ \f3\-i\f1 ] \c +[ \f3\-m\f1 force usage of minimal tape strategy ] + [ \f3\-n\f1 file ] \c +[ \f3\-o\f1 ] \c +[ \f3\-p\f1 report_interval ] \c +[ \f3\-r\f1 ] + [ \f3\-s\f1 subtree ... ] \c +[ \f3\-t\f1 ] \c +[ \f3\-v\f1 verbosity ] \c +[ \f3\-A\f1 ] [ \f3\-D\f1 ] + [ \f3\-E\f1 ] [ \f3\-F\f1 ] \c +[ \f3\-I\f1 [ subopt=value ... ] ] \c +[ \f3\-J\f1 ] \c +[ \f3\-L\f1 session_label ] + [ \f3\-O\f1 options_file ] \c +[ \f3\-Q\f1 ] \c +[ \f3\-R\f1 ] \c +[ \f3\-S\f1 session_id ] \c +[ \f3\-T\f1 ] + [ \f3\-Y\f1 io_ring_length ] \c +[ \f3\-\f1 ] \c +destination +.fi +.SH DESCRIPTION +.I xfsrestore +restores filesystems from dumps produced by \f2xfsdump\f1(8). +Two modes of operation are available: +simple and cumulative. +.P +The default is simple mode. +.I xfsrestore +populates the specified destination directory, \f2destination\f1, +with the files contained in the dump media. +.P +The +.B \-r +option specifies the cumulative mode. +Successive invocations of +.I xfsrestore +are used to apply a chronologically +ordered sequence of delta dumps to a base (level 0) dump. +The contents of the filesystem at the time each dump was produced +is reproduced. +This can involve adding, deleting, renaming, linking, and +unlinking files and directories. +.P +A delta dump is defined as either an incremental dump +(\f2xfsdump\f1 +.B \-l +option with level > 0) +or a resumed dump +(\f2xfsdump\f1 +.B \-R +option). +The deltas must be applied in the order they were produced. +Each delta applied must have been produced with the previously applied +delta as its base. +.TP 5 +\f3\-a\f1 \f2housekeeping\f1 +Each invocation of \f2xfsrestore\f1 +creates a directory called +.IR xfsrestorehousekeepingdir . +This directory is normally created +directly under the \f2destination\f1 directory. +The +.B \-a +option allows the operator to specify an alternate directory, +\f2housekeeping\f1, +in which +.I xfsrestore +creates the +.I xfsrestorehousekeeping +directory. +When performing a cumulative (\f3\-r\f1 option) restore, +each successive invocation of \f2xfsrestore\f1 must specify the same alternate +directory. +.TP 5 +\f3\-b\f1 \f2blocksize\f1 +Specifies the blocksize, in bytes, to be used for the restore. +For other drives such as DAT or 8 mm , the same blocksize used for the +xfsdump operation must be specified to restore the tape. +The default block size is 1Mb. +.TP 5 +\f3\-c\f1 \f2media_change_alert_program\f1 +Use the specified program to alert the operator when a media change is +required. The alert program is typically a script to send a mail or +flash a window to draw the operator's attention. +.TP 5 +\f3\-e\f1 +Prevents +.I xfsrestore +from overwriting existing files in the \f2destination\f1 directory. +.TP 5 +\f3\-f\f1 \f2source\f1 +Specifies a source of the dump to be restored. +This can be the pathname of a device (such as a tape drive), +a regular file or a remote tape drive (see \f2rmt\f1(8)). +This option must be omitted if the standard input option +(a lone +.B \- +preceding the \f2destination\f1 specification) +is specified. +.TP 5 +.B \-i +Selects interactive operation. +Once the on-media directory hierarchy has been read, an +interactive dialogue is begun. +The operator uses a small set of commands to peruse the +directory hierarchy, selecting files and subtrees for extraction. +The available commands are given below. +Initially nothing is selected, +except for those subtrees specified with \f3\-s\f1 command line options. +.RS +.TP 15 +\f3ls\f1 [\f2arg\f1] +List the entries in the current directory or the specified directory, +or the specified non-directory file entry. +Both the entry's original inode number and name are displayed. +Entries that are directories are appended with a `/'. +Entries that have been selected for extraction are prepended with a `*'. +.TP +\f3cd\f1 [\f2arg\f1] +Change the current working directory to the specified argument, or to the +filesystem root directory if no argument is specified. +.TP +\f3pwd\f1 +Print the pathname of the current directory, relative to the filesystem root. +.TP +\f3add\f1 [\f2arg\f1] +The current directory +or specified file or directory within the current directory +is selected for extraction. +If a directory is specified, then it and all its descendents are +selected. +Entries that are selected for extraction are prepended with a `*' +when they are listed by +.BR ls . +.TP +\f3delete\f1 [\f2arg\f1] +The current directory +or specified file or directory within the current directory +is deselected for extraction. +If a directory is specified, then it and all its descendents are +deselected. +The most expedient way to extract most of the files from a directory +is to select the directory and then deselect +those files that are not needed. +.TP +\f3extract\f1 +Ends the interactive dialogue, and causes all selected subtrees to be restored. +.TP +\f3quit\f1 +.I xfsrestore +ends the interactive dialogue and immediately exits, +even if there are files or subtrees selected for extraction. +.TP +\f3help\f1 +List a summary of the available commands. +.RE +.TP 5 +.B \-m +Use the minimal tape protocol. +This option cannot be used without specifying a blocksize to be used (see +.B \-b +option above). +.TP 5 +\f3\-n\f1 \f2file\f1 +Allows +.I xfsrestore +to restore only files newer than \f2file\f1. +The modification time of \f2file\f1 +(i.e., as displayed with the \f3ls -l\f1 command) +is compared to the inode modification time +of each file on the source media +(i.e., as displayed with the \f3ls -lc\f1 command). +A file is restored from media only if its inode modification time +is greater than or equal to +the modification time of \f2file\f1. +.TP 5 +\f3\-o\f1 +Restore file and directory owner/group even if not root. +When run with an effective user id of root, +.I xfsrestore +restores owner and group of each file and directory. +When run with any other effective user id it does not, +unless this option is specified. +.TP 5 +\f3\-p\f1 \f2report_interval\f1 +Causes progress reports to be printed at intervals of +\f2report_interval\f1 seconds. +The interval value is approximate, \f2xfsrestore\f1 will +delay progress reports to avoid undue processing overhead. +.TP 5 +\f3\-r\f1 +Selects the cumulative mode of operation. +.TP 5 +\f3\-s\f1 \f2subtree\f1 +Specifies a subtree to restore. +Any number of +.B \-s +options are allowed. +The restore is constrained to the union of all subtrees specified. +Each subtree is specified +as a pathname relative to the restore \f2destination\f1. +If a directory is specified, the directory and all files beneath +that directory are restored. +.TP 5 +.B \-t +Displays the contents of the dump, +but does not create or modify any files or directories. +It may be desirable to set the verbosity level to \f3silent\f1 +when using this option. +.TP 5 +\f3\-v\f1 \f2verbosity_level\f1 +Specifies the level of detail of the messages displayed during the course +of the restore. +The argument can be \f3silent\f1, \f3verbose\f1, or \f3trace\f1. +The default is \f3verbose\f1. +.TP 5 +.B \-A +Do not restore extended file attributes. +If this option is not specified, +extended file attributes are restored. +Note that dumping of extended file attributes is also optional. +.TP 5 +.B \-D +Restore DMAPI (Data Management Application Programming Interface) +event settings. +.I xfsdump +backs backs up these settings, +but it is usually not desirable to restore them. +However, the current implementation in Linux does not yet support the +\f3\-D\f1 option. +.TP 5 +.B \-E +Prevents +.I xfsrestore +from overwriting newer versions of files. +The inode modification time of the on-media file is compared to the +inode modification time of corresponding file in the \f2destination\f1 +directory. +The file is restored only if the on-media version is newer than the version +in the \f2destination\f1 directory. +The inode modification time of a file can be displayed with the \f3ls -lc\f1 command. +.TP 5 +.B \-F +Inhibit interactive operator prompts. +This option inhibits +.I xfsrestore +from prompting the operator for verification of the selected dump +as the restore target and from prompting for any media change. +.TP 5 +.B \-I +Causes the \f2xfsdump\f1 inventory to be displayed +(no restore is performed). +Each time \f2xfsdump\f1 is used, an online inventory +in \f2/var/xfsdump/inventory\f1 is updated. +This is used to determine the base for incremental dumps. +It is also useful for manually identifying a dump session to be restored +(see the +.B \-L +and +.B \-S +options). +Suboptions to filter the inventory display are described later. +.TP 5 +.B \-J +Inhibits inventory update when on-media session inventory encountered +during restore. +.I xfsrestore +opportunistically updates the online inventory +when it encounters an on-media session inventory, +but only if run with an effective user id of root +and only if this option is not given. +.TP 5 +\f3\-L\f1 \f2session_label\f1 +Specifies the label +of the dump session to be restored. +The source media is searched for this label. +It is any arbitrary string up to 255 characters long. +The label of the desired dump session can be copied from the inventory display +produced by the +.B \-I +option. +.TP 5 +\f3\-O\f1 \f2options_file\f1 +Insert the options contained in \f2options_file\f1 +into the beginning of the command line. +The options are specified just as they would appear if typed into the +command line. +In addition, newline characters (\\n) can be used as whitespace. +The options are placed before all options actually given +on the command line, +just after the command name. +Only one \f3\-O\f1 option can be used. +Recursive use is ignored. +The destination directory cannot be specified in \f2options_file\f1. +.TP 5 +.B \-Q +Force completion of an interrupted restore session. +This option is required to work around one specific pathological scenario. +When restoring a dump session which was interrupted due to an EOM +condition and no online session inventory is available, +.I xfsrestore +cannot know when the restore of that dump session is complete. +The operator is forced to interrupt the restore session. +In that case, if the operator tries to subsequently apply +a resumed dump (using the \f3\-r\f1 option), +.I xfsrestore +refuses to do so. +The operator must tell +.I xfsrestore +to consider the base restore complete +by using this option when applying the resumed dump. +.TP 5 +.B \-R +Resume a previously interrupted restore. +.I xfsrestore +can be interrupted at any time by pressing the +terminal interrupt character (see \f2stty\f1(1)). +Use this option to resume the restore. +The +.B \-a +and +.I destination +options must be the same. +.TP 5 +\f3\-S\f1 \f2session_id\f1 +Specifies the session UUID +of the dump session to be restored. +The source media is searched for this UUID. +The UUID of the desired dump session can be copied from the inventory display +produced by the +.B \-I +option. +.TP 5 +.B \-T +Inhibits interactive dialogue timeouts. +.I xfsrestore +prompts the operator for media changes. +This dialogue normally times out if no response is supplied. +This option prevents the timeout. +.TP 5 +\f3\-X\f1 \f2subtree\f1 +Specifies a subtree to exclude. +This is the converse of the +.B \-s +option. +Any number of +.B \-X +options are allowed. +Each subtree is specified +as a pathname relative to the restore \f2destination\f1. +If a directory is specified, the directory and all files beneath +that directory are excluded. +.TP 5 +\f3\-Y\f1 \f2io_ring_length\f1 +Specify I/O buffer ring length. +.I xfsrestore +uses a ring of input buffers to achieve maximum throughput +when restoring from tape drives. +The default ring length is 3. +However, this is only supported when running multi-threaded +which has not been done for Linux yet - making this option benign. +.TP 5 +.B \- +A lone +.B \- +causes the standard input to be read +as the source of the dump to be restored. +Standard input +can be a pipe from another utility (such as \f2xfsdump\f1(8)) +or a redirected file. +This option cannot be used with the +.B \-f +option. +The +.B \- +must follow all other options, and precede the \f2destination\f1 +specification. +.P +The dumped filesystem is restored into the \f2destination\f1 directory. +There is no default; the \f2destination\f1 must be specified. +.SH NOTES +.SS Cumulative Restoration +A base (level 0) dump and an ordered set of delta dumps can be +sequentially restored, +each on top of the previous, +to reproduce the contents of the original filesystem +at the time the last delta was produced. +The operator invokes +.I xfsrestore +once for each dump. +The +.B \-r +option must be specified. +The \f2destination\f1 directory must be the same for all invocations. +Each invocation leaves a directory named +.I xfsrestorehousekeeping +in the \f2destination\f1 directory +(however, see the +.B \-a +option above). +This directory contains the state information that must be communicated +between invocations. +The operator must remove this directory after the last delta +has been applied. +.P +.I xfsrestore +also generates a directory named +.I orphanage +in the \f2destination\f1 directory. +.I xfsrestore +removes this directory after completing a simple restore. +However, if +.I orphanage +is not empty, +it is not removed. +This can happen if files present on the dump media +are not referenced by any of the restored directories. +The +.I orphanage +has an entry for each such file. +The entry name is the file's original inode number, +a ".", +and the file's generation count modulo 4096 +(only the lower 12 bits of the generation count are used). +.P +.I xfsrestore +does not remove the +.I orphanage +after cumulative restores. +Like the +.I xfsrestorehousekeeping +directory, +the operator must remove it after applying all delta dumps. +.SS Media Management +A dump consists of one or more media files +contained on one or more media objects. +A media file contains all or a portion of the filesystem dump. +Large filesystems are broken up into multiple media files +to minimize the impact of media dropouts, +and to accommodate media object boundaries (end-of-media). +.P +A media object is any storage medium: +a tape cartridge, +a remote tape device (see \f2rmt\f1(8)), +a regular file, +or the standard input +(currently other removable media drives are not supported). +Tape cartridges can contain multiple media files, +which are typically separated by +(in tape parlance) +file marks. +If a dump spans multiple media objects, +the restore must begin with the media object containing the +first media file dumped. +The operator is prompted when the next media object is needed. +.P +Media objects can contain more than one dump. +The operator can select the desired dump +by specifying the dump label +.RB ( \-L +option), +or by specifying the dump UUID +.RB ( \-S +option). +If neither is specified, +\f2xfsrestore\f1 scans the entire media object, +prompting the operator as each dump session is encountered. +.P +The inventory display +.RB ( \-I +option) is useful for +identifying the media objects required. +It is also useful for identifying a dump session. +The session UUID can be copied from the inventory display +to the +\f3\-S\f1 option argument +to unambiguously identify a dump session to be restored. +.P +Dumps placed in regular files or the standard output +do not span multiple media objects, +nor do they contain multiple dumps. +.SS Inventory +Each dump session updates an inventory database in \f2/var/xfsdump/inventory\f1. +This database can be displayed by invoking +.I xfsrestore +with the +.B \-I +option. +The display uses tabbed indentation to present the inventory +hierarchically. +The first level is filesystem. +The second level is session. +The third level is media stream (currently only one stream is supported). +The fourth level lists the media files sequentially composing the stream. +.P +The following suboptions are available to filter the display. +.TP5 +\f3\-I depth=\f1\f2n\f1 +(where +.I n +is 1, 2, or 3) limits the hierarchical depth of the display. When +.I n +is 1, only the filesystem information from the inventory is displayed. When +.I n +is 2, only filesystem and session information are displayed. When +.I n +is 3, only filesystem, session and stream information are displayed. +.TP5 +\f3\-I level=\f1\f2n\f1 +(where +.I n +is the dump level) limits the display to dumps of that particular dump level. +.P +The display may be restricted to media files contained in a specific +media object. +.TP5 +\f3\-I mobjid=\f1\f2value\f1 +(where +.I value +is a media ID) specifies the media object by its media ID. +.TP5 +\f3\-I mobjlabel=\f1\f2value\f1 +(where +.I value +is a media label) specifies the media object by its media label. +.P +Similarly, the display can be restricted to a specific filesystem. +.TP5 +\f3\-I mnt=\f1\f2host-qualified_mount_point_pathname\f1 +(that is, hostname:pathname), identifies the filesystem by mountpoint. +.TP5 +\f3\-I fsid=\f1\f2filesystem_id\f1 +identifies the filesystem by filesystem ID. +.TP5 +\f3\-I dev=\f1\f2host-qualified_device_pathname\f1 +(that is, hostname:device_pathname) identifies the filesystem by device. +.P +More than one of these suboptions, separated by commas, may be specified +at the same time to limit the display of the inventory to +those dumps of interest. +However, at most four suboptions can be specified at once: +one to constrain the display hierarchy depth, +one to constrain the dump level, +one to constrain the media object, +and one to constrain the filesystem. +.P +For example, +.B \-I depth=1,mobjlabel="tape 1",mnt=host1:/test_mnt +would display only the filesystem information (depth=1) for +those filesystems that were mounted on \f2host1:/test_mnt\f1 +at the time of the dump, +and only those filesystems dumped to the media object labeled "tape 1". +.P +Dump records may be removed (pruned) from the inventory using the +.I xfsinvutil +program. +.P +An additional media file is placed +at the end of each dump stream. +This media file contains the inventory information for the +current dump session. +This is currently unused. +.SS Media Errors +\f2xfsdump\f1 is tolerant of media errors, +but cannot do error correction. +If a media error occurs in the body of a media file, +the filesystem file represented at that point is +lost. +The bad portion of the media is skipped, +and the restoration resumes at the next filesystem file +after the bad portion of the media. +.P +If a media error occurs in the beginning of the +media file, +the entire media file is lost. +For this reason, +large dumps are broken into a number +of reasonably sized media files. +The restore resumes with the next media file. +.SS Quotas +When +.I xfsdump +dumps a filesystem with quotas, it creates a file in the root of the +dump called +.IR xfsdump_quotas . +.I xfsrestore +can restore this file like any other file included in the dump. This +file can be processed by the +.IR xfsrq (8) +command to reactivate the quotas. However, the +.I xfsdump_quotas +file contains information which may first require modification; +specifically the filesystem name and the user ids. If you are +restoring the quotas for the same users on the same filesystem from +which the dump was taken, then no modification will be necessary. +However, if you are restoring the dump to a different filesystem, you +will need to: +.HP +- +ensure the new filesystem is mounted with the +quota +option +.HP +- +modify the +.I xfsdump_quotas +file to contain the new filesystem name +.HP +- +ensure the uids in the +.I xfsdump_quotas +file are correct +.P +Once the quota information has been verified, +.I xfsrq (8) +can be used to apply the quota limits to the filesystem. +.SH FILES +.TP 25 +/var/xfsdump/inventory +dump inventory database +.SH SEE ALSO +rmt(8), +xfsdump(8), +xfsinvutil(8), +xfsrq(8), +attr_set(2). +.SH DIAGNOSTICS +The exit code is 0 on normal completion, +and non-zero if an error occurred +or the restore was terminated by the operator. +.SH BUGS +Pathnames of restored non-directory files +(relative to the \f2destination\f1 directory) +must be 1023 characters (MAXPATHLEN) or less. +Longer pathnames are discarded +and a warning message displayed. +.P +There is no verify option to \f2xfsrestore\f1. +This would allow the operator to compare a filesystem dump to +an existing filesystem, +without actually doing a restore. +.P +The interactive commands (\f3\-i\f1 option) do not understand +regular expressions. +.P +.I xfsrestore +uses the alert program only when a media change is required. +.P +Cumulative mode (\f3\-r\f1 option) requires that the operator invoke +.I xfsrestore +for the base and for each delta to be applied in sequence to the base. +It would be better to allow the operator to identify the last delta +in the sequence of interest, +and let +.I xfsrestore +work backwards from that delta to identify +and apply the preceding deltas and base dump, +all in one invocation. diff -rNu linux-2.4.7/cmd/xfsdump/quota/CVS/Entries linux-2.4-xfs/cmd/xfsdump/quota/CVS/Entries --- linux-2.4.7/cmd/xfsdump/quota/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/quota/CVS/Entries Thu Jul 5 11:44:09 2001 @@ -0,0 +1,4 @@ +/Makefile/1.1/Thu Mar 22 01:29:53 2001/-ko/ +/xfsdq.c/1.4/Tue May 1 05:51:57 2001/-ko/ +/xfsrq.sh/1.1/Thu Mar 22 01:29:53 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/quota/CVS/Repository linux-2.4-xfs/cmd/xfsdump/quota/CVS/Repository --- linux-2.4.7/cmd/xfsdump/quota/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/quota/CVS/Repository Thu Jul 5 11:44:09 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/quota diff -rNu linux-2.4.7/cmd/xfsdump/quota/CVS/Root linux-2.4-xfs/cmd/xfsdump/quota/CVS/Root --- linux-2.4.7/cmd/xfsdump/quota/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/quota/CVS/Root Thu Jul 5 11:44:09 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/quota/Makefile linux-2.4-xfs/cmd/xfsdump/quota/Makefile --- linux-2.4.7/cmd/xfsdump/quota/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/quota/Makefile Wed Mar 21 19:29:53 2001 @@ -0,0 +1,48 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = xfsdq +CFILES = xfsdq.c +LSRCFILES = xfsrq.sh + +default: $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_BIN_DIR) + $(INSTALL) -m 755 xfsrq.sh $(PKG_BIN_DIR)/xfsrq +install-dev: diff -rNu linux-2.4.7/cmd/xfsdump/quota/xfsdq.c linux-2.4-xfs/cmd/xfsdump/quota/xfsdq.c --- linux-2.4.7/cmd/xfsdump/quota/xfsdq.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/quota/xfsdq.c Tue May 1 00:51:57 2001 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *progname; + +static void usage(void) +{ + fprintf(stderr, "%s: [-ugV] \n", progname); + exit(2); +} + +void report(int id, int type, char *device) +{ + struct fs_disk_quota d; + + memset(&d, 0, sizeof(struct fs_disk_quota)); + if (quotactl(QCMD(Q_XGETQUOTA, type), device, id, (void *)&d) < 0) { + /* + * debug only - uid's without quota expected to give errors * + fprintf(stderr, "%s: quotactl id=%d, device=", progname, id); + perror(device); + */ + return; + } + printf("fs = %s\n", device); + printf("%-10d %7llu %7llu %7llu %7llu\n", id, + (unsigned long long)d.d_blk_softlimit, + (unsigned long long)d.d_blk_hardlimit, + (unsigned long long)d.d_ino_softlimit, + (unsigned long long)d.d_ino_hardlimit); +} + +int main(int argc, char **argv) +{ + struct mntent *mntp; + FILE *mtab; + int c; + int found = 0; + int type = USRQUOTA; + + progname = basename(argv[0]); + while ((c = getopt(argc, argv, "ugV")) != EOF) { + switch(c) { + case 'u': + type = USRQUOTA; + break; + case 'g': + type = GRPQUOTA; + break; + case 'V': + printf("%s version %s\n", progname, VERSION); + break; + default: + usage(); + } + } + + if (argc < optind + 1) + usage(); + + if ((mtab = setmntent(MOUNTED, "r")) == NULL) { + fprintf(stderr, "%s: no "MOUNTED" file\n", progname); + exit(1); + } + while ((mntp = getmntent(mtab)) != NULL) { + if (strcmp(argv[optind], mntp->mnt_dir) != 0) + continue; + found = 1; + if (type == USRQUOTA) { + struct passwd *u; + setpwent(); + while ((u = getpwent()) != NULL) + report(u->pw_uid, type, mntp->mnt_fsname); + endpwent(); + } + else { + struct group *g; + setgrent(); + while ((g = getgrent()) != NULL) + report(g->gr_gid, type, mntp->mnt_fsname); + endgrent(); + } + break; + } + endmntent(mtab); + + if (!found) { + fprintf(stderr, "%s: mount point %s is not in " MOUNTED, + progname, argv[optind]); + exit(1); + } + exit(0); +} diff -rNu linux-2.4.7/cmd/xfsdump/quota/xfsrq.sh linux-2.4-xfs/cmd/xfsdump/quota/xfsrq.sh --- linux-2.4.7/cmd/xfsdump/quota/xfsrq.sh Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/quota/xfsrq.sh Wed Mar 21 19:29:53 2001 @@ -0,0 +1,71 @@ +#!/bin/sh -f +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +OPTS=" -u" +VERBOSE=false +PATH="/bin:/usr/bin:/usr/sbin" +USAGE="Usage: xfsrq [-guv] dumpfile" + +while getopts "guv" c +do + case $c in + g) OPTS=" -g";; + u) OPTS=" -u";; + v) VERBOSE=true;; + \?) echo $USAGE 1>&2 + exit 2 + ;; + esac +done + +[ -x /usr/bin/perl ] || "Error: cannot find /usr/bin/perl" +[ -x /usr/bin/expr ] || "Error: cannot find /usr/bin/expr" +[ -x /usr/sbin/setquota ] || "Error: cannot find /usr/sbin/setquota" + +set -- extra $@ +shift $OPTIND +case $# in + 1) perl -pe 's/^fs = (.*)/\1 / && chomp' < $1 | \ + while read fs id bsoft bhard isoft ihard; do + [ $VERBOSE ] && echo setting quota for id=$id dev=$fs + # blk conversion (512 -> 1024) + bsoft=`expr $bsoft / 2` + bhard=`expr $bhard / 2` + setquota $OPTS -n $id $fs $bsoft $bhard $isoft $ihard + done + ;; + *) echo $USAGE 1>&2 + exit 2 + ;; +esac +exit 0 diff -rNu linux-2.4.7/cmd/xfsdump/restore/CVS/Entries linux-2.4-xfs/cmd/xfsdump/restore/CVS/Entries --- linux-2.4.7/cmd/xfsdump/restore/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/CVS/Entries Thu Jul 5 11:44:16 2001 @@ -0,0 +1,20 @@ +/Makefile/1.3/Fri Feb 9 07:45:14 2001/-ko/ +/bag.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/bag.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/content.c/1.8/Mon May 21 00:35:02 2001/-ko/ +/dirattr.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/dirattr.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/getopt.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/inomap.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/inomap.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/mmap.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/mmap.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/namreg.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/namreg.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/node.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/node.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/tree.c/1.4/Tue May 15 04:05:35 2001/-ko/ +/tree.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/win.c/1.1/Mon Jan 15 04:06:20 2001/-ko/ +/win.h/1.1/Mon Jan 15 04:06:20 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsdump/restore/CVS/Repository linux-2.4-xfs/cmd/xfsdump/restore/CVS/Repository --- linux-2.4.7/cmd/xfsdump/restore/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/CVS/Repository Thu Jul 5 11:44:09 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsdump/restore diff -rNu linux-2.4.7/cmd/xfsdump/restore/CVS/Root linux-2.4-xfs/cmd/xfsdump/restore/CVS/Root --- linux-2.4.7/cmd/xfsdump/restore/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/CVS/Root Thu Jul 5 11:44:09 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsdump/restore/Makefile linux-2.4-xfs/cmd/xfsdump/restore/Makefile --- linux-2.4.7/cmd/xfsdump/restore/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/Makefile Fri Feb 9 01:45:14 2001 @@ -0,0 +1,147 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LIBRMT = $(TOPDIR)/librmt/librmt.a + +COMMINCL = \ + arch_xlate.h \ + attr.h \ + cldmgr.h \ + content.h \ + content_inode.h \ + dlog.h \ + drive.h \ + exit.h \ + fs.h \ + getdents.h \ + global.h \ + lock.h \ + media.h \ + mlog.h \ + openutil.h \ + path.h \ + qlock.h \ + rec_hdr.h \ + ring.h \ + sproc.h \ + stkchk.h \ + stream.h \ + types.h \ + util.h + +INVINCL = \ + inventory.h \ + inv_priv.h + +INVCOMMON = \ + inv_api.c \ + inv_core.c \ + inv_fstab.c \ + inv_idx.c \ + inv_mgr.c \ + inv_stobj.c + +COMMON = \ + arch_xlate.c \ + attr.c \ + cldmgr.c \ + dlog.c \ + drive.c \ + drive_scsitape.c \ + drive_simple.c \ + drive_minrmt.c \ + fs.c \ + getdents.c \ + global.c \ + lock.c \ + main.c \ + mlog.c \ + openutil.c \ + path.c \ + qlock.c \ + ring.c \ + sproc.c \ + stkchk.c \ + stream.c \ + util.c + +LOCALS = \ + bag.c \ + content.c \ + dirattr.c \ + inomap.c \ + mmap.c \ + namreg.c \ + node.c \ + tree.c \ + win.c + +LOCALINCL = \ + bag.h \ + dirattr.h \ + getopt.h \ + inomap.h \ + mmap.h \ + namreg.h \ + node.h \ + tree.h \ + win.h + +CMDTARGET = xfsrestore +CMDDEPS = $(LIBHANDLE) $(LIBATTR) + +CFILES = $(COMMON) $(INVCOMMON) $(LOCALS) +HFILES = $(LOCALINCL) +LINKS = $(COMMINCL) $(COMMON) $(INVINCL) $(INVCOMMON) +LDIRT = $(LINKS) +LLDLIBS = $(LIBHANDLE) $(LIBUUID) $(LIBRMT) $(LIBATTR) + +LCFLAGS = -DRESTORE -DRMT -DBASED -DDOSOCKS -DINVCONVFIX -DPIPEINVFIX -DEOMFIX -DSESSCPLT -DWHITEPARSE -DNODECHK -DDIRENTHDR_CHECKSUM -DEXTATTR +#LCFLAGS += -DDMEXTATTR + +default: $(LINKS) $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_BIN_DIR) +install-dev: + +$(COMMINCL) $(COMMON): + @$(RM) $@; $(LN_S) ../common/$@ $@ + +$(INVINCL) $(INVCOMMON): + @$(RM) $@; $(LN_S) ../inventory/$@ $@ diff -rNu linux-2.4.7/cmd/xfsdump/restore/bag.c linux-2.4-xfs/cmd/xfsdump/restore/bag.c --- linux-2.4.7/cmd/xfsdump/restore/bag.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/bag.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include + +#include "types.h" +#include "mlog.h" +#include "bag.h" + +bag_t * +bag_alloc( void ) +{ + bag_t *bagp; + + bagp = ( bag_t * )calloc( 1, sizeof( bag_t )); + ASSERT( bagp ); + return bagp; +} + +void +bag_insert( bag_t *bagp, + bagelem_t *newp, + size64_t key, + void *payloadp ) +{ + register bagelem_t *nextp; + register bagelem_t *prevp; + + ASSERT( ! newp->be_loaded ); + newp->be_loaded = BOOL_TRUE; + ASSERT( ! newp->be_bagp ); + newp->be_bagp = bagp; + + newp->be_key = key; + newp->be_payloadp = payloadp; + + if ( bagp->b_headp ) { + nextp = bagp->b_headp; + prevp = bagp->b_headp->be_prevp; + } else { + nextp = newp; + prevp = newp; + } + + newp->be_nextp = nextp; + newp->be_prevp = prevp; + nextp->be_prevp = newp; + prevp->be_nextp = newp; + + bagp->b_headp = newp; +} + +void +bag_remove( bag_t *bagp, + bagelem_t *oldp, + size64_t *keyp, + void **payloadpp ) +{ + register bagelem_t *nextp; + register bagelem_t *prevp; + + ASSERT( oldp->be_loaded ); + ASSERT( oldp->be_bagp == bagp ); + + nextp = oldp->be_nextp; + prevp = oldp->be_prevp; + + nextp->be_prevp = prevp; + prevp->be_nextp = nextp; + + if ( bagp->b_headp == oldp ) { + if ( nextp == oldp ) { + ASSERT( prevp == oldp ); + bagp->b_headp = 0; + } else { + bagp->b_headp = nextp; + } + } + + *keyp = oldp->be_key; + *payloadpp = oldp->be_payloadp; + + memset( ( void * )oldp, 0, sizeof( bagelem_t )); +} + +bagelem_t * +bag_find( bag_t *bagp, + size64_t key, + void **payloadpp ) +{ + register bagelem_t *p; + + for ( p = bagp->b_headp + ; + p && p->be_nextp != bagp->b_headp && p->be_key != key + ; + p = p->be_nextp ) + ; + + if ( ! p || p->be_key != key ) { + *payloadpp = 0; + return 0; + } else { + ASSERT( p->be_loaded ); + ASSERT( p->be_bagp == bagp ); + *payloadpp = p->be_payloadp; + return p; + } +} + + +void +bagiter_init( bag_t *bagp, bagiter_t *iterp ) +{ + iterp->bi_bagp = bagp; + if ( ! bagp->b_headp ) { + iterp->bi_nextp = 0; + return; + } + iterp->bi_lastp = bagp->b_headp->be_prevp; + iterp->bi_nextp = bagp->b_headp; +} + +bagelem_t * +bagiter_next( bagiter_t *iterp, void **payloadpp ) +{ + bagelem_t *returnp; + + /* termination condition + */ + if ( ! iterp->bi_nextp ) { + *payloadpp = 0; + return 0; + } + + /* save the element to be returned + */ + returnp = iterp->bi_nextp; + + /* calculate next. if returning last, set next to NULL + */ + if ( iterp->bi_nextp == iterp->bi_lastp ) { + iterp->bi_nextp = 0; + } else { + iterp->bi_nextp = iterp->bi_nextp->be_nextp; + } + + *payloadpp = returnp->be_payloadp; + return returnp; +} + +void +bag_free( bag_t *bagp ) +{ + register bagelem_t *p; + + p = bagp->b_headp; + while ( p ) { + register bagelem_t *nextp = p->be_nextp; + memset( ( void * )p, 0, sizeof( bagelem_t )); + p = nextp; + if ( p == bagp->b_headp ) { + break; + } + ASSERT( p ); + } + + memset( ( void * )bagp, 0, sizeof( bag_t )); + free( ( void * )bagp ); +} diff -rNu linux-2.4.7/cmd/xfsdump/restore/bag.h linux-2.4-xfs/cmd/xfsdump/restore/bag.h --- linux-2.4.7/cmd/xfsdump/restore/bag.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/bag.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef BAG_H +#define BAG_H + +/* bag.[hc] - bag abstraction + * + * user embeds a bagelem_t into items to be bagged. the element contains + * an element key, and a user-specified pointer. items can be inserted + * into the bag, removed from the bag, and searched for in the bag. the + * user-embedded bagelem_t is soley owned by the bag: DON'T try to + * reference bagelem_t members! + */ +struct bagelem { + bool_t be_loaded; + struct bag *be_bagp; + size64_t be_key; + void *be_payloadp; + struct bagelem *be_nextp; + struct bagelem *be_prevp; +}; + +typedef struct bagelem bagelem_t; + +struct bag { + bagelem_t *b_headp; +}; + +typedef struct bag bag_t; + +/* creates a new bag + */ +extern bag_t *bag_alloc( void ); + +/* insert the item into the bag. the caller supplies a search key + * and arbitrary payload. + */ +extern void bag_insert( bag_t *bagp, + bagelem_t *bagelemp, + size64_t key, + void *payloadp ); + +/* remove the item from the bag. the key and payload originally supplied + * to the insert operator are returned by reference. + */ +extern void bag_remove( bag_t *bagp, + bagelem_t *bagelemp, + size64_t *keyp, + void **payloadpp ); + +/* search by key for an element in the bag. + * returns the element pointer if a matching item is found, as well as + * the payload (by reference). if the item is not in the bag, returns + * a null pointer and (by reference) payload. + */ +extern bagelem_t *bag_find( bag_t *bagp, + size64_t key, + void **payloadpp ); + +/* private bag iterator + */ +struct bagiter { + bag_t *bi_bagp; + bagelem_t *bi_lastp; + bagelem_t *bi_nextp; +}; + +typedef struct bagiter bagiter_t; + +/* initializes a bag iterator + */ +extern void bagiter_init( bag_t *bagp, bagiter_t *iterp ); + +/* returns the next element in the bag. caller may remove the element + * prior to the next call. + */ +extern bagelem_t * bagiter_next( bagiter_t *iterp, void **payloadpp ); + +/* destroys the bag. + */ +extern void bag_free( bag_t *bagp ); + +#endif /* BAG_H */ diff -rNu linux-2.4.7/cmd/xfsdump/restore/content.c linux-2.4-xfs/cmd/xfsdump/restore/content.c --- linux-2.4.7/cmd/xfsdump/restore/content.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/content.c Sun May 20 19:35:02 2001 @@ -0,0 +1,9373 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#ifdef DOSOCKS +#include +#include +#endif /* DOSOCKS */ +#include +#include +#include +#ifdef EXTATTR +#include +#include +#endif /* EXTATTR */ +#ifdef DMEXTATTR /* also see F_FSSETDM */ +#include +#endif /* DMEXTATTR */ +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "util.h" +#include "cldmgr.h" +#include "qlock.h" +#include "lock.h" +#include "path.h" +#include "openutil.h" +#include "exit.h" +#include "getopt.h" +#include "mlog.h" +#include "dlog.h" +#include "bag.h" +#include "node.h" +#include "namreg.h" +#include "stream.h" +#include "global.h" +#include "drive.h" +#include "media.h" +#include "content.h" +#include "content_inode.h" +#include "inomap.h" +#include "dirattr.h" +#include "tree.h" +#include "inventory.h" +#include "mmap.h" +#include "arch_xlate.h" + +/* content.c - manages restore content + */ + +/* structure definitions used locally ****************************************/ + +#define WRITE_TRIES_MAX 3 + /* retry loop tuning for write(2) workaround + */ +typedef enum { SYNC_INIT, SYNC_BUSY, SYNC_DONE } sync_t; + /* for lock-step synchronization + */ +typedef struct { xfs_ino_t eg_ino; off64_t eg_off; } egrp_t; + /* extent group descriptor + */ +typedef char label_t[ GLOBAL_HDR_STRING_SZ ]; + /* dump or mobj label + */ +typedef enum { PURP_SEARCH, PURP_DIR, PURP_NONDIR } purp_t; + /* to describe purpose for a media file request. may be for + * searching for a dump to restore, for dir restore, or non-dir + */ +typedef off_t dh_t; + /* handles for descriptors in persistent state inventory + * encoded as byte offset plus one of descriptor into descriptor + * portion of persistent state. plus one so DH_NULL can be zero. + */ +#define DH_NULL ( ( dh_t )0 ) + /* NULL inv. descriptor handles, to terminate linked descriptor lists. + * must be zero-valued, so memset of pers.s sets freeh to DH_NULL. + */ +#define DH2F( h ) ( ASSERT( descp ), ASSERT( h > DH_NULL ), ( pers_file_t * )( ( char * )descp + ( h - 1 ))) +#define DH2O( h ) ( ASSERT( descp ), ASSERT( h > DH_NULL ), ( pers_obj_t * )( ( char * )descp + ( h - 1 ))) +#define DH2S( h ) ( ASSERT( descp ), ASSERT( h > DH_NULL ), ( pers_strm_t * )( ( char * )descp + ( h - 1 ))) +#define DH2D( h ) ( ASSERT( descp ), ASSERT( h > DH_NULL ), ( pers_desc_t * )( ( char * )descp + ( h - 1 ))) + /* convert file, object, and stream inv. descriptor handle into + * descriptor pointers + */ +#define DAU 1 + /* number of descriptor pages to allocate when free list exhausted + */ +#define IBPGINCR 32 + /* session inv. restore retry buffer increment + */ + +/* Media state abstraction + */ +struct Media { + drive_t *M_drivep; + global_hdr_t *M_grhdrp; + drive_hdr_t *M_drhdrp; + media_hdr_t *M_mrhdrp; + content_hdr_t *M_crhdrp; + content_inode_hdr_t *M_scrhdrp; + + enum { POS_UNKN, /* whenever media file not open */ + POS_ATHDR, /* at beginning of media file */ + POS_INDIR, /* at beginning of inomap/dirdump */ + POS_ATNONDIR, /* at first non-dir file */ + POS_END, /* EOM/EOD */ + POS_USELESS, /* current object contains nothing useful */ + POS_BLANK /* like useless */ + } M_pos; + /* media positioning info. initially UNKN, set back to + * unkn whenever end_read op called. + */ + ix_t M_fmfix; + ix_t M_lmfix; + ix_t M_pmfix; + bool_t M_pmfixvalpr; + purp_t M_mfixpurp; + bool_t M_flmfixvalpr; + /* the indices within the current media object of the first + * and last media files seen, as well as previous last. + * invalidated whenever purpose changes or media is changed. + * previous (pmfix) not valid until second media file seen. + */ + ix_t M_fsfix; + ix_t M_fsoix; + ix_t M_fssix; + bool_t M_fsfixvalpr; + /* index within the current media object of the first + * media file that is part of dump being restored, + * and indices of the obj and stream containing that mfile. + * invalidated on media change. + */ +}; + +typedef struct Media Media_t; + + +/* persistent state - mmapped, has linked lists of dump streams, media + * objects, and media files. descriptors for each fit into PERS_DESCSZ + * bytes, and are allocated from a common free pool. + */ + +/* persistent media file descriptor + */ +struct pers_file { + dh_t f_nexth; + /* singly-linked list of files withing object + */ + dh_t f_parh; + /* parent object + */ + bool_t f_szvalpr; + off64_t f_sz; + /* if this info came from an inventory (on-line or on-media), + * we know the media file size + */ + bool_t f_dirtriedpr; + /* set if attempted to restore dirs from this media file. + * says nothing about success or failure. prevents us from + * trying to restore dirs from this media file again. + */ + bool_t f_valpr; + /* following three fields are valid + */ + egrp_t f_firstegrp; + /* first extent group in this media file + */ + egrp_t f_curegrp; + /* next extent group to be restored from this media file. + * initially equals f_firstegrp. + */ + drive_mark_t f_curmark; + /* drive manager mark for seeking to current extent group + */ + bool_t f_nondirdonepr; + /* TRUE when non-dirs from this media file completely restored, + * or as restored as they can be (some or all lost due to + * media corruption). + */ + bool_t f_nondirskippr; + /* no non-dirs are needed from this nmedia file (due to + * subtree or interactive selections) + */ + intgen_t f_flags; + /* mark terminators and inventories + */ + bool_t f_underheadpr; + /* the drive is currently positioned at or in this media file + */ +}; + +/* f_flags + */ +#define PF_INV ( 1 << 0 ) +#define PF_TERM ( 1 << 1 ) + +typedef struct pers_file pers_file_t; + +/* persistent media object descriptor + */ +struct pers_obj { + dh_t o_nexth; + /* singly-linked list of objects in stream + */ + dh_t o_parh; + /* parent dump stream descriptor + */ + dh_t o_cldh; + /* head of list of pertinent media files contained in + * this media object + */ + bool_t o_idlabvalpr; + /* id and label fields are valid + */ + uuid_t o_id; + /* uuid of media object + */ + label_t o_lab; + /* label of media object + */ + ix_t o_fmfmix; + bool_t o_fmfmixvalpr; + /* 0-based index into this mobj's mfiles of first + * mfile in the mobj that is part of the dump stream. + */ + ix_t o_fmfsix; + bool_t o_fmfsixvalpr; + /* 0-based index into this dump stream's mfiles of first + * mfile in the mobj that is part of the dump stream. + */ + bool_t o_lmfknwnpr; + /* TRUE if last media file on object is represented in + * children list. + */ + bool_t o_indrivepr; + ix_t o_indriveix; + /* TRUE if this object is in a drive, and which drive it is + * in. + */ +}; + +typedef struct pers_obj pers_obj_t; + +/* media dump stream descriptor + */ +struct pers_strm { + dh_t s_nexth; + /* singly-linked list of streams generated by dump + */ + dh_t s_cldh; + /* head of list of mobjs containing this dstrm's mfiles + */ + bool_t s_lastobjknwnpr; + /* TRUE if if last object in the stream is represented in + * children list. + */ +}; + +typedef struct pers_strm pers_strm_t; + +/* media descriptor allocation object (for free list) + */ +union pers_desc { + dh_t d_nexth; + /* singly-linked free list of descriptors + */ + pers_file_t d_file; + /* media file descriptor overlay; + */ + pers_obj_t d_obj; + /* media object descriptor overlay; + */ + pers_strm_t d_strm; + /* media stream descriptor overlay; + */ +}; + +typedef union pers_desc pers_desc_t; + +#define PERS_DESCSZ 512 + /* size of media object, media file, and media stream descriptors. + * need to fit integral number into a page, single allocator + * used allocate and free all types . + */ + +/* subtree descriptor - the subtree command line arguments are transcribed + * into variable-length descriptors and placed in an integral number of + * pages after the persistent header, and before the media descriptor free list. + */ +#define STDESCALIGN 8 + +struct stdesc { + bool_t std_sensepr; + /* TRUE if this is a subtree to INCLUDE, FALSE if EXCLUDE + */ + off_t std_nextoff; + /* offset to next descriptor, in bytes relative to this + */ + char std_path[ 1 ]; + /* first character of a NULL-terminated string containing the + * the relative subtree pathname + */ +}; + +typedef struct stdesc stdesc_t; + +#ifdef EXTATTR +/* byte span descriptor - registers a span of a file restored. + */ +struct bytespan { + off64_t offset; + off64_t endoffset; +} ; + +typedef struct bytespan bytespan_t; + +/* partial restore descriptor - Keeps track of different byte spans restored + * for a specific inode. Used to sync operations between restore streams. + */ +struct partial_rest { + xfs_ino_t is_ino; + /* inode number */ + bytespan_t is_bs[STREAM_SIMMAX]; + /* each stream could conceivably be writing to a single + * file simultaneously if one file spans all device streams. + * Need a record for each possible place in the file. + */ +}; + +typedef struct partial_rest partial_rest_t; +#endif /* EXTATTR */ + + +/* persistent state file header - two parts: accumulation state + * which spans several sessions, and session state. each has a valid + * bit, and no fields are valid until the valid bit is set. + * all elements defined such that a bzero results in a valid initial state. + */ +struct pers { + /* command line arguments from first session, and session + * history. + */ + struct { + bool_t valpr; + /* not set until a BASE dump has been identified + * and validated for restoral, and an attempt has + * been made to load the dump inventory into persistent + * state, and the namreg and tree abstractions + * have been initialized, and the session history + * has been initialized and validated. + */ + char dstdir[ MAXPATHLEN ]; + bool_t dstdirisxfspr; + /* absolute pathname of the destination directory + */ + ix_t dumpcnt; + /* how many dumps have been applied completedly (A1) + */ + uuid_t lastdumpid; + /* uuid of the last dump completely restored (A1) + */ + label_t lastdumplab; + /* label of the last dump completely restored (A1) + */ + bool_t cumpr; + /* is a cumulative restore (-r) + */ + bool_t interpr; + /* interactive mode specified on command line (-i) + */ + bool_t existpr; + /* existing files may not be overwritten (-e) + */ + bool_t changepr; + /* only missing or old files may be overwritten (-E) + */ + bool_t newerpr; + time_t newertime; + /* only files older than example may be overwritten (-n) + */ + bool_t ownerpr; + /* attempt to restore owner/group (-o) + */ + ix_t stcnt; + /* how many subtree args (both inclusive and exclusive) + * are recorded in the subtree pages (-s) + */ + bool_t firststsensepr; + bool_t firststsenseprvalpr; + /* sense of first subtree arg + */ + ix_t stpgcnt; + /* how many pages following the header page are reserved + * for the subtree descriptors + */ + bool_t restoredmpr; + /* restore DMAPI event settings + */ +#ifdef EXTATTR + bool_t restoreextattrpr; + /* restore extended attributes + */ + + ix_t parrestcnt; + /* Count of partialy restored files. Used to speed + * up searches in parrest. + */ + + partial_rest_t parrest[ STREAM_SIMMAX * 2 - 2 ]; + /* record of bytes restored to partially restored files. + * Max possible is two per stream except the first + * drive will never finish another drives file and the + * last drive will never leave a file for another to + * complete. + */ +#endif /* EXTATTR */ + } a; + + /* session state. + */ + struct { + bool_t valpr; + /* until this is true, a resume will ignore (and bzero) + * this structure. validate just prior to applying + * the directory dump, and after all fields marked (A2) + * are correct. invalidate as soon as the session is + * complete, and atomically update all fields marked + * (A1) at the same time. dirattr abstraction must be + * initialized prior to setting this. + */ + time_t accumtime; + /* for measuring elapsed time of restore + */ + uuid_t dumpid; + /* id of dump currently being applied + */ + label_t dumplab; + /* label of the dump being applied (A2) + */ + time_t begintime; + /* set when session begun and each time resumed + */ + bool_t stat_valpr; + /* the following stats are not valid until the + * first media file header has been read. + */ + u_int64_t stat_inocnt; + /* number of non-dir inos to restore during session + */ + u_int64_t stat_inodone; + /* number of non-dir inos restored so far + */ + off64_t stat_datacnt; + /* bytes of ordinary files to restore during session + */ + off64_t stat_datadone; + /* bytes of ordinary files restored so far + */ + ix_t descpgcnt; + /* number of pages mapped for pers. media descriptors + */ + dh_t descfreeh; + /* linked list of free media descriptor alloc objs (A2) + */ + dh_t strmheadh; + /* head of singly-linked list of stream descriptors (A2) + */ + bool_t fullinvpr; + /* have discovered and incorporated a full inventory + * description into pers. may come from online or a + * inventory media file. + */ + bool_t marknorefdonepr; + /* have marked tree nodes as unreferenced by directory + * entries, and nulled dirattr handles. + */ + bool_t dirdonepr; + /* have applied all directories from a dirdump. + */ + bool_t adjrefdonepr; + /* have adjusted marking of nodes no longer referenced + * by directory entries. + */ + bool_t inomapsanitizedonepr; + /* the inomap needs to b sanitized prior to subtree + * or interactive selections + */ + bool_t stdonepr; + /* have applied subtree selections + */ + bool_t interdonepr; + /* have completed interactive subtree dialog + */ + bool_t treepostdonepr; + /* all of the above treep ost-processing steps have + * been completed. + */ + /* + * nondir restore done here + */ + bool_t dirattrdonepr; + /* directory attributes have been restored and + * directory attributes registry has been deleted + */ + bool_t orphdeltriedpr; + /* removed (or tried to remove) orphanage + */ + bool_t inomapdelpr; + /* deleted session ino map + */ + } s; +}; + +typedef struct pers pers_t; + +/* transient state. re-generated during each restore session + */ + +struct tran { + time_t t_starttime; + /* for measuring elapsed time of restore session + */ + size64_t t_dircnt; + size64_t t_dirdonecnt; + /* for displaying stats on directory reconstruction + */ + size64_t t_vmsz; + /* how much vm may be used. recorded here from main, + * passed to tree_init() once we have a valid media + * file header + */ + bool_t t_toconlypr; + /* just display table of contents; don't restore files + */ + bool_t t_noinvupdatepr; + /* true if inventory is NOT to be updated when on-media + * inventory encountered. + */ + bool_t t_dumpidknwnpr; + /* determined during initialization; if false, set during + * per-stream init + */ + bool_t t_dirattrinitdonepr; + bool_t t_namreginitdonepr; + bool_t t_treeinitdonepr; + /* determinied during initialization, used during + * per-stream restore + */ + uuid_t t_reqdumpid; + bool_t t_reqdumpidvalpr; + /* uuid of the dump as requested on cmd line + */ + char * t_reqdumplab; + bool_t t_reqdumplabvalpr; + /* label of the dump as requested on cmd line + */ + char *t_hkdir; + /* absolute pathname of housekeeping directory + */ + intgen_t t_persfd; + /* file descriptor of the persistent state file + */ + sync_t t_sync1; + /* to single-thread attempt to validate command line + * selection of dump with online inventory + */ + sync_t t_sync2; + /* to single-thread dump selection by media scan + */ + sync_t t_sync3; + /* to single-thread attempt to apply dirdump to tree + */ + sync_t t_sync4; + /* to single-thread attempt to do tree post-processing + * prior to non-directory restore + */ + sync_t t_sync5; + /* to single-thread cleanup after applying non-dir restore + */ + qlockh_t t_pilockh; + /* to establish critical regions while updating pers + * inventory + */ +}; + +typedef struct tran tran_t; + + +/* declarations of externally defined global symbols *************************/ + +extern void usage( void ); +extern bool_t preemptchk( void ); +extern char *homedir; +extern bool_t miniroot; +extern bool_t pipeline; +extern bool_t stdoutpiped; +extern char *sistr; +extern size_t pgsz; +extern size_t pgmask; + + +/* forward declarations of locally defined static functions ******************/ + +static void toconly_cleanup( void ); + +static Media_t *Media_create( ix_t thrdix ); +static void Media_indir( Media_t *Mediap ); +static void Media_indir( Media_t *Mediap ); +static void Media_atnondir( Media_t *Mediap ); +static rv_t Media_mfile_next( Media_t *Mediap, + purp_t purp, + sync_t *donesyncp, + dh_t *filehp, + global_hdr_t **grhdrpp, + drive_hdr_t **drhdrpp, + media_hdr_t **mrhdrpp, + content_hdr_t **crhdrpp, + content_inode_hdr_t **scrhdrpp, + drive_t **drivepp, + filehdr_t *fhdr ); +static void Media_end( Media_t *Mediap ); +static bool_t Media_prompt_change( drive_t *drivep, + purp_t purp, + bag_t *bagp, + bool_t knownholespr, + bool_t maybeholespr ); + +static bool_t Inv_validate_cmdline( void ); +static bool_t dumpcompat( bool_t resumepr, + ix_t level, + uuid_t baseid, + bool_t logpr ); +static bool_t promptdumpmatch( ix_t thrdix, + global_hdr_t *grhdrp, + media_hdr_t *mrhdrp, + content_hdr_t *crhdrp, + content_inode_hdr_t *scrhdrp ); + +static void pi_checkpoint( dh_t fileh, + drive_mark_t *drivemarkp, + xfs_ino_t ino, + off64_t off ); +static bool_t pi_transcribe( inv_session_t *sessp ); +static dh_t pi_addfile( Media_t *Mediap, + global_hdr_t *grhdrp, + drive_hdr_t *drhdrp, + media_hdr_t *mrhdrp, + content_inode_hdr_t *scrhdrp, + drive_t * drivep ); +static void pi_seestrmend( ix_t strmix ); +static void pi_seeobjstrmend( ix_t strmix, ix_t mediaix ); +static xfs_ino_t pi_scanfileendino( dh_t fileh ); +static bool_t pi_alldone( void ); +static bag_t * pi_neededobjs_dir_alloc( bool_t *knownholesprp, + bool_t *maybeholesprp ); +static bag_t * pi_neededobjs_nondir_alloc( bool_t *knownholesprp, + bool_t *maybeholesprp, + bool_t showobjindrivepr, + bool_t markskippr ); +static void pi_neededobjs_free( bag_t *bagp ); +static void pi_bracketneededegrps( dh_t thisfileh, + egrp_t *first_egrp, + egrp_t *next_egrp ); +static void pi_update_stats( off64_t sz ); +static void pi_hiteod( ix_t strmix, ix_t objix ); +static void pi_hiteom( ix_t strmix, ix_t objix ); +static void pi_hitnextdump( ix_t strmix, ix_t objix, ix_t lastfileix ); +static bool_t pi_know_no_more_on_object( purp_t purp, ix_t strmix, ix_t objix ); +static bool_t pi_know_no_more_beyond_on_object( purp_t purp, + ix_t strmix, + ix_t objix, + ix_t fileix ); +static void pi_preclean( void ); +static void pi_driveempty( ix_t driveix ); +static void pi_note_indrive( ix_t driveix, uuid_t mediaid ); +static void pi_note_underhead( dh_t thisobjh, dh_t thisfileh ); +static void pi_lock( void ); +static void pi_unlock( void ); + +static rv_t applydirdump( drive_t *drivep, + dh_t fileh, + content_inode_hdr_t *scrhdrp, + filehdr_t *fhdrp ); +static rv_t treepost( char *path1, char *path2 ); +static rv_t applynondirdump( drive_t *drivep, + dh_t fileh, + content_inode_hdr_t *scrhdrp, + char *path1, + char *path2, + filehdr_t *fhdrp ); +static rv_t finalize( char *path1, char *path2 ); +static void wipepersstate( void ); + +static rv_t read_filehdr( drive_t *drivep, filehdr_t *fhdrp, bool_t fhcs ); +static rv_t restore_file( drive_t *drivep, + filehdr_t *fhdrp, + bool_t ehcs, + char *path1, + char *path2 ); +static bool_t restore_reg( drive_t *drivep, + filehdr_t *fhdrp, + rv_t *rvp, + char *path, + bool_t ehcs ); +static bool_t restore_spec( filehdr_t *fhdrp, rv_t *rvp, char *path ); +static bool_t restore_symlink( drive_t *drivep, + filehdr_t *fhdrp, + rv_t *rvp, + char *path, + char *scratchpath, + bool_t ehcs ); +static rv_t read_extenthdr( drive_t *drivep, extenthdr_t *ehdrp, bool_t ehcs ); +static rv_t read_dirent( drive_t *drivep, + direnthdr_t *dhdrp, + size_t direntbufsz, + bool_t dhcs ); +static rv_t discard_padding( size_t sz, drive_t *drivep ); +static rv_t restore_extent( filehdr_t *fhdrp, + extenthdr_t *ehdrp, + int fd, + char *path, + drive_t *drivep, + off64_t *bytesreadp ); +static bool_t askinvforbaseof( uuid_t baseid, inv_session_t *sessp ); +static void addobj( bag_t *bagp, + uuid_t *objidp, + label_t objlabel, + bool_t indrivepr, + ix_t indriveix ); +static size_t cntobj( bag_t *bagp ); +static bool_t gapneeded( egrp_t *firstegrpp, egrp_t *lastegrpp ); +static char * ehdr_typestr( int32_t type ); +static intgen_t egrpcmp( egrp_t *egrpap, egrp_t *egrpbp ); +static void display_dump_label( bool_t lockpr, + intgen_t mllevel, + char *introstr, + global_hdr_t *grhdrp, + media_hdr_t *mrhdrp, + content_hdr_t *crhdrp, + content_inode_hdr_t *scrhdrp ); +static void display_needed_objects( purp_t purp, + bag_t *bagp, + bool_t knownholespr, + bool_t maybeholespr ); +static void set_mcflag( ix_t thrdix ); +static void clr_mcflag( ix_t thrdix ); +static void pi_show( char *introstring ); +static void pi_show_nomloglock( void ); + +#ifdef EXTATTR +static bool_t extattr_init( void ); +static rv_t restore_extattr( drive_t *drivep, + filehdr_t *fhdrp, + char *path1, + char *path2, + bool_t ahcs, + bool_t isdirpr, + dah_t dah ); +static bool_t restore_extattr_cb( void *ctxp, + bool_t islinkpr, + char *path1, + char *path2 ); +static bool_t restore_dir_extattr_cb( char *path, dah_t dah ); +static bool_t restore_dir_extattr_cb_cb( extattrhdr_t *ahdrp, void *ctxp ); +static void setextattr( char *path, extattrhdr_t *ahdrp ); +static void partial_reg(ix_t d_index, xfs_ino_t ino, off64_t fsize, + off64_t offset, off64_t sz); +static bool_t partial_check (xfs_ino_t ino, off64_t fsize); +static bool_t partial_check2 (partial_rest_t *isptr, off64_t fsize); +#endif /* EXTATTR */ +#ifdef F_FSSETDM +static int reopen_invis(char * path, int oflags); +static int do_fssetdm_by_handle( char *path, fsdmidata_t *fdmp); +#endif +static int quotafilecheck(char *type, char *dstdir, char *quotafile); + +/* definition of locally defined global variables ****************************/ + +bool_t content_media_change_needed; +char *media_change_alert_program = NULL; +size_t perssz; + + +/* definition of locally defined static variables *****************************/ + +static pers_t *persp; /* mapped at init, ok to use */ +static tran_t *tranp; /* allocated at init, ok to use */ +static pers_desc_t *descp = 0; /* mapped on the fly; don't use! (see macros) */ +static char *hkdirname = "xfsrestorehousekeepingdir"; +static char *persname = "state"; +static char *perspath = 0; +static bool_t mcflag[ STREAM_SIMMAX ]; /* media change flag */ + + + +/* definition of locally defined global functions ****************************/ + +bool_t +content_init( intgen_t argc, char *argv[ ], size64_t vmsz ) +{ + char *dstdir; /* abs. path to destination dir */ + bool_t cumpr; /* cmd line cumulative restore specification */ + bool_t resumepr;/* cmd line resumed restore specification */ + bool_t existpr; /* cmd line overwrite inhibit specification */ + bool_t newerpr; /* cmd line overwrite inhibit specification */ + time_t newertime = 0; + bool_t changepr;/* cmd line overwrite inhibit specification */ + bool_t interpr; /* cmd line interactive mode requested */ + bool_t ownerpr; /* cmd line chown/chmod requested */ + bool_t restoredmpr; /* cmd line restore dm api attrs specification */ +#ifdef EXTATTR + bool_t restoreextattrpr; /* cmd line restore extended attr spec */ +#endif /* EXTATTR */ +#ifdef SESSCPLT + bool_t sesscpltpr; /* force completion of prev interrupted session */ +#endif /* SESSCPLT */ + ix_t stcnt; /* cmd line number of subtrees requested */ + bool_t firststsensepr; + bool_t firststsenseprvalpr; + ix_t stsz; /* bytes required to record subtree selections */ + ix_t stpgcnt; /* pages required to hold subtree selections */ + ix_t newstpgcnt;/* pages required to hold subtree selections */ + ix_t descpgcnt; /* pages allocated for persistent descriptors */ + struct stat statbuf; + pid_t pid; + intgen_t c; + bool_t ok; + intgen_t rval; + bool_t fullpr; + + /* Calculate the size needed for the persistent inventory + */ + for ( perssz = pgsz; perssz < sizeof(pers_t); perssz += pgsz ) + ; + + /* sanity checks + */ + ASSERT( sizeof( pers_desc_t ) <= PERS_DESCSZ ); + ASSERT( PERS_DESCSZ <= pgsz ); + ASSERT( ! ( pgsz % PERS_DESCSZ )); +#ifdef EXTATTR + ASSERT( sizeof( extattrhdr_t ) == EXTATTRHDR_SZ ); +#endif /* EXTATTR */ + + ASSERT( ! ( perssz % pgsz )); + + ASSERT( SYNC_INIT == 0 ); + + mlog( MLOG_NITTY, + "sizeof( pers_desc_t ) == %d, pgsz == %d, perssz == %d \n", + sizeof( pers_desc_t ), pgsz, perssz ); + + /* allocate transient state + */ + tranp = ( tran_t * )calloc( 1, sizeof( tran_t )); + ASSERT( tranp ); + + /* allocate a qlock for establishing pi critical regions + */ + tranp->t_pilockh = qlock_alloc( QLOCK_ORD_PI ); + + /* record vmsz; will be used later to init tree abstraction + */ + tranp->t_vmsz = vmsz; + + /* record the start time for stats display + */ + tranp->t_starttime = time( 0 ); + + /* get command line options + */ + cumpr = BOOL_FALSE; + resumepr = BOOL_FALSE; + existpr = BOOL_FALSE; + newerpr = BOOL_FALSE; + changepr = BOOL_FALSE; + ownerpr = BOOL_FALSE; + restoredmpr = BOOL_FALSE; +#ifdef EXTATTR + restoreextattrpr = BOOL_TRUE; +#endif /* EXTATTR */ +#ifdef SESSCPLT + sesscpltpr = BOOL_FALSE; +#endif /* SESSCPLT */ + stcnt = 0; + firststsensepr = firststsenseprvalpr = BOOL_FALSE; + stsz = 0; + interpr = BOOL_FALSE; + optind = 1; + opterr = 0; + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + switch ( c ) { + case GETOPT_TOC: + tranp->t_toconlypr = BOOL_TRUE; + break; + case GETOPT_CUMULATIVE: + cumpr = BOOL_TRUE; + break; + case GETOPT_RESUME: + resumepr = BOOL_TRUE; + break; + case GETOPT_EXISTING: + existpr = BOOL_TRUE; + break; + case GETOPT_NEWER: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument missing\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + if ( stat( optarg, &statbuf )) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "unable to get status of -%c argument %s:" + " %s\n", + optopt, + optarg, + strerror( errno )); + return BOOL_FALSE; + } + newerpr = BOOL_TRUE; + newertime = statbuf.st_mtime; + break; + case GETOPT_CHANGED: + changepr = BOOL_TRUE; + break; + case GETOPT_OWNER: + ownerpr = BOOL_TRUE; + break; + case GETOPT_WORKSPACE: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument missing\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + if ( optarg[ 0 ] != '/' ) { + tranp->t_hkdir = path_reltoabs( optarg, + homedir ); + if ( ! tranp->t_hkdir ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument %s is an " + "invalid pathname\n", + optopt, + optarg ); + usage( ); + return BOOL_FALSE; + } + mlog( MLOG_DEBUG, + "alternate workspace path converted " + "from %s to %s\n", + optarg, + tranp->t_hkdir ); + } else { + tranp->t_hkdir = optarg; + } + rval = stat( tranp->t_hkdir, &statbuf ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "cannot stat -%c argument %s (%s): %s\n", + optopt, + optarg, + tranp->t_hkdir, + strerror( errno )); + usage( ); + return BOOL_FALSE; + } + if ( ( statbuf.st_mode & S_IFMT ) != S_IFDIR ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument %s (%s) " + "is not a directory\n", + optopt, + optarg, + tranp->t_hkdir ); + usage( ); + return BOOL_FALSE; + } + + break; + case GETOPT_DUMPLABEL: + if ( tranp->t_reqdumplabvalpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "too many -%c arguments: " + "\"-%c %s\" already given\n", + optopt, + optopt, + tranp->t_reqdumplab ); + usage( ); + return BOOL_FALSE; + } + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument missing\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + if ( strlen( optarg ) + > + sizeofmember( pers_t, s.dumplab )) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument %s too long: max is %d\n", + optopt, + optarg, + sizeofmember( pers_t, s.dumplab )); + usage( ); + return BOOL_FALSE; + } + tranp->t_reqdumplab = optarg; + tranp->t_reqdumplabvalpr = BOOL_TRUE; + break; + case GETOPT_SESSIONID: + if ( tranp->t_reqdumpidvalpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "too many -%c arguments\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument missing\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + if (uuid_parse( optarg, tranp->t_reqdumpid ) < 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument not a valid uuid\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + tranp->t_reqdumpidvalpr = BOOL_TRUE; + break; + case GETOPT_SUBTREE: + case GETOPT_NOSUBTREE: + if ( ! optarg + || + optarg[ 0 ] == 0 + || + optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL, + "-%c argument missing\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + if ( optarg[ 0 ] == '/' ) { + mlog( MLOG_NORMAL, + "-%c argument must be relative\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + stcnt++; + if ( ! firststsenseprvalpr ) { + if ( c == GETOPT_SUBTREE ) { + firststsensepr = BOOL_TRUE; + } else { + firststsensepr = BOOL_FALSE; + } + firststsenseprvalpr = BOOL_TRUE; + } + stsz += sizeof( stdesc_t ) + + + strlen( optarg ) + + + ( STDESCALIGN - 1 ); + stsz &= ~( STDESCALIGN - 1 ); + break; + case GETOPT_INTERACTIVE: + if ( ! dlog_allowed( )) { + mlog( MLOG_NORMAL, + "-%c unavailable: no /dev/tty\n", + GETOPT_INTERACTIVE ); + return BOOL_FALSE; + } + interpr = BOOL_TRUE; + break; + case GETOPT_NOINVUPDATE: + tranp->t_noinvupdatepr = BOOL_TRUE; + break; + case GETOPT_SETDM: + restoredmpr = BOOL_TRUE; + break; + case GETOPT_ALERTPROG: + if ( ! optarg || optarg[ 0 ] == '-' ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c argument missing\n", + optopt ); + usage( ); + return BOOL_FALSE; + } + media_change_alert_program = optarg; + break; +#ifdef EXTATTR + case GETOPT_NOEXTATTR: + restoreextattrpr = BOOL_FALSE; + break; +#endif /* EXTATTR */ +#ifdef SESSCPLT + case GETOPT_SESSCPLT: + sesscpltpr = BOOL_TRUE; + break; +#endif /* SESSCPLT */ + } + } + + /* command line option error checking + */ + if ( cumpr && tranp->t_toconlypr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c and -%c option cannot be used together\n", + GETOPT_TOC, + GETOPT_CUMULATIVE ); + usage( ); + return BOOL_FALSE; + } + if ( resumepr && tranp->t_toconlypr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c and -%c option cannot be used together\n", + GETOPT_TOC, + GETOPT_RESUME ); + usage( ); + return BOOL_FALSE; + } + + /* the user may specify stdin as the restore source stream, + * by a single dash ('-') with no option letter. This must + * appear between the last lettered argument and the destination + * directory pathname. + */ + if ( optind < argc && ! strcmp( argv[ optind ], "-" )) { + optind++; + } + + /* the last argument must be the destination directory. not + * required if table-of-contents display, or if a resumed restore + * or a delta restore. + */ + if ( ! tranp->t_toconlypr ) { + if ( optind >= argc ) { + dstdir = 0; + } else { + if ( argv[ optind ][ 0 ] != '/' ) { + dstdir = path_reltoabs( argv[ optind ], + homedir ); + if ( ! dstdir ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "destination directory %s " + "invalid pathname\n", + argv[ optind ] ); + usage( ); + return BOOL_FALSE; + } + mlog( MLOG_DEBUG, + "restore destination path converted " + "from %s to %s\n", + argv[ optind ], + dstdir ); + } else { + dstdir = argv[ optind ]; + } + rval = stat( dstdir, &statbuf ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "cannot stat destination directory %s: " + "%s\n", + dstdir, + strerror( errno )); + usage( ); + return BOOL_FALSE; + } + if ( ( statbuf.st_mode & S_IFMT ) != S_IFDIR ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "specified destination %s " + "is not a directory\n", + dstdir ); + usage( ); + return BOOL_FALSE; + } + } + } else { + if ( optind < argc ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "do not specify destination directory " + "if contents only restore invoked (-%c option)\n", + GETOPT_TOC ); + usage( ); + return BOOL_FALSE; + } + dstdir = "."; + } + + /* generate a full pathname for the housekeeping dir. + * the housekeeping dir will by default be placed in the + * destination directory, unless this is a toc, in which case + * it will be placed in the current directory. in either case, an + * alternate directory may be specified on the command line. + * if this is toconly, modify the housekeeping dir's name with + * the pid. + */ + if ( ! tranp->t_hkdir ) { + if ( tranp->t_toconlypr ) { + if (isinxfs(homedir) == BOOL_FALSE) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "Current directory not XFS: %s\n", homedir); + return BOOL_FALSE; + } + tranp->t_hkdir = homedir; + } else { + if ( ! dstdir ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "destination directory " + "not specified\n" ); + usage( ); + return BOOL_FALSE; + } else { + tranp->t_hkdir = dstdir; + } + } + } + if ( tranp->t_toconlypr ) { + pid = getpid( ); + } else { + pid = 0; + } + tranp->t_hkdir = open_pathalloc( tranp->t_hkdir, hkdirname, pid ); + + /* if this is a table-of-contents only restore, register an + * exit handler to get rid of the housekeeping directory and + * its contents. NOTE: needs several tran fields initialized! + */ + if ( tranp->t_toconlypr ) { + atexit( toconly_cleanup ); + } + + /* create housekeeping dir if not present + */ + rval = mkdir( tranp->t_hkdir, S_IRWXU ); + if ( rval && errno != EEXIST ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "unable to create %s: %s\n", + tranp->t_hkdir, + strerror( errno )); + return BOOL_FALSE; + } + + /* build a full pathname to pers. state file + */ + ASSERT( ! perspath ); + perspath = open_pathalloc( tranp->t_hkdir, persname, 0 ); + + /* open, creating if non-existent + */ + tranp->t_persfd = open( perspath, + O_CREAT | O_RDWR, + S_IRUSR | S_IWUSR ); + if ( tranp->t_persfd < 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "could not open/create persistent state file %s: %s\n", + perspath, + strerror( errno )); + return BOOL_FALSE; + } + + /* temporarily mmap just the header, and validate the command line + * arguments. three cases: no dumps applied so far, or one or more + * dumps applied completely, or restore session was interrupted + */ + persp = ( pers_t * ) mmap_autogrow(perssz, tranp->t_persfd, 0); + + if ( persp == ( pers_t * )-1 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "could not map persistent state file hdr %s: %s\n", + perspath, + strerror( errno )); + return BOOL_FALSE; + } + if ( ! persp->a.valpr ) { + if ( ! dstdir ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "destination directory not specified\n" ); + usage( ); + return BOOL_FALSE; + } + if ( strlen( dstdir ) >= sizeofmember( pers_t, a.dstdir )) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "destination directory pathname too long: " + "max is %d characters\n", + sizeofmember( pers_t, a.dstdir ) - 1 ); + usage( ); + return BOOL_FALSE; + } + if ( resumepr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c option invalid: there is no " + "interrupted restore to resume\n", + GETOPT_RESUME ); + usage( ); + return BOOL_FALSE; + } +#ifdef SESSCPLT + if ( sesscpltpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c option invalid: there is no " + "interrupted restore to force completion of\n", + GETOPT_SESSCPLT ); + usage( ); + return BOOL_FALSE; + } +#endif /* SESSCPLT */ + } else if ( ! persp->s.valpr ) { + if ( ! cumpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "must rm -rf %s prior to noncumulative restore\n", + tranp->t_hkdir ); + return BOOL_FALSE; + } + if ( resumepr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c option invalid: there is no " + "interrupted restore to resume\n", + GETOPT_RESUME ); + usage( ); + return BOOL_FALSE; + } +#ifdef SESSCPLT + if ( sesscpltpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c option invalid: there is no " + "interrupted restore to force completion of\n", + GETOPT_SESSCPLT ); + usage( ); + return BOOL_FALSE; + } +#endif /* SESSCPLT */ + if ( existpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c valid only when initiating " + "cumulative restore\n", + GETOPT_EXISTING ); + return BOOL_FALSE; + } + if ( newerpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c valid only when initiating " + "cumulative restore\n", + GETOPT_NEWER ); + return BOOL_FALSE; + } + if ( changepr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c valid only when initiating " + "cumulative restore\n", + GETOPT_CHANGED ); + return BOOL_FALSE; + } + if ( ownerpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c valid only when initiating " + "cumulative restore\n", + GETOPT_OWNER ); + return BOOL_FALSE; + } + if ( stcnt ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c and -%c valid only when initiating " + "cumulative restore\n", + GETOPT_SUBTREE, + GETOPT_NOSUBTREE ); + return BOOL_FALSE; + } + } else { +#ifdef SESSCPLT + if ( ! resumepr && ! sesscpltpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c option required to resume " + "or " + "-%c option required to force completion of " + "previously " + "interrupted restore session\n", + GETOPT_RESUME, + GETOPT_SESSCPLT ); + return BOOL_FALSE; + } +#else /* SESSCPLT */ + if ( ! resumepr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c option required to resume previously " + "interrupted restore session\n", + GETOPT_RESUME ); + return BOOL_FALSE; + } +#endif /* SESSCPLT */ + if ( tranp->t_reqdumplabvalpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c valid only when initiating restore\n", + GETOPT_DUMPLABEL ); + return BOOL_FALSE; + } + if ( tranp->t_reqdumpidvalpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c valid only when initiating restore\n", + GETOPT_SESSIONID ); + return BOOL_FALSE; + } + if ( existpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c valid only when initiating restore\n", + GETOPT_EXISTING ); + return BOOL_FALSE; + } + if ( newerpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c valid only when initiating restore\n", + GETOPT_NEWER ); + return BOOL_FALSE; + } + if ( changepr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c valid only when initiating restore\n", + GETOPT_CHANGED ); + return BOOL_FALSE; + } + if ( ownerpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c valid only when initiating restore\n", + GETOPT_OWNER ); + return BOOL_FALSE; + } + if ( interpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c valid only when initiating restore\n", + GETOPT_INTERACTIVE ); + return BOOL_FALSE; + } + if ( stcnt ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c and -%c valid only when initiating restore\n", + GETOPT_SUBTREE, + GETOPT_NOSUBTREE ); + return BOOL_FALSE; + } + } + + if ( persp->a.valpr ) { + if ( restoredmpr && persp->a.restoredmpr != restoredmpr) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c cannot reset flag from previous restore\n", + GETOPT_SETDM ); + return BOOL_FALSE; + } +#ifdef EXTATTR + if ( ! restoreextattrpr && + persp->a.restoreextattrpr != restoreextattrpr) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "-%c cannot reset flag from previous restore\n", + GETOPT_NOEXTATTR ); + return BOOL_FALSE; + } +#endif /* EXTATTR */ + } + + /* force owner option if root + */ + ownerpr = ( geteuid( ) == 0 ) ? BOOL_TRUE : ownerpr; + +#ifdef SESSCPLT + /* force completion of interrupted restore if asked to do so + */ + if ( sesscpltpr ) { + char *path1; + char *path2; + rv_t rv; + intgen_t rval; + + path1 = ( char * )calloc( 1, 2 * MAXPATHLEN ); + ASSERT( path1 ); + path2 = ( char * )calloc( 1, 2 * MAXPATHLEN ); + ASSERT( path2 ); + ASSERT( persp->a.valpr ); + ASSERT( persp->s.valpr ); + rval = chdir( persp->a.dstdir ); + if ( rval ) { + mlog( MLOG_NORMAL, + "chdir %s failed: %s\n", + persp->a.dstdir, + strerror( errno )); + return BOOL_FALSE; + } + ok = dirattr_init( tranp->t_hkdir, BOOL_TRUE, ( u_int64_t )0 ); + if ( ! ok ) { + return BOOL_FALSE; + } + ok = namreg_init( tranp->t_hkdir, BOOL_TRUE, ( u_int64_t )0 ); + if ( ! ok ) { + return BOOL_FALSE; + } + ok = inomap_sync_pers( tranp->t_hkdir ); + if ( ! ok ) { + return BOOL_FALSE; + } + + /* This is only a full restore if we're doing a level + * 0 restore. + */ + if (persp->a.dumpcnt == 0) { + fullpr = BOOL_TRUE; + } else { + fullpr = BOOL_FALSE; + } + + ok = tree_sync( tranp->t_hkdir, + persp->a.dstdir, + tranp->t_toconlypr, + fullpr ); + if ( ! ok ) { + return BOOL_FALSE; + } + rv = finalize( path1, path2 ); + free( ( void * )path1 ); + free( ( void * )path2 ); + switch ( rv ) { + case RV_OK: + break; + case RV_ERROR: + return EXIT_ERROR; + case RV_INTR: + return EXIT_NORMAL; + case RV_CORE: + default: + return EXIT_FAULT; + } + } +#endif /* SESSCPLT */ + + /* for the three cases, calculate old and new mapping params + * and wipe partial state + */ + if ( ! persp->a.valpr ) { + stpgcnt = 0; + newstpgcnt = ( stsz + pgmask ) / pgsz; + descpgcnt = 0; + memset( ( void * )persp, 0, sizeof( pers_t )); + } else if ( ! persp->s.valpr ) { + stpgcnt = persp->a.stpgcnt; + newstpgcnt = stpgcnt; + descpgcnt = 0; + memset( ( void * )&persp->s, 0, sizeofmember( pers_t, s )); + } else { + stpgcnt = persp->a.stpgcnt; + newstpgcnt = stpgcnt; + descpgcnt = persp->s.descpgcnt; + ASSERT( resumepr ); + mlog( MLOG_VERBOSE, + "resuming restore previously begun %s\n", + ctimennl( &persp->s.begintime )); + persp->s.begintime = time( 0 ); + } + + /* unmap temp mapping of hdr, truncate, and remap hdr/subtrees + */ + rval = munmap( ( void * )persp, perssz ); + ASSERT( ! rval ); + rval = ftruncate( tranp->t_persfd, ( off_t )perssz + + + ( off_t )( stpgcnt + descpgcnt ) + * + ( off_t )pgsz ); + ASSERT( ! rval ); + stpgcnt = newstpgcnt; + persp = ( pers_t * ) mmap_autogrow( perssz + stpgcnt * pgsz, + tranp->t_persfd, 0); + if ( persp == ( pers_t * )-1 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "could not map persistent state file %s: %s\n", + perspath, + strerror( errno )); + return BOOL_FALSE; + } + + /* if first restore session, record cmd line args and subtrees + * and start time. + */ + if ( ! persp->a.valpr ) { + stdesc_t *stdescp; + + strcpy( persp->a.dstdir, dstdir ); + persp->a.dstdirisxfspr = isinxfs( dstdir ); + if ( cumpr ) { + persp->a.cumpr = cumpr; + } + if ( interpr ) { + persp->a.interpr = interpr; + } + if ( existpr ) { + persp->a.existpr = existpr; + } + if ( changepr ) { + persp->a.changepr = changepr; + } + if ( ownerpr ) { + persp->a.ownerpr = ownerpr; + } + if ( newerpr ) { + persp->a.newerpr = newerpr; + persp->a.newertime = newertime; + } + persp->a.restoredmpr = restoredmpr; +#ifdef EXTATTR + if ( ! persp->a.dstdirisxfspr ) { + restoreextattrpr = BOOL_FALSE; + } + persp->a.restoreextattrpr = restoreextattrpr; +#endif /* EXTATTR */ + persp->a.stcnt = stcnt; + persp->a.firststsensepr = firststsensepr; + persp->a.firststsenseprvalpr = firststsenseprvalpr; + persp->a.stpgcnt = stpgcnt; + optind = 1; + opterr = 0; + stdescp = ( stdesc_t * )( ( char * )persp + perssz ); + while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { + size_t stdsz; + switch ( c ) { + case GETOPT_SUBTREE: + case GETOPT_NOSUBTREE: + stdescp->std_sensepr = ( c == GETOPT_SUBTREE ) + ? + BOOL_TRUE + : + BOOL_FALSE; + stdsz = sizeof( stdesc_t ) + + + strlen( optarg ) + + + ( STDESCALIGN - 1 ); + stdsz &= ~( STDESCALIGN - 1 ); + ASSERT( stdsz <= ( size_t )OFFMAX ); + stdescp->std_nextoff = ( off_t )stdsz; + strcpy( stdescp->std_path, optarg ); + stdescp = ( stdesc_t * ) + ( ( char * )stdescp + stdsz ); + stcnt--; + break; + } + } + ASSERT( stcnt == 0 ); + } + +#ifdef EXTATTR + /* initialize the local extattr abstraction. must be done even if + * we don't intend to restore extended attributes + */ + ok = extattr_init( ); + if ( ! ok ) { + return BOOL_FALSE; + } +#endif /* EXTATTR */ + + /* map in pers. inv. descriptors, if any. NOTE: this ptr is to be + * referenced ONLY via the macros provided; the descriptors will be + * occasionally remapped, causing the ptr to change. + */ + ASSERT( ! descp ); + if ( descpgcnt ) { + descp = ( pers_desc_t * ) mmap_autogrow( descpgcnt * pgsz, + tranp->t_persfd, + ( off_t )perssz + + + ( off_t )( stpgcnt * pgsz )); + if ( descp == ( pers_desc_t * )-1 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "could not map persistent state file inv %s: " + "%s (%d)\n", + perspath, + strerror( errno ), + errno ); + descp = 0; + return BOOL_FALSE; + } + pi_preclean( ); + } + + /* if resuming an interrupted restore, indicate we know the id + * of the dump session being restored. otherwise, it will be determined + * during coordination of per-drive threads. + */ + if ( persp->a.valpr && persp->s.valpr ) { + persp->s.begintime = time( 0 ); + tranp->t_dumpidknwnpr = BOOL_TRUE; + } + + /* sync up with the directory attributes registry. + * starts fresh with each dump session restored. + * determine if full init needed instead. + */ + if ( persp->a.valpr && persp->s.valpr ) { + ok = dirattr_init( tranp->t_hkdir, BOOL_TRUE, ( u_int64_t )0 ); + if ( ! ok ) { + return BOOL_FALSE; + } + tranp->t_dirattrinitdonepr = BOOL_TRUE; + } + + /* sync up with the name registry. created by the + * first session, retained by subsequent sessions. + * determine if full init needed instead. + */ + if ( persp->a.valpr ) { + ok = namreg_init( tranp->t_hkdir, BOOL_TRUE, ( u_int64_t )0 ); + if ( ! ok ) { + return BOOL_FALSE; + } + tranp->t_namreginitdonepr = BOOL_TRUE; + } + + /* sync up with the inomap abstraction. created anew with each fresh + * restore session, but persistent after tree updated with dirdump. + * determine if full init needed instead. + */ + ok = inomap_sync_pers( tranp->t_hkdir ); + if ( ! ok ) { + return BOOL_FALSE; + } + + /* sync up with the tree abstraction. created by the + * first session, retained by subsequent sessions. + * don't call tree_init( ) from here; can only be called + * when a valid media file header is at hand. + */ + if ( persp->a.valpr ) { + /* This is only a full restore if we're doing a level + * 0 restore. + */ + if (persp->a.dumpcnt == 0) { + fullpr = BOOL_TRUE; + } else { + fullpr = BOOL_FALSE; + } + + ok = tree_sync( tranp->t_hkdir, + persp->a.dstdir, + tranp->t_toconlypr, + fullpr ); + if ( ! ok ) { + return BOOL_FALSE; + } + tranp->t_treeinitdonepr = BOOL_TRUE; + } + + /* set media change flags to FALSE; + */ + { + ix_t ix; + ix_t endix = sizeof( mcflag ) + / + sizeof( mcflag[ 0 ] ); + for ( ix = 0 ; ix < endix ; ix++ ) { + mcflag[ ix ] = BOOL_FALSE; + } + } + content_media_change_needed = BOOL_FALSE; + + pi_show( " at initialization" ); + return BOOL_TRUE; +} + +/* stream thread entry point - returns exit code + */ +intgen_t +content_stream_restore( ix_t thrdix ) +{ + dh_t fileh; + Media_t *Mediap; /* local media abstraction */ + char *path1; + char *path2; + drive_t *drivep; + intgen_t dcaps; + global_hdr_t *grhdrp; + drive_hdr_t *drhdrp; + media_hdr_t *mrhdrp; + content_hdr_t *crhdrp; + content_inode_hdr_t *scrhdrp; + filehdr_t fhdr; /* save hdr terminating dir restore */ + uuid_t lastdumprejectedid; + rv_t rv; + bool_t ok; + intgen_t rval; + + /* allocate two path buffers + */ + path1 = ( char * )calloc( 1, 2 * MAXPATHLEN ); + ASSERT( path1 ); + path2 = ( char * )calloc( 1, 2 * MAXPATHLEN ); + ASSERT( path2 ); + + /* set the current directory to dstdir. the tree abstraction + * depends on the current directory being the root of the + * destination file system. + */ + rval = chdir( persp->a.dstdir ); + if ( rval ) { + mlog( MLOG_NORMAL, + "chdir %s failed: %s\n", + persp->a.dstdir, + strerror( errno )); + return EXIT_ERROR; + } + + /* set my file creation mask to zero, to avoid modifying the + * dumped mode bits + */ + ( void )umask( 0 ); + + /* initialize the Media abstraction + */ + Mediap = Media_create( thrdix ); + + /* if we don't know the dump session id to restore, + * first see if command line options can be validated + * against the online inventory to identify it. only + * one stream needs to do this; the others just wait. + * side-effect of validation is to incorporate the online + * inventory into the persistent state. + */ + if ( tranp->t_dumpidknwnpr ) { + tranp->t_sync1 = SYNC_DONE; + } + while ( tranp->t_sync1 != SYNC_DONE ) { + lock( ); + if ( tranp->t_sync1 == SYNC_BUSY ) { + unlock( ); + sleep( 1 ); + if ( cldmgr_stop_requested( )) { + return EXIT_NORMAL; + } + continue; + } + if ( tranp->t_sync1 == SYNC_DONE ) { + unlock( ); + continue; + } + tranp->t_sync1 = SYNC_BUSY; + unlock( ); + mlog( MLOG_DEBUG, + "checking and validating command line dump id/label\n" ); + ok = Inv_validate_cmdline( ); + /* side-effect - searches for and incorporates online inv + * into pi, and makes persp->s.dumpid valid. + */ + if ( ok == BOOL_ERROR ) { + return EXIT_ERROR; + } + tranp->t_dumpidknwnpr = ok; + tranp->t_sync1 = SYNC_DONE; + } + + /* if we still don't know the session to restore, search the + * media for a match either to the command line arguments or + * until the operator selects a media file from the desired + * dump. + */ + if ( tranp->t_dumpidknwnpr ) { + tranp->t_sync2 = SYNC_DONE; + } + uuid_clear(lastdumprejectedid); + if ( tranp->t_sync2 != SYNC_DONE ) { + mlog( MLOG_VERBOSE, + "searching media for dump\n" ); + } + while ( tranp->t_sync2 != SYNC_DONE ) { + bool_t matchpr; + inv_session_t *sessp; + bool_t resumepr; + ix_t level; + uuid_t *baseidp; + + rv = Media_mfile_next( Mediap, + PURP_SEARCH, + &tranp->t_sync2, + 0, + &grhdrp, + &drhdrp, + &mrhdrp, + &crhdrp, + &scrhdrp, + &drivep, + &fhdr ); + switch ( rv ) { + case RV_OK: + break; + case RV_DONE: + case RV_NOMORE: + continue; + case RV_INTR: + case RV_QUIT: + case RV_DRIVE: + Media_end( Mediap ); + return EXIT_NORMAL; + case RV_CORE: + default: + Media_end( Mediap ); + return EXIT_FAULT; + } + dcaps = drivep->d_capabilities; + + lock( ); + while ( tranp->t_sync2 == SYNC_BUSY ) { + unlock( ); + sleep( 1 ); + if ( cldmgr_stop_requested( )) { + Media_end( Mediap ); + return EXIT_NORMAL; + } + lock( ); + } + if ( tranp->t_sync2 == SYNC_DONE ) { + unlock( ); + continue; + } + tranp->t_sync2 = SYNC_BUSY; + + unlock( ); + mlog( MLOG_DEBUG, + "dump found: checking\n" ); + matchpr = BOOL_FALSE; + resumepr = ( scrhdrp->cih_dumpattr & CIH_DUMPATTR_RESUME ); + ASSERT( scrhdrp->cih_level >= 0 ); + level = ( ix_t )scrhdrp->cih_level; + baseidp = resumepr + ? + &scrhdrp->cih_resume_id + : + &scrhdrp->cih_last_id; + if ( tranp->t_reqdumpidvalpr ) { + if ( uuid_compare( tranp->t_reqdumpid, + grhdrp->gh_dumpid) == 0) { + matchpr = BOOL_TRUE; + display_dump_label( BOOL_TRUE, /* lock */ + MLOG_VERBOSE, + "found dump " + "matching specified id:\n", + grhdrp, + mrhdrp, + crhdrp, + scrhdrp ); + } + } else if ( tranp->t_reqdumplabvalpr ) { + if ( ! strncmp( tranp->t_reqdumplab, + grhdrp->gh_dumplabel, + sizeof( grhdrp->gh_dumplabel ))) { + matchpr = BOOL_TRUE; + display_dump_label( BOOL_TRUE, /* lock */ + MLOG_VERBOSE, + "found dump " + "matching specified label:\n", + grhdrp, + mrhdrp, + crhdrp, + scrhdrp ); + } + } else if ( dumpcompat( resumepr, + level, + *baseidp, + BOOL_FALSE )) { + if ( uuid_compare( lastdumprejectedid, + grhdrp->gh_dumpid) == 0) { + matchpr = BOOL_FALSE; + } else { + if ( dlog_allowed( ) + && + ( ( dcaps & DRIVE_CAP_FILES ) + || + ( dcaps & DRIVE_CAP_REMOVABLE ) + || + drivecnt > 1 )) { + matchpr = promptdumpmatch( thrdix, + grhdrp, + mrhdrp, + crhdrp, + scrhdrp ); + } else { + matchpr = BOOL_TRUE; + display_dump_label( BOOL_TRUE,/* lock */ + MLOG_VERBOSE, + "dump " + "description: \n", + grhdrp, + mrhdrp, + crhdrp, + scrhdrp ); + } + } + } + if ( cldmgr_stop_requested( )) { + Media_end( Mediap ); + return EXIT_NORMAL; + } + if ( ! matchpr ) { + Media_end( Mediap ); + uuid_copy(lastdumprejectedid, grhdrp->gh_dumpid); + tranp->t_sync2 = SYNC_INIT; + if ( ! dlog_allowed( ) + || + ( ! ( dcaps & DRIVE_CAP_FILES ) + && + ! ( dcaps & DRIVE_CAP_REMOVABLE ))) { + return EXIT_NORMAL; + } + continue; + } + if ( ! dumpcompat( resumepr, level, *baseidp, BOOL_TRUE )) { + Media_end( Mediap ); + return EXIT_ERROR; + } + strncpyterm( persp->s.dumplab, + grhdrp->gh_dumplabel, + sizeof( persp->s.dumplab )); + sessp = 0; + +#ifdef PIPEINVFIX + /* don't look at the online inventory if the input is piped + */ + if ( ! drivep->d_isnamedpipepr + && + ! drivep->d_isunnamedpipepr ) { +#endif /* PIPEINVFIX */ + ok = inv_get_session_byuuid( &grhdrp->gh_dumpid, + &sessp ); + if ( ok && sessp ) { + mlog( MLOG_VERBOSE, + "using online session inventory\n" ); + persp->s.fullinvpr = pi_transcribe( sessp ); + inv_free_session( &sessp ); + } +#ifdef PIPEINVFIX + } +#endif /* PIPEINVFIX */ + fileh = pi_addfile( Mediap, + grhdrp, + drhdrp, + mrhdrp, + scrhdrp, + drivep ); + /* done here because Media_mfile_next doesn't know + * if this is a match + */ + if ( fileh == DH_NULL ) { + return EXIT_FAULT; + } + uuid_copy(persp->s.dumpid,grhdrp->gh_dumpid); + persp->s.begintime = time( 0 ); + tranp->t_dumpidknwnpr = BOOL_TRUE; + tranp->t_sync2 = SYNC_DONE; + } + + /* all drives coordinate in attempt to apply session dir dump. + * only one actually completes. + */ + if ( persp->s.dirdonepr ) { + tranp->t_sync3 = SYNC_DONE; + } + if ( tranp->t_sync3 != SYNC_DONE ) { + mlog( MLOG_VERBOSE, + "searching media for directory dump\n" ); + } + while ( tranp->t_sync3 != SYNC_DONE ) { + rv = Media_mfile_next( Mediap, + PURP_DIR, + &tranp->t_sync3, + &fileh, + &grhdrp, + &drhdrp, + &mrhdrp, + &crhdrp, + &scrhdrp, + &drivep, + &fhdr ); + switch ( rv ) { + case RV_OK: + break; + case RV_DONE: + case RV_NOMORE: + continue; + case RV_INTR: + case RV_QUIT: + case RV_DRIVE: + Media_end( Mediap ); + return EXIT_NORMAL; + case RV_CORE: + default: + Media_end( Mediap ); + return EXIT_FAULT; + } + dcaps = drivep->d_capabilities; + ASSERT( fileh != DH_NULL ); + lock( ); + if ( tranp->t_sync3 == SYNC_BUSY ) { + unlock( ); + mlog( MLOG_TRACE, + "waiting for directories to be restored\n" ); + lock( ); + } + while ( tranp->t_sync3 == SYNC_BUSY ) { + unlock( ); + sleep( 1 ); + if ( cldmgr_stop_requested( )) { + Media_end( Mediap ); + return EXIT_NORMAL; + } + lock( ); + } + if ( tranp->t_sync3 == SYNC_DONE ) { + unlock( ); + continue; + } + tranp->t_sync3 = SYNC_BUSY; + unlock( ); + if ( ! tranp->t_dirattrinitdonepr ) { + mlog( MLOG_TRACE, + "initializing directory attributes registry\n" ); + mlog( MLOG_NITTY, + "content_stream_restore: dircnt %llu\n", + scrhdrp->cih_inomap_dircnt ); + ok = dirattr_init( tranp->t_hkdir, + BOOL_FALSE, + scrhdrp->cih_inomap_dircnt ); + if ( ! ok ) { + Media_end( Mediap ); + return EXIT_ERROR; + } + tranp->t_dirattrinitdonepr = BOOL_TRUE; + } + + if ( ! tranp->t_namreginitdonepr ) { + mlog( MLOG_TRACE, + "initializing directory entry name registry\n" ); + ok = namreg_init( tranp->t_hkdir, + BOOL_FALSE, + scrhdrp->cih_inomap_dircnt + + + scrhdrp->cih_inomap_nondircnt ); + if ( ! ok ) { + Media_end( Mediap ); + return EXIT_ERROR; + } + tranp->t_namreginitdonepr = BOOL_TRUE; + } + + if ( ! tranp->t_treeinitdonepr ) { + bool_t fullpr; + + fullpr = ( scrhdrp->cih_level + == + 0 ) + && + ! ( scrhdrp->cih_dumpattr + & + CIH_DUMPATTR_RESUME ); + + mlog( MLOG_TRACE, + "initializing directory hierarchy image\n" ); + ok = tree_init( tranp->t_hkdir, + persp->a.dstdir, + tranp->t_toconlypr, + persp->a.ownerpr, + scrhdrp->cih_rootino, + scrhdrp->cih_inomap_firstino, + scrhdrp->cih_inomap_lastino, + scrhdrp->cih_inomap_dircnt, + scrhdrp->cih_inomap_nondircnt, + tranp->t_vmsz, + fullpr, + persp->a.restoredmpr ); + if ( ! ok ) { + Media_end( Mediap ); + return EXIT_ERROR; + } + tranp->t_treeinitdonepr = BOOL_TRUE; + } + + /* commit the session and accumulative state + */ + persp->s.valpr = BOOL_TRUE; + persp->a.valpr = BOOL_TRUE; + + mlog( MLOG_VERBOSE, + "reading directories\n" ); + rv = applydirdump( drivep, fileh, scrhdrp, &fhdr ); + switch ( rv ) { + case RV_OK: + DH2F( fileh )->f_dirtriedpr = BOOL_TRUE; + Media_atnondir( Mediap ); + tranp->t_sync3 = SYNC_DONE; + break; + case RV_CORRUPT: + Media_indir( Mediap ); + DH2F( fileh )->f_dirtriedpr = BOOL_TRUE; + tranp->t_sync3 = SYNC_INIT; + break; + case RV_INTR: + case RV_DRIVE: + Media_end( Mediap ); + return EXIT_NORMAL; + case RV_CORE: + default: + Media_end( Mediap ); + return EXIT_FAULT; + } + } + + /* now let one thread do all tree post-processing prior to + * non-dir restore + */ + if ( persp->s.treepostdonepr ) { + tranp->t_sync4 = SYNC_DONE; + } + while ( tranp->t_sync4 != SYNC_DONE ) { + lock( ); + if ( tranp->t_sync4 == SYNC_BUSY ) { + unlock( ); + mlog( MLOG_TRACE, + "waiting for directory post-processing " + "to complete\n" ); + lock( ); + } + while ( tranp->t_sync4 == SYNC_BUSY ) { + unlock( ); + sleep( 1 ); + if ( cldmgr_stop_requested( )) { + Media_end( Mediap ); + return EXIT_NORMAL; + } + lock( ); + } + if ( tranp->t_sync4 == SYNC_DONE ) { + unlock( ); + continue; + } + tranp->t_sync4 = SYNC_BUSY; + unlock( ); + mlog( MLOG_VERBOSE, + "directory post-processing\n" ); + rv = treepost( path1, path2 ); + switch ( rv ) { + case RV_OK: + break; + case RV_ERROR: + Media_end( Mediap ); + return EXIT_ERROR; + case RV_INTR: + Media_end( Mediap ); + return EXIT_INTERRUPT; + case RV_CORE: + default: + Media_end( Mediap ); + return EXIT_FAULT; + } + + /* now that we have a tree and inomap, scan the + * pi to see what media files can be skipped. + * this func has cancer: too many flags and + * side-effects! + */ + { + bool_t dummyknownholespr; + bool_t dummymaybeholespr; + bag_t *bagp = pi_neededobjs_nondir_alloc( &dummyknownholespr, + &dummymaybeholespr, + BOOL_FALSE, + BOOL_TRUE ); + if ( bagp ) { + pi_neededobjs_free( bagp ); + bagp = 0; + } + } + + /* release exclusion + */ + tranp->t_sync4 = SYNC_DONE; + } + + /* now all are free to do concurrent non-dir restore! + * apply media files until there are no more, or we are interrupted + */ + for (;;) { + mlog( MLOG_DEBUG, + "getting next media file for non-dir restore\n" ); + rv = Media_mfile_next( Mediap, + PURP_NONDIR, + 0, + &fileh, + &grhdrp, + &drhdrp, + &mrhdrp, + &crhdrp, + &scrhdrp, + &drivep, + &fhdr ); + if ( rv == RV_NOMORE ) { + break; + } + switch ( rv ) { + case RV_OK: + break; + case RV_INTR: + case RV_QUIT: + case RV_DRIVE: + Media_end( Mediap ); + return EXIT_NORMAL; + case RV_CORE: + default: + Media_end( Mediap ); + return EXIT_FAULT; + } + dcaps = drivep->d_capabilities; + ASSERT( fileh > DH_NULL ); + if ( tranp->t_toconlypr ) { + mlog( MLOG_VERBOSE, + "reading non-directory files\n" ); + } else { + mlog( MLOG_VERBOSE, + "restoring non-directory files\n" ); + } + mlog( MLOG_TRACE, + "media file %u in " + "object %u " + "of stream %u\n", + mrhdrp->mh_mediafileix, + mrhdrp->mh_mediaix, + drhdrp->dh_driveix ); + mlog( MLOG_DEBUG, + "file %u in stream, " + "file %u in dump %u on object\n", + mrhdrp->mh_dumpfileix, + mrhdrp->mh_dumpmediafileix, + mrhdrp->mh_dumpmediaix ); + rv = applynondirdump( drivep, + fileh, + scrhdrp, + path1, + path2, + &fhdr ); + switch ( rv ) { + case RV_OK: + DH2F( fileh )->f_nondirdonepr = BOOL_TRUE; +#ifdef EOMFIX + Media_end( Mediap ); +#endif /* EOMFIX */ + break; + case RV_INTR: + Media_end( Mediap ); + return EXIT_NORMAL; + case RV_DRIVE: + Media_end( Mediap ); + return EXIT_NORMAL; + case RV_CORE: + default: + Media_end( Mediap ); + return EXIT_FAULT; + } + } + + /* finally, choose one thread to do final processing + * and cleanup. the winner waits, the losers all exit. + * once the losers exit, the winner can perform cleanup. + */ + lock( ); + if ( tranp->t_sync5 == SYNC_BUSY ) { + unlock( ); +#ifndef EOMFIX + Media_end( Mediap ); +#endif /* ! EOMFIX */ + return EXIT_NORMAL; + } + tranp->t_sync5 = SYNC_BUSY; + unlock( ); + if ( ! miniroot ) { + if ( drivecnt > 1 ) { + mlog( MLOG_TRACE, + "waiting for other streams to exit\n" ); + } + while ( cldmgr_otherstreamsremain( thrdix )) { + sleep( 1 ); + } + } + + mlog( MLOG_DEBUG, + "tree finalize\n" ); + rv = finalize( path1, path2 ); + switch ( rv ) { + case RV_OK: + break; + case RV_ERROR: +#ifndef EOMFIX + Media_end( Mediap ); +#endif /* ! EOMFIX */ + return EXIT_ERROR; + case RV_INTR: +#ifndef EOMFIX + Media_end( Mediap ); +#endif /* ! EOMFIX */ + return EXIT_NORMAL; + case RV_CORE: + default: +#ifndef EOMFIX + Media_end( Mediap ); +#endif /* ! EOMFIX */ + return EXIT_FAULT; + } + + /* made it! I'm last, now exit + */ +#ifndef EOMFIX + Media_end( Mediap ); +#endif /* ! EOMFIX */ + return EXIT_NORMAL; +} + +/* called after all threads have exited. scans state to decide + * if interrupted or not. + */ +bool_t +content_complete( void ) +{ + bool_t completepr; + time_t elapsed; + + if ( ! persp ) { + completepr = BOOL_TRUE; + } else if ( ! persp->a.valpr ) { + completepr = BOOL_TRUE; + } else if ( ! persp->s.valpr ) { + completepr = BOOL_TRUE; + } else { + completepr = BOOL_FALSE; + } + + elapsed = time( 0 ) - tranp->t_starttime; + if ( persp ) { + elapsed += persp->s.accumtime; + } + + if ( completepr ) { + if ( tranp->t_toconlypr ) { + mlog( MLOG_VERBOSE, + "table of contents display complete" + ": %u seconds elapsed" + "\n", + elapsed ); + } else { + quotafilecheck("user", persp->a.dstdir, CONTENT_QUOTAFILE); + quotafilecheck("group", persp->a.dstdir, CONTENT_GQUOTAFILE); + + mlog( MLOG_VERBOSE, + "restore complete" + ": %u seconds elapsed" + "\n", + elapsed ); + } + } else if ( tranp->t_toconlypr ) { + mlog( MLOG_VERBOSE | MLOG_NOTE, + "table of contents display interrupted" + ": %u seconds elapsed" + "\n", + elapsed ); + } else { + mlog( MLOG_VERBOSE | MLOG_NOTE, + "restore interrupted" + ": %u seconds elapsed" + ": may resume later using -%c option" + "\n", + elapsed, + GETOPT_RESUME ); + } + + /* accumulate total elapsed time + */ + if ( persp ) { + persp->s.accumtime = elapsed; + } + + if ( ! persp->a.valpr ) { + wipepersstate( ); + persp = 0; + } + + return completepr; +} + +#define STATLINESZ 160 + +size_t +content_statline( char **linespp[ ] ) +{ + static char statlinebuf[ 1 ][ STATLINESZ ]; + static char *statline[ 1 ]; + size64_t inodone; + off64_t datadone; + size64_t inocnt; + off64_t datacnt; + double percent; + time_t elapsed; + time_t now; + struct tm *tmp; + ix_t i; + + /* build and supply the line array + */ + for ( i = 0 ; i < 1 ; i++ ) { + statline[ i ] = &statlinebuf[ i ][ 0 ]; + } + *linespp = statline; + + if ( ! persp->s.stat_valpr ) { + return 0; + } + + /* calculate the elapsed time + */ + elapsed = persp->s.accumtime + + + ( time( 0 ) - tranp->t_starttime ); + + /* get local time + */ + now = time( 0 ); + tmp = localtime( &now ); + + if ( ! persp->s.dirdonepr ) { + if ( ! tranp->t_dircnt ) { + return 0; + } + + percent = ( double )tranp->t_dirdonecnt + / + ( double )tranp->t_dircnt; + percent *= 100.0; + sprintf( statline[ 0 ], + "status at %02d:%02d:%02d: " + "%llu/%llu directories reconstructed, " + "%.1f%%%% complete, " + "%lu seconds elapsed\n", + tmp->tm_hour, + tmp->tm_min, + tmp->tm_sec, + (unsigned long long)tranp->t_dirdonecnt, + (unsigned long long)tranp->t_dircnt, + percent, + elapsed ); + ASSERT( strlen( statline[ 0 ] ) < STATLINESZ ); + + return 1; + } + + /* get the accumulated totals for non-dir inos and data bytes dumped. + * not under lock! + */ + inodone = persp->s.stat_inodone; + datadone = persp->s.stat_datadone; + inocnt = persp->s.stat_inocnt; + datacnt = persp->s.stat_datacnt; + + /* calculate percentage of data dumped + */ + if ( datacnt ) { + percent = ( double )datadone + / + ( double )datacnt; + percent *= 100.0; + } else { + percent = 100.0; + } + if ( percent > 100.0 ) { + percent = 100.0; + } + + /* format the status line in a local static buffer (non-re-entrant!) + */ + sprintf( statline[ 0 ], + "status at %02d:%02d:%02d: %llu/%llu files restored, " + "%.1f%%%% complete, " + "%lu seconds elapsed\n", + tmp->tm_hour, + tmp->tm_min, + tmp->tm_sec, + (unsigned long long)inodone, + (unsigned long long)inocnt, + percent, + elapsed ); + ASSERT( strlen( statline[ 0 ] ) < STATLINESZ ); + + /* return buffer to caller + */ + return 1; +} + +void +content_showinv( void ) +{ + pi_show_nomloglock( ); +} + +void +content_showremainingobjects( void ) +{ + bool_t knownholespr = BOOL_FALSE; + bool_t maybeholespr = BOOL_FALSE; + bag_t *bagp; + + bagp = pi_neededobjs_nondir_alloc( &knownholespr, + &maybeholespr, + BOOL_TRUE, + BOOL_FALSE ); + display_needed_objects( PURP_NONDIR, + bagp, + knownholespr, + maybeholespr ); + if ( bagp ) { + pi_neededobjs_free( bagp ); + bagp = 0; + } +} + +/* dlog_begin already called; this is a second-level dialog. + * prompt for each thread currently waiting for confirmation, + * as well as an info prompt. + */ +#define PREAMBLEMAX 3 +#define QUERYMAX 36 +#define CHOICEMAX 30 +#define ACKMAX 3 +#define POSTAMBLEMAX 3 +#define DLOG_TIMEOUT 300 +#define DLOG_TIMEOUT_MEDIA 3600 + +#define CHOICESTRSZ 10 +typedef struct { ix_t thrdix; char choicestr[ CHOICESTRSZ ]; } cttm_t; + +char * +content_mediachange_query( void ) +{ + cttm_t choicetothrdmap[ STREAM_SIMMAX ]; + char *querystr[ QUERYMAX ]; + size_t querycnt; + char *choicestr[ CHOICEMAX ]; + size_t choicecnt; + char *ackstr[ ACKMAX ]; + size_t ackcnt; + size_t maxdrvchoiceix; + size_t infoix; + size_t nochangeix; + size_t responseix; + ix_t thrdix; + + infoix = querycnt = 0; + querystr[ querycnt++ ] = "select a drive to acknowledge media change\n"; + choicecnt = 0; + maxdrvchoiceix = 0; + for ( thrdix = 0 ; thrdix < STREAM_SIMMAX ; thrdix++ ) { + if ( mcflag[ thrdix ] ) { + choicetothrdmap[ choicecnt ].thrdix = thrdix; + sprintf( choicetothrdmap[ choicecnt ].choicestr, + "drive %u", + (unsigned int)thrdix ); + choicestr[ choicecnt ] = + choicetothrdmap[ choicecnt ].choicestr; + maxdrvchoiceix = choicecnt; + choicecnt++; + } + } + if ( persp->s.valpr ) { + infoix = choicecnt; + choicestr[ choicecnt++ ] = "display needed media objects"; + } + nochangeix = choicecnt; + choicestr[ choicecnt++ ] = "continue"; + ASSERT( choicecnt <= CHOICEMAX ); + responseix = dlog_multi_query( querystr, + querycnt, + choicestr, + choicecnt, + 0, /* hilitestr */ + IXMAX, /* hiliteix */ + 0, /* defaultstr */ + nochangeix, /* defaultix */ + DLOG_TIMEOUT, + nochangeix, /* timeout ix */ + nochangeix, /* sigint ix */ + nochangeix, /* sighup ix */ + nochangeix);/* sigquit ix */ + if ( responseix <= maxdrvchoiceix ) { + clr_mcflag( choicetothrdmap[ responseix ].thrdix ); + return "media change acknowledged\n"; + } + if ( responseix == infoix ) { + bool_t knownholespr = BOOL_FALSE; + bool_t maybeholespr = BOOL_FALSE; + bag_t *bagp = pi_neededobjs_nondir_alloc( &knownholespr, + &maybeholespr, + BOOL_FALSE, + BOOL_FALSE ); + display_needed_objects( PURP_NONDIR, + bagp, + knownholespr, + maybeholespr ); + if ( bagp ) { + pi_neededobjs_free( bagp ); + bagp = 0; + } + ackcnt = 0; + dlog_multi_ack( ackstr, + ackcnt ); + querycnt = 0; + choicecnt = 0; + nochangeix = choicecnt; + choicestr[ choicecnt++ ] = "continue"; + ASSERT( choicecnt <= CHOICEMAX ); + responseix = dlog_multi_query( querystr, + querycnt, + choicestr, + choicecnt, + 0, /* hilitestr */ + IXMAX, /* hiliteix */ + 0, /* defaultstr */ + nochangeix, /* defaultix */ + DLOG_TIMEOUT, + nochangeix, /* timeout ix */ + nochangeix, /* sigint ix */ + nochangeix, /* sighup ix */ + nochangeix);/* sigquit ix */ + return "continuing\n"; + } + ASSERT( responseix == nochangeix ); + return "continuing\n"; +} + +/* definition of locally defined static functions ****************************/ + +/* does all pre-processing leading up to applying the dirdump, + * then applies the dirdump. updates pers progress flags along the way. + * does NOT do any post-processing! + */ +/* ARGSUSED */ +static rv_t +applydirdump( drive_t *drivep, + dh_t fileh, + content_inode_hdr_t *scrhdrp, + filehdr_t *fhdrp ) +{ + bool_t fhcs; + bool_t dhcs; +#ifdef EXTATTR + bool_t ahcs; +#endif /* EXTATTR */ + + fhcs = ( scrhdrp->cih_dumpattr & CIH_DUMPATTR_FILEHDR_CHECKSUM ) + ? + BOOL_TRUE + : + BOOL_FALSE; + dhcs = ( scrhdrp->cih_dumpattr & CIH_DUMPATTR_DIRENTHDR_CHECKSUM ) + ? + BOOL_TRUE + : + BOOL_FALSE; +#ifdef EXTATTR + ahcs = ( scrhdrp->cih_dumpattr & CIH_DUMPATTR_EXTATTRHDR_CHECKSUM ) + ? + BOOL_TRUE + : + BOOL_FALSE; +#endif /* EXTATTR */ + + if ( ! persp->s.marknorefdonepr ) { + tree_marknoref( ); + persp->s.marknorefdonepr = BOOL_TRUE; + } + + if ( ! persp->s.dirdonepr ) { + rv_t rv; + dah_t dah; + + char _direntbuf[ sizeof( direnthdr_t ) + + + NAME_MAX + + + DIRENTHDR_ALIGN ]; + char *direntbuf = ALIGN_PTR(_direntbuf, DIRENTHDR_ALIGN); + size_t direntbufsz = + sizeof(_direntbuf) - (direntbuf - _direntbuf); + + mlog( MLOG_TRACE, + "reading the ino map\n" ); + rv = inomap_restore_pers( drivep, scrhdrp, tranp->t_hkdir ); + if ( rv != RV_OK ) { + return rv; + } + + tranp->t_dircnt = scrhdrp->cih_inomap_dircnt; + tranp->t_dirdonecnt = 0; + + mlog( MLOG_TRACE, + "reading the directories \n" ); + + dah = DAH_NULL; + for (;;) { + nh_t dirh; + + /* read the file header + */ + rv = read_filehdr( drivep, fhdrp, fhcs ); + if ( rv ) { + return rv; + } + + /* if this is a null file hdr, we're done + * reading dirs, and there are no nondirs. + * done. + */ + if ( fhdrp->fh_flags & FILEHDR_FLAGS_NULL ) { + break; + } + + /* if its not a directory, must be the + * first non-dir file. done. + */ + if ( ( fhdrp->fh_stat.bs_mode & S_IFMT ) != S_IFDIR ) { + break; + } + + /* if stop requested bail out gracefully + */ + if ( cldmgr_stop_requested( )) { + return RV_INTR; + } + + /* if miniroot or pipeline , call preemptchk( ) to + * print status reports + */ + if ( miniroot || pipeline ) + { + mlog( MLOG_DEBUG , + "preemptchk( )\n"); + preemptchk( ); + } + +#ifdef EXTATTR + /* may be an extended attributes file hdr + */ + if ( fhdrp->fh_flags & FILEHDR_FLAGS_EXTATTR ) { + rv = restore_extattr( drivep, + fhdrp, + 0, + 0, + ahcs, + BOOL_TRUE, /* isdirpr */ + dah ); + if ( rv != RV_OK ) { + return rv; + } + continue; + } +#endif /* EXTATTR */ + + /* add the directory to the tree. save the + * returned tree node id, to associate with + * the directory entries. get the dirattr handle, + * so that any extattr following will be associated + * with that dir. + */ + dah = DAH_NULL; + dirh = tree_begindir( fhdrp, &dah ); + + /* read the directory entries, and populate the + * tree with them. we can tell when we are done + * by looking for a null dirent. + */ + for ( ; ; ) { + register direnthdr_t *dhdrp = + ( direnthdr_t * )direntbuf; + register size_t namelen; + + rv = read_dirent( drivep, + dhdrp, + direntbufsz, + dhcs ); + if ( rv ) { + return rv; + } + + /* if null, we're done with this dir. + * break out of this inner loop and + * move on th the next dir. + */ + if ( dhdrp->dh_ino == 0 ) { + break; + } + namelen = strlen( dhdrp->dh_name ); + ASSERT( namelen < NAME_MAX ); + + /* add this dirent to the tree. + */ + tree_addent( dirh, + dhdrp->dh_ino, + ( size_t )dhdrp->dh_gen, + dhdrp->dh_name, + namelen ); + } + + tree_enddir( dirh ); + + tranp->t_dirdonecnt++; + } + persp->s.dirdonepr = BOOL_TRUE; + } + + return RV_OK; +} + +/* like applydirdump, but just eats up the inomap/dirdump portion of the + * dump, doesn't use it. the first non-dir filehdr_t is copied into supplied + * buffer. returns integer error code from drive ops used. + */ +/* ARGSUSED */ +rv_t +eatdirdump( drive_t *drivep, + dh_t fileh, + content_inode_hdr_t *scrhdrp, + filehdr_t *fhdrp ) +{ + bool_t fhcs; + bool_t dhcs; + char _direntbuf[ sizeof( direnthdr_t ) + + + NAME_MAX + + + DIRENTHDR_ALIGN ]; + char *direntbuf = ALIGN_PTR(_direntbuf, DIRENTHDR_ALIGN); + size_t direntbufsz = sizeof(_direntbuf) - (direntbuf - _direntbuf); + rv_t rv; + + fhcs = ( scrhdrp->cih_dumpattr & CIH_DUMPATTR_FILEHDR_CHECKSUM ) + ? + BOOL_TRUE + : + BOOL_FALSE; + dhcs = ( scrhdrp->cih_dumpattr & CIH_DUMPATTR_DIRENTHDR_CHECKSUM ) + ? + BOOL_TRUE + : + BOOL_FALSE; + + mlog( MLOG_DEBUG, + "discarding ino map\n" ); + rv = inomap_discard( drivep, scrhdrp ); + if ( rv != RV_OK ) { + return rv; + } + + mlog( MLOG_DEBUG, + "discarding directories \n" ); + for (;;) { + /* read the file header + */ + rv = read_filehdr( drivep, fhdrp, fhcs ); + if ( rv ) { + return rv; + } + + /* if this is a null file hdr, we're done + * reading dirs, and there are no nondirs. + * done. + */ + if ( fhdrp->fh_flags & FILEHDR_FLAGS_NULL ) { + break; + } + + /* if its not a directory, must be the + * first non-dir file. done. + */ + if ( ( fhdrp->fh_stat.bs_mode & S_IFMT ) != S_IFDIR ) { + break; + } + + /* if stop requested bail out gracefully + */ + if ( cldmgr_stop_requested( )) { + return RV_INTR; + } + + /* read the directory entries. + * we can tell when we are done + * by looking for a null dirent. + */ + for ( ; ; ) { + register direnthdr_t *dhdrp = + ( direnthdr_t * )direntbuf; + /* REFERENCED */ + register size_t namelen; + + rv = read_dirent( drivep, + dhdrp, + direntbufsz, + dhcs ); + if ( rv ) { + return rv; + } + + /* if null, we're done with this dir. + * break out of this inner loop and + * move on th the next dir. + */ + if ( dhdrp->dh_ino == 0 ) { + break; + } + namelen = strlen( dhdrp->dh_name ); + ASSERT( namelen < NAME_MAX ); + } + } + + return RV_OK; +} + +/* does all post-processing of the tree required prior to restoral of + * the non-directory portion of the dump. only one thread at a time, + * so no locking needed. since the steps are interdependent, loops + * until no point in doing so. + */ +static rv_t +treepost( char *path1, char *path2 ) +{ + bool_t ok; + +#ifdef TREE_CHK + /* first scan the tree for corruption + */ + mlog( MLOG_DEBUG | MLOG_TREE, + "checking tree for consistency\n" ); + if ( ! tree_chk( )) { + return RV_CORE; + } +#endif /* TREE_CHK */ + + /* adjust ref flags based on what dirs were dumped + */ + if ( ! persp->s.adjrefdonepr ) { + mlog( MLOG_DEBUG | MLOG_TREE, + "adjusting dirent ref flags\n" ); + ok = tree_adjref( ); + if ( ! ok ) { + return RV_INTR; + } + persp->s.adjrefdonepr = BOOL_TRUE; + } + + /* if a subtree or interactive restore, sanitize the inomap + * so only inos selected by subtree or interactive cmds will + * be present in inomap. + */ + if ( ! persp->s.inomapsanitizedonepr ) { + if ( persp->a.interpr + || + ( persp->a.firststsenseprvalpr + && + persp->a.firststsensepr )) { + inomap_sanitize( ); + } + persp->s.inomapsanitizedonepr = BOOL_TRUE; + } + + /* apply subtree selections + */ + if ( ! persp->s.stdonepr ) { + ix_t stix; + stdesc_t *stdescp; + + mlog( MLOG_DEBUG | MLOG_TREE, + "applying subtree selections\n" ); + + /* if first subtree selection is inclusive in sense, + * first mark the entire tree as unselected. otherwise, + * select all (no subtree selections or first was excluding). + */ + if ( ( persp->a.interpr + && + ( ! persp->a.firststsenseprvalpr + || + persp->a.firststsensepr )) + || + ( persp->a.firststsenseprvalpr + && + persp->a.firststsensepr )) { + tree_markallsubtree( BOOL_FALSE ); + } else { + tree_markallsubtree( BOOL_TRUE ); + } + + /* now apply all subtree commands from command line + */ + for ( stix = 0, + stdescp = ( stdesc_t * )( ( char * )persp + perssz ) + ; + stix < persp->a.stcnt + ; + stix++, + stdescp = ( stdesc_t * )( ( char * )stdescp + + + stdescp->std_nextoff )) { + ok = tree_subtree_parse( stdescp->std_sensepr, + stdescp->std_path ); + if ( ! ok ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "subtree argument %s invalid\n", + stdescp->std_path ); + return RV_ERROR; + } + } + persp->s.stdonepr = BOOL_TRUE; + } + + /* next engage interactive subtree selection + */ + if ( ! persp->s.interdonepr ) { + if ( persp->a.interpr ) { + ok = tree_subtree_inter( ); + if ( ! ok ) { + return RV_INTR; + } + } + persp->s.interdonepr = BOOL_TRUE; + } + + ok = tree_post( path1, path2 ); + + if ( ! ok ) { + return RV_INTR; + } + +#ifdef EXTATTR + ok = tree_extattr( restore_dir_extattr_cb, path1 ); + if ( ! ok ) { + return RV_INTR; + } +#endif /* EXTATTR */ + + persp->s.treepostdonepr = BOOL_TRUE; + + return RV_OK; +} + +static rv_t +applynondirdump( drive_t *drivep, + dh_t fileh, + content_inode_hdr_t *scrhdrp, + char *path1, + char *path2, + filehdr_t *fhdrp ) +{ + bool_t fhcs; + bool_t ehcs; +#ifdef EXTATTR + bool_t ahcs; +#endif /* EXTATTR */ + egrp_t first_egrp; + egrp_t next_egrp; + + /* determine if file header and/or extent heade checksums present + */ + fhcs = ( scrhdrp->cih_dumpattr & CIH_DUMPATTR_FILEHDR_CHECKSUM ) + ? + BOOL_TRUE + : + BOOL_FALSE; + ehcs = ( scrhdrp->cih_dumpattr & CIH_DUMPATTR_EXTENTHDR_CHECKSUM ) + ? + BOOL_TRUE + : + BOOL_FALSE; +#ifdef EXTATTR + ahcs = ( scrhdrp->cih_dumpattr & CIH_DUMPATTR_EXTATTRHDR_CHECKSUM ) + ? + BOOL_TRUE + : + BOOL_FALSE; +#endif /* EXTATTR */ + + /* determine the first and next egrps needed from this media file. + * used to decide if stats should be updated + */ + pi_bracketneededegrps( fileh, &first_egrp, &next_egrp ); + + for ( ; ; ) { + drive_ops_t *dop = drivep->d_opsp; + drive_mark_t drivemark; + bstat_t *bstatp = &fhdrp->fh_stat; + bool_t resyncpr = BOOL_FALSE; + rv_t rv; + intgen_t rval; + + /* if a null file header, break + */ + if ( fhdrp->fh_flags & FILEHDR_FLAGS_NULL ) { + break; + } + +#ifdef EXTATTR + if ( fhdrp->fh_flags & FILEHDR_FLAGS_EXTATTR ) { + rv = restore_extattr( drivep, + fhdrp, + path1, + path2, + ahcs, + BOOL_FALSE, /* isdirpr */ + DAH_NULL ); + switch( rv ) { + case RV_OK: + break; + case RV_EOD: + return RV_OK; + case RV_CORRUPT: + rval = ( * dop->do_next_mark )( drivep ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "unable to resync media file: " + "some portion of dump will NOT " + "be restored\n" ); + return RV_OK; /* treat as EOD */ + } + resyncpr = BOOL_TRUE; + break; + default: + return rv; + } + goto extattrbypass; + } +#endif /* EXTATTR */ + + /* restore file + */ + resyncpr = BOOL_FALSE; + rv = restore_file( drivep, fhdrp, ehcs, path1, path2 ); + switch( rv ) { + case RV_OK: + break; + case RV_EOD: + return RV_OK; + case RV_CORRUPT: + rval = ( * dop->do_next_mark )( drivep ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "unable to resync media file: " + "some portion of dump will NOT " + "be restored\n" ); + return RV_OK; /* treat as EOD */ + } + resyncpr = BOOL_TRUE; + break; + default: + return rv; + } + + /* update stats if appropriate + */ + if ( ( ( bstatp->bs_mode & S_IFMT ) == S_IFREG ) + && + fhdrp->fh_offset == 0 ) { + egrp_t cur_egrp; + cur_egrp.eg_ino = fhdrp->fh_stat.bs_ino; + cur_egrp.eg_off = fhdrp->fh_offset; + if (cur_egrp.eg_ino > first_egrp.eg_ino ) { + if ( cur_egrp.eg_ino < next_egrp.eg_ino + || + next_egrp.eg_off > 0 ) { + ASSERT( cur_egrp.eg_ino + <= + next_egrp.eg_ino ); + pi_update_stats( bstatp->bs_blocks + * + ( off64_t ) + bstatp->bs_blksize ); + } + } + } + +#ifdef EXTATTR +extattrbypass: +#endif /* EXTATTR */ + + do { + /* get a mark for the next read, in case we restart here + */ + ( * dop->do_get_mark )( drivep, &drivemark ); + + /* read the file header. + */ + rv = read_filehdr( drivep, fhdrp, fhcs ); + switch( rv ) { + case RV_OK: + break; + case RV_EOD: + return RV_OK; + case RV_CORRUPT: + rval = ( * dop->do_next_mark )( drivep ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "unable to resync media file: " + "some portion of dump will NOT " + "be restored\n" ); + return RV_OK; /* treat as EOD */ + } + resyncpr = BOOL_TRUE; + default: + return rv; + } + + if ( resyncpr && rv == RV_OK ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "resynchronization achieved at " + "ino %llu offset %lld\n", + fhdrp->fh_stat.bs_ino, + fhdrp->fh_offset ); + resyncpr = BOOL_FALSE; + } + } while ( resyncpr ); + + /* checkpoint into persistent state if not a null file hdr + */ + if ( ! ( fhdrp->fh_flags & FILEHDR_FLAGS_NULL )) { + pi_checkpoint( fileh, + &drivemark, + fhdrp->fh_stat.bs_ino, + fhdrp->fh_offset ); + } + + /* if miniroot or pipeline , call preemptchk( ) to + * print status reports + */ + if ( miniroot || pipeline ) + { + mlog( MLOG_DEBUG , + "preemptchk( )\n"); + preemptchk( ); + } + } + return RV_OK; +} + +/* ARGSUSED */ +static rv_t +finalize( char *path1, char *path2 ) +{ + bool_t ok; + + if ( ! tranp->t_toconlypr ) { + + /* restore directory attributes + */ + if ( ! persp->s.dirattrdonepr ) {; + ok = tree_setattr( path1 ); + if ( ! ok ) { + return RV_INTR; + } + persp->s.dirattrdonepr = BOOL_TRUE; + } + + /* remove orphanage if empty + */ + if ( ! persp->s.orphdeltriedpr ) {; + ok = tree_delorph( ); + if ( ! ok ) { + return RV_INTR; + } + persp->s.orphdeltriedpr = BOOL_TRUE; + } + + /* delete the persistent ino map + */ + if ( ! persp->s.inomapdelpr ) { + inomap_del_pers( tranp->t_hkdir ); + persp->s.inomapdelpr = BOOL_TRUE; + } + } + + /* at this point, all session-only persistent state has been deleted. + * if this is a cumulative restore, just update the pers cum state and + * invalidate the pers session state. otherwise, invalidate the + * persistent state. content_complete will remove housekeeping dir. + */ + if ( persp->a.cumpr ) { + /* following must be atomic! + */ + persp->a.dumpcnt++; + uuid_copy(persp->a.lastdumpid, persp->s.dumpid); + strcpy( persp->a.lastdumplab, persp->s.dumplab ); + persp->s.valpr = BOOL_FALSE; + } else { + persp->a.valpr = BOOL_FALSE; + } + return RV_OK; +} + +static void +toconly_cleanup( void ) +{ + if ( ! tranp ) { + return; + } + + if ( ! tranp->t_toconlypr ) { + return; + } + + if ( ! tranp->t_hkdir ) { + return; + } + + if ( ! strlen( tranp->t_hkdir )) { + return; + } + + wipepersstate( ); +} + +static void +wipepersstate( void ) +{ + DIR *dirp; + struct dirent64 *direntp; + char pathname[ MAXPATHLEN ]; + dirp = opendir( tranp->t_hkdir ); + if ( ! dirp ) { + return; + } + + while ( ( direntp = readdir64( dirp )) != 0 ) { + /* REFERENCED */ + intgen_t len; + if ( ! strcmp( direntp->d_name, "." )) { + continue; + } + if ( ! strcmp( direntp->d_name, ".." )) { + continue; + } + len = sprintf( pathname, + "%s/%s", + tranp->t_hkdir, + direntp->d_name ); + ASSERT( len > 0 ); + ASSERT( len < MAXPATHLEN ); + ( void )unlink( pathname ); + closedir( dirp ); + dirp = opendir( tranp->t_hkdir ); + if ( ! dirp ) { + return; + } + } + closedir( dirp ); + + rmdir( tranp->t_hkdir ); +} + +/* Inv abstraction ***********************************************************/ + +/* attempt to validate id or label against online inventory. + * sets pers id/label and pers idvalpr etc as side-effect (does NOT set valpr!) + */ +static bool_t +Inv_validate_cmdline( void ) +{ + inv_session_t *sessp; + bool_t ok; + bool_t rok; + + ASSERT( ! persp->s.valpr ); + + ok = BOOL_FALSE; + sessp = 0; + if ( tranp->t_reqdumpidvalpr ) { + ok = inv_get_session_byuuid( &tranp->t_reqdumpid, &sessp ); + } else if ( tranp->t_reqdumplabvalpr ) { + ok = inv_get_session_bylabel( tranp->t_reqdumplab, &sessp ); + } + rok = BOOL_FALSE; + if ( ok && sessp ) { + uuid_t baseid; + + uuid_clear(baseid); + askinvforbaseof( baseid, sessp ); + if ( ! dumpcompat( sessp->s_isresumed, + ( ix_t )( sessp->s_level ), + baseid, + BOOL_TRUE )) { + inv_free_session( &sessp ); + return BOOL_ERROR; + } + + mlog( MLOG_VERBOSE, + "using online session inventory\n" ); + persp->s.fullinvpr = pi_transcribe( sessp ); + if ( persp->s.fullinvpr ) { + strncpyterm( persp->s.dumplab, + sessp->s_label, + sizeof( persp->s.dumplab )); + uuid_copy(persp->s.dumpid, sessp->s_sesid); + rok = BOOL_TRUE; + } + inv_free_session( &sessp ); + } + return rok; +} + + +/* Media abstraction *********************************************************/ + + +static Media_t * +Media_create( ix_t thrdix ) +{ + drive_t *drivep = drivepp[ thrdix ]; + global_hdr_t *grhdrp = drivep->d_greadhdrp; + drive_hdr_t *drhdrp = drivep->d_readhdrp; + media_hdr_t *mrhdrp = ( media_hdr_t * )drhdrp->dh_upper; + content_hdr_t *crhdrp = ( content_hdr_t * )mrhdrp->mh_upper; + content_inode_hdr_t *scrhdrp = + ( content_inode_hdr_t * )crhdrp->ch_specific; + Media_t *Mediap; + + + mlog( MLOG_DEBUG, + "Media_create\n" ); + + Mediap = ( Media_t * )calloc( 1, sizeof( Media_t )); + Mediap->M_drivep = drivep; + Mediap->M_grhdrp = grhdrp; + Mediap->M_drhdrp = drhdrp; + Mediap->M_mrhdrp = mrhdrp; + Mediap->M_crhdrp = crhdrp; + Mediap->M_scrhdrp = scrhdrp; + ASSERT( POS_UNKN == 0 ); + + return Mediap; +} + +/* these calls allow the Media users to clue Media in to fine position changes + * within the current media file + */ +static void +Media_indir( Media_t *Mediap ) +{ + mlog( MLOG_DEBUG, + "Media_indir\n" ); + + Mediap->M_pos = POS_INDIR; +} + +static void +Media_atnondir( Media_t *Mediap ) +{ + mlog( MLOG_DEBUG, + "Media_atnondir\n" ); + + Mediap->M_pos = POS_ATNONDIR; +} + +/* supplies pertinent media files to the caller. if purpose is search, + * returns all media files. otherwise, returns only media files with the + * dump ID. smart enough to know that if purpose was search but is now dir, + * current media file can be returned again. same for other transitions. + * always traverses the media object in a forward direction, beginning with + * current media file, wrapping around to beginning of media if necessary. + * also supplies fresh hdr pointers and drive manager. in current + * implementation these do not change, but will when we use new TLM. does + * fine positioning within media file according to purpose of request. + */ +static rv_t +Media_mfile_next( Media_t *Mediap, + purp_t purp, + sync_t *donesyncp, + dh_t *filehp, + global_hdr_t **grhdrpp, + drive_hdr_t **drhdrpp, + media_hdr_t **mrhdrpp, + content_hdr_t **crhdrpp, + content_inode_hdr_t **scrhdrpp, + drive_t **drivepp, + filehdr_t *fhdrp ) /*caller-supplied buf if NONDIR purp*/ +{ + drive_t *drivep = Mediap->M_drivep; + drive_ops_t *dop = drivep->d_opsp; + global_hdr_t *grhdrp = Mediap->M_grhdrp; + drive_hdr_t *drhdrp = Mediap->M_drhdrp; + media_hdr_t *mrhdrp = Mediap->M_mrhdrp; + content_hdr_t *crhdrp = Mediap->M_crhdrp; + content_inode_hdr_t *scrhdrp = Mediap->M_scrhdrp; + dh_t fileh; + intgen_t rval = 0; + rv_t rv; + bool_t ok; + uuid_t prevmfiledumpid; + + mlog( MLOG_DEBUG | MLOG_MEDIA, + "Media_mfile_next: purp==%d pos==%d\n", + purp, + Mediap->M_pos ); + + /* pass back hdr and drive ptrs + */ + *grhdrpp = grhdrp; + *drhdrpp = drhdrp; + *mrhdrpp = mrhdrp; + *crhdrpp = crhdrp; + *scrhdrpp = scrhdrp; + *drivepp = drivep; + + /* if ref return for pers mfile desc supplied, pre-zero + */ + if ( filehp ) { + *filehp = DH_NULL; + } + + /* keep a close eye on the validity of fileh + */ + fileh = DH_NULL; + + /* if purpose has changed, invalidate first, last, and previous indices + */ + if ( Mediap->M_flmfixvalpr ) { + if ( purp != Mediap->M_mfixpurp ) { + Mediap->M_flmfixvalpr = BOOL_FALSE; + Mediap->M_pmfixvalpr = BOOL_FALSE; + } + } + + /* use a local variable to keep track of dump sessions seen on + * media. if not in search mode, each time we see a different + * dump session, log a message to keep the user informed. + * invalidated each time we change media or rewind. + */ + uuid_clear(prevmfiledumpid); + + /* if restore is complete, return indication. be sure to end read + * if active. + */ + if ( purp == PURP_NONDIR + && + pi_alldone( )) { + if ( Mediap->M_pos == POS_ATHDR + || + Mediap->M_pos == POS_INDIR + || + Mediap->M_pos == POS_ATNONDIR ) { + ( * dop->do_end_read )( drivep ); + Mediap->M_pos = POS_UNKN; + fileh = DH_NULL; + } + return RV_NOMORE; + } + + /* loop searching for an acceptable media file. + * change media as necessary. + */ + for ( ; ; ) { + bool_t emptypr; /* begin_read says drive empty */ + bool_t partofdumppr; + bool_t hassomepr; + bool_t resumepr; + bool_t canseeknextpr; + drive_mark_t chkpnt; + bool_t fhcs; + bag_t *bagp = NULL; + bool_t knownholespr; + bool_t maybeholespr; + xfs_ino_t begino; + xfs_ino_t endino; + intgen_t dcaps = drivep->d_capabilities; + dh_t objh = DH_NULL; + + emptypr = BOOL_FALSE; + + /* check if no point in going on + */ + if ( cldmgr_stop_requested( )) { + return RV_INTR; + } + if ( donesyncp && *donesyncp == SYNC_DONE ) { + return RV_DONE; + } + if ( purp == PURP_NONDIR + && + pi_alldone( )) { + return RV_NOMORE; + } + + /* if we have a useless media object, get another one + */ + if ( Mediap->M_pos == POS_USELESS + || + Mediap->M_pos == POS_BLANK ) { + goto newmedia; + } + + /* if the purpose if to search, and we already have + * a media file, that media file has already been + * searched, so set pos to cause another begin read + */ + if ( purp == PURP_SEARCH ) { + if ( Mediap->M_pos == POS_ATHDR + || + Mediap->M_pos == POS_INDIR + || + Mediap->M_pos == POS_ATNONDIR ) { + Mediap->M_pos = POS_UNKN; + } + } + + /* if already have a media file, skip the begin_read + */ + if ( Mediap->M_pos == POS_ATHDR + || + Mediap->M_pos == POS_INDIR + || + Mediap->M_pos == POS_ATNONDIR ) { + goto validate; + } + + /* see if the indices say we've seen all there is to see + */ + if ( Mediap->M_flmfixvalpr ) { + if ( Mediap->M_pos == POS_UNKN ) { + if ( Mediap->M_lmfix + 1 == Mediap->M_fmfix ) { + goto newmedia; + } + } + if ( Mediap->M_pos == POS_END ) { + if ( Mediap->M_fmfix == 0 ) { + goto newmedia; + } + if ( Mediap->M_fsfixvalpr + && + Mediap->M_fmfix <= Mediap->M_fsfix ) { + goto newmedia; + } + } + } + + /* if we are at the end, do a rewind, or get new media + * if rewinds not possible. this may take a while, so + * afterwards check for interrupt or if someone else + * has finished the job. + */ + if ( Mediap->M_pos == POS_END ) { + if ( ! ( dcaps & DRIVE_CAP_REWIND )) { + goto newmedia; + } + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "rewinding\n" ); + ( * drivep->d_opsp->do_rewind )( drivep ); + Mediap->M_pos = POS_UNKN; + if ( cldmgr_stop_requested( )) { + return RV_INTR; + } + if ( donesyncp && *donesyncp == SYNC_DONE ) { + return RV_DONE; + } + if ( purp == PURP_NONDIR + && + pi_alldone( )) { + return RV_NOMORE; + } + } + + /* begin a new media file, and determine new position. + * bail if catastrophic. also, tell pi about EOD/EOM + * if appropriate. + */ + rval = ( * drivep->d_opsp->do_begin_read )( drivep ); + switch ( rval ) { + case 0: + mlog_lock( ); + mlog( MLOG_VERBOSE | MLOG_NOLOCK | MLOG_MEDIA, + "examining media file %u\n", + mrhdrp->mh_mediafileix ); + mlog( MLOG_TRACE | MLOG_NOLOCK | MLOG_MEDIA, + "file %u in " + "object %u " + "of stream %u\n", + mrhdrp->mh_mediafileix, + mrhdrp->mh_mediaix, + drhdrp->dh_driveix ); + mlog( MLOG_TRACE | MLOG_NOLOCK | MLOG_MEDIA, + "file %u in stream, " + "file %u of dump %u on object\n", + mrhdrp->mh_dumpfileix, + mrhdrp->mh_dumpmediafileix, + mrhdrp->mh_dumpmediaix ); + mlog_unlock( ); + + Mediap->M_pos = POS_ATHDR; + if ( Mediap->M_flmfixvalpr ) { + Mediap->M_pmfix = Mediap->M_lmfix; + Mediap->M_pmfixvalpr = BOOL_TRUE; + } + + pi_note_indrive( drhdrp->dh_driveix, + mrhdrp->mh_mediaid ); + + break; + case DRIVE_ERROR_EOD: + Mediap->M_pos = POS_END; + if ( Mediap->M_fsfixvalpr ) { + ASSERT( purp != PURP_SEARCH ); + pi_hiteod( Mediap->M_fssix, + Mediap->M_fsoix ); + } + break; + case DRIVE_ERROR_EOM: + Mediap->M_pos = POS_END; + if ( Mediap->M_fsfixvalpr ) { + ASSERT( purp != PURP_SEARCH ); + pi_hiteom( Mediap->M_fssix, + Mediap->M_fsoix ); + } + break; + case DRIVE_ERROR_MEDIA: +/* + * pv: 766024; tes@engr + * The setting of emptypr, in my opinion, should only happen + * in the case that the drive does not have a tape online. + * This corresponds to a couple of cases in prepare_drive(). + * Otherwise, when we go to a newmedia we won't be able to eject + * the tape when we want/need to. + * This may need to be reviewed in the future. + */ + emptypr = BOOL_TRUE; /* so don't try to eject */ + /* fall through */ + case DRIVE_ERROR_FOREIGN: + case DRIVE_ERROR_FORMAT: + case DRIVE_ERROR_VERSION: + case DRIVE_ERROR_EOF: + Mediap->M_pos = POS_USELESS; + break; + case DRIVE_ERROR_BLANK: + Mediap->M_pos = POS_BLANK; + break; + case DRIVE_ERROR_CORRUPTION: + Mediap->M_pos = POS_UNKN; + continue; + case DRIVE_ERROR_STOP: + return RV_INTR; + case DRIVE_ERROR_DEVICE: + return RV_DRIVE; + default: + return RV_CORE; + } + +validate: + /* update the positional indices + */ + if ( Mediap->M_pos == POS_ATHDR + || + Mediap->M_pos == POS_INDIR + || + Mediap->M_pos == POS_ATNONDIR ) { + if ( ! Mediap->M_flmfixvalpr ) { + Mediap->M_fmfix = mrhdrp->mh_mediafileix; + Mediap->M_mfixpurp = purp; + Mediap->M_flmfixvalpr = BOOL_TRUE; + } + Mediap->M_lmfix = mrhdrp->mh_mediafileix; + } + + /* check for interrupt. be sure to end_read if necessary + */ + if ( cldmgr_stop_requested( )) { + if ( Mediap->M_pos == POS_ATHDR + || + Mediap->M_pos == POS_INDIR + || + Mediap->M_pos == POS_ATNONDIR ) { + ( * dop->do_end_read )( drivep ); + Mediap->M_pos = POS_UNKN; + fileh = DH_NULL; + } + return RV_INTR; + } + + /* check if another thread has finished job (for this purpose). + * don't end_read, we will be back. + */ + if ( donesyncp && *donesyncp == SYNC_DONE ) { + return RV_DONE; + } + + /* we may be done due to the actions of other threads. + * if so, return indicating so + */ + if ( purp == PURP_NONDIR + && + pi_alldone( )) { + return RV_NOMORE; + } + + /* if the media object is useless, go get more + */ + if ( Mediap->M_pos == POS_USELESS + || + Mediap->M_pos == POS_BLANK ) { + goto newmedia; + } + + /* if we hit the end, this is not a search, and we've + * seen at least one media file pertaining to the dump, + * ask the inventory if there is any point in examining + * the beginning of the object. + */ + if ( Mediap->M_pos == POS_END + && + purp != PURP_SEARCH + && + Mediap->M_fsfixvalpr + && + pi_know_no_more_on_object( purp, + Mediap->M_fssix, + Mediap->M_fsoix )) { + goto newmedia; + } + + /* if we hit the end, go back to the top, where + * we will decide if we should rewind or get new media. + */ + if ( Mediap->M_pos == POS_END ) { + continue; + } + + /* if the purpose is to search, return this media file + */ + if ( purp == PURP_SEARCH ) { + ASSERT( Mediap->M_pos == POS_ATHDR ); + return RV_OK; + } + + /* see if this media file is part of the desired dump session + */ + partofdumppr = ( bool_t )(uuid_compare( persp->s.dumpid, + grhdrp->gh_dumpid) == 0); + if (!partofdumppr) { + char gh_string_uuid[UUID_STR_LEN + 1]; + char inv_string_uuid[UUID_STR_LEN + 1]; + + uuid_unparse( grhdrp->gh_dumpid, gh_string_uuid); + uuid_unparse( persp->s.dumpid, inv_string_uuid); + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "inventory session uuid (%s) does not match " + "the media header's session uuid (%s)\n", + inv_string_uuid, gh_string_uuid ); + } + + /* if media file dump id is different from the preceeding + * media file, print something useful at TRACE verbosity. + */ + if ( uuid_compare( prevmfiledumpid, + grhdrp->gh_dumpid) != 0) { + + char string_uuid[UUID_STR_LEN + 1]; + + mlog_lock( ); + mlog( MLOG_TRACE | MLOG_NOLOCK | MLOG_MEDIA, + "dump session label: \"%s\"\n", + grhdrp->gh_dumplabel ); + + uuid_unparse( grhdrp->gh_dumpid, string_uuid); + mlog( MLOG_TRACE | MLOG_NOLOCK | MLOG_MEDIA, + "dump session id: %s\n", + string_uuid ); + mlog( MLOG_TRACE | MLOG_NOLOCK | MLOG_MEDIA, + "stream %u, object %u, file %u\n", + drhdrp->dh_driveix, + mrhdrp->mh_mediaix, + mrhdrp->mh_dumpmediafileix ); + mlog_unlock( ); + uuid_copy(prevmfiledumpid, grhdrp->gh_dumpid); + } + + /* if this media file is not part of the desired dump session, + * and a preceeding media file on this object was part of the + * dump, we know we have hit the end of the stream. tell the + * persistent inventory. + */ + if ( ! partofdumppr + && + Mediap->M_fsfixvalpr + && + Mediap->M_lmfix > Mediap->M_fsfix ) { + pi_hitnextdump( Mediap->M_fssix, + Mediap->M_fsoix, + Mediap->M_lmfix ); + } + + + /* if this media file is not part of the desired dump session, + * we are doing non-dir, and the preceeding media file on this + * object was part of the dump, we know we have hit the end of + * the stream. check if we are done. + */ + if ( ! partofdumppr + && + purp == PURP_NONDIR + && + Mediap->M_fsfixvalpr + && + Mediap->M_lmfix > Mediap->M_fsfix ) { + if ( pi_alldone( )) { + ( * dop->do_end_read )( drivep ); + Mediap->M_pos = POS_UNKN; + fileh = DH_NULL; + return RV_NOMORE; + } + } + + + /* if this media file is not part of the desired dump session, + * and preceeding media files on this object were, decide if + * we need to rewind and look at the beginning of the object. + */ + if ( ! partofdumppr + && + Mediap->M_fsfixvalpr + && + Mediap->M_fmfix <= Mediap->M_fsfix ) { + ( * dop->do_end_read )( drivep ); + Mediap->M_pos = POS_UNKN; + fileh = DH_NULL; + if ( dcaps & DRIVE_CAP_REWIND ) { + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "rewinding\n" ); + ( * drivep->d_opsp->do_rewind )( drivep ); + continue; + } else { + goto newmedia; + } + } + + + /* if this media file is not part of the desired dump session, + * and the above conditions were not met, then keep looking + */ + if ( ! partofdumppr ) { + ( * dop->do_end_read )( drivep ); + Mediap->M_pos = POS_UNKN; + fileh = DH_NULL; + continue; + } + + /* record the index within this media object of the first + * media file in the dump stream + */ + if ( ! Mediap->M_fsfixvalpr ) { + Mediap->M_fsfix = + mrhdrp->mh_mediafileix + - + mrhdrp->mh_dumpmediafileix; + Mediap->M_fsoix = mrhdrp->mh_mediaix; + Mediap->M_fssix = drhdrp->dh_driveix; + Mediap->M_fsfixvalpr = BOOL_TRUE; + } + + /* this media file is part of the dump. add it to the + * persistent inventory and get a file handle. + */ + fileh = pi_addfile( Mediap, + grhdrp, + drhdrp, + mrhdrp, + scrhdrp, + drivep ); + + if ( fileh == DH_NULL ) { + return RV_CORE; + } + + pi_lock( ); + objh = DH2F( fileh )->f_parh; + DH2O( objh )->o_indriveix = drivep->d_index; + DH2O( objh )->o_indrivepr = BOOL_TRUE; + pi_unlock( ); + + pi_note_underhead( objh, fileh ); + + /* if purp is nondir, we may be done. + */ + if ( purp == PURP_NONDIR && pi_alldone( )) { + ( * dop->do_end_read )( drivep ); + Mediap->M_pos = POS_UNKN; + return RV_NOMORE; + } + + /* check for a wraparound + */ + if ( Mediap->M_flmfixvalpr ) { + if ( Mediap->M_fsfixvalpr + && + Mediap->M_fmfix <= Mediap->M_fsfix + && + Mediap->M_lmfix < Mediap->M_fmfix ) { + ( * dop->do_end_read )( drivep ); + Mediap->M_pos = POS_UNKN; + fileh = DH_NULL; + goto newmedia; + } + if ( Mediap->M_pmfixvalpr + && + Mediap->M_pmfix < Mediap->M_fmfix + && + Mediap->M_lmfix > Mediap->M_fmfix ) { + ( * dop->do_end_read )( drivep ); + Mediap->M_pos = POS_UNKN; + fileh = DH_NULL; + goto newmedia; + } + } + + /* if this media file is an inventory or a terminator, + * we have hit the end of the stream. don't tell the persistent + * inventory; it already knows because of a pi_addfile. + * decide if any preceeding media files are useful and if so + * go get them. otherwise get another media object. + */ + if ( MEDIA_TERMINATOR_CHK( mrhdrp ) + || + scrhdrp->cih_mediafiletype + == + CIH_MEDIAFILETYPE_INVENTORY ) { + ( * dop->do_end_read )( drivep ); + Mediap->M_pos = POS_UNKN; + fileh = DH_NULL; + if ( pi_know_no_more_on_object( purp, + Mediap->M_fssix, + Mediap->M_fsoix )) { + goto newmedia; + } + if ( Mediap->M_fmfix > Mediap->M_fsfix + && + ( dcaps & DRIVE_CAP_REWIND )) { + pi_note_underhead( objh, DH_NULL ); + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "rewinding\n" ); + ( * drivep->d_opsp->do_rewind )( drivep ); + continue; + } + goto newmedia; + } + + /* if the purpose is dir, but this media file is not positioned + * at the hdr or has already been tried, get another one. + * use the persistent inventory to do this intelligently. + */ + if ( purp == PURP_DIR + && + ( Mediap->M_pos != POS_ATHDR + || + DH2F( fileh )->f_dirtriedpr )) { + ( * dop->do_end_read )( drivep ); + Mediap->M_pos = POS_UNKN; + fileh = DH_NULL; + if ( pi_know_no_more_beyond_on_object( purp, + Mediap->M_fssix, + Mediap->M_fsoix, + mrhdrp->mh_dumpmediafileix )) { + if ( pi_know_no_more_on_object( purp, + Mediap->M_fssix, + Mediap->M_fsoix )) { + goto newmedia; + } + if ( Mediap->M_fmfix > Mediap->M_fsfix + && + ( dcaps & DRIVE_CAP_REWIND )) { + pi_note_underhead( objh, DH_NULL ); + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "rewinding\n" ); + ( * drivep->d_opsp->do_rewind )(drivep); + continue; + } + goto newmedia; + } else { + continue; + } + } + + /* if the purpose is dir, give it to the caller + */ + if ( purp == PURP_DIR ) { + ASSERT( Mediap->M_pos == POS_ATHDR ); + if ( filehp ) { + ASSERT( fileh != DH_NULL ); + *filehp = fileh; + } + return RV_OK; + } + + /* if we made it this far, the purpose is NONDIR and this + * is a valid media file from the desired dump session. + */ + + /* see if this media file contains any inodes not yet restored + */ + ASSERT( fileh != DH_NULL ); + pi_lock( ); + ASSERT( DH2F( fileh )->f_valpr ); + begino = DH2F( fileh )->f_curegrp.eg_ino; + endino = pi_scanfileendino( fileh ); + hassomepr = inomap_rst_needed( begino, endino ); + + /* if we have already given up on this media file or + * it doesn't contains anything not yet restored, + * or it can be skipped, move on. force the done flag on, + * so we don't check it again. + */ + if ( DH2F( fileh )->f_nondirdonepr + || + DH2F( fileh )->f_nondirskippr + || + ! hassomepr ) { + if ( ! DH2F( fileh )->f_nondirskippr ) { + DH2F( fileh )->f_nondirdonepr = BOOL_TRUE; + } + pi_unlock( ); + ( * dop->do_end_read )( drivep ); + Mediap->M_pos = POS_UNKN; + fileh = DH_NULL; + if ( pi_know_no_more_beyond_on_object( purp, + Mediap->M_fssix, + Mediap->M_fsoix, + mrhdrp->mh_dumpmediafileix )) { + if ( pi_know_no_more_on_object( purp, + Mediap->M_fssix, + Mediap->M_fsoix )) { + goto newmedia; + } + if ( Mediap->M_fmfix > Mediap->M_fsfix + && + ( dcaps & DRIVE_CAP_REWIND )) { + pi_note_underhead( objh, DH_NULL ); + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "rewinding\n" ); + ( * drivep->d_opsp->do_rewind )(drivep); + continue; + } + goto newmedia; + } else { + continue; + } + } + + /* so the purpose is NONDIR and we like this media file. + * be sure we are positioned at the beginning of the + * non-dir filehdr not yet restored, and supply to caller. + */ + + /* need to position just after the first + * non-dir filehdr_t not yet restored. + * may be a problem if we are currently positioned + * in the middle of the dir dump and have no + * checkpoint to seek to. if at beginning + * and no check point, can still get there + * by doing dummy read of dirdump. + */ + ASSERT( fileh != DH_NULL ); + ASSERT( DH2F( fileh )->f_valpr ); + resumepr = ( ( DH2F( fileh )->f_firstegrp.eg_ino + != + DH2F( fileh )->f_curegrp.eg_ino ) + || + ( DH2F( fileh )->f_firstegrp.eg_off + != + DH2F( fileh )->f_curegrp.eg_off )); + chkpnt = DH2F( fileh )->f_curmark; + pi_unlock( ); + fhcs = ( scrhdrp->cih_dumpattr + & + CIH_DUMPATTR_FILEHDR_CHECKSUM ) + ? + BOOL_TRUE + : + BOOL_FALSE; + canseeknextpr = dcaps & DRIVE_CAP_NEXTMARK; + switch( Mediap->M_pos ) { + case POS_ATHDR: + case POS_INDIR: + if ( resumepr ) { + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "seeking past portion of media file " + "already restored\n" ); + rval = ( * dop->do_seek_mark )( drivep, + &chkpnt ); + if ( ! rval ) { + rv_t rv; + rv = read_filehdr( drivep, + fhdrp, + fhcs ); + if ( rv != RV_OK ) { + rval = 1; + } else { + mlog( MLOG_TRACE | MLOG_MEDIA, + "positioned at unrestored " + "portion of media file\n" ); + } + } + } else if ( canseeknextpr ) { + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "seeking past media file " + "directory dump\n" ); + rval = ( * dop->do_next_mark )( drivep); + if ( ! rval ) { + rv_t rv; + rv = read_filehdr( drivep, + fhdrp, + fhcs ); + if ( rv != RV_OK ) { + rval = 1; + } else { + mlog( MLOG_TRACE | MLOG_MEDIA, + "positioned at " + "media file " + "non-directory dump\n" ); + } + } + } else if ( Mediap->M_pos == POS_ATHDR ) { + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "seeking past media file " + "directory dump\n" ); + rv = eatdirdump( drivep, + fileh, + scrhdrp, + fhdrp ); + if ( rv != RV_OK ) { + rval = 1; + } else { + mlog( MLOG_TRACE | MLOG_MEDIA, + "positioned at " + "media file " + "non-directory dump\n" ); + } + } else { + rval = 1; + } + break; + case POS_ATNONDIR: + rval = 0; + break; + default: + ASSERT( 0 ); + rval = 1; + break; + } + + /* if error encountered during fine positioning, + * mark file so we won't try it again + */ + if ( rval ) { + DH2F( fileh )->f_nondirdonepr = BOOL_TRUE; + } else { + Mediap->M_pos = POS_ATNONDIR; + } + + /* if no error during fine positioning, return. + */ + if ( ! rval ) { + if ( filehp ) { + ASSERT( fileh != DH_NULL ); + *filehp = fileh; + } + return RV_OK; + } + + /* an error occurred during fine positioning. any other useful + * media files on this object? if so, continue; if not, get + * more media. + */ + ( * dop->do_end_read )( drivep ); + Mediap->M_pos = POS_UNKN; + fileh = DH_NULL; + ASSERT( purp == PURP_NONDIR ); + if ( pi_know_no_more_beyond_on_object( purp, + Mediap->M_fssix, + Mediap->M_fsoix, + mrhdrp->mh_dumpmediafileix )) { + if ( pi_know_no_more_on_object( purp, + Mediap->M_fssix, + Mediap->M_fsoix )) { + goto newmedia; + } + if ( Mediap->M_fmfix > Mediap->M_fsfix + && + ( dcaps & DRIVE_CAP_REWIND )) { + pi_note_underhead( objh, DH_NULL ); + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "rewinding\n" ); + ( * drivep->d_opsp->do_rewind )(drivep); + continue; + } + goto newmedia; + } else { + continue; + } + /* fall through */ + +newmedia: + /* invalidate prev id, so we log a TRACE msg for first + * media file seen on new media + */ + uuid_clear(prevmfiledumpid); + + /* if we are searching and some other thread completed + * the search, don't pop the media unless it is useless + */ + if ( purp == PURP_SEARCH + && + Mediap->M_pos != POS_USELESS + && + Mediap->M_pos != POS_BLANK + && + donesyncp + && + *donesyncp == SYNC_DONE ) { + return RV_DONE; + } + + /* if media not removable, just return + */ + if ( ( * dop->do_get_device_class )( drivep ) + == + DEVICE_NONREMOVABLE ) { + return RV_QUIT; + } + + /* check for an interrupt + */ + if ( cldmgr_stop_requested( )) { + return RV_INTR; + } + + /* check if we are done. + */ + switch( purp ) { + case PURP_SEARCH: + knownholespr = BOOL_TRUE; + maybeholespr = BOOL_FALSE; + bagp = 0; + break; + case PURP_DIR: + knownholespr = BOOL_FALSE; + maybeholespr = BOOL_FALSE; + bagp = pi_neededobjs_dir_alloc( &knownholespr, + &maybeholespr ); + break; + case PURP_NONDIR: + knownholespr = BOOL_FALSE; + maybeholespr = BOOL_FALSE; + bagp = pi_neededobjs_nondir_alloc( &knownholespr, + &maybeholespr, + BOOL_FALSE, + BOOL_FALSE ); + break; + default: + ASSERT( 0 ); + } + + if ( ! bagp && ! knownholespr && ! maybeholespr ) { + /* if PURP_DIR, this may be a problem + */ + if ( purp == PURP_NONDIR ) { + return RV_NOMORE; + } + } + + /* eject media if drive not already empty + */ + if ( ! emptypr ) { + intgen_t dcaps = drivep->d_capabilities; + if ( purp == PURP_SEARCH ) { + if ( Mediap->M_pos == POS_USELESS ) { + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "media object not useful\n" ); + } else if ( Mediap->M_pos == POS_BLANK ) { + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "media object empty\n" ); + } else { + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "all media files examined, " + "none selected for restoral\n" ); + } + } + if ( dcaps & DRIVE_CAP_EJECT ) { + ( * dop->do_eject_media )( drivep ); + } + } + + /* tell the persistent inventory this drive is now empty + */ + pi_driveempty( drivep->d_index ); + + /* invalidate all positional descriptors + */ + Mediap->M_pos = POS_UNKN; + Mediap->M_flmfixvalpr = BOOL_FALSE; + Mediap->M_pmfixvalpr = BOOL_FALSE; + Mediap->M_fsfixvalpr = BOOL_FALSE; + fileh = DH_NULL; + + + /* ask for a media change: supply a list of media objects + * which may contain useful media files + */ + if ( dlog_allowed( )) { + /* If an alert program has been specified , run it. + */ + if (media_change_alert_program != NULL) + system(media_change_alert_program); + + if ( drivecnt > 1 && ! stdoutpiped ) { + ix_t thrdix = drivep->d_index; + if ( bagp ) { + pi_neededobjs_free( bagp ); + bagp = 0; + } + ASSERT( sistr ); + mlog( MLOG_NORMAL | MLOG_NOTE | MLOG_MEDIA, + "please change media: " + "type %s to confirm media change\n", + sistr ); + set_mcflag( thrdix ); + while ( mcflag[ thrdix ] ) { + sleep( 2 ); + if ( cldmgr_stop_requested( )) { + clr_mcflag( thrdix ); + return RV_INTR; + } + if ( purp == PURP_NONDIR + && + pi_alldone( )) { + clr_mcflag( thrdix ); + return RV_NOMORE; + } + } + ok = BOOL_TRUE; + } else { + ok = Media_prompt_change( drivep, + purp, + bagp, + knownholespr, + maybeholespr ); + } + } else { + ok = BOOL_FALSE; + } + if ( bagp ) { + pi_neededobjs_free( bagp ); + bagp = 0; + } + if ( cldmgr_stop_requested( )) { + return RV_INTR; + } + if ( ! ok ) { + return RV_QUIT; + } + } + /* NOTREACHED */ +} + +/* figures out and calls if needed do_end_read( ). + */ +static void +Media_end( Media_t *Mediap ) +{ + drive_t *drivep = Mediap->M_drivep; + drive_ops_t *dop = drivep->d_opsp; + + mlog( MLOG_DEBUG | MLOG_MEDIA, + "Media_end: pos==%d\n", + Mediap->M_pos ); + + if ( Mediap->M_pos == POS_ATHDR + || + Mediap->M_pos == POS_INDIR + || + Mediap->M_pos == POS_ATNONDIR ) { + ( * dop->do_end_read )( drivep ); + Mediap->M_pos = POS_UNKN; + } +} + +/* Persistent inventory operators *******************************************/ + +/* the persistent inventory is an mmap()ed file containing a hierarchical + * representation of all the media files generated by a dump session. it + * is useful for asking questions about how much of the dump remains to + * be restored. + * + * the top of the hierarchy is a linked list of streams. each of these contains + * a linked list of objects, which in turn each contain a linked list of files. + * each stream descriptor also has a flag indicating the last object in the + * stream is represented. each file descriptor contains a flag indicating the + * last file in that object is represented. the object descriptor also contains + * two indices; one indicating where in the dump stream the first media file + * in that object lies, and where in the object the first media file pertaining + * to the dump stream lies. each file descriptor describes the first extent + * group in that media file, and the next extent group in the media file to be + * restored. the file descriptor also contains flags indicating if an attempt + * (successful or unsuccessful) to use the file for a directory dump, and + * a similar flag for non-dir. + * + * all media files generated during the dump are represented, including + * terminators and inventories. + */ +static void +pi_lock( void ) +{ + qlock_lock( tranp->t_pilockh ); +} + +static void +pi_unlock( void ) +{ + qlock_unlock( tranp->t_pilockh ); +} + +/* sets check point in media file descriptor + */ +static void +pi_checkpoint( dh_t fileh, drive_mark_t *drivemarkp, xfs_ino_t ino, off64_t off ) +{ + pi_lock( ); + DH2F( fileh )->f_curmark = *drivemarkp; + DH2F( fileh )->f_curegrp.eg_ino = ino; + DH2F( fileh )->f_curegrp.eg_off = off; + pi_unlock( ); +} + +/* lock must be held by caller + */ +static bool_t +pi_allocdesc( dh_t *deschp ) +{ + dh_t desch; + + if ( persp->s.descfreeh == DH_NULL ) { + ix_t stpgcnt = persp->a.stpgcnt; + ix_t olddescpgcnt = persp->s.descpgcnt; + ix_t newdescpgcnt = olddescpgcnt + DAU; + ix_t descppg = pgsz / PERS_DESCSZ; + ix_t descix; + /* REFERENCED */ + intgen_t rval; + + /* first unmap if any existing descriptors + */ + if ( descp ) { + ASSERT( olddescpgcnt > 0 ); + rval = munmap( ( void * )descp, + olddescpgcnt * pgsz ); + ASSERT( ! rval ); + descp = 0; + } else { + ASSERT( olddescpgcnt == 0 ); + } + + /* remap with DAU more pages of descriptors + */ + ASSERT( stpgcnt <= ( ix_t )INTGENMAX ); + ASSERT( newdescpgcnt > 0 ); + descp = ( pers_desc_t * ) mmap_autogrow( newdescpgcnt * pgsz, + tranp->t_persfd, + ( off_t )perssz + + + ( off_t )( stpgcnt * pgsz )); + if ( descp == ( pers_desc_t * )( -1 )) { + pi_unlock( ); + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_MEDIA, + "could not remap persistent state file " + "inv %s: %d (%s)\n", + perspath, + errno, + strerror( errno )); + pi_lock( ); + descp = 0; + return BOOL_FALSE; + } + persp->s.descfreeh = ( dh_t )( olddescpgcnt * pgsz + 1 ); + for ( descix = 0, desch = persp->s.descfreeh + ; + descix < ( DAU * descppg ) - 1 + ; + descix++, desch += PERS_DESCSZ ) { + DH2D( desch )->d_nexth = desch + PERS_DESCSZ; + } + DH2D( desch )->d_nexth = DH_NULL; + persp->s.descpgcnt = newdescpgcnt; + } + + desch = persp->s.descfreeh; + persp->s.descfreeh = DH2D( desch )->d_nexth; + memset( ( void * )DH2D( desch ), 0, sizeof( pers_desc_t )); + ASSERT( desch != DH_NULL ); + *deschp = desch; + return BOOL_TRUE; +} + +/* inserts the indexed file into the given stream. ensures that all + * previous files are represented as well. if dmfix is not valid, only + * adds objects. + */ +static dh_t +pi_insertfile( ix_t drivecnt, + ix_t driveix, + ix_t mediaix, + bool_t idlabvalpr, + uuid_t *mediaidp, + label_t medialabel, + bool_t previdlabvalpr, + uuid_t *prevmediaidp, + label_t prevmedialabel, + bool_t mfixvalpr, + ix_t mediafileix, + bool_t dmfixvalpr, + ix_t dumpmediafileix, + bool_t dfixvalpr, + ix_t dumpfileix, + bool_t egrpvalpr, + xfs_ino_t startino, + off64_t startoffset, + intgen_t flags, + bool_t fileszvalpr, + off64_t filesz ) +{ + ix_t strmix; + dh_t strmh; + ix_t objix; + dh_t objh; + dh_t prevobjh; + ix_t fileix; + dh_t fileh; + dh_t prevfileh; + bool_t ok; + + pi_lock( ); + + /* first alloc stream descriptors if needed + */ + if ( persp->s.strmheadh == DH_NULL ) { + for ( strmix = 0 ; strmix < drivecnt ; strmix++ ) { + ok = pi_allocdesc( &strmh ); + if ( ! ok ) { + pi_unlock( ); + return DH_NULL; + } + DH2S( strmh )->s_nexth = persp->s.strmheadh; + persp->s.strmheadh = strmh; + } + } + + /* get handle to this stream + */ + for ( strmix = 0, + strmh = persp->s.strmheadh + ; + strmix < driveix + ; + strmix++, + strmh = DH2S( strmh )->s_nexth ) + ; + ASSERT( strmh != DH_NULL ); + + /* get handle to this object by walking/constructing this stream's + * object list, up to the desired object + */ + objh = prevobjh = DH_NULL; + for ( objix = 0 ; objix <= mediaix ; objix++ ) { + prevobjh = objh; + if ( objix == 0 ) { + objh = DH2S( strmh )->s_cldh; + } else { + objh = DH2O( prevobjh )->o_nexth; + } + if ( objh == DH_NULL ) { + ok = pi_allocdesc( &objh ); + if ( ! ok ) { + pi_unlock( ); + return DH_NULL; + } + DH2O( objh )->o_parh = strmh; + if ( objix == 0 ) { + DH2S( strmh )->s_cldh = objh; + } else { + DH2O( prevobjh )->o_nexth = objh; + } + } + } + + /* update the object fields if not yet valid + */ + if ( idlabvalpr + && + ! DH2O( objh )->o_idlabvalpr ) { + uuid_copy(DH2O( objh )->o_id, *mediaidp); + strncpy( DH2O( objh )->o_lab, + medialabel, + sizeof( DH2O( objh )->o_lab )); + DH2O( objh )->o_idlabvalpr = BOOL_TRUE; + } + if ( mfixvalpr + && + dmfixvalpr + && + ! DH2O( objh )->o_fmfmixvalpr ) { + DH2O( objh )->o_fmfmix = mediafileix - dumpmediafileix; + DH2O( objh )->o_fmfmixvalpr = BOOL_TRUE; + } + if ( dfixvalpr + && + dmfixvalpr + && + ! DH2O( objh )->o_fmfsixvalpr ) { + DH2O( objh )->o_fmfsix = dumpfileix - dumpmediafileix; + DH2O( objh )->o_fmfsixvalpr = BOOL_TRUE; + } + + /* record the previous object's id and label if not yet valid + */ + if ( prevobjh != DH_NULL + && + previdlabvalpr + && + ! DH2O( prevobjh )->o_idlabvalpr ) { + uuid_copy(DH2O( prevobjh )->o_id, *prevmediaidp); + strncpy( DH2O( prevobjh )->o_lab, + prevmedialabel, + sizeof( DH2O( prevobjh )->o_lab )); + DH2O( prevobjh )->o_idlabvalpr = BOOL_TRUE; + } + + /* if the dump file and dump media file indices are valid, + * and the previous object has at least one media file with its + * dump file index valid, can infer the index of the last media + * file on the previous dump object. + */ + if ( DH2O( objh )->o_fmfsixvalpr + && + prevobjh != DH_NULL + && + DH2O( prevobjh )->o_fmfsixvalpr + && + ! DH2O( prevobjh )->o_lmfknwnpr ) { + size_t prevmfcnt; + ASSERT( DH2O( objh )->o_fmfsix > DH2O( prevobjh )->o_fmfsix ); + prevmfcnt = DH2O( objh )->o_fmfsix - DH2O( prevobjh )->o_fmfsix; + pi_unlock( ); + ASSERT( mediaix > 0 ); + ( void )pi_insertfile( drivecnt, + driveix, + mediaix - 1, + BOOL_FALSE, + 0, + 0, + BOOL_FALSE, + 0, + 0, + BOOL_FALSE, + 0, + BOOL_TRUE, + prevmfcnt - 1, + BOOL_TRUE, + DH2O( objh )->o_fmfsix - 1, + 0, + 0, + 0, + 0, + BOOL_FALSE, + ( off64_t )0 ); + pi_seeobjstrmend( strmix, mediaix - 1 ); + pi_lock( ); + } + + /* if don't know dump stream media file index, can't add any media files + */ + if ( ! dmfixvalpr ) { + pi_unlock( ); + pi_show( " after pi_insertfile no media file ix" ); + return DH_NULL; + } + + /* get handle to this file by walking/constructing this object's + * file list, up to the desired file + */ + fileh = DH_NULL; + for ( fileix = 0 ; fileix <= dumpmediafileix ; fileix++ ) { + prevfileh = fileh; + if ( fileix == 0 ) { + fileh = DH2O( objh )->o_cldh; + } else { + fileh = DH2F( prevfileh )->f_nexth; + } + if ( fileh == DH_NULL ) { + ok = pi_allocdesc( &fileh ); + if ( ! ok ) { + pi_unlock( ); + return DH_NULL; + } + DH2F( fileh )->f_parh = objh; + if ( fileix == 0 ) { + DH2O( objh )->o_cldh = fileh; + } else { + DH2F( prevfileh )->f_nexth = fileh; + } + } + } + + /* update the media file fields not yet valid + */ + if ( egrpvalpr && ! DH2F( fileh )->f_valpr ) { + ASSERT( ! ( DH2F( fileh )->f_flags & PF_INV )); + ASSERT( ! ( DH2F( fileh )->f_flags & PF_TERM )); + DH2F( fileh )->f_firstegrp.eg_ino = startino; + DH2F( fileh )->f_firstegrp.eg_off = startoffset; + DH2F( fileh )->f_curegrp = DH2F( fileh )->f_firstegrp; + DH2F( fileh )->f_valpr = BOOL_TRUE; + } + + /* set flags + */ + DH2F( fileh )->f_flags = flags; + + /* if we know the file size, + * update it + */ + if ( fileszvalpr ) { + DH2F( fileh )->f_sz = filesz; + DH2F( fileh )->f_szvalpr = BOOL_TRUE; + } + + pi_unlock( ); + pi_show( " after pi_insertfile" ); + return fileh; +} + +/* add pers file desc if not already present. will automatically + * update/alloc pers obj and strm descriptors. If given a session inventory, + * attempt to incorporate into pi. also, initializes completion stats. + */ +/* ARGSUSED */ +static dh_t +pi_addfile( Media_t *Mediap, + global_hdr_t *grhdrp, + drive_hdr_t *drhdrp, + media_hdr_t *mrhdrp, + content_inode_hdr_t *scrhdrp, + drive_t * drivep ) +{ + dh_t fileh; + + if ( ! persp->s.stat_valpr ) { + persp->s.stat_inocnt = scrhdrp->cih_inomap_nondircnt; + persp->s.stat_inodone = 0; + ASSERT( scrhdrp->cih_inomap_datasz <= OFF64MAX ); + persp->s.stat_datacnt = ( off64_t )scrhdrp->cih_inomap_datasz; + persp->s.stat_datadone = 0; + persp->s.stat_valpr = BOOL_TRUE; + } + + /* if we see a terminator, we know we have seen the end of + * a stream. + */ + if ( MEDIA_TERMINATOR_CHK( mrhdrp )) { + fileh = pi_insertfile( drhdrp->dh_drivecnt, + drhdrp->dh_driveix, + mrhdrp->mh_mediaix, + BOOL_TRUE, + &mrhdrp->mh_mediaid, + mrhdrp->mh_medialabel, + BOOL_TRUE, + &mrhdrp->mh_prevmediaid, + mrhdrp->mh_prevmedialabel, + BOOL_TRUE, + mrhdrp->mh_mediafileix, + BOOL_TRUE, + mrhdrp->mh_dumpmediafileix, + BOOL_TRUE, + mrhdrp->mh_dumpfileix, + BOOL_FALSE, + ( xfs_ino_t )0, + ( off64_t )0, + PF_TERM, + BOOL_FALSE, + ( off64_t )0 ); + if ( fileh == DH_NULL ) { + return DH_NULL; + } + pi_seestrmend( drhdrp->dh_driveix ); + pi_seeobjstrmend( drhdrp->dh_driveix, mrhdrp->mh_mediaix ); + return fileh; + } + + /* data file + */ + if ( scrhdrp->cih_mediafiletype == CIH_MEDIAFILETYPE_DATA ) { + /* tell the inventory about this media file + */ + fileh = pi_insertfile( drhdrp->dh_drivecnt, + drhdrp->dh_driveix, + mrhdrp->mh_mediaix, + BOOL_TRUE, + &mrhdrp->mh_mediaid, + mrhdrp->mh_medialabel, + BOOL_TRUE, + &mrhdrp->mh_prevmediaid, + mrhdrp->mh_prevmedialabel, + BOOL_TRUE, + mrhdrp->mh_mediafileix, + BOOL_TRUE, + mrhdrp->mh_dumpmediafileix, + BOOL_TRUE, + mrhdrp->mh_dumpfileix, + BOOL_TRUE, + scrhdrp->cih_startpt.sp_ino, + scrhdrp->cih_startpt.sp_offset, + 0, + BOOL_FALSE, + ( off64_t )0 ); + if ( fileh == DH_NULL ) { + return DH_NULL; + } + ASSERT( drhdrp->dh_drivecnt > 0 ); + if ( drhdrp->dh_driveix < drhdrp->dh_drivecnt - 1 ) { + /* if this is not in the last stream, we know + * there is at least one other media file in + * the following stream, and we know its start pt + */ + ( void )pi_insertfile( drhdrp->dh_drivecnt, + drhdrp->dh_driveix + 1, + 0, + BOOL_FALSE, + 0, + 0, + BOOL_FALSE, + 0, + 0, + BOOL_FALSE, + 0, + BOOL_TRUE, + 0, + BOOL_FALSE, + 0, + BOOL_TRUE, + scrhdrp->cih_endpt.sp_ino, + scrhdrp->cih_endpt.sp_offset, + 0, + BOOL_FALSE, + ( off64_t )0 ); + } + if ( ! ( drivep->d_capabilities & DRIVE_CAP_FILES )) { + /* if drive does not support multiple files, + * we know this is end of object and stream + */ + pi_seestrmend( drhdrp->dh_driveix ); + pi_seeobjstrmend( drhdrp->dh_driveix, mrhdrp->mh_mediaix ); + } + + return fileh; + } + + /* inventory file + */ + if ( scrhdrp->cih_mediafiletype == CIH_MEDIAFILETYPE_INVENTORY ) { + fileh = pi_insertfile( drhdrp->dh_drivecnt, + drhdrp->dh_driveix, + mrhdrp->mh_mediaix, + BOOL_TRUE, + &mrhdrp->mh_mediaid, + mrhdrp->mh_medialabel, + BOOL_TRUE, + &mrhdrp->mh_prevmediaid, + mrhdrp->mh_prevmedialabel, + BOOL_TRUE, + mrhdrp->mh_mediafileix, + BOOL_TRUE, + mrhdrp->mh_dumpmediafileix, + BOOL_TRUE, + mrhdrp->mh_dumpfileix, + BOOL_FALSE, + ( xfs_ino_t )0, + ( off64_t )0, + PF_INV, + BOOL_FALSE, + ( off64_t )0 ); + if ( fileh == DH_NULL ) { + return DH_NULL; + } + pi_seestrmend( drhdrp->dh_driveix ); + pi_seeobjstrmend( drhdrp->dh_driveix, + mrhdrp->mh_mediaix ); + if ( drhdrp->dh_driveix < drhdrp->dh_drivecnt - 1 ) { + ( void )pi_insertfile( drhdrp->dh_drivecnt, + drhdrp->dh_driveix + 1, + 0, + BOOL_FALSE, + 0, + 0, + BOOL_FALSE, + 0, + 0, + BOOL_FALSE, + 0, + BOOL_TRUE, + 0, + BOOL_FALSE, + 0, + BOOL_TRUE, + scrhdrp->cih_endpt.sp_ino, + scrhdrp->cih_endpt.sp_offset, + 0, + BOOL_FALSE, + ( off64_t )0 ); + } + if ( ! persp->s.fullinvpr + && + Mediap->M_pos == POS_ATHDR ) { + size_t bufszincr; + size_t bufsz; + size_t buflen; + char *bufp; + inv_session_t *sessp; + invt_sessinfo_t sessinfo; + bool_t ok; + bool_t donepr; + + /* read inventory into buffer + */ + bufszincr = IBPGINCR * PGSZ; + /* use 4096, no need to be correlated + * with system page size + */ + bufsz = bufszincr; + buflen = 0; + bufp = ( char * )malloc( bufsz ); + + /* need to read until we hit EOF/EOD. that's the only + * way to know how big the inventory is. mark the Media + * current media file as no longer at hdr. + */ + Mediap->M_pos = POS_ATNONDIR; + donepr = BOOL_FALSE; + while ( ! donepr ) { + intgen_t nread; + drive_ops_t *dop = drivep->d_opsp; + intgen_t rval = 0; + nread = read_buf( bufp + buflen, + bufszincr, + ( void * )drivep, + ( rfp_t )dop->do_read, + ( rrbfp_t )dop->do_return_read_buf, + &rval ); + switch( rval ) { + case 0: + ASSERT( nread == ( intgen_t )bufszincr ); + buflen += ( size_t )nread; + bufsz += bufszincr; + bufp = ( char * )realloc(( void * )bufp, + bufsz ); + ASSERT( bufp ); + continue; + case DRIVE_ERROR_EOD: + case DRIVE_ERROR_EOF: + buflen += ( size_t )nread; + donepr = BOOL_TRUE; + break; + default: + free( ( void * )bufp ); + return fileh; + } + } + + /* ask inventory to convert buffer into session + * desc. + */ + sessp = 0; + if ( ! buflen ) { + ok = BOOL_FALSE; + } else { + /* extract the session information from the buffer */ + if ( stobj_unpack_sessinfo( bufp, buflen, &sessinfo )<0 ) { + ok = BOOL_FALSE; + } else { + stobj_convert_sessinfo(&sessp, &sessinfo); + ok = BOOL_TRUE; + } + } + if ( ! ok || ! sessp ) { + mlog( MLOG_DEBUG | MLOG_WARNING | MLOG_MEDIA, + "on-media session " + "inventory corrupt\n" ); + } else { + /* if root, update online inventory. + */ + if ( ! geteuid( ) + && + ! tranp->t_noinvupdatepr ) { + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "incorporating on-media session " + "inventory into online " + "inventory\n" ); + inv_put_sessioninfo( &sessinfo ); + } + + /* convert into pi format + */ + mlog( MLOG_VERBOSE | MLOG_MEDIA, + "using on-media session inventory\n" ); + persp->s.fullinvpr = pi_transcribe( sessp ); + inv_free_session( &sessp ); + } + free( ( void * )bufp ); + } + return fileh; + } + + ASSERT( 0 ); + return DH_NULL; +} + +/* translate a session inventory into a pi + */ +static bool_t +pi_transcribe( inv_session_t *sessp ) +{ + ix_t strmcnt; + ix_t strmix; + + /* traverse inventory, transcribing into pers inv. + */ + strmcnt = ( size_t )sessp->s_nstreams; + for ( strmix = 0 ; strmix < strmcnt ; strmix++ ) { + inv_stream_t *strmp; + size_t fileix; + size_t filecnt; + uuid_t lastobjid; + label_t lastobjlabel; + ix_t mediaix; + size_t dumpmediafileix; + + strmp = &sessp->s_streams[ strmix ]; + filecnt = strmp->st_nmediafiles; + uuid_clear(lastobjid); + lastobjlabel[ 0 ] = 0; + mediaix = 0; + dumpmediafileix = 0; + + /* insert all media files from this stream. note that + * the media object representation is inverted + */ + for ( fileix = 0 ; fileix < filecnt ; fileix++ ) { + inv_mediafile_t *filep; + bool_t fileszvalpr; + + filep = &strmp->st_mediafiles[ fileix ]; + if ( uuid_compare( filep->m_moid, + lastobjid ) != 0) { + dumpmediafileix = 0; + if ( fileix != 0 ) { + pi_seeobjstrmend( strmix, mediaix ); + mediaix++; + } + } + + fileszvalpr = BOOL_TRUE; + + ( void )pi_insertfile( strmcnt, + strmix, + mediaix, + BOOL_TRUE, + &filep->m_moid, + filep->m_label, + BOOL_TRUE, + &lastobjid, + lastobjlabel, + BOOL_TRUE, + filep->m_mfile_index, + BOOL_TRUE, + dumpmediafileix, + BOOL_TRUE, + fileix, + filep->m_isinvdump + ? + BOOL_FALSE + : + BOOL_TRUE, + filep->m_startino, + filep->m_startino_off, + filep->m_isinvdump + ? + PF_INV + : + 0, + fileszvalpr, + filep->m_size ); + uuid_copy(lastobjid, filep->m_moid); + strncpy( lastobjlabel, + filep->m_label, + sizeof( lastobjlabel )); + dumpmediafileix++; + } + pi_seestrmend( strmix ); + pi_seeobjstrmend( strmix, mediaix ); + } + + return BOOL_TRUE; +} + +/* clean up pers. inv: initially no media objects in drives. flags may + * be set from previously interrupted invocation. + */ +static void +pi_preclean( void ) +{ + dh_t strmh; + dh_t objh; + dh_t fileh; + + for ( strmh = persp->s.strmheadh + ; + strmh != DH_NULL + ; + strmh = DH2S( strmh )->s_nexth ) { + for ( objh = DH2S( strmh )->s_cldh + ; + objh != DH_NULL + ; + objh = DH2O( objh )->o_nexth ) { + DH2O( objh )->o_indrivepr = BOOL_FALSE; + for ( fileh = DH2O( objh )->o_cldh + ; + fileh != DH_NULL + ; + fileh = DH2F( fileh )->f_nexth ) { + DH2F( fileh )->f_underheadpr = BOOL_FALSE; + } + } + } +} + +/* tell pi no media objects are in this drive + */ +static void +pi_driveempty( ix_t driveix ) +{ + dh_t strmh; + dh_t objh; + dh_t fileh; + + pi_lock( ); + + for ( strmh = persp->s.strmheadh + ; + strmh != DH_NULL + ; + strmh = DH2S( strmh )->s_nexth ) { + for ( objh = DH2S( strmh )->s_cldh + ; + objh != DH_NULL + ; + objh = DH2O( objh )->o_nexth ) { + if ( DH2O( objh )->o_indrivepr + && + DH2O( objh )->o_indriveix == driveix ) { + DH2O( objh )->o_indrivepr = BOOL_FALSE; + for ( fileh = DH2O( objh )->o_cldh + ; + fileh != DH_NULL + ; + fileh = DH2F( fileh )->f_nexth ) { + DH2F( fileh )->f_underheadpr = + BOOL_FALSE; + } + } + } + } + + pi_unlock( ); +} + +/* tell pi this media object is in the drive + */ +static void +pi_note_indrive( ix_t driveix, uuid_t media_id ) +{ + dh_t strmh; + dh_t objh; + + pi_lock( ); + + for ( strmh = persp->s.strmheadh + ; + strmh != DH_NULL + ; + strmh = DH2S( strmh )->s_nexth ) { + for ( objh = DH2S( strmh )->s_cldh + ; + objh != DH_NULL + ; + objh = DH2O( objh )->o_nexth ) { + if ( DH2O( objh )->o_idlabvalpr + && + uuid_compare( DH2O( objh )->o_id, media_id) == 0) { + DH2O( objh )->o_indrivepr = BOOL_TRUE; + DH2O( objh )->o_indriveix = driveix; + goto done; + } + } + } + +done: + pi_unlock( ); +} + +/* tell pi this media file is under the head of the drive containing the object + */ +static void +pi_note_underhead( dh_t thisobjh, dh_t thisfileh ) +{ + dh_t fileh; + + if ( thisobjh == DH_NULL ) { + return; + } + + pi_lock( ); + + if ( thisfileh != DH_NULL ) { + DH2F( thisfileh )->f_underheadpr = BOOL_TRUE; + } + + for ( fileh = DH2O( thisobjh )->o_cldh + ; + fileh != DH_NULL + ; + fileh = DH2F( fileh )->f_nexth ) { + if ( fileh != thisfileh ) { + DH2F( fileh )->f_underheadpr = BOOL_FALSE; + } + } + + pi_unlock( ); +} + +/* mark the pi stream indicating all objects in that stream are known. + */ +static void +pi_seestrmend( ix_t strmix ) +{ + ix_t ix; + dh_t strmh; + + pi_lock( ); + + /* get handle to the indexed stream + */ + for ( ix = 0, + strmh = persp->s.strmheadh + ; + strmh != DH_NULL && ix < strmix + ; + ix++, + strmh = DH2S( strmh )->s_nexth ) + ; + + /* if an empty stream (can happen when dump interrupted), + * nothing need be done, so return + */ + if ( strmh == DH_NULL ) { + pi_unlock( ); + return; + } + + /* set stream flag and object and file counts + */ + DH2S( strmh )->s_lastobjknwnpr = BOOL_TRUE; + + pi_unlock( ); + pi_show( " after pi_seestrmend" ); +} + +/* mark pi indicating all media files in object are known + */ +static void +pi_seeobjstrmend( ix_t strmix, ix_t mediaix ) +{ + ix_t ix; + dh_t strmh; + dh_t objh; + + pi_lock( ); + + /* get handle to the indexed stream + */ + for ( ix = 0, + strmh = persp->s.strmheadh + ; + strmh != DH_NULL && ix < strmix + ; + ix++, + strmh = DH2S( strmh )->s_nexth ) + ; + + /* if an empty stream (can happen when dump interrupted), + * nothing need be done, so return + */ + if ( strmh == DH_NULL ) { + pi_unlock( ); + return; + } + + + /* get handle to indexed object in stream + */ + for ( ix = 0, + objh = DH2S( strmh )->s_cldh + ; + objh != DH_NULL && ix < mediaix + ; + ix++, + objh = DH2O( objh )->o_nexth ) + ; + + /* if an empty object (can happen when dump interrupted), + * nothing need be done, so return + */ + if ( objh == DH_NULL ) { + pi_unlock( ); + return; + } + + + /* set object flag + */ + DH2O( objh )->o_lmfknwnpr = BOOL_TRUE; + + pi_unlock( ); + pi_show( " after pi_seeobjstrmend" ); +} + +/* scans pi to determine ino of last file wholly or partially contained on + * this mfile. must err on the high side if partial info. + * NOTE: assumes caller locks pi! + */ +static xfs_ino_t +pi_scanfileendino( dh_t fileh ) +{ + dh_t strmh; + ix_t mode = 0; + + ASSERT( fileh != DH_NULL ); + + /* traverse the pi tree, looking for the next media file after + */ + for ( strmh = persp->s.strmheadh + ; + strmh != DH_NULL + ; + strmh = DH2S( strmh )->s_nexth ) { + dh_t objh; + + for ( objh = DH2S( strmh )->s_cldh + ; + objh != DH_NULL + ; + objh = DH2O( objh )->o_nexth ) { + dh_t nexth; + + for ( nexth = DH2O( objh )->o_cldh + ; + nexth != DH_NULL + ; + nexth = DH2F( nexth )->f_nexth ) { + + switch( mode ) { + case 0: + if ( nexth == fileh ) { + mode = 1; + } + break; + default: + if ( DH2F( nexth )->f_valpr ) { + xfs_ino_t ino; + + ASSERT( ! ( DH2F( nexth )->f_flags & PF_INV )); + ASSERT( ! ( DH2F( nexth )->f_flags & PF_TERM )); + if ( DH2F( nexth )->f_firstegrp.eg_off ) { + ino = DH2F( nexth )->f_firstegrp.eg_ino; + return ino; + } else { + ASSERT( DH2F( nexth )->f_firstegrp.eg_ino > 0 ); + ino = DH2F( nexth )->f_firstegrp.eg_ino - 1; + return ino; + } + } + break; + } + } + } + } + return INO64MAX; +} + +/* used to detemine range of extent groups still to be restored + * from media file. *--o + */ +static void +pi_bracketneededegrps( dh_t thisfileh, egrp_t *first_egrp, egrp_t *next_egrp ) +{ + dh_t strmh; + bool_t thisfoundpr = BOOL_FALSE; + dh_t prech = DH_NULL; + dh_t follh = DH_NULL; + + + ASSERT( thisfileh != DH_NULL ); + + /* traverse the pi tree, looking for fileh + */ + pi_lock( ); + ASSERT( DH2F( thisfileh )->f_valpr ); + + for ( strmh = persp->s.strmheadh + ; + strmh != DH_NULL + ; + strmh = DH2S( strmh )->s_nexth ) { + dh_t objh; + + for ( objh = DH2S( strmh )->s_cldh + ; + objh != DH_NULL + ; + objh = DH2O( objh )->o_nexth ) { + dh_t fileh; + + for ( fileh = DH2O( objh )->o_cldh + ; + fileh != DH_NULL + ; + fileh = DH2F( fileh )->f_nexth ) { + if ( ! thisfoundpr ) { + if ( fileh == thisfileh ) { + thisfoundpr = BOOL_TRUE; + } else if ( DH2F( fileh )->f_valpr ) { + ASSERT( ! ( DH2F( fileh )->f_flags & PF_INV )); + ASSERT( ! ( DH2F( fileh )->f_flags & PF_TERM )); + prech = fileh; + } + } else if ( DH2F( fileh )->f_valpr ) { + ASSERT( ! ( DH2F( fileh )->f_flags & PF_INV )); + ASSERT( ! ( DH2F( fileh )->f_flags & PF_TERM )); + ASSERT( follh == DH_NULL ); + follh = fileh; + goto done; + } + } + } + } +done: + + ASSERT( thisfoundpr ); + + /* initially the lower bracket is this file descriptor's + * current egrp. this catches the case where a previous restore + * session was interrupted while restoring this media file. + */ + *first_egrp = DH2F( thisfileh )->f_curegrp; + + /* if the closest valid preceeding media file's current egrp is + * greater, use it as the lower bracket + */ + if ( prech != DH_NULL + && + egrpcmp( &DH2F( prech )->f_curegrp, first_egrp ) > 0 ) { + *first_egrp = DH2F( prech )->f_curegrp; + } + + /* the upper bracket is initially the end of the world. + * if we found a valid following file descriptor describing a + * media file which has already been at least restored, use + * its first egrp as an upper bracket. + */ + next_egrp->eg_ino = INO64MAX; + next_egrp->eg_off = OFF64MAX; + if ( follh != DH_NULL + && + egrpcmp( &DH2F( follh )->f_curegrp, &DH2F( follh )->f_firstegrp ) + > + 0 ) { + *next_egrp = DH2F( follh )->f_firstegrp; + } + + pi_unlock( ); +} + +static void +pi_update_stats( off64_t sz ) +{ + pi_lock( ); + ASSERT( persp->s.stat_valpr ); + persp->s.stat_inodone++; + persp->s.stat_datadone += sz; + pi_unlock( ); +} + +/* pi_iterator - each invocation of the iterator advances to the next media file + * in the dump session, walking the media file hierarchy depth-wise. if + * an object's file list is exhausted and the first media file in the next + * object is returned and the exhausted object's last media file has not yet + * been identified, the return-by-ref flag filemissingpr is set. similarly for + * streams, objmissingpr. + * NOTE: does not preset missingpr's to FALSE. + * NOTE: caller must lock pi. + */ + +struct pi_iter { + bool_t initializedpr; + dh_t strmh; + dh_t objh; + dh_t fileh; + bool_t donepr; +}; + +typedef struct pi_iter pi_iter_t; + +static pi_iter_t * +pi_iter_alloc( void ) +{ + pi_iter_t *iterp; + + iterp = ( pi_iter_t * )calloc( 1, sizeof( pi_iter_t )); + ASSERT( iterp ); + return iterp; +} + +static void +pi_iter_free( pi_iter_t *iterp ) +{ + free( ( void * )iterp ); +} + +static dh_t +pi_iter_nextfileh( pi_iter_t *iterp, + bool_t *objmissingprp, + bool_t *filemissingprp ) +{ + ASSERT( ! iterp->donepr ); + + if ( persp->s.strmheadh == DH_NULL ) { + iterp->donepr = BOOL_TRUE; + return DH_NULL; + } + + if ( ! iterp->initializedpr ) { + ASSERT( persp->s.strmheadh != DH_NULL ); + iterp->strmh = persp->s.strmheadh; + iterp->objh = DH2S( iterp->strmh )->s_cldh; + if ( iterp->objh == DH_NULL ) { + if ( ! DH2S( iterp->strmh )->s_lastobjknwnpr ) { + *objmissingprp = BOOL_TRUE; + } + } else { + iterp->fileh = DH2O( iterp->objh )->o_cldh; + if ( iterp->fileh == DH_NULL ) { + if ( ! DH2O( iterp->objh )->o_lmfknwnpr ) { + *filemissingprp = BOOL_TRUE; + } + } + } + + while ( iterp->fileh == DH_NULL ) { + while ( iterp->objh == DH_NULL ) { + if ( ! DH2S( iterp->strmh )->s_lastobjknwnpr ) { + *objmissingprp = BOOL_TRUE; + } + iterp->strmh = DH2S( iterp->strmh )->s_nexth; + if ( iterp->strmh == DH_NULL ) { + iterp->donepr = BOOL_TRUE; + return DH_NULL; + } + iterp->objh = DH2S( iterp->strmh )->s_cldh; + } + iterp->fileh = DH2O( iterp->objh )->o_cldh; + if ( iterp->fileh == DH_NULL ) { + if ( ! DH2O( iterp->objh )->o_lmfknwnpr ) { + *filemissingprp = BOOL_TRUE; + } + iterp->objh = DH2O( iterp->objh )->o_nexth; + } + } + iterp->initializedpr = BOOL_TRUE; + return iterp->fileh; + } + + iterp->fileh = DH2F( iterp->fileh )->f_nexth; + while ( iterp->fileh == DH_NULL ) { + if ( ! DH2O( iterp->objh )->o_lmfknwnpr ) { + *filemissingprp = BOOL_TRUE; + } + iterp->objh = DH2O( iterp->objh )->o_nexth; + while ( iterp->objh == DH_NULL ) { + if ( ! DH2S( iterp->strmh )->s_lastobjknwnpr ) { + *objmissingprp = BOOL_TRUE; + } + iterp->strmh = DH2S( iterp->strmh )->s_nexth; + if ( iterp->strmh == DH_NULL ) { + iterp->donepr = BOOL_TRUE; + return DH_NULL; + } + iterp->objh = DH2S( iterp->strmh )->s_cldh; + } + iterp->fileh = DH2O( iterp->objh )->o_cldh; + } + + return iterp->fileh; +} + +/* produces a list of media objects needed. also indicates if we know + * some unidentified media objects are needed, and if it is possible + * that we need some unidentifed objects, but don't know for sure. + * if markskippr is set, set the f_nondirskipr flag if the media file + * does not contain any nondirs of interest. + */ + +struct bagobj { + bagelem_t bagelem; + uuid_t id; + label_t label; + bool_t indrivepr; + ix_t indriveix; +}; + +typedef struct bagobj bagobj_t; + +static bag_t * +pi_neededobjs_nondir_alloc( bool_t *knownholesprp, + bool_t *maybeholesprp, + bool_t showobjindrivepr, + bool_t markskippr ) +{ + bag_t *bagp; + pi_iter_t *headiterp; + pi_iter_t *tailiterp; + dh_t headh; + dh_t tailh; + egrp_t tailegrp; + bool_t knownobjmissingpr; + bool_t maybeobjmissingpr; + bool_t maybefilemissingpr; + dh_t lastobjaddedh; + intgen_t objlistlen; + + /* no point in proceeding if pi not begun + */ + if ( persp->s.strmheadh == DH_NULL ) { + *knownholesprp = BOOL_TRUE; + *maybeholesprp = BOOL_FALSE; + return 0; + } + + /* to hold a list of media object handles: caller must free + * using pi_neededobjs_free( ). + */ + bagp = bag_alloc( ); + + /* allocate two iterators to scan pi + */ + tailiterp = pi_iter_alloc( ); + headiterp = pi_iter_alloc( ); + + /* set the handle to the last file added to the list to NULL. + * this will be updated each time we add an object to the list, + * preventing the same object from being added more than once. + * this works because the media files for a given object will + * always appear contiguous and just once in a pi iteration. + */ + lastobjaddedh = DH_NULL; + objlistlen = 0; + + /* these will be set TRUE if the tail iterator ever indicates + * we crossed an object or stream boundary and did not see a + * valid last file or last object respectively. can accumulate + * the booleans, since iterator never sets FALSE, just TRUE. + */ + maybeobjmissingpr = BOOL_FALSE; + maybefilemissingpr = BOOL_FALSE; + + /* this will be set TRUE if we see a needed media file but the + * object containing the media file has not been IDed. + */ + knownobjmissingpr = BOOL_FALSE; + + tailegrp.eg_ino = 0; + tailegrp.eg_off = 0; + + tailh = DH_NULL; + + /* lock up the inventory during the scan + */ + pi_lock( ); + + do { + egrp_t headegrp; + bool_t foundgappr; + + /* advance the head until we see the next media file which has + * a valid egrp, or until we run out of media files. + */ + do { + bool_t dummyobjmissingpr; + bool_t dummyfilemissingpr; + headh = pi_iter_nextfileh( headiterp, + &dummyobjmissingpr, + &dummyfilemissingpr ); + } while ( headh != DH_NULL && ! DH2F( headh )->f_valpr ); + if ( headh == DH_NULL ) { + headegrp.eg_ino = INO64MAX; + headegrp.eg_off = OFF64MAX; + } else { + ASSERT( ! ( DH2F( headh )->f_flags & PF_INV )); + ASSERT( ! ( DH2F( headh )->f_flags & PF_TERM )); + headegrp = DH2F( headh )->f_firstegrp; + } + + /* see if the range of egrps from head up to but not including + * tail needed according to ino map + */ + if ( gapneeded( &tailegrp, &headegrp )) { + foundgappr = BOOL_TRUE; + } else { + foundgappr = BOOL_FALSE; + } + + /* now bring tail up to head, adding objects and setting flags + * along the way. note special handling of NULL tailh. possible + * only first time through: ignore. also, ignore inv and term. + */ + do { + /* if requested, mark media files not needed + */ + if ( markskippr + && + ! foundgappr + && + tailh != DH_NULL + && + ! ( DH2F( tailh )->f_flags & PF_INV ) + && + ! ( DH2F( tailh )->f_flags & PF_TERM ) + && + ! DH2F( tailh )->f_nondirskippr ) { + DH2F( tailh )->f_nondirskippr = BOOL_TRUE; + } + + /* build up list of needed objects + */ + if ( foundgappr + && + tailh != DH_NULL + && + ! ( DH2F( tailh )->f_flags & PF_INV ) + && + ! ( DH2F( tailh )->f_flags & PF_TERM ) + && + ! DH2F( tailh )->f_nondirdonepr + && + ! DH2F( tailh )->f_nondirskippr ) { + + dh_t objh = DH2F( tailh )->f_parh; + + if ( ! DH2O( objh )->o_indrivepr + || + showobjindrivepr ) { + if ( DH2O( objh )->o_idlabvalpr ) { + if ( objh != lastobjaddedh ) { + addobj( bagp, + &DH2O( objh )->o_id, + DH2O( objh )->o_lab, + DH2O( objh )->o_indrivepr, + DH2O( objh )->o_indriveix ); + lastobjaddedh = objh; + objlistlen++; + } + } else { + knownobjmissingpr = BOOL_TRUE; + } + } + } + + /* pull the tail up to the next media file + */ + tailh = pi_iter_nextfileh( tailiterp, + &maybeobjmissingpr, + &maybefilemissingpr ); + } while ( tailh != headh ); + + tailegrp = headegrp; + + } while ( headh != DH_NULL ); + + pi_unlock( ); + + /* free the iterators + */ + pi_iter_free( tailiterp ); + pi_iter_free( headiterp ); + + /* free the bag and return NULL if object list empty + */ + if ( objlistlen == 0 ) { + bag_free( bagp ); + bagp = 0; + } + + *maybeholesprp = ( maybeobjmissingpr || maybefilemissingpr ); + *knownholesprp = knownobjmissingpr; + return bagp; +} + +static bag_t * +pi_neededobjs_dir_alloc( bool_t *knownholesprp, bool_t *maybeholesprp ) +{ + bag_t *bagp; + dh_t fileh; + pi_iter_t *iterp; + bool_t knownobjmissingpr; + bool_t maybeobjmissingpr; + bool_t maybefilemissingpr; + dh_t lastobjaddedh; + intgen_t objlistlen; + + bagp = bag_alloc( ); + iterp = pi_iter_alloc( ); + + knownobjmissingpr = BOOL_FALSE; + maybeobjmissingpr = BOOL_FALSE; + maybefilemissingpr = BOOL_FALSE; + lastobjaddedh = DH_NULL; + objlistlen = 0; + + pi_lock( ); + + while ( ( fileh = pi_iter_nextfileh( iterp, + &maybeobjmissingpr, + &maybefilemissingpr )) + != DH_NULL ) { + if ( ! DH2F( fileh )->f_dirtriedpr ) { + dh_t objh = DH2F( fileh )->f_parh; + if ( ! DH2O( objh )->o_indrivepr ) { + if ( DH2O( objh )->o_idlabvalpr ) { + if ( objh != lastobjaddedh ) { + addobj( bagp, + &DH2O( objh )->o_id, + DH2O( objh )->o_lab, + DH2O( objh )->o_indrivepr, + DH2O( objh )->o_indriveix ); + lastobjaddedh = objh; + objlistlen++; + } + } else { + knownobjmissingpr = BOOL_TRUE; + } + } + } + } + + pi_unlock( ); + + pi_iter_free( iterp ); + + if ( objlistlen == 0 ) { + bag_free( bagp ); + bagp = 0; + } + + *maybeholesprp = ( maybeobjmissingpr || maybefilemissingpr ); + *knownholesprp = knownobjmissingpr; + return bagp; +} + +static void +pi_neededobjs_free( bag_t *bagp ) +{ + bagiter_t bagiter; + bagobj_t *bagobjp; + bagelem_t *bagelemp; + size64_t dummykey; + void *dummypayloadp; + + ASSERT( bagp ); + + bagiter_init( bagp, &bagiter ); + + bagobjp = 0; + while (( bagelemp = bagiter_next( &bagiter, ( void ** )&bagobjp ) )) { + bag_remove( bagp, bagelemp, &dummykey, &dummypayloadp ); + ASSERT( bagobjp ); + ASSERT( bagobjp == ( bagobj_t * )dummypayloadp ); + free( ( void * )bagobjp ); + bagobjp = 0; + } + + bag_free( bagp ); +} + +/* a macro predicate to indicate if we know we are done. if we are not + * done or don't know, returns FALSE. + */ +static bool_t +pi_alldone( void ) +{ + bag_t *bagp; + bool_t knownholespr; + bool_t maybeholespr; + size_t cnt; + + knownholespr = BOOL_FALSE; + maybeholespr = BOOL_FALSE; + bagp = pi_neededobjs_nondir_alloc( &knownholespr, + &maybeholespr, + BOOL_TRUE, + BOOL_FALSE ); + if ( bagp ) { + cnt = cntobj( bagp ); + pi_neededobjs_free( bagp ); + } else { + cnt = 0; + } + + if ( cnt || knownholespr || maybeholespr ) { + return BOOL_FALSE; + } else { + return BOOL_TRUE; + } +} + +/* tells the persistent inventory we hit end-of-data while examining the + * object specified by the index param. this tells us we've seen the end + * of the stream as well as the end of the object. + */ +static void +pi_hiteod( ix_t strmix, ix_t objix ) +{ + ix_t ix; + dh_t strmh; + dh_t objh; + size_t objcnt; + ix_t lastobjix; + + pi_lock( ); + + /* get handle to the indexed stream + */ + for ( ix = 0, + strmh = persp->s.strmheadh + ; + strmh != DH_NULL && ix < strmix + ; + ix++, + strmh = DH2S( strmh )->s_nexth ) + ; + ASSERT( strmh != DH_NULL ); + + /* get index to last object in stream + */ + for ( objcnt = 0, objh = DH2S( strmh )->s_cldh + ; + objh != DH_NULL + ; + objh = DH2O( objh )->o_nexth, objcnt++ ) + ; + ASSERT( objcnt != 0 ); + lastobjix = objcnt - 1; + + pi_unlock( ); + + /* can't possibly happen, but check for case where pi indicates + * other media objects beyond this one. + */ + if ( objix != lastobjix ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_MEDIA, + "hit EOD at stream %u object %u, " + "yet inventory indicates last object index is %u\n", + strmix, + objix, + lastobjix ); + } else { + pi_seestrmend( strmix ); + } + + pi_seeobjstrmend( strmix, lastobjix ); +} + +/* tells the persistent inventory we hit end-of-media while examining the + * object specified by the index param. this tells us we've seen the end + * of the object. + */ +static void +pi_hiteom( ix_t strmix, ix_t objix ) +{ +#ifndef EOMFIX + pi_seestrmend( strmix ); +#endif /* ! EOMFIX */ + pi_seeobjstrmend( strmix, objix ); +} + +static void +pi_hitnextdump( ix_t strmix, ix_t objix, ix_t lastfileix ) +{ + ix_t ix; + dh_t strmh; + dh_t objh; + size_t objcnt; + ix_t lastobjix; + + pi_lock( ); + + /* get handle to the indexed stream + */ + for ( ix = 0, + strmh = persp->s.strmheadh + ; + strmh != DH_NULL && ix < strmix + ; + ix++, + strmh = DH2S( strmh )->s_nexth ) + ; + ASSERT( strmh != DH_NULL ); + + /* get index to last object in stream + */ + for ( objcnt = 0, objh = DH2S( strmh )->s_cldh + ; + objh != DH_NULL + ; + objh = DH2O( objh )->o_nexth, objcnt++ ) + ; + ASSERT( objcnt != 0 ); + lastobjix = objcnt - 1; + + pi_unlock( ); + + /* can't possibly happen, but check for case where pi indicates + * other media objects beyond this one. + */ + if ( objix != lastobjix ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_MEDIA, + "hit next dump at stream %u object %u file %u, " + "yet inventory indicates last object index is %u\n", + strmix, + objix, + lastfileix, + lastobjix ); + } else { + pi_seestrmend( strmix ); + } + + pi_seeobjstrmend( strmix, lastobjix ); +} + +/* returns TRUE if pi is certain no more useful media files remaining + * on object. if any doubt, such as not knowing the last media file on + * the object, returns FALSE. + */ +static bool_t +pi_know_no_more_on_object( purp_t purp, ix_t strmix, ix_t objix ) +{ + ix_t ix; + dh_t strmh; + dh_t objh; + dh_t fileh; + + ASSERT( purp == PURP_DIR || purp == PURP_NONDIR ); + + pi_lock( ); + + /* get handle to the indexed stream + */ + for ( ix = 0, + strmh = persp->s.strmheadh + ; + strmh != DH_NULL && ix < strmix + ; + ix++, + strmh = DH2S( strmh )->s_nexth ) + ; + ASSERT( strmh != DH_NULL ); + + /* get handle to indexed object + */ + for ( ix = 0, objh = DH2S( strmh )->s_cldh + ; + objh != DH_NULL && ix < objix + ; + ix++, + objh = DH2O( objh )->o_nexth ) + ; + ASSERT( objh != DH_NULL ); + + /* if don't know last media file on object, return FALSE + */ + if ( ! DH2O( objh )->o_lmfknwnpr ) { + pi_unlock( ); + return BOOL_FALSE; + } + + /* check all media files on object. if any are not marked done, + * return FALSE. + */ + for ( fileh = DH2O( objh )->o_cldh + ; + fileh != DH_NULL + ; + fileh = DH2F( fileh )->f_nexth ) { + if ( DH2F( fileh )->f_flags & PF_INV ) { + continue; + } + if ( DH2F( fileh )->f_flags & PF_TERM ) { + continue; + } + if ( purp == PURP_DIR ) { + if ( ! DH2F( fileh )->f_dirtriedpr ) { + pi_unlock( ); + return BOOL_FALSE; + } + } else { + if ( ! DH2F( fileh )->f_nondirskippr + && + ! DH2F( fileh )->f_nondirdonepr ) { + pi_unlock( ); + return BOOL_FALSE; + } + } + } + + pi_unlock( ); + return BOOL_TRUE; +} + +static bool_t +pi_know_no_more_beyond_on_object( purp_t purp, + ix_t strmix, + ix_t objix, + ix_t fileix ) +{ + ix_t ix; + dh_t strmh; + dh_t objh; + dh_t fileh; + + ASSERT( purp == PURP_DIR || purp == PURP_NONDIR ); + + pi_lock( ); + + /* get handle to the indexed stream + */ + for ( ix = 0, + strmh = persp->s.strmheadh + ; + strmh != DH_NULL && ix < strmix + ; + ix++, + strmh = DH2S( strmh )->s_nexth ) + ; + ASSERT( strmh != DH_NULL ); + + /* get handle to indexed object + */ + for ( ix = 0, + objh = DH2S( strmh )->s_cldh + ; + objh != DH_NULL && ix < objix + ; + ix++, + objh = DH2O( objh )->o_nexth ) + ; + ASSERT( objh != DH_NULL ); + + /* if don't know last media file on object, return FALSE + */ + if ( ! DH2O( objh )->o_lmfknwnpr ) { + pi_unlock( ); + return BOOL_FALSE; + } + + /* check all files on object after indexed file. if any are not marked + * done, return FALSE. skip inventory and terminator files. + */ + for ( ix = 0, + fileh = DH2O( objh )->o_cldh + ; + fileh != DH_NULL + ; + ix++, + fileh = DH2F( fileh )->f_nexth ) { + if ( ix <= fileix ) { + continue; + } + if ( DH2F( fileh )->f_flags & PF_INV ) { + continue; + } + if ( DH2F( fileh )->f_flags & PF_TERM ) { + continue; + } + if ( purp == PURP_DIR ) { + if ( ! DH2F( fileh )->f_dirtriedpr ) { + pi_unlock( ); + return BOOL_FALSE; + } + } else { + if ( ! DH2F( fileh )->f_nondirdonepr + && + ! DH2F( fileh )->f_nondirskippr ) { + pi_unlock( ); + return BOOL_FALSE; + } + } + } + + pi_unlock( ); + return BOOL_TRUE; +} + +/* indicates if the given extent group range is called for by the + * ino map. *---o (endpoint not inclusive) + */ +static bool_t +gapneeded( egrp_t *firstegrpp, egrp_t *lastegrpp ) +{ + xfs_ino_t endino; + + if ( firstegrpp->eg_ino > lastegrpp->eg_ino ) { + return BOOL_FALSE; + } + + if ( firstegrpp->eg_ino == lastegrpp->eg_ino + && + firstegrpp->eg_off > lastegrpp->eg_off ) { + return BOOL_FALSE; + } + + if ( lastegrpp->eg_off > 0 || lastegrpp->eg_ino == 0 ) { + endino = lastegrpp->eg_ino; + } else { + endino = lastegrpp->eg_ino - 1; + } + + if ( ! inomap_rst_needed( firstegrpp->eg_ino, endino )) { + return BOOL_FALSE; + } + + return BOOL_TRUE; +} + +static void +addobj( bag_t *bagp, + uuid_t *idp, + label_t label, + bool_t indrivepr, + ix_t indriveix ) +{ + bagobj_t *bagobjp; + + bagobjp = ( bagobj_t * )calloc( 1, sizeof( bagobj_t )); + ASSERT( bagobjp ); + uuid_copy(bagobjp->id, *idp); + strncpy( bagobjp->label, + label, + sizeof( bagobjp->label )); + bagobjp->indrivepr = indrivepr; + bagobjp->indriveix = indriveix; + bag_insert( bagp, + &bagobjp->bagelem, + ( size64_t )0, + ( void * )bagobjp ); +} + +static size_t +cntobj( bag_t *bagp ) +{ + bagiter_t bagiter; + bagobj_t *bagobjp; + size_t cnt; + + ASSERT( bagp ); + + bagiter_init( bagp, &bagiter ); + cnt = 0; + bagobjp = 0; /* keep lint happy */ + while ( bagiter_next( &bagiter, ( void ** )&bagobjp )) { + cnt++; + bagobjp = 0; /* keep lint happy */ + } + + return cnt; +} + + +/* misc. static functions ***************************************************/ + +/* queries inventory for the base of the given session. if the given session + * was a resumed dump, then must be last dump of same level. otherwise, + * must be last dump of a lesser level + */ +static bool_t +askinvforbaseof( uuid_t baseid, inv_session_t *sessp ) +{ + ix_t level; + bool_t resumedpr; + inv_idbtoken_t invtok; + inv_session_t *basesessp; + bool_t ok; + + level = ( ix_t )sessp->s_level; + resumedpr = sessp->s_isresumed; + + /* don't look for base if level 0 and not resumed + */ + if ( level == 0 && ! resumedpr ) { + return BOOL_TRUE; + } + + /* open the inventory for this file system + */ + invtok = inv_open( INV_BY_UUID, + INV_SEARCH_ONLY, + ( void * )&sessp->s_fsid ); + if ( invtok == INV_TOKEN_NULL ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_MEDIA, + "unable to open inventory to validate dump\n" ); + return BOOL_FALSE; + } + + /* get the base session + */ + if ( resumedpr ) { + ok = inv_lastsession_level_equalto( invtok, + ( u_char_t )level, + &basesessp ); + } else { + ok = inv_lastsession_level_lessthan( invtok, + ( u_char_t )level, + &basesessp ); + } + if ( ! ok ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_MEDIA, + "unable to find base dump in inventory " + "to validate dump\n" ); + return BOOL_FALSE; + } + + /* close the inventory + */ + ok = inv_close( invtok ); + ASSERT( ok ); + + /* return id of base session + */ + uuid_copy(baseid, basesessp->s_sesid); + + /* free the base session descriptor + */ + inv_free_session( &basesessp ); + + return BOOL_TRUE; +} + +static bool_t +dumpcompat( bool_t resumepr, ix_t level, uuid_t baseid, bool_t logpr ) +{ + if ( persp->a.cumpr ) { + if ( persp->a.dumpcnt == 0 ) { + if ( resumepr ) { + if ( logpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "cumulative restores must begin with " + "an initial (not resumed) " + "level 0 dump\n" ); + } + return BOOL_FALSE; + } + if ( level > 0 ) { + if ( logpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "cumulative restores must begin with " + "a level 0 dump\n" ); + } + return BOOL_FALSE; + } + } else { + if ( resumepr ) { + if ( uuid_compare( persp->a.lastdumpid, + baseid) != 0) { + if ( logpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "selected resumed dump " + "not a resumption of " + "previously applied dump\n" ); + } + return BOOL_FALSE; + } + } else { + if ( uuid_compare( persp->a.lastdumpid, + baseid) != 0) { + if ( logpr ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "selected dump not based on " + "previously applied dump\n" ); + } + return BOOL_FALSE; + } + } + } + } + + return BOOL_TRUE; +} + +/* prompts for a new media object. supplies list of media objects still + * needed, and indicates if there are or may be unidentified media objects + * still needed/available + */ +static bool_t +Media_prompt_change( drive_t *drivep, + purp_t purp, + bag_t *bagp, + bool_t knownholespr, + bool_t maybeholespr ) +{ + fold_t fold; + char question[ 100 ]; + char *preamblestr[ PREAMBLEMAX ]; + size_t preamblecnt; + char *querystr[ QUERYMAX ]; + size_t querycnt; + char *choicestr[ CHOICEMAX ]; + size_t choicecnt; + char *ackstr[ ACKMAX ]; + size_t ackcnt; + char *postamblestr[ POSTAMBLEMAX ]; + size_t postamblecnt; + ix_t doix; + ix_t dontix; + ix_t invstatix; + ix_t neededix; + ix_t responseix; + ix_t sigintix; + +retry: + fold_init( fold, "change media dialog", '=' ); + preamblecnt = 0; + preamblestr[ preamblecnt++ ] = "\n"; + preamblestr[ preamblecnt++ ] = fold; + preamblestr[ preamblecnt++ ] = "\n\n"; + ASSERT( preamblecnt <= PREAMBLEMAX ); + dlog_begin( preamblestr, preamblecnt ); + + /* query: ask if media changed or declined + */ + if ( drivecnt > 1 ) { + sprintf( question, + "please change media in " + "drive %u\n", + (unsigned int)drivep->d_index ); + } else { + sprintf( question, + "please change media in " + "drive\n" ); + } + querycnt = 0; + querystr[ querycnt++ ] = question; + ASSERT( querycnt <= QUERYMAX ); + choicecnt = 0; + dontix = choicecnt; + choicestr[ choicecnt++ ] = "media change declined"; + if ( purp != PURP_SEARCH ) { + invstatix = choicecnt; + choicestr[ choicecnt++ ] = "display media inventory status"; + neededix = choicecnt; + choicestr[ choicecnt++ ] = "list needed media objects"; + } else { + invstatix = IXMAX; + neededix = IXMAX; + } + doix = choicecnt; + choicestr[ choicecnt++ ] = "media changed"; + ASSERT( choicecnt <= CHOICEMAX ); + sigintix = IXMAX - 1; + + responseix = dlog_multi_query( querystr, + querycnt, + choicestr, + choicecnt, + 0, /* hilitestr */ + IXMAX, /* hiliteix */ + 0, /* defaultstr */ + doix, /* defaultix */ + DLOG_TIMEOUT_MEDIA, + dontix, /* timeout ix */ + sigintix, /* sigint ix */ + dontix, /* sighup ix */ + dontix ); /* sigquit ix */ + ackcnt = 0; + if ( responseix == doix ) { + ackstr[ ackcnt++ ] = "examining new media\n"; + } else if ( responseix == dontix ) { + ackstr[ ackcnt++ ] = "media change aborted\n"; + } else if ( responseix == invstatix ) { + ackstr[ ackcnt++ ] = "\n"; + ASSERT( ackcnt <= ACKMAX ); + dlog_multi_ack( ackstr, + ackcnt ); + pi_show_nomloglock( ); + postamblecnt = 0; + fold_init( fold, "end dialog", '-' ); + postamblestr[ postamblecnt++ ] = "\n"; + postamblestr[ postamblecnt++ ] = fold; + postamblestr[ postamblecnt++ ] = "\n\n"; + ASSERT( postamblecnt <= POSTAMBLEMAX ); + dlog_end( postamblestr, + postamblecnt ); + goto retry; + } else if ( responseix == neededix ) { + ackstr[ ackcnt++ ] = "\n"; + ASSERT( ackcnt <= ACKMAX ); + dlog_multi_ack( ackstr, + ackcnt ); + display_needed_objects( purp, + bagp, + knownholespr, + maybeholespr ); + postamblecnt = 0; + fold_init( fold, "end dialog", '-' ); + postamblestr[ postamblecnt++ ] = "\n"; + postamblestr[ postamblecnt++ ] = fold; + postamblestr[ postamblecnt++ ] = "\n\n"; + ASSERT( postamblecnt <= POSTAMBLEMAX ); + dlog_end( postamblestr, + postamblecnt ); + goto retry; + } else { + ASSERT( responseix == sigintix ); + ackstr[ ackcnt++ ] = "keyboard interrupt\n"; + } + + ASSERT( ackcnt <= ACKMAX ); + dlog_multi_ack( ackstr, + ackcnt ); + + postamblecnt = 0; + fold_init( fold, "end dialog", '-' ); + postamblestr[ postamblecnt++ ] = "\n"; + postamblestr[ postamblecnt++ ] = fold; + postamblestr[ postamblecnt++ ] = "\n\n"; + ASSERT( postamblecnt <= POSTAMBLEMAX ); + dlog_end( postamblestr, + postamblecnt ); + + if ( responseix == sigintix ) { + if ( cldmgr_stop_requested( )) { + return BOOL_FALSE; + } + sleep( 1 ); /* to allow main thread to begin dialog */ + mlog( MLOG_NORMAL | MLOG_BARE, + "" ); /* to block until main thread dialog complete */ + sleep( 1 ); /* to allow main thread to request children die */ + if ( cldmgr_stop_requested( )) { + return BOOL_FALSE; + } + mlog( MLOG_DEBUG, + "retrying media change dialog\n" ); + goto retry; + } + + return responseix == doix; +} +/* prompts the operator, asking if the current media file header describes + * the dump to be restored + */ +static bool_t +promptdumpmatch( ix_t thrdix, + global_hdr_t *grhdrp, + media_hdr_t *mrhdrp, + content_hdr_t *crhdrp, + content_inode_hdr_t *scrhdrp ) +{ + fold_t fold; + char introstring[ 80 ]; + char *preamblestr[ PREAMBLEMAX ]; + size_t preamblecnt; + char *querystr[ QUERYMAX ]; + size_t querycnt; + char *choicestr[ CHOICEMAX ]; + size_t choicecnt; + char *ackstr[ ACKMAX ]; + size_t ackcnt; + char *postamblestr[ POSTAMBLEMAX ]; + size_t postamblecnt; + ix_t doix; + ix_t dontix; + ix_t responseix; + ix_t sigintix; + +retry: + preamblecnt = 0; + fold_init( fold, "dump selection dialog", '=' ); + preamblestr[ preamblecnt++ ] = "\n"; + preamblestr[ preamblecnt++ ] = fold; + preamblestr[ preamblecnt++ ] = "\n\n"; + ASSERT( preamblecnt <= PREAMBLEMAX ); + dlog_begin( preamblestr, preamblecnt ); + + /* display vital stats and ask if this one should be restored + */ + if ( drivecnt > 0 ) { + sprintf( introstring, + "the following dump has been found" + " on drive %u" + "\n\n", + (unsigned int)thrdix ); + } else { + sprintf( introstring, + "the following dump has been found" + "\n\n" ); + } + ASSERT( strlen( introstring ) < sizeof( introstring )); + display_dump_label( BOOL_FALSE, + MLOG_NORMAL | MLOG_BARE, + introstring, + grhdrp, + mrhdrp, + crhdrp, + scrhdrp ); + + querycnt = 0; + if ( tranp->t_toconlypr ) { + querystr[ querycnt++ ] = "\nexamine this dump?\n"; + } else { + querystr[ querycnt++ ] = "\nrestore this dump?\n"; + } + ASSERT( querycnt <= QUERYMAX ); + choicecnt = 0; + dontix = choicecnt; + choicestr[ choicecnt++ ] = "skip"; + doix = choicecnt; + choicestr[ choicecnt++ ] = "restore"; + ASSERT( choicecnt <= CHOICEMAX ); + sigintix = IXMAX - 1; + + responseix = dlog_multi_query( querystr, + querycnt, + choicestr, + choicecnt, + 0, /* hilitestr */ + IXMAX, /* hiliteix */ + 0, /* defaultstr */ + doix, /* defaultix */ + 0, + IXMAX, /* timeout ix */ + sigintix, /* sigint ix */ + dontix, /* sighup ix */ + dontix ); /* sigquit ix */ + ackcnt = 0; + if ( responseix == doix ) { + ackstr[ ackcnt++ ] = "this dump selected for restoral\n"; + } else if ( responseix == dontix ) { + ackstr[ ackcnt++ ] = "dump skipped\n"; + } else { + ASSERT( responseix == sigintix ); + ackstr[ ackcnt++ ] = "keyboard interrupt\n"; + } + + ASSERT( ackcnt <= ACKMAX ); + dlog_multi_ack( ackstr, + ackcnt ); + + postamblecnt = 0; + fold_init( fold, "end dialog", '-' ); + postamblestr[ postamblecnt++ ] = "\n"; + postamblestr[ postamblecnt++ ] = fold; + postamblestr[ postamblecnt++ ] = "\n\n"; + ASSERT( postamblecnt <= POSTAMBLEMAX ); + dlog_end( postamblestr, + postamblecnt ); + + if ( responseix == sigintix ) { + if ( cldmgr_stop_requested( )) { + return BOOL_FALSE; + } + sleep( 1 ); /* to allow main thread to begin dialog */ + mlog( MLOG_NORMAL | MLOG_BARE, + "" ); /* to block until main thread dialog complete */ + sleep( 1 ); /* to allow main thread to request children die */ + if ( cldmgr_stop_requested( )) { + return BOOL_FALSE; + } + mlog( MLOG_DEBUG, + "retrying dump selection dialog\n" ); + goto retry; + } + + return responseix == doix; +} + +/* restore_file - knows how to restore non-directory files + * + * uses the tree's callback iterator, which will call me for each + * link to the specified inode. + */ +struct cb_context { + drive_t *cb_drivep; + filehdr_t *cb_fhdrp; + rv_t cb_rv; + bool_t cb_ehcs; + char *cb_path1; + char *cb_path2; +}; + +typedef struct cb_context cb_context_t; + +static bool_t restore_file_cb( void *, bool_t, char *, char * ); + +static rv_t +restore_file( drive_t *drivep, + filehdr_t *fhdrp, + bool_t ehcs, + char *path1, + char *path2 ) +{ + bstat_t *bstatp = &fhdrp->fh_stat; + cb_context_t context; + + /* ask the tree to call me back for each link to this inode. + * my callback will restore the file the first time it is + * invoked, and create a hard link in subsequent calls. + */ + context.cb_drivep = drivep; + context.cb_fhdrp = fhdrp; + context.cb_rv = RV_OK; + context.cb_ehcs = ehcs; + context.cb_path1 = path1; + context.cb_path2 = path2; + tree_cb_links( bstatp->bs_ino, + bstatp->bs_gen, + bstatp->bs_ctime.tv_sec, + bstatp->bs_mtime.tv_sec, + restore_file_cb, + &context, + path1, + path2 ); + + return context.cb_rv; +} + +/* called for each link to the file described by fhdr. the first + * call is detected by noting linkpr is FALSE, and is used to create/ + * update the first link to the file, using path1. subsequent calls have + * linkpr set false, and should link path1 to path2. if path1 is ever null, + * just pull from media: don't create. + * if this func returns FALSE, will cause tree_cb_links to abort + */ +static bool_t +restore_file_cb( void *cp, bool_t linkpr, char *path1, char *path2 ) +{ + cb_context_t *contextp = ( cb_context_t * )cp; + drive_t *drivep = contextp->cb_drivep; + filehdr_t *fhdrp = contextp->cb_fhdrp; + bstat_t *bstatp = &fhdrp->fh_stat; + rv_t *rvp = &contextp->cb_rv; + bool_t ehcs = contextp->cb_ehcs; + int rval; + bool_t ok; + + if ( cldmgr_stop_requested( )) { + *rvp = RV_INTR; + return BOOL_FALSE; + } + + if ( ! linkpr ) { + /* call type-specific function to create the file + */ + switch( bstatp->bs_mode & S_IFMT ) { + case S_IFREG: + ok = restore_reg( drivep, fhdrp, rvp, path1, ehcs ); + return ok; + case S_IFBLK: + case S_IFCHR: + case S_IFIFO: +#ifdef S_IFNAM + case S_IFNAM: +#endif +#ifdef DOSOCKS + case S_IFSOCK: +#endif /* DOSOCKS */ + ok = restore_spec( fhdrp, rvp, path1 ); + return ok; + case S_IFLNK: + ok = restore_symlink( drivep, + fhdrp, + rvp, + path1, + path2, + ehcs ); + return ok; + default: + mlog( MLOG_NORMAL | MLOG_WARNING, + "ino %llu: unknown file type: %08x\n", + bstatp->bs_ino, + bstatp->bs_mode ); + return BOOL_FALSE; + } + } else if ( ! tranp->t_toconlypr ) { + ASSERT( path1 ); + ASSERT( path2 ); + mlog( MLOG_TRACE, + "linking %s to %s\n", + path1, + path2 ); + rval = unlink( path2 ); + if ( rval && errno != ENOENT ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "unable to unlink " + "current file prior to linking " + "%s to %s:" + " %s\n", + path1, + path2, + strerror( errno )); + } else { + rval = link( path1, path2 ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "attempt to " + "link %s to %s failed:" + " %s\n", + path1, + path2, + strerror( errno )); + } + } + return BOOL_TRUE; + } else { + mlog( MLOG_NORMAL | MLOG_BARE, + "%s\n", + path2 ); + return BOOL_TRUE; + } +} + +/* called to peel a regular file's extent groups from the media. + * if no path given, or if just toc, don't actually write, just + * read. also get into that situation if cannot prepare destination. + * fd == -1 signifies no write. *statp is set to indicate drive errors. + * returns FALSE if should abort this iteration. + */ +static bool_t +restore_reg( drive_t *drivep, + filehdr_t *fhdrp, + rv_t *rvp, + char *path, + bool_t ehcs ) +{ + bstat_t *bstatp = &fhdrp->fh_stat; + intgen_t fd; + intgen_t rval; +#ifdef EXTATTR + off64_t restoredsz = 0; +#endif /* EXTATTR */ + off64_t offset = 0; + rv_t rv; + + if ( ! path ) { + fd = -1; + } else { + struct stat64 stat; + + offset = fhdrp->fh_offset; + if ( offset ) { + if ( ! tranp->t_toconlypr ) { + mlog( MLOG_TRACE, + "restoring regular file ino %llu %s" + " (offset %lld)\n", + bstatp->bs_ino, + path, + offset ); + } else { + mlog( MLOG_NORMAL | MLOG_BARE, + "%s (offset %lld)\n", + path, + offset ); + } + } else { + if ( ! tranp->t_toconlypr ) { + mlog( MLOG_TRACE, + "restoring regular file ino %llu %s\n", + bstatp->bs_ino, + path ); + } else { + mlog( MLOG_NORMAL | MLOG_BARE, + "%s\n", + path ); + } + } + + if ( tranp->t_toconlypr ) { + fd = -1; + } else { + intgen_t oflags; + bool_t isrealtime; + + isrealtime = ( bool_t )( bstatp->bs_xflags + & + XFS_XFLAG_REALTIME ); + oflags = O_CREAT | O_RDWR; + if ( persp->a.dstdirisxfspr && isrealtime ) { + oflags |= O_DIRECT; + } + + fd = open( path, oflags, S_IRUSR | S_IWUSR ); + if ( fd < 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "open of %s failed: " + "%s: discarding ino %llu\n", + path, + strerror( errno ), + fhdrp->fh_stat.bs_ino ); + fd = -1; + } else { + rval = fstat64( fd, &stat ); + if ( rval != 0 ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "attempt to stat %s " + "failed: %s\n", + path, + strerror( errno )); + } else { + if ( stat.st_size + != + bstatp->bs_size ) { + mlog( MLOG_TRACE, + "truncating %s" + " from %lld " + "to %lld\n", + path, + stat.st_size, + bstatp->bs_size ); + rval = + ftruncate64( fd, + bstatp->bs_size); + if ( rval != 0 ) { + mlog( MLOG_VERBOSE|MLOG_WARNING, + "attempt" + " to truncate %s" + " failed: %s\n", + path, + strerror( errno )); + } + } + } + +#ifdef EXTATTR + /* set the extended attributes + */ + if ( persp->a.dstdirisxfspr ) { + struct fsxattr fsxattr; + + ( void )memset((void *)&fsxattr, + 0, + sizeof( fsxattr )); + fsxattr.fsx_xflags = + bstatp->bs_xflags; + ASSERT( bstatp->bs_extsize >= 0 ); + fsxattr.fsx_extsize = + ( u_int32_t ) + bstatp->bs_extsize; + + rval = ioctl( fd, + XFS_IOC_FSSETXATTR, + (void *)&fsxattr); + if ( rval < 0 ) { + mlog(MLOG_NORMAL | MLOG_WARNING, + "attempt to set " + "extended " + "attributes " + "(xflags 0x%x, " + "extsize = 0x%x)" + "of %s failed: " + "%s\n", + bstatp->bs_xflags, + bstatp->bs_extsize, + path, + strerror(errno)); + } + } +#endif + +#ifdef F_FSSETDM + if ( persp->a.restoredmpr) { + fsdmidata_t fssetdm; + + /* Set the DMAPI Fields. */ + + fssetdm.fsd_dmevmask = + bstatp->bs_dmevmask; + fssetdm.fsd_padding = 0; + fssetdm.fsd_dmstate = + bstatp->bs_dmstate; + rval = fcntl( fd, + F_FSSETDM, + ( void * ) + &fssetdm ); + if ( rval ) { + mlog(MLOG_NORMAL | MLOG_WARNING, + "attempt to set DMI " + "attributes of %s failed: " + "%s\n", + path, + strerror( errno )); + } + + /* Reopen the file to cause invisible I/O. */ + + (void)close(fd); + fd = reopen_invis(path, oflags); + if (fd < 0) { + mlog(MLOG_NORMAL | MLOG_WARNING, + "attempt to reopen_invis %s failed." + " The file will not be restored.\n", + path); + } + /* If fd < 0, we will not restore the file. */ + } +#endif /* F_FSSETDM */ + } + } + } + + /* copy data extents from media to the file + */ + for ( ; ; ) { + extenthdr_t ehdr; + off64_t bytesread; + + /* read the extent header + */ + rv = read_extenthdr( drivep, &ehdr, ehcs ); + if ( rv != RV_OK ) { + *rvp = rv; + return BOOL_FALSE; + } + mlog( MLOG_NITTY, + "read extent hdr type %s offset %lld sz %lld flags %x\n", + ehdr_typestr( ehdr.eh_type ), + ehdr.eh_offset, + ehdr.eh_sz, + ehdr.eh_flags ); + + + /* if we see the specially marked last extent hdr, + * we are done. + */ + if ( ehdr.eh_type == EXTENTHDR_TYPE_LAST ) { + break; + } + + /* if its an ALIGNment extent, discard the extent. + */ + if ( ehdr.eh_type == EXTENTHDR_TYPE_ALIGN ) { + size_t sz; + ASSERT( ehdr.eh_sz <= INTGENMAX ); + sz = ( size_t )ehdr.eh_sz; + rv = discard_padding( sz, drivep ); + if ( rv != RV_OK ) { + *rvp = rv; + return BOOL_FALSE; + } + continue; + } + +#ifdef EXTATTR + /* Add up extents restored to later check if the file + * is done. + */ + restoredsz += ehdr.eh_sz; /* Increments of block size (usually 512) */ +#endif /* EXTATTR */ + + /* Holes do not need to be restored since we now + * unlink the file at the start of the restore. + */ + if ( ehdr.eh_type == EXTENTHDR_TYPE_HOLE ) { + continue; + } + + /* real data + */ + ASSERT( ehdr.eh_type == EXTENTHDR_TYPE_DATA ); + bytesread = 0; + rv = restore_extent( fhdrp, + &ehdr, + fd, + path, + drivep, + &bytesread ); + if ( rv != RV_OK ) { + *rvp = rv; + return BOOL_FALSE; + } + + if ( cldmgr_stop_requested( )) { + *rvp = RV_INTR; + return BOOL_FALSE; + } + } + +#ifdef EXTATTR + /* The extent group has been restored. If the file is not + * complete, we may need to co-ordinate with other restore + * streams to time the restoration of extended attributes. + * Register the portion of the file completed here in the + * persistent state. + */ + if (bstatp->bs_size > restoredsz) { + partial_reg(drivep->d_index, bstatp->bs_ino, bstatp->bs_size, + offset, restoredsz); + } +#endif /* EXTATTR */ + + if ( fd != -1 ) { + struct utimbuf utimbuf; + + + /* restore the attributes + */ + + /* set the access and modification times + */ + utimbuf.actime = + ( time_t )bstatp->bs_atime.tv_sec; + utimbuf.modtime = + ( time_t )bstatp->bs_mtime.tv_sec; + rval = utime( path, &utimbuf ); + if ( rval ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "unable to set access and modification" + " times of %s: %s\n", + path, + strerror( errno )); + } + + /* set the owner and group (if enabled) + */ + if ( persp->a.ownerpr ) { + rval = fchown( fd, + ( uid_t )bstatp->bs_uid, + ( gid_t )bstatp->bs_gid ); + if ( rval ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "unable to set owner and group " + "of %s: %s\n", + path, + strerror( errno )); + } + } + + /* set the permissions/mode + */ + rval = fchmod( fd, ( mode_t )bstatp->bs_mode ); + if ( rval ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "unable to set mode " + "of %s: %s\n", + path, + strerror( errno )); + } + + rval = close( fd ); + if ( rval ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "unable to close " + "%s: %s\n", + path, + strerror( errno )); + } + } + + return BOOL_TRUE; +} + +/* ARGSUSED */ +static bool_t +restore_spec( filehdr_t *fhdrp, rv_t *rvp, char *path ) +{ + bstat_t *bstatp = &fhdrp->fh_stat; + struct utimbuf utimbuf; + char *printstr; + intgen_t rval; + + if ( ! path ) { + return BOOL_TRUE; + } + + switch ( bstatp->bs_mode & S_IFMT ) { + case S_IFBLK: + printstr = "block special file"; + break; + case S_IFCHR: + printstr = "char special file"; + break; + case S_IFIFO: + printstr = "named pipe"; + break; +#ifdef S_IFNAM + case S_IFNAM: + printstr = "XENIX named pipe"; + break; +#endif +#ifdef DOSOCKS + case S_IFSOCK: + printstr = "UNIX domain socket"; + break; +#endif /* DOSOCKS */ + default: + mlog( MLOG_NORMAL | MLOG_WARNING, + "%s: unknown file type: mode 0x%x ino %llu\n", + path, + bstatp->bs_mode, + fhdrp->fh_stat.bs_ino ); + return BOOL_TRUE; + } + + if ( ! tranp->t_toconlypr ) { + mlog( MLOG_TRACE, + "restoring %s ino %llu %s\n", + printstr, + fhdrp->fh_stat.bs_ino, + path ); + } else { + mlog( MLOG_NORMAL | MLOG_BARE, + "%s\n", + path ); + } + + if ( ! tranp->t_toconlypr ) { +#ifdef DOSOCKS + if ( ( bstatp->bs_mode & S_IFMT ) == S_IFSOCK ) { + int sockfd; + struct sockaddr_un addr; + size_t addrlen; + + sockfd = socket( AF_UNIX, SOCK_STREAM, 0 ); + if ( sockfd < 0 ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "unable to create " + "%s ino %llu %s: %s: discarding\n", + printstr, + fhdrp->fh_stat.bs_ino, + path, + strerror( errno )); + return BOOL_TRUE; + } + memset( ( void * )&addr, 0, sizeof( addr )); + addr.sun_family = AF_UNIX; + if ( strlen( path ) >= sizeof( addr.sun_path )) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "pathname too long for bind of " + "%s ino %llu %s: %s: discarding\n", + printstr, + fhdrp->fh_stat.bs_ino, + path ); + ( void )close( sockfd ); + return BOOL_TRUE; + } + strcpy( addr.sun_path, path ); + addrlen = strlen( addr.sun_path ) + + + sizeof( addr.sun_family ); + rval = bind( sockfd, + ( struct sockaddr * )&addr, + ( int )addrlen ); + if ( rval < 0 ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "unable to bind " + "%s ino %llu %s: %s: discarding\n", + printstr, + fhdrp->fh_stat.bs_ino, + path, + strerror( errno )); + ( void )close( sockfd ); + return BOOL_TRUE; + } + ( void )close( sockfd ); + goto sockbypass; + } +#endif /* DOSOCKS */ + + /* create the node + */ + rval = mknod( path, + ( mode_t )bstatp->bs_mode, + ( dev_t )bstatp->bs_rdev ); + if ( rval && rval != EEXIST ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "unable to create %s " + "ino %llu %s: %s: discarding\n", + printstr, + fhdrp->fh_stat.bs_ino, + path, + strerror( errno )); + return BOOL_TRUE; + } + +#ifdef DOSOCKS +sockbypass: +#endif /* DOSOCKS */ + /* set the owner and group (if enabled) + */ + if ( persp->a.ownerpr ) { + rval = chown( path, + ( uid_t )bstatp->bs_uid, + ( gid_t )bstatp->bs_gid ); + if ( rval ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "unable to set owner and group of %s %s: " + "%s\n", + printstr, + path, + strerror( errno )); + } + } + + /* set the permissions/mode + */ + rval = chmod( path, ( mode_t )fhdrp->fh_stat.bs_mode ); + if ( rval ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "unable to set mode " + "of %s: %s\n", + path, + strerror( errno )); + } + + /* set the access and modification times + */ + utimbuf.actime = ( time_t )bstatp->bs_atime.tv_sec; + utimbuf.modtime = ( time_t )bstatp->bs_mtime.tv_sec; + rval = utime( path, &utimbuf ); + if ( rval ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "unable to set access and modification " + "times of %s: %s\n", + path, + strerror( errno )); + } + } + + return BOOL_TRUE; +} + +static bool_t +restore_symlink( drive_t *drivep, + filehdr_t *fhdrp, + rv_t *rvp, + char *path, + char *scratchpath, + bool_t ehcs ) +{ + bstat_t *bstatp = &fhdrp->fh_stat; + drive_ops_t *dop = drivep->d_opsp; + extenthdr_t ehdr; + char *scratch; + intgen_t nread; + intgen_t rval; + rv_t rv; + mode_t oldumask; + + if ( path ) { + if ( ! tranp->t_toconlypr ) { + mlog( MLOG_TRACE, + "restoring symbolic link ino %llu %s\n", + bstatp->bs_ino, + path ); + } else { + mlog( MLOG_NORMAL | MLOG_BARE, + "%s\n", + path ); + } + } + + /* read the extent header + */ + rv = read_extenthdr( drivep, &ehdr, ehcs ); + if ( rv != RV_OK ) { + *rvp = rv; + return BOOL_FALSE; + } + + /* symlinks always have one extent + */ + ASSERT( ehdr.eh_type == EXTENTHDR_TYPE_DATA ); + + /* read the link path extent + */ + if ( ehdr.eh_sz < ( off64_t )( 2 * MAXPATHLEN )) { + scratch = scratchpath; + } else { + scratch = 0; + } + nread = read_buf( scratch, + ( size_t )ehdr.eh_sz, + ( void * )drivep, + ( rfp_t )dop->do_read, + ( rrbfp_t )dop->do_return_read_buf, + &rval ); + if ( rval ) { + switch( rval ) { + case DRIVE_ERROR_EOF: + case DRIVE_ERROR_EOD: + case DRIVE_ERROR_EOM: + case DRIVE_ERROR_MEDIA: + *rvp = RV_EOD; + break; + case DRIVE_ERROR_CORRUPTION: + *rvp = RV_CORRUPT; + break; + case DRIVE_ERROR_DEVICE: + *rvp = RV_DRIVE; + break; + case DRIVE_ERROR_CORE: + default: + *rvp = RV_CORE; + } + return BOOL_FALSE; + } + ASSERT( ( off64_t )nread == ehdr.eh_sz ); + if ( ! scratch ) { + if ( path ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "unable to create " + "symlink ino %llu %s: src too long: discarding\n", + bstatp->bs_ino, + path ); + } + return BOOL_TRUE; + } + scratchpath[ nread ] = 0; + if ( ! tranp->t_toconlypr && path ) { + /* create the symbolic link + */ + /* NOTE: There is no direct way to set mode for + * sym links. Do it using umask. + * No way of setting times for sym links. + */ + + oldumask = umask( (( mode_t )(~bstatp->bs_mode)) & 0777 ); + + rval = symlink( scratchpath, path ); + + umask( oldumask ); + + if ( rval ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "unable to create " + "symlink ino %llu %s: %s: discarding\n", + bstatp->bs_ino, + path, + strerror( errno )); + return BOOL_TRUE; + } + + /* set the owner and group (if enabled) + */ + if ( persp->a.ownerpr ) { + rval = lchown( path, + ( uid_t )bstatp->bs_uid, + ( gid_t )bstatp->bs_gid ); + if ( rval ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "unable to set owner and group " + "of %s: %s\n", + path, + strerror( errno )); + } + } +#ifdef F_FSSETDM + if ( persp->a.restoredmpr) { + fsdmidata_t fssetdm; + + /* Restore DMAPI fields. */ + + fssetdm.fsd_dmevmask = bstatp->bs_dmevmask; + fssetdm.fsd_padding = 0; + fssetdm.fsd_dmstate = bstatp->bs_dmstate; + rval = do_fssetdm_by_handle(path, &fssetdm); + } +#endif /* F_FSSETDM */ + } + + return BOOL_TRUE; +} + +/* ARGSUSED */ +static rv_t +read_filehdr( drive_t *drivep, filehdr_t *fhdrp, bool_t fhcs ) +{ + bstat_t *bstatp = &fhdrp->fh_stat; + drive_ops_t *dop = drivep->d_opsp; + /* REFERENCED */ + intgen_t nread; +#ifdef FILEHDR_CHECKSUM + register u_int32_t *sump = ( u_int32_t * )fhdrp; + register u_int32_t *endp = ( u_int32_t * )( fhdrp + 1 ); + register u_int32_t sum; +#endif /* FILEHDR_CHECKSUM */ + intgen_t rval; + filehdr_t tmpfh; + + nread = read_buf( ( char * )&tmpfh, + sizeof( *fhdrp ), + ( void * )drivep, + ( rfp_t )dop->do_read, + ( rrbfp_t )dop->do_return_read_buf, + &rval ); + xlate_filehdr(&tmpfh, fhdrp, 1); + + switch( rval ) { + case 0: + break; + case DRIVE_ERROR_EOD: + case DRIVE_ERROR_EOF: + case DRIVE_ERROR_EOM: + case DRIVE_ERROR_MEDIA: + return RV_EOD; + case DRIVE_ERROR_CORRUPTION: + return RV_CORRUPT; + case DRIVE_ERROR_DEVICE: + return RV_DRIVE; + case DRIVE_ERROR_CORE: + default: + return RV_CORE; + } + ASSERT( ( size_t )nread == sizeof( *fhdrp )); + + mlog( MLOG_NITTY, + "read file hdr off %lld flags 0x%x ino %llu mode 0x%08x\n", + fhdrp->fh_offset, + fhdrp->fh_flags, + bstatp->bs_ino, + bstatp->bs_mode ); + +#ifdef FILEHDR_CHECKSUM + if ( fhcs ) { + if ( ! ( fhdrp->fh_flags & FILEHDR_FLAGS_CHECKSUM )) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "corrupt file header\n" ); + return RV_CORRUPT; + } + for ( sum = 0 ; sump < endp ; sum += *sump++ ) ; + if ( sum ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "bad file header checksum\n" ); + return RV_CORRUPT; + } + } +#endif /* FILEHDR_CHECKSUM */ + + return RV_OK; +} + +/* ARGSUSED */ +static rv_t +read_extenthdr( drive_t *drivep, extenthdr_t *ehdrp, bool_t ehcs ) +{ + drive_ops_t *dop = drivep->d_opsp; + /* REFERENCED */ + intgen_t nread; +#ifdef EXTENTHDR_CHECKSUM + register u_int32_t *sump = ( u_int32_t * )ehdrp; + register u_int32_t *endp = ( u_int32_t * )( ehdrp + 1 ); + register u_int32_t sum; +#endif /* EXTENTHDR_CHECKSUM */ + intgen_t rval; + extenthdr_t tmpeh; + + nread = read_buf( ( char * )&tmpeh, + sizeof( *ehdrp ), + ( void * )drivep, + ( rfp_t )dop->do_read, + ( rrbfp_t )dop->do_return_read_buf, + &rval ); + xlate_extenthdr(&tmpeh, ehdrp, 1); + + switch( rval ) { + case 0: + break; + case DRIVE_ERROR_EOD: + case DRIVE_ERROR_EOF: + case DRIVE_ERROR_EOM: + case DRIVE_ERROR_MEDIA: + return RV_EOD; + case DRIVE_ERROR_CORRUPTION: + return RV_CORRUPT; + case DRIVE_ERROR_DEVICE: + return RV_DRIVE; + case DRIVE_ERROR_CORE: + default: + return RV_CORE; + } + ASSERT( ( size_t )nread == sizeof( *ehdrp )); + + mlog( MLOG_NITTY, + "read extent hdr size %lld offset %lld type %d flags %08x\n", + ehdrp->eh_sz, + ehdrp->eh_offset, + ehdrp->eh_type, + ehdrp->eh_flags ); + +#ifdef EXTENTHDR_CHECKSUM + if ( ehcs ) { + if ( ! ( ehdrp->eh_flags & EXTENTHDR_FLAGS_CHECKSUM )) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "corrupt extent header\n" ); + return RV_CORRUPT; + } + for ( sum = 0 ; sump < endp ; sum += *sump++ ) ; + if ( sum ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "bad extent header checksum\n" ); + return RV_CORRUPT; + } + } +#endif /* EXTENTHDR_CHECKSUM */ + + return RV_OK; +} + +/* ARGSUSED */ +static rv_t +read_dirent( drive_t *drivep, + direnthdr_t *dhdrp, + size_t direntbufsz, + bool_t dhcs ) +{ + drive_ops_t *dop = drivep->d_opsp; + /* REFERENCED */ + intgen_t nread; +#ifdef DIRENTHDR_CHECKSUM + register u_int32_t *sump = ( u_int32_t * )dhdrp; + register u_int32_t *endp = ( u_int32_t * )( dhdrp + 1 ); + register u_int32_t sum; +#endif /* DIRENTHDR_CHECKSUM */ + intgen_t rval; + direnthdr_t tmpdh; + + /* read the head of the dirent + */ + nread = read_buf( ( char * )&tmpdh, + sizeof( direnthdr_t ), + ( void * )drivep, + ( rfp_t )dop->do_read, + ( rrbfp_t ) + dop->do_return_read_buf, + &rval ); + xlate_direnthdr(&tmpdh, dhdrp, 1); + + switch( rval ) { + case 0: + break; + case DRIVE_ERROR_EOD: + case DRIVE_ERROR_EOF: + case DRIVE_ERROR_EOM: + case DRIVE_ERROR_MEDIA: + return RV_EOD; + case DRIVE_ERROR_CORRUPTION: + return RV_CORRUPT; + case DRIVE_ERROR_DEVICE: + return RV_DRIVE; + case DRIVE_ERROR_CORE: + default: + return RV_CORE; + } + ASSERT( ( size_t )nread == sizeof( direnthdr_t )); + + mlog( MLOG_NITTY, + "read dirent hdr ino %llu gen %u size %u\n", + dhdrp->dh_ino, + ( size_t )dhdrp->dh_gen, + ( size_t )dhdrp->dh_sz ); + +#ifdef DIRENTHDR_CHECKSUM + if ( dhcs ) { + if ( dhdrp->dh_sz == 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "corrupt directory entry header\n" ); + return RV_CORRUPT; + } + for ( sum = 0 ; sump < endp ; sum += *sump++ ) ; + if ( sum ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "bad directory entry header checksum\n" ); + return RV_CORRUPT; + } + } +#endif /* DIRENTHDR_CHECKSUM */ + + /* if null, return + */ + if ( dhdrp->dh_ino == 0 ) { + ASSERT( ( size_t )dhdrp->dh_sz == sizeof( direnthdr_t )); + return RV_OK; + } + + /* read the remainder of the dirent. + */ + ASSERT( ( size_t )dhdrp->dh_sz <= direntbufsz ); + ASSERT( ( size_t )dhdrp->dh_sz >= sizeof( direnthdr_t )); + ASSERT( ! ( ( size_t )dhdrp->dh_sz & ( DIRENTHDR_ALIGN - 1 ))); + mlog( MLOG_NITTY, + "read_dirent: dhdrp->dh_sz %u, direnthdr_t %u\n", + dhdrp->dh_sz, + sizeof( direnthdr_t )); + if ( ( size_t )dhdrp->dh_sz > sizeof( direnthdr_t )) { + size_t remsz = ( size_t )dhdrp->dh_sz - sizeof( direnthdr_t ); + mlog( MLOG_NITTY, + "read_dirent: remsz %u\n", + remsz ); + nread = read_buf( ( char * )( dhdrp + 1 ), + remsz, + ( void * )drivep, + ( rfp_t )dop->do_read, + ( rrbfp_t ) + dop->do_return_read_buf, + &rval ); + switch( rval ) { + case 0: + break; + case DRIVE_ERROR_EOD: + case DRIVE_ERROR_EOF: + case DRIVE_ERROR_EOM: + case DRIVE_ERROR_MEDIA: + return RV_EOD; + case DRIVE_ERROR_CORRUPTION: + return RV_CORRUPT; + case DRIVE_ERROR_DEVICE: + return RV_DRIVE; + case DRIVE_ERROR_CORE: + default: + return RV_CORE; + } + ASSERT( ( size_t ) nread == remsz ); + } + + return RV_OK; +} + +#ifdef EXTATTR +/* ARGSUSED */ +static rv_t +read_extattrhdr( drive_t *drivep, extattrhdr_t *ahdrp, bool_t ahcs ) +{ + drive_ops_t *dop = drivep->d_opsp; + /* REFERENCED */ + intgen_t nread; +#ifdef EXTATTRHDR_CHECKSUM + register u_int32_t *sump = ( u_int32_t * )ahdrp; + register u_int32_t *endp = ( u_int32_t * )( ahdrp + 1 ); + register u_int32_t sum; +#endif /* EXTATTRHDR_CHECKSUM */ + intgen_t rval; + extattrhdr_t tmpah; + + nread = read_buf( ( char * )&tmpah, + sizeof( *ahdrp ), + ( void * )drivep, + ( rfp_t )dop->do_read, + ( rrbfp_t )dop->do_return_read_buf, + &rval ); + xlate_extattrhdr(&tmpah, ahdrp, 1); + + switch( rval ) { + case 0: + break; + case DRIVE_ERROR_EOD: + case DRIVE_ERROR_EOF: + case DRIVE_ERROR_EOM: + case DRIVE_ERROR_MEDIA: + return RV_EOD; + case DRIVE_ERROR_CORRUPTION: + return RV_CORRUPT; + case DRIVE_ERROR_DEVICE: + return RV_DRIVE; + case DRIVE_ERROR_CORE: + default: + return RV_CORE; + } + ASSERT( ( size_t )nread == sizeof( *ahdrp )); + + mlog( MLOG_NITTY, + "read extattr hdr sz %u valoff %u flags 0x%x valsz %u cs 0x%x\n", + ahdrp->ah_sz, + ( u_intgen_t )ahdrp->ah_valoff, + ( u_intgen_t )ahdrp->ah_flags, + ahdrp->ah_valsz, + ahdrp->ah_checksum ); + +#ifdef EXTATTRHDR_CHECKSUM + if ( ahcs ) { + if ( ! ( ahdrp->ah_flags & EXTATTRHDR_FLAGS_CHECKSUM )) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "corrupt extattr header\n" ); + return RV_CORRUPT; + } + for ( sum = 0 ; sump < endp ; sum += *sump++ ) ; + if ( sum ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "bad extattr header checksum\n" ); + return RV_CORRUPT; + } + } +#endif /* EXTATTRHDR_CHECKSUM */ + + return RV_OK; +} +#endif /* EXTATTR */ + +static rv_t +discard_padding( size_t sz, drive_t *drivep ) +{ + drive_ops_t *dop = drivep->d_opsp; + /* REFERENCED */ + intgen_t nread; + intgen_t rval; + + nread = read_buf( 0, + sz, + ( void * )drivep, + ( rfp_t )dop->do_read, + ( rrbfp_t )dop->do_return_read_buf, + &rval ); + switch( rval ) { + case 0: + ASSERT( ( size_t )nread == sz ); + return RV_OK; + case DRIVE_ERROR_EOF: + case DRIVE_ERROR_EOD: + case DRIVE_ERROR_EOM: + case DRIVE_ERROR_MEDIA: + return RV_EOD; + case DRIVE_ERROR_CORRUPTION: + return RV_CORRUPT; + case DRIVE_ERROR_DEVICE: + return RV_DRIVE; + case DRIVE_ERROR_CORE: + default: + return RV_CORE; + } +} + +static rv_t +restore_extent( filehdr_t *fhdrp, + extenthdr_t *ehdrp, + int fd, + char *path, + drive_t *drivep, + off64_t *bytesreadp ) +{ + bstat_t *bstatp = &fhdrp->fh_stat; + drive_ops_t *dop = drivep->d_opsp; + off64_t off = ehdrp->eh_offset; + off64_t sz = ehdrp->eh_sz; + off64_t new_off; + struct dioattr da; + bool_t isrealtime = BOOL_FALSE; + + *bytesreadp = 0; + + if ( fd != -1 ) { + ASSERT( path ); + /* seek to the beginning of the extent. + * must be on a basic fs blksz boundary. + */ + ASSERT( ( off & ( off64_t )( BBSIZE - 1 )) == 0 ); + new_off = lseek64( fd, off, SEEK_SET ); + if ( new_off < 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "attempt to seek %s to %lld failed: %s: " + "not restoring extent off %lld sz %lld\n", + path, + off, + strerror( errno ), + off, + sz ); + fd = -1; + new_off = off; + } + ASSERT( new_off == off ); + } + if ( (fd != -1) && (bstatp->bs_xflags & XFS_XFLAG_REALTIME) ) { + if ( (ioctl(fd, XFS_IOC_DIOINFO, &da) < 0) ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "dioinfo %s failed: " + "%s: discarding ino %llu\n", + path, + strerror( errno ), + fhdrp->fh_stat.bs_ino ); + fd = -1; + } else + isrealtime = BOOL_TRUE; + } + + /* move from media to fs. + */ + while ( sz ) { + char *bufp; + size_t req_bufsz; /* requested bufsz */ + size_t sup_bufsz; /* supplied bufsz */ + intgen_t nwritten; + intgen_t rval; + size_t ntowrite; + + req_bufsz = ( size_t )min( ( off64_t )INTGENMAX, sz ); + bufp = ( * dop->do_read )(drivep, req_bufsz, &sup_bufsz, &rval); + if ( rval ) { + rv_t rv; + char *reasonstr; + switch( rval ) { + case DRIVE_ERROR_EOF: + rv = RV_EOD; + reasonstr = "end of media file"; + break; + case DRIVE_ERROR_EOD: + rv = RV_EOD; + reasonstr = "end of recorded data"; + break; + case DRIVE_ERROR_EOM: + rv = RV_EOD; + reasonstr = "end of media"; + break; + case DRIVE_ERROR_MEDIA: + rv = RV_EOD; + reasonstr = "media error or no media"; + break; + case DRIVE_ERROR_CORRUPTION: + rv = RV_CORRUPT; + reasonstr = "end of media file"; + break; + case DRIVE_ERROR_DEVICE: + rv = RV_DRIVE; + reasonstr = "end of media file"; + break; + case DRIVE_ERROR_CORE: + default: + rv = RV_CORE; + reasonstr = "dumping core"; + break; + } + mlog( MLOG_NORMAL, + "attempt to read %u bytes failed: %s\n", + req_bufsz, + reasonstr ); + return rv; + } + if ( off >= bstatp->bs_size ) { + ASSERT( off == bstatp->bs_size ); + ntowrite = 0; + } else if ((off64_t)sup_bufsz > bstatp->bs_size - off ) { + ntowrite = ( size_t )( bstatp->bs_size - off ); + } else { + ntowrite = sup_bufsz; + } + ASSERT( ntowrite <= ( size_t )INTGENMAX ); + if ( ntowrite > 0 ) { + *bytesreadp += ( off64_t )ntowrite; + if ( fd != -1 ) { + size_t tries; + size_t remaining; + intgen_t rval; + off64_t tmp_off; + + rval = 0; /* for lint */ + for ( nwritten = 0, + tries = 0, + remaining = ntowrite, + tmp_off = off + ; + nwritten < ( intgen_t )ntowrite + && + tries < WRITE_TRIES_MAX + ; + nwritten += rval, + tries++, + remaining -= ( size_t )rval, + tmp_off += ( off64_t )rval ) { + int rttrunc = 0; + ASSERT( remaining + <= + ( size_t )INTGENMAX ); + /* + * Realtime files must be written + * to the end of the block even if + * it has been truncated back. + */ + if ( isrealtime && + (remaining % da.d_miniosz != 0 || + remaining < da.d_miniosz) ) { + /* + * Since the ring and static + * buffers from the different + * drives are always large, we + * just need to write to the + * end of the next block + * boundry and truncate. + */ + rttrunc = remaining; + remaining += da.d_miniosz - + (remaining % da.d_miniosz); + } + rval = write( fd, bufp, remaining ); + if ( rval < 0 ) { + nwritten = rval; + break; + } + ASSERT( ( size_t )rval <= remaining ); + if ( ( size_t )rval < remaining ) { + mlog( MLOG_NORMAL, + "WARNING: attempt to " + "write %u bytes to %s at " + "offset %lld failed: " + "only %d bytes written\n", + remaining, + path, + tmp_off, + rval ); + } + if (rttrunc) { + /* truncate and re-set rval */ + if (rval == remaining) + rval = rttrunc; + ftruncate(fd, bstatp->bs_size); + } + } + } else { + nwritten = ( intgen_t )ntowrite; + } + } else { + nwritten = 0; + } + ( * dop->do_return_read_buf )( drivep, bufp, sup_bufsz ); + if ( ( size_t )nwritten != ntowrite ) { + if ( nwritten < 0 ) { + mlog( MLOG_NORMAL, + "attempt to write %u bytes to %s " + "at offset %lld failed: %s\n", + ntowrite, + path, + off, + strerror( errno )); + } else { + ASSERT( ( size_t )nwritten < ntowrite ); + mlog( MLOG_NORMAL, + "attempt to write %u bytes to %s at " + "offset %lld failed: only %d bytes " + "written\n", + ntowrite, + path, + off, + nwritten ); + } + /* stop attempting to write, but complete reads + */ + fd = -1; + ASSERT( ntowrite <= ( size_t )INTGENMAX ); + nwritten = ( intgen_t )ntowrite; + } + sz -= ( off64_t )sup_bufsz; + off += ( off64_t )nwritten; + } + + return RV_OK; +} + +#ifdef EXTATTR +static char *extattrbufp = 0; +static size_t extattrbufsz = 0; + +static bool_t +extattr_init( void ) +{ + ASSERT( ! extattrbufp ); + extattrbufsz = EXTATTRHDR_SZ /* dump hdr */ + + + NAME_MAX /* attribute name */ + + + 1 /* NULL term. of name */ + + + ATTR_MAX_VALUELEN; /* attribute value */ + extattrbufsz = roundup(extattrbufsz, EXTATTRHDR_ALIGN); + + extattrbufp = memalign( EXTATTRHDR_ALIGN, extattrbufsz ); + ASSERT( extattrbufp ); + + return BOOL_TRUE; +} + +struct extattr_cb_ctx { + extattrhdr_t *ecb_ahdrp; +}; + +typedef struct extattr_cb_ctx extattr_cb_ctx_t; + +static rv_t +restore_extattr( drive_t *drivep, + filehdr_t *fhdrp, + char *path1, + char *path2, + bool_t ahcs, + bool_t isdirpr, + dah_t dah ) +{ + drive_ops_t *dop = drivep->d_opsp; + extattrhdr_t *ahdrp = ( extattrhdr_t * )extattrbufp; + bstat_t *bstatp = &fhdrp->fh_stat; + bool_t isfilerestored = BOOL_FALSE; + + ASSERT( extattrbufp ); + + if ( ! isdirpr ) + isfilerestored = partial_check(bstatp->bs_ino, bstatp->bs_size); + + /* peel off extattrs until null hdr hit + */ + for ( ; ; ) { + size_t recsz; + /* REFERENCED */ + intgen_t nread; + intgen_t rval; + rv_t rv; + + rv = read_extattrhdr( drivep, ahdrp, ahcs ); + if ( rv != RV_OK ) { + return rv; + } + + if ( ahdrp->ah_flags & EXTATTRHDR_FLAGS_NULL ) { + return RV_OK; + } + + recsz = ( size_t )ahdrp->ah_sz; + ASSERT( recsz <= extattrbufsz ); + ASSERT( recsz >= EXTATTRHDR_SZ ); + nread = read_buf( ( char * )&ahdrp[ 1 ], + recsz - EXTATTRHDR_SZ, + ( void * )drivep, + ( rfp_t )dop->do_read, + ( rrbfp_t )dop->do_return_read_buf, + &rval ); + switch( rval ) { + case 0: + break; + case DRIVE_ERROR_EOD: + case DRIVE_ERROR_EOF: + case DRIVE_ERROR_EOM: + case DRIVE_ERROR_MEDIA: + return RV_EOD; + case DRIVE_ERROR_CORRUPTION: + return RV_CORRUPT; + case DRIVE_ERROR_DEVICE: + return RV_DRIVE; + case DRIVE_ERROR_CORE: + default: + return RV_CORE; + } + ASSERT( nread == ( intgen_t )( recsz - EXTATTRHDR_SZ )); + + if ( ! persp->a.restoreextattrpr && ! persp->a.restoredmpr ) { + continue; + } + + if ( isdirpr ) { + ASSERT( ! path1 ); + ASSERT( ! path2 ); + if ( dah != DAH_NULL ) { + dirattr_addextattr( dah, ahdrp ); + } + } else if ( isfilerestored ) { + extattr_cb_ctx_t context; + ASSERT( path1 ); + ASSERT( path2 ); + context.ecb_ahdrp = ahdrp; + tree_cb_links( bstatp->bs_ino, + bstatp->bs_gen, + bstatp->bs_ctime.tv_sec, + bstatp->bs_mtime.tv_sec, + restore_extattr_cb, + &context, + path1, + path2 ); + } + } + /* NOTREACHED */ +} + +/* ARGSUSED */ +static bool_t +restore_extattr_cb( void *ctxp, bool_t islinkpr, char *path1, char *path2 ) +{ + extattr_cb_ctx_t *contextp = ( extattr_cb_ctx_t * )ctxp; + + if ( islinkpr ) { + return BOOL_TRUE; + } + + if ( ! path1 ) { + return BOOL_TRUE; + } + + setextattr( path1, contextp->ecb_ahdrp ); + + return BOOL_TRUE; +} + +static bool_t +restore_dir_extattr_cb( char *path, dah_t dah ) +{ + extattrhdr_t *ahdrp = ( extattrhdr_t * )extattrbufp; + bool_t ok; + + /* ask the dirattr abstraction to call me back for each + * extended dirattr associated with this dah. + */ + ok = dirattr_cb_extattr( dah, + restore_dir_extattr_cb_cb, + ahdrp, + ( void * )path ); + return ok; +} + +static bool_t +restore_dir_extattr_cb_cb( extattrhdr_t *ahdrp, void *ctxp ) +{ + char *path = ( char * )ctxp; + + setextattr( path, ahdrp ); + + return BOOL_TRUE; +} + +static void +setextattr( char *path, extattrhdr_t *ahdrp ) +{ +#ifdef DMEXTATTR + static char dmiattr[] = DMATTR_PREFIXSTRING; +#endif /* DMEXTATTR */ + + bool_t isrootpr = ahdrp->ah_flags & EXTATTRHDR_FLAGS_ROOT; + bool_t isdm = BOOL_FALSE; + intgen_t rval; + + /* Check if just displaying a dump before setting attributes */ + if ( tranp->t_toconlypr ) { + return; + } + + /*DBGmlog( MLOG_NITTY, + "setting attribute path %s name %s valsz %u\n", + path, + ( char * )( &ahdrp[ 1 ] ), + ahdrp->ah_valsz );*/ + +#ifdef DMEXTATTR + isdm = isrootpr && + (strncmp((char *)(&ahdrp[1]), dmiattr, sizeof(dmiattr)-1) == 0); +#endif /* DMEXTATTR */ + + + /* If restoreextattrpr not set, then we are here because -D was */ + /* specified. So return unless it looks like a root DMAPI attribute. */ + + if ((!persp->a.restoreextattrpr) && !isdm) + return; + + rval = attr_set( path, + ( char * )( &ahdrp[ 1 ] ), + ( ( char * )ahdrp ) + ( u_long_t )ahdrp->ah_valoff, + ( intgen_t )ahdrp->ah_valsz, + isrootpr + ? + ATTR_ROOT | ATTR_DONTFOLLOW + : + ATTR_DONTFOLLOW ); + if ( rval ) { + mlog( MLOG_VERBOSE | MLOG_WARNING, + "unable to set %s extended attribute for %s: " + "%s (%d)\n", + isrootpr + ? + "root" + : + "non-root", + path, + strerror( errno ), + errno ); + } +} + +/* partial_reg - Registers files that are only partially restored by + * a dump stream into the persistent state. + * + * This is done because DMAPI extended attributes must not be set until + * the entire file has been restored in order to co-ordinate with the + * Data Migration Facility (DMF) daemons. Since extended attributes are + * recorded with each extent group in the dump, this registry is used to + * make sure only the final dump stream applies the extended attributes. + */ +static void +partial_reg( ix_t d_index, + xfs_ino_t ino, + off64_t fsize, + off64_t offset, + off64_t sz) +{ + off64_t endoffset; + partial_rest_t *isptr = NULL; + bytespan_t *bsptr = NULL; + int i; + + endoffset = offset + sz; + + if ( partialmax == 0 ) + return; + + pi_lock(); + + /* Search for a matching inode. Gaps can exist so we must search + * all entries. + */ + for (i=0; i < partialmax; i++ ) { + if (persp->a.parrest[i].is_ino == ino) { + isptr = &persp->a.parrest[i]; + break; + } + } + + /* If not found, find a free one, fill it in and return */ + if ( ! isptr ) { + /* find a free one */ + for (i=0; i < partialmax; i++ ) { + if (persp->a.parrest[i].is_ino == 0) { + int j; + + isptr = &persp->a.parrest[i]; + isptr->is_ino = ino; + persp->a.parrestcnt++; + + /* Clear all endoffsets (this value is + * used to decide if an entry is used or + * not + */ + for (j=0, bsptr=isptr->is_bs; + j < drivecnt; j++, bsptr++) { + bsptr->endoffset = 0; + } + + goto found; + } + } + + /* Should never get here. */ + pi_unlock(); + mlog( MLOG_NORMAL | MLOG_WARNING, + "partial_reg: Out of records. Extend attrs applied early.\n"); + return; + } + +found: + /* Update this drive's entry */ + bsptr = &isptr->is_bs[d_index]; + if (bsptr->endoffset == 0) { + /* no existing entry for this drive, fill in the values */ + bsptr->offset = offset; + bsptr->endoffset = endoffset; + } else { + bool_t ret; + + /* entry exists for this drive, just extend the endoffset, the + * records will be sequential for any given drive. + */ + bsptr->endoffset = endoffset; + ret = partial_check2(isptr, fsize); + mlog( MLOG_NITTY, "partial_reg: check returns: %d\n", ret); + } + + pi_unlock(); + +#ifdef DEBUGPARTIALS + /* DEBUG code to view partial files */ + pi_lock(); + printf("\npartial_reg: count=%d\n", persp->a.parrestcnt); + if (persp->a.parrestcnt > 0) { + for (i=0; i < partialmax; i++ ) { + if (persp->a.parrest[i].is_ino > 0) { + int j; + + isptr = &persp->a.parrest[i]; + printf( "\tino=%lld ", isptr->is_ino); + for (j=0, bsptr=isptr->is_bs; + j < drivecnt; + j++, bsptr++) + { + if (bsptr->endoffset > 0) { + printf("%d:%lld-%lld ", + j, bsptr->offset, + bsptr->endoffset); + } + } + printf( "\n"); + } + } + } + printf("\n"); + pi_unlock(); +#endif /* DEBUGPARTIALS */ +} + + +/* Checks the registry of files that are only partially restored by + * any given dump stream to see if the remainder of the file has + * been restored by another dump stream. + */ +static bool_t +partial_check (xfs_ino_t ino, off64_t fsize) +{ + partial_rest_t *isptr = NULL; +#ifdef DEBUGPARTIALS + bytespan_t *bsptr = NULL; +#endif /* DEBUGPARTIALS */ + bool_t ret; + int i; + + if ( partialmax == 0 ) + return BOOL_TRUE; + + pi_lock(); + + /* Check if no files are listed in the sync area */ + if (persp->a.parrestcnt == 0) { + pi_unlock(); + return BOOL_TRUE; + } + + /* Search for the inode. Gaps can exist so we must search + * all entries. + */ + for (i=0; i < partialmax; i++ ) { + if (persp->a.parrest[i].is_ino == ino) { + isptr = &persp->a.parrest[i]; + break; + } + } + + /* If not found, return okay */ + if ( ! isptr ) { + pi_unlock(); + return BOOL_TRUE; + } + + ret = partial_check2(isptr, fsize); + + pi_unlock(); + +#ifdef DEBUGPARTIALS + pi_lock(); + printf("\npartial_check: count=%d\n", persp->a.parrestcnt); + if (persp->a.parrestcnt > 0) { + for (i=0; i < partialmax; i++ ) { + if (persp->a.parrest[i].is_ino > 0) { + int j; + + isptr = &persp->a.parrest[i]; + printf( "\tino=%lld ", isptr->is_ino); + for (j=0, bsptr=isptr->is_bs; + j < drivecnt; + j++, bsptr++) + { + if (bsptr->endoffset > 0) { + printf("%d:%lld-%lld ", + j, bsptr->offset, + bsptr->endoffset); + } + } + printf( "\n"); + } + } + } + printf("\n"); + pi_unlock(); +#endif /* DEBUGPARTIALS */ + + return ret; +} + +/* + * Checks the given parrest entry to see if the file has + * been completely restored. + * Always invoked with the persistent inventory locked (pi_lock) + */ +static bool_t +partial_check2(partial_rest_t *isptr, off64_t fsize) +{ + bytespan_t *bsptr = NULL; + off64_t curoffset = 0; + int i; + +gapsearch: + /* Search the entire set of bytespan records to see if the next + * span has been restored. Bytespans are not necessarily in order + * so the search is repeated from the start each time. + */ + for (i=0, bsptr=isptr->is_bs; i < drivecnt; i++, bsptr++) { + if (bsptr->endoffset > 0 && + bsptr->offset <= curoffset && + bsptr->endoffset > curoffset) + { + curoffset = bsptr->endoffset; + goto gapsearch; + } + } + + /* Check if all bytes are accounted for. */ + if (curoffset >= fsize) { + isptr->is_ino = 0; /* clear the entry */ + persp->a.parrestcnt--; + return BOOL_TRUE; + } else { + return BOOL_FALSE; + } +} + +#endif /* EXTATTR */ + +static char * +ehdr_typestr( int32_t type ) +{ + switch ( type ) { + case EXTENTHDR_TYPE_LAST: + return "LAST"; + case EXTENTHDR_TYPE_ALIGN: + return "ALIGN"; + case EXTENTHDR_TYPE_DATA: + return "DATA"; + case EXTENTHDR_TYPE_HOLE: + return "HOLE"; + default: + return "?"; + } +} + +/* ARGSUSED */ +bool_t +content_overwrite_ok( char *path, + int32_t ctime, + int32_t mtime, + char **reasonstrp ) +{ + struct stat statbuf; + + /* if file doesn't exist, allow + */ + if ( lstat( path, &statbuf )) { + *reasonstrp = 0; + return BOOL_TRUE; + } + + /* if overwrites absolutely inhibited, disallow + */ + if ( persp->a.existpr ) { + *reasonstrp = "overwrites inhibited"; + return BOOL_FALSE; + } + + /* if newer time specified, compare + */ + if ( persp->a.newerpr ) { + if ( ( time_t )ctime < persp->a.newertime ) { + *reasonstrp = "too old"; + return BOOL_FALSE; + } + } + + /* don't overwrite changed files + */ + if ( persp->a.changepr ) { + if ( statbuf.st_ctime >= ( time_t )ctime ) { + *reasonstrp = "existing version is newer"; + return BOOL_FALSE; + } + } + + *reasonstrp = 0; + return BOOL_TRUE; +} + + +static void +set_mcflag( ix_t thrdix ) +{ + lock( ); + mcflag[ thrdix ] = BOOL_TRUE; + content_media_change_needed = BOOL_TRUE; + unlock( ); +} + +static void +clr_mcflag( ix_t thrdix ) +{ + lock( ); + mcflag[ thrdix ] = BOOL_FALSE; + for ( thrdix = 0 ; thrdix < drivecnt ; thrdix++ ) { + if ( mcflag[ thrdix ] ) { + unlock( ); + return; + } + } + content_media_change_needed = BOOL_FALSE; + unlock( ); +} + +/* debug functions ***********************************************************/ + +static void +pi_show( char *introstring ) +{ + char strbuf[ 100 ]; + /* REFERENCED */ + intgen_t strbuflen; + fold_t fold; + + if ( mlog_level_ss[ MLOG_SS_MEDIA ] < MLOG_NITTY + 1 ) { + return; + } + + mlog_lock( ); + + strbuflen = sprintf( strbuf, + "persistent inventory media file tree%s", + introstring ); + ASSERT( ( size_t )strbuflen < sizeof( strbuf )); + fold_init( fold, strbuf, ':' ); + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK, + "\n%s\n\n", + fold ); + + pi_show_nomloglock( ); + + fold_init( fold, "end persistent inventory display", '.' ); + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK, + "\n%s\n\n", + fold ); + + mlog_unlock( ); +} + +static void +pi_show_nomloglock( void ) +{ + dh_t strmh; + intgen_t strmix; + + + /* no point in proceeding if pi not begun + */ + if ( persp->s.strmheadh == DH_NULL ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + "session inventory unknown\n" ); + return; + } + + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + "session inventory display\n" ); + + /* iterate over all streams + */ + for ( strmh = persp->s.strmheadh, strmix = 0 + ; + strmh != DH_NULL + ; + strmh = DH2S( strmh )->s_nexth, strmix++ ) { + dh_t objh; + intgen_t objix; + + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + "\nmedia stream %u:\n", + strmix ); + if ( DH2S( strmh )->s_cldh == DH_NULL ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + "\n media objects not yet identified\n" ); + continue; + } + /* iterate over all objects + */ + for ( objh = DH2S( strmh )->s_cldh, objix = 0 + ; + objh != DH_NULL + ; + objh = DH2O( objh )->o_nexth, objix++ ) { + dh_t fileh; + ix_t fileix; + + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + "\n media object %u:\n\n", + objix ); + if ( DH2O( objh )->o_idlabvalpr ) { + if ( strlen( DH2O( objh )->o_lab )) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " label: \"%s\"\n", + DH2O( objh )->o_lab ); + } else { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " label is blank\n" ); + } + if ( ! uuid_is_null( DH2O( objh )->o_id)) { + char media_string_uuid[UUID_STR_LEN + 1]; + uuid_unparse( DH2O( objh )->o_id, + media_string_uuid); + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " id: %s\n", + media_string_uuid ); + } + } else { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " label not identified\n" ); + } + if ( DH2O( objh )->o_fmfmixvalpr ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " index within object " + "of first media file: %u\n", + DH2O( objh )->o_fmfmix ); + } + if ( DH2O( objh )->o_fmfsixvalpr ) { + mlog( MLOG_DEBUG | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " index within stream " + "of first media file: %u\n", + DH2O( objh )->o_fmfsix ); + } + + if ( DH2O( objh )->o_indrivepr ) { + if ( drivecnt > 1 ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " now in drive %u\n", + DH2O( objh )->o_indriveix ); + } else { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " now in drive\n" ); + } + } + + if ( DH2O( objh )->o_cldh == DH_NULL ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " media files not yet " + "identified\n" ); + continue; + } + + /* iterate over all files + */ + for ( fileh = DH2O( objh )->o_cldh, fileix = 0 + ; + fileh != DH_NULL + ; + fileh = DH2F( fileh )->f_nexth, fileix++ ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + "\n media file %u", + fileix ); + if ( DH2O( objh )->o_fmfmixvalpr ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " (%u):\n", + DH2O( objh )->o_fmfmix + fileix ); + } else { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + ":\n" ); + } + if ( DH2F( fileh )->f_szvalpr ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " size: " + "%lld bytes\n", + DH2F( fileh )->f_sz ); + } + if ( DH2F( fileh )->f_dirtriedpr ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " used for directory " + "restoral\n" ); + } + if ( DH2F( fileh )->f_valpr ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " first extent contained: " + "ino %llu off %lld\n", + DH2F( fileh )->f_firstegrp.eg_ino, + DH2F( fileh )->f_firstegrp.eg_off ); + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " next extent to restore: " + "ino %llu off %lld\n", + DH2F( fileh )->f_curegrp.eg_ino, + DH2F( fileh )->f_curegrp.eg_off ); + mlog( MLOG_DEBUG | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " rollback mark %lld\n", + DH2F( fileh )->f_curmark ); + } + if ( DH2F( fileh )->f_nondirskippr ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " contains no selected " + "non-directories\n" ); + } + if ( DH2F( fileh )->f_nondirdonepr ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " non-directories done\n" ); + } + if ( DH2F( fileh )->f_flags & PF_INV ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " contains session " + "inventory\n" ); + } + if ( DH2F( fileh )->f_flags & PF_TERM ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " is stream terminator\n" ); + } + if ( DH2F( fileh )->f_underheadpr ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + " now reading\n" ); + } + } + if ( ! DH2O( objh )->o_lmfknwnpr ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + "\n may be additional " + "unidentified media files\n" ); + } + } + if ( ! DH2S( strmh )->s_lastobjknwnpr ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK | MLOG_MEDIA, + "\n may be " + "additional unidentified media objects\n\n" ); + } + } +} + +static intgen_t +egrpcmp( egrp_t *egrpap, egrp_t *egrpbp ) +{ + if ( egrpap->eg_ino < egrpbp->eg_ino ) { + return -1; + } else if ( egrpap->eg_ino > egrpbp->eg_ino ) { + return 1; + } else if ( egrpap->eg_off < egrpbp->eg_off ) { + return -1; + } else if ( egrpap->eg_off > egrpbp->eg_off ) { + return 1; + } else { + return 0; + } +} + +static void +display_dump_label( bool_t lockpr, + intgen_t mllevel, + char *introstr, + global_hdr_t *grhdrp, + media_hdr_t *mrhdrp, + content_hdr_t *crhdrp, + content_inode_hdr_t *scrhdrp ) +{ + char dateline[ 28 ]; + char level_string[ 2 ]; + char dump_string_uuid[UUID_STR_LEN + 1]; + char media_string_uuid[UUID_STR_LEN + 1]; + char fs_string_uuid[UUID_STR_LEN + 1]; + + ASSERT( scrhdrp->cih_level >= 0 ); + ASSERT( scrhdrp->cih_level < 10 ); + level_string[ 0 ] = ( char )( '0' + ( u_char_t )scrhdrp->cih_level ); + level_string[ 1 ] = 0; + + uuid_unparse(grhdrp->gh_dumpid, dump_string_uuid); + uuid_unparse(mrhdrp->mh_mediaid, media_string_uuid); + uuid_unparse(crhdrp->ch_fsid, fs_string_uuid); + + if ( lockpr ) { + mlog_lock( ); + } + + mlog( mllevel | MLOG_NOLOCK, + "%s", + introstr ); + mlog( mllevel | MLOG_NOLOCK, + "hostname: %s\n", + grhdrp->gh_hostname ); + mlog( mllevel | MLOG_NOLOCK, + "mount point: %s\n", + crhdrp->ch_mntpnt ); + mlog( mllevel | MLOG_NOLOCK, + "volume: %s\n", + crhdrp->ch_fsdevice ); + mlog( mllevel | MLOG_NOLOCK, + "session time: %s", + ctime_r( &grhdrp->gh_timestamp, dateline )); + mlog( mllevel | MLOG_NOLOCK, + "level: %s%s\n", + level_string, + ( scrhdrp->cih_dumpattr & CIH_DUMPATTR_RESUME ) + ? + " resumed" + : + "" ); + mlog( mllevel | MLOG_NOLOCK, + "session label: \"%s\"\n", + grhdrp->gh_dumplabel ); + mlog( mllevel | MLOG_NOLOCK, + "media label: \"%s\"\n", + mrhdrp->mh_medialabel ); + mlog( mllevel | MLOG_NOLOCK, + "file system id: %s\n", + fs_string_uuid ); + mlog( mllevel | MLOG_NOLOCK, + "session id: %s\n", + dump_string_uuid ); + mlog( mllevel | MLOG_NOLOCK, + "media id: %s\n", + media_string_uuid ); + + if ( lockpr ) { + mlog_unlock( ); + } +} + +static void +display_needed_objects( purp_t purp, + bag_t *bagp, + bool_t knownholespr, + bool_t maybeholespr ) +{ + if ( bagp ) { + ix_t ix; + bagiter_t iter; + bagobj_t *bagobjp; + if ( purp == PURP_DIR ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK, + "the following media objects " + "contain media files not yet tried " + "for directory hierarchy restoral:\n" ); + } + if ( purp == PURP_NONDIR ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK, + "the following media objects " + "are needed:\n" ); + } + bagiter_init( bagp, &iter ); + bagobjp = 0; /* keep lint happy */ + ix = 0; + while ( bagiter_next( &iter, + ( void ** )&bagobjp )) { + char uuidstr[UUID_STR_LEN + 1]; + uuid_unparse( bagobjp->id, uuidstr); + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK, + "\n" ); + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK, + "%2u. label: \"%s\"\n", + ix, + bagobjp->label ); + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK, + " id: \"%s\"\n", + uuidstr ); + if ( bagobjp->indrivepr ) { + if ( drivecnt > 1 ) { + mlog( MLOG_NORMAL + | + MLOG_BARE + | + MLOG_NOLOCK, + " now in drive %u\n", + bagobjp->indriveix ); + } else { + mlog( MLOG_NORMAL + | + MLOG_BARE + | + MLOG_NOLOCK, + " now in drive\n" ); + } + } + ix++; + bagobjp = 0; /* keep lint happy */ + } + } + if ( knownholespr ) { + if ( purp == PURP_DIR ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK, + "\nthere are %sunidentified " + "media objects " + "containing media files not yet tried " + "for directory hierarchy restoral:\n", + bagp ? "additional " : "" ); + } + if ( purp == PURP_NONDIR ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK, + "\nthere are %sunidentified " + "media objects " + "not yet fully restored\n", + bagp ? "additional " : "" ); + } + } else if ( maybeholespr ) { + if ( purp == PURP_DIR ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK, + "\nthere may be %sunidentified " + "media objects " + "containing media files not yet tried " + "for directory hierarchy restoral:\n", + bagp ? "additional " : "" ); + } + if ( purp == PURP_NONDIR ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK, + "\nthere may be %sunidentified " + "media objects " + "not yet fully restored\n", + bagp ? "additional " : "" ); + } + } + + if ( ! bagp && ! knownholespr && ! maybeholespr ) { + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_NOLOCK, + "no additional media objects needed\n" ); + } +} + +/* This routine re-opens the file specified by path. We use the + * "standard" path_to_handle/open_by_handle routines rather than + * the jdm_open syntax - mainly because we would like to get rid + * of the jdm_open stuff and replace it by the standard routines + * specified in sys/handle.h (someday). + * + * The point of the re-open here is to get the FINVIS flag set for + * the file so that invisible I/O occurs when xfsrestore is writing + * a file with DMAPI events set. We do not call reopen_invis for + * files without DMAPI event flags, so that a DMAPI application that + * tries to mess with a non-DMAPI file that is being restored will + * see write events generated by xfsrestore. The logic is a little + * loose here - since we don't really check to see if the event bits + * being set in the F_FSSETDM call include read/write/trunc. + */ +#ifdef F_FSSETDM +static int +reopen_invis(char *path, int oflags) +{ + void *hanp; + size_t hlen; + int fd; + + oflags &= ~(O_EXCL|O_CREAT); + if (path_to_handle(path, &hanp, &hlen)) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "path_to_handle of %s failed:%s\n", + path, strerror( errno )); + return -1; + } + + fd = open_by_handle(hanp, hlen, oflags); + if (fd < 0) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "open_by_handle of %s failed:%s\n", + path, strerror( errno )); + free_handle(hanp, hlen); + return -1; + } + free_handle(hanp, hlen); + return fd; +} + +static int +do_fssetdm_by_handle( + char *path, + fsdmidata_t *fdmp) +{ + void *hanp; + size_t hlen; + int rc; + + if (path_to_handle(path, &hanp, &hlen)) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "path_to_handle of %s failed:%s\n", + path, strerror( errno )); + return -1; + } + + rc = fssetdm_by_handle(hanp, hlen, fdmp); + free_handle(hanp, hlen); + if (rc) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "fssetdm_by_handle of %s failed %s\n", + path, strerror( errno )); + } + return rc; +} +#endif /*F_FSSETDM*/ + +static int +quotafilecheck(char *type, char *dstdir, char *quotafile) +{ + struct stat s; + char buf[MAXPATHLEN]; + + sprintf( buf, + "%s/%s", + dstdir, + quotafile ); + + if ( stat (buf, &s ) >= 0 && S_ISREG(s.st_mode)) { + mlog(MLOG_NORMAL, + "%s quota information written to \'%s\'\n", + type, + buf ); + return 1; + } + + return 0; +} diff -rNu linux-2.4.7/cmd/xfsdump/restore/dirattr.c linux-2.4-xfs/cmd/xfsdump/restore/dirattr.c --- linux-2.4.7/cmd/xfsdump/restore/dirattr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/dirattr.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,1094 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "util.h" +#include "mlog.h" +#include "global.h" +#include "drive.h" +#include "media.h" +#include "content.h" +#include "content_inode.h" +#include "dirattr.h" +#include "openutil.h" +#include "mmap.h" + +/* structure definitions used locally ****************************************/ + +#define max( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) + +/* node handle limits + */ +#ifdef DIRATTRCHK + +/* macros for manipulating dirattr handles when handle consistency + * checking is enabled. the upper bits of a handle will be loaded + * with a handle checksum. + */ +#define HDLSUMCNT 4 +#define HDLSUMSHIFT ( NBBY * sizeof ( dah_t ) - HDLSUMCNT ) +#define HDLSUMLOMASK ( ( 1 << HDLSUMCNT ) - 1 ) +#define HDLSUMMASK ( HDLSUMLOMASK << HDLSUMSHIFT ) +#define HDLDIXCNT HDLSUMSHIFT +#define HDLDIXMASK ( ( 1 << HDLDIXCNT ) - 1 ) +#define HDLGETSUM( h ) ( ( u_int16_t ) \ + ( ( ( int )h >> HDLSUMSHIFT ) \ + & \ + HDLSUMLOMASK )) +#define HDLGETDIX( h ) ( ( dix_t )( ( int )h & HDLDIXMASK )) +#define HDLMKHDL( s, d ) ( ( dah_t )( ( ( ( int )s << HDLSUMSHIFT )\ + & \ + HDLSUMMASK ) \ + | \ + ( ( int )d & HDLDIXMASK ))) +#define DIX_MAX ( ( off64_t )HDLDIXMASK ) + +/* each dirattr will hold two check fields: a handle checksum, and unique + * pattern, to differentiate a valid dirattr from random file contents. + */ +#define DIRATTRUNQ 0xa116 + +#else /* DIRATTRCHK */ + +#define DIX_MAX ( ( ( off64_t )1 \ + << \ + ( ( off64_t )NBBY \ + * \ + ( off64_t )sizeof( dah_t ))) \ + - \ + ( off64_t )2 ) /* 2 to avoid DAH_NULL */ + +#endif /* DIRATTRCHK */ + +/* dirattr definition + */ +struct dirattr { +#ifdef DIRATTRCHK + u_int16_t d_unq; + u_int16_t d_sum; +#endif /* DIRATTRCHK */ + mode_t d_mode; + uid_t d_uid; + gid_t d_gid; + time_t d_atime; + time_t d_mtime; + time_t d_ctime; + u_int32_t d_xflags; + u_int32_t d_extsize; + u_int32_t d_dmevmask; + u_int32_t d_dmstate; +#ifdef EXTATTR + off64_t d_extattroff; +#endif /* EXTATTR */ +}; + +typedef struct dirattr dirattr_t; + +#ifdef EXTATTR +#define DIRATTR_EXTATTROFFNULL ( ( off64_t )OFF64MAX ) +#endif /* EXTATTR */ + +/* dirattr persistent context definition + */ +struct dirattr_pers { + off64_t dp_appendoff; +}; + +typedef struct dirattr_pers dirattr_pers_t; + +#define DIRATTR_PERS_SZ pgsz + +/* dirattr transient context definition + */ +struct dirattr_tran { + char *dt_pathname; + int dt_fd; + bool_t dt_at_endpr; + dah_t dt_cachedh; + dirattr_t dt_cached_dirattr; +#ifdef EXTATTR + char *dt_extattrpathname; + int dt_extattrfd; + bool_t dt_extattrfdbadpr; +#endif /* EXTATTR */ +}; + +typedef struct dirattr_tran dirattr_tran_t; + + +/* a dirattr is identified internally by its index into the backing store. + * this index is the offset of the dirattr (relative to the end of the dirattr + * persistent state hdr) into the backing store divided by the size of a + * dirattr. a special index is reserved to represent the null index. a type + * is defined for dirattr index (dix_t). it is a 64 bit signed for direct use + * in the lseek64 system call. + */ +typedef off64_t dix_t; +#define DIX2OFF( dix ) ( ( off64_t )( dix * ( off64_t )sizeof( dirattr_t ) \ + + \ + ( off64_t )DIRATTR_PERS_SZ )) +#define OFF2DIX( doff ) ( ( dix_t )( ( doff - ( off64_t )DIRATTR_PERS_SZ ) \ + / \ + ( off64_t )sizeof( dirattr_t ))) + + +/* declarations of externally defined global symbols *************************/ + +extern size_t pgsz; + +/* forward declarations of locally defined static functions ******************/ + +static void dirattr_get( dah_t ); +#ifdef EXTATTR +static void dirattr_flush( void ); +#endif /* EXTATTR */ +#ifdef DIRATTRCHK +static u_int16_t calcdixcum( dix_t dix ); +#endif /* DIRATTRCHK */ + + +/* definition of locally defined global variables ****************************/ + + +/* definition of locally defined static variables *****************************/ + +static char *dirattrfile = "dirattr"; +#ifdef EXTATTR +static char *dirextattrfile = "dirextattr"; +#endif /* EXTATTR */ +static dirattr_tran_t *dtp = 0; +static dirattr_pers_t *dpp = 0; + + +/* definition of locally defined global functions ****************************/ + +bool_t +dirattr_init( char *hkdir, bool_t resume, u_int64_t dircnt ) +{ +#ifdef SESSCPLT + if ( dtp ) { + return BOOL_TRUE; + } +#endif /* SESSCPLT */ + + /* sanity checks + */ + ASSERT( sizeof( dirattr_pers_t ) <= DIRATTR_PERS_SZ ); + ASSERT( ! dtp ); + ASSERT( ! dpp ); + + /* allocate and initialize context + */ + dtp = ( dirattr_tran_t * )calloc( 1, sizeof( dirattr_tran_t )); + ASSERT( dtp ); + dtp->dt_cachedh = DAH_NULL; + dtp->dt_fd = -1; +#ifdef EXTATTR + dtp->dt_extattrfd = -1; +#endif /* EXTATTR */ + + /* generate a string containing the pathname of the dirattr file + */ + dtp->dt_pathname = open_pathalloc( hkdir, dirattrfile, 0 ); + + /* open the dirattr file + */ + if ( resume ) { + /* open existing file + */ + dtp->dt_fd = open( dtp->dt_pathname, O_RDWR ); + if ( dtp->dt_fd < 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "could not find directory attributes file %s: " + "%s\n", + dtp->dt_pathname, + strerror( errno )); + return BOOL_FALSE; + } + } else { + /* create the dirattr file, first unlinking any older version + * laying around + */ + ( void )unlink( dtp->dt_pathname ); + dtp->dt_fd = open( dtp->dt_pathname, + O_RDWR | O_CREAT | O_EXCL, + S_IRUSR | S_IWUSR ); + if ( dtp->dt_fd < 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "could not create directory attributes file %s: " + "%s\n", + dtp->dt_pathname, + strerror( errno )); + return BOOL_FALSE; + } + + /* reserve space for the backing store. try to use F_RESVSP64. + * if doesn't work, try F_RESVSP64. the former is faster, since + * it does not zero the space. + */ + { + bool_t successpr; + intgen_t ioctlcmd; + intgen_t loglevel; + size_t trycnt; + +#ifndef F_RESVSP64 +#define F_RESVSP64 0 +#endif /* F_RESVSP64 */ + + for ( trycnt = 0, + successpr = BOOL_FALSE, + ioctlcmd = XFS_IOC_RESVSP64, + loglevel = MLOG_VERBOSE + ; + ! successpr && trycnt < 2 + ; + trycnt++, + ioctlcmd = XFS_IOC_ALLOCSP64, + loglevel = max( MLOG_NORMAL, loglevel - 1 )) { + off64_t initsz; + struct flock64 flock64; + intgen_t rval; + + if ( ! ioctlcmd ) { + continue; + } + + initsz = ( off64_t )DIRATTR_PERS_SZ + + + ( ( off64_t )dircnt * sizeof( dirattr_t )); + flock64.l_whence = 0; + flock64.l_start = 0; + flock64.l_len = initsz; + rval = ioctl( dtp->dt_fd, ioctlcmd, &flock64 ); + if ( rval ) { + mlog( loglevel | MLOG_NOTE, + "attempt to reserve %lld bytes for %s " + "using %s " + "failed: %s (%d)\n", + initsz, + dtp->dt_pathname, + ioctlcmd == F_RESVSP64 + ? + "F_RESVSP64" + : + "F_ALLOCSP64", + strerror( errno ), + errno ); + } else { + successpr = BOOL_TRUE; + } + } + } + } + + /* mmap the persistent descriptor + */ + ASSERT( ! ( DIRATTR_PERS_SZ % pgsz )); + dpp = ( dirattr_pers_t * )mmap_autogrow( DIRATTR_PERS_SZ, + dtp->dt_fd, + ( off_t )0 ); + ASSERT( dpp ); + if ( dpp == ( dirattr_pers_t * )-1 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "unable to map %s: %s\n", + dtp->dt_pathname, + strerror( errno )); + return BOOL_FALSE; + } + + /* initialize persistent state + */ + if ( ! resume ) { + dpp->dp_appendoff = ( off64_t )DIRATTR_PERS_SZ; + } + + /* initialize transient state + */ + dtp->dt_at_endpr = BOOL_FALSE; + +#ifdef EXTATTR + /* calculate the dir extattr pathname, and set the fd to -1. + * file will be created on demand. + */ + dtp->dt_extattrpathname = open_pathalloc( hkdir, dirextattrfile, 0 ); + dtp->dt_extattrfd = -1; + dtp->dt_extattrfdbadpr = BOOL_FALSE; + if ( resume ) { + ( void )unlink( dtp->dt_extattrpathname ); + } +#endif /* EXTATTR */ + + return BOOL_TRUE; +} + +void +dirattr_cleanup( void ) +{ + /* REFERENCED */ + intgen_t rval; + + if ( ! dtp ) { + return; + } + if ( dpp ) { + rval = munmap( ( void * )dpp, DIRATTR_PERS_SZ ); + ASSERT( ! rval ); + dpp = 0; + } + if ( dtp->dt_fd >= 0 ) { + ( void )close( dtp->dt_fd ); + dtp->dt_fd = -1; + } + if ( dtp->dt_pathname ) { + ( void )unlink( dtp->dt_pathname ); + free( ( void * )dtp->dt_pathname ); + } +#ifdef EXTATTR + if ( dtp->dt_extattrfd >= 0 ) { + ( void )close( dtp->dt_extattrfd ); + dtp->dt_extattrfd = -1; + } + if ( dtp->dt_extattrpathname ) { + ( void )unlink( dtp->dt_extattrpathname ); + free( ( void * )dtp->dt_extattrpathname ); + } +#endif /* EXTATTR */ + free( ( void * )dtp ); + dtp = 0; +} + +dah_t +dirattr_add( filehdr_t *fhdrp ) +{ + dirattr_t dirattr; + intgen_t nwritten; + off64_t oldoff; + dix_t dix; +#ifdef DIRATTRCHK + u_int16_t sum; +#endif /* DIRATTRCHK */ + dah_t dah; + + /* sanity checks + */ + ASSERT( dtp ); + ASSERT( dpp ); + + /* make sure file pointer is positioned to write at end of file + */ + if ( ! dtp->dt_at_endpr ) { + off64_t newoff; + newoff = lseek64( dtp->dt_fd, dpp->dp_appendoff, SEEK_SET ); + if ( newoff == ( off64_t )-1 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "lseek of dirattr failed: %s\n", + strerror( errno )); + return DAH_NULL; + } + ASSERT( dpp->dp_appendoff == newoff ); + dtp->dt_at_endpr = BOOL_TRUE; + } + + /* calculate the index of this dirattr + */ + oldoff = dpp->dp_appendoff; + dix = OFF2DIX( oldoff ); + ASSERT( dix <= DIX_MAX ); + + /* populate a dirattr + */ + dirattr.d_mode = ( mode_t )fhdrp->fh_stat.bs_mode; + dirattr.d_uid = ( uid_t )fhdrp->fh_stat.bs_uid; + dirattr.d_gid = ( gid_t )fhdrp->fh_stat.bs_gid; + dirattr.d_atime = ( time_t )fhdrp->fh_stat.bs_atime.tv_sec; + dirattr.d_mtime = ( time_t )fhdrp->fh_stat.bs_mtime.tv_sec; + dirattr.d_ctime = ( time_t )fhdrp->fh_stat.bs_ctime.tv_sec; + dirattr.d_xflags = fhdrp->fh_stat.bs_xflags; + dirattr.d_extsize = ( u_int32_t )fhdrp->fh_stat.bs_extsize; + dirattr.d_dmevmask = fhdrp->fh_stat.bs_dmevmask; + dirattr.d_dmstate = ( u_int32_t )fhdrp->fh_stat.bs_dmstate; +#ifdef DIRATTRCHK + dirattr.d_unq = DIRATTRUNQ; + sum = calcdixcum( dix ); + dirattr.d_sum = sum; +#endif /* DIRATTRCHK */ +#ifdef EXTATTR + dirattr.d_extattroff = DIRATTR_EXTATTROFFNULL; +#endif /* EXTATTR */ + + /* write the dirattr + */ + nwritten = write( dtp->dt_fd, ( void * )&dirattr, sizeof( dirattr )); + if ( ( size_t )nwritten != sizeof( dirattr )) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "write of dirattr failed: %s\n", + strerror( errno )); + return DAH_NULL; + } + + /* update the next write offset + */ + ASSERT( dpp->dp_appendoff <= OFF64MAX - ( off64_t )nwritten ); + dpp->dp_appendoff += ( off64_t )nwritten; + +#ifdef DIRATTRCHK + dah = HDLMKHDL( sum, dix ); +#else /* DIRATTRCHK */ + dah = ( dah_t )dix; +#endif /* DIRATTRCHK */ + + return dah; +} + +#ifdef EXTATTR +void +dirattr_addextattr( dah_t dah, extattrhdr_t *ahdrp ) +{ + off64_t oldoff; + off64_t off; + off64_t seekoff; + off64_t nulloff; + intgen_t nread; + intgen_t nwritten; + + /* pull the selected dir attributes into the cache + */ + dirattr_get( dah ); + + /* open/create extended attributes file if not yet done + */ + if ( dtp->dt_extattrfd < 0 ) { + if ( dtp->dt_extattrfdbadpr ) { + return; + } + dtp->dt_extattrfd = open( dtp->dt_extattrpathname, + O_RDWR | O_CREAT, + S_IRUSR | S_IWUSR ); + if ( dtp->dt_extattrfd < 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not open/create directory " + "extended attributes file %s: " + "%s (%d)\n", + dtp->dt_extattrpathname, + strerror( errno ), + errno ); + dtp->dt_extattrfdbadpr = BOOL_TRUE; + return; + } + } + + /* seek to the end of the dir extattr list + */ + off = dtp->dt_cached_dirattr.d_extattroff; + oldoff = DIRATTR_EXTATTROFFNULL; + while ( off != DIRATTR_EXTATTROFFNULL ) { + seekoff = lseek64( dtp->dt_extattrfd, off, SEEK_SET ); + if ( seekoff < 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not seek to into extended attributes " + "file %s: " + "%s (%d)\n", + dtp->dt_extattrpathname, + strerror( errno ), + errno ); + dtp->dt_extattrfdbadpr = BOOL_TRUE; + return; + } + ASSERT( seekoff == off ); + + oldoff = off; + + nread = read( dtp->dt_extattrfd, + ( void * )&off, + sizeof( off )); + if ( nread != ( intgen_t )sizeof( off )) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not read extended attributes " + "file %s: " + "%s (%d)\n", + dtp->dt_extattrpathname, + strerror( errno ), + errno ); + dtp->dt_extattrfdbadpr = BOOL_TRUE; + return; + } + } + + /* append the extended attributes + */ + off = lseek64( dtp->dt_extattrfd, 0, SEEK_END ); + if ( off < 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not seek to end of extended attributes " + "file %s: " + "%s (%d)\n", + dtp->dt_extattrpathname, + strerror( errno ), + errno ); + dtp->dt_extattrfdbadpr = BOOL_TRUE; + return; + } + nulloff = DIRATTR_EXTATTROFFNULL; + nwritten = write( dtp->dt_extattrfd, + ( void * )&nulloff, + sizeof( nulloff )); + if ( nwritten != ( intgen_t )sizeof( nulloff )) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not write extended attributes " + "file %s: " + "%s (%d)\n", + dtp->dt_extattrpathname, + strerror( errno ), + errno ); + dtp->dt_extattrfdbadpr = BOOL_TRUE; + return; + } + nwritten = write( dtp->dt_extattrfd, ( void * )ahdrp, ahdrp->ah_sz ); + if ( nwritten != ( intgen_t )( ahdrp->ah_sz )) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not write at end of extended attributes " + "file %s: " + "%s (%d)\n", + dtp->dt_extattrpathname, + strerror( errno ), + errno ); + dtp->dt_extattrfdbadpr = BOOL_TRUE; + return; + } + + /* fill in the offset of the extended attributes into the + * linked list + */ + if ( oldoff == DIRATTR_EXTATTROFFNULL ) { + dtp->dt_cached_dirattr.d_extattroff = off; + dirattr_flush( ); + } else { + seekoff = lseek64( dtp->dt_extattrfd, oldoff, SEEK_SET ); + if ( seekoff < 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not seek to into extended attributes " + "file %s: " + "%s (%d)\n", + dtp->dt_extattrpathname, + strerror( errno ), + errno ); + dtp->dt_extattrfdbadpr = BOOL_TRUE; + return; + } + ASSERT( seekoff == oldoff ); + nwritten = write( dtp->dt_extattrfd, + ( void * )&off, + sizeof( off )); + if ( nwritten != ( intgen_t )sizeof( off )) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not write extended attributes " + "file %s: " + "%s (%d)\n", + dtp->dt_extattrpathname, + strerror( errno ), + errno ); + dtp->dt_extattrfdbadpr = BOOL_TRUE; + return; + } + } +} + +bool_t +dirattr_cb_extattr( dah_t dah, + bool_t ( * cbfunc )( extattrhdr_t *ahdrp, + void *ctxp ), + extattrhdr_t *ahdrp, + void *ctxp ) +{ + off64_t off; + + /* pull the selected dir attributes into the cache + */ + dirattr_get( dah ); + + /* open/create extended attributes file if not yet done + */ + if ( dtp->dt_extattrfd < 0 ) { + if ( dtp->dt_extattrfdbadpr ) { + return BOOL_TRUE; + } + dtp->dt_extattrfd = open( dtp->dt_extattrpathname, + O_RDWR | O_CREAT, + S_IRUSR | S_IWUSR ); + if ( dtp->dt_extattrfd < 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not open/create directory " + "extended attributes file %s: " + "%s (%d)\n", + dtp->dt_extattrpathname, + strerror( errno ), + errno ); + dtp->dt_extattrfdbadpr = BOOL_TRUE; + return BOOL_TRUE; + } + } + + /* walk through the dirattr list for this dah + */ + off = dtp->dt_cached_dirattr.d_extattroff; + while ( off != DIRATTR_EXTATTROFFNULL ) { + off64_t seekoff; + intgen_t nread; + off64_t nextoff; + size_t recsz; + bool_t ok; + + /* seek to the extattr + */ + seekoff = lseek64( dtp->dt_extattrfd, off, SEEK_SET ); + if ( seekoff < 0 ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not seek to into extended attributes " + "file %s: " + "%s (%d)\n", + dtp->dt_extattrpathname, + strerror( errno ), + errno ); + dtp->dt_extattrfdbadpr = BOOL_TRUE; + return BOOL_TRUE; + } + ASSERT( seekoff == off ); + + /* peel off the next offset + */ + nread = read( dtp->dt_extattrfd, + ( void * )&nextoff, + sizeof( nextoff )); + if ( nread != ( intgen_t )sizeof( nextoff )) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not read extended attributes " + "file %s: " + "%s (%d)\n", + dtp->dt_extattrpathname, + strerror( errno ), + errno ); + dtp->dt_extattrfdbadpr = BOOL_TRUE; + return BOOL_TRUE; + } + + /* read the extattr hdr + */ + nread = read( dtp->dt_extattrfd, + ( void * )ahdrp, + EXTATTRHDR_SZ ); + if ( nread != EXTATTRHDR_SZ ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not read extended attributes " + "file %s: " + "%s (%d)\n", + dtp->dt_extattrpathname, + strerror( errno ), + errno ); + dtp->dt_extattrfdbadpr = BOOL_TRUE; + return BOOL_TRUE; + } + + /* read the remainder of the extattr + */ + recsz = ( size_t )ahdrp->ah_sz; + ASSERT( recsz >= EXTATTRHDR_SZ ); + nread = read( dtp->dt_extattrfd, + ( void * )&ahdrp[ 1 ], + recsz - EXTATTRHDR_SZ ); + if ( nread != ( intgen_t )( recsz - EXTATTRHDR_SZ )) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "could not read extended attributes " + "file %s: " + "%s (%d)\n", + dtp->dt_extattrpathname, + strerror( errno ), + errno ); + dtp->dt_extattrfdbadpr = BOOL_TRUE; + return BOOL_TRUE; + } + + /* call the callback func + */ + ok = ( * cbfunc )( ahdrp, ctxp ); + if ( ! ok ) { + return BOOL_FALSE; + } + + /* go th the next one + */ + off = nextoff; + } + + return BOOL_TRUE; +} +#endif /* EXTATTR */ + +void +dirattr_update( dah_t dah, filehdr_t *fhdrp ) +{ + dix_t dix; +#ifdef DIRATTRCHK + u_int16_t sum; +#endif /* DIRATTRCHK */ + off64_t argoff; + off64_t newoff; + dirattr_t dirattr; + intgen_t nwritten; + + /* sanity checks + */ + ASSERT( dtp ); + ASSERT( dpp ); + + ASSERT( dah != DAH_NULL ); + +#ifdef DIRATTRCHK + sum = HDLGETSUM( dah ); + dix = HDLGETDIX( dah ); +#else /* DIRATTRCHK */ + dix = ( dix_t )dah; +#endif /* DIRATTRCHK */ + + ASSERT( dix >= 0 ); + ASSERT( dix <= DIX_MAX ); + + argoff = DIX2OFF( dix ); + ASSERT( argoff >= 0 ); + ASSERT( argoff >= ( off64_t )DIRATTR_PERS_SZ ); + ASSERT( argoff <= dpp->dp_appendoff - ( off64_t )sizeof( dirattr_t )); + +#ifdef DIRATTRCHK + dirattr_get( dah ); + ASSERT( dtp->dt_cached_dirattr.d_unq == DIRATTRUNQ ); + ASSERT( dtp->dt_cached_dirattr.d_sum == sum ); +#endif /* DIRATTRCHK */ + + /* seek to the dirattr + */ + newoff = lseek64( dtp->dt_fd, argoff, SEEK_SET ); + if ( newoff == ( off64_t )-1 ) { + mlog( MLOG_NORMAL, + "lseek of dirattr failed: %s\n", + strerror( errno )); + ASSERT( 0 ); + } + ASSERT( newoff == argoff ); + + /* populate a dirattr + */ + dirattr.d_mode = ( mode_t )fhdrp->fh_stat.bs_mode; + dirattr.d_uid = ( uid_t )fhdrp->fh_stat.bs_uid; + dirattr.d_gid = ( gid_t )fhdrp->fh_stat.bs_gid; + dirattr.d_atime = ( time_t )fhdrp->fh_stat.bs_atime.tv_sec; + dirattr.d_mtime = ( time_t )fhdrp->fh_stat.bs_mtime.tv_sec; + dirattr.d_ctime = ( time_t )fhdrp->fh_stat.bs_ctime.tv_sec; + dirattr.d_xflags = fhdrp->fh_stat.bs_xflags; + dirattr.d_extsize = ( u_int32_t )fhdrp->fh_stat.bs_extsize; + dirattr.d_dmevmask = fhdrp->fh_stat.bs_dmevmask; + dirattr.d_dmstate = ( u_int32_t )fhdrp->fh_stat.bs_dmstate; +#ifdef EXTATTR + dirattr.d_extattroff = DIRATTR_EXTATTROFFNULL; +#endif /* EXTATTR */ + + /* write the dirattr + */ + nwritten = write( dtp->dt_fd, ( void * )&dirattr, sizeof( dirattr )); + if ( ( size_t )nwritten != sizeof( dirattr )) { + mlog( MLOG_NORMAL, + "update of dirattr failed: %s\n", + strerror( errno )); + ASSERT( 0 ); + } + + dtp->dt_at_endpr = BOOL_FALSE; + dtp->dt_cachedh = dah; +} + +/* ARGSUSED */ +void +dirattr_del( dah_t dah ) +{ +} + +mode_t +dirattr_get_mode( dah_t dah ) +{ + dirattr_get( dah ); + return dtp->dt_cached_dirattr.d_mode; +} + +uid_t +dirattr_get_uid( dah_t dah ) +{ + dirattr_get( dah ); + return dtp->dt_cached_dirattr.d_uid; +} + +uid_t +dirattr_get_gid( dah_t dah ) +{ + dirattr_get( dah ); + return dtp->dt_cached_dirattr.d_gid; +} + +time_t +dirattr_get_atime( dah_t dah ) +{ + dirattr_get( dah ); + return dtp->dt_cached_dirattr.d_atime; +} + +time_t +dirattr_get_mtime( dah_t dah ) +{ + dirattr_get( dah ); + return dtp->dt_cached_dirattr.d_mtime; +} + +time_t +dirattr_get_ctime( dah_t dah ) +{ + dirattr_get( dah ); + return dtp->dt_cached_dirattr.d_ctime; +} + +u_int32_t +dirattr_get_xflags( dah_t dah ) +{ + dirattr_get( dah ); + return dtp->dt_cached_dirattr.d_xflags; +} + +u_int32_t +dirattr_get_extsize( dah_t dah ) +{ + dirattr_get( dah ); + return dtp->dt_cached_dirattr.d_extsize; +} + +u_int32_t +dirattr_get_dmevmask( dah_t dah ) +{ + dirattr_get( dah ); + return dtp->dt_cached_dirattr.d_dmevmask; +} + +u_int32_t +dirattr_get_dmstate( dah_t dah ) +{ + dirattr_get( dah ); + return dtp->dt_cached_dirattr.d_dmstate; +} + + +/* definition of locally defined static functions ****************************/ + +static void +dirattr_get( dah_t dah ) +{ + dix_t dix; + off64_t argoff; + off64_t newoff; + intgen_t nread; +#ifdef DIRATTRCHK + u_int16_t sum; +#endif /* DIRATTRCHK */ + + /* sanity checks + */ + ASSERT( dtp ); + ASSERT( dpp ); + + ASSERT( dah != DAH_NULL ); + + /* if we are already holding this dirattr in cache, + * just return + */ + if ( dtp->dt_cachedh == dah ) { + return; + } + +#ifdef DIRATTRCHK + sum = HDLGETSUM( dah ); + dix = HDLGETDIX( dah ); +#else /* DIRATTRCHK */ + dix = ( dix_t )dah; +#endif /* DIRATTRCHK */ + ASSERT( dix >= 0 ); + ASSERT( dix <= DIX_MAX ); + + argoff = DIX2OFF( dix ); + ASSERT( argoff >= 0 ); + ASSERT( argoff >= ( off64_t )DIRATTR_PERS_SZ ); + ASSERT( argoff <= dpp->dp_appendoff - ( off64_t )sizeof( dirattr_t )); + + /* seek to the dirattr + */ + newoff = lseek64( dtp->dt_fd, argoff, SEEK_SET ); + if ( newoff == ( off64_t )-1 ) { + mlog( MLOG_NORMAL, + "lseek of dirattr failed: %s\n", + strerror( errno )); + ASSERT( 0 ); + } + ASSERT( newoff == argoff ); + + /* read the dirattr + */ + nread = read( dtp->dt_fd, + ( void * )&dtp->dt_cached_dirattr, + sizeof( dtp->dt_cached_dirattr )); + if ( ( size_t )nread != sizeof( dtp->dt_cached_dirattr )) { + mlog( MLOG_NORMAL, + "read of dirattr failed: %s\n", + strerror( errno )); + ASSERT( 0 ); + } + +#ifdef DIRATTRCHK + ASSERT( dtp->dt_cached_dirattr.d_unq == DIRATTRUNQ ); + ASSERT( dtp->dt_cached_dirattr.d_sum == sum ); +#endif /* DIRATTRCHK */ + + dtp->dt_at_endpr = BOOL_FALSE; + dtp->dt_cachedh = dah; +} + +#ifdef EXTATTR +static void +dirattr_flush( void ) +{ + dah_t dah; + dix_t dix; +#ifdef DIRATTRCHK + u_int16_t sum; +#endif /* DIRATTRCHK */ + off64_t argoff; + off64_t newoff; + intgen_t nwritten; + + /* sanity checks + */ + ASSERT( dtp ); + ASSERT( dpp ); + + /* if nothing in the cache, ignore + */ + dah = dtp->dt_cachedh; + ASSERT( dah != DAH_NULL ); + if ( dah == DAH_NULL ) { + return; + } + +#ifdef DIRATTRCHK + sum = HDLGETSUM( dah ); + dix = HDLGETDIX( dah ); +#else /* DIRATTRCHK */ + dix = ( dix_t )dah; +#endif /* DIRATTRCHK */ + +#ifdef DIRATTRCHK + ASSERT( dtp->dt_cached_dirattr.d_unq == DIRATTRUNQ ); + ASSERT( dtp->dt_cached_dirattr.d_sum == sum ); +#endif /* DIRATTRCHK */ + + ASSERT( dix >= 0 ); + ASSERT( dix <= DIX_MAX ); + + argoff = DIX2OFF( dix ); + ASSERT( argoff >= 0 ); + ASSERT( argoff >= ( off64_t )DIRATTR_PERS_SZ ); + ASSERT( argoff <= dpp->dp_appendoff - ( off64_t )sizeof( dirattr_t )); + + /* seek to the dirattr + */ + newoff = lseek64( dtp->dt_fd, argoff, SEEK_SET ); + if ( newoff == ( off64_t )-1 ) { + mlog( MLOG_NORMAL, + "lseek of dirattr failed: %s\n", + strerror( errno )); + ASSERT( 0 ); + } + ASSERT( newoff == argoff ); + + /* write the dirattr + */ + nwritten = write( dtp->dt_fd, + ( void * )&dtp->dt_cached_dirattr, + sizeof( dtp->dt_cached_dirattr )); + if ( ( size_t )nwritten != sizeof( dtp->dt_cached_dirattr )) { + mlog( MLOG_NORMAL, + "flush of dirattr failed: %s\n", + strerror( errno )); + ASSERT( 0 ); + } + + dtp->dt_at_endpr = BOOL_FALSE; +} +#endif /* EXTATTR */ + + +#ifdef DIRATTRCHK + +static u_int16_t +calcdixcum( dix_t dix ) +{ + u_int16_t sum; + ix_t nibcnt; + ix_t nibix; + + ASSERT( ( sizeof( dah_t ) / HDLSUMCNT ) * HDLSUMCNT == sizeof( dah_t )); + + nibcnt = ( sizeof( dah_t ) / HDLSUMCNT ) - 1; + sum = 0; + for ( nibix = 0 ; nibix < nibcnt ; nibix++ ) { + sum += ( u_int16_t )( dix & HDLSUMLOMASK ); + dix >>= HDLSUMCNT; + } + sum = ( u_int16_t )( ( ~sum + 1 ) & HDLSUMLOMASK ); + + return sum; +} + +#endif /* DIRATTRCHK */ diff -rNu linux-2.4.7/cmd/xfsdump/restore/dirattr.h linux-2.4-xfs/cmd/xfsdump/restore/dirattr.h --- linux-2.4.7/cmd/xfsdump/restore/dirattr.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/dirattr.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef DIRATTR_H +#define DIRATTR_H + +/* dah_t - handle to registered directory attributes + * a special handle is reserved for the caller's convenience, + * to indicate no directory attributes have been registered. + */ +typedef size32_t dah_t; +#define DAH_NULL SIZE32MAX + + +/* dirattr_init - creates the directory attributes registry. + * resync indicates if an existing context should be re-opened. + * returns FALSE if an error encountered. if NOT resync, + * dircnt hints at number of directories to expect. + */ +extern bool_t dirattr_init( char *housekeepingdir, + bool_t resync, + u_int64_t dircnt ); + + +/* dirattr_cleanup - removes all traces + */ +extern void dirattr_cleanup( void ); + + +/* dirattr_add - registers a directory's attributes. knows how to interpret + * the filehdr. returns handle for use with dirattr_get_...(). + */ +extern dah_t dirattr_add( filehdr_t *fhdrp ); + +/* dirattr_update - modifies existing registered attributes + */ +extern void dirattr_update( dah_t dah, filehdr_t *fhdrp ); + +/* dirattr_del - frees dirattr no longer needed + */ +extern void dirattr_del( dah_t dah ); + +/* dirattr_get_... - retrieve various attributes + */ +mode_t dirattr_get_mode( dah_t dah ); +uid_t dirattr_get_uid( dah_t dah ); +gid_t dirattr_get_gid( dah_t dah ); +time_t dirattr_get_atime( dah_t dah ); +time_t dirattr_get_mtime( dah_t dah ); +time_t dirattr_get_ctime( dah_t dah ); +u_int32_t dirattr_get_xflags( dah_t dah ); +u_int32_t dirattr_get_extsize( dah_t dah ); +u_int32_t dirattr_get_dmevmask( dah_t dah ); +u_int32_t dirattr_get_dmstate( dah_t dah ); + +#ifdef EXTATTR +/* dirattr_addextattr - record an extended attribute. second argument is + * ptr to extattrhdr_t, with extattr name and value appended as + * described by hdr. + */ +extern void dirattr_addextattr( dah_t dah, extattrhdr_t *ahdrp ); + +/* dirattr_cb_extattr - calls back for every extended attribute associated with + * the given dah. stops iteration and returnd FALSE if cbfunc returns FALSE, + * else returns TRUE. + */ +extern bool_t dirattr_cb_extattr( dah_t dah, + bool_t ( * cbfunc )( extattrhdr_t *ahdrp, + void *ctxp ), + extattrhdr_t *ahdrp, + void *ctxp ); +#endif /* EXTATTR */ + +#endif /* DIRATTR_H */ diff -rNu linux-2.4.7/cmd/xfsdump/restore/getopt.h linux-2.4-xfs/cmd/xfsdump/restore/getopt.h --- linux-2.4.7/cmd/xfsdump/restore/getopt.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/getopt.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef GETOPT_H +#define GETOPT_H + +/* getopt.h common getopt command string + * + * several modules parse the command line looking for arguments specific to + * that module. Unfortunately, each of the getopt(3) calls needs the + * complete command string, to know how to parse. This file's sole + * purpose is to contain that command string. + */ + +#define GETOPT_CMDSTRING "a:b:c:def:himn:op:qrs:tv:ACDEFG:H:I:JL:M:NO:PQRS:TUVWX:Y:Z" + +#define GETOPT_WORKSPACE 'a' /* workspace dir (content.c) */ +#define GETOPT_BLOCKSIZE 'b' /* blocksize for rmt */ +#define GETOPT_ALERTPROG 'c' /* Media Change Alert prog(content.c) */ +#define GETOPT_PV766024 'd' /* DRIVE_ERROR_MEDIA for pv#766024 */ +#define GETOPT_EXISTING 'e' /* don't overwrite existing files */ +#define GETOPT_DUMPDEST 'f' /* dump src. file (drive.c) */ +#define GETOPT_HELP 'h' /* display version and usage */ +#define GETOPT_INTERACTIVE 'i' /* interactive subtree selection */ +#define GETOPT_MINRMT 'm' /* use minimal rmt protocol */ +#define GETOPT_NEWER 'n' /* only restore files newer than arg */ +#define GETOPT_OWNER 'o' /* restore owner/grp even if not root */ +#define GETOPT_PROGRESS 'p' /* interval between progress reports */ +#define GETOPT_QIC 'q' /* option to tell dump it's a QIC tape */ +#define GETOPT_CUMULATIVE 'r' /* accumulating restore (content.c) */ +#define GETOPT_SUBTREE 's' /* subtree restore (content.c) */ +#define GETOPT_TOC 't' /* display contents only (content.c) */ +#define GETOPT_VERBOSITY 'v' /* verbosity level (0 to 4 ) */ +#define GETOPT_NOEXTATTR 'A' /* do not restore ext. file attr. */ +#define GETOPT_RECCHKSUM 'C' /* use record checksums */ +#define GETOPT_SETDM 'D' /* set DMAPI event mask and state */ +#define GETOPT_CHANGED 'E' /* overwrite if missing or old */ +#define GETOPT_FORCE 'F' /* don't prompt (getopt.c) */ +#define GETOPT_MINSTACKSZ 'G' /* minimum stack size (bytes) */ +#define GETOPT_MAXSTACKSZ 'H' /* maximum stack size (bytes) */ +#define GETOPT_INVPRINT 'I' /* just display the inventory */ +#define GETOPT_NOINVUPDATE 'J' /* do not update the dump inventory */ +#define GETOPT_DUMPLABEL 'L' /* dump session label (global.c) */ +#define GETOPT_MEDIALABEL 'M' /* media object label (media.c) */ +#define GETOPT_TIMESTAMP 'N' /* show timestamps in log msgs */ +#define GETOPT_OPTFILE 'O' /* specifycmd line options file */ +#define GETOPT_RINGPIN 'P' /* pin down I/O buffer ring */ +#define GETOPT_SESSCPLT 'Q' /* force completion of intr. session */ +#define GETOPT_RESUME 'R' /* resume intr rest (content.c) */ +#define GETOPT_SESSIONID 'S' /* dump session uuid (global.c) */ +#define GETOPT_NOTIMEOUTS 'T' /* don't timeout dialogs */ +#define GETOPT_UNLOAD 'U' /* unload media when change needed */ +#define GETOPT_SHOWLOGSS 'V' /* show subsystem of log messages */ +#define GETOPT_SHOWLOGLEVEL 'W' /* show level of log messages */ +#define GETOPT_NOSUBTREE 'X' /* subtree to exclude */ +#define GETOPT_RINGLEN 'Y' /* specify I/O buffer ring length */ +#define GETOPT_MINIROOT 'Z' /* apply miniroot restrictions */ + +#endif /* GETOPT_H */ diff -rNu linux-2.4.7/cmd/xfsdump/restore/inomap.c linux-2.4-xfs/cmd/xfsdump/restore/inomap.c --- linux-2.4.7/cmd/xfsdump/restore/inomap.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/inomap.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,616 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "util.h" +#include "openutil.h" +#include "mlog.h" +#include "global.h" +#include "drive.h" +#include "media.h" +#include "content.h" +#include "content_inode.h" +#include "inomap.h" +#include "mmap.h" +#include "arch_xlate.h" + +/* structure definitions used locally ****************************************/ + +/* restores the inomap into a file + */ +#define PERS_NAME "inomap" + +/* reserve the first page for persistent state + */ +struct pers { + size64_t hnkcnt; + /* number of hunks in map + */ + size64_t segcnt; + /* number of segments + */ + xfs_ino_t last_ino_added; +}; + +typedef struct pers pers_t; + +#define PERSSZ perssz + + + +/* declarations of externally defined global symbols *************************/ + +extern size_t pgsz; + + +/* forward declarations of locally defined static functions ******************/ + +/* inomap primitives + */ +static intgen_t map_getset( xfs_ino_t, intgen_t, bool_t ); +static intgen_t map_set( xfs_ino_t ino, intgen_t ); + + +/* definition of locally defined global variables ****************************/ + + +/* definition of locally defined static variables *****************************/ + +static intgen_t pers_fd = -1; + /* file descriptor for persistent inomap backing store + */ + +/* context for inomap construction - initialized by inomap_restore_pers + */ +static u_int64_t hnkcnt; +static u_int64_t segcnt; +static hnk_t *roothnkp = 0; +static hnk_t *tailhnkp; +static seg_t *lastsegp; +static xfs_ino_t last_ino_added; + + +/* definition of locally defined global functions ****************************/ + +rv_t +inomap_restore_pers( drive_t *drivep, + content_inode_hdr_t *scrhdrp, + char *hkdir ) +{ + drive_ops_t *dop = drivep->d_opsp; + char *perspath; + pers_t *persp; + hnk_t *pershnkp; + hnk_t *tmphnkp; + intgen_t fd; + /* REFERENCED */ + intgen_t nread; + intgen_t rval; + /* REFERENCED */ + intgen_t rval1; + int i; + bool_t ok; + + /* sanity checks + */ + ASSERT( INOPERSEG == ( sizeof( (( seg_t * )0 )->lobits ) * NBBY )); + ASSERT( sizeof( hnk_t ) == HNKSZ ); + ASSERT( HNKSZ >= pgsz ); + ASSERT( ! ( HNKSZ % pgsz )); + ASSERT( sizeof( pers_t ) <= PERSSZ ); + + /* get inomap info from media hdr + */ + hnkcnt = scrhdrp->cih_inomap_hnkcnt; + segcnt = scrhdrp->cih_inomap_segcnt; + last_ino_added = scrhdrp->cih_inomap_lastino; + + /* truncate and open the backing store + */ + perspath = open_pathalloc( hkdir, PERS_NAME, 0 ); + ( void )unlink( perspath ); + fd = open( perspath, + O_RDWR | O_CREAT, + S_IRUSR | S_IWUSR ); + if ( fd < 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "could not open %s: %s\n", + perspath, + strerror( errno )); + return RV_ERROR; + } + + /* mmap the persistent hdr and space for the map + */ + ASSERT( sizeof( hnk_t ) * ( size_t )hnkcnt >= pgsz ); + ASSERT( ! ( sizeof( hnk_t ) * ( size_t )hnkcnt % pgsz )); + persp = ( pers_t * ) mmap_autogrow( + PERSSZ + + + sizeof( hnk_t ) * ( size_t )hnkcnt, + fd, + ( off64_t )0 ); + if ( persp == ( pers_t * )-1 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "unable to map %s: %s\n", + perspath, + strerror( errno )); + return RV_ERROR; + } + + /* load the pers hdr + */ + persp->hnkcnt = hnkcnt; + persp->segcnt = segcnt; + persp->last_ino_added = last_ino_added; + + tmphnkp = ( hnk_t * )calloc( ( size_t )hnkcnt, sizeof( hnk_t )); + ASSERT( tmphnkp ); + + /* read the map in from media + */ + nread = read_buf( ( char * )tmphnkp, + sizeof( hnk_t ) * ( size_t )hnkcnt, + ( void * )drivep, + ( rfp_t )dop->do_read, + ( rrbfp_t )dop->do_return_read_buf, + &rval ); + + pershnkp = (hnk_t *)((char *)persp + PERSSZ); + for(i = 0; i < hnkcnt; i++) { + xlate_hnk(&tmphnkp[i], &pershnkp[i], 1); + } + free(tmphnkp); + + mlog(MLOG_NITTY, "inomap_restore_pers: pre-munmap\n"); + + /* close up + */ + rval1 = munmap( ( void * )persp, + PERSSZ + + + sizeof( hnk_t ) * ( size_t )hnkcnt ); + ASSERT( ! rval1 ); + ( void )close( fd ); + free( ( void * )perspath ); + + mlog(MLOG_NITTY, "inomap_restore_pers: post-munmap\n"); + + /* check the return code from read + */ + switch( rval ) { + case 0: + ASSERT( ( size_t )nread == sizeof( hnk_t ) * ( size_t )hnkcnt ); + ok = inomap_sync_pers( hkdir ); + if ( ! ok ) { + return RV_ERROR; + } + return RV_OK; + case DRIVE_ERROR_EOD: + case DRIVE_ERROR_EOF: + case DRIVE_ERROR_EOM: + case DRIVE_ERROR_MEDIA: + case DRIVE_ERROR_CORRUPTION: + return RV_CORRUPT; + case DRIVE_ERROR_DEVICE: + return RV_DRIVE; + case DRIVE_ERROR_CORE: + default: + return RV_CORE; + } +} + +/* peels inomap from media + */ +rv_t +inomap_discard( drive_t *drivep, content_inode_hdr_t *scrhdrp ) +{ + drive_ops_t *dop = drivep->d_opsp; + u_int64_t tmphnkcnt; + /* REFERENCED */ + intgen_t nread; + intgen_t rval; + + /* get inomap info from media hdr + */ + tmphnkcnt = scrhdrp->cih_inomap_hnkcnt; + + /* read the map in from media + */ + nread = read_buf( 0, + sizeof( hnk_t ) * ( size_t )tmphnkcnt, + ( void * )drivep, + ( rfp_t )dop->do_read, + ( rrbfp_t )dop->do_return_read_buf, + &rval ); + /* check the return code from read + */ + switch( rval ) { + case 0: + ASSERT( ( size_t )nread == sizeof( hnk_t ) * ( size_t )hnkcnt ); + return RV_OK; + case DRIVE_ERROR_EOD: + case DRIVE_ERROR_EOF: + case DRIVE_ERROR_EOM: + case DRIVE_ERROR_MEDIA: + case DRIVE_ERROR_CORRUPTION: + return RV_CORRUPT; + case DRIVE_ERROR_DEVICE: + return RV_DRIVE; + case DRIVE_ERROR_CORE: + default: + return RV_CORE; + } +} + +bool_t +inomap_sync_pers( char *hkdir ) +{ + char *perspath; + pers_t *persp; + hnk_t *hnkp; + + /* sanity checks + */ + ASSERT( sizeof( hnk_t ) == HNKSZ ); + ASSERT( HNKSZ >= pgsz ); + ASSERT( ! ( HNKSZ % pgsz )); + + /* only needed once per session + */ + if ( pers_fd >= 0 ) { + return BOOL_TRUE; + } + + /* open the backing store. if not present, ok, hasn't been created yet + */ + perspath = open_pathalloc( hkdir, PERS_NAME, 0 ); + pers_fd = open( perspath, O_RDWR ); + if ( pers_fd < 0 ) { + return BOOL_TRUE; + } + + /* mmap the persistent hdr + */ + persp = ( pers_t * ) mmap_autogrow( + PERSSZ, + pers_fd, + ( off64_t )0 ); + if ( persp == ( pers_t * )-1 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "unable to map %s hdr: %s\n", + perspath, + strerror( errno )); + return BOOL_FALSE; + } + + /* read the pers hdr + */ + hnkcnt = persp->hnkcnt; + segcnt = persp->segcnt; + last_ino_added = persp->last_ino_added; + + /* mmap the pers inomap + */ + ASSERT( hnkcnt * sizeof( hnk_t ) <= ( size64_t )INT32MAX ); + roothnkp = ( hnk_t * ) mmap_autogrow( + sizeof( hnk_t ) * ( size_t )hnkcnt, + pers_fd, + ( off64_t )PERSSZ ); + if ( roothnkp == ( hnk_t * )-1 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "unable to map %s: %s\n", + perspath, + strerror( errno )); + return BOOL_FALSE; + } + + /* correct the next pointers + */ + for ( hnkp = roothnkp + ; + hnkp < roothnkp + ( intgen_t )hnkcnt - 1 + ; + hnkp++ ) { + hnkp->nextp = hnkp + 1; + } + hnkp->nextp = 0; + + /* calculate the tail pointers + */ + tailhnkp = hnkp; + ASSERT( hnkcnt > 0 ); + lastsegp = &tailhnkp->seg[ ( intgen_t )( segcnt + - + SEGPERHNK * ( hnkcnt - 1 ) + - + 1 ) ]; + + /* now all inomap operators will work + */ + return BOOL_TRUE; +} + +/* de-allocate the persistent inomap + */ +void +inomap_del_pers( char *hkdir ) +{ + char *perspath = open_pathalloc( hkdir, PERS_NAME, 0 ); + ( void )unlink( perspath ); + free( ( void * )perspath ); +} + +/* mark all included non-dirs as MAP_NDR_NOREST + */ +void +inomap_sanitize( void ) +{ + hnk_t *hnkp; + seg_t *segp; + + /* step through all hunks, segs, and inos + */ + for ( hnkp = roothnkp + ; + hnkp != 0 + ; + hnkp = hnkp->nextp ) { + for ( segp = hnkp->seg + ; + segp < hnkp->seg + SEGPERHNK + ; + segp++ ) { + xfs_ino_t ino; + if ( hnkp == tailhnkp && segp > lastsegp ) { + return; + } + for ( ino = segp->base + ; + ino < segp->base + INOPERSEG + ; + ino++ ) { + intgen_t state; + if ( ino > last_ino_added ) { + return; + } + SEG_GET_BITS( segp, ino, state ); + if ( state == MAP_NDR_CHANGE ) { + state = MAP_NDR_NOREST; + SEG_SET_BITS( segp, ino, state ); + } + } + } + } +} + +/* called to mark a non-dir ino as TO be restored + */ +void +inomap_rst_add( xfs_ino_t ino ) +{ + ASSERT( pers_fd >= 0 ); + ( void )map_set( ino, MAP_NDR_CHANGE ); +} + +/* called to mark a non-dir ino as NOT to be restored + */ +void +inomap_rst_del( xfs_ino_t ino ) +{ + ASSERT( pers_fd >= 0 ); + ( void )map_set( ino, MAP_NDR_NOREST ); +} + +/* called to ask if any inos in the given range need to be restored. + * range is inclusive + */ +bool_t +inomap_rst_needed( xfs_ino_t firstino, xfs_ino_t lastino ) +{ + hnk_t *hnkp; + seg_t *segp; + + /* if inomap not restored/resynced, just say yes + */ + if ( ! roothnkp ) { + return BOOL_TRUE; + } + + /* may be completely out of range + */ + if ( firstino > last_ino_added ) { + return BOOL_FALSE; + } + + /* find the hunk/seg containing first ino or any ino beyond + */ + for ( hnkp = roothnkp ; hnkp != 0 ; hnkp = hnkp->nextp ) { + if ( firstino > hnkp->maxino ) { + continue; + } + for ( segp = hnkp->seg; segp < hnkp->seg + SEGPERHNK ; segp++ ){ + if ( hnkp == tailhnkp && segp > lastsegp ) { + return BOOL_FALSE; + } + if ( firstino < segp->base + INOPERSEG ) { + goto begin; + } + } + } + return BOOL_FALSE; + +begin: + /* search until at least one ino is needed or until beyond last ino + */ + for ( ; ; ) { + xfs_ino_t ino; + + if ( segp->base > lastino ) { + return BOOL_FALSE; + } + for ( ino = segp->base ; ino < segp->base + INOPERSEG ; ino++ ){ + intgen_t state; + if ( ino < firstino ) { + continue; + } + if ( ino > lastino ) { + return BOOL_FALSE; + } + SEG_GET_BITS( segp, ino, state ); + if ( state == MAP_NDR_CHANGE ) { + return BOOL_TRUE; + } + } + segp++; + if ( hnkp == tailhnkp && segp > lastsegp ) { + return BOOL_FALSE; + } + if ( segp >= hnkp->seg + SEGPERHNK ) { + hnkp = hnkp->nextp; + if ( ! hnkp ) { + return BOOL_FALSE; + } + segp = hnkp->seg; + } + } + /* NOTREACHED */ +} + +/* calls the callback for all inos with an inomap state included + * in the state mask. stops iteration when inos exhaused or cb + * returns FALSE. + */ +void +inomap_cbiter( intgen_t statemask, + bool_t ( * cbfunc )( void *ctxp, xfs_ino_t ino ), + void *ctxp ) +{ + hnk_t *hnkp; + seg_t *segp; + + /* step through all hunks, segs, and inos + */ + for ( hnkp = roothnkp + ; + hnkp != 0 + ; + hnkp = hnkp->nextp ) { + for ( segp = hnkp->seg + ; + segp < hnkp->seg + SEGPERHNK + ; + segp++ ) { + xfs_ino_t ino; + if ( hnkp == tailhnkp && segp > lastsegp ) { + return; + } + for ( ino = segp->base + ; + ino < segp->base + INOPERSEG + ; + ino++ ) { + intgen_t state; + if ( ino > last_ino_added ) { + return; + } + SEG_GET_BITS( segp, ino, state ); + if ( statemask & ( 1 << state )) { + bool_t ok; + ok = ( cbfunc )( ctxp, ino ); + if ( ! ok ) { + return; + } + } + } + } + } +} + +/* definition of locally defined static functions ****************************/ + +/* map_getset - locates and gets the state of the specified ino, + * and optionally sets the state to a new value. + */ +static intgen_t +map_getset( xfs_ino_t ino, intgen_t newstate, bool_t setflag ) +{ + hnk_t *hnkp; + seg_t *segp; + + if ( ino > last_ino_added ) { + return MAP_INO_UNUSED; + } + for ( hnkp = roothnkp ; hnkp != 0 ; hnkp = hnkp->nextp ) { + if ( ino > hnkp->maxino ) { + continue; + } + for ( segp = hnkp->seg; segp < hnkp->seg + SEGPERHNK ; segp++ ){ + if ( hnkp == tailhnkp && segp > lastsegp ) { + return MAP_INO_UNUSED; + } + if ( ino < segp->base ) { + return MAP_INO_UNUSED; + } + if ( ino < segp->base + INOPERSEG ) { + intgen_t state; + SEG_GET_BITS( segp, ino, state ); + if ( setflag ) { + SEG_SET_BITS( segp, ino, newstate ); + } + return state; + } + } + return MAP_INO_UNUSED; + } + return MAP_INO_UNUSED; +} + +static intgen_t +map_set( xfs_ino_t ino, intgen_t state ) +{ + intgen_t oldstate; + + oldstate = map_getset( ino, state, BOOL_TRUE ); + return oldstate; +} diff -rNu linux-2.4.7/cmd/xfsdump/restore/inomap.h linux-2.4-xfs/cmd/xfsdump/restore/inomap.h --- linux-2.4.7/cmd/xfsdump/restore/inomap.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/inomap.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef INOMAP_H +#define INOMAP_H + +/* inomap.[hc] - inode map abstraction + * + * an inode map describes the inode numbers (inos) in a file system dump. + * the map identifies which inos are in-use by the fs, which of those are + * directories, and which are dumped. + * + * the map is represented as a list of map segments. a map segment is + * a 64-bit starting ino and two 64-bit bitmaps. the bitmaps describe + * the 64 inos beginning with the starting ino. two bits are available + * for each ino. + */ + +/* map state values + */ +#define MAP_INO_UNUSED 0 /* ino not in use by fs */ +#define MAP_DIR_NOCHNG 1 /* dir, ino in use by fs, but not dumped */ +#define MAP_NDR_NOCHNG 2 /* non-dir, ino in use by fs, but not dumped */ +#define MAP_DIR_CHANGE 3 /* dir, changed since last dump */ +#define MAP_NDR_CHANGE 4 /* non-dir, changed since last dump */ +#define MAP_DIR_SUPPRT 5 /* dir, unchanged but needed for hierarchy */ +#define MAP_NDR_NOREST 6 /* was MAP_NDR_CHANGE, but not to be restored */ +#define MAP_RESERVED2 7 /* this state currently not used */ + + +/* map context and operators + */ + +/* the inomap is implemented as a linked list of chunks. each chunk contains + * an array of map segments. a map segment contains a start ino and a + * bitmap of 64 3-bit state values (see MAP_... in inomap.h). the SEG_macros + * index and manipulate the 3-bit state values. + */ +struct seg { + xfs_ino_t base; + u_int64_t lobits; + u_int64_t mebits; + u_int64_t hibits; +}; + +typedef struct seg seg_t; + +#define SEG_SET_BASE( segp, ino ) \ + { \ + segp->base = ino; \ + } + +#define SEG_ADD_BITS( segp, ino, state ) \ + { \ + register xfs_ino_t relino; \ + relino = ino - segp->base; \ + segp->lobits |= ( u_int64_t )( ( state >> 0 ) & 1 ) << relino; \ + segp->mebits |= ( u_int64_t )( ( state >> 1 ) & 1 ) << relino; \ + segp->hibits |= ( u_int64_t )( ( state >> 2 ) & 1 ) << relino; \ + } + +#define SEG_SET_BITS( segp, ino, state ) \ + { \ + register xfs_ino_t relino; \ + register u_int64_t clrmask; \ + relino = ino - segp->base; \ + clrmask = ~( ( u_int64_t )1 << relino ); \ + segp->lobits &= clrmask; \ + segp->mebits &= clrmask; \ + segp->hibits &= clrmask; \ + segp->lobits |= ( u_int64_t )( ( state >> 0 ) & 1 ) << relino; \ + segp->mebits |= ( u_int64_t )( ( state >> 1 ) & 1 ) << relino; \ + segp->hibits |= ( u_int64_t )( ( state >> 2 ) & 1 ) << relino; \ + } + +#define SEG_GET_BITS( segp, ino, state ) \ + { \ + register xfs_ino_t relino; \ + relino = ino - segp->base; \ + state = 0; \ + state |= ( intgen_t )((( segp->lobits >> relino ) & 1 ) * 1 );\ + state |= ( intgen_t )((( segp->mebits >> relino ) & 1 ) * 2 );\ + state |= ( intgen_t )((( segp->hibits >> relino ) & 1 ) * 4 );\ + } + +#define INOPERSEG ( sizeofmember( seg_t, lobits ) * NBBY ) + +#define HNKSZ ( 4 * PGSZ ) +#define SEGPERHNK ( ( HNKSZ / sizeof( seg_t )) - 1 ) + +struct hnk { + seg_t seg[ SEGPERHNK ]; + xfs_ino_t maxino; + struct hnk *nextp; + char pad[sizeof( seg_t ) - sizeof( xfs_ino_t ) - sizeof( struct hnk * )]; +}; + +typedef struct hnk hnk_t; + + +extern bool_t inomap_sync_pers( char *hkdir ); +extern rv_t inomap_restore_pers( drive_t *drivep, + content_inode_hdr_t *scrhdrp, + char *hkdir ); +extern void inomap_del_pers( char *hkdir ); +extern void inomap_sanitize( void ); +extern bool_t inomap_rst_needed( xfs_ino_t begino, xfs_ino_t endino ); +extern void inomap_rst_add( xfs_ino_t ino ); +extern void inomap_rst_del( xfs_ino_t ino ); +extern rv_t inomap_discard( drive_t *drivep, content_inode_hdr_t *scrhdrp ); +extern void inomap_cbiter( intgen_t mapstatemask, + bool_t ( * cbfunc )( void *ctxp, xfs_ino_t ino ), + void *ctxp ); + +#endif /* INOMAP_H */ diff -rNu linux-2.4.7/cmd/xfsdump/restore/mmap.c linux-2.4-xfs/cmd/xfsdump/restore/mmap.c --- linux-2.4.7/cmd/xfsdump/restore/mmap.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/mmap.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +/* + * our custom mmap b/c Linux doesn't have MAP_AUTOGROW + * and for an empty file we need to write to last byte + * to ensure it can be accessed + */ + +void * +mmap_autogrow(size_t len, int fd, off_t offset) +{ + struct stat buf; + char nul_buffer[] = ""; + + /* prealloc file if it is an empty file */ + if (fstat(fd, &buf) == -1) {; + return (void*)MAP_FAILED; + } + if (buf.st_size < offset+len) { + (void)lseek(fd, offset+len-1, SEEK_SET); + (void)write(fd, nul_buffer, 1); + } + + return mmap( 0, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset ); +} diff -rNu linux-2.4.7/cmd/xfsdump/restore/mmap.h linux-2.4-xfs/cmd/xfsdump/restore/mmap.h --- linux-2.4.7/cmd/xfsdump/restore/mmap.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/mmap.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef MMAP_H +#define MMAP_H + +void *mmap_autogrow(size_t len, int fd, off_t offset); + +#endif diff -rNu linux-2.4.7/cmd/xfsdump/restore/namreg.c linux-2.4-xfs/cmd/xfsdump/restore/namreg.c --- linux-2.4.7/cmd/xfsdump/restore/namreg.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/namreg.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "types.h" +#include "lock.h" +#include "mlog.h" +#include "namreg.h" +#include "openutil.h" +#include "mmap.h" + +/* structure definitions used locally ****************************************/ + +#define max( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) + +#define NAMREG_AVGLEN 10 + +/* persistent context for a namreg - placed in first page + * of the namreg file by namreg_init if not a sync + */ +struct namreg_pers { + off64_t np_appendoff; +}; + +typedef struct namreg_pers namreg_pers_t; + +#define NAMREG_PERS_SZ pgsz + +/* transient context for a namreg - allocated by namreg_init() + */ +struct namreg_tran { + char *nt_pathname; + int nt_fd; + bool_t nt_at_endpr; +}; + +typedef struct namreg_tran namreg_tran_t; + + +#ifdef NAMREGCHK + +/* macros for manipulating namreg handles when handle consistency + * checking is enabled. + */ +#define CHKBITCNT 2 +#define CHKBITSHIFT ( NBBY * sizeof( nrh_t ) - CHKBITCNT ) +#define CHKBITLOMASK ( ( 1 << CHKBITCNT ) - 1 ) +#define CHKBITMASK ( CHKBITLOMASK << CHKBITSHIFT ) +#define CHKHDLCNT CHKBITSHIFT +#define CHKHDLMASK ( ( 1 << CHKHDLCNT ) - 1 ) +#define CHKGETBIT( h ) ( ( h >> CHKBITSHIFT ) & CHKBITLOMASK ) +#define CHKGETHDL( h ) ( h & CHKHDLMASK ) +#define CHKMKHDL( c, h ) ( ( ( c << CHKBITSHIFT ) & CHKBITMASK ) \ + | \ + ( h & CHKHDLMASK )) +#define HDLMAX ( ( off64_t )CHKHDLMASK ) + +#else /* NAMREGCHK */ + +#define HDLMAX ( ( ( off64_t )1 \ + << \ + ( ( off64_t )NBBY \ + * \ + ( off64_t )sizeof( nrh_t ))) \ + - \ + ( off64_t )2 ) /* 2 to avoid NRH_NULL */ + +#endif /* NAMREGCHK */ + + +/* declarations of externally defined global symbols *************************/ + +extern size_t pgsz; + +/* forward declarations of locally defined static functions ******************/ + + +/* definition of locally defined global variables ****************************/ + + +/* definition of locally defined static variables *****************************/ + +static char *namregfile = "namreg"; +static namreg_tran_t *ntp = 0; +static namreg_pers_t *npp = 0; + + +/* definition of locally defined global functions ****************************/ + +bool_t +namreg_init( char *hkdir, bool_t resume, u_int64_t inocnt ) +{ +#ifdef SESSCPLT + if ( ntp ) { + return BOOL_TRUE; + } +#endif /* SESSCPLT */ + + /* sanity checks + */ + ASSERT( ! ntp ); + ASSERT( ! npp ); + + ASSERT( sizeof( namreg_pers_t ) <= NAMREG_PERS_SZ ); + + /* allocate and initialize context + */ + ntp = ( namreg_tran_t * )calloc( 1, sizeof( namreg_tran_t )); + ASSERT( ntp ); + + /* generate a string containing the pathname of the namreg file + */ + ntp->nt_pathname = open_pathalloc( hkdir, namregfile, 0 ); + + /* open the namreg file + */ + if ( resume ) { + /* open existing file + */ + ntp->nt_fd = open( ntp->nt_pathname, O_RDWR ); + if ( ntp->nt_fd < 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "could not find name registry file %s: " + "%s\n", + ntp->nt_pathname, + strerror( errno )); + return BOOL_FALSE; + } + } else { + /* create the namreg file, first unlinking any older version + * laying around + */ + ( void )unlink( ntp->nt_pathname ); + ntp->nt_fd = open( ntp->nt_pathname, + O_RDWR | O_CREAT | O_EXCL, + S_IRUSR | S_IWUSR ); + if ( ntp->nt_fd < 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "could not create name registry file %s: " + "%s\n", + ntp->nt_pathname, + strerror( errno )); + return BOOL_FALSE; + } + + /* reserve space for the backing store. try to use F_RESVSP64. + * if doesn't work, try F_RESVSP64. the former is faster, since + * it does not zero the space. + */ + { + bool_t successpr; + intgen_t ioctlcmd; + intgen_t loglevel; + size_t trycnt; + +#ifndef F_RESVSP64 +#define F_RESVSP64 0 +#endif /* F_RESVSP64 */ + + for ( trycnt = 0, + successpr = BOOL_FALSE, + ioctlcmd = XFS_IOC_RESVSP64, + loglevel = MLOG_VERBOSE + ; + ! successpr && trycnt < 2 + ; + trycnt++, + ioctlcmd = XFS_IOC_ALLOCSP64, + loglevel = max( MLOG_NORMAL, loglevel - 1 )) { + off64_t initsz; + struct flock64 flock64; + intgen_t rval; + + if ( ! ioctlcmd ) { + continue; + } + + initsz = ( off64_t )NAMREG_PERS_SZ + + + ( ( off64_t )inocnt * NAMREG_AVGLEN ); + flock64.l_whence = 0; + flock64.l_start = 0; + flock64.l_len = initsz; + rval = ioctl( ntp->nt_fd, ioctlcmd, &flock64 ); + if ( rval ) { + mlog( loglevel | MLOG_NOTE, + "attempt to reserve %lld bytes for %s " + "using %s " + "failed: %s (%d)\n", + initsz, + ntp->nt_pathname, + ioctlcmd == F_RESVSP64 + ? + "F_RESVSP64" + : + "F_ALLOCSP64", + strerror( errno ), + errno ); + } else { + successpr = BOOL_TRUE; + } + } + } + } + + /* mmap the persistent descriptor + */ + ASSERT( ! ( NAMREG_PERS_SZ % pgsz )); + npp = ( namreg_pers_t * ) mmap_autogrow( + NAMREG_PERS_SZ, + ntp->nt_fd, + ( off_t )0 ); + if ( npp == ( namreg_pers_t * )-1 ) { + mlog( MLOG_NORMAL | MLOG_ERROR, + "unable to map %s: %s\n", + ntp->nt_pathname, + strerror( errno )); + return BOOL_FALSE; + } + + /* initialize persistent state + */ + if ( ! resume ) { + npp->np_appendoff = ( off64_t )NAMREG_PERS_SZ; + } + + /* initialize transient state + */ + ntp->nt_at_endpr = BOOL_FALSE; + + return BOOL_TRUE; +} + +nrh_t +namreg_add( char *name, size_t namelen ) +{ + off64_t oldoff; + intgen_t nwritten; + unsigned char c; + nrh_t nrh; + + /* sanity checks + */ + ASSERT( ntp ); + ASSERT( npp ); + + /* make sure file pointer is positioned to append + */ + if ( ! ntp->nt_at_endpr ) { + off64_t newoff; + newoff = lseek64( ntp->nt_fd, npp->np_appendoff, SEEK_SET ); + if ( newoff == ( off64_t )-1 ) { + mlog( MLOG_NORMAL, + "lseek of namreg failed: %s\n", + strerror( errno )); + ASSERT( 0 ); + return NRH_NULL; + } + ASSERT( npp->np_appendoff == newoff ); + ntp->nt_at_endpr = BOOL_TRUE; + } + + /* save the current offset + */ + oldoff = npp->np_appendoff; + + /* write a one byte unsigned string length + */ + ASSERT( namelen < 256 ); + c = ( unsigned char )( namelen & 0xff ); + nwritten = write( ntp->nt_fd, ( void * )&c, 1 ); + if ( nwritten != 1 ) { + mlog( MLOG_NORMAL, + "write of namreg failed: %s\n", + strerror( errno )); + ASSERT( 0 ); + return NRH_NULL; + } + + /* write the name string + */ + nwritten = write( ntp->nt_fd, ( void * )name, namelen ); + if ( ( size_t )nwritten != namelen ) { + mlog( MLOG_NORMAL, + "write of namreg failed: %s\n", + strerror( errno )); + ASSERT( 0 ); + return NRH_NULL; + } + + npp->np_appendoff += ( off64_t )( 1 + namelen ); + ASSERT( oldoff <= HDLMAX ); + +#ifdef NAMREGCHK + + /* encode the lsb of the len plus the first character into the handle. + */ + nrh = CHKMKHDL( ( nrh_t )namelen + ( nrh_t )*name, ( nrh_t )oldoff ); + +#else /* NAMREGCHK */ + + nrh = ( nrh_t )oldoff; + +#endif /* NAMREGCHK */ + + return nrh; +} + +/* ARGSUSED */ +void +namreg_del( nrh_t nrh ) +{ + /* currently not implemented - grows, never shrinks + */ +} + +intgen_t +namreg_get( nrh_t nrh, + char *bufp, + size_t bufsz ) +{ + off64_t newoff; + intgen_t nread; + size_t len; + unsigned char c; +#ifdef NAMREGCHK + nrh_t chkbit; +#endif /* NAMREGCHK */ + + /* sanity checks + */ + ASSERT( ntp ); + ASSERT( npp ); + + /* make sure we aren't being given a NULL handle + */ + ASSERT( nrh != NRH_NULL ); + + /* convert the handle into the offset + */ +#ifdef NAMREGCHK + + newoff = ( off64_t )( size64_t )CHKGETHDL( nrh ); + chkbit = CHKGETBIT( nrh ); + +#else /* NAMREGCHK */ + + newoff = ( off64_t )( size64_t )nrh; + +#endif /* NAMREGCHK */ + + /* do sanity check on offset + */ + ASSERT( newoff <= HDLMAX ); + ASSERT( newoff < npp->np_appendoff ); + ASSERT( newoff >= ( off64_t )NAMREG_PERS_SZ ); + + lock( ); + + /* seek to the name + */ + newoff = lseek64( ntp->nt_fd, newoff, SEEK_SET ); + if ( newoff == ( off64_t )-1 ) { + unlock( ); + mlog( MLOG_NORMAL, + "lseek of namreg failed: %s\n", + strerror( errno )); + return -3; + } + + /* read the name length + */ + c = 0; /* unnecessary, but keeps lint happy */ + nread = read( ntp->nt_fd, ( void * )&c, 1 ); + if ( nread != 1 ) { + unlock( ); + mlog( MLOG_NORMAL, + "read of namreg failed: %s (nread = %d)\n", + strerror( errno ), + nread ); + return -3; + } + + /* deal with a short caller-supplied buffer + */ + len = ( size_t )c; + if ( bufsz < len + 1 ) { + unlock( ); + return -1; + } + + /* read the name + */ + nread = read( ntp->nt_fd, ( void * )bufp, len ); + if ( ( size_t )nread != len ) { + unlock( ); + mlog( MLOG_NORMAL, + "read of namreg failed: %s\n", + strerror( errno )); + return -3; + } + +#ifdef NAMREGCHK + + /* validate the checkbit + */ + ASSERT( chkbit + == + ( ( ( nrh_t )len + ( nrh_t )bufp[ 0 ] ) & CHKBITLOMASK )); + +#endif /* NAMREGCHK */ + + /* null-terminate the string if room + */ + bufp[ len ] = 0; + + ntp->nt_at_endpr = BOOL_FALSE; + + unlock( ); + + return ( intgen_t )len; +} + + +/* definition of locally defined static functions ****************************/ diff -rNu linux-2.4.7/cmd/xfsdump/restore/namreg.h linux-2.4-xfs/cmd/xfsdump/restore/namreg.h --- linux-2.4.7/cmd/xfsdump/restore/namreg.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/namreg.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef NAMREG_H +#define NAMREG_H + +/* namreg.[hc] - directory entry registry + * + * provides unique directory entry ID's and storage for the entry + * name. + */ + +/* nrh_t - handle to a registered name + */ +typedef size32_t nrh_t; +#define NRH_NULL SIZE32MAX + + +/* namreg_init - creates the name registry. resync is TRUE if the + * registry should already exist, and we are resynchronizing. + * if NOT resync, inocnt hints at how many names will be held + */ +extern bool_t namreg_init( char *housekeepingdir, + bool_t resync, + u_int64_t inocnt ); + + +/* namreg_add - registers a name. name does not need to be null-terminated. + * returns handle for use with namreg_get(). + */ +extern nrh_t namreg_add( char *name, size_t namelen ); + + +/* namreg_del - remove a name from the registry + */ +extern void namreg_del( nrh_t nrh ); + + +/* namreg_get - retrieves the name identified by the index. + * fills the buffer with the null-terminated name from the registry. + * returns the strlen() of the name. returns -1 if the buffer is too + * small to fit the null-terminated name. return -2 if the name + * not in the registry. return -3 if a system call fails. + */ +extern intgen_t namreg_get( nrh_t nrh, char *bufp, size_t bufsz ); + +#endif /* NAMREG_H */ diff -rNu linux-2.4.7/cmd/xfsdump/restore/node.c linux-2.4-xfs/cmd/xfsdump/restore/node.c --- linux-2.4.7/cmd/xfsdump/restore/node.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/node.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,671 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include + +#include "types.h" +#include "mlog.h" +#include "win.h" +#include "node.h" +#include "mmap.h" + +#define min( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) + +extern size_t pgsz; +extern size_t pgmask; + +/* node handle limits + */ +#ifdef NODECHK + +/* macros for manipulating node handles when handle consistency + * checking is enabled. the upper bits of a handle will be loaded + * with the node gen count, described below. + */ +#define HDLGENCNT 4 +#define HDLGENSHIFT ( NBBY * sizeof ( nh_t ) - HDLGENCNT ) +#define HDLGENLOMASK ( ( 1 << HDLGENCNT ) - 1 ) +#define HDLGENMASK ( HDLGENLOMASK << HDLGENSHIFT ) +#define HDLNIXCNT HDLGENSHIFT +#define HDLNIXMASK ( ( 1 << HDLNIXCNT ) - 1 ) +#define HDLGETGEN( h ) ( ( u_char_t ) \ + ( ( ( int )h >> HDLGENSHIFT ) \ + & \ + HDLGENLOMASK )) +#define HDLGETNIX( h ) ( ( nix_t )( ( int )h & HDLNIXMASK )) +#define HDLMKHDL( g, n ) ( ( nh_t )( ( ( ( int )g << HDLGENSHIFT )\ + & \ + HDLGENMASK ) \ + | \ + ( ( int )n & HDLNIXMASK ))) +#define NIX_MAX ( ( off64_t )HDLNIXMASK ) + +/* the housekeeping byte of each node will hold two check fields: + * a gen count, initialized to the node ix and incremented each time a node + * is allocated, to catch re-use of stale handles; and unique pattern, to + * differentiate a valid node from random memory. two unique patterns will + * be used; one when the node is on the free list, another when it is + * allocated. this allows me to detect use of handles to nodes which have + * be freed. + */ +#define HKPGENCNT HDLGENCNT +#define HKPGENSHIFT ( NBBY - HKPGENCNT ) +#define HKPGENLOMASK ( ( 1 << HKPGENCNT ) - 1 ) +#define HKPGENMASK ( HKPGENLOMASK << HKPGENSHIFT ) +#define HKPUNQCNT ( NBBY - HKPGENCNT ) +#define HKPUNQMASK ( ( 1 << HKPUNQCNT ) - 1 ) +#define HKPGETGEN( b ) ( ( u_char_t ) \ + ( ( ( int )b >> HKPGENSHIFT ) \ + & \ + HKPGENLOMASK )) +#define HKPGETUNQ( b ) ( ( u_char_t )( ( int )b & HKPUNQMASK )) +#define HKPMKHKP( g, u ) ( ( u_char_t ) \ + ( ( ( ( int )g << HKPGENSHIFT ) \ + & \ + HKPGENMASK ) \ + | \ + ( ( int )u & HKPUNQMASK ))) + +/* simple patterns for detecting a node + */ +#define NODEUNQFREE 0x9 +#define NODEUNQALCD 0x6 + +#else /* NODECHK */ + +#define NIX_MAX ( ( ( off64_t )1 \ + << \ + ( ( off64_t )NBBY \ + * \ + ( off64_t )sizeof( nh_t ))) \ + - \ + ( off64_t )2 ) /* 2 to avoid NH_NULL */ + +#endif /* NODECHK */ + +/* window constraints + */ +#define NODESPERSEGMIN 1000000 +#define NODESPERSEGMAX 2000000 +#define SEGSZMIN 40000000 +#define SEGSZMAX 80000000 + +/* how many nodes to place on free list at a time + */ +#define VIRGSACRMAX 8192 /* fudged: 8192 40 byte nodes (20 or 80 pages) */ + +/* a node is identified internally by its index into the backing store. + * this index is the offset of the node into the segmented portion of + * backing store (follows the abstraction header page) divided by the + * size of a node. a special index is reserved to represent the null + * index. a type is defined for node index (nix_t). it is a 64 bit + * unsigned to facilitate conversion from index to 64 bit offset. + */ +typedef off64_t nix_t; +#define NIX_NULL OFF64MAX +#define NIX2OFF( nix ) ( nix * ( nix_t )node_hdrp->nh_nodesz ) +#define OFF2NIX( noff ) ( noff / ( nix_t )node_hdrp->nh_nodesz ) + +/* reserve the firstpage for a header to save persistent context + */ +#define NODE_HDRSZ pgsz + +struct node_hdr { + size_t nh_nodesz; + /* internal node size - user may see something smaller + */ + ix_t nh_nodehkix; + /* index of byte in each node the user has reserved + * for use by me + */ + size_t nh_nodesperseg; + /* an integral number of internal nodes must fit into a + * segment + */ + size_t nh_segsz; + /* the backing store is partitoned into segment, which + * can be mapped into VM windows by the win abstraction + */ + size_t nh_winmapmax; + /* maximum number of windows which can be mapped + */ + size_t nh_nodealignsz; + /* user's constraint on node alignment + */ + nix_t nh_freenix; + /* index into backing store of first node of singly-linked + * list of free nodes + */ + off64_t nh_firstsegoff; + /* offset into backing store of the first segment + */ + off64_t nh_virgsegreloff; + /* offset (relative to beginning of first segment) into + * backing store of segment containing one or + * more virgin nodes. relative to beginning of segmented + * portion of backing store. bumped only when all of the + * nodes in the segment have been placed on the free list. + * when bumped, nh_virginrelnix is simultaneously set back + * to zero. + */ + nix_t nh_virgrelnix; + /* relative node index within the segment identified by + * nh_virgsegreloff of the next node not yet placed on the + * free list. never reaches nh_nodesperseg: instead set + * to zero and bump nh_virgsegreloff by one segment. + */ +}; + +typedef struct node_hdr node_hdr_t; + +static node_hdr_t *node_hdrp; +static intgen_t node_fd; + +/* ARGSUSED */ +bool_t +node_init( intgen_t fd, + off64_t off, + size_t usrnodesz, + ix_t nodehkix, + size_t nodealignsz, + size64_t vmsz, + size64_t mincnt ) +{ + size_t nodesz; + size_t segsz; + size_t nodesperseg; + size_t winmapmax; + intgen_t rval; + + /* sanity checks + */ + ASSERT( sizeof( node_hdr_t ) <= NODE_HDRSZ ); + ASSERT( sizeof( nh_t ) < sizeof( off64_t )); + ASSERT( nodehkix < usrnodesz ); + ASSERT( usrnodesz >= sizeof( char * ) + 1 ); + /* so node is at least big enough to hold + * the free list linkage and the housekeeping byte + */ + ASSERT( nodehkix > sizeof( char * )); + /* since beginning of each node is used to + * link it in the free list. + */ + + /* adjust the user's node size to meet user's alignment constraint + */ + nodesz = ( usrnodesz + nodealignsz - 1 ) & ~( nodealignsz - 1 ); + + /* calculate the segment size, based on the constraints defined + * at the top of this file. the segment size must be an + * integral multiple of pgsz. + */ + for ( nodesperseg = NODESPERSEGMIN, segsz = nodesz * nodesperseg + ; + ( segsz & pgmask ) + || + segsz < SEGSZMIN + || + nodesperseg < NODESPERSEGMIN + ; + nodesperseg++, segsz += nodesz ) { + ASSERT( nodesperseg <= NODESPERSEGMAX ); + ASSERT( segsz <= SEGSZMAX ); + } + ASSERT( ! ( segsz % pgsz )); + + /* calculate the maximum number of windows which may be mapped. + * base on vmsz, which is this abstraction's share of VM. + */ + if ( vmsz > ( size64_t )SIZEMAX ) { + vmsz = ( size64_t )SIZEMAX; /* be reasonable! */ + } + winmapmax = ( size_t )vmsz / segsz; + ASSERT( winmapmax > 0 ); + + /* map the abstraction header + */ + ASSERT( ( NODE_HDRSZ & pgmask ) == 0 ); + ASSERT( ! ( NODE_HDRSZ % pgsz )); + ASSERT( off <= OFF64MAX ); + ASSERT( ! ( off % ( off64_t )pgsz )); + node_hdrp = ( node_hdr_t * )mmap_autogrow( + NODE_HDRSZ, + fd, + off ); + ASSERT( node_hdrp ); + ASSERT( node_hdrp != ( node_hdr_t * )( -1 )); + ASSERT( ( size64_t )segsz <= OFF64MAX ); + /* avoid sign extention questions */ + + /* initialize and save persistent context. + */ + node_hdrp->nh_nodesz = nodesz; + node_hdrp->nh_nodehkix = nodehkix; + node_hdrp->nh_segsz = segsz; + node_hdrp->nh_winmapmax = winmapmax; + node_hdrp->nh_nodesperseg = nodesperseg; + node_hdrp->nh_nodealignsz = nodealignsz; + node_hdrp->nh_freenix = NIX_NULL; + node_hdrp->nh_firstsegoff = off + ( off64_t )NODE_HDRSZ; + node_hdrp->nh_virgsegreloff = 0; + node_hdrp->nh_virgrelnix = 0; + + /* save transient context + */ + node_fd = fd; + + /* autogrow the first segment + */ + mlog( MLOG_DEBUG, + "pre-growing new node array segment at %lld " + "size %lld\n", + node_hdrp->nh_firstsegoff, + ( off64_t )node_hdrp->nh_segsz ); + rval = ftruncate64( node_fd, + node_hdrp->nh_firstsegoff + + + ( off64_t )node_hdrp->nh_segsz ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_TREE, + "unable to autogrow first node segment: %s (%d)\n", + strerror( errno ), + errno ); + return BOOL_FALSE; + } + + /* initialize the window abstraction + */ + win_init( fd, + node_hdrp->nh_firstsegoff, + segsz, + winmapmax ); + + /* announce the results + */ + mlog( MLOG_DEBUG | MLOG_TREE, + "node_init:" + " usrnodesz = %u (0x%x)" + " nodesz = %u (0x%x)" + " segsz = %u (0x%x)" + " nodesperseg = %u (0x%x)" + " winmapmax = %u (0x%x)" + "\n", + usrnodesz, + usrnodesz, + nodesz, + nodesz, + segsz, + segsz, + nodesperseg, + nodesperseg, + winmapmax, + winmapmax ); + + return BOOL_TRUE; +} + +bool_t +node_sync( intgen_t fd, off64_t off ) +{ + /* sanity checks + */ + ASSERT( sizeof( node_hdr_t ) <= NODE_HDRSZ ); + + /* map the abstraction header + */ + ASSERT( ( NODE_HDRSZ & pgmask ) == 0 ); + ASSERT( off <= ( off64_t )OFF64MAX ); + ASSERT( ! ( off % ( off64_t )pgsz )); + node_hdrp = ( node_hdr_t * )mmap_autogrow( + NODE_HDRSZ, + fd, + off ); + ASSERT( node_hdrp ); + ASSERT( node_hdrp != ( node_hdr_t * )( -1 )); + + /* save transient context + */ + node_fd = fd; + + /* initialize the window abstraction + */ + win_init( fd, + node_hdrp->nh_firstsegoff, + node_hdrp->nh_segsz, + node_hdrp->nh_winmapmax ); + + return BOOL_TRUE; +} + +nh_t +node_alloc( void ) +{ + nix_t nix; + u_char_t *p; + nh_t nh; + register nix_t *linkagep; +#ifdef NODECHK + register u_char_t *hkpp; + register u_char_t gen; + register u_char_t unq; +#endif /* NODECHK */ + + /* if free list is depleted, map in a new window at the + * end of backing store. put all nodes on free list. + * initialize the gen count to the node index, and the unique + * pattern to the free pattern. + */ + if ( node_hdrp->nh_freenix == NIX_NULL ) { + nix_t virgbegnix; /* abs. nix of first node in virg seg */ + nix_t virgendnix; /* abs. nix of next node after last */ + nix_t sacrcnt; /* how many virgins to put on free list */ + nix_t sacrnix; + + ASSERT( node_hdrp->nh_virgrelnix + < + ( nix_t )node_hdrp->nh_nodesperseg ); + virgbegnix = OFF2NIX( node_hdrp->nh_virgsegreloff ) + + + node_hdrp->nh_virgrelnix; + virgendnix = + OFF2NIX( ( node_hdrp->nh_virgsegreloff + + + ( off64_t )node_hdrp->nh_segsz ) ); + ASSERT( virgendnix > virgbegnix ); + sacrcnt = min( VIRGSACRMAX, virgendnix - virgbegnix ); + ASSERT( sacrcnt >= 1 ); + p = 0; /* keep lint happy */ + win_map( NIX2OFF( virgbegnix ), ( void ** )&p ); + ASSERT( p ); + node_hdrp->nh_freenix = virgbegnix; + for ( sacrnix = virgbegnix + ; + sacrnix < virgbegnix + sacrcnt - 1 + ; + p += node_hdrp->nh_nodesz, sacrnix++ ) { + linkagep = ( nix_t * )p; + *linkagep = sacrnix + 1; +#ifdef NODECHK + hkpp = p + node_hdrp->nh_nodehkix; + gen = ( u_char_t )sacrnix; + *hkpp = ( u_char_t )HKPMKHKP( ( size_t )gen, + NODEUNQFREE ); +#endif /* NODECHK */ + } + linkagep = ( nix_t * )p; + *linkagep = NIX_NULL; +#ifdef NODECHK + hkpp = p + node_hdrp->nh_nodehkix; + gen = ( u_char_t )sacrnix; + *hkpp = HKPMKHKP( gen, NODEUNQFREE ); +#endif /* NODECHK */ + node_hdrp->nh_virgrelnix += sacrcnt; + win_unmap( node_hdrp->nh_virgsegreloff, ( void ** )&p ); + + if ( node_hdrp->nh_virgrelnix + >= + ( nix_t )node_hdrp->nh_nodesperseg ) { + intgen_t rval; + ASSERT( node_hdrp->nh_virgrelnix + == + ( nix_t )node_hdrp->nh_nodesperseg ); + ASSERT( node_hdrp->nh_virgsegreloff + <= + OFF64MAX - ( off64_t )node_hdrp->nh_segsz ); + node_hdrp->nh_virgsegreloff += + ( off64_t )node_hdrp->nh_segsz; + node_hdrp->nh_virgrelnix = 0; + mlog( MLOG_DEBUG, + "pre-growing new node array segment at %lld " + "size %lld\n", + node_hdrp->nh_firstsegoff + + + node_hdrp->nh_virgsegreloff + + + ( off64_t )node_hdrp->nh_segsz, + ( off64_t )node_hdrp->nh_segsz ); + rval = ftruncate64( node_fd, + node_hdrp->nh_firstsegoff + + + node_hdrp->nh_virgsegreloff + + + ( off64_t )node_hdrp->nh_segsz ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "unable to autogrow node segment %llu: " + "%s (%d)\n", + node_hdrp->nh_virgsegreloff + / + ( off64_t )node_hdrp->nh_segsz, + strerror( errno ), + errno ); + } + } + } + + /* map in window containing node at top of free list, + * and adjust free list. + */ + nix = node_hdrp->nh_freenix; + win_map( NIX2OFF( nix ), ( void ** )&p ); + ASSERT( p ); +#ifdef NODECHK + hkpp = p + node_hdrp->nh_nodehkix; + unq = HKPGETUNQ( *hkpp ); + ASSERT( unq != NODEUNQALCD ); + ASSERT( unq == NODEUNQFREE ); +#endif /* NODECHK */ + linkagep = ( nix_t * )p; + node_hdrp->nh_freenix = *linkagep; + + /* clean the node + */ + memset( ( void * )p, 0, node_hdrp->nh_nodesz ); + + /* build a handle for node + */ + ASSERT( nix <= NIX_MAX ); +#ifdef NODECHK + hkpp = p + ( int )node_hdrp->nh_nodehkix; + gen = ( u_char_t )( HKPGETGEN( *p ) + ( u_char_t )1 ); + nh = HDLMKHDL( gen, nix ); + *hkpp = HKPMKHKP( gen, NODEUNQALCD ); +#else /* NODECHK */ + nh = ( nh_t )nix; +#endif /* NODECHK */ + + /* unmap window + */ + win_unmap( NIX2OFF( nix ), ( void ** )&p ); + + return nh; +} + +void * +node_map( nh_t nh ) +{ + nix_t nix; + u_char_t *p; +#ifdef NODECHK + register u_char_t hkp; + register u_char_t hdlgen; + register u_char_t nodegen; + register u_char_t nodeunq; +#endif /* NODECHK */ + + ASSERT( nh != NH_NULL ); + + /* convert the handle into an index + */ +#ifdef NODECHK + hdlgen = HDLGETGEN( nh ); + nix = HDLGETNIX( nh ); +#else /* NODECHK */ + nix = ( nix_t )nh; +#endif /* NODECHK */ + + ASSERT( nix <= NIX_MAX ); + + /* map in + */ + p = 0; /* keep lint happy */ + win_map( NIX2OFF( nix ), ( void ** )&p ); + ASSERT( p ); + +#ifdef NODECHK + hkp = *( p + node_hdrp->nh_nodehkix ); + nodegen = HKPGETGEN( hkp ); + nodeunq = HKPGETUNQ( hkp ); + ASSERT( nodegen == hdlgen ); + ASSERT( nodeunq != NODEUNQFREE ); + ASSERT( nodeunq == NODEUNQALCD ); +#endif /* NODECHK */ + + return ( void * )p; +} + +/* ARGSUSED */ +static void +node_unmap_internal( nh_t nh, void **pp, bool_t internalpr ) +{ + nix_t nix; +#ifdef NODECHK + register u_char_t hkp; + register u_char_t hdlgen; + register u_char_t nodegen; + register u_char_t nodeunq; +#endif /* NODECHK */ + + ASSERT( pp ); + ASSERT( *pp ); + ASSERT( nh != NH_NULL ); + + /* convert the handle into an index + */ +#ifdef NODECHK + hdlgen = HDLGETGEN( nh ); + nix = HDLGETNIX( nh ); +#else /* NODECHK */ + nix = ( nix_t )nh; +#endif /* NODECHK */ + + ASSERT( nix <= NIX_MAX ); + +#ifdef NODECHK + hkp = *( *( u_char_t ** )pp + node_hdrp->nh_nodehkix ); + nodegen = HKPGETGEN( hkp ); + ASSERT( nodegen == hdlgen ); + nodeunq = HKPGETUNQ( hkp ); + if ( ! internalpr ) { + ASSERT( nodeunq != NODEUNQFREE ); + ASSERT( nodeunq == NODEUNQALCD ); + } else { + ASSERT( nodeunq != NODEUNQALCD ); + ASSERT( nodeunq == NODEUNQFREE ); + } +#endif /* NODECHK */ + + /* unmap the window containing the node + */ + win_unmap( NIX2OFF( nix ), pp ); /* zeros *pp */ +} + +void +node_unmap( nh_t nh, void **pp ) +{ + node_unmap_internal( nh, pp, BOOL_FALSE ); +} + +void +node_free( nh_t *nhp ) +{ + nh_t nh; + nix_t nix; + u_char_t *p; + register nix_t *linkagep; +#ifdef NODECHK + register u_char_t *hkpp; + register u_char_t hdlgen; + register u_char_t nodegen; + register u_char_t nodeunq; +#endif /* NODECHK */ + + ASSERT( nhp ); + nh = *nhp; + ASSERT( nh != NH_NULL ); + + /* convert the handle into an index + */ +#ifdef NODECHK + hdlgen = HDLGETGEN( nh ); + nix = HDLGETNIX( nh ); +#else /* NODECHK */ + nix = ( nix_t )nh; +#endif /* NODECHK */ + + ASSERT( nix <= NIX_MAX ); + + /* map in + */ + p = ( u_char_t * )node_map( nh ); + +#ifdef NODECHK + /* fix up unique field + */ + hkpp = p + node_hdrp->nh_nodehkix; + nodegen = HKPGETGEN( *hkpp ); + nodeunq = HKPGETUNQ( *hkpp ); + ASSERT( nodegen == hdlgen ); + ASSERT( nodeunq != NODEUNQFREE ); + ASSERT( nodeunq == NODEUNQALCD ); + *hkpp = HKPMKHKP( nodegen, NODEUNQFREE ); +#endif /* NODECHK */ + + /* put node on free list + */ + linkagep = ( nix_t * )p; + *linkagep = node_hdrp->nh_freenix; + node_hdrp->nh_freenix = nix; + + /* map out + */ + node_unmap_internal( nh, ( void ** )&p, BOOL_TRUE ); + + /* invalidate caller's handle + */ + *nhp = NH_NULL; +} diff -rNu linux-2.4.7/cmd/xfsdump/restore/node.h linux-2.4-xfs/cmd/xfsdump/restore/node.h --- linux-2.4.7/cmd/xfsdump/restore/node.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/node.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef NODE_H +#define NODE_H + +/* node.[ch] - abstract pool of nodes + * + * operators alloc, free, map, and unmap nodes. + */ + +typedef size32_t nh_t; +#define NH_NULL SIZE32MAX + +/* node_init - creates a new node abstraction. + * user reserves one byte per node for use by the node abstraction + */ +extern bool_t node_init( intgen_t fd, /* backing store */ + off64_t off, /* offset into backing store */ + size_t nodesz, /* node size */ + ix_t nodehkix, /* my housekeeping byte */ + size_t alignsz, /* node alignment requirement */ + size64_t vmsz, /* abstractions's share of VM */ + size64_t mincnt ); /* min. est. nodes needed */ + +/* node_sync - syncs up with existing node abstraction persistent state + */ +extern bool_t node_sync( intgen_t fd, off64_t off ); + +/* node_alloc - allocates a node, returning a handle. + * returns NULL handle if no space left. + */ +extern nh_t node_alloc( void ); + +/* node_map - returns a pointer to the node identified by the node handle. + * pointer remains valid until node_unmap called. + */ +extern void *node_map( nh_t node_handle ); + +/* node_unmap - unmaps the node. + * SIDE-EFFECT: sets *nodepp to 0. + */ +extern void node_unmap( nh_t node_handle, void **nodepp ); + +/* node_free - frees a previously allocated node. + * SIDE-EFFECT: sets *node_handlep to NODE_HANDLE_NULL. + */ +extern void node_free( nh_t *node_handlep ); + +#endif /* NODE_H */ diff -rNu linux-2.4.7/cmd/xfsdump/restore/tree.c linux-2.4-xfs/cmd/xfsdump/restore/tree.c --- linux-2.4.7/cmd/xfsdump/restore/tree.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/tree.c Mon May 14 23:05:35 2001 @@ -0,0 +1,4716 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "util.h" +#include "cldmgr.h" +#include "path.h" +#include "openutil.h" +#include "getopt.h" +#include "stream.h" +#include "mlog.h" +#include "dlog.h" +#include "global.h" +#include "drive.h" +#include "media.h" +#include "content.h" +#include "content_inode.h" +#include "inomap.h" +#include "namreg.h" +#include "dirattr.h" +#include "bag.h" +#include "win.h" +#include "node.h" +#include "tree.h" +#include "libgen.h" +#include "mmap.h" + +/* structure definitions used locally ****************************************/ + +/* name of persistent state file + */ +#define PERS_NAME "tree" + +/* orphanage specifics. ino must be otherwise unused in the dump source fs. + * zero works. + */ +#define ORPH_INO 0 +#define ORPH_NAME "orphanage" + + +/* VM budgeting - give hash array one eigth, rest goes to node array + */ +#define HASHSZ_PERVM 8 + + +/* reserve the first page for persistent state + */ +struct treePersStorage { + xfs_ino_t p_rootino; + /* ino of root + */ + nh_t p_rooth; + /* handle of root node + */ + nh_t p_orphh; + /* handle to orphanage node + */ + size64_t p_hashsz; + /* size of hash array (private to hash abstraction) + */ + size_t p_hashmask; + /* hash mask (private to hash abstraction) + */ + bool_t p_ownerpr; + /* restore directory owner/group attributes + */ + bool_t p_fullpr; + /* restoring a full level 0 non-resumed dump (can skip + * some steps) + */ + bool_t p_ignoreorphpr; + /* set if positive subtree or interactive + */ + bool_t p_restoredmpr; + /* restore DMI event settings + */ +}; + +typedef struct treePersStorage treepers_t; + +#define PERSSZ perssz + + +/* interactive dialog transient state + */ +#define INTER_ARGMAX 10 /* max number of args to interactive cmds */ +struct inter { + size_t i_argc; + char *i_argv[ INTER_ARGMAX ]; + nh_t i_cwdh; + char i_name[ NAME_MAX ]; +}; + +typedef struct inter inter_t; + +/* transient state + */ +struct tran { + bool_t t_toconlypr; + /* just display table of contents; don't restore files + */ + char *t_hkdir; + /* full absolute pathname of housekeeping directory + */ + char *t_dstdir; + /* full absolute pathname of destination directory + */ + char *t_orphdir; + /* full absolute pathname of orphanage directory + */ + char *t_hksubtree; + /* if non-NULL, is path of hkdir relative to dstdir. + * don't restore there. + */ + intgen_t t_persfd; + /* file descriptor of the persistent state file + */ + nh_t *t_hashp; + /* pointer to mapped hash array (private to hash abstraction) + */ + char t_namebuf[ NAME_MAX ]; + /* to hold names temporarily retrieved from name registry + */ + inter_t t_inter; + /* context for interactive subtree selection + */ +}; + +typedef struct tran tran_t; + + +/* node structure. each node represents a directory entry + */ +#define NODESZ 40 + +struct node { + xfs_ino_t n_ino; /* 8 8 ino */ + nrh_t n_nrh; /* 4 12 handle to name in name registry */ + dah_t n_dah; /* 4 16 handle to directory attributes */ + nh_t n_hashh; /* 4 20 hash array */ + nh_t n_parh; /* 4 24 parent */ + nh_t n_sibh; /* 4 28 sibling list */ + nh_t n_cldh; /* 4 32 children list */ + nh_t n_lnkh; /* 4 36 hard link list */ + gen_t n_gen; /* 2 38 generation count mod 0x10000 */ + u_char_t n_flags; /* 1 39 action and state flags */ + u_char_t n_nodehkbyte; /* 1 40 given to node abstraction */ +}; + +typedef struct node node_t; + +#define NF_REAL ( 1 << 0 ) + /* set when the corresponding file/dir has been created in + * the restore destination. + */ +#define NF_SUBTREE ( 1 << 1 ) + /* marks nodes in the selected subtrees. + */ +#define NF_REFED ( 1 << 2 ) + /* indicates node is still referenced according to incremental/resumed + * dump. used to detect dirents no longer used. prior to restoring + * a dump session, this flag is cleared in all nodes. during the dirent + * restoral, it is set. it may also be set during the adjustment + * for referenced but undumped directories. NOTE: nodes in the + * orphanage NEVER have this flag set. + */ +#define NF_WRITTEN ( 1 << 3 ) + /* set as soon as a non-dir node restore is begun. allows + * overwrite inhibit options to work with segmented files + */ +#define NF_ISDIR ( 1 << 4 ) + /* indicates this node is a directory. set when a directory is taken + * from the dirdump. + */ +#define NF_DUMPEDDIR ( 1 << 5 ) + /* indicates this node is a directory present in the current dirdump. + * at beginning of session, this flag is cleared in all nodes. + * then as each directory dump is read from media, the flag + * is set from the corresponding node. this allows adjustments to + * the NF_REFED flag: if a directory was not dumped, either it no + * longer exists or it has not changed. if it is referenced, we assume + * it exists, in which case if it is not dumped then all of its entries + * are referenced as well. + */ +#define NF_NEWORPH ( 1 << 6 ) + /* cleared from all nodes in the orphanage before a dump is applied. + * set if a dir is seen in the dirdump but no node exists for it. + * cleared if that dir is adopted subsequently during the dirdump. + * set if a nondir is seen in the nondir dump but no node exists for + * it. in either case a node is created and placed in the orphanage. + * during rmdir/unlink processing, nodes so marked are left alone. + * since the flag is cleared at the beginning of the next increment, + * old orphans had better be adopted, otherwise they will be unlinked. + */ + +/* link list iterator context + */ +struct link_iter_context { + nh_t li_headh; /* head of hard link list */ + nh_t li_prevh; /* next to last node returned by _next() */ + nh_t li_lasth; /* last node returned by _next() */ + bool_t li_donepr; /* set as soon as last.next null */ +}; +typedef struct link_iter_context link_iter_context_t; + + +/* declarations of externally defined global symbols *************************/ + +extern void usage( void ); +extern size_t pgsz; +extern size_t pgmask; + + +/* forward declarations of locally defined static functions ******************/ + +static nh_t Node_alloc( xfs_ino_t ino, + gen_t gen, + nrh_t nrh, + dah_t dah, + size_t flags ); +static void Node_free( nh_t *nhp ); +static node_t * Node_map( nh_t nh ); +static void Node_unmap( nh_t nh, node_t **npp ); +static intgen_t Node2path_recurse( nh_t nh, char *buf, intgen_t bufsz ); +static void adopt( nh_t parh, nh_t cldh, nrh_t nrh ); +static nrh_t disown( nh_t cldh ); +static void selsubtree( nh_t nh, bool_t sensepr ); +static void selsubtree_recurse_down( nh_t nh, bool_t sensepr ); +static nh_t link_hardh( xfs_ino_t ino, gen_t gen ); +static nh_t link_nexth( nh_t nh ); +static nh_t link_matchh( nh_t hardh, nh_t parh, char *name ); +static void link_in( nh_t nh ); +static void link_out( nh_t nh ); +static void link_headiter( bool_t ( * cbfp )( void *contextp, nh_t hardh ), + void *contextp ); +static void link_iter_init( link_iter_context_t *link_iter_contextp, + nh_t hardheadh ); +static nh_t link_iter_next( link_iter_context_t *link_iter_contextp ); +void link_iter_unlink( link_iter_context_t *link_iter_contextp, nh_t nh ); +static bool_t hash_init( size64_t vmsz, + size64_t dircnt, + size64_t nondircnt, + char *perspath ); +static bool_t hash_sync( char *perspath ); +static void hash_in( nh_t nh ); +static void hash_out( nh_t nh ); +static nh_t hash_find( xfs_ino_t ino, gen_t gen ); +static void hash_iter( bool_t ( * cbfp )( void *contextp, nh_t hashh ), + void *contextp ); +static void setdirattr( dah_t dah, char *path ); +static bool_t tsi_walkpath( char *arg, nh_t rooth, nh_t cwdh, + dlog_pcbp_t pcb, void *pctxp, + nh_t *namedhp, nh_t *parhp, nh_t *cldhp, + xfs_ino_t *inop, bool_t *isdirprp, bool_t *isselpr ); +static bool_t Node2path( nh_t nh, char *path, char *errmsg ); +static bool_t tree_setattr_recurse( nh_t parh, char *path ); +static void tsi_cmd_pwd_recurse( void *ctxp, + dlog_pcbp_t pcb, + void *pctxp, + nh_t nh ); +static int mkdir_r(char *path); +#ifdef TREE_CHK +static bool_t Node_chk( nh_t nh, nh_t *nexthashhp, nh_t *nextlnkhp ); +static bool_t tree_chk2( void ); +#endif /* TREE_CHK */ + +/* definition of locally defined global variables ****************************/ + + +/* definition of locally defined static variables *****************************/ + +static treepers_t *persp = 0; +static tran_t *tranp = 0; +static char *persname = PERS_NAME; +static char *orphname = ORPH_NAME; +static xfs_ino_t orphino = ORPH_INO; + + +/* definition of locally defined global functions ****************************/ + +/* ARGSUSED */ +bool_t +tree_init( char *hkdir, + char *dstdir, + bool_t toconlypr, + bool_t ownerpr, + xfs_ino_t rootino, + xfs_ino_t firstino, + xfs_ino_t lastino, + size64_t dircnt, + size64_t nondircnt, + size64_t vmsz, + bool_t fullpr, + bool_t restoredmpr ) +{ + off64_t nodeoff; + char *perspath; + bool_t ok; + intgen_t rval; + + /* sanity checks + */ + ASSERT( ! ( PERSSZ % pgsz )); + ASSERT( sizeof( persp ) <= PERSSZ ); + ASSERT( sizeof( node_t ) <= NODESZ ); + ASSERT( ! persp ); + ASSERT( ! tranp ); + + /* allocate transient state + */ + tranp = ( tran_t * )calloc( 1, sizeof( tran_t )); + ASSERT( tranp ); + + tranp->t_toconlypr = toconlypr; + tranp->t_hkdir = hkdir; + tranp->t_dstdir = dstdir; + + /* allocate a char string buffer to hold the abs. pathname + * of the orphanage directory file. load it with the pathname. + */ + tranp->t_orphdir = open_pathalloc( tranp->t_dstdir, + orphname, + 0 ); + + /* determine if housekeeping dir is within the destination. + * generate a relative path containing the difference, + * else null. will not restore into there. + */ + if ( strcmp( dstdir, "." )) { + tranp->t_hksubtree = path_diff( hkdir, dstdir ); + } else { + tranp->t_hksubtree = 0; + } + + /* create an orphanage, if it already exists, complain. + * not needed if just a table-of-contents restore. + */ + if ( ! tranp->t_toconlypr ) { + rval = mkdir( tranp->t_orphdir, S_IRWXU ); + if ( rval ) { + if ( errno == EEXIST ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_TREE, + "%s already exists: " + "rm -rf prior to initating restore\n", + tranp->t_orphdir, + strerror( errno )); + } else { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_TREE, + "unable to create %s: %s\n", + tranp->t_orphdir, + strerror( errno )); + } + return BOOL_FALSE; + } + } + + /* build a full pathname to pers. state file + */ + perspath = open_pathalloc( tranp->t_hkdir, persname, 0 ); + + /* create the persistent state file + */ + ( void )unlink( perspath ); + tranp->t_persfd = open( perspath, + O_RDWR | O_CREAT, + S_IRUSR | S_IWUSR ); + if ( tranp->t_persfd < 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_TREE, + "could not open %s: %s\n", + perspath, + strerror( errno )); + return BOOL_FALSE; + } + + /* mmap the persistent state + */ + ASSERT( ! ( PERSSZ % pgsz )); + persp = ( treepers_t * ) mmap_autogrow( + PERSSZ, + tranp->t_persfd, + ( off64_t )0 ); + if ( persp == ( treepers_t * )-1 ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_TREE, + "unable to map %s: %s\n", + perspath, + strerror( errno )); + return BOOL_FALSE; + } + + /* create the hash abstraction. it will map more of the + * persistent state file. + */ + ok = hash_init( vmsz / HASHSZ_PERVM, dircnt, nondircnt, perspath ); + if ( ! ok ) { + return BOOL_FALSE; + } + + /* initialize the node abstraction. let it's use of backing store + * begin immediately after the hash abstraction. give it the remainder + * of vm. + */ + ASSERT( persp->p_hashsz <= ( size64_t )( OFF64MAX - ( off64_t )PERSSZ)); + nodeoff = ( off64_t )PERSSZ + ( off64_t )persp->p_hashsz; + ASSERT( vmsz > ( size64_t )nodeoff ); + ok = node_init( tranp->t_persfd, + nodeoff, + NODESZ, + ( ix_t )offsetofmember( node_t, n_nodehkbyte ), + sizeof( size64_t ), /* node alignment */ + vmsz - ( size64_t )nodeoff, + dircnt + nondircnt ); + if ( ! ok ) { + return BOOL_FALSE; + } + + /* extract the root ino and allocate a node for + * the root and for the orphanage. place both nodes + * in the hash list. make the orphanage a child of + * root, and indicate he is real. + */ + persp->p_rootino = rootino; + persp->p_rooth = Node_alloc( rootino, + 0, /* gen cnt */ + NRH_NULL, + DAH_NULL, + NF_ISDIR | NF_REAL ); + link_in( persp->p_rooth ); + persp->p_orphh = Node_alloc( orphino, + 0, /* gen cnt */ + namreg_add( orphname, strlen( orphname )), + DAH_NULL, + NF_ISDIR | NF_REAL ); + link_in( persp->p_orphh ); + adopt( persp->p_rooth, persp->p_orphh, NRH_NULL ); + + /* record if we should attempt to restore original owner/group + */ + persp->p_ownerpr = ownerpr; + + /* record if this is a full dump. can skip link processing if so + */ + persp->p_fullpr = fullpr; + + /* record if DMI event settings should be restored + */ + persp->p_restoredmpr = restoredmpr; + + return BOOL_TRUE; +} + +bool_t +tree_sync( char *hkdir, char *dstdir, bool_t toconlypr, bool_t fullpr ) +{ + off64_t nodeoff; + char *perspath; + bool_t ok; + intgen_t rval; + +#ifdef SESSCPLT + if ( persp ) { + return BOOL_TRUE; + } +#endif /* SESSCPLT */ + + /* sanity checks + */ + ASSERT( ! ( PERSSZ % pgsz )); + ASSERT( sizeof( persp ) <= PERSSZ ); + ASSERT( sizeof( node_t ) <= NODESZ ); + ASSERT( ! persp ); + ASSERT( ! tranp ); + + /* allocate transient state + */ + tranp = ( tran_t * )calloc( 1, sizeof( tran_t )); + ASSERT( tranp ); + + tranp->t_toconlypr = toconlypr; + tranp->t_hkdir = hkdir; + tranp->t_dstdir = dstdir; + + /* allocate a char string buffer to hold the abs. pathname + * of the orphanage directory file. load it with the pathname. + */ + tranp->t_orphdir = open_pathalloc( tranp->t_dstdir, + orphname, + 0 ); + + /* determine if housekeeping dir is within the destination. + * generate a relative path containing the difference, + * else null. will not restore into there. + */ + if ( strcmp( dstdir, "." )) { + tranp->t_hksubtree = path_diff( hkdir, dstdir ); + } else { + tranp->t_hksubtree = 0; + } + + /* re-create the orphanage (in case someone rmdir'ed it) + */ + rval = mkdir( tranp->t_orphdir, S_IRWXU ); + if ( rval && errno != EEXIST ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_TREE, + "unable to recreate %s: %s\n", + tranp->t_orphdir, + strerror( errno )); + return BOOL_FALSE; + } + + /* build a full pathname to pers. state file + */ + perspath = open_pathalloc( tranp->t_hkdir, persname, 0 ); + + /* re-open the persistent state file + */ + tranp->t_persfd = open( perspath, O_RDWR ); + if ( tranp->t_persfd < 0 ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_TREE, + "could not open %s: %s\n", + perspath, + strerror( errno )); + return BOOL_FALSE; + } + + /* mmap the persistent state + */ + ASSERT( ! ( PERSSZ % pgsz )); + persp = ( treepers_t * ) mmap_autogrow( + PERSSZ, + tranp->t_persfd, + ( off64_t )0 ); + if ( persp == ( treepers_t * )-1 ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_TREE, + "unable to map %s: %s\n", + perspath, + strerror( errno )); + return BOOL_FALSE; + } + + /* update the fullpr field of the persistent state to match + * the input of our caller. + */ + persp->p_fullpr = fullpr; + + /* rsynchronize with the hash abstraction. it will map more of the + * persistent state file. + */ + ok = hash_sync( perspath ); + if ( ! ok ) { + return BOOL_FALSE; + } + + /* synchronize with the node abstraction. + */ + ASSERT( persp->p_hashsz <= ( size64_t )( OFF64MAX - ( off64_t )PERSSZ)); + nodeoff = ( off64_t )PERSSZ + ( off64_t )persp->p_hashsz; + ok = node_sync( tranp->t_persfd, nodeoff ); + if ( ! ok ) { + return BOOL_FALSE; + } + + /* extract the root ino and allocate a node for + * the root and for the orphanage. place both nodes + * in the hash list. make the orphanage a child of + * root, and indicate he is real. + */ + return BOOL_TRUE; +} + +/* recursively descend the tree clearing REFED and DIRDUMPED and NEWORPH + * flags. force the orphanage to be refed and dumped, so we won't try + * to orphan it, and so things added to it won't look like they are + * referenced during ref adj. also null dirattr handles, since they are + * not retained across dump session restores. + */ +static void tree_marknoref_recurse( nh_t parh ); + +void +tree_marknoref( void ) +{ + tree_marknoref_recurse( persp->p_rooth ); + + { + node_t *orphp; + orphp = Node_map( persp->p_orphh ); + orphp->n_flags |= ( NF_REFED | NF_DUMPEDDIR ); + ASSERT( orphp->n_dah == DAH_NULL ); + Node_unmap( persp->p_orphh, &orphp ); + } +} + +static void +tree_marknoref_recurse( nh_t parh ) +{ + nh_t cldh; + + { + node_t *parp; + parp = Node_map( parh ); + parp->n_flags &= ~( NF_REFED | NF_DUMPEDDIR | NF_NEWORPH ); + + parp->n_dah = DAH_NULL; + cldh = parp->n_cldh; + Node_unmap( parh, &parp ); + } + while ( cldh != NH_NULL ) { + node_t *cldp; + nh_t nextcldh; + tree_marknoref_recurse( cldh ); /* RECURSION */ + cldp = Node_map( cldh ); + nextcldh = cldp->n_sibh; + Node_unmap( cldh, &cldp ); + cldh = nextcldh; + } +} + +void +tree_markallsubtree( bool_t sensepr ) +{ + if ( ! sensepr ) { + persp->p_ignoreorphpr = BOOL_TRUE; + } + selsubtree( persp->p_rooth, sensepr ); +} + +nh_t +tree_begindir( filehdr_t *fhdrp, dah_t *dahp ) +{ + nh_t hardh; + xfs_ino_t ino = fhdrp->fh_stat.bs_ino; + u_int32_t biggen = fhdrp->fh_stat.bs_gen; + gen_t gen = BIGGEN2GEN( biggen ); + dah_t dah; + + /* sanity check - orphino is supposed to be an unused ino! + */ + ASSERT( ino != orphino ); + + /* lookup head of hardlink list + */ + hardh = link_hardh( ino, gen ); + ASSERT( ino != persp->p_rootino || hardh == persp->p_rooth ); + + /* already present + */ + if ( hardh != NH_NULL ) { + node_t *hardp; + hardp = Node_map( hardh ); + if ( ! ( hardp->n_flags & NF_ISDIR )) { + /* case 1: previously seen as dirent, now know is dir + */ + mlog( MLOG_TRACE | MLOG_TREE, + "directory %llu %u (%u): " + "upgrading to dir\n", + ino, + gen, + biggen ); + if ( ! tranp->t_toconlypr ) { + ASSERT( hardp->n_dah == DAH_NULL ); + hardp->n_dah = dirattr_add( fhdrp ); + } + } else if ( ! tranp->t_toconlypr && hardp->n_dah == DAH_NULL ) { + /* case 2: node is a dir, but had thrown away dirattr + */ + mlog( MLOG_TRACE | MLOG_TREE, + "directory %llu %u (%u): " + "updating\n", + ino, + gen, + biggen ); + hardp->n_dah = dirattr_add( fhdrp ); + } else { + /* case 3: already has dirattr; must be restart + */ + mlog( MLOG_TRACE | MLOG_TREE, + "directory %llu %u (%u): " + "retaining\n", + ino, + gen, + biggen ); + } + hardp->n_flags |= NF_ISDIR; + hardp->n_flags |= NF_DUMPEDDIR; + *dahp = hardp->n_dah; + Node_unmap( hardh, &hardp ); + } else { + /* case 4: first time seen + */ + mlog( MLOG_TRACE | MLOG_TREE, + "directory %llu %u (%u): " + "new\n", + ino, + gen, + biggen ); + if ( ! tranp->t_toconlypr ) { + dah = dirattr_add( fhdrp ); + } else { + dah = DAH_NULL; + } + hardh = Node_alloc( ino, + gen, + NRH_NULL, + dah, + NF_ISDIR | NF_NEWORPH ); + link_in( hardh ); + adopt( persp->p_orphh, hardh, NRH_NULL ); + *dahp = dah; + } + + return hardh; +} + +void +tree_addent( nh_t parh, xfs_ino_t ino, size_t g, char *name, size_t namelen ) +{ + gen_t gen = BIGGEN2GEN( g ); + nh_t hardh; + + /* sanity check - orphino is supposed to be an unused ino! + */ + ASSERT( ino != orphino ); + + /* don't allow entries named "orphanage" under root to be added + */ + if ( parh == persp->p_rooth && !strcmp( name, orphname )) { + mlog( MLOG_DEBUG | MLOG_TREE, + "dirent %s %llu %u: " + "skipping (reserved)\n", + name, + ino, + gen ); + return; + } + + /* if the parent is null, just ignore + */ + if ( parh == NH_NULL ) { + mlog( MLOG_DEBUG | MLOG_TREE, + "dirent %s %llu %u: " + "skipping (null parent)\n", + name, + ino, + gen ); + return; + } + + /* see if one or more links to this ino already exist. + */ + hardh = link_hardh( ino, gen ); + + if ( hardh != NH_NULL ) { + node_t *hardp; + hardp = Node_map( hardh ); + if ( hardp->n_flags & NF_ISDIR ) { + nh_t renameh; + node_t *renamep; + /* REFERENCED */ + intgen_t namebuflen; + + hardp->n_flags |= NF_REFED; + if ( hardp->n_parh == persp->p_orphh ) { + /* dir now seen as entry + * if in orph but REAL, must be pending rename + */ + if ( ( hardp->n_flags & NF_REAL ) + && + hardp->n_lnkh == NH_NULL ) { + hardp->n_lnkh = Node_alloc( ino, + gen, + NRH_NULL, + DAH_NULL, + 0 ); + } + if ( hardp->n_lnkh != NH_NULL ) { + ASSERT( hardp->n_flags & NF_REAL ); + renameh = hardp->n_lnkh; + renamep = Node_map( renameh ); + if ( renamep->n_parh == NH_NULL ) { + mlog( MLOG_DEBUG | MLOG_TREE, + "dirent %s %llu %u: " + "adopting (dir par)\n", + name, + ino, + gen ); + renamep->n_parh = parh; + } + if ( renamep->n_parh != parh ) { + mlog( MLOG_DEBUG | MLOG_TREE, + "dirent %s %llu %u: " + "re-adopting (dir par)\n", + name, + ino, + gen ); + renamep->n_parh = parh; + } + if ( renamep->n_nrh != NRH_NULL ) { + namebuflen + = + namreg_get( renamep->n_nrh, + tranp->t_namebuf, + sizeof( tranp->t_namebuf )); + ASSERT( namebuflen > 0 ); + if ( strcmp( name, + tranp->t_namebuf )) { + mlog( MLOG_DEBUG + | + MLOG_TREE, + "dirent %s " + "%llu %u: " + "re-adopting " + "(dir name): " + "was %s\n", + name, + ino, + gen, + tranp->t_namebuf ); + namreg_del( + renamep->n_nrh ); + renamep->n_nrh = + NRH_NULL; + } + } + if ( renamep->n_nrh == NRH_NULL ) { + renamep->n_nrh + = + namreg_add( name, namelen ); + renamep->n_parh = parh; + } + Node_unmap( renameh, &renamep ); + } else { + nrh_t nrh; + + hardp->n_flags &= ~NF_NEWORPH; + ASSERT( hardp->n_nrh == NRH_NULL ); + ASSERT( hardp->n_parh != NH_NULL ); + nrh = disown( hardh ); + ASSERT( nrh == NRH_NULL ); + nrh = namreg_add( name, namelen ); + adopt( parh, hardh, nrh ); + mlog( MLOG_DEBUG | MLOG_TREE, + "dirent %s %llu %u: " + "updating (dir)\n", + name, + ino, + gen ); + } + } else { + ASSERT( hardp->n_nrh != NRH_NULL ); + namebuflen + = + namreg_get( hardp->n_nrh, + tranp->t_namebuf, + sizeof( tranp->t_namebuf )); + ASSERT( namebuflen > 0 ); + if ( hardp->n_parh == parh + && + ! strcmp( tranp->t_namebuf, name )) { + /* dir seen as entry again + */ + if ( hardp->n_lnkh != NH_NULL ) { + /* rescind rename + */ + mlog( MLOG_DEBUG | MLOG_TREE, + "dirent %s %llu %u: " + "rescind rename (dir)\n", + name, + ino, + gen ); + Node_free( &hardp->n_lnkh ); + } else { + mlog( MLOG_DEBUG | MLOG_TREE, + "dirent %s %llu %u: " + "retaining (dir)\n", + name, + ino, + gen ); + } + } else { + /* dir rename + */ + nh_t renameh; + node_t *renamep; + if ( hardp->n_lnkh == NH_NULL ) { + renameh = Node_alloc( ino, + gen, + NRH_NULL, + DAH_NULL, + 0 ); + hardp->n_lnkh = renameh; + } else { + mlog( MLOG_DEBUG | MLOG_TREE, + "dirent %s %llu %u: " + "re-renaming\n", + name, + ino, + gen ); + renameh = hardp->n_lnkh; + renamep = Node_map( renameh ); + renamep->n_parh = NH_NULL; + if ( renamep->n_nrh + != + NRH_NULL ) { + namreg_del( renamep->n_nrh ); + } + renamep->n_nrh = NRH_NULL; + Node_unmap( renameh, &renamep ); + } + renamep = Node_map( renameh ); + ASSERT( hardp->n_parh != NH_NULL ); + if ( hardp->n_parh != parh ) { + /* different parent + */ + renamep->n_parh = parh; + mlog( MLOG_DEBUG | MLOG_TREE, + "dirent %s %llu %u: " + "renaming (parent)\n", + name, + ino, + gen ); + } + if ( strcmp( tranp->t_namebuf, name )) { + /* different name + */ + renamep->n_nrh = + namreg_add( name, namelen ); + mlog( MLOG_DEBUG | MLOG_TREE, + "dirent %s %llu %u: " + "renaming (name)\n", + name, + ino, + gen ); + } + Node_unmap( renameh, &renamep ); + } + } + } else { + nh_t matchh; + matchh = link_matchh( hardh, parh, name ); + if ( matchh != NH_NULL ) { + /* entry already exists + */ + node_t *matchp; + matchp = Node_map( matchh ); + hardp->n_flags |= NF_REFED; + Node_unmap( matchh, &matchp ); + mlog( MLOG_DEBUG | MLOG_TREE, + "dirent %s %llu %u: " + "retaining (nondir)\n", + name, + ino, + gen ); + } else { + /* case 5: new hard link + */ + nrh_t nrh; + nh_t linkh; + nrh = namreg_add( name, namelen ); + linkh = Node_alloc( ino, + gen, + NRH_NULL, + DAH_NULL, + NF_REFED ); + link_in( linkh ); + adopt( parh, linkh, nrh ); + mlog( MLOG_DEBUG | MLOG_TREE, + "dirent %s %llu %u: " + "adding (link)\n", + name, + ino, + gen ); + } + } + Node_unmap( hardh, &hardp ); + } else { + /* case 6: new entry + */ + nrh_t nrh; + nrh = namreg_add( name, namelen ); + hardh = Node_alloc( ino, + gen, + NRH_NULL, + DAH_NULL, + NF_REFED ); + link_in( hardh ); + adopt( parh, hardh, nrh ); + mlog( MLOG_DEBUG | MLOG_TREE, + "dirent %s %llu %u: " + "adding (new)\n", + name, + ino, + gen ); + } +} + +/* ARGSUSED */ +void +tree_enddir( nh_t dirh ) +{ +} + +bool_t +tree_subtree_parse( bool_t sensepr, char *path ) +{ + nh_t namedh; + nh_t parh; + nh_t cldh; + xfs_ino_t ino; + bool_t isdirpr; + bool_t isselpr; + bool_t ok; + + /* walk the tree down this relative pathname from the root. + */ + ok = tsi_walkpath( path, + NH_NULL, + persp->p_rooth, + 0, + 0, + &namedh, + &parh, + &cldh, + &ino, + &isdirpr, + &isselpr ); + if ( ! ok ) { + return BOOL_FALSE; + } + + /* set or clear flag in this node and all of its children, + * and ajust parentage flags. + */ + selsubtree( namedh, sensepr ); + + return BOOL_TRUE; +} + +/* tree_post - called after the dirdump has been applied. + * first phase is to eliminate all unreferenced dirents. + * done by recursive depth-wise descent of the tree. on the way + * up, unlink or orphan unreferenced nondirs, unlink unreferenced + * dirs, orphan dirs to be renamed. if a dir is unreferenced, but + * contains referenced dirents, orphan those dirents. orphan unreferenced + * nondirs if they are the last link to an inode referenced but not real + * somewhere else in the tree. next, make new directories. then rename + * directories. finally, create hardlinks from orphanage. + */ +static bool_t noref_elim_recurse( nh_t parh, + nh_t cldh, + bool_t parrefpr, + char *path1, + char *path2 ); + +static bool_t mkdirs_recurse( nh_t parh, + nh_t cldh, + char *path ); + +static bool_t rename_dirs( nh_t cldh, + char *path1, + char *path2 ); + +static bool_t proc_hardlinks( char *path1, + char *path2 ); + +bool_t +tree_post( char *path1, char *path2 ) +{ + node_t *rootp; + node_t *orphp; + nh_t cldh; + bool_t ok; + + /* eliminate unreferenced dirents + */ + if ( ! persp->p_fullpr ) { + mlog( MLOG_DEBUG | MLOG_TREE, + "eliminating unreferenced directory entries\n" ); + rootp = Node_map( persp->p_rooth ); + cldh = rootp->n_cldh; + Node_unmap( persp->p_rooth, &rootp ); + ok = noref_elim_recurse( persp->p_rooth, + cldh, + BOOL_TRUE, + path1, + path2 ); + if ( ! ok ) { + return BOOL_FALSE; + } + } + + /* make new directories + */ + mlog( MLOG_DEBUG | MLOG_TREE, + "making new directories\n" ); + rootp = Node_map( persp->p_rooth ); + cldh = rootp->n_cldh; + Node_unmap( persp->p_rooth, &rootp ); + ok = mkdirs_recurse( persp->p_rooth, cldh, path1 ); + if ( ! ok ) { + return BOOL_FALSE; + } + +#ifdef TREE_CHK + ASSERT( tree_chk( )); +#endif /* TREE_CHK */ + + /* rename directories + */ + if ( ! persp->p_fullpr ) { + mlog( MLOG_DEBUG | MLOG_TREE, + "performing directory renames\n" ); + orphp = Node_map( persp->p_orphh ); + cldh = orphp->n_cldh; + Node_unmap( persp->p_orphh, &orphp ); + ok = rename_dirs( cldh, path1, path2 ); + if ( ! ok ) { + return BOOL_FALSE; + } + } + +#ifdef TREE_CHK + ASSERT( tree_chk( )); +#endif /* TREE_CHK */ + + /* process hard links + */ + if ( ! persp->p_fullpr ) { + mlog( MLOG_DEBUG | MLOG_TREE, + "processing hard links\n" ); + ok = proc_hardlinks( path1, path2 ); + if ( ! ok ) { + return BOOL_FALSE; + } + } + + return BOOL_TRUE; +} + +/* ARGSUSED */ +static bool_t +noref_elim_recurse( nh_t parh, + nh_t cldh, + bool_t parrefpr, + char *path1, + char *path2 ) +{ + while ( cldh != NH_NULL ) { + node_t *cldp; + xfs_ino_t ino; + gen_t gen; + bool_t inorphanagepr; + bool_t isdirpr; + bool_t isrealpr; + bool_t isrefpr; + bool_t isrenamepr; + nh_t renameh; + nh_t grandcldh; + nh_t nextcldh; + intgen_t rval; + bool_t ok; + + cldp = Node_map( cldh ); + ino = cldp->n_ino; + gen = cldp->n_gen; + inorphanagepr = cldp->n_parh == persp->p_orphh; + isdirpr = ( cldp->n_flags & NF_ISDIR ); + isrealpr = ( cldp->n_flags & NF_REAL ); + isrefpr = ( cldp->n_flags & NF_REFED ); + isrenamepr = ( isdirpr && cldp->n_lnkh != NH_NULL ); + renameh = cldp->n_lnkh; + grandcldh = cldp->n_cldh; + nextcldh = cldp->n_sibh; + Node_unmap( cldh, &cldp ); + + if ( isdirpr ) { + bool_t ok; + + ok = noref_elim_recurse( cldh, + grandcldh, + isrefpr, + path1, + path2 ); + /* RECURSION */ + if ( ! ok ) { + return BOOL_FALSE; + } + + if ( inorphanagepr ) { + cldh = nextcldh; + continue; + } + + if ( ! isrefpr ) { + nrh_t nrh; + + ASSERT( ! isrenamepr ); + if ( isrealpr ) { + ok = Node2path( cldh, path1, "rmdir" ); + if ( ! ok ) { + cldh = nextcldh; + continue; + } + mlog( MLOG_TRACE | MLOG_TREE, + "rmdir %s\n", + path1 ); + rval = rmdir( path1 ); + if ( rval ) { + mlog( MLOG_NORMAL + | + MLOG_WARNING + | + MLOG_TREE, + "unable to rmdir %s: %s\n", + path1, + strerror( errno )); + cldh = nextcldh; + continue; + } + } + nrh = disown( cldh ); + ASSERT( nrh != NRH_NULL ); + namreg_del( nrh ); + link_out( cldh ); + Node_free( &cldh ); + } + + if ( isrenamepr ) { + nrh_t nrh; + node_t *renamep; + + ASSERT( isrefpr ); + ASSERT( isrealpr ); + ok = Node2path( cldh, + path1, + "tmp dir rename src" ); + if ( ! ok ) { + cldh = nextcldh; + continue; + } + nrh = disown( cldh ); + ASSERT( nrh != NRH_NULL ); + adopt( persp->p_orphh, cldh, NRH_NULL ); + ok = Node2path( cldh, + path2, + "tmp dir rename dst" ); + if ( ! ok ) { + /* REFERENCED */ + nrh_t dummynrh; + dummynrh = disown( cldh ); + ASSERT( dummynrh == NRH_NULL ); + adopt( parh, cldh, nrh ); + cldh = nextcldh; + continue; + } + mlog( MLOG_TRACE | MLOG_TREE, + "rename dir %s to %s\n", + path1, + path2 ); + rval = rename( path1, path2 ); + if ( rval ) { + /* REFERENCED */ + nrh_t dummynrh; + mlog( MLOG_NORMAL | MLOG_WARNING, + "unable to rename dir %s " + "to dir %s: %s\n", + path1, + path2, + strerror( errno )); + dummynrh = disown( cldh ); + ASSERT( dummynrh == NRH_NULL ); + adopt( parh, cldh, nrh ); + cldh = nextcldh; + continue; + } + cldp = Node_map( cldh ); + renamep = Node_map( renameh ); + if ( renamep->n_nrh == NRH_NULL ) { + renamep->n_nrh = nrh; + } else { + namreg_del( nrh ); + } + if ( renamep->n_parh == NH_NULL ) { + renamep->n_parh = parh; + } + cldp->n_flags |= NF_NEWORPH; + Node_unmap( renameh, &renamep ); + Node_unmap( cldh, &cldp ); + } + } else { + /* determine if we can unlink this node. + * if its not real, and not refed, simple. + * if real and not refed and there is at least + * one unreal refed node and no other real + * nodes around, must put this one in orphanage + * rather than unlinking it. + */ + bool_t mustorphpr; + bool_t canunlinkpr; + + if ( inorphanagepr ) { + cldh = nextcldh; + continue; + } + + mustorphpr = BOOL_FALSE; + canunlinkpr = ! isrefpr && ! isrealpr; + if ( ! isrefpr && isrealpr ) { + nh_t hardh; + bool_t neededpr; + hardh = link_hardh( ino, gen ); + ASSERT( hardh != NH_NULL ); + canunlinkpr = BOOL_FALSE; + neededpr = BOOL_FALSE; + while ( hardh != NH_NULL ) { + node_t *hardp; + bool_t hardisrefpr; + bool_t hardisrealpr; + nh_t nexthardh; + + hardp = Node_map( hardh ); + hardisrefpr = hardp->n_flags & NF_REFED; + hardisrealpr = hardp->n_flags & NF_REAL; + nexthardh = hardp->n_lnkh; + Node_unmap( hardh, &hardp ); + if ( hardh != cldh && hardisrealpr ) { + canunlinkpr = BOOL_TRUE; + break; + } + if ( hardisrefpr && ! hardisrealpr ) { + neededpr = BOOL_TRUE; + } + hardh = nexthardh; + } + if ( neededpr ) { + mustorphpr = BOOL_TRUE; + } + } + + if ( mustorphpr ) { + nrh_t nrh; + ASSERT( ! canunlinkpr ); + ok = Node2path( cldh, + path1, + "tmp nondir rename src" ); + if ( ! ok ) { + cldh = nextcldh; + continue; + } + nrh = disown( cldh ); + ASSERT( nrh != NRH_NULL ); + adopt( persp->p_orphh, cldh, NRH_NULL ); + ok = Node2path( cldh, + path2, + "tmp nondir rename dst" ); + if ( ! ok ) { + /* REFERENCED */ + nrh_t dummynrh; + dummynrh = disown( cldh ); + ASSERT( dummynrh == NRH_NULL ); + adopt( parh, cldh, nrh ); + cldh = nextcldh; + continue; + } + mlog( MLOG_TRACE | MLOG_TREE, + "rename nondir %s to %s\n", + path1, + path2 ); + rval = rename( path1, path2 ); + if ( rval ) { + /* REFERENCED */ + nrh_t dummynrh; + mlog( MLOG_NORMAL | MLOG_WARNING, + "unable to rename nondir %s " + "to nondir %s: %s\n", + path1, + path2, + strerror( errno )); + dummynrh = disown( cldh ); + ASSERT( dummynrh == NRH_NULL ); + adopt( parh, cldh, nrh ); + cldh = nextcldh; + continue; + } + namreg_del( nrh ); + cldp = Node_map( cldh ); + cldp->n_flags |= NF_NEWORPH; + Node_unmap( cldh, &cldp ); + } + if ( canunlinkpr ) { + /* REFERENCED */ + nrh_t nrh; + + ASSERT( ! mustorphpr ); + if ( isrealpr ) { + ok = Node2path( cldh, path1, "rmdir" ); + if ( ! ok ) { + cldh = nextcldh; + continue; + } + mlog( MLOG_TRACE | MLOG_TREE, + "unlink %s\n", + path1 ); + rval = unlink( path1 ); + if ( rval ) { + mlog( MLOG_NORMAL + | + MLOG_WARNING + | + MLOG_TREE, + "unable to unlink nondir " + "%s: %s\n", + path1, + strerror( errno )); + cldh = nextcldh; + continue; + } + } + nrh = disown( cldh ); + ASSERT( nrh != NRH_NULL ); + link_out( cldh ); + Node_free( &cldh ); + } + } + + /* next! + */ + cldh = nextcldh; + } + + return BOOL_TRUE; +} + +/* ARGSUSED */ +static bool_t +mkdirs_recurse( nh_t parh, nh_t cldh, char *path ) +{ + while ( cldh != NH_NULL ) { + node_t *cldp; + bool_t isdirpr; + bool_t isselpr; + bool_t isrealpr; + bool_t isrefpr; + nh_t grandcldh; + nh_t nextcldh; + + cldp = Node_map( cldh ); + isdirpr = ( cldp->n_flags & NF_ISDIR ); + isrealpr = ( cldp->n_flags & NF_REAL ); + isrefpr = ( cldp->n_flags & NF_REFED ); + isselpr = ( cldp->n_flags & NF_SUBTREE ); + grandcldh = cldp->n_cldh; + nextcldh = cldp->n_sibh; + Node_unmap( cldh, &cldp ); + + /* if needed, create a directory and update real flag + */ + if ( isdirpr && ! isrealpr && isrefpr && isselpr ) { + intgen_t rval; + + if ( ! Node2path( cldh, path, "makedir" )) { + cldh = nextcldh; + continue; + } + if ( tranp->t_toconlypr ) { + rval = 0; + } else { + mlog( MLOG_TRACE | MLOG_TREE, + "mkdir %s\n", + path ); + rval = mkdir( path, S_IRWXU ); + } + if ( rval && errno != EEXIST ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "mkdir %s failed: %s\n", + path, + strerror( errno )); + + } else { + cldp = Node_map( cldh ); + cldp->n_flags |= NF_REAL; + Node_unmap( cldh, &cldp ); + isrealpr = BOOL_TRUE; + } + } + + /* if a real selected directory, recurse + */ + if ( isdirpr && isrealpr && isselpr ) { + bool_t ok; + ok = mkdirs_recurse( cldh, grandcldh, path ); + /* RECURSION */ + if ( ! ok ) { + return BOOL_FALSE; + } + } + + /* next! + */ + cldh = nextcldh; + } + + return BOOL_TRUE; +} + +static bool_t +rename_dirs( nh_t cldh, + char *path1, + char *path2 ) +{ + while ( cldh != NH_NULL ) { + node_t *cldp; + /* REFERENCED */ + nh_t parh; + bool_t isdirpr; + nh_t renameh; + bool_t isrenamepr; + nh_t nextcldh; + nh_t newparh; + nh_t newnrh; + + cldp = Node_map( cldh ); + parh = cldp->n_parh; + isdirpr = cldp->n_flags & NF_ISDIR; + renameh = cldp->n_lnkh; + isrenamepr = isdirpr && renameh != NH_NULL; + nextcldh = cldp->n_sibh; + Node_unmap( cldh, &cldp ); + ASSERT( parh == persp->p_orphh ); + + if ( isrenamepr ) { + node_t *renamep; + intgen_t rval; + /* REFERENCED */ + nrh_t dummynrh; + bool_t ok; + + renamep = Node_map( renameh ); + newparh = renamep->n_parh; + newnrh = renamep->n_nrh; + Node_unmap( renameh, &renamep ); + ok = Node2path( cldh, path1, "rename dir" ); + if ( ! ok ) { + cldh = nextcldh; + continue; + } + dummynrh = disown( cldh ); + ASSERT( dummynrh == NRH_NULL ); + adopt( newparh, cldh, newnrh ); + ok = Node2path( cldh, path2, "rename dir" ); + if ( ! ok ) { + dummynrh = disown( cldh ); + ASSERT( dummynrh == newnrh ); + adopt( persp->p_orphh, cldh, NRH_NULL ); + cldp = Node_map( cldh ); + cldp->n_nrh = NRH_NULL; + Node_unmap( cldh, &cldp ); + cldh = nextcldh; + continue; + } + mlog( MLOG_TRACE | MLOG_TREE, + "rename dir %s to %s\n", + path1, + path2 ); + rval = rename( path1, path2 ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "unable to rename dir %s " + "to dir %s: %s\n", + path1, + path2, + strerror( errno )); + dummynrh = disown( cldh ); + ASSERT( dummynrh == newnrh ); + adopt( persp->p_orphh, cldh, NRH_NULL ); + cldh = nextcldh; + continue; + } + cldp = Node_map( cldh ); + cldp->n_flags &= ~NF_NEWORPH; + cldp->n_lnkh = NH_NULL; + Node_unmap( cldh, &cldp ); + Node_free( &renameh ); + } + + /* next! + */ + cldh = nextcldh; + } + + return BOOL_TRUE; +} + +/* will call funcp for all links to be created. will abort if funcp + * ever returns FALSE; + */ +void +tree_cb_links( xfs_ino_t ino, + u_int32_t biggen, + int32_t ctime, + int32_t mtime, + bool_t ( * funcp )( void *contextp, + bool_t linkpr, + char *path1, + char *path2 ), + void *contextp, + char *path1, + char *path2 ) +{ + gen_t gen = BIGGEN2GEN( biggen ); + nh_t hardh; + nh_t nh; + char *path; + bool_t ok; + int rval; + + /* find the hardhead + */ + hardh = link_hardh( ino, gen ); + + /* loop through all hard links, attempting to restore/link + */ + path = path1; + for ( nh = hardh ; nh != NH_NULL ; nh = link_nexth( nh )) { + node_t *np; + u_char_t flags; + char *reasonstr; + + /* get the node flags + */ + np = Node_map( nh ); + flags = np->n_flags; + Node_unmap( nh, &np ); + + /* build a pathname + */ + ok = Node2path( nh, path, "restore" ); + if ( ! ok ) { + continue; + } + + /* skip if not in selected subtree + */ + if ( ! ( flags & NF_SUBTREE )) { + mlog( (MLOG_NITTY + 1) | MLOG_TREE, + "skipping %s (ino %llu gen %u): %s\n", + path, + ino, + gen, + "not in selected subtree" ); + continue; + } + + /* don't restore into the housekeeping directory + */ + if ( path_beginswith( path, tranp->t_hkdir )) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "cannot restore %s (ino %llu gen %u): " + "pathname contains %s\n", + path, + ino, + gen, + tranp->t_hkdir ); + continue; + } + + /* check if ok to overwrite: don't check if we've already + * been here and decided overwrite ok. if ok, set flag + * so we won't check again. in fact, can't check again + * since restore changes the answer. + */ + if ( ! ( flags & NF_WRITTEN )) { + if ( ! content_overwrite_ok( path, + ctime, + mtime, + &reasonstr )) { + mlog( MLOG_TRACE | MLOG_TREE, + "skipping %s (ino %llu gen %u): %s\n", + path, + ino, + gen, + reasonstr ); + continue; + } else { + np = Node_map( nh ); + np->n_flags |= NF_WRITTEN; + Node_unmap( nh, &np ); + + /* + * We're the first stream to restore this file. + * Unlink it first to remove extended attributes + * that may have been set since the dump was + * taken. + */ + if ( ! tranp->t_toconlypr ) { + rval = unlink( path ); + if ( rval && errno != ENOENT ) { + mlog( MLOG_NORMAL | + MLOG_WARNING, + "unable to unlink " + "current file prior to " + "restore: " + "%s: %s: discarding\n", + path, + strerror( errno )); + continue; + } + } + } + } + + /* call callback to restore file / create hard link. + * returns !ok if should abort. + */ + if ( path == path2 ) { + mlog( MLOG_TRACE | MLOG_TREE, + "link %s to %s (%llu %u)\n", + path1, + path2, + ino, + gen ); + } else { + mlog( MLOG_TRACE | MLOG_TREE, + "restoring %s (%llu %u)\n", + path1, + ino, + gen ); + } + ok = ( * funcp )( contextp, path == path2, path1, path2 ); + if ( ! ok ) { + return; + } + + /* set flag, indicating node is now real + */ + np = Node_map( nh ); + np->n_flags |= NF_REAL; + Node_unmap( nh, &np ); + + /* switch to second path buffer, for link paths + */ + path = path2; + } + + + /* if not yet peeled from tape, do so: place in orphanage if + * no references found (i.e., hard link list empty). + */ + if ( path == path1 ) { + if ( hardh != NH_NULL || persp->p_ignoreorphpr ) { + /* + * The file is referenced so the path is + * valid. This means that if path begins + * with 'orphanage' the file is one of two + * things: + * 1) It's a file that really is an + * orphanage file from a previous restore + * that has now ended up on this dump tape. + * We don't really want to restore this file + * but, it's harmless to do so, it should + * happen rarely, and the path name is + * indistinguishable from ... + * 2) A file whose name was never resolved + * from root because of file corruption. + * Some granparent dir (parent dir of it's + * parent dir) was corrupted so the code that + * walks the trees was thus never able to set + * the NF_SUBTREE flag. It then ends up here + * with a non-resolved name but a valid + * hard reference. We really need to give + * the admin the opportunity to get this + * data since one corrupted dirnode would + * make the whole tree of data + * unreachable. pv698761 + */ + if ( persp->p_ignoreorphpr || (strncmp(ORPH_NAME, path, + strlen(ORPH_NAME)) != 0)) { + mlog( MLOG_DEBUG | MLOG_TREE, + "discarding %llu %u\n", + ino, + gen ); + ok = ( * funcp )( contextp, BOOL_FALSE, 0, 0 ); + if ( ! ok ) { + return; + } + } else { + char *dir; + char tmp[PATH_MAX]; + + strcpy(tmp, path); + dir = dirname(tmp); + mkdir_r(dir); + mlog (MLOG_VERBOSE | MLOG_NOTE | MLOG_TREE, + "ino %llu salvaging file," + " placing in %s\n", ino, path1); + ok = ( * funcp )( contextp, path == path2, + path1, path2 ); + if ( ! ok ) { + return; + } + } + } else { + mlog( MLOG_VERBOSE | MLOG_NOTE | MLOG_TREE, + "ino %llu gen %u not referenced: " + "placing in orphanage\n", + ino, + biggen ); + nh = Node_alloc( ino, + gen, + NRH_NULL, + DAH_NULL, + NF_REAL | NF_NEWORPH ); + link_in( nh ); + adopt( persp->p_orphh, nh, NRH_NULL ); + ok = Node2path( nh, path1, "orphan" ); + ASSERT( ok ); + ( void )( * funcp )( contextp, BOOL_FALSE, path1,path2); + } + } +} + +/* uses flags cleared during directory restore (NF_DUMPEDDIR and NF_REFED ) + * to determine what directory entries are no longer needed. this can + * be done because whenever a directory chenges, it and all of its current + * entries are dumped. so if an entry is dumped which is a dir, but that + * dir is not dumped, all of that directories entries are needed and so must + * have their REFED flag cleared. + * + * does a recursive depth-wise descent of the tree, following this rule to + * clear the REFED flags. + */ + +static void tree_adjref_recurse( nh_t cldh, + bool_t pardumpedpr, + bool_t parrefedpr ); + +bool_t +tree_adjref( void ) +{ + tree_adjref_recurse( persp->p_rooth, BOOL_FALSE, BOOL_TRUE ); + return BOOL_TRUE; +} + +static void +tree_adjref_recurse( nh_t cldh, + bool_t pardumpedpr, + bool_t parrefedpr ) +{ + nh_t grandcldh; + bool_t clddumpedpr; + bool_t cldrefedpr; + { + node_t *cldp; + cldp = Node_map( cldh ); + if ( ! pardumpedpr && parrefedpr ) { + cldp->n_flags |= NF_REFED; + } + clddumpedpr = ( intgen_t )cldp->n_flags & NF_DUMPEDDIR; + cldrefedpr = ( intgen_t )cldp->n_flags & NF_REFED; + grandcldh = cldp->n_cldh; + Node_unmap( cldh, &cldp ); + } + while ( grandcldh != NH_NULL ) { + node_t *grandcldp; + nh_t nextgrandcldh; + tree_adjref_recurse( grandcldh, clddumpedpr, cldrefedpr ); + /* RECURSION */ + grandcldp = Node_map( grandcldh ); + nextgrandcldh = grandcldp->n_sibh; + Node_unmap( grandcldh, &grandcldp ); + grandcldh = nextgrandcldh; + } +} + +#ifdef EXTATTR +static bool_t tree_extattr_recurse( nh_t parh, + nh_t cldh, + bool_t ( * cbfunc )( char *path, + dah_t dah ), + char *path ); + +bool_t +tree_extattr( bool_t ( * cbfunc )( char *path, dah_t dah ), char *path ) +{ + node_t *rootp; + nh_t cldh; + bool_t ok; + + rootp = Node_map( persp->p_rooth ); + cldh = rootp->n_cldh; + Node_unmap( persp->p_rooth, &rootp ); + ok = tree_extattr_recurse( persp->p_rooth, cldh, cbfunc, path ); + + return ok; +} + +static bool_t +tree_extattr_recurse( nh_t parh, + nh_t cldh, + bool_t ( * cbfunc )( char *path, dah_t dah ), + char *path ) +{ + node_t *parp; + dah_t dah; + bool_t ok; + + /* first update all children + */ + while ( cldh != NH_NULL ) { + node_t *cldp; + bool_t isdirpr; + bool_t isselpr; + bool_t isrealpr; + nh_t grandcldh; + nh_t nextcldh; + + cldp = Node_map( cldh ); + isdirpr = ( cldp->n_flags & NF_ISDIR ); + isrealpr = ( cldp->n_flags & NF_REAL ); + isselpr = ( cldp->n_flags & NF_SUBTREE ); + grandcldh = cldp->n_cldh; + nextcldh = cldp->n_sibh; + Node_unmap( cldh, &cldp ); + + /* if a real selected directory, recurse + */ + if ( isdirpr && isrealpr && isselpr ) { + bool_t ok; + ok = tree_extattr_recurse( cldh, + grandcldh, + cbfunc, + path ); + /* RECURSION */ + if ( ! ok ) { + return BOOL_FALSE; + } + } + + /* next! + */ + cldh = nextcldh; + } + + /* now update self + */ + parp = Node_map( parh ); + dah = parp->n_dah; + Node_unmap( parh, &parp ); + if ( ! Node2path( parh, path, "set dir extattr" )) { + mlog (MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "tree_extattr_recurse: Could not convert node to ", + "path for %s\n", path); + return BOOL_TRUE; + } + if ( dah != DAH_NULL ) { + ok = ( * cbfunc )( path, dah ); + } else { + ok = BOOL_TRUE; + } + + return ok; +} +#endif /* EXTATTR */ + +struct phcb { + char *path1; + char *path2; + bool_t ok; +}; + +typedef struct phcb phcb_t; + +static bool_t proc_hardlinks_cb( void *contextp, nh_t hardheadh ); + +static bool_t +proc_hardlinks( char *path1, char *path2 ) +{ + phcb_t phcb; + + /* have callback invoked for all hardheads + */ + phcb.path1 = path1; + phcb.path2 = path2; + phcb.ok = BOOL_TRUE; + link_headiter( proc_hardlinks_cb, ( void * )&phcb ); + return phcb.ok; +} + +/* called for every hard head + */ +static bool_t +proc_hardlinks_cb( void *contextp, nh_t hardheadh ) +{ + phcb_t *phcbp = ( phcb_t * )contextp; + node_t *hardheadp; + xfs_ino_t ino; + gen_t gen; + bool_t isdirpr; + nh_t rnsrcheadh; + nh_t rndstheadh; + nh_t lnsrch; + nh_t nh; + link_iter_context_t link_iter_context; + bool_t ok; + intgen_t rval; + + /* skip directories + */ + hardheadp = Node_map( hardheadh ); + ino = hardheadp->n_ino; + gen = hardheadp->n_gen; + isdirpr = hardheadp->n_flags & NF_ISDIR; + Node_unmap( hardheadh, &hardheadp ); + if ( isdirpr ) { + return BOOL_TRUE; + } + + mlog( MLOG_DEBUG | MLOG_TREE, + "processing hardlinks to %llu %u\n", + ino, + gen ); + + /* first pass through hard link list: for each node, leave on + * list, unlink and place on rename src list, unlink and place on + * rename dst list, or unlink and discard. note a node available + * to link from, in case we need it. + */ + rnsrcheadh = NH_NULL; + rndstheadh = NH_NULL; + lnsrch = NH_NULL; + link_iter_init( &link_iter_context, hardheadh ); + while ( ( nh = link_iter_next( &link_iter_context )) != NH_NULL ) { + + node_t *np = Node_map( nh ); + bool_t isrealpr = np->n_flags & NF_REAL; + bool_t isrefpr = np->n_flags & NF_REFED; + bool_t isselpr = np->n_flags & NF_SUBTREE; + + /* if unrefed, unreal, free node etc. (sel doesn't matter) + */ + if ( (! isrealpr && ! isrefpr && ! isselpr) + || + (! isrealpr && ! isrefpr && isselpr) ) { + mlog( MLOG_NITTY | MLOG_TREE, + "freeing node %x: not real, not referenced\n", + nh ); + link_iter_unlink( &link_iter_context, nh ); + Node_unmap( nh, &np ); + ( void )disown( nh ); + Node_free( &nh ); + continue; + } + + /* not real, refed, but not selected, can't help + */ + if ( ! isrealpr && isrefpr && ! isselpr ) { + mlog( MLOG_NITTY | MLOG_TREE, + "skipping node %x: not selected\n", + nh ); + Node_unmap( nh, &np ); + continue; + } + + /* if unreal, refed, sel, add to dst list, + */ + if ( ! isrealpr && isrefpr && isselpr ) { + mlog( MLOG_NITTY | MLOG_TREE, + "making node %x dst: " + "not real, refed, sel\n", + nh ); + link_iter_unlink( &link_iter_context, nh ); + np->n_lnkh = rndstheadh; + rndstheadh = nh; + Node_unmap( nh, &np ); + continue; + } + + /* if real, unrefed, sel, add to src list + */ + if ( isrealpr && ! isrefpr && isselpr ) { + mlog( MLOG_NITTY | MLOG_TREE, + "making node %x src: real, not refed, sel\n", + nh ); + link_iter_unlink( &link_iter_context, nh ); + np->n_lnkh = rnsrcheadh; + rnsrcheadh = nh; + Node_unmap( nh, &np ); + continue; + } + + /* would like to get rid of but not selected, or + * real and referenced, leave alone (sel doesn't matter). + * consider as a lnk src, since real and not going away. + */ + if ( (isrealpr && ! isrefpr && ! isselpr) + || + (isrealpr && isrefpr && ! isselpr) + || + (isrealpr && isrefpr && isselpr) ) { + mlog( MLOG_NITTY | MLOG_TREE, + "skipping node %x: %s\n", + nh, + isselpr ? "real and ref" : "real and not sel" ); + Node_unmap( nh, &np ); + if ( lnsrch == NH_NULL ) { + mlog( MLOG_NITTY | MLOG_TREE, + "node %x will be link src\n", + nh ); + lnsrch = nh; + } + continue; + } + ASSERT( 0 ); + } + + /* now pass through dst list, doing renames if src list not empty, + * otherwise links if a lnk src available, otherwise put back in link + * list + */ + while ( rndstheadh != NH_NULL ) { + nh_t dsth; + node_t *dstp; + bool_t successpr; + + dsth = rndstheadh; + dstp = Node_map( dsth ); + rndstheadh = dstp->n_lnkh; + dstp->n_lnkh = NH_NULL; + Node_unmap( dsth, &dstp ); + + /* build pathname to dst + */ + ok = Node2path( dsth, phcbp->path2, "rename to" ); + if ( ! ok ) { + link_in( dsth ); + continue; + } + + successpr = BOOL_FALSE; + while ( ! successpr && rnsrcheadh != NH_NULL ) { + nh_t srch; + nrh_t nrh; + node_t *srcp; + + srch = rnsrcheadh; + srcp = Node_map( srch ); + rnsrcheadh = srcp->n_lnkh; + srcp->n_lnkh = NH_NULL; + Node_unmap( srch, &srcp ); + + /* build a path to src + */ + ok = Node2path( srch, phcbp->path1, "rename from" ); + if ( ! ok ) { + link_in( srch ); + continue; + } + + if ( tranp->t_toconlypr ) { + rval = 0; + } else { + mlog( MLOG_TRACE | MLOG_TREE, + "rename nondir %s to %s\n", + phcbp->path1, + phcbp->path2 ); + rval = rename( phcbp->path1, + phcbp->path2 ); + } + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "unable to rename nondir " + "%s to %s: %s\n", + phcbp->path1, + phcbp->path2, + strerror( errno )); + link_in( srch ); + continue; + } + + nrh = disown( srch ); + if ( nrh != NRH_NULL ) { + namreg_del( nrh ); + } + Node_free( &srch ); + + successpr = BOOL_TRUE; + } + + while ( ! successpr && lnsrch != NH_NULL ) { + ok = Node2path( lnsrch, phcbp->path1, "link" ); + + if ( ! ok ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "unable to use %s " + "as a hard link source\n", + phcbp->path1 ); + lnsrch = NH_NULL; + continue; + } + + if ( tranp->t_toconlypr ) { + rval = 0; + } else { + mlog( MLOG_TRACE | MLOG_TREE, + "link nondir %s to %s\n", + phcbp->path1, + phcbp->path2 ); + rval = link( phcbp->path1, + phcbp->path2 ); + } + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "unable to link nondir " + "%s to %s: %s\n", + phcbp->path1, + phcbp->path2, + strerror( errno )); + break; + } + successpr = BOOL_TRUE; + } + + if ( ! successpr ) { + mlog( MLOG_NITTY | MLOG_TREE, + "no link src for node %x\n", + dsth ); + } else { + dstp = Node_map( dsth ); + dstp->n_flags |= NF_REAL; + Node_unmap( dsth, &dstp ); + } + + link_in( dsth ); + } + + /* finally, pass through remaining src list, unlinking/disowning. + */ + while ( rnsrcheadh != NH_NULL ) { + nh_t srch; + node_t *srcp; + bool_t ok; + + srch = rnsrcheadh; + srcp = Node_map( srch ); + rnsrcheadh = srcp->n_lnkh; + srcp->n_lnkh = NH_NULL; + Node_unmap( srch, &srcp ); + + ok = Node2path( srch, phcbp->path1, "unlink" ); + if ( ! ok ) { + link_in( srch ); + continue; + } + + if ( tranp->t_toconlypr ) { + rval = 0; + } else { + mlog( MLOG_TRACE | MLOG_TREE, + "unlink nondir %s\n", + phcbp->path1 ); + rval = unlink( phcbp->path1 ); + } + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "unable to unlink %s: %s\n", + phcbp->path1, + strerror( errno )); + link_in( srch ); + } else { + nrh_t nrh; + nrh = disown( srch ); + if ( nrh != NRH_NULL ) { + namreg_del( nrh ); + } + Node_free( &srch ); + } + } + + return BOOL_TRUE; +} + +/* traverse tree depth-wise bottom-up for dirs no longer referenced. + * if non-empty, move children to orphanage + */ +bool_t +tree_setattr( char *path ) +{ + bool_t ok; + ok = tree_setattr_recurse( persp->p_rooth, path ); + return ok; +} + +static bool_t +tree_setattr_recurse( nh_t parh, char *path ) +{ + node_t *parp = Node_map( parh ); + nh_t cldh = parp->n_cldh; + Node_unmap( parh, &parp ); + while ( cldh != NH_NULL ) { + nh_t nextcldh; + + /* get the node attributes + */ + node_t *cldp = Node_map( cldh ); + bool_t isdirpr = ( cldp->n_flags & NF_ISDIR ); + bool_t isselpr = ( cldp->n_flags & NF_SUBTREE ); + bool_t isrealpr = ( cldp->n_flags & NF_REAL ); + dah_t dah = cldp->n_dah; + + /* get next cld + */ + nextcldh = cldp->n_sibh; + Node_unmap( cldh, &cldp ); + + /* if is a real selected dir, go ahead + */ + if ( isdirpr && isselpr && isrealpr ) { + bool_t ok; + ok = tree_setattr_recurse( cldh, path ); /* RECURSION */ + if ( ! ok ) { + Node_unmap( cldh, &cldp ); + return BOOL_FALSE; + } + if ( dah != DAH_NULL ) { + bool_t ok; + ok = Node2path( cldh, path, "set dirattr" ); + if ( ok ) { + setdirattr( dah, path ); + } + } + } + + cldh = nextcldh; + } + + return BOOL_TRUE; +} + +static void +setdirattr( dah_t dah, char *path ) +{ + mode_t mode; + struct utimbuf utimbuf; + /* REFERENCED */ + struct fsxattr fsxattr; /* can we get rid of this? */ + intgen_t rval; + + fsxattr.fsx_xflags = dirattr_get_xflags( dah ); + fsxattr.fsx_extsize = dirattr_get_extsize( dah ); + +#ifdef F_FSSETDM + if ( persp->p_restoredmpr ) { + size_t hlen; + void *hanp; + fsdmidata_t fssetdm; + intgen_t fd; + + fssetdm.fsd_dmevmask = dirattr_get_dmevmask( dah ); + fssetdm.fsd_padding = 0; /* not used */ + fssetdm.fsd_dmstate = ( u_int16_t )dirattr_get_dmstate( dah ); + + /* restore DMAPI event settings etc. + */ + if (path_to_handle(path, &hanp, &hlen)) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "path_to_handle of %s failed:%s\n", + path, strerror( errno )); + return; + } + + fd = open_by_handle(hanp, hlen, O_RDONLY); + if (fd < 0) { + mlog( MLOG_NORMAL | MLOG_WARNING, + "open_by_handle of %s failed:%s\n", + path, strerror( errno )); + free_handle(hanp, hlen); + return; + } + free_handle(hanp, hlen); + rval = fcntl( fd, + F_FSSETDM, + ( void * )&fssetdm ); + if ( rval ) { + mlog( errno == EINVAL + ? + ( MLOG_NITTY + 1 ) | MLOG_TREE + : + MLOG_NITTY | MLOG_TREE, + "set DMI attributes" + " of %s failed: %s\n", + path, + strerror( errno )); + } + ( void )close( fd ); + } +#endif /* F_FSSETDM */ + + utimbuf.actime = dirattr_get_atime( dah ); + utimbuf.modtime = dirattr_get_mtime( dah ); + rval = utime( path, &utimbuf ); + if ( rval ) { + mlog( MLOG_VERBOSE | MLOG_TREE, + "could not set access and modification times" + " of %s: %s\n", + path, + strerror( errno )); + } + mode = dirattr_get_mode( dah ); + if ( persp->p_ownerpr ) { + rval = chown( path, + dirattr_get_uid( dah ), + dirattr_get_gid( dah )); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_TREE, + "chown (uid=%d, gid=%d) %s failed: %s\n", + dirattr_get_uid( dah ), + dirattr_get_gid( dah ), + path, + strerror( errno )); + } + } + rval = chmod( path, mode ); + if ( rval ) { + mlog( MLOG_NORMAL | MLOG_TREE, + "chmod %s failed: %s\n", + path, + strerror( errno )); + } +} + +/* deletes orphanage if empty, else warns + */ +bool_t +tree_delorph( void ) +{ + intgen_t rval; + + rval = rmdir( tranp->t_orphdir ); + if ( rval ) { + if ( errno == EEXIST ) { + mlog(MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "unable to rmdir %s: not empty\n", + tranp->t_orphdir ); + } else { + mlog(MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "unable to rmdir %s: %s\n", + tranp->t_orphdir, + strerror( errno )); + } + } + + return BOOL_TRUE; +} + + +/* definition of locally defined static functions ****************************/ + + +/* interactive subtree abstraction *******************************************/ + +static void tsi_cmd_inst( void *, dlog_pcbp_t, void * ); +static void tsi_cmd_pwd( void *, dlog_pcbp_t, void * ); +static void tsi_cmd_ls( void *, dlog_pcbp_t, void * ); +static void tsi_cmd_cd( void *, dlog_pcbp_t, void * ); +static void tsi_cmd_add( void *, dlog_pcbp_t, void * ); +static void tsi_cmd_delete( void *, dlog_pcbp_t, void * ); +static void tsi_cmd_extract( void *, dlog_pcbp_t, void * ); +static void tsi_cmd_quit( void *, dlog_pcbp_t, void * ); +static void tsi_cmd_help( void *, dlog_pcbp_t, void * ); +static void tsi_cmd_parse( char * ); +static dlog_ucbp_t tsi_cmd_match( void ); + +#define PREAMBLEMAX 3 +#define ACKMAX 3 +#define POSTAMBLEMAX 3 + +bool_t +tree_subtree_inter( void ) +{ + fold_t fold; + char *preamblestr[ PREAMBLEMAX ]; + size_t preamblecnt; + char *ackstr[ ACKMAX ]; + size_t ackcnt; + char *postamblestr[ POSTAMBLEMAX ]; + size_t postamblecnt; + + dlog_ucbp_t cmdp; + +restart: + /* make the current working directory the root of the fs + */ + tranp->t_inter.i_cwdh = persp->p_rooth; + + /* begin the dialog + */ + preamblecnt = 0; + fold_init( fold, "subtree selection dialog", '=' ); + preamblestr[ preamblecnt++ ] = "\n"; + preamblestr[ preamblecnt++ ] = fold; + preamblestr[ preamblecnt++ ] = "\n\n"; + ASSERT( preamblecnt <= PREAMBLEMAX ); + dlog_begin( preamblestr, preamblecnt ); + + /* execute commands until time to extract or quit. always begin with + * an implicit instructions command. if see SIGINT, give main thread + * dialog a chance to decide if a session interrupt is wanted. + */ + cmdp = tsi_cmd_inst; + do { + char buf[ MAXPATHLEN ]; + const ix_t abortix = 1; + const ix_t sigintix = 2; + const ix_t okix = 3; + ix_t responseix; + + /* execute command and get response + */ + responseix = dlog_string_query( cmdp, + 0, + buf, + sizeof( buf ), + 0, + IXMAX, /* timeout ix */ + sigintix, /* sigint ix */ + abortix, /* sighup ix */ + abortix, /* sigquit ix */ + okix ); /* ok ix */ + + /* ack the response + */ + ackcnt = 0; + if ( responseix == sigintix ) { + ackstr[ ackcnt++ ] = "keyboard interrupt\n"; + } else if ( responseix == abortix ) { + ackstr[ ackcnt++ ] = "abort\n"; + } else { + ASSERT( responseix == okix ); + } + ASSERT( ackcnt <= ACKMAX ); + dlog_string_ack( ackstr, + ackcnt ); + + /* exception handling + */ + if ( responseix != okix ) { + /* if exception, end the dialog. may restart + * if operator decidesd not to intr. + */ + postamblecnt = 0; + fold_init( fold, "end dialog", '-' ); + postamblestr[ postamblecnt++ ] = "\n"; + postamblestr[ postamblecnt++ ] = fold; + postamblestr[ postamblecnt++ ] = "\n\n"; + ASSERT( postamblecnt <= POSTAMBLEMAX ); + dlog_end( postamblestr, postamblecnt ); + + /* if sighup or sigquit, immediately quit + */ + if ( responseix == abortix ) { + return BOOL_FALSE; + } + + /* if sigint, allow main thread to decide if + * operator really wants to quit + */ + ASSERT( responseix == sigintix ); + if ( cldmgr_stop_requested( )) { + return BOOL_FALSE; + } + sleep( 1 ); /* to allow main thread to begin dialog */ + mlog( MLOG_NORMAL | MLOG_BARE | MLOG_TREE, + "" ); /* block until main thread dialog done */ + sleep( 1 ); /* let main thread ask children to die */ + if ( cldmgr_stop_requested( )) { + return BOOL_FALSE; + } + mlog( MLOG_DEBUG | MLOG_TREE, + "retrying interactive subtree selection dialog\n" ); + goto restart; + } + + + tsi_cmd_parse( buf ); + cmdp = tsi_cmd_match( ); + if ( ! cmdp ) { + cmdp = tsi_cmd_help; + } + } while ( cmdp != tsi_cmd_quit && cmdp != tsi_cmd_extract ); + + postamblecnt = 0; + fold_init( fold, "end dialog", '-' ); + postamblestr[ postamblecnt++ ] = "\n"; + postamblestr[ postamblecnt++ ] = fold; + postamblestr[ postamblecnt++ ] = "\n\n"; + ASSERT( postamblecnt <= POSTAMBLEMAX ); + dlog_end( postamblestr, postamblecnt ); + + /* pv 773569 - quit is not a reason to consider session + * to be interrupted (we haven't started yet) so just unmark + * any selected directories and return */ + if ( cmdp == tsi_cmd_quit ) { + mlog (MLOG_NORMAL, "Unmark and quit\n"); + selsubtree (persp->p_rooth , BOOL_FALSE ); + } + + return BOOL_TRUE; +} + +static void +tsi_cmd_inst( void *ctxp, + dlog_pcbp_t pcb, + void *pctxp ) +{ + tsi_cmd_help( ctxp, pcb, pctxp ); +} + +static void +tsi_cmd_pwd( void *ctxp, + dlog_pcbp_t pcb, + void *pctxp ) +{ + /* special case root + */ + if ( tranp->t_inter.i_cwdh == persp->p_rooth ) { + ( * pcb )( pctxp, "cwd is fs root\n" ); + return; + } + + /* ascend tree recursively, print path on way back + */ + tsi_cmd_pwd_recurse( ctxp, pcb, pctxp, tranp->t_inter.i_cwdh ); + ( * pcb )( pctxp, "\n" ); +} + +static void +tsi_cmd_pwd_recurse( void *ctxp, + dlog_pcbp_t pcb, + void *pctxp, + nh_t nh ) +{ + node_t *np; + register nh_t parh; + /* REFERENCED */ + register intgen_t namelen; + nrh_t nrh; + + ASSERT( nh != NH_NULL ); + + np = Node_map( nh ); + nrh = np->n_nrh; + parh = np->n_parh; + Node_unmap( nh, &np ); + if ( parh != persp->p_rooth ) { + tsi_cmd_pwd_recurse( ctxp, pcb, pctxp, parh ); + /* RECURSION */ + ( * pcb )( pctxp, "/" ); + } + ASSERT( nrh != NRH_NULL ); + namelen = namreg_get( nrh, + tranp->t_inter.i_name, + sizeof( tranp->t_inter.i_name )); + ASSERT( namelen > 0 ); + ( * pcb )( pctxp, tranp->t_inter.i_name ); +} + +/* ARGSUSED */ +static void +tsi_cmd_ls( void *ctxp, + dlog_pcbp_t pcb, + void *pctxp ) +{ + size_t argc = tranp->t_inter.i_argc; + char *arg = ( argc > 1 ) ? tranp->t_inter.i_argv[ 1 ] : 0; + bool_t ok; + + nh_t cldh; + nh_t parh; + nh_t namedh; + xfs_ino_t ino; + bool_t isdirpr; + bool_t isselpr; + + /* walk the tree according to the path argument, to get + * the named node. + */ + ok = tsi_walkpath( arg, + persp->p_rooth, + tranp->t_inter.i_cwdh, + pcb, + pctxp, + &namedh, + &parh, + &cldh, + &ino, + &isdirpr, + &isselpr ); + if ( ! ok ) { + return; + } + + /* if named is not a dir, just display named + */ + if ( ! isdirpr ) { + ( * pcb )( pctxp, + " %s %10llu %s%s\n", + isselpr ? "*" : " ", + ino, + tranp->t_inter.i_name, + isdirpr ? "/" : " " ); + + return; + } + + /* iterate through the directory, printing all matching entries. + * hide the orphanage. + */ + while ( cldh != NH_NULL ) { + node_t *cldp; + nrh_t nrh; + nh_t nextcldh; + cldp = Node_map( cldh ); + nrh = cldp->n_nrh; + nextcldh = cldp->n_sibh; + isdirpr = ( cldp->n_flags & NF_ISDIR ); + isselpr = ( cldp->n_flags & NF_SUBTREE ); + ino = cldp->n_ino; + Node_unmap( cldh, &cldp ); + if ( cldh != persp->p_orphh ) { + /* REFERENCED */ + intgen_t namelen; + namelen = namreg_get( nrh, + tranp->t_inter.i_name, + sizeof( tranp->t_inter.i_name )); + ASSERT( namelen > 0 ); + ( * pcb )( pctxp, + " %s %10llu %s%s\n", + isselpr ? "*" : " ", + ino, + tranp->t_inter.i_name, + isdirpr ? "/" : " " ); + } + cldh = nextcldh; + } +} + +/* ARGSUSED */ +static void +tsi_cmd_cd( void *ctxp, + dlog_pcbp_t pcb, + void *pctxp ) +{ + size_t argc = tranp->t_inter.i_argc; + char *arg = ( argc > 1 ) ? tranp->t_inter.i_argv[ 1 ] : 0; + + nh_t cldh; + nh_t parh; + nh_t namedh; + xfs_ino_t ino; + bool_t isdirpr; + bool_t isselpr; + bool_t ok; + + /* walk the tree according to the path argument, to get + * the named node. + */ + ok = tsi_walkpath( arg, + persp->p_rooth, + tranp->t_inter.i_cwdh, + pcb, + pctxp, + &namedh, + &parh, + &cldh, + &ino, + &isdirpr, + &isselpr ); + if ( ! ok ) { + return; + } + + /* if named is not a dir, complain + */ + if ( ! isdirpr ) { + ASSERT( arg ); + ( * pcb )( pctxp, + "%s is not a directory\n", + arg ); + + return; + } + + /* change the current working directory + */ + tranp->t_inter.i_cwdh = namedh; +} + +/* ARGSUSED */ +static void +tsi_cmd_add( void *ctxp, + dlog_pcbp_t pcb, + void *pctxp ) +{ + size_t argc = tranp->t_inter.i_argc; + char *arg = ( argc > 1 ) ? tranp->t_inter.i_argv[ 1 ] : 0; + + nh_t cldh; + nh_t parh; + nh_t namedh; + xfs_ino_t ino; + bool_t isdirpr; + bool_t isselpr; + bool_t ok; + + /* walk the tree according to the path argument, to get + * the named node. + */ + ok = tsi_walkpath( arg, + persp->p_rooth, + tranp->t_inter.i_cwdh, + pcb, + pctxp, + &namedh, + &parh, + &cldh, + &ino, + &isdirpr, + &isselpr ); + if ( ! ok ) { + return; + } + + selsubtree( namedh, BOOL_TRUE ); +} + +/* ARGSUSED */ +static void +tsi_cmd_delete( void *ctxp, + dlog_pcbp_t pcb, + void *pctxp ) +{ + size_t argc = tranp->t_inter.i_argc; + char *arg = ( argc > 1 ) ? tranp->t_inter.i_argv[ 1 ] : 0; + + nh_t cldh; + nh_t parh; + nh_t namedh; + xfs_ino_t ino; + bool_t isdirpr; + bool_t isselpr; + bool_t ok; + + /* walk the tree according to the path argument, to get + * the named node. + */ + ok = tsi_walkpath( arg, + persp->p_rooth, + tranp->t_inter.i_cwdh, + pcb, + pctxp, + &namedh, + &parh, + &cldh, + &ino, + &isdirpr, + &isselpr ); + if ( ! ok ) { + return; + } + + selsubtree( namedh, BOOL_FALSE ); +} + +/* ARGSUSED */ +static void +tsi_cmd_extract( void *ctxp, + dlog_pcbp_t pcb, + void *pctxp ) +{ +} + +/* ARGSUSED */ +static void +tsi_cmd_quit( void *ctxp, + dlog_pcbp_t pcb, + void *pctxp ) +{ +} + +#ifdef WHITEPARSE + +static int parse( int slotcnt, char **slotbuf, char *string ); + +static void +tsi_cmd_parse( char *buf ) +{ + int wordcnt; + + if ( ! buf ) { + tranp->t_inter.i_argc = 0; + return; + } + + wordcnt = parse( INTER_ARGMAX, tranp->t_inter.i_argv, buf ); + + tranp->t_inter.i_argc = ( size_t )min( max( 0, wordcnt ), INTER_ARGMAX ); +} + +#else /* WHITEPARSE */ + +static void +tsi_cmd_parse( char *buf ) +{ + size_t argc; + char *t; + char *b; + + if ( ! buf ) { + tranp->t_inter.i_argc = 0; + return; + } + + argc = 0; + b = buf; + while ( argc < INTER_ARGMAX && ( t = strtok( b, " \t" )) != 0 ) { + tranp->t_inter.i_argv[ argc++ ] = t; + b = 0; + } + tranp->t_inter.i_argc = argc; +} + +#endif /* WHITEPARSE */ + +struct tsi_cmd_tbl { + char *tct_pattern; + char *tct_help; + dlog_ucbp_t tct_ucb; + size_t tct_argcmin; + size_t tct_argcmax; +}; + +typedef struct tsi_cmd_tbl tsi_cmd_tbl_t; + +static tsi_cmd_tbl_t tsi_cmd_tbl[] = { + { "pwd", "", tsi_cmd_pwd, 1, 1 }, + { "ls", "[ ]", tsi_cmd_ls, 1, 2 }, + { "cd", "[ ]", tsi_cmd_cd, 1, 2 }, + { "add", "[ ]", tsi_cmd_add, 1, 2 }, + { "delete", "[ ]", tsi_cmd_delete, 1, 2 }, + { "extract", "", tsi_cmd_extract,1, 1 }, + { "quit", "", tsi_cmd_quit, 1, 1 }, + { "help", "", tsi_cmd_help, 1, 1 }, +}; + +static dlog_ucbp_t +tsi_cmd_match( void ) +{ + tsi_cmd_tbl_t *tblp = tsi_cmd_tbl; + tsi_cmd_tbl_t *tblendp = tsi_cmd_tbl + + + sizeof( tsi_cmd_tbl ) + / + sizeof( tsi_cmd_tbl[ 0 ] ); + + if ( tranp->t_inter.i_argc == 0 ) { + return 0; + } + + for ( ; tblp < tblendp ; tblp++ ) { + if ( ! strncmp( tranp->t_inter.i_argv[ 0 ], + tblp->tct_pattern, + strlen( tranp->t_inter.i_argv[ 0 ] ))) { + break; + } + } + + if ( tblp == tblendp ) { + return 0; + } + + ASSERT( tblp->tct_argcmin != 0 ); + if ( tranp->t_inter.i_argc < tblp->tct_argcmin ) { + return 0; + } + + if ( tranp->t_inter.i_argc > tblp->tct_argcmax ) { + return 0; + } + + return tblp->tct_ucb; +} + +/* ARGSUSED */ +static void +tsi_cmd_help( void *ctxp, + dlog_pcbp_t pcb, + void *pctxp ) +{ + tsi_cmd_tbl_t *tblp = tsi_cmd_tbl; + tsi_cmd_tbl_t *tblendp = tsi_cmd_tbl + + + sizeof( tsi_cmd_tbl ) + / + sizeof( tsi_cmd_tbl[ 0 ] ); + + ( * pcb )( pctxp, "the following commands are available:\n" ); + for ( ; tblp < tblendp ; tblp++ ) { + ( * pcb )( pctxp, + "\t%s %s\n", + tblp->tct_pattern, + tblp->tct_help ); + } +} + +/* walks the tree following the given path. + * returns FALSE if syntax error encountered. + * returns by reference handles to the named node, its parent, + * the first child in its cld list, its ino, if it is a directory, + * and if it is selected. + * optionally given a dlog print func and context, to be used for diag output. + */ +static bool_t +tsi_walkpath( char *arg, nh_t rooth, nh_t cwdh, + dlog_pcbp_t pcb, void *pctxp, + nh_t *namedhp, nh_t *parhp, nh_t *cldhp, + xfs_ino_t *inop, bool_t *isdirprp, bool_t *isselprp ) +{ + nh_t namedh; + nh_t parh; + nh_t cldh; + node_t *namedp; + char *path; + char nbuf[ NAME_MAX ]; + xfs_ino_t ino; + bool_t isdirpr; + bool_t isselpr; + + + /* correct arg if ends with slash (if arg is "/", ok) + */ + if ( arg && strlen( arg ) > 1 && arg[ strlen( arg ) - 1 ] == '/' ) { + arg[ strlen( arg ) - 1 ] = 0; + } + + /* use path to walk down the path argument + */ + path = arg; + + /* walk the tree beginning either at the root node + * or at the current working directory + */ + if ( path && *path == '/' ) { + ASSERT( rooth != NH_NULL ); + namedh = rooth; + path++; + } else { + ASSERT( cwdh != NH_NULL ); + namedh = cwdh; + } + + /* get the parent of the starting point, and its cld list + */ + namedp = Node_map( namedh ); + parh = namedp->n_parh; + cldh = namedp->n_cldh; + ino = namedp->n_ino; + isselpr = ( namedp->n_flags & NF_SUBTREE ); + ASSERT( namedp->n_flags & NF_ISDIR ); + Node_unmap( namedh, &namedp ); + isdirpr = BOOL_TRUE; + + /* walk the tree from the starting point following the path arg. + * on leaving this loop, the following will be valid: + * namedh - the handle of the node named by path arg; + * parh - the parent of the named node; + * isdirpr - TRUE if named node is a directory; + * cldh - the first child in the named node's cld list. + */ + for ( ; ; ) { + size_t namelen; + char *strpatchp; + nh_t sibh; + + /* if no path arg, break + */ + if ( ! path ) { + break; + } + + /* clean out leading slashes. these can occur if the + * path arg is ".../////..." or "////..." + */ + while ( *path == '/' ) { + path++; + } + + /* if empty path arg, break + */ + if ( ! strlen( path )) { + break; + } + + /* copy the first name from the path, and advance + * the path pointer. + */ + namelen = strcspn( path, "/" ); + ASSERT( namelen < sizeof( nbuf )); + strncpy( nbuf, path, namelen ); + nbuf[ namelen ] = 0; + path += namelen; + if ( *path ) { + ASSERT( *path == '/' ); + strpatchp = path; + *strpatchp = 0; + path++; + } else { + strpatchp = 0; + } + + /* be sure the named node is a dir + */ + if ( ! isdirpr ) { + if ( pcb ) { + ( * pcb )( pctxp, + "parent of %s is not a directory\n", + arg ); + } + return BOOL_FALSE; + } + + /* special case "." + */ + if ( ! strcmp( nbuf, "." )) { + if ( strpatchp ) { + *strpatchp = '/'; + } + continue; + } + + /* special case ".." + */ + if ( ! strcmp( nbuf, ".." )) { + if ( parh == NH_NULL ) { + if ( pcb ) { + ( * pcb )( pctxp, + "%s above root\n", + arg ); + } + return BOOL_FALSE; + } + namedh = parh; + namedp = Node_map( namedh ); + parh = namedp->n_parh; + cldh = namedp->n_cldh; + ino = namedp->n_ino; + isselpr = ( namedp->n_flags & NF_SUBTREE ); + Node_unmap( namedh, &namedp ); + if ( strpatchp ) { + *strpatchp = '/'; + } + continue; + } + + /* look for child with right name + */ + sibh = cldh; + while ( sibh != NH_NULL ) { + node_t *sibp; + nh_t nextsibh; + nrh_t nrh; + /* REFERENCED */ + intgen_t siblen; + + sibp = Node_map( sibh ); + nrh = sibp->n_nrh; + nextsibh = sibp->n_sibh; + cldh = sibp->n_cldh; + ino = sibp->n_ino; + isselpr = ( sibp->n_flags & NF_SUBTREE ); + isdirpr = ( sibp->n_flags & NF_ISDIR ); + Node_unmap( sibh, &sibp ); + ASSERT( nrh != NRH_NULL || sibh == persp->p_orphh ); + if ( nrh != NRH_NULL ) { + siblen = namreg_get( nrh, + tranp->t_inter.i_name, + sizeof( tranp->t_inter.i_name )); + ASSERT( siblen > 0 ); + if ( ! strcmp( nbuf, tranp->t_inter.i_name )) { + break; + } + } + sibh = nextsibh; + } + + /* if no match, complain + */ + if ( sibh == NH_NULL ) { + if ( pcb ) { + ( * pcb )( pctxp, + "%s not found\n", + arg ); + } + return BOOL_FALSE; + } + + /* continue search. cldh, ino and isdirpr + * set in inner loop above + */ + parh = namedh; + namedh = sibh; + if ( strpatchp ) { + *strpatchp = '/'; + } + } + *namedhp = namedh; + *parhp = parh; + *cldhp = cldh; + *inop = ino; + *isdirprp = isdirpr; + *isselprp = isselpr; + + return BOOL_TRUE; +} + +/* Node abstraction *********************************************************/ + +static nh_t +Node_alloc( xfs_ino_t ino, gen_t gen, nrh_t nrh, dah_t dah, size_t flags ) +{ + nh_t nh; + node_t *np; + + nh = node_alloc( ); + ASSERT( nh != NH_NULL ); + np = Node_map( nh ); + np->n_ino = ino; + np->n_nrh = nrh; + np->n_dah = dah; + np->n_hashh = NH_NULL; + np->n_parh = NH_NULL; + np->n_sibh = NH_NULL; + np->n_cldh = NH_NULL; + np->n_lnkh = NH_NULL; + np->n_gen = gen; + np->n_flags = ( u_char_t )flags; + Node_unmap( nh, &np ); + return nh; +} + +static void +Node_free( nh_t *nhp ) +{ + node_t *np; + np = Node_map( *nhp ); + np->n_ino = 0; + np->n_gen = 0; + if ( np->n_nrh != NRH_NULL ) { + namreg_del( np->n_nrh ); + np->n_nrh = NRH_NULL; + } + if ( np->n_dah != NRH_NULL ) { + dirattr_del( np->n_dah ); + np->n_dah = NRH_NULL; + } + np->n_flags = 0; + np->n_parh = NH_NULL; + np->n_sibh = NH_NULL; + np->n_cldh = NH_NULL; + np->n_lnkh = NH_NULL; + Node_unmap( *nhp, &np ); + node_free( nhp ); +} + +static node_t * +Node_map( nh_t nh ) +{ + return ( node_t * )node_map( nh ); +} + +static void +Node_unmap( nh_t nh, node_t **npp ) +{ + node_unmap( nh, ( void ** )npp ); +} + +/* builds a pathname for the specified node, relative to root + * returns FALSE if pathname too long + */ +static bool_t +Node2path( nh_t nh, char *path, char *errmsg ) +{ + intgen_t remainingcnt; + path[ 0 ] = 0; /* in case root node passed in */ + remainingcnt = Node2path_recurse( nh, path, MAXPATHLEN ); + if ( remainingcnt <= 0 ) { + node_t *np = Node_map( nh ); + xfs_ino_t ino = np->n_ino; + gen_t gen = np->n_gen; + Node_unmap( nh, &np ); + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "unable %s ino %llu gen %u: " + "relative pathname too long (partial %s)\n", + errmsg, + ino, + gen, + path ); + return BOOL_FALSE; + } else { + return BOOL_TRUE; + } +} + +/* returns how much of the buffer remains, assuming the buffer size is + * MAXPATHLEN. always null-terminates, but null char not counted in return. + * works because the buffer size is secretly 2 * MAXPATHLEN. + */ +static intgen_t +Node2path_recurse( nh_t nh, char *buf, intgen_t bufsz ) +{ + node_t *np; + nh_t parh; + xfs_ino_t ino; + gen_t gen; + nrh_t nrh; + intgen_t oldbufsz; + intgen_t namelen; + + /* recursion termination + */ + if ( nh == persp->p_rooth ) { + return bufsz; + } + + /* extract useful node members + */ + np = Node_map( nh ); + parh = np->n_parh; + ino = np->n_ino; + gen = np->n_gen; + nrh = np->n_nrh; + Node_unmap( nh, &np ); + + /* build path to parent + */ + oldbufsz = bufsz; + bufsz = Node2path_recurse( parh, buf, bufsz ); /* RECURSION */ + if ( bufsz <= 0 ) { + return bufsz; + } + buf += oldbufsz - bufsz; + + /* insert slash if parent not root + */ + if ( parh != persp->p_rooth ) { + ASSERT( bufsz + MAXPATHLEN >= 2 ); + *buf++ = '/'; + *( buf + 1 ) = 0; + bufsz--; + if ( bufsz <= 0 ) { + return bufsz; + } + } + + /* append entry name: special case if in orphanage + */ + if ( parh == persp->p_orphh ) { + namelen = sprintf( buf, "%llu.%u", (unsigned long long)ino, gen ); + } else if ( nh == persp->p_orphh ) { + namelen = sprintf( buf, "%s", orphname ); + } else { + ASSERT( nrh != NRH_NULL ); + namelen = namreg_get( nrh, buf, ( size_t )bufsz + MAXPATHLEN ); + ASSERT( namelen > 0 ); + } + + /* return remaining buffer size + */ + bufsz -= namelen; + ASSERT( bufsz + MAXPATHLEN > 0 ); + return bufsz; +} + +/* family abstraction *********************************************************/ + +static void +adopt( nh_t parh, nh_t cldh, nrh_t nrh ) +{ + node_t *parp; + node_t *cldp; + + cldp = Node_map( cldh ); + cldp->n_parh = parh; + cldp->n_nrh = nrh; + parp = Node_map( parh ); + cldp->n_sibh = parp->n_cldh; + Node_unmap( cldh, &cldp ); + parp->n_cldh = cldh; + Node_unmap( parh, &parp ); +} + +static nrh_t +disown( nh_t cldh ) +{ + node_t *cldp; + nrh_t nrh; + nh_t parh; + node_t *parp; + + cldp = Node_map( cldh ); + + nrh = cldp->n_nrh; + + parh = cldp->n_parh; + ASSERT( parh != NH_NULL ); + if ( parh == NH_NULL ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "attempt to disown child " + "which has no parent!\n" ); + return nrh; + } + parp = Node_map( parh ); + ASSERT( parp->n_cldh != NH_NULL ); + if ( parp->n_cldh == NH_NULL ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "attempt to disown child " + "when parent has no children!\n" ); + return nrh; + } + if ( parp->n_cldh == cldh ) { + parp->n_cldh = cldp->n_sibh; + } else { + nh_t prevcldh = parp->n_cldh; + node_t *prevcldp = Node_map( prevcldh ); + while ( prevcldp->n_sibh != NH_NULL + && + prevcldp->n_sibh != cldh ) { + nh_t tmph = prevcldp->n_sibh; + Node_unmap( prevcldh, &prevcldp ); + prevcldh = tmph; + prevcldp = Node_map( prevcldh ); + } + ASSERT( prevcldp->n_sibh != NH_NULL ); + if ( prevcldp->n_sibh == NH_NULL ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "attempt to disown child " + "with wrong parent!\n" ); + return nrh; + } + prevcldp->n_sibh = cldp->n_sibh; + Node_unmap( prevcldh, &prevcldp ); + } + Node_unmap( parh, &parp ); + cldp->n_parh = NH_NULL; + cldp->n_sibh = NH_NULL; + Node_unmap( cldh, &cldp ); + + return nrh; +} + +/* recursively marks all nodes in subtree as selected or not selected + * for subtree restoral. adjusts ancestors flags accordingly. also adjusts + * inomap, which will be used by content.c to see if a media file contains + * any nondirs which might need to be restored. + */ +static void +selsubtree( nh_t nh, bool_t sensepr ) +{ + node_t *np; + nh_t parh; + + /* first mark the subtree + */ + selsubtree_recurse_down( nh, sensepr ); + + /* get parent + */ + np = Node_map( nh ); + parh = np->n_parh; + Node_unmap( nh, &np ); + + /* next adjust ancestory + */ + while ( parh != NH_NULL ) { + node_t *parp; + nh_t newparh; + + parp = Node_map( parh ); + if ( sensepr ) { + parp->n_flags |= NF_SUBTREE; + } else { + bool_t atleastonechildselpr = BOOL_FALSE; + nh_t cldh = parp->n_cldh; + while ( cldh != NH_NULL ) { + node_t *cldp; + nh_t nextcldh; + bool_t cldsensepr; + cldp = Node_map( cldh ); + cldsensepr = ( cldp->n_flags & NF_SUBTREE ) + ? + BOOL_TRUE + : + BOOL_FALSE; + nextcldh = cldp->n_sibh; + Node_unmap( cldh, &cldp ); + if ( cldsensepr ) { + atleastonechildselpr = BOOL_TRUE; + break; + } + cldh = nextcldh; + } + if ( ! atleastonechildselpr ) { + parp->n_flags &= ~NF_SUBTREE; + /* DBG could break out here (remember to unmap!) + */ + } + } + newparh = parp->n_parh; + Node_unmap( parh, &parp ); + parh = newparh; + } +} + +static void +selsubtree_recurse_down( nh_t nh, bool_t sensepr ) +{ + nh_t cldh; + + /* first mark the node indicated, and get head of cld list + */ + { + node_t *np; + bool_t isdirpr; + xfs_ino_t ino; + gen_t gen; + + np = Node_map( nh ); + if ( sensepr ) { + np->n_flags |= NF_SUBTREE; + } else { + np->n_flags &= ~NF_SUBTREE; + } + cldh = np->n_cldh; + ino = np->n_ino; + gen = np->n_gen; + isdirpr = ( np->n_flags & NF_ISDIR ); + Node_unmap( nh, &np ); + if ( ! isdirpr ) { + if ( sensepr ) { + inomap_rst_add( ino ); + } else { + /* check hardlist: don't del unless none needed + */ + nh_t nh; + bool_t neededpr = BOOL_FALSE; + for ( nh = link_hardh( ino, gen ) + ; + nh != NH_NULL + ; + nh = link_nexth( nh )) { + node_t *np; + u_char_t flags; + np = Node_map( nh ); + flags = np->n_flags; + Node_unmap( nh, &np ); + if ( flags & NF_SUBTREE ) { + neededpr = BOOL_TRUE; + break; + } + } + if ( ! neededpr ) { + inomap_rst_del( ino ); + } + } + } + } + + /* then mark all of its children. be sure to skip the orphanage!!! + */ + while ( cldh != NH_NULL ) { + node_t *cldp; + nh_t nextcldh; + + if ( cldh != persp->p_orphh ) { + selsubtree_recurse_down( cldh, sensepr ); + } + cldp = Node_map( cldh ); + nextcldh = cldp->n_sibh; + Node_unmap( cldh, &cldp ); + cldh = nextcldh; + } +} + + +/* link abstraction *********************************************************/ + +/* returns handle to head of hard link list + */ +static nh_t +link_hardh( xfs_ino_t ino, gen_t gen ) +{ + return hash_find( ino, gen ); +} + +/* returns following node in hard link list + */ +static nh_t +link_nexth( nh_t nh ) +{ + node_t *np; + nh_t nexth; + + np = Node_map( nh ); + nexth = np->n_lnkh; + Node_unmap( nh, &np ); + return nexth; +} + +/* searches hard link list for exact match. + * returns hard link list head + */ +static nh_t +link_matchh( nh_t hardh, nh_t parh, char *name ) +{ + while ( hardh != NH_NULL ) { + node_t *np; + nh_t nexth; + np = Node_map( hardh ); + if ( np->n_parh == parh ) { + /* REFERENCED */ + intgen_t namelen; + namelen = namreg_get( np->n_nrh, + tranp->t_namebuf, + sizeof( tranp->t_namebuf )); + ASSERT( namelen > 0 ); + if ( ! strcmp( name, tranp->t_namebuf )) { + Node_unmap( hardh, &np ); + break; + } + } + nexth = np->n_lnkh; + Node_unmap( hardh, &np ); + hardh = nexth; + } + return hardh; +} + +static void +link_in( nh_t nh ) +{ + node_t *np; + xfs_ino_t ino; + gen_t gen; + nh_t hardh; + + /* map in the node to read ino and gen + */ + np = Node_map( nh ); + ino = np->n_ino; + gen = np->n_gen; + + /* see if one or more links already hashed. + */ + hardh = hash_find( ino, gen ); + + /* if not hashed, just hash it. otherwise put at end + * of hard link (lnk) list. + */ + if ( hardh == NH_NULL ) { + hash_in( nh ); + } else { + nh_t prevh = hardh; + node_t *prevp = Node_map( prevh ); + while ( prevp->n_lnkh != NH_NULL ) { + nh_t nexth = prevp->n_lnkh; + Node_unmap( prevh, &prevp ); + prevh = nexth; + prevp = Node_map( prevh ); + } + prevp->n_lnkh = nh; + Node_unmap( prevh, &prevp ); + } + + /* since always put at end of hard link list, make node's + * lnk member terminate list. + */ + np->n_lnkh = NH_NULL; + Node_unmap( nh, &np ); +} + +static void +link_out( nh_t nh ) +{ + node_t *np; + xfs_ino_t ino; + gen_t gen; + nh_t hardh; + + /* map in the node to read ino and gen + */ + np = Node_map( nh ); + ino = np->n_ino; + gen = np->n_gen; + + /* get head of hard link list + */ + hardh = hash_find( ino, gen ); + ASSERT( hardh != NH_NULL ); + + /* if node is at head of hard link list, hash it out and + * hash in the following node in link list, if there is one. + * otherwise, unlink from hardlink list. + */ + if ( nh == hardh ) { + hash_out( nh ); + if ( np->n_lnkh != NH_NULL ) { + hash_in( np->n_lnkh ); + } + } else { + nh_t prevh = hardh; + node_t *prevp = Node_map( prevh ); + while ( prevp->n_lnkh != nh ) { + nh_t nexth = prevp->n_lnkh; + Node_unmap( prevh, &prevp ); + prevh = nexth; + ASSERT( prevh != NH_NULL ); + prevp = Node_map( prevh ); + } + prevp->n_lnkh = np->n_lnkh; + Node_unmap( prevh, &prevp ); + } + np->n_lnkh = NH_NULL; + + /* release the mapping + */ + Node_unmap( nh, &np ); +} + +/* invokes callback for all hardheads + * iteration aborted if callback returns FALSE + */ +static void +link_headiter( bool_t ( * cbfp )( void *contextp, nh_t hardh ), void *contextp ) +{ + hash_iter( cbfp, contextp ); +} + +/* iterator for a hard link list. allows deletion of the last node + * returned. + */ +static void +link_iter_init( link_iter_context_t *link_iter_contextp, nh_t hardheadh ) +{ + link_iter_contextp->li_headh = hardheadh; + link_iter_contextp->li_prevh = NH_NULL; + link_iter_contextp->li_lasth = NH_NULL; + link_iter_contextp->li_donepr = BOOL_FALSE; +} + +static nh_t +link_iter_next( link_iter_context_t *link_iter_contextp ) +{ + node_t *lastp; + nh_t tmplasth; + + /* if already done, return + */ + if ( link_iter_contextp->li_donepr == BOOL_TRUE ) { + return NH_NULL; + } + + /* if no hardhead, done + */ + if ( link_iter_contextp->li_headh == NH_NULL ) { + link_iter_contextp->li_donepr = BOOL_TRUE; + return NH_NULL; + } + + /* make tmp copy of last + */ + tmplasth = link_iter_contextp->li_lasth; + + /* if no last, must be first call + */ + if ( tmplasth == NH_NULL ) { + ASSERT( link_iter_contextp->li_prevh == NH_NULL ); + link_iter_contextp->li_lasth = link_iter_contextp->li_headh; + return link_iter_contextp->li_lasth; + } + + /* slide last into prev + */ + link_iter_contextp->li_prevh = tmplasth; + lastp = Node_map( tmplasth ); + link_iter_contextp->li_lasth = lastp->n_lnkh; + Node_unmap( tmplasth, &lastp ); + + /* if NULL, flag done + */ + if ( link_iter_contextp->li_lasth == NH_NULL ) { + link_iter_contextp->li_donepr = BOOL_TRUE; + } + + /* return the last handle + */ + return link_iter_contextp->li_lasth; +} + +/* ARGSUSED */ +void +link_iter_unlink( link_iter_context_t *link_iter_contextp, nh_t nh ) +{ + node_t *lastp; + nh_t nexth; + + /* sanity checks + */ + ASSERT( link_iter_contextp->li_lasth != NH_NULL ); + ASSERT( nh == link_iter_contextp->li_lasth ); + + /* get the next node in list + */ + lastp = Node_map( link_iter_contextp->li_lasth ); + nexth = lastp->n_lnkh; + lastp->n_lnkh = NH_NULL; + Node_unmap( link_iter_contextp->li_lasth, &lastp ); + + if ( link_iter_contextp->li_lasth == link_iter_contextp->li_headh ) { + ASSERT( link_iter_contextp->li_prevh == NH_NULL ); + hash_out( link_iter_contextp->li_headh ); + link_iter_contextp->li_headh = nexth; + if ( nexth != NH_NULL ) { + hash_in( nexth ); + } + } else { + node_t *prevp; + ASSERT( link_iter_contextp->li_prevh != NH_NULL ); + prevp = Node_map( link_iter_contextp->li_prevh ); + prevp->n_lnkh = nexth; + Node_unmap( link_iter_contextp->li_prevh, &prevp ); + } + link_iter_contextp->li_lasth = link_iter_contextp->li_prevh; + link_iter_contextp->li_prevh = NH_NULL; +} + + +/* hash abstraction *********************************************************/ + +#define HASHLEN_MIN ( pgsz / sizeof( nh_t )) + +static bool_t +hash_init( size64_t vmsz, + size64_t dircnt, + size64_t nondircnt, + char *perspath ) +{ + size64_t hashlen; + size64_t loghashlen; + size64_t vmlen; + size64_t hashlenmax; + ix_t hix; + + /* sanity checks + */ + ASSERT( pgsz % sizeof( nh_t ) == 0 ); + + /* calculate the size of the hash array. must be a power of two, + * and a multiple of the page size. don't use more than the available + * vm. but enforce a minimum. + */ + vmlen = vmsz / sizeof( nh_t ); + hashlenmax = min( vmlen, SIZEMAX ); + hashlen = ( dircnt + nondircnt ); + hashlen = max( hashlen, ( size64_t )HASHLEN_MIN ); + hashlen = min( hashlen, hashlenmax ); + + for ( loghashlen = 0 + ; + ( ( size64_t )1 << loghashlen ) <= hashlen + ; + loghashlen++ ) + ; + ASSERT( loghashlen > 0 ); + loghashlen--; + hashlen = ( size64_t )1 << loghashlen; + ASSERT( hashlen <= hashlenmax ); + + /* record hash size in persistent state + */ + persp->p_hashsz = hashlen * sizeof( nh_t ); + + /* map the hash array just after the persistent state header + */ + ASSERT( persp->p_hashsz <= SIZEMAX ); + ASSERT( ! ( persp->p_hashsz % ( size64_t )pgsz )); + ASSERT( ! ( PERSSZ % pgsz )); + tranp->t_hashp = ( nh_t * ) mmap_autogrow( + ( size_t )persp->p_hashsz, + tranp->t_persfd, + ( off64_t )PERSSZ ); + if ( tranp->t_hashp == ( nh_t * )-1 ) { + mlog( MLOG_NORMAL | MLOG_TREE, + "unable to mmap hash array into %s: %s\n", + perspath, + strerror( errno )); + return BOOL_FALSE; + } + + /* initialize the hash array to all NULL node handles + */ + for ( hix = 0 ; hix < ( ix_t )hashlen ; hix++ ) { + tranp->t_hashp[ hix ] = NH_NULL; + } + + /* build a hash mask. this works because hashlen is a power of two. + * record in persistent state. + */ + ASSERT( hashlen - 1 <= SIZEMAX ); + persp->p_hashmask = ( size_t )( hashlen - 1 ); + + return BOOL_TRUE; +} + +static bool_t +hash_sync( char *perspath ) +{ + size64_t hashsz; + + /* sanity checks + */ + ASSERT( pgsz % sizeof( nh_t ) == 0 ); + + /* retrieve the hash size from the persistent state + */ + hashsz = persp->p_hashsz; + ASSERT( ! ( hashsz % sizeof( nh_t ))); + + /* map the hash array just after the persistent state header + */ + ASSERT( hashsz <= SIZEMAX ); + ASSERT( ! ( hashsz % ( size64_t )pgsz )); + ASSERT( ! ( PERSSZ % pgsz )); + tranp->t_hashp = ( nh_t * ) mmap_autogrow( + ( size_t )hashsz, + tranp->t_persfd, + ( off64_t )PERSSZ ); + if ( tranp->t_hashp == ( nh_t * )-1 ) { + mlog( MLOG_NORMAL | MLOG_TREE, + "unable to mmap hash array into %s: %s\n", + perspath, + strerror( errno )); + return BOOL_FALSE; + } + + return BOOL_TRUE; +} + +static void +hash_in( nh_t nh ) +{ + node_t *np; + xfs_ino_t ino; + size_t hix; + nh_t *entryp; + + /* get a mapping to the node + */ + np = Node_map( nh ); + + /* get ino from node + */ + ino = np->n_ino; + + /* assert not already in + */ + ASSERT( hash_find( np->n_ino, np->n_gen ) == NH_NULL ); + + /* calculate the hash index + */ + hix = ( size_t )ino & persp->p_hashmask; + + /* get a pointer to the indexed hash array entry + */ + entryp = &tranp->t_hashp[ hix ]; + + /* insert into the list, at the head + */ + ASSERT( np->n_hashh == NH_NULL ); + np->n_hashh = *entryp; + *entryp = nh; + + /* release the mapping + */ + Node_unmap( nh, &np ); +} + +static void +hash_out( nh_t nh ) +{ + node_t *np; + xfs_ino_t ino; + nh_t hashheadh; + size_t hix; + nh_t *entryp; + + /* get a mapping to the node + */ + np = Node_map( nh ); + + /* get the ino + */ + ino = np->n_ino; + + /* get a pointer to the hash array entry + */ + hix = ( size_t )ino & persp->p_hashmask; + entryp = &tranp->t_hashp[ hix ]; + + /* get the handle of the first node in the appropriate hash array + */ + hashheadh = *entryp; + ASSERT( hashheadh != NH_NULL ); + + /* if node is first in list, replace entry with following node. + * otherwise, walk the list until found. + */ + if ( hashheadh == nh ) { + *entryp = np->n_hashh; + } else { + nh_t prevh = hashheadh; + node_t *prevp = Node_map( prevh ); + while ( prevp->n_hashh != nh ) { + nh_t nexth = prevp->n_hashh; + Node_unmap( prevh, &prevp ); + prevh = nexth; + ASSERT( prevh != NH_NULL ); + prevp = Node_map( prevh ); + } + prevp->n_hashh = np->n_hashh; + Node_unmap( prevh, &prevp ); + } + np->n_hashh = NH_NULL; + + /* release the mapping + */ + Node_unmap( nh, &np ); +} + +static nh_t +hash_find( xfs_ino_t ino, gen_t gen ) +{ + nh_t nh; + node_t *np; + size_t hix; + + /* get handle to first node in appropriate hash array + */ + hix = ( size_t )ino & persp->p_hashmask; + nh = tranp->t_hashp[ hix ]; + + /* if list empty, return null handle + */ + if ( nh == NH_NULL ) { + return NH_NULL; + } + + /* walk the list until found. + */ + np = Node_map( nh ); + while ( np->n_ino != ino || np->n_gen != gen ) { + nh_t nextnh = np->n_hashh; + Node_unmap( nh, &np ); + nh = nextnh; + if ( nh == NH_NULL ) { + return NH_NULL; + } + np = Node_map( nh ); + } + Node_unmap( nh, &np ); + + return nh; +} + +/* invokes callback for all hashed nodes + * iteration aborted if callback returns FALSE + * call back may hash out and free the node, so + * must figure next node prior to calling callback. + */ +static void +hash_iter( bool_t ( * cbfp )( void *contextp, nh_t hashh ), void *contextp ) +{ + ix_t hix; + size64_t hashlen = persp->p_hashsz / sizeof( nh_t ); + + for ( hix = 0 ; hix < ( ix_t )hashlen ; hix++ ) { + nh_t nh = tranp->t_hashp[ hix ]; + + while ( nh != NH_NULL ) { + node_t *np; + nh_t nexth; + bool_t ok; + + np = Node_map( nh ); + nexth = np->n_hashh; + Node_unmap( nh, &np ); + + ok = ( * cbfp )( contextp, nh ); + if ( ! ok ) { + return; + } + + nh = nexth; + } + } +} + +/* misc static functions *****************************************************/ + +#ifdef TREE_CHK +/* use hash array to iterate through all nodes. check + * each node's hash, hardlink, namreg, dirattr, parent, + * and sibling handles. + */ +static bool_t +Node_chk( nh_t nh, nh_t *nexthashhp, nh_t *nextlnkhp ) +{ + node_t *np; + node_t n; + char nambuf[ NAME_MAX + 1 ]; + bool_t okaccum; + + mlog( MLOG_NITTY + 1 | MLOG_TREE, + "checking node nh == 0x%x\n", + nh ); + + okaccum = BOOL_TRUE; + + if ( nexthashhp ) { + *nexthashhp = NH_NULL; + } + + ASSERT( nextlnkhp ); + *nextlnkhp = NH_NULL; + + np = Node_map( nh ); + ASSERT( np ); + n = *np; + Node_unmap( nh, &np ); + + if ( ! nexthashhp && n.n_hashh != NH_NULL ) { + mlog( MLOG_NORMAL | MLOG_ERROR | MLOG_TREE, + "nh 0x%x np 0x%x hash link not null\n", + nh, + np ); + okaccum = BOOL_FALSE; + } + + if ( n.n_hashh != NH_NULL ) { + np = Node_map( n.n_hashh ); + Node_unmap( n.n_hashh, &np ); + } + + if ( n.n_lnkh != NH_NULL ) { + np = Node_map( n.n_lnkh ); + Node_unmap( n.n_lnkh, &np ); + } + + if ( n.n_parh != NH_NULL ) { + np = Node_map( n.n_parh ); + Node_unmap( n.n_parh, &np ); + } + + if ( n.n_cldh != NH_NULL ) { + np = Node_map( n.n_cldh ); + Node_unmap( n.n_cldh, &np ); + } + + if ( n.n_sibh != NH_NULL ) { + np = Node_map( n.n_sibh ); + Node_unmap( n.n_sibh, &np ); + } + + if ( n.n_nrh != NRH_NULL ) { + intgen_t rval; + rval = namreg_get( n.n_nrh, nambuf, sizeof( nambuf )); + ASSERT( rval >= 0 ); + } + + if ( n.n_dah != DAH_NULL ) { + ( void )dirattr_get_mode( n.n_dah ); + } + + if ( nexthashhp ) { + *nexthashhp = n.n_hashh; + } + + *nextlnkhp = n.n_lnkh; + + return okaccum; +} + +bool_t +tree_chk( void ) +{ + ix_t hix; + size64_t hashlen = persp->p_hashsz / sizeof( nh_t ); + bool_t ok; + bool_t okaccum; + + okaccum = BOOL_TRUE; + + for ( hix = 0 ; hix < ( ix_t )hashlen ; hix++ ) { + nh_t hashh = tranp->t_hashp[ hix ]; + + mlog( MLOG_NITTY + 1 | MLOG_TREE, + "checking hix %u\n", + hix ); + while ( hashh != NH_NULL ) { + nh_t lnkh; + + ok = Node_chk( hashh, &hashh, &lnkh ); + if ( ! ok ) { + okaccum = BOOL_FALSE; + } + + while ( lnkh != NH_NULL ) { + ok = Node_chk( lnkh, 0, &lnkh ); + if ( ! ok ) { + okaccum = BOOL_FALSE; + } + } + } + } + + ok = tree_chk2( ); + if ( ! ok ) { + okaccum = BOOL_FALSE; + } + + return okaccum; +} + +static bool_t tree_chk2_recurse( nh_t cldh, nh_t parh ); + +static bool_t +tree_chk2( void ) +{ + node_t *rootp; + nh_t cldh; + bool_t ok; + + mlog( MLOG_DEBUG | MLOG_TREE, + "tree hierarchy check\n" ); + + rootp = Node_map( persp->p_rooth ); + cldh = rootp->n_cldh; + Node_unmap( persp->p_rooth, &rootp ); + + ok = tree_chk2_recurse( cldh, persp->p_rooth ); + + return ok; +} + +static bool_t +tree_chk2_recurse( nh_t cldh, nh_t parh ) +{ + bool_t okaccum = BOOL_TRUE; + + ASSERT( parh != NH_NULL ); + + while ( cldh != NH_NULL ) { + node_t *cldp; + xfs_ino_t ino; + gen_t gen; + nh_t nodeparh; + nrh_t nrh; + nh_t grandcldh; + nh_t nextcldh; + bool_t ok; + + cldp = Node_map( cldh ); + ino = cldp->n_ino; + gen = cldp->n_gen; + nodeparh = cldp->n_parh; + nrh = cldp->n_nrh; + grandcldh = cldp->n_cldh; + nextcldh = cldp->n_sibh; + Node_unmap( cldh, &cldp ); + + if ( parh == persp->p_orphh ) { + sprintf( tranp->t_namebuf, "%llu.%u", ino, gen ); + } else if ( cldh == persp->p_orphh ) { + sprintf( tranp->t_namebuf, "%llu.%u", ino, gen ); + } else { + intgen_t namelen; + namelen = namreg_get( nrh, + tranp->t_namebuf, + sizeof( tranp->t_namebuf )); + ASSERT( namelen >= 0 ); + } + + if ( nodeparh == NH_NULL ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "node %x %s %llu %u parent NULL\n", + cldh, + tranp->t_namebuf, + ino, + gen ); + return BOOL_FALSE; + } else if ( nodeparh != parh ) { + mlog( MLOG_NORMAL | MLOG_WARNING | MLOG_TREE, + "node %x %s %llu %u parent mismatch: " + "nodepar %x par %x\n", + cldh, + tranp->t_namebuf, + ino, + gen, + nodeparh, + parh ); + return BOOL_FALSE; + } else { + mlog( MLOG_DEBUG | MLOG_TREE, + "node %x %s %llu %u parent %x\n", + cldh, + tranp->t_namebuf, + ino, + gen, + parh ); + } + ok = tree_chk2_recurse( grandcldh, cldh ); + if ( ! ok ) { + okaccum = BOOL_FALSE; + } + + cldh = nextcldh; + } + + return okaccum; +} + +#endif /* TREE_CHK */ + +#ifdef WHITEPARSE + +static char *whites = " \t\r\n\v\f"; + +static int is_white( char c ); +static void fix_escape( char *string, char *liter ); +static void fix_quoted_span( char *string, char *liter ); +static void collapse_white( char *string, char *liter ); +static size_t distance_to_space( char *s, char *l ); + +static int +parse( int slotcnt, char **slotbuf, char *string ) +{ + char *liter; + char *s; + char *l; + size_t wordcnt; + + /* sanity checkcs + */ + ASSERT( slotcnt >= 0 ); + + /* allocate a companion to the input string for identifying + * characters which are to be interpreted literally. + */ + liter = ( char * )calloc( 1, strlen( string ) + 1 ); + if ( ! liter ) { + return -1; + } + + /* pass 1: collapse escape sequences, identifying characters which + * are to be interpreted literally + */ + for ( s = string, l = liter ; *s ; s++, l++ ) { + if ( *s == '\\' && ! *l ) { + fix_escape( s, l ); + } + } + + /* pass 2: collapse quoted spans, identifying characters which + * are to be interpreted literally + */ + for ( s = string, l = liter ; *s ; s++, l++ ) { + if ( *s == '\"' && ! *l ) { + fix_quoted_span( s, l ); + } + } + + /* pass 3: collapse white space spans into a single space + */ + for ( s = string, l = liter ; *s ; s++, l++ ) { + if ( is_white( *s ) && ! *l ) { + collapse_white( s, l ); + } + } + + /* pass 4: identify and null-terminate words + */ + wordcnt = 0; + s = string; + l = liter; + while ( *s ) { + size_t d; + if ( wordcnt < ( size_t )slotcnt ) { + slotbuf[ wordcnt ] = s; + } + wordcnt++; + d = distance_to_space( s, l ); + s += d; + l += d; + if ( *s ) { + *s = 0; + s++; + l++; + } + } + + free( ( void * )liter ); + return ( int )wordcnt; +} + +struct escape_table { + char sequence; + char substitute; +}; +typedef struct escape_table escape_table_t; + +static escape_table_t escape_table[ ] = { + { 'n', '\n' }, + { 't', '\t' }, + { 'v', '\v' }, + { 'b', '\b' }, + { 'r', '\r' }, + { 'f', '\f' }, + { 'f', '\f' }, + { 'a', '\a' }, + { '\\', '\\' } +}; + +static void shrink( char *s, size_t cnt ); +static int is_hex( char c ); +static size_t hex_to_size( char c ); +static int is_octal( char c ); +static size_t octal_to_size( char c ); + +static void +fix_escape( char *string, char *liter ) +{ + escape_table_t *ep; + escape_table_t *endep; + + /* first look for special escapes described in table + */ + ep = escape_table; + endep = escape_table + ( sizeof( escape_table ) + / + sizeof( escape_table[ 0 ] )); + for ( ; ep < endep ; ep++ ) { + if ( string[ 1 ] == ep->sequence ) { + string[ 0 ] = ep->substitute; + liter[ 0 ] = ( char )1; + shrink( &string[ 1 ], 1 ); + shrink( &liter[ 1 ], 1 ); + return; + } + } + + /* detect white space escapes + */ + if ( is_white( string[ 1 ] )) { + liter[ 0 ] = ( char )1; + shrink( &string[ 0 ], 1 ); + shrink( &liter[ 1 ], 1 ); + return; + } + + /* detect hex escapes (don't allow null) + */ + if ( string[ 1 ] == 'x' ) { + size_t hexlen; + size_t accum; + accum = 0; + for ( hexlen = 0 + ; + hexlen < 2 && is_hex( string[ 2 + hexlen ] ) + ; + hexlen++ ) { + accum *= 16; + accum += hex_to_size( string[ 2 + hexlen ] ); + } + if ( hexlen && accum ) { + string[ 0 ] = ( char )accum; + liter[ 0 ] = ( char )1; + shrink( &string[ 1 ], 1 + hexlen ); + shrink( &liter[ 1 ], 1 + hexlen ); + return; + } + } + + /* detect octal escapes (don't allow null) + */ + if ( is_octal( string[ 1 ] )) { + size_t octallen; + size_t accum; + accum = octal_to_size( string[ 1 ] ); + for ( octallen = 1 + ; + octallen < 3 && is_octal( string[ 1 + octallen ] ) + ; + octallen++ ) { + accum *= 8; + accum += octal_to_size( string[ 1 + octallen ] ); + } + if ( accum ) { + string[ 0 ] = ( char )accum; + liter[ 0 ] = ( char )1; + shrink( &string[ 1 ], octallen ); + shrink( &liter[ 1 ], octallen ); + return; + } + } + + /* didn't match any escape sequences, so assume literal + */ + liter[ 0 ] = ( char )1; +} + +static void +fix_quoted_span( char *string, char *liter ) +{ + char *s; + char *l; + + /* first cover the leading quote + */ + shrink( string, 1 ); + shrink( liter, 1 ); + + /* scan for the next non-literal quote, marking all + * characters in between as literal + */ + for ( s = string, l = liter ; *s && ( *s != '\"' || *l ) ; s++, l++ ) { + *l = ( char )1; + } + + if ( *s ) { + shrink( s, 1 ); + shrink( l, 1 ); + } +} + +static void +collapse_white( char *string, char *liter ) +{ + char *s; + char *l; + size_t cnt; + + cnt = 0; + for ( s = string, l = liter ; is_white( *s ) && ! *l ; s++, l++ ) { + cnt++; + } + + string[ 0 ] = ' '; + + if ( cnt > 1 ) { + shrink( &string[ 1 ], cnt - 1 ); + shrink( &liter[ 1 ], cnt - 1 ); + } +} + +static size_t +distance_to_space( char *s, char *l ) +{ + size_t cnt; + + for ( cnt = 0 ; *s && ( ! is_white( *s ) || *l ) ; s++, l++ ) { + cnt++; + } + + return cnt; +} + +static void +shrink( char *s, size_t cnt ) +{ + strcpy( s, s + cnt ); +} + +static int +is_white( char c ) +{ + if ( c && strchr( whites, ( int )c )) { + return 1; + } else { + return 0; + } +} + +static int +is_hex( char c ) +{ + if ( c >= '0' && c <= '9' ) { + return 1; + } + + if ( c >= 'a' && c <= 'f' ) { + return 1; + } + + if ( c >= 'A' && c <= 'F' ) { + return 1; + } + + return 0; +} + +static size_t +hex_to_size( char c ) +{ + if ( c >= '0' && c <= '9' ) { + return ( size_t )( c - '0' ); + } + + if ( c >= 'a' && c <= 'f' ) { + return ( size_t )( c - 'a' ) + ( size_t )0xa; + } + + if ( c >= 'A' && c <= 'F' ) { + return ( size_t )( c - 'A' ) + ( size_t )0xa; + } + + return 0; +} + +static int +is_octal( char c ) +{ + if ( c >= '0' && c <= '7' ) { + return 1; + } + + return 0; +} + +static size_t +octal_to_size( char c ) +{ + if ( c >= '0' && c <= '7' ) { + return ( size_t )( c - '0' ); + } + + return 0; +} + +#endif /* WHITEPARSE */ + +static int +mkdir_r(char *path) +{ + struct stat sbuf; + + if (stat(path, &sbuf) < 0) { + if (mkdir_r(dirname(strdup(path))) < 0) + return -1; + return mkdir(path, 0755); + } + else if ((sbuf.st_mode & S_IFDIR) == 0) { + mlog( MLOG_TRACE | MLOG_ERROR | MLOG_TREE, + "%s is not a directory\n", path); + exit(1); + } + return 0; +} + diff -rNu linux-2.4.7/cmd/xfsdump/restore/tree.h linux-2.4-xfs/cmd/xfsdump/restore/tree.h --- linux-2.4.7/cmd/xfsdump/restore/tree.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/tree.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef TREE_H +#define TREE_H + +/* tree_init - creates a new tree abstraction. + */ +extern bool_t tree_init( char *hkdir, + char *dstdir, + bool_t toconlypr, + bool_t ownerpr, + xfs_ino_t rootino, + xfs_ino_t firstino, + xfs_ino_t lastino, + size64_t dircnt, + size64_t nondircnt, + size64_t vmsz, + bool_t fullpr, + bool_t restoredmpr ); + +/* tree_sync - synchronizes with an existing tree abstraction + */ +extern bool_t tree_sync( char *hkdir, + char *dstdir, + bool_t toconlypr, + bool_t fullpr); + + +/* tree_begindir - begins application of dumped directory to tree. + * returns handle to dir node. returns by reference the dirattr + * handle if new. caller must pre-zero (DAH_NULL). + */ +extern nh_t tree_begindir( filehdr_t *fhdrp, dah_t *dahp ); + +/* tree_addent - adds a directory entry; takes dirh from above call + */ +extern void tree_addent( nh_t dirh, + xfs_ino_t ino, + size_t gen, + char *name, + size_t namelen ); + +/* ends application of dir + */ +extern void tree_enddir( nh_t dirh ); + +#ifdef TREE_CHK +/* tree_chk - do a sanity check of the tree prior to post-processing and + * non-dir restoral. returns FALSE if corruption detected. + */ +extern bool_t tree_chk( void ); +#endif /* TREE_CHK */ + +/* tree_marknoref - mark all nodes as no reference, not dumped dirs, and + * clear all directory attribute handles. done at the beginning + * of the restoral of a dump session, in order to detect directory entries + * no longer needed. + */ +extern void tree_marknoref( void ); + +/* mark all nodes in tree as either selected or unselected, depending on sense + */ +extern void tree_markallsubtree( bool_t sensepr ); + +extern bool_t tree_subtree_parse( bool_t sensepr, char *path ); + +extern bool_t tree_post( char *path1, char *path2 ); + +extern void tree_cb_links( xfs_ino_t ino, + u_int32_t biggen, + int32_t ctime, + int32_t mtime, + bool_t ( * funcp )( void *contextp, + bool_t linkpr, + char *path1, + char *path2 ), + void *contextp, + char *path1, + char *path2 ); + +/* called after all dirs have been restored. adjusts the ref flags, + * by noting that dirents not refed because their parents were not dumped + * are virtually reffed if their parents are refed. + */ +extern bool_t tree_adjref( void ); + +extern bool_t tree_setattr( char *path ); +extern bool_t tree_delorph( void ); +extern bool_t tree_subtree_inter( void ); + +#ifdef EXTATTR +extern bool_t tree_extattr( bool_t ( * cbfunc )( char *path, dah_t dah ), + char *path ); + /* does a depthwise bottom-up traversal of the tree, calling + * the supplied callback for all directories with a non-NULL dirattr + * handle. The callback will get called with the directory's pathname + * and it dirattr handle. the traversal will be aborted if the + * callback returns FALSE. returns FALSE if operator requests + * an interrupt. + */ +#endif /* EXTATTR */ + +#endif /* TREE_H */ diff -rNu linux-2.4.7/cmd/xfsdump/restore/win.c linux-2.4-xfs/cmd/xfsdump/restore/win.c --- linux-2.4.7/cmd/xfsdump/restore/win.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/win.c Sun Jan 14 22:06:20 2001 @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "types.h" +#include "mlog.h" +#include "bag.h" +#include "qlock.h" +#include "mmap.h" + +extern size_t pgsz; +extern size_t pgmask; + +/* window descriptor + */ +struct win { + off64_t w_off; + /* offset from first segment of segment mapped by this window + */ + void *w_p; + /* window virtual address + */ + size_t w_refcnt; + /* reference count + */ + time_t w_lasttouched; + /* time stamp of most refcnt decrement + */ + struct win *w_nextp; + /* LRU list forward linkage + */ + struct win *w_prevp; + /* LRU list backward linkage + */ + bagelem_t w_bagelem; + /* bag element cookie + */ +}; + +typedef struct win win_t; + +/* forward declarations + */ +static void win_bag_insert( win_t *winp ); +static void win_bag_remove( win_t *winp ); +static win_t *win_bag_find_off( off64_t off ); +static void critical_init( void ); +static void critical_begin( void ); +static void critical_end( void ); + +/* transient state + */ +struct tran { + intgen_t t_fd; + /* file descriptor of backing store to be windowed + */ + off64_t t_firstoff; + /* offset of first seg within backing store (for mmap( )) + */ + size_t t_segsz; + /* backing store segment / window size + */ + size_t t_winmax; + /* maximum number of windows to allocate + */ + size_t t_wincnt; + /* number of windows allocated + */ + win_t *t_lruheadp; + /* LRU head (re-use from this end) + */ + win_t *t_lrutailp; + /* LRU tail (put here when no refs) + */ + bag_t *t_bagp; + /* context for bag abstraction + */ + qlockh_t t_qlockh; + /* for establishing critical regions + */ + +}; + +typedef struct tran tran_t; + +static tran_t *tranp = 0; + +void +win_init( intgen_t fd, + off64_t firstoff, + size_t segsz, + size_t winmax ) +{ + /* validate parameters + */ + ASSERT( ( firstoff & ( off64_t )pgmask ) == 0 ); + ASSERT( ( segsz & pgmask ) == 0 ); + + /* allocate and initialize transient state + */ + ASSERT( tranp == 0 ); + tranp = ( tran_t * )calloc( 1, sizeof( tran_t )); + ASSERT( tranp ); + + tranp->t_fd = fd; + tranp->t_firstoff = firstoff; + tranp->t_segsz = segsz; + tranp->t_winmax = winmax; + + /* create a bag + */ + tranp->t_bagp = bag_alloc( ); + + /* initialize critical region enforcer + */ + critical_init( ); +} + +void +win_map( off64_t off, void **pp ) +{ + size_t offwithinseg; + off64_t segoff; + win_t *winp; + + critical_begin( ); + + /* calculate offset within segment + */ + offwithinseg = ( size_t )( off % ( off64_t )tranp->t_segsz ); + + /* calculate offset of segment + */ + segoff = off - ( off64_t )offwithinseg; + + /* see if segment already mapped. if ref cnt zero, + * remove from LRU list. + */ + winp = win_bag_find_off( segoff ); + if ( winp ) { + if ( winp->w_refcnt == 0 ) { + ASSERT( tranp->t_lruheadp ); + ASSERT( tranp->t_lrutailp ); + if ( tranp->t_lruheadp == winp ) { + if ( tranp->t_lrutailp == winp ) { + tranp->t_lruheadp = 0; + tranp->t_lrutailp = 0; + } else { + tranp->t_lruheadp = winp->w_nextp; + tranp->t_lruheadp->w_prevp = 0; + } + } else { + if ( tranp->t_lrutailp == winp ) { + tranp->t_lrutailp = winp->w_prevp; + tranp->t_lrutailp->w_nextp = 0; + } else { + winp->w_prevp->w_nextp = winp->w_nextp; + winp->w_nextp->w_prevp = winp->w_prevp; + } + } + winp->w_prevp = 0; + winp->w_nextp = 0; + } else { + ASSERT( ! winp->w_prevp ); + ASSERT( ! winp->w_nextp ); + } + winp->w_refcnt++; + *pp = ( void * )( ( char * )( winp->w_p ) + offwithinseg ); + critical_end( ); + return; + } + + /* if LRU list not empty, re-use descriptor at head. + * if LRU list is empty, allocate a new descriptor if + * not too many already. + */ + if ( tranp->t_lruheadp ) { + /* REFERENCED */ + intgen_t rval; + ASSERT( tranp->t_lrutailp ); + winp = tranp->t_lruheadp; + tranp->t_lruheadp = winp->w_nextp; + if ( tranp->t_lruheadp ) { + tranp->t_lruheadp->w_prevp = 0; + } else { + tranp->t_lrutailp = 0; + } + win_bag_remove( winp ); + rval = munmap( winp->w_p, tranp->t_segsz ); + ASSERT( ! rval ); + memset( ( void * )winp, 0, sizeof( win_t )); + } else if ( tranp->t_wincnt < tranp->t_winmax ) { + winp = ( win_t * )calloc( 1, sizeof( win_t )); + ASSERT( winp ); + tranp->t_wincnt++; + } else { + ASSERT( tranp->t_wincnt == tranp->t_winmax ); + *pp = 0; + critical_end( ); + mlog( MLOG_NORMAL | MLOG_WARNING, + "all map windows in use. Check virtual memory limits\n" ); + return; + } + + /* map the window + */ + ASSERT( tranp->t_segsz >= 1 ); + ASSERT( tranp->t_firstoff + <= + OFF64MAX - segoff - ( off64_t )tranp->t_segsz + 1ll ); + ASSERT( ! ( tranp->t_segsz % pgsz )); + ASSERT( ! ( ( tranp->t_firstoff + segoff ) % ( off64_t )pgsz )); + winp->w_p = mmap_autogrow( + tranp->t_segsz, + tranp->t_fd, + ( off64_t )( tranp->t_firstoff + segoff )); + ASSERT( winp->w_p ); + ASSERT( winp->w_p != ( void * )( -1 )); + winp->w_off = segoff; + ASSERT( winp->w_refcnt == 0 ); + winp->w_refcnt++; + win_bag_insert( winp ); + + *pp = ( void * )( ( char * )( winp->w_p ) + offwithinseg ); + + critical_end( ); +} + +void +win_unmap( off64_t off, void **pp ) +{ + size_t offwithinseg; + off64_t segoff; + win_t *winp; + + critical_begin( ); + + /* calculate offset within segment + */ + offwithinseg = ( size_t )( off % ( off64_t )tranp->t_segsz ); + + /* convert offset within range into window's offset within range + */ + segoff = off - ( off64_t )offwithinseg; + + /* verify window mapped + */ + winp = win_bag_find_off( segoff ); + ASSERT( winp ); + + /* validate p + */ + ASSERT( pp ); + ASSERT( *pp ); + ASSERT( *pp >= winp->w_p ); + ASSERT( *pp < ( void * )( ( char * )( winp->w_p ) + tranp->t_segsz )); + + /* decrement the reference count. if zero, place at tail of LRU list. + */ + ASSERT( winp->w_refcnt > 0 ); + winp->w_refcnt--; + winp->w_lasttouched = time( 0 ); + ASSERT( ! winp->w_prevp ); + ASSERT( ! winp->w_nextp ); + if ( winp->w_refcnt == 0 ) { + if ( tranp->t_lrutailp ) { + ASSERT( tranp->t_lruheadp ); + winp->w_prevp = tranp->t_lrutailp; + tranp->t_lrutailp->w_nextp = winp; + tranp->t_lrutailp = winp; + } else { + ASSERT( ! tranp->t_lruheadp ); + ASSERT( ! winp->w_prevp ); + tranp->t_lruheadp = winp; + tranp->t_lrutailp = winp; + } + ASSERT( ! winp->w_nextp ); + } + + /* zero the caller's pointer + */ + *pp = 0; + + critical_end( ); +} + +static void +win_bag_insert( win_t *winp ) +{ + bag_insert( tranp->t_bagp, + &winp->w_bagelem, + ( size64_t )winp->w_off, + ( void * )winp ); +} + +static void +win_bag_remove( win_t *winp ) +{ + off64_t off; + win_t *p; + + off = 0; /* keep lint happy */ + p = 0; /* keep lint happy */ + bag_remove( tranp->t_bagp, + &winp->w_bagelem, + ( size64_t * )&off, + ( void ** )&p ); + ASSERT( off == winp->w_off ); + ASSERT( p == winp ); +} + +static win_t * +win_bag_find_off( off64_t winoff ) +{ + bagelem_t *bagelemp; + win_t *p; + + p = 0; /* keep lint happy */ + bagelemp = bag_find( tranp->t_bagp, + ( size64_t )winoff, + ( void ** )&p ); + if ( ! bagelemp ) { + return 0; + } + ASSERT( p ); + ASSERT( bagelemp == &p->w_bagelem ); + return p; +} + +static void +critical_init( void ) +{ + tranp->t_qlockh = qlock_alloc( QLOCK_ORD_WIN ); +} + +static void +critical_begin( void ) +{ + qlock_lock( tranp->t_qlockh ); +} + +static void +critical_end( void ) +{ + qlock_unlock( tranp->t_qlockh ); +} diff -rNu linux-2.4.7/cmd/xfsdump/restore/win.h linux-2.4-xfs/cmd/xfsdump/restore/win.h --- linux-2.4.7/cmd/xfsdump/restore/win.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsdump/restore/win.h Sun Jan 14 22:06:20 2001 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef WIN_H +#define WIN_H + +/* win.[ch] - windows into a very large file + */ + +/* initialize the window abstraction + */ +void win_init( intgen_t fd, + off64_t rngoff, /* offset into file of windowing */ + size_t winsz, /* window size */ + size_t wincntmax ); /* max number of windows to manage */ + +/* supply a pointer to the portion of the file identified by off. + */ +void win_map( off64_t off, /* file offset relative to rngoff */ + void **pp ); /* returns pointer by reference */ + +/* invalidate the pointer previously supplied. SIDE-EFFECT: zeros + * by reference the caller's pointer. + */ +void win_unmap( off64_t off, /* must match win_map param */ + void **pp ); /* ptr generated by win_map: ZEROED */ + +#endif /* WIN_H */ diff -rNu linux-2.4.7/cmd/xfsmisc/CVS/Entries linux-2.4-xfs/cmd/xfsmisc/CVS/Entries --- linux-2.4.7/cmd/xfsmisc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsmisc/CVS/Entries Thu Jul 5 11:44:18 2001 @@ -0,0 +1,6 @@ +/README/1.2/Tue Apr 3 23:02:04 2001/-ko/ +/XFSgenPatch.pl/1.4/Thu May 31 08:05:47 2001/-ko/ +/kiobuf_io.patch/1.2/Fri Apr 6 14:35:25 2001/-ko/ +/mkinitrd.xfs/1.1/Wed Mar 21 01:57:16 2001/-ko/ +/xfs_stats.pl/1.2/Tue Apr 3 20:00:08 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsmisc/CVS/Repository linux-2.4-xfs/cmd/xfsmisc/CVS/Repository --- linux-2.4.7/cmd/xfsmisc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsmisc/CVS/Repository Thu Jul 5 11:44:16 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsmisc diff -rNu linux-2.4.7/cmd/xfsmisc/CVS/Root linux-2.4-xfs/cmd/xfsmisc/CVS/Root --- linux-2.4.7/cmd/xfsmisc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsmisc/CVS/Root Thu Jul 5 11:44:16 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsmisc/README linux-2.4-xfs/cmd/xfsmisc/README --- linux-2.4.7/cmd/xfsmisc/README Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsmisc/README Tue Apr 3 18:02:04 2001 @@ -0,0 +1,23 @@ +Miscellaneous utilities for XFS +------------------------------- + +mkinitrd.xfs + Russell's modified version of mkinitrd. Notes from rlog: + + Modified mkinitrd: make it large enough to fit xfs and pagebuf (15meg) + Use static version of bash rather than sash; sash doesn't seem to work. + (bash.static not supplied must build your own). + Note default ram disk size in the kernel is 4096k + add append="ramdisk_size=15000" to lilo.conf + +xfs_stats.pl + Perl script to massage the /proc/fs/xfs/stat file into a readable + format. Use "perldoc xfs_stats.pl" to see the man page. We dont + install this script in xfsprogs, for example, as we don't want to + introduce a prereq on perl just for this little script. + +kiobuf_io.patch + Patch (against the xfs tree at 2.4.3) to re-introduce the + kiobuf based I/O patch. This code was removed due to change + in direction in the community direction for the block I/O + layer. diff -rNu linux-2.4.7/cmd/xfsmisc/XFSgenPatch.pl linux-2.4-xfs/cmd/xfsmisc/XFSgenPatch.pl --- linux-2.4.7/cmd/xfsmisc/XFSgenPatch.pl Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsmisc/XFSgenPatch.pl Thu May 31 03:05:47 2001 @@ -0,0 +1,200 @@ +#!/usr/bin/perl + +use Data::Dumper; +use POSIX qw(strftime); + +$date = strftime "%m%d%Y", localtime; + +$corePatch = "linux-2.4.2-core-xfs-".$date.".patch"; +$xfsPatch = "linux-2.4.2-xfs-".$date.".patch"; + +$baseLinux = "/export/extra/lxfs-cvs/linux-2.4.5"; + +@xfs_dir = ( + "fs/xfs_support", + "fs/xfs", + "fs/pagebuf", + "fs/ext_attr.c", + "fs/noposix_acl.c", + "fs/posix_acl.c", + "Documentation/filesystems/xfs.txt", + "include/linux/xfs_fs_i.h", + "include/linux/page_buf.h", + "include/linux/vnode.h", + "include/linux/xfs_fs_sb.h", + "include/linux/xfs_fs.h", + "include/linux/avl.h", + "include/linux/page_buf_trace.h", + "include/linux/dmapi_kern.h", + "include/linux/dmapi.h", + "include/linux/behavior.h", + "include/linux/grio.h", + "include/linux/attributes.h", + "include/linux/xqm.h" + ); + +@file = ( + "Makefile", + "Rules.make", + "scripts/mkdep.c", # note remove for 2.4.3 + "fs/Makefile", #Add xfs and pagebuf directories + "fs/buffer.c", # Delayed buffers + "fs/inode.c", #ihold4 + "fs/filesystems.c", #init_xfs call + "fs/dquot.c", #XFS quota changes + "fs/Config.in", #xfs config options + "init/main.c", #pagebuf init call + "kernel/ksyms.c", #extra symbol exports + "mm/filemap.c", #Some tweaks from Rik Van Reil, pagebuf hooks + "mm/vmscan.c", #GFP_PAGE_IO support from Marcelo + "mm/slab.c", #kmem_cache_zalloc + "mm/vmalloc.c", + "include/linux/iobuf.h", # alloc kiobuf changes + "fs/iobuf.c", + # kiobuf mount flag, blksetsize ioctl, extra buffer flags, xfs includes and + # additions to inode and super block. ops vector changes for pagebuf and xfs. + "include/linux/fs.h", + "include/linux/sysctl.h", # pagebuf sysctl changes + "include/linux/pagemap.h", #Added new function prototypes + "include/linux/mm.h", #DelallocPage macro, GFP_PAGE_IO define + "include/linux/slab.h", #PAGE_IO defines, kmem_cache_zalloc define + "include/linux/vmalloc.h", + "arch/sparc64/kernel/ioctl32.c", + "arch/mips64/kernel/ioctl32.c", + "drivers/scsi/sd.c", + "drivers/block/blkpg.c", + "drivers/block/ll_rw_blk.c", # small delalloc check + "drivers/md/md.c", + "drivers/ide/ide.c", # blkset size addtions +# LVM files + "drivers/md/lvm-internal.h", + "drivers/md/lvm-fs.c", + "include/linux/lvm.h", + "drivers/md/lvm.c", + "drivers/md/raid1.c", + "drivers/md/raid5.c", # raid fixes + "drivers/md/Makefile", + "drivers/md/lvm-snap.c", +# end LVM files +# "fs/partitions/check.c", # Sar additions +# "include/linux/genhd.h", # Sar addtions + "Documentation/filesystems/00-INDEX", #XFS documentation + "Documentation/Changes", + "MAINTAINERS", # entry for XFS + "Documentation/Configure.help",#Config option help + "arch/i386/boot/Makefile" # Change -oformat to --oformat for newer binutils + ); + +#DMAPI specific changes (14 files) +@dmapi = ( + "include/asm-i386/fcntl.h", + "include/asm-mips/fcntl.h", + "include/asm-alpha/fcntl.h", + "include/asm-m68k/fcntl.h", + "include/asm-sparc/fcntl.h", + "include/asm-ppc/fcntl.h", + "include/asm-sparc64/fcntl.h", + "include/asm-arm/fcntl.h", + "include/asm-sh/fcntl.h", + "include/asm-ia64/fcntl.h", + "include/asm-mips64/fcntl.h", + "include/asm-s390/fcntl.h", #O_INVISIBLE definition + "include/linux/miscdevice.h", #DMAPI device definition - should be submitted to device number maintainer + "fs/super.c"); #dmapi code in mount path + +#KIOBUF I/O specific changes (17 files) +@kio = ( + "fs/iobuf.c", +# "fs/buffer.c", #kiobuf bounce page support +# "drivers/scsi/sd.c", + "drivers/block/rd.c", + "drivers/scsi/scsi_merge.c", + "drivers/scsi/scsi_lib.c", + "drivers/ide/ide-disk.c", + "drivers/ide/ide-dma.c", +# "drivers/ide/ide.c", +# "drivers/md/raid1.c", +# "drivers/md/raid5.c", #Kiobuf I/O support + "drivers/char/raw.c", #Kiobuf I/O support for Raw I/O + "include/linux/blkdev.h", #kiobuf I/O function definition changes and require structure changes + "include/linux/major.h", # kiobuf I/O added macros + "include/linux/ide.h", #Kiobuf I/O ide structure changes +# "drivers/block/ll_rw_blk.c", + "drivers/block/elevator.c", #kiobuf I/O changes + "include/linux/iobuf.h"); #Kiobuf I/O changes for bounce buffers + +@attr = ( +# "fs/Makefile", #add posix_acl code and extended attribute code +# "fs/Config.in", #posix acl config options + "include/asm-i386/unistd.h", + "include/asm-ia64/unistd.h", + "arch/i386/kernel/entry.S", + "arch/ia64/ia32/ia32_entry.S", + "arch/ia64/kernel/entry.S", + "arch/ia64/kernel/ivt.S"); #extended attribute and acl syscall numbers + +@genfix = ( "fs/namei.c", #nested symlink fix - is this real? If it is lets get it submitted + "mm/memory.c",#kiovec locking fixes - needed for generic pagebuf code + "fs/iobuf.c", # change calls to suppport kiovec locking + "include/linux/iobuf.h"); + + +push (@full, \@genfix); +push (@full, \@attr); +#push (@full, \@kio); +push (@full, \@dmapi); +push (@full, \@file); +#push (@full, \@xfs_dir); + + +foreach $dir (@full){ + push(@fullList,@{$dir}); +} + +foreach $dir (sort(@fullList)){ + print "$dir\n"; +} + +coreFiles(); +newFile(); + +exit; + +sub coreFiles { + open(CORE,"> $corePatch") || die "$corePatch $!\n"; + foreach $dir (sort(@fullList)){ + if ( -f "$baseLinux/linux/$dir" ){ + $cmd = "diff -rNu $baseLinux/linux/$dir linux/$dir"; + } else { + $cmd = "diff -rNu /dev/null linux/$dir"; + } + print STDERR "$cmd\n"; + open (DIFF, "$cmd |") || die "$cmd $!\n"; + while (){ + print CORE $_; + } + close(DIFF); + } + close(CORE); +} + +sub newFile { + open(XFS,"> $xfsPatch") || die "$xfsPatch $!\n"; + foreach $dir (@xfs_dir) { + # $cmd = "diff -rNu $baseLinux/linux/$dir linux/$dir"; + if (! -d "/tmp/null") { + mkdir ("/tmp/null",0755) || die "/tmp/null $!\n"; + } + if (-d "linux/$dir" ) { + $cmd = "diff -rNu /tmp/null linux/$dir"; + } elsif (-f "linux/$dir" ) { + $cmd = "diff -rNu /dev/null linux/$dir"; + } + print STDERR "$cmd\n"; + open (DIFF, "$cmd |") || die "$cmd $!\n"; + while (){ + print XFS $_; + } + close(DIFF); + } +} diff -rNu linux-2.4.7/cmd/xfsmisc/kiobuf_io.patch linux-2.4-xfs/cmd/xfsmisc/kiobuf_io.patch --- linux-2.4.7/cmd/xfsmisc/kiobuf_io.patch Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsmisc/kiobuf_io.patch Fri Apr 6 09:35:25 2001 @@ -0,0 +1,3008 @@ + +=========================================================================== +Index: linux/drivers/block/elevator.c +=========================================================================== + +--- linux/drivers/block/elevator.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/drivers/block/elevator.c_1.7 Tue Apr 3 17:57:09 2001 +@@ -94,6 +94,8 @@ + + if (__rq->sem) + continue; ++ if (__rq->kiobuf) ++ continue; + if (__rq->rq_dev != bh->b_rdev) + continue; + if (!*req && bh_rq_in_between(bh, __rq, &q->queue_head)) +@@ -155,7 +157,8 @@ + entry = &q->queue_head; + while ((entry = entry->prev) != head) { + struct request *__rq = blkdev_entry_to_request(entry); +- ++ if (__rq->kiobuf) ++ continue; + if (__rq->cmd != rw) + continue; + if (__rq->rq_dev != bh->b_rdev) + +=========================================================================== +Index: linux/drivers/block/ll_rw_blk.c +=========================================================================== + +--- linux/drivers/block/ll_rw_blk.c Tue Apr 3 17:47:19 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/drivers/block/ll_rw_blk.c_1.65 Tue Apr 3 17:57:09 2001 +@@ -6,6 +6,7 @@ + * Elevator latency, (C) 2000 Andrea Arcangeli SuSE + * Queue request tables / lock, selectable elevator, Jens Axboe + * kernel-doc documentation started by NeilBrown - July2000 ++ * Support for kiobuf-based I/O requests: Chaitanya Tumuluri [chait@sgi.com] + */ + + /* +@@ -404,7 +405,9 @@ + spin_lock_init(&q->queue_lock); + } + +-static int __make_request(request_queue_t * q, int rw, struct buffer_head * bh); ++static int __make_request(request_queue_t * q, int rw, struct buffer_head * bh, ++ struct kiobuf * kiobuf, kdev_t dev, unsigned int sector, ++ unsigned int count); + + /** + * blk_init_queue - prepare a request queue for use with a block device +@@ -565,6 +568,121 @@ + printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n"); + } + ++/* Return up to two hd_structs on which to do IO accounting for a given ++ * request. On a partitioned device, we want to account both against ++ * the partition and against the whole disk. */ ++static void locate_hd_struct(struct request *req, ++ struct hd_struct **hd1, ++ struct hd_struct **hd2) ++{ ++ struct gendisk *gd; ++ ++ *hd1 = NULL; ++ *hd2 = NULL; ++ ++ gd = major_gendisk[MAJOR(req->rq_dev)]; ++ if (gd && gd->part) { ++ /* Mask out the partition bits: account for the entire disk */ ++ int devnr = MINOR(req->rq_dev) >> gd->minor_shift; ++ int whole_minor = devnr << gd->minor_shift; ++ *hd1 = &gd->part[whole_minor]; ++ if (whole_minor != MINOR(req->rq_dev)) ++ *hd2= &gd->part[MINOR(req->rq_dev)]; ++ } ++} ++ ++/* Round off the performance stats on an hd_struct. The average IO ++ * queue length and utilisation statistics are maintained by observing ++ * the current state of the queue length and the amount of time it has ++ * been in this state for. Normally, that accounting is done on IO ++ * completion, but that can result in more than a second's worth of IO ++ * being accounted for within any one second, leading to >100% ++ * utilisation. To deal with that, we do a round-off before returning ++ * the results when reading /proc/partitions, accounting immediately for ++ * all queue usage up to the current jiffies and restarting the counters ++ * again. */ ++void disk_round_stats(struct hd_struct *hd) ++{ ++ unsigned long now = jiffies; ++ ++ hd->aveq += (hd->ios_in_flight * (jiffies - hd->last_queue_change)); ++ hd->last_queue_change = now; ++ ++ if (hd->ios_in_flight) ++ hd->io_ticks += (now - hd->last_idle_time); ++ hd->last_idle_time = now; ++} ++ ++ ++static inline void down_ios(struct hd_struct *hd) ++{ ++ disk_round_stats(hd); ++ --hd->ios_in_flight; ++} ++ ++static inline void up_ios(struct hd_struct *hd) ++{ ++ disk_round_stats(hd); ++ ++hd->ios_in_flight; ++} ++ ++static void account_io_start(struct hd_struct *hd, struct request *req, ++ int merge, int sectors) ++{ ++ switch (req->cmd) { ++ case READ: ++ if (merge) ++ hd->rd_merges++; ++ hd->rd_sectors += sectors; ++ break; ++ case WRITE: ++ if (merge) ++ hd->wr_merges++; ++ hd->wr_sectors += sectors; ++ break; ++ default: ++ } ++ if (!merge) ++ up_ios(hd); ++} ++ ++static void account_io_end(struct hd_struct *hd, struct request *req) ++{ ++ unsigned long duration = jiffies - req->start_time; ++ switch (req->cmd) { ++ case READ: ++ hd->rd_ticks += duration; ++ hd->rd_ios++; ++ break; ++ case WRITE: ++ hd->wr_ticks += duration; ++ hd->wr_ios++; ++ break; ++ default: ++ } ++ down_ios(hd); ++} ++ ++void req_new_io(struct request *req, int merge, int sectors) ++{ ++ struct hd_struct *hd1, *hd2; ++ locate_hd_struct(req, &hd1, &hd2); ++ if (hd1) ++ account_io_start(hd1, req, merge, sectors); ++ if (hd2) ++ account_io_start(hd2, req, merge, sectors); ++} ++ ++void req_finished_io(struct request *req) ++{ ++ struct hd_struct *hd1, *hd2; ++ locate_hd_struct(req, &hd1, &hd2); ++ if (hd1) ++ account_io_end(hd1, req); ++ if (hd2) ++ account_io_end(hd2, req); ++} ++ + /* + * add-request adds a request to the linked list. + * io_request_lock is held and interrupts disabled, as we muck with the +@@ -644,8 +762,11 @@ + int max_segments) + { + struct request *next; ++ struct hd_struct *hd1, *hd2; + + next = blkdev_next_request(req); ++ if (req->kiobuf || next->kiobuf) ++ return; + if (req->sector + req->nr_sectors != next->sector) + return; + if (req->cmd != next->cmd +@@ -667,6 +788,15 @@ + req->bhtail = next->bhtail; + req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors; + list_del(&next->queue); ++ ++ /* One last thing: we have removed a request, so we now have one ++ less expected IO to complete for accounting purposes. */ ++ ++ locate_hd_struct(req, &hd1, &hd2); ++ if (hd1) ++ down_ios(hd1); ++ if (hd2) ++ down_ios(hd2); + blkdev_release_request(next); + } + +@@ -694,10 +824,68 @@ + attempt_merge(q, blkdev_entry_to_request(prev), max_sectors, max_segments); + } + +-static int __make_request(request_queue_t * q, int rw, +- struct buffer_head * bh) ++ ++static inline void __blk_init_req_bh(struct request *rq, struct buffer_head *bh) ++{ ++ rq->buffer = bh->b_data; ++ rq->kiobuf = NULL; ++ rq->bh = bh; ++ rq->bhtail = bh; ++} ++ ++static inline void __blk_init_req_kio(struct request *rq, struct kiobuf *kiobuf) ++{ ++ unsigned int nr_bytes, total_bytes; ++ int kioind = 0, c_off; ++ ++ /* Calculate req->buffer for kiobufs */ ++ c_off = kiobuf->offset; ++ if (c_off > PAGE_SIZE) { ++ kioind = c_off >> PAGE_SHIFT; ++ c_off &= ~PAGE_MASK; ++ } ++ ++ rq->buffer = c_off + (char *) page_address(kiobuf->maplist[kioind]); ++ ++ /* Re-calculate current_nr_sectors */ ++ nr_bytes = total_bytes = kiobuf->length; ++ if (!(PAGE_SIZE - c_off > total_bytes)) ++ nr_bytes = PAGE_SIZE - c_off; ++ ++ rq->hard_cur_sectors = rq->current_nr_sectors = nr_bytes >> 9; ++ ++ /* Recalculate # segments; reuse "kioind" from above */ ++ for (; kioind < kiobuf->nr_pages && nr_bytes != total_bytes; kioind++){ ++ ++rq->nr_segments; ++ if (nr_bytes + PAGE_SIZE > total_bytes) ++ break; ++ ++ nr_bytes += PAGE_SIZE; ++ } ++ ++ rq->kiobuf = kiobuf; ++ rq->bh = rq->bhtail = NULL; ++} ++ ++ ++static void blk_init_req(struct request *rq, struct buffer_head *bh, ++ struct kiobuf *kiobuf) ++{ ++ if (bh) ++ __blk_init_req_bh(rq, bh); ++ else if (kiobuf) ++ __blk_init_req_kio(rq, kiobuf); ++ else { ++ printk("blk_init_req: neither bh nor kio given\n"); ++ BUG(); ++ } ++} ++ ++ ++static int __make_request(request_queue_t * q, int rw, struct buffer_head * bh, ++ struct kiobuf * kiobuf, kdev_t dev, ++ unsigned int sector, unsigned int count) + { +- unsigned int sector, count; + int max_segments = MAX_SEGMENTS; + struct request * req, *freereq = NULL; + int rw_ahead, max_sectors, el_ret; +@@ -705,9 +893,6 @@ + int latency; + elevator_t *elevator = &q->elevator; + +- count = bh->b_size >> 9; +- sector = bh->b_rsector; +- + rw_ahead = 0; /* normal case; gets changed below for READA */ + switch (rw) { + case READA: +@@ -722,6 +907,7 @@ + goto end_io; + } + ++ if(bh){ + /* We'd better have a real physical mapping! + Check this bit only if the buffer was dirty and just locked + down by us so at this point flushpage will block and +@@ -737,12 +923,13 @@ + #if CONFIG_HIGHMEM + bh = create_bounce(rw, bh); + #endif +- ++ } + /* look for a free request. */ + /* + * Try to coalesce the new request with old requests + */ +- max_sectors = get_max_sectors(bh->b_rdev); ++ max_sectors = get_max_sectors(dev); ++ + + again: + req = NULL; +@@ -755,11 +942,14 @@ + + insert_here = head->prev; + if (list_empty(head)) { +- q->plug_device_fn(q, bh->b_rdev); /* is atomic */ ++ q->plug_device_fn(q, dev); /* is atomic */ + goto get_rq; + } else if (q->head_active && !q->plugged) + head = head->next; + ++ if (kiobuf) ++ goto get_rq; ++ + el_ret = elevator->elevator_merge_fn(q, &req, head, bh, rw,max_sectors); + switch (el_ret) { + +@@ -772,6 +962,7 @@ + req->nr_sectors = req->hard_nr_sectors += count; + blk_started_io(count); + drive_stat_acct(req->rq_dev, req->cmd, count, 0); ++ req_new_io(req, 1, count); + attempt_back_merge(q, req, max_sectors, max_segments); + goto out; + +@@ -783,10 +974,12 @@ + req->bh = bh; + req->buffer = bh->b_data; + req->current_nr_sectors = count; ++ req->hard_cur_sectors = count; + req->sector = req->hard_sector = sector; + req->nr_sectors = req->hard_nr_sectors += count; + blk_started_io(count); + drive_stat_acct(req->rq_dev, req->cmd, count, 0); ++ req_new_io(req, 1, count); + attempt_front_merge(q, head, req, max_sectors, max_segments); + goto out; + +@@ -819,9 +1012,11 @@ + freereq = NULL; + } else if ((req = get_request(q, rw)) == NULL) { + spin_unlock_irq(&io_request_lock); +- if (rw_ahead) ++ if (rw_ahead) { ++ if (kiobuf) ++ kiobuf->errno = -EBUSY; + goto end_io; +- ++ } + freereq = __get_request_wait(q, rw); + goto again; + } +@@ -832,14 +1027,14 @@ + req->errors = 0; + req->hard_sector = req->sector = sector; + req->hard_nr_sectors = req->nr_sectors = count; +- req->current_nr_sectors = count; ++ req->hard_cur_sectors = req->current_nr_sectors = count; + req->nr_segments = 1; /* Always 1 for a new request. */ + req->nr_hw_segments = 1; /* Always 1 for a new request. */ +- req->buffer = bh->b_data; ++ blk_init_req(req, bh, kiobuf); + req->sem = NULL; +- req->bh = bh; +- req->bhtail = bh; +- req->rq_dev = bh->b_rdev; ++ req->rq_dev = dev; ++ req->start_time = jiffies; ++ req_new_io(req, 0, count); + blk_started_io(count); + add_request(q, req, insert_here); + out: +@@ -848,7 +1043,8 @@ + spin_unlock_irq(&io_request_lock); + return 0; + end_io: +- bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); ++ if (bh) ++ bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); + return 0; + } + +@@ -886,22 +1082,35 @@ + * particular, no other flags, are changed by generic_make_request or + * any lower level drivers. + * */ +-void generic_make_request (int rw, struct buffer_head * bh) +-{ +- int major = MAJOR(bh->b_rdev); ++void generic_make_request (int rw, struct buffer_head * bh, ++ struct kiobuf * kiobuf, kdev_t dev, ++ unsigned long blocknr, size_t blksize) ++{ ++ int major, minor; ++ unsigned long sector; ++ unsigned int count; + request_queue_t *q; +- +- if (!bh->b_end_io) +- BUG(); ++ ++ if (bh) { ++ if (!bh->b_end_io) ++ BUG(); ++ count = bh->b_size >> 9; ++ sector = bh->b_rsector; ++ dev = bh->b_rdev; ++ } else { ++ count = kiobuf->length >> 9; ++ sector = blocknr * (blksize >> 9); ++ } ++ major = MAJOR(dev); ++ minor = MINOR(dev); + + if (blk_size[major]) { +- unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1; +- unsigned long sector = bh->b_rsector; +- unsigned int count = bh->b_size >> 9; ++ unsigned long maxsector = (blk_size[major][minor] << 1) + 1; + + if (maxsector < count || maxsector - count < sector) { +- bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped); +- if (blk_size[major][MINOR(bh->b_rdev)]) { ++ if (bh) ++ bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped); ++ if (blk_size[major][minor]) { + + /* This may well happen - the kernel calls bread() + without checking the size of the device, e.g., +@@ -909,11 +1118,14 @@ + printk(KERN_INFO + "attempt to access beyond end of device\n"); + printk(KERN_INFO "%s: rw=%d, want=%ld, limit=%d\n", +- kdevname(bh->b_rdev), rw, ++ kdevname(dev), rw, + (sector + count)>>1, +- blk_size[major][MINOR(bh->b_rdev)]); ++ blk_size[major][minor]); + } +- bh->b_end_io(bh, 0); ++ if (bh) ++ bh->b_end_io(bh, 0); ++ else ++ kiobuf->errno = -EINVAL; + return; + } + } +@@ -927,15 +1139,24 @@ + * Stacking drivers are expected to know what they are doing. + */ + do { +- q = blk_get_queue(bh->b_rdev); ++ /* LVM and others may have changed the dev for bh cases */ ++ if (bh && dev != bh->b_rdev) { ++ dev = bh->b_rdev; ++ sector = bh->b_rsector; ++ } ++ ++ q = blk_get_queue(dev); + if (!q) { + printk(KERN_ERR + "generic_make_request: Trying to access nonexistent block-device %s (%ld)\n", +- kdevname(bh->b_rdev), bh->b_rsector); +- buffer_IO_error(bh); ++ kdevname(dev), sector); ++ if (bh) ++ buffer_IO_error(bh); ++ else ++ kiobuf->errno = -ENODEV; + break; + } +- } while (q->make_request_fn(q, rw, bh)); ++ } while (q->make_request_fn(q, rw, bh, kiobuf, dev, sector, count)); + } + + +@@ -968,7 +1189,7 @@ + bh->b_rdev = bh->b_dev; + bh->b_rsector = bh->b_blocknr * count; + +- generic_make_request(rw, bh); ++ generic_make_request(rw, bh, NULL, 0, 0, 0); + + switch (rw) { + case WRITE: +@@ -1110,6 +1331,98 @@ + mark_buffer_clean(bhs[i]); + } + ++ ++ ++/* ++ * Function: ll_rw_kio() ++ * ++ * Purpose: Insert kiobuf-based request into request queue. ++ * ++ * Arguments: rw - read/write ++ * kiobuf - collection of pages ++ * dev - device against which I/O requested ++ * blocknr - dev block number at which to start I/O ++ * sector - units (512B or other) of blocknr ++ * error - return status ++ * ++ * Lock status: Assumed no lock held upon entry. ++ * Assumed that the pages in the kiobuf ___ARE LOCKED DOWN___. ++ * ++ * Returns: Nothing ++ * ++ * Notes: This function is called from any subsystem using kiovec[] ++ * collection of kiobufs for I/O (e.g. `pagebufs', raw-io). ++ * Relies on "kiobuf" field in the request structure. ++ */ ++void ll_rw_kio(int rw, struct kiobuf *kiobuf, kdev_t dev, unsigned long blocknr, ++ size_t sector, int *error) ++{ ++ int correct_size, i; ++ ++ /* ++ * Only support SCSI disk for now. ++ * ++ * ENOSYS to indicate caller ++ * should try ll_rw_block() ++ * for non-SCSI (e.g. IDE) disks. ++ */ ++ if (!SCSI_DISK_MAJOR(MAJOR(dev)) && !IDE_DISK_MAJOR(MAJOR(dev))) { ++ *error = -ENOSYS; ++ goto end_io; ++ } ++ /* ++ * Sanity checks ++ */ ++ correct_size = BLOCK_SIZE; ++ if (blksize_size[MAJOR(dev)]) { ++ if ((i = blksize_size[MAJOR(dev)][MINOR(dev)])) ++ correct_size = i; ++ } ++ if (kiobuf->length % correct_size) { ++ printk(KERN_NOTICE "ll_rw_kio: " ++ "request size [%d] not a multiple of device [%s] block-size [%d]\n", ++ kiobuf->length, ++ kdevname(dev), ++ correct_size); ++ *error = -EINVAL; ++ goto end_io; ++ } ++ if ((rw & WRITE) && is_read_only(dev)) { ++ printk(KERN_NOTICE "Can't write to read-only device %s\n", ++ kdevname(dev)); ++ *error = -EPERM; ++ goto end_io; ++ } ++ ++ switch(rw) { ++ case WRITE: ++ kstat.pgpgout++; ++ break; ++ ++ case READA: ++ case READ: ++ kstat.pgpgin++; ++ break; ++ default: ++ BUG(); ++ } ++ ++ generic_make_request(rw, NULL, kiobuf, dev, blocknr, sector); ++ if (kiobuf->errno != 0) { ++ *error = kiobuf->errno; ++ goto end_io; ++ } ++ ++ return; ++end_io: ++ /* ++ * We come here only on an error so, just set ++ * kiobuf->errno if it isn't already set and return. ++ */ ++ if(kiobuf->errno == 0) ++ kiobuf->errno = *error; ++} ++ + #ifdef CONFIG_STRAM_SWAP + extern int stram_device_init (void); + #endif +@@ -1157,6 +1470,7 @@ + req->nr_sectors = req->hard_nr_sectors; + + req->current_nr_sectors = bh->b_size >> 9; ++ req->hard_cur_sectors = bh->b_size >> 9; + if (req->nr_sectors < req->current_nr_sectors) { + req->nr_sectors = req->current_nr_sectors; + printk("end_request: buffer-list destroyed\n"); +@@ -1172,6 +1486,7 @@ + { + if (req->sem != NULL) + up(req->sem); ++ req_finished_io(req); + + blkdev_release_request(req); + } +@@ -1340,6 +1655,7 @@ + EXPORT_SYMBOL(io_request_lock); + EXPORT_SYMBOL(end_that_request_first); + EXPORT_SYMBOL(end_that_request_last); ++EXPORT_SYMBOL(req_finished_io); + EXPORT_SYMBOL(blk_init_queue); + EXPORT_SYMBOL(blk_get_queue); + EXPORT_SYMBOL(__blk_get_queue); +@@ -1348,6 +1664,7 @@ + EXPORT_SYMBOL(blk_queue_pluggable); + EXPORT_SYMBOL(blk_queue_make_request); + EXPORT_SYMBOL(generic_make_request); ++EXPORT_SYMBOL(ll_rw_kio); + EXPORT_SYMBOL(blkdev_release_request); + EXPORT_SYMBOL(generic_unplug_device); + EXPORT_SYMBOL(queued_sectors); + +=========================================================================== +Index: linux/drivers/block/loop.c +=========================================================================== + +--- linux/drivers/block/loop.c Tue Apr 3 17:46:10 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/drivers/block/loop.c_1.29 Tue Apr 3 17:57:09 2001 +@@ -418,7 +418,9 @@ + return bh; + } + +-static int loop_make_request(request_queue_t *q, int rw, struct buffer_head *rbh) ++static int loop_make_request(request_queue_t *q, int rw, struct buffer_head *rbh, ++ struct kiobuf *kio, kdev_t dev, unsigned int block, ++ unsigned int bsize) + { + struct buffer_head *bh = NULL; + struct loop_device *lo; +@@ -473,7 +475,7 @@ + goto err; + } + +- generic_make_request(rw, bh); ++ generic_make_request(rw, bh, NULL, 0, 0, 0); + return 0; + + err: + +=========================================================================== +Index: linux/drivers/block/rd.c +=========================================================================== + +--- linux/drivers/block/rd.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/drivers/block/rd.c_1.27 Tue Apr 3 17:57:09 2001 +@@ -194,7 +194,9 @@ + * 19-JAN-1998 Richard Gooch Added devfs support + * + */ +-static int rd_make_request(request_queue_t * q, int rw, struct buffer_head *sbh) ++static int rd_make_request(request_queue_t * q, int rw, struct buffer_head *sbh, ++ struct kiobuf *kio, kdev_t dev, unsigned int block, ++ unsigned int bsize) + { + unsigned int minor; + unsigned long offset, len; + +=========================================================================== +Index: linux/drivers/char/raw.c +=========================================================================== + +--- linux/drivers/char/raw.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/drivers/char/raw.c_1.13 Tue Apr 3 17:57:09 2001 +@@ -240,6 +240,76 @@ + #define SECTOR_SIZE (1U << SECTOR_BITS) + #define SECTOR_MASK (SECTOR_SIZE - 1) + ++/* ++ * IO completion routine for a kiobuf-based request. ++ */ ++static void end_kiobuf_io_kiobuf(struct kiobuf *kiobuf) ++{ ++ kiobuf->locked = 0; ++ if (atomic_dec_and_test(&kiobuf->io_count)) ++ wake_up(&kiobuf->wait_queue); ++} ++ ++/* ++ * Send I/O down the ll_rw_kio() path first. ++ * It is assumed that any requisite locking ++ * and unlocking of pages in the kiobuf has ++ * been taken care of by the caller. ++ * ++ * Return 0 if I/O should be retried on buffer_head path. ++ * Return number of transferred bytes if successful. ++ * Return -1 value, if there was an I/O error. ++ */ ++static inline int try_kiobuf_io(struct kiobuf *iobuf, ++ int rw, ++ unsigned long blocknr, ++ kdev_t dev, ++ char *buf, ++ size_t sector_size) ++{ ++ int err, retval; ++ ++ /* Bounce ... ugh! */ ++ err = setup_kiobuf_bounce_pages(iobuf, GFP_USER); ++ if (err) { ++ retval = 0; ++ goto error; ++ } ++ if (rw & WRITE) ++ kiobuf_copy_bounce(iobuf, COPY_TO_BOUNCE, -1); ++ ++ /* Now do actual I/O */ ++ iobuf->end_io = end_kiobuf_io_kiobuf; ++ iobuf->errno = 0; ++ iobuf->locked = 1; ++ atomic_inc(&iobuf->io_count); ++ err = 0; ++ ll_rw_kio(rw, iobuf, dev, blocknr, sector_size, &err); ++ ++ if ( err == 0 ) { ++ kiobuf_wait_for_io(iobuf); ++ if (iobuf->errno == 0) { ++ retval = iobuf->length; /* Success */ ++ } else { ++ retval = -1; /* I/O error */ ++ } ++ } else { ++ atomic_dec(&iobuf->io_count); ++ if ( err == -ENOSYS ) { ++ retval = 0; /* Retry the buffer_head path */ ++ } else { ++ retval = -1; /* I/O error */ ++ } ++ } ++ ++ error: ++ /* Take care of any bounce buffers allocated */ ++ cleanup_bounce_buffers(rw, 1, &iobuf, retval); ++ iobuf->locked = 0; ++ return retval; ++} ++ ++ + ssize_t rw_raw_dev(int rw, struct file *filp, char *buf, + size_t size, loff_t *offp) + { +@@ -256,7 +326,8 @@ + + int sector_size, sector_bits, sector_mask; + int max_sectors; +- ++ int kiobuf_io = 1; ++ + /* + * First, a few checks on device size limits + */ +@@ -288,17 +359,17 @@ + if (err) + return err; + ++ blocknr = *offp >> sector_bits; + /* +- * Split the IO into KIO_MAX_SECTORS chunks, mapping and +- * unmapping the single kiobuf as we go to perform each chunk of +- * IO. ++ * Try sending down the entire kiobuf first via ll_rw_kio(). ++ * If not successful then, split the IO into KIO_MAX_SECTORS ++ * chunks, mapping and unmapping the single kiobuf as we go ++ * to perform each chunk of IO. + */ +- +- transferred = 0; +- blocknr = *offp >> sector_bits; ++ err = transferred = 0; + while (size > 0) { + blocks = size >> sector_bits; +- if (blocks > max_sectors) ++ if (blocks > max_sectors && (kiobuf_io == 0)) + blocks = max_sectors; + if (blocks > limit - blocknr) + blocks = limit - blocknr; +@@ -315,11 +386,20 @@ + if (err) + break; + #endif +- +- for (i=0; i < blocks; i++) +- b[i] = blocknr++; ++ if (kiobuf_io == 0) { ++ for (i=0; i < blocks; i++) ++ b[i] = blocknr++; + +- err = brw_kiovec(rw, 1, &iobuf, dev, b, sector_size); ++ err = brw_kiovec(rw, 1, &iobuf, dev, b, sector_size); ++ } else { ++ err = try_kiobuf_io(iobuf, rw, blocknr, dev, buf, sector_size); ++ if ( err > 0 ) { ++ blocknr += (err >> sector_bits); ++ } else if ( err == 0 ) { ++ kiobuf_io = 0; ++ continue; ++ } /* else if err < 0, break out of loop below */ ++ } + + if (err >= 0) { + transferred += err; + +=========================================================================== +Index: linux/drivers/ide/ide-disk.c +=========================================================================== + +--- linux/drivers/ide/ide-disk.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/drivers/ide/ide-disk.c_1.12 Tue Apr 3 17:57:09 2001 +@@ -220,6 +220,88 @@ + } + + /* ++ * Function: __ide_update_bh_request() ++ * ++ * Purpose: Helper routine for ide_multwrite() to update the rq->buffer ++ * pointer and rq->X_Y_sectors, if not at the end of I/O. ++ * ++ * Arguments: rq - request struct. ++ * mcount - max. size of PRD table for I/O. ++ * ++ * Lock status: Assumed that io_requset_lock is held upon entry. ++ * ++ * Returns: Nothing ++ * ++ * Notes: Separate buffer-head processing from kiobuf processing ++ * We're operating on the hwgroup->wrq. ++ */ ++inline void __ide_update_bh_request(struct request *rq, unsigned int *mcount) ++{ ++ struct buffer_head *bh = rq->bh->b_reqnext; ++ ++ /* end early early we ran out of requests */ ++ if (!bh) { ++ *mcount = 0; ++ } else { ++ rq->bh = bh; ++ rq->current_nr_sectors = bh->b_size >> 9; ++ rq->buffer = bh->b_data; ++ } ++} ++ ++/* ++ * Function: __ide_update_kio_request() ++ * ++ * Purpose: Helper routine for ide_multwrite() to update the rq->buffer ++ * pointer and rq->X_Y_sectors, if not at the end of I/O. ++ * ++ * Arguments: req - request struct. ++ * mcount - max. size of PRD table for I/O ++ * ++ * Lock status: Assumed that io_requset_lock is held upon entry. ++ * ++ * Returns: Nothing ++ * ++ * Notes: Separate buffer-head processing from kiobuf processing ++ * We're operating on the hwgroup->wrq. ++ */ ++inline void __ide_update_kio_request(struct request *rq, int c_off, unsigned int *mcount) ++{ ++ int index = 0; ++ unsigned int nr_bytes; ++ ++ /* How far into the kiobuf is the offset? */ ++ if (c_off > PAGE_CACHE_SIZE) { ++ index = c_off >> PAGE_CACHE_SHIFT; ++ c_off &= ~PAGE_CACHE_MASK; ++ } ++ ++ /* Finished all sectors? */ ++ if (rq->nr_sectors == 0) { ++ *mcount = 0; ++ } else { ++ /* Sanity check: c_off should be page-aligned */ ++ if (c_off & ~PAGE_CACHE_MASK) { ++ printk("Offset calculations busted in ide_multwrite()!\n"); ++ BUG(); ++ } ++ if (index >= rq->kiobuf->nr_pages) { ++ printk("Index fell off end of kiobuf\n"); ++ BUG(); ++ } ++ nr_bytes = rq->nr_sectors << 9; ++ /* Update rq->current_nr_sectors based on nr_bytes value */ ++ if (PAGE_CACHE_SIZE > nr_bytes) ++ rq->current_nr_sectors = nr_bytes >> 9; ++ else ++ rq->current_nr_sectors = PAGE_CACHE_SIZE >> 9; ++ ++ /* Update rq->buffer */ ++ rq->buffer = page_address(rq->kiobuf->maplist[index]); ++ } ++} ++ ++/* + * ide_multwrite() transfers a block of up to mcount sectors of data + * to a drive as part of a disk multiple-sector write operation. + * +@@ -234,35 +316,50 @@ + { + ide_hwgroup_t *hwgroup= HWGROUP(drive); + struct request *rq = &hwgroup->wrq; ++ unsigned long flags; + + do { +- char *buffer; + int nsect = rq->current_nr_sectors; ++ char *buffer; + + if (nsect > mcount) + nsect = mcount; + mcount -= nsect; + buffer = rq->buffer; + ++ /* ++ * Careful: ide_multwrite() Can be called from both non-irq ++ * and irq context. Grab (i.e. abuse!) the io_request_lock. ++ */ ++ spin_lock_irqsave(&io_request_lock, flags); ++ + rq->sector += nsect; + rq->buffer += nsect << 9; + rq->nr_sectors -= nsect; + rq->current_nr_sectors -= nsect; ++ rq->hard_nr_sectors -= nsect; /* Necessary to track completion! */ + +- /* Do we move to the next bh after this? */ +- if (!rq->current_nr_sectors) { +- struct buffer_head *bh = rq->bh->b_reqnext; ++ if (rq->kiobuf) { ++ hwgroup->kio_offset += nsect << 9; ++ } + +- /* end early early we ran out of requests */ +- if (!bh) { +- mcount = 0; +- } else { +- rq->bh = bh; +- rq->current_nr_sectors = bh->b_size >> 9; +- rq->buffer = bh->b_data; +- } ++ /* ++ * Do we need to update rq->buffer after this? ++ * Note: ide_multwrite/multwrite_intr operate on ++ * the hwgroup->wrq; whereas the end_request() ++ * operate on the original hwgroup->rq. ++ */ ++ if (!rq->current_nr_sectors) { ++ if (rq->kiobuf) { ++ __ide_update_kio_request(rq, ++ hwgroup->kio_offset, &mcount); ++ } else { ++ __ide_update_bh_request(rq, &mcount); ++ } + } + ++ spin_unlock_irqrestore(&io_request_lock, flags); ++ + /* + * Ok, we're all setup for the interrupt + * re-entering us on the last transfer. +@@ -306,6 +403,9 @@ + i -= rq->current_nr_sectors; + ide_end_request(1, hwgroup); + } ++ if (rq->kiobuf) ++ hwgroup->kio_offset = 0; ++ + return ide_stopped; + } + } +@@ -369,7 +469,13 @@ + { + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl,IDE_CONTROL_REG); +- OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG); ++ ++ /* ++ * for clustered kio requests, nr_sectors can be much bigger than ++ * what ide hw can handle. do those in chunks of 256 ++ */ ++ OUT_BYTE(rq->nr_sectors < 256 ? rq->nr_sectors : 0, IDE_NSECTOR_REG); ++ + #ifdef CONFIG_BLK_DEV_PDC4030 + if (drive->select.b.lba || IS_PDC4030_DRIVE) { + #else /* !CONFIG_BLK_DEV_PDC4030 */ +@@ -440,7 +546,33 @@ + * + * Except when you get an error it seems... + */ ++ ++ /* ++ * I/O is done in chunks of 256 sectors. The ++ * "scratchpad" (including rq->nr_sectors) is ++ * copied over for every ide_multwrite() call, ++ * below. So, we need to preserve the current ++ * value of wrq->nr_sectors before it is written ++ * over. This is necessary for termination condition ++ * in multwrite_intr(). ++ * ++ * This is only an issue for kiobuf requests which ++ * are larger than the 256 sectors PRD limit. ++ * ++ * YUCK! ++ */ ++ unsigned long nr_sectors = 0; ++ /* If a kiobuf request and is a re-injection */ ++ if (rq->kiobuf && (rq->kiobuf->offset < hwgroup->kio_offset)) ++ nr_sectors = rq->nr_sectors - hwgroup->wrq.nr_sectors; ++ + hwgroup->wrq = *rq; /* scratchpad */ ++ hwgroup->wrq.nr_sectors -= nr_sectors; ++ ++ /* If a kiobuf request and is an original injection */ ++ if (rq->kiobuf && hwgroup->kio_offset == 0) ++ hwgroup->kio_offset = rq->kiobuf->offset; ++ + ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL); + if (ide_multwrite(drive, drive->mult_count)) { + unsigned long flags; + +=========================================================================== +Index: linux/drivers/ide/ide-dma.c +=========================================================================== + +--- linux/drivers/ide/ide-dma.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/drivers/ide/ide-dma.c_1.9 Tue Apr 3 17:57:09 2001 +@@ -199,9 +199,10 @@ + if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) { + if (!dma_stat) { + struct request *rq = HWGROUP(drive)->rq; +- rq = HWGROUP(drive)->rq; +- for (i = rq->nr_sectors; i > 0;) { +- i -= rq->current_nr_sectors; ++ if ((i = rq->nr_sectors) > 256) ++ i = 256; ++ while (i > 0) { ++ i -= rq->hard_cur_sectors; + ide_end_request(1, HWGROUP(drive)); + } + return ide_stopped; +@@ -211,16 +212,81 @@ + return ide_error(drive, "dma_intr", stat); + } + +-static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq) ++/* ++ * Build kiobuf based scatter-gather list. Return number of segments. ++ */ ++static int ide_kio_sgl(struct request *rq, struct scatterlist *sg) ++{ ++ unsigned int total_bytes, nr_bytes, nr_seg, sg_size, segs; ++ struct kiobuf *kiobuf = rq->kiobuf; ++ unsigned int c_off, nr_pgs = 0, nr_sects = 0; ++ unsigned char *va; ++ ++ /* ++ * For leftover requests, only rq->nr_sectors gets adjusted. ++ */ ++ total_bytes = rq->nr_sectors << 9; ++ ++ /* ++ * find offset ++ */ ++ c_off = kiobuf->offset + (((kiobuf->length >> 9) - rq->nr_sectors) << 9); ++ if (c_off >= PAGE_SIZE) { ++ nr_pgs = (c_off >> PAGE_SHIFT); ++ c_off &= ~PAGE_MASK; ++ } ++ ++ /* ++ * limit to max ide hw size, if need be ++ */ ++ if ((segs = rq->nr_segments) > PRD_ENTRIES) ++ segs = PRD_ENTRIES; ++ ++ /* ++ * now build sg list ++ */ ++ for (sg_size = 0, nr_seg = 0, nr_bytes = 0; nr_seg < segs && nr_sects <= 256; nr_seg++, nr_sects += sg_size >> 9) { ++ va = c_off + (char *) page_address(kiobuf->maplist[nr_pgs]); ++ nr_pgs++; ++ if (c_off) { ++ if ((sg_size = PAGE_SIZE - c_off) > total_bytes) ++ sg_size = total_bytes; ++ ++ c_off = 0; ++ } else if (nr_bytes + PAGE_SIZE > total_bytes) { ++ sg_size = total_bytes - nr_bytes; ++ } else { ++ sg_size = PAGE_SIZE; ++ } ++ ++ nr_bytes += sg_size; ++ memset(&sg[nr_seg], 0, sizeof(struct scatterlist)); ++ sg[nr_seg].address = va; ++ sg[nr_seg].length = sg_size; ++ } ++ ++ /* ++ * your plain paranoia ++ */ ++ if ((nr_bytes > total_bytes) || (nr_pgs > rq->kiobuf->nr_pages)) { ++ printk(KERN_ERR ++ "ide_kio_sgl: sgl bytes[%d], request bytes[%d]\n" ++ "ide_kio_sgl: pgcnt[%d], kiobuf->pgcnt[%d]!\n", ++ nr_bytes, total_bytes, nr_pgs, kiobuf->nr_pages); ++ BUG(); ++ } ++ ++ return nr_seg; ++} ++ ++/* ++ * Build bh based scatter-gather list. Return number of segments. ++ */ ++static int ide_bh_sgl(struct request *rq, struct scatterlist *sg) + { + struct buffer_head *bh; +- struct scatterlist *sg = hwif->sg_table; + int nents = 0; + +- if (rq->cmd == READ) +- hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; +- else +- hwif->sg_dma_direction = PCI_DMA_TODEVICE; + bh = rq->bh; + do { + unsigned char *virt_addr = bh->b_data; +@@ -234,12 +300,32 @@ + break; + size += bh->b_size; + } +- memset(&sg[nents], 0, sizeof(*sg)); ++ memset(&sg[nents], 0, sizeof(struct scatterlist)); + sg[nents].address = virt_addr; + sg[nents].length = size; + nents++; + } while (bh != NULL); + ++ return nents; ++} ++ ++static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq) ++{ ++ struct scatterlist *sg = hwif->sg_table; ++ int nents; ++ ++ if (rq->cmd == READ) ++ hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; ++ else ++ hwif->sg_dma_direction = PCI_DMA_TODEVICE; ++ ++ if (rq->bh) ++ nents = ide_bh_sgl(rq, sg); ++ else if (rq->kiobuf) ++ nents = ide_kio_sgl(rq, sg); ++ else ++ panic("neither rq->bh nor rq->kiobuf in place\n"); ++ + return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction); + } + +@@ -306,8 +392,11 @@ + i--; + } + +- if (!count) ++ if (!count) { ++ struct request *rq = HWGROUP(drive)->rq; + printk("%s: empty DMA table?\n", drive->name); ++ printk("sector %lu, hard sector %lu, nr_sectors %lu, hard nr_sectors %lu, cur nr_sectors %lu\n", rq->sector, rq->hard_sector, rq->nr_sectors, rq->hard_nr_sectors, rq->current_nr_sectors); ++ } + else if (!is_trm290_chipset) + *--table |= cpu_to_le32(0x80000000); + + +=========================================================================== +Index: linux/drivers/ide/ide.c +=========================================================================== + +--- linux/drivers/ide/ide.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/drivers/ide/ide.c_1.19 Tue Apr 3 17:57:09 2001 +@@ -502,6 +502,92 @@ + return 1; /* drive ready: *might* be interrupting */ + } + ++int ide_end_kio_request(struct request *rq, int uptodate, int sectors) ++{ ++ int pgcnt = 0, nr_pages; ++ size_t curr_offset; ++ unsigned int nr_bytes, total_bytes, page_sectors, nr_sectors; ++ char *va = NULL; ++ ++ if ((nr_sectors = rq->hard_nr_sectors) > 256) ++ nr_sectors = 256; ++ ++ blk_finished_io(sectors); ++ ++ nr_pages = rq->kiobuf->nr_pages; ++ total_bytes = nr_sectors << 9; ++ curr_offset = rq->kiobuf->offset; ++ ++ /* ++ * In the case of leftover requests, the kiobuf->length ++ * remains the same, but rq->nr_sectors would be smaller. ++ * Adjust curr_offset in this case. If not a leftover, ++ * the following makes no difference. ++ */ ++ curr_offset += (((rq->kiobuf->length >> 9) - nr_sectors) << 9); ++ ++ /* How far into the kiobuf is the offset? */ ++ if (curr_offset > PAGE_SIZE) { ++ pgcnt = curr_offset >> PAGE_SHIFT; ++ curr_offset &= ~PAGE_MASK; ++ } ++ ++ /* ++ * Reusing the pgcnt and va value from above: ++ * Harvest pages to account for number of sectors ++ * passed into function. ++ */ ++ for (nr_bytes = 0; pgcnt < nr_pages && nr_bytes != total_bytes; pgcnt++) { ++ va = page_address(rq->kiobuf->maplist[pgcnt]) + curr_offset; ++ /* First page or final page? Partial page? */ ++ if (curr_offset) { ++ if (PAGE_SIZE - curr_offset > total_bytes) ++ page_sectors = total_bytes >> 9; ++ else ++ page_sectors = (PAGE_SIZE - curr_offset) >> 9; ++ curr_offset = 0; ++ } else if (nr_bytes + PAGE_SIZE > total_bytes) { ++ page_sectors = (total_bytes - nr_bytes) >> 9; ++ } else { ++ page_sectors = PAGE_SIZE >> 9; ++ } ++ nr_bytes += (page_sectors << 9); ++ /* Leftover sectors in this page (onward)? */ ++ if (sectors < page_sectors) { ++ rq->hard_nr_sectors -= sectors; ++ rq->sector += sectors; ++ rq->hard_cur_sectors = page_sectors - sectors; ++ va += (sectors << 9); /* Update for rq->buffer */ ++ sectors = 0; ++ break; ++ } ++ ++ /* Mark this page as done */ ++ rq->nr_segments--; ++ rq->hard_nr_sectors -= page_sectors; ++ rq->sector += page_sectors; ++ if (!uptodate && rq->kiobuf->errno) ++ rq->kiobuf->errno = -EIO; ++ sectors -= page_sectors; ++ } ++ ++ rq->current_nr_sectors = rq->hard_cur_sectors; ++ rq->nr_sectors = rq->hard_nr_sectors; ++ ++ /* Check for leftovers */ ++ if (rq->hard_nr_sectors) { ++ rq->buffer = va; ++ if (!rq->nr_segments) ++ rq->nr_segments = 1; ++ return 1; ++ } ++ ++ if (rq->kiobuf->end_io) ++ rq->kiobuf->end_io(rq->kiobuf); ++ ++ return 0; ++} ++ + /* + * This is our end_request replacement function. + */ +@@ -509,11 +595,24 @@ + { + struct request *rq; + unsigned long flags; ++ int r; + + spin_lock_irqsave(&io_request_lock, flags); + rq = hwgroup->rq; + +- if (!end_that_request_first(rq, uptodate, hwgroup->drive->name)) { ++ /* ++ * kiovec request ++ */ ++ if (rq->kiobuf) ++ r = ide_end_kio_request(rq, uptodate, rq->hard_cur_sectors); ++ else ++ r = end_that_request_first(rq, uptodate, hwgroup->drive->name); ++ ++ /* ++ * finish request if either kiovec request or bh based request ++ * is done ++ */ ++ if (!r) { + add_blkdev_randomness(MAJOR(rq->rq_dev)); + blkdev_dequeue_request(rq); + hwgroup->rq = NULL; + +=========================================================================== +Index: linux/drivers/md/raid1.c +=========================================================================== + +--- linux/drivers/md/raid1.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/drivers/md/raid1.c_1.6 Tue Apr 3 17:57:09 2001 +@@ -608,7 +608,7 @@ + /* bh_req->b_rsector = bh->n_rsector; */ + bh_req->b_end_io = raid1_end_request; + bh_req->b_private = r1_bh; +- generic_make_request (rw, bh_req); ++ generic_make_request (rw, bh_req, NULL, 0, 0, 0); + return 0; + } + +@@ -683,7 +683,7 @@ + while(bh) { + struct buffer_head *bh2 = bh; + bh = bh->b_next; +- generic_make_request(rw, bh2); ++ generic_make_request(rw, bh2, NULL, 0, 0, 0); + } + return (0); + } +@@ -1179,7 +1179,7 @@ + while (mbh) { + struct buffer_head *bh1 = mbh; + mbh = mbh->b_next; +- generic_make_request(WRITE, bh1); ++ generic_make_request(WRITE, bh1, NULL, 0, 0, 0); + md_sync_acct(bh1->b_dev, bh1->b_size/512); + } + } else { +@@ -1192,7 +1192,7 @@ + printk (REDIRECT_SECTOR, + partition_name(bh->b_dev), bh->b_blocknr); + bh->b_rdev = bh->b_dev; +- generic_make_request(READ, bh); ++ generic_make_request(READ, bh, NULL, 0, 0, 0); + } + } + +@@ -1209,7 +1209,7 @@ + printk (REDIRECT_SECTOR, + partition_name(bh->b_dev), bh->b_blocknr); + bh->b_rdev = bh->b_dev; +- generic_make_request (r1_bh->cmd, bh); ++ generic_make_request (r1_bh->cmd, bh, NULL, 0, 0, 0); + } + break; + } +@@ -1395,7 +1395,7 @@ + bh->b_rsector = sector; + init_waitqueue_head(&bh->b_wait); + +- generic_make_request(READ, bh); ++ generic_make_request(READ, bh, NULL, 0, 0, 0); + md_sync_acct(bh->b_dev, bh->b_size/512); + + return (bsize >> 9); + +=========================================================================== +Index: linux/drivers/md/raid5.c +=========================================================================== + +--- linux/drivers/md/raid5.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/drivers/md/raid5.c_1.12 Tue Apr 3 17:57:09 2001 +@@ -1096,7 +1096,7 @@ + atomic_inc(&sh->count); + bh->b_rdev = bh->b_dev; + bh->b_rsector = bh->b_blocknr * (bh->b_size>>9); +- generic_make_request(action[i]-1, bh); ++ generic_make_request(action[i]-1, bh, NULL, 0, 0, 0); + } else { + PRINTK("skip op %d on disc %d for sector %ld\n", action[i]-1, i, sh->sector); + clear_bit(BH_Lock, &bh->b_state); + +=========================================================================== +Index: linux/drivers/scsi/scsi_lib.c +=========================================================================== + +--- linux/drivers/scsi/scsi_lib.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/drivers/scsi/scsi_lib.c_1.28 Tue Apr 3 17:57:09 2001 +@@ -15,6 +15,8 @@ + * a low-level driver if they wished. Note however that this file also + * contains the "default" versions of these functions, as we don't want to + * go through and retrofit queueing functions into all 30 some-odd drivers. ++ * ++ * Added support for kiobuf-based I/O requests. [Chaitanya Tumuluri, chait@sgi.com] + */ + + #define __NO_VERSION__ +@@ -330,6 +332,155 @@ + spin_unlock_irqrestore(&io_request_lock, flags); + } + ++ ++/* ++ * Function: __scsi_collect_bh_sectors() ++ * ++ * Purpose: Helper routine for __scsi_end_request() to mark some number ++ * (or all, if that is the case) of sectors complete. ++ * ++ * Arguments: req - request struct. from scsi command block. ++ * uptodate - 1 if I/O indicates success, 0 for I/O error. ++ * sectors - number of sectors we want to mark. ++ * leftovers- indicates if any sectors were not done. ++ * ++ * Lock status: Assumed that lock is not held upon entry. ++ * ++ * Returns: Nothing ++ * ++ * Notes: Separate buffer-head processing from kiobuf processing ++ */ ++__inline static void __scsi_collect_bh_sectors(struct request *req, ++ int uptodate, ++ int sectors, ++ char **leftovers) ++{ ++ struct buffer_head *bh; ++ int nsect; ++ ++ do { ++ if ((bh = req->bh) != NULL) { ++ nsect = bh->b_size >> 9; ++ blk_finished_io(nsect); ++ req->bh = bh->b_reqnext; ++ req->nr_sectors -= nsect; ++ req->sector += nsect; ++ bh->b_reqnext = NULL; ++ sectors -= nsect; ++ bh->b_end_io(bh, uptodate); ++ if ((bh = req->bh) != NULL) { ++ req->current_nr_sectors = bh->b_size >> 9; ++ if (req->nr_sectors < req->current_nr_sectors) { ++ req->nr_sectors = req->current_nr_sectors; ++ printk("scsi_end_request: buffer-list destroyed\n"); ++ } ++ } ++ } ++ } while (sectors && bh); ++ ++ /* Check for leftovers */ ++ if (req->bh) { ++ *leftovers = req->bh->b_data; ++ } ++} ++ ++/* ++ * Function: __scsi_collect_kio_sectors() ++ * ++ * Purpose: Helper routine for __scsi_end_request() to mark some number ++ * (or all) of the I/O sectors and attendant pages complete. ++ * Updates the request nr_segments, nr_sectors accordingly. ++ * ++ * Arguments: req - request struct. from scsi command block. ++ * uptodate - 1 if I/O indicates success, 0 for I/O error. ++ * sectors - number of sectors we want to mark. ++ * leftovers- indicates if any sectors were not done. ++ * ++ * Lock status: Assumed that lock is not held upon entry. ++ * ++ * Returns: Nothing ++ * ++ * Notes: Separate buffer-head processing from kiobuf processing. ++ * We don't know if this was a single or multi-segment sgl ++ * request. Treat it as though it were a multi-segment one. ++ */ ++__inline static void __scsi_collect_kio_sectors(struct request *req, ++ int uptodate, ++ int sectors, ++ char **leftovers) ++{ ++ int pgcnt = 0, nr_pages; ++ size_t curr_offset; ++ unsigned long va = 0; ++ unsigned int nr_bytes, total_bytes, page_sectors; ++ ++ nr_pages = req->kiobuf->nr_pages; ++ total_bytes = (req->nr_sectors << 9); ++ curr_offset = req->kiobuf->offset; ++ ++ blk_finished_io(sectors); ++ ++ /* ++ * In the case of leftover requests, the kiobuf->length ++ * remains the same, but req->nr_sectors would be smaller. ++ * Adjust curr_offset in this case. If not a leftover, ++ * the following makes no difference. ++ */ ++ curr_offset += (((req->kiobuf->length >> 9) - req->nr_sectors) << 9); ++ ++ /* How far into the kiobuf is the offset? */ ++ if (curr_offset > PAGE_SIZE) { ++ pgcnt = (curr_offset >> PAGE_SHIFT); ++ curr_offset &= ~PAGE_MASK; ++ } ++ ++ /* ++ * Reusing the pgcnt and va value from above: ++ * Harvest pages to account for number of sectors ++ * passed into function. ++ */ ++ for (nr_bytes = 0; pgcntkiobuf->maplist[pgcnt]) + curr_offset; ++ /* First page or final page? Partial page? */ ++ if (curr_offset != 0) { ++ page_sectors = (PAGE_SIZE - curr_offset) > total_bytes ? ++ total_bytes >> 9 : (PAGE_SIZE - curr_offset) >> 9; ++ curr_offset = 0; ++ } else if((nr_bytes + PAGE_SIZE) > total_bytes) { ++ page_sectors = (total_bytes - nr_bytes) >> 9; ++ } else { ++ page_sectors = PAGE_SIZE >> 9; ++ } ++ nr_bytes += (page_sectors << 9); ++ /* Leftover sectors in this page (onward)? */ ++ if (sectors < page_sectors) { ++ req->nr_sectors -= sectors; ++ req->sector += sectors; ++ req->current_nr_sectors = page_sectors - sectors; ++ va += (sectors << 9); /* Update for req->buffer */ ++ sectors = 0; ++ break; ++ } else { ++ /* Mark this page as done */ ++ req->nr_segments--; /* No clustering for kiobuf */ ++ req->nr_sectors -= page_sectors; ++ req->sector += page_sectors; ++ if (!uptodate && (req->kiobuf->errno != 0)){ ++ req->kiobuf->errno = -EIO; ++ } ++ sectors -= page_sectors; ++ } ++ } ++ ++ /* Check for leftovers */ ++ if (req->nr_sectors) { ++ *leftovers = (char *)va; ++ } else if (req->kiobuf->end_io) { ++ req->kiobuf->end_io(req->kiobuf); ++ } ++} ++ ++ + /* + * Function: scsi_end_request() + * +@@ -360,10 +511,9 @@ + int frequeue) + { + struct request *req; +- struct buffer_head *bh; +- Scsi_Device * SDpnt; +- int nsect; +- ++ char * leftovers = NULL; ++ Scsi_Device * SDpnt; ++ + ASSERT_LOCK(&io_request_lock, 0); + + req = &SCpnt->request; +@@ -372,47 +522,36 @@ + printk(" I/O error: dev %s, sector %lu\n", + kdevname(req->rq_dev), req->sector); + } +- do { +- if ((bh = req->bh) != NULL) { +- nsect = bh->b_size >> 9; +- blk_finished_io(nsect); +- req->bh = bh->b_reqnext; +- req->nr_sectors -= nsect; +- req->sector += nsect; +- bh->b_reqnext = NULL; +- sectors -= nsect; +- bh->b_end_io(bh, uptodate); +- if ((bh = req->bh) != NULL) { +- req->current_nr_sectors = bh->b_size >> 9; +- if (req->nr_sectors < req->current_nr_sectors) { +- req->nr_sectors = req->current_nr_sectors; +- printk("scsi_end_request: buffer-list destroyed\n"); +- } +- } +- } +- } while (sectors && bh); ++ ++ leftovers = NULL; ++ if (req->bh != NULL) { /* Buffer head based request */ ++ __scsi_collect_bh_sectors(req, uptodate, sectors, &leftovers); ++ } else if (req->kiobuf != NULL) { /* Kiobuf based request */ ++ __scsi_collect_kio_sectors(req, uptodate, sectors, &leftovers); ++ } else { ++ panic("Both bh and kiobuf pointers are unset in request!\n"); ++ } + + /* + * If there are blocks left over at the end, set up the command + * to queue the remainder of them. + */ +- if (req->bh) { ++ if (leftovers != NULL) { + request_queue_t *q; +- +- if( !requeue ) +- { +- return SCpnt; +- } ++ ++ if( !requeue ) { ++ return SCpnt; ++ } + + q = &SCpnt->device->request_queue; +- +- req->buffer = bh->b_data; +- /* +- * Bleah. Leftovers again. Stick the leftovers in +- * the front of the queue, and goose the queue again. +- */ +- scsi_queue_next_request(q, SCpnt); +- return SCpnt; ++ ++ req->buffer = leftovers; ++ /* ++ * Bleah. Leftovers again. Stick the leftovers in ++ * the front of the queue, and goose the queue again. ++ */ ++ scsi_queue_next_request(q, SCpnt); ++ return SCpnt; + } + /* + * This request is done. If there is someone blocked waiting for this +@@ -422,6 +561,7 @@ + if (req->sem != NULL) { + up(req->sem); + } ++ req_finished_io(req); + add_blkdev_randomness(MAJOR(req->rq_dev)); + + SDpnt = SCpnt->device; +@@ -581,13 +721,13 @@ + scsi_free(SCpnt->buffer, SCpnt->sglist_len); + } else { + if (SCpnt->buffer != SCpnt->request.buffer) { +- if (SCpnt->request.cmd == READ) { +- memcpy(SCpnt->request.buffer, SCpnt->buffer, +- SCpnt->bufflen); +- } +- scsi_free(SCpnt->buffer, SCpnt->bufflen); ++ if (SCpnt->request.cmd == READ) { ++ memcpy(SCpnt->request.buffer, SCpnt->buffer, ++ SCpnt->bufflen); ++ } ++ scsi_free(SCpnt->buffer, SCpnt->bufflen); + } +- } ++ } + + /* + * Zero these out. They now point to freed memory, and it is +@@ -631,7 +771,7 @@ + * rest of the command, or start a new one. + */ + if (result == 0 || SCpnt == NULL ) { +- return; ++ return; + } + } + /* +@@ -815,7 +955,7 @@ + Scsi_Device *SDpnt; + struct Scsi_Host *SHpnt; + struct Scsi_Device_Template *STpnt; +- ++ + ASSERT_LOCK(&io_request_lock, 1); + + SDpnt = (Scsi_Device *) q->queuedata; + +=========================================================================== +Index: linux/drivers/scsi/scsi_merge.c +=========================================================================== + +--- linux/drivers/scsi/scsi_merge.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/drivers/scsi/scsi_merge.c_1.26 Tue Apr 3 17:57:09 2001 +@@ -6,6 +6,7 @@ + * Based upon conversations with large numbers + * of people at Linux Expo. + * Support for dynamic DMA mapping: Jakub Jelinek (jakub@redhat.com). ++ * Support for kiobuf-based I/O requests. [Chaitanya Tumuluri, chait@sgi.com] + */ + + /* +@@ -90,7 +91,7 @@ + printk("nr_segments is %x\n", req->nr_segments); + printk("counted segments is %x\n", segments); + printk("Flags %d %d\n", use_clustering, dma_host); +- for (bh = req->bh; bh->b_reqnext != NULL; bh = bh->b_reqnext) ++ for (bh = req->bh; bh != NULL; bh = bh->b_reqnext) + { + printk("Segment 0x%p, blocks %d, addr 0x%lx\n", + bh, +@@ -298,9 +299,22 @@ + SHpnt = SCpnt->host; + SDpnt = SCpnt->device; + +- req->nr_segments = __count_segments(req, +- CLUSTERABLE_DEVICE(SHpnt, SDpnt), +- SHpnt->unchecked_isa_dma, NULL); ++ if (req->bh){ ++ req->nr_segments = __count_segments(req, ++ CLUSTERABLE_DEVICE(SHpnt, SDpnt), ++ SHpnt->unchecked_isa_dma, NULL); ++ } else if (req->kiobuf){ ++ /* Since there is no clustering/merging in kiobuf ++ * requests, the nr_segments is simply a count of ++ * the number of pages needing I/O. nr_segments is ++ * updated in __scsi_collect_kio_sectors() called ++ * from scsi_end_request(), for the leftover case. ++ * [chait@sgi.com] ++ */ ++ return; ++ } else { ++ panic("Both kiobuf and bh pointers are NULL!"); ++ } + } + + #define MERGEABLE_BUFFERS(X,Y) \ +@@ -743,6 +757,186 @@ + MERGEREQFCT(scsi_merge_requests_fn_, 0, 0) + MERGEREQFCT(scsi_merge_requests_fn_c, 1, 0) + MERGEREQFCT(scsi_merge_requests_fn_dc, 1, 1) ++ ++ ++ ++/* ++ * Function: scsi_bh_sgl() ++ * ++ * Purpose: Helper routine to construct S(catter) G(ather) L(ist) ++ * assuming buffer_head-based request in the Scsi_Cmnd. ++ * ++ * Arguments: SCpnt - Command descriptor ++ * use_clustering - 1 if host uses clustering ++ * dma_host - 1 if this host has ISA DMA issues (bus doesn't ++ * expose all of the address lines, so that DMA cannot ++ * be done from an arbitrary address). ++ * sgpnt - pointer to sgl ++ * ++ * Returns: Number of sg segments in the sgl. ++ * ++ * Notes: Only the SCpnt argument should be a non-constant variable. ++ * This functionality was abstracted out of the original code ++ * in __init_io(). ++ */ ++__inline static int scsi_bh_sgl(Scsi_Cmnd * SCpnt, ++ int use_clustering, ++ int dma_host, ++ struct scatterlist * sgpnt) ++{ ++ int count; ++ struct buffer_head * bh; ++ struct buffer_head * bhprev; ++ ++ bhprev = NULL; ++ ++ for (count = 0, bh = SCpnt->request.bh; bh; bh = bh->b_reqnext) { ++ if (use_clustering && bhprev != NULL) { ++ if (dma_host && ++ virt_to_phys(bhprev->b_data) - 1 == ISA_DMA_THRESHOLD) { ++ /* Nothing - fall through */ ++ } else if (CONTIGUOUS_BUFFERS(bhprev, bh)) { ++ /* ++ * This one is OK. Let it go. Note that we ++ * do not have the ability to allocate ++ * bounce buffer segments > PAGE_SIZE, so ++ * for now we limit the thing. ++ */ ++ if( dma_host ) { ++#ifdef DMA_SEGMENT_SIZE_LIMITED ++ if( virt_to_phys(bh->b_data) - 1 < ISA_DMA_THRESHOLD ++ || sgpnt[count - 1].length + bh->b_size <= PAGE_SIZE ) { ++ sgpnt[count - 1].length += bh->b_size; ++ bhprev = bh; ++ continue; ++ } ++#else ++ sgpnt[count - 1].length += bh->b_size; ++ bhprev = bh; ++ continue; ++#endif ++ } else { ++ sgpnt[count - 1].length += bh->b_size; ++ SCpnt->request_bufflen += bh->b_size; ++ bhprev = bh; ++ continue; ++ } ++ } ++ } ++ count++; ++ sgpnt[count - 1].address = bh->b_data; ++ sgpnt[count - 1].length += bh->b_size; ++ if (!dma_host) { ++ SCpnt->request_bufflen += bh->b_size; ++ } ++ bhprev = bh; ++ } ++ ++ return count; ++} ++ ++ ++/* ++ * Function: scsi_kio_sgl() ++ * ++ * Purpose: Helper routine to construct S(catter) G(ather) L(ist) ++ * assuming kiobuf-based request in the Scsi_Cmnd. ++ * ++ * Arguments: SCpnt - Command descriptor ++ * dma_host - 1 if this host has ISA DMA issues (bus doesn't ++ * expose all of the address lines, so that DMA cannot ++ * be done from an arbitrary address). ++ * sgpnt - pointer to sgl ++ * ++ * Returns: Number of sg segments in the sgl. ++ * ++ * Notes: Only the SCpnt argument should be a non-constant variable. ++ * This functionality was created out of __ini_io() in the ++ * original implementation for constructing the sgl for ++ * kiobuf-based I/Os as well. ++ * ++ * Constructs SCpnt->use_sg sgl segments for the kiobuf. ++ * ++ * No clustering of pages is attempted unlike the buffer_head ++ * case. Primarily because the pages in a kiobuf are unlikely to ++ * be contiguous. Bears checking. ++ */ ++__inline static int scsi_kio_sgl(Scsi_Cmnd * SCpnt, ++ int dma_host, ++ struct scatterlist * sgpnt) ++{ ++ int pgcnt = 0, nr_seg, curr_seg, nr_sectors, curr_offset; ++ unsigned int nr_bytes, total_bytes, sgl_seg_bytes; ++ unsigned long va; ++ ++ curr_seg = SCpnt->use_sg; /* This many sgl segments */ ++ nr_sectors = SCpnt->request.nr_sectors; ++ total_bytes = (nr_sectors << 9); ++ curr_offset = SCpnt->request.kiobuf->offset; ++ ++ /* ++ * In the case of leftover requests, the kiobuf->length ++ * remains the same, but req->nr_sectors would be smaller. ++ * Use this difference to adjust curr_offset in this case. ++ * If not a leftover, the following makes no difference. ++ */ ++ curr_offset += (((SCpnt->request.kiobuf->length >> 9) - nr_sectors) << 9); ++ /* How far into the kiobuf is the offset? */ ++ if (curr_offset >= PAGE_SIZE) { ++ pgcnt = (curr_offset >> PAGE_SHIFT); ++ curr_offset &= ~PAGE_MASK; ++ } ++ ++ /* ++ * Reusing the pgcnt value from above: ++ * Starting at the right page and offset, build curr_seg ++ * sgl segments (one per page). Account for both a ++ * potentially partial last page and unrequired pages ++ * at the end of the kiobuf. ++ */ ++ nr_bytes = 0; ++ for (nr_seg = 0; nr_seg < curr_seg; nr_seg++) { ++ va = (unsigned long) page_address(SCpnt->request.kiobuf->maplist[pgcnt]) ++ + curr_offset; ++ ++pgcnt; ++ ++ /* ++ * If this is the first page, account for offset. ++ * If this the final (maybe partial) page, get remainder. ++ */ ++ if (curr_offset != 0) { ++ sgl_seg_bytes = (PAGE_SIZE - curr_offset) > total_bytes ? ++ total_bytes : (PAGE_SIZE - curr_offset); ++ curr_offset = 0; ++ } else if((nr_bytes + PAGE_SIZE) > total_bytes) { ++ sgl_seg_bytes = total_bytes - nr_bytes; ++ } else { ++ sgl_seg_bytes = PAGE_SIZE; ++ } ++ ++ nr_bytes += sgl_seg_bytes; ++ sgpnt[nr_seg].address = (char *)va; ++ sgpnt[nr_seg].alt_address = 0; ++ sgpnt[nr_seg].length = sgl_seg_bytes; ++ ++ if (!dma_host) ++ SCpnt->request_bufflen += sgl_seg_bytes; ++ } ++ /* Sanity Check */ ++ if ((nr_bytes > total_bytes) || ++ (pgcnt > SCpnt->request.kiobuf->nr_pages)) { ++ printk(KERN_ERR ++ "scsi_kio_sgl: sgl bytes[%d], request bytes[%d]\n" ++ "scsi_kio_sgl: pgcnt[%d], kiobuf->pgcnt[%d]!\n", ++ nr_bytes, total_bytes, pgcnt, SCpnt->request.kiobuf->nr_pages); ++ BUG(); ++ } ++ return nr_seg; ++ ++} ++ ++ ++ + /* + * Function: __init_io() + * +@@ -775,6 +969,9 @@ + * gather list, the sg count in the request won't be valid + * (mainly because we don't need queue management functions + * which keep the tally uptodate. ++ * ++ * Modified to handle kiobuf argument in the SCpnt->request ++ * structure. + */ + __inline static int __init_io(Scsi_Cmnd * SCpnt, + int sg_count_valid, +@@ -782,7 +979,6 @@ + int dma_host) + { + struct buffer_head * bh; +- struct buffer_head * bhprev; + char * buff; + int count; + int i; +@@ -797,13 +993,13 @@ + * needed any more. Need to play with it and see if we hit the + * panic. If not, then don't bother. + */ +- if (!SCpnt->request.bh) { ++ if ((!SCpnt->request.bh && !SCpnt->request.kiobuf) || ++ (SCpnt->request.bh && SCpnt->request.kiobuf)) { + /* +- * Case of page request (i.e. raw device), or unlinked buffer +- * Typically used for swapping, but this isn't how we do +- * swapping any more. ++ * Case of unlinked buffer. Typically used for swapping, ++ * but this isn't how we do swapping any more. + */ +- panic("I believe this is dead code. If we hit this, I was wrong"); ++ panic("I believe this is dead code. If we hit this, I was wrong"); + #if 0 + SCpnt->request_bufflen = SCpnt->request.nr_sectors << 9; + SCpnt->request_buffer = SCpnt->request.buffer; +@@ -817,6 +1013,12 @@ + req = &SCpnt->request; + /* + * First we need to know how many scatter gather segments are needed. ++ * ++ * Redundant test per comment below indicating sg_count_valid is always ++ * set to 1.(ll_rw_blk.c's estimate of req->nr_segments is always trusted). ++ * ++ * count is initialized in ll_rw_kio() for the kiobuf path and since these ++ * requests are never merged, the counts are stay valid. + */ + if (!sg_count_valid) { + count = __count_segments(req, use_clustering, dma_host, NULL); +@@ -835,17 +1037,30 @@ + } + /* + * Don't bother with scatter-gather if there is only one segment. +- */ ++ */ + if (count == 1) { + this_count = SCpnt->request.nr_sectors; + goto single_segment; + } +- SCpnt->use_sg = count; ++ /* Check if size of the sgl would be greater than the size ++ * of the host sgl table. In which case, limit the sgl size. ++ * When the request sectors are harvested after completion of ++ * I/O in __scsi_collect_kio_sectors, the additional sectors ++ * will be reinjected into the request queue as a special cmd. ++ * This will be done till all the request sectors are done. ++ * [chait@sgi.com] ++ */ ++ if((SCpnt->request.kiobuf != NULL) && ++ (count > SCpnt->host->sg_tablesize)) { ++ count = SCpnt->host->sg_tablesize - 1; ++ } + ++ SCpnt->use_sg = count; + /* + * Allocate the actual scatter-gather table itself. + * scsi_malloc can only allocate in chunks of 512 bytes + */ ++ + SCpnt->sglist_len = (SCpnt->use_sg + * sizeof(struct scatterlist) + 511) & ~511; + +@@ -870,49 +1085,13 @@ + memset(sgpnt, 0, SCpnt->sglist_len); + SCpnt->request_buffer = (char *) sgpnt; + SCpnt->request_bufflen = 0; +- bhprev = NULL; + +- for (count = 0, bh = SCpnt->request.bh; +- bh; bh = bh->b_reqnext) { +- if (use_clustering && bhprev != NULL) { +- if (dma_host && +- virt_to_phys(bhprev->b_data) - 1 == ISA_DMA_THRESHOLD) { +- /* Nothing - fall through */ +- } else if (CONTIGUOUS_BUFFERS(bhprev, bh)) { +- /* +- * This one is OK. Let it go. Note that we +- * do not have the ability to allocate +- * bounce buffer segments > PAGE_SIZE, so +- * for now we limit the thing. +- */ +- if( dma_host ) { +-#ifdef DMA_SEGMENT_SIZE_LIMITED +- if( virt_to_phys(bh->b_data) - 1 < ISA_DMA_THRESHOLD +- || sgpnt[count - 1].length + bh->b_size <= PAGE_SIZE ) { +- sgpnt[count - 1].length += bh->b_size; +- bhprev = bh; +- continue; +- } +-#else +- sgpnt[count - 1].length += bh->b_size; +- bhprev = bh; +- continue; +-#endif +- } else { +- sgpnt[count - 1].length += bh->b_size; +- SCpnt->request_bufflen += bh->b_size; +- bhprev = bh; +- continue; +- } +- } +- } +- count++; +- sgpnt[count - 1].address = bh->b_data; +- sgpnt[count - 1].length += bh->b_size; +- if (!dma_host) { +- SCpnt->request_bufflen += bh->b_size; +- } +- bhprev = bh; ++ if (SCpnt->request.bh){ ++ count = scsi_bh_sgl(SCpnt, use_clustering, dma_host, sgpnt); ++ } else if (SCpnt->request.kiobuf) { ++ count = scsi_kio_sgl(SCpnt, dma_host, sgpnt); ++ } else { ++ panic("Yowza! Both kiobuf and buffer_head pointers are null!"); + } + + /* +@@ -1007,6 +1186,17 @@ + scsi_free(SCpnt->request_buffer, SCpnt->sglist_len); + + /* ++ * Shouldn't ever get here for a kiobuf request. ++ * ++ * Since each segment is a page and also, we couldn't ++ * allocate bounce buffers for even the first page, ++ * this means that the DMA buffer pool is exhausted! ++ */ ++ if (SCpnt->request.kiobuf){ ++ dma_exhausted(SCpnt, 0); ++ } ++ ++ /* + * Make an attempt to pick up as much as we reasonably can. + * Just keep adding sectors until the pool starts running kind of + * low. The limit of 30 is somewhat arbitrary - the point is that +@@ -1041,34 +1231,33 @@ + * segment. Possibly the entire request, or possibly a small + * chunk of the entire request. + */ +- bh = SCpnt->request.bh; + buff = SCpnt->request.buffer; + + if (dma_host) { +- /* +- * Allocate a DMA bounce buffer. If the allocation fails, fall +- * back and allocate a really small one - enough to satisfy +- * the first buffer. +- */ +- if (virt_to_phys(SCpnt->request.bh->b_data) +- + (this_count << 9) - 1 > ISA_DMA_THRESHOLD) { +- buff = (char *) scsi_malloc(this_count << 9); +- if (!buff) { +- printk("Warning - running low on DMA memory\n"); +- this_count = SCpnt->request.current_nr_sectors; +- buff = (char *) scsi_malloc(this_count << 9); +- if (!buff) { +- dma_exhausted(SCpnt, 0); +- } +- } +- if (SCpnt->request.cmd == WRITE) +- memcpy(buff, (char *) SCpnt->request.buffer, this_count << 9); +- } ++ /* ++ * Allocate a DMA bounce buffer. If the allocation fails, fall ++ * back and allocate a really small one - enough to satisfy ++ * the first buffer. ++ */ ++ if (virt_to_phys(SCpnt->request.buffer) + (this_count << 9) - 1 > ++ ISA_DMA_THRESHOLD) { ++ buff = (char *) scsi_malloc(this_count << 9); ++ if (!buff) { ++ printk("Warning - running low on DMA memory\n"); ++ this_count = SCpnt->request.current_nr_sectors; ++ buff = (char *) scsi_malloc(this_count << 9); ++ if (!buff) { ++ dma_exhausted(SCpnt, 0); ++ } ++ } ++ if (SCpnt->request.cmd == WRITE) ++ memcpy(buff, (char *) SCpnt->request.buffer, this_count << 9); ++ } + } + SCpnt->request_bufflen = this_count << 9; + SCpnt->request_buffer = buff; + SCpnt->use_sg = 0; +- return 1; ++ return 1; + } + + #define INITIO(_FUNCTION, _VALID, _CLUSTER, _DMA) \ + +=========================================================================== +Index: linux/drivers/scsi/sd.c +=========================================================================== + +--- linux/drivers/scsi/sd.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/drivers/scsi/sd.c_1.33 Tue Apr 3 17:57:09 2001 +@@ -590,7 +590,10 @@ + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | + SCpnt->sense_buffer[6]; +- if (SCpnt->request.bh != NULL) ++ /* Tweak to support kiobuf-based I/O requests, [chait@sgi.com] */ ++ if (SCpnt->request.kiobuf != NULL) ++ block_sectors = SCpnt->request.kiobuf->length >> 9; ++ else if (SCpnt->request.bh != NULL) + block_sectors = SCpnt->request.bh->b_size >> 9; + switch (SCpnt->device->sector_size) { + case 1024: + +=========================================================================== +Index: linux/fs/buffer.c +=========================================================================== + +--- linux/fs/buffer.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/fs/buffer.c_1.59 Tue Apr 3 17:57:09 2001 +@@ -2078,6 +2078,34 @@ + } + + /* ++ * Clean up the bounce buffers potentially used by brw_kiovec. All of ++ * the kiovec's bounce buffers must be cleared of temporarily allocated ++ * bounce pages, but only READ pages for whom IO completed successfully ++ * can actually be transferred back to user space. ++ */ ++ ++void cleanup_bounce_buffers(int rw, int nr, struct kiobuf *iovec[], ++ int transferred) ++{ ++ int i; ++ for (i = 0; i < nr; i++) { ++ struct kiobuf *iobuf = iovec[i]; ++ if (iobuf->bounced) { ++ if (transferred > 0 && !(rw & WRITE)) ++ kiobuf_copy_bounce(iobuf, COPY_FROM_BOUNCE, ++ transferred); ++ ++ clear_kiobuf_bounce_pages(iobuf); ++ } ++ transferred -= iobuf->length; ++ } ++ ++ /* Your vanilla paranoia */ ++ if (transferred > 0) ++ BUG(); ++} ++ ++/* + * Start I/O on a physical range of kernel memory, defined by a vector + * of kiobuf structs (much like a user-space iovec list). + * +@@ -2126,6 +2154,12 @@ + bufind = bhind = transferred = err = 0; + for (i = 0; i < nr; i++) { + iobuf = iovec[i]; ++ err = setup_kiobuf_bounce_pages(iobuf, GFP_USER); ++ if (err) ++ goto finished; ++ if (rw & WRITE) ++ kiobuf_copy_bounce(iobuf, COPY_TO_BOUNCE, -1); ++ + offset = iobuf->offset; + length = iobuf->length; + iobuf->errno = 0; +@@ -2197,6 +2231,8 @@ + } + + finished: ++ cleanup_bounce_buffers(rw, nr, iovec, transferred); ++ + if (transferred) + return transferred; + return err; +@@ -2209,6 +2245,14 @@ + __put_unused_buffer_head(bh[i]); + } + spin_unlock(&unused_list_lock); ++ ++ /* ++ * This deallocates bounce pages for current kiobuf. Then, ++ * cleanup_bounce_buffers() copies from previously bounced ++ * kiobufs in the iovec[] and deallocates those bounce pages. ++ */ ++ clear_kiobuf_bounce_pages(iobuf); ++ + goto finished; + } + + +=========================================================================== +Index: linux/fs/iobuf.c +=========================================================================== + +--- linux/fs/iobuf.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/fs/iobuf.c_1.16 Tue Apr 3 17:57:09 2001 +@@ -8,6 +8,7 @@ + + #include + #include ++#include + + static kmem_cache_t *kiobuf_cachep; + +@@ -41,6 +42,7 @@ + init_waitqueue_head(&iobuf->wait_queue); + iobuf->array_len = KIO_STATIC_PAGES; + iobuf->maplist = iobuf->map_array; ++ iobuf->orig_maplist = iobuf->orig_map_array; + } + + int alloc_kiovec(int nr, struct kiobuf **bufp) +@@ -61,6 +63,27 @@ + return 0; + } + ++void clear_kiobuf_bounce_pages(struct kiobuf *iobuf) ++{ ++ int i; ++ ++ if (!iobuf->bounced) ++ return; ++ ++ for (i = 0; i < iobuf->nr_pages; i++) { ++ struct page *page = iobuf->orig_maplist[i]; ++ if (page) { ++ page = iobuf->maplist[i]; ++ iobuf->maplist[i] = iobuf->orig_maplist[i]; ++ __free_pages(page, 0); ++ iobuf->orig_maplist[i] = NULL; ++ } ++ } ++ iobuf->bounced = 0; ++} ++ ++ ++ + void free_kiovec(int nr, struct kiobuf **bufp) + { + int i; +@@ -68,17 +91,22 @@ + + for (i = 0; i < nr; i++) { + iobuf = bufp[i]; ++ clear_kiobuf_bounce_pages(iobuf); + if (iobuf->locked) + unlock_kiovec(1, &iobuf, iobuf->nr_pages); +- if (iobuf->array_len > KIO_STATIC_PAGES) ++ ++ if (iobuf->array_len > KIO_STATIC_PAGES) { + kfree (iobuf->maplist); ++ kfree (iobuf->orig_maplist); ++ } ++ + kmem_cache_free(kiobuf_cachep, bufp[i]); + } + } + + int expand_kiobuf(struct kiobuf *iobuf, int wanted) + { +- struct page ** maplist; ++ struct page **maplist, **orig_maplist; + + if (iobuf->array_len >= wanted) + return 0; +@@ -87,23 +115,215 @@ + kmalloc(wanted * sizeof(struct page **), GFP_KERNEL); + if (!maplist) + return -ENOMEM; +- ++ else { ++ orig_maplist = (struct page **) ++ kmalloc(wanted * sizeof(struct page **), GFP_KERNEL); ++ if (!orig_maplist) ++ return -ENOMEM; ++ } ++ + /* Did it grow while we waited? */ + if (iobuf->array_len >= wanted) { + kfree(maplist); ++ kfree(orig_maplist); + return 0; + } +- ++ ++ memset(maplist, 0, wanted * sizeof(struct page **)); ++ memset(orig_maplist, 0, wanted * sizeof(struct page **)); + memcpy (maplist, iobuf->maplist, iobuf->array_len * sizeof(struct page **)); ++ memcpy (orig_maplist, iobuf->orig_maplist, iobuf->array_len * sizeof(struct page **)); + +- if (iobuf->array_len > KIO_STATIC_PAGES) ++ if (iobuf->array_len > KIO_STATIC_PAGES) { + kfree (iobuf->maplist); ++ kfree (iobuf->orig_maplist); ++ } + +- iobuf->maplist = maplist; ++ iobuf->maplist = maplist; ++ iobuf->orig_maplist = orig_maplist; + iobuf->array_len = wanted; + return 0; + } + ++/* ++ * Test whether a given page from the bounce buffer matches the given ++ * gfp_mask. Return true if a bounce buffer is required for this ++ * page. ++ */ ++ ++static inline int test_bounce_page(struct page * map, int gfp_mask) ++{ ++ /* ++ * Unmapped pages from PCI memory or HIGHMEM pages always need a ++ * bounce buffer unless the caller is prepared to accept ++ * GFP_HIGHMEM pages. ++ */ ++ ++ if (PageHighMem(map)) ++ /* ++ * Careful, the following must return the right value ++ * even if CONFIG_HIGHMEM is not set ++ */ ++ return !(gfp_mask & __GFP_HIGHMEM); ++ ++ /* ++ * Possibly, Non-DMA-capable page and needs ++ * bounce buffers if GFP_DMA is requested ++ */ ++ return gfp_mask & __GFP_DMA; ++} ++ ++ ++ ++/* ++ * Note: orig_maplist[] contains only original pages. ++ * maplist[] contains both original and bounce-pages. ++ */ ++int setup_kiobuf_bounce_pages(struct kiobuf *iobuf, int gfp_mask) ++{ ++ int i; ++#if CONFIG_HIGHMEM ++ int try_count=0; ++#endif ++ ++ clear_kiobuf_bounce_pages(iobuf); ++ ++ for (i = 0; i < iobuf->nr_pages; i++) { ++ struct page *map = iobuf->maplist[i]; ++ struct page *bounce_page; ++ ++ bounce_page = NULL; ++ if (!test_bounce_page(map, gfp_mask)) { ++ iobuf->orig_maplist[i] = 0; ++ continue; ++ } ++#if CONFIG_HIGHMEM ++ try_again: ++ bounce_page = alloc_pages(GFP_KERNEL, 0); ++ if (!bounce_page) { ++ if (try_count < 8) { /* Arbit. limit */ ++ ++try_count; ++ wakeup_bdflush(1); ++ current->policy |= SCHED_YIELD; ++ schedule(); ++ goto try_again; ++ } else if (try_count == 8) { ++ run_task_queue(&tq_disk); ++ ++try_count; ++ goto try_again; ++ } else ++ goto error; ++ } ++ iobuf->orig_maplist[i] = iobuf->maplist[i]; ++ iobuf->maplist[i] = bounce_page; ++ iobuf->bounced = 1; ++#else ++ printk("Bouncing needed in non-highmem kernel?!\n"); ++ BUG(); ++#endif ++ } ++ return 0; ++ ++#if CONFIG_HIGHMEM ++ error: ++ printk("Failed bounce-page allocation!\n"); ++ clear_kiobuf_bounce_pages(iobuf); ++ return -ENOMEM; ++#endif ++} ++/* ++ * Copy a bounce buffer. For completion of partially-failed read IOs, ++ * we need to be able to place an upper limit on the data successfully ++ * transferred from bounce buffers to the user's own buffers. ++ */ ++ ++void kiobuf_copy_bounce(struct kiobuf *iobuf, int direction, int max) ++{ ++ int i; ++ int offset, length; ++ ++ if (!iobuf->bounced) ++ return; ++ ++ offset = iobuf->offset; ++ length = iobuf->length; ++ if (max >= 0 && length > max) ++ length = max; ++ ++ i = 0; ++ if (offset > PAGE_SIZE) { ++ i = (offset >> PAGE_SHIFT); ++ offset &= ~PAGE_MASK; ++ } ++ ++ for (; i < iobuf->nr_pages && length > 0; i++) { ++ struct page *page = iobuf->orig_maplist[i]; ++ int pagelen = length; ++ ++ if (page) { ++#if CONFIG_HIGHMEM ++ struct page *bounce_page = iobuf->maplist[i]; ++ unsigned long kin, kout; ++ ++ /* If this is the first page, account for offset. */ ++ if (offset && ( (PAGE_SIZE - offset) < pagelen )) ++ pagelen = PAGE_SIZE - offset; ++ else if (pagelen > PAGE_SIZE) ++ pagelen = PAGE_SIZE; ++ ++ /* ++ * Ouch...kmap() may be called from interrupt ++ * context. Song and dance to avoid re-entrancy. ++ */ ++ if (in_interrupt()) { ++ unsigned long flags; ++ ++ __save_flags(flags); ++ __cli(); ++ ++ if (direction == COPY_TO_BOUNCE) { ++ kout = (unsigned long) page_address(bounce_page); ++ kin = kmap_atomic(page, KM_BOUNCE_WRITE); ++ } else { ++ kin = (unsigned long) page_address(bounce_page); ++ kout = kmap_atomic(page, KM_BOUNCE_READ); ++ } ++ ++ memcpy((char *) (kout+offset), ++ (char *) (kin+offset), ++ pagelen); ++ ++ if (direction == COPY_TO_BOUNCE) ++ kunmap_atomic(kin, KM_BOUNCE_WRITE); ++ else ++ kunmap_atomic(kout, KM_BOUNCE_READ); ++ __restore_flags(flags); ++ } else { ++ ++ if (direction == COPY_TO_BOUNCE) { ++ kin = kmap(page); ++ kout = (unsigned long) page_address(bounce_page); ++ } else { ++ kout = kmap(page); ++ kin = (unsigned long) page_address(bounce_page); ++ } ++ memcpy((char *) (kout+offset), ++ (char *) (kin+offset), ++ pagelen); ++ kunmap(page); ++ } ++#else ++ printk("Found bounce pages in non-highmem kernel!\n"); ++ BUG(); ++#endif ++ } ++ ++ length -= pagelen; ++ offset = 0; ++ } ++} ++ ++ + + void kiobuf_wait_for_io(struct kiobuf *kiobuf) + { +@@ -124,6 +344,3 @@ + tsk->state = TASK_RUNNING; + remove_wait_queue(&kiobuf->wait_queue, &wait); + } +- +- +- + +=========================================================================== +Index: linux/fs/pagebuf/page_buf.c +=========================================================================== + +--- linux/fs/pagebuf/page_buf.c Tue Apr 3 17:54:39 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/fs/pagebuf/page_buf.c_1.71 Tue Apr 3 17:57:09 2001 +@@ -178,6 +178,7 @@ + + struct pbstats pbstats; + ++#define KIOBUF_IO + #define REMAPPING_SUPPORT + + #ifdef REMAPPING_SUPPORT +@@ -1346,7 +1347,7 @@ + atomic_inc(&PBP(pb)->pb_io_remaining); + + for (itr=0; itr < cnt; itr++){ +- generic_make_request(rw, bufferlist[itr]); ++ generic_make_request(rw, bufferlist[itr], NULL, 0, 0, 0); + } + } else { + if (psync) + +=========================================================================== +Index: linux/fs/partitions/check.c +=========================================================================== + +--- linux/fs/partitions/check.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/fs/partitions/check.c_1.21 Tue Apr 3 17:57:09 2001 +@@ -39,6 +39,7 @@ + extern void initrd_load(void); + + struct gendisk *gendisk_head; ++struct gendisk *major_gendisk[MAX_BLKDEV]; + int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ + + static int (*check_part[])(struct gendisk *hd, kdev_t dev, unsigned long first_sect, int first_minor) = { +@@ -239,12 +240,17 @@ + } + + #ifdef CONFIG_PROC_FS ++/* Normalise the disk performance stats to a notional timer tick of ++ 1ms. */ ++#define MSEC(x) ((x) * 1000 / HZ) ++ + int get_partition_list(char *page, char **start, off_t offset, int count) + { + struct gendisk *dsk; ++ struct hd_struct *hd; + int len; + +- len = sprintf(page, "major minor #blocks name\n\n"); ++ len = sprintf(page, "major minor #blocks name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq\n\n"); + for (dsk = gendisk_head; dsk; dsk = dsk->next) { + int n; + +@@ -252,10 +258,22 @@ + if (dsk->part[n].nr_sects) { + char buf[64]; + +- len += sprintf(page + len, +- "%4d %4d %10d %s\n", ++ hd = &dsk->part[n]; ++ disk_round_stats(hd); ++ len += sprintf(page + len, ++ "%4d %4d %10d %s " ++ "%d %d %d %d %d %d %d %d %d %d %d\n", + dsk->major, n, dsk->sizes[n], +- disk_name(dsk, n, buf)); ++ disk_name(dsk, n, buf), ++ hd->rd_ios, hd->rd_merges, ++ hd->rd_sectors, ++ MSEC(hd->rd_ticks), ++ hd->wr_ios, hd->wr_merges, ++ hd->wr_sectors, ++ MSEC(hd->wr_ticks), ++ hd->ios_in_flight, ++ MSEC(hd->io_ticks), ++ MSEC(hd->aveq)); + if (len < offset) + offset -= len, len = 0; + else if (len >= offset + count) +@@ -409,6 +427,7 @@ + if (!gdev) + return; + grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size); ++ major_gendisk[MAJOR(dev)] = gdev; + } + + void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size) + +=========================================================================== +Index: linux/fs/xfs/linux/xfs_super.c +=========================================================================== + +--- linux/fs/xfs/linux/xfs_super.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/fs/xfs/linux/xfs_super.c_1.112 Tue Apr 3 17:57:10 2001 +@@ -78,6 +78,9 @@ + #define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */ + #define MNTOPT_RO "ro" /* read only */ + #define MNTOPT_RW "rw" /* read/write */ ++#define MNTOPT_NOKIO "nokio" /* no kiobuf io */ ++#define MNTOPT_KIO "kio" /* use kiobuf io */ ++#define MNTOPT_KIOCLUSTER "kiocluster" /* use kiobuf io - with clustering */ + + STATIC int + mountargs_xfs( +@@ -221,6 +224,10 @@ + args->flags |= MS_RDONLY; + } else if (!strcmp(this_char, MNTOPT_NOSUID)) { + args->flags |= MS_NOSUID; ++ } else if (!strcmp(this_char, MNTOPT_KIO)) { ++ args->flags |= MS_KIOBUFIO; ++ } else if (!strcmp(this_char, MNTOPT_KIOCLUSTER)) { ++ args->flags |= MS_KIOBUFIO; + } else { + printk( + "mount: unknown mount option \"%s\".\n", this_char); +@@ -365,6 +372,12 @@ + memset(args, 0, sizeof(struct xfs_args)); + if (mountargs_xfs((char *)data, args) != 0) { + return NULL; ++ } ++ /* check to see if kio is suppose to be on for this mount */ ++ if (args->flags & MS_KIOBUFIO){ ++ sb->s_flags |= MS_KIOBUFIO; ++ printk("XFS (dev: %d/%d) mounting with kiobuf I/O\n", ++ MAJOR(sb->s_dev),MINOR(sb->s_dev)); + } + + args->fsname = uap->spec; + +=========================================================================== +Index: linux/include/linux/blkdev.h +=========================================================================== + +--- linux/include/linux/blkdev.h Tue Apr 3 17:35:15 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/include/linux/blkdev.h_1.29 Tue Apr 3 17:57:10 2001 +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + + struct request_queue; + typedef struct request_queue request_queue_t; +@@ -33,15 +34,17 @@ + kdev_t rq_dev; + int cmd; /* READ or WRITE */ + int errors; ++ unsigned long start_time; + unsigned long sector; + unsigned long nr_sectors; +- unsigned long hard_sector, hard_nr_sectors; ++ unsigned long hard_sector, hard_nr_sectors, hard_cur_sectors; + unsigned int nr_segments; + unsigned int nr_hw_segments; + unsigned long current_nr_sectors; + void * special; + char * buffer; + struct semaphore * sem; ++ struct kiobuf * kiobuf; + struct buffer_head * bh; + struct buffer_head * bhtail; + request_queue_t *q; +@@ -59,7 +62,9 @@ + int); + typedef void (request_fn_proc) (request_queue_t *q); + typedef request_queue_t * (queue_proc) (kdev_t dev); +-typedef int (make_request_fn) (request_queue_t *q, int rw, struct buffer_head *bh); ++typedef int (make_request_fn) (request_queue_t *q, int rw, struct buffer_head *bh, ++ struct kiobuf *kiobuf, kdev_t dev, unsigned int sector, ++ unsigned int count); + typedef void (plug_device_fn) (request_queue_t *q, kdev_t device); + typedef void (unplug_device_fn) (void *q); + +@@ -150,7 +155,9 @@ + extern struct blk_dev_struct blk_dev[MAX_BLKDEV]; + extern void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size); + extern void register_disk(struct gendisk *dev, kdev_t first, unsigned minors, struct block_device_operations *ops, long size); +-extern void generic_make_request(int rw, struct buffer_head * bh); ++extern void generic_make_request(int rw, struct buffer_head * bh, ++ struct kiobuf * kiobuf, kdev_t dev, ++ unsigned long blkocknr, size_t blksize); + extern request_queue_t *blk_get_queue(kdev_t dev); + extern inline request_queue_t *__blk_get_queue(kdev_t dev); + extern void blkdev_release_request(struct request *); + +=========================================================================== +Index: linux/include/linux/fs.h +=========================================================================== + +--- linux/include/linux/fs.h Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/include/linux/fs.h_1.87 Tue Apr 3 17:57:10 2001 +@@ -28,6 +28,7 @@ + + struct poll_table_struct; + ++struct kiobuf; + + /* + * It's silly to have NR_OPEN bigger than NR_FILE, but you can change +@@ -116,6 +117,8 @@ + #define MS_NODIRATIME 2048 /* Do not update directory access times */ + #define MS_BIND 4096 + ++#define MS_KIOBUFIO (1<<17) /* mount flag; use KIOBUF */ ++ + /* + * Flags that can be altered by MS_REMOUNT + */ +@@ -158,6 +161,7 @@ + #define IS_NOEXEC(inode) __IS_FLG(inode, MS_NOEXEC) + #define IS_SYNC(inode) (__IS_FLG(inode, MS_SYNCHRONOUS) || ((inode)->i_flags & S_SYNC)) + #define IS_MANDLOCK(inode) __IS_FLG(inode, MS_MANDLOCK) ++#define IS_KIOBUFIO(inode) __IS_FLG(inode, MS_KIOBUFIO) + + #define IS_QUOTAINIT(inode) ((inode)->i_flags & S_QUOTA) + #define IS_APPEND(inode) ((inode)->i_flags & S_APPEND) +@@ -1260,6 +1264,8 @@ + extern struct buffer_head * get_hash_table(kdev_t, int, int); + extern struct buffer_head * getblk(kdev_t, int, int); + extern void ll_rw_block(int, int, struct buffer_head * bh[]); ++extern void ll_rw_kio(int, struct kiobuf *, kdev_t, unsigned long, ++ size_t, int *); + extern void submit_bh(int, struct buffer_head *); + extern int is_read_only(kdev_t); + extern void __brelse(struct buffer_head *); + +=========================================================================== +Index: linux/include/linux/genhd.h +=========================================================================== + +--- linux/include/linux/genhd.h Tue Apr 3 17:35:15 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/include/linux/genhd.h_1.11 Tue Apr 3 17:57:10 2001 +@@ -51,6 +51,22 @@ + long start_sect; + long nr_sects; + devfs_handle_t de; /* primary (master) devfs entry */ ++ ++ /* Performance stats: */ ++ unsigned int ios_in_flight; ++ unsigned int io_ticks; ++ unsigned int last_idle_time; ++ unsigned int last_queue_change; ++ unsigned int aveq; ++ ++ unsigned int rd_ios; ++ unsigned int rd_merges; ++ unsigned int rd_ticks; ++ unsigned int rd_sectors; ++ unsigned int wr_ios; ++ unsigned int wr_merges; ++ unsigned int wr_ticks; ++ unsigned int wr_sectors; + }; + + #define GENHD_FL_REMOVABLE 1 +@@ -75,6 +91,8 @@ + }; + #endif /* __KERNEL__ */ + ++extern struct gendisk *major_gendisk[]; ++ + #ifdef CONFIG_SOLARIS_X86_PARTITION + + #define SOLARIS_X86_NUMSLICE 8 +@@ -232,6 +250,19 @@ + extern struct gendisk *gendisk_head; /* linked list of disks */ + + char *disk_name (struct gendisk *hd, int minor, char *buf); ++ ++/* ++ * disk_round_stats is used to round off the IO statistics for a disk ++ * for a complete clock tick. ++ */ ++void disk_round_stats(struct hd_struct *hd); ++ ++/* ++ * Account for the completion of an IO request (used by drivers which ++ * bypass the normal end_request processing) ++ */ ++struct request; ++void req_finished_io(struct request *); + + extern void devfs_register_partitions (struct gendisk *dev, int minor, + int unregister); + +=========================================================================== +Index: linux/include/linux/ide.h +=========================================================================== + +--- linux/include/linux/ide.h Tue Apr 3 17:31:50 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/include/linux/ide.h_1.27 Tue Apr 3 17:57:10 2001 +@@ -498,6 +498,7 @@ + struct request *rq; /* current request */ + struct timer_list timer; /* failsafe timer */ + struct request wrq; /* local copy of current write rq */ ++ int kio_offset; /* loccal kiobuf offset */ + unsigned long poll_timeout; /* timeout value during long polls */ + ide_expiry_t *expiry; /* queried upon timeouts */ + } ide_hwgroup_t; +@@ -657,6 +658,7 @@ + #include + + void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup); ++int ide_end_kio_request(struct request *rq, int uptodate, int sectors); + + /* + * This is used for (nearly) all data transfers from/to the IDE interface + +=========================================================================== +Index: linux/include/linux/iobuf.h +=========================================================================== + +--- linux/include/linux/iobuf.h Tue Apr 3 17:49:57 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/include/linux/iobuf.h_1.10 Tue Apr 3 17:57:10 2001 +@@ -43,17 +43,21 @@ + * region, there won't necessarily be page structs defined for + * every address. */ + +- struct page ** maplist; +- +- unsigned int locked : 1; /* If set, pages has been locked */ +- ++ struct page ** maplist; /* Both orig. pages and bounce-pages */ ++ struct page ** orig_maplist; /* Orig. pages which've been bounced */ ++ ++ unsigned int locked : 1; /* If set, pages have been locked */ ++ unsigned int bounced : 1; /* If set, pages have been bounced */ ++ + /* Always embed enough struct pages for 64k of IO */ + struct page * map_array[KIO_STATIC_PAGES]; ++ struct page * orig_map_array[KIO_STATIC_PAGES]; + + /* Dynamic state for IO completion: */ + atomic_t io_count; /* IOs still in progress */ + int errno; /* Status of completed IO */ + void (*end_io) (struct kiobuf *); /* Completion callback */ ++ void *k_dev_id; /* Store kiovec (or pagebuf) here */ + wait_queue_head_t wait_queue; + }; + +@@ -76,9 +80,21 @@ + int expand_kiobuf(struct kiobuf *, int); + void kiobuf_wait_for_io(struct kiobuf *); + ++int setup_kiobuf_bounce_pages(struct kiobuf *, int gfp_mask); ++void clear_kiobuf_bounce_pages(struct kiobuf *); ++void kiobuf_copy_bounce(struct kiobuf *, int direction, int max); ++ ++/* Direction codes for kiobuf_copy_bounce: */ ++enum { ++ COPY_TO_BOUNCE, ++ COPY_FROM_BOUNCE ++}; ++ + /* fs/buffer.c */ + + int brw_kiovec(int rw, int nr, struct kiobuf *iovec[], + kdev_t dev, unsigned long b[], int size); ++void cleanup_bounce_buffers(int rw, int nr, struct kiobuf *iovec[], ++ int transferred); + + #endif /* __LINUX_IOBUF_H */ + +=========================================================================== +Index: linux/include/linux/major.h +=========================================================================== + +--- linux/include/linux/major.h Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/include/linux/major.h_1.24 Tue Apr 3 17:57:10 2001 +@@ -167,8 +167,23 @@ + (SCSI_DISK_MAJOR(M) \ + || (M) == SCSI_CDROM_MAJOR) + +-static __inline__ int scsi_blk_major(int m) { ++static inline int scsi_blk_major(int m) ++{ + return SCSI_BLK_MAJOR(m); ++} ++ ++/* ++ * Tests for IDE devices ++ */ ++#define IDE_DISK_MAJOR(M) ((M) == IDE0_MAJOR || (M) == IDE1_MAJOR || \ ++ (M) == IDE2_MAJOR || (M) == IDE3_MAJOR || \ ++ (M) == IDE4_MAJOR || (M) == IDE5_MAJOR || \ ++ (M) == IDE6_MAJOR || (M) == IDE7_MAJOR || \ ++ (M) == IDE8_MAJOR || (M) == IDE9_MAJOR) ++ ++static inline int ide_blk_major(int m) ++{ ++ return IDE_DISK_MAJOR(m); + } + + #endif + +=========================================================================== +Index: linux/kernel/ksyms.c +=========================================================================== + +--- linux/kernel/ksyms.c Tue Apr 3 17:28:04 2001 ++++ /usr/tmp/TmpDir.30941-0/linux/kernel/ksyms.c_1.82 Tue Apr 3 17:57:10 2001 +@@ -423,6 +423,10 @@ + EXPORT_SYMBOL(unlock_kiovec); + EXPORT_SYMBOL(brw_kiovec); + EXPORT_SYMBOL(kiobuf_wait_for_io); ++EXPORT_SYMBOL(setup_kiobuf_bounce_pages); ++EXPORT_SYMBOL(clear_kiobuf_bounce_pages); ++EXPORT_SYMBOL(kiobuf_copy_bounce); ++EXPORT_SYMBOL(cleanup_bounce_buffers); + + /* dma handling */ + EXPORT_SYMBOL(request_dma); + +=========================================================================== +Index: linux/drivers/md/lvm.c +=========================================================================== + +--- linux/drivers/md/lvm.c Thu Apr 5 09:38:04 2001 ++++ /usr/tmp/TmpDir.10320-0/linux/drivers/md/lvm.c_1.9 Fri Apr 6 09:33:39 2001 +@@ -252,7 +252,8 @@ + /* + * External function prototypes + */ +-static int lvm_make_request_fn(request_queue_t*, int, struct buffer_head*); ++static int lvm_make_request_fn(request_queue_t*, int, struct buffer_head*, ++ struct kiobuf *, kdev_t, unsigned int, unsigned int); + + static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong); + static int lvm_blk_open(struct inode *, struct file *); +@@ -1276,9 +1277,11 @@ + /* + * make request function + */ +-static int lvm_make_request_fn(request_queue_t *q, +- int rw, +- struct buffer_head *bh) { ++static int lvm_make_request_fn(request_queue_t *q, ++ int rw, ++ struct buffer_head *bh, ++ struct kiobuf *kio, kdev_t dev, ++ unsigned int block, unsigned int bsize) { + return (lvm_map(bh, rw) < 0) ? 0 : 1; + } + + +=========================================================================== +Index: linux/drivers/md/md.c +=========================================================================== + +--- linux/drivers/md/md.c Thu Apr 5 09:38:04 2001 ++++ /usr/tmp/TmpDir.10342-0/linux/drivers/md/md.c_1.10 Fri Apr 6 09:34:09 2001 +@@ -176,7 +176,9 @@ + mddev_map[minor].data = NULL; + } + +-static int md_make_request (request_queue_t *q, int rw, struct buffer_head * bh) ++static int md_make_request (request_queue_t *q, int rw, struct buffer_head * bh, ++ struct kiobuf *kio, kdev_t dev, unsigned int block, ++ unsigned int bsize) + { + mddev_t *mddev = kdev_to_mddev(bh->b_rdev); + diff -rNu linux-2.4.7/cmd/xfsmisc/mkinitrd.xfs linux-2.4-xfs/cmd/xfsmisc/mkinitrd.xfs --- linux-2.4.7/cmd/xfsmisc/mkinitrd.xfs Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsmisc/mkinitrd.xfs Tue Mar 20 19:57:16 2001 @@ -0,0 +1,399 @@ +#!/bin/bash + +# mkinitrd +# +# Written by Erik Troan +# +# Contributors: +# Elliot Lee +# Miguel de Icaza +# Christian 'Dr. Disk' Hechelmann +# Michael K. Johnson +# Pierre Habraken +# Jakub Jelinek +# Carlo Arenas Belon (carenas@chasqui.lared.net.pe> +# Keith Owens + +PATH=/sbin:$PATH +export PATH + +VERSION=2.6 + +compress=1 +target="" +kernel="" +force="" +verbose="" +MODULES="" +basicmodules="-pagebuf -xfs_support -xfs" +img_vers="" +modulefile=/etc/modules.conf + +#if [ `uname -m` = "ia64" ]; then +# IMAGESIZE=3000 +#else +# IMAGESIZE=1500 +#fi + +IMAGESIZE=25000 + +PRESCSIMODS="scsi_mod sd_mod unknown" +fstab="/etc/fstab" + +usage () { + echo "usage: `basename $0` [--version] [-v] [-f] [--ifneeded] [--preload ]" >&2 + echo " [--omit-scsi-modules] [--omit-raid-modules] [--with=]" >&2 + echo " [--image-version] [--fstab=] [--nocompress] " >&2 + echo " " >&2 + echo " (ex: `basename $0` /boot/initrd-2.2.5-15.img 2.2.5-15)" >&2 + exit 1 +} + +findmodule() { + skiperrors="" + modName=$1 + if [ $(echo $modName | cut -b1) = "-" ]; then + skiperrors=1 + modName=$(echo $modName | cut -b2-) + fi + + if [ "$modName" = "pluto" ]; then + findmodule fc4 + findmodule soc + fi + if [ "$modName" = "fcal" ]; then + findmodule fc4 + findmodule socal + fi + + fmPath=`(cd /lib/modules/$kernel; find -type f -name $modName.o)` + + if [ ! -f /lib/modules/$kernel/$fmPath ]; then + if [ -n "$skiperrors" ]; then + return + fi + + # ignore the absence of the scsi modules + for n in $PRESCSIMODS; do + if [ "$n" = "$modName" ]; then + return; + fi + done; + + echo "No module $modName found for kernel $kernel" >&2 + exit 1 + fi + + # only need to add each module once + if echo $MODULES | grep $fmPath >/dev/null 2>&1 ; then : ; else + MODULES="$MODULES $fmPath" + fi +} + +inst() { + if [ "$#" != "2" ];then + echo "usage: inst " + return + fi + [ -n "$verbose" ] && echo "$1 -> $2" + cp $1 $2 +} + +while [ $# -gt 0 ]; do + case $1 in + --fstab*) + if echo $1 | grep '=' >/dev/null ; then + fstab=`echo $1 | sed 's/^--fstab=//'` + else + fstab=$2 + shift + fi + ;; + + --with*) + if echo $1 | grep '=' >/dev/null ; then + modname=`echo $1 | sed 's/^--with=//'` + else + modname=$2 + shift + fi + + basicmodules="$basicmodules $modname" + ;; + + --version) + echo "mkinitrd: version $VERSION" + exit 0 + ;; + + -v) + verbose=-v + ;; + + --nocompress) + compress="" + ;; + + --ifneeded) + ifneeded=1 + ;; + + -f) + force=1 + ;; + --preload) + if echo $1 | grep '=' >/dev/null ; then + modname=`echo $1 | sed 's/^--preload=//'` + else + modname=$2 + shift + fi + PREMODS="$PREMODS $modname" + ;; + --omit-scsi-modules) + PRESCSIMODS="" + noscsi=1; + ;; + --omit-raid-modules) + noraid=1; + ;; + --image-version) + img_vers=yes + ;; + *) + if [ -z "$target" ]; then + target=$1 + elif [ -z "$kernel" ]; then + kernel=$1 + else + usage + fi + ;; + esac + + shift +done + +if [ -z "$target" -o -z "$kernel" ]; then + usage +fi + +if [ -n "$img_vers" ]; then + target="$target-$kernel" +fi + +if [ -z "$force" -a -f $target ]; then + echo "$target already exists." >&2 + exit 1 +fi + +if [ ! -d /lib/modules/$kernel ]; then + echo "/lib/modules/$kernel is not a directory." >&2 + exit 1 +fi + +for n in $PREMODS; do + findmodule $n +done + +if [ -z "$noscsi" ]; then + for n in $PRESCSIMODS; do + findmodule $n + done + + if [ ! -f $modulefile ]; then + modulefile=/etc/conf.modules + fi + + if [ -f $modulefile ]; then + scsimodules=`grep scsi_hostadapter $modulefile | grep -v '^[ ]*#' | LC_ALL=C sort -u | awk '{ print $3 }'` + for n in $scsimodules; do + # for now allow scsi modules to come from anywhere. There are some + # RAID controllers with drivers in block/ + findmodule $n + done + fi +fi + +# If we have ide devices and module ide, do the right thing +ide=/proc/ide/ide* +if [ -n "$ide" ]; then + findmodule -ide-mod + findmodule -ide-probe-mod + findmodule -ide-disk +fi + +if [ -z "$noraid" ]; then + # load appropriate raid devices if necessary + if grep '^/dev/md' $fstab | grep -v noauto >/dev/null 2>&1 ; then + for number in $(grep '^[ ]*raid-level' /etc/raidtab | + awk '{print $2}' | LC_ALL=C sort -u) ; do + case $number in + [0145]) + findmodule raid$number + ;; + *) + echo "raid level $number (in /etc/raidtab) not recognized" >&2 + ;; + esac + done + fi +fi + +# check to see if we need to set up a loopback filesystem +rootdev=$(awk '{ if ($2 == "/") { print $1; }}' $fstab) +if echo $rootdev | cut -d/ -f3 | grep loop >/dev/null; then + key="^# $(echo $rootdev | cut -d/ -f3 | tr '[a-z]' '[A-Z]'):" + if ! grep "$key" $fstab > /dev/null; then + echo "The root filesystem is on a $rootdev, but there is no magic entry in $fstab" 1>&2 + echo "for this device. Consult the mkinitrd man page for more information" 2>&2 + exit 1 + fi + + line=$(grep "$key" $fstab) + loopDev=$(echo $line | awk '{print $3}') + loopFs=$(echo $line | awk '{print $4}') + loopFile=$(echo $line | awk '{print $5}') + + basicmodules="$basicmodules -loop" + if [ "$loopFs" = "vfat" -o "$loopFs" = "msdos" ]; then + basicmodules="$basicmodules -fat" + fi + basicmodules="$basicmodules -${loopFs}" + +fi + +for n in $basicmodules; do + findmodule $n +done + +if [ -n "$ifneeded" -a -z "$MODULES" ]; then + if [ -n "$verbose" ]; then + echo "No modules are needed -- not building initrd image." + fi + exit 0 +fi + +if [ -n "$verbose" ]; then + echo "Using modules: $MODULES" +fi + +MNTIMAGE=/tmp/initrd.$$ +IMAGE=/tmp/initrd.img-$$ +MNTPOINT=/tmp/initrd.mnt-$$ +RCFILE=$MNTIMAGE/linuxrc + +if [ -f $MNTIMAGE ]; then + echo "$MNTIMAGE already exists. Remove it and try again" >&2 + exit 1 +fi + +if [ -f $IMAGE ]; then + echo "$IMAGE already exists. Remove it and try again" >&2 + exit 1 +fi + +dd if=/dev/zero of=$IMAGE bs=1k count=$IMAGESIZE 2> /dev/null + +if [ -e /dev/.devfsd ]; then + LOOPDEV=/dev/loop/ +else + LOOPDEV=/dev/loop +fi + +for devnum in 0 1 2 3 4 5 6 7 8; do + if losetup ${LOOPDEV}${devnum} $IMAGE 2>/dev/null ; then break; fi +done + +if [ "$devnum" = "8" ]; then + rm -rf $MNTPOINT $IMAGE + echo "All of your loopback devices are in use!" >&2 + exit 1 +fi + +LODEV=${LOOPDEV}${devnum} + +# We have to "echo y |" so that it doesn't complain about $IMAGE not +# being a block device +echo y | mke2fs $LODEV $IMAGESIZE >/dev/null 2>/dev/null + +if [ -n "$verbose" ]; then + echo "Using loopback device $LODEV" +fi + +mkdir -p $MNTPOINT +mount -t ext2 $LODEV $MNTPOINT || { + echo "Can't get a loopback device" + exit 1 +} + +mkdir -p $MNTIMAGE +mkdir -p $MNTIMAGE/lib +mkdir -p $MNTIMAGE/bin +mkdir -p $MNTIMAGE/etc +mkdir -p $MNTIMAGE/dev +mkdir -p $MNTIMAGE/loopfs + +# We don't need this directory, so let's save space +rm -rf $MNTPOINT/lost+found + +inst /sbin/sash "$MNTIMAGE/bin/sash" +inst /sbin/insmod.static "$MNTIMAGE/bin/insmod" + +for MODULE in $MODULES; do + cp $verbose -a /lib/modules/$kernel/$MODULE $MNTIMAGE/lib +done + +# mknod'ing the devices instead of copying them works both with and +# without devfs... +mknod $MNTIMAGE/dev/console c 5 1 +mknod $MNTIMAGE/dev/null c 1 3 +mknod $MNTIMAGE/dev/ram b 1 1 +mknod $MNTIMAGE/dev/systty c 4 0 +for i in 1 2 3 4; do + mknod $MNTIMAGE/dev/tty$i c 4 1 +done + +echo "#!/bin/sash" > $RCFILE +echo "" >> $RCFILE +echo "aliasall" >> $RCFILE +echo "" >> $RCFILE + +for MODULE in $MODULES; do + module=`echo $MODULE | sed "s|.*/||" | sed "s/.o$//"` + + options=`sed -n -e "s/^options[ ][ ]*$module[ ][ ]*//p" $modulefile` + + if [ -n "$verbose" ]; then + echo "Loading module $module with options $options" + fi + echo "echo \"Loading $module module\"" >> $RCFILE + echo "insmod /lib/$module.o $options" >> $RCFILE +done + +if [ -n "$loopDev" ]; then + if [ ! -d /initrd ]; then + mkdir /initrd + fi + + cp -a $loopDev $MNTIMAGE/dev + cp -a $rootdev $MNTIMAGE/dev + echo "echo Mounting device containing loopback root filesystem" >> $RCFILE + echo "mount -t $loopFs $loopDev /loopfs" >> $RCFILE + echo "echo Setting up loopback device $rootdev" >> $RCFILE + echo "losetup $rootdev /loopfs$loopFile" >> $RCFILE +fi + +chmod +x $RCFILE + +(cd $MNTIMAGE; tar cf - .) | (cd $MNTPOINT; tar xf -) + +umount $MNTPOINT +losetup -d $LODEV + +if [ -n "$compress" ]; then + gzip -9 < $IMAGE > $target +else + cp -a $IMAGE $target +fi +rm -rf $MNTIMAGE $MNTPOINT $IMAGE diff -rNu linux-2.4.7/cmd/xfsmisc/xfs_stats.pl linux-2.4-xfs/cmd/xfsmisc/xfs_stats.pl --- linux-2.4.7/cmd/xfsmisc/xfs_stats.pl Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsmisc/xfs_stats.pl Tue Apr 3 15:00:08 2001 @@ -0,0 +1,581 @@ +#!/usr/bin/perl -w +use strict; + +# +# Display raw XFS statistics from one of these sources: +# o /proc/fs/xfs/stat (the default) +# o pmcd on host, via (pmprobe) -h +# o PCP archive, via (pmprobe) -a +# + +use vars qw( @values @tmp ); +my $file = '/proc/fs/xfs/stat'; + +unless (defined(@ARGV)) { # use the XFS/procfs statistics file directly + unless (open(STATS, $file)) { + print STDERR "The running kernel is not exporting XFS statistics.\n"; + die "$file: $!"; + } + while () { + chomp; + /^(extent_alloc|abt|blk_map|bmbt|dir|trans|ig|log|push_ail|xstrat|rw|attr|qm|icluster|vnodes|xpc)/ || next; #die "Unrecognised line in $file:\n\t'$_'\n"; + foreach (split(' ', $')) { + push @values, sprintf("%11s", $_); + } + } + @tmp = @values[75..77]; # reorder some items to get Ted's format.. + splice(@values, 75); + splice(@values, 48, 0, ($tmp[0])); + splice(@values, 52, 0, ($tmp[1])); + splice(@values, 54, 0, ($tmp[2])); +} +else { # source values from pmprobe (host/archive) + open(STATS, "/usr/bin/pmprobe -v @ARGV xfs |") || die "pmprobe: $!"; + while () { + my @result = split(' ', $_); + ( $#result == 2 ) || die "pmprobe - $_"; + push @values, sprintf("%11s", $result[2]); + } + @tmp = @values[0..6]; # reorder some items to get Ted's format.. + splice(@values, 0, 7); + splice(@values, 51, 0, @tmp[0..3]); + splice(@values, 67, 0, @tmp[4..6]); +} + +($#values == 77) || die "Found $#values XFS values, expected 77"; + +unless (open(STATS1, "/proc/fs/pagebuf/stat")) { + print STDERR "The running kernel is not exporting pagebuf stats.\n", + die "/proc/fs/pagebuf/stat: $!"; +} +while () { + chomp; + /^(pagebuf)/ || next; #die "Unrecognised line in file"; + foreach (split(' ', $')) { + push @values, sprintf("%11s", $_); + } +} + + +print < [ B<-h> I ] [ B<-a> I ] + +=head1 DESCRIPTION + +I uses the /proc interface to extract XFS performance +data from the running kernel. +Alternatively, the performance data can be sourced from a Performance +Co-Pilot (PCP) host running the I(1) daemon or from a PCP +archive created by the I(1) utility. + +=head1 OPTIONS + +=head2 B<-h> I + +The named I should be the source of live performance data, +rather than /proc. + +=head2 B<-a> I + +The historical data contained in the named I should be +displayed, rather than /proc. + +=head1 STATISTICS + +=head2 B (I) + +Number of file system extents allocated over all XFS filesystems. + +=head2 B (I) + +Number of file system blocks allocated over all XFS filesystems. + +=head2 B (I) + +Number of file system extents freed over all XFS filesystems. + +=head2 B (I) + +Number of file system blocks freed over all XFS filesystems. + +=head2 B (I) + +Number of lookup operations in XFS filesystem allocation btrees. + +=head2 B (I) + +Number of compares in XFS filesystem allocation btree lookups. + +=head2 B (I) + +Number of extent records inserted into XFS filesystem allocation btrees. + +=head2 B (I) + +Number of extent records deleted from XFS filesystem allocation btrees. + +=head2 B (I) + +Number of block map for read operations performed on XFS files. + +=head2 B (I) + +Number of block map for write operations performed on XFS files. + +=head2 B (I) + +Number of block unmap (delete) operations performed on XFS files. + +=head2 B (I) + +Number of extent list insertion operations for XFS files. + +=head2 B (I) + +Number of extent list deletion operations for XFS files. + +=head2 B (I) + +Number of extent list lookup operations for XFS files. + +=head2 B (I) + +Number of extent list comparisons in XFS extent list lookups. + +=head2 B (I) + +Number of block map btree lookup operations on XFS files. + +=head2 B (I) + +Number of block map btree compare operations in XFS block map lookups. + +=head2 B (I) + +Number of block map btree records inserted for XFS files. + +=head2 B (I) + +Number of block map btree records deleted for XFS files. + +=head2 B (I) + +This is a count of the number of file name directory lookups in XFS +filesystems. It counts only those lookups which miss in the operating +system's directory name lookup cache and must search the real directory +structure for the name in question. The count is incremented once for +each level of a pathname search that results in a directory lookup. + +=head2 B (I) + +This is the number of times a new directory entry was created in XFS +filesystems. Each time that a new file, directory, link, symbolic link, +or special file is created in the directory hierarchy the count is +incremented. + +=head2 B (I) + +This is the number of times an existing directory entry was removed in +XFS filesystems. Each time that a file, directory, link, symbolic link, +or special file is removed from the directory hierarchy the count is +incremented. + +=head2 B (I) + +This is the number of times the XFS directory getdents operation was +performed. The getdents operation is used by programs to read the +contents of directories in a file system independent fashion. This +count corresponds exactly to the number of times the getdents(2) system +call was successfully used on an XFS directory. + +=head2 B (I) + +This is the number of meta-data transactions which waited to be +committed to the on-disk log before allowing the process performing the +transaction to continue. These transactions are slower and more +expensive than asynchronous transactions, because they force the in +memory log buffers to be forced to disk more often and they wait for +the completion of the log buffer writes. Synchronous transactions +include file truncations and all directory updates when the file system +is mounted with the 'wsync' option. + +=head2 B (I) + +This is the number of meta-data transactions which did not wait to be +committed to the on-disk log before allowing the process performing the +transaction to continue. These transactions are faster and more +efficient than synchronous transactions, because they commit their data +to the in memory log buffers without forcing those buffers to be +written to disk. This allows multiple asynchronous transactions to be +committed to disk in a single log buffer write. Most transactions used +in XFS file systems are asynchronous. + +=head2 B (I) + +This is the number of meta-data transactions which did not actually +change anything. These are transactions which were started for some +purpose, but in the end it turned out that no change was necessary. + +=head2 B (I) + +This is the number of times the operating system looked for an XFS +inode in the inode cache. Whether the inode was found in the cache or +needed to be read in from the disk is not indicated here, but this can +be computed from the ig_found and ig_missed counts. + +=head2 B (I) + +This is the number of times the operating system looked for an XFS +inode in the inode cache and found it. The closer this count is to the +ig_attempts count the better the inode cache is performing. + +=head2 B (I) + +This is the number of times the operating system looked for an XFS +inode in the inode cache and saw that it was there but was unable to +use the in memory inode because it was being recycled by another +process. + +=head2 B (I) + +This is the number of times the operating system looked for an XFS +inode in the inode cache and the inode was not there. The further this +count is from the ig_attempts count the better. + +=head2 B (I) + +This is the number of times the operating system looked for an XFS +inode in the inode cache and found that it was not there but upon +attempting to add the inode to the cache found that another process had +already inserted it. + +=head2 B (I) + +This is the number of times the operating system recycled an XFS inode +from the inode cache in order to use the memory for that inode for +another purpose. Inodes are recycled in order to keep the inode cache +from growing without bound. If the reclaim rate is high it may be +beneficial to raise the vnode_free_ratio kernel tunable variable to +increase the size of the inode cache. + +=head2 B (I) + +This is the number of times the operating system explicitly changed the +attributes of an XFS inode. For example, this could be to change the +inode's owner, the inode's size, or the inode's timestamps. + +=head2 B (I) + +This variable counts the number of log buffer writes going to the +physical log partitions of all XFS filesystems. Log data traffic is +proportional to the level of meta-data updating. Log buffer writes get +generated when they fill up or external syncs occur. + +=head2 B (I) + +This variable counts the number of Kbytes of information being written +to the physical log partitions of all XFS filesystems. Log data traffic +is proportional to the level of meta-data updating. The rate with which +log data gets written depends on the size of internal log buffers and +disk write speed. Therefore, filesystems with very high meta-data +updating may need to stripe the log partition or put the log partition +on a separate drive. + +=head2 B (I) + +This variable keeps track of times when a logged transaction can not +get any log buffer space. When this occurs, all of the internal log +buffers are busy flushing their data to the physical on-disk log. + +=head2 B (I) + +The number of times the in-core log is forced to disk. It is +equivalent to the number of successful calls to the function +xfs_log_force(). + +=head2 B (I) + +Value exported from the xs_log_force_sleep field of struct xfsstats. + +=head2 B (I) + +This is the number of buffers flushed out by the XFS flushing daemons +which are written to contiguous space on disk. The buffers handled by +the XFS daemons are delayed allocation buffers, so this count gives an +indication of the success of the XFS daemons in allocating contiguous +disk space for the data being flushed to disk. + +=head2 B (I) + +This is the number of buffers flushed out by the XFS flushing daemons +which are written to non-contiguous space on disk. The buffers handled +by the XFS daemons are delayed allocation buffers, so this count gives +an indication of the failure of the XFS daemons in allocating +contiguous disk space for the data being flushed to disk. Large values +in this counter indicate that the file system has become fragmented. + +=head2 B (I) + +This is the number of write(2) system calls made to files in +XFS file systems. + +=head2 B (I) + +This is the number of read(2) system calls made to files in XFS file +systems. + +=head2 B (I) + +The number of "get" operations performed on extended file attributes +within XFS filesystems. The "get" operation retrieves the value of an +extended attribute. + +=head2 B (I) + +The number of "set" operations performed on extended file attributes +within XFS filesystems. The "set" operation creates and sets the value +of an extended attribute. + +=head2 B (I) + +The number of "remove" operations performed on extended file attributes +within XFS filesystems. The "remove" operation deletes an extended +attribute. + +=head2 B (I) + +The number of "list" operations performed on extended file attributes +within XFS filesystems. The "list" operation retrieves the set of +extended attributes associated with a file. + +=head2 B (I) + +Value from the xs_try_logspace field of struct xfsstats. + +=head2 B (I) + +Value from the xs_sleep_logspace field of struct xfsstats. + +=head2 B (I) + +The number of times the tail of the AIL is moved forward. It is +equivalent to the number of successful calls to the function +xfs_trans_push_ail(). + +=head2 B (I) + +Value from xs_push_ail_success field of struct xfsstats. + +=head2 B (I) + +Value from xs_push_ail_pushbuf field of struct xfsstats. + +=head2 B (I) + +Value from xs_push_ail_pinned field of struct xfsstats. + +=head2 B (I) + +Value from xs_push_ail_locked field of struct xfsstats. + +=head2 B (I) + +Value from xs_push_ail_flushing field of struct xfsstats. + +=head2 B (I) + +Value from xs_push_ail_restarts field of struct xfsstats. + +=head2 B (I) + +Value from xs_push_ail_flush field of struct xfsstats. + +=head2 B (I) + +Value from xs_qm_dqreclaims field of struct xfsstats. + +=head2 B (I) + +Value from xs_qm_dqreclaim_misses field of struct xfsstats. + +=head2 B (I) + +Value from xs_qm_dquot_dups field of struct xfsstats. + +=head2 B (I) + +Value from xs_qm_dqcachemisses field of struct xfsstats. + +=head2 B (I) + +Value from xs_qm_dqcachehits field of struct xfsstats. + +=head2 B (I) + +Value from xs_qm_dqwants field of struct xfsstats. + +=head2 B (I) + +Value from xs_qm_dqshake_reclaims field of struct xfsstats. + +=head2 B (I) + +Value from xs_qm_dqinact_reclaims field of struct xfsstats. + +=head2 B (I) + +This is the number of calls to xfs_iflush which gets called when an +inode is being flushed (such as by bdflush or tail pushing). +xfs_iflush searches for other inodes in the same cluster which are +dirty and flushable. + +=head2 B (I) + +Value from xs_icluster_flushcnt field of struct xfsstats. + +=head2 B (I) + +This is the number of times that the inode clustering was not able to +flush anything but the one inode it was called with. + +=head2 B (I) + +Number of vnodes not on free lists. + +=head2 B (I) + +Number of times vn_alloc called. + +=head2 B (I) + +Number of times vn_get called. + +=head2 B (I) + +Number of times vn_hold called. + +=head2 B (I) + +Number of times vn_rele called. + +=head2 B (I) + +Number of times vn_reclaim called. + +=head2 B (I) + +Number of times vn_remove called. + +=head2 B (I) + +Number of times vn_free called. + +=head2 B (I) + +This is a count of bytes written via B(2) system calls to files +in XFS file systems. It can be used in conjunction with the write_calls +count to calculate the average size of the write operations to files in +XFS file systems. + +=head2 B (I) + +This is a count of bytes read via B(2) system calls to files in +XFS file systems. It can be used in conjunction with the read_calls +count to calculate the average size of the read operations to files in +XFS file systems. + +=head2 B (I) + +This is a count of bytes of file data flushed out by the XFS +flushing daemons. + +=head1 NOTES + +Many of these statistics are monotonically increasing +counters, and of course are subject to counter overflow +(the final three listed above are 64-bit values, all others +are 32-bit values). +As such they are of limited value in this raw form - if you +are interested in monitoring throughput (e.g. bytes read/written +per second), or other rates of change, you will be better served +by investigating the PCP package more thoroughly - it contains a +number of performance analysis tools which can help in this regard. + +=head1 FILES + +F - XFS statistical data + +=head1 SEE ALSO + +I(1), I(1), I(5), I(8). + +=cut diff -rNu linux-2.4.7/cmd/xfsprogs/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/CVS/Entries Thu Jul 5 11:44:18 2001 @@ -0,0 +1,7 @@ +/Makefile/1.3/Thu May 17 02:58:46 2001/-ko/ +/Makepkgs/1.3/Thu Mar 29 06:30:35 2001/-ko/ +/README/1.1/Mon Jan 15 06:52:52 2001/-ko/ +/VERSION/1.19/Tue Jul 3 04:33:45 2001/-ko/ +/configure.in/1.6/Tue Jun 12 07:20:31 2001/-ko/ +/install-sh/1.1/Mon Jan 15 06:52:52 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/CVS/Entries.Log linux-2.4-xfs/cmd/xfsprogs/CVS/Entries.Log --- linux-2.4.7/cmd/xfsprogs/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/CVS/Entries.Log Thu Jul 5 11:44:59 2001 @@ -0,0 +1,17 @@ +A D/bmap//// +A D/build//// +A D/db//// +A D/debian//// +A D/doc//// +A D/freeze//// +A D/fsck//// +A D/growfs//// +A D/include//// +A D/libhandle//// +A D/libxfs//// +A D/logprint//// +A D/man//// +A D/mkfile//// +A D/mkfs//// +A D/repair//// +A D/rtcp//// diff -rNu linux-2.4.7/cmd/xfsprogs/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/CVS/Repository Thu Jul 5 11:44:18 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs diff -rNu linux-2.4.7/cmd/xfsprogs/CVS/Root linux-2.4-xfs/cmd/xfsprogs/CVS/Root --- linux-2.4.7/cmd/xfsprogs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/CVS/Root Thu Jul 5 11:44:18 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/Makefile linux-2.4-xfs/cmd/xfsprogs/Makefile --- linux-2.4.7/cmd/xfsprogs/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/Makefile Wed May 16 21:58:46 2001 @@ -0,0 +1,76 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = . +HAVE_BUILDDEFS = $(shell test -f $(TOPDIR)/include/builddefs && echo yes || echo no) + +ifeq ($(HAVE_BUILDDEFS), yes) +include $(TOPDIR)/include/builddefs +endif + +CONFIGURE = configure include/builddefs include/platform_defs.h +LSRCFILES = configure configure.in Makepkgs install-sh README VERSION +LDIRT = config.* conftest* Logs/* built install.* install-dev.* *.gz + +SUBDIRS = include libxfs libhandle \ + bmap db freeze fsck growfs logprint mkfile mkfs repair rtcp \ + man doc debian build + +default: $(CONFIGURE) +ifeq ($(HAVE_BUILDDEFS), no) + $(MAKE) -C . $@ +else + $(SUBDIRS_MAKERULE) +endif + +ifeq ($(HAVE_BUILDDEFS), yes) +include $(BUILDRULES) +else +clean: # if configure hasn't run, nothing to clean +endif + +$(CONFIGURE): configure.in include/builddefs.in VERSION + rm -f config.cache + autoconf + ./configure + +install: default + $(SUBDIRS_MAKERULE) + $(INSTALL) -m 755 -d $(PKG_DOC_DIR) + $(INSTALL) -m 644 README $(PKG_DOC_DIR) + +install-dev: default + $(SUBDIRS_MAKERULE) + +realclean distclean: clean + rm -f $(LDIRT) $(CONFIGURE) + [ ! -d Logs ] || rmdir Logs diff -rNu linux-2.4.7/cmd/xfsprogs/Makepkgs linux-2.4-xfs/cmd/xfsprogs/Makepkgs --- linux-2.4.7/cmd/xfsprogs/Makepkgs Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/Makepkgs Thu Mar 29 00:30:35 2001 @@ -0,0 +1,109 @@ +#! /bin/sh +# +# Make whichever packages have been requested. +# Defaults to RPMs. +# +LOGDIR=Logs + +type=rpm +verbose=false + +MAKE=${MAKE:-make} +test ! -z "$MAKE" && make=$MAKE + +for opt in $* +do + case "$opt" in + clean) + ;; # ignored, kept for backward compatibility + rpm) + type=rpm ;; + debian) + type=debian ;; + verbose) + verbose=true ;; + *) + echo "Usage: Makepkgs [verbose] [debian|rpm]"; exit 1 ;; + esac +done + +# start with a clean manifest +test -f files.rpm && rm -f files.rpm +test -f filesdevel.rpm && rm -f filesdevel.rpm + +test ! -d $LOGDIR && mkdir $LOGDIR +rm -rf $LOGDIR/* > /dev/null 2>&1 + +# build Debian packages, cleans itself before starting +SUDO=${SUDO:-sudo} +test ! -z "$SUDO" && sudo=$SUDO +if [ $type = debian ] ; then + LOGDEB=`pwd` + LOGDEB=../`basename $LOGDEB`.log + echo "== Debian build, log is $LOGDEB"; echo + if $verbose ; then + dpkg-buildpackage -r$SUDO | tee $LOGDEB + else + dpkg-buildpackage -r$SUDO > $LOGDEB + fi + exit 0 +fi + +# build RPM packages - manual clean before starting +echo "== clean, log is $LOGDIR/clean" +if $verbose ; then + $MAKE clean 2>&1 | tee $LOGDIR/clean +else + $MAKE clean > $LOGDIR/clean 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"$MAKE clean\" failed, see log in $LOGDIR/clean + tail $LOGDIR/clean + exit 1 +fi + +echo +echo "== configure, log is $LOGDIR/configure" +if $verbose ; then + autoconf 2>&1 | tee $LOGDIR/configure + ./configure 2>&1 | tee -a $LOGDIR/configure +else + autoconf > $LOGDIR/configure 2>&1 + ./configure >> $LOGDIR/configure 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"configure\" failed, see log in $LOGDIR/configure + tail $LOGDIR/configure + exit 1 +fi + +echo +echo "== default, log is $LOGDIR/default" +if $verbose ; then + $MAKE default 2>&1 | tee $LOGDIR/default +else + $MAKE default > $LOGDIR/default 2>&1 +fi +if [ $? -ne 0 ] ; then + echo \"$MAKE default\" failed, see log in $LOGDIR/default + tail $LOGDIR/default + exit 1 +fi + +echo +echo "== dist, log is $LOGDIR/dist" +[ ! -f .census ] && touch .census +if $verbose ; then + $MAKE -C build dist 2>&1 | tee $LOGDIR/dist +else + $MAKE -C build dist > $LOGDIR/dist 2>&1 +fi +if [ $? -ne 0 ] ; then + echo $MAKE dist failed, see log in $LOGDIR/dist + tail $LOGDIR/dist + exit 1 +else + grep '^Wrote:' $LOGDIR/dist | sed -e 's/\.\.\/\.\.\///' +fi + +exit 0 diff -rNu linux-2.4.7/cmd/xfsprogs/README linux-2.4-xfs/cmd/xfsprogs/README --- linux-2.4.7/cmd/xfsprogs/README Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/README Mon Jan 15 00:52:52 2001 @@ -0,0 +1,15 @@ +XFS User Tools README +_____________________ + +See the file doc/INSTALL for build, installation and post- +install configuration steps. + +Refer to the xfs(5) manual page for general XFS information +and references to other XFS manual pages. + +For more information and details on how to contribute to the +XFS project see the web pages at: + http://oss.sgi.com/projects/xfs/ + +For more information on the build process, please refer to +the doc/PORTING document. diff -rNu linux-2.4.7/cmd/xfsprogs/VERSION linux-2.4-xfs/cmd/xfsprogs/VERSION --- linux-2.4.7/cmd/xfsprogs/VERSION Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/VERSION Mon Jul 2 23:33:45 2001 @@ -0,0 +1,7 @@ +# +# This file is used by configure to get version information +# +PKG_MAJOR=1 +PKG_MINOR=2 +PKG_REVISION=8 +PKG_BUILD=0 diff -rNu linux-2.4.7/cmd/xfsprogs/bmap/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/bmap/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/bmap/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/bmap/CVS/Entries Thu Jul 5 11:44:18 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Mon Jan 15 06:52:52 2001/-ko/ +/xfs_bmap.c/1.3/Wed May 9 06:56:06 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/bmap/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/bmap/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/bmap/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/bmap/CVS/Repository Thu Jul 5 11:44:18 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/bmap diff -rNu linux-2.4.7/cmd/xfsprogs/bmap/CVS/Root linux-2.4-xfs/cmd/xfsprogs/bmap/CVS/Root --- linux-2.4.7/cmd/xfsprogs/bmap/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/bmap/CVS/Root Thu Jul 5 11:44:18 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/bmap/Makefile linux-2.4-xfs/cmd/xfsprogs/bmap/Makefile --- linux-2.4.7/cmd/xfsprogs/bmap/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/bmap/Makefile Mon Jan 15 00:52:52 2001 @@ -0,0 +1,46 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = xfs_bmap +CFILES = xfs_bmap.c + +default: $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_BIN_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/xfsprogs/bmap/xfs_bmap.c linux-2.4-xfs/cmd/xfsprogs/bmap/xfs_bmap.c --- linux-2.4.7/cmd/xfsprogs/bmap/xfs_bmap.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/bmap/xfs_bmap.c Wed May 9 01:56:06 2001 @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Bmap display utility for xfs. + */ + +#include +#include +#include + +int aflag = 0; /* Attribute fork. */ +int lflag = 0; /* list number of blocks with each extent */ +int nflag = 0; /* number of extents specified */ +int vflag = 0; /* Verbose output */ +int bmv_iflags = 0; /* Input flags for XFS_IOC_GETBMAPX */ + +int dofile(char *); +__off64_t file_size(int fd, char * fname); +int numlen(__off64_t); + +int +main(int argc, char **argv) +{ + char *fname; + int i = 0; + int option; + + fname = basename(argv[0]); + while ((option = getopt(argc, argv, "adln:pvV")) != EOF) { + switch (option) { + case 'a': + bmv_iflags |= BMV_IF_ATTRFORK; + aflag = 1; + break; + case 'l': + lflag = 1; + break; + case 'n': + nflag = atoi(optarg); + break; + case 'd': + /* do not recall possibly offline DMAPI files */ + bmv_iflags |= BMV_IF_NO_DMAPI_READ; + break; + case 'p': + /* report unwritten preallocated blocks */ + bmv_iflags |= BMV_IF_PREALLOC; + break; + case 'v': + vflag++; + break; + case 'V': + printf("%s version %s\n", fname, VERSION); + break; + default: + fprintf(stderr, "Usage: %s [-adlpV] [-n nx] file...\n", + fname); + exit(1); + } + } + if (aflag) + bmv_iflags &= ~(BMV_IF_PREALLOC|BMV_IF_NO_DMAPI_READ); + while (optind < argc) { + fname = argv[optind]; + i += dofile(fname); + optind++; + } + return(i ? 1 : 0); +} + +__off64_t +file_size(int fd, char *fname) +{ + struct stat64 st; + int i; + int errno_save; + + errno_save = errno; /* in case fstat64 fails */ + i = fstat64(fd, &st); + if (i < 0) { + fprintf(stderr,"fstat64 failed for %s", fname); + perror("fstat64"); + errno = errno_save; + return -1; + } + return st.st_size; +} + + +int +dofile(char *fname) +{ + int fd; + struct fsxattr fsx; + int i; + struct getbmapx *map; + char mbuf[1024]; + int map_size; + int loop = 0; + xfs_fsop_geom_t fsgeo; + + fd = open(fname, O_RDONLY); + if (fd < 0) { + sprintf(mbuf, "open %s", fname); + perror(mbuf); + return 1; + } + + if (vflag) { + if (ioctl(fd, XFS_IOC_FSGEOMETRY, &fsgeo) < 0) { + sprintf(mbuf, "Can't get XFS geom, %s", fname); + perror(mbuf); + close(fd); + return 1; + } + + if (vflag > 1) + printf( + "xfs_bmap: fsgeo.agblocks=%u, fsgeo.blocksize=%u, fsgeo.agcount=%u\n", + fsgeo.agblocks, fsgeo.blocksize, + fsgeo.agcount); + + if ((ioctl(fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) { + sprintf(mbuf, "Can't read attrs %s", fname); + perror(mbuf); + close(fd); + return 1; + } + + if (vflag > 1) + printf( + "xfs_bmap: fsx.dsx_xflags=%u, fsx.fsx_extsize=%u, fsx.fsx_nextents=%u\n", + fsx.fsx_xflags, fsx.fsx_extsize, + fsx.fsx_nextents); + + if (fsx.fsx_xflags == XFS_XFLAG_REALTIME) { + /* + * ag info not applicable to rt, continue + * without ag output. + */ + vflag = 0; + } + } + + map_size = nflag ? nflag+1 : 32; /* initial guess - 256 for checkin KCM */ + map = malloc(map_size*sizeof(*map)); + if (map == NULL) { + fprintf(stderr, "malloc of %d bytes failed.\n", + (int)(map_size * sizeof(*map))); + close(fd); + return 1; + } + + +/* Try the ioctl(XFS_IOC_GETBMAPX) for the number of extents specified by + * nflag, or the initial guess number of extents (256). + * + * If there are more extents than we guessed, use ioctl + * (XFS_IOC_FSGETXATTR[A]) to get the extent count, realloc some more + * space based on this count, and try again. + * + * If the initial FGETBMAPX attempt returns EINVAL, this may mean + * that we tried the FGETBMAPX on a zero length file. If we get + * EINVAL, check the length with fstat() and return "no extents" + * if the length == 0. + * + * Why not do the ioctl(XFS_IOC_FSGETXATTR[A]) first? Two reasons: + * (1) The extent count may be wrong for a file with delayed + * allocation blocks. The XFS_IOC_GETBMAPX forces the real + * allocation and fixes up the extent count. + * (2) For XFS_IOC_GETBMAP[X] on a DMAPI file that has been moved + * offline by a DMAPI application (e.g., DMF) the + * XFS_IOC_FSGETXATTR only reflects the extents actually online. + * Doing XFS_IOC_GETBMAPX call first forces that data blocks online + * and then everything proceeds normally (see PV #545725). + * + * If you don't want this behavior on a DMAPI offline file, + * try the "-d" option which sets the BMV_IF_NO_DMAPI_READ + * iflag for XFS_IOC_GETBMAPX. + */ + + do { /* loop a miximum of two times */ + + bzero(map, sizeof(*map)); /* zero header */ + + map->bmv_length = -1; + map->bmv_count = map_size; + map->bmv_iflags = bmv_iflags; + + i = ioctl(fd, XFS_IOC_GETBMAPX, map); + + if (vflag > 1) + printf( + "xfs_bmap: i=%d map.bmv_offset=%lld, map.bmv_block=%lld, " + "map.bmv_length=%lld, map.bmv_count=%d, map.bmv_entries=%d\n", + i, (long long)map->bmv_offset, + (long long)map->bmv_block, + (long long)map->bmv_length, + map->bmv_count, map->bmv_entries); + if (i < 0) { + if ( errno == EINVAL + && !aflag && file_size(fd, fname) == 0) { + break; + } else { + sprintf(mbuf, "ioctl(XFS_IOC_GETBMAPX (iflags 0x%x) %s", + map->bmv_iflags, fname); + perror(mbuf); + close(fd); + free(map); + return 1; + } + } + if (nflag) + break; + if (map->bmv_entries < map->bmv_count-1) + break; + /* Get number of extents from ioctl XFS_IOC_FSGETXATTR[A] + * syscall. + */ + i = ioctl(fd, aflag ? XFS_IOC_FSGETXATTRA : XFS_IOC_FSGETXATTR, &fsx); + if (i < 0) { + sprintf(mbuf, "ioctl(XFS_IOC_FSGETXATTR%s) %s", + aflag ? "A" : "", fname); + perror(mbuf); + close(fd); + free(map); + return 1; + } + if (fsx.fsx_nextents >= map_size-1) { + map_size = 2*(fsx.fsx_nextents+1); + map = realloc(map, map_size*sizeof(*map)); + if (map == NULL) { + fprintf(stderr, "cannot realloc %d bytes.\n", + (int)(map_size * sizeof(*map))); + close(fd); + return 1; + } + } + } while (++loop < 2); + if (!nflag) { + if (map->bmv_entries <= 0) { + printf("%s: no extents\n", fname); + close(fd); + free(map); + return 0; + } + } + close(fd); + printf("%s:\n", fname); + if (!vflag) { + for (i = 0; i < map->bmv_entries; i++) { + printf("\t%d: [%lld..%lld]: ", i, + (long long) map[i + 1].bmv_offset, + (long long)(map[i + 1].bmv_offset + + map[i + 1].bmv_length - 1LL)); + if (map[i + 1].bmv_block == -1) + printf("hole"); + else { + printf("%lld..%lld", + (long long) map[i + 1].bmv_block, + (long long)(map[i + 1].bmv_block + + map[i + 1].bmv_length - 1LL)); + + } + if (lflag) + printf(" %lld blocks\n", (long long)map[i+1].bmv_length); + else + printf("\n"); + } + } else { + /* + * Verbose mode displays: + * extent: [startoffset..endoffset]: startblock..endblock \ + * ag# (agoffset..agendoffset) totalbbs + */ +#define MINRANGE_WIDTH 16 +#define MINAG_WIDTH 2 +#define MINTOT_WIDTH 5 +#define max(a,b) (a > b ? a : b) + int agno; + __off64_t agoff, bbperag; + int foff_w, boff_w, aoff_w, tot_w, agno_w; + char rbuf[32], bbuf[32], abuf[32]; + + foff_w = boff_w = aoff_w = MINRANGE_WIDTH; + tot_w = MINTOT_WIDTH; + bbperag = (__off64_t)fsgeo.agblocks * + (__off64_t)fsgeo.blocksize / BBSIZE; + + /* + * Go through the extents and figure out the width + * needed for all columns. + */ + for (i = 0; i < map->bmv_entries; i++) { + sprintf(rbuf, "[%lld..%lld]:", + (long long) map[i + 1].bmv_offset, + (long long)(map[i + 1].bmv_offset + + map[i + 1].bmv_length - 1LL)); + if (map[i + 1].bmv_block == -1) { + foff_w = max(foff_w, strlen(rbuf)); + tot_w = max(tot_w, + numlen(map[i+1].bmv_length)); + } else { + sprintf(bbuf, "%lld..%lld", + (long long) map[i + 1].bmv_block, + (long long)(map[i + 1].bmv_block + + map[i + 1].bmv_length - 1LL)); + agno = map[i + 1].bmv_block / bbperag; + agoff = map[i + 1].bmv_block - (agno * bbperag); + sprintf(abuf, "(%lld..%lld)", + (long long)agoff, (long long) + (agoff + map[i + 1].bmv_length - 1LL)); + foff_w = max(foff_w, strlen(rbuf)); + boff_w = max(boff_w, strlen(bbuf)); + aoff_w = max(aoff_w, strlen(abuf)); + tot_w = max(tot_w, + numlen(map[i+1].bmv_length)); + } + } + agno_w = max(MINAG_WIDTH, numlen(fsgeo.agcount)); + printf("%4s: %-*s %-*s %*s %-*s %*s\n", + "EXT", + foff_w, "FILE-OFFSET", + boff_w, "BLOCK-RANGE", + agno_w, "AG", + aoff_w, "AG-OFFSET", + tot_w, "TOTAL"); + for (i = 0; i < map->bmv_entries; i++) { + sprintf(rbuf, "[%lld..%lld]:", + (long long) map[i + 1].bmv_offset, + (long long)(map[i + 1].bmv_offset + + map[i + 1].bmv_length - 1LL)); + if (map[i + 1].bmv_block == -1) { + printf("%4d: %-*s %-*s %*s %-*s %*lld\n", + i, + foff_w, rbuf, + boff_w, "hole", + agno_w, "", + aoff_w, "", + tot_w, (long long)map[i+1].bmv_length); + } else { + sprintf(bbuf, "%lld..%lld", + (long long) map[i + 1].bmv_block, + (long long)(map[i + 1].bmv_block + + map[i + 1].bmv_length - 1LL)); + agno = map[i + 1].bmv_block / bbperag; + agoff = map[i + 1].bmv_block - (agno * bbperag); + sprintf(abuf, "(%lld..%lld)", + (long long)agoff, (long long) + (agoff + map[i + 1].bmv_length - 1LL)); + printf("%4d: %-*s %-*s %*d %-*s %*lld\n", + i, + foff_w, rbuf, + boff_w, bbuf, + agno_w, agno, + aoff_w, abuf, + tot_w, (long long)map[i+1].bmv_length); + } + } + } + free(map); + return 0; +} + +int +numlen( __off64_t val) +{ + __off64_t tmp; + int len; + + for (len=0, tmp=val; tmp > 0; tmp=tmp/10) len++; + return(len == 0 ? 1 : len); +} diff -rNu linux-2.4.7/cmd/xfsprogs/build/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/build/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/build/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/CVS/Entries Thu Jul 5 11:44:18 2001 @@ -0,0 +1,2 @@ +/Makefile/1.3/Thu Mar 1 01:31:21 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/build/CVS/Entries.Log linux-2.4-xfs/cmd/xfsprogs/build/CVS/Entries.Log --- linux-2.4.7/cmd/xfsprogs/build/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/CVS/Entries.Log Thu Jul 5 11:44:18 2001 @@ -0,0 +1,2 @@ +A D/rpm//// +A D/tar//// diff -rNu linux-2.4.7/cmd/xfsprogs/build/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/build/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/build/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/CVS/Repository Thu Jul 5 11:44:18 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/build diff -rNu linux-2.4.7/cmd/xfsprogs/build/CVS/Root linux-2.4-xfs/cmd/xfsprogs/build/CVS/Root --- linux-2.4.7/cmd/xfsprogs/build/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/CVS/Root Thu Jul 5 11:44:18 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/build/Makefile linux-2.4-xfs/cmd/xfsprogs/build/Makefile --- linux-2.4.7/cmd/xfsprogs/build/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/Makefile Wed Feb 28 19:31:21 2001 @@ -0,0 +1,76 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +MANIFEST=src-manifest +SRCTAR=$(PKG_NAME)-$(PKG_VERSION).src.tar.gz + +LDIRT = *-manifest *.gz $(TOPDIR)/$(PKG_NAME)-* + +# for clean and clobber +SUBDIRS = tar rpm + +# nothing to build here (it's all packaging) +default install install-dev : + +include $(BUILDRULES) + +# Symlink in the TOPDIR is used to pack files relative to +# product-version directory. +$(MANIFEST) : $(_FORCE) + @if [ ! -L $(TOPDIR)/$(PKG_NAME)-$(PKG_VERSION) ] ; then \ + $(LN_S) . $(TOPDIR)/$(PKG_NAME)-$(PKG_VERSION) ; \ + fi + @CDIR=`pwd`; cd $(TOPDIR); \ + $(MAKE) --no-print-directory source | \ + sed -e 's/^\./$(PKG_NAME)-$(PKG_VERSION)/' > $$CDIR/$@ ;\ + if [ $$? -ne 0 ] ; then \ + exit 1; \ + else \ + unset TAPE; \ + $(TAR) -T $$CDIR/$@ -cf - | $(ZIP) --best > $$CDIR/$(SRCTAR); \ + fi + +dist : default $(MANIFEST) + @DIST_MANIFEST=`pwd`/bin-manifest; DIST_ROOT=/tmp/$$$$; \ + export DIST_MANIFEST DIST_ROOT; \ + rm -f $$DIST_MANIFEST; \ + echo === install === && $(MAKE) -C $(TOPDIR) install || exit $$?; \ + if [ -x $(TAR) ]; then \ + ( echo "=== tar ===" && $(MAKEF) -C tar $@ || exit $$? ); \ + fi; \ + if [ -x $(RPM) ]; then \ + ( echo "=== rpm ===" && $(MAKEF) -C rpm $@ || exit $$? ); \ + fi; \ + test -z "$$KEEP_DIST_ROOT" || rm -rf $$DIST_ROOT; echo Done diff -rNu linux-2.4.7/cmd/xfsprogs/build/rpm/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/build/rpm/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/build/rpm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/rpm/CVS/Entries Thu Jul 5 11:44:18 2001 @@ -0,0 +1,5 @@ +/Makefile/1.4/Tue Mar 20 19:36:13 2001/-ko/ +/macros.template/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/rpm-2.rc.template/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfsprogs.spec.in/1.7/Tue Mar 20 04:12:26 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/build/rpm/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/build/rpm/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/build/rpm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/rpm/CVS/Repository Thu Jul 5 11:44:18 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/build/rpm diff -rNu linux-2.4.7/cmd/xfsprogs/build/rpm/CVS/Root linux-2.4-xfs/cmd/xfsprogs/build/rpm/CVS/Root --- linux-2.4.7/cmd/xfsprogs/build/rpm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/rpm/CVS/Root Thu Jul 5 11:44:18 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/build/rpm/Makefile linux-2.4-xfs/cmd/xfsprogs/build/rpm/Makefile --- linux-2.4.7/cmd/xfsprogs/build/rpm/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/rpm/Makefile Tue Mar 20 13:36:13 2001 @@ -0,0 +1,78 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +TREEROOT = $(shell cd ${TOPDIR}; pwd) +include $(TOPDIR)/include/builddefs + +SPECF = $(PKG_NAME).spec +LDIRT = $(PKG_NAME)*.rpm $(SPECF) rpmmacros rpm-*.rc $(TOPDIR)/files*.rpm + +LSRCFILES = macros.template $(SPECF).in rpm-2.rc.template + +default install install-dev : + +include $(BUILDRULES) + +# generate a binary rpm file +dist : default $(SPECF) rpm-$(RPM_VERSION).rc + $(RPM) -ba --rcfile ./rpm-$(RPM_VERSION).rc $(SPECF) + +# Because rpm prior to v.2.90 does not support macros and old style config +# is not supported by rpm v.3, we have to resort to such ugly hacks +ifneq ($RPM_VERSION,2) +rpm-$(RPM_VERSION).rc : rpmmacros + sed -e '/^macrofiles:/s|~/.rpmmacros|rpmmacros|' $@ + +rpmmacros : macros.template + @sed -e 's|%topdir%|$(TREEROOT)|g' < $< > $@ +else +rpm-2.rc: rpm-2.rc.template + @sed -e 's|%topdir%|$(TOPDIR)|g' < $< > $@ +endif + +.PHONY: $(SPECF) +${SPECF} : ${SPECF}.in + sed -e's|@pkg_name@|$(PKG_NAME)|g' \ + -e's|@pkg_version@|$(PKG_VERSION)|g' \ + -e's|@pkg_release@|$(PKG_RELEASE)|g' \ + -e's|@pkg_distribution@|$(PKG_DISTRIBUTION)|g' \ + -e's|@pkg_builder@|$(PKG_BUILDER)|g' \ + -e's|@build_root@|$(DIST_ROOT)|g' \ + -e'/^BuildRoot: *$$/d' \ + -e's|@pkg_var_dir@|$(PKG_VAR_DIR)|g' \ + -e's|@pkg_share_dir@|$(PKG_SHARE_DIR)|g' \ + -e's|@pkg_log_dir@|$(PKG_LOG_DIR)|g' \ + -e's|@pkg_doc_dir@|$(PKG_DOC_DIR)|g' \ + -e's|@pkg_man_dir@|$(PKG_MAN_DIR)|g' \ + -e's|@pkg_tmp_dir@|$(PKG_TMP_DIR)|g' \ + -e's|@make@|$(MAKE)|g' < $< > $@ diff -rNu linux-2.4.7/cmd/xfsprogs/build/rpm/macros.template linux-2.4-xfs/cmd/xfsprogs/build/rpm/macros.template --- linux-2.4.7/cmd/xfsprogs/build/rpm/macros.template Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/rpm/macros.template Sun Jan 14 23:36:03 2001 @@ -0,0 +1,30 @@ +# +# rpmrc.template +# +# Template to fudge rpm directory structure inside IRIX-like build +# environment + +# Force 386 build on all platforms +%_target i386-pc-linux +%_target_cpu i386 +%_target_os linux + +# topdir == $(WORKAREA) +%_topdir %topdir% + +# Following directories are specific to the topdir +# This is where build is done. In our case it's the same as $WORKAREA +%_builddir %topdir% + +# This is where foo.1.99.tar.gz is living in the real world. +# Be careful not to run full rpm build as it will override the sources +%_sourcedir %topdir%/build + +# This is where binary RPM and source RPM would end up +%_rpmdir %topdir%/build/rpm +%_srcrpmdir %topdir%/build/rpm +%_specdir %topdir%/build/rpm + +# Leave RPM files in the same directory - we're not building for +# multiple architectures +%_rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm diff -rNu linux-2.4.7/cmd/xfsprogs/build/rpm/rpm-2.rc.template linux-2.4-xfs/cmd/xfsprogs/build/rpm/rpm-2.rc.template --- linux-2.4.7/cmd/xfsprogs/build/rpm/rpm-2.rc.template Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/rpm/rpm-2.rc.template Sun Jan 14 23:36:03 2001 @@ -0,0 +1,25 @@ +# +# rpmrc.template +# +# Template to fudge rpm directory structure inside IRIX-like build +# environment + +# topdir == $(WORKAREA) +topdir: %topdir% + +# Following directories are specific to the topdir +# This is where build is done. In out case it's the same as $WORKAREA +# Be careful not to run full rpm build as it will override the sources +builddir: %topdir% + +# This is where foo.1.99.tar.gz is living in the real world. +sourcedir: %topdir%/build + +# This is where binary RPM and source RPM would end up +rpmdir: %topdir%/build/rpm +srcrpmdir: %topdir%/build/rpm +specdir: %topdir%/build/rpm + +# Leave RPM files in the same directory - we're not building for +# multiple architectures +rpmfilename: %{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm diff -rNu linux-2.4.7/cmd/xfsprogs/build/rpm/xfsprogs.spec.in linux-2.4-xfs/cmd/xfsprogs/build/rpm/xfsprogs.spec.in --- linux-2.4.7/cmd/xfsprogs/build/rpm/xfsprogs.spec.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/rpm/xfsprogs.spec.in Mon Mar 19 22:12:26 2001 @@ -0,0 +1,98 @@ +Summary: Utilities for managing the XFS filesystem. +Name: @pkg_name@ +Version: @pkg_version@ +Release: @pkg_release@ +Distribution: @pkg_distribution@ +Packager: @pkg_builder@ +BuildRoot: @build_root@ +Provides: xfs-cmds +Obsoletes: xfs-cmds +Prereq: /sbin/ldconfig +Source: @pkg_name@-@pkg_version@.src.tar.gz +Copyright: Copyright (C) 2000 Silicon Graphics, Inc. +Vendor: Silicon Graphics, Inc. +URL: http://oss.sgi.com/projects/xfs/ +Group: System Environment/Base + +%description +A set of commands to use the XFS filesystem, including mkfs.xfs. + +XFS is a high performance journaling filesystem which originated +on the SGI IRIX platform. It is completely multi-threaded, can +support large files and large filesystems, extended attributes, +variable block sizes, is extent based, and makes extensive use of +Btrees (directories, extents, free space) to aid both performance +and scalability. + +Refer to the documentation at http://oss.sgi.com/projects/xfs/ +for complete details. This implementation is on-disk compatible +with the IRIX version of XFS. + +%package devel +Summary: XFS filesystem-specific static libraries and headers. +Group: Development/Libraries +Requires: @pkg_name@ + +%description devel +xfsprogs-devel contains the libraries and header files needed to +develop XFS filesystem-specific programs. + +You should install xfsprogs-devel if you want to develop XFS +filesystem-specific programs, If you install xfsprogs-devel, you'll +also want to install xfsprogs. + +# If .census exists, then no setup is necessary, just go and do the build, +# otherwise run setup +%prep +if [ -f .census ] ; then + if [ ! -d ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION} ] ; then + ln -s . ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION} + fi +else +%setup +touch .census +./configure +fi + +%build +@make@ + +%install +DIST_ROOT="$RPM_BUILD_ROOT" +DIST_INSTALL=`pwd`/install.manifest +DIST_INSTALL_DEV=`pwd`/install-dev.manifest +export DIST_ROOT DIST_INSTALL DIST_INSTALL_DEV +@make@ install DIST_MANIFEST="$DIST_INSTALL" +@make@ install-dev DIST_MANIFEST="$DIST_INSTALL_DEV" +files() +{ + sort | uniq | awk ' +$1 == "d" { printf ("%%%%dir %%%%attr(%s,%s,%s) %s\n", $2, $3, $4, $5); } +$1 == "f" { if (match ($6, "@pkg_man_dir@") || match ($6, "@pkg_doc_dir@")) + printf ("%%%%doc "); + if (match ($6, "@pkg_man_dir@")) + printf ("%%%%attr(%s,%s,%s) %s*\n", $2, $3, $4, $6); + else + printf ("%%%%attr(%s,%s,%s) %s\n", $2, $3, $4, $6); } +$1 == "l" { if (match ($3, "@pkg_man_dir@") || match ($3, "@pkg_doc_dir@")) + printf ("%%%%doc "); + if (match ($3, "@pkg_man_dir@")) + printf ("%attr(0777,root,root) %s*\n", $3); + else + printf ("%attr(0777,root,root) %s\n", $3); }' +} +set +x +files < "$DIST_INSTALL" > files.rpm +files < "$DIST_INSTALL_DEV" > filesdevel.rpm +set -x + +%clean +rm -rf $RPM_BUILD_ROOT + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files -f files.rpm + +%files devel -f filesdevel.rpm diff -rNu linux-2.4.7/cmd/xfsprogs/build/tar/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/build/tar/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/build/tar/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/tar/CVS/Entries Thu Jul 5 11:44:18 2001 @@ -0,0 +1,2 @@ +/Makefile/1.3/Thu Mar 1 01:48:49 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/build/tar/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/build/tar/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/build/tar/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/tar/CVS/Repository Thu Jul 5 11:44:18 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/build/tar diff -rNu linux-2.4.7/cmd/xfsprogs/build/tar/CVS/Root linux-2.4-xfs/cmd/xfsprogs/build/tar/CVS/Root --- linux-2.4.7/cmd/xfsprogs/build/tar/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/tar/CVS/Root Thu Jul 5 11:44:18 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/build/tar/Makefile linux-2.4-xfs/cmd/xfsprogs/build/tar/Makefile --- linux-2.4.7/cmd/xfsprogs/build/tar/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/build/tar/Makefile Wed Feb 28 19:48:49 2001 @@ -0,0 +1,50 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +BINTAR=$(PKG_NAME)-$(PKG_VERSION).tar.gz +LDIRT = *.gz + +default install install-dev : + +include $(BUILDRULES) + +dist : default + @HERE=`pwd`; cd $${DIST_ROOT:-/}; \ + sort $$HERE/../bin-manifest | uniq | $(AWK) ' \ + $$1 == "f" { printf (".%s\n", $$6); } \ + $$1 == "d" { next; } \ + $$1 == "l" { printf (".%s\n", $$3); }' \ + | $(TAR) -T - -cf - | $(ZIP) --best > $$HERE/$(BINTAR) + @echo Wrote: `pwd`/$(BINTAR) diff -rNu linux-2.4.7/cmd/xfsprogs/configure.in linux-2.4-xfs/cmd/xfsprogs/configure.in --- linux-2.4.7/cmd/xfsprogs/configure.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/configure.in Tue Jun 12 02:20:31 2001 @@ -0,0 +1,249 @@ +dnl unpacking check - this file must exist +AC_INIT(include/libxfs.h) +pkg_name="xfsprogs" +AC_SUBST(pkg_name) + +# +# Note: the following environment variables may be set to override the +# defaults (to change paths and/or executables, build parameters, etc): +# +# DEBUG OPTIMIZER MAKE CC LD TAR ZIP RPM AWK SED ECHO +# MALLOCLIB DISTRIBUTION PACKAGE_BUILDER PREFIX ROOT_PREFIX +# + +DEBUG=${DEBUG:-'-DDEBUG'} # -DNDEBUG +OPTIMIZER=${OPTIMIZER:-'-g'} # (-O1 enforced default) +MALLOCLIB=${MALLOCLIB:-''} # /usr/lib/libefence.a + +dnl Debug build? +debug_build="$DEBUG" +AC_SUBST(debug_build) + +dnl Optimization options? +opt_build="$OPTIMIZER" +AC_SUBST(opt_build) + +dnl Alternate malloc library? +malloc_lib="$MALLOCLIB" +AC_SUBST(malloc_lib) + +dnl Set version +. ./VERSION + +pkg_version=${PKG_MAJOR}.${PKG_MINOR}.${PKG_REVISION} +pkg_release=$PKG_BUILD +AC_SUBST(pkg_version) +AC_SUBST(pkg_release) + +pkg_distribution="SGI ProPack" +test -z "$DISTRIBUTION" || pkg_distribution="$DISTRIBUTION" +AC_SUBST(pkg_distribution) + +pkg_builder=`id -u -n`@`hostname -f` +test -z "$PACKAGE_BUILDER" || pkg_builder="$PACKAGE_BUILDER" +AC_SUBST(pkg_builder) + + +dnl output header with cpp defs HAVE_*, etc +AC_CONFIG_HEADER(include/platform_defs.h) + +dnl check if user wants their own C compiler +test -z "$CC" && AC_PROG_CC +cc=$CC +AC_SUBST(cc) + +dnl check if users wants their own make +test -z "$MAKE" && AC_PATH_PROG(MAKE, make, /usr/bin/make) +make=$MAKE +AC_SUBST(make) + +dnl check if users wants their own linker +test -z "$LD" && AC_PATH_PROG(LD, ld, /usr/bin/ld) +ld=$LD +AC_SUBST(ld) + +dnl check if the tar program is available +test -z "$TAR" && AC_PATH_PROG(TAR, tar) +tar=$TAR +AC_SUBST(tar) + +dnl check if the gzip program is available +test -z "$ZIP" && AC_PATH_PROG(ZIP, gzip, /bin/gzip) +zip=$ZIP +AC_SUBST(zip) + +dnl check if the rpm program is available +test -z "$RPM" && AC_PATH_PROG(RPM, rpm, /bin/rpm) +rpm=$RPM +AC_SUBST(rpm) + +dnl .. and what version is rpm +rpm_version=0 +test -x $RPM && \ + rpm_version=`$RPM --version | awk '{print $NF}' | awk -F. '{print $1}'` +AC_SUBST(rpm_version) + +dnl check if the makedepend program is available +test -z "$MAKEDEPEND" && AC_PATH_PROG(MAKEDEPEND, makedepend, /bin/true) +makedepend=$MAKEDEPEND +AC_SUBST(makedepend) + +dnl check if symbolic links are supported +AC_PROG_LN_S + +dnl check if user wants their own awk, sed and echo +test -z "$AWK" && AC_PATH_PROG(AWK, awk, /bin/awk) +awk=$AWK +AC_SUBST(awk) +test -z "$SED" && AC_PATH_PROG(SED, sed, /bin/sed) +sed=$SED +AC_SUBST(sed) +test -z "$ECHO" && AC_PATH_PROG(ECHO, echo, /bin/echo) +echo=$ECHO +AC_SUBST(echo) + +dnl Checks for UUID header and library. +AC_CHECK_HEADER(uuid/uuid.h,, [ + echo + echo 'FATAL ERROR: could not find a valid UUID header.' + echo 'Install either the e2fsprogs-devel (rpm) or the uuid-dev (deb) package.' + exit 1 +]) +AC_CHECK_LIB(uuid, uuid_generate,, [ + echo + echo 'FATAL ERROR: could not find a valid UUID library.' + echo 'Install either the e2fsprogs-devel (rpm) or the uuid-dev (deb) package.' + exit 1 +]) +libuuid="/usr/lib/libuuid.a" +AC_SUBST(libuuid) + +dnl Checks for LVM library +AC_MSG_CHECKING([for liblvm.a]) +liblvm="" +for dir in /usr/local/lib /usr/lib /lib; do + if test -f $dir/liblvm.a; then + liblvm=$dir/liblvm.a + fi +done +if test -n "$liblvm"; then + AC_MSG_RESULT(yes) + have_liblvm=1 +else + AC_MSG_RESULT(no) + have_liblvm=0 +fi +AC_SUBST(liblvm) +AC_SUBST(have_liblvm) + +dnl Check if we have a type for the pointer's size integer (__psint_t) +AC_MSG_CHECKING([for __psint_t ]) +AC_TRY_COMPILE( +[ + #include + #include + #include +], +[ + __psint_t psint; +], AC_DEFINE(HAVE___PSINT_T) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) + +dnl Check if we have a type for the pointer's size unsigned (__psunsigned_t) +AC_MSG_CHECKING([for __psunsigned_t ]) +AC_TRY_COMPILE( +[ + #include + #include + #include +], +[ + __psunsigned_t psuint; +], AC_DEFINE(HAVE___PSUNSIGNED_T) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) + + +dnl check sizeof long +AC_MSG_CHECKING([sizeof long]) +cat <conftest.c +#include +main() { printf("%d\n", sizeof(long)); } +End-of-File +(eval $ac_compile) 2>&5 +(eval $ac_link) 2>&5 +ans=`./conftest` +echo "./conftest -> \"$ans\"" >&5 +AC_MSG_RESULT($ans) +test $ans -eq 4 && AC_DEFINE(HAVE_32BIT_LONG) +test $ans -eq 8 && AC_DEFINE(HAVE_64BIT_LONG) +rm -f conftest conftest.* + +dnl check sizeof pointer +AC_MSG_CHECKING([sizeof pointer]) +cat <conftest.c +#include +main() { printf("%d\n", sizeof(char *)); } +End-of-File +(eval $ac_compile) 2>&5 +(eval $ac_link) 2>&5 +ans=`./conftest` +echo "./conftest -> \"$ans\"" >&5 +AC_MSG_RESULT($ans) +test $ans -eq 4 && AC_DEFINE(HAVE_32BIT_PTR) +test $ans -eq 8 && AC_DEFINE(HAVE_64BIT_PTR) +rm -f conftest conftest.* + + +dnl alternate root and usr prefixes +test -z "$ROOT_PREFIX" && ROOT_PREFIX="" +root_prefix="$ROOT_PREFIX" +test -z "$PREFIX" && PREFIX="/usr" +prefix="$PREFIX" + +dnl man pages (source) +dnl also check if man page source is gzipped +dnl (usually on Debian, but not Redhat pre-7.0) +pkg_man_dir=${prefix}/share/man +have_zipped_manpages=false +for d in ${prefix}/share/man ${prefix}/man ; do + if test -f $d/man1/man.1.gz + then + pkg_man_dir=$d + have_zipped_manpages=true + break + fi +done +AC_SUBST(pkg_man_dir) +AC_SUBST(have_zipped_manpages) + +dnl binaries +pkg_bin_dir=${prefix}/sbin +AC_SUBST(pkg_bin_dir) + +dnl static libraries +pkg_lib_dir=${prefix}/lib +AC_SUBST(pkg_lib_dir) + +dnl runtime shared system libraries +pkg_slib_dir=${root_prefix}/lib +AC_SUBST(pkg_slib_dir) + +dnl system binaries +pkg_sbin_dir=${root_prefix}/sbin +AC_SUBST(pkg_sbin_dir) + +dnl include files +pkg_inc_dir=${prefix}/include/xfs +AC_SUBST(pkg_inc_dir) + +dnl doc directory +pkg_doc_dir=${prefix}/share/doc/${pkg_name} +AC_SUBST(pkg_doc_dir) + + +dnl +dnl output files +dnl + +AC_OUTPUT( \ +dnl Build definitions for use in Makefiles + include/builddefs \ +) diff -rNu linux-2.4.7/cmd/xfsprogs/db/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/db/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/db/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/CVS/Entries Thu Jul 5 11:44:26 2001 @@ -0,0 +1,106 @@ +/Makefile/1.2/Mon Jan 15 06:52:52 2001/-ko/ +/addr.c/1.1/Mon Jan 15 05:36:03 2001// +/addr.h/1.1/Mon Jan 15 05:36:03 2001// +/agf.c/1.1/Mon Jan 15 05:36:03 2001// +/agf.h/1.1/Mon Jan 15 05:36:03 2001// +/agfl.c/1.1/Mon Jan 15 05:36:03 2001// +/agfl.h/1.1/Mon Jan 15 05:36:03 2001// +/agi.c/1.1/Mon Jan 15 05:36:03 2001// +/agi.h/1.1/Mon Jan 15 05:36:03 2001// +/attr.c/1.1/Mon Jan 15 05:36:03 2001// +/attr.h/1.1/Mon Jan 15 05:36:03 2001// +/attrshort.c/1.1/Mon Jan 15 05:36:03 2001// +/attrshort.h/1.1/Mon Jan 15 05:36:03 2001// +/bit.c/1.1/Mon Jan 15 05:36:03 2001// +/bit.h/1.1/Mon Jan 15 05:36:03 2001// +/block.c/1.1/Mon Jan 15 05:36:03 2001// +/block.h/1.1/Mon Jan 15 05:36:03 2001// +/bmap.c/1.1/Mon Jan 15 05:36:03 2001// +/bmap.h/1.1/Mon Jan 15 05:36:03 2001// +/bmapbt.c/1.1/Mon Jan 15 05:36:03 2001// +/bmapbt.h/1.1/Mon Jan 15 05:36:03 2001// +/bmroot.c/1.1/Mon Jan 15 05:36:03 2001// +/bmroot.h/1.1/Mon Jan 15 05:36:03 2001// +/bnobt.c/1.1/Mon Jan 15 05:36:03 2001// +/bnobt.h/1.1/Mon Jan 15 05:36:03 2001// +/check.c/1.4/Thu Apr 12 23:49:04 2001// +/check.h/1.1/Mon Jan 15 05:36:03 2001// +/cntbt.c/1.1/Mon Jan 15 05:36:03 2001// +/cntbt.h/1.1/Mon Jan 15 05:36:03 2001// +/command.c/1.1/Mon Jan 15 05:36:03 2001// +/command.h/1.1/Mon Jan 15 05:36:03 2001// +/convert.c/1.1/Mon Jan 15 05:36:03 2001// +/convert.h/1.1/Mon Jan 15 05:36:03 2001// +/data.c/1.1/Mon Jan 15 05:36:03 2001// +/data.h/1.1/Mon Jan 15 05:36:03 2001// +/dbread.c/1.1/Mon Jan 15 05:36:03 2001// +/dbread.h/1.1/Mon Jan 15 05:36:03 2001// +/debug.c/1.1/Mon Jan 15 05:36:03 2001// +/debug.h/1.1/Mon Jan 15 05:36:03 2001// +/dir.c/1.1/Mon Jan 15 05:36:03 2001// +/dir.h/1.1/Mon Jan 15 05:36:03 2001// +/dir2.c/1.1/Mon Jan 15 05:36:03 2001// +/dir2.h/1.1/Mon Jan 15 05:36:03 2001// +/dir2sf.c/1.1/Mon Jan 15 05:36:03 2001// +/dir2sf.h/1.1/Mon Jan 15 05:36:03 2001// +/dirshort.c/1.1/Mon Jan 15 05:36:03 2001// +/dirshort.h/1.1/Mon Jan 15 05:36:03 2001// +/dquot.c/1.2/Tue Apr 3 02:52:38 2001// +/dquot.h/1.1/Mon Jan 15 05:36:03 2001// +/echo.c/1.1/Mon Jan 15 05:36:03 2001// +/echo.h/1.1/Mon Jan 15 05:36:03 2001// +/faddr.c/1.1/Mon Jan 15 05:36:03 2001// +/faddr.h/1.1/Mon Jan 15 05:36:03 2001// +/field.c/1.1/Mon Jan 15 05:36:03 2001// +/field.h/1.1/Mon Jan 15 05:36:03 2001// +/flist.c/1.2/Thu Apr 12 23:49:04 2001// +/flist.h/1.1/Mon Jan 15 05:36:03 2001// +/fprint.c/1.1/Mon Jan 15 05:36:03 2001// +/fprint.h/1.1/Mon Jan 15 05:36:03 2001// +/frag.c/1.2/Tue Apr 3 02:52:38 2001// +/frag.h/1.1/Mon Jan 15 05:36:03 2001// +/freesp.c/1.1/Mon Jan 15 05:36:03 2001// +/freesp.h/1.1/Mon Jan 15 05:36:03 2001// +/hash.c/1.1/Mon Jan 15 05:36:03 2001// +/hash.h/1.1/Mon Jan 15 05:36:03 2001// +/help.c/1.1/Mon Jan 15 05:36:03 2001// +/help.h/1.1/Mon Jan 15 05:36:03 2001// +/init.c/1.1/Mon Jan 15 05:36:03 2001// +/init.h/1.1/Mon Jan 15 05:36:03 2001// +/inobt.c/1.1/Mon Jan 15 05:36:03 2001// +/inobt.h/1.1/Mon Jan 15 05:36:03 2001// +/inode.c/1.2/Tue Apr 3 02:52:38 2001// +/inode.h/1.1/Mon Jan 15 05:36:03 2001// +/input.c/1.2/Mon Jan 15 06:52:52 2001// +/input.h/1.1/Mon Jan 15 05:36:03 2001// +/io.c/1.4/Wed May 9 06:56:06 2001// +/io.h/1.1/Mon Jan 15 05:36:03 2001// +/main.c/1.1/Mon Jan 15 05:36:03 2001// +/malloc.c/1.1/Mon Jan 15 05:36:03 2001// +/malloc.h/1.1/Mon Jan 15 05:36:03 2001// +/mount.c/1.1/Mon Jan 15 05:36:03 2001// +/mount.h/1.1/Mon Jan 15 05:36:03 2001// +/output.c/1.1/Mon Jan 15 05:36:03 2001// +/output.h/1.1/Mon Jan 15 05:36:03 2001// +/print.c/1.1/Mon Jan 15 05:36:03 2001// +/print.h/1.1/Mon Jan 15 05:36:03 2001// +/quit.c/1.1/Mon Jan 15 05:36:03 2001// +/quit.h/1.1/Mon Jan 15 05:36:03 2001// +/sb.c/1.2/Tue Apr 3 02:52:38 2001// +/sb.h/1.1/Mon Jan 15 05:36:03 2001// +/sig.c/1.1/Mon Jan 15 05:36:03 2001// +/sig.h/1.1/Mon Jan 15 05:36:03 2001// +/strvec.c/1.1/Mon Jan 15 05:36:03 2001// +/strvec.h/1.1/Mon Jan 15 05:36:03 2001// +/type.c/1.1/Mon Jan 15 05:36:03 2001// +/type.h/1.1/Mon Jan 15 05:36:03 2001// +/uuid.c/1.2/Tue Jan 16 04:03:49 2001/-ko/ +/uuid.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/write.c/1.1/Mon Jan 15 05:36:03 2001// +/write.h/1.1/Mon Jan 15 05:36:03 2001// +/xfs_admin.sh/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_check.sh/1.1/Mon Jan 15 05:36:03 2001// +/xfs_check64.sh/1.1/Mon Jan 15 05:36:03 2001// +/xfs_ncheck.sh/1.1/Mon Jan 15 05:36:03 2001// +/xfs_ncheck64.sh/1.1/Mon Jan 15 05:36:03 2001// +D diff -rNu linux-2.4.7/cmd/xfsprogs/db/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/db/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/db/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/CVS/Repository Thu Jul 5 11:44:18 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/db diff -rNu linux-2.4.7/cmd/xfsprogs/db/CVS/Root linux-2.4-xfs/cmd/xfsprogs/db/CVS/Root --- linux-2.4.7/cmd/xfsprogs/db/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/CVS/Root Thu Jul 5 11:44:18 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/db/Makefile linux-2.4-xfs/cmd/xfsprogs/db/Makefile --- linux-2.4.7/cmd/xfsprogs/db/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/Makefile Mon Jan 15 00:52:52 2001 @@ -0,0 +1,59 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = xfs_db + +HFILES = addr.h agf.h agfl.h agi.h attr.h attrshort.h bit.h block.h bmap.h \ + bmapbt.h bmroot.h bnobt.h check.h cntbt.h command.h convert.h data.h \ + dbread.h debug.h dir.h dir2.h dir2sf.h dirshort.h dquot.h echo.h \ + faddr.h field.h flist.h fprint.h frag.h freesp.h hash.h help.h \ + init.h inobt.h inode.h input.h io.h malloc.h mount.h output.h \ + print.h quit.h sb.h uuid.h sig.h strvec.h type.h write.h +CFILES = $(HFILES:.h=.c) main.c +LSRCFILES = xfs_admin.sh xfs_check.sh xfs_ncheck.sh +LLDLIBS = $(LIBXFS) $(LIBUUID) +LLDFLAGS = -L$(TOPDIR)/libxfs + +default: $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_BIN_DIR) + $(INSTALL) -m 755 xfs_admin.sh $(PKG_BIN_DIR)/xfs_admin + $(INSTALL) -m 755 xfs_check.sh $(PKG_BIN_DIR)/xfs_check + $(INSTALL) -m 755 xfs_ncheck.sh $(PKG_BIN_DIR)/xfs_ncheck +install-dev: diff -rNu linux-2.4.7/cmd/xfsprogs/db/addr.c linux-2.4-xfs/cmd/xfsprogs/db/addr.c --- linux-2.4.7/cmd/xfsprogs/db/addr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/addr.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "addr.h" +#include "command.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "io.h" +#include "flist.h" +#include "inode.h" +#include "output.h" + +static int addr_f(int argc, char **argv); +static void addr_help(void); + +static const cmdinfo_t addr_cmd = + { "addr", "a", addr_f, 0, 1, 1, "[field-expression]", + "set current address", addr_help }; + +static void +addr_help(void) +{ + dbprintf( +"\n" +" 'addr' uses the given field to set the filesystem address and type\n" +"\n" +" Examples:\n" +"\n" +" sb\n" +" a rootino - set the type to inode and set position to the root inode\n" +" a u.bmx[0].startblock (for inode with blockmap)\n" +"\n" +); + +} + +static int +addr_f( + int argc, + char **argv) +{ + adfnc_t adf; + const ftattr_t *fa; + flist_t *fl; + const field_t *fld; + typnm_t next; + flist_t *tfl; + + if (argc == 1) { + print_iocur("current", iocur_top); + return 0; + } + if (cur_typ == NULL) { + dbprintf("no current type\n"); + return 0; + } + fld = cur_typ->fields; + if (fld != NULL && fld->name[0] == '\0') { + fa = &ftattrtab[fld->ftyp]; + ASSERT(fa->ftyp == fld->ftyp); + fld = fa->subfld; + } + if (fld == NULL) { + dbprintf("no fields for type %s\n", cur_typ->name); + return 0; + } + fl = flist_scan(argv[1]); + if (fl == NULL) + return 0; + if (!flist_parse(fld, fl, iocur_top->data, 0)) { + flist_free(fl); + return 0; + } + flist_print(fl); + for (tfl = fl; tfl->child != NULL; tfl = tfl->child) { + if ((tfl->flags & FL_OKLOW) && tfl->low < tfl->high) { + dbprintf("array not allowed for addr command\n"); + flist_free(fl); + return 0; + } + } + fld = tfl->fld; + next = fld->next; + if (next == TYP_INODATA) + next = inode_next_type(); + if (next == TYP_NONE) { + dbprintf("no next type for field %s\n", fld->name); + return 0; + } + fa = &ftattrtab[fld->ftyp]; + ASSERT(fa->ftyp == fld->ftyp); + adf = fa->adfunc; + if (adf == NULL) { + dbprintf("no addr function for field %s (type %s)\n", + fld->name, fa->name); + return 0; + } + (*adf)(iocur_top->data, tfl->offset, next); + flist_free(fl); + return 0; +} + +void +addr_init(void) +{ + add_command(&addr_cmd); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/addr.h linux-2.4-xfs/cmd/xfsprogs/db/addr.h --- linux-2.4.7/cmd/xfsprogs/db/addr.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/addr.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern void addr_init(void); diff -rNu linux-2.4.7/cmd/xfsprogs/db/agf.c linux-2.4-xfs/cmd/xfsprogs/db/agf.c --- linux-2.4.7/cmd/xfsprogs/db/agf.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/agf.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "agf.h" +#include "command.h" +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "io.h" +#include "bit.h" +#include "output.h" +#include "mount.h" + +static int agf_f(int argc, char **argv); +static void agf_help(void); + +static const cmdinfo_t agf_cmd = + { "agf", NULL, agf_f, 0, 1, 1, "[agno]", + "set address to agf header", agf_help }; + +const field_t agf_hfld[] = { + { "", FLDT_AGF, OI(0), C1, 0, TYP_NONE }, + { NULL } +}; + +#define OFF(f) bitize(offsetof(xfs_agf_t, agf_ ## f)) +#define SZ(f) bitszof(xfs_agf_t, agf_ ## f) +const field_t agf_flds[] = { + { "magicnum", FLDT_UINT32X, OI(OFF(magicnum)), C1, 0, TYP_NONE }, + { "versionnum", FLDT_UINT32D, OI(OFF(versionnum)), C1, 0, TYP_NONE }, + { "seqno", FLDT_AGNUMBER, OI(OFF(seqno)), C1, 0, TYP_NONE }, + { "length", FLDT_AGBLOCK, OI(OFF(length)), C1, 0, TYP_NONE }, + { "roots", FLDT_AGBLOCK, OI(OFF(roots)), CI(XFS_BTNUM_AGF), + FLD_ARRAY|FLD_SKIPALL, TYP_NONE }, + { "bnoroot", FLDT_AGBLOCK, + OI(OFF(roots) + XFS_BTNUM_BNO * SZ(roots[XFS_BTNUM_BNO])), C1, 0, + TYP_BNOBT }, + { "cntroot", FLDT_AGBLOCK, + OI(OFF(roots) + XFS_BTNUM_CNT * SZ(roots[XFS_BTNUM_CNT])), C1, 0, + TYP_CNTBT }, + { "levels", FLDT_UINT32D, OI(OFF(levels)), CI(XFS_BTNUM_AGF), + FLD_ARRAY|FLD_SKIPALL, TYP_NONE }, + { "bnolevel", FLDT_UINT32D, + OI(OFF(levels) + XFS_BTNUM_BNO * SZ(levels[XFS_BTNUM_BNO])), C1, 0, + TYP_NONE }, + { "cntlevel", FLDT_UINT32D, + OI(OFF(levels) + XFS_BTNUM_CNT * SZ(levels[XFS_BTNUM_CNT])), C1, 0, + TYP_NONE }, + { "flfirst", FLDT_UINT32D, OI(OFF(flfirst)), C1, 0, TYP_NONE }, + { "fllast", FLDT_UINT32D, OI(OFF(fllast)), C1, 0, TYP_NONE }, + { "flcount", FLDT_UINT32D, OI(OFF(flcount)), C1, 0, TYP_NONE }, + { "freeblks", FLDT_EXTLEN, OI(OFF(freeblks)), C1, 0, TYP_NONE }, + { "longest", FLDT_EXTLEN, OI(OFF(longest)), C1, 0, TYP_NONE }, + { NULL } +}; + +static void +agf_help(void) +{ + dbprintf( +"\n" +" set allocation group free block list\n" +"\n" +" Example:\n" +"\n" +" agf 2 - move location to AGF in 2nd filesystem allocation group\n" +"\n" +" Located in the 2nd 512 byte block of each allocation group,\n" +" the AGF contains the root of two different freespace btrees:\n" +" The 'cnt' btree keeps track freespace indexed on section size.\n" +" The 'bno' btree tracks sections of freespace indexed on block number.\n" +); +} + +static int +agf_f( + int argc, + char **argv) +{ + xfs_agnumber_t agno; + char *p; + + if (argc > 1) { + agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0); + if (*p != '\0' || agno >= mp->m_sb.sb_agcount) { + dbprintf("bad allocation group number %s\n", argv[1]); + return 0; + } + cur_agno = agno; + } else if (cur_agno == NULLAGNUMBER) + cur_agno = 0; + ASSERT(typtab[TYP_AGF].typnm == TYP_AGF); + set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, cur_agno, XFS_AGF_DADDR), 1, + DB_RING_ADD, NULL); + return 0; +} + +void +agf_init(void) +{ + add_command(&agf_cmd); +} + +int +agf_size( + void *obj, + int startoff, + int idx) +{ + return bitize(mp->m_sb.sb_sectsize); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/agf.h linux-2.4-xfs/cmd/xfsprogs/db/agf.h --- linux-2.4.7/cmd/xfsprogs/db/agf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/agf.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct field; + +extern const struct field agf_flds[]; +extern const struct field agf_hfld[]; + +extern void agf_init(void); +extern int agf_size(void *obj, int startoff, int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/agfl.c linux-2.4-xfs/cmd/xfsprogs/db/agfl.c --- linux-2.4.7/cmd/xfsprogs/db/agfl.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/agfl.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "agfl.h" +#include "command.h" +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "io.h" +#include "bit.h" +#include "output.h" +#include "mount.h" + +static int agfl_f(int argc, char **argv); +static void agfl_help(void); + +static const cmdinfo_t agfl_cmd = + { "agfl", NULL, agfl_f, 0, 1, 1, "[agno]", + "set address to agfl block", agfl_help }; + +const field_t agfl_hfld[] = { + { "", FLDT_AGFL, OI(0), C1, 0, TYP_NONE }, + { NULL } +}; + +#define OFF(f) bitize(offsetof(xfs_agfl_t, agfl_ ## f)) +const field_t agfl_flds[] = { + { "bno", FLDT_AGBLOCKNZ, OI(OFF(bno)), CI(XFS_AGFL_SIZE), FLD_ARRAY, + TYP_DATA }, + { NULL } +}; + +static void +agfl_help(void) +{ + dbprintf( +"\n" +" set allocation group freelist\n" +"\n" +" Example:\n" +"\n" +" agfl 5" +"\n" +" Located in the 4th 512 byte block of each allocation group,\n" +" the agfl freelist for internal btree space allocation is maintained\n" +" for each allocation group. This acts as a reserved pool of space\n" +" separate from the general filesystem freespace (not used for user data).\n" +"\n" +); + +} + +static int +agfl_f( + int argc, + char **argv) +{ + xfs_agnumber_t agno; + char *p; + + if (argc > 1) { + agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0); + if (*p != '\0' || agno >= mp->m_sb.sb_agcount) { + dbprintf("bad allocation group number %s\n", argv[1]); + return 0; + } + cur_agno = agno; + } else if (cur_agno == NULLAGNUMBER) + cur_agno = 0; + ASSERT(typtab[TYP_AGFL].typnm == TYP_AGFL); + set_cur(&typtab[TYP_AGFL], XFS_AG_DADDR(mp, cur_agno, XFS_AGFL_DADDR), + 1, DB_RING_ADD, NULL); + return 0; +} + +void +agfl_init(void) +{ + add_command(&agfl_cmd); +} + +/*ARGSUSED*/ +int +agfl_size( + void *obj, + int startoff, + int idx) +{ + return bitize(mp->m_sb.sb_sectsize); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/agfl.h linux-2.4-xfs/cmd/xfsprogs/db/agfl.h --- linux-2.4.7/cmd/xfsprogs/db/agfl.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/agfl.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct field; + +extern const struct field agfl_flds[]; +extern const struct field agfl_hfld[]; + +extern void agfl_init(void); +extern int agfl_size(void *obj, int startoff, int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/agi.c linux-2.4-xfs/cmd/xfsprogs/db/agi.c --- linux-2.4.7/cmd/xfsprogs/db/agi.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/agi.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "agi.h" +#include "command.h" +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "io.h" +#include "bit.h" +#include "output.h" +#include "mount.h" + +static int agi_f(int argc, char **argv); +static void agi_help(void); + +static const cmdinfo_t agi_cmd = + { "agi", NULL, agi_f, 0, 1, 1, "[agno]", + "set address to agi header", agi_help }; + +const field_t agi_hfld[] = { + { "", FLDT_AGI, OI(0), C1, 0, TYP_NONE }, + { NULL } +}; + +#define OFF(f) bitize(offsetof(xfs_agi_t, agi_ ## f)) +const field_t agi_flds[] = { + { "magicnum", FLDT_UINT32X, OI(OFF(magicnum)), C1, 0, TYP_NONE }, + { "versionnum", FLDT_UINT32D, OI(OFF(versionnum)), C1, 0, TYP_NONE }, + { "seqno", FLDT_AGNUMBER, OI(OFF(seqno)), C1, 0, TYP_NONE }, + { "length", FLDT_AGBLOCK, OI(OFF(length)), C1, 0, TYP_NONE }, + { "count", FLDT_AGINO, OI(OFF(count)), C1, 0, TYP_NONE }, + { "root", FLDT_AGBLOCK, OI(OFF(root)), C1, 0, TYP_INOBT }, + { "level", FLDT_UINT32D, OI(OFF(level)), C1, 0, TYP_NONE }, + { "freecount", FLDT_AGINO, OI(OFF(freecount)), C1, 0, TYP_NONE }, + { "newino", FLDT_AGINO, OI(OFF(newino)), C1, 0, TYP_INODE }, + { "dirino", FLDT_AGINO, OI(OFF(dirino)), C1, 0, TYP_INODE }, + { "unlinked", FLDT_AGINONN, OI(OFF(unlinked)), + CI(XFS_AGI_UNLINKED_BUCKETS), FLD_ARRAY, TYP_NONE }, + { NULL } +}; + +static void +agi_help(void) +{ + dbprintf( +"\n" +" set allocation group inode btree\n" +"\n" +" Example:\n" +"\n" +" agi 3 (set location to 3rd allocation group inode btree and type to 'agi')\n" +"\n" +" Located in the 3rd 512 byte block of each allocation group,\n" +" the agi inode btree tracks all used/free inodes in the allocation group.\n" +" Inodes are allocated in 16k 'chunks', each btree entry tracks a 'chunk'.\n" +"\n" +); +} + +static int +agi_f( + int argc, + char **argv) +{ + xfs_agnumber_t agno; + char *p; + + if (argc > 1) { + agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0); + if (*p != '\0' || agno >= mp->m_sb.sb_agcount) { + dbprintf("bad allocation group number %s\n", argv[1]); + return 0; + } + cur_agno = agno; + } else if (cur_agno == NULLAGNUMBER) + cur_agno = 0; + ASSERT(typtab[TYP_AGI].typnm == TYP_AGI); + set_cur(&typtab[TYP_AGI], XFS_AG_DADDR(mp, cur_agno, XFS_AGI_DADDR), 1, + DB_RING_ADD, NULL); + return 0; +} + +void +agi_init(void) +{ + add_command(&agi_cmd); +} + +/*ARGSUSED*/ +int +agi_size( + void *obj, + int startoff, + int idx) +{ + return bitize(mp->m_sb.sb_sectsize); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/agi.h linux-2.4-xfs/cmd/xfsprogs/db/agi.h --- linux-2.4.7/cmd/xfsprogs/db/agi.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/agi.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct field; + +extern const struct field agi_flds[]; +extern const struct field agi_hfld[]; + +extern void agi_init(void); +extern int agi_size(void *obj, int startoff, int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/attr.c linux-2.4-xfs/cmd/xfsprogs/db/attr.c --- linux-2.4.7/cmd/xfsprogs/db/attr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/attr.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "bit.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "attr.h" +#include "io.h" +#include "data.h" +#include "mount.h" + +static int attr_leaf_entries_count(void *obj, int startoff); +static int attr_leaf_hdr_count(void *obj, int startoff); +static int attr_leaf_name_local_count(void *obj, int startoff); +static int attr_leaf_name_local_name_count(void *obj, int startoff); +static int attr_leaf_name_local_value_count(void *obj, int startoff); +static int attr_leaf_name_local_value_offset(void *obj, int startoff, + int idx); +static int attr_leaf_name_remote_count(void *obj, int startoff); +static int attr_leaf_name_remote_name_count(void *obj, int startoff); +static int attr_leaf_nvlist_count(void *obj, int startoff); +static int attr_leaf_nvlist_offset(void *obj, int startoff, int idx); +static int attr_node_btree_count(void *obj, int startoff); +static int attr_node_hdr_count(void *obj, int startoff); + +const field_t attr_hfld[] = { + { "", FLDT_ATTR, OI(0), C1, 0, TYP_NONE }, + { NULL } +}; + +#define LOFF(f) bitize(offsetof(xfs_attr_leafblock_t, f)) +#define NOFF(f) bitize(offsetof(xfs_da_intnode_t, f)) +const field_t attr_flds[] = { + { "hdr", FLDT_ATTR_LEAF_HDR, OI(LOFF(hdr)), attr_leaf_hdr_count, + FLD_COUNT, TYP_NONE }, + { "hdr", FLDT_ATTR_NODE_HDR, OI(NOFF(hdr)), attr_node_hdr_count, + FLD_COUNT, TYP_NONE }, + { "entries", FLDT_ATTR_LEAF_ENTRY, OI(LOFF(entries)), + attr_leaf_entries_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, + { "btree", FLDT_ATTR_NODE_ENTRY, OI(NOFF(btree)), attr_node_btree_count, + FLD_ARRAY|FLD_COUNT, TYP_NONE }, + { "nvlist", FLDT_ATTR_LEAF_NAME, attr_leaf_nvlist_offset, + attr_leaf_nvlist_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, + { NULL } +}; + +#define BOFF(f) bitize(offsetof(xfs_da_blkinfo_t, f)) +const field_t attr_blkinfo_flds[] = { + { "forw", FLDT_ATTRBLOCK, OI(BOFF(forw)), C1, 0, TYP_ATTR }, + { "back", FLDT_ATTRBLOCK, OI(BOFF(back)), C1, 0, TYP_ATTR }, + { "magic", FLDT_UINT16X, OI(BOFF(magic)), C1, 0, TYP_NONE }, + { "pad", FLDT_UINT16X, OI(BOFF(pad)), C1, FLD_SKIPALL, TYP_NONE }, + { NULL } +}; + +#define LEOFF(f) bitize(offsetof(xfs_attr_leaf_entry_t, f)) +const field_t attr_leaf_entry_flds[] = { + { "hashval", FLDT_UINT32X, OI(LEOFF(hashval)), C1, 0, TYP_NONE }, + { "nameidx", FLDT_UINT16D, OI(LEOFF(nameidx)), C1, 0, TYP_NONE }, + { "flags", FLDT_UINT8X, OI(LEOFF(flags)), C1, FLD_SKIPALL, TYP_NONE }, + { "incomplete", FLDT_UINT1, + OI(LEOFF(flags) + bitsz(__uint8_t) - XFS_ATTR_INCOMPLETE_BIT - 1), C1, + 0, TYP_NONE }, + { "root", FLDT_UINT1, + OI(LEOFF(flags) + bitsz(__uint8_t) - XFS_ATTR_ROOT_BIT - 1), C1, 0, + TYP_NONE }, + { "local", FLDT_UINT1, + OI(LEOFF(flags) + bitsz(__uint8_t) - XFS_ATTR_LOCAL_BIT - 1), C1, 0, + TYP_NONE }, + { "pad2", FLDT_UINT8X, OI(LEOFF(pad2)), C1, FLD_SKIPALL, TYP_NONE }, + { NULL } +}; + +#define LHOFF(f) bitize(offsetof(xfs_attr_leaf_hdr_t, f)) +const field_t attr_leaf_hdr_flds[] = { + { "info", FLDT_ATTR_BLKINFO, OI(LHOFF(info)), C1, 0, TYP_NONE }, + { "count", FLDT_UINT16D, OI(LHOFF(count)), C1, 0, TYP_NONE }, + { "usedbytes", FLDT_UINT16D, OI(LHOFF(usedbytes)), C1, 0, TYP_NONE }, + { "firstused", FLDT_UINT16D, OI(LHOFF(firstused)), C1, 0, TYP_NONE }, + { "holes", FLDT_UINT8D, OI(LHOFF(holes)), C1, 0, TYP_NONE }, + { "pad1", FLDT_UINT8X, OI(LHOFF(pad1)), C1, FLD_SKIPALL, TYP_NONE }, + { "freemap", FLDT_ATTR_LEAF_MAP, OI(LHOFF(freemap)), + CI(XFS_ATTR_LEAF_MAPSIZE), FLD_ARRAY, TYP_NONE }, + { NULL } +}; + +#define LMOFF(f) bitize(offsetof(xfs_attr_leaf_map_t, f)) +const field_t attr_leaf_map_flds[] = { + { "base", FLDT_UINT16D, OI(LMOFF(base)), C1, 0, TYP_NONE }, + { "size", FLDT_UINT16D, OI(LMOFF(size)), C1, 0, TYP_NONE }, + { NULL } +}; + +#define LNOFF(f) bitize(offsetof(xfs_attr_leaf_name_local_t, f)) +#define LVOFF(f) bitize(offsetof(xfs_attr_leaf_name_remote_t, f)) +const field_t attr_leaf_name_flds[] = { + { "valuelen", FLDT_UINT16D, OI(LNOFF(valuelen)), + attr_leaf_name_local_count, FLD_COUNT, TYP_NONE }, + { "namelen", FLDT_UINT8D, OI(LNOFF(namelen)), + attr_leaf_name_local_count, FLD_COUNT, TYP_NONE }, + { "name", FLDT_CHARNS, OI(LNOFF(nameval)), + attr_leaf_name_local_name_count, FLD_COUNT, TYP_NONE }, + { "value", FLDT_CHARNS, attr_leaf_name_local_value_offset, + attr_leaf_name_local_value_count, FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { "valueblk", FLDT_UINT32X, OI(LVOFF(valueblk)), + attr_leaf_name_remote_count, FLD_COUNT, TYP_NONE }, + { "valuelen", FLDT_UINT32D, OI(LVOFF(valuelen)), + attr_leaf_name_remote_count, FLD_COUNT, TYP_NONE }, + { "namelen", FLDT_UINT8D, OI(LVOFF(namelen)), + attr_leaf_name_remote_count, FLD_COUNT, TYP_NONE }, + { "name", FLDT_CHARNS, OI(LVOFF(name)), + attr_leaf_name_remote_name_count, FLD_COUNT, TYP_NONE }, + { NULL } +}; + +#define EOFF(f) bitize(offsetof(xfs_da_node_entry_t, f)) +const field_t attr_node_entry_flds[] = { + { "hashval", FLDT_UINT32X, OI(EOFF(hashval)), C1, 0, TYP_NONE }, + { "before", FLDT_ATTRBLOCK, OI(EOFF(before)), C1, 0, TYP_ATTR }, + { NULL } +}; + +#define HOFF(f) bitize(offsetof(xfs_da_node_hdr_t, f)) +const field_t attr_node_hdr_flds[] = { + { "info", FLDT_ATTR_BLKINFO, OI(HOFF(info)), C1, 0, TYP_NONE }, + { "count", FLDT_UINT16D, OI(HOFF(count)), C1, 0, TYP_NONE }, + { "level", FLDT_UINT16D, OI(HOFF(level)), C1, 0, TYP_NONE }, + { NULL } +}; + +/*ARGSUSED*/ +static int +attr_leaf_entries_count( + void *obj, + int startoff) +{ + xfs_attr_leafblock_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->hdr.info.magic, ARCH_CONVERT) + != XFS_ATTR_LEAF_MAGIC) { + return 0; + } + + return INT_GET(block->hdr.count, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +attr_leaf_hdr_count( + void *obj, + int startoff) +{ + xfs_attr_leafblock_t *block; + + ASSERT(startoff == 0); + block = obj; + return INT_GET(block->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC; +} + +static int +attr_leaf_name_local_count( + void *obj, + int startoff) +{ + xfs_attr_leafblock_t *block; + xfs_attr_leaf_entry_t *e; + int i; + int off; + + ASSERT(bitoffs(startoff) == 0); + off = byteize(startoff); + block = obj; + if (INT_GET(block->hdr.info.magic, ARCH_CONVERT) + != XFS_ATTR_LEAF_MAGIC) + return 0; + for (i = 0; i < INT_GET(block->hdr.count, ARCH_CONVERT); i++) { + e = &block->entries[i]; + if (INT_GET(e->nameidx, ARCH_CONVERT) == off) + return (INT_GET(e->flags, ARCH_CONVERT) + & XFS_ATTR_LOCAL) != 0; + } + return 0; +} + +static int +attr_leaf_name_local_name_count( + void *obj, + int startoff) +{ + xfs_attr_leafblock_t *block; + xfs_attr_leaf_entry_t *e; + int i; + xfs_attr_leaf_name_local_t *l; + int off; + + ASSERT(bitoffs(startoff) == 0); + off = byteize(startoff); + block = obj; + if (INT_GET(block->hdr.info.magic, ARCH_CONVERT) + != XFS_ATTR_LEAF_MAGIC) + return 0; + for (i = 0; i < INT_GET(block->hdr.count, ARCH_CONVERT); i++) { + e = &block->entries[i]; + if (INT_GET(e->nameidx, ARCH_CONVERT) == off) { + if (INT_GET(e->flags, ARCH_CONVERT) & XFS_ATTR_LOCAL) { + l = XFS_ATTR_LEAF_NAME_LOCAL(block, i); + return INT_GET(l->namelen, ARCH_CONVERT); + } else + return 0; + } + } + return 0; +} + +static int +attr_leaf_name_local_value_count( + void *obj, + int startoff) +{ + xfs_attr_leafblock_t *block; + xfs_attr_leaf_entry_t *e; + int i; + xfs_attr_leaf_name_local_t *l; + int off; + + ASSERT(bitoffs(startoff) == 0); + off = byteize(startoff); + block = obj; + if (INT_GET(block->hdr.info.magic, ARCH_CONVERT) + != XFS_ATTR_LEAF_MAGIC) + return 0; + for (i = 0; i < INT_GET(block->hdr.count, ARCH_CONVERT); i++) { + e = &block->entries[i]; + if (INT_GET(e->nameidx, ARCH_CONVERT) == off) { + if (INT_GET(e->flags, ARCH_CONVERT) & XFS_ATTR_LOCAL) { + l = XFS_ATTR_LEAF_NAME_LOCAL(block, i); + return INT_GET(l->valuelen, ARCH_CONVERT); + } else + return 0; + } + } + return 0; +} + +/*ARGSUSED*/ +static int +attr_leaf_name_local_value_offset( + void *obj, + int startoff, + int idx) +{ + xfs_attr_leafblock_t *block; + xfs_attr_leaf_name_local_t *l; + char *vp; + int off; + xfs_attr_leaf_entry_t *e; + int i; + + ASSERT(bitoffs(startoff) == 0); + off = byteize(startoff); + block = obj; + if (INT_GET(block->hdr.info.magic, ARCH_CONVERT) + != XFS_ATTR_LEAF_MAGIC) + return 0; + + for (i = 0; i < INT_GET(block->hdr.count, ARCH_CONVERT); i++) { + e = &block->entries[i]; + if (INT_GET(e->nameidx, ARCH_CONVERT) == off) + break; + } + if (i>=INT_GET(block->hdr.count, ARCH_CONVERT)) return 0; + + l = XFS_ATTR_LEAF_NAME_LOCAL(block, i); + vp = (char *)&l->nameval[l->namelen]; + return (int)bitize(vp - (char *)l); +} + +static int +attr_leaf_name_remote_count( + void *obj, + int startoff) +{ + xfs_attr_leafblock_t *block; + xfs_attr_leaf_entry_t *e; + int i; + int off; + + ASSERT(bitoffs(startoff) == 0); + off = byteize(startoff); + block = obj; + if (INT_GET(block->hdr.info.magic, ARCH_CONVERT) + != XFS_ATTR_LEAF_MAGIC) + return 0; + for (i = 0; i < INT_GET(block->hdr.count, ARCH_CONVERT); i++) { + e = &block->entries[i]; + if (INT_GET(e->nameidx, ARCH_CONVERT) == off) + return (INT_GET(e->flags, ARCH_CONVERT) & XFS_ATTR_LOCAL) == 0; + } + return 0; +} + +static int +attr_leaf_name_remote_name_count( + void *obj, + int startoff) +{ + xfs_attr_leafblock_t *block; + xfs_attr_leaf_entry_t *e; + int i; + int off; + xfs_attr_leaf_name_remote_t *r; + + ASSERT(bitoffs(startoff) == 0); + off = byteize(startoff); + block = obj; + if (INT_GET(block->hdr.info.magic, ARCH_CONVERT) + != XFS_ATTR_LEAF_MAGIC) + return 0; + for (i = 0; i < INT_GET(block->hdr.count, ARCH_CONVERT); i++) { + e = &block->entries[i]; + if (INT_GET(e->nameidx, ARCH_CONVERT) == off) { + if (!(INT_GET(e->flags, ARCH_CONVERT) & XFS_ATTR_LOCAL)) { + r = XFS_ATTR_LEAF_NAME_REMOTE(block, i); + return INT_GET(r->namelen, ARCH_CONVERT); + } else + return 0; + } + } + return 0; +} + +/*ARGSUSED*/ +int +attr_leaf_name_size( + void *obj, + int startoff, + int idx) +{ + xfs_attr_leafblock_t *block; + xfs_attr_leaf_entry_t *e; + xfs_attr_leaf_name_local_t *l; + xfs_attr_leaf_name_remote_t *r; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->hdr.info.magic, ARCH_CONVERT) + != XFS_ATTR_LEAF_MAGIC) + return 0; + e = &block->entries[idx]; + if (INT_GET(e->flags, ARCH_CONVERT) & XFS_ATTR_LOCAL) { + l = XFS_ATTR_LEAF_NAME_LOCAL(block, idx); + return (int)bitize(XFS_ATTR_LEAF_ENTSIZE_LOCAL(INT_GET(l->namelen, ARCH_CONVERT), + INT_GET(l->valuelen, ARCH_CONVERT))); + } else { + r = XFS_ATTR_LEAF_NAME_REMOTE(block, idx); + return (int)bitize(XFS_ATTR_LEAF_ENTSIZE_REMOTE(INT_GET(r->namelen, ARCH_CONVERT))); + } +} + +/*ARGSUSED*/ +static int +attr_leaf_nvlist_count( + void *obj, + int startoff) +{ + xfs_attr_leafblock_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->hdr.info.magic, ARCH_CONVERT) + != XFS_ATTR_LEAF_MAGIC) + return 0; + return INT_GET(block->hdr.count, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +attr_leaf_nvlist_offset( + void *obj, + int startoff, + int idx) +{ + xfs_attr_leafblock_t *block; + xfs_attr_leaf_entry_t *e; + + ASSERT(startoff == 0); + block = obj; + e = &block->entries[idx]; + return bitize(INT_GET(e->nameidx, ARCH_CONVERT)); +} + +/*ARGSUSED*/ +static int +attr_node_btree_count( + void *obj, + int startoff) +{ + xfs_da_intnode_t *block; + + ASSERT(startoff == 0); /* this is a base structure */ + block = obj; + if (INT_GET(block->hdr.info.magic, ARCH_CONVERT) + != XFS_DA_NODE_MAGIC) + return 0; + return INT_GET(block->hdr.count, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +attr_node_hdr_count( + void *obj, + int startoff) +{ + xfs_da_intnode_t *block; + + ASSERT(startoff == 0); + block = obj; + return INT_GET(block->hdr.info.magic, ARCH_CONVERT) + == XFS_DA_NODE_MAGIC; +} + +/*ARGSUSED*/ +int +attr_size( + void *obj, + int startoff, + int idx) +{ + return bitize(mp->m_sb.sb_blocksize); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/attr.h linux-2.4-xfs/cmd/xfsprogs/db/attr.h --- linux-2.4.7/cmd/xfsprogs/db/attr.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/attr.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern const field_t attr_flds[]; +extern const field_t attr_hfld[]; +extern const field_t attr_blkinfo_flds[]; +extern const field_t attr_leaf_entry_flds[]; +extern const field_t attr_leaf_hdr_flds[]; +extern const field_t attr_leaf_map_flds[]; +extern const field_t attr_leaf_name_flds[]; +extern const field_t attr_node_entry_flds[]; +extern const field_t attr_node_hdr_flds[]; + +extern int attr_leaf_name_size(void *obj, int startoff, int idx); +extern int attr_size(void *obj, int startoff, int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/attrshort.c linux-2.4-xfs/cmd/xfsprogs/db/attrshort.c --- linux-2.4.7/cmd/xfsprogs/db/attrshort.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/attrshort.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "bit.h" +#include "attrshort.h" + +static int attr_sf_entry_name_count(void *obj, int startoff); +static int attr_sf_entry_value_count(void *obj, int startoff); +static int attr_sf_entry_value_offset(void *obj, int startoff, int idx); +static int attr_shortform_list_count(void *obj, int startoff); +static int attr_shortform_list_offset(void *obj, int startoff, int idx); + +#define OFF(f) bitize(offsetof(xfs_attr_shortform_t, f)) +const field_t attr_shortform_flds[] = { + { "hdr", FLDT_ATTR_SF_HDR, OI(OFF(hdr)), C1, 0, TYP_NONE }, + { "list", FLDT_ATTR_SF_ENTRY, attr_shortform_list_offset, + attr_shortform_list_count, FLD_ARRAY|FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { NULL } +}; + +#define HOFF(f) bitize(offsetof(xfs_attr_sf_hdr_t, f)) +const field_t attr_sf_hdr_flds[] = { + { "totsize", FLDT_UINT16D, OI(HOFF(totsize)), C1, 0, TYP_NONE }, + { "count", FLDT_UINT8D, OI(HOFF(count)), C1, 0, TYP_NONE }, + { NULL } +}; + +#define EOFF(f) bitize(offsetof(xfs_attr_sf_entry_t, f)) +const field_t attr_sf_entry_flds[] = { + { "namelen", FLDT_UINT8D, OI(EOFF(namelen)), C1, 0, TYP_NONE }, + { "valuelen", FLDT_UINT8D, OI(EOFF(valuelen)), C1, 0, TYP_NONE }, + { "flags", FLDT_UINT8X, OI(EOFF(flags)), C1, FLD_SKIPALL, TYP_NONE }, + { "root", FLDT_UINT1, + OI(EOFF(flags) + bitsz(__uint8_t) - XFS_ATTR_ROOT_BIT - 1), C1, 0, + TYP_NONE }, + { "name", FLDT_CHARNS, OI(EOFF(nameval)), attr_sf_entry_name_count, + FLD_COUNT, TYP_NONE }, + { "value", FLDT_CHARNS, attr_sf_entry_value_offset, + attr_sf_entry_value_count, FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { NULL } +}; + +static int +attr_sf_entry_name_count( + void *obj, + int startoff) +{ + xfs_attr_sf_entry_t *e; + + ASSERT(bitoffs(startoff) == 0); + e = (xfs_attr_sf_entry_t *)((char *)obj + byteize(startoff)); + return e->namelen; +} + +int +attr_sf_entry_size( + void *obj, + int startoff, + int idx) +{ + xfs_attr_sf_entry_t *e; + int i; + xfs_attr_shortform_t *sf; + + ASSERT(bitoffs(startoff) == 0); + sf = (xfs_attr_shortform_t *)((char *)obj + byteize(startoff)); + e = &sf->list[0]; + for (i = 0; i < idx; i++) + e = XFS_ATTR_SF_NEXTENTRY(e); + return bitize((int)XFS_ATTR_SF_ENTSIZE(e)); +} + +static int +attr_sf_entry_value_count( + void *obj, + int startoff) +{ + xfs_attr_sf_entry_t *e; + + ASSERT(bitoffs(startoff) == 0); + e = (xfs_attr_sf_entry_t *)((char *)obj + byteize(startoff)); + return e->valuelen; +} + +/*ARGSUSED*/ +static int +attr_sf_entry_value_offset( + void *obj, + int startoff, + int idx) +{ + xfs_attr_sf_entry_t *e; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(idx == 0); + e = (xfs_attr_sf_entry_t *)((char *)obj + byteize(startoff)); + return bitize((int)((char *)&e->nameval[e->namelen] - (char *)e)); +} + +static int +attr_shortform_list_count( + void *obj, + int startoff) +{ + xfs_attr_shortform_t *sf; + + ASSERT(bitoffs(startoff) == 0); + sf = (xfs_attr_shortform_t *)((char *)obj + byteize(startoff)); + return sf->hdr.count; +} + +static int +attr_shortform_list_offset( + void *obj, + int startoff, + int idx) +{ + xfs_attr_sf_entry_t *e; + int i; + xfs_attr_shortform_t *sf; + + ASSERT(bitoffs(startoff) == 0); + sf = (xfs_attr_shortform_t *)((char *)obj + byteize(startoff)); + e = &sf->list[0]; + for (i = 0; i < idx; i++) + e = XFS_ATTR_SF_NEXTENTRY(e); + return bitize((int)((char *)e - (char *)sf)); +} + +/*ARGSUSED*/ +int +attrshort_size( + void *obj, + int startoff, + int idx) +{ + xfs_attr_sf_entry_t *e; + int i; + xfs_attr_shortform_t *sf; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(idx == 0); + sf = (xfs_attr_shortform_t *)((char *)obj + byteize(startoff)); + e = &sf->list[0]; + for (i = 0; i < sf->hdr.count; i++) + e = XFS_ATTR_SF_NEXTENTRY(e); + return bitize((int)((char *)e - (char *)sf)); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/attrshort.h linux-2.4-xfs/cmd/xfsprogs/db/attrshort.h --- linux-2.4.7/cmd/xfsprogs/db/attrshort.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/attrshort.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern const field_t attr_sf_entry_flds[]; +extern const field_t attr_sf_hdr_flds[]; +extern const field_t attr_shortform_flds[]; +extern const field_t attrshort_hfld[]; + +extern int attr_sf_entry_size(void *obj, int startoff, int idx); +extern int attrshort_size(void *obj, int startoff, int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/bit.c linux-2.4-xfs/cmd/xfsprogs/db/bit.c --- linux-2.4.7/cmd/xfsprogs/db/bit.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/bit.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "bit.h" + +#undef setbit /* defined in param.h on Linux */ + +static int getbit(char *ptr, int bit); +static void setbit(char *ptr, int bit, int val); + +static int +getbit( + char *ptr, + int bit) +{ + int mask; + int shift; + + ptr += byteize(bit); + bit = bitoffs(bit); + shift = 7 - bit; + mask = 1 << shift; + return (*ptr & mask) >> shift; +} + +static void +setbit( + char *ptr, + int bit, + int val) +{ + int mask; + int shift; + + ptr += byteize(bit); + bit = bitoffs(bit); + shift = 7 - bit; + mask = (1 << shift); + if (val) { + *ptr |= mask; + } else { + mask = ~mask; + *ptr &= mask; + } +} + +__int64_t +getbitval( + void *obj, + int bitoff, + int nbits, + int flags) +{ + int bit; + int i; + char *p; + __int64_t rval; + int signext; + int z1, z2, z3, z4; + + ASSERT(nbits<=64); + + p = (char *)obj + byteize(bitoff); + bit = bitoffs(bitoff); + signext = (flags & BVSIGNED) != 0; + z4 = ((__psint_t)p & 0xf) == 0 && bit == 0; + if (nbits == 64 && z4) { + if (signext) + return (__int64_t)INT_GET(*(__int64_t *)p, ARCH_CONVERT); + else + return (__int64_t)INT_GET(*(__uint64_t *)p, ARCH_CONVERT); + } + z3 = ((__psint_t)p & 0x7) == 0 && bit == 0; + if (nbits == 32 && z3) { + if (signext) + return (__int64_t)INT_GET(*(__int32_t *)p, ARCH_CONVERT); + else + return (__int64_t)INT_GET(*(__uint32_t *)p, ARCH_CONVERT); + } + z2 = ((__psint_t)p & 0x3) == 0 && bit == 0; + if (nbits == 16 && z2) { + if (signext) + return (__int64_t)INT_GET(*(__int16_t *)p, ARCH_CONVERT); + else + return (__int64_t)INT_GET(*(__uint16_t *)p, ARCH_CONVERT); + } + z1 = ((__psint_t)p & 0x1) == 0 && bit == 0; + if (nbits == 8 && z1) { + if (signext) + return (__int64_t)INT_GET(*(__int8_t *)p, ARCH_CONVERT); + else + return (__int64_t)INT_GET(*(__uint8_t *)p, ARCH_CONVERT); + } + + + for (i = 0, rval = 0LL; i < nbits; i++) { + if (getbit(p, bit + i)) { + /* If the last bit is on and we care about sign + * bits and we don't have a full 64 bit + * container, turn all bits on between the + * sign bit and the most sig bit. + */ + + /* handle endian swap here */ +#if __BYTE_ORDER == LITTLE_ENDIAN + if (i == 0 && signext && nbits < 64) + rval = -1LL << nbits; + rval |= 1LL << (nbits - i - 1); +#else + if ((i == (nbits - 1)) && signext && nbits < 64) + rval |= (-1LL << nbits); + rval |= 1LL << i; +#endif + } + } + return rval; +} + +void +setbitval( + void *obuf, /* buffer to write into */ + int bitoff, /* bit offset of where to write */ + int nbits, /* number of bits to write */ + void *ibuf) /* source bits */ +{ + char *in = (char *)ibuf; + char *out = (char *)obuf; + + int bit; + +#if BYTE_ORDER == LITTLE_ENDIAN + int big = 0; +#else + int big = 1; +#endif + + /* only need to swap LE integers */ + if (big || (nbits!=2 && nbits!=4 && nbits!=8) ) { + /* We don't have type info, so we can only assume + * that 2,4 & 8 byte values are integers. sigh. + */ + + /* byte aligned ? */ + if (bitoff%NBBY) { + /* no - bit copy */ + for (bit=0; bit +#include "block.h" +#include "bmap.h" +#include "command.h" +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "inode.h" +#include "io.h" +#include "output.h" +#include "mount.h" + +static int ablock_f(int argc, char **argv); +static void ablock_help(void); +static int daddr_f(int argc, char **argv); +static void daddr_help(void); +static int dblock_f(int argc, char **argv); +static void dblock_help(void); +static int fsblock_f(int argc, char **argv); +static void fsblock_help(void); +static void print_rawdata(void *data, int len); + +static const cmdinfo_t ablock_cmd = + { "ablock", NULL, ablock_f, 1, 1, 1, "filoff", + "set address to file offset (attr fork)", ablock_help }; +static const cmdinfo_t daddr_cmd = + { "daddr", NULL, daddr_f, 0, 1, 1, "[d]", + "set address to daddr value", daddr_help }; +static const cmdinfo_t dblock_cmd = + { "dblock", NULL, dblock_f, 1, 1, 1, "filoff", + "set address to file offset (data fork)", dblock_help }; +static const cmdinfo_t fsblock_cmd = + { "fsblock", "fsb", fsblock_f, 0, 1, 1, "[fsb]", + "set address to fsblock value", fsblock_help }; + +static void +ablock_help(void) +{ + dbprintf( +"\n Example:\n" +"\n" +" 'ablock 23' - sets the file position to the 23rd filesystem block in\n" +" the inode's attribute fork. The filesystem block size is specified in\n" +" the superblock.\n\n" +); +} + +/*ARGSUSED*/ +static int +ablock_f( + int argc, + char **argv) +{ + bmap_ext_t bm; + xfs_dfiloff_t bno; + xfs_dfsbno_t dfsbno; + int haveattr; + int nex; + char *p; + + bno = (xfs_dfiloff_t)strtoull(argv[1], &p, 0); + if (*p != '\0') { + dbprintf("bad block number %s\n", argv[1]); + return 0; + } + push_cur(); + set_cur_inode(iocur_top->ino); + haveattr = XFS_DFORK_Q((xfs_dinode_t *)iocur_top->data); + pop_cur(); + if (!haveattr) { + dbprintf("no attribute data for file\n"); + return 0; + } + nex = 1; + bmap(bno, 1, XFS_ATTR_FORK, &nex, &bm); + if (nex == 0) { + dbprintf("file attr block is unmapped\n"); + return 0; + } + dfsbno = bm.startblock + (bno - bm.startoff); + ASSERT(typtab[TYP_ATTR].typnm == TYP_ATTR); + set_cur(&typtab[TYP_ATTR], (__int64_t)XFS_FSB_TO_DADDR(mp, dfsbno), + blkbb, DB_RING_ADD, NULL); + return 0; +} + +void +block_init(void) +{ + add_command(&ablock_cmd); + add_command(&daddr_cmd); + add_command(&dblock_cmd); + add_command(&fsblock_cmd); +} + +static void +daddr_help(void) +{ + dbprintf( +"\n Example:\n" +"\n" +" 'daddr 102' - sets position to the 102nd absolute disk block\n" +" (512 byte block).\n" +); +} + +static int +daddr_f( + int argc, + char **argv) +{ + __int64_t d; + char *p; + + if (argc == 1) { + dbprintf("current daddr is %lld\n", iocur_top->off >> BBSHIFT); + return 0; + } + d = (__int64_t)strtoull(argv[1], &p, 0); + if (*p != '\0' || + d >= mp->m_sb.sb_dblocks << (mp->m_sb.sb_blocklog - BBSHIFT)) { + dbprintf("bad daddr %s\n", argv[1]); + return 0; + } + ASSERT(typtab[TYP_DATA].typnm == TYP_DATA); + set_cur(&typtab[TYP_DATA], d, 1, DB_RING_ADD, NULL); + return 0; +} + +static void +dblock_help(void) +{ + dbprintf( +"\n Example:\n" +"\n" +" 'dblock 23' - sets the file position to the 23rd filesystem block in\n" +" the inode's data fork. The filesystem block size is specified in the\n" +" superblock.\n\n" +); +} + +static int +dblock_f( + int argc, + char **argv) +{ + bbmap_t bbmap; + bmap_ext_t *bmp; + xfs_dfiloff_t bno; + xfs_dfsbno_t dfsbno; + int nb; + int nex; + char *p; + typnm_t type; + + bno = (xfs_dfiloff_t)strtoull(argv[1], &p, 0); + if (*p != '\0') { + dbprintf("bad block number %s\n", argv[1]); + return 0; + } + push_cur(); + set_cur_inode(iocur_top->ino); + type = inode_next_type(); + pop_cur(); + if (type == TYP_NONE) { + dbprintf("no type for file data\n"); + return 0; + } + nex = nb = type == TYP_DIR2 ? mp->m_dirblkfsbs : 1; + bmp = malloc(nb * sizeof(*bmp)); + bmap(bno, nb, XFS_DATA_FORK, &nex, bmp); + if (nex == 0) { + dbprintf("file data block is unmapped\n"); + free(bmp); + return 0; + } + dfsbno = bmp->startblock + (bno - bmp->startoff); + ASSERT(typtab[type].typnm == type); + if (nex > 1) + make_bbmap(&bbmap, nex, bmp); + set_cur(&typtab[type], (__int64_t)XFS_FSB_TO_DADDR(mp, dfsbno), + nb * blkbb, DB_RING_ADD, nex > 1 ? &bbmap : NULL); + free(bmp); + return 0; +} + +static void +fsblock_help(void) +{ + dbprintf( +"\n Example:\n" +"\n" +" 'fsblock 1023' - sets the file position to the 1023rd filesystem block.\n" +" The filesystem block size is specified in the superblock and set during\n" +" mkfs time. Offset is absolute (not AG relative).\n\n" +); +} + +static int +fsblock_f( + int argc, + char **argv) +{ + xfs_agblock_t agbno; + xfs_agnumber_t agno; + xfs_dfsbno_t d; + char *p; + + if (argc == 1) { + dbprintf("current fsblock is %lld\n", + XFS_DADDR_TO_FSB(mp, iocur_top->off >> BBSHIFT)); + return 0; + } + d = strtoull(argv[1], &p, 0); + if (*p != '\0') { + dbprintf("bad fsblock %s\n", argv[1]); + return 0; + } + agno = XFS_FSB_TO_AGNO(mp, d); + agbno = XFS_FSB_TO_AGBNO(mp, d); + if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks) { + dbprintf("bad fsblock %s\n", argv[1]); + return 0; + } + ASSERT(typtab[TYP_DATA].typnm == TYP_DATA); + set_cur(&typtab[TYP_DATA], XFS_AGB_TO_DADDR(mp, agno, agbno), + blkbb, DB_RING_ADD, NULL); + return 0; +} + +void +print_block( + const field_t *fields, + int argc, + char **argv) +{ + print_rawdata(iocur_top->data, iocur_top->len); +} + +static void +print_rawdata( + void *data, + int len) +{ + int i; + int j; + int lastaddr; + int offchars; + unsigned char *p; + + lastaddr = (len - 1) & ~(32 - 1); + if (lastaddr < 0x10) + offchars = 1; + else if (lastaddr < 0x100) + offchars = 2; + else if (lastaddr < 0x1000) + offchars = 3; + else + offchars = 4; + for (i = 0, p = data; i < len; i += 32) { + dbprintf("%-0*.*x:", offchars, offchars, i); + for (j = 0; j < 32 && i + j < len; j++, p++) { + if ((j & 3) == 0) + dbprintf(" "); + dbprintf("%02x", *p); + } + dbprintf("\n"); + } +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/block.h linux-2.4-xfs/cmd/xfsprogs/db/block.h --- linux-2.4.7/cmd/xfsprogs/db/block.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/block.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct field; + +extern void block_init(void); +extern void print_block(const struct field *fields, int argc, char **argv); diff -rNu linux-2.4.7/cmd/xfsprogs/db/bmap.c linux-2.4-xfs/cmd/xfsprogs/db/bmap.c --- linux-2.4.7/cmd/xfsprogs/db/bmap.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/bmap.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "command.h" +#include "data.h" +#include "type.h" +#include "bmap.h" +#include "io.h" +#include "inode.h" +#include "output.h" +#include "mount.h" + +static int bmap_f(int argc, char **argv); +static int bmap_one_extent(xfs_bmbt_rec_64_t *ep, + xfs_dfiloff_t *offp, xfs_dfiloff_t eoff, + int *idxp, bmap_ext_t *bep); +static xfs_fsblock_t select_child(xfs_dfiloff_t off, xfs_bmbt_key_t *kp, + xfs_bmbt_ptr_t *pp, int nrecs); + +static const cmdinfo_t bmap_cmd = + { "bmap", NULL, bmap_f, 0, 3, 0, "[-ad] [block [len]]", + "show block map for current file", NULL }; + +void +bmap( + xfs_dfiloff_t offset, + xfs_dfilblks_t len, + int whichfork, + int *nexp, + bmap_ext_t *bep) +{ + xfs_bmbt_block_t *block; + xfs_fsblock_t bno; + xfs_dfiloff_t curoffset; + xfs_dinode_t *dip; + xfs_dfiloff_t eoffset; + xfs_bmbt_rec_64_t *ep; + xfs_dinode_fmt_t fmt; + int fsize; + xfs_bmbt_key_t *kp; + int n; + int nex; + xfs_fsblock_t nextbno; + int nextents; + xfs_bmbt_ptr_t *pp; + xfs_bmdr_block_t *rblock; + typnm_t typ; + xfs_bmbt_rec_64_t *xp; + + push_cur(); + set_cur_inode(iocur_top->ino); + nex = *nexp; + *nexp = 0; + ASSERT(nex > 0); + dip = iocur_top->data; + n = 0; + eoffset = offset + len - 1; + curoffset = offset; + fmt = (xfs_dinode_fmt_t)XFS_DFORK_FORMAT_ARCH(dip, whichfork, ARCH_CONVERT); + typ = whichfork == XFS_DATA_FORK ? TYP_BMAPBTD : TYP_BMAPBTA; + ASSERT(typtab[typ].typnm == typ); + ASSERT(fmt == XFS_DINODE_FMT_EXTENTS || fmt == XFS_DINODE_FMT_BTREE); + if (fmt == XFS_DINODE_FMT_EXTENTS) { + nextents = XFS_DFORK_NEXTENTS_ARCH(dip, whichfork, ARCH_CONVERT); + xp = (xfs_bmbt_rec_64_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT); + for (ep = xp; ep < &xp[nextents] && n < nex; ep++) { + if (!bmap_one_extent(ep, &curoffset, eoffset, &n, bep)) + break; + } + } else { + push_cur(); + bno = NULLFSBLOCK; + rblock = (xfs_bmdr_block_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT); + fsize = XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_CONVERT); + pp = XFS_BTREE_PTR_ADDR(fsize, xfs_bmdr, rblock, 1, + XFS_BTREE_BLOCK_MAXRECS(fsize, xfs_bmdr, 0)); + kp = XFS_BTREE_KEY_ADDR(fsize, xfs_bmdr, rblock, 1, + XFS_BTREE_BLOCK_MAXRECS(fsize, xfs_bmdr, 0)); + bno = select_child(curoffset, kp, pp, INT_GET(rblock->bb_numrecs, ARCH_CONVERT)); + for (;;) { + set_cur(&typtab[typ], XFS_FSB_TO_DADDR(mp, bno), + blkbb, DB_RING_IGN, NULL); + block = (xfs_bmbt_block_t *)iocur_top->data; + if (INT_GET(block->bb_level, ARCH_CONVERT) == 0) + break; + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, + block, 1, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, + xfs_bmbt, 0)); + kp = XFS_BTREE_KEY_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, + block, 1, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, + xfs_bmbt, 0)); + bno = select_child(curoffset, kp, pp, + INT_GET(block->bb_numrecs, ARCH_CONVERT)); + } + for (;;) { + nextbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + nextents = INT_GET(block->bb_numrecs, ARCH_CONVERT); + xp = (xfs_bmbt_rec_64_t *)XFS_BTREE_REC_ADDR( + mp->m_sb.sb_blocksize, xfs_bmbt, block, 1, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, + xfs_bmbt, 1)); + for (ep = xp; ep < &xp[nextents] && n < nex; ep++) { + if (!bmap_one_extent(ep, &curoffset, eoffset, + &n, bep)) { + nextbno = NULLFSBLOCK; + break; + } + } + bno = nextbno; + if (bno == NULLFSBLOCK) + break; + set_cur(&typtab[typ], XFS_FSB_TO_DADDR(mp, bno), + blkbb, DB_RING_IGN, NULL); + block = (xfs_bmbt_block_t *)iocur_top->data; + } + pop_cur(); + } + pop_cur(); + *nexp = n; +} + +static int +bmap_f( + int argc, + char **argv) +{ + int afork = 0; + bmap_ext_t be; + int c; + xfs_dfiloff_t co; + int dfork = 0; + xfs_dinode_t *dip; + xfs_dfiloff_t eo; + xfs_dfilblks_t len; + int nex; + char *p; + int whichfork; + + if (iocur_top->ino == NULLFSINO) { + dbprintf("no current inode\n"); + return 0; + } + optind = 0; + if (argc) while ((c = getopt(argc, argv, "ad")) != EOF) { + switch (c) { + case 'a': + afork = 1; + break; + case 'd': + dfork = 1; + break; + default: + dbprintf("bad option for bmap command\n"); + return 0; + } + } + if (afork + dfork == 0) { + push_cur(); + set_cur_inode(iocur_top->ino); + dip = iocur_top->data; + if (INT_GET(dip->di_core.di_nextents, ARCH_CONVERT)) + dfork = 1; + if (INT_GET(dip->di_core.di_anextents, ARCH_CONVERT)) + afork = 1; + pop_cur(); + } + if (optind < argc) { + co = (xfs_dfiloff_t)strtoull(argv[optind], &p, 0); + if (*p != '\0') { + dbprintf("bad block number for bmap %s\n", + argv[optind]); + return 0; + } + optind++; + if (optind < argc) { + len = (xfs_dfilblks_t)strtoull(argv[optind], &p, 0); + if (*p != '\0') { + dbprintf("bad len for bmap %s\n", argv[optind]); + return 0; + } + eo = co + len - 1; + } else + eo = co; + } else { + co = 0; + eo = -1; + } + for (whichfork = XFS_DATA_FORK; + whichfork <= XFS_ATTR_FORK; + whichfork++) { + if (whichfork == XFS_DATA_FORK && !dfork) + continue; + if (whichfork == XFS_ATTR_FORK && !afork) + continue; + for (;;) { + nex = 1; + bmap(co, eo - co + 1, whichfork, &nex, &be); + if (nex == 0) + break; + dbprintf("%s offset %lld startblock %llu (%u/%u) count " + "%llu flag %u\n", + whichfork == XFS_DATA_FORK ? "data" : "attr", + be.startoff, be.startblock, + XFS_FSB_TO_AGNO(mp, be.startblock), + XFS_FSB_TO_AGBNO(mp, be.startblock), + be.blockcount, be.flag); + co = be.startoff + be.blockcount; + } + } + return 0; +} + +void +bmap_init(void) +{ + add_command(&bmap_cmd); +} + +static int +bmap_one_extent( + xfs_bmbt_rec_64_t *ep, + xfs_dfiloff_t *offp, + xfs_dfiloff_t eoff, + int *idxp, + bmap_ext_t *bep) +{ + xfs_dfilblks_t c; + xfs_dfiloff_t curoffset; + int f; + int idx; + xfs_dfiloff_t o; + xfs_dfsbno_t s; + + convert_extent(ep, &o, &s, &c, &f); + curoffset = *offp; + idx = *idxp; + if (o + c <= curoffset) + return 1; + if (o > eoff) + return 0; + if (o < curoffset) { + c -= curoffset - o; + s += curoffset - o; + o = curoffset; + } + if (o + c - 1 > eoff) + c -= (o + c - 1) - eoff; + bep[idx].startoff = o; + bep[idx].startblock = s; + bep[idx].blockcount = c; + bep[idx].flag = f; + *idxp = idx + 1; + *offp = o + c; + return 1; +} + +void +convert_extent( + xfs_bmbt_rec_64_t *rp, + xfs_dfiloff_t *op, + xfs_dfsbno_t *sp, + xfs_dfilblks_t *cp, + int *fp) +{ + xfs_bmbt_irec_t irec, *s = &irec; + + libxfs_bmbt_get_all((xfs_bmbt_rec_t *)rp, s); + + if (s->br_state == XFS_EXT_UNWRITTEN) { + *fp = 1; + } else { + *fp = 0; + } + + *op = s->br_startoff; + *sp = s->br_startblock; + *cp = s->br_blockcount; +} + +void +make_bbmap( + bbmap_t *bbmap, + int nex, + bmap_ext_t *bmp) +{ + int d; + xfs_dfsbno_t dfsbno; + int i; + int j; + int k; + + for (i = 0, d = 0; i < nex; i++) { + dfsbno = bmp[i].startblock; + for (j = 0; j < bmp[i].blockcount; j++, dfsbno++) { + for (k = 0; k < blkbb; k++) + bbmap->b[d++] = + XFS_FSB_TO_DADDR(mp, dfsbno) + k; + } + } +} + +static xfs_fsblock_t +select_child( + xfs_dfiloff_t off, + xfs_bmbt_key_t *kp, + xfs_bmbt_ptr_t *pp, + int nrecs) +{ + int i; + + for (i = 0; i < nrecs; i++) { + if (INT_GET(kp[i].br_startoff, ARCH_CONVERT) == off) + return INT_GET(pp[i], ARCH_CONVERT); + if (INT_GET(kp[i].br_startoff, ARCH_CONVERT) > off) { + if (i == 0) + return INT_GET(pp[i], ARCH_CONVERT); + else + return INT_GET(pp[i - 1], ARCH_CONVERT); + } + } + return INT_GET(pp[nrecs - 1], ARCH_CONVERT); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/bmap.h linux-2.4-xfs/cmd/xfsprogs/db/bmap.h --- linux-2.4.7/cmd/xfsprogs/db/bmap.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/bmap.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct bbmap; +struct xfs_bmbt_rec_64; + +typedef struct bmap_ext { + xfs_dfiloff_t startoff; + xfs_dfsbno_t startblock; + xfs_dfilblks_t blockcount; + int flag; +} bmap_ext_t; + +extern void bmap(xfs_dfiloff_t offset, xfs_dfilblks_t len, int whichfork, + int *nexp, bmap_ext_t *bep); +extern void bmap_init(void); +extern void convert_extent(struct xfs_bmbt_rec_64 *rp, xfs_dfiloff_t *op, + xfs_dfsbno_t *sp, xfs_dfilblks_t *cp, int *fp); +extern void make_bbmap(struct bbmap *bbmap, int nex, bmap_ext_t *bmp); diff -rNu linux-2.4.7/cmd/xfsprogs/db/bmapbt.c linux-2.4-xfs/cmd/xfsprogs/db/bmapbt.c --- linux-2.4.7/cmd/xfsprogs/db/bmapbt.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/bmapbt.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "bmapbt.h" +#include "print.h" +#include "bit.h" +#include "mount.h" + +static int bmapbta_key_count(void *obj, int startoff); +static int bmapbta_key_offset(void *obj, int startoff, int idx); +static int bmapbta_ptr_count(void *obj, int startoff); +static int bmapbta_ptr_offset(void *obj, int startoff, int idx); +static int bmapbta_rec_count(void *obj, int startoff); +static int bmapbta_rec_offset(void *obj, int startoff, int idx); +static int bmapbtd_key_count(void *obj, int startoff); +static int bmapbtd_key_offset(void *obj, int startoff, int idx); +static int bmapbtd_ptr_count(void *obj, int startoff); +static int bmapbtd_ptr_offset(void *obj, int startoff, int idx); +static int bmapbtd_rec_count(void *obj, int startoff); +static int bmapbtd_rec_offset(void *obj, int startoff, int idx); + +const field_t bmapbta_hfld[] = { + { "", FLDT_BMAPBTA, OI(0), C1, 0, TYP_NONE }, + { NULL } +}; +const field_t bmapbtd_hfld[] = { + { "", FLDT_BMAPBTD, OI(0), C1, 0, TYP_NONE }, + { NULL } +}; + +#define OFF(f) bitize(offsetof(xfs_bmbt_block_t, bb_ ## f)) +const field_t bmapbta_flds[] = { + { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, + { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, + { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, + { "leftsib", FLDT_DFSBNO, OI(OFF(leftsib)), C1, 0, TYP_BMAPBTA }, + { "rightsib", FLDT_DFSBNO, OI(OFF(rightsib)), C1, 0, TYP_BMAPBTA }, + { "recs", FLDT_BMAPBTAREC, bmapbta_rec_offset, bmapbta_rec_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { "keys", FLDT_BMAPBTAKEY, bmapbta_key_offset, bmapbta_key_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { "ptrs", FLDT_BMAPBTAPTR, bmapbta_ptr_offset, bmapbta_ptr_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_BMAPBTA }, + { NULL } +}; +const field_t bmapbtd_flds[] = { + { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, + { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, + { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, + { "leftsib", FLDT_DFSBNO, OI(OFF(leftsib)), C1, 0, TYP_BMAPBTD }, + { "rightsib", FLDT_DFSBNO, OI(OFF(rightsib)), C1, 0, TYP_BMAPBTD }, + { "recs", FLDT_BMAPBTDREC, bmapbtd_rec_offset, bmapbtd_rec_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { "keys", FLDT_BMAPBTDKEY, bmapbtd_key_offset, bmapbtd_key_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { "ptrs", FLDT_BMAPBTDPTR, bmapbtd_ptr_offset, bmapbtd_ptr_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_BMAPBTD }, + { NULL } +}; + +#define KOFF(f) bitize(offsetof(xfs_bmbt_key_t, br_ ## f)) +const field_t bmapbta_key_flds[] = { + { "startoff", FLDT_DFILOFFA, OI(KOFF(startoff)), C1, 0, TYP_ATTR }, + { NULL } +}; +const field_t bmapbtd_key_flds[] = { + { "startoff", FLDT_DFILOFFD, OI(KOFF(startoff)), C1, 0, TYP_INODATA }, + { NULL } +}; + +const field_t bmapbta_rec_flds[] = { + { "startoff", FLDT_CFILEOFFA, OI(BMBT_STARTOFF_BITOFF), C1, 0, + TYP_ATTR }, + { "startblock", FLDT_CFSBLOCK, OI(BMBT_STARTBLOCK_BITOFF), C1, 0, + TYP_ATTR }, + { "blockcount", FLDT_CEXTLEN, OI(BMBT_BLOCKCOUNT_BITOFF), C1, 0, + TYP_NONE }, + { "extentflag", FLDT_CEXTFLG, OI(BMBT_EXNTFLAG_BITOFF), C1, 0, + TYP_NONE }, + { NULL } +}; +const field_t bmapbtd_rec_flds[] = { + { "startoff", FLDT_CFILEOFFD, OI(BMBT_STARTOFF_BITOFF), C1, 0, + TYP_INODATA }, + { "startblock", FLDT_CFSBLOCK, OI(BMBT_STARTBLOCK_BITOFF), C1, 0, + TYP_INODATA }, + { "blockcount", FLDT_CEXTLEN, OI(BMBT_BLOCKCOUNT_BITOFF), C1, 0, + TYP_NONE }, + { "extentflag", FLDT_CEXTFLG, OI(BMBT_EXNTFLAG_BITOFF), C1, 0, + TYP_NONE }, + { NULL } +}; + +static int +bmapbta_key_count( + void *obj, + int startoff) +{ + xfs_bmbt_block_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->bb_level, ARCH_CONVERT) == 0) + return 0; + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +static int +bmapbta_key_offset( + void *obj, + int startoff, + int idx) +{ + xfs_bmbt_block_t *block; + xfs_bmbt_key_t *kp; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + kp = XFS_BTREE_KEY_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, idx, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_bmbt, 0)); + return bitize((int)((char *)kp - (char *)block)); +} + +static int +bmapbta_ptr_count( + void *obj, + int startoff) +{ + xfs_bmbt_block_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->bb_level, ARCH_CONVERT) == 0) + return 0; + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +static int +bmapbta_ptr_offset( + void *obj, + int startoff, + int idx) +{ + xfs_bmbt_block_t *block; + xfs_bmbt_ptr_t *pp; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, idx, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_bmbt, 0)); + return bitize((int)((char *)pp - (char *)block)); +} + +static int +bmapbta_rec_count( + void *obj, + int startoff) +{ + xfs_bmbt_block_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->bb_level, ARCH_CONVERT) > 0) + return 0; + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +static int +bmapbta_rec_offset( + void *obj, + int startoff, + int idx) +{ + xfs_bmbt_block_t *block; + xfs_bmbt_rec_t *rp; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) == 0); + rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, idx, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_bmbt, 1)); + return bitize((int)((char *)rp - (char *)block)); +} + +int +bmapbta_size( + void *obj, + int startoff, + int idx) +{ + return bitize(mp->m_sb.sb_blocksize); +} + +static int +bmapbtd_key_count( + void *obj, + int startoff) +{ + xfs_bmbt_block_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->bb_level, ARCH_CONVERT) == 0) + return 0; + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +static int +bmapbtd_key_offset( + void *obj, + int startoff, + int idx) +{ + xfs_bmbt_block_t *block; + xfs_bmbt_key_t *kp; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + kp = XFS_BTREE_KEY_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, idx, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_bmbt, 0)); + return bitize((int)((char *)kp - (char *)block)); +} + +static int +bmapbtd_ptr_count( + void *obj, + int startoff) +{ + xfs_bmbt_block_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->bb_level, ARCH_CONVERT) == 0) + return 0; + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +static int +bmapbtd_ptr_offset( + void *obj, + int startoff, + int idx) +{ + xfs_bmbt_block_t *block; + xfs_bmbt_ptr_t *pp; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, idx, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_bmbt, 0)); + return bitize((int)((char *)pp - (char *)block)); +} + +static int +bmapbtd_rec_count( + void *obj, + int startoff) +{ + xfs_bmbt_block_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->bb_level, ARCH_CONVERT) > 0) + return 0; + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +static int +bmapbtd_rec_offset( + void *obj, + int startoff, + int idx) +{ + xfs_bmbt_block_t *block; + xfs_bmbt_rec_t *rp; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) == 0); + rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, idx, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_bmbt, 1)); + return bitize((int)((char *)rp - (char *)block)); +} + +int +bmapbtd_size( + void *obj, + int startoff, + int idx) +{ + return bitize(mp->m_sb.sb_blocksize); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/bmapbt.h linux-2.4-xfs/cmd/xfsprogs/db/bmapbt.h --- linux-2.4.7/cmd/xfsprogs/db/bmapbt.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/bmapbt.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct field; + +extern const struct field bmapbta_flds[]; +extern const struct field bmapbta_hfld[]; +extern const struct field bmapbta_key_flds[]; +extern const struct field bmapbta_rec_flds[]; +extern const struct field bmapbtd_flds[]; +extern const struct field bmapbtd_hfld[]; +extern const struct field bmapbtd_key_flds[]; +extern const struct field bmapbtd_rec_flds[]; + +extern int bmapbta_size(void *obj, int startoff, int idx); +extern int bmapbtd_size(void *obj, int startoff, int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/bmroot.c linux-2.4-xfs/cmd/xfsprogs/db/bmroot.c --- linux-2.4.7/cmd/xfsprogs/db/bmroot.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/bmroot.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "bmroot.h" +#include "io.h" +#include "print.h" +#include "bit.h" +#include "mount.h" + +static int bmroota_key_count(void *obj, int startoff); +static int bmroota_key_offset(void *obj, int startoff, int idx); +static int bmroota_ptr_count(void *obj, int startoff); +static int bmroota_ptr_offset(void *obj, int startoff, int idx); +static int bmrootd_key_count(void *obj, int startoff); +static int bmrootd_key_offset(void *obj, int startoff, int idx); +static int bmrootd_ptr_count(void *obj, int startoff); +static int bmrootd_ptr_offset(void *obj, int startoff, int idx); + +#define OFF(f) bitize(offsetof(xfs_bmdr_block_t, bb_ ## f)) +const field_t bmroota_flds[] = { + { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, + { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, + { "keys", FLDT_BMROOTAKEY, bmroota_key_offset, bmroota_key_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { "ptrs", FLDT_BMROOTAPTR, bmroota_ptr_offset, bmroota_ptr_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_BMAPBTA }, + { NULL } +}; +const field_t bmrootd_flds[] = { + { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, + { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, + { "keys", FLDT_BMROOTDKEY, bmrootd_key_offset, bmrootd_key_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { "ptrs", FLDT_BMROOTDPTR, bmrootd_ptr_offset, bmrootd_ptr_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_BMAPBTD }, + { NULL } +}; + +#define KOFF(f) bitize(offsetof(xfs_bmdr_key_t, br_ ## f)) +const field_t bmroota_key_flds[] = { + { "startoff", FLDT_DFILOFFA, OI(KOFF(startoff)), C1, 0, TYP_NONE }, + { NULL } +}; +const field_t bmrootd_key_flds[] = { + { "startoff", FLDT_DFILOFFD, OI(KOFF(startoff)), C1, 0, TYP_NONE }, + { NULL } +}; + +static int +bmroota_key_count( + void *obj, + int startoff) +{ + xfs_bmdr_block_t *block; +#ifdef DEBUG + xfs_dinode_t *dip = obj; +#endif + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); + ASSERT(XFS_DFORK_Q(dip) && (char *)block == XFS_DFORK_APTR(dip)); + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +static int +bmroota_key_offset( + void *obj, + int startoff, + int idx) +{ + xfs_bmdr_block_t *block; + /* REFERENCED */ + xfs_dinode_t *dip; + xfs_bmdr_key_t *kp; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + dip = obj; + block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); + ASSERT(XFS_DFORK_Q(dip) && (char *)block == XFS_DFORK_APTR(dip)); + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + kp = XFS_BTREE_KEY_ADDR(iocur_top->len, xfs_bmdr, block, idx, + XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_ASIZE(dip, mp), xfs_bmdr, 0)); + return bitize((int)((char *)kp - (char *)block)); +} + +static int +bmroota_ptr_count( + void *obj, + int startoff) +{ + xfs_bmdr_block_t *block; +#ifdef DEBUG + xfs_dinode_t *dip = obj; +#endif + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); + ASSERT(XFS_DFORK_Q(dip) && (char *)block == XFS_DFORK_APTR(dip)); + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +static int +bmroota_ptr_offset( + void *obj, + int startoff, + int idx) +{ + xfs_bmdr_block_t *block; + xfs_dinode_t *dip; + xfs_bmdr_ptr_t *pp; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + dip = obj; + block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); + ASSERT(XFS_DFORK_Q(dip) && (char *)block == XFS_DFORK_APTR(dip)); + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + pp = XFS_BTREE_PTR_ADDR(iocur_top->len, xfs_bmdr, block, idx, + XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_ASIZE(dip, mp), xfs_bmdr, 0)); + return bitize((int)((char *)pp - (char *)block)); +} + +int +bmroota_size( + void *obj, + int startoff, + int idx) +{ + xfs_dinode_t *dip; +#ifdef DEBUG + xfs_bmdr_block_t *block; +#endif + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + ASSERT(idx == 0); + dip = obj; +#ifdef DEBUG + block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); + ASSERT(XFS_DFORK_Q(dip) && (char *)block == XFS_DFORK_APTR(dip)); +#endif + return bitize((int)XFS_DFORK_ASIZE(dip, mp)); +} + +static int +bmrootd_key_count( + void *obj, + int startoff) +{ + xfs_bmdr_block_t *block; +#ifdef DEBUG + xfs_dinode_t *dip = obj; +#endif + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); + ASSERT((char *)block == XFS_DFORK_DPTR(dip)); + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +static int +bmrootd_key_offset( + void *obj, + int startoff, + int idx) +{ + xfs_bmdr_block_t *block; + xfs_bmdr_key_t *kp; + xfs_dinode_t *dip; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + dip = obj; + block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + kp = XFS_BTREE_KEY_ADDR(iocur_top->len, xfs_bmdr, block, idx, + XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_DSIZE(dip, mp), xfs_bmdr, 0)); + return bitize((int)((char *)kp - (char *)block)); +} + +static int +bmrootd_ptr_count( + void *obj, + int startoff) +{ + xfs_bmdr_block_t *block; +#ifdef DEBUG + xfs_dinode_t *dip = obj; +#endif + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); + ASSERT((char *)block == XFS_DFORK_DPTR(dip)); + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +static int +bmrootd_ptr_offset( + void *obj, + int startoff, + int idx) +{ + xfs_bmdr_block_t *block; + xfs_bmdr_ptr_t *pp; + xfs_dinode_t *dip; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + dip = obj; + block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff)); + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + pp = XFS_BTREE_PTR_ADDR(iocur_top->len, xfs_bmdr, block, idx, + XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_DSIZE(dip, mp), xfs_bmdr, 0)); + return bitize((int)((char *)pp - (char *)block)); +} + +int +bmrootd_size( + void *obj, + int startoff, + int idx) +{ + xfs_dinode_t *dip; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + ASSERT(idx == 0); + dip = obj; + return bitize((int)XFS_DFORK_DSIZE(dip, mp)); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/bmroot.h linux-2.4-xfs/cmd/xfsprogs/db/bmroot.h --- linux-2.4.7/cmd/xfsprogs/db/bmroot.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/bmroot.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct field; + +extern const struct field bmroota_flds[]; +extern const struct field bmroota_key_flds[]; +extern const struct field bmrootd_flds[]; +extern const struct field bmrootd_key_flds[]; + +extern int bmroota_size(void *obj, int startoff, int idx); +extern int bmrootd_size(void *obj, int startoff, int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/bnobt.c linux-2.4-xfs/cmd/xfsprogs/db/bnobt.c --- linux-2.4.7/cmd/xfsprogs/db/bnobt.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/bnobt.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "bnobt.h" +#include "io.h" +#include "print.h" +#include "bit.h" +#include "mount.h" + +static int bnobt_key_count(void *obj, int startoff); +static int bnobt_key_offset(void *obj, int startoff, int idx); +static int bnobt_ptr_count(void *obj, int startoff); +static int bnobt_ptr_offset(void *obj, int startoff, int idx); +static int bnobt_rec_count(void *obj, int startoff); +static int bnobt_rec_offset(void *obj, int startoff, int idx); + +const field_t bnobt_hfld[] = { + { "", FLDT_BNOBT, OI(0), C1, 0, TYP_NONE }, + { NULL } +}; + +#define OFF(f) bitize(offsetof(xfs_alloc_block_t, bb_ ## f)) +const field_t bnobt_flds[] = { + { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, + { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, + { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, + { "leftsib", FLDT_AGBLOCK, OI(OFF(leftsib)), C1, 0, TYP_BNOBT }, + { "rightsib", FLDT_AGBLOCK, OI(OFF(rightsib)), C1, 0, TYP_BNOBT }, + { "recs", FLDT_BNOBTREC, bnobt_rec_offset, bnobt_rec_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { "keys", FLDT_BNOBTKEY, bnobt_key_offset, bnobt_key_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { "ptrs", FLDT_BNOBTPTR, bnobt_ptr_offset, bnobt_ptr_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_BNOBT }, + { NULL } +}; + +#define KOFF(f) bitize(offsetof(xfs_alloc_key_t, ar_ ## f)) +const field_t bnobt_key_flds[] = { + { "startblock", FLDT_AGBLOCK, OI(KOFF(startblock)), C1, 0, TYP_DATA }, + { "blockcount", FLDT_EXTLEN, OI(KOFF(blockcount)), C1, 0, TYP_NONE }, + { NULL } +}; + +#define ROFF(f) bitize(offsetof(xfs_alloc_rec_t, ar_ ## f)) +const field_t bnobt_rec_flds[] = { + { "startblock", FLDT_AGBLOCK, OI(ROFF(startblock)), C1, 0, TYP_DATA }, + { "blockcount", FLDT_EXTLEN, OI(ROFF(blockcount)), C1, 0, TYP_NONE }, + { NULL } +}; + +static int +bnobt_key_count( + void *obj, + int startoff) +{ + xfs_alloc_block_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->bb_level, ARCH_CONVERT) == 0) + return 0; + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +static int +bnobt_key_offset( + void *obj, + int startoff, + int idx) +{ + xfs_alloc_block_t *block; + xfs_alloc_key_t *kp; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + kp = XFS_BTREE_KEY_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, idx, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_alloc, 0)); + return bitize((int)((char *)kp - (char *)block)); +} + +static int +bnobt_ptr_count( + void *obj, + int startoff) +{ + xfs_alloc_block_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->bb_level, ARCH_CONVERT) == 0) + return 0; + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +static int +bnobt_ptr_offset( + void *obj, + int startoff, + int idx) +{ + xfs_alloc_block_t *block; + xfs_alloc_ptr_t *pp; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, idx, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_alloc, 0)); + return bitize((int)((char *)pp - (char *)block)); +} + +static int +bnobt_rec_count( + void *obj, + int startoff) +{ + xfs_alloc_block_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->bb_level, ARCH_CONVERT) > 0) + return 0; + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +static int +bnobt_rec_offset( + void *obj, + int startoff, + int idx) +{ + xfs_alloc_block_t *block; + xfs_alloc_rec_t *rp; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) == 0); + rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, idx, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_alloc, 1)); + return bitize((int)((char *)rp - (char *)block)); +} + +int +bnobt_size( + void *obj, + int startoff, + int idx) +{ + return bitize(mp->m_sb.sb_blocksize); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/bnobt.h linux-2.4-xfs/cmd/xfsprogs/db/bnobt.h --- linux-2.4.7/cmd/xfsprogs/db/bnobt.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/bnobt.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct field; + +extern const struct field bnobt_flds[]; +extern const struct field bnobt_hfld[]; +extern const struct field bnobt_key_flds[]; +extern const struct field bnobt_rec_flds[]; + +extern int bnobt_size(void *obj, int startoff, int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/check.c linux-2.4-xfs/cmd/xfsprogs/db/check.c --- linux-2.4.7/cmd/xfsprogs/db/check.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/check.c Thu Apr 12 18:49:04 2001 @@ -0,0 +1,4476 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include "bmap.h" +#include "check.h" +#include "command.h" +#include "data.h" +#include "io.h" +#include "output.h" +#include "type.h" +#include "mount.h" +#include "malloc.h" + +typedef enum { + DBM_UNKNOWN, DBM_AGF, DBM_AGFL, DBM_AGI, + DBM_ATTR, DBM_BTBMAPA, DBM_BTBMAPD, DBM_BTBNO, + DBM_BTCNT, DBM_BTINO, DBM_DATA, DBM_DIR, + DBM_FREE1, DBM_FREE2, DBM_FREELIST, DBM_INODE, + DBM_LOG, DBM_MISSING, DBM_QUOTA, DBM_RTBITMAP, + DBM_RTDATA, DBM_RTFREE, DBM_RTSUM, DBM_SB, + DBM_SYMLINK, + DBM_NDBM +} dbm_t; + +typedef struct inodata { + struct inodata *next; + nlink_t link_set; + nlink_t link_add; + char isdir; + char security; + char ilist; + xfs_ino_t ino; + struct inodata *parent; + char *name; +} inodata_t; +#define MIN_INODATA_HASH_SIZE 256 +#define MAX_INODATA_HASH_SIZE 65536 +#define INODATA_AVG_HASH_LENGTH 8 + +typedef struct qinfo { + xfs_qcnt_t bc; + xfs_qcnt_t ic; + xfs_qcnt_t rc; +} qinfo_t; + +#define QDATA_HASH_SIZE 256 +typedef struct qdata { + struct qdata *next; + xfs_dqid_t id; + qinfo_t count; + qinfo_t dq; +} qdata_t; + +typedef struct blkent { + xfs_fileoff_t startoff; + int nblks; + xfs_fsblock_t blks[1]; +} blkent_t; +#define BLKENT_SIZE(n) \ + (offsetof(blkent_t, blks) + (sizeof(xfs_fsblock_t) * (n))) + +typedef struct blkmap { + int naents; + int nents; + blkent_t *ents[1]; +} blkmap_t; +#define BLKMAP_SIZE(n) \ + (offsetof(blkmap_t, ents) + (sizeof(blkent_t *) * (n))) + +typedef struct freetab { + int naents; + int nents; + xfs_dir2_data_off_t ents[1]; +} freetab_t; +#define FREETAB_SIZE(n) \ + (offsetof(freetab_t, ents) + (sizeof(xfs_dir2_data_off_t) * (n))) + +typedef struct dirhash { + struct dirhash *next; + xfs_dir2_leaf_entry_t entry; + int seen; +} dirhash_t; +#define DIR_HASH_SIZE 1024 +#define DIR_HASH_FUNC(h,a) (((h) ^ (a)) % DIR_HASH_SIZE) + +static xfs_extlen_t agffreeblks; +static xfs_extlen_t agflongest; +static xfs_agino_t agicount; +static xfs_agino_t agifreecount; +static xfs_fsblock_t *blist; +static int blist_size; +static char **dbmap; /* really dbm_t:8 */ +static dirhash_t **dirhash; +static int error; +static __uint64_t fdblocks; +static __uint64_t frextents; +static __uint64_t icount; +static __uint64_t ifree; +static inodata_t ***inodata; +static int inodata_hash_size; +static inodata_t ***inomap; +static int nflag; +static int pflag; +static qdata_t **qgdata; +static int qgdo; +static qdata_t **qudata; +static int qudo; +static unsigned sbversion; +static int sbver_err; +static int serious_error; +static int sflag; +static xfs_suminfo_t *sumcompute; +static xfs_suminfo_t *sumfile; +static const char *typename[] = { + "unknown", + "agf", + "agfl", + "agi", + "attr", + "btbmapa", + "btbmapd", + "btbno", + "btcnt", + "btino", + "data", + "dir", + "free1", + "free2", + "freelist", + "inode", + "log", + "missing", + "quota", + "rtbitmap", + "rtdata", + "rtfree", + "rtsum", + "sb", + "symlink", + NULL +}; +static int verbose; + +#define CHECK_BLIST(b) (blist_size && check_blist(b)) +#define CHECK_BLISTA(a,b) \ + (blist_size && check_blist(XFS_AGB_TO_FSB(mp, a, b))) + +typedef void (*scan_lbtree_f_t)(xfs_btree_lblock_t *block, + int level, + dbm_t type, + xfs_fsblock_t bno, + inodata_t *id, + xfs_drfsbno_t *totd, + xfs_drfsbno_t *toti, + xfs_extnum_t *nex, + blkmap_t **blkmapp, + int isroot, + typnm_t btype); + +typedef void (*scan_sbtree_f_t)(xfs_btree_sblock_t *block, + int level, + xfs_agf_t *agf, + xfs_agblock_t bno, + int isroot); + +static void add_blist(xfs_fsblock_t bno); +static void add_ilist(xfs_ino_t ino); +static void addlink_inode(inodata_t *id); +static void addname_inode(inodata_t *id, char *name, int namelen); +static void addparent_inode(inodata_t *id, xfs_ino_t parent); +static void blkent_append(blkent_t **entp, xfs_fsblock_t b, + xfs_extlen_t c); +static blkent_t *blkent_new(xfs_fileoff_t o, xfs_fsblock_t b, + xfs_extlen_t c); +static void blkent_prepend(blkent_t **entp, xfs_fsblock_t b, + xfs_extlen_t c); +static blkmap_t *blkmap_alloc(xfs_extnum_t); +static void blkmap_free(blkmap_t *blkmap); +static xfs_fsblock_t blkmap_get(blkmap_t *blkmap, xfs_fileoff_t o); +static int blkmap_getn(blkmap_t *blkmap, xfs_fileoff_t o, int nb, + bmap_ext_t **bmpp); +static void blkmap_grow(blkmap_t **blkmapp, blkent_t **entp, + blkent_t *newent); +static xfs_fileoff_t blkmap_next_off(blkmap_t *blkmap, xfs_fileoff_t o, + int *t); +static void blkmap_set_blk(blkmap_t **blkmapp, xfs_fileoff_t o, + xfs_fsblock_t b); +static void blkmap_set_ext(blkmap_t **blkmapp, xfs_fileoff_t o, + xfs_fsblock_t b, xfs_extlen_t c); +static void blkmap_shrink(blkmap_t *blkmap, blkent_t **entp); +static int blockfree_f(int argc, char **argv); +static int blockget_f(int argc, char **argv); +#ifdef DEBUG +static int blocktrash_f(int argc, char **argv); +#endif +static int blockuse_f(int argc, char **argv); +static int check_blist(xfs_fsblock_t bno); +static void check_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno, + xfs_extlen_t len, dbm_t type); +static int check_inomap(xfs_agnumber_t agno, xfs_agblock_t agbno, + xfs_extlen_t len, xfs_ino_t c_ino); +static void check_linkcounts(xfs_agnumber_t agno); +static int check_range(xfs_agnumber_t agno, xfs_agblock_t agbno, + xfs_extlen_t len); +static void check_rdbmap(xfs_drfsbno_t bno, xfs_extlen_t len, + dbm_t type); +static int check_rinomap(xfs_drfsbno_t bno, xfs_extlen_t len, + xfs_ino_t c_ino); +static void check_rootdir(void); +static int check_rrange(xfs_drfsbno_t bno, xfs_extlen_t len); +static void check_set_dbmap(xfs_agnumber_t agno, + xfs_agblock_t agbno, xfs_extlen_t len, + dbm_t type1, dbm_t type2, + xfs_agnumber_t c_agno, + xfs_agblock_t c_agbno); +static void check_set_rdbmap(xfs_drfsbno_t bno, xfs_extlen_t len, + dbm_t type1, dbm_t type2); +static void check_summary(void); +static void checknot_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno, + xfs_extlen_t len, int typemask); +static void checknot_rdbmap(xfs_drfsbno_t bno, xfs_extlen_t len, + int typemask); +static void dir_hash_add(xfs_dahash_t hash, + xfs_dir2_dataptr_t addr); +static void dir_hash_check(inodata_t *id, int v); +static void dir_hash_done(void); +static void dir_hash_init(void); +static int dir_hash_see(xfs_dahash_t hash, + xfs_dir2_dataptr_t addr); +static inodata_t *find_inode(xfs_ino_t ino, int add); +static void free_inodata(xfs_agnumber_t agno); +static int init(int argc, char **argv); +static char *inode_name(xfs_ino_t ino, inodata_t **ipp); +static int ncheck_f(int argc, char **argv); +static char *prepend_path(char *oldpath, char *parent); +static xfs_ino_t process_block_dir_v2(blkmap_t *blkmap, int *dot, + int *dotdot, inodata_t *id); +static void process_bmbt_reclist(xfs_bmbt_rec_32_t *rp, int numrecs, + dbm_t type, inodata_t *id, + xfs_drfsbno_t *tot, + blkmap_t **blkmapp); +static void process_btinode(inodata_t *id, xfs_dinode_t *dip, + dbm_t type, xfs_drfsbno_t *totd, + xfs_drfsbno_t *toti, xfs_extnum_t *nex, + blkmap_t **blkmapp, int whichfork); +static xfs_ino_t process_data_dir_v2(int *dot, int *dotdot, + inodata_t *id, int v, + xfs_dablk_t dabno, + freetab_t **freetabp); +static xfs_dir2_data_free_t + *process_data_dir_v2_freefind(xfs_dir2_data_t *data, + xfs_dir2_data_unused_t *dup); +static void process_dir(xfs_dinode_t *dip, blkmap_t *blkmap, + inodata_t *id); +static int process_dir_v1(xfs_dinode_t *dip, blkmap_t *blkmap, + int *dot, int *dotdot, inodata_t *id, + xfs_ino_t *parent); +static int process_dir_v2(xfs_dinode_t *dip, blkmap_t *blkmap, + int *dot, int *dotdot, inodata_t *id, + xfs_ino_t *parent); +static void process_exinode(inodata_t *id, xfs_dinode_t *dip, + dbm_t type, xfs_drfsbno_t *totd, + xfs_drfsbno_t *toti, xfs_extnum_t *nex, + blkmap_t **blkmapp, int whichfork); +static void process_inode(xfs_agf_t *agf, xfs_agino_t agino, + xfs_dinode_t *dip, int isfree); +static void process_lclinode(inodata_t *id, xfs_dinode_t *dip, + dbm_t type, xfs_drfsbno_t *totd, + xfs_drfsbno_t *toti, xfs_extnum_t *nex, + blkmap_t **blkmapp, int whichfork); +static xfs_ino_t process_leaf_dir_v1(blkmap_t *blkmap, int *dot, + int *dotdot, inodata_t *id); +static xfs_ino_t process_leaf_dir_v1_int(int *dot, int *dotdot, + inodata_t *id); +static xfs_ino_t process_leaf_node_dir_v2(blkmap_t *blkmap, int *dot, + int *dotdot, inodata_t *id, + xfs_fsize_t dirsize); +static void process_leaf_node_dir_v2_free(inodata_t *id, int v, + xfs_dablk_t dbno, + freetab_t *freetab); +static void process_leaf_node_dir_v2_int(inodata_t *id, int v, + xfs_dablk_t dbno, + freetab_t *freetab); +static xfs_ino_t process_node_dir_v1(blkmap_t *blkmap, int *dot, + int *dotdot, inodata_t *id); +static void process_quota(int isgrp, inodata_t *id, + blkmap_t *blkmap); +static void process_rtbitmap(blkmap_t *blkmap); +static void process_rtsummary(blkmap_t *blkmap); +static xfs_ino_t process_sf_dir_v2(xfs_dinode_t *dip, int *dot, + int *dotdot, inodata_t *id); +static xfs_ino_t process_shortform_dir_v1(xfs_dinode_t *dip, int *dot, + int *dotdot, inodata_t *id); +static void quota_add(xfs_dqid_t grpid, xfs_dqid_t usrid, + int dq, xfs_qcnt_t bc, xfs_qcnt_t ic, + xfs_qcnt_t rc); +static void quota_add1(qdata_t **qt, xfs_dqid_t id, int dq, + xfs_qcnt_t bc, xfs_qcnt_t ic, + xfs_qcnt_t rc); +static void quota_check(char *s, qdata_t **qt); +static void quota_init(void); +static void scan_ag(xfs_agnumber_t agno); +static void scan_freelist(xfs_agf_t *agf); +static void scan_lbtree(xfs_fsblock_t root, int nlevels, + scan_lbtree_f_t func, dbm_t type, + inodata_t *id, xfs_drfsbno_t *totd, + xfs_drfsbno_t *toti, xfs_extnum_t *nex, + blkmap_t **blkmapp, int isroot, + typnm_t btype); +static void scan_sbtree(xfs_agf_t *agf, xfs_agblock_t root, + int nlevels, int isroot, + scan_sbtree_f_t func, typnm_t btype); +static void scanfunc_bmap(xfs_btree_lblock_t *ablock, int level, + dbm_t type, xfs_fsblock_t bno, + inodata_t *id, xfs_drfsbno_t *totd, + xfs_drfsbno_t *toti, xfs_extnum_t *nex, + blkmap_t **blkmapp, int isroot, + typnm_t btype); +static void scanfunc_bno(xfs_btree_sblock_t *ablock, int level, + xfs_agf_t *agf, xfs_agblock_t bno, + int isroot); +static void scanfunc_cnt(xfs_btree_sblock_t *ablock, int level, + xfs_agf_t *agf, xfs_agblock_t bno, + int isroot); +static void scanfunc_ino(xfs_btree_sblock_t *ablock, int level, + xfs_agf_t *agf, xfs_agblock_t bno, + int isroot); +static void set_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno, + xfs_extlen_t len, dbm_t type, + xfs_agnumber_t c_agno, xfs_agblock_t c_agbno); +static void set_inomap(xfs_agnumber_t agno, xfs_agblock_t agbno, + xfs_extlen_t len, inodata_t *id); +static void set_rdbmap(xfs_drfsbno_t bno, xfs_extlen_t len, + dbm_t type); +static void set_rinomap(xfs_drfsbno_t bno, xfs_extlen_t len, + inodata_t *id); +static void setlink_inode(inodata_t *id, nlink_t nlink, int isdir, + int security); + +static const cmdinfo_t blockfree_cmd = + { "blockfree", NULL, blockfree_f, 0, 0, 0, + NULL, "free block usage information", NULL }; +static const cmdinfo_t blockget_cmd = + { "blockget", "check", blockget_f, 0, -1, 0, + "[-s|-v] [-n] [-b bno]... [-i ino] ...", + "get block usage and check consistency", NULL }; +#ifdef DEBUG +static const cmdinfo_t blocktrash_cmd = + { "blocktrash", NULL, blocktrash_f, 0, -1, 0, + "[-n count] [-x minlen] [-y maxlen] [-s seed] [-0123] [-t type] ...", + "trash randomly selected block(s)", NULL }; +#endif +static const cmdinfo_t blockuse_cmd = + { "blockuse", NULL, blockuse_f, 0, 3, 0, + "[-n] [-c blockcount]", + "print usage for current block(s)", NULL }; +static const cmdinfo_t ncheck_cmd = + { "ncheck", NULL, ncheck_f, 0, -1, 0, + "[-s] [-i ino] ...", + "print inode-name pairs", NULL }; + + +static void +add_blist( + xfs_fsblock_t bno) +{ + blist_size++; + blist = xrealloc(blist, blist_size * sizeof(bno)); + blist[blist_size - 1] = bno; +} + +static void +add_ilist( + xfs_ino_t ino) +{ + inodata_t *id; + + id = find_inode(ino, 1); + if (id == NULL) { + dbprintf("-i %lld bad inode number\n", ino); + return; + } + id->ilist = 1; +} + +static void +addlink_inode( + inodata_t *id) +{ + id->link_add++; + if (verbose || id->ilist) + dbprintf("inode %lld add link, now %u\n", id->ino, + id->link_add); +} + +static void +addname_inode( + inodata_t *id, + char *name, + int namelen) +{ + if (!nflag || id->name) + return; + id->name = xmalloc(namelen + 1); + memcpy(id->name, name, namelen); + id->name[namelen] = '\0'; +} + +static void +addparent_inode( + inodata_t *id, + xfs_ino_t parent) +{ + inodata_t *pid; + + pid = find_inode(parent, 1); + id->parent = pid; + if (verbose || id->ilist || (pid && pid->ilist)) + dbprintf("inode %lld parent %lld\n", id->ino, parent); +} + +static void +blkent_append( + blkent_t **entp, + xfs_fsblock_t b, + xfs_extlen_t c) +{ + blkent_t *ent; + int i; + + ent = *entp; + *entp = ent = xrealloc(ent, BLKENT_SIZE(c + ent->nblks)); + for (i = 0; i < c; i++) + ent->blks[ent->nblks + i] = b + i; + ent->nblks += c; +} + +static blkent_t * +blkent_new( + xfs_fileoff_t o, + xfs_fsblock_t b, + xfs_extlen_t c) +{ + blkent_t *ent; + int i; + + ent = xmalloc(BLKENT_SIZE(c)); + ent->nblks = c; + ent->startoff = o; + for (i = 0; i < c; i++) + ent->blks[i] = b + i; + return ent; +} + +static void +blkent_prepend( + blkent_t **entp, + xfs_fsblock_t b, + xfs_extlen_t c) +{ + int i; + blkent_t *newent; + blkent_t *oldent; + + oldent = *entp; + newent = xmalloc(BLKENT_SIZE(oldent->nblks + c)); + newent->nblks = oldent->nblks + c; + newent->startoff = oldent->startoff - c; + for (i = 0; i < c; i++) + newent->blks[i] = b + c; + for (; i < oldent->nblks + c; i++) + newent->blks[i] = oldent->blks[i - c]; + xfree(oldent); + *entp = newent; +} + +static blkmap_t * +blkmap_alloc( + xfs_extnum_t nex) +{ + blkmap_t *blkmap; + + if (nex < 1) + nex = 1; + blkmap = xmalloc(BLKMAP_SIZE(nex)); + blkmap->naents = nex; + blkmap->nents = 0; + return blkmap; +} + +static void +blkmap_free( + blkmap_t *blkmap) +{ + blkent_t **entp; + xfs_extnum_t i; + + for (i = 0, entp = blkmap->ents; i < blkmap->nents; i++, entp++) + xfree(*entp); + xfree(blkmap); +} + +static xfs_fsblock_t +blkmap_get( + blkmap_t *blkmap, + xfs_fileoff_t o) +{ + blkent_t *ent; + blkent_t **entp; + int i; + + for (i = 0, entp = blkmap->ents; i < blkmap->nents; i++, entp++) { + ent = *entp; + if (o >= ent->startoff && o < ent->startoff + ent->nblks) + return ent->blks[o - ent->startoff]; + } + return NULLFSBLOCK; +} + +static int +blkmap_getn( + blkmap_t *blkmap, + xfs_fileoff_t o, + int nb, + bmap_ext_t **bmpp) +{ + bmap_ext_t *bmp; + blkent_t *ent; + xfs_fileoff_t ento; + blkent_t **entp; + int i; + int nex; + + for (i = nex = 0, bmp = NULL, entp = blkmap->ents; + i < blkmap->nents; + i++, entp++) { + ent = *entp; + if (ent->startoff >= o + nb) + break; + if (ent->startoff + ent->nblks <= o) + continue; + for (ento = ent->startoff; + ento < ent->startoff + ent->nblks && ento < o + nb; + ento++) { + if (ento < o) + continue; + if (bmp && + bmp[nex - 1].startoff + bmp[nex - 1].blockcount == + ento && + bmp[nex - 1].startblock + bmp[nex - 1].blockcount == + ent->blks[ento - ent->startoff]) + bmp[nex - 1].blockcount++; + else { + bmp = realloc(bmp, ++nex * sizeof(*bmp)); + bmp[nex - 1].startoff = ento; + bmp[nex - 1].startblock = + ent->blks[ento - ent->startoff]; + bmp[nex - 1].blockcount = 1; + bmp[nex - 1].flag = 0; + } + } + } + *bmpp = bmp; + return nex; +} + +static void +blkmap_grow( + blkmap_t **blkmapp, + blkent_t **entp, + blkent_t *newent) +{ + blkmap_t *blkmap; + int i; + int idx; + + blkmap = *blkmapp; + idx = (int)(entp - blkmap->ents); + if (blkmap->naents == blkmap->nents) { + blkmap = xrealloc(blkmap, BLKMAP_SIZE(blkmap->nents + 1)); + *blkmapp = blkmap; + blkmap->naents++; + } + for (i = blkmap->nents; i > idx; i--) + blkmap->ents[i] = blkmap->ents[i - 1]; + blkmap->ents[idx] = newent; + blkmap->nents++; +} + +static xfs_fileoff_t +blkmap_last_off( + blkmap_t *blkmap) +{ + blkent_t *ent; + + if (!blkmap->nents) + return NULLFILEOFF; + ent = blkmap->ents[blkmap->nents - 1]; + return ent->startoff + ent->nblks; +} + +static xfs_fileoff_t +blkmap_next_off( + blkmap_t *blkmap, + xfs_fileoff_t o, + int *t) +{ + blkent_t *ent; + blkent_t **entp; + + if (!blkmap->nents) + return NULLFILEOFF; + if (o == NULLFILEOFF) { + *t = 0; + ent = blkmap->ents[0]; + return ent->startoff; + } + entp = &blkmap->ents[*t]; + ent = *entp; + if (o < ent->startoff + ent->nblks - 1) + return o + 1; + entp++; + if (entp >= &blkmap->ents[blkmap->nents]) + return NULLFILEOFF; + (*t)++; + ent = *entp; + return ent->startoff; +} + +static void +blkmap_set_blk( + blkmap_t **blkmapp, + xfs_fileoff_t o, + xfs_fsblock_t b) +{ + blkmap_t *blkmap; + blkent_t *ent; + blkent_t **entp; + blkent_t *nextent; + + blkmap = *blkmapp; + for (entp = blkmap->ents; entp < &blkmap->ents[blkmap->nents]; entp++) { + ent = *entp; + if (o < ent->startoff - 1) { + ent = blkent_new(o, b, 1); + blkmap_grow(blkmapp, entp, ent); + return; + } + if (o == ent->startoff - 1) { + blkent_prepend(entp, b, 1); + return; + } + if (o >= ent->startoff && o < ent->startoff + ent->nblks) { + ent->blks[o - ent->startoff] = b; + return; + } + if (o > ent->startoff + ent->nblks) + continue; + blkent_append(entp, b, 1); + if (entp == &blkmap->ents[blkmap->nents - 1]) + return; + ent = *entp; + nextent = entp[1]; + if (ent->startoff + ent->nblks < nextent->startoff) + return; + blkent_append(entp, nextent->blks[0], nextent->nblks); + blkmap_shrink(blkmap, &entp[1]); + return; + } + ent = blkent_new(o, b, 1); + blkmap_grow(blkmapp, entp, ent); +} + +static void +blkmap_set_ext( + blkmap_t **blkmapp, + xfs_fileoff_t o, + xfs_fsblock_t b, + xfs_extlen_t c) +{ + blkmap_t *blkmap; + blkent_t *ent; + blkent_t **entp; + xfs_extnum_t i; + + blkmap = *blkmapp; + if (!blkmap->nents) { + blkmap->ents[0] = blkent_new(o, b, c); + blkmap->nents = 1; + return; + } + entp = &blkmap->ents[blkmap->nents - 1]; + ent = *entp; + if (ent->startoff + ent->nblks == o) { + blkent_append(entp, b, c); + return; + } + if (ent->startoff + ent->nblks < o) { + ent = blkent_new(o, b, c); + blkmap_grow(blkmapp, &blkmap->ents[blkmap->nents], ent); + return; + } + for (i = 0; i < c; i++) + blkmap_set_blk(blkmapp, o + i, b + i); +} + +static void +blkmap_shrink( + blkmap_t *blkmap, + blkent_t **entp) +{ + int i; + int idx; + + xfree(*entp); + idx = (int)(entp - blkmap->ents); + for (i = idx + 1; i < blkmap->nents; i++) + blkmap->ents[i] = blkmap->ents[i - 1]; + blkmap->nents--; +} + +/* ARGSUSED */ +static int +blockfree_f( + int argc, + char **argv) +{ + xfs_agnumber_t c; + int rt; + + if (!dbmap) { + dbprintf("block usage information not allocated\n"); + return 0; + } + rt = mp->m_sb.sb_rextents != 0; + for (c = 0; c < mp->m_sb.sb_agcount; c++) { + xfree(dbmap[c]); + xfree(inomap[c]); + free_inodata(c); + } + if (rt) { + xfree(dbmap[c]); + xfree(inomap[c]); + xfree(sumcompute); + xfree(sumfile); + sumcompute = sumfile = NULL; + } + xfree(dbmap); + xfree(inomap); + xfree(inodata); + dbmap = NULL; + inomap = NULL; + inodata = NULL; + return 0; +} + +/* + * Check consistency of xfs filesystem contents. + */ +static int +blockget_f( + int argc, + char **argv) +{ + xfs_agnumber_t agno; + int oldprefix; + int sbyell; + + if (dbmap) { + dbprintf("already have block usage information\n"); + return 0; + } + if (!init(argc, argv)) + return 0; + oldprefix = dbprefix; + dbprefix |= pflag; + for (agno = 0, sbyell = 0; agno < mp->m_sb.sb_agcount; agno++) { + scan_ag(agno); + if (sbver_err > 4 && !sbyell && sbver_err >= agno) { + sbyell = 1; + dbprintf("WARNING: this may be a newer XFS " + "filesystem.\n"); + } + } + if (blist_size) { + xfree(blist); + blist = NULL; + blist_size = 0; + } + if (serious_error) { + exitcode = 2; + dbprefix = oldprefix; + return 0; + } + check_rootdir(); + for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { + /* + * Check that there are no blocks either + * a) unaccounted for or + * b) bno-free but not cnt-free + */ + checknot_dbmap(agno, 0, mp->m_sb.sb_agblocks, + (1 << DBM_UNKNOWN) | (1 << DBM_FREE1)); + check_linkcounts(agno); + } + if (mp->m_sb.sb_rblocks) { + checknot_rdbmap(0, + (xfs_extlen_t)(mp->m_sb.sb_rextents * + mp->m_sb.sb_rextsize), + 1 << DBM_UNKNOWN); + check_summary(); + } + if (mp->m_sb.sb_icount != icount) { + if (!sflag) + dbprintf("sb_icount %lld, counted %lld\n", + mp->m_sb.sb_icount, icount); + error++; + } + if (mp->m_sb.sb_ifree != ifree) { + if (!sflag) + dbprintf("sb_ifree %lld, counted %lld\n", + mp->m_sb.sb_ifree, ifree); + error++; + } + if (mp->m_sb.sb_fdblocks != fdblocks) { + if (!sflag) + dbprintf("sb_fdblocks %lld, counted %lld\n", + mp->m_sb.sb_fdblocks, fdblocks); + error++; + } + if (mp->m_sb.sb_frextents != frextents) { + if (!sflag) + dbprintf("sb_frextents %lld, counted %lld\n", + mp->m_sb.sb_frextents, frextents); + error++; + } + if ((sbversion & XFS_SB_VERSION_ATTRBIT) && + !XFS_SB_VERSION_HASATTR(&mp->m_sb)) { + if (!sflag) + dbprintf("sb versionnum missing attr bit %x\n", + XFS_SB_VERSION_ATTRBIT); + error++; + } + if ((sbversion & XFS_SB_VERSION_NLINKBIT) && + !XFS_SB_VERSION_HASNLINK(&mp->m_sb)) { + if (!sflag) + dbprintf("sb versionnum missing nlink bit %x\n", + XFS_SB_VERSION_NLINKBIT); + error++; + } + if ((sbversion & XFS_SB_VERSION_QUOTABIT) && + !XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) { + if (!sflag) + dbprintf("sb versionnum missing quota bit %x\n", + XFS_SB_VERSION_QUOTABIT); + error++; + } + if (!(sbversion & XFS_SB_VERSION_ALIGNBIT) && + XFS_SB_VERSION_HASALIGN(&mp->m_sb)) { + if (!sflag) + dbprintf("sb versionnum extra align bit %x\n", + XFS_SB_VERSION_ALIGNBIT); + error++; + } + if (qudo) + quota_check("user", qudata); + if (qgdo) + quota_check("group", qgdata); + if (sbver_err > mp->m_sb.sb_agcount / 2) + dbprintf("WARNING: this may be a newer XFS filesystem.\n"); + if (error) + exitcode = 3; + dbprefix = oldprefix; + return 0; +} + +#ifdef DEBUG +typedef struct ltab { + int min; + int max; +} ltab_t; + +static void +blocktrash_b( + xfs_agnumber_t agno, + xfs_agblock_t agbno, + dbm_t type, + ltab_t *ltabp, + int mode) +{ + int bit; + int bitno; + char *buf; + int byte; + int len; + int mask; + int newbit; + int offset; + static char *modestr[] = { + "zeroed", "set", "flipped", "randomized" + }; + + len = (int)((random() % (ltabp->max - ltabp->min + 1)) + ltabp->min); + offset = (int)(random() % (int)(mp->m_sb.sb_blocksize * NBBY)); + newbit = 0; + push_cur(); + set_cur(&typtab[DBM_UNKNOWN], + XFS_AGB_TO_DADDR(mp, agno, agbno), blkbb, DB_RING_IGN, NULL); + if ((buf = iocur_top->data) == NULL) { + dbprintf("can't read block %u/%u for trashing\n", agno, agbno); + pop_cur(); + return; + } + for (bitno = 0; bitno < len; bitno++) { + bit = (offset + bitno) % (mp->m_sb.sb_blocksize * NBBY); + byte = bit / NBBY; + bit %= NBBY; + mask = 1 << bit; + switch (mode) { + case 0: + newbit = 0; + break; + case 1: + newbit = 1; + break; + case 2: + newbit = (buf[byte] & mask) == 0; + break; + case 3: + newbit = (int)random() & 1; + break; + } + if (newbit) + buf[byte] |= mask; + else + buf[byte] &= ~mask; + } + write_cur(); + pop_cur(); + printf("blocktrash: %u/%u %s block %d bit%s starting %d:%d %s\n", + agno, agbno, typename[type], len, len == 1 ? "" : "s", + offset / NBBY, offset % NBBY, modestr[mode]); +} + +int +blocktrash_f( + int argc, + char **argv) +{ + xfs_agblock_t agbno; + xfs_agnumber_t agno; + xfs_drfsbno_t bi; + xfs_drfsbno_t blocks; + int c; + int count; + int done; + int goodmask; + int i; + ltab_t *lentab; + int lentablen; + int max; + int min; + int mode; + struct timeval now; + char *p; + xfs_drfsbno_t randb; + uint seed; + int sopt; + int tmask; + + if (!dbmap) { + dbprintf("must run blockget first\n"); + return 0; + } + optind = 0; + count = 1; + min = 1; + max = 128 * NBBY; + mode = 2; + gettimeofday(&now, NULL); + seed = (unsigned int)(now.tv_sec ^ now.tv_usec); + sopt = 0; + tmask = 0; + goodmask = (1 << DBM_AGF) | + (1 << DBM_AGFL) | + (1 << DBM_AGI) | + (1 << DBM_ATTR) | + (1 << DBM_BTBMAPA) | + (1 << DBM_BTBMAPD) | + (1 << DBM_BTBNO) | + (1 << DBM_BTCNT) | + (1 << DBM_BTINO) | + (1 << DBM_DIR) | + (1 << DBM_INODE) | + (1 << DBM_QUOTA) | + (1 << DBM_RTBITMAP) | + (1 << DBM_RTSUM) | + (1 << DBM_SB); + while ((c = getopt(argc, argv, "0123n:s:t:x:y:")) != EOF) { + switch (c) { + case '0': + mode = 0; + break; + case '1': + mode = 1; + break; + case '2': + mode = 2; + break; + case '3': + mode = 3; + break; + case 'n': + count = (int)strtol(optarg, &p, 0); + if (*p != '\0' || count <= 0) { + dbprintf("bad blocktrash count %s\n", optarg); + return 0; + } + break; + case 's': + seed = (uint)strtoul(optarg, &p, 0); + sopt = 1; + break; + case 't': + for (i = 0; typename[i]; i++) { + if (strcmp(typename[i], optarg) == 0) + break; + } + if (!typename[i] || (((1 << i) & goodmask) == 0)) { + dbprintf("bad blocktrash type %s\n", optarg); + return 0; + } + tmask |= 1 << i; + break; + case 'x': + min = (int)strtol(optarg, &p, 0); + if (*p != '\0' || min <= 0 || + min > mp->m_sb.sb_blocksize * NBBY) { + dbprintf("bad blocktrash min %s\n", optarg); + return 0; + } + break; + case 'y': + max = (int)strtol(optarg, &p, 0); + if (*p != '\0' || max <= 0 || + max > mp->m_sb.sb_blocksize * NBBY) { + dbprintf("bad blocktrash max %s\n", optarg); + return 0; + } + break; + default: + dbprintf("bad option for blocktrash command\n"); + return 0; + } + } + if (min > max) { + dbprintf("bad min/max for blocktrash command\n"); + return 0; + } + if (tmask == 0) + tmask = goodmask; + lentab = xmalloc(sizeof(ltab_t)); + lentab->min = lentab->max = min; + lentablen = 1; + for (i = min + 1; i <= max; i++) { + if ((i & (i - 1)) == 0) { + lentab = xrealloc(lentab, + sizeof(ltab_t) * (lentablen + 1)); + lentab[lentablen].min = lentab[lentablen].max = i; + lentablen++; + } else + lentab[lentablen - 1].max = i; + } + for (blocks = 0, agno = 0; agno < mp->m_sb.sb_agcount; agno++) { + for (agbno = 0, p = dbmap[agno]; + agbno < mp->m_sb.sb_agblocks; + agbno++, p++) { + if ((1 << *p) & tmask) + blocks++; + } + } + if (blocks == 0) { + dbprintf("blocktrash: no matching blocks\n"); + return 0; + } + if (!sopt) + dbprintf("blocktrash: seed %u\n", seed); + srandom(seed); + for (i = 0; i < count; i++) { + randb = (xfs_drfsbno_t)((((__int64_t)random() << 32) | + random()) % blocks); + for (bi = 0, agno = 0, done = 0; + !done && agno < mp->m_sb.sb_agcount; + agno++) { + for (agbno = 0, p = dbmap[agno]; + agbno < mp->m_sb.sb_agblocks; + agbno++, p++) { + if (!((1 << *p) & tmask)) + continue; + if (bi++ < randb) + continue; + blocktrash_b(agno, agbno, (dbm_t)*p, + &lentab[random() % lentablen], mode); + done = 1; + break; + } + } + } + xfree(lentab); + return 0; +} +#endif + +int +blockuse_f( + int argc, + char **argv) +{ + xfs_agblock_t agbno; + xfs_agnumber_t agno; + int c; + int count; + xfs_agblock_t end; + xfs_fsblock_t fsb; + inodata_t *i; + char *p; + int shownames; + + if (!dbmap) { + dbprintf("must run blockget first\n"); + return 0; + } + optind = 0; + count = 1; + shownames = 0; + fsb = XFS_DADDR_TO_FSB(mp, iocur_top->off >> BBSHIFT); + agno = XFS_FSB_TO_AGNO(mp, fsb); + end = agbno = XFS_FSB_TO_AGBNO(mp, fsb); + while ((c = getopt(argc, argv, "c:n")) != EOF) { + switch (c) { + case 'c': + count = (int)strtol(optarg, &p, 0); + end = agbno + count - 1; + if (*p != '\0' || count <= 0 || + end >= mp->m_sb.sb_agblocks) { + dbprintf("bad blockuse count %s\n", optarg); + return 0; + } + break; + case 'n': + if (!nflag) { + dbprintf("must run blockget -n first\n"); + return 0; + } + shownames = 1; + break; + default: + dbprintf("bad option for blockuse command\n"); + return 0; + } + } + while (agbno <= end) { + p = &dbmap[agno][agbno]; + i = inomap[agno][agbno]; + dbprintf("block %llu (%u/%u) type %s", + (xfs_dfsbno_t)XFS_AGB_TO_FSB(mp, agno, agbno), + agno, agbno, typename[(dbm_t)*p]); + if (i) { + dbprintf(" inode %lld", i->ino); + if (shownames && (p = inode_name(i->ino, NULL))) { + dbprintf(" %s", p); + xfree(p); + } + } + dbprintf("\n"); + agbno++; + } + return 0; +} + +static int +check_blist( + xfs_fsblock_t bno) +{ + int i; + + for (i = 0; i < blist_size; i++) { + if (blist[i] == bno) + return 1; + } + return 0; +} + +static void +check_dbmap( + xfs_agnumber_t agno, + xfs_agblock_t agbno, + xfs_extlen_t len, + dbm_t type) +{ + xfs_extlen_t i; + char *p; + + for (i = 0, p = &dbmap[agno][agbno]; i < len; i++, p++) { + if ((dbm_t)*p != type) { + if (!sflag || CHECK_BLISTA(agno, agbno + i)) + dbprintf("block %u/%u expected type %s got " + "%s\n", + agno, agbno + i, typename[type], + typename[(dbm_t)*p]); + error++; + } + } +} + +void +check_init(void) +{ + add_command(&blockfree_cmd); + add_command(&blockget_cmd); +#ifdef DEBUG + add_command(&blocktrash_cmd); +#endif + add_command(&blockuse_cmd); + add_command(&ncheck_cmd); +} + +static int +check_inomap( + xfs_agnumber_t agno, + xfs_agblock_t agbno, + xfs_extlen_t len, + xfs_ino_t c_ino) +{ + xfs_extlen_t i; + inodata_t **idp; + int rval; + + if (!check_range(agno, agbno, len)) { + dbprintf("blocks %u/%u..%u claimed by inode %lld\n", + agno, agbno, agbno + len - 1, c_ino); + return 0; + } + for (i = 0, rval = 1, idp = &inomap[agno][agbno]; i < len; i++, idp++) { + if (*idp) { + if (!sflag || (*idp)->ilist || + CHECK_BLISTA(agno, agbno + i)) + dbprintf("block %u/%u claimed by inode %lld, " + "previous inum %lld\n", + agno, agbno + i, c_ino, (*idp)->ino); + error++; + rval = 0; + } + } + return rval; +} + +static void +check_linkcounts( + xfs_agnumber_t agno) +{ + inodata_t *ep; + inodata_t **ht; + int idx; + char *path; + + ht = inodata[agno]; + for (idx = 0; idx < inodata_hash_size; ht++, idx++) { + ep = *ht; + while (ep) { + if (ep->link_set != ep->link_add || ep->link_set == 0) { + path = inode_name(ep->ino, NULL); + if (!path && ep->link_add) + path = xstrdup("?"); + if (!sflag || ep->ilist) { + if (ep->link_add) + dbprintf("link count mismatch " + "for inode %lld (name " + "%s), nlink %d, " + "counted %d\n", + ep->ino, path, + ep->link_set, + ep->link_add); + else if (ep->link_set) + dbprintf("disconnected inode " + "%lld, nlink %d\n", + ep->ino, ep->link_set); + else + dbprintf("allocated inode %lld " + "has 0 link count\n", + ep->ino); + } + if (path) + xfree(path); + error++; + } else if (verbose || ep->ilist) { + path = inode_name(ep->ino, NULL); + if (path) { + dbprintf("inode %lld name %s\n", + ep->ino, path); + xfree(path); + } + } + ep = ep->next; + } + } + +} + +static int +check_range( + xfs_agnumber_t agno, + xfs_agblock_t agbno, + xfs_extlen_t len) +{ + xfs_extlen_t i; + + if (agno >= mp->m_sb.sb_agcount || + agbno + len - 1 >= mp->m_sb.sb_agblocks) { + for (i = 0; i < len; i++) { + if (!sflag || CHECK_BLISTA(agno, agbno + i)) + dbprintf("block %u/%u out of range\n", + agno, agbno + i); + } + error++; + return 0; + } + return 1; +} + +static void +check_rdbmap( + xfs_drfsbno_t bno, + xfs_extlen_t len, + dbm_t type) +{ + xfs_extlen_t i; + char *p; + + for (i = 0, p = &dbmap[mp->m_sb.sb_agcount][bno]; i < len; i++, p++) { + if ((dbm_t)*p != type) { + if (!sflag || CHECK_BLIST(bno + i)) + dbprintf("rtblock %llu expected type %s got " + "%s\n", + bno + i, typename[type], + typename[(dbm_t)*p]); + error++; + } + } +} + +static int +check_rinomap( + xfs_drfsbno_t bno, + xfs_extlen_t len, + xfs_ino_t c_ino) +{ + xfs_extlen_t i; + inodata_t **idp; + int rval; + + if (!check_rrange(bno, len)) { + dbprintf("rtblocks %llu..%llu claimed by inode %lld\n", + bno, bno + len - 1, c_ino); + return 0; + } + for (i = 0, rval = 1, idp = &inomap[mp->m_sb.sb_agcount][bno]; + i < len; + i++, idp++) { + if (*idp) { + if (!sflag || (*idp)->ilist || CHECK_BLIST(bno + i)) + dbprintf("rtblock %llu claimed by inode %lld, " + "previous inum %lld\n", + bno + i, c_ino, (*idp)->ino); + error++; + rval = 0; + } + } + return rval; +} + +static void +check_rootdir(void) +{ + inodata_t *id; + + id = find_inode(mp->m_sb.sb_rootino, 0); + if (id == NULL) { + if (!sflag) + dbprintf("root inode %lld is missing\n", + mp->m_sb.sb_rootino); + error++; + } else if (!id->isdir) { + if (!sflag || id->ilist) + dbprintf("root inode %lld is not a directory\n", + mp->m_sb.sb_rootino); + error++; + } +} + +static int +check_rrange( + xfs_drfsbno_t bno, + xfs_extlen_t len) +{ + xfs_extlen_t i; + + if (bno + len - 1 >= mp->m_sb.sb_rblocks) { + for (i = 0; i < len; i++) { + if (!sflag || CHECK_BLIST(bno + i)) + dbprintf("rtblock %llu out of range\n", + bno + i); + } + error++; + return 0; + } + return 1; +} + +static void +check_set_dbmap( + xfs_agnumber_t agno, + xfs_agblock_t agbno, + xfs_extlen_t len, + dbm_t type1, + dbm_t type2, + xfs_agnumber_t c_agno, + xfs_agblock_t c_agbno) +{ + xfs_extlen_t i; + int mayprint; + char *p; + + if (!check_range(agno, agbno, len)) { + dbprintf("blocks %u/%u..%u claimed by block %u/%u\n", agno, + agbno, agbno + len - 1, c_agno, c_agbno); + return; + } + check_dbmap(agno, agbno, len, type1); + mayprint = verbose | blist_size; + for (i = 0, p = &dbmap[agno][agbno]; i < len; i++, p++) { + *p = (char)type2; + if (mayprint && (verbose || CHECK_BLISTA(agno, agbno + i))) + dbprintf("setting block %u/%u to %s\n", agno, agbno + i, + typename[type2]); + } +} + +static void +check_set_rdbmap( + xfs_drfsbno_t bno, + xfs_extlen_t len, + dbm_t type1, + dbm_t type2) +{ + xfs_extlen_t i; + int mayprint; + char *p; + + if (!check_rrange(bno, len)) + return; + check_rdbmap(bno, len, type1); + mayprint = verbose | blist_size; + for (i = 0, p = &dbmap[mp->m_sb.sb_agcount][bno]; i < len; i++, p++) { + *p = (char)type2; + if (mayprint && (verbose || CHECK_BLIST(bno + i))) + dbprintf("setting rtblock %llu to %s\n", + bno + i, typename[type2]); + } +} + +static void +check_summary(void) +{ + xfs_drfsbno_t bno; + xfs_suminfo_t *csp; + xfs_suminfo_t *fsp; + int log; + + csp = sumcompute; + fsp = sumfile; + for (log = 0; log < mp->m_rsumlevels; log++) { + for (bno = 0; + bno < mp->m_sb.sb_rbmblocks; + bno++, csp++, fsp++) { + if (*csp != *fsp) { + if (!sflag) + dbprintf("rt summary mismatch, size %d " + "block %llu, file: %d, " + "computed: %d\n", + log, bno, *fsp, *csp); + error++; + } + } + } +} + +static void +checknot_dbmap( + xfs_agnumber_t agno, + xfs_agblock_t agbno, + xfs_extlen_t len, + int typemask) +{ + xfs_extlen_t i; + char *p; + + if (!check_range(agno, agbno, len)) + return; + for (i = 0, p = &dbmap[agno][agbno]; i < len; i++, p++) { + if ((1 << *p) & typemask) { + if (!sflag || CHECK_BLISTA(agno, agbno + i)) + dbprintf("block %u/%u type %s not expected\n", + agno, agbno + i, typename[(dbm_t)*p]); + error++; + } + } +} + +static void +checknot_rdbmap( + xfs_drfsbno_t bno, + xfs_extlen_t len, + int typemask) +{ + xfs_extlen_t i; + char *p; + + if (!check_rrange(bno, len)) + return; + for (i = 0, p = &dbmap[mp->m_sb.sb_agcount][bno]; i < len; i++, p++) { + if ((1 << *p) & typemask) { + if (!sflag || CHECK_BLIST(bno + i)) + dbprintf("rtblock %llu type %s not expected\n", + bno + i, typename[(dbm_t)*p]); + error++; + } + } +} + +static void +dir_hash_add( + xfs_dahash_t hash, + xfs_dir2_dataptr_t addr) +{ + int i; + dirhash_t *p; + + i = DIR_HASH_FUNC(hash, addr); + p = malloc(sizeof(*p)); + p->next = dirhash[i]; + dirhash[i] = p; + p->entry.hashval = hash; + p->entry.address = addr; + p->seen = 0; +} + +static void +dir_hash_check( + inodata_t *id, + int v) +{ + int i; + dirhash_t *p; + + for (i = 0; i < DIR_HASH_SIZE; i++) { + for (p = dirhash[i]; p; p = p->next) { + if (p->seen) + continue; + if (!sflag || id->ilist || v) + dbprintf("dir ino %lld missing leaf entry for " + "%x/%x\n", + id->ino, p->entry.hashval, + p->entry.address); + error++; + } + } +} + +static void +dir_hash_done(void) +{ + int i; + dirhash_t *n; + dirhash_t *p; + + for (i = 0; i < DIR_HASH_SIZE; i++) { + for (p = dirhash[i]; p; p = n) { + n = p->next; + free(p); + } + dirhash[i] = NULL; + } +} + +static void +dir_hash_init(void) +{ + if (!dirhash) + dirhash = calloc(DIR_HASH_SIZE, sizeof(*dirhash)); +} + +static int +dir_hash_see( + xfs_dahash_t hash, + xfs_dir2_dataptr_t addr) +{ + int i; + dirhash_t *p; + + i = DIR_HASH_FUNC(hash, addr); + for (p = dirhash[i]; p; p = p->next) { + if (p->entry.hashval == hash && p->entry.address == addr) { + if (p->seen) + return 1; + p->seen = 1; + return 0; + } + } + return -1; +} + +static inodata_t * +find_inode( + xfs_ino_t ino, + int add) +{ + xfs_agino_t agino; + xfs_agnumber_t agno; + inodata_t *ent; + inodata_t **htab; + xfs_agino_t ih; + + agno = XFS_INO_TO_AGNO(mp, ino); + agino = XFS_INO_TO_AGINO(mp, ino); + if (agno >= mp->m_sb.sb_agcount || + XFS_AGINO_TO_INO(mp, agno, agino) != ino) + return NULL; + htab = inodata[agno]; + ih = agino % inodata_hash_size; + ent = htab[ih]; + while (ent) { + if (ent->ino == ino) + return ent; + ent = ent->next; + } + if (!add) + return NULL; + ent = xcalloc(1, sizeof(*ent)); + ent->ino = ino; + ent->next = htab[ih]; + htab[ih] = ent; + return ent; +} + +static void +free_inodata( + xfs_agnumber_t agno) +{ + inodata_t *hp; + inodata_t **ht; + int i; + inodata_t *next; + + ht = inodata[agno]; + for (i = 0; i < inodata_hash_size; i++) { + hp = ht[i]; + while (hp) { + next = hp->next; + if (hp->name) + xfree(hp->name); + xfree(hp); + hp = next; + } + } + xfree(ht); +} + +static int +init( + int argc, + char **argv) +{ + xfs_fsblock_t bno; + int c; + xfs_ino_t ino; + int rt; + + if (mp->m_sb.sb_magicnum != XFS_SB_MAGIC) { + dbprintf("bad superblock magic number %x, giving up\n", + mp->m_sb.sb_magicnum); + return 0; + } + rt = mp->m_sb.sb_rextents != 0; + dbmap = xmalloc((mp->m_sb.sb_agcount + rt) * sizeof(*dbmap)); + inomap = xmalloc((mp->m_sb.sb_agcount + rt) * sizeof(*inomap)); + inodata = xmalloc(mp->m_sb.sb_agcount * sizeof(*inodata)); + inodata_hash_size = + (int)MAX(MIN(mp->m_sb.sb_icount / + (INODATA_AVG_HASH_LENGTH * mp->m_sb.sb_agcount), + MAX_INODATA_HASH_SIZE), + MIN_INODATA_HASH_SIZE); + for (c = 0; c < mp->m_sb.sb_agcount; c++) { + dbmap[c] = xcalloc(mp->m_sb.sb_agblocks, sizeof(**dbmap)); + inomap[c] = xcalloc(mp->m_sb.sb_agblocks, sizeof(**inomap)); + inodata[c] = xcalloc(inodata_hash_size, sizeof(**inodata)); + } + if (rt) { + dbmap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**dbmap)); + inomap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**inomap)); + sumfile = xcalloc(mp->m_rsumsize, 1); + sumcompute = xcalloc(mp->m_rsumsize, 1); + } + nflag = sflag = verbose = optind = 0; + while ((c = getopt(argc, argv, "b:i:npsv")) != EOF) { + switch (c) { + case 'b': + bno = atoll(optarg); + add_blist(bno); + break; + case 'i': + ino = atoll(optarg); + add_ilist(ino); + break; + case 'n': + nflag = 1; + break; + case 'p': + pflag = 1; + break; + case 's': + sflag = 1; + break; + case 'v': + verbose = 1; + break; + default: + dbprintf("bad option for blockget command\n"); + return 0; + } + } + error = sbver_err = serious_error = 0; + fdblocks = frextents = icount = ifree = 0; + sbversion = XFS_SB_VERSION_4; + if (mp->m_sb.sb_inoalignmt) + sbversion |= XFS_SB_VERSION_ALIGNBIT; + if ((mp->m_sb.sb_uquotino && mp->m_sb.sb_uquotino != NULLFSINO) || + (mp->m_sb.sb_gquotino && mp->m_sb.sb_gquotino != NULLFSINO)) + sbversion |= XFS_SB_VERSION_QUOTABIT; + quota_init(); + return 1; +} + +static char * +inode_name( + xfs_ino_t ino, + inodata_t **ipp) +{ + inodata_t *id; + char *npath; + char *path; + + id = find_inode(ino, 0); + if (ipp) + *ipp = id; + if (id == NULL) + return NULL; + if (id->name == NULL) + return NULL; + path = xstrdup(id->name); + while (id->parent) { + id = id->parent; + if (id->name == NULL) + break; + npath = prepend_path(path, id->name); + xfree(path); + path = npath; + } + return path; +} + +static int +ncheck_f( + int argc, + char **argv) +{ + xfs_agnumber_t agno; + int c; + inodata_t *hp; + inodata_t **ht; + int i; + inodata_t *id; + xfs_ino_t *ilist; + int ilist_size; + xfs_ino_t *ilp; + xfs_ino_t ino; + char *p; + int security; + + if (!inodata || !nflag) { + dbprintf("must run blockget -n first\n"); + return 0; + } + security = optind = ilist_size = 0; + ilist = NULL; + while ((c = getopt(argc, argv, "i:s")) != EOF) { + switch (c) { + case 'i': + ino = atoll(optarg); + ilist = xrealloc(ilist, (ilist_size + 1) * + sizeof(*ilist)); + ilist[ilist_size++] = ino; + break; + case 's': + security = 1; + break; + default: + dbprintf("bad option -%c for ncheck command\n", c); + return 0; + } + } + if (ilist) { + for (ilp = ilist; ilp < &ilist[ilist_size]; ilp++) { + ino = *ilp; + if ((p = inode_name(ino, &hp))) { + dbprintf("%11llu %s", ino, p); + if (hp->isdir) + dbprintf("/."); + dbprintf("\n"); + xfree(p); + } + } + xfree(ilist); + return 0; + } + for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { + ht = inodata[agno]; + for (i = 0; i < inodata_hash_size; i++) { + hp = ht[i]; + for (hp = ht[i]; hp; hp = hp->next) { + ino = XFS_AGINO_TO_INO(mp, agno, hp->ino); + p = inode_name(ino, &id); + if (!p || !id) + continue; + if (!security || id->security) { + dbprintf("%11llu %s", ino, p); + if (hp->isdir) + dbprintf("/."); + dbprintf("\n"); + } + xfree(p); + } + } + } + return 0; +} + +static char * +prepend_path( + char *oldpath, + char *parent) +{ + int len; + char *path; + + len = (int)(strlen(oldpath) + strlen(parent) + 2); + path = xmalloc(len); + sprintf(path, "%s/%s", parent, oldpath); + return path; +} + +static xfs_ino_t +process_block_dir_v2( + blkmap_t *blkmap, + int *dot, + int *dotdot, + inodata_t *id) +{ + xfs_fsblock_t b; + bbmap_t bbmap; + bmap_ext_t *bmp; + int nex; + xfs_ino_t parent; + int v; + int x; + + nex = blkmap_getn(blkmap, 0, mp->m_dirblkfsbs, &bmp); + v = id->ilist || verbose; + if (nex == 0) { + if (!sflag || v) + dbprintf("block 0 for directory inode %lld is " + "missing\n", + id->ino); + error++; + return 0; + } + push_cur(); + if (nex > 1) + make_bbmap(&bbmap, nex, bmp); + set_cur(&typtab[TYP_DIR], XFS_FSB_TO_DADDR(mp, bmp->startblock), + mp->m_dirblkfsbs * blkbb, DB_RING_IGN, nex > 1 ? &bbmap : NULL); + for (x = 0; !v && x < nex; x++) { + for (b = bmp[x].startblock; + !v && b < bmp[x].startblock + bmp[x].blockcount; + b++) + v = CHECK_BLIST(b); + } + free(bmp); + if (iocur_top->data == NULL) { + if (!sflag || id->ilist || v) + dbprintf("can't read block 0 for directory inode " + "%lld\n", + id->ino); + error++; + return 0; + } + dir_hash_init(); + parent = process_data_dir_v2(dot, dotdot, id, v, mp->m_dirdatablk, + NULL); + dir_hash_check(id, v); + dir_hash_done(); + pop_cur(); + return parent; +} + +static void +process_bmbt_reclist( + xfs_bmbt_rec_32_t *rp, + int numrecs, + dbm_t type, + inodata_t *id, + xfs_drfsbno_t *tot, + blkmap_t **blkmapp) +{ + xfs_agblock_t agbno; + xfs_agnumber_t agno; + xfs_fsblock_t b; + xfs_dfilblks_t c; + xfs_dfilblks_t cp; + int f; + int i; + xfs_agblock_t iagbno; + xfs_agnumber_t iagno; + xfs_dfiloff_t o; + xfs_dfiloff_t op; + xfs_dfsbno_t s; + int v; + + cp = op = 0; + v = verbose || id->ilist; + iagno = XFS_INO_TO_AGNO(mp, id->ino); + iagbno = XFS_INO_TO_AGBNO(mp, id->ino); + for (i = 0; i < numrecs; i++, rp++) { + convert_extent((xfs_bmbt_rec_64_t *)rp, &o, &s, &c, &f); + if (v) + dbprintf("inode %lld extent [%lld,%lld,%lld,%d]\n", + id->ino, o, s, c, f); + if (!sflag && i > 0 && op + cp > o) + dbprintf("bmap rec out of order, inode %lld entry %d\n", + id->ino, i); + op = o; + cp = c; + if (type == DBM_RTDATA) { + if (!sflag && s >= mp->m_sb.sb_rblocks) { + dbprintf("inode %lld bad rt block number %lld, " + "offset %lld\n", + id->ino, s, o); + continue; + } + } else if (!sflag) { + agno = XFS_FSB_TO_AGNO(mp, s); + agbno = XFS_FSB_TO_AGBNO(mp, s); + if (agno >= mp->m_sb.sb_agcount || + agbno >= mp->m_sb.sb_agblocks) { + dbprintf("inode %lld bad block number %lld " + "[%d,%d], offset %lld\n", + id->ino, s, agno, agbno, o); + continue; + } + if (agbno + c - 1 >= mp->m_sb.sb_agblocks) { + dbprintf("inode %lld bad block number %lld " + "[%d,%d], offset %lld\n", + id->ino, s + c - 1, agno, + agbno + (xfs_agblock_t)c - 1, o); + continue; + } + } + if (blkmapp && *blkmapp) + blkmap_set_ext(blkmapp, (xfs_fileoff_t)o, + (xfs_fsblock_t)s, (xfs_extlen_t)c); + if (type == DBM_RTDATA) { + set_rdbmap((xfs_fsblock_t)s, (xfs_extlen_t)c, + DBM_RTDATA); + set_rinomap((xfs_fsblock_t)s, (xfs_extlen_t)c, id); + for (b = (xfs_fsblock_t)s; + blist_size && b < s + c; + b++, o++) { + if (CHECK_BLIST(b)) + dbprintf("inode %lld block %lld at " + "offset %lld\n", + id->ino, (xfs_dfsbno_t)b, o); + } + } else { + agno = XFS_FSB_TO_AGNO(mp, (xfs_fsblock_t)s); + agbno = XFS_FSB_TO_AGBNO(mp, (xfs_fsblock_t)s); + set_dbmap(agno, agbno, (xfs_extlen_t)c, type, iagno, + iagbno); + set_inomap(agno, agbno, (xfs_extlen_t)c, id); + for (b = (xfs_fsblock_t)s; + blist_size && b < s + c; + b++, o++, agbno++) { + if (CHECK_BLIST(b)) + dbprintf("inode %lld block %lld at " + "offset %lld\n", + id->ino, (xfs_dfsbno_t)b, o); + } + } + *tot += c; + } +} + +static void +process_btinode( + inodata_t *id, + xfs_dinode_t *dip, + dbm_t type, + xfs_drfsbno_t *totd, + xfs_drfsbno_t *toti, + xfs_extnum_t *nex, + blkmap_t **blkmapp, + int whichfork) +{ + xfs_bmdr_block_t *dib; + int i; + xfs_bmbt_ptr_t *pp; + xfs_bmbt_rec_32_t *rp; + + dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_NOCONVERT); + if (INT_GET(dib->bb_level, ARCH_CONVERT) >= XFS_BM_MAXLEVELS(mp, whichfork)) { + if (!sflag || id->ilist) + dbprintf("level for ino %lld %s fork bmap root too " + "large (%u)\n", + id->ino, + whichfork == XFS_DATA_FORK ? "data" : "attr", + INT_GET(dib->bb_level, ARCH_CONVERT)); + error++; + return; + } + if (INT_GET(dib->bb_numrecs, ARCH_CONVERT) > + XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_NOCONVERT), + xfs_bmdr, INT_GET(dib->bb_level, ARCH_CONVERT) == 0)) { + if (!sflag || id->ilist) + dbprintf("numrecs for ino %lld %s fork bmap root too " + "large (%u)\n", + id->ino, + whichfork == XFS_DATA_FORK ? "data" : "attr", + INT_GET(dib->bb_numrecs, ARCH_CONVERT)); + error++; + return; + } + if (INT_GET(dib->bb_level, ARCH_CONVERT) == 0) { + rp = (xfs_bmbt_rec_32_t *)XFS_BTREE_REC_ADDR( + XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_NOCONVERT), + xfs_bmdr, dib, 1, + XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_SIZE(dip, mp, + whichfork), + xfs_bmdr, 1)); + process_bmbt_reclist(rp, INT_GET(dib->bb_numrecs, ARCH_CONVERT), type, id, totd, + blkmapp); + *nex += INT_GET(dib->bb_numrecs, ARCH_CONVERT); + return; + } else { + pp = XFS_BTREE_PTR_ADDR(XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_NOCONVERT), + xfs_bmdr, dib, 1, + XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_SIZE(dip, mp, + whichfork), + xfs_bmdr, 0)); + for (i = 0; i < INT_GET(dib->bb_numrecs, ARCH_CONVERT); i++) + scan_lbtree((xfs_fsblock_t)INT_GET(pp[i], ARCH_CONVERT), INT_GET(dib->bb_level, ARCH_CONVERT), + scanfunc_bmap, type, id, totd, toti, nex, + blkmapp, 1, + whichfork == XFS_DATA_FORK ? + TYP_BMAPBTD : TYP_BMAPBTA); + } + if (*nex <= + XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_NOCONVERT) / sizeof(xfs_bmbt_rec_t)) { + if (!sflag || id->ilist) + dbprintf("extent count for ino %lld %s fork too low " + "(%d) for file format\n", + id->ino, + whichfork == XFS_DATA_FORK ? "data" : "attr", + *nex); + error++; + } +} + +static xfs_ino_t +process_data_dir_v2( + int *dot, + int *dotdot, + inodata_t *id, + int v, + xfs_dablk_t dabno, + freetab_t **freetabp) +{ + xfs_dir2_dataptr_t addr; + xfs_dir2_data_free_t *bf; + int bf_err; + xfs_dir2_block_t *block; + xfs_dir2_block_tail_t *btp = NULL; + inodata_t *cid; + int count; + xfs_dir2_data_t *data; + xfs_dir2_db_t db; + xfs_dir2_data_entry_t *dep; + xfs_dir2_data_free_t *dfp; + xfs_dir2_data_unused_t *dup; + char *endptr; + int freeseen; + freetab_t *freetab; + xfs_dahash_t hash; + int i; + int lastfree; + int lastfree_err; + xfs_dir2_leaf_entry_t *lep = NULL; + xfs_ino_t lino; + xfs_ino_t parent = 0; + char *ptr; + int stale = 0; + int tag_err; + xfs_dir2_data_off_t *tagp; + + data = iocur_top->data; + block = iocur_top->data; + if (INT_GET(block->hdr.magic, ARCH_CONVERT) != XFS_DIR2_BLOCK_MAGIC && + INT_GET(data->hdr.magic, ARCH_CONVERT) != XFS_DIR2_DATA_MAGIC) { + if (!sflag || v) + dbprintf("bad directory data magic # %#x for dir ino " + "%lld block %d\n", + INT_GET(data->hdr.magic, ARCH_CONVERT), id->ino, dabno); + error++; + return NULLFSINO; + } + db = XFS_DIR2_DA_TO_DB(mp, dabno); + bf = data->hdr.bestfree; + ptr = (char *)data->u; + if (INT_GET(block->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + lep = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + endptr = (char *)lep; + if (endptr <= ptr || endptr > (char *)btp) { + endptr = (char *)data + mp->m_dirblksize; + lep = NULL; + if (!sflag || v) + dbprintf("bad block directory tail for dir ino " + "%lld\n", + id->ino); + error++; + } + } else + endptr = (char *)data + mp->m_dirblksize; + bf_err = lastfree_err = tag_err = 0; + count = lastfree = freeseen = 0; + if (INT_GET(bf[0].length, ARCH_CONVERT) == 0) { + bf_err += INT_GET(bf[0].offset, ARCH_CONVERT) != 0; + freeseen |= 1 << 0; + } + if (INT_GET(bf[1].length, ARCH_CONVERT) == 0) { + bf_err += INT_GET(bf[1].offset, ARCH_CONVERT) != 0; + freeseen |= 1 << 1; + } + if (INT_GET(bf[2].length, ARCH_CONVERT) == 0) { + bf_err += INT_GET(bf[2].offset, ARCH_CONVERT) != 0; + freeseen |= 1 << 2; + } + bf_err += INT_GET(bf[0].length, ARCH_CONVERT) < INT_GET(bf[1].length, ARCH_CONVERT); + bf_err += INT_GET(bf[1].length, ARCH_CONVERT) < INT_GET(bf[2].length, ARCH_CONVERT); + if (freetabp) { + freetab = *freetabp; + if (freetab->naents <= db) { + *freetabp = freetab = + realloc(freetab, FREETAB_SIZE(db + 1)); + for (i = freetab->naents; i < db; i++) + freetab->ents[i] = NULLDATAOFF; + freetab->naents = db + 1; + } + if (freetab->nents < db + 1) + freetab->nents = db + 1; + freetab->ents[db] = INT_GET(bf[0].length, ARCH_CONVERT); + } + while (ptr < endptr) { + dup = (xfs_dir2_data_unused_t *)ptr; + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + lastfree_err += lastfree != 0; + if ((INT_GET(dup->length, ARCH_CONVERT) & (XFS_DIR2_DATA_ALIGN - 1)) || + INT_GET(dup->length, ARCH_CONVERT) == 0 || + (char *)(tagp = XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT)) >= + endptr) { + if (!sflag || v) + dbprintf("dir %lld block %d bad free " + "entry at %d\n", + id->ino, dabno, + (int)((char *)dup - + (char *)data)); + error++; + break; + } + tag_err += INT_GET(*tagp, ARCH_CONVERT) != (char *)dup - (char *)data; + dfp = process_data_dir_v2_freefind(data, dup); + if (dfp) { + i = (int)(dfp - bf); + bf_err += (freeseen & (1 << i)) != 0; + freeseen |= 1 << i; + } else + bf_err += INT_GET(dup->length, ARCH_CONVERT) > INT_GET(bf[2].length, ARCH_CONVERT); + ptr += INT_GET(dup->length, ARCH_CONVERT); + lastfree = 1; + continue; + } + dep = (xfs_dir2_data_entry_t *)dup; + if (dep->namelen == 0) { + if (!sflag || v) + dbprintf("dir %lld block %d zero length entry " + "at %d\n", + id->ino, dabno, + (int)((char *)dep - (char *)data)); + error++; + } + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + if ((char *)tagp >= endptr) { + if (!sflag || v) + dbprintf("dir %lld block %d bad entry at %d\n", + id->ino, dabno, + (int)((char *)dep - (char *)data)); + error++; + break; + } + tag_err += INT_GET(*tagp, ARCH_CONVERT) != (char *)dep - (char *)data; + addr = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, db, + (char *)dep - (char *)data); + hash = libxfs_da_hashname((char *)dep->name, dep->namelen); + dir_hash_add(hash, addr); + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + count++; + lastfree = 0; + lino = INT_GET(dep->inumber, ARCH_CONVERT); + cid = find_inode(lino, 1); + if (v) + dbprintf("dir %lld block %d entry %*.*s %lld\n", + id->ino, dabno, dep->namelen, dep->namelen, + dep->name, lino); + if (cid) + addlink_inode(cid); + else { + if (!sflag || v) + dbprintf("dir %lld block %d entry %*.*s bad " + "inode number %lld\n", + id->ino, dabno, dep->namelen, + dep->namelen, dep->name, lino); + error++; + } + if (dep->namelen == 2 && dep->name[0] == '.' && + dep->name[1] == '.') { + if (parent) { + if (!sflag || v) + dbprintf("multiple .. entries in dir " + "%lld (%lld, %lld)\n", + id->ino, parent, lino); + error++; + } else + parent = cid ? lino : NULLFSINO; + (*dotdot)++; + } else if (dep->namelen != 1 || dep->name[0] != '.') { + if (cid != NULL) { + if (!cid->parent) + cid->parent = id; + addname_inode(cid, (char *)dep->name, + dep->namelen); + } + } else { + if (lino != id->ino) { + if (!sflag || v) + dbprintf("dir %lld entry . inode " + "number mismatch (%lld)\n", + id->ino, lino); + error++; + } + (*dot)++; + } + } + if (INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + endptr = (char *)data + mp->m_dirblksize; + for (i = stale = 0; lep && i < INT_GET(btp->count, ARCH_CONVERT); i++) { + if ((char *)&lep[i] >= endptr) { + if (!sflag || v) + dbprintf("dir %lld block %d bad count " + "%u\n", + id->ino, dabno, INT_GET(btp->count, ARCH_CONVERT)); + error++; + break; + } + if (INT_GET(lep[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + stale++; + else if (dir_hash_see(INT_GET(lep[i].hashval, ARCH_CONVERT), INT_GET(lep[i].address, ARCH_CONVERT))) { + if (!sflag || v) + dbprintf("dir %lld block %d extra leaf " + "entry %x %x\n", + id->ino, dabno, INT_GET(lep[i].hashval, ARCH_CONVERT), + INT_GET(lep[i].address, ARCH_CONVERT)); + error++; + } + } + } + bf_err += freeseen != 7; + if (bf_err) { + if (!sflag || v) + dbprintf("dir %lld block %d bad bestfree data\n", + id->ino, dabno); + error++; + } + if (INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC && + count != INT_GET(btp->count, ARCH_CONVERT) - INT_GET(btp->stale, ARCH_CONVERT)) { + if (!sflag || v) + dbprintf("dir %lld block %d bad block tail count %d " + "(stale %d)\n", + id->ino, dabno, INT_GET(btp->count, ARCH_CONVERT), INT_GET(btp->stale, ARCH_CONVERT)); + error++; + } + if (INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC && stale != INT_GET(btp->stale, ARCH_CONVERT)) { + if (!sflag || v) + dbprintf("dir %lld block %d bad stale tail count %d\n", + id->ino, dabno, INT_GET(btp->stale, ARCH_CONVERT)); + error++; + } + if (lastfree_err) { + if (!sflag || v) + dbprintf("dir %lld block %d consecutive free entries\n", + id->ino, dabno); + error++; + } + if (tag_err) { + if (!sflag || v) + dbprintf("dir %lld block %d entry/unused tag " + "mismatch\n", + id->ino, dabno); + error++; + } + return parent; +} + +static xfs_dir2_data_free_t * +process_data_dir_v2_freefind( + xfs_dir2_data_t *data, + xfs_dir2_data_unused_t *dup) +{ + xfs_dir2_data_free_t *dfp; + xfs_dir2_data_aoff_t off; + + off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)data); + if (INT_GET(dup->length, ARCH_CONVERT) < INT_GET(data->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT - 1].length, ARCH_CONVERT)) + return NULL; + for (dfp = &data->hdr.bestfree[0]; + dfp < &data->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT]; + dfp++) { + if (INT_GET(dfp->offset, ARCH_CONVERT) == 0) + return NULL; + if (INT_GET(dfp->offset, ARCH_CONVERT) == off) + return dfp; + } + return NULL; +} + +static void +process_dir( + xfs_dinode_t *dip, + blkmap_t *blkmap, + inodata_t *id) +{ + xfs_fsblock_t bno; + int dot; + int dotdot; + xfs_ino_t parent; + + dot = dotdot = 0; + if (XFS_DIR_IS_V2(mp)) { + if (process_dir_v2(dip, blkmap, &dot, &dotdot, id, &parent)) + return; + } else + { + if (process_dir_v1(dip, blkmap, &dot, &dotdot, id, &parent)) + return; + } + bno = XFS_INO_TO_FSB(mp, id->ino); + if (dot == 0) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("no . entry for directory %lld\n", id->ino); + error++; + } + if (dotdot == 0) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("no .. entry for directory %lld\n", id->ino); + error++; + } else if (parent == id->ino && id->ino != mp->m_sb.sb_rootino) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf(". and .. same for non-root directory %lld\n", + id->ino); + error++; + } else if (id->ino == mp->m_sb.sb_rootino && id->ino != parent) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("root directory %lld has .. %lld\n", id->ino, + parent); + error++; + } else if (parent != NULLFSINO && id->ino != parent) + addparent_inode(id, parent); +} + +static int +process_dir_v1( + xfs_dinode_t *dip, + blkmap_t *blkmap, + int *dot, + int *dotdot, + inodata_t *id, + xfs_ino_t *parent) +{ + if (dip->di_core.di_size <= XFS_DFORK_DSIZE_ARCH(dip, mp, ARCH_NOCONVERT) && + dip->di_core.di_format == XFS_DINODE_FMT_LOCAL) + *parent = + process_shortform_dir_v1(dip, dot, dotdot, id); + else if (dip->di_core.di_size == XFS_LBSIZE(mp) && + (dip->di_core.di_format == XFS_DINODE_FMT_EXTENTS || + dip->di_core.di_format == XFS_DINODE_FMT_BTREE)) + *parent = process_leaf_dir_v1(blkmap, dot, dotdot, id); + else if (dip->di_core.di_size >= XFS_LBSIZE(mp) && + (dip->di_core.di_format == XFS_DINODE_FMT_EXTENTS || + dip->di_core.di_format == XFS_DINODE_FMT_BTREE)) + *parent = process_node_dir_v1(blkmap, dot, dotdot, id); + else { + dbprintf("bad size (%lld) or format (%d) for directory inode " + "%lld\n", + dip->di_core.di_size, (int)dip->di_core.di_format, + id->ino); + error++; + return 1; + } + return 0; +} + +static int +process_dir_v2( + xfs_dinode_t *dip, + blkmap_t *blkmap, + int *dot, + int *dotdot, + inodata_t *id, + xfs_ino_t *parent) +{ + xfs_fileoff_t last = 0; + + if (blkmap) + last = blkmap_last_off(blkmap); + if (dip->di_core.di_size <= XFS_DFORK_DSIZE_ARCH(dip, mp, ARCH_NOCONVERT) && + dip->di_core.di_format == XFS_DINODE_FMT_LOCAL) + *parent = process_sf_dir_v2(dip, dot, dotdot, id); + else if (last == mp->m_dirblkfsbs && + (dip->di_core.di_format == XFS_DINODE_FMT_EXTENTS || + dip->di_core.di_format == XFS_DINODE_FMT_BTREE)) + *parent = process_block_dir_v2(blkmap, dot, dotdot, id); + else if (last >= mp->m_dirleafblk + mp->m_dirblkfsbs && + (dip->di_core.di_format == XFS_DINODE_FMT_EXTENTS || + dip->di_core.di_format == XFS_DINODE_FMT_BTREE)) + *parent = process_leaf_node_dir_v2(blkmap, dot, dotdot, id, + dip->di_core.di_size); + else { + dbprintf("bad size (%lld) or format (%d) for directory inode " + "%lld\n", + dip->di_core.di_size, (int)dip->di_core.di_format, + id->ino); + error++; + return 1; + } + return 0; +} + +/* ARGSUSED */ +static void +process_exinode( + inodata_t *id, + xfs_dinode_t *dip, + dbm_t type, + xfs_drfsbno_t *totd, + xfs_drfsbno_t *toti, + xfs_extnum_t *nex, + blkmap_t **blkmapp, + int whichfork) +{ + xfs_bmbt_rec_32_t *rp; + + rp = (xfs_bmbt_rec_32_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_NOCONVERT); + *nex = XFS_DFORK_NEXTENTS_ARCH(dip, whichfork, ARCH_NOCONVERT); + if (*nex < 0 || + *nex > + XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_NOCONVERT) / sizeof(xfs_bmbt_rec_32_t)) { + if (!sflag || id->ilist) + dbprintf("bad number of extents %d for inode %lld\n", + *nex, id->ino); + error++; + return; + } + process_bmbt_reclist(rp, *nex, type, id, totd, blkmapp); +} + +static void +process_inode( + xfs_agf_t *agf, + xfs_agino_t agino, + xfs_dinode_t *dip, + int isfree) +{ + blkmap_t *blkmap; + xfs_fsblock_t bno = 0; + xfs_dinode_core_t tdic; + xfs_dinode_core_t *dic; + inodata_t *id = NULL; + xfs_ino_t ino; + xfs_extnum_t nextents = 0; + int nlink; + int security; + xfs_drfsbno_t totblocks; + xfs_drfsbno_t totdblocks = 0; + xfs_drfsbno_t totiblocks = 0; + dbm_t type; + xfs_extnum_t anextents = 0; + xfs_drfsbno_t atotdblocks = 0; + xfs_drfsbno_t atotiblocks = 0; + xfs_qcnt_t bc = 0; + xfs_qcnt_t ic = 0; + xfs_qcnt_t rc = 0; + static char okfmts[] = { + 0, /* type 0 unused */ + 1 << XFS_DINODE_FMT_DEV, /* FIFO */ + 1 << XFS_DINODE_FMT_DEV, /* CHR */ + 0, /* type 3 unused */ + (1 << XFS_DINODE_FMT_LOCAL) | + (1 << XFS_DINODE_FMT_EXTENTS) | + (1 << XFS_DINODE_FMT_BTREE), /* DIR */ + 0, /* type 5 unused */ + 1 << XFS_DINODE_FMT_DEV, /* BLK */ + 0, /* type 7 unused */ + (1 << XFS_DINODE_FMT_EXTENTS) | + (1 << XFS_DINODE_FMT_BTREE), /* REG */ + 0, /* type 9 unused */ + (1 << XFS_DINODE_FMT_LOCAL) | + (1 << XFS_DINODE_FMT_EXTENTS), /* LNK */ + 0, /* type 11 unused */ + 1 << XFS_DINODE_FMT_DEV, /* SOCK */ + 0, /* type 13 unused */ + 1 << XFS_DINODE_FMT_UUID, /* MNT */ + 0 /* type 15 unused */ + }; + static char *fmtnames[] = { + "dev", "local", "extents", "btree", "uuid" + }; + + /* convert the core, then copy it back into the inode */ + libxfs_xlate_dinode_core((xfs_caddr_t)&dip->di_core, &tdic, 1, + ARCH_CONVERT); + memcpy(&dip->di_core, &tdic, sizeof(xfs_dinode_core_t)); + dic=&dip->di_core; + + ino = XFS_AGINO_TO_INO(mp, INT_GET(agf->agf_seqno, ARCH_CONVERT), agino); + if (!isfree) { + id = find_inode(ino, 1); + bno = XFS_INO_TO_FSB(mp, ino); + blkmap = NULL; + } + if (dic->di_magic != XFS_DINODE_MAGIC) { + if (!sflag || isfree || id->ilist || CHECK_BLIST(bno)) + dbprintf("bad magic number %#x for inode %lld\n", + dic->di_magic, ino); + error++; + return; + } + if (!XFS_DINODE_GOOD_VERSION(dic->di_version)) { + if (!sflag || isfree || id->ilist || CHECK_BLIST(bno)) + dbprintf("bad version number %#x for inode %lld\n", + dic->di_version, ino); + error++; + return; + } + if (isfree) { + if (dic->di_nblocks != 0) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("bad nblocks %lld for free inode " + "%lld\n", + dic->di_nblocks, ino); + error++; + } + if (dic->di_version == XFS_DINODE_VERSION_1) + nlink = dic->di_onlink; + else + nlink = dic->di_nlink; + if (nlink != 0) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("bad nlink %d for free inode %lld\n", + nlink, ino); + error++; + } + if (dic->di_mode != 0) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("bad mode %#o for free inode %lld\n", + dic->di_mode, ino); + error++; + } + return; + } + /* + * di_mode is a 16-bit uint so no need to check the < 0 case + */ + if ((((dic->di_mode & IFMT) >> 12) > 15) || + (!(okfmts[(dic->di_mode & IFMT) >> 12] & (1 << dic->di_format)))) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("bad format %d for inode %lld type %#o\n", + dic->di_format, id->ino, dic->di_mode & IFMT); + error++; + return; + } + if ((unsigned int)XFS_DFORK_ASIZE_ARCH(dip, mp, ARCH_NOCONVERT) >= XFS_LITINO(mp)) { + if (!sflag || id->ilist) + dbprintf("bad fork offset %d for inode %lld\n", + dic->di_forkoff, id->ino); + error++; + return; + } + if ((unsigned int)dic->di_aformat > XFS_DINODE_FMT_BTREE) { + if (!sflag || id->ilist) + dbprintf("bad attribute format %d for inode %lld\n", + dic->di_aformat, id->ino); + error++; + return; + } + if (verbose || id->ilist || CHECK_BLIST(bno)) + dbprintf("inode %lld mode %#o fmt %s " + "afmt %s " + "nex %d anex %d nblk %lld sz %lld%s%s\n", + id->ino, dic->di_mode, fmtnames[dic->di_format], + fmtnames[dic->di_aformat], + dic->di_nextents, + dic->di_anextents, + dic->di_nblocks, dic->di_size, + dic->di_flags & XFS_DIFLAG_REALTIME ? " rt" : "", + dic->di_flags & XFS_DIFLAG_PREALLOC ? " pre" : "" + ); + security = 0; + switch (dic->di_mode & IFMT) { + case IFDIR: + type = DBM_DIR; + if (dic->di_format == XFS_DINODE_FMT_LOCAL) + break; + blkmap = blkmap_alloc(dic->di_nextents); + break; + case IFREG: + if (dic->di_flags & XFS_DIFLAG_REALTIME) + type = DBM_RTDATA; + else if (id->ino == mp->m_sb.sb_rbmino) { + type = DBM_RTBITMAP; + blkmap = blkmap_alloc(dic->di_nextents); + addlink_inode(id); + } else if (id->ino == mp->m_sb.sb_rsumino) { + type = DBM_RTSUM; + blkmap = blkmap_alloc(dic->di_nextents); + addlink_inode(id); + } + else if (id->ino == mp->m_sb.sb_uquotino || + id->ino == mp->m_sb.sb_gquotino) { + type = DBM_QUOTA; + blkmap = blkmap_alloc(dic->di_nextents); + addlink_inode(id); + } + else + type = DBM_DATA; + if (dic->di_mode & (ISUID | ISGID)) + security = 1; + break; + case IFLNK: + type = DBM_SYMLINK; + break; + default: + security = 1; + type = DBM_UNKNOWN; + break; + } + if (dic->di_version == XFS_DINODE_VERSION_1) + setlink_inode(id, dic->di_onlink, type == DBM_DIR, security); + else { + sbversion |= XFS_SB_VERSION_NLINKBIT; + setlink_inode(id, dic->di_nlink, type == DBM_DIR, security); + } + switch (dic->di_format) { + case XFS_DINODE_FMT_LOCAL: + process_lclinode(id, dip, type, &totdblocks, &totiblocks, + &nextents, &blkmap, XFS_DATA_FORK); + break; + case XFS_DINODE_FMT_EXTENTS: + process_exinode(id, dip, type, &totdblocks, &totiblocks, + &nextents, &blkmap, XFS_DATA_FORK); + break; + case XFS_DINODE_FMT_BTREE: + process_btinode(id, dip, type, &totdblocks, &totiblocks, + &nextents, &blkmap, XFS_DATA_FORK); + break; + } + if (XFS_DFORK_Q_ARCH(dip, ARCH_NOCONVERT)) { + sbversion |= XFS_SB_VERSION_ATTRBIT; + switch (dic->di_aformat) { + case XFS_DINODE_FMT_LOCAL: + process_lclinode(id, dip, DBM_ATTR, &atotdblocks, + &atotiblocks, &anextents, NULL, XFS_ATTR_FORK); + break; + case XFS_DINODE_FMT_EXTENTS: + process_exinode(id, dip, DBM_ATTR, &atotdblocks, + &atotiblocks, &anextents, NULL, XFS_ATTR_FORK); + break; + case XFS_DINODE_FMT_BTREE: + process_btinode(id, dip, DBM_ATTR, &atotdblocks, + &atotiblocks, &anextents, NULL, XFS_ATTR_FORK); + break; + } + } + if (qgdo || qudo) { + switch (type) { + case DBM_DATA: + case DBM_DIR: + case DBM_RTBITMAP: + case DBM_RTSUM: + case DBM_SYMLINK: + case DBM_UNKNOWN: + bc = totdblocks + totiblocks + + atotdblocks + atotiblocks; + ic = 1; + break; + case DBM_RTDATA: + bc = totiblocks + atotdblocks + atotiblocks; + rc = totdblocks; + ic = 1; + break; + default: + } + if (ic) + quota_add(dic->di_gid, dic->di_uid, 0, bc, ic, rc); + } + totblocks = totdblocks + totiblocks + atotdblocks + atotiblocks; + if (totblocks != dic->di_nblocks) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("bad nblocks %lld for inode %lld, counted " + "%lld\n", + dic->di_nblocks, id->ino, totblocks); + error++; + } + if (nextents != dic->di_nextents) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("bad nextents %d for inode %lld, counted %d\n", + dic->di_nextents, id->ino, nextents); + error++; + } + if (anextents != dic->di_anextents) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("bad anextents %d for inode %lld, counted " + "%d\n", + dic->di_anextents, id->ino, anextents); + error++; + } + if (type == DBM_DIR) + process_dir(dip, blkmap, id); + else if (type == DBM_RTBITMAP) + process_rtbitmap(blkmap); + else if (type == DBM_RTSUM) + process_rtsummary(blkmap); + /* + * If the CHKD flag is not set, this can legitimately contain garbage; + * xfs_repair may have cleared that bit. + */ + else if (type == DBM_QUOTA) { + if (id->ino == mp->m_sb.sb_uquotino && + (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) && + (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD)) + process_quota(0, id, blkmap); + else if (id->ino == mp->m_sb.sb_gquotino && + (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) && + (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD)) + process_quota(1, id, blkmap); + } + if (blkmap) + blkmap_free(blkmap); +} + +/* ARGSUSED */ +static void +process_lclinode( + inodata_t *id, + xfs_dinode_t *dip, + dbm_t type, + xfs_drfsbno_t *totd, + xfs_drfsbno_t *toti, + xfs_extnum_t *nex, + blkmap_t **blkmapp, + int whichfork) +{ + xfs_attr_shortform_t *asf; + xfs_fsblock_t bno; + xfs_dinode_core_t *dic; + + dic = &dip->di_core; + bno = XFS_INO_TO_FSB(mp, id->ino); + if (whichfork == XFS_DATA_FORK && + dic->di_size > XFS_DFORK_DSIZE_ARCH(dip, mp, ARCH_NOCONVERT)) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("local inode %lld data is too large (size " + "%lld)\n", + id->ino, dic->di_size); + error++; + } + else if (whichfork == XFS_ATTR_FORK) { + asf = (xfs_attr_shortform_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_NOCONVERT); + if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) > XFS_DFORK_ASIZE_ARCH(dip, mp, ARCH_NOCONVERT)) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("local inode %lld attr is too large " + "(size %d)\n", + id->ino, INT_GET(asf->hdr.totsize, ARCH_CONVERT)); + error++; + } + } +} + +static xfs_ino_t +process_leaf_dir_v1( + blkmap_t *blkmap, + int *dot, + int *dotdot, + inodata_t *id) +{ + xfs_fsblock_t bno; + xfs_ino_t parent; + + bno = blkmap_get(blkmap, 0); + if (bno == NULLFSBLOCK) { + if (!sflag || id->ilist) + dbprintf("block 0 for directory inode %lld is " + "missing\n", + id->ino); + error++; + return 0; + } + push_cur(); + set_cur(&typtab[TYP_DIR], XFS_FSB_TO_DADDR(mp, bno), blkbb, DB_RING_IGN, + NULL); + if (iocur_top->data == NULL) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("can't read block 0 for directory inode " + "%lld\n", + id->ino); + error++; + return 0; + } + parent = process_leaf_dir_v1_int(dot, dotdot, id); + pop_cur(); + return parent; +} + +static xfs_ino_t +process_leaf_dir_v1_int( + int *dot, + int *dotdot, + inodata_t *id) +{ + xfs_fsblock_t bno; + inodata_t *cid; + xfs_dir_leaf_entry_t *entry; + int i; + xfs_dir_leafblock_t *leaf; + xfs_ino_t lino; + xfs_dir_leaf_name_t *namest; + xfs_ino_t parent = 0; + int v; + + bno = XFS_DADDR_TO_FSB(mp, iocur_top->bb); + v = verbose || id->ilist || CHECK_BLIST(bno); + leaf = iocur_top->data; + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("bad directory leaf magic # %#x for dir ino " + "%lld\n", + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), id->ino); + error++; + return NULLFSINO; + } + entry = &leaf->entries[0]; + for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + lino=DIRINO_GET_ARCH(&namest->inumber, ARCH_CONVERT); + cid = find_inode(lino, 1); + if (v) + dbprintf("dir %lld entry %*.*s %lld\n", id->ino, + entry->namelen, entry->namelen, namest->name, + lino); + if (cid) + addlink_inode(cid); + else { + if (!sflag) + dbprintf("dir %lld entry %*.*s bad inode " + "number %lld\n", + id->ino, entry->namelen, entry->namelen, + namest->name, lino); + error++; + } + if (entry->namelen == 2 && namest->name[0] == '.' && + namest->name[1] == '.') { + if (parent) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("multiple .. entries in dir " + "%lld (%lld, %lld)\n", + id->ino, parent, lino); + error++; + } else + parent = cid ? lino : NULLFSINO; + (*dotdot)++; + } else if (entry->namelen != 1 || namest->name[0] != '.') { + if (cid != NULL) { + if (!cid->parent) + cid->parent = id; + addname_inode(cid, (char *)namest->name, + entry->namelen); + } + } else { + if (lino != id->ino) { + if (!sflag) + dbprintf("dir %lld entry . inode " + "number mismatch (%lld)\n", + id->ino, lino); + error++; + } + (*dot)++; + } + } + return parent; +} + +static xfs_ino_t +process_leaf_node_dir_v2( + blkmap_t *blkmap, + int *dot, + int *dotdot, + inodata_t *id, + xfs_fsize_t dirsize) +{ + xfs_fsblock_t b; + bbmap_t bbmap; + bmap_ext_t *bmp; + xfs_fileoff_t dbno; + freetab_t *freetab; + int i; + xfs_ino_t lino; + int nex; + xfs_ino_t parent; + int t; + int v; + int v2; + int x; + + v2 = verbose || id->ilist; + v = parent = 0; + dbno = NULLFILEOFF; + freetab = malloc(FREETAB_SIZE(dirsize / mp->m_dirblksize)); + freetab->naents = (int)(dirsize / mp->m_dirblksize); + freetab->nents = 0; + for (i = 0; i < freetab->naents; i++) + freetab->ents[i] = NULLDATAOFF; + dir_hash_init(); + while ((dbno = blkmap_next_off(blkmap, dbno, &t)) != NULLFILEOFF) { + nex = blkmap_getn(blkmap, dbno, mp->m_dirblkfsbs, &bmp); + ASSERT(nex > 0); + for (v = v2, x = 0; !v && x < nex; x++) { + for (b = bmp[x].startblock; + !v && b < bmp[x].startblock + bmp[x].blockcount; + b++) + v = CHECK_BLIST(b); + } + if (v) + dbprintf("dir inode %lld block %u=%llu\n", id->ino, + (__uint32_t)dbno, + (xfs_dfsbno_t)bmp->startblock); + push_cur(); + if (nex > 1) + make_bbmap(&bbmap, nex, bmp); + set_cur(&typtab[TYP_DIR], XFS_FSB_TO_DADDR(mp, bmp->startblock), + mp->m_dirblkfsbs * blkbb, DB_RING_IGN, + nex > 1 ? &bbmap : NULL); + free(bmp); + if (iocur_top->data == NULL) { + if (!sflag || v) + dbprintf("can't read block %u for directory " + "inode %lld\n", + (__uint32_t)dbno, id->ino); + error++; + pop_cur(); + dbno += mp->m_dirblkfsbs - 1; + continue; + } + if (dbno < mp->m_dirleafblk) { + lino = process_data_dir_v2(dot, dotdot, id, v, + (xfs_dablk_t)dbno, &freetab); + if (lino) { + if (parent) { + if (!sflag || v) + dbprintf("multiple .. entries " + "in dir %lld\n", + id->ino); + error++; + } else + parent = lino; + } + } else if (dbno < mp->m_dirfreeblk) { + process_leaf_node_dir_v2_int(id, v, (xfs_dablk_t)dbno, + freetab); + } else { + process_leaf_node_dir_v2_free(id, v, (xfs_dablk_t)dbno, + freetab); + } + pop_cur(); + dbno += mp->m_dirblkfsbs - 1; + } + dir_hash_check(id, v); + dir_hash_done(); + for (i = 0; i < freetab->nents; i++) { + if (freetab->ents[i] != NULLDATAOFF) { + if (!sflag || v) + dbprintf("missing free index for data block %d " + "in dir ino %lld\n", + XFS_DIR2_DB_TO_DA(mp, i), id->ino); + error++; + } + } + free(freetab); + return parent; +} + +static void +process_leaf_node_dir_v2_free( + inodata_t *id, + int v, + xfs_dablk_t dabno, + freetab_t *freetab) +{ + xfs_dir2_data_off_t ent; + xfs_dir2_free_t *free; + int i; + int maxent; + int used; + + free = iocur_top->data; + if (INT_GET(free->hdr.magic, ARCH_CONVERT) != XFS_DIR2_FREE_MAGIC) { + if (!sflag || v) + dbprintf("bad free block magic # %#x for dir ino %lld " + "block %d\n", + INT_GET(free->hdr.magic, ARCH_CONVERT), id->ino, dabno); + error++; + return; + } + maxent = XFS_DIR2_MAX_FREE_BESTS(mp); + if (INT_GET(free->hdr.firstdb, ARCH_CONVERT) != + XFS_DIR2_DA_TO_DB(mp, dabno - mp->m_dirfreeblk) * maxent) { + if (!sflag || v) + dbprintf("bad free block firstdb %d for dir ino %lld " + "block %d\n", + INT_GET(free->hdr.firstdb, ARCH_CONVERT), id->ino, dabno); + error++; + return; + } + if (INT_GET(free->hdr.nvalid, ARCH_CONVERT) > maxent || INT_GET(free->hdr.nvalid, ARCH_CONVERT) < 0 || + INT_GET(free->hdr.nused, ARCH_CONVERT) > maxent || INT_GET(free->hdr.nused, ARCH_CONVERT) < 0 || + INT_GET(free->hdr.nused, ARCH_CONVERT) > INT_GET(free->hdr.nvalid, ARCH_CONVERT)) { + if (!sflag || v) + dbprintf("bad free block nvalid/nused %d/%d for dir " + "ino %lld block %d\n", + INT_GET(free->hdr.nvalid, ARCH_CONVERT), INT_GET(free->hdr.nused, ARCH_CONVERT), id->ino, + dabno); + error++; + return; + } + for (used = i = 0; i < INT_GET(free->hdr.nvalid, ARCH_CONVERT); i++) { + if (freetab->nents <= INT_GET(free->hdr.firstdb, ARCH_CONVERT) + i) + ent = NULLDATAOFF; + else + ent = freetab->ents[INT_GET(free->hdr.firstdb, ARCH_CONVERT) + i]; + if (ent != INT_GET(free->bests[i], ARCH_CONVERT)) { + if (!sflag || v) + dbprintf("bad free block ent %d is %d should " + "be %d for dir ino %lld block %d\n", + i, INT_GET(free->bests[i], ARCH_CONVERT), ent, id->ino, dabno); + error++; + } + if (INT_GET(free->bests[i], ARCH_CONVERT) != NULLDATAOFF) + used++; + if (ent != NULLDATAOFF) + freetab->ents[INT_GET(free->hdr.firstdb, ARCH_CONVERT) + i] = NULLDATAOFF; + } + if (used != INT_GET(free->hdr.nused, ARCH_CONVERT)) { + if (!sflag || v) + dbprintf("bad free block nused %d should be %d for dir " + "ino %lld block %d\n", + INT_GET(free->hdr.nused, ARCH_CONVERT), used, id->ino, dabno); + error++; + } +} + +static void +process_leaf_node_dir_v2_int( + inodata_t *id, + int v, + xfs_dablk_t dabno, + freetab_t *freetab) +{ + int i; + xfs_dir2_data_off_t *lbp; + xfs_dir2_leaf_t *leaf; + xfs_dir2_leaf_entry_t *lep; + xfs_dir2_leaf_tail_t *ltp; + xfs_da_intnode_t *node; + int stale; + + leaf = iocur_top->data; + switch (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)) { + case XFS_DIR2_LEAF1_MAGIC: + if (INT_GET(leaf->hdr.info.forw, ARCH_CONVERT) || INT_GET(leaf->hdr.info.back, ARCH_CONVERT)) { + if (!sflag || v) + dbprintf("bad leaf block forw/back pointers " + "%d/%d for dir ino %lld block %d\n", + INT_GET(leaf->hdr.info.forw, ARCH_CONVERT), + INT_GET(leaf->hdr.info.back, ARCH_CONVERT), id->ino, dabno); + error++; + } + if (dabno != mp->m_dirleafblk) { + if (!sflag || v) + dbprintf("single leaf block for dir ino %lld " + "block %d should be at block %d\n", + id->ino, dabno, + (xfs_dablk_t)mp->m_dirleafblk); + error++; + } + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + lbp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + for (i = 0; i < INT_GET(ltp->bestcount, ARCH_CONVERT); i++) { + if (freetab->nents <= i || freetab->ents[i] != INT_GET(lbp[i], ARCH_CONVERT)) { + if (!sflag || v) + dbprintf("bestfree %d for dir ino %lld " + "block %d doesn't match table " + "value %d\n", + freetab->nents <= i ? + NULLDATAOFF : + freetab->ents[i], + id->ino, + XFS_DIR2_DB_TO_DA(mp, i), + INT_GET(lbp[i], ARCH_CONVERT)); + } + if (freetab->nents > i) + freetab->ents[i] = NULLDATAOFF; + } + break; + case XFS_DIR2_LEAFN_MAGIC: + /* if it's at the root location then we can check the + * pointers are null XXX */ + break; + case XFS_DA_NODE_MAGIC: + node = iocur_top->data; + if (INT_GET(node->hdr.level, ARCH_CONVERT) < 1 || + INT_GET(node->hdr.level, ARCH_CONVERT) > XFS_DA_NODE_MAXDEPTH) { + if (!sflag || v) + dbprintf("bad node block level %d for dir ino " + "%lld block %d\n", + INT_GET(node->hdr.level, ARCH_CONVERT), id->ino, dabno); + error++; + } + return; + default: + if (!sflag || v) + dbprintf("bad directory data magic # %#x for dir ino " + "%lld block %d\n", + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), id->ino, dabno); + error++; + return; + } + lep = leaf->ents; + for (i = stale = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); i++) { + if (INT_GET(lep[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + stale++; + else if (dir_hash_see(INT_GET(lep[i].hashval, ARCH_CONVERT), INT_GET(lep[i].address, ARCH_CONVERT))) { + if (!sflag || v) + dbprintf("dir %lld block %d extra leaf entry " + "%x %x\n", + id->ino, dabno, INT_GET(lep[i].hashval, ARCH_CONVERT), + INT_GET(lep[i].address, ARCH_CONVERT)); + error++; + } + } + if (stale != INT_GET(leaf->hdr.stale, ARCH_CONVERT)) { + if (!sflag || v) + dbprintf("dir %lld block %d stale mismatch " + "%d/%d\n", + id->ino, dabno, stale, + INT_GET(leaf->hdr.stale, ARCH_CONVERT)); + error++; + } +} + +static xfs_ino_t +process_node_dir_v1( + blkmap_t *blkmap, + int *dot, + int *dotdot, + inodata_t *id) +{ + xfs_fsblock_t bno; + xfs_fileoff_t dbno; + xfs_ino_t lino; + xfs_da_intnode_t *node; + xfs_ino_t parent; + int t; + int v; + int v2; + + v = verbose || id->ilist; + parent = 0; + dbno = NULLFILEOFF; + while ((dbno = blkmap_next_off(blkmap, dbno, &t)) != NULLFILEOFF) { + bno = blkmap_get(blkmap, dbno); + v2 = bno != NULLFSBLOCK && CHECK_BLIST(bno); + if (bno == NULLFSBLOCK && dbno == 0) { + if (!sflag || v) + dbprintf("can't read root block for directory " + "inode %lld\n", + id->ino); + error++; + } + if (v || v2) + dbprintf("dir inode %lld block %u=%llu\n", id->ino, + (__uint32_t)dbno, (xfs_dfsbno_t)bno); + if (bno == NULLFSBLOCK) + continue; + push_cur(); + set_cur(&typtab[TYP_DIR], XFS_FSB_TO_DADDR(mp, bno), blkbb, + DB_RING_IGN, NULL); + if ((node = iocur_top->data) == NULL) { + if (!sflag || v || v2) + dbprintf("can't read block %u for directory " + "inode %lld\n", + (__uint32_t)dbno, id->ino); + error++; + continue; + } +#if VERS >= V_62 + if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) +#else + if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_NODE_MAGIC) +#endif + { + pop_cur(); + continue; + } + lino = process_leaf_dir_v1_int(dot, dotdot, id); + if (lino) { + if (parent) { + if (!sflag || v || v2) + dbprintf("multiple .. entries in dir " + "%lld\n", + id->ino); + error++; + } else + parent = lino; + } + pop_cur(); + } + return parent; +} + +static void +process_quota( + int isgrp, + inodata_t *id, + blkmap_t *blkmap) +{ + xfs_fsblock_t bno; + int cb; + xfs_dqblk_t *dqb; + xfs_dqid_t dqid; + u_int8_t exp_flags; + int i; + int perblock; + xfs_fileoff_t qbno; + char *s; + int scicb; + int t; + + perblock = (int)(mp->m_sb.sb_blocksize / sizeof(*dqb)); + s = isgrp ? "group" : "user"; + exp_flags = isgrp ? XFS_DQ_GROUP : XFS_DQ_USER; + dqid = 0; + qbno = NULLFILEOFF; + while ((qbno = blkmap_next_off(blkmap, qbno, &t)) != + NULLFILEOFF) { + bno = blkmap_get(blkmap, qbno); + dqid = (xfs_dqid_t)qbno * perblock; + cb = CHECK_BLIST(bno); + scicb = !sflag || id->ilist || cb; + push_cur(); + set_cur(&typtab[TYP_DQBLK], XFS_FSB_TO_DADDR(mp, bno), blkbb, + DB_RING_IGN, NULL); + if ((dqb = iocur_top->data) == NULL) { + pop_cur(); + if (scicb) + dbprintf("can't read block %lld for %s quota " + "inode (fsblock %lld)\n", + (xfs_dfiloff_t)qbno, s, + (xfs_dfsbno_t)bno); + error++; + continue; + } + for (i = 0; i < perblock; i++, dqid++, dqb++) { + if (verbose || id->ilist || cb) + dbprintf("%s dqblk %lld entry %d id %d bc " + "%lld ic %lld rc %lld\n", + s, (xfs_dfiloff_t)qbno, i, dqid, + INT_GET(dqb->dd_diskdq.d_bcount, ARCH_CONVERT), + INT_GET(dqb->dd_diskdq.d_icount, ARCH_CONVERT), + INT_GET(dqb->dd_diskdq.d_rtbcount, ARCH_CONVERT)); + if (INT_GET(dqb->dd_diskdq.d_magic, ARCH_CONVERT) != XFS_DQUOT_MAGIC) { + if (scicb) + dbprintf("bad magic number %#x for %s " + "dqblk %lld entry %d id %d\n", + INT_GET(dqb->dd_diskdq.d_magic, ARCH_CONVERT), s, + (xfs_dfiloff_t)qbno, i, dqid); + error++; + continue; + } + if (INT_GET(dqb->dd_diskdq.d_version, ARCH_CONVERT) != XFS_DQUOT_VERSION) { + if (scicb) + dbprintf("bad version number %#x for " + "%s dqblk %lld entry %d id " + "%d\n", + INT_GET(dqb->dd_diskdq.d_version, ARCH_CONVERT), s, + (xfs_dfiloff_t)qbno, i, dqid); + error++; + continue; + } + if (INT_GET(dqb->dd_diskdq.d_flags, ARCH_CONVERT) != exp_flags) { + if (scicb) + dbprintf("bad flags %#x for %s dqblk " + "%lld entry %d id %d\n", + INT_GET(dqb->dd_diskdq.d_flags, ARCH_CONVERT), s, + (xfs_dfiloff_t)qbno, i, dqid); + error++; + continue; + } + if (INT_GET(dqb->dd_diskdq.d_id, ARCH_CONVERT) != dqid) { + if (scicb) + dbprintf("bad id %d for %s dqblk %lld " + "entry %d id %d\n", + INT_GET(dqb->dd_diskdq.d_id, ARCH_CONVERT), s, + (xfs_dfiloff_t)qbno, i, dqid); + error++; + continue; + } + quota_add(isgrp ? dqid : -1, isgrp ? -1 : dqid, 1, + INT_GET(dqb->dd_diskdq.d_bcount, ARCH_CONVERT), + INT_GET(dqb->dd_diskdq.d_icount, ARCH_CONVERT), + INT_GET(dqb->dd_diskdq.d_rtbcount, ARCH_CONVERT)); + } + pop_cur(); + } +} + +static void +process_rtbitmap( + blkmap_t *blkmap) +{ +#define xfs_highbit64 libxfs_highbit64 /* for XFS_RTBLOCKLOG macro */ + int bit; + int bitsperblock; + xfs_fileoff_t bmbno; + xfs_fsblock_t bno; + xfs_drtbno_t extno; + int len; + int log; + int offs; + int prevbit; + xfs_drfsbno_t rtbno; + int start_bmbno; + int start_bit; + int t; + xfs_rtword_t *words; + + bitsperblock = mp->m_sb.sb_blocksize * NBBY; + bit = extno = prevbit = start_bmbno = start_bit = 0; + bmbno = NULLFILEOFF; + while ((bmbno = blkmap_next_off(blkmap, bmbno, &t)) != + NULLFILEOFF) { + bno = blkmap_get(blkmap, bmbno); + if (bno == NULLFSBLOCK) { + if (!sflag) + dbprintf("block %lld for rtbitmap inode is " + "missing\n", + (xfs_dfiloff_t)bmbno); + error++; + continue; + } + push_cur(); + set_cur(&typtab[TYP_RTBITMAP], XFS_FSB_TO_DADDR(mp, bno), blkbb, + DB_RING_IGN, NULL); + if ((words = iocur_top->data) == NULL) { + pop_cur(); + if (!sflag) + dbprintf("can't read block %lld for rtbitmap " + "inode\n", + (xfs_dfiloff_t)bmbno); + error++; + continue; + } + for (bit = 0; + bit < bitsperblock && extno < mp->m_sb.sb_rextents; + bit++, extno++) { + if (isset(words, bit)) { + rtbno = extno * mp->m_sb.sb_rextsize; + set_rdbmap(rtbno, mp->m_sb.sb_rextsize, + DBM_RTFREE); + frextents++; + if (prevbit == 0) { + start_bmbno = (int)bmbno; + start_bit = bit; + prevbit = 1; + } + } else if (prevbit == 1) { + len = ((int)bmbno - start_bmbno) * + bitsperblock + (bit - start_bit); + log = XFS_RTBLOCKLOG(len); + offs = XFS_SUMOFFS(mp, log, start_bmbno); + sumcompute[offs]++; + prevbit = 0; + } + } + pop_cur(); + if (extno == mp->m_sb.sb_rextents) + break; + } + if (prevbit == 1) { + len = ((int)bmbno - start_bmbno) * bitsperblock + + (bit - start_bit); + log = XFS_RTBLOCKLOG(len); + offs = XFS_SUMOFFS(mp, log, start_bmbno); + sumcompute[offs]++; + } +} + +static void +process_rtsummary( + blkmap_t *blkmap) +{ + xfs_fsblock_t bno; + char *bytes; + xfs_fileoff_t sumbno; + int t; + + sumbno = NULLFILEOFF; + while ((sumbno = blkmap_next_off(blkmap, sumbno, &t)) != + NULLFILEOFF) { + bno = blkmap_get(blkmap, sumbno); + if (bno == NULLFSBLOCK) { + if (!sflag) + dbprintf("block %lld for rtsummary inode is " + "missing\n", + (xfs_dfiloff_t)sumbno); + error++; + continue; + } + push_cur(); + set_cur(&typtab[TYP_RTSUMMARY], XFS_FSB_TO_DADDR(mp, bno), + blkbb, DB_RING_IGN, NULL); + if ((bytes = iocur_top->data) == NULL) { + if (!sflag) + dbprintf("can't read block %lld for rtsummary " + "inode\n", + (xfs_dfiloff_t)sumbno); + error++; + continue; + } + memcpy((char *)sumfile + sumbno * mp->m_sb.sb_blocksize, bytes, + mp->m_sb.sb_blocksize); + pop_cur(); + } +} + +static xfs_ino_t +process_sf_dir_v2( + xfs_dinode_t *dip, + int *dot, + int *dotdot, + inodata_t *id) +{ + inodata_t *cid; + int i; + int i8; + xfs_ino_t lino; + int offset; + xfs_dir2_sf_t *sf; + xfs_dir2_sf_entry_t *sfe; + int v; + + sf = &dip->di_u.di_dir2sf; + addlink_inode(id); + v = verbose || id->ilist; + if (v) + dbprintf("dir %lld entry . %lld\n", id->ino, id->ino); + (*dot)++; + sfe = XFS_DIR2_SF_FIRSTENTRY(sf); + offset = XFS_DIR2_DATA_FIRST_OFFSET; + for (i = INT_GET(sf->hdr.count, ARCH_CONVERT) - 1, i8 = 0; i >= 0; i--) { + if ((__psint_t)sfe + XFS_DIR2_SF_ENTSIZE_BYENTRY(sf, sfe) - + (__psint_t)sf > dip->di_core.di_size) { + if (!sflag) + dbprintf("dir %llu bad size in entry at %d\n", + id->ino, + (int)((char *)sfe - (char *)sf)); + error++; + break; + } + lino = XFS_DIR2_SF_GET_INUMBER_ARCH(sf, XFS_DIR2_SF_INUMBERP(sfe), ARCH_CONVERT); + if (lino > XFS_DIR2_MAX_SHORT_INUM) + i8++; + cid = find_inode(lino, 1); + if (cid == NULL) { + if (!sflag) + dbprintf("dir %lld entry %*.*s bad inode " + "number %lld\n", + id->ino, sfe->namelen, sfe->namelen, + sfe->name, lino); + error++; + } else { + addlink_inode(cid); + if (!cid->parent) + cid->parent = id; + addname_inode(cid, (char *)sfe->name, sfe->namelen); + } + if (v) + dbprintf("dir %lld entry %*.*s offset %d %lld\n", + id->ino, sfe->namelen, sfe->namelen, sfe->name, + XFS_DIR2_SF_GET_OFFSET_ARCH(sfe, ARCH_CONVERT), lino); + if (XFS_DIR2_SF_GET_OFFSET_ARCH(sfe, ARCH_CONVERT) < offset) { + if (!sflag) + dbprintf("dir %lld entry %*.*s bad offset %d\n", + id->ino, sfe->namelen, sfe->namelen, + sfe->name, XFS_DIR2_SF_GET_OFFSET_ARCH(sfe, ARCH_CONVERT)); + error++; + } + offset = + XFS_DIR2_SF_GET_OFFSET_ARCH(sfe, ARCH_CONVERT) + + XFS_DIR2_DATA_ENTSIZE(sfe->namelen); + sfe = XFS_DIR2_SF_NEXTENTRY(sf, sfe); + } + if (i < 0 && (__psint_t)sfe - (__psint_t)sf != dip->di_core.di_size) { + if (!sflag) + dbprintf("dir %llu size is %lld, should be %u\n", + id->ino, dip->di_core.di_size, + (uint)((char *)sfe - (char *)sf)); + error++; + } + if (offset + (INT_GET(sf->hdr.count, ARCH_CONVERT) + 2) * sizeof(xfs_dir2_leaf_entry_t) + + sizeof(xfs_dir2_block_tail_t) > mp->m_dirblksize) { + if (!sflag) + dbprintf("dir %llu offsets too high\n", id->ino); + error++; + } + lino = XFS_DIR2_SF_GET_INUMBER_ARCH(sf, &sf->hdr.parent, ARCH_CONVERT); + if (lino > XFS_DIR2_MAX_SHORT_INUM) + i8++; + cid = find_inode(lino, 1); + if (cid) + addlink_inode(cid); + else { + if (!sflag) + dbprintf("dir %lld entry .. bad inode number %lld\n", + id->ino, lino); + error++; + } + if (v) + dbprintf("dir %lld entry .. %lld\n", id->ino, lino); + if (i8 != sf->hdr.i8count) { + if (!sflag) + dbprintf("dir %lld i8count mismatch is %d should be " + "%d\n", + id->ino, sf->hdr.i8count, i8); + error++; + } + (*dotdot)++; + return cid ? lino : NULLFSINO; +} + +static xfs_ino_t +process_shortform_dir_v1( + xfs_dinode_t *dip, + int *dot, + int *dotdot, + inodata_t *id) +{ + inodata_t *cid; + int i; + xfs_ino_t lino; + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + int v; + + sf = &dip->di_u.di_dirsf; + addlink_inode(id); + v = verbose || id->ilist; + if (v) + dbprintf("dir %lld entry . %lld\n", id->ino, id->ino); + (*dot)++; + sfe = &sf->list[0]; + for (i = INT_GET(sf->hdr.count, ARCH_CONVERT) - 1; i >= 0; i--) { + lino = DIRINO_GET_ARCH(&sfe->inumber, ARCH_CONVERT); + cid = find_inode(lino, 1); + if (cid == NULL) { + if (!sflag) + dbprintf("dir %lld entry %*.*s bad inode " + "number %lld\n", + id->ino, sfe->namelen, sfe->namelen, + sfe->name, lino); + error++; + } else { + addlink_inode(cid); + if (!cid->parent) + cid->parent = id; + addname_inode(cid, (char *)sfe->name, sfe->namelen); + } + if (v) + dbprintf("dir %lld entry %*.*s %lld\n", id->ino, + sfe->namelen, sfe->namelen, sfe->name, lino); + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + if ((__psint_t)sfe - (__psint_t)sf != dip->di_core.di_size) + dbprintf("dir %llu size is %lld, should be %d\n", + id->ino, dip->di_core.di_size, + (int)((char *)sfe - (char *)sf)); + lino=DIRINO_GET_ARCH(&sf->hdr.parent, ARCH_CONVERT); + cid = find_inode(lino, 1); + if (cid) + addlink_inode(cid); + else { + if (!sflag) + dbprintf("dir %lld entry .. bad inode number %lld\n", + id->ino, lino); + error++; + } + if (v) + dbprintf("dir %lld entry .. %lld\n", id->ino, lino); + (*dotdot)++; + return cid ? lino : NULLFSINO; +} + +static void +quota_add( + xfs_dqid_t grpid, + xfs_dqid_t usrid, + int dq, + xfs_qcnt_t bc, + xfs_qcnt_t ic, + xfs_qcnt_t rc) +{ + if (qudo && usrid != -1) + quota_add1(qudata, usrid, dq, bc, ic, rc); + if (qgdo && grpid != -1) + quota_add1(qgdata, grpid, dq, bc, ic, rc); +} + +static void +quota_add1( + qdata_t **qt, + xfs_dqid_t id, + int dq, + xfs_qcnt_t bc, + xfs_qcnt_t ic, + xfs_qcnt_t rc) +{ + qdata_t *qe; + int qh; + qinfo_t *qi; + + qh = (int)((__uint32_t)id % QDATA_HASH_SIZE); + qe = qt[qh]; + while (qe) { + if (qe->id == id) { + qi = dq ? &qe->dq : &qe->count; + qi->bc += bc; + qi->ic += ic; + qi->rc += rc; + return; + } + qe = qe->next; + } + qe = xmalloc(sizeof(*qe)); + qe->id = id; + qi = dq ? &qe->dq : &qe->count; + qi->bc = bc; + qi->ic = ic; + qi->rc = rc; + qi = dq ? &qe->count : &qe->dq; + qi->bc = qi->ic = qi->rc = 0; + qe->next = qt[qh]; + qt[qh] = qe; +} + +static void +quota_check( + char *s, + qdata_t **qt) +{ + int i; + qdata_t *next; + qdata_t *qp; + + for (i = 0; i < QDATA_HASH_SIZE; i++) { + qp = qt[i]; + while (qp) { + next = qp->next; + if (qp->count.bc != qp->dq.bc || + qp->count.ic != qp->dq.ic || + qp->count.rc != qp->dq.rc) { + if (!sflag) { + dbprintf("%s quota id %d, have/exp", + s, qp->id); + if (qp->count.bc != qp->dq.bc) + dbprintf(" bc %lld/%lld", + qp->dq.bc, + qp->count.bc); + if (qp->count.ic != qp->dq.ic) + dbprintf(" ic %lld/%lld", + qp->dq.ic, + qp->count.ic); + if (qp->count.rc != qp->dq.rc) + dbprintf(" rc %lld/%lld", + qp->dq.rc, + qp->count.rc); + dbprintf("\n"); + } + error++; + } + xfree(qp); + qp = next; + } + } + xfree(qt); +} + +static void +quota_init(void) +{ + qudo = mp->m_sb.sb_uquotino != 0 && + mp->m_sb.sb_uquotino != NULLFSINO && + (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) && + (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD); + qgdo = mp->m_sb.sb_gquotino != 0 && + mp->m_sb.sb_gquotino != NULLFSINO && + (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) && + (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD); + if (qudo) + qudata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *)); + if (qgdo) + qgdata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *)); +} + +static void +scan_ag( + xfs_agnumber_t agno) +{ + xfs_agf_t *agf; + xfs_agi_t *agi; + int i; + xfs_sb_t tsb; + xfs_sb_t *sb=&tsb; + + agffreeblks = agflongest = 0; + agicount = agifreecount = 0; + push_cur(); + set_cur(&typtab[TYP_SB], XFS_AG_DADDR(mp, agno, XFS_SB_DADDR), 1, + DB_RING_IGN, NULL); + + if (!iocur_top->data) { + dbprintf("can't read superblock for ag %u\n", agno); + pop_cur(); + serious_error++; + return; + } + + libxfs_xlate_sb(iocur_top->data, sb, 1, ARCH_CONVERT, XFS_SB_ALL_BITS); + + if (sb->sb_magicnum != XFS_SB_MAGIC) { + if (!sflag) + dbprintf("bad sb magic # %#x in ag %u\n", + sb->sb_magicnum, agno); + error++; + } + if (!XFS_SB_GOOD_VERSION(sb)) { + if (!sflag) + dbprintf("bad sb version # %#x in ag %u\n", + sb->sb_versionnum, agno); + error++; + sbver_err++; + } + if (agno == 0 && sb->sb_inprogress != 0) { + if (!sflag) + dbprintf("mkfs not completed successfully\n"); + error++; + } + set_dbmap(agno, XFS_SB_BLOCK(mp), 1, DBM_SB, agno, XFS_SB_BLOCK(mp)); + if (sb->sb_logstart && XFS_FSB_TO_AGNO(mp, sb->sb_logstart) == agno) + set_dbmap(agno, XFS_FSB_TO_AGBNO(mp, sb->sb_logstart), + sb->sb_logblocks, DBM_LOG, agno, XFS_SB_BLOCK(mp)); + push_cur(); + set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR), 1, + DB_RING_IGN, NULL); + if ((agf = iocur_top->data) == NULL) { + dbprintf("can't read agf block for ag %u\n", agno); + pop_cur(); + pop_cur(); + serious_error++; + return; + } + if (INT_GET(agf->agf_magicnum, ARCH_CONVERT) != XFS_AGF_MAGIC) { + if (!sflag) + dbprintf("bad agf magic # %#x in ag %u\n", + INT_GET(agf->agf_magicnum, ARCH_CONVERT), agno); + error++; + } + if (!XFS_AGF_GOOD_VERSION(INT_GET(agf->agf_versionnum, ARCH_CONVERT))) { + if (!sflag) + dbprintf("bad agf version # %#x in ag %u\n", + INT_GET(agf->agf_versionnum, ARCH_CONVERT), agno); + error++; + } + if (XFS_SB_BLOCK(mp) != XFS_AGF_BLOCK(mp)) + set_dbmap(agno, XFS_AGF_BLOCK(mp), 1, DBM_AGF, agno, + XFS_SB_BLOCK(mp)); + if (sb->sb_agblocks > INT_GET(agf->agf_length, ARCH_CONVERT)) + set_dbmap(agno, INT_GET(agf->agf_length, ARCH_CONVERT), + sb->sb_agblocks - INT_GET(agf->agf_length, ARCH_CONVERT), + DBM_MISSING, agno, XFS_SB_BLOCK(mp)); + push_cur(); + set_cur(&typtab[TYP_AGI], XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR), 1, + DB_RING_IGN, NULL); + if ((agi = iocur_top->data) == NULL) { + dbprintf("can't read agi block for ag %u\n", agno); + serious_error++; + pop_cur(); + pop_cur(); + pop_cur(); + return; + } + if (INT_GET(agi->agi_magicnum, ARCH_CONVERT) != XFS_AGI_MAGIC) { + if (!sflag) + dbprintf("bad agi magic # %#x in ag %u\n", + INT_GET(agi->agi_magicnum, ARCH_CONVERT), agno); + error++; + } + if (!XFS_AGI_GOOD_VERSION(INT_GET(agi->agi_versionnum, ARCH_CONVERT))) { + if (!sflag) + dbprintf("bad agi version # %#x in ag %u\n", + INT_GET(agi->agi_versionnum, ARCH_CONVERT), agno); + error++; + } + if (XFS_SB_BLOCK(mp) != XFS_AGI_BLOCK(mp) && + XFS_AGF_BLOCK(mp) != XFS_AGI_BLOCK(mp)) + set_dbmap(agno, XFS_AGI_BLOCK(mp), 1, DBM_AGI, agno, + XFS_SB_BLOCK(mp)); + scan_freelist(agf); + fdblocks--; + scan_sbtree(agf, + INT_GET(agf->agf_roots[XFS_BTNUM_BNO], ARCH_CONVERT), + INT_GET(agf->agf_levels[XFS_BTNUM_BNO], ARCH_CONVERT), + 1, scanfunc_bno, TYP_BNOBT); + fdblocks--; + scan_sbtree(agf, + INT_GET(agf->agf_roots[XFS_BTNUM_CNT], ARCH_CONVERT), + INT_GET(agf->agf_levels[XFS_BTNUM_CNT], ARCH_CONVERT), + 1, scanfunc_cnt, TYP_CNTBT); + scan_sbtree(agf, + INT_GET(agi->agi_root, ARCH_CONVERT), + INT_GET(agi->agi_level, ARCH_CONVERT), + 1, scanfunc_ino, TYP_INOBT); + if (INT_GET(agf->agf_freeblks, ARCH_CONVERT) != agffreeblks) { + if (!sflag) + dbprintf("agf_freeblks %u, counted %u in ag %u\n", + INT_GET(agf->agf_freeblks, ARCH_CONVERT), + agffreeblks, agno); + error++; + } + if (INT_GET(agf->agf_longest, ARCH_CONVERT) != agflongest) { + if (!sflag) + dbprintf("agf_longest %u, counted %u in ag %u\n", + INT_GET(agf->agf_longest, ARCH_CONVERT), + agflongest, agno); + error++; + } + if (INT_GET(agi->agi_count, ARCH_CONVERT) != agicount) { + if (!sflag) + dbprintf("agi_count %u, counted %u in ag %u\n", + INT_GET(agi->agi_count, ARCH_CONVERT), + agicount, agno); + error++; + } + if (INT_GET(agi->agi_freecount, ARCH_CONVERT) != agifreecount) { + if (!sflag) + dbprintf("agi_freecount %u, counted %u in ag %u\n", + INT_GET(agi->agi_freecount, ARCH_CONVERT), + agifreecount, agno); + error++; + } + for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) { + if (INT_GET(agi->agi_unlinked[i], ARCH_CONVERT) != NULLAGINO) { + if (!sflag) { + xfs_agino_t agino=INT_GET(agi->agi_unlinked[i], ARCH_CONVERT); + dbprintf("agi unlinked bucket %d is %u in ag " + "%u (inode=%lld)\n", i, agino, agno, + XFS_AGINO_TO_INO(mp, agno, agino)); + } + error++; + } + } + pop_cur(); + pop_cur(); + pop_cur(); +} + +static void +scan_freelist( + xfs_agf_t *agf) +{ + xfs_agnumber_t seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + xfs_agfl_t *agfl; + xfs_agblock_t bno; + uint count; + int i; + + if (XFS_SB_BLOCK(mp) != XFS_AGFL_BLOCK(mp) && + XFS_AGF_BLOCK(mp) != XFS_AGFL_BLOCK(mp) && + XFS_AGI_BLOCK(mp) != XFS_AGFL_BLOCK(mp)) + set_dbmap(seqno, XFS_AGFL_BLOCK(mp), 1, DBM_AGFL, seqno, + XFS_SB_BLOCK(mp)); + if (INT_GET(agf->agf_flcount, ARCH_CONVERT) == 0) + return; + push_cur(); + set_cur(&typtab[TYP_AGFL], + XFS_AG_DADDR(mp, seqno, XFS_AGFL_DADDR), 1, DB_RING_IGN, NULL); + if ((agfl = iocur_top->data) == NULL) { + dbprintf("can't read agfl block for ag %u\n", seqno); + serious_error++; + return; + } + i = INT_GET(agf->agf_flfirst, ARCH_CONVERT); + count = 0; + for (;;) { + bno = INT_GET(agfl->agfl_bno[i], ARCH_CONVERT); + set_dbmap(seqno, bno, 1, DBM_FREELIST, seqno, + XFS_AGFL_BLOCK(mp)); + count++; + if (i == INT_GET(agf->agf_fllast, ARCH_CONVERT)) + break; + if (++i == XFS_AGFL_SIZE) + i = 0; + } + if (count != INT_GET(agf->agf_flcount, ARCH_CONVERT)) { + if (!sflag) + dbprintf("freeblk count %u != flcount %u in ag %u\n", + count, INT_GET(agf->agf_flcount, ARCH_CONVERT), + seqno); + error++; + } + fdblocks += count; + pop_cur(); +} + +static void +scan_lbtree( + xfs_fsblock_t root, + int nlevels, + scan_lbtree_f_t func, + dbm_t type, + inodata_t *id, + xfs_drfsbno_t *totd, + xfs_drfsbno_t *toti, + xfs_extnum_t *nex, + blkmap_t **blkmapp, + int isroot, + typnm_t btype) +{ + push_cur(); + set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, root), blkbb, DB_RING_IGN, + NULL); + if (iocur_top->data == NULL) { + if (!sflag) + dbprintf("can't read btree block %u/%u\n", + XFS_FSB_TO_AGNO(mp, root), + XFS_FSB_TO_AGBNO(mp, root)); + error++; + return; + } + (*func)(iocur_top->data, nlevels - 1, type, root, id, totd, toti, nex, + blkmapp, isroot, btype); + pop_cur(); +} + +static void +scan_sbtree( + xfs_agf_t *agf, + xfs_agblock_t root, + int nlevels, + int isroot, + scan_sbtree_f_t func, + typnm_t btype) +{ + xfs_agnumber_t seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + + push_cur(); + set_cur(&typtab[btype], + XFS_AGB_TO_DADDR(mp, seqno, root), blkbb, DB_RING_IGN, NULL); + if (iocur_top->data == NULL) { + if (!sflag) + dbprintf("can't read btree block %u/%u\n", seqno, root); + error++; + return; + } + (*func)(iocur_top->data, nlevels - 1, agf, root, isroot); + pop_cur(); +} + +static void +scanfunc_bmap( + xfs_btree_lblock_t *ablock, + int level, + dbm_t type, + xfs_fsblock_t bno, + inodata_t *id, + xfs_drfsbno_t *totd, + xfs_drfsbno_t *toti, + xfs_extnum_t *nex, + blkmap_t **blkmapp, + int isroot, + typnm_t btype) +{ + xfs_agblock_t agbno; + xfs_agnumber_t agno; + xfs_bmbt_block_t *block = (xfs_bmbt_block_t *)ablock; + int i; + xfs_bmbt_ptr_t *pp; + xfs_bmbt_rec_32_t *rp; + + agno = XFS_FSB_TO_AGNO(mp, bno); + agbno = XFS_FSB_TO_AGBNO(mp, bno); + if (INT_GET(block->bb_magic, ARCH_CONVERT) != XFS_BMAP_MAGIC) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("bad magic # %#x in inode %lld bmbt block " + "%u/%u\n", + INT_GET(block->bb_magic, ARCH_CONVERT), id->ino, agno, agbno); + error++; + } + if (INT_GET(block->bb_level, ARCH_CONVERT) != level) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("expected level %d got %d in inode %lld bmbt " + "block %u/%u\n", + level, INT_GET(block->bb_level, ARCH_CONVERT), id->ino, agno, agbno); + error++; + } + set_dbmap(agno, agbno, 1, type, agno, agbno); + set_inomap(agno, agbno, 1, id); + (*toti)++; + if (level == 0) { + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_bmap_dmxr[0] || + (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_bmap_dmnr[0])) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("bad btree nrecs (%u, min=%u, max=%u) " + "in inode %lld bmap block %lld\n", + INT_GET(block->bb_numrecs, ARCH_CONVERT), mp->m_bmap_dmnr[0], + mp->m_bmap_dmxr[0], id->ino, + (xfs_dfsbno_t)bno); + error++; + return; + } + rp = (xfs_bmbt_rec_32_t *) + XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, + block, 1, mp->m_bmap_dmxr[0]); + *nex += INT_GET(block->bb_numrecs, ARCH_CONVERT); + process_bmbt_reclist(rp, INT_GET(block->bb_numrecs, ARCH_CONVERT), type, id, totd, + blkmapp); + return; + } + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_bmap_dmxr[1] || + (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_bmap_dmnr[1])) { + if (!sflag || id->ilist || CHECK_BLIST(bno)) + dbprintf("bad btree nrecs (%u, min=%u, max=%u) in " + "inode %lld bmap block %lld\n", + INT_GET(block->bb_numrecs, ARCH_CONVERT), mp->m_bmap_dmnr[1], + mp->m_bmap_dmxr[1], id->ino, (xfs_dfsbno_t)bno); + error++; + return; + } + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, 1, + mp->m_bmap_dmxr[0]); + for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) + scan_lbtree(INT_GET(pp[i], ARCH_CONVERT), level, scanfunc_bmap, type, id, totd, toti, + nex, blkmapp, 0, btype); +} + +static void +scanfunc_bno( + xfs_btree_sblock_t *ablock, + int level, + xfs_agf_t *agf, + xfs_agblock_t bno, + int isroot) +{ + xfs_alloc_block_t *block = (xfs_alloc_block_t *)ablock; + int i; + xfs_alloc_ptr_t *pp; + xfs_alloc_rec_t *rp; + xfs_agnumber_t seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + + if (INT_GET(block->bb_magic, ARCH_CONVERT) != XFS_ABTB_MAGIC) { + dbprintf("bad magic # %#x in btbno block %u/%u\n", + INT_GET(block->bb_magic, ARCH_CONVERT), seqno, bno); + serious_error++; + return; + } + fdblocks++; + if (INT_GET(block->bb_level, ARCH_CONVERT) != level) { + if (!sflag) + dbprintf("expected level %d got %d in btbno block " + "%u/%u\n", + level, INT_GET(block->bb_level, ARCH_CONVERT), seqno, bno); + error++; + } + set_dbmap(seqno, bno, 1, DBM_BTBNO, seqno, bno); + if (level == 0) { + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_alloc_mxr[0] || + (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_alloc_mnr[0])) { + dbprintf("bad btree nrecs (%u, min=%u, max=%u) in " + "btbno block %u/%u\n", + INT_GET(block->bb_numrecs, ARCH_CONVERT), mp->m_alloc_mnr[0], + mp->m_alloc_mxr[0], seqno, bno); + serious_error++; + return; + } + rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, + 1, mp->m_alloc_mxr[0]); + for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) { + set_dbmap(seqno, INT_GET(rp[i].ar_startblock, ARCH_CONVERT), + INT_GET(rp[i].ar_blockcount, ARCH_CONVERT), DBM_FREE1, + seqno, bno); + } + return; + } + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_alloc_mxr[1] || + (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_alloc_mnr[1])) { + dbprintf("bad btree nrecs (%u, min=%u, max=%u) in btbno block " + "%u/%u\n", + INT_GET(block->bb_numrecs, ARCH_CONVERT), mp->m_alloc_mnr[1], + mp->m_alloc_mxr[1], seqno, bno); + serious_error++; + return; + } + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, 1, + mp->m_alloc_mxr[1]); + for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) + scan_sbtree(agf, INT_GET(pp[i], ARCH_CONVERT), level, 0, scanfunc_bno, TYP_BNOBT); +} + +static void +scanfunc_cnt( + xfs_btree_sblock_t *ablock, + int level, + xfs_agf_t *agf, + xfs_agblock_t bno, + int isroot) +{ + xfs_alloc_block_t *block = (xfs_alloc_block_t *)ablock; + xfs_agnumber_t seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + int i; + xfs_alloc_ptr_t *pp; + xfs_alloc_rec_t *rp; + + if (INT_GET(block->bb_magic, ARCH_CONVERT) != XFS_ABTC_MAGIC) { + dbprintf("bad magic # %#x in btcnt block %u/%u\n", + INT_GET(block->bb_magic, ARCH_CONVERT), seqno, bno); + serious_error++; + return; + } + fdblocks++; + if (INT_GET(block->bb_level, ARCH_CONVERT) != level) { + if (!sflag) + dbprintf("expected level %d got %d in btcnt block " + "%u/%u\n", + level, INT_GET(block->bb_level, ARCH_CONVERT), seqno, bno); + error++; + } + set_dbmap(seqno, bno, 1, DBM_BTCNT, seqno, bno); + if (level == 0) { + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_alloc_mxr[0] || + (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_alloc_mnr[0])) { + dbprintf("bad btree nrecs (%u, min=%u, max=%u) in " + "btbno block %u/%u\n", + INT_GET(block->bb_numrecs, ARCH_CONVERT), mp->m_alloc_mnr[0], + mp->m_alloc_mxr[0], seqno, bno); + serious_error++; + return; + } + rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, + 1, mp->m_alloc_mxr[0]); + for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) { + check_set_dbmap(seqno, INT_GET(rp[i].ar_startblock, ARCH_CONVERT), + INT_GET(rp[i].ar_blockcount, ARCH_CONVERT), DBM_FREE1, DBM_FREE2, + seqno, bno); + fdblocks += INT_GET(rp[i].ar_blockcount, ARCH_CONVERT); + agffreeblks += INT_GET(rp[i].ar_blockcount, ARCH_CONVERT); + if (INT_GET(rp[i].ar_blockcount, ARCH_CONVERT) > agflongest) + agflongest = INT_GET(rp[i].ar_blockcount, ARCH_CONVERT); + } + return; + } + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_alloc_mxr[1] || + (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_alloc_mnr[1])) { + dbprintf("bad btree nrecs (%u, min=%u, max=%u) in btbno block " + "%u/%u\n", + INT_GET(block->bb_numrecs, ARCH_CONVERT), mp->m_alloc_mnr[1], + mp->m_alloc_mxr[1], seqno, bno); + serious_error++; + return; + } + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, 1, + mp->m_alloc_mxr[1]); + for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) + scan_sbtree(agf, INT_GET(pp[i], ARCH_CONVERT), level, 0, scanfunc_cnt, TYP_CNTBT); +} + +static void +scanfunc_ino( + xfs_btree_sblock_t *ablock, + int level, + xfs_agf_t *agf, + xfs_agblock_t bno, + int isroot) +{ + xfs_agino_t agino; + xfs_inobt_block_t *block = (xfs_inobt_block_t *)ablock; + xfs_agnumber_t seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + int i; + int isfree; + int j; + int nfree; + int off; + xfs_inobt_ptr_t *pp; + xfs_inobt_rec_t *rp; + + if (INT_GET(block->bb_magic, ARCH_CONVERT) != XFS_IBT_MAGIC) { + dbprintf("bad magic # %#x in inobt block %u/%u\n", + INT_GET(block->bb_magic, ARCH_CONVERT), seqno, bno); + serious_error++; + return; + } + if (INT_GET(block->bb_level, ARCH_CONVERT) != level) { + if (!sflag) + dbprintf("expected level %d got %d in inobt block " + "%u/%u\n", + level, INT_GET(block->bb_level, ARCH_CONVERT), seqno, bno); + error++; + } + set_dbmap(seqno, bno, 1, DBM_BTINO, seqno, bno); + if (level == 0) { + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_inobt_mxr[0] || + (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_inobt_mnr[0])) { + dbprintf("bad btree nrecs (%u, min=%u, max=%u) in " + "inobt block %u/%u\n", + INT_GET(block->bb_numrecs, ARCH_CONVERT), mp->m_inobt_mnr[0], + mp->m_inobt_mxr[0], seqno, bno); + serious_error++; + return; + } + rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_inobt, block, + 1, mp->m_inobt_mxr[0]); + for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) { + agino = INT_GET(rp[i].ir_startino, ARCH_CONVERT); + off = XFS_INO_TO_OFFSET(mp, agino); + if (off == 0) { + if ((sbversion & XFS_SB_VERSION_ALIGNBIT) && + mp->m_sb.sb_inoalignmt && + (XFS_INO_TO_AGBNO(mp, agino) % + mp->m_sb.sb_inoalignmt)) + sbversion &= ~XFS_SB_VERSION_ALIGNBIT; + set_dbmap(seqno, XFS_AGINO_TO_AGBNO(mp, agino), + (xfs_extlen_t)MAX(1, + XFS_INODES_PER_CHUNK >> + mp->m_sb.sb_inopblog), + DBM_INODE, seqno, bno); + } + icount += XFS_INODES_PER_CHUNK; + agicount += XFS_INODES_PER_CHUNK; + ifree += INT_GET(rp[i].ir_freecount, ARCH_CONVERT); + agifreecount += INT_GET(rp[i].ir_freecount, ARCH_CONVERT); + push_cur(); + set_cur(&typtab[TYP_INODE], + XFS_AGB_TO_DADDR(mp, seqno, + XFS_AGINO_TO_AGBNO(mp, agino)), + (int)XFS_FSB_TO_BB(mp, XFS_IALLOC_BLOCKS(mp)), + DB_RING_IGN, NULL); + if (iocur_top->data == NULL) { + if (!sflag) + dbprintf("can't read inode block " + "%u/%u\n", + seqno, + XFS_AGINO_TO_AGBNO(mp, agino)); + error++; + continue; + } + for (j = 0, nfree = 0; j < XFS_INODES_PER_CHUNK; j++) { + if ((isfree = XFS_INOBT_IS_FREE(&rp[i], j, ARCH_CONVERT))) + nfree++; + process_inode(agf, agino + j, + (xfs_dinode_t *)((char *)iocur_top->data + ((off + j) << mp->m_sb.sb_inodelog)), + isfree); + } + if (nfree != INT_GET(rp[i].ir_freecount, ARCH_CONVERT)) { + if (!sflag) + dbprintf("ir_freecount/free mismatch, " + "inode chunk %u/%u, freecount " + "%d nfree %d\n", + seqno, agino, + INT_GET(rp[i].ir_freecount, ARCH_CONVERT), nfree); + error++; + } + pop_cur(); + } + return; + } + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_inobt_mxr[1] || + (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_inobt_mnr[1])) { + dbprintf("bad btree nrecs (%u, min=%u, max=%u) in inobt block " + "%u/%u\n", + INT_GET(block->bb_numrecs, ARCH_CONVERT), mp->m_inobt_mnr[1], + mp->m_inobt_mxr[1], seqno, bno); + serious_error++; + return; + } + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_inobt, block, 1, + mp->m_inobt_mxr[1]); + for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) + scan_sbtree(agf, INT_GET(pp[i], ARCH_CONVERT), level, 0, scanfunc_ino, TYP_INOBT); +} + +static void +set_dbmap( + xfs_agnumber_t agno, + xfs_agblock_t agbno, + xfs_extlen_t len, + dbm_t type, + xfs_agnumber_t c_agno, + xfs_agblock_t c_agbno) +{ + check_set_dbmap(agno, agbno, len, DBM_UNKNOWN, type, c_agno, c_agbno); +} + +static void +set_inomap( + xfs_agnumber_t agno, + xfs_agblock_t agbno, + xfs_extlen_t len, + inodata_t *id) +{ + xfs_extlen_t i; + inodata_t **idp; + int mayprint; + + if (!check_inomap(agno, agbno, len, id->ino)) + return; + mayprint = verbose | id->ilist | blist_size; + for (i = 0, idp = &inomap[agno][agbno]; i < len; i++, idp++) { + *idp = id; + if (mayprint && + (verbose || id->ilist || CHECK_BLISTA(agno, agbno + i))) + dbprintf("setting inode to %lld for block %u/%u\n", + id->ino, agno, agbno + i); + } +} + +static void +set_rdbmap( + xfs_drfsbno_t bno, + xfs_extlen_t len, + dbm_t type) +{ + check_set_rdbmap(bno, len, DBM_UNKNOWN, type); +} + +static void +set_rinomap( + xfs_drfsbno_t bno, + xfs_extlen_t len, + inodata_t *id) +{ + xfs_extlen_t i; + inodata_t **idp; + int mayprint; + + if (!check_rinomap(bno, len, id->ino)) + return; + mayprint = verbose | id->ilist | blist_size; + for (i = 0, idp = &inomap[mp->m_sb.sb_agcount][bno]; + i < len; + i++, idp++) { + *idp = id; + if (mayprint && (verbose || id->ilist || CHECK_BLIST(bno + i))) + dbprintf("setting inode to %lld for rtblock %llu\n", + id->ino, bno + i); + } +} + +static void +setlink_inode( + inodata_t *id, + nlink_t nlink, + int isdir, + int security) +{ + id->link_set = nlink; + id->isdir = isdir; + id->security = security; + if (verbose || id->ilist) + dbprintf("inode %lld nlink %u %s dir\n", id->ino, nlink, + isdir ? "is" : "not"); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/check.h linux-2.4-xfs/cmd/xfsprogs/db/check.h --- linux-2.4.7/cmd/xfsprogs/db/check.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/check.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern void check_init(void); diff -rNu linux-2.4.7/cmd/xfsprogs/db/cntbt.c linux-2.4-xfs/cmd/xfsprogs/db/cntbt.c --- linux-2.4.7/cmd/xfsprogs/db/cntbt.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/cntbt.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "cntbt.h" +#include "print.h" +#include "bit.h" +#include "mount.h" + +static int cntbt_key_count(void *obj, int startoff); +static int cntbt_key_offset(void *obj, int startoff, int idx); +static int cntbt_ptr_count(void *obj, int startoff); +static int cntbt_ptr_offset(void *obj, int startoff, int idx); +static int cntbt_rec_count(void *obj, int startoff); +static int cntbt_rec_offset(void *obj, int startoff, int idx); + +const field_t cntbt_hfld[] = { + { "", FLDT_CNTBT, OI(0), C1, 0, TYP_NONE }, + { NULL } +}; + +#define OFF(f) bitize(offsetof(xfs_alloc_block_t, bb_ ## f)) +const field_t cntbt_flds[] = { + { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, + { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, + { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, + { "leftsib", FLDT_AGBLOCK, OI(OFF(leftsib)), C1, 0, TYP_CNTBT }, + { "rightsib", FLDT_AGBLOCK, OI(OFF(rightsib)), C1, 0, TYP_CNTBT }, + { "recs", FLDT_CNTBTREC, cntbt_rec_offset, cntbt_rec_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { "keys", FLDT_CNTBTKEY, cntbt_key_offset, cntbt_key_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { "ptrs", FLDT_CNTBTPTR, cntbt_ptr_offset, cntbt_ptr_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_CNTBT }, + { NULL } +}; + +#define KOFF(f) bitize(offsetof(xfs_alloc_key_t, ar_ ## f)) +const field_t cntbt_key_flds[] = { + { "blockcount", FLDT_EXTLEN, OI(KOFF(blockcount)), C1, 0, TYP_NONE }, + { "startblock", FLDT_AGBLOCK, OI(KOFF(startblock)), C1, 0, TYP_DATA }, + { NULL } +}; + +#define ROFF(f) bitize(offsetof(xfs_alloc_rec_t, ar_ ## f)) +const field_t cntbt_rec_flds[] = { + { "startblock", FLDT_AGBLOCK, OI(ROFF(startblock)), C1, 0, TYP_DATA }, + { "blockcount", FLDT_EXTLEN, OI(ROFF(blockcount)), C1, 0, TYP_NONE }, + { NULL } +}; + +/*ARGSUSED*/ +static int +cntbt_key_count( + void *obj, + int startoff) +{ + xfs_alloc_block_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->bb_level, ARCH_CONVERT) == 0) + return 0; + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +cntbt_key_offset( + void *obj, + int startoff, + int idx) +{ + xfs_alloc_block_t *block; + xfs_alloc_key_t *kp; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + kp = XFS_BTREE_KEY_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, idx, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_alloc, 0)); + return bitize((int)((char *)kp - (char *)block)); +} + +/*ARGSUSED*/ +static int +cntbt_ptr_count( + void *obj, + int startoff) +{ + xfs_alloc_block_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->bb_level, ARCH_CONVERT) == 0) + return 0; + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +cntbt_ptr_offset( + void *obj, + int startoff, + int idx) +{ + xfs_alloc_block_t *block; + xfs_alloc_ptr_t *pp; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, idx, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_alloc, 0)); + return bitize((int)((char *)pp - (char *)block)); +} + +/*ARGSUSED*/ +static int +cntbt_rec_count( + void *obj, + int startoff) +{ + xfs_alloc_block_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->bb_level, ARCH_CONVERT) > 0) + return 0; + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +cntbt_rec_offset( + void *obj, + int startoff, + int idx) +{ + xfs_alloc_block_t *block; + xfs_alloc_rec_t *rp; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) == 0); + rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, idx, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_alloc, 1)); + return bitize((int)((char *)rp - (char *)block)); +} + +/*ARGSUSED*/ +int +cntbt_size( + void *obj, + int startoff, + int idx) +{ + return bitize(mp->m_sb.sb_blocksize); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/cntbt.h linux-2.4-xfs/cmd/xfsprogs/db/cntbt.h --- linux-2.4.7/cmd/xfsprogs/db/cntbt.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/cntbt.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct field; + +extern const struct field cntbt_flds[]; +extern const struct field cntbt_hfld[]; +extern const struct field cntbt_key_flds[]; +extern const struct field cntbt_rec_flds[]; + +extern int cntbt_size(void *obj, int startoff, int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/command.c linux-2.4-xfs/cmd/xfsprogs/db/command.c --- linux-2.4.7/cmd/xfsprogs/db/command.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/command.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "addr.h" +#include "agf.h" +#include "agfl.h" +#include "agi.h" +#include "block.h" +#include "bmap.h" +#include "check.h" +#include "command.h" +#include "convert.h" +#include "debug.h" +#include "type.h" +#include "echo.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "frag.h" +#include "freesp.h" +#include "help.h" +#include "hash.h" +#include "inode.h" +#include "input.h" +#include "io.h" +#include "output.h" +#include "print.h" +#include "quit.h" +#include "sb.h" +#include "uuid.h" +#include "write.h" +#include "malloc.h" +#include "dquot.h" + +cmdinfo_t *cmdtab; +int ncmds; + +static int cmd_compare(const void *a, const void *b); + +static int +cmd_compare(const void *a, const void *b) +{ + return strcmp(((const cmdinfo_t *)a)->name, + ((const cmdinfo_t *)b)->name); +} + +void +add_command( + const cmdinfo_t *ci) +{ + cmdtab = xrealloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab)); + cmdtab[ncmds - 1] = *ci; + qsort(cmdtab, ncmds, sizeof(*cmdtab), cmd_compare); +} + +int +command( + int argc, + char **argv) +{ + char *cmd; + const cmdinfo_t *ct; + + cmd = argv[0]; + ct = find_command(cmd); + if (ct == NULL) { + dbprintf("command %s not found\n", cmd); + return 0; + } + if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) { + dbprintf("bad argument count %d to %s, expected ", argc-1, cmd); + if (ct->argmax == -1) + dbprintf("at least %d", ct->argmin); + else if (ct->argmin == ct->argmax) + dbprintf("%d", ct->argmin); + else + dbprintf("between %d and %d", ct->argmin, ct->argmax); + dbprintf(" arguments\n"); + return 0; + } + optind = 0; + return ct->cfunc(argc, argv); +} + +const cmdinfo_t * +find_command( + const char *cmd) +{ + cmdinfo_t *ct; + + for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) { + if (strcmp(ct->name, cmd) == 0 || + (ct->altname && strcmp(ct->altname, cmd) == 0)) + return (const cmdinfo_t *)ct; + } + return NULL; +} + +void +init_commands(void) +{ + addr_init(); + agf_init(); + agfl_init(); + agi_init(); + block_init(); + bmap_init(); + check_init(); + convert_init(); + debug_init(); + echo_init(); + frag_init(); + freesp_init(); + help_init(); + hash_init(); + inode_init(); + input_init(); + io_init(); + output_init(); + print_init(); + quit_init(); + sb_init(); + uuid_init(); + type_init(); + write_init(); + dquot_init(); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/command.h linux-2.4-xfs/cmd/xfsprogs/db/command.h --- linux-2.4.7/cmd/xfsprogs/db/command.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/command.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +typedef int (*cfunc_t)(int argc, char **argv); +typedef void (*helpfunc_t)(void); + +typedef struct cmdinfo +{ + const char *name; + const char *altname; + cfunc_t cfunc; + int argmin; + int argmax; + int canpush; + const char *args; + const char *oneline; + helpfunc_t help; +} cmdinfo_t; + +extern cmdinfo_t *cmdtab; +extern int ncmds; + +extern void add_command(const cmdinfo_t *ci); +extern int command(int argc, char **argv); +extern const cmdinfo_t *find_command(const char *cmd); +extern void init_commands(void); diff -rNu linux-2.4.7/cmd/xfsprogs/db/convert.c linux-2.4-xfs/cmd/xfsprogs/db/convert.c --- linux-2.4.7/cmd/xfsprogs/db/convert.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/convert.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "command.h" +#include "data.h" +#include "convert.h" +#include "output.h" +#include "mount.h" + +#define M(A) (1 << CT_ ## A) +#define agblock_to_bytes(x) \ + ((__uint64_t)(x) << mp->m_sb.sb_blocklog) +#define agino_to_bytes(x) \ + ((__uint64_t)(x) << mp->m_sb.sb_inodelog) +#define agnumber_to_bytes(x) \ + agblock_to_bytes((__uint64_t)(x) * mp->m_sb.sb_agblocks) +#define daddr_to_bytes(x) \ + ((__uint64_t)(x) << BBSHIFT) +#define fsblock_to_bytes(x) \ + (agnumber_to_bytes(XFS_FSB_TO_AGNO(mp, (x))) + \ + agblock_to_bytes(XFS_FSB_TO_AGBNO(mp, (x)))) +#define ino_to_bytes(x) \ + (agnumber_to_bytes(XFS_INO_TO_AGNO(mp, (x))) + \ + agino_to_bytes(XFS_INO_TO_AGINO(mp, (x)))) +#define inoidx_to_bytes(x) \ + ((__uint64_t)(x) << mp->m_sb.sb_inodelog) + +typedef enum { + CT_NONE = -1, + CT_AGBLOCK, /* xfs_agblock_t */ + CT_AGINO, /* xfs_agino_t */ + CT_AGNUMBER, /* xfs_agno_t */ + CT_BBOFF, /* byte offset in daddr */ + CT_BLKOFF, /* byte offset in fsb/agb */ + CT_BYTE, /* byte in filesystem */ + CT_DADDR, /* daddr_t */ + CT_FSBLOCK, /* xfs_fsblock_t */ + CT_INO, /* xfs_ino_t */ + CT_INOIDX, /* index of inode in fsblock */ + CT_INOOFF, /* byte offset in inode */ + NCTS +} ctype_t; + +typedef struct ctydesc { + ctype_t ctype; + int allowed; + const char **names; +} ctydesc_t; + +typedef union { + xfs_agblock_t agblock; + xfs_agino_t agino; + xfs_agnumber_t agnumber; + int bboff; + int blkoff; + __uint64_t byte; + xfs_daddr_t daddr; + xfs_fsblock_t fsblock; + xfs_ino_t ino; + int inoidx; + int inooff; +} cval_t; + +static __uint64_t bytevalue(ctype_t ctype, cval_t *val); +static int convert_f(int argc, char **argv); +static int getvalue(char *s, ctype_t ctype, cval_t *val); +static ctype_t lookupcty(char *ctyname); + +static const char *agblock_names[] = { "agblock", "agbno", NULL }; +static const char *agino_names[] = { "agino", "aginode", NULL }; +static const char *agnumber_names[] = { "agnumber", "agno", NULL }; +static const char *bboff_names[] = { "bboff", "daddroff", NULL }; +static const char *blkoff_names[] = { "blkoff", "fsboff", "agboff", + NULL }; +static const char *byte_names[] = { "byte", "fsbyte", NULL }; +static const char *daddr_names[] = { "daddr", "bb", NULL }; +static const char *fsblock_names[] = { "fsblock", "fsb", "fsbno", NULL }; +static const char *ino_names[] = { "ino", "inode", NULL }; +static const char *inoidx_names[] = { "inoidx", "offset", NULL }; +static const char *inooff_names[] = { "inooff", "inodeoff", NULL }; + +static const ctydesc_t ctydescs[NCTS] = { + { CT_AGBLOCK, M(AGNUMBER)|M(BBOFF)|M(BLKOFF)|M(INOIDX)|M(INOOFF), + agblock_names }, + { CT_AGINO, M(AGNUMBER)|M(INOOFF), agino_names }, + { CT_AGNUMBER, + M(AGBLOCK)|M(AGINO)|M(BBOFF)|M(BLKOFF)|M(INOIDX)|M(INOOFF), + agnumber_names }, + { CT_BBOFF, M(AGBLOCK)|M(AGNUMBER)|M(DADDR)|M(FSBLOCK), bboff_names }, + { CT_BLKOFF, M(AGBLOCK)|M(AGNUMBER)|M(FSBLOCK), blkoff_names }, + { CT_BYTE, 0, byte_names }, + { CT_DADDR, M(BBOFF), daddr_names }, + { CT_FSBLOCK, M(BBOFF)|M(BLKOFF)|M(INOIDX), fsblock_names }, + { CT_INO, M(INOOFF), ino_names }, + { CT_INOIDX, M(AGBLOCK)|M(AGNUMBER)|M(FSBLOCK)|M(INOOFF), + inoidx_names }, + { CT_INOOFF, + M(AGBLOCK)|M(AGINO)|M(AGNUMBER)|M(FSBLOCK)|M(INO)|M(INOIDX), + inooff_names }, +}; + +static const cmdinfo_t convert_cmd = + { "convert", NULL, convert_f, 3, 9, 0, "type num [type num]... type", + "convert from one address form to another", NULL }; + +static __uint64_t +bytevalue(ctype_t ctype, cval_t *val) +{ + switch (ctype) { + case CT_AGBLOCK: + return agblock_to_bytes(val->agblock); + case CT_AGINO: + return agino_to_bytes(val->agino); + case CT_AGNUMBER: + return agnumber_to_bytes(val->agnumber); + case CT_BBOFF: + return (__uint64_t)val->bboff; + case CT_BLKOFF: + return (__uint64_t)val->blkoff; + case CT_BYTE: + return val->byte; + case CT_DADDR: + return daddr_to_bytes(val->daddr); + case CT_FSBLOCK: + return fsblock_to_bytes(val->fsblock); + case CT_INO: + return ino_to_bytes(val->ino); + case CT_INOIDX: + return inoidx_to_bytes(val->inoidx); + case CT_INOOFF: + return (__uint64_t)val->inooff; + case CT_NONE: + case NCTS: + } + /* NOTREACHED */ + return 0; +} + +static int +convert_f(int argc, char **argv) +{ + ctype_t c; + int conmask; + cval_t cvals[NCTS]; + int i; + int mask; + __uint64_t v; + ctype_t wtype; + + /* move past the "convert" command */ + argc--; + argv++; + + if ((argc % 2) != 1) { + dbprintf("bad argument count %d to convert, expected 3,5,7,9 " + "arguments\n", argc); + return 0; + } + if ((wtype = lookupcty(argv[argc - 1])) == CT_NONE) { + dbprintf("unknown conversion type %s\n", argv[argc - 1]); + return 0; + } + + for (i = mask = conmask = 0; i < (argc - 1) / 2; i++) { + c = lookupcty(argv[i * 2]); + if (c == CT_NONE) { + dbprintf("unknown conversion type %s\n", argv[i * 2]); + return 0; + } + if (c == wtype) { + dbprintf("result type same as argument\n"); + return 0; + } + if (conmask & (1 << c)) { + dbprintf("conflicting conversion type %s\n", + argv[i * 2]); + return 0; + } + if (!getvalue(argv[i * 2 + 1], c, &cvals[c])) + return 0; + mask |= 1 << c; + conmask |= ~ctydescs[c].allowed; + } + if (cur_agno != NULLAGNUMBER && (conmask & M(AGNUMBER)) == 0) { + cvals[CT_AGNUMBER].agnumber = cur_agno; + mask |= M(AGNUMBER); + conmask |= ~ctydescs[CT_AGNUMBER].allowed; + } + v = 0; + for (c = (ctype_t)0; c < NCTS; c++) { + if (!(mask & (1 << c))) + continue; + v += bytevalue(c, &cvals[c]); + } + switch (wtype) { + case CT_AGBLOCK: + v = XFS_DADDR_TO_AGBNO(mp, v >> BBSHIFT); + break; + case CT_AGINO: + v = (v >> mp->m_sb.sb_inodelog) % + (mp->m_sb.sb_agblocks << mp->m_sb.sb_inopblog); + break; + case CT_AGNUMBER: + v = XFS_DADDR_TO_AGNO(mp, v >> BBSHIFT); + break; + case CT_BBOFF: + v &= BBMASK; + break; + case CT_BLKOFF: + v &= mp->m_blockmask; + break; + case CT_BYTE: + break; + case CT_DADDR: + v >>= BBSHIFT; + break; + case CT_FSBLOCK: + v = XFS_DADDR_TO_FSB(mp, v >> BBSHIFT); + break; + case CT_INO: + v = XFS_AGINO_TO_INO(mp, XFS_DADDR_TO_AGNO(mp, v >> BBSHIFT), + (v >> mp->m_sb.sb_inodelog) % + (mp->m_sb.sb_agblocks << mp->m_sb.sb_inopblog)); + break; + case CT_INOIDX: + v = (v >> mp->m_sb.sb_inodelog) & (mp->m_sb.sb_inopblock - 1); + break; + case CT_INOOFF: + v &= mp->m_sb.sb_inodesize - 1; + break; + case CT_NONE: + case NCTS: + /* NOTREACHED */ + } + dbprintf("0x%llx (%llu)\n", v, v); + return 0; +} + +void +convert_init(void) +{ + add_command(&convert_cmd); +} + +static int +getvalue(char *s, ctype_t ctype, cval_t *val) +{ + char *p; + __uint64_t v; + + v = strtoull(s, &p, 0); + if (*p != '\0') { + dbprintf("%s is not a number\n", s); + return 0; + } + switch (ctype) { + case CT_AGBLOCK: + val->agblock = (xfs_agblock_t)v; + break; + case CT_AGINO: + val->agino = (xfs_agino_t)v; + break; + case CT_AGNUMBER: + val->agnumber = (xfs_agnumber_t)v; + break; + case CT_BBOFF: + val->bboff = (int)v; + break; + case CT_BLKOFF: + val->blkoff = (int)v; + break; + case CT_BYTE: + val->byte = (__uint64_t)v; + break; + case CT_DADDR: + val->daddr = (xfs_daddr_t)v; + break; + case CT_FSBLOCK: + val->fsblock = (xfs_fsblock_t)v; + break; + case CT_INO: + val->ino = (xfs_ino_t)v; + break; + case CT_INOIDX: + val->inoidx = (int)v; + break; + case CT_INOOFF: + val->inooff = (int)v; + break; + case CT_NONE: + case NCTS: + /* NOTREACHED */ + } + return 1; +} + +static ctype_t +lookupcty(char *ctyname) +{ + ctype_t cty; + const char **name; + + for (cty = (ctype_t)0; cty < NCTS; cty++) { + for (name = ctydescs[cty].names; *name; name++) { + if (strcmp(ctyname, *name) == 0) + return cty; + } + } + return CT_NONE; +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/convert.h linux-2.4-xfs/cmd/xfsprogs/db/convert.h --- linux-2.4.7/cmd/xfsprogs/db/convert.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/convert.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern void convert_init(void); diff -rNu linux-2.4.7/cmd/xfsprogs/db/data.c linux-2.4-xfs/cmd/xfsprogs/db/data.c --- linux-2.4.7/cmd/xfsprogs/db/data.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/data.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "data.h" + +int blkbb; +xfs_agnumber_t cur_agno = NULLAGNUMBER; +int exitcode; +int flag_expert_mode = 0; +int flag_readonly = 0; +libxfs_init_t xfsargs; diff -rNu linux-2.4.7/cmd/xfsprogs/db/data.h linux-2.4-xfs/cmd/xfsprogs/db/data.h --- linux-2.4.7/cmd/xfsprogs/db/data.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/data.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern int blkbb; +extern xfs_agnumber_t cur_agno; +extern int exitcode; +extern int flag_expert_mode; +extern int flag_readonly; +extern int flag_arch; +extern libxfs_init_t xfsargs; diff -rNu linux-2.4.7/cmd/xfsprogs/db/dbread.c linux-2.4-xfs/cmd/xfsprogs/db/dbread.c --- linux-2.4.7/cmd/xfsprogs/db/dbread.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/dbread.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "bmap.h" +#include "data.h" +#include "dbread.h" +#include "io.h" +#include "mount.h" + +int +dbread(void *buf, int nblocks, xfs_fileoff_t bno, int whichfork) +{ + bmap_ext_t bm; + char *bp; + xfs_dfiloff_t eb; + xfs_dfiloff_t end; + int i; + int nex; + + nex = 1; + end = bno + nblocks; + bp = buf; + while (bno < end) { + bmap(bno, end - bno, whichfork, &nex, &bm); + if (nex == 0) { + bm.startoff = end; + bm.blockcount = 1; + } + if (bm.startoff > bno) { + eb = end < bm.startoff ? end : bm.startoff; + i = (int)XFS_FSB_TO_B(mp, eb - bno); + memset(bp, 0, i); + bp += i; + bno = eb; + } + if (bno == end) + break; + if (bno > bm.startoff) { + bm.blockcount -= bno - bm.startoff; + bm.startblock += bno - bm.startoff; + bm.startoff = bno; + } + if (bm.startoff + bm.blockcount > end) + bm.blockcount = end - bm.startoff; + i = read_bbs(XFS_FSB_TO_DADDR(mp, bm.startblock), + (int)XFS_FSB_TO_BB(mp, bm.blockcount), + (void **)&bp, NULL); + if (i) + return i; + bp += XFS_FSB_TO_B(mp, bm.blockcount); + bno += bm.blockcount; + } + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/dbread.h linux-2.4-xfs/cmd/xfsprogs/db/dbread.h --- linux-2.4.7/cmd/xfsprogs/db/dbread.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/dbread.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern int dbread(void *buf, int nblocks, xfs_fileoff_t bno, + int whichfork); diff -rNu linux-2.4.7/cmd/xfsprogs/db/debug.c linux-2.4-xfs/cmd/xfsprogs/db/debug.c --- linux-2.4.7/cmd/xfsprogs/db/debug.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/debug.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "command.h" +#include "debug.h" +#include "output.h" + +static int debug_f(int argc, char **argv); + +static const cmdinfo_t debug_cmd = + { "debug", NULL, debug_f, 0, 1, 0, "[flagbits]", + "set debug option bits", NULL }; + +long debug_state; + +static int +debug_f( + int argc, + char **argv) +{ + char *p; + + if (argc > 1) { + debug_state = strtol(argv[1], &p, 0); + if (*p != '\0') { + dbprintf("bad value for debug %s\n", argv[1]); + return 0; + } + } + dbprintf("debug = %ld\n", debug_state); + return 0; +} + +void +debug_init(void) +{ + add_command(&debug_cmd); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/debug.h linux-2.4-xfs/cmd/xfsprogs/db/debug.h --- linux-2.4.7/cmd/xfsprogs/db/debug.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/debug.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#define DEBUG_FLIST 0x1 + +extern long debug_state; +extern void debug_init(void); diff -rNu linux-2.4.7/cmd/xfsprogs/db/dir.c linux-2.4-xfs/cmd/xfsprogs/db/dir.c --- linux-2.4.7/cmd/xfsprogs/db/dir.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/dir.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "bit.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "dir.h" +#include "io.h" +#include "data.h" +#include "mount.h" + +static int dir_leaf_entries_count(void *obj, int startoff); +static int dir_leaf_hdr_count(void *obj, int startoff); +static int dir_leaf_name_count(void *obj, int startoff); +static int dir_leaf_namelist_count(void *obj, int startoff); +static int dir_leaf_namelist_offset(void *obj, int startoff, int idx); +static int dir_node_btree_count(void *obj, int startoff); +static int dir_node_hdr_count(void *obj, int startoff); + +const field_t dir_hfld[] = { + { "", FLDT_DIR, OI(0), C1, 0, TYP_NONE }, + { NULL } +}; + +#define LOFF(f) bitize(offsetof(xfs_dir_leafblock_t, f)) +#define NOFF(f) bitize(offsetof(xfs_da_intnode_t, f)) +const field_t dir_flds[] = { + { "lhdr", FLDT_DIR_LEAF_HDR, OI(LOFF(hdr)), dir_leaf_hdr_count, + FLD_COUNT, TYP_NONE }, + { "nhdr", FLDT_DIR_NODE_HDR, OI(NOFF(hdr)), dir_node_hdr_count, + FLD_COUNT, TYP_NONE }, + { "entries", FLDT_DIR_LEAF_ENTRY, OI(LOFF(entries)), + dir_leaf_entries_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, + { "btree", FLDT_DIR_NODE_ENTRY, OI(NOFF(btree)), + dir_node_btree_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, + { "namelist", FLDT_DIR_LEAF_NAME, dir_leaf_namelist_offset, + dir_leaf_namelist_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, + { NULL } +}; + +#define BOFF(f) bitize(offsetof(xfs_da_blkinfo_t, f)) +const field_t dir_blkinfo_flds[] = { + { "forw", FLDT_DIRBLOCK, OI(BOFF(forw)), C1, 0, TYP_INODATA }, + { "back", FLDT_DIRBLOCK, OI(BOFF(back)), C1, 0, TYP_INODATA }, + { "magic", FLDT_UINT16X, OI(BOFF(magic)), C1, 0, TYP_NONE }, + { "pad", FLDT_UINT16X, OI(BOFF(pad)), C1, FLD_SKIPALL, TYP_NONE }, + { NULL } +}; + +#define LEOFF(f) bitize(offsetof(xfs_dir_leaf_entry_t, f)) +const field_t dir_leaf_entry_flds[] = { + { "hashval", FLDT_UINT32X, OI(LEOFF(hashval)), C1, 0, TYP_NONE }, + { "nameidx", FLDT_UINT16D, OI(LEOFF(nameidx)), C1, 0, TYP_NONE }, + { "namelen", FLDT_UINT8D, OI(LEOFF(namelen)), C1, 0, TYP_NONE }, + { "pad2", FLDT_UINT8X, OI(LEOFF(pad2)), C1, FLD_SKIPALL, TYP_NONE }, + { NULL } +}; + +#define LHOFF(f) bitize(offsetof(xfs_dir_leaf_hdr_t, f)) +const field_t dir_leaf_hdr_flds[] = { + { "info", FLDT_DIR_BLKINFO, OI(LHOFF(info)), C1, 0, TYP_NONE }, + { "count", FLDT_UINT16D, OI(LHOFF(count)), C1, 0, TYP_NONE }, + { "namebytes", FLDT_UINT16D, OI(LHOFF(namebytes)), C1, 0, TYP_NONE }, + { "firstused", FLDT_UINT16D, OI(LHOFF(firstused)), C1, 0, TYP_NONE }, + { "holes", FLDT_UINT8D, OI(LHOFF(holes)), C1, 0, TYP_NONE }, + { "pad1", FLDT_UINT8X, OI(LHOFF(pad1)), C1, FLD_SKIPALL, TYP_NONE }, + { "freemap", FLDT_DIR_LEAF_MAP, OI(LHOFF(freemap)), + CI(XFS_DIR_LEAF_MAPSIZE), FLD_ARRAY, TYP_NONE }, + { NULL } +}; + +#define LMOFF(f) bitize(offsetof(xfs_dir_leaf_map_t, f)) +const field_t dir_leaf_map_flds[] = { + { "base", FLDT_UINT16D, OI(LMOFF(base)), C1, 0, TYP_NONE }, + { "size", FLDT_UINT16D, OI(LMOFF(size)), C1, 0, TYP_NONE }, + { NULL } +}; + +#define LNOFF(f) bitize(offsetof(xfs_dir_leaf_name_t, f)) +const field_t dir_leaf_name_flds[] = { + { "inumber", FLDT_DIR_INO, OI(LNOFF(inumber)), C1, 0, TYP_INODE }, + { "name", FLDT_CHARNS, OI(LNOFF(name)), dir_leaf_name_count, FLD_COUNT, + TYP_NONE }, + { NULL } +}; + +#define EOFF(f) bitize(offsetof(xfs_da_node_entry_t, f)) +const field_t dir_node_entry_flds[] = { + { "hashval", FLDT_UINT32X, OI(EOFF(hashval)), C1, 0, TYP_NONE }, + { "before", FLDT_DIRBLOCK, OI(EOFF(before)), C1, 0, TYP_INODATA }, + { NULL } +}; + +#define HOFF(f) bitize(offsetof(xfs_da_node_hdr_t, f)) +const field_t dir_node_hdr_flds[] = { + { "info", FLDT_DIR_BLKINFO, OI(HOFF(info)), C1, 0, TYP_NONE }, + { "count", FLDT_UINT16D, OI(HOFF(count)), C1, 0, TYP_NONE }, + { "level", FLDT_UINT16D, OI(HOFF(level)), C1, 0, TYP_NONE }, + { NULL } +}; + +/*ARGSUSED*/ +static int +dir_leaf_entries_count( + void *obj, + int startoff) +{ + xfs_dir_leafblock_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) + return 0; + return INT_GET(block->hdr.count, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +dir_leaf_hdr_count( + void *obj, + int startoff) +{ + xfs_dir_leafblock_t *block; + + ASSERT(startoff == 0); + block = obj; + return INT_GET(block->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC; +} + +static int +dir_leaf_name_count( + void *obj, + int startoff) +{ + xfs_dir_leafblock_t *block; + xfs_dir_leaf_entry_t *e; + int i; + int off; + + ASSERT(bitoffs(startoff) == 0); + off = byteize(startoff); + block = obj; + if (INT_GET(block->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) + return 0; + for (i = 0; i < INT_GET(block->hdr.count, ARCH_CONVERT); i++) { + e = &block->entries[i]; + if (INT_GET(e->nameidx, ARCH_CONVERT) == off) + return e->namelen; + } + return 0; +} + +/*ARGSUSED*/ +int +dir_leaf_name_size( + void *obj, + int startoff, + int idx) +{ + xfs_dir_leafblock_t *block; + xfs_dir_leaf_entry_t *e; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) + return 0; + e = &block->entries[idx]; + return bitize((int)XFS_DIR_LEAF_ENTSIZE_BYENTRY(e)); +} + +/*ARGSUSED*/ +static int +dir_leaf_namelist_count( + void *obj, + int startoff) +{ + xfs_dir_leafblock_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) + return 0; + return INT_GET(block->hdr.count, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +dir_leaf_namelist_offset( + void *obj, + int startoff, + int idx) +{ + xfs_dir_leafblock_t *block; + xfs_dir_leaf_entry_t *e; + + ASSERT(startoff == 0); + block = obj; + e = &block->entries[idx]; + return bitize(INT_GET(e->nameidx, ARCH_CONVERT)); +} + +/*ARGSUSED*/ +static int +dir_node_btree_count( + void *obj, + int startoff) +{ + xfs_da_intnode_t *block; + + ASSERT(startoff == 0); /* this is a base structure */ + block = obj; + if (INT_GET(block->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) + return 0; + return INT_GET(block->hdr.count, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +dir_node_hdr_count( + void *obj, + int startoff) +{ + xfs_da_intnode_t *block; + + ASSERT(startoff == 0); + block = obj; + return INT_GET(block->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC; +} + +/*ARGSUSED*/ +int +dir_size( + void *obj, + int startoff, + int idx) +{ + return bitize(mp->m_sb.sb_blocksize); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/dir.h linux-2.4-xfs/cmd/xfsprogs/db/dir.h --- linux-2.4.7/cmd/xfsprogs/db/dir.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/dir.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern const field_t dir_flds[]; +extern const field_t dir_hfld[]; +extern const field_t dir_blkinfo_flds[]; +extern const field_t dir_leaf_entry_flds[]; +extern const field_t dir_leaf_hdr_flds[]; +extern const field_t dir_leaf_map_flds[]; +extern const field_t dir_leaf_name_flds[]; +extern const field_t dir_node_entry_flds[]; +extern const field_t dir_node_hdr_flds[]; + +extern int dir_leaf_name_size(void *obj, int startoff, int idx); +extern int dir_size(void *obj, int startoff, int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/dir2.c linux-2.4-xfs/cmd/xfsprogs/db/dir2.c --- linux-2.4.7/cmd/xfsprogs/db/dir2.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/dir2.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,727 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "bit.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "dir.h" +#include "dir2.h" +#include "mount.h" +#include "data.h" + +static int dir2_block_hdr_count(void *obj, int startoff); +static int dir2_block_leaf_count(void *obj, int startoff); +static int dir2_block_leaf_offset(void *obj, int startoff, int idx); +static int dir2_block_tail_count(void *obj, int startoff); +static int dir2_block_tail_offset(void *obj, int startoff, int idx); +static int dir2_block_u_count(void *obj, int startoff); +static int dir2_block_u_offset(void *obj, int startoff, int idx); +static int dir2_data_union_freetag_count(void *obj, int startoff); +static int dir2_data_union_inumber_count(void *obj, int startoff); +static int dir2_data_union_length_count(void *obj, int startoff); +static int dir2_data_union_name_count(void *obj, int startoff); +static int dir2_data_union_namelen_count(void *obj, int startoff); +static int dir2_data_union_tag_count(void *obj, int startoff); +static int dir2_data_union_tag_offset(void *obj, int startoff, int idx); +static int dir2_data_hdr_count(void *obj, int startoff); +static int dir2_data_u_count(void *obj, int startoff); +static int dir2_data_u_offset(void *obj, int startoff, int idx); +static int dir2_free_bests_count(void *obj, int startoff); +static int dir2_free_hdr_count(void *obj, int startoff); +static int dir2_leaf_bests_count(void *obj, int startoff); +static int dir2_leaf_bests_offset(void *obj, int startoff, int idx); +static int dir2_leaf_ents_count(void *obj, int startoff); +static int dir2_leaf_hdr_count(void *obj, int startoff); +static int dir2_leaf_tail_count(void *obj, int startoff); +static int dir2_leaf_tail_offset(void *obj, int startoff, int idx); +static int dir2_node_btree_count(void *obj, int startoff); +static int dir2_node_hdr_count(void *obj, int startoff); + +const field_t dir2_hfld[] = { + { "", FLDT_DIR2, OI(0), C1, 0, TYP_NONE }, + { NULL } +}; + +#define BOFF(f) bitize(offsetof(xfs_dir2_block_t, f)) +#define DOFF(f) bitize(offsetof(xfs_dir2_data_t, f)) +#define FOFF(f) bitize(offsetof(xfs_dir2_free_t, f)) +#define LOFF(f) bitize(offsetof(xfs_dir2_leaf_t, f)) +#define NOFF(f) bitize(offsetof(xfs_da_intnode_t, f)) +const field_t dir2_flds[] = { + { "bhdr", FLDT_DIR2_DATA_HDR, OI(BOFF(hdr)), dir2_block_hdr_count, + FLD_COUNT, TYP_NONE }, + { "bu", FLDT_DIR2_DATA_UNION, dir2_block_u_offset, dir2_block_u_count, + FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, + { "bleaf", FLDT_DIR2_LEAF_ENTRY, dir2_block_leaf_offset, + dir2_block_leaf_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, + { "btail", FLDT_DIR2_BLOCK_TAIL, dir2_block_tail_offset, + dir2_block_tail_count, FLD_OFFSET|FLD_COUNT, TYP_NONE }, + { "dhdr", FLDT_DIR2_DATA_HDR, OI(DOFF(hdr)), dir2_data_hdr_count, + FLD_COUNT, TYP_NONE }, + { "du", FLDT_DIR2_DATA_UNION, dir2_data_u_offset, dir2_data_u_count, + FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, + { "lhdr", FLDT_DIR2_LEAF_HDR, OI(LOFF(hdr)), dir2_leaf_hdr_count, + FLD_COUNT, TYP_NONE }, + { "lbests", FLDT_DIR2_DATA_OFF, dir2_leaf_bests_offset, + dir2_leaf_bests_count, FLD_ARRAY|FLD_OFFSET|FLD_COUNT, TYP_NONE }, + { "lents", FLDT_DIR2_LEAF_ENTRY, OI(LOFF(ents)), dir2_leaf_ents_count, + FLD_ARRAY|FLD_COUNT, TYP_NONE }, + { "ltail", FLDT_DIR2_LEAF_TAIL, dir2_leaf_tail_offset, + dir2_leaf_tail_count, FLD_OFFSET|FLD_COUNT, TYP_NONE }, + { "nhdr", FLDT_DIR_NODE_HDR, OI(NOFF(hdr)), dir2_node_hdr_count, + FLD_COUNT, TYP_NONE }, + { "nbtree", FLDT_DIR_NODE_ENTRY, OI(NOFF(btree)), dir2_node_btree_count, + FLD_ARRAY|FLD_COUNT, TYP_NONE }, + { "fhdr", FLDT_DIR2_FREE_HDR, OI(FOFF(hdr)), dir2_free_hdr_count, + FLD_COUNT, TYP_NONE }, + { "fbests", FLDT_DIR2_DATA_OFFNZ, OI(FOFF(bests)), + dir2_free_bests_count, FLD_ARRAY|FLD_COUNT, TYP_NONE }, + { NULL } +}; + +#define BTOFF(f) bitize(offsetof(xfs_dir2_block_tail_t, f)) +const field_t dir2_block_tail_flds[] = { + { "count", FLDT_UINT32D, OI(BTOFF(count)), C1, 0, TYP_NONE }, + { "stale", FLDT_UINT32D, OI(BTOFF(stale)), C1, 0, TYP_NONE }, + { NULL } +}; + +#define DFOFF(f) bitize(offsetof(xfs_dir2_data_free_t, f)) +const field_t dir2_data_free_flds[] = { + { "offset", FLDT_DIR2_DATA_OFF, OI(DFOFF(offset)), C1, 0, TYP_NONE }, + { "length", FLDT_DIR2_DATA_OFF, OI(DFOFF(length)), C1, 0, TYP_NONE }, + { NULL } +}; + +#define DHOFF(f) bitize(offsetof(xfs_dir2_data_hdr_t, f)) +const field_t dir2_data_hdr_flds[] = { + { "magic", FLDT_UINT32X, OI(DHOFF(magic)), C1, 0, TYP_NONE }, + { "bestfree", FLDT_DIR2_DATA_FREE, OI(DHOFF(bestfree)), + CI(XFS_DIR2_DATA_FD_COUNT), FLD_ARRAY, TYP_NONE }, + { NULL } +}; + +#define DEOFF(f) bitize(offsetof(xfs_dir2_data_entry_t, f)) +#define DUOFF(f) bitize(offsetof(xfs_dir2_data_unused_t, f)) +const field_t dir2_data_union_flds[] = { + { "freetag", FLDT_UINT16X, OI(DUOFF(freetag)), + dir2_data_union_freetag_count, FLD_COUNT, TYP_NONE }, + { "inumber", FLDT_INO, OI(DEOFF(inumber)), + dir2_data_union_inumber_count, FLD_COUNT, TYP_INODE }, + { "length", FLDT_DIR2_DATA_OFF, OI(DUOFF(length)), + dir2_data_union_length_count, FLD_COUNT, TYP_NONE }, + { "namelen", FLDT_UINT8D, OI(DEOFF(namelen)), + dir2_data_union_namelen_count, FLD_COUNT, TYP_NONE }, + { "name", FLDT_CHARNS, OI(DEOFF(name)), dir2_data_union_name_count, + FLD_COUNT, TYP_NONE }, + { "tag", FLDT_DIR2_DATA_OFF, dir2_data_union_tag_offset, + dir2_data_union_tag_count, FLD_OFFSET|FLD_COUNT, TYP_NONE }, + { NULL } +}; + +#define LEOFF(f) bitize(offsetof(xfs_dir2_leaf_entry_t, f)) +const field_t dir2_leaf_entry_flds[] = { + { "hashval", FLDT_UINT32X, OI(LEOFF(hashval)), C1, 0, TYP_NONE }, + { "address", FLDT_UINT32X, OI(LEOFF(address)), C1, 0, TYP_NONE }, + { NULL } +}; + +#define LHOFF(f) bitize(offsetof(xfs_dir2_leaf_hdr_t, f)) +const field_t dir2_leaf_hdr_flds[] = { + { "info", FLDT_DIR_BLKINFO, OI(LHOFF(info)), C1, 0, TYP_NONE }, + { "count", FLDT_UINT16D, OI(LHOFF(count)), C1, 0, TYP_NONE }, + { "stale", FLDT_UINT16D, OI(LHOFF(stale)), C1, 0, TYP_NONE }, + { NULL } +}; + +#define LTOFF(f) bitize(offsetof(xfs_dir2_leaf_tail_t, f)) +const field_t dir2_leaf_tail_flds[] = { + { "bestcount", FLDT_UINT32D, OI(LTOFF(bestcount)), C1, 0, TYP_NONE }, + { NULL } +}; + +#define FHOFF(f) bitize(offsetof(xfs_dir2_free_hdr_t, f)) +const field_t dir2_free_hdr_flds[] = { + { "magic", FLDT_UINT32X, OI(FHOFF(magic)), C1, 0, TYP_NONE }, + { "firstdb", FLDT_INT32D, OI(FHOFF(firstdb)), C1, 0, TYP_NONE }, + { "nvalid", FLDT_INT32D, OI(FHOFF(nvalid)), C1, 0, TYP_NONE }, + { "nused", FLDT_INT32D, OI(FHOFF(nused)), C1, 0, TYP_NONE }, + { NULL } +}; + +/*ARGSUSED*/ +static int +dir2_block_hdr_count( + void *obj, + int startoff) +{ + xfs_dir2_block_t *block; + + ASSERT(startoff == 0); + block = obj; + return INT_GET(block->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC; +} + +/*ARGSUSED*/ +static int +dir2_block_leaf_count( + void *obj, + int startoff) +{ + xfs_dir2_block_t *block; + xfs_dir2_block_tail_t *btp; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->hdr.magic, ARCH_CONVERT) != XFS_DIR2_BLOCK_MAGIC) + return 0; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + return INT_GET(btp->count, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +dir2_block_leaf_offset( + void *obj, + int startoff, + int idx) +{ + xfs_dir2_block_t *block; + xfs_dir2_block_tail_t *btp; + xfs_dir2_leaf_entry_t *lep; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + lep = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT) + idx; + return bitize((int)((char *)lep - (char *)block)); +} + +/*ARGSUSED*/ +static int +dir2_block_tail_count( + void *obj, + int startoff) +{ + xfs_dir2_block_t *block; + + ASSERT(startoff == 0); + block = obj; + return INT_GET(block->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC; +} + +/*ARGSUSED*/ +static int +dir2_block_tail_offset( + void *obj, + int startoff, + int idx) +{ + xfs_dir2_block_t *block; + xfs_dir2_block_tail_t *btp; + + ASSERT(startoff == 0); + ASSERT(idx == 0); + block = obj; + ASSERT(INT_GET(block->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + return bitize((int)((char *)btp - (char *)block)); +} + +/*ARGSUSED*/ +static int +dir2_block_u_count( + void *obj, + int startoff) +{ + xfs_dir2_block_t *block; + xfs_dir2_block_tail_t *btp; + xfs_dir2_data_entry_t *dep; + xfs_dir2_data_unused_t *dup; + char *endptr; + int i; + char *ptr; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->hdr.magic, ARCH_CONVERT) != XFS_DIR2_BLOCK_MAGIC) + return 0; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + ptr = (char *)block->u; + endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + for (i = 0; ptr < endptr; i++) { + dup = (xfs_dir2_data_unused_t *)ptr; + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) + ptr += INT_GET(dup->length, ARCH_CONVERT); + else { + dep = (xfs_dir2_data_entry_t *)ptr; + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + } + return i; +} + +/*ARGSUSED*/ +static int +dir2_block_u_offset( + void *obj, + int startoff, + int idx) +{ + xfs_dir2_block_t *block; + xfs_dir2_block_tail_t *btp; + xfs_dir2_data_entry_t *dep; + xfs_dir2_data_unused_t *dup; + /*REFERENCED*/ + char *endptr; + int i; + char *ptr; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + ptr = (char *)block->u; + endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + for (i = 0; i < idx; i++) { + ASSERT(ptr < endptr); + dup = (xfs_dir2_data_unused_t *)ptr; + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) + ptr += INT_GET(dup->length, ARCH_CONVERT); + else { + dep = (xfs_dir2_data_entry_t *)ptr; + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + } + return bitize((int)(ptr - (char *)block)); +} + +static int +dir2_data_union_freetag_count( + void *obj, + int startoff) +{ + xfs_dir2_data_unused_t *dup; + char *end; + + ASSERT(bitoffs(startoff) == 0); + dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); + end = (char *)&dup->freetag + sizeof(dup->freetag); + return end <= (char *)obj + mp->m_dirblksize && + INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG; +} + +static int +dir2_data_union_inumber_count( + void *obj, + int startoff) +{ + xfs_dir2_data_entry_t *dep; + xfs_dir2_data_unused_t *dup; + char *end; + + ASSERT(bitoffs(startoff) == 0); + dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); + dep = (xfs_dir2_data_entry_t *)dup; + end = (char *)&dep->inumber + sizeof(dep->inumber); + return end <= (char *)obj + mp->m_dirblksize && + INT_GET(dup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG; +} + +static int +dir2_data_union_length_count( + void *obj, + int startoff) +{ + xfs_dir2_data_unused_t *dup; + char *end; + + ASSERT(bitoffs(startoff) == 0); + dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); + end = (char *)&dup->length + sizeof(dup->length); + return end <= (char *)obj + mp->m_dirblksize && + INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG; +} + +static int +dir2_data_union_name_count( + void *obj, + int startoff) +{ + xfs_dir2_data_entry_t *dep; + xfs_dir2_data_unused_t *dup; + char *end; + + ASSERT(bitoffs(startoff) == 0); + dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); + dep = (xfs_dir2_data_entry_t *)dup; + end = (char *)&dep->namelen + sizeof(dep->namelen); + if (end >= (char *)obj + mp->m_dirblksize || + INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) + return 0; + end = (char *)&dep->name[0] + dep->namelen; + return end <= (char *)obj + mp->m_dirblksize ? dep->namelen : 0; +} + +static int +dir2_data_union_namelen_count( + void *obj, + int startoff) +{ + xfs_dir2_data_entry_t *dep; + xfs_dir2_data_unused_t *dup; + char *end; + + ASSERT(bitoffs(startoff) == 0); + dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); + dep = (xfs_dir2_data_entry_t *)dup; + end = (char *)&dep->namelen + sizeof(dep->namelen); + return end <= (char *)obj + mp->m_dirblksize && + INT_GET(dup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG; +} + +static int +dir2_data_union_tag_count( + void *obj, + int startoff) +{ + xfs_dir2_data_entry_t *dep; + xfs_dir2_data_unused_t *dup; + char *end; + xfs_dir2_data_off_t *tagp; + + ASSERT(bitoffs(startoff) == 0); + dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); + dep = (xfs_dir2_data_entry_t *)dup; + end = (char *)&dup->freetag + sizeof(dup->freetag); + if (end > (char *)obj + mp->m_dirblksize) + return 0; + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + end = (char *)&dup->length + sizeof(dup->length); + if (end > (char *)obj + mp->m_dirblksize) + return 0; + tagp = XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT); + } else { + end = (char *)&dep->namelen + sizeof(dep->namelen); + if (end > (char *)obj + mp->m_dirblksize) + return 0; + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + } + end = (char *)tagp + sizeof(*tagp); + return end <= (char *)obj + mp->m_dirblksize; +} + +/*ARGSUSED*/ +static int +dir2_data_union_tag_offset( + void *obj, + int startoff, + int idx) +{ + xfs_dir2_data_entry_t *dep; + xfs_dir2_data_unused_t *dup; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(idx == 0); + dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) + return bitize((int)((char *)XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT) - + (char *)dup)); + dep = (xfs_dir2_data_entry_t *)dup; + return bitize((int)((char *)XFS_DIR2_DATA_ENTRY_TAG_P(dep) - + (char *)dep)); +} + +/*ARGSUSED*/ +static int +dir2_data_hdr_count( + void *obj, + int startoff) +{ + xfs_dir2_data_t *data; + + ASSERT(startoff == 0); + data = obj; + return INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC; +} + +/*ARGSUSED*/ +static int +dir2_data_u_count( + void *obj, + int startoff) +{ + xfs_dir2_data_t *data; + xfs_dir2_data_entry_t *dep; + xfs_dir2_data_unused_t *dup; + char *endptr; + int i; + char *ptr; + + ASSERT(startoff == 0); + data = obj; + if (INT_GET(data->hdr.magic, ARCH_CONVERT) != XFS_DIR2_DATA_MAGIC) + return 0; + ptr = (char *)data->u; + endptr = (char *)data + mp->m_dirblksize; + for (i = 0; ptr < endptr; i++) { + dup = (xfs_dir2_data_unused_t *)ptr; + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) + ptr += INT_GET(dup->length, ARCH_CONVERT); + else { + dep = (xfs_dir2_data_entry_t *)ptr; + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + } + return i; +} + +/*ARGSUSED*/ +static int +dir2_data_u_offset( + void *obj, + int startoff, + int idx) +{ + xfs_dir2_data_t *data; + xfs_dir2_data_entry_t *dep; + xfs_dir2_data_unused_t *dup; + /*REFERENCED*/ + char *endptr; + int i; + char *ptr; + + ASSERT(startoff == 0); + data = obj; + ASSERT(INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC); + ptr = (char *)data->u; + endptr = (char *)data + mp->m_dirblksize; + for (i = 0; i < idx; i++) { + ASSERT(ptr < endptr); + dup = (xfs_dir2_data_unused_t *)ptr; + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) + ptr += INT_GET(dup->length, ARCH_CONVERT); + else { + dep = (xfs_dir2_data_entry_t *)ptr; + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + } + return bitize((int)(ptr - (char *)data)); +} + +/*ARGSUSED*/ +int +dir2_data_union_size( + void *obj, + int startoff, + int idx) +{ + xfs_dir2_data_entry_t *dep; + xfs_dir2_data_unused_t *dup; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(idx == 0); + dup = (xfs_dir2_data_unused_t *)((char *)obj + byteize(startoff)); + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) + return bitize(INT_GET(dup->length, ARCH_CONVERT)); + else { + dep = (xfs_dir2_data_entry_t *)dup; + return bitize(XFS_DIR2_DATA_ENTSIZE(dep->namelen)); + } +} + +/*ARGSUSED*/ +static int +dir2_free_bests_count( + void *obj, + int startoff) +{ + xfs_dir2_free_t *free; + + ASSERT(startoff == 0); + free = obj; + if (INT_GET(free->hdr.magic, ARCH_CONVERT) != XFS_DIR2_FREE_MAGIC) + return 0; + return INT_GET(free->hdr.nvalid, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +dir2_free_hdr_count( + void *obj, + int startoff) +{ + xfs_dir2_free_t *free; + + ASSERT(startoff == 0); + free = obj; + return INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC; +} + +/*ARGSUSED*/ +static int +dir2_leaf_bests_count( + void *obj, + int startoff) +{ + xfs_dir2_leaf_t *leaf; + xfs_dir2_leaf_tail_t *ltp; + + ASSERT(startoff == 0); + leaf = obj; + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR2_LEAF1_MAGIC) + return 0; + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + return INT_GET(ltp->bestcount, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +dir2_leaf_bests_offset( + void *obj, + int startoff, + int idx) +{ + xfs_dir2_data_off_t *lbp; + xfs_dir2_leaf_t *leaf; + xfs_dir2_leaf_tail_t *ltp; + + ASSERT(startoff == 0); + leaf = obj; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC); + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + lbp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT) + idx; + return bitize((int)((char *)lbp - (char *)leaf)); +} + +/*ARGSUSED*/ +static int +dir2_leaf_ents_count( + void *obj, + int startoff) +{ + xfs_dir2_leaf_t *leaf; + + ASSERT(startoff == 0); + leaf = obj; + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR2_LEAF1_MAGIC && + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR2_LEAFN_MAGIC) + return 0; + return INT_GET(leaf->hdr.count, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +dir2_leaf_hdr_count( + void *obj, + int startoff) +{ + xfs_dir2_leaf_t *leaf; + + ASSERT(startoff == 0); + leaf = obj; + return INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC || + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC; +} + +/*ARGSUSED*/ +static int +dir2_leaf_tail_count( + void *obj, + int startoff) +{ + xfs_dir2_leaf_t *leaf; + + ASSERT(startoff == 0); + leaf = obj; + return INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC; +} + +/*ARGSUSED*/ +static int +dir2_leaf_tail_offset( + void *obj, + int startoff, + int idx) +{ + xfs_dir2_leaf_t *leaf; + xfs_dir2_leaf_tail_t *ltp; + + ASSERT(startoff == 0); + ASSERT(idx == 0); + leaf = obj; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC); + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + return bitize((int)((char *)ltp - (char *)leaf)); +} + +/*ARGSUSED*/ +static int +dir2_node_btree_count( + void *obj, + int startoff) +{ + xfs_da_intnode_t *node; + + ASSERT(startoff == 0); + node = obj; + if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) + return 0; + return INT_GET(node->hdr.count, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +dir2_node_hdr_count( + void *obj, + int startoff) +{ + xfs_da_intnode_t *node; + + ASSERT(startoff == 0); + node = obj; + return INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC; +} + +/*ARGSUSED*/ +int +dir2_size( + void *obj, + int startoff, + int idx) +{ + return bitize(mp->m_dirblksize); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/dir2.h linux-2.4-xfs/cmd/xfsprogs/db/dir2.h --- linux-2.4.7/cmd/xfsprogs/db/dir2.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/dir2.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern const field_t dir2_flds[]; +extern const field_t dir2_hfld[]; +extern const field_t dir2_block_tail_flds[]; +extern const field_t dir2_data_free_flds[]; +extern const field_t dir2_data_hdr_flds[]; +extern const field_t dir2_data_union_flds[]; +extern const field_t dir2_free_hdr_flds[]; +extern const field_t dir2_leaf_entry_flds[]; +extern const field_t dir2_leaf_hdr_flds[]; +extern const field_t dir2_leaf_tail_flds[]; + +extern int dir2_data_union_size(void *obj, int startoff, int idx); +extern int dir2_size(void *obj, int startoff, int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/dir2sf.c linux-2.4-xfs/cmd/xfsprogs/db/dir2sf.c --- linux-2.4.7/cmd/xfsprogs/db/dir2sf.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/dir2sf.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "bit.h" +#include "dir2sf.h" + +static int dir2_inou_i4_count(void *obj, int startoff); +static int dir2_inou_i8_count(void *obj, int startoff); +static int dir2_sf_entry_inumber_offset(void *obj, int startoff, int idx); +static int dir2_sf_entry_name_count(void *obj, int startoff); +static int dir2_sf_list_count(void *obj, int startoff); +static int dir2_sf_list_offset(void *obj, int startoff, int idx); + +#define OFF(f) bitize(offsetof(xfs_dir2_sf_t, f)) +const field_t dir2sf_flds[] = { + { "hdr", FLDT_DIR2_SF_HDR, OI(OFF(hdr)), C1, 0, TYP_NONE }, + { "list", FLDT_DIR2_SF_ENTRY, dir2_sf_list_offset, dir2_sf_list_count, + FLD_ARRAY|FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { NULL } +}; + +#define UOFF(f) bitize(offsetof(xfs_dir2_inou_t, f)) +const field_t dir2_inou_flds[] = { + { "i8", FLDT_DIR2_INO8, OI(UOFF(i8)), dir2_inou_i8_count, FLD_COUNT, + TYP_INODE }, + { "i4", FLDT_DIR2_INO4, OI(UOFF(i4)), dir2_inou_i4_count, FLD_COUNT, + TYP_INODE }, + { NULL } +}; + +#define HOFF(f) bitize(offsetof(xfs_dir2_sf_hdr_t, f)) +const field_t dir2_sf_hdr_flds[] = { + { "count", FLDT_UINT8D, OI(HOFF(count)), C1, 0, TYP_NONE }, + { "i8count", FLDT_UINT8D, OI(HOFF(i8count)), C1, 0, TYP_NONE }, + { "parent", FLDT_DIR2_INOU, OI(HOFF(parent)), C1, 0, TYP_NONE }, + { NULL } +}; + +#define EOFF(f) bitize(offsetof(xfs_dir2_sf_entry_t, f)) +const field_t dir2_sf_entry_flds[] = { + { "namelen", FLDT_UINT8D, OI(EOFF(namelen)), C1, 0, TYP_NONE }, + { "offset", FLDT_DIR2_SF_OFF, OI(EOFF(offset)), C1, 0, TYP_NONE }, + { "name", FLDT_CHARNS, OI(EOFF(name)), dir2_sf_entry_name_count, + FLD_COUNT, TYP_NONE }, + { "inumber", FLDT_DIR2_INOU, dir2_sf_entry_inumber_offset, C1, + FLD_OFFSET, TYP_NONE }, + { NULL } +}; + +/*ARGSUSED*/ +static int +dir2_inou_i4_count( + void *obj, + int startoff) +{ + xfs_dir2_sf_t *sf; + + ASSERT(bitoffs(startoff) == 0); + sf = &((xfs_dinode_t *)obj)->di_u.di_dir2sf; + return sf->hdr.i8count == 0; +} + +/*ARGSUSED*/ +static int +dir2_inou_i8_count( + void *obj, + int startoff) +{ + xfs_dir2_sf_t *sf; + + ASSERT(bitoffs(startoff) == 0); + sf = &((xfs_dinode_t *)obj)->di_u.di_dir2sf; + return sf->hdr.i8count != 0; +} + +/*ARGSUSED*/ +int +dir2_inou_size( + void *obj, + int startoff, + int idx) +{ + xfs_dir2_sf_t *sf; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(idx == 0); + sf = &((xfs_dinode_t *)obj)->di_u.di_dir2sf; + return bitize(sf->hdr.i8count ? + (uint)sizeof(xfs_dir2_ino8_t) : + (uint)sizeof(xfs_dir2_ino4_t)); +} + +static int +dir2_sf_entry_name_count( + void *obj, + int startoff) +{ + xfs_dir2_sf_entry_t *e; + + ASSERT(bitoffs(startoff) == 0); + e = (xfs_dir2_sf_entry_t *)((char *)obj + byteize(startoff)); + return e->namelen; +} + +/*ARGSUSED*/ +static int +dir2_sf_entry_inumber_offset( + void *obj, + int startoff, + int idx) +{ + xfs_dir2_sf_entry_t *e; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(idx == 0); + e = (xfs_dir2_sf_entry_t *)((char *)obj + byteize(startoff)); + return bitize((int)((char *)XFS_DIR2_SF_INUMBERP(e) - (char *)e)); +} + +int +dir2_sf_entry_size( + void *obj, + int startoff, + int idx) +{ + xfs_dir2_sf_entry_t *e; + int i; + xfs_dir2_sf_t *sf; + + ASSERT(bitoffs(startoff) == 0); + sf = (xfs_dir2_sf_t *)((char *)obj + byteize(startoff)); + e = XFS_DIR2_SF_FIRSTENTRY(sf); + for (i = 0; i < idx; i++) + e = XFS_DIR2_SF_NEXTENTRY(sf, e); + return bitize((int)XFS_DIR2_SF_ENTSIZE_BYENTRY(sf, e)); +} + +/*ARGSUSED*/ +int +dir2_sf_hdr_size( + void *obj, + int startoff, + int idx) +{ + xfs_dir2_sf_t *sf; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(idx == 0); + sf = (xfs_dir2_sf_t *)((char *)obj + byteize(startoff)); + return bitize(XFS_DIR2_SF_HDR_SIZE(sf->hdr.i8count)); +} + +static int +dir2_sf_list_count( + void *obj, + int startoff) +{ + xfs_dir2_sf_t *sf; + + ASSERT(bitoffs(startoff) == 0); + sf = (xfs_dir2_sf_t *)((char *)obj + byteize(startoff)); + return sf->hdr.count; +} + +static int +dir2_sf_list_offset( + void *obj, + int startoff, + int idx) +{ + xfs_dir2_sf_entry_t *e; + int i; + xfs_dir2_sf_t *sf; + + ASSERT(bitoffs(startoff) == 0); + sf = (xfs_dir2_sf_t *)((char *)obj + byteize(startoff)); + e = XFS_DIR2_SF_FIRSTENTRY(sf); + for (i = 0; i < idx; i++) + e = XFS_DIR2_SF_NEXTENTRY(sf, e); + return bitize((int)((char *)e - (char *)sf)); +} + +/*ARGSUSED*/ +int +dir2sf_size( + void *obj, + int startoff, + int idx) +{ + xfs_dir2_sf_entry_t *e; + int i; + xfs_dir2_sf_t *sf; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(idx == 0); + sf = (xfs_dir2_sf_t *)((char *)obj + byteize(startoff)); + e = XFS_DIR2_SF_FIRSTENTRY(sf); + for (i = 0; i < sf->hdr.count; i++) + e = XFS_DIR2_SF_NEXTENTRY(sf, e); + return bitize((int)((char *)e - (char *)sf)); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/dir2sf.h linux-2.4-xfs/cmd/xfsprogs/db/dir2sf.h --- linux-2.4.7/cmd/xfsprogs/db/dir2sf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/dir2sf.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern const field_t dir2sf_flds[]; +extern const field_t dir2_inou_flds[]; +extern const field_t dir2_sf_hdr_flds[]; +extern const field_t dir2_sf_entry_flds[]; + +extern int dir2sf_size(void *obj, int startoff, int idx); +extern int dir2_inou_size(void *obj, int startoff, int idx); +extern int dir2_sf_entry_size(void *obj, int startoff, int idx); +extern int dir2_sf_hdr_size(void *obj, int startoff, int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/dirshort.c linux-2.4-xfs/cmd/xfsprogs/db/dirshort.c --- linux-2.4.7/cmd/xfsprogs/db/dirshort.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/dirshort.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "bit.h" +#include "dirshort.h" + +static int dir_sf_entry_name_count(void *obj, int startoff); +static int dir_shortform_list_count(void *obj, int startoff); +static int dir_shortform_list_offset(void *obj, int startoff, int idx); + +#define OFF(f) bitize(offsetof(xfs_dir_shortform_t, f)) +const field_t dir_shortform_flds[] = { + { "hdr", FLDT_DIR_SF_HDR, OI(OFF(hdr)), C1, 0, TYP_NONE }, + { "list", FLDT_DIR_SF_ENTRY, dir_shortform_list_offset, + dir_shortform_list_count, FLD_ARRAY|FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { NULL } +}; + +#define HOFF(f) bitize(offsetof(xfs_dir_sf_hdr_t, f)) +const field_t dir_sf_hdr_flds[] = { + { "parent", FLDT_DIR_INO, OI(HOFF(parent)), C1, 0, TYP_INODE }, + { "count", FLDT_UINT8D, OI(HOFF(count)), C1, 0, TYP_NONE }, + { NULL } +}; + +#define EOFF(f) bitize(offsetof(xfs_dir_sf_entry_t, f)) +const field_t dir_sf_entry_flds[] = { + { "inumber", FLDT_DIR_INO, OI(EOFF(inumber)), C1, 0, TYP_INODE }, + { "namelen", FLDT_UINT8D, OI(EOFF(namelen)), C1, 0, TYP_NONE }, + { "name", FLDT_CHARNS, OI(EOFF(name)), dir_sf_entry_name_count, + FLD_COUNT, TYP_NONE }, + { NULL } +}; + +static int +dir_sf_entry_name_count( + void *obj, + int startoff) +{ + xfs_dir_sf_entry_t *e; + + ASSERT(bitoffs(startoff) == 0); + e = (xfs_dir_sf_entry_t *)((char *)obj + byteize(startoff)); + return e->namelen; +} + +int +dir_sf_entry_size( + void *obj, + int startoff, + int idx) +{ + xfs_dir_sf_entry_t *e; + int i; + xfs_dir_shortform_t *sf; + + ASSERT(bitoffs(startoff) == 0); + sf = (xfs_dir_shortform_t *)((char *)obj + byteize(startoff)); + e = &sf->list[0]; + for (i = 0; i < idx; i++) + e = XFS_DIR_SF_NEXTENTRY(e); + return bitize((int)XFS_DIR_SF_ENTSIZE_BYENTRY(e)); +} + +static int +dir_shortform_list_count( + void *obj, + int startoff) +{ + xfs_dir_shortform_t *sf; + + ASSERT(bitoffs(startoff) == 0); + sf = (xfs_dir_shortform_t *)((char *)obj + byteize(startoff)); + return sf->hdr.count; +} + +static int +dir_shortform_list_offset( + void *obj, + int startoff, + int idx) +{ + xfs_dir_sf_entry_t *e; + int i; + xfs_dir_shortform_t *sf; + + ASSERT(bitoffs(startoff) == 0); + sf = (xfs_dir_shortform_t *)((char *)obj + byteize(startoff)); + e = &sf->list[0]; + for (i = 0; i < idx; i++) + e = XFS_DIR_SF_NEXTENTRY(e); + return bitize((int)((char *)e - (char *)sf)); +} + +int +dirshort_size( + void *obj, + int startoff, + int idx) +{ + xfs_dir_sf_entry_t *e; + int i; + xfs_dir_shortform_t *sf; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(idx == 0); + sf = (xfs_dir_shortform_t *)((char *)obj + byteize(startoff)); + e = &sf->list[0]; + for (i = 0; i < sf->hdr.count; i++) + e = XFS_DIR_SF_NEXTENTRY(e); + return bitize((int)((char *)e - (char *)sf)); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/dirshort.h linux-2.4-xfs/cmd/xfsprogs/db/dirshort.h --- linux-2.4.7/cmd/xfsprogs/db/dirshort.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/dirshort.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern const field_t dir_sf_entry_flds[]; +extern const field_t dir_sf_hdr_flds[]; +extern const field_t dir_shortform_flds[]; +extern const field_t dirshort_hfld[]; + +extern int dir_sf_entry_size(void *obj, int startoff, int idx); +extern int dirshort_size(void *obj, int startoff, int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/dquot.c linux-2.4-xfs/cmd/xfsprogs/db/dquot.c --- linux-2.4.7/cmd/xfsprogs/db/dquot.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/dquot.c Mon Apr 2 21:52:38 2001 @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "bit.h" +#include "bmap.h" +#include "command.h" +#include "data.h" +#include "dquot.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "inode.h" +#include "io.h" +#include "mount.h" +#include "output.h" + +static int dquot_f(int argc, char **argv); +static void dquot_help(void); + +static const cmdinfo_t dquot_cmd = + { "dquot", NULL, dquot_f, 1, 2, 1, "[gid|uid]", + "set current address to group or user quota block", dquot_help }; + +const field_t dqblk_hfld[] = { + { "", FLDT_DQBLK, OI(0), C1, 0, TYP_NONE }, + { NULL } +}; + +#define DDOFF(f) bitize(offsetof(xfs_dqblk_t, dd_ ## f)) +#define DDSZC(f) szcount(xfs_dqblk_t, dd_ ## f) +const field_t dqblk_flds[] = { + { "diskdq", FLDT_DISK_DQUOT, OI(DDOFF(diskdq)), C1, 0, TYP_NONE }, + { "fill", FLDT_CHARS, OI(DDOFF(fill)), CI(DDSZC(fill)), FLD_SKIPALL, + TYP_NONE }, + { NULL } +}; + +#define DOFF(f) bitize(offsetof(xfs_disk_dquot_t, d_ ## f)) +const field_t disk_dquot_flds[] = { + { "magic", FLDT_UINT16X, OI(DOFF(magic)), C1, 0, TYP_NONE }, + { "version", FLDT_UINT8X, OI(DOFF(version)), C1, 0, TYP_NONE }, + { "flags", FLDT_UINT8X, OI(DOFF(flags)), C1, 0, TYP_NONE }, + { "id", FLDT_DQID, OI(DOFF(id)), C1, 0, TYP_NONE }, + { "blk_hardlimit", FLDT_QCNT, OI(DOFF(blk_hardlimit)), C1, 0, + TYP_NONE }, + { "blk_softlimit", FLDT_QCNT, OI(DOFF(blk_softlimit)), C1, 0, + TYP_NONE }, + { "ino_hardlimit", FLDT_QCNT, OI(DOFF(ino_hardlimit)), C1, 0, + TYP_NONE }, + { "ino_softlimit", FLDT_QCNT, OI(DOFF(ino_softlimit)), C1, 0, + TYP_NONE }, + { "bcount", FLDT_QCNT, OI(DOFF(bcount)), C1, 0, TYP_NONE }, + { "icount", FLDT_QCNT, OI(DOFF(icount)), C1, 0, TYP_NONE }, + { "itimer", FLDT_INT32D, OI(DOFF(itimer)), C1, 0, TYP_NONE }, + { "btimer", FLDT_INT32D, OI(DOFF(btimer)), C1, 0, TYP_NONE }, + { "iwarns", FLDT_QWARNCNT, OI(DOFF(iwarns)), C1, 0, TYP_NONE }, + { "bwarns", FLDT_QWARNCNT, OI(DOFF(bwarns)), C1, 0, TYP_NONE }, + { "pad0", FLDT_INT32D, OI(DOFF(pad0)), C1, FLD_SKIPALL, TYP_NONE }, + { "rtb_hardlimit", FLDT_QCNT, OI(DOFF(rtb_hardlimit)), C1, 0, + TYP_NONE }, + { "rtb_softlimit", FLDT_QCNT, OI(DOFF(rtb_softlimit)), C1, 0, + TYP_NONE }, + { "rtbcount", FLDT_QCNT, OI(DOFF(rtbcount)), C1, 0, TYP_NONE }, + { "rtbtimer", FLDT_INT32D, OI(DOFF(rtbtimer)), C1, 0, TYP_NONE }, + { "rtbwarns", FLDT_QWARNCNT, OI(DOFF(rtbwarns)), C1, 0, TYP_NONE }, + { "pad", FLDT_UINT16X, OI(DOFF(pad)), C1, FLD_SKIPALL, TYP_NONE }, + { NULL } +}; + +static void +dquot_help(void) +{ +} + +static int +dquot_f( + int argc, + char **argv) +{ + bmap_ext_t bm; + int c; + int dogrp; + xfs_dqid_t id; + xfs_ino_t ino; + int nex; + char *p; + int perblock; + xfs_fileoff_t qbno; + int qoff; + char *s; + + dogrp = optind = 0; + while ((c = getopt(argc, argv, "gu")) != EOF) { + switch (c) { + case 'g': + dogrp = 1; + break; + case 'u': + dogrp = 0; + break; + default: + dbprintf("bad option for dquot command\n"); + return 0; + } + } + s = dogrp ? "group" : "user"; + if (optind != argc - 1) { + dbprintf("dquot command requires one %s id argument\n", s); + return 0; + } + ino = dogrp ? mp->m_sb.sb_gquotino : mp->m_sb.sb_uquotino; + if (ino == 0 || ino == NULLFSINO) { + dbprintf("no %s quota inode present\n", s); + return 0; + } + id = (xfs_dqid_t)strtol(argv[optind], &p, 0); + if (*p != '\0') { + dbprintf("bad %s id for dquot %s\n", s, argv[optind]); + return 0; + } + perblock = (int)(mp->m_sb.sb_blocksize / sizeof(xfs_dqblk_t)); + qbno = (xfs_fileoff_t)(id / perblock); + qoff = (int)(id % perblock); + push_cur(); + set_cur_inode(ino); + nex = 1; + bmap(qbno, 1, XFS_DATA_FORK, &nex, &bm); + pop_cur(); + if (nex == 0) { + dbprintf("no %s quota data for id %d\n", s, id); + return 0; + } + set_cur(&typtab[TYP_DQBLK], XFS_FSB_TO_DADDR(mp, bm.startblock), blkbb, + DB_RING_IGN, NULL); + off_cur(qoff * (int)sizeof(xfs_dqblk_t), sizeof(xfs_dqblk_t)); + ring_add(); + return 0; +} + +void +dquot_init(void) +{ + add_command(&dquot_cmd); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/dquot.h linux-2.4-xfs/cmd/xfsprogs/db/dquot.h --- linux-2.4.7/cmd/xfsprogs/db/dquot.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/dquot.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct field; + +extern const struct field disk_dquot_flds[]; +extern const struct field dqblk_flds[]; +extern const struct field dqblk_hfld[]; + +extern void dquot_init(void); diff -rNu linux-2.4.7/cmd/xfsprogs/db/echo.c linux-2.4-xfs/cmd/xfsprogs/db/echo.c --- linux-2.4.7/cmd/xfsprogs/db/echo.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/echo.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "command.h" +#include "echo.h" +#include "output.h" + +static int echo_f(int argc, char **argv); + +static const cmdinfo_t echo_cmd = + { "echo", NULL, echo_f, 0, -1, 0, "[args]...", + "echo arguments", NULL }; + +/*ARGSUSED*/ +static int +echo_f( + int argc, + char **argv) +{ + char *c; + + for (c = *(++argv); c; c = *(++argv)) + dbprintf("%s ", c); + dbprintf("\n"); + return 0; +} + +void +echo_init(void) +{ + add_command(&echo_cmd); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/echo.h linux-2.4-xfs/cmd/xfsprogs/db/echo.h --- linux-2.4.7/cmd/xfsprogs/db/echo.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/echo.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern void echo_init(void); diff -rNu linux-2.4.7/cmd/xfsprogs/db/faddr.c linux-2.4-xfs/cmd/xfsprogs/db/faddr.c --- linux-2.4.7/cmd/xfsprogs/db/faddr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/faddr.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "inode.h" +#include "io.h" +#include "bit.h" +#include "bmap.h" +#include "output.h" +#include "mount.h" + +void +fa_agblock( + void *obj, + int bit, + typnm_t next) +{ + xfs_agblock_t bno; + + if (cur_agno == NULLAGNUMBER) { + dbprintf("no current allocation group, cannot set new addr\n"); + return; + } + bno = (xfs_agblock_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); + if (bno == NULLAGBLOCK) { + dbprintf("null block number, cannot set new addr\n"); + return; + } + ASSERT(typtab[next].typnm == next); + set_cur(&typtab[next], XFS_AGB_TO_DADDR(mp, cur_agno, bno), blkbb, + DB_RING_ADD, NULL); +} + +/*ARGSUSED*/ +void +fa_agino( + void *obj, + int bit, + typnm_t next) +{ + xfs_agino_t agino; + + if (cur_agno == NULLAGNUMBER) { + dbprintf("no current allocation group, cannot set new addr\n"); + return; + } + agino = (xfs_agino_t)getbitval(obj, bit, bitsz(agino), BVUNSIGNED); + if (agino == NULLAGINO) { + dbprintf("null inode number, cannot set new addr\n"); + return; + } + set_cur_inode(XFS_AGINO_TO_INO(mp, cur_agno, agino)); +} + +/*ARGSUSED*/ +void +fa_attrblock( + void *obj, + int bit, + typnm_t next) +{ + bmap_ext_t bm; + __uint32_t bno; + xfs_dfsbno_t dfsbno; + int nex; + + bno = (__uint32_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); + if (bno == 0) { + dbprintf("null attribute block number, cannot set new addr\n"); + return; + } + nex = 1; + bmap(bno, 1, XFS_ATTR_FORK, &nex, &bm); + if (nex == 0) { + dbprintf("attribute block is unmapped\n"); + return; + } + dfsbno = bm.startblock + (bno - bm.startoff); + ASSERT(typtab[next].typnm == next); + set_cur(&typtab[next], (__int64_t)XFS_FSB_TO_DADDR(mp, dfsbno), blkbb, + DB_RING_ADD, NULL); +} + +void +fa_cfileoffa( + void *obj, + int bit, + typnm_t next) +{ + bmap_ext_t bm; + xfs_dfiloff_t bno; + xfs_dfsbno_t dfsbno; + int nex; + + bno = (xfs_dfiloff_t)getbitval(obj, bit, BMBT_STARTOFF_BITLEN, + BVUNSIGNED); + if (bno == NULLDFILOFF) { + dbprintf("null block number, cannot set new addr\n"); + return; + } + nex = 1; + bmap(bno, 1, XFS_ATTR_FORK, &nex, &bm); + if (nex == 0) { + dbprintf("file block is unmapped\n"); + return; + } + dfsbno = bm.startblock + (bno - bm.startoff); + ASSERT(typtab[next].typnm == next); + set_cur(&typtab[next], XFS_FSB_TO_DADDR(mp, dfsbno), blkbb, DB_RING_ADD, + NULL); +} + +void +fa_cfileoffd( + void *obj, + int bit, + typnm_t next) +{ + bbmap_t bbmap; + bmap_ext_t *bmp; + xfs_dfiloff_t bno; + xfs_dfsbno_t dfsbno; + int nb; + int nex; + + bno = (xfs_dfiloff_t)getbitval(obj, bit, BMBT_STARTOFF_BITLEN, + BVUNSIGNED); + if (bno == NULLDFILOFF) { + dbprintf("null block number, cannot set new addr\n"); + return; + } + nex = nb = next == TYP_DIR2 ? mp->m_dirblkfsbs : 1; + bmp = malloc(nb * sizeof(*bmp)); + bmap(bno, nb, XFS_DATA_FORK, &nex, bmp); + if (nex == 0) { + dbprintf("file block is unmapped\n"); + free(bmp); + return; + } + dfsbno = bmp->startblock + (bno - bmp->startoff); + ASSERT(typtab[next].typnm == next); + if (nex > 1) + make_bbmap(&bbmap, nex, bmp); + set_cur(&typtab[next], XFS_FSB_TO_DADDR(mp, dfsbno), nb * blkbb, + DB_RING_ADD, nex > 1 ? &bbmap: NULL); + free(bmp); +} + +void +fa_cfsblock( + void *obj, + int bit, + typnm_t next) +{ + xfs_dfsbno_t bno; + + bno = (xfs_dfsbno_t)getbitval(obj, bit, BMBT_STARTBLOCK_BITLEN, + BVUNSIGNED); + if (bno == NULLDFSBNO) { + dbprintf("null block number, cannot set new addr\n"); + return; + } + ASSERT(typtab[next].typnm == next); + set_cur(&typtab[next], XFS_FSB_TO_DADDR(mp, bno), blkbb, DB_RING_ADD, + NULL); +} + +void +fa_dfiloffa( + void *obj, + int bit, + typnm_t next) +{ + bmap_ext_t bm; + xfs_dfiloff_t bno; + xfs_dfsbno_t dfsbno; + int nex; + + bno = (xfs_dfiloff_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); + if (bno == NULLDFILOFF) { + dbprintf("null block number, cannot set new addr\n"); + return; + } + nex = 1; + bmap(bno, 1, XFS_ATTR_FORK, &nex, &bm); + if (nex == 0) { + dbprintf("file block is unmapped\n"); + return; + } + dfsbno = bm.startblock + (bno - bm.startoff); + ASSERT(typtab[next].typnm == next); + set_cur(&typtab[next], XFS_FSB_TO_DADDR(mp, dfsbno), blkbb, DB_RING_ADD, + NULL); +} + +void +fa_dfiloffd( + void *obj, + int bit, + typnm_t next) +{ + bbmap_t bbmap; + bmap_ext_t *bmp; + xfs_dfiloff_t bno; + xfs_dfsbno_t dfsbno; + int nb; + int nex; + + bno = (xfs_dfiloff_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); + if (bno == NULLDFILOFF) { + dbprintf("null block number, cannot set new addr\n"); + return; + } + nex = nb = next == TYP_DIR2 ? mp->m_dirblkfsbs : 1; + bmp = malloc(nb * sizeof(*bmp)); + bmap(bno, nb, XFS_DATA_FORK, &nex, bmp); + if (nex == 0) { + dbprintf("file block is unmapped\n"); + free(bmp); + return; + } + dfsbno = bmp->startblock + (bno - bmp->startoff); + ASSERT(typtab[next].typnm == next); + if (nex > 1) + make_bbmap(&bbmap, nex, bmp); + set_cur(&typtab[next], XFS_FSB_TO_DADDR(mp, dfsbno), nb * blkbb, + DB_RING_ADD, nex > 1 ? &bbmap : NULL); + free(bmp); +} + +void +fa_dfsbno( + void *obj, + int bit, + typnm_t next) +{ + xfs_dfsbno_t bno; + + bno = (xfs_dfsbno_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); + if (bno == NULLDFSBNO) { + dbprintf("null block number, cannot set new addr\n"); + return; + } + ASSERT(typtab[next].typnm == next); + set_cur(&typtab[next], XFS_FSB_TO_DADDR(mp, bno), blkbb, DB_RING_ADD, + NULL); +} + +/*ARGSUSED*/ +void +fa_dirblock( + void *obj, + int bit, + typnm_t next) +{ + bbmap_t bbmap; + bmap_ext_t *bmp; + __uint32_t bno; + xfs_dfsbno_t dfsbno; + int nex; + + bno = (__uint32_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); + if (bno == 0) { + dbprintf("null directory block number, cannot set new addr\n"); + return; + } + nex = mp->m_dirblkfsbs; + bmp = malloc(nex * sizeof(*bmp)); + bmap(bno, mp->m_dirblkfsbs, XFS_DATA_FORK, &nex, bmp); + if (nex == 0) { + dbprintf("directory block is unmapped\n"); + free(bmp); + return; + } + dfsbno = bmp->startblock + (bno - bmp->startoff); + ASSERT(typtab[next].typnm == next); + if (nex > 1) + make_bbmap(&bbmap, nex, bmp); + set_cur(&typtab[next], (__int64_t)XFS_FSB_TO_DADDR(mp, dfsbno), + (int)XFS_FSB_TO_DADDR(mp, mp->m_dirblkfsbs), DB_RING_ADD, + nex > 1 ? &bbmap : NULL); + free(bmp); +} + +void +fa_drfsbno( + void *obj, + int bit, + typnm_t next) +{ + xfs_drfsbno_t bno; + + bno = (xfs_drfsbno_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); + if (bno == NULLDRFSBNO) { + dbprintf("null block number, cannot set new addr\n"); + return; + } + ASSERT(typtab[next].typnm == next); + set_cur(&typtab[next], (__int64_t)XFS_FSB_TO_BB(mp, bno), blkbb, + DB_RING_ADD, NULL); +} + +/*ARGSUSED*/ +void +fa_drtbno( + void *obj, + int bit, + typnm_t next) +{ + xfs_drtbno_t bno; + + bno = (xfs_drtbno_t)getbitval(obj, bit, bitsz(bno), BVUNSIGNED); + if (bno == NULLDRTBNO) { + dbprintf("null block number, cannot set new addr\n"); + return; + } + /* need set_cur to understand rt subvolume */ +} + +/*ARGSUSED*/ +void +fa_ino( + void *obj, + int bit, + typnm_t next) +{ + xfs_ino_t ino; + + ASSERT(next == TYP_INODE); + ino = (xfs_ino_t)getbitval(obj, bit, bitsz(ino), BVUNSIGNED); + if (ino == NULLFSINO) { + dbprintf("null inode number, cannot set new addr\n"); + return; + } + set_cur_inode(ino); +} + +void +fa_ino4( + void *obj, + int bit, + typnm_t next) +{ + xfs_ino_t ino; + xfs_dir2_ino4_t ino4; + + ASSERT(next == TYP_INODE); + ino = (xfs_ino_t)getbitval(obj, bit, bitsz(ino4), BVUNSIGNED); + if (ino == NULLFSINO) { + dbprintf("null inode number, cannot set new addr\n"); + return; + } + set_cur_inode(ino); +} + +void +fa_ino8( + void *obj, + int bit, + typnm_t next) +{ + xfs_ino_t ino; + xfs_dir2_ino8_t ino8; + + ASSERT(next == TYP_INODE); + ino = (xfs_ino_t)getbitval(obj, bit, bitsz(ino8), BVUNSIGNED); + if (ino == NULLFSINO) { + dbprintf("null inode number, cannot set new addr\n"); + return; + } + set_cur_inode(ino); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/faddr.h linux-2.4-xfs/cmd/xfsprogs/db/faddr.h --- linux-2.4.7/cmd/xfsprogs/db/faddr.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/faddr.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +typedef void (*adfnc_t)(void *obj, int bit, typnm_t next); + +extern void fa_agblock(void *obj, int bit, typnm_t next); +extern void fa_agino(void *obj, int bit, typnm_t next); +extern void fa_attrblock(void *obj, int bit, typnm_t next); +extern void fa_cfileoffd(void *obj, int bit, typnm_t next); +extern void fa_cfsblock(void *obj, int bit, typnm_t next); +extern void fa_dfiloffd(void *obj, int bit, typnm_t next); +extern void fa_dfsbno(void *obj, int bit, typnm_t next); +extern void fa_dinode_union(void *obj, int bit, typnm_t next); +extern void fa_dirblock(void *obj, int bit, typnm_t next); +extern void fa_drfsbno(void *obj, int bit, typnm_t next); +extern void fa_drtbno(void *obj, int bit, typnm_t next); +extern void fa_ino(void *obj, int bit, typnm_t next); +extern void fa_cfileoffa(void *obj, int bit, typnm_t next); +extern void fa_dfiloffa(void *obj, int bit, typnm_t next); +extern void fa_ino4(void *obj, int bit, typnm_t next); +extern void fa_ino8(void *obj, int bit, typnm_t next); diff -rNu linux-2.4.7/cmd/xfsprogs/db/field.c linux-2.4-xfs/cmd/xfsprogs/db/field.c --- linux-2.4.7/cmd/xfsprogs/db/field.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/field.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "inode.h" +#include "bnobt.h" +#include "cntbt.h" +#include "inobt.h" +#include "bmapbt.h" +#include "bmroot.h" +#include "bit.h" +#include "agf.h" +#include "agfl.h" +#include "agi.h" +#include "sb.h" +#include "dir.h" +#include "dirshort.h" +#include "attr.h" +#include "attrshort.h" +#include "dquot.h" +#include "dir2.h" +#include "dir2sf.h" + +const ftattr_t ftattrtab[] = { + { FLDT_AEXTNUM, "aextnum", fp_num, "%d", SI(bitsz(xfs_aextnum_t)), + FTARG_SIGNED, NULL, NULL }, + { FLDT_AGBLOCK, "agblock", fp_num, "%u", SI(bitsz(xfs_agblock_t)), + FTARG_DONULL, fa_agblock, NULL }, + { FLDT_AGBLOCKNZ, "agblocknz", fp_num, "%u", SI(bitsz(xfs_agblock_t)), + FTARG_SKIPZERO|FTARG_DONULL, fa_agblock, NULL }, + { FLDT_AGF, "agf", NULL, (char *)agf_flds, agf_size, FTARG_SIZE, NULL, + agf_flds }, + { FLDT_AGFL, "agfl", NULL, (char *)agfl_flds, agfl_size, FTARG_SIZE, + NULL, agfl_flds }, + { FLDT_AGI, "agi", NULL, (char *)agi_flds, agi_size, FTARG_SIZE, NULL, + agi_flds }, + { FLDT_AGINO, "agino", fp_num, "%u", SI(bitsz(xfs_agino_t)), + FTARG_DONULL, fa_agino, NULL }, + { FLDT_AGINONN, "aginonn", fp_num, "%u", SI(bitsz(xfs_agino_t)), + FTARG_SKIPNULL, fa_agino, NULL }, + { FLDT_AGNUMBER, "agnumber", fp_num, "%u", SI(bitsz(xfs_agnumber_t)), + FTARG_DONULL, NULL, NULL }, + { FLDT_ATTR, "attr", NULL, (char *)attr_flds, attr_size, FTARG_SIZE, + NULL, attr_flds }, + { FLDT_ATTR_BLKINFO, "attr_blkinfo", NULL, (char *)attr_blkinfo_flds, + SI(bitsz(struct xfs_da_blkinfo)), 0, NULL, attr_blkinfo_flds }, + { FLDT_ATTR_LEAF_ENTRY, "attr_leaf_entry", fp_sarray, + (char *)attr_leaf_entry_flds, SI(bitsz(struct xfs_attr_leaf_entry)), + 0, NULL, attr_leaf_entry_flds }, + { FLDT_ATTR_LEAF_HDR, "attr_leaf_hdr", NULL, (char *)attr_leaf_hdr_flds, + SI(bitsz(struct xfs_attr_leaf_hdr)), 0, NULL, attr_leaf_hdr_flds }, + { FLDT_ATTR_LEAF_MAP, "attr_leaf_map", fp_sarray, + (char *)attr_leaf_map_flds, SI(bitsz(struct xfs_attr_leaf_map)), 0, + NULL, attr_leaf_map_flds }, + { FLDT_ATTR_LEAF_NAME, "attr_leaf_name", NULL, + (char *)attr_leaf_name_flds, attr_leaf_name_size, FTARG_SIZE, NULL, + attr_leaf_name_flds }, + { FLDT_ATTR_NODE_ENTRY, "attr_node_entry", fp_sarray, + (char *)attr_node_entry_flds, SI(bitsz(struct xfs_da_node_entry)), 0, + NULL, attr_node_entry_flds }, + { FLDT_ATTR_NODE_HDR, "attr_node_hdr", NULL, (char *)attr_node_hdr_flds, + SI(bitsz(struct xfs_da_node_hdr)), 0, NULL, attr_node_hdr_flds }, + { FLDT_ATTR_SF_ENTRY, "attr_sf_entry", NULL, (char *)attr_sf_entry_flds, + attr_sf_entry_size, FTARG_SIZE, NULL, attr_sf_entry_flds }, + { FLDT_ATTR_SF_HDR, "attr_sf_hdr", NULL, (char *)attr_sf_hdr_flds, + SI(bitsz(struct xfs_attr_sf_hdr)), 0, NULL, attr_sf_hdr_flds }, + { FLDT_ATTRBLOCK, "attrblock", fp_num, "%u", SI(bitsz(__uint32_t)), 0, + fa_attrblock, NULL }, + { FLDT_ATTRSHORT, "attrshort", NULL, (char *)attr_shortform_flds, + attrshort_size, FTARG_SIZE, NULL, attr_shortform_flds }, + { FLDT_BMAPBTA, "bmapbta", NULL, (char *)bmapbta_flds, bmapbta_size, + FTARG_SIZE, NULL, bmapbta_flds }, + { FLDT_BMAPBTAKEY, "bmapbtakey", fp_sarray, (char *)bmapbta_key_flds, + SI(bitsz(xfs_bmbt_key_t)), 0, NULL, bmapbta_key_flds }, + { FLDT_BMAPBTAPTR, "bmapbtaptr", fp_num, "%llu", + SI(bitsz(xfs_bmbt_ptr_t)), 0, fa_dfsbno, NULL }, + { FLDT_BMAPBTAREC, "bmapbtarec", fp_sarray, (char *)bmapbta_rec_flds, + SI(bitsz(xfs_bmbt_rec_t)), 0, NULL, bmapbta_rec_flds }, + { FLDT_BMAPBTD, "bmapbtd", NULL, (char *)bmapbtd_flds, bmapbtd_size, + FTARG_SIZE, NULL, bmapbtd_flds }, + { FLDT_BMAPBTDKEY, "bmapbtdkey", fp_sarray, (char *)bmapbtd_key_flds, + SI(bitsz(xfs_bmbt_key_t)), 0, NULL, bmapbtd_key_flds }, + { FLDT_BMAPBTDPTR, "bmapbtdptr", fp_num, "%llu", + SI(bitsz(xfs_bmbt_ptr_t)), 0, fa_dfsbno, NULL }, + { FLDT_BMAPBTDREC, "bmapbtdrec", fp_sarray, (char *)bmapbtd_rec_flds, + SI(bitsz(xfs_bmbt_rec_t)), 0, NULL, bmapbtd_rec_flds }, + { FLDT_BMROOTA, "bmroota", NULL, (char *)bmroota_flds, bmroota_size, + FTARG_SIZE, NULL, bmroota_flds }, + { FLDT_BMROOTAKEY, "bmrootakey", fp_sarray, (char *)bmroota_key_flds, + SI(bitsz(xfs_bmdr_key_t)), 0, NULL, bmroota_key_flds }, + { FLDT_BMROOTAPTR, "bmrootaptr", fp_num, "%llu", + SI(bitsz(xfs_bmdr_ptr_t)), 0, fa_dfsbno, NULL }, + { FLDT_BMROOTD, "bmrootd", NULL, (char *)bmrootd_flds, bmrootd_size, + FTARG_SIZE, NULL, bmrootd_flds }, + { FLDT_BMROOTDKEY, "bmrootdkey", fp_sarray, (char *)bmrootd_key_flds, + SI(bitsz(xfs_bmdr_key_t)), 0, NULL, bmrootd_key_flds }, + { FLDT_BMROOTDPTR, "bmrootdptr", fp_num, "%llu", + SI(bitsz(xfs_bmdr_ptr_t)), 0, fa_dfsbno, NULL }, + { FLDT_BNOBT, "bnobt", NULL, (char *)bnobt_flds, bnobt_size, FTARG_SIZE, + NULL, bnobt_flds }, + { FLDT_BNOBTKEY, "bnobtkey", fp_sarray, (char *)bnobt_key_flds, + SI(bitsz(xfs_alloc_key_t)), 0, NULL, bnobt_key_flds }, + { FLDT_BNOBTPTR, "bnobtptr", fp_num, "%u", SI(bitsz(xfs_alloc_ptr_t)), + 0, fa_agblock, NULL }, + { FLDT_BNOBTREC, "bnobtrec", fp_sarray, (char *)bnobt_rec_flds, + SI(bitsz(xfs_alloc_rec_t)), 0, NULL, bnobt_rec_flds }, + { FLDT_CEXTFLG, "cextflag", fp_num, "%u", SI(BMBT_EXNTFLAG_BITLEN), 0, + NULL, NULL }, + { FLDT_CEXTLEN, "cextlen", fp_num, "%u", SI(BMBT_BLOCKCOUNT_BITLEN), 0, + NULL, NULL }, + { FLDT_CFILEOFFA, "cfileoffa", fp_num, "%llu", SI(BMBT_STARTOFF_BITLEN), + 0, fa_cfileoffa, NULL }, + { FLDT_CFILEOFFD, "cfileoffd", fp_num, "%llu", SI(BMBT_STARTOFF_BITLEN), + 0, fa_cfileoffd, NULL }, + { FLDT_CFSBLOCK, "cfsblock", fp_num, "%llu", SI(BMBT_STARTBLOCK_BITLEN), + 0, fa_cfsblock, NULL }, + { FLDT_CHARNS, "charns", fp_charns, NULL, SI(bitsz(char)), 0, NULL, + NULL }, + { FLDT_CHARS, "chars", fp_num, "%c", SI(bitsz(char)), 0, NULL, NULL }, + { FLDT_CNTBT, "cntbt", NULL, (char *)cntbt_flds, cntbt_size, FTARG_SIZE, + NULL, cntbt_flds }, + { FLDT_CNTBTKEY, "cntbtkey", fp_sarray, (char *)cntbt_key_flds, + SI(bitsz(xfs_alloc_key_t)), 0, NULL, cntbt_key_flds }, + { FLDT_CNTBTPTR, "cntbtptr", fp_num, "%u", SI(bitsz(xfs_alloc_ptr_t)), + 0, fa_agblock, NULL }, + { FLDT_CNTBTREC, "cntbtrec", fp_sarray, (char *)cntbt_rec_flds, + SI(bitsz(xfs_alloc_rec_t)), 0, NULL, cntbt_rec_flds }, + { FLDT_DEV, "dev", fp_num, "%#x", SI(bitsz(xfs_dev_t)), 0, NULL, NULL }, + { FLDT_DFILOFFA, "dfiloffa", fp_num, "%llu", SI(bitsz(xfs_dfiloff_t)), + 0, fa_dfiloffa, NULL }, + { FLDT_DFILOFFD, "dfiloffd", fp_num, "%llu", SI(bitsz(xfs_dfiloff_t)), + 0, fa_dfiloffd, NULL }, + { FLDT_DFSBNO, "dfsbno", fp_num, "%llu", SI(bitsz(xfs_dfsbno_t)), + FTARG_DONULL, fa_dfsbno, NULL }, + { FLDT_DINODE_A, "dinode_a", NULL, (char *)inode_a_flds, inode_a_size, + FTARG_SIZE|FTARG_OKEMPTY, NULL, inode_a_flds }, + { FLDT_DINODE_CORE, "dinode_core", NULL, (char *)inode_core_flds, + SI(bitsz(xfs_dinode_core_t)), 0, NULL, inode_core_flds }, + { FLDT_DINODE_FMT, "dinode_fmt", fp_dinode_fmt, NULL, + SI(bitsz(__int8_t)), 0, NULL, NULL }, + { FLDT_DINODE_U, "dinode_u", NULL, (char *)inode_u_flds, inode_u_size, + FTARG_SIZE|FTARG_OKEMPTY, NULL, inode_u_flds }, + { FLDT_DIR, "dir", NULL, (char *)dir_flds, dir_size, FTARG_SIZE, NULL, + dir_flds }, + { FLDT_DIR2, "dir2", NULL, (char *)dir2_flds, dir2_size, FTARG_SIZE, + NULL, dir2_flds }, + { FLDT_DIR2_BLOCK_TAIL, "dir2_block_tail", NULL, + (char *)dir2_block_tail_flds, SI(bitsz(xfs_dir2_block_tail_t)), 0, + NULL, dir2_block_tail_flds }, + { FLDT_DIR2_DATA_FREE, "dir2_data_free", NULL, + (char *)dir2_data_free_flds, SI(bitsz(xfs_dir2_data_free_t)), 0, NULL, + dir2_data_free_flds }, + { FLDT_DIR2_DATA_HDR, "dir2_data_hdr", NULL, (char *)dir2_data_hdr_flds, + SI(bitsz(xfs_dir2_data_hdr_t)), 0, NULL, dir2_data_hdr_flds }, + { FLDT_DIR2_DATA_OFF, "dir2_data_off", fp_num, "%#x", + SI(bitsz(xfs_dir2_data_off_t)), 0, NULL, NULL }, + { FLDT_DIR2_DATA_OFFNZ, "dir2_data_offnz", fp_num, "%#x", + SI(bitsz(xfs_dir2_data_off_t)), FTARG_SKIPZERO, NULL, NULL }, + { FLDT_DIR2_DATA_UNION, "dir2_data_union", NULL, + (char *)dir2_data_union_flds, dir2_data_union_size, FTARG_SIZE, NULL, + dir2_data_union_flds }, + { FLDT_DIR2_FREE_HDR, "dir2_free_hdr", NULL, (char *)dir2_free_hdr_flds, + SI(bitsz(xfs_dir2_free_hdr_t)), 0, NULL, dir2_free_hdr_flds }, + { FLDT_DIR2_INO4, "dir2_ino4", fp_num, "%u", SI(bitsz(xfs_dir2_ino4_t)), + 0, fa_ino4, NULL }, + { FLDT_DIR2_INO8, "dir2_ino8", fp_num, "%llu", + SI(bitsz(xfs_dir2_ino8_t)), 0, fa_ino8, NULL }, + { FLDT_DIR2_INOU, "dir2_inou", NULL, (char *)dir2_inou_flds, + dir2_inou_size, FTARG_SIZE, NULL, dir2_inou_flds }, + { FLDT_DIR2_LEAF_ENTRY, "dir2_leaf_entry", NULL, + (char *)dir2_leaf_entry_flds, SI(bitsz(xfs_dir2_leaf_entry_t)), 0, + NULL, dir2_leaf_entry_flds }, + { FLDT_DIR2_LEAF_HDR, "dir2_leaf_hdr", NULL, (char *)dir2_leaf_hdr_flds, + SI(bitsz(xfs_dir2_leaf_hdr_t)), 0, NULL, dir2_leaf_hdr_flds }, + { FLDT_DIR2_LEAF_TAIL, "dir2_leaf_tail", NULL, + (char *)dir2_leaf_tail_flds, SI(bitsz(xfs_dir2_leaf_tail_t)), 0, NULL, + dir2_leaf_tail_flds }, + { FLDT_DIR2_SF_ENTRY, "dir2_sf_entry", NULL, (char *)dir2_sf_entry_flds, + dir2_sf_entry_size, FTARG_SIZE, NULL, dir2_sf_entry_flds }, + { FLDT_DIR2_SF_HDR, "dir2_sf_hdr", NULL, (char *)dir2_sf_hdr_flds, + dir2_sf_hdr_size, FTARG_SIZE, NULL, dir2_sf_hdr_flds }, + { FLDT_DIR2_SF_OFF, "dir2_sf_off", fp_num, "%#x", + SI(bitsz(xfs_dir2_sf_off_t)), 0, NULL, NULL }, + { FLDT_DIR2SF, "dir2sf", NULL, (char *)dir2sf_flds, dir2sf_size, + FTARG_SIZE, NULL, dir2sf_flds }, + { FLDT_DIR_BLKINFO, "dir_blkinfo", NULL, (char *)dir_blkinfo_flds, + SI(bitsz(struct xfs_da_blkinfo)), 0, NULL, dir_blkinfo_flds }, + { FLDT_DIR_INO, "dir_ino", fp_num, "%llu", SI(bitsz(xfs_dir_ino_t)), 0, + fa_ino, NULL }, + { FLDT_DIR_LEAF_ENTRY, "dir_leaf_entry", fp_sarray, + (char *)dir_leaf_entry_flds, SI(bitsz(struct xfs_dir_leaf_entry)), 0, + NULL, dir_leaf_entry_flds }, + { FLDT_DIR_LEAF_HDR, "dir_leaf_hdr", NULL, (char *)dir_leaf_hdr_flds, + SI(bitsz(struct xfs_dir_leaf_hdr)), 0, NULL, dir_leaf_hdr_flds }, + { FLDT_DIR_LEAF_MAP, "dir_leaf_map", fp_sarray, + (char *)dir_leaf_map_flds, SI(bitsz(struct xfs_dir_leaf_map)), 0, + NULL, dir_leaf_map_flds }, + { FLDT_DIR_LEAF_NAME, "dir_leaf_name", NULL, (char *)dir_leaf_name_flds, + dir_leaf_name_size, FTARG_SIZE, NULL, dir_leaf_name_flds }, + { FLDT_DIR_NODE_ENTRY, "dir_node_entry", fp_sarray, + (char *)dir_node_entry_flds, SI(bitsz(struct xfs_da_node_entry)), 0, + NULL, dir_node_entry_flds }, + { FLDT_DIR_NODE_HDR, "dir_node_hdr", NULL, (char *)dir_node_hdr_flds, + SI(bitsz(struct xfs_da_node_hdr)), 0, NULL, dir_node_hdr_flds }, + { FLDT_DIR_SF_ENTRY, "dir_sf_entry", NULL, (char *)dir_sf_entry_flds, + dir_sf_entry_size, FTARG_SIZE, NULL, dir_sf_entry_flds }, + { FLDT_DIR_SF_HDR, "dir_sf_hdr", NULL, (char *)dir_sf_hdr_flds, + SI(bitsz(struct xfs_dir_sf_hdr)), 0, NULL, dir_sf_hdr_flds }, + { FLDT_DIRBLOCK, "dirblock", fp_num, "%u", SI(bitsz(__uint32_t)), 0, + fa_dirblock, NULL }, + { FLDT_DIRSHORT, "dirshort", NULL, (char *)dir_shortform_flds, + dirshort_size, FTARG_SIZE, NULL, dir_shortform_flds }, + { FLDT_DISK_DQUOT, "disk_dquot", NULL, (char *)disk_dquot_flds, + SI(bitsz(xfs_disk_dquot_t)), 0, NULL, disk_dquot_flds }, + { FLDT_DQBLK, "dqblk", NULL, (char *)dqblk_flds, SI(bitsz(xfs_dqblk_t)), + 0, NULL, dqblk_flds }, + { FLDT_DQID, "dqid", fp_num, "%d", SI(bitsz(xfs_dqid_t)), 0, NULL, + NULL }, + { FLDT_DRFSBNO, "drfsbno", fp_num, "%llu", SI(bitsz(xfs_drfsbno_t)), + FTARG_DONULL, fa_drfsbno, NULL }, + { FLDT_DRTBNO, "drtbno", fp_num, "%llu", SI(bitsz(xfs_drtbno_t)), + FTARG_DONULL, fa_drtbno, NULL }, + { FLDT_EXTLEN, "extlen", fp_num, "%u", SI(bitsz(xfs_extlen_t)), 0, NULL, + NULL }, + { FLDT_EXTNUM, "extnum", fp_num, "%d", SI(bitsz(xfs_extnum_t)), + FTARG_SIGNED, NULL, NULL }, + { FLDT_FSIZE, "fsize", fp_num, "%lld", SI(bitsz(xfs_fsize_t)), + FTARG_SIGNED, NULL, NULL }, + { FLDT_INO, "ino", fp_num, "%llu", SI(bitsz(xfs_ino_t)), FTARG_DONULL, + fa_ino, NULL }, + { FLDT_INOBT, "inobt", NULL, (char *)inobt_flds, inobt_size, + FTARG_SIZE, NULL, inobt_flds }, + { FLDT_INOBTKEY, "inobtkey", fp_sarray, (char *)inobt_key_flds, + SI(bitsz(xfs_inobt_key_t)), 0, NULL, inobt_key_flds }, + { FLDT_INOBTPTR, "inobtptr", fp_num, "%u", SI(bitsz(xfs_inobt_ptr_t)), + 0, fa_agblock, NULL }, + { FLDT_INOBTREC, "inobtrec", fp_sarray, (char *)inobt_rec_flds, + SI(bitsz(xfs_inobt_rec_t)), 0, NULL, inobt_rec_flds }, + { FLDT_INODE, "inode", NULL, (char *)inode_flds, inode_size, FTARG_SIZE, + NULL, inode_flds }, + { FLDT_INOFREE, "inofree", fp_num, "%#llx", SI(bitsz(xfs_inofree_t)), 0, + NULL, NULL }, + { FLDT_INT16D, "int16d", fp_num, "%d", SI(bitsz(__int16_t)), + FTARG_SIGNED, NULL, NULL }, + { FLDT_INT32D, "int32d", fp_num, "%d", SI(bitsz(__int32_t)), + FTARG_SIGNED, NULL, NULL }, + { FLDT_INT64D, "int64d", fp_num, "%lld", SI(bitsz(__int64_t)), + FTARG_SIGNED, NULL, NULL }, + { FLDT_INT8D, "int8d", fp_num, "%d", SI(bitsz(__int8_t)), FTARG_SIGNED, + NULL, NULL }, + { FLDT_NSEC, "nsec", fp_num, "%09d", SI(bitsz(__int32_t)), FTARG_SIGNED, + NULL, NULL }, + { FLDT_QCNT, "qcnt", fp_num, "%llu", SI(bitsz(xfs_qcnt_t)), 0, NULL, + NULL }, + { FLDT_QWARNCNT, "qwarncnt", fp_num, "%u", SI(bitsz(xfs_qwarncnt_t)), 0, + NULL, NULL }, + { FLDT_SB, "sb", NULL, (char *)sb_flds, sb_size, FTARG_SIZE, NULL, + sb_flds }, + { FLDT_TIME, "time", fp_time, NULL, SI(bitsz(__int32_t)), FTARG_SIGNED, + NULL, NULL }, + { FLDT_TIMESTAMP, "timestamp", NULL, (char *)timestamp_flds, + SI(bitsz(xfs_timestamp_t)), 0, NULL, timestamp_flds }, + { FLDT_UINT1, "uint1", fp_num, "%u", SI(1), 0, NULL, NULL }, + { FLDT_UINT16D, "uint16d", fp_num, "%u", SI(bitsz(__uint16_t)), 0, NULL, + NULL }, + { FLDT_UINT16O, "uint16o", fp_num, "%#o", SI(bitsz(__uint16_t)), 0, + NULL, NULL }, + { FLDT_UINT16X, "uint16x", fp_num, "%#x", SI(bitsz(__uint16_t)), 0, + NULL, NULL }, + { FLDT_UINT32D, "uint32d", fp_num, "%u", SI(bitsz(__uint32_t)), 0, NULL, + NULL }, + { FLDT_UINT32O, "uint32o", fp_num, "%#o", SI(bitsz(__uint32_t)), 0, + NULL, NULL }, + { FLDT_UINT32X, "uint32x", fp_num, "%#x", SI(bitsz(__uint32_t)), 0, + NULL, NULL }, + { FLDT_UINT64D, "uint64d", fp_num, "%llu", SI(bitsz(__uint64_t)), 0, + NULL, NULL }, + { FLDT_UINT64O, "uint64o", fp_num, "%#llo", SI(bitsz(__uint64_t)), 0, + NULL, NULL }, + { FLDT_UINT64X, "uint64x", fp_num, "%#llx", SI(bitsz(__uint64_t)), 0, + NULL, NULL }, + { FLDT_UINT8D, "uint8d", fp_num, "%u", SI(bitsz(__uint8_t)), 0, NULL, + NULL }, + { FLDT_UINT8O, "uint8o", fp_num, "%#o", SI(bitsz(__uint8_t)), 0, NULL, + NULL }, + { FLDT_UINT8X, "uint8x", fp_num, "%#x", SI(bitsz(__uint8_t)), 0, NULL, + NULL }, + { FLDT_UUID, "uuid", fp_uuid, NULL, SI(bitsz(uuid_t)), 0, NULL, NULL }, + { FLDT_ZZZ, NULL } +}; + +int +bitoffset( + const field_t *f, + void *obj, + int startoff, + int idx) +{ + + if (!(f->flags & FLD_OFFSET)) { + if (f->flags & FLD_ARRAY) { + int abase; +#ifdef DEBUG + const ftattr_t *fa = &ftattrtab[f->ftyp]; +#endif + + abase = (f->flags & FLD_ABASE1) != 0; + ASSERT(fa->ftyp == f->ftyp); + ASSERT((fa->arg & FTARG_SIZE) == 0); + return (int)(__psint_t)f->offset + + (idx - abase) * fsize(f, obj, startoff, idx); + } else + return (int)(__psint_t)f->offset; + } else + return (*f->offset)(obj, startoff, idx); +} + +int +fcount( + const field_t *f, + void *obj, + int startoff) +{ + if (!(f->flags & FLD_COUNT)) + return (int)(__psint_t)f->count; + else + return (*f->count)(obj, startoff); +} + +const field_t * +findfield( + char *name, + const field_t *fields, + void *obj, + int startoff) +{ + const field_t *f; + + /* we only match if this field name matches and has a non-zero count */ + for (f = fields; f->name; f++) + if (strcmp(f->name, name) == 0 && fcount(f, obj, startoff)) + return f; + return NULL; +} + +int +fsize( + const field_t *f, + void *obj, + int startoff, + int idx) +{ + const ftattr_t *fa; + + fa = &ftattrtab[f->ftyp]; + ASSERT(fa->ftyp == f->ftyp); + if (!(fa->arg & FTARG_SIZE)) + return (int)(__psint_t)fa->size; + else + return (*fa->size)(obj, startoff, idx); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/field.h linux-2.4-xfs/cmd/xfsprogs/db/field.h --- linux-2.4.7/cmd/xfsprogs/db/field.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/field.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +typedef enum fldt { + FLDT_AEXTNUM, + FLDT_AGBLOCK, + FLDT_AGBLOCKNZ, + FLDT_AGF, + FLDT_AGFL, + FLDT_AGI, + FLDT_AGINO, + FLDT_AGINONN, + FLDT_AGNUMBER, + FLDT_ATTR, + FLDT_ATTR_BLKINFO, + FLDT_ATTR_LEAF_ENTRY, + FLDT_ATTR_LEAF_HDR, + FLDT_ATTR_LEAF_MAP, + FLDT_ATTR_LEAF_NAME, + FLDT_ATTR_NODE_ENTRY, + FLDT_ATTR_NODE_HDR, + FLDT_ATTR_SF_ENTRY, + FLDT_ATTR_SF_HDR, + FLDT_ATTRBLOCK, + FLDT_ATTRSHORT, + FLDT_BMAPBTA, + FLDT_BMAPBTAKEY, + FLDT_BMAPBTAPTR, + FLDT_BMAPBTAREC, + FLDT_BMAPBTD, + FLDT_BMAPBTDKEY, + FLDT_BMAPBTDPTR, + FLDT_BMAPBTDREC, + FLDT_BMROOTA, + FLDT_BMROOTAKEY, + FLDT_BMROOTAPTR, + FLDT_BMROOTD, + FLDT_BMROOTDKEY, + FLDT_BMROOTDPTR, + FLDT_BNOBT, + FLDT_BNOBTKEY, + FLDT_BNOBTPTR, + FLDT_BNOBTREC, + FLDT_CEXTFLG, + FLDT_CEXTLEN, + FLDT_CFILEOFFA, + FLDT_CFILEOFFD, + FLDT_CFSBLOCK, + FLDT_CHARNS, + FLDT_CHARS, + FLDT_CNTBT, + FLDT_CNTBTKEY, + FLDT_CNTBTPTR, + FLDT_CNTBTREC, + FLDT_DEV, + FLDT_DFILOFFA, + FLDT_DFILOFFD, + FLDT_DFSBNO, + FLDT_DINODE_A, + FLDT_DINODE_CORE, + FLDT_DINODE_FMT, + FLDT_DINODE_U, + FLDT_DIR, + FLDT_DIR2, + FLDT_DIR2_BLOCK_TAIL, + FLDT_DIR2_DATA_FREE, + FLDT_DIR2_DATA_HDR, + FLDT_DIR2_DATA_OFF, + FLDT_DIR2_DATA_OFFNZ, + FLDT_DIR2_DATA_UNION, + FLDT_DIR2_FREE_HDR, + FLDT_DIR2_INO4, + FLDT_DIR2_INO8, + FLDT_DIR2_INOU, + FLDT_DIR2_LEAF_ENTRY, + FLDT_DIR2_LEAF_HDR, + FLDT_DIR2_LEAF_TAIL, + FLDT_DIR2_SF_ENTRY, + FLDT_DIR2_SF_HDR, + FLDT_DIR2_SF_OFF, + FLDT_DIR2SF, + FLDT_DIR_BLKINFO, + FLDT_DIR_INO, + FLDT_DIR_LEAF_ENTRY, + FLDT_DIR_LEAF_HDR, + FLDT_DIR_LEAF_MAP, + FLDT_DIR_LEAF_NAME, + FLDT_DIR_NODE_ENTRY, + FLDT_DIR_NODE_HDR, + FLDT_DIR_SF_ENTRY, + FLDT_DIR_SF_HDR, + FLDT_DIRBLOCK, + FLDT_DIRSHORT, + FLDT_DISK_DQUOT, + FLDT_DQBLK, + FLDT_DQID, + FLDT_DRFSBNO, + FLDT_DRTBNO, + FLDT_EXTLEN, + FLDT_EXTNUM, + FLDT_FSIZE, + FLDT_INO, + FLDT_INOBT, + FLDT_INOBTKEY, + FLDT_INOBTPTR, + FLDT_INOBTREC, + FLDT_INODE, + FLDT_INOFREE, + FLDT_INT16D, + FLDT_INT32D, + FLDT_INT64D, + FLDT_INT8D, + FLDT_NSEC, + FLDT_QCNT, + FLDT_QWARNCNT, + FLDT_SB, + FLDT_TIME, + FLDT_TIMESTAMP, + FLDT_UINT1, + FLDT_UINT16D, + FLDT_UINT16O, + FLDT_UINT16X, + FLDT_UINT32D, + FLDT_UINT32O, + FLDT_UINT32X, + FLDT_UINT64D, + FLDT_UINT64O, + FLDT_UINT64X, + FLDT_UINT8D, + FLDT_UINT8O, + FLDT_UINT8X, + FLDT_UUID, + FLDT_ZZZ /* mark last entry */ +} fldt_t; + +typedef int (*offset_fnc_t)(void *obj, int startoff, int idx); +#define OI(o) ((offset_fnc_t)(__psint_t)(o)) + +typedef int (*count_fnc_t)(void *obj, int startoff); +#define CI(c) ((count_fnc_t)(__psint_t)(c)) +#define C1 CI(1) + +typedef struct field +{ + char *name; + fldt_t ftyp; + offset_fnc_t offset; + count_fnc_t count; + int flags; + typnm_t next; +} field_t; + +/* + * flag values + */ +#define FLD_ABASE1 1 /* field array base is 1 not 0 */ +#define FLD_SKIPALL 2 /* skip this field in an all-fields print */ +#define FLD_ARRAY 4 /* this field is an array */ +#define FLD_OFFSET 8 /* offset value is a function pointer */ +#define FLD_COUNT 16 /* count value is a function pointer */ + +typedef int (*size_fnc_t)(void *obj, int startoff, int idx); +#define SI(s) ((size_fnc_t)(__psint_t)(s)) + +typedef struct ftattr +{ + fldt_t ftyp; + char *name; + prfnc_t prfunc; + char *fmtstr; + size_fnc_t size; + int arg; + adfnc_t adfunc; + const field_t *subfld; +} ftattr_t; +extern const ftattr_t ftattrtab[]; + +/* + * arg values + */ +#define FTARG_SKIPZERO 1 /* skip 0 words */ +#define FTARG_DONULL 2 /* make -1 words be "null" */ +#define FTARG_SKIPNULL 4 /* skip -1 words */ +#define FTARG_SIGNED 8 /* field value is signed */ +#define FTARG_SIZE 16 /* size field is a function */ +#define FTARG_SKIPNMS 32 /* skip printing names this time */ +#define FTARG_OKEMPTY 64 /* ok if this (union type) is empty */ + +extern int bitoffset(const field_t *f, void *obj, int startoff, + int idx); +extern int fcount(const field_t *f, void *obj, int startoff); +extern const field_t *findfield(char *name, const field_t *fields, + void *obj, int startoff); +extern int fsize(const field_t *f, void *obj, int startoff, + int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/flist.c linux-2.4-xfs/cmd/xfsprogs/db/flist.c --- linux-2.4.7/cmd/xfsprogs/db/flist.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/flist.c Thu Apr 12 18:49:04 2001 @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "flist.h" +#include "debug.h" +#include "output.h" +#include "malloc.h" + +static void flist_expand_arrays(flist_t *fl); +static void flist_expand_structs(flist_t *fl, void *obj); +static flist_t *flist_replicate(flist_t *fl); +static ftok_t *flist_split(char *s); +static void ftok_free(ftok_t *ft); + +static void +flist_expand_arrays( + flist_t *fl) +{ + const field_t *f; +#ifdef DEBUG + const ftattr_t *fa; +#endif + int high; + int idx; + int low; + flist_t *new; + flist_t *prev; + flist_t *sib; + + f = fl->fld; +#ifdef DEBUG + fa = &ftattrtab[f->ftyp]; +#endif + ASSERT(fa->ftyp == f->ftyp); + ASSERT(f->flags & FLD_ARRAY); + low = fl->low; + high = fl->high; + fl->high = fl->low; + sib = fl->sibling; + for (idx = low + 1, prev = fl; idx <= high; idx++) { + new = flist_make(f->name); + new->fld = f; + new->low = new->high = idx; + new->flags |= FL_OKLOW | FL_OKHIGH; + new->child = flist_replicate(fl->child); + prev->sibling = new; + prev = new; + } + prev->sibling = sib; +} + +static void +flist_expand_structs( + flist_t *fl, + void *obj) +{ + const field_t *cf; + const field_t *f; + const ftattr_t *fa; + flist_t *new; + flist_t *prev; + + f = fl->fld; + fa = &ftattrtab[f->ftyp]; + ASSERT(fa->ftyp == f->ftyp); + ASSERT(fa->subfld != NULL); + ASSERT(fl->child == NULL); + for (cf = fa->subfld, prev = NULL; cf->name != NULL; cf++) { + if (fcount(cf, obj, fl->offset) == 0) + continue; + if (cf->flags & FLD_SKIPALL) + continue; + new = flist_make(cf->name); + new->fld = cf; + if (prev) + prev->sibling = new; + else + fl->child = new; + prev = new; + } +} + +void +flist_free( + flist_t *fl) +{ + if (fl->child) + flist_free(fl->child); + if (fl->sibling) + flist_free(fl->sibling); + if (fl->name) + xfree(fl->name); + xfree(fl); +} + +flist_t * +flist_make( + char *name) +{ + flist_t *fl; + + fl = xmalloc(sizeof(*fl)); + fl->name = xstrdup(name); + fl->fld = NULL; + fl->child = NULL; + fl->sibling = NULL; + fl->low = 0; + fl->high = 0; + fl->flags = 0; + fl->offset = 0; + return fl; +} + +int +flist_parse( + const field_t *fields, + flist_t *fl, + void *obj, + int startoff) +{ + const field_t *f; + const ftattr_t *fa; + int high; + int low; + + while (fl) { + f = findfield(fl->name, fields, obj, startoff); + if (f == NULL) { + dbprintf("field %s not found\n", fl->name); + return 0; + } + fl->fld = f; + fa = &ftattrtab[f->ftyp]; + ASSERT(fa->ftyp == f->ftyp); + if (f->flags & FLD_ARRAY) { + low = (f->flags & FLD_ABASE1) != 0; + high = fcount(f, obj, startoff) + low - 1; + if (low > high) { + dbprintf("no elements in %s\n", fl->name); + return 0; + } + if (fl->flags & FL_OKHIGH) { + if (fl->low < low || fl->low > high || + fl->high < low || fl->high > high) { + dbprintf("indices %d-%d for field %s " + "out of range %d-%d\n", + fl->low, fl->high, fl->name, + low, high); + return 0; + } + } else if (fl->flags & FL_OKLOW) { + if (fl->low < low || fl->low > high) { + dbprintf("index %d for field %s out of " + "range %d-%d\n", + fl->low, fl->name, low, high); + return 0; + } + fl->high = fl->low; + fl->flags |= FL_OKHIGH; + } else { + fl->low = low; + fl->high = high; + fl->flags |= FL_OKLOW | FL_OKHIGH; + } + } else { + if (fl->flags & FL_OKLOW) { + dbprintf("field %s is not an array\n", + fl->name); + return 0; + } + } + fl->offset = startoff + bitoffset(f, obj, startoff, fl->low); + if ((fl->child != NULL || fa->prfunc == NULL) && + (f->flags & FLD_ARRAY) && fl->low != fl->high) + flist_expand_arrays(fl); + if (fa->prfunc == NULL && fl->child == NULL) + flist_expand_structs(fl, obj); + if (fl->child) { + if (fa->subfld == NULL) { + dbprintf("field %s has no subfields\n", + fl->name); + return 0; + } + if (!flist_parse(fa->subfld, fl->child, obj, + fl->offset)) + return 0; + } + fl = fl->sibling; + } + return 1; +} + +void +flist_print( + flist_t *fl) +{ + if (!(debug_state & DEBUG_FLIST)) + return; + while (fl) { + dbprintf("fl@%p:\n", fl); + dbprintf("\tname=%s, fld=%p, child=%p, sibling=%p\n", + fl->name, fl->fld, fl->child, fl->sibling); + dbprintf("\tlow=%d, high=%d, flags=%d (%s%s), offset=%d\n", + fl->low, fl->high, fl->flags, + fl->flags & FL_OKLOW ? "oklow " : "", + fl->flags & FL_OKHIGH ? "okhigh" : "", fl->offset); + dbprintf("\tfld->name=%s, fld->ftyp=%d (%s)\n", + fl->fld->name, fl->fld->ftyp, + ftattrtab[fl->fld->ftyp].name); + dbprintf("\tfld->flags=%d (%s%s%s%s%s)\n", fl->fld->flags, + fl->fld->flags & FLD_ABASE1 ? "abase1 " : "", + fl->fld->flags & FLD_SKIPALL ? "skipall " : "", + fl->fld->flags & FLD_ARRAY ? "array " : "", + fl->fld->flags & FLD_OFFSET ? "offset " : "", + fl->fld->flags & FLD_COUNT ? "count " : ""); + if (fl->child) + flist_print(fl->child); + fl = fl->sibling; + } +} + +static flist_t * +flist_replicate( + flist_t *f) +{ + flist_t *new; + + if (f == NULL) + return NULL; + new = flist_make(f->name); + new->fld = f->fld; + new->child = flist_replicate(f->child); + new->sibling = flist_replicate(f->sibling); + new->low = f->low; + new->high = f->high; + new->flags = f->flags; + new->offset = f->offset; + return new; +} + +flist_t * +flist_scan( + char *name) +{ + flist_t *fl; + flist_t *lfl; + flist_t *nfl; + int num; + ftok_t *p; + ftok_t *v; + char *x; + + v = flist_split(name); + if (!v) + return NULL; + p = v; + fl = lfl = NULL; + while (p->tokty != TT_END) { + if (p->tokty != TT_NAME) + goto bad; + nfl = flist_make(p->tok); + if (lfl) + lfl->child = nfl; + else + fl = nfl; + lfl = nfl; + p++; + if (p->tokty == TT_LB) { + p++; + if (p->tokty != TT_NUM) + goto bad; + num = (int)strtoul(p->tok, &x, 0); + if (*x != '\0') + goto bad; + nfl->flags |= FL_OKLOW; + nfl->low = num; + p++; + if (p->tokty == TT_DASH) { + p++; + if (p->tokty != TT_NUM) + goto bad; + num = (int)strtoul(p->tok, &x, 0); + if (*x != '\0') + goto bad; + nfl->flags |= FL_OKHIGH; + nfl->high = num; + p++; + } + if (p->tokty != TT_RB) + goto bad; + p++; + } + if (p->tokty == TT_DOT) { + p++; + if (p->tokty == TT_END) + goto bad; + } + } + ftok_free(v); + return fl; +bad: + dbprintf("bad syntax in field name %s\n", name); + ftok_free(v); + if (fl) + flist_free(fl); + return NULL; +} + +static ftok_t * +flist_split( + char *s) +{ + char *a; + int i; + static char *idchars; + static char *initidchar; + int l; + int tailskip = 0; + static char *numchars; + static char *xnumchars; /* extended for hex conversion */ + int nv; + static char punctchars[] = "[-]."; + static tokty_t puncttypes[] = { TT_LB, TT_DASH, TT_RB, TT_DOT }; + tokty_t t; + ftok_t *v; + + if (idchars == NULL) { + idchars = xmalloc(26 + 10 + 1 + 1); + initidchar = xmalloc(26 + 1); + numchars = xmalloc(10 + 1); + xnumchars = xmalloc(12 + 1); + for (i = 'a'; i <= 'z'; i++) { + idchars[i - 'a'] = i; + initidchar[i - 'a'] = i; + } + + for (i = '0'; i <= '9'; i++) { + idchars[26 + (i - '0')] = i; + numchars[i - '0'] = i; + xnumchars[i - '0'] = i; + } + idchars[26 + 10] = '_'; + idchars[26 + 10 + 1] = '\0'; + initidchar[26] = '\0'; + numchars[10] = '\0'; + xnumchars[10] = 'x'; + xnumchars[11] = 'X'; + xnumchars[12] = '\0'; + } + nv = 0; + v = xmalloc(sizeof(*v)); + v->tok = NULL; + while (*s) { + /* need to add string handling */ + if (*s == '\"') { + s++; /* skip first quote */ + if ((a = strrchr(s, '\"')) == NULL) { + dbprintf("missing closing quote %s\n", s); + ftok_free(v); + return NULL; + } + tailskip = 1; /* skip remaing quote */ + l = (int)(a - s); + t = TT_STRING; + } else if (strchr(initidchar, *s)) { + l = (int)strspn(s, idchars); + t = TT_NAME; + } else if (strchr(numchars, *s)) { + l = (int)strspn(s, xnumchars); + t = TT_NUM; + } else if ((a = strchr(punctchars, *s))) { + l = 1; + t = puncttypes[a - punctchars]; + } else { + dbprintf("bad character in field %s\n", s); + ftok_free(v); + return NULL; + } + a = xmalloc(l + 1); + strncpy(a, s, l); + a[l] = '\0'; + v = xrealloc(v, (nv + 2) * sizeof(*v)); + v[nv].tok = a; + v[nv].tokty = t; + nv++; + s += l + tailskip; + tailskip = 0; + } + v[nv].tok = NULL; + v[nv].tokty = TT_END; + return v; +} + +static void +ftok_free( + ftok_t *ft) +{ + ftok_t *p; + + for (p = ft; p->tok; p++) + xfree(p->tok); + xfree(ft); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/flist.h linux-2.4-xfs/cmd/xfsprogs/db/flist.h --- linux-2.4.7/cmd/xfsprogs/db/flist.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/flist.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct field; + +typedef struct flist { + char *name; + const struct field *fld; + struct flist *child; + struct flist *sibling; + int low; + int high; + int flags; + int offset; +} flist_t; + +/* + * Flags for flist + */ +#define FL_OKLOW 1 +#define FL_OKHIGH 2 + +typedef enum tokty { + TT_NAME, TT_NUM, TT_STRING, TT_LB, TT_RB, TT_DASH, TT_DOT, TT_END +} tokty_t; + +typedef struct ftok { + char *tok; + tokty_t tokty; +} ftok_t; + +extern void flist_free(flist_t *fl); +extern flist_t *flist_make(char *name); +extern int flist_parse(const struct field *fields, flist_t *fl, void *obj, + int startoff); +extern void flist_print(flist_t *fl); +extern flist_t *flist_scan(char *name); diff -rNu linux-2.4.7/cmd/xfsprogs/db/fprint.c linux-2.4-xfs/cmd/xfsprogs/db/fprint.c --- linux-2.4.7/cmd/xfsprogs/db/fprint.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/fprint.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "inode.h" +#include "inobt.h" +#include "bit.h" +#include "print.h" +#include "output.h" +#include "sig.h" +#include "malloc.h" + +int +fp_charns( + void *obj, + int bit, + int count, + char *fmtstr, + int size, + int arg, + int base, + int array) +{ + int i; + char *p; + + ASSERT(bitoffs(bit) == 0); + ASSERT(size == bitsz(char)); + dbprintf("\""); + for (i = 0, p = (char *)obj + byteize(bit); + i < count && !seenint(); + i++, p++) { + if (*p == '\\' || *p == '\'' || *p == '"' || *p == '\?') + dbprintf("\\%c", *p); + else if (isgraph(*p) || *p == ' ') + dbprintf("%c", *p); + else if (*p == '\a' || *p == '\b' || *p == '\f' || *p == '\n' || + *p == '\r' || *p == '\t' || *p == '\v') + dbprintf("\\%c", *p + ('a' - '\a')); + else + dbprintf("\\%03o", *p & 0xff); + } + dbprintf("\""); + return 1; +} + +int +fp_num( + void *obj, + int bit, + int count, + char *fmtstr, + int size, + int arg, + int base, + int array) +{ + int bitpos; + int i; + int isnull; + __int64_t val; + + for (i = 0, bitpos = bit; + i < count && !seenint(); + i++, bitpos += size) { + val = getbitval(obj, bitpos, size, + (arg & FTARG_SIGNED) ? BVSIGNED : BVUNSIGNED); + if ((arg & FTARG_SKIPZERO) && val == 0) + continue; + isnull = (arg & FTARG_SIGNED) || size == 64 ? + val == -1LL : val == ((1LL << size) - 1LL); + if ((arg & FTARG_SKIPNULL) && isnull) + continue; + if (array) + dbprintf("%d:", i + base); + if ((arg & FTARG_DONULL) && isnull) + dbprintf("null"); + else if (size > 32) + dbprintf(fmtstr, val); + else + dbprintf(fmtstr, (__int32_t)val); + if (i < count - 1) + dbprintf(" "); + } + return 1; +} + +/*ARGSUSED*/ +int +fp_sarray( + void *obj, + int bit, + int count, + char *fmtstr, + int size, + int arg, + int base, + int array) +{ + print_sarray(obj, bit, count, size, base, array, + (const field_t *)fmtstr, (arg & FTARG_SKIPNMS) != 0); + return 1; +} + +/*ARGSUSED*/ +int +fp_time( + void *obj, + int bit, + int count, + char *fmtstr, + int size, + int arg, + int base, + int array) +{ + int bitpos; + char *c; + int i; + time_t t; + + ASSERT(bitoffs(bit) == 0); + for (i = 0, bitpos = bit; + i < count && !seenint(); + i++, bitpos += size) { + if (array) + dbprintf("%d:", i + base); + t=(time_t)getbitval((char *)obj + byteize(bitpos), 0, sizeof(time_t)*8, 0); + c = ctime(&t); + dbprintf("%24.24s", c); + if (i < count - 1) + dbprintf(" "); + } + return 1; +} + +/*ARGSUSED*/ +int +fp_uuid( + void *obj, + int bit, + int count, + char *fmtstr, + int size, + int arg, + int base, + int array) +{ + char bp[40]; /* UUID string is 36 chars + trailing '\0' */ + int i; + uuid_t *p; + + ASSERT(bitoffs(bit) == 0); + for (p = (uuid_t *)((char *)obj + byteize(bit)), i = 0; + i < count && !seenint(); + i++, p++) { + if (array) + dbprintf("%d:", i + base); + uuid_unparse(*p, bp); + dbprintf("%s", bp); + if (i < count - 1) + dbprintf(" "); + } + return 1; +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/fprint.h linux-2.4-xfs/cmd/xfsprogs/db/fprint.h --- linux-2.4.7/cmd/xfsprogs/db/fprint.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/fprint.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +typedef int (*prfnc_t)(void *obj, int bit, int count, char *fmtstr, int size, + int arg, int base, int array); + +extern int fp_charns(void *obj, int bit, int count, char *fmtstr, int size, + int arg, int base, int array); +extern int fp_num(void *obj, int bit, int count, char *fmtstr, int size, + int arg, int base, int array); +extern int fp_sarray(void *obj, int bit, int count, char *fmtstr, int size, + int arg, int base, int array); +extern int fp_time(void *obj, int bit, int count, char *fmtstr, int size, + int arg, int base, int array); +extern int fp_uuid(void *obj, int bit, int count, char *fmtstr, int size, + int arg, int base, int array); diff -rNu linux-2.4.7/cmd/xfsprogs/db/frag.c linux-2.4-xfs/cmd/xfsprogs/db/frag.c --- linux-2.4.7/cmd/xfsprogs/db/frag.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/frag.c Mon Apr 2 21:52:38 2001 @@ -0,0 +1,534 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include "bmap.h" +#include "command.h" +#include "data.h" +#include "frag.h" +#include "io.h" +#include "output.h" +#include "type.h" +#include "mount.h" +#include "malloc.h" + +typedef struct extent { + xfs_fileoff_t startoff; + xfs_filblks_t blockcount; +} extent_t; + +typedef struct extmap { + int naents; + int nents; + extent_t ents[1]; +} extmap_t; +#define EXTMAP_SIZE(n) \ + (offsetof(extmap_t, ents) + (sizeof(extent_t) * (n))) + +static int aflag; +static int dflag; +static __uint64_t extcount_actual; +static __uint64_t extcount_ideal; +static int fflag; +static int lflag; +static int qflag; +static int Rflag; +static int rflag; +static int vflag; + +typedef void (*scan_lbtree_f_t)(xfs_btree_lblock_t *block, + int level, + extmap_t **extmapp, + typnm_t btype); + +typedef void (*scan_sbtree_f_t)(xfs_btree_sblock_t *block, + int level, + xfs_agf_t *agf); + +static extmap_t *extmap_alloc(xfs_extnum_t nex); +static xfs_extnum_t extmap_ideal(extmap_t *extmap); +static void extmap_set_ext(extmap_t **extmapp, xfs_fileoff_t o, + xfs_extlen_t c); +static int frag_f(int argc, char **argv); +static int init(int argc, char **argv); +static void process_bmbt_reclist(xfs_bmbt_rec_32_t *rp, int numrecs, + extmap_t **extmapp); +static void process_btinode(xfs_dinode_t *dip, extmap_t **extmapp, + int whichfork); +static void process_exinode(xfs_dinode_t *dip, extmap_t **extmapp, + int whichfork); +static void process_fork(xfs_dinode_t *dip, int whichfork); +static void process_inode(xfs_agf_t *agf, xfs_agino_t agino, + xfs_dinode_t *dip); +static void scan_ag(xfs_agnumber_t agno); +static void scan_lbtree(xfs_fsblock_t root, int nlevels, + scan_lbtree_f_t func, extmap_t **extmapp, + typnm_t btype); +static void scan_sbtree(xfs_agf_t *agf, xfs_agblock_t root, + int nlevels, scan_sbtree_f_t func, + typnm_t btype); +static void scanfunc_bmap(xfs_btree_lblock_t *ablock, int level, + extmap_t **extmapp, typnm_t btype); +static void scanfunc_ino(xfs_btree_sblock_t *ablock, int level, + xfs_agf_t *agf); + +static const cmdinfo_t frag_cmd = + { "frag", NULL, frag_f, 0, -1, 0, + "[-a] [-d] [-f] [-l] [-r]", + "get file fragmentation data", NULL }; + +static extmap_t * +extmap_alloc( + xfs_extnum_t nex) +{ + extmap_t *extmap; + + if (nex < 1) + nex = 1; + extmap = xmalloc(EXTMAP_SIZE(nex)); + extmap->naents = nex; + extmap->nents = 0; + return extmap; +} + +static xfs_extnum_t +extmap_ideal( + extmap_t *extmap) +{ + extent_t *ep; + xfs_extnum_t rval; + + for (ep = &extmap->ents[0], rval = 0; + ep < &extmap->ents[extmap->nents]; + ep++) { + if (ep == &extmap->ents[0] || + ep->startoff != ep[-1].startoff + ep[-1].blockcount) + rval++; + } + return rval; +} + +static void +extmap_set_ext( + extmap_t **extmapp, + xfs_fileoff_t o, + xfs_extlen_t c) +{ + extmap_t *extmap; + extent_t *ent; + + extmap = *extmapp; + if (extmap->nents == extmap->naents) { + extmap->naents++; + extmap = xrealloc(extmap, EXTMAP_SIZE(extmap->naents)); + *extmapp = extmap; + } + ent = &extmap->ents[extmap->nents]; + ent->startoff = o; + ent->blockcount = c; + extmap->nents++; +} + +void +frag_init(void) +{ + add_command(&frag_cmd); +} + +/* + * Get file fragmentation information. + */ +static int +frag_f( + int argc, + char **argv) +{ + xfs_agnumber_t agno; + double answer; + + if (!init(argc, argv)) + return 0; + for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) + scan_ag(agno); + if (extcount_actual) + answer = (double)(extcount_actual - extcount_ideal) * 100.0 / + (double)extcount_actual; + else + answer = 0.0; + dbprintf("actual %llu, ideal %llu, fragmentation factor %.2f%%\n", + extcount_actual, extcount_ideal, answer); + return 0; +} + +static int +init( + int argc, + char **argv) +{ + int c; + + aflag = dflag = fflag = lflag = qflag = Rflag = rflag = vflag = 0; + optind = 0; + while ((c = getopt(argc, argv, "adflqRrv")) != EOF) { + switch (c) { + case 'a': + aflag = 1; + break; + case 'd': + dflag = 1; + break; + case 'f': + fflag = 1; + break; + case 'l': + lflag = 1; + break; + case 'q': + qflag = 1; + break; + case 'R': + Rflag = 1; + break; + case 'r': + rflag = 1; + break; + case 'v': + vflag = 1; + break; + default: + dbprintf("bad option for frag command\n"); + return 0; + } + } + if (!aflag && !dflag && !fflag && !lflag && !qflag && !Rflag && !rflag) + aflag = dflag = fflag = lflag = qflag = Rflag = rflag = 1; + extcount_actual = extcount_ideal = 0; + return 1; +} + +static void +process_bmbt_reclist( + xfs_bmbt_rec_32_t *rp, + int numrecs, + extmap_t **extmapp) +{ + xfs_dfilblks_t c; + int f; + int i; + xfs_dfiloff_t o; + xfs_dfsbno_t s; + + for (i = 0; i < numrecs; i++, rp++) { + convert_extent((xfs_bmbt_rec_64_t *)rp, &o, &s, &c, &f); + extmap_set_ext(extmapp, (xfs_fileoff_t)o, (xfs_extlen_t)c); + } +} + +static void +process_btinode( + xfs_dinode_t *dip, + extmap_t **extmapp, + int whichfork) +{ + xfs_bmdr_block_t *dib; + int i; + xfs_bmbt_ptr_t *pp; + xfs_bmbt_rec_32_t *rp; + + dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); + if (INT_GET(dib->bb_level, ARCH_CONVERT) == 0) { + rp = (xfs_bmbt_rec_32_t *)XFS_BTREE_REC_ADDR( + XFS_DFORK_SIZE(dip, mp, whichfork), + xfs_bmdr, dib, 1, + XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_SIZE(dip, mp, + whichfork), + xfs_bmdr, 1)); + process_bmbt_reclist(rp, INT_GET(dib->bb_numrecs, ARCH_CONVERT), extmapp); + return; + } + pp = XFS_BTREE_PTR_ADDR(XFS_DFORK_SIZE(dip, mp, whichfork), + xfs_bmdr, dib, 1, + XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_SIZE(dip, mp, whichfork), + xfs_bmdr, 0)); + for (i = 0; i < INT_GET(dib->bb_numrecs, ARCH_CONVERT); i++) + scan_lbtree((xfs_fsblock_t)INT_GET(pp[i], ARCH_CONVERT), INT_GET(dib->bb_level, ARCH_CONVERT), scanfunc_bmap, + extmapp, + whichfork == XFS_DATA_FORK ? TYP_BMAPBTD : TYP_BMAPBTA); +} + +static void +process_exinode( + xfs_dinode_t *dip, + extmap_t **extmapp, + int whichfork) +{ + xfs_bmbt_rec_32_t *rp; + + rp = (xfs_bmbt_rec_32_t *)XFS_DFORK_PTR(dip, whichfork); + process_bmbt_reclist(rp, XFS_DFORK_NEXTENTS(dip, whichfork), extmapp); +} + +static void +process_fork( + xfs_dinode_t *dip, + int whichfork) +{ + extmap_t *extmap; + int nex; + + nex = XFS_DFORK_NEXTENTS(dip, whichfork); + if (!nex) + return; + extmap = extmap_alloc(nex); + switch (XFS_DFORK_FORMAT(dip, whichfork)) { + case XFS_DINODE_FMT_EXTENTS: + process_exinode(dip, &extmap, whichfork); + break; + case XFS_DINODE_FMT_BTREE: + process_btinode(dip, &extmap, whichfork); + break; + } + extcount_actual += extmap->nents; + extcount_ideal += extmap_ideal(extmap); + xfree(extmap); +} + +static void +process_inode( + xfs_agf_t *agf, + xfs_agino_t agino, + xfs_dinode_t *dip) +{ + __uint64_t actual; + xfs_dinode_core_t *dic; + __uint64_t ideal; + xfs_ino_t ino; + int skipa; + int skipd; + + dic = &dip->di_core; + ino = XFS_AGINO_TO_INO(mp, INT_GET(agf->agf_seqno, ARCH_CONVERT), agino); + switch (INT_GET(dic->di_mode, ARCH_CONVERT) & IFMT) { + case IFDIR: + skipd = !dflag; + break; + case IFREG: + if (!rflag && (INT_GET(dic->di_flags, ARCH_CONVERT) & XFS_DIFLAG_REALTIME)) + skipd = 1; + else if (!Rflag && + (ino == mp->m_sb.sb_rbmino || + ino == mp->m_sb.sb_rsumino)) + skipd = 1; + else if (!qflag && + (ino == mp->m_sb.sb_uquotino || + ino == mp->m_sb.sb_gquotino)) + skipd = 1; + else + skipd = !fflag; + break; + case IFLNK: + skipd = !lflag; + break; + default: + skipd = 1; + break; + } + actual = extcount_actual; + ideal = extcount_ideal; + if (!skipd) + process_fork(dip, XFS_DATA_FORK); + skipa = !aflag || !XFS_DFORK_Q(dip); + if (!skipa) + process_fork(dip, XFS_ATTR_FORK); + if (vflag && (!skipd || !skipa)) + dbprintf("inode %lld actual %lld ideal %lld\n", + ino, extcount_actual - actual, extcount_ideal - ideal); +} + +static void +scan_ag( + xfs_agnumber_t agno) +{ + xfs_agf_t *agf; + xfs_agi_t *agi; + + push_cur(); + set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR), 1, + DB_RING_IGN, NULL); + if ((agf = iocur_top->data) == NULL) { + dbprintf("can't read agf block for ag %u\n", agno); + pop_cur(); + return; + } + push_cur(); + set_cur(&typtab[TYP_AGI], XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR), 1, + DB_RING_IGN, NULL); + if ((agi = iocur_top->data) == NULL) { + dbprintf("can't read agi block for ag %u\n", agno); + pop_cur(); + pop_cur(); + return; + } + scan_sbtree(agf, + INT_GET(agi->agi_root, ARCH_CONVERT), + INT_GET(agi->agi_level, ARCH_CONVERT), + scanfunc_ino, TYP_INOBT); + pop_cur(); + pop_cur(); +} + +static void +scan_lbtree( + xfs_fsblock_t root, + int nlevels, + scan_lbtree_f_t func, + extmap_t **extmapp, + typnm_t btype) +{ + push_cur(); + set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, root), blkbb, DB_RING_IGN, + NULL); + if (iocur_top->data == NULL) { + dbprintf("can't read btree block %u/%u\n", + XFS_FSB_TO_AGNO(mp, root), + XFS_FSB_TO_AGBNO(mp, root)); + return; + } + (*func)(iocur_top->data, nlevels - 1, extmapp, btype); + pop_cur(); +} + +static void +scan_sbtree( + xfs_agf_t *agf, + xfs_agblock_t root, + int nlevels, + scan_sbtree_f_t func, + typnm_t btype) +{ + xfs_agnumber_t seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + + push_cur(); + set_cur(&typtab[btype], XFS_AGB_TO_DADDR(mp, seqno, root), + blkbb, DB_RING_IGN, NULL); + if (iocur_top->data == NULL) { + dbprintf("can't read btree block %u/%u\n", seqno, root); + return; + } + (*func)(iocur_top->data, nlevels - 1, agf); + pop_cur(); +} + +static void +scanfunc_bmap( + xfs_btree_lblock_t *ablock, + int level, + extmap_t **extmapp, + typnm_t btype) +{ + xfs_bmbt_block_t *block = (xfs_bmbt_block_t *)ablock; + int i; + xfs_bmbt_ptr_t *pp; + xfs_bmbt_rec_32_t *rp; + + if (level == 0) { + rp = (xfs_bmbt_rec_32_t *) + XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, + block, 1, mp->m_bmap_dmxr[0]); + process_bmbt_reclist(rp, INT_GET(block->bb_numrecs, ARCH_CONVERT), extmapp); + return; + } + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, 1, + mp->m_bmap_dmxr[0]); + for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) + scan_lbtree(INT_GET(pp[i], ARCH_CONVERT), level, scanfunc_bmap, extmapp, btype); +} + +static void +scanfunc_ino( + xfs_btree_sblock_t *ablock, + int level, + xfs_agf_t *agf) +{ + xfs_agino_t agino; + xfs_inobt_block_t *block = (xfs_inobt_block_t *)ablock; + xfs_agnumber_t seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + int i; + int j; + int off; + xfs_inobt_ptr_t *pp; + xfs_inobt_rec_t *rp; + + if (level == 0) { + rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_inobt, block, + 1, mp->m_inobt_mxr[0]); + for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) { + agino = INT_GET(rp[i].ir_startino, ARCH_CONVERT); + off = XFS_INO_TO_OFFSET(mp, agino); + push_cur(); + set_cur(&typtab[TYP_INODE], + XFS_AGB_TO_DADDR(mp, seqno, + XFS_AGINO_TO_AGBNO(mp, agino)), + (int)XFS_FSB_TO_BB(mp, XFS_IALLOC_BLOCKS(mp)), + DB_RING_IGN, NULL); + if (iocur_top->data == NULL) { + dbprintf("can't read inode block %u/%u\n", + seqno, XFS_AGINO_TO_AGBNO(mp, agino)); + continue; + } + for (j = 0; j < XFS_INODES_PER_CHUNK; j++) { + xfs_dinode_t *dip; + xfs_dinode_core_t tdic; + + dip=(xfs_dinode_t *)((char *)iocur_top->data + ((off + j) << mp->m_sb.sb_inodelog)); + + /* convert the core, then copy it back into the inode */ + libxfs_xlate_dinode_core( (xfs_caddr_t) + &dip->di_core, &tdic, 1, ARCH_CONVERT ); + memcpy(&dip->di_core, &tdic, sizeof(xfs_dinode_core_t)); + + if (XFS_INOBT_IS_FREE(&rp[i], j, ARCH_CONVERT)) + continue; + process_inode(agf, agino + j, + (xfs_dinode_t *)((char *)iocur_top->data + ((off + j) << mp->m_sb.sb_inodelog))); + } + pop_cur(); + } + return; + } + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_inobt, block, 1, + mp->m_inobt_mxr[1]); + for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) + scan_sbtree(agf, INT_GET(pp[i], ARCH_CONVERT), level, scanfunc_ino, TYP_INOBT); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/frag.h linux-2.4-xfs/cmd/xfsprogs/db/frag.h --- linux-2.4.7/cmd/xfsprogs/db/frag.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/frag.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern void frag_init(void); diff -rNu linux-2.4.7/cmd/xfsprogs/db/freesp.c linux-2.4-xfs/cmd/xfsprogs/db/freesp.c --- linux-2.4.7/cmd/xfsprogs/db/freesp.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/freesp.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "command.h" +#include "data.h" +#include "freesp.h" +#include "io.h" +#include "type.h" +#include "output.h" +#include "mount.h" +#include "malloc.h" + +typedef struct histent +{ + int low; + int high; + long long count; + long long blocks; +} histent_t; + +static void addhistent(int h); +static void addtohist(xfs_agnumber_t agno, xfs_agblock_t agbno, + xfs_extlen_t len); +static int freesp_f(int argc, char **argv); +static void histinit(int maxlen); +static int init(int argc, char **argv); +static void printhist(void); +static void scan_ag(xfs_agnumber_t agno); +static void scanfunc_bno(xfs_btree_sblock_t *ablock, typnm_t typ, int level, + xfs_agf_t *agf); +static void scanfunc_cnt(xfs_btree_sblock_t *ablock, typnm_t typ, int level, + xfs_agf_t *agf); +static void scan_freelist(xfs_agf_t *agf); +static void scan_sbtree(xfs_agf_t *agf, xfs_agblock_t root, typnm_t typ, + int nlevels, + void (*func)(xfs_btree_sblock_t *block, typnm_t typ, + int level, xfs_agf_t *agf)); +static int usage(void); + +static int agcount; +static xfs_agnumber_t *aglist; +static int countflag; +static int dumpflag; +static int equalsize; +static histent_t *hist; +static int histcount; +static int multsize; +static int seen1; +static int summaryflag; +static long long totblocks; +static long long totexts; + +static const cmdinfo_t freesp_cmd = + { "freesp", NULL, freesp_f, 0, -1, 0, + "[-bcdfs] [-a agno]... [-e binsize] [-h h1]... [-m binmult]", + "summarize free space for filesystem", NULL }; + +static int +inaglist( + xfs_agnumber_t agno) +{ + int i; + + if (agcount == 0) + return 1; + for (i = 0; i < agcount; i++) + if (aglist[i] == agno) + return 1; + return 0; +} + +/* + * Report on freespace usage in xfs filesystem. + */ +static int +freesp_f( + int argc, + char **argv) +{ + xfs_agnumber_t agno; + + if (!init(argc, argv)) + return 0; + for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { + if (inaglist(agno)) + scan_ag(agno); + } + if (histcount) + printhist(); + if (summaryflag) { + dbprintf("total free extents %lld\n", totexts); + dbprintf("total free blocks %lld\n", totblocks); + dbprintf("average free extent size %g\n", + (double)totblocks / (double)totexts); + } + if (aglist) + xfree(aglist); + if (hist) + xfree(hist); + return 0; +} + +void +freesp_init(void) +{ + add_command(&freesp_cmd); +} + +static void +aglistadd( + char *a) +{ + aglist = xrealloc(aglist, (agcount + 1) * sizeof(*aglist)); + aglist[agcount] = (xfs_agnumber_t)atoi(a); + agcount++; +} + +static int +init( + int argc, + char **argv) +{ + int c; + int speced = 0; + + agcount = countflag = dumpflag = equalsize = multsize = optind = 0; + histcount = seen1 = summaryflag = 0; + totblocks = totexts = 0; + aglist = NULL; + hist = NULL; + while ((c = getopt(argc, argv, "a:bcde:h:m:s")) != EOF) { + switch (c) { + case 'a': + aglistadd(optarg); + break; + case 'b': + if (speced) + return usage(); + multsize = 2; + speced = 1; + break; + case 'c': + countflag = 1; + break; + case 'd': + dumpflag = 1; + break; + case 'e': + if (speced) + return usage(); + equalsize = atoi(optarg); + speced = 1; + break; + case 'h': + if (speced && !histcount) + return usage(); + addhistent(atoi(optarg)); + speced = 1; + break; + case 'm': + if (speced) + return usage(); + multsize = atoi(optarg); + speced = 1; + break; + case 's': + summaryflag = 1; + break; + case '?': + return usage(); + } + } + if (optind != argc) + return usage(); + if (!speced) + multsize = 2; + histinit((int)mp->m_sb.sb_agblocks); + return 1; +} + +static int +usage(void) +{ + dbprintf("freesp arguments: [-bcdfs] [-a agno] [-e binsize] [-h h1]... " + "[-m binmult]\n"); + return 0; +} + +static void +scan_ag( + xfs_agnumber_t agno) +{ + xfs_agf_t *agf; + + push_cur(); + set_cur(&typtab[TYP_AGF], XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR), 1, + DB_RING_IGN, NULL); + agf = iocur_top->data; + scan_freelist(agf); + if (countflag) + scan_sbtree(agf, + INT_GET(agf->agf_roots[XFS_BTNUM_CNT], ARCH_CONVERT), + TYP_CNTBT, + INT_GET(agf->agf_levels[XFS_BTNUM_CNT], ARCH_CONVERT), + scanfunc_cnt); + else + scan_sbtree(agf, + INT_GET(agf->agf_roots[XFS_BTNUM_BNO], ARCH_CONVERT), + TYP_BNOBT, + INT_GET(agf->agf_levels[XFS_BTNUM_BNO], ARCH_CONVERT), + scanfunc_bno); + pop_cur(); +} + +static void +scan_freelist( + xfs_agf_t *agf) +{ + xfs_agnumber_t seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + xfs_agfl_t *agfl; + xfs_agblock_t bno; + int i; + + if (INT_GET(agf->agf_flcount, ARCH_CONVERT) == 0) + return; + push_cur(); + set_cur(&typtab[TYP_AGFL], + XFS_AG_DADDR(mp, seqno, XFS_AGFL_DADDR), 1, + DB_RING_IGN, NULL); + agfl = iocur_top->data; + i = INT_GET(agf->agf_flfirst, ARCH_CONVERT); + for (;;) { + bno = INT_GET(agfl->agfl_bno[i], ARCH_CONVERT); + addtohist(seqno, bno, 1); + if (i == INT_GET(agf->agf_fllast, ARCH_CONVERT)) + break; + if (++i == XFS_AGFL_SIZE) + i = 0; + } + pop_cur(); +} + +static void +scan_sbtree( + xfs_agf_t *agf, + xfs_agblock_t root, + typnm_t typ, + int nlevels, + void (*func)(xfs_btree_sblock_t *block, + typnm_t typ, + int level, + xfs_agf_t *agf)) +{ + push_cur(); + set_cur(&typtab[typ], + XFS_AGB_TO_DADDR(mp, INT_GET(agf->agf_seqno, ARCH_CONVERT), root), + blkbb, DB_RING_IGN, NULL); + (*func)((xfs_btree_sblock_t *)iocur_top->data, typ, nlevels - 1, agf); + pop_cur(); +} + +/*ARGSUSED*/ +static void +scanfunc_bno( + xfs_btree_sblock_t *ablock, + typnm_t typ, + int level, + xfs_agf_t *agf) +{ + xfs_alloc_block_t *block = (xfs_alloc_block_t *)ablock; + int i; + xfs_alloc_ptr_t *pp; + xfs_alloc_rec_t *rp; + + if (level == 0) { + rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, + 1, mp->m_alloc_mxr[0]); + for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) + addtohist(INT_GET(agf->agf_seqno, ARCH_CONVERT), + INT_GET(rp[i].ar_startblock, ARCH_CONVERT), INT_GET(rp[i].ar_blockcount, ARCH_CONVERT)); + return; + } + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, 1, + mp->m_alloc_mxr[1]); + for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) + scan_sbtree(agf, pp[i], typ, level, scanfunc_bno); +} + +static void +scanfunc_cnt( + xfs_btree_sblock_t *ablock, + typnm_t typ, + int level, + xfs_agf_t *agf) +{ + xfs_alloc_block_t *block = (xfs_alloc_block_t *)ablock; + int i; + xfs_alloc_ptr_t *pp; + xfs_alloc_rec_t *rp; + + if (level == 0) { + rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, + 1, mp->m_alloc_mxr[0]); + for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) + addtohist(INT_GET(agf->agf_seqno, ARCH_CONVERT), + INT_GET(rp[i].ar_startblock, ARCH_CONVERT), INT_GET(rp[i].ar_blockcount, ARCH_CONVERT)); + return; + } + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, 1, + mp->m_alloc_mxr[1]); + for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) + scan_sbtree(agf, pp[i], typ, level, scanfunc_cnt); +} + +static void +addhistent( + int h) +{ + hist = xrealloc(hist, (histcount + 1) * sizeof(*hist)); + if (h == 0) + h = 1; + hist[histcount].low = h; + hist[histcount].count = hist[histcount].blocks = 0; + histcount++; + if (h == 1) + seen1 = 1; +} + +static void +addtohist( + xfs_agnumber_t agno, + xfs_agblock_t agbno, + xfs_extlen_t len) +{ + int i; + + if (dumpflag) + dbprintf("%8d %8d %8d\n", agno, agbno, len); + totexts++; + totblocks += len; + for (i = 0; i < histcount; i++) { + if (hist[i].high >= len) { + hist[i].count++; + hist[i].blocks += len; + break; + } + } +} + +static int +hcmp( + const void *a, + const void *b) +{ + return ((histent_t *)a)->low - ((histent_t *)b)->low; +} + +static void +histinit( + int maxlen) +{ + int i; + + if (equalsize) { + for (i = 1; i < maxlen; i += equalsize) + addhistent(i); + } else if (multsize) { + for (i = 1; i < maxlen; i *= multsize) + addhistent(i); + } else { + if (!seen1) + addhistent(1); + qsort(hist, histcount, sizeof(*hist), hcmp); + } + for (i = 0; i < histcount; i++) { + if (i < histcount - 1) + hist[i].high = hist[i + 1].low - 1; + else + hist[i].high = maxlen; + } +} + +static void +printhist(void) +{ + int i; + + dbprintf("%7s %7s %7s %7s %6s\n", + "from", "to", "extents", "blocks", "pct"); + for (i = 0; i < histcount; i++) { + if (hist[i].count) + dbprintf("%7d %7d %7lld %7lld %6.2f\n", hist[i].low, + hist[i].high, hist[i].count, hist[i].blocks, + hist[i].blocks * 100.0 / totblocks); + } +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/freesp.h linux-2.4-xfs/cmd/xfsprogs/db/freesp.h --- linux-2.4.7/cmd/xfsprogs/db/freesp.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/freesp.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern void freesp_init(void); diff -rNu linux-2.4.7/cmd/xfsprogs/db/hash.c linux-2.4-xfs/cmd/xfsprogs/db/hash.c --- linux-2.4.7/cmd/xfsprogs/db/hash.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/hash.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "addr.h" +#include "command.h" +#include "type.h" +#include "io.h" +#include "output.h" + +static int hash_f(int argc, char **argv); +static void hash_help(void); + +static const cmdinfo_t hash_cmd = + { "hash", NULL, hash_f, 1, 1, 0, "string", + "calculate hash value", hash_help }; + +static void +hash_help(void) +{ + dbprintf( +"\n" +" 'hash' prints out the calculated hash value for a string using the\n" +"directory/attribute code hash function.\n" +"\n" +" Usage: \"hash \"\n" +"\n" +); + +} + +/* ARGSUSED */ +static int +hash_f( + int argc, + char **argv) +{ + xfs_dahash_t hashval; + + hashval = libxfs_da_hashname(argv[1], (int)strlen(argv[1])); + dbprintf("0x%x\n", hashval); + return 0; +} + +void +hash_init(void) +{ + add_command(&hash_cmd); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/hash.h linux-2.4-xfs/cmd/xfsprogs/db/hash.h --- linux-2.4.7/cmd/xfsprogs/db/hash.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/hash.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern void hash_init(void); +extern xfs_dahash_t xfs_da_hashname(char *name, int namelen); diff -rNu linux-2.4.7/cmd/xfsprogs/db/help.c linux-2.4-xfs/cmd/xfsprogs/db/help.c --- linux-2.4.7/cmd/xfsprogs/db/help.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/help.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "command.h" +#include "help.h" +#include "output.h" + +static void help_all(void); +static void help_onecmd(const char *cmd, const cmdinfo_t *ct); +static int help_f(int argc, char **argv); +static void help_oneline(const char *cmd, const cmdinfo_t *ct); + +static const cmdinfo_t help_cmd = + { "help", "?", help_f, 0, 1, 0, "[command]", + "help for one or all commands", NULL }; + +static void +help_all(void) +{ + const cmdinfo_t *ct; + + for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) + help_oneline(ct->name, ct); + dbprintf("\nUse 'help commandname' for extended help.\n"); +} + +static int +help_f( + int argc, + char **argv) +{ + const cmdinfo_t *ct; + + if (argc == 1) { + help_all(); + return 0; + } + ct = find_command(argv[1]); + if (ct == NULL) { + dbprintf("command %s not found\n", argv[1]); + return 0; + } + help_onecmd(argv[1], ct); + return 0; +} + +void +help_init(void) +{ + add_command(&help_cmd); +} + +static void +help_onecmd( + const char *cmd, + const cmdinfo_t *ct) +{ + help_oneline(cmd, ct); + if (ct->help) + ct->help(); +} + +static void +help_oneline( + const char *cmd, + const cmdinfo_t *ct) +{ + if (cmd) + dbprintf("%s ", cmd); + else { + dbprintf("%s ", ct->name); + if (ct->altname) + dbprintf("(or %s) ", ct->altname); + } + if (ct->args) + dbprintf("%s ", ct->args); + dbprintf("-- %s\n", ct->oneline); +} + diff -rNu linux-2.4.7/cmd/xfsprogs/db/help.h linux-2.4-xfs/cmd/xfsprogs/db/help.h --- linux-2.4.7/cmd/xfsprogs/db/help.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/help.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern void help_init(void); diff -rNu linux-2.4.7/cmd/xfsprogs/db/init.c linux-2.4-xfs/cmd/xfsprogs/db/init.c --- linux-2.4.7/cmd/xfsprogs/db/init.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/init.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include "command.h" +#include "data.h" +#include "init.h" +#include "input.h" +#include "io.h" +#include "mount.h" +#include "sig.h" +#include "output.h" + +char *fsdevice; + +static void +usage(void) +{ + dbprintf("Usage: %s [-c cmd]... [-p prog] [-l logdev] [-frxV] devname\n", progname); + exit(1); +} + +void +init( + int argc, + char **argv) +{ + int c; + FILE *cfile = NULL; + + progname = basename(argv[0]); + while ((c = getopt(argc, argv, "c:fip:rxVl:")) != EOF) { + switch (c) { + case 'c': + if (!cfile) + cfile = tmpfile(); + if (!cfile) { + perror("tmpfile"); + exit(1); + } + if (fprintf(cfile, "%s\n", optarg) < 0) { + perror("fprintf(tmpfile)"); + dbprintf("%s: error writing temporary file\n", + progname); + exit(1); + } + break; + case 'f': + xfsargs.disfile = 1; + break; + case 'i': + xfsargs.isreadonly = + (LIBXFS_ISREADONLY | LIBXFS_ISINACTIVE); + flag_readonly = 1; + break; + case 'p': + progname = optarg; + break; + case 'r': + xfsargs.isreadonly = LIBXFS_ISREADONLY; + flag_readonly = 1; + break; + case 'l': + xfsargs.logname = optarg; + break; + case 'x': + flag_expert_mode = 1; + break; + case 'V': + printf("%s version %s\n", progname, VERSION); + break; + case '?': + usage(); + /*NOTREACHED*/ + } + } + if (optind + 1 != argc) { + usage(); + /*NOTREACHED*/ + } + fsdevice = argv[optind]; + if (!xfsargs.disfile) + xfsargs.volname = fsdevice; + else + xfsargs.dname = fsdevice; + xfsargs.notvolok = 1; + if (!libxfs_init(&xfsargs)) { + fputs("\nfatal error -- couldn't initialize XFS library\n", + stderr); + exit(1); + } + mp = dbmount(); + if (mp == NULL) { + dbprintf("%s: %s is not a valid filesystem\n", + progname, fsdevice); + exit(1); + /*NOTREACHED*/ + } + blkbb = 1 << mp->m_blkbb_log; + push_cur(); + init_commands(); + init_sig(); + if (cfile) { + if (fprintf(cfile, "q\n")<0) { + perror("fprintf(tmpfile)"); + dbprintf("%s: error writing temporary file\n", progname); + exit(1); + } + if (fflush(cfile)<0) { + perror("fflush(tmpfile)"); + dbprintf("%s: error writing temporary file\n", progname); + exit(1); + } + rewind(cfile); + pushfile(cfile); + } +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/init.h linux-2.4-xfs/cmd/xfsprogs/db/init.h --- linux-2.4.7/cmd/xfsprogs/db/init.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/init.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern char *fsdevice; +extern void init(int argc, char **argv); diff -rNu linux-2.4.7/cmd/xfsprogs/db/inobt.c linux-2.4-xfs/cmd/xfsprogs/db/inobt.c --- linux-2.4.7/cmd/xfsprogs/db/inobt.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/inobt.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "inobt.h" +#include "print.h" +#include "bit.h" +#include "mount.h" + +static int inobt_key_count(void *obj, int startoff); +static int inobt_key_offset(void *obj, int startoff, int idx); +static int inobt_ptr_count(void *obj, int startoff); +static int inobt_ptr_offset(void *obj, int startoff, int idx); +static int inobt_rec_count(void *obj, int startoff); +static int inobt_rec_offset(void *obj, int startoff, int idx); + +const field_t inobt_hfld[] = { + { "", FLDT_INOBT, OI(0), C1, 0, TYP_NONE }, + { NULL } +}; + +#define OFF(f) bitize(offsetof(xfs_inobt_block_t, bb_ ## f)) +const field_t inobt_flds[] = { + { "magic", FLDT_UINT32X, OI(OFF(magic)), C1, 0, TYP_NONE }, + { "level", FLDT_UINT16D, OI(OFF(level)), C1, 0, TYP_NONE }, + { "numrecs", FLDT_UINT16D, OI(OFF(numrecs)), C1, 0, TYP_NONE }, + { "leftsib", FLDT_AGBLOCK, OI(OFF(leftsib)), C1, 0, TYP_INOBT }, + { "rightsib", FLDT_AGBLOCK, OI(OFF(rightsib)), C1, 0, TYP_INOBT }, + { "recs", FLDT_INOBTREC, inobt_rec_offset, inobt_rec_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { "keys", FLDT_INOBTKEY, inobt_key_offset, inobt_key_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { "ptrs", FLDT_INOBTPTR, inobt_ptr_offset, inobt_ptr_count, + FLD_ARRAY|FLD_ABASE1|FLD_COUNT|FLD_OFFSET, TYP_INOBT }, + { NULL } +}; + +#define KOFF(f) bitize(offsetof(xfs_inobt_key_t, ir_ ## f)) +const field_t inobt_key_flds[] = { + { "startino", FLDT_AGINO, OI(KOFF(startino)), C1, 0, TYP_INODE }, + { NULL } +}; + +#define ROFF(f) bitize(offsetof(xfs_inobt_rec_t, ir_ ## f)) +const field_t inobt_rec_flds[] = { + { "startino", FLDT_AGINO, OI(ROFF(startino)), C1, 0, TYP_INODE }, + { "freecount", FLDT_INT32D, OI(ROFF(freecount)), C1, 0, TYP_NONE }, + { "free", FLDT_INOFREE, OI(ROFF(free)), C1, 0, TYP_NONE }, + { NULL } +}; + +/*ARGSUSED*/ +static int +inobt_key_count( + void *obj, + int startoff) +{ + xfs_inobt_block_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->bb_level, ARCH_CONVERT) == 0) + return 0; + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +inobt_key_offset( + void *obj, + int startoff, + int idx) +{ + xfs_inobt_block_t *block; + xfs_inobt_key_t *kp; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + kp = XFS_BTREE_KEY_ADDR(mp->m_sb.sb_blocksize, xfs_inobt, block, idx, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_inobt, 0)); + return bitize((int)((char *)kp - (char *)block)); +} + +/*ARGSUSED*/ +static int +inobt_ptr_count( + void *obj, + int startoff) +{ + xfs_inobt_block_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->bb_level, ARCH_CONVERT) == 0) + return 0; + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +inobt_ptr_offset( + void *obj, + int startoff, + int idx) +{ + xfs_inobt_block_t *block; + xfs_inobt_ptr_t *pp; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_inobt, block, idx, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_inobt, 0)); + return bitize((int)((char *)pp - (char *)block)); +} + +/*ARGSUSED*/ +static int +inobt_rec_count( + void *obj, + int startoff) +{ + xfs_inobt_block_t *block; + + ASSERT(startoff == 0); + block = obj; + if (INT_GET(block->bb_level, ARCH_CONVERT) > 0) + return 0; + return INT_GET(block->bb_numrecs, ARCH_CONVERT); +} + +/*ARGSUSED*/ +static int +inobt_rec_offset( + void *obj, + int startoff, + int idx) +{ + xfs_inobt_block_t *block; + xfs_inobt_rec_t *rp; + + ASSERT(startoff == 0); + block = obj; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) == 0); + rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_inobt, block, idx, + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_inobt, 1)); + return bitize((int)((char *)rp - (char *)block)); +} + +/*ARGSUSED*/ +int +inobt_size( + void *obj, + int startoff, + int idx) +{ + return bitize(mp->m_sb.sb_blocksize); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/inobt.h linux-2.4-xfs/cmd/xfsprogs/db/inobt.h --- linux-2.4.7/cmd/xfsprogs/db/inobt.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/inobt.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct field; + +extern const struct field inobt_flds[]; +extern const struct field inobt_hfld[]; +extern const struct field inobt_key_flds[]; +extern const struct field inobt_rec_flds[]; + +extern int inobt_size(void *obj, int startoff, int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/inode.c linux-2.4-xfs/cmd/xfsprogs/db/inode.c --- linux-2.4.7/cmd/xfsprogs/db/inode.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/inode.c Mon Apr 2 21:52:38 2001 @@ -0,0 +1,594 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "command.h" +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "inode.h" +#include "io.h" +#include "print.h" +#include "block.h" +#include "bit.h" +#include "output.h" +#include "mount.h" + +static int inode_a_bmbt_count(void *obj, int startoff); +static int inode_a_bmx_count(void *obj, int startoff); +static int inode_a_count(void *obj, int startoff); +static int inode_a_offset(void *obj, int startoff, int idx); +static int inode_a_sfattr_count(void *obj, int startoff); +static int inode_core_nlinkv2_count(void *obj, int startoff); +static int inode_core_onlink_count(void *obj, int startoff); +static int inode_core_projid_count(void *obj, int startoff); +static int inode_core_nlinkv1_count(void *obj, int startoff); +static int inode_f(int argc, char **argv); +static int inode_u_bmbt_count(void *obj, int startoff); +static int inode_u_bmx_count(void *obj, int startoff); +static int inode_u_c_count(void *obj, int startoff); +static int inode_u_dev_count(void *obj, int startoff); +static int inode_u_muuid_count(void *obj, int startoff); +static int inode_u_sfdir_count(void *obj, int startoff); +static int inode_u_sfdir2_count(void *obj, int startoff); +static int inode_u_symlink_count(void *obj, int startoff); + +static const cmdinfo_t inode_cmd = + { "inode", NULL, inode_f, 0, 1, 1, "[inode#]", + "set current inode", NULL }; + +const field_t inode_hfld[] = { + { "", FLDT_INODE, OI(0), C1, 0, TYP_NONE }, + { NULL } +}; + +#define OFF(f) bitize(offsetof(xfs_dinode_t, di_ ## f)) +const field_t inode_flds[] = { + { "core", FLDT_DINODE_CORE, OI(OFF(core)), C1, 0, TYP_NONE }, + { "next_unlinked", FLDT_AGINO, OI(OFF(next_unlinked)), C1, 0, + TYP_INODE }, + { "u", FLDT_DINODE_U, OI(OFF(u)), C1, 0, TYP_NONE }, + { "a", FLDT_DINODE_A, inode_a_offset, inode_a_count, + FLD_COUNT|FLD_OFFSET, TYP_NONE }, + { NULL } +}; + +#define COFF(f) bitize(offsetof(xfs_dinode_core_t, di_ ## f)) +const field_t inode_core_flds[] = { + { "magic", FLDT_UINT16X, OI(COFF(magic)), C1, 0, TYP_NONE }, + { "mode", FLDT_UINT16O, OI(COFF(mode)), C1, 0, TYP_NONE }, + { "version", FLDT_INT8D, OI(COFF(version)), C1, 0, TYP_NONE }, + { "format", FLDT_DINODE_FMT, OI(COFF(format)), C1, 0, TYP_NONE }, + { "nlinkv1", FLDT_UINT16D, OI(COFF(onlink)), inode_core_nlinkv1_count, + FLD_COUNT, TYP_NONE }, + { "nlinkv2", FLDT_UINT32D, OI(COFF(nlink)), inode_core_nlinkv2_count, + FLD_COUNT, TYP_NONE }, + { "onlink", FLDT_UINT16D, OI(COFF(onlink)), inode_core_onlink_count, + FLD_COUNT, TYP_NONE }, + { "projid", FLDT_UINT16D, OI(COFF(projid)), inode_core_projid_count, + FLD_COUNT, TYP_NONE }, + { "uid", FLDT_UINT32D, OI(COFF(uid)), C1, 0, TYP_NONE }, + { "gid", FLDT_UINT32D, OI(COFF(gid)), C1, 0, TYP_NONE }, + { "atime", FLDT_TIMESTAMP, OI(COFF(atime)), C1, 0, TYP_NONE }, + { "mtime", FLDT_TIMESTAMP, OI(COFF(mtime)), C1, 0, TYP_NONE }, + { "ctime", FLDT_TIMESTAMP, OI(COFF(ctime)), C1, 0, TYP_NONE }, + { "size", FLDT_FSIZE, OI(COFF(size)), C1, 0, TYP_NONE }, + { "nblocks", FLDT_DRFSBNO, OI(COFF(nblocks)), C1, 0, TYP_NONE }, + { "extsize", FLDT_EXTLEN, OI(COFF(extsize)), C1, 0, TYP_NONE }, + { "nextents", FLDT_EXTNUM, OI(COFF(nextents)), C1, 0, TYP_NONE }, + { "naextents", FLDT_AEXTNUM, OI(COFF(anextents)), C1, 0, TYP_NONE }, + { "forkoff", FLDT_UINT8D, OI(COFF(forkoff)), C1, 0, TYP_NONE }, + { "aformat", FLDT_DINODE_FMT, OI(COFF(aformat)), C1, 0, TYP_NONE }, + { "dmevmask", FLDT_UINT32X, OI(COFF(dmevmask)), C1, 0, TYP_NONE }, + { "dmstate", FLDT_UINT16D, OI(COFF(dmstate)), C1, 0, TYP_NONE }, + { "flags", FLDT_UINT16X, OI(COFF(flags)), C1, FLD_SKIPALL, TYP_NONE }, + { "newrtbm", FLDT_UINT1, + OI(COFF(flags) + bitsz(__uint16_t) - XFS_DIFLAG_NEWRTBM_BIT - 1), C1, + 0, TYP_NONE }, + { "prealloc", FLDT_UINT1, + OI(COFF(flags) + bitsz(__uint16_t) - XFS_DIFLAG_PREALLOC_BIT - 1), C1, + 0, TYP_NONE }, + { "realtime", FLDT_UINT1, + OI(COFF(flags) + bitsz(__uint16_t) - XFS_DIFLAG_REALTIME_BIT - 1), C1, + 0, TYP_NONE }, + { "gen", FLDT_UINT32D, OI(COFF(gen)), C1, 0, TYP_NONE }, + { NULL } +}; + +#define TOFF(f) bitize(offsetof(xfs_timestamp_t, t_ ## f)) +const field_t timestamp_flds[] = { + { "sec", FLDT_TIME, OI(TOFF(sec)), C1, 0, TYP_NONE }, + { "nsec", FLDT_NSEC, OI(TOFF(nsec)), C1, 0, TYP_NONE }, + { NULL } +}; + +const field_t inode_u_flds[] = { + { "bmbt", FLDT_BMROOTD, 0, inode_u_bmbt_count, FLD_COUNT, TYP_NONE }, + { "bmx", FLDT_BMAPBTDREC, 0, inode_u_bmx_count, FLD_ARRAY|FLD_COUNT, + TYP_NONE }, + { "c", FLDT_CHARNS, 0, inode_u_c_count, FLD_COUNT, TYP_NONE }, + { "dev", FLDT_DEV, 0, inode_u_dev_count, FLD_COUNT, TYP_NONE }, + { "muuid", FLDT_UUID, 0, inode_u_muuid_count, FLD_COUNT, TYP_NONE }, + { "sfdir", FLDT_DIRSHORT, 0, inode_u_sfdir_count, FLD_COUNT, TYP_NONE }, + { "sfdir2", FLDT_DIR2SF, 0, inode_u_sfdir2_count, FLD_COUNT, TYP_NONE }, + { "symlink", FLDT_CHARNS, 0, inode_u_symlink_count, FLD_COUNT, + TYP_NONE }, + { NULL } +}; + +const field_t inode_a_flds[] = { + { "bmbt", FLDT_BMROOTA, 0, inode_a_bmbt_count, FLD_COUNT, TYP_NONE }, + { "bmx", FLDT_BMAPBTAREC, 0, inode_a_bmx_count, FLD_ARRAY|FLD_COUNT, + TYP_NONE }, + { "sfattr", FLDT_ATTRSHORT, 0, inode_a_sfattr_count, FLD_COUNT, + TYP_NONE }, + { NULL } +}; + +static const char *dinode_fmt_name[] = + { "dev", "local", "extents", "btree", "uuid" }; +static const int dinode_fmt_name_size = + sizeof(dinode_fmt_name) / sizeof(dinode_fmt_name[0]); + +/*ARGSUSED*/ +int +fp_dinode_fmt( + void *obj, + int bit, + int count, + char *fmtstr, + int size, + int arg, + int base, + int array) +{ + int bitpos; + xfs_dinode_fmt_t f; + int i; + + for (i = 0, bitpos = bit; i < count; i++, bitpos += size) { + f = (xfs_dinode_fmt_t)getbitval(obj, bitpos, size, BVSIGNED); + if (array) + dbprintf("%d:", i + base); + if (f < 0 || f >= dinode_fmt_name_size) + dbprintf("%d", (int)f); + else + dbprintf("%d (%s)", (int)f, dinode_fmt_name[(int)f]); + if (i < count - 1) + dbprintf(" "); + } + return 1; +} + +static int +inode_a_bmbt_count( + void *obj, + int startoff) +{ + xfs_dinode_t *dip; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + dip = obj; + if (!XFS_DFORK_Q_ARCH(dip, ARCH_CONVERT)) + return 0; + ASSERT((char *)XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT) - (char *)dip == byteize(startoff)); + return INT_GET(dip->di_core.di_aformat, ARCH_CONVERT) == XFS_DINODE_FMT_BTREE; +} + +static int +inode_a_bmx_count( + void *obj, + int startoff) +{ + xfs_dinode_t *dip; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + dip = obj; + if (!XFS_DFORK_Q_ARCH(dip, ARCH_CONVERT)) + return 0; + ASSERT((char *)XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT) - (char *)dip == byteize(startoff)); + return INT_GET(dip->di_core.di_aformat, ARCH_CONVERT) == XFS_DINODE_FMT_EXTENTS ? + INT_GET(dip->di_core.di_anextents, ARCH_CONVERT) : 0; +} + +static int +inode_a_count( + void *obj, + int startoff) +{ + xfs_dinode_t *dip; + + ASSERT(startoff == 0); + dip = obj; + return XFS_DFORK_Q_ARCH(dip, ARCH_CONVERT); +} + +static int +inode_a_offset( + void *obj, + int startoff, + int idx) +{ + xfs_dinode_t *dip; + + ASSERT(startoff == 0); + ASSERT(idx == 0); + dip = obj; + ASSERT(XFS_DFORK_Q_ARCH(dip, ARCH_CONVERT)); + return bitize((int)((char *)XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT) - (char *)dip)); +} + +static int +inode_a_sfattr_count( + void *obj, + int startoff) +{ + xfs_dinode_t *dip; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + dip = obj; + if (!XFS_DFORK_Q_ARCH(dip, ARCH_CONVERT)) + return 0; + ASSERT((char *)XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT) - (char *)dip == byteize(startoff)); + return INT_GET(dip->di_core.di_aformat, ARCH_CONVERT) == XFS_DINODE_FMT_LOCAL; +} + +int +inode_a_size( + void *obj, + int startoff, + int idx) +{ + xfs_attr_shortform_t *asf; + xfs_dinode_t *dip; + + ASSERT(startoff == 0); + ASSERT(idx == 0); + dip = obj; + switch (INT_GET(dip->di_core.di_aformat, ARCH_CONVERT)) { + case XFS_DINODE_FMT_LOCAL: + asf = (xfs_attr_shortform_t *)XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT); + return bitize((int)asf->hdr.totsize); + case XFS_DINODE_FMT_EXTENTS: + return (int)(INT_GET(dip->di_core.di_anextents, ARCH_CONVERT) * bitsz(xfs_bmbt_rec_t)); + case XFS_DINODE_FMT_BTREE: + return bitize((int)XFS_DFORK_ASIZE_ARCH(dip, mp, ARCH_CONVERT)); + default: + return 0; + } +} + +static int +inode_core_nlinkv1_count( + void *obj, + int startoff) +{ + xfs_dinode_core_t *dic; + + ASSERT(startoff == 0); + ASSERT(obj == iocur_top->data); + dic = obj; + return dic->di_version == XFS_DINODE_VERSION_1; +} + +static int +inode_core_nlinkv2_count( + void *obj, + int startoff) +{ + xfs_dinode_core_t *dic; + + ASSERT(startoff == 0); + ASSERT(obj == iocur_top->data); + dic = obj; + return dic->di_version == XFS_DINODE_VERSION_2; +} + +static int +inode_core_onlink_count( + void *obj, + int startoff) +{ + xfs_dinode_core_t *dic; + + ASSERT(startoff == 0); + ASSERT(obj == iocur_top->data); + dic = obj; + return dic->di_version == XFS_DINODE_VERSION_2; +} + +static int +inode_core_projid_count( + void *obj, + int startoff) +{ + xfs_dinode_core_t *dic; + + ASSERT(startoff == 0); + ASSERT(obj == iocur_top->data); + dic = obj; + return dic->di_version == XFS_DINODE_VERSION_2; +} + +static int +inode_f( + int argc, + char **argv) +{ + xfs_ino_t ino; + char *p; + + if (argc > 1) { + ino = strtoull(argv[1], &p, 0); + if (*p != '\0') { + dbprintf("bad value for inode number %s\n", argv[1]); + return 0; + } + set_cur_inode(ino); + } else if (iocur_top->ino == NULLFSINO) + dbprintf("no current inode\n"); + else + dbprintf("current inode number is %lld\n", iocur_top->ino); + return 0; +} + +void +inode_init(void) +{ + add_command(&inode_cmd); +} + +typnm_t +inode_next_type(void) +{ + switch (iocur_top->mode & IFMT) { + case IFDIR: + return XFS_DIR_IS_V2(mp) ? TYP_DIR2 : TYP_DIR; + case IFLNK: + return TYP_SYMLINK; + case IFREG: + if (iocur_top->ino == mp->m_sb.sb_rbmino) + return TYP_RTBITMAP; + else if (iocur_top->ino == mp->m_sb.sb_rsumino) + return TYP_RTSUMMARY; + else if (iocur_top->ino == mp->m_sb.sb_uquotino || + iocur_top->ino == mp->m_sb.sb_gquotino) + return TYP_DQBLK; + else + return TYP_DATA; + default: + return TYP_NONE; + } +} + +int +inode_size( + void *obj, + int startoff, + int idx) +{ + return bitize(mp->m_sb.sb_inodesize); +} + +static int +inode_u_bmbt_count( + void *obj, + int startoff) +{ + xfs_dinode_t *dip; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + dip = obj; + ASSERT((char *)&dip->di_u - (char *)dip == byteize(startoff)); + return INT_GET(dip->di_core.di_format, ARCH_CONVERT) == XFS_DINODE_FMT_BTREE; +} + +static int +inode_u_bmx_count( + void *obj, + int startoff) +{ + xfs_dinode_t *dip; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + dip = obj; + ASSERT((char *)&dip->di_u - (char *)dip == byteize(startoff)); + return INT_GET(dip->di_core.di_format, ARCH_CONVERT) == XFS_DINODE_FMT_EXTENTS ? + INT_GET(dip->di_core.di_nextents, ARCH_CONVERT) : 0; +} + +static int +inode_u_c_count( + void *obj, + int startoff) +{ + xfs_dinode_t *dip; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + dip = obj; + ASSERT((char *)&dip->di_u - (char *)dip == byteize(startoff)); + return INT_GET(dip->di_core.di_format, ARCH_CONVERT) == XFS_DINODE_FMT_LOCAL && + (INT_GET(dip->di_core.di_mode, ARCH_CONVERT) & IFMT) == IFREG ? + (int)INT_GET(dip->di_core.di_size, ARCH_CONVERT) : 0; +} + +static int +inode_u_dev_count( + void *obj, + int startoff) +{ + xfs_dinode_t *dip; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + dip = obj; + ASSERT((char *)&dip->di_u - (char *)dip == byteize(startoff)); + return INT_GET(dip->di_core.di_format, ARCH_CONVERT) == XFS_DINODE_FMT_DEV; +} + +static int +inode_u_muuid_count( + void *obj, + int startoff) +{ + xfs_dinode_t *dip; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + dip = obj; + ASSERT((char *)&dip->di_u - (char *)dip == byteize(startoff)); + return INT_GET(dip->di_core.di_format, ARCH_CONVERT) == XFS_DINODE_FMT_UUID; +} + +static int +inode_u_sfdir_count( + void *obj, + int startoff) +{ + xfs_dinode_t *dip; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + dip = obj; + ASSERT((char *)&dip->di_u - (char *)dip == byteize(startoff)); + return INT_GET(dip->di_core.di_format, ARCH_CONVERT) == XFS_DINODE_FMT_LOCAL && + (INT_GET(dip->di_core.di_mode, ARCH_CONVERT) & IFMT) == IFDIR + && XFS_DIR_IS_V1(mp); +} + +static int +inode_u_sfdir2_count( + void *obj, + int startoff) +{ + xfs_dinode_t *dip; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + dip = obj; + ASSERT((char *)&dip->di_u - (char *)dip == byteize(startoff)); + return INT_GET(dip->di_core.di_format, ARCH_CONVERT) == XFS_DINODE_FMT_LOCAL && + (INT_GET(dip->di_core.di_mode, ARCH_CONVERT) & IFMT) == IFDIR && + XFS_DIR_IS_V2(mp); +} + +int +inode_u_size( + void *obj, + int startoff, + int idx) +{ + xfs_dinode_t *dip; + + ASSERT(startoff == 0); + ASSERT(idx == 0); + dip = obj; + switch (INT_GET(dip->di_core.di_format, ARCH_CONVERT)) { + case XFS_DINODE_FMT_DEV: + return bitsz(xfs_dev_t); + case XFS_DINODE_FMT_LOCAL: + return bitize((int)INT_GET(dip->di_core.di_size, ARCH_CONVERT)); + case XFS_DINODE_FMT_EXTENTS: + return (int)(INT_GET(dip->di_core.di_nextents, ARCH_CONVERT) * bitsz(xfs_bmbt_rec_t)); + case XFS_DINODE_FMT_BTREE: + return bitize((int)XFS_DFORK_DSIZE_ARCH(dip, mp, ARCH_CONVERT)); + case XFS_DINODE_FMT_UUID: + return bitsz(uuid_t); + default: + return 0; + } +} + +static int +inode_u_symlink_count( + void *obj, + int startoff) +{ + xfs_dinode_t *dip; + + ASSERT(bitoffs(startoff) == 0); + ASSERT(obj == iocur_top->data); + dip = obj; + ASSERT((char *)&dip->di_u - (char *)dip == byteize(startoff)); + return INT_GET(dip->di_core.di_format, ARCH_CONVERT) == XFS_DINODE_FMT_LOCAL && + (INT_GET(dip->di_core.di_mode, ARCH_CONVERT) & IFMT) == IFLNK ? + (int)INT_GET(dip->di_core.di_size, ARCH_CONVERT) : 0; +} + +void +set_cur_inode( + xfs_ino_t ino) +{ + xfs_agblock_t agbno; + xfs_agino_t agino; + xfs_agnumber_t agno; + xfs_dinode_t *dip; + int offset; + + agno = XFS_INO_TO_AGNO(mp, ino); + agino = XFS_INO_TO_AGINO(mp, ino); + agbno = XFS_AGINO_TO_AGBNO(mp, agino); + offset = XFS_AGINO_TO_OFFSET(mp, agino); + if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || + offset >= mp->m_sb.sb_inopblock || + XFS_AGINO_TO_INO(mp, agno, agino) != ino) { + dbprintf("bad inode number %lld\n", ino); + return; + } + cur_agno = agno; + /* + * First set_cur to the block with the inode + * then use off_cur to get the right part of the buffer. + */ + ASSERT(typtab[TYP_INODE].typnm == TYP_INODE); + + /* ingore ring update here, do it explicitly below */ + set_cur(&typtab[TYP_INODE], XFS_AGB_TO_DADDR(mp, agno, agbno), + blkbb, DB_RING_IGN, NULL); + off_cur(offset << mp->m_sb.sb_inodelog, mp->m_sb.sb_inodesize); + dip = iocur_top->data; + iocur_top->ino = ino; + iocur_top->mode = INT_GET(dip->di_core.di_mode, ARCH_CONVERT); + if ((iocur_top->mode & IFMT) == IFDIR) + iocur_top->dirino = ino; + + /* track updated info in ring */ + ring_add(); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/inode.h linux-2.4-xfs/cmd/xfsprogs/db/inode.h --- linux-2.4.7/cmd/xfsprogs/db/inode.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/inode.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern const struct field inode_a_flds[]; +extern const struct field inode_core_flds[]; +extern const struct field inode_flds[]; +extern const struct field inode_hfld[]; +extern const struct field inode_u_flds[]; +extern const struct field timestamp_flds[]; + +extern int fp_dinode_fmt(void *obj, int bit, int count, char *fmtstr, + int size, int arg, int base, int array); +extern int inode_a_size(void *obj, int startoff, int idx); +extern void inode_init(void); +extern typnm_t inode_next_type(void); +extern int inode_size(void *obj, int startoff, int idx); +extern int inode_u_size(void *obj, int startoff, int idx); +extern void set_cur_inode(xfs_ino_t ino); diff -rNu linux-2.4.7/cmd/xfsprogs/db/input.c linux-2.4-xfs/cmd/xfsprogs/db/input.c --- linux-2.4.7/cmd/xfsprogs/db/input.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/input.c Mon Jan 15 00:52:52 2001 @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "command.h" +#include "data.h" +#include "input.h" +#include "output.h" +#include "sig.h" +#include "malloc.h" +#include "init.h" + +int inputstacksize; +FILE **inputstack; +FILE *curinput; + +static void popfile(void); +static int source_f(int argc, char **argv); + +static const cmdinfo_t source_cmd = + { "source", NULL, source_f, 1, 1, 0, "source-file", + "get commands from source-file", NULL }; + +/* our homegrown strtok that understands strings */ + +static char * +tokenize( + char *inp) +{ + static char *last_place = NULL; + char *start; + char *walk; + int in_string = 0; + int in_escape = 0; + + if (inp) { + start = inp; + } else { + if (last_place == NULL) + return NULL; + + /* we're done */ + if (*last_place != '\0') + return NULL; + + start = last_place + 1; + } + last_place = NULL; + + /* eat whitespace */ + while (*start == ' ' || *start == '\t') + start++; + + walk = start; + for (;*walk != '\0'; walk++) { + if (in_escape) { + in_escape = 0; + continue; + } + if (*walk == '\\') + in_escape = 1; + else if (*walk == '\"') + in_string ^= 1; + + if (!in_string && !in_escape && + (*walk == ' ' || *walk == '\t')) { + last_place = walk; + *last_place = '\0'; + break; + } + } + if (walk == start) + return NULL; + + return start; +} + +char ** +breakline( + char *input, + int *count) +{ + int c; + char *inp; + char *p; + char **rval; + + c = 0; + inp = input; + rval = xcalloc(sizeof(char *), 1); + for (;;) { + + p = tokenize(inp); + + if (p == NULL) + break; + inp = NULL; + c++; + rval = xrealloc(rval, sizeof(*rval) * (c + 1)); + rval[c - 1] = p; + rval[c] = NULL; + } + *count = c; + return rval; +} + +void +doneline( + char *input, + char **vec) +{ + xfree(input); + xfree(vec); +} + +char * +fetchline(void) +{ + char buf[1024]; + int iscont; + size_t len; + size_t rlen; + char *rval; + + rval = NULL; + for (rlen = iscont = 0; ; ) { + if (inputstacksize == 1) { + if (iscont) + dbprintf("... "); + else + dbprintf("%s: ", progname); + fflush(stdin); + } + if (seenint() || + (!fgets(buf, sizeof(buf), curinput) && + ferror(curinput) && seenint())) { + clearint(); + dbprintf("^C\n"); + clearerr(curinput); + if (iscont) { + iscont = 0; + rlen = 0; + if (rval) { + xfree(rval); + rval = NULL; + } + } + continue; + } + if (ferror(curinput) || feof(curinput) || + (len = strlen(buf)) == 0) { + popfile(); + if (curinput == NULL) { + dbprintf("\n"); + return NULL; + } + iscont = 0; + rlen = 0; + if (rval) { + xfree(rval); + rval = NULL; + } + continue; + } + if (inputstacksize == 1) + logprintf("%s", buf); + rval = xrealloc(rval, rlen + len + 1); + if (rlen == 0) + rval[0] = '\0'; + rlen += len; + strcat(rval, buf); + if (buf[len - 1] == '\n') { + if (len > 1 && buf[len - 2] == '\\') { + rval[rlen - 2] = ' '; + rval[rlen - 1] = '\0'; + rlen--; + iscont = 1; + } else { + rval[rlen - 1] = '\0'; + rlen--; + break; + } + } + } + return rval; +} + +void +input_init(void) +{ + add_command(&source_cmd); +} + +static void +popfile(void) +{ + if (inputstacksize == 0) { + curinput = NULL; + return; + } + if (curinput != stdin) + fclose(curinput); + + inputstacksize--; + if (inputstacksize) { + inputstack = + xrealloc(inputstack, inputstacksize * sizeof(*inputstack)); + curinput = inputstack[inputstacksize - 1]; + } else { + free(inputstack); + curinput = NULL; + inputstack = NULL; + } +} + +void +pushfile( + FILE *file) +{ + inputstack = + xrealloc(inputstack, + (inputstacksize + 1) * sizeof(*inputstack)); + inputstacksize++; + curinput = inputstack[inputstacksize - 1] = file; +} + +/* ARGSUSED */ +static int +source_f( + int argc, + char **argv) +{ + FILE *f; + + f = fopen(argv[1], "r"); + if (f == NULL) + dbprintf("can't open %s\n", argv[0]); + else + pushfile(f); + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/input.h linux-2.4-xfs/cmd/xfsprogs/db/input.h --- linux-2.4.7/cmd/xfsprogs/db/input.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/input.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern char **breakline(char *input, int *count); +extern void doneline(char *input, char **vec); +extern char *fetchline(void); +extern void input_init(void); +extern void pushfile(FILE *file); diff -rNu linux-2.4.7/cmd/xfsprogs/db/io.c linux-2.4-xfs/cmd/xfsprogs/db/io.c --- linux-2.4.7/cmd/xfsprogs/db/io.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/io.c Wed May 9 01:56:06 2001 @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "command.h" +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "inode.h" +#include "io.h" +#include "output.h" +#include "mount.h" +#include "malloc.h" + +static int pop_f(int argc, char **argv); +static void pop_help(void); +static int push_f(int argc, char **argv); +static void push_help(void); +static int stack_f(int argc, char **argv); +static void stack_help(void); +static int forward_f(int argc, char **argv); +static void forward_help(void); +static int back_f(int argc, char **argv); +static void back_help(void); +static int ring_f(int argc, char **argv); +static void ring_help(void); + +static const cmdinfo_t pop_cmd = + { "pop", NULL, pop_f, 0, 0, 0, NULL, + "pop location from the stack", pop_help }; +static const cmdinfo_t push_cmd = + { "push", NULL, push_f, 0, 2, 0, "[command]", + "push location to the stack", push_help }; +static const cmdinfo_t stack_cmd = + { "stack", NULL, stack_f, 0, 0, 0, NULL, + "view the location stack", stack_help }; +static const cmdinfo_t forward_cmd = + { "forward", "f", forward_f, 0, 0, 0, NULL, + "move forward to next entry in the position ring", forward_help }; +static const cmdinfo_t back_cmd = + { "back", "b", back_f, 0, 0, 0, NULL, + "move to the previous location in the position ring", back_help }; +static const cmdinfo_t ring_cmd = + { "ring", NULL, ring_f, 0, 1, 0, NULL, + "show position ring or move to a specific entry", ring_help }; + +iocur_t *iocur_base; +iocur_t *iocur_top; +int iocur_sp = -1; +int iocur_len; + +#define RING_ENTRIES 20 +static iocur_t iocur_ring[RING_ENTRIES]; +static int ring_head = -1; +static int ring_tail = -1; +static int ring_current = -1; + +void +io_init(void) +{ + add_command(&pop_cmd); + add_command(&push_cmd); + add_command(&stack_cmd); + add_command(&forward_cmd); + add_command(&back_cmd); + add_command(&ring_cmd); +} + +void +off_cur( + int off, + int len) +{ + if (iocur_top == NULL || off + len > BBTOB(iocur_top->blen)) + dbprintf("can't set block offset to %d\n", off); + else { + iocur_top->boff = off; + iocur_top->off = ((xfs_off_t)iocur_top->bb << BBSHIFT) + off; + iocur_top->len = len; + iocur_top->data = (void *)((char *)iocur_top->buf + off); + } +} + +void +pop_cur(void) +{ + if (iocur_sp < 0) { + dbprintf("can't pop anything from I/O stack\n"); + return; + } + if (iocur_top->buf) + xfree(iocur_top->buf); + if (--iocur_sp >= 0) { + iocur_top = iocur_base + iocur_sp; + cur_typ = iocur_top->typ; + } else { + iocur_top = iocur_base; + iocur_sp = 0; + } +} + +/*ARGSUSED*/ +static int +pop_f( + int argc, + char **argv) +{ + pop_cur(); + return 0; +} + +static void +pop_help(void) +{ + dbprintf( +"\n" +" Changes the address and data type to the first entry on the stack.\n" +"\n" + ); +} + +void +print_iocur( + char *tag, + iocur_t *ioc) +{ + int i; + + dbprintf("%s\n", tag); + dbprintf("\tbyte offset %lld, length %d\n", ioc->off, ioc->len); + dbprintf("\tbuffer block %lld (fsbno %lld), %d bb%s\n", ioc->bb, + (xfs_dfsbno_t)XFS_DADDR_TO_FSB(mp, ioc->bb), ioc->blen, + ioc->blen == 1 ? "" : "s"); + if (ioc->use_bbmap) { + dbprintf("\tblock map"); + for (i = 0; i < ioc->blen; i++) + dbprintf(" %d:%lld", i, ioc->bbmap.b[i]); + dbprintf("\n"); + } + dbprintf("\tinode %lld, dir inode %lld, type %s\n", ioc->ino, + ioc->dirino, ioc->typ == NULL ? "none" : ioc->typ->name); +} + +void +print_ring(void) +{ + int i; + iocur_t *ioc; + + if (ring_current == -1) { + dbprintf("no entries in location ring.\n"); + return; + } + + dbprintf(" type bblock bblen fsbno inode\n"); + + i = ring_head; + for (;;) { + ioc = &iocur_ring[i]; + if (i == ring_current) + printf("*%2d: ", i); + else + printf(" %2d: ", i); + + dbprintf("%-7.7s %8lld %5d %8lld %9lld\n", + ioc->typ == NULL ? "none" : ioc->typ->name, + ioc->bb, + ioc->blen, + (xfs_dfsbno_t)XFS_DADDR_TO_FSB(mp, ioc->bb), + ioc->ino + ); + + if (i == ring_tail) + break; + + i = (i+(RING_ENTRIES-1))%RING_ENTRIES; + } +} + + +void +push_cur(void) +{ + if (iocur_sp + 1 >= iocur_len) { + iocur_base = xrealloc(iocur_base, + sizeof(*iocur_base) * (iocur_len + 1)); + iocur_len++; + } + iocur_sp++; + iocur_top = iocur_base + iocur_sp; + memset(iocur_top, 0, sizeof(*iocur_base)); + iocur_top->ino = iocur_sp > 0 ? iocur_top[-1].ino : NULLFSINO; + iocur_top->dirino = iocur_sp > 0 ? iocur_top[-1].dirino : NULLFSINO; + iocur_top->mode = iocur_sp > 0 ? iocur_top[-1].mode : 0; + cur_typ = NULL; +} + +static int +push_f( + int argc, + char **argv) +{ + const cmdinfo_t *ct; + + if (argc > 1) { + /* check we can execute command */ + ct = find_command(argv[1]); + if (ct == NULL) { + dbprintf("no such command %s\n", argv[1]); + return 0; + } + if (!ct->canpush) { + dbprintf("no push form allowed for %s\n", argv[1]); + return 0; + } + } + + /* save current state */ + push_cur(); + if (iocur_top[-1].typ && iocur_top[-1].typ->typnm == TYP_INODE) + set_cur_inode(iocur_top[-1].ino); + else + set_cur(iocur_top[-1].typ, iocur_top[-1].bb, + iocur_top[-1].blen, DB_RING_IGN, + iocur_top[-1].use_bbmap ? &iocur_top[-1].bbmap : NULL); + + /* run requested command */ + if (argc>1) + (void)command(argc-1, argv+1); + return 0; +} + +static void +push_help(void) +{ + dbprintf( +"\n" +" Allows you to push the current address and data type on the stack for\n" +" later return. 'push' also accepts an additional command to execute after\n" +" storing the current address (ex: 'push a rootino' from the superblock).\n" +"\n" + ); +} + +/* move forward through the ring */ +/* ARGSUSED */ +static int +forward_f( + int argc, + char **argv) +{ + if (ring_current == -1) { + dbprintf("ring is empty\n"); + return 0; + } + if (ring_current == ring_head) { + dbprintf("no further entries\n"); + return 0; + } + + ring_current = (ring_current+1)%RING_ENTRIES; + + set_cur(iocur_ring[ring_current].typ, + iocur_ring[ring_current].bb, + iocur_ring[ring_current].blen, + DB_RING_IGN, + iocur_ring[ring_current].use_bbmap ? + &iocur_ring[ring_current].bbmap : NULL); + + return 0; +} + +static void +forward_help(void) +{ + dbprintf( +"\n" +" The 'forward' ('f') command moves to the next location in the position\n" +" ring, updating the current position and data type. If the current location\n" +" is the top entry in the ring, then the 'forward' command will have\n" +" no effect.\n" +"\n" + ); +} + +/* move backwards through the ring */ +/* ARGSUSED */ +static int +back_f( + int argc, + char **argv) +{ + if (ring_current == -1) { + dbprintf("ring is empty\n"); + return 0; + } + if (ring_current == ring_tail) { + dbprintf("no previous entries\n"); + return 0; + } + + ring_current = (ring_current+(RING_ENTRIES-1))%RING_ENTRIES; + + set_cur(iocur_ring[ring_current].typ, + iocur_ring[ring_current].bb, + iocur_ring[ring_current].blen, + DB_RING_IGN, + iocur_ring[ring_current].use_bbmap ? + &iocur_ring[ring_current].bbmap : NULL); + + return 0; +} + +static void +back_help(void) +{ + dbprintf( +"\n" +" The 'back' ('b') command moves to the previous location in the position\n" +" ring, updating the current position and data type. If the current location\n" +" is the last entry in the ring, then the 'back' command will have no effect.\n" +"\n" + ); +} + +/* show or go to specific point in ring */ +static int +ring_f( + int argc, + char **argv) +{ + int index; + + if (argc == 1) { + print_ring(); + return 0; + } + + index = (int)strtoul(argv[0], NULL, 0); + if (index < 0 || index >= RING_ENTRIES) + dbprintf("invalid entry: %d\n", index); + + ring_current = index; + + set_cur(iocur_ring[index].typ, + iocur_ring[index].bb, + iocur_ring[index].blen, + DB_RING_IGN, + iocur_ring[index].use_bbmap ? &iocur_ring[index].bbmap : NULL); + + return 0; +} + +static void +ring_help(void) +{ + dbprintf( +"\n" +" The position ring automatically keeps track of each disk location and\n" +" structure type for each change of position you make during your xfs_db\n" +" session. The last %d most recent entries are kept in the ring.\n" +"\n" +" To display the current list of ring entries type 'ring' by itself on\n" +" the command line. The entry highlighted by an asterisk ('*') is the\n" +" current entry.\n" +"\n" +" To move to another entry in the ring type 'ring ' where is\n" +" your desired entry from the ring position list.\n" +"\n" +" You may also use the 'forward' ('f') or 'back' ('b') commands to move\n" +" to the previous or next entry in the ring, respectively.\n" +"\n" +" Note: Unlike the 'stack', 'push' and 'pop' commands, the ring tracks your\n" +" location implicitly. Use the 'push' and 'pop' commands if you wish to\n" +" store a specific location explicitly for later return.\n" +"\n", + RING_ENTRIES); +} + + +void +ring_add(void) +{ + if (ring_head == -1) { + /* only get here right after startup */ + ring_head = 0; + ring_tail = 0; + ring_current = 0; + iocur_ring[0] = *iocur_top; + } else { + if (ring_current == ring_head) { + ring_head = (ring_head+1)%RING_ENTRIES; + iocur_ring[ring_head] = *iocur_top; + if (ring_head == ring_tail) + ring_tail = (ring_tail+1)%RING_ENTRIES; + ring_current = ring_head; + } else { + ring_current = (ring_current+1)%RING_ENTRIES; + iocur_ring[ring_current] = *iocur_top; + } + } +} + + +int +write_bbs( + __int64_t bbno, + int count, + void *bufp, + bbmap_t *bbmap) +{ + int c; + int i; + int j; + int rval = EINVAL; /* initialize for zero `count' case */ + + for (j = 0; j < count; j += bbmap ? 1 : count) { + if (bbmap) + bbno = bbmap->b[j]; + if (lseek64(xfsargs.dfd, bbno << BBSHIFT, SEEK_SET) < 0) { + rval = errno; + dbprintf("can't seek in filesystem at bb %lld\n", bbno); + return rval; + } + c = BBTOB(bbmap ? 1 : count); + i = (int)write(xfsargs.dfd, (char *)bufp + BBTOB(j), c); + if (i < 0) { + rval = errno; + } else if (i < c) { + rval = -1; + } else + rval = 0; + if (rval) + break; + } + return rval; +} + +int +read_bbs( + __int64_t bbno, + int count, + void **bufp, + bbmap_t *bbmap) +{ + void *buf; + int c; + int i; + int j; + int rval = EINVAL; + + if (!count) + return EINVAL; + + c = BBTOB(count); + if (*bufp == NULL) + buf = xmalloc(c); + else + buf = *bufp; + for (j = 0; j < count; j += bbmap ? 1 : count) { + if (bbmap) + bbno = bbmap->b[j]; + if (lseek64(xfsargs.dfd, bbno << BBSHIFT, SEEK_SET) < 0) { + rval = errno; + dbprintf("can't seek in filesystem at bb %lld\n", bbno); + if (*bufp == NULL) + xfree(buf); + buf = NULL; + } else { + c = BBTOB(bbmap ? 1 : count); + i = (int)read(xfsargs.dfd, (char *)buf + BBTOB(j), c); + if (i < 0) { + rval = errno; + if (*bufp == NULL) + xfree(buf); + buf = NULL; + } else if (i < c) { + rval = -1; + if (*bufp == NULL) + xfree(buf); + buf = NULL; + } else + rval = 0; + } + if (buf == NULL) + break; + } + if (*bufp == NULL) + *bufp = buf; + return rval; +} + +void +write_cur(void) +{ + int ret; + + if (iocur_sp < 0) { + dbprintf("nothing to write\n"); + return; + } + ret = write_bbs(iocur_top->bb, iocur_top->blen, iocur_top->buf, + iocur_top->use_bbmap ? &iocur_top->bbmap : NULL); + if (ret == -1) + dbprintf("incomplete write, block: %lld\n", + (iocur_base + iocur_sp)->bb); + else if (ret != 0) + dbprintf("write error: %s\n", strerror(ret)); + /* re-read buffer from disk */ + ret = read_bbs(iocur_top->bb, iocur_top->blen, &iocur_top->buf, + iocur_top->use_bbmap ? &iocur_top->bbmap : NULL); + if (ret == -1) + dbprintf("incomplete read, block: %lld\n", + (iocur_base + iocur_sp)->bb); + else if (ret != 0) + dbprintf("read error: %s\n", strerror(ret)); +} + +void +set_cur( + const typ_t *t, + __int64_t d, + int c, + int ring_flag, + bbmap_t *bbmap) +{ + xfs_ino_t dirino; + xfs_ino_t ino; + __uint16_t mode; + + if (iocur_sp < 0) { + dbprintf("set_cur no stack element to set\n"); + return; + } + +#ifdef DEBUG + if (bbmap) + printf("xfs_db got a bbmap for %lld\n", (long long)d); +#endif + ino = iocur_top->ino; + dirino = iocur_top->dirino; + mode = iocur_top->mode; + pop_cur(); + push_cur(); + if (read_bbs(d, c, &iocur_top->buf, bbmap)) + return; + iocur_top->bb = d; + iocur_top->blen = c; + iocur_top->boff = 0; + iocur_top->data = iocur_top->buf; + iocur_top->len = BBTOB(c); + iocur_top->off = d << BBSHIFT; + iocur_top->typ = cur_typ = t; + iocur_top->ino = ino; + iocur_top->dirino = dirino; + iocur_top->mode = mode; + if ((iocur_top->use_bbmap = (bbmap != NULL))) + iocur_top->bbmap = *bbmap; + + /* store location in ring */ + if (ring_flag) + ring_add(); +} + +static void +stack_help(void) +{ + dbprintf( +"\n" +" The stack is used to explicitly store your location and data type\n" +" for later return. The 'push' operation stores the current address\n" +" and type on the stack, the 'pop' operation returns you to the\n" +" position and datatype of the top entry on the stack.\n" +"\n" +" The 'stack' allows explicit location saves, see 'ring' for implicit\n" +" position tracking.\n" +"\n" + ); +} + +/*ARGSUSED*/ +static int +stack_f( + int argc, + char **argv) +{ + int i; + char tagbuf[8]; + + for (i = iocur_sp; i >= 0; i--) { + sprintf(tagbuf, "%d: ", i); + print_iocur(tagbuf, &iocur_base[i]); + } + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/io.h linux-2.4-xfs/cmd/xfsprogs/db/io.h --- linux-2.4.7/cmd/xfsprogs/db/io.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/io.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct typ; + +#define BBMAP_SIZE (XFS_MAX_BLOCKSIZE / BBSIZE) +typedef struct bbmap { + __int64_t b[BBMAP_SIZE]; +} bbmap_t; + +typedef struct iocur { + __int64_t bb; /* BB number in filesystem of buf */ + int blen; /* length of "buf", bb's */ + int boff; /* data - buf */ + void *buf; /* base address of buffer */ + void *data; /* current interesting data */ + xfs_ino_t dirino; /* current directory inode number */ + xfs_ino_t ino; /* current inode number */ + int len; /* length of "data", bytes */ + __uint16_t mode; /* current inode's mode */ + xfs_off_t off; /* fs offset of "data" in bytes */ + const struct typ *typ; /* type of "data" */ + int use_bbmap; /* set if bbmap is valid */ + bbmap_t bbmap; /* map daddr if fragmented */ +} iocur_t; + +#define DB_RING_ADD 1 /* add to ring on set_cur */ +#define DB_RING_IGN 0 /* do not add to ring on set_cur */ + +extern iocur_t *iocur_base; /* base of stack */ +extern iocur_t *iocur_top; /* top element of stack */ +extern int iocur_sp; /* current top of stack */ +extern int iocur_len; /* length of stack array */ + +extern void io_init(void); +extern void off_cur(int off, int len); +extern void pop_cur(void); +extern void print_iocur(char *tag, iocur_t *ioc); +extern void push_cur(void); +extern int read_bbs(__int64_t daddr, int count, void **bufp, + bbmap_t *bbmap); +extern int write_bbs(__int64_t daddr, int count, void *bufp, + bbmap_t *bbmap); +extern void write_cur(void); +extern void set_cur(const struct typ *t, __int64_t d, int c, int ring_add, + bbmap_t *bbmap); +extern void ring_add(void); diff -rNu linux-2.4.7/cmd/xfsprogs/db/main.c linux-2.4-xfs/cmd/xfsprogs/db/main.c --- linux-2.4.7/cmd/xfsprogs/db/main.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/main.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "command.h" +#include "data.h" +#include "init.h" +#include "input.h" + +int +main( + int argc, + char **argv) +{ + int c; + int done; + char *input; + char **v; + + pushfile(stdin); + init(argc, argv); + done = 0; + while (!done) { + if ((input = fetchline()) == NULL) + break; + v = breakline(input, &c); + if (c) + done = command(c, v); + doneline(input, v); + } + return exitcode; +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/malloc.c linux-2.4-xfs/cmd/xfsprogs/db/malloc.c --- linux-2.4.7/cmd/xfsprogs/db/malloc.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/malloc.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "init.h" +#include "malloc.h" +#include "output.h" + +static void +badmalloc(void) +{ + dbprintf("%s: out of memory\n", progname); + exit(4); +} + +void * +xcalloc( + size_t nelem, + size_t elsize) +{ + void *ptr; + + ptr = calloc(nelem, elsize); + if (ptr) + return ptr; + badmalloc(); + /* NOTREACHED */ + return NULL; +} + +void +xfree( + void *ptr) +{ + free(ptr); +} + +void * +xmalloc( + size_t size) +{ + void *ptr; + + ptr = malloc(size); + if (ptr) + return ptr; + badmalloc(); + /* NOTREACHED */ + return NULL; +} + +void * +xrealloc( + void *ptr, + size_t size) +{ + ptr = realloc(ptr, size); + if (ptr || !size) + return ptr; + badmalloc(); + /* NOTREACHED */ + return NULL; +} + +char * +xstrdup( + const char *s1) +{ + char *s; + + s = strdup(s1); + if (s) + return s; + badmalloc(); + /* NOTREACHED */ + return NULL; +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/malloc.h linux-2.4-xfs/cmd/xfsprogs/db/malloc.h --- linux-2.4.7/cmd/xfsprogs/db/malloc.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/malloc.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern void *xcalloc(size_t nelem, size_t elsize); +extern void xfree(void *ptr); +extern void *xmalloc(size_t size); +extern void *xrealloc(void *ptr, size_t size); +extern char *xstrdup(const char *s1); diff -rNu linux-2.4.7/cmd/xfsprogs/db/mount.c linux-2.4-xfs/cmd/xfsprogs/db/mount.c --- linux-2.4.7/cmd/xfsprogs/db/mount.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/mount.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "init.h" +#include "io.h" +#include "mount.h" +#include "malloc.h" +#include "data.h" + +xfs_mount_t *mp; + +static void +compute_maxlevels( + xfs_mount_t *mp, + int whichfork) +{ + int level; + uint maxblocks; + uint maxleafents; + int maxrootrecs; + int minleafrecs; + int minnoderecs; + int sz; + + maxleafents = (whichfork == XFS_DATA_FORK) ? MAXEXTNUM : MAXAEXTNUM; + minleafrecs = mp->m_bmap_dmnr[0]; + minnoderecs = mp->m_bmap_dmnr[1]; + sz = mp->m_sb.sb_inodesize; + maxrootrecs = (int)XFS_BTREE_BLOCK_MAXRECS(sz, xfs_bmdr, 0); + maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; + for (level = 1; maxblocks > 1; level++) { + if (maxblocks <= maxrootrecs) + maxblocks = 1; + else + maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; + } + mp->m_bm_maxlevels[whichfork] = level; +} + +xfs_mount_t * +dbmount(void) +{ + void *bufp; + int i; + xfs_mount_t *mp; + xfs_sb_t *sbp; + + mp = xcalloc(1, sizeof(*mp)); + bufp = NULL; + if (read_bbs(XFS_SB_DADDR, 1, &bufp, NULL)) + return NULL; + + /* copy sb from buf to in-core, converting architecture */ + libxfs_xlate_sb(bufp, &mp->m_sb, 1, ARCH_CONVERT, XFS_SB_ALL_BITS); + xfree(bufp); + sbp = &mp->m_sb; + + if (sbp->sb_magicnum != XFS_SB_MAGIC) { + fprintf(stderr,"%s: unexpected XFS SB magic number 0x%08x\n", + progname, sbp->sb_magicnum); + } + mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG; + mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT; + mp->m_agno_log = libxfs_highbit32(sbp->sb_agcount - 1) + 1; + mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog; + mp->m_litino = + (int)(sbp->sb_inodesize - + (sizeof(xfs_dinode_core_t) + sizeof(xfs_agino_t))); + mp->m_blockmask = sbp->sb_blocksize - 1; + mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG; + mp->m_blockwmask = mp->m_blockwsize - 1; + for (i = 0; i < 2; i++) { + mp->m_alloc_mxr[i] = + (uint)XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, + xfs_alloc, i == 0); + mp->m_alloc_mnr[i] = + (uint)XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, + xfs_alloc, i == 0); + mp->m_bmap_dmxr[i] = + (uint)XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, + xfs_bmbt, i == 0); + mp->m_bmap_dmnr[i] = + (uint)XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, + xfs_bmbt, i == 0); + mp->m_inobt_mxr[i] = + (uint)XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, + xfs_inobt, i == 0); + mp->m_inobt_mnr[i] = + (uint)XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, + xfs_inobt, i == 0); + } + compute_maxlevels(mp, XFS_DATA_FORK); + compute_maxlevels(mp, XFS_ATTR_FORK); + mp->m_bsize = XFS_FSB_TO_BB(mp, 1); + mp->m_ialloc_inos = (int)MAX(XFS_INODES_PER_CHUNK, sbp->sb_inopblock); + mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog; + if (sbp->sb_rblocks) { + mp->m_rsumlevels = sbp->sb_rextslog + 1; + mp->m_rsumsize = + (uint)sizeof(xfs_suminfo_t) * mp->m_rsumlevels * + sbp->sb_rbmblocks; + if (sbp->sb_blocksize) + mp->m_rsumsize = + roundup(mp->m_rsumsize, sbp->sb_blocksize); + } + if (XFS_SB_VERSION_HASDIRV2(sbp)) { + mp->m_dirversion = 2; + mp->m_dirblksize = + 1 << (sbp->sb_dirblklog + sbp->sb_blocklog); + mp->m_dirblkfsbs = 1 << sbp->sb_dirblklog; + mp->m_dirdatablk = + XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_DATA_FIRSTDB(mp)); + mp->m_dirleafblk = + XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_LEAF_FIRSTDB(mp)); + mp->m_dirfreeblk = + XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_FREE_FIRSTDB(mp)); + } else { + mp->m_dirversion = 1; + mp->m_dirblksize = sbp->sb_blocksize; + mp->m_dirblkfsbs = 1; + } + return mp; +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/mount.h linux-2.4-xfs/cmd/xfsprogs/db/mount.h --- linux-2.4.7/cmd/xfsprogs/db/mount.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/mount.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern xfs_mount_t *dbmount(void); +extern xfs_mount_t *mp; diff -rNu linux-2.4.7/cmd/xfsprogs/db/output.c linux-2.4-xfs/cmd/xfsprogs/db/output.c --- linux-2.4.7/cmd/xfsprogs/db/output.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/output.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "command.h" +#include "output.h" +#include "sig.h" +#include "malloc.h" +#include "init.h" + +static int log_f(int argc, char **argv); + +static const cmdinfo_t log_cmd = + { "log", NULL, log_f, 0, 2, 0, "[stop|start ]", + "start or stop logging to a file", NULL }; + +int dbprefix; +static FILE *log_file; +static char *log_file_name; + +int +dbprintf(const char *fmt, ...) +{ + va_list ap; + int i; + + if (seenint()) + return 0; + va_start(ap, fmt); + blockint(); + i = 0; + if (dbprefix) + i += printf("%s: ", fsdevice); + i += vprintf(fmt, ap); + unblockint(); + va_end(ap); + if (log_file) { + va_start(ap, fmt); + vfprintf(log_file, fmt, ap); + va_end(ap); + } + return i; +} + +static int +log_f( + int argc, + char **argv) +{ + if (argc == 1) { + if (log_file) + dbprintf("logging to %s\n", log_file_name); + else + dbprintf("no log file\n"); + } else if (argc == 2 && strcmp(argv[1], "stop") == 0) { + if (log_file) { + xfree(log_file_name); + fclose(log_file); + log_file = NULL; + } else + dbprintf("no log file\n"); + } else if (argc == 3 && strcmp(argv[1], "start") == 0) { + if (log_file) + dbprintf("already logging to %s\n", log_file_name); + else { + log_file = fopen(argv[2], "a"); + if (log_file == NULL) + dbprintf("can't open %s for writing\n", + argv[2]); + else + log_file_name = xstrdup(argv[1]); + } + } else + dbprintf("bad log command, ignored\n"); + return 0; +} + +void +logprintf(const char *fmt, ...) +{ + va_list ap; + + if (log_file) { + va_start(ap, fmt); + (void)vfprintf(log_file, fmt, ap); + va_end(ap); + } +} + +void +output_init(void) +{ + add_command(&log_cmd); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/output.h linux-2.4-xfs/cmd/xfsprogs/db/output.h --- linux-2.4.7/cmd/xfsprogs/db/output.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/output.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern int dbprefix; + +extern int dbprintf(const char *, ...); +extern void logprintf(const char *, ...); +extern void output_init(void); diff -rNu linux-2.4.7/cmd/xfsprogs/db/print.c linux-2.4-xfs/cmd/xfsprogs/db/print.c --- linux-2.4.7/cmd/xfsprogs/db/print.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/print.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "command.h" +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "io.h" +#include "print.h" +#include "bit.h" +#include "flist.h" +#include "strvec.h" +#include "output.h" +#include "sig.h" +#include "write.h" + +static void print_allfields(const struct field *fields); +static int print_f(int argc, char **argv); +static void print_flist_1(struct flist *flist, char **pfx, int parentoff); +static void print_somefields(const struct field *fields, int argc, + char **argv); + +static const cmdinfo_t print_cmd = + { "print", "p", print_f, 0, -1, 0, "[value]...", + "print field values", NULL }; + +static void +print_allfields( + const field_t *fields) +{ + flist_t *flist; +#ifdef DEBUG + int i; +#endif + + flist = flist_make(""); + flist->fld = fields; +#ifndef DEBUG + (void)flist_parse(fields, flist, iocur_top->data, 0); +#else + i = flist_parse(fields, flist, iocur_top->data, 0); + ASSERT(i == 1); +#endif + flist_print(flist); + print_flist(flist); + flist_free(flist); +} + +static int +print_f( + int argc, + char **argv) +{ + pfunc_t pf; + + if (cur_typ == NULL) { + dbprintf("no current type\n"); + return 0; + } + pf = cur_typ->pfunc; + if (pf == NULL) { + dbprintf("no print function for type %s\n", cur_typ->name); + return 0; + } + argc--; + argv++; + (*pf)(DB_READ, cur_typ->fields, argc, argv); + return 0; +} + +void +print_flist( + flist_t *flist) +{ + char **pfx; + + pfx = new_strvec(0); + print_flist_1(flist, pfx, 0); + free_strvec(pfx); +} + +static void +print_flist_1( + flist_t *flist, + char **ppfx, + int parentoff) +{ + char buf[16]; + const field_t *f; + const ftattr_t *fa; + flist_t *fl; + int low; + int neednl; + char **pfx; + + for (fl = flist; fl && !seenint(); fl = fl->sibling) { + pfx = copy_strvec(ppfx); + if (fl->name[0]) + add_strvec(&pfx, fl->name); + if (fl->flags & FL_OKLOW) { + add_strvec(&pfx, "["); + sprintf(buf, "%d", fl->low); + add_strvec(&pfx, buf); + if (fl->low != fl->high) { + add_strvec(&pfx, "-"); + sprintf(buf, "%d", fl->high); + add_strvec(&pfx, buf); + } + add_strvec(&pfx, "]"); + } + if (fl->child) { + if (fl->name[0]) + add_strvec(&pfx, "."); + print_flist_1(fl->child, pfx, fl->offset); + } else { + f = fl->fld; + fa = &ftattrtab[f->ftyp]; + ASSERT(fa->ftyp == f->ftyp); + print_strvec(pfx); + dbprintf(" = "); + if (fl->flags & FL_OKLOW) + low = fl->low; + else + low = 0; + if (fa->prfunc) { + neednl = fa->prfunc(iocur_top->data, fl->offset, + fcount(f, iocur_top->data, parentoff), + fa->fmtstr, + fsize(f, iocur_top->data, parentoff, 0), + fa->arg, low, + (f->flags & FLD_ARRAY) != 0); + if (neednl) + dbprintf("\n"); + } else { + ASSERT(fa->arg & FTARG_OKEMPTY); + dbprintf("(empty)\n"); + } + } + free_strvec(pfx); + } +} + +void +print_init(void) +{ + add_command(&print_cmd); +} + +void +print_sarray( + void *obj, + int bit, + int count, + int size, + int base, + int array, + const field_t *flds, + int skipnms) +{ + int bitoff; + const field_t *f; + const ftattr_t *fa; + int first; + int i; + + ASSERT(bitoffs(bit) == 0); + if (skipnms == 0) { + for (f = flds, first = 1; f->name; f++) { + if (f->flags & FLD_SKIPALL) + continue; + dbprintf("%c%s", first ? '[' : ',', f->name); + first = 0; + } + dbprintf("] "); + } + for (i = 0, bitoff = bit; + i < count && !seenint(); + i++, bitoff += size) { + if (array) + dbprintf("%d:", i + base); + for (f = flds, first = 1; f->name; f++) { + if (f->flags & FLD_SKIPALL) + continue; + fa = &ftattrtab[f->ftyp]; + ASSERT(fa->ftyp == f->ftyp); + dbprintf("%c", first ? '[' : ','); + first = 0; + if (fa->prfunc) + fa->prfunc(obj, + bitoff + + bitoffset(f, obj, bitoff, i + base), + fcount(f, obj, bitoff), fa->fmtstr, + fsize(f, obj, bitoff, i + base), + fa->arg, (f->flags & FLD_ABASE1) != 0, + f->flags & FLD_ARRAY); + else { + ASSERT(fa->arg & FTARG_OKEMPTY); + dbprintf("(empty)"); + } + } + dbprintf("]"); + if (i < count - 1) + dbprintf(" "); + } +} + +static void +print_somefields( + const field_t *fields, + int argc, + char **argv) +{ + const ftattr_t *fa; + flist_t *fl; + flist_t *lfl; + flist_t *nfl; + + fl = lfl = NULL; + while (argc > 0) { + nfl = flist_scan(*argv); + if (!nfl) { + if (fl) + flist_free(fl); + return; + } + if (lfl) + lfl->sibling = nfl; + else + fl = nfl; + lfl = nfl; + argc--; + argv++; + } + if (fields->name[0] == '\0') { + fa = &ftattrtab[fields->ftyp]; + ASSERT(fa->ftyp == fields->ftyp); + fields = fa->subfld; + } + if (!flist_parse(fields, fl, iocur_top->data, 0)) { + flist_free(fl); + return; + } + flist_print(fl); + print_flist(fl); + flist_free(fl); +} + +/*ARGSUSED*/ +void +print_string( + const field_t *fields, + int argc, + char **argv) +{ + char *cp; + + if (argc != 0) + dbprintf("no arguments allowed\n"); + dbprintf("\""); + for (cp = iocur_top->data; + cp < (char *)iocur_top->data + iocur_top->len && *cp && + !seenint(); + cp++) + dbprintf("%c", *cp); + dbprintf("\"\n"); +} + +void +print_struct( + const field_t *fields, + int argc, + char **argv) +{ + if (argc == 0) + print_allfields(fields); + else + print_somefields(fields, argc, argv); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/print.h linux-2.4-xfs/cmd/xfsprogs/db/print.h --- linux-2.4.7/cmd/xfsprogs/db/print.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/print.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct field; +struct flist; + +extern void print_flist(struct flist *flist); +extern void print_init(void); +extern void print_sarray(void *obj, int bit, int count, int size, int base, + int array, const field_t *flds, int skipnms); +extern void print_struct(const struct field *fields, int argc, char **argv); +extern void print_string(const struct field *fields, int argc, char **argv); diff -rNu linux-2.4.7/cmd/xfsprogs/db/quit.c linux-2.4-xfs/cmd/xfsprogs/db/quit.c --- linux-2.4.7/cmd/xfsprogs/db/quit.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/quit.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "command.h" +#include "quit.h" + +static int quit_f(int argc, char **argv); + +static const cmdinfo_t quit_cmd = + { "quit", "q", quit_f, 0, 0, 0, NULL, + "exit xfs_db", NULL }; + +static int +quit_f( + int argc, + char **argv) +{ + return 1; +} + +void +quit_init(void) +{ + add_command(&quit_cmd); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/quit.h linux-2.4-xfs/cmd/xfsprogs/db/quit.h --- linux-2.4.7/cmd/xfsprogs/db/quit.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/quit.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern void quit_init(void); diff -rNu linux-2.4.7/cmd/xfsprogs/db/sb.c linux-2.4-xfs/cmd/xfsprogs/db/sb.c --- linux-2.4.7/cmd/xfsprogs/db/sb.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/sb.c Mon Apr 2 21:52:38 2001 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "command.h" +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "io.h" +#include "sb.h" +#include "bit.h" +#include "output.h" +#include "mount.h" + +static int sb_f(int argc, char **argv); +static void sb_help(void); + +static const cmdinfo_t sb_cmd = + { "sb", NULL, sb_f, 0, 1, 1, "[agno]", + "set current address to sb header", sb_help }; + +const field_t sb_hfld[] = { + { "", FLDT_SB, OI(0), C1, 0, TYP_NONE }, + { NULL } +}; + +#define OFF(f) bitize(offsetof(xfs_sb_t, sb_ ## f)) +#define SZC(f) szcount(xfs_sb_t, sb_ ## f) +const field_t sb_flds[] = { + { "magicnum", FLDT_UINT32X, OI(OFF(magicnum)), C1, 0, TYP_NONE }, + { "blocksize", FLDT_UINT32D, OI(OFF(blocksize)), C1, 0, TYP_NONE }, + { "dblocks", FLDT_DRFSBNO, OI(OFF(dblocks)), C1, 0, TYP_NONE }, + { "rblocks", FLDT_DRFSBNO, OI(OFF(rblocks)), C1, 0, TYP_NONE }, + { "rextents", FLDT_DRTBNO, OI(OFF(rextents)), C1, 0, TYP_NONE }, + { "uuid", FLDT_UUID, OI(OFF(uuid)), C1, 0, TYP_NONE }, + { "logstart", FLDT_DFSBNO, OI(OFF(logstart)), C1, 0, TYP_LOG }, + { "rootino", FLDT_INO, OI(OFF(rootino)), C1, 0, TYP_INODE }, + { "rbmino", FLDT_INO, OI(OFF(rbmino)), C1, 0, TYP_INODE }, + { "rsumino", FLDT_INO, OI(OFF(rsumino)), C1, 0, TYP_INODE }, + { "rextsize", FLDT_AGBLOCK, OI(OFF(rextsize)), C1, 0, TYP_NONE }, + { "agblocks", FLDT_AGBLOCK, OI(OFF(agblocks)), C1, 0, TYP_NONE }, + { "agcount", FLDT_AGNUMBER, OI(OFF(agcount)), C1, 0, TYP_NONE }, + { "rbmblocks", FLDT_EXTLEN, OI(OFF(rbmblocks)), C1, 0, TYP_NONE }, + { "logblocks", FLDT_EXTLEN, OI(OFF(logblocks)), C1, 0, TYP_NONE }, + { "versionnum", FLDT_UINT16X, OI(OFF(versionnum)), C1, 0, TYP_NONE }, + { "sectsize", FLDT_UINT16D, OI(OFF(sectsize)), C1, 0, TYP_NONE }, + { "inodesize", FLDT_UINT16D, OI(OFF(inodesize)), C1, 0, TYP_NONE }, + { "inopblock", FLDT_UINT16D, OI(OFF(inopblock)), C1, 0, TYP_NONE }, + { "fname", FLDT_CHARNS, OI(OFF(fname)), CI(SZC(fname)), 0, TYP_NONE }, + { "blocklog", FLDT_UINT8D, OI(OFF(blocklog)), C1, 0, TYP_NONE }, + { "sectlog", FLDT_UINT8D, OI(OFF(sectlog)), C1, 0, TYP_NONE }, + { "inodelog", FLDT_UINT8D, OI(OFF(inodelog)), C1, 0, TYP_NONE }, + { "inopblog", FLDT_UINT8D, OI(OFF(inopblog)), C1, 0, TYP_NONE }, + { "agblklog", FLDT_UINT8D, OI(OFF(agblklog)), C1, 0, TYP_NONE }, + { "rextslog", FLDT_UINT8D, OI(OFF(rextslog)), C1, 0, TYP_NONE }, + { "inprogress", FLDT_UINT8D, OI(OFF(inprogress)), C1, 0, TYP_NONE }, + { "imax_pct", FLDT_UINT8D, OI(OFF(imax_pct)), C1, 0, TYP_NONE }, + { "icount", FLDT_UINT64D, OI(OFF(icount)), C1, 0, TYP_NONE }, + { "ifree", FLDT_UINT64D, OI(OFF(ifree)), C1, 0, TYP_NONE }, + { "fdblocks", FLDT_UINT64D, OI(OFF(fdblocks)), C1, 0, TYP_NONE }, + { "frextents", FLDT_UINT64D, OI(OFF(frextents)), C1, 0, TYP_NONE }, + { "uquotino", FLDT_INO, OI(OFF(uquotino)), C1, 0, TYP_INODE }, + { "gquotino", FLDT_INO, OI(OFF(gquotino)), C1, 0, TYP_INODE }, + { "qflags", FLDT_UINT16X, OI(OFF(qflags)), C1, 0, TYP_NONE }, + { "flags", FLDT_UINT8X, OI(OFF(flags)), C1, 0, TYP_NONE }, + { "shared_vn", FLDT_UINT8D, OI(OFF(shared_vn)), C1, 0, TYP_NONE }, + { "inoalignmt", FLDT_EXTLEN, OI(OFF(inoalignmt)), C1, 0, TYP_NONE }, + { "unit", FLDT_UINT32D, OI(OFF(unit)), C1, 0, TYP_NONE }, + { "width", FLDT_UINT32D, OI(OFF(width)), C1, 0, TYP_NONE }, + { "dirblklog", FLDT_UINT8D, OI(OFF(dirblklog)), C1, 0, TYP_NONE }, + { NULL } +}; + +static void +sb_help(void) +{ + dbprintf( +"\n" +" set allocation group superblock\n" +"\n" +" Example:\n" +"\n" +" 'sb 7' - set location to 7th allocation group superblock, set type to 'sb'\n" +"\n" +" Located in the 1st 512 byte block of each allocation group,\n" +" the superblock contains the base information for the filesystem.\n" +" The superblock in allocation group 0 is the primary. The copies in the\n" +" remaining allocation groups only serve as backup for filesystem recovery.\n" +" The icount/ifree/fdblocks/frextents are only updated in superblock 0.\n" +"\n" +); +} + +static int +sb_f( + int argc, + char **argv) +{ + xfs_agnumber_t agno; + char *p; + + if (argc > 1) { + agno = (xfs_agnumber_t)strtoul(argv[1], &p, 0); + if (*p != '\0' || agno >= mp->m_sb.sb_agcount) { + dbprintf("bad allocation group number %s\n", argv[1]); + return 0; + } + cur_agno = agno; + } else if (cur_agno == NULLAGNUMBER) + cur_agno = 0; + ASSERT(typtab[TYP_SB].typnm == TYP_SB); + set_cur(&typtab[TYP_SB], XFS_AG_DADDR(mp, cur_agno, XFS_SB_DADDR), 1, + DB_RING_ADD, NULL); + return 0; +} + +void +sb_init(void) +{ + add_command(&sb_cmd); +} + +/*ARGSUSED*/ +int +sb_size( + void *obj, + int startoff, + int idx) +{ + return bitize(mp->m_sb.sb_sectsize); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/sb.h linux-2.4-xfs/cmd/xfsprogs/db/sb.h --- linux-2.4.7/cmd/xfsprogs/db/sb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/sb.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct field; + +extern const struct field sb_flds[]; +extern const struct field sb_hfld[]; + +extern void sb_init(void); +extern int sb_size(void *obj, int startoff, int idx); diff -rNu linux-2.4.7/cmd/xfsprogs/db/sig.c linux-2.4-xfs/cmd/xfsprogs/db/sig.c --- linux-2.4.7/cmd/xfsprogs/db/sig.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/sig.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "sig.h" + +static int gotintr; +static sigset_t intrset; + +static void +interrupt(int sig, siginfo_t *info, void *uc) +{ + gotintr = 1; +} + +void +blockint(void) +{ + sigprocmask(SIG_BLOCK, &intrset, NULL); +} + +void +clearint(void) +{ + gotintr = 0; +} + +void +init_sig(void) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = interrupt; + sigaction(SIGINT, &sa, NULL); + sigemptyset(&intrset); + sigaddset(&intrset, SIGINT); +} + +int +seenint(void) +{ + return gotintr; +} + +void +unblockint(void) +{ + sigprocmask(SIG_UNBLOCK, &intrset, NULL); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/sig.h linux-2.4-xfs/cmd/xfsprogs/db/sig.h --- linux-2.4.7/cmd/xfsprogs/db/sig.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/sig.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern void blockint(void); +extern void clearint(void); +extern void init_sig(void); +extern int seenint(void); +extern void unblockint(void); diff -rNu linux-2.4.7/cmd/xfsprogs/db/strvec.c linux-2.4-xfs/cmd/xfsprogs/db/strvec.c --- linux-2.4.7/cmd/xfsprogs/db/strvec.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/strvec.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "strvec.h" +#include "output.h" +#include "malloc.h" + +static int count_strvec(char **vec); + +void +add_strvec( + char ***vecp, + char *str) +{ + char *dup; + int i; + char **vec; + + dup = xstrdup(str); + vec = *vecp; + i = count_strvec(vec); + vec = xrealloc(vec, sizeof(*vec) * (i + 2)); + vec[i] = dup; + vec[i + 1] = NULL; + *vecp = vec; +} + +char ** +copy_strvec( + char **vec) +{ + int i; + char **rval; + + i = count_strvec(vec); + rval = new_strvec(i); + for (i = 0; vec[i] != NULL; i++) + rval[i] = xstrdup(vec[i]); + return rval; +} + +static int +count_strvec( + char **vec) +{ + int i; + + for (i = 0; vec[i] != NULL; i++) + continue; + return i; +} + +void +free_strvec( + char **vec) +{ + int i; + + for (i = 0; vec[i] != NULL; i++) + xfree(vec[i]); + xfree(vec); +} + +char ** +new_strvec( + int count) +{ + char **rval; + + rval = xmalloc(sizeof(*rval) * (count + 1)); + rval[count] = NULL; + return rval; +} + +void +print_strvec( + char **vec) +{ + int i; + + for (i = 0; vec[i] != NULL; i++) + dbprintf("%s", vec[i]); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/strvec.h linux-2.4-xfs/cmd/xfsprogs/db/strvec.h --- linux-2.4.7/cmd/xfsprogs/db/strvec.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/strvec.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern void add_strvec(char ***vecp, char *str); +extern char **copy_strvec(char **vec); +extern void free_strvec(char **vec); +extern char **new_strvec(int count); +extern void print_strvec(char **vec); diff -rNu linux-2.4.7/cmd/xfsprogs/db/type.c linux-2.4-xfs/cmd/xfsprogs/db/type.c --- linux-2.4.7/cmd/xfsprogs/db/type.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/type.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "agf.h" +#include "agfl.h" +#include "agi.h" +#include "block.h" +#include "command.h" +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "print.h" +#include "sb.h" +#include "inode.h" +#include "bnobt.h" +#include "cntbt.h" +#include "inobt.h" +#include "bmapbt.h" +#include "bmroot.h" +#include "agf.h" +#include "agfl.h" +#include "agi.h" +#include "dir.h" +#include "dirshort.h" +#include "io.h" +#include "output.h" +#include "write.h" +#include "attr.h" +#include "dquot.h" +#include "dir2.h" + +static const typ_t *findtyp(char *name); +static int type_f(int argc, char **argv); + +const typ_t *cur_typ; + +static const cmdinfo_t type_cmd = + { "type", NULL, type_f, 0, 1, 1, "[newtype]", + "set/show current data type", NULL }; + +const typ_t typtab[] = { + { TYP_AGF, "agf", handle_struct, agf_hfld }, + { TYP_AGFL, "agfl", handle_struct, agfl_hfld }, + { TYP_AGI, "agi", handle_struct, agi_hfld }, + { TYP_ATTR, "attr", handle_struct, attr_hfld }, + { TYP_BMAPBTA, "bmapbta", handle_struct, bmapbta_hfld }, + { TYP_BMAPBTD, "bmapbtd", handle_struct, bmapbtd_hfld }, + { TYP_BNOBT, "bnobt", handle_struct, bnobt_hfld }, + { TYP_CNTBT, "cntbt", handle_struct, cntbt_hfld }, + { TYP_DATA, "data", handle_block, NULL }, + { TYP_DIR, "dir", handle_struct, dir_hfld }, + { TYP_DIR2, "dir2", handle_struct, dir2_hfld }, + { TYP_DQBLK, "dqblk", handle_struct, dqblk_hfld }, + { TYP_INOBT, "inobt", handle_struct, inobt_hfld }, + { TYP_INODATA, "inodata", NULL, NULL }, + { TYP_INODE, "inode", handle_struct, inode_hfld }, + { TYP_LOG, "log", NULL, NULL }, + { TYP_RTBITMAP, "rtbitmap", NULL, NULL }, + { TYP_RTSUMMARY, "rtsummary", NULL, NULL }, + { TYP_SB, "sb", handle_struct, sb_hfld }, + { TYP_SYMLINK, "symlink", handle_string, NULL }, + { TYP_NONE, NULL } +}; + +static const typ_t * +findtyp( + char *name) +{ + const typ_t *tt; + + for (tt = typtab; tt->name != NULL; tt++) { + ASSERT(tt->typnm == (typnm_t)(tt - typtab)); + if (strcmp(tt->name, name) == 0) + return tt; + } + return NULL; +} + +static int +type_f( + int argc, + char **argv) +{ + const typ_t *tt; + int count = 0; + + if (argc == 1) { + if (cur_typ == NULL) + dbprintf("no current type\n"); + else + dbprintf("current type is \"%s\"\n", cur_typ->name); + + dbprintf("\n supported types are:\n "); + for (tt = typtab, count = 0; tt->name != NULL; tt++) { + if ((tt+1)->name != NULL) { + dbprintf("%s, ", tt->name); + if ((++count % 8) == 0) + dbprintf("\n "); + } else { + dbprintf("%s\n", tt->name); + } + } + + + } else { + tt = findtyp(argv[1]); + if (tt == NULL) { + dbprintf("no such type %s\n", argv[1]); + } else { + if (iocur_top->typ == NULL) { + dbprintf("no current object\n"); + } else { + iocur_top->typ = cur_typ = tt; + } + } + } + return 0; +} + +void +type_init(void) +{ + add_command(&type_cmd); +} + +/* read/write selectors for each major data type */ + +void +handle_struct( + int action, + const field_t *fields, + int argc, + char **argv) +{ + if (action == DB_WRITE) + write_struct(fields, argc, argv); + else + print_struct(fields, argc, argv); +} + +void +handle_string( + int action, + const field_t *fields, + int argc, + char **argv) +{ + if (action == DB_WRITE) + write_string(fields, argc, argv); + else + print_string(fields, argc, argv); +} + +void +handle_block( + int action, + const field_t *fields, + int argc, + char **argv) +{ + if (action == DB_WRITE) + write_block(fields, argc, argv); + else + print_block(fields, argc, argv); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/type.h linux-2.4-xfs/cmd/xfsprogs/db/type.h --- linux-2.4.7/cmd/xfsprogs/db/type.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/type.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct field; + +#define szof(x,y) sizeof(((x *)0)->y) +#define szcount(x,y) (szof(x,y) / szof(x,y[0])) + +typedef enum typnm +{ + TYP_AGF, TYP_AGFL, TYP_AGI, TYP_ATTR, TYP_BMAPBTA, + TYP_BMAPBTD, TYP_BNOBT, TYP_CNTBT, TYP_DATA, TYP_DIR, + TYP_DIR2, TYP_DQBLK, TYP_INOBT, TYP_INODATA, TYP_INODE, + TYP_LOG, TYP_RTBITMAP, TYP_RTSUMMARY, TYP_SB, TYP_SYMLINK, + TYP_NONE +} typnm_t; + +#define DB_WRITE 1 +#define DB_READ 0 + +typedef void (*opfunc_t)(const struct field *fld, int argc, char **argv); +typedef void (*pfunc_t)(int action, const struct field *fld, int argc, char **argv); + +typedef struct typ +{ + typnm_t typnm; + char *name; + pfunc_t pfunc; + const struct field *fields; +} typ_t; +extern const typ_t typtab[], *cur_typ; + +extern void type_init(void); +extern void handle_block(int action, const struct field *fields, int argc, + char **argv); +extern void handle_string(int action, const struct field *fields, int argc, + char **argv); +extern void handle_struct(int action, const struct field *fields, int argc, + char **argv); diff -rNu linux-2.4.7/cmd/xfsprogs/db/uuid.c linux-2.4-xfs/cmd/xfsprogs/db/uuid.c --- linux-2.4.7/cmd/xfsprogs/db/uuid.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/uuid.c Mon Jan 15 22:03:49 2001 @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "command.h" +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "io.h" +#include "uuid.h" +#include "bit.h" +#include "output.h" +#include "mount.h" + +static int uuid_f(int argc, char **argv); +static void uuid_help(void); +static int label_f(int argc, char **argv); +static void label_help(void); + +static const cmdinfo_t uuid_cmd = + { "uuid", NULL, uuid_f, 0, 1, 1, "[uuid]", + "write/print FS uuid", uuid_help }; +static const cmdinfo_t label_cmd = + { "label", NULL, label_f, 0, 1, 1, "[label]", + "write/print FS label", label_help }; +static int warned; + +static void +uuid_help(void) +{ + dbprintf( +"\n" +" write/print FS uuid\n" +"\n" +" Example:\n" +"\n" +" 'uuid' - print UUID\n" +" 'uuid 01234567-0123-0123-0123-0123456789ab' - write UUID\n" +" 'uuid generate' - generate and write\n" +" 'uuid rewrite' - copy UUID from SB 0\n" +"\n" +"The print function checks the UUID in each SB and will warn if the UUIDs\n" +"differ between AGs (the log is not checked). The write commands will\n" +"set the uuid in all AGs to either a specified value, a newly generated\n" +"value or the value found in the first superblock (SB 0) respectively.\n" +"As a side effect of writing the UUID, the log is cleared (which is fine\n" +"on a CLEANLY unmounted FS).\n" +"\n" +); +} + +static void +label_help(void) +{ + dbprintf( +"\n" +" write/print FS label\n" +"\n" +" Example:\n" +"\n" +" 'label' - print label\n" +" 'label 123456789012' - write label\n" +" 'label --' - write an empty label\n" +"\n" +"The print function checks the label in each SB and will warn if the labels\n" +"differ between AGs. The write commands will set the label in all AGs to the\n" +"specified value. The maximum length of a label is 12 characters - use of a\n" +"longer label will result in truncation and a warning will be issued.\n" +"\n" +); +} + +static int +get_sb(xfs_agnumber_t agno, xfs_sb_t *sb) +{ + push_cur(); + set_cur(&typtab[TYP_SB], XFS_AG_DADDR(mp, agno, XFS_SB_DADDR), 1, + DB_RING_IGN, NULL); + + if (!iocur_top->data) { + dbprintf("can't read superblock for AG %u\n", agno); + pop_cur(); + return 0; + } + + libxfs_xlate_sb(iocur_top->data, sb, 1, ARCH_CONVERT, XFS_SB_ALL_BITS); + + if (sb->sb_magicnum != XFS_SB_MAGIC) { + dbprintf("bad sb magic # %#x in AG %u\n", + sb->sb_magicnum, agno); + return 0; + } + if (!XFS_SB_GOOD_VERSION(sb)) { + dbprintf("bad sb version # %#x in AG %u\n", + sb->sb_versionnum, agno); + return 0; + } + if (agno == 0 && sb->sb_inprogress != 0) { + dbprintf("mkfs not completed successfully\n"); + return 0; + } + return 1; +} + +static uuid_t * +do_uuid(xfs_agnumber_t agno, uuid_t *uuid) +{ + xfs_sb_t tsb; + static uuid_t uu; + + if (!get_sb(agno, &tsb)) + return NULL; + + if (!uuid) { /* get uuid */ + memcpy(&uu, &tsb.sb_uuid, sizeof(uuid_t)); + pop_cur(); + return &uu; + } + /* set uuid */ + memcpy(&tsb.sb_uuid, uuid, sizeof(uuid_t)); + libxfs_xlate_sb(iocur_top->data, &tsb, -1, ARCH_CONVERT, XFS_SB_UUID); + write_cur(); + return uuid; +} + +static char * +do_label(xfs_agnumber_t agno, char *label) +{ + size_t len; + xfs_sb_t tsb; + static char lbl[sizeof(tsb.sb_fname) + 1]; + + if (!get_sb(agno, &tsb)) + return NULL; + + memset(&lbl[0], 0, sizeof(lbl)); + + if (!label) { /* get label */ + pop_cur(); + memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname)); + return &lbl[0]; + } + /* set label */ + if ((len = strlen(label)) > sizeof(tsb.sb_fname)) { + if (!warned++) + dbprintf("warning: truncating label from %lld to %lld " + "characters\n", + (long long)len, (long long)sizeof(tsb.sb_fname)); + len = sizeof(tsb.sb_fname); + } + if ( len == 2 && + (strcmp(label, "\"\"") == 0 || + strcmp(label, "''") == 0 || + strcmp(label, "--") == 0) ) + label[0] = label[1] = '\0'; + memset(&tsb.sb_fname, 0, sizeof(tsb.sb_fname)); + memcpy(&tsb.sb_fname, label, len); + memcpy(&lbl[0], &tsb.sb_fname, sizeof(tsb.sb_fname)); + libxfs_xlate_sb(iocur_top->data, &tsb, -1, ARCH_CONVERT, XFS_SB_FNAME); + write_cur(); + return &lbl[0]; +} + +static int +uuid_f( + int argc, + char **argv) +{ + char bp[40]; + xfs_agnumber_t agno; + uuid_t uu; + uuid_t *uup=NULL; + + if (argc != 1 && argc != 2) { + dbprintf("invalid parameters\n"); + return 0; + } + + if (argc==2) { + /* write uuid */ + + if (flag_readonly || !flag_expert_mode) { + dbprintf("%s not started in read-write expert mode, writing disabled\n", + progname); + return 0; + } + + if (!strcasecmp(argv[1], "generate")) { + uuid_generate(uu); + } else if (!strcasecmp(argv[1], "nil")) { + uuid_clear(uu); + } else if (!strcasecmp(argv[1], "rewrite")) { + uup=do_uuid(0, NULL); + if (!uup) { + dbprintf("failed to read UUID from AG 0\n"); + return 0; + } + memcpy(&uu, *uup, sizeof(uuid_t)); + uuid_unparse(uu, bp); + dbprintf("old uuid = %s\n", bp); + } else { + if (uuid_parse(argv[1], uu)) { + dbprintf("invalid uuid\n"); + return 0; + } + } + + if (mp->m_sb.sb_logstart) { + if (xfsargs.logdev) { + dbprintf("external log specified for FS with internal log - aborting \n"); + return 0; + } + } else { + if (!xfsargs.logdev) { + dbprintf("no external log specified for FS with external log - aborting\n"); + return 0; + } + } + + dbprintf("clearing log and setting uuid\n"); + + /* clear log (setting uuid) */ + + if (libxfs_log_clear( + (mp->m_sb.sb_logstart)?xfsargs.ddev:xfsargs.logdev, + XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart), + XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks), + &uu, + XLOG_FMT)) { + dbprintf("error clearing log\n"); + return 0; + } + + + dbprintf("writing all SBs\n"); + + for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) + if (!do_uuid(agno, &uu)) { + dbprintf("failed to set uuid in AG %d\n", agno); + break; + } + + uuid_unparse(uu, bp); + dbprintf("new uuid = %s\n", bp); + + return 0; + + } else { + /* get (check) uuid */ + + for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { + uup=do_uuid(agno, NULL); + if (!uup) { + dbprintf("failed to read UUID from AG %d\n", agno); + return 0; + } + if (agno) { + if (memcmp(&uu, uup, sizeof(uuid_t))) { + dbprintf("warning: uuid copies differ\n"); + break; + } + } else { + memcpy(uu, uup, sizeof(uuid_t)); + } + } + if (mp->m_sb.sb_logstart) { + if (xfsargs.logdev) + dbprintf("warning: external log specified for FS with internal log\n"); + } else { + if (!xfsargs.logdev) { + dbprintf("warning: no external log specified for FS with external log\n"); + } + } + + uuid_unparse(uu, bp); + dbprintf("uuid = %s\n", bp); + } + + return 0; +} + +static int +label_f( + int argc, + char **argv) +{ + char *p = NULL; + xfs_sb_t sb; + xfs_agnumber_t ag; + + if (argc != 1 && argc != 2) { + dbprintf("invalid parameters\n"); + return 0; + } + + if (argc==2) { /* write label */ + if (flag_readonly || !flag_expert_mode) { + dbprintf("%s not started in read-write expert mode, " + "writing disabled\n", progname); + return 0; + } + + dbprintf("writing all SBs\n"); + for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) + if ((p = do_label(ag, argv[1])) == NULL) { + dbprintf("failed to set label in AG %d\n", ag); + break; + } + dbprintf("new label = \"%s\"\n", p); + } else { /* print label */ + for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) { + p = do_label(ag, NULL); + if (!p) { + dbprintf("failed to read label in AG %d\n", ag); + return 0; + } + if (!ag) + memcpy(&sb.sb_fname, p, sizeof(sb.sb_fname)); + else if (memcmp(&sb.sb_fname, p, sizeof(sb.sb_fname))) + dbprintf("warning: label in AG %d differs\n", ag); + } + dbprintf("label = \"%s\"\n", p); + } + return 0; +} + +void +uuid_init(void) +{ + warned = 0; + add_command(&label_cmd); + add_command(&uuid_cmd); +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/uuid.h linux-2.4-xfs/cmd/xfsprogs/db/uuid.h --- linux-2.4.7/cmd/xfsprogs/db/uuid.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/uuid.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +extern void uuid_init(void); diff -rNu linux-2.4.7/cmd/xfsprogs/db/write.c linux-2.4-xfs/cmd/xfsprogs/db/write.c --- linux-2.4.7/cmd/xfsprogs/db/write.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/write.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,708 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include "bit.h" +#include "block.h" +#include "command.h" +#include "data.h" +#include "type.h" +#include "faddr.h" +#include "fprint.h" +#include "field.h" +#include "flist.h" +#include "io.h" +#include "output.h" +#include "print.h" +#include "write.h" +#include "malloc.h" + +static int write_f(int argc, char **argv); +static void write_help(void); + +static const cmdinfo_t write_cmd = + { "write", NULL, write_f, 0, -1, 0, "[field or value]...", + "write value to disk", write_help }; + +void +write_init(void) +{ + if (!flag_expert_mode) + return; + + add_command(&write_cmd); + srand48(clock()); +} + +static void +write_help(void) +{ + dbprintf( +"\n" +" The 'write' command takes on different personalities depending on the\n" +" type of object being worked with.\n\n" +" Write has 3 modes:\n" +" 'struct mode' - is active anytime you're looking at a filesystem object\n" +" which contains individual fields (ex: an inode).\n" +" 'data mode' - is active anytime you set a disk address directly or set\n" +" the type to 'data'.\n" +" 'string mode' - only used for writing symlink blocks.\n" +"\n" +" Examples:\n" +" Struct mode: 'write core.uid 23' - set an inode uid field to 23.\n" +" 'write fname \"hello\\000\"' - write superblock fname.\n" +" (note: in struct mode strings are not null terminated)\n" +" 'write fname #6669736800' - write superblock fname with hex.\n" +" 'write uuid 00112233-4455-6677-8899-aabbccddeeff'\n" +" - write superblock uuid.\n" +" Data mode: 'write fill 0xff' - fill the entire block with 0xff's\n" +" 'write lshift 3' - shift the block 3 bytes to the left\n" +" 'write sequence 1 5' - write a cycle of number [1-5] through\n" +" the entire block.\n" +" String mode: 'write \"This_is_a_filename\" - write null terminated string.\n" +"\n" +" In data mode type 'write' by itself for a list of specific commands.\n\n" +); + +} + +static int +write_f( + int argc, + char **argv) +{ + pfunc_t pf; + extern char *progname; + + if (flag_readonly) { + dbprintf("%s started in read only mode, writing disabled\n", + progname); + return 0; + } + + if (cur_typ == NULL) { + dbprintf("no current type\n"); + return 0; + } + + pf = cur_typ->pfunc; + if (pf == NULL) { + dbprintf("no handler function for type %s, write unsupported.\n", + cur_typ->name); + return 0; + } + + /* move past the "write" command */ + argc--; + argv++; + + (*pf)(DB_WRITE, cur_typ->fields, argc, argv); + + return 0; +} + +/* compare significant portions of commands */ + +static int +sigcmp( + char *s1, + char *s2, + int sig) +{ + int sigcnt; + + if (!s1 || !s2) + return 0; + + for (sigcnt = 0; *s1 == *s2; s1++, s2++) { + sigcnt++; + if (*s1 == '\0') + return 1; + } + if (*s1 && *s2) + return 0; + + if (sig && (sigcnt >= sig)) + return 1; + + return 0; +} + +/* ARGSUSED */ +static void +bwrite_lshift( + int start, + int len, + int shift, + int from, + int to) +{ + char *base; + + if (shift == -1) + shift = 1; + if (start == -1) + start = 0; + if (len == -1) + len = iocur_top->len - start; + + if (len+start > iocur_top->len) { + dbprintf("length (%d) too large for data block size (%d)", + len, iocur_top->len); + } + + base = (char *)iocur_top->data + start; + + memcpy(base, base+shift, len-shift); + memset(base+(len-shift), 0, shift); +} + +/* ARGSUSED */ +static void +bwrite_rshift( + int start, + int len, + int shift, + int from, + int to) +{ + char *base; + + if (shift == -1) + shift = 1; + if (start == -1) + start = 0; + if (len == -1) + len = iocur_top->len - start; + + if (len+start > iocur_top->len) { + dbprintf("length (%d) too large for data block size (%d)", + len, iocur_top->len); + } + + base = (char *)iocur_top->data + start; + + memcpy(base+shift, base, len-shift); + memset(base, 0, shift); +} + +/* ARGSUSED */ +static void +bwrite_lrot( + int start, + int len, + int shift, + int from, + int to) +{ + char *base; + char *hold_region; + + if (shift == -1) + shift = 1; + if (start == -1) + start = 0; + if (len == -1) + len = iocur_top->len - start; + + if (len+start > iocur_top->len) { + dbprintf("length (%d) too large for data block size (%d)", + len, iocur_top->len); + } + + base = (char *)iocur_top->data + start; + + hold_region = xmalloc(shift); + memcpy(hold_region, base, shift); + memcpy(base, base+shift, len-shift); + memcpy(base+(len-shift), hold_region, shift); +} + +/* ARGSUSED */ +static void +bwrite_rrot( + int start, + int len, + int shift, + int from, + int to) +{ + char *base; + char *hold_region; + + if (shift == -1) + shift = 1; + if (start == -1) + start = 0; + if (len == -1) + len = iocur_top->len - start; + + if (len+start > iocur_top->len) { + dbprintf("length (%d) too large for data block size (%d)", + len, iocur_top->len); + } + + base = (char *)iocur_top->data + start; + + hold_region = xmalloc(shift); + memcpy(hold_region, base+(len-shift), shift); + memcpy(base+shift, base, len-shift); + memcpy(base, hold_region, shift); +} + +/* ARGSUSED */ +static void +bwrite_seq( + int start, + int len, + int step, + int from, + int to) +{ + int i; + int tmp; + int base; + int range; + int top; + char *buf = (char *)iocur_top->data; + + if (start == -1) + start = 0; + + if (len == -1) + len = iocur_top->len - start; + + if (len+start > iocur_top->len) { + dbprintf("length (%d) too large for data block size (%d)", + len, iocur_top->len); + } + + if (from == -1 || from > 255) + from = 0; + if (to == -1 || to > 255) + to = 255; + if (step == -1) + step = 1; + + base = from; + top = to; + if (from > to) { + base = to; + top = from; + if (step > 0) + step = -step; + } + + range = top - base; + + tmp = 0; + for (i = start; i < start+len; i++) { + *buf++ = tmp + base; + tmp = (tmp + step)%(range+1); + } +} + +/* ARGSUSED */ +static void +bwrite_random( + int start, + int len, + int shift, + int from, + int to) +{ + int i; + char *buf = (char *)iocur_top->data; + + if (start == -1) + start = 0; + + if (len == -1) + len = iocur_top->len - start; + + if (len+start > iocur_top->len) { + dbprintf("length (%d) too large for data block size (%d)", + len, iocur_top->len); + } + + for (i = start; i < start+len; i++) + *buf++ = (char)lrand48(); +} + +/* ARGSUSED */ +static void +bwrite_fill( + int start, + int len, + int value, + int from, + int to) +{ + char *base; + + if (value == -1) + value = 0; + if (start == -1) + start = 0; + if (len == -1) + len = iocur_top->len - start; + + if (len+start > iocur_top->len) { + dbprintf("length (%d) too large for data block size (%d)", + len, iocur_top->len); + } + + base = (char *)iocur_top->data + start; + + memset(base, value, len); +} + +static struct bw_cmd { + void (*cmdfunc)(int,int,int,int,int); + char *cmdstr; + int sig_chars; + int argmin; + int argmax; + int shiftcount_arg; + int from_arg; + int to_arg; + int start_arg; + int len_arg; + char *usage; +} bw_cmdtab[] = { + /* cmd sig min max sh frm to start len */ + { bwrite_lshift, "lshift", 2, 0, 3, 1, 0, 0, 2, 3, + "[shiftcount] [start] [len]", }, + { bwrite_rshift, "rshift", 2, 0, 3, 1, 0, 0, 2, 3, + "[shiftcount] [start] [len]", }, + { bwrite_lrot, "lrot", 2, 0, 3, 1, 0, 0, 2, 3, + "[shiftcount] [start] [len]", }, + { bwrite_rrot, "rrot", 2, 0, 3, 1, 0, 0, 2, 3, + "[shiftcount] [start] [len]", }, + { bwrite_seq, "sequence", 3, 0, 4, 0, 1, 2, 3, 4, + "[from] [to] [start] [len]", }, + { bwrite_random, "random", 3, 0, 2, 0, 0, 0, 1, 2, + "[start] [len]", }, + { bwrite_fill, "fill", 1, 1, 3, 1, 0, 0, 2, 3, + "num [start] [len]" } +}; + +#define BWRITE_CMD_MAX (sizeof(bw_cmdtab)/sizeof(bw_cmdtab[0])) + +static int +convert_oct( + char *arg, + int *ret) +{ + int count; + int i; + int val = 0; + + /* only allow 1 case, '\' and 3 octal digits (or less) */ + + for (count = 0; count < 3; count++) { + if (arg[count] == '\0') + break; + + if ((arg[count] < '0') && (arg[count] > '7')) + break; + } + + for (i = 0; i < count; i++) { + val |= ((arg[(count-1)-i]-'0')&0x07)<<(i*3); + } + + *ret = val&0xff; + + return(count); +} + +#define NYBBLE(x) (isdigit(x)?(x-'0'):(tolower(x)-'a'+0xa)) + +static char * +convert_arg( + char *arg, + int bit_length) +{ + int i; + static char *buf = NULL; + char *rbuf; + long long *value; + int alloc_size; + char *ostr; + int octval, ret; + + if (bit_length <= 64) + alloc_size = 8; + else + alloc_size = (bit_length+7)/8; + + buf = xrealloc(buf, alloc_size); + memset(buf, 0, alloc_size); + value = (long long *)buf; + rbuf = buf; + + if (*arg == '\"') { + /* handle strings */ + + /* zap closing quote if there is one */ + if ((ostr = strrchr(arg+1, '\"')) != NULL) + *ostr = '\0'; + + ostr = arg+1; + for (i = 0; i < alloc_size; i++) { + if (!*ostr) + break; + + /* do octal */ + if (*ostr == '\\') { + if (*(ostr+1) >= '0' || *(ostr+1) <= '7') { + ret = convert_oct(ostr+1, &octval); + *rbuf++ = octval; + ostr += ret+1; + continue; + } + } + *rbuf++ = *ostr++; + } + + return buf; + } else if (arg[0] == '#' || strchr(arg,'-')) { + /* + * handle hex blocks ie + * #00112233445566778899aabbccddeeff + * and uuids ie + * 1122334455667788-99aa-bbcc-ddee-ff00112233445566778899 + */ + int bytes=bit_length/8; + + /* skip leading hash */ + if (*arg=='#') arg++; + + while (*arg && bytes--) { + /* skip hypens */ + while (*arg=='-') arg++; + + /* get first nybble */ + if (!isxdigit(*arg)) return NULL; + *rbuf=NYBBLE(*arg)<<4; + arg++; + + /* skip more hyphens */ + while (*arg=='-') arg++; + + /* get second nybble */ + if (!isxdigit(*arg)) return NULL; + *rbuf++|=NYBBLE(*arg); + arg++; + } + if (bytes<0&&*arg) return NULL; + return buf; + } else { + /* + * handle integers + */ + *value = strtoll(arg, NULL, 0); + +#if __BYTE_ORDER == BIG_ENDIAN + /* hackery for big endian */ + if (bit_length <= 8) { + rbuf += 7; + } else if (bit_length <= 16) { + rbuf += 6; + } else if (bit_length <= 32) { + rbuf += 4; + } +#endif + return rbuf; + } +} + + +/* ARGSUSED */ +void +write_struct( + const field_t *fields, + int argc, + char **argv) +{ + const ftattr_t *fa; + flist_t *fl; + flist_t *sfl; + int bit_length; + char *buf; + int parentoffset; + + if (argc != 2) { + dbprintf("usage: write fieldname value\n"); + return; + } + + fl = flist_scan(argv[0]); + if (!fl) { + dbprintf("unable to parse '%s'.\n", argv[0]); + return; + } + + /* if we're a root field type, go down 1 layer to get field list */ + if (fields->name[0] == '\0') { + fa = &ftattrtab[fields->ftyp]; + ASSERT(fa->ftyp == fields->ftyp); + fields = fa->subfld; + } + + /* run down the field list and set offsets into the data */ + if (!flist_parse(fields, fl, iocur_top->data, 0)) { + flist_free(fl); + dbprintf("parsing error\n"); + return; + } + + sfl = fl; + parentoffset = 0; + while (sfl->child) { + parentoffset = sfl->offset; + sfl = sfl->child; + } + + bit_length = fsize(sfl->fld, iocur_top->data, parentoffset, 0); + bit_length *= fcount(sfl->fld, iocur_top->data, parentoffset); + + /* convert this to a generic conversion routine */ + /* should be able to handle str, num, or even labels */ + + buf = convert_arg(argv[1], bit_length); + if (!buf) { + dbprintf("unable to convert value '%s'.\n", argv[1]); + return; + } + + setbitval(iocur_top->data, sfl->offset, bit_length, buf); + write_cur(); + + flist_print(fl); + print_flist(fl); + flist_free(fl); +} + +/* ARGSUSED */ +void +write_string( + const field_t *fields, + int argc, + char **argv) +{ + char *buf; + int i; + + if (argc != 1) { + dbprintf("usage (in string mode): write \"string...\"\n"); + return; + } + + buf = convert_arg(argv[0], (int)((strlen(argv[0])+1)*8)); + for (i = 0; i < iocur_top->len; i++) { + ((char *)iocur_top->data)[i] = *buf; + if (*buf++ == '\0') + break; + } + + /* write back to disk */ + write_cur(); +} + +/* ARGSUSED */ +void +write_block( + const field_t *fields, + int argc, + char **argv) +{ + int i; + int shiftcount = -1; + int start = -1; + int len = -1; + int from = -1; + int to = -1; + struct bw_cmd *cmd = NULL; + + if (argc <= 1 || argc > 5) + goto block_usage; + + for (i = 0; i < BWRITE_CMD_MAX; i++) { + if (sigcmp(argv[0], bw_cmdtab[i].cmdstr, + bw_cmdtab[i].sig_chars)) { + cmd = &bw_cmdtab[i]; + break; + } + } + + if (!cmd) { + dbprintf("write: invalid subcommand\n"); + goto block_usage; + } + + if ((argc < cmd->argmin + 1) || (argc > cmd->argmax + 1)) { + dbprintf("write %s: invalid number of arguments\n", + cmd->cmdstr); + goto block_usage; + } + + if (cmd->shiftcount_arg && (cmd->shiftcount_arg < argc)) + shiftcount = (int)strtoul(argv[cmd->shiftcount_arg], NULL, 0); + if (cmd->start_arg && (cmd->start_arg < argc)) + start = (int)strtoul(argv[cmd->start_arg], NULL, 0); + if (cmd->len_arg && (cmd->len_arg < argc)) + len = (int)strtoul(argv[cmd->len_arg], NULL, 0); + if (cmd->from_arg && (cmd->len_arg < argc)) + from = (int)strtoul(argv[cmd->from_arg], NULL, 0); + if (cmd->to_arg && (cmd->len_arg < argc)) + to = (int)strtoul(argv[cmd->to_arg], NULL, 0); + + cmd->cmdfunc(start, len, shiftcount, from, to); + + /* write back to disk */ + write_cur(); + return; + + block_usage: + + dbprintf("usage: write (in data mode)\n"); + for (i = 0; i < BWRITE_CMD_MAX; i++) { + dbprintf(" %-9.9s %s\n", + bw_cmdtab[i].cmdstr, bw_cmdtab[i].usage); + } + dbprintf("\n"); + return; +} diff -rNu linux-2.4.7/cmd/xfsprogs/db/write.h linux-2.4-xfs/cmd/xfsprogs/db/write.h --- linux-2.4.7/cmd/xfsprogs/db/write.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/write.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct field; + +extern void write_init(void); +extern void write_block(const field_t *fields, int argc, char **argv); +extern void write_string(const field_t *fields, int argc, char **argv); +extern void write_struct(const field_t *fields, int argc, char **argv); diff -rNu linux-2.4.7/cmd/xfsprogs/db/xfs_admin.sh linux-2.4-xfs/cmd/xfsprogs/db/xfs_admin.sh --- linux-2.4.7/cmd/xfsprogs/db/xfs_admin.sh Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/xfs_admin.sh Sun Jan 14 23:36:03 2001 @@ -0,0 +1,60 @@ +#!/bin/sh -f +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +OPTS="" +USAGE="Usage: xfs_admin [-flu] [-L label] [-U uuid] special" + +while getopts "fluL:U:" c +do + case $c in + f) OPTS=$OPTS" -f";; + l) OPTS=$OPTS" -c label";; + L) OPTS=$OPTS" -c 'label "$OPTARG"'";; + u) OPTS=$OPTS" -c uuid";; + U) OPTS=$OPTS" -c 'uuid "$OPTARG"'";; + \?) echo $USAGE 1>&2 + exit 2 + ;; + esac +done +set -- extra $@ +shift $OPTIND +case $# in + 1) eval xfs_db -x -p xfs_admin $OPTS $1 + status=$? + ;; + *) echo $USAGE 1>&2 + exit 2 + ;; +esac +exit $status diff -rNu linux-2.4.7/cmd/xfsprogs/db/xfs_check.sh linux-2.4-xfs/cmd/xfsprogs/db/xfs_check.sh --- linux-2.4.7/cmd/xfsprogs/db/xfs_check.sh Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/xfs_check.sh Sun Jan 14 23:36:03 2001 @@ -0,0 +1,63 @@ +#!/bin/sh -f +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +#ident "$Revision: 1.1 $" + +OPTS=" " +ISFILE=" " +USAGE="usage: xfs_check [-svf] [-i ino]... [-b bno]... special" + + +while getopts "b:fi:sv" c +do + case $c in + s) OPTS=$OPTS"-s ";; + v) OPTS=$OPTS"-v ";; + i) OPTS=$OPTS"-i "$OPTARG" ";; + b) OPTS=$OPTS"-b "$OPTARG" ";; + f) ISFILE=" -f";; + \?) echo $USAGE 1>&2 + exit 2 + ;; + esac +done +set -- extra $@ +shift $OPTIND +case $# in + 1) xfs_db$ISFILE -i -p xfs_check -c "check$OPTS" $1 + status=$? + ;; + *) echo $USAGE 1>&2 + exit 2 + ;; +esac +exit $status diff -rNu linux-2.4.7/cmd/xfsprogs/db/xfs_check64.sh linux-2.4-xfs/cmd/xfsprogs/db/xfs_check64.sh --- linux-2.4.7/cmd/xfsprogs/db/xfs_check64.sh Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/xfs_check64.sh Sun Jan 14 23:36:03 2001 @@ -0,0 +1,63 @@ +#!/bin/sh -f +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +#ident "$Revision: 1.1 $" + +OPTS=" " +ISFILE=" " +USAGE="usage: xfs_check64 [-svf] [-i ino]... [-b bno]... special" + + +while getopts "b:fi:sv" c +do + case $c in + s) OPTS=$OPTS"-s ";; + v) OPTS=$OPTS"-v ";; + i) OPTS=$OPTS"-i "$OPTARG" ";; + b) OPTS=$OPTS"-b "$OPTARG" ";; + f) ISFILE=" -f";; + \?) echo $USAGE 1>&2 + exit 2 + ;; + esac +done +set -- extra $@ +shift $OPTIND +case $# in + 1) xfs_db64$ISFILE -i -p xfs_check64 -c "check$OPTS" $1 + status=$? + ;; + *) echo $USAGE 1>&2 + exit 2 + ;; +esac +exit $status diff -rNu linux-2.4.7/cmd/xfsprogs/db/xfs_ncheck.sh linux-2.4-xfs/cmd/xfsprogs/db/xfs_ncheck.sh --- linux-2.4.7/cmd/xfsprogs/db/xfs_ncheck.sh Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/xfs_ncheck.sh Sun Jan 14 23:36:03 2001 @@ -0,0 +1,61 @@ +#!/bin/sh -f +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +#ident "$Revision: 1.1 $" + +OPTS=" " +ISFILE=" " +USAGE="usage: xfs_ncheck [-sf] [-i ino]... special" + + +while getopts "b:fi:sv" c +do + case $c in + s) OPTS=$OPTS"-s ";; + i) OPTS=$OPTS"-i "$OPTARG" ";; + f) ISFILE=" -f";; + \?) echo $USAGE 1>&2 + exit 2 + ;; + esac +done +set -- extra $@ +shift $OPTIND +case $# in + 1) xfs_db$ISFILE -r -p xfs_ncheck -c "blockget -ns" -c "ncheck$OPTS" $1 + status=$? + ;; + *) echo $USAGE 1>&2 + exit 2 + ;; +esac +exit $status diff -rNu linux-2.4.7/cmd/xfsprogs/db/xfs_ncheck64.sh linux-2.4-xfs/cmd/xfsprogs/db/xfs_ncheck64.sh --- linux-2.4.7/cmd/xfsprogs/db/xfs_ncheck64.sh Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/db/xfs_ncheck64.sh Sun Jan 14 23:36:03 2001 @@ -0,0 +1,61 @@ +#!/bin/sh -f +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +#ident "$Revision: 1.1 $" + +OPTS=" " +ISFILE=" " +USAGE="usage: xfs_ncheck64 [-sf] [-i ino]... special" + + +while getopts "b:fi:sv" c +do + case $c in + s) OPTS=$OPTS"-s ";; + i) OPTS=$OPTS"-i "$OPTARG" ";; + f) ISFILE=" -f";; + \?) echo $USAGE 1>&2 + exit 2 + ;; + esac +done +set -- extra $@ +shift $OPTIND +case $# in + 1) xfs_db64$ISFILE -r -p xfs_ncheck64 -c "blockget -ns" -c "ncheck$OPTS" $1 + status=$? + ;; + *) echo $USAGE 1>&2 + exit 2 + ;; +esac +exit $status diff -rNu linux-2.4.7/cmd/xfsprogs/debian/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/debian/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/debian/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/debian/CVS/Entries Thu Jul 5 11:44:26 2001 @@ -0,0 +1,6 @@ +/Makefile/1.1/Mon Jan 15 06:52:52 2001/-ko/ +/changelog/1.16/Tue Jul 3 04:33:45 2001/-ko/ +/control/1.4/Wed May 9 06:56:06 2001/-ko/ +/copyright/1.1/Mon Jan 15 06:52:52 2001/-ko/ +/rules/1.4/Wed May 9 06:56:06 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/debian/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/debian/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/debian/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/debian/CVS/Repository Thu Jul 5 11:44:26 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/debian diff -rNu linux-2.4.7/cmd/xfsprogs/debian/CVS/Root linux-2.4-xfs/cmd/xfsprogs/debian/CVS/Root --- linux-2.4.7/cmd/xfsprogs/debian/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/debian/CVS/Root Thu Jul 5 11:44:26 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/debian/Makefile linux-2.4-xfs/cmd/xfsprogs/debian/Makefile --- linux-2.4.7/cmd/xfsprogs/debian/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/debian/Makefile Mon Jan 15 00:52:52 2001 @@ -0,0 +1,40 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LSRCFILES = changelog control copyright rules + +default install install-dev: + +include $(BUILDRULES) diff -rNu linux-2.4.7/cmd/xfsprogs/debian/changelog linux-2.4-xfs/cmd/xfsprogs/debian/changelog --- linux-2.4.7/cmd/xfsprogs/debian/changelog Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/debian/changelog Mon Jul 2 23:33:45 2001 @@ -0,0 +1,102 @@ +xfsprogs (1.2.8) unstable; urgency=low + + * Fixed a bug in libxfs /etc/mtab read-only mount detection + * First try procfs, fall back to /etc/mtab, for read-only mounts + * Sync with recent mount code changes for reiserfs and ext3 probes + * Fix logprint build problem under gcc 3.0 + + -- Nathan Scott Mon, 2 Jul 2001 13:59:08 +1000 + +xfsprogs (1.2.7) unstable; urgency=low + + * New xfs_freeze(8) command - volume manager snapshot helper + + -- Nathan Scott Tue, 22 May 2001 17:22:32 +1000 + +xfsprogs (1.2.6) unstable; urgency=low + + * Merge support for -d agsize=/su=/sw= (AG, stripe unit/width size) + * Merge support for dynamic configuration of default log size + * Document these updates, and fix a couple of man page typos too + + -- Nathan Scott Tue, 15 May 2001 12:34:17 +1000 + +xfsprogs (1.2.5) unstable; urgency=low + + * Fix missing Makefile include entries for LVM headers + * Add experimental xfs_rtcp (realtime copy) command + * PowerPC build failure fixups - thanks to Robert Ramiega + * Cleanup arch-specific code, esp. the byteswab routines + * Suggests xfsdump and attr packages + + -- Nathan Scott Tue, 8 May 2001 15:50:27 +1000 + +xfsprogs (1.2.4) unstable; urgency=low + + * Add -L option to mkfs.xfs (filesystem label) + + -- Nathan Scott Tue, 1 May 2001 14:03:14 +1000 + +xfsprogs (1.2.3) unstable; urgency=low + + * Add dquot and quotaoff log item support into xfs_logprint + * Fix logprint core dump reporting AGI in "continue"'d transactions + + -- Nathan Scott Fri, 27 Apr 2001 10:17:25 +1000 + +xfsprogs (1.2.2) unstable; urgency=low + + * Fix problem in xfs_db (check) group quota logic + * Fixes to warnings from recent gcc and/or 64-bit builds + + -- Nathan Scott Fri, 13 Apr 2001 09:50:37 +1000 + +xfsprogs (1.2.1) unstable; urgency=low + + * Support for group quota added + * Stripe unit/stripe width extraction for MD devices + * Added mkfs.xfs heuristics for size of internal log + * Sync up with recent changes to XFS kernel headers + + -- Nathan Scott Wed, 4 Apr 2001 13:54:00 +1000 + +xfsprogs (1.1.6) unstable; urgency=low + + * Fix sparc build failure - fcntl.h missing O_DIRECT (closes: #90211) + * Added README.quota describing the use of quota with XFS + + -- Nathan Scott Tue, 20 Mar 2001 11:25:03 +1100 + +xfsprogs (1.1.5) unstable; urgency=low + + * Upgraded LVM stripe unit/width support to 0.9beta2 (IOP 10) + * Kernel now supports O_DIRECT - re-enable its use in xfs_mkfile + * BLKSETSIZE ioctl replaced by BLKBSZSET ioctl in libxfs + * libxfs_init extended so only mkfs and xfs_repair use BLKBSZSET + * NOTE: this requires an XFS kernel from 9 March '01 or later + + -- Nathan Scott Sun, 18 Mar 2001 14:31:17 +1100 + +xfsprogs (1.1.3) unstable; urgency=low + + * Minor changes to xfs_logprint tail verification + * Update build Makefile to pick up extra dirt before packaging + + -- Nathan Scott Thu, 1 Mar 2001 12:24:28 +1100 + +xfsprogs (1.1.2) unstable; urgency=low + + * Fix stdarg.h issue causing build failure with glibc 2.2.2 + * Changes to libhandle for supporting extended attributes + + -- Nathan Scott Tue, 20 Feb 2001 08:29:36 +1100 + +xfsprogs (1.1.0) unstable; urgency=low + + * Initial release (closes: #83829) + + -- Nathan Scott Thu, 4 Jan 2001 11:15:11 -0500 + +Local variables: +mode: debian-changelog +End: diff -rNu linux-2.4.7/cmd/xfsprogs/debian/control linux-2.4-xfs/cmd/xfsprogs/debian/control --- linux-2.4.7/cmd/xfsprogs/debian/control Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/debian/control Wed May 9 01:56:06 2001 @@ -0,0 +1,34 @@ +Source: xfsprogs +Section: admin +Priority: optional +Maintainer: Nathan Scott +Build-Depends: uuid-dev, autoconf, debmake +Standards-Version: 3.1.1 + +Package: xfsprogs +Depends: ${shlibs:Depends} +Suggests: xfsdump, attr +Architecture: any +Description: Utilities for managing the XFS filesystem + A set of commands to use the XFS filesystem, including mkfs.xfs. + . + XFS is a high performance journaling filesystem which originated + on the SGI IRIX platform. It is completely multi-threaded, can + support large files and large filesystems, extended attributes, + variable block sizes, is extent based, and makes extensive use of + Btrees (directories, extents, free space) to aid both performance + and scalability. + . + Refer to the documentation at http://oss.sgi.com/projects/xfs/ + for complete details. This implementation is on-disk compatible + with the IRIX version of XFS. + +Package: xfslibs-dev +Section: devel +Priority: extra +Depends: libc6-dev, xfsprogs +Architecture: any +Description: XFS filesystem-specific static libraries and headers. + xfslibs-dev contains the libraries and header files needed to + develop XFS filesystem-specific programs. + diff -rNu linux-2.4.7/cmd/xfsprogs/debian/copyright linux-2.4-xfs/cmd/xfsprogs/debian/copyright --- linux-2.4.7/cmd/xfsprogs/debian/copyright Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/debian/copyright Mon Jan 15 00:52:52 2001 @@ -0,0 +1,14 @@ +This package was debianized by Nathan Scott nathans@debian.org on +Sun, 19 Nov 2000 07:37:09 -0500. + +It can be downloaded from ftp://oss.sgi.com/projects/xfs/download/ + +Copyright: + +Copyright (C) 2000 Silicon Graphics, Inc. + +You are free to distribute this software under the terms of +the GNU General Public License. +On Debian systems, the complete text of the GNU General Public +License can be found in /usr/share/common-licenses/GPL file. + diff -rNu linux-2.4.7/cmd/xfsprogs/debian/rules linux-2.4-xfs/cmd/xfsprogs/debian/rules --- linux-2.4.7/cmd/xfsprogs/debian/rules Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/debian/rules Wed May 9 01:56:06 2001 @@ -0,0 +1,60 @@ +#!/usr/bin/make -f + +package = xfsprogs +develop = xfslibs-dev + +dirtmp = debian/tmp +dirdev = debian/$(develop) +doctmp = /usr/share/doc/$(package) +docdev = /usr/share/doc/$(develop) +pkgtmp = DIST_ROOT=`pwd`/$(dirtmp); export DIST_ROOT; +pkgdev = DIST_ROOT=`pwd`/$(dirdev); export DIST_ROOT; +stdenv = GZIP=-q; export GZIP; + +options = DEBUG=-DNDEBUG; DISTRIBUTION=debian; export DEBUG DISTRIBUTION; +checkdir = test -f debian/rules + +build: built +built: + @echo "== dpkg-buildpackage: build" 1>&2 + $(checkdir) + autoconf + $(options) ./configure + $(MAKE) default + touch built + +clean: + @echo "== dpkg-buildpackage: clean" 1>&2 + $(checkdir) + -rm -f built + $(MAKE) distclean + -rm -rf $(dirtmp) $(dirdev) debian/*substvars debian/files* + +binary-indep: + +binary-arch: checkroot built + @echo "== dpkg-buildpackage: binary-arch" 1>&2 + $(checkdir) + -rm -rf $(dirtmp) $(dirdev) + $(pkgtmp) $(MAKE) -C . install + $(pkgdev) $(MAKE) -C . install-dev + $(pkgtmp) $(MAKE) -C build src-manifest + $(pkgdev) ./install-sh -m 755 -d $(doctmp) + $(pkgdev) ./install-sh -m 755 -d $(docdev) + $(pkgdev) ./install-sh -m 644 debian/copyright $(docdev) + $(pkgdev) ./install-sh -m 644 debian/changelog $(docdev) + @echo "== dpkg-buildpackage: debstd" 1>&2 + $(stdenv) debstd -m + dpkg-gencontrol -isp -p$(package) -P$(dirtmp) + dpkg-gencontrol -isp -p$(develop) -P$(dirdev) + chown -R root.root $(dirtmp) $(dirdev) + chmod -R go=rX $(dirtmp) $(dirdev) + dpkg --build $(dirtmp) .. + dpkg --build $(dirdev) .. + +binary: binary-indep binary-arch + +checkroot: + test 0 -eq `id -u` + +.PHONY: binary binary-arch binary-indep clean checkroot diff -rNu linux-2.4.7/cmd/xfsprogs/doc/CHANGES linux-2.4-xfs/cmd/xfsprogs/doc/CHANGES --- linux-2.4.7/cmd/xfsprogs/doc/CHANGES Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/doc/CHANGES Mon Jul 2 23:33:45 2001 @@ -0,0 +1,127 @@ +xfsprogs-1.2.8 (02 Jul 2001) + - fixed a bug in libxfs /etc/mtab read-only mount detection + - first try procfs, fall back to /etc/mtab, for read-only mounts + - sync with recent mount code changes for reiserfs and ext3 probes + - fix logprint build problem under gcc 3.0 + +xfsprogs-1.2.7 (22 May 2001) + - new xfs_freeze(8) command - volume manager snapshot helper + +xfsprogs-1.2.6 (15 May 2001) + - merge support for -d agsize=/su=/sw= (AG, stripe unit/width size) + - merge support for dynamic configuration of default log size + - document these and fix a couple of man page typos too + +xfsprogs-1.2.5 (07 May 2001) + - fix missing Makefile include entries for LVM headers + - configure script default man path now /usr/share/man + - add experimental xfs_rtcp (realtime copy) command + - powerpc build failure fixups - thanks to Robert Ramiega + - cleanup arch-specific code, esp. the byteswab routines + - as a result, move to -O1 as default for extern inlines + +xfsprogs-1.2.4 (01 May 2001) + - added -L option to mkfs.xfs (filesystem label) + +xfsprogs-1.2.3 (27 April 2001) + - add dquot and quotaoff log item support into xfs_logprint + - fix logprint core dump reporting AGI in "continue"'d transactions + +xfsprogs-1.2.2 (09 April 2001) + - fix problem in xfs_db (check) group quota logic + - fixes to warnings from recent gcc and/or 64-bit builds + +xfsprogs-1.2.1 (04 April 2001) + - sync up with recent changes to XFS kernel headers + +xfsprogs-1.2.0 (01 April 2001) + - support for group quota added + - some headers updated, in particular + - now in late stages of beta + +xfsprogs-1.1.9 (26 March 2001) + - added automagic stripe unit/stripe width extraction for MD devices + +xfsprogs-1.1.8 (23 March 2001) + - mkfs heuristics to make a qualified guess of internal logsize + +xfsprogs-1.1.7 (20 March 2001) + - upgraded LVM to 0.9beta6 + - minor rpm spec file changes + +xfsprogs-1.1.6 (20 March 2001) + - fix sparc build failure - fcntl.h missing O_DIRECT + - added README.quota describing use of quota with XFS + +xfsprogs-1.1.5 (12 March 2001) + - upgraded LVM support to 0.9beta2 (IOP 10) + +xfsprogs-1.1.4 (10 March 2001) + - kernel now supports O_DIRECT - re-enable its use in xfs_mkfile + - BLKSETSIZE ioctl replaced by BLKBSZSET ioctl in libxfs + - libxfs_init extended so only mkfs and xfs_repair use BLKBSZSET + - NOTE: this version requires an XFS kernel from March 9 or later + +xfsprogs-1.1.3 (02 March 2001) + - minor Makefile-related cleanups + +xfsprogs-1.1.2 (10 February 2001) + - added libhandle routines to simplify dump/restore EA support + +xfsprogs-1.1.1 (30 January 2001) + - minor rpm and deb packaging work + +xfsprogs-1.1.0 (15 January 2001) + - rework xfs-cmds package into base, devel and dump packages + - completed Debian packaging + - late beta code + +xfs-cmds-1.0.7 (02 January 2001) + - added mkfs support for extracting LVM stripe unit/width + - libattr (*experimental* extended attributes interface) added + - removed xfs_fstab.5 man page (merged into mount.8) + - install xfs_repair into /sbin, not /usr/sbin + +xfs-cmds-1.0.6 (04 October 2000) + - reworked external log format to be IRIX compatible + - mkfs, repair, db, logprint now work with new format + - xfs_admin added for setting filesystem label + +xfs-cmds-1.0.5 (18 September 2000) + - minor bug fixes + - first beta release + +xfs-cmds-1.0.4 (18 August 2000) + - minor bug fixes + - xfs_growfs added + - xfs_info added + - late alpha code + +xfs-cmds-1.0.3 (16 August 2000) + - numerous bug fixes + - xfsdump and xfsrestore added + - xfsstats added + - fsck.xfs (symlink to /bin/true) added + - demise of sim library complete, mkfs and repair reworked + - no longer need to have an XFS kernel handy for building xfs-cmds + - xfs_copy compiles on Linux + - dump/restore README added + - late alpha code + +xfs-cmds-1.0.2 (27 July 2000) + - numerous bug fixes + - xfs_attr (extended attributes) command added + - fsr_xfs added (ported by jones@tacc.utexas.edu) + - LVM+XFS README added + - early alpha code + +xfs-cmds-1.0.1 (5 July 2000) + - numerous bug fixes + - reworked build environment + - begun work on user/kernel separation + - early alpha code + +xfs-cmds-1.0.0 (16 June 2000) + - initial release for USENIX CDs + - early alpha code + diff -rNu linux-2.4.7/cmd/xfsprogs/doc/COPYING linux-2.4-xfs/cmd/xfsprogs/doc/COPYING --- linux-2.4.7/cmd/xfsprogs/doc/COPYING Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/doc/COPYING Mon Jan 15 00:52:52 2001 @@ -0,0 +1,346 @@ +---------------------------------------------------------------------- + + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +---------------------------------------------------------------------- diff -rNu linux-2.4.7/cmd/xfsprogs/doc/CREDITS linux-2.4-xfs/cmd/xfsprogs/doc/CREDITS --- linux-2.4.7/cmd/xfsprogs/doc/CREDITS Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/doc/CREDITS Tue Jul 3 06:59:45 2001 @@ -0,0 +1,64 @@ + + This is a credits-file of people that have contributed to + the Linux/XFS project. It is sorted by name and formatted + to allow easy grepping and beautification by scripts (i.e. + it follows the same format Linus has used in the kernel). + The fields are: name (N), email (E), web-address (W), PGP + key ID and fingerprint (P), description (D), and snail-mail + address (S). + +---------- + +N: Jens Axboe +E: axboe@suse.de +D: Block/elevator/kiobuf hacking, IDE kiobuf support +S: Peter Bangs Vej 258, 2TH +S: 2500 Valby +S: Denmark + +N: Danny Cox +E: dcox@connex.com +D: ACL port to Linux +S: Danny Cox; Connex; 2970 Brandywine Ln; Suite 120; Atlanta GA 30341-5527 + +N: Thomas Graichen +E: tgr@spoiled.org +D: Original XFS FAQ maintainer +D: PowerPC and Alpha porting +S: Berlin, Germany + +N: Juergen Hasch +E: hasch@t-online.de +D: libacl fixes +S: Meisenstr. 23, 73066 Uhingen, Germany + +N: Bill Jones +E: jones@hpc.utexas.edu +D: fsr port to Linux +S: Austin, Texas, USA + +N: Jan Kara +E: jack@atrey.karlin.mff.cuni.cz +E: jack@suse.cz +D: Quota 3.01 user tools, allowing different forms of quota to coexist +D: Merging XFS support into quota user tools +W: http://atrey.karlin.mff.cuni.cz/~jack/ +S: Krosenska' 543 +S: 181 00 Praha 8 +S: Czech Republic + +N: Seth Mos +E: seth@arosa.nl +D: XFS FAQ ( http://oss.sgi.com/projects/xfs/faq.html ) maintainer +W: http://iserv.nl/ +S: Den Helder, The Netherlands + +N: Robert Stickel +E: rstickel@connex.com +D: libacl port to Linux +S: 2970 Brandywine Rd, Suite 120, Atlanta, GA 30431, USA + +N: John Trostel +E: jtrostel@connex.com +D: libacl extensions for Linux +S: 2970 Brandywine Rd, Suite 120, Atlanta, GA 30431, USA diff -rNu linux-2.4.7/cmd/xfsprogs/doc/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/doc/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/doc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/doc/CVS/Entries Thu Jul 5 11:44:26 2001 @@ -0,0 +1,9 @@ +/CHANGES/1.21/Tue Jul 3 04:33:45 2001/-ko/ +/COPYING/1.1/Mon Jan 15 06:52:52 2001/-ko/ +/CREDITS/1.11/Tue Jul 3 11:59:45 2001/-ko/ +/INSTALL/1.1/Mon Jan 15 06:52:52 2001/-ko/ +/Makefile/1.4/Tue Mar 20 01:57:36 2001/-ko/ +/PORTING/1.1/Mon Jan 15 06:52:52 2001/-ko/ +/README.LVM/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/README.quota/1.4/Fri May 4 01:15:24 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/doc/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/doc/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/doc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/doc/CVS/Repository Thu Jul 5 11:44:26 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/doc diff -rNu linux-2.4.7/cmd/xfsprogs/doc/CVS/Root linux-2.4-xfs/cmd/xfsprogs/doc/CVS/Root --- linux-2.4.7/cmd/xfsprogs/doc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/doc/CVS/Root Thu Jul 5 11:44:26 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/doc/INSTALL linux-2.4-xfs/cmd/xfsprogs/doc/INSTALL --- linux-2.4.7/cmd/xfsprogs/doc/INSTALL Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/doc/INSTALL Mon Jan 15 00:52:52 2001 @@ -0,0 +1,52 @@ +This document describes how to configure and build the open source XFS +commands and utilites ("xfsprogs") from source, and how to install and +run them. + +0. If you have the binary rpm, simply install it and skip to step 2 (below). + The rpm command to do this is: + # rpm -Uvh xfsprogs + + The Debian command to do this is: + # dpkg -i xfsprogs + or, if you have apt configured (don't need the binary package): + # apt-get install xfsprogs + +1. Configure, build and install the package + + The xfsprogs package uses autoconf/configure and expects a GNU build + environment (your platform must at least have both autoconf and gmake). + You will also need to have installed either the e2fsprogs-devel package + (on an RPM based system) or the uuid-dev package (on a Debian system) + as some of the commands make use of the UUID library provided by these. + + If you just want to spin an RPM and/or tar file, use the Makepkgs + script in the top level directory. This will configure and build + the package and leave binary and src RPMs in the build/rpm + directory. It will also leave a tar file in the build/tar + directory. + + # ./Makepkgs verbose + + If you want to build the package and install it manually, use the + following steps: + + # make configure (or run autoconf; ./configure) + # make + # su root + # make install + + Note that there are so many "install" variants out there that we + wrote our own script (see "install-sh" in the top level directory). + + If you wish to turn off debugging asserts in the command build and + turn on the optimizer then set the shell environment variables: + + OPTIMIZER=-O + DEBUG=-DNDEBUG + + before running make configure or Makepkgs. + +2. How to Contribute + + See the README file in this directory for details about how to + contribute to the XFS project. diff -rNu linux-2.4.7/cmd/xfsprogs/doc/Makefile linux-2.4-xfs/cmd/xfsprogs/doc/Makefile --- linux-2.4.7/cmd/xfsprogs/doc/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/doc/Makefile Mon Mar 19 19:57:36 2001 @@ -0,0 +1,53 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +README = README.LVM README.quota +LSRCFILES = INSTALL PORTING CHANGES COPYING CREDITS $(README) +LDIRT = *.gz + +default: $(CMDTARGET) CHANGES.gz + +include $(BUILDRULES) + +CHANGES.gz: + $(ZIP) --best -c < CHANGES > $@ + +install: default + $(INSTALL) -m 755 -d $(PKG_DOC_DIR) +ifneq ($(PKG_DISTRIBUTION), debian) + $(INSTALL) -m 644 COPYING $(PKG_DOC_DIR) +endif + $(INSTALL) -m 644 PORTING CHANGES.gz CREDITS $(README) $(PKG_DOC_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/xfsprogs/doc/PORTING linux-2.4-xfs/cmd/xfsprogs/doc/PORTING --- linux-2.4.7/cmd/xfsprogs/doc/PORTING Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/doc/PORTING Mon Jan 15 00:52:52 2001 @@ -0,0 +1,86 @@ + +1. unpack the source tarball and cd to the resulting dir + +2. # autoconf + this reads configure.in and generates the ./configure script + +3. # ./configure + this probes your system and then, for each "file" named + in the AC_OUTPUT() macro near the end of configure.in, + read "file".in and generate "file". Variables named @somevariable@ + will be substituted with literal values. + +4. step (3) produces several files. These files are generated by + configure from their respective .in file in the same directory. + You should have a read of these generated files and diff them + against their respective .in files to see what was substituted + by configure. + + src/include/builddefs + common definitions for the build environment. This is included + by all Makefiles, in conjunction with src/include/buildrules. + Note that most autoconf/configure build environments generate + Makefile (from Makefile.in) in every src dir. Instead, we + generate builddefs, and then include it in every Makefile. + + src/include/platform_defs.h + header containing conditional macros defining the C run-time + environment discovered by the configure script. + +5. read some or all of the GNU tool chain documentation + gmake Table Of Contents : + http://www.delorie.com/gnu/docs/make/make_toc.html + gmake Quick Reference section : + http://www.delorie.com/gnu/docs/make/make_120.html + Autoconf : + http://www.delorie.com/gnu/docs/autoconf/autoconf_toc.html + gcc/g++ : + http://www.delorie.com/gnu/docs/gcc/gcc_toc.html + +6. Makefiles and build environment + First have a look at some Makefiles + + example using SUBDIRS : xfsprogs/Makefile + example static library: xfsprogs/libxfs/Makefile + example command : xfsprogs/bmap/Makefile + + All Makefiles must define TOPDIR as the root of the project. This + allows other stuff to be found relative to $(TOPDIR). + + All Makefiles should have the following structure, which is + much like commondefs and commonrules in the IRIX build environment, e.g. + + # ---------------------------------------------------------------------- + # TOPDIR must point to the root of the project + # The builddefs file defines lots of things. Read it. + TOPDIR = .. + include $(TOPDIR)/include/builddefs + + # first rule should always be "default" + default : sometarget + commands to build targets, if necessary + + # $(BUILDRULES) is defined in builddefs and includes rules for + # descending subdirs, building targets and installation rules + include $(BUILDRULES) + + install : default + $(INSTALL) sometargets somewhere + # ---------------------------------------------------------------------- + +7. packaging + + # ./Makepkgs + this script generates all of the packages supported - each has a + subdirectory below xfsprogs/build where knowledge specific to + each package type is maintained. + + The script produces logs of each stage of the build (this info is + also echoed to the screen when the "verbose" option is provided): + + xfsprogs/Logs/configure - `autoconf; ./configure' output + xfsprogs/Logs/default - `make default' output + xfsprogs/Logs/dist - `make build dist' output + + On successful completion, the script echoes the names of packages + successfully generated. diff -rNu linux-2.4.7/cmd/xfsprogs/doc/README.LVM linux-2.4-xfs/cmd/xfsprogs/doc/README.LVM --- linux-2.4.7/cmd/xfsprogs/doc/README.LVM Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/doc/README.LVM Sun Jan 14 23:36:03 2001 @@ -0,0 +1,77 @@ +XFS on LVM +__________ + +PREFACE + +This is a quick reference to setting XFS up on LVM. For more information +please see the LVM HOWTO at: + + http://www.linuxdoc.org/HOWTO/LVM-HOWTO.html + +PREREQUISITES + +You need a kernel with LVM support either built in or as a module. +This document assumes lvm as a module. + +SETTING UP LVM + +>>> Load module + + [root@crash /sbin]# modprobe lvm-mod + +>>> Set partition type to 0x8e for partitions you wish to use with LVM + + [root@crash /sbin]# fdisk /dev/sda1 + Command (m for help): t + Partition number (1-4): 1 + Hex code (type L to list codes): 8e + Changed system type of partition 1 to 8e (Unknown) + + Command (m for help): w + The partition table has been altered! + +>>> Write PV superblock on physical volumes + + [root@crash /root]# pvcreate /dev/sda1 /dev/sdb1 /dev/sdc1 /dev/sdd1 + pvcreate -- physical volume "/dev/sda1" successfully created + pvcreate -- physical volume "/dev/sdb1" successfully created + pvcreate -- physical volume "/dev/sdc1" successfully created + pvcreate -- physical volume "/dev/sdd1" successfully created + +>>> Create a volume group consisting of the PVs we just set up + +[root@crash /root]# vgcreate vg00 /dev/sda1 /dev/sdb1 /dev/sdc1 /dev/sdd1 + vgcreate -- INFO: using default physical extent size 4 MB + vgcreate -- INFO: maximum logical volume size is 255.99 Gigabyte + vgcreate -- doing automatic backup of volume group "vg00" + vgcreate -- volume group "vg00" successfully created and activated + +>>> Create a logical volume - striped across 4 PVs, 64 KB chunk size, 20 GB + +[root@crash /root]# lvcreate -i 4 -I 64 -L 20G -n lv00 vg00 + lvcreate -- rounding 20971520 KB to stripe boundary size 20975616 KB / 5121 PE + lvcreate -- doing automatic backup of "vg00" + lvcreate -- logical volume "/dev/vg00/lv00" successfully created + +>>> Build a filesystem on the LV + +[root@crash /root]# mkfs -t xfs /dev/vg00/lv00 + meta-data=/dev/vg00/lv00 isize=256 agcount=20, agsize=262144 blks + data = bsize=4096 blocks=5242879, imaxpct=25 + = sunit=0 swidth=0 blks, unwritten=1 + naming =version 2 bsize=4096 + log =internal log bsize=4096 blocks=1200 + realtime =none extsz=65536 blocks=0, rtextents=0 + +[root@crash /root]# mount -t xfs /dev/vg00/lv00 /xfs + +>>> Go nuts + + +After a reboot you will need to reactivate the VGs/LVs: + + modprobe lvm-mod + vgchange -a y + +These commands could be added to a startup script. + diff -rNu linux-2.4.7/cmd/xfsprogs/doc/README.quota linux-2.4-xfs/cmd/xfsprogs/doc/README.quota --- linux-2.4.7/cmd/xfsprogs/doc/README.quota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/doc/README.quota Thu May 3 20:15:24 2001 @@ -0,0 +1,299 @@ +QUOTA on XFS +____________ + +PREFACE + +For an additional source of information on Linux quota, you can refer to +the (currently out-of-date) Linux Quota HOWTO at: + + http://www.linuxdoc.org/HOWTO/mini/Quota.html + +If you are looking to get started quickly, you can skip down to the +section GETTING STARTED below. It is recommended that you at least +read the "Administering the XFS Quota System" section below, however. + + +DESCRIPTION + +In most computing environments, disk space is not infinite. The quota +subsystem provides a mechanism to control usage of disk space. Quotas +can be set for each individual user on any/all of the local filesystems. +The quotas subsystem warns users when they exceed their allotted limit, +but allows some extra space for current work (hard limit/soft limit). +In addition, XFS filesystems with limit enforcement turned off can be +used as an effective disk usage accounting system. + + Users' Views of Disk Quotas + To most users, disk quotas are either of no concern or a fact of life + that cannot be avoided. There are two possible quotas that can be + imposed - a limit can be set on the amount of space a user can occupy, + and there may be a limit on the number of files (inodes) he can own. + + The quota(1) command provides information on the quotas that have been + set by the system administrators and current usage. + + There are four numbers for each limit: current usage, soft limit + (quota), hard limit, and time limit. The soft limit is the number of 1K + blocks (or files) that the user is expected to remain below. The hard + limit cannot be exceeded. If a user's usage reaches the hard limit, + further requests for space (or attempts to create a file) fail with an + EDQUOT/ENOSPC error. + + When a user exceeds the soft limit, the timer is enabled. Any time the + quota drops below the soft limits, the timer is disabled. If the timer + pops, the particular limit that has been exceeded is treated as if the + hard limit has been reached, and no more resources are allocated to the + user. The only way to reset this condition, short of turning off limit + enforcement or increasing the limit, is to reduce usage below quota. + Only the superuser can set the time limits and this is done on a per + filesystem basis. + + Surviving When the Quota Limit Is Reached + In most cases, the only way for a user to recover from over-quota + conditions is to abort whatever activity is in progress on the filesystem + that has reached its limit, remove sufficient files to bring the limit + back below quota, and retry the failed program. + + However, if a user is in the editor and a write fails because of an over + quota situation, that is not a suitable course of action. It is most + likely that initially attempting to write the file has truncated its + previous contents, so if the editor is aborted without correctly writing + the file, not only are the recent changes lost, but possibly much, or + even all, of the contents that previously existed. + + There are several possible safe exits for a user caught in this + situation. He can use the editor ! shell escape command to examine his + file space and remove surplus files. Alternatively, using csh(1), he can + suspend the editor, remove some files, then resume it. A third + possibility is to write the file to some other filesystem (perhaps to a + file on /tmp) where the user's quota has not been exceeded. Then after + rectifying the quota situation, the file can be moved back to the + filesystem it belongs on. + + +ADMINISTRATION + +Quotas is a configurable subsystem that is optionally built into the kernel. +A decision as to which filesystems need to have quotas enabled needs to be +made. Usually, only filesystems that house users' home directories or other +user files need to be subjected to the quota system. It is recommended that +the filesystem housing /tmp should be free of quotas. + +XFS and the Linux VFS quota systems (e.g. as used on ext2 filesystems) share +many characteristics. We begin with an overview of how the Linux VFS quota +system is administered. + + Administering the Linux VFS Quota System + On most filesystems, quota file(s) should be created in the root of + those filesystems that are to have quotas. These files should be of + size zero and should be readable and writable only by root. After + deciding on the filesystems that will have quotas, the administrator + then establishes quotas for individual users. + The edquota(8) and/or setquota(8) commands are used to actually set + the limits desired upon each user. Where a number of users are to be + given the same quotas (a common occurrence) the -p option to edquota + allows this to be easily accomplished. Unless explicitly given a quota, + users have no limits set on the amount of disk they can use or the number + of files they can create. + + Once the quotas are set and ready to operate, the system must be informed + to enforce quotas on the desired filesystems. This is accomplished with + the quotaon(8) command. For quotas to be accurate, it should be enabled + on a local filesystem immediately after the filesystem has been mounted. + quotaon either enables quotas for a particular filesystem or, with the -a + option, enables quotas for each filesystem indicated in /etc/fstab as + using quotas. See mount(8) for details. When the quota package is + installed, + + /usr/etc/quotaon -a + + can be automatically executed during system boot up time by the startup + scripts. + + When quotas need to be disabled, the quotaoff(8) command is used. + However, if the filesystem is about to be dismounted, the umount(8) + command disables quotas immediately before the filesystem is unmounted. + This is actually an effect of the umount(2) system call, and it + guarantees that the quota system is not disabled if the umount would fail + because the filesystem is not idle. + + Periodically (certainly after each reboot and when quotas are first + enabled for a filesystem), the records retained in the quota file should + be checked for consistency with the actual number of blocks and files + allocated to the user. The quotacheck(8) command is used to accomplish + this. It is not necessary to unmount the filesystem or disable the + quota system to run this command, though on active filesystems inaccurate + results may occur. This does no real harm in most cases; another run of + quotacheck when the filesystem is idle corrects any inaccuracy. The + startup scripts can be configured to run quotacheck automatically. + + The superuser can use the quota command to examine the usage and quotas + of any user, and the repquota(8) command can be used to check the usages + and limits for all users on a filesystem. + + Administering the XFS Quota System + The XFS quota system is different from that of the Linux VFS in many ways. + + o There is no need for quota file(s) in the root of the XFS filesystem. + + o XFS distinguishes between quota accounting and limit enforcement. + Quota accounting must be turned on at the time of mounting the XFS + filesystem. However, it is possible to turn on/off limit + enforcement any time quota accounting is turned on. The "quota" + option in mount(8) turns on both (user) quota accounting and + enforcement. The "uqnoenforce" option must be used to turn on + user accounting with limit enforcement disabled. quotaon(8) + contains some examples of frequently used procedures. + + o Turning on quotas on the root filesystem is slightly different from + the above. quotaon(8) must be used on the root XFS filesystem + first; quotas will be turned on the next time the system is + rebooted. It is useful to use repquota(8) with the -v option to + monitor the effect of quotaon/off at various stages. + + o quotacheck(8) has no effect on XFS filesystems. The first time + quota accounting is turned on, XFS does an automatic quotacheck + internally; afterwards, the quota system will always be completely + consistent until quotas are manually turned off. + + o repquota(8) with the -v option can be used to monitor the status of + the quota system of an XFS filesystem. This can be used to see if + quotas are turned on, given an XFS filesystem. It can also be used + to monitor the space occupied by the quota system itself. + + o Refer to the xfsdump(8), xfsdq(8), and xfsrq(8) man pages, from the + xfsdump package, which describes a mechanism built into xfsdump that + allows quota limit information to be backed up and easily restored. + + o edquota(8) and setquota(8) cannot be used to set quota limits before + turning on quotas on the filesystem concerned. + + o XFS filesystems keep quota accounting on the superuser, and quota -v + will display the superuser's usage information. However, limits are + never enforced on the superuser. + + o XFS filesystems keep quota accounting whether the user has quota + limits or not. + + +IMPLEMENTATION NOTES + + On filesystems using Linux VFS quota, disk quota usage information is + stored in a file on the filesystem that the quotas are to be applied to. + Conventionally, this file is called quotas, and resides at the root of + the filesystem. + + The system is informed of the existence of the quota file by the quotactl + system call. It then reads the quota entries for any open files owned by + users. Each subsequent open of a file in the filesystem is accompanied + by a pairing with its quota information. + + Each time a block is accessed or released and each time an inode is + allocated or freed, the quota system gets told about it and, in the case + of allocations, gets the opportunity to deny the allocation. + + Note that the XFS quota system implementation is radically different + to the Linux VFS described above. XFS considers quota information as + filesystem metadata and uses journaling to provide a higher level + guarantee of consistency. + + +GETTING STARTED + + To use quota under XFS you will need the following: + o An XFS aware kernel; + o Quota must be enabled at the time the kernel is built + (CONFIG_QUOTA, at the start of the Filesystems menu); + o XFS quota must be enabled at the time XFS is built + (CONFIG_XFS_QUOTA, below XFS in the Filesystems menu); + o Userspace quota tools which are aware of XFS quota. + + User tools which support XFS can be downloaded from the Linux + quota project at: + http://sourceforge.net/projects/linuxquota/ + The quota tools from version 3.01-pre2 onward have full support + for XFS. They can be downloaded via cvs or as a source tarball. + + Building the user tools from source: + # autoconf + # ./configure --prefix=/usr --mandir=/usr/share/man + # make + # make install + + +EXAMPLES + +>>> Enabling quota enforcement on a non-root XFS filesystem + +[root@troppo]# echo /dev/hdb10 /mnt/xqm xfs rw,usrquota 0 0 >>/etc/fstab +[root@troppo]# mount /mnt/xqm + +>>> Set limits for a user (can also use edquota, interactively) + +[root@troppo]# setquota nathans 600 800 15 20 /mnt/xqm + +>>> Report current user quota + +[root@troppo]# repquota /mnt/xqm +*** Report for user quotas on device /dev/hdb10 +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +User used soft hard grace used soft hard grace +---------------------------------------------------------------------- +root -- 1552 0 0 11 0 0 +nathans -- 440 600 800 8 15 20 +pcpqa -- 880 0 0 1 0 0 + +>>> Push user over quota (see "File limits" above for user "nathans") + +[nathans@troppo]$ sh +sh-2.04$ for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 +> do +> touch /mnt/xqm/blat/file${i} +> done +touch: creating `/mnt/xqm/blat/file12': Disk quota exceeded +touch: creating `/mnt/xqm/blat/file13': Disk quota exceeded +sh-2.04$ ^D + +>>> Report current user quota again + +[root@troppo]# repquota /mnt/xqm +*** Report for user quotas on device /dev/hdb10 +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +User used soft hard grace used soft hard grace +---------------------------------------------------------------------- +root -- 1560 0 0 11 0 0 +nathans -+ 440 600 800 20 15 20 7 days +pcpqa -- 880 0 0 1 0 0 + +>>> From the users point of view: + +[nathans@troppo]$ quota +Disk quotas for user nathans (uid 16302): + Filesystem blocks quota limit grace files quota limit grace + /dev/hdb10 440 600 800 20* 15 20 7 days + +>>> Run warnquota(8) via cron(8) to periodically inform users of violations. + + +CAVEATS + +The XFS allocation mechanism will always reserve the maximum amount of +space required before proceeding with a space allocation. If insufficient +space for this reservation is available, due to the users block quota limit +being reached for example, this may result in the allocation failing even +though there is sufficient space. Quota enforcement can thus sometimes +happen in situations where the user is under quota and the end result of +some operation would still have left the user under quota had the operation +been allowed to run its course. This is an unavoidable side of affect of +the way XFS operates, so should be kept in mind when assigning users block +limits. This additional overhead is typically in the range of tens of +filesystem-sized blocks. + +On IRIX, XFS supports project quota. This is not (ever) likely to be +supported on Linux/XFS, as the concept of a project is specific to IRIX. +A filesystem that has used user quota on IRIX, however, can be migrated +to Linux, and vice-versa, as the ondisk format is shared between both +versions of XFS (and Linux/XFS is "endian clean"). + diff -rNu linux-2.4.7/cmd/xfsprogs/freeze/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/freeze/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/freeze/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/freeze/CVS/Entries Thu Jul 5 11:44:26 2001 @@ -0,0 +1,3 @@ +/Makefile/1.1/Thu May 17 02:58:46 2001/-ko/ +/xfs_freeze.c/1.2/Thu May 17 03:23:53 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/freeze/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/freeze/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/freeze/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/freeze/CVS/Repository Thu Jul 5 11:44:26 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/freeze diff -rNu linux-2.4.7/cmd/xfsprogs/freeze/CVS/Root linux-2.4-xfs/cmd/xfsprogs/freeze/CVS/Root --- linux-2.4.7/cmd/xfsprogs/freeze/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/freeze/CVS/Root Thu Jul 5 11:44:26 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/freeze/Makefile linux-2.4-xfs/cmd/xfsprogs/freeze/Makefile --- linux-2.4.7/cmd/xfsprogs/freeze/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/freeze/Makefile Wed May 16 21:58:46 2001 @@ -0,0 +1,47 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = xfs_freeze + +CFILES = xfs_freeze.c + +default: $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_BIN_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/xfsprogs/freeze/xfs_freeze.c linux-2.4-xfs/cmd/xfsprogs/freeze/xfs_freeze.c --- linux-2.4.7/cmd/xfsprogs/freeze/xfs_freeze.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/freeze/xfs_freeze.c Wed May 16 22:23:53 2001 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include + +char *progname; + +static void +usage(void) +{ + fprintf(stderr, +"Usage: %s [options] mountpoint\n\n\ +Options:\n\ + -f freeze filesystem access\n\ + -u unfreeze filesystem access\n", + progname); + exit(2); +} + +int +main(int argc, char **argv) +{ + int c; /* current option character */ + int ffd; /* mount point file descriptor */ + int fflag, uflag; + int level; + struct statfs buf; + + fflag = uflag = 0; + progname = basename(argv[0]); + while ((c = getopt(argc, argv, "fu")) != EOF) { + switch (c) { + case 'f': + fflag = 1; + break; + case 'u': + uflag = 1; + break; + case '?': + default: + usage(); + } + } + if (argc - optind != 1) + usage(); + if ((fflag + uflag) != 1) + usage(); + + ffd = open(argv[optind], O_RDONLY); + if (ffd < 0) { + perror(argv[optind]); + return 1; + } + fstatfs(ffd, &buf); + if (buf.f_type != XFS_SUPER_MAGIC) { + fprintf(stderr, + "%s: specified file is not on an XFS filesystem\n", + progname); + exit(1); + } + + if (fflag) { + level = 1; + if (ioctl(ffd, XFS_IOC_FREEZE, &level) < 0) { + fprintf(stderr, "%s: cannot freeze filesystem" + " mounted at %s: %s\n", + progname, argv[optind], strerror(errno)); + exit(1); + } + } + + if (uflag) { + if (ioctl(ffd, XFS_IOC_THAW, &level) < 0) { + fprintf(stderr, "%s: cannot unfreeze filesystem" + " mounted at %s: %s\n", + progname, argv[optind], strerror(errno)); + exit(1); + } + } + + close(ffd); + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/fsck/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/fsck/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/fsck/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/fsck/CVS/Entries Thu Jul 5 11:44:26 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Mon Jan 15 06:52:52 2001/-ko/ +/xfs_fsck.c/1.1/Mon Jan 15 05:36:03 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/fsck/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/fsck/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/fsck/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/fsck/CVS/Repository Thu Jul 5 11:44:26 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/fsck diff -rNu linux-2.4.7/cmd/xfsprogs/fsck/CVS/Root linux-2.4-xfs/cmd/xfsprogs/fsck/CVS/Root --- linux-2.4.7/cmd/xfsprogs/fsck/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/fsck/CVS/Root Thu Jul 5 11:44:26 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/fsck/Makefile linux-2.4-xfs/cmd/xfsprogs/fsck/Makefile --- linux-2.4.7/cmd/xfsprogs/fsck/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/fsck/Makefile Mon Jan 15 00:52:52 2001 @@ -0,0 +1,47 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = fsck.xfs +CFILES = xfs_fsck.c +LCFLAGS = -s -O3 + +default: $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_SBIN_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/xfsprogs/fsck/xfs_fsck.c linux-2.4-xfs/cmd/xfsprogs/fsck/xfs_fsck.c --- linux-2.4.7/cmd/xfsprogs/fsck/xfs_fsck.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/fsck/xfs_fsck.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html */ +/* Unfortunately, we need to be a little more portable. ;^) */ +/* This used to be a symlink to /bin/true but that gives a wierd */ +/* dependency problem in a certain package manager. */ + +int +main(int argc, char **argv) +{ + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/growfs/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/growfs/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/growfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/growfs/CVS/Entries Thu Jul 5 11:44:26 2001 @@ -0,0 +1,4 @@ +/Makefile/1.2/Mon Jan 15 06:52:52 2001/-ko/ +/xfs_growfs.c/1.4/Wed May 9 06:56:06 2001/-ko/ +/xfs_info.sh/1.1/Mon Jan 15 05:36:03 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/growfs/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/growfs/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/growfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/growfs/CVS/Repository Thu Jul 5 11:44:26 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/growfs diff -rNu linux-2.4.7/cmd/xfsprogs/growfs/CVS/Root linux-2.4-xfs/cmd/xfsprogs/growfs/CVS/Root --- linux-2.4.7/cmd/xfsprogs/growfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/growfs/CVS/Root Thu Jul 5 11:44:26 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/growfs/Makefile linux-2.4-xfs/cmd/xfsprogs/growfs/Makefile --- linux-2.4.7/cmd/xfsprogs/growfs/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/growfs/Makefile Mon Jan 15 00:52:52 2001 @@ -0,0 +1,51 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = xfs_growfs + +CFILES = xfs_growfs.c +LLDLIBS = $(LIBXFS) $(LIBUUID) +LLDFLAGS = -L$(TOPDIR)/libxfs +LSRCFILES = xfs_info.sh + +default: $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_BIN_DIR) + $(INSTALL) -m 755 xfs_info.sh $(PKG_BIN_DIR)/xfs_info +install-dev: diff -rNu linux-2.4.7/cmd/xfsprogs/growfs/xfs_growfs.c linux-2.4-xfs/cmd/xfsprogs/growfs/xfs_growfs.c --- linux-2.4.7/cmd/xfsprogs/growfs/xfs_growfs.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/growfs/xfs_growfs.c Wed May 9 01:56:06 2001 @@ -0,0 +1,458 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include + +static char *fname; /* mount point name */ +static char *datadev; /* data device name */ +static char *logdev; /* log device name */ +static char *rtdev; /* RT device name */ + +static void +usage(void) +{ + fprintf(stderr, +"Usage: %s [options] mountpoint\n\n\ +Options:\n\ + -d grow data/metadata section\n\ + -l grow log section\n\ + -r grow realtime section\n\ + -n don't change anything, just show geometry\n\ + -i convert log from external to internal format\n\ + -t alternate location for mount table (/etc/mtab)\n\ + -x convert log from internal to external format\n\ + -D size grow data/metadata section to size blks\n\ + -L size grow/shrink log section to size blks\n\ + -R size grow realtime section to size blks\n\ + -e size set realtime extent size to size blks\n\ + -m imaxpct set inode max percent to imaxpct\n\ + -V print version information\n", + progname); + exit(2); +} + +void +report_info( + xfs_fsop_geom_t geo, + char *mntpoint, + int unwritten, + int dirversion, + int isint) +{ + printf("meta-data=%-22s isize=%-6d agcount=%d, agsize=%d blks\n" + "data =%-22s bsize=%-6d blocks=%lld, imaxpct=%d\n" + " =%-22s sunit=%-6d swidth=%d blks, unwritten=%d\n" + "naming =version %-14d bsize=%-6d\n" + "log =%-22s bsize=%-6d blocks=%d\n" + "realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n", + mntpoint, geo.inodesize, geo.agcount, geo.agblocks, + "", geo.blocksize, (long long)geo.datablocks, geo.imaxpct, + "", geo.sunit, geo.swidth, unwritten, + dirversion, geo.dirblocksize, + isint ? "internal" : "external", geo.blocksize, geo.logblocks, + geo.rtblocks ? "external" : "none", + geo.rtextsize * geo.blocksize, + (long long)geo.rtblocks, (long long)geo.rtextents); +} + +void +explore_mtab(char *mtab, char *mntpoint) +{ + struct mntent *mnt; + struct stat64 statuser; + struct stat64 statmtab; + FILE *mtp; + char *rtend; + char *logend; + + if ((mtp = setmntent(mtab, "r")) == NULL) { + fprintf(stderr, "%s: cannot access mount list %s: %s\n", + progname, MOUNTED, strerror(errno)); + exit(1); + } + if (stat64(mntpoint, &statuser) < 0) { + fprintf(stderr, "%s: cannot access mount point %s: %s\n", + progname, mntpoint, strerror(errno)); + exit(1); + } + + while ((mnt = getmntent(mtp)) != NULL) { + if (stat64(mnt->mnt_dir, &statmtab) < 0) { + fprintf(stderr, "%s: ignoring entry %s in %s: %s\n", + progname, mnt->mnt_dir, mtab, strerror(errno)); + continue; + } + if (statuser.st_ino != statmtab.st_ino || + statuser.st_dev != statmtab.st_dev) + continue; + else if (strcmp(mnt->mnt_type, "xfs") != 0) { + fprintf(stderr, "%s: %s is not an XFS filesystem\n", + progname, mntpoint); + exit(1); + } + break; /* we've found it */ + } + + if (mnt == NULL) { + fprintf(stderr, + "%s: %s is not a filesystem mount point, according to %s\n", + progname, mntpoint, MOUNTED); + exit(1); + } + + /* find the data, log (logdev=), and realtime (rtdev=) devices */ + rtend = logend = NULL; + fname = mnt->mnt_dir; + datadev = mnt->mnt_fsname; + if ((logdev = hasmntopt(mnt, "logdev="))) { + logdev += 7; + logend = strtok(logdev, " "); + } + if ((rtdev = hasmntopt(mnt, "rtdev="))) { + rtdev += 6; + rtend = strtok(rtdev, " "); + } + + /* Do this only after we've finished processing mount options */ + if (logdev && logend != logdev) + *logend = '\0'; /* terminate end of log device name */ + if (rtdev && rtend != rtdev) + *rtend = '\0'; /* terminate end of rt device name */ + + endmntent(mtp); +} + +int +main(int argc, char **argv) +{ + int aflag; /* fake flag, do all pieces */ + int c; /* current option character */ + long long ddsize; /* device size in 512-byte blocks */ + int dflag; /* -d flag */ + int dirversion; /* directory version number */ + long long dlsize; /* device size in 512-byte blocks */ + long long drsize; /* device size in 512-byte blocks */ + long long dsize; /* new data size in fs blocks */ + int error; /* we have hit an error */ + long esize; /* new rt extent size */ + int ffd; /* mount point file descriptor */ + xfs_fsop_geom_t geo; /* current fs geometry */ + int iflag; /* -i flag */ + int isint; /* log is currently internal */ + int lflag; /* -l flag */ + long long lsize; /* new log size in fs blocks */ + int maxpct; /* -m flag value */ + int mflag; /* -m flag */ + char *mtab; /* mount table file (/etc/mtab) */ + int nflag; /* -n flag */ + xfs_fsop_geom_t ngeo; /* new fs geometry */ + int rflag; /* -r flag */ + long long rsize; /* new rt size in fs blocks */ + int unwritten; /* unwritten extent flag */ + int xflag; /* -x flag */ + libxfs_init_t xi; /* libxfs structure */ + + mtab = MOUNTED; + progname = basename(argv[0]); + aflag = dflag = iflag = lflag = mflag = nflag = rflag = xflag = 0; + maxpct = esize = 0; + dsize = lsize = rsize = 0LL; + while ((c = getopt(argc, argv, "dD:e:ilL:m:np:rR:t:xV")) != EOF) { + switch (c) { + case 'D': + dsize = atoll(optarg); + /* fall through */ + case 'd': + dflag = 1; + break; + case 'e': + esize = atol(optarg); + rflag = 1; + break; + case 'i': + lflag = iflag = 1; + break; + case 'L': + lsize = atoll(optarg); + /* fall through */ + case 'l': + lflag = 1; + break; + case 'm': + mflag = 1; + maxpct = atoi(optarg); + break; + case 'n': + nflag = 1; + break; + case 'p': + progname = optarg; + break; + case 'R': + rsize = atoll(optarg); + /* fall through */ + case 'r': + rflag = 1; + break; + case 't': + mtab = optarg; + break; + case 'x': + lflag = xflag = 1; + break; + case 'V': + printf("%s version %s\n", progname, VERSION); + break; + case '?': + default: + usage(); + } + } + if (argc - optind != 1) + usage(); + if (iflag && xflag) + usage(); + if (dflag + lflag + rflag == 0) + aflag = 1; + + explore_mtab(mtab, argv[optind]); + + ffd = open(fname, O_RDONLY); + if (ffd < 0) { + perror(fname); + return 1; + } + + /* get the current filesystem size & geometry */ + if (ioctl(ffd, XFS_IOC_FSGEOMETRY, &geo) < 0) { + fprintf(stderr, "%s: cannot determine geometry of filesystem" + " mounted at %s: %s\n", + progname, fname, strerror(errno)); + exit(1); + } + isint = geo.logstart > 0; + unwritten = geo.flags & XFS_FSOP_GEOM_FLAGS_EXTFLG ? 1 : 0; + dirversion = geo.flags & XFS_FSOP_GEOM_FLAGS_DIRV2 ? 2 : 1; + + if (nflag) { + report_info(geo, fname, unwritten, dirversion, isint); + exit(0); + } + + /* + * Need root access from here on (using raw devices)... + */ + + bzero(&xi, sizeof(xi)); + xi.dname = datadev; + xi.logname = logdev; + xi.rtname = rtdev; + xi.notvolok = 1; + xi.isreadonly = LIBXFS_ISREADONLY; + + if (!libxfs_init(&xi)) + usage(); + + /* check we got the info for all the sections we are trying to modify */ + if (!xi.ddev) { + fprintf(stderr, "%s: failed to access data device for %s\n", + progname, fname); + exit(1); + } + if (lflag && !isint && !xi.logdev) { + fprintf(stderr, "%s: failed to access external log for %s\n", + progname, fname); + exit(1); + } + if (rflag && !xi.rtdev) { + fprintf(stderr, "%s: failed to access realtime device for %s\n", + progname, fname); + exit(1); + } + + report_info(geo, fname, unwritten, dirversion, isint); + + ddsize = xi.dsize; + dlsize = ( xi.logBBsize? xi.logBBsize : + geo.logblocks * (geo.blocksize / BBSIZE) ); + drsize = xi.rtsize; + + error = 0; + if (dflag | aflag) { + xfs_growfs_data_t in; + + if (!mflag) + maxpct = geo.imaxpct; + if (!dsize) + dsize = ddsize / (geo.blocksize / BBSIZE); + else if (dsize > ddsize / (geo.blocksize / BBSIZE)) { + fprintf(stderr, + "data size %lld too large, maximum is %lld\n", + (long long)dsize, + (long long)(ddsize/(geo.blocksize/BBSIZE))); + error = 1; + } + if (!error && dsize < geo.datablocks) { + fprintf(stderr, "data size %lld too small," + " old size is %lld\n", + (long long)dsize, (long long)geo.datablocks); + error = 1; + } else if (!error && + dsize == geo.datablocks && maxpct == geo.imaxpct) { + if (dflag) + fprintf(stderr, + "data size unchanged, skipping\n"); + if (mflag) + fprintf(stderr, + "inode max pct unchanged, skipping\n"); + } else if (!error && !nflag) { + in.newblocks = (__u64)dsize; + in.imaxpct = (__u32)maxpct; + if (ioctl(ffd, XFS_IOC_FSGROWFSDATA, &in) < 0) { + if (errno == EWOULDBLOCK) + fprintf(stderr, + "%s: growfs operation in progress already\n", + progname); + else + fprintf(stderr, + "%s: ioctl failed - XFS_IOC_FSGROWFSDATA: %s\n", + progname, strerror(errno)); + error = 1; + } + } + } + + if (!error && (rflag | aflag)) { + xfs_growfs_rt_t in; + + if (!esize) + esize = (__u32)geo.rtextsize; + if (!rsize) + rsize = drsize / (geo.blocksize / BBSIZE); + else if (rsize > drsize / (geo.blocksize / BBSIZE)) { + fprintf(stderr, + "realtime size %lld too large, maximum is %lld\n", + rsize, drsize / (geo.blocksize / BBSIZE)); + error = 1; + } + if (!error && rsize < geo.rtblocks) { + fprintf(stderr, + "realtime size %lld too small, old size is %lld\n", + (long long)rsize, (long long)geo.rtblocks); + error = 1; + } else if (!error && rsize == geo.rtblocks) { + if (rflag) + fprintf(stderr, + "realtime size unchanged, skipping\n"); + } else if (!error && !nflag) { + in.newblocks = (__u64)rsize; + in.extsize = (__u32)esize; + if (ioctl(ffd, XFS_IOC_FSGROWFSRT, &in) < 0) { + if (errno == EWOULDBLOCK) + fprintf(stderr, + "%s: growfs operation in progress already\n", + progname); + else if (errno == ENOSYS) + fprintf(stderr, + "%s: realtime growth not implemented\n", + progname); + else + fprintf(stderr, + "%s: ioctl failed - XFS_IOC_FSGROWFSRT: %s\n", + progname, strerror(errno)); + error = 1; + } + } + } + + if (!error && (lflag | aflag)) { + xfs_growfs_log_t in; + + if (!lsize) + lsize = dlsize / (geo.blocksize / BBSIZE); + if (iflag) + in.isint = 1; + else if (xflag) + in.isint = 0; + else + in.isint = xi.logBBsize == 0; + if (lsize == geo.logblocks && (in.isint == isint)) { + if (lflag) + fprintf(stderr, + "log size unchanged, skipping\n"); + } else if (!nflag) { + in.newblocks = (__u32)lsize; + if (ioctl(ffd, XFS_IOC_FSGROWFSLOG, &in) < 0) { + if (errno == EWOULDBLOCK) + fprintf(stderr, + "%s: growfs operation in progress already\n", + progname); + else if (errno == ENOSYS) + fprintf(stderr, + "%s: log growth not supported yet\n", progname); + else + fprintf(stderr, + "%s: ioctl failed - XFS_IOC_FSGROWFSLOG: %s\n", + progname, strerror(errno)); + error = 1; + } + } + } + + if (ioctl(ffd, XFS_IOC_FSGEOMETRY, &ngeo) < 0) { + fprintf(stderr, "%s: ioctl failed - XFS_IOC_FSGEOMETRY: %s\n", + progname, strerror(errno)); + exit(1); + } + if (geo.datablocks != ngeo.datablocks) + printf("data blocks changed from %lld to %lld\n", + (long long)geo.datablocks, (long long)ngeo.datablocks); + if (geo.imaxpct != ngeo.imaxpct) + printf("inode max percent changed from %d to %d\n", + geo.imaxpct, ngeo.imaxpct); + if (geo.logblocks != ngeo.logblocks) + printf("log blocks changed from %d to %d\n", + geo.logblocks, ngeo.logblocks); + if ((geo.logstart == 0) != (ngeo.logstart == 0)) + printf("log changed from %s to %s\n", + geo.logstart ? "internal" : "external", + ngeo.logstart ? "internal" : "external"); + if (geo.rtblocks != ngeo.rtblocks) + printf("realtime blocks changed from %lld to %lld\n", + (long long)geo.rtblocks, (long long)ngeo.rtblocks); + if (geo.rtextsize != ngeo.rtextsize) + printf("realtime extent size changed from %d to %d\n", + geo.rtextsize, ngeo.rtextsize); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfsprogs/growfs/xfs_info.sh linux-2.4-xfs/cmd/xfsprogs/growfs/xfs_info.sh --- linux-2.4.7/cmd/xfsprogs/growfs/xfs_info.sh Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/growfs/xfs_info.sh Sun Jan 14 23:36:03 2001 @@ -0,0 +1,56 @@ +#!/bin/sh -f +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +OPTS="" +USAGE="Usage: xfs_info [-t mtab] mountpoint" + +while getopts "t:" c +do + case $c in + t) OPTS="-t $OPTARG" ;; + *) echo $USAGE 1>&2 + exit 2 + ;; + esac +done +set -- extra $@ +shift $OPTIND +case $# in + 1) xfs_growfs -p xfs_info -n $OPTS $1 + status=$? + ;; + *) echo $USAGE 1>&2 + exit 2 + ;; +esac +exit $status diff -rNu linux-2.4.7/cmd/xfsprogs/include/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/include/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/include/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/CVS/Entries Thu Jul 5 11:44:34 2001 @@ -0,0 +1,60 @@ +/Makefile/1.4/Mon May 7 02:46:00 2001/-ko/ +/arch.h/1.2/Wed May 9 06:56:06 2001/-ko/ +/builddefs.in/1.5/Wed May 9 06:56:06 2001/-ko/ +/buildrules/1.2/Mon Jan 15 06:52:52 2001/-ko/ +/handle.h/1.2/Fri Feb 9 07:45:14 2001/-ko/ +/jdm.h/1.2/Fri Feb 9 07:45:14 2001/-ko/ +/liblvm.h/1.3/Tue Mar 20 20:10:08 2001/-ko/ +/libxfs.h/1.3/Wed May 9 06:56:06 2001/-ko/ +/lvm.h/1.3/Tue Mar 20 20:10:08 2001/-ko/ +/lvm_config.h/1.2/Tue Mar 20 20:10:08 2001/-ko/ +/lvm_log.h/1.2/Tue Mar 20 20:10:08 2001/-ko/ +/lvm_user.h/1.3/Tue Mar 20 20:10:08 2001/-ko/ +/md-int.h/1.1/Tue Mar 27 04:24:31 2001/-ko/ +/platform_defs.h.in/1.5/Wed May 9 06:56:06 2001/-ko/ +/xfs_ag.h/1.2/Tue May 15 03:43:23 2001/-ko/ +/xfs_alloc.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_alloc_btree.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_arch.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_attr_leaf.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_attr_sf.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_bit.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_bmap.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_bmap_btree.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_btree.h/1.2/Wed Apr 4 04:11:07 2001/-ko/ +/xfs_buf_item.h/1.2/Tue Apr 3 02:52:38 2001/-ko/ +/xfs_cred.h/1.2/Mon Jan 15 10:28:46 2001/-ko/ +/xfs_da_btree.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_dfrag.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_dinode.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_dir.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_dir2.h/1.3/Thu Apr 12 23:30:32 2001/-ko/ +/xfs_dir2_block.h/1.2/Thu Apr 12 23:30:32 2001/-ko/ +/xfs_dir2_data.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_dir2_leaf.h/1.2/Thu Apr 12 23:30:32 2001/-ko/ +/xfs_dir2_node.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_dir2_sf.h/1.2/Thu Apr 12 23:30:32 2001/-ko/ +/xfs_dir_leaf.h/1.3/Thu Apr 12 23:30:32 2001/-ko/ +/xfs_dir_sf.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_dqblk.h/1.2/Tue Apr 3 02:52:38 2001/-ko/ +/xfs_dquot_item.h/1.2/Tue Apr 3 02:52:38 2001/-ko/ +/xfs_extfree_item.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_fs.h/1.5/Thu May 17 02:58:46 2001/-ko/ +/xfs_ialloc.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_ialloc_btree.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_imap.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_inode.h/1.9/Wed Jun 20 14:51:43 2001/-ko/ +/xfs_inode_item.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_inum.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_log.h/1.3/Thu Apr 19 02:29:42 2001/-ko/ +/xfs_log_priv.h/1.2/Sat Feb 24 03:45:21 2001/-ko/ +/xfs_log_recover.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_mount.h/1.5/Tue Jul 3 04:33:45 2001/-ko/ +/xfs_quota.h/1.3/Tue Apr 17 01:36:11 2001/-ko/ +/xfs_rtalloc.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_sb.h/1.2/Tue Apr 3 02:52:38 2001/-ko/ +/xfs_trans.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_trans_space.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_types.h/1.3/Thu Apr 19 02:41:37 2001/-ko/ +/xqm.h/1.3/Tue Apr 3 02:52:38 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/include/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/include/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/include/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/CVS/Repository Thu Jul 5 11:44:26 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/include diff -rNu linux-2.4.7/cmd/xfsprogs/include/CVS/Root linux-2.4-xfs/cmd/xfsprogs/include/CVS/Root --- linux-2.4.7/cmd/xfsprogs/include/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/CVS/Root Thu Jul 5 11:44:26 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/include/Makefile linux-2.4-xfs/cmd/xfsprogs/include/Makefile --- linux-2.4.7/cmd/xfsprogs/include/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/Makefile Sun May 6 21:46:00 2001 @@ -0,0 +1,58 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +HFILES = arch.h handle.h jdm.h libxfs.h xqm.h \ + xfs_ag.h xfs_alloc.h xfs_alloc_btree.h xfs_arch.h xfs_attr_leaf.h \ + xfs_attr_sf.h xfs_bit.h xfs_bmap.h xfs_bmap_btree.h xfs_btree.h \ + xfs_buf_item.h xfs_cred.h xfs_da_btree.h xfs_dfrag.h xfs_dinode.h \ + xfs_dir.h xfs_dir2.h xfs_dir2_block.h xfs_dir2_data.h xfs_dir2_leaf.h \ + xfs_dir2_node.h xfs_dir2_sf.h xfs_dir_leaf.h xfs_dir_sf.h xfs_dqblk.h \ + xfs_dquot_item.h xfs_extfree_item.h xfs_fs.h xfs_ialloc.h \ + xfs_ialloc_btree.h xfs_imap.h xfs_inode.h xfs_inode_item.h xfs_inum.h \ + xfs_log.h xfs_log_priv.h xfs_log_recover.h xfs_mount.h xfs_quota.h \ + xfs_rtalloc.h xfs_sb.h xfs_trans.h xfs_trans_space.h xfs_types.h + +LSRCFILES = platform_defs.h.in builddefs.in buildrules \ + lvm.h lvm_config.h lvm_log.h lvm_user.h liblvm.h \ + md-int.h + +default install : + +include $(BUILDRULES) + +install-dev: default + $(INSTALL) -m 755 -d $(PKG_INC_DIR) + $(INSTALL) -m 644 $(HFILES) $(PKG_INC_DIR) + $(INSTALL) -m 644 platform_defs.h $(PKG_INC_DIR) diff -rNu linux-2.4.7/cmd/xfsprogs/include/arch.h linux-2.4-xfs/cmd/xfsprogs/include/arch.h --- linux-2.4.7/cmd/xfsprogs/include/arch.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/arch.h Wed May 9 01:56:06 2001 @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_ARCH_H__ +#define __XFS_SUPPORT_ARCH_H__ + +#ifdef __KERNEL__ + +#include + +#ifdef __LITTLE_ENDIAN +# define __BYTE_ORDER __LITTLE_ENDIAN +#endif +#ifdef __BIG_ENDIAN +# define __BYTE_ORDER __BIG_ENDIAN +#endif + +#endif /* __KERNEL__ */ + +/* do we need conversion? */ + +#define ARCH_NOCONVERT 1 +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define ARCH_CONVERT 0 +#else +#define ARCH_CONVERT ARCH_NOCONVERT +#endif + +/* generic swapping macros */ + +#define INT_SWAP16(A) ((typeof(A))(__swab16((__u16)A))) +#define INT_SWAP32(A) ((typeof(A))(__swab32((__u32)A))) +#define INT_SWAP64(A) ((typeof(A))(__swab64((__u64)A))) + +#define INT_SWAP(type, var) \ + ((sizeof(type) == 8) ? INT_SWAP64(var) : \ + ((sizeof(type) == 4) ? INT_SWAP32(var) : \ + ((sizeof(type) == 2) ? INT_SWAP16(var) : \ + (var)))) + + +#define INT_SWAP_UNALIGNED_32(from,to) \ + { \ + ((__u8*)(to))[0] = ((__u8*)(from))[3]; \ + ((__u8*)(to))[1] = ((__u8*)(from))[2]; \ + ((__u8*)(to))[2] = ((__u8*)(from))[1]; \ + ((__u8*)(to))[3] = ((__u8*)(from))[0]; \ + } + +#define INT_SWAP_UNALIGNED_64(from,to) \ + { \ + INT_SWAP_UNALIGNED_32( ((__u8*)(from)) + 4, ((__u8*)(to))); \ + INT_SWAP_UNALIGNED_32( ((__u8*)(from)), ((__u8*)(to)) + 4); \ + } + +/* + * get and set integers from potentially unaligned locations + */ + +#define INT_GET_UNALIGNED_16_LE(pointer) \ + ((__u16)((((__u8*)(pointer))[0] ) | (((__u8*)(pointer))[1] << 8 ))) +#define INT_GET_UNALIGNED_16_BE(pointer) \ + ((__u16)((((__u8*)(pointer))[0] << 8) | (((__u8*)(pointer))[1]))) +#define INT_SET_UNALIGNED_16_LE(pointer,value) \ + { \ + ((__u8*)(pointer))[0] = (((value) ) & 0xff); \ + ((__u8*)(pointer))[1] = (((value) >> 8) & 0xff); \ + } +#define INT_SET_UNALIGNED_16_BE(pointer,value) \ + { \ + ((__u8*)(pointer))[0] = (((value) >> 8) & 0xff); \ + ((__u8*)(pointer))[1] = (((value) ) & 0xff); \ + } + +#define INT_GET_UNALIGNED_32_LE(pointer) \ + ((__u32)((((__u8*)(pointer))[0] ) | (((__u8*)(pointer))[1] << 8 ) \ + |(((__u8*)(pointer))[2] << 16) | (((__u8*)(pointer))[3] << 24))) +#define INT_GET_UNALIGNED_32_BE(pointer) \ + ((__u32)((((__u8*)(pointer))[0] << 24) | (((__u8*)(pointer))[1] << 16) \ + |(((__u8*)(pointer))[2] << 8) | (((__u8*)(pointer))[3] ))) + +#define INT_GET_UNALIGNED_64_LE(pointer) \ + (((__u64)(INT_GET_UNALIGNED_32_LE(((__u8*)(pointer))+4)) << 32 ) \ + |((__u64)(INT_GET_UNALIGNED_32_LE(((__u8*)(pointer)) )) )) +#define INT_GET_UNALIGNED_64_BE(pointer) \ + (((__u64)(INT_GET_UNALIGNED_32_BE(((__u8*)(pointer)) )) << 32 ) \ + |((__u64)(INT_GET_UNALIGNED_32_BE(((__u8*)(pointer))+4)) )) + +/* + * now pick the right ones for our MACHINE ARCHITECTURE + */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define INT_GET_UNALIGNED_16(pointer) INT_GET_UNALIGNED_16_LE(pointer) +#define INT_SET_UNALIGNED_16(pointer,value) INT_SET_UNALIGNED_16_LE(pointer,value) +#define INT_GET_UNALIGNED_32(pointer) INT_GET_UNALIGNED_32_LE(pointer) +#define INT_GET_UNALIGNED_64(pointer) INT_GET_UNALIGNED_64_LE(pointer) +#else +#define INT_GET_UNALIGNED_16(pointer) INT_GET_UNALIGNED_16_BE(pointer) +#define INT_SET_UNALIGNED_16(pointer,value) INT_SET_UNALIGNED_16_BE(pointer,value) +#define INT_GET_UNALIGNED_32(pointer) INT_GET_UNALIGNED_32_BE(pointer) +#define INT_GET_UNALIGNED_64(pointer) INT_GET_UNALIGNED_64_BE(pointer) +#endif + +/* define generic INT_ macros */ + +#define INT_GET(reference,arch) \ + (((arch) == ARCH_NOCONVERT) \ + ? \ + (reference) \ + : \ + INT_SWAP((reference),(reference)) \ + ) + +/* does not return a value */ +#define INT_SET(reference,arch,valueref) \ + (void)( \ + ((reference) = (valueref)), \ + ( \ + ((arch) != ARCH_NOCONVERT) ? \ + (reference) = INT_SWAP((reference),(reference)) \ + : 0 \ + ) \ + ) + +/* does not return a value */ +#define INT_MOD_EXPR(reference,arch,code) \ + (void)(((arch) == ARCH_NOCONVERT) \ + ? \ + ((reference) code) \ + : \ + ( \ + (reference) = INT_GET((reference),arch) , \ + ((reference) code), \ + INT_SET(reference, arch, reference) \ + ) \ + ) + +/* does not return a value */ +#define INT_MOD(reference,arch,delta) \ + (void)( \ + INT_MOD_EXPR(reference,arch,+=(delta)) \ + ) + +/* + * INT_COPY - copy a value between two locations with the + * _same architecture_ but _potentially different sizes_ + * + * if the types of the two parameters are equal or they are + * in native architecture, a simple copy is done + * + * otherwise, architecture conversions are done + * + */ + +/* does not return a value */ +#define INT_COPY(dst,src,arch) \ + (void)( \ + ((sizeof(dst) == sizeof(src)) || ((arch) == ARCH_NOCONVERT)) \ + ? \ + ((dst) = (src)) \ + : \ + INT_SET(dst, arch, INT_GET(src, arch)) \ + ) + +/* + * INT_XLATE - copy a value in either direction between two locations + * with different architectures + * + * dir < 0 - copy from memory to buffer (native to arch) + * dir > 0 - copy from buffer to memory (arch to native) + */ + +/* does not return a value */ +#define INT_XLATE(buf,mem,dir,arch) {\ + ASSERT(dir); \ + if (dir>0) { \ + (mem)=INT_GET(buf, arch); \ + } else { \ + INT_SET(buf, arch, mem); \ + } \ +} + +#define INT_ISZERO(reference,arch) \ + ((reference) == 0) + +#define INT_ZERO(reference,arch) \ + ((reference) = 0) + +#define INT_GET_UNALIGNED_16_ARCH(pointer,arch) \ + ( ((arch) == ARCH_NOCONVERT) \ + ? \ + (INT_GET_UNALIGNED_16(pointer)) \ + : \ + (INT_GET_UNALIGNED_16_BE(pointer)) \ + ) +#define INT_SET_UNALIGNED_16_ARCH(pointer,value,arch) \ + if ((arch) == ARCH_NOCONVERT) { \ + INT_SET_UNALIGNED_16(pointer,value); \ + } else { \ + INT_SET_UNALIGNED_16_BE(pointer,value); \ + } + +#endif /* __XFS_SUPPORT_ARCH_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/builddefs.in linux-2.4-xfs/cmd/xfsprogs/include/builddefs.in --- linux-2.4.7/cmd/xfsprogs/include/builddefs.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/builddefs.in Wed May 9 01:56:06 2001 @@ -0,0 +1,171 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# @configure_input@ +# + +ifndef _BUILDDEFS_INCLUDED_ +_BUILDDEFS_INCLUDED_ = 1 + +DEBUG = @debug_build@ +OPTIMIZER = @opt_build@ +MALLOCLIB = @malloc_lib@ + +LIBUUID = @libuuid@ +LIBXFS = -lxfs +LIBHANDLE = -lhandle + +LIBLVM = @liblvm@ +USELVM = -DHAVE_LIBLVM=@have_liblvm@ + +BUILDRULES = $(TOPDIR)/include/buildrules + +# General package information +PKG_NAME = @pkg_name@ +PKG_RELEASE = @pkg_release@ +PKG_VERSION = @pkg_version@ +PKG_DISTRIBUTION = @pkg_distribution@ +PKG_BUILDER = @pkg_builder@ +PKG_BIN_DIR = @pkg_bin_dir@ +PKG_LIB_DIR = @pkg_lib_dir@ +PKG_SBIN_DIR = @pkg_sbin_dir@ +PKG_SLIB_DIR = @pkg_slib_dir@ +PKG_INC_DIR = @pkg_inc_dir@ +PKG_MAN_DIR = @pkg_man_dir@ +PKG_DOC_DIR = @pkg_doc_dir@ + +# LCFLAGS, LLDFLAGS, LLDLIBS, LSRCFILES and LDIRT may be specified in +# user Makefiles. Note: LSRCFILES is anything other than Makefile, $(CFILES) +# $(CXXFILES), or $(HFILES) and is used to construct the manifest list +# during the "dist" phase (packaging). + +CFLAGS += -O1 $(OPTIMIZER) $(DEBUG) -funsigned-char -Wall $(LCFLAGS) \ + -I$(TOPDIR)/include '-DVERSION="$(PKG_VERSION)"' -D_GNU_SOURCE \ + -D_FILE_OFFSET_BITS=64 -DXFS_BIG_FILES=1 -DXFS_BIG_FILESYSTEMS=1 + +LDFLAGS = $(LLDFLAGS) +LDLIBS = $(LLDLIBS) $(MALLOCLIB) + +MAKEOPTS = --no-print-directory +SRCFILES = Makefile $(HFILES) $(CFILES) $(LSRCFILES) $(LFILES) $(YFILES) +DIRT = $(LDIRT) dep dep.bak $(OBJECTS) $(CMDTARGET) $(LIBTARGET) \ + $(STATICLIBTARGET) *.[1-9].gz + +OBJECTS = $(ASFILES:.s=.o) \ + $(CFILES:.c=.o) \ + $(LFILES:.l=.o) \ + $(YFILES:%.y=%.tab.o) + +MAKE = @make@ +CC = @cc@ +LD = @ld@ +AWK = @awk@ +SED = @sed@ +INSTALL = $(TOPDIR)/install-sh -o root -g root +ECHO = @echo@ +LN_S = @LN_S@ + +CCF = $(CC) $(CFLAGS) +MAKEF = $(MAKE) $(MAKEOPTS) +CXXF = $(CXX) $(CXXFLAGS) +LDF = $(LD) $(LDFLAGS) +MAKEDEPEND = @makedepend@ + +ZIP = @zip@ +TAR = @tar@ +RPM = @rpm@ +RPM_VERSION = @rpm_version@ + +HAVE_ZIPPED_MANPAGES = @have_zipped_manpages@ + +SHELL = /bin/sh +IMAGES_DIR = $(TOPDIR)/all-images +DIST_DIR = $(TOPDIR)/dist + +SUBDIRS_MAKERULE = \ + @for d in $(SUBDIRS) ""; do \ + if test -d "$$d" -a ! -z "$$d"; then \ + $(ECHO) === $$d ===; \ + $(MAKEF) -C $$d $@ || exit $$?; \ + fi; \ + done + +MAN_MAKERULE = \ + @for f in *.[12345678] ""; do \ + if test ! -z "$$f"; then \ + $(ZIP) --best -c < $$f > $$f.gz; \ + fi; \ + done + +INSTALL_MAN = \ + @for d in $(MAN_PAGES); do \ + first=true; \ + for m in `$(AWK) '/^\.SH NAME/ {ok=1; next} ok {print; exit}' $$d \ + | sed -e 's/,/ /g' -e 's/\\-.*//' -e 's/\\\f[0-9]//g' -e 's/ / /g;q'`; \ + do \ + [ -z "$$m" -o "$$m" = "\\" ] && continue; \ + t=$(MAN_DEST)/$$m.$(MAN_SECTION); \ + if $$first; then \ + if $(HAVE_ZIPPED_MANPAGES); then \ + $(ZIP) --best -c $$d > $$d.gz; _sfx=.gz; \ + fi; \ + u=$$m.$(MAN_SECTION)$$_sfx; \ + echo $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ + $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ + else \ + echo $(INSTALL) -S $$u $${t}$$_sfx; \ + $(INSTALL) -S $$u $${t}$$_sfx; \ + fi; \ + first=false; \ + done; \ + done + +DIST_MAKERULE = \ + $(MAKEF) -C build dist + +SOURCE_MAKERULE = \ + @test -z "$$DIR" && DIR="."; \ + for f in $(SRCFILES) ""; do \ + if test ! -z "$$f"; then $(ECHO) $$DIR/$$f; fi;\ + done; \ + for d in `echo $(SUBDIRS)` ; do \ + if test -d "$$d" -a ! -z "$$d"; then \ + $(MAKEF) DIR=$$DIR/$$d -C $$d $@ || exit $$?; \ + fi; \ + done + +endif + +# +# For targets that should always be rebuilt, +# define a target that is never up-to-date. +# Targets needing this should depend on $(_FORCE) +_FORCE = __force_build diff -rNu linux-2.4.7/cmd/xfsprogs/include/buildrules linux-2.4-xfs/cmd/xfsprogs/include/buildrules --- linux-2.4.7/cmd/xfsprogs/include/buildrules Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/buildrules Mon Jan 15 00:52:52 2001 @@ -0,0 +1,77 @@ +# +# Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Fondation. +# +# This program is distributed in the hope that it would be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. Further, any license provided herein, +# whether implied or otherwise, is limited to this program in accordance with +# the express provisions of the GNU General Public License. Patent licenses, +# if any, provided herein do not apply to combinations of this program with +# other product or programs, or any other product whatsoever. This program is +# distributed without any warranty that the program is delivered free of the +# rightful claim of any third person by way of infringement or the like. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write the Free Software Foundation, Inc., 59 Temple +# Place - Suite 330, Boston MA 02111-1307, USA. +# Common build rules for gmake +# +ifndef _BUILDRULES_INCLUDED_ +_BUILDRULES_INCLUDED_ = 1 + +include $(TOPDIR)/include/builddefs + +# +# Standard targets +# +ifdef CMDTARGET +$(CMDTARGET) : $(SUBDIRS) $(OBJECTS) + $(CCF) -o $(CMDTARGET) $(LDFLAGS) $(OBJECTS) $(LDLIBS) +$(CMDTARGET).static : $(SUBDIRS) $(OBJECTS) + $(CCF) -static -o $(CMDTARGET).static $(LDFLAGS) $(OBJECTS) $(LDLIBS) +endif + +ifdef LIBTARGET +$(LIBTARGET) : $(SUBDIRS) $(OBJECTS) + $(CC) $(LDFLAGS) -fPIC -shared -Wl,-soname,$(LIBTARGET) -o $(LIBTARGET) $(OBJECTS) $(LDLIBS) +endif + +ifdef STATICLIBTARGET +$(STATICLIBTARGET) : $(SUBDIRS) $(OBJECTS) + $(AR) crf $(STATICLIBTARGET) $? +endif + +clean clobber : $(SUBDIRS) + rm -f $(DIRT) + $(SUBDIRS_MAKERULE) + +# Never blow away subdirs +ifdef SUBDIRS +.PRECIOUS: $(SUBDIRS) +$(SUBDIRS): + $(SUBDIRS_MAKERULE) +endif + +source : + $(SOURCE_MAKERULE) + +endif + +$(_FORCE): + +.PHONY : depend + +depend : $(CFILES) $(HFILES) + $(SUBDIRS_MAKERULE) + touch dep + $(MAKEDEPEND) -fdep -- $(CFLAGS) -- $(CFILES) + +# Include dep, but only if it exists +ifeq ($(shell test -f dep && echo dep), dep) +include dep +endif diff -rNu linux-2.4.7/cmd/xfsprogs/include/handle.h linux-2.4-xfs/cmd/xfsprogs/include/handle.h --- linux-2.4.7/cmd/xfsprogs/include/handle.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/handle.h Fri Feb 9 01:45:14 2001 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __HANDLE_H__ +#define __HANDLE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int path_to_handle (char *__path, void **__hanp, size_t *__hlen); +extern int path_to_fshandle (char *__path, void **__hanp, size_t *__hlen); +extern int fd_to_handle (int __fd, void **__hanp, size_t *__hlen); +extern int handle_to_fshandle (void *__hanp, size_t __hlen, void **__fshanp, + size_t *__fshlen); +extern int handle_to_fsfd (void *__hanp); +extern void free_handle (void *__hanp, size_t __hlen); +extern int open_by_handle (void *__hanp, size_t __hlen, int __rw); +extern int readlink_by_handle (void *__hanp, size_t __hlen, void *__buf, + size_t __bs); + +#ifdef __cplusplus +} +#endif + +#endif /* __HANDLE_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/jdm.h linux-2.4-xfs/cmd/xfsprogs/include/jdm.h --- linux-2.4.7/cmd/xfsprogs/include/jdm.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/jdm.h Fri Feb 9 01:45:14 2001 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __JDM_H__ +#define __JDM_H__ + +typedef int intgen_t; +typedef void jdm_fshandle_t; /* filesystem handle */ +typedef void jdm_filehandle_t; /* filehandle */ + +struct xfs_bstat; + + +extern jdm_fshandle_t * +jdm_getfshandle( char *mntpnt); + +extern void +jdm_new_filehandle( jdm_filehandle_t **handlep, /* new filehandle */ + size_t *hlen, /* new filehandle size */ + jdm_fshandle_t *fshandlep, /* filesystem filehandle */ + struct xfs_bstat *sp); /* bulkstat info */ + +extern void +jdm_delete_filehandle( jdm_filehandle_t *handlep,/* filehandle to delete */ + size_t hlen); /* filehandle size */ + +extern intgen_t +jdm_open( jdm_fshandle_t *fshandlep, + struct xfs_bstat *sp, + intgen_t oflags); + +extern intgen_t +jdm_readlink( jdm_fshandle_t *fshandlep, + struct xfs_bstat *sp, + char *bufp, + size_t bufsz); + +/* macro for determining the size of a structure member */ +#define sizeofmember( t, m ) sizeof( ( ( t * )0 )->m ) + +/* macro for calculating the offset of a structure member */ +#define offsetofmember( t, m ) ( ( size_t )( char * )&( ( ( t * )0 )->m ) ) + +#endif /* __JDM_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/liblvm.h linux-2.4-xfs/cmd/xfsprogs/include/liblvm.h --- linux-2.4.7/cmd/xfsprogs/include/liblvm.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/liblvm.h Tue Mar 20 14:10:08 2001 @@ -0,0 +1,729 @@ +/* + * tools/lib/liblvm.h + * + * Copyright (C) 1997 - 2000 Heinz Mauelshagen, Sistina Software + * + * March-June 1997 + * January 1998 + * January,February,July 1999 + * February,March 2000 + * + * + * This LVM library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This LVM library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this LVM library; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA + * + */ + +/* + * Changelog + * + * 03/01/1999 - port to libc6 + * 07/02/1999 - conditional data conversion macros + * 05/07/1999 - rearanged includes due to 2.3.x changes + * + */ + +/* lvm_lib_version "LVM 0.9 by Heinz Mauelshagen 11/11/2000\n" */ + +#ifndef _LIBLVM_H_INCLUDE +#define _LIBLVM_H_INCLUDE + +#define LVM_LIB_IOP_VERSION 10 + +#include +#include + +#ifndef LINUX_VERSION_CODE +# include +#endif + +#include + +#ifndef uint8_t +# define uint8_t unsigned char +#endif +#ifndef uint16_t +# define uint16_t unsigned short int +#endif +#ifndef uint32_t +# define uint32_t unsigned int +#endif +#ifndef uint64_t +# define uint64_t unsigned long long int +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "lvm.h" + +#include "lvm_log.h" +#include "lvm_config.h" + +extern struct config_file *config_file; + +#define SECTOR_SIZE 512 +#define BLKGETSIZE _IO(0x12,96) /* return device size */ +#define BLKRASET _IO(0x12,98) /* Set read ahead */ +#define EXT2_SUPER_MAGIC 0xEF53 +#ifndef BLOCK_SIZE +#define BLOCK_SIZE 1024 +#endif + +#define LVM_ID "HM" /* Identifier PV (id in pv_t) */ +#define EXPORTED "PV_EXP" /* Identifier exported PV (system_id in pv_t) */ +#define IMPORTED "PV_IMP" /* Identifier imported PV ( " ) */ +#define LVMTAB "/etc/lvmtab" /* LVM table of VGs */ +#define LVMTAB_DIR "/etc/lvmtab.d" /* storage dir VG data */ +#define LVMTAB_MINSIZE ( sizeof ( vg_t) + sizeof ( lv_t) + sizeof ( pv_t)) +#define LVM_DEV "/dev/lvm" +#define VG_BACKUP_DIR "/etc/lvmconf" +#define DISK_NAME_LEN 8 +#define LV_MIN_NAME_LEN 5 +#define LV_MAX_NAME_LEN 7 +#define MIN_PART 1 +#define MAX_PART 15 + + +extern int errno; +extern char *cmd; + +#ifdef DEBUG +extern int opt_d; +#endif + +/* for lvm_show_size () */ +typedef enum { SHORT, LONG} size_len_t; + +/* for future use, maybe in pv_check_free () */ +typedef enum { + NEXT_FREE, + LINEAR, + LINEAR_CONTIGUOUS, + STRIPED, + STRIPED_CONTIGUOUS} +alloc_t; + +/* for lvm_dir_cache () */ +typedef struct { + char *dev_name; + dev_t st_rdev; + short st_mode; +} dir_cache_t; + +/* PE type data layer functions */ +pe_disk_t *pe_copy_from_disk ( pe_disk_t*, int); +pe_disk_t *pe_copy_to_disk ( pe_disk_t*, int); + +/* VG functions */ +int vg_cfgbackup ( char *, char *, int, vg_t *); +int vg_cfgrestore ( char *, char *, int, vg_t *); +int vg_check_active ( char *); +int vg_check_exist ( char *); +char ** vg_check_exist_all_vg ( void); +int vg_check_dir ( char *); +int vg_check_name ( char *); +int vg_check_consistency ( vg_t *); +int vg_check_consistency_with_pv_and_lv ( vg_t *); +int vg_check_online_all_pv ( vg_t*, pv_t***, pv_t***); +int vg_check_pe_size ( ulong); +char ** vg_check_active_all_vg ( void); +vg_t *vg_copy_from_disk ( vg_disk_t *); +vg_disk_t *vg_copy_to_disk ( vg_t *); +int vg_create ( char *, vg_t *); +int vg_create_dir_and_group ( vg_t *); +int vg_create_dir_and_group_and_nodes ( vg_t *, int); +void vg_deactivate ( char *); +inline int vg_extend ( char *, pv_t *, vg_t *); +int vg_free ( vg_t *, int); +char *vg_name_of_lv ( char *); +int vg_remove ( char *); +int vg_rename ( char *, char *); +int vg_read ( char *, vg_t **); +int vg_read_from_pv ( char *, vg_t **); +int vg_read_with_pv_and_lv ( char *, vg_t **); +inline int vg_reduce ( char *, pv_t *, vg_t *); +int vg_remove_dir_and_group_and_nodes ( char *); +int vg_set_extendable ( char*); +void vg_setup_pointers_for_snapshots ( vg_t*); +int vg_clear_extendable ( char*); +int vg_setup_for_create ( char *, vg_t *, pv_t **, int, ulong, ulong); +int vg_setup_for_extend ( char **, int, pv_t **, vg_t *, char **); +int vg_setup_for_merge ( vg_t *, vg_t *); +int vg_setup_for_reduce ( char **, int, vg_t *, pv_t ***, char **); +int vg_setup_for_split ( vg_t *, char *, vg_t **, char **, char ***, char **); +void vg_show ( vg_t *); +void vg_show_colon ( vg_t *); +void vg_show_with_pv_and_lv ( vg_t *); +int vg_write ( char*, pv_t *, vg_t *); +int vg_write_with_pv_and_lv ( vg_t *); +int vg_status ( char *, vg_t **); +int vg_status_get_count ( void); +int vg_status_get_namelist ( char *); +int vg_status_with_pv_and_lv ( char *, vg_t **); + + +/* PV functions */ +int pe_lock ( char *, kdev_t, ulong, ushort, ushort, kdev_t); +int pe_unlock ( char *); +int pv_change ( char *, pv_t *); +int pv_change_all_pv_of_vg ( char *, vg_t *); +int pv_change_all_pv_for_lv_of_vg ( char *, char *, vg_t *); +int pv_check_active ( char *, char *); +int pv_check_active_in_all_vg ( char *); +int pv_check_free ( pv_t *, ulong, ulong *); +int pv_check_free_contiguous ( pv_t *, ulong, ulong *); +int pv_check_in_vg ( vg_t *, char *); +int pv_check_new ( pv_t *); +int pv_check_consistency ( pv_t *); +int pv_check_consistency_all_pv ( vg_t *); +int pv_check_name ( char *); +int pv_check_number ( pv_t **, int); +int pv_check_part ( char *); +int pv_check_volume ( char *, pv_t *); +pv_t *pv_copy_from_disk ( pv_disk_t *); +pv_disk_t *pv_copy_to_disk ( pv_t *); +char **pv_find_all_pv_names ( void); +kdev_t pv_create_kdev_t ( char *); +char *pv_create_name_from_kdev_t ( kdev_t); +int pv_find_vg ( char *, char **); +int pv_flush ( char *); +int pv_get_index_by_kdev_t ( vg_t *, kdev_t); +int pv_get_index_by_name ( vg_t *, char *); +kdev_t pv_get_kdev_t_by_number ( vg_t *, int); +int pv_get_size ( char *, struct partition *); +int pv_move_pes ( vg_t*, char*, char**, int, int, + long*, long*, long*, int, int); +int pv_move_pe ( vg_t*, char*, long, long, long, long, + int, int, int, int); +int pv_read ( char *, pv_t **, int *); +int pv_read_already_red ( char *); +int pv_read_pe ( pv_t *, pe_disk_t **); +int pv_read_all_pv ( pv_t ***, int); +int pv_read_all_pv_of_vg ( char *, pv_t ***, int); +int pv_read_all_pe_of_vg ( char *, pe_disk_t ***, int); +int pv_read_uuidlist ( pv_t *, char **); +int pv_release_pe ( vg_t *, pe_disk_t *, uint *, uint); +int pv_reserve_pe ( pv_t *, pe_disk_t *, uint *, pe_t *, uint, int); +int pv_setup_for_create ( char *, pv_t *, uint); +void pv_show ( pv_t *); +void pv_show_colon ( pv_t *); +void pv_show_short ( pv_t *); +void pv_show_all_pv_of_vg ( vg_t *); +void pv_show_all_pv_of_vg_short ( vg_t *); +void pv_show_pe ( pv_t *, pe_disk_t *, int); +int pv_show_pe_text ( pv_t *, pe_disk_t *, int); +int pv_status ( char *, char *, pv_t **); +int pv_status_all_pv_of_vg ( char *, pv_t ***); +int pv_write ( char*, pv_t *); +int pv_write_all_pv_of_vg ( vg_t *); +int pv_write_uuidlist ( char *, vg_t *); +int pv_write_pe ( char*, pv_t *); +int pv_write_with_pe ( char*, pv_t *); + + +/* LV functions */ +char *lv_change_vgname ( char *, char *); +int lv_change_read_ahead ( char *, int); +int lv_check_active ( char *, char *); +int lv_check_on_pv ( pv_t *, int); +int lv_check_contiguous ( vg_t *, int); +int lv_check_consistency ( lv_t *); +int lv_check_consistency_all_lv ( vg_t *); +int lv_check_exist ( char *); +int lv_check_name ( char *); +int lv_check_stripesize ( int); +lv_t *lv_copy_from_disk ( lv_disk_t *); +lv_disk_t *lv_copy_to_disk ( lv_t *); +int lv_count_pe ( pv_t *, int); +inline int lv_create ( vg_t *, lv_t *, char *); +int lv_create_name ( char *, char *, int); +int lv_create_node ( lv_t *); +inline int lv_extend ( vg_t *, lv_t *, char *); +int lv_get_index_by_kdev_t ( vg_t *, kdev_t); +int lv_get_index_by_minor ( vg_t *, int); +int lv_get_index_by_name ( vg_t *, char *); +int lv_get_index_by_number ( vg_t *, int); +int lv_get_le_on_pv ( pv_t *, int); +char *lv_get_name ( vg_t*, int); +int lv_init_COW_table ( vg_t *, lv_t *); +int lv_number_from_name_in_vg ( char *, vg_t *); +int lv_le_remap ( vg_t*, le_remap_req_t*); +int lv_read ( char *, char *, lv_t **); +int lv_read_byindex ( char *vg_name, ulong lv_index, lv_t **lv); +int lv_read_COW_table ( vg_t * vg, lv_t * lv); +int lv_read_with_pe ( char *, char *, lv_t **); +int lv_read_all_lv ( char *, lv_t ***, int); +inline int lv_reduce ( vg_t *, lv_t *, char *); +int lv_release ( vg_t *, char *); +inline int lv_remove ( vg_t *, lv_t *, char *); +int lv_rename ( char *, lv_t *); +int lv_setup_for_create ( char *, vg_t **, char *, int *, + uint, uint, uint, uint, uint, uint, char **); +int lv_setup_for_extend ( char *, vg_t *, char *, uint, char **); +int lv_setup_for_reduce ( char *, vg_t *, char *, uint); +int lv_setup_COW_table_for_create ( vg_t *, char *, int, int); +void lv_show ( lv_t *); +void lv_show_colon ( lv_t *); +void lv_show_all_lv_of_vg ( vg_t *); +void lv_show_current_pe ( lv_t *); +int lv_show_current_pe_text ( lv_t *); +int lv_snapshot_use_rate ( char *, int, int); +int lv_status_byname ( char *, char *, lv_t **); +int lv_status_byindex ( char *, ulong, lv_t **); +int lv_status_all_lv_of_vg ( char *, vg_t *, lv_t ***); +int lv_write ( char *, vg_t *, lv_t *, int); +int lv_write_all_pv ( vg_t *, int); +int lv_write_all_lv ( char*, vg_t *); + + +/* print debug info on stdout */ +#ifdef DEBUG +void lvm_debug(const char *fmt, ...); +void lvm_debug_enter(const char *fmt, ...); +void lvm_debug_leave(const char *fmt, ...); + +#define debug(fmt, args...) lvm_debug(fmt, ## args) +#define debug_enter(fmt, args...) lvm_debug_enter(fmt, ## args) +#define debug_leave(fmt, args...) lvm_debug_leave(fmt, ## args) +#else +#define debug(fmt, args...) +#define debug_enter(fmt, args...) +#define debug_leave(fmt, args...) +#endif + +/* generate nice KB/MB/... strings */ +char *lvm_show_size ( unsigned long long, size_len_t); + +/* system identifier handling */ +int system_id_set ( char *); +int system_id_set_exported ( char *); +int system_id_set_imported ( char *); +int system_id_check_exported ( char *); +int system_id_check_imported ( char *); + +/* LVM locking / interrupt masking etc. */ +int lvm_check_chars ( char*); +int lvm_check_dev ( struct stat*, int); +int lvm_check_devfs (); +int lvm_check_extended_partition ( dev_t); +int lvm_check_kernel_lvmtab_consistency ( void); +int lvm_check_partitioned_dev ( dev_t); +int lvm_check_whole_disk_dev ( dev_t); +void lvm_check_special ( void); +long lvm_check_number ( char *, int); +int lvm_check_uuid ( char*); +unsigned char *lvm_create_uuid ( int); +char *lvm_show_uuid ( char *); +int lvm_dir_cache ( dir_cache_t **); +dir_cache_t *lvm_dir_cache_find ( char *); +void lvm_dont_interrupt ( int); +int lvm_get_col_numbers ( char *, long **); +int lvm_get_iop_version ( void); +void lvm_init(int argc, char **argv); +void lvm_interrupt ( void); +int lvm_lock ( void); +int lvm_partition_count ( dev_t); +char *lvm_error ( int); +int lvm_remove_recursive ( const char*); +int lvm_show_filetype ( ushort, char *); +int lvm_unlock ( void); + +/* LVMTAB based functions */ +int lvm_tab_read ( char **, int *); +int lvm_tab_write ( char *, int); +int lvm_tab_create ( void); +int lvm_tab_get_free_vg_number ( void); +int lvm_tab_lv_check_exist ( char *); +int lvm_tab_lv_read_by_name ( char *, char*, lv_t **); +int lvm_tab_vg_insert ( char *); +int lvm_tab_vg_read_with_pv_and_lv ( char *, vg_t **); +int lvm_tab_vg_read ( char *, vg_t **); +int lvm_tab_vg_remove ( char *); +int lvm_tab_vg_check_exist ( char *, vg_t **); +int lvm_tab_get_free_blk_dev ( kdev_t **); +char **lvm_tab_vg_check_exist_all_vg ( void); + +/* core <-> disk conversion macros */ +#if __BYTE_ORDER == __BIG_ENDIAN +#define LVM_TO_CORE16(x) ( \ + ((uint16_t)((((uint16_t)(x) & 0x00FFU) << 8) | \ + (((uint16_t)(x) & 0xFF00U) >> 8)))) + +#define LVM_TO_DISK16(x) LVM_TO_CORE16(x) + +#define LVM_TO_CORE32(x) ( \ + ((uint32_t)((((uint32_t)(x) & 0x000000FFU) << 24) | \ + (((uint32_t)(x) & 0x0000FF00U) << 8) | \ + (((uint32_t)(x) & 0x00FF0000U) >> 8) | \ + (((uint32_t)(x) & 0xFF000000U) >> 24)))) + +#define LVM_TO_DISK32(x) LVM_TO_CORE32(x) + +#define LVM_TO_CORE64(x) \ + ((uint64_t)((((uint64_t)(x) & 0x00000000000000FFULL) << 56) | \ + (((uint64_t)(x) & 0x000000000000FF00ULL) << 40) | \ + (((uint64_t)(x) & 0x0000000000FF0000ULL) << 24) | \ + (((uint64_t)(x) & 0x00000000FF000000ULL) << 8) | \ + (((uint64_t)(x) & 0x000000FF00000000ULL) >> 8) | \ + (((uint64_t)(x) & 0x0000FF0000000000ULL) >> 24) | \ + (((uint64_t)(x) & 0x00FF000000000000ULL) >> 40) | \ + (((uint64_t)(x) & 0xFF00000000000000ULL) >> 56))) + +#define LVM_TO_DISK64(x) LVM_TO_CORE64(x) +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define LVM_TO_CORE16(x) x +#define LVM_TO_DISK16(x) x +#define LVM_TO_CORE32(x) x +#define LVM_TO_DISK32(x) x +#define LVM_TO_CORE64(x) x +#define LVM_TO_DISK64(x) x +#else +#error "__BYTE_ORDER must be defined as __LITTLE_ENDIAN or __BIG_ENDIAN" +#endif /* #if __BYTE_ORDER == __BIG_ENDIAN */ + +/* return codes */ +#define LVM_VG_CFGBACKUP_NO_DIFF 100 + + +/* error return codes */ +#define LVM_EPARAM 99 + + +#define LVM_ELVM_CHECK_CHARS 100 +#define LVM_ELVM_FIND_VG_REALLOC 101 +#define LVM_ELVM_IOP_VERSION_OPEN 102 +#define LVM_ELVM_LOCK_YET_LOCKED 103 +#define LVM_ELVM_NOT_LOCKED 104 +#define LVM_ELVM_TAB_CREATE_LVMTAB 105 +#define LVM_ELVM_TAB_CREATE_LVMTAB_DIR 106 +#define LVM_ELVM_TAB_GET_FREE_BLK_DEV_LVM_TAB_VG_CHECK_EXIST 107 +#define LVM_ELVM_TAB_GET_FREE_BLK_DEV_NO_DEV 108 +#define LVM_ELVM_TAB_GET_FREE_BLK_DEV_REALLOC 109 +#define LVM_ELVM_TAB_GET_FREE_VG_NUMBER_MALLOC 110 +#define LVM_ELVM_TAB_LV_READ_BY_NAME_LVM_TAB_VG_READ_WITH_PV_AND_LV 111 +#define LVM_ELVM_TAB_LV_READ_BY_NAME_LV_GET_INDEX_BY_NAME 112 +#define LVM_ELVM_TAB_READ_FSTAT 113 +#define LVM_ELVM_TAB_READ_MALLOC 114 +#define LVM_ELVM_TAB_READ_OPEN 115 +#define LVM_ELVM_TAB_READ_PV_CHECK_NAME 116 +#define LVM_ELVM_TAB_READ_READ 117 +#define LVM_ELVM_TAB_READ_SIZE 118 +#define LVM_ELVM_TAB_READ_VG_CHECK_NAME 119 +#define LVM_ELVM_TAB_VG_CHECK_EXIST_ALL_VG_REALLOC 120 +#define LVM_ELVM_TAB_VG_INSERT_REALLOC 121 +#define LVM_ELVM_TAB_VG_INSERT_VG_EXISTS 122 +#define LVM_ELVM_TAB_VG_REMOVE_NOT_EXISTS 123 +#define LVM_ELVM_TAB_VG_REMOVE_UNLINK 124 +#define LVM_ELVM_TAB_WRITE_FCHMOD 125 +#define LVM_ELVM_TAB_WRITE_OPEN 126 +#define LVM_ELVM_TAB_WRITE_WRITE 127 +#define LVM_ELV_ACCESS 128 +#define LVM_ELV_ALLOCATED_LE 129 +#define LVM_ELV_ALLOCATION 130 +#define LVM_ELV_BADBLOCK 131 +#define LVM_ELV_CHECK_NAME_LV_NAME 132 +#define LVM_ELV_CHECK_NAME_LV_NUM 133 +#define LVM_ELV_CHECK_NAME_VG_NAME 134 +#define LVM_ELV_CHECK_STRIPE_SIZE 135 +#define LVM_ELV_CREATE_NODE_CHMOD 136 +#define LVM_ELV_CREATE_NODE_CHOWN 137 +#define LVM_ELV_CREATE_NODE_MKNOD 138 +#define LVM_ELV_CREATE_NODE_UNLINK 139 +#define LVM_ELV_CREATE_REMOVE_OPEN 140 +#define LVM_ELV_CURRENT_LE 141 +#define LVM_ELV_EXTEND_REDUCE_OPEN 142 +#define LVM_ELV_INIT_COW_TABLE_CLOSE 143 +#define LVM_ELV_INIT_COW_TABLE_LLSEEK 144 +#define LVM_ELV_INIT_COW_TABLE_MALLOC 145 +#define LVM_ELV_INIT_COW_TABLE_OPEN 146 +#define LVM_ELV_INIT_COW_TABLE_WRITE 147 +#define LVM_ELV_LE_REMAP_OPEN 148 +#define LVM_ELV_LVNAME 149 +#define LVM_ELV_MIRROR_COPIES 150 +#define LVM_ELV_NUMBER 151 +#define LVM_ELV_OPEN 152 +#define LVM_ELV_READ_ALL_LV_LSEEK 153 +#define LVM_ELV_READ_ALL_LV_MALLOC 154 +#define LVM_ELV_READ_ALL_LV_NL 155 +#define LVM_ELV_READ_ALL_LV_OPEN 156 +#define LVM_ELV_READ_ALL_LV_READ 157 +#define LVM_ELV_READ_ALL_LV_VG_READ 158 +#define LVM_ELV_READ_BYINDEX_LV_READ_ALL_LV 159 +#define LVM_ELV_READ_BYINDEX_VG_NAME 160 +#define LVM_ELV_READ_BYINDEX_VG_READ 161 +#define LVM_ELV_READ_COW_TABLE_CLOSE 162 +#define LVM_ELV_READ_COW_TABLE_LLSEEK 163 +#define LVM_ELV_READ_COW_TABLE_MALLOC 164 +#define LVM_ELV_READ_COW_TABLE_OPEN 165 +#define LVM_ELV_READ_COW_TABLE_READ 166 +#define LVM_ELV_READ_LV 167 +#define LVM_ELV_READ_LV_NAME 168 +#define LVM_ELV_READ_LV_READ_ALL_LV 169 +#define LVM_ELV_READ_VG_NAME 170 +#define LVM_ELV_READ_VG_READ 171 +#define LVM_ELV_RECOVERY 172 +#define LVM_ELV_RELEASE_LV_NUM 173 +#define LVM_ELV_RENAME_OPEN 174 +#define LVM_ELV_SCHEDULE 175 +#define LVM_ELV_SETUP_COW_TABLE_FOR_CREATE_MALLOC 176 +#define LVM_ELV_SETUP_FOR_CREATE_LVM_TAB_GET_FREE_BLK_DEV 177 +#define LVM_ELV_SETUP_FOR_CREATE_LV_MAX 178 +#define LVM_ELV_SETUP_FOR_CREATE_MALLOC 179 +#define LVM_ELV_SETUP_FOR_CREATE_PE 180 +#define LVM_ELV_SETUP_FOR_CREATE_STRIPES 181 +#define LVM_ELV_SETUP_FOR_CREATE_STRIPESIZE 182 +#define LVM_ELV_SETUP_FOR_EXTEND_LV_INDEX 183 +#define LVM_ELV_SETUP_FOR_EXTEND_REALLOC 184 +#define LVM_ELV_SETUP_FOR_EXTEND_STRIPES 185 +#define LVM_ELV_SETUP_FOR_REDUCE_LV_INDEX 186 +#define LVM_ELV_SETUP_FOR_REDUCE_MALLOC 187 +#define LVM_ELV_SHOW_CURRENT_PE_TEXT_LV_INDEX 188 +#define LVM_ELV_SHOW_VG_READ_WITH_PV_AND_LV 189 +#define LVM_ELV_SIZE 190 +#define LVM_ELV_SNAPSHOT_USE_RATE_OPEN 191 +#define LVM_ELV_STATUS 192 +#define LVM_ELV_STATUS_ALL_LV_OF_VG_MALLOC 193 +#define LVM_ELV_STATUS_BYINDEX_MALLOC 194 +#define LVM_ELV_STATUS_BYNAME_MALLOC 195 +#define LVM_ELV_STATUS_INTERNAL_OPEN 196 +#define LVM_ELV_STATUS_NL 197 +#define LVM_ELV_STRIPES 198 +#define LVM_ELV_STRIPESIZE 199 +#define LVM_ELV_TIMEOUT 200 +#define LVM_ELV_VGNAME 201 +#define LVM_ELV_WRITE_ALL_LV_LSEEK 202 +#define LVM_ELV_WRITE_ALL_LV_MALLOC 203 +#define LVM_ELV_WRITE_ALL_LV_OPEN 204 +#define LVM_ELV_WRITE_ALL_LV_WRITE 205 +#define LVM_ELV_WRITE_LSEEK 206 +#define LVM_ELV_WRITE_OPEN 207 +#define LVM_ELV_WRITE_WRITE 208 +#define LVM_EPE_LOCK 209 +#define LVM_EPV_CHANGE_ALL_PV_FOR_LV_OF_VG_LV_NUM 210 +#define LVM_EPV_CHANGE_OPEN 211 +#define LVM_EPV_CHECK_CONSISTENCY_ALL_PV_PE 212 +#define LVM_EPV_CHECK_CONSISTENCY_LVM_ID 213 +#define LVM_EPV_CHECK_CONSISTENCY_LV_CUR 214 +#define LVM_EPV_CHECK_CONSISTENCY_MAJOR 215 +#define LVM_EPV_CHECK_CONSISTENCY_PE_ALLOCATED 216 +#define LVM_EPV_CHECK_CONSISTENCY_PE_SIZE 217 +#define LVM_EPV_CHECK_CONSISTENCY_PE_STALE 218 +#define LVM_EPV_CHECK_CONSISTENCY_PE_TOTAL 219 +#define LVM_EPV_CHECK_CONSISTENCY_PV_ALLOCATABLE 220 +#define LVM_EPV_CHECK_CONSISTENCY_PV_NAME 221 +#define LVM_EPV_CHECK_CONSISTENCY_PV_SIZE 222 +#define LVM_EPV_CHECK_CONSISTENCY_PV_STATUS 223 +#define LVM_EPV_CHECK_CONSISTENCY_STRUCT_VERSION 224 +#define LVM_EPV_CHECK_CONSISTENCY_VG_NAME 225 +#define LVM_EPV_CHECK_NAME 226 +#define LVM_EPV_CHECK_NAME_STAT 227 +#define LVM_EPV_CHECK_NUMBER_MALLOC 228 +#define LVM_EPV_CHECK_NUMBER_MAX_NUMBER 229 +#define LVM_EPV_CHECK_NUMBER_PV_NUMBER 230 +#define LVM_EPV_CHECK_PART 231 +#define LVM_EPV_FIND_ALL_PV_PV_READ 232 +#define LVM_EPV_FLUSH_OPEN 233 +#define LVM_EPV_GET_SIZE_IOCTL 234 +#define LVM_EPV_GET_SIZE_LLSEEK 235 +#define LVM_EPV_GET_SIZE_LVM_DIR_CACHE 236 +#define LVM_EPV_GET_SIZE_NO_EXTENDED 237 +#define LVM_EPV_GET_SIZE_NO_PRIMARY 238 +#define LVM_EPV_GET_SIZE_OPEN 239 +#define LVM_EPV_GET_SIZE_PART 240 +#define LVM_EPV_GET_SIZE_READ 241 +#define LVM_EPV_MOVE_LV_LE_REMAP 242 +#define LVM_EPV_MOVE_PES_ALLOC_STRIPES 243 +#define LVM_EPV_MOVE_PES_NO_PES 244 +#define LVM_EPV_MOVE_PES_NO_SPACE 245 +#define LVM_EPV_MOVE_PES_REALLOC 246 +#define LVM_EPV_MOVE_PE_LLSEEK_IN 247 +#define LVM_EPV_MOVE_PE_LLSEEK_OUT 248 +#define LVM_EPV_MOVE_PE_LOCK 249 +#define LVM_EPV_MOVE_PE_LV_GET_NAME 250 +#define LVM_EPV_MOVE_PE_OPEN 251 +#define LVM_EPV_MOVE_PE_OPEN_IN 252 +#define LVM_EPV_MOVE_PE_READ_IN 253 +#define LVM_EPV_MOVE_PE_UNLOCK 254 +#define LVM_EPV_MOVE_PE_WRITE_OUT 255 +#define LVM_EPV_MOVE_PV_CHANGE_DEST 256 +#define LVM_EPV_MOVE_PV_CHANGE_SRC 257 +#define LVM_EPV_MOVE_PV_PV_WRITE_WITH_PE_DEST 258 +#define LVM_EPV_MOVE_PV_PV_WRITE_WITH_PE_SRC 259 +#define LVM_EPV_READ_ALL_PE_OF_VG_MALLOC 260 +#define LVM_EPV_READ_ALL_PE_OF_VG_PV_NUMBER 261 +#define LVM_EPV_READ_ALL_PV_LVM_DIR_CACHE 262 +#define LVM_EPV_READ_ALL_PV_MALLOC 263 +#define LVM_EPV_READ_ALL_PV_OF_VG_MALLOC 264 +#define LVM_EPV_READ_ALL_PV_OF_VG_NP 265 +#define LVM_EPV_READ_ALL_PV_OF_VG_NP_SORT 266 +#define LVM_EPV_READ_ALL_PV_OF_VG_PV_NUMBER 267 +#define LVM_EPV_READ_ID_INVALID 268 +#define LVM_EPV_READ_LVM_STRUCT_VERSION 269 +#define LVM_EPV_READ_MAJOR 270 +#define LVM_EPV_READ_MD_DEVICE 271 +#define LVM_EPV_READ_OPEN 272 +#define LVM_EPV_READ_PE_LSEEK 273 +#define LVM_EPV_READ_PE_MALLOC 274 +#define LVM_EPV_READ_PE_OPEN 275 +#define LVM_EPV_READ_PE_READ 276 +#define LVM_EPV_READ_PE_SIZE 277 +#define LVM_EPV_READ_PV_CREATE_NAME_FROM_KDEV_T 278 +#define LVM_EPV_READ_PV_EXPORTED 279 +#define LVM_EPV_READ_PV_FLUSH 280 +#define LVM_EPV_READ_RDEV 281 +#define LVM_EPV_READ_READ 282 +#define LVM_EPV_READ_STAT 283 +#define LVM_EPV_READ_UUIDLIST_LSEEK 284 +#define LVM_EPV_READ_UUIDLIST_OPEN 285 +#define LVM_EPV_READ_UUIDLIST_READ 286 +#define LVM_EPV_READ_UUIDLIST_MALLOC 287 +#define LVM_EPV_RELEASE_PE_NO_PV 288 +#define LVM_EPV_RELEASE_PE_REALLOC 289 +#define LVM_EPV_SHOW_PE_TEXT_MALLOC 290 +#define LVM_EPV_SHOW_PE_TEXT_REALLOC 291 +#define LVM_EPV_SHOW_PE_TEXT_VG_READ_WITH_PV_AND_LV 292 +#define LVM_EPV_STATUS_ALL_PV_LVM_DIR_CACHE 293 +#define LVM_EPV_STATUS_ALL_PV_OF_VG_MALLOC 294 +#define LVM_EPV_STATUS_ALL_PV_OF_VG_NP 295 +#define LVM_EPV_STATUS_OPEN 296 +#define LVM_EPV_TIME_CHECK 297 +#define LVM_EPV_WRITE_LSEEK 298 +#define LVM_EPV_WRITE_OPEN 299 +#define LVM_EPV_WRITE_PE_LSEEK 300 +#define LVM_EPV_WRITE_PE_OPEN 301 +#define LVM_EPV_WRITE_PE_SIZE 302 +#define LVM_EPV_WRITE_PE_WRITE 303 +#define LVM_EPV_WRITE_UUIDLIST_LSEEK 304 +#define LVM_EPV_WRITE_UUIDLIST_MALLOC 305 +#define LVM_EPV_WRITE_UUIDLIST_OPEN 306 +#define LVM_EPV_WRITE_UUIDLIST_WRITE 307 +#define LVM_EPV_WRITE_WRITE 308 +#define LVM_EREMOVE_RECURSIVE_MALLOC 309 +#define LVM_EREMOVE_RECURSIVE_OPENDIR 310 +#define LVM_ESIZE 311 +#define LVM_ESYSTEM_ID_SET_UNAME 312 +#define LVM_EVG_CFGBACKUP_FILE_EXISTS 313 +#define LVM_EVG_CFGBACKUP_MALLOC 314 +#define LVM_EVG_CFGBACKUP_OPEN 315 +#define LVM_EVG_CFGBACKUP_READ 316 +#define LVM_EVG_CFGBACKUP_RENAME 317 +#define LVM_EVG_CFGBACKUP_TMP_FILE 318 +#define LVM_EVG_CFGBACKUP_UNLINK 319 +#define LVM_EVG_CFGBACKUP_VG_CHECK_EXIST 320 +#define LVM_EVG_CFGBACKUP_VG_READ_WITH_PV_AND_LV 321 +#define LVM_EVG_CFGBACKUP_WRITE 322 +#define LVM_EVG_CFGRESTORE_FILE_EXISTS 323 +#define LVM_EVG_CFGRESTORE_LV_CHECK_CONSISTENCY 324 +#define LVM_EVG_CFGRESTORE_MALLOC 325 +#define LVM_EVG_CFGRESTORE_OPEN 326 +#define LVM_EVG_CFGRESTORE_PV_CHECK_CONSISTENCY 327 +#define LVM_EVG_CFGRESTORE_READ 328 +#define LVM_EVG_CFGRESTORE_VG_CHECK_CONSISTENCY 329 +#define LVM_EVG_CFGRESTORE_VG_CHECK_CONSISTENCY_WITH_PV_AND_LV 330 +#define LVM_EVG_CHECK_ACTIVE_ALL_VG_COUNT 331 +#define LVM_EVG_CHECK_ACTIVE_ALL_VG_MALLOC 332 +#define LVM_EVG_CHECK_ACTIVE_ALL_VG_NAMELIST 333 +#define LVM_EVG_CHECK_CONSISTENCY 334 +#define LVM_EVG_CHECK_CONSISTENCY_LV_CUR 335 +#define LVM_EVG_CHECK_CONSISTENCY_MAX_PE_PER_PV 336 +#define LVM_EVG_CHECK_CONSISTENCY_PE_ALLOCATED 337 +#define LVM_EVG_CHECK_CONSISTENCY_PE_SIZE 338 +#define LVM_EVG_CHECK_CONSISTENCY_PE_TOTAL 339 +#define LVM_EVG_CHECK_CONSISTENCY_PVG_TOTAL 340 +#define LVM_EVG_CHECK_CONSISTENCY_PV_ACT 341 +#define LVM_EVG_CHECK_CONSISTENCY_PV_CUR 342 +#define LVM_EVG_CHECK_CONSISTENCY_VGDA 343 +#define LVM_EVG_CHECK_CONSISTENCY_VG_ACCESS 344 +#define LVM_EVG_CHECK_CONSISTENCY_VG_NAME 345 +#define LVM_EVG_CHECK_CONSISTENCY_VG_STATUS 346 +#define LVM_EVG_CHECK_EXIST_PV_COUNT 347 +#define LVM_EVG_CHECK_NAME 348 +#define LVM_EVG_CHECK_ONLINE_ALL_PV 349 +#define LVM_EVG_CHECK_ONLINE_ALL_PV_MALLOC 350 +#define LVM_EVG_CHECK_PE_SIZE 351 +#define LVM_EVG_CREATE_DIR_AND_GROUP_CHMOD_DIR 352 +#define LVM_EVG_CREATE_DIR_AND_GROUP_CHMOD_GROUP 353 +#define LVM_EVG_CREATE_DIR_AND_GROUP_CHOWN_GROUP 354 +#define LVM_EVG_CREATE_DIR_AND_GROUP_MKDIR 355 +#define LVM_EVG_CREATE_DIR_AND_GROUP_MKNOD 356 +#define LVM_EVG_CREATE_REMOVE_OPEN 357 +#define LVM_EVG_EXTEND_REDUCE_OPEN 358 +#define LVM_EVG_READ_LSEEK 359 +#define LVM_EVG_READ_LVM_STRUCT_VERSION 360 +#define LVM_EVG_READ_OPEN 361 +#define LVM_EVG_READ_PV 362 +#define LVM_EVG_READ_READ 363 +#define LVM_EVG_READ_VG_EXPORTED 364 +#define LVM_EVG_READ_WITH_PV_AND_LV_LV_ALLOCATED_LE 365 +#define LVM_EVG_READ_WITH_PV_AND_LV_MALLOC 366 +#define LVM_EVG_READ_WITH_PV_AND_LV_PV_CUR 367 +#define LVM_EVG_RENAME_OPEN 368 +#define LVM_EVG_SETUP_FOR_CREATE_MALLOC 369 +#define LVM_EVG_SETUP_FOR_CREATE_PV_SIZE 370 +#define LVM_EVG_SETUP_FOR_CREATE_VG_NUMBER 371 +#define LVM_EVG_SETUP_FOR_EXTEND_MALLOC 372 +#define LVM_EVG_SETUP_FOR_EXTEND_MAX_PV 373 +#define LVM_EVG_SETUP_FOR_EXTEND_NO_PV 374 +#define LVM_EVG_SETUP_FOR_EXTEND_PV_ALREADY 375 +#define LVM_EVG_SETUP_FOR_EXTEND_PV_CHECK_NAME 376 +#define LVM_EVG_SETUP_FOR_EXTEND_PV_CHECK_NEW 377 +#define LVM_EVG_SETUP_FOR_EXTEND_PV_GET_SIZE 378 +#define LVM_EVG_SETUP_FOR_EXTEND_PV_SIZE 379 +#define LVM_EVG_SETUP_FOR_EXTEND_PV_SIZE_REL 380 +#define LVM_EVG_SETUP_FOR_MERGE_BLK_DEV 381 +#define LVM_EVG_SETUP_FOR_MERGE_LV_MAX 382 +#define LVM_EVG_SETUP_FOR_MERGE_PE_SIZE 383 +#define LVM_EVG_SETUP_FOR_MERGE_PV_MAX 384 +#define LVM_EVG_SETUP_FOR_MERGE_VG_CHECK_CONSISTENCY_WITH_PV_AND_LV 385 +#define LVM_EVG_SETUP_FOR_REDUCE_LAST_PV 386 +#define LVM_EVG_SETUP_FOR_REDUCE_LAST_PV_NOT_IN_VG 387 +#define LVM_EVG_SETUP_FOR_REDUCE_LV 388 +#define LVM_EVG_SETUP_FOR_REDUCE_NO_PV_TO_REDUCE 389 +#define LVM_EVG_SETUP_FOR_REDUCE_PV_INVALID 390 +#define LVM_EVG_SETUP_FOR_REDUCE_REALLOC 391 +#define LVM_EVG_SETUP_FOR_SPLIT_LV_ON_PV 392 +#define LVM_EVG_SETUP_FOR_SPLIT_MALLOC 393 +#define LVM_EVG_SETUP_FOR_SPLIT_PV 394 +#define LVM_EVG_SETUP_FOR_SPLIT_PV_COUNT 395 +#define LVM_EVG_SETUP_FOR_SPLIT_VG_NUMBER 396 +#define LVM_EVG_SET_CLEAR_EXTENDABLE_OPEN 397 +#define LVM_EVG_STATUS_GET_COUNT_OPEN 398 +#define LVM_EVG_STATUS_GET_NAMELIST_OPEN 399 +#define LVM_EVG_STATUS_MALLOC 400 +#define LVM_EVG_STATUS_OPEN 401 +#define LVM_EVG_WRITE_LSEEK 402 +#define LVM_EVG_WRITE_OPEN 403 +#define LVM_EVG_WRITE_WRITE 404 +#define LVM_ELV_PV_CREATE_NAME_FROM_KDEV_T 405 +#define LVM_EPV_FLUSH_STAT 406 + +#endif /* #ifndef _LIBLVM_H_INCLUDE */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/libxfs.h linux-2.4-xfs/cmd/xfsprogs/include/libxfs.h --- linux-2.4.7/cmd/xfsprogs/include/libxfs.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/libxfs.h Wed May 9 01:56:06 2001 @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __LIBXFS_H__ +#define __LIBXFS_H__ + +#include "platform_defs.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 +#include +#include + +/* + * Argument structure for libxfs_init(). + */ +typedef struct { + /* input parameters */ + char *volname; /* pathname of volume */ + char *dname; /* pathname of data "subvolume" */ + char *logname; /* pathname of log "subvolume" */ + char *rtname; /* pathname of realtime "subvolume" */ + int isreadonly; /* filesystem is only read in applic */ + int disfile; /* data "subvolume" is a regular file */ int dcreat; /* try to create data subvolume */ + int lisfile; /* log "subvolume" is a regular file */ + int lcreat; /* try to create log subvolume */ + int risfile; /* realtime "subvolume" is a reg file */ int rcreat; /* try to create realtime subvolume */ + char *notvolmsg; /* format string for not XLV message */ + int notvolok; /* set if not XLV => try data */ + /* output results */ + dev_t ddev; /* device for data subvolume */ + dev_t logdev; /* device for log subvolume */ + dev_t rtdev; /* device for realtime subvolume */ + long long dsize; /* size of data subvolume (BBs) */ + long long logBBsize; /* size of log subvolume (BBs) */ + /* (blocks allocated for use as + * log is stored in mount structure) */ + long long logBBstart; /* start block of log subvolume (BBs) */ long long rtsize; /* size of realtime subvolume (BBs) */ + int dfd; /* data subvolume file descriptor */ + int logfd; /* log subvolume file descriptor */ + int rtfd; /* realtime subvolume file descriptor */ + int setblksize; /* attempt to set device block size */ +} libxfs_init_t; + +#define LIBXFS_ISREADONLY 0x0069 /* disallow all mounted filesystems */ +#define LIBXFS_ISINACTIVE 0x6900 /* allow mounted only if mounted ro */ + +extern char *progname; +extern int libxfs_init (libxfs_init_t *); +extern int libxfs_device_to_fd (dev_t); +extern dev_t libxfs_device_open (char *, int, int, int); +extern void libxfs_device_zero (dev_t, xfs_daddr_t, uint); +extern void libxfs_device_close (dev_t); + +/* check or write log footer: specify device, log size in blocks & uuid */ +extern int libxfs_log_clear (dev_t, xfs_daddr_t, uint, uuid_t *, int); + +/* + * Define a user-level mount structure with all we need + * in order to make use of the numerous XFS_* macros. + */ +struct xfs_inode; +typedef struct xfs_mount { + xfs_sb_t m_sb; /* copy of fs superblock */ + int m_bsize; /* fs logical block size */ + xfs_agnumber_t m_agfrotor; /* last ag where space found */ + xfs_agnumber_t m_agirotor; /* last ag dir inode alloced */ + uint m_rsumlevels; /* rt summary levels */ + uint m_rsumsize; /* size of rt summary, bytes */ + struct xfs_inode *m_rbmip; /* pointer to bitmap inode */ + struct xfs_inode *m_rsumip; /* pointer to summary inode */ + struct xfs_inode *m_rootip; /* pointer to root directory */ + dev_t m_dev; + dev_t m_logdev; + dev_t m_rtdev; + __uint8_t m_dircook_elog; /* log d-cookie entry bits */ + __uint8_t m_blkbit_log; /* blocklog + NBBY */ + __uint8_t m_blkbb_log; /* blocklog - BBSHIFT */ + __uint8_t m_agno_log; /* log #ag's */ + __uint8_t m_agino_log; /* #bits for agino in inum */ + __uint16_t m_inode_cluster_size;/* min inode buf size */ + uint m_blockmask; /* sb_blocksize-1 */ + uint m_blockwsize; /* sb_blocksize in words */ + uint m_blockwmask; /* blockwsize-1 */ + uint m_alloc_mxr[2]; /* XFS_ALLOC_BLOCK_MAXRECS */ + uint m_alloc_mnr[2]; /* XFS_ALLOC_BLOCK_MINRECS */ + uint m_bmap_dmxr[2]; /* XFS_BMAP_BLOCK_DMAXRECS */ + uint m_bmap_dmnr[2]; /* XFS_BMAP_BLOCK_DMINRECS */ + uint m_inobt_mxr[2]; /* XFS_INOBT_BLOCK_MAXRECS */ + uint m_inobt_mnr[2]; /* XFS_INOBT_BLOCK_MINRECS */ + uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */ + uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */ + uint m_in_maxlevels; /* XFS_IN_MAXLEVELS */ + xfs_perag_t *m_perag; /* per-ag accounting info */ + uint m_flags; /* global mount flags */ + uint m_qflags; /* quota status flags */ + uint m_attroffset; /* inode attribute offset */ + int m_da_node_ents; /* how many entries in danode */ + int m_ialloc_inos; /* inodes in inode allocation */ + int m_ialloc_blks; /* blocks in inode allocation */ + int m_litino; /* size of inode union area */ + int m_inoalign_mask;/* mask sb_inoalignmt if used */ + xfs_trans_reservations_t m_reservations;/* precomputed res values */ + __uint64_t m_maxicount; /* maximum inode count */ + int m_dalign; /* stripe unit */ + int m_swidth; /* stripe width */ + int m_sinoalign; /* stripe unit inode alignmnt */ + int m_dir_magicpct; /* 37% of the dir blocksize */ + __uint8_t m_dirversion; /* 1 or 2 */ + int m_dirblksize; /* directory block sz--bytes */ + int m_dirblkfsbs; /* directory block sz--fsbs */ + xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */ + xfs_dablk_t m_dirleafblk; /* blockno of dir non-data v2 */ + xfs_dablk_t m_dirfreeblk; /* blockno of dirfreeindex v2 */ +} xfs_mount_t; + + +extern xfs_mount_t *libxfs_mount (xfs_mount_t *, xfs_sb_t *, + dev_t, dev_t, dev_t, int); +extern void libxfs_mount_common (xfs_mount_t *, xfs_sb_t *); +extern void libxfs_umount (xfs_mount_t *); +extern int libxfs_rtmount_init (xfs_mount_t *); +extern void libxfs_alloc_compute_maxlevels (xfs_mount_t *); +extern void libxfs_bmap_compute_maxlevels (xfs_mount_t *, int); +extern void libxfs_ialloc_compute_maxlevels (xfs_mount_t *); +extern void libxfs_trans_init (xfs_mount_t *); + + +/* + * Simple I/O interface + */ +typedef struct xfs_buf { + xfs_daddr_t b_blkno; + unsigned b_bcount; + dev_t b_dev; + void *b_fsprivate; + void *b_fsprivate2; + void *b_fsprivate3; + char *b_addr; + /* b_addr must be the last field */ +} xfs_buf_t; +#define XFS_BUF_PTR(bp) ((bp)->b_addr) +#define xfs_buf_offset(bp, offset) (XFS_BUF_PTR(bp) + (offset)) +#define XFS_BUF_ADDR(bp) ((bp)->b_blkno) +#define XFS_BUF_COUNT(bp) ((bp)->b_bcount) +#define XFS_BUF_TARGET(bp) ((bp)->b_dev) +#define XFS_BUF_SET_PTR(bp,p,cnt) ((bp)->b_addr = (char *)(p)); \ + XFS_BUF_SETCOUNT(bp,cnt) +#define XFS_BUF_SET_ADDR(bp,blk) ((bp)->b_blkno = (blk)) +#define XFS_BUF_SETCOUNT(bp,cnt) ((bp)->b_bcount = (cnt)) + +#define XFS_BUF_FSPRIVATE(bp,type) ((type)(bp)->b_fsprivate) +#define XFS_BUF_SET_FSPRIVATE(bp,val) (bp)->b_fsprivate = (void *)(val) +#define XFS_BUF_FSPRIVATE2(bp,type) ((type)(bp)->b_fsprivate2) +#define XFS_BUF_SET_FSPRIVATE2(bp,val) (bp)->b_fsprivate2 = (void *)(val) +#define XFS_BUF_FSPRIVATE3(bp,type) ((type)(bp)->b_fsprivate3) +#define XFS_BUF_SET_FSPRIVATE3(bp,val) (bp)->b_fsprivate3 = (void *)(val) + +extern xfs_buf_t *libxfs_getbuf (dev_t, xfs_daddr_t, int); +extern xfs_buf_t *libxfs_readbuf (dev_t, xfs_daddr_t, int, int); +extern xfs_buf_t *libxfs_getsb (xfs_mount_t *, int); +extern int libxfs_readbufr (dev_t, xfs_daddr_t, xfs_buf_t *, int, int); +extern int libxfs_writebuf (xfs_buf_t *, int); +extern int libxfs_writebuf_int (xfs_buf_t *, int); +extern void libxfs_putbuf (xfs_buf_t *); + + +/* + * Transaction interface + */ + +typedef struct xfs_log_item { + struct xfs_log_item_desc *li_desc; /* ptr to current desc*/ + struct xfs_mount *li_mountp; /* ptr to fs mount */ + uint li_type; /* item type */ +} xfs_log_item_t; + +typedef struct xfs_inode_log_item { + xfs_log_item_t ili_item; /* common portion */ + struct xfs_inode *ili_inode; /* inode pointer */ + unsigned short ili_flags; /* misc flags */ + unsigned int ili_last_fields; /* fields when flushed*/ + xfs_inode_log_format_t ili_format; /* logged structure */ +} xfs_inode_log_item_t; + +typedef struct xfs_buf_log_item { + xfs_log_item_t bli_item; /* common item structure */ + struct xfs_buf *bli_buf; /* real buffer pointer */ + unsigned int bli_flags; /* misc flags */ + unsigned int bli_recur; /* recursion count */ + xfs_buf_log_format_t bli_format; /* in-log header */ +} xfs_buf_log_item_t; + +#include + +typedef struct xfs_trans { + unsigned int t_type; /* transaction type */ + xfs_mount_t *t_mountp; /* ptr to fs mount struct */ + unsigned int t_flags; /* misc flags */ + long t_icount_delta; /* superblock icount change */ + long t_ifree_delta; /* superblock ifree change */ + long t_fdblocks_delta; /* superblock fdblocks chg */ + long t_frextents_delta; /* superblock freextents chg */ + unsigned int t_items_free; /* log item descs free */ + xfs_log_item_chunk_t t_items; /* first log item desc chunk */ +} xfs_trans_t; + +extern xfs_trans_t *libxfs_trans_alloc (xfs_mount_t *, int); +extern xfs_trans_t *libxfs_trans_dup (xfs_trans_t *); +extern int libxfs_trans_reserve (xfs_trans_t *, uint,uint,uint,uint,uint); +extern int libxfs_trans_commit (xfs_trans_t *, uint, xfs_lsn_t *); +extern void libxfs_trans_cancel (xfs_trans_t *, int); +extern void libxfs_mod_sb (xfs_trans_t *, __int64_t); + +extern int libxfs_trans_iget (xfs_mount_t *, xfs_trans_t *, xfs_ino_t, + uint, struct xfs_inode **); +extern void libxfs_trans_iput(xfs_trans_t *, struct xfs_inode *, uint); +extern void libxfs_trans_ijoin (xfs_trans_t *, struct xfs_inode *, uint); +extern void libxfs_trans_ihold (xfs_trans_t *, struct xfs_inode *); +extern void libxfs_trans_log_inode (xfs_trans_t *, struct xfs_inode *, + uint); + +extern void libxfs_trans_brelse (xfs_trans_t *, struct xfs_buf *); +extern void libxfs_trans_binval (xfs_trans_t *, struct xfs_buf *); +extern void libxfs_trans_bjoin (xfs_trans_t *, struct xfs_buf *); +extern void libxfs_trans_bhold (xfs_trans_t *, struct xfs_buf *); +extern void libxfs_trans_log_buf (xfs_trans_t *, struct xfs_buf *, + uint, uint); +extern xfs_buf_t *libxfs_trans_get_buf (xfs_trans_t *, dev_t, + xfs_daddr_t, int, uint); +extern int libxfs_trans_read_buf (xfs_mount_t *, xfs_trans_t *, dev_t, + xfs_daddr_t, int, uint, struct xfs_buf **); + + +/* + * Simple memory interface + */ +typedef struct xfs_zone { + int zone_unitsize; /* Size in bytes of zone unit */ + char *zone_name; /* tag name */ + int allocated; /* debug: How many currently allocated */ +} xfs_zone_t; + +extern xfs_zone_t *libxfs_zone_init (int, char *); +extern void *libxfs_zone_zalloc (xfs_zone_t *); +extern void libxfs_zone_free (xfs_zone_t *, void *); +extern void *libxfs_malloc (size_t); +extern void libxfs_free (void *); +extern void *libxfs_realloc (void *, size_t); + + +/* + * Inode interface + */ +struct xfs_inode_log_item; +typedef struct xfs_inode { + xfs_mount_t *i_mount; /* fs mount struct ptr */ + xfs_ino_t i_ino; /* inode number (agno/agino) */ + xfs_daddr_t i_blkno; /* blkno of inode buffer */ + dev_t i_dev; /* dev for this inode */ + ushort i_len; /* len of inode buffer */ + ushort i_boffset; /* off of inode in buffer */ + xfs_ifork_t *i_afp; /* attribute fork pointer */ + xfs_ifork_t i_df; /* data fork */ + struct xfs_trans *i_transp; /* ptr to owning transaction */ + struct xfs_inode_log_item *i_itemp; /* logging information */ + unsigned int i_delayed_blks; /* count of delay alloc blks */ + xfs_dinode_core_t i_d; /* most of ondisk inode */ +} xfs_inode_t; + +extern int libxfs_inode_alloc (xfs_trans_t **, xfs_inode_t *, mode_t, + ushort, dev_t, cred_t *, xfs_inode_t **); +extern void libxfs_trans_inode_alloc_buf (xfs_trans_t *, xfs_buf_t *); + +extern void libxfs_idata_realloc (xfs_inode_t *, int, int); +extern int libxfs_iread (xfs_mount_t *, xfs_trans_t *, xfs_ino_t, + xfs_inode_t **, xfs_daddr_t); +extern void libxfs_ichgtime (xfs_inode_t *, int); +extern int libxfs_iflush_int (xfs_inode_t *, xfs_buf_t *); +extern int libxfs_itobp (xfs_mount_t *, xfs_trans_t *, xfs_inode_t *, + xfs_dinode_t **, xfs_buf_t **, xfs_daddr_t); +extern int libxfs_iget (xfs_mount_t *, xfs_trans_t *, xfs_ino_t, + uint, xfs_inode_t **, xfs_daddr_t); +extern void libxfs_iput (xfs_inode_t *, uint); + + +/* + * Directory interface + */ +extern void libxfs_dir_mount (xfs_mount_t *); +extern void libxfs_dir2_mount (xfs_mount_t *); +extern int libxfs_dir_init (xfs_trans_t *, xfs_inode_t *, xfs_inode_t *); +extern int libxfs_dir2_init (xfs_trans_t *, xfs_inode_t *, xfs_inode_t *); +extern int libxfs_dir_createname (xfs_trans_t *, xfs_inode_t *, char *, + int, xfs_ino_t, xfs_fsblock_t *, + xfs_bmap_free_t *, xfs_extlen_t); +extern int libxfs_dir2_createname (xfs_trans_t *, xfs_inode_t *, char *, + int, xfs_ino_t, xfs_fsblock_t *, + xfs_bmap_free_t *, xfs_extlen_t); +extern int libxfs_dir_lookup (xfs_trans_t *, xfs_inode_t *, + char *, int, xfs_ino_t *); +extern int libxfs_dir2_lookup (xfs_trans_t *, xfs_inode_t *, + char *, int, xfs_ino_t *); +extern int libxfs_dir_replace (xfs_trans_t *, xfs_inode_t *, + char *, int, xfs_ino_t, xfs_fsblock_t *, + xfs_bmap_free_t *, xfs_extlen_t); +extern int libxfs_dir2_replace (xfs_trans_t *, xfs_inode_t *, + char *, int, xfs_ino_t, xfs_fsblock_t *, + xfs_bmap_free_t *, xfs_extlen_t); +extern int libxfs_dir_removename (xfs_trans_t *, xfs_inode_t *, + char *, int, xfs_ino_t, xfs_fsblock_t *, + xfs_bmap_free_t *, xfs_extlen_t); +extern int libxfs_dir2_removename (xfs_trans_t *, xfs_inode_t *, + char *, int, xfs_ino_t, xfs_fsblock_t *, + xfs_bmap_free_t *, xfs_extlen_t); +extern int libxfs_dir_bogus_removename (xfs_trans_t *, xfs_inode_t *, + char *, xfs_fsblock_t *, xfs_bmap_free_t *, + xfs_extlen_t, xfs_dahash_t, int); +extern int libxfs_dir2_bogus_removename (xfs_trans_t *, xfs_inode_t *, + char *, xfs_fsblock_t *, xfs_bmap_free_t *, + xfs_extlen_t, xfs_dahash_t, int); + + +/* + * Block map interface + */ +extern int libxfs_bmapi (xfs_trans_t *, xfs_inode_t *, xfs_fileoff_t, + xfs_filblks_t, int, xfs_fsblock_t *, + xfs_extlen_t, xfs_bmbt_irec_t *, int *, + xfs_bmap_free_t *); +extern int libxfs_bmap_finish (xfs_trans_t **, xfs_bmap_free_t *, + xfs_fsblock_t, int *); +extern int libxfs_bmap_next_offset (xfs_trans_t *, xfs_inode_t *, + xfs_fileoff_t *, int); +extern int libxfs_bunmapi (xfs_trans_t *, xfs_inode_t *, xfs_fileoff_t, + xfs_filblks_t, int, xfs_extnum_t, + xfs_fsblock_t *, xfs_bmap_free_t *, int *); +extern void libxfs_bmap_del_free (xfs_bmap_free_t *, + xfs_bmap_free_item_t *, xfs_bmap_free_item_t *); + + +/* + * All other routines we want to keep common... + */ + +extern int libxfs_highbit32 (__uint32_t); +extern int libxfs_highbit64 (__uint64_t); +extern uint libxfs_da_log2_roundup (uint); + +extern void libxfs_xlate_sb (void *, xfs_sb_t *, int, xfs_arch_t, + __int64_t); +extern void libxfs_xlate_dinode_core (xfs_caddr_t buf, + xfs_dinode_core_t *, int, xfs_arch_t); + +extern int libxfs_alloc_fix_freelist (xfs_alloc_arg_t *, int); +extern int libxfs_alloc_file_space (xfs_inode_t *, xfs_off_t, + xfs_off_t, int, int); + +extern xfs_dahash_t libxfs_da_hashname (char *, int); +extern int libxfs_attr_leaf_newentsize (xfs_da_args_t *, int, int *); + +extern xfs_filblks_t libxfs_bmbt_get_blockcount (xfs_bmbt_rec_t *); +extern xfs_fileoff_t libxfs_bmbt_get_startoff (xfs_bmbt_rec_t *); +extern void libxfs_bmbt_get_all (xfs_bmbt_rec_t *, xfs_bmbt_irec_t *); + +extern int libxfs_free_extent (xfs_trans_t *, xfs_fsblock_t, xfs_extlen_t); +extern int libxfs_rtfree_extent (xfs_trans_t *, xfs_rtblock_t, + xfs_extlen_t); + +/* Directory/Attribute routines used by xfs_repair */ +extern void libxfs_da_bjoin (xfs_trans_t *, xfs_dabuf_t *); +extern int libxfs_da_shrink_inode (xfs_da_args_t *, xfs_dablk_t, + xfs_dabuf_t *); +extern int libxfs_da_grow_inode (xfs_da_args_t *, xfs_dablk_t *); +extern void libxfs_da_bhold (xfs_trans_t *, xfs_dabuf_t *); +extern void libxfs_da_brelse (xfs_trans_t *, xfs_dabuf_t *); +extern int libxfs_da_read_bufr (xfs_trans_t *, xfs_inode_t *, xfs_dablk_t, + xfs_daddr_t, xfs_dabuf_t **, int); +extern int libxfs_da_read_buf (xfs_trans_t *, xfs_inode_t *, + xfs_dablk_t, xfs_daddr_t, xfs_dabuf_t **, int); +extern int libxfs_da_get_buf (xfs_trans_t *, xfs_inode_t *, + xfs_dablk_t, xfs_daddr_t, xfs_dabuf_t **, int); +extern void libxfs_da_log_buf (xfs_trans_t *, xfs_dabuf_t *, uint, uint); +extern int libxfs_dir2_shrink_inode (xfs_da_args_t *, xfs_dir2_db_t, + xfs_dabuf_t *); +extern int libxfs_dir2_grow_inode (xfs_da_args_t *, int, xfs_dir2_db_t *); +extern int libxfs_dir2_isleaf (xfs_trans_t *, xfs_inode_t *, int *); +extern int libxfs_dir2_isblock (xfs_trans_t *, xfs_inode_t *, int *); +extern void libxfs_dir2_data_use_free (xfs_trans_t *, xfs_dabuf_t *, + xfs_dir2_data_unused_t *, xfs_dir2_data_aoff_t, + xfs_dir2_data_aoff_t, int *, int *); +extern void libxfs_dir2_data_make_free (xfs_trans_t *, xfs_dabuf_t *, + xfs_dir2_data_aoff_t, xfs_dir2_data_aoff_t, + int *, int *); +extern void libxfs_dir2_data_log_entry (xfs_trans_t *, xfs_dabuf_t *, + xfs_dir2_data_entry_t *); +extern void libxfs_dir2_data_log_header (xfs_trans_t *, xfs_dabuf_t *); +extern void libxfs_dir2_data_freescan (xfs_mount_t *, xfs_dir2_data_t *, + int *, char *); +extern void libxfs_dir2_free_log_bests (xfs_trans_t *, xfs_dabuf_t *, + int, int); + +/* Shared utility routines */ +extern unsigned int libxfs_log2_roundup(unsigned int i); + +#endif /* __LIBXFS_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/lvm.h linux-2.4-xfs/cmd/xfsprogs/include/lvm.h --- linux-2.4.7/cmd/xfsprogs/include/lvm.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/lvm.h Tue Mar 20 14:10:08 2001 @@ -0,0 +1,858 @@ +/* + * include/linux/lvm.h + * kernel/lvm.h + * tools/lib/lvm.h + * + * Copyright (C) 1997 - 2001 Heinz Mauelshagen, Sistina Software + * + * February-November 1997 + * May-July 1998 + * January-March,July,September,October,Dezember 1999 + * January,February,July,November 2000 + * January-March 2001 + * + * lvm is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * lvm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/* + * Changelog + * + * 10/10/1997 - beginning of new structure creation + * 12/05/1998 - incorporated structures from lvm_v1.h and deleted lvm_v1.h + * 07/06/1998 - avoided LVM_KMALLOC_MAX define by using vmalloc/vfree + * instead of kmalloc/kfree + * 01/07/1998 - fixed wrong LVM_MAX_SIZE + * 07/07/1998 - extended pe_t structure by ios member (for statistic) + * 02/08/1998 - changes for official char/block major numbers + * 07/08/1998 - avoided init_module() and cleanup_module() to be static + * 29/08/1998 - seprated core and disk structure type definitions + * 01/09/1998 - merged kernel integration version (mike) + * 20/01/1999 - added LVM_PE_DISK_OFFSET macro for use in + * vg_read_with_pv_and_lv(), pv_move_pe(), pv_show_pe_text()... + * 18/02/1999 - added definition of time_disk_t structure for; + * keeps time stamps on disk for nonatomic writes (future) + * 15/03/1999 - corrected LV() and VG() macro definition to use argument + * instead of minor + * 03/07/1999 - define for genhd.c name handling + * 23/07/1999 - implemented snapshot part + * 08/12/1999 - changed LVM_LV_SIZE_MAX macro to reflect current 1TB limit + * 01/01/2000 - extended lv_v2 core structure by wait_queue member + * 12/02/2000 - integrated Andrea Arcagnelli's snapshot work + * 18/02/2000 - seperated user and kernel space parts by + * #ifdef them with __KERNEL__ + * 08/03/2000 - implemented cluster/shared bits for vg_access + * 26/06/2000 - implemented snapshot persistency and resizing support + * 02/11/2000 - added hash table size member to lv structure + * 12/11/2000 - removed unneeded timestamp definitions + * 24/12/2000 - removed LVM_TO_{CORE,DISK}*, use cpu_{from, to}_le* + * instead - Christoph Hellwig + * 22/01/2001 - Change ulong to uint32_t + * 14/02/2001 - changed LVM_SNAPSHOT_MIN_CHUNK to 1 page + * 20/02/2001 - incremented IOP version to 11 because of incompatible + * change in VG activation (in order to support devfs better) + * 01/03/2001 - Revert to IOP10 and add VG_CREATE_OLD call for compatibility + * 08/03/2001 - new lv_t (in core) version number 5: changed page member + * to (struct kiobuf *) to use for COW exception table io + * + */ + + +#ifndef _LVM_H_INCLUDE +#define _LVM_H_INCLUDE + +#define LVM_RELEASE_NAME "0.9.1_beta6" +#define LVM_RELEASE_DATE "12/03/2001" + +#define _LVM_KERNEL_H_VERSION "LVM "LVM_RELEASE_NAME" ("LVM_RELEASE_DATE")" + +#include + +/* + * preprocessor definitions + */ +/* if you like emergency reset code in the driver */ +#define LVM_TOTAL_RESET + +#ifdef __KERNEL__ +#undef LVM_HD_NAME /* display nice names in /proc/partitions */ + +/* lots of debugging output (see driver source) + #define DEBUG_LVM_GET_INFO + #define DEBUG + #define DEBUG_MAP + #define DEBUG_MAP_SIZE + #define DEBUG_IOCTL + #define DEBUG_READ + #define DEBUG_GENDISK + #define DEBUG_VG_CREATE + #define DEBUG_DEVICE + #define DEBUG_KFREE + */ +#endif /* #ifdef __KERNEL__ */ + +#ifndef __KERNEL__ +#define __KERNEL__ +#include +#include +#undef __KERNEL__ +#else +#include +#include +#endif /* #ifndef __KERNEL__ */ + +#include +#include + +#ifdef __KERNEL__ +#if LINUX_VERSION_CODE >= KERNEL_VERSION ( 2, 3 ,0) +#include +#else +#include +#endif + +#include +#endif /* #ifdef __KERNEL__ */ + +#include + +#if !defined ( LVM_BLK_MAJOR) || !defined ( LVM_CHAR_MAJOR) +#error Bad include/linux/major.h - LVM MAJOR undefined +#endif + +#ifdef BLOCK_SIZE +#undef BLOCK_SIZE +#endif + +#ifdef CONFIG_ARCH_S390 +#define BLOCK_SIZE 4096 +#else +#define BLOCK_SIZE 512 +#endif + +#ifndef SECTOR_SIZE +#define SECTOR_SIZE 512 +#endif + +#define LVM_STRUCT_VERSION 1 /* structure version */ + +#define LVM_DIR_PREFIX "/dev/" + +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef max +#define max(a,b) (((a)>(b))?(a):(b)) +#endif + +/* set the default structure version */ +#if ( LVM_STRUCT_VERSION == 1) +#define pv_t pv_v2_t +#define lv_t lv_v5_t +#define vg_t vg_v3_t +#define pv_disk_t pv_disk_v2_t +#define lv_disk_t lv_disk_v3_t +#define vg_disk_t vg_disk_v2_t +#define lv_block_exception_t lv_block_exception_v1_t +#define lv_COW_table_disk_t lv_COW_table_disk_v1_t +#endif + + + +/* + * i/o protocol version + * + * defined here for the driver and defined seperate in the + * user land tools/lib/liblvm.h + * + */ +#define LVM_DRIVER_IOP_VERSION 10 + +#define LVM_NAME "lvm" +#define LVM_GLOBAL "global" +#define LVM_DIR "lvm" +#define LVM_VG_SUBDIR "VGs" +#define LVM_LV_SUBDIR "LVs" +#define LVM_PV_SUBDIR "PVs" + +/* + * VG/LV indexing macros + */ +/* character minor maps directly to volume group */ +#define VG_CHR(a) ( a) + +/* block minor indexes into a volume group/logical volume indirection table */ +#define VG_BLK(a) ( vg_lv_map[a].vg_number) +#define LV_BLK(a) ( vg_lv_map[a].lv_number) + +/* + * absolute limits for VGs, PVs per VG and LVs per VG + */ +#define ABS_MAX_VG 99 +#define ABS_MAX_PV 256 +#define ABS_MAX_LV 256 /* caused by 8 bit minor */ + +#define MAX_VG ABS_MAX_VG +#define MAX_LV ABS_MAX_LV +#define MAX_PV ABS_MAX_PV + +#if ( MAX_VG > ABS_MAX_VG) +#undef MAX_VG +#define MAX_VG ABS_MAX_VG +#endif + +#if ( MAX_LV > ABS_MAX_LV) +#undef MAX_LV +#define MAX_LV ABS_MAX_LV +#endif + + +/* + * VGDA: default disk spaces and offsets + * + * there's space after the structures for later extensions. + * + * offset what size + * --------------- ---------------------------------- ------------ + * 0 physical volume structure ~500 byte + * + * 1K volume group structure ~200 byte + * + * 6K namelist of physical volumes 128 byte each + * + * 6k + n * ~300byte n logical volume structures ~300 byte each + * + * + m * 4byte m physical extent alloc. structs 4 byte each + * + * End of disk - first physical extent typically 4 megabyte + * PE total * + * PE size + * + * + */ + +/* DONT TOUCH THESE !!! */ +/* base of PV structure in disk partition */ +#define LVM_PV_DISK_BASE 0L + +/* size reserved for PV structure on disk */ +#define LVM_PV_DISK_SIZE 1024L + +/* base of VG structure in disk partition */ +#define LVM_VG_DISK_BASE LVM_PV_DISK_SIZE + +/* size reserved for VG structure */ +#define LVM_VG_DISK_SIZE ( 9 * 512L) + +/* size reserved for timekeeping */ +#define LVM_TIMESTAMP_DISK_BASE ( LVM_VG_DISK_BASE + LVM_VG_DISK_SIZE) +#define LVM_TIMESTAMP_DISK_SIZE 512L /* reserved for timekeeping */ + +/* name list of physical volumes on disk */ +#define LVM_PV_UUIDLIST_DISK_BASE ( LVM_TIMESTAMP_DISK_BASE + \ + LVM_TIMESTAMP_DISK_SIZE) + +/* now for the dynamically calculated parts of the VGDA */ +#define LVM_LV_DISK_OFFSET(a, b) ( (a)->lv_on_disk.base + \ + sizeof ( lv_disk_t) * b) +#define LVM_DISK_SIZE(pv) ( (pv)->pe_on_disk.base + \ + (pv)->pe_on_disk.size) +#define LVM_PE_DISK_OFFSET(pe, pv) ( pe * pv->pe_size + \ + ( LVM_DISK_SIZE ( pv) / SECTOR_SIZE)) +#define LVM_PE_ON_DISK_BASE(pv) \ + { int rest; \ + pv->pe_on_disk.base = pv->lv_on_disk.base + pv->lv_on_disk.size; \ + if ( ( rest = pv->pe_on_disk.base % SECTOR_SIZE) != 0) \ + pv->pe_on_disk.base += ( SECTOR_SIZE - rest); \ + } +/* END default disk spaces and offsets for PVs */ + + +/* + * LVM_PE_T_MAX corresponds to: + * + * 8KB PE size can map a ~512 MB logical volume at the cost of 1MB memory, + * + * 128MB PE size can map a 8TB logical volume at the same cost of memory. + * + * Default PE size of 4 MB gives a maximum logical volume size of 256 GB. + * + * Maximum PE size of 16GB gives a maximum logical volume size of 1024 TB. + * + * AFAIK, the actual kernels limit this to 1 TB. + * + * Should be a sufficient spectrum ;*) + */ + +/* This is the usable size of pe_disk_t.le_num !!! v v */ +#define LVM_PE_T_MAX ( ( 1 << ( sizeof ( uint16_t) * 8)) - 2) + +#define LVM_LV_SIZE_MAX(a) ( ( long long) LVM_PE_T_MAX * (a)->pe_size > ( long long) 1024*1024/SECTOR_SIZE*1024*1024 ? ( long long) 1024*1024/SECTOR_SIZE*1024*1024 : ( long long) LVM_PE_T_MAX * (a)->pe_size) +#define LVM_MIN_PE_SIZE ( 8192L / SECTOR_SIZE) /* 8 KB in sectors */ +#define LVM_MAX_PE_SIZE ( 16L * 1024L * 1024L / SECTOR_SIZE * 1024) /* 16GB in sectors */ +#define LVM_DEFAULT_PE_SIZE ( 4096L * 1024 / SECTOR_SIZE) /* 4 MB in sectors */ +#define LVM_DEFAULT_STRIPE_SIZE 16L /* 16 KB */ +#define LVM_MIN_STRIPE_SIZE ( PAGE_SIZE/SECTOR_SIZE) /* PAGESIZE in sectors */ +#define LVM_MAX_STRIPE_SIZE ( 512L * 1024 / SECTOR_SIZE) /* 512 KB in sectors */ +#define LVM_MAX_STRIPES 128 /* max # of stripes */ +#define LVM_MAX_SIZE ( 1024LU * 1024 / SECTOR_SIZE * 1024 * 1024) /* 1TB[sectors] */ +#define LVM_MAX_MIRRORS 2 /* future use */ +#define LVM_MIN_READ_AHEAD 2 /* minimum read ahead sectors */ +#define LVM_MAX_READ_AHEAD 120 /* maximum read ahead sectors */ +#define LVM_MAX_LV_IO_TIMEOUT 60 /* seconds I/O timeout (future use) */ +#define LVM_PARTITION 0xfe /* LVM partition id */ +#define LVM_NEW_PARTITION 0x8e /* new LVM partition id (10/09/1999) */ +#define LVM_PE_SIZE_PV_SIZE_REL 5 /* max relation PV size and PE size */ + +#define LVM_SNAPSHOT_MAX_CHUNK 1024 /* 1024 KB */ +#define LVM_SNAPSHOT_DEF_CHUNK 64 /* 64 KB */ +#define LVM_SNAPSHOT_MIN_CHUNK (PAGE_SIZE/1024) /* 4 or 8 KB */ + +#define UNDEF -1 +#define FALSE 0 +#define TRUE 1 + + +#define LVM_GET_COW_TABLE_CHUNKS_PER_PE(vg, lv) ( \ + vg->pe_size / lv->lv_chunk_size) + +#define LVM_GET_COW_TABLE_ENTRIES_PER_PE(vg, lv) ( \ +{ \ + int COW_table_entries_per_PE; \ + int COW_table_chunks_per_PE; \ +\ + COW_table_entries_per_PE = LVM_GET_COW_TABLE_CHUNKS_PER_PE(vg, lv); \ + COW_table_chunks_per_PE = ( COW_table_entries_per_PE * sizeof(lv_COW_table_disk_t) / SECTOR_SIZE + lv->lv_chunk_size - 1) / lv->lv_chunk_size; \ + COW_table_entries_per_PE - COW_table_chunks_per_PE;}) + + +/* + * ioctls + */ +/* volume group */ +#define VG_CREATE_OLD _IOW ( 0xfe, 0x00, 1) +#define VG_REMOVE _IOW ( 0xfe, 0x01, 1) + +#define VG_EXTEND _IOW ( 0xfe, 0x03, 1) +#define VG_REDUCE _IOW ( 0xfe, 0x04, 1) + +#define VG_STATUS _IOWR ( 0xfe, 0x05, 1) +#define VG_STATUS_GET_COUNT _IOWR ( 0xfe, 0x06, 1) +#define VG_STATUS_GET_NAMELIST _IOWR ( 0xfe, 0x07, 1) + +#define VG_SET_EXTENDABLE _IOW ( 0xfe, 0x08, 1) +#define VG_RENAME _IOW ( 0xfe, 0x09, 1) + +/* Since 0.9beta6 */ +#define VG_CREATE _IOW ( 0xfe, 0x0a, 1) + +/* logical volume */ +#define LV_CREATE _IOW ( 0xfe, 0x20, 1) +#define LV_REMOVE _IOW ( 0xfe, 0x21, 1) + +#define LV_ACTIVATE _IO ( 0xfe, 0x22) +#define LV_DEACTIVATE _IO ( 0xfe, 0x23) + +#define LV_EXTEND _IOW ( 0xfe, 0x24, 1) +#define LV_REDUCE _IOW ( 0xfe, 0x25, 1) + +#define LV_STATUS_BYNAME _IOWR ( 0xfe, 0x26, 1) +#define LV_STATUS_BYINDEX _IOWR ( 0xfe, 0x27, 1) + +#define LV_SET_ACCESS _IOW ( 0xfe, 0x28, 1) +#define LV_SET_ALLOCATION _IOW ( 0xfe, 0x29, 1) +#define LV_SET_STATUS _IOW ( 0xfe, 0x2a, 1) + +#define LE_REMAP _IOW ( 0xfe, 0x2b, 1) + +#define LV_SNAPSHOT_USE_RATE _IOWR ( 0xfe, 0x2c, 1) + +#define LV_STATUS_BYDEV _IOWR ( 0xfe, 0x2e, 1) + +#define LV_RENAME _IOW ( 0xfe, 0x2f, 1) + +#define LV_BMAP _IOWR ( 0xfe, 0x30, 1) + + +/* physical volume */ +#define PV_STATUS _IOWR ( 0xfe, 0x40, 1) +#define PV_CHANGE _IOWR ( 0xfe, 0x41, 1) +#define PV_FLUSH _IOW ( 0xfe, 0x42, 1) + +/* physical extent */ +#define PE_LOCK_UNLOCK _IOW ( 0xfe, 0x50, 1) + +/* i/o protocol version */ +#define LVM_GET_IOP_VERSION _IOR ( 0xfe, 0x98, 1) + +#ifdef LVM_TOTAL_RESET +/* special reset function for testing purposes */ +#define LVM_RESET _IO ( 0xfe, 0x99) +#endif + +/* lock the logical volume manager */ +#define LVM_LOCK_LVM _IO ( 0xfe, 0x100) +/* END ioctls */ + + +/* + * Status flags + */ +/* volume group */ +#define VG_ACTIVE 0x01 /* vg_status */ +#define VG_EXPORTED 0x02 /* " */ +#define VG_EXTENDABLE 0x04 /* " */ + +#define VG_READ 0x01 /* vg_access */ +#define VG_WRITE 0x02 /* " */ +#define VG_CLUSTERED 0x04 /* " */ +#define VG_SHARED 0x08 /* " */ + +/* logical volume */ +#define LV_ACTIVE 0x01 /* lv_status */ +#define LV_SPINDOWN 0x02 /* " */ + +#define LV_READ 0x01 /* lv_access */ +#define LV_WRITE 0x02 /* " */ +#define LV_SNAPSHOT 0x04 /* " */ +#define LV_SNAPSHOT_ORG 0x08 /* " */ + +#define LV_BADBLOCK_ON 0x01 /* lv_badblock */ + +#define LV_STRICT 0x01 /* lv_allocation */ +#define LV_CONTIGUOUS 0x02 /* " */ + +/* physical volume */ +#define PV_ACTIVE 0x01 /* pv_status */ +#define PV_ALLOCATABLE 0x02 /* pv_allocatable */ + + +/* misc */ +#define LVM_SNAPSHOT_DROPPED_SECTOR 1 + +/* + * Structure definitions core/disk follow + * + * conditional conversion takes place on big endian architectures + * in functions * pv_copy_*(), vg_copy_*() and lv_copy_*() + * + */ + +#define NAME_LEN 128 /* don't change!!! */ +#define UUID_LEN 32 /* don't change!!! */ + +/* copy on write tables in disk format */ +typedef struct { + uint64_t pv_org_number; + uint64_t pv_org_rsector; + uint64_t pv_snap_number; + uint64_t pv_snap_rsector; +} lv_COW_table_disk_v1_t; + +/* remap physical sector/rdev pairs including hash */ +typedef struct { + struct list_head hash; + uint32_t rsector_org; + kdev_t rdev_org; + uint32_t rsector_new; + kdev_t rdev_new; +} lv_block_exception_v1_t; + +/* disk stored pe information */ +typedef struct { + uint16_t lv_num; + uint16_t le_num; +} pe_disk_t; + +/* disk stored PV, VG, LV and PE size and offset information */ +typedef struct { + uint32_t base; + uint32_t size; +} lvm_disk_data_t; + + +/* + * Structure Physical Volume (PV) Version 1 + */ + +/* core */ +typedef struct { + char id[2]; /* Identifier */ + unsigned short version; /* HM lvm version */ + lvm_disk_data_t pv_on_disk; + lvm_disk_data_t vg_on_disk; + lvm_disk_data_t pv_namelist_on_disk; + lvm_disk_data_t lv_on_disk; + lvm_disk_data_t pe_on_disk; + char pv_name[NAME_LEN]; + char vg_name[NAME_LEN]; + char system_id[NAME_LEN]; /* for vgexport/vgimport */ + kdev_t pv_dev; + uint pv_number; + uint pv_status; + uint pv_allocatable; + uint pv_size; /* HM */ + uint lv_cur; + uint pe_size; + uint pe_total; + uint pe_allocated; + uint pe_stale; /* for future use */ + pe_disk_t *pe; /* HM */ + struct inode *inode; /* HM */ +} pv_v1_t; + +/* core */ +typedef struct { + char id[2]; /* Identifier */ + unsigned short version; /* HM lvm version */ + lvm_disk_data_t pv_on_disk; + lvm_disk_data_t vg_on_disk; + lvm_disk_data_t pv_uuidlist_on_disk; + lvm_disk_data_t lv_on_disk; + lvm_disk_data_t pe_on_disk; + char pv_name[NAME_LEN]; + char vg_name[NAME_LEN]; + char system_id[NAME_LEN]; /* for vgexport/vgimport */ + kdev_t pv_dev; + uint pv_number; + uint pv_status; + uint pv_allocatable; + uint pv_size; /* HM */ + uint lv_cur; + uint pe_size; + uint pe_total; + uint pe_allocated; + uint pe_stale; /* for future use */ + pe_disk_t *pe; /* HM */ + struct inode *inode; /* HM */ + char pv_uuid[UUID_LEN+1]; +} pv_v2_t; + + +/* disk */ +typedef struct { + uint8_t id[2]; /* Identifier */ + uint16_t version; /* HM lvm version */ + lvm_disk_data_t pv_on_disk; + lvm_disk_data_t vg_on_disk; + lvm_disk_data_t pv_namelist_on_disk; + lvm_disk_data_t lv_on_disk; + lvm_disk_data_t pe_on_disk; + uint8_t pv_name[NAME_LEN]; + uint8_t vg_name[NAME_LEN]; + uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */ + uint32_t pv_major; + uint32_t pv_number; + uint32_t pv_status; + uint32_t pv_allocatable; + uint32_t pv_size; /* HM */ + uint32_t lv_cur; + uint32_t pe_size; + uint32_t pe_total; + uint32_t pe_allocated; +} pv_disk_v1_t; + +/* disk */ +typedef struct { + uint8_t id[2]; /* Identifier */ + uint16_t version; /* HM lvm version */ + lvm_disk_data_t pv_on_disk; + lvm_disk_data_t vg_on_disk; + lvm_disk_data_t pv_uuidlist_on_disk; + lvm_disk_data_t lv_on_disk; + lvm_disk_data_t pe_on_disk; + uint8_t pv_uuid[NAME_LEN]; + uint8_t vg_name[NAME_LEN]; + uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */ + uint32_t pv_major; + uint32_t pv_number; + uint32_t pv_status; + uint32_t pv_allocatable; + uint32_t pv_size; /* HM */ + uint32_t lv_cur; + uint32_t pe_size; + uint32_t pe_total; + uint32_t pe_allocated; +} pv_disk_v2_t; + + +/* + * Structures for Logical Volume (LV) + */ + +/* core PE information */ +typedef struct { + kdev_t dev; + uint32_t pe; /* to be changed if > 2TB */ + uint32_t reads; + uint32_t writes; +} pe_t; + +typedef struct { + char lv_name[NAME_LEN]; + kdev_t old_dev; + kdev_t new_dev; + uint32_t old_pe; + uint32_t new_pe; +} le_remap_req_t; + +typedef struct lv_bmap { + uint32_t lv_block; + dev_t lv_dev; +} lv_bmap_t; + +/* + * Structure Logical Volume (LV) Version 3 + */ + +/* core */ +typedef struct lv_v4 { + char lv_name[NAME_LEN]; + char vg_name[NAME_LEN]; + uint lv_access; + uint lv_status; + uint lv_open; /* HM */ + kdev_t lv_dev; /* HM */ + uint lv_number; /* HM */ + uint lv_mirror_copies; /* for future use */ + uint lv_recovery; /* " */ + uint lv_schedule; /* " */ + uint lv_size; + pe_t *lv_current_pe; /* HM */ + uint lv_current_le; /* for future use */ + uint lv_allocated_le; + uint lv_stripes; + uint lv_stripesize; + uint lv_badblock; /* for future use */ + uint lv_allocation; + uint lv_io_timeout; /* for future use */ + uint lv_read_ahead; + + /* delta to version 1 starts here */ + struct lv_v4 *lv_snapshot_org; + struct lv_v4 *lv_snapshot_prev; + struct lv_v4 *lv_snapshot_next; + lv_block_exception_t *lv_block_exception; + uint lv_remap_ptr; + uint lv_remap_end; + uint lv_chunk_size; + uint lv_snapshot_minor; +#ifdef __KERNEL__ + struct kiobuf *lv_iobuf; + struct kiobuf *lv_COW_table_iobuf; + struct semaphore lv_snapshot_sem; + struct list_head *lv_snapshot_hash_table; + uint32_t lv_snapshot_hash_table_size; + uint32_t lv_snapshot_hash_mask; +#if LINUX_VERSION_CODE > KERNEL_VERSION ( 2, 3, 0) + wait_queue_head_t lv_snapshot_wait; +#else + struct wait_queue *lv_snapshot_wait; +#endif + int lv_snapshot_use_rate; + void *vg; + + uint lv_allocated_snapshot_le; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) + struct buffer_head **bheads; +#endif +#else + char dummy[200]; +#endif +} lv_v5_t; + +/* disk */ +typedef struct { + uint8_t lv_name[NAME_LEN]; + uint8_t vg_name[NAME_LEN]; + uint32_t lv_access; + uint32_t lv_status; + uint32_t lv_open; /* HM */ + uint32_t lv_dev; /* HM */ + uint32_t lv_number; /* HM */ + uint32_t lv_mirror_copies; /* for future use */ + uint32_t lv_recovery; /* " */ + uint32_t lv_schedule; /* " */ + uint32_t lv_size; + uint32_t lv_snapshot_minor;/* minor number of original */ + uint16_t lv_chunk_size; /* chunk size of snapshot */ + uint16_t dummy; + uint32_t lv_allocated_le; + uint32_t lv_stripes; + uint32_t lv_stripesize; + uint32_t lv_badblock; /* for future use */ + uint32_t lv_allocation; + uint32_t lv_io_timeout; /* for future use */ + uint32_t lv_read_ahead; /* HM */ +} lv_disk_v3_t; + +/* + * Structure Volume Group (VG) Version 1 + */ + +/* core */ +typedef struct { + char vg_name[NAME_LEN]; /* volume group name */ + uint vg_number; /* volume group number */ + uint vg_access; /* read/write */ + uint vg_status; /* active or not */ + uint lv_max; /* maximum logical volumes */ + uint lv_cur; /* current logical volumes */ + uint lv_open; /* open logical volumes */ + uint pv_max; /* maximum physical volumes */ + uint pv_cur; /* current physical volumes FU */ + uint pv_act; /* active physical volumes */ + uint dummy; /* was obsolete max_pe_per_pv */ + uint vgda; /* volume group descriptor arrays FU */ + uint pe_size; /* physical extent size in sectors */ + uint pe_total; /* total of physical extents */ + uint pe_allocated; /* allocated physical extents */ + uint pvg_total; /* physical volume groups FU */ + struct proc_dir_entry *proc; + pv_t *pv[ABS_MAX_PV + 1]; /* physical volume struct pointers */ + lv_t *lv[ABS_MAX_LV + 1]; /* logical volume struct pointers */ +} vg_v1_t; + +typedef struct { + char vg_name[NAME_LEN]; /* volume group name */ + uint vg_number; /* volume group number */ + uint vg_access; /* read/write */ + uint vg_status; /* active or not */ + uint lv_max; /* maximum logical volumes */ + uint lv_cur; /* current logical volumes */ + uint lv_open; /* open logical volumes */ + uint pv_max; /* maximum physical volumes */ + uint pv_cur; /* current physical volumes FU */ + uint pv_act; /* active physical volumes */ + uint dummy; /* was obsolete max_pe_per_pv */ + uint vgda; /* volume group descriptor arrays FU */ + uint pe_size; /* physical extent size in sectors */ + uint pe_total; /* total of physical extents */ + uint pe_allocated; /* allocated physical extents */ + uint pvg_total; /* physical volume groups FU */ + struct proc_dir_entry *proc; + pv_t *pv[ABS_MAX_PV + 1]; /* physical volume struct pointers */ + lv_t *lv[ABS_MAX_LV + 1]; /* logical volume struct pointers */ + char vg_uuid[UUID_LEN+1]; /* volume group UUID */ +#ifdef __KERNEL__ + struct proc_dir_entry *vg_dir_pde; + struct proc_dir_entry *lv_subdir_pde; + struct proc_dir_entry *pv_subdir_pde; +#else + char dummy1[200]; +#endif +} vg_v3_t; + + +/* disk */ +typedef struct { + uint8_t vg_name[NAME_LEN]; /* volume group name */ + uint32_t vg_number; /* volume group number */ + uint32_t vg_access; /* read/write */ + uint32_t vg_status; /* active or not */ + uint32_t lv_max; /* maximum logical volumes */ + uint32_t lv_cur; /* current logical volumes */ + uint32_t lv_open; /* open logical volumes */ + uint32_t pv_max; /* maximum physical volumes */ + uint32_t pv_cur; /* current physical volumes FU */ + uint32_t pv_act; /* active physical volumes */ + uint32_t dummy; + uint32_t vgda; /* volume group descriptor arrays FU */ + uint32_t pe_size; /* physical extent size in sectors */ + uint32_t pe_total; /* total of physical extents */ + uint32_t pe_allocated; /* allocated physical extents */ + uint32_t pvg_total; /* physical volume groups FU */ +} vg_disk_v1_t; + +typedef struct { + uint8_t vg_uuid[UUID_LEN]; /* volume group UUID */ + uint8_t vg_name_dummy[NAME_LEN-UUID_LEN]; /* rest of v1 VG name */ + uint32_t vg_number; /* volume group number */ + uint32_t vg_access; /* read/write */ + uint32_t vg_status; /* active or not */ + uint32_t lv_max; /* maximum logical volumes */ + uint32_t lv_cur; /* current logical volumes */ + uint32_t lv_open; /* open logical volumes */ + uint32_t pv_max; /* maximum physical volumes */ + uint32_t pv_cur; /* current physical volumes FU */ + uint32_t pv_act; /* active physical volumes */ + uint32_t dummy; + uint32_t vgda; /* volume group descriptor arrays FU */ + uint32_t pe_size; /* physical extent size in sectors */ + uint32_t pe_total; /* total of physical extents */ + uint32_t pe_allocated; /* allocated physical extents */ + uint32_t pvg_total; /* physical volume groups FU */ +} vg_disk_v2_t; + + +/* + * Request structures for ioctls + */ + +/* Request structure PV_STATUS_BY_NAME... */ +typedef struct { + char pv_name[NAME_LEN]; + pv_t *pv; +} pv_status_req_t, pv_change_req_t; + +/* Request structure PV_FLUSH */ +typedef struct { + char pv_name[NAME_LEN]; + kdev_t pv_dev; +} pv_flush_req_t; + + +/* Request structure PE_MOVE */ +typedef struct { + enum { + LOCK_PE, UNLOCK_PE + } lock; + struct { + kdev_t lv_dev; + kdev_t pv_dev; + uint32_t pv_offset; + } data; +} pe_lock_req_t; + + +/* Request structure LV_STATUS_BYNAME */ +typedef struct { + char lv_name[NAME_LEN]; + lv_t *lv; +} lv_status_byname_req_t, lv_req_t; + +/* Request structure LV_STATUS_BYINDEX */ +typedef struct { + uint32_t lv_index; + lv_t *lv; + /* Transfer size because user space and kernel space differ */ + ushort size; +} lv_status_byindex_req_t; + +/* Request structure LV_STATUS_BYDEV... */ +typedef struct { + dev_t dev; + lv_t *lv; +} lv_status_bydev_req_t; + + +/* Request structure LV_SNAPSHOT_USE_RATE */ +typedef struct { + int block; + int rate; +} lv_snapshot_use_rate_req_t; + +#endif /* #ifndef _LVM_H_INCLUDE */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/lvm_config.h linux-2.4-xfs/cmd/xfsprogs/include/lvm_config.h --- linux-2.4.7/cmd/xfsprogs/include/lvm_config.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/lvm_config.h Tue Mar 20 14:10:08 2001 @@ -0,0 +1,58 @@ +/* + * tools/lib/lvm_config.h + * + * Copyright (C) 2001 Sistina Software + * + * + * This LVM library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This LVM library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this LVM library; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA + * + */ + +/* + * Changelog + * + * 22/01/2001 - First version (Joe Thornber) + * + */ + +#ifndef LVM_CONFIG_H +#define LVM_CONFIG_H + +struct config_file; +struct value_list { + char *value; + struct value_list *next; +}; + +struct config_file *read_config_file(const char *path); +void destroy_config_file(struct config_file *cf); + +void config_check_section(struct config_file *cf, const char *section, ...); + +int config_bool(struct config_file *cf, const char *section, + const char *key, int fail); +const char *config_value(struct config_file *cf, + const char *section, const char *key); +struct value_list *config_values(struct config_file *cf, + const char *section, const char *key); + +#endif + +/* + * Local variables: + * c-file-style: "gnu" + * End: + */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/lvm_log.h linux-2.4-xfs/cmd/xfsprogs/include/lvm_log.h --- linux-2.4.7/cmd/xfsprogs/include/lvm_log.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/lvm_log.h Tue Mar 20 14:10:08 2001 @@ -0,0 +1,67 @@ +/* + * tools/lib/lvm_log.h + * + * Copyright (C) 2001 Sistina Software + * + * + * This LVM library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This LVM library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this LVM library; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA + * + */ + +/* + * Changelog + * + * 22/01/2001 - First version (Joe Thornber) + * + */ + +#ifndef LVM_LOG_H +#define LVM_LOG_H + +#include + +#define LOG_INFO 0 +#define LOG_WARN 1 +#define LOG_ERROR 2 +#define LOG_FATAL 3 + +void init_log(FILE *fp, int low_level); +void fin_log(); + +void print_log(int level, const char *format, ...); + +#define plog(l, f, n, x, a...) print_log(l, "%s:%d " x "\n", f, n, ## a) +#define lvm_info(x...) plog(LOG_INFO, __FILE__, __LINE__, "info: " ## x) +#define lvm_warn(x...) plog(LOG_WARN, __FILE__, __LINE__, "warning: " ## x) +#define lvm_err(x...) plog(LOG_ERROR, __FILE__, __LINE__, "error: " ## x) + +#define lvm_fatal(x...) do {\ + plog(LOG_FATAL, __FILE__, __LINE__, "(FATAL) " ## x); \ + exit(1); \ +} while(0) + +#define lvm_sys_err(x) plog(LOG_ERROR, __FILE__, __LINE__, \ + "system call '%s' failed", x) + +#define stack plog(LOG_INFO, __FILE__, __LINE__, "stack trace") + +#endif /* LVM_LOG_H */ + +/* + * Local variables: + * c-file-style: "gnu" + * End: + */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/lvm_user.h linux-2.4-xfs/cmd/xfsprogs/include/lvm_user.h --- linux-2.4.7/cmd/xfsprogs/include/lvm_user.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/lvm_user.h Tue Mar 20 14:10:08 2001 @@ -0,0 +1,602 @@ +/* + * tools/lvm_user.h + * + * Copyright (C) 1997 - 2001 Heinz Mauelshagen, Sistina Software + * + * March 1997 + * May 1998 + * January 1999 + * + * LVM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * LVM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/* + * Changelog + * + * 16/05/1998 - added macro LVMTAB_CHECK + * 01/01/1999 - ported to libc6 + * 01/22/1999 - added exit states of commands + * 15/09/1999 - enhanced check with lvm_check_kernel_lvmtab_consistency() + * + */ + +#ifndef _LVM_USER_H_INCLUDE +#define _LVM_USER_H_INCLUDE + +#include +#include "liblvm.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "lvm.h" + +char *lvm_version = "Logical Volume Manager "LVM_RELEASE_NAME"\nHeinz Mauelshagen, Sistina Software "LVM_RELEASE_DATE; + +#define SUSER_CHECK { \ + if ( ! ( getuid () == 0 && geteuid () == 0)) { \ + fprintf ( stderr, "%s -- this command is for root only\n\n", cmd); \ + return 1; \ + } \ +} + +#define LVMFILE_CHECK( chkfile) { \ + int file = -1; \ + if ( ( file = open ( chkfile, O_RDONLY)) == -1) { \ + fprintf ( stderr, "%s -- ERROR: \"%s\" doesn't exist; " \ + "please run vgscan\n\n", \ + cmd, chkfile); \ + return LVM_ELVMTAB; \ + } else close ( file); \ +} + +#define LVMTAB_CHECK { \ + LVMFILE_CHECK ( LVMTAB); \ + LVMFILE_CHECK ( LVMTAB_DIR); \ + if ( lvm_check_kernel_lvmtab_consistency () == FALSE) { \ + fprintf ( stderr, "%s -- ERROR: VGDA in kernel and lvmtab are NOT " \ + "consistent; please run vgscan\n\n", \ + cmd); \ + return LVM_ELVMTAB; \ + } \ +} + +#define LVM_CHECK_IOP { \ + int ret = lvm_get_iop_version (); \ + if ( ret < 0) { \ + fprintf ( stderr, "%s -- LVM driver/module not loaded?\n\n", cmd); \ + return LVM_EDRIVER; \ + } \ + if ( ret != LVM_LIB_IOP_VERSION) { \ + fprintf ( stderr, "%s -- invalid i/o protocol version %d\n\n", \ + cmd, ret); \ + return LVM_EINVALID_IOP; \ + } \ +} + +#define LVM_LOCK( level) { \ + if ( opt_v > level) printf ( "%s -- locking logical volume manager\n", cmd); \ + if ( ( ret = lvm_lock ()) < 0) { \ + if ( ret == -ENODEV) \ + fprintf ( stderr, "%s -- no such device while locking logical " \ + "volume manager\n", cmd); \ + else if ( ret == -LVM_ELVM_LOCK_YET_LOCKED) { \ + fprintf(stderr, "%s -- logical volume manager already locked\n", cmd);\ + return LVM_ELOCK; \ + } else \ + fprintf ( stderr, "%s -- ERROR %d locking logical volume manager\n", \ + cmd, ret); \ + fprintf ( stderr, "%s -- LVM not in kernel/loaded?\n\n", cmd); \ + return LVM_ELOCK; \ + }; \ + atexit ( ( void *) &lvm_unlock); \ +} + +#define LVM_UNLOCK( level) { \ + if ( opt_v > level) printf ( "%s -- unlocking logical " \ + "volume manager\n", cmd); \ + lvm_unlock (); \ +} + +#define CMD_MINUS_CHK { \ + if ( optind < argc && *argv[optind] == '-') { \ + fprintf ( stderr, "%s -- invalid command line\n\n", cmd); \ + return LVM_EINVALID_CMD_LINE; \ + } \ +} + + +#define CMD_CHECK_OPT_A_SET { \ + if ( opt_A_set == 0) { \ + char *lvm_autobackup = getenv ( "LVM_AUTOBACKUP"); \ + if ( lvm_autobackup != NULL) { \ + char *ptr = lvm_autobackup; \ + while ( *ptr != 0) { *ptr = tolower ( *ptr); ptr++;} \ + printf ( "%s -- INFO: using environment variable LVM_AUTOBACKUP" \ + " to set option A\n", cmd); \ + if ( strcmp ( lvm_autobackup, "no") == 0) opt_A = 0; \ + else if ( strcmp ( lvm_autobackup, "yes") == 0) opt_A = 1; \ + else { \ + fprintf ( stderr, "%s -- ERROR: environment variable " \ + "LVM_AUTOBACKUP has invalid value " \ + "\"%s\"!\n\n", \ + cmd, lvm_autobackup); \ + return LVM_EINVALID_CMD_LINE; \ + } \ + } \ + } \ +} + +#define LVM_CHECK_DEFAULT_VG_NAME( lv_name, buffer, len) { \ +{ \ + if ( strchr ( lv_name, '/') == NULL) { \ + char *lvm_default_vg_name = getenv ( "LVM_VG_NAME"); \ + if ( lvm_default_vg_name != NULL) { \ + if ( strlen ( lv_name) < len - strlen ( lvm_default_vg_name) - sizeof ( LVM_DIR_PREFIX)) { \ + if ( strchr ( lvm_default_vg_name, '/') == NULL) { \ + sprintf ( buffer, "%s%s/%s%c", LVM_DIR_PREFIX, lvm_default_vg_name, lv_name, 0); \ + } else { \ + sprintf ( buffer, "%s/%s%c", lvm_default_vg_name, lv_name, 0); \ + } \ + lv_name = buffer; \ + } \ + } \ + } \ +} \ +} + + +#define LVM_GET_DEFAULT_VG_NAME( vg_name, buffer, len) { \ +{ \ + char *lvm_default_vg_name = getenv ( "LVM_VG_NAME"); \ + if ( lvm_default_vg_name != NULL) { \ + if ( len > strlen ( lvm_default_vg_name) + sizeof ( LVM_DIR_PREFIX)) { \ + if ( strchr ( lvm_default_vg_name, '/') == NULL) { \ + sprintf ( buffer, "%s%s%c", LVM_DIR_PREFIX, lvm_default_vg_name, 0); \ + } else { \ + strcpy ( buffer, lvm_default_vg_name); \ + } \ + vg_name = buffer; \ + } else vg_name = NULL; \ + } \ +} \ +} + + +/* return codes of the tools */ +#define LVM_EDRIVER 95 +#define LVM_EINVALID_IOP 96 +#define LVM_ELOCK 97 +#define LVM_ELVMTAB 98 +#define LVM_EINVALID_CMD_LINE 99 + + +/* e2fsadm */ +#define LVM_EE2FSADM_FSSIZE 1 +#define LVM_EE2FSADM_LV_MISSING 2 +#define LVM_EE2FSADM_LVNAME 3 +#define LVM_EE2FSADM_LV_EXIST 4 +#define LVM_EE2FSADM_VG_READ 5 +#define LVM_EE2FSADM_FSSIZE_CHANGE 6 +#define LVM_EE2FSADM_PROC_MOUNTS 7 +#define LVM_EE2FSADM_MOUNTED 8 +#define LVM_EE2FSADM_NO_EXT2 9 +#define LVM_EE2FSADM_FSCK_PATH 10 +#define LVM_EE2FSADM_RESIZE_PATH 11 +#define LVM_EE2FSADM_FSCK_RUN 12 +#define LVM_EE2FSADM_RESIZE_RUN 13 +#define LVM_EE2FSADM_LV_READ 14 +#define LVM_EE2FSADM_LV_SIZE 15 +#define LVM_EE2FSADM_LV_EXTEND_PATH 16 +#define LVM_EE2FSADM_LV_EXTEND_RUN 17 +#define LVM_EE2FSADM_LV_REDUCE_PATH 18 +#define LVM_EE2FSADM_LV_REDUCE_RUN 19 + + +/* lvchange */ +#define LVM_ELVCHANGE_LV_PATH 1 +#define LVM_ELVCHANGE_VG_CHECK_EXIST 2 +#define LVM_ELVCHANGE_LV_OPEN 3 +#define LVM_ELVCHANGE_LV_SET_ACCESS 4 +#define LVM_ELVCHANGE_LV_SET_STATUS 5 +#define LVM_ELVCHANGE_LV_SET_ALLOCATION 6 +#define LVM_ELVCHANGE_LV_WRITE_ALL_PV 7 +#define LVM_ELVCHANGE_READ_AHEAD 8 + + +/* lvcreate */ +#define LVM_ELVCREATE_VG_NAME 1 +#define LVM_ELVCREATE_VG_CHECK_EXIST 2 +#define LVM_ELVCREATE_VG_CHECK_ACTIVE 3 +#define LVM_ELVCREATE_LV_CHECK_NAME 4 +#define LVM_ELVCREATE_LV_LSTAT 5 +#define LVM_ELVCREATE_LV_CHECK_EXIST 6 +#define LVM_ELVCREATE_PV_CHECK_NAME 7 +#define LVM_ELVCREATE_PV_NUMBER 8 +#define LVM_ELVCREATE_STRIPES 9 +#define LVM_ELVCREATE_STRIPE_SIZE 10 +#define LVM_ELVCREATE_VG_STATUS 11 +#define LVM_ELVCREATE_LV_SIZE 12 +#define LVM_ELVCREATE_PE_FREE 13 +#define LVM_ELVCREATE_STRIPE_COUNT 14 +#define LVM_ELVCREATE_VG_READ 15 +#define LVM_ELVCREATE_PV_CHECK_IN_VG 16 +#define LVM_ELVCREATE_PV_READ 17 +#define LVM_ELVCREATE_LV_COUNT 18 +#define LVM_ELVCREATE_VG_SIZE 19 +#define LVM_ELVCREATE_LV_SETUP 20 +#define LVM_ELVCREATE_LV_CREATE 21 +#define LVM_ELVCREATE_VG_WRITE 22 +#define LVM_ELVCREATE_LV_CREATE_NODE 23 +#define LVM_ELVCREATE_LV_OPEN 24 +#define LVM_ELVCREATE_LV_WRITE 25 +#define LVM_ELVCREATE_READ_AHEAD 26 +#define LVM_ELVCREATE_NO_DEV 27 +#define LVM_ELVCREATE_LV_NAME 28 +#define LVM_ELVCREATE_LV_SETUP_COW_TABLE_FOR_CREATE 29 +#define LVM_ELVCREATE_LV_INIT_COW_TABLE 30 +#define LVM_ELVCREATE_LV_STATUS_BYNAME 31 +#define LVM_ELVCREATE_LV_SNAPSHOT_EXISTS 32 + +/* lvdisplay */ +#define LVM_ELVDISPLAY_LV_MISSING 1 + +/* lvextend */ +#define LVM_ELVEXTEND_LV_MISSING 1 +#define LVM_ELVEXTEND_PV_NAME 2 +#define LVM_ELVEXTEND_LV_NAME 3 +#define LVM_ELVEXTEND_LV_CHECK_EXIST 4 +#define LVM_ELVEXTEND_LV_CHECK_ACTIVE 5 +#define LVM_ELVEXTEND_VG_READ 6 +#define LVM_ELVEXTEND_PV_CHECK_IN_VG 7 +#define LVM_ELVEXTEND_LV_GET_INDEX 8 +#define LVM_ELVEXTEND_LV_SIZE 9 +#define LVM_ELVEXTEND_LV_SIZE_FREE 10 +#define LVM_ELVEXTEND_LV_SIZE_MAX 11 +#define LVM_ELVEXTEND_LV_SETUP 12 +#define LVM_ELVEXTEND_LV_EXTEND 13 +#define LVM_ELVEXTEND_VG_WRITE 14 +#define LVM_ELVEXTEND_LV_GET_INDEX_BY_NAME 15 +#define LVM_ELVEXTEND_LV_STATUS_BYNAME 16 +#define LVM_ELVEXTEND_LV_SETUP_COW_TABLE_FOR_CREATE 17 + +/* lvmchange */ +#define LVM_ELVMCHANGE_OPEN 1 +#define LVM_ELVMCHANGE_RESET 2 +#define LVM_ELVMCHANGE_READ_AHEAD 3 + +/* lvmdiskscan */ +#define LVM_ELVMDISKSCAN_NO_FILES_FOUND 1 +#define LVM_ELVMDISKSCAN_NO_DISKS_FOUND 2 + +/* lvmsadc */ +#define LVM_ELVMSADC_NO_LOG_FILE 1 +#define LVM_ELVMSADC_FOPEN 2 +#define LVM_ELVMSADC_NO_VGS 3 +#define LVM_ELVMSADC_FCLOSE 4 + +/* lvmsar */ +#define LVM_ELVMSAR_FOPEN 1 +#define LVM_ELVMSAR_FCLOSE 2 + +/* lvreduce */ +#define LVM_ELVREDUCE_LV_MISSING 1 +#define LVM_ELVREDUCE_LV_NAME 2 +#define LVM_ELVREDUCE_LV_CHECK_ACTIVE 3 +#define LVM_ELVREDUCE_LV_CHECK_EXIST 4 +#define LVM_ELVREDUCE_VG_READ 5 +#define LVM_ELVREDUCE_LV_GET_INDEX 6 +#define LVM_ELVREDUCE_LV_SIZE 7 +#define LVM_ELVREDUCE_LV_SETUP 8 +#define LVM_ELVREDUCE_LV_REDUCE 9 +#define LVM_ELVREDUCE_VG_WRITE 10 +#define LVM_ELVREDUCE_LV_GET_INDEX_BY_NAME 11 +#define LVM_ELVREDUCE_LV_STATUS_BYNAME 12 +#define LVM_ELVREDUCE_LV_SETUP_COW_TABLE_FOR_CREATE 17 + +/* lvremove */ +#define LVM_ELVREMOVE_LV_MISSING 1 +#define LVM_ELVREMOVE_LV_CHECK_NAME 2 +#define LVM_ELVREMOVE_VG_CHECK_EXIST 3 +#define LVM_ELVREMOVE_VG_CHECK_ACTIVE 4 +#define LVM_ELVREMOVE_VG_STATUS 5 +#define LVM_ELVREMOVE_LV_STATUS 6 +#define LVM_ELVREMOVE_LV_OPEN 7 +#define LVM_ELVREMOVE_VG_READ 8 +#define LVM_ELVREMOVE_LV_RELEASE 9 +#define LVM_ELVREMOVE_LV_REMOVE 10 +#define LVM_ELVREMOVE_VG_WRITE 11 +#define LVM_ELVREMOVE_LV_SNAPSHOT 12 + +/* lvrename */ +#define LVM_ELVRENAME_LV_NAME 1 +#define LVM_ELVRENAME_VG_CHECK_EXIST 2 +#define LVM_ELVRENAME_VG_CHECK_ACTIVE 3 +#define LVM_ELVRENAME_LSTAT 4 +#define LVM_ELVRENAME_LV_CHECK_EXIST_OLD 5 +#define LVM_ELVRENAME_VG_NAME_DIFFER 6 +#define LVM_ELVRENAME_LV_CHECK_EXIST_NEW 7 +#define LVM_ELVRENAME_VG_READ 9 +#define LVM_ELVRENAME_LV_GET_INDEX 10 +#define LVM_ELVRENAME_LV_RENAME 11 +#define LVM_ELVRENAME_LV_CREATE 12 +#define LVM_ELVRENAME_VG_WRITE 13 +#define LVM_ELVRENAME_LV_CREATE_NODE 14 + +/* lvscan */ +#define LVM_ELVSCAN_NO_VGS 1 +#define LVM_ELVSCAN_VG_CHECK_NAME 2 +#define LVM_ELVSCAN_VG_STATUS 3 + +/* pvchange */ +#define LVM_EPVCHANGE_PV_MISSING 1 +#define LVM_EPVCHANGE_PV_FIND_ALL_PV_NAMES 2 +#define LVM_EPVCHANGE_PV_CHANGE 3 +#define LVM_EPVCHANGE_PV_WRITE 4 + +/* pvcreate */ +#define LVM_EPVCREATE_PV_MISSING 1 +#define LVM_EPVCREATE_VG_CHECK_EXIST 2 +#define LVM_EPVCREATE_PV_SETUP 3 +#define LVM_EPVCREATE_PV_WRITE 4 +#define LVM_EPVCREATE_INVALID_ID 5 +#define LVM_EPVCREATE_PV_CHECK_NAME 6 +#define LVM_EPVCREATE_PV_GET_SIZE 7 + +/* pvdata */ +#define LVM_EPVDATA_PV_MISSING 1 + +/* pvdisplay */ +#define LVM_EPVDISPLAY_PV_MISSING 1 +#define LVM_EPVDISPLAY_PV_CHECK_CONSISTENCY 2 +#define LVM_EPVDISPLAY_PV_READ_PE 3 + +/* pvmove */ +#define LVM_EPVMOVE_PV_SOURCE 1 +#define LVM_EPVMOVE_LVM_GET_COL_NUMBERS 2 +#define LVM_EPVMOVE_PV_CHECK_NAME_SOURCE 3 +#define LVM_EPVMOVE_PV_READ 4 +#define LVM_EPVMOVE_PV_CHECK_CONSISTENCY 5 +#define LVM_EPVMOVE_VG_CHECK_EXIST 6 +#define LVM_EPVMOVE_VG_READ 7 +#define LVM_EPVMOVE_VG_CHECK_CONSISTENCY 8 +#define LVM_EPVMOVE_PV_GET_INDEX 9 +#define LVM_EPVMOVE_PE_ALLOCATED 10 +#define LVM_EPVMOVE_LV_CHECK_NAME 12 +#define LVM_EPVMOVE_LV_NUMBER 13 +#define LVM_EPVMOVE_LV_CHECK_ON_PV 14 +#define LVM_EPVMOVE_MALLOC 15 +#define LVM_EPVMOVE_PV_CHECK_NAME 16 +#define LVM_EPVMOVE_PV_CHECK_IN_VG 17 +#define LVM_EPVMOVE_DEST_PES 18 +#define LVM_EPVMOVE_LV_GET_INDEX 19 +#define LVM_EPVMOVE_LE_INVALID 20 +#define LVM_EPVMOVE_PE_INVALID 21 +#define LVM_EPVMOVE_PE_IN_USE 22 +#define LVM_EPVMOVE_PV_MOVE_PES 23 + +/* pvscan */ +#define LVM_EPVSCAN_PV_READ_ALL_PV 1 +#define LVM_EPVSCAN_NO_PV_FOUND 2 + +/* vgcfgbackup */ +#define LVM_EVGCFGBACKUP_VG_CFGBACKUP 1 + +/* vgcfgrestore */ +#define LVM_EVGCFGRESTORE_PV_MISSING 1 +#define LVM_EVGCFGRESTORE_PV_CHECK_NAME 2 +#define LVM_EVGCFGRESTORE_VG_CHECK_ACTIVE 3 +#define LVM_EVGCFGRESTORE_VG_CFGRESTORE 4 +#define LVM_EVGCFGRESTORE_INVALID 5 +#define LVM_EVGCFGRESTORE_VG_CHECK_CONSISTENCY 6 +#define LVM_EVGCFGRESTORE_PV_CHECK_IN_VG 7 +#define LVM_EVGCFGRESTORE_PV_READ 8 +#define LVM_EVGCFGRESTORE_PV_GET_SIZE 9 +#define LVM_EVGCFGRESTORE_VG_WRITE 10 +#define LVM_EVGCFGRESTORE_VG_REMOVE_DIR 11 +#define LVM_EVGCFGRESTORE_LVM_TAB_VG_INSERT 12 +#define LVM_EVGCFGRESTORE_VG_CFGBACKUP 13 + +/* vgchange */ +#define LVM_EVGCHANGE_VG_WRITE 1 +#define LVM_EVGCHANGE_VG_EXTEND 2 +#define LVM_EVGCHANGE_VG_CFG_BACKUP 3 +#define LVM_EVGCHANGE_PE_OVERLAP 4 +#define LVM_EVGCHANGE_VG_CFGBACKUP 5 +#define LVM_EVGCHANGE_VG_CFGBACKUP_LVMTAB 6 +#define LVM_EVGCHANGE_VG_CREATE_DIR_AND_GROUP_NODES 7 +#define LVM_EVGCHANGE_VG_REMOVE_DIR_AND_GROUP_NODES 8 +#define LVM_EVGCHANGE_LV_SETUP_COW_TABLE_FOR_CREATE 9 +#define LVM_EVGCHANGE_LV_READ_COW_TABLE 10 + +/* vgck */ +#define LVM_EVGCK_CHECK_ERRORS 1 + +/* vgcreate */ +#define LVM_EVGCREATE_VG_AND_PV_MISSING 1 +#define LVM_EVGCREATE_PV_MISSING 2 +#define LVM_EVGCREATE_VG_CHECK_NAME 3 +#define LVM_EVGCREATE_VG_CHECK_EXIST 4 +#define LVM_EVGCREATE_MAX_VG 5 +#define LVM_EVGCREATE_PV_READ_ALL_PV 6 +#define LVM_EVGCREATE_PV_CHECK_NAME 7 +#define LVM_EVGCREATE_PV_GET_SIZE 8 +#define LVM_EVGCREATE_PV_CHECK_NEW 9 +#define LVM_EVGCREATE_PV_MULTIPLE 10 +#define LVM_EVGCREATE_REALLOC 11 +#define LVM_EVGCREATE_NO_VALID_PV 12 +#define LVM_EVGCREATE_SOME_INVALID_PV 13 +#define LVM_EVGCREATE_PV_TOO_SMALL 14 +#define LVM_EVGCREATE_VG_SETUP 15 +#define LVM_EVGCREATE_VG_WRITE 16 +#define LVM_EVGCREATE_VG_CREATE 17 +#define LVM_EVGCREATE_VG_INSERT 18 +#define LVM_EVGCREATE_VG_CFGBACKUP 19 +#define LVM_EVGCREATE_VG_CFGBACKUP_LVMTAB 20 +#define LVM_EVGCREATE_VG_CHECK_DIR 21 + +/* vgdisplay */ +#define LVM_EVGDISPLAY_VG_READ 1 +#define LVM_EVGDISPLAY_VG_EEXIST 2 +#define LVM_EVGDISPLAY_PV_COUNT 3 +#define LVM_EVGDISPLAY_VG_NOT_FOUND 4 +#define LVM_EVGDISPLAY_NO_VG 5 +#define LVM_EVGDISPLAY_VG_CFGRESTORE 6 + +/* vgexport */ +#define LVM_EVGEXPORT_NO_VG 1 +#define LVM_EVGEXPORT_VG_MISSING 2 + +/* vgextend */ +#define LVM_EVGEXTEND_VG_MISSING 1 +#define LVM_EVGEXTEND_NO_VG_NAME 2 +#define LVM_EVGEXTEND_PV_MISSING 3 +#define LVM_EVGEXTEND_VG_CHECK_NAME 4 +#define LVM_EVGEXTEND_VG_CHECK_EXIST 5 +#define LVM_EVGEXTEND_VG_CHECK_ACTIVE 6 +#define LVM_EVGEXTEND_VG_READ 7 +#define LVM_EVGEXTEND_NOT_EXTENDABLE 8 +#define LVM_EVGEXTEND_PV_MAX 9 +#define LVM_EVGEXTEND_PV_READ_ALL_PV 10 +#define LVM_EVGEXTEND_VG_SETUP 11 +#define LVM_EVGEXTEND_VG_EXTEND 12 +#define LVM_EVGEXTEND_VG_WRITE 13 + +/* vgimport */ +#define LVM_EVGIMPORT_VG_MISSING 1 +#define LVM_EVGIMPORT_VG_CHECK_NAME 2 +#define LVM_EVGIMPORT_PV_MISSING 3 +#define LVM_EVGIMPORT_VG_CHECK_EXIST 4 +#define LVM_EVGIMPORT_PV_MULTIPLE 5 +#define LVM_EVGIMPORT_PV_CHECK_NAME 6 +#define LVM_EVGIMPORT_PV_READ 7 +#define LVM_EVGIMPORT_CHECK_EXPORTED 8 +#define LVM_EVGIMPORT_REALLOC 9 +#define LVM_EVGIMPORT_MALLOC 10 +#define LVM_EVGIMPORT_NO_PV_FOUND 11 +#define LVM_EVGIMPORT_VG_DIFF 12 +#define LVM_EVGIMPORT_PV_COUNT 13 +#define LVM_EVGIMPORT_VG_READ 14 +#define LVM_EVGIMPORT_VG_CHECK_CONSISTENCY 15 +#define LVM_EVGIMPORT_MAX_LV 16 +#define LVM_EVGIMPORT_GET_FREE_VG_NUMBER 17 +#define LVM_EVGIMPORT_VG_WRITE 18 +#define LVM_EVGIMPORT_VG_CREATE 19 +#define LVM_EVGIMPORT_VG_INSERT 20 +#define LVM_EVGIMPORT_VG_CFGBACKUP 21 +#define LVM_EVGIMPORT_VG_CFGBACKUP_LVMTAB 22 +#define LVM_EVGIMPORT_NO_DEV 23 + +/* vgmerge */ +#define LVM_EVGMERGE_VG_NAMES 1 +#define LVM_EVGMERGE_VG_CHECK_ACTIVE 2 +#define LVM_EVGMERGE_VG_READ_TO 3 +#define LVM_EVGMERGE_VG_READ_FROM 4 +#define LVM_EVGMERGE_VG_SETUP 5 +#define LVM_EVGMERGE_VG_EXTEND 6 +#define LVM_EVGMERGE_VG_WRITE 7 +#define LVM_EVGMERGE_VG_CREATE_DIR_AND_GROUP_NODES 8 +#define LVM_EVGMERGE_VG_REMOVE 9 + +/* vgmknodes */ +#define LVM_EVGMKNODES_VG_CHECK_NAME 1 +#define LVM_EVGMKNODES_VG_CHECK_EXIST 2 +#define LVM_EVGMKNODES_VG_REMOVE_DIR_AND_GROUP_NODES 3 +#define LVM_EVGMKNODES_VG_CREATE_DIR_AND_GROUP_NODES 4 + +/* vgreduce */ +#define LVM_EVGREDUCE_VG_PV_NAMES 1 +#define LVM_EVGREDUCE_VG_CHECK_NAME 2 +#define LVM_EVGREDUCE_VG_CHECK_EXIST 3 +#define LVM_EVGREDUCE_VG_CHECK_ACTIVE 4 +#define LVM_EVGREDUCE_VG_READ 5 +#define LVM_EVGREDUCE_VG_NOT_REDUCABLE 6 +#define LVM_EVGREDUCE_PV_NAME 7 +#define LVM_EVGREDUCE_REALLOC 8 +#define LVM_EVGREDUCE_MALLOC 9 +#define LVM_EVGREDUCE_NO_EMPTY_PV 10 +#define LVM_EVGREDUCE_VG_SETUP 11 +#define LVM_EVGREDUCE_VG_REDUCE 12 +#define LVM_EVGREDUCE_VG_WRITE 13 + +/* vgremove */ +#define LVM_EVGREMOVE_VG_NAME 1 +#define LVM_EVGREMOVE_PV_SETUP 2 +#define LVM_EVGREMOVE_PV_WRITE_ALL_PV_OF_VG 3 +#define LVM_EVGREMOVE_VG_REMOVE 4 +#define LVM_EVGREMOVE_LV_EXISTS 5 +#define LVM_EVGREMOVE_VG_CHECK_NAME 6 +#define LVM_EVGREMOVE_VG_CHECK_ACTIVE 7 +#define LVM_EVGREMOVE_PV_ONLINE 8 +#define LVM_EVGREMOVE_VG_ERROR 9 +#define LVM_EVGREMOVE_VG_READ 10 + +/* vgrename */ +#define LVM_EVGRENAME_VG_DIR_NEW 1 +#define LVM_EVGRENAME_VG_DIR_OLD 2 +#define LVM_EVGRENAME_VG_CHECK_NAME_NEW 3 +#define LVM_EVGRENAME_VG_CHECK_NAME_OLD 4 +#define LVM_EVGRENAME_VG_CHECK_EXIST_OLD 5 +#define LVM_EVGRENAME_VG_NAMES_IDENTICAL 7 +#define LVM_EVGRENAME_VG_CHECK_EXIST_NEW 8 +#define LVM_EVGRENAME_VG_READ 9 +#define LVM_EVGRENAME_VG_REMOVE 10 +#define LVM_EVGRENAME_LVM_TAB_VG_REMOVE 11 +#define LVM_EVGRENAME_VG_REMOVE_DIR_AND_GROUP_NODES 12 +#define LVM_EVGRENAME_VG_CREATE_DIR_AND_GROUP_NODES 13 +#define LVM_EVGRENAME_VG_INSERT 14 +#define LVM_EVGRENAME_VG_CFGBACKUP 15 +#define LVM_EVGRENAME_VG_CFGBACKUP_LVMTAB 16 +#define LVM_EVGRENAME_VG_RENAME 17 + +/* vgscan */ +#define LVM_EVGSCAN_PV_READ_ALL_PV 1 +#define LVM_EVGSCAN_VG_INSERT 2 +#define LVM_EVGSCAN_NO_VG 3 +#define LVM_EVGSCAN_LVMTAB 4 +#define LVM_EVGSCAN_NO_DEV 5 +#define LVM_EVGSCAN_VG_WRITE 6 + +/* vgsplit */ +#define LVM_EVGSPLIT_VG_CHECK_NAME 1 +#define LVM_EVGSPLIT_PV_CHECK_NAME 2 +#define LVM_EVGSPLIT_MALLOC 3 +#define LVM_EVGSPLIT_VG_READ_EXIST 4 +#define LVM_EVGSPLIT_VG_CHECK_EXIST_NEW 5 +#define LVM_EVGSPLIT_VG_SETUP 6 +#define LVM_EVGSPLIT_LV_CHECK_EXIST 7 +#define LVM_EVGSPLIT_LV_STATUS_BYNAME 8 +#define LVM_EVGSPLIT_LV_REMOVE 9 +#define LVM_EVGSPLIT_VG_REDUCE 10 +#define LVM_EVGSPLIT_VG_WRITE_EXIST 11 +#define LVM_EVGSPLIT_VG_WRITE_NEW 12 +#define LVM_EVGSPLIT_VG_CREATE_DIR_AND_GROUP_NODES_EXIST 13 +#define LVM_EVGSPLIT_VG_CREATE_DIR_AND_GROUP_NODES_NEW 14 +#define LVM_EVGSPLIT_VG_CREATE 15 +#define LVM_EVGSPLIT_VG_INSERT 16 + +#endif /* #ifndef _LVM_USER_H_INCLUDE */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/md-int.h linux-2.4-xfs/cmd/xfsprogs/include/md-int.h --- linux-2.4.7/cmd/xfsprogs/include/md-int.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/md-int.h Mon Mar 26 22:24:31 2001 @@ -0,0 +1,290 @@ +/* + md.h : Multiple Devices driver for Linux + Copyright (C) 1997-1999 Ingo Molnar + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + You should have received a copy of the GNU General Public License + (for example /usr/src/linux/COPYING); if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef MD_INT_H +#define MD_INT_H + +/* don't include the kernel RAID header! */ +#define _MD_H + +typedef unsigned int md_u32; +typedef unsigned short md_u16; +typedef unsigned char md_u8; + +#include +#include + +/* + * Different major versions are not compatible. + * Different minor versions are only downward compatible. + * Different patchlevel versions are downward and upward compatible. + */ + +struct md_version { + int major; + int minor; + int patchlevel; +}; + +/* + * default readahead + */ +#define MD_READAHEAD (256 * 1024) + +/* These are the ioctls for md versions < 0.50 */ +#define REGISTER_MD_DEV _IO (MD_MAJOR, 1) +#define START_MD _IO (MD_MAJOR, 2) +#define STOP_MD _IO (MD_MAJOR, 3) + +/* status */ +#define RAID_VERSION _IOR (MD_MAJOR, 0x10, struct md_version) +#define GET_ARRAY_INFO _IOR (MD_MAJOR, 0x11, md_array_info_t) +#define GET_DISK_INFO _IOR (MD_MAJOR, 0x12, md_disk_info_t) +#define PRINT_RAID_DEBUG _IO (MD_MAJOR, 0x13) + +/* configuration */ +#define CLEAR_ARRAY _IO (MD_MAJOR, 0x20) +#define ADD_NEW_DISK _IOW (MD_MAJOR, 0x21, md_disk_info_t) +#define HOT_REMOVE_DISK _IO (MD_MAJOR, 0x22) +#define SET_ARRAY_INFO _IOW (MD_MAJOR, 0x23, md_array_info_t) +#define SET_DISK_INFO _IO (MD_MAJOR, 0x24) +#define WRITE_RAID_INFO _IO (MD_MAJOR, 0x25) +#define UNPROTECT_ARRAY _IO (MD_MAJOR, 0x26) +#define PROTECT_ARRAY _IO (MD_MAJOR, 0x27) +#define HOT_ADD_DISK _IO (MD_MAJOR, 0x28) +#define SET_DISK_FAULTY _IO (MD_MAJOR, 0x29) + +/* usage */ +#define RUN_ARRAY _IOW (MD_MAJOR, 0x30, struct md_param) +#define START_ARRAY _IO (MD_MAJOR, 0x31) +#define STOP_ARRAY _IO (MD_MAJOR, 0x32) +#define STOP_ARRAY_RO _IO (MD_MAJOR, 0x33) +#define RESTART_ARRAY_RW _IO (MD_MAJOR, 0x34) + + +/* for raid < 0.50 only */ +#define MD_PERSONALITY_SHIFT 16 + +#define MD_RESERVED 0UL +#define LINEAR 1UL +#define STRIPED 2UL +#define RAID0 STRIPED +#define RAID1 3UL +#define RAID5 4UL +#define TRANSLUCENT 5UL +#define LVM 6UL +#define MAX_PERSONALITY 7UL + +/* + * MD superblock. + * + * The MD superblock maintains some statistics on each MD configuration. + * Each real device in the MD set contains it near the end of the device. + * Some of the ideas are copied from the ext2fs implementation. + * + * We currently use 4096 bytes as follows: + * + * word offset function + * + * 0 - 31 Constant generic MD device information. + * 32 - 63 Generic state information. + * 64 - 127 Personality specific information. + * 128 - 511 12 32-words descriptors of the disks in the raid set. + * 512 - 911 Reserved. + * 912 - 1023 Disk specific descriptor. + */ + +/* + * If x is the real device size in bytes, we return an apparent size of: + * + * y = (x & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES + * + * and place the 4kB superblock at offset y. + */ +#define MD_RESERVED_BYTES (64 * 1024) +#define MD_RESERVED_SECTORS (MD_RESERVED_BYTES / 512) +#define MD_RESERVED_BLOCKS (MD_RESERVED_BYTES / BLOCK_SIZE) + +#define MD_NEW_SIZE_SECTORS(x) ((x & ~(MD_RESERVED_SECTORS - 1)) - MD_RESERVED_SECTORS) +#define MD_NEW_SIZE_BLOCKS(x) ((x & ~(MD_RESERVED_BLOCKS - 1)) - MD_RESERVED_BLOCKS) + +#define MD_SB_BYTES 4096 +#define MD_SB_WORDS (MD_SB_BYTES / 4) +#define MD_SB_BLOCKS (MD_SB_BYTES / BLOCK_SIZE) +#define MD_SB_SECTORS (MD_SB_BYTES / 512) + +/* + * The following are counted in 32-bit words + */ +#define MD_SB_GENERIC_OFFSET 0 +#define MD_SB_PERSONALITY_OFFSET 64 +#define MD_SB_DISKS_OFFSET 128 +#define MD_SB_DESCRIPTOR_OFFSET 992 + +#define MD_SB_GENERIC_CONSTANT_WORDS 32 +#define MD_SB_GENERIC_STATE_WORDS 32 +#define MD_SB_GENERIC_WORDS (MD_SB_GENERIC_CONSTANT_WORDS + MD_SB_GENERIC_STATE_WORDS) +#define MD_SB_PERSONALITY_WORDS 64 +#define MD_SB_DESCRIPTOR_WORDS 32 +#define MD_SB_DISKS 27 +#define MD_SB_DISKS_WORDS (MD_SB_DISKS*MD_SB_DESCRIPTOR_WORDS) +#define MD_SB_RESERVED_WORDS (1024 - MD_SB_GENERIC_WORDS - MD_SB_PERSONALITY_WORDS - MD_SB_DISKS_WORDS - MD_SB_DESCRIPTOR_WORDS) +#define MD_SB_EQUAL_WORDS (MD_SB_GENERIC_WORDS + MD_SB_PERSONALITY_WORDS + MD_SB_DISKS_WORDS) + +/* + * Device "operational" state bits + */ +#define MD_DISK_FAULTY 0 /* disk is faulty / operational */ +#define MD_DISK_ACTIVE 1 /* disk is running or spare disk */ +#define MD_DISK_SYNC 2 /* disk is in sync with the raid set */ + +typedef struct md_device_descriptor_s { + md_u32 number; /* 0 Device number in the entire set */ + md_u32 major; /* 1 Device major number */ + md_u32 minor; /* 2 Device minor number */ + md_u32 raid_disk; /* 3 The role of the device in the raid set */ + md_u32 state; /* 4 Operational state */ + md_u32 reserved[MD_SB_DESCRIPTOR_WORDS - 5]; +} md_descriptor_t; + +#define MD_SB_MAGIC 0xa92b4efc + +/* + * Superblock state bits + */ +#define MD_SB_CLEAN 0 +#define MD_SB_ERRORS 1 + +typedef struct md_superblock_s { + /* + * Constant generic information + */ + md_u32 md_magic; /* 0 MD identifier */ + md_u32 major_version; /* 1 major version to which the set conforms */ + md_u32 minor_version; /* 2 minor version ... */ + md_u32 patch_version; /* 3 patchlevel version ... */ + md_u32 gvalid_words; /* 4 Number of used words in this section */ + md_u32 set_magic; /* 5 Raid set identifier */ + md_u32 ctime; /* 6 Creation time */ + md_u32 level; /* 7 Raid personality */ + md_u32 size; /* 8 Apparent size of each individual disk */ + md_u32 nr_disks; /* 9 total disks in the raid set */ + md_u32 raid_disks; /* 10 disks in a fully functional raid set */ + md_u32 md_minor; /* 11 preferred MD minor device number */ + md_u32 gstate_creserved[MD_SB_GENERIC_CONSTANT_WORDS - 12]; + + /* + * Generic state information + */ + md_u32 utime; /* 0 Superblock update time */ + md_u32 state; /* 1 State bits (clean, ...) */ + md_u32 active_disks; /* 2 Number of currently active disks */ + md_u32 working_disks; /* 3 Number of working disks */ + md_u32 failed_disks; /* 4 Number of failed disks */ + md_u32 spare_disks; /* 5 Number of spare disks */ + md_u32 gstate_sreserved[MD_SB_GENERIC_STATE_WORDS - 6]; + + /* + * Personality information + */ + md_u32 layout; /* 0 the array's physical layout */ + md_u32 chunk_size; /* 1 chunk size in bytes */ + md_u32 pstate_reserved[MD_SB_PERSONALITY_WORDS - 2]; + + /* + * Disks information + */ + md_descriptor_t disks[MD_SB_DISKS]; + + /* + * Reserved + */ + md_u32 reserved[MD_SB_RESERVED_WORDS]; + + /* + * Active descriptor + */ + md_descriptor_t descriptor; + +} md_superblock_t; + +/* + * options passed in raidstart: + */ + +#define MAX_CHUNK_SIZE (4096*1024) + +struct md_param +{ + int personality; /* 1,2,3,4 */ + int chunk_size; /* in bytes */ + int max_fault; /* unused for now */ +}; + +typedef struct md_array_info_s { + /* + * Generic constant information + */ + md_u32 major_version; + md_u32 minor_version; + md_u32 patch_version; + md_u32 ctime; + md_u32 level; + md_u32 size; + md_u32 nr_disks; + md_u32 raid_disks; + md_u32 md_minor; + md_u32 not_persistent; + + /* + * Generic state information + */ + md_u32 utime; /* 0 Superblock update time */ + md_u32 state; /* 1 State bits (clean, ...) */ + md_u32 active_disks; /* 2 Number of currently active disks */ + md_u32 working_disks; /* 3 Number of working disks */ + md_u32 failed_disks; /* 4 Number of failed disks */ + md_u32 spare_disks; /* 5 Number of spare disks */ + + /* + * Personality information + */ + md_u32 layout; /* 0 the array's physical layout */ + md_u32 chunk_size; /* 1 chunk size in bytes */ + +} md_array_info_t; + +typedef struct md_disk_info_s { + /* + * configuration/status of one particular disk + */ + md_u32 number; + md_u32 major; + md_u32 minor; + md_u32 raid_disk; + md_u32 state; + +} md_disk_info_t; + + +/* + * Supported RAID5 algorithms + */ +#define RAID5_ALGORITHM_LEFT_ASYMMETRIC 0 +#define RAID5_ALGORITHM_RIGHT_ASYMMETRIC 1 +#define RAID5_ALGORITHM_LEFT_SYMMETRIC 2 +#define RAID5_ALGORITHM_RIGHT_SYMMETRIC 3 + +#endif _MD_H diff -rNu linux-2.4.7/cmd/xfsprogs/include/platform_defs.h.in linux-2.4-xfs/cmd/xfsprogs/include/platform_defs.h.in --- linux-2.4.7/cmd/xfsprogs/include/platform_defs.h.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/platform_defs.h.in Wed May 9 01:56:06 2001 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + * + * @configure_input@ + */ +#ifndef __XFS_PLATFORM_DEFS_H__ +#define __XFS_PLATFORM_DEFS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined (__powerpc__) /* ppc fix from: Robert Ramiega (jedi@plukwa.net) */ +# define __BYTEORDER_HAS_U64__ +#endif +#include + +#include +#include + +#ifndef O_DIRECT +# if defined (__powerpc__) +# define O_DIRECT 0400000 +# elif defined (__sparc__) +# define O_DIRECT 0x100000 +# endif +#endif + +#if (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ <= 1)) +# define constpp const char * const * +#else +# define constpp char * const * +#endif + +typedef loff_t xfs_off_t; +typedef __uint64_t xfs_ino_t; +typedef __uint32_t xfs_dev_t; +typedef __int64_t xfs_daddr_t; +typedef char* xfs_caddr_t; + +/* long and pointer must be either 32 bit or 64 bit */ +#undef HAVE_64BIT_LONG +#undef HAVE_32BIT_LONG +#undef HAVE_32BIT_PTR +#undef HAVE_64BIT_PTR + +/* Check if __psint_t is set to something meaningful */ +#undef HAVE___PSINT_T +#ifndef HAVE___PSINT_T +# ifdef HAVE_32BIT_PTR +typedef int __psint_t; +# elif defined HAVE_64BIT_PTR +# ifdef HAVE_64BIT_LONG +typedef long __psint_t; +# else +/* This is a very strange architecture, which has 64 bit pointers but + * not 64 bit longs. So, I'd just punt here and assume long long is Ok */ +typedef long long __psint_t; +# endif +# else +# error Unknown pointer size +# endif +#endif + +/* Check if __psunsigned_t is set to something meaningful */ +#undef HAVE___PSUNSIGNED_T +#ifndef HAVE___PSUNSIGNED_T +# ifdef HAVE_32BIT_PTR +typedef unsigned int __psunsigned_t; +# elif defined HAVE_64BIT_PTR +# ifdef HAVE_64BIT_LONG +typedef long __psunsigned_t; +# else +/* This is a very strange architecture, which has 64 bit pointers but + * not 64 bit longs. So, I'd just punt here and assume long long is Ok */ +typedef unsigned long long __psunsigned_t; +# endif +# else +# error Unknown pointer size +# endif +#endif + +#ifdef DEBUG +# define ASSERT assert +#else +# define ASSERT(EX) ((void) 0) +#endif + +#endif /* __XFS_PLATFORM_DEFS_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_ag.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_ag.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_ag.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_ag.h Mon May 14 22:43:23 2001 @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_AG_H__ +#define __XFS_AG_H__ + +/* + * Allocation group header + * This is divided into three structures, placed in sequential 512-byte + * buffers after a copy of the superblock (also in a 512-byte buffer). + */ + +struct xfs_buf; +struct xfs_mount; + +#define XFS_AGF_MAGIC 0x58414746 /* 'XAGF' */ +#define XFS_AGI_MAGIC 0x58414749 /* 'XAGI' */ +#define XFS_AGF_VERSION 1 +#define XFS_AGI_VERSION 1 +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGF_GOOD_VERSION) +int xfs_agf_good_version(unsigned v); +#define XFS_AGF_GOOD_VERSION(v) xfs_agf_good_version(v) +#else +#define XFS_AGF_GOOD_VERSION(v) ((v) == XFS_AGF_VERSION) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGI_GOOD_VERSION) +int xfs_agi_good_version(unsigned v); +#define XFS_AGI_GOOD_VERSION(v) xfs_agi_good_version(v) +#else +#define XFS_AGI_GOOD_VERSION(v) ((v) == XFS_AGI_VERSION) +#endif + +/* + * Btree number 0 is bno, 1 is cnt. This value gives the size of the + * arrays below. + */ +#define XFS_BTNUM_AGF ((int)XFS_BTNUM_CNTi + 1) + +/* + * The second word of agf_levels in the first a.g. overlaps the EFS + * superblock's magic number. Since the magic numbers valid for EFS + * are > 64k, our value cannot be confused for an EFS superblock's. + */ + +typedef struct xfs_agf +{ + /* + * Common allocation group header information + */ + __uint32_t agf_magicnum; /* magic number == XFS_AGF_MAGIC */ + __uint32_t agf_versionnum; /* header version == XFS_AGF_VERSION */ + xfs_agnumber_t agf_seqno; /* sequence # starting from 0 */ + xfs_agblock_t agf_length; /* size in blocks of a.g. */ + /* + * Freespace information + */ + xfs_agblock_t agf_roots[XFS_BTNUM_AGF]; /* root blocks */ + __uint32_t agf_spare0; /* spare field */ + __uint32_t agf_levels[XFS_BTNUM_AGF]; /* btree levels */ + __uint32_t agf_spare1; /* spare field */ + __uint32_t agf_flfirst; /* first freelist block's index */ + __uint32_t agf_fllast; /* last freelist block's index */ + __uint32_t agf_flcount; /* count of blocks in freelist */ + xfs_extlen_t agf_freeblks; /* total free blocks */ + xfs_extlen_t agf_longest; /* longest free space */ +} xfs_agf_t; + +#define XFS_AGF_MAGICNUM 0x00000001 +#define XFS_AGF_VERSIONNUM 0x00000002 +#define XFS_AGF_SEQNO 0x00000004 +#define XFS_AGF_LENGTH 0x00000008 +#define XFS_AGF_ROOTS 0x00000010 +#define XFS_AGF_LEVELS 0x00000020 +#define XFS_AGF_FLFIRST 0x00000040 +#define XFS_AGF_FLLAST 0x00000080 +#define XFS_AGF_FLCOUNT 0x00000100 +#define XFS_AGF_FREEBLKS 0x00000200 +#define XFS_AGF_LONGEST 0x00000400 +#define XFS_AGF_NUM_BITS 11 +#define XFS_AGF_ALL_BITS ((1 << XFS_AGF_NUM_BITS) - 1) + +/* disk block (xfs_daddr_t) in the AG */ +#define XFS_AGF_DADDR ((xfs_daddr_t)1) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGF_BLOCK) +xfs_agblock_t xfs_agf_block(struct xfs_mount *mp); +#define XFS_AGF_BLOCK(mp) xfs_agf_block(mp) +#else +#define XFS_AGF_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGF_DADDR) +#endif + +/* + * Size of the unlinked inode hash table in the agi. + */ +#define XFS_AGI_UNLINKED_BUCKETS 64 + +typedef struct xfs_agi +{ + /* + * Common allocation group header information + */ + __uint32_t agi_magicnum; /* magic number == XFS_AGI_MAGIC */ + __uint32_t agi_versionnum; /* header version == XFS_AGI_VERSION */ + xfs_agnumber_t agi_seqno; /* sequence # starting from 0 */ + xfs_agblock_t agi_length; /* size in blocks of a.g. */ + /* + * Inode information + * Inodes are mapped by interpreting the inode number, so no + * mapping data is needed here. + */ + xfs_agino_t agi_count; /* count of allocated inodes */ + xfs_agblock_t agi_root; /* root of inode btree */ + __uint32_t agi_level; /* levels in inode btree */ + xfs_agino_t agi_freecount; /* number of free inodes */ + xfs_agino_t agi_newino; /* new inode just allocated */ + xfs_agino_t agi_dirino; /* last directory inode chunk */ + /* + * Hash table of inodes which have been unlinked but are + * still being referenced. + */ + xfs_agino_t agi_unlinked[XFS_AGI_UNLINKED_BUCKETS]; +} xfs_agi_t; + +#define XFS_AGI_MAGICNUM 0x00000001 +#define XFS_AGI_VERSIONNUM 0x00000002 +#define XFS_AGI_SEQNO 0x00000004 +#define XFS_AGI_LENGTH 0x00000008 +#define XFS_AGI_COUNT 0x00000010 +#define XFS_AGI_ROOT 0x00000020 +#define XFS_AGI_LEVEL 0x00000040 +#define XFS_AGI_FREECOUNT 0x00000080 +#define XFS_AGI_NEWINO 0x00000100 +#define XFS_AGI_DIRINO 0x00000200 +#define XFS_AGI_UNLINKED 0x00000400 +#define XFS_AGI_NUM_BITS 11 +#define XFS_AGI_ALL_BITS ((1 << XFS_AGI_NUM_BITS) - 1) + +/* disk block (xfs_daddr_t) in the AG */ +#define XFS_AGI_DADDR ((xfs_daddr_t)2) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGI_BLOCK) +xfs_agblock_t xfs_agi_block(struct xfs_mount *mp); +#define XFS_AGI_BLOCK(mp) xfs_agi_block(mp) +#else +#define XFS_AGI_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGI_DADDR) +#endif + +/* + * The third a.g. block contains the a.g. freelist, an array + * of block pointers to blocks owned by the allocation btree code. + */ +#define XFS_AGFL_DADDR ((xfs_daddr_t)3) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGFL_BLOCK) +xfs_agblock_t xfs_agfl_block(struct xfs_mount *mp); +#define XFS_AGFL_BLOCK(mp) xfs_agfl_block(mp) +#else +#define XFS_AGFL_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGFL_DADDR) +#endif +#define XFS_AGFL_SIZE (BBSIZE / sizeof(xfs_agblock_t)) +typedef struct xfs_agfl +{ + xfs_agblock_t agfl_bno[XFS_AGFL_SIZE]; +} xfs_agfl_t; + +/* + * Per-ag incore structure, copies of information in agf and agi, + * to improve the performance of allocation group selection. + */ +typedef struct xfs_perag +{ + char pagf_init; /* this agf's entry is initialized */ + char pagi_init; /* this agi's entry is initialized */ + __uint8_t pagf_levels[XFS_BTNUM_AGF]; + /* # of levels in bno & cnt btree */ + __uint32_t pagf_flcount; /* count of blocks in freelist */ + xfs_extlen_t pagf_freeblks; /* total free blocks */ + xfs_extlen_t pagf_longest; /* longest free space */ + xfs_agino_t pagi_freecount; /* number of free inodes */ +} xfs_perag_t; + +#define XFS_AG_MIN_BYTES (1LL << 24) /* 16 MB */ +#define XFS_AG_BEST_BYTES (1LL << 30) /* 1 GB */ +#define XFS_AG_MAX_BYTES (1LL << 32) /* 4 GB */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_MIN_BLOCKS) +xfs_extlen_t xfs_ag_min_blocks(int bl); +#define XFS_AG_MIN_BLOCKS(bl) xfs_ag_min_blocks(bl) +#else +#define XFS_AG_MIN_BLOCKS(bl) ((xfs_extlen_t)(XFS_AG_MIN_BYTES >> bl)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_BEST_BLOCKS) +xfs_extlen_t xfs_ag_best_blocks(int bl, xfs_drfsbno_t blks); +#define XFS_AG_BEST_BLOCKS(bl,blks) xfs_ag_best_blocks(bl,blks) +#else +/*--#define XFS_AG_BEST_BLOCKS(bl) ((xfs_extlen_t)(XFS_AG_BEST_BYTES >> bl))*/ +/* + * Best is XFS_AG_BEST_BLOCKS at and below 64 Gigabyte filesystems, and + * XFS_AG_MAX_BLOCKS above 64 Gigabytes. + */ +#define XFS_AG_BEST_BLOCKS(bl,blks) ((xfs_extlen_t)((1LL << (36 - bl)) >= \ + blks) ? \ + ((xfs_extlen_t)(XFS_AG_BEST_BYTES >> bl)) : \ + XFS_AG_MAX_BLOCKS(bl)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_MAX_BLOCKS) +xfs_extlen_t xfs_ag_max_blocks(int bl); +#define XFS_AG_MAX_BLOCKS(bl) xfs_ag_max_blocks(bl) +#else +#define XFS_AG_MAX_BLOCKS(bl) ((xfs_extlen_t)(XFS_AG_MAX_BYTES >> bl)) +#endif + +#define XFS_MAX_AGNUMBER ((xfs_agnumber_t)(NULLAGNUMBER - 1)) + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_MAXLEVELS) +int xfs_ag_maxlevels(struct xfs_mount *mp); +#define XFS_AG_MAXLEVELS(mp) xfs_ag_maxlevels(mp) +#else +#define XFS_AG_MAXLEVELS(mp) ((mp)->m_ag_maxlevels) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MIN_FREELIST) +int xfs_min_freelist(xfs_agf_t *a, struct xfs_mount *mp); +#define XFS_MIN_FREELIST(a,mp) xfs_min_freelist(a,mp) +#else +#define XFS_MIN_FREELIST(a,mp) \ + XFS_MIN_FREELIST_RAW( \ + INT_GET((a)->agf_levels[XFS_BTNUM_BNOi], ARCH_CONVERT), \ + INT_GET((a)->agf_levels[XFS_BTNUM_CNTi], ARCH_CONVERT), mp) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MIN_FREELIST_PAG) +int xfs_min_freelist_pag(xfs_perag_t *pag, struct xfs_mount *mp); +#define XFS_MIN_FREELIST_PAG(pag,mp) xfs_min_freelist_pag(pag,mp) +#else +#define XFS_MIN_FREELIST_PAG(pag,mp) \ + XFS_MIN_FREELIST_RAW((pag)->pagf_levels[XFS_BTNUM_BNOi], \ + (pag)->pagf_levels[XFS_BTNUM_CNTi], mp) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MIN_FREELIST_RAW) +int xfs_min_freelist_raw(int bl, int cl, struct xfs_mount *mp); +#define XFS_MIN_FREELIST_RAW(bl,cl,mp) xfs_min_freelist_raw(bl,cl,mp) +#else +#define XFS_MIN_FREELIST_RAW(bl,cl,mp) \ + (MIN(bl + 1, XFS_AG_MAXLEVELS(mp)) + \ + MIN(cl + 1, XFS_AG_MAXLEVELS(mp))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGB_TO_FSB) +xfs_fsblock_t xfs_agb_to_fsb(struct xfs_mount *mp, xfs_agnumber_t agno, + xfs_agblock_t agbno); +#define XFS_AGB_TO_FSB(mp,agno,agbno) xfs_agb_to_fsb(mp,agno,agbno) +#else +#define XFS_AGB_TO_FSB(mp,agno,agbno) \ + (((xfs_fsblock_t)(agno) << (mp)->m_sb.sb_agblklog) | (agbno)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_TO_AGNO) +xfs_agnumber_t xfs_fsb_to_agno(struct xfs_mount *mp, xfs_fsblock_t fsbno); +#define XFS_FSB_TO_AGNO(mp,fsbno) xfs_fsb_to_agno(mp,fsbno) +#else +#define XFS_FSB_TO_AGNO(mp,fsbno) \ + ((xfs_agnumber_t)((fsbno) >> (mp)->m_sb.sb_agblklog)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_TO_AGBNO) +xfs_agblock_t xfs_fsb_to_agbno(struct xfs_mount *mp, xfs_fsblock_t fsbno); +#define XFS_FSB_TO_AGBNO(mp,fsbno) xfs_fsb_to_agbno(mp,fsbno) +#else +#define XFS_FSB_TO_AGBNO(mp,fsbno) \ + ((xfs_agblock_t)((fsbno) & XFS_MASK32LO((mp)->m_sb.sb_agblklog))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGB_TO_DADDR) +xfs_daddr_t xfs_agb_to_daddr(struct xfs_mount *mp, xfs_agnumber_t agno, + xfs_agblock_t agbno); +#define XFS_AGB_TO_DADDR(mp,agno,agbno) xfs_agb_to_daddr(mp,agno,agbno) +#else +#define XFS_AGB_TO_DADDR(mp,agno,agbno) \ + ((xfs_daddr_t)(XFS_FSB_TO_BB(mp, \ + (xfs_fsblock_t)(agno) * (mp)->m_sb.sb_agblocks + (agbno)))) +#endif +/* + * XFS_DADDR_TO_AGNO and XFS_DADDR_TO_AGBNO moved to xfs_mount.h + * to avoid header file ordering change + */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_DADDR) +xfs_daddr_t xfs_ag_daddr(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_daddr_t d); +#define XFS_AG_DADDR(mp,agno,d) xfs_ag_daddr(mp,agno,d) +#else +#define XFS_AG_DADDR(mp,agno,d) (XFS_AGB_TO_DADDR(mp, agno, 0) + (d)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_AGF) +xfs_agf_t *xfs_buf_to_agf(struct xfs_buf *bp); +#define XFS_BUF_TO_AGF(bp) xfs_buf_to_agf(bp) +#else +#define XFS_BUF_TO_AGF(bp) ((xfs_agf_t *)XFS_BUF_PTR(bp)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_AGI) +xfs_agi_t *xfs_buf_to_agi(struct xfs_buf *bp); +#define XFS_BUF_TO_AGI(bp) xfs_buf_to_agi(bp) +#else +#define XFS_BUF_TO_AGI(bp) ((xfs_agi_t *)XFS_BUF_PTR(bp)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_AGFL) +xfs_agfl_t *xfs_buf_to_agfl(struct xfs_buf *bp); +#define XFS_BUF_TO_AGFL(bp) xfs_buf_to_agfl(bp) +#else +#define XFS_BUF_TO_AGFL(bp) ((xfs_agfl_t *)XFS_BUF_PTR(bp)) +#endif + +/* + * For checking for bad ranges of xfs_daddr_t's, covering multiple + * allocation groups or a single xfs_daddr_t that's a superblock copy. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_CHECK_DADDR) +void xfs_ag_check_daddr(struct xfs_mount *mp, xfs_daddr_t d, xfs_extlen_t len); +#define XFS_AG_CHECK_DADDR(mp,d,len) xfs_ag_check_daddr(mp,d,len) +#else +#define XFS_AG_CHECK_DADDR(mp,d,len) \ + ((len) == 1 ? \ + ASSERT((d) == XFS_SB_DADDR || \ + XFS_DADDR_TO_AGBNO(mp, d) != XFS_SB_DADDR) : \ + ASSERT(XFS_DADDR_TO_AGNO(mp, d) == \ + XFS_DADDR_TO_AGNO(mp, (d) + (len) - 1))) +#endif + +#endif /* __XFS_AG_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_alloc.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_alloc.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_alloc.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_alloc.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ALLOC_H__ +#define __XFS_ALLOC_H__ + +struct xfs_buf; +struct xfs_mount; +struct xfs_perag; +struct xfs_trans; + +/* + * Freespace allocation types. Argument to xfs_alloc_[v]extent. + */ +typedef enum xfs_alloctype +{ + XFS_ALLOCTYPE_ANY_AG, /* allocate anywhere, use rotor */ + XFS_ALLOCTYPE_FIRST_AG, /* ... start at ag 0 */ + XFS_ALLOCTYPE_START_AG, /* anywhere, start in this a.g. */ + XFS_ALLOCTYPE_THIS_AG, /* anywhere in this a.g. */ + XFS_ALLOCTYPE_START_BNO, /* near this block else anywhere */ + XFS_ALLOCTYPE_NEAR_BNO, /* in this a.g. and near this block */ + XFS_ALLOCTYPE_THIS_BNO /* at exactly this block */ +} xfs_alloctype_t; + +/* + * Flags for xfs_alloc_fix_freelist. + */ +#define XFS_ALLOC_FLAG_TRYLOCK 0x00000001 /* use trylock for buffer locking */ + +/* + * Argument structure for xfs_alloc routines. + * This is turned into a structure to avoid having 20 arguments passed + * down several levels of the stack. + */ +typedef struct xfs_alloc_arg { + struct xfs_trans *tp; /* transaction pointer */ + struct xfs_mount *mp; /* file system mount point */ + struct xfs_buf *agbp; /* buffer for a.g. freelist header */ + struct xfs_perag *pag; /* per-ag struct for this agno */ + xfs_fsblock_t fsbno; /* file system block number */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_agblock_t agbno; /* allocation group-relative block # */ + xfs_extlen_t minlen; /* minimum size of extent */ + xfs_extlen_t maxlen; /* maximum size of extent */ + xfs_extlen_t mod; /* mod value for extent size */ + xfs_extlen_t prod; /* prod value for extent size */ + xfs_extlen_t minleft; /* min blocks must be left after us */ + xfs_extlen_t total; /* total blocks needed in xaction */ + xfs_extlen_t alignment; /* align answer to multiple of this */ + xfs_extlen_t minalignslop; /* slop for minlen+alignment calcs */ + xfs_extlen_t len; /* output: actual size of extent */ + xfs_alloctype_t type; /* allocation type XFS_ALLOCTYPE_... */ + xfs_alloctype_t otype; /* original allocation type */ + char wasdel; /* set if allocation was prev delayed */ + char wasfromfl; /* set if allocation is from freelist */ + char isfl; /* set if is freelist blocks - !actg */ + char userdata; /* set if this is user data */ +} xfs_alloc_arg_t; + + +#ifdef __KERNEL__ + +/* + * Types for alloc tracing. + */ +#define XFS_ALLOC_KTRACE_ALLOC 1 +#define XFS_ALLOC_KTRACE_FREE 2 +#define XFS_ALLOC_KTRACE_MODAGF 3 +/* + * Allocation tracing buffer size. + */ +#define XFS_ALLOC_TRACE_SIZE 4096 + +#ifdef XFS_ALL_TRACE +#define XFS_ALLOC_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_ALLOC_TRACE +#endif + +/* + * Prototypes for visible xfs_alloc.c routines + */ + +/* + * Compute and fill in value of m_ag_maxlevels. + */ +void +xfs_alloc_compute_maxlevels( + struct xfs_mount *mp); /* file system mount structure */ + +/* + * Decide whether to use this allocation group for this allocation. + * If so, fix up the btree freelist's size. + * This is external so mkfs can call it, too. + */ +int /* error */ +xfs_alloc_fix_freelist( + xfs_alloc_arg_t *args, /* allocation argument structure */ + int flags); /* XFS_ALLOC_FLAG_... */ + +/* + * Get a block from the freelist. + * Returns with the buffer for the block gotten. + */ +int /* error */ +xfs_alloc_get_freelist( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_buf *agbp, /* buffer containing the agf structure */ + xfs_agblock_t *bnop); /* block address retrieved from freelist */ + +/* + * Log the given fields from the agf structure. + */ +void +xfs_alloc_log_agf( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_buf *bp, /* buffer for a.g. freelist header */ + int fields);/* mask of fields to be logged (XFS_AGF_...) */ + +/* + * Interface for inode allocation to force the pag data to be initialized. + */ +int /* error */ +xfs_alloc_pagf_init( + struct xfs_mount *mp, /* file system mount structure */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + int flags); /* XFS_ALLOC_FLAGS_... */ + +/* + * Put the block on the freelist for the allocation group. + */ +int /* error */ +xfs_alloc_put_freelist( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_buf *agbp, /* buffer for a.g. freelist header */ + struct xfs_buf *agflbp,/* buffer for a.g. free block array */ + xfs_agblock_t bno); /* block being freed */ + +/* + * Read in the allocation group header (free/alloc section). + */ +int /* error */ +xfs_alloc_read_agf( + struct xfs_mount *mp, /* mount point structure */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + int flags, /* XFS_ALLOC_FLAG_... */ + struct xfs_buf **bpp); /* buffer for the ag freelist header */ + +/* + * Allocate an extent (variable-size). + */ +int /* error */ +xfs_alloc_vextent( + xfs_alloc_arg_t *args); /* allocation argument structure */ + +/* + * Free an extent. + */ +int /* error */ +xfs_free_extent( + struct xfs_trans *tp, /* transaction pointer */ + xfs_fsblock_t bno, /* starting block number of extent */ + xfs_extlen_t len); /* length of extent */ + +#endif /* __KERNEL__ */ + +#endif /* __XFS_ALLOC_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_alloc_btree.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_alloc_btree.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_alloc_btree.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_alloc_btree.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ALLOC_BTREE_H__ +#define __XFS_ALLOC_BTREE_H__ + +/* + * Freespace on-disk structures + */ + +struct xfs_buf; +struct xfs_btree_cur; +struct xfs_btree_sblock; +struct xfs_mount; + +/* + * There are two on-disk btrees, one sorted by blockno and one sorted + * by blockcount and blockno. All blocks look the same to make the code + * simpler; if we have time later, we'll make the optimizations. + */ +#define XFS_ABTB_MAGIC 0x41425442 /* 'ABTB' for bno tree */ +#define XFS_ABTC_MAGIC 0x41425443 /* 'ABTC' for cnt tree */ + +/* + * Data record/key structure + */ +typedef struct xfs_alloc_rec +{ + xfs_agblock_t ar_startblock; /* starting block number */ + xfs_extlen_t ar_blockcount; /* count of free blocks */ +} xfs_alloc_rec_t, xfs_alloc_key_t; + +typedef xfs_agblock_t xfs_alloc_ptr_t; /* btree pointer type */ + /* btree block header type */ +typedef struct xfs_btree_sblock xfs_alloc_block_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_ALLOC_BLOCK) +xfs_alloc_block_t *xfs_buf_to_alloc_block(struct xfs_buf *bp); +#define XFS_BUF_TO_ALLOC_BLOCK(bp) xfs_buf_to_alloc_block(bp) +#else +#define XFS_BUF_TO_ALLOC_BLOCK(bp) ((xfs_alloc_block_t *)(XFS_BUF_PTR(bp))) +#endif + +/* + * Real block structures have a size equal to the disk block size. + */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_BLOCK_SIZE) +int xfs_alloc_block_size(int lev, struct xfs_btree_cur *cur); +#define XFS_ALLOC_BLOCK_SIZE(lev,cur) xfs_alloc_block_size(lev,cur) +#else +#define XFS_ALLOC_BLOCK_SIZE(lev,cur) (1 << (cur)->bc_blocklog) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_BLOCK_MAXRECS) +int xfs_alloc_block_maxrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_ALLOC_BLOCK_MAXRECS(lev,cur) xfs_alloc_block_maxrecs(lev,cur) +#else +#define XFS_ALLOC_BLOCK_MAXRECS(lev,cur) \ + ((cur)->bc_mp->m_alloc_mxr[lev != 0]) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_BLOCK_MINRECS) +int xfs_alloc_block_minrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_ALLOC_BLOCK_MINRECS(lev,cur) xfs_alloc_block_minrecs(lev,cur) +#else +#define XFS_ALLOC_BLOCK_MINRECS(lev,cur) \ + ((cur)->bc_mp->m_alloc_mnr[lev != 0]) +#endif + +/* + * Minimum and maximum blocksize. + * The blocksize upper limit is pretty much arbitrary. + */ +#define XFS_MIN_BLOCKSIZE_LOG 9 /* i.e. 512 bytes */ +#define XFS_MAX_BLOCKSIZE_LOG 16 /* i.e. 65536 bytes */ +#define XFS_MIN_BLOCKSIZE (1 << XFS_MIN_BLOCKSIZE_LOG) +#define XFS_MAX_BLOCKSIZE (1 << XFS_MAX_BLOCKSIZE_LOG) + +/* + * block numbers in the AG; SB is BB 0, AGF is BB 1, AGI is BB 2, AGFL is BB 3 + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BNO_BLOCK) +xfs_agblock_t xfs_bno_block(struct xfs_mount *mp); +#define XFS_BNO_BLOCK(mp) xfs_bno_block(mp) +#else +#define XFS_BNO_BLOCK(mp) ((xfs_agblock_t)(XFS_AGFL_BLOCK(mp) + 1)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CNT_BLOCK) +xfs_agblock_t xfs_cnt_block(struct xfs_mount *mp); +#define XFS_CNT_BLOCK(mp) xfs_cnt_block(mp) +#else +#define XFS_CNT_BLOCK(mp) ((xfs_agblock_t)(XFS_BNO_BLOCK(mp) + 1)) +#endif + +/* + * Record, key, and pointer address macros for btree blocks. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_REC_ADDR) +xfs_alloc_rec_t *xfs_alloc_rec_addr(xfs_alloc_block_t *bb, int i, + struct xfs_btree_cur *cur); +#define XFS_ALLOC_REC_ADDR(bb,i,cur) xfs_alloc_rec_addr(bb,i,cur) +#else +#define XFS_ALLOC_REC_ADDR(bb,i,cur) \ + XFS_BTREE_REC_ADDR(XFS_ALLOC_BLOCK_SIZE(0,cur), xfs_alloc, bb, i, \ + XFS_ALLOC_BLOCK_MAXRECS(0, cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_KEY_ADDR) +xfs_alloc_key_t *xfs_alloc_key_addr(xfs_alloc_block_t *bb, int i, + struct xfs_btree_cur *cur); +#define XFS_ALLOC_KEY_ADDR(bb,i,cur) xfs_alloc_key_addr(bb,i,cur) +#else +#define XFS_ALLOC_KEY_ADDR(bb,i,cur) \ + XFS_BTREE_KEY_ADDR(XFS_ALLOC_BLOCK_SIZE(1,cur), xfs_alloc, bb, i, \ + XFS_ALLOC_BLOCK_MAXRECS(1, cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_PTR_ADDR) +xfs_alloc_ptr_t *xfs_alloc_ptr_addr(xfs_alloc_block_t *bb, int i, + struct xfs_btree_cur *cur); +#define XFS_ALLOC_PTR_ADDR(bb,i,cur) xfs_alloc_ptr_addr(bb,i,cur) +#else +#define XFS_ALLOC_PTR_ADDR(bb,i,cur) \ + XFS_BTREE_PTR_ADDR(XFS_ALLOC_BLOCK_SIZE(1,cur), xfs_alloc, bb, i, \ + XFS_ALLOC_BLOCK_MAXRECS(1, cur)) +#endif + +/* + * Prototypes for externally visible routines. + */ + +/* + * Decrement cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_alloc_decrement( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat); /* success/failure */ + +/* + * Delete the record pointed to by cur. + * The cursor refers to the place where the record was (could be inserted) + * when the operation returns. + */ +int /* error */ +xfs_alloc_delete( + struct xfs_btree_cur *cur, /* btree cursor */ + int *stat); /* success/failure */ + +/* + * Get the data from the pointed-to record. + */ +int /* error */ +xfs_alloc_get_rec( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agblock_t *bno, /* output: starting block of extent */ + xfs_extlen_t *len, /* output: length of extent */ + int *stat); /* output: success/failure */ + +/* + * Increment cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_alloc_increment( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat); /* success/failure */ + +/* + * Insert the current record at the point referenced by cur. + * The cursor may be inconsistent on return if splits have been done. + */ +int /* error */ +xfs_alloc_insert( + struct xfs_btree_cur *cur, /* btree cursor */ + int *stat); /* success/failure */ + +/* + * Lookup the record equal to [bno, len] in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_eq( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat); /* success/failure */ + +/* + * Lookup the first record greater than or equal to [bno, len] + * in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_ge( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat); /* success/failure */ + +/* + * Lookup the first record less than or equal to [bno, len] + * in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_le( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat); /* success/failure */ + +/* + * Update the record referred to by cur, to the value given by [bno, len]. + * This either works (return 0) or gets an EFSCORRUPTED error. + */ +int /* error */ +xfs_alloc_update( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len); /* length of extent */ + +#endif /* __XFS_ALLOC_BTREE_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_arch.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_arch.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_arch.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_arch.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ARCH_H__ +#define __XFS_ARCH_H__ + +#ifndef XFS_BIG_FILESYSTEMS +#error XFS_BIG_FILESYSTEMS must be defined true or false +#endif + +#define DIRINO4_GET_ARCH(pointer,arch) \ + ( ((arch) == ARCH_NOCONVERT) \ + ? \ + (INT_GET_UNALIGNED_32(pointer)) \ + : \ + (INT_GET_UNALIGNED_32_BE(pointer)) \ + ) + +#if XFS_BIG_FILESYSTEMS +#define DIRINO_GET_ARCH(pointer,arch) \ + ( ((arch) == ARCH_NOCONVERT) \ + ? \ + (INT_GET_UNALIGNED_64(pointer)) \ + : \ + (INT_GET_UNALIGNED_64_BE(pointer)) \ + ) +#else +/* MACHINE ARCHITECTURE dependent */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define DIRINO_GET_ARCH(pointer,arch) \ + DIRINO4_GET_ARCH((((__u8*)pointer)+4),arch) +#else +#define DIRINO_GET_ARCH(pointer,arch) \ + DIRINO4_GET_ARCH(pointer,arch) +#endif +#endif + +#define DIRINO_COPY_ARCH(from,to,arch) \ + if ((arch) == ARCH_NOCONVERT) { \ + bcopy(from,to,sizeof(xfs_ino_t)); \ + } else { \ + INT_SWAP_UNALIGNED_64(from,to); \ + } +#define DIRINO4_COPY_ARCH(from,to,arch) \ + if ((arch) == ARCH_NOCONVERT) { \ + bcopy((((__u8*)from+4)),to,sizeof(xfs_dir2_ino4_t)); \ + } else { \ + INT_SWAP_UNALIGNED_32(from,to); \ + } + +#endif /* __XFS_ARCH_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_attr_leaf.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_attr_leaf.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_attr_leaf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_attr_leaf.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ATTR_LEAF_H__ +#define __XFS_ATTR_LEAF_H__ + +/* + * Attribute storage layout, internal structure, access macros, etc. + * + * Attribute lists are structured around Btrees where all the data + * elements are in the leaf nodes. Attribute names are hashed into an int, + * then that int is used as the index into the Btree. Since the hashval + * of an attribute name may not be unique, we may have duplicate keys. The + * internal links in the Btree are logical block offsets into the file. + */ + +struct attrlist; +struct attrlist_cursor_kern; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_da_state; +struct xfs_da_state_blk; +struct xfs_inode; +struct xfs_trans; + +/*======================================================================== + * Attribute structure when equal to XFS_LBSIZE(mp) bytes. + *========================================================================*/ + +/* + * This is the structure of the leaf nodes in the Btree. + * + * Struct leaf_entry's are packed from the top. Name/values grow from the + * bottom but are not packed. The freemap contains run-length-encoded entries + * for the free bytes after the leaf_entry's, but only the N largest such, + * smaller runs are dropped. When the freemap doesn't show enough space + * for an allocation, we compact the name/value area and try again. If we + * still don't have enough space, then we have to split the block. The + * name/value structs (both local and remote versions) must be 32bit aligned. + * + * Since we have duplicate hash keys, for each key that matches, compare + * the actual name string. The root and intermediate node search always + * takes the first-in-the-block key match found, so we should only have + * to work "forw"ard. If none matches, continue with the "forw"ard leaf + * nodes until the hash key changes or the attribute name is found. + * + * We store the fact that an attribute is a ROOT versus USER attribute in + * the leaf_entry. The namespaces are independent only because we also look + * at the root/user bit when we are looking for a matching attribute name. + * + * We also store a "incomplete" bit in the leaf_entry. It shows that an + * attribute is in the middle of being created and should not be shown to + * the user if we crash during the time that the bit is set. We clear the + * bit when we have finished setting up the attribute. We do this because + * we cannot create some large attributes inside a single transaction, and we + * need some indication that we weren't finished if we crash in the middle. + */ +#define XFS_ATTR_LEAF_MAPSIZE 3 /* how many freespace slots */ + +typedef struct xfs_attr_leafblock { + struct xfs_attr_leaf_hdr { /* constant-structure header block */ + xfs_da_blkinfo_t info; /* block type, links, etc. */ + __uint16_t count; /* count of active leaf_entry's */ + __uint16_t usedbytes; /* num bytes of names/values stored */ + __uint16_t firstused; /* first used byte in name area */ + __uint8_t holes; /* != 0 if blk needs compaction */ + __uint8_t pad1; + struct xfs_attr_leaf_map { /* RLE map of free bytes */ + __uint16_t base; /* base of free region */ + __uint16_t size; /* length of free region */ + } freemap[XFS_ATTR_LEAF_MAPSIZE]; /* N largest free regions */ + } hdr; + struct xfs_attr_leaf_entry { /* sorted on key, not name */ + xfs_dahash_t hashval; /* hash value of name */ + __uint16_t nameidx; /* index into buffer of name/value */ + __uint8_t flags; /* LOCAL, ROOT and INCOMPLETE flags */ + __uint8_t pad2; /* unused pad byte */ + } entries[1]; /* variable sized array */ + struct xfs_attr_leaf_name_local { + __uint16_t valuelen; /* number of bytes in value */ + __uint8_t namelen; /* length of name bytes */ + __uint8_t nameval[1]; /* name/value bytes */ + } namelist; /* grows from bottom of buf */ + struct xfs_attr_leaf_name_remote { + xfs_dablk_t valueblk; /* block number of value bytes */ + __uint32_t valuelen; /* number of bytes in value */ + __uint8_t namelen; /* length of name bytes */ + __uint8_t name[1]; /* name bytes */ + } valuelist; /* grows from bottom of buf */ +} xfs_attr_leafblock_t; +typedef struct xfs_attr_leaf_hdr xfs_attr_leaf_hdr_t; +typedef struct xfs_attr_leaf_map xfs_attr_leaf_map_t; +typedef struct xfs_attr_leaf_entry xfs_attr_leaf_entry_t; +typedef struct xfs_attr_leaf_name_local xfs_attr_leaf_name_local_t; +typedef struct xfs_attr_leaf_name_remote xfs_attr_leaf_name_remote_t; + +/* + * Flags used in the leaf_entry[i].flags field. + * NOTE: the INCOMPLETE bit must not collide with the flags bits specified + * on the system call, they are "or"ed together for various operations. + */ +#define XFS_ATTR_LOCAL_BIT 0 /* attr is stored locally */ +#define XFS_ATTR_ROOT_BIT 1 /* limit access to attr to userid 0 */ +#define XFS_ATTR_INCOMPLETE_BIT 7 /* attr in middle of create/delete */ +#define XFS_ATTR_LOCAL (1 << XFS_ATTR_LOCAL_BIT) +#define XFS_ATTR_ROOT (1 << XFS_ATTR_ROOT_BIT) +#define XFS_ATTR_INCOMPLETE (1 << XFS_ATTR_INCOMPLETE_BIT) + +/* + * Alignment for namelist and valuelist entries (since they are mixed + * there can be only one alignment value) + */ +#define XFS_ATTR_LEAF_NAME_ALIGN ((uint)sizeof(xfs_dablk_t)) + +/* + * Cast typed pointers for "local" and "remote" name/value structs. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_NAME_REMOTE) +xfs_attr_leaf_name_remote_t * +xfs_attr_leaf_name_remote(xfs_attr_leafblock_t *leafp, int idx); +#define XFS_ATTR_LEAF_NAME_REMOTE(leafp,idx) \ + xfs_attr_leaf_name_remote(leafp,idx) +#else +#define XFS_ATTR_LEAF_NAME_REMOTE(leafp,idx) /* remote name struct ptr */ \ + ((xfs_attr_leaf_name_remote_t *) \ + &((char *)(leafp))[ INT_GET((leafp)->entries[idx].nameidx, ARCH_CONVERT) ]) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_NAME_LOCAL) +xfs_attr_leaf_name_local_t * +xfs_attr_leaf_name_local(xfs_attr_leafblock_t *leafp, int idx); +#define XFS_ATTR_LEAF_NAME_LOCAL(leafp,idx) \ + xfs_attr_leaf_name_local(leafp,idx) +#else +#define XFS_ATTR_LEAF_NAME_LOCAL(leafp,idx) /* local name struct ptr */ \ + ((xfs_attr_leaf_name_local_t *) \ + &((char *)(leafp))[ INT_GET((leafp)->entries[idx].nameidx, ARCH_CONVERT) ]) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_NAME) +char *xfs_attr_leaf_name(xfs_attr_leafblock_t *leafp, int idx); +#define XFS_ATTR_LEAF_NAME(leafp,idx) xfs_attr_leaf_name(leafp,idx) +#else +#define XFS_ATTR_LEAF_NAME(leafp,idx) /* generic name struct ptr */ \ + (&((char *)(leafp))[ INT_GET((leafp)->entries[idx].nameidx, ARCH_CONVERT) ]) +#endif + +/* + * Calculate total bytes used (including trailing pad for alignment) for + * a "local" name/value structure, a "remote" name/value structure, and + * a pointer which might be either. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_ENTSIZE_REMOTE) +int xfs_attr_leaf_entsize_remote(int nlen); +#define XFS_ATTR_LEAF_ENTSIZE_REMOTE(nlen) \ + xfs_attr_leaf_entsize_remote(nlen) +#else +#define XFS_ATTR_LEAF_ENTSIZE_REMOTE(nlen) /* space for remote struct */ \ + (((uint)sizeof(xfs_attr_leaf_name_remote_t) - 1 + (nlen) + \ + XFS_ATTR_LEAF_NAME_ALIGN - 1) & ~(XFS_ATTR_LEAF_NAME_ALIGN - 1)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_ENTSIZE_LOCAL) +int xfs_attr_leaf_entsize_local(int nlen, int vlen); +#define XFS_ATTR_LEAF_ENTSIZE_LOCAL(nlen,vlen) \ + xfs_attr_leaf_entsize_local(nlen,vlen) +#else +#define XFS_ATTR_LEAF_ENTSIZE_LOCAL(nlen,vlen) /* space for local struct */ \ + (((uint)sizeof(xfs_attr_leaf_name_local_t) - 1 + (nlen) + (vlen) + \ + XFS_ATTR_LEAF_NAME_ALIGN - 1) & ~(XFS_ATTR_LEAF_NAME_ALIGN - 1)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX) +int xfs_attr_leaf_entsize_local_max(int bsize); +#define XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX(bsize) \ + xfs_attr_leaf_entsize_local_max(bsize) +#else +#define XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX(bsize) /* max local struct size */ \ + (((bsize) >> 1) + ((bsize) >> 2)) +#endif + + +/*======================================================================== + * Structure used to pass context around among the routines. + *========================================================================*/ + +typedef struct xfs_attr_list_context { + struct xfs_inode *dp; /* inode */ + struct attrlist_cursor_kern *cursor;/* position in list */ + struct attrlist *alist; /* output buffer */ + int count; /* num used entries */ + int dupcnt; /* count dup hashvals seen */ + int bufsize;/* total buffer size */ + int firstu; /* first used byte in buffer */ + int flags; /* from VOP call */ + int resynch;/* T/F: resynch with cursor */ +} xfs_attr_list_context_t; + +/* + * Used to keep a list of "remote value" extents when unlinking an inode. + */ +typedef struct xfs_attr_inactive_list { + xfs_dablk_t valueblk; /* block number of value bytes */ + int valuelen; /* number of bytes in value */ +} xfs_attr_inactive_list_t; + + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Internal routines when dirsize < XFS_LITINO(mp). + */ +int xfs_attr_shortform_create(struct xfs_da_args *args); +int xfs_attr_shortform_add(struct xfs_da_args *add); +int xfs_attr_shortform_lookup(struct xfs_da_args *args); +int xfs_attr_shortform_getvalue(struct xfs_da_args *args); +int xfs_attr_shortform_to_leaf(struct xfs_da_args *args); +int xfs_attr_shortform_remove(struct xfs_da_args *remove); +int xfs_attr_shortform_list(struct xfs_attr_list_context *context); +int xfs_attr_shortform_replace(struct xfs_da_args *args); +int xfs_attr_shortform_allfit(struct xfs_dabuf *bp, struct xfs_inode *dp); + +/* + * Internal routines when dirsize == XFS_LBSIZE(mp). + */ +int xfs_attr_leaf_to_node(struct xfs_da_args *args); +int xfs_attr_leaf_to_shortform(struct xfs_dabuf *bp, + struct xfs_da_args *args); +int xfs_attr_leaf_clearflag(struct xfs_da_args *args); +int xfs_attr_leaf_setflag(struct xfs_da_args *args); +int xfs_attr_leaf_flipflags(xfs_da_args_t *args); + +/* + * Routines used for growing the Btree. + */ +int xfs_attr_leaf_create(struct xfs_da_args *args, xfs_dablk_t which_block, + struct xfs_dabuf **bpp); +int xfs_attr_leaf_split(struct xfs_da_state *state, + struct xfs_da_state_blk *oldblk, + struct xfs_da_state_blk *newblk); +int xfs_attr_leaf_lookup_int(struct xfs_dabuf *leaf, + struct xfs_da_args *args); +int xfs_attr_leaf_getvalue(struct xfs_dabuf *bp, struct xfs_da_args *args); +int xfs_attr_leaf_add(struct xfs_dabuf *leaf_buffer, + struct xfs_da_args *args); +int xfs_attr_leaf_remove(struct xfs_dabuf *leaf_buffer, + struct xfs_da_args *args); +int xfs_attr_leaf_list_int(struct xfs_dabuf *bp, + struct xfs_attr_list_context *context); + +/* + * Routines used for shrinking the Btree. + */ +int xfs_attr_leaf_toosmall(struct xfs_da_state *state, int *retval); +void xfs_attr_leaf_unbalance(struct xfs_da_state *state, + struct xfs_da_state_blk *drop_blk, + struct xfs_da_state_blk *save_blk); +int xfs_attr_root_inactive(struct xfs_trans **trans, struct xfs_inode *dp); +int xfs_attr_node_inactive(struct xfs_trans **trans, struct xfs_inode *dp, + struct xfs_dabuf *bp, int level); +int xfs_attr_leaf_inactive(struct xfs_trans **trans, struct xfs_inode *dp, + struct xfs_dabuf *bp); +int xfs_attr_leaf_freextent(struct xfs_trans **trans, struct xfs_inode *dp, + xfs_dablk_t blkno, int blkcnt); + +/* + * Utility routines. + */ +xfs_dahash_t xfs_attr_leaf_lasthash(struct xfs_dabuf *bp, int *count); +int xfs_attr_leaf_order(struct xfs_dabuf *leaf1_bp, + struct xfs_dabuf *leaf2_bp); +int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int blocksize, + int *local); +int xfs_attr_leaf_entsize(struct xfs_attr_leafblock *leaf, int index); +int xfs_attr_put_listent(struct xfs_attr_list_context *context, + char *name, int namelen, int valuelen); +int xfs_attr_rolltrans(struct xfs_trans **transp, struct xfs_inode *dp); + +#endif /* __XFS_ATTR_LEAF_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_attr_sf.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_attr_sf.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_attr_sf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_attr_sf.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ATTR_SF_H__ +#define __XFS_ATTR_SF_H__ + +/* + * Attribute storage when stored inside the inode. + * + * Small attribute lists are packed as tightly as possible so as + * to fit into the literal area of the inode. + */ + +struct xfs_inode; + +/* + * Entries are packed toward the top as tight as possible. + */ +typedef struct xfs_attr_shortform { + struct xfs_attr_sf_hdr { /* constant-structure header block */ + __uint16_t totsize; /* total bytes in shortform list */ + __uint8_t count; /* count of active entries */ + } hdr; + struct xfs_attr_sf_entry { + __uint8_t namelen; /* actual length of name (no NULL) */ + __uint8_t valuelen; /* actual length of value (no NULL) */ + __uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */ + __uint8_t nameval[1]; /* name & value bytes concatenated */ + } list[1]; /* variable sized array */ +} xfs_attr_shortform_t; +typedef struct xfs_attr_sf_hdr xfs_attr_sf_hdr_t; +typedef struct xfs_attr_sf_entry xfs_attr_sf_entry_t; + +/* + * We generate this then sort it, attr_list() must return things in hash-order. + */ +typedef struct xfs_attr_sf_sort { + __uint8_t entno; /* entry number in original list */ + __uint8_t namelen; /* length of name value (no null) */ + __uint8_t valuelen; /* length of value */ + xfs_dahash_t hash; /* this entry's hash value */ + char *name; /* name value, pointer into buffer */ +} xfs_attr_sf_sort_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_SF_ENTSIZE_BYNAME) +int xfs_attr_sf_entsize_byname(int nlen, int vlen); +#define XFS_ATTR_SF_ENTSIZE_BYNAME(nlen,vlen) \ + xfs_attr_sf_entsize_byname(nlen,vlen) +#else +#define XFS_ATTR_SF_ENTSIZE_BYNAME(nlen,vlen) /* space name/value uses */ \ + ((int)sizeof(xfs_attr_sf_entry_t)-1 + (nlen)+(vlen)) +#endif +#define XFS_ATTR_SF_ENTSIZE_MAX /* max space for name&value */ \ + ((1 << (NBBY*(int)sizeof(__uint8_t))) - 1) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_SF_ENTSIZE) +int xfs_attr_sf_entsize(xfs_attr_sf_entry_t *sfep); +#define XFS_ATTR_SF_ENTSIZE(sfep) xfs_attr_sf_entsize(sfep) +#else +#define XFS_ATTR_SF_ENTSIZE(sfep) /* space an entry uses */ \ + ((int)sizeof(xfs_attr_sf_entry_t)-1 + (sfep)->namelen+(sfep)->valuelen) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_SF_NEXTENTRY) +xfs_attr_sf_entry_t *xfs_attr_sf_nextentry(xfs_attr_sf_entry_t *sfep); +#define XFS_ATTR_SF_NEXTENTRY(sfep) xfs_attr_sf_nextentry(sfep) +#else +#define XFS_ATTR_SF_NEXTENTRY(sfep) /* next entry in struct */ \ + ((xfs_attr_sf_entry_t *) \ + ((char *)(sfep) + XFS_ATTR_SF_ENTSIZE(sfep))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_SF_TOTSIZE) +int xfs_attr_sf_totsize(struct xfs_inode *dp); +#define XFS_ATTR_SF_TOTSIZE(dp) xfs_attr_sf_totsize(dp) +#else +#define XFS_ATTR_SF_TOTSIZE(dp) /* total space in use */ \ + (INT_GET(((xfs_attr_shortform_t *)((dp)->i_afp->if_u1.if_data))->hdr.totsize, ARCH_CONVERT)) +#endif + +#ifdef XFS_ALL_TRACE +#define XFS_ATTR_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_ATTR_TRACE +#endif + +/* + * Kernel tracing support for attribute lists + */ +struct xfs_attr_list_context; +struct xfs_da_intnode; +struct xfs_da_node_entry; +struct xfs_attr_leafblock; + +#define XFS_ATTR_TRACE_SIZE 4096 /* size of global trace buffer */ + +/* + * Trace record types. + */ +#define XFS_ATTR_KTRACE_L_C 1 /* context */ +#define XFS_ATTR_KTRACE_L_CN 2 /* context, node */ +#define XFS_ATTR_KTRACE_L_CB 3 /* context, btree */ +#define XFS_ATTR_KTRACE_L_CL 4 /* context, leaf */ + +#if defined(XFS_ATTR_TRACE) + +void xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context); +void xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context, + struct xfs_da_intnode *node); +void xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context, + struct xfs_da_node_entry *btree); +void xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, + struct xfs_attr_leafblock *leaf); +void xfs_attr_trace_enter(int type, char *where, + __psunsigned_t a2, __psunsigned_t a3, + __psunsigned_t a4, __psunsigned_t a5, + __psunsigned_t a6, __psunsigned_t a7, + __psunsigned_t a8, __psunsigned_t a9, + __psunsigned_t a10, __psunsigned_t a11, + __psunsigned_t a12, __psunsigned_t a13, + __psunsigned_t a14, __psunsigned_t a15); +#else +#define xfs_attr_trace_l_c(w,c) +#define xfs_attr_trace_l_cn(w,c,n) +#define xfs_attr_trace_l_cb(w,c,b) +#define xfs_attr_trace_l_cl(w,c,l) +#endif /* XFS_ATTR_TRACE */ + +#endif /* __XFS_ATTR_SF_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_bit.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_bit.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_bit.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_bit.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BIT_H__ +#define __XFS_BIT_H__ + +/* + * XFS bit manipulation routines. + */ + +/* + * masks with n high/low bits set, 32-bit values & 64-bit values + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MASK32HI) +__uint32_t xfs_mask32hi(int n); +#define XFS_MASK32HI(n) xfs_mask32hi(n) +#else +#define XFS_MASK32HI(n) ((__uint32_t)-1 << (32 - (n))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MASK64HI) +__uint64_t xfs_mask64hi(int n); +#define XFS_MASK64HI(n) xfs_mask64hi(n) +#else +#define XFS_MASK64HI(n) ((__uint64_t)-1 << (64 - (n))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MASK32LO) +__uint32_t xfs_mask32lo(int n); +#define XFS_MASK32LO(n) xfs_mask32lo(n) +#else +#define XFS_MASK32LO(n) (((__uint32_t)1 << (n)) - 1) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MASK64LO) +__uint64_t xfs_mask64lo(int n); +#define XFS_MASK64LO(n) xfs_mask64lo(n) +#else +#define XFS_MASK64LO(n) (((__uint64_t)1 << (n)) - 1) +#endif + +/* + * Index of low bit number in byte, -1 for none set, 0..7 otherwise. + */ +extern const char xfs_lowbit[256]; + +/* + * Index of high bit number in byte, -1 for none set, 0..7 otherwise. + */ +extern const char xfs_highbit[256]; + +/* + * Count of bits set in byte, 0..8. + */ +extern const char xfs_countbit[256]; + +/* + * xfs_lowbit32: get low bit set out of 32-bit argument, -1 if none set. + */ +extern int xfs_lowbit32(__uint32_t v); + +/* + * xfs_highbit32: get high bit set out of 32-bit argument, -1 if none set. + */ +extern int xfs_highbit32(__uint32_t v); + +/* + * xfs_lowbit64: get low bit set out of 64-bit argument, -1 if none set. + */ +extern int xfs_lowbit64(__uint64_t v); + +/* + * xfs_highbit64: get high bit set out of 64-bit argument, -1 if none set. + */ +extern int xfs_highbit64(__uint64_t); + +#endif /* __XFS_BIT_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_bmap.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_bmap.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_bmap.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_bmap.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BMAP_H__ +#define __XFS_BMAP_H__ + +struct getbmap; +struct xfs_bmbt_irec; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * List of extents to be free "later". + * The list is kept sorted on xbf_startblock. + */ +typedef struct xfs_bmap_free_item +{ + xfs_fsblock_t xbfi_startblock;/* starting fs block number */ + xfs_extlen_t xbfi_blockcount;/* number of blocks in extent */ + struct xfs_bmap_free_item *xbfi_next; /* link to next entry */ +} xfs_bmap_free_item_t; + +/* + * Header for free extent list. + */ +typedef struct xfs_bmap_free +{ + xfs_bmap_free_item_t *xbf_first; /* list of to-be-free extents */ + int xbf_count; /* count of items on list */ + int xbf_low; /* kludge: alloc in low mode */ +} xfs_bmap_free_t; + +#define XFS_BMAP_MAX_NMAP 4 + +/* + * Flags for xfs_bmapi + */ +#define XFS_BMAPI_WRITE 0x001 /* write operation: allocate space */ +#define XFS_BMAPI_DELAY 0x002 /* delayed write operation */ +#define XFS_BMAPI_ENTIRE 0x004 /* return entire extent, not trimmed */ +#define XFS_BMAPI_METADATA 0x008 /* mapping metadata not user data */ +#define XFS_BMAPI_EXACT 0x010 /* allocate only to spec'd bounds */ +#define XFS_BMAPI_ATTRFORK 0x020 /* use attribute fork not data */ +#define XFS_BMAPI_ASYNC 0x040 /* bunmapi xactions can be async */ +#define XFS_BMAPI_RSVBLOCKS 0x080 /* OK to alloc. reserved data blocks */ +#define XFS_BMAPI_PREALLOC 0x100 /* preallocation op: unwritten space */ +#define XFS_BMAPI_IGSTATE 0x200 /* Ignore state - */ + /* combine contig. space */ +#define XFS_BMAPI_CONTIG 0x400 /* must allocate only one extent */ +#define XFS_BMAPI_DIRECT_IO 0x800 /* Flag from cxfs client, not used + * by xfs directly. Indicates alloc + * request is for direct I/O not + * extent conversion by server */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAPI_AFLAG) +int xfs_bmapi_aflag(int w); +#define XFS_BMAPI_AFLAG(w) xfs_bmapi_aflag(w) +#else +#define XFS_BMAPI_AFLAG(w) ((w) == XFS_ATTR_FORK ? XFS_BMAPI_ATTRFORK : 0) +#endif + +/* + * Special values for xfs_bmbt_irec_t br_startblock field. + */ +#define DELAYSTARTBLOCK ((xfs_fsblock_t)-1LL) +#define HOLESTARTBLOCK ((xfs_fsblock_t)-2LL) + +/* + * Trace operations for bmap extent tracing + */ +#define XFS_BMAP_KTRACE_DELETE 1 +#define XFS_BMAP_KTRACE_INSERT 2 +#define XFS_BMAP_KTRACE_PRE_UP 3 +#define XFS_BMAP_KTRACE_POST_UP 4 + +#define XFS_BMAP_TRACE_SIZE 4096 /* size of global trace buffer */ +#define XFS_BMAP_KTRACE_SIZE 32 /* size of per-inode trace buffer */ + +#if defined(XFS_ALL_TRACE) +#define XFS_BMAP_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_BMAP_TRACE +#endif + + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_INIT) +void xfs_bmap_init(xfs_bmap_free_t *flp, xfs_fsblock_t *fbp); +#define XFS_BMAP_INIT(flp,fbp) xfs_bmap_init(flp,fbp) +#else +#define XFS_BMAP_INIT(flp,fbp) \ + ((flp)->xbf_first = NULL, (flp)->xbf_count = 0, \ + (flp)->xbf_low = 0, *(fbp) = NULLFSBLOCK) +#endif + +/* + * Argument structure for xfs_bmap_alloc. + */ +typedef struct xfs_bmalloca { + xfs_fsblock_t firstblock; /* i/o first block allocated */ + xfs_fsblock_t rval; /* starting block of new extent */ + xfs_fileoff_t off; /* offset in file filling in */ + struct xfs_trans *tp; /* transaction pointer */ + struct xfs_inode *ip; /* incore inode pointer */ + struct xfs_bmbt_irec *prevp; /* extent before the new one */ + struct xfs_bmbt_irec *gotp; /* extent after, or delayed */ + xfs_extlen_t alen; /* i/o length asked/allocated */ + xfs_extlen_t total; /* total blocks needed for xaction */ + xfs_extlen_t minlen; /* mininum allocation size (blocks) */ + xfs_extlen_t minleft; /* amount must be left after alloc */ + int eof; /* set if allocating past last extent */ + int wasdel; /* replacing a delayed allocation */ + int userdata;/* set if is user data */ + int low; /* low on space, using seq'l ags */ + int aeof; /* allocated space at eof */ +} xfs_bmalloca_t; + +#ifdef __KERNEL__ +/* + * Convert inode from non-attributed to attributed. + * Must not be in a transaction, ip must not be locked. + */ +int /* error code */ +xfs_bmap_add_attrfork( + struct xfs_inode *ip, /* incore inode pointer */ + int rsvd); /* flag for reserved block allocation */ + +/* + * Add the extent to the list of extents to be free at transaction end. + * The list is maintained sorted (by block number). + */ +void +xfs_bmap_add_free( + xfs_fsblock_t bno, /* fs block number of extent */ + xfs_filblks_t len, /* length of extent */ + xfs_bmap_free_t *flist, /* list of extents */ + struct xfs_mount *mp); /* mount point structure */ + +/* + * Routine to clean up the free list data structure when + * an error occurs during a transaction. + */ +void +xfs_bmap_cancel( + xfs_bmap_free_t *flist); /* free list to clean up */ + +/* + * Routine to check if a specified inode is swap capable. + */ +int +xfs_bmap_check_swappable( + struct xfs_inode *ip); /* incore inode */ + +/* + * Compute and fill in the value of the maximum depth of a bmap btree + * in this filesystem. Done once, during mount. + */ +void +xfs_bmap_compute_maxlevels( + struct xfs_mount *mp, /* file system mount structure */ + int whichfork); /* data or attr fork */ + +/* + * Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi + * caller. Frees all the extents that need freeing, which must be done + * last due to locking considerations. + * + * Return 1 if the given transaction was committed and a new one allocated, + * and 0 otherwise. + */ +int /* error */ +xfs_bmap_finish( + struct xfs_trans **tp, /* transaction pointer addr */ + xfs_bmap_free_t *flist, /* i/o: list extents to free */ + xfs_fsblock_t firstblock, /* controlled a.g. for allocs */ + int *committed); /* xact committed or not */ + +/* + * Returns the file-relative block number of the first unused block in the file. + * This is the lowest-address hole if the file has holes, else the first block + * past the end of file. + */ +int /* error */ +xfs_bmap_first_unused( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_extlen_t len, /* size of hole to find */ + xfs_fileoff_t *unused, /* unused block num */ + int whichfork); /* data or attr fork */ + +/* + * Returns the file-relative block number of the last block + 1 before + * last_block (input value) in the file. + * This is not based on i_size, it is based on the extent list. + * Returns 0 for local files, as they do not have an extent list. + */ +int /* error */ +xfs_bmap_last_before( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t *last_block, /* last block */ + int whichfork); /* data or attr fork */ + +/* + * Returns the file-relative block number of the first block past eof in + * the file. This is not based on i_size, it is based on the extent list. + * Returns 0 for local files, as they do not have an extent list. + */ +int /* error */ +xfs_bmap_last_offset( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t *unused, /* last block num */ + int whichfork); /* data or attr fork */ + +/* + * Returns whether the selected fork of the inode has exactly one + * block or not. For the data fork we check this matches di_size, + * implying the file's range is 0..bsize-1. + */ +int +xfs_bmap_one_block( + struct xfs_inode *ip, /* incore inode */ + int whichfork); /* data or attr fork */ + +/* + * Read in the extents to iu_extents. + * All inode fields are set up by caller, we just traverse the btree + * and copy the records in. + */ +int /* error */ +xfs_bmap_read_extents( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + int whichfork); /* data or attr fork */ + +#if defined(XFS_BMAP_TRACE) +/* + * Add bmap trace insert entries for all the contents of the extent list. + */ +void +xfs_bmap_trace_exlist( + char *fname, /* function name */ + struct xfs_inode *ip, /* incore inode pointer */ + xfs_extnum_t cnt, /* count of entries in list */ + int whichfork); /* data or attr fork */ +#else +#define xfs_bmap_trace_exlist(f,ip,c,w) +#endif + +/* + * Map file blocks to filesystem blocks. + * File range is given by the bno/len pair. + * Adds blocks to file if a write ("flags & XFS_BMAPI_WRITE" set) + * into a hole or past eof. + * Only allocates blocks from a single allocation group, + * to avoid locking problems. + * The returned value in "firstblock" from the first call in a transaction + * must be remembered and presented to subsequent calls in "firstblock". + * An upper bound for the number of blocks to be allocated is supplied to + * the first call in "total"; if no allocation group has that many free + * blocks then the call will fail (return NULLFSBLOCK in "firstblock"). + */ +int /* error */ +xfs_bmapi( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t bno, /* starting file offs. mapped */ + xfs_filblks_t len, /* length to map in file */ + int flags, /* XFS_BMAPI_... */ + xfs_fsblock_t *firstblock, /* first allocated block + controls a.g. for allocs */ + xfs_extlen_t total, /* total blocks needed */ + struct xfs_bmbt_irec *mval, /* output: map values */ + int *nmap, /* i/o: mval size/count */ + xfs_bmap_free_t *flist); /* i/o: list extents to free */ + +/* + * Map file blocks to filesystem blocks, simple version. + * One block only, read-only. + * For flags, only the XFS_BMAPI_ATTRFORK flag is examined. + * For the other flag values, the effect is as if XFS_BMAPI_METADATA + * was set and all the others were clear. + */ +int /* error */ +xfs_bmapi_single( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + int whichfork, /* data or attr fork */ + xfs_fsblock_t *fsb, /* output: mapped block */ + xfs_fileoff_t bno); /* starting file offs. mapped */ + +/* + * Unmap (remove) blocks from a file. + * If nexts is nonzero then the number of extents to remove is limited to + * that value. If not all extents in the block range can be removed then + * *done is set. + */ +int /* error */ +xfs_bunmapi( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t bno, /* starting offset to unmap */ + xfs_filblks_t len, /* length to unmap in file */ + int flags, /* XFS_BMAPI_... */ + xfs_extnum_t nexts, /* number of extents max */ + xfs_fsblock_t *firstblock, /* first allocated block + controls a.g. for allocs */ + xfs_bmap_free_t *flist, /* i/o: list extents to free */ + int *done); /* set if not done yet */ + +/* + * Fcntl interface to xfs_bmapi. + */ +int /* error code */ +xfs_getbmap( + bhv_desc_t *bdp, /* XFS behavior descriptor*/ + struct getbmap *bmv, /* user bmap structure */ + void *ap, /* pointer to user's array */ + int iflags); /* interface flags */ + +/* + * Check the last inode extent to determine whether this allocation will result + * in blocks being allocated at the end of the file. When we allocate new data + * blocks at the end of the file which do not start at the previous data block, + * we will try to align the new blocks at stripe unit boundaries. + */ +int +xfs_bmap_isaeof( + struct xfs_inode *ip, + xfs_fileoff_t off, + int whichfork, + int *aeof); + +/* + * Check if the endoff is outside the last extent. If so the caller will grow + * the allocation to a stripe unit boundary + */ +int +xfs_bmap_eof( + struct xfs_inode *ip, + xfs_fileoff_t endoff, + int whichfork, + int *eof); + +/* + * Count fsblocks of the given fork. + */ +int +xfs_bmap_count_blocks( + xfs_trans_t *tp, + xfs_inode_t *ip, + int whichfork, + int *count); + +/* + * Check an extent list, which has just been read, for + * any bit in the extent flag field. + */ +int +xfs_check_nostate_extents( + xfs_bmbt_rec_t *ep, + xfs_extnum_t num); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_BMAP_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_bmap_btree.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_bmap_btree.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_bmap_btree.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_bmap_btree.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,661 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BMAP_BTREE_H__ +#define __XFS_BMAP_BTREE_H__ + +#define XFS_BMAP_MAGIC 0x424d4150 /* 'BMAP' */ + +struct xfs_btree_cur; +struct xfs_btree_lblock; +struct xfs_mount; +struct xfs_inode; + +/* + * Bmap root header, on-disk form only. + */ +typedef struct xfs_bmdr_block +{ + __uint16_t bb_level; /* 0 is a leaf */ + __uint16_t bb_numrecs; /* current # of data records */ +} xfs_bmdr_block_t; + +/* + * Bmap btree record and extent descriptor. + * For 32-bit kernels, + * l0:31 is an extent flag (value 1 indicates non-normal). + * l0:0-30 and l1:9-31 are startoff. + * l1:0-8, l2:0-31, and l3:21-31 are startblock. + * l3:0-20 are blockcount. + * For 64-bit kernels, + * l0:63 is an extent flag (value 1 indicates non-normal). + * l0:9-62 are startoff. + * l0:0-8 and l1:21-63 are startblock. + * l1:0-20 are blockcount. + */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +#define BMBT_TOTAL_BITLEN 128 /* 128 bits, 16 bytes */ +#define BMBT_EXNTFLAG_BITOFF 0 +#define BMBT_EXNTFLAG_BITLEN 1 +#define BMBT_STARTOFF_BITOFF (BMBT_EXNTFLAG_BITOFF + BMBT_EXNTFLAG_BITLEN) +#define BMBT_STARTOFF_BITLEN 54 +#define BMBT_STARTBLOCK_BITOFF (BMBT_STARTOFF_BITOFF + BMBT_STARTOFF_BITLEN) +#define BMBT_STARTBLOCK_BITLEN 52 +#define BMBT_BLOCKCOUNT_BITOFF \ + (BMBT_STARTBLOCK_BITOFF + BMBT_STARTBLOCK_BITLEN) +#define BMBT_BLOCKCOUNT_BITLEN (BMBT_TOTAL_BITLEN - BMBT_BLOCKCOUNT_BITOFF) + +#else + +#define BMBT_TOTAL_BITLEN 128 /* 128 bits, 16 bytes */ +#define BMBT_EXNTFLAG_BITOFF 63 +#define BMBT_EXNTFLAG_BITLEN 1 +#define BMBT_STARTOFF_BITOFF (BMBT_EXNTFLAG_BITOFF - BMBT_STARTOFF_BITLEN) +#define BMBT_STARTOFF_BITLEN 54 +#define BMBT_STARTBLOCK_BITOFF 85 /* 128 - 43 (other 9 is in first word) */ +#define BMBT_STARTBLOCK_BITLEN 52 +#define BMBT_BLOCKCOUNT_BITOFF 64 /* Start of second 64 bit container */ +#define BMBT_BLOCKCOUNT_BITLEN 21 + +#endif + + +#define BMBT_USE_64 1 + +typedef struct xfs_bmbt_rec_32 +{ + __uint32_t l0, l1, l2, l3; +} xfs_bmbt_rec_32_t; +typedef struct xfs_bmbt_rec_64 +{ + __uint64_t l0, l1; +} xfs_bmbt_rec_64_t; + +#if BMBT_USE_64 +typedef __uint64_t xfs_bmbt_rec_base_t; /* use this for casts */ +typedef xfs_bmbt_rec_64_t xfs_bmbt_rec_t, xfs_bmdr_rec_t; +#else /* !BMBT_USE_64 */ +typedef __uint32_t xfs_bmbt_rec_base_t; /* use this for casts */ +typedef xfs_bmbt_rec_32_t xfs_bmbt_rec_t, xfs_bmdr_rec_t; +#endif /* BMBT_USE_64 */ + +/* + * Values and macros for delayed-allocation startblock fields. + */ +#define STARTBLOCKVALBITS 17 +#define STARTBLOCKMASKBITS (15 + XFS_BIG_FILESYSTEMS * 20) +#define DSTARTBLOCKMASKBITS (15 + 20) +#define STARTBLOCKMASK \ + (((((xfs_fsblock_t)1) << STARTBLOCKMASKBITS) - 1) << STARTBLOCKVALBITS) +#define DSTARTBLOCKMASK \ + (((((xfs_dfsbno_t)1) << DSTARTBLOCKMASKBITS) - 1) << STARTBLOCKVALBITS) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_ISNULLSTARTBLOCK) +int isnullstartblock(xfs_fsblock_t x); +#define ISNULLSTARTBLOCK(x) isnullstartblock(x) +#else +#define ISNULLSTARTBLOCK(x) (((x) & STARTBLOCKMASK) == STARTBLOCKMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_ISNULLDSTARTBLOCK) +int isnulldstartblock(xfs_dfsbno_t x); +#define ISNULLDSTARTBLOCK(x) isnulldstartblock(x) +#else +#define ISNULLDSTARTBLOCK(x) (((x) & DSTARTBLOCKMASK) == DSTARTBLOCKMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_NULLSTARTBLOCK) +xfs_fsblock_t nullstartblock(int k); +#define NULLSTARTBLOCK(k) nullstartblock(k) +#else +#define NULLSTARTBLOCK(k) \ + ((ASSERT(k < (1 << STARTBLOCKVALBITS))), (STARTBLOCKMASK | (k))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_STARTBLOCKVAL) +xfs_filblks_t startblockval(xfs_fsblock_t x); +#define STARTBLOCKVAL(x) startblockval(x) +#else +#define STARTBLOCKVAL(x) ((xfs_filblks_t)((x) & ~STARTBLOCKMASK)) +#endif + +/* + * Possible extent formats. + */ +typedef enum { + XFS_EXTFMT_NOSTATE = 0, + XFS_EXTFMT_HASSTATE +} xfs_exntfmt_t; + +/* + * Possible extent states. + */ +typedef enum { + XFS_EXT_NORM, XFS_EXT_UNWRITTEN, + XFS_EXT_DMAPI_OFFLINE +} xfs_exntst_t; + +/* + * Extent state and extent format macros. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_EXTFMT_INODE ) +xfs_exntfmt_t xfs_extfmt_inode(struct xfs_inode *ip); +#define XFS_EXTFMT_INODE(x) xfs_extfmt_inode(x) +#else +#define XFS_EXTFMT_INODE(x) \ + (XFS_SB_VERSION_HASEXTFLGBIT(&((x)->i_mount->m_sb)) ? \ + XFS_EXTFMT_HASSTATE : XFS_EXTFMT_NOSTATE) +#endif +#define ISUNWRITTEN(x) ((x) == XFS_EXT_UNWRITTEN) + +/* + * Incore version of above. + */ +typedef struct xfs_bmbt_irec +{ + xfs_fileoff_t br_startoff; /* starting file offset */ + xfs_fsblock_t br_startblock; /* starting block number */ + xfs_filblks_t br_blockcount; /* number of blocks */ + xfs_exntst_t br_state; /* extent state */ +} xfs_bmbt_irec_t; + +/* + * Key structure for non-leaf levels of the tree. + */ +typedef struct xfs_bmbt_key +{ + xfs_dfiloff_t br_startoff; /* starting file offset */ +} xfs_bmbt_key_t, xfs_bmdr_key_t; + +typedef xfs_dfsbno_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t; /* btree pointer type */ + /* btree block header type */ +typedef struct xfs_btree_lblock xfs_bmbt_block_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_BMBT_BLOCK) +xfs_bmbt_block_t *xfs_buf_to_bmbt_block(struct xfs_buf *bp); +#define XFS_BUF_TO_BMBT_BLOCK(bp) xfs_buf_to_bmbt_block(bp) +#else +#define XFS_BUF_TO_BMBT_BLOCK(bp) ((xfs_bmbt_block_t *)(XFS_BUF_PTR(bp))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_RBLOCK_DSIZE) +int xfs_bmap_rblock_dsize(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_RBLOCK_DSIZE(lev,cur) xfs_bmap_rblock_dsize(lev,cur) +#else +#define XFS_BMAP_RBLOCK_DSIZE(lev,cur) ((cur)->bc_private.b.forksize) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_RBLOCK_ISIZE) +int xfs_bmap_rblock_isize(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_RBLOCK_ISIZE(lev,cur) xfs_bmap_rblock_isize(lev,cur) +#else +#define XFS_BMAP_RBLOCK_ISIZE(lev,cur) \ + ((int)XFS_IFORK_PTR((cur)->bc_private.b.ip, \ + (cur)->bc_private.b.whichfork)->if_broot_bytes) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_IBLOCK_SIZE) +int xfs_bmap_iblock_size(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_IBLOCK_SIZE(lev,cur) xfs_bmap_iblock_size(lev,cur) +#else +#define XFS_BMAP_IBLOCK_SIZE(lev,cur) (1 << (cur)->bc_blocklog) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_DSIZE) +int xfs_bmap_block_dsize(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_DSIZE(lev,cur) xfs_bmap_block_dsize(lev,cur) +#else +#define XFS_BMAP_BLOCK_DSIZE(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BMAP_RBLOCK_DSIZE(lev,cur) : \ + XFS_BMAP_IBLOCK_SIZE(lev,cur)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_ISIZE) +int xfs_bmap_block_isize(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_ISIZE(lev,cur) xfs_bmap_block_isize(lev,cur) +#else +#define XFS_BMAP_BLOCK_ISIZE(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BMAP_RBLOCK_ISIZE(lev,cur) : \ + XFS_BMAP_IBLOCK_SIZE(lev,cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_DMAXRECS) +int xfs_bmap_block_dmaxrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_DMAXRECS(lev,cur) xfs_bmap_block_dmaxrecs(lev,cur) +#else +#define XFS_BMAP_BLOCK_DMAXRECS(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BTREE_BLOCK_MAXRECS(XFS_BMAP_RBLOCK_DSIZE(lev,cur), \ + xfs_bmdr, (lev) == 0) : \ + ((cur)->bc_mp->m_bmap_dmxr[(lev) != 0])) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_IMAXRECS) +int xfs_bmap_block_imaxrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_IMAXRECS(lev,cur) xfs_bmap_block_imaxrecs(lev,cur) +#else +#define XFS_BMAP_BLOCK_IMAXRECS(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BTREE_BLOCK_MAXRECS(XFS_BMAP_RBLOCK_ISIZE(lev,cur), \ + xfs_bmbt, (lev) == 0) : \ + ((cur)->bc_mp->m_bmap_dmxr[(lev) != 0])) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_DMINRECS) +int xfs_bmap_block_dminrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_DMINRECS(lev,cur) xfs_bmap_block_dminrecs(lev,cur) +#else +#define XFS_BMAP_BLOCK_DMINRECS(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BTREE_BLOCK_MINRECS(XFS_BMAP_RBLOCK_DSIZE(lev,cur), \ + xfs_bmdr, (lev) == 0) : \ + ((cur)->bc_mp->m_bmap_dmnr[(lev) != 0])) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_IMINRECS) +int xfs_bmap_block_iminrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_IMINRECS(lev,cur) xfs_bmap_block_iminrecs(lev,cur) +#else +#define XFS_BMAP_BLOCK_IMINRECS(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BTREE_BLOCK_MINRECS(XFS_BMAP_RBLOCK_ISIZE(lev,cur), \ + xfs_bmbt, (lev) == 0) : \ + ((cur)->bc_mp->m_bmap_dmnr[(lev) != 0])) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_REC_DADDR) +xfs_bmbt_rec_t * +xfs_bmap_rec_daddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_REC_DADDR(bb,i,cur) xfs_bmap_rec_daddr(bb,i,cur) +#else +#define XFS_BMAP_REC_DADDR(bb,i,cur) \ + XFS_BTREE_REC_ADDR(XFS_BMAP_BLOCK_DSIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_REC_IADDR) +xfs_bmbt_rec_t * +xfs_bmap_rec_iaddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_REC_IADDR(bb,i,cur) xfs_bmap_rec_iaddr(bb,i,cur) +#else +#define XFS_BMAP_REC_IADDR(bb,i,cur) \ + XFS_BTREE_REC_ADDR(XFS_BMAP_BLOCK_ISIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_KEY_DADDR) +xfs_bmbt_key_t * +xfs_bmap_key_daddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_KEY_DADDR(bb,i,cur) xfs_bmap_key_daddr(bb,i,cur) +#else +#define XFS_BMAP_KEY_DADDR(bb,i,cur) \ + XFS_BTREE_KEY_ADDR(XFS_BMAP_BLOCK_DSIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_KEY_IADDR) +xfs_bmbt_key_t * +xfs_bmap_key_iaddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_KEY_IADDR(bb,i,cur) xfs_bmap_key_iaddr(bb,i,cur) +#else +#define XFS_BMAP_KEY_IADDR(bb,i,cur) \ + XFS_BTREE_KEY_ADDR(XFS_BMAP_BLOCK_ISIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_PTR_DADDR) +xfs_bmbt_ptr_t * +xfs_bmap_ptr_daddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_PTR_DADDR(bb,i,cur) xfs_bmap_ptr_daddr(bb,i,cur) +#else +#define XFS_BMAP_PTR_DADDR(bb,i,cur) \ + XFS_BTREE_PTR_ADDR(XFS_BMAP_BLOCK_DSIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_PTR_IADDR) +xfs_bmbt_ptr_t * +xfs_bmap_ptr_iaddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_PTR_IADDR(bb,i,cur) xfs_bmap_ptr_iaddr(bb,i,cur) +#else +#define XFS_BMAP_PTR_IADDR(bb,i,cur) \ + XFS_BTREE_PTR_ADDR(XFS_BMAP_BLOCK_ISIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif + +/* + * These are to be used when we know the size of the block and + * we don't have a cursor. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_REC_ADDR) +xfs_bmbt_rec_t *xfs_bmap_broot_rec_addr(xfs_bmbt_block_t *bb, int i, int sz); +#define XFS_BMAP_BROOT_REC_ADDR(bb,i,sz) xfs_bmap_broot_rec_addr(bb,i,sz) +#else +#define XFS_BMAP_BROOT_REC_ADDR(bb,i,sz) \ + XFS_BTREE_REC_ADDR(sz,xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_KEY_ADDR) +xfs_bmbt_key_t *xfs_bmap_broot_key_addr(xfs_bmbt_block_t *bb, int i, int sz); +#define XFS_BMAP_BROOT_KEY_ADDR(bb,i,sz) xfs_bmap_broot_key_addr(bb,i,sz) +#else +#define XFS_BMAP_BROOT_KEY_ADDR(bb,i,sz) \ + XFS_BTREE_KEY_ADDR(sz,xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_PTR_ADDR) +xfs_bmbt_ptr_t *xfs_bmap_broot_ptr_addr(xfs_bmbt_block_t *bb, int i, int sz); +#define XFS_BMAP_BROOT_PTR_ADDR(bb,i,sz) xfs_bmap_broot_ptr_addr(bb,i,sz) +#else +#define XFS_BMAP_BROOT_PTR_ADDR(bb,i,sz) \ + XFS_BTREE_PTR_ADDR(sz,xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_NUMRECS) +int xfs_bmap_broot_numrecs(xfs_bmdr_block_t *bb); +#define XFS_BMAP_BROOT_NUMRECS(bb) xfs_bmap_broot_numrecs(bb) +#else +#define XFS_BMAP_BROOT_NUMRECS(bb) (INT_GET((bb)->bb_numrecs, ARCH_CONVERT)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_MAXRECS) +int xfs_bmap_broot_maxrecs(int sz); +#define XFS_BMAP_BROOT_MAXRECS(sz) xfs_bmap_broot_maxrecs(sz) +#else +#define XFS_BMAP_BROOT_MAXRECS(sz) XFS_BTREE_BLOCK_MAXRECS(sz,xfs_bmbt,0) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_SPACE_CALC) +int xfs_bmap_broot_space_calc(int nrecs); +#define XFS_BMAP_BROOT_SPACE_CALC(nrecs) xfs_bmap_broot_space_calc(nrecs) +#else +#define XFS_BMAP_BROOT_SPACE_CALC(nrecs) \ + ((int)(sizeof(xfs_bmbt_block_t) + \ + ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_SPACE) +int xfs_bmap_broot_space(xfs_bmdr_block_t *bb); +#define XFS_BMAP_BROOT_SPACE(bb) xfs_bmap_broot_space(bb) +#else +#define XFS_BMAP_BROOT_SPACE(bb) \ + XFS_BMAP_BROOT_SPACE_CALC(INT_GET((bb)->bb_numrecs, ARCH_CONVERT)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMDR_SPACE_CALC) +int xfs_bmdr_space_calc(int nrecs); +#define XFS_BMDR_SPACE_CALC(nrecs) xfs_bmdr_space_calc(nrecs) +#else +#define XFS_BMDR_SPACE_CALC(nrecs) \ + ((int)(sizeof(xfs_bmdr_block_t) + \ + ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))) +#endif + +/* + * Maximum number of bmap btree levels. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BM_MAXLEVELS) +int xfs_bm_maxlevels(struct xfs_mount *mp, int w); +#define XFS_BM_MAXLEVELS(mp,w) xfs_bm_maxlevels(mp,w) +#else +#define XFS_BM_MAXLEVELS(mp,w) ((mp)->m_bm_maxlevels[w]) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_SANITY_CHECK) +int xfs_bmap_sanity_check(struct xfs_mount *mp, xfs_bmbt_block_t *bb, + int level); +#define XFS_BMAP_SANITY_CHECK(mp,bb,level) \ + xfs_bmap_sanity_check(mp,bb,level) +#else +#define XFS_BMAP_SANITY_CHECK(mp,bb,level) \ + (INT_GET((bb)->bb_magic, ARCH_CONVERT) == XFS_BMAP_MAGIC && \ + INT_GET((bb)->bb_level, ARCH_CONVERT) == level && \ + INT_GET((bb)->bb_numrecs, ARCH_CONVERT) > 0 && \ + INT_GET((bb)->bb_numrecs, ARCH_CONVERT) <= (mp)->m_bmap_dmxr[(level) != 0]) +#endif + +/* + * Trace buffer entry types. + */ +#define XFS_BMBT_KTRACE_ARGBI 1 +#define XFS_BMBT_KTRACE_ARGBII 2 +#define XFS_BMBT_KTRACE_ARGFFFI 3 +#define XFS_BMBT_KTRACE_ARGI 4 +#define XFS_BMBT_KTRACE_ARGIFK 5 +#define XFS_BMBT_KTRACE_ARGIFR 6 +#define XFS_BMBT_KTRACE_ARGIK 7 +#define XFS_BMBT_KTRACE_CUR 8 + +#define XFS_BMBT_TRACE_SIZE 4096 /* size of global trace buffer */ +#define XFS_BMBT_KTRACE_SIZE 32 /* size of per-inode trace buffer */ + +#if defined(XFS_ALL_TRACE) +#define XFS_BMBT_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_BMBT_TRACE +#endif + + +/* + * Prototypes for xfs_bmap.c to call. + */ + +void +xfs_bmdr_to_bmbt( + xfs_bmdr_block_t *, + int, + xfs_bmbt_block_t *, + int); + +int +xfs_bmbt_decrement( + struct xfs_btree_cur *, + int, + int *); + +int +xfs_bmbt_delete( + struct xfs_btree_cur *, + int, + int *); + +void +xfs_bmbt_get_all( + xfs_bmbt_rec_t *r, + xfs_bmbt_irec_t *s); + +xfs_bmbt_block_t * +xfs_bmbt_get_block( + struct xfs_btree_cur *cur, + int level, + struct xfs_buf **bpp); + +xfs_filblks_t +xfs_bmbt_get_blockcount( + xfs_bmbt_rec_t *r); + +xfs_fsblock_t +xfs_bmbt_get_startblock( + xfs_bmbt_rec_t *r); + +xfs_fileoff_t +xfs_bmbt_get_startoff( + xfs_bmbt_rec_t *r); + +xfs_exntst_t +xfs_bmbt_get_state( + xfs_bmbt_rec_t *r); + +int +xfs_bmbt_increment( + struct xfs_btree_cur *, + int, + int *); + +int +xfs_bmbt_insert( + struct xfs_btree_cur *, + int *); + +int +xfs_bmbt_insert_many( + struct xfs_btree_cur *, + int, + xfs_bmbt_rec_t *, + int *); + +void +xfs_bmbt_log_block( + struct xfs_btree_cur *, + struct xfs_buf *, + int); + +void +xfs_bmbt_log_recs( + struct xfs_btree_cur *, + struct xfs_buf *, + int, + int); + +int +xfs_bmbt_lookup_eq( + struct xfs_btree_cur *, + xfs_fileoff_t, + xfs_fsblock_t, + xfs_filblks_t, + int *); + +int +xfs_bmbt_lookup_ge( + struct xfs_btree_cur *, + xfs_fileoff_t, + xfs_fsblock_t, + xfs_filblks_t, + int *); + +int +xfs_bmbt_lookup_le( + struct xfs_btree_cur *, + xfs_fileoff_t, + xfs_fsblock_t, + xfs_filblks_t, + int *); + +/* + * Give the bmap btree a new root block. Copy the old broot contents + * down into a real block and make the broot point to it. + */ +int /* error */ +xfs_bmbt_newroot( + struct xfs_btree_cur *cur, /* btree cursor */ + int *logflags, /* logging flags for inode */ + int *stat); /* return status - 0 fail */ + +void +xfs_bmbt_set_all( + xfs_bmbt_rec_t *r, + xfs_bmbt_irec_t *s); + +void +xfs_bmbt_set_allf( + xfs_bmbt_rec_t *r, + xfs_fileoff_t o, + xfs_fsblock_t b, + xfs_filblks_t c, + xfs_exntst_t v); + +void +xfs_bmbt_set_blockcount( + xfs_bmbt_rec_t *r, + xfs_filblks_t v); + +void +xfs_bmbt_set_startblock( + xfs_bmbt_rec_t *r, + xfs_fsblock_t v); + +void +xfs_bmbt_set_startoff( + xfs_bmbt_rec_t *r, + xfs_fileoff_t v); + +void +xfs_bmbt_set_state( + xfs_bmbt_rec_t *r, + xfs_exntst_t v); + +void +xfs_bmbt_to_bmdr( + xfs_bmbt_block_t *, + int, + xfs_bmdr_block_t *, + int); + +int +xfs_bmbt_update( + struct xfs_btree_cur *, + xfs_fileoff_t, + xfs_fsblock_t, + xfs_filblks_t, + xfs_exntst_t); + +#ifdef XFSDEBUG +/* + * Get the data from the pointed-to record. + */ +int +xfs_bmbt_get_rec( + struct xfs_btree_cur *, + xfs_fileoff_t *, + xfs_fsblock_t *, + xfs_filblks_t *, + xfs_exntst_t *, + int *); +#endif + + +/* + * Search an extent list for the extent which includes block + * bno. + */ +xfs_bmbt_rec_t * +xfs_bmap_do_search_extents( + xfs_bmbt_rec_t *, + xfs_extnum_t, + xfs_extnum_t, + xfs_fileoff_t, + int *, + xfs_extnum_t *, + xfs_bmbt_irec_t *, + xfs_bmbt_irec_t *); + + +#endif /* __XFS_BMAP_BTREE_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_btree.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_btree.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_btree.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_btree.h Tue Apr 3 23:11:07 2001 @@ -0,0 +1,587 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BTREE_H__ +#define __XFS_BTREE_H__ + +struct xfs_buf; +struct xfs_bmap_free; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * This nonsense is to make -wlint happy. + */ +#define XFS_LOOKUP_EQ ((xfs_lookup_t)XFS_LOOKUP_EQi) +#define XFS_LOOKUP_LE ((xfs_lookup_t)XFS_LOOKUP_LEi) +#define XFS_LOOKUP_GE ((xfs_lookup_t)XFS_LOOKUP_GEi) + +#define XFS_BTNUM_BNO ((xfs_btnum_t)XFS_BTNUM_BNOi) +#define XFS_BTNUM_CNT ((xfs_btnum_t)XFS_BTNUM_CNTi) +#define XFS_BTNUM_BMAP ((xfs_btnum_t)XFS_BTNUM_BMAPi) +#define XFS_BTNUM_INO ((xfs_btnum_t)XFS_BTNUM_INOi) + +/* + * Short form header: space allocation btrees. + */ +typedef struct xfs_btree_sblock +{ + __uint32_t bb_magic; /* magic number for block type */ + __uint16_t bb_level; /* 0 is a leaf */ + __uint16_t bb_numrecs; /* current # of data records */ + xfs_agblock_t bb_leftsib; /* left sibling block or NULLAGBLOCK */ + xfs_agblock_t bb_rightsib; /* right sibling block or NULLAGBLOCK */ +} xfs_btree_sblock_t; + +/* + * Long form header: bmap btrees. + */ +typedef struct xfs_btree_lblock +{ + __uint32_t bb_magic; /* magic number for block type */ + __uint16_t bb_level; /* 0 is a leaf */ + __uint16_t bb_numrecs; /* current # of data records */ + xfs_dfsbno_t bb_leftsib; /* left sibling block or NULLDFSBNO */ + xfs_dfsbno_t bb_rightsib; /* right sibling block or NULLDFSBNO */ +} xfs_btree_lblock_t; + +/* + * Combined header and structure, used by common code. + */ +typedef struct xfs_btree_hdr +{ + __uint32_t bb_magic; /* magic number for block type */ + __uint16_t bb_level; /* 0 is a leaf */ + __uint16_t bb_numrecs; /* current # of data records */ +} xfs_btree_hdr_t; + +typedef struct xfs_btree_block +{ + xfs_btree_hdr_t bb_h; /* header */ + union { + struct { + xfs_agblock_t bb_leftsib; + xfs_agblock_t bb_rightsib; + } s; /* short form pointers */ + struct { + xfs_dfsbno_t bb_leftsib; + xfs_dfsbno_t bb_rightsib; + } l; /* long form pointers */ + } bb_u; /* rest */ +} xfs_btree_block_t; + +/* + * For logging record fields. + */ +#define XFS_BB_MAGIC 0x01 +#define XFS_BB_LEVEL 0x02 +#define XFS_BB_NUMRECS 0x04 +#define XFS_BB_LEFTSIB 0x08 +#define XFS_BB_RIGHTSIB 0x10 +#define XFS_BB_NUM_BITS 5 +#define XFS_BB_ALL_BITS ((1 << XFS_BB_NUM_BITS) - 1) + +/* + * Boolean to select which form of xfs_btree_block_t.bb_u to use. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BTREE_LONG_PTRS) +int xfs_btree_long_ptrs(xfs_btnum_t btnum); +#define XFS_BTREE_LONG_PTRS(btnum) ((btnum) == XFS_BTNUM_BMAP) +#else +#define XFS_BTREE_LONG_PTRS(btnum) ((btnum) == XFS_BTNUM_BMAP) +#endif + +/* + * Magic numbers for btree blocks. + */ +extern const __uint32_t xfs_magics[]; + +/* + * Maximum and minimum records in a btree block. + * Given block size, type prefix, and leaf flag (0 or 1). + * The divisor below is equivalent to lf ? (e1) : (e2) but that produces + * compiler warnings. + */ +#define XFS_BTREE_BLOCK_MAXRECS(bsz,t,lf) \ + ((int)(((bsz) - (uint)sizeof(t ## _block_t)) / \ + (((lf) * (uint)sizeof(t ## _rec_t)) + \ + ((1 - (lf)) * \ + ((uint)sizeof(t ## _key_t) + (uint)sizeof(t ## _ptr_t)))))) +#define XFS_BTREE_BLOCK_MINRECS(bsz,t,lf) \ + (XFS_BTREE_BLOCK_MAXRECS(bsz,t,lf) / 2) + +/* + * Record, key, and pointer address calculation macros. + * Given block size, type prefix, block pointer, and index of requested entry + * (first entry numbered 1). + */ +#define XFS_BTREE_REC_ADDR(bsz,t,bb,i,mxr) \ + ((t ## _rec_t *)((char *)(bb) + sizeof(t ## _block_t) + \ + ((i) - 1) * sizeof(t ## _rec_t))) +#define XFS_BTREE_KEY_ADDR(bsz,t,bb,i,mxr) \ + ((t ## _key_t *)((char *)(bb) + sizeof(t ## _block_t) + \ + ((i) - 1) * sizeof(t ## _key_t))) +#define XFS_BTREE_PTR_ADDR(bsz,t,bb,i,mxr) \ + ((t ## _ptr_t *)((char *)(bb) + sizeof(t ## _block_t) + \ + (mxr) * sizeof(t ## _key_t) + ((i) - 1) * sizeof(t ## _ptr_t))) + +#define XFS_BTREE_MAXLEVELS 8 /* max of all btrees */ + +/* + * Btree cursor structure. + * This collects all information needed by the btree code in one place. + */ +typedef struct xfs_btree_cur +{ + struct xfs_trans *bc_tp; /* transaction we're in, if any */ + struct xfs_mount *bc_mp; /* file system mount struct */ + union { + xfs_alloc_rec_t a; + xfs_bmbt_irec_t b; + xfs_inobt_rec_t i; + } bc_rec; /* current insert/search record value */ + struct xfs_buf *bc_bufs[XFS_BTREE_MAXLEVELS]; /* buf ptr per level */ + int bc_ptrs[XFS_BTREE_MAXLEVELS]; /* key/record # */ + __uint8_t bc_ra[XFS_BTREE_MAXLEVELS]; /* readahead bits */ +#define XFS_BTCUR_LEFTRA 1 /* left sibling has been read-ahead */ +#define XFS_BTCUR_RIGHTRA 2 /* right sibling has been read-ahead */ + __uint8_t bc_nlevels; /* number of levels in the tree */ + __uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */ + xfs_btnum_t bc_btnum; /* identifies which btree type */ + union { + struct { /* needed for BNO, CNT */ + struct xfs_buf *agbp; /* agf buffer pointer */ + xfs_agnumber_t agno; /* ag number */ + } a; + struct { /* needed for BMAP */ + struct xfs_inode *ip; /* pointer to our inode */ + struct xfs_bmap_free *flist; /* list to free after */ + xfs_fsblock_t firstblock; /* 1st blk allocated */ + int allocated; /* count of alloced */ + short forksize; /* fork's inode space */ + char whichfork; /* data or attr fork */ + char flags; /* flags */ +#define XFS_BTCUR_BPRV_WASDEL 1 /* was delayed */ + } b; + struct { /* needed for INO */ + struct xfs_buf *agbp; /* agi buffer pointer */ + xfs_agnumber_t agno; /* ag number */ + } i; + } bc_private; /* per-btree type data */ +} xfs_btree_cur_t; + +#define XFS_BTREE_NOERROR 0 +#define XFS_BTREE_ERROR 1 + +/* + * Convert from buffer to btree block header. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_BLOCK) +xfs_btree_block_t *xfs_buf_to_block(struct xfs_buf *bp); +#define XFS_BUF_TO_BLOCK(bp) xfs_buf_to_block(bp) +#else +#define XFS_BUF_TO_BLOCK(bp) ((xfs_btree_block_t *)(XFS_BUF_PTR(bp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_LBLOCK) +xfs_btree_lblock_t *xfs_buf_to_lblock(struct xfs_buf *bp); +#define XFS_BUF_TO_LBLOCK(bp) xfs_buf_to_lblock(bp) +#else +#define XFS_BUF_TO_LBLOCK(bp) ((xfs_btree_lblock_t *)(XFS_BUF_PTR(bp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_SBLOCK) +xfs_btree_sblock_t *xfs_buf_to_sblock(struct xfs_buf *bp); +#define XFS_BUF_TO_SBLOCK(bp) xfs_buf_to_sblock(bp) +#else +#define XFS_BUF_TO_SBLOCK(bp) ((xfs_btree_sblock_t *)(XFS_BUF_PTR(bp))) +#endif + +#ifdef __KERNEL__ + +#ifdef DEBUG +/* + * Debug routine: check that block header is ok. + */ +void +xfs_btree_check_block( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_block_t *block, /* generic btree block pointer */ + int level, /* level of the btree block */ + struct xfs_buf *bp); /* buffer containing block, if any */ + +/* + * Debug routine: check that keys are in the right order. + */ +void +xfs_btree_check_key( + xfs_btnum_t btnum, /* btree identifier */ + void *ak1, /* pointer to left (lower) key */ + void *ak2); /* pointer to right (higher) key */ + +/* + * Debug routine: check that records are in the right order. + */ +void +xfs_btree_check_rec( + xfs_btnum_t btnum, /* btree identifier */ + void *ar1, /* pointer to left (lower) record */ + void *ar2); /* pointer to right (higher) record */ +#else +#define xfs_btree_check_block(a,b,c,d) +#define xfs_btree_check_key(a,b,c) +#define xfs_btree_check_rec(a,b,c) +#endif /* DEBUG */ + +/* + * Checking routine: check that long form block header is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_lblock( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_lblock_t *block, /* btree long form block pointer */ + int level, /* level of the btree block */ + struct xfs_buf *bp); /* buffer containing block, if any */ + +/* + * Checking routine: check that (long) pointer is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_lptr( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_dfsbno_t ptr, /* btree block disk address */ + int level); /* btree block level */ + +/* + * Checking routine: check that short form block header is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_sblock( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_sblock_t *block, /* btree short form block pointer */ + int level, /* level of the btree block */ + struct xfs_buf *bp); /* buffer containing block */ + +/* + * Checking routine: check that (short) pointer is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_sptr( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t ptr, /* btree block disk address */ + int level); /* btree block level */ + +/* + * Delete the btree cursor. + */ +void +xfs_btree_del_cursor( + xfs_btree_cur_t *cur, /* btree cursor */ + int error); /* del because of error */ + +/* + * Duplicate the btree cursor. + * Allocate a new one, copy the record, re-get the buffers. + */ +int /* error */ +xfs_btree_dup_cursor( + xfs_btree_cur_t *cur, /* input cursor */ + xfs_btree_cur_t **ncur);/* output cursor */ + +/* + * Change the cursor to point to the first record in the current block + * at the given level. Other levels are unaffected. + */ +int /* success=1, failure=0 */ +xfs_btree_firstrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level); /* level to change */ + +/* + * Retrieve the block pointer from the cursor at the given level. + * This may be a bmap btree root or from a buffer. + */ +xfs_btree_block_t * /* generic btree block pointer */ +xfs_btree_get_block( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree */ + struct xfs_buf **bpp); /* buffer containing the block */ + +/* + * Get a buffer for the block, return it with no data read. + * Long-form addressing. + */ +struct xfs_buf * /* buffer for fsbno */ +xfs_btree_get_bufl( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_fsblock_t fsbno, /* file system block number */ + uint lock); /* lock flags for get_buf */ + +/* + * Get a buffer for the block, return it with no data read. + * Short-form addressing. + */ +struct xfs_buf * /* buffer for agno/agbno */ +xfs_btree_get_bufs( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + uint lock); /* lock flags for get_buf */ + +/* + * Allocate a new btree cursor. + * The cursor is either for allocation (A) or bmap (B). + */ +xfs_btree_cur_t * /* new btree cursor */ +xfs_btree_init_cursor( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_buf *agbp, /* (A only) buffer for agf structure */ + xfs_agnumber_t agno, /* (A only) allocation group number */ + xfs_btnum_t btnum, /* btree identifier */ + struct xfs_inode *ip, /* (B only) inode owning the btree */ + int whichfork); /* (B only) data/attr fork */ + +/* + * Check for the cursor referring to the last block at the given level. + */ +int /* 1=is last block, 0=not last block */ +xfs_btree_islastblock( + xfs_btree_cur_t *cur, /* btree cursor */ + int level); /* level to check */ + +/* + * Change the cursor to point to the last record in the current block + * at the given level. Other levels are unaffected. + */ +int /* success=1, failure=0 */ +xfs_btree_lastrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level); /* level to change */ + +/* + * Compute first and last byte offsets for the fields given. + * Interprets the offsets table, which contains struct field offsets. + */ +void +xfs_btree_offsets( + __int64_t fields, /* bitmask of fields */ + const short *offsets,/* table of field offsets */ + int nbits, /* number of bits to inspect */ + int *first, /* output: first byte offset */ + int *last); /* output: last byte offset */ + +/* + * Get a buffer for the block, return it read in. + * Long-form addressing. + */ +int /* error */ +xfs_btree_read_bufl( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_fsblock_t fsbno, /* file system block number */ + uint lock, /* lock flags for read_buf */ + struct xfs_buf **bpp, /* buffer for fsbno */ + int refval);/* ref count value for buffer */ + +/* + * Get a buffer for the block, return it read in. + * Short-form addressing. + */ +int /* error */ +xfs_btree_read_bufs( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + uint lock, /* lock flags for read_buf */ + struct xfs_buf **bpp, /* buffer for agno/agbno */ + int refval);/* ref count value for buffer */ + +/* + * Read-ahead the block, don't wait for it, don't return a buffer. + * Long-form addressing. + */ +void /* error */ +xfs_btree_reada_bufl( + struct xfs_mount *mp, /* file system mount point */ + xfs_fsblock_t fsbno, /* file system block number */ + xfs_extlen_t count); /* count of filesystem blocks */ + +/* + * Read-ahead the block, don't wait for it, don't return a buffer. + * Short-form addressing. + */ +void /* error */ +xfs_btree_reada_bufs( + struct xfs_mount *mp, /* file system mount point */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + xfs_extlen_t count); /* count of filesystem blocks */ + +/* + * Read-ahead btree blocks, at the given level. + * Bits in lr are set from XFS_BTCUR_{LEFT,RIGHT}RA. + */ +int /* readahead block count */ +xfs_btree_readahead_core( + xfs_btree_cur_t *cur, /* btree cursor */ + int lev, /* level in btree */ + int lr); /* left/right bits */ + +static inline int /* readahead block count */ +xfs_btree_readahead( + xfs_btree_cur_t *cur, /* btree cursor */ + int lev, /* level in btree */ + int lr) /* left/right bits */ +{ + if ((cur->bc_ra[lev] | lr) == cur->bc_ra[lev]) + return 0; + + return xfs_btree_readahead_core(cur, lev, lr); +} + + +/* + * Set the buffer for level "lev" in the cursor to bp, releasing + * any previous buffer. + */ +void +xfs_btree_setbuf( + xfs_btree_cur_t *cur, /* btree cursor */ + int lev, /* level in btree */ + struct xfs_buf *bp); /* new buffer to set */ + +#endif /* __KERNEL__ */ + + +/* + * Min and max functions for extlen, agblock, fileoff, and filblks types. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_EXTLEN_MIN) +xfs_extlen_t xfs_extlen_min(xfs_extlen_t a, xfs_extlen_t b); +#define XFS_EXTLEN_MIN(a,b) xfs_extlen_min(a,b) +#else +#define XFS_EXTLEN_MIN(a,b) \ + ((xfs_extlen_t)(a) < (xfs_extlen_t)(b) ? \ + (xfs_extlen_t)(a) : (xfs_extlen_t)(b)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_EXTLEN_MAX) +xfs_extlen_t xfs_extlen_max(xfs_extlen_t a, xfs_extlen_t b); +#define XFS_EXTLEN_MAX(a,b) xfs_extlen_max(a,b) +#else +#define XFS_EXTLEN_MAX(a,b) \ + ((xfs_extlen_t)(a) > (xfs_extlen_t)(b) ? \ + (xfs_extlen_t)(a) : (xfs_extlen_t)(b)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGBLOCK_MIN) +xfs_agblock_t xfs_agblock_min(xfs_agblock_t a, xfs_agblock_t b); +#define XFS_AGBLOCK_MIN(a,b) xfs_agblock_min(a,b) +#else +#define XFS_AGBLOCK_MIN(a,b) \ + ((xfs_agblock_t)(a) < (xfs_agblock_t)(b) ? \ + (xfs_agblock_t)(a) : (xfs_agblock_t)(b)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGBLOCK_MAX) +xfs_agblock_t xfs_agblock_max(xfs_agblock_t a, xfs_agblock_t b); +#define XFS_AGBLOCK_MAX(a,b) xfs_agblock_max(a,b) +#else +#define XFS_AGBLOCK_MAX(a,b) \ + ((xfs_agblock_t)(a) > (xfs_agblock_t)(b) ? \ + (xfs_agblock_t)(a) : (xfs_agblock_t)(b)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FILEOFF_MIN) +xfs_fileoff_t xfs_fileoff_min(xfs_fileoff_t a, xfs_fileoff_t b); +#define XFS_FILEOFF_MIN(a,b) xfs_fileoff_min(a,b) +#else +#define XFS_FILEOFF_MIN(a,b) \ + ((xfs_fileoff_t)(a) < (xfs_fileoff_t)(b) ? \ + (xfs_fileoff_t)(a) : (xfs_fileoff_t)(b)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FILEOFF_MAX) +xfs_fileoff_t xfs_fileoff_max(xfs_fileoff_t a, xfs_fileoff_t b); +#define XFS_FILEOFF_MAX(a,b) xfs_fileoff_max(a,b) +#else +#define XFS_FILEOFF_MAX(a,b) \ + ((xfs_fileoff_t)(a) > (xfs_fileoff_t)(b) ? \ + (xfs_fileoff_t)(a) : (xfs_fileoff_t)(b)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FILBLKS_MIN) +xfs_filblks_t xfs_filblks_min(xfs_filblks_t a, xfs_filblks_t b); +#define XFS_FILBLKS_MIN(a,b) xfs_filblks_min(a,b) +#else +#define XFS_FILBLKS_MIN(a,b) \ + ((xfs_filblks_t)(a) < (xfs_filblks_t)(b) ? \ + (xfs_filblks_t)(a) : (xfs_filblks_t)(b)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FILBLKS_MAX) +xfs_filblks_t xfs_filblks_max(xfs_filblks_t a, xfs_filblks_t b); +#define XFS_FILBLKS_MAX(a,b) xfs_filblks_max(a,b) +#else +#define XFS_FILBLKS_MAX(a,b) \ + ((xfs_filblks_t)(a) > (xfs_filblks_t)(b) ? \ + (xfs_filblks_t)(a) : (xfs_filblks_t)(b)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_SANITY_CHECK) +int xfs_fsb_sanity_check(struct xfs_mount *mp, xfs_fsblock_t fsb); +#define XFS_FSB_SANITY_CHECK(mp,fsb) xfs_fsb_sanity_check(mp,fsb) +#else +#define XFS_FSB_SANITY_CHECK(mp,fsb) \ + (XFS_FSB_TO_AGNO(mp, fsb) < mp->m_sb.sb_agcount && \ + XFS_FSB_TO_AGBNO(mp, fsb) < mp->m_sb.sb_agblocks) +#endif + +/* + * Macros to set EFSCORRUPTED & return/branch. + */ +#define XFS_WANT_CORRUPTED_GOTO(x,l) \ + { \ + int fs_is_ok = (x); \ + ASSERT(fs_is_ok); \ + if (!fs_is_ok) { \ + error = XFS_ERROR(EFSCORRUPTED); \ + goto l; \ + } \ + } + +#define XFS_WANT_CORRUPTED_RETURN(x) \ + { \ + int fs_is_ok = (x); \ + ASSERT(fs_is_ok); \ + if (!fs_is_ok) \ + return XFS_ERROR(EFSCORRUPTED); \ + } + +#endif /* __XFS_BTREE_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_buf_item.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_buf_item.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_buf_item.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_buf_item.h Mon Apr 2 21:52:38 2001 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BUF_ITEM_H__ +#define __XFS_BUF_ITEM_H__ + +/* + * This is the structure used to lay out a buf log item in the + * log. The data map describes which 128 byte chunks of the buffer + * have been logged. This structure works only on buffers that + * reside up to the first TB in the filesystem. These buffers are + * generated only by pre-6.2 systems and are known as XFS_LI_6_1_BUF. + */ +typedef struct xfs_buf_log_format_v1 { + unsigned short blf_type; /* buf log item type indicator */ + unsigned short blf_size; /* size of this item */ + __int32_t blf_blkno; /* starting blkno of this buf */ + ushort blf_flags; /* misc state */ + ushort blf_len; /* number of blocks in this buf */ + unsigned int blf_map_size; /* size of data bitmap in words */ + unsigned int blf_data_map[1];/* variable size bitmap of */ + /* regions of buffer in this item */ +} xfs_buf_log_format_v1_t; + +/* + * This is a form of the above structure with a 64 bit blkno field. + * For 6.2 and beyond, this is XFS_LI_BUF. We use this to log everything. + */ +typedef struct xfs_buf_log_format_t { + unsigned short blf_type; /* buf log item type indicator */ + unsigned short blf_size; /* size of this item */ + ushort blf_flags; /* misc state */ + ushort blf_len; /* number of blocks in this buf */ + __int64_t blf_blkno; /* starting blkno of this buf */ + unsigned int blf_map_size; /* size of data bitmap in words */ + unsigned int blf_data_map[1];/* variable size bitmap of */ + /* regions of buffer in this item */ +} xfs_buf_log_format_t; + +/* + * This flag indicates that the buffer contains on disk inodes + * and requires special recovery handling. + */ +#define XFS_BLI_INODE_BUF 0x1 +/* + * This flag indicates that the buffer should not be replayed + * during recovery because its blocks are being freed. + */ +#define XFS_BLI_CANCEL 0x2 +/* + * This flag indicates that the buffer contains on disk + * user or group dquots and may require special recovery handling. + */ +#define XFS_BLI_UDQUOT_BUF 0x4 +/* #define XFS_BLI_PDQUOT_BUF 0x8 */ +#define XFS_BLI_GDQUOT_BUF 0x10 + +#define XFS_BLI_CHUNK 128 +#define XFS_BLI_SHIFT 7 +#define BIT_TO_WORD_SHIFT 5 +#define NBWORD (NBBY * sizeof(unsigned int)) + +/* + * buf log item flags + */ +#define XFS_BLI_HOLD 0x01 +#define XFS_BLI_DIRTY 0x02 +#define XFS_BLI_STALE 0x04 +#define XFS_BLI_LOGGED 0x08 +#define XFS_BLI_INODE_ALLOC_BUF 0x10 + + +#ifdef __KERNEL__ + +struct xfs_buf; +struct ktrace; +struct xfs_mount; + +/* + * This is the in core log item structure used to track information + * needed to log buffers. It tracks how many times the lock has been + * locked, and which 128 byte chunks of the buffer are dirty. + */ +typedef struct xfs_buf_log_item { + xfs_log_item_t bli_item; /* common item structure */ + struct xfs_buf *bli_buf; /* real buffer pointer */ + unsigned int bli_flags; /* misc flags */ + unsigned int bli_recur; /* lock recursion count */ + atomic_t bli_refcount; /* cnt of tp refs */ +#ifdef DEBUG + struct ktrace *bli_trace; /* event trace buf */ +#endif +#ifdef XFS_TRANS_DEBUG + char *bli_orig; /* original buffer copy */ + char *bli_logged; /* bytes logged (bitmap) */ +#endif + xfs_buf_log_format_t bli_format; /* in-log header */ +} xfs_buf_log_item_t; + +/* + * This structure is used during recovery to record the buf log + * items which have been canceled and should not be replayed. + */ +typedef struct xfs_buf_cancel { + xfs_daddr_t bc_blkno; + uint bc_len; + int bc_refcount; + struct xfs_buf_cancel *bc_next; +} xfs_buf_cancel_t; + +#define XFS_BLI_TRACE_SIZE 32 + + +#if defined(XFS_ALL_TRACE) +#define XFS_BLI_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_BLI_TRACE +#endif + +#if defined(XFS_BLI_TRACE) +void xfs_buf_item_trace(char *, xfs_buf_log_item_t *); +#else +#define xfs_buf_item_trace(id, bip) +#endif + +void xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *); +void xfs_buf_item_relse(struct xfs_buf *); +void xfs_buf_item_log(xfs_buf_log_item_t *, uint, uint); +uint xfs_buf_item_dirty(xfs_buf_log_item_t *); +int xfs_buf_item_bits(uint *, uint, uint); +int xfs_buf_item_contig_bits(uint *, uint, uint); +int xfs_buf_item_next_bit(uint *, uint, uint); +void xfs_buf_attach_iodone(struct xfs_buf *, + void(*)(struct xfs_buf *, xfs_log_item_t *), + xfs_log_item_t *); +void xfs_buf_iodone_callbacks(struct xfs_buf *); +void xfs_buf_iodone(struct xfs_buf *, xfs_buf_log_item_t *); + +#ifdef XFS_TRANS_DEBUG +void +xfs_buf_item_flush_log_debug( + struct xfs_buf *bp, + uint first, + uint last); +#else +#define xfs_buf_item_flush_log_debug(bp, first, last) +#endif + +#endif /* __KERNEL__ */ + +#endif /* __XFS_BUF_ITEM_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_cred.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_cred.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_cred.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_cred.h Mon Jan 15 04:28:46 2001 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef __XFS_CRED_H__ +#define __XFS_CRED_H__ + +#include /* For NGROUPS */ +#ifdef __KERNEL__ +#include +#include +#endif + +/* + * Capabilities + */ +typedef __uint64_t cap_value_t; + +typedef struct cap_set { + cap_value_t cap_effective; /* use in capability checks */ + cap_value_t cap_permitted; /* combined with file attrs */ + cap_value_t cap_inheritable;/* pass through exec */ +} cap_set_t; + + +/* + * Mandatory Access Control + * + * Layout of a composite MAC label: + * ml_list contains the list of categories (MSEN) followed by the list of + * divisions (MINT). This is actually a header for the data structure which + * will have an ml_list with more than one element. + * + * ------------------------------- + * | ml_msen_type | ml_mint_type | + * ------------------------------- + * | ml_level | ml_grade | + * ------------------------------- + * | ml_catcount | + * ------------------------------- + * | ml_divcount | + * ------------------------------- + * | category 1 | + * | . . . | + * | category N | (where N = ml_catcount) + * ------------------------------- + * | division 1 | + * | . . . | + * | division M | (where M = ml_divcount) + * ------------------------------- + */ +#define MAC_MAX_SETS 250 +typedef struct mac_label { + unsigned char ml_msen_type; /* MSEN label type */ + unsigned char ml_mint_type; /* MINT label type */ + unsigned char ml_level; /* Hierarchical level */ + unsigned char ml_grade; /* Hierarchical grade */ + unsigned short ml_catcount; /* Category count */ + unsigned short ml_divcount; /* Division count */ + /* Category set, then Division set */ + unsigned short ml_list[MAC_MAX_SETS]; +} mac_label; + +/* Data types required by POSIX P1003.1eD15 */ +typedef struct mac_label * mac_t; + + +/* + * Credentials + */ +typedef struct cred { + int cr_ref; /* reference count */ + ushort cr_ngroups; /* number of groups in cr_groups */ + uid_t cr_uid; /* effective user id */ + gid_t cr_gid; /* effective group id */ + uid_t cr_ruid; /* real user id */ + gid_t cr_rgid; /* real group id */ + uid_t cr_suid; /* "saved" user id (from exec) */ + gid_t cr_sgid; /* "saved" group id (from exec) */ + struct mac_label *cr_mac; /* MAC label for B1 and beyond */ + cap_set_t cr_cap; /* capability (privilege) sets */ + gid_t cr_groups[NGROUPS]; /* supplementary group list */ +} cred_t; + + +#ifdef __KERNEL__ +extern int mac_enabled; +extern mac_label *mac_high_low_lp; +static __inline void mac_never(void) {} +struct xfs_inode; +extern int mac_xfs_iaccess(struct xfs_inode *, mode_t, cred_t *); +#define _MAC_XFS_IACCESS(i,m,c) \ + (mac_enabled? (mac_never(), mac_xfs_iaccess(i,m,c)): 0) +extern int mac_xfs_vaccess(vnode_t *, cred_t *, mode_t); +#define _MAC_VACCESS(v,c,m) \ + (mac_enabled? (mac_never(), mac_xfs_vaccess(v,c,m)): 0) + +#define VREAD 01 +#define VWRITE 02 +#endif /* __KERNEL__ */ + +#define MACWRITE 00200 +#define SGI_MAC_FILE "/dev/null" +#define SGI_MAC_FILE_SIZE 10 +#define SGI_CAP_FILE "/dev/null" +#define SGI_CAP_FILE_SIZE 10 + +/* MSEN label type names. Choose an upper case ASCII character. */ +#define MSEN_ADMIN_LABEL 'A' /* Admin: lowm_da_node_ents) +#endif + +#define XFS_DA_MAXHASH ((xfs_dahash_t)-1) /* largest valid hash value */ + +/* + * Macros used by directory code to interface to the filesystem. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LBSIZE) +int xfs_lbsize(struct xfs_mount *mp); +#define XFS_LBSIZE(mp) xfs_lbsize(mp) +#else +#define XFS_LBSIZE(mp) ((mp)->m_sb.sb_blocksize) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LBLOG) +int xfs_lblog(struct xfs_mount *mp); +#define XFS_LBLOG(mp) xfs_lblog(mp) +#else +#define XFS_LBLOG(mp) ((mp)->m_sb.sb_blocklog) +#endif + +/* + * Macros used by directory code to interface to the kernel + */ + +/* + * Macros used to manipulate directory off_t's + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_MAKE_BNOENTRY) +__uint32_t xfs_da_make_bnoentry(struct xfs_mount *mp, xfs_dablk_t bno, + int entry); +#define XFS_DA_MAKE_BNOENTRY(mp,bno,entry) \ + xfs_da_make_bnoentry(mp,bno,entry) +#else +#define XFS_DA_MAKE_BNOENTRY(mp,bno,entry) \ + (((bno) << (mp)->m_dircook_elog) | (entry)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_MAKE_COOKIE) +xfs_off_t xfs_da_make_cookie(struct xfs_mount *mp, xfs_dablk_t bno, int entry, + xfs_dahash_t hash); +#define XFS_DA_MAKE_COOKIE(mp,bno,entry,hash) \ + xfs_da_make_cookie(mp,bno,entry,hash) +#else +#define XFS_DA_MAKE_COOKIE(mp,bno,entry,hash) \ + (((xfs_off_t)XFS_DA_MAKE_BNOENTRY(mp, bno, entry) << 32) | (hash)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_COOKIE_HASH) +xfs_dahash_t xfs_da_cookie_hash(struct xfs_mount *mp, xfs_off_t cookie); +#define XFS_DA_COOKIE_HASH(mp,cookie) xfs_da_cookie_hash(mp,cookie) +#else +#define XFS_DA_COOKIE_HASH(mp,cookie) ((xfs_dahash_t)(cookie)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_COOKIE_BNO) +xfs_dablk_t xfs_da_cookie_bno(struct xfs_mount *mp, xfs_off_t cookie); +#define XFS_DA_COOKIE_BNO(mp,cookie) xfs_da_cookie_bno(mp,cookie) +#else +#define XFS_DA_COOKIE_BNO(mp,cookie) \ + (((xfs_off_t)(cookie) >> 31) == -1LL ? \ + (xfs_dablk_t)0 : \ + (xfs_dablk_t)((xfs_off_t)(cookie) >> ((mp)->m_dircook_elog + 32))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_COOKIE_ENTRY) +int xfs_da_cookie_entry(struct xfs_mount *mp, xfs_off_t cookie); +#define XFS_DA_COOKIE_ENTRY(mp,cookie) xfs_da_cookie_entry(mp,cookie) +#else +#define XFS_DA_COOKIE_ENTRY(mp,cookie) \ + (((xfs_off_t)(cookie) >> 31) == -1LL ? \ + (xfs_dablk_t)0 : \ + (xfs_dablk_t)(((xfs_off_t)(cookie) >> 32) & \ + ((1 << (mp)->m_dircook_elog) - 1))) +#endif + + +/*======================================================================== + * Btree searching and modification structure definitions. + *========================================================================*/ + +/* + * Structure to ease passing around component names. + */ +typedef struct xfs_da_args { + char *name; /* string (maybe not NULL terminated) */ + int namelen; /* length of string (maybe no NULL) */ + char *value; /* set of bytes (maybe contain NULLs) */ + int valuelen; /* length of value */ + int flags; /* argument flags (eg: ATTR_NOCREATE) */ + xfs_dahash_t hashval; /* hash value of name */ + xfs_ino_t inumber; /* input/output inode number */ + struct xfs_inode *dp; /* directory inode to manipulate */ + xfs_fsblock_t *firstblock; /* ptr to firstblock for bmap calls */ + struct xfs_bmap_free *flist; /* ptr to freelist for bmap_finish */ + struct xfs_trans *trans; /* current trans (changes over time) */ + xfs_extlen_t total; /* total blocks needed, for 1st bmap */ + int whichfork; /* data or attribute fork */ + xfs_dablk_t blkno; /* blkno of attr leaf of interest */ + int index; /* index of attr of interest in blk */ + xfs_dablk_t rmtblkno; /* remote attr value starting blkno */ + int rmtblkcnt; /* remote attr value block count */ + int rename; /* T/F: this is an atomic rename op */ + xfs_dablk_t blkno2; /* blkno of 2nd attr leaf of interest */ + int index2; /* index of 2nd attr in blk */ + xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */ + int rmtblkcnt2; /* remote attr value block count */ + int justcheck; /* check for ok with no space */ + int addname; /* T/F: this is an add operation */ + int oknoent; /* T/F: ok to return ENOENT, else die */ +} xfs_da_args_t; + +/* + * Structure to describe buffer(s) for a block. + * This is needed in the directory version 2 format case, when + * multiple non-contiguous fsblocks might be needed to cover one + * logical directory block. + * If the buffer count is 1 then the data pointer points to the + * same place as the b_addr field for the buffer, else to kmem_alloced memory. + */ +typedef struct xfs_dabuf { + int nbuf; /* number of buffer pointers present */ + short dirty; /* data needs to be copied back */ + short bbcount; /* how large is data in bbs */ + void *data; /* pointer for buffers' data */ +#ifdef XFS_DABUF_DEBUG + inst_t *ra; /* return address of caller to make */ + struct xfs_dabuf *next; /* next in global chain */ + struct xfs_dabuf *prev; /* previous in global chain */ + dev_t dev; /* device for buffer */ + xfs_daddr_t blkno; /* daddr first in bps[0] */ +#endif + struct xfs_buf *bps[1]; /* actually nbuf of these */ +} xfs_dabuf_t; +#define XFS_DA_BUF_SIZE(n) \ + (sizeof(xfs_dabuf_t) + sizeof(struct xfs_buf *) * ((n) - 1)) + +#ifdef XFS_DABUF_DEBUG +extern xfs_dabuf_t *xfs_dabuf_global_list; +#endif + +/* + * Storage for holding state during Btree searches and split/join ops. + * + * Only need space for 5 intermediate nodes. With a minimum of 62-way + * fanout to the Btree, we can support over 900 million directory blocks, + * which is slightly more than enough. + */ +typedef struct xfs_da_state_blk { + xfs_dabuf_t *bp; /* buffer containing block */ + xfs_dablk_t blkno; /* filesystem blkno of buffer */ + xfs_daddr_t disk_blkno; /* on-disk blkno (in BBs) of buffer */ + int index; /* relevant index into block */ + xfs_dahash_t hashval; /* last hash value in block */ + int magic; /* blk's magic number, ie: blk type */ +} xfs_da_state_blk_t; + +typedef struct xfs_da_state_path { + int active; /* number of active levels */ + xfs_da_state_blk_t blk[XFS_DA_NODE_MAXDEPTH]; +} xfs_da_state_path_t; + +typedef struct xfs_da_state { + xfs_da_args_t *args; /* filename arguments */ + struct xfs_mount *mp; /* filesystem mount point */ + int blocksize; /* logical block size */ + int inleaf; /* insert into 1->lf, 0->splf */ + xfs_da_state_path_t path; /* search/split paths */ + xfs_da_state_path_t altpath; /* alternate path for join */ + int extravalid; /* T/F: extrablk is in use */ + int extraafter; /* T/F: extrablk is after new */ + xfs_da_state_blk_t extrablk; /* for double-splits on leafs */ + /* for dirv2 extrablk is data */ +} xfs_da_state_t; + +/* + * Utility macros to aid in logging changed structure fields. + */ +#define XFS_DA_LOGOFF(BASE, ADDR) ((char *)(ADDR) - (char *)(BASE)) +#define XFS_DA_LOGRANGE(BASE, ADDR, SIZE) \ + (uint)(XFS_DA_LOGOFF(BASE, ADDR)), \ + (uint)(XFS_DA_LOGOFF(BASE, ADDR)+(SIZE)-1) + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Routines used for growing the Btree. + */ +int xfs_da_node_create(xfs_da_args_t *args, xfs_dablk_t blkno, int level, + xfs_dabuf_t **bpp, int whichfork); +int xfs_da_split(xfs_da_state_t *state); + +/* + * Routines used for shrinking the Btree. + */ +int xfs_da_join(xfs_da_state_t *state); +void xfs_da_fixhashpath(xfs_da_state_t *state, + xfs_da_state_path_t *path_to_to_fix); + +/* + * Routines used for finding things in the Btree. + */ +int xfs_da_node_lookup_int(xfs_da_state_t *state, int *result); +int xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path, + int forward, int release, int *result); +/* + * Utility routines. + */ +int xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk); +int xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk, + xfs_da_state_blk_t *new_blk); + +/* + * Utility routines. + */ +int xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno); +int xfs_da_get_buf(struct xfs_trans *trans, struct xfs_inode *dp, + xfs_dablk_t bno, xfs_daddr_t mappedbno, + xfs_dabuf_t **bp, int whichfork); +int xfs_da_read_buf(struct xfs_trans *trans, struct xfs_inode *dp, + xfs_dablk_t bno, xfs_daddr_t mappedbno, + xfs_dabuf_t **bpp, int whichfork); +xfs_daddr_t xfs_da_reada_buf(struct xfs_trans *trans, struct xfs_inode *dp, + xfs_dablk_t bno, int whichfork); +int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, + xfs_dabuf_t *dead_buf); + +uint xfs_da_hashname(char *name_string, int name_length); +uint xfs_da_log2_roundup(uint i); +xfs_da_state_t *xfs_da_state_alloc(void); +void xfs_da_state_free(xfs_da_state_t *state); +void xfs_da_state_kill_altpath(xfs_da_state_t *state); + +void xfs_da_buf_done(xfs_dabuf_t *dabuf); +void xfs_da_log_buf(struct xfs_trans *tp, xfs_dabuf_t *dabuf, uint first, + uint last); +void xfs_da_brelse(struct xfs_trans *tp, xfs_dabuf_t *dabuf); +void xfs_da_binval(struct xfs_trans *tp, xfs_dabuf_t *dabuf); +xfs_daddr_t xfs_da_blkno(xfs_dabuf_t *dabuf); + +extern struct xfs_zone *xfs_da_state_zone; + +#endif /* __XFS_DA_BTREE_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_dfrag.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_dfrag.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_dfrag.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_dfrag.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DFRAG_H__ +#define __XFS_DFRAG_H__ + +/* + * Structure passed to xfs_swapext + */ + +typedef struct xfs_swapext +{ + __int64_t sx_version; /* version */ + __int64_t sx_fdtarget; /* fd of target file */ + __int64_t sx_fdtmp; /* fd of tmp file */ + xfs_off_t sx_offset; /* offset into file */ + xfs_off_t sx_length; /* leng from offset */ + char sx_pad[16]; /* pad space, unused */ + xfs_bstat_t sx_stat; /* stat of target b4 copy */ +} xfs_swapext_t; + +/* + * Version flag + */ +#define XFS_SX_VERSION 0 + +#ifdef __KERNEL__ +/* + * Prototypes for visible xfs_dfrag.c routines. + */ + +/* + * Syscall interface for xfs_swapext + */ +int xfs_swapext(struct xfs_swapext *sx); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_DFRAG_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_dinode.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_dinode.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_dinode.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_dinode.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DINODE_H__ +#define __XFS_DINODE_H__ + +struct xfs_buf; +struct xfs_mount; + +#define XFS_DINODE_VERSION_1 1 +#define XFS_DINODE_VERSION_2 2 +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DINODE_GOOD_VERSION) +int xfs_dinode_good_version(int v); +#define XFS_DINODE_GOOD_VERSION(v) xfs_dinode_good_version(v) +#else +#define XFS_DINODE_GOOD_VERSION(v) (((v) == XFS_DINODE_VERSION_1) || \ + ((v) == XFS_DINODE_VERSION_2)) +#endif +#define XFS_DINODE_MAGIC 0x494e /* 'IN' */ + +/* + * Disk inode structure. + * This is just the header; the inode is expanded to fill a variable size + * with the last field expanding. It is split into the core and "other" + * because we only need the core part in the in-core inode. + */ +typedef struct xfs_timestamp { + __int32_t t_sec; /* timestamp seconds */ + __int32_t t_nsec; /* timestamp nanoseconds */ +} xfs_timestamp_t; + +/* + * Note: Coordinate changes to this structure with the XFS_DI_* #defines + * below and the offsets table in xfs_ialloc_log_di(). + */ +typedef struct xfs_dinode_core +{ + __uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */ + __uint16_t di_mode; /* mode and type of file */ + __int8_t di_version; /* inode version */ + __int8_t di_format; /* format of di_c data */ + __uint16_t di_onlink; /* old number of links to file */ + __uint32_t di_uid; /* owner's user id */ + __uint32_t di_gid; /* owner's group id */ + __uint32_t di_nlink; /* number of links to file */ + __uint16_t di_projid; /* owner's project id */ + __uint8_t di_pad[10]; /* unused, zeroed space */ + xfs_timestamp_t di_atime; /* time last accessed */ + xfs_timestamp_t di_mtime; /* time last modified */ + xfs_timestamp_t di_ctime; /* time created/inode modified */ + xfs_fsize_t di_size; /* number of bytes in file */ + xfs_drfsbno_t di_nblocks; /* # of direct & btree blocks used */ + xfs_extlen_t di_extsize; /* basic/minimum extent size for file */ + xfs_extnum_t di_nextents; /* number of extents in data fork */ + xfs_aextnum_t di_anextents; /* number of extents in attribute fork*/ + __uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */ + __int8_t di_aformat; /* format of attr fork's data */ + __uint32_t di_dmevmask; /* DMIG event mask */ + __uint16_t di_dmstate; /* DMIG state info */ + __uint16_t di_flags; /* random flags, XFS_DIFLAG_... */ + __uint32_t di_gen; /* generation number */ +} xfs_dinode_core_t; + +typedef struct xfs_dinode +{ + xfs_dinode_core_t di_core; + /* + * In adding anything between the core and the union, be + * sure to update the macros like XFS_LITINO below and + * XFS_BMAP_RBLOCK_DSIZE in xfs_bmap_btree.h. + */ + xfs_agino_t di_next_unlinked;/* agi unlinked list ptr */ + union { + xfs_bmdr_block_t di_bmbt; /* btree root block */ + xfs_bmbt_rec_32_t di_bmx[1]; /* extent list */ + xfs_dir_shortform_t di_dirsf; /* shortform directory */ + xfs_dir2_sf_t di_dir2sf; /* shortform directory v2 */ + char di_c[1]; /* local contents */ + xfs_dev_t di_dev; /* device for IFCHR/IFBLK */ + uuid_t di_muuid; /* mount point value */ + char di_symlink[1]; /* local symbolic link */ + } di_u; + union { + xfs_bmdr_block_t di_abmbt; /* btree root block */ + xfs_bmbt_rec_32_t di_abmx[1]; /* extent list */ + xfs_attr_shortform_t di_attrsf; /* shortform attribute list */ + } di_a; +} xfs_dinode_t; + +/* + * The 32 bit link count in the inode theoretically maxes out at UINT_MAX. + * Since the pathconf interface is signed, we use 2^31 - 1 instead. + * The old inode format had a 16 bit link count, so its maximum is USHRT_MAX. + */ +#define XFS_MAXLINK ((1U << 31) - 1U) +#define XFS_MAXLINK_1 65535U + +/* + * Bit names for logging disk inodes only + */ +#define XFS_DI_MAGIC 0x0000001 +#define XFS_DI_MODE 0x0000002 +#define XFS_DI_VERSION 0x0000004 +#define XFS_DI_FORMAT 0x0000008 +#define XFS_DI_ONLINK 0x0000010 +#define XFS_DI_UID 0x0000020 +#define XFS_DI_GID 0x0000040 +#define XFS_DI_NLINK 0x0000080 +#define XFS_DI_PROJID 0x0000100 +#define XFS_DI_PAD 0x0000200 +#define XFS_DI_ATIME 0x0000400 +#define XFS_DI_MTIME 0x0000800 +#define XFS_DI_CTIME 0x0001000 +#define XFS_DI_SIZE 0x0002000 +#define XFS_DI_NBLOCKS 0x0004000 +#define XFS_DI_EXTSIZE 0x0008000 +#define XFS_DI_NEXTENTS 0x0010000 +#define XFS_DI_NAEXTENTS 0x0020000 +#define XFS_DI_FORKOFF 0x0040000 +#define XFS_DI_AFORMAT 0x0080000 +#define XFS_DI_DMEVMASK 0x0100000 +#define XFS_DI_DMSTATE 0x0200000 +#define XFS_DI_FLAGS 0x0400000 +#define XFS_DI_GEN 0x0800000 +#define XFS_DI_NEXT_UNLINKED 0x1000000 +#define XFS_DI_U 0x2000000 +#define XFS_DI_A 0x4000000 +#define XFS_DI_NUM_BITS 27 +#define XFS_DI_ALL_BITS ((1 << XFS_DI_NUM_BITS) - 1) +#define XFS_DI_CORE_BITS (XFS_DI_ALL_BITS & ~(XFS_DI_U|XFS_DI_A)) + +/* + * Values for di_format + */ +typedef enum xfs_dinode_fmt +{ + XFS_DINODE_FMT_DEV, /* CHR, BLK: di_dev */ + XFS_DINODE_FMT_LOCAL, /* DIR, REG: di_c */ + /* LNK: di_symlink */ + XFS_DINODE_FMT_EXTENTS, /* DIR, REG, LNK: di_bmx */ + XFS_DINODE_FMT_BTREE, /* DIR, REG, LNK: di_bmbt */ + XFS_DINODE_FMT_UUID /* MNT: di_uuid */ +} xfs_dinode_fmt_t; + +/* + * Inode minimum and maximum sizes. + */ +#define XFS_DINODE_MIN_LOG 8 +#define XFS_DINODE_MAX_LOG 11 +#define XFS_DINODE_MIN_SIZE (1 << XFS_DINODE_MIN_LOG) +#define XFS_DINODE_MAX_SIZE (1 << XFS_DINODE_MAX_LOG) + +/* + * Inode size for given fs. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LITINO) +int xfs_litino(struct xfs_mount *mp); +#define XFS_LITINO(mp) xfs_litino(mp) +#else +#define XFS_LITINO(mp) ((mp)->m_litino) +#endif +#define XFS_BROOT_SIZE_ADJ \ + (sizeof(xfs_bmbt_block_t) - sizeof(xfs_bmdr_block_t)) + +/* + * Fork identifiers. Here so utilities can use them without including + * xfs_inode.h. + */ +#define XFS_DATA_FORK 0 +#define XFS_ATTR_FORK 1 + +/* + * Inode data & attribute fork sizes, per inode. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_Q) +int xfs_cfork_q_arch(xfs_dinode_core_t *dcp, xfs_arch_t arch); +int xfs_cfork_q(xfs_dinode_core_t *dcp); +#define XFS_CFORK_Q_ARCH(dcp,arch) xfs_cfork_q_arch(dcp,arch) +#define XFS_CFORK_Q(dcp) xfs_cfork_q(dcp) +#else +#define XFS_CFORK_Q_ARCH(dcp,arch) (INT_GET((dcp)->di_forkoff, arch) != 0) +#define XFS_CFORK_Q(dcp) XFS_CFORK_Q_ARCH(dcp,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_BOFF) +int xfs_cfork_boff_arch(xfs_dinode_core_t *dcp, xfs_arch_t arch); +int xfs_cfork_boff(xfs_dinode_core_t *dcp); +#define XFS_CFORK_BOFF_ARCH(dcp,arch) xfs_cfork_boff_arch(dcp,arch) +#define XFS_CFORK_BOFF(dcp) xfs_cfork_boff(dcp) +#else +#define XFS_CFORK_BOFF_ARCH(dcp,arch) ((int)(INT_GET((dcp)->di_forkoff, arch) << 3)) +#define XFS_CFORK_BOFF(dcp) XFS_CFORK_BOFF_ARCH(dcp,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_DSIZE) +int xfs_cfork_dsize_arch(xfs_dinode_core_t *dcp, struct xfs_mount *mp, xfs_arch_t arch); +int xfs_cfork_dsize(xfs_dinode_core_t *dcp, struct xfs_mount *mp); +#define XFS_CFORK_DSIZE_ARCH(dcp,mp,arch) xfs_cfork_dsize_arch(dcp,mp,arch) +#define XFS_CFORK_DSIZE(dcp,mp) xfs_cfork_dsize(dcp,mp) +#else +#define XFS_CFORK_DSIZE_ARCH(dcp,mp,arch) \ + (XFS_CFORK_Q_ARCH(dcp, arch) ? XFS_CFORK_BOFF_ARCH(dcp, arch) : XFS_LITINO(mp)) +#define XFS_CFORK_DSIZE(dcp,mp) XFS_CFORK_DSIZE_ARCH(dcp,mp,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_ASIZE) +int xfs_cfork_asize_arch(xfs_dinode_core_t *dcp, struct xfs_mount *mp, xfs_arch_t arch); +int xfs_cfork_asize(xfs_dinode_core_t *dcp, struct xfs_mount *mp); +#define XFS_CFORK_ASIZE_ARCH(dcp,mp,arch) xfs_cfork_asize_arch(dcp,mp,arch) +#define XFS_CFORK_ASIZE(dcp,mp) xfs_cfork_asize(dcp,mp) +#else +#define XFS_CFORK_ASIZE_ARCH(dcp,mp,arch) \ + (XFS_CFORK_Q_ARCH(dcp, arch) ? XFS_LITINO(mp) - XFS_CFORK_BOFF_ARCH(dcp, arch) : 0) +#define XFS_CFORK_ASIZE(dcp,mp) XFS_CFORK_ASIZE_ARCH(dcp,mp,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_SIZE) +int xfs_cfork_size_arch(xfs_dinode_core_t *dcp, struct xfs_mount *mp, int w, xfs_arch_t arch); +int xfs_cfork_size(xfs_dinode_core_t *dcp, struct xfs_mount *mp, int w); +#define XFS_CFORK_SIZE_ARCH(dcp,mp,w,arch) xfs_cfork_size_arch(dcp,mp,w,arch) +#define XFS_CFORK_SIZE(dcp,mp,w) xfs_cfork_size(dcp,mp,w) +#else +#define XFS_CFORK_SIZE_ARCH(dcp,mp,w,arch) \ + ((w) == XFS_DATA_FORK ? \ + XFS_CFORK_DSIZE_ARCH(dcp, mp, arch) : XFS_CFORK_ASIZE_ARCH(dcp, mp, arch)) +#define XFS_CFORK_SIZE(dcp,mp,w) XFS_CFORK_SIZE_ARCH(dcp,mp,w,ARCH_NOCONVERT) + +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_DSIZE) +int xfs_dfork_dsize_arch(xfs_dinode_t *dip, struct xfs_mount *mp, xfs_arch_t arch); +int xfs_dfork_dsize(xfs_dinode_t *dip, struct xfs_mount *mp); +#define XFS_DFORK_DSIZE_ARCH(dip,mp,arch) xfs_dfork_dsize_arch(dip,mp,arch) +#define XFS_DFORK_DSIZE(dip,mp) xfs_dfork_dsize(dip,mp) +#else +#define XFS_DFORK_DSIZE_ARCH(dip,mp,arch) XFS_CFORK_DSIZE_ARCH(&(dip)->di_core, mp, arch) +#define XFS_DFORK_DSIZE(dip,mp) XFS_DFORK_DSIZE_ARCH(dip,mp,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_ASIZE) +int xfs_dfork_asize_arch(xfs_dinode_t *dip, struct xfs_mount *mp, xfs_arch_t arch); +int xfs_dfork_asize(xfs_dinode_t *dip, struct xfs_mount *mp); +#define XFS_DFORK_ASIZE_ARCH(dip,mp,arch) xfs_dfork_asize_arch(dip,mp,arch) +#define XFS_DFORK_ASIZE(dip,mp) xfs_dfork_asize(dip,mp) +#else +#define XFS_DFORK_ASIZE_ARCH(dip,mp,arch) XFS_CFORK_ASIZE_ARCH(&(dip)->di_core, mp, arch) +#define XFS_DFORK_ASIZE(dip,mp) XFS_DFORK_ASIZE_ARCH(dip,mp,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_SIZE) +int xfs_dfork_size_arch(xfs_dinode_t *dip, struct xfs_mount *mp, int w, xfs_arch_t arch); +int xfs_dfork_size(xfs_dinode_t *dip, struct xfs_mount *mp, int w); +#define XFS_DFORK_SIZE_ARCH(dip,mp,w,arch) xfs_dfork_size_arch(dip,mp,w,arch) +#define XFS_DFORK_SIZE(dip,mp,w) xfs_dfork_size(dip,mp,w) +#else +#define XFS_DFORK_SIZE_ARCH(dip,mp,w,arch) XFS_CFORK_SIZE_ARCH(&(dip)->di_core, mp, w, arch) +#define XFS_DFORK_SIZE(dip,mp,w) XFS_DFORK_SIZE_ARCH(dip,mp,w,ARCH_NOCONVERT) + +#endif + +/* + * Macros for accessing per-fork disk inode information. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_Q) +int xfs_dfork_q_arch(xfs_dinode_t *dip, xfs_arch_t arch); +int xfs_dfork_q(xfs_dinode_t *dip); +#define XFS_DFORK_Q_ARCH(dip,arch) xfs_dfork_q_arch(dip,arch) +#define XFS_DFORK_Q(dip) xfs_dfork_q(dip) +#else +#define XFS_DFORK_Q_ARCH(dip,arch) XFS_CFORK_Q_ARCH(&(dip)->di_core, arch) +#define XFS_DFORK_Q(dip) XFS_DFORK_Q_ARCH(dip,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_BOFF) +int xfs_dfork_boff_arch(xfs_dinode_t *dip, xfs_arch_t arch); +int xfs_dfork_boff(xfs_dinode_t *dip); +#define XFS_DFORK_BOFF_ARCH(dip,arch) xfs_dfork_boff_arch(dip,arch) +#define XFS_DFORK_BOFF(dip) xfs_dfork_boff(dip) +#else +#define XFS_DFORK_BOFF_ARCH(dip,arch) XFS_CFORK_BOFF_ARCH(&(dip)->di_core, arch) +#define XFS_DFORK_BOFF(dip) XFS_DFORK_BOFF_ARCH(dip,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_DPTR) +char *xfs_dfork_dptr_arch(xfs_dinode_t *dip, xfs_arch_t arch); +char *xfs_dfork_dptr(xfs_dinode_t *dip); +#define XFS_DFORK_DPTR_ARCH(dip,arch) xfs_dfork_dptr_arch(dip,arch) +#define XFS_DFORK_DPTR(dip) xfs_dfork_dptr(dip) +#else +#define XFS_DFORK_DPTR_ARCH(dip,arch) ((dip)->di_u.di_c) +#define XFS_DFORK_DPTR(dip) XFS_DFORK_DPTR_ARCH(dip,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_APTR) +char *xfs_dfork_aptr_arch(xfs_dinode_t *dip, xfs_arch_t arch); +char *xfs_dfork_aptr(xfs_dinode_t *dip); +#define XFS_DFORK_APTR_ARCH(dip,arch) xfs_dfork_aptr_arch(dip,arch) +#define XFS_DFORK_APTR(dip) xfs_dfork_aptr(dip) +#else +#define XFS_DFORK_APTR_ARCH(dip,arch) ((dip)->di_u.di_c + XFS_DFORK_BOFF_ARCH(dip, arch)) +#define XFS_DFORK_APTR(dip) XFS_DFORK_APTR_ARCH(dip,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_PTR) +char *xfs_dfork_ptr_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch); +char *xfs_dfork_ptr(xfs_dinode_t *dip, int w); +#define XFS_DFORK_PTR_ARCH(dip,w,arch) xfs_dfork_ptr_arch(dip,w,arch) +#define XFS_DFORK_PTR(dip,w) xfs_dfork_ptr(dip,w) +#else +#define XFS_DFORK_PTR_ARCH(dip,w,arch) \ + ((w) == XFS_DATA_FORK ? XFS_DFORK_DPTR_ARCH(dip, arch) : XFS_DFORK_APTR_ARCH(dip, arch)) +#define XFS_DFORK_PTR(dip,w) XFS_DFORK_PTR_ARCH(dip,w,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_FORMAT) +int xfs_cfork_format_arch(xfs_dinode_core_t *dcp, int w, xfs_arch_t arch); +int xfs_cfork_format(xfs_dinode_core_t *dcp, int w); +#define XFS_CFORK_FORMAT_ARCH(dcp,w,arch) xfs_cfork_format_arch(dcp,w,arch) +#define XFS_CFORK_FORMAT(dcp,w) xfs_cfork_format(dcp,w) +#else +#define XFS_CFORK_FORMAT_ARCH(dcp,w,arch) \ + ((w) == XFS_DATA_FORK ? INT_GET((dcp)->di_format, arch) : INT_GET((dcp)->di_aformat, arch)) +#define XFS_CFORK_FORMAT(dcp,w) XFS_CFORK_FORMAT_ARCH(dcp,w,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_FMT_SET) +void xfs_cfork_fmt_set_arch(xfs_dinode_core_t *dcp, int w, int n, xfs_arch_t arch); +void xfs_cfork_fmt_set(xfs_dinode_core_t *dcp, int w, int n); +#define XFS_CFORK_FMT_SET_ARCH(dcp,w,n,arch) xfs_cfork_fmt_set_arch(dcp,w,n,arch) +#define XFS_CFORK_FMT_SET(dcp,w,n) xfs_cfork_fmt_set(dcp,w,n) +#else +#define XFS_CFORK_FMT_SET_ARCH(dcp,w,n,arch) \ + ((w) == XFS_DATA_FORK ? \ + (INT_SET((dcp)->di_format, arch, (n))) : \ + (INT_SET((dcp)->di_aformat, arch, (n)))) +#define XFS_CFORK_FMT_SET(dcp,w,n) XFS_CFORK_FMT_SET_ARCH(dcp,w,n,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_NEXTENTS) +int xfs_cfork_nextents_arch(xfs_dinode_core_t *dcp, int w, xfs_arch_t arch); +int xfs_cfork_nextents(xfs_dinode_core_t *dcp, int w); +#define XFS_CFORK_NEXTENTS_ARCH(dcp,w,arch) xfs_cfork_nextents_arch(dcp,w,arch) +#define XFS_CFORK_NEXTENTS(dcp,w) xfs_cfork_nextents(dcp,w) +#else +#define XFS_CFORK_NEXTENTS_ARCH(dcp,w,arch) \ + ((w) == XFS_DATA_FORK ? INT_GET((dcp)->di_nextents, arch) : INT_GET((dcp)->di_anextents, arch)) +#define XFS_CFORK_NEXTENTS(dcp,w) XFS_CFORK_NEXTENTS_ARCH(dcp,w,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_NEXT_SET) +void xfs_cfork_next_set_arch(xfs_dinode_core_t *dcp, int w, int n, xfs_arch_t arch); +void xfs_cfork_next_set(xfs_dinode_core_t *dcp, int w, int n); +#define XFS_CFORK_NEXT_SET_ARCH(dcp,w,n,arch) xfs_cfork_next_set_arch(dcp,w,n,arch) +#define XFS_CFORK_NEXT_SET(dcp,w,n) xfs_cfork_next_set(dcp,w,n) +#else +#define XFS_CFORK_NEXT_SET_ARCH(dcp,w,n,arch) \ + ((w) == XFS_DATA_FORK ? \ + (INT_SET((dcp)->di_nextents, arch, (n))) : \ + (INT_SET((dcp)->di_anextents, arch, (n)))) +#define XFS_CFORK_NEXT_SET(dcp,w,n) XFS_CFORK_NEXT_SET_ARCH(dcp,w,n,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_FORMAT) +int xfs_dfork_format_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch); +int xfs_dfork_format(xfs_dinode_t *dip, int w); +#define XFS_DFORK_FORMAT_ARCH(dip,w,arch) xfs_dfork_format_arch(dip,w,arch) +#define XFS_DFORK_FORMAT(dip,w) xfs_dfork_format(dip,w) +#else +#define XFS_DFORK_FORMAT_ARCH(dip,w,arch) XFS_CFORK_FORMAT_ARCH(&(dip)->di_core, w, arch) +#define XFS_DFORK_FORMAT(dip,w) XFS_DFORK_FORMAT_ARCH(dip,w,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_FMT_SET) +void xfs_dfork_fmt_set_arch(xfs_dinode_t *dip, int w, int n, xfs_arch_t arch); +void xfs_dfork_fmt_set(xfs_dinode_t *dip, int w, int n); +#define XFS_DFORK_FMT_SET_ARCH(dip,w,n,arch) xfs_dfork_fmt_set_arch(dip,w,n,arch) +#define XFS_DFORK_FMT_SET(dip,w,n) xfs_dfork_fmt_set(dip,w,n) +#else +#define XFS_DFORK_FMT_SET_ARCH(dip,w,n,arch) XFS_CFORK_FMT_SET_ARCH(&(dip)->di_core, w, n, arch) +#define XFS_DFORK_FMT_SET(dip,w,n) XFS_DFORK_FMT_SET_ARCH(dip,w,n,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_NEXTENTS) +int xfs_dfork_nextents_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch); +int xfs_dfork_nextents(xfs_dinode_t *dip, int w); +#define XFS_DFORK_NEXTENTS_ARCH(dip,w,arch) xfs_dfork_nextents_arch(dip,w,arch) +#define XFS_DFORK_NEXTENTS(dip,w) xfs_dfork_nextents(dip,w) +#else +#define XFS_DFORK_NEXTENTS_ARCH(dip,w,arch) XFS_CFORK_NEXTENTS_ARCH(&(dip)->di_core, w, arch) +#define XFS_DFORK_NEXTENTS(dip,w) XFS_DFORK_NEXTENTS_ARCH(dip,w,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_NEXT_SET) +void xfs_dfork_next_set_arch(xfs_dinode_t *dip, int w, int n, xfs_arch_t arch); +void xfs_dfork_next_set(xfs_dinode_t *dip, int w, int n); +#define XFS_DFORK_NEXT_SET_ARCH(dip,w,n,arch) xfs_dfork_next_set_arch(dip,w,n,arch) +#define XFS_DFORK_NEXT_SET(dip,w,n) xfs_dfork_next_set(dip,w,n) +#else +#define XFS_DFORK_NEXT_SET_ARCH(dip,w,n,arch) XFS_CFORK_NEXT_SET_ARCH(&(dip)->di_core, w, n, arch) +#define XFS_DFORK_NEXT_SET(dip,w,n) XFS_DFORK_NEXT_SET_ARCH(dip,w,n,ARCH_NOCONVERT) + +#endif + +/* + * File types (mode field) + */ +#define IFMT 0170000 /* type of file */ +#define IFIFO 0010000 /* named pipe (fifo) */ +#define IFCHR 0020000 /* character special */ +#define IFDIR 0040000 /* directory */ +#define IFBLK 0060000 /* block special */ +#define IFREG 0100000 /* regular */ +#define IFLNK 0120000 /* symbolic link */ +#define IFSOCK 0140000 /* socket */ +#define IFMNT 0160000 /* mount point */ + +/* + * File execution and access modes. + */ +#define ISUID 04000 /* set user id on execution */ +#define ISGID 02000 /* set group id on execution */ +#define ISVTX 01000 /* sticky directory */ +#define IREAD 0400 /* read, write, execute permissions */ +#define IWRITE 0200 +#define IEXEC 0100 + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_DINODE) +xfs_dinode_t *xfs_buf_to_dinode(struct xfs_buf *bp); +#define XFS_BUF_TO_DINODE(bp) xfs_buf_to_dinode(bp) +#else +#define XFS_BUF_TO_DINODE(bp) ((xfs_dinode_t *)(XFS_BUF_PTR(bp))) +#endif + +/* + * Values for di_flags + * There should be a one-to-one correspondence between these flags and the + * XFS_XFLAG_s. + */ +#define XFS_DIFLAG_REALTIME_BIT 0 /* file's blocks come from rt area */ +#define XFS_DIFLAG_PREALLOC_BIT 1 /* file space has been preallocated */ +#define XFS_DIFLAG_NEWRTBM_BIT 2 /* for rtbitmap inode, new format */ +#define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) +#define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) +#define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) +#define XFS_DIFLAG_ALL \ + (XFS_DIFLAG_REALTIME|XFS_DIFLAG_PREALLOC|XFS_DIFLAG_NEWRTBM) + +#endif /* __XFS_DINODE_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_dir.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_dir.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR_H__ +#define __XFS_DIR_H__ + +/* + * Large directories are structured around Btrees where all the data + * elements are in the leaf nodes. Filenames are hashed into an int, + * then that int is used as the index into the Btree. Since the hashval + * of a filename may not be unique, we may have duplicate keys. The + * internal links in the Btree are logical block offsets into the file. + * + * Small directories use a different format and are packed as tightly + * as possible so as to fit into the literal area of the inode. + */ + +#ifdef XFS_ALL_TRACE +#define XFS_DIR_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_DIR_TRACE +#endif + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +struct uio; +struct xfs_bmap_free; +struct xfs_da_args; +struct xfs_dinode; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * Directory function types. + * Put in structures (xfs_dirops_t) for v1 and v2 directories. + */ +typedef void (*xfs_dir_mount_t)(struct xfs_mount *mp); +typedef int (*xfs_dir_isempty_t)(struct xfs_inode *dp); +typedef int (*xfs_dir_init_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + struct xfs_inode *pdp); +typedef int (*xfs_dir_createname_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name, + int namelen, + xfs_ino_t inum, + xfs_fsblock_t *first, + struct xfs_bmap_free *flist, + xfs_extlen_t total); +typedef int (*xfs_dir_lookup_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name, + int namelen, + xfs_ino_t *inum); +typedef int (*xfs_dir_removename_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name, + int namelen, + xfs_ino_t ino, + xfs_fsblock_t *first, + struct xfs_bmap_free *flist, + xfs_extlen_t total); +typedef int (*xfs_dir_getdents_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + struct uio *uio, + int *eofp); +typedef int (*xfs_dir_replace_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name, + int namelen, + xfs_ino_t inum, + xfs_fsblock_t *first, + struct xfs_bmap_free *flist, + xfs_extlen_t total); +typedef int (*xfs_dir_canenter_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name, + int namelen); +typedef int (*xfs_dir_shortform_validate_ondisk_t)(struct xfs_mount *mp, + struct xfs_dinode *dip); +typedef int (*xfs_dir_shortform_to_single_t)(struct xfs_da_args *args); + +typedef struct xfs_dirops { + xfs_dir_mount_t xd_mount; + xfs_dir_isempty_t xd_isempty; + xfs_dir_init_t xd_init; + xfs_dir_createname_t xd_createname; + xfs_dir_lookup_t xd_lookup; + xfs_dir_removename_t xd_removename; + xfs_dir_getdents_t xd_getdents; + xfs_dir_replace_t xd_replace; + xfs_dir_canenter_t xd_canenter; + xfs_dir_shortform_validate_ondisk_t xd_shortform_validate_ondisk; + xfs_dir_shortform_to_single_t xd_shortform_to_single; +} xfs_dirops_t; + +/* + * Overall external interface routines. + */ +void xfs_dir_startup(void); /* called exactly once */ + +#define XFS_DIR_MOUNT(mp) \ + ((mp)->m_dirops.xd_mount(mp)) +#define XFS_DIR_ISEMPTY(mp,dp) \ + ((mp)->m_dirops.xd_isempty(dp)) +#define XFS_DIR_INIT(mp,tp,dp,pdp) \ + ((mp)->m_dirops.xd_init(tp,dp,pdp)) +#define XFS_DIR_CREATENAME(mp,tp,dp,name,namelen,inum,first,flist,total) \ + ((mp)->m_dirops.xd_createname(tp,dp,name,namelen,inum,first,flist,\ + total)) +#define XFS_DIR_LOOKUP(mp,tp,dp,name,namelen,inum) \ + ((mp)->m_dirops.xd_lookup(tp,dp,name,namelen,inum)) +#define XFS_DIR_REMOVENAME(mp,tp,dp,name,namelen,ino,first,flist,total) \ + ((mp)->m_dirops.xd_removename(tp,dp,name,namelen,ino,first,flist,total)) +#define XFS_DIR_GETDENTS(mp,tp,dp,uio,eofp) \ + ((mp)->m_dirops.xd_getdents(tp,dp,uio,eofp)) +#define XFS_DIR_REPLACE(mp,tp,dp,name,namelen,inum,first,flist,total) \ + ((mp)->m_dirops.xd_replace(tp,dp,name,namelen,inum,first,flist,total)) +#define XFS_DIR_CANENTER(mp,tp,dp,name,namelen) \ + ((mp)->m_dirops.xd_canenter(tp,dp,name,namelen)) +#define XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp,dip) \ + ((mp)->m_dirops.xd_shortform_validate_ondisk(mp,dip)) +#define XFS_DIR_SHORTFORM_TO_SINGLE(mp,args) \ + ((mp)->m_dirops.xd_shortform_to_single(args)) + +#define XFS_DIR_IS_V1(mp) ((mp)->m_dirversion == 1) +extern xfs_dirops_t xfsv1_dirops; + +#endif /* __XFS_DIR_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_dir2.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir2.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_dir2.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir2.h Thu Apr 12 18:30:32 2001 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_H__ +#define __XFS_DIR2_H__ + +struct dirent; +struct uio; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_dir2_put_args; +struct xfs_inode; +struct xfs_trans; + +/* + * Directory version 2. + * There are 4 possible formats: + * shortform + * single block - data with embedded leaf at the end + * multiple data blocks, single leaf+freeindex block + * data blocks, node&leaf blocks (btree), freeindex blocks + * + * The shortform format is in xfs_dir2_sf.h. + * The single block format is in xfs_dir2_block.h. + * The data block format is in xfs_dir2_data.h. + * The leaf and freeindex block formats are in xfs_dir2_leaf.h. + * Node blocks are the same as the other version, in xfs_da_btree.h. + */ + +/* + * Byte offset in data block and shortform entry. + */ +typedef __uint16_t xfs_dir2_data_off_t; +#define NULLDATAOFF 0xffffU +typedef uint xfs_dir2_data_aoff_t; /* argument form */ + +/* + * Directory block number (logical dirblk in file) + */ +typedef __uint32_t xfs_dir2_db_t; + +/* + * Byte offset in a directory. + */ +typedef xfs_off_t xfs_dir2_off_t; + +/* + * For getdents, argument struct for put routines. + */ +typedef int (*xfs_dir2_put_t)(struct xfs_dir2_put_args *pa); +typedef struct xfs_dir2_put_args { + xfs_off_t cook; /* cookie of (next) entry */ + xfs_intino_t ino; /* inode number */ + struct xfs_dirent *dbp; /* buffer pointer */ + char *name; /* directory entry name */ + int namelen; /* length of name */ + int done; /* output: set if value was stored */ + xfs_dir2_put_t put; /* put function ptr (i/o) */ + struct uio *uio; /* uio control structure */ +} xfs_dir2_put_args_t; + +#define XFS_DIR_IS_V2(mp) ((mp)->m_dirversion == 2) +extern xfs_dirops_t xfsv2_dirops; + +/* + * Other interfaces used by the rest of the dir v2 code. + */ +extern int + xfs_dir2_grow_inode(struct xfs_da_args *args, int space, + xfs_dir2_db_t *dbp); + +extern int + xfs_dir2_isblock(struct xfs_trans *tp, struct xfs_inode *dp, int *vp); + +extern int + xfs_dir2_isleaf(struct xfs_trans *tp, struct xfs_inode *dp, int *vp); + +extern int + xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db, + struct xfs_dabuf *bp); + +#endif /* __XFS_DIR2_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_dir2_block.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir2_block.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_dir2_block.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir2_block.h Thu Apr 12 18:30:32 2001 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_BLOCK_H__ +#define __XFS_DIR2_BLOCK_H__ + +/* + * xfs_dir2_block.h + * Directory version 2, single block format structures + */ + +struct dirent; +struct uio; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_dir2_data_hdr; +struct xfs_dir2_leaf_entry; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * The single block format is as follows: + * xfs_dir2_data_hdr_t structure + * xfs_dir2_data_entry_t and xfs_dir2_data_unused_t structures + * xfs_dir2_leaf_entry_t structures + * xfs_dir2_block_tail_t structure + */ + +#define XFS_DIR2_BLOCK_MAGIC 0x58443242 /* XD2B: for one block dirs */ + +typedef struct xfs_dir2_block_tail { + __uint32_t count; /* count of leaf entries */ + __uint32_t stale; /* count of stale lf entries */ +} xfs_dir2_block_tail_t; + +/* + * Generic single-block structure, for xfs_db. + */ +typedef struct xfs_dir2_block { + xfs_dir2_data_hdr_t hdr; /* magic XFS_DIR2_BLOCK_MAGIC */ + xfs_dir2_data_union_t u[1]; + xfs_dir2_leaf_entry_t leaf[1]; + xfs_dir2_block_tail_t tail; +} xfs_dir2_block_t; + +/* + * Pointer to the leaf header embedded in a data block (1-block format) + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BLOCK_TAIL_P) +xfs_dir2_block_tail_t * +xfs_dir2_block_tail_p(struct xfs_mount *mp, xfs_dir2_block_t *block); +#define XFS_DIR2_BLOCK_TAIL_P(mp,block) xfs_dir2_block_tail_p(mp,block) +#else +#define XFS_DIR2_BLOCK_TAIL_P(mp,block) \ + (((xfs_dir2_block_tail_t *)((char *)(block) + (mp)->m_dirblksize)) - 1) +#endif + +/* + * Pointer to the leaf entries embedded in a data block (1-block format) + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BLOCK_LEAF_P) +struct xfs_dir2_leaf_entry *xfs_dir2_block_leaf_p_arch( + xfs_dir2_block_tail_t *btp, xfs_arch_t arch); +#define XFS_DIR2_BLOCK_LEAF_P_ARCH(btp,arch) \ + xfs_dir2_block_leaf_p_arch(btp,arch) +#else +#define XFS_DIR2_BLOCK_LEAF_P_ARCH(btp,arch) \ + (((struct xfs_dir2_leaf_entry *)(btp)) - INT_GET((btp)->count, arch)) +#endif + +/* + * Function declarations. + */ + +extern int + xfs_dir2_block_addname(struct xfs_da_args *args); + +extern int + xfs_dir2_block_getdents(struct xfs_trans *tp, struct xfs_inode *dp, + struct uio *uio, int *eofp, struct xfs_dirent *dbp, + xfs_dir2_put_t put); + +extern int + xfs_dir2_block_lookup(struct xfs_da_args *args); + +extern int + xfs_dir2_block_removename(struct xfs_da_args *args); + +extern int + xfs_dir2_block_replace(struct xfs_da_args *args); + +extern int + xfs_dir2_leaf_to_block(struct xfs_da_args *args, struct xfs_dabuf *lbp, + struct xfs_dabuf *dbp); + +extern int + xfs_dir2_sf_to_block(struct xfs_da_args *args); + +#endif /* __XFS_DIR2_BLOCK_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_dir2_data.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir2_data.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_dir2_data.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir2_data.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_DATA_H__ +#define __XFS_DIR2_DATA_H__ + +/* + * Directory format 2, data block structures. + */ + +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_inode; +struct xfs_trans; + +/* + * Constants. + */ +#define XFS_DIR2_DATA_MAGIC 0x58443244 /* XD2D: for multiblock dirs */ +#define XFS_DIR2_DATA_ALIGN_LOG 3 /* i.e., 8 bytes */ +#define XFS_DIR2_DATA_ALIGN (1 << XFS_DIR2_DATA_ALIGN_LOG) +#define XFS_DIR2_DATA_FREE_TAG 0xffff +#define XFS_DIR2_DATA_FD_COUNT 3 + +/* + * Directory address space divided into sections, + * spaces separated by 32gb. + */ +#define XFS_DIR2_SPACE_SIZE (1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG)) +#define XFS_DIR2_DATA_SPACE 0 +#define XFS_DIR2_DATA_OFFSET (XFS_DIR2_DATA_SPACE * XFS_DIR2_SPACE_SIZE) +#define XFS_DIR2_DATA_FIRSTDB(mp) \ + XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_DATA_OFFSET) + +/* + * Offsets of . and .. in data space (always block 0) + */ +#define XFS_DIR2_DATA_DOT_OFFSET \ + ((xfs_dir2_data_aoff_t)sizeof(xfs_dir2_data_hdr_t)) +#define XFS_DIR2_DATA_DOTDOT_OFFSET \ + (XFS_DIR2_DATA_DOT_OFFSET + XFS_DIR2_DATA_ENTSIZE(1)) +#define XFS_DIR2_DATA_FIRST_OFFSET \ + (XFS_DIR2_DATA_DOTDOT_OFFSET + XFS_DIR2_DATA_ENTSIZE(2)) + +/* + * Structures. + */ + +/* + * Describe a free area in the data block. + * The freespace will be formatted as a xfs_dir2_data_unused_t. + */ +typedef struct xfs_dir2_data_free { + xfs_dir2_data_off_t offset; /* start of freespace */ + xfs_dir2_data_off_t length; /* length of freespace */ +} xfs_dir2_data_free_t; + +/* + * Header for the data blocks. + * Always at the beginning of a directory-sized block. + * The code knows that XFS_DIR2_DATA_FD_COUNT is 3. + */ +typedef struct xfs_dir2_data_hdr { + __uint32_t magic; /* XFS_DIR2_DATA_MAGIC */ + /* or XFS_DIR2_BLOCK_MAGIC */ + xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT]; +} xfs_dir2_data_hdr_t; + +/* + * Active entry in a data block. Aligned to 8 bytes. + * Tag appears as the last 2 bytes. + */ +typedef struct xfs_dir2_data_entry { + xfs_ino_t inumber; /* inode number */ + __uint8_t namelen; /* name length */ + __uint8_t name[1]; /* name bytes, no null */ + /* variable offset */ + xfs_dir2_data_off_t tag; /* starting offset of us */ +} xfs_dir2_data_entry_t; + +/* + * Unused entry in a data block. Aligned to 8 bytes. + * Tag appears as the last 2 bytes. + */ +typedef struct xfs_dir2_data_unused { + __uint16_t freetag; /* XFS_DIR2_DATA_FREE_TAG */ + xfs_dir2_data_off_t length; /* total free length */ + /* variable offset */ + xfs_dir2_data_off_t tag; /* starting offset of us */ +} xfs_dir2_data_unused_t; + +typedef union { + xfs_dir2_data_entry_t entry; + xfs_dir2_data_unused_t unused; +} xfs_dir2_data_union_t; + +/* + * Generic data block structure, for xfs_db. + */ +typedef struct xfs_dir2_data { + xfs_dir2_data_hdr_t hdr; /* magic XFS_DIR2_DATA_MAGIC */ + xfs_dir2_data_union_t u[1]; +} xfs_dir2_data_t; + +/* + * Macros. + */ + +/* + * Size of a data entry. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATA_ENTSIZE) +int xfs_dir2_data_entsize(int n); +#define XFS_DIR2_DATA_ENTSIZE(n) xfs_dir2_data_entsize(n) +#else +#define XFS_DIR2_DATA_ENTSIZE(n) \ + ((int)(roundup(offsetof(xfs_dir2_data_entry_t, name[0]) + (n) + \ + (uint)sizeof(xfs_dir2_data_off_t), XFS_DIR2_DATA_ALIGN))) +#endif + +/* + * Pointer to an entry's tag word. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATA_ENTRY_TAG_P) +xfs_dir2_data_off_t *xfs_dir2_data_entry_tag_p(xfs_dir2_data_entry_t *dep); +#define XFS_DIR2_DATA_ENTRY_TAG_P(dep) xfs_dir2_data_entry_tag_p(dep) +#else +#define XFS_DIR2_DATA_ENTRY_TAG_P(dep) \ + ((xfs_dir2_data_off_t *)\ + ((char *)(dep) + XFS_DIR2_DATA_ENTSIZE((dep)->namelen) - \ + (uint)sizeof(xfs_dir2_data_off_t))) +#endif + +/* + * Pointer to a freespace's tag word. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATA_UNUSED_TAG_P) +xfs_dir2_data_off_t *xfs_dir2_data_unused_tag_p_arch( + xfs_dir2_data_unused_t *dup, xfs_arch_t arch); +#define XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup,arch) \ + xfs_dir2_data_unused_tag_p_arch(dup,arch) +#else +#define XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup,arch) \ + ((xfs_dir2_data_off_t *)\ + ((char *)(dup) + INT_GET((dup)->length, arch) \ + - (uint)sizeof(xfs_dir2_data_off_t))) +#endif + +/* + * Function declarations. + */ + +#ifdef DEBUG +extern void + xfs_dir2_data_check(struct xfs_inode *dp, struct xfs_dabuf *bp); +#else +#define xfs_dir2_data_check(dp,bp) +#endif + +extern xfs_dir2_data_free_t * + xfs_dir2_data_freefind(xfs_dir2_data_t *d, + xfs_dir2_data_unused_t *dup); + +extern xfs_dir2_data_free_t * + xfs_dir2_data_freeinsert(xfs_dir2_data_t *d, + xfs_dir2_data_unused_t *dup, int *loghead); + +extern void + xfs_dir2_data_freeremove(xfs_dir2_data_t *d, + xfs_dir2_data_free_t *dfp, int *loghead); + +extern void + xfs_dir2_data_freescan(struct xfs_mount *mp, xfs_dir2_data_t *d, + int *loghead, char *aendp); + +extern int + xfs_dir2_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno, + struct xfs_dabuf **bpp); + +extern void + xfs_dir2_data_log_entry(struct xfs_trans *tp, struct xfs_dabuf *bp, + xfs_dir2_data_entry_t *dep); + +extern void + xfs_dir2_data_log_header(struct xfs_trans *tp, struct xfs_dabuf *bp); + +extern void + xfs_dir2_data_log_unused(struct xfs_trans *tp, struct xfs_dabuf *bp, + xfs_dir2_data_unused_t *dup); + +extern void + xfs_dir2_data_make_free(struct xfs_trans *tp, struct xfs_dabuf *bp, + xfs_dir2_data_aoff_t offset, + xfs_dir2_data_aoff_t len, int *needlogp, + int *needscanp); + +extern void + xfs_dir2_data_use_free(struct xfs_trans *tp, struct xfs_dabuf *bp, + xfs_dir2_data_unused_t *dup, + xfs_dir2_data_aoff_t offset, + xfs_dir2_data_aoff_t len, int *needlogp, + int *needscanp); + +#endif /* __XFS_DIR2_DATA_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_dir2_leaf.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir2_leaf.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_dir2_leaf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir2_leaf.h Thu Apr 12 18:30:32 2001 @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_LEAF_H__ +#define __XFS_DIR2_LEAF_H__ + +/* + * Directory version 2, leaf block structures. + */ + +struct dirent; +struct uio; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * Constants. + */ + +/* + * Offset of the leaf/node space. First block in this space + * is the btree root. + */ +#define XFS_DIR2_LEAF_SPACE 1 +#define XFS_DIR2_LEAF_OFFSET (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE) +#define XFS_DIR2_LEAF_FIRSTDB(mp) \ + XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_LEAF_OFFSET) + +/* + * Types. + */ + +/* + * Offset in data space of a data entry. + */ +typedef __uint32_t xfs_dir2_dataptr_t; +#define XFS_DIR2_MAX_DATAPTR ((xfs_dir2_dataptr_t)0x7fffffff) +#define XFS_DIR2_NULL_DATAPTR ((xfs_dir2_dataptr_t)0) + +/* + * Structures. + */ + +/* + * Leaf block header. + */ +typedef struct xfs_dir2_leaf_hdr { + xfs_da_blkinfo_t info; /* header for da routines */ + __uint16_t count; /* count of entries */ + __uint16_t stale; /* count of stale entries */ +} xfs_dir2_leaf_hdr_t; + +/* + * Leaf block entry. + */ +typedef struct xfs_dir2_leaf_entry { + xfs_dahash_t hashval; /* hash value of name */ + xfs_dir2_dataptr_t address; /* address of data entry */ +} xfs_dir2_leaf_entry_t; + +/* + * Leaf block tail. + */ +typedef struct xfs_dir2_leaf_tail { + __uint32_t bestcount; +} xfs_dir2_leaf_tail_t; + +/* + * Leaf block. + * bests and tail are at the end of the block for single-leaf only + * (magic = XFS_DIR2_LEAF1_MAGIC not XFS_DIR2_LEAFN_MAGIC). + */ +typedef struct xfs_dir2_leaf { + xfs_dir2_leaf_hdr_t hdr; /* leaf header */ + xfs_dir2_leaf_entry_t ents[1]; /* entries */ + /* ... */ + xfs_dir2_data_off_t bests[1]; /* best free counts */ + xfs_dir2_leaf_tail_t tail; /* leaf tail */ +} xfs_dir2_leaf_t; + +/* + * Macros. + * The DB blocks are logical directory block numbers, not filesystem blocks. + */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_MAX_LEAF_ENTS) +int +xfs_dir2_max_leaf_ents(struct xfs_mount *mp); +#define XFS_DIR2_MAX_LEAF_ENTS(mp) \ + xfs_dir2_max_leaf_ents(mp) +#else +#define XFS_DIR2_MAX_LEAF_ENTS(mp) \ + ((int)(((mp)->m_dirblksize - (uint)sizeof(xfs_dir2_leaf_hdr_t)) / \ + (uint)sizeof(xfs_dir2_leaf_entry_t))) +#endif + +/* + * Get address of the bestcount field in the single-leaf block. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_LEAF_TAIL_P) +xfs_dir2_leaf_tail_t * +xfs_dir2_leaf_tail_p(struct xfs_mount *mp, xfs_dir2_leaf_t *lp); +#define XFS_DIR2_LEAF_TAIL_P(mp,lp) \ + xfs_dir2_leaf_tail_p(mp, lp) +#else +#define XFS_DIR2_LEAF_TAIL_P(mp,lp) \ + ((xfs_dir2_leaf_tail_t *)\ + ((char *)(lp) + (mp)->m_dirblksize - \ + (uint)sizeof(xfs_dir2_leaf_tail_t))) +#endif + +/* + * Get address of the bests array in the single-leaf block. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_LEAF_BESTS_P) +xfs_dir2_data_off_t * +xfs_dir2_leaf_bests_p_arch(xfs_dir2_leaf_tail_t *ltp, xfs_arch_t arch); +#define XFS_DIR2_LEAF_BESTS_P_ARCH(ltp,arch) xfs_dir2_leaf_bests_p_arch(ltp,arch) +#else +#define XFS_DIR2_LEAF_BESTS_P_ARCH(ltp,arch) \ + ((xfs_dir2_data_off_t *)(ltp) - INT_GET((ltp)->bestcount, arch)) +#endif + +/* + * Convert dataptr to byte in file space + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATAPTR_TO_BYTE) +xfs_dir2_off_t +xfs_dir2_dataptr_to_byte(struct xfs_mount *mp, xfs_dir2_dataptr_t dp); +#define XFS_DIR2_DATAPTR_TO_BYTE(mp,dp) xfs_dir2_dataptr_to_byte(mp, dp) +#else +#define XFS_DIR2_DATAPTR_TO_BYTE(mp,dp) \ + ((xfs_dir2_off_t)(dp) << XFS_DIR2_DATA_ALIGN_LOG) +#endif + +/* + * Convert byte in file space to dataptr. It had better be aligned. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BYTE_TO_DATAPTR) +xfs_dir2_dataptr_t +xfs_dir2_byte_to_dataptr(struct xfs_mount *mp, xfs_dir2_off_t by); +#define XFS_DIR2_BYTE_TO_DATAPTR(mp,by) xfs_dir2_byte_to_dataptr(mp,by) +#else +#define XFS_DIR2_BYTE_TO_DATAPTR(mp,by) \ + ((xfs_dir2_dataptr_t)((by) >> XFS_DIR2_DATA_ALIGN_LOG)) +#endif + +/* + * Convert dataptr to a block number + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATAPTR_TO_DB) +xfs_dir2_db_t +xfs_dir2_dataptr_to_db(struct xfs_mount *mp, xfs_dir2_dataptr_t dp); +#define XFS_DIR2_DATAPTR_TO_DB(mp,dp) xfs_dir2_dataptr_to_db(mp, dp) +#else +#define XFS_DIR2_DATAPTR_TO_DB(mp,dp) \ + XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_DATAPTR_TO_BYTE(mp, dp)) +#endif + +/* + * Convert dataptr to a byte offset in a block + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATAPTR_TO_OFF) +xfs_dir2_data_aoff_t +xfs_dir2_dataptr_to_off(struct xfs_mount *mp, xfs_dir2_dataptr_t dp); +#define XFS_DIR2_DATAPTR_TO_OFF(mp,dp) xfs_dir2_dataptr_to_off(mp, dp) +#else +#define XFS_DIR2_DATAPTR_TO_OFF(mp,dp) \ + XFS_DIR2_BYTE_TO_OFF(mp, XFS_DIR2_DATAPTR_TO_BYTE(mp, dp)) +#endif + +/* + * Convert block and offset to byte in space + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DB_OFF_TO_BYTE) +xfs_dir2_off_t +xfs_dir2_db_off_to_byte(struct xfs_mount *mp, xfs_dir2_db_t db, + xfs_dir2_data_aoff_t o); +#define XFS_DIR2_DB_OFF_TO_BYTE(mp,db,o) \ + xfs_dir2_db_off_to_byte(mp, db, o) +#else +#define XFS_DIR2_DB_OFF_TO_BYTE(mp,db,o) \ + (((xfs_dir2_off_t)(db) << \ + ((mp)->m_sb.sb_blocklog + (mp)->m_sb.sb_dirblklog)) + (o)) +#endif + +/* + * Convert byte in space to (DB) block + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BYTE_TO_DB) +xfs_dir2_db_t xfs_dir2_byte_to_db(struct xfs_mount *mp, xfs_dir2_off_t by); +#define XFS_DIR2_BYTE_TO_DB(mp,by) xfs_dir2_byte_to_db(mp, by) +#else +#define XFS_DIR2_BYTE_TO_DB(mp,by) \ + ((xfs_dir2_db_t)((by) >> \ + ((mp)->m_sb.sb_blocklog + (mp)->m_sb.sb_dirblklog))) +#endif + +/* + * Convert byte in space to (DA) block + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BYTE_TO_DA) +xfs_dablk_t xfs_dir2_byte_to_da(struct xfs_mount *mp, xfs_dir2_off_t by); +#define XFS_DIR2_BYTE_TO_DA(mp,by) xfs_dir2_byte_to_da(mp, by) +#else +#define XFS_DIR2_BYTE_TO_DA(mp,by) \ + XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_BYTE_TO_DB(mp, by)) +#endif + +/* + * Convert byte in space to offset in a block + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BYTE_TO_OFF) +xfs_dir2_data_aoff_t +xfs_dir2_byte_to_off(struct xfs_mount *mp, xfs_dir2_off_t by); +#define XFS_DIR2_BYTE_TO_OFF(mp,by) xfs_dir2_byte_to_off(mp, by) +#else +#define XFS_DIR2_BYTE_TO_OFF(mp,by) \ + ((xfs_dir2_data_aoff_t)((by) & \ + ((1 << ((mp)->m_sb.sb_blocklog + \ + (mp)->m_sb.sb_dirblklog)) - 1))) +#endif + +/* + * Convert block and offset to dataptr + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DB_OFF_TO_DATAPTR) +xfs_dir2_dataptr_t +xfs_dir2_db_off_to_dataptr(struct xfs_mount *mp, xfs_dir2_db_t db, + xfs_dir2_data_aoff_t o); +#define XFS_DIR2_DB_OFF_TO_DATAPTR(mp,db,o) \ + xfs_dir2_db_off_to_dataptr(mp, db, o) +#else +#define XFS_DIR2_DB_OFF_TO_DATAPTR(mp,db,o) \ + XFS_DIR2_BYTE_TO_DATAPTR(mp, XFS_DIR2_DB_OFF_TO_BYTE(mp, db, o)) +#endif + +/* + * Convert block (DB) to block (dablk) + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DB_TO_DA) +xfs_dablk_t xfs_dir2_db_to_da(struct xfs_mount *mp, xfs_dir2_db_t db); +#define XFS_DIR2_DB_TO_DA(mp,db) xfs_dir2_db_to_da(mp, db) +#else +#define XFS_DIR2_DB_TO_DA(mp,db) \ + ((xfs_dablk_t)((db) << (mp)->m_sb.sb_dirblklog)) +#endif + +/* + * Convert block (dablk) to block (DB) + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DA_TO_DB) +xfs_dir2_db_t xfs_dir2_da_to_db(struct xfs_mount *mp, xfs_dablk_t da); +#define XFS_DIR2_DA_TO_DB(mp,da) xfs_dir2_da_to_db(mp, da) +#else +#define XFS_DIR2_DA_TO_DB(mp,da) \ + ((xfs_dir2_db_t)((da) >> (mp)->m_sb.sb_dirblklog)) +#endif + +/* + * Convert block (dablk) to byte offset in space + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DA_TO_BYTE) +xfs_dir2_off_t xfs_dir2_da_to_byte(struct xfs_mount *mp, xfs_dablk_t da); +#define XFS_DIR2_DA_TO_BYTE(mp,da) xfs_dir2_da_to_byte(mp, da) +#else +#define XFS_DIR2_DA_TO_BYTE(mp,da) \ + XFS_DIR2_DB_OFF_TO_BYTE(mp, XFS_DIR2_DA_TO_DB(mp, da), 0) +#endif + +/* + * Function declarations. + */ + +extern int + xfs_dir2_block_to_leaf(struct xfs_da_args *args, struct xfs_dabuf *dbp); + +extern int + xfs_dir2_leaf_addname(struct xfs_da_args *args); + +extern void + xfs_dir2_leaf_compact(struct xfs_da_args *args, struct xfs_dabuf *bp); + +extern void + xfs_dir2_leaf_compact_x1(struct xfs_dabuf *bp, int *indexp, + int *lowstalep, int *highstalep, int *lowlogp, + int *highlogp); + +extern int + xfs_dir2_leaf_getdents(struct xfs_trans *tp, struct xfs_inode *dp, + struct uio *uio, int *eofp, struct xfs_dirent *dbp, + xfs_dir2_put_t put); + +extern int + xfs_dir2_leaf_init(struct xfs_da_args *args, xfs_dir2_db_t bno, + struct xfs_dabuf **bpp, int magic); + +extern void + xfs_dir2_leaf_log_ents(struct xfs_trans *tp, struct xfs_dabuf *bp, + int first, int last); + +extern void + xfs_dir2_leaf_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp, + int first, int last); + +extern void + xfs_dir2_leaf_log_header(struct xfs_trans *tp, struct xfs_dabuf *bp); + +extern void + xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_dabuf *bp); + +extern int + xfs_dir2_leaf_lookup(struct xfs_da_args *args); + +extern int + xfs_dir2_leaf_removename(struct xfs_da_args *args); + +extern int + xfs_dir2_leaf_replace(struct xfs_da_args *args); + +extern int + xfs_dir2_leaf_search_hash(struct xfs_da_args *args, + struct xfs_dabuf *lbp); +extern int + xfs_dir2_leaf_trim_data(struct xfs_da_args *args, struct xfs_dabuf *lbp, xfs_dir2_db_t db); + +extern int + xfs_dir2_node_to_leaf(struct xfs_da_state *state); + +#endif /* __XFS_DIR2_LEAF_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_dir2_node.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir2_node.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_dir2_node.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir2_node.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_NODE_H__ +#define __XFS_DIR2_NODE_H__ + +/* + * Directory version 2, btree node format structures + */ + +struct dirent; +struct uio; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_da_state; +struct xfs_da_state_blk; +struct xfs_inode; +struct xfs_trans; + +/* + * Constants. + */ + +/* + * Offset of the freespace index. + */ +#define XFS_DIR2_FREE_SPACE 2 +#define XFS_DIR2_FREE_OFFSET (XFS_DIR2_FREE_SPACE * XFS_DIR2_SPACE_SIZE) +#define XFS_DIR2_FREE_FIRSTDB(mp) \ + XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_FREE_OFFSET) + +#define XFS_DIR2_FREE_MAGIC 0x58443246 /* XD2F */ + +/* + * Structures. + */ +typedef struct xfs_dir2_free_hdr { + __uint32_t magic; /* XFS_DIR2_FREE_MAGIC */ + __int32_t firstdb; /* db of first entry */ + __int32_t nvalid; /* count of valid entries */ + __int32_t nused; /* count of used entries */ +} xfs_dir2_free_hdr_t; + +typedef struct xfs_dir2_free { + xfs_dir2_free_hdr_t hdr; /* block header */ + xfs_dir2_data_off_t bests[1]; /* best free counts */ + /* unused entries are -1 */ +} xfs_dir2_free_t; +#define XFS_DIR2_MAX_FREE_BESTS(mp) \ + (((mp)->m_dirblksize - (uint)sizeof(xfs_dir2_free_hdr_t)) / \ + (uint)sizeof(xfs_dir2_data_off_t)) + +/* + * Macros. + */ + +/* + * Convert data space db to the corresponding free db. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DB_TO_FDB) +xfs_dir2_db_t +xfs_dir2_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db); +#define XFS_DIR2_DB_TO_FDB(mp,db) xfs_dir2_db_to_fdb(mp, db) +#else +#define XFS_DIR2_DB_TO_FDB(mp,db) \ + (XFS_DIR2_FREE_FIRSTDB(mp) + (db) / XFS_DIR2_MAX_FREE_BESTS(mp)) +#endif + +/* + * Convert data space db to the corresponding index in a free db. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DB_TO_FDINDEX) +int +xfs_dir2_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db); +#define XFS_DIR2_DB_TO_FDINDEX(mp,db) xfs_dir2_db_to_fdindex(mp, db) +#else +#define XFS_DIR2_DB_TO_FDINDEX(mp,db) ((db) % XFS_DIR2_MAX_FREE_BESTS(mp)) +#endif + +/* + * Functions. + */ + +extern void + xfs_dir2_free_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp, + int first, int last); + +extern int + xfs_dir2_leaf_to_node(struct xfs_da_args *args, struct xfs_dabuf *lbp); + +extern xfs_dahash_t + xfs_dir2_leafn_lasthash(struct xfs_dabuf *bp, int *count); + +extern int + xfs_dir2_leafn_lookup_int(struct xfs_dabuf *bp, + struct xfs_da_args *args, int *indexp, + struct xfs_da_state *state); + +extern int + xfs_dir2_leafn_order(struct xfs_dabuf *leaf1_bp, + struct xfs_dabuf *leaf2_bp); + +extern int + xfs_dir2_leafn_split(struct xfs_da_state *state, + struct xfs_da_state_blk *oldblk, + struct xfs_da_state_blk *newblk); + +extern int + xfs_dir2_leafn_toosmall(struct xfs_da_state *state, int *action); + +extern void + xfs_dir2_leafn_unbalance(struct xfs_da_state *state, + struct xfs_da_state_blk *drop_blk, + struct xfs_da_state_blk *save_blk); + +extern int + xfs_dir2_node_addname(struct xfs_da_args *args); + +extern int + xfs_dir2_node_lookup(struct xfs_da_args *args); + +extern int + xfs_dir2_node_removename(struct xfs_da_args *args); + +extern int + xfs_dir2_node_replace(struct xfs_da_args *args); + +extern int + xfs_dir2_node_trim_free(struct xfs_da_args *args, xfs_fileoff_t fo, + int *rvalp); + +#endif /* __XFS_DIR2_NODE_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_dir2_sf.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir2_sf.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_dir2_sf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir2_sf.h Thu Apr 12 18:30:32 2001 @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_SF_H__ +#define __XFS_DIR2_SF_H__ + +/* + * Directory layout when stored internal to an inode. + * + * Small directories are packed as tightly as possible so as to + * fit into the literal area of the inode. + */ + +struct dirent; +struct uio; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_dir2_block; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * Maximum size of a shortform directory. + */ +#define XFS_DIR2_SF_MAX_SIZE \ + (XFS_DINODE_MAX_SIZE - (uint)sizeof(xfs_dinode_core_t) - \ + (uint)sizeof(xfs_agino_t)) + +/* + * Inode number stored as 8 8-bit values. + */ +typedef struct { __uint8_t i[8]; } xfs_dir2_ino8_t; + +#define XFS_DIR2_SF_GET_INO8_ARCH(di,arch) \ + (xfs_ino_t)(DIRINO_GET_ARCH(&di,arch)) +#define XFS_DIR2_SF_GET_INO8(di) \ + XFS_DIR2_SF_GET_INO8_ARCH(di,ARCH_NOCONVERT) + +/* + * Inode number stored as 4 8-bit values. + * Works a lot of the time, when all the inode numbers in a directory + * fit in 32 bits. + */ +typedef struct { __uint8_t i[4]; } xfs_dir2_ino4_t; +#define XFS_DIR2_SF_GET_INO4_ARCH(di,arch) \ + (xfs_ino_t)(DIRINO4_GET_ARCH(&di,arch)) +#define XFS_DIR2_SF_GET_INO4(di) \ + XFS_DIR2_SF_GET_INO4_ARCH(di,ARCH_NOCONVERT) + +typedef union { + xfs_dir2_ino8_t i8; + xfs_dir2_ino4_t i4; +} xfs_dir2_inou_t; +#define XFS_DIR2_MAX_SHORT_INUM ((xfs_ino_t)0xffffffffULL) + +/* + * Normalized offset (in a data block) of the entry, really xfs_dir2_data_off_t. + * Only need 16 bits, this is the byte offset into the single block form. + */ +typedef struct { __uint8_t i[2]; } xfs_dir2_sf_off_t; + +/* + * The parent directory has a dedicated field, and the self-pointer must + * be calculated on the fly. + * + * Entries are packed toward the top as tightly as possible. The header + * and the elements must be bcopy()'d out into a work area to get correct + * alignment for the inode number fields. + */ +typedef struct xfs_dir2_sf_hdr { + __uint8_t count; /* count of entries */ + __uint8_t i8count; /* count of 8-byte inode #s */ + xfs_dir2_inou_t parent; /* parent dir inode number */ +} xfs_dir2_sf_hdr_t; + +typedef struct xfs_dir2_sf_entry { + __uint8_t namelen; /* actual name length */ + xfs_dir2_sf_off_t offset; /* saved offset */ + __uint8_t name[1]; /* name, variable size */ + xfs_dir2_inou_t inumber; /* inode number, var. offset */ +} xfs_dir2_sf_entry_t; + +typedef struct xfs_dir2_sf { + xfs_dir2_sf_hdr_t hdr; /* shortform header */ + xfs_dir2_sf_entry_t list[1]; /* shortform entries */ +} xfs_dir2_sf_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_HDR_SIZE) +int xfs_dir2_sf_hdr_size(int i8count); +#define XFS_DIR2_SF_HDR_SIZE(i8count) xfs_dir2_sf_hdr_size(i8count) +#else +#define XFS_DIR2_SF_HDR_SIZE(i8count) \ + ((uint)sizeof(xfs_dir2_sf_hdr_t) - \ + ((i8count) == 0) * \ + ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_INUMBERP) +xfs_dir2_inou_t *xfs_dir2_sf_inumberp(xfs_dir2_sf_entry_t *sfep); +#define XFS_DIR2_SF_INUMBERP(sfep) xfs_dir2_sf_inumberp(sfep) +#else +#define XFS_DIR2_SF_INUMBERP(sfep) \ + ((xfs_dir2_inou_t *)&(sfep)->name[(sfep)->namelen]) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_GET_INUMBER) +xfs_intino_t xfs_dir2_sf_get_inumber_arch(xfs_dir2_sf_t *sfp, xfs_dir2_inou_t *from, + xfs_arch_t arch); +#define XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, from, arch) \ + xfs_dir2_sf_get_inumber_arch(sfp, from, arch) + +#else +#define XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, from, arch) \ + ((sfp)->hdr.i8count == 0 ? \ + (xfs_intino_t)XFS_DIR2_SF_GET_INO4_ARCH(*(from), arch) : \ + (xfs_intino_t)XFS_DIR2_SF_GET_INO8_ARCH(*(from), arch)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_PUT_INUMBER) +void xfs_dir2_sf_put_inumber_arch(xfs_dir2_sf_t *sfp, xfs_ino_t *from, + xfs_dir2_inou_t *to, xfs_arch_t arch); +#define XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp,from,to,arch) \ + xfs_dir2_sf_put_inumber_arch(sfp,from,to,arch) +#else +#define XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp,from,to,arch) \ + if ((sfp)->hdr.i8count == 0) { \ + DIRINO4_COPY_ARCH(from,to,arch); \ + } else { \ + DIRINO_COPY_ARCH(from,to,arch); \ + } +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_GET_OFFSET) +xfs_dir2_data_aoff_t xfs_dir2_sf_get_offset_arch(xfs_dir2_sf_entry_t *sfep, + xfs_arch_t arch); +xfs_dir2_data_aoff_t xfs_dir2_sf_get_offset(xfs_dir2_sf_entry_t *sfep); +#define XFS_DIR2_SF_GET_OFFSET_ARCH(sfep,arch) \ + xfs_dir2_sf_get_offset_arch(sfep,arch) +#else +#define XFS_DIR2_SF_GET_OFFSET_ARCH(sfep,arch) \ + INT_GET_UNALIGNED_16_ARCH(&(sfep)->offset.i,arch) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_PUT_OFFSET) +void xfs_dir2_sf_put_offset_arch(xfs_dir2_sf_entry_t *sfep, + xfs_dir2_data_aoff_t off, xfs_arch_t arch); +#define XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep,off,arch) \ + xfs_dir2_sf_put_offset_arch(sfep,off,arch) +#else +#define XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep,off,arch) \ + INT_SET_UNALIGNED_16_ARCH(&(sfep)->offset.i,off,arch) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_ENTSIZE_BYNAME) +int xfs_dir2_sf_entsize_byname(xfs_dir2_sf_t *sfp, int len); +#define XFS_DIR2_SF_ENTSIZE_BYNAME(sfp,len) \ + xfs_dir2_sf_entsize_byname(sfp,len) +#else +#define XFS_DIR2_SF_ENTSIZE_BYNAME(sfp,len) /* space a name uses */ \ + ((uint)sizeof(xfs_dir2_sf_entry_t) - 1 + (len) - \ + ((sfp)->hdr.i8count == 0) * \ + ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_ENTSIZE_BYENTRY) +int xfs_dir2_sf_entsize_byentry(xfs_dir2_sf_t *sfp, xfs_dir2_sf_entry_t *sfep); +#define XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp,sfep) \ + xfs_dir2_sf_entsize_byentry(sfp,sfep) +#else +#define XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp,sfep) /* space an entry uses */ \ + ((uint)sizeof(xfs_dir2_sf_entry_t) - 1 + (sfep)->namelen - \ + ((sfp)->hdr.i8count == 0) * \ + ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_FIRSTENTRY) +xfs_dir2_sf_entry_t *xfs_dir2_sf_firstentry(xfs_dir2_sf_t *sfp); +#define XFS_DIR2_SF_FIRSTENTRY(sfp) xfs_dir2_sf_firstentry(sfp) +#else +#define XFS_DIR2_SF_FIRSTENTRY(sfp) /* first entry in struct */ \ + ((xfs_dir2_sf_entry_t *) \ + ((char *)(sfp) + XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_NEXTENTRY) +xfs_dir2_sf_entry_t *xfs_dir2_sf_nextentry(xfs_dir2_sf_t *sfp, + xfs_dir2_sf_entry_t *sfep); +#define XFS_DIR2_SF_NEXTENTRY(sfp,sfep) xfs_dir2_sf_nextentry(sfp,sfep) +#else +#define XFS_DIR2_SF_NEXTENTRY(sfp,sfep) /* next entry in struct */ \ + ((xfs_dir2_sf_entry_t *) \ + ((char *)(sfep) + XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp,sfep))) +#endif + +/* + * Functions. + */ + +extern int + xfs_dir2_block_sfsize(struct xfs_inode *dp, + struct xfs_dir2_block *block, + xfs_dir2_sf_hdr_t *sfhp); + +extern int + xfs_dir2_block_to_sf(struct xfs_da_args *args, struct xfs_dabuf *bp, + int size, xfs_dir2_sf_hdr_t *sfhp); + +extern int + xfs_dir2_sf_addname(struct xfs_da_args *args); + +extern int + xfs_dir2_sf_create(struct xfs_da_args *args, xfs_ino_t pino); + +extern int + xfs_dir2_sf_getdents(struct xfs_inode *dp, struct uio *uio, int *eofp, + struct xfs_dirent *dbp, xfs_dir2_put_t put); + +extern int + xfs_dir2_sf_lookup(struct xfs_da_args *args); + +extern int + xfs_dir2_sf_removename(struct xfs_da_args *args); + +extern int + xfs_dir2_sf_replace(struct xfs_da_args *args); + +#endif /* __XFS_DIR2_SF_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_dir_leaf.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir_leaf.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_dir_leaf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir_leaf.h Thu Apr 12 18:30:32 2001 @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR_LEAF_H__ +#define __XFS_DIR_LEAF_H__ + +/* + * Directory layout, internal structure, access macros, etc. + * + * Large directories are structured around Btrees where all the data + * elements are in the leaf nodes. Filenames are hashed into an int, + * then that int is used as the index into the Btree. Since the hashval + * of a filename may not be unique, we may have duplicate keys. The + * internal links in the Btree are logical block offsets into the file. + */ + +struct dirent; +struct uio; +struct xfs_bmap_free; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_da_state; +struct xfs_da_state_blk; +struct xfs_dir_put_args; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/*======================================================================== + * Directory Structure when equal to XFS_LBSIZE(mp) bytes. + *========================================================================*/ + +/* + * This is the structure of the leaf nodes in the Btree. + * + * Struct leaf_entry's are packed from the top. Names grow from the bottom + * but are not packed. The freemap contains run-length-encoded entries + * for the free bytes after the leaf_entry's, but only the N largest such, + * smaller runs are dropped. When the freemap doesn't show enough space + * for an allocation, we compact the namelist area and try again. If we + * still don't have enough space, then we have to split the block. + * + * Since we have duplicate hash keys, for each key that matches, compare + * the actual string. The root and intermediate node search always takes + * the first-in-the-block key match found, so we should only have to work + * "forw"ard. If none matches, continue with the "forw"ard leaf nodes + * until the hash key changes or the filename is found. + * + * The parent directory and the self-pointer are explicitly represented + * (ie: there are entries for "." and ".."). + * + * Note that the count being a __uint16_t limits us to something like a + * blocksize of 1.3MB in the face of worst case (short) filenames. + */ +#define XFS_DIR_LEAF_MAPSIZE 3 /* how many freespace slots */ + +typedef struct xfs_dir_leafblock { + struct xfs_dir_leaf_hdr { /* constant-structure header block */ + xfs_da_blkinfo_t info; /* block type, links, etc. */ + __uint16_t count; /* count of active leaf_entry's */ + __uint16_t namebytes; /* num bytes of name strings stored */ + __uint16_t firstused; /* first used byte in name area */ + __uint8_t holes; /* != 0 if blk needs compaction */ + __uint8_t pad1; + struct xfs_dir_leaf_map {/* RLE map of free bytes */ + __uint16_t base; /* base of free region */ + __uint16_t size; /* run length of free region */ + } freemap[XFS_DIR_LEAF_MAPSIZE]; /* N largest free regions */ + } hdr; + struct xfs_dir_leaf_entry { /* sorted on key, not name */ + xfs_dahash_t hashval; /* hash value of name */ + __uint16_t nameidx; /* index into buffer of name */ + __uint8_t namelen; /* length of name string */ + __uint8_t pad2; + } entries[1]; /* var sized array */ + struct xfs_dir_leaf_name { + xfs_dir_ino_t inumber; /* inode number for this key */ + __uint8_t name[1]; /* name string itself */ + } namelist[1]; /* grows from bottom of buf */ +} xfs_dir_leafblock_t; +typedef struct xfs_dir_leaf_hdr xfs_dir_leaf_hdr_t; +typedef struct xfs_dir_leaf_map xfs_dir_leaf_map_t; +typedef struct xfs_dir_leaf_entry xfs_dir_leaf_entry_t; +typedef struct xfs_dir_leaf_name xfs_dir_leaf_name_t; + +/* + * Length of name for which a 512-byte block filesystem + * can get a double split. + */ +#define XFS_DIR_LEAF_CAN_DOUBLE_SPLIT_LEN \ + (512 - (uint)sizeof(xfs_dir_leaf_hdr_t) - \ + (uint)sizeof(xfs_dir_leaf_entry_t) * 2 - \ + (uint)sizeof(xfs_dir_leaf_name_t) * 2 - (MAXNAMELEN - 2) + 1 + 1) + +typedef int (*xfs_dir_put_t)(struct xfs_dir_put_args *pa); + +typedef union { + xfs_off_t o; /* offset (cookie) */ + /* + * Watch the order here (endian-ness dependent). + */ + struct { +#if __BYTE_ORDER == __LITTLE_ENDIAN + xfs_dahash_t h; /* hash value */ + __uint32_t be; /* block and entry */ +#else /* __BYTE_ORDER == __BIG_ENDIAN */ + __uint32_t be; /* block and entry */ + xfs_dahash_t h; /* hash value */ +#endif /* __BYTE_ORDER == __BIG_ENDIAN */ + } s; +} xfs_dircook_t; + +#define XFS_PUT_COOKIE(c,mp,bno,entry,hash) \ + ((c).s.be = XFS_DA_MAKE_BNOENTRY(mp, bno, entry), (c).s.h = (hash)) + +#define XFS_GET_DIR_INO_ARCH(mp,di,arch) \ + DIRINO_GET_ARCH(&(di),arch) +#define XFS_GET_DIR_INO(mp,di) \ + XFS_GET_DIR_INO_ARCH(mp,di,ARCH_NOCONVERT) + +typedef struct xfs_dir_put_args +{ + xfs_dircook_t cook; /* cookie of (next) entry */ + xfs_intino_t ino; /* inode number */ + struct xfs_dirent *dbp; /* buffer pointer */ + char *name; /* directory entry name */ + int namelen; /* length of name */ + int done; /* output: set if value was stored */ + xfs_dir_put_t put; /* put function ptr (i/o) */ + struct uio *uio; /* uio control structure */ +} xfs_dir_put_args_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_LEAF_ENTSIZE_BYNAME) +int xfs_dir_leaf_entsize_byname(int len); +#define XFS_DIR_LEAF_ENTSIZE_BYNAME(len) xfs_dir_leaf_entsize_byname(len) +#else +#define XFS_DIR_LEAF_ENTSIZE_BYNAME(len) /* space a name will use */ \ + ((uint)sizeof(xfs_dir_leaf_name_t)-1 + len) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_LEAF_ENTSIZE_BYENTRY) +int xfs_dir_leaf_entsize_byentry(xfs_dir_leaf_entry_t *entry); +#define XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry) \ + xfs_dir_leaf_entsize_byentry(entry) +#else +#define XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry) /* space an entry will use */ \ + ((uint)sizeof(xfs_dir_leaf_name_t)-1 + (entry)->namelen) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_LEAF_NAMESTRUCT) +xfs_dir_leaf_name_t * +xfs_dir_leaf_namestruct(xfs_dir_leafblock_t *leafp, int offset); +#define XFS_DIR_LEAF_NAMESTRUCT(leafp,offset) \ + xfs_dir_leaf_namestruct(leafp,offset) +#else +#define XFS_DIR_LEAF_NAMESTRUCT(leafp,offset) /* point to name struct */ \ + ((xfs_dir_leaf_name_t *)&((char *)(leafp))[offset]) +#endif + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Internal routines when dirsize < XFS_LITINO(mp). + */ +int xfs_dir_shortform_create(struct xfs_da_args *args, xfs_ino_t parent); +int xfs_dir_shortform_addname(struct xfs_da_args *args); +int xfs_dir_shortform_lookup(struct xfs_da_args *args); +int xfs_dir_shortform_to_leaf(struct xfs_da_args *args); +int xfs_dir_shortform_removename(struct xfs_da_args *args); +int xfs_dir_shortform_getdents(struct xfs_inode *dp, struct uio *uio, int *eofp, + struct xfs_dirent *dbp, xfs_dir_put_t put); +int xfs_dir_shortform_replace(struct xfs_da_args *args); + +/* + * Internal routines when dirsize == XFS_LBSIZE(mp). + */ +int xfs_dir_leaf_to_node(struct xfs_da_args *args); +int xfs_dir_leaf_to_shortform(struct xfs_da_args *args); + +/* + * Routines used for growing the Btree. + */ +int xfs_dir_leaf_create(struct xfs_da_args *args, xfs_dablk_t which_block, + struct xfs_dabuf **bpp); +int xfs_dir_leaf_split(struct xfs_da_state *state, + struct xfs_da_state_blk *oldblk, + struct xfs_da_state_blk *newblk); +int xfs_dir_leaf_add(struct xfs_dabuf *leaf_buffer, + struct xfs_da_args *args, int insertion_index); +int xfs_dir_leaf_addname(struct xfs_da_args *args); +int xfs_dir_leaf_lookup_int(struct xfs_dabuf *leaf_buffer, + struct xfs_da_args *args, + int *index_found_at); +int xfs_dir_leaf_remove(struct xfs_trans *trans, + struct xfs_dabuf *leaf_buffer, + int index_to_remove); +int xfs_dir_leaf_getdents_int(struct xfs_dabuf *bp, struct xfs_inode *dp, + xfs_dablk_t bno, struct uio *uio, + int *eobp, struct xfs_dirent *dbp, + xfs_dir_put_t put, xfs_daddr_t nextda); + +/* + * Routines used for shrinking the Btree. + */ +int xfs_dir_leaf_toosmall(struct xfs_da_state *state, int *retval); +void xfs_dir_leaf_unbalance(struct xfs_da_state *state, + struct xfs_da_state_blk *drop_blk, + struct xfs_da_state_blk *save_blk); + +/* + * Utility routines. + */ +uint xfs_dir_leaf_lasthash(struct xfs_dabuf *bp, int *count); +int xfs_dir_leaf_order(struct xfs_dabuf *leaf1_bp, + struct xfs_dabuf *leaf2_bp); +int xfs_dir_put_dirent32_direct(xfs_dir_put_args_t *pa); +int xfs_dir_put_dirent32_uio(xfs_dir_put_args_t *pa); +int xfs_dir_put_dirent64_direct(xfs_dir_put_args_t *pa); +int xfs_dir_put_dirent64_uio(xfs_dir_put_args_t *pa); +int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino); + + +/* + * Global data. + */ +extern xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot; + +#endif /* __XFS_DIR_LEAF_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_dir_sf.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir_sf.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_dir_sf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_dir_sf.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR_SF_H__ +#define __XFS_DIR_SF_H__ + +/* + * Directory layout when stored internal to an inode. + * + * Small directories are packed as tightly as possible so as to + * fit into the literal area of the inode. + */ + +typedef struct { __uint8_t i[sizeof(xfs_ino_t)]; } xfs_dir_ino_t; + +/* + * The parent directory has a dedicated field, and the self-pointer must + * be calculated on the fly. + * + * Entries are packed toward the top as tight as possible. The header + * and the elements much be bcopy()'d out into a work area to get correct + * alignment for the inode number fields. + */ +typedef struct xfs_dir_shortform { + struct xfs_dir_sf_hdr { /* constant-structure header block */ + xfs_dir_ino_t parent; /* parent dir inode number */ + __uint8_t count; /* count of active entries */ + } hdr; + struct xfs_dir_sf_entry { + xfs_dir_ino_t inumber; /* referenced inode number */ + __uint8_t namelen; /* actual length of name (no NULL) */ + __uint8_t name[1]; /* name */ + } list[1]; /* variable sized array */ +} xfs_dir_shortform_t; +typedef struct xfs_dir_sf_hdr xfs_dir_sf_hdr_t; +typedef struct xfs_dir_sf_entry xfs_dir_sf_entry_t; + +/* + * We generate this then sort it, so that readdirs are returned in + * hash-order. Else seekdir won't work. + */ +typedef struct xfs_dir_sf_sort { + __uint8_t entno; /* .=0, ..=1, else entry# + 2 */ + __uint8_t seqno; /* sequence # with same hash value */ + __uint8_t namelen; /* length of name value (no null) */ + xfs_dahash_t hash; /* this entry's hash value */ + xfs_intino_t ino; /* this entry's inode number */ + char *name; /* name value, pointer into buffer */ +} xfs_dir_sf_sort_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_GET_DIRINO) +void xfs_dir_sf_get_dirino_arch(xfs_dir_ino_t *from, xfs_ino_t *to, xfs_arch_t arch); +void xfs_dir_sf_get_dirino(xfs_dir_ino_t *from, xfs_ino_t *to); +#define XFS_DIR_SF_GET_DIRINO_ARCH(from,to,arch) xfs_dir_sf_get_dirino_arch(from, to, arch) +#define XFS_DIR_SF_GET_DIRINO(from,to) xfs_dir_sf_get_dirino(from, to) +#else +#define XFS_DIR_SF_GET_DIRINO_ARCH(from,to,arch) DIRINO_COPY_ARCH(from,to,arch) +#define XFS_DIR_SF_GET_DIRINO(from,to) DIRINO_COPY_ARCH(from,to,ARCH_NOCONVERT) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_PUT_DIRINO) +void xfs_dir_sf_put_dirino_arch(xfs_ino_t *from, xfs_dir_ino_t *to, xfs_arch_t arch); +void xfs_dir_sf_put_dirino(xfs_ino_t *from, xfs_dir_ino_t *to); +#define XFS_DIR_SF_PUT_DIRINO_ARCH(from,to,arch) xfs_dir_sf_put_dirino_arch(from, to, arch) +#define XFS_DIR_SF_PUT_DIRINO(from,to) xfs_dir_sf_put_dirino(from, to) +#else +#define XFS_DIR_SF_PUT_DIRINO_ARCH(from,to,arch) DIRINO_COPY_ARCH(from,to,arch) +#define XFS_DIR_SF_PUT_DIRINO(from,to) DIRINO_COPY_ARCH(from,to,ARCH_NOCONVERT) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_ENTSIZE_BYNAME) +int xfs_dir_sf_entsize_byname(int len); +#define XFS_DIR_SF_ENTSIZE_BYNAME(len) xfs_dir_sf_entsize_byname(len) +#else +#define XFS_DIR_SF_ENTSIZE_BYNAME(len) /* space a name uses */ \ + ((uint)sizeof(xfs_dir_sf_entry_t)-1 + (len)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_ENTSIZE_BYENTRY) +int xfs_dir_sf_entsize_byentry(xfs_dir_sf_entry_t *sfep); +#define XFS_DIR_SF_ENTSIZE_BYENTRY(sfep) xfs_dir_sf_entsize_byentry(sfep) +#else +#define XFS_DIR_SF_ENTSIZE_BYENTRY(sfep) /* space an entry uses */ \ + ((uint)sizeof(xfs_dir_sf_entry_t)-1 + (sfep)->namelen) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_NEXTENTRY) +xfs_dir_sf_entry_t *xfs_dir_sf_nextentry(xfs_dir_sf_entry_t *sfep); +#define XFS_DIR_SF_NEXTENTRY(sfep) xfs_dir_sf_nextentry(sfep) +#else +#define XFS_DIR_SF_NEXTENTRY(sfep) /* next entry in struct */ \ + ((xfs_dir_sf_entry_t *) \ + ((char *)(sfep) + XFS_DIR_SF_ENTSIZE_BYENTRY(sfep))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_ALLFIT) +int xfs_dir_sf_allfit(int count, int totallen); +#define XFS_DIR_SF_ALLFIT(count,totallen) \ + xfs_dir_sf_allfit(count,totallen) +#else +#define XFS_DIR_SF_ALLFIT(count,totallen) /* will all entries fit? */ \ + ((uint)sizeof(xfs_dir_sf_hdr_t) + \ + ((uint)sizeof(xfs_dir_sf_entry_t)-1)*(count) + (totallen)) +#endif + +#ifdef XFS_ALL_TRACE +#define XFS_DIR_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_DIR_TRACE +#endif + +/* + * Kernel tracing support for directories. + */ +struct uio; +struct xfs_inode; +struct xfs_da_intnode; +struct xfs_dinode; +struct xfs_dir_leafblock; +struct xfs_dir_leaf_entry; + +#define XFS_DIR_TRACE_SIZE 4096 /* size of global trace buffer */ + +/* + * Trace record types. + */ +#define XFS_DIR_KTRACE_G_DU 1 /* dp, uio */ +#define XFS_DIR_KTRACE_G_DUB 2 /* dp, uio, bno */ +#define XFS_DIR_KTRACE_G_DUN 3 /* dp, uio, node */ +#define XFS_DIR_KTRACE_G_DUL 4 /* dp, uio, leaf */ +#define XFS_DIR_KTRACE_G_DUE 5 /* dp, uio, leaf entry */ +#define XFS_DIR_KTRACE_G_DUC 6 /* dp, uio, cookie */ + +#if defined(XFS_DIR_TRACE) + +void xfs_dir_trace_g_du(char *where, struct xfs_inode *dp, struct uio *uio); +void xfs_dir_trace_g_dub(char *where, struct xfs_inode *dp, struct uio *uio, + xfs_dablk_t bno); +void xfs_dir_trace_g_dun(char *where, struct xfs_inode *dp, struct uio *uio, + struct xfs_da_intnode *node); +void xfs_dir_trace_g_dul(char *where, struct xfs_inode *dp, struct uio *uio, + struct xfs_dir_leafblock *leaf); +void xfs_dir_trace_g_due(char *where, struct xfs_inode *dp, struct uio *uio, + struct xfs_dir_leaf_entry *entry); +void xfs_dir_trace_g_duc(char *where, struct xfs_inode *dp, struct uio *uio, + xfs_off_t cookie); +void xfs_dir_trace_enter(int type, char *where, + __psunsigned_t a0, __psunsigned_t a1, + __psunsigned_t a2, __psunsigned_t a3, + __psunsigned_t a4, __psunsigned_t a5, + __psunsigned_t a6, __psunsigned_t a7, + __psunsigned_t a8, __psunsigned_t a9, + __psunsigned_t a10, __psunsigned_t a11); +#else +#define xfs_dir_trace_g_du(w,d,u) +#define xfs_dir_trace_g_dub(w,d,u,b) +#define xfs_dir_trace_g_dun(w,d,u,n) +#define xfs_dir_trace_g_dul(w,d,u,l) +#define xfs_dir_trace_g_due(w,d,u,e) +#define xfs_dir_trace_g_duc(w,d,u,c) +#endif /* DEBUG */ + +#endif /* __XFS_DIR_SF_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_dqblk.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_dqblk.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_dqblk.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_dqblk.h Mon Apr 2 21:52:38 2001 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DQBLK_H__ +#define __XFS_DQBLK_H__ + +/* + * The ondisk form of a dquot structure. + */ +#define XFS_DQUOT_MAGIC 0x4451 /* 'DQ' */ +#define XFS_DQUOT_VERSION (u_int8_t)0x01 /* latest version number */ + +/* + * This is the main portion of the on-disk representation of quota + * information for a user. This is the q_core of the xfs_dquot_t that + * is kept in kernel memory. We pad this with some more expansion room + * to construct the on disk structure. + */ +typedef struct xfs_disk_dquot { +/*16*/ u_int16_t d_magic; /* dquot magic = XFS_DQUOT_MAGIC */ +/*8 */ u_int8_t d_version; /* dquot version */ +/*8 */ u_int8_t d_flags; /* XFS_DQ_USER/PROJ/GROUP */ +/*32*/ xfs_dqid_t d_id; /* user,project,group id */ +/*64*/ xfs_qcnt_t d_blk_hardlimit;/* absolute limit on disk blks */ +/*64*/ xfs_qcnt_t d_blk_softlimit;/* preferred limit on disk blks */ +/*64*/ xfs_qcnt_t d_ino_hardlimit;/* maximum # allocated inodes */ +/*64*/ xfs_qcnt_t d_ino_softlimit;/* preferred inode limit */ +/*64*/ xfs_qcnt_t d_bcount; /* disk blocks owned by the user */ +/*64*/ xfs_qcnt_t d_icount; /* inodes owned by the user */ +/*32*/ __int32_t d_itimer; /* zero if within inode limits if not, + this is when we refuse service */ +/*32*/ __int32_t d_btimer; /* similar to above; for disk blocks */ +/*16*/ xfs_qwarncnt_t d_iwarns; /* warnings issued wrt num inodes */ +/*16*/ xfs_qwarncnt_t d_bwarns; /* warnings issued wrt disk blocks */ +/*32*/ __int32_t d_pad0; /* 64 bit align */ +/*64*/ xfs_qcnt_t d_rtb_hardlimit;/* absolute limit on realtime blks */ +/*64*/ xfs_qcnt_t d_rtb_softlimit;/* preferred limit on RT disk blks */ +/*64*/ xfs_qcnt_t d_rtbcount; /* realtime blocks owned */ +/*32*/ __int32_t d_rtbtimer; /* similar to above; for RT disk blocks */ +/*16*/ xfs_qwarncnt_t d_rtbwarns; /* warnings issued wrt RT disk blocks */ +/*16*/ __uint16_t d_pad; +} xfs_disk_dquot_t; + +/* + * This is what goes on disk. This is separated from the xfs_disk_dquot because + * carrying the unnecessary padding would be a waste of memory. + */ +typedef struct xfs_dqblk { + xfs_disk_dquot_t dd_diskdq; /* portion that lives incore as well */ + char dd_fill[32]; /* filling for posterity */ +} xfs_dqblk_t; + +/* + * flags for q_flags field in the dquot. + */ +#define XFS_DQ_USER 0x0001 /* a user quota */ +/* #define XFS_DQ_PROJ 0x0002 -- project quota (IRIX) */ +#define XFS_DQ_GROUP 0x0004 /* a group quota */ +#define XFS_DQ_FLOCKED 0x0008 /* flush lock taken */ +#define XFS_DQ_DIRTY 0x0010 /* dquot is dirty */ +#define XFS_DQ_WANT 0x0020 /* for lookup/reclaim race */ +#define XFS_DQ_INACTIVE 0x0040 /* dq off mplist & hashlist */ +#define XFS_DQ_MARKER 0x0080 /* sentinel */ + +/* + * In the worst case, when both user and group quotas are on, + * we can have a max of three dquots changing in a single transaction. + */ +#define XFS_DQUOT_LOGRES(mp) (sizeof(xfs_disk_dquot_t) * 3) + +#endif /* __XFS_DQBLK_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_dquot_item.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_dquot_item.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_dquot_item.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_dquot_item.h Mon Apr 2 21:52:38 2001 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DQUOT_ITEM_H__ +#define __XFS_DQUOT_ITEM_H__ + +/* + * These are the structures used to lay out dquots and quotaoff + * records on the log. Quite similar to those of inodes. + */ + +/* + * log format struct for dquots. + * The first two fields must be the type and size fitting into + * 32 bits : log_recovery code assumes that. + */ +typedef struct xfs_dq_logformat { + __uint16_t qlf_type; /* dquot log item type */ + __uint16_t qlf_size; /* size of this item */ + xfs_dqid_t qlf_id; /* usr/grp id number : 32 bits */ + __int64_t qlf_blkno; /* blkno of dquot buffer */ + __int32_t qlf_len; /* len of dquot buffer */ + __uint32_t qlf_boffset; /* off of dquot in buffer */ +} xfs_dq_logformat_t; + +/* + * log format struct for QUOTAOFF records. + * The first two fields must be the type and size fitting into + * 32 bits : log_recovery code assumes that. + * We write two LI_QUOTAOFF logitems per quotaoff, the last one keeps a pointer + * to the first and ensures that the first logitem is taken out of the AIL + * only when the last one is securely committed. + */ +typedef struct xfs_qoff_logformat { + unsigned short qf_type; /* quotaoff log item type */ + unsigned short qf_size; /* size of this item */ + unsigned int qf_flags; /* USR and/or GRP */ + char qf_pad[12]; /* padding for future */ +} xfs_qoff_logformat_t; + + +#ifdef __KERNEL__ + +struct xfs_dquot; +struct xfs_trans; +struct xfs_mount; +typedef struct xfs_dq_logitem { + xfs_log_item_t qli_item; /* common portion */ + struct xfs_dquot *qli_dquot; /* dquot ptr */ + xfs_lsn_t qli_flush_lsn; /* lsn at last flush */ + unsigned short qli_pushbuf_flag; /* one bit used in push_ail */ +#ifdef DEBUG + uint64_t qli_push_owner; +#endif + xfs_dq_logformat_t qli_format; /* logged structure */ +} xfs_dq_logitem_t; + + +typedef struct xfs_qoff_logitem { + xfs_log_item_t qql_item; /* common portion */ + struct xfs_qoff_logitem *qql_start_lip; /* qoff-start logitem, if any */ + xfs_qoff_logformat_t qql_format; /* logged structure */ +} xfs_qoff_logitem_t; + + +extern void xfs_qm_dquot_logitem_init(struct xfs_dquot *); +extern xfs_qoff_logitem_t *xfs_qm_qoff_logitem_init(struct xfs_mount *, + xfs_qoff_logitem_t *, uint); +extern xfs_qoff_logitem_t *xfs_trans_get_qoff_item(struct xfs_trans *, + xfs_qoff_logitem_t *, uint); +extern void xfs_trans_log_quotaoff_item(struct xfs_trans *, + xfs_qoff_logitem_t *); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_DQUOT_ITEM_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_extfree_item.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_extfree_item.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_extfree_item.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_extfree_item.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_EXTFREE_ITEM_H__ +#define __XFS_EXTFREE_ITEM_H__ + +struct xfs_mount; +struct xfs_zone; + +typedef struct xfs_extent { + xfs_dfsbno_t ext_start; + xfs_extlen_t ext_len; +} xfs_extent_t; + +/* + * This is the structure used to lay out an efi log item in the + * log. The efi_extents field is a variable size array whose + * size is given by efi_nextents. + */ +typedef struct xfs_efi_log_format { + unsigned short efi_type; /* efi log item type */ + unsigned short efi_size; /* size of this item */ + uint efi_nextents; /* # extents to free */ + __uint64_t efi_id; /* efi identifier */ + xfs_extent_t efi_extents[1]; /* array of extents to free */ +} xfs_efi_log_format_t; + +/* + * This is the structure used to lay out an efd log item in the + * log. The efd_extents array is a variable size array whose + * size is given by efd_nextents; + */ +typedef struct xfs_efd_log_format { + unsigned short efd_type; /* efd log item type */ + unsigned short efd_size; /* size of this item */ + uint efd_nextents; /* # of extents freed */ + __uint64_t efd_efi_id; /* id of corresponding efi */ + xfs_extent_t efd_extents[1]; /* array of extents freed */ +} xfs_efd_log_format_t; + + +#ifdef __KERNEL__ + +/* + * Max number of extents in fast allocation path. + */ +#define XFS_EFI_MAX_FAST_EXTENTS 16 + +/* + * Define EFI flags. + */ +#define XFS_EFI_RECOVERED 0x1 +#define XFS_EFI_COMMITTED 0x2 +#define XFS_EFI_CANCELED 0x4 + +/* + * This is the "extent free intention" log item. It is used + * to log the fact that some extents need to be free. It is + * used in conjunction with the "extent free done" log item + * described below. + */ +typedef struct xfs_efi_log_item { + xfs_log_item_t efi_item; + uint efi_flags; /* misc flags */ + uint efi_next_extent; + xfs_efi_log_format_t efi_format; +} xfs_efi_log_item_t; + +/* + * This is the "extent free done" log item. It is used to log + * the fact that some extents earlier mentioned in an efi item + * have been freed. + */ +typedef struct xfs_efd_log_item { + xfs_log_item_t efd_item; + xfs_efi_log_item_t *efd_efip; + uint efd_next_extent; + xfs_efd_log_format_t efd_format; +} xfs_efd_log_item_t; + +/* + * Max number of extents in fast allocation path. + */ +#define XFS_EFD_MAX_FAST_EXTENTS 16 + +extern struct xfs_zone *xfs_efi_zone; +extern struct xfs_zone *xfs_efd_zone; + +xfs_efi_log_item_t *xfs_efi_init(struct xfs_mount *, uint); +xfs_efd_log_item_t *xfs_efd_init(struct xfs_mount *, xfs_efi_log_item_t *, + uint); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_EXTFREE_ITEM_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_fs.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_fs.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_fs.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_fs.h Wed May 16 21:58:46 2001 @@ -0,0 +1,485 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef _LINUX_XFS_FS_H +#define _LINUX_XFS_FS_H + +#include +#include + + +/* + * SGI's XFS filesystem's major stuff (constants, structures) + */ + +#define XFS_SUPER_MAGIC 0x58465342 +#define XFS_NAME "xfs" + +struct biosize { + __u32 biosz_flags; + __s32 biosz_read; + __s32 biosz_write; + __s32 dfl_biosz_read; + __s32 dfl_biosz_write; +}; + +/* + * direct I/O attribute record used with F_DIOINFO + * d_miniosz is the min xfer size, xfer size multiple and file seek offset + * alignment. + */ +struct dioattr { + __u32 d_mem; /* data buffer memory alignment */ + __u32 d_miniosz; /* min xfer size */ + __u32 d_maxiosz; /* max xfer size */ +}; + +/* + * Structure for F_FSGETXATTR[A] and F_FSSETXATTR. + */ +struct fsxattr { + __u32 fsx_xflags; /* xflags field value (get/set) */ + __u32 fsx_extsize; /* extsize field value (get/set)*/ + __u32 fsx_nextents; /* nextents field value (get) */ + unsigned char fsx_pad[16]; +}; + +/* + * Flags for the bs_xflags/fsx_xflags field + * There should be a one-to-one correspondence between these flags and the + * XFS_DIFLAG_s. + */ +#define XFS_XFLAG_REALTIME 0x00000001 +#define XFS_XFLAG_PREALLOC 0x00000002 +#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ +#define XFS_XFLAG_ALL \ + ( XFS_XFLAG_REALTIME|XFS_XFLAG_PREALLOC|XFS_XFLAG_HASATTR ) + + +/* + * Structure for F_GETBMAP. + * On input, fill in bmv_offset and bmv_length of the first structure + * to indicate the area of interest in the file, and bmv_entry with the + * number of array elements given. The first structure is updated on + * return to give the offset and length for the next call. + */ +struct getbmap { + __s64 bmv_offset; /* file offset of segment in blocks */ + __s64 bmv_block; /* starting block (64-bit daddr_t) */ + __s64 bmv_length; /* length of segment, blocks */ + __s32 bmv_count; /* # of entries in array incl. 1st */ + __s32 bmv_entries; /* # of entries filled in (output) */ +}; + +/* + * Structure for F_GETBMAPX. The fields bmv_offset through bmv_entries + * are used exactly as in the getbmap structure. The getbmapx structure + * has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field + * is only used for the first structure. It contains input flags + * specifying F_GETBMAPX actions. The bmv_oflags field is filled in + * by the F_GETBMAPX command for each returned structure after the first. + */ +struct getbmapx { + __s64 bmv_offset; /* file offset of segment in blocks */ + __s64 bmv_block; /* starting block (64-bit daddr_t) */ + __s64 bmv_length; /* length of segment, blocks */ + __s32 bmv_count; /* # of entries in array incl. 1st */ + __s32 bmv_entries; /* # of entries filled in (output). */ + __s32 bmv_iflags; /* input flags (1st structure) */ + __s32 bmv_oflags; /* output flags (after 1st structure)*/ + __s32 bmv_unused1; /* future use */ + __s32 bmv_unused2; /* future use */ +}; + +/* bmv_iflags values - set by F_GETBMAPX caller. */ + +#define BMV_IF_ATTRFORK 0x1 /* return attr fork rather than data */ +#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */ +#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */ + +#define BMV_IF_VALID (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC) + +/* bmv_oflags values - returned from F_GETBMAPX for each non-header segment */ + +#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ + +/* Convert getbmap <-> getbmapx - move fields from p1 to p2. */ + +#define GETBMAP_CONVERT(p1,p2) { \ + p2.bmv_offset = p1.bmv_offset; \ + p2.bmv_block = p1.bmv_block; \ + p2.bmv_length = p1.bmv_length; \ + p2.bmv_count = p1.bmv_count; \ + p2.bmv_entries = p1.bmv_entries; } + +#ifdef __KERNEL__ + +/* Kernel only bmv_iflags value. */ +#define BMV_IF_EXTENDED 0x40000000 /* getpmapx if set */ + +#endif /* __KERNEL__ */ + +/* + * Structure for F_FSSETDM. + * For use by backup and restore programs to set the XFS on-disk inode + * fields di_dmevmask and di_dmstate. These must be set to exactly and + * only values previously obtained via xfs_bulkstat! (Specifically the + * xfs_bstat_t fields bs_dmevmask and bs_dmstate.) + */ +struct fsdmidata { + __s32 fsd_dmevmask; /* corresponds to di_dmevmask */ + __u16 fsd_padding; + __u16 fsd_dmstate; /* corresponds to di_dmstate */ +}; + +/* + * File segment locking set data type for 64 bit access. + * Also used for all the RESV/FREE interfaces. + */ +typedef struct xfs_flock64 { + __s16 l_type; + __s16 l_whence; + __s64 l_start; + __s64 l_len; /* len == 0 means until end of file */ + __s32 l_sysid; + pid_t l_pid; + __s32 l_pad[4]; /* reserve area */ +} xfs_flock64_t; + +/* + * Output for XFS_IOC_FSGEOMETRY + */ +typedef struct xfs_fsop_geom { + __u32 blocksize; /* filesystem (data) block size */ + __u32 rtextsize; /* realtime extent size */ + __u32 agblocks; /* fsblocks in an AG */ + __u32 agcount; /* number of allocation groups */ + __u32 logblocks; /* fsblocks in the log */ + __u32 sectsize; /* (data) sector size, bytes */ + __u32 inodesize; /* inode size in bytes */ + __u32 imaxpct; /* max allowed inode space(%) */ + __u64 datablocks; /* fsblocks in data subvolume */ + __u64 rtblocks; /* fsblocks in realtime subvol */ + __u64 rtextents; /* rt extents in realtime subvol*/ + __u64 logstart; /* starting fsblock of the log */ + unsigned char uuid[16]; /* unique id of the filesystem */ + __u32 sunit; /* stripe unit, fsblocks */ + __u32 swidth; /* stripe width, fsblocks */ + __s32 version; /* structure version */ + __u32 flags; /* superblock version flags */ + __u32 logsectsize; /* log sector size, bytes */ + __u32 rtsectsize; /* realtime sector size, bytes */ + __u32 dirblocksize; /* directory block size, bytes */ +} xfs_fsop_geom_t; + +/* Output for XFS_FS_COUNTS */ +typedef struct xfs_fsop_counts { + __u64 freedata; /* free data section blocks */ + __u64 freertx; /* free rt extents */ + __u64 freeino; /* free inodes */ + __u64 allocino; /* total allocated inodes */ +} xfs_fsop_counts_t; + +/* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */ +typedef struct xfs_fsop_resblks { + __u64 resblks; + __u64 resblks_avail; +} xfs_fsop_resblks_t; + +#define XFS_FSOP_GEOM_VERSION 0 + +#define XFS_FSOP_GEOM_FLAGS_ATTR 0x01 /* attributes in use */ +#define XFS_FSOP_GEOM_FLAGS_NLINK 0x02 /* 32-bit nlink values */ +#define XFS_FSOP_GEOM_FLAGS_QUOTA 0x04 /* quotas enabled */ +#define XFS_FSOP_GEOM_FLAGS_IALIGN 0x08 /* inode alignment */ +#define XFS_FSOP_GEOM_FLAGS_DALIGN 0x10 /* large data alignment */ +#define XFS_FSOP_GEOM_FLAGS_SHARED 0x20 /* read-only shared */ +#define XFS_FSOP_GEOM_FLAGS_EXTFLG 0x40 /* special extent flag */ +#define XFS_FSOP_GEOM_FLAGS_DIRV2 0x80 /* directory version 2 */ + + +/* + * Minimum and maximum sizes need for growth checks + */ +#define XFS_MIN_AG_BLOCKS 64 +#define XFS_MIN_LOG_BLOCKS 512 +#define XFS_MAX_LOG_BLOCKS (64 * 1024) +#define XFS_MIN_LOG_BYTES (256 * 1024) +#define XFS_MAX_LOG_BYTES (128 * 1024 * 1024) + +/* + * XFS_IOC_FSGROWFSDATA + */ +typedef struct xfs_growfs_data { + __u64 newblocks; /* new data subvol size, fsblocks */ + __u32 imaxpct; /* new inode space percentage limit */ +} xfs_growfs_data_t; + +/* + * XFS_IOC_FSGROWFSLOG + */ +typedef struct xfs_growfs_log { + __u32 newblocks; /* new log size, fsblocks */ + __u32 isint; /* 1 if new log is internal */ +} xfs_growfs_log_t; + +/* + * XFS_IOC_FSGROWFSRT + */ +typedef struct xfs_growfs_rt { + __u64 newblocks; /* new realtime size, fsblocks */ + __u32 extsize; /* new realtime extent size, fsblocks */ +} xfs_growfs_rt_t; + + +/* + * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE + */ +typedef struct xfs_bstime { + time_t tv_sec; /* seconds */ + __s32 tv_nsec; /* and nanoseconds */ +} xfs_bstime_t; + +typedef struct xfs_bstat { + __u64 bs_ino; /* inode number */ + __u16 bs_mode; /* type and mode */ + __u16 bs_nlink; /* number of links */ + __u32 bs_uid; /* user id */ + __u32 bs_gid; /* group id */ + __u32 bs_rdev; /* device value */ + __s32 bs_blksize; /* block size */ + __s64 bs_size; /* file size */ + xfs_bstime_t bs_atime; /* access time */ + xfs_bstime_t bs_mtime; /* modify time */ + xfs_bstime_t bs_ctime; /* inode change time */ + int64_t bs_blocks; /* number of blocks */ + __u32 bs_xflags; /* extended flags */ + __s32 bs_extsize; /* extent size */ + __s32 bs_extents; /* number of extents */ + __u32 bs_gen; /* generation count */ + __u16 bs_projid; /* project id */ + unsigned char bs_pad[14]; /* pad space, unused */ + __u32 bs_dmevmask; /* DMIG event mask */ + __u16 bs_dmstate; /* DMIG state info */ + __u16 bs_aextents; /* attribute number of extents */ +} xfs_bstat_t; + +/* + * The user-level BulkStat Request interface structure. + */ +typedef struct xfs_fsop_bulkreq { + __u64 *lastip; /* last inode # pointer */ + __s32 icount; /* count of entries in buffer */ + void *ubuffer; /* user buffer for inode desc. */ + __s32 *ocount; /* output count pointer */ +} xfs_fsop_bulkreq_t; + + +/* + * Structures returned from xfs_inumbers syssgi routine. + */ +typedef struct xfs_inogrp { + __u64 xi_startino; /* starting inode number */ + __s32 xi_alloccount; /* # bits set in allocmask */ + __u64 xi_allocmask; /* mask of allocated inodes */ +} xfs_inogrp_t; + + +/* + * The user-level Handle Request interface structure. + */ +typedef struct xfs_fsop_handlereq { + __u32 fd; /* fd for FD_TO_HANDLE */ + void *path; /* user pathname */ + __u32 oflags; /* open flags */ + void *ihandle; /* user supplied handle */ + __u32 ihandlen; /* user supplied length */ + void *ohandle; /* user buffer for handle */ + __u32 *ohandlen; /* user buffer length */ +} xfs_fsop_handlereq_t; + +/* + * Error injection can be turned on ethier by DEBUG or by INDUCE_IO_ERROR + * below since relying only on DEBUG will undoubtedly be a different + * code path. + */ +/*#define INDUCE_IO_ERROR*/ + +#if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) +/* + * Error injection. + */ +typedef struct xfs_error_injection { + __s32 fd; + __s32 errtag; +} xfs_error_injection_t; +#endif /* DEBUG || INDUCE_IO_ERROR */ + +/* + * Compound structure for passing args through ioctl to xfs_attrctl_by_handle + */ +typedef struct xfs_fsop_attr_handlereq { + struct xfs_fsop_handlereq *hreq;/* handle request interface */ + /* structure */ + struct attr_op *ops; /* array of attribute ops */ + int count; /* number of attribute ops */ +} xfs_fsop_attr_handlereq_t; + +/* + * File system identifier. Should be unique (at least per machine). + */ +typedef struct { + __u32 val[2]; /* file system id type */ +} xfs_fsid_t; + +/* + * File identifier. Should be unique per filesystem on a single machine. + * This is typically called by a stateless file server in order to generate + * "file handles". + */ +#define MAXFIDSZ 46 + +typedef struct fid { + __u16 fid_len; /* length of data in bytes */ + unsigned char fid_data[MAXFIDSZ]; /* data (variable length) */ +} fid_t; + +typedef struct xfs_fid { + __u16 xfs_fid_len; /* length of remainder */ + __u16 xfs_fid_pad; + __u32 xfs_fid_gen; /* generation number */ + __u64 xfs_fid_ino; /* 64 bits inode number */ +} xfs_fid_t; + +typedef struct xfs_fid2 { + __u16 fid_len; /* length of remainder */ + __u16 fid_pad; /* padding, must be zero */ + __u32 fid_gen; /* generation number */ + __u64 fid_ino; /* inode number */ +} xfs_fid2_t; + +typedef struct xfs_handle { + union { + __s64 align; /* force alignment of ha_fid */ + xfs_fsid_t _ha_fsid; /* unique file system identifier */ + } ha_u; + xfs_fid_t ha_fid; /* file system specific file ID */ +} xfs_handle_t; + +#define ha_fsid ha_u._ha_fsid + +#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.xfs_fid_pad \ + - (char *) &(handle)) \ + + (handle).ha_fid.xfs_fid_len) + +#define XFS_HANDLE_CMP(h1, h2) bcmp(h1, h2, sizeof (xfs_handle_t)) + +#define FSHSIZE sizeof (fsid_t) + + +/* + * ioctl commands that replace IRIX fcntl()'s + * For 'documentation' purposed more than anything else, + * the "cmd #" field reflects the IRIX fcntl number. + */ +#define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64) +#define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64) +#define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr) +#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr) +#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr) +#define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64) +#define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64) +#define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap) +#define XFS_IOC_FSSETDM _IOW ('X', 39, struct fsdmidata) +#define XFS_IOC_RESVSP _IOW ('X', 40, struct xfs_flock64) +#define XFS_IOC_UNRESVSP _IOW ('X', 41, struct xfs_flock64) +#define XFS_IOC_RESVSP64 _IOW ('X', 42, struct xfs_flock64) +#define XFS_IOC_UNRESVSP64 _IOW ('X', 43, struct xfs_flock64) +#define XFS_IOC_GETBMAPA _IOWR('X', 44, struct getbmap) +#define XFS_IOC_FSGETXATTRA _IOR ('X', 45, struct fsxattr) +#define XFS_IOC_SETBIOSIZE _IOW ('X', 46, struct biosize) +#define XFS_IOC_GETBIOSIZE _IOR ('X', 47, struct biosize) +#define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap) + +/* + * ioctl commands that replace IRIX syssgi()'s + */ +#define XFS_IOC_FSGEOMETRY _IOR ('X', 100, struct xfs_fsop_geom) +#define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct xfs_fsop_bulkreq) +#define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct xfs_fsop_bulkreq) +#define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct xfs_fsop_bulkreq) +#define XFS_IOC_PATH_TO_FSHANDLE _IOWR('X', 104, struct xfs_fsop_handlereq) +#define XFS_IOC_PATH_TO_HANDLE _IOWR('X', 105, struct xfs_fsop_handlereq) +#define XFS_IOC_FD_TO_HANDLE _IOWR('X', 106, struct xfs_fsop_handlereq) +#define XFS_IOC_OPEN_BY_HANDLE _IOWR('X', 107, struct xfs_fsop_handlereq) +#define XFS_IOC_READLINK_BY_HANDLE _IOWR('X', 108, struct xfs_fsop_handlereq) +#define XFS_IOC_SWAPEXT _IOWR('X', 109, struct xfs_swapext) +#define XFS_IOC_FSGROWFSDATA _IOW('X', 110, struct xfs_growfs_data) +#define XFS_IOC_FSGROWFSLOG _IOW('X', 111, struct xfs_growfs_log) +#define XFS_IOC_FSGROWFSRT _IOW('X', 112, struct xfs_growfs_rt) +#define XFS_IOC_FSCOUNTS _IOR ('X', 113, struct xfs_fsop_counts) +#define XFS_IOC_SET_RESBLKS _IOR ('X', 114, struct xfs_fsop_resblks) +#define XFS_IOC_GET_RESBLKS _IOR ('X', 115, struct xfs_fsop_resblks) +#if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) +#define XFS_IOC_ERROR_INJECTION _IOW('X', 116, struct xfs_error_injection) +#define XFS_IOC_ERROR_CLEARALL _IOW('X', 117, struct xfs_error_injection) +#endif /* DEBUG || INDUCE_IO_ERROR */ +#define XFS_IOC_ATTRCTL_BY_HANDLE _IOWR('X', 118, struct xfs_fsop_attr_handlereq) +#define XFS_IOC_FREEZE _IOWR('X', 119, int) +#define XFS_IOC_THAW _IOWR('X', 120, int) +/* + * ioctl command to export information not in standard interfaces + * 140: IRIX statvfs.f_fstr field - UUID from the superblock + */ +#define XFS_IOC_GETFSUUID _IOR ('X', 140, unsigned char[16]) + + +/* + * Block I/O parameterization. A basic block (BB) is the lowest size of + * filesystem allocation, and must == NBPSCTR. Length units given to bio + * routines are in BB's. + */ +#define BBSHIFT 9 +#define BBSIZE (1<> BBSHIFT) +#define BTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT) +#define BBTOB(bbs) ((bbs) << BBSHIFT) +#define OFFTOBB(bytes) (((__u64)(bytes) + BBSIZE - 1) >> BBSHIFT) +#define OFFTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT) +#define BBTOOFF(bbs) ((__u64)(bbs) << BBSHIFT) + +#define SEEKLIMIT32 0x7fffffff +#define BBSEEKLIMIT32 BTOBBT(SEEKLIMIT32) +#define SEEKLIMIT 0x7fffffffffffffffLL +#define BBSEEKLIMIT OFFTOBBT(SEEKLIMIT) + +#endif /* _LINUX_XFS_FS_H */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_ialloc.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_ialloc.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_ialloc.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_ialloc.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_IALLOC_H__ +#define __XFS_IALLOC_H__ + +struct xfs_buf; +struct xfs_dinode; +struct xfs_mount; +struct xfs_trans; + +/* + * Allocation parameters for inode allocation. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IALLOC_INODES) +int xfs_ialloc_inodes(struct xfs_mount *mp); +#define XFS_IALLOC_INODES(mp) xfs_ialloc_inodes(mp) +#else +#define XFS_IALLOC_INODES(mp) ((mp)->m_ialloc_inos) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IALLOC_BLOCKS) +xfs_extlen_t xfs_ialloc_blocks(struct xfs_mount *mp); +#define XFS_IALLOC_BLOCKS(mp) xfs_ialloc_blocks(mp) +#else +#define XFS_IALLOC_BLOCKS(mp) ((mp)->m_ialloc_blks) +#endif + +/* + * For small block file systems, move inodes in clusters of this size. + * When we don't have a lot of memory, however, we go a bit smaller + * to reduce the number of AGI and ialloc btree blocks we need to keep + * around for xfs_dilocate(). We choose which one to use in + * xfs_mount_int(). + */ +#define XFS_INODE_BIG_CLUSTER_SIZE 8192 +#define XFS_INODE_SMALL_CLUSTER_SIZE 4096 +#define XFS_INODE_CLUSTER_SIZE(mp) (mp)->m_inode_cluster_size + +/* + * Make an inode pointer out of the buffer/offset. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MAKE_IPTR) +struct xfs_dinode *xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o); +#define XFS_MAKE_IPTR(mp,b,o) xfs_make_iptr(mp,b,o) +#else +#define XFS_MAKE_IPTR(mp,b,o) \ + ((xfs_dinode_t *)(xfs_buf_offset(b, (o) << (mp)->m_sb.sb_inodelog))) +#endif + +/* + * Find a free (set) bit in the inode bitmask. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IALLOC_FIND_FREE) +int xfs_ialloc_find_free(xfs_inofree_t *fp); +#define XFS_IALLOC_FIND_FREE(fp) xfs_ialloc_find_free(fp) +#else +#define XFS_IALLOC_FIND_FREE(fp) xfs_lowbit64(*(fp)) +#endif + + +#ifdef __KERNEL__ + +/* + * Prototypes for visible xfs_ialloc.c routines. + */ + +/* + * Allocate an inode on disk. + * Mode is used to tell whether the new inode will need space, and whether + * it is a directory. + * + * To work within the constraint of one allocation per transaction, + * xfs_dialloc() is designed to be called twice if it has to do an + * allocation to make more free inodes. If an inode is + * available without an allocation, agbp would be set to the current + * agbp and alloc_done set to false. + * If an allocation needed to be done, agbp would be set to the + * inode header of the allocation group and alloc_done set to true. + * The caller should then commit the current transaction and allocate a new + * transaction. xfs_dialloc() should then be called again with + * the agbp value returned from the previous call. + * + * Once we successfully pick an inode its number is returned and the + * on-disk data structures are updated. The inode itself is not read + * in, since doing so would break ordering constraints with xfs_reclaim. + * + * *agbp should be set to NULL on the first call, *alloc_done set to FALSE. + */ +int /* error */ +xfs_dialloc( + struct xfs_trans *tp, /* transaction pointer */ + xfs_ino_t parent, /* parent inode (directory) */ + mode_t mode, /* mode bits for new inode */ + int okalloc, /* ok to allocate more space */ + struct xfs_buf **agbp, /* buf for a.g. inode header */ + boolean_t *alloc_done, /* an allocation was done to replenish + the free inodes */ + xfs_ino_t *inop); /* inode number allocated */ + +/* + * Free disk inode. Carefully avoids touching the incore inode, all + * manipulations incore are the caller's responsibility. + * The on-disk inode is not changed by this operation, only the + * btree (free inode mask) is changed. + */ +int /* error */ +xfs_difree( + struct xfs_trans *tp, /* transaction pointer */ + xfs_ino_t inode); /* inode to be freed */ + +/* + * Return the location of the inode in bno/len/off, + * for mapping it into a buffer. + */ +int +xfs_dilocate( + struct xfs_mount *mp, /* file system mount structure */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_ino_t ino, /* inode to locate */ + xfs_fsblock_t *bno, /* output: block containing inode */ + int *len, /* output: num blocks in cluster*/ + int *off, /* output: index in block of inode */ + uint flags); /* flags for inode btree lookup */ + +/* + * Compute and fill in value of m_in_maxlevels. + */ +void +xfs_ialloc_compute_maxlevels( + struct xfs_mount *mp); /* file system mount structure */ + +/* + * Log specified fields for the ag hdr (inode section) + */ +void +xfs_ialloc_log_agi( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_buf *bp, /* allocation group header buffer */ + int fields); /* bitmask of fields to log */ + +/* + * Read in the allocation group header (inode allocation section) + */ +int /* error */ +xfs_ialloc_read_agi( + struct xfs_mount *mp, /* file system mount structure */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + struct xfs_buf **bpp); /* allocation group hdr buf */ + +#endif /* __KERNEL__ */ + +#endif /* __XFS_IALLOC_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_ialloc_btree.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_ialloc_btree.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_ialloc_btree.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_ialloc_btree.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_IALLOC_BTREE_H__ +#define __XFS_IALLOC_BTREE_H__ + +/* + * Inode map on-disk structures + */ + +struct xfs_buf; +struct xfs_btree_cur; +struct xfs_btree_sblock; +struct xfs_mount; + +/* + * There is a btree for the inode map per allocation group. + */ +#define XFS_IBT_MAGIC 0x49414254 /* 'IABT' */ + +typedef __uint64_t xfs_inofree_t; +#define XFS_INODES_PER_CHUNK (NBBY * sizeof(xfs_inofree_t)) +#define XFS_INODES_PER_CHUNK_LOG (XFS_NBBYLOG + 3) +#define XFS_INOBT_ALL_FREE ((xfs_inofree_t)-1) + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_MASKN) +xfs_inofree_t xfs_inobt_maskn(int i, int n); +#define XFS_INOBT_MASKN(i,n) xfs_inobt_maskn(i,n) +#else +#define XFS_INOBT_MASKN(i,n) \ + ((((n) >= XFS_INODES_PER_CHUNK ? \ + (xfs_inofree_t)0 : ((xfs_inofree_t)1 << (n))) - 1) << (i)) +#endif + +/* + * Data record structure + */ +typedef struct xfs_inobt_rec +{ + xfs_agino_t ir_startino; /* starting inode number */ + __int32_t ir_freecount; /* count of free inodes (set bits) */ + xfs_inofree_t ir_free; /* free inode mask */ +} xfs_inobt_rec_t; + +/* + * Key structure + */ +typedef struct xfs_inobt_key +{ + xfs_agino_t ir_startino; /* starting inode number */ +} xfs_inobt_key_t; + +typedef xfs_agblock_t xfs_inobt_ptr_t; /* btree pointer type */ + /* btree block header type */ +typedef struct xfs_btree_sblock xfs_inobt_block_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_INOBT_BLOCK) +xfs_inobt_block_t *xfs_buf_to_inobt_block(struct xfs_buf *bp); +#define XFS_BUF_TO_INOBT_BLOCK(bp) xfs_buf_to_inobt_block(bp) +#else +#define XFS_BUF_TO_INOBT_BLOCK(bp) ((xfs_inobt_block_t *)(XFS_BUF_PTR(bp))) +#endif + +/* + * Bit manipulations for ir_free. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_MASK) +xfs_inofree_t xfs_inobt_mask(int i); +#define XFS_INOBT_MASK(i) xfs_inobt_mask(i) +#else +#define XFS_INOBT_MASK(i) ((xfs_inofree_t)1 << (i)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_IS_FREE) +int xfs_inobt_is_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch); +#define XFS_INOBT_IS_FREE(rp,i,arch) xfs_inobt_is_free(rp,i,arch) +#else +#define XFS_INOBT_IS_FREE(rp,i,arch) ((INT_GET((rp)->ir_free, arch) \ + & XFS_INOBT_MASK(i)) != 0) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_SET_FREE) +void xfs_inobt_set_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch); +#define XFS_INOBT_SET_FREE(rp,i,arch) xfs_inobt_set_free(rp,i,arch) +#else +#define XFS_INOBT_SET_FREE(rp,i,arch) (INT_MOD_EXPR((rp)->ir_free, arch, |= XFS_INOBT_MASK(i))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_CLR_FREE) +void xfs_inobt_clr_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch); +#define XFS_INOBT_CLR_FREE(rp,i,arch) xfs_inobt_clr_free(rp,i,arch) +#else +#define XFS_INOBT_CLR_FREE(rp,i,arch) (INT_MOD_EXPR((rp)->ir_free, arch, &= ~XFS_INOBT_MASK(i))) +#endif + +/* + * Real block structures have a size equal to the disk block size. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_BLOCK_SIZE) +int xfs_inobt_block_size(int lev, struct xfs_btree_cur *cur); +#define XFS_INOBT_BLOCK_SIZE(lev,cur) xfs_inobt_block_size(lev,cur) +#else +#define XFS_INOBT_BLOCK_SIZE(lev,cur) (1 << (cur)->bc_blocklog) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_BLOCK_MAXRECS) +int xfs_inobt_block_maxrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_INOBT_BLOCK_MAXRECS(lev,cur) xfs_inobt_block_maxrecs(lev,cur) +#else +#define XFS_INOBT_BLOCK_MAXRECS(lev,cur) \ + ((cur)->bc_mp->m_inobt_mxr[lev != 0]) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_BLOCK_MINRECS) +int xfs_inobt_block_minrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_INOBT_BLOCK_MINRECS(lev,cur) xfs_inobt_block_minrecs(lev,cur) +#else +#define XFS_INOBT_BLOCK_MINRECS(lev,cur) \ + ((cur)->bc_mp->m_inobt_mnr[lev != 0]) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_IS_LAST_REC) +int xfs_inobt_is_last_rec(struct xfs_btree_cur *cur); +#define XFS_INOBT_IS_LAST_REC(cur) xfs_inobt_is_last_rec(cur) +#else +#define XFS_INOBT_IS_LAST_REC(cur) \ + ((cur)->bc_ptrs[0] == \ + INT_GET(XFS_BUF_TO_INOBT_BLOCK((cur)->bc_bufs[0])->bb_numrecs, ARCH_CONVERT)) +#endif + +/* + * Maximum number of inode btree levels. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IN_MAXLEVELS) +int xfs_in_maxlevels(struct xfs_mount *mp); +#define XFS_IN_MAXLEVELS(mp) xfs_in_maxlevels(mp) +#else +#define XFS_IN_MAXLEVELS(mp) ((mp)->m_in_maxlevels) +#endif + +/* + * block numbers in the AG. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IBT_BLOCK) +xfs_agblock_t xfs_ibt_block(struct xfs_mount *mp); +#define XFS_IBT_BLOCK(mp) xfs_ibt_block(mp) +#else +#define XFS_IBT_BLOCK(mp) ((xfs_agblock_t)(XFS_CNT_BLOCK(mp) + 1)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_PREALLOC_BLOCKS) +xfs_agblock_t xfs_prealloc_blocks(struct xfs_mount *mp); +#define XFS_PREALLOC_BLOCKS(mp) xfs_prealloc_blocks(mp) +#else +#define XFS_PREALLOC_BLOCKS(mp) ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1)) +#endif + +/* + * Record, key, and pointer address macros for btree blocks. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_REC_ADDR) +xfs_inobt_rec_t * +xfs_inobt_rec_addr(xfs_inobt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_INOBT_REC_ADDR(bb,i,cur) xfs_inobt_rec_addr(bb,i,cur) +#else +#define XFS_INOBT_REC_ADDR(bb,i,cur) \ + XFS_BTREE_REC_ADDR(XFS_INOBT_BLOCK_SIZE(0,cur), xfs_inobt, bb, i, \ + XFS_INOBT_BLOCK_MAXRECS(0, cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_KEY_ADDR) +xfs_inobt_key_t * +xfs_inobt_key_addr(xfs_inobt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_INOBT_KEY_ADDR(bb,i,cur) xfs_inobt_key_addr(bb,i,cur) +#else +#define XFS_INOBT_KEY_ADDR(bb,i,cur) \ + XFS_BTREE_KEY_ADDR(XFS_INOBT_BLOCK_SIZE(1,cur), xfs_inobt, bb, i, \ + XFS_INOBT_BLOCK_MAXRECS(1, cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_PTR_ADDR) +xfs_inobt_ptr_t * +xfs_inobt_ptr_addr(xfs_inobt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_INOBT_PTR_ADDR(bb,i,cur) xfs_inobt_ptr_addr(bb,i,cur) +#else +#define XFS_INOBT_PTR_ADDR(bb,i,cur) \ + XFS_BTREE_PTR_ADDR(XFS_INOBT_BLOCK_SIZE(1,cur), xfs_inobt, bb, i, \ + XFS_INOBT_BLOCK_MAXRECS(1, cur)) +#endif + +/* + * Prototypes for externally visible routines. + */ + +/* + * Decrement cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_inobt_decrement( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat); /* success/failure */ + +#ifdef _NOTYET_ +/* + * Delete the record pointed to by cur. + * The cursor refers to the place where the record was (could be inserted) + * when the operation returns. + */ +int /* error */ +xfs_inobt_delete( + struct xfs_btree_cur *cur, /* btree cursor */ + int *stat); /* success/failure */ +#endif /* _NOTYET_ */ + +/* + * Get the data from the pointed-to record. + */ +int /* error */ +xfs_inobt_get_rec( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agino_t *ino, /* output: starting inode of chunk */ + __int32_t *fcnt, /* output: number of free inodes */ + xfs_inofree_t *free, /* output: free inode mask */ + int *stat, /* output: success/failure */ + xfs_arch_t arch); /* output: architecture */ + +/* + * Increment cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_inobt_increment( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat); /* success/failure */ + +/* + * Insert the current record at the point referenced by cur. + * The cursor may be inconsistent on return if splits have been done. + */ +int /* error */ +xfs_inobt_insert( + struct xfs_btree_cur *cur, /* btree cursor */ + int *stat); /* success/failure */ + +/* + * Lookup the record equal to ino in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_eq( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat); /* success/failure */ + +/* + * Lookup the first record greater than or equal to ino + * in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_ge( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat); /* success/failure */ + +/* + * Lookup the first record less than or equal to ino + * in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_le( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat); /* success/failure */ + +/* + * Update the record referred to by cur, to the value given + * by [ino, fcnt, free]. + * This either works (return 0) or gets an EFSCORRUPTED error. + */ +int /* error */ +xfs_inobt_update( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free); /* free inode mask */ + +#endif /* __XFS_IALLOC_BTREE_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_imap.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_imap.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_imap.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_imap.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_IMAP_H__ +#define __XFS_IMAP_H__ + +/* + * This is the structure passed to xfs_imap() to map + * an inode number to its on disk location. + */ +typedef struct xfs_imap { + xfs_daddr_t im_blkno; /* starting BB of inode chunk */ + uint im_len; /* length in BBs of inode chunk */ + xfs_agblock_t im_agblkno; /* logical block of inode chunk in ag */ + ushort im_ioffset; /* inode offset in block in "inodes" */ + ushort im_boffset; /* inode offset in block in bytes */ +} xfs_imap_t; + +#ifdef __KERNEL__ +struct xfs_mount; +struct xfs_trans; +int xfs_imap(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, + xfs_imap_t *, uint); +#endif + +#endif /* __XFS_IMAP_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_inode.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_inode.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_inode.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_inode.h Wed Jun 20 09:51:43 2001 @@ -0,0 +1,602 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_INODE_H__ +#define __XFS_INODE_H__ + +/* + * File incore extent information, present for each of data & attr forks. + */ +#define XFS_INLINE_EXTS 2 +#define XFS_INLINE_DATA 32 +typedef struct xfs_ifork { + int if_bytes; /* bytes in if_u1 */ + int if_real_bytes; /* bytes allocated in if_u1 */ + xfs_bmbt_block_t *if_broot; /* file's incore btree root */ + short if_broot_bytes; /* bytes allocated for root */ + unsigned char if_flags; /* per-fork flags */ + unsigned char if_ext_max; /* max # of extent records */ + xfs_extnum_t if_lastex; /* last if_extents used */ + union { + xfs_bmbt_rec_t *if_extents; /* linear map file exts */ + char *if_data; /* inline file data */ + } if_u1; + union { + xfs_bmbt_rec_t if_inline_ext[XFS_INLINE_EXTS]; + /* very small file extents */ + char if_inline_data[XFS_INLINE_DATA]; + /* very small file data */ + xfs_dev_t if_rdev; /* dev number if special */ + uuid_t if_uuid; /* mount point value */ + } if_u2; +} xfs_ifork_t; + +/* + * Flags for xfs_ichgtime(). + */ +#define XFS_ICHGTIME_MOD 0x1 /* data fork modification timestamp */ +#define XFS_ICHGTIME_ACC 0x2 /* data fork access timestamp */ +#define XFS_ICHGTIME_CHG 0x4 /* inode field change timestamp */ + +/* + * Per-fork incore inode flags. + */ +#define XFS_IFINLINE 0x0001 /* Inline data is read in */ +#define XFS_IFEXTENTS 0x0002 /* All extent pointers are read in */ +#define XFS_IFBROOT 0x0004 /* i_broot points to the bmap b-tree root */ + +/* + * Flags for xfs_imap() and xfs_dilocate(). + */ +#define XFS_IMAP_LOOKUP 0x1 + +/* + * Maximum number of extent pointers in if_u1.if_extents. + */ +#define XFS_MAX_INCORE_EXTENTS 32768 + + +#ifdef __KERNEL__ +struct bhv_desc; +struct cred; +struct ktrace; +struct vnode; +struct xfs_buf; +struct xfs_bmap_free; +struct xfs_bmbt_irec; +struct xfs_bmbt_block; +struct xfs_ext_attr; +struct xfs_inode; +struct xfs_inode_log_item; +struct xfs_mount; +struct xfs_trans; +struct xfs_dquot; +struct pm; + + +/* + * This structure is used to communicate which extents of a file + * were holes when a write started from xfs_write_file() to + * xfs_strat_read(). This is necessary so that we can know which + * blocks need to be zeroed when they are read in in xfs_strat_read() + * if they weren\'t allocated when the buffer given to xfs_strat_read() + * was mapped. + * + * We keep a list of these attached to the inode. The list is + * protected by the inode lock and the fact that the io lock is + * held exclusively by writers. + */ +typedef struct xfs_gap { + struct xfs_gap *xg_next; + xfs_fileoff_t xg_offset_fsb; + xfs_extlen_t xg_count_fsb; +} xfs_gap_t; + +/* + * This structure is used to hold common pieces of the buffer + * and file for xfs_dio_write and xfs_dio_read. + */ +typedef struct xfs_dio { + struct xfs_buf *xd_bp; + bhv_desc_t *xd_bdp; + struct xfs_inode *xd_ip; + struct xfs_iocore *xd_io; + struct cred *xd_cr; + struct pm *xd_pmp; + int xd_blkalgn; + int xd_ioflag; + xfs_off_t xd_start; + size_t xd_length; +} xfs_dio_t; + + +typedef struct xfs_iocore { + void *io_obj; /* pointer to container + * inode or dcxvn structure */ + struct xfs_mount *io_mount; /* fs mount struct ptr */ + mrlock_t *io_lock; /* inode lock */ + mrlock_t *io_iolock; /* inode IO lock */ + sema_t *io_flock; /* inode flush lock */ + + /* I/O state */ + xfs_fsize_t io_new_size; /* sz when write completes */ + unsigned int io_readio_blocks; /* read buffer size */ + unsigned int io_writeio_blocks; /* write buffer size */ + uchar_t io_readio_log; /* log2 of read buffer size */ + uchar_t io_writeio_log; /* log2 of write buffer size */ + uchar_t io_max_io_log; /* max r/w io value */ + int io_queued_bufs; /* count of xfsd queued bufs*/ + + /* Miscellaneous state. */ + unsigned int io_flags; /* IO related flags */ + + /* DMAPI state */ + __uint32_t io_dmevmask; /* DMIG event mask */ + __uint16_t io_dmstate; /* DMIG state info */ +} xfs_iocore_t; + +#define XFS_IO_INODE(io) ((xfs_inode_t *) ((io)->io_obj)) +#define XFS_IO_DCXVN(io) ((dcxvn_t *) ((io)->io_obj)) + +/* + * Flags in the flags field + */ + +#define XFS_IOCORE_ISXFS 0x01 +#define XFS_IOCORE_ISCXFS 0x02 +#define XFS_IOCORE_RT 0x04 +#define XFS_IOCORE_UIOSZ 0x08 + +#define IO_IS_XFS(io) ((io)->io_flags & XFS_IOCORE_ISXFS) + +/* + * Clear out the read-ahead state in the in-core inode. + * We actually only need to clear i_next_offset and + * i_last_req_sz to get the effect of making all the + * read ahead state unusable. + */ +#define XFS_INODE_CLEAR_READ_AHEAD(io) + + +/* + * xfs_iocore prototypes + */ + +extern void xfs_iocore_inode_init(struct xfs_inode *); +extern void xfs_iocore_inode_reinit(struct xfs_inode *); +extern void xfs_iocore_reset(xfs_iocore_t *); + + +/* + * This is the type used in the xfs inode hash table. + * An array of these is allocated for each mounted + * file system to hash the inodes for that file system. + */ +typedef struct xfs_ihash { + struct xfs_inode *ih_next; + mrlock_t ih_lock; + uint ih_version; +} xfs_ihash_t; +#if defined(MP) +#pragma set type attribute xfs_ihash align=128 +#endif + +/* + * Inode hashing and hash bucket locking. + */ +#define XFS_BUCKETS(mp) (37*(mp)->m_sb.sb_agcount-1) +#define XFS_IHASH(mp,ino) ((mp)->m_ihash + (((uint)ino) % (mp)->m_ihsize)) + +/* + * This is the xfs inode cluster hash. This hash is used by xfs_iflush to + * find inodes that share a cluster and can be flushed to disk at the same + * time. + */ + +typedef struct xfs_chashlist { + struct xfs_chashlist *chl_next; + struct xfs_inode *chl_ip; + xfs_daddr_t chl_blkno; /* starting block number of + * the cluster */ +#ifdef DEBUG + struct xfs_buf *chl_buf; /* debug: the inode buffer */ +#endif +} xfs_chashlist_t; + +typedef struct xfs_chash { + xfs_chashlist_t *ch_list; + lock_t ch_lock; +} xfs_chash_t; + + +/* + * This is the xfs in-core inode structure. + * Most of the on-disk inode is embedded in the i_d field. + * + * The extent pointers/inline file space, however, are managed + * separately. The memory for this information is pointed to by + * the if_u1 unions depending on the type of the data. + * This is used to linearize the array of extents for fast in-core + * access. This is used until the file's number of extents + * surpasses XFS_MAX_INCORE_EXTENTS, at which point all extent pointers + * are accessed through the buffer cache. + * + * Other state kept in the in-core inode is used for identification, + * locking, transactional updating, etc of the inode. + * + * Generally, we do not want to hold the i_rlock while holding the + * i_ilock. Hierarchy is i_iolock followed by i_rlock. + * + * xfs_iptr_t contains all the inode fields upto and including the + * i_mnext and i_mprev fields, it is used as a marker in the inode + * chain off the mount structure by xfs_sync calls. + */ + +typedef struct { + struct xfs_ihash *ip_hash; /* pointer to hash header */ + struct xfs_inode *ip_next; /* inode hash link forw */ + struct xfs_inode *ip_mnext; /* next inode in mount list */ + struct xfs_inode *ip_mprev; /* ptr to prev inode */ + struct xfs_inode **ip_prevp; /* ptr to prev i_next */ + struct xfs_mount *ip_mount; /* fs mount struct ptr */ +} xfs_iptr_t; + +typedef struct xfs_inode { + /* Inode linking and identification information. */ + struct xfs_ihash *i_hash; /* pointer to hash header */ + struct xfs_inode *i_next; /* inode hash link forw */ + struct xfs_inode *i_mnext; /* next inode in mount list */ + struct xfs_inode *i_mprev; /* ptr to prev inode */ + struct xfs_inode **i_prevp; /* ptr to prev i_next */ + struct xfs_mount *i_mount; /* fs mount struct ptr */ + struct bhv_desc i_bhv_desc; /* inode behavior descriptor*/ + struct xfs_dquot *i_udquot; /* user dquot */ + struct xfs_dquot *i_gdquot; /* group dquot */ + + /* Inode location stuff */ + xfs_ino_t i_ino; /* inode number (agno/agino)*/ + xfs_daddr_t i_blkno; /* blkno of inode buffer */ + dev_t i_dev; /* dev for this inode */ + ushort i_len; /* len of inode buffer */ + ushort i_boffset; /* off of inode in buffer */ + + /* Extent information. */ + xfs_ifork_t *i_afp; /* attribute fork pointer */ + xfs_ifork_t i_df; /* data fork */ + + /* Transaction and locking information. */ + struct xfs_trans *i_transp; /* ptr to owning transaction*/ + struct xfs_inode_log_item *i_itemp; /* logging information */ + mrlock_t i_lock; /* inode lock */ + mrlock_t i_iolock; /* inode IO lock */ + sema_t i_flock; /* inode flush lock */ + unsigned int i_pincount; /* inode pin count */ + sv_t i_pinsema; /* inode pin sema */ + lock_t i_ipinlock; /* inode pinning mutex */ + struct xfs_inode **i_refcache; /* ptr to entry in ref cache */ + struct xfs_inode *i_release; /* inode to unref */ + + /* I/O state */ + xfs_iocore_t i_iocore; /* I/O core */ + + /* Miscellaneous state. */ + unsigned short i_flags; /* see defined flags below */ + unsigned short i_update_core; /* timestamps/size is dirty */ + unsigned short i_update_size; /* di_size field is dirty */ + unsigned int i_gen; /* generation count */ + unsigned int i_delayed_blks; /* count of delay alloc blks */ + struct xfs_ext_attr *i_ext_attr; /* Critical ext attributes */ + void *i_ilock_ra; /* current ilock ret addr */ + + xfs_dinode_core_t i_d; /* most of ondisk inode */ + xfs_chashlist_t *i_chash; /* cluster hash list header */ + struct xfs_inode *i_cnext; /* cluster hash link forward */ + struct xfs_inode *i_cprev; /* cluster hash link backward */ + +#ifdef DEBUG + /* Trace buffers per inode. */ + struct ktrace *i_xtrace; /* inode extent list trace */ + struct ktrace *i_btrace; /* inode bmap btree trace */ + struct ktrace *i_rwtrace; /* inode read/write trace */ + struct ktrace *i_strat_trace; /* inode strat_write trace */ + struct ktrace *i_lock_trace; /* inode lock/unlock trace */ + struct ktrace *i_dir_trace; /* inode directory trace */ +#endif /* DEBUG */ +} xfs_inode_t; + +#endif /* __KERNEL__ */ + + +/* + * Fork handling. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_PTR) +xfs_ifork_t *xfs_ifork_ptr(xfs_inode_t *ip, int w); +#define XFS_IFORK_PTR(ip,w) xfs_ifork_ptr(ip,w) +#else +#define XFS_IFORK_PTR(ip,w) ((w) == XFS_DATA_FORK ? &(ip)->i_df : (ip)->i_afp) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_Q) +int xfs_ifork_q(xfs_inode_t *ip); +#define XFS_IFORK_Q(ip) xfs_ifork_q(ip) +#else +#define XFS_IFORK_Q(ip) XFS_CFORK_Q(&(ip)->i_d) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_DSIZE) +int xfs_ifork_dsize(xfs_inode_t *ip); +#define XFS_IFORK_DSIZE(ip) xfs_ifork_dsize(ip) +#else +#define XFS_IFORK_DSIZE(ip) XFS_CFORK_DSIZE(&ip->i_d, ip->i_mount) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_ASIZE) +int xfs_ifork_asize(xfs_inode_t *ip); +#define XFS_IFORK_ASIZE(ip) xfs_ifork_asize(ip) +#else +#define XFS_IFORK_ASIZE(ip) XFS_CFORK_ASIZE(&ip->i_d, ip->i_mount) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_SIZE) +int xfs_ifork_size(xfs_inode_t *ip, int w); +#define XFS_IFORK_SIZE(ip,w) xfs_ifork_size(ip,w) +#else +#define XFS_IFORK_SIZE(ip,w) XFS_CFORK_SIZE(&ip->i_d, ip->i_mount, w) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_FORMAT) +int xfs_ifork_format(xfs_inode_t *ip, int w); +#define XFS_IFORK_FORMAT(ip,w) xfs_ifork_format(ip,w) +#else +#define XFS_IFORK_FORMAT(ip,w) XFS_CFORK_FORMAT(&ip->i_d, w) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_FMT_SET) +void xfs_ifork_fmt_set(xfs_inode_t *ip, int w, int n); +#define XFS_IFORK_FMT_SET(ip,w,n) xfs_ifork_fmt_set(ip,w,n) +#else +#define XFS_IFORK_FMT_SET(ip,w,n) XFS_CFORK_FMT_SET(&ip->i_d, w, n) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_NEXTENTS) +int xfs_ifork_nextents(xfs_inode_t *ip, int w); +#define XFS_IFORK_NEXTENTS(ip,w) xfs_ifork_nextents(ip,w) +#else +#define XFS_IFORK_NEXTENTS(ip,w) XFS_CFORK_NEXTENTS(&ip->i_d, w) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_NEXT_SET) +void xfs_ifork_next_set(xfs_inode_t *ip, int w, int n); +#define XFS_IFORK_NEXT_SET(ip,w,n) xfs_ifork_next_set(ip,w,n) +#else +#define XFS_IFORK_NEXT_SET(ip,w,n) XFS_CFORK_NEXT_SET(&ip->i_d, w, n) +#endif + + +#ifdef __KERNEL__ + +/* + * In-core inode flags. + */ +#define XFS_IGRIO 0x0001 /* inode used for guaranteed rate i/o */ +#define XFS_IUIOSZ 0x0002 /* inode i/o sizes have been explicitly set */ +#define XFS_IQUIESCE 0x0004 /* we have started quiescing for this inode */ +#define XFS_IRECLAIM 0x0008 /* we have started reclaiming this inode */ + +/* + * Flags for inode locking. + */ +#define XFS_IOLOCK_EXCL 0x001 +#define XFS_IOLOCK_SHARED 0x002 +#define XFS_ILOCK_EXCL 0x004 +#define XFS_ILOCK_SHARED 0x008 +#define XFS_IUNLOCK_NONOTIFY 0x010 +#define XFS_IOLOCK_NESTED 0x020 +#define XFS_EXTENT_TOKEN_RD 0x040 +#define XFS_SIZE_TOKEN_RD 0x080 +#define XFS_EXTSIZE_RD (XFS_EXTENT_TOKEN_RD|XFS_SIZE_TOKEN_RD) +#define XFS_WILLLEND 0x100 /* Always acquire tokens for lending */ +#define XFS_EXTENT_TOKEN_WR (XFS_EXTENT_TOKEN_RD | XFS_WILLLEND) +#define XFS_SIZE_TOKEN_WR (XFS_SIZE_TOKEN_RD | XFS_WILLLEND) +#define XFS_EXTSIZE_WR (XFS_EXTSIZE_RD | XFS_WILLLEND) + + +#define XFS_LOCK_MASK \ + (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL | \ + XFS_IOLOCK_NESTED | \ + XFS_ILOCK_SHARED | XFS_EXTENT_TOKEN_RD | XFS_SIZE_TOKEN_RD | \ + XFS_WILLLEND) + +/* + * Flags for xfs_iflush() + */ +#define XFS_IFLUSH_DELWRI_ELSE_SYNC 1 +#define XFS_IFLUSH_DELWRI_ELSE_ASYNC 2 +#define XFS_IFLUSH_SYNC 3 +#define XFS_IFLUSH_ASYNC 4 +#define XFS_IFLUSH_DELWRI 5 + +/* + * Flags for xfs_iflush_all. + */ +#define XFS_FLUSH_ALL 0x1 + +/* + * Flags for xfs_itruncate_start(). + */ +#define XFS_ITRUNC_DEFINITE 0x1 +#define XFS_ITRUNC_MAYBE 0x2 + +/* + * Maximum file size. + * if XFS_BIG_FILES 2^63 - 1 (largest positive value of xfs_fsize_t) + * else 2^40 - 1 (40=31+9) (might be an int holding a block #) + * Note, we allow seeks to this offset, although you can't read or write. + * For the not XFS_BIG_FILES case, the value could be 1 higher but we don't + * do that, for symmetry. + */ +#if XFS_BIG_FILES +#define XFS_MAX_FILE_OFFSET ((long long)((1ULL<<63)-1ULL)) +#else +#define XFS_MAX_FILE_OFFSET ((1LL<<40)-1LL) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ITOV) +struct vnode *xfs_itov(xfs_inode_t *ip); +#define XFS_ITOV(ip) xfs_itov(ip) +#else +#define XFS_ITOV(ip) BHV_TO_VNODE(XFS_ITOBHV(ip)) +#endif +#define XFS_ITOV_NULL(ip) BHV_TO_VNODE_NULL(XFS_ITOBHV(ip)) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ITOBHV) +struct bhv_desc *xfs_itobhv(xfs_inode_t *ip); +#define XFS_ITOBHV(ip) xfs_itobhv(ip) +#else +#define XFS_ITOBHV(ip) ((struct bhv_desc *)(&((ip)->i_bhv_desc))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BHVTOI) +xfs_inode_t *xfs_bhvtoi(struct bhv_desc *bhvp); +#define XFS_BHVTOI(bhvp) xfs_bhvtoi(bhvp) +#else +#define XFS_BHVTOI(bhvp) \ + ((xfs_inode_t *)((char *)(bhvp) - \ + (char *)&(((xfs_inode_t *)0)->i_bhv_desc))) +#endif + +#define BHV_IS_XFS(bdp) (BHV_OPS(bdp) == &xfs_vnodeops) + +/* + * Pick the inode cluster hash bucket + * (m_chash is the same size as m_ihash) + */ +#define XFS_CHASH(mp,blk) ((mp)->m_chash + (((uint)blk) % (mp)->m_chsize)) + +/* + * For multiple groups support: if ISGID bit is set in the parent + * directory, group of new file is set to that of the parent, and + * new subdirectory gets ISGID bit from parent. + */ +#define XFS_INHERIT_GID(pip, vfsp) ((pip) != NULL && \ + (((vfsp)->vfs_flag & VFS_GRPID) || ((pip)->i_d.di_mode & ISGID))) + +/* + * xfs_iget.c prototypes. + */ +void xfs_ihash_init(struct xfs_mount *); +void xfs_ihash_free(struct xfs_mount *); +void xfs_chash_init(struct xfs_mount *); +void xfs_chash_free(struct xfs_mount *); +xfs_inode_t *xfs_inode_incore(struct xfs_mount *, xfs_ino_t, + struct xfs_trans *); +void xfs_inode_lock_init(xfs_inode_t *, struct vnode *); +int xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, + uint, xfs_inode_t **, xfs_daddr_t); +int xfs_vn_iget(vfs_t *, struct vnode *, xfs_ino_t); +void xfs_iput(xfs_inode_t *, uint); +void xfs_ilock(xfs_inode_t *, uint); +int xfs_ilock_nowait(xfs_inode_t *, uint); +void xfs_iunlock(xfs_inode_t *, uint); +void xfs_ilock_demote(xfs_inode_t *, uint); +void xfs_iflock(xfs_inode_t *); +int xfs_iflock_nowait(xfs_inode_t *); +uint xfs_ilock_map_shared(xfs_inode_t *); +void xfs_iunlock_map_shared(xfs_inode_t *, uint); +void xfs_ifunlock(xfs_inode_t *); +void xfs_ireclaim(xfs_inode_t *); +int xfs_finish_reclaim(xfs_inode_t *, int, int); + +/* + * xfs_inode.c prototypes. + */ +int xfs_inotobp(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, + xfs_dinode_t **, struct xfs_buf **, int *); +int xfs_itobp(struct xfs_mount *, struct xfs_trans *, + xfs_inode_t *, xfs_dinode_t **, struct xfs_buf **, + xfs_daddr_t); +int xfs_iread(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, + xfs_inode_t **, xfs_daddr_t); +int xfs_iread_extents(struct xfs_trans *, xfs_inode_t *, int); +int xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t, nlink_t, + dev_t, struct cred *, xfs_prid_t, int, + struct xfs_buf **, boolean_t *, xfs_inode_t **); +void xfs_xlate_dinode_core(xfs_caddr_t, struct xfs_dinode_core *, int, + xfs_arch_t); +int xfs_ifree(struct xfs_trans *, xfs_inode_t *); +int xfs_atruncate_start(xfs_inode_t *); +void xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t); +int xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *, + xfs_fsize_t, int, int); +int xfs_iunlink(struct xfs_trans *, xfs_inode_t *); +int xfs_igrow_start(xfs_inode_t *, xfs_fsize_t, struct cred *); +void xfs_igrow_finish(struct xfs_trans *, xfs_inode_t *, + xfs_fsize_t, int); + +void xfs_idestroy_fork(xfs_inode_t *, int); +void xfs_idestroy(xfs_inode_t *); +void xfs_idata_realloc(xfs_inode_t *, int, int); +void xfs_iextract(xfs_inode_t *); +void xfs_iext_realloc(xfs_inode_t *, int, int); +void xfs_iroot_realloc(xfs_inode_t *, int, int); +void xfs_ipin(xfs_inode_t *); +void xfs_iunpin(xfs_inode_t *); +unsigned int xfs_ipincount(xfs_inode_t *); +int xfs_iextents_copy(xfs_inode_t *, xfs_bmbt_rec_32_t *, int); +int xfs_iflush(xfs_inode_t *, uint); +int xfs_iflush_all(struct xfs_mount *, int); +int xfs_ibusy_check(xfs_inode_t *, int); +int xfs_iaccess(xfs_inode_t *, mode_t, cred_t *); +uint xfs_iroundup(uint); +void xfs_ichgtime(xfs_inode_t *, int); +xfs_fsize_t xfs_file_last_byte(xfs_inode_t *); +xfs_inode_t *xfs_get_inode(dev_t, xfs_ino_t); +void xfs_lock_inodes(xfs_inode_t **, int, int, uint); + + +#ifdef DEBUG +void xfs_isize_check(struct xfs_mount *, xfs_inode_t *, xfs_fsize_t); +#else /* DEBUG */ +#define xfs_isize_check(mp, ip, isize) +#endif /* DEBUG */ + +#if defined(DEBUG) +void xfs_inobp_check(struct xfs_mount *, struct xfs_buf *); +#else +#define xfs_inobp_check(mp, bp) +#endif /* DEBUG */ + +extern struct xfs_zone *xfs_chashlist_zone; +extern struct xfs_zone *xfs_ifork_zone; +extern struct xfs_zone *xfs_inode_zone; +extern struct xfs_zone *xfs_ili_zone; +extern struct vnodeops xfs_vnodeops; + +#ifdef XFS_ILOCK_TRACE +#define XFS_ILOCK_KTRACE_SIZE 32 +void xfs_ilock_trace(xfs_inode_t *ip, int lock, unsigned int lockflags, + inst_t *ra); +#endif + +#endif /* __KERNEL__ */ + +#endif /* __XFS_INODE_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_inode_item.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_inode_item.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_inode_item.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_inode_item.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_INODE_ITEM_H__ +#define __XFS_INODE_ITEM_H__ + +/* + * This is the structure used to lay out an inode log item in the + * log. The size of the inline data/extents/b-tree root to be logged + * (if any) is indicated in the ilf_dsize field. Changes to this structure + * must be added on to the end. + * + * Convention for naming inode log item versions : The current version + * is always named XFS_LI_INODE. When an inode log item gets superseded, + * add the latest version of IRIX that will generate logs with that item + * to the version name. + * + * -Version 1 of this structure (XFS_LI_5_3_INODE) included up to the first + * union (ilf_u) field. This was released with IRIX 5.3-XFS. + * -Version 2 of this structure (XFS_LI_6_1_INODE) is currently the entire + * structure. This was released with IRIX 6.0.1-XFS and IRIX 6.1. + * -Version 3 of this structure (XFS_LI_INODE) is the same as version 2 + * so a new structure definition wasn't necessary. However, we had + * to add a new type because the inode cluster size changed from 4K + * to 8K and the version number had to be rev'ved to keep older kernels + * from trying to recover logs with the 8K buffers in them. The logging + * code can handle recovery on different-sized clusters now so hopefully + * this'll be the last time we need to change the inode log item just + * for a change in the inode cluster size. This new version was + * released with IRIX 6.2. + */ +typedef struct xfs_inode_log_format { + unsigned short ilf_type; /* inode log item type */ + unsigned short ilf_size; /* size of this item */ + uint ilf_fields; /* flags for fields logged */ + ushort ilf_asize; /* size of attr d/ext/root */ + ushort ilf_dsize; /* size of data/ext/root */ + xfs_ino_t ilf_ino; /* inode number */ + union { + xfs_dev_t ilfu_rdev; /* rdev value for dev inode*/ + uuid_t ilfu_uuid; /* mount point value */ + } ilf_u; + __int64_t ilf_blkno; /* blkno of inode buffer */ + int ilf_len; /* len of inode buffer */ + int ilf_boffset; /* off of inode in buffer */ +} xfs_inode_log_format_t; + +/* Initial version shipped with IRIX 5.3-XFS */ +typedef struct xfs_inode_log_format_v1 { + unsigned short ilf_type; /* inode log item type */ + unsigned short ilf_size; /* size of this item */ + uint ilf_fields; /* flags for fields logged */ + uint ilf_dsize; /* size of data/ext/root */ + xfs_ino_t ilf_ino; /* inode number */ + union { + xfs_dev_t ilfu_rdev; /* rdev value for dev inode*/ + uuid_t ilfu_uuid; /* mount point value */ + } ilf_u; +} xfs_inode_log_format_t_v1; + +/* + * Flags for xfs_trans_log_inode flags field. + */ +#define XFS_ILOG_CORE 0x001 /* log standard inode fields */ +#define XFS_ILOG_DDATA 0x002 /* log i_df.if_data */ +#define XFS_ILOG_DEXT 0x004 /* log i_df.if_extents */ +#define XFS_ILOG_DBROOT 0x008 /* log i_df.i_broot */ +#define XFS_ILOG_DEV 0x010 /* log the dev field */ +#define XFS_ILOG_UUID 0x020 /* log the uuid field */ +#define XFS_ILOG_ADATA 0x040 /* log i_af.if_data */ +#define XFS_ILOG_AEXT 0x080 /* log i_af.if_extents */ +#define XFS_ILOG_ABROOT 0x100 /* log i_af.i_broot */ + +#define XFS_ILOG_NONCORE (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ + XFS_ILOG_DBROOT | XFS_ILOG_DEV | \ + XFS_ILOG_UUID | XFS_ILOG_ADATA | \ + XFS_ILOG_AEXT | XFS_ILOG_ABROOT) + +#define XFS_ILOG_DFORK (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ + XFS_ILOG_DBROOT) + +#define XFS_ILOG_AFORK (XFS_ILOG_ADATA | XFS_ILOG_AEXT | \ + XFS_ILOG_ABROOT) + +#define XFS_ILOG_ALL (XFS_ILOG_CORE | XFS_ILOG_DDATA | \ + XFS_ILOG_DEXT | XFS_ILOG_DBROOT | \ + XFS_ILOG_DEV | XFS_ILOG_UUID | \ + XFS_ILOG_ADATA | XFS_ILOG_AEXT | \ + XFS_ILOG_ABROOT) + +#define XFS_ILI_HOLD 0x1 +#define XFS_ILI_IOLOCKED_EXCL 0x2 +#define XFS_ILI_IOLOCKED_SHARED 0x4 + +#define XFS_ILI_IOLOCKED_ANY (XFS_ILI_IOLOCKED_EXCL | XFS_ILI_IOLOCKED_SHARED) + + +#ifdef __KERNEL__ + +struct xfs_buf; +struct xfs_bmbt_rec_32; +struct xfs_inode; +struct xfs_mount; + + +typedef struct xfs_inode_log_item { + xfs_log_item_t ili_item; /* common portion */ + struct xfs_inode *ili_inode; /* inode ptr */ + xfs_lsn_t ili_flush_lsn; /* lsn at last flush */ + xfs_lsn_t ili_last_lsn; /* lsn at last transaction */ + unsigned short ili_ilock_recur; /* lock recursion count */ + unsigned short ili_iolock_recur; /* lock recursion count */ + unsigned short ili_flags; /* misc flags */ + unsigned short ili_logged; /* flushed logged data */ + unsigned int ili_last_fields; /* fields when flushed */ + struct xfs_bmbt_rec_32 *ili_extents_buf; /* array of logged exts */ + unsigned int ili_pushbuf_flag; /* one bit used in push_ail */ + +#ifdef DEBUG + uint64_t ili_push_owner; /* one who sets pushbuf_flag + above gets to push the buf */ +#endif +#ifdef XFS_TRANS_DEBUG + int ili_root_size; + char *ili_orig_root; +#endif + xfs_inode_log_format_t ili_format; /* logged structure */ +} xfs_inode_log_item_t; + + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ILOG_FDATA) +int xfs_ilog_fdata(int w); +#define XFS_ILOG_FDATA(w) xfs_ilog_fdata(w) +#else +#define XFS_ILOG_FDATA(w) \ + ((w) == XFS_DATA_FORK ? XFS_ILOG_DDATA : XFS_ILOG_ADATA) +#endif + +#endif /* __KERNEL__ */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ILOG_FBROOT) +int xfs_ilog_fbroot(int w); +#define XFS_ILOG_FBROOT(w) xfs_ilog_fbroot(w) +#else +#define XFS_ILOG_FBROOT(w) \ + ((w) == XFS_DATA_FORK ? XFS_ILOG_DBROOT : XFS_ILOG_ABROOT) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ILOG_FEXT) +int xfs_ilog_fext(int w); +#define XFS_ILOG_FEXT(w) xfs_ilog_fext(w) +#else +#define XFS_ILOG_FEXT(w) \ + ((w) == XFS_DATA_FORK ? XFS_ILOG_DEXT : XFS_ILOG_AEXT) +#endif + +#ifdef __KERNEL__ + +void xfs_inode_item_init(struct xfs_inode *, struct xfs_mount *); +void xfs_inode_item_destroy(struct xfs_inode *); +void xfs_iflush_done(struct xfs_buf *, xfs_inode_log_item_t *); +void xfs_iflush_abort(struct xfs_inode *); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_INODE_ITEM_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_inum.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_inum.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_inum.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_inum.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_INUM_H__ +#define __XFS_INUM_H__ + +/* + * Inode number format: + * low inopblog bits - offset in block + * next agblklog bits - block number in ag + * next agno_log bits - ag number + * high agno_log-agblklog-inopblog bits - 0 + */ + +typedef __uint32_t xfs_agino_t; /* within allocation grp inode number */ + +/* + * Useful inode bits for this kernel. + * Used in some places where having 64-bits in the 32-bit kernels + * costs too much. + */ +#if XFS_BIG_FILESYSTEMS +typedef xfs_ino_t xfs_intino_t; +#else +typedef __uint32_t xfs_intino_t; +#endif + +#define NULLFSINO ((xfs_ino_t)-1) +#define NULLAGINO ((xfs_agino_t)-1) + +struct xfs_mount; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_MASK) +__uint32_t xfs_ino_mask(int k); +#define XFS_INO_MASK(k) xfs_ino_mask(k) +#else +#define XFS_INO_MASK(k) ((__uint32_t)((1ULL << (k)) - 1)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_OFFSET_BITS) +int xfs_ino_offset_bits(struct xfs_mount *mp); +#define XFS_INO_OFFSET_BITS(mp) xfs_ino_offset_bits(mp) +#else +#define XFS_INO_OFFSET_BITS(mp) ((mp)->m_sb.sb_inopblog) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_AGBNO_BITS) +int xfs_ino_agbno_bits(struct xfs_mount *mp); +#define XFS_INO_AGBNO_BITS(mp) xfs_ino_agbno_bits(mp) +#else +#define XFS_INO_AGBNO_BITS(mp) ((mp)->m_sb.sb_agblklog) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_AGINO_BITS) +int xfs_ino_agino_bits(struct xfs_mount *mp); +#define XFS_INO_AGINO_BITS(mp) xfs_ino_agino_bits(mp) +#else +#define XFS_INO_AGINO_BITS(mp) ((mp)->m_agino_log) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_AGNO_BITS) +int xfs_ino_agno_bits(struct xfs_mount *mp); +#define XFS_INO_AGNO_BITS(mp) xfs_ino_agno_bits(mp) +#else +#define XFS_INO_AGNO_BITS(mp) ((mp)->m_agno_log) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_BITS) +int xfs_ino_bits(struct xfs_mount *mp); +#define XFS_INO_BITS(mp) xfs_ino_bits(mp) +#else +#define XFS_INO_BITS(mp) (XFS_INO_AGNO_BITS(mp) + XFS_INO_AGINO_BITS(mp)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_TO_AGNO) +xfs_agnumber_t xfs_ino_to_agno(struct xfs_mount *mp, xfs_ino_t i); +#define XFS_INO_TO_AGNO(mp,i) xfs_ino_to_agno(mp,i) +#else +#define XFS_INO_TO_AGNO(mp,i) \ + ((xfs_agnumber_t)((i) >> XFS_INO_AGINO_BITS(mp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_TO_AGINO) +xfs_agino_t xfs_ino_to_agino(struct xfs_mount *mp, xfs_ino_t i); +#define XFS_INO_TO_AGINO(mp,i) xfs_ino_to_agino(mp,i) +#else +#define XFS_INO_TO_AGINO(mp,i) \ + ((xfs_agino_t)(i) & XFS_INO_MASK(XFS_INO_AGINO_BITS(mp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_TO_AGBNO) +xfs_agblock_t xfs_ino_to_agbno(struct xfs_mount *mp, xfs_ino_t i); +#define XFS_INO_TO_AGBNO(mp,i) xfs_ino_to_agbno(mp,i) +#else +#define XFS_INO_TO_AGBNO(mp,i) \ + (((xfs_agblock_t)(i) >> XFS_INO_OFFSET_BITS(mp)) & \ + XFS_INO_MASK(XFS_INO_AGBNO_BITS(mp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_TO_OFFSET) +int xfs_ino_to_offset(struct xfs_mount *mp, xfs_ino_t i); +#define XFS_INO_TO_OFFSET(mp,i) xfs_ino_to_offset(mp,i) +#else +#define XFS_INO_TO_OFFSET(mp,i) \ + ((int)(i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(mp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_TO_FSB) +xfs_fsblock_t xfs_ino_to_fsb(struct xfs_mount *mp, xfs_ino_t i); +#define XFS_INO_TO_FSB(mp,i) xfs_ino_to_fsb(mp,i) +#else +#define XFS_INO_TO_FSB(mp,i) \ + XFS_AGB_TO_FSB(mp, XFS_INO_TO_AGNO(mp,i), XFS_INO_TO_AGBNO(mp,i)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGINO_TO_INO) +xfs_ino_t +xfs_agino_to_ino(struct xfs_mount *mp, xfs_agnumber_t a, xfs_agino_t i); +#define XFS_AGINO_TO_INO(mp,a,i) xfs_agino_to_ino(mp,a,i) +#else +#define XFS_AGINO_TO_INO(mp,a,i) \ + (((xfs_ino_t)(a) << XFS_INO_AGINO_BITS(mp)) | (i)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGINO_TO_AGBNO) +xfs_agblock_t xfs_agino_to_agbno(struct xfs_mount *mp, xfs_agino_t i); +#define XFS_AGINO_TO_AGBNO(mp,i) xfs_agino_to_agbno(mp,i) +#else +#define XFS_AGINO_TO_AGBNO(mp,i) ((i) >> XFS_INO_OFFSET_BITS(mp)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGINO_TO_OFFSET) +int xfs_agino_to_offset(struct xfs_mount *mp, xfs_agino_t i); +#define XFS_AGINO_TO_OFFSET(mp,i) xfs_agino_to_offset(mp,i) +#else +#define XFS_AGINO_TO_OFFSET(mp,i) \ + ((i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(mp))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_OFFBNO_TO_AGINO) +xfs_agino_t xfs_offbno_to_agino(struct xfs_mount *mp, xfs_agblock_t b, int o); +#define XFS_OFFBNO_TO_AGINO(mp,b,o) xfs_offbno_to_agino(mp,b,o) +#else +#define XFS_OFFBNO_TO_AGINO(mp,b,o) \ + ((xfs_agino_t)(((b) << XFS_INO_OFFSET_BITS(mp)) | (o))) +#endif + +#if XFS_BIG_FILESYSTEMS +#define XFS_MAXINUMBER ((xfs_ino_t)((1ULL << 56) - 1ULL)) +#define XFS_INO64_OFFSET ((xfs_ino_t)(1ULL << 32)) +#else +#define XFS_MAXINUMBER ((xfs_ino_t)((1ULL << 32) - 1ULL)) +#endif +#define XFS_MAXINUMBER_32 ((xfs_ino_t)((1ULL << 32) - 1ULL)) + +#endif /* __XFS_INUM_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_log.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_log.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_log.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_log.h Wed Apr 18 21:29:42 2001 @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_LOG_H__ +#define __XFS_LOG_H__ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define LSN_FIELD_CYCLE(arch) (((arch)==ARCH_NOCONVERT)?1:0) +#define LSN_FIELD_BLOCK(arch) (((arch)==ARCH_NOCONVERT)?0:1) +#else +#define LSN_FIELD_CYCLE(arch) (0) +#define LSN_FIELD_BLOCK(arch) (1) +#endif + +/* get lsn fields */ + +#define CYCLE_LSN(lsn,arch) (INT_GET(((uint *)&(lsn))[LSN_FIELD_CYCLE(arch)], arch)) +#define BLOCK_LSN(lsn,arch) (INT_GET(((uint *)&(lsn))[LSN_FIELD_BLOCK(arch)], arch)) + +#ifdef __KERNEL__ +/* + * By comparing each compnent, we don't have to worry about extra + * endian issues in treating two 32 bit numbers as one 64 bit number + */ +static +#ifdef __GNUC__ +# if !((__GNUC__ == 2) && (__GNUC_MINOR__ == 95)) +__inline__ +#endif +#endif +xfs_lsn_t _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2, xfs_arch_t arch) +{ + if (CYCLE_LSN(lsn1, arch) != CYCLE_LSN(lsn2, arch)) + return (CYCLE_LSN(lsn1, arch)> XLOG_RECORD_BSHIFT) +#endif + +#define XLOG_HEADER_SIZE 512 + +/* + * set lsns + */ + +#define ASSIGN_LSN_CYCLE(lsn,cycle,arch) \ + INT_SET(((uint *)&(lsn))[LSN_FIELD_CYCLE(arch)], arch, (cycle)); +#define ASSIGN_LSN_BLOCK(lsn,block,arch) \ + INT_SET(((uint *)&(lsn))[LSN_FIELD_BLOCK(arch)], arch, (block)); +#define ASSIGN_ANY_LSN(lsn,cycle,block,arch) \ + { \ + ASSIGN_LSN_CYCLE(lsn,cycle,arch); \ + ASSIGN_LSN_BLOCK(lsn,block,arch); \ + } +#define ASSIGN_LSN(lsn,log,arch) \ + ASSIGN_ANY_LSN(lsn,(log)->l_curr_cycle,(log)->l_curr_block,arch); + +#define XLOG_SET(f,b) (((f) & (b)) == (b)) + +#define GET_CYCLE(ptr, arch) \ + (INT_GET(*(uint *)(ptr), arch) == XLOG_HEADER_MAGIC_NUM ? \ + INT_GET(*((uint *)(ptr)+1), arch) : \ + INT_GET(*(uint *)(ptr), arch) \ + ) + +#define BLK_AVG(blk1, blk2) ((blk1+blk2) >> 1) + + +#ifdef __KERNEL__ +/* + * get client id from packed copy. + * + * this hack is here because the xlog_pack code copies four bytes + * of xlog_op_header containing the fields oh_clientid, oh_flags + * and oh_res2 into the packed copy. + * + * later on this four byte chunk is treated as an int and the + * client id is pulled out. + * + * this has endian issues, of course. + */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define GET_CLIENT_ID(i,arch) \ + ((i) & 0xff) +#else +#define GET_CLIENT_ID(i,arch) \ + ((i) >> 24) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XLOG_GRANT_SUB_SPACE) +void xlog_grant_sub_space(struct log *log, int bytes, int type); +#define XLOG_GRANT_SUB_SPACE(log,bytes,type) \ + xlog_grant_sub_space(log,bytes,type) +#else +#define XLOG_GRANT_SUB_SPACE(log,bytes,type) \ + { \ + if (type == 'w') { \ + (log)->l_grant_write_bytes -= (bytes); \ + if ((log)->l_grant_write_bytes < 0) { \ + (log)->l_grant_write_bytes += (log)->l_logsize; \ + (log)->l_grant_write_cycle--; \ + } \ + } else { \ + (log)->l_grant_reserve_bytes -= (bytes); \ + if ((log)->l_grant_reserve_bytes < 0) { \ + (log)->l_grant_reserve_bytes += (log)->l_logsize;\ + (log)->l_grant_reserve_cycle--; \ + } \ + } \ + } +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XLOG_GRANT_ADD_SPACE) +void xlog_grant_add_space(struct log *log, int bytes, int type); +#define XLOG_GRANT_ADD_SPACE(log,bytes,type) \ + xlog_grant_add_space(log,bytes,type) +#else +#define XLOG_GRANT_ADD_SPACE(log,bytes,type) \ + { \ + if (type == 'w') { \ + (log)->l_grant_write_bytes += (bytes); \ + if ((log)->l_grant_write_bytes > (log)->l_logsize) { \ + (log)->l_grant_write_bytes -= (log)->l_logsize; \ + (log)->l_grant_write_cycle++; \ + } \ + } else { \ + (log)->l_grant_reserve_bytes += (bytes); \ + if ((log)->l_grant_reserve_bytes > (log)->l_logsize) { \ + (log)->l_grant_reserve_bytes -= (log)->l_logsize;\ + (log)->l_grant_reserve_cycle++; \ + } \ + } \ + } +#endif +#define XLOG_INS_TICKETQ(q,tic) \ + { \ + if (q) { \ + (tic)->t_next = (q); \ + (tic)->t_prev = (q)->t_prev; \ + (q)->t_prev->t_next = (tic); \ + (q)->t_prev = (tic); \ + } else { \ + (tic)->t_prev = (tic)->t_next = (tic); \ + (q) = (tic); \ + } \ + (tic)->t_flags |= XLOG_TIC_IN_Q; \ + } +#define XLOG_DEL_TICKETQ(q,tic) \ + { \ + if ((tic) == (tic)->t_next) { \ + (q) = NULL; \ + } else { \ + (q) = (tic)->t_next; \ + (tic)->t_next->t_prev = (tic)->t_prev; \ + (tic)->t_prev->t_next = (tic)->t_next; \ + } \ + (tic)->t_next = (tic)->t_prev = NULL; \ + (tic)->t_flags &= ~XLOG_TIC_IN_Q; \ + } + + +#define GRANT_LOCK(log) mutex_spinlock(&(log)->l_grant_lock) +#define GRANT_UNLOCK(log, s) mutex_spinunlock(&(log)->l_grant_lock, s) +#define LOG_LOCK(log) mutex_spinlock(&(log)->l_icloglock) +#define LOG_UNLOCK(log, s) mutex_spinunlock(&(log)->l_icloglock, s) + +#define xlog_panic(s) {cmn_err(CE_PANIC, s); } +#define xlog_exit(s) {cmn_err(CE_PANIC, s); } +#define xlog_warn(s) {cmn_err(CE_WARN, s); } + +/* + * In core log state + */ +#define XLOG_STATE_ACTIVE 0x0001 /* Current IC log being written to */ +#define XLOG_STATE_WANT_SYNC 0x0002 /* Want to sync this iclog; no more writes */ +#define XLOG_STATE_SYNCING 0x0004 /* This IC log is syncing */ +#define XLOG_STATE_DONE_SYNC 0x0008 /* Done syncing to disk */ +#define XLOG_STATE_DO_CALLBACK \ + 0x0010 /* Process callback functions */ +#define XLOG_STATE_CALLBACK 0x0020 /* Callback functions now */ +#define XLOG_STATE_DIRTY 0x0040 /* Dirty IC log, not ready for ACTIVE status*/ +#define XLOG_STATE_IOERROR 0x0080 /* IO error happened in sync'ing log */ +#define XLOG_STATE_ALL 0x7FFF /* All possible valid flags */ +#define XLOG_STATE_NOTUSED 0x8000 /* This IC log not being used */ +#endif /* __KERNEL__ */ + +/* + * Flags to log operation header + * + * The first write of a new transaction will be preceded with a start + * record, XLOG_START_TRANS. Once a transaction is committed, a commit + * record is written, XLOG_COMMIT_TRANS. If a single region can not fit into + * the remainder of the current active in-core log, it is split up into + * multiple regions. Each partial region will be marked with a + * XLOG_CONTINUE_TRANS until the last one, which gets marked with XLOG_END_TRANS. + * + */ +#define XLOG_START_TRANS 0x01 /* Start a new transaction */ +#define XLOG_COMMIT_TRANS 0x02 /* Commit this transaction */ +#define XLOG_CONTINUE_TRANS 0x04 /* Cont this trans into new region */ +#define XLOG_WAS_CONT_TRANS 0x08 /* Cont this trans into new region */ +#define XLOG_END_TRANS 0x10 /* End a continued transaction */ +#define XLOG_UNMOUNT_TRANS 0x20 /* Unmount a filesystem transaction */ +#define XLOG_SKIP_TRANS (XLOG_COMMIT_TRANS | XLOG_CONTINUE_TRANS | \ + XLOG_WAS_CONT_TRANS | XLOG_END_TRANS | \ + XLOG_UNMOUNT_TRANS) + +#ifdef __KERNEL__ +/* + * Flags to log ticket + */ +#define XLOG_TIC_INITED 0x1 /* has been initialized */ +#define XLOG_TIC_PERM_RESERV 0x2 /* permanent reservation */ +#define XLOG_TIC_IN_Q 0x4 +#endif /* __KERNEL__ */ + +#define XLOG_UNMOUNT_TYPE 0x556e /* Un for Unmount */ + +/* + * Flags for log structure + */ +#define XLOG_CHKSUM_MISMATCH 0x1 /* used only during recovery */ +#define XLOG_ACTIVE_RECOVERY 0x2 /* in the middle of recovery */ +#define XLOG_RECOVERY_NEEDED 0x4 /* log was recovered */ +#define XLOG_IO_ERROR 0x8 /* log hit an I/O error, and being + shutdown */ +typedef __uint32_t xlog_tid_t; + + +#ifdef __KERNEL__ +/* + * Below are states for covering allocation transactions. + * By covering, we mean changing the h_tail_lsn in the last on-disk + * log write such that no allocation transactions will be re-done during + * recovery after a system crash. Recovery starts at the last on-disk + * log write. + * + * These states are used to insert dummy log entries to cover + * space allocation transactions which can undo non-transactional changes + * after a crash. Writes to a file with space + * already allocated do not result in any transactions. Allocations + * might include space beyond the EOF. So if we just push the EOF a + * little, the last transaction for the file could contain the wrong + * size. If there is no file system activity, after an allocation + * transaction, and the system crashes, the allocation transaction + * will get replayed and the file will be truncated. This could + * be hours/days/... after the allocation occurred. + * + * The fix for this is to do two dummy transactions when the + * system is idle. We need two dummy transaction because the h_tail_lsn + * in the log record header needs to point beyond the last possible + * non-dummy transaction. The first dummy changes the h_tail_lsn to + * the first transaction before the dummy. The second dummy causes + * h_tail_lsn to point to the first dummy. Recovery starts at h_tail_lsn. + * + * These dummy transactions get committed when everything + * is idle (after there has been some activity). + * + * There are 5 states used to control this. + * + * IDLE -- no logging has been done on the file system or + * we are done covering previous transactions. + * NEED -- logging has occurred and we need a dummy transaction + * when the log becomes idle. + * DONE -- we were in the NEED state and have committed a dummy + * transaction. + * NEED2 -- we detected that a dummy transaction has gone to the + * on disk log with no other transactions. + * DONE2 -- we committed a dummy transaction when in the NEED2 state. + * + * There are two places where we switch states: + * + * 1.) In xfs_sync, when we detect an idle log and are in NEED or NEED2. + * We commit the dummy transaction and switch to DONE or DONE2, + * respectively. In all other states, we don't do anything. + * + * 2.) When we finish writing the on-disk log (xlog_state_clean_log). + * + * No matter what state we are in, if this isn't the dummy + * transaction going out, the next state is NEED. + * So, if we aren't in the DONE or DONE2 states, the next state + * is NEED. We can't be finishing a write of the dummy record + * unless it was committed and the state switched to DONE or DONE2. + * + * If we are in the DONE state and this was a write of the + * dummy transaction, we move to NEED2. + * + * If we are in the DONE2 state and this was a write of the + * dummy transaction, we move to IDLE. + * + * + * Writing only one dummy transaction can get appended to + * one file space allocation. When this happens, the log recovery + * code replays the space allocation and a file could be truncated. + * This is why we have the NEED2 and DONE2 states before going idle. + */ + +#define XLOG_STATE_COVER_IDLE 0 +#define XLOG_STATE_COVER_NEED 1 +#define XLOG_STATE_COVER_DONE 2 +#define XLOG_STATE_COVER_NEED2 3 +#define XLOG_STATE_COVER_DONE2 4 + +#define XLOG_COVER_OPS 5 + +typedef struct xlog_ticket { + sv_t t_sema; /* sleep on this semaphore :20 */ + struct xlog_ticket *t_next; /* : 4 */ + struct xlog_ticket *t_prev; /* : 4 */ + xlog_tid_t t_tid; /* transaction identifier : 4 */ + int t_curr_res; /* current reservation in bytes : 4 */ + int t_unit_res; /* unit reservation in bytes : 4 */ + char t_ocnt; /* original count : 1 */ + char t_cnt; /* current count : 1 */ + char t_clientid; /* who does this belong to; : 1 */ + char t_flags; /* properties of reservation : 1 */ +} xlog_ticket_t; +#endif + + +typedef struct xlog_op_header { + xlog_tid_t oh_tid; /* transaction id of operation : 4 b */ + int oh_len; /* bytes in data region : 2 b */ + char oh_clientid; /* who sent me this : 1 b */ + char oh_flags; /* : 1 b */ + ushort oh_res2; /* 32 bit align : 2 b */ +} xlog_op_header_t; + + +/* valid values for h_fmt */ +#define XLOG_FMT_UNKNOWN 0 +#define XLOG_FMT_LINUX_LE 1 +#define XLOG_FMT_LINUX_BE 2 +#define XLOG_FMT_IRIX_BE 3 + +/* our fmt */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define XLOG_FMT XLOG_FMT_LINUX_LE +#else +#if __BYTE_ORDER == __BIG_ENDIAN +#define XLOG_FMT XLOG_FMT_LINUX_BE +#else +#error unknown byte order +#endif +#endif + +typedef struct xlog_rec_header { + uint h_magicno; /* log record (LR) identifier : 4 */ + uint h_cycle; /* write cycle of log : 4 */ + int h_version; /* LR version : 4 */ + int h_len; /* len in bytes; should be 64-bit aligned: 4 */ + xfs_lsn_t h_lsn; /* lsn of this LR : 8 */ + xfs_lsn_t h_tail_lsn; /* lsn of 1st LR w/ buffers not committed: 8 */ + uint h_chksum; /* may not be used; non-zero if used : 4 */ + int h_prev_block; /* block number to previous LR : 4 */ + int h_num_logops; /* number of log operations in this LR : 4 */ + uint h_cycle_data[XLOG_MAX_RECORD_BSIZE / BBSIZE]; + /* new fields */ + int h_fmt; /* format of log record : 4 */ + uuid_t h_fs_uuid; /* uuid of FS : 16 */ +} xlog_rec_header_t; + +#ifdef __KERNEL__ +/* + * - A log record header is 512 bytes. There is plenty of room to grow the + * xlog_rec_header_t into the reserved space. + * - ic_data follows, so a write to disk can start at the beginning of + * the iclog. + * - ic_forcesema is used to implement synchronous forcing of the iclog to disk. + * - ic_next is the pointer to the next iclog in the ring. + * - ic_bp is a pointer to the buffer used to write this incore log to disk. + * - ic_log is a pointer back to the global log structure. + * - ic_callback is a linked list of callback function/argument pairs to be + * called after an iclog finishes writing. + * - ic_size is the full size of the header plus data. + * - ic_offset is the current number of bytes written to in this iclog. + * - ic_refcnt is bumped when someone is writing to the log. + * - ic_state is the state of the iclog. + */ +typedef struct xlog_iclog_fields { + sv_t ic_forcesema; + struct xlog_in_core *ic_next; + struct xlog_in_core *ic_prev; + struct xfs_buf *ic_bp; + struct log *ic_log; + xfs_log_callback_t *ic_callback; + xfs_log_callback_t **ic_callback_tail; +#ifdef DEBUG + struct ktrace *ic_trace; +#endif + int ic_size; + int ic_offset; + int ic_refcnt; + int ic_roundoff; + int ic_bwritecnt; + ushort_t ic_state; +} xlog_iclog_fields_t; + +typedef struct xlog_in_core { + union { + xlog_iclog_fields_t hic_fields; + char hic_pad[BBSIZE]; + } ic_h1; + union { + xlog_rec_header_t hic_header; + char hic_sector[XLOG_HEADER_SIZE]; + } ic_h2; + char ic_data[1]; +} xlog_in_core_t; + +/* + * Defines to save our code from this glop. + */ +#define ic_forcesema ic_h1.hic_fields.ic_forcesema +#define ic_next ic_h1.hic_fields.ic_next +#define ic_prev ic_h1.hic_fields.ic_prev +#define ic_bp ic_h1.hic_fields.ic_bp +#define ic_log ic_h1.hic_fields.ic_log +#define ic_callback ic_h1.hic_fields.ic_callback +#define ic_callback_tail ic_h1.hic_fields.ic_callback_tail +#define ic_trace ic_h1.hic_fields.ic_trace +#define ic_size ic_h1.hic_fields.ic_size +#define ic_offset ic_h1.hic_fields.ic_offset +#define ic_refcnt ic_h1.hic_fields.ic_refcnt +#define ic_roundoff ic_h1.hic_fields.ic_roundoff +#define ic_bwritecnt ic_h1.hic_fields.ic_bwritecnt +#define ic_state ic_h1.hic_fields.ic_state +#define ic_header ic_h2.hic_header + +/* + * The reservation head lsn is not made up of a cycle number and block number. + * Instead, it uses a cycle number and byte number. Logs don't expect to + * overflow 31 bits worth of byte offset, so using a byte number will mean + * that round off problems won't occur when releasing partial reservations. + */ +typedef struct log { + /* The following block of fields are changed while holding icloglock */ + sema_t l_flushsema; /* iclog flushing semaphore */ + int l_flushcnt; /* # of procs waiting on this sema */ + int l_ticket_cnt; /* free ticket count */ + int l_ticket_tcnt; /* total ticket count */ + int l_covered_state;/* state of "covering disk log entries" */ + xlog_ticket_t *l_freelist; /* free list of tickets */ + xlog_ticket_t *l_unmount_free;/* kmem_free these addresses */ + xlog_ticket_t *l_tail; /* free list of tickets */ + xlog_in_core_t *l_iclog; /* head log queue */ + lock_t l_icloglock; /* grab to change iclog state */ + xfs_lsn_t l_tail_lsn; /* lsn of 1st LR w/ unflush buffers */ + xfs_lsn_t l_last_sync_lsn;/* lsn of last LR on disk */ + struct xfs_mount *l_mp; /* mount point */ + struct xfs_buf *l_xbuf; /* extra buffer for log wrapping */ + dev_t l_dev; /* dev_t of log */ + xfs_daddr_t l_logBBstart; /* start block of log */ + int l_logsize; /* size of log in bytes */ + int l_logBBsize; /* size of log in 512 byte chunks */ + int l_roundoff; /* round off error of all iclogs */ + int l_curr_cycle; /* Cycle number of log writes */ + int l_prev_cycle; /* Cycle # b4 last block increment */ + int l_curr_block; /* current logical block of log */ + int l_prev_block; /* previous logical block of log */ + int l_iclog_size; /* size of log in bytes */ + int l_iclog_size_log;/* log power size of log */ + int l_iclog_bufs; /* number of iclog buffers */ + + /* The following field are used for debugging; need to hold icloglock */ + char *l_iclog_bak[XLOG_MAX_ICLOGS]; + + /* The following block of fields are changed while holding grant_lock */ + lock_t l_grant_lock; /* protects below fields */ + xlog_ticket_t *l_reserve_headq; /* */ + xlog_ticket_t *l_write_headq; /* */ + int l_grant_reserve_cycle; /* */ + int l_grant_reserve_bytes; /* */ + int l_grant_write_cycle; /* */ + int l_grant_write_bytes; /* */ + + /* The following fields don't need locking */ +#ifdef DEBUG + struct ktrace *l_trace; + struct ktrace *l_grant_trace; +#endif + uint l_flags; + uint l_quotaoffs_flag;/* XFS_DQ_*, if QUOTAOFFs found */ + struct xfs_buf_cancel **l_buf_cancel_table; +} xlog_t; + + +/* common routines */ +extern xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp, + xlog_in_core_t *iclog); +extern int xlog_find_head(xlog_t *log, xfs_daddr_t *head_blk); +extern int xlog_find_tail(xlog_t *log, + xfs_daddr_t *head_blk, + xfs_daddr_t *tail_blk, + int readonly); +extern int xlog_print_find_oldest(xlog_t *log, xfs_daddr_t *last_blk); +extern int xlog_recover(xlog_t *log, int readonly); +extern int xlog_recover_finish(xlog_t *log, int mfsi_flags); +extern void xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog); +extern struct xfs_buf *xlog_get_bp(int,xfs_mount_t *); +extern void xlog_put_bp(struct xfs_buf *); +extern int xlog_bread(xlog_t *, xfs_daddr_t blkno, int bblks, struct xfs_buf *bp); +extern void xlog_recover_process_iunlinks(xlog_t *log); + +#define XLOG_TRACE_GRAB_FLUSH 1 +#define XLOG_TRACE_REL_FLUSH 2 +#define XLOG_TRACE_SLEEP_FLUSH 3 +#define XLOG_TRACE_WAKE_FLUSH 4 + +#endif /* __KERNEL__ */ + +#endif /* __XFS_LOG_PRIV_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_log_recover.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_log_recover.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_log_recover.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_log_recover.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_LOG_RECOVER_H__ +#define __XFS_LOG_RECOVER_H__ + +/* + * Macros, structures, prototypes for internal log manager use. + */ + +#define XLOG_RHASH_BITS 4 +#define XLOG_RHASH_SIZE 16 +#define XLOG_RHASH_SHIFT 2 +#define XLOG_RHASH(tid) \ + ((((__uint32_t)tid)>>XLOG_RHASH_SHIFT) & (XLOG_RHASH_SIZE-1)) + +#define XLOG_MAX_REGIONS_IN_ITEM (XFS_MAX_BLOCKSIZE / XFS_BLI_CHUNK / 2 + 1) + + +/* + * item headers are in ri_buf[0]. Additional buffers follow. + */ +typedef struct xlog_recover_item { + struct xlog_recover_item *ri_next; + struct xlog_recover_item *ri_prev; + int ri_type; + int ri_cnt; /* count of regions found */ + int ri_total; /* total regions */ + xfs_log_iovec_t *ri_buf; /* ptr to regions buffer */ +} xlog_recover_item_t; + +struct xlog_tid; +typedef struct xlog_recover { + struct xlog_recover *r_next; + xlog_tid_t r_log_tid; /* log's transaction id */ + xfs_trans_header_t r_theader; /* trans header for partial */ + int r_state; /* not needed */ + xfs_lsn_t r_lsn; /* xact lsn */ + xlog_recover_item_t *r_itemq; /* q for items */ +} xlog_recover_t; + +#define ITEM_TYPE(i) (*(ushort *)(i)->ri_buf[0].i_addr) + +/* + * This is the number of entries in the l_buf_cancel_table used during + * recovery. + */ +#define XLOG_BC_TABLE_SIZE 64 + +#define XLOG_RECOVER_PASS1 1 +#define XLOG_RECOVER_PASS2 2 + +#endif /* __XFS_LOG_RECOVER_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_mount.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_mount.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_mount.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_mount.h Mon Jul 2 23:33:45 2001 @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_MOUNT_H__ +#define __XFS_MOUNT_H__ + + +typedef struct xfs_trans_reservations { + uint tr_write; /* extent alloc trans */ + uint tr_itruncate; /* truncate trans */ + uint tr_rename; /* rename trans */ + uint tr_link; /* link trans */ + uint tr_remove; /* unlink trans */ + uint tr_symlink; /* symlink trans */ + uint tr_create; /* create trans */ + uint tr_mkdir; /* mkdir trans */ + uint tr_ifree; /* inode free trans */ + uint tr_ichange; /* inode update trans */ + uint tr_growdata; /* fs data section grow trans */ + uint tr_swrite; /* sync write inode trans */ + uint tr_addafork; /* cvt inode to attributed trans */ + uint tr_writeid; /* write setuid/setgid file */ + uint tr_attrinval; /* attr fork buffer invalidation */ + uint tr_attrset; /* set/create an attribute */ + uint tr_attrrm; /* remove an attribute */ + uint tr_clearagi; /* clear bad agi unlinked ino bucket */ + uint tr_growrtalloc; /* grow realtime allocations */ + uint tr_growrtzero; /* grow realtime zeroing */ + uint tr_growrtfree; /* grow realtime freeing */ +} xfs_trans_reservations_t; + + +#ifndef __KERNEL__ +/* + * Moved here from xfs_ag.h to avoid reordering header files + */ +#define XFS_DADDR_TO_AGNO(mp,d) \ + ((xfs_agnumber_t)(XFS_BB_TO_FSBT(mp, d) / (mp)->m_sb.sb_agblocks)) +#define XFS_DADDR_TO_AGBNO(mp,d) \ + ((xfs_agblock_t)(XFS_BB_TO_FSBT(mp, d) % (mp)->m_sb.sb_agblocks)) +#else +struct cred; +struct mounta; +struct vfs; +struct vnode; +struct xfs_args; +struct xfs_ihash; +struct xfs_chash; +struct xfs_inode; +struct xfs_perag; +struct xfs_quotainfo; +struct xfs_iocore; +struct xfs_dio; +struct xfs_bmbt_irec; +struct xfs_bmap_free; + +#if defined(INTERRUPT_LATENCY_TESTING) +#define SPLDECL(s) +#define AIL_LOCK_T mutex_t +#define AIL_LOCKINIT(x,y) mutex_init(x,MUTEX_DEFAULT, y) +#define AIL_LOCK_DESTROY(x) mutex_destroy(x) +#define AIL_LOCK(mp,s) mutex_lock(&(mp)->m_ail_lock, PZERO) +#define AIL_UNLOCK(mp,s) mutex_unlock(&(mp)->m_ail_lock) +#else /* !INTERRUPT_LATENCY_TESTING */ +#define SPLDECL(s) int s +#define AIL_LOCK_T lock_t +#define AIL_LOCKINIT(x,y) spinlock_init(x,y) +#define AIL_LOCK_DESTROY(x) spinlock_destroy(x) +#define AIL_LOCK(mp,s) s=mutex_spinlock(&(mp)->m_ail_lock) +#define AIL_UNLOCK(mp,s) mutex_spinunlock(&(mp)->m_ail_lock, s) +#endif /* !INTERRUPT_LATENCY_TESTING */ + + +/* Prototypes and functions for I/O core modularization, a vector + * of functions is used to indirect from xfs/cxfs independent code + * to the xfs/cxfs dependent code. + * The vector is placed in the mount structure so that we can + * minimize the number of memory indirections involved. + */ + +typedef int (*xfs_dio_write_t)(struct xfs_dio *); +typedef int (*xfs_dio_read_t)(struct xfs_dio *); +typedef int (*xfs_strat_write_t)(struct xfs_iocore *, struct xfs_buf *); +typedef int (*xfs_bmapi_t)(struct xfs_trans *, void *, + xfs_fileoff_t, xfs_filblks_t, int, + xfs_fsblock_t *, xfs_extlen_t, + struct xfs_bmbt_irec *, int *, + struct xfs_bmap_free *); +typedef int (*xfs_bmap_eof_t)(void *, xfs_fileoff_t, int, int *); +typedef int (*xfs_rsync_t)(void *, int, xfs_off_t, xfs_off_t); +typedef uint (*xfs_lck_map_shared_t)(void *); +typedef void (*xfs_lock_t)(void *, uint); +typedef void (*xfs_lock_demote_t)(void *, uint); +typedef int (*xfs_lock_nowait_t)(void *, uint); +typedef void (*xfs_unlk_t)(void *, unsigned int); +typedef void (*xfs_chgtime_t)(void *, int); +typedef xfs_fsize_t (*xfs_size_t)(void *); +typedef xfs_fsize_t (*xfs_setsize_t)(void *, xfs_off_t); +typedef xfs_fsize_t (*xfs_lastbyte_t)(void *); + +#ifdef CELL_CAPABLE +typedef int (*xfs_checklock_t)(bhv_desc_t *, struct vnode *, + int, off_t, off_t, int, struct cred *, + struct flid *, vrwlock_t, int); +#endif + +typedef struct xfs_ioops { + xfs_dio_write_t xfs_dio_write_func; + xfs_dio_read_t xfs_dio_read_func; + xfs_strat_write_t xfs_strat_write_func; + xfs_bmapi_t xfs_bmapi_func; + xfs_bmap_eof_t xfs_bmap_eof_func; + xfs_rsync_t xfs_rsync_func; + xfs_lck_map_shared_t xfs_lck_map_shared; + xfs_lock_t xfs_ilock; + xfs_lock_demote_t xfs_ilock_demote; + xfs_lock_nowait_t xfs_ilock_nowait; + xfs_unlk_t xfs_unlock; + xfs_chgtime_t xfs_chgtime; + xfs_size_t xfs_size_func; + xfs_setsize_t xfs_setsize_func; + xfs_lastbyte_t xfs_lastbyte; +#ifdef CELL_CAPABLE + xfs_checklock_t xfs_checklock; +#endif +} xfs_ioops_t; + + +#define XFS_DIO_WRITE(mp, diop) \ + (*(mp)->m_io_ops.xfs_dio_write_func)(diop) + +#define XFS_DIO_READ(mp, diop) \ + (*(mp)->m_io_ops.xfs_dio_read_func)(diop) + +#define XFS_STRAT_WRITE(mp, io, bp) \ + (*(mp)->m_io_ops.xfs_strat_write_func)(io, bp) + +#define XFS_BMAPI(mp, trans,io,bno,len,f,first,tot,mval,nmap,flist) \ + (*(mp)->m_io_ops.xfs_bmapi_func) \ + (trans,(io)->io_obj,bno,len,f,first,tot,mval,nmap,flist) + +#define XFS_BMAP_EOF(mp, io, endoff, whichfork, eof) \ + (*(mp)->m_io_ops.xfs_bmap_eof_func) \ + ((io)->io_obj, endoff, whichfork, eof) + +#define XFS_RSYNC(mp, io, ioflag, start, end) \ + (*(mp)->m_io_ops.xfs_rsync_func)((io)->io_obj, ioflag, start, end) + +#define XFS_LCK_MAP_SHARED(mp, io) \ + (*(mp)->m_io_ops.xfs_lck_map_shared)((io)->io_obj) + +#define XFS_UNLK_MAP_SHARED(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_unlock)((io)->io_obj, mode) + +#define XFS_ILOCK(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_ilock)((io)->io_obj, mode) + +#define XFS_ILOCK_NOWAIT(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_ilock_nowait)((io)->io_obj, mode) + +#define XFS_IUNLOCK(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_unlock)((io)->io_obj, mode) + +#define XFS_ILOCK_DEMOTE(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_ilock_demote)((io)->io_obj, mode) + +#define XFS_CHGTIME(mp, io, flags) \ + (*(mp)->m_io_ops.xfs_chgtime)((io)->io_obj, flags) + +#define XFS_SIZE(mp, io) \ + (*(mp)->m_io_ops.xfs_size_func)((io)->io_obj) + +#define XFS_SETSIZE(mp, io, newsize) \ + (*(mp)->m_io_ops.xfs_setsize_func)((io)->io_obj, newsize) + +#define XFS_LASTBYTE(mp, io) \ + (*(mp)->m_io_ops.xfs_lastbyte)((io)->io_obj) + + +typedef struct xfs_mount { + bhv_desc_t m_bhv; /* vfs xfs behavior */ + xfs_tid_t m_tid; /* next unused tid for fs */ + AIL_LOCK_T m_ail_lock; /* fs AIL mutex */ + xfs_ail_entry_t m_ail; /* fs active log item list */ + uint m_ail_gen; /* fs AIL generation count */ + xfs_sb_t m_sb; /* copy of fs superblock */ + lock_t m_sb_lock; /* sb counter mutex */ + struct xfs_buf *m_sb_bp; /* buffer for superblock */ + char *m_fsname; /* filesystem name */ + int m_fsname_len; /* strlen of fs name */ + int m_bsize; /* fs logical block size */ + xfs_agnumber_t m_agfrotor; /* last ag where space found */ + xfs_agnumber_t m_agirotor; /* last ag dir inode alloced */ + int m_ihsize; /* size of next field */ + struct xfs_ihash *m_ihash; /* fs private inode hash table*/ + struct xfs_inode *m_inodes; /* active inode list */ + mutex_t m_ilock; /* inode list mutex */ + uint m_ireclaims; /* count of calls to reclaim*/ + uint m_readio_log; /* min read size log bytes */ + uint m_readio_blocks; /* min read size blocks */ + uint m_writeio_log; /* min write size log bytes */ + uint m_writeio_blocks; /* min write size blocks */ + void *m_log; /* log specific stuff */ + int m_logbufs; /* number of log buffers */ + int m_logbsize; /* size of each log buffer */ + uint m_rsumlevels; /* rt summary levels */ + uint m_rsumsize; /* size of rt summary, bytes */ + struct xfs_inode *m_rbmip; /* pointer to bitmap inode */ + struct xfs_inode *m_rsumip; /* pointer to summary inode */ + struct xfs_inode *m_rootip; /* pointer to root directory */ + struct xfs_quotainfo *m_quotainfo; /* disk quota information */ + buftarg_t m_ddev_targ; /* ptr to data device */ + buftarg_t m_logdev_targ; /* ptr to log device */ + buftarg_t m_rtdev_targ; /* ptr to rt device */ + buftarg_t *m_ddev_targp; /* saves taking the address */ +#define m_dev m_ddev_targ.dev +#define m_logdev m_logdev_targ.dev +#define m_rtdev m_rtdev_targ.dev + __uint8_t m_dircook_elog; /* log d-cookie entry bits */ + __uint8_t m_blkbit_log; /* blocklog + NBBY */ + __uint8_t m_blkbb_log; /* blocklog - BBSHIFT */ + __uint8_t m_agno_log; /* log #ag's */ + __uint8_t m_agino_log; /* #bits for agino in inum */ + __uint8_t m_nreadaheads; /* #readahead buffers */ + __uint16_t m_inode_cluster_size;/* min inode buf size */ + uint m_blockmask; /* sb_blocksize-1 */ + uint m_blockwsize; /* sb_blocksize in words */ + uint m_blockwmask; /* blockwsize-1 */ + uint m_alloc_mxr[2]; /* XFS_ALLOC_BLOCK_MAXRECS */ + uint m_alloc_mnr[2]; /* XFS_ALLOC_BLOCK_MINRECS */ + uint m_bmap_dmxr[2]; /* XFS_BMAP_BLOCK_DMAXRECS */ + uint m_bmap_dmnr[2]; /* XFS_BMAP_BLOCK_DMINRECS */ + uint m_inobt_mxr[2]; /* XFS_INOBT_BLOCK_MAXRECS */ + uint m_inobt_mnr[2]; /* XFS_INOBT_BLOCK_MINRECS */ + uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */ + uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */ + uint m_in_maxlevels; /* XFS_IN_MAXLEVELS */ + struct xfs_perag *m_perag; /* per-ag accounting info */ + mrlock_t m_peraglock; /* lock for m_perag (pointer) */ + sema_t m_growlock; /* growfs mutex */ + int m_fixedfsid[2]; /* unchanged for life of FS */ + uint m_dmevmask; /* DMI events for this FS */ + uint m_flags; /* global mount flags */ + uint m_attroffset; /* inode attribute offset */ + int m_da_node_ents; /* how many entries in danode */ + int m_ialloc_inos; /* inodes in inode allocation */ + int m_ialloc_blks; /* blocks in inode allocation */ + int m_litino; /* size of inode union area */ + int m_inoalign_mask;/* mask sb_inoalignmt if used */ + uint m_qflags; /* quota status flags */ + xfs_trans_reservations_t m_reservations;/* precomputed res values */ + __uint64_t m_maxicount; /* maximum inode count */ + __uint64_t m_resblks; /* total reserved blocks */ + __uint64_t m_resblks_avail;/* available reserved blocks */ +#if XFS_BIG_FILESYSTEMS + xfs_ino_t m_inoadd; /* add value for ino64_offset */ +#endif + int m_dalign; /* stripe unit */ + int m_swidth; /* stripe width */ + int m_sinoalign; /* stripe unit inode alignmnt */ + int m_attr_magicpct;/* 37% of the blocksize */ + int m_dir_magicpct; /* 37% of the dir blocksize */ + __uint8_t m_mk_sharedro; /* mark shared ro on unmount */ + __uint8_t m_inode_quiesce;/* call quiesce on new inodes. + field governed by m_ilock */ + __uint8_t m_dirversion; /* 1 or 2 */ + xfs_dirops_t m_dirops; /* table of dir funcs */ + int m_dirblksize; /* directory block sz--bytes */ + int m_dirblkfsbs; /* directory block sz--fsbs */ + xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */ + xfs_dablk_t m_dirleafblk; /* blockno of dir non-data v2 */ + xfs_dablk_t m_dirfreeblk; /* blockno of dirfreeindex v2 */ + int m_chsize; /* size of next field */ + struct xfs_chash *m_chash; /* fs private inode per-cluster + * hash table */ + struct xfs_ioops m_io_ops; /* vector of I/O ops */ + struct xfs_expinfo *m_expinfo; /* info to export to other + cells. */ + uint64_t m_shadow_pinmask; + /* which bits matter in rpc + log item pin masks */ + uint m_cxfstype; /* mounted shared, etc. */ + lock_t m_freeze_lock; + uint m_frozen; + sv_t m_wait_unfreeze; + atomic_t m_active_trans; +} xfs_mount_t; + +/* + * Flags for m_flags. + */ +#define XFS_MOUNT_WSYNC 0x00000001 /* for nfs - all metadata ops + must be synchronous except + for space allocations */ +#if XFS_BIG_FILESYSTEMS +#define XFS_MOUNT_INO64 0x00000002 +#endif +#define XFS_MOUNT_ROOTQCHECK 0x00000004 + /* 0x00000008 -- currently unused */ +#define XFS_MOUNT_FS_SHUTDOWN 0x00000010 /* atomic stop of all filesystem + operations, typically for + disk errors in metadata */ +#define XFS_MOUNT_NOATIME 0x00000020 /* don't modify inode access + times on reads */ +#define XFS_MOUNT_RETERR 0x00000040 /* return alignment errors to + user */ +#define XFS_MOUNT_NOALIGN 0x00000080 /* turn off stripe alignment + allocations */ + /* 0x00000100 -- currently unused */ +#define XFS_MOUNT_REGISTERED 0x00000200 /* registered with cxfs master + cell logic */ +#define XFS_MOUNT_NORECOVERY 0x00000400 /* no recovery - dirty fs */ +#define XFS_MOUNT_SHARED 0x00000800 /* shared mount */ +#define XFS_MOUNT_DFLT_IOSIZE 0x00001000 /* set default i/o size */ +#define XFS_MOUNT_OSYNCISDSYNC 0x00002000 /* treat o_sync like o_dsync */ +#define XFS_MOUNT_NOUUID 0x00004000 /* ignore uuid during mount */ + +/* + * Flags for m_cxfstype + */ +#define XFS_CXFS_NOT 0x00000001 /* local mount */ +#define XFS_CXFS_SERVER 0x00000002 /* we're the CXFS server */ +#define XFS_CXFS_CLIENT 0x00000004 /* We're a CXFS client */ +#define XFS_CXFS_REC_ENABLED 0x00000008 /* recovery is enabled */ + +#define XFS_FORCED_SHUTDOWN(mp) ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN) + +/* + * Default minimum read and write sizes. + */ +#define XFS_READIO_LOG_LARGE 12 /* > 32MB memory */ +#define XFS_WRITEIO_LOG_LARGE 12 + +/* + * max and min values for UIO and mount-option defined I/O sizes + * min value can't be less than a page. Lower limit for 4K machines + * is 4K because that's what was tested. + */ +#define XFS_MAX_IO_LOG 16 /* 64K */ + +#if (_PAGESZ == 16384) || (_PAGESZ == 8192) +#define XFS_MIN_IO_LOG 14 /* 16K */ +#elif _PAGESZ == 4096 +#define XFS_MIN_IO_LOG 12 /* 4K */ +#else +#error "Unknown page size" +#endif + + +/* + * Synchronous read and write sizes. This should be + * better for NFSv2 wsync filesystems. + */ +#define XFS_WSYNC_READIO_LOG 15 /* 32K */ +#define XFS_WSYNC_WRITEIO_LOG 14 /* 16K */ + +#define xfs_force_shutdown(m,f) _xfs_force_shutdown(m,f,__FILE__,__LINE__); +/* + * Flags sent to xfs_force_shutdown. + */ +#define XFS_METADATA_IO_ERROR 0x1 +#define XFS_LOG_IO_ERROR 0x2 +#define XFS_FORCE_UMOUNT 0x4 +#define XFS_CORRUPT_INCORE 0x8 /* corrupt in-memory data structures */ +#if CELL_CAPABLE +#define XFS_SHUTDOWN_REMOTE_REQ 0x10 /* shutdown req came from remote cell */ +#endif + +/* + * xflags for xfs_syncsub + */ +#define XFS_XSYNC_RELOC 0x01 + +/* + * Flags for xfs_mountfs + */ +#define XFS_MFSI_SECOND 0x01 /* Is a cxfs secondary mount -- skip */ + /* stuff which should only be done */ + /* once. */ +#define XFS_MFSI_CLIENT 0x02 /* Is a client -- skip lots of stuff */ +#define XFS_MFSI_NOUNLINK 0x08 /* Skip unlinked inode processing in */ + /* log recovery */ + +/* + * Macros for getting from mount to vfs and back. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MTOVFS) +struct vfs *xfs_mtovfs(xfs_mount_t *mp); +#define XFS_MTOVFS(mp) xfs_mtovfs(mp) +#else +#define XFS_MTOVFS(mp) (bhvtovfs(&(mp)->m_bhv)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BHVTOM) +xfs_mount_t *xfs_bhvtom(bhv_desc_t *bdp); +#define XFS_BHVTOM(bdp) xfs_bhvtom(bdp) +#else +#define XFS_BHVTOM(bdp) ((xfs_mount_t *)BHV_PDATA(bdp)) +#endif + + +/* + * Moved here from xfs_ag.h to avoid reordering header files + */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DADDR_TO_AGNO) +xfs_agnumber_t xfs_daddr_to_agno(struct xfs_mount *mp, xfs_daddr_t d); +#define XFS_DADDR_TO_AGNO(mp,d) xfs_daddr_to_agno(mp,d) +#else + +static inline xfs_agnumber_t XFS_DADDR_TO_AGNO(xfs_mount_t *mp, xfs_daddr_t d) +{ + d = XFS_BB_TO_FSBT(mp, d); + do_div(d, mp->m_sb.sb_agblocks); + return (xfs_agnumber_t) d; +} + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DADDR_TO_AGBNO) +xfs_agblock_t xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d); +#define XFS_DADDR_TO_AGBNO(mp,d) xfs_daddr_to_agbno(mp,d) +#else + +static inline xfs_agblock_t XFS_DADDR_TO_AGBNO(xfs_mount_t *mp, xfs_daddr_t d) +{ + d = XFS_BB_TO_FSBT(mp, d); + return (xfs_agblock_t) do_div(d, mp->m_sb.sb_agblocks); +} + +#endif + +/* + * This structure is for use by the xfs_mod_incore_sb_batch() routine. + */ +typedef struct xfs_mod_sb { + xfs_sb_field_t msb_field; /* Field to modify, see below */ + int msb_delta; /* change to make to the specified field */ +} xfs_mod_sb_t; + +#define XFS_MOUNT_ILOCK(mp) mutex_lock(&((mp)->m_ilock), PINOD) +#define XFS_MOUNT_IUNLOCK(mp) mutex_unlock(&((mp)->m_ilock)) +#define XFS_SB_LOCK(mp) mutex_spinlock(&(mp)->m_sb_lock) +#define XFS_SB_UNLOCK(mp,s) mutex_spinunlock(&(mp)->m_sb_lock,(s)) + +void xfs_mod_sb(xfs_trans_t *, __int64_t); +xfs_mount_t *xfs_mount_init(void); +void xfs_mount_free(xfs_mount_t *mp, int remove_bhv); +int xfs_mountfs(struct vfs *, xfs_mount_t *mp, dev_t, int); +int xfs_mountargs(struct mounta *, struct xfs_args *); + +int xfs_unmountfs(xfs_mount_t *, int, struct cred *); +void xfs_unmountfs_close(xfs_mount_t *, int, struct cred *); +int xfs_unmountfs_writesb(xfs_mount_t *); +int xfs_unmount_flush(xfs_mount_t *, int); +int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int, int); +int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *, uint, int); +int xfs_readsb(xfs_mount_t *mp, dev_t); +struct xfs_buf *xfs_getsb(xfs_mount_t *, int); +void xfs_freesb(xfs_mount_t *); +void _xfs_force_shutdown(struct xfs_mount *, int, char *, int); +int xfs_syncsub(xfs_mount_t *, int, int, int *); +void xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t, __int64_t); + +#define XFS_FREEZE_WRITE 1 +#define XFS_FREEZE_TRANS 2 + +void xfs_start_freeze(xfs_mount_t *, int); +void xfs_finish_freeze(xfs_mount_t *); +void xfs_check_frozen(xfs_mount_t *, int); + +extern struct vfsops xfs_vfsops; + +#endif /* __KERNEL__ */ + +#endif /* __XFS_MOUNT_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_quota.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_quota.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_quota.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_quota.h Mon Apr 16 20:36:11 2001 @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_QUOTA_H__ +#define __XFS_QUOTA_H__ + +/* + * uid_t and gid_t are hard-coded to 32 bits in the inode. + * Hence, an 'id' in a dquot is 32 bits.. + */ +typedef __int32_t xfs_dqid_t; + +/* + * Eventhough users may not have quota limits occupying all 64-bits, + * they may need 64-bit accounting. Hence, 64-bit quota-counters, + * and quota-limits. This is a waste in the common case, but hey ... + */ +typedef __uint64_t xfs_qcnt_t; +typedef __uint16_t xfs_qwarncnt_t; + +/* + * Disk quotas status in m_qflags, and also sb_qflags. 16 bits. + */ +#define XFS_UQUOTA_ACCT 0x0001 /* user quota accounting ON */ +#define XFS_UQUOTA_ENFD 0x0002 /* user quota limits enforced */ +#define XFS_UQUOTA_CHKD 0x0004 /* quotacheck run on usr quotas */ +#define XFS_PQUOTA_ACCT 0x0008 /* (IRIX) project quota accounting ON */ +#define XFS_GQUOTA_ENFD 0x0010 /* group quota limits enforced */ +#define XFS_GQUOTA_CHKD 0x0020 /* quotacheck run on grp quotas */ +#define XFS_GQUOTA_ACCT 0x0040 /* group quota accounting ON */ + +/* + * Incore only flags for quotaoff - these bits get cleared when quota(s) + * are in the process of getting turned off. These flags are in m_qflags but + * never in sb_qflags. + */ +#define XFS_UQUOTA_ACTIVE 0x0080 /* uquotas are being turned off */ +#define XFS_GQUOTA_ACTIVE 0x0100 /* gquotas are being turned off */ + +/* + * Typically, we turn quotas off if we weren't explicitly asked to + * mount quotas. This is the mount option not to do that. + * This option is handy in the miniroot, when trying to mount /root. + * We can't really know what's in /etc/fstab until /root is already mounted! + * This stops quotas getting turned off in the root filesystem everytime + * the system boots up a miniroot. + */ +#define XFS_QUOTA_MAYBE 0x0200 /* Turn quotas on if SB has quotas on */ + +/* + * Checking XFS_IS_*QUOTA_ON() while holding any inode lock guarantees + * quota will be not be switched off as long as that inode lock is held. + */ +#define XFS_IS_QUOTA_ON(mp) ((mp)->m_qflags & (XFS_UQUOTA_ACTIVE | \ + XFS_GQUOTA_ACTIVE)) +#define XFS_IS_UQUOTA_ON(mp) ((mp)->m_qflags & XFS_UQUOTA_ACTIVE) +#define XFS_IS_GQUOTA_ON(mp) ((mp)->m_qflags & XFS_GQUOTA_ACTIVE) + +/* + * Flags to tell various functions what to do. Not all of these are meaningful + * to a single function. None of these XFS_QMOPT_* flags are meant to have + * persistent values (ie. their values can and will change between versions) + */ +#define XFS_QMOPT_DQLOCK 0x0000001 /* dqlock */ +#define XFS_QMOPT_DQALLOC 0x0000002 /* alloc dquot ondisk if needed */ +#define XFS_QMOPT_UQUOTA 0x0000004 /* user dquot requested */ +#define XFS_QMOPT_GQUOTA 0x0000008 /* group dquot requested */ +#define XFS_QMOPT_FORCE_RES 0x0000010 /* ignore quota limits */ +#define XFS_QMOPT_DQSUSER 0x0000020 /* don't cache super users dquot */ +#define XFS_QMOPT_SBVERSION 0x0000040 /* change superblock version num */ +#define XFS_QMOPT_QUOTAOFF 0x0000080 /* quotas are being turned off */ +#define XFS_QMOPT_UMOUNTING 0x0000100 /* filesys is being unmounted */ +#define XFS_QMOPT_DOLOG 0x0000200 /* log buf changes (in quotacheck) */ +#define XFS_QMOPT_DOWARN 0x0000400 /* increase warning cnt if necessary */ +#define XFS_QMOPT_ILOCKED 0x0000800 /* inode is already locked (excl) */ +#define XFS_QMOPT_DQREPAIR 0x0001000 /* repair dquot, if damaged. */ + +/* + * flags to xfs_trans_mod_dquot to indicate which field needs to be + * modified. + */ +#define XFS_QMOPT_RES_REGBLKS 0x0010000 +#define XFS_QMOPT_RES_RTBLKS 0x0020000 +#define XFS_QMOPT_BCOUNT 0x0040000 +#define XFS_QMOPT_ICOUNT 0x0080000 +#define XFS_QMOPT_RTBCOUNT 0x0100000 +#define XFS_QMOPT_DELBCOUNT 0x0200000 +#define XFS_QMOPT_DELRTBCOUNT 0x0400000 +#define XFS_QMOPT_RES_INOS 0x0800000 + +/* + * flags for dqflush and dqflush_all. + */ +#define XFS_QMOPT_SYNC 0x1000000 +#define XFS_QMOPT_ASYNC 0x2000000 +#define XFS_QMOPT_DELWRI 0x4000000 + +/* + * flags for dqalloc. + */ +#define XFS_QMOPT_INHERIT 0x8000000 + +/* + * flags to xfs_trans_mod_dquot. + */ +#define XFS_TRANS_DQ_RES_BLKS XFS_QMOPT_RES_REGBLKS +#define XFS_TRANS_DQ_RES_RTBLKS XFS_QMOPT_RES_RTBLKS +#define XFS_TRANS_DQ_RES_INOS XFS_QMOPT_RES_INOS +#define XFS_TRANS_DQ_BCOUNT XFS_QMOPT_BCOUNT +#define XFS_TRANS_DQ_DELBCOUNT XFS_QMOPT_DELBCOUNT +#define XFS_TRANS_DQ_ICOUNT XFS_QMOPT_ICOUNT +#define XFS_TRANS_DQ_RTBCOUNT XFS_QMOPT_RTBCOUNT +#define XFS_TRANS_DQ_DELRTBCOUNT XFS_QMOPT_DELRTBCOUNT + + +#define XFS_QMOPT_QUOTALL (XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA) +#define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS) + +/* + * This check is done typically without holding the inode lock; + * that may seem racey, but it is harmless in the context that it is used. + * The inode cannot go inactive as long a reference is kept, and + * therefore if dquot(s) were attached, they'll stay consistent. + * If, for example, the ownership of the inode changes while + * we didnt have the inode locked, the appropriate dquot(s) will be + * attached atomically. + */ +#define XFS_NOT_DQATTACHED(mp, ip) ((XFS_IS_UQUOTA_ON(mp) &&\ + (ip)->i_udquot == NULL) || \ + (XFS_IS_GQUOTA_ON(mp) && \ + (ip)->i_gdquot == NULL)) + +#define XFS_QM_NEED_QUOTACHECK(mp) ((XFS_IS_UQUOTA_ON(mp) && \ + (mp->m_sb.sb_qflags & \ + XFS_UQUOTA_CHKD) == 0) || \ + (XFS_IS_GQUOTA_ON(mp) && \ + (mp->m_sb.sb_qflags & \ + XFS_GQUOTA_CHKD) == 0)) + +#define XFS_MOUNT_QUOTA_ALL (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ + XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\ + XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD) +#define XFS_MOUNT_QUOTA_MASK (XFS_MOUNT_QUOTA_ALL | XFS_UQUOTA_ACTIVE | \ + XFS_GQUOTA_ACTIVE) + +#define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) + + +#ifdef __KERNEL__ +/* + * External Interface to the XFS disk quota subsystem. + */ +struct bhv_desc; +struct vfs; +struct xfs_disk_dquot; +struct xfs_dqhash; +struct xfs_dquot; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * Quota Manager Interface. + */ +extern struct xfs_qm *xfs_qm_init(void); +extern void xfs_qm_destroy(struct xfs_qm *); +extern int xfs_qm_dqflush_all(struct xfs_mount *, int); +extern int xfs_qm_dqattach(struct xfs_inode *, uint); +extern int xfs_qm_dqpurge_all(struct xfs_mount *, uint); +extern void xfs_qm_mount_quotainit(struct xfs_mount *, uint); +extern void xfs_qm_unmount_quotadestroy(struct xfs_mount *); +extern int xfs_qm_mount_quotas(struct xfs_mount *); +extern int xfs_qm_unmount_quotas(struct xfs_mount *); +extern void xfs_qm_dqdettach_inode(struct xfs_inode *); +extern int xfs_qm_sync(struct xfs_mount *, short); + + +/* + * system call interface + */ +extern int xfs_quotactl(xfs_mount_t *, struct vfs *, int, int, + int, xfs_caddr_t); + +/* + * dquot interface. + */ +extern void xfs_dqlock(struct xfs_dquot *); +extern void xfs_dqunlock(struct xfs_dquot *); +extern void xfs_dqunlock_nonotify(struct xfs_dquot *); +extern void xfs_dqlock2(struct xfs_dquot *, struct xfs_dquot *); +extern void xfs_qm_dqput(struct xfs_dquot *); +extern void xfs_qm_dqrele(struct xfs_dquot *); +extern xfs_dqid_t xfs_qm_dqid(struct xfs_dquot *); +extern int xfs_qm_dqget(struct xfs_mount *, + struct xfs_inode *, xfs_dqid_t, + uint, uint, struct xfs_dquot **); +extern int xfs_qm_dqcheck(struct xfs_disk_dquot *, + xfs_dqid_t, uint, uint, char *); + +/* + * Vnodeops specific code that should actually be _in_ xfs_vnodeops.c, but + * is here because it's nicer to keep vnodeops (therefore, XFS) lean + * and clean. + */ +extern struct xfs_dquot * xfs_qm_vop_chown(struct xfs_trans *, + struct xfs_inode *, + struct xfs_dquot **, + struct xfs_dquot *); +extern int xfs_qm_vop_dqalloc(struct xfs_mount *, + struct xfs_inode *, + uid_t, gid_t, uint, + struct xfs_dquot **, + struct xfs_dquot **); + +extern int xfs_qm_vop_chown_dqalloc(struct xfs_mount *, + struct xfs_inode *, + int, uid_t, gid_t, + struct xfs_dquot **, + struct xfs_dquot **); + +extern int xfs_qm_vop_chown_reserve(struct xfs_trans *, + struct xfs_inode *, + struct xfs_dquot *, + struct xfs_dquot *, + uint); + +extern int xfs_qm_vop_rename_dqattach(struct xfs_inode **); +extern void xfs_qm_vop_dqattach_and_dqmod_newinode( + struct xfs_trans *, + struct xfs_inode *, + struct xfs_dquot *, + struct xfs_dquot *); + + +/* + * Dquot Transaction interface + */ +extern void xfs_trans_alloc_dqinfo(struct xfs_trans *); +extern void xfs_trans_free_dqinfo(struct xfs_trans *); +extern void xfs_trans_dup_dqinfo(struct xfs_trans *, + struct xfs_trans *); +extern void xfs_trans_mod_dquot(struct xfs_trans *, + struct xfs_dquot *, + uint, long); +extern int xfs_trans_mod_dquot_byino(struct xfs_trans *, + struct xfs_inode *, + uint, long); +extern void xfs_trans_apply_dquot_deltas(struct xfs_trans *); +extern void xfs_trans_unreserve_and_mod_dquots(struct xfs_trans *); + +extern int xfs_trans_reserve_quota_nblks(struct xfs_trans *, + struct xfs_inode *, + long, long, uint); + + +extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *, + struct xfs_dquot *, + struct xfs_dquot *, + long, long, uint); +extern void xfs_trans_log_dquot(struct xfs_trans *, + struct xfs_dquot *); +extern void xfs_trans_dqjoin(struct xfs_trans *, + struct xfs_dquot *); +extern void xfs_qm_dqrele_all_inodes(struct xfs_mount *, uint); + +/* + * Regular disk block quota reservations + */ +#define xfs_trans_reserve_blkquota(tp, ip, nblks) \ +xfs_trans_reserve_quota_nblks(tp, ip, nblks, 0, XFS_QMOPT_RES_REGBLKS) + +#define xfs_trans_unreserve_blkquota(tp, ip, nblks) \ +xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), 0, XFS_QMOPT_RES_REGBLKS) + +#define xfs_trans_reserve_quota(tp, udq, gdq, nb, ni, f) \ +xfs_trans_reserve_quota_bydquots(tp, udq, gdq, nb, ni, f|XFS_QMOPT_RES_REGBLKS) + +#define xfs_trans_unreserve_quota(tp, ud, gd, b, i, f) \ +xfs_trans_reserve_quota_bydquots(tp, ud, gd, -(b), -(i), f|XFS_QMOPT_RES_REGBLKS) + +/* + * Realtime disk block quota reservations + */ +#define xfs_trans_reserve_rtblkquota(mp, tp, ip, nblks) \ +xfs_trans_reserve_quota_nblks(tp, ip, nblks, 0, XFS_QMOPT_RES_RTBLKS) + +#define xfs_trans_unreserve_rtblkquota(tp, ip, nblks) \ +xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), 0, XFS_QMOPT_RES_RTBLKS) + +#define xfs_trans_reserve_rtquota(mp, tp, uq, pq, blks, f) \ +xfs_trans_reserve_quota_bydquots(mp, tp, uq, pq, blks, 0, f|XFS_QMOPT_RES_RTBLKS) + +#define xfs_trans_unreserve_rtquota(tp, uq, pq, blks) \ +xfs_trans_reserve_quota_bydquots(tp, uq, pq, -(blks), XFS_QMOPT_RES_RTBLKS) + +#endif /* __KERNEL__ */ + +#endif /* __XFS_QUOTA_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_rtalloc.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_rtalloc.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_rtalloc.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_rtalloc.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_RTALLOC_H__ +#define __XFS_RTALLOC_H__ + +struct xfs_mount; +struct xfs_trans; + +/* Min and max rt extent sizes, specified in bytes */ +#define XFS_MAX_RTEXTSIZE (1024 * 1024 * 1024) /* 1GB */ +#define XFS_DFL_RTEXTSIZE (64 * 1024) /* 64KB */ +#define XFS_MIN_RTEXTSIZE (4 * 1024) /* 4KB */ + +/* + * Constants for bit manipulations. + */ +#define XFS_NBBYLOG 3 /* log2(NBBY) */ +#define XFS_WORDLOG 2 /* log2(sizeof(xfs_rtword_t)) */ +#define XFS_NBWORDLOG (XFS_NBBYLOG + XFS_WORDLOG) +#define XFS_NBWORD (1 << XFS_NBWORDLOG) +#define XFS_WORDMASK ((1 << XFS_WORDLOG) - 1) + +#define XFS_BLOCKSIZE(mp) ((mp)->m_sb.sb_blocksize) +#define XFS_BLOCKMASK(mp) ((mp)->m_blockmask) +#define XFS_BLOCKWSIZE(mp) ((mp)->m_blockwsize) +#define XFS_BLOCKWMASK(mp) ((mp)->m_blockwmask) + +/* + * Summary and bit manipulation macros. + */ +#define XFS_SUMOFFS(mp,ls,bb) ((int)((ls) * (mp)->m_sb.sb_rbmblocks + (bb))) +#define XFS_SUMOFFSTOBLOCK(mp,s) \ + (((s) * (uint)sizeof(xfs_suminfo_t)) >> (mp)->m_sb.sb_blocklog) +#define XFS_SUMPTR(mp,bp,so) \ + ((xfs_suminfo_t *)((char *)XFS_BUF_PTR(bp) + \ + (((so) * (uint)sizeof(xfs_suminfo_t)) & XFS_BLOCKMASK(mp)))) + +#define XFS_BITTOBLOCK(mp,bi) ((bi) >> (mp)->m_blkbit_log) +#define XFS_BLOCKTOBIT(mp,bb) ((bb) << (mp)->m_blkbit_log) +#define XFS_BITTOWORD(mp,bi) \ + ((int)(((bi) >> XFS_NBWORDLOG) & XFS_BLOCKWMASK(mp))) + +#define XFS_RTMIN(a,b) ((a) < (b) ? (a) : (b)) +#define XFS_RTMAX(a,b) ((a) > (b) ? (a) : (b)) + +#define XFS_RTLOBIT(w) xfs_lowbit32(w) +#define XFS_RTHIBIT(w) xfs_highbit32(w) + +#if XFS_BIG_FILESYSTEMS +#define XFS_RTBLOCKLOG(b) xfs_highbit64(b) +#else +#define XFS_RTBLOCKLOG(b) xfs_highbit32(b) +#endif + +/* + * Function prototypes for exported functions. + */ + +/* + * Allocate an extent in the realtime subvolume, with the usual allocation + * parameters. The length units are all in realtime extents, as is the + * result block number. + */ +int /* error */ +xfs_rtallocate_extent( + struct xfs_trans *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number to allocate */ + xfs_extlen_t minlen, /* minimum length to allocate */ + xfs_extlen_t maxlen, /* maximum length to allocate */ + xfs_extlen_t *len, /* out: actual length allocated */ + xfs_alloctype_t type, /* allocation type XFS_ALLOCTYPE... */ + int wasdel, /* was a delayed allocation extent */ + xfs_extlen_t prod, /* extent product factor */ + xfs_rtblock_t *rtblock); /* out: start block allocated */ + +/* + * Free an extent in the realtime subvolume. Length is expressed in + * realtime extents, as is the block number. + */ +int /* error */ +xfs_rtfree_extent( + struct xfs_trans *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number to free */ + xfs_extlen_t len); /* length of extent freed */ + +/* + * Initialize realtime fields in the mount structure. + */ +int /* error */ +xfs_rtmount_init( + struct xfs_mount *mp); /* file system mount structure */ + +/* + * Get the bitmap and summary inodes into the mount structure + * at mount time. + */ +int /* error */ +xfs_rtmount_inodes( + struct xfs_mount *mp); /* file system mount structure */ + +/* + * Pick an extent for allocation at the start of a new realtime file. + * Use the sequence number stored in the atime field of the bitmap inode. + * Translate this to a fraction of the rtextents, and return the product + * of rtextents and the fraction. + * The fraction sequence is 0, 1/2, 1/4, 3/4, 1/8, ..., 7/8, 1/16, ... + */ +int /* error */ +xfs_rtpick_extent( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_extlen_t len, /* allocation length (rtextents) */ + xfs_rtblock_t *pick); /* result rt extent */ + +#ifdef XFSDEBUG +/* + * Debug code: print out the value of a range in the bitmap. + */ +void +xfs_rtprint_range( + struct xfs_mount *mp, /* file system mount structure */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to print */ + xfs_extlen_t len); /* length to print */ + +/* + * Debug code: print the summary file. + */ +void +xfs_rtprint_summary( + struct xfs_mount *mp, /* file system mount structure */ + struct xfs_trans *tp); /* transaction pointer */ +#endif /* XFSDEBUG */ + +#endif /* __XFS_RTALLOC_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_sb.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_sb.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_sb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_sb.h Mon Apr 2 21:52:38 2001 @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SB_H__ +#define __XFS_SB_H__ + +/* + * Super block + * Fits into a 512-byte buffer at daddr_t 0 of each allocation group. + * Only the first of these is ever updated except during growfs. + */ + +struct xfs_buf; +struct xfs_mount; + +#define XFS_SB_MAGIC 0x58465342 /* 'XFSB' */ +#define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */ +#define XFS_SB_VERSION_2 2 /* 6.2 - attributes */ +#define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */ +#define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */ +#define XFS_SB_VERSION_NUMBITS 0x000f +#define XFS_SB_VERSION_ALLFBITS 0xfff0 +#define XFS_SB_VERSION_SASHFBITS 0xf000 +#define XFS_SB_VERSION_REALFBITS 0x0ff0 +#define XFS_SB_VERSION_ATTRBIT 0x0010 +#define XFS_SB_VERSION_NLINKBIT 0x0020 +#define XFS_SB_VERSION_QUOTABIT 0x0040 +#define XFS_SB_VERSION_ALIGNBIT 0x0080 +#define XFS_SB_VERSION_DALIGNBIT 0x0100 +#define XFS_SB_VERSION_SHAREDBIT 0x0200 +#define XFS_SB_VERSION_EXTFLGBIT 0x1000 +#define XFS_SB_VERSION_DIRV2BIT 0x2000 +#define XFS_SB_VERSION_OKSASHFBITS \ + (XFS_SB_VERSION_EXTFLGBIT | \ + XFS_SB_VERSION_DIRV2BIT) +#define XFS_SB_VERSION_OKREALFBITS \ + (XFS_SB_VERSION_ATTRBIT | \ + XFS_SB_VERSION_NLINKBIT | \ + XFS_SB_VERSION_QUOTABIT | \ + XFS_SB_VERSION_ALIGNBIT | \ + XFS_SB_VERSION_DALIGNBIT | \ + XFS_SB_VERSION_SHAREDBIT) +#define XFS_SB_VERSION_OKSASHBITS \ + (XFS_SB_VERSION_NUMBITS | \ + XFS_SB_VERSION_REALFBITS | \ + XFS_SB_VERSION_OKSASHFBITS) +#define XFS_SB_VERSION_OKREALBITS \ + (XFS_SB_VERSION_NUMBITS | \ + XFS_SB_VERSION_OKREALFBITS | \ + XFS_SB_VERSION_OKSASHFBITS) +#define XFS_SB_VERSION_MKFS(ia,dia,extflag,dirv2) \ + (((ia) || (dia) || (extflag) || (dirv2)) ? \ + (XFS_SB_VERSION_4 | \ + ((ia) ? XFS_SB_VERSION_ALIGNBIT : 0) | \ + ((dia) ? XFS_SB_VERSION_DALIGNBIT : 0) | \ + ((extflag) ? XFS_SB_VERSION_EXTFLGBIT : 0) | \ + ((dirv2) ? XFS_SB_VERSION_DIRV2BIT : 0)) : \ + XFS_SB_VERSION_1) + +typedef struct xfs_sb +{ + __uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */ + __uint32_t sb_blocksize; /* logical block size, bytes */ + xfs_drfsbno_t sb_dblocks; /* number of data blocks */ + xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */ + xfs_drtbno_t sb_rextents; /* number of realtime extents */ + uuid_t sb_uuid; /* file system unique id */ + xfs_dfsbno_t sb_logstart; /* starting block of log if internal */ + xfs_ino_t sb_rootino; /* root inode number */ + xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */ + xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */ + xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */ + xfs_agblock_t sb_agblocks; /* size of an allocation group */ + xfs_agnumber_t sb_agcount; /* number of allocation groups */ + xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */ + xfs_extlen_t sb_logblocks; /* number of log blocks */ + __uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */ + __uint16_t sb_sectsize; /* volume sector size, bytes */ + __uint16_t sb_inodesize; /* inode size, bytes */ + __uint16_t sb_inopblock; /* inodes per block */ + char sb_fname[12]; /* file system name */ + __uint8_t sb_blocklog; /* log2 of sb_blocksize */ + __uint8_t sb_sectlog; /* log2 of sb_sectsize */ + __uint8_t sb_inodelog; /* log2 of sb_inodesize */ + __uint8_t sb_inopblog; /* log2 of sb_inopblock */ + __uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */ + __uint8_t sb_rextslog; /* log2 of sb_rextents */ + __uint8_t sb_inprogress; /* mkfs is in progress, don't mount */ + __uint8_t sb_imax_pct; /* max % of fs for inode space */ + /* statistics */ + /* + * These fields must remain contiguous. If you really + * want to change their layout, make sure you fix the + * code in xfs_trans_apply_sb_deltas(). + */ + __uint64_t sb_icount; /* allocated inodes */ + __uint64_t sb_ifree; /* free inodes */ + __uint64_t sb_fdblocks; /* free data blocks */ + __uint64_t sb_frextents; /* free realtime extents */ + /* + * End contiguous fields. + */ + xfs_ino_t sb_uquotino; /* user quota inode */ + xfs_ino_t sb_gquotino; /* group quota inode */ + __uint16_t sb_qflags; /* quota flags */ + __uint8_t sb_flags; /* misc. flags */ + __uint8_t sb_shared_vn; /* shared version number */ + xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */ + __uint32_t sb_unit; /* stripe or raid unit */ + __uint32_t sb_width; /* stripe or raid width */ + __uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */ + __uint8_t sb_dummy[7]; /* padding */ +} xfs_sb_t; + +/* + * Sequence number values for the fields. + */ +typedef enum { + XFS_SBS_MAGICNUM, XFS_SBS_BLOCKSIZE, XFS_SBS_DBLOCKS, XFS_SBS_RBLOCKS, + XFS_SBS_REXTENTS, XFS_SBS_UUID, XFS_SBS_LOGSTART, XFS_SBS_ROOTINO, + XFS_SBS_RBMINO, XFS_SBS_RSUMINO, XFS_SBS_REXTSIZE, XFS_SBS_AGBLOCKS, + XFS_SBS_AGCOUNT, XFS_SBS_RBMBLOCKS, XFS_SBS_LOGBLOCKS, + XFS_SBS_VERSIONNUM, XFS_SBS_SECTSIZE, XFS_SBS_INODESIZE, + XFS_SBS_INOPBLOCK, XFS_SBS_FNAME, XFS_SBS_BLOCKLOG, + XFS_SBS_SECTLOG, XFS_SBS_INODELOG, XFS_SBS_INOPBLOG, XFS_SBS_AGBLKLOG, + XFS_SBS_REXTSLOG, XFS_SBS_INPROGRESS, XFS_SBS_IMAX_PCT, XFS_SBS_ICOUNT, + XFS_SBS_IFREE, XFS_SBS_FDBLOCKS, XFS_SBS_FREXTENTS, XFS_SBS_UQUOTINO, + XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN, + XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG, + XFS_SBS_DUMMY, + XFS_SBS_FIELDCOUNT +} xfs_sb_field_t; + +/* + * Mask values, defined based on the xfs_sb_field_t values. + * Only define the ones we're using. + */ +#define XFS_SB_MVAL(x) (1LL << XFS_SBS_ ## x) +#define XFS_SB_UUID XFS_SB_MVAL(UUID) +#define XFS_SB_FNAME XFS_SB_MVAL(FNAME) +#define XFS_SB_ROOTINO XFS_SB_MVAL(ROOTINO) +#define XFS_SB_RBMINO XFS_SB_MVAL(RBMINO) +#define XFS_SB_RSUMINO XFS_SB_MVAL(RSUMINO) +#define XFS_SB_VERSIONNUM XFS_SB_MVAL(VERSIONNUM) +#define XFS_SB_UQUOTINO XFS_SB_MVAL(UQUOTINO) +#define XFS_SB_GQUOTINO XFS_SB_MVAL(GQUOTINO) +#define XFS_SB_QFLAGS XFS_SB_MVAL(QFLAGS) +#define XFS_SB_SHARED_VN XFS_SB_MVAL(SHARED_VN) +#define XFS_SB_UNIT XFS_SB_MVAL(UNIT) +#define XFS_SB_WIDTH XFS_SB_MVAL(WIDTH) +#define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT) +#define XFS_SB_ALL_BITS ((1LL << XFS_SB_NUM_BITS) - 1) +#define XFS_SB_MOD_BITS \ + (XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \ + XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \ + XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH) + +/* + * Misc. Flags - warning - these will be cleared by xfs_repair unless + * a feature bit is set when the flag is used. + */ +#define XFS_SBF_NOFLAGS 0x00 /* no flags set */ +#define XFS_SBF_READONLY 0x01 /* only read-only mounts allowed */ + +/* + * define max. shared version we can interoperate with + */ +#define XFS_SB_MAX_SHARED_VN 0 + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_NUM) +int xfs_sb_version_num(xfs_sb_t *sbp); +#define XFS_SB_VERSION_NUM(sbp) xfs_sb_version_num(sbp) +#else +#define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_GOOD_VERSION) +int xfs_sb_good_version(xfs_sb_t *sbp); +#define XFS_SB_GOOD_VERSION(sbp) xfs_sb_good_version(sbp) +#else +#define XFS_SB_GOOD_VERSION_INT(sbp) \ + ((((sbp)->sb_versionnum >= XFS_SB_VERSION_1) && \ + ((sbp)->sb_versionnum <= XFS_SB_VERSION_3)) || \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + !((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS) +#ifdef __KERNEL__ +#define XFS_SB_GOOD_VERSION(sbp) \ + (XFS_SB_GOOD_VERSION_INT(sbp) && \ + (sbp)->sb_shared_vn <= XFS_SB_MAX_SHARED_VN) )) +#else +/* + * extra 2 paren's here (( to unconfuse paren-matching editors + * like vi because XFS_SB_GOOD_VERSION_INT is a partial expression + * and the two XFS_SB_GOOD_VERSION's each 2 more close paren's to + * complete the expression. + */ +#define XFS_SB_GOOD_VERSION(sbp) \ + (XFS_SB_GOOD_VERSION_INT(sbp) && \ + (!((sbp)->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) || \ + (sbp)->sb_shared_vn <= XFS_SB_MAX_SHARED_VN)) )) +#endif /* __KERNEL__ */ +#endif + +#define XFS_SB_GOOD_SASH_VERSION(sbp) \ + ((((sbp)->sb_versionnum >= XFS_SB_VERSION_1) && \ + ((sbp)->sb_versionnum <= XFS_SB_VERSION_3)) || \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + !((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKSASHBITS))) + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_TONEW) +unsigned xfs_sb_version_tonew(unsigned v); +#define XFS_SB_VERSION_TONEW(v) xfs_sb_version_tonew(v) +#else +#define XFS_SB_VERSION_TONEW(v) \ + ((((v) == XFS_SB_VERSION_1) ? \ + 0 : \ + (((v) == XFS_SB_VERSION_2) ? \ + XFS_SB_VERSION_ATTRBIT : \ + (XFS_SB_VERSION_ATTRBIT | XFS_SB_VERSION_NLINKBIT))) | \ + XFS_SB_VERSION_4) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_TOOLD) +unsigned xfs_sb_version_toold(unsigned v); +#define XFS_SB_VERSION_TOOLD(v) xfs_sb_version_toold(v) +#else +#define XFS_SB_VERSION_TOOLD(v) \ + (((v) & (XFS_SB_VERSION_QUOTABIT | XFS_SB_VERSION_ALIGNBIT)) ? \ + 0 : \ + (((v) & XFS_SB_VERSION_NLINKBIT) ? \ + XFS_SB_VERSION_3 : \ + (((v) & XFS_SB_VERSION_ATTRBIT) ? \ + XFS_SB_VERSION_2 : \ + XFS_SB_VERSION_1))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASATTR) +int xfs_sb_version_hasattr(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASATTR(sbp) xfs_sb_version_hasattr(sbp) +#else +#define XFS_SB_VERSION_HASATTR(sbp) \ + (((sbp)->sb_versionnum == XFS_SB_VERSION_2) || \ + ((sbp)->sb_versionnum == XFS_SB_VERSION_3) || \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_ATTRBIT))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDATTR) +void xfs_sb_version_addattr(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDATTR(sbp) xfs_sb_version_addattr(sbp) +#else +#define XFS_SB_VERSION_ADDATTR(sbp) \ + ((sbp)->sb_versionnum = \ + (((sbp)->sb_versionnum == XFS_SB_VERSION_1) ? \ + XFS_SB_VERSION_2 : \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) ? \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_ATTRBIT) : \ + (XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT)))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASNLINK) +int xfs_sb_version_hasnlink(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASNLINK(sbp) xfs_sb_version_hasnlink(sbp) +#else +#define XFS_SB_VERSION_HASNLINK(sbp) \ + (((sbp)->sb_versionnum == XFS_SB_VERSION_3) || \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_NLINKBIT))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDNLINK) +void xfs_sb_version_addnlink(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDNLINK(sbp) xfs_sb_version_addnlink(sbp) +#else +#define XFS_SB_VERSION_ADDNLINK(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum <= XFS_SB_VERSION_2 ? \ + XFS_SB_VERSION_3 : \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_NLINKBIT))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASQUOTA) +int xfs_sb_version_hasquota(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASQUOTA(sbp) xfs_sb_version_hasquota(sbp) +#else +#define XFS_SB_VERSION_HASQUOTA(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_QUOTABIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDQUOTA) +void xfs_sb_version_addquota(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDQUOTA(sbp) xfs_sb_version_addquota(sbp) +#else +#define XFS_SB_VERSION_ADDQUOTA(sbp) \ + ((sbp)->sb_versionnum = \ + (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 ? \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_QUOTABIT) : \ + (XFS_SB_VERSION_TONEW((sbp)->sb_versionnum) | \ + XFS_SB_VERSION_QUOTABIT))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASALIGN) +int xfs_sb_version_hasalign(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASALIGN(sbp) xfs_sb_version_hasalign(sbp) +#else +#define XFS_SB_VERSION_HASALIGN(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_ALIGNBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_SUBALIGN) +void xfs_sb_version_subalign(xfs_sb_t *sbp); +#define XFS_SB_VERSION_SUBALIGN(sbp) xfs_sb_version_subalign(sbp) +#else +#define XFS_SB_VERSION_SUBALIGN(sbp) \ + ((sbp)->sb_versionnum = \ + XFS_SB_VERSION_TOOLD((sbp)->sb_versionnum & ~XFS_SB_VERSION_ALIGNBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASDALIGN) +int xfs_sb_version_hasdalign(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASDALIGN(sbp) xfs_sb_version_hasdalign(sbp) +#else +#define XFS_SB_VERSION_HASDALIGN(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_DALIGNBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDDALIGN) +int xfs_sb_version_adddalign(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDDALIGN(sbp) xfs_sb_version_adddalign(sbp) +#else +#define XFS_SB_VERSION_ADDDALIGN(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_DALIGNBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASSHARED) +int xfs_sb_version_hasshared(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASSHARED(sbp) xfs_sb_version_hasshared(sbp) +#else +#define XFS_SB_VERSION_HASSHARED(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_SHAREDBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDSHARED) +int xfs_sb_version_addshared(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDSHARED(sbp) xfs_sb_version_addshared(sbp) +#else +#define XFS_SB_VERSION_ADDSHARED(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_SHAREDBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_SUBSHARED) +int xfs_sb_version_subshared(xfs_sb_t *sbp); +#define XFS_SB_VERSION_SUBSHARED(sbp) xfs_sb_version_subshared(sbp) +#else +#define XFS_SB_VERSION_SUBSHARED(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum & ~XFS_SB_VERSION_SHAREDBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASDIRV2) +int xfs_sb_version_hasdirv2(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASDIRV2(sbp) xfs_sb_version_hasdirv2(sbp) +#else +#define XFS_SB_VERSION_HASDIRV2(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_DIRV2BIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASEXTFLGBIT) +int xfs_sb_version_hasextflgbit(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASEXTFLGBIT(sbp) xfs_sb_version_hasextflgbit(sbp) +#else +#define XFS_SB_VERSION_HASEXTFLGBIT(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDEXTFLGBIT) +int xfs_sb_version_addextflgbit(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDEXTFLGBIT(sbp) xfs_sb_version_addextflgbit(sbp) +#else +#define XFS_SB_VERSION_ADDEXTFLGBIT(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_EXTFLGBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_SUBEXTFLGBIT) +int xfs_sb_version_subextflgbit(xfs_sb_t *sbp); +#define XFS_SB_VERSION_SUBEXTFLGBIT(sbp) xfs_sb_version_subextflgbit(sbp) +#else +#define XFS_SB_VERSION_SUBEXTFLGBIT(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum & ~XFS_SB_VERSION_EXTFLGBIT)) +#endif + +/* + * end of superblock version macros + */ + +#define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in filesystem/ag */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_BLOCK) +xfs_agblock_t xfs_sb_block(struct xfs_mount *mp); +#define XFS_SB_BLOCK(mp) xfs_sb_block(mp) +#else +#define XFS_SB_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_SB_DADDR) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_HDR_BLOCK) +xfs_agblock_t xfs_hdr_block(struct xfs_mount *mp, xfs_daddr_t d); +#define XFS_HDR_BLOCK(mp,d) xfs_hdr_block(mp,d) +#else +#define XFS_HDR_BLOCK(mp,d) ((xfs_agblock_t)(XFS_BB_TO_FSBT(mp,d))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DADDR_TO_FSB) +xfs_fsblock_t xfs_daddr_to_fsb(struct xfs_mount *mp, xfs_daddr_t d); +#define XFS_DADDR_TO_FSB(mp,d) xfs_daddr_to_fsb(mp,d) +#else +#define XFS_DADDR_TO_FSB(mp,d) \ + XFS_AGB_TO_FSB(mp, XFS_DADDR_TO_AGNO(mp,d), XFS_DADDR_TO_AGBNO(mp,d)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_TO_DADDR) +xfs_daddr_t xfs_fsb_to_daddr(struct xfs_mount *mp, xfs_fsblock_t fsbno); +#define XFS_FSB_TO_DADDR(mp,fsbno) xfs_fsb_to_daddr(mp,fsbno) +#else +#define XFS_FSB_TO_DADDR(mp,fsbno) \ + XFS_AGB_TO_DADDR(mp, XFS_FSB_TO_AGNO(mp,fsbno), \ + XFS_FSB_TO_AGBNO(mp,fsbno)) +#endif + +/* + * File system block to basic block conversions. + */ +#define XFS_FSB_TO_BB(mp,fsbno) ((fsbno) << (mp)->m_blkbb_log) +#define XFS_BB_TO_FSB(mp,bb) \ + (((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log) +#define XFS_BB_TO_FSBT(mp,bb) ((bb) >> (mp)->m_blkbb_log) +#define XFS_BB_FSB_OFFSET(mp,bb) ((bb) & ((mp)->m_bsize - 1)) + +/* + * File system block to byte conversions. + */ +#define XFS_FSB_TO_B(mp,fsbno) ((xfs_fsize_t)(fsbno) << \ + (mp)->m_sb.sb_blocklog) +#define XFS_B_TO_FSB(mp,b) \ + ((((__uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog) +#define XFS_B_TO_FSBT(mp,b) (((__uint64_t)(b)) >> (mp)->m_sb.sb_blocklog) +#define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask) + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_SBP) +xfs_sb_t *xfs_buf_to_sbp(struct xfs_buf *bp); +#define XFS_BUF_TO_SBP(bp) xfs_buf_to_sbp(bp) +#else +#define XFS_BUF_TO_SBP(bp) ((xfs_sb_t *)XFS_BUF_PTR(bp)) +#endif + +#endif /* __XFS_SB_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_trans.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_trans.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_trans.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_trans.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,1000 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_TRANS_H__ +#define __XFS_TRANS_H__ + +/* + * This is the structure written in the log at the head of + * every transaction. It identifies the type and id of the + * transaction, and contains the number of items logged by + * the transaction so we know how many to expect during recovery. + * + * Do not change the below structure without redoing the code in + * xlog_recover_add_to_trans() and xlog_recover_add_to_cont_trans(). + */ +typedef struct xfs_trans_header { + uint th_magic; /* magic number */ + uint th_type; /* transaction type */ + __int32_t th_tid; /* transaction id (unused) */ + uint th_num_items; /* num items logged by trans */ +} xfs_trans_header_t; + +#define XFS_TRANS_HEADER_MAGIC 0x5452414e /* TRAN */ + +/* + * Log item types. + */ +#define XFS_LI_5_3_BUF 0x1234 /* v1 bufs, 1-block inode buffers */ +#define XFS_LI_5_3_INODE 0x1235 /* 1-block inode buffers */ +#define XFS_LI_EFI 0x1236 +#define XFS_LI_EFD 0x1237 +#define XFS_LI_IUNLINK 0x1238 +#define XFS_LI_6_1_INODE 0x1239 /* 4K non-aligned inode bufs */ +#define XFS_LI_6_1_BUF 0x123a /* v1, 4K inode buffers */ +#define XFS_LI_INODE 0x123b /* aligned ino chunks, var-size ibufs */ +#define XFS_LI_BUF 0x123c /* v2 bufs, variable sized inode bufs */ +#define XFS_LI_DQUOT 0x123d +#define XFS_LI_QUOTAOFF 0x123e +#define XFS_LI_RPC 0x123f /* CXFS RPC return info */ + +/* + * Transaction types. Used to distinguish types of buffers. + */ +#define XFS_TRANS_SETATTR_NOT_SIZE 1 +#define XFS_TRANS_SETATTR_SIZE 2 +#define XFS_TRANS_INACTIVE 3 +#define XFS_TRANS_CREATE 4 +#define XFS_TRANS_CREATE_TRUNC 5 +#define XFS_TRANS_TRUNCATE_FILE 6 +#define XFS_TRANS_REMOVE 7 +#define XFS_TRANS_LINK 8 +#define XFS_TRANS_RENAME 9 +#define XFS_TRANS_MKDIR 10 +#define XFS_TRANS_RMDIR 11 +#define XFS_TRANS_SYMLINK 12 +#define XFS_TRANS_SET_DMATTRS 13 +#define XFS_TRANS_GROWFS 14 +#define XFS_TRANS_STRAT_WRITE 15 +#define XFS_TRANS_DIOSTRAT 16 +#define XFS_TRANS_WRITE_SYNC 17 +#define XFS_TRANS_WRITEID 18 +#define XFS_TRANS_ADDAFORK 19 +#define XFS_TRANS_ATTRINVAL 20 +#define XFS_TRANS_ATRUNCATE 21 +#define XFS_TRANS_ATTR_SET 22 +#define XFS_TRANS_ATTR_RM 23 +#define XFS_TRANS_ATTR_FLAG 24 +#define XFS_TRANS_CLEAR_AGI_BUCKET 25 +#define XFS_TRANS_QM_SBCHANGE 26 +/* + * Dummy entries since we use the transaction type to index into the + * trans_type[] in xlog_recover_print_trans_head() + */ +#define XFS_TRANS_DUMMY1 27 +#define XFS_TRANS_DUMMY2 28 +#define XFS_TRANS_QM_QUOTAOFF 29 +#define XFS_TRANS_QM_DQALLOC 30 +#define XFS_TRANS_QM_SETQLIM 31 +#define XFS_TRANS_QM_DQCLUSTER 32 +#define XFS_TRANS_QM_QINOCREATE 33 +#define XFS_TRANS_QM_QUOTAOFF_END 34 +#define XFS_TRANS_SB_UNIT 35 +#define XFS_TRANS_FSYNC_TS 36 +#define XFS_TRANS_GROWFSRT_ALLOC 37 +#define XFS_TRANS_GROWFSRT_ZERO 38 +#define XFS_TRANS_GROWFSRT_FREE 39 +#define XFS_TRANS_SWAPEXT 40 +/* new transaction types need to be reflected in xfs_logprint(8) */ + + +#ifdef __KERNEL__ +struct xfs_buf; +struct buftarg; +struct xfs_efd_log_item; +struct xfs_efi_log_item; +struct xfs_inode; +struct xfs_item_ops; +struct xfs_log_iovec; +struct xfs_log_item; +struct xfs_log_item_desc; +struct xfs_mount; +struct xfs_trans; +struct xfs_dquot_acct; + +typedef struct xfs_ail_entry { + struct xfs_log_item *ail_forw; /* AIL forw pointer */ + struct xfs_log_item *ail_back; /* AIL back pointer */ +} xfs_ail_entry_t; + +/* + * This structure is passed as a parameter to xfs_trans_push_ail() + * and is used to track the what LSN the waiting processes are + * waiting to become unused. + */ +typedef struct xfs_ail_ticket { + xfs_lsn_t at_lsn; /* lsn waitin for */ + struct xfs_ail_ticket *at_forw; /* wait list ptr */ + struct xfs_ail_ticket *at_back; /* wait list ptr */ + sv_t at_sema; /* wait sema */ +} xfs_ail_ticket_t; + + +typedef struct xfs_log_item { + xfs_ail_entry_t li_ail; /* AIL pointers */ + xfs_lsn_t li_lsn; /* last on-disk lsn */ + struct xfs_log_item_desc *li_desc; /* ptr to current desc*/ + struct xfs_mount *li_mountp; /* ptr to fs mount */ + uint li_type; /* item type */ + uint li_flags; /* misc flags */ + struct xfs_log_item *li_bio_list; /* buffer item list */ + void (*li_cb)(struct xfs_buf *, + struct xfs_log_item *); + /* buffer item iodone */ + /* callback func */ + struct xfs_item_ops *li_ops; /* function list */ +} xfs_log_item_t; + +#define XFS_LI_IN_AIL 0x1 +#define XFS_LI_ABORTED 0x2 + +typedef struct xfs_item_ops { + uint (*iop_size)(xfs_log_item_t *); + void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *); + void (*iop_pin)(xfs_log_item_t *); + void (*iop_unpin)(xfs_log_item_t *); + void (*iop_unpin_remove)(xfs_log_item_t *, struct xfs_trans *); + uint (*iop_trylock)(xfs_log_item_t *); + void (*iop_unlock)(xfs_log_item_t *); + xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t); + void (*iop_push)(xfs_log_item_t *); + void (*iop_abort)(xfs_log_item_t *); + void (*iop_pushbuf)(xfs_log_item_t *); + void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t); +} xfs_item_ops_t; + +#define IOP_SIZE(ip) (*(ip)->li_ops->iop_size)(ip) +#define IOP_FORMAT(ip,vp) (*(ip)->li_ops->iop_format)(ip, vp) +#define IOP_PIN(ip) (*(ip)->li_ops->iop_pin)(ip) +#define IOP_UNPIN(ip) (*(ip)->li_ops->iop_unpin)(ip) +#define IOP_UNPIN_REMOVE(ip,tp) (*(ip)->li_ops->iop_unpin_remove)(ip, tp) +#define IOP_TRYLOCK(ip) (*(ip)->li_ops->iop_trylock)(ip) +#define IOP_UNLOCK(ip) (*(ip)->li_ops->iop_unlock)(ip) +#define IOP_COMMITTED(ip, lsn) (*(ip)->li_ops->iop_committed)(ip, lsn) +#define IOP_PUSH(ip) (*(ip)->li_ops->iop_push)(ip) +#define IOP_ABORT(ip) (*(ip)->li_ops->iop_abort)(ip) +#define IOP_PUSHBUF(ip) (*(ip)->li_ops->iop_pushbuf)(ip) +#define IOP_COMMITTING(ip, lsn) (*(ip)->li_ops->iop_committing)(ip, lsn) + +/* + * Return values for the IOP_TRYLOCK() routines. + */ +#define XFS_ITEM_SUCCESS 0 +#define XFS_ITEM_PINNED 1 +#define XFS_ITEM_LOCKED 2 +#define XFS_ITEM_FLUSHING 3 +#define XFS_ITEM_PUSHBUF 4 + +#endif /* __KERNEL__ */ + +/* + * This structure is used to track log items associated with + * a transaction. It points to the log item and keeps some + * flags to track the state of the log item. It also tracks + * the amount of space needed to log the item it describes + * once we get to commit processing (see xfs_trans_commit()). + */ +typedef struct xfs_log_item_desc { + xfs_log_item_t *lid_item; + ushort lid_size; + unsigned char lid_flags; + unsigned char lid_index; +} xfs_log_item_desc_t; + +#define XFS_LID_DIRTY 0x1 +#define XFS_LID_PINNED 0x2 +#define XFS_LID_SYNC_UNLOCK 0x4 + +/* + * This structure is used to maintain a chunk list of log_item_desc + * structures. The free field is a bitmask indicating which descriptors + * in this chunk's array are free. The unused field is the first value + * not used since this chunk was allocated. + */ +#define XFS_LIC_NUM_SLOTS 15 +typedef struct xfs_log_item_chunk { + struct xfs_log_item_chunk *lic_next; + ushort lic_free; + ushort lic_unused; + xfs_log_item_desc_t lic_descs[XFS_LIC_NUM_SLOTS]; +} xfs_log_item_chunk_t; + +#define XFS_LIC_MAX_SLOT (XFS_LIC_NUM_SLOTS - 1) +#define XFS_LIC_FREEMASK ((1 << XFS_LIC_NUM_SLOTS) - 1) + + +/* + * Initialize the given chunk. Set the chunk's free descriptor mask + * to indicate that all descriptors are free. The caller gets to set + * lic_unused to the right value (0 matches all free). The + * lic_descs.lid_index values are set up as each desc is allocated. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_INIT) +void xfs_lic_init(xfs_log_item_chunk_t *cp); +#define XFS_LIC_INIT(cp) xfs_lic_init(cp) +#else +#define XFS_LIC_INIT(cp) ((cp)->lic_free = XFS_LIC_FREEMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_INIT_SLOT) +void xfs_lic_init_slot(xfs_log_item_chunk_t *cp, int slot); +#define XFS_LIC_INIT_SLOT(cp,slot) xfs_lic_init_slot(cp, slot) +#else +#define XFS_LIC_INIT_SLOT(cp,slot) \ + ((cp)->lic_descs[slot].lid_index = (unsigned char)(slot)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_VACANCY) +int xfs_lic_vacancy(xfs_log_item_chunk_t *cp); +#define XFS_LIC_VACANCY(cp) xfs_lic_vacancy(cp) +#else +#define XFS_LIC_VACANCY(cp) (((cp)->lic_free) & XFS_LIC_FREEMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_ALL_FREE) +void xfs_lic_all_free(xfs_log_item_chunk_t *cp); +#define XFS_LIC_ALL_FREE(cp) xfs_lic_all_free(cp) +#else +#define XFS_LIC_ALL_FREE(cp) ((cp)->lic_free = XFS_LIC_FREEMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_ARE_ALL_FREE) +int xfs_lic_are_all_free(xfs_log_item_chunk_t *cp); +#define XFS_LIC_ARE_ALL_FREE(cp) xfs_lic_are_all_free(cp) +#else +#define XFS_LIC_ARE_ALL_FREE(cp) (((cp)->lic_free & XFS_LIC_FREEMASK) ==\ + XFS_LIC_FREEMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_ISFREE) +int xfs_lic_isfree(xfs_log_item_chunk_t *cp, int slot); +#define XFS_LIC_ISFREE(cp,slot) xfs_lic_isfree(cp,slot) +#else +#define XFS_LIC_ISFREE(cp,slot) ((cp)->lic_free & (1 << (slot))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_CLAIM) +void xfs_lic_claim(xfs_log_item_chunk_t *cp, int slot); +#define XFS_LIC_CLAIM(cp,slot) xfs_lic_claim(cp,slot) +#else +#define XFS_LIC_CLAIM(cp,slot) ((cp)->lic_free &= ~(1 << (slot))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_RELSE) +void xfs_lic_relse(xfs_log_item_chunk_t *cp, int slot); +#define XFS_LIC_RELSE(cp,slot) xfs_lic_relse(cp,slot) +#else +#define XFS_LIC_RELSE(cp,slot) ((cp)->lic_free |= 1 << (slot)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_SLOT) +xfs_log_item_desc_t *xfs_lic_slot(xfs_log_item_chunk_t *cp, int slot); +#define XFS_LIC_SLOT(cp,slot) xfs_lic_slot(cp,slot) +#else +#define XFS_LIC_SLOT(cp,slot) (&((cp)->lic_descs[slot])) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_DESC_TO_SLOT) +int xfs_lic_desc_to_slot(xfs_log_item_desc_t *dp); +#define XFS_LIC_DESC_TO_SLOT(dp) xfs_lic_desc_to_slot(dp) +#else +#define XFS_LIC_DESC_TO_SLOT(dp) ((uint)((dp)->lid_index)) +#endif +/* + * Calculate the address of a chunk given a descriptor pointer: + * dp - dp->lid_index give the address of the start of the lic_descs array. + * From this we subtract the offset of the lic_descs field in a chunk. + * All of this yields the address of the chunk, which is + * cast to a chunk pointer. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_DESC_TO_CHUNK) +xfs_log_item_chunk_t *xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp); +#define XFS_LIC_DESC_TO_CHUNK(dp) xfs_lic_desc_to_chunk(dp) +#else +#define XFS_LIC_DESC_TO_CHUNK(dp) ((xfs_log_item_chunk_t*) \ + (((xfs_caddr_t)((dp) - (dp)->lid_index)) -\ + (xfs_caddr_t)(((xfs_log_item_chunk_t*) \ + 0)->lic_descs))) +#endif + +#ifdef __KERNEL__ +/* + * This is the type of function which can be given to xfs_trans_callback() + * to be called upon the transaction's commit to disk. + */ +typedef void (*xfs_trans_callback_t)(struct xfs_trans *, void *); + +/* + * This is the structure maintained for every active transaction. + */ +typedef struct xfs_trans { + unsigned int t_magic; /* magic number */ + xfs_log_callback_t t_logcb; /* log callback struct */ + struct xfs_trans *t_forw; /* async list pointers */ + struct xfs_trans *t_back; /* async list pointers */ + unsigned int t_type; /* transaction type */ + unsigned int t_log_res; /* amt of log space resvd */ + unsigned int t_log_count; /* count for perm log res */ + unsigned int t_blk_res; /* # of blocks resvd */ + unsigned int t_blk_res_used; /* # of resvd blocks used */ + unsigned int t_rtx_res; /* # of rt extents resvd */ + unsigned int t_rtx_res_used; /* # of resvd rt extents used */ + xfs_log_ticket_t t_ticket; /* log mgr ticket */ + sema_t t_sema; /* sema for commit completion */ + xfs_lsn_t t_lsn; /* log seq num of trans commit*/ + struct xfs_mount *t_mountp; /* ptr to fs mount struct */ + struct xfs_dquot_acct *t_dqinfo; /* accting info for dquots */ + xfs_trans_callback_t t_callback; /* transaction callback */ + void *t_callarg; /* callback arg */ + unsigned int t_flags; /* misc flags */ + long t_icount_delta; /* superblock icount change */ + long t_ifree_delta; /* superblock ifree change */ + long t_fdblocks_delta; /* superblock fdblocks chg */ + long t_res_fdblocks_delta; /* on-disk only chg */ + long t_frextents_delta;/* superblock freextents chg*/ + long t_res_frextents_delta; /* on-disk only chg */ + long t_ag_freeblks_delta; /* debugging counter */ + long t_ag_flist_delta; /* debugging counter */ + long t_ag_btree_delta; /* debugging counter */ + long t_dblocks_delta;/* superblock dblocks change */ + long t_agcount_delta;/* superblock agcount change */ + long t_imaxpct_delta;/* superblock imaxpct change */ + long t_rextsize_delta;/* superblock rextsize chg */ + long t_rbmblocks_delta;/* superblock rbmblocks chg */ + long t_rblocks_delta;/* superblock rblocks change */ + long t_rextents_delta;/* superblocks rextents chg */ + long t_rextslog_delta;/* superblocks rextslog chg */ + unsigned int t_items_free; /* log item descs free */ + xfs_log_item_chunk_t t_items; /* first log item desc chunk */ + xfs_trans_header_t t_header; /* header for in-log trans */ +} xfs_trans_t; + +#endif /* __KERNEL__ */ + + +#define XFS_TRANS_MAGIC 0x5452414E /* 'TRAN' */ +/* + * Values for t_flags. + */ +#define XFS_TRANS_DIRTY 0x01 /* something needs to be logged */ +#define XFS_TRANS_SB_DIRTY 0x02 /* superblock is modified */ +#define XFS_TRANS_PERM_LOG_RES 0x04 /* xact took a permanent log res */ +#define XFS_TRANS_SYNC 0x08 /* make commit synchronous */ +#define XFS_TRANS_DQ_DIRTY 0x10 /* at least one dquot in trx dirty */ +#define XFS_TRANS_RESERVE 0x20 /* OK to use reserved data blocks */ + +/* + * Values for call flags parameter. + */ +#define XFS_TRANS_NOSLEEP 0x1 +#define XFS_TRANS_WAIT 0x2 +#define XFS_TRANS_RELEASE_LOG_RES 0x4 +#define XFS_TRANS_ABORT 0x8 + +/* + * Field values for xfs_trans_mod_sb. + */ +#define XFS_TRANS_SB_ICOUNT 0x00000001 +#define XFS_TRANS_SB_IFREE 0x00000002 +#define XFS_TRANS_SB_FDBLOCKS 0x00000004 +#define XFS_TRANS_SB_RES_FDBLOCKS 0x00000008 +#define XFS_TRANS_SB_FREXTENTS 0x00000010 +#define XFS_TRANS_SB_RES_FREXTENTS 0x00000020 +#define XFS_TRANS_SB_DBLOCKS 0x00000040 +#define XFS_TRANS_SB_AGCOUNT 0x00000080 +#define XFS_TRANS_SB_IMAXPCT 0x00000100 +#define XFS_TRANS_SB_REXTSIZE 0x00000200 +#define XFS_TRANS_SB_RBMBLOCKS 0x00000400 +#define XFS_TRANS_SB_RBLOCKS 0x00000800 +#define XFS_TRANS_SB_REXTENTS 0x00001000 +#define XFS_TRANS_SB_REXTSLOG 0x00002000 + + +/* + * Various log reservation values. + * These are based on the size of the file system block + * because that is what most transactions manipulate. + * Each adds in an additional 128 bytes per item logged to + * try to account for the overhead of the transaction mechanism. + * + * Note: + * Most of the reservations underestimate the number of allocation + * groups into which they could free extents in the xfs_bmap_finish() + * call. This is because the number in the worst case is quite high + * and quite unusual. In order to fix this we need to change + * xfs_bmap_finish() to free extents in only a single AG at a time. + * This will require changes to the EFI code as well, however, so that + * the EFI for the extents not freed is logged again in each transaction. + * See bug 261917. + */ + +/* + * Per-extent log reservation for the allocation btree changes + * involved in freeing or allocating an extent. + * 2 trees * (2 blocks/level * max depth - 1) * block size + */ +#define XFS_ALLOCFREE_LOG_RES(mp,nx) \ + ((nx) * (2 * XFS_FSB_TO_B((mp), 2 * XFS_AG_MAXLEVELS(mp) - 1))) +#define XFS_ALLOCFREE_LOG_COUNT(mp,nx) \ + ((nx) * (2 * (2 * XFS_AG_MAXLEVELS(mp) - 1))) + +/* + * Per-directory log reservation for any directory change. + * dir blocks: (1 btree block per level + data block + free block) * dblock size + * bmap btree: (levels + 2) * max depth * block size + * v2 directory blocks can be fragmented below the dirblksize down to the fsb + * size, so account for that in the DAENTER macros. + */ +#define XFS_DIROP_LOG_RES(mp) \ + (XFS_FSB_TO_B(mp, XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK)) + \ + (XFS_FSB_TO_B(mp, XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1))) +#define XFS_DIROP_LOG_COUNT(mp) \ + (XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK) + \ + XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1) + +/* + * In a write transaction we can allocate a maximum of 2 + * extents. This gives: + * the inode getting the new extents: inode size + * the inode\'s bmap btree: max depth * block size + * the agfs of the ags from which the extents are allocated: 2 * sector + * the superblock free block counter: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size + * And the bmap_finish transaction can free bmap blocks in a join: + * the agfs of the ags containing the blocks: 2 * sector size + * the agfls of the ags containing the blocks: 2 * sector size + * the super block free block counter: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_WRITE_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)) + \ + (2 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 2) + \ + (128 * (4 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))),\ + ((2 * (mp)->m_sb.sb_sectsize) + \ + (2 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 2) + \ + (128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))))) + +#define XFS_WRITE_LOG_RES(mp) ((mp)->m_reservations.tr_write) + +/* + * In truncating a file we free up to two extents at once. We can modify: + * the inode being truncated: inode size + * the inode\'s bmap btree: (max depth + 1) * block size + * And the bmap_finish transaction can free the blocks and bmap blocks: + * the agf for each of the ags: 4 * sector size + * the agfl for each of the ags: 4 * sector size + * the super block to reflect the freed blocks: sector size + * worst case split in allocation btrees per extent assuming 4 extents: + * 4 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_ITRUNCATE_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1) + \ + (128 * (2 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)))), \ + ((4 * (mp)->m_sb.sb_sectsize) + \ + (4 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 4) + \ + (128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4)))))) + +#define XFS_ITRUNCATE_LOG_RES(mp) ((mp)->m_reservations.tr_itruncate) + +/* + * In renaming a files we can modify: + * the four inodes involved: 4 * inode size + * the two directory btrees: 2 * (max depth + v2) * dir block size + * the two directory bmap btrees: 2 * max depth * block size + * And the bmap_finish transaction can free dir and bmap blocks (two sets + * of bmap blocks) giving: + * the agf for the ags in which the blocks live: 3 * sector size + * the agfl for the ags in which the blocks live: 3 * sector size + * the superblock for the free block count: sector size + * the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_RENAME_LOG_RES(mp) \ + (MAX( \ + ((4 * (mp)->m_sb.sb_inodesize) + \ + (2 * XFS_DIROP_LOG_RES(mp)) + \ + (128 * (4 + 2 * XFS_DIROP_LOG_COUNT(mp)))), \ + ((3 * (mp)->m_sb.sb_sectsize) + \ + (3 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 3) + \ + (128 * (7 + XFS_ALLOCFREE_LOG_COUNT(mp, 3)))))) + +#define XFS_RENAME_LOG_RES(mp) ((mp)->m_reservations.tr_rename) + +/* + * For creating a link to an inode: + * the parent directory inode: inode size + * the linked inode: inode size + * the directory btree could split: (max depth + v2) * dir block size + * the directory bmap btree could join or split: (max depth + v2) * blocksize + * And the bmap_finish transaction can free some bmap blocks giving: + * the agf for the ag in which the blocks live: sector size + * the agfl for the ag in which the blocks live: sector size + * the superblock for the free block count: sector size + * the allocation btrees: 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_LINK_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_inodesize + \ + XFS_DIROP_LOG_RES(mp) + \ + (128 * (2 + XFS_DIROP_LOG_COUNT(mp)))), \ + ((mp)->m_sb.sb_sectsize + \ + (mp)->m_sb.sb_sectsize + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (3 + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))))) + +#define XFS_LINK_LOG_RES(mp) ((mp)->m_reservations.tr_link) + +/* + * For removing a directory entry we can modify: + * the parent directory inode: inode size + * the removed inode: inode size + * the directory btree could join: (max depth + v2) * dir block size + * the directory bmap btree could join or split: (max depth + v2) * blocksize + * And the bmap_finish transaction can free the dir and bmap blocks giving: + * the agf for the ag in which the blocks live: 2 * sector size + * the agfl for the ag in which the blocks live: 2 * sector size + * the superblock for the free block count: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_REMOVE_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_inodesize + \ + XFS_DIROP_LOG_RES(mp) + \ + (128 * (2 + XFS_DIROP_LOG_COUNT(mp)))), \ + ((2 * (mp)->m_sb.sb_sectsize) + \ + (2 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 2) + \ + (128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))))) + +#define XFS_REMOVE_LOG_RES(mp) ((mp)->m_reservations.tr_remove) + +/* + * For symlink we can modify: + * the parent directory inode: inode size + * the new inode: inode size + * the inode btree entry: 1 block + * the directory btree: (max depth + v2) * dir block size + * the directory inode\'s bmap btree: (max depth + v2) * block size + * the blocks for the symlink: 1 KB + * Or in the first xact we allocate some inodes giving: + * the agi and agf of the ag getting the new inodes: 2 * sectorsize + * the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize + * the inode btree: max depth * blocksize + * the allocation btrees: 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_SYMLINK_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_inodesize + \ + XFS_FSB_TO_B(mp, 1) + \ + XFS_DIROP_LOG_RES(mp) + \ + 1024 + \ + (128 * (4 + XFS_DIROP_LOG_COUNT(mp)))), \ + (2 * (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B((mp), XFS_IALLOC_BLOCKS((mp))) + \ + XFS_FSB_TO_B((mp), XFS_IN_MAXLEVELS(mp)) + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (2 + XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp) + \ + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))))) + +#define XFS_SYMLINK_LOG_RES(mp) ((mp)->m_reservations.tr_symlink) + +/* + * For create we can modify: + * the parent directory inode: inode size + * the new inode: inode size + * the inode btree entry: block size + * the superblock for the nlink flag: sector size + * the directory btree: (max depth + v2) * dir block size + * the directory inode\'s bmap btree: (max depth + v2) * block size + * Or in the first xact we allocate some inodes giving: + * the agi and agf of the ag getting the new inodes: 2 * sectorsize + * the superblock for the nlink flag: sector size + * the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize + * the inode btree: max depth * blocksize + * the allocation btrees: 2 trees * (max depth - 1) * block size + */ +#define XFS_CALC_CREATE_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B(mp, 1) + \ + XFS_DIROP_LOG_RES(mp) + \ + (128 * (3 + XFS_DIROP_LOG_COUNT(mp)))), \ + (3 * (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B((mp), XFS_IALLOC_BLOCKS((mp))) + \ + XFS_FSB_TO_B((mp), XFS_IN_MAXLEVELS(mp)) + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (2 + XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp) + \ + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))))) + +#define XFS_CREATE_LOG_RES(mp) ((mp)->m_reservations.tr_create) + +/* + * Making a new directory is the same as creating a new file. + */ +#define XFS_CALC_MKDIR_LOG_RES(mp) XFS_CALC_CREATE_LOG_RES(mp) + +#define XFS_MKDIR_LOG_RES(mp) ((mp)->m_reservations.tr_mkdir) + +/* + * In freeing an inode we can modify: + * the inode being freed: inode size + * the super block free inode counter: sector size + * the agi hash list and counters: sector size + * the inode btree entry: block size + * the on disk inode before ours in the agi hash list: inode cluster size + */ +#define XFS_CALC_IFREE_LOG_RES(mp) \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_sectsize + \ + (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B((mp), 1) + \ + MAX(XFS_FSB_TO_B((mp), 1), XFS_INODE_CLUSTER_SIZE(mp)) + \ + (128 * 5)) + +#define XFS_IFREE_LOG_RES(mp) ((mp)->m_reservations.tr_ifree) + +/* + * When only changing the inode we log the inode and possibly the superblock + * We also add a bit of slop for the transaction stuff. + */ +#define XFS_CALC_ICHANGE_LOG_RES(mp) ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_sectsize + 512) + +#define XFS_ICHANGE_LOG_RES(mp) ((mp)->m_reservations.tr_ichange) + +/* + * Growing the data section of the filesystem. + * superblock + * agi and agf + * allocation btrees + */ +#define XFS_CALC_GROWDATA_LOG_RES(mp) \ + ((mp)->m_sb.sb_sectsize * 3 + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (3 + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) + +#define XFS_GROWDATA_LOG_RES(mp) ((mp)->m_reservations.tr_growdata) + +/* + * Growing the rt section of the filesystem. + * In the first set of transactions (ALLOC) we allocate space to the + * bitmap or summary files. + * superblock: sector size + * agf of the ag from which the extent is allocated: sector size + * bmap btree for bitmap/summary inode: max depth * blocksize + * bitmap/summary inode: inode size + * allocation btrees for 1 block alloc: 2 * (2 * maxdepth - 1) * blocksize + */ +#define XFS_CALC_GROWRTALLOC_LOG_RES(mp) \ + (2 * (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)) + \ + (mp)->m_sb.sb_inodesize + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * \ + (3 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + \ + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) + +#define XFS_GROWRTALLOC_LOG_RES(mp) ((mp)->m_reservations.tr_growrtalloc) + +/* + * Growing the rt section of the filesystem. + * In the second set of transactions (ZERO) we zero the new metadata blocks. + * one bitmap/summary block: blocksize + */ +#define XFS_CALC_GROWRTZERO_LOG_RES(mp) \ + ((mp)->m_sb.sb_blocksize + 128) + +#define XFS_GROWRTZERO_LOG_RES(mp) ((mp)->m_reservations.tr_growrtzero) + +/* + * Growing the rt section of the filesystem. + * In the third set of transactions (FREE) we update metadata without + * allocating any new blocks. + * superblock: sector size + * bitmap inode: inode size + * summary inode: inode size + * one bitmap block: blocksize + * summary blocks: new summary size + */ +#define XFS_CALC_GROWRTFREE_LOG_RES(mp) \ + ((mp)->m_sb.sb_sectsize + \ + 2 * (mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_blocksize + \ + (mp)->m_rsumsize + \ + (128 * 5)) + +#define XFS_GROWRTFREE_LOG_RES(mp) ((mp)->m_reservations.tr_growrtfree) + +/* + * Logging the inode modification timestamp on a synchronous write. + * inode + */ +#define XFS_CALC_SWRITE_LOG_RES(mp) \ + ((mp)->m_sb.sb_inodesize + 128) + +#define XFS_SWRITE_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) + +/* + * Logging the inode timestamps on an fsync -- same as SWRITE + * as long as SWRITE logs the entire inode core + */ +#define XFS_FSYNC_TS_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) + +/* + * Logging the inode mode bits when writing a setuid/setgid file + * inode + */ +#define XFS_CALC_WRITEID_LOG_RES(mp) \ + ((mp)->m_sb.sb_inodesize + 128) + +#define XFS_WRITEID_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) + +/* + * Converting the inode from non-attributed to attributed. + * the inode being converted: inode size + * agf block and superblock (for block allocation) + * the new block (directory sized) + * bmap blocks for the new directory block + * allocation btrees + */ +#define XFS_CALC_ADDAFORK_LOG_RES(mp) \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_sectsize * 2 + \ + (mp)->m_dirblksize + \ + (XFS_DIR_IS_V1(mp) ? 0 : \ + XFS_FSB_TO_B(mp, (XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1))) + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (4 + \ + (XFS_DIR_IS_V1(mp) ? 0 : \ + XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1) + \ + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) + +#define XFS_ADDAFORK_LOG_RES(mp) ((mp)->m_reservations.tr_addafork) + +/* + * Removing the attribute fork of a file + * the inode being truncated: inode size + * the inode\'s bmap btree: max depth * block size + * And the bmap_finish transaction can free the blocks and bmap blocks: + * the agf for each of the ags: 4 * sector size + * the agfl for each of the ags: 4 * sector size + * the super block to reflect the freed blocks: sector size + * worst case split in allocation btrees per extent assuming 4 extents: + * 4 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_ATTRINVAL_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + \ + (128 * (1 + XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)))), \ + ((4 * (mp)->m_sb.sb_sectsize) + \ + (4 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 4) + \ + (128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4)))))) + +#define XFS_ATTRINVAL_LOG_RES(mp) ((mp)->m_reservations.tr_attrinval) + +/* + * Setting an attribute. + * the inode getting the attribute + * the superblock for allocations + * the agfs extents are allocated from + * the attribute btree * max depth + * the inode allocation btree + * Since attribute transaction space is dependent on the size of the attribute, + * the calculation is done partially at mount time and partially at runtime. + */ +#define XFS_CALC_ATTRSET_LOG_RES(mp) \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B((mp), XFS_DA_NODE_MAXDEPTH) + \ + (128 * (2 + XFS_DA_NODE_MAXDEPTH))) + +#define XFS_ATTRSET_LOG_RES(mp, ext) \ + ((mp)->m_reservations.tr_attrset + \ + (ext * (mp)->m_sb.sb_sectsize) + \ + (ext * XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK))) + \ + (128 * (ext + (ext * XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK))))) + +/* + * Removing an attribute. + * the inode: inode size + * the attribute btree could join: max depth * block size + * the inode bmap btree could join or split: max depth * block size + * And the bmap_finish transaction can free the attr blocks freed giving: + * the agf for the ag in which the blocks live: 2 * sector size + * the agfl for the ag in which the blocks live: 2 * sector size + * the superblock for the free block count: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_ATTRRM_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + XFS_FSB_TO_B((mp), XFS_DA_NODE_MAXDEPTH) + \ + XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + \ + (128 * (1 + XFS_DA_NODE_MAXDEPTH + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)))), \ + ((2 * (mp)->m_sb.sb_sectsize) + \ + (2 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 2) + \ + (128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))))) + +#define XFS_ATTRRM_LOG_RES(mp) ((mp)->m_reservations.tr_attrrm) + +/* + * Clearing a bad agino number in an agi hash bucket. + */ +#define XFS_CALC_CLEAR_AGI_BUCKET_LOG_RES(mp) \ + ((mp)->m_sb.sb_sectsize + 128) + +#define XFS_CLEAR_AGI_BUCKET_LOG_RES(mp) ((mp)->m_reservations.tr_clearagi) + + +/* + * Various log count values. + */ +#define XFS_DEFAULT_LOG_COUNT 1 +#define XFS_DEFAULT_PERM_LOG_COUNT 2 +#define XFS_ITRUNCATE_LOG_COUNT 2 +#define XFS_CREATE_LOG_COUNT 2 +#define XFS_MKDIR_LOG_COUNT 3 +#define XFS_SYMLINK_LOG_COUNT 3 +#define XFS_REMOVE_LOG_COUNT 2 +#define XFS_LINK_LOG_COUNT 2 +#define XFS_RENAME_LOG_COUNT 2 +#define XFS_WRITE_LOG_COUNT 2 +#define XFS_ADDAFORK_LOG_COUNT 2 +#define XFS_ATTRINVAL_LOG_COUNT 1 +#define XFS_ATTRSET_LOG_COUNT 3 +#define XFS_ATTRRM_LOG_COUNT 3 + +/* + * Here we centralize the specification of XFS meta-data buffer + * reference count values. This determine how hard the buffer + * cache tries to hold onto the buffer. + */ +#define XFS_AGF_REF 4 +#define XFS_AGI_REF 4 +#define XFS_AGFL_REF 3 +#define XFS_INO_BTREE_REF 3 +#define XFS_ALLOC_BTREE_REF 2 +#define XFS_BMAP_BTREE_REF 2 +#define XFS_DIR_BTREE_REF 2 +#define XFS_ATTR_BTREE_REF 1 +#define XFS_INO_REF 1 +#define XFS_DQUOT_REF 1 + +#ifdef __KERNEL__ +/* + * XFS transaction mechanism exported interfaces that are + * actually macros. + */ +#define xfs_trans_get_log_res(tp) ((tp)->t_log_res) +#define xfs_trans_get_log_count(tp) ((tp)->t_log_count) +#define xfs_trans_get_block_res(tp) ((tp)->t_blk_res) +#define xfs_trans_set_sync(tp) ((tp)->t_flags |= XFS_TRANS_SYNC) + +#ifdef DEBUG +#define xfs_trans_agblocks_delta(tp, d) ((tp)->t_ag_freeblks_delta += (long)d) +#define xfs_trans_agflist_delta(tp, d) ((tp)->t_ag_flist_delta += (long)d) +#define xfs_trans_agbtree_delta(tp, d) ((tp)->t_ag_btree_delta += (long)d) +#else +#define xfs_trans_agblocks_delta(tp, d) +#define xfs_trans_agflist_delta(tp, d) +#define xfs_trans_agbtree_delta(tp, d) +#endif + +/* + * XFS transaction mechanism exported interfaces. + */ +void xfs_trans_init(struct xfs_mount *); +xfs_trans_t *xfs_trans_alloc(struct xfs_mount *, uint); +xfs_trans_t *xfs_trans_dup(xfs_trans_t *); +int xfs_trans_reserve(xfs_trans_t *, uint, uint, uint, + uint, uint); +void xfs_trans_callback(xfs_trans_t *, + void (*)(xfs_trans_t *, void *), void *); +void xfs_trans_mod_sb(xfs_trans_t *, uint, long); +struct xfs_buf *xfs_trans_get_buf(xfs_trans_t *, struct buftarg *, xfs_daddr_t, + int, uint); +int xfs_trans_read_buf(struct xfs_mount *, xfs_trans_t *, + struct buftarg *, xfs_daddr_t, int, uint, + struct xfs_buf **); +struct xfs_buf *xfs_trans_getsb(xfs_trans_t *, struct xfs_mount *, int); + +void xfs_trans_brelse(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_bjoin(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_bhold(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_bhold_until_committed(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_binval(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint); +void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *); +int xfs_trans_iget(struct xfs_mount *, xfs_trans_t *, + xfs_ino_t , uint, struct xfs_inode **); +void xfs_trans_iput(xfs_trans_t *, struct xfs_inode *, uint); +void xfs_trans_ijoin(xfs_trans_t *, struct xfs_inode *, uint); +void xfs_trans_ihold(xfs_trans_t *, struct xfs_inode *); +void xfs_trans_ihold_release(xfs_trans_t *, struct xfs_inode *); +void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint); +void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint); +struct xfs_efi_log_item *xfs_trans_get_efi(xfs_trans_t *, uint); +void xfs_efi_release(struct xfs_efi_log_item *, uint); +void xfs_trans_log_efi_extent(xfs_trans_t *, + struct xfs_efi_log_item *, + xfs_fsblock_t, + xfs_extlen_t); +struct xfs_efd_log_item *xfs_trans_get_efd(xfs_trans_t *, + struct xfs_efi_log_item *, + uint); +void xfs_trans_log_efd_extent(xfs_trans_t *, + struct xfs_efd_log_item *, + xfs_fsblock_t, + xfs_extlen_t); +void xfs_trans_log_create_rpc(xfs_trans_t *, int, xfs_ino_t); +void xfs_trans_log_setattr_rpc(xfs_trans_t *, int); +int xfs_trans_commit(xfs_trans_t *, uint flags, xfs_lsn_t *); +void xfs_trans_commit_async(struct xfs_mount *); +void xfs_trans_cancel(xfs_trans_t *, int); +void xfs_trans_ail_init(struct xfs_mount *); +xfs_lsn_t xfs_trans_push_ail(struct xfs_mount *, xfs_lsn_t); +xfs_lsn_t xfs_trans_tail_ail(struct xfs_mount *); +void xfs_trans_unlocked_item(struct xfs_mount *, + xfs_log_item_t *); + +/* + * Not necessarily exported, but used outside a single file. + */ +int xfs_trans_lsn_danger(struct xfs_mount *, xfs_lsn_t); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_TRANS_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_trans_space.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_trans_space.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_trans_space.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_trans_space.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_TRANS_SPACE_H__ +#define __XFS_TRANS_SPACE_H__ + +/* + * Components of space reservations. + */ +#define XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) \ + (((mp)->m_alloc_mxr[0]) - ((mp)->m_alloc_mnr[0])) +#define XFS_EXTENTADD_SPACE_RES(mp,w) (XFS_BM_MAXLEVELS(mp,w) - 1) +#define XFS_NEXTENTADD_SPACE_RES(mp,b,w)\ + (((b + XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) - 1) / \ + XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp)) * \ + XFS_EXTENTADD_SPACE_RES(mp,w)) +#define XFS_DAENTER_1B(mp,w) ((w) == XFS_DATA_FORK ? (mp)->m_dirblkfsbs : 1) +#define XFS_DAENTER_DBS(mp,w) \ + (XFS_DA_NODE_MAXDEPTH + \ + ((XFS_DIR_IS_V2(mp) && (w) == XFS_DATA_FORK) ? 2 : 0)) +#define XFS_DAENTER_BLOCKS(mp,w) \ + (XFS_DAENTER_1B(mp,w) * XFS_DAENTER_DBS(mp,w)) +#define XFS_DAENTER_BMAP1B(mp,w) \ + XFS_NEXTENTADD_SPACE_RES(mp, XFS_DAENTER_1B(mp, w), w) +#define XFS_DAENTER_BMAPS(mp,w) \ + (XFS_DAENTER_DBS(mp,w) * XFS_DAENTER_BMAP1B(mp,w)) +#define XFS_DAENTER_SPACE_RES(mp,w) \ + (XFS_DAENTER_BLOCKS(mp,w) + XFS_DAENTER_BMAPS(mp,w)) +#define XFS_DAREMOVE_SPACE_RES(mp,w) XFS_DAENTER_BMAPS(mp,w) +#define XFS_DIRENTER_MAX_SPLIT(mp,nl) \ + (((mp)->m_sb.sb_blocksize == 512 && \ + XFS_DIR_IS_V1(mp) && \ + (nl) >= XFS_DIR_LEAF_CAN_DOUBLE_SPLIT_LEN) ? 2 : 1) +#define XFS_DIRENTER_SPACE_RES(mp,nl) \ + (XFS_DAENTER_SPACE_RES(mp, XFS_DATA_FORK) * \ + XFS_DIRENTER_MAX_SPLIT(mp,nl)) +#define XFS_DIRREMOVE_SPACE_RES(mp) \ + XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK) +#define XFS_IALLOC_SPACE_RES(mp) \ + (XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp)-1) + +/* + * Space reservation values for various transactions. + */ +#define XFS_ADDAFORK_SPACE_RES(mp) \ + ((mp)->m_dirblkfsbs + \ + (XFS_DIR_IS_V1(mp) ? 0 : XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK))) +#define XFS_ATTRRM_SPACE_RES(mp) \ + XFS_DAREMOVE_SPACE_RES(mp, XFS_ATTR_FORK) +/* This macro is not used - see inline code in xfs_attr_set */ +#define XFS_ATTRSET_SPACE_RES(mp, v) \ + (XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) + XFS_B_TO_FSB(mp, v)) +#define XFS_CREATE_SPACE_RES(mp,nl) \ + (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) +#define XFS_DIOSTRAT_SPACE_RES(mp, v) \ + (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + (v)) +#define XFS_GROWFS_SPACE_RES(mp) \ + (2 * XFS_AG_MAXLEVELS(mp)) +#define XFS_GROWFSRT_SPACE_RES(mp,b) \ + ((b) + XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK)) +#define XFS_LINK_SPACE_RES(mp,nl) \ + XFS_DIRENTER_SPACE_RES(mp,nl) +#define XFS_MKDIR_SPACE_RES(mp,nl) \ + (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) +#define XFS_QM_DQALLOC_SPACE_RES(mp) \ + (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + \ + XFS_DQUOT_CLUSTER_SIZE_FSB) +#define XFS_QM_QINOCREATE_SPACE_RES(mp) \ + XFS_IALLOC_SPACE_RES(mp) +#define XFS_REMOVE_SPACE_RES(mp) \ + XFS_DIRREMOVE_SPACE_RES(mp) +#define XFS_RENAME_SPACE_RES(mp,nl) \ + (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) +#define XFS_SYMLINK_SPACE_RES(mp,nl,b) \ + (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b)) + +#endif /* __XFS_TRANS_SPACE_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/include/xfs_types.h linux-2.4-xfs/cmd/xfsprogs/include/xfs_types.h --- linux-2.4.7/cmd/xfsprogs/include/xfs_types.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/include/xfs_types.h Wed Apr 18 21:41:37 2001 @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_TYPES_H__ +#define __XFS_TYPES_H__ + +/* + * Some types are conditional based on the selected configuration. + * Set XFS_BIG_FILES=1 or 0 and XFS_BIG_FILESYSTEMS=1 or 0 depending + * on the desired configuration. + * XFS_BIG_FILES needs pgno_t to be 64 bits (64-bit kernels). + * XFS_BIG_FILESYSTEMS needs daddr_t to be 64 bits (N32 and 64-bit kernels). + * + * Expect these to be set from klocaldefs, or from the machine-type + * defs files for the normal case. + */ + +#define XFS_BIG_FILES 1 +#define XFS_BIG_FILESYSTEMS 1 + +typedef __uint32_t xfs_agblock_t; /* blockno in alloc. group */ +typedef __uint32_t xfs_extlen_t; /* extent length in blocks */ +typedef __uint32_t xfs_agnumber_t; /* allocation group number */ +typedef __int32_t xfs_extnum_t; /* # of extents in a file */ +typedef __int16_t xfs_aextnum_t; /* # extents in an attribute fork */ +typedef __int64_t xfs_fsize_t; /* bytes in a file */ +typedef __uint64_t xfs_ufsize_t; /* unsigned bytes in a file */ + +typedef __int32_t xfs_suminfo_t; /* type of bitmap summary info */ +typedef __int32_t xfs_rtword_t; /* word type for bitmap manipulations */ + +typedef __int64_t xfs_lsn_t; /* log sequence number */ +typedef __int32_t xfs_tid_t; /* transaction identifier */ + +typedef __uint32_t xfs_dablk_t; /* dir/attr block number (in file) */ +typedef __uint32_t xfs_dahash_t; /* dir/attr hash value */ + +typedef __uint16_t xfs_prid_t; /* prid_t truncated to 16bits in XFS */ + +/* + * These types are 64 bits on disk but are either 32 or 64 bits in memory. + * Disk based types: + */ +typedef __uint64_t xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */ +typedef __uint64_t xfs_drfsbno_t; /* blockno in filesystem (raw) */ +typedef __uint64_t xfs_drtbno_t; /* extent (block) in realtime area */ +typedef __uint64_t xfs_dfiloff_t; /* block number in a file */ +typedef __uint64_t xfs_dfilblks_t; /* number of blocks in a file */ + +/* + * Memory based types are conditional. + */ +#if XFS_BIG_FILESYSTEMS +typedef __uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */ +typedef __uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */ +typedef __uint64_t xfs_rtblock_t; /* extent (block) in realtime area */ +typedef __int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */ +#else +typedef __uint32_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */ +typedef __uint32_t xfs_rfsblock_t; /* blockno in filesystem (raw) */ +typedef __uint32_t xfs_rtblock_t; /* extent (block) in realtime area */ +typedef __int32_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */ +#endif +#if XFS_BIG_FILES +typedef __uint64_t xfs_fileoff_t; /* block number in a file */ +typedef __int64_t xfs_sfiloff_t; /* signed block number in a file */ +typedef __uint64_t xfs_filblks_t; /* number of blocks in a file */ +#else +typedef __uint32_t xfs_fileoff_t; /* block number in a file */ +typedef __int32_t xfs_sfiloff_t; /* signed block number in a file */ +typedef __uint32_t xfs_filblks_t; /* number of blocks in a file */ +#endif + +typedef __uint8_t xfs_arch_t; /* architecutre of an xfs fs */ + +/* + * Null values for the types. + */ +#define NULLDFSBNO ((xfs_dfsbno_t)-1) +#define NULLDRFSBNO ((xfs_drfsbno_t)-1) +#define NULLDRTBNO ((xfs_drtbno_t)-1) +#define NULLDFILOFF ((xfs_dfiloff_t)-1) + +#define NULLFSBLOCK ((xfs_fsblock_t)-1) +#define NULLRFSBLOCK ((xfs_rfsblock_t)-1) +#define NULLRTBLOCK ((xfs_rtblock_t)-1) +#define NULLFILEOFF ((xfs_fileoff_t)-1) + +#define NULLAGBLOCK ((xfs_agblock_t)-1) +#define NULLAGNUMBER ((xfs_agnumber_t)-1) +#define NULLEXTNUM ((xfs_extnum_t)-1) + +#define NULLCOMMITLSN ((xfs_lsn_t)-1) + +/* + * Max values for extlen, extnum, aextnum. + */ +#define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */ +#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */ +#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */ + +/* + * MAXNAMELEN is the length (including the terminating null) of + * the longest permissible file (component) name. + */ +#define MAXNAMELEN 256 + +typedef enum { + XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi +} xfs_lookup_t; + +typedef enum { + XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi, + XFS_BTNUM_MAX +} xfs_btnum_t; + + +#if defined(CONFIG_PROC_FS) && defined(__KERNEL__) +/* + * XFS global statistics + */ +struct xfsstats { +# define XFSSTAT_END_EXTENT_ALLOC 4 + __uint32_t xs_allocx; + __uint32_t xs_allocb; + __uint32_t xs_freex; + __uint32_t xs_freeb; +# define XFSSTAT_END_ALLOC_BTREE (XFSSTAT_END_EXTENT_ALLOC+4) + __uint32_t xs_abt_lookup; + __uint32_t xs_abt_compare; + __uint32_t xs_abt_insrec; + __uint32_t xs_abt_delrec; +# define XFSSTAT_END_BLOCK_MAPPING (XFSSTAT_END_ALLOC_BTREE+7) + __uint32_t xs_blk_mapr; + __uint32_t xs_blk_mapw; + __uint32_t xs_blk_unmap; + __uint32_t xs_add_exlist; + __uint32_t xs_del_exlist; + __uint32_t xs_look_exlist; + __uint32_t xs_cmp_exlist; +# define XFSSTAT_END_BLOCK_MAP_BTREE (XFSSTAT_END_BLOCK_MAPPING+4) + __uint32_t xs_bmbt_lookup; + __uint32_t xs_bmbt_compare; + __uint32_t xs_bmbt_insrec; + __uint32_t xs_bmbt_delrec; +# define XFSSTAT_END_DIRECTORY_OPS (XFSSTAT_END_BLOCK_MAP_BTREE+4) + __uint32_t xs_dir_lookup; + __uint32_t xs_dir_create; + __uint32_t xs_dir_remove; + __uint32_t xs_dir_getdents; +# define XFSSTAT_END_TRANSACTIONS (XFSSTAT_END_DIRECTORY_OPS+3) + __uint32_t xs_trans_sync; + __uint32_t xs_trans_async; + __uint32_t xs_trans_empty; +# define XFSSTAT_END_INODE_OPS (XFSSTAT_END_TRANSACTIONS+7) + __uint32_t xs_ig_attempts; + __uint32_t xs_ig_found; + __uint32_t xs_ig_frecycle; + __uint32_t xs_ig_missed; + __uint32_t xs_ig_dup; + __uint32_t xs_ig_reclaims; + __uint32_t xs_ig_attrchg; +# define XFSSTAT_END_LOG_OPS (XFSSTAT_END_INODE_OPS+5) + __uint32_t xs_log_writes; + __uint32_t xs_log_blocks; + __uint32_t xs_log_noiclogs; + __uint32_t xs_log_force; + __uint32_t xs_log_force_sleep; +# define XFSSTAT_END_TAIL_PUSHING (XFSSTAT_END_LOG_OPS+10) + __uint32_t xs_try_logspace; + __uint32_t xs_sleep_logspace; + __uint32_t xs_push_ail; + __uint32_t xs_push_ail_success; + __uint32_t xs_push_ail_pushbuf; + __uint32_t xs_push_ail_pinned; + __uint32_t xs_push_ail_locked; + __uint32_t xs_push_ail_flushing; + __uint32_t xs_push_ail_restarts; + __uint32_t xs_push_ail_flush; +# define XFSSTAT_END_WRITE_CONVERT (XFSSTAT_END_TAIL_PUSHING+2) + __uint32_t xs_xstrat_quick; + __uint32_t xs_xstrat_split; +# define XFSSTAT_END_READ_WRITE_OPS (XFSSTAT_END_WRITE_CONVERT+2) + __uint32_t xs_write_calls; + __uint32_t xs_read_calls; +# define XFSSTAT_END_ATTRIBUTE_OPS (XFSSTAT_END_READ_WRITE_OPS+4) + __uint32_t xs_attr_get; + __uint32_t xs_attr_set; + __uint32_t xs_attr_remove; + __uint32_t xs_attr_list; +# define XFSSTAT_END_QUOTA_OPS (XFSSTAT_END_ATTRIBUTE_OPS+8) + __uint32_t xs_qm_dqreclaims; + __uint32_t xs_qm_dqreclaim_misses; + __uint32_t xs_qm_dquot_dups; + __uint32_t xs_qm_dqcachemisses; + __uint32_t xs_qm_dqcachehits; + __uint32_t xs_qm_dqwants; + __uint32_t xs_qm_dqshake_reclaims; + __uint32_t xs_qm_dqinact_reclaims; +# define XFSSTAT_END_INODE_CLUSTER (XFSSTAT_END_QUOTA_OPS+3) + __uint32_t xs_iflush_count; + __uint32_t xs_icluster_flushcnt; + __uint32_t xs_icluster_flushinode; +# define XFSSTAT_END_VNODE_OPS (XFSSTAT_END_INODE_CLUSTER+8) + __uint32_t vn_active; /* # vnodes not on free lists */ + __uint32_t vn_alloc; /* # times vn_alloc called */ + __uint32_t vn_get; /* # times vn_get called */ + __uint32_t vn_hold; /* # times vn_hold called */ + __uint32_t vn_rele; /* # times vn_rele called */ + __uint32_t vn_reclaim; /* # times vn_reclaim called */ + __uint32_t vn_remove; /* # times vn_remove called */ + __uint32_t vn_free; /* # times vn_free called */ +/* Extra precision counters */ + __uint64_t xs_xstrat_bytes; + __uint64_t xs_write_bytes; + __uint64_t xs_read_bytes; +} xfsstats; + +# define XFS_STATS_INC(count) ( (count)++ ) +# define XFS_STATS_DEC(count) ( (count)-- ) +# define XFS_STATS_ADD(count, inc) ( (count) += (inc) ) +#else /* !CONFIG_PROC_FS */ +# define XFS_STATS_INC(count) +# define XFS_STATS_DEC(count) +# define XFS_STATS_ADD(count, inc) +#endif /* !CONFIG_PROC_FS */ + + +#ifdef __KERNEL__ + +/* juggle IRIX device numbers - still used in ondisk structures */ + +#define IRIX_DEV_BITSMAJOR 14 +#define IRIX_DEV_BITSMINOR 18 +#define IRIX_DEV_MAXMAJ 0x1ff +#define IRIX_DEV_MAXMIN 0x3ffff +#define IRIX_DEV_MAJOR(dev) ((int)(((unsigned)(dev)>>IRIX_DEV_BITSMINOR) \ + & IRIX_DEV_MAXMAJ)) +#define IRIX_DEV_MINOR(dev) ((int)((dev)&IRIX_DEV_MAXMIN)) +#define IRIX_MKDEV(major,minor) ((xfs_dev_t)(((major)< + +#define XQM_CMD(cmd) ( ('X'<<8)+(cmd) ) +#define IS_XQM_CMD(cmd) ( ((int)(cmd)>>8) == 'X' ) + +/* + * Disk quota - quotactl(2) commands for XFS Quota Manager (XQM). + */ +#define Q_XQUOTAON XQM_CMD(0x1) /* enable quota accounting/enforcement */ +#define Q_XQUOTAOFF XQM_CMD(0x2) /* disable quota accounting/enforcement */ +#define Q_XGETQUOTA XQM_CMD(0x3) /* get disk limits & usage */ +#define Q_XSETQLIM XQM_CMD(0x4) /* set disk limits only */ +#define Q_XGETQSTAT XQM_CMD(0x5) /* returns fs_quota_stat_t struct */ +#define Q_XQUOTARM XQM_CMD(0x6) /* free quota files' space */ + +/* + * fs_disk_quota structure: + * + * This contains the current quota information regarding a user/proj/group. + * It is 64-bit aligned, and all the blk units are in BBs (Basic Blocks) of + * 512 bytes. + */ +#define FS_DQUOT_VERSION 1 /* fs_disk_quota.d_version */ +typedef struct fs_disk_quota { + __s8 d_version; /* version of this structure */ + __s8 d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */ + __u16 d_fieldmask; /* field specifier */ + __u32 d_id; /* user, project, or group ID */ + __u64 d_blk_hardlimit;/* absolute limit on disk blks */ + __u64 d_blk_softlimit;/* preferred limit on disk blks */ + __u64 d_ino_hardlimit;/* maximum # allocated inodes */ + __u64 d_ino_softlimit;/* preferred inode limit */ + __u64 d_bcount; /* # disk blocks owned by the user */ + __u64 d_icount; /* # inodes owned by the user */ + __s32 d_itimer; /* zero if within inode limits */ + /* if not, we refuse service */ + __s32 d_btimer; /* similar to above; for disk blocks */ + __u16 d_iwarns; /* # warnings issued wrt num inodes */ + __u16 d_bwarns; /* # warnings issued wrt disk blocks */ + __s32 d_padding2; /* padding2 - for future use */ + __u64 d_rtb_hardlimit;/* absolute limit on realtime blks */ + __u64 d_rtb_softlimit;/* preferred limit on RT disk blks */ + __u64 d_rtbcount; /* # realtime blocks owned */ + __s32 d_rtbtimer; /* similar to above; for RT disk blks */ + __u16 d_rtbwarns; /* # warnings issued wrt RT disk blks */ + __s16 d_padding3; /* padding3 - for future use */ + char d_padding4[8]; /* yet more padding */ +} fs_disk_quota_t; + +/* + * These fields are sent to Q_XSETQLIM to specify fields that need to change. + */ +#define FS_DQ_ISOFT (1<<0) +#define FS_DQ_IHARD (1<<1) +#define FS_DQ_BSOFT (1<<2) +#define FS_DQ_BHARD (1<<3) +#define FS_DQ_RTBSOFT (1<<4) +#define FS_DQ_RTBHARD (1<<5) +#define FS_DQ_LIMIT_MASK (FS_DQ_ISOFT | FS_DQ_IHARD | FS_DQ_BSOFT | \ + FS_DQ_BHARD | FS_DQ_RTBSOFT | FS_DQ_RTBHARD) +/* + * These timers can only be set in super user's dquot. For others, timers are + * automatically started and stopped. Superusers timer values set the limits + * for the rest. In case these values are zero, the DQ_{F,B}TIMELIMIT values + * defined below are used. + * These values also apply only to the d_fieldmask field for Q_XSETQLIM. + */ +#define FS_DQ_BTIMER (1<<6) +#define FS_DQ_ITIMER (1<<7) +#define FS_DQ_RTBTIMER (1<<8) +#define FS_DQ_TIMER_MASK (FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER) + +/* + * The following constants define the default amount of time given a user + * before the soft limits are treated as hard limits (usually resulting + * in an allocation failure). These may be modified by the quotactl(2) + * system call with the Q_XSETQLIM command. + */ +#define DQ_FTIMELIMIT (7 * 24*60*60) /* 1 week */ +#define DQ_BTIMELIMIT (7 * 24*60*60) /* 1 week */ + +/* + * Various flags related to quotactl(2). Only relevant to XFS filesystems. + */ +#define XFS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */ +#define XFS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */ +#define XFS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */ +#define XFS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */ + +#define XFS_USER_QUOTA (1<<0) /* user quota type */ +#define XFS_PROJ_QUOTA (1<<1) /* (IRIX) project quota type */ +#define XFS_GROUP_QUOTA (1<<2) /* group quota type */ + +/* + * fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system. + * Provides a centralized way to get meta infomation about the quota subsystem. + * eg. space taken up for user and group quotas, number of dquots currently + * incore. + */ +#define FS_QSTAT_VERSION 1 /* fs_quota_stat.qs_version */ + +/* + * Some basic infomation about 'quota files'. + */ +typedef struct fs_qfilestat { + __u64 qfs_ino; /* inode number */ + __u64 qfs_nblks; /* number of BBs 512-byte-blks */ + __u32 qfs_nextents; /* number of extents */ +} fs_qfilestat_t; + +typedef struct fs_quota_stat { + __s8 qs_version; /* version number for future changes */ + __u16 qs_flags; /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */ + __s8 qs_pad; /* unused */ + fs_qfilestat_t qs_uquota; /* user quota storage information */ + fs_qfilestat_t qs_gquota; /* group quota storage information */ + __u32 qs_incoredqs; /* number of dquots incore */ + __s32 qs_btimelimit; /* limit for blks timer */ + __s32 qs_itimelimit; /* limit for inodes timer */ + __s32 qs_rtbtimelimit;/* limit for rt blks timer */ + __u16 qs_bwarnlimit; /* limit for num warnings */ + __u16 qs_iwarnlimit; /* limit for num warnings */ +} fs_quota_stat_t; + +#endif /* __XQM_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/install-sh linux-2.4-xfs/cmd/xfsprogs/install-sh --- linux-2.4.7/cmd/xfsprogs/install-sh Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/install-sh Mon Jan 15 00:52:52 2001 @@ -0,0 +1,273 @@ +#! /bin/sh +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +# +# This script emulates bsd install and also recognises +# two environment variables, with the following semantics :- +# +# $DIST_MANIFEST - if set, the name of the file to append manifest +# information in the following format: +# File : f mode owner group src target +# Directory: d mode owner group target +# Symlink : l linkval target +# +# $DIST_ROOT - if set, prepend to target +# +# The sematics of all combinations of these two variables +# are as follows: +# +# $DIST_MANIFEST? $DIST_ROOT? | Copy? Append Manifest? +# -----------------------------+-------------------------- +# not set not set | yes no +# not set set | yes no +# set not set | no yes +# set set | yes yes +# +_usage() { + echo "Usage: $prog [-o owner] [-g group] [-m mode] -d directory" + echo "or $prog [-D] [-o owner] [-g group] [-m mode] file directory/file" + echo "or $prog [-o owner] [-g group] [-m mode] file [file ...] directory" + echo "or $prog -S file target (creates \"target\" symlink)" + echo "" + echo "The \$DIST_MANIFEST and \$DIST_ROOT environment variables affect the" + echo "behaviour of this command - see comments in the script." + echo "The -D flag is only available for the second usage, and causes" + echo "the target directory to be created before installing the file." + echo "" + exit 1 +} + +_chown () +{ + _st=255 + if [ $# -eq 3 ] ; then + chown $1:$2 $3 + _st=$? + if [ $_st -ne 0 ] ; then + if [ $REAL_UID != '0' ] ; then + if [ ! -f $DIST_ROOT/.chown.quite ] ; then + echo '===============================================' + echo Ownership of files under ${DIST_ROOT:-/} + echo cannot be changed + echo '===============================================' + if [ -n "$DIST_ROOT" ] ; then + touch $DIST_ROOT/.chown.quite + fi + fi + _st=0 + fi + fi + fi + + return $_st +} + + +_manifest () +{ + echo $* | sed -e 's/\/\//\//g' >>${DIST_MANIFEST:-/dev/null} +} + +prog=`basename $0` +HERE=`pwd` +dflag=false +Dflag=false +Sflag=false +DIRMODE=755 +FILEMODE=644 +OWNER=`id -u` +GROUP=`id -g` +REAL_UID=$OWNER + +# default is to install and don't append manifest +INSTALL=true +MANIFEST=: + +[ -n "$DIST_MANIFEST" -a -z "$DIST_ROOT" ] && INSTALL=false +[ -n "$DIST_MANIFEST" ] && MANIFEST="_manifest" + +[ $# -eq 0 ] && _usage + +if $INSTALL +then + CP=cp; LN=ln; MKDIR=mkdir; CHMOD=chmod; CHOWN=_chown +else + CP=true; LN=true; MKDIR=true; CHMOD=true; CHOWN=true +fi + +[ -n "$DIST_ROOT" -a $REAL_UID -ne 0 ] && CHOWN=true + +while getopts "Dcm:d:S:o:g:" c $* +do + case $c in + c) + ;; + g) + GROUP=$OPTARG + ;; + o) + OWNER=$OPTARG + ;; + m) + DIRMODE=`expr $OPTARG` + FILEMODE=$DIRMODE + ;; + D) + Dflag=true + ;; + S) + symlink=$OPTARG + Sflag=true + ;; + d) + dir=$DIST_ROOT/$OPTARG + dflag=true + ;; + *) + _usage + ;; + esac +done + +shift `expr $OPTIND - 1` + +status=0 +if $dflag +then + # + # first usage + # + $MKDIR -p $dir + status=$? + if [ $status -eq 0 ] + then + $CHMOD $DIRMODE $dir + status=$? + fi + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir + status=$? + fi + $MANIFEST d $DIRMODE $OWNER $GROUP ${dir#$DIST_ROOT} +elif $Sflag +then + # + # fourth usage (symlink) + # + if [ $# -ne 1 ] + then + _usage + else + target=$DIST_ROOT/$1 + fi + $LN -s -f $symlink $target + status=$? + $MANIFEST l $symlink ${target#$DIST_ROOT} +else + list="" + dir="" + if [ $# -eq 2 ] + then + # + # second usage + # + f=$1 + dir=$DIST_ROOT/$2 + if $Dflag + then + mkdir -p `dirname $dir` + fi + $CP $f $dir + status=$? + if [ $status -eq 0 ] + then + if [ -f $dir/$f ] + then + $CHMOD $FILEMODE $dir/$f + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir/$f + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f + else + $CHMOD $FILEMODE $dir + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$dir ${dir#$DIST_ROOT} + fi + fi + else + # + # third usage + # + n=1 + while [ $# -gt 0 ] + do + if [ $# -gt 1 ] + then + list="$list $1" + else + dir=$DIST_ROOT/$1 + fi + shift + done + + # echo DIR=$dir list=\"$list\" + for f in $list + do + $CP $f $dir + status=$? + if [ $status -eq 0 ] + then + $CHMOD $FILEMODE $dir/$f + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir/$f + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f + fi + [ $status -ne 0 ] && break + done + fi +fi + +exit $status diff -rNu linux-2.4.7/cmd/xfsprogs/libhandle/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/libhandle/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/libhandle/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libhandle/CVS/Entries Thu Jul 5 11:44:34 2001 @@ -0,0 +1,4 @@ +/Makefile/1.3/Fri Feb 9 07:45:14 2001/-ko/ +/handle.c/1.4/Wed May 9 06:56:06 2001/-ko/ +/jdm.c/1.2/Fri Feb 9 07:45:14 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/libhandle/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/libhandle/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/libhandle/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libhandle/CVS/Repository Thu Jul 5 11:44:34 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/libhandle diff -rNu linux-2.4.7/cmd/xfsprogs/libhandle/CVS/Root linux-2.4-xfs/cmd/xfsprogs/libhandle/CVS/Root --- linux-2.4.7/cmd/xfsprogs/libhandle/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libhandle/CVS/Root Thu Jul 5 11:44:34 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/libhandle/Makefile linux-2.4-xfs/cmd/xfsprogs/libhandle/Makefile --- linux-2.4.7/cmd/xfsprogs/libhandle/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libhandle/Makefile Fri Feb 9 01:45:14 2001 @@ -0,0 +1,61 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LIB = libhandle +STATICLIBTARGET = $(LIB).a +#MAJOR = 1 +#MINOR = 0 +#LIBTARGET = $(LIB).so.$(MAJOR) + +CFILES = handle.c jdm.c +LCFLAGS = -D_REENTRANT + +default: $(STATICLIBTARGET) + +include $(BUILDRULES) + +install: default + +#MODE = $(shell test -f /etc/debian_version && echo 644 || echo 755) +#install: default +# $(INSTALL) -m 755 -d $(PKG_SLIB_DIR) +# $(INSTALL) -m $(MODE) $(LIBTARGET) $(PKG_SLIB_DIR)/$(LIBTARGET).$(MINOR) +# $(INSTALL) -S $(LIBTARGET).$(MINOR) $(PKG_SLIB_DIR)/$(LIBTARGET) +#install-dev: default +# $(INSTALL) -S $(PKG_SLIB_DIR)/$(LIBTARGET) $(PKG_LIB_DIR)/$(LIB).so + +install-dev: default + $(INSTALL) -m 755 -d $(PKG_LIB_DIR) + $(INSTALL) -m 644 $(STATICLIBTARGET) $(PKG_LIB_DIR) diff -rNu linux-2.4.7/cmd/xfsprogs/libhandle/handle.c linux-2.4-xfs/cmd/xfsprogs/libhandle/handle.c --- linux-2.4.7/cmd/xfsprogs/libhandle/handle.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libhandle/handle.c Wed May 9 01:56:06 2001 @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include "handle.h" + +/* just pick a value we know is more than big enough */ +#define MAXHANSIZ 64 + +/* + * The actual content of a handle is supposed to be opaque here. + * But, to do handle_to_fshandle, we need to know what it is. Sigh. + * However we can get by with knowing only that the first 8 bytes of + * a file handle are the file system ID, and that a file system handle + * consists of only those 8 bytes. + */ + +#define FSIDSIZE 8 + +typedef union { + int fd; + char *path; +} comarg_t; + + +int +obj_to_handle ( + int fsfd, + unsigned int opcode, + comarg_t obj, + void **hanp, + size_t *hlen); + + +/* + * Filesystem Handle -> Open File Descriptor Cache + * + * Maps filesystem handles to a corresponding open file descriptor for that + * filesystem. We need this because we're doing handle operations via ioctl + * and we need to remember the open file descriptor for each filesystem. + */ + +struct fdhash { + int fsfd; + char fsh[FSIDSIZE]; + struct fdhash *fnxt; +}; + +struct fdhash *fdhash_head = NULL; + +int +path_to_fshandle ( + char *path, /* input, path to convert */ + void **hanp, /* output, pointer to data */ + size_t *hlen) /* output, size of returned data */ +{ + int result; + int fd; + comarg_t obj; + struct fdhash *fdhp; + + fd = open(path, O_RDONLY); + + if (fd < 0) { + perror(path); + exit(1); + } + + obj.path = path; + + result = obj_to_handle (fd, XFS_IOC_PATH_TO_FSHANDLE, + obj, hanp, hlen); + + if (result >= 0) { + fdhp = malloc(sizeof(struct fdhash)); + + if (fdhp == NULL) { + errno = ENOMEM; + return -1; + } + + fdhp->fsfd = fd; + fdhp->fnxt = NULL; + + memcpy(fdhp->fsh, *hanp, FSIDSIZE); + + if (fdhash_head) + fdhash_head->fnxt = fdhp; + else + fdhash_head = fdhp; + } + + return result; +} + + +int +path_to_handle ( + char *path, /* input, path to convert */ + void **hanp, /* output, pointer to data */ + size_t *hlen) /* output, size of returned data */ +{ + int fd; + int result; + comarg_t obj; + + fd = open(path, O_RDONLY); + + if (fd < 0) { + perror(path); + exit(1); + } + + obj.path = path; + + result = obj_to_handle (fd, XFS_IOC_PATH_TO_HANDLE, obj, hanp, hlen); + + close(fd); + + return result; +} + + +int +fd_to_handle ( + int fd, /* input, file descriptor */ + void **hanp, /* output, pointer to data */ + size_t *hlen) /* output, size of returned data */ +{ + comarg_t obj; + + obj.fd = fd; + + return obj_to_handle (fd, XFS_IOC_FD_TO_HANDLE, obj, hanp, hlen); +} + + +int +handle_to_fshandle ( + void *hanp, + size_t hlen, + void **fshanp, + size_t *fshlen) +{ + if (hlen < FSIDSIZE) + return EINVAL; + + *fshanp = malloc (FSIDSIZE); + + if (*fshanp == NULL) + return ENOMEM; + + *fshlen = FSIDSIZE; + + memcpy(*fshanp, hanp, FSIDSIZE); + + return 0; +} + + +int +handle_to_fsfd(void *hanp) +{ + struct fdhash *fdhp; + + for (fdhp = fdhash_head; fdhp != NULL; fdhp = fdhp->fnxt) { + if (memcmp(fdhp->fsh, hanp, FSIDSIZE) == 0) + return fdhp->fsfd; + } + return -1; +} + + +int +obj_to_handle ( + int fsfd, + unsigned int opcode, + comarg_t obj, + void **hanp, + size_t *hlen) +{ + char hbuf [MAXHANSIZ]; + int ret; + xfs_fsop_handlereq_t hreq; + + if (opcode == XFS_IOC_FD_TO_HANDLE) { + hreq.fd = obj.fd; + hreq.path = NULL; + } else { + hreq.fd = 0; + hreq.path = obj.path; + } + + hreq.oflags = 0; + hreq.ihandle = NULL; + hreq.ihandlen = 0; + hreq.ohandle = hbuf; + hreq.ohandlen = (__u32 *)hlen; + + ret = (int) ioctl(fsfd, opcode, &hreq); + + if (ret) + return ret; + + *hanp = malloc(*hlen); + + if (*hanp == NULL) { + errno = ENOMEM; + return -1; + } + + memcpy(*hanp, hbuf, (int) *hlen); + + return 0; +} + + + +int +open_by_handle ( + void *hanp, + size_t hlen, + int rw) +{ + int fd; + int result; + xfs_fsop_handlereq_t hreq; + + if ((fd = handle_to_fsfd(hanp)) < 0) { + errno = EBADF; + return -1; + } + + hreq.fd = 0; + hreq.path = NULL; + hreq.oflags = rw; + hreq.ihandle = hanp; + hreq.ihandlen = hlen; + hreq.ohandle = NULL; + hreq.ohandlen = NULL; + + result = ioctl(fd, XFS_IOC_OPEN_BY_HANDLE, &hreq); + + return result; +} + +int +readlink_by_handle ( + void *hanp, + size_t hlen, + void *buf, + size_t bufsiz) +{ + int fd; + xfs_fsop_handlereq_t hreq; + + + if ((fd = handle_to_fsfd(hanp)) < 0) { + errno = EBADF; + return -1; + } + + hreq.fd = 0; + hreq.path = NULL; + hreq.oflags = 0; + hreq.ihandle = hanp; + hreq.ihandlen = hlen; + hreq.ohandle = buf; + hreq.ohandlen = (__u32 *)&bufsiz; + + return (int) ioctl(fd, XFS_IOC_READLINK_BY_HANDLE, &hreq); +} + +/*ARGSUSED*/ +void +free_handle ( + void *hanp, + size_t hlen) +{ + free (hanp); +} diff -rNu linux-2.4.7/cmd/xfsprogs/libhandle/jdm.c linux-2.4-xfs/cmd/xfsprogs/libhandle/jdm.c --- linux-2.4.7/cmd/xfsprogs/libhandle/jdm.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libhandle/jdm.c Fri Feb 9 01:45:14 2001 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include + +/* internal fshandle - typecast to a void for external use */ +#define FSHANDLE_SZ 8 +typedef struct fshandle { + char fsh_space[FSHANDLE_SZ]; +} fshandle_t; + +/* private file handle - for use by open_by_handle */ +#define FILEHANDLE_SZ 24 +#define FILEHANDLE_SZ_FOLLOWING 14 +#define FILEHANDLE_SZ_PAD 2 +typedef struct filehandle { + fshandle_t fh_fshandle; /* handle of fs containing this inode */ + int16_t fh_sz_following; /* bytes in handle after this member */ + char fh_pad[FILEHANDLE_SZ_PAD]; /* padding, must be zeroed */ + __uint32_t fh_gen; /* generation count */ + xfs_ino_t fh_ino; /* 64 bit ino */ +} filehandle_t; + + +static void +jdm_fill_filehandle( filehandle_t *handlep, + fshandle_t *fshandlep, + xfs_bstat_t *statp ) +{ + handlep->fh_fshandle = *fshandlep; + handlep->fh_sz_following = FILEHANDLE_SZ_FOLLOWING; + bzero(handlep->fh_pad, FILEHANDLE_SZ_PAD); + handlep->fh_gen = statp->bs_gen; + handlep->fh_ino = statp->bs_ino; +} + +jdm_fshandle_t * +jdm_getfshandle( char *mntpnt ) +{ + fshandle_t *fshandlep; + size_t fshandlesz; + char resolved[MAXPATHLEN]; + + /* sanity checks */ + ASSERT( sizeof( fshandle_t ) == FSHANDLE_SZ ); + ASSERT( sizeof( filehandle_t ) == FILEHANDLE_SZ ); + ASSERT( sizeof( filehandle_t ) + - + offsetofmember( filehandle_t, fh_pad ) + == + FILEHANDLE_SZ_FOLLOWING ); + ASSERT( sizeofmember( filehandle_t, fh_pad ) == FILEHANDLE_SZ_PAD ); + ASSERT( FILEHANDLE_SZ_PAD == sizeof( int16_t )); + + fshandlep = 0; /* for lint */ + fshandlesz = sizeof( *fshandlep ); + + if (!realpath( mntpnt, resolved )) + return NULL; + + if (path_to_fshandle( resolved, ( void ** )&fshandlep, &fshandlesz )) + return NULL; + + assert( fshandlesz == sizeof( *fshandlep )); + + return ( jdm_fshandle_t * )fshandlep; +} + + +/* externally visible functions */ + +void +jdm_new_filehandle( jdm_filehandle_t **handlep, + size_t *hlen, + jdm_fshandle_t *fshandlep, + xfs_bstat_t *statp) +{ + /* allocate and fill filehandle */ + *hlen = sizeof(filehandle_t); + *handlep = (filehandle_t *) malloc(*hlen); + + if (*handlep) + jdm_fill_filehandle(*handlep, (fshandle_t *) fshandlep, statp); +} + +/* ARGSUSED */ +void +jdm_delete_filehandle( jdm_filehandle_t *handlep, size_t hlen ) +{ + free(handlep); +} + +intgen_t +jdm_open( jdm_fshandle_t *fshp, xfs_bstat_t *statp, intgen_t oflags ) +{ + register fshandle_t *fshandlep = ( fshandle_t * )fshp; + filehandle_t filehandle; + intgen_t fd; + + jdm_fill_filehandle( &filehandle, fshandlep, statp ); + fd = open_by_handle( ( void * )&filehandle, + sizeof( filehandle ), + oflags ); + return fd; +} + +intgen_t +jdm_readlink( jdm_fshandle_t *fshp, + xfs_bstat_t *statp, + char *bufp, size_t bufsz ) +{ + register fshandle_t *fshandlep = ( fshandle_t * )fshp; + filehandle_t filehandle; + intgen_t rval; + + jdm_fill_filehandle( &filehandle, fshandlep, statp ); + rval = readlink_by_handle( ( void * )&filehandle, + sizeof( filehandle ), + ( void * )bufp, + bufsz ); + return rval; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/libxfs/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/libxfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/CVS/Entries Thu Jul 5 11:44:44 2001 @@ -0,0 +1,31 @@ +/Makefile/1.4/Wed May 9 06:56:06 2001/-ko/ +/init.c/1.7/Tue Jul 3 04:33:45 2001/-ko/ +/logitem.c/1.2/Fri Apr 13 00:04:55 2001/-ko/ +/rdwr.c/1.4/Wed May 9 06:56:06 2001/-ko/ +/trans.c/1.3/Thu Apr 12 23:30:32 2001/-ko/ +/util.c/1.3/Thu Apr 12 23:30:32 2001/-ko/ +/xfs.h/1.6/Mon Apr 16 22:53:46 2001/-ko/ +/xfs_alloc.c/1.3/Thu Apr 19 02:41:37 2001/-ko/ +/xfs_alloc_btree.c/1.3/Thu Apr 19 02:41:37 2001/-ko/ +/xfs_attr_leaf.c/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_bit.c/1.2/Thu Apr 12 23:30:32 2001/-ko/ +/xfs_bmap.c/1.4/Thu Apr 19 02:41:37 2001/-ko/ +/xfs_bmap_btree.c/1.4/Thu Apr 19 02:41:37 2001/-ko/ +/xfs_btree.c/1.4/Mon May 28 00:02:18 2001/-ko/ +/xfs_da_btree.c/1.3/Mon Apr 16 22:53:46 2001/-ko/ +/xfs_dir.c/1.3/Thu Apr 19 02:41:37 2001/-ko/ +/xfs_dir2.c/1.3/Thu Apr 19 02:41:37 2001/-ko/ +/xfs_dir2_block.c/1.2/Thu Apr 12 23:30:32 2001/-ko/ +/xfs_dir2_data.c/1.2/Thu Apr 12 23:30:32 2001/-ko/ +/xfs_dir2_leaf.c/1.2/Thu Apr 12 23:30:32 2001/-ko/ +/xfs_dir2_node.c/1.3/Fri Apr 13 00:04:55 2001/-ko/ +/xfs_dir2_sf.c/1.2/Thu Apr 12 23:30:32 2001/-ko/ +/xfs_dir_leaf.c/1.2/Thu Apr 12 23:30:32 2001/-ko/ +/xfs_ialloc.c/1.2/Thu Apr 12 23:30:32 2001/-ko/ +/xfs_ialloc_btree.c/1.2/Thu Apr 12 23:30:32 2001/-ko/ +/xfs_inode.c/1.2/Mon Apr 16 22:53:46 2001/-ko/ +/xfs_mount.c/1.2/Tue Apr 3 02:52:38 2001/-ko/ +/xfs_rtalloc.c/1.3/Thu Apr 12 23:30:32 2001/-ko/ +/xfs_rtbit.c/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_trans.c/1.1/Mon Jan 15 05:36:03 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/libxfs/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/libxfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/CVS/Repository Thu Jul 5 11:44:34 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/libxfs diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/CVS/Root linux-2.4-xfs/cmd/xfsprogs/libxfs/CVS/Root --- linux-2.4.7/cmd/xfsprogs/libxfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/CVS/Root Thu Jul 5 11:44:34 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/Makefile linux-2.4-xfs/cmd/xfsprogs/libxfs/Makefile --- linux-2.4.7/cmd/xfsprogs/libxfs/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/Makefile Wed May 9 01:56:06 2001 @@ -0,0 +1,82 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +LIB = libxfs +STATICLIBTARGET = $(LIB).a + +HFILES = xfs.h +CFILES = init.c logitem.c rdwr.c trans.c util.c \ + xfs_bit.c xfs_rtbit.c xfs_alloc.c xfs_ialloc.c xfs_rtalloc.c \ + xfs_inode.c xfs_btree.c xfs_alloc_btree.c xfs_ialloc_btree.c \ + xfs_bmap_btree.c xfs_da_btree.c xfs_dir.c xfs_dir_leaf.c \ + xfs_dir2.c xfs_dir2_leaf.c xfs_attr_leaf.c xfs_dir2_block.c \ + xfs_dir2_node.c xfs_dir2_data.c xfs_dir2_sf.c xfs_bmap.c \ + xfs_mount.c xfs_trans.c + +# +# Tracing flags: +# -DIO_DEBUG reads and writes of buffers +# -DMEM_DEBUG all zone memory use +# -DLI_DEBUG log item (ino/buf) manipulation +# -DXACT_DEBUG transaction state changes +# +LCFLAGS += -I. + +# don't try linking xfs_repair with a debug libxfs. +DEBUG = -DNDEBUG + +default: $(STATICLIBTARGET) + +include $(BUILDRULES) + +install: default + +install-dev: default + $(INSTALL) -m 755 -d $(PKG_LIB_DIR) + $(INSTALL) -m 644 $(STATICLIBTARGET) $(PKG_LIB_DIR) + +#MODE = $(shell test -f /etc/debian_version && echo 644 || echo 755) +#MAJOR = 1 +#MINOR = 0 +#LIBTARGET = $(LIB).so.$(MAJOR) +#LDIRT = $(LIB).so +#default: +# [ -L $(LIB).so ] || $(LN_S) $(LIBTARGET) $(LIB).so +#install: default +# $(INSTALL) -m 755 -d $(PKG_SLIB_DIR) +# $(INSTALL) -m $(MODE) $(LIBTARGET) $(PKG_SLIB_DIR)/$(LIBTARGET).$(MINOR) +# #$(INSTALL) -S $(LIBTARGET).$(MINOR) $(PKG_SLIB_DIR)/$(LIBTARGET) +#install-dev: default +# $(INSTALL) -S $(PKG_SLIB_DIR)/$(LIBTARGET) $(PKG_LIB_DIR)/$(LIB).so diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/init.c linux-2.4-xfs/cmd/xfsprogs/libxfs/init.c --- linux-2.4.7/cmd/xfsprogs/libxfs/init.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/init.c Mon Jul 2 23:33:45 2001 @@ -0,0 +1,775 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#define ustat __kernel_ustat +#include +#include +#include +#undef ustat +#include +#include +#include + +#ifndef BLKBSZSET +#define BLKBSZSET _IO(0x12,110) /* set device block size */ +#endif + +#define findrawpath(x) x +#define findblockpath(x) x + +char *progname = "libxfs"; /* default, changed by each tool */ + +/* + * dev_map - map open devices to fd. + */ +#define MAX_DEVS 10 /* arbitary maximum */ +int nextfakedev = -1; /* device number to give to next fake device */ +static struct dev_to_fd { + dev_t dev; + int fd; +} dev_map[MAX_DEVS]={{0}}; + +static int +check_ismounted(char *name, char *block) +{ + struct ustat ust; + struct stat64 st; + + if (stat64(block, &st) < 0) + return 0; + if ((st.st_mode & S_IFMT) != S_IFBLK) + return 0; + if (ustat(st.st_rdev, &ust) >= 0) { + fprintf(stderr, "%s: %s contains a mounted filesystem\n", + progname, name); + return 1; + } + return 0; +} + +/* + * Checks whether a given device has a mounted, writable + * filesystem, returns 1 if it does & fatal (just warns + * if not fatal, but allows us to proceed). + * + * Useful to tools which will produce uncertain results + * if the filesystem is active - repair, check, logprint. + */ +static int +check_isactive(char *name, char *block, int fatal) +{ +#define PROC_MOUNTED "/proc/mounts" + int sts = 0; + FILE *f; + struct mntent *mnt; + struct stat64 st, mst; + struct ustat ust; + char mounts[MAXPATHLEN]; + + if (stat64(block, &st) < 0) + return sts; + if ((st.st_mode & S_IFMT) != S_IFBLK) + return sts; + if (ustat(st.st_rdev, &ust) < 0) + return sts; + + strcpy(mounts, access(PROC_MOUNTED, R_OK)? PROC_MOUNTED : MOUNTED); + if ((f = setmntent(mounts, "r")) == NULL) { + fprintf(stderr, "%s: %s contains a possibly writable, mounted " + "filesystem\n", progname, name); + return fatal; + } + while ((mnt = getmntent(f)) != NULL) { + if (stat64(mnt->mnt_fsname, &mst) < 0) + continue; + if ((mst.st_mode & S_IFMT) != S_IFBLK) + continue; + if (mst.st_rdev == st.st_rdev + && hasmntopt(mnt, MNTOPT_RO) != NULL) + break; + } + if (mnt == NULL) { + fprintf(stderr, "%s: %s contains a writable, mounted " + "filesystem\n", progname, name); + sts = fatal; + } + endmntent(f); + + return sts; +} + +static __int64_t +findsize(char *path) +{ + int fd; + int error; + long size; + struct stat64 st; + + /* Test to see if we are dealing with a regular file rather than a + * block device, if we are just use the size returned by stat64 + */ + if (stat64(path, &st) < 0) { + fprintf(stderr, "%s: " + "cannot stat the device special file \"%s\": %s\n", + progname, path, strerror(errno)); + exit(1); + } + if ((st.st_mode & S_IFMT) == S_IFREG) { + return (__int64_t)(st.st_size >> 9); + } + + if ((fd = open(path, 0)) < 0) { + fprintf(stderr, "%s: " + "error opening the device special file \"%s\": %s\n", + progname, path, strerror(errno)); + exit(1); + } + error = ioctl(fd, BLKGETSIZE, &size); + if (error < 0) { + fprintf(stderr, "%s: can't determine device size\n", progname); + exit(1); + } + + close(fd); + + return (__int64_t)size; +} + + +/* libxfs_device_to_fd: + * lookup a device number in the device map + * return the associated fd + */ +int +libxfs_device_to_fd(dev_t device) +{ + int d; + + for (d=0;ddname; + logname = a->logname; + rtname = a->rtname; + a->ddev = a->logdev = a->rtdev = 0; + a->dfd = a->logfd = a->rtfd = -1; + a->dsize = a->logBBsize = a->logBBstart = a->rtsize = 0; + + (void)getcwd(curdir,MAXPATHLEN); + needcd = 0; + fd = -1; + readonly = (a->isreadonly & LIBXFS_ISREADONLY); + inactive = (a->isreadonly & LIBXFS_ISINACTIVE); + if (a->volname) { + if (stat64(a->volname, &stbuf) < 0) { + perror(a->volname); + goto done; + } + if (!(rawfile = findrawpath(a->volname))) { + fprintf(stderr, "%s: " + "can't find a character device matching %s\n", + progname, a->volname); + goto done; + } + if (!(blockfile = findblockpath(a->volname))) { + fprintf(stderr, "%s: " + "can't find a block device matching %s\n", + progname, a->volname); + goto done; + } + if (!readonly && !inactive && check_ismounted( + a->volname, blockfile)) + goto done; + if (inactive && check_isactive( + a->volname, blockfile, readonly)) + goto done; + needcd = 1; + fd = open(rawfile, O_RDONLY); +#ifdef HAVE_VOLUME_MANAGER + xlv_getdev_t getdev; + if (ioctl(fd, DIOCGETVOLDEV, &getdev) < 0) +#else + if (1) +#endif + { + if (a->notvolok) { + dname = a->dname = a->volname; + a->volname = NULL; + goto voldone; + } + fprintf(stderr, "%s: " + "%s is not a volume device name\n", + progname, a->volname); + if (a->notvolmsg) + fprintf(stderr, a->notvolmsg, a->volname); + goto done; + } +#ifdef HAVE_VOLUME_MANAGER + if (getdev.data_subvol_dev && dname) { + fprintf(stderr, "%s: " + "%s has a data subvolume, cannot specify %s\n", + progname, a->volname, dname); + goto done; + } + if (getdev.log_subvol_dev && logname) { + fprintf(stderr, "%s: " + "%s has a log subvolume, cannot specify %s\n", + progname, a->volname, logname); + goto done; + } + if (getdev.rt_subvol_dev && rtname) { + fprintf(stderr, "%s: %s has a realtime subvolume, " + "cannot specify %s\n", + progname, a->volname, rtname); + goto done; + } + if (!dname && getdev.data_subvol_dev) { + strcpy(dpath, "/tmp/libxfsdXXXXXX"); + (void)mktemp(dpath); + if (mknod(dpath, S_IFCHR | 0600, + getdev.data_subvol_dev) < 0) { + fprintf(stderr, "%s: mknod failed: %s\n", + progname, strerror(errno)); + goto done; + } + dname = dpath; + } + if (!logname && getdev.log_subvol_dev) { + strcpy(logpath, "/tmp/libxfslXXXXXX"); + (void)mktemp(logpath); + if (mknod(logpath, S_IFCHR | 0600, + getdev.log_subvol_dev) < 0) { + fprintf(stderr, "%s: mknod failed: %s\n", + progname, strerror(errno)); + goto done; + } + logname = logpath; + } + if (!rtname && getdev.rt_subvol_dev) { + strcpy(rtpath, "/tmp/libxfsrXXXXXX"); + (void)mktemp(rtpath); + if (mknod(rtpath, S_IFCHR | 0600, + getdev.rt_subvol_dev) < 0) { + fprintf(stderr, "%s: mknod failed: %s\n", + progname, strerror(errno)); + goto done; + } + rtname = rtpath; + } +#endif + } +voldone: + if (dname) { + if (dname[0] != '/' && needcd) + chdir(curdir); + if (a->disfile) { + a->ddev= libxfs_device_open(dname, a->dcreat, readonly, + a->setblksize); + a->dfd = libxfs_device_to_fd(a->ddev); + } else { + if (stat64(dname, &stbuf) < 0) { + fprintf(stderr, "%s: stat64 failed on %s: %s\n", + progname, dname, strerror(errno)); + goto done; + } + if (!(rawfile = findrawpath(dname))) { + fprintf(stderr, "%s: can't find a char device " + "matching %s\n", progname, dname); + goto done; + } + if (!(blockfile = findblockpath(dname))) { + fprintf(stderr, "%s: can't find a block device " + "matching %s\n", progname, dname); + goto done; + } + if (!readonly && !inactive && check_ismounted( + dname, blockfile)) + goto done; + if (inactive && check_isactive( + dname, blockfile, readonly)) + goto done; + a->ddev = libxfs_device_open(rawfile, + a->dcreat, readonly, a->setblksize); + a->dfd = libxfs_device_to_fd(a->ddev); + a->dsize = findsize(rawfile); + } + needcd = 1; + } else + a->dsize = 0; + if (logname) { + if (logname[0] != '/' && needcd) + chdir(curdir); + if (a->lisfile) { + a->logdev = libxfs_device_open(logname, + a->lcreat, readonly, a->setblksize); + a->logfd = libxfs_device_to_fd(a->logdev); + } else { + if (stat64(logname, &stbuf) < 0) { + fprintf(stderr, "%s: stat64 failed on %s: %s\n", + progname, logname, strerror(errno)); + goto done; + } + if (!(rawfile = findrawpath(logname))) { + fprintf(stderr, "%s: can't find a char device " + "matching %s\n", progname, logname); + goto done; + } + if (!(blockfile = findblockpath(logname))) { + fprintf(stderr, "%s: can't find a block device " + "matching %s\n", progname, logname); + goto done; + } + if (!readonly && !inactive && check_ismounted( + logname, blockfile)) + goto done; + else if (inactive && check_isactive( + logname, blockfile, readonly)) + goto done; + a->logdev = libxfs_device_open(rawfile, + a->lcreat, readonly, a->setblksize); + a->logfd = libxfs_device_to_fd(a->logdev); + a->logBBsize = findsize(rawfile); + } + needcd = 1; + } else + a->logBBsize = 0; + if (rtname) { + if (rtname[0] != '/' && needcd) + chdir(curdir); + if (a->risfile) { + a->rtdev = libxfs_device_open(rtname, + a->rcreat, readonly, a->setblksize); + a->rtfd = libxfs_device_to_fd(a->rtdev); + } else { + if (stat64(rtname, &stbuf) < 0) { + fprintf(stderr, "%s: stat64 failed on %s: %s\n", + progname, rtname, strerror(errno)); + goto done; + } + if (!(rawfile = findrawpath(rtname))) { + fprintf(stderr, "%s: can't find a char device " + "matching %s\n", progname, rtname); + goto done; + } + if (!(blockfile = findblockpath(rtname))) { + fprintf(stderr, "%s: can't find a block device " + "matching %s\n", progname, rtname); + goto done; + } + if (!readonly && !inactive && check_ismounted( + rtname, blockfile)) + goto done; + if (inactive && check_isactive( + rtname, blockfile, readonly)) + goto done; + a->rtdev = libxfs_device_open(rawfile, + a->rcreat, readonly, a->setblksize); + a->rtfd = libxfs_device_to_fd(a->rtdev); + a->rtsize = findsize(rawfile); + } + needcd = 1; + } else + a->rtsize = 0; + if (a->dsize < 0) { + fprintf(stderr, "%s: can't get size for data subvolume\n", + progname); + goto done; + } + if (a->logBBsize < 0) { + fprintf(stderr, "%s: can't get size for log subvolume\n", + progname); + goto done; + } + if (a->rtsize < 0) { + fprintf(stderr, "%s: can't get size for realtime subvolume\n", + progname); + goto done; + } + if (needcd) + chdir(curdir); + rval = 1; +done: + if (dpath[0]) + unlink(dpath); + if (logpath[0]) + unlink(logpath); + if (rtpath[0]) + unlink(rtpath); + if (fd >= 0) + close(fd); + if (!rval && a->ddev) + libxfs_device_close(a->ddev); + if (!rval && a->logdev) + libxfs_device_close(a->logdev); + if (!rval && a->rtdev) + libxfs_device_close(a->rtdev); + return rval; +} + + +/* + * Initialize/destroy all of the zone allocators we use. + */ +static void +manage_zones(int release) +{ + extern xfs_zone_t *xfs_ili_zone; + extern xfs_zone_t *xfs_inode_zone; + extern xfs_zone_t *xfs_ifork_zone; + extern xfs_zone_t *xfs_dabuf_zone; + extern xfs_zone_t *xfs_buf_item_zone; + extern xfs_zone_t *xfs_da_state_zone; + extern xfs_zone_t *xfs_btree_cur_zone; + extern xfs_zone_t *xfs_bmap_free_item_zone; + extern void xfs_dir_startup(); + + if (release) { /* free zone allocation */ + libxfs_free(xfs_inode_zone); + libxfs_free(xfs_ifork_zone); + libxfs_free(xfs_dabuf_zone); + libxfs_free(xfs_buf_item_zone); + libxfs_free(xfs_da_state_zone); + libxfs_free(xfs_btree_cur_zone); + libxfs_free(xfs_bmap_free_item_zone); + return; + } + /* otherwise initialise zone allocation */ + xfs_inode_zone = libxfs_zone_init(sizeof(xfs_inode_t), "xfs_inode"); + xfs_ifork_zone = libxfs_zone_init(sizeof(xfs_ifork_t), "xfs_ifork"); + xfs_dabuf_zone = libxfs_zone_init(sizeof(xfs_dabuf_t), "xfs_dabuf"); + xfs_ili_zone = libxfs_zone_init( + sizeof(xfs_inode_log_item_t), "xfs_inode_log_item"); + xfs_buf_item_zone = libxfs_zone_init( + sizeof(xfs_buf_log_item_t), "xfs_buf_log_item"); + xfs_da_state_zone = libxfs_zone_init( + sizeof(xfs_da_state_t), "xfs_da_state"); + xfs_btree_cur_zone = libxfs_zone_init( + sizeof(xfs_btree_cur_t), "xfs_btree_cur"); + xfs_bmap_free_item_zone = libxfs_zone_init( + sizeof(xfs_bmap_free_item_t), "xfs_bmap_free_item"); + xfs_dir_startup(); +} + +/* + * Get the bitmap and summary inodes into the mount structure + * at mount time. + */ +static int +rtmount_inodes(xfs_mount_t *mp) +{ + int error; + xfs_sb_t *sbp; + + sbp = &mp->m_sb; + if (sbp->sb_rbmino == NULLFSINO) + return 0; + error = libxfs_iread(mp, NULL, sbp->sb_rbmino, &mp->m_rbmip, 0); + if (error) { + fprintf(stderr, "%s: cannot read realtime bitmap inode (%d)\n", + progname, error); + return error; + } + ASSERT(mp->m_rbmip != NULL); + ASSERT(sbp->sb_rsumino != NULLFSINO); + error = libxfs_iread(mp, NULL, sbp->sb_rsumino, &mp->m_rsumip, 0); + if (error) { + fprintf(stderr, "%s: cannot read realtime summary inode (%d)\n", + progname, error); + return error; + } + ASSERT(mp->m_rsumip != NULL); + return 0; +} + +/* + * Mount structure initialization, provides a filled-in xfs_mount_t + * such that the numerous XFS_* macros can be used. If dev is zero, + * no IO will be performed (no size checks, read root inodes). + */ +xfs_mount_t * +libxfs_mount( + xfs_mount_t *mp, + xfs_sb_t *sb, + dev_t dev, + dev_t logdev, + dev_t rtdev, + int rrootinos) +{ + xfs_daddr_t d; + xfs_buf_t *bp; + xfs_sb_t *sbp; + size_t size; + int error; + + mp->m_dev = dev; + mp->m_rtdev = rtdev; + mp->m_logdev = logdev; + mp->m_sb = *sb; + sbp = &(mp->m_sb); + manage_zones(0); + + libxfs_mount_common(mp, sb); + + libxfs_alloc_compute_maxlevels(mp); + libxfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK); + libxfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK); + libxfs_ialloc_compute_maxlevels(mp); + + if (sbp->sb_imax_pct) { + /* Make sure the maximum inode count is a multiple of the + * units we allocate inodes in. + */ + mp->m_maxicount = (sbp->sb_dblocks * sbp->sb_imax_pct) / 100; + mp->m_maxicount = ((mp->m_maxicount / mp->m_ialloc_blks) * + mp->m_ialloc_blks) << sbp->sb_inopblog; + } else + mp->m_maxicount = 0; + + mp->m_inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE; + + /* + * Set whether we're using inode alignment. + */ + if (XFS_SB_VERSION_HASALIGN(&mp->m_sb) && + mp->m_sb.sb_inoalignmt >= + XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) + mp->m_inoalign_mask = mp->m_sb.sb_inoalignmt - 1; + else + mp->m_inoalign_mask = 0; + /* + * If we are using stripe alignment, check whether + * the stripe unit is a multiple of the inode alignment + */ + if ( mp->m_dalign + && mp->m_inoalign_mask && !(mp->m_dalign & mp->m_inoalign_mask)) + mp->m_sinoalign = mp->m_dalign; + else + mp->m_sinoalign = 0; + + /* + * Check that the data (and log if separate) are an ok size. + */ + d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks); + if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) { + fprintf(stderr, "%s: size check failed\n", progname); + return NULL; + } + + /* Initialize the appropriate directory manager */ + if (XFS_SB_VERSION_HASDIRV2(sbp)) + libxfs_dir2_mount(mp); + else + libxfs_dir_mount(mp); + + /* Initialize the precomputed transaction reservations values */ + libxfs_trans_init(mp); + + if (dev == 0) /* maxtrres, we have no device so leave now */ + return mp; + + bp = libxfs_readbuf(mp->m_dev, d - 1, 1, 0); + if (bp == NULL) { + fprintf(stderr, "%s: data size check failed\n", progname); + return NULL; + } + libxfs_putbuf(bp); + + if (mp->m_logdev && mp->m_logdev != mp->m_dev) { + d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); + if ( (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) || + (!(bp = libxfs_readbuf(mp->m_logdev, d - 1, 1, 1)))) { + fprintf(stderr, "%s: log size checks failed\n", + progname); + return NULL; + } + libxfs_putbuf(bp); + } + + /* Initialize realtime fields in the mount structure */ + if (libxfs_rtmount_init(mp)) { + fprintf(stderr, "%s: real-time device init failed\n", progname); + return NULL; + } + + /* Allocate and initialize the per-ag data */ + size = sbp->sb_agcount * sizeof(xfs_perag_t); + if ((mp->m_perag = calloc(size, 1)) == NULL) { + fprintf(stderr, "%s: failed to alloc %ld bytes: %s\n", + progname, (long)size, strerror(errno)); + exit(1); + } + + /* + * mkfs calls mount before the root inode is allocated. + */ + if (rrootinos && sbp->sb_rootino != NULLFSINO) { + error = libxfs_iread(mp, NULL, sbp->sb_rootino, + &mp->m_rootip, 0); + if (error) { + fprintf(stderr, "%s: cannot read root inode (%d)\n", + progname, error); + return NULL; + } + ASSERT(mp->m_rootip != NULL); + } + if (rrootinos && rtmount_inodes(mp)) + return NULL; + return mp; +} + +/* + * Release any resourse obtained during a mount. + */ +void +libxfs_umount(xfs_mount_t *mp) +{ + manage_zones(1); + free(mp->m_perag); +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/logitem.c linux-2.4-xfs/cmd/xfsprogs/libxfs/logitem.c --- linux-2.4.7/cmd/xfsprogs/libxfs/logitem.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/logitem.c Thu Apr 12 19:04:55 2001 @@ -0,0 +1,496 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +xfs_zone_t *xfs_buf_item_zone; +xfs_zone_t *xfs_ili_zone; /* inode log item zone */ + + +/* + * This is called to add the given log item to the transaction's + * list of log items. It must find a free log item descriptor + * or allocate a new one and add the item to that descriptor. + * The function returns a pointer to item descriptor used to point + * to the new item. The log item will now point to its new descriptor + * with its li_desc field. + */ +xfs_log_item_desc_t * +xfs_trans_add_item(xfs_trans_t *tp, xfs_log_item_t *lip) +{ + xfs_log_item_desc_t *lidp; + xfs_log_item_chunk_t *licp; + int i = 0; + + /* + * If there are no free descriptors, allocate a new chunk + * of them and put it at the front of the chunk list. + */ + if (tp->t_items_free == 0) { + licp = (xfs_log_item_chunk_t*) + kmem_alloc(sizeof(xfs_log_item_chunk_t), KM_SLEEP); + ASSERT(licp != NULL); + /* + * Initialize the chunk, and then + * claim the first slot in the newly allocated chunk. + */ + XFS_LIC_INIT(licp); + XFS_LIC_CLAIM(licp, 0); + licp->lic_unused = 1; + XFS_LIC_INIT_SLOT(licp, 0); + lidp = XFS_LIC_SLOT(licp, 0); + + /* + * Link in the new chunk and update the free count. + */ + licp->lic_next = tp->t_items.lic_next; + tp->t_items.lic_next = licp; + tp->t_items_free = XFS_LIC_NUM_SLOTS - 1; + + /* + * Initialize the descriptor and the generic portion + * of the log item. + * + * Point the new slot at this item and return it. + * Also point the log item at its currently active + * descriptor and set the item's mount pointer. + */ + lidp->lid_item = lip; + lidp->lid_flags = 0; + lidp->lid_size = 0; + lip->li_desc = lidp; + lip->li_mountp = tp->t_mountp; + return (lidp); + } + + /* + * Find the free descriptor. It is somewhere in the chunklist + * of descriptors. + */ + licp = &tp->t_items; + while (licp != NULL) { + if (XFS_LIC_VACANCY(licp)) { + if (licp->lic_unused <= XFS_LIC_MAX_SLOT) { + i = licp->lic_unused; + ASSERT(XFS_LIC_ISFREE(licp, i)); + break; + } + for (i = 0; i <= XFS_LIC_MAX_SLOT; i++) { + if (XFS_LIC_ISFREE(licp, i)) + break; + } + ASSERT(i <= XFS_LIC_MAX_SLOT); + break; + } + licp = licp->lic_next; + } + ASSERT(licp != NULL); + /* + * If we find a free descriptor, claim it, + * initialize it, and return it. + */ + XFS_LIC_CLAIM(licp, i); + if (licp->lic_unused <= i) { + licp->lic_unused = i + 1; + XFS_LIC_INIT_SLOT(licp, i); + } + lidp = XFS_LIC_SLOT(licp, i); + tp->t_items_free--; + lidp->lid_item = lip; + lidp->lid_flags = 0; + lidp->lid_size = 0; + lip->li_desc = lidp; + lip->li_mountp = tp->t_mountp; + return (lidp); +} + +/* + * Free the given descriptor. + * + * This requires setting the bit in the chunk's free mask corresponding + * to the given slot. + */ +void +xfs_trans_free_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp) +{ + uint slot; + xfs_log_item_chunk_t *licp; + xfs_log_item_chunk_t **licpp; + + slot = XFS_LIC_DESC_TO_SLOT(lidp); + licp = XFS_LIC_DESC_TO_CHUNK(lidp); + XFS_LIC_RELSE(licp, slot); + lidp->lid_item->li_desc = NULL; + tp->t_items_free++; + + /* + * If there are no more used items in the chunk and this is not + * the chunk embedded in the transaction structure, then free + * the chunk. First pull it from the chunk list and then + * free it back to the heap. We didn't bother with a doubly + * linked list here because the lists should be very short + * and this is not a performance path. It's better to save + * the memory of the extra pointer. + * + * Also decrement the transaction structure's count of free items + * by the number in a chunk since we are freeing an empty chunk. + */ + if (XFS_LIC_ARE_ALL_FREE(licp) && (licp != &(tp->t_items))) { + licpp = &(tp->t_items.lic_next); + while (*licpp != licp) { + ASSERT(*licpp != NULL); + licpp = &((*licpp)->lic_next); + } + *licpp = licp->lic_next; + kmem_free(licp, sizeof(xfs_log_item_chunk_t)); + tp->t_items_free -= XFS_LIC_NUM_SLOTS; + } +} + +/* + * This is called to find the descriptor corresponding to the given + * log item. It returns a pointer to the descriptor. + * The log item MUST have a corresponding descriptor in the given + * transaction. This routine does not return NULL, it panics. + * + * The descriptor pointer is kept in the log item's li_desc field. + * Just return it. + */ +xfs_log_item_desc_t * +xfs_trans_find_item(xfs_trans_t *tp, xfs_log_item_t *lip) +{ + ASSERT(lip->li_desc != NULL); + + return (lip->li_desc); +} + +/* + * This is called to unlock all of the items of a transaction and to free + * all the descriptors of that transaction. + * + * It walks the list of descriptors and unlocks each item. It frees + * each chunk except that embedded in the transaction as it goes along. + */ +void +xfs_trans_free_items( + xfs_trans_t *tp, + int flags) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_chunk_t *next_licp; + int abort; + + abort = flags & XFS_TRANS_ABORT; + licp = &tp->t_items; + /* + * Special case the embedded chunk so we don't free it below. + */ + if (!XFS_LIC_ARE_ALL_FREE(licp)) { + (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN); + XFS_LIC_ALL_FREE(licp); + licp->lic_unused = 0; + } + licp = licp->lic_next; + + /* + * Unlock each item in each chunk and free the chunks. + */ + while (licp != NULL) { + ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); + (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN); + next_licp = licp->lic_next; + kmem_free(licp, sizeof(xfs_log_item_chunk_t)); + licp = next_licp; + } + + /* + * Reset the transaction structure's free item count. + */ + tp->t_items_free = XFS_LIC_NUM_SLOTS; + tp->t_items.lic_next = NULL; +} + +/* + * Check to see if a buffer matching the given parameters is already + * a part of the given transaction. Only check the first, embedded + * chunk, since we don't want to spend all day scanning large transactions. + */ +STATIC xfs_buf_t * +xfs_trans_buf_item_match( + xfs_trans_t *tp, + buftarg_t *target, + xfs_daddr_t blkno, + int len) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_desc_t *lidp; + xfs_buf_log_item_t *blip; + xfs_buf_t *bp; + int i; + +#ifdef LI_DEBUG + fprintf(stderr, "buf_item_match (fast) log items for xact %p\n", tp); +#endif + + bp = NULL; + len = BBTOB(len); + licp = &tp->t_items; + if (!XFS_LIC_ARE_ALL_FREE(licp)) { + for (i = 0; i < licp->lic_unused; i++) { + /* + * Skip unoccupied slots. + */ + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + lidp = XFS_LIC_SLOT(licp, i); + blip = (xfs_buf_log_item_t *)lidp->lid_item; +#ifdef LI_DEBUG + fprintf(stderr, + "\tfound log item, xact %p, blip=%p (%d/%d)\n", + tp, blip, i, licp->lic_unused); +#endif + if (blip->bli_item.li_type != XFS_LI_BUF) { + continue; + } + + bp = blip->bli_buf; +#ifdef LI_DEBUG + fprintf(stderr, + "\tfound buf %p log item, xact %p, blip=%p (%d)\n", + bp, tp, blip, i); +#endif + if ((XFS_BUF_TARGET(bp) == target->dev) && + (XFS_BUF_ADDR(bp) == blkno) && + (XFS_BUF_COUNT(bp) == len)) { + /* + * We found it. Break out and + * return the pointer to the buffer. + */ +#ifdef LI_DEBUG + fprintf(stderr, + "\tfound REAL buf log item, bp=%p\n", + bp); +#endif + break; + } else { + bp = NULL; + } + } + } +#ifdef LI_DEBUG + if (!bp) fprintf(stderr, "\tfast search - got nothing\n"); +#endif + return bp; +} + +/* + * Check to see if a buffer matching the given parameters is already + * a part of the given transaction. Check all the chunks, we + * want to be thorough. + */ +STATIC xfs_buf_t * +xfs_trans_buf_item_match_all( + xfs_trans_t *tp, + buftarg_t *target, + xfs_daddr_t blkno, + int len) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_desc_t *lidp; + xfs_buf_log_item_t *blip; + xfs_buf_t *bp; + int i; + +#ifdef LI_DEBUG + fprintf(stderr, "buf_item_match_all (slow) log items for xact %p\n", + tp); +#endif + + bp = NULL; + len = BBTOB(len); + for (licp = &tp->t_items; licp != NULL; licp = licp->lic_next) { + if (XFS_LIC_ARE_ALL_FREE(licp)) { + ASSERT(licp == &tp->t_items); + ASSERT(licp->lic_next == NULL); + return NULL; + } + for (i = 0; i < licp->lic_unused; i++) { + /* + * Skip unoccupied slots. + */ + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + lidp = XFS_LIC_SLOT(licp, i); + blip = (xfs_buf_log_item_t *)lidp->lid_item; +#ifdef LI_DEBUG + fprintf(stderr, + "\tfound log item, xact %p, blip=%p (%d/%d)\n", + tp, blip, i, licp->lic_unused); +#endif + if (blip->bli_item.li_type != XFS_LI_BUF) { + continue; + } + + bp = blip->bli_buf; + ASSERT(bp); + ASSERT(XFS_BUF_ADDR(bp)); +#ifdef LI_DEBUG + fprintf(stderr, + "\tfound buf %p log item, xact %p, blip=%p (%d)\n", + bp, tp, blip, i); +#endif + if ((XFS_BUF_TARGET(bp) == target->dev) && + (XFS_BUF_ADDR(bp) == blkno) && + (XFS_BUF_COUNT(bp) == len)) { + /* + * We found it. Break out and + * return the pointer to the buffer. + */ +#ifdef LI_DEBUG + fprintf(stderr, + "\tfound REAL buf log item, bp=%p\n", + bp); +#endif + return bp; + } + } + } +#ifdef LI_DEBUG + if (!bp) fprintf(stderr, "slow search - got nothing\n"); +#endif + return NULL; +} + +/* + * Allocate a new buf log item to go with the given buffer. + * Set the buffer's b_fsprivate field to point to the new + * buf log item. If there are other item's attached to the + * buffer (see xfs_buf_attach_iodone() below), then put the + * buf log item at the front. + */ +void +xfs_buf_item_init( + xfs_buf_t *bp, + xfs_mount_t *mp) +{ + xfs_log_item_t *lip; + xfs_buf_log_item_t *bip; + +#ifdef LI_DEBUG + fprintf(stderr, "buf_item_init for buffer %p\n", bp); +#endif + + /* + * Check to see if there is already a buf log item for + * this buffer. If there is, it is guaranteed to be + * the first. If we do already have one, there is + * nothing to do here so return. + */ + if (XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *) != mp) + XFS_BUF_SET_FSPRIVATE3(bp, mp); + XFS_BUF_SET_BDSTRAT_FUNC(bp, xfs_bdstrat_cb); + if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) { + lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); + if (lip->li_type == XFS_LI_BUF) { +#ifdef LI_DEBUG + fprintf(stderr, + "reused buf item %p for pre-logged buffer %p\n", + lip, bp); +#endif + return; + } + } + + bip = (xfs_buf_log_item_t *)kmem_zone_zalloc(xfs_buf_item_zone, + KM_SLEEP); +#ifdef LI_DEBUG + fprintf(stderr, "adding buf item %p for not-logged buffer %p\n", + bip, bp); +#endif + bip->bli_item.li_type = XFS_LI_BUF; + bip->bli_item.li_mountp = mp; + bip->bli_buf = bp; + bip->bli_format.blf_type = XFS_LI_BUF; + bip->bli_format.blf_blkno = (__int64_t)XFS_BUF_ADDR(bp); + bip->bli_format.blf_len = (ushort)BTOBB(XFS_BUF_COUNT(bp)); + XFS_BUF_SET_FSPRIVATE(bp, bip); +} + + +/* + * Mark bytes first through last inclusive as dirty in the buf + * item's bitmap. + */ +void +xfs_buf_item_log( + xfs_buf_log_item_t *bip, + uint first, + uint last) +{ + /* + * Mark the item as having some dirty data for + * quick reference in xfs_buf_item_dirty. + */ + bip->bli_flags |= XFS_BLI_DIRTY; +} + +/* + * Initialize the inode log item for a newly allocated (in-core) inode. + */ +void +xfs_inode_item_init( + xfs_inode_t *ip, + xfs_mount_t *mp) +{ + xfs_inode_log_item_t *iip; + + ASSERT(ip->i_itemp == NULL); + iip = ip->i_itemp = (xfs_inode_log_item_t *) + kmem_zone_zalloc(xfs_ili_zone, KM_SLEEP); +#ifdef LI_DEBUG + fprintf(stderr, "inode_item_init for inode %llu, iip=%p\n", + ip->i_ino, iip); +#endif + + iip->ili_item.li_type = XFS_LI_INODE; + iip->ili_item.li_mountp = mp; + iip->ili_inode = ip; + iip->ili_format.ilf_type = XFS_LI_INODE; + iip->ili_format.ilf_ino = ip->i_ino; + iip->ili_format.ilf_blkno = ip->i_blkno; + iip->ili_format.ilf_len = ip->i_len; + iip->ili_format.ilf_boffset = ip->i_boffset; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/rdwr.c linux-2.4-xfs/cmd/xfsprogs/libxfs/rdwr.c --- linux-2.4.7/cmd/xfsprogs/libxfs/rdwr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/rdwr.c Wed May 9 01:56:06 2001 @@ -0,0 +1,464 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include + +#define BBTOOFF64(bbs) (((xfs_off_t)(bbs)) << BBSHIFT) +#define BDSTRAT_SIZE (256 * 1024) + +void +libxfs_device_zero(dev_t dev, xfs_daddr_t start, uint len) +{ + xfs_daddr_t bno; + uint nblks; + int size; + int fd; + char *z; + + size = BDSTRAT_SIZE <= BBTOB(len) ? BDSTRAT_SIZE : BBTOB(len); + if ((z = memalign(getpagesize(), size)) == NULL) { + fprintf(stderr, "%s: device_zero can't memalign %d bytes: %s\n", + progname, size, strerror(errno)); + exit(1); + } + bzero(z, size); + fd = libxfs_device_to_fd(dev); + for (bno = start; bno < start + len; ) { + nblks = (uint)BTOBB(size); + if (bno + nblks > start + len) + nblks = (uint)(start + len - bno); + if (lseek64(fd, BBTOOFF64(bno), SEEK_SET) < 0) { + fprintf(stderr, "%s: device_zero lseek64 failed: %s\n", + progname, strerror(errno)); + exit(1); + } + if (write(fd, z, BBTOB(nblks)) < BBTOB(nblks)) { + fprintf(stderr, "%s: device_zero write failed: %s\n", + progname, strerror(errno)); + exit(1); + } + bno += nblks; + } + free(z); +} + +int +libxfs_log_clear( + dev_t device, + xfs_daddr_t start, + uint length, + uuid_t *fs_uuid, + int fmt) +{ + xfs_buf_t *buf; + xlog_rec_header_t *head; + xlog_op_header_t *op; + /* the data section must be 32 bit size aligned */ + struct { + __uint16_t magic; + __uint16_t pad1; + __uint32_t pad2; /* may as well make it 64 bits */ + } magic = { XLOG_UNMOUNT_TYPE, 0, 0 }; + + if (!device || !fs_uuid) + return -EINVAL; + + /* first zero the log */ + libxfs_device_zero(device, start, length); + + /* then write a log record header */ + buf = libxfs_getbuf(device, start, 1); + if (!buf) + return -1; + + memset(XFS_BUF_PTR(buf), 0, BBSIZE); + head = (xlog_rec_header_t *)XFS_BUF_PTR(buf); + + /* note that oh_tid actually contains the cycle number + * and the tid is stored in h_cycle_data[0] - that's the + * way things end up on disk. + */ + + INT_SET(head->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM); + INT_SET(head->h_cycle, ARCH_CONVERT, 1); + INT_SET(head->h_version, ARCH_CONVERT, 1); + INT_SET(head->h_len, ARCH_CONVERT, 20); + INT_SET(head->h_chksum, ARCH_CONVERT, 0); + INT_SET(head->h_prev_block, ARCH_CONVERT, -1); + INT_SET(head->h_num_logops, ARCH_CONVERT, 1); + INT_SET(head->h_cycle_data[0], ARCH_CONVERT, 0xb0c0d0d0); + INT_SET(head->h_fmt, ARCH_CONVERT, fmt); + + ASSIGN_ANY_LSN(head->h_lsn, 1, 0, ARCH_CONVERT); + ASSIGN_ANY_LSN(head->h_tail_lsn, 1, 0, ARCH_CONVERT); + + memcpy(head->h_fs_uuid, fs_uuid, sizeof(uuid_t)); + + if (libxfs_writebuf(buf, 0)) + return -1; + + buf = libxfs_getbuf(device, start + 1, 1); + if (!buf) + return -1; + + /* now a log unmount op */ + memset(XFS_BUF_PTR(buf), 0, BBSIZE); + op = (xlog_op_header_t *)XFS_BUF_PTR(buf); + INT_SET(op->oh_tid, ARCH_CONVERT, 1); + INT_SET(op->oh_len, ARCH_CONVERT, sizeof(magic)); + INT_SET(op->oh_clientid, ARCH_CONVERT, XFS_LOG); + INT_SET(op->oh_flags, ARCH_CONVERT, XLOG_UNMOUNT_TRANS); + INT_SET(op->oh_res2, ARCH_CONVERT, 0); + + /* and the data for this op */ + + memcpy(XFS_BUF_PTR(buf) + sizeof(xlog_op_header_t), + &magic, + sizeof(magic)); + + if (libxfs_writebuf(buf, 0)) + return -1; + + return 0; +} + +/* + * Simple I/O interface + */ + +xfs_buf_t * +libxfs_getbuf(dev_t device, xfs_daddr_t blkno, int len) +{ + xfs_buf_t *buf; + size_t total; + + total = sizeof(xfs_buf_t) + BBTOB(len); + if ((buf = calloc(total, 1)) == NULL) { + fprintf(stderr, "%s: buf calloc failed (%ld bytes): %s\n", + progname, (long)total, strerror(errno)); + exit(1); + } + /* by default, we allocate buffer directly after the header */ + buf->b_blkno = blkno; + buf->b_bcount = BBTOB(len); + buf->b_dev = device; + buf->b_addr = (char *)(&buf->b_addr + 1); /* must be last field */ +#ifdef IO_DEBUG + fprintf(stderr, "getbuf allocated %ubytes, blkno=%llu(%llu), %p\n", + BBTOB(len), BBTOOFF64(blkno), blkno, buf); +#endif + + return(buf); +} + +int +libxfs_readbufr(dev_t dev, xfs_daddr_t blkno, xfs_buf_t *buf, int len, int die) +{ + int fd = libxfs_device_to_fd(dev); + + buf->b_dev = dev; + buf->b_blkno = blkno; + ASSERT(BBTOB(len) <= buf->b_bcount); + + if (lseek64(fd, BBTOOFF64(blkno), SEEK_SET) < 0) { + fprintf(stderr, "%s: lseek64 to %llu failed: %s\n", progname, + (unsigned long long)BBTOOFF64(blkno), strerror(errno)); + ASSERT(0); + if (die) + exit(1); + return errno; + } + if (read(fd, buf->b_addr, BBTOB(len)) < 0) { + fprintf(stderr, "%s: read failed: %s\n", + progname, strerror(errno)); + if (die) + exit(1); + return errno; + } +#ifdef IO_DEBUG + fprintf(stderr, "readbufr read %ubytes, blkno=%llu(%llu), %p\n", + BBTOB(len), BBTOOFF64(blkno), blkno, buf); +#endif + return 0; +} + +xfs_buf_t * +libxfs_readbuf(dev_t dev, xfs_daddr_t blkno, int len, int die) +{ + xfs_buf_t *buf; + int error; + + buf = libxfs_getbuf(dev, blkno, len); + error = libxfs_readbufr(dev, blkno, buf, len, die); + if (error) { + libxfs_putbuf(buf); + return NULL; + } + return buf; +} + +xfs_buf_t * +libxfs_getsb(xfs_mount_t *mp, int die) +{ + return libxfs_readbuf(mp->m_dev, XFS_SB_DADDR, + XFS_FSB_TO_BB(mp, 1), die); +} + +int +libxfs_writebuf_int(xfs_buf_t *buf, int die) +{ + int sts; + int fd = libxfs_device_to_fd(buf->b_dev); + + if (lseek64(fd, BBTOOFF64(buf->b_blkno), SEEK_SET) < 0) { + fprintf(stderr, "%s: lseek64 to %llu failed: %s\n", progname, + (unsigned long long)BBTOOFF64(buf->b_blkno), strerror(errno)); + ASSERT(0); + if (die) + exit(1); + return errno; + } +#ifdef IO_DEBUG + fprintf(stderr, "writing %ubytes at blkno=%llu(%llu), %p\n", + buf->b_bcount, BBTOOFF64(buf->b_blkno), buf->b_blkno, buf); +#endif + sts = write(fd, buf->b_addr, buf->b_bcount); + if (sts < 0) { + fprintf(stderr, "%s: write failed: %s\n", + progname, strerror(errno)); + ASSERT(0); + if (die) + exit(1); + return errno; + } + else if (sts != buf->b_bcount) { + fprintf(stderr, "%s: error - wrote only %d of %d bytes\n", + progname, sts, buf->b_bcount); + if (die) + exit(1); + return EIO; + } + return 0; +} + +int +libxfs_writebuf(xfs_buf_t *buf, int die) +{ + int error = libxfs_writebuf_int(buf, die); + libxfs_putbuf(buf); + return error; +} + +void +libxfs_putbuf(xfs_buf_t *buf) +{ + if (buf != NULL) { + xfs_buf_log_item_t *bip; + extern xfs_zone_t *xfs_buf_item_zone; + + bip = XFS_BUF_FSPRIVATE(buf, xfs_buf_log_item_t *); + + if (bip) + libxfs_zone_free(xfs_buf_item_zone, bip); +#ifdef IO_DEBUG + fprintf(stderr, "putbuf released %ubytes, %p\n", + buf->b_bcount, buf); +#endif + free(buf); + buf = NULL; + } +} + + +/* + * Simple memory interface + */ + +xfs_zone_t * +libxfs_zone_init(int size, char *name) +{ + xfs_zone_t *ptr; + + if ((ptr = malloc(sizeof(xfs_zone_t))) == NULL) { + fprintf(stderr, "%s: zone init failed (%s, %d bytes): %s\n", + progname, name, (int)sizeof(xfs_zone_t), strerror(errno)); + exit(1); + } + ptr->zone_unitsize = size; + ptr->zone_name = name; +#ifdef MEM_DEBUG + ptr->allocated = 0; + fprintf(stderr, "new zone %p for \"%s\", size=%d\n", ptr, name, size); +#endif + return ptr; +} + +void * +libxfs_zone_zalloc(xfs_zone_t *z) +{ + void *ptr; + + ASSERT(z != NULL); + if ((ptr = calloc(z->zone_unitsize, 1)) == NULL) { + fprintf(stderr, "%s: zone calloc failed (%s, %d bytes): %s\n", + progname, z->zone_name, z->zone_unitsize, + strerror(errno)); + exit(1); + } +#ifdef MEM_DEBUG + z->allocated++; + fprintf(stderr, "## zone alloc'd item %p from %s (%d bytes) (%d active)\n", + ptr, z->zone_name, z->zone_unitsize, + z->allocated); +#endif + return ptr; +} + +void +libxfs_zone_free(xfs_zone_t *z, void *ptr) +{ +#ifdef MEM_DEBUG + z->allocated--; + fprintf(stderr, "## zone freed item %p from %s (%d bytes) (%d active)\n", + ptr, z->zone_name, z->zone_unitsize, + z->allocated); +#endif + if (ptr != NULL) { + free(ptr); + ptr = NULL; + } +} + +void * +libxfs_malloc(size_t size) +{ + void *ptr; + + if ((ptr = malloc(size)) == NULL) { + fprintf(stderr, "%s: malloc failed (%d bytes): %s\n", + progname, (int)size, strerror(errno)); + exit(1); + } +#ifdef MEM_DEBUG + fprintf(stderr, "## malloc'd item %p size %d bytes\n", + ptr, size); +#endif + return ptr; +} + +void +libxfs_free(void *ptr) +{ +#ifdef MEM_DEBUG + fprintf(stderr, "## freed item %p\n", + ptr); +#endif + if (ptr != NULL) { + free(ptr); + ptr = NULL; + } +} + +void * +libxfs_realloc(void *ptr, size_t size) +{ +#ifdef MEM_DEBUG + void *optr=ptr; +#endif + if ((ptr = realloc(ptr, size)) == NULL) { + fprintf(stderr, "%s: realloc failed (%d bytes): %s\n", + progname, (int)size, strerror(errno)); + exit(1); + } +#ifdef MEM_DEBUG + fprintf(stderr, "## realloc'd item %p now %p size %d bytes\n", + optr, ptr, size); +#endif + return ptr; +} + + +int +libxfs_iget(xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, uint lock_flags, + xfs_inode_t **ipp, xfs_daddr_t bno) +{ + xfs_inode_t *ip; + int error; + + error = libxfs_iread(mp, tp, ino, &ip, bno); + if (error) + return error; + *ipp = ip; + return 0; +} + +void +libxfs_iput(xfs_inode_t *ip, uint lock_flags) +{ + extern xfs_zone_t *xfs_ili_zone; + extern xfs_zone_t *xfs_inode_zone; + + if (ip != NULL) { + + /* free attached inode log item */ + if (ip->i_itemp) + libxfs_zone_free(xfs_ili_zone, ip->i_itemp); + ip->i_itemp = NULL; + + libxfs_zone_free(xfs_inode_zone, ip); + ip = NULL; + } +} + +/* + * libxfs_mod_sb can be used to copy arbitrary changes to the + * in-core superblock into the superblock buffer to be logged. + * + * In user-space, we simply convert to big-endian, and write the + * the whole superblock - the in-core changes have all been made + * already. + */ +void +libxfs_mod_sb(xfs_trans_t *tp, __int64_t fields) +{ + xfs_buf_t *bp; + xfs_mount_t *mp; + + mp = tp->t_mountp; + bp = libxfs_getbuf(mp->m_dev, XFS_SB_DADDR, 1); + libxfs_xlate_sb(XFS_BUF_PTR(bp), &mp->m_sb, -1, ARCH_CONVERT, + XFS_SB_ALL_BITS); + libxfs_writebuf(bp, 1); +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/trans.c linux-2.4-xfs/cmd/xfsprogs/libxfs/trans.c --- linux-2.4.7/cmd/xfsprogs/libxfs/trans.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/trans.c Thu Apr 12 18:30:32 2001 @@ -0,0 +1,753 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * Simple transaction interface + */ + +xfs_trans_t * +libxfs_trans_alloc(xfs_mount_t *mp, int type) +{ + xfs_trans_t *ptr; + + if ((ptr = calloc(sizeof(xfs_trans_t), 1)) == NULL) { + fprintf(stderr, "%s: xact calloc failed (%d bytes): %s\n", + progname, (int)sizeof(xfs_trans_t), strerror(errno)); + exit(1); + } + ptr->t_mountp = mp; + ptr->t_type = type; + ptr->t_items_free = XFS_LIC_NUM_SLOTS; + XFS_LIC_INIT(&(ptr->t_items)); +#ifdef XACT_DEBUG + fprintf(stderr, "allocated new transaction %p\n", ptr); +#endif + return ptr; +} + +xfs_trans_t * +libxfs_trans_dup(xfs_trans_t *tp) +{ + xfs_trans_t *ptr; + + ptr = libxfs_trans_alloc(tp->t_mountp, tp->t_type); +#ifdef XACT_DEBUG + fprintf(stderr, "duplicated transaction %p (new=%p)\n", tp, ptr); +#endif + return ptr; +} + +int +libxfs_trans_reserve(xfs_trans_t *tp, + uint blocks, uint logspace, uint rtextents, uint flags, uint logcount) +{ + xfs_sb_t *mpsb = &tp->t_mountp->m_sb; + + /* + * Attempt to reserve the needed disk blocks by decrementing + * the number needed from the number available. This will + * fail if the count would go below zero. + */ + if (blocks > 0) { + if (mpsb->sb_fdblocks < blocks) + return ENOSPC; + } + /* user space, don't need log/RT stuff (preserve the API though) */ + return 0; +} + +void +libxfs_trans_cancel(xfs_trans_t *tp, int flags) +{ +#ifdef XACT_DEBUG + xfs_trans_t *otp = tp; +#endif + if (tp != NULL) { + xfs_trans_free_items(tp, flags); + free(tp); + tp = NULL; + } +#ifdef XACT_DEBUG + fprintf(stderr, "## cancelled transaction %p\n", otp); +#endif +} + +int +libxfs_trans_iget(xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, + uint lock_flags, xfs_inode_t **ipp) +{ + int error; + xfs_inode_t *ip; + xfs_inode_log_item_t *iip; + + if (tp == NULL) + return libxfs_iread(mp, tp, ino, ipp, 0); + + error = libxfs_iread(mp, tp, ino, &ip, 0); + if (error) + return error; + ASSERT(ip != NULL); + + if (ip->i_itemp == NULL) + xfs_inode_item_init(ip, mp); + iip = ip->i_itemp; + xfs_trans_add_item(tp, (xfs_log_item_t *)(iip)); + + /* initialize i_transp so we can find it incore */ + ip->i_transp = tp; + + *ipp = ip; + return 0; +} + +void +libxfs_trans_iput(xfs_trans_t *tp, xfs_inode_t *ip, uint lock_flags) +{ + xfs_inode_log_item_t *iip; + xfs_log_item_desc_t *lidp; + + if (tp == NULL) { + libxfs_iput(ip, lock_flags); + return; + } + + ASSERT(ip->i_transp == tp); + iip = ip->i_itemp; + ASSERT(iip != NULL); + + lidp = xfs_trans_find_item(tp, (xfs_log_item_t *)iip); + ASSERT(lidp != NULL); + ASSERT(lidp->lid_item == (xfs_log_item_t *)iip); + ASSERT(!(lidp->lid_flags & XFS_LID_DIRTY)); + xfs_trans_free_item(tp, lidp); + + libxfs_iput(ip, lock_flags); +} + +void +libxfs_trans_ijoin(xfs_trans_t *tp, xfs_inode_t *ip, uint lock_flags) +{ + xfs_inode_log_item_t *iip; + + ASSERT(ip->i_transp == NULL); + if (ip->i_itemp == NULL) + xfs_inode_item_init(ip, ip->i_mount); + iip = ip->i_itemp; + ASSERT(iip->ili_flags == 0); + ASSERT(iip->ili_inode != NULL); + + xfs_trans_add_item(tp, (xfs_log_item_t *)(iip)); + + ip->i_transp = tp; +#ifdef XACT_DEBUG + fprintf(stderr, "ijoin'd inode %llu, transaction %p\n", ip->i_ino, tp); +#endif +} + +void +libxfs_trans_ihold(xfs_trans_t *tp, xfs_inode_t *ip) +{ + ASSERT(ip->i_transp == tp); + ASSERT(ip->i_itemp != NULL); + + ip->i_itemp->ili_flags |= XFS_ILI_HOLD; +#ifdef XACT_DEBUG + fprintf(stderr, "ihold'd inode %llu, transaction %p\n", ip->i_ino, tp); +#endif +} + +void +libxfs_trans_inode_alloc_buf(xfs_trans_t *tp, xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + bip->bli_flags |= XFS_BLI_INODE_ALLOC_BUF; +} + +/* + * This is called to mark the fields indicated in fieldmask as needing + * to be logged when the transaction is committed. The inode must + * already be associated with the given transaction. + * + * The values for fieldmask are defined in xfs_inode_item.h. We always + * log all of the core inode if any of it has changed, and we always log + * all of the inline data/extents/b-tree root if any of them has changed. + */ +void +xfs_trans_log_inode( + xfs_trans_t *tp, + xfs_inode_t *ip, + uint flags) +{ + xfs_log_item_desc_t *lidp; + + ASSERT(ip->i_transp == tp); + ASSERT(ip->i_itemp != NULL); +#ifdef XACT_DEBUG + fprintf(stderr, "dirtied inode %llu, transaction %p\n", ip->i_ino, tp); +#endif + + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(ip->i_itemp)); + ASSERT(lidp != NULL); + + tp->t_flags |= XFS_TRANS_DIRTY; + lidp->lid_flags |= XFS_LID_DIRTY; + + /* + * Always OR in the bits from the ili_last_fields field. + * This is to coordinate with the xfs_iflush() and xfs_iflush_done() + * routines in the eventual clearing of the ilf_fields bits. + * See the big comment in xfs_iflush() for an explanation of + * this coordination mechanism. + */ + flags |= ip->i_itemp->ili_last_fields; + ip->i_itemp->ili_format.ilf_fields |= flags; +} + +/* + * This is called to mark bytes first through last inclusive of the given + * buffer as needing to be logged when the transaction is committed. + * The buffer must already be associated with the given transaction. + * + * First and last are numbers relative to the beginning of this buffer, + * so the first byte in the buffer is numbered 0 regardless of the + * value of b_blkno. + */ +void +libxfs_trans_log_buf(xfs_trans_t *tp, xfs_buf_t *bp, uint first, uint last) +{ + xfs_buf_log_item_t *bip; + xfs_log_item_desc_t *lidp; + + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + ASSERT((first <= last) && (last < XFS_BUF_COUNT(bp))); +#ifdef XACT_DEBUG + fprintf(stderr, "dirtied buffer %p, transaction %p\n", bp, tp); +#endif + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + + lidp = xfs_trans_find_item(tp, (xfs_log_item_t *)bip); + ASSERT(lidp != NULL); + + tp->t_flags |= XFS_TRANS_DIRTY; + lidp->lid_flags |= XFS_LID_DIRTY; + xfs_buf_item_log(bip, first, last); +} + +void +libxfs_trans_brelse(xfs_trans_t *tp, xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + xfs_log_item_desc_t *lidp; +#ifdef XACT_DEBUG + fprintf(stderr, "released buffer %p, transaction %p\n", bp, tp); +#endif + + if (tp == NULL) { + ASSERT(XFS_BUF_FSPRIVATE2(bp, void *) == NULL); + libxfs_putbuf(bp); + return; + } + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(bip->bli_item.li_type == XFS_LI_BUF); + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip); + ASSERT(lidp != NULL); + if (bip->bli_recur > 0) { + bip->bli_recur--; + return; + } + /* If dirty, can't release till transaction committed */ + if (lidp->lid_flags & XFS_LID_DIRTY) { + return; + } + xfs_trans_free_item(tp, lidp); + if (bip->bli_flags & XFS_BLI_HOLD) { + bip->bli_flags &= ~XFS_BLI_HOLD; + } + XFS_BUF_SET_FSPRIVATE2(bp, NULL); + libxfs_putbuf(bp); +} + +void +libxfs_trans_binval(xfs_trans_t *tp, xfs_buf_t *bp) +{ + xfs_log_item_desc_t *lidp; + xfs_buf_log_item_t *bip; +#ifdef XACT_DEBUG + fprintf(stderr, "binval'd buffer %p, transaction %p\n", bp, tp); +#endif + + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip); + ASSERT(lidp != NULL); + bip->bli_flags &= ~(XFS_BLI_DIRTY); + bip->bli_format.blf_flags &= ~XFS_BLI_INODE_BUF; + bip->bli_format.blf_flags |= XFS_BLI_CANCEL; + lidp->lid_flags |= XFS_LID_DIRTY; + tp->t_flags |= XFS_TRANS_DIRTY; +} + +void +libxfs_trans_bjoin(xfs_trans_t *tp, xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_FSPRIVATE2(bp, void *) == NULL); +#ifdef XACT_DEBUG + fprintf(stderr, "bjoin'd buffer %p, transaction %p\n", bp, tp); +#endif + + xfs_buf_item_init(bp, tp->t_mountp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + xfs_trans_add_item(tp, (xfs_log_item_t *)bip); + XFS_BUF_SET_FSPRIVATE2(bp, tp); +} + +void +libxfs_trans_bhold(xfs_trans_t *tp, xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); +#ifdef XACT_DEBUG + fprintf(stderr, "bhold'd buffer %p, transaction %p\n", bp, tp); +#endif + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + bip->bli_flags |= XFS_BLI_HOLD; +} + +xfs_buf_t * +libxfs_trans_get_buf(xfs_trans_t *tp, dev_t dev, xfs_daddr_t d, int len, uint f) +{ + xfs_buf_t *bp; + xfs_buf_log_item_t *bip; + buftarg_t bdev = { dev }; + + if (tp == NULL) + return libxfs_getbuf(dev, d, len); + + if (tp->t_items.lic_next == NULL) + bp = xfs_trans_buf_item_match(tp, &bdev, d, len); + else + bp = xfs_trans_buf_item_match_all(tp, &bdev, d, len); + if (bp != NULL) { + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(bip != NULL); + bip->bli_recur++; + return bp; + } + + bp = libxfs_getbuf(dev, d, len); + if (bp == NULL) + return NULL; +#ifdef XACT_DEBUG + fprintf(stderr, "trans_get_buf buffer %p, transaction %p\n", bp, tp); +#endif + + xfs_buf_item_init(bp, tp->t_mountp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + bip->bli_recur = 0; + xfs_trans_add_item(tp, (xfs_log_item_t *)bip); + + /* initialize b_fsprivate2 so we can find it incore */ + XFS_BUF_SET_FSPRIVATE2(bp, tp); + return bp; +} + +int +libxfs_trans_read_buf(xfs_mount_t *mp, xfs_trans_t *tp, dev_t dev, + xfs_daddr_t blkno, int len, uint f, xfs_buf_t **bpp) +{ + xfs_buf_t *bp; + xfs_buf_log_item_t *bip; + int error; + buftarg_t bdev = { dev }; + + if (tp == NULL) { + bp = libxfs_getbuf(mp->m_dev, blkno, len); + error = libxfs_readbufr(dev, blkno, bp, len, 0); + *bpp = bp; + return error; + } + + if (tp->t_items.lic_next == NULL) + bp = xfs_trans_buf_item_match(tp, &bdev, blkno, len); + else + bp = xfs_trans_buf_item_match_all(tp, &bdev, blkno, len); + if (bp != NULL) { + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + bip->bli_recur++; + *bpp = bp; + return 0; + } + + bp = libxfs_getbuf(mp->m_dev, blkno, len); + error = libxfs_readbufr(dev, blkno, bp, len, 0); + if (error) { + *bpp = NULL; + return error; + } +#ifdef XACT_DEBUG + fprintf(stderr, "trans_read_buf buffer %p, transaction %p\n", bp, tp); +#endif + + xfs_buf_item_init(bp, tp->t_mountp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + bip->bli_recur = 0; + xfs_trans_add_item(tp, (xfs_log_item_t *)bip); + + /* initialise b_fsprivate2 so we can find it incore */ + XFS_BUF_SET_FSPRIVATE2(bp, tp); + *bpp = bp; + return 0; +} + +/* + * Record the indicated change to the given field for application + * to the file system's superblock when the transaction commits. + * For now, just store the change in the transaction structure. + * Mark the transaction structure to indicate that the superblock + * needs to be updated before committing. + * + * Originally derived from xfs_trans_mod_sb(). + */ +void +libxfs_trans_mod_sb(xfs_trans_t *tp, uint field, long delta) +{ + switch (field) { + case XFS_TRANS_SB_RES_FDBLOCKS: + return; + case XFS_TRANS_SB_FDBLOCKS: + tp->t_fdblocks_delta += delta; + break; + case XFS_TRANS_SB_ICOUNT: + ASSERT(delta > 0); + tp->t_icount_delta += delta; + break; + case XFS_TRANS_SB_IFREE: + tp->t_ifree_delta += delta; + break; + case XFS_TRANS_SB_FREXTENTS: + tp->t_frextents_delta += delta; + break; + default: + ASSERT(0); + return; + } + tp->t_flags |= (XFS_TRANS_SB_DIRTY | XFS_TRANS_DIRTY); +} + + +/* + * Transaction commital code follows (i.e. write to disk in libxfs) + */ + +STATIC void +inode_item_done(xfs_inode_log_item_t *iip) +{ + xfs_dinode_t *dip; + xfs_inode_t *ip; + xfs_mount_t *mp; + xfs_buf_t *bp; + int hold; + int error; + extern xfs_zone_t *xfs_ili_zone; + + ip = iip->ili_inode; + mp = iip->ili_item.li_mountp; + hold = iip->ili_flags & XFS_ILI_HOLD; + ASSERT(ip != NULL); + + if (!(iip->ili_format.ilf_fields & XFS_ILOG_ALL)) { + ip->i_transp = NULL; /* disassociate from transaction */ + iip->ili_flags = 0; /* reset all flags */ + if (!hold) + goto ili_done; + return; + } + + /* + * Get the buffer containing the on-disk inode. + */ + error = libxfs_itobp(mp, NULL, ip, &dip, &bp, 0); + if (error) { + fprintf(stderr, "%s: warning - itobp failed (%d)\n", + progname, error); + goto ili_done; + } + + XFS_BUF_SET_FSPRIVATE(bp, iip); + error = libxfs_iflush_int(ip, bp); + if (error) { + fprintf(stderr, "%s: warning - iflush_int failed (%d)\n", + progname, error); + goto ili_done; + } + + ip->i_transp = NULL; /* disassociate from transaction */ + XFS_BUF_SET_FSPRIVATE(bp, NULL); /* remove log item */ + XFS_BUF_SET_FSPRIVATE2(bp, NULL); /* remove xact ptr */ + libxfs_writebuf_int(bp, 0); +#ifdef XACT_DEBUG + fprintf(stderr, "flushing dirty inode %llu, buffer %p (hold=%u)\n", + ip->i_ino, bp, hold); +#endif + if (hold) { + iip->ili_flags &= ~XFS_ILI_HOLD; + return; + } + else { + /*libxfs_iput(iip->ili_inode, 0); - nathans TODO? */ + libxfs_putbuf(bp); + } + +ili_done: + if (ip->i_itemp) + kmem_zone_free(xfs_ili_zone, ip->i_itemp); + else + ASSERT(0); + ip->i_itemp = NULL; +} + +STATIC void +buf_item_done(xfs_buf_log_item_t *bip) +{ + extern xfs_zone_t *xfs_buf_item_zone; + xfs_buf_t *bp; + int hold; + + bp = bip->bli_buf; + ASSERT(bp != NULL); + XFS_BUF_SET_FSPRIVATE(bp, NULL); /* remove log item */ + XFS_BUF_SET_FSPRIVATE2(bp, NULL); /* remove xact ptr */ + + hold = (bip->bli_flags & XFS_BLI_HOLD); + if (bip->bli_flags & XFS_BLI_DIRTY) { +#ifdef XACT_DEBUG + fprintf(stderr, "flushing dirty buffer %p (hold=%d)\n", + bp, hold); +#endif + libxfs_writebuf_int(bp, 0); + if (hold) + bip->bli_flags &= ~XFS_BLI_HOLD; + else + libxfs_putbuf(bp); + } + /* release the buf item */ + kmem_zone_free(xfs_buf_item_zone, bip); +} + +/* + * This is called to perform the commit processing for each + * item described by the given chunk. + */ +static void +trans_chunk_committed(xfs_log_item_chunk_t *licp) +{ + xfs_log_item_desc_t *lidp; + xfs_log_item_t *lip; + int i; + + lidp = licp->lic_descs; + for (i = 0; i < licp->lic_unused; i++, lidp++) { + if (XFS_LIC_ISFREE(licp, i)) + continue; + lip = lidp->lid_item; + if (lip->li_type == XFS_LI_BUF) + buf_item_done((xfs_buf_log_item_t *)lidp->lid_item); + else if (lip->li_type == XFS_LI_INODE) + inode_item_done((xfs_inode_log_item_t *)lidp->lid_item); + else { + fprintf(stderr, "%s: unrecognised log item type\n", + progname); + ASSERT(0); + } + } +} + +/* + * Calls trans_chunk_committed() to process the items in each chunk. + */ +static void +trans_committed(xfs_trans_t *tp) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_chunk_t *next_licp; + + /* + * Special case the chunk embedded in the transaction. + */ + licp = &(tp->t_items); + if (!(XFS_LIC_ARE_ALL_FREE(licp))) { + trans_chunk_committed(licp); + } + + /* + * Process the items in each chunk in turn. + */ + licp = licp->lic_next; + while (licp != NULL) { + trans_chunk_committed(licp); + next_licp = licp->lic_next; + kmem_free(licp, sizeof(xfs_log_item_chunk_t)); + licp = next_licp; + } +} + +/* + * Unlock each item pointed to by a descriptor in the given chunk. + * Free descriptors pointing to items which are not dirty if freeing_chunk + * is zero. If freeing_chunk is non-zero, then we need to unlock all + * items in the chunk. Return the number of descriptors freed. + * Originally based on xfs_trans_unlock_chunk() - adapted for libxfs + * transactions though. + */ +int +xfs_trans_unlock_chunk( + xfs_log_item_chunk_t *licp, + int freeing_chunk, + int abort, + xfs_lsn_t commit_lsn) /* nb: unused */ +{ + xfs_log_item_desc_t *lidp; + xfs_log_item_t *lip; + int i; + int freed; + + freed = 0; + lidp = licp->lic_descs; + for (i = 0; i < licp->lic_unused; i++, lidp++) { + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + lip = lidp->lid_item; + lip->li_desc = NULL; + + /* + * Disassociate the logged item from this transaction + */ + if (lip->li_type == XFS_LI_BUF) { + xfs_buf_log_item_t *bip; + + bip = (xfs_buf_log_item_t *)lidp->lid_item; + XFS_BUF_SET_FSPRIVATE2(bip->bli_buf, NULL); + bip->bli_flags &= ~XFS_BLI_HOLD; + } + else if (lip->li_type == XFS_LI_INODE) { + xfs_inode_log_item_t *iip; + + iip = (xfs_inode_log_item_t*)lidp->lid_item; + iip->ili_inode->i_transp = NULL; + iip->ili_flags &= ~XFS_ILI_HOLD; + } + else { + fprintf(stderr, "%s: unrecognised log item type\n", + progname); + ASSERT(0); + } + + /* + * Free the descriptor if the item is not dirty + * within this transaction and the caller is not + * going to just free the entire thing regardless. + */ + if (!(freeing_chunk) && + (!(lidp->lid_flags & XFS_LID_DIRTY) || abort)) { + XFS_LIC_RELSE(licp, i); + freed++; + } + } + + return (freed); +} + + +/* + * Commit the changes represented by this transaction + */ +int +libxfs_trans_commit(xfs_trans_t *tp, uint flags, xfs_lsn_t *commit_lsn_p) +{ + xfs_sb_t *sbp; + + if (tp == NULL) + return 0; + + if (!(tp->t_flags & XFS_TRANS_DIRTY)) { +#ifdef XACT_DEBUG + fprintf(stderr, "committed clean transaction %p\n", tp); +#endif + xfs_trans_free_items(tp, flags); + free(tp); + tp = NULL; + return 0; + } + + if (tp->t_flags & XFS_TRANS_SB_DIRTY) { + sbp = &(tp->t_mountp->m_sb); + if (tp->t_icount_delta) + sbp->sb_icount += tp->t_icount_delta; + if (tp->t_ifree_delta) + sbp->sb_ifree += tp->t_ifree_delta; + if (tp->t_fdblocks_delta) + sbp->sb_fdblocks += tp->t_fdblocks_delta; + if (tp->t_frextents_delta) + sbp->sb_frextents += tp->t_frextents_delta; + libxfs_mod_sb(tp, XFS_SB_ALL_BITS); + } + +#ifdef XACT_DEBUG + fprintf(stderr, "committing dirty transaction %p\n", tp); +#endif + trans_committed(tp); + + /* That's it for the transaction structure. Free it. */ + free(tp); + tp = NULL; + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/util.c linux-2.4-xfs/cmd/xfsprogs/libxfs/util.c --- linux-2.4.7/cmd/xfsprogs/libxfs/util.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/util.c Thu Apr 12 18:30:32 2001 @@ -0,0 +1,735 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +/* + * Wrapper around call to libxfs_ialloc. Takes care of committing and + * allocating a new transaction as needed. + * + * Originally there were two copies of this code - one in mkfs, the + * other in repair - now there is just the one. + */ +int +libxfs_inode_alloc( + xfs_trans_t **tp, + xfs_inode_t *pip, + mode_t mode, + ushort nlink, + dev_t rdev, + cred_t *cr, + xfs_inode_t **ipp) +{ + boolean_t call_again; + int i; + xfs_buf_t *ialloc_context; + xfs_inode_t *ip; + xfs_trans_t *ntp; + int error; + + call_again = B_FALSE; + ialloc_context = (xfs_buf_t *)0; + error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr, (xfs_prid_t) 0, + 1, &ialloc_context, &call_again, &ip); + if (error) { + return error; + } + if (call_again) { + xfs_trans_bhold(*tp, ialloc_context); + ntp = xfs_trans_dup(*tp); + xfs_trans_commit(*tp, 0, NULL); + *tp = ntp; + if ((i = xfs_trans_reserve(*tp, 0, 0, 0, 0, 0))) { + fprintf(stderr, "%s: cannot reserve space: %s\n", + progname, strerror(errno)); + exit(1); + } + xfs_trans_bjoin(*tp, ialloc_context); + error = libxfs_ialloc(*tp, pip, mode, nlink, rdev, cr, + (xfs_prid_t) 0, 1, &ialloc_context, + &call_again, &ip); + if (error) { + return error; + } + } + *ipp = ip; + ASSERT(ip); + return error; +} + +/* + * Change the requested timestamp in the given inode. + * + * This was once shared with the kernel, but has diverged to the point + * where its no longer worth the hassle of maintaining common code. + */ +void +libxfs_ichgtime(xfs_inode_t *ip, int flags) +{ + struct timespec tv; + struct timeval stv; + + gettimeofday(&stv, (struct timezone *)0); + tv.tv_sec = stv.tv_sec; + tv.tv_nsec = stv.tv_usec * 1000; + if (flags & XFS_ICHGTIME_MOD) { + ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec; + ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec; + } + if (flags & XFS_ICHGTIME_ACC) { + ip->i_d.di_atime.t_sec = (__int32_t)tv.tv_sec; + ip->i_d.di_atime.t_nsec = (__int32_t)tv.tv_nsec; + } + if (flags & XFS_ICHGTIME_CHG) { + ip->i_d.di_ctime.t_sec = (__int32_t)tv.tv_sec; + ip->i_d.di_ctime.t_nsec = (__int32_t)tv.tv_nsec; + } +} + +/* + * Allocate an inode on disk and return a copy of it's in-core version. + * Set mode, nlink, and rdev appropriately within the inode. + * The uid and gid for the inode are set according to the contents of + * the given cred structure. + * + * This was once shared with the kernel, but has diverged to the point + * where its no longer worth the hassle of maintaining common code. + */ +int +libxfs_ialloc( + xfs_trans_t *tp, + xfs_inode_t *pip, + mode_t mode, + nlink_t nlink, + dev_t rdev, + cred_t *cr, + xfs_prid_t prid, + int okalloc, + xfs_buf_t **ialloc_context, + boolean_t *call_again, + xfs_inode_t **ipp) +{ + xfs_ino_t ino; + xfs_inode_t *ip; + uint flags; + int error; + + /* + * Call the space management code to pick + * the on-disk inode to be allocated. + */ + error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc, + ialloc_context, call_again, &ino); + if (error != 0) + return error; + if (*call_again || ino == NULLFSINO) { + *ipp = NULL; + return 0; + } + ASSERT(*ialloc_context == NULL); + + error = xfs_trans_iget(tp->t_mountp, tp, ino, 0, &ip); + if (error != 0) + return error; + ASSERT(ip != NULL); + + ip->i_d.di_mode = (__uint16_t)mode; + ip->i_d.di_onlink = 0; + ip->i_d.di_nlink = nlink; + ASSERT(ip->i_d.di_nlink == nlink); + ip->i_d.di_uid = cr->cr_uid; + ip->i_d.di_gid = cr->cr_gid; + ip->i_d.di_projid = prid; + bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad)); + + /* + * If the superblock version is up to where we support new format + * inodes and this is currently an old format inode, then change + * the inode version number now. This way we only do the conversion + * here rather than here and in the flush/logging code. + */ + if (XFS_SB_VERSION_HASNLINK(&tp->t_mountp->m_sb) && + ip->i_d.di_version == XFS_DINODE_VERSION_1) { + ip->i_d.di_version = XFS_DINODE_VERSION_2; + /* old link count, projid field, pad field already zeroed */ + } + + ip->i_d.di_size = 0; + ip->i_d.di_nextents = 0; + ASSERT(ip->i_d.di_nblocks == 0); + xfs_ichgtime(ip, XFS_ICHGTIME_CHG|XFS_ICHGTIME_ACC|XFS_ICHGTIME_MOD); + /* + * di_gen will have been taken care of in xfs_iread. + */ + ip->i_d.di_extsize = 0; + ip->i_d.di_dmevmask = 0; + ip->i_d.di_dmstate = 0; + ip->i_d.di_flags = 0; + flags = XFS_ILOG_CORE; + switch (mode & IFMT) { + case IFIFO: + case IFCHR: + case IFBLK: + case IFSOCK: + ip->i_d.di_format = XFS_DINODE_FMT_DEV; + ip->i_df.if_u2.if_rdev = makedev(major(rdev), minor(rdev)); ip->i_df.if_flags = 0; + flags |= XFS_ILOG_DEV; + break; + case IFREG: + case IFDIR: + case IFLNK: + ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; + ip->i_df.if_flags = XFS_IFEXTENTS; + ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0; + ip->i_df.if_u1.if_extents = NULL; + break; + default: + ASSERT(0); + } + /* Attribute fork settings for new inode. */ + ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; + ip->i_d.di_anextents = 0; + + /* + * Log the new values stuffed into the inode. + */ + xfs_trans_log_inode(tp, ip, flags); + *ipp = ip; + return 0; +} + +void +libxfs_iprint(xfs_inode_t *ip) +{ + xfs_dinode_core_t *dip; + xfs_bmbt_rec_t *ep; + xfs_extnum_t i; + xfs_extnum_t nextents; + + printf("Inode %lx\n", (unsigned long)ip); + printf(" i_dev %llx\n", (unsigned long long)ip->i_dev); + printf(" i_ino %llx\n", (unsigned long long)ip->i_ino); + + if (ip->i_df.if_flags & XFS_IFEXTENTS) + printf("EXTENTS "); + printf("\n"); + printf(" i_df.if_bytes %d\n", ip->i_df.if_bytes); + printf(" i_df.if_u1.if_extents/if_data %lx\n", + (unsigned long)ip->i_df.if_u1.if_extents); + if (ip->i_df.if_flags & XFS_IFEXTENTS) { + nextents = ip->i_df.if_bytes / (uint)sizeof(*ep); + for (ep = ip->i_df.if_u1.if_extents, i = 0; i < nextents; i++, ep++) { + xfs_bmbt_irec_t rec; + + xfs_bmbt_get_all(ep, &rec); + printf("\t%d: startoff %llu, startblock 0x%llx," + " blockcount %llu, state %d\n", + i, (unsigned long long)rec.br_startoff, + (unsigned long long)rec.br_startblock, + (unsigned long long)rec.br_blockcount, + (int)rec.br_state); + } + } + printf(" i_df.if_broot %lx\n", (unsigned long)ip->i_df.if_broot); + printf(" i_df.if_broot_bytes %x\n", ip->i_df.if_broot_bytes); + + dip = &(ip->i_d); + printf("\nOn disk portion\n"); + printf(" di_magic %x\n", dip->di_magic); + printf(" di_mode %o\n", dip->di_mode); + printf(" di_version %x\n", (uint)dip->di_version); + switch (ip->i_d.di_format) { + case XFS_DINODE_FMT_LOCAL: + printf(" Inline inode\n"); + break; + case XFS_DINODE_FMT_EXTENTS: + printf(" Extents inode\n"); + break; + case XFS_DINODE_FMT_BTREE: + printf(" B-tree inode\n"); + break; + default: + printf(" Other inode\n"); + break; + } + printf(" di_nlink %x\n", dip->di_nlink); + printf(" di_uid %d\n", dip->di_uid); + printf(" di_gid %d\n", dip->di_gid); + printf(" di_nextents %d\n", dip->di_nextents); + printf(" di_size %llu\n", (unsigned long long)dip->di_size); + printf(" di_gen %x\n", dip->di_gen); + printf(" di_extsize %d\n", dip->di_extsize); + printf(" di_flags %x\n", dip->di_flags); + printf(" di_nblocks %llu\n", (unsigned long long)dip->di_nblocks); +} + +/* + * Writes a modified inode's changes out to the inode's on disk home. + * Originally based on xfs_iflush_int() from xfs_inode.c in the kernel. + */ +int +libxfs_iflush_int(xfs_inode_t *ip, xfs_buf_t *bp) +{ + xfs_inode_log_item_t *iip; + xfs_dinode_t *dip; + xfs_mount_t *mp; + + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || + ip->i_d.di_nextents > ip->i_df.if_ext_max); + + iip = ip->i_itemp; + mp = ip->i_mount; + + /* set *dip = inode's place in the buffer */ + dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_boffset); + +#ifdef DEBUG + ASSERT(ip->i_d.di_magic == XFS_DINODE_MAGIC); + if ((ip->i_d.di_mode & IFMT) == IFREG) { + ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) || + (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) ); + } + else if ((ip->i_d.di_mode & IFMT) == IFDIR) { + ASSERT( (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS) || + (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) || + (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL) ); + } + ASSERT(ip->i_d.di_nextents+ip->i_d.di_anextents <= ip->i_d.di_nblocks); + ASSERT(ip->i_d.di_forkoff <= mp->m_sb.sb_inodesize); +#endif + + /* + * Copy the dirty parts of the inode into the on-disk + * inode. We always copy out the core of the inode, + * because if the inode is dirty at all the core must + * be. + */ + xfs_xlate_dinode_core((xfs_caddr_t)&(dip->di_core), &(ip->i_d), -1, + ARCH_CONVERT); + /* + * If this is really an old format inode and the superblock version + * has not been updated to support only new format inodes, then + * convert back to the old inode format. If the superblock version + * has been updated, then make the conversion permanent. + */ + ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1 || + XFS_SB_VERSION_HASNLINK(&mp->m_sb)); + if (ip->i_d.di_version == XFS_DINODE_VERSION_1) { + if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) { + /* + * Convert it back. + */ + ASSERT(ip->i_d.di_nlink <= XFS_MAXLINK_1); + INT_SET(dip->di_core.di_onlink, ARCH_CONVERT, + ip->i_d.di_nlink); + } else { + /* + * The superblock version has already been bumped, + * so just make the conversion to the new inode + * format permanent. + */ + ip->i_d.di_version = XFS_DINODE_VERSION_2; + INT_SET(dip->di_core.di_version, ARCH_CONVERT, + XFS_DINODE_VERSION_2); + ip->i_d.di_onlink = 0; + INT_ZERO(dip->di_core.di_onlink, ARCH_CONVERT); + bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad)); + bzero(&(dip->di_core.di_pad[0]), + sizeof(dip->di_core.di_pad)); + ASSERT(ip->i_d.di_projid == 0); + } + } + + if (xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK, bp) == EFSCORRUPTED) + return EFSCORRUPTED; + if (XFS_IFORK_Q(ip)) { + /* The only error from xfs_iflush_fork is on the data fork. */ + xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK, bp); + } + + return 0; +} + +/* + * Given a block number in a fork, return the next valid block number + * (not a hole). + * If this is the last block number then NULLFILEOFF is returned. + * + * This was originally in the kernel, but only used in xfs_repair. + */ +int +libxfs_bmap_next_offset( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + xfs_fileoff_t *bnop, /* current block */ + int whichfork) /* data or attr fork */ +{ + xfs_fileoff_t bno; /* current block */ + int eof; /* hit end of file */ + int error; /* error return value */ + xfs_bmbt_irec_t got; /* current extent value */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t lastx; /* last extent used */ + xfs_bmbt_irec_t prev; /* previous extent value */ + + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) + return XFS_ERROR(EIO); + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + *bnop = NULLFILEOFF; + return 0; + } + ifp = XFS_IFORK_PTR(ip, whichfork); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + bno = *bnop + 1; + xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, &prev); + if (eof) + *bnop = NULLFILEOFF; + else + *bnop = got.br_startoff < bno ? bno : got.br_startoff; + return 0; +} + +/* + * Like xfs_dir_removename, but only for removing entries with + * (name, hashvalue) pairs that may not be consistent (hashvalue + * may not be correctly set for the name). + * + * This was originally in the kernel, but only used in xfs_repair. + */ +int +xfs_dir_bogus_removename(xfs_trans_t *trans, xfs_inode_t *dp, char *name, + xfs_fsblock_t *firstblock, xfs_bmap_free_t *flist, + xfs_extlen_t total, xfs_dahash_t hashval, int namelen) +{ + xfs_da_args_t args; + int count, totallen, newsize, retval; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (namelen >= MAXNAMELEN) { + return EINVAL; + } + + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = hashval; + args.inumber = 0; + args.dp = dp; + args.firstblock = firstblock; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = trans; + args.justcheck = args.addname = 0; + args.oknoent = 1; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + retval = xfs_dir_shortform_removename(&args); + } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_removename(&args, &count, &totallen); + if (retval == 0) { + newsize = XFS_DIR_SF_ALLFIT(count, totallen); + if (newsize <= XFS_IFORK_DSIZE(dp)) { + retval = xfs_dir_leaf_to_shortform(&args); + } + } + } else { + retval = xfs_dir_node_removename(&args); + } + return(retval); +} + +/* + * Like xfs_dir_removename, but only for removing entries with + * (name, hashvalue) pairs that may not be consistent (hashvalue + * may not be correctly set for the name). + * + * This was originally in the kernel, but only used in xfs_repair. + */ +int +xfs_dir2_bogus_removename( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + char *name, /* name of entry to remove */ + xfs_fsblock_t *first, /* bmap's firstblock */ + xfs_bmap_free_t *flist, /* bmap's freeblock list */ + xfs_extlen_t total, /* bmap's total block count */ + xfs_dahash_t hash, /* name's real hash value */ + int namelen) /* entry's name length */ +{ + xfs_da_args_t args; /* operation arguments */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (namelen >= MAXNAMELEN) + return EINVAL; + + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = hash; + args.inumber = 0; + args.dp = dp; + args.firstblock = first; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = tp; + args.justcheck = args.addname = 0; + args.oknoent = 1; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_removename(&args); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) + return rval; + else if (v) + rval = xfs_dir2_block_removename(&args); + else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) + return rval; + else if (v) + rval = xfs_dir2_leaf_removename(&args); + else + rval = xfs_dir2_node_removename(&args); + return rval; +} + +/* + * Utility routine common used to apply a delta to a field in the + * in-core superblock. + * Switch on the field indicated and apply the delta to that field. + * Fields are not allowed to dip below zero, so if the delta would + * do this do not apply it and return EINVAL. + * + * Originally derived from xfs_mod_incore_sb(). + */ +int +libxfs_mod_incore_sb(xfs_mount_t *mp, xfs_sb_field_t field, int delta, int rsvd) +{ + long long lcounter; /* long counter for 64 bit fields */ + + switch (field) { + case XFS_SBS_FDBLOCKS: + lcounter = (long long)mp->m_sb.sb_fdblocks; + lcounter += delta; + if (lcounter < 0) + return (XFS_ERROR(ENOSPC)); + mp->m_sb.sb_fdblocks = lcounter; + break; + default: + ASSERT(0); + } + return 0; +} + +int +libxfs_bmap_finish( + xfs_trans_t **tp, + xfs_bmap_free_t *flist, + xfs_fsblock_t firstblock, + int *committed) +{ + xfs_bmap_free_item_t *free; /* free extent list item */ + xfs_bmap_free_item_t *next; /* next item on free list */ + int error; + + if (flist->xbf_count == 0) { + *committed = 0; + return 0; + } + + for (free = flist->xbf_first; free != NULL; free = next) { + next = free->xbfi_next; + if ((error = xfs_free_extent(*tp, free->xbfi_startblock, + free->xbfi_blockcount))) + return error; + xfs_bmap_del_free(flist, NULL, free); + } + return 0; +} + +/* + * This routine allocates disk space for the given file. + * Originally derived from xfs_alloc_file_space(). + */ +int +libxfs_alloc_file_space( + xfs_inode_t *ip, + xfs_off_t offset, + xfs_off_t len, + int alloc_type, + int attr_flags) +{ + xfs_mount_t *mp; + xfs_off_t count; + xfs_filblks_t datablocks; + xfs_filblks_t allocated_fsb; + xfs_filblks_t allocatesize_fsb; + xfs_fsblock_t firstfsb; + xfs_bmap_free_t free_list; + xfs_bmbt_irec_t *imapp; + xfs_bmbt_irec_t imaps[1]; + int reccount; + uint resblks; + xfs_fileoff_t startoffset_fsb; + xfs_trans_t *tp; + int xfs_bmapi_flags; + int committed; + int error; + + if (len <= 0) + return EINVAL; + + count = len; + error = 0; + imapp = &imaps[0]; + reccount = 1; + xfs_bmapi_flags = XFS_BMAPI_WRITE | (alloc_type ? XFS_BMAPI_PREALLOC : 0); + mp = ip->i_mount; + startoffset_fsb = XFS_B_TO_FSBT(mp, offset); + allocatesize_fsb = XFS_B_TO_FSB(mp, count); + + /* allocate file space until done or until there is an error */ + while (allocatesize_fsb && !error) { + datablocks = allocatesize_fsb; + + tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); + resblks = (uint)XFS_DIOSTRAT_SPACE_RES(mp, datablocks); + error = xfs_trans_reserve(tp, resblks, 0, 0, 0, 0); + if (error) + break; + xfs_trans_ijoin(tp, ip, 0); + xfs_trans_ihold(tp, ip); + + XFS_BMAP_INIT(&free_list, &firstfsb); + error = xfs_bmapi(tp, ip, startoffset_fsb, allocatesize_fsb, + xfs_bmapi_flags, &firstfsb, 0, imapp, + &reccount, &free_list); + if (error) + break; + + /* complete the transaction */ + error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed); + if (error) + break; + + error = xfs_trans_commit(tp, 0, NULL); + if (error) + break; + + allocated_fsb = imapp->br_blockcount; + if (reccount == 0) + return ENOSPC; + + startoffset_fsb += allocated_fsb; + allocatesize_fsb -= allocated_fsb; + } + return error; +} + +unsigned int +libxfs_log2_roundup(unsigned int i) +{ + unsigned int rval; + + for (rval = 0; rval < NBBY * sizeof(i); rval++) { + if ((1 << rval) >= i) + break; + } + return rval; +} + +/* + * Get a buffer for the dir/attr block, fill in the contents. + * Don't check magic number, the caller will (it's xfs_repair). + * + * Originally from xfs_da_btree.c in the kernel, but only used + * in userspace so it now resides here. + */ +int +libxfs_da_read_bufr( + xfs_trans_t *trans, + xfs_inode_t *dp, + xfs_dablk_t bno, + xfs_daddr_t mappedbno, + xfs_dabuf_t **bpp, + int whichfork) +{ + return libxfs_da_do_buf(trans, dp, bno, &mappedbno, bpp, whichfork, 2, + (inst_t *)__return_address); +} + +/* + * Hold dabuf at transaction commit. + * + * Originally from xfs_da_btree.c in the kernel, but only used + * in userspace so it now resides here. + */ +void +libxfs_da_bhold(xfs_trans_t *tp, xfs_dabuf_t *dabuf) +{ + int i; + + for (i = 0; i < dabuf->nbuf; i++) + xfs_trans_bhold(tp, dabuf->bps[i]); +} + +/* + * Join dabuf to transaction. + * + * Originally from xfs_da_btree.c in the kernel, but only used + * in userspace so it now resides here. + */ +void +libxfs_da_bjoin(xfs_trans_t *tp, xfs_dabuf_t *dabuf) +{ + int i; + + for (i = 0; i < dabuf->nbuf; i++) + xfs_trans_bjoin(tp, dabuf->bps[i]); +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs.h linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs.h --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs.h Mon Apr 16 17:53:46 2001 @@ -0,0 +1,563 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * This header is effectively a "namespace multiplexor" for the + * user level XFS code. It provides all of the necessary stuff + * such that we can build some parts of the XFS kernel code in + * user space in a controlled fashion, and translates the names + * used in the kernel into the names which libxfs is going to + * make available to user tools. + * + * It should only ever be #include'd by XFS "kernel" code being + * compiled in user space. + * + * Our goals here are to... + * o "share" large amounts of complex code between user and + * kernel space; + * o shield the user tools from changes in the bleeding + * edge kernel code, merging source changes when + * convenient and not immediately (no symlinks); + * o i.e. be able to merge changes to the kernel source back + * into the affected user tools in a controlled fashion; + * o provide a _minimalist_ life-support system for kernel + * code in user land, not the "everything + the kitchen + * sink" model which libsim had mutated into; + * o allow the kernel code to be completely free of code + * specifically there to support the user level build. + */ + +#include +#include +#include +#include + +/* + * Map XFS kernel routine names to libxfs.h names + */ + +#define xfs_xlatesb libxfs_xlate_sb +#define xfs_xlate_dinode_core libxfs_xlate_dinode_core +#define xfs_bmbt_get_all libxfs_bmbt_get_all +#define xfs_bmbt_get_blockcount libxfs_bmbt_get_blockcount +#define xfs_bmbt_get_startoff libxfs_bmbt_get_startoff +#define xfs_da_hashname libxfs_da_hashname +#define xfs_da_log2_roundup libxfs_da_log2_roundup +#define xfs_highbit32 libxfs_highbit32 +#define xfs_highbit64 libxfs_highbit64 +#define xfs_attr_leaf_newentsize libxfs_attr_leaf_newentsize +#define xfs_alloc_compute_maxlevels libxfs_alloc_compute_maxlevels +#define xfs_bmap_compute_maxlevels libxfs_bmap_compute_maxlevels +#define xfs_ialloc_compute_maxlevels libxfs_ialloc_compute_maxlevels + +#define xfs_dir_init libxfs_dir_init +#define xfs_dir2_init libxfs_dir2_init +#define xfs_dir_mount libxfs_dir_mount +#define xfs_dir2_mount libxfs_dir2_mount +#define xfs_dir_createname libxfs_dir_createname +#define xfs_dir2_createname libxfs_dir2_createname +#define xfs_dir_lookup libxfs_dir_lookup +#define xfs_dir2_lookup libxfs_dir2_lookup +#define xfs_dir_replace libxfs_dir_replace +#define xfs_dir2_replace libxfs_dir2_replace +#define xfs_dir_removename libxfs_dir_removename +#define xfs_dir2_removename libxfs_dir2_removename +#define xfs_dir_bogus_removename libxfs_dir_bogus_removename +#define xfs_dir2_bogus_removename libxfs_dir2_bogus_removename + +#define xfs_mount_common libxfs_mount_common +#define xfs_rtmount_init libxfs_rtmount_init +#define xfs_alloc_fix_freelist libxfs_alloc_fix_freelist +#define xfs_iread libxfs_iread +#define xfs_ialloc libxfs_ialloc +#define xfs_idata_realloc libxfs_idata_realloc +#define xfs_itobp libxfs_itobp +#define xfs_ichgtime libxfs_ichgtime +#define xfs_bmapi libxfs_bmapi +#define xfs_bmap_finish libxfs_bmap_finish +#define xfs_bmap_del_free libxfs_bmap_del_free +#define xfs_bunmapi libxfs_bunmapi +#define xfs_free_extent libxfs_free_extent +#define xfs_rtfree_extent libxfs_rtfree_extent +#define xfs_mod_sb libxfs_mod_sb +#define xfs_mod_incore_sb libxfs_mod_incore_sb + +#define xfs_trans_init libxfs_trans_init +#define xfs_trans_dup libxfs_trans_dup +#define xfs_trans_iget libxfs_trans_iget +#define xfs_trans_ijoin libxfs_trans_ijoin +#define xfs_trans_ihold libxfs_trans_ihold +#define xfs_trans_bjoin libxfs_trans_bjoin +#define xfs_trans_bhold libxfs_trans_bhold +#define xfs_trans_alloc libxfs_trans_alloc +#define xfs_trans_commit libxfs_trans_commit +#define xfs_trans_mod_sb libxfs_trans_mod_sb +#define xfs_trans_reserve libxfs_trans_reserve +#define xfs_trans_get_buf libxfs_trans_get_buf +#define xfs_trans_log_buf libxfs_trans_log_buf +#define xfs_trans_read_buf libxfs_trans_read_buf +#define xfs_trans_log_inode libxfs_trans_log_inode +#define xfs_trans_inode_alloc_buf libxfs_trans_inode_alloc_buf +#define xfs_trans_brelse libxfs_trans_brelse +#define xfs_trans_binval libxfs_trans_binval + +#define xfs_da_shrink_inode libxfs_da_shrink_inode +#define xfs_da_grow_inode libxfs_da_grow_inode +#define xfs_da_brelse libxfs_da_brelse +#define xfs_da_read_buf libxfs_da_read_buf +#define xfs_da_get_buf libxfs_da_get_buf +#define xfs_da_log_buf libxfs_da_log_buf +#define xfs_da_do_buf libxfs_da_do_buf +#define xfs_dir2_shrink_inode libxfs_dir2_shrink_inode +#define xfs_dir2_grow_inode libxfs_dir2_grow_inode +#define xfs_dir2_isleaf libxfs_dir2_isleaf +#define xfs_dir2_isblock libxfs_dir2_isblock +#define xfs_dir2_data_use_free libxfs_dir2_data_use_free +#define xfs_dir2_data_make_free libxfs_dir2_data_make_free +#define xfs_dir2_data_log_entry libxfs_dir2_data_log_entry +#define xfs_dir2_data_log_header libxfs_dir2_data_log_header +#define xfs_dir2_data_freescan libxfs_dir2_data_freescan +#define xfs_dir2_free_log_bests libxfs_dir2_free_log_bests + + +/* + * Infrastructure to support building kernel XFS code in user space + */ + +/* buffer management */ +#define XFS_BUF_LOCK 0 +#define XFS_BUF_MAPPED 0 +#define XFS_BUF_TRYLOCK 0 +#define XFS_BUF_ISDONE(bp) 0 +#define XFS_BUF_GETERROR(bp) 0 +#define XFS_BUF_DONE(bp) ((void) 0) +#define XFS_BUF_SET_REF(a,b) ((void) 0) +#define XFS_BUF_SET_VTYPE(a,b) ((void) 0) +#define XFS_BUF_SET_VTYPE_REF(a,b,c) ((void) 0) +#define XFS_BUF_SET_BDSTRAT_FUNC(a,b) ((void) 0) +#define xfs_baread(a,b,c) ((void) 0) /* no readahead */ +#define xfs_buftrace(x,y) ((void) 0) /* debug only */ +#define xfs_buf_item_log_debug(bip,a,b) ((void) 0) /* debug only */ +#define xfs_validate_extents(e,n,f) ((void) 0) /* debug only */ +#define xfs_buf_relse(bp) libxfs_putbuf(bp) +#define xfs_read_buf(mp,x,blkno,len,f,bpp) \ + ( *(bpp) = libxfs_readbuf( (mp)->m_dev, (blkno), (len), 1), 0 ) + + +/* transaction management */ +#define xfs_trans_set_sync(tp) ((void) 0) +#define xfs_trans_agblocks_delta(tp, d) ((void) 0) /* debug only */ +#define xfs_trans_agflist_delta(tp, d) ((void) 0) /* debug only */ +#define xfs_trans_agbtree_delta(tp, d) ((void) 0) /* debug only */ +#define xfs_trans_mod_dquot_byino(tp,ip,f,d) ((void) 0) +#define xfs_trans_get_block_res(tp) 1 +#define xfs_trans_reserve_blkquota(tp,i,n) 0 +#define xfs_trans_unreserve_blkquota(tp,i,n) ((void) 0) +#define xfs_trans_unreserve_rtblkquota(tp,i,n) ((void) 0) + + +/* memory management */ +#define KM_SLEEP 1 +#define KM_SLEEP_IO 2 +#define kmem_zone_init(a, b) libxfs_zone_init(a, b) +#define kmem_zone_alloc(z, f) libxfs_zone_zalloc(z) +#define kmem_zone_zalloc(z, f) libxfs_zone_zalloc(z) +#define kmem_zone_free(z, p) libxfs_zone_free(z, p) +#define kmem_realloc(p,sz,u,f) libxfs_realloc(p,sz) +#define kmem_alloc(size, f) libxfs_malloc(size) +#define kmem_free(p, size) libxfs_free(p) + +/* directory management */ +#define xfs_dir2_trace_args(where, args) ((void) 0) +#define xfs_dir2_trace_args_b(where, args, bp) ((void) 0) +#define xfs_dir2_trace_args_bb(where, args, lbp, dbp) ((void) 0) +#define xfs_dir2_trace_args_bibii(where, args, bs, ss, bd, sd, c) ((void) 0) +#define xfs_dir2_trace_args_db(where, args, db, bp) ((void) 0) +#define xfs_dir2_trace_args_i(where, args, i) ((void) 0) +#define xfs_dir2_trace_args_s(where, args, s) ((void) 0) +#define xfs_dir2_trace_args_sb(where, args, s, bp) ((void) 0) +#define xfs_dir_shortform_validate_ondisk(a,b) ((void) 0) + + +/* block management */ +#define xfs_bmap_check_extents(ip,w) ((void) 0) +#define xfs_bmap_trace_delete(f,d,ip,i,c,w) ((void) 0) +#define xfs_bmap_trace_exlist(f,ip,i,w) ((void) 0) +#define xfs_bmap_trace_insert(f,d,ip,i,c,r1,r2,w) ((void) 0) +#define xfs_bmap_trace_post_update(f,d,ip,i,w) ((void) 0) +#define xfs_bmap_trace_pre_update(f,d,ip,i,w) ((void) 0) +#define xfs_bmap_validate_ret(bno,len,flags,mval,onmap,nmap) ((void) 0) +#define xfs_bunmap_trace(ip, bno, len, flags, ra) ((void) 0) +#define XFS_BMBT_TRACE_ARGBI(c,b,i) ((void) 0) +#define XFS_BMBT_TRACE_ARGBII(c,b,i,j) ((void) 0) +#define XFS_BMBT_TRACE_ARGFFFI(c,o,b,i,j) ((void) 0) +#define XFS_BMBT_TRACE_ARGI(c,i) ((void) 0) +#define XFS_BMBT_TRACE_ARGIFK(c,i,f,k) ((void) 0) +#define XFS_BMBT_TRACE_ARGIFR(c,i,f,r) ((void) 0) +#define XFS_BMBT_TRACE_ARGIK(c,i,k) ((void) 0) +#define XFS_BMBT_TRACE_CURSOR(c,s) ((void) 0) + + +/* anything else */ +typedef __uint32_t inst_t; /* an instruction */ +typedef enum { B_FALSE, B_TRUE } boolean_t; +typedef struct { dev_t dev; } buftarg_t; +#define STATIC +#define ATTR_ROOT 1 /* use attrs in root namespace */ +#define ENOATTR ENODATA /* Attribute not found */ +#define EFSCORRUPTED 990 /* Filesystem is corrupted */ +#define ktrace_t void +#define m_ddev_targp m_dev +#define KERN_WARNING +#define XFS_ERROR(e) (e) +#define XFS_TEST_ERROR(expr,a,b,c) ( expr ) +#define TRACE_FREE(s,a,b,x,f) ((void) 0) +#define TRACE_ALLOC(s,a) ((void) 0) +#define TRACE_MODAGF(a,b,c) ((void) 0) +#define XFS_FORCED_SHUTDOWN(mp) 0 +#define XFS_MOUNT_WSYNC 0 +#define XFS_MOUNT_NOALIGN 0 +#define XFS_ILOCK_EXCL 0 +#define mrlock(a,b,c) ((void) 0) +#define mraccunlock(a) ((void) 0) +#define mrunlock(a) ((void) 0) +#define mraccess(a) ((void) 0) +#define ismrlocked(a,b) 1 +#define ovbcopy(from,to,count) memmove(to,from,count) +#define __return_address __builtin_return_address(0) +#define xfs_btree_reada_bufl(m,fsb,c) ((void) 0) +#define xfs_btree_reada_bufs(m,fsb,c,x) ((void) 0) +#undef XFS_DIR_SHORTFORM_VALIDATE_ONDISK +#define XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp,dip) 0 + +#if (__GNUC__ < 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ <= 95)) +# define xfs_fs_cmn_err(a,b,msg,args...)( fprintf(stderr, msg, ## args) ) +# define printk(msg,args...) ( fprintf(stderr, msg, ## args) ) +#else +# define xfs_fs_cmn_err(a,b,...) ( fprintf(stderr, __VA_ARGS__) ) +# define printk(...) ( fprintf(stderr, __VA_ARGS__) ) +#endif + +#define do_mod(a, b) ((a) % (b)) +#define do_div(n,base) ({ \ + int __res; \ + __res = ((unsigned long) n) % (unsigned) base; \ + n = ((unsigned long) n) / (unsigned) base; \ + __res; }) + +#include +#define NBPP PAGE_SIZE + +static inline int atomicIncWithWrap(int *a, int b) +{ + int r = *a; + (*a)++; + if (*a == b) + *a = 0; + return r; +} + + +/* + * Prototypes needed for a clean build + */ + +/* xfs_alloc.c */ +int xfs_alloc_get_freelist (xfs_trans_t *, xfs_buf_t *, xfs_agblock_t *); +void xfs_alloc_log_agf (xfs_trans_t *, xfs_buf_t *, int); +int xfs_alloc_put_freelist (xfs_trans_t *, xfs_buf_t *, xfs_buf_t *, + xfs_agblock_t); +int xfs_alloc_read_agf (xfs_mount_t *, xfs_trans_t *, xfs_agnumber_t, + int, xfs_buf_t **); +int xfs_alloc_vextent (xfs_alloc_arg_t *); +int xfs_alloc_pagf_init (xfs_mount_t *, xfs_trans_t *, xfs_agnumber_t, int); +int xfs_alloc_ag_vextent_size (xfs_alloc_arg_t *); +int xfs_alloc_ag_vextent_near (xfs_alloc_arg_t *); +int xfs_alloc_ag_vextent_exact (xfs_alloc_arg_t *); +int xfs_alloc_ag_vextent_small (xfs_alloc_arg_t *, xfs_btree_cur_t *, + xfs_agblock_t *, xfs_extlen_t *, int *); + +/* xfs_ialloc.c */ +int xfs_dialloc (xfs_trans_t *, xfs_ino_t, mode_t, int, xfs_buf_t **, + boolean_t *, xfs_ino_t *); +void xfs_ialloc_log_agi (xfs_trans_t *, xfs_buf_t *, int); +int xfs_ialloc_read_agi (xfs_mount_t *, xfs_trans_t *, xfs_agnumber_t, + xfs_buf_t **); +int xfs_dilocate (xfs_mount_t *, xfs_trans_t *, xfs_ino_t, xfs_fsblock_t *, + int *, int *, uint); + +/* xfs_rtalloc.c */ +int xfs_rtfree_extent (xfs_trans_t *, xfs_rtblock_t, xfs_extlen_t); +int xfs_rtmodify_range (xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, + xfs_extlen_t, int); +int xfs_rtmodify_summary (xfs_mount_t *, xfs_trans_t *, int, + xfs_rtblock_t, int, xfs_buf_t **, xfs_fsblock_t *); + +/* xfs_btree.c */ +extern xfs_zone_t *xfs_btree_cur_zone; +void xfs_btree_check_key (xfs_btnum_t, void *, void *); +void xfs_btree_check_rec (xfs_btnum_t, void *, void *); +int xfs_btree_check_lblock (xfs_btree_cur_t *, xfs_btree_lblock_t *, + int, xfs_buf_t *); +int xfs_btree_check_sblock (xfs_btree_cur_t *, xfs_btree_sblock_t *, + int, xfs_buf_t *); +int xfs_btree_check_sptr (xfs_btree_cur_t *, xfs_agblock_t, int); +int xfs_btree_check_lptr (xfs_btree_cur_t *, xfs_dfsbno_t, int); +void xfs_btree_del_cursor (xfs_btree_cur_t *, int); +int xfs_btree_dup_cursor (xfs_btree_cur_t *, xfs_btree_cur_t **); +int xfs_btree_firstrec (xfs_btree_cur_t *, int); +xfs_btree_block_t *xfs_btree_get_block (xfs_btree_cur_t *, int, xfs_buf_t **); +xfs_buf_t *xfs_btree_get_bufs (xfs_mount_t *, xfs_trans_t *, xfs_agnumber_t, + xfs_agblock_t, uint); +xfs_buf_t *xfs_btree_get_bufl (xfs_mount_t *, xfs_trans_t *tp, + xfs_fsblock_t, uint); +xfs_btree_cur_t *xfs_btree_init_cursor (xfs_mount_t *, xfs_trans_t *, + xfs_buf_t *, xfs_agnumber_t, xfs_btnum_t, + xfs_inode_t *, int); +int xfs_btree_islastblock (xfs_btree_cur_t *, int); +int xfs_btree_lastrec (xfs_btree_cur_t *, int); +void xfs_btree_offsets (__int64_t, const short *, int, int *, int *); +void xfs_btree_setbuf (xfs_btree_cur_t *, int, xfs_buf_t *); +int xfs_btree_read_bufs (xfs_mount_t *, xfs_trans_t *, xfs_agnumber_t, + xfs_agblock_t, uint, xfs_buf_t **, int); +int xfs_btree_read_bufl (xfs_mount_t *, xfs_trans_t *, xfs_fsblock_t, + uint, xfs_buf_t **, int); +int xfs_btree_readahead_core (xfs_btree_cur_t *, int, int); +static inline int xfs_btree_readahead (xfs_btree_cur_t *cur, int lev, int lr) +{ + if ((cur->bc_ra[lev] | lr) == cur->bc_ra[lev]) + return 0; + return xfs_btree_readahead_core(cur, lev, lr); +} + + +/* xfs_inode.c */ +int xfs_ialloc (xfs_trans_t *, xfs_inode_t *, mode_t, nlink_t, dev_t, cred_t *, + xfs_prid_t, int, xfs_buf_t **, boolean_t *, xfs_inode_t **); +int xfs_iread_extents (xfs_trans_t *, xfs_inode_t *, int); +int xfs_imap (xfs_mount_t *, xfs_trans_t *, xfs_ino_t, xfs_imap_t *, uint); +int xfs_iextents_copy (xfs_inode_t *, xfs_bmbt_rec_32_t *, int); +int xfs_iflush_int (xfs_inode_t *, xfs_buf_t *); +int xfs_iflush_fork (xfs_inode_t *, xfs_dinode_t *, xfs_inode_log_item_t *, + int, xfs_buf_t *); +int xfs_iformat_local (xfs_inode_t *, xfs_dinode_t *, int, int, int); +int xfs_iformat_extents (xfs_inode_t *, xfs_dinode_t *, int, int); +int xfs_iformat_btree (xfs_inode_t *, xfs_dinode_t *, int, int); +void xfs_iroot_realloc (xfs_inode_t *, int, int); +void xfs_idata_realloc (xfs_inode_t *, int, int); +void xfs_iext_realloc (xfs_inode_t *, int, int); +void xfs_idestroy_fork (xfs_inode_t *, int); +uint xfs_iroundup (uint); + +/* xfs_bmap.c */ +xfs_bmbt_rec_t *xfs_bmap_search_extents (xfs_inode_t *ip, + xfs_fileoff_t, int, int *, xfs_extnum_t *, + xfs_bmbt_irec_t *, xfs_bmbt_irec_t *); +int xfs_bmap_read_extents (xfs_trans_t *, xfs_inode_t *, int); +void xfs_bmap_add_free (xfs_fsblock_t, xfs_filblks_t, xfs_bmap_free_t *, + xfs_mount_t *); +int xfs_bmap_first_unused (xfs_trans_t *, xfs_inode_t *, xfs_extlen_t, + xfs_fileoff_t *, int); +int xfs_bmap_last_offset (xfs_trans_t *, xfs_inode_t *, xfs_fileoff_t *, int); +int xfs_bmap_last_before (xfs_trans_t *, xfs_inode_t *, xfs_fileoff_t *, int); +int xfs_bmap_one_block (xfs_inode_t *, int); +int xfs_bmapi_single (xfs_trans_t *, xfs_inode_t *, int, xfs_fsblock_t *, + xfs_fileoff_t); +int xfs_bmapi (xfs_trans_t *, xfs_inode_t *, xfs_fileoff_t, + xfs_filblks_t, int, xfs_fsblock_t *, xfs_extlen_t, + xfs_bmbt_irec_t *, int *, xfs_bmap_free_t *); +int xfs_bunmapi (xfs_trans_t *, xfs_inode_t *, xfs_fileoff_t, + xfs_filblks_t, int, xfs_extnum_t, xfs_fsblock_t *, + xfs_bmap_free_t *, int *); +int xfs_bmap_add_extent_hole_delay (xfs_inode_t *ip, xfs_extnum_t, + xfs_btree_cur_t *, xfs_bmbt_irec_t *, int *, int); +int xfs_bmap_add_extent_hole_real (xfs_inode_t *, xfs_extnum_t, + xfs_btree_cur_t *, xfs_bmbt_irec_t *, int *, int); +int xfs_bmap_add_extent_unwritten_real (xfs_inode_t *, xfs_extnum_t, + xfs_btree_cur_t **, xfs_bmbt_irec_t *, int *); +int xfs_bmap_add_extent_delay_real (xfs_inode_t *, xfs_extnum_t, + xfs_btree_cur_t **, xfs_bmbt_irec_t *, xfs_filblks_t *, + xfs_fsblock_t *, xfs_bmap_free_t *, int *, int); +int xfs_bmap_extents_to_btree (xfs_trans_t *, xfs_inode_t *, xfs_fsblock_t *, + xfs_bmap_free_t *, xfs_btree_cur_t **, int, int *, int); +void xfs_bmap_delete_exlist (xfs_inode_t *, xfs_extnum_t, xfs_extnum_t, int); +xfs_filblks_t xfs_bmap_worst_indlen (xfs_inode_t *, xfs_filblks_t); +int xfs_bmap_isaeof (xfs_inode_t *, xfs_fileoff_t, int, int *); +void xfs_bmap_insert_exlist (xfs_inode_t *, xfs_extnum_t, xfs_extnum_t, + xfs_bmbt_irec_t *, int); + +/* xfs_bmap_btree.c */ +int xfs_check_nostate_extents (xfs_bmbt_rec_t *, xfs_extnum_t); +void xfs_bmbt_log_ptrs (xfs_btree_cur_t *, xfs_buf_t *, int, int); +void xfs_bmbt_log_keys (xfs_btree_cur_t *, xfs_buf_t *, int, int); +int xfs_bmbt_killroot (xfs_btree_cur_t *, int); +int xfs_bmbt_updkey (xfs_btree_cur_t *, xfs_bmbt_key_t *, int); +int xfs_bmbt_lshift (xfs_btree_cur_t *, int, int *); +int xfs_bmbt_rshift (xfs_btree_cur_t *, int, int *); +int xfs_bmbt_split (xfs_btree_cur_t *, int, xfs_fsblock_t *, + xfs_bmbt_key_t *, xfs_btree_cur_t **, int *); + +/* xfs_ialloc_btree.c */ +int xfs_inobt_newroot (xfs_btree_cur_t *, int *); +int xfs_inobt_rshift (xfs_btree_cur_t *, int, int *); +int xfs_inobt_lshift (xfs_btree_cur_t *, int, int *); +int xfs_inobt_split (xfs_btree_cur_t *, int, xfs_agblock_t *, + xfs_inobt_key_t *, xfs_btree_cur_t **, int *); +void xfs_inobt_log_keys (xfs_btree_cur_t *, xfs_buf_t *, int, int); +void xfs_inobt_log_ptrs (xfs_btree_cur_t *, xfs_buf_t *, int, int); +void xfs_inobt_log_recs (xfs_btree_cur_t *, xfs_buf_t *, int, int); +void xfs_inobt_log_block (xfs_trans_t *, xfs_buf_t *, int); +int xfs_inobt_updkey (xfs_btree_cur_t *, xfs_inobt_key_t *, int); + +/* xfs_alloc_btree.c */ +void xfs_alloc_log_ptrs (xfs_btree_cur_t *, xfs_buf_t *, int, int); +void xfs_alloc_log_keys (xfs_btree_cur_t *, xfs_buf_t *, int, int); +void xfs_alloc_log_recs (xfs_btree_cur_t *, xfs_buf_t *, int, int); +void xfs_alloc_log_block (xfs_trans_t *, xfs_buf_t *, int); +int xfs_alloc_updkey (xfs_btree_cur_t *, xfs_alloc_key_t *, int); +int xfs_alloc_lshift (xfs_btree_cur_t *, int, int *); +int xfs_alloc_rshift (xfs_btree_cur_t *, int, int *); +int xfs_alloc_newroot (xfs_btree_cur_t *, int *); +int xfs_alloc_split (xfs_btree_cur_t *, int, xfs_agblock_t *, + xfs_alloc_key_t *, xfs_btree_cur_t **, int *); + +/* xfs_da_btree.c */ +xfs_dabuf_t *xfs_da_buf_make (int, xfs_buf_t **, inst_t *); +int xfs_da_root_join (xfs_da_state_t *, xfs_da_state_blk_t *); +int xfs_da_root_split (xfs_da_state_t *, xfs_da_state_blk_t *, + xfs_da_state_blk_t *); +void xfs_da_node_add (xfs_da_state_t *, xfs_da_state_blk_t *, + xfs_da_state_blk_t *); +int xfs_da_node_split (xfs_da_state_t *, xfs_da_state_blk_t *, + xfs_da_state_blk_t *, xfs_da_state_blk_t *, int, int *); +void xfs_da_node_rebalance (xfs_da_state_t *, xfs_da_state_blk_t *, + xfs_da_state_blk_t *); +void xfs_da_node_remove (xfs_da_state_t *, xfs_da_state_blk_t *); +void xfs_da_node_unbalance (xfs_da_state_t *, xfs_da_state_blk_t *, + xfs_da_state_blk_t *); +int xfs_da_node_order (xfs_dabuf_t *, xfs_dabuf_t *); +int xfs_da_node_toosmall (xfs_da_state_t *, int *); +uint xfs_da_node_lasthash (xfs_dabuf_t *, int *); +int xfs_da_do_buf (xfs_trans_t *, xfs_inode_t *, xfs_dablk_t, xfs_daddr_t *, + xfs_dabuf_t **, int, int, inst_t *); + +/* xfs_dir.c */ +int xfs_dir_node_addname (xfs_da_args_t *); +int xfs_dir_leaf_lookup (xfs_da_args_t *); +int xfs_dir_node_lookup (xfs_da_args_t *); +int xfs_dir_leaf_replace (xfs_da_args_t *); +int xfs_dir_node_replace (xfs_da_args_t *); +int xfs_dir_node_removename (xfs_da_args_t *); +int xfs_dir_leaf_removename (xfs_da_args_t *, int *, int *); + +/* xfs_dir_leaf.c */ +void xfs_dir_leaf_rebalance (xfs_da_state_t *, xfs_da_state_blk_t *, + xfs_da_state_blk_t *); +void xfs_dir_leaf_add_work (xfs_dabuf_t *, xfs_da_args_t *, int, int); +int xfs_dir_leaf_compact (xfs_trans_t *, xfs_dabuf_t *, int, int); +int xfs_dir_leaf_figure_balance (xfs_da_state_t *, xfs_da_state_blk_t *, + xfs_da_state_blk_t *, int *, int *); +void xfs_dir_leaf_moveents (xfs_dir_leafblock_t *, int, + xfs_dir_leafblock_t *, int, int, xfs_mount_t *); + +/* xfs_dir2_leaf.c */ +void xfs_dir2_leaf_check (xfs_inode_t *, xfs_dabuf_t *); +int xfs_dir2_leaf_lookup_int (xfs_da_args_t *, xfs_dabuf_t **, + int *, xfs_dabuf_t **); + +/* xfs_dir2_block.c */ +void xfs_dir2_block_log_tail (xfs_trans_t *, xfs_dabuf_t *); +void xfs_dir2_block_log_leaf (xfs_trans_t *, xfs_dabuf_t *, int, int); +int xfs_dir2_block_lookup_int (xfs_da_args_t *, xfs_dabuf_t **, int *); + +/* xfs_dir2_node.c */ +void xfs_dir2_leafn_check (xfs_inode_t *, xfs_dabuf_t *); +int xfs_dir2_leafn_remove (xfs_da_args_t *, xfs_dabuf_t *, int, + xfs_da_state_blk_t *, int *); +int xfs_dir2_node_addname_int (xfs_da_args_t *, xfs_da_state_blk_t *); + +/* xfs_dir2_sf.c */ +void xfs_dir2_sf_check (xfs_da_args_t *); +int xfs_dir2_sf_addname_pick (xfs_da_args_t *, int, + xfs_dir2_sf_entry_t **, xfs_dir2_data_aoff_t *); +void xfs_dir2_sf_addname_easy (xfs_da_args_t *, xfs_dir2_sf_entry_t *, + xfs_dir2_data_aoff_t, int); +void xfs_dir2_sf_addname_hard (xfs_da_args_t *, int, int); +void xfs_dir2_sf_toino8 (xfs_da_args_t *); +void xfs_dir2_sf_toino4 (xfs_da_args_t *); + +/* xfs_attr_leaf.c */ +void xfs_attr_leaf_rebalance (xfs_da_state_t *, xfs_da_state_blk_t *, + xfs_da_state_blk_t *); +int xfs_attr_leaf_add_work (xfs_dabuf_t *, xfs_da_args_t *, int); +void xfs_attr_leaf_compact (xfs_trans_t *, xfs_dabuf_t *); +void xfs_attr_leaf_moveents (xfs_attr_leafblock_t *, int, + xfs_attr_leafblock_t *, int, int, xfs_mount_t *); +int xfs_attr_leaf_figure_balance (xfs_da_state_t *, xfs_da_state_blk_t *, + xfs_da_state_blk_t *, int *, int *); + +/* xfs_trans_item.c */ +xfs_log_item_desc_t *xfs_trans_add_item (xfs_trans_t *, xfs_log_item_t *); +xfs_log_item_desc_t *xfs_trans_find_item (xfs_trans_t *, xfs_log_item_t *); +void xfs_trans_free_item (xfs_trans_t *, xfs_log_item_desc_t *); +void xfs_trans_free_items (xfs_trans_t *, int); + +/* xfs_trans_buf.c */ +xfs_buf_t *xfs_trans_buf_item_match (xfs_trans_t *, buftarg_t *, + xfs_daddr_t, int); +xfs_buf_t *xfs_trans_buf_item_match_all (xfs_trans_t *, buftarg_t *, + xfs_daddr_t, int); + +/* xfs_inode_item.c */ +void xfs_inode_item_init (xfs_inode_t *, xfs_mount_t *); + +/* xfs_buf_item.c */ +void xfs_buf_item_init (xfs_buf_t *, xfs_mount_t *); +void xfs_buf_item_log (xfs_buf_log_item_t *, uint, uint); + +/* local source files */ +int xfs_mod_incore_sb (xfs_mount_t *, xfs_sb_field_t, int, int); +void xfs_trans_mod_sb (xfs_trans_t *, uint, long); +int xfs_trans_unlock_chunk (xfs_log_item_chunk_t *, int, int, xfs_lsn_t); + + +#ifndef DEBUG +#define xfs_inobp_check(mp,bp) ((void) 0) +#define xfs_btree_check_key(a,b,c) ((void) 0) +#define xfs_btree_check_rec(a,b,c) ((void) 0) +#define xfs_btree_check_block(a,b,c,d) ((void) 0) +#define xfs_dir2_sf_check(args) ((void) 0) +#define xfs_dir2_leaf_check(dp,bp) ((void) 0) +#define xfs_dir2_leafn_check(dp,bp) ((void) 0) +#undef xfs_dir2_data_check +#define xfs_dir2_data_check(dp,bp) ((void) 0) +#endif diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_alloc.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_alloc.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_alloc.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_alloc.c Wed Apr 18 21:41:37 2001 @@ -0,0 +1,2350 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#define XFS_ABSDIFF(a,b) (((a) <= (b)) ? ((b) - (a)) : ((a) - (b))) +#define XFSA_FIXUP_BNO_OK 1 +#define XFSA_FIXUP_CNT_OK 2 + +/* + * Compute aligned version of the found extent. + * Takes alignment and min length into account. + */ +STATIC int /* success (>= minlen) */ +xfs_alloc_compute_aligned( + xfs_agblock_t foundbno, /* starting block in found extent */ + xfs_extlen_t foundlen, /* length in found extent */ + xfs_extlen_t alignment, /* alignment for allocation */ + xfs_extlen_t minlen, /* minimum length for allocation */ + xfs_agblock_t *resbno, /* result block number */ + xfs_extlen_t *reslen) /* result length */ +{ + xfs_agblock_t bno; + xfs_extlen_t diff; + xfs_extlen_t len; + + if (alignment > 1 && foundlen >= minlen) { + bno = roundup(foundbno, alignment); + diff = bno - foundbno; + len = diff >= foundlen ? 0 : foundlen - diff; + } else { + bno = foundbno; + len = foundlen; + } + *resbno = bno; + *reslen = len; + return len >= minlen; +} + +/* + * Compute best start block and diff for "near" allocations. + * freelen >= wantlen already checked by caller. + */ +STATIC xfs_extlen_t /* difference value (absolute) */ +xfs_alloc_compute_diff( + xfs_agblock_t wantbno, /* target starting block */ + xfs_extlen_t wantlen, /* target length */ + xfs_extlen_t alignment, /* target alignment */ + xfs_agblock_t freebno, /* freespace's starting block */ + xfs_extlen_t freelen, /* freespace's length */ + xfs_agblock_t *newbnop) /* result: best start block from free */ +{ + xfs_agblock_t freeend; /* end of freespace extent */ + xfs_agblock_t newbno1; /* return block number */ + xfs_agblock_t newbno2; /* other new block number */ + xfs_extlen_t newlen1=0; /* length with newbno1 */ + xfs_extlen_t newlen2=0; /* length with newbno2 */ + xfs_agblock_t wantend; /* end of target extent */ + + ASSERT(freelen >= wantlen); + freeend = freebno + freelen; + wantend = wantbno + wantlen; + if (freebno >= wantbno) { + if ((newbno1 = roundup(freebno, alignment)) >= freeend) + newbno1 = NULLAGBLOCK; + } else if (freeend >= wantend && alignment > 1) { + newbno1 = roundup(wantbno, alignment); + newbno2 = newbno1 - alignment; + if (newbno1 >= freeend) + newbno1 = NULLAGBLOCK; + else + newlen1 = XFS_EXTLEN_MIN(wantlen, freeend - newbno1); + if (newbno2 < freebno) + newbno2 = NULLAGBLOCK; + else + newlen2 = XFS_EXTLEN_MIN(wantlen, freeend - newbno2); + if (newbno1 != NULLAGBLOCK && newbno2 != NULLAGBLOCK) { + if (newlen1 < newlen2 || + (newlen1 == newlen2 && + XFS_ABSDIFF(newbno1, wantbno) > + XFS_ABSDIFF(newbno2, wantbno))) + newbno1 = newbno2; + } else if (newbno2 != NULLAGBLOCK) + newbno1 = newbno2; + } else if (freeend >= wantend) { + newbno1 = wantbno; + } else if (alignment > 1) { + newbno1 = roundup(freeend - wantlen, alignment); + if (newbno1 > freeend - wantlen && + newbno1 - alignment >= freebno) + newbno1 -= alignment; + else if (newbno1 >= freeend) + newbno1 = NULLAGBLOCK; + } else + newbno1 = freeend - wantlen; + *newbnop = newbno1; + return newbno1 == NULLAGBLOCK ? 0 : XFS_ABSDIFF(newbno1, wantbno); +} + +/* + * Fix up the length, based on mod and prod. + * len should be k * prod + mod for some k. + * If len is too small it is returned unchanged. + * If len hits maxlen it is left alone. + */ +STATIC void +xfs_alloc_fix_len( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_extlen_t k; + xfs_extlen_t rlen; + + ASSERT(args->mod < args->prod); + rlen = args->len; + ASSERT(rlen >= args->minlen); + ASSERT(rlen <= args->maxlen); + if (args->prod <= 1 || rlen < args->mod || rlen == args->maxlen || + (args->mod == 0 && rlen < args->prod)) + return; + k = rlen % args->prod; + if (k == args->mod) + return; + if (k > args->mod) { + if ((int)(rlen = rlen - k - args->mod) < (int)args->minlen) + return; + } else { + if ((int)(rlen = rlen - args->prod - (args->mod - k)) < + (int)args->minlen) + return; + } + ASSERT(rlen >= args->minlen); + ASSERT(rlen <= args->maxlen); + args->len = rlen; +} + +/* + * Fix up length if there is too little space left in the a.g. + * Return 1 if ok, 0 if too little, should give up. + */ +STATIC int +xfs_alloc_fix_minleft( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_agf_t *agf; /* a.g. freelist header */ + int diff; /* free space difference */ + + if (args->minleft == 0) + return 1; + agf = XFS_BUF_TO_AGF(args->agbp); + diff = INT_GET(agf->agf_freeblks, ARCH_CONVERT) + + INT_GET(agf->agf_flcount, ARCH_CONVERT) + - args->len - args->minleft; + if (diff >= 0) + return 1; + args->len += diff; /* shrink the allocated space */ + if (args->len >= args->minlen) + return 1; + args->agbno = NULLAGBLOCK; + return 0; +} + +/* + * Update the two btrees, logically removing from freespace the extent + * starting at rbno, rlen blocks. The extent is contained within the + * actual (current) free extent fbno for flen blocks. + * Flags are passed in indicating whether the cursors are set to the + * relevant records. + */ +STATIC int /* error code */ +xfs_alloc_fixup_trees( + xfs_btree_cur_t *cnt_cur, /* cursor for by-size btree */ + xfs_btree_cur_t *bno_cur, /* cursor for by-block btree */ + xfs_agblock_t fbno, /* starting block of free extent */ + xfs_extlen_t flen, /* length of free extent */ + xfs_agblock_t rbno, /* starting block of returned extent */ + xfs_extlen_t rlen, /* length of returned extent */ + int flags) /* flags, XFSA_FIXUP_... */ +{ + int error; /* error code */ + int i; /* operation results */ + xfs_agblock_t nfbno1; /* first new free startblock */ + xfs_agblock_t nfbno2; /* second new free startblock */ + xfs_extlen_t nflen1=0; /* first new free length */ + xfs_extlen_t nflen2=0; /* second new free length */ + + /* + * Look up the record in the by-size tree if necessary. + */ + if (flags & XFSA_FIXUP_CNT_OK) { +#ifdef DEBUG + if ((error = xfs_alloc_get_rec(cnt_cur, &nfbno1, &nflen1, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN( + i == 1 && nfbno1 == fbno && nflen1 == flen); +#endif + } else { + if ((error = xfs_alloc_lookup_eq(cnt_cur, fbno, flen, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } + /* + * Look up the record in the by-block tree if necessary. + */ + if (flags & XFSA_FIXUP_BNO_OK) { +#ifdef DEBUG + if ((error = xfs_alloc_get_rec(bno_cur, &nfbno1, &nflen1, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN( + i == 1 && nfbno1 == fbno && nflen1 == flen); +#endif + } else { + if ((error = xfs_alloc_lookup_eq(bno_cur, fbno, flen, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } +#ifdef DEBUG + { + xfs_alloc_block_t *bnoblock; + xfs_alloc_block_t *cntblock; + + if (bno_cur->bc_nlevels == 1 && + cnt_cur->bc_nlevels == 1) { + bnoblock = XFS_BUF_TO_ALLOC_BLOCK(bno_cur->bc_bufs[0]); + cntblock = XFS_BUF_TO_ALLOC_BLOCK(cnt_cur->bc_bufs[0]); + XFS_WANT_CORRUPTED_RETURN( + INT_GET(bnoblock->bb_numrecs, ARCH_CONVERT) == INT_GET(cntblock->bb_numrecs, ARCH_CONVERT)); + } + } +#endif + /* + * Deal with all four cases: the allocated record is contained + * within the freespace record, so we can have new freespace + * at either (or both) end, or no freespace remaining. + */ + if (rbno == fbno && rlen == flen) + nfbno1 = nfbno2 = NULLAGBLOCK; + else if (rbno == fbno) { + nfbno1 = rbno + rlen; + nflen1 = flen - rlen; + nfbno2 = NULLAGBLOCK; + } else if (rbno + rlen == fbno + flen) { + nfbno1 = fbno; + nflen1 = flen - rlen; + nfbno2 = NULLAGBLOCK; + } else { + nfbno1 = fbno; + nflen1 = rbno - fbno; + nfbno2 = rbno + rlen; + nflen2 = (fbno + flen) - nfbno2; + } + /* + * Delete the entry from the by-size btree. + */ + if ((error = xfs_alloc_delete(cnt_cur, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + /* + * Add new by-size btree entry(s). + */ + if (nfbno1 != NULLAGBLOCK) { + if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno1, nflen1, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 0); + if ((error = xfs_alloc_insert(cnt_cur, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } + if (nfbno2 != NULLAGBLOCK) { + if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno2, nflen2, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 0); + if ((error = xfs_alloc_insert(cnt_cur, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } + /* + * Fix up the by-block btree entry(s). + */ + if (nfbno1 == NULLAGBLOCK) { + /* + * No remaining freespace, just delete the by-block tree entry. + */ + if ((error = xfs_alloc_delete(bno_cur, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } else { + /* + * Update the by-block entry to start later|be shorter. + */ + if ((error = xfs_alloc_update(bno_cur, nfbno1, nflen1))) + return error; + } + if (nfbno2 != NULLAGBLOCK) { + /* + * 2 resulting free entries, need to add one. + */ + if ((error = xfs_alloc_lookup_eq(bno_cur, nfbno2, nflen2, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 0); + if ((error = xfs_alloc_insert(bno_cur, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } + return 0; +} + +/* + * Read in the allocation group free block array. + */ +STATIC int /* error */ +xfs_alloc_read_agfl( + xfs_mount_t *mp, /* mount point structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_buf_t **bpp) /* buffer for the ag free block array */ +{ + xfs_buf_t *bp; /* return value */ + xfs_daddr_t d; /* disk block address */ + int error; + + ASSERT(agno != NULLAGNUMBER); + d = XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, 1, 0, &bp))) + return error; + ASSERT(bp); + ASSERT(!XFS_BUF_GETERROR(bp)); + XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGFL, XFS_AGFL_REF); + *bpp = bp; + return 0; +} + +#if defined(XFS_ALLOC_TRACE) +/* + * Add an allocation trace entry for an alloc call. + */ +STATIC void +xfs_alloc_trace_alloc( + char *name, /* function tag string */ + char *str, /* additional string */ + xfs_alloc_arg_t *args, /* allocation argument structure */ + int line) /* source line number */ +{ + ktrace_enter(xfs_alloc_trace_buf, + (void *)(__psint_t)(XFS_ALLOC_KTRACE_ALLOC | (line << 16)), + (void *)name, + (void *)str, + (void *)args->mp, + (void *)(__psunsigned_t)args->agno, + (void *)(__psunsigned_t)args->agbno, + (void *)(__psunsigned_t)args->minlen, + (void *)(__psunsigned_t)args->maxlen, + (void *)(__psunsigned_t)args->mod, + (void *)(__psunsigned_t)args->prod, + (void *)(__psunsigned_t)args->minleft, + (void *)(__psunsigned_t)args->total, + (void *)(__psunsigned_t)args->alignment, + (void *)(__psunsigned_t)args->len, + (void *)((((__psint_t)args->type) << 16) | + (__psint_t)args->otype), + (void *)(__psint_t)((args->wasdel << 3) | + (args->wasfromfl << 2) | + (args->isfl << 1) | + (args->userdata << 0))); +} + +/* + * Add an allocation trace entry for a free call. + */ +STATIC void +xfs_alloc_trace_free( + char *name, /* function tag string */ + char *str, /* additional string */ + xfs_mount_t *mp, /* file system mount point */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* a.g. relative block number */ + xfs_extlen_t len, /* length of extent */ + int isfl, /* set if is freelist allocation/free */ + int line) /* source line number */ +{ + ktrace_enter(xfs_alloc_trace_buf, + (void *)(__psint_t)(XFS_ALLOC_KTRACE_FREE | (line << 16)), + (void *)name, + (void *)str, + (void *)mp, + (void *)(__psunsigned_t)agno, + (void *)(__psunsigned_t)agbno, + (void *)(__psunsigned_t)len, + (void *)(__psint_t)isfl, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); +} + +/* + * Add an allocation trace entry for modifying an agf. + */ +STATIC void +xfs_alloc_trace_modagf( + char *name, /* function tag string */ + char *str, /* additional string */ + xfs_mount_t *mp, /* file system mount point */ + xfs_agf_t *agf, /* new agf value */ + int flags, /* logging flags for agf */ + int line) /* source line number */ +{ + ktrace_enter(xfs_alloc_trace_buf, + (void *)(__psint_t)(XFS_ALLOC_KTRACE_MODAGF | (line << 16)), + (void *)name, + (void *)str, + (void *)mp, + (void *)(__psint_t)flags, + (void *)(__psunsigned_t)INT_GET(agf->agf_seqno, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_length, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_roots[XFS_BTNUM_BNO], + ARCH_CONVERT); + (void *)(__psunsigned_t)INT_GET(agf->agf_roots[XFS_BTNUM_CNT], + ARCH_CONVERT); + (void *)(__psunsigned_t)INT_GET(agf->agf_levels[XFS_BTNUM_BNO], + ARCH_CONVERT); + (void *)(__psunsigned_t)INT_GET(agf->agf_levels[XFS_BTNUM_CNT], + ARCH_CONVERT); + (void *)(__psunsigned_t)INT_GET(agf->agf_flfirst, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_fllast, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_flcount, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_freeblks, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_longest, ARCH_CONVERT)); +} +#endif /* XFS_ALLOC_TRACE */ + +/* + * Allocation group level functions. + */ + +/* + * Allocate a variable extent in the allocation group agno. + * Type and bno are used to determine where in the allocation group the + * extent will start. + * Extent's length (returned in *len) will be between minlen and maxlen, + * and of the form k * prod + mod unless there's nothing that large. + * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. + */ +STATIC int /* error */ +xfs_alloc_ag_vextent( + xfs_alloc_arg_t *args) /* argument structure for allocation */ +{ + int error=0; +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_ag_vextent"; +#endif + + ASSERT(args->minlen > 0); + ASSERT(args->maxlen > 0); + ASSERT(args->minlen <= args->maxlen); + ASSERT(args->mod < args->prod); + ASSERT(args->alignment > 0); + /* + * Branch to correct routine based on the type. + */ + args->wasfromfl = 0; + switch (args->type) { + case XFS_ALLOCTYPE_THIS_AG: + error = xfs_alloc_ag_vextent_size(args); + break; + case XFS_ALLOCTYPE_NEAR_BNO: + error = xfs_alloc_ag_vextent_near(args); + break; + case XFS_ALLOCTYPE_THIS_BNO: + error = xfs_alloc_ag_vextent_exact(args); + break; + default: + ASSERT(0); + /* NOTREACHED */ + } + if (error) + return error; + /* + * If the allocation worked, need to change the agf structure + * (and log it), and the superblock. + */ + if (args->agbno != NULLAGBLOCK) { + xfs_agf_t *agf; /* allocation group freelist header */ +#ifdef XFS_ALLOC_TRACE + xfs_mount_t *mp = args->mp; +#endif + long slen = (long)args->len; + + ASSERT(args->len >= args->minlen && args->len <= args->maxlen); + ASSERT(!(args->wasfromfl) || !args->isfl); + ASSERT(args->agbno % args->alignment == 0); + if (!(args->wasfromfl)) { + + agf = XFS_BUF_TO_AGF(args->agbp); + INT_MOD(agf->agf_freeblks, ARCH_CONVERT, -(args->len)); + xfs_trans_agblocks_delta(args->tp, + -((long)(args->len))); + args->pag->pagf_freeblks -= args->len; + ASSERT(INT_GET(agf->agf_freeblks, ARCH_CONVERT) + <= INT_GET(agf->agf_length, ARCH_CONVERT)); + TRACE_MODAGF(NULL, agf, XFS_AGF_FREEBLKS); + xfs_alloc_log_agf(args->tp, args->agbp, + XFS_AGF_FREEBLKS); + } + if (!args->isfl) + xfs_trans_mod_sb(args->tp, + args->wasdel ? XFS_TRANS_SB_RES_FDBLOCKS : + XFS_TRANS_SB_FDBLOCKS, -slen); + XFS_STATS_INC(xfsstats.xs_allocx); + XFS_STATS_ADD(xfsstats.xs_allocb, args->len); + } + return 0; +} + +/* + * Allocate a variable extent at exactly agno/bno. + * Extent's length (returned in *len) will be between minlen and maxlen, + * and of the form k * prod + mod unless there's nothing that large. + * Return the starting a.g. block (bno), or NULLAGBLOCK if we can't do it. + */ +STATIC int /* error */ +xfs_alloc_ag_vextent_exact( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_btree_cur_t *bno_cur;/* by block-number btree cursor */ + xfs_btree_cur_t *cnt_cur;/* by count btree cursor */ + xfs_agblock_t end; /* end of allocated extent */ + int error; + xfs_agblock_t fbno; /* start block of found extent */ + xfs_agblock_t fend; /* end block of found extent */ + xfs_extlen_t flen; /* length of found extent */ +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_ag_vextent_exact"; +#endif + int i; /* success/failure of operation */ + xfs_agblock_t maxend; /* end of maximal extent */ + xfs_agblock_t minend; /* end of minimal extent */ + xfs_extlen_t rlen; /* length of returned extent */ + + ASSERT(args->alignment == 1); + /* + * Allocate/initialize a cursor for the by-number freespace btree. + */ + bno_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_BNO, 0, 0); + /* + * Lookup bno and minlen in the btree (minlen is irrelevant, really). + * Look for the closest free block <= bno, it must contain bno + * if any free block does. + */ + if ((error = xfs_alloc_lookup_le(bno_cur, args->agbno, args->minlen, &i))) + goto error0; + if (!i) { + /* + * Didn't find it, return null. + */ + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + args->agbno = NULLAGBLOCK; + return 0; + } + /* + * Grab the freespace record. + */ + if ((error = xfs_alloc_get_rec(bno_cur, &fbno, &flen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + ASSERT(fbno <= args->agbno); + minend = args->agbno + args->minlen; + maxend = args->agbno + args->maxlen; + fend = fbno + flen; + /* + * Give up if the freespace isn't long enough for the minimum request. + */ + if (fend < minend) { + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + args->agbno = NULLAGBLOCK; + return 0; + } + /* + * End of extent will be smaller of the freespace end and the + * maximal requested end. + */ + end = XFS_AGBLOCK_MIN(fend, maxend); + /* + * Fix the length according to mod and prod if given. + */ + args->len = end - args->agbno; + xfs_alloc_fix_len(args); + if (!xfs_alloc_fix_minleft(args)) { + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + return 0; + } + rlen = args->len; + ASSERT(args->agbno + rlen <= fend); + end = args->agbno + rlen; + /* + * We are allocating agbno for rlen [agbno .. end] + * Allocate/initialize a cursor for the by-size btree. + */ + cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_CNT, 0, 0); + ASSERT(args->agbno + args->len <= + INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, + ARCH_CONVERT)); + if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, + args->agbno, args->len, XFSA_FIXUP_BNO_OK))) { + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); + goto error0; + } + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + TRACE_ALLOC("normal", args); + args->wasfromfl = 0; + return 0; + +error0: + xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); + TRACE_ALLOC("error", args); + return error; +} + +/* + * Allocate a variable extent near bno in the allocation group agno. + * Extent's length (returned in len) will be between minlen and maxlen, + * and of the form k * prod + mod unless there's nothing that large. + * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. + */ +STATIC int /* error */ +xfs_alloc_ag_vextent_near( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_btree_cur_t *bno_cur_gt; /* cursor for bno btree, right side */ + xfs_btree_cur_t *bno_cur_lt; /* cursor for bno btree, left side */ + xfs_btree_cur_t *cnt_cur; /* cursor for count btree */ +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_ag_vextent_near"; +#endif + xfs_agblock_t gtbno; /* start bno of right side entry */ + xfs_agblock_t gtbnoa; /* aligned ... */ + xfs_extlen_t gtdiff; /* difference to right side entry */ + xfs_extlen_t gtlen; /* length of right side entry */ + xfs_extlen_t gtlena; /* aligned ... */ + xfs_agblock_t gtnew; /* useful start bno of right side */ + int error; /* error code */ + int i; /* result code, temporary */ + int j; /* result code, temporary */ + xfs_agblock_t ltbno; /* start bno of left side entry */ + xfs_agblock_t ltbnoa; /* aligned ... */ + xfs_extlen_t ltdiff; /* difference to left side entry */ + /*REFERENCED*/ + xfs_agblock_t ltend; /* end bno of left side entry */ + xfs_extlen_t ltlen; /* length of left side entry */ + xfs_extlen_t ltlena; /* aligned ... */ + xfs_agblock_t ltnew; /* useful start bno of left side */ + xfs_extlen_t rlen; /* length of returned extent */ +#if defined(DEBUG) && defined(__KERNEL__) + /* + * Randomly don't execute the first algorithm. + */ + static int seed; /* randomizing seed value */ + int dofirst; /* set to do first algorithm */ + timespec_t now; /* current time */ + + if (!seed) { + nanotime(&now); + seed = (int)now.tv_sec ^ (int)now.tv_nsec; + } + dofirst = random() & 1; +#endif + /* + * Get a cursor for the by-size btree. + */ + cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_CNT, 0, 0); + ltlen = 0; + bno_cur_lt = bno_cur_gt = NULL; + /* + * See if there are any free extents as big as maxlen. + */ + if ((error = xfs_alloc_lookup_ge(cnt_cur, 0, args->maxlen, &i))) + goto error0; + /* + * If none, then pick up the last entry in the tree unless the + * tree is empty. + */ + if (!i) { + if ((error = xfs_alloc_ag_vextent_small(args, cnt_cur, <bno, + <len, &i))) + goto error0; + if (i == 0 || ltlen == 0) { + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + return 0; + } + ASSERT(i == 1); + } + args->wasfromfl = 0; + /* + * First algorithm. + * If the requested extent is large wrt the freespaces available + * in this a.g., then the cursor will be pointing to a btree entry + * near the right edge of the tree. If it's in the last btree leaf + * block, then we just examine all the entries in that block + * that are big enough, and pick the best one. + * This is written as a while loop so we can break out of it, + * but we never loop back to the top. + */ + while (xfs_btree_islastblock(cnt_cur, 0)) { + xfs_extlen_t bdiff; + int besti=0; + xfs_extlen_t blen=0; + xfs_agblock_t bnew=0; + +#if defined(DEBUG) && defined(__KERNEL__) + if (!dofirst) + break; +#endif + /* + * Start from the entry that lookup found, sequence through + * all larger free blocks. If we're actually pointing at a + * record smaller than maxlen, go to the start of this block, + * and skip all those smaller than minlen. + */ + if (ltlen || args->alignment > 1) { + cnt_cur->bc_ptrs[0] = 1; + do { + if ((error = xfs_alloc_get_rec(cnt_cur, <bno, + <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (ltlen >= args->minlen) + break; + if ((error = xfs_alloc_increment(cnt_cur, 0, &i))) + goto error0; + } while (i); + ASSERT(ltlen >= args->minlen); + if (!i) + break; + } + i = cnt_cur->bc_ptrs[0]; + for (j = 1, blen = 0, bdiff = 0; + !error && j && (blen < args->maxlen || bdiff > 0); + error = xfs_alloc_increment(cnt_cur, 0, &j)) { + /* + * For each entry, decide if it's better than + * the previous best entry. + */ + if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (!xfs_alloc_compute_aligned(ltbno, ltlen, + args->alignment, args->minlen, + <bnoa, <lena)) + continue; + args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); + xfs_alloc_fix_len(args); + ASSERT(args->len >= args->minlen); + if (args->len < blen) + continue; + ltdiff = xfs_alloc_compute_diff(args->agbno, args->len, + args->alignment, ltbno, ltlen, <new); + if (ltnew != NULLAGBLOCK && + (args->len > blen || ltdiff < bdiff)) { + bdiff = ltdiff; + bnew = ltnew; + blen = args->len; + besti = cnt_cur->bc_ptrs[0]; + } + } + /* + * It didn't work. We COULD be in a case where + * there's a good record somewhere, so try again. + */ + if (blen == 0) + break; + /* + * Point at the best entry, and retrieve it again. + */ + cnt_cur->bc_ptrs[0] = besti; + if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + ltend = ltbno + ltlen; + ASSERT(ltend <= INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, + ARCH_CONVERT)); + args->len = blen; + if (!xfs_alloc_fix_minleft(args)) { + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + TRACE_ALLOC("nominleft", args); + return 0; + } + blen = args->len; + /* + * We are allocating starting at bnew for blen blocks. + */ + args->agbno = bnew; + ASSERT(bnew >= ltbno); + ASSERT(bnew + blen <= ltend); + /* + * Set up a cursor for the by-bno tree. + */ + bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp, + args->agbp, args->agno, XFS_BTNUM_BNO, 0, 0); + /* + * Fix up the btree entries. + */ + if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, + ltlen, bnew, blen, XFSA_FIXUP_CNT_OK))) + goto error0; + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); + TRACE_ALLOC("first", args); + return 0; + } + /* + * Second algorithm. + * Search in the by-bno tree to the left and to the right + * simultaneously, until in each case we find a space big enough, + * or run into the edge of the tree. When we run into the edge, + * we deallocate that cursor. + * If both searches succeed, we compare the two spaces and pick + * the better one. + * With alignment, it's possible for both to fail; the upper + * level algorithm that picks allocation groups for allocations + * is not supposed to do this. + */ + /* + * Allocate and initialize the cursor for the leftward search. + */ + bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_BNO, 0, 0); + /* + * Lookup <= bno to find the leftward search's starting point. + */ + if ((error = xfs_alloc_lookup_le(bno_cur_lt, args->agbno, args->maxlen, &i))) + goto error0; + if (!i) { + /* + * Didn't find anything; use this cursor for the rightward + * search. + */ + bno_cur_gt = bno_cur_lt; + bno_cur_lt = 0; + } + /* + * Found something. Duplicate the cursor for the rightward search. + */ + else if ((error = xfs_btree_dup_cursor(bno_cur_lt, &bno_cur_gt))) + goto error0; + /* + * Increment the cursor, so we will point at the entry just right + * of the leftward entry if any, or to the leftmost entry. + */ + if ((error = xfs_alloc_increment(bno_cur_gt, 0, &i))) + goto error0; + if (!i) { + /* + * It failed, there are no rightward entries. + */ + xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + } + /* + * Loop going left with the leftward cursor, right with the + * rightward cursor, until either both directions give up or + * we find an entry at least as big as minlen. + */ + do { + if (bno_cur_lt) { + if ((error = xfs_alloc_get_rec(bno_cur_lt, <bno, <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (xfs_alloc_compute_aligned(ltbno, ltlen, + args->alignment, args->minlen, + <bnoa, <lena)) + break; + if ((error = xfs_alloc_decrement(bno_cur_lt, 0, &i))) + goto error0; + if (!i) { + xfs_btree_del_cursor(bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + } + } + if (bno_cur_gt) { + if ((error = xfs_alloc_get_rec(bno_cur_gt, >bno, >len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (xfs_alloc_compute_aligned(gtbno, gtlen, + args->alignment, args->minlen, + >bnoa, >lena)) + break; + if ((error = xfs_alloc_increment(bno_cur_gt, 0, &i))) + goto error0; + if (!i) { + xfs_btree_del_cursor(bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + } + } + } while (bno_cur_lt || bno_cur_gt); + /* + * Got both cursors still active, need to find better entry. + */ + if (bno_cur_lt && bno_cur_gt) { + /* + * Left side is long enough, look for a right side entry. + */ + if (ltlena >= args->minlen) { + /* + * Fix up the length. + */ + args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); + xfs_alloc_fix_len(args); + rlen = args->len; + ltdiff = xfs_alloc_compute_diff(args->agbno, rlen, + args->alignment, ltbno, ltlen, <new); + /* + * Not perfect. + */ + if (ltdiff) { + /* + * Look until we find a better one, run out of + * space, or run off the end. + */ + while (bno_cur_lt && bno_cur_gt) { + if ((error = xfs_alloc_get_rec( + bno_cur_gt, >bno, + >len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + xfs_alloc_compute_aligned(gtbno, gtlen, + args->alignment, args->minlen, + >bnoa, >lena); + /* + * The left one is clearly better. + */ + if (gtbnoa >= args->agbno + ltdiff) { + xfs_btree_del_cursor( + bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + break; + } + /* + * If we reach a big enough entry, + * compare the two and pick the best. + */ + if (gtlena >= args->minlen) { + args->len = + XFS_EXTLEN_MIN(gtlena, + args->maxlen); + xfs_alloc_fix_len(args); + rlen = args->len; + gtdiff = xfs_alloc_compute_diff( + args->agbno, rlen, + args->alignment, + gtbno, gtlen, >new); + /* + * Right side is better. + */ + if (gtdiff < ltdiff) { + xfs_btree_del_cursor( + bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + } + /* + * Left side is better. + */ + else { + xfs_btree_del_cursor( + bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + } + break; + } + /* + * Fell off the right end. + */ + if ((error = xfs_alloc_increment( + bno_cur_gt, 0, &i))) + goto error0; + if (!i) { + xfs_btree_del_cursor( + bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + break; + } + } + } + /* + * The left side is perfect, trash the right side. + */ + else { + xfs_btree_del_cursor(bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + } + } + /* + * It's the right side that was found first, look left. + */ + else { + /* + * Fix up the length. + */ + args->len = XFS_EXTLEN_MIN(gtlena, args->maxlen); + xfs_alloc_fix_len(args); + rlen = args->len; + gtdiff = xfs_alloc_compute_diff(args->agbno, rlen, + args->alignment, gtbno, gtlen, >new); + /* + * Right side entry isn't perfect. + */ + if (gtdiff) { + /* + * Look until we find a better one, run out of + * space, or run off the end. + */ + while (bno_cur_lt && bno_cur_gt) { + if ((error = xfs_alloc_get_rec( + bno_cur_lt, <bno, + <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + xfs_alloc_compute_aligned(ltbno, ltlen, + args->alignment, args->minlen, + <bnoa, <lena); + /* + * The right one is clearly better. + */ + if (ltbnoa <= args->agbno - gtdiff) { + xfs_btree_del_cursor( + bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + break; + } + /* + * If we reach a big enough entry, + * compare the two and pick the best. + */ + if (ltlena >= args->minlen) { + args->len = XFS_EXTLEN_MIN( + ltlena, args->maxlen); + xfs_alloc_fix_len(args); + rlen = args->len; + ltdiff = xfs_alloc_compute_diff( + args->agbno, rlen, + args->alignment, + ltbno, ltlen, <new); + /* + * Left side is better. + */ + if (ltdiff < gtdiff) { + xfs_btree_del_cursor( + bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + } + /* + * Right side is better. + */ + else { + xfs_btree_del_cursor( + bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + } + break; + } + /* + * Fell off the left end. + */ + if ((error = xfs_alloc_decrement( + bno_cur_lt, 0, &i))) + goto error0; + if (!i) { + xfs_btree_del_cursor(bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + break; + } + } + } + /* + * The right side is perfect, trash the left side. + */ + else { + xfs_btree_del_cursor(bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + } + } + } + /* + * If we couldn't get anything, give up. + */ + if (bno_cur_lt == NULL && bno_cur_gt == NULL) { + TRACE_ALLOC("neither", args); + args->agbno = NULLAGBLOCK; + return 0; + } + /* + * At this point we have selected a freespace entry, either to the + * left or to the right. If it's on the right, copy all the + * useful variables to the "left" set so we only have one + * copy of this code. + */ + if (bno_cur_gt) { + bno_cur_lt = bno_cur_gt; + bno_cur_gt = NULL; + ltbno = gtbno; + ltbnoa = gtbnoa; + ltlen = gtlen; + ltlena = gtlena; + j = 1; + } else + j = 0; + /* + * Fix up the length and compute the useful address. + */ + ltend = ltbno + ltlen; + args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); + xfs_alloc_fix_len(args); + if (!xfs_alloc_fix_minleft(args)) { + TRACE_ALLOC("nominleft", args); + xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + return 0; + } + rlen = args->len; + (void)xfs_alloc_compute_diff(args->agbno, rlen, args->alignment, ltbno, + ltlen, <new); + ASSERT(ltnew >= ltbno); + ASSERT(ltnew + rlen <= ltend); + ASSERT(ltnew + rlen <= INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, + ARCH_CONVERT)); + args->agbno = ltnew; + if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, ltlen, + ltnew, rlen, XFSA_FIXUP_BNO_OK))) + goto error0; + TRACE_ALLOC(j ? "gt" : "lt", args); + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); + return 0; + + error0: + TRACE_ALLOC("error", args); + if (cnt_cur != NULL) + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); + if (bno_cur_lt != NULL) + xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_ERROR); + if (bno_cur_gt != NULL) + xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_ERROR); + return error; +} + +/* + * Allocate a variable extent anywhere in the allocation group agno. + * Extent's length (returned in len) will be between minlen and maxlen, + * and of the form k * prod + mod unless there's nothing that large. + * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. + */ +STATIC int /* error */ +xfs_alloc_ag_vextent_size( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_btree_cur_t *bno_cur; /* cursor for bno btree */ + xfs_btree_cur_t *cnt_cur; /* cursor for cnt btree */ + int error; /* error result */ + xfs_agblock_t fbno; /* start of found freespace */ + xfs_extlen_t flen; /* length of found freespace */ +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_ag_vextent_size"; +#endif + int i; /* temp status variable */ + xfs_agblock_t rbno; /* returned block number */ + xfs_extlen_t rlen; /* length of returned extent */ + + /* + * Allocate and initialize a cursor for the by-size btree. + */ + cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_CNT, 0, 0); + bno_cur = NULL; + /* + * Look for an entry >= maxlen+alignment-1 blocks. + */ + if ((error = xfs_alloc_lookup_ge(cnt_cur, 0, + args->maxlen + args->alignment - 1, &i))) + goto error0; + /* + * If none, then pick up the last entry in the tree unless the + * tree is empty. + */ + if (!i) { + if ((error = xfs_alloc_ag_vextent_small(args, cnt_cur, &fbno, + &flen, &i))) + goto error0; + if (i == 0 || flen == 0) { + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + TRACE_ALLOC("noentry", args); + return 0; + } + ASSERT(i == 1); + } + /* + * There's a freespace as big as maxlen+alignment-1, get it. + */ + else { + if ((error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + /* + * In the first case above, we got the last entry in the + * by-size btree. Now we check to see if the space hits maxlen + * once aligned; if not, we search left for something better. + * This can't happen in the second case above. + */ + xfs_alloc_compute_aligned(fbno, flen, args->alignment, args->minlen, + &rbno, &rlen); + rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); + XFS_WANT_CORRUPTED_GOTO(rlen == 0 || + (rlen <= flen && rbno + rlen <= fbno + flen), error0); + if (rlen < args->maxlen) { + xfs_agblock_t bestfbno; + xfs_extlen_t bestflen; + xfs_agblock_t bestrbno; + xfs_extlen_t bestrlen; + + bestrlen = rlen; + bestrbno = rbno; + bestflen = flen; + bestfbno = fbno; + for (;;) { + if ((error = xfs_alloc_decrement(cnt_cur, 0, &i))) + goto error0; + if (i == 0) + break; + if ((error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, + &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (flen < bestrlen) + break; + xfs_alloc_compute_aligned(fbno, flen, args->alignment, + args->minlen, &rbno, &rlen); + rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); + XFS_WANT_CORRUPTED_GOTO(rlen == 0 || + (rlen <= flen && rbno + rlen <= fbno + flen), + error0); + if (rlen > bestrlen) { + bestrlen = rlen; + bestrbno = rbno; + bestflen = flen; + bestfbno = fbno; + if (rlen == args->maxlen) + break; + } + } + if ((error = xfs_alloc_lookup_eq(cnt_cur, bestfbno, bestflen, + &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + rlen = bestrlen; + rbno = bestrbno; + flen = bestflen; + fbno = bestfbno; + } + args->wasfromfl = 0; + /* + * Fix up the length. + */ + args->len = rlen; + xfs_alloc_fix_len(args); + if (rlen < args->minlen || !xfs_alloc_fix_minleft(args)) { + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + TRACE_ALLOC("nominleft", args); + args->agbno = NULLAGBLOCK; + return 0; + } + rlen = args->len; + XFS_WANT_CORRUPTED_GOTO(rlen <= flen, error0); + /* + * Allocate and initialize a cursor for the by-block tree. + */ + bno_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_BNO, 0, 0); + if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, + rbno, rlen, XFSA_FIXUP_CNT_OK))) + goto error0; + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + cnt_cur = bno_cur = NULL; + args->len = rlen; + args->agbno = rbno; + XFS_WANT_CORRUPTED_GOTO( + args->agbno + args->len <= + INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, + ARCH_CONVERT), + error0); + TRACE_ALLOC("normal", args); + return 0; + +error0: + TRACE_ALLOC("error", args); + if (cnt_cur) + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); + if (bno_cur) + xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Deal with the case where only small freespaces remain. + * Either return the contents of the last freespace record, + * or allocate space from the freelist if there is nothing in the tree. + */ +STATIC int /* error */ +xfs_alloc_ag_vextent_small( + xfs_alloc_arg_t *args, /* allocation argument structure */ + xfs_btree_cur_t *ccur, /* by-size cursor */ + xfs_agblock_t *fbnop, /* result block number */ + xfs_extlen_t *flenp, /* result length */ + int *stat) /* status: 0-freelist, 1-normal/none */ +{ + int error; + xfs_agblock_t fbno; + xfs_extlen_t flen; +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_ag_vextent_small"; +#endif + int i; + + if ((error = xfs_alloc_decrement(ccur, 0, &i))) + goto error0; + if (i) { + if ((error = xfs_alloc_get_rec(ccur, &fbno, &flen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + /* + * Nothing in the btree, try the freelist. Make sure + * to respect minleft even when pulling from the + * freelist. + */ + else if (args->minlen == 1 && args->alignment == 1 && !args->isfl && + (INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_flcount, + ARCH_CONVERT) > args->minleft)) { + if ((error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno))) + goto error0; + if (fbno != NULLAGBLOCK) { + if (args->userdata) { + xfs_buf_t *bp; + + bp = xfs_btree_get_bufs(args->mp, args->tp, + args->agno, fbno, 0); + xfs_trans_binval(args->tp, bp); + /* + * Since blocks move to the free list without + * the coordination used in xfs_bmap_finish, + * we can't allow the user to write to the + * block until we know that the transaction + * that moved it to the free list is + * permanently on disk. The only way to + * ensure that is to make this transaction + * synchronous. + */ + xfs_trans_set_sync(args->tp); + } + args->len = 1; + args->agbno = fbno; + XFS_WANT_CORRUPTED_GOTO( + args->agbno + args->len <= + INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, + ARCH_CONVERT), + error0); + args->wasfromfl = 1; + TRACE_ALLOC("freelist", args); + *stat = 0; + return 0; + } + /* + * Nothing in the freelist. + */ + else + flen = 0; + } + /* + * Can't allocate from the freelist for some reason. + */ + else + flen = 0; + /* + * Can't do the allocation, give up. + */ + if (flen < args->minlen) { + args->agbno = NULLAGBLOCK; + TRACE_ALLOC("notenough", args); + flen = 0; + } + *fbnop = fbno; + *flenp = flen; + *stat = 1; + TRACE_ALLOC("normal", args); + return 0; + +error0: + TRACE_ALLOC("error", args); + return error; +} + +/* + * Free the extent starting at agno/bno for length. + */ +STATIC int /* error */ +xfs_free_ag_extent( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* buffer for a.g. freelist header */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t bno, /* starting block number */ + xfs_extlen_t len, /* length of extent */ + int isfl) /* set if is freelist blocks - no sb acctg */ +{ + xfs_btree_cur_t *bno_cur; /* cursor for by-block btree */ + xfs_btree_cur_t *cnt_cur; /* cursor for by-size btree */ + int error; /* error return value */ +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_free_ag_extent"; +#endif + xfs_agblock_t gtbno; /* start of right neighbor block */ + xfs_extlen_t gtlen; /* length of right neighbor block */ + int haveleft; /* have a left neighbor block */ + int haveright; /* have a right neighbor block */ + int i; /* temp, result code */ + xfs_agblock_t ltbno; /* start of left neighbor block */ + xfs_extlen_t ltlen; /* length of left neighbor block */ + xfs_mount_t *mp; /* mount point struct for filesystem */ + xfs_agblock_t nbno; /* new starting block of freespace */ + xfs_extlen_t nlen; /* new length of freespace */ + + mp = tp->t_mountp; + /* + * Allocate and initialize a cursor for the by-block btree. + */ + bno_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO, 0, + 0); + cnt_cur = NULL; + /* + * Look for a neighboring block on the left (lower block numbers) + * that is contiguous with this space. + */ + if ((error = xfs_alloc_lookup_le(bno_cur, bno, len, &haveleft))) + goto error0; + if (haveleft) { + /* + * There is a block to our left. + */ + if ((error = xfs_alloc_get_rec(bno_cur, <bno, <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * It's not contiguous, though. + */ + if (ltbno + ltlen < bno) + haveleft = 0; + else { + /* + * If this failure happens the request to free this + * space was invalid, it's (partly) already free. + * Very bad. + */ + XFS_WANT_CORRUPTED_GOTO(ltbno + ltlen <= bno, error0); + } + } + /* + * Look for a neighboring block on the right (higher block numbers) + * that is contiguous with this space. + */ + if ((error = xfs_alloc_increment(bno_cur, 0, &haveright))) + goto error0; + if (haveright) { + /* + * There is a block to our right. + */ + if ((error = xfs_alloc_get_rec(bno_cur, >bno, >len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * It's not contiguous, though. + */ + if (bno + len < gtbno) + haveright = 0; + else { + /* + * If this failure happens the request to free this + * space was invalid, it's (partly) already free. + * Very bad. + */ + XFS_WANT_CORRUPTED_GOTO(gtbno >= bno + len, error0); + } + } + /* + * Now allocate and initialize a cursor for the by-size tree. + */ + cnt_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT, 0, + 0); + /* + * Have both left and right contiguous neighbors. + * Merge all three into a single free block. + */ + if (haveleft && haveright) { + /* + * Delete the old by-size entry on the left. + */ + if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_delete(cnt_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Delete the old by-size entry on the right. + */ + if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_delete(cnt_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Delete the old by-block entry for the right block. + */ + if ((error = xfs_alloc_delete(bno_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Move the by-block cursor back to the left neighbor. + */ + if ((error = xfs_alloc_decrement(bno_cur, 0, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); +#ifdef DEBUG + /* + * Check that this is the right record: delete didn't + * mangle the cursor. + */ + { + xfs_agblock_t xxbno; + xfs_extlen_t xxlen; + + if ((error = xfs_alloc_get_rec(bno_cur, &xxbno, &xxlen, + &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO( + i == 1 && xxbno == ltbno && xxlen == ltlen, + error0); + } +#endif + /* + * Update remaining by-block entry to the new, joined block. + */ + nbno = ltbno; + nlen = len + ltlen + gtlen; + if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) + goto error0; + } + /* + * Have only a left contiguous neighbor. + * Merge it together with the new freespace. + */ + else if (haveleft) { + /* + * Delete the old by-size entry on the left. + */ + if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_delete(cnt_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Back up the by-block cursor to the left neighbor, and + * update its length. + */ + if ((error = xfs_alloc_decrement(bno_cur, 0, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + nbno = ltbno; + nlen = len + ltlen; + if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) + goto error0; + } + /* + * Have only a right contiguous neighbor. + * Merge it together with the new freespace. + */ + else if (haveright) { + /* + * Delete the old by-size entry on the right. + */ + if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_delete(cnt_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Update the starting block and length of the right + * neighbor in the by-block tree. + */ + nbno = bno; + nlen = len + gtlen; + if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) + goto error0; + } + /* + * No contiguous neighbors. + * Insert the new freespace into the by-block tree. + */ + else { + nbno = bno; + nlen = len; + if ((error = xfs_alloc_insert(bno_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + bno_cur = NULL; + /* + * In all cases we need to insert the new freespace in the by-size tree. + */ + if ((error = xfs_alloc_lookup_eq(cnt_cur, nbno, nlen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 0, error0); + if ((error = xfs_alloc_insert(cnt_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + cnt_cur = NULL; + /* + * Update the freespace totals in the ag and superblock. + */ + { + xfs_agf_t *agf; + xfs_perag_t *pag; /* per allocation group data */ + + agf = XFS_BUF_TO_AGF(agbp); + pag = &mp->m_perag[agno]; + INT_MOD(agf->agf_freeblks, ARCH_CONVERT, len); + xfs_trans_agblocks_delta(tp, len); + pag->pagf_freeblks += len; + XFS_WANT_CORRUPTED_GOTO( + INT_GET(agf->agf_freeblks, ARCH_CONVERT) + <= INT_GET(agf->agf_length, ARCH_CONVERT), + error0); + TRACE_MODAGF(NULL, agf, XFS_AGF_FREEBLKS); + xfs_alloc_log_agf(tp, agbp, XFS_AGF_FREEBLKS); + if (!isfl) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (long)len); + XFS_STATS_INC(xfsstats.xs_freex); + XFS_STATS_ADD(xfsstats.xs_freeb, len); + } + TRACE_FREE(haveleft ? + (haveright ? "both" : "left") : + (haveright ? "right" : "none"), + agno, bno, len, isfl); + return 0; + + error0: + TRACE_FREE("error", agno, bno, len, isfl); + if (bno_cur) + xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); + if (cnt_cur) + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Visible (exported) allocation/free functions. + * Some of these are used just by xfs_alloc_btree.c and this file. + */ + +/* + * Compute and fill in value of m_ag_maxlevels. + */ +void +xfs_alloc_compute_maxlevels( + xfs_mount_t *mp) /* file system mount structure */ +{ + int level; + uint maxblocks; + uint maxleafents; + int minleafrecs; + int minnoderecs; + + maxleafents = (mp->m_sb.sb_agblocks + 1) / 2; + minleafrecs = mp->m_alloc_mnr[0]; + minnoderecs = mp->m_alloc_mnr[1]; + maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; + for (level = 1; maxblocks > 1; level++) + maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; + mp->m_ag_maxlevels = level; +} + +/* + * Decide whether to use this allocation group for this allocation. + * If so, fix up the btree freelist's size. + * This is external so mkfs can call it, too. + */ +int /* error */ +xfs_alloc_fix_freelist( + xfs_alloc_arg_t *args, /* allocation argument structure */ + int flags) /* XFS_ALLOC_FLAG_... */ +{ + xfs_buf_t *agbp; /* agf buffer pointer */ + xfs_agf_t *agf; /* a.g. freespace structure pointer */ + xfs_buf_t *agflbp;/* agfl buffer pointer */ + xfs_agblock_t bno; /* freelist block */ + xfs_extlen_t delta; /* new blocks needed in freelist */ + int error; /* error result code */ + xfs_extlen_t longest;/* longest extent in allocation group */ + xfs_mount_t *mp; /* file system mount point structure */ + xfs_extlen_t need; /* total blocks needed in freelist */ + xfs_perag_t *pag; /* per-ag information structure */ + xfs_alloc_arg_t targs; /* local allocation arguments */ + xfs_trans_t *tp; /* transaction pointer */ + + mp = args->mp; + + pag = args->pag; + tp = args->tp; + if (!pag->pagf_init) { + if ((error = xfs_alloc_read_agf(mp, tp, args->agno, flags, + &agbp))) + return error; + if (!pag->pagf_init) { + args->agbp = NULL; + return 0; + } + } else + agbp = NULL; + need = XFS_MIN_FREELIST_PAG(pag, mp); + delta = need > pag->pagf_flcount ? need - pag->pagf_flcount : 0; + /* + * If it looks like there isn't a long enough extent, or enough + * total blocks, reject it. + */ + longest = (pag->pagf_longest > delta) ? + (pag->pagf_longest - delta) : + (pag->pagf_flcount > 0 || pag->pagf_longest > 0); + if (args->minlen + args->alignment + args->minalignslop - 1 > longest || + (args->minleft && + (int)(pag->pagf_freeblks + pag->pagf_flcount - + need - args->total) < + (int)args->minleft)) { + if (agbp) + xfs_trans_brelse(tp, agbp); + args->agbp = NULL; + return 0; + } + /* + * Get the a.g. freespace buffer. + * Can fail if we're not blocking on locks, and it's held. + */ + if (agbp == NULL) { + if ((error = xfs_alloc_read_agf(mp, tp, args->agno, flags, + &agbp))) + return error; + if (agbp == NULL) { + args->agbp = NULL; + return 0; + } + } + /* + * Figure out how many blocks we should have in the freelist. + */ + agf = XFS_BUF_TO_AGF(agbp); + need = XFS_MIN_FREELIST(agf, mp); + delta = need > INT_GET(agf->agf_flcount, ARCH_CONVERT) ? + (need - INT_GET(agf->agf_flcount, ARCH_CONVERT)) : 0; + /* + * If there isn't enough total or single-extent, reject it. + */ + longest = INT_GET(agf->agf_longest, ARCH_CONVERT); + longest = (longest > delta) ? (longest - delta) : + (INT_GET(agf->agf_flcount, ARCH_CONVERT) > 0 || longest > 0); + if (args->minlen + args->alignment + args->minalignslop - 1 > longest || + (args->minleft && + (int)(INT_GET(agf->agf_freeblks, ARCH_CONVERT) + + INT_GET(agf->agf_flcount, ARCH_CONVERT) - need - args->total) < + (int)args->minleft)) { + xfs_trans_brelse(tp, agbp); + args->agbp = NULL; + return 0; + } + /* + * Make the freelist shorter if it's too long. + */ + while (INT_GET(agf->agf_flcount, ARCH_CONVERT) > need) { + xfs_buf_t *bp; + + if ((error = xfs_alloc_get_freelist(tp, agbp, &bno))) + return error; + if ((error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, 1))) + return error; + bp = xfs_btree_get_bufs(mp, tp, args->agno, bno, 0); + xfs_trans_binval(tp, bp); + /* + * Since blocks move to the free list without + * the coordination used in xfs_bmap_finish, + * we can't allow block to be available for reallocation + * and non-transaction writing (user data) + * until we know that the transaction + * that moved it to the free list is + * permanently on disk. The only way to + * ensure that is to make this transaction + * synchronous. The one exception to this + * is in the case of wsync-mounted filesystem + * where we know that any block that made it + * onto the freelist won't be seen again in + * the file from which it came since the transactions + * that free metadata blocks or shrink inodes in + * wsync filesystems are all themselves synchronous. + */ + if (!(mp->m_flags & XFS_MOUNT_WSYNC)) + xfs_trans_set_sync(tp); + } + /* + * Initialize the args structure. + */ + targs.tp = tp; + targs.mp = mp; + targs.agbp = agbp; + targs.agno = args->agno; + targs.mod = targs.minleft = targs.wasdel = targs.userdata = + targs.minalignslop = 0; + targs.alignment = targs.minlen = targs.prod = targs.isfl = 1; + targs.type = XFS_ALLOCTYPE_THIS_AG; + targs.pag = pag; + if ((error = xfs_alloc_read_agfl(mp, tp, targs.agno, &agflbp))) + return error; + /* + * Make the freelist longer if it's too short. + */ + while (INT_GET(agf->agf_flcount, ARCH_CONVERT) < need) { + targs.agbno = 0; + targs.maxlen = need - INT_GET(agf->agf_flcount, ARCH_CONVERT); + /* + * Allocate as many blocks as possible at once. + */ + if ((error = xfs_alloc_ag_vextent(&targs))) + return error; + /* + * Stop if we run out. Won't happen if callers are obeying + * the restrictions correctly. Can happen for free calls + * on a completely full ag. + */ + if (targs.agbno == NULLAGBLOCK) + break; + /* + * Put each allocated block on the list. + */ + for (bno = targs.agbno; bno < targs.agbno + targs.len; bno++) { + if ((error = xfs_alloc_put_freelist(tp, agbp, agflbp, + bno))) + return error; + } + } + args->agbp = agbp; + return 0; +} + +/* + * Get a block from the freelist. + * Returns with the buffer for the block gotten. + */ +int /* error */ +xfs_alloc_get_freelist( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* buffer containing the agf structure */ + xfs_agblock_t *bnop) /* block address retrieved from freelist */ +{ + xfs_agf_t *agf; /* a.g. freespace structure */ + xfs_agfl_t *agfl; /* a.g. freelist structure */ + xfs_buf_t *agflbp;/* buffer for a.g. freelist structure */ + xfs_agblock_t bno; /* block number returned */ + int error; +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_get_freelist"; +#endif + xfs_mount_t *mp; /* mount structure */ + xfs_perag_t *pag; /* per allocation group data */ + + agf = XFS_BUF_TO_AGF(agbp); + /* + * Freelist is empty, give up. + */ + if (INT_GET(agf->agf_flcount, ARCH_CONVERT) == 0) { + *bnop = NULLAGBLOCK; + return 0; + } + /* + * Read the array of free blocks. + */ + mp = tp->t_mountp; + if ((error = xfs_alloc_read_agfl(mp, tp, + INT_GET(agf->agf_seqno, ARCH_CONVERT), &agflbp))) + return error; + agfl = XFS_BUF_TO_AGFL(agflbp); + /* + * Get the block number and update the data structures. + */ + bno = INT_GET(agfl->agfl_bno[INT_GET(agf->agf_flfirst, ARCH_CONVERT)], ARCH_CONVERT); + INT_MOD(agf->agf_flfirst, ARCH_CONVERT, 1); + xfs_trans_brelse(tp, agflbp); + if (INT_GET(agf->agf_flfirst, ARCH_CONVERT) == XFS_AGFL_SIZE) + INT_ZERO(agf->agf_flfirst, ARCH_CONVERT); + pag = &mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)]; + INT_MOD(agf->agf_flcount, ARCH_CONVERT, -1); + xfs_trans_agflist_delta(tp, -1); + pag->pagf_flcount--; + TRACE_MODAGF(NULL, agf, XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT); + xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT); + *bnop = bno; + return 0; +} + +/* + * Log the given fields from the agf structure. + */ +void +xfs_alloc_log_agf( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *bp, /* buffer for a.g. freelist header */ + int fields) /* mask of fields to be logged (XFS_AGF_...) */ +{ + int first; /* first byte offset */ + int last; /* last byte offset */ + static const short offsets[] = { + offsetof(xfs_agf_t, agf_magicnum), + offsetof(xfs_agf_t, agf_versionnum), + offsetof(xfs_agf_t, agf_seqno), + offsetof(xfs_agf_t, agf_length), + offsetof(xfs_agf_t, agf_roots[0]), + offsetof(xfs_agf_t, agf_levels[0]), + offsetof(xfs_agf_t, agf_flfirst), + offsetof(xfs_agf_t, agf_fllast), + offsetof(xfs_agf_t, agf_flcount), + offsetof(xfs_agf_t, agf_freeblks), + offsetof(xfs_agf_t, agf_longest), + sizeof(xfs_agf_t) + }; + + xfs_btree_offsets(fields, offsets, XFS_AGF_NUM_BITS, &first, &last); + xfs_trans_log_buf(tp, bp, (uint)first, (uint)last); +} + +/* + * Interface for inode allocation to force the pag data to be initialized. + */ +int /* error */ +xfs_alloc_pagf_init( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + int flags) /* XFS_ALLOC_FLAGS_... */ +{ + xfs_buf_t *bp; + int error; + + if ((error = xfs_alloc_read_agf(mp, tp, agno, flags, &bp))) + return error; + if (bp) + xfs_trans_brelse(tp, bp); + return 0; +} + +/* + * Put the block on the freelist for the allocation group. + */ +int /* error */ +xfs_alloc_put_freelist( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* buffer for a.g. freelist header */ + xfs_buf_t *agflbp,/* buffer for a.g. free block array */ + xfs_agblock_t bno) /* block being freed */ +{ + xfs_agf_t *agf; /* a.g. freespace structure */ + xfs_agfl_t *agfl; /* a.g. free block array */ + xfs_agblock_t *blockp;/* pointer to array entry */ + int error; +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_put_freelist"; +#endif + xfs_mount_t *mp; /* mount structure */ + xfs_perag_t *pag; /* per allocation group data */ + + agf = XFS_BUF_TO_AGF(agbp); + mp = tp->t_mountp; + + if (!agflbp && (error = xfs_alloc_read_agfl(mp, tp, + INT_GET(agf->agf_seqno, ARCH_CONVERT), &agflbp))) + return error; + agfl = XFS_BUF_TO_AGFL(agflbp); + INT_MOD(agf->agf_fllast, ARCH_CONVERT, 1); + if (INT_GET(agf->agf_fllast, ARCH_CONVERT) == XFS_AGFL_SIZE) + INT_ZERO(agf->agf_fllast, ARCH_CONVERT); + pag = &mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)]; + INT_MOD(agf->agf_flcount, ARCH_CONVERT, 1); + xfs_trans_agflist_delta(tp, 1); + pag->pagf_flcount++; + ASSERT(INT_GET(agf->agf_flcount, ARCH_CONVERT) <= XFS_AGFL_SIZE); + blockp = &agfl->agfl_bno[INT_GET(agf->agf_fllast, ARCH_CONVERT)]; + INT_SET(*blockp, ARCH_CONVERT, bno); + TRACE_MODAGF(NULL, agf, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT); + xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT); + xfs_trans_log_buf(tp, agflbp, + (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl), + (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl + + sizeof(xfs_agblock_t) - 1)); + return 0; +} + +/* + * Read in the allocation group header (free/alloc section). + */ +int /* error */ +xfs_alloc_read_agf( + xfs_mount_t *mp, /* mount point structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + int flags, /* XFS_ALLOC_FLAG_... */ + xfs_buf_t **bpp) /* buffer for the ag freelist header */ +{ + xfs_agf_t *agf; /* ag freelist header */ + int agf_ok; /* set if agf is consistent */ + xfs_buf_t *bp; /* return value */ + xfs_daddr_t d; /* disk block address */ + int error; + xfs_perag_t *pag; /* per allocation group data */ + + ASSERT(agno != NULLAGNUMBER); + d = XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, 1, + (flags & XFS_ALLOC_FLAG_TRYLOCK) ? XFS_BUF_TRYLOCK : 0U, + &bp))) + return error; + ASSERT(!bp || !XFS_BUF_GETERROR(bp)); + if (!bp) { + *bpp = NULL; + return 0; + } + /* + * Validate the magic number of the agf block. + */ + agf = XFS_BUF_TO_AGF(bp); + agf_ok = + INT_GET(agf->agf_magicnum, ARCH_CONVERT) == XFS_AGF_MAGIC && + XFS_AGF_GOOD_VERSION(INT_GET(agf->agf_versionnum, ARCH_CONVERT)) && + INT_GET(agf->agf_freeblks, ARCH_CONVERT) <= + INT_GET(agf->agf_length, ARCH_CONVERT) && + INT_GET(agf->agf_flfirst, ARCH_CONVERT) < XFS_AGFL_SIZE && + INT_GET(agf->agf_fllast, ARCH_CONVERT) < XFS_AGFL_SIZE && + INT_GET(agf->agf_flcount, ARCH_CONVERT) <= XFS_AGFL_SIZE; + if (XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF, + XFS_RANDOM_ALLOC_READ_AGF)) { + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EFSCORRUPTED); + } + pag = &mp->m_perag[agno]; + if (!pag->pagf_init) { + pag->pagf_freeblks = INT_GET(agf->agf_freeblks, ARCH_CONVERT); + pag->pagf_flcount = INT_GET(agf->agf_flcount, ARCH_CONVERT); + pag->pagf_longest = INT_GET(agf->agf_longest, ARCH_CONVERT); + pag->pagf_levels[XFS_BTNUM_BNOi] = + INT_GET(agf->agf_levels[XFS_BTNUM_BNOi], ARCH_CONVERT); + pag->pagf_levels[XFS_BTNUM_CNTi] = + INT_GET(agf->agf_levels[XFS_BTNUM_CNTi], ARCH_CONVERT); + pag->pagf_init = 1; + } +#ifdef DEBUG + else if (!XFS_FORCED_SHUTDOWN(mp)) { + ASSERT(pag->pagf_freeblks == INT_GET(agf->agf_freeblks, ARCH_CONVERT)); + ASSERT(pag->pagf_flcount == INT_GET(agf->agf_flcount, ARCH_CONVERT)); + ASSERT(pag->pagf_longest == INT_GET(agf->agf_longest, ARCH_CONVERT)); + ASSERT(pag->pagf_levels[XFS_BTNUM_BNOi] == + INT_GET(agf->agf_levels[XFS_BTNUM_BNOi], ARCH_CONVERT)); + ASSERT(pag->pagf_levels[XFS_BTNUM_CNTi] == + INT_GET(agf->agf_levels[XFS_BTNUM_CNTi], ARCH_CONVERT)); + } +#endif + XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGF, XFS_AGF_REF); + *bpp = bp; + return 0; +} + +/* + * Allocate an extent (variable-size). + * Depending on the allocation type, we either look in a single allocation + * group or loop over the allocation groups to find the result. + */ +int /* error */ +xfs_alloc_vextent( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_agblock_t agsize; /* allocation group size */ + int error; + int flags; /* XFS_ALLOC_FLAG_... locking flags */ +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_vextent"; +#endif + xfs_extlen_t minleft;/* minimum left value, temp copy */ + xfs_mount_t *mp; /* mount structure pointer */ + xfs_agnumber_t sagno; /* starting allocation group number */ + xfs_alloctype_t type; /* input allocation type */ + + mp = args->mp; + type = args->otype = args->type; + args->agbno = NULLAGBLOCK; + /* + * Just fix this up, for the case where the last a.g. is shorter + * (or there's only one a.g.) and the caller couldn't easily figure + * that out (xfs_bmap_alloc). + */ + agsize = mp->m_sb.sb_agblocks; + if (args->maxlen > agsize) + args->maxlen = agsize; + if (args->alignment == 0) + args->alignment = 1; + ASSERT(XFS_FSB_TO_AGNO(mp, args->fsbno) < mp->m_sb.sb_agcount); + ASSERT(XFS_FSB_TO_AGBNO(mp, args->fsbno) < agsize); + ASSERT(args->minlen <= args->maxlen); + ASSERT(args->minlen <= agsize); + ASSERT(args->mod < args->prod); + if (XFS_FSB_TO_AGNO(mp, args->fsbno) >= mp->m_sb.sb_agcount || + XFS_FSB_TO_AGBNO(mp, args->fsbno) >= agsize || + args->minlen > args->maxlen || args->minlen > agsize || + args->mod >= args->prod) { + args->fsbno = NULLFSBLOCK; + TRACE_ALLOC("badargs", args); + return 0; + } + switch (type) { + case XFS_ALLOCTYPE_THIS_AG: + case XFS_ALLOCTYPE_NEAR_BNO: + case XFS_ALLOCTYPE_THIS_BNO: + /* + * These three force us into a single a.g. + */ + args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); + mrlock(&mp->m_peraglock, MR_ACCESS, PINOD); + args->pag = &mp->m_perag[args->agno]; + minleft = args->minleft; + args->minleft = 0; + error = xfs_alloc_fix_freelist(args, 0); + args->minleft = minleft; + if (error) { + TRACE_ALLOC("nofix", args); + goto error0; + } + if (!args->agbp) { + mrunlock(&mp->m_peraglock); + TRACE_ALLOC("noagbp", args); + break; + } + args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); + if ((error = xfs_alloc_ag_vextent(args))) + goto error0; + mrunlock(&mp->m_peraglock); + break; + case XFS_ALLOCTYPE_START_BNO: + /* + * Try near allocation first, then anywhere-in-ag after + * the first a.g. fails. + */ + args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); + args->type = XFS_ALLOCTYPE_NEAR_BNO; + /* FALLTHROUGH */ + case XFS_ALLOCTYPE_ANY_AG: + case XFS_ALLOCTYPE_START_AG: + case XFS_ALLOCTYPE_FIRST_AG: + /* + * Rotate through the allocation groups looking for a winner. + */ + if (type == XFS_ALLOCTYPE_ANY_AG) { + /* + * Start with the last place we left off. + */ + args->agno = sagno = mp->m_agfrotor; + args->type = XFS_ALLOCTYPE_THIS_AG; + flags = XFS_ALLOC_FLAG_TRYLOCK; + } else if (type == XFS_ALLOCTYPE_FIRST_AG) { + /* + * Start with allocation group given by bno. + */ + args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); + args->type = XFS_ALLOCTYPE_THIS_AG; + sagno = 0; + flags = 0; + } else { + if (type == XFS_ALLOCTYPE_START_AG) + args->type = XFS_ALLOCTYPE_THIS_AG; + /* + * Start with the given allocation group. + */ + args->agno = sagno = XFS_FSB_TO_AGNO(mp, args->fsbno); + flags = XFS_ALLOC_FLAG_TRYLOCK; + } + /* + * Loop over allocation groups twice; first time with + * trylock set, second time without. + */ + for (;;) { + mrlock(&mp->m_peraglock, MR_ACCESS, PINOD); + args->pag = &mp->m_perag[args->agno]; + if ((error = xfs_alloc_fix_freelist(args, flags))) { + TRACE_ALLOC("nofix", args); + goto error0; + } + /* + * If we get a buffer back then the allocation will fly. + */ + if (args->agbp) { + if ((error = xfs_alloc_ag_vextent(args))) + goto error0; + mrunlock(&mp->m_peraglock); + break; + } + mrunlock(&mp->m_peraglock); + TRACE_ALLOC("loopfailed", args); + /* + * Didn't work, figure out the next iteration. + */ + if (args->agno == sagno && + type == XFS_ALLOCTYPE_START_BNO) + args->type = XFS_ALLOCTYPE_THIS_AG; + if (++(args->agno) == mp->m_sb.sb_agcount) + args->agno = 0; + /* + * Reached the starting a.g., must either be done + * or switch to non-trylock mode. + */ + if (args->agno == sagno) { + if (flags == 0) { + args->agbno = NULLAGBLOCK; + TRACE_ALLOC("allfailed", args); + break; + } + flags = 0; + if (type == XFS_ALLOCTYPE_START_BNO) { + args->agbno = XFS_FSB_TO_AGBNO(mp, + args->fsbno); + args->type = XFS_ALLOCTYPE_NEAR_BNO; + } + } + } + mp->m_agfrotor = (args->agno + 1) % mp->m_sb.sb_agcount; + break; + default: + ASSERT(0); + /* NOTREACHED */ + } + if (args->agbno == NULLAGBLOCK) + args->fsbno = NULLFSBLOCK; + else { + args->fsbno = XFS_AGB_TO_FSB(mp, args->agno, args->agbno); +#ifdef DEBUG + ASSERT(args->len >= args->minlen); + ASSERT(args->len <= args->maxlen); + ASSERT(args->agbno % args->alignment == 0); + XFS_AG_CHECK_DADDR(mp, XFS_FSB_TO_DADDR(mp, args->fsbno), + args->len); +#endif + } + return 0; +error0: + mrunlock(&mp->m_peraglock); + return error; +} + +/* + * Free an extent. + * Just break up the extent address and hand off to xfs_free_ag_extent + * after fixing up the freelist. + */ +int /* error */ +xfs_free_extent( + xfs_trans_t *tp, /* transaction pointer */ + xfs_fsblock_t bno, /* starting block number of extent */ + xfs_extlen_t len) /* length of extent */ +{ +#ifdef DEBUG + xfs_agf_t *agf; /* a.g. freespace header */ +#endif + xfs_alloc_arg_t args; /* allocation argument structure */ + int error; + + ASSERT(len != 0); + args.tp = tp; + args.mp = tp->t_mountp; + args.agno = XFS_FSB_TO_AGNO(args.mp, bno); + ASSERT(args.agno < args.mp->m_sb.sb_agcount); + args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno); + args.alignment = 1; + args.minlen = args.minleft = args.minalignslop = 0; + mrlock(&args.mp->m_peraglock, MR_ACCESS, PINOD); + args.pag = &args.mp->m_perag[args.agno]; + if ((error = xfs_alloc_fix_freelist(&args, 0))) + goto error0; +#ifdef DEBUG + ASSERT(args.agbp != NULL); + agf = XFS_BUF_TO_AGF(args.agbp); + ASSERT(args.agbno + len <= INT_GET(agf->agf_length, ARCH_CONVERT)); +#endif + error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, + len, 0); +error0: + mrunlock(&args.mp->m_peraglock); + return error; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_alloc_btree.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_alloc_btree.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_alloc_btree.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_alloc_btree.c Wed Apr 18 21:41:37 2001 @@ -0,0 +1,2136 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Free space allocation for XFS. + */ + +#include + +/* + * Single level of the xfs_alloc_delete record deletion routine. + * Delete record pointed to by cur/level. + * Remove the record from its block then rebalance the tree. + * Return 0 for error, 1 for done, 2 to go on to the next level. + */ +STATIC int /* error */ +xfs_alloc_delrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level removing record from */ + int *stat) /* fail/done/go-on */ +{ + xfs_agf_t *agf; /* allocation group freelist header */ + xfs_alloc_block_t *block; /* btree block record/key lives in */ + xfs_agblock_t bno; /* btree block number */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ + int i; /* loop index */ + xfs_alloc_key_t key; /* kp points here if block is level 0 */ + xfs_agblock_t lbno; /* left block's block number */ + xfs_buf_t *lbp; /* left block's buffer pointer */ + xfs_alloc_block_t *left; /* left btree block */ + xfs_alloc_key_t *lkp=NULL; /* left block key pointer */ + xfs_alloc_ptr_t *lpp=NULL; /* left block address pointer */ + int lrecs=0; /* number of records in left block */ + xfs_alloc_rec_t *lrp; /* left block record pointer */ + xfs_mount_t *mp; /* mount structure */ + int ptr; /* index in btree block for this rec */ + xfs_agblock_t rbno; /* right block's block number */ + xfs_buf_t *rbp; /* right block's buffer pointer */ + xfs_alloc_block_t *right; /* right btree block */ + xfs_alloc_key_t *rkp; /* right block key pointer */ + xfs_alloc_ptr_t *rpp; /* right block address pointer */ + int rrecs=0; /* number of records in right block */ + xfs_alloc_rec_t *rrp; /* right block record pointer */ + xfs_btree_cur_t *tcur; /* temporary btree cursor */ + + /* + * Get the index of the entry being deleted, check for nothing there. + */ + ptr = cur->bc_ptrs[level]; + if (ptr == 0) { + *stat = 0; + return 0; + } + /* + * Get the buffer & block containing the record or key/ptr. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; +#endif + /* + * Fail if we're off the end of the block. + */ + if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + *stat = 0; + return 0; + } + XFS_STATS_INC(xfsstats.xs_abt_delrec); + /* + * It's a nonleaf. Excise the key and ptr being deleted, by + * sliding the entries past them down one. + * Log the changed areas of the block. + */ + if (level > 0) { + lkp = XFS_ALLOC_KEY_ADDR(block, 1, cur); + lpp = XFS_ALLOC_PTR_ADDR(block, 1, cur); +#ifdef DEBUG + for (i = ptr; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(lpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ovbcopy(&lkp[ptr], &lkp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*lkp)); /* INT_: mem copy */ + ovbcopy(&lpp[ptr], &lpp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*lpp)); /* INT_: mem copy */ + xfs_alloc_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + xfs_alloc_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + } + } + /* + * It's a leaf. Excise the record being deleted, by sliding the + * entries past it down one. Log the changed areas of the block. + */ + else { + lrp = XFS_ALLOC_REC_ADDR(block, 1, cur); + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ovbcopy(&lrp[ptr], &lrp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*lrp)); + xfs_alloc_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + } + /* + * If it's the first record in the block, we'll need a key + * structure to pass up to the next level (updkey). + */ + if (ptr == 1) { + key.ar_startblock = lrp->ar_startblock; /* INT_: direct copy */ + key.ar_blockcount = lrp->ar_blockcount; /* INT_: direct copy */ + lkp = &key; + } + } + /* + * Decrement and log the number of entries in the block. + */ + INT_MOD(block->bb_numrecs, ARCH_CONVERT, -1); + xfs_alloc_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS); + /* + * See if the longest free extent in the allocation group was + * changed by this operation. True if it's the by-size btree, and + * this is the leaf level, and there is no right sibling block, + * and this was the last record. + */ + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + mp = cur->bc_mp; + + if (level == 0 && + cur->bc_btnum == XFS_BTNUM_CNT && + INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK && + ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ASSERT(ptr == INT_GET(block->bb_numrecs, ARCH_CONVERT) + 1); + /* + * There are still records in the block. Grab the size + * from the last one. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + rrp = XFS_ALLOC_REC_ADDR(block, INT_GET(block->bb_numrecs, ARCH_CONVERT), cur); + INT_COPY(agf->agf_longest, rrp->ar_blockcount, ARCH_CONVERT); + } + /* + * No free extents left. + */ + else + INT_ZERO(agf->agf_longest, ARCH_CONVERT); + mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)].pagf_longest = + INT_GET(agf->agf_longest, ARCH_CONVERT); + xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, + XFS_AGF_LONGEST); + } + /* + * Is this the root level? If so, we're almost done. + */ + if (level == cur->bc_nlevels - 1) { + /* + * If this is the root level, + * and there's only one entry left, + * and it's NOT the leaf level, + * then we can get rid of this level. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) == 1 && level > 0) { + /* + * lpp is still set to the first pointer in the block. + * Make it the new root of the btree. + */ + bno = INT_GET(agf->agf_roots[cur->bc_btnum], ARCH_CONVERT); + INT_COPY(agf->agf_roots[cur->bc_btnum], *lpp, ARCH_CONVERT); + INT_MOD(agf->agf_levels[cur->bc_btnum], ARCH_CONVERT, -1); + mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)].pagf_levels[cur->bc_btnum]--; + /* + * Put this buffer/block on the ag's freelist. + */ + if ((error = xfs_alloc_put_freelist(cur->bc_tp, + cur->bc_private.a.agbp, NULL, bno))) + return error; + xfs_trans_agbtree_delta(cur->bc_tp, -1); + xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, + XFS_AGF_ROOTS | XFS_AGF_LEVELS); + /* + * Update the cursor so there's one fewer level. + */ + xfs_btree_setbuf(cur, level, 0); + cur->bc_nlevels--; + } else if (level > 0 && + (error = xfs_alloc_decrement(cur, level, &i))) + return error; + *stat = 1; + return 0; + } + /* + * If we deleted the leftmost entry in the block, update the + * key values above us in the tree. + */ + if (ptr == 1 && (error = xfs_alloc_updkey(cur, lkp, level + 1))) + return error; + /* + * If the number of records remaining in the block is at least + * the minimum, we're done. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) >= XFS_ALLOC_BLOCK_MINRECS(level, cur)) { + if (level > 0 && (error = xfs_alloc_decrement(cur, level, &i))) + return error; + *stat = 1; + return 0; + } + /* + * Otherwise, we have to move some records around to keep the + * tree balanced. Look at the left and right sibling blocks to + * see if we can re-balance by moving only one record. + */ + rbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + lbno = INT_GET(block->bb_leftsib, ARCH_CONVERT); + bno = NULLAGBLOCK; + ASSERT(rbno != NULLAGBLOCK || lbno != NULLAGBLOCK); + /* + * Duplicate the cursor so our btree manipulations here won't + * disrupt the next level up. + */ + if ((error = xfs_btree_dup_cursor(cur, &tcur))) + return error; + /* + * If there's a right sibling, see if it's ok to shift an entry + * out of it. + */ + if (rbno != NULLAGBLOCK) { + /* + * Move the temp cursor to the last entry in the next block. + * Actually any entry but the first would suffice. + */ + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_increment(tcur, level, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Grab a pointer to the block. + */ + rbp = tcur->bc_bufs[level]; + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + goto error0; +#endif + /* + * Grab the current block number, for future use. + */ + bno = INT_GET(right->bb_leftsib, ARCH_CONVERT); + /* + * If right block is full enough so that removing one entry + * won't make it too empty, and left-shifting an entry out + * of right to us works, we're done. + */ + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_ALLOC_BLOCK_MINRECS(level, cur)) { + if ((error = xfs_alloc_lshift(tcur, level, &i))) + goto error0; + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_ALLOC_BLOCK_MINRECS(level, cur)); + xfs_btree_del_cursor(tcur, + XFS_BTREE_NOERROR); + if (level > 0 && + (error = xfs_alloc_decrement(cur, level, + &i))) + return error; + *stat = 1; + return 0; + } + } + /* + * Otherwise, grab the number of records in right for + * future reference, and fix up the temp cursor to point + * to our block again (last record). + */ + rrecs = INT_GET(right->bb_numrecs, ARCH_CONVERT); + if (lbno != NULLAGBLOCK) { + i = xfs_btree_firstrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_decrement(tcur, level, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + } + /* + * If there's a left sibling, see if it's ok to shift an entry + * out of it. + */ + if (lbno != NULLAGBLOCK) { + /* + * Move the temp cursor to the first entry in the + * previous block. + */ + i = xfs_btree_firstrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_decrement(tcur, level, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + xfs_btree_firstrec(tcur, level); + /* + * Grab a pointer to the block. + */ + lbp = tcur->bc_bufs[level]; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + goto error0; +#endif + /* + * Grab the current block number, for future use. + */ + bno = INT_GET(left->bb_rightsib, ARCH_CONVERT); + /* + * If left block is full enough so that removing one entry + * won't make it too empty, and right-shifting an entry out + * of left to us works, we're done. + */ + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_ALLOC_BLOCK_MINRECS(level, cur)) { + if ((error = xfs_alloc_rshift(tcur, level, &i))) + goto error0; + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_ALLOC_BLOCK_MINRECS(level, cur)); + xfs_btree_del_cursor(tcur, + XFS_BTREE_NOERROR); + if (level == 0) + cur->bc_ptrs[0]++; + *stat = 1; + return 0; + } + } + /* + * Otherwise, grab the number of records in right for + * future reference. + */ + lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + /* + * Delete the temp cursor, we're done with it. + */ + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + /* + * If here, we need to do a join to keep the tree balanced. + */ + ASSERT(bno != NULLAGBLOCK); + /* + * See if we can join with the left neighbor block. + */ + if (lbno != NULLAGBLOCK && + lrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { + /* + * Set "right" to be the starting block, + * "left" to be the left neighbor. + */ + rbno = bno; + right = block; + rbp = bp; + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + cur->bc_private.a.agno, lbno, 0, &lbp, + XFS_ALLOC_BTREE_REF))) + return error; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; + } + /* + * If that won't work, see if we can join with the right neighbor block. + */ + else if (rbno != NULLAGBLOCK && + rrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= + XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { + /* + * Set "left" to be the starting block, + * "right" to be the right neighbor. + */ + lbno = bno; + left = block; + lbp = bp; + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + cur->bc_private.a.agno, rbno, 0, &rbp, + XFS_ALLOC_BTREE_REF))) + return error; + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + return error; + } + /* + * Otherwise, we can't fix the imbalance. + * Just return. This is probably a logic error, but it's not fatal. + */ + else { + if (level > 0 && (error = xfs_alloc_decrement(cur, level, &i))) + return error; + *stat = 1; + return 0; + } + /* + * We're now going to join "left" and "right" by moving all the stuff + * in "right" to "left" and deleting "right". + */ + if (level > 0) { + /* + * It's a non-leaf. Move keys and pointers. + */ + lkp = XFS_ALLOC_KEY_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + lpp = XFS_ALLOC_PTR_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur); + rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + bcopy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp)); /* INT_: structure copy */ + bcopy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp)); /* INT_: structure copy */ + xfs_alloc_log_keys(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_alloc_log_ptrs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } else { + /* + * It's a leaf. Move records. + */ + lrp = XFS_ALLOC_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rrp = XFS_ALLOC_REC_ADDR(right, 1, cur); + bcopy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp)); + xfs_alloc_log_recs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } + /* + * If we joined with the left neighbor, set the buffer in the + * cursor to the left block, and fix up the index. + */ + if (bp != lbp) { + xfs_btree_setbuf(cur, level, lbp); + cur->bc_ptrs[level] += INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + /* + * If we joined with the right neighbor and there's a level above + * us, increment the cursor at that level. + */ + else if (level + 1 < cur->bc_nlevels && + (error = xfs_alloc_increment(cur, level + 1, &i))) + return error; + /* + * Fix up the number of records in the surviving block. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + /* + * Fix up the right block pointer in the surviving block, and log it. + */ + left->bb_rightsib = right->bb_rightsib; /* INT_: direct copy */ + xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); + /* + * If there is a right sibling now, make it point to the + * remaining block. + */ + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_alloc_block_t *rrblock; + xfs_buf_t *rrbp; + + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + cur->bc_private.a.agno, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, + &rrbp, XFS_ALLOC_BTREE_REF))) + return error; + rrblock = XFS_BUF_TO_ALLOC_BLOCK(rrbp); + if ((error = xfs_btree_check_sblock(cur, rrblock, level, rrbp))) + return error; + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, lbno); + xfs_alloc_log_block(cur->bc_tp, rrbp, XFS_BB_LEFTSIB); + } + /* + * Free the deleting block by putting it on the freelist. + */ + if ((error = xfs_alloc_put_freelist(cur->bc_tp, cur->bc_private.a.agbp, + NULL, rbno))) + return error; + xfs_trans_agbtree_delta(cur->bc_tp, -1); + /* + * Adjust the current level's cursor so that we're left referring + * to the right node, after we're done. + * If this leaves the ptr value 0 our caller will fix it up. + */ + if (level > 0) + cur->bc_ptrs[level]--; + /* + * Return value means the next level up has something to do. + */ + *stat = 2; + return 0; + +error0: + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; +} + +/* + * Insert one record/level. Return information to the caller + * allowing the next level up to proceed if necessary. + */ +STATIC int /* error */ +xfs_alloc_insrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to insert record at */ + xfs_agblock_t *bnop, /* i/o: block number inserted */ + xfs_alloc_rec_t *recp, /* i/o: record data inserted */ + xfs_btree_cur_t **curp, /* output: new cursor replacing cur */ + int *stat) /* output: success/failure */ +{ + xfs_agf_t *agf; /* allocation group freelist header */ + xfs_alloc_block_t *block; /* btree block record/key lives in */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ + int i; /* loop index */ + xfs_alloc_key_t key; /* key value being inserted */ + xfs_alloc_key_t *kp; /* pointer to btree keys */ + xfs_agblock_t nbno; /* block number of allocated block */ + xfs_btree_cur_t *ncur; /* new cursor to be used at next lvl */ + xfs_alloc_key_t nkey; /* new key value, from split */ + xfs_alloc_rec_t nrec; /* new record value, for caller */ + int optr; /* old ptr value */ + xfs_alloc_ptr_t *pp; /* pointer to btree addresses */ + int ptr; /* index in btree block for this rec */ + xfs_alloc_rec_t *rp; /* pointer to btree records */ + + ASSERT(INT_GET(recp->ar_blockcount, ARCH_CONVERT) > 0); + /* + * If we made it to the root level, allocate a new root block + * and we're done. + */ + if (level >= cur->bc_nlevels) { + XFS_STATS_INC(xfsstats.xs_abt_insrec); + if ((error = xfs_alloc_newroot(cur, &i))) + return error; + *bnop = NULLAGBLOCK; + *stat = i; + return 0; + } + /* + * Make a key out of the record data to be inserted, and save it. + */ + key.ar_startblock = recp->ar_startblock; /* INT_: direct copy */ + key.ar_blockcount = recp->ar_blockcount; /* INT_: direct copy */ + optr = ptr = cur->bc_ptrs[level]; + /* + * If we're off the left edge, return failure. + */ + if (ptr == 0) { + *stat = 0; + return 0; + } + XFS_STATS_INC(xfsstats.xs_abt_insrec); + /* + * Get pointers to the btree buffer and block. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; + /* + * Check that the new entry is being inserted in the right place. + */ + if (ptr <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + if (level == 0) { + rp = XFS_ALLOC_REC_ADDR(block, ptr, cur); + xfs_btree_check_rec(cur->bc_btnum, recp, rp); + } else { + kp = XFS_ALLOC_KEY_ADDR(block, ptr, cur); + xfs_btree_check_key(cur->bc_btnum, &key, kp); + } + } +#endif + nbno = NULLAGBLOCK; + ncur = (xfs_btree_cur_t *)0; + /* + * If the block is full, we can't insert the new entry until we + * make the block un-full. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { + /* + * First, try shifting an entry to the right neighbor. + */ + if ((error = xfs_alloc_rshift(cur, level, &i))) + return error; + if (i) { + /* nothing */ + } + /* + * Next, try shifting an entry to the left neighbor. + */ + else { + if ((error = xfs_alloc_lshift(cur, level, &i))) + return error; + if (i) + optr = ptr = cur->bc_ptrs[level]; + else { + /* + * Next, try splitting the current block in + * half. If this works we have to re-set our + * variables because we could be in a + * different block now. + */ + if ((error = xfs_alloc_split(cur, level, &nbno, + &nkey, &ncur, &i))) + return error; + if (i) { + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = + xfs_btree_check_sblock(cur, + block, level, bp))) + return error; +#endif + ptr = cur->bc_ptrs[level]; + nrec.ar_startblock = nkey.ar_startblock; /* INT_: direct copy */ + nrec.ar_blockcount = nkey.ar_blockcount; /* INT_: direct copy */ + } + /* + * Otherwise the insert fails. + */ + else { + *stat = 0; + return 0; + } + } + } + } + /* + * At this point we know there's room for our new entry in the block + * we're pointing at. + */ + if (level > 0) { + /* + * It's a non-leaf entry. Make a hole for the new data + * in the key and ptr regions of the block. + */ + kp = XFS_ALLOC_KEY_ADDR(block, 1, cur); + pp = XFS_ALLOC_PTR_ADDR(block, 1, cur); +#ifdef DEBUG + for (i = INT_GET(block->bb_numrecs, ARCH_CONVERT); i >= ptr; i--) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(pp[i - 1], ARCH_CONVERT), level))) + return error; + } +#endif + ovbcopy(&kp[ptr - 1], &kp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*kp)); /* INT_: copy */ + ovbcopy(&pp[ptr - 1], &pp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*pp)); /* INT_: copy */ +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, *bnop, level))) + return error; +#endif + /* + * Now stuff the new data in, bump numrecs and log the new data. + */ + kp[ptr - 1] = key; + INT_SET(pp[ptr - 1], ARCH_CONVERT, *bnop); + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_alloc_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + xfs_alloc_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); +#ifdef DEBUG + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) + xfs_btree_check_key(cur->bc_btnum, kp + ptr - 1, + kp + ptr); +#endif + } else { + /* + * It's a leaf entry. Make a hole for the new record. + */ + rp = XFS_ALLOC_REC_ADDR(block, 1, cur); + ovbcopy(&rp[ptr - 1], &rp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*rp)); + /* + * Now stuff the new record in, bump numrecs + * and log the new data. + */ + rp[ptr - 1] = *recp; /* INT_: struct copy */ + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_alloc_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); +#ifdef DEBUG + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) + xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1, + rp + ptr); +#endif + } + /* + * Log the new number of records in the btree header. + */ + xfs_alloc_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS); + /* + * If we inserted at the start of a block, update the parents' keys. + */ + if (optr == 1 && (error = xfs_alloc_updkey(cur, &key, level + 1))) + return error; + /* + * Look to see if the longest extent in the allocation group + * needs to be updated. + */ + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + if (level == 0 && + cur->bc_btnum == XFS_BTNUM_CNT && + INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK && + INT_GET(recp->ar_blockcount, ARCH_CONVERT) > INT_GET(agf->agf_longest, ARCH_CONVERT)) { + /* + * If this is a leaf in the by-size btree and there + * is no right sibling block and this block is bigger + * than the previous longest block, update it. + */ + INT_COPY(agf->agf_longest, recp->ar_blockcount, ARCH_CONVERT); + cur->bc_mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)].pagf_longest + = INT_GET(recp->ar_blockcount, ARCH_CONVERT); + xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, + XFS_AGF_LONGEST); + } + /* + * Return the new block number, if any. + * If there is one, give back a record value and a cursor too. + */ + *bnop = nbno; + if (nbno != NULLAGBLOCK) { + *recp = nrec; /* INT_: struct copy */ + *curp = ncur; /* INT_: struct copy */ + } + *stat = 1; + return 0; +} + +/* + * Log header fields from a btree block. + */ +STATIC void +xfs_alloc_log_block( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *bp, /* buffer containing btree block */ + int fields) /* mask of fields: XFS_BB_... */ +{ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + static const short offsets[] = { /* table of offsets */ + offsetof(xfs_alloc_block_t, bb_magic), + offsetof(xfs_alloc_block_t, bb_level), + offsetof(xfs_alloc_block_t, bb_numrecs), + offsetof(xfs_alloc_block_t, bb_leftsib), + offsetof(xfs_alloc_block_t, bb_rightsib), + sizeof(xfs_alloc_block_t) + }; + + xfs_btree_offsets(fields, offsets, XFS_BB_NUM_BITS, &first, &last); + xfs_trans_log_buf(tp, bp, first, last); +} + +/* + * Log keys from a btree block (nonleaf). + */ +STATIC void +xfs_alloc_log_keys( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int kfirst, /* index of first key to log */ + int klast) /* index of last key to log */ +{ + xfs_alloc_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + xfs_alloc_key_t *kp; /* key pointer in btree block */ + int last; /* last byte offset logged */ + + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + kp = XFS_ALLOC_KEY_ADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&kp[kfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&kp[klast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Log block pointer fields from a btree block (nonleaf). + */ +STATIC void +xfs_alloc_log_ptrs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int pfirst, /* index of first pointer to log */ + int plast) /* index of last pointer to log */ +{ + xfs_alloc_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + xfs_alloc_ptr_t *pp; /* block-pointer pointer in btree blk */ + + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + pp = XFS_ALLOC_PTR_ADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&pp[pfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&pp[plast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Log records from a btree block (leaf). + */ +STATIC void +xfs_alloc_log_recs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int rfirst, /* index of first record to log */ + int rlast) /* index of last record to log */ +{ + xfs_alloc_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + xfs_alloc_rec_t *rp; /* record pointer for btree block */ + + + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + rp = XFS_ALLOC_REC_ADDR(block, 1, cur); +#ifdef DEBUG + { + xfs_agf_t *agf; + xfs_alloc_rec_t *p; + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + for (p = &rp[rfirst - 1]; p <= &rp[rlast - 1]; p++) + ASSERT(INT_GET(p->ar_startblock, ARCH_CONVERT) + INT_GET(p->ar_blockcount, ARCH_CONVERT) <= + INT_GET(agf->agf_length, ARCH_CONVERT)); + } +#endif + first = (int)((xfs_caddr_t)&rp[rfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&rp[rlast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Lookup the record. The cursor is made to point to it, based on dir. + * Return 0 if can't find any such record, 1 for success. + */ +STATIC int /* error */ +xfs_alloc_lookup( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_lookup_t dir, /* <=, ==, or >= */ + int *stat) /* success/failure */ +{ + xfs_agblock_t agbno; /* a.g. relative btree block number */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_alloc_block_t *block=NULL; /* current btree block */ + int diff; /* difference for the current key */ + int error; /* error return value */ + int keyno=0; /* current key number */ + int level; /* level in the btree */ + xfs_mount_t *mp; /* file system mount point */ + + XFS_STATS_INC(xfsstats.xs_abt_lookup); + /* + * Get the allocation group header, and the root block number. + */ + mp = cur->bc_mp; + + { + xfs_agf_t *agf; /* a.g. freespace header */ + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + agno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + agbno = INT_GET(agf->agf_roots[cur->bc_btnum], ARCH_CONVERT); + } + /* + * Iterate over each level in the btree, starting at the root. + * For each level above the leaves, find the key we need, based + * on the lookup record, then follow the corresponding block + * pointer down to the next level. + */ + for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) { + xfs_buf_t *bp; /* buffer pointer for btree block */ + xfs_daddr_t d; /* disk address of btree block */ + + /* + * Get the disk address we're looking for. + */ + d = XFS_AGB_TO_DADDR(mp, agno, agbno); + /* + * If the old buffer at this level is for a different block, + * throw it away, otherwise just use it. + */ + bp = cur->bc_bufs[level]; + if (bp && XFS_BUF_ADDR(bp) != d) + bp = (xfs_buf_t *)0; + if (!bp) { + /* + * Need to get a new buffer. Read it, then + * set it in the cursor, releasing the old one. + */ + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, agno, + agbno, 0, &bp, XFS_ALLOC_BTREE_REF))) + return error; + xfs_btree_setbuf(cur, level, bp); + /* + * Point to the btree block, now that we have the buffer + */ + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, level, + bp))) + return error; + } else + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + /* + * If we already had a key match at a higher level, we know + * we need to use the first entry in this block. + */ + if (diff == 0) + keyno = 1; + /* + * Otherwise we need to search this block. Do a binary search. + */ + else { + int high; /* high entry number */ + xfs_alloc_key_t *kkbase=NULL;/* base of keys in block */ + xfs_alloc_rec_t *krbase=NULL;/* base of records in block */ + int low; /* low entry number */ + + /* + * Get a pointer to keys or records. + */ + if (level > 0) + kkbase = XFS_ALLOC_KEY_ADDR(block, 1, cur); + else + krbase = XFS_ALLOC_REC_ADDR(block, 1, cur); + /* + * Set low and high entry numbers, 1-based. + */ + low = 1; + if (!(high = INT_GET(block->bb_numrecs, ARCH_CONVERT))) { + /* + * If the block is empty, the tree must + * be an empty leaf. + */ + ASSERT(level == 0 && cur->bc_nlevels == 1); + cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE; + *stat = 0; + return 0; + } + /* + * Binary search the block. + */ + while (low <= high) { + xfs_extlen_t blockcount; /* key value */ + xfs_agblock_t startblock; /* key value */ + + XFS_STATS_INC(xfsstats.xs_abt_compare); + /* + * keyno is average of low and high. + */ + keyno = (low + high) >> 1; + /* + * Get startblock & blockcount. + */ + if (level > 0) { + xfs_alloc_key_t *kkp; + + kkp = kkbase + keyno - 1; + startblock = INT_GET(kkp->ar_startblock, ARCH_CONVERT); + blockcount = INT_GET(kkp->ar_blockcount, ARCH_CONVERT); + } else { + xfs_alloc_rec_t *krp; + + krp = krbase + keyno - 1; + startblock = INT_GET(krp->ar_startblock, ARCH_CONVERT); + blockcount = INT_GET(krp->ar_blockcount, ARCH_CONVERT); + } + /* + * Compute difference to get next direction. + */ + if (cur->bc_btnum == XFS_BTNUM_BNO) + diff = (int)startblock - + (int)cur->bc_rec.a.ar_startblock; + else if (!(diff = (int)blockcount - + (int)cur->bc_rec.a.ar_blockcount)) + diff = (int)startblock - + (int)cur->bc_rec.a.ar_startblock; + /* + * Less than, move right. + */ + if (diff < 0) + low = keyno + 1; + /* + * Greater than, move left. + */ + else if (diff > 0) + high = keyno - 1; + /* + * Equal, we're done. + */ + else + break; + } + } + /* + * If there are more levels, set up for the next level + * by getting the block number and filling in the cursor. + */ + if (level > 0) { + /* + * If we moved left, need the previous key number, + * unless there isn't one. + */ + if (diff > 0 && --keyno < 1) + keyno = 1; + agbno = INT_GET(*XFS_ALLOC_PTR_ADDR(block, keyno, cur), ARCH_CONVERT); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, agbno, level))) + return error; +#endif + cur->bc_ptrs[level] = keyno; + } + } + /* + * Done with the search. + * See if we need to adjust the results. + */ + if (dir != XFS_LOOKUP_LE && diff < 0) { + keyno++; + /* + * If ge search and we went off the end of the block, but it's + * not the last block, we're in the wrong block. + */ + if (dir == XFS_LOOKUP_GE && + keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT) && + INT_GET(block->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + int i; + + cur->bc_ptrs[0] = keyno; + if ((error = xfs_alloc_increment(cur, 0, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + *stat = 1; + return 0; + } + } + else if (dir == XFS_LOOKUP_LE && diff > 0) + keyno--; + cur->bc_ptrs[0] = keyno; + /* + * Return if we succeeded or not. + */ + if (keyno == 0 || keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT)) + *stat = 0; + else + *stat = ((dir != XFS_LOOKUP_EQ) || (diff == 0)); + return 0; +} + +/* + * Move 1 record left from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_alloc_lshift( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to shift record on */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef DEBUG + int i; /* loop index */ +#endif + xfs_alloc_key_t key; /* key value for leaf level upward */ + xfs_buf_t *lbp; /* buffer for left neighbor block */ + xfs_alloc_block_t *left; /* left neighbor btree block */ + int nrec; /* new number of left block entries */ + xfs_buf_t *rbp; /* buffer for right (current) block */ + xfs_alloc_block_t *right; /* right (current) btree block */ + xfs_alloc_key_t *rkp=NULL; /* key pointer for right block */ + xfs_alloc_ptr_t *rpp=NULL; /* address pointer for right block */ + xfs_alloc_rec_t *rrp=NULL; /* record pointer for right block */ + + /* + * Set up variables for this block as "right". + */ + rbp = cur->bc_bufs[level]; + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + return error; +#endif + /* + * If we've got no left sibling then we can't shift an entry left. + */ + if (INT_GET(right->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * If the cursor entry is the one that would be moved, don't + * do it... it's too complicated. + */ + if (cur->bc_ptrs[level] <= 1) { + *stat = 0; + return 0; + } + /* + * Set up the left neighbor as "left". + */ + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.a.agno, INT_GET(right->bb_leftsib, ARCH_CONVERT), 0, &lbp, + XFS_ALLOC_BTREE_REF))) + return error; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; + /* + * If it's full, it can't take another entry. + */ + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { + *stat = 0; + return 0; + } + nrec = INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1; + /* + * If non-leaf, copy a key and a ptr to the left block. + */ + if (level > 0) { + xfs_alloc_key_t *lkp; /* key pointer for left block */ + xfs_alloc_ptr_t *lpp; /* address pointer for left block */ + + lkp = XFS_ALLOC_KEY_ADDR(left, nrec, cur); + rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur); + *lkp = *rkp; + xfs_alloc_log_keys(cur, lbp, nrec, nrec); + lpp = XFS_ALLOC_PTR_ADDR(left, nrec, cur); + rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, INT_GET(*rpp, ARCH_CONVERT), level))) + return error; +#endif + *lpp = *rpp; /* INT_: copy */ + xfs_alloc_log_ptrs(cur, lbp, nrec, nrec); + xfs_btree_check_key(cur->bc_btnum, lkp - 1, lkp); + } + /* + * If leaf, copy a record to the left block. + */ + else { + xfs_alloc_rec_t *lrp; /* record pointer for left block */ + + lrp = XFS_ALLOC_REC_ADDR(left, nrec, cur); + rrp = XFS_ALLOC_REC_ADDR(right, 1, cur); + *lrp = *rrp; + xfs_alloc_log_recs(cur, lbp, nrec, nrec); + xfs_btree_check_rec(cur->bc_btnum, lrp - 1, lrp); + } + /* + * Bump and log left's numrecs, decrement and log right's numrecs. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, +1); + xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); + INT_MOD(right->bb_numrecs, ARCH_CONVERT, -1); + xfs_alloc_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); + /* + * Slide the contents of right down one entry. + */ + if (level > 0) { +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i + 1], ARCH_CONVERT), + level))) + return error; + } +#endif + ovbcopy(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); + xfs_alloc_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_alloc_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } else { + ovbcopy(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_alloc_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + key.ar_startblock = rrp->ar_startblock; /* INT_: direct copy */ + key.ar_blockcount = rrp->ar_blockcount; /* INT_: direct copy */ + rkp = &key; + } + /* + * Update the parent key values of right. + */ + if ((error = xfs_alloc_updkey(cur, rkp, level + 1))) + return error; + /* + * Slide the cursor value left one. + */ + cur->bc_ptrs[level]--; + *stat = 1; + return 0; +} + +/* + * Allocate a new root block, fill it in. + */ +STATIC int /* error */ +xfs_alloc_newroot( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + xfs_agblock_t lbno; /* left block number */ + xfs_buf_t *lbp; /* left btree buffer */ + xfs_alloc_block_t *left; /* left btree block */ + xfs_mount_t *mp; /* mount structure */ + xfs_agblock_t nbno; /* new block number */ + xfs_buf_t *nbp; /* new (root) buffer */ + xfs_alloc_block_t *new; /* new (root) btree block */ + int nptr; /* new value for key index, 1 or 2 */ + xfs_agblock_t rbno; /* right block number */ + xfs_buf_t *rbp; /* right btree buffer */ + xfs_alloc_block_t *right; /* right btree block */ + + mp = cur->bc_mp; + + ASSERT(cur->bc_nlevels < XFS_AG_MAXLEVELS(mp)); + /* + * Get a buffer from the freelist blocks, for the new root. + */ + if ((error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp, + &nbno))) + return error; + /* + * None available, we fail. + */ + if (nbno == NULLAGBLOCK) { + *stat = 0; + return 0; + } + xfs_trans_agbtree_delta(cur->bc_tp, 1); + nbp = xfs_btree_get_bufs(mp, cur->bc_tp, cur->bc_private.a.agno, nbno, + 0); + new = XFS_BUF_TO_ALLOC_BLOCK(nbp); + /* + * Set the root data in the a.g. freespace structure. + */ + { + xfs_agf_t *agf; /* a.g. freespace header */ + xfs_agnumber_t seqno; + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + INT_SET(agf->agf_roots[cur->bc_btnum], ARCH_CONVERT, nbno); + INT_MOD(agf->agf_levels[cur->bc_btnum], ARCH_CONVERT, 1); + seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + mp->m_perag[seqno].pagf_levels[cur->bc_btnum]++; + xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, + XFS_AGF_ROOTS | XFS_AGF_LEVELS); + } + /* + * At the previous root level there are now two blocks: the old + * root, and the new block generated when it was split. + * We don't know which one the cursor is pointing at, so we + * set up variables "left" and "right" for each case. + */ + lbp = cur->bc_bufs[cur->bc_nlevels - 1]; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, cur->bc_nlevels - 1, lbp))) + return error; +#endif + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + /* + * Our block is left, pick up the right block. + */ + lbno = XFS_DADDR_TO_AGBNO(mp, XFS_BUF_ADDR(lbp)); + rbno = INT_GET(left->bb_rightsib, ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + cur->bc_private.a.agno, rbno, 0, &rbp, + XFS_ALLOC_BTREE_REF))) + return error; + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); + if ((error = xfs_btree_check_sblock(cur, right, + cur->bc_nlevels - 1, rbp))) + return error; + nptr = 1; + } else { + /* + * Our block is right, pick up the left block. + */ + rbp = lbp; + right = left; + rbno = XFS_DADDR_TO_AGBNO(mp, XFS_BUF_ADDR(rbp)); + lbno = INT_GET(right->bb_leftsib, ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + cur->bc_private.a.agno, lbno, 0, &lbp, + XFS_ALLOC_BTREE_REF))) + return error; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); + if ((error = xfs_btree_check_sblock(cur, left, + cur->bc_nlevels - 1, lbp))) + return error; + nptr = 2; + } + /* + * Fill in the new block's btree header and log it. + */ + INT_SET(new->bb_magic, ARCH_CONVERT, xfs_magics[cur->bc_btnum]); + INT_SET(new->bb_level, ARCH_CONVERT, (__uint16_t)cur->bc_nlevels); + INT_SET(new->bb_numrecs, ARCH_CONVERT, 2); + INT_SET(new->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(new->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + xfs_alloc_log_block(cur->bc_tp, nbp, XFS_BB_ALL_BITS); + ASSERT(lbno != NULLAGBLOCK && rbno != NULLAGBLOCK); + /* + * Fill in the key data in the new root. + */ + { + xfs_alloc_key_t *kp; /* btree key pointer */ + + kp = XFS_ALLOC_KEY_ADDR(new, 1, cur); + if (INT_GET(left->bb_level, ARCH_CONVERT) > 0) { + kp[0] = *XFS_ALLOC_KEY_ADDR(left, 1, cur); /* INT_: structure copy */ + kp[1] = *XFS_ALLOC_KEY_ADDR(right, 1, cur);/* INT_: structure copy */ + } else { + xfs_alloc_rec_t *rp; /* btree record pointer */ + + rp = XFS_ALLOC_REC_ADDR(left, 1, cur); + kp[0].ar_startblock = rp->ar_startblock; /* INT_: direct copy */ + kp[0].ar_blockcount = rp->ar_blockcount; /* INT_: direct copy */ + rp = XFS_ALLOC_REC_ADDR(right, 1, cur); + kp[1].ar_startblock = rp->ar_startblock; /* INT_: direct copy */ + kp[1].ar_blockcount = rp->ar_blockcount; /* INT_: direct copy */ + } + } + xfs_alloc_log_keys(cur, nbp, 1, 2); + /* + * Fill in the pointer data in the new root. + */ + { + xfs_alloc_ptr_t *pp; /* btree address pointer */ + + pp = XFS_ALLOC_PTR_ADDR(new, 1, cur); + INT_SET(pp[0], ARCH_CONVERT, lbno); + INT_SET(pp[1], ARCH_CONVERT, rbno); + } + xfs_alloc_log_ptrs(cur, nbp, 1, 2); + /* + * Fix up the cursor. + */ + xfs_btree_setbuf(cur, cur->bc_nlevels, nbp); + cur->bc_ptrs[cur->bc_nlevels] = nptr; + cur->bc_nlevels++; + *stat = 1; + return 0; +} + +/* + * Move 1 record right from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_alloc_rshift( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to shift record on */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* loop index */ + xfs_alloc_key_t key; /* key value for leaf level upward */ + xfs_buf_t *lbp; /* buffer for left (current) block */ + xfs_alloc_block_t *left; /* left (current) btree block */ + xfs_buf_t *rbp; /* buffer for right neighbor block */ + xfs_alloc_block_t *right; /* right neighbor btree block */ + xfs_alloc_key_t *rkp; /* key pointer for right block */ + xfs_btree_cur_t *tcur; /* temporary cursor */ + + /* + * Set up variables for this block as "left". + */ + lbp = cur->bc_bufs[level]; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; +#endif + /* + * If we've got no right sibling then we can't shift an entry right. + */ + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * If the cursor entry is the one that would be moved, don't + * do it... it's too complicated. + */ + if (cur->bc_ptrs[level] >= INT_GET(left->bb_numrecs, ARCH_CONVERT)) { + *stat = 0; + return 0; + } + /* + * Set up the right neighbor as "right". + */ + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.a.agno, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, &rbp, + XFS_ALLOC_BTREE_REF))) + return error; + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + return error; + /* + * If it's full, it can't take another entry. + */ + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { + *stat = 0; + return 0; + } + /* + * Make a hole at the start of the right neighbor block, then + * copy the last left block entry to the hole. + */ + if (level > 0) { + xfs_alloc_key_t *lkp; /* key pointer for left block */ + xfs_alloc_ptr_t *lpp; /* address pointer for left block */ + xfs_alloc_ptr_t *rpp; /* address pointer for right block */ + + lkp = XFS_ALLOC_KEY_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + lpp = XFS_ALLOC_PTR_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur); + rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1; i >= 0; i--) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + ovbcopy(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, INT_GET(*lpp, ARCH_CONVERT), level))) + return error; +#endif + *rkp = *lkp; /* INT_: copy */ + *rpp = *lpp; /* INT_: copy */ + xfs_alloc_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + xfs_alloc_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + xfs_btree_check_key(cur->bc_btnum, rkp, rkp + 1); + } else { + xfs_alloc_rec_t *lrp; /* record pointer for left block */ + xfs_alloc_rec_t *rrp; /* record pointer for right block */ + + lrp = XFS_ALLOC_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rrp = XFS_ALLOC_REC_ADDR(right, 1, cur); + ovbcopy(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + *rrp = *lrp; + xfs_alloc_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + key.ar_startblock = rrp->ar_startblock; /* INT_: direct copy */ + key.ar_blockcount = rrp->ar_blockcount; /* INT_: direct copy */ + rkp = &key; + xfs_btree_check_rec(cur->bc_btnum, rrp, rrp + 1); + } + /* + * Decrement and log left's numrecs, bump and log right's numrecs. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -1); + xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); + xfs_alloc_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); + /* + * Using a temporary cursor, update the parent key values of the + * block on the right. + */ + if ((error = xfs_btree_dup_cursor(cur, &tcur))) + return error; + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_increment(tcur, level, &i)) || + (error = xfs_alloc_updkey(tcur, rkp, level + 1))) + goto error0; + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + *stat = 1; + return 0; +error0: + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; +} + +/* + * Split cur/level block in half. + * Return new block number and its first record (to be inserted into parent). + */ +STATIC int /* error */ +xfs_alloc_split( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to split */ + xfs_agblock_t *bnop, /* output: block number allocated */ + xfs_alloc_key_t *keyp, /* output: first key of new block */ + xfs_btree_cur_t **curp, /* output: new cursor */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* loop index/record number */ + xfs_agblock_t lbno; /* left (current) block number */ + xfs_buf_t *lbp; /* buffer for left block */ + xfs_alloc_block_t *left; /* left (current) btree block */ + xfs_agblock_t rbno; /* right (new) block number */ + xfs_buf_t *rbp; /* buffer for right block */ + xfs_alloc_block_t *right; /* right (new) btree block */ + + /* + * Allocate the new block from the freelist. + * If we can't do it, we're toast. Give up. + */ + if ((error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp, + &rbno))) + return error; + if (rbno == NULLAGBLOCK) { + *stat = 0; + return 0; + } + xfs_trans_agbtree_delta(cur->bc_tp, 1); + rbp = xfs_btree_get_bufs(cur->bc_mp, cur->bc_tp, cur->bc_private.a.agno, + rbno, 0); + /* + * Set up the new block as "right". + */ + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); + /* + * "Left" is the current (according to the cursor) block. + */ + lbp = cur->bc_bufs[level]; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; +#endif + /* + * Fill in the btree header for the new block. + */ + INT_SET(right->bb_magic, ARCH_CONVERT, xfs_magics[cur->bc_btnum]); + right->bb_level = left->bb_level; /* INT_: direct copy */ + INT_SET(right->bb_numrecs, ARCH_CONVERT, (__uint16_t)(INT_GET(left->bb_numrecs, ARCH_CONVERT) / 2)); + /* + * Make sure that if there's an odd number of entries now, that + * each new block will have the same number of entries. + */ + if ((INT_GET(left->bb_numrecs, ARCH_CONVERT) & 1) && + cur->bc_ptrs[level] <= INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1) + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); + i = INT_GET(left->bb_numrecs, ARCH_CONVERT) - INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1; + /* + * For non-leaf blocks, copy keys and addresses over to the new block. + */ + if (level > 0) { + xfs_alloc_key_t *lkp; /* left btree key pointer */ + xfs_alloc_ptr_t *lpp; /* left btree address pointer */ + xfs_alloc_key_t *rkp; /* right btree key pointer */ + xfs_alloc_ptr_t *rpp; /* right btree address pointer */ + + lkp = XFS_ALLOC_KEY_ADDR(left, i, cur); + lpp = XFS_ALLOC_PTR_ADDR(left, i, cur); + rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur); + rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(lpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + bcopy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); /* INT_: copy */ + bcopy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));/* INT_: copy */ + xfs_alloc_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_alloc_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + *keyp = *rkp; + } + /* + * For leaf blocks, copy records over to the new block. + */ + else { + xfs_alloc_rec_t *lrp; /* left btree record pointer */ + xfs_alloc_rec_t *rrp; /* right btree record pointer */ + + lrp = XFS_ALLOC_REC_ADDR(left, i, cur); + rrp = XFS_ALLOC_REC_ADDR(right, 1, cur); + bcopy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_alloc_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + keyp->ar_startblock = rrp->ar_startblock; /* INT_: direct copy */ + keyp->ar_blockcount = rrp->ar_blockcount; /* INT_: direct copy */ + } + /* + * Find the left block number by looking in the buffer. + * Adjust numrecs, sibling pointers. + */ + lbno = XFS_DADDR_TO_AGBNO(cur->bc_mp, XFS_BUF_ADDR(lbp)); + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -(INT_GET(right->bb_numrecs, ARCH_CONVERT))); + right->bb_rightsib = left->bb_rightsib; /* INT_: direct copy */ + INT_SET(left->bb_rightsib, ARCH_CONVERT, rbno); + INT_SET(right->bb_leftsib, ARCH_CONVERT, lbno); + xfs_alloc_log_block(cur->bc_tp, rbp, XFS_BB_ALL_BITS); + xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); + /* + * If there's a block to the new block's right, make that block + * point back to right instead of to left. + */ + if (INT_GET(right->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_alloc_block_t *rrblock; /* rr btree block */ + xfs_buf_t *rrbp; /* buffer for rrblock */ + + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.a.agno, INT_GET(right->bb_rightsib, ARCH_CONVERT), 0, + &rrbp, XFS_ALLOC_BTREE_REF))) + return error; + rrblock = XFS_BUF_TO_ALLOC_BLOCK(rrbp); + if ((error = xfs_btree_check_sblock(cur, rrblock, level, rrbp))) + return error; + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, rbno); + xfs_alloc_log_block(cur->bc_tp, rrbp, XFS_BB_LEFTSIB); + } + /* + * If the cursor is really in the right block, move it there. + * If it's just pointing past the last entry in left, then we'll + * insert there, so don't change anything in that case. + */ + if (cur->bc_ptrs[level] > INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1) { + xfs_btree_setbuf(cur, level, rbp); + cur->bc_ptrs[level] -= INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + /* + * If there are more levels, we'll need another cursor which refers to + * the right block, no matter where this cursor was. + */ + if (level + 1 < cur->bc_nlevels) { + if ((error = xfs_btree_dup_cursor(cur, curp))) + return error; + (*curp)->bc_ptrs[level + 1]++; + } + *bnop = rbno; + *stat = 1; + return 0; +} + +/* + * Update keys at all levels from here to the root along the cursor's path. + */ +STATIC int /* error */ +xfs_alloc_updkey( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_alloc_key_t *keyp, /* new key value to update to */ + int level) /* starting level for update */ +{ + int ptr; /* index of key in block */ + + /* + * Go up the tree from this level toward the root. + * At each level, update the key value to the value input. + * Stop when we reach a level where the cursor isn't pointing + * at the first entry in the block. + */ + for (ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) { + xfs_alloc_block_t *block; /* btree block */ + xfs_buf_t *bp; /* buffer for block */ +#ifdef DEBUG + int error; /* error return value */ +#endif + xfs_alloc_key_t *kp; /* ptr to btree block keys */ + + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; +#endif + ptr = cur->bc_ptrs[level]; + kp = XFS_ALLOC_KEY_ADDR(block, ptr, cur); + *kp = *keyp; + xfs_alloc_log_keys(cur, bp, ptr, ptr); + } + return 0; +} + +/* + * Externally visible routines. + */ + +/* + * Decrement cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_alloc_decrement( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat) /* success/failure */ +{ + xfs_alloc_block_t *block; /* btree block */ + int error; /* error return value */ + int lev; /* btree level */ + + ASSERT(level < cur->bc_nlevels); + /* + * Read-ahead to the left at this level. + */ + xfs_btree_readahead(cur, level, XFS_BTCUR_LEFTRA); + /* + * Decrement the ptr at this level. If we're still in the block + * then we're done. + */ + if (--cur->bc_ptrs[level] > 0) { + *stat = 1; + return 0; + } + /* + * Get a pointer to the btree block. + */ + block = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[level]); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, + cur->bc_bufs[level]))) + return error; +#endif + /* + * If we just went off the left edge of the tree, return failure. + */ + if (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * March up the tree decrementing pointers. + * Stop when we don't go off the left edge of a block. + */ + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + if (--cur->bc_ptrs[lev] > 0) + break; + /* + * Read-ahead the left block, we're going to read it + * in the next loop. + */ + xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA); + } + /* + * If we went off the root then we are seriously confused. + */ + ASSERT(lev < cur->bc_nlevels); + /* + * Now walk back down the tree, fixing up the cursor's buffer + * pointers and key numbers. + */ + for (block = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[lev]); lev > level; ) { + xfs_agblock_t agbno; /* block number of btree block */ + xfs_buf_t *bp; /* buffer pointer for block */ + + agbno = INT_GET(*XFS_ALLOC_PTR_ADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.a.agno, agbno, 0, &bp, + XFS_ALLOC_BTREE_REF))) + return error; + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; + cur->bc_ptrs[lev] = INT_GET(block->bb_numrecs, ARCH_CONVERT); + } + *stat = 1; + return 0; +} + +/* + * Delete the record pointed to by cur. + * The cursor refers to the place where the record was (could be inserted) + * when the operation returns. + */ +int /* error */ +xfs_alloc_delete( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* result code */ + int level; /* btree level */ + + /* + * Go up the tree, starting at leaf level. + * If 2 is returned then a join was done; go to the next level. + * Otherwise we are done. + */ + for (level = 0, i = 2; i == 2; level++) { + if ((error = xfs_alloc_delrec(cur, level, &i))) + return error; + } + if (i == 0) { + for (level = 1; level < cur->bc_nlevels; level++) { + if (cur->bc_ptrs[level] == 0) { + if ((error = xfs_alloc_decrement(cur, level, &i))) + return error; + break; + } + } + } + *stat = i; + return 0; +} + +/* + * Get the data from the pointed-to record. + */ +int /* error */ +xfs_alloc_get_rec( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t *bno, /* output: starting block of extent */ + xfs_extlen_t *len, /* output: length of extent */ + int *stat) /* output: success/failure */ +{ + xfs_alloc_block_t *block; /* btree block */ +#ifdef DEBUG + int error; /* error return value */ +#endif + int ptr; /* record number */ + + ptr = cur->bc_ptrs[0]; + block = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[0]); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, 0, cur->bc_bufs[0]))) + return error; +#endif + /* + * Off the right end or left end, return failure. + */ + if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT) || ptr <= 0) { + *stat = 0; + return 0; + } + /* + * Point to the record and extract its data. + */ + { + xfs_alloc_rec_t *rec; /* record data */ + + rec = XFS_ALLOC_REC_ADDR(block, ptr, cur); + *bno = INT_GET(rec->ar_startblock, ARCH_CONVERT); + *len = INT_GET(rec->ar_blockcount, ARCH_CONVERT); + } + *stat = 1; + return 0; +} + +/* + * Increment cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_alloc_increment( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat) /* success/failure */ +{ + xfs_alloc_block_t *block; /* btree block */ + xfs_buf_t *bp; /* tree block buffer */ + int error; /* error return value */ + int lev; /* btree level */ + + ASSERT(level < cur->bc_nlevels); + /* + * Read-ahead to the right at this level. + */ + xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); + /* + * Get a pointer to the btree block. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; +#endif + /* + * Increment the ptr at this level. If we're still in the block + * then we're done. + */ + if (++cur->bc_ptrs[level] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + *stat = 1; + return 0; + } + /* + * If we just went off the right edge of the tree, return failure. + */ + if (INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * March up the tree incrementing pointers. + * Stop when we don't go off the right edge of a block. + */ + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + bp = cur->bc_bufs[lev]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; +#endif + if (++cur->bc_ptrs[lev] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) + break; + /* + * Read-ahead the right block, we're going to read it + * in the next loop. + */ + xfs_btree_readahead(cur, lev, XFS_BTCUR_RIGHTRA); + } + /* + * If we went off the root then we are seriously confused. + */ + ASSERT(lev < cur->bc_nlevels); + /* + * Now walk back down the tree, fixing up the cursor's buffer + * pointers and key numbers. + */ + for (bp = cur->bc_bufs[lev], block = XFS_BUF_TO_ALLOC_BLOCK(bp); + lev > level; ) { + xfs_agblock_t agbno; /* block number of btree block */ + + agbno = INT_GET(*XFS_ALLOC_PTR_ADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.a.agno, agbno, 0, &bp, + XFS_ALLOC_BTREE_REF))) + return error; + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; + cur->bc_ptrs[lev] = 1; + } + *stat = 1; + return 0; +} + +/* + * Insert the current record at the point referenced by cur. + * The cursor may be inconsistent on return if splits have been done. + */ +int /* error */ +xfs_alloc_insert( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* result value, 0 for failure */ + int level; /* current level number in btree */ + xfs_agblock_t nbno; /* new block number (split result) */ + xfs_btree_cur_t *ncur; /* new cursor (split result) */ + xfs_alloc_rec_t nrec; /* record being inserted this level */ + xfs_btree_cur_t *pcur; /* previous level's cursor */ + + level = 0; + nbno = NULLAGBLOCK; + INT_SET(nrec.ar_startblock, ARCH_CONVERT, cur->bc_rec.a.ar_startblock); + INT_SET(nrec.ar_blockcount, ARCH_CONVERT, cur->bc_rec.a.ar_blockcount); + ncur = (xfs_btree_cur_t *)0; + pcur = cur; + /* + * Loop going up the tree, starting at the leaf level. + * Stop when we don't get a split block, that must mean that + * the insert is finished with this level. + */ + do { + /* + * Insert nrec/nbno into this level of the tree. + * Note if we fail, nbno will be null. + */ + if ((error = xfs_alloc_insrec(pcur, level++, &nbno, &nrec, &ncur, + &i))) { + if (pcur != cur) + xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); + return error; + } + /* + * See if the cursor we just used is trash. + * Can't trash the caller's cursor, but otherwise we should + * if ncur is a new cursor or we're about to be done. + */ + if (pcur != cur && (ncur || nbno == NULLAGBLOCK)) { + cur->bc_nlevels = pcur->bc_nlevels; + xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); + } + /* + * If we got a new cursor, switch to it. + */ + if (ncur) { + pcur = ncur; + ncur = (xfs_btree_cur_t *)0; + } + } while (nbno != NULLAGBLOCK); + *stat = i; + return 0; +} + +/* + * Lookup the record equal to [bno, len] in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_eq( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat) /* success/failure */ +{ + cur->bc_rec.a.ar_startblock = bno; + cur->bc_rec.a.ar_blockcount = len; + return xfs_alloc_lookup(cur, XFS_LOOKUP_EQ, stat); +} + +/* + * Lookup the first record greater than or equal to [bno, len] + * in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_ge( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat) /* success/failure */ +{ + cur->bc_rec.a.ar_startblock = bno; + cur->bc_rec.a.ar_blockcount = len; + return xfs_alloc_lookup(cur, XFS_LOOKUP_GE, stat); +} + +/* + * Lookup the first record less than or equal to [bno, len] + * in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_le( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat) /* success/failure */ +{ + cur->bc_rec.a.ar_startblock = bno; + cur->bc_rec.a.ar_blockcount = len; + return xfs_alloc_lookup(cur, XFS_LOOKUP_LE, stat); +} + +/* + * Update the record referred to by cur, to the value given by [bno, len]. + * This either works (return 0) or gets an EFSCORRUPTED error. + */ +int /* error */ +xfs_alloc_update( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len) /* length of extent */ +{ + xfs_alloc_block_t *block; /* btree block to update */ + int error; /* error return value */ + int ptr; /* current record number (updating) */ + + ASSERT(len > 0); + /* + * Pick up the a.g. freelist struct and the current block. + */ + block = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[0]); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, 0, cur->bc_bufs[0]))) + return error; +#endif + /* + * Get the address of the rec to be updated. + */ + ptr = cur->bc_ptrs[0]; + { + xfs_alloc_rec_t *rp; /* pointer to updated record */ + + rp = XFS_ALLOC_REC_ADDR(block, ptr, cur); + /* + * Fill in the new contents and log them. + */ + INT_SET(rp->ar_startblock, ARCH_CONVERT, bno); + INT_SET(rp->ar_blockcount, ARCH_CONVERT, len); + xfs_alloc_log_recs(cur, cur->bc_bufs[0], ptr, ptr); + } + /* + * If it's the by-size btree and it's the last leaf block and + * it's the last record... then update the size of the longest + * extent in the a.g., which we cache in the a.g. freelist header. + */ + if (cur->bc_btnum == XFS_BTNUM_CNT && + INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK && + ptr == INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + xfs_agf_t *agf; /* a.g. freespace header */ + xfs_agnumber_t seqno; + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + cur->bc_mp->m_perag[seqno].pagf_longest = len; + INT_SET(agf->agf_longest, ARCH_CONVERT, len); + xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, + XFS_AGF_LONGEST); + } + /* + * Updating first record in leaf. Pass new key value up to our parent. + */ + if (ptr == 1) { + xfs_alloc_key_t key; /* key containing [bno, len] */ + + INT_SET(key.ar_startblock, ARCH_CONVERT, bno); + INT_SET(key.ar_blockcount, ARCH_CONVERT, len); + if ((error = xfs_alloc_updkey(cur, &key, 1))) + return error; + } + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_attr_leaf.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_attr_leaf.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_attr_leaf.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_attr_leaf.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,1169 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * xfs_attr_leaf.c + * + * Routines to implement leaf blocks of attributes as Btrees of hashed names. + */ + +/*======================================================================== + * Routines used for growing the Btree. + *========================================================================*/ + +/* + * Create the initial contents of a leaf attribute list + * or a leaf in a node attribute list. + */ +int +xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_hdr_t *hdr; + xfs_inode_t *dp; + xfs_dabuf_t *bp; + int error; + + dp = args->dp; + ASSERT(dp != NULL); + error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp, + XFS_ATTR_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + leaf = bp->data; + bzero((char *)leaf, XFS_LBSIZE(dp->i_mount)); + hdr = &leaf->hdr; + INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_ATTR_LEAF_MAGIC); + INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount)); + if (INT_GET(hdr->firstused, ARCH_CONVERT) == 0) { + INT_SET(hdr->firstused, ARCH_CONVERT, + XFS_LBSIZE(dp->i_mount) - XFS_ATTR_LEAF_NAME_ALIGN); + } + + INT_SET(hdr->freemap[0].base, ARCH_CONVERT, + sizeof(xfs_attr_leaf_hdr_t)); + INT_SET(hdr->freemap[0].size, ARCH_CONVERT, + INT_GET(hdr->firstused, ARCH_CONVERT) + - INT_GET(hdr->freemap[0].base, + ARCH_CONVERT)); + + xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1); + + *bpp = bp; + return(0); +} + +/* + * Split the leaf node, rebalance, then add the new entry. + */ +int +xfs_attr_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, + xfs_da_state_blk_t *newblk) +{ + xfs_dablk_t blkno; + int error; + + /* + * Allocate space for a new leaf node. + */ + ASSERT(oldblk->magic == XFS_ATTR_LEAF_MAGIC); + error = xfs_da_grow_inode(state->args, &blkno); + if (error) + return(error); + error = xfs_attr_leaf_create(state->args, blkno, &newblk->bp); + if (error) + return(error); + newblk->blkno = blkno; + newblk->magic = XFS_ATTR_LEAF_MAGIC; + + /* + * Rebalance the entries across the two leaves. + * NOTE: rebalance() currently depends on the 2nd block being empty. + */ + xfs_attr_leaf_rebalance(state, oldblk, newblk); + error = xfs_da_blk_link(state, oldblk, newblk); + if (error) + return(error); + + /* + * Save info on "old" attribute for "atomic rename" ops, leaf_add() + * modifies the index/blkno/rmtblk/rmtblkcnt fields to show the + * "new" attrs info. Will need the "old" info to remove it later. + * + * Insert the "new" entry in the correct block. + */ + if (state->inleaf) + error = xfs_attr_leaf_add(oldblk->bp, state->args); + else + error = xfs_attr_leaf_add(newblk->bp, state->args); + + /* + * Update last hashval in each block since we added the name. + */ + oldblk->hashval = xfs_attr_leaf_lasthash(oldblk->bp, NULL); + newblk->hashval = xfs_attr_leaf_lasthash(newblk->bp, NULL); + return(error); +} + +/* + * Add a name to the leaf attribute list structure. + */ +int +xfs_attr_leaf_add(xfs_dabuf_t *bp, xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_hdr_t *hdr; + xfs_attr_leaf_map_t *map; + int tablesize, entsize, sum, tmp, i; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT((args->index >= 0) + && (args->index <= INT_GET(leaf->hdr.count, ARCH_CONVERT))); + hdr = &leaf->hdr; + entsize = xfs_attr_leaf_newentsize(args, + args->trans->t_mountp->m_sb.sb_blocksize, NULL); + + /* + * Search through freemap for first-fit on new name length. + * (may need to figure in size of entry struct too) + */ + tablesize = (INT_GET(hdr->count, ARCH_CONVERT) + 1) + * sizeof(xfs_attr_leaf_entry_t) + + sizeof(xfs_attr_leaf_hdr_t); + map = &hdr->freemap[XFS_ATTR_LEAF_MAPSIZE-1]; + for (sum = 0, i = XFS_ATTR_LEAF_MAPSIZE-1; i >= 0; map--, i--) { + if (tablesize > INT_GET(hdr->firstused, ARCH_CONVERT)) { + sum += INT_GET(map->size, ARCH_CONVERT); + continue; + } + if (INT_GET(map->size, ARCH_CONVERT) == 0) + continue; /* no space in this map */ + tmp = entsize; + if (INT_GET(map->base, ARCH_CONVERT) + < INT_GET(hdr->firstused, ARCH_CONVERT)) + tmp += sizeof(xfs_attr_leaf_entry_t); + if (INT_GET(map->size, ARCH_CONVERT) >= tmp) { + tmp = xfs_attr_leaf_add_work(bp, args, i); + return(tmp); + } + sum += INT_GET(map->size, ARCH_CONVERT); + } + + /* + * If there are no holes in the address space of the block, + * and we don't have enough freespace, then compaction will do us + * no good and we should just give up. + */ + if (!hdr->holes && (sum < entsize)) + return(XFS_ERROR(ENOSPC)); + + /* + * Compact the entries to coalesce free space. + * This may change the hdr->count via dropping INCOMPLETE entries. + */ + xfs_attr_leaf_compact(args->trans, bp); + + /* + * After compaction, the block is guaranteed to have only one + * free region, in freemap[0]. If it is not big enough, give up. + */ + if (INT_GET(hdr->freemap[0].size, ARCH_CONVERT) + < (entsize + sizeof(xfs_attr_leaf_entry_t))) + return(XFS_ERROR(ENOSPC)); + + return(xfs_attr_leaf_add_work(bp, args, 0)); +} + +/* + * Add a name to a leaf attribute list structure. + */ +STATIC int +xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_hdr_t *hdr; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_local_t *name_loc; + xfs_attr_leaf_name_remote_t *name_rmt; + xfs_attr_leaf_map_t *map; + xfs_mount_t *mp; + int tmp, i; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + hdr = &leaf->hdr; + ASSERT((mapindex >= 0) && (mapindex < XFS_ATTR_LEAF_MAPSIZE)); + ASSERT((args->index >= 0) + && (args->index <= INT_GET(hdr->count, ARCH_CONVERT))); + + /* + * Force open some space in the entry array and fill it in. + */ + entry = &leaf->entries[args->index]; + if (args->index < INT_GET(hdr->count, ARCH_CONVERT)) { + tmp = INT_GET(hdr->count, ARCH_CONVERT) - args->index; + tmp *= sizeof(xfs_attr_leaf_entry_t); + ovbcopy((char *)entry, (char *)(entry+1), tmp); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry))); + } + INT_MOD(hdr->count, ARCH_CONVERT, 1); + + /* + * Allocate space for the new string (at the end of the run). + */ + map = &hdr->freemap[mapindex]; + mp = args->trans->t_mountp; + ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT((INT_GET(map->base, ARCH_CONVERT) & 0x3) == 0); + ASSERT(INT_GET(map->size, ARCH_CONVERT) + >= xfs_attr_leaf_newentsize(args, + mp->m_sb.sb_blocksize, NULL)); + ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT((INT_GET(map->size, ARCH_CONVERT) & 0x3) == 0); + INT_MOD(map->size, ARCH_CONVERT, + -xfs_attr_leaf_newentsize(args, mp->m_sb.sb_blocksize, &tmp)); + INT_SET(entry->nameidx, ARCH_CONVERT, + INT_GET(map->base, ARCH_CONVERT) + + INT_GET(map->size, ARCH_CONVERT)); + INT_SET(entry->hashval, ARCH_CONVERT, args->hashval); + entry->flags = tmp ? XFS_ATTR_LOCAL : 0; + entry->flags |= (args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0; + if (args->rename) { + entry->flags |= XFS_ATTR_INCOMPLETE; + if ((args->blkno2 == args->blkno) && + (args->index2 <= args->index)) { + args->index2++; + } + } + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); + ASSERT((args->index == 0) || (INT_GET(entry->hashval, ARCH_CONVERT) + >= INT_GET((entry-1)->hashval, + ARCH_CONVERT))); + ASSERT((args->index == INT_GET(hdr->count, ARCH_CONVERT)-1) || + (INT_GET(entry->hashval, ARCH_CONVERT) + <= (INT_GET((entry+1)->hashval, ARCH_CONVERT)))); + + /* + * Copy the attribute name and value into the new space. + * + * For "remote" attribute values, simply note that we need to + * allocate space for the "remote" value. We can't actually + * allocate the extents in this transaction, and we can't decide + * which blocks they should be as we might allocate more blocks + * as part of this transaction (a split operation for example). + */ + if (entry->flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index); + name_loc->namelen = args->namelen; + INT_SET(name_loc->valuelen, ARCH_CONVERT, args->valuelen); + bcopy(args->name, (char *)name_loc->nameval, args->namelen); + bcopy(args->value, (char *)&name_loc->nameval[args->namelen], + INT_GET(name_loc->valuelen, ARCH_CONVERT)); + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); + name_rmt->namelen = args->namelen; + bcopy(args->name, (char *)name_rmt->name, args->namelen); + entry->flags |= XFS_ATTR_INCOMPLETE; + /* just in case */ + INT_SET(name_rmt->valuelen, ARCH_CONVERT, 0); + INT_SET(name_rmt->valueblk, ARCH_CONVERT, 0); + args->rmtblkno = 1; + args->rmtblkcnt = XFS_B_TO_FSB(mp, args->valuelen); + } + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, XFS_ATTR_LEAF_NAME(leaf, args->index), + xfs_attr_leaf_entsize(leaf, args->index))); + + /* + * Update the control info for this leaf node + */ + if (INT_GET(entry->nameidx, ARCH_CONVERT) + < INT_GET(hdr->firstused, ARCH_CONVERT)) { + INT_SET(hdr->firstused, ARCH_CONVERT, + INT_GET(entry->nameidx, ARCH_CONVERT)); + } + ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) + >= ((INT_GET(hdr->count, ARCH_CONVERT) + * sizeof(*entry))+sizeof(*hdr))); + tmp = (INT_GET(hdr->count, ARCH_CONVERT)-1) + * sizeof(xfs_attr_leaf_entry_t) + + sizeof(xfs_attr_leaf_hdr_t); + map = &hdr->freemap[0]; + for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; map++, i++) { + if (INT_GET(map->base, ARCH_CONVERT) == tmp) { + INT_MOD(map->base, ARCH_CONVERT, + sizeof(xfs_attr_leaf_entry_t)); + INT_MOD(map->size, ARCH_CONVERT, + -sizeof(xfs_attr_leaf_entry_t)); + } + } + INT_MOD(hdr->usedbytes, ARCH_CONVERT, + xfs_attr_leaf_entsize(leaf, args->index)); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); + return(0); +} + +/* + * Garbage collect a leaf attribute list block by copying it to a new buffer. + */ +STATIC void +xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp) +{ + xfs_attr_leafblock_t *leaf_s, *leaf_d; + xfs_attr_leaf_hdr_t *hdr_s, *hdr_d; + xfs_mount_t *mp; + char *tmpbuffer; + + mp = trans->t_mountp; + tmpbuffer = kmem_alloc(XFS_LBSIZE(mp), KM_SLEEP); + ASSERT(tmpbuffer != NULL); + bcopy(bp->data, tmpbuffer, XFS_LBSIZE(mp)); + bzero(bp->data, XFS_LBSIZE(mp)); + + /* + * Copy basic information + */ + leaf_s = (xfs_attr_leafblock_t *)tmpbuffer; + leaf_d = bp->data; + hdr_s = &leaf_s->hdr; + hdr_d = &leaf_d->hdr; + hdr_d->info = hdr_s->info; /* struct copy */ + INT_SET(hdr_d->firstused, ARCH_CONVERT, XFS_LBSIZE(mp)); + /* handle truncation gracefully */ + if (INT_GET(hdr_d->firstused, ARCH_CONVERT) == 0) { + INT_SET(hdr_d->firstused, ARCH_CONVERT, + XFS_LBSIZE(mp) - XFS_ATTR_LEAF_NAME_ALIGN); + } + INT_SET(hdr_d->usedbytes, ARCH_CONVERT, 0); + INT_SET(hdr_d->count, ARCH_CONVERT, 0); + hdr_d->holes = 0; + INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, + sizeof(xfs_attr_leaf_hdr_t)); + INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, + INT_GET(hdr_d->firstused, ARCH_CONVERT) + - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); + + /* + * Copy all entry's in the same (sorted) order, + * but allocate name/value pairs packed and in sequence. + */ + xfs_attr_leaf_moveents(leaf_s, 0, leaf_d, 0, + (int)INT_GET(hdr_s->count, ARCH_CONVERT), mp); + + xfs_da_log_buf(trans, bp, 0, XFS_LBSIZE(mp) - 1); + + kmem_free(tmpbuffer, XFS_LBSIZE(mp)); +} + +/* + * Redistribute the attribute list entries between two leaf nodes, + * taking into account the size of the new entry. + * + * NOTE: if new block is empty, then it will get the upper half of the + * old block. At present, all (one) callers pass in an empty second block. + * + * This code adjusts the args->index/blkno and args->index2/blkno2 fields + * to match what it is doing in splitting the attribute leaf block. Those + * values are used in "atomic rename" operations on attributes. Note that + * the "new" and "old" values can end up in different blocks. + */ +STATIC void +xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2) +{ + xfs_da_args_t *args; + xfs_da_state_blk_t *tmp_blk; + xfs_attr_leafblock_t *leaf1, *leaf2; + xfs_attr_leaf_hdr_t *hdr1, *hdr2; + int count, totallen, max, space, swap; + + /* + * Set up environment. + */ + ASSERT(blk1->magic == XFS_ATTR_LEAF_MAGIC); + ASSERT(blk2->magic == XFS_ATTR_LEAF_MAGIC); + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + args = state->args; + + /* + * Check ordering of blocks, reverse if it makes things simpler. + * + * NOTE: Given that all (current) callers pass in an empty + * second block, this code should never set "swap". + */ + swap = 0; + if (xfs_attr_leaf_order(blk1->bp, blk2->bp)) { + tmp_blk = blk1; + blk1 = blk2; + blk2 = tmp_blk; + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + swap = 1; + } + hdr1 = &leaf1->hdr; + hdr2 = &leaf2->hdr; + + /* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. Then get + * the direction to copy and the number of elements to move. + * + * "inleaf" is true if the new entry should be inserted into blk1. + * If "swap" is also true, then reverse the sense of "inleaf". + */ + state->inleaf = xfs_attr_leaf_figure_balance(state, blk1, blk2, + &count, &totallen); + if (swap) + state->inleaf = !state->inleaf; + + /* + * Move any entries required from leaf to leaf: + */ + if (count < INT_GET(hdr1->count, ARCH_CONVERT)) { + /* + * Figure the total bytes to be added to the destination leaf. + */ + /* number entries being moved */ + count = INT_GET(hdr1->count, ARCH_CONVERT) - count; + space = INT_GET(hdr1->usedbytes, ARCH_CONVERT) - totallen; + space += count * sizeof(xfs_attr_leaf_entry_t); + + /* + * leaf2 is the destination, compact it if it looks tight. + */ + max = INT_GET(hdr2->firstused, ARCH_CONVERT) + - sizeof(xfs_attr_leaf_hdr_t); + max -= INT_GET(hdr2->count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t); + if (space > max) { + xfs_attr_leaf_compact(args->trans, blk2->bp); + } + + /* + * Move high entries from leaf1 to low end of leaf2. + */ + xfs_attr_leaf_moveents(leaf1, + INT_GET(hdr1->count, ARCH_CONVERT)-count, + leaf2, 0, count, state->mp); + + xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1); + xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1); + } else if (count > INT_GET(hdr1->count, ARCH_CONVERT)) { + /* + * I assert that since all callers pass in an empty + * second buffer, this code should never execute. + */ + + /* + * Figure the total bytes to be added to the destination leaf. + */ + /* number entries being moved */ + count -= INT_GET(hdr1->count, ARCH_CONVERT); + space = totallen - INT_GET(hdr1->usedbytes, ARCH_CONVERT); + space += count * sizeof(xfs_attr_leaf_entry_t); + + /* + * leaf1 is the destination, compact it if it looks tight. + */ + max = INT_GET(hdr1->firstused, ARCH_CONVERT) + - sizeof(xfs_attr_leaf_hdr_t); + max -= INT_GET(hdr1->count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t); + if (space > max) { + xfs_attr_leaf_compact(args->trans, blk1->bp); + } + + /* + * Move low entries from leaf2 to high end of leaf1. + */ + xfs_attr_leaf_moveents(leaf2, 0, leaf1, + (int)INT_GET(hdr1->count, ARCH_CONVERT), count, + state->mp); + + xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1); + xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1); + } + + /* + * Copy out last hashval in each block for B-tree code. + */ + blk1->hashval = + INT_GET(leaf1->entries[INT_GET(leaf1->hdr.count, + ARCH_CONVERT)-1].hashval, ARCH_CONVERT); + blk2->hashval = + INT_GET(leaf2->entries[INT_GET(leaf2->hdr.count, + ARCH_CONVERT)-1].hashval, ARCH_CONVERT); + + /* + * Adjust the expected index for insertion. + * NOTE: this code depends on the (current) situation that the + * second block was originally empty. + * + * If the insertion point moved to the 2nd block, we must adjust + * the index. We must also track the entry just following the + * new entry for use in an "atomic rename" operation, that entry + * is always the "old" entry and the "new" entry is what we are + * inserting. The index/blkno fields refer to the "old" entry, + * while the index2/blkno2 fields refer to the "new" entry. + */ + if (blk1->index > INT_GET(leaf1->hdr.count, ARCH_CONVERT)) { + ASSERT(state->inleaf == 0); + blk2->index = blk1->index + - INT_GET(leaf1->hdr.count, ARCH_CONVERT); + args->index = args->index2 = blk2->index; + args->blkno = args->blkno2 = blk2->blkno; + } else if (blk1->index == INT_GET(leaf1->hdr.count, ARCH_CONVERT)) { + if (state->inleaf) { + args->index = blk1->index; + args->blkno = blk1->blkno; + args->index2 = 0; + args->blkno2 = blk2->blkno; + } else { + blk2->index = blk1->index + - INT_GET(leaf1->hdr.count, ARCH_CONVERT); + args->index = args->index2 = blk2->index; + args->blkno = args->blkno2 = blk2->blkno; + } + } else { + ASSERT(state->inleaf == 1); + args->index = args->index2 = blk1->index; + args->blkno = args->blkno2 = blk1->blkno; + } +} + +/* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. + * GROT: Is this really necessary? With other than a 512 byte blocksize, + * GROT: there will always be enough room in either block for a new entry. + * GROT: Do a double-split for this case? + */ +STATIC int +xfs_attr_leaf_figure_balance(xfs_da_state_t *state, + xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2, + int *countarg, int *usedbytesarg) +{ + xfs_attr_leafblock_t *leaf1, *leaf2; + xfs_attr_leaf_hdr_t *hdr1, *hdr2; + xfs_attr_leaf_entry_t *entry; + int count, max, index, totallen, half; + int lastdelta, foundit, tmp; + + /* + * Set up environment. + */ + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + hdr1 = &leaf1->hdr; + hdr2 = &leaf2->hdr; + foundit = 0; + totallen = 0; + + /* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. + */ + max = INT_GET(hdr1->count, ARCH_CONVERT) + + INT_GET(hdr2->count, ARCH_CONVERT); + half = (max+1) * sizeof(*entry); + half += INT_GET(hdr1->usedbytes, ARCH_CONVERT) + + INT_GET(hdr2->usedbytes, ARCH_CONVERT) + + xfs_attr_leaf_newentsize(state->args, + state->blocksize, NULL); + half /= 2; + lastdelta = state->blocksize; + entry = &leaf1->entries[0]; + for (count = index = 0; count < max; entry++, index++, count++) { + +#define XFS_ATTR_ABS(A) (((A) < 0) ? -(A) : (A)) + /* + * The new entry is in the first block, account for it. + */ + if (count == blk1->index) { + tmp = totallen + sizeof(*entry) + + xfs_attr_leaf_newentsize(state->args, + state->blocksize, + NULL); + if (XFS_ATTR_ABS(half - tmp) > lastdelta) + break; + lastdelta = XFS_ATTR_ABS(half - tmp); + totallen = tmp; + foundit = 1; + } + + /* + * Wrap around into the second block if necessary. + */ + if (count == INT_GET(hdr1->count, ARCH_CONVERT)) { + leaf1 = leaf2; + entry = &leaf1->entries[0]; + index = 0; + } + + /* + * Figure out if next leaf entry would be too much. + */ + tmp = totallen + sizeof(*entry) + xfs_attr_leaf_entsize(leaf1, + index); + if (XFS_ATTR_ABS(half - tmp) > lastdelta) + break; + lastdelta = XFS_ATTR_ABS(half - tmp); + totallen = tmp; +#undef XFS_ATTR_ABS + } + + /* + * Calculate the number of usedbytes that will end up in lower block. + * If new entry not in lower block, fix up the count. + */ + totallen -= count * sizeof(*entry); + if (foundit) { + totallen -= sizeof(*entry) + + xfs_attr_leaf_newentsize(state->args, + state->blocksize, + NULL); + } + + *countarg = count; + *usedbytesarg = totallen; + return(foundit); +} + +/*======================================================================== + * Routines used for shrinking the Btree. + *========================================================================*/ + +/* + * Check a leaf block and its neighbors to see if the block should be + * collapsed into one or the other neighbor. Always keep the block + * with the smaller block number. + * If the current block is over 50% full, don't try to join it, return 0. + * If the block is empty, fill in the state structure and return 2. + * If it can be collapsed, fill in the state structure and return 1. + * If nothing can be done, return 0. + * + * GROT: allow for INCOMPLETE entries in calculation. + */ +int +xfs_attr_leaf_toosmall(xfs_da_state_t *state, int *action) +{ + xfs_attr_leafblock_t *leaf; + xfs_da_state_blk_t *blk; + xfs_da_blkinfo_t *info; + int count, bytes, forward, error, retval, i; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + + /* + * Check for the degenerate case of the block being over 50% full. + * If so, it's not worth even looking to see if we might be able + * to coalesce with a sibling. + */ + blk = &state->path.blk[ state->path.active-1 ]; + info = blk->bp->data; + ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); + leaf = (xfs_attr_leafblock_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes = sizeof(xfs_attr_leaf_hdr_t) + + count * sizeof(xfs_attr_leaf_entry_t) + + INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); + if (bytes > (state->blocksize >> 1)) { + *action = 0; /* blk over 50%, dont try to join */ + return(0); + } + + /* + * Check for the degenerate case of the block being empty. + * If the block is empty, we'll simply delete it, no need to + * coalesce it with a sibling block. We choose (aribtrarily) + * to merge with the forward block unless it is NULL. + */ + if (count == 0) { + /* + * Make altpath point to the block we want to keep and + * path point to the block we want to drop (this one). + */ + forward = (INT_GET(info->forw, ARCH_CONVERT) != 0); + bcopy(&state->path, &state->altpath, sizeof(state->path)); + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + if (error) + return(error); + if (retval) { + *action = 0; + } else { + *action = 2; + } + return(0); + } + + /* + * Examine each sibling block to see if we can coalesce with + * at least 25% free space to spare. We need to figure out + * whether to merge with the forward or the backward block. + * We prefer coalescing with the lower numbered sibling so as + * to shrink an attribute list over time. + */ + /* start with smaller blk num */ + forward = (INT_GET(info->forw, ARCH_CONVERT) + < INT_GET(info->back, ARCH_CONVERT)); + for (i = 0; i < 2; forward = !forward, i++) { + if (forward) + blkno = INT_GET(info->forw, ARCH_CONVERT); + else + blkno = INT_GET(info->back, ARCH_CONVERT); + if (blkno == 0) + continue; + error = xfs_da_read_buf(state->args->trans, state->args->dp, + blkno, -1, &bp, XFS_ATTR_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + + leaf = (xfs_attr_leafblock_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes = state->blocksize - (state->blocksize>>2); + bytes -= INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + count += INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes -= INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); + bytes -= count * sizeof(xfs_attr_leaf_entry_t); + bytes -= sizeof(xfs_attr_leaf_hdr_t); + xfs_da_brelse(state->args->trans, bp); + if (bytes >= 0) + break; /* fits with at least 25% to spare */ + } + if (i >= 2) { + *action = 0; + return(0); + } + + /* + * Make altpath point to the block we want to keep (the lower + * numbered block) and path point to the block we want to drop. + */ + bcopy(&state->path, &state->altpath, sizeof(state->path)); + if (blkno < blk->blkno) { + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + } else { + error = xfs_da_path_shift(state, &state->path, forward, + 0, &retval); + } + if (error) + return(error); + if (retval) { + *action = 0; + } else { + *action = 1; + } + return(0); +} + +/* + * Move all the attribute list entries from drop_leaf into save_leaf. + */ +void +xfs_attr_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk) +{ + xfs_attr_leafblock_t *drop_leaf, *save_leaf, *tmp_leaf; + xfs_attr_leaf_hdr_t *drop_hdr, *save_hdr, *tmp_hdr; + xfs_mount_t *mp; + char *tmpbuffer; + + /* + * Set up environment. + */ + mp = state->mp; + ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC); + ASSERT(save_blk->magic == XFS_ATTR_LEAF_MAGIC); + drop_leaf = drop_blk->bp->data; + save_leaf = save_blk->bp->data; + ASSERT(INT_GET(drop_leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(INT_GET(save_leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + drop_hdr = &drop_leaf->hdr; + save_hdr = &save_leaf->hdr; + + /* + * Save last hashval from dying block for later Btree fixup. + */ + drop_blk->hashval = + INT_GET(drop_leaf->entries[INT_GET(drop_leaf->hdr.count, + ARCH_CONVERT)-1].hashval, + ARCH_CONVERT); + + /* + * Check if we need a temp buffer, or can we do it in place. + * Note that we don't check "leaf" for holes because we will + * always be dropping it, toosmall() decided that for us already. + */ + if (save_hdr->holes == 0) { + /* + * dest leaf has no holes, so we add there. May need + * to make some room in the entry array. + */ + if (xfs_attr_leaf_order(save_blk->bp, drop_blk->bp)) { + xfs_attr_leaf_moveents(drop_leaf, 0, save_leaf, 0, + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); + } else { + xfs_attr_leaf_moveents(drop_leaf, 0, save_leaf, + INT_GET(save_hdr->count, ARCH_CONVERT), + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), + mp); + } + } else { + /* + * Destination has holes, so we make a temporary copy + * of the leaf and add them both to that. + */ + tmpbuffer = kmem_alloc(state->blocksize, KM_SLEEP); + ASSERT(tmpbuffer != NULL); + bzero(tmpbuffer, state->blocksize); + tmp_leaf = (xfs_attr_leafblock_t *)tmpbuffer; + tmp_hdr = &tmp_leaf->hdr; + tmp_hdr->info = save_hdr->info; /* struct copy */ + INT_SET(tmp_hdr->count, ARCH_CONVERT, 0); + INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize); + if (INT_GET(tmp_hdr->firstused, ARCH_CONVERT) == 0) { + INT_SET(tmp_hdr->firstused, ARCH_CONVERT, + state->blocksize - XFS_ATTR_LEAF_NAME_ALIGN); + } + INT_SET(tmp_hdr->usedbytes, ARCH_CONVERT, 0); + if (xfs_attr_leaf_order(save_blk->bp, drop_blk->bp)) { + xfs_attr_leaf_moveents(drop_leaf, 0, tmp_leaf, 0, + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), + mp); + xfs_attr_leaf_moveents(save_leaf, 0, tmp_leaf, + INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), + (int)INT_GET(save_hdr->count, ARCH_CONVERT), + mp); + } else { + xfs_attr_leaf_moveents(save_leaf, 0, tmp_leaf, 0, + (int)INT_GET(save_hdr->count, ARCH_CONVERT), + mp); + xfs_attr_leaf_moveents(drop_leaf, 0, tmp_leaf, + INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), + mp); + } + bcopy((char *)tmp_leaf, (char *)save_leaf, state->blocksize); + kmem_free(tmpbuffer, state->blocksize); + } + + xfs_da_log_buf(state->args->trans, save_blk->bp, 0, + state->blocksize - 1); + + /* + * Copy out last hashval in each block for B-tree code. + */ + save_blk->hashval = + INT_GET(save_leaf->entries[INT_GET(save_leaf->hdr.count, + ARCH_CONVERT)-1].hashval, + ARCH_CONVERT); +} + + +/*======================================================================== + * Utility routines. + *========================================================================*/ + +/* + * Move the indicated entries from one leaf to another. + * NOTE: this routine modifies both source and destination leaves. + */ +/*ARGSUSED*/ +STATIC void +xfs_attr_leaf_moveents(xfs_attr_leafblock_t *leaf_s, int start_s, + xfs_attr_leafblock_t *leaf_d, int start_d, + int count, xfs_mount_t *mp) +{ + xfs_attr_leaf_hdr_t *hdr_s, *hdr_d; + xfs_attr_leaf_entry_t *entry_s, *entry_d; + int desti, tmp, i; + + /* + * Check for nothing to do. + */ + if (count == 0) + return; + + /* + * Set up environment. + */ + ASSERT(INT_GET(leaf_s->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(INT_GET(leaf_d->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + hdr_s = &leaf_s->hdr; + hdr_d = &leaf_d->hdr; + ASSERT((INT_GET(hdr_s->count, ARCH_CONVERT) > 0) + && (INT_GET(hdr_s->count, ARCH_CONVERT) + < (XFS_LBSIZE(mp)/8))); + ASSERT(INT_GET(hdr_s->firstused, ARCH_CONVERT) >= + ((INT_GET(hdr_s->count, ARCH_CONVERT) + * sizeof(*entry_s))+sizeof(*hdr_s))); + ASSERT(INT_GET(hdr_d->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8)); + ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= + ((INT_GET(hdr_d->count, ARCH_CONVERT) + * sizeof(*entry_d))+sizeof(*hdr_d))); + + ASSERT(start_s < INT_GET(hdr_s->count, ARCH_CONVERT)); + ASSERT(start_d <= INT_GET(hdr_d->count, ARCH_CONVERT)); + ASSERT(count <= INT_GET(hdr_s->count, ARCH_CONVERT)); + + /* + * Move the entries in the destination leaf up to make a hole? + */ + if (start_d < INT_GET(hdr_d->count, ARCH_CONVERT)) { + tmp = INT_GET(hdr_d->count, ARCH_CONVERT) - start_d; + tmp *= sizeof(xfs_attr_leaf_entry_t); + entry_s = &leaf_d->entries[start_d]; + entry_d = &leaf_d->entries[start_d + count]; + ovbcopy((char *)entry_s, (char *)entry_d, tmp); + } + + /* + * Copy all entry's in the same (sorted) order, + * but allocate attribute info packed and in sequence. + */ + entry_s = &leaf_s->entries[start_s]; + entry_d = &leaf_d->entries[start_d]; + desti = start_d; + for (i = 0; i < count; entry_s++, entry_d++, desti++, i++) { + ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + >= INT_GET(hdr_s->firstused, ARCH_CONVERT)); + tmp = xfs_attr_leaf_entsize(leaf_s, start_s + i); +#ifdef GROT + /* + * Code to drop INCOMPLETE entries. Difficult to use as we + * may also need to change the insertion index. Code turned + * off for 6.2, should be revisited later. + */ + if (entry_s->flags & XFS_ATTR_INCOMPLETE) { /* skip partials? */ + bzero(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), tmp); + INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp); + INT_MOD(hdr_s->count, ARCH_CONVERT, -1); + entry_d--; /* to compensate for ++ in loop hdr */ + desti--; + if ((start_s + i) < offset) + result++; /* insertion index adjustment */ + } else { +#endif /* GROT */ + INT_MOD(hdr_d->firstused, ARCH_CONVERT, -tmp); + INT_SET(entry_d->hashval, ARCH_CONVERT, + INT_GET(entry_s->hashval, ARCH_CONVERT)); + INT_SET(entry_d->nameidx, ARCH_CONVERT, + INT_GET(hdr_d->firstused, + ARCH_CONVERT)); + entry_d->flags = entry_s->flags; + ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp + <= XFS_LBSIZE(mp)); + ovbcopy(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), + XFS_ATTR_LEAF_NAME(leaf_d, desti), tmp); + ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp + <= XFS_LBSIZE(mp)); + bzero(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), tmp); + INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp); + INT_MOD(hdr_d->usedbytes, ARCH_CONVERT, tmp); + INT_MOD(hdr_s->count, ARCH_CONVERT, -1); + INT_MOD(hdr_d->count, ARCH_CONVERT, 1); + tmp = INT_GET(hdr_d->count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t) + + sizeof(xfs_attr_leaf_hdr_t); + ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= tmp); +#ifdef GROT + } +#endif /* GROT */ + } + + /* + * Zero out the entries we just copied. + */ + if (start_s == INT_GET(hdr_s->count, ARCH_CONVERT)) { + tmp = count * sizeof(xfs_attr_leaf_entry_t); + entry_s = &leaf_s->entries[start_s]; + ASSERT(((char *)entry_s + tmp) <= + ((char *)leaf_s + XFS_LBSIZE(mp))); + bzero((char *)entry_s, tmp); + } else { + /* + * Move the remaining entries down to fill the hole, + * then zero the entries at the top. + */ + tmp = INT_GET(hdr_s->count, ARCH_CONVERT) - count; + tmp *= sizeof(xfs_attr_leaf_entry_t); + entry_s = &leaf_s->entries[start_s + count]; + entry_d = &leaf_s->entries[start_s]; + ovbcopy((char *)entry_s, (char *)entry_d, tmp); + + tmp = count * sizeof(xfs_attr_leaf_entry_t); + entry_s = &leaf_s->entries[INT_GET(hdr_s->count, + ARCH_CONVERT)]; + ASSERT(((char *)entry_s + tmp) <= + ((char *)leaf_s + XFS_LBSIZE(mp))); + bzero((char *)entry_s, tmp); + } + + /* + * Fill in the freemap information + */ + INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, + sizeof(xfs_attr_leaf_hdr_t)); + INT_MOD(hdr_d->freemap[0].base, ARCH_CONVERT, + INT_GET(hdr_d->count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t)); + INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, + INT_GET(hdr_d->firstused, ARCH_CONVERT) + - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); + INT_SET(hdr_d->freemap[1].base, ARCH_CONVERT, 0); + INT_SET(hdr_d->freemap[2].base, ARCH_CONVERT, 0); + INT_SET(hdr_d->freemap[1].size, ARCH_CONVERT, 0); + INT_SET(hdr_d->freemap[2].size, ARCH_CONVERT, 0); + hdr_s->holes = 1; /* leaf may not be compact */ +} + +/* + * Compare two leaf blocks "order". + * Return 0 unless leaf2 should go before leaf1. + */ +int +xfs_attr_leaf_order(xfs_dabuf_t *leaf1_bp, xfs_dabuf_t *leaf2_bp) +{ + xfs_attr_leafblock_t *leaf1, *leaf2; + + leaf1 = leaf1_bp->data; + leaf2 = leaf2_bp->data; + ASSERT((INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC) && + (INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC)); + if ( (INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0) + && (INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0) + && ( (INT_GET(leaf2->entries[ 0 ].hashval, ARCH_CONVERT) < + INT_GET(leaf1->entries[ 0 ].hashval, ARCH_CONVERT)) + || (INT_GET(leaf2->entries[INT_GET(leaf2->hdr.count, + ARCH_CONVERT)-1].hashval, ARCH_CONVERT) < + INT_GET(leaf1->entries[INT_GET(leaf1->hdr.count, + ARCH_CONVERT)-1].hashval, ARCH_CONVERT))) ) { + return(1); + } + return(0); +} + +/* + * Pick up the last hashvalue from a leaf block. + */ +xfs_dahash_t +xfs_attr_leaf_lasthash(xfs_dabuf_t *bp, int *count) +{ + xfs_attr_leafblock_t *leaf; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + if (count) + *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + if (INT_GET(leaf->hdr.count, ARCH_CONVERT) == 0) + return(0); + return(INT_GET(leaf->entries[INT_GET(leaf->hdr.count, + ARCH_CONVERT)-1].hashval, ARCH_CONVERT)); +} + +/* + * Calculate the number of bytes used to store the indicated attribute + * (whether local or remote only calculate bytes in this block). + */ +int +xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index) +{ + xfs_attr_leaf_name_local_t *name_loc; + xfs_attr_leaf_name_remote_t *name_rmt; + int size; + + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + if (leaf->entries[index].flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, index); + size = XFS_ATTR_LEAF_ENTSIZE_LOCAL(name_loc->namelen, + INT_GET(name_loc->valuelen, + ARCH_CONVERT)); + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, index); + size = XFS_ATTR_LEAF_ENTSIZE_REMOTE(name_rmt->namelen); + } + return(size); +} + +/* + * Calculate the number of bytes that would be required to store the new + * attribute (whether local or remote only calculate bytes in this block). + * This routine decides as a side effect whether the attribute will be + * a "local" or a "remote" attribute. + */ +int +xfs_attr_leaf_newentsize(xfs_da_args_t *args, int blocksize, int *local) +{ + int size; + + size = XFS_ATTR_LEAF_ENTSIZE_LOCAL(args->namelen, args->valuelen); + if (size < XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX(blocksize)) { + if (local) { + *local = 1; + } + } else { + size = XFS_ATTR_LEAF_ENTSIZE_REMOTE(args->namelen); + if (local) { + *local = 0; + } + } + return(size); +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_bit.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_bit.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_bit.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_bit.c Thu Apr 12 18:30:32 2001 @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * XFS bit manipulation routines, used in non-realtime code. + */ + +#include + +/* + * Index of low bit number in byte, -1 for none set, 0..7 otherwise. + */ +const char xfs_lowbit[256] = { + -1, 0, 1, 0, 2, 0, 1, 0, /* 00 .. 07 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 08 .. 0f */ + 4, 0, 1, 0, 2, 0, 1, 0, /* 10 .. 17 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 18 .. 1f */ + 5, 0, 1, 0, 2, 0, 1, 0, /* 20 .. 27 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 28 .. 2f */ + 4, 0, 1, 0, 2, 0, 1, 0, /* 30 .. 37 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 38 .. 3f */ + 6, 0, 1, 0, 2, 0, 1, 0, /* 40 .. 47 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 48 .. 4f */ + 4, 0, 1, 0, 2, 0, 1, 0, /* 50 .. 57 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 58 .. 5f */ + 5, 0, 1, 0, 2, 0, 1, 0, /* 60 .. 67 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 68 .. 6f */ + 4, 0, 1, 0, 2, 0, 1, 0, /* 70 .. 77 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 78 .. 7f */ + 7, 0, 1, 0, 2, 0, 1, 0, /* 80 .. 87 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 88 .. 8f */ + 4, 0, 1, 0, 2, 0, 1, 0, /* 90 .. 97 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 98 .. 9f */ + 5, 0, 1, 0, 2, 0, 1, 0, /* a0 .. a7 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* a8 .. af */ + 4, 0, 1, 0, 2, 0, 1, 0, /* b0 .. b7 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* b8 .. bf */ + 6, 0, 1, 0, 2, 0, 1, 0, /* c0 .. c7 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* c8 .. cf */ + 4, 0, 1, 0, 2, 0, 1, 0, /* d0 .. d7 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* d8 .. df */ + 5, 0, 1, 0, 2, 0, 1, 0, /* e0 .. e7 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* e8 .. ef */ + 4, 0, 1, 0, 2, 0, 1, 0, /* f0 .. f7 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* f8 .. ff */ +}; + +/* + * Index of high bit number in byte, -1 for none set, 0..7 otherwise. + */ +const char xfs_highbit[256] = { + -1, 0, 1, 1, 2, 2, 2, 2, /* 00 .. 07 */ + 3, 3, 3, 3, 3, 3, 3, 3, /* 08 .. 0f */ + 4, 4, 4, 4, 4, 4, 4, 4, /* 10 .. 17 */ + 4, 4, 4, 4, 4, 4, 4, 4, /* 18 .. 1f */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 20 .. 27 */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 28 .. 2f */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 30 .. 37 */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 38 .. 3f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 40 .. 47 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 48 .. 4f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 50 .. 57 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 58 .. 5f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 60 .. 67 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 68 .. 6f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 70 .. 77 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 78 .. 7f */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 80 .. 87 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 88 .. 8f */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 90 .. 97 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 98 .. 9f */ + 7, 7, 7, 7, 7, 7, 7, 7, /* a0 .. a7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* a8 .. af */ + 7, 7, 7, 7, 7, 7, 7, 7, /* b0 .. b7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* b8 .. bf */ + 7, 7, 7, 7, 7, 7, 7, 7, /* c0 .. c7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* c8 .. cf */ + 7, 7, 7, 7, 7, 7, 7, 7, /* d0 .. d7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* d8 .. df */ + 7, 7, 7, 7, 7, 7, 7, 7, /* e0 .. e7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* e8 .. ef */ + 7, 7, 7, 7, 7, 7, 7, 7, /* f0 .. f7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* f8 .. ff */ +}; + +/* + * Count of bits set in byte, 0..8. + */ +const char xfs_countbit[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, /* 00 .. 07 */ + 1, 2, 2, 3, 2, 3, 3, 4, /* 08 .. 0f */ + 1, 2, 2, 3, 2, 3, 3, 4, /* 10 .. 17 */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 18 .. 1f */ + 1, 2, 2, 3, 2, 3, 3, 4, /* 20 .. 27 */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 28 .. 2f */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 30 .. 37 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* 38 .. 3f */ + 1, 2, 2, 3, 2, 3, 3, 4, /* 40 .. 47 */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 48 .. 4f */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 50 .. 57 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* 58 .. 5f */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 60 .. 67 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* 68 .. 6f */ + 3, 4, 4, 5, 4, 5, 5, 6, /* 70 .. 77 */ + 4, 5, 5, 6, 5, 6, 6, 7, /* 78 .. 7f */ + 1, 2, 2, 3, 2, 3, 3, 4, /* 80 .. 87 */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 88 .. 8f */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 90 .. 97 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* 98 .. 9f */ + 2, 3, 3, 4, 3, 4, 4, 5, /* a0 .. a7 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* a8 .. af */ + 3, 4, 4, 5, 4, 5, 5, 6, /* b0 .. b7 */ + 4, 5, 5, 6, 5, 6, 6, 7, /* b8 .. bf */ + 2, 3, 3, 4, 3, 4, 4, 5, /* c0 .. c7 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* c8 .. cf */ + 3, 4, 4, 5, 4, 5, 5, 6, /* d0 .. d7 */ + 4, 5, 5, 6, 5, 6, 6, 7, /* d8 .. df */ + 3, 4, 4, 5, 4, 5, 5, 6, /* e0 .. e7 */ + 4, 5, 5, 6, 5, 6, 6, 7, /* e8 .. ef */ + 4, 5, 5, 6, 5, 6, 6, 7, /* f0 .. f7 */ + 5, 6, 6, 7, 6, 7, 7, 8, /* f8 .. ff */ +}; + +/* + * xfs_highbit32: get high bit set out of 32-bit argument, -1 if none set. + */ +int +xfs_highbit32( + __uint32_t v) +{ + int i; + + if (v & 0xffff0000) + if (v & 0xff000000) + i = 24; + else + i = 16; + else if (v & 0x0000ffff) + if (v & 0x0000ff00) + i = 8; + else + i = 0; + else + return -1; + return i + xfs_highbit[(v >> i) & 0xff]; +} + +/* + * xfs_lowbit64: get low bit set out of 64-bit argument, -1 if none set. + */ +int +xfs_lowbit64( + __uint64_t v) +{ + int i; +#if XFS_64 + if (v & 0x00000000ffffffff) + if (v & 0x000000000000ffff) + if (v & 0x00000000000000ff) + i = 0; + else + i = 8; + else + if (v & 0x0000000000ff0000) + i = 16; + else + i = 24; + else if (v & 0xffffffff00000000) + if (v & 0x0000ffff00000000) + if (v & 0x000000ff00000000) + i = 32; + else + i = 40; + else + if (v & 0x00ff000000000000) + i = 48; + else + i = 56; + else + return -1; + return i + xfs_lowbit[(v >> i) & 0xff]; +#else + __uint32_t vw; + + if ((vw = v)) { + if (vw & 0x0000ffff) + if (vw & 0x000000ff) + i = 0; + else + i = 8; + else + if (vw & 0x00ff0000) + i = 16; + else + i = 24; + return i + xfs_lowbit[(vw >> i) & 0xff]; + } else if ((vw = v >> 32)) { + if (vw & 0x0000ffff) + if (vw & 0x000000ff) + i = 32; + else + i = 40; + else + if (vw & 0x00ff0000) + i = 48; + else + i = 56; + return i + xfs_lowbit[(vw >> (i - 32)) & 0xff]; + } else + return -1; +#endif +} + +/* + * xfs_highbit64: get high bit set out of 64-bit argument, -1 if none set. + */ +int +xfs_highbit64( + __uint64_t v) +{ + int i; +#if XFS_64 + if (v & 0xffffffff00000000) + if (v & 0xffff000000000000) + if (v & 0xff00000000000000) + i = 56; + else + i = 48; + else + if (v & 0x0000ff0000000000) + i = 40; + else + i = 32; + else if (v & 0x00000000ffffffff) + if (v & 0x00000000ffff0000) + if (v & 0x00000000ff000000) + i = 24; + else + i = 16; + else + if (v & 0x000000000000ff00) + i = 8; + else + i = 0; + else + return -1; + return i + xfs_highbit[(v >> i) & 0xff]; +#else + __uint32_t vw; + + if ((vw = v >> 32)) { + if (vw & 0xffff0000) + if (vw & 0xff000000) + i = 56; + else + i = 48; + else + if (vw & 0x0000ff00) + i = 40; + else + i = 32; + return i + xfs_highbit[(vw >> (i - 32)) & 0xff]; + } else if ((vw = v)) { + if (vw & 0xffff0000) + if (vw & 0xff000000) + i = 24; + else + i = 16; + else + if (vw & 0x0000ff00) + i = 8; + else + i = 0; + return i + xfs_highbit[(vw >> i) & 0xff]; + } else + return -1; +#endif +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_bmap.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_bmap.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_bmap.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_bmap.c Wed Apr 18 21:41:37 2001 @@ -0,0 +1,4511 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +xfs_zone_t *xfs_bmap_free_item_zone; + +/* + * Called by xfs_bmapi to update extent list structure and the btree + * after allocating space (or doing a delayed allocation). + */ +STATIC int /* error */ +xfs_bmap_add_extent( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + xfs_fsblock_t *first, /* pointer to firstblock variable */ + xfs_bmap_free_t *flist, /* list of extents to be freed */ + int *logflagsp, /* inode logging flags */ + int whichfork, /* data or attr fork */ + int rsvd) /* OK to use reserved data blocks */ +{ + xfs_btree_cur_t *cur; /* btree cursor or null */ + xfs_filblks_t da_new; /* new count del alloc blocks used */ + xfs_filblks_t da_old; /* old count del alloc blocks used */ + int error; /* error return value */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_add_extent"; +#endif + xfs_ifork_t *ifp; /* inode fork ptr */ + int logflags; /* returned value */ + xfs_extnum_t nextents; /* number of extents in file now */ + + XFS_STATS_INC(xfsstats.xs_add_exlist); + cur = *curp; + ifp = XFS_IFORK_PTR(ip, whichfork); + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + ASSERT(idx <= nextents); + da_old = da_new = 0; + error = 0; + /* + * This is the first extent added to a new/empty file. + * Special case this one, so other routines get to assume there are + * already extents in the list. + */ + if (nextents == 0) { + xfs_bmap_trace_insert(fname, "insert empty", ip, 0, 1, new, + NULL, whichfork); + xfs_bmap_insert_exlist(ip, 0, 1, new, whichfork); + ASSERT(cur == NULL); + ifp->if_lastex = 0; + if (!ISNULLSTARTBLOCK(new->br_startblock)) { + XFS_IFORK_NEXT_SET(ip, whichfork, 1); + logflags = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); + } else + logflags = 0; + } + /* + * Any kind of new delayed allocation goes here. + */ + else if (ISNULLSTARTBLOCK(new->br_startblock)) { + if (cur) + ASSERT((cur->bc_private.b.flags & + XFS_BTCUR_BPRV_WASDEL) == 0); + if ((error = xfs_bmap_add_extent_hole_delay(ip, idx, cur, new, + &logflags, rsvd))) + goto done; + } + /* + * Real allocation off the end of the file. + */ + else if (idx == nextents) { + if (cur) + ASSERT((cur->bc_private.b.flags & + XFS_BTCUR_BPRV_WASDEL) == 0); + if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new, + &logflags, whichfork))) + goto done; + } else { + xfs_bmbt_irec_t prev; /* old extent at offset idx */ + + /* + * Get the record referred to by idx. + */ + xfs_bmbt_get_all(&ifp->if_u1.if_extents[idx], &prev); + /* + * If it's a real allocation record, and the new allocation ends + * after the start of the referred to record, then we're filling + * in a delayed or unwritten allocation with a real one, or + * converting real back to unwritten. + */ + if (!ISNULLSTARTBLOCK(new->br_startblock) && + new->br_startoff + new->br_blockcount > prev.br_startoff) { + if (prev.br_state != XFS_EXT_UNWRITTEN && + ISNULLSTARTBLOCK(prev.br_startblock)) { + da_old = STARTBLOCKVAL(prev.br_startblock); + if (cur) + ASSERT(cur->bc_private.b.flags & + XFS_BTCUR_BPRV_WASDEL); + if ((error = xfs_bmap_add_extent_delay_real(ip, + idx, &cur, new, &da_new, first, flist, + &logflags, rsvd))) + goto done; + } else if (new->br_state == XFS_EXT_NORM) { + ASSERT(new->br_state == XFS_EXT_NORM); + if ((error = xfs_bmap_add_extent_unwritten_real( + ip, idx, &cur, new, &logflags))) + goto done; + } else { + ASSERT(new->br_state == XFS_EXT_UNWRITTEN); + if ((error = xfs_bmap_add_extent_unwritten_real( + ip, idx, &cur, new, &logflags))) + goto done; + } + ASSERT(*curp == cur || *curp == NULL); + } + /* + * Otherwise we're filling in a hole with an allocation. + */ + else { + if (cur) + ASSERT((cur->bc_private.b.flags & + XFS_BTCUR_BPRV_WASDEL) == 0); + if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, + new, &logflags, whichfork))) + goto done; + } + } + + ASSERT(*curp == cur || *curp == NULL); + /* + * Convert to a btree if necessary. + */ + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) { + int tmp_logflags; /* partial log flag return val */ + + ASSERT(cur == NULL); + error = xfs_bmap_extents_to_btree(ip->i_transp, ip, first, + flist, &cur, da_old > 0, &tmp_logflags, whichfork); + logflags |= tmp_logflags; + if (error) + goto done; + } + /* + * Adjust for changes in reserved delayed indirect blocks. + * Nothing to do for disk quotas here. + */ + if (da_old || da_new) { + xfs_filblks_t nblks; + + nblks = da_new; + if (cur) + nblks += cur->bc_private.b.allocated; + ASSERT(nblks <= da_old); + if (nblks < da_old) + xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS, + (int)(da_old - nblks), rsvd); + } + /* + * Clear out the allocated field, done with it now in any case. + */ + if (cur) { + cur->bc_private.b.allocated = 0; + *curp = cur; + } +done: +#ifdef XFSDEBUG + if (!error) + xfs_bmap_check_leaf_extents(*curp, ip, whichfork); +#endif + *logflagsp = logflags; + return error; +} + +/* + * Called by xfs_bmap_add_extent to handle cases converting a delayed + * allocation to a real allocation. + */ +STATIC int /* error */ +xfs_bmap_add_extent_delay_real( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + xfs_filblks_t *dnew, /* new delayed-alloc indirect blocks */ + xfs_fsblock_t *first, /* pointer to firstblock variable */ + xfs_bmap_free_t *flist, /* list of extents to be freed */ + int *logflagsp, /* inode logging flags */ + int rsvd) /* OK to use reserved data block allocation */ +{ + xfs_bmbt_rec_t *base; /* base of extent entry list */ + xfs_btree_cur_t *cur; /* btree cursor */ + int diff; /* temp value */ + xfs_bmbt_rec_t *ep; /* extent entry for idx */ + int error; /* error return value */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_add_extent_delay_real"; +#endif + int i; /* temp state */ + xfs_fileoff_t new_endoff; /* end offset of new entry */ + xfs_bmbt_irec_t r[3]; /* neighbor extent entries */ + /* left is 0, right is 1, prev is 2 */ + int rval=0; /* return value (logging flags) */ + int state = 0;/* state bits, accessed thru macros */ + xfs_filblks_t temp; /* value for dnew calculations */ + xfs_filblks_t temp2; /* value for dnew calculations */ + int tmp_rval; /* partial logging flags */ + enum { /* bit number definitions for state */ + LEFT_CONTIG, RIGHT_CONTIG, + LEFT_FILLING, RIGHT_FILLING, + LEFT_DELAY, RIGHT_DELAY, + LEFT_VALID, RIGHT_VALID + }; + +#define LEFT r[0] +#define RIGHT r[1] +#define PREV r[2] +#define MASK(b) (1 << (b)) +#define MASK2(a,b) (MASK(a) | MASK(b)) +#define MASK3(a,b,c) (MASK2(a,b) | MASK(c)) +#define MASK4(a,b,c,d) (MASK3(a,b,c) | MASK(d)) +#define STATE_SET(b,v) ((v) ? (state |= MASK(b)) : (state &= ~MASK(b))) +#define STATE_TEST(b) (state & MASK(b)) +#define STATE_SET_TEST(b,v) ((v) ? ((state |= MASK(b)), 1) : \ + ((state &= ~MASK(b)), 0)) +#define SWITCH_STATE \ + (state & MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG)) + + /* + * Set up a bunch of variables to make the tests simpler. + */ + cur = *curp; + base = ip->i_df.if_u1.if_extents; + ep = &base[idx]; + xfs_bmbt_get_all(ep, &PREV); + new_endoff = new->br_startoff + new->br_blockcount; + ASSERT(PREV.br_startoff <= new->br_startoff); + ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff); + /* + * Set flags determining what part of the previous delayed allocation + * extent is being replaced by a real allocation. + */ + STATE_SET(LEFT_FILLING, PREV.br_startoff == new->br_startoff); + STATE_SET(RIGHT_FILLING, + PREV.br_startoff + PREV.br_blockcount == new_endoff); + /* + * Check and set flags if this segment has a left neighbor. + * Don't set contiguous if the combined extent would be too large. + */ + if (STATE_SET_TEST(LEFT_VALID, idx > 0)) { + xfs_bmbt_get_all(ep - 1, &LEFT); + STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(LEFT.br_startblock)); + } + STATE_SET(LEFT_CONTIG, + STATE_TEST(LEFT_VALID) && !STATE_TEST(LEFT_DELAY) && + LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff && + LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock && + LEFT.br_state == new->br_state && + LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN); + /* + * Check and set flags if this segment has a right neighbor. + * Don't set contiguous if the combined extent would be too large. + * Also check for all-three-contiguous being too large. + */ + if (STATE_SET_TEST(RIGHT_VALID, + idx < + ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1)) { + xfs_bmbt_get_all(ep + 1, &RIGHT); + STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(RIGHT.br_startblock)); + } + STATE_SET(RIGHT_CONTIG, + STATE_TEST(RIGHT_VALID) && !STATE_TEST(RIGHT_DELAY) && + new_endoff == RIGHT.br_startoff && + new->br_startblock + new->br_blockcount == + RIGHT.br_startblock && + new->br_state == RIGHT.br_state && + new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN && + ((state & MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING)) != + MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING) || + LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount + <= MAXEXTLEN)); + error = 0; + /* + * Switch out based on the FILLING and CONTIG state bits. + */ + switch (SWITCH_STATE) { + + case MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + /* + * Filling in all of a previously delayed allocation extent. + * The left and right neighbors are both contiguous with new. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + PREV.br_blockcount + + RIGHT.br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|RF|LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmap_trace_delete(fname, "LF|RF|LC|RC", ip, idx, 2, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx, 2, XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + ip->i_d.di_nextents--; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, + RIGHT.br_startblock, + RIGHT.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + + PREV.br_blockcount + + RIGHT.br_blockcount, LEFT.br_state))) + goto done; + } + *dnew = 0; + break; + + case MASK3(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG): + /* + * Filling in all of a previously delayed allocation extent. + * The left neighbor is contiguous, the right is not. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + PREV.br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|RF|LC", ip, idx - 1, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + xfs_bmap_trace_delete(fname, "LF|RF|LC", ip, idx, 1, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx, 1, XFS_DATA_FORK); + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, LEFT.br_startoff, + LEFT.br_startblock, LEFT.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + + PREV.br_blockcount, LEFT.br_state))) + goto done; + } + *dnew = 0; + break; + + case MASK3(LEFT_FILLING, RIGHT_FILLING, RIGHT_CONTIG): + /* + * Filling in all of a previously delayed allocation extent. + * The right neighbor is contiguous, the left is not. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|RC", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_startblock(ep, new->br_startblock); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount + RIGHT.br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|RF|RC", ip, idx, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + xfs_bmap_trace_delete(fname, "LF|RF|RC", ip, idx + 1, 1, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx + 1, 1, XFS_DATA_FORK); + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, + RIGHT.br_startblock, + RIGHT.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, PREV.br_startoff, + new->br_startblock, + PREV.br_blockcount + + RIGHT.br_blockcount, PREV.br_state))) + goto done; + } + *dnew = 0; + break; + + case MASK2(LEFT_FILLING, RIGHT_FILLING): + /* + * Filling in all of a previously delayed allocation extent. + * Neither the left nor right neighbors are contiguous with + * the new one. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_startblock(ep, new->br_startblock); + xfs_bmap_trace_post_update(fname, "LF|RF", ip, idx, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 0); + cur->bc_rec.b.br_state = XFS_EXT_NORM; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + *dnew = 0; + break; + + case MASK2(LEFT_FILLING, LEFT_CONTIG): + /* + * Filling in the first part of a previous delayed allocation. + * The left neighbor is contiguous. + */ + xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + new->br_blockcount); + xfs_bmbt_set_startoff(ep, + PREV.br_startoff + new->br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx - 1, + XFS_DATA_FORK); + temp = PREV.br_blockcount - new->br_blockcount; + xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, temp); + ip->i_df.if_lastex = idx - 1; + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, LEFT.br_startoff, + LEFT.br_startblock, LEFT.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + + new->br_blockcount, + LEFT.br_state))) + goto done; + } + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + STARTBLOCKVAL(PREV.br_startblock)); + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx, + XFS_DATA_FORK); + *dnew = temp; + break; + + case MASK(LEFT_FILLING): + /* + * Filling in the first part of a previous delayed allocation. + * The left neighbor is not contiguous. + */ + xfs_bmap_trace_pre_update(fname, "LF", ip, idx, XFS_DATA_FORK); + xfs_bmbt_set_startoff(ep, new_endoff); + temp = PREV.br_blockcount - new->br_blockcount; + xfs_bmbt_set_blockcount(ep, temp); + xfs_bmap_trace_insert(fname, "LF", ip, idx, 1, new, NULL, + XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx, 1, new, XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 0); + cur->bc_rec.b.br_state = XFS_EXT_NORM; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && + ip->i_d.di_nextents > ip->i_df.if_ext_max) { + error = xfs_bmap_extents_to_btree(ip->i_transp, ip, + first, flist, &cur, 1, &tmp_rval, + XFS_DATA_FORK); + rval |= tmp_rval; + if (error) + goto done; + } + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + STARTBLOCKVAL(PREV.br_startblock) - + (cur ? cur->bc_private.b.allocated : 0)); + base = ip->i_df.if_u1.if_extents; + ep = &base[idx + 1]; + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "LF", ip, idx + 1, + XFS_DATA_FORK); + *dnew = temp; + break; + + case MASK2(RIGHT_FILLING, RIGHT_CONTIG): + /* + * Filling in the last part of a previous delayed allocation. + * The right neighbor is contiguous with the new allocation. + */ + temp = PREV.br_blockcount - new->br_blockcount; + xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx, + XFS_DATA_FORK); + xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx + 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, temp); + xfs_bmbt_set_allf(ep + 1, new->br_startoff, new->br_startblock, + new->br_blockcount + RIGHT.br_blockcount, + RIGHT.br_state); + xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx + 1, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, + RIGHT.br_startblock, + RIGHT.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, new->br_startoff, + new->br_startblock, + new->br_blockcount + + RIGHT.br_blockcount, + RIGHT.br_state))) + goto done; + } + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + STARTBLOCKVAL(PREV.br_startblock)); + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx, + XFS_DATA_FORK); + *dnew = temp; + break; + + case MASK(RIGHT_FILLING): + /* + * Filling in the last part of a previous delayed allocation. + * The right neighbor is not contiguous. + */ + temp = PREV.br_blockcount - new->br_blockcount; + xfs_bmap_trace_pre_update(fname, "RF", ip, idx, XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, temp); + xfs_bmap_trace_insert(fname, "RF", ip, idx + 1, 1, + new, NULL, XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx + 1, 1, new, XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 0); + cur->bc_rec.b.br_state = XFS_EXT_NORM; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && + ip->i_d.di_nextents > ip->i_df.if_ext_max) { + error = xfs_bmap_extents_to_btree(ip->i_transp, ip, + first, flist, &cur, 1, &tmp_rval, + XFS_DATA_FORK); + rval |= tmp_rval; + if (error) + goto done; + } + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + STARTBLOCKVAL(PREV.br_startblock) - + (cur ? cur->bc_private.b.allocated : 0)); + base = ip->i_df.if_u1.if_extents; + ep = &base[idx]; + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "RF", ip, idx, XFS_DATA_FORK); + *dnew = temp; + break; + + case 0: + /* + * Filling in the middle part of a previous delayed allocation. + * Contiguity is impossible here. + * This case is avoided almost all the time. + */ + temp = new->br_startoff - PREV.br_startoff; + xfs_bmap_trace_pre_update(fname, "0", ip, idx, XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, temp); + r[0] = *new; + r[1].br_startoff = new_endoff; + temp2 = PREV.br_startoff + PREV.br_blockcount - new_endoff; + r[1].br_blockcount = temp2; + xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 2, &r[0], &r[1], + XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx + 1, 2, &r[0], XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 0); + cur->bc_rec.b.br_state = XFS_EXT_NORM; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && + ip->i_d.di_nextents > ip->i_df.if_ext_max) { + error = xfs_bmap_extents_to_btree(ip->i_transp, ip, + first, flist, &cur, 1, &tmp_rval, + XFS_DATA_FORK); + rval |= tmp_rval; + if (error) + goto done; + } + temp = xfs_bmap_worst_indlen(ip, temp); + temp2 = xfs_bmap_worst_indlen(ip, temp2); + diff = (int)(temp + temp2 - STARTBLOCKVAL(PREV.br_startblock) - + (cur ? cur->bc_private.b.allocated : 0)); + if (diff > 0 && + xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS, -diff, rsvd)) { + /* + * Ick gross gag me with a spoon. + */ + ASSERT(0); /* want to see if this ever happens! */ + while (diff > 0) { + if (temp) { + temp--; + diff--; + if (!diff || + !xfs_mod_incore_sb(ip->i_mount, + XFS_SBS_FDBLOCKS, -diff, rsvd)) + break; + } + if (temp2) { + temp2--; + diff--; + if (!diff || + !xfs_mod_incore_sb(ip->i_mount, + XFS_SBS_FDBLOCKS, -diff, rsvd)) + break; + } + } + } + base = ip->i_df.if_u1.if_extents; + ep = &base[idx]; + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "0", ip, idx, XFS_DATA_FORK); + xfs_bmap_trace_pre_update(fname, "0", ip, idx + 2, + XFS_DATA_FORK); + xfs_bmbt_set_startblock(ep + 2, NULLSTARTBLOCK((int)temp2)); + xfs_bmap_trace_post_update(fname, "0", ip, idx + 2, + XFS_DATA_FORK); + *dnew = temp + temp2; + break; + + case MASK3(LEFT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + case MASK3(RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + case MASK2(LEFT_FILLING, RIGHT_CONTIG): + case MASK2(RIGHT_FILLING, LEFT_CONTIG): + case MASK2(LEFT_CONTIG, RIGHT_CONTIG): + case MASK(LEFT_CONTIG): + case MASK(RIGHT_CONTIG): + /* + * These cases are all impossible. + */ + ASSERT(0); + } + *curp = cur; +done: + *logflagsp = rval; + return error; +#undef LEFT +#undef RIGHT +#undef PREV +#undef MASK +#undef MASK2 +#undef MASK3 +#undef MASK4 +#undef STATE_SET +#undef STATE_TEST +#undef STATE_SET_TEST +#undef SWITCH_STATE +} + +/* + * Called by xfs_bmap_add_extent to handle cases converting an unwritten + * allocation to a real allocation or vice versa. + */ +STATIC int /* error */ +xfs_bmap_add_extent_unwritten_real( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int *logflagsp) /* inode logging flags */ +{ + xfs_bmbt_rec_t *base; /* base of extent entry list */ + xfs_btree_cur_t *cur; /* btree cursor */ + xfs_bmbt_rec_t *ep; /* extent entry for idx */ + int error; /* error return value */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_add_extent_unwritten_real"; +#endif + int i; /* temp state */ + xfs_fileoff_t new_endoff; /* end offset of new entry */ + xfs_exntst_t newext; /* new extent state */ + xfs_exntst_t oldext; /* old extent state */ + xfs_bmbt_irec_t r[3]; /* neighbor extent entries */ + /* left is 0, right is 1, prev is 2 */ + int rval=0; /* return value (logging flags) */ + int state = 0;/* state bits, accessed thru macros */ + enum { /* bit number definitions for state */ + LEFT_CONTIG, RIGHT_CONTIG, + LEFT_FILLING, RIGHT_FILLING, + LEFT_DELAY, RIGHT_DELAY, + LEFT_VALID, RIGHT_VALID + }; + +#define LEFT r[0] +#define RIGHT r[1] +#define PREV r[2] +#define MASK(b) (1 << (b)) +#define MASK2(a,b) (MASK(a) | MASK(b)) +#define MASK3(a,b,c) (MASK2(a,b) | MASK(c)) +#define MASK4(a,b,c,d) (MASK3(a,b,c) | MASK(d)) +#define STATE_SET(b,v) ((v) ? (state |= MASK(b)) : (state &= ~MASK(b))) +#define STATE_TEST(b) (state & MASK(b)) +#define STATE_SET_TEST(b,v) ((v) ? ((state |= MASK(b)), 1) : \ + ((state &= ~MASK(b)), 0)) +#define SWITCH_STATE \ + (state & MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG)) + + /* + * Set up a bunch of variables to make the tests simpler. + */ + error = 0; + cur = *curp; + base = ip->i_df.if_u1.if_extents; + ep = &base[idx]; + xfs_bmbt_get_all(ep, &PREV); + newext = new->br_state; + oldext = (newext == XFS_EXT_UNWRITTEN) ? + XFS_EXT_NORM : XFS_EXT_UNWRITTEN; + ASSERT(PREV.br_state == oldext); + new_endoff = new->br_startoff + new->br_blockcount; + ASSERT(PREV.br_startoff <= new->br_startoff); + ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff); + /* + * Set flags determining what part of the previous oldext allocation + * extent is being replaced by a newext allocation. + */ + STATE_SET(LEFT_FILLING, PREV.br_startoff == new->br_startoff); + STATE_SET(RIGHT_FILLING, + PREV.br_startoff + PREV.br_blockcount == new_endoff); + /* + * Check and set flags if this segment has a left neighbor. + * Don't set contiguous if the combined extent would be too large. + */ + if (STATE_SET_TEST(LEFT_VALID, idx > 0)) { + xfs_bmbt_get_all(ep - 1, &LEFT); + STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(LEFT.br_startblock)); + } + STATE_SET(LEFT_CONTIG, + STATE_TEST(LEFT_VALID) && !STATE_TEST(LEFT_DELAY) && + LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff && + LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock && + LEFT.br_state == newext && + LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN); + /* + * Check and set flags if this segment has a right neighbor. + * Don't set contiguous if the combined extent would be too large. + * Also check for all-three-contiguous being too large. + */ + if (STATE_SET_TEST(RIGHT_VALID, + idx < + ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1)) { + xfs_bmbt_get_all(ep + 1, &RIGHT); + STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(RIGHT.br_startblock)); + } + STATE_SET(RIGHT_CONTIG, + STATE_TEST(RIGHT_VALID) && !STATE_TEST(RIGHT_DELAY) && + new_endoff == RIGHT.br_startoff && + new->br_startblock + new->br_blockcount == + RIGHT.br_startblock && + newext == RIGHT.br_state && + new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN && + ((state & MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING)) != + MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING) || + LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount + <= MAXEXTLEN)); + /* + * Switch out based on the FILLING and CONTIG state bits. + */ + switch (SWITCH_STATE) { + + case MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + /* + * Setting all of a previous oldext extent to newext. + * The left and right neighbors are both contiguous with new. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + PREV.br_blockcount + + RIGHT.br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|RF|LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmap_trace_delete(fname, "LF|RF|LC|RC", ip, idx, 2, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx, 2, XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + ip->i_d.di_nextents -= 2; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, + RIGHT.br_startblock, + RIGHT.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + PREV.br_blockcount + + RIGHT.br_blockcount, LEFT.br_state))) + goto done; + } + break; + + case MASK3(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG): + /* + * Setting all of a previous oldext extent to newext. + * The left neighbor is contiguous, the right is not. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + PREV.br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|RF|LC", ip, idx - 1, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + xfs_bmap_trace_delete(fname, "LF|RF|LC", ip, idx, 1, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx, 1, XFS_DATA_FORK); + ip->i_d.di_nextents--; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, PREV.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + PREV.br_blockcount, + LEFT.br_state))) + goto done; + } + break; + + case MASK3(LEFT_FILLING, RIGHT_FILLING, RIGHT_CONTIG): + /* + * Setting all of a previous oldext extent to newext. + * The right neighbor is contiguous, the left is not. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|RC", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount + RIGHT.br_blockcount); + xfs_bmbt_set_state(ep, newext); + xfs_bmap_trace_post_update(fname, "LF|RF|RC", ip, idx, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + xfs_bmap_trace_delete(fname, "LF|RF|RC", ip, idx + 1, 1, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx + 1, 1, XFS_DATA_FORK); + ip->i_d.di_nextents--; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, + RIGHT.br_startblock, + RIGHT.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, new->br_startoff, + new->br_startblock, + new->br_blockcount + RIGHT.br_blockcount, + newext))) + goto done; + } + break; + + case MASK2(LEFT_FILLING, RIGHT_FILLING): + /* + * Setting all of a previous oldext extent to newext. + * Neither the left nor right neighbors are contiguous with + * the new one. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_state(ep, newext); + xfs_bmap_trace_post_update(fname, "LF|RF", ip, idx, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + newext))) + goto done; + } + break; + + case MASK2(LEFT_FILLING, LEFT_CONTIG): + /* + * Setting the first part of a previous oldext extent to newext. + * The left neighbor is contiguous. + */ + xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + new->br_blockcount); + xfs_bmbt_set_startoff(ep, + PREV.br_startoff + new->br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_startblock(ep, + new->br_startblock + new->br_blockcount); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount - new->br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, PREV.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, + PREV.br_startoff + new->br_blockcount, + PREV.br_startblock + new->br_blockcount, + PREV.br_blockcount - new->br_blockcount, + oldext))) + goto done; + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + if (xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + new->br_blockcount, + LEFT.br_state)) + goto done; + } + break; + + case MASK(LEFT_FILLING): + /* + * Setting the first part of a previous oldext extent to newext. + * The left neighbor is not contiguous. + */ + xfs_bmap_trace_pre_update(fname, "LF", ip, idx, XFS_DATA_FORK); + ASSERT(ep && xfs_bmbt_get_state(ep) == oldext); + xfs_bmbt_set_startoff(ep, new_endoff); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount - new->br_blockcount); + xfs_bmbt_set_startblock(ep, + new->br_startblock + new->br_blockcount); + xfs_bmap_trace_post_update(fname, "LF", ip, idx, XFS_DATA_FORK); + xfs_bmap_trace_insert(fname, "LF", ip, idx, 1, new, NULL, + XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx, 1, new, XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, PREV.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, + PREV.br_startoff + new->br_blockcount, + PREV.br_startblock + new->br_blockcount, + PREV.br_blockcount - new->br_blockcount, + oldext))) + goto done; + cur->bc_rec.b = *new; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + break; + + case MASK2(RIGHT_FILLING, RIGHT_CONTIG): + /* + * Setting the last part of a previous oldext extent to newext. + * The right neighbor is contiguous with the new allocation. + */ + xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx, + XFS_DATA_FORK); + xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx + 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount - new->br_blockcount); + xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_allf(ep + 1, new->br_startoff, new->br_startblock, + new->br_blockcount + RIGHT.br_blockcount, newext); + xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx + 1, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, + PREV.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, PREV.br_startoff, + PREV.br_startblock, + PREV.br_blockcount - new->br_blockcount, + oldext))) + goto done; + if ((error = xfs_bmbt_increment(cur, 0, &i))) + goto done; + if ((error = xfs_bmbt_update(cur, new->br_startoff, + new->br_startblock, + new->br_blockcount + RIGHT.br_blockcount, + newext))) + goto done; + } + break; + + case MASK(RIGHT_FILLING): + /* + * Setting the last part of a previous oldext extent to newext. + * The right neighbor is not contiguous. + */ + xfs_bmap_trace_pre_update(fname, "RF", ip, idx, XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount - new->br_blockcount); + xfs_bmap_trace_post_update(fname, "RF", ip, idx, XFS_DATA_FORK); + xfs_bmap_trace_insert(fname, "RF", ip, idx + 1, 1, + new, NULL, XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx + 1, 1, new, XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, PREV.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, PREV.br_startoff, + PREV.br_startblock, + PREV.br_blockcount - new->br_blockcount, + oldext))) + goto done; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 0); + cur->bc_rec.b.br_state = XFS_EXT_NORM; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + break; + + case 0: + /* + * Setting the middle part of a previous oldext extent to + * newext. Contiguity is impossible here. + * One extent becomes three extents. + */ + xfs_bmap_trace_pre_update(fname, "0", ip, idx, XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, + new->br_startoff - PREV.br_startoff); + xfs_bmap_trace_post_update(fname, "0", ip, idx, XFS_DATA_FORK); + r[0] = *new; + r[1].br_startoff = new_endoff; + r[1].br_blockcount = + PREV.br_startoff + PREV.br_blockcount - new_endoff; + r[1].br_startblock = new->br_startblock + new->br_blockcount; + r[1].br_state = oldext; + xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 2, &r[0], &r[1], + XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx + 1, 2, &r[0], XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + ip->i_d.di_nextents += 2; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, PREV.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + /* new right extent - oldext */ + if ((error = xfs_bmbt_update(cur, r[1].br_startoff, + r[1].br_startblock, r[1].br_blockcount, + r[1].br_state))) + goto done; + /* new left extent - oldext */ + PREV.br_blockcount = + new->br_startoff - PREV.br_startoff; + cur->bc_rec.b = PREV; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_increment(cur, 0, &i))) + goto done; + ASSERT(i == 1); + /* new middle extent - newext */ + cur->bc_rec.b = *new; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + break; + + case MASK3(LEFT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + case MASK3(RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + case MASK2(LEFT_FILLING, RIGHT_CONTIG): + case MASK2(RIGHT_FILLING, LEFT_CONTIG): + case MASK2(LEFT_CONTIG, RIGHT_CONTIG): + case MASK(LEFT_CONTIG): + case MASK(RIGHT_CONTIG): + /* + * These cases are all impossible. + */ + ASSERT(0); + } + *curp = cur; +done: + *logflagsp = rval; + return error; +#undef LEFT +#undef RIGHT +#undef PREV +#undef MASK +#undef MASK2 +#undef MASK3 +#undef MASK4 +#undef STATE_SET +#undef STATE_TEST +#undef STATE_SET_TEST +#undef SWITCH_STATE +} + +/* + * Called by xfs_bmap_add_extent to handle cases converting a hole + * to a delayed allocation. + */ +/*ARGSUSED*/ +STATIC int /* error */ +xfs_bmap_add_extent_hole_delay( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t *cur, /* if null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int *logflagsp, /* inode logging flags */ + int rsvd) /* OK to allocate reserved blocks */ +{ + xfs_bmbt_rec_t *base; /* base of extent entry list */ + xfs_bmbt_rec_t *ep; /* extent list entry for idx */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_add_extent_hole_delay"; +#endif + xfs_bmbt_irec_t left; /* left neighbor extent entry */ + xfs_filblks_t newlen=0; /* new indirect size */ + xfs_filblks_t oldlen=0; /* old indirect size */ + xfs_bmbt_irec_t right; /* right neighbor extent entry */ + int state; /* state bits, accessed thru macros */ + xfs_filblks_t temp; /* temp for indirect calculations */ + enum { /* bit number definitions for state */ + LEFT_CONTIG, RIGHT_CONTIG, + LEFT_DELAY, RIGHT_DELAY, + LEFT_VALID, RIGHT_VALID + }; + +#define MASK(b) (1 << (b)) +#define MASK2(a,b) (MASK(a) | MASK(b)) +#define STATE_SET(b,v) ((v) ? (state |= MASK(b)) : (state &= ~MASK(b))) +#define STATE_TEST(b) (state & MASK(b)) +#define STATE_SET_TEST(b,v) ((v) ? ((state |= MASK(b)), 1) : \ + ((state &= ~MASK(b)), 0)) +#define SWITCH_STATE (state & MASK2(LEFT_CONTIG, RIGHT_CONTIG)) + + base = ip->i_df.if_u1.if_extents; + ep = &base[idx]; + state = 0; + ASSERT(ISNULLSTARTBLOCK(new->br_startblock)); + /* + * Check and set flags if this segment has a left neighbor + */ + if (STATE_SET_TEST(LEFT_VALID, idx > 0)) { + xfs_bmbt_get_all(ep - 1, &left); + STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(left.br_startblock)); + } + /* + * Check and set flags if the current (right) segment exists. + * If it doesn't exist, we're converting the hole at end-of-file. + */ + if (STATE_SET_TEST(RIGHT_VALID, + idx < + ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t))) { + xfs_bmbt_get_all(ep, &right); + STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(right.br_startblock)); + } + /* + * Set contiguity flags on the left and right neighbors. + * Don't let extents get too large, even if the pieces are contiguous. + */ + STATE_SET(LEFT_CONTIG, + STATE_TEST(LEFT_VALID) && STATE_TEST(LEFT_DELAY) && + left.br_startoff + left.br_blockcount == new->br_startoff && + left.br_blockcount + new->br_blockcount <= MAXEXTLEN); + STATE_SET(RIGHT_CONTIG, + STATE_TEST(RIGHT_VALID) && STATE_TEST(RIGHT_DELAY) && + new->br_startoff + new->br_blockcount == right.br_startoff && + new->br_blockcount + right.br_blockcount <= MAXEXTLEN && + (!STATE_TEST(LEFT_CONTIG) || + (left.br_blockcount + new->br_blockcount + + right.br_blockcount <= MAXEXTLEN))); + /* + * Switch out based on the contiguity flags. + */ + switch (SWITCH_STATE) { + + case MASK2(LEFT_CONTIG, RIGHT_CONTIG): + /* + * New allocation is contiguous with delayed allocations + * on the left and on the right. + * Merge all three into a single extent list entry. + */ + temp = left.br_blockcount + new->br_blockcount + + right.br_blockcount; + xfs_bmap_trace_pre_update(fname, "LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, temp); + oldlen = STARTBLOCKVAL(left.br_startblock) + + STARTBLOCKVAL(new->br_startblock) + + STARTBLOCKVAL(right.br_startblock); + newlen = xfs_bmap_worst_indlen(ip, temp); + xfs_bmbt_set_startblock(ep - 1, NULLSTARTBLOCK((int)newlen)); + xfs_bmap_trace_post_update(fname, "LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmap_trace_delete(fname, "LC|RC", ip, idx, 1, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx, 1, XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + break; + + case MASK(LEFT_CONTIG): + /* + * New allocation is contiguous with a delayed allocation + * on the left. + * Merge the new allocation with the left neighbor. + */ + temp = left.br_blockcount + new->br_blockcount; + xfs_bmap_trace_pre_update(fname, "LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, temp); + oldlen = STARTBLOCKVAL(left.br_startblock) + + STARTBLOCKVAL(new->br_startblock); + newlen = xfs_bmap_worst_indlen(ip, temp); + xfs_bmbt_set_startblock(ep - 1, NULLSTARTBLOCK((int)newlen)); + xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + break; + + case MASK(RIGHT_CONTIG): + /* + * New allocation is contiguous with a delayed allocation + * on the right. + * Merge the new allocation with the right neighbor. + */ + xfs_bmap_trace_pre_update(fname, "RC", ip, idx, XFS_DATA_FORK); + temp = new->br_blockcount + right.br_blockcount; + oldlen = STARTBLOCKVAL(new->br_startblock) + + STARTBLOCKVAL(right.br_startblock); + newlen = xfs_bmap_worst_indlen(ip, temp); + xfs_bmbt_set_allf(ep, new->br_startoff, + NULLSTARTBLOCK((int)newlen), temp, right.br_state); + xfs_bmap_trace_post_update(fname, "RC", ip, idx, XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + break; + + case 0: + /* + * New allocation is not contiguous with another + * delayed allocation. + * Insert a new entry. + */ + oldlen = newlen = 0; + xfs_bmap_trace_insert(fname, "0", ip, idx, 1, new, NULL, + XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx, 1, new, XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + break; + } + if (oldlen != newlen) { + ASSERT(oldlen > newlen); + xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS, + (int)(oldlen - newlen), rsvd); + /* + * Nothing to do for disk quota accounting here. + */ + } + *logflagsp = 0; + return 0; +#undef MASK +#undef MASK2 +#undef STATE_SET +#undef STATE_TEST +#undef STATE_SET_TEST +#undef SWITCH_STATE +} + +/* + * Called by xfs_bmap_add_extent to handle cases converting a hole + * to a real allocation. + */ +STATIC int /* error */ +xfs_bmap_add_extent_hole_real( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t *cur, /* if null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int *logflagsp, /* inode logging flags */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *ep; /* pointer to extent entry ins. point */ + int error; /* error return value */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_add_extent_hole_real"; +#endif + int i; /* temp state */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_irec_t left; /* left neighbor extent entry */ + xfs_bmbt_irec_t right; /* right neighbor extent entry */ + int state; /* state bits, accessed thru macros */ + enum { /* bit number definitions for state */ + LEFT_CONTIG, RIGHT_CONTIG, + LEFT_DELAY, RIGHT_DELAY, + LEFT_VALID, RIGHT_VALID + }; + +#define MASK(b) (1 << (b)) +#define MASK2(a,b) (MASK(a) | MASK(b)) +#define STATE_SET(b,v) ((v) ? (state |= MASK(b)) : (state &= ~MASK(b))) +#define STATE_TEST(b) (state & MASK(b)) +#define STATE_SET_TEST(b,v) ((v) ? ((state |= MASK(b)), 1) : \ + ((state &= ~MASK(b)), 0)) +#define SWITCH_STATE (state & MASK2(LEFT_CONTIG, RIGHT_CONTIG)) + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(idx <= ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)); + ep = &ifp->if_u1.if_extents[idx]; + state = 0; + /* + * Check and set flags if this segment has a left neighbor. + */ + if (STATE_SET_TEST(LEFT_VALID, idx > 0)) { + xfs_bmbt_get_all(ep - 1, &left); + STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(left.br_startblock)); + } + /* + * Check and set flags if this segment has a current value. + * Not true if we're inserting into the "hole" at eof. + */ + if (STATE_SET_TEST(RIGHT_VALID, + idx < + ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))) { + xfs_bmbt_get_all(ep, &right); + STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(right.br_startblock)); + } + /* + * We're inserting a real allocation between "left" and "right". + * Set the contiguity flags. Don't let extents get too large. + */ + STATE_SET(LEFT_CONTIG, + STATE_TEST(LEFT_VALID) && !STATE_TEST(LEFT_DELAY) && + left.br_startoff + left.br_blockcount == new->br_startoff && + left.br_startblock + left.br_blockcount == new->br_startblock && + left.br_state == new->br_state && + left.br_blockcount + new->br_blockcount <= MAXEXTLEN); + STATE_SET(RIGHT_CONTIG, + STATE_TEST(RIGHT_VALID) && !STATE_TEST(RIGHT_DELAY) && + new->br_startoff + new->br_blockcount == right.br_startoff && + new->br_startblock + new->br_blockcount == + right.br_startblock && + new->br_state == right.br_state && + new->br_blockcount + right.br_blockcount <= MAXEXTLEN && + (!STATE_TEST(LEFT_CONTIG) || + left.br_blockcount + new->br_blockcount + + right.br_blockcount <= MAXEXTLEN)); + + /* + * Select which case we're in here, and implement it. + */ + switch (SWITCH_STATE) { + + case MASK2(LEFT_CONTIG, RIGHT_CONTIG): + /* + * New allocation is contiguous with real allocations on the + * left and on the right. + * Merge all three into a single extent list entry. + */ + xfs_bmap_trace_pre_update(fname, "LC|RC", ip, idx - 1, + whichfork); + xfs_bmbt_set_blockcount(ep - 1, + left.br_blockcount + new->br_blockcount + + right.br_blockcount); + xfs_bmap_trace_post_update(fname, "LC|RC", ip, idx - 1, + whichfork); + xfs_bmap_trace_delete(fname, "LC|RC", ip, + idx, 1, whichfork); + xfs_bmap_delete_exlist(ip, idx, 1, whichfork); + ifp->if_lastex = idx - 1; + XFS_IFORK_NEXT_SET(ip, whichfork, + XFS_IFORK_NEXTENTS(ip, whichfork) - 1); + if (cur == NULL) { + *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); + return 0; + } + *logflagsp = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, right.br_startoff, + right.br_startblock, right.br_blockcount, &i))) + return error; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + return error; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + return error; + ASSERT(i == 1); + error = xfs_bmbt_update(cur, left.br_startoff, + left.br_startblock, + left.br_blockcount + new->br_blockcount + + right.br_blockcount, left.br_state); + return error; + + case MASK(LEFT_CONTIG): + /* + * New allocation is contiguous with a real allocation + * on the left. + * Merge the new allocation with the left neighbor. + */ + xfs_bmap_trace_pre_update(fname, "LC", ip, idx - 1, whichfork); + xfs_bmbt_set_blockcount(ep - 1, + left.br_blockcount + new->br_blockcount); + xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1, whichfork); + ifp->if_lastex = idx - 1; + if (cur == NULL) { + *logflagsp = XFS_ILOG_FEXT(whichfork); + return 0; + } + *logflagsp = 0; + if ((error = xfs_bmbt_lookup_eq(cur, left.br_startoff, + left.br_startblock, left.br_blockcount, &i))) + return error; + ASSERT(i == 1); + error = xfs_bmbt_update(cur, left.br_startoff, + left.br_startblock, + left.br_blockcount + new->br_blockcount, + left.br_state); + return error; + + case MASK(RIGHT_CONTIG): + /* + * New allocation is contiguous with a real allocation + * on the right. + * Merge the new allocation with the right neighbor. + */ + xfs_bmap_trace_pre_update(fname, "RC", ip, idx, whichfork); + xfs_bmbt_set_allf(ep, new->br_startoff, new->br_startblock, + new->br_blockcount + right.br_blockcount, + right.br_state); + xfs_bmap_trace_post_update(fname, "RC", ip, idx, whichfork); + ifp->if_lastex = idx; + if (cur == NULL) { + *logflagsp = XFS_ILOG_FEXT(whichfork); + return 0; + } + *logflagsp = 0; + if ((error = xfs_bmbt_lookup_eq(cur, right.br_startoff, + right.br_startblock, right.br_blockcount, &i))) + return error; + ASSERT(i == 1); + error = xfs_bmbt_update(cur, new->br_startoff, + new->br_startblock, + new->br_blockcount + right.br_blockcount, + right.br_state); + return error; + + case 0: + /* + * New allocation is not contiguous with another + * real allocation. + * Insert a new entry. + */ + xfs_bmap_trace_insert(fname, "0", ip, idx, 1, new, NULL, + whichfork); + xfs_bmap_insert_exlist(ip, idx, 1, new, whichfork); + ifp->if_lastex = idx; + XFS_IFORK_NEXT_SET(ip, whichfork, + XFS_IFORK_NEXTENTS(ip, whichfork) + 1); + if (cur == NULL) { + *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); + return 0; + } + *logflagsp = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, &i))) + return error; + ASSERT(i == 0); + cur->bc_rec.b.br_state = new->br_state; + if ((error = xfs_bmbt_insert(cur, &i))) + return error; + ASSERT(i == 1); + return 0; + } +#undef MASK +#undef MASK2 +#undef STATE_SET +#undef STATE_TEST +#undef STATE_SET_TEST +#undef SWITCH_STATE + /* NOTREACHED */ + ASSERT(0); + return 0; /* keep gcc quite */ +} + +#define XFS_ALLOC_GAP_UNITS 4 + +/* + * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. + * It figures out where to ask the underlying allocator to put the new extent. + */ +STATIC int /* error */ +xfs_bmap_alloc( + xfs_bmalloca_t *ap) /* bmap alloc argument struct */ +{ + xfs_fsblock_t adjust; /* adjustment to block numbers */ + xfs_alloctype_t atype=0; /* type for allocation routines */ + int error; /* error return value */ + xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */ + xfs_mount_t *mp; /* mount point structure */ + int nullfb; /* true if ap->firstblock isn't set */ + int rt; /* true if inode is realtime */ +#ifdef __KERNEL__ + xfs_extlen_t prod=0; /* product factor for allocators */ + xfs_extlen_t ralen=0; /* realtime allocation length */ +#endif + +#define ISLEGAL(x,y) \ + (rt ? \ + (x) < mp->m_sb.sb_rblocks : \ + XFS_FSB_TO_AGNO(mp, x) == XFS_FSB_TO_AGNO(mp, y) && \ + XFS_FSB_TO_AGNO(mp, x) < mp->m_sb.sb_agcount && \ + XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks) + + /* + * Set up variables. + */ + mp = ap->ip->i_mount; + nullfb = ap->firstblock == NULLFSBLOCK; + rt = (ap->ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && ap->userdata; + fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock); +#ifdef __KERNEL__ + if (rt) { + xfs_extlen_t extsz; /* file extent size for rt */ + xfs_fileoff_t nexto; /* next file offset */ + xfs_extlen_t orig_alen; /* original ap->alen */ + xfs_fileoff_t orig_end; /* original off+len */ + xfs_fileoff_t orig_off; /* original ap->off */ + xfs_extlen_t mod_off; /* modulus calculations */ + xfs_fileoff_t prevo; /* previous file offset */ + xfs_rtblock_t rtx; /* realtime extent number */ + xfs_extlen_t temp; /* temp for rt calculations */ + + /* + * Set prod to match the realtime extent size. + */ + if (!(extsz = ap->ip->i_d.di_extsize)) + extsz = mp->m_sb.sb_rextsize; + prod = extsz / mp->m_sb.sb_rextsize; + orig_off = ap->off; + orig_alen = ap->alen; + orig_end = orig_off + orig_alen; + /* + * If the file offset is unaligned vs. the extent size + * we need to align it. This will be possible unless + * the file was previously written with a kernel that didn't + * perform this alignment. + */ + mod_off = do_mod(orig_off, extsz); + if (mod_off) { + ap->alen += mod_off; + ap->off -= mod_off; + } + /* + * Same adjustment for the end of the requested area. + */ + if ((temp = (ap->alen % extsz))) + ap->alen += extsz - temp; + /* + * If the previous block overlaps with this proposed allocation + * then move the start forward without adjusting the length. + */ + prevo = + ap->prevp->br_startoff == NULLFILEOFF ? + 0 : + (ap->prevp->br_startoff + + ap->prevp->br_blockcount); + if (ap->off != orig_off && ap->off < prevo) + ap->off = prevo; + /* + * If the next block overlaps with this proposed allocation + * then move the start back without adjusting the length, + * but not before offset 0. + * This may of course make the start overlap previous block, + * and if we hit the offset 0 limit then the next block + * can still overlap too. + */ + nexto = (ap->eof || ap->gotp->br_startoff == NULLFILEOFF) ? + NULLFILEOFF : ap->gotp->br_startoff; + if (!ap->eof && + ap->off + ap->alen != orig_end && + ap->off + ap->alen > nexto) + ap->off = nexto > ap->alen ? nexto - ap->alen : 0; + /* + * If we're now overlapping the next or previous extent that + * means we can't fit an extsz piece in this hole. Just move + * the start forward to the first legal spot and set + * the length so we hit the end. + */ + if ((ap->off != orig_off && ap->off < prevo) || + (ap->off + ap->alen != orig_end && + ap->off + ap->alen > nexto)) { + ap->off = prevo; + ap->alen = nexto - prevo; + } + /* + * If the result isn't a multiple of rtextents we need to + * remove blocks until it is. + */ + if ((temp = (ap->alen % mp->m_sb.sb_rextsize))) { + /* + * We're not covering the original request, or + * we won't be able to once we fix the length. + */ + if (orig_off < ap->off || + orig_end > ap->off + ap->alen || + ap->alen - temp < orig_alen) + return XFS_ERROR(EINVAL); + /* + * Try to fix it by moving the start up. + */ + if (ap->off + temp <= orig_off) { + ap->alen -= temp; + ap->off += temp; + } + /* + * Try to fix it by moving the end in. + */ + else if (ap->off + ap->alen - temp >= orig_end) + ap->alen -= temp; + /* + * Set the start to the minimum then trim the length. + */ + else { + ap->alen -= orig_off - ap->off; + ap->off = orig_off; + ap->alen -= ap->alen % mp->m_sb.sb_rextsize; + } + /* + * Result doesn't cover the request, fail it. + */ + if (orig_off < ap->off || orig_end > ap->off + ap->alen) + return XFS_ERROR(EINVAL); + } + ASSERT(ap->alen % mp->m_sb.sb_rextsize == 0); + /* + * If the offset & length are not perfectly aligned + * then kill prod, it will just get us in trouble. + */ + if (do_mod(ap->off, extsz) || ap->alen % extsz) + prod = 1; + /* + * Set ralen to be the actual requested length in rtextents. + */ + ralen = ap->alen / mp->m_sb.sb_rextsize; + /* + * If the old value was close enough to MAXEXTLEN that + * we rounded up to it, cut it back so it's legal again. + * Note that if it's a really large request (bigger than + * MAXEXTLEN), we don't hear about that number, and can't + * adjust the starting point to match it. + */ + if (ralen * mp->m_sb.sb_rextsize >= MAXEXTLEN) + ralen = MAXEXTLEN / mp->m_sb.sb_rextsize; + /* + * If it's an allocation to an empty file at offset 0, + * pick an extent that will space things out in the rt area. + */ + if (ap->eof && ap->off == 0) { + error = xfs_rtpick_extent(mp, ap->tp, ralen, &rtx); + if (error) + return error; + ap->rval = rtx * mp->m_sb.sb_rextsize; + } else + ap->rval = 0; + } +#else + if (rt) + ap->rval = 0; +#endif /* __KERNEL__ */ + else if (nullfb) + ap->rval = XFS_INO_TO_FSB(mp, ap->ip->i_ino); + else + ap->rval = ap->firstblock; + /* + * If allocating at eof, and there's a previous real block, + * try to use it's last block as our starting point. + */ + if (ap->eof && ap->prevp->br_startoff != NULLFILEOFF && + !ISNULLSTARTBLOCK(ap->prevp->br_startblock) && + ISLEGAL(ap->prevp->br_startblock + ap->prevp->br_blockcount, + ap->prevp->br_startblock)) { + ap->rval = ap->prevp->br_startblock + ap->prevp->br_blockcount; + /* + * Adjust for the gap between prevp and us. + */ + adjust = ap->off - + (ap->prevp->br_startoff + ap->prevp->br_blockcount); + if (adjust && + ISLEGAL(ap->rval + adjust, ap->prevp->br_startblock)) + ap->rval += adjust; + } + /* + * If not at eof, then compare the two neighbor blocks. + * Figure out whether either one gives us a good starting point, + * and pick the better one. + */ + else if (!ap->eof) { + xfs_fsblock_t gotbno; /* right side block number */ + xfs_fsblock_t gotdiff=0; /* right side difference */ + xfs_fsblock_t prevbno; /* left side block number */ + xfs_fsblock_t prevdiff=0; /* left side difference */ + + /* + * If there's a previous (left) block, select a requested + * start block based on it. + */ + if (ap->prevp->br_startoff != NULLFILEOFF && + !ISNULLSTARTBLOCK(ap->prevp->br_startblock) && + (prevbno = ap->prevp->br_startblock + + ap->prevp->br_blockcount) && + ISLEGAL(prevbno, ap->prevp->br_startblock)) { + /* + * Calculate gap to end of previous block. + */ + adjust = prevdiff = ap->off - + (ap->prevp->br_startoff + + ap->prevp->br_blockcount); + /* + * Figure the startblock based on the previous block's + * end and the gap size. + * Heuristic! + * If the gap is large relative to the piece we're + * allocating, or using it gives us an illegal block + * number, then just use the end of the previous block. + */ + if (prevdiff <= XFS_ALLOC_GAP_UNITS * ap->alen && + ISLEGAL(prevbno + prevdiff, + ap->prevp->br_startblock)) + prevbno += adjust; + else + prevdiff += adjust; + /* + * If the firstblock forbids it, can't use it, + * must use default. + */ + if (!rt && !nullfb && + XFS_FSB_TO_AGNO(mp, prevbno) != fb_agno) + prevbno = NULLFSBLOCK; + } + /* + * No previous block or can't follow it, just default. + */ + else + prevbno = NULLFSBLOCK; + /* + * If there's a following (right) block, select a requested + * start block based on it. + */ + if (!ISNULLSTARTBLOCK(ap->gotp->br_startblock)) { + /* + * Calculate gap to start of next block. + */ + adjust = gotdiff = ap->gotp->br_startoff - ap->off; + /* + * Figure the startblock based on the next block's + * start and the gap size. + */ + gotbno = ap->gotp->br_startblock; + /* + * Heuristic! + * If the gap is large relative to the piece we're + * allocating, or using it gives us an illegal block + * number, then just use the start of the next block + * offset by our length. + */ + if (gotdiff <= XFS_ALLOC_GAP_UNITS * ap->alen && + ISLEGAL(gotbno - gotdiff, gotbno)) + gotbno -= adjust; + else if (ISLEGAL(gotbno - ap->alen, gotbno)) { + gotbno -= ap->alen; + gotdiff += adjust - ap->alen; + } else + gotdiff += adjust; + /* + * If the firstblock forbids it, can't use it, + * must use default. + */ + if (!rt && !nullfb && + XFS_FSB_TO_AGNO(mp, gotbno) != fb_agno) + gotbno = NULLFSBLOCK; + } + /* + * No next block, just default. + */ + else + gotbno = NULLFSBLOCK; + /* + * If both valid, pick the better one, else the only good + * one, else ap->rval is already set (to 0 or the inode block). + */ + if (prevbno != NULLFSBLOCK && gotbno != NULLFSBLOCK) + ap->rval = prevdiff <= gotdiff ? prevbno : gotbno; + else if (prevbno != NULLFSBLOCK) + ap->rval = prevbno; + else if (gotbno != NULLFSBLOCK) + ap->rval = gotbno; + } + /* + * If allowed, use ap->rval; otherwise must use firstblock since + * it's in the right allocation group. + */ + if (nullfb || rt || XFS_FSB_TO_AGNO(mp, ap->rval) == fb_agno) + ; + else + ap->rval = ap->firstblock; + /* + * Realtime allocation, done through xfs_rtallocate_extent. + */ + if (rt) { +#ifndef __KERNEL__ + ASSERT(0); +#else + xfs_rtblock_t rtb; + + atype = ap->rval == 0 ? + XFS_ALLOCTYPE_ANY_AG : XFS_ALLOCTYPE_NEAR_BNO; + do_div(ap->rval, mp->m_sb.sb_rextsize); + rtb = ap->rval; + ap->alen = ralen; + if ((error = xfs_rtallocate_extent(ap->tp, ap->rval, 1, ap->alen, + &ralen, atype, ap->wasdel, prod, &rtb))) + return error; + if (rtb == NULLFSBLOCK && prod > 1 && + (error = xfs_rtallocate_extent(ap->tp, ap->rval, 1, + ap->alen, &ralen, atype, + ap->wasdel, 1, &rtb))) + return error; + ap->rval = rtb; + if (ap->rval != NULLFSBLOCK) { + ap->rval *= mp->m_sb.sb_rextsize; + ralen *= mp->m_sb.sb_rextsize; + ap->alen = ralen; + ap->ip->i_d.di_nblocks += ralen; + xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE); + if (ap->wasdel) + ap->ip->i_delayed_blks -= ralen; + /* + * Adjust the disk quota also. This was reserved + * earlier. + */ + if (XFS_IS_QUOTA_ON(mp) && + ap->ip->i_ino != mp->m_sb.sb_uquotino && + ap->ip->i_ino != mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(ap->tp, ap->ip, + ap->wasdel ? + XFS_TRANS_DQ_DELRTBCOUNT : + XFS_TRANS_DQ_RTBCOUNT, + (long)ralen); + } else + ap->alen = 0; +#endif /* __KERNEL__ */ + } + /* + * Normal allocation, done through xfs_alloc_vextent. + */ + else { + xfs_agnumber_t ag; + xfs_alloc_arg_t args; + xfs_extlen_t blen; + xfs_extlen_t delta; + int isaligned; + xfs_extlen_t longest; + xfs_extlen_t need; + xfs_extlen_t nextminlen=0; + int notinit; + xfs_perag_t *pag; + xfs_agnumber_t startag; + int tryagain; + + tryagain = isaligned = 0; + args.tp = ap->tp; + args.mp = mp; + args.fsbno = ap->rval; + args.maxlen = MIN(ap->alen, mp->m_sb.sb_agblocks); + blen = 0; + if (nullfb) { + args.type = XFS_ALLOCTYPE_START_BNO; + args.total = ap->total; + /* + * Find the longest available space. + * We're going to try for the whole allocation at once. + */ + startag = ag = XFS_FSB_TO_AGNO(mp, args.fsbno); + notinit = 0; + mrlock(&mp->m_peraglock, MR_ACCESS, PINOD); + while (blen < ap->alen) { + pag = &mp->m_perag[ag]; + if (!pag->pagf_init && + (error = xfs_alloc_pagf_init(mp, args.tp, + ag, XFS_ALLOC_FLAG_TRYLOCK))) { + mrunlock(&mp->m_peraglock); + return error; + } + /* + * See xfs_alloc_fix_freelist... + */ + if (pag->pagf_init) { + need = XFS_MIN_FREELIST_PAG(pag, mp); + delta = need > pag->pagf_flcount ? + need - pag->pagf_flcount : 0; + longest = (pag->pagf_longest > delta) ? + (pag->pagf_longest - delta) : + (pag->pagf_flcount > 0 || + pag->pagf_longest > 0); + if (blen < longest) + blen = longest; + } else + notinit = 1; + if (++ag == mp->m_sb.sb_agcount) + ag = 0; + if (ag == startag) + break; + } + mrunlock(&mp->m_peraglock); + /* + * Since the above loop did a BUF_TRYLOCK, it is + * possible that there is space for this request. + */ + if (notinit || blen < ap->minlen) + args.minlen = ap->minlen; + /* + * If the best seen length is less than the request + * length, use the best as the minimum. + */ + else if (blen < ap->alen) + args.minlen = blen; + /* + * Otherwise we've seen an extent as big as alen, + * use that as the minimum. + */ + else + args.minlen = ap->alen; + } else if (ap->low) { + args.type = XFS_ALLOCTYPE_FIRST_AG; + args.total = args.minlen = ap->minlen; + } else { + args.type = XFS_ALLOCTYPE_NEAR_BNO; + args.total = ap->total; + args.minlen = ap->minlen; + } + if (ap->ip->i_d.di_extsize) { + args.prod = ap->ip->i_d.di_extsize; + if ((args.mod = (xfs_extlen_t)do_mod(ap->off, args.prod))) + args.mod = (xfs_extlen_t)(args.prod - args.mod); + } else if (mp->m_sb.sb_blocksize >= NBPP) { + args.prod = 1; + args.mod = 0; + } else { + args.prod = NBPP >> mp->m_sb.sb_blocklog; + if ((args.mod = (xfs_extlen_t)(do_mod(ap->off, args.prod)))) + args.mod = (xfs_extlen_t)(args.prod - args.mod); + } + /* + * If we are not low on available data blocks, and the + * underlying logical volume manager is a stripe, and + * the file offset is zero then try to allocate data + * blocks on stripe unit boundary. + * NOTE: ap->aeof is only set if the allocation length + * is >= the stripe unit and the allocation offset is + * at the end of file. + */ + if (!ap->low && ap->aeof) { + if (!ap->off) { + args.alignment = mp->m_dalign; + atype = args.type; + isaligned = 1; + /* + * Adjust for alignment + */ + if (blen > args.alignment && blen <= ap->alen) + args.minlen = blen - args.alignment; + args.minalignslop = 0; + } else { + /* + * First try an exact bno allocation. + * If it fails then do a near or start bno + * allocation with alignment turned on. + */ + atype = args.type; + tryagain = 1; + args.type = XFS_ALLOCTYPE_THIS_BNO; + args.alignment = 1; + /* + * Compute the minlen+alignment for the + * next case. Set slop so that the value + * of minlen+alignment+slop doesn't go up + * between the calls. + */ + if (blen > mp->m_dalign && blen <= ap->alen) + nextminlen = blen - mp->m_dalign; + else + nextminlen = args.minlen; + if (nextminlen + mp->m_dalign > args.minlen + 1) + args.minalignslop = + nextminlen + mp->m_dalign - + args.minlen - 1; + else + args.minalignslop = 0; + } + } else { + args.alignment = 1; + args.minalignslop = 0; + } + args.minleft = ap->minleft; + args.wasdel = ap->wasdel; + args.isfl = 0; + args.userdata = ap->userdata; + if ((error = xfs_alloc_vextent(&args))) + return error; + if (tryagain && args.fsbno == NULLFSBLOCK) { + /* + * Exact allocation failed. Now try with alignment + * turned on. + */ + args.type = atype; + args.fsbno = ap->rval; + args.alignment = mp->m_dalign; + args.minlen = nextminlen; + args.minalignslop = 0; + isaligned = 1; + if ((error = xfs_alloc_vextent(&args))) + return error; + } + if (isaligned && args.fsbno == NULLFSBLOCK) { + /* + * allocation failed, so turn off alignment and + * try again. + */ + args.type = atype; + args.fsbno = ap->rval; + args.alignment = 0; + if ((error = xfs_alloc_vextent(&args))) + return error; + } + if (args.fsbno == NULLFSBLOCK && nullfb && + args.minlen > ap->minlen) { + args.minlen = ap->minlen; + args.type = XFS_ALLOCTYPE_START_BNO; + args.fsbno = ap->rval; + if ((error = xfs_alloc_vextent(&args))) + return error; + } + if (args.fsbno == NULLFSBLOCK && nullfb) { + args.fsbno = 0; + args.type = XFS_ALLOCTYPE_FIRST_AG; + args.total = ap->minlen; + args.minleft = 0; + if ((error = xfs_alloc_vextent(&args))) + return error; + ap->low = 1; + } + if (args.fsbno != NULLFSBLOCK) { + ap->firstblock = ap->rval = args.fsbno; + ASSERT(nullfb || fb_agno == args.agno || + (ap->low && fb_agno < args.agno)); + ap->alen = args.len; + ap->ip->i_d.di_nblocks += args.len; + xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE); + if (ap->wasdel) + ap->ip->i_delayed_blks -= args.len; + /* + * Adjust the disk quota also. This was reserved + * earlier. + */ + if (XFS_IS_QUOTA_ON(mp) && + ap->ip->i_ino != mp->m_sb.sb_uquotino && + ap->ip->i_ino != mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(ap->tp, ap->ip, + ap->wasdel ? + XFS_TRANS_DQ_DELBCOUNT : + XFS_TRANS_DQ_BCOUNT, + (long)args.len); + } else { + ap->rval = NULLFSBLOCK; + ap->alen = 0; + } + } + return 0; +#undef ISLEGAL +} + +/* + * Transform a btree format file with only one leaf node, where the + * extents list will fit in the inode, into an extents format file. + * Since the extent list is already in-core, all we have to do is + * give up the space for the btree root and pitch the leaf block. + */ +STATIC int /* error */ +xfs_bmap_btree_to_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_btree_cur_t *cur, /* btree cursor */ + int *logflagsp, /* inode logging flags */ + int whichfork, /* data or attr fork */ + int async) /* xaction can be async */ +{ + /* REFERENCED */ + xfs_bmbt_block_t *cblock;/* child btree block */ + xfs_fsblock_t cbno; /* child block number */ + xfs_buf_t *cbp; /* child block's buffer */ + int error; /* error return value */ + xfs_ifork_t *ifp; /* inode fork data */ + xfs_mount_t *mp; /* mount point structure */ + xfs_bmbt_ptr_t *pp; /* ptr to block address */ + xfs_bmbt_block_t *rblock;/* root btree block */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_flags & XFS_IFEXTENTS); + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE); + rblock = ifp->if_broot; + ASSERT(INT_GET(rblock->bb_level, ARCH_CONVERT) == 1); + ASSERT(INT_GET(rblock->bb_numrecs, ARCH_CONVERT) == 1); + ASSERT(XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes) == 1); + mp = ip->i_mount; + pp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, ifp->if_broot_bytes); + *logflagsp = 0; +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), 1))) + return error; +#endif + cbno = INT_GET(*pp, ARCH_CONVERT); + if ((error = xfs_btree_read_bufl(mp, tp, cbno, 0, &cbp, + XFS_BMAP_BTREE_REF))) + return error; + cblock = XFS_BUF_TO_BMBT_BLOCK(cbp); + if ((error = xfs_btree_check_lblock(cur, cblock, 0, cbp))) + return error; + xfs_bmap_add_free(cbno, 1, cur->bc_private.b.flist, mp); + if (!async) + xfs_trans_set_sync(tp); + ip->i_d.di_nblocks--; + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); + xfs_trans_binval(tp, cbp); + if (cur->bc_bufs[0] == cbp) + cur->bc_bufs[0] = NULL; + xfs_iroot_realloc(ip, -1, whichfork); + ASSERT(ifp->if_broot == NULL); + ASSERT((ifp->if_flags & XFS_IFBROOT) == 0); + XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); + *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); + return 0; +} + +/* + * Called by xfs_bmapi to update extent list structure and the btree + * after removing space (or undoing a delayed allocation). + */ +STATIC int /* error */ +xfs_bmap_del_extent( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_trans_t *tp, /* current transaction pointer */ + xfs_extnum_t idx, /* extent number to update/delete */ + xfs_bmap_free_t *flist, /* list of extents to be freed */ + xfs_btree_cur_t *cur, /* if null, not a btree */ + xfs_bmbt_irec_t *del, /* data to remove from extent list */ + int iflags, /* input flags */ + int *logflagsp, /* inode logging flags */ + int whichfork, /* data or attr fork */ + int rsvd) /* OK to allocate reserved blocks */ +{ + xfs_filblks_t da_new; /* new delay-alloc indirect blocks */ + xfs_filblks_t da_old; /* old delay-alloc indirect blocks */ + xfs_fsblock_t del_endblock=0; /* first block past del */ + xfs_fileoff_t del_endoff; /* first offset past del */ + int delay; /* current block is delayed allocated */ + int do_fx; /* free extent at end of routine */ + xfs_bmbt_rec_t *ep; /* current extent entry pointer */ + int error; /* error return value */ + int flags; /* inode logging flags */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_del_extent"; +#endif + xfs_bmbt_irec_t got; /* current extent entry */ + xfs_fileoff_t got_endoff; /* first offset past got */ + int i; /* temp state */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_mount_t *mp; /* mount structure */ + xfs_filblks_t nblks; /* quota/sb block count */ + xfs_bmbt_irec_t new; /* new record to be inserted */ + /* REFERENCED */ + xfs_extnum_t nextents; /* number of extents in list */ + uint qfield; /* quota field to update */ + xfs_filblks_t temp; /* for indirect length calculations */ + xfs_filblks_t temp2; /* for indirect length calculations */ + + XFS_STATS_INC(xfsstats.xs_del_exlist); + mp = ip->i_mount; + ifp = XFS_IFORK_PTR(ip, whichfork); + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + ASSERT(idx >= 0 && idx < nextents); + ASSERT(del->br_blockcount > 0); + ep = &ifp->if_u1.if_extents[idx]; + xfs_bmbt_get_all(ep, &got); + ASSERT(got.br_startoff <= del->br_startoff); + del_endoff = del->br_startoff + del->br_blockcount; + got_endoff = got.br_startoff + got.br_blockcount; + ASSERT(got_endoff >= del_endoff); + delay = ISNULLSTARTBLOCK(got.br_startblock); + ASSERT(ISNULLSTARTBLOCK(del->br_startblock) == delay); + flags = 0; + qfield = 0; + error = 0; + /* + * If deleting a real allocation, must free up the disk space. + */ + if (!delay) { + flags = XFS_ILOG_CORE; + /* + * Realtime allocation. Free it and record di_nblocks update. + */ + if (whichfork == XFS_DATA_FORK && + (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { + xfs_fsblock_t bno; + xfs_filblks_t len; + + ASSERT(do_mod(del->br_blockcount, + mp->m_sb.sb_rextsize) == 0); + ASSERT(do_mod(del->br_startblock, + mp->m_sb.sb_rextsize) == 0); + bno = del->br_startblock; + do_div(bno, mp->m_sb.sb_rextsize); + len = del->br_blockcount; + do_div(len, mp->m_sb.sb_rextsize); + if ((error = xfs_rtfree_extent(ip->i_transp, bno, + (xfs_extlen_t)len))) + goto done; + do_fx = 0; + nblks = len * mp->m_sb.sb_rextsize; + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) + qfield = XFS_TRANS_DQ_RTBCOUNT; + } + /* + * Ordinary allocation. + */ + else { + do_fx = 1; + nblks = del->br_blockcount; + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) + qfield = XFS_TRANS_DQ_BCOUNT; + /* + * If we're freeing meta-data, then the transaction + * that frees the blocks must be synchronous. This + * ensures that noone can reuse the blocks before + * they are permanently free. For regular data + * it is the callers responsibility to make the + * data permanently inaccessible before calling + * here to free it. + */ + if (iflags & XFS_BMAPI_METADATA) + xfs_trans_set_sync(tp); + } + /* + * Set up del_endblock and cur for later. + */ + del_endblock = del->br_startblock + del->br_blockcount; + if (cur) { + if ((error = xfs_bmbt_lookup_eq(cur, got.br_startoff, + got.br_startblock, got.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + } + da_old = da_new = 0; + } else { + da_old = STARTBLOCKVAL(got.br_startblock); + da_new = 0; + nblks = 0; + do_fx = 0; + } + /* + * Set flag value to use in switch statement. + * Left-contig is 2, right-contig is 1. + */ + switch (((got.br_startoff == del->br_startoff) << 1) | + (got_endoff == del_endoff)) { + case 3: + /* + * Matches the whole extent. Delete the entry. + */ + xfs_bmap_trace_delete(fname, "3", ip, idx, 1, whichfork); + xfs_bmap_delete_exlist(ip, idx, 1, whichfork); + ifp->if_lastex = idx; + if (delay) + break; + XFS_IFORK_NEXT_SET(ip, whichfork, + XFS_IFORK_NEXTENTS(ip, whichfork) - 1); + flags |= XFS_ILOG_CORE; + if (!cur) { + flags |= XFS_ILOG_FEXT(whichfork); + break; + } + if ((error = xfs_bmbt_delete(cur, iflags & XFS_BMAPI_ASYNC, &i))) + goto done; + ASSERT(i == 1); + break; + + case 2: + /* + * Deleting the first part of the extent. + */ + xfs_bmap_trace_pre_update(fname, "2", ip, idx, whichfork); + xfs_bmbt_set_startoff(ep, del_endoff); + temp = got.br_blockcount - del->br_blockcount; + xfs_bmbt_set_blockcount(ep, temp); + ifp->if_lastex = idx; + if (delay) { + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + da_old); + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "2", ip, idx, + whichfork); + da_new = temp; + break; + } + xfs_bmbt_set_startblock(ep, del_endblock); + xfs_bmap_trace_post_update(fname, "2", ip, idx, whichfork); + if (!cur) { + flags |= XFS_ILOG_FEXT(whichfork); + break; + } + if ((error = xfs_bmbt_update(cur, del_endoff, del_endblock, + got.br_blockcount - del->br_blockcount, + got.br_state))) + goto done; + break; + + case 1: + /* + * Deleting the last part of the extent. + */ + temp = got.br_blockcount - del->br_blockcount; + xfs_bmap_trace_pre_update(fname, "1", ip, idx, whichfork); + xfs_bmbt_set_blockcount(ep, temp); + ifp->if_lastex = idx; + if (delay) { + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + da_old); + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "1", ip, idx, + whichfork); + da_new = temp; + break; + } + xfs_bmap_trace_post_update(fname, "1", ip, idx, whichfork); + if (!cur) { + flags |= XFS_ILOG_FEXT(whichfork); + break; + } + if ((error = xfs_bmbt_update(cur, got.br_startoff, + got.br_startblock, + got.br_blockcount - del->br_blockcount, + got.br_state))) + goto done; + break; + + case 0: + /* + * Deleting the middle of the extent. + */ + temp = del->br_startoff - got.br_startoff; + xfs_bmap_trace_pre_update(fname, "0", ip, idx, whichfork); + xfs_bmbt_set_blockcount(ep, temp); + new.br_startoff = del_endoff; + temp2 = got_endoff - del_endoff; + new.br_blockcount = temp2; + new.br_state = got.br_state; + if (!delay) { + new.br_startblock = del_endblock; + flags |= XFS_ILOG_CORE; + if (cur) { + if ((error = xfs_bmbt_update(cur, + got.br_startoff, + got.br_startblock, temp, + got.br_state))) + goto done; + if ((error = xfs_bmbt_increment(cur, 0, &i))) + goto done; + cur->bc_rec.b = new; + error = xfs_bmbt_insert(cur, &i); + if (error && error != ENOSPC) + goto done; + /* + * If get no-space back from btree insert, + * it tried a split, and we have a zero + * block reservation. + * Fix up our state and return the error. + */ + if (error == ENOSPC) { + /* + * Reset the cursor, don't trust + * it after any insert operation. + */ + if ((error = xfs_bmbt_lookup_eq(cur, + got.br_startoff, + got.br_startblock, + temp, &i))) + goto done; + ASSERT(i == 1); + /* + * Update the btree record back + * to the original value. + */ + if ((error = xfs_bmbt_update(cur, + got.br_startoff, + got.br_startblock, + got.br_blockcount, + got.br_state))) + goto done; + /* + * Reset the extent record back + * to the original value. + */ + xfs_bmbt_set_blockcount(ep, + got.br_blockcount); + flags = 0; + error = XFS_ERROR(ENOSPC); + goto done; + } + ASSERT(i == 1); + } else + flags |= XFS_ILOG_FEXT(whichfork); + XFS_IFORK_NEXT_SET(ip, whichfork, + XFS_IFORK_NEXTENTS(ip, whichfork) + 1); + } else { + ASSERT(whichfork == XFS_DATA_FORK); + temp = xfs_bmap_worst_indlen(ip, temp); + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + temp2 = xfs_bmap_worst_indlen(ip, temp2); + new.br_startblock = NULLSTARTBLOCK((int)temp2); + da_new = temp + temp2; + while (da_new > da_old) { + if (temp) { + temp--; + da_new--; + xfs_bmbt_set_startblock(ep, + NULLSTARTBLOCK((int)temp)); + } + if (da_new == da_old) + break; + if (temp2) { + temp2--; + da_new--; + new.br_startblock = + NULLSTARTBLOCK((int)temp2); + } + } + } + xfs_bmap_trace_post_update(fname, "0", ip, idx, whichfork); + xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 1, &new, NULL, + whichfork); + xfs_bmap_insert_exlist(ip, idx + 1, 1, &new, whichfork); + ifp->if_lastex = idx + 1; + break; + } + /* + * If we need to, add to list of extents to delete. + */ + if (do_fx) + xfs_bmap_add_free(del->br_startblock, del->br_blockcount, flist, + mp); + /* + * Adjust inode # blocks in the file. + */ + if (nblks) + ip->i_d.di_nblocks -= nblks; + /* + * Adjust quota data. + */ + if (qfield) + xfs_trans_mod_dquot_byino(tp, ip, qfield, (long)-nblks); + /* + * Account for change in delayed indirect blocks. + * Nothing to do for disk quota accounting here. + */ + ASSERT(da_old >= da_new); + if (da_old > da_new) + xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, (int)(da_old - da_new), + rsvd); +done: + *logflagsp = flags; + return error; +} + +/* + * Remove the entry "free" from the free item list. Prev points to the + * previous entry, unless "free" is the head of the list. + */ +STATIC void +xfs_bmap_del_free( + xfs_bmap_free_t *flist, /* free item list header */ + xfs_bmap_free_item_t *prev, /* previous item on list, if any */ + xfs_bmap_free_item_t *free) /* list item to be freed */ +{ + if (prev) + prev->xbfi_next = free->xbfi_next; + else + flist->xbf_first = free->xbfi_next; + flist->xbf_count--; + kmem_zone_free(xfs_bmap_free_item_zone, free); +} + +/* + * Remove count entries from the extents array for inode "ip", starting + * at index "idx". Copies the remaining items down over the deleted ones, + * and gives back the excess memory. + */ +STATIC void +xfs_bmap_delete_exlist( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* starting delete index */ + xfs_extnum_t count, /* count of items to delete */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* base of extent list */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t nextents; /* number of extents in list after */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_flags & XFS_IFEXTENTS); + base = ifp->if_u1.if_extents; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - count; + ovbcopy(&base[idx + count], &base[idx], + (nextents - idx) * sizeof(*base)); + xfs_iext_realloc(ip, -count, whichfork); +} + +/* + * Convert an extents-format file into a btree-format file. + * The new file will have a root block (in the inode) and a single child block. + */ +STATIC int /* error */ +xfs_bmap_extents_to_btree( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first-block-allocated */ + xfs_bmap_free_t *flist, /* blocks freed in xaction */ + xfs_btree_cur_t **curp, /* cursor returned to caller */ + int wasdel, /* converting a delayed alloc */ + int *logflagsp, /* inode logging flags */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_block_t *ablock; /* allocated (child) bt block */ + xfs_buf_t *abp; /* buffer for ablock */ + xfs_alloc_arg_t args; /* allocation arguments */ + xfs_bmbt_rec_t *arp; /* child record pointer */ + xfs_bmbt_block_t *block; /* btree root block */ + xfs_btree_cur_t *cur; /* bmap btree cursor */ + xfs_bmbt_rec_t *ep; /* extent list pointer */ + int error; /* error return value */ + xfs_extnum_t i; /* extent list index */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_key_t *kp; /* root block key pointer */ + xfs_mount_t *mp; /* mount structure */ + xfs_extnum_t nextents; /* extent list size */ + xfs_bmbt_ptr_t *pp; /* root block address pointer */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS); + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + /* + * Make space in the inode incore. + */ + xfs_iroot_realloc(ip, 1, whichfork); + ifp->if_flags |= XFS_IFBROOT; + /* + * Fill in the root. + */ + block = ifp->if_broot; + INT_SET(block->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC); + INT_SET(block->bb_level, ARCH_CONVERT, 1); + INT_SET(block->bb_numrecs, ARCH_CONVERT, 1); + INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLDFSBNO); + INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLDFSBNO); + /* + * Need a cursor. Can't allocate until bb_level is filled in. + */ + mp = ip->i_mount; + cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip, + whichfork); + cur->bc_private.b.firstblock = *firstblock; + cur->bc_private.b.flist = flist; + cur->bc_private.b.flags = wasdel ? XFS_BTCUR_BPRV_WASDEL : 0; + /* + * Convert to a btree with two levels, one record in root. + */ + XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_BTREE); + args.tp = tp; + args.mp = mp; + if (*firstblock == NULLFSBLOCK) { + args.type = XFS_ALLOCTYPE_START_BNO; + args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino); + } else if (flist->xbf_low) { + args.type = XFS_ALLOCTYPE_START_BNO; + args.fsbno = *firstblock; + } else { + args.type = XFS_ALLOCTYPE_NEAR_BNO; + args.fsbno = *firstblock; + } + args.minlen = args.maxlen = args.prod = 1; + args.total = args.minleft = args.alignment = args.mod = args.isfl = + args.minalignslop = 0; + args.wasdel = wasdel; + *logflagsp = 0; + if ((error = xfs_alloc_vextent(&args))) { + xfs_iroot_realloc(ip, -1, whichfork); + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; + } + /* + * Allocation can't fail, the space was reserved. + */ + ASSERT(args.fsbno != NULLFSBLOCK); + ASSERT(*firstblock == NULLFSBLOCK || + args.agno == XFS_FSB_TO_AGNO(mp, *firstblock) || + (flist->xbf_low && + args.agno > XFS_FSB_TO_AGNO(mp, *firstblock))); + *firstblock = cur->bc_private.b.firstblock = args.fsbno; + cur->bc_private.b.allocated++; + ip->i_d.di_nblocks++; + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L); + abp = xfs_btree_get_bufl(mp, tp, args.fsbno, 0); + /* + * Fill in the child block. + */ + ablock = XFS_BUF_TO_BMBT_BLOCK(abp); + INT_SET(ablock->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC); + INT_ZERO(ablock->bb_level, ARCH_CONVERT); + INT_ZERO(ablock->bb_numrecs, ARCH_CONVERT); + INT_SET(ablock->bb_leftsib, ARCH_CONVERT, NULLDFSBNO); + INT_SET(ablock->bb_rightsib, ARCH_CONVERT, NULLDFSBNO); + arp = XFS_BMAP_REC_IADDR(ablock, 1, cur); + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + for (ep = ifp->if_u1.if_extents, i = 0; i < nextents; i++, ep++) { + if (!ISNULLSTARTBLOCK(xfs_bmbt_get_startblock(ep))) { + *arp++ = *ep; + INT_MOD(ablock->bb_numrecs, ARCH_CONVERT, +1); + } + } + ASSERT(INT_GET(ablock->bb_numrecs, ARCH_CONVERT) == XFS_IFORK_NEXTENTS(ip, whichfork)); + /* + * Fill in the root key and pointer. + */ + kp = XFS_BMAP_KEY_IADDR(block, 1, cur); + arp = XFS_BMAP_REC_IADDR(ablock, 1, cur); + INT_SET(kp->br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(arp)); + pp = XFS_BMAP_PTR_IADDR(block, 1, cur); + INT_SET(*pp, ARCH_CONVERT, args.fsbno); + /* + * Do all this logging at the end so that + * the root is at the right level. + */ + xfs_bmbt_log_block(cur, abp, XFS_BB_ALL_BITS); + xfs_bmbt_log_recs(cur, abp, 1, INT_GET(ablock->bb_numrecs, ARCH_CONVERT)); + ASSERT(*curp == NULL); + *curp = cur; + *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FBROOT(whichfork); + return 0; +} + +/* + * Insert new item(s) in the extent list for inode "ip". + * Count new items are inserted at offset idx. + */ +STATIC void +xfs_bmap_insert_exlist( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* starting index of new items */ + xfs_extnum_t count, /* number of inserted items */ + xfs_bmbt_irec_t *new, /* items to insert */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* extent list base */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t nextents; /* extent list size */ + xfs_extnum_t to; /* extent list index */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_flags & XFS_IFEXTENTS); + xfs_iext_realloc(ip, count, whichfork); + base = ifp->if_u1.if_extents; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + ovbcopy(&base[idx], &base[idx + count], + (nextents - (idx + count)) * sizeof(*base)); + for (to = idx; to < idx + count; to++, new++) + xfs_bmbt_set_all(&base[to], new); +} + +/* + * Convert a local file to an extents file. + * This code is out of bounds for data forks of regular files, + * since the file data needs to get logged so things will stay consistent. + * (The bmap-level manipulations are ok, though). + */ +STATIC int /* error */ +xfs_bmap_local_to_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first block allocated in xaction */ + xfs_extlen_t total, /* total blocks needed by transaction */ + int *logflagsp, /* inode logging flags */ + int whichfork) /* data or attr fork */ +{ + int error; /* error return value */ + int flags; /* logging flags returned */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_local_to_extents"; +#endif + xfs_ifork_t *ifp; /* inode fork pointer */ + + /* + * We don't want to deal with the case of keeping inode data inline yet. + * So sending the data fork of a regular inode is illegal. + */ + ASSERT(!((ip->i_d.di_mode & IFMT) == IFREG && + whichfork == XFS_DATA_FORK)); + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); + flags = 0; + error = 0; + if (ifp->if_bytes) { + xfs_alloc_arg_t args; /* allocation arguments */ + xfs_buf_t *bp; /* buffer for extent list block */ + xfs_bmbt_rec_t *ep; /* extent list pointer */ + + args.tp = tp; + args.mp = ip->i_mount; + ASSERT(ifp->if_flags & XFS_IFINLINE); + /* + * Allocate a block. We know we need only one, since the + * file currently fits in an inode. + */ + if (*firstblock == NULLFSBLOCK) { + args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino); + args.type = XFS_ALLOCTYPE_START_BNO; + } else { + args.fsbno = *firstblock; + args.type = XFS_ALLOCTYPE_NEAR_BNO; + } + args.total = total; + args.mod = args.minleft = args.alignment = args.wasdel = + args.isfl = args.minalignslop = 0; + args.minlen = args.maxlen = args.prod = 1; + if ((error = xfs_alloc_vextent(&args))) + goto done; + /* + * Can't fail, the space was reserved. + */ + ASSERT(args.fsbno != NULLFSBLOCK); + ASSERT(args.len == 1); + *firstblock = args.fsbno; + bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0); + bcopy(ifp->if_u1.if_data, (char *)XFS_BUF_PTR(bp), + ifp->if_bytes); + xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1); + xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); + xfs_iext_realloc(ip, 1, whichfork); + ep = ifp->if_u1.if_extents; + xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM); + xfs_bmap_trace_post_update(fname, "new", ip, 0, whichfork); + XFS_IFORK_NEXT_SET(ip, whichfork, 1); + ip->i_d.di_nblocks = 1; + if (XFS_IS_QUOTA_ON(args.mp) && + ip->i_ino != args.mp->m_sb.sb_uquotino && + ip->i_ino != args.mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, + 1L); + flags |= XFS_ILOG_FEXT(whichfork); + } else + ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0); + ifp->if_flags &= ~XFS_IFINLINE; + ifp->if_flags |= XFS_IFEXTENTS; + XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); + flags |= XFS_ILOG_CORE; +done: + *logflagsp = flags; + return error; +} + +xfs_bmbt_rec_t * /* pointer to found extent entry */ +xfs_bmap_do_search_extents( + xfs_bmbt_rec_t *base, /* base of extent list */ + xfs_extnum_t lastx, /* last extent index used */ + xfs_extnum_t nextents, /* extent list size */ + xfs_fileoff_t bno, /* block number searched for */ + int *eofp, /* out: end of file found */ + xfs_extnum_t *lastxp, /* out: last extent index */ + xfs_bmbt_irec_t *gotp, /* out: extent entry found */ + xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */ +{ + xfs_bmbt_rec_t *ep; /* extent list entry pointer */ + xfs_bmbt_irec_t got; /* extent list entry, decoded */ + int high; /* high index of binary search */ + int low; /* low index of binary search */ + + if (lastx != NULLEXTNUM && lastx < nextents) + ep = base + lastx; + else + ep = NULL; + prevp->br_startoff = NULLFILEOFF; + if (ep && bno >= (got.br_startoff = xfs_bmbt_get_startoff(ep)) && + bno < got.br_startoff + + (got.br_blockcount = xfs_bmbt_get_blockcount(ep))) + *eofp = 0; + else if (ep && lastx < nextents - 1 && + bno >= (got.br_startoff = xfs_bmbt_get_startoff(ep + 1)) && + bno < got.br_startoff + + (got.br_blockcount = xfs_bmbt_get_blockcount(ep + 1))) { + lastx++; + ep++; + *eofp = 0; + } else if (nextents == 0) + *eofp = 1; + else if (bno == 0 && + (got.br_startoff = xfs_bmbt_get_startoff(base)) == 0) { + ep = base; + lastx = 0; + got.br_blockcount = xfs_bmbt_get_blockcount(ep); + *eofp = 0; + } else { + /* binary search the extents array */ + low = 0; + high = nextents - 1; + while (low <= high) { + XFS_STATS_INC(xfsstats.xs_cmp_exlist); + lastx = (low + high) >> 1; + ep = base + lastx; + got.br_startoff = xfs_bmbt_get_startoff(ep); + got.br_blockcount = xfs_bmbt_get_blockcount(ep); + if (bno < got.br_startoff) + high = lastx - 1; + else if (bno >= got.br_startoff + got.br_blockcount) + low = lastx + 1; + else { + got.br_startblock = xfs_bmbt_get_startblock(ep); + got.br_state = xfs_bmbt_get_state(ep); + *eofp = 0; + *lastxp = lastx; + *gotp = got; + return ep; + } + } + if (bno >= got.br_startoff + got.br_blockcount) { + lastx++; + if (lastx == nextents) { + *eofp = 1; + got.br_startblock = xfs_bmbt_get_startblock(ep); + got.br_state = xfs_bmbt_get_state(ep); + *prevp = got; + ep = NULL; + } else { + *eofp = 0; + xfs_bmbt_get_all(ep, prevp); + ep++; + got.br_startoff = xfs_bmbt_get_startoff(ep); + got.br_blockcount = xfs_bmbt_get_blockcount(ep); + } + } else { + *eofp = 0; + if (ep > base) + xfs_bmbt_get_all(ep - 1, prevp); + } + } + if (ep) { + got.br_startblock = xfs_bmbt_get_startblock(ep); + got.br_state = xfs_bmbt_get_state(ep); + } + *lastxp = lastx; + *gotp = got; + return ep; +} + +/* + * Search the extents list for the inode, for the extent containing bno. + * If bno lies in a hole, point to the next entry. If bno lies past eof, + * *eofp will be set, and *prevp will contain the last entry (null if none). + * Else, *lastxp will be set to the index of the found + * entry; *gotp will contain the entry. + */ +STATIC xfs_bmbt_rec_t * /* pointer to found extent entry */ +xfs_bmap_search_extents( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fileoff_t bno, /* block number searched for */ + int whichfork, /* data or attr fork */ + int *eofp, /* out: end of file found */ + xfs_extnum_t *lastxp, /* out: last extent index */ + xfs_bmbt_irec_t *gotp, /* out: extent entry found */ + xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */ +{ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_rec_t *base; /* base of extent list */ + xfs_extnum_t lastx; /* last extent index used */ + xfs_extnum_t nextents; /* extent list size */ + + XFS_STATS_INC(xfsstats.xs_look_exlist); + ifp = XFS_IFORK_PTR(ip, whichfork); + lastx = ifp->if_lastex; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + base = &ifp->if_u1.if_extents[0]; + + return xfs_bmap_do_search_extents(base, lastx, nextents, bno, eofp, + lastxp, gotp, prevp); +} + +/* + * Compute the worst-case number of indirect blocks that will be used + * for ip's delayed extent of length "len". + */ +STATIC xfs_filblks_t +xfs_bmap_worst_indlen( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_filblks_t len) /* delayed extent length */ +{ + int level; /* btree level number */ + int maxrecs; /* maximum record count at this level */ + xfs_mount_t *mp; /* mount structure */ + xfs_filblks_t rval; /* return value */ + + mp = ip->i_mount; + maxrecs = mp->m_bmap_dmxr[0]; + for (level = 0, rval = 0; + level < XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK); + level++) { + len += maxrecs - 1; + do_div(len, maxrecs); + rval += len; + if (len == 1) + return rval + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - + level - 1; + if (level == 0) + maxrecs = mp->m_bmap_dmxr[1]; + } + return rval; +} + +/* + * Add the extent to the list of extents to be free at transaction end. + * The list is maintained sorted (by block number). + */ +/* ARGSUSED */ +void +xfs_bmap_add_free( + xfs_fsblock_t bno, /* fs block number of extent */ + xfs_filblks_t len, /* length of extent */ + xfs_bmap_free_t *flist, /* list of extents */ + xfs_mount_t *mp) /* mount point structure */ +{ + xfs_bmap_free_item_t *cur; /* current (next) element */ + xfs_bmap_free_item_t *new; /* new element */ + xfs_bmap_free_item_t *prev; /* previous element */ +#ifdef DEBUG + xfs_agnumber_t agno; + xfs_agblock_t agbno; + + ASSERT(bno != NULLFSBLOCK); + ASSERT(len > 0); + ASSERT(len <= MAXEXTLEN); + ASSERT(!ISNULLSTARTBLOCK(bno)); + agno = XFS_FSB_TO_AGNO(mp, bno); + agbno = XFS_FSB_TO_AGBNO(mp, bno); + ASSERT(agno < mp->m_sb.sb_agcount); + ASSERT(agbno < mp->m_sb.sb_agblocks); + ASSERT(len < mp->m_sb.sb_agblocks); + ASSERT(agbno + len <= mp->m_sb.sb_agblocks); +#endif + ASSERT(xfs_bmap_free_item_zone != NULL); + new = kmem_zone_alloc(xfs_bmap_free_item_zone, KM_SLEEP); + new->xbfi_startblock = bno; + new->xbfi_blockcount = (xfs_extlen_t)len; + for (prev = NULL, cur = flist->xbf_first; + cur != NULL; + prev = cur, cur = cur->xbfi_next) { + if (cur->xbfi_startblock >= bno) + break; + } + if (prev) + prev->xbfi_next = new; + else + flist->xbf_first = new; + new->xbfi_next = cur; + flist->xbf_count++; +} + +/* + * Compute and fill in the value of the maximum depth of a bmap btree + * in this filesystem. Done once, during mount. + */ +void +xfs_bmap_compute_maxlevels( + xfs_mount_t *mp, /* file system mount structure */ + int whichfork) /* data or attr fork */ +{ + int level; /* btree level */ + uint maxblocks; /* max blocks at this level */ + uint maxleafents; /* max leaf entries possible */ + int maxrootrecs; /* max records in root block */ + int minleafrecs; /* min records in leaf block */ + int minnoderecs; /* min records in node block */ + int sz; /* root block size */ + + /* + * The maximum number of extents in a file, hence the maximum + * number of leaf entries, is controlled by the type of di_nextents + * (a signed 32-bit number, xfs_extnum_t), or by di_anextents + * (a signed 16-bit number, xfs_aextnum_t). + */ + maxleafents = (whichfork == XFS_DATA_FORK) ? MAXEXTNUM : MAXAEXTNUM; + minleafrecs = mp->m_bmap_dmnr[0]; + minnoderecs = mp->m_bmap_dmnr[1]; + sz = (whichfork == XFS_DATA_FORK) ? + mp->m_attroffset : + mp->m_sb.sb_inodesize - mp->m_attroffset; + maxrootrecs = (int)XFS_BTREE_BLOCK_MAXRECS(sz, xfs_bmdr, 0); + maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; + for (level = 1; maxblocks > 1; level++) { + if (maxblocks <= maxrootrecs) + maxblocks = 1; + else + maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; + } + mp->m_bm_maxlevels[whichfork] = level; +} + +/* + * Returns the file-relative block number of the first unused block(s) + * in the file with at least "len" logically contiguous blocks free. + * This is the lowest-address hole if the file has holes, else the first block + * past the end of file. + * Return 0 if the file is currently local (in-inode). + */ +int /* error */ +xfs_bmap_first_unused( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + xfs_extlen_t len, /* size of hole to find */ + xfs_fileoff_t *first_unused, /* unused block */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* base of extent array */ + xfs_bmbt_rec_t *ep; /* pointer to an extent entry */ + int error; /* error return value */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_fileoff_t lastaddr; /* last block number seen */ + xfs_fileoff_t lowest; /* lowest useful block */ + xfs_fileoff_t max; /* starting useful block */ + xfs_fileoff_t off; /* offset for this block */ + xfs_extnum_t nextents; /* number of extent entries */ + + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE || + XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS || + XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + *first_unused = 0; + return 0; + } + ifp = XFS_IFORK_PTR(ip, whichfork); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + lowest = *first_unused; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + base = &ifp->if_u1.if_extents[0]; + for (lastaddr = 0, max = lowest, ep = base; + ep < &base[nextents]; + ep++) { + off = xfs_bmbt_get_startoff(ep); + /* + * See if the hole before this extent will work. + */ + if (off >= lowest + len && off - max >= len) { + *first_unused = max; + return 0; + } + lastaddr = off + xfs_bmbt_get_blockcount(ep); + max = XFS_FILEOFF_MAX(lastaddr, lowest); + } + *first_unused = max; + return 0; +} + +/* + * Returns the file-relative block number of the last block + 1 before + * last_block (input value) in the file. + * This is not based on i_size, it is based on the extent list. + * Returns 0 for local files, as they do not have an extent list. + */ +int /* error */ +xfs_bmap_last_before( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + xfs_fileoff_t *last_block, /* last block */ + int whichfork) /* data or attr fork */ +{ + xfs_fileoff_t bno; /* input file offset */ + int eof; /* hit end of file */ + xfs_bmbt_rec_t *ep; /* pointer to last extent */ + int error; /* error return value */ + xfs_bmbt_irec_t got; /* current extent value */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t lastx; /* last extent used */ + xfs_bmbt_irec_t prev; /* previous extent value */ + + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) + return XFS_ERROR(EIO); + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + *last_block = 0; + return 0; + } + ifp = XFS_IFORK_PTR(ip, whichfork); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + bno = *last_block - 1; + ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, + &prev); + if (eof || xfs_bmbt_get_startoff(ep) > bno) { + if (prev.br_startoff == NULLFILEOFF) + *last_block = 0; + else + *last_block = prev.br_startoff + prev.br_blockcount; + } + /* + * Otherwise *last_block is already the right answer. + */ + return 0; +} + +/* + * Returns the file-relative block number of the first block past eof in + * the file. This is not based on i_size, it is based on the extent list. + * Returns 0 for local files, as they do not have an extent list. + */ +int /* error */ +xfs_bmap_last_offset( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + xfs_fileoff_t *last_block, /* last block */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* base of extent array */ + xfs_bmbt_rec_t *ep; /* pointer to last extent */ + int error; /* error return value */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t nextents; /* number of extent entries */ + + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) + return XFS_ERROR(EIO); + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + *last_block = 0; + return 0; + } + ifp = XFS_IFORK_PTR(ip, whichfork); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + if (!nextents) { + *last_block = 0; + return 0; + } + base = &ifp->if_u1.if_extents[0]; + ASSERT(base != NULL); + ep = &base[nextents - 1]; + *last_block = xfs_bmbt_get_startoff(ep) + xfs_bmbt_get_blockcount(ep); + return 0; +} + +/* + * Returns whether the selected fork of the inode has exactly one + * block or not. For the data fork we check this matches di_size, + * implying the file's range is 0..bsize-1. + */ +int /* 1=>1 block, 0=>otherwise */ +xfs_bmap_one_block( + xfs_inode_t *ip, /* incore inode */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *ep; /* ptr to fork's extent */ + xfs_ifork_t *ifp; /* inode fork pointer */ + int rval; /* return value */ + xfs_bmbt_irec_t s; /* internal version of extent */ + +#ifndef DEBUG + if (whichfork == XFS_DATA_FORK) + return ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize; +#endif /* !DEBUG */ + if (XFS_IFORK_NEXTENTS(ip, whichfork) != 1) + return 0; + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) + return 0; + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_flags & XFS_IFEXTENTS); + ep = ifp->if_u1.if_extents; + xfs_bmbt_get_all(ep, &s); + rval = s.br_startoff == 0 && s.br_blockcount == 1; + if (rval && whichfork == XFS_DATA_FORK) + ASSERT(ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize); + return rval; +} + +/* + * Read in the extents to if_extents. + * All inode fields are set up by caller, we just traverse the btree + * and copy the records in. If the file system cannot contain unwritten + * extents, the records are checked for no "state" flags. + */ +int /* error */ +xfs_bmap_read_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_block_t *block; /* current btree block */ + xfs_fsblock_t bno; /* block # of "block" */ + xfs_buf_t *bp; /* buffer for "block" */ + int error; /* error return value */ + xfs_exntfmt_t exntf; /* XFS_EXTFMT_NOSTATE, if checking */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_read_extents"; +#endif + xfs_extnum_t i; /* index into the extents list */ + xfs_ifork_t *ifp; /* fork structure */ + int level; /* btree level, for checking */ + xfs_mount_t *mp; /* file system mount structure */ + xfs_bmbt_ptr_t *pp; /* pointer to block address */ + /* REFERENCED */ + xfs_extnum_t room; /* number of entries there's room for */ + xfs_bmbt_rec_t *trp; /* target record pointer */ + + bno = NULLFSBLOCK; + mp = ip->i_mount; + ifp = XFS_IFORK_PTR(ip, whichfork); + exntf = (whichfork != XFS_DATA_FORK) ? XFS_EXTFMT_NOSTATE : + XFS_EXTFMT_INODE(ip); + block = ifp->if_broot; + /* + * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out. + */ + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + level = INT_GET(block->bb_level, ARCH_CONVERT); + pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes); + ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO); + ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount); + ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks); + bno = INT_GET(*pp, ARCH_CONVERT); + /* + * Go down the tree until leaf level is reached, following the first + * pointer (leftmost) at each level. + */ + while (level-- > 0) { + if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, + XFS_BMAP_BTREE_REF))) + return error; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + XFS_WANT_CORRUPTED_GOTO( + XFS_BMAP_SANITY_CHECK(mp, block, level), + error0); + if (level == 0) + break; + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, + 1, mp->m_bmap_dmxr[1]); + XFS_WANT_CORRUPTED_GOTO(XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)), error0); + bno = INT_GET(*pp, ARCH_CONVERT); + xfs_trans_brelse(tp, bp); + } + /* + * Here with bp and block set to the leftmost leaf node in the tree. + */ + room = ifp->if_bytes / (uint)sizeof(*trp); + trp = ifp->if_u1.if_extents; + i = 0; + /* + * Loop over all leaf nodes. Copy information to the extent list. + */ + for (;;) { + xfs_bmbt_rec_t *frp; + xfs_fsblock_t nextbno; + xfs_extnum_t num_recs; + + + num_recs = INT_GET(block->bb_numrecs, ARCH_CONVERT); + if (i + num_recs > room) { + ASSERT(i + num_recs <= room); + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt dinode %Lu, (btree extents). Unmount and run xfs_repair.", + ip->i_ino); + goto error0; + } + XFS_WANT_CORRUPTED_GOTO( + XFS_BMAP_SANITY_CHECK(mp, block, 0), + error0); + /* + * Read-ahead the next leaf block, if any. + */ + nextbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + if (nextbno != NULLFSBLOCK) + xfs_btree_reada_bufl(mp, nextbno, 1); + /* + * Copy records into the extent list. + */ + frp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, + block, 1, mp->m_bmap_dmxr[0]); + bcopy(frp, trp, num_recs * sizeof(*frp)); + if (exntf == XFS_EXTFMT_NOSTATE) { + /* + * Check all attribute bmap btree records and + * any "older" data bmap btree records for a + * set bit in the "extent flag" position. + */ + if (xfs_check_nostate_extents(trp, num_recs)) { + goto error0; + } + } + trp += num_recs; + i += num_recs; + xfs_trans_brelse(tp, bp); + bno = nextbno; + /* + * If we've reached the end, stop. + */ + if (bno == NULLFSBLOCK) + break; + if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, + XFS_BMAP_BTREE_REF))) + return error; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + } + ASSERT(i == ifp->if_bytes / (uint)sizeof(*trp)); + ASSERT(i == XFS_IFORK_NEXTENTS(ip, whichfork)); + xfs_bmap_trace_exlist(fname, ip, i, whichfork); + return 0; +error0: + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EFSCORRUPTED); +} + +/* + * Map file blocks to filesystem blocks. + * File range is given by the bno/len pair. + * Adds blocks to file if a write ("flags & XFS_BMAPI_WRITE" set) + * into a hole or past eof. + * Only allocates blocks from a single allocation group, + * to avoid locking problems. + * The returned value in "firstblock" from the first call in a transaction + * must be remembered and presented to subsequent calls in "firstblock". + * An upper bound for the number of blocks to be allocated is supplied to + * the first call in "total"; if no allocation group has that many free + * blocks then the call will fail (return NULLFSBLOCK in "firstblock"). + */ +int /* error */ +xfs_bmapi( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + xfs_fileoff_t bno, /* starting file offs. mapped */ + xfs_filblks_t len, /* length to map in file */ + int flags, /* XFS_BMAPI_... */ + xfs_fsblock_t *firstblock, /* first allocated block + controls a.g. for allocs */ + xfs_extlen_t total, /* total blocks needed */ + xfs_bmbt_irec_t *mval, /* output: map values */ + int *nmap, /* i/o: mval size/count */ + xfs_bmap_free_t *flist) /* i/o: list extents to free */ +{ + xfs_fsblock_t abno; /* allocated block number */ + xfs_extlen_t alen; /* allocated extent length */ + xfs_fileoff_t aoff; /* allocated file offset */ + xfs_bmalloca_t bma; /* args for xfs_bmap_alloc */ + int contig; /* allocation must be one extent */ + xfs_btree_cur_t *cur; /* bmap btree cursor */ + char delay; /* this request is for delayed alloc */ + xfs_fileoff_t end; /* end of mapped file region */ + int eof; /* we've hit the end of extent list */ + xfs_bmbt_rec_t *ep; /* extent list entry pointer */ + int error; /* error return */ + char exact; /* don't do all of wasdelayed extent */ + xfs_bmbt_irec_t got; /* current extent list record */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extlen_t indlen; /* indirect blocks length */ + char inhole; /* current location is hole in file */ + xfs_extnum_t lastx; /* last useful extent number */ + int logflags; /* flags for transaction logging */ + xfs_extlen_t minleft; /* min blocks left after allocation */ + xfs_extlen_t minlen; /* min allocation size */ + xfs_mount_t *mp; /* xfs mount structure */ + int n; /* current extent index */ + int nallocs; /* number of extents alloc\'d */ + xfs_extnum_t nextents; /* number of extents in file */ + xfs_fileoff_t obno; /* old block number (offset) */ + xfs_bmbt_irec_t prev; /* previous extent list record */ + int stateless; /* ignore state flag set */ + int tmp_logflags; /* temp flags holder */ + char trim; /* output trimmed to match range */ + char userdata; /* allocating non-metadata */ + char wasdelay; /* old extent was delayed */ + int whichfork; /* data or attr fork */ + char wr; /* this is a write request */ + int rsvd; /* OK to allocate reserved blocks */ +#ifdef DEBUG + xfs_fileoff_t orig_bno; /* original block number value */ + int orig_flags; /* original flags arg value */ + xfs_filblks_t orig_len; /* original value of len arg */ + xfs_bmbt_irec_t *orig_mval; /* original value of mval */ + int orig_nmap; /* original value of *nmap */ + + orig_bno = bno; + orig_len = len; + orig_flags = flags; + orig_mval = mval; + orig_nmap = *nmap; +#endif + ASSERT(*nmap >= 1); + ASSERT(*nmap <= XFS_BMAP_MAX_NMAP || !(flags & XFS_BMAPI_WRITE)); + whichfork = (flags & XFS_BMAPI_ATTRFORK) ? + XFS_ATTR_FORK : XFS_DATA_FORK; + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) + return XFS_ERROR(EFSCORRUPTED); + mp = ip->i_mount; + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + if ((wr = (flags & XFS_BMAPI_WRITE)) != 0) + XFS_STATS_INC(xfsstats.xs_blk_mapw); + else + XFS_STATS_INC(xfsstats.xs_blk_mapr); + delay = (flags & XFS_BMAPI_DELAY) != 0; + trim = (flags & XFS_BMAPI_ENTIRE) == 0; + userdata = (flags & XFS_BMAPI_METADATA) == 0; + exact = (flags & XFS_BMAPI_EXACT) != 0; + rsvd = (flags & XFS_BMAPI_RSVBLOCKS) != 0; + contig = (flags & XFS_BMAPI_CONTIG) != 0; + /* + * stateless is used to combine extents which + * differ only due to the state of the extents. + * This technique is used from xfs_getbmap() + * when the caller does not wish to see the + * separation (which is the default). + * + * This technique is also used when writing a + * buffer which has been partially written, + * (usually by being flushed during a chunkread), + * to ensure one write takes place. This also + * prevents a change in the xfs inode extents at + * this time, intentionally. This change occurs + * on completion of the write operation, in + * xfs_strat_comp(), where the xfs_bmapi() call + * is transactioned, and the extents combined. + */ + stateless = (flags & XFS_BMAPI_IGSTATE) != 0; + if (stateless && wr) /* if writing unwritten space, no */ + wr = 0; /* allocations are allowed */ + ASSERT(wr || !delay); + logflags = 0; + nallocs = 0; + cur = NULL; + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + ASSERT(wr && tp); + if ((error = xfs_bmap_local_to_extents(tp, ip, firstblock, total, + &logflags, whichfork))) + goto error0; + } + if (wr && *firstblock == NULLFSBLOCK) { + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE) + minleft = INT_GET(ifp->if_broot->bb_level, ARCH_CONVERT) + 1; + else + minleft = 1; + } else + minleft = 0; + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + goto error0; + ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, + &prev); + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + n = 0; + end = bno + len; + obno = bno; + bma.ip = NULL; + while (bno < end && n < *nmap) { + /* + * Reading past eof, act as though there's a hole + * up to end. + */ + if (eof && !wr) + got.br_startoff = end; + inhole = eof || got.br_startoff > bno; + wasdelay = wr && !inhole && !delay && + ISNULLSTARTBLOCK(got.br_startblock); + /* + * First, deal with the hole before the allocated space + * that we found, if any. + */ + if (wr && (inhole || wasdelay)) { + /* + * For the wasdelay case, we could also just + * allocate the stuff asked for in this bmap call + * but that wouldn't be as good. + */ + if (wasdelay && !exact) { + alen = (xfs_extlen_t)got.br_blockcount; + aoff = got.br_startoff; + if (lastx != NULLEXTNUM && lastx) { + ep = &ifp->if_u1.if_extents[lastx - 1]; + xfs_bmbt_get_all(ep, &prev); + } + } else if (wasdelay) { + alen = (xfs_extlen_t) + XFS_FILBLKS_MIN(len, + (got.br_startoff + + got.br_blockcount) - bno); + aoff = bno; + } else { + alen = (xfs_extlen_t) + XFS_FILBLKS_MIN(len, MAXEXTLEN); + if (!eof) + alen = (xfs_extlen_t) + XFS_FILBLKS_MIN(alen, + got.br_startoff - bno); + aoff = bno; + } + minlen = contig ? alen : 1; + if (delay) { + indlen = (xfs_extlen_t) + xfs_bmap_worst_indlen(ip, alen); + ASSERT(indlen > 0); + /* + * Make a transaction-less quota reservation for + * delayed allocation blocks. This number gets + * adjusted later. + * We return EDQUOT if we haven't allocated + * blks already inside this loop; + */ + if (XFS_IS_QUOTA_ON(ip->i_mount) && + xfs_trans_reserve_blkquota(NULL, ip, + (long)alen)) { + if (n == 0) { + *nmap = 0; + ASSERT(cur == NULL); + return XFS_ERROR(EDQUOT); + } + break; + } + if (xfs_mod_incore_sb(ip->i_mount, + XFS_SBS_FDBLOCKS, + -(alen + indlen), rsvd)) { + if (XFS_IS_QUOTA_ON(ip->i_mount)) + xfs_trans_unreserve_blkquota( + NULL, ip, (long)alen); + break; + } + ip->i_delayed_blks += alen; + abno = NULLSTARTBLOCK(indlen); + } else { + /* + * If first time, allocate and fill in + * once-only bma fields. + */ + if (bma.ip == NULL) { + bma.tp = tp; + bma.ip = ip; + bma.prevp = &prev; + bma.gotp = &got; + bma.total = total; + bma.userdata = userdata; + } + /* + * Fill in changeable bma fields. + */ + bma.eof = eof; + bma.firstblock = *firstblock; + bma.alen = alen; + bma.off = aoff; + bma.wasdel = wasdelay; + bma.minlen = minlen; + bma.low = flist->xbf_low; + bma.minleft = minleft; + /* + * Only want to do the alignment at the + * eof if it is userdata and allocation length + * is larger than a stripe unit. + */ + if (mp->m_dalign && alen >= mp->m_dalign && + userdata && whichfork == XFS_DATA_FORK) { + if ((error = xfs_bmap_isaeof(ip, aoff, + whichfork, &bma.aeof))) + goto error0; + } else + bma.aeof = 0; + /* + * Call allocator. + */ + if ((error = xfs_bmap_alloc(&bma))) + goto error0; + /* + * Copy out result fields. + */ + abno = bma.rval; + if ((flist->xbf_low = bma.low)) + minleft = 0; + alen = bma.alen; + aoff = bma.off; + ASSERT(*firstblock == NULLFSBLOCK || + XFS_FSB_TO_AGNO(ip->i_mount, + *firstblock) == + XFS_FSB_TO_AGNO(ip->i_mount, + bma.firstblock) || + (flist->xbf_low && + XFS_FSB_TO_AGNO(ip->i_mount, + *firstblock) < + XFS_FSB_TO_AGNO(ip->i_mount, + bma.firstblock))); + *firstblock = bma.firstblock; + if (cur) + cur->bc_private.b.firstblock = + *firstblock; + if (abno == NULLFSBLOCK) + break; + if ((ifp->if_flags & XFS_IFBROOT) && !cur) { + cur = xfs_btree_init_cursor(ip->i_mount, + tp, NULL, 0, XFS_BTNUM_BMAP, + ip, whichfork); + cur->bc_private.b.firstblock = + *firstblock; + cur->bc_private.b.flist = flist; + } + /* + * Bump the number of extents we've allocated + * in this call. + */ + nallocs++; + } + if (cur) + cur->bc_private.b.flags = + wasdelay ? XFS_BTCUR_BPRV_WASDEL : 0; + got.br_startoff = aoff; + got.br_startblock = abno; + got.br_blockcount = alen; + got.br_state = XFS_EXT_NORM; /* assume normal */ + /* + * Determine state of extent, and the filesystem. + * A wasdelay extent has been initialized, so + * shouldn't be flagged as unwritten. + */ + if (wr && XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) { + if (!wasdelay && (flags & XFS_BMAPI_PREALLOC)) + got.br_state = XFS_EXT_UNWRITTEN; + } + error = xfs_bmap_add_extent(ip, lastx, &cur, &got, + firstblock, flist, &tmp_logflags, whichfork, + rsvd); + logflags |= tmp_logflags; + if (error) + goto error0; + lastx = ifp->if_lastex; + ep = &ifp->if_u1.if_extents[lastx]; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + xfs_bmbt_get_all(ep, &got); + ASSERT(got.br_startoff <= aoff); + ASSERT(got.br_startoff + got.br_blockcount >= + aoff + alen); +#ifdef DEBUG + if (delay) { + ASSERT(ISNULLSTARTBLOCK(got.br_startblock)); + ASSERT(STARTBLOCKVAL(got.br_startblock) > 0); + } + ASSERT(got.br_state == XFS_EXT_NORM || + got.br_state == XFS_EXT_UNWRITTEN); +#endif + /* + * Fall down into the found allocated space case. + */ + } else if (inhole) { + /* + * Reading in a hole. + */ + mval->br_startoff = bno; + mval->br_startblock = HOLESTARTBLOCK; + mval->br_blockcount = + XFS_FILBLKS_MIN(len, got.br_startoff - bno); + mval->br_state = XFS_EXT_NORM; + bno += mval->br_blockcount; + len -= mval->br_blockcount; + mval++; + n++; + continue; + } + /* + * Then deal with the allocated space we found. + */ + ASSERT(ep != NULL); + if (trim && (got.br_startoff + got.br_blockcount > obno)) { + if (obno > bno) + bno = obno; + ASSERT((bno >= obno) || (n == 0)); + ASSERT(bno < end); + mval->br_startoff = bno; + if (ISNULLSTARTBLOCK(got.br_startblock)) { + ASSERT(!wr || delay); + mval->br_startblock = DELAYSTARTBLOCK; + } else + mval->br_startblock = + got.br_startblock + + (bno - got.br_startoff); + /* + * Return the minimum of what we got and what we + * asked for for the length. We can use the len + * variable here because it is modified below + * and we could have been there before coming + * here if the first part of the allocation + * didn't overlap what was asked for. + */ + mval->br_blockcount = + XFS_FILBLKS_MIN(end - bno, got.br_blockcount - + (bno - got.br_startoff)); + mval->br_state = got.br_state; + ASSERT(mval->br_blockcount <= len); + } else { + *mval = got; + if (ISNULLSTARTBLOCK(mval->br_startblock)) { + ASSERT(!wr || delay); + mval->br_startblock = DELAYSTARTBLOCK; + } + } + + /* + * Check if writing previously allocated but + * unwritten extents. + */ + if (wr && mval->br_state == XFS_EXT_UNWRITTEN && + ((flags & (XFS_BMAPI_PREALLOC|XFS_BMAPI_DELAY)) == 0)) { + /* + * Modify (by adding) the state flag, if writing. + */ + ASSERT(mval->br_blockcount <= len); + if ((ifp->if_flags & XFS_IFBROOT) && !cur) { + cur = xfs_btree_init_cursor(ip->i_mount, + tp, NULL, 0, XFS_BTNUM_BMAP, + ip, whichfork); + cur->bc_private.b.firstblock = + *firstblock; + cur->bc_private.b.flist = flist; + } + mval->br_state = XFS_EXT_NORM; + error = xfs_bmap_add_extent(ip, lastx, &cur, mval, + firstblock, flist, &tmp_logflags, whichfork, + rsvd); + logflags |= tmp_logflags; + if (error) + goto error0; + lastx = ifp->if_lastex; + ep = &ifp->if_u1.if_extents[lastx]; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + xfs_bmbt_get_all(ep, &got); + /* + * We may have combined previously unwritten + * space with written space, so generate + * another request. + */ + if (mval->br_blockcount < len) + continue; + } + + ASSERT(!trim || + ((mval->br_startoff + mval->br_blockcount) <= end)); + ASSERT(!trim || (mval->br_blockcount <= len) || + (mval->br_startoff < obno)); + bno = mval->br_startoff + mval->br_blockcount; + len = end - bno; + if (n > 0 && mval->br_startoff == mval[-1].br_startoff) { + ASSERT(mval->br_startblock == mval[-1].br_startblock); + ASSERT(mval->br_blockcount > mval[-1].br_blockcount); + ASSERT(mval->br_state == mval[-1].br_state); + mval[-1].br_blockcount = mval->br_blockcount; + mval[-1].br_state = mval->br_state; + } else if (n > 0 && mval->br_startblock != DELAYSTARTBLOCK && + mval[-1].br_startblock != DELAYSTARTBLOCK && + mval[-1].br_startblock != HOLESTARTBLOCK && + mval->br_startblock == + mval[-1].br_startblock + mval[-1].br_blockcount && + (stateless || mval[-1].br_state == mval->br_state)) { + ASSERT(mval->br_startoff == + mval[-1].br_startoff + mval[-1].br_blockcount); + mval[-1].br_blockcount += mval->br_blockcount; + } else if (n > 0 && + mval->br_startblock == DELAYSTARTBLOCK && + mval[-1].br_startblock == DELAYSTARTBLOCK && + mval->br_startoff == + mval[-1].br_startoff + mval[-1].br_blockcount) { + mval[-1].br_blockcount += mval->br_blockcount; + mval[-1].br_state = mval->br_state; + } else if (!((n == 0) && + ((mval->br_startoff + mval->br_blockcount) <= + obno))) { + mval++; + n++; + } + /* + * If we're done, stop now. Stop when we've allocated + * XFS_BMAP_MAX_NMAP extents no matter what. Otherwise + * the transaction may get too big. + */ + if (bno >= end || n >= *nmap || nallocs >= *nmap) + break; + /* + * Else go on to the next record. + */ + ep++; + lastx++; + if (lastx >= nextents) { + eof = 1; + prev = got; + } else + xfs_bmbt_get_all(ep, &got); + } + ifp->if_lastex = lastx; + *nmap = n; + /* + * Transform from btree to extents, give it cur. + */ + if (tp && XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE && + XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max) { + ASSERT(wr && cur); + error = xfs_bmap_btree_to_extents(tp, ip, cur, + &tmp_logflags, whichfork, 0); + logflags |= tmp_logflags; + if (error) + goto error0; + } + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE || + XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max); + error = 0; + +error0: + /* + * Log everything. Do this after conversion, there's no point in + * logging the extent list if we've converted to btree format. + */ + if ((logflags & XFS_ILOG_FEXT(whichfork)) && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) + logflags &= ~XFS_ILOG_FEXT(whichfork); + else if ((logflags & XFS_ILOG_FBROOT(whichfork)) && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) + logflags &= ~XFS_ILOG_FBROOT(whichfork); + /* + * Log whatever the flags say, even if error. Otherwise we might miss + * detecting a case where the data is changed, there's an error, + * and it's not logged so we don't shutdown when we should. + */ + if (logflags) { + ASSERT(tp && wr); + xfs_trans_log_inode(tp, ip, logflags); + } + if (cur) { + if (!error) { + ASSERT(*firstblock == NULLFSBLOCK || + XFS_FSB_TO_AGNO(ip->i_mount, *firstblock) == + XFS_FSB_TO_AGNO(ip->i_mount, + cur->bc_private.b.firstblock) || + (flist->xbf_low && + XFS_FSB_TO_AGNO(ip->i_mount, *firstblock) < + XFS_FSB_TO_AGNO(ip->i_mount, + cur->bc_private.b.firstblock))); + *firstblock = cur->bc_private.b.firstblock; + } + xfs_btree_del_cursor(cur, + error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); + } + if (!error) + xfs_bmap_validate_ret(orig_bno, orig_len, orig_flags, orig_mval, + orig_nmap, *nmap); + return error; +} + +/* + * Map file blocks to filesystem blocks, simple version. + * One block (extent) only, read-only. + * For flags, only the XFS_BMAPI_ATTRFORK flag is examined. + * For the other flag values, the effect is as if XFS_BMAPI_METADATA + * was set and all the others were clear. + */ +int /* error */ +xfs_bmapi_single( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + int whichfork, /* data or attr fork */ + xfs_fsblock_t *fsb, /* output: mapped block */ + xfs_fileoff_t bno) /* starting file offs. mapped */ +{ + int eof; /* we've hit the end of extent list */ + int error; /* error return */ + xfs_bmbt_irec_t got; /* current extent list record */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t lastx; /* last useful extent number */ + xfs_bmbt_irec_t prev; /* previous extent list record */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) + return XFS_ERROR(EFSCORRUPTED); + if (XFS_FORCED_SHUTDOWN(ip->i_mount)) + return XFS_ERROR(EIO); + XFS_STATS_INC(xfsstats.xs_blk_mapr); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + (void)xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, + &prev); + /* + * Reading past eof, act as though there's a hole + * up to end. + */ + if (eof || got.br_startoff > bno) { + *fsb = NULLFSBLOCK; + return 0; + } + ASSERT(!ISNULLSTARTBLOCK(got.br_startblock)); + ASSERT(bno < got.br_startoff + got.br_blockcount); + *fsb = got.br_startblock + (bno - got.br_startoff); + ifp->if_lastex = lastx; + return 0; +} + +/* + * Unmap (remove) blocks from a file. + * If nexts is nonzero then the number of extents to remove is limited to + * that value. If not all extents in the block range can be removed then + * *done is set. + */ +int /* error */ +xfs_bunmapi( + xfs_trans_t *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t bno, /* starting offset to unmap */ + xfs_filblks_t len, /* length to unmap in file */ + int flags, /* misc flags */ + xfs_extnum_t nexts, /* number of extents max */ + xfs_fsblock_t *firstblock, /* first allocated block + controls a.g. for allocs */ + xfs_bmap_free_t *flist, /* i/o: list extents to free */ + int *done) /* set if not done yet */ +{ + int async; /* xactions can be async */ + xfs_btree_cur_t *cur; /* bmap btree cursor */ + xfs_bmbt_irec_t del; /* extent being deleted */ + int eof; /* is deleting at eof */ + xfs_bmbt_rec_t *ep; /* extent list entry pointer */ + int error; /* error return value */ + xfs_extnum_t extno; /* extent number in list */ + xfs_bmbt_irec_t got; /* current extent list entry */ + xfs_ifork_t *ifp; /* inode fork pointer */ + int isrt; /* freeing in rt area */ + xfs_extnum_t lastx; /* last extent index used */ + int logflags; /* transaction logging flags */ + xfs_extlen_t mod; /* rt extent offset */ + xfs_mount_t *mp; /* mount structure */ + xfs_extnum_t nextents; /* size of extent list */ + xfs_bmbt_irec_t prev; /* previous extent list entry */ + xfs_fileoff_t start; /* first file offset deleted */ + int tmp_logflags; /* partial logging flags */ + int wasdel; /* was a delayed alloc extent */ + int whichfork; /* data or attribute fork */ + int rsvd; /* OK to allocate reserved blocks */ + xfs_fsblock_t sum; + + xfs_bunmap_trace(ip, bno, len, flags, (inst_t *)__return_address); + whichfork = (flags & XFS_BMAPI_ATTRFORK) ? + XFS_ATTR_FORK : XFS_DATA_FORK; + ifp = XFS_IFORK_PTR(ip, whichfork); + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) + return XFS_ERROR(EFSCORRUPTED); + mp = ip->i_mount; + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + async = flags & XFS_BMAPI_ASYNC; + rsvd = (flags & XFS_BMAPI_RSVBLOCKS) != 0; + ASSERT(len > 0); + ASSERT(nexts >= 0); + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + if (nextents == 0) { + *done = 1; + return 0; + } + XFS_STATS_INC(xfsstats.xs_blk_unmap); + isrt = (whichfork == XFS_DATA_FORK) && + (ip->i_d.di_flags & XFS_DIFLAG_REALTIME); + start = bno; + bno = start + len - 1; + ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, + &prev); + /* + * Check to see if the given block number is past the end of the + * file, back up to the last block if so... + */ + if (eof) { + ep = &ifp->if_u1.if_extents[--lastx]; + xfs_bmbt_get_all(ep, &got); + bno = got.br_startoff + got.br_blockcount - 1; + } + logflags = 0; + if (ifp->if_flags & XFS_IFBROOT) { + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE); + cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip, + whichfork); + cur->bc_private.b.firstblock = *firstblock; + cur->bc_private.b.flist = flist; + cur->bc_private.b.flags = 0; + } else + cur = NULL; + extno = 0; + while (bno != (xfs_fileoff_t)-1 && bno >= start && lastx >= 0 && + (nexts == 0 || extno < nexts)) { + /* + * Is the found extent after a hole in which bno lives? + * Just back up to the previous extent, if so. + */ + if (got.br_startoff > bno) { + if (--lastx < 0) + break; + ep--; + xfs_bmbt_get_all(ep, &got); + } + /* + * Is the last block of this extent before the range + * we're supposed to delete? If so, we're done. + */ + bno = XFS_FILEOFF_MIN(bno, + got.br_startoff + got.br_blockcount - 1); + if (bno < start) + break; + /* + * Then deal with the (possibly delayed) allocated space + * we found. + */ + ASSERT(ep != NULL); + del = got; + wasdel = ISNULLSTARTBLOCK(del.br_startblock); + if (got.br_startoff < start) { + del.br_startoff = start; + del.br_blockcount -= start - got.br_startoff; + if (!wasdel) + del.br_startblock += start - got.br_startoff; + } + if (del.br_startoff + del.br_blockcount > bno + 1) + del.br_blockcount = bno + 1 - del.br_startoff; + sum = del.br_startblock + del.br_blockcount; + if (isrt && + (mod = do_mod(sum, mp->m_sb.sb_rextsize))) { + /* + * Realtime extent not lined up at the end. + * The extent could have been split into written + * and unwritten pieces, or we could just be + * unmapping part of it. But we can't really + * get rid of part of a realtime extent. + */ + if (del.br_state == XFS_EXT_UNWRITTEN || + !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) { + /* + * This piece is unwritten, or we're not + * using unwritten extents. Skip over it. + */ + ASSERT(bno >= mod); + bno -= mod > del.br_blockcount ? + del.br_blockcount : mod; + if (bno < got.br_startoff) { + if (--lastx >= 0) + xfs_bmbt_get_all(--ep, &got); + } + continue; + } + /* + * It's written, turn it unwritten. + * This is better than zeroing it. + */ + ASSERT(del.br_state == XFS_EXT_NORM); + ASSERT(xfs_trans_get_block_res(tp) > 0); + /* + * If this spans a realtime extent boundary, + * chop it back to the start of the one we end at. + */ + if (del.br_blockcount > mod) { + del.br_startoff += del.br_blockcount - mod; + del.br_startblock += del.br_blockcount - mod; + del.br_blockcount = mod; + } + del.br_state = XFS_EXT_UNWRITTEN; + error = xfs_bmap_add_extent(ip, lastx, &cur, &del, + firstblock, flist, &logflags, XFS_DATA_FORK, 0); + if (error) + goto error0; + goto nodelete; + } + if (isrt && (mod = do_mod(del.br_startblock, mp->m_sb.sb_rextsize))) { + /* + * Realtime extent is lined up at the end but not + * at the front. We'll get rid of full extents if + * we can. + */ + mod = mp->m_sb.sb_rextsize - mod; + if (del.br_blockcount > mod) { + del.br_blockcount -= mod; + del.br_startoff += mod; + del.br_startblock += mod; + } else if ((del.br_startoff == start && + (del.br_state == XFS_EXT_UNWRITTEN || + xfs_trans_get_block_res(tp) == 0)) || + !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) { + /* + * Can't make it unwritten. There isn't + * a full extent here so just skip it. + */ + ASSERT(bno >= del.br_blockcount); + bno -= del.br_blockcount; + if (bno < got.br_startoff) { + if (--lastx >= 0) + xfs_bmbt_get_all(--ep, &got); + } + continue; + } else if (del.br_state == XFS_EXT_UNWRITTEN) { + /* + * This one is already unwritten. + * It must have a written left neighbor. + * Unwrite the killed part of that one and + * try again. + */ + ASSERT(lastx > 0); + xfs_bmbt_get_all(ep - 1, &prev); + ASSERT(prev.br_state == XFS_EXT_NORM); + ASSERT(!ISNULLSTARTBLOCK(prev.br_startblock)); + ASSERT(del.br_startblock == + prev.br_startblock + prev.br_blockcount); + if (prev.br_startoff < start) { + mod = start - prev.br_startoff; + prev.br_blockcount -= mod; + prev.br_startblock += mod; + prev.br_startoff = start; + } + prev.br_state = XFS_EXT_UNWRITTEN; + error = xfs_bmap_add_extent(ip, lastx - 1, &cur, + &prev, firstblock, flist, &logflags, + XFS_DATA_FORK, 0); + if (error) + goto error0; + goto nodelete; + } else { + ASSERT(del.br_state == XFS_EXT_NORM); + del.br_state = XFS_EXT_UNWRITTEN; + error = xfs_bmap_add_extent(ip, lastx, &cur, + &del, firstblock, flist, &logflags, + XFS_DATA_FORK, 0); + if (error) + goto error0; + goto nodelete; + } + } + if (wasdel) { + ASSERT(STARTBLOCKVAL(del.br_startblock) > 0); + xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, + (int)del.br_blockcount, rsvd); + if (XFS_IS_QUOTA_ON(ip->i_mount)) { + ASSERT(ip->i_ino != mp->m_sb.sb_uquotino); + ASSERT(ip->i_ino != mp->m_sb.sb_gquotino); + if (!isrt) + xfs_trans_unreserve_blkquota(NULL, ip, + (long)del.br_blockcount); + else + xfs_trans_unreserve_rtblkquota(NULL, ip, + (long)del.br_blockcount); + } + ip->i_delayed_blks -= del.br_blockcount; + if (cur) + cur->bc_private.b.flags |= + XFS_BTCUR_BPRV_WASDEL; + } else if (cur) + cur->bc_private.b.flags &= ~XFS_BTCUR_BPRV_WASDEL; + /* + * If it's the case where the directory code is running + * with no block reservation, and the deleted block is in + * the middle of its extent, and the resulting insert + * of an extent would cause transformation to btree format, + * then reject it. The calling code will then swap + * blocks around instead. + * We have to do this now, rather than waiting for the + * conversion to btree format, since the transaction + * will be dirty. + */ + if (!wasdel && xfs_trans_get_block_res(tp) == 0 && + XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_NEXTENTS(ip, whichfork) >= ifp->if_ext_max && + del.br_startoff > got.br_startoff && + del.br_startoff + del.br_blockcount < + got.br_startoff + got.br_blockcount) { + error = XFS_ERROR(ENOSPC); + goto error0; + } + error = xfs_bmap_del_extent(ip, tp, lastx, flist, cur, &del, + flags, &tmp_logflags, whichfork, rsvd); + logflags |= tmp_logflags; + if (error) + goto error0; + bno = del.br_startoff - 1; +nodelete: + lastx = ifp->if_lastex; + /* + * If not done go on to the next (previous) record. + * Reset ep in case the extents array was re-alloced. + */ + ep = &ifp->if_u1.if_extents[lastx]; + if (bno != (xfs_fileoff_t)-1 && bno >= start) { + if (lastx >= XFS_IFORK_NEXTENTS(ip, whichfork) || + xfs_bmbt_get_startoff(ep) > bno) { + lastx--; + ep--; + } + if (lastx >= 0) + xfs_bmbt_get_all(ep, &got); + extno++; + } + } + ifp->if_lastex = lastx; + *done = bno == (xfs_fileoff_t)-1 || bno < start || lastx < 0; + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + /* + * Convert to a btree if necessary. + */ + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) { + ASSERT(cur == NULL); + error = xfs_bmap_extents_to_btree(tp, ip, firstblock, flist, + &cur, 0, &tmp_logflags, whichfork); + logflags |= tmp_logflags; + if (error) + goto error0; + } + /* + * transform from btree to extents, give it cur + */ + else if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE && + XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max) { + ASSERT(cur != NULL); + error = xfs_bmap_btree_to_extents(tp, ip, cur, &tmp_logflags, + whichfork, async); + logflags |= tmp_logflags; + if (error) + goto error0; + } + /* + * transform from extents to local? + */ + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + error = 0; +error0: + /* + * Log everything. Do this after conversion, there's no point in + * logging the extent list if we've converted to btree format. + */ + if ((logflags & XFS_ILOG_FEXT(whichfork)) && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) + logflags &= ~XFS_ILOG_FEXT(whichfork); + else if ((logflags & XFS_ILOG_FBROOT(whichfork)) && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) + logflags &= ~XFS_ILOG_FBROOT(whichfork); + /* + * Log inode even in the error case, if the transaction + * is dirty we'll need to shut down the filesystem. + */ + if (logflags) + xfs_trans_log_inode(tp, ip, logflags); + if (cur) { + if (!error) { + *firstblock = cur->bc_private.b.firstblock; + cur->bc_private.b.allocated = 0; + } + xfs_btree_del_cursor(cur, + error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); + } + return error; +} + +/* + * Check the last inode extent to determine whether this allocation will result + * in blocks being allocated at the end of the file. When we allocate new data + * blocks at the end of the file which do not start at the previous data block, + * we will try to align the new blocks at stripe unit boundaries. + */ +int /* error */ +xfs_bmap_isaeof( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fileoff_t off, /* file offset in fsblocks */ + int whichfork, /* data or attribute fork */ + int *aeof) /* return value */ +{ + int error; /* error return value */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_rec_t *lastrec; /* extent list entry pointer */ + xfs_extnum_t nextents; /* size of extent list */ + xfs_bmbt_irec_t s; /* expanded extent list entry */ + + ASSERT(whichfork == XFS_DATA_FORK); + ifp = XFS_IFORK_PTR(ip, whichfork); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(NULL, ip, whichfork))) + return error; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + if (nextents == 0) { + *aeof = 1; + return 0; + } + /* + * Go to the last extent + */ + lastrec = &ifp->if_u1.if_extents[nextents - 1]; + xfs_bmbt_get_all(lastrec, &s); + /* + * Check we are allocating in the last extent (for delayed allocations) + * or past the last extent for non-delayed allocations. + */ + *aeof = (off >= s.br_startoff && + off < s.br_startoff + s.br_blockcount && + ISNULLSTARTBLOCK(s.br_startblock)) || + off >= s.br_startoff + s.br_blockcount; + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_bmap_btree.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_bmap_btree.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_bmap_btree.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_bmap_btree.c Wed Apr 18 21:41:37 2001 @@ -0,0 +1,2528 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * Delete record pointed to by cur/level. + */ +STATIC int /* error */ +xfs_bmbt_delrec( + xfs_btree_cur_t *cur, + int level, + int async, /* deletion can be async */ + int *stat) /* success/failure */ +{ + xfs_bmbt_block_t *block; /* bmap btree block */ + xfs_fsblock_t bno; /* fs-relative block number */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_delrec"; +#endif + int i; /* loop counter */ + int j; /* temp state */ + xfs_bmbt_key_t key; /* bmap btree key */ + xfs_bmbt_key_t *kp=NULL; /* pointer to bmap btree key */ + xfs_fsblock_t lbno; /* left sibling block number */ + xfs_buf_t *lbp; /* left buffer pointer */ + xfs_bmbt_block_t *left; /* left btree block */ + xfs_bmbt_key_t *lkp; /* left btree key */ + xfs_bmbt_ptr_t *lpp; /* left address pointer */ + int lrecs=0; /* left record count */ + xfs_bmbt_rec_t *lrp; /* left record pointer */ + xfs_mount_t *mp; /* file system mount point */ + xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */ + int ptr; /* key/record index */ + xfs_fsblock_t rbno; /* right sibling block number */ + xfs_buf_t *rbp; /* right buffer pointer */ + xfs_bmbt_block_t *right; /* right btree block */ + xfs_bmbt_key_t *rkp; /* right btree key */ + xfs_bmbt_rec_t *rp; /* pointer to bmap btree rec */ + xfs_bmbt_ptr_t *rpp; /* right address pointer */ + xfs_bmbt_block_t *rrblock; /* right-right btree block */ + xfs_buf_t *rrbp; /* right-right buffer pointer */ + int rrecs=0; /* right record count */ + xfs_bmbt_rec_t *rrp; /* right record pointer */ + xfs_btree_cur_t *tcur; /* temporary btree cursor */ + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, level); + ptr = cur->bc_ptrs[level]; + tcur = (xfs_btree_cur_t *)0; + if (ptr == 0) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + block = xfs_bmbt_get_block(cur, level, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } +#endif + if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + XFS_STATS_INC(xfsstats.xs_bmbt_delrec); + if (level > 0) { + kp = XFS_BMAP_KEY_IADDR(block, 1, cur); + pp = XFS_BMAP_PTR_IADDR(block, 1, cur); +#ifdef DEBUG + for (i = ptr; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(pp[i], ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + } +#endif + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ovbcopy(&kp[ptr], &kp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*kp)); + ovbcopy(&pp[ptr], &pp[ptr - 1], /* INT_: direct copy */ + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*pp)); + xfs_bmbt_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + xfs_bmbt_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + } + } else { + rp = XFS_BMAP_REC_IADDR(block, 1, cur); + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ovbcopy(&rp[ptr], &rp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*rp)); + xfs_bmbt_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + } + if (ptr == 1) { + INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(rp)); + kp = &key; + } + } + INT_MOD(block->bb_numrecs, ARCH_CONVERT, -1); + xfs_bmbt_log_block(cur, bp, XFS_BB_NUMRECS); + /* + * We're at the root level. + * First, shrink the root block in-memory. + * Try to get rid of the next level down. + * If we can't then there's nothing left to do. + */ + if (level == cur->bc_nlevels - 1) { + xfs_iroot_realloc(cur->bc_private.b.ip, -1, + cur->bc_private.b.whichfork); + if ((error = xfs_bmbt_killroot(cur, async))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (level > 0 && (error = xfs_bmbt_decrement(cur, level, &j))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + if (ptr == 1 && (error = xfs_bmbt_updkey(cur, kp, level + 1))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) >= XFS_BMAP_BLOCK_IMINRECS(level, cur)) { + if (level > 0 && (error = xfs_bmbt_decrement(cur, level, &j))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + rbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + lbno = INT_GET(block->bb_leftsib, ARCH_CONVERT); + /* + * One child of root, need to get a chance to copy its contents + * into the root and delete it. Can't go up to next level, + * there's nothing to delete there. + */ + if (lbno == NULLFSBLOCK && rbno == NULLFSBLOCK && + level == cur->bc_nlevels - 2) { + if ((error = xfs_bmbt_killroot(cur, async))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (level > 0 && (error = xfs_bmbt_decrement(cur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + ASSERT(rbno != NULLFSBLOCK || lbno != NULLFSBLOCK); + if ((error = xfs_btree_dup_cursor(cur, &tcur))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + bno = NULLFSBLOCK; + if (rbno != NULLFSBLOCK) { + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_bmbt_increment(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + rbp = tcur->bc_bufs[level]; + right = XFS_BUF_TO_BMBT_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, right, level, rbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } +#endif + bno = INT_GET(right->bb_leftsib, ARCH_CONVERT); + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_BMAP_BLOCK_IMINRECS(level, cur)) { + if ((error = xfs_bmbt_lshift(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_BMAP_BLOCK_IMINRECS(level, tcur)); + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + tcur = NULL; + if (level > 0) { + if ((error = xfs_bmbt_decrement(cur, + level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, + ERROR); + goto error0; + } + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + } + rrecs = INT_GET(right->bb_numrecs, ARCH_CONVERT); + if (lbno != NULLFSBLOCK) { + i = xfs_btree_firstrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_bmbt_decrement(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + } + if (lbno != NULLFSBLOCK) { + i = xfs_btree_firstrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * decrement to last in block + */ + if ((error = xfs_bmbt_decrement(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + i = xfs_btree_firstrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + lbp = tcur->bc_bufs[level]; + left = XFS_BUF_TO_BMBT_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, left, level, lbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } +#endif + bno = INT_GET(left->bb_rightsib, ARCH_CONVERT); + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_BMAP_BLOCK_IMINRECS(level, cur)) { + if ((error = xfs_bmbt_rshift(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_BMAP_BLOCK_IMINRECS(level, tcur)); + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + tcur = NULL; + if (level == 0) + cur->bc_ptrs[0]++; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + } + lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + tcur = NULL; + mp = cur->bc_mp; + ASSERT(bno != NULLFSBLOCK); + if (lbno != NULLFSBLOCK && + lrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { + rbno = bno; + right = block; + rbp = bp; + if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, lbno, 0, &lbp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + left = XFS_BUF_TO_BMBT_BLOCK(lbp); + if ((error = xfs_btree_check_lblock(cur, left, level, lbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + } else if (rbno != NULLFSBLOCK && + rrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= + XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { + lbno = bno; + left = block; + lbp = bp; + if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, rbno, 0, &rbp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + right = XFS_BUF_TO_BMBT_BLOCK(rbp); + if ((error = xfs_btree_check_lblock(cur, right, level, rbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT); + } else { + if (level > 0 && (error = xfs_bmbt_decrement(cur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + if (level > 0) { + lkp = XFS_BMAP_KEY_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + lpp = XFS_BMAP_PTR_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rkp = XFS_BMAP_KEY_IADDR(right, 1, cur); + rpp = XFS_BMAP_PTR_IADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + } +#endif + bcopy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp)); + bcopy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp)); + xfs_bmbt_log_keys(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_bmbt_log_ptrs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } else { + lrp = XFS_BMAP_REC_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rrp = XFS_BMAP_REC_IADDR(right, 1, cur); + bcopy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp)); + xfs_bmbt_log_recs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } + INT_MOD(left->bb_numrecs, ARCH_CONVERT, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + left->bb_rightsib = right->bb_rightsib; /* INT_: direct copy */ + xfs_bmbt_log_block(cur, lbp, XFS_BB_RIGHTSIB | XFS_BB_NUMRECS); + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) != NULLDFSBNO) { + if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, + INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, &rrbp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + rrblock = XFS_BUF_TO_BMBT_BLOCK(rrbp); + if ((error = xfs_btree_check_lblock(cur, rrblock, level, rrbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, lbno); + xfs_bmbt_log_block(cur, rrbp, XFS_BB_LEFTSIB); + } + xfs_bmap_add_free(XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(rbp)), 1, + cur->bc_private.b.flist, mp); + if (!async) + xfs_trans_set_sync(cur->bc_tp); + cur->bc_private.b.ip->i_d.di_nblocks--; + xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, XFS_ILOG_CORE); + if (XFS_IS_QUOTA_ON(mp) && + cur->bc_private.b.ip->i_ino != mp->m_sb.sb_uquotino && + cur->bc_private.b.ip->i_ino != mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(cur->bc_tp, cur->bc_private.b.ip, + XFS_TRANS_DQ_BCOUNT, -1L); + xfs_trans_binval(cur->bc_tp, rbp); + if (bp != lbp) { + cur->bc_bufs[level] = lbp; + cur->bc_ptrs[level] += lrecs; + cur->bc_ra[level] = 0; + } else if ((error = xfs_bmbt_increment(cur, level + 1, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (level > 0) + cur->bc_ptrs[level]--; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 2; + return 0; + +error0: + if (tcur) + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; +} + +/* + * Insert one record/level. Return information to the caller + * allowing the next level up to proceed if necessary. + */ +STATIC int /* error */ +xfs_bmbt_insrec( + xfs_btree_cur_t *cur, + int level, + xfs_fsblock_t *bnop, + xfs_bmbt_rec_t *recp, + xfs_btree_cur_t **curp, + int *stat) /* no-go/done/continue */ +{ + xfs_bmbt_block_t *block; /* bmap btree block */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_insrec"; +#endif + int i; /* loop index */ + xfs_bmbt_key_t key; /* bmap btree key */ + xfs_bmbt_key_t *kp=NULL; /* pointer to bmap btree key */ + int logflags; /* inode logging flags */ + xfs_fsblock_t nbno; /* new block number */ + struct xfs_btree_cur *ncur; /* new btree cursor */ + xfs_bmbt_key_t nkey; /* new btree key value */ + xfs_bmbt_rec_t nrec; /* new record count */ + int optr; /* old key/record index */ + xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */ + int ptr; /* key/record index */ + xfs_bmbt_rec_t *rp=NULL; /* pointer to bmap btree rec */ + + ASSERT(level < cur->bc_nlevels); + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGIFR(cur, level, *bnop, recp); + ncur = (xfs_btree_cur_t *)0; + INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(recp)); + optr = ptr = cur->bc_ptrs[level]; + if (ptr == 0) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + XFS_STATS_INC(xfsstats.xs_bmbt_insrec); + block = xfs_bmbt_get_block(cur, level, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (ptr <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + if (level == 0) { + rp = XFS_BMAP_REC_IADDR(block, ptr, cur); + xfs_btree_check_rec(XFS_BTNUM_BMAP, recp, rp); + } else { + kp = XFS_BMAP_KEY_IADDR(block, ptr, cur); + xfs_btree_check_key(XFS_BTNUM_BMAP, &key, kp); + } + } +#endif + nbno = NULLFSBLOCK; + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) == XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) < XFS_BMAP_BLOCK_DMAXRECS(level, cur)) { + /* + * A root block, that can be made bigger. + */ + xfs_iroot_realloc(cur->bc_private.b.ip, 1, + cur->bc_private.b.whichfork); + block = xfs_bmbt_get_block(cur, level, &bp); + } else if (level == cur->bc_nlevels - 1) { + if ((error = xfs_bmbt_newroot(cur, &logflags, stat)) || + *stat == 0) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, + logflags); + block = xfs_bmbt_get_block(cur, level, &bp); + } else { + if ((error = xfs_bmbt_rshift(cur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (i) { + /* nothing */ + } else { + if ((error = xfs_bmbt_lshift(cur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (i) { + optr = ptr = cur->bc_ptrs[level]; + } else { + if ((error = xfs_bmbt_split(cur, level, + &nbno, &nkey, &ncur, + &i))) { + XFS_BMBT_TRACE_CURSOR(cur, + ERROR); + return error; + } + if (i) { + block = xfs_bmbt_get_block( + cur, level, &bp); +#ifdef DEBUG + if ((error = + xfs_btree_check_lblock(cur, + block, level, bp))) { + XFS_BMBT_TRACE_CURSOR( + cur, ERROR); + return error; + } +#endif + ptr = cur->bc_ptrs[level]; + xfs_bmbt_set_allf(&nrec, + nkey.br_startoff, 0, 0, + XFS_EXT_NORM); + } else { + XFS_BMBT_TRACE_CURSOR(cur, + EXIT); + *stat = 0; + return 0; + } + } + } + } + } + if (level > 0) { + kp = XFS_BMAP_KEY_IADDR(block, 1, cur); + pp = XFS_BMAP_PTR_IADDR(block, 1, cur); +#ifdef DEBUG + for (i = INT_GET(block->bb_numrecs, ARCH_CONVERT); i >= ptr; i--) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(pp[i - 1], ARCH_CONVERT), + level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + ovbcopy(&kp[ptr - 1], &kp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*kp)); + ovbcopy(&pp[ptr - 1], &pp[ptr], /* INT_: direct copy */ + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*pp)); +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, (xfs_bmbt_ptr_t)*bnop, + level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + kp[ptr - 1] = key; + INT_SET(pp[ptr - 1], ARCH_CONVERT, *bnop); + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_bmbt_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + xfs_bmbt_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + } else { + rp = XFS_BMAP_REC_IADDR(block, 1, cur); + ovbcopy(&rp[ptr - 1], &rp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*rp)); + rp[ptr - 1] = *recp; + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_bmbt_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + } + xfs_bmbt_log_block(cur, bp, XFS_BB_NUMRECS); +#ifdef DEBUG + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + if (level == 0) + xfs_btree_check_rec(XFS_BTNUM_BMAP, rp + ptr - 1, + rp + ptr); + else + xfs_btree_check_key(XFS_BTNUM_BMAP, kp + ptr - 1, + kp + ptr); + } +#endif + if (optr == 1 && (error = xfs_bmbt_updkey(cur, &key, level + 1))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + *bnop = nbno; + if (nbno != NULLFSBLOCK) { + *recp = nrec; + *curp = ncur; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +} + +STATIC int +xfs_bmbt_killroot( + xfs_btree_cur_t *cur, + int async) +{ + xfs_bmbt_block_t *block; + xfs_bmbt_block_t *cblock; + xfs_buf_t *cbp; + xfs_bmbt_key_t *ckp; + xfs_bmbt_ptr_t *cpp; +#ifdef DEBUG + int error; +#endif +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_killroot"; +#endif + int i; + xfs_bmbt_key_t *kp; + xfs_inode_t *ip; + xfs_ifork_t *ifp; + int level; + xfs_bmbt_ptr_t *pp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + level = cur->bc_nlevels - 1; + ASSERT(level >= 1); + /* + * Don't deal with the root block needs to be a leaf case. + * We're just going to turn the thing back into extents anyway. + */ + if (level == 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; + } + block = xfs_bmbt_get_block(cur, level, &cbp); + /* + * Give up if the root has multiple children. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) != 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; + } + /* + * Only do this if the next level will fit. + * Then the data must be copied up to the inode, + * instead of freeing the root you free the next level. + */ + cbp = cur->bc_bufs[level - 1]; + cblock = XFS_BUF_TO_BMBT_BLOCK(cbp); + if (INT_GET(cblock->bb_numrecs, ARCH_CONVERT) > XFS_BMAP_BLOCK_DMAXRECS(level, cur)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; + } + ASSERT(INT_GET(cblock->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO); + ASSERT(INT_GET(cblock->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO); + ip = cur->bc_private.b.ip; + ifp = XFS_IFORK_PTR(ip, cur->bc_private.b.whichfork); + ASSERT(XFS_BMAP_BLOCK_IMAXRECS(level, cur) == + XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes)); + i = (int)(INT_GET(cblock->bb_numrecs, ARCH_CONVERT) - XFS_BMAP_BLOCK_IMAXRECS(level, cur)); + if (i) { + xfs_iroot_realloc(ip, i, cur->bc_private.b.whichfork); + block = ifp->if_broot; + } + INT_MOD(block->bb_numrecs, ARCH_CONVERT, i); + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) == INT_GET(cblock->bb_numrecs, ARCH_CONVERT)); + kp = XFS_BMAP_KEY_IADDR(block, 1, cur); + ckp = XFS_BMAP_KEY_IADDR(cblock, 1, cur); + bcopy(ckp, kp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*kp)); + pp = XFS_BMAP_PTR_IADDR(block, 1, cur); + cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(cblock->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(cpp[i], ARCH_CONVERT), level - 1))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + bcopy(cpp, pp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*pp)); + xfs_bmap_add_free(XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(cbp)), 1, + cur->bc_private.b.flist, cur->bc_mp); + if (!async) + xfs_trans_set_sync(cur->bc_tp); + ip->i_d.di_nblocks--; + if (XFS_IS_QUOTA_ON(cur->bc_mp) && + ip->i_ino != cur->bc_mp->m_sb.sb_uquotino && + ip->i_ino != cur->bc_mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(cur->bc_tp, ip, XFS_TRANS_DQ_BCOUNT, + -1L); + xfs_trans_binval(cur->bc_tp, cbp); + cur->bc_bufs[level - 1] = NULL; + INT_MOD(block->bb_level, ARCH_CONVERT, -1); + xfs_trans_log_inode(cur->bc_tp, ip, + XFS_ILOG_CORE | XFS_ILOG_FBROOT(cur->bc_private.b.whichfork)); + cur->bc_nlevels--; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; +} + +/* + * Log key values from the btree block. + */ +STATIC void +xfs_bmbt_log_keys( + xfs_btree_cur_t *cur, + xfs_buf_t *bp, + int kfirst, + int klast) +{ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_log_keys"; +#endif + xfs_trans_t *tp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGBII(cur, bp, kfirst, klast); + tp = cur->bc_tp; + if (bp) { + xfs_bmbt_block_t *block; + int first; + xfs_bmbt_key_t *kp; + int last; + + block = XFS_BUF_TO_BMBT_BLOCK(bp); + kp = XFS_BMAP_KEY_DADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&kp[kfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&kp[klast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(tp, bp, first, last); + } else { + xfs_inode_t *ip; + + ip = cur->bc_private.b.ip; + xfs_trans_log_inode(tp, ip, + XFS_ILOG_FBROOT(cur->bc_private.b.whichfork)); + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); +} + +/* + * Log pointer values from the btree block. + */ +STATIC void +xfs_bmbt_log_ptrs( + xfs_btree_cur_t *cur, + xfs_buf_t *bp, + int pfirst, + int plast) +{ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_log_ptrs"; +#endif + xfs_trans_t *tp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGBII(cur, bp, pfirst, plast); + tp = cur->bc_tp; + if (bp) { + xfs_bmbt_block_t *block; + int first; + int last; + xfs_bmbt_ptr_t *pp; + + block = XFS_BUF_TO_BMBT_BLOCK(bp); + pp = XFS_BMAP_PTR_DADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&pp[pfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&pp[plast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(tp, bp, first, last); + } else { + xfs_inode_t *ip; + + ip = cur->bc_private.b.ip; + xfs_trans_log_inode(tp, ip, + XFS_ILOG_FBROOT(cur->bc_private.b.whichfork)); + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); +} + +/* + * Lookup the record. The cursor is made to point to it, based on dir. + */ +STATIC int /* error */ +xfs_bmbt_lookup( + xfs_btree_cur_t *cur, + xfs_lookup_t dir, + int *stat) /* success/failure */ +{ + xfs_bmbt_block_t *block=NULL; + xfs_buf_t *bp; + xfs_daddr_t d; + xfs_sfiloff_t diff; + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_lookup"; +#endif + xfs_fsblock_t fsbno=0; + int high; + int i; + int keyno=0; + xfs_bmbt_key_t *kkbase=NULL; + xfs_bmbt_key_t *kkp; + xfs_bmbt_rec_t *krbase=NULL; + xfs_bmbt_rec_t *krp; + int level; + int low; + xfs_mount_t *mp; + xfs_bmbt_ptr_t *pp; + xfs_bmbt_irec_t *rp; + xfs_fileoff_t startoff; + xfs_trans_t *tp; + + XFS_STATS_INC(xfsstats.xs_bmbt_lookup); + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, (int)dir); + tp = cur->bc_tp; + mp = cur->bc_mp; + rp = &cur->bc_rec.b; + for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) { + if (level < cur->bc_nlevels - 1) { + d = XFS_FSB_TO_DADDR(mp, fsbno); + bp = cur->bc_bufs[level]; + if (bp && XFS_BUF_ADDR(bp) != d) + bp = (xfs_buf_t *)0; + if (!bp) { + if ((error = xfs_btree_read_bufl(mp, tp, fsbno, + 0, &bp, XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + xfs_btree_setbuf(cur, level, bp); + block = XFS_BUF_TO_BMBT_BLOCK(bp); + if ((error = xfs_btree_check_lblock(cur, block, + level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } else + block = XFS_BUF_TO_BMBT_BLOCK(bp); + } else + block = xfs_bmbt_get_block(cur, level, &bp); + if (diff == 0) + keyno = 1; + else { + if (level > 0) + kkbase = XFS_BMAP_KEY_IADDR(block, 1, cur); + else + krbase = XFS_BMAP_REC_IADDR(block, 1, cur); + low = 1; + if (!(high = INT_GET(block->bb_numrecs, ARCH_CONVERT))) { + ASSERT(level == 0); + cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + while (low <= high) { + XFS_STATS_INC(xfsstats.xs_bmbt_compare); + keyno = (low + high) >> 1; + if (level > 0) { + kkp = kkbase + keyno - 1; + startoff = INT_GET(kkp->br_startoff, ARCH_CONVERT); + } else { + krp = krbase + keyno - 1; + startoff = xfs_bmbt_get_startoff(krp); + } + diff = (xfs_sfiloff_t) + (startoff - rp->br_startoff); + if (diff < 0) + low = keyno + 1; + else if (diff > 0) + high = keyno - 1; + else + break; + } + } + if (level > 0) { + if (diff > 0 && --keyno < 1) + keyno = 1; + pp = XFS_BMAP_PTR_IADDR(block, keyno, cur); +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + fsbno = INT_GET(*pp, ARCH_CONVERT); + cur->bc_ptrs[level] = keyno; + } + } + if (dir != XFS_LOOKUP_LE && diff < 0) { + keyno++; + /* + * If ge search and we went off the end of the block, but it's + * not the last block, we're in the wrong block. + */ + if (dir == XFS_LOOKUP_GE && keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT) && + INT_GET(block->bb_rightsib, ARCH_CONVERT) != NULLDFSBNO) { + cur->bc_ptrs[0] = keyno; + if ((error = xfs_bmbt_increment(cur, 0, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + XFS_WANT_CORRUPTED_RETURN(i == 1); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + } + else if (dir == XFS_LOOKUP_LE && diff > 0) + keyno--; + cur->bc_ptrs[0] = keyno; + if (keyno == 0 || keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + } else { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = ((dir != XFS_LOOKUP_EQ) || (diff == 0)); + } + return 0; +} + +/* + * Move 1 record left from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_bmbt_lshift( + xfs_btree_cur_t *cur, + int level, + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_lshift"; +#endif +#ifdef DEBUG + int i; /* loop counter */ +#endif + xfs_bmbt_key_t key; /* bmap btree key */ + xfs_buf_t *lbp; /* left buffer pointer */ + xfs_bmbt_block_t *left; /* left btree block */ + xfs_bmbt_key_t *lkp=NULL; /* left btree key */ + xfs_bmbt_ptr_t *lpp; /* left address pointer */ + int lrecs; /* left record count */ + xfs_bmbt_rec_t *lrp=NULL; /* left record pointer */ + xfs_mount_t *mp; /* file system mount point */ + xfs_buf_t *rbp; /* right buffer pointer */ + xfs_bmbt_block_t *right; /* right btree block */ + xfs_bmbt_key_t *rkp=NULL; /* right btree key */ + xfs_bmbt_ptr_t *rpp=NULL; /* right address pointer */ + xfs_bmbt_rec_t *rrp=NULL; /* right record pointer */ + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, level); + if (level == cur->bc_nlevels - 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + rbp = cur->bc_bufs[level]; + right = XFS_BUF_TO_BMBT_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, right, level, rbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + if (INT_GET(right->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + if (cur->bc_ptrs[level] <= 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + mp = cur->bc_mp; + if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, INT_GET(right->bb_leftsib, ARCH_CONVERT), 0, + &lbp, XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + left = XFS_BUF_TO_BMBT_BLOCK(lbp); + if ((error = xfs_btree_check_lblock(cur, left, level, lbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) == XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1; + if (level > 0) { + lkp = XFS_BMAP_KEY_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rkp = XFS_BMAP_KEY_IADDR(right, 1, cur); + *lkp = *rkp; + xfs_bmbt_log_keys(cur, lbp, lrecs, lrecs); + lpp = XFS_BMAP_PTR_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rpp = XFS_BMAP_PTR_IADDR(right, 1, cur); +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, INT_GET(*rpp, ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + *lpp = *rpp; /* INT_: direct copy */ + xfs_bmbt_log_ptrs(cur, lbp, lrecs, lrecs); + } else { + lrp = XFS_BMAP_REC_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rrp = XFS_BMAP_REC_IADDR(right, 1, cur); + *lrp = *rrp; + xfs_bmbt_log_recs(cur, lbp, lrecs, lrecs); + } + INT_MOD(left->bb_numrecs, ARCH_CONVERT, +1); + xfs_bmbt_log_block(cur, lbp, XFS_BB_NUMRECS); +#ifdef DEBUG + if (level > 0) + xfs_btree_check_key(XFS_BTNUM_BMAP, lkp - 1, lkp); + else + xfs_btree_check_rec(XFS_BTNUM_BMAP, lrp - 1, lrp); +#endif + INT_MOD(right->bb_numrecs, ARCH_CONVERT, -1); + xfs_bmbt_log_block(cur, rbp, XFS_BB_NUMRECS); + if (level > 0) { +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i + 1], ARCH_CONVERT), + level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + ovbcopy(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); + xfs_bmbt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_bmbt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } else { + ovbcopy(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_bmbt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(rrp)); + rkp = &key; + } + if ((error = xfs_bmbt_updkey(cur, rkp, level + 1))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + cur->bc_ptrs[level]--; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +} + +/* + * Move 1 record right from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_bmbt_rshift( + xfs_btree_cur_t *cur, + int level, + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_rshift"; +#endif + int i; /* loop counter */ + xfs_bmbt_key_t key; /* bmap btree key */ + xfs_buf_t *lbp; /* left buffer pointer */ + xfs_bmbt_block_t *left; /* left btree block */ + xfs_bmbt_key_t *lkp; /* left btree key */ + xfs_bmbt_ptr_t *lpp; /* left address pointer */ + xfs_bmbt_rec_t *lrp; /* left record pointer */ + xfs_mount_t *mp; /* file system mount point */ + xfs_buf_t *rbp; /* right buffer pointer */ + xfs_bmbt_block_t *right; /* right btree block */ + xfs_bmbt_key_t *rkp; /* right btree key */ + xfs_bmbt_ptr_t *rpp; /* right address pointer */ + xfs_bmbt_rec_t *rrp=NULL; /* right record pointer */ + struct xfs_btree_cur *tcur; /* temporary btree cursor */ + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, level); + if (level == cur->bc_nlevels - 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + lbp = cur->bc_bufs[level]; + left = XFS_BUF_TO_BMBT_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, left, level, lbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + if (cur->bc_ptrs[level] >= INT_GET(left->bb_numrecs, ARCH_CONVERT)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + mp = cur->bc_mp; + if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, + &rbp, XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + right = XFS_BUF_TO_BMBT_BLOCK(rbp); + if ((error = xfs_btree_check_lblock(cur, right, level, rbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) == XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + if (level > 0) { + lkp = XFS_BMAP_KEY_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + lpp = XFS_BMAP_PTR_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rkp = XFS_BMAP_KEY_IADDR(right, 1, cur); + rpp = XFS_BMAP_PTR_IADDR(right, 1, cur); +#ifdef DEBUG + for (i = INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1; i >= 0; i--) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + ovbcopy(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, INT_GET(*lpp, ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + *rkp = *lkp; + *rpp = *lpp; /* INT_: direct copy */ + xfs_bmbt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + xfs_bmbt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + } else { + lrp = XFS_BMAP_REC_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rrp = XFS_BMAP_REC_IADDR(right, 1, cur); + ovbcopy(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + *rrp = *lrp; + xfs_bmbt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(rrp)); + rkp = &key; + } + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -1); + xfs_bmbt_log_block(cur, lbp, XFS_BB_NUMRECS); + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); +#ifdef DEBUG + if (level > 0) + xfs_btree_check_key(XFS_BTNUM_BMAP, rkp, rkp + 1); + else + xfs_btree_check_rec(XFS_BTNUM_BMAP, rrp, rrp + 1); +#endif + xfs_bmbt_log_block(cur, rbp, XFS_BB_NUMRECS); + if ((error = xfs_btree_dup_cursor(cur, &tcur))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_bmbt_increment(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(tcur, ERROR); + goto error1; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_bmbt_updkey(tcur, rkp, level + 1))) { + XFS_BMBT_TRACE_CURSOR(tcur, ERROR); + goto error1; + } + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +error0: + XFS_BMBT_TRACE_CURSOR(cur, ERROR); +error1: + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; +} + +/* + * Determine the extent state. + */ +/* ARGSUSED */ +STATIC xfs_exntst_t +xfs_extent_state( + xfs_filblks_t blks, + int extent_flag) +{ + if (extent_flag) { + ASSERT(blks != 0); /* saved for DMIG */ + return XFS_EXT_UNWRITTEN; + } + return XFS_EXT_NORM; +} + + +/* + * Split cur/level block in half. + * Return new block number and its first record (to be inserted into parent). + */ +STATIC int /* error */ +xfs_bmbt_split( + xfs_btree_cur_t *cur, + int level, + xfs_fsblock_t *bnop, + xfs_bmbt_key_t *keyp, + xfs_btree_cur_t **curp, + int *stat) /* success/failure */ +{ + xfs_alloc_arg_t args; /* block allocation args */ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_split"; +#endif + int i; /* loop counter */ + xfs_fsblock_t lbno; /* left sibling block number */ + xfs_buf_t *lbp; /* left buffer pointer */ + xfs_bmbt_block_t *left; /* left btree block */ + xfs_bmbt_key_t *lkp; /* left btree key */ + xfs_bmbt_ptr_t *lpp; /* left address pointer */ + xfs_bmbt_rec_t *lrp; /* left record pointer */ + xfs_buf_t *rbp; /* right buffer pointer */ + xfs_bmbt_block_t *right; /* right btree block */ + xfs_bmbt_key_t *rkp; /* right btree key */ + xfs_bmbt_ptr_t *rpp; /* right address pointer */ + xfs_bmbt_block_t *rrblock; /* right-right btree block */ + xfs_buf_t *rrbp; /* right-right buffer pointer */ + xfs_bmbt_rec_t *rrp; /* right record pointer */ + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGIFK(cur, level, *bnop, keyp); + args.tp = cur->bc_tp; + args.mp = cur->bc_mp; + lbp = cur->bc_bufs[level]; + lbno = XFS_DADDR_TO_FSB(args.mp, XFS_BUF_ADDR(lbp)); + left = XFS_BUF_TO_BMBT_BLOCK(lbp); + args.fsbno = cur->bc_private.b.firstblock; + if (args.fsbno == NULLFSBLOCK) { + args.fsbno = lbno; + args.type = XFS_ALLOCTYPE_START_BNO; + } else if (cur->bc_private.b.flist->xbf_low) + args.type = XFS_ALLOCTYPE_FIRST_AG; + else + args.type = XFS_ALLOCTYPE_NEAR_BNO; + args.mod = args.minleft = args.alignment = args.total = args.isfl = + args.userdata = args.minalignslop = 0; + args.minlen = args.maxlen = args.prod = 1; + args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; + if (!args.wasdel && xfs_trans_get_block_res(args.tp) == 0) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return XFS_ERROR(ENOSPC); + } + if ((error = xfs_alloc_vextent(&args))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (args.fsbno == NULLFSBLOCK) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + ASSERT(args.len == 1); + cur->bc_private.b.firstblock = args.fsbno; + cur->bc_private.b.allocated++; + cur->bc_private.b.ip->i_d.di_nblocks++; + xfs_trans_log_inode(args.tp, cur->bc_private.b.ip, XFS_ILOG_CORE); + if (XFS_IS_QUOTA_ON(args.mp) && + cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_uquotino && + cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip, + XFS_TRANS_DQ_BCOUNT, 1L); + rbp = xfs_btree_get_bufl(args.mp, args.tp, args.fsbno, 0); + right = XFS_BUF_TO_BMBT_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, left, level, rbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + INT_SET(right->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC); + right->bb_level = left->bb_level; /* INT_: direct copy */ + INT_SET(right->bb_numrecs, ARCH_CONVERT, (__uint16_t)(INT_GET(left->bb_numrecs, ARCH_CONVERT) / 2)); + if ((INT_GET(left->bb_numrecs, ARCH_CONVERT) & 1) && + cur->bc_ptrs[level] <= INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1) + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); + i = INT_GET(left->bb_numrecs, ARCH_CONVERT) - INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1; + if (level > 0) { + lkp = XFS_BMAP_KEY_IADDR(left, i, cur); + lpp = XFS_BMAP_PTR_IADDR(left, i, cur); + rkp = XFS_BMAP_KEY_IADDR(right, 1, cur); + rpp = XFS_BMAP_PTR_IADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(lpp[i], ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + bcopy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + bcopy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); + xfs_bmbt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_bmbt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + keyp->br_startoff = INT_GET(rkp->br_startoff, ARCH_CONVERT); + } else { + lrp = XFS_BMAP_REC_IADDR(left, i, cur); + rrp = XFS_BMAP_REC_IADDR(right, 1, cur); + bcopy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_bmbt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + keyp->br_startoff = xfs_bmbt_get_startoff(rrp); + } + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -(INT_GET(right->bb_numrecs, ARCH_CONVERT))); + right->bb_rightsib = left->bb_rightsib; /* INT_: direct copy */ + INT_SET(left->bb_rightsib, ARCH_CONVERT, args.fsbno); + INT_SET(right->bb_leftsib, ARCH_CONVERT, lbno); + xfs_bmbt_log_block(cur, rbp, XFS_BB_ALL_BITS); + xfs_bmbt_log_block(cur, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); + if (INT_GET(right->bb_rightsib, ARCH_CONVERT) != NULLDFSBNO) { + if ((error = xfs_btree_read_bufl(args.mp, args.tp, + INT_GET(right->bb_rightsib, ARCH_CONVERT), 0, &rrbp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + rrblock = XFS_BUF_TO_BMBT_BLOCK(rrbp); + if ((error = xfs_btree_check_lblock(cur, rrblock, level, rrbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, args.fsbno); + xfs_bmbt_log_block(cur, rrbp, XFS_BB_LEFTSIB); + } + if (cur->bc_ptrs[level] > INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1) { + xfs_btree_setbuf(cur, level, rbp); + cur->bc_ptrs[level] -= INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + if (level + 1 < cur->bc_nlevels) { + if ((error = xfs_btree_dup_cursor(cur, curp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + (*curp)->bc_ptrs[level + 1]++; + } + *bnop = args.fsbno; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +} + +/* + * Update keys for the record. + */ +STATIC int +xfs_bmbt_updkey( + xfs_btree_cur_t *cur, + xfs_bmbt_key_t *keyp, /* on-disk format */ + int level) +{ + xfs_bmbt_block_t *block; + xfs_buf_t *bp; +#ifdef DEBUG + int error; +#endif +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_updkey"; +#endif + xfs_bmbt_key_t *kp; + int ptr; + + ASSERT(level >= 1); + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGIK(cur, level, keyp); + for (ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) { + block = xfs_bmbt_get_block(cur, level, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + ptr = cur->bc_ptrs[level]; + kp = XFS_BMAP_KEY_IADDR(block, ptr, cur); + *kp = *keyp; + xfs_bmbt_log_keys(cur, bp, ptr, ptr); + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; +} + +/* + * Convert on-disk form of btree root to in-memory form. + */ +void +xfs_bmdr_to_bmbt( + xfs_bmdr_block_t *dblock, + int dblocklen, + xfs_bmbt_block_t *rblock, + int rblocklen) +{ + int dmxr; + xfs_bmbt_key_t *fkp; + xfs_bmbt_ptr_t *fpp; + xfs_bmbt_key_t *tkp; + xfs_bmbt_ptr_t *tpp; + + INT_SET(rblock->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC); + rblock->bb_level = dblock->bb_level; /* both in on-disk format */ + ASSERT(INT_GET(rblock->bb_level, ARCH_CONVERT) > 0); + rblock->bb_numrecs = dblock->bb_numrecs;/* both in on-disk format */ + INT_SET(rblock->bb_leftsib, ARCH_CONVERT, NULLDFSBNO); + INT_SET(rblock->bb_rightsib, ARCH_CONVERT, NULLDFSBNO); + dmxr = (int)XFS_BTREE_BLOCK_MAXRECS(dblocklen, xfs_bmdr, 0); + fkp = XFS_BTREE_KEY_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + tkp = XFS_BMAP_BROOT_KEY_ADDR(rblock, 1, rblocklen); + fpp = XFS_BTREE_PTR_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + tpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen); + dmxr = INT_GET(dblock->bb_numrecs, ARCH_CONVERT); + bcopy(fkp, tkp, sizeof(*fkp) * dmxr); + bcopy(fpp, tpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */ +} + +/* + * Decrement cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_bmbt_decrement( + xfs_btree_cur_t *cur, + int level, + int *stat) /* success/failure */ +{ + xfs_bmbt_block_t *block; + xfs_buf_t *bp; + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_decrement"; +#endif + xfs_fsblock_t fsbno; + int lev; + xfs_mount_t *mp; + xfs_trans_t *tp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, level); + ASSERT(level < cur->bc_nlevels); + if (level < cur->bc_nlevels - 1) + xfs_btree_readahead(cur, level, XFS_BTCUR_LEFTRA); + if (--cur->bc_ptrs[level] > 0) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + block = xfs_bmbt_get_block(cur, level, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + if (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + if (--cur->bc_ptrs[lev] > 0) + break; + if (lev < cur->bc_nlevels - 1) + xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA); + } + if (lev == cur->bc_nlevels) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + tp = cur->bc_tp; + mp = cur->bc_mp; + for (block = xfs_bmbt_get_block(cur, lev, &bp); lev > level; ) { + fsbno = INT_GET(*XFS_BMAP_PTR_IADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufl(mp, tp, fsbno, 0, &bp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_BMBT_BLOCK(bp); + if ((error = xfs_btree_check_lblock(cur, block, lev, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + cur->bc_ptrs[lev] = INT_GET(block->bb_numrecs, ARCH_CONVERT); + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +} + +/* + * Delete the record pointed to by cur. + */ +int /* error */ +xfs_bmbt_delete( + xfs_btree_cur_t *cur, + int async, /* deletion can be async */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_delete"; +#endif + int i; + int level; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + for (level = 0, i = 2; i == 2; level++) { + if ((error = xfs_bmbt_delrec(cur, level, async, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } + if (i == 0) { + for (level = 1; level < cur->bc_nlevels; level++) { + if (cur->bc_ptrs[level] == 0) { + if ((error = xfs_bmbt_decrement(cur, level, + &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + break; + } + } + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = i; + return 0; +} + +/* + * Convert a compressed bmap extent record to an uncompressed form. + * This code must be in sync with the routines xfs_bmbt_get_startoff, + * xfs_bmbt_get_startblock, xfs_bmbt_get_blockcount and xfs_bmbt_get_state. + */ +void +xfs_bmbt_get_all( + xfs_bmbt_rec_t *r, + xfs_bmbt_irec_t *s) +{ + int ext_flag; + xfs_exntst_t st; + +#if BMBT_USE_64 + ext_flag = (int)((INT_GET(r->l0, ARCH_CONVERT)) >> (64 - BMBT_EXNTFLAG_BITLEN)); +#if XFS_BIG_FILES + s->br_startoff = ((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; +#else /* !XFS_BIG_FILES */ + { + xfs_dfiloff_t o; + + o = ((xfs_dfiloff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; + ASSERT((o >> 32) == 0); + s->br_startoff = (xfs_fileoff_t)o; + } +#endif /* XFS_BIG_FILES */ +#if XFS_BIG_FILESYSTEMS + s->br_startblock = (((xfs_fsblock_t)INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(9)) << 43) | + (((xfs_fsblock_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); +#else +#ifdef DEBUG + { + xfs_dfsbno_t b; + + b = (((xfs_dfsbno_t)INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(9)) << 43) | + (((xfs_dfsbno_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); + ASSERT((b >> 32) == 0 || ISNULLDSTARTBLOCK(b)); + s->br_startblock = (xfs_fsblock_t)b; + } +#else /* !DEBUG */ + s->br_startblock = (xfs_fsblock_t)(((xfs_dfsbno_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); +#endif /* DEBUG */ +#endif /* XFS_BIG_FILESYSTEMS */ + s->br_blockcount = (xfs_filblks_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK64LO(21)); +#else /* !BMBT_USE_64 */ + ext_flag = (INT_GET(r->l0, ARCH_CONVERT) >> (32 - BMBT_EXNTFLAG_BITLEN)); +#if XFS_BIG_FILES + s->br_startoff = (((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK32LO(32 - BMBT_EXNTFLAG_BITLEN)) << 23) | + (((xfs_fileoff_t)INT_GET(r->l1, ARCH_CONVERT)) >> 9); +#else /* !XFS_BIG_FILES */ +#ifdef DEBUG + { + xfs_dfiloff_t o; + + o = (((xfs_dfiloff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK32LO(32 - BMBT_EXNTFLAG_BITLEN)) << 23) | + (((xfs_dfiloff_t)INT_GET(r->l1, ARCH_CONVERT)) >> 9); + ASSERT((o >> 32) == 0); + s->br_startoff = (xfs_fileoff_t)o; + } +#else /* !DEBUG */ + s->br_startoff = (((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK32LO(32 - BMBT_EXNTFLAG_BITLEN)) << 23) | + (((xfs_fileoff_t)INT_GET(r->l1, ARCH_CONVERT)) >> 9); +#endif /* DEBUG */ +#endif /* XFS_BIG_FILES */ +#if XFS_BIG_FILESYSTEMS + s->br_startblock = + (((xfs_fsblock_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK32LO(9))) << 43) | + (((xfs_fsblock_t)INT_GET(r->l2, ARCH_CONVERT)) << 11) | + (((xfs_fsblock_t)INT_GET(r->l3, ARCH_CONVERT)) >> 21); +#else +#ifdef DEBUG + { + xfs_dfsbno_t b; + + b = (((xfs_dfsbno_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK32LO(9))) << 43) | + (((xfs_dfsbno_t)INT_GET(r->l2, ARCH_CONVERT)) << 11) | + (((xfs_dfsbno_t)INT_GET(r->l3, ARCH_CONVERT)) >> 21); + ASSERT((b >> 32) == 0 || ISNULLDSTARTBLOCK(b)); + s->br_startblock = (xfs_fsblock_t)b; + } +#else /* !DEBUG */ + s->br_startblock = (((xfs_fsblock_t)INT_GET(r->l2, ARCH_CONVERT)) << 11) | + (((xfs_fsblock_t)INT_GET(r->l3, ARCH_CONVERT)) >> 21); +#endif /* DEBUG */ +#endif /* XFS_BIG_FILESYSTEMS */ + s->br_blockcount = (xfs_filblks_t)(INT_GET(r->l3, ARCH_CONVERT) & XFS_MASK32LO(21)); +#endif /* BMBT_USE_64 */ + /* This is xfs_extent_state() in-line */ + if (ext_flag) { + ASSERT(s->br_blockcount != 0); /* saved for DMIG */ + st = XFS_EXT_UNWRITTEN; + } else + st = XFS_EXT_NORM; + s->br_state = st; +} + +/* + * Get the block pointer for the given level of the cursor. + * Fill in the buffer pointer, if applicable. + */ +xfs_bmbt_block_t * +xfs_bmbt_get_block( + xfs_btree_cur_t *cur, + int level, + xfs_buf_t **bpp) +{ + xfs_ifork_t *ifp; + xfs_bmbt_block_t *rval; + + if (level < cur->bc_nlevels - 1) { + *bpp = cur->bc_bufs[level]; + rval = XFS_BUF_TO_BMBT_BLOCK(*bpp); + } else { + *bpp = 0; + ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, + cur->bc_private.b.whichfork); + rval = ifp->if_broot; + } + return rval; +} + +/* + * Extract the blockcount field from a bmap extent record. + */ +xfs_filblks_t +xfs_bmbt_get_blockcount( + xfs_bmbt_rec_t *r) +{ +#if BMBT_USE_64 + return (xfs_filblks_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK64LO(21)); +#else /* !BMBT_USE_64 */ + return (xfs_filblks_t)(INT_GET(r->l3, ARCH_CONVERT) & XFS_MASK32LO(21)); +#endif /* BMBT_USE_64 */ +} + +/* + * Extract the startblock field from a bmap extent record. + */ +xfs_fsblock_t +xfs_bmbt_get_startblock( + xfs_bmbt_rec_t *r) +{ +#if BMBT_USE_64 +#if XFS_BIG_FILESYSTEMS + return (((xfs_fsblock_t)INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(9)) << 43) | + (((xfs_fsblock_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); +#else +#ifdef DEBUG + xfs_dfsbno_t b; + + b = (((xfs_dfsbno_t)INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(9)) << 43) | + (((xfs_dfsbno_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); + ASSERT((b >> 32) == 0 || ISNULLDSTARTBLOCK(b)); + return (xfs_fsblock_t)b; +#else /* !DEBUG */ + return (xfs_fsblock_t)(((xfs_dfsbno_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); +#endif /* DEBUG */ +#endif /* XFS_BIG_FILESYSTEMS */ +#else /* !BMBT_USE_64 */ +#if XFS_BIG_FILESYSTEMS + return (((xfs_fsblock_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK32LO(9))) << 43) | + (((xfs_fsblock_t)INT_GET(r->l2, ARCH_CONVERT)) << 11) | + (((xfs_fsblock_t)INT_GET(r->l3, ARCH_CONVERT)) >> 21); +#else +#ifdef DEBUG + xfs_dfsbno_t b; + + b = (((xfs_dfsbno_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK32LO(9))) << 43) | + (((xfs_dfsbno_t)INT_GET(r->l2, ARCH_CONVERT)) << 11) | + (((xfs_dfsbno_t)INT_GET(r->l3, ARCH_CONVERT)) >> 21); + ASSERT((b >> 32) == 0 || ISNULLDSTARTBLOCK(b)); + return (xfs_fsblock_t)b; +#else /* !DEBUG */ + return (((xfs_fsblock_t)INT_GET(r->l2, ARCH_CONVERT)) << 11) | + (((xfs_fsblock_t)INT_GET(r->l3, ARCH_CONVERT)) >> 21); +#endif /* DEBUG */ +#endif /* XFS_BIG_FILESYSTEMS */ +#endif /* BMBT_USE_64 */ +} + +/* + * Extract the startoff field from a bmap extent record. + */ +xfs_fileoff_t +xfs_bmbt_get_startoff( + xfs_bmbt_rec_t *r) +{ +#if BMBT_USE_64 +#if XFS_BIG_FILES + return ((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; +#else /* !XFS_BIG_FILES */ + xfs_dfiloff_t o; + + o = ((xfs_dfiloff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; + ASSERT((o >> 32) == 0); + return (xfs_fileoff_t)o; +#endif /* XFS_BIG_FILES */ +#else /* !BMBT_USE_64 */ +#if XFS_BIG_FILES + return (((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK32LO(32 - BMBT_EXNTFLAG_BITLEN)) << 23) | + (((xfs_fileoff_t)INT_GET(r->l1, ARCH_CONVERT)) >> 9); +#else /* !XFS_BIG_FILES */ +#ifdef DEBUG + xfs_dfiloff_t o; + + o = (((xfs_dfiloff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK32LO(32 - BMBT_EXNTFLAG_BITLEN)) << 23) | + (((xfs_dfiloff_t)INT_GET(r->l1, ARCH_CONVERT)) >> 9); + ASSERT((o >> 32) == 0); + return (xfs_fileoff_t)o; +#else /* !DEBUG */ + return (((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK32LO(32 - BMBT_EXNTFLAG_BITLEN)) << 23) | + (((xfs_fileoff_t)INT_GET(r->l1, ARCH_CONVERT)) >> 9); +#endif /* DEBUG */ +#endif /* XFS_BIG_FILES */ +#endif /* BMBT_USE_64 */ +} + +xfs_exntst_t +xfs_bmbt_get_state( + xfs_bmbt_rec_t *r) +{ + int ext_flag; + +#if BMBT_USE_64 + ext_flag = (int)((INT_GET(r->l0, ARCH_CONVERT)) >> (64 - BMBT_EXNTFLAG_BITLEN)); +#else /* !BMBT_USE_64 */ + ext_flag = (INT_GET(r->l0, ARCH_CONVERT) >> (32 - BMBT_EXNTFLAG_BITLEN)); +#endif /* BMBT_USE_64 */ + return xfs_extent_state(xfs_bmbt_get_blockcount(r), + ext_flag); +} + + +/* + * Increment cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_bmbt_increment( + xfs_btree_cur_t *cur, + int level, + int *stat) /* success/failure */ +{ + xfs_bmbt_block_t *block; + xfs_buf_t *bp; + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_increment"; +#endif + xfs_fsblock_t fsbno; + int lev; + xfs_mount_t *mp; + xfs_trans_t *tp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, level); + ASSERT(level < cur->bc_nlevels); + if (level < cur->bc_nlevels - 1) + xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); + block = xfs_bmbt_get_block(cur, level, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + if (++cur->bc_ptrs[level] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + if (INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + block = xfs_bmbt_get_block(cur, lev, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, lev, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + if (++cur->bc_ptrs[lev] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) + break; + if (lev < cur->bc_nlevels - 1) + xfs_btree_readahead(cur, lev, XFS_BTCUR_RIGHTRA); + } + if (lev == cur->bc_nlevels) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + tp = cur->bc_tp; + mp = cur->bc_mp; + for (block = xfs_bmbt_get_block(cur, lev, &bp); lev > level; ) { + fsbno = INT_GET(*XFS_BMAP_PTR_IADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufl(mp, tp, fsbno, 0, &bp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_BMBT_BLOCK(bp); + if ((error = xfs_btree_check_lblock(cur, block, lev, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + cur->bc_ptrs[lev] = 1; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +} + +/* + * Insert the current record at the point referenced by cur. + */ +int /* error */ +xfs_bmbt_insert( + xfs_btree_cur_t *cur, + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_insert"; +#endif + int i; + int level; + xfs_fsblock_t nbno; + xfs_btree_cur_t *ncur; + xfs_bmbt_rec_t nrec; + xfs_btree_cur_t *pcur; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + level = 0; + nbno = NULLFSBLOCK; + xfs_bmbt_set_all(&nrec, &cur->bc_rec.b); + ncur = (xfs_btree_cur_t *)0; + pcur = cur; + do { + if ((error = xfs_bmbt_insrec(pcur, level++, &nbno, &nrec, &ncur, + &i))) { + if (pcur != cur) + xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (pcur != cur && (ncur || nbno == NULLFSBLOCK)) { + cur->bc_nlevels = pcur->bc_nlevels; + cur->bc_private.b.allocated += + pcur->bc_private.b.allocated; + pcur->bc_private.b.allocated = 0; + ASSERT((cur->bc_private.b.firstblock != NULLFSBLOCK) || + (cur->bc_private.b.ip->i_d.di_flags & + XFS_DIFLAG_REALTIME)); + cur->bc_private.b.firstblock = + pcur->bc_private.b.firstblock; + ASSERT(cur->bc_private.b.flist == + pcur->bc_private.b.flist); + xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); + } + if (ncur) { + pcur = ncur; + ncur = (xfs_btree_cur_t *)0; + } + } while (nbno != NULLFSBLOCK); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = i; + return 0; +error0: + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; +} + +/* + * Log fields from the btree block header. + */ +void +xfs_bmbt_log_block( + xfs_btree_cur_t *cur, + xfs_buf_t *bp, + int fields) +{ + int first; +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_log_block"; +#endif + int last; + xfs_trans_t *tp; + static const short offsets[] = { + offsetof(xfs_bmbt_block_t, bb_magic), + offsetof(xfs_bmbt_block_t, bb_level), + offsetof(xfs_bmbt_block_t, bb_numrecs), + offsetof(xfs_bmbt_block_t, bb_leftsib), + offsetof(xfs_bmbt_block_t, bb_rightsib), + sizeof(xfs_bmbt_block_t) + }; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGBI(cur, bp, fields); + tp = cur->bc_tp; + if (bp) { + xfs_btree_offsets(fields, offsets, XFS_BB_NUM_BITS, &first, + &last); + xfs_trans_log_buf(tp, bp, first, last); + } else + xfs_trans_log_inode(tp, cur->bc_private.b.ip, + XFS_ILOG_FBROOT(cur->bc_private.b.whichfork)); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); +} + +/* + * Log record values from the btree block. + */ +void +xfs_bmbt_log_recs( + xfs_btree_cur_t *cur, + xfs_buf_t *bp, + int rfirst, + int rlast) +{ + xfs_bmbt_block_t *block; + int first; +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_log_recs"; +#endif + int last; + xfs_bmbt_rec_t *rp; + xfs_trans_t *tp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGBII(cur, bp, rfirst, rlast); + ASSERT(bp); + tp = cur->bc_tp; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + rp = XFS_BMAP_REC_DADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&rp[rfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&rp[rlast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(tp, bp, first, last); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); +} + +int /* error */ +xfs_bmbt_lookup_eq( + xfs_btree_cur_t *cur, + xfs_fileoff_t off, + xfs_fsblock_t bno, + xfs_filblks_t len, + int *stat) /* success/failure */ +{ + cur->bc_rec.b.br_startoff = off; + cur->bc_rec.b.br_startblock = bno; + cur->bc_rec.b.br_blockcount = len; + return xfs_bmbt_lookup(cur, XFS_LOOKUP_EQ, stat); +} + +int /* error */ +xfs_bmbt_lookup_ge( + xfs_btree_cur_t *cur, + xfs_fileoff_t off, + xfs_fsblock_t bno, + xfs_filblks_t len, + int *stat) /* success/failure */ +{ + cur->bc_rec.b.br_startoff = off; + cur->bc_rec.b.br_startblock = bno; + cur->bc_rec.b.br_blockcount = len; + return xfs_bmbt_lookup(cur, XFS_LOOKUP_GE, stat); +} + +int /* error */ +xfs_bmbt_lookup_le( + xfs_btree_cur_t *cur, + xfs_fileoff_t off, + xfs_fsblock_t bno, + xfs_filblks_t len, + int *stat) /* success/failure */ +{ + cur->bc_rec.b.br_startoff = off; + cur->bc_rec.b.br_startblock = bno; + cur->bc_rec.b.br_blockcount = len; + return xfs_bmbt_lookup(cur, XFS_LOOKUP_LE, stat); +} + +/* + * Give the bmap btree a new root block. Copy the old broot contents + * down into a real block and make the broot point to it. + */ +int /* error */ +xfs_bmbt_newroot( + xfs_btree_cur_t *cur, /* btree cursor */ + int *logflags, /* logging flags for inode */ + int *stat) /* return status - 0 fail */ +{ + xfs_alloc_arg_t args; /* allocation arguments */ + xfs_bmbt_block_t *block; /* bmap btree block */ + xfs_buf_t *bp; /* buffer for block */ + xfs_bmbt_block_t *cblock; /* child btree block */ + xfs_bmbt_key_t *ckp; /* child key pointer */ + xfs_bmbt_ptr_t *cpp; /* child ptr pointer */ + int error; /* error return code */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_newroot"; +#endif +#ifdef DEBUG + int i; /* loop counter */ +#endif + xfs_bmbt_key_t *kp; /* pointer to bmap btree key */ + int level; /* btree level */ + xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */ + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + level = cur->bc_nlevels - 1; + block = xfs_bmbt_get_block(cur, level, &bp); + /* + * Copy the root into a real block. + */ + args.mp = cur->bc_mp; + pp = XFS_BMAP_PTR_IADDR(block, 1, cur); + args.tp = cur->bc_tp; + args.fsbno = cur->bc_private.b.firstblock; + args.mod = args.minleft = args.alignment = args.total = args.isfl = + args.userdata = args.minalignslop = 0; + args.minlen = args.maxlen = args.prod = 1; + args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; + if (args.fsbno == NULLFSBLOCK) { +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + args.fsbno = INT_GET(*pp, ARCH_CONVERT); + args.type = XFS_ALLOCTYPE_START_BNO; + } else if (args.wasdel) + args.type = XFS_ALLOCTYPE_FIRST_AG; + else + args.type = XFS_ALLOCTYPE_NEAR_BNO; + if ((error = xfs_alloc_vextent(&args))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (args.fsbno == NULLFSBLOCK) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + ASSERT(args.len == 1); + cur->bc_private.b.firstblock = args.fsbno; + cur->bc_private.b.allocated++; + cur->bc_private.b.ip->i_d.di_nblocks++; + if (XFS_IS_QUOTA_ON(args.mp) && + cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_uquotino && + cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip, + XFS_TRANS_DQ_BCOUNT, 1L); + bp = xfs_btree_get_bufl(args.mp, cur->bc_tp, args.fsbno, 0); + cblock = XFS_BUF_TO_BMBT_BLOCK(bp); + *cblock = *block; + INT_MOD(block->bb_level, ARCH_CONVERT, +1); + INT_SET(block->bb_numrecs, ARCH_CONVERT, 1); + cur->bc_nlevels++; + cur->bc_ptrs[level + 1] = 1; + kp = XFS_BMAP_KEY_IADDR(block, 1, cur); + ckp = XFS_BMAP_KEY_IADDR(cblock, 1, cur); + bcopy(kp, ckp, INT_GET(cblock->bb_numrecs, ARCH_CONVERT) * sizeof(*kp)); + cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(cblock->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(pp[i], ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + bcopy(pp, cpp, INT_GET(cblock->bb_numrecs, ARCH_CONVERT) * sizeof(*pp)); +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, (xfs_bmbt_ptr_t)args.fsbno, + level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + INT_SET(*pp, ARCH_CONVERT, args.fsbno); + xfs_iroot_realloc(cur->bc_private.b.ip, 1 - INT_GET(cblock->bb_numrecs, ARCH_CONVERT), + cur->bc_private.b.whichfork); + xfs_btree_setbuf(cur, level, bp); + /* + * Do all this logging at the end so that + * the root is at the right level. + */ + xfs_bmbt_log_block(cur, bp, XFS_BB_ALL_BITS); + xfs_bmbt_log_keys(cur, bp, 1, INT_GET(cblock->bb_numrecs, ARCH_CONVERT)); + xfs_bmbt_log_ptrs(cur, bp, 1, INT_GET(cblock->bb_numrecs, ARCH_CONVERT)); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *logflags |= + XFS_ILOG_CORE | XFS_ILOG_FBROOT(cur->bc_private.b.whichfork); + *stat = 1; + return 0; +} + +/* + * Set all the fields in a bmap extent record from the uncompressed form. + */ +void +xfs_bmbt_set_all( + xfs_bmbt_rec_t *r, + xfs_bmbt_irec_t *s) +{ + int extent_flag; + + ASSERT((s->br_state == XFS_EXT_NORM) || + (s->br_state == XFS_EXT_UNWRITTEN)); + extent_flag = (s->br_state == XFS_EXT_NORM) ? 0 : 1; +#if XFS_BIG_FILES + ASSERT((s->br_startoff & XFS_MASK64HI(9)) == 0); + ASSERT((s->br_blockcount & XFS_MASK64HI(43)) == 0); +#else /* !XFS_BIG_FILES */ + ASSERT((s->br_blockcount & XFS_MASK32HI(11)) == 0); +#endif /* XFS_BIG_FILES */ +#if XFS_BIG_FILESYSTEMS + ASSERT((s->br_startblock & XFS_MASK64HI(12)) == 0); +#endif /* XFS_BIG_FILESYSTEMS */ +#if BMBT_USE_64 +#if XFS_BIG_FILESYSTEMS + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)s->br_startoff << 9) | + ((xfs_bmbt_rec_base_t)s->br_startblock >> 43)); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | + ((xfs_bmbt_rec_base_t)s->br_blockcount & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); +#else /* !XFS_BIG_FILESYSTEMS */ + if (ISNULLSTARTBLOCK(s->br_startblock)) { + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)s->br_startoff << 9) | + (xfs_bmbt_rec_base_t)XFS_MASK64LO(9)); + INT_SET(r->l1, ARCH_CONVERT, XFS_MASK64HI(11) | + ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | + ((xfs_bmbt_rec_base_t)s->br_blockcount & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } else { + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)s->br_startoff << 9)); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | + ((xfs_bmbt_rec_base_t)s->br_blockcount & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } +#endif /* XFS_BIG_FILESYSTEMS */ +#else /* !BMBT_USE_64 */ + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 31) | + ((xfs_bmbt_rec_base_t)(s->br_startoff >> 23))); + INT_SET(r->l3, ARCH_CONVERT, (((xfs_bmbt_rec_base_t)s->br_startblock) << 21) | + ((xfs_bmbt_rec_base_t)(s->br_blockcount & XFS_MASK32LO(21)))); +#if XFS_BIG_FILESYSTEMS + INT_SET(r->l1, ARCH_CONVERT, (((xfs_bmbt_rec_base_t)s->br_startoff) << 9) | + ((xfs_bmbt_rec_base_t)(s->br_startblock >> 43))); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(s->br_startblock >> 11)); +#else /* !XFS_BIG_FILESYSTEMS */ + if (ISNULLSTARTBLOCK(s->br_startblock)) { + INT_SET(r->l1, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(s->br_startoff << 9) | + (xfs_bmbt_rec_base_t)XFS_MASK32LO(9)); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)XFS_MASK32HI(11) | + (xfs_bmbt_rec_base_t)(s->br_startblock >> 11)); + } else { + INT_SET(r->l1, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(s->br_startoff << 9)); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(s->br_startblock >> 11)); + } +#endif /* XFS_BIG_FILESYSTEMS */ +#endif /* BMBT_USE_64 */ +} + +/* + * Set all the fields in a bmap extent record from the arguments. + */ +void +xfs_bmbt_set_allf( + xfs_bmbt_rec_t *r, + xfs_fileoff_t o, + xfs_fsblock_t b, + xfs_filblks_t c, + xfs_exntst_t v) +{ + int extent_flag; + + ASSERT((v == XFS_EXT_NORM) || (v == XFS_EXT_UNWRITTEN)); + extent_flag = (v == XFS_EXT_NORM) ? 0 : 1; +#if XFS_BIG_FILES + ASSERT((o & XFS_MASK64HI(64-BMBT_STARTOFF_BITLEN)) == 0); + ASSERT((c & XFS_MASK64HI(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); +#else /* !XFS_BIG_FILES */ + ASSERT((c & XFS_MASK32HI(11)) == 0); +#endif /* XFS_BIG_FILES */ +#if XFS_BIG_FILESYSTEMS + ASSERT((b & XFS_MASK64HI(64-BMBT_STARTBLOCK_BITLEN)) == 0); +#endif /* XFS_BIG_FILESYSTEMS */ +#if BMBT_USE_64 +#if XFS_BIG_FILESYSTEMS + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)o << 9) | + ((xfs_bmbt_rec_base_t)b >> 43)); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)b << 21) | + ((xfs_bmbt_rec_base_t)c & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); +#else /* !XFS_BIG_FILESYSTEMS */ + if (ISNULLSTARTBLOCK(b)) { + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)o << 9) | + (xfs_bmbt_rec_base_t)XFS_MASK64LO(9)); + INT_SET(r->l1, ARCH_CONVERT, XFS_MASK64HI(11) | + ((xfs_bmbt_rec_base_t)b << 21) | + ((xfs_bmbt_rec_base_t)c & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } else { + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)o << 9)); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)b << 21) | + ((xfs_bmbt_rec_base_t)c & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } +#endif /* XFS_BIG_FILESYSTEMS */ +#else /* !BMBT_USE_64 */ + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 31) | + ((xfs_bmbt_rec_base_t)(o >> 23))); + INT_SET(r->l3, ARCH_CONVERT, (((xfs_bmbt_rec_base_t)b) << 21) | + ((xfs_bmbt_rec_base_t)(c & XFS_MASK32LO(21)))); +#if XFS_BIG_FILESYSTEMS + INT_SET(r->l1, ARCH_CONVERT, (((xfs_bmbt_rec_base_t)o) << 9) | + ((xfs_bmbt_rec_base_t)(b >> 43))); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(b >> 11)); +#else /* !XFS_BIG_FILESYSTEMS */ + if (ISNULLSTARTBLOCK(b)) { + INT_SET(r->l1, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(o << 9) | + (xfs_bmbt_rec_base_t)XFS_MASK32LO(9)); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)XFS_MASK32HI(11) | + (xfs_bmbt_rec_base_t)(b >> 11)); + } else { + INT_SET(r->l1, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(o << 9)); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(b >> 11)); + } +#endif /* XFS_BIG_FILESYSTEMS */ +#endif /* BMBT_USE_64 */ +} + +/* + * Set the blockcount field in a bmap extent record. + */ +void +xfs_bmbt_set_blockcount( + xfs_bmbt_rec_t *r, + xfs_filblks_t v) +{ +#if XFS_BIG_FILES + ASSERT((v & XFS_MASK64HI(43)) == 0); +#else /* !XFS_BIG_FILES */ + ASSERT((v & XFS_MASK32HI(11)) == 0); +#endif +#if BMBT_USE_64 + INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64HI(43)) | + (xfs_bmbt_rec_base_t)(v & XFS_MASK64LO(21))); +#else /* !BMBT_USE_64 */ + INT_SET(r->l3, ARCH_CONVERT, (INT_GET(r->l3, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK32HI(11)) | + ((xfs_bmbt_rec_base_t)v & XFS_MASK32LO(21))); +#endif /* BMBT_USE_64 */ +} + +/* + * Set the startblock field in a bmap extent record. + */ +void +xfs_bmbt_set_startblock( + xfs_bmbt_rec_t *r, + xfs_fsblock_t v) +{ +#if XFS_BIG_FILESYSTEMS + ASSERT((v & XFS_MASK64HI(12)) == 0); +#endif /* XFS_BIG_FILESYSTEMS */ +#if BMBT_USE_64 +#if XFS_BIG_FILESYSTEMS + INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64HI(55)) | + (xfs_bmbt_rec_base_t)(v >> 43)); + INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)) | + (xfs_bmbt_rec_base_t)(v << 21)); +#else /* !XFS_BIG_FILESYSTEMS */ + if (ISNULLSTARTBLOCK(v)) { + INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) | (xfs_bmbt_rec_base_t)XFS_MASK64LO(9))); + INT_SET(r->l1, ARCH_CONVERT, (xfs_bmbt_rec_base_t)XFS_MASK64HI(11) | + ((xfs_bmbt_rec_base_t)v << 21) | + (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } else { + INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & ~(xfs_bmbt_rec_base_t)XFS_MASK64LO(9))); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)v << 21) | + (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } +#endif /* XFS_BIG_FILESYSTEMS */ +#else /* !BMBT_USE_64 */ +#if XFS_BIG_FILESYSTEMS + INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK32HI(23)) | (xfs_bmbt_rec_base_t)(v >> 43)); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(v >> 11)); +#else /* !XFS_BIG_FILESYSTEMS */ + if (ISNULLSTARTBLOCK(v)) { + INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) | XFS_MASK32LO(9))); + INT_SET(r->l2, ARCH_CONVERT, XFS_MASK32HI(11) | (xfs_bmbt_rec_base_t)(v >> 11)); + } else { + INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) & ~XFS_MASK32LO(9))); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(v >> 11)); + } +#endif /* XFS_BIG_FILESYSTEMS */ + INT_SET(r->l3, ARCH_CONVERT, (INT_GET(r->l3, ARCH_CONVERT) & XFS_MASK32LO(21)) | + (((xfs_bmbt_rec_base_t)v) << 21)); +#endif /* BMBT_USE_64 */ +} + +/* + * Set the startoff field in a bmap extent record. + */ +void +xfs_bmbt_set_startoff( + xfs_bmbt_rec_t *r, + xfs_fileoff_t v) +{ +#if XFS_BIG_FILES + ASSERT((v & XFS_MASK64HI(9)) == 0); +#endif /* XFS_BIG_FILES */ +#if BMBT_USE_64 + INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t) XFS_MASK64HI(1)) | + ((xfs_bmbt_rec_base_t)v << 9) | + (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(9))); +#else /* !BMBT_USE_64 */ + INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t) XFS_MASK32HI(1)) | + (xfs_bmbt_rec_base_t)(v >> 23)); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)v << 9) | + (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK32LO(9))); +#endif /* BMBT_USE_64 */ +} + +/* + * Set the extent state field in a bmap extent record. + */ +void +xfs_bmbt_set_state( + xfs_bmbt_rec_t *r, + xfs_exntst_t v) +{ + ASSERT(v == XFS_EXT_NORM || v == XFS_EXT_UNWRITTEN); + if (v == XFS_EXT_NORM) +#if BMBT_USE_64 + INT_SET(r->l0, ARCH_CONVERT, INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)); +#else /* !BMBT_USE_64 */ + INT_SET(r->l0, ARCH_CONVERT, INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK32LO(32 - BMBT_EXNTFLAG_BITLEN)); +#endif /* BMBT_USE_64 */ + else +#if BMBT_USE_64 + INT_SET(r->l0, ARCH_CONVERT, INT_GET(r->l0, ARCH_CONVERT) | XFS_MASK64HI(BMBT_EXNTFLAG_BITLEN)); +#else /* !BMBT_USE_64 */ + INT_SET(r->l0, ARCH_CONVERT, INT_GET(r->l0, ARCH_CONVERT) | XFS_MASK32HI(BMBT_EXNTFLAG_BITLEN)); +#endif /* BMBT_USE_64 */ +} + +/* + * Convert in-memory form of btree root to on-disk form. + */ +void +xfs_bmbt_to_bmdr( + xfs_bmbt_block_t *rblock, + int rblocklen, + xfs_bmdr_block_t *dblock, + int dblocklen) +{ + int dmxr; + xfs_bmbt_key_t *fkp; + xfs_bmbt_ptr_t *fpp; + xfs_bmbt_key_t *tkp; + xfs_bmbt_ptr_t *tpp; + + ASSERT(INT_GET(rblock->bb_magic, ARCH_CONVERT) == XFS_BMAP_MAGIC); + ASSERT(INT_GET(rblock->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO); + ASSERT(INT_GET(rblock->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO); + ASSERT(INT_GET(rblock->bb_level, ARCH_CONVERT) > 0); + dblock->bb_level = rblock->bb_level; /* both in on-disk format */ + dblock->bb_numrecs = rblock->bb_numrecs;/* both in on-disk format */ + dmxr = (int)XFS_BTREE_BLOCK_MAXRECS(dblocklen, xfs_bmdr, 0); + fkp = XFS_BMAP_BROOT_KEY_ADDR(rblock, 1, rblocklen); + tkp = XFS_BTREE_KEY_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + fpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen); + tpp = XFS_BTREE_PTR_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + dmxr = INT_GET(dblock->bb_numrecs, ARCH_CONVERT); + bcopy(fkp, tkp, sizeof(*fkp) * dmxr); + bcopy(fpp, tpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */ +} + +/* + * Update the record to the passed values. + */ +int +xfs_bmbt_update( + xfs_btree_cur_t *cur, + xfs_fileoff_t off, + xfs_fsblock_t bno, + xfs_filblks_t len, + xfs_exntst_t state) +{ + xfs_bmbt_block_t *block; + xfs_buf_t *bp; + int error; +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_update"; +#endif + xfs_bmbt_key_t key; + int ptr; + xfs_bmbt_rec_t *rp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGFFFI(cur, (xfs_dfiloff_t)off, (xfs_dfsbno_t)bno, + (xfs_dfilblks_t)len, (int)state); + block = xfs_bmbt_get_block(cur, 0, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, 0, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + ptr = cur->bc_ptrs[0]; + rp = XFS_BMAP_REC_IADDR(block, ptr, cur); + xfs_bmbt_set_allf(rp, off, bno, len, state); + xfs_bmbt_log_recs(cur, bp, ptr, ptr); + if (ptr > 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; + } + INT_SET(key.br_startoff, ARCH_CONVERT, off); + if ((error = xfs_bmbt_updkey(cur, &key, 1))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; +} + +/* + * Check an extent list, which has just been read, for + * any bit in the extent flag field. ASSERT on debug + * kernels, as this condition should not occur. + * Return an error condition (1) if any flags found, + * otherwise return 0. + */ +int +xfs_check_nostate_extents( + xfs_bmbt_rec_t *ep, + xfs_extnum_t num) +{ + for (; num > 0; num--, ep++) { + if ( +#if BMBT_USE_64 + ((INT_GET(ep->l0, ARCH_CONVERT)) >> (64 - BMBT_EXNTFLAG_BITLEN)) != 0 +#else /* !BMBT_USE_64 */ + ((INT_GET(ep->l0, ARCH_CONVERT)) >> (32 - BMBT_EXNTFLAG_BITLEN)) != 0 +#endif /* BMBT_USE_64 */ + ) { + ASSERT(0); + return 1; + } + } + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_btree.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_btree.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_btree.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_btree.c Sun May 27 19:02:18 2001 @@ -0,0 +1,883 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * This file contains common code for the space manager's btree implementations. + */ + +#include + +/* + * Cursor allocation zone. + */ +xfs_zone_t *xfs_btree_cur_zone; + +/* + * Btree magic numbers. + */ +const __uint32_t xfs_magics[XFS_BTNUM_MAX] = +{ + XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC +}; + +/* + * Prototypes for internal routines. + */ + +/* + * Checking routine: return maxrecs for the block. + */ +STATIC int /* number of records fitting in block */ +xfs_btree_maxrecs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_block_t *block);/* generic btree block pointer */ + +/* + * Internal routines. + */ + +/* + * Checking routine: return maxrecs for the block. + */ +STATIC int /* number of records fitting in block */ +xfs_btree_maxrecs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_block_t *block) /* generic btree block pointer */ +{ + switch (cur->bc_btnum) { + case XFS_BTNUM_BNO: + case XFS_BTNUM_CNT: + return (int)XFS_ALLOC_BLOCK_MAXRECS(INT_GET(block->bb_h.bb_level, ARCH_CONVERT), cur); + case XFS_BTNUM_BMAP: + return (int)XFS_BMAP_BLOCK_IMAXRECS(INT_GET(block->bb_h.bb_level, ARCH_CONVERT), cur); + case XFS_BTNUM_INO: + return (int)XFS_INOBT_BLOCK_MAXRECS(INT_GET(block->bb_h.bb_level, ARCH_CONVERT), cur); + default: + ASSERT(0); + return 0; + } +} + +/* + * External routines. + */ + +#ifdef DEBUG +/* + * Debug routine: check that block header is ok. + */ +void +xfs_btree_check_block( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_block_t *block, /* generic btree block pointer */ + int level, /* level of the btree block */ + xfs_buf_t *bp) /* buffer containing block, if any */ +{ + if (XFS_BTREE_LONG_PTRS(cur->bc_btnum)) + xfs_btree_check_lblock(cur, (xfs_btree_lblock_t *)block, level, + bp); + else + xfs_btree_check_sblock(cur, (xfs_btree_sblock_t *)block, level, + bp); +} + +/* + * Debug routine: check that keys are in the right order. + */ +void +xfs_btree_check_key( + xfs_btnum_t btnum, /* btree identifier */ + void *ak1, /* pointer to left (lower) key */ + void *ak2) /* pointer to right (higher) key */ +{ + switch (btnum) { + case XFS_BTNUM_BNO: { + xfs_alloc_key_t *k1; + xfs_alloc_key_t *k2; + + k1 = ak1; + k2 = ak2; + ASSERT(INT_GET(k1->ar_startblock, ARCH_CONVERT) < INT_GET(k2->ar_startblock, ARCH_CONVERT)); + break; + } + case XFS_BTNUM_CNT: { + xfs_alloc_key_t *k1; + xfs_alloc_key_t *k2; + + k1 = ak1; + k2 = ak2; + ASSERT(INT_GET(k1->ar_blockcount, ARCH_CONVERT) < INT_GET(k2->ar_blockcount, ARCH_CONVERT) || + (INT_GET(k1->ar_blockcount, ARCH_CONVERT) == INT_GET(k2->ar_blockcount, ARCH_CONVERT) && + INT_GET(k1->ar_startblock, ARCH_CONVERT) < INT_GET(k2->ar_startblock, ARCH_CONVERT))); + break; + } + case XFS_BTNUM_BMAP: { + xfs_bmbt_key_t *k1; + xfs_bmbt_key_t *k2; + + k1 = ak1; + k2 = ak2; + ASSERT(INT_GET(k1->br_startoff, ARCH_CONVERT) < INT_GET(k2->br_startoff, ARCH_CONVERT)); + break; + } + case XFS_BTNUM_INO: { + xfs_inobt_key_t *k1; + xfs_inobt_key_t *k2; + + k1 = ak1; + k2 = ak2; + ASSERT(INT_GET(k1->ir_startino, ARCH_CONVERT) < INT_GET(k2->ir_startino, ARCH_CONVERT)); + break; + } + default: + ASSERT(0); + } +} +#endif /* DEBUG */ + +/* + * Checking routine: check that long form block header is ok. + */ +/* ARGSUSED */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_lblock( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_lblock_t *block, /* btree long form block pointer */ + int level, /* level of the btree block */ + xfs_buf_t *bp) /* buffer for block, if any */ +{ + int lblock_ok; /* block passes checks */ + xfs_mount_t *mp; /* file system mount point */ + + mp = cur->bc_mp; + lblock_ok = + INT_GET(block->bb_magic, ARCH_CONVERT) == xfs_magics[cur->bc_btnum] && + INT_GET(block->bb_level, ARCH_CONVERT) == level && + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= + xfs_btree_maxrecs(cur, (xfs_btree_block_t *)block) && + INT_GET(block->bb_leftsib, ARCH_CONVERT) != 0 && + (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO || + XFS_FSB_SANITY_CHECK(mp, INT_GET(block->bb_leftsib, ARCH_CONVERT))) && + INT_GET(block->bb_rightsib, ARCH_CONVERT) != 0 && + (INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO || + XFS_FSB_SANITY_CHECK(mp, INT_GET(block->bb_rightsib, ARCH_CONVERT))); + if (XFS_TEST_ERROR(!lblock_ok, mp, XFS_ERRTAG_BTREE_CHECK_LBLOCK, + XFS_RANDOM_BTREE_CHECK_LBLOCK)) { + if (bp) + xfs_buftrace("LBTREE ERROR", bp); + return XFS_ERROR(EFSCORRUPTED); + } + return 0; +} + +/* + * Checking routine: check that (long) pointer is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_lptr( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_dfsbno_t ptr, /* btree block disk address */ + int level) /* btree block level */ +{ + xfs_mount_t *mp; /* file system mount point */ + + mp = cur->bc_mp; + XFS_WANT_CORRUPTED_RETURN( + level > 0 && + ptr != NULLDFSBNO && + XFS_FSB_SANITY_CHECK(mp, ptr)); + return 0; +} + +#ifdef DEBUG +/* + * Debug routine: check that records are in the right order. + */ +void +xfs_btree_check_rec( + xfs_btnum_t btnum, /* btree identifier */ + void *ar1, /* pointer to left (lower) record */ + void *ar2) /* pointer to right (higher) record */ +{ + switch (btnum) { + case XFS_BTNUM_BNO: { + xfs_alloc_rec_t *r1; + xfs_alloc_rec_t *r2; + + r1 = ar1; + r2 = ar2; + ASSERT(INT_GET(r1->ar_startblock, ARCH_CONVERT) + INT_GET(r1->ar_blockcount, ARCH_CONVERT) <= + INT_GET(r2->ar_startblock, ARCH_CONVERT)); + break; + } + case XFS_BTNUM_CNT: { + xfs_alloc_rec_t *r1; + xfs_alloc_rec_t *r2; + + r1 = ar1; + r2 = ar2; + ASSERT(INT_GET(r1->ar_blockcount, ARCH_CONVERT) < INT_GET(r2->ar_blockcount, ARCH_CONVERT) || + (INT_GET(r1->ar_blockcount, ARCH_CONVERT) == INT_GET(r2->ar_blockcount, ARCH_CONVERT) && + INT_GET(r1->ar_startblock, ARCH_CONVERT) < INT_GET(r2->ar_startblock, ARCH_CONVERT))); + break; + } + case XFS_BTNUM_BMAP: { + xfs_bmbt_rec_t *r1; + xfs_bmbt_rec_t *r2; + + r1 = ar1; + r2 = ar2; + ASSERT(xfs_bmbt_get_startoff(r1) + + xfs_bmbt_get_blockcount(r1) <= + xfs_bmbt_get_startoff(r2)); + break; + } + case XFS_BTNUM_INO: { + xfs_inobt_rec_t *r1; + xfs_inobt_rec_t *r2; + + r1 = ar1; + r2 = ar2; + ASSERT(INT_GET(r1->ir_startino, ARCH_CONVERT) + XFS_INODES_PER_CHUNK <= + INT_GET(r2->ir_startino, ARCH_CONVERT)); + break; + } + default: + ASSERT(0); + } +} +#endif /* DEBUG */ + +/* + * Checking routine: check that block header is ok. + */ +/* ARGSUSED */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_sblock( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_sblock_t *block, /* btree short form block pointer */ + int level, /* level of the btree block */ + xfs_buf_t *bp) /* buffer containing block */ +{ + xfs_buf_t *agbp; /* buffer for ag. freespace struct */ + xfs_agf_t *agf; /* ag. freespace structure */ + xfs_agblock_t agflen; /* native ag. freespace length */ + int sblock_ok; /* block passes checks */ + + agbp = cur->bc_private.a.agbp; + agf = XFS_BUF_TO_AGF(agbp); + agflen = INT_GET(agf->agf_length, ARCH_CONVERT); + sblock_ok = + INT_GET(block->bb_magic, ARCH_CONVERT) == xfs_magics[cur->bc_btnum] && + INT_GET(block->bb_level, ARCH_CONVERT) == level && + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= + xfs_btree_maxrecs(cur, (xfs_btree_block_t *)block) && + (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK || + INT_GET(block->bb_leftsib, ARCH_CONVERT) < agflen) && + INT_GET(block->bb_leftsib, ARCH_CONVERT) != 0 && + (INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK || + INT_GET(block->bb_rightsib, ARCH_CONVERT) < agflen) && + INT_GET(block->bb_rightsib, ARCH_CONVERT) != 0; + if (XFS_TEST_ERROR(!sblock_ok, cur->bc_mp, + XFS_ERRTAG_BTREE_CHECK_SBLOCK, + XFS_RANDOM_BTREE_CHECK_SBLOCK)) { + if (bp) + xfs_buftrace("SBTREE ERROR", bp); + return XFS_ERROR(EFSCORRUPTED); + } + return 0; +} + +/* + * Checking routine: check that (short) pointer is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_sptr( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t ptr, /* btree block disk address */ + int level) /* btree block level */ +{ + xfs_buf_t *agbp; /* buffer for ag. freespace struct */ + xfs_agf_t *agf; /* ag. freespace structure */ + + agbp = cur->bc_private.a.agbp; + agf = XFS_BUF_TO_AGF(agbp); + XFS_WANT_CORRUPTED_RETURN( + level > 0 && + ptr != NULLAGBLOCK && ptr != 0 && + ptr < INT_GET(agf->agf_length, ARCH_CONVERT)); + return 0; +} + +/* + * Delete the btree cursor. + */ +void +xfs_btree_del_cursor( + xfs_btree_cur_t *cur, /* btree cursor */ + int error) /* del because of error */ +{ + int i; /* btree level */ + + /* + * Clear the buffer pointers, and release the buffers. + * If we're doing this in the face of an error, we + * need to make sure to inspect all of the entries + * in the bc_bufs array for buffers to be unlocked. + * This is because some of the btree code works from + * level n down to 0, and if we get an error along + * the way we won't have initialized all the entries + * down to 0. + */ + for (i = 0; i < cur->bc_nlevels; i++) { + if (cur->bc_bufs[i]) + xfs_btree_setbuf(cur, i, NULL); + else if (!error) + break; + } + /* + * Can't free a bmap cursor without having dealt with the + * allocated indirect blocks' accounting. + */ + ASSERT(cur->bc_btnum != XFS_BTNUM_BMAP || + cur->bc_private.b.allocated == 0); + /* + * Free the cursor. + */ + kmem_zone_free(xfs_btree_cur_zone, cur); +} + +/* + * Duplicate the btree cursor. + * Allocate a new one, copy the record, re-get the buffers. + */ +int /* error */ +xfs_btree_dup_cursor( + xfs_btree_cur_t *cur, /* input cursor */ + xfs_btree_cur_t **ncur) /* output cursor */ +{ + xfs_buf_t *bp; /* btree block's buffer pointer */ + int error; /* error return value */ + int i; /* level number of btree block */ + xfs_mount_t *mp; /* mount structure for filesystem */ + xfs_btree_cur_t *new; /* new cursor value */ + xfs_trans_t *tp; /* transaction pointer, can be NULL */ + + tp = cur->bc_tp; + mp = cur->bc_mp; + /* + * Allocate a new cursor like the old one. + */ + new = xfs_btree_init_cursor(mp, tp, cur->bc_private.a.agbp, + cur->bc_private.a.agno, cur->bc_btnum, cur->bc_private.b.ip, + cur->bc_private.b.whichfork); + /* + * Copy the record currently in the cursor. + */ + new->bc_rec = cur->bc_rec; + /* + * For each level current, re-get the buffer and copy the ptr value. + */ + for (i = 0; i < new->bc_nlevels; i++) { + new->bc_ptrs[i] = cur->bc_ptrs[i]; + new->bc_ra[i] = cur->bc_ra[i]; + if ((bp = cur->bc_bufs[i])) { + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, + XFS_BUF_ADDR(bp), mp->m_bsize, 0, &bp))) { + xfs_btree_del_cursor(new, error); + *ncur = NULL; + return error; + } + new->bc_bufs[i] = bp; + ASSERT(bp); + ASSERT(!XFS_BUF_GETERROR(bp)); + } else + new->bc_bufs[i] = NULL; + } + /* + * For bmap btrees, copy the firstblock, flist, and flags values, + * since init cursor doesn't get them. + */ + if (new->bc_btnum == XFS_BTNUM_BMAP) { + new->bc_private.b.firstblock = cur->bc_private.b.firstblock; + new->bc_private.b.flist = cur->bc_private.b.flist; + new->bc_private.b.flags = cur->bc_private.b.flags; + } + *ncur = new; + return 0; +} + +/* + * Change the cursor to point to the first record at the given level. + * Other levels are unaffected. + */ +int /* success=1, failure=0 */ +xfs_btree_firstrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level) /* level to change */ +{ + xfs_btree_block_t *block; /* generic btree block pointer */ + xfs_buf_t *bp; /* buffer containing block */ + + /* + * Get the block pointer for this level. + */ + block = xfs_btree_get_block(cur, level, &bp); + xfs_btree_check_block(cur, block, level, bp); + /* + * It's empty, there is no such record. + */ + if (INT_GET(block->bb_h.bb_numrecs, ARCH_CONVERT) == 0) + return 0; + /* + * Set the ptr value to 1, that's the first record/key. + */ + cur->bc_ptrs[level] = 1; + return 1; +} + +/* + * Retrieve the block pointer from the cursor at the given level. + * This may be a bmap btree root or from a buffer. + */ +xfs_btree_block_t * /* generic btree block pointer */ +xfs_btree_get_block( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree */ + xfs_buf_t **bpp) /* buffer containing the block */ +{ + xfs_btree_block_t *block; /* return value */ + xfs_buf_t *bp; /* return buffer */ + xfs_ifork_t *ifp; /* inode fork pointer */ + int whichfork; /* data or attr fork */ + + if (cur->bc_btnum == XFS_BTNUM_BMAP && level == cur->bc_nlevels - 1) { + whichfork = cur->bc_private.b.whichfork; + ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, whichfork); + block = (xfs_btree_block_t *)ifp->if_broot; + bp = NULL; + } else { + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_BLOCK(bp); + } + ASSERT(block != NULL); + *bpp = bp; + return block; +} + +/* + * Get a buffer for the block, return it with no data read. + * Long-form addressing. + */ +xfs_buf_t * /* buffer for fsbno */ +xfs_btree_get_bufl( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_fsblock_t fsbno, /* file system block number */ + uint lock) /* lock flags for get_buf */ +{ + xfs_buf_t *bp; /* buffer pointer (return value) */ + xfs_daddr_t d; /* real disk block address */ + + ASSERT(fsbno != NULLFSBLOCK); + d = XFS_FSB_TO_DADDR(mp, fsbno); + bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock); + ASSERT(bp); + ASSERT(!XFS_BUF_GETERROR(bp)); + return bp; +} + +/* + * Get a buffer for the block, return it with no data read. + * Short-form addressing. + */ +xfs_buf_t * /* buffer for agno/agbno */ +xfs_btree_get_bufs( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + uint lock) /* lock flags for get_buf */ +{ + xfs_buf_t *bp; /* buffer pointer (return value) */ + xfs_daddr_t d; /* real disk block address */ + + ASSERT(agno != NULLAGNUMBER); + ASSERT(agbno != NULLAGBLOCK); + d = XFS_AGB_TO_DADDR(mp, agno, agbno); + bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock); + ASSERT(bp); + ASSERT(!XFS_BUF_GETERROR(bp)); + return bp; +} + +/* + * Allocate a new btree cursor. + * The cursor is either for allocation (A) or bmap (B) or inodes (I). + */ +xfs_btree_cur_t * /* new btree cursor */ +xfs_btree_init_cursor( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* (A only) buffer for agf structure */ + /* (I only) buffer for agi structure */ + xfs_agnumber_t agno, /* (AI only) allocation group number */ + xfs_btnum_t btnum, /* btree identifier */ + xfs_inode_t *ip, /* (B only) inode owning the btree */ + int whichfork) /* (B only) data or attr fork */ +{ + xfs_agf_t *agf; /* (A) allocation group freespace */ + xfs_agi_t *agi; /* (I) allocation group inodespace */ + xfs_btree_cur_t *cur; /* return value */ + xfs_ifork_t *ifp; /* (I) inode fork pointer */ + int nlevels=0; /* number of levels in the btree */ + + ASSERT(xfs_btree_cur_zone != NULL); + /* + * Allocate a new cursor. + */ + cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); + /* + * Deduce the number of btree levels from the arguments. + */ + switch (btnum) { + case XFS_BTNUM_BNO: + case XFS_BTNUM_CNT: + agf = XFS_BUF_TO_AGF(agbp); + nlevels = INT_GET(agf->agf_levels[btnum], ARCH_CONVERT); + break; + case XFS_BTNUM_BMAP: + ifp = XFS_IFORK_PTR(ip, whichfork); + nlevels = INT_GET(ifp->if_broot->bb_level, ARCH_CONVERT) + 1; + break; + case XFS_BTNUM_INO: + agi = XFS_BUF_TO_AGI(agbp); + nlevels = INT_GET(agi->agi_level, ARCH_CONVERT); + break; + default: + ASSERT(0); + } + /* + * Fill in the common fields. + */ + cur->bc_tp = tp; + cur->bc_mp = mp; + cur->bc_nlevels = nlevels; + cur->bc_btnum = btnum; + cur->bc_blocklog = mp->m_sb.sb_blocklog; + /* + * Fill in private fields. + */ + switch (btnum) { + case XFS_BTNUM_BNO: + case XFS_BTNUM_CNT: + /* + * Allocation btree fields. + */ + cur->bc_private.a.agbp = agbp; + cur->bc_private.a.agno = agno; + break; + case XFS_BTNUM_BMAP: + /* + * Bmap btree fields. + */ + cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork); + cur->bc_private.b.ip = ip; + cur->bc_private.b.firstblock = NULLFSBLOCK; + cur->bc_private.b.flist = NULL; + cur->bc_private.b.allocated = 0; + cur->bc_private.b.flags = 0; + cur->bc_private.b.whichfork = whichfork; + break; + case XFS_BTNUM_INO: + /* + * Inode allocation btree fields. + */ + cur->bc_private.i.agbp = agbp; + cur->bc_private.i.agno = agno; + break; + default: + ASSERT(0); + } + return cur; +} + +/* + * Check for the cursor referring to the last block at the given level. + */ +int /* 1=is last block, 0=not last block */ +xfs_btree_islastblock( + xfs_btree_cur_t *cur, /* btree cursor */ + int level) /* level to check */ +{ + xfs_btree_block_t *block; /* generic btree block pointer */ + xfs_buf_t *bp; /* buffer containing block */ + + block = xfs_btree_get_block(cur, level, &bp); + xfs_btree_check_block(cur, block, level, bp); + if (XFS_BTREE_LONG_PTRS(cur->bc_btnum)) + return INT_GET(block->bb_u.l.bb_rightsib, ARCH_CONVERT) == NULLDFSBNO; + else + return INT_GET(block->bb_u.s.bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK; +} + +/* + * Change the cursor to point to the last record in the current block + * at the given level. Other levels are unaffected. + */ +int /* success=1, failure=0 */ +xfs_btree_lastrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level) /* level to change */ +{ + xfs_btree_block_t *block; /* generic btree block pointer */ + xfs_buf_t *bp; /* buffer containing block */ + + /* + * Get the block pointer for this level. + */ + block = xfs_btree_get_block(cur, level, &bp); + xfs_btree_check_block(cur, block, level, bp); + /* + * It's empty, there is no such record. + */ + if (INT_GET(block->bb_h.bb_numrecs, ARCH_CONVERT) == 0) + return 0; + /* + * Set the ptr value to numrecs, that's the last record/key. + */ + cur->bc_ptrs[level] = INT_GET(block->bb_h.bb_numrecs, ARCH_CONVERT); + return 1; +} + +/* + * Compute first and last byte offsets for the fields given. + * Interprets the offsets table, which contains struct field offsets. + */ +void +xfs_btree_offsets( + __int64_t fields, /* bitmask of fields */ + const short *offsets, /* table of field offsets */ + int nbits, /* number of bits to inspect */ + int *first, /* output: first byte offset */ + int *last) /* output: last byte offset */ +{ + int i; /* current bit number */ + __int64_t imask; /* mask for current bit number */ + + ASSERT(fields != 0); + /* + * Find the lowest bit, so the first byte offset. + */ + for (i = 0, imask = 1LL; ; i++, imask <<= 1) { + if (imask & fields) { + *first = offsets[i]; + break; + } + } + /* + * Find the highest bit, so the last byte offset. + */ + for (i = nbits - 1, imask = 1LL << i; ; i--, imask >>= 1) { + if (imask & fields) { + *last = offsets[i + 1] - 1; + break; + } + } +} + +/* + * Get a buffer for the block, return it read in. + * Long-form addressing. + */ +int /* error */ +xfs_btree_read_bufl( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_fsblock_t fsbno, /* file system block number */ + uint lock, /* lock flags for read_buf */ + xfs_buf_t **bpp, /* buffer for fsbno */ + int refval) /* ref count value for buffer */ +{ + xfs_buf_t *bp; /* return value */ + xfs_daddr_t d; /* real disk block address */ + int error; + + ASSERT(fsbno != NULLFSBLOCK); + d = XFS_FSB_TO_DADDR(mp, fsbno); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, + mp->m_bsize, lock, &bp))) { + return error; + } + ASSERT(!bp || !XFS_BUF_GETERROR(bp)); + if (bp != NULL) { + XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, refval); + } + *bpp = bp; + return 0; +} + +/* + * Get a buffer for the block, return it read in. + * Short-form addressing. + */ +int /* error */ +xfs_btree_read_bufs( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + uint lock, /* lock flags for read_buf */ + xfs_buf_t **bpp, /* buffer for agno/agbno */ + int refval) /* ref count value for buffer */ +{ + xfs_buf_t *bp; /* return value */ + xfs_daddr_t d; /* real disk block address */ + int error; + + ASSERT(agno != NULLAGNUMBER); + ASSERT(agbno != NULLAGBLOCK); + d = XFS_AGB_TO_DADDR(mp, agno, agbno); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, + mp->m_bsize, lock, &bp))) { + return error; + } + ASSERT(!bp || !XFS_BUF_GETERROR(bp)); + if (bp != NULL) { + switch (refval) { + case XFS_ALLOC_BTREE_REF: + XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, refval); + break; + case XFS_INO_BTREE_REF: + XFS_BUF_SET_VTYPE_REF(bp, B_FS_INOMAP, refval); + break; + } + } + *bpp = bp; + return 0; +} + +/* + * Read-ahead btree blocks, at the given level. + * Bits in lr are set from XFS_BTCUR_{LEFT,RIGHT}RA. + */ +int +xfs_btree_readahead_core( + xfs_btree_cur_t *cur, /* btree cursor */ + int lev, /* level in btree */ + int lr) /* left/right bits */ +{ + xfs_alloc_block_t *a; + xfs_bmbt_block_t *b; + xfs_inobt_block_t *i; + int rval = 0; + + ASSERT(cur->bc_bufs[lev] != NULL); + cur->bc_ra[lev] |= lr; + switch (cur->bc_btnum) { + case XFS_BTNUM_BNO: + case XFS_BTNUM_CNT: + a = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[lev]); + if ((lr & XFS_BTCUR_LEFTRA) && INT_GET(a->bb_leftsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, + INT_GET(a->bb_leftsib, ARCH_CONVERT), 1); + rval++; + } + if ((lr & XFS_BTCUR_RIGHTRA) && INT_GET(a->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, + INT_GET(a->bb_rightsib, ARCH_CONVERT), 1); + rval++; + } + break; + case XFS_BTNUM_BMAP: + b = XFS_BUF_TO_BMBT_BLOCK(cur->bc_bufs[lev]); + if ((lr & XFS_BTCUR_LEFTRA) && INT_GET(b->bb_leftsib, ARCH_CONVERT) != NULLDFSBNO) { + xfs_btree_reada_bufl(cur->bc_mp, INT_GET(b->bb_leftsib, ARCH_CONVERT), 1); + rval++; + } + if ((lr & XFS_BTCUR_RIGHTRA) && INT_GET(b->bb_rightsib, ARCH_CONVERT) != NULLDFSBNO) { + xfs_btree_reada_bufl(cur->bc_mp, INT_GET(b->bb_rightsib, ARCH_CONVERT), 1); + rval++; + } + break; + case XFS_BTNUM_INO: + i = XFS_BUF_TO_INOBT_BLOCK(cur->bc_bufs[lev]); + if ((lr & XFS_BTCUR_LEFTRA) && INT_GET(i->bb_leftsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.i.agno, + INT_GET(i->bb_leftsib, ARCH_CONVERT), 1); + rval++; + } + if ((lr & XFS_BTCUR_RIGHTRA) && INT_GET(i->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.i.agno, + INT_GET(i->bb_rightsib, ARCH_CONVERT), 1); + rval++; + } + break; + default: + ASSERT(0); + } + return rval; +} + +/* + * Set the buffer for level "lev" in the cursor to bp, releasing + * any previous buffer. + */ +void +xfs_btree_setbuf( + xfs_btree_cur_t *cur, /* btree cursor */ + int lev, /* level in btree */ + xfs_buf_t *bp) /* new buffer to set */ +{ + xfs_btree_block_t *b; /* btree block */ + xfs_buf_t *obp; /* old buffer pointer */ + + obp = cur->bc_bufs[lev]; + if (obp) + xfs_trans_brelse(cur->bc_tp, obp); + cur->bc_bufs[lev] = bp; + cur->bc_ra[lev] = 0; + if (!bp) + return; + b = XFS_BUF_TO_BLOCK(bp); + if (XFS_BTREE_LONG_PTRS(cur->bc_btnum)) { + if (INT_GET(b->bb_u.l.bb_leftsib, ARCH_CONVERT) == NULLDFSBNO) + cur->bc_ra[lev] |= XFS_BTCUR_LEFTRA; + if (INT_GET(b->bb_u.l.bb_rightsib, ARCH_CONVERT) == NULLDFSBNO) + cur->bc_ra[lev] |= XFS_BTCUR_RIGHTRA; + } else { + if (INT_GET(b->bb_u.s.bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK) + cur->bc_ra[lev] |= XFS_BTCUR_LEFTRA; + if (INT_GET(b->bb_u.s.bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK) + cur->bc_ra[lev] |= XFS_BTCUR_RIGHTRA; + } +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_da_btree.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_da_btree.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_da_btree.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_da_btree.c Mon Apr 16 17:53:46 2001 @@ -0,0 +1,2507 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * xfs_da_btree.c + * + * Routines to implement directories as Btrees of hashed names. + */ + + +/*======================================================================== + * Routines used for growing the Btree. + *========================================================================*/ + +/* + * Create the initial contents of an intermediate node. + */ +int +xfs_da_node_create(xfs_da_args_t *args, xfs_dablk_t blkno, int level, + xfs_dabuf_t **bpp, int whichfork) +{ + xfs_da_intnode_t *node; + xfs_dabuf_t *bp; + int error; + xfs_trans_t *tp; + + tp = args->trans; + error = xfs_da_get_buf(tp, args->dp, blkno, -1, &bp, whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + node = bp->data; + INT_ZERO(node->hdr.info.forw, ARCH_CONVERT); + INT_ZERO(node->hdr.info.back, ARCH_CONVERT); + INT_SET(node->hdr.info.magic, ARCH_CONVERT, XFS_DA_NODE_MAGIC); + INT_ZERO(node->hdr.info.pad, ARCH_CONVERT); + INT_ZERO(node->hdr.count, ARCH_CONVERT); + INT_SET(node->hdr.level, ARCH_CONVERT, level); + + xfs_da_log_buf(tp, bp, + XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr))); + + *bpp = bp; + return(0); +} + +/* + * Split a leaf node, rebalance, then possibly split + * intermediate nodes, rebalance, etc. + */ +int /* error */ +xfs_da_split(xfs_da_state_t *state) +{ + xfs_da_state_blk_t *oldblk, *newblk, *addblk; + xfs_da_intnode_t *node; + xfs_dabuf_t *bp; + int max, action, error, i; + + /* + * Walk back up the tree splitting/inserting/adjusting as necessary. + * If we need to insert and there isn't room, split the node, then + * decide which fragment to insert the new block from below into. + * Note that we may split the root this way, but we need more fixup. + */ + max = state->path.active - 1; + ASSERT((max >= 0) && (max < XFS_DA_NODE_MAXDEPTH)); + ASSERT(state->path.blk[max].magic == XFS_ATTR_LEAF_MAGIC || + state->path.blk[max].magic == XFS_DIRX_LEAF_MAGIC(state->mp)); + + addblk = &state->path.blk[max]; /* initial dummy value */ + for (i = max; (i >= 0) && addblk; state->path.active--, i--) { + oldblk = &state->path.blk[i]; + newblk = &state->altpath.blk[i]; + + /* + * If a leaf node then + * Allocate a new leaf node, then rebalance across them. + * else if an intermediate node then + * We split on the last layer, must we split the node? + */ + switch (oldblk->magic) { + case XFS_ATTR_LEAF_MAGIC: +#ifndef __KERNEL__ + return(ENOTTY); +#else + error = xfs_attr_leaf_split(state, oldblk, newblk); + if ((error != 0) && (error != ENOSPC)) { + return(error); /* GROT: attr is inconsistent */ + } + if (!error) { + addblk = newblk; + break; + } + /* + * Entry wouldn't fit, split the leaf again. + */ + state->extravalid = 1; + if (state->inleaf) { + state->extraafter = 0; /* before newblk */ + error = xfs_attr_leaf_split(state, oldblk, + &state->extrablk); + } else { + state->extraafter = 1; /* after newblk */ + error = xfs_attr_leaf_split(state, newblk, + &state->extrablk); + } + if (error) + return(error); /* GROT: attr inconsistent */ + addblk = newblk; + break; +#endif + case XFS_DIR_LEAF_MAGIC: + ASSERT(XFS_DIR_IS_V1(state->mp)); + error = xfs_dir_leaf_split(state, oldblk, newblk); + if ((error != 0) && (error != ENOSPC)) { + return(error); /* GROT: dir is inconsistent */ + } + if (!error) { + addblk = newblk; + break; + } + /* + * Entry wouldn't fit, split the leaf again. + */ + state->extravalid = 1; + if (state->inleaf) { + state->extraafter = 0; /* before newblk */ + error = xfs_dir_leaf_split(state, oldblk, + &state->extrablk); + if (error) + return(error); /* GROT: dir incon. */ + addblk = newblk; + } else { + state->extraafter = 1; /* after newblk */ + error = xfs_dir_leaf_split(state, newblk, + &state->extrablk); + if (error) + return(error); /* GROT: dir incon. */ + addblk = newblk; + } + break; + case XFS_DIR2_LEAFN_MAGIC: + ASSERT(XFS_DIR_IS_V2(state->mp)); + error = xfs_dir2_leafn_split(state, oldblk, newblk); + if (error) + return error; + addblk = newblk; + break; + case XFS_DA_NODE_MAGIC: + error = xfs_da_node_split(state, oldblk, newblk, addblk, + max - i, &action); + xfs_da_buf_done(addblk->bp); + addblk->bp = NULL; + if (error) + return(error); /* GROT: dir is inconsistent */ + /* + * Record the newly split block for the next time thru? + */ + if (action) + addblk = newblk; + else + addblk = NULL; + break; + } + + /* + * Update the btree to show the new hashval for this child. + */ + xfs_da_fixhashpath(state, &state->path); + /* + * If we won't need this block again, it's getting dropped + * from the active path by the loop control, so we need + * to mark it done now. + */ + if (i > 0 || !addblk) + xfs_da_buf_done(oldblk->bp); + } + if (!addblk) + return(0); + + /* + * Split the root node. + */ + ASSERT(state->path.active == 0); + oldblk = &state->path.blk[0]; + error = xfs_da_root_split(state, oldblk, addblk); + if (error) { + xfs_da_buf_done(oldblk->bp); + xfs_da_buf_done(addblk->bp); + addblk->bp = NULL; + return(error); /* GROT: dir is inconsistent */ + } + + /* + * Update pointers to the node which used to be block 0 and + * just got bumped because of the addition of a new root node. + * There might be three blocks involved if a double split occurred, + * and the original block 0 could be at any position in the list. + */ + + node = oldblk->bp->data; + if (!INT_ISZERO(node->hdr.info.forw, ARCH_CONVERT)) { + if (INT_GET(node->hdr.info.forw, ARCH_CONVERT) == addblk->blkno) { + bp = addblk->bp; + } else { + ASSERT(state->extravalid); + bp = state->extrablk.bp; + } + node = bp->data; + INT_SET(node->hdr.info.back, ARCH_CONVERT, oldblk->blkno); + xfs_da_log_buf(state->args->trans, bp, + XFS_DA_LOGRANGE(node, &node->hdr.info, + sizeof(node->hdr.info))); + } + node = oldblk->bp->data; + if (INT_GET(node->hdr.info.back, ARCH_CONVERT)) { + if (INT_GET(node->hdr.info.back, ARCH_CONVERT) == addblk->blkno) { + bp = addblk->bp; + } else { + ASSERT(state->extravalid); + bp = state->extrablk.bp; + } + node = bp->data; + INT_SET(node->hdr.info.forw, ARCH_CONVERT, oldblk->blkno); + xfs_da_log_buf(state->args->trans, bp, + XFS_DA_LOGRANGE(node, &node->hdr.info, + sizeof(node->hdr.info))); + } + xfs_da_buf_done(oldblk->bp); + xfs_da_buf_done(addblk->bp); + addblk->bp = NULL; + return(0); +} + +/* + * Split the root. We have to create a new root and point to the two + * parts (the split old root) that we just created. Copy block zero to + * the EOF, extending the inode in process. + */ +STATIC int /* error */ +xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2) +{ + xfs_da_intnode_t *node, *oldroot; + xfs_da_args_t *args; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + int error, size; + xfs_inode_t *dp; + xfs_trans_t *tp; + xfs_mount_t *mp; + xfs_dir2_leaf_t *leaf; + + /* + * Copy the existing (incorrect) block from the root node position + * to a free space somewhere. + */ + args = state->args; + ASSERT(args != NULL); + error = xfs_da_grow_inode(args, &blkno); + if (error) + return(error); + dp = args->dp; + tp = args->trans; + mp = state->mp; + error = xfs_da_get_buf(tp, dp, blkno, -1, &bp, args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + node = bp->data; + oldroot = blk1->bp->data; + if (INT_GET(oldroot->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) { + size = (int)((char *)&oldroot->btree[INT_GET(oldroot->hdr.count, ARCH_CONVERT)] - + (char *)oldroot); + } else { + ASSERT(XFS_DIR_IS_V2(mp)); + ASSERT(INT_GET(oldroot->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + leaf = (xfs_dir2_leaf_t *)oldroot; + size = (int)((char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] - + (char *)leaf); + } + bcopy(oldroot, node, size); + xfs_da_log_buf(tp, bp, 0, size - 1); + xfs_da_buf_done(blk1->bp); + blk1->bp = bp; + blk1->blkno = blkno; + + /* + * Set up the new root node. + */ + error = xfs_da_node_create(args, + args->whichfork == XFS_DATA_FORK && + XFS_DIR_IS_V2(mp) ? mp->m_dirleafblk : 0, + INT_GET(node->hdr.level, ARCH_CONVERT) + 1, &bp, args->whichfork); + if (error) + return(error); + node = bp->data; + INT_SET(node->btree[0].hashval, ARCH_CONVERT, blk1->hashval); + INT_SET(node->btree[0].before, ARCH_CONVERT, blk1->blkno); + INT_SET(node->btree[1].hashval, ARCH_CONVERT, blk2->hashval); + INT_SET(node->btree[1].before, ARCH_CONVERT, blk2->blkno); + INT_SET(node->hdr.count, ARCH_CONVERT, 2); + if (XFS_DIR_IS_V2(mp)) { + ASSERT(blk1->blkno >= mp->m_dirleafblk && + blk1->blkno < mp->m_dirfreeblk); + ASSERT(blk2->blkno >= mp->m_dirleafblk && + blk2->blkno < mp->m_dirfreeblk); + } + /* Header is already logged by xfs_da_node_create */ + xfs_da_log_buf(tp, bp, + XFS_DA_LOGRANGE(node, node->btree, + sizeof(xfs_da_node_entry_t) * 2)); + xfs_da_buf_done(bp); + + return(0); +} + +/* + * Split the node, rebalance, then add the new entry. + */ +STATIC int /* error */ +xfs_da_node_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, + xfs_da_state_blk_t *newblk, + xfs_da_state_blk_t *addblk, + int treelevel, int *result) +{ + xfs_da_intnode_t *node; + xfs_dablk_t blkno; + int newcount, error; + int useextra; + + node = oldblk->bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + + /* + * With V2 the extra block is data or freespace. + */ + useextra = state->extravalid && XFS_DIR_IS_V1(state->mp); + newcount = 1 + useextra; + /* + * Do we have to split the node? + */ + if ((INT_GET(node->hdr.count, ARCH_CONVERT) + newcount) > XFS_DA_NODE_ENTRIES(state->mp)) { + /* + * Allocate a new node, add to the doubly linked chain of + * nodes, then move some of our excess entries into it. + */ + error = xfs_da_grow_inode(state->args, &blkno); + if (error) + return(error); /* GROT: dir is inconsistent */ + + error = xfs_da_node_create(state->args, blkno, treelevel, + &newblk->bp, state->args->whichfork); + if (error) + return(error); /* GROT: dir is inconsistent */ + newblk->blkno = blkno; + newblk->magic = XFS_DA_NODE_MAGIC; + xfs_da_node_rebalance(state, oldblk, newblk); + error = xfs_da_blk_link(state, oldblk, newblk); + if (error) + return(error); + *result = 1; + } else { + *result = 0; + } + + /* + * Insert the new entry(s) into the correct block + * (updating last hashval in the process). + * + * xfs_da_node_add() inserts BEFORE the given index, + * and as a result of using node_lookup_int() we always + * point to a valid entry (not after one), but a split + * operation always results in a new block whose hashvals + * FOLLOW the current block. + * + * If we had double-split op below us, then add the extra block too. + */ + node = oldblk->bp->data; + if (oldblk->index <= INT_GET(node->hdr.count, ARCH_CONVERT)) { + oldblk->index++; + xfs_da_node_add(state, oldblk, addblk); + if (useextra) { + if (state->extraafter) + oldblk->index++; + xfs_da_node_add(state, oldblk, &state->extrablk); + state->extravalid = 0; + } + } else { + newblk->index++; + xfs_da_node_add(state, newblk, addblk); + if (useextra) { + if (state->extraafter) + newblk->index++; + xfs_da_node_add(state, newblk, &state->extrablk); + state->extravalid = 0; + } + } + + return(0); +} + +/* + * Balance the btree elements between two intermediate nodes, + * usually one full and one empty. + * + * NOTE: if blk2 is empty, then it will get the upper half of blk1. + */ +STATIC void +xfs_da_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2) +{ + xfs_da_intnode_t *node1, *node2, *tmpnode; + xfs_da_node_entry_t *btree_s, *btree_d; + int count, tmp; + xfs_trans_t *tp; + + node1 = blk1->bp->data; + node2 = blk2->bp->data; + /* + * Figure out how many entries need to move, and in which direction. + * Swap the nodes around if that makes it simpler. + */ + if ((INT_GET(node1->hdr.count, ARCH_CONVERT) > 0) && (INT_GET(node2->hdr.count, ARCH_CONVERT) > 0) && + ((INT_GET(node2->btree[ 0 ].hashval, ARCH_CONVERT) < INT_GET(node1->btree[ 0 ].hashval, ARCH_CONVERT)) || + (INT_GET(node2->btree[ INT_GET(node2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) < + INT_GET(node1->btree[ INT_GET(node1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)))) { + tmpnode = node1; + node1 = node2; + node2 = tmpnode; + } + ASSERT(INT_GET(node1->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + ASSERT(INT_GET(node2->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + count = (INT_GET(node1->hdr.count, ARCH_CONVERT) - INT_GET(node2->hdr.count, ARCH_CONVERT)) / 2; + if (count == 0) + return; + tp = state->args->trans; + /* + * Two cases: high-to-low and low-to-high. + */ + if (count > 0) { + /* + * Move elements in node2 up to make a hole. + */ + if ((tmp = INT_GET(node2->hdr.count, ARCH_CONVERT)) > 0) { + tmp *= (uint)sizeof(xfs_da_node_entry_t); + btree_s = &node2->btree[0]; + btree_d = &node2->btree[count]; + ovbcopy(btree_s, btree_d, tmp); + } + + /* + * Move the req'd B-tree elements from high in node1 to + * low in node2. + */ + INT_MOD(node2->hdr.count, ARCH_CONVERT, count); + tmp = count * (uint)sizeof(xfs_da_node_entry_t); + btree_s = &node1->btree[INT_GET(node1->hdr.count, ARCH_CONVERT) - count]; + btree_d = &node2->btree[0]; + bcopy(btree_s, btree_d, tmp); + INT_MOD(node1->hdr.count, ARCH_CONVERT, -(count)); + + } else { + /* + * Move the req'd B-tree elements from low in node2 to + * high in node1. + */ + count = -count; + tmp = count * (uint)sizeof(xfs_da_node_entry_t); + btree_s = &node2->btree[0]; + btree_d = &node1->btree[INT_GET(node1->hdr.count, ARCH_CONVERT)]; + bcopy(btree_s, btree_d, tmp); + INT_MOD(node1->hdr.count, ARCH_CONVERT, count); + xfs_da_log_buf(tp, blk1->bp, + XFS_DA_LOGRANGE(node1, btree_d, tmp)); + + /* + * Move elements in node2 down to fill the hole. + */ + tmp = INT_GET(node2->hdr.count, ARCH_CONVERT) - count; + tmp *= (uint)sizeof(xfs_da_node_entry_t); + btree_s = &node2->btree[count]; + btree_d = &node2->btree[0]; + ovbcopy(btree_s, btree_d, tmp); + INT_MOD(node2->hdr.count, ARCH_CONVERT, -(count)); + } + + /* + * Log header of node 1 and all current bits of node 2. + */ + xfs_da_log_buf(tp, blk1->bp, + XFS_DA_LOGRANGE(node1, &node1->hdr, sizeof(node1->hdr))); + xfs_da_log_buf(tp, blk2->bp, + XFS_DA_LOGRANGE(node2, &node2->hdr, + sizeof(node2->hdr) + + sizeof(node2->btree[0]) * INT_GET(node2->hdr.count, ARCH_CONVERT))); + + /* + * Record the last hashval from each block for upward propagation. + * (note: don't use the swapped node pointers) + */ + node1 = blk1->bp->data; + node2 = blk2->bp->data; + blk1->hashval = INT_GET(node1->btree[ INT_GET(node1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + blk2->hashval = INT_GET(node2->btree[ INT_GET(node2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + + /* + * Adjust the expected index for insertion. + */ + if (blk1->index >= INT_GET(node1->hdr.count, ARCH_CONVERT)) { + blk2->index = blk1->index - INT_GET(node1->hdr.count, ARCH_CONVERT); + blk1->index = INT_GET(node1->hdr.count, ARCH_CONVERT) + 1; /* make it invalid */ + } +} + +/* + * Add a new entry to an intermediate node. + */ +STATIC void +xfs_da_node_add(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, + xfs_da_state_blk_t *newblk) +{ + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + int tmp; + xfs_mount_t *mp; + + node = oldblk->bp->data; + mp = state->mp; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + ASSERT((oldblk->index >= 0) && (oldblk->index <= INT_GET(node->hdr.count, ARCH_CONVERT))); + ASSERT(newblk->blkno != 0); + if (state->args->whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) + ASSERT(newblk->blkno >= mp->m_dirleafblk && + newblk->blkno < mp->m_dirfreeblk); + + /* + * We may need to make some room before we insert the new node. + */ + tmp = 0; + btree = &node->btree[ oldblk->index ]; + if (oldblk->index < INT_GET(node->hdr.count, ARCH_CONVERT)) { + tmp = (INT_GET(node->hdr.count, ARCH_CONVERT) - oldblk->index) * (uint)sizeof(*btree); + ovbcopy(btree, btree + 1, tmp); + } + INT_SET(btree->hashval, ARCH_CONVERT, newblk->hashval); + INT_SET(btree->before, ARCH_CONVERT, newblk->blkno); + xfs_da_log_buf(state->args->trans, oldblk->bp, + XFS_DA_LOGRANGE(node, btree, tmp + sizeof(*btree))); + INT_MOD(node->hdr.count, ARCH_CONVERT, +1); + xfs_da_log_buf(state->args->trans, oldblk->bp, + XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr))); + + /* + * Copy the last hash value from the oldblk to propagate upwards. + */ + oldblk->hashval = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); +} + +/*======================================================================== + * Routines used for shrinking the Btree. + *========================================================================*/ + +/* + * Deallocate an empty leaf node, remove it from its parent, + * possibly deallocating that block, etc... + */ +int +xfs_da_join(xfs_da_state_t *state) +{ + xfs_da_state_blk_t *drop_blk, *save_blk; + int action, error; + + action = 0; + drop_blk = &state->path.blk[ state->path.active-1 ]; + save_blk = &state->altpath.blk[ state->path.active-1 ]; + ASSERT(state->path.blk[0].magic == XFS_DA_NODE_MAGIC); + ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC || + drop_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp)); + + /* + * Walk back up the tree joining/deallocating as necessary. + * When we stop dropping blocks, break out. + */ + for ( ; state->path.active >= 2; drop_blk--, save_blk--, + state->path.active--) { + /* + * See if we can combine the block with a neighbor. + * (action == 0) => no options, just leave + * (action == 1) => coalesce, then unlink + * (action == 2) => block empty, unlink it + */ + switch (drop_blk->magic) { + case XFS_ATTR_LEAF_MAGIC: +#ifndef __KERNEL__ + error = ENOTTY; +#else + error = xfs_attr_leaf_toosmall(state, &action); +#endif + if (error) + return(error); + if (action == 0) + return(0); +#ifdef __KERNEL__ + xfs_attr_leaf_unbalance(state, drop_blk, save_blk); +#endif + break; + case XFS_DIR_LEAF_MAGIC: + ASSERT(XFS_DIR_IS_V1(state->mp)); + error = xfs_dir_leaf_toosmall(state, &action); + if (error) + return(error); + if (action == 0) + return(0); + xfs_dir_leaf_unbalance(state, drop_blk, save_blk); + break; + case XFS_DIR2_LEAFN_MAGIC: + ASSERT(XFS_DIR_IS_V2(state->mp)); + error = xfs_dir2_leafn_toosmall(state, &action); + if (error) + return error; + if (action == 0) + return 0; + xfs_dir2_leafn_unbalance(state, drop_blk, save_blk); + break; + case XFS_DA_NODE_MAGIC: + /* + * Remove the offending node, fixup hashvals, + * check for a toosmall neighbor. + */ + xfs_da_node_remove(state, drop_blk); + xfs_da_fixhashpath(state, &state->path); + error = xfs_da_node_toosmall(state, &action); + if (error) + return(error); + if (action == 0) + return 0; + xfs_da_node_unbalance(state, drop_blk, save_blk); + break; + } + xfs_da_fixhashpath(state, &state->altpath); + error = xfs_da_blk_unlink(state, drop_blk, save_blk); + xfs_da_state_kill_altpath(state); + if (error) + return(error); + error = xfs_da_shrink_inode(state->args, drop_blk->blkno, + drop_blk->bp); + drop_blk->bp = NULL; + if (error) + return(error); + } + /* + * We joined all the way to the top. If it turns out that + * we only have one entry in the root, make the child block + * the new root. + */ + xfs_da_node_remove(state, drop_blk); + xfs_da_fixhashpath(state, &state->path); + error = xfs_da_root_join(state, &state->path.blk[0]); + return(error); +} + +/* + * We have only one entry in the root. Copy the only remaining child of + * the old root to block 0 as the new root node. + */ +STATIC int +xfs_da_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk) +{ + xfs_da_intnode_t *oldroot; + /* REFERENCED */ + xfs_da_blkinfo_t *blkinfo; + xfs_da_args_t *args; + xfs_dablk_t child; + xfs_dabuf_t *bp; + int error; + + args = state->args; + ASSERT(args != NULL); + ASSERT(root_blk->magic == XFS_DA_NODE_MAGIC); + oldroot = root_blk->bp->data; + ASSERT(INT_GET(oldroot->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + ASSERT(INT_ISZERO(oldroot->hdr.info.forw, ARCH_CONVERT)); + ASSERT(INT_ISZERO(oldroot->hdr.info.back, ARCH_CONVERT)); + + /* + * If the root has more than one child, then don't do anything. + */ + if (INT_GET(oldroot->hdr.count, ARCH_CONVERT) > 1) + return(0); + + /* + * Read in the (only) child block, then copy those bytes into + * the root block's buffer and free the original child block. + */ + child = INT_GET(oldroot->btree[ 0 ].before, ARCH_CONVERT); + ASSERT(child != 0); + error = xfs_da_read_buf(args->trans, args->dp, child, -1, &bp, + args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + blkinfo = bp->data; + if (INT_GET(oldroot->hdr.level, ARCH_CONVERT) == 1) { + ASSERT(INT_GET(blkinfo->magic, ARCH_CONVERT) == XFS_DIRX_LEAF_MAGIC(state->mp) || + INT_GET(blkinfo->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); + } else { + ASSERT(INT_GET(blkinfo->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + } + ASSERT(INT_GET(blkinfo->forw, ARCH_CONVERT) == 0); + ASSERT(INT_GET(blkinfo->back, ARCH_CONVERT) == 0); + bcopy(bp->data, root_blk->bp->data, state->blocksize); + xfs_da_log_buf(args->trans, root_blk->bp, 0, state->blocksize - 1); + error = xfs_da_shrink_inode(args, child, bp); + return(error); +} + +/* + * Check a node block and its neighbors to see if the block should be + * collapsed into one or the other neighbor. Always keep the block + * with the smaller block number. + * If the current block is over 50% full, don't try to join it, return 0. + * If the block is empty, fill in the state structure and return 2. + * If it can be collapsed, fill in the state structure and return 1. + * If nothing can be done, return 0. + */ +STATIC int +xfs_da_node_toosmall(xfs_da_state_t *state, int *action) +{ + xfs_da_intnode_t *node; + xfs_da_state_blk_t *blk; + xfs_da_blkinfo_t *info; + int count, forward, error, retval, i; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + + /* + * Check for the degenerate case of the block being over 50% full. + * If so, it's not worth even looking to see if we might be able + * to coalesce with a sibling. + */ + blk = &state->path.blk[ state->path.active-1 ]; + info = blk->bp->data; + ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + node = (xfs_da_intnode_t *)info; + count = INT_GET(node->hdr.count, ARCH_CONVERT); + if (count > (XFS_DA_NODE_ENTRIES(state->mp) >> 1)) { + *action = 0; /* blk over 50%, dont try to join */ + return(0); /* blk over 50%, dont try to join */ + } + + /* + * Check for the degenerate case of the block being empty. + * If the block is empty, we'll simply delete it, no need to + * coalesce it with a sibling block. We choose (aribtrarily) + * to merge with the forward block unless it is NULL. + */ + if (count == 0) { + /* + * Make altpath point to the block we want to keep and + * path point to the block we want to drop (this one). + */ + forward = (!INT_ISZERO(info->forw, ARCH_CONVERT)); + bcopy(&state->path, &state->altpath, sizeof(state->path)); + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + if (error) + return(error); + if (retval) { + *action = 0; + } else { + *action = 2; + } + return(0); + } + + /* + * Examine each sibling block to see if we can coalesce with + * at least 25% free space to spare. We need to figure out + * whether to merge with the forward or the backward block. + * We prefer coalescing with the lower numbered sibling so as + * to shrink a directory over time. + */ + /* start with smaller blk num */ + forward = (INT_GET(info->forw, ARCH_CONVERT) + < INT_GET(info->back, ARCH_CONVERT)); + for (i = 0; i < 2; forward = !forward, i++) { + if (forward) + blkno = INT_GET(info->forw, ARCH_CONVERT); + else + blkno = INT_GET(info->back, ARCH_CONVERT); + if (blkno == 0) + continue; + error = xfs_da_read_buf(state->args->trans, state->args->dp, + blkno, -1, &bp, state->args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + + node = (xfs_da_intnode_t *)info; + count = XFS_DA_NODE_ENTRIES(state->mp); + count -= XFS_DA_NODE_ENTRIES(state->mp) >> 2; + count -= INT_GET(node->hdr.count, ARCH_CONVERT); + node = bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + count -= INT_GET(node->hdr.count, ARCH_CONVERT); + xfs_da_brelse(state->args->trans, bp); + if (count >= 0) + break; /* fits with at least 25% to spare */ + } + if (i >= 2) { + *action = 0; + return(0); + } + + /* + * Make altpath point to the block we want to keep (the lower + * numbered block) and path point to the block we want to drop. + */ + bcopy(&state->path, &state->altpath, sizeof(state->path)); + if (blkno < blk->blkno) { + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + if (error) { + return(error); + } + if (retval) { + *action = 0; + return(0); + } + } else { + error = xfs_da_path_shift(state, &state->path, forward, + 0, &retval); + if (error) { + return(error); + } + if (retval) { + *action = 0; + return(0); + } + } + *action = 1; + return(0); +} + + +/* + * Walk back up the tree adjusting hash values as necessary, + * when we stop making changes, return. + */ +void +xfs_da_fixhashpath(xfs_da_state_t *state, xfs_da_state_path_t *path) +{ + xfs_da_state_blk_t *blk; + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + xfs_dahash_t lasthash=0; + int level, count; + + level = path->active-1; + blk = &path->blk[ level ]; + switch (blk->magic) { +#ifdef __KERNEL__ + case XFS_ATTR_LEAF_MAGIC: + lasthash = xfs_attr_leaf_lasthash(blk->bp, &count); + if (count == 0) + return; + break; +#endif + case XFS_DIR_LEAF_MAGIC: + ASSERT(XFS_DIR_IS_V1(state->mp)); + lasthash = xfs_dir_leaf_lasthash(blk->bp, &count); + if (count == 0) + return; + break; + case XFS_DIR2_LEAFN_MAGIC: + ASSERT(XFS_DIR_IS_V2(state->mp)); + lasthash = xfs_dir2_leafn_lasthash(blk->bp, &count); + if (count == 0) + return; + break; + case XFS_DA_NODE_MAGIC: + lasthash = xfs_da_node_lasthash(blk->bp, &count); + if (count == 0) + return; + break; + } + for (blk--, level--; level >= 0; blk--, level--) { + node = blk->bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + btree = &node->btree[ blk->index ]; + if (INT_GET(btree->hashval, ARCH_CONVERT) == lasthash) + break; + blk->hashval = lasthash; + INT_SET(btree->hashval, ARCH_CONVERT, lasthash); + xfs_da_log_buf(state->args->trans, blk->bp, + XFS_DA_LOGRANGE(node, btree, sizeof(*btree))); + + lasthash = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + } +} + + + +/* + * Remove an entry from an intermediate node. + */ +STATIC void +xfs_da_node_remove(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk) +{ + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + int tmp; + + node = drop_blk->bp->data; + ASSERT(drop_blk->index < INT_GET(node->hdr.count, ARCH_CONVERT)); + ASSERT(drop_blk->index >= 0); + + /* + * Copy over the offending entry, or just zero it out. + */ + btree = &node->btree[drop_blk->index]; + if (drop_blk->index < (INT_GET(node->hdr.count, ARCH_CONVERT)-1)) { + tmp = INT_GET(node->hdr.count, ARCH_CONVERT) - drop_blk->index - 1; + tmp *= (uint)sizeof(xfs_da_node_entry_t); + ovbcopy(btree + 1, btree, tmp); + xfs_da_log_buf(state->args->trans, drop_blk->bp, + XFS_DA_LOGRANGE(node, btree, tmp)); + btree = &node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ]; + } + bzero((char *)btree, sizeof(xfs_da_node_entry_t)); + xfs_da_log_buf(state->args->trans, drop_blk->bp, + XFS_DA_LOGRANGE(node, btree, sizeof(*btree))); + INT_MOD(node->hdr.count, ARCH_CONVERT, -1); + xfs_da_log_buf(state->args->trans, drop_blk->bp, + XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr))); + + /* + * Copy the last hash value from the block to propagate upwards. + */ + btree--; + drop_blk->hashval = INT_GET(btree->hashval, ARCH_CONVERT); +} + +/* + * Unbalance the btree elements between two intermediate nodes, + * move all Btree elements from one node into another. + */ +STATIC void +xfs_da_node_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk) +{ + xfs_da_intnode_t *drop_node, *save_node; + xfs_da_node_entry_t *btree; + int tmp; + xfs_trans_t *tp; + + drop_node = drop_blk->bp->data; + save_node = save_blk->bp->data; + ASSERT(INT_GET(drop_node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + ASSERT(INT_GET(save_node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + tp = state->args->trans; + + /* + * If the dying block has lower hashvals, then move all the + * elements in the remaining block up to make a hole. + */ + if ((INT_GET(drop_node->btree[ 0 ].hashval, ARCH_CONVERT) < INT_GET(save_node->btree[ 0 ].hashval, ARCH_CONVERT)) || + (INT_GET(drop_node->btree[ INT_GET(drop_node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) < + INT_GET(save_node->btree[ INT_GET(save_node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT))) + { + btree = &save_node->btree[ INT_GET(drop_node->hdr.count, ARCH_CONVERT) ]; + tmp = INT_GET(save_node->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_da_node_entry_t); + ovbcopy(&save_node->btree[0], btree, tmp); + btree = &save_node->btree[0]; + xfs_da_log_buf(tp, save_blk->bp, + XFS_DA_LOGRANGE(save_node, btree, + (INT_GET(save_node->hdr.count, ARCH_CONVERT) + INT_GET(drop_node->hdr.count, ARCH_CONVERT)) * + sizeof(xfs_da_node_entry_t))); + } else { + btree = &save_node->btree[ INT_GET(save_node->hdr.count, ARCH_CONVERT) ]; + xfs_da_log_buf(tp, save_blk->bp, + XFS_DA_LOGRANGE(save_node, btree, + INT_GET(drop_node->hdr.count, ARCH_CONVERT) * + sizeof(xfs_da_node_entry_t))); + } + + /* + * Move all the B-tree elements from drop_blk to save_blk. + */ + tmp = INT_GET(drop_node->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_da_node_entry_t); + bcopy(&drop_node->btree[0], btree, tmp); + INT_MOD(save_node->hdr.count, ARCH_CONVERT, INT_GET(drop_node->hdr.count, ARCH_CONVERT)); + + xfs_da_log_buf(tp, save_blk->bp, + XFS_DA_LOGRANGE(save_node, &save_node->hdr, + sizeof(save_node->hdr))); + + /* + * Save the last hashval in the remaining block for upward propagation. + */ + save_blk->hashval = INT_GET(save_node->btree[ INT_GET(save_node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); +} + + +/*======================================================================== + * Routines used for finding things in the Btree. + *========================================================================*/ + +/* + * Walk down the Btree looking for a particular filename, filling + * in the state structure as we go. + * + * We will set the state structure to point to each of the elements + * in each of the nodes where either the hashval is or should be. + * + * We support duplicate hashval's so for each entry in the current + * node that could contain the desired hashval, descend. This is a + * pruned depth-first tree search. + */ +int /* error */ +xfs_da_node_lookup_int(xfs_da_state_t *state, int *result) +{ + xfs_da_state_blk_t *blk; + xfs_da_blkinfo_t *curr; + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + xfs_dablk_t blkno; + int probe, span, max, error, retval; + xfs_dahash_t hashval; + xfs_da_args_t *args; + + args = state->args; + /* + * Descend thru the B-tree searching each level for the right + * node to use, until the right hashval is found. + */ + if (args->whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(state->mp)) + blkno = state->mp->m_dirleafblk; + else + blkno = 0; + for (blk = &state->path.blk[0], state->path.active = 1; + state->path.active <= XFS_DA_NODE_MAXDEPTH; + blk++, state->path.active++) { + /* + * Read the next node down in the tree. + */ + blk->blkno = blkno; + error = xfs_da_read_buf(state->args->trans, state->args->dp, + blkno, -1, &blk->bp, + state->args->whichfork); + if (error) { + blk->blkno = 0; + state->path.active--; + return(error); + } + ASSERT(blk->bp != NULL); + curr = blk->bp->data; + ASSERT(INT_GET(curr->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC || + INT_GET(curr->magic, ARCH_CONVERT) == XFS_DIRX_LEAF_MAGIC(state->mp) || + INT_GET(curr->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); + + /* + * Search an intermediate node for a match. + */ + blk->magic = INT_GET(curr->magic, ARCH_CONVERT); + if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) { + node = blk->bp->data; + blk->hashval = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + + /* + * Binary search. (note: small blocks will skip loop) + */ + max = INT_GET(node->hdr.count, ARCH_CONVERT); + probe = span = max / 2; + hashval = state->args->hashval; + for (btree = &node->btree[probe]; span > 4; + btree = &node->btree[probe]) { + span /= 2; + if (INT_GET(btree->hashval, ARCH_CONVERT) < hashval) + probe += span; + else if (INT_GET(btree->hashval, ARCH_CONVERT) > hashval) + probe -= span; + else + break; + } + ASSERT((probe >= 0) && (probe < max)); + ASSERT((span <= 4) || (INT_GET(btree->hashval, ARCH_CONVERT) == hashval)); + + /* + * Since we may have duplicate hashval's, find the first + * matching hashval in the node. + */ + while ((probe > 0) && (INT_GET(btree->hashval, ARCH_CONVERT) >= hashval)) { + btree--; + probe--; + } + while ((probe < max) && (INT_GET(btree->hashval, ARCH_CONVERT) < hashval)) { + btree++; + probe++; + } + + /* + * Pick the right block to descend on. + */ + if (probe == max) { + blk->index = max-1; + blkno = INT_GET(node->btree[ max-1 ].before, ARCH_CONVERT); + } else { + blk->index = probe; + blkno = INT_GET(btree->before, ARCH_CONVERT); + } + } +#ifdef __KERNEL__ + else if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC) { + blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL); + break; + } +#endif + else if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC) { + blk->hashval = xfs_dir_leaf_lasthash(blk->bp, NULL); + break; + } + else if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC) { + blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, NULL); + break; + } + } + + /* + * A leaf block that ends in the hashval that we are interested in + * (final hashval == search hashval) means that the next block may + * contain more entries with the same hashval, shift upward to the + * next leaf and keep searching. + */ + for (;;) { + if (blk->magic == XFS_DIR_LEAF_MAGIC) { + ASSERT(XFS_DIR_IS_V1(state->mp)); + retval = xfs_dir_leaf_lookup_int(blk->bp, state->args, + &blk->index); + } else if (blk->magic == XFS_DIR2_LEAFN_MAGIC) { + ASSERT(XFS_DIR_IS_V2(state->mp)); + retval = xfs_dir2_leafn_lookup_int(blk->bp, state->args, + &blk->index, state); + } +#ifdef __KERNEL__ + else if (blk->magic == XFS_ATTR_LEAF_MAGIC) { + retval = xfs_attr_leaf_lookup_int(blk->bp, state->args); + blk->index = state->args->index; + state->args->blkno = blk->blkno; + } +#endif + if (((retval == ENOENT) || (retval == ENOATTR)) && + (blk->hashval == state->args->hashval)) { + error = xfs_da_path_shift(state, &state->path, 1, 1, + &retval); + if (error) + return(error); + if (retval == 0) { + continue; + } +#ifdef __KERNEL__ + else if (blk->magic == XFS_ATTR_LEAF_MAGIC) { + /* path_shift() gives ENOENT */ + retval = XFS_ERROR(ENOATTR); + } +#endif + } + break; + } + *result = retval; + return(0); +} + + +/*======================================================================== + * Utility routines. + *========================================================================*/ + +/* + * Link a new block into a doubly linked list of blocks (of whatever type). + */ +int /* error */ +xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk, + xfs_da_state_blk_t *new_blk) +{ + xfs_da_blkinfo_t *old_info, *new_info, *tmp_info; + xfs_da_args_t *args; + int before=0, error; + xfs_dabuf_t *bp; + + /* + * Set up environment. + */ + args = state->args; + ASSERT(args != NULL); + old_info = old_blk->bp->data; + new_info = new_blk->bp->data; + ASSERT(old_blk->magic == XFS_DA_NODE_MAGIC || + old_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp) || + old_blk->magic == XFS_ATTR_LEAF_MAGIC); + ASSERT(old_blk->magic == INT_GET(old_info->magic, ARCH_CONVERT)); + ASSERT(new_blk->magic == INT_GET(new_info->magic, ARCH_CONVERT)); + ASSERT(old_blk->magic == new_blk->magic); + + switch (old_blk->magic) { +#ifdef __KERNEL__ + case XFS_ATTR_LEAF_MAGIC: + before = xfs_attr_leaf_order(old_blk->bp, new_blk->bp); + break; +#endif + case XFS_DIR_LEAF_MAGIC: + ASSERT(XFS_DIR_IS_V1(state->mp)); + before = xfs_dir_leaf_order(old_blk->bp, new_blk->bp); + break; + case XFS_DIR2_LEAFN_MAGIC: + ASSERT(XFS_DIR_IS_V2(state->mp)); + before = xfs_dir2_leafn_order(old_blk->bp, new_blk->bp); + break; + case XFS_DA_NODE_MAGIC: + before = xfs_da_node_order(old_blk->bp, new_blk->bp); + break; + } + + /* + * Link blocks in appropriate order. + */ + if (before) { + /* + * Link new block in before existing block. + */ + INT_SET(new_info->forw, ARCH_CONVERT, old_blk->blkno); + new_info->back = old_info->back; /* INT_: direct copy */ + if (INT_GET(old_info->back, ARCH_CONVERT)) { + error = xfs_da_read_buf(args->trans, args->dp, + INT_GET(old_info->back, + ARCH_CONVERT), -1, &bp, + args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + tmp_info = bp->data; + ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT) == INT_GET(old_info->magic, ARCH_CONVERT)); + ASSERT(INT_GET(tmp_info->forw, ARCH_CONVERT) == old_blk->blkno); + INT_SET(tmp_info->forw, ARCH_CONVERT, new_blk->blkno); + xfs_da_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1); + xfs_da_buf_done(bp); + } + INT_SET(old_info->back, ARCH_CONVERT, new_blk->blkno); + } else { + /* + * Link new block in after existing block. + */ + new_info->forw = old_info->forw; /* INT_: direct copy */ + INT_SET(new_info->back, ARCH_CONVERT, old_blk->blkno); + if (INT_GET(old_info->forw, ARCH_CONVERT)) { + error = xfs_da_read_buf(args->trans, args->dp, + INT_GET(old_info->forw, ARCH_CONVERT), -1, &bp, + args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + tmp_info = bp->data; + ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT) + == INT_GET(old_info->magic, ARCH_CONVERT)); + ASSERT(INT_GET(tmp_info->back, ARCH_CONVERT) + == old_blk->blkno); + INT_SET(tmp_info->back, ARCH_CONVERT, new_blk->blkno); + xfs_da_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1); + xfs_da_buf_done(bp); + } + INT_SET(old_info->forw, ARCH_CONVERT, new_blk->blkno); + } + + xfs_da_log_buf(args->trans, old_blk->bp, 0, sizeof(*tmp_info) - 1); + xfs_da_log_buf(args->trans, new_blk->bp, 0, sizeof(*tmp_info) - 1); + return(0); +} + + +/* + * Compare two intermediate nodes for "order". + */ +STATIC int +xfs_da_node_order(xfs_dabuf_t *node1_bp, xfs_dabuf_t *node2_bp) +{ + xfs_da_intnode_t *node1, *node2; + + node1 = node1_bp->data; + node2 = node2_bp->data; + ASSERT((INT_GET(node1->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) && + (INT_GET(node2->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC)); + if ((INT_GET(node1->hdr.count, ARCH_CONVERT) > 0) && (INT_GET(node2->hdr.count, ARCH_CONVERT) > 0) && + ((INT_GET(node2->btree[ 0 ].hashval, ARCH_CONVERT) < + INT_GET(node1->btree[ 0 ].hashval, ARCH_CONVERT)) || + (INT_GET(node2->btree[ INT_GET(node2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) < + INT_GET(node1->btree[ INT_GET(node1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)))) { + return(1); + } + return(0); +} + + +/* + * Pick up the last hashvalue from an intermediate node. + */ +STATIC uint +xfs_da_node_lasthash(xfs_dabuf_t *bp, int *count) +{ + xfs_da_intnode_t *node; + + node = bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + if (count) + *count = INT_GET(node->hdr.count, ARCH_CONVERT); + if (INT_GET(node->hdr.count, ARCH_CONVERT) == 0) + return(0); + return(INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)); +} + +/* + * Unlink a block from a doubly linked list of blocks. + */ +int /* error */ +xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk) +{ + xfs_da_blkinfo_t *drop_info, *save_info, *tmp_info; + xfs_da_args_t *args; + xfs_dabuf_t *bp; + int error; + + /* + * Set up environment. + */ + args = state->args; + ASSERT(args != NULL); + save_info = save_blk->bp->data; + drop_info = drop_blk->bp->data; + ASSERT(save_blk->magic == XFS_DA_NODE_MAGIC || + save_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp) || + save_blk->magic == XFS_ATTR_LEAF_MAGIC); + ASSERT(save_blk->magic == INT_GET(save_info->magic, ARCH_CONVERT)); + ASSERT(drop_blk->magic == INT_GET(drop_info->magic, ARCH_CONVERT)); + ASSERT(save_blk->magic == drop_blk->magic); + ASSERT((INT_GET(save_info->forw, ARCH_CONVERT) == drop_blk->blkno) || + (INT_GET(save_info->back, ARCH_CONVERT) == drop_blk->blkno)); + ASSERT((INT_GET(drop_info->forw, ARCH_CONVERT) == save_blk->blkno) || + (INT_GET(drop_info->back, ARCH_CONVERT) == save_blk->blkno)); + + /* + * Unlink the leaf block from the doubly linked chain of leaves. + */ + if (INT_GET(save_info->back, ARCH_CONVERT) == drop_blk->blkno) { + save_info->back = drop_info->back; /* INT_: direct copy */ + if (INT_GET(drop_info->back, ARCH_CONVERT)) { + error = xfs_da_read_buf(args->trans, args->dp, + INT_GET(drop_info->back, + ARCH_CONVERT), -1, &bp, + args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + tmp_info = bp->data; + ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT) == INT_GET(save_info->magic, ARCH_CONVERT)); + ASSERT(INT_GET(tmp_info->forw, ARCH_CONVERT) == drop_blk->blkno); + INT_SET(tmp_info->forw, ARCH_CONVERT, save_blk->blkno); + xfs_da_log_buf(args->trans, bp, 0, + sizeof(*tmp_info) - 1); + xfs_da_buf_done(bp); + } + } else { + save_info->forw = drop_info->forw; /* INT_: direct copy */ + if (INT_GET(drop_info->forw, ARCH_CONVERT)) { + error = xfs_da_read_buf(args->trans, args->dp, + INT_GET(drop_info->forw, ARCH_CONVERT), -1, &bp, + args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + tmp_info = bp->data; + ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT) + == INT_GET(save_info->magic, ARCH_CONVERT)); + ASSERT(INT_GET(tmp_info->back, ARCH_CONVERT) + == drop_blk->blkno); + INT_SET(tmp_info->back, ARCH_CONVERT, save_blk->blkno); + xfs_da_log_buf(args->trans, bp, 0, + sizeof(*tmp_info) - 1); + xfs_da_buf_done(bp); + } + } + + xfs_da_log_buf(args->trans, save_blk->bp, 0, sizeof(*save_info) - 1); + return(0); +} + +/* + * Move a path "forward" or "!forward" one block at the current level. + * + * This routine will adjust a "path" to point to the next block + * "forward" (higher hashvalues) or "!forward" (lower hashvals) in the + * Btree, including updating pointers to the intermediate nodes between + * the new bottom and the root. + */ +int /* error */ +xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path, + int forward, int release, int *result) +{ + xfs_da_state_blk_t *blk; + xfs_da_blkinfo_t *info; + xfs_da_intnode_t *node; + xfs_da_args_t *args; + xfs_dablk_t blkno=0; + int level, error; + + /* + * Roll up the Btree looking for the first block where our + * current index is not at the edge of the block. Note that + * we skip the bottom layer because we want the sibling block. + */ + args = state->args; + ASSERT(args != NULL); + ASSERT(path != NULL); + ASSERT((path->active > 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); + level = (path->active-1) - 1; /* skip bottom layer in path */ + for (blk = &path->blk[level]; level >= 0; blk--, level--) { + ASSERT(blk->bp != NULL); + node = blk->bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + if (forward && (blk->index < INT_GET(node->hdr.count, ARCH_CONVERT)-1)) { + blk->index++; + blkno = INT_GET(node->btree[ blk->index ].before, ARCH_CONVERT); + break; + } else if (!forward && (blk->index > 0)) { + blk->index--; + blkno = INT_GET(node->btree[ blk->index ].before, ARCH_CONVERT); + break; + } + } + if (level < 0) { + *result = XFS_ERROR(ENOENT); /* we're out of our tree */ + ASSERT(args->oknoent); + return(0); + } + + /* + * Roll down the edge of the subtree until we reach the + * same depth we were at originally. + */ + for (blk++, level++; level < path->active; blk++, level++) { + /* + * Release the old block. + * (if it's dirty, trans won't actually let go) + */ + if (release) + xfs_da_brelse(args->trans, blk->bp); + + /* + * Read the next child block. + */ + blk->blkno = blkno; + error = xfs_da_read_buf(args->trans, args->dp, blkno, -1, + &blk->bp, args->whichfork); + if (error) + return(error); + ASSERT(blk->bp != NULL); + info = blk->bp->data; + ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC || + INT_GET(info->magic, ARCH_CONVERT) == XFS_DIRX_LEAF_MAGIC(state->mp) || + INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); + blk->magic = INT_GET(info->magic, ARCH_CONVERT); + if (INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) { + node = (xfs_da_intnode_t *)info; + blk->hashval = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + if (forward) + blk->index = 0; + else + blk->index = INT_GET(node->hdr.count, ARCH_CONVERT)-1; + blkno = INT_GET(node->btree[ blk->index ].before, ARCH_CONVERT); + } else { + ASSERT(level == path->active-1); + blk->index = 0; + switch(blk->magic) { +#ifdef __KERNEL__ + case XFS_ATTR_LEAF_MAGIC: + blk->hashval = xfs_attr_leaf_lasthash(blk->bp, + NULL); + break; +#endif + case XFS_DIR_LEAF_MAGIC: + ASSERT(XFS_DIR_IS_V1(state->mp)); + blk->hashval = xfs_dir_leaf_lasthash(blk->bp, + NULL); + break; + case XFS_DIR2_LEAFN_MAGIC: + ASSERT(XFS_DIR_IS_V2(state->mp)); + blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, + NULL); + break; + default: + ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC || + blk->magic == + XFS_DIRX_LEAF_MAGIC(state->mp)); + break; + } + } + } + *result = 0; + return(0); +} + + +/*======================================================================== + * Utility routines. + *========================================================================*/ + +/* + * Implement a simple hash on a character string. + * Rotate the hash value by 7 bits, then XOR each character in. + * This is implemented with some source-level loop unrolling. + */ +xfs_dahash_t +xfs_da_hashname(char *name, int namelen) +{ + xfs_dahash_t hash; + +#define ROTL(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#ifdef SLOWVERSION + /* + * This is the old one-byte-at-a-time version. + */ + for (hash = 0; namelen > 0; namelen--) { + hash = *name++ ^ ROTL(hash, 7); + } + return(hash); +#else + /* + * Do four characters at a time as long as we can. + */ + for (hash = 0; namelen >= 4; namelen -= 4, name += 4) { + hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^ + (name[3] << 0) ^ ROTL(hash, 7 * 4); + } + /* + * Now do the rest of the characters. + */ + switch (namelen) { + case 3: + return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^ + ROTL(hash, 7 * 3); + case 2: + return (name[0] << 7) ^ (name[1] << 0) ^ ROTL(hash, 7 * 2); + case 1: + return (name[0] << 0) ^ ROTL(hash, 7 * 1); + case 0: + return hash; + } + /* NOTREACHED */ +#endif +#undef ROTL + return 0; /* keep gcc happy */ +} + +/* + * Add a block to the btree ahead of the file. + * Return the new block number to the caller. + */ +int +xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno) +{ + xfs_fileoff_t bno, b; + xfs_bmbt_irec_t map; + xfs_bmbt_irec_t *mapp; + xfs_inode_t *dp; + int nmap, error, w, count, c, got, i, mapi; + xfs_fsize_t size; + xfs_trans_t *tp; + xfs_mount_t *mp; + + dp = args->dp; + mp = dp->i_mount; + w = args->whichfork; + tp = args->trans; + /* + * For new directories adjust the file offset and block count. + */ + if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) { + bno = mp->m_dirleafblk; + count = mp->m_dirblkfsbs; + } else { + bno = 0; + count = 1; + } + /* + * Find a spot in the file space to put the new block. + */ + if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, w))) { + return error; + } + if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) + ASSERT(bno >= mp->m_dirleafblk && bno < mp->m_dirfreeblk); + /* + * Try mapping it in one filesystem block. + */ + nmap = 1; + ASSERT(args->firstblock != NULL); + if ((error = xfs_bmapi(tp, dp, bno, count, + XFS_BMAPI_AFLAG(w)|XFS_BMAPI_WRITE|XFS_BMAPI_METADATA| + XFS_BMAPI_CONTIG, + args->firstblock, args->total, &map, &nmap, + args->flist))) { + return error; + } + ASSERT(nmap <= 1); + if (nmap == 1) { + mapp = ↦ + mapi = 1; + } + /* + * If we didn't get it and the block might work if fragmented, + * try without the CONTIG flag. Loop until we get it all. + */ + else if (nmap == 0 && count > 1) { + mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP); + for (b = bno, mapi = 0; b < bno + count; ) { + nmap = MIN(XFS_BMAP_MAX_NMAP, count); + c = (int)(bno + count - b); + if ((error = xfs_bmapi(tp, dp, b, c, + XFS_BMAPI_AFLAG(w)|XFS_BMAPI_WRITE| + XFS_BMAPI_METADATA, + args->firstblock, args->total, + &mapp[mapi], &nmap, args->flist))) { + kmem_free(mapp, sizeof(*mapp) * count); + return error; + } + if (nmap < 1) + break; + mapi += nmap; + b = mapp[mapi - 1].br_startoff + + mapp[mapi - 1].br_blockcount; + } + } else { + mapi = 0; + mapp = NULL; + } + /* + * Count the blocks we got, make sure it matches the total. + */ + for (i = 0, got = 0; i < mapi; i++) + got += mapp[i].br_blockcount; + if (got != count || mapp[0].br_startoff != bno || + mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != + bno + count) { + if (mapp != &map) + kmem_free(mapp, sizeof(*mapp) * count); + return XFS_ERROR(ENOSPC); + } + if (mapp != &map) + kmem_free(mapp, sizeof(*mapp) * count); + *new_blkno = (xfs_dablk_t)bno; + /* + * For version 1 directories, adjust the file size if it changed. + */ + if (w == XFS_DATA_FORK && XFS_DIR_IS_V1(mp)) { + ASSERT(mapi == 1); + if ((error = xfs_bmap_last_offset(tp, dp, &bno, w))) + return error; + size = XFS_FSB_TO_B(mp, bno); + if (size != dp->i_d.di_size) { + dp->i_d.di_size = size; + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + } + } + return 0; +} + + +/* + * Ick. We need to always be able to remove a btree block, even + * if there's no space reservation because the filesystem is full. + * This is called if xfs_bunmapi on a btree block fails due to ENOSPC. + * It swaps the target block with the last block in the file. The + * last block in the file can always be removed since it can't cause + * a bmap btree split to do that. + */ +STATIC int +xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop, + xfs_dabuf_t **dead_bufp) +{ + xfs_dablk_t dead_blkno, last_blkno, sib_blkno, par_blkno; + xfs_dabuf_t *dead_buf, *last_buf, *sib_buf, *par_buf; + xfs_fileoff_t lastoff; + xfs_inode_t *ip; + xfs_trans_t *tp; + xfs_mount_t *mp; + int error, w, entno, level, dead_level; + xfs_da_blkinfo_t *dead_info, *sib_info; + xfs_da_intnode_t *par_node, *dead_node; + xfs_dir_leafblock_t *dead_leaf; + xfs_dir2_leaf_t *dead_leaf2; + xfs_dahash_t dead_hash; + + dead_buf = *dead_bufp; + dead_blkno = *dead_blknop; + tp = args->trans; + ip = args->dp; + w = args->whichfork; + ASSERT(w == XFS_DATA_FORK); + mp = ip->i_mount; + if (XFS_DIR_IS_V2(mp)) { + lastoff = mp->m_dirfreeblk; + error = xfs_bmap_last_before(tp, ip, &lastoff, w); + } else + error = xfs_bmap_last_offset(tp, ip, &lastoff, w); + if (error) + return error; + if (lastoff == 0) + return XFS_ERROR(EFSCORRUPTED); + /* + * Read the last block in the btree space. + */ + last_blkno = (xfs_dablk_t)lastoff - mp->m_dirblkfsbs; + if ((error = xfs_da_read_buf(tp, ip, last_blkno, -1, &last_buf, w))) + return error; + /* + * Copy the last block into the dead buffer and log it. + */ + bcopy(last_buf->data, dead_buf->data, mp->m_dirblksize); + xfs_da_log_buf(tp, dead_buf, 0, mp->m_dirblksize - 1); + dead_info = dead_buf->data; + /* + * Get values from the moved block. + */ + if (INT_GET(dead_info->magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC) { + ASSERT(XFS_DIR_IS_V1(mp)); + dead_leaf = (xfs_dir_leafblock_t *)dead_info; + dead_level = 0; + dead_hash = + INT_GET(dead_leaf->entries[INT_GET(dead_leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); + } else if (INT_GET(dead_info->magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC) { + ASSERT(XFS_DIR_IS_V2(mp)); + dead_leaf2 = (xfs_dir2_leaf_t *)dead_info; + dead_level = 0; + dead_hash = INT_GET(dead_leaf2->ents[INT_GET(dead_leaf2->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); + } else { + ASSERT(INT_GET(dead_info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + dead_node = (xfs_da_intnode_t *)dead_info; + dead_level = INT_GET(dead_node->hdr.level, ARCH_CONVERT); + dead_hash = INT_GET(dead_node->btree[INT_GET(dead_node->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); + } + sib_buf = par_buf = NULL; + /* + * If the moved block has a left sibling, fix up the pointers. + */ + if ((sib_blkno = INT_GET(dead_info->back, ARCH_CONVERT))) { + if ((error = xfs_da_read_buf(tp, ip, sib_blkno, -1, &sib_buf, w))) + goto done; + sib_info = sib_buf->data; + if (INT_GET(sib_info->forw, ARCH_CONVERT) != last_blkno || + INT_GET(sib_info->magic, ARCH_CONVERT) != INT_GET(dead_info->magic, ARCH_CONVERT)) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + INT_SET(sib_info->forw, ARCH_CONVERT, dead_blkno); + xfs_da_log_buf(tp, sib_buf, + XFS_DA_LOGRANGE(sib_info, &sib_info->forw, + sizeof(sib_info->forw))); + xfs_da_buf_done(sib_buf); + sib_buf = NULL; + } + /* + * If the moved block has a right sibling, fix up the pointers. + */ + if ((sib_blkno = INT_GET(dead_info->forw, ARCH_CONVERT))) { + if ((error = xfs_da_read_buf(tp, ip, sib_blkno, -1, &sib_buf, w))) + goto done; + sib_info = sib_buf->data; + if ( INT_GET(sib_info->back, ARCH_CONVERT) != last_blkno + || INT_GET(sib_info->magic, ARCH_CONVERT) + != INT_GET(dead_info->magic, ARCH_CONVERT)) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + INT_SET(sib_info->back, ARCH_CONVERT, dead_blkno); + xfs_da_log_buf(tp, sib_buf, + XFS_DA_LOGRANGE(sib_info, &sib_info->back, + sizeof(sib_info->back))); + xfs_da_buf_done(sib_buf); + sib_buf = NULL; + } + par_blkno = XFS_DIR_IS_V1(mp) ? 0 : mp->m_dirleafblk; + level = -1; + /* + * Walk down the tree looking for the parent of the moved block. + */ + for (;;) { + if ((error = xfs_da_read_buf(tp, ip, par_blkno, -1, &par_buf, w))) + goto done; + par_node = par_buf->data; + if (INT_GET(par_node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC || + (level >= 0 && level != INT_GET(par_node->hdr.level, ARCH_CONVERT) + 1)) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + level = INT_GET(par_node->hdr.level, ARCH_CONVERT); + for (entno = 0; + entno < INT_GET(par_node->hdr.count, ARCH_CONVERT) && + INT_GET(par_node->btree[entno].hashval, ARCH_CONVERT) < dead_hash; + entno++) + continue; + if (entno == INT_GET(par_node->hdr.count, ARCH_CONVERT)) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + par_blkno = INT_GET(par_node->btree[entno].before, ARCH_CONVERT); + if (level == dead_level + 1) + break; + xfs_da_brelse(tp, par_buf); + par_buf = NULL; + } + /* + * We're in the right parent block. + * Look for the right entry. + */ + for (;;) { + for (; + entno < INT_GET(par_node->hdr.count, ARCH_CONVERT) && + INT_GET(par_node->btree[entno].before, ARCH_CONVERT) != last_blkno; + entno++) + continue; + if (entno < INT_GET(par_node->hdr.count, ARCH_CONVERT)) + break; + par_blkno = INT_GET(par_node->hdr.info.forw, ARCH_CONVERT); + xfs_da_brelse(tp, par_buf); + par_buf = NULL; + if (par_blkno == 0) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + if ((error = xfs_da_read_buf(tp, ip, par_blkno, -1, &par_buf, w))) + goto done; + par_node = par_buf->data; + if (INT_GET(par_node->hdr.level, ARCH_CONVERT) != level || + INT_GET(par_node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + entno = 0; + } + /* + * Update the parent entry pointing to the moved block. + */ + INT_SET(par_node->btree[entno].before, ARCH_CONVERT, dead_blkno); + xfs_da_log_buf(tp, par_buf, + XFS_DA_LOGRANGE(par_node, &par_node->btree[entno].before, + sizeof(par_node->btree[entno].before))); + xfs_da_buf_done(par_buf); + xfs_da_buf_done(dead_buf); + *dead_blknop = last_blkno; + *dead_bufp = last_buf; + return 0; +done: + if (par_buf) + xfs_da_brelse(tp, par_buf); + if (sib_buf) + xfs_da_brelse(tp, sib_buf); + xfs_da_brelse(tp, last_buf); + return error; +} + +/* + * Remove a btree block from a directory or attribute. + */ +int +xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, + xfs_dabuf_t *dead_buf) +{ + xfs_inode_t *dp; + int done, error, w, count; + xfs_fileoff_t bno; + xfs_fsize_t size; + xfs_trans_t *tp; + xfs_mount_t *mp; + + dp = args->dp; + w = args->whichfork; + tp = args->trans; + mp = dp->i_mount; + if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) + count = mp->m_dirblkfsbs; + else + count = 1; + for (;;) { + /* + * Remove extents. If we get ENOSPC for a dir we have to move + * the last block to the place we want to kill. + */ + if ((error = xfs_bunmapi(tp, dp, dead_blkno, count, + XFS_BMAPI_AFLAG(w)|XFS_BMAPI_METADATA, + 0, args->firstblock, args->flist, + &done)) == ENOSPC) { + if (w != XFS_DATA_FORK) + goto done; + if ((error = xfs_da_swap_lastblock(args, &dead_blkno, + &dead_buf))) + goto done; + } else if (error) + goto done; + else + break; + } + ASSERT(done); + xfs_da_binval(tp, dead_buf); + /* + * Adjust the directory size for version 1. + */ + if (w == XFS_DATA_FORK && XFS_DIR_IS_V1(mp)) { + if ((error = xfs_bmap_last_offset(tp, dp, &bno, w))) + return error; + size = XFS_FSB_TO_B(dp->i_mount, bno); + if (size != dp->i_d.di_size) { + dp->i_d.di_size = size; + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + } + } + return 0; +done: + xfs_da_binval(tp, dead_buf); + return error; +} + +/* + * See if the mapping(s) for this btree block are valid, i.e. + * don't contain holes, are logically contiguous, and cover the whole range. + */ +STATIC int +xfs_da_map_covers_blocks( + int nmap, + xfs_bmbt_irec_t *mapp, + xfs_dablk_t bno, + int count) +{ + int i; + xfs_fileoff_t off; + + for (i = 0, off = bno; i < nmap; i++) { + if (mapp[i].br_startblock == HOLESTARTBLOCK || + mapp[i].br_startblock == DELAYSTARTBLOCK) { + return 0; + } + if (off != mapp[i].br_startoff) { + return 0; + } + off += mapp[i].br_blockcount; + } + return off == bno + count; +} + +/* + * Make a dabuf. + * Used for get_buf, read_buf, read_bufr, and reada_buf. + */ +STATIC int +xfs_da_do_buf( + xfs_trans_t *trans, + xfs_inode_t *dp, + xfs_dablk_t bno, + xfs_daddr_t *mappedbnop, + xfs_dabuf_t **bpp, + int whichfork, + int caller, + inst_t *ra) +{ + xfs_buf_t *bp = 0; + xfs_buf_t **bplist; + int error=0; + int i; + xfs_bmbt_irec_t map; + xfs_bmbt_irec_t *mapp; + xfs_daddr_t mappedbno; + xfs_mount_t *mp; + int nbplist=0; + int nfsb; + int nmap; + xfs_dabuf_t *rbp; + + mp = dp->i_mount; + if (whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) + nfsb = mp->m_dirblkfsbs; + else + nfsb = 1; + mappedbno = *mappedbnop; + /* + * Caller doesn't have a mapping. -2 means don't complain + * if we land in a hole. + */ + if (mappedbno == -1 || mappedbno == -2) { + /* + * Optimize the one-block case. + */ + if (nfsb == 1) { + xfs_fsblock_t fsb; + + if ((error = + xfs_bmapi_single(trans, dp, whichfork, &fsb, + (xfs_fileoff_t)bno))) { + return error; + } + mapp = ↦ + if (fsb == NULLFSBLOCK) { + nmap = 0; + } else { + map.br_startblock = fsb; + map.br_startoff = (xfs_fileoff_t)bno; + map.br_blockcount = 1; + nmap = 1; + } + } else { + xfs_fsblock_t firstblock; + + firstblock = NULLFSBLOCK; + mapp = kmem_alloc(sizeof(*mapp) * nfsb, + trans ? KM_SLEEP : KM_SLEEP_IO); + nmap = nfsb; + if ((error = xfs_bmapi(trans, dp, (xfs_fileoff_t)bno, + nfsb, + XFS_BMAPI_METADATA | + XFS_BMAPI_AFLAG(whichfork), + &firstblock, 0, mapp, &nmap, NULL))) + goto exit0; + } + } else { + map.br_startblock = XFS_DADDR_TO_FSB(mp, mappedbno); + map.br_startoff = (xfs_fileoff_t)bno; + map.br_blockcount = nfsb; + mapp = ↦ + nmap = 1; + } + if (!xfs_da_map_covers_blocks(nmap, mapp, bno, nfsb)) { + error = mappedbno == -2 ? 0 : XFS_ERROR(EFSCORRUPTED); + goto exit0; + } + if (caller != 3 && nmap > 1) { + bplist = kmem_alloc(sizeof(*bplist) * nmap, KM_SLEEP); + nbplist = 0; + } else + bplist = NULL; + /* + * Turn the mapping(s) into buffer(s). + */ + for (i = 0; i < nmap; i++) { + int nmapped; + + mappedbno = XFS_FSB_TO_DADDR(mp, mapp[i].br_startblock); + if (i == 0) + *mappedbnop = mappedbno; + nmapped = (int)XFS_FSB_TO_BB(mp, mapp[i].br_blockcount); + switch (caller) { + case 0: + bp = xfs_trans_get_buf(trans, mp->m_ddev_targp, + mappedbno, nmapped, 0); + error = bp ? XFS_BUF_GETERROR(bp) : XFS_ERROR(EIO); + break; + case 1: +#ifndef __KERNEL__ + case 2: +#endif + bp = NULL; + error = xfs_trans_read_buf(mp, trans, mp->m_ddev_targp, + mappedbno, nmapped, 0, &bp); + break; +#ifdef __KERNEL__ + case 3: + xfs_baread(mp->m_ddev_targp, mappedbno, nmapped); + error = 0; + bp = NULL; + break; +#endif + } + if (error) { + if (bp) + xfs_trans_brelse(trans, bp); + goto exit1; + } + if (!bp) + continue; + if (caller == 1) { + if (whichfork == XFS_ATTR_FORK) { + XFS_BUF_SET_VTYPE_REF(bp, B_FS_ATTR_BTREE, + XFS_ATTR_BTREE_REF); + } else { + XFS_BUF_SET_VTYPE_REF(bp, B_FS_DIR_BTREE, + XFS_DIR_BTREE_REF); + } + } + if (bplist) { + bplist[nbplist++] = bp; + } + } + /* + * Build a dabuf structure. + */ + if (bplist) { + rbp = xfs_da_buf_make(nbplist, bplist, ra); + } else if (bp) + rbp = xfs_da_buf_make(1, &bp, ra); + else + rbp = NULL; + /* + * For read_buf, check the magic number. + */ + if (caller == 1) { + xfs_dir2_data_t *data; + xfs_dir2_free_t *free; + xfs_da_blkinfo_t *info; + + info = rbp->data; + data = rbp->data; + free = rbp->data; + if (XFS_TEST_ERROR((INT_GET(info->magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) && + (INT_GET(info->magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) && + (INT_GET(info->magic, ARCH_CONVERT) != XFS_ATTR_LEAF_MAGIC) && + (INT_GET(info->magic, ARCH_CONVERT) != XFS_DIR2_LEAF1_MAGIC) && + (INT_GET(info->magic, ARCH_CONVERT) != XFS_DIR2_LEAFN_MAGIC) && + (INT_GET(data->hdr.magic, ARCH_CONVERT) != XFS_DIR2_BLOCK_MAGIC) && + (INT_GET(data->hdr.magic, ARCH_CONVERT) != XFS_DIR2_DATA_MAGIC) && + (INT_GET(free->hdr.magic, ARCH_CONVERT) != XFS_DIR2_FREE_MAGIC), + mp, XFS_ERRTAG_DA_READ_BUF, + XFS_RANDOM_DA_READ_BUF)) { + xfs_buftrace("DA READ ERROR", rbp->bps[0]); + error = XFS_ERROR(EFSCORRUPTED); + xfs_da_brelse(trans, rbp); + nbplist = 0; + goto exit1; + } + } + if (bplist) { + kmem_free(bplist, sizeof(*bplist) * nmap); + } + if (mapp != &map) { + kmem_free(mapp, sizeof(*mapp) * nfsb); + } + if (bpp) + *bpp = rbp; + return 0; +exit1: + if (bplist) { + for (i = 0; i < nbplist; i++) + xfs_trans_brelse(trans, bplist[i]); + kmem_free(bplist, sizeof(*bplist) * nmap); + } +exit0: + if (mapp != &map) + kmem_free(mapp, sizeof(*mapp) * nfsb); + if (bpp) + *bpp = NULL; + return error; +} + +/* + * Get a buffer for the dir/attr block. + */ +int +xfs_da_get_buf( + xfs_trans_t *trans, + xfs_inode_t *dp, + xfs_dablk_t bno, + xfs_daddr_t mappedbno, + xfs_dabuf_t **bpp, + int whichfork) +{ + return xfs_da_do_buf(trans, dp, bno, &mappedbno, bpp, whichfork, 0, + (inst_t *)__return_address); +} + +/* + * Get a buffer for the dir/attr block, fill in the contents. + */ +int +xfs_da_read_buf( + xfs_trans_t *trans, + xfs_inode_t *dp, + xfs_dablk_t bno, + xfs_daddr_t mappedbno, + xfs_dabuf_t **bpp, + int whichfork) +{ + return xfs_da_do_buf(trans, dp, bno, &mappedbno, bpp, whichfork, 1, + (inst_t *)__return_address); +} + +/* + * Calculate the number of bits needed to hold i different values. + */ +uint +xfs_da_log2_roundup(uint i) +{ + uint rval; + + for (rval = 0; rval < NBBY * sizeof(i); rval++) { + if ((1 << rval) >= i) + break; + } + return(rval); +} + +xfs_zone_t *xfs_da_state_zone; /* anchor for state struct zone */ +xfs_zone_t *xfs_dabuf_zone; /* dabuf zone */ + +/* + * Allocate a dir-state structure. + * We don't put them on the stack since they're large. + */ +xfs_da_state_t * +xfs_da_state_alloc(void) +{ + return kmem_zone_zalloc(xfs_da_state_zone, KM_SLEEP); +} + +/* + * Kill the altpath contents of a da-state structure. + */ +void +xfs_da_state_kill_altpath(xfs_da_state_t *state) +{ + int i; + + for (i = 0; i < state->altpath.active; i++) { + if (state->altpath.blk[i].bp) { + if (state->altpath.blk[i].bp != state->path.blk[i].bp) + xfs_da_buf_done(state->altpath.blk[i].bp); + state->altpath.blk[i].bp = NULL; + } + } + state->altpath.active = 0; +} + +/* + * Free a da-state structure. + */ +void +xfs_da_state_free(xfs_da_state_t *state) +{ + int i; + + xfs_da_state_kill_altpath(state); + for (i = 0; i < state->path.active; i++) { + if (state->path.blk[i].bp) + xfs_da_buf_done(state->path.blk[i].bp); + } + if (state->extravalid && state->extrablk.bp) + xfs_da_buf_done(state->extrablk.bp); +#ifdef DEBUG + bzero((char *)state, sizeof(*state)); +#endif /* DEBUG */ + kmem_zone_free(xfs_da_state_zone, state); +} + +#ifdef XFS_DABUF_DEBUG +xfs_dabuf_t *xfs_dabuf_global_list; +lock_t xfs_dabuf_global_lock; +#endif + +/* + * Create a dabuf. + */ +/* ARGSUSED */ +STATIC xfs_dabuf_t * +xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra) +{ + xfs_buf_t *bp; + xfs_dabuf_t *dabuf; + int i; + int off; + + if (nbuf == 1) + dabuf = kmem_zone_alloc(xfs_dabuf_zone, KM_SLEEP); + else + dabuf = kmem_alloc(XFS_DA_BUF_SIZE(nbuf), KM_SLEEP); + dabuf->dirty = 0; +#ifdef XFS_DABUF_DEBUG + dabuf->ra = ra; + dabuf->dev = XFS_BUF_TARGET(bps[0]); + dabuf->blkno = XFS_BUF_ADDR(bps[0]); +#endif + if (nbuf == 1) { + dabuf->nbuf = 1; + bp = bps[0]; + dabuf->bbcount = (short)BTOBB(XFS_BUF_COUNT(bp)); + dabuf->data = XFS_BUF_PTR(bp); + dabuf->bps[0] = bp; + } else { + dabuf->nbuf = nbuf; + for (i = 0, dabuf->bbcount = 0; i < nbuf; i++) { + dabuf->bps[i] = bp = bps[i]; + dabuf->bbcount += BTOBB(XFS_BUF_COUNT(bp)); + } + dabuf->data = kmem_alloc(BBTOB(dabuf->bbcount), KM_SLEEP); + for (i = off = 0; i < nbuf; i++, off += XFS_BUF_COUNT(bp)) { + bp = bps[i]; + bcopy(XFS_BUF_PTR(bp), (char *)dabuf->data + off, + XFS_BUF_COUNT(bp)); + } + } +#ifdef XFS_DABUF_DEBUG + { + int s; + xfs_dabuf_t *p; + + s = mutex_spinlock(&xfs_dabuf_global_lock); + for (p = xfs_dabuf_global_list; p; p = p->next) { + ASSERT(p->blkno != dabuf->blkno || + p->dev != dabuf->dev); + } + dabuf->prev = NULL; + if (xfs_dabuf_global_list) + xfs_dabuf_global_list->prev = dabuf; + dabuf->next = xfs_dabuf_global_list; + xfs_dabuf_global_list = dabuf; + mutex_spinunlock(&xfs_dabuf_global_lock, s); + } +#endif + return dabuf; +} + +/* + * Un-dirty a dabuf. + */ +STATIC void +xfs_da_buf_clean(xfs_dabuf_t *dabuf) +{ + xfs_buf_t *bp; + int i; + int off; + + if (dabuf->dirty) { + ASSERT(dabuf->nbuf > 1); + dabuf->dirty = 0; + for (i = off = 0; i < dabuf->nbuf; + i++, off += XFS_BUF_COUNT(bp)) { + bp = dabuf->bps[i]; + bcopy((char *)dabuf->data + off, XFS_BUF_PTR(bp), + XFS_BUF_COUNT(bp)); + } + } +} + +/* + * Release a dabuf. + */ +void +xfs_da_buf_done(xfs_dabuf_t *dabuf) +{ + ASSERT(dabuf); + ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]); + if (dabuf->dirty) + xfs_da_buf_clean(dabuf); + if (dabuf->nbuf > 1) + kmem_free(dabuf->data, BBTOB(dabuf->bbcount)); +#ifdef XFS_DABUF_DEBUG + { + int s; + + s = mutex_spinlock(&xfs_dabuf_global_lock); + if (dabuf->prev) + dabuf->prev->next = dabuf->next; + else + xfs_dabuf_global_list = dabuf->next; + if (dabuf->next) + dabuf->next->prev = dabuf->prev; + mutex_spinunlock(&xfs_dabuf_global_lock, s); + } + bzero(dabuf, XFS_DA_BUF_SIZE(dabuf->nbuf)); +#endif + if (dabuf->nbuf == 1) + kmem_zone_free(xfs_dabuf_zone, dabuf); + else + kmem_free(dabuf, XFS_DA_BUF_SIZE(dabuf->nbuf)); +} + +/* + * Log transaction from a dabuf. + */ +void +xfs_da_log_buf(xfs_trans_t *tp, xfs_dabuf_t *dabuf, uint first, uint last) +{ + xfs_buf_t *bp; + uint f; + int i; + uint l; + int off; + + ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]); + if (dabuf->nbuf == 1) { + ASSERT(dabuf->data == (void *)XFS_BUF_PTR(dabuf->bps[0])); + xfs_trans_log_buf(tp, dabuf->bps[0], first, last); + return; + } + dabuf->dirty = 1; + ASSERT(first <= last); + for (i = off = 0; i < dabuf->nbuf; i++, off += XFS_BUF_COUNT(bp)) { + bp = dabuf->bps[i]; + f = off; + l = f + XFS_BUF_COUNT(bp) - 1; + if (f < first) + f = first; + if (l > last) + l = last; + if (f <= l) + xfs_trans_log_buf(tp, bp, f - off, l - off); + /* + * B_DONE is set by xfs_trans_log buf. + * If we don't set it on a new buffer (get not read) + * then if we don't put anything in the buffer it won't + * be set, and at commit it it released into the cache, + * and then a read will fail. + */ + else if (!(XFS_BUF_ISDONE(bp))) + XFS_BUF_DONE(bp); + } + ASSERT(last < off); +} + +/* + * Release dabuf from a transaction. + * Have to free up the dabuf before the buffers are released, + * since the synchronization on the dabuf is really the lock on the buffer. + */ +void +xfs_da_brelse(xfs_trans_t *tp, xfs_dabuf_t *dabuf) +{ + xfs_buf_t *bp; + xfs_buf_t **bplist; + int i; + int nbuf; + + ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]); + if ((nbuf = dabuf->nbuf) == 1) { + bplist = &bp; + bp = dabuf->bps[0]; + } else { + bplist = kmem_alloc(nbuf * sizeof(*bplist), KM_SLEEP); + bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist)); + } + xfs_da_buf_done(dabuf); + for (i = 0; i < nbuf; i++) + xfs_trans_brelse(tp, bplist[i]); + if (bplist != &bp) + kmem_free(bplist, nbuf * sizeof(*bplist)); +} + +/* + * Invalidate dabuf from a transaction. + */ +void +xfs_da_binval(xfs_trans_t *tp, xfs_dabuf_t *dabuf) +{ + xfs_buf_t *bp; + xfs_buf_t **bplist; + int i; + int nbuf; + + ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]); + if ((nbuf = dabuf->nbuf) == 1) { + bplist = &bp; + bp = dabuf->bps[0]; + } else { + bplist = kmem_alloc(nbuf * sizeof(*bplist), KM_SLEEP); + bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist)); + } + xfs_da_buf_done(dabuf); + for (i = 0; i < nbuf; i++) + xfs_trans_binval(tp, bplist[i]); + if (bplist != &bp) + kmem_free(bplist, nbuf * sizeof(*bplist)); +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir.c Wed Apr 18 21:41:37 2001 @@ -0,0 +1,622 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * xfs_dir.c + * + * Provide the external interfaces to manage directories. + */ + + +xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot; + +/* + * One-time startup routine called from xfs_init(). + */ +void +xfs_dir_startup(void) +{ + xfs_dir_hash_dot = xfs_da_hashname(".", 1); + xfs_dir_hash_dotdot = xfs_da_hashname("..", 2); +} + +/* + * Initialize directory-related fields in the mount structure. + */ +STATIC void +xfs_dir_mount(xfs_mount_t *mp) +{ + uint shortcount, leafcount, count; + + mp->m_dirversion = 1; + shortcount = (mp->m_attroffset - (uint)sizeof(xfs_dir_sf_hdr_t)) / + (uint)sizeof(xfs_dir_sf_entry_t); + leafcount = (XFS_LBSIZE(mp) - (uint)sizeof(xfs_dir_leaf_hdr_t)) / + ((uint)sizeof(xfs_dir_leaf_entry_t) + + (uint)sizeof(xfs_dir_leaf_name_t)); + count = shortcount > leafcount ? shortcount : leafcount; + mp->m_dircook_elog = xfs_da_log2_roundup(count + 1); + ASSERT(mp->m_dircook_elog <= mp->m_sb.sb_blocklog); + mp->m_da_node_ents = + (XFS_LBSIZE(mp) - (uint)sizeof(xfs_da_node_hdr_t)) / + (uint)sizeof(xfs_da_node_entry_t); + mp->m_dir_magicpct = (XFS_LBSIZE(mp) * 37) / 100; + mp->m_dirblksize = mp->m_sb.sb_blocksize; + mp->m_dirblkfsbs = 1; +} + +/* + * Initialize a directory with its "." and ".." entries. + */ +STATIC int +xfs_dir_init(xfs_trans_t *trans, xfs_inode_t *dir, xfs_inode_t *parent_dir) +{ + xfs_da_args_t args; + int error; + + bzero((char *)&args, sizeof(args)); + args.dp = dir; + args.trans = trans; + + ASSERT((dir->i_d.di_mode & IFMT) == IFDIR); + if ((error = xfs_dir_ino_validate(trans->t_mountp, parent_dir->i_ino))) + return error; + + return(xfs_dir_shortform_create(&args, parent_dir->i_ino)); +} + +/* + * Generic handler routine to add a name to a directory. + * Transitions directory from shortform to Btree as necessary. + */ +STATIC int /* error */ +xfs_dir_createname(xfs_trans_t *trans, xfs_inode_t *dp, char *name, + int namelen, xfs_ino_t inum, xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, xfs_extlen_t total) +{ + xfs_da_args_t args; + int retval, newsize, done; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + + if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum))) + return (retval); + + XFS_STATS_INC(xfsstats.xs_dir_create); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = inum; + args.dp = dp; + args.firstblock = firstblock; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = trans; + args.justcheck = 0; + args.addname = args.oknoent = 1; + + /* + * Decide on what work routines to call based on the inode size. + */ + done = 0; + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + newsize = XFS_DIR_SF_ENTSIZE_BYNAME(args.namelen); + if ((dp->i_d.di_size + newsize) <= XFS_IFORK_DSIZE(dp)) { + retval = xfs_dir_shortform_addname(&args); + done = 1; + } else { + if (total == 0) + return XFS_ERROR(ENOSPC); + retval = xfs_dir_shortform_to_leaf(&args); + done = retval != 0; + } + } + if (!done && xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_addname(&args); + done = retval != ENOSPC; + if (!done) { + if (total == 0) + return XFS_ERROR(ENOSPC); + retval = xfs_dir_leaf_to_node(&args); + done = retval != 0; + } + } + if (!done) { + retval = xfs_dir_node_addname(&args); + } + return(retval); +} + +/* + * Generic handler routine to remove a name from a directory. + * Transitions directory from Btree to shortform as necessary. + */ +STATIC int /* error */ +xfs_dir_removename(xfs_trans_t *trans, xfs_inode_t *dp, char *name, + int namelen, xfs_ino_t ino, xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, xfs_extlen_t total) +{ + xfs_da_args_t args; + int count, totallen, newsize, retval; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + XFS_STATS_INC(xfsstats.xs_dir_remove); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = ino; + args.dp = dp; + args.firstblock = firstblock; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = trans; + args.justcheck = args.addname = args.oknoent = 0; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + retval = xfs_dir_shortform_removename(&args); + } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_removename(&args, &count, &totallen); + if (retval == 0) { + newsize = XFS_DIR_SF_ALLFIT(count, totallen); + if (newsize <= XFS_IFORK_DSIZE(dp)) { + retval = xfs_dir_leaf_to_shortform(&args); + } + } + } else { + retval = xfs_dir_node_removename(&args); + } + return(retval); +} + +STATIC int /* error */ +xfs_dir_lookup(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen, + xfs_ino_t *inum) +{ + xfs_da_args_t args; + int retval; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (namelen >= MAXNAMELEN) { + return(XFS_ERROR(EINVAL)); + } + + XFS_STATS_INC(xfsstats.xs_dir_lookup); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = 0; + args.dp = dp; + args.firstblock = NULL; + args.flist = NULL; + args.total = 0; + args.whichfork = XFS_DATA_FORK; + args.trans = trans; + args.justcheck = args.addname = 0; + args.oknoent = 1; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + retval = xfs_dir_shortform_lookup(&args); + } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_lookup(&args); + } else { + retval = xfs_dir_node_lookup(&args); + } + if (retval == EEXIST) + retval = 0; + *inum = args.inumber; + return(retval); +} + +STATIC int /* error */ +xfs_dir_replace(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen, + xfs_ino_t inum, xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, xfs_extlen_t total) +{ + xfs_da_args_t args; + int retval; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (namelen >= MAXNAMELEN) { + return(XFS_ERROR(EINVAL)); + } + + if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum))) + return retval; + + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = inum; + args.dp = dp; + args.firstblock = firstblock; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = trans; + args.justcheck = args.addname = args.oknoent = 0; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + retval = xfs_dir_shortform_replace(&args); + } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_replace(&args); + } else { + retval = xfs_dir_node_replace(&args); + } + + return(retval); +} + + +/*======================================================================== + * External routines when dirsize == XFS_LBSIZE(dp->i_mount). + *========================================================================*/ + +/* + * Add a name to the leaf directory structure + * This is the external routine. + */ +int +xfs_dir_leaf_addname(xfs_da_args_t *args) +{ + int index, retval; + xfs_dabuf_t *bp; + + retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + + retval = xfs_dir_leaf_lookup_int(bp, args, &index); + if (retval == ENOENT) + retval = xfs_dir_leaf_add(bp, args, index); + xfs_da_buf_done(bp); + return(retval); +} + +/* + * Remove a name from the leaf directory structure + * This is the external routine. + */ +STATIC int +xfs_dir_leaf_removename(xfs_da_args_t *args, int *count, int *totallen) +{ + xfs_dir_leafblock_t *leaf; + int index, retval; + xfs_dabuf_t *bp; + + retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + retval = xfs_dir_leaf_lookup_int(bp, args, &index); + if (retval == EEXIST) { + (void)xfs_dir_leaf_remove(args->trans, bp, index); + *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + *totallen = INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); + retval = 0; + } + xfs_da_buf_done(bp); + return(retval); +} + +/* + * Look up a name in a leaf directory structure. + * This is the external routine. + */ +STATIC int +xfs_dir_leaf_lookup(xfs_da_args_t *args) +{ + int index, retval; + xfs_dabuf_t *bp; + + retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + retval = xfs_dir_leaf_lookup_int(bp, args, &index); + xfs_da_brelse(args->trans, bp); + return(retval); +} + +/* + * Look up a name in a leaf directory structure, replace the inode number. + * This is the external routine. + */ +STATIC int +xfs_dir_leaf_replace(xfs_da_args_t *args) +{ + int index, retval; + xfs_dabuf_t *bp; + xfs_ino_t inum; + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + + inum = args->inumber; + retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + retval = xfs_dir_leaf_lookup_int(bp, args, &index); + if (retval == EEXIST) { + leaf = bp->data; + entry = &leaf->entries[index]; + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + /* XXX - replace assert? */ + XFS_DIR_SF_PUT_DIRINO_ARCH(&inum, &namest->inumber, ARCH_CONVERT); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber))); + xfs_da_buf_done(bp); + retval = 0; + } else + xfs_da_brelse(args->trans, bp); + return(retval); +} + + +/*======================================================================== + * External routines when dirsize > XFS_LBSIZE(mp). + *========================================================================*/ + +/* + * Add a name to a Btree-format directory. + * + * This will involve walking down the Btree, and may involve splitting + * leaf nodes and even splitting intermediate nodes up to and including + * the root node (a special case of an intermediate node). + */ +STATIC int +xfs_dir_node_addname(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + xfs_da_state_blk_t *blk; + int retval, error; + + /* + * Fill in bucket of arguments/results/context to carry around. + */ + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + + /* + * Search to see if name already exists, and get back a pointer + * to where it should go. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) + retval = error; + if (retval != ENOENT) + goto error; + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); + retval = xfs_dir_leaf_add(blk->bp, args, blk->index); + if (retval == 0) { + /* + * Addition succeeded, update Btree hashvals. + */ + if (!args->justcheck) + xfs_da_fixhashpath(state, &state->path); + } else { + /* + * Addition failed, split as many Btree elements as required. + */ + if (args->total == 0) { + ASSERT(retval == ENOSPC); + goto error; + } + retval = xfs_da_split(state); + } +error: + xfs_da_state_free(state); + + return(retval); +} + +/* + * Remove a name from a B-tree directory. + * + * This will involve walking down the Btree, and may involve joining + * leaf nodes and even joining intermediate nodes up to and including + * the root node (a special case of an intermediate node). + */ +STATIC int +xfs_dir_node_removename(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + xfs_da_state_blk_t *blk; + int retval, error; + + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + + /* + * Search to see if name exists, and get back a pointer to it. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) + retval = error; + if (retval != EEXIST) { + xfs_da_state_free(state); + return(retval); + } + + /* + * Remove the name and update the hashvals in the tree. + */ + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); + retval = xfs_dir_leaf_remove(args->trans, blk->bp, blk->index); + xfs_da_fixhashpath(state, &state->path); + + /* + * Check to see if the tree needs to be collapsed. + */ + error = 0; + if (retval) { + error = xfs_da_join(state); + } + + xfs_da_state_free(state); + if (error) + return(error); + return(0); +} + +/* + * Look up a filename in a int directory. + * Use an internal routine to actually do all the work. + */ +STATIC int +xfs_dir_node_lookup(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + int retval, error, i; + + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + + /* + * Search to see if name exists, + * and get back a pointer to it. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) { + retval = error; + } + + /* + * If not in a transaction, we have to release all the buffers. + */ + for (i = 0; i < state->path.active; i++) { + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + + xfs_da_state_free(state); + return(retval); +} + +/* + * Look up a filename in an int directory, replace the inode number. + * Use an internal routine to actually do the lookup. + */ +STATIC int +xfs_dir_node_replace(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + xfs_da_state_blk_t *blk; + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + xfs_ino_t inum; + int retval, error, i; + xfs_dabuf_t *bp; + + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + inum = args->inumber; + + /* + * Search to see if name exists, + * and get back a pointer to it. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) { + retval = error; + } + + if (retval == EEXIST) { + blk = &state->path.blk[state->path.active - 1]; + ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); + bp = blk->bp; + leaf = bp->data; + entry = &leaf->entries[blk->index]; + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + /* XXX - replace assert ? */ + XFS_DIR_SF_PUT_DIRINO_ARCH(&inum, &namest->inumber, ARCH_CONVERT); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber))); + xfs_da_buf_done(bp); + blk->bp = NULL; + retval = 0; + } else { + i = state->path.active - 1; + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + for (i = 0; i < state->path.active - 1; i++) { + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + + xfs_da_state_free(state); + return(retval); +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir2.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir2.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir2.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir2.c Wed Apr 18 21:41:37 2001 @@ -0,0 +1,572 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * XFS v2 directory implmentation. + * Top-level and utility routines. + */ + +#include + + +/* + * Initialize directory-related fields in the mount structure. + */ +void +xfs_dir2_mount( + xfs_mount_t *mp) /* filesystem mount point */ +{ + mp->m_dirversion = 2; + ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <= + XFS_MAX_BLOCKSIZE); + mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog); + mp->m_dirblkfsbs = 1 << mp->m_sb.sb_dirblklog; + mp->m_dirdatablk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_DATA_FIRSTDB(mp)); + mp->m_dirleafblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_LEAF_FIRSTDB(mp)); + mp->m_dirfreeblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_FREE_FIRSTDB(mp)); + mp->m_da_node_ents = + (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) / + (uint)sizeof(xfs_da_node_entry_t); + mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100; +} + +/* + * Initialize a directory with its "." and ".." entries. + */ +int /* error */ +xfs_dir2_init( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + xfs_inode_t *pdp) /* incore parent directory inode */ +{ + xfs_da_args_t args; /* operation arguments */ + int error; /* error return value */ + + bzero((char *)&args, sizeof(args)); + args.dp = dp; + args.trans = tp; + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) { + return error; + } + return xfs_dir2_sf_create(&args, pdp->i_ino); +} + +/* + Enter a name in a directory. + */ +STATIC int /* error */ +xfs_dir2_createname( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + char *name, /* new entry name */ + int namelen, /* new entry name length */ + xfs_ino_t inum, /* new entry inode number */ + xfs_fsblock_t *first, /* bmap's firstblock */ + xfs_bmap_free_t *flist, /* bmap's freeblock list */ + xfs_extlen_t total) /* bmap's total block count */ +{ + xfs_da_args_t args; /* operation arguments */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) { + return rval; + } + XFS_STATS_INC(xfsstats.xs_dir_create); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = inum; + args.dp = dp; + args.firstblock = first; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = tp; + args.justcheck = 0; + args.addname = args.oknoent = 1; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_addname(&args); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_block_addname(&args); + else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_leaf_addname(&args); + else + rval = xfs_dir2_node_addname(&args); + return rval; +} + +/* + * Lookup a name in a directory, give back the inode number. + */ +STATIC int /* error */ +xfs_dir2_lookup( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + char *name, /* lookup name */ + int namelen, /* lookup name length */ + xfs_ino_t *inum) /* out: inode number */ +{ + xfs_da_args_t args; /* operation arguments */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (namelen >= MAXNAMELEN) { + return XFS_ERROR(EINVAL); + } + XFS_STATS_INC(xfsstats.xs_dir_lookup); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = 0; + args.dp = dp; + args.firstblock = NULL; + args.flist = NULL; + args.total = 0; + args.whichfork = XFS_DATA_FORK; + args.trans = tp; + args.justcheck = args.addname = 0; + args.oknoent = 1; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_lookup(&args); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_block_lookup(&args); + else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_leaf_lookup(&args); + else + rval = xfs_dir2_node_lookup(&args); + if (rval == EEXIST) + rval = 0; + if (rval == 0) + *inum = args.inumber; + return rval; +} + +/* + * Remove an entry from a directory. + */ +STATIC int /* error */ +xfs_dir2_removename( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + char *name, /* name of entry to remove */ + int namelen, /* name length of entry to remove */ + xfs_ino_t ino, /* inode number of entry to remove */ + xfs_fsblock_t *first, /* bmap's firstblock */ + xfs_bmap_free_t *flist, /* bmap's freeblock list */ + xfs_extlen_t total) /* bmap's total block count */ +{ + xfs_da_args_t args; /* operation arguments */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + XFS_STATS_INC(xfsstats.xs_dir_remove); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = ino; + args.dp = dp; + args.firstblock = first; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = tp; + args.justcheck = args.addname = args.oknoent = 0; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_removename(&args); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_block_removename(&args); + else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_leaf_removename(&args); + else + rval = xfs_dir2_node_removename(&args); + return rval; +} + +/* + * Replace the inode number of a directory entry. + */ +STATIC int /* error */ +xfs_dir2_replace( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + char *name, /* name of entry to replace */ + int namelen, /* name length of entry to replace */ + xfs_ino_t inum, /* new inode number */ + xfs_fsblock_t *first, /* bmap's firstblock */ + xfs_bmap_free_t *flist, /* bmap's freeblock list */ + xfs_extlen_t total) /* bmap's total block count */ +{ + xfs_da_args_t args; /* operation arguments */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (namelen >= MAXNAMELEN) { + return XFS_ERROR(EINVAL); + } + if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) { + return rval; + } + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = inum; + args.dp = dp; + args.firstblock = first; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = tp; + args.justcheck = args.addname = args.oknoent = 0; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_replace(&args); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_block_replace(&args); + else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_leaf_replace(&args); + else + rval = xfs_dir2_node_replace(&args); + return rval; +} + +/* + * Utility routines. + */ + +/* + * Add a block to the directory. + * This routine is for data and free blocks, not leaf/node blocks + * which are handled by xfs_da_grow_inode. + */ +int /* error */ +xfs_dir2_grow_inode( + xfs_da_args_t *args, /* operation arguments */ + int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */ + xfs_dir2_db_t *dbp) /* out: block number added */ +{ + xfs_fileoff_t bno; /* directory offset of new block */ + int count; /* count of filesystem blocks */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + int got; /* blocks actually mapped */ + int i; /* temp mapping index */ + xfs_bmbt_irec_t map; /* single structure for bmap */ + int mapi; /* mapping index */ + xfs_bmbt_irec_t *mapp; /* bmap mapping structure(s) */ + xfs_mount_t *mp; /* filesystem mount point */ + int nmap; /* number of bmap entries */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_s("grow_inode", args, space); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + /* + * Set lowest possible block in the space requested. + */ + bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE); + count = mp->m_dirblkfsbs; + /* + * Find the first hole for our block. + */ + if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, XFS_DATA_FORK))) { + return error; + } + nmap = 1; + ASSERT(args->firstblock != NULL); + /* + * Try mapping the new block contiguously (one extent). + */ + if ((error = xfs_bmapi(tp, dp, bno, count, + XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG, + args->firstblock, args->total, &map, &nmap, + args->flist))) { + return error; + } + ASSERT(nmap <= 1); + /* + * Got it in 1. + */ + if (nmap == 1) { + mapp = ↦ + mapi = 1; + } + /* + * Didn't work and this is a multiple-fsb directory block. + * Try again with contiguous flag turned on. + */ + else if (nmap == 0 && count > 1) { + xfs_fileoff_t b; /* current file offset */ + + /* + * Space for maximum number of mappings. + */ + mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP); + /* + * Iterate until we get to the end of our block. + */ + for (b = bno, mapi = 0; b < bno + count; ) { + int c; /* current fsb count */ + + /* + * Can't map more than MAX_NMAP at once. + */ + nmap = MIN(XFS_BMAP_MAX_NMAP, count); + c = (int)(bno + count - b); + if ((error = xfs_bmapi(tp, dp, b, c, + XFS_BMAPI_WRITE|XFS_BMAPI_METADATA, + args->firstblock, args->total, + &mapp[mapi], &nmap, args->flist))) { + kmem_free(mapp, sizeof(*mapp) * count); + return error; + } + if (nmap < 1) + break; + /* + * Add this bunch into our table, go to the next offset. + */ + mapi += nmap; + b = mapp[mapi - 1].br_startoff + + mapp[mapi - 1].br_blockcount; + } + } + /* + * Didn't work. + */ + else { + mapi = 0; + mapp = NULL; + } + /* + * See how many fsb's we got. + */ + for (i = 0, got = 0; i < mapi; i++) + got += mapp[i].br_blockcount; + /* + * Didn't get enough fsb's, or the first/last block's are wrong. + */ + if (got != count || mapp[0].br_startoff != bno || + mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != + bno + count) { + if (mapp != &map) + kmem_free(mapp, sizeof(*mapp) * count); + return XFS_ERROR(ENOSPC); + } + /* + * Done with the temporary mapping table. + */ + if (mapp != &map) + kmem_free(mapp, sizeof(*mapp) * count); + *dbp = XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)bno); + /* + * Update file's size if this is the data space and it grew. + */ + if (space == XFS_DIR2_DATA_SPACE) { + xfs_fsize_t size; /* directory file (data) size */ + + size = XFS_FSB_TO_B(mp, bno + count); + if (size > dp->i_d.di_size) { + dp->i_d.di_size = size; + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + } + } + return 0; +} + +/* + * See if the directory is a single-block form directory. + */ +int /* error */ +xfs_dir2_isblock( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + int *vp) /* out: 1 is block, 0 is not block */ +{ + xfs_fileoff_t last; /* last file offset */ + xfs_mount_t *mp; /* filesystem mount point */ + int rval; /* return value */ + + mp = dp->i_mount; + if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) { + return rval; + } + rval = XFS_FSB_TO_B(mp, last) == mp->m_dirblksize; + ASSERT(rval == 0 || dp->i_d.di_size == mp->m_dirblksize); + *vp = rval; + return 0; +} + +/* + * See if the directory is a single-leaf form directory. + */ +int /* error */ +xfs_dir2_isleaf( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + int *vp) /* out: 1 is leaf, 0 is not leaf */ +{ + xfs_fileoff_t last; /* last file offset */ + xfs_mount_t *mp; /* filesystem mount point */ + int rval; /* return value */ + + mp = dp->i_mount; + if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) { + return rval; + } + *vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog); + return 0; +} + +/* + * Remove the given block from the directory. + * This routine is used for data and free blocks, leaf/node are done + * by xfs_da_shrink_inode. + */ +int +xfs_dir2_shrink_inode( + xfs_da_args_t *args, /* operation arguments */ + xfs_dir2_db_t db, /* directory block number */ + xfs_dabuf_t *bp) /* block's buffer */ +{ + xfs_fileoff_t bno; /* directory file offset */ + xfs_dablk_t da; /* directory file offset */ + int done; /* bunmap is finished */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_db("shrink_inode", args, db, bp); + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + da = XFS_DIR2_DB_TO_DA(mp, db); + /* + * Unmap the fsblock(s). + */ + if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs, + XFS_BMAPI_METADATA, 0, args->firstblock, args->flist, + &done))) { + /* + * ENOSPC actually can happen if we're in a removename with + * no space reservation, and the resulting block removal + * would cause a bmap btree split or conversion from extents + * to btree. This can only happen for un-fragmented + * directory blocks, since you need to be punching out + * the middle of an extent. + * In this case we need to leave the block in the file, + * and not binval it. + * So the block has to be in a consistent empty state + * and appropriately logged. + * We don't free up the buffer, the caller can tell it + * hasn't happened since it got an error back. + */ + return error; + } + ASSERT(done); + /* + * Invalidate the buffer from the transaction. + */ + xfs_da_binval(tp, bp); + /* + * If it's not a data block, we're done. + */ + if (db >= XFS_DIR2_LEAF_FIRSTDB(mp)) + return 0; + /* + * If the block isn't the last one in the directory, we're done. + */ + if (dp->i_d.di_size > XFS_DIR2_DB_OFF_TO_BYTE(mp, db + 1, 0)) + return 0; + bno = da; + if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) { + /* + * This can't really happen unless there's kernel corruption. + */ + return error; + } + if (db == mp->m_dirdatablk) + ASSERT(bno == 0); + else + ASSERT(bno > 0); + /* + * Set the size to the new last block. + */ + dp->i_d.di_size = XFS_FSB_TO_B(mp, bno); + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir2_block.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir2_block.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir2_block.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir2_block.c Thu Apr 12 18:30:32 2001 @@ -0,0 +1,1076 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_block.c + * XFS V2 directory implementation, single-block form. + * See xfs_dir2_block.h for the format. + */ + +#include + +/* + * Add an entry to a block directory. + */ +int /* error */ +xfs_dir2_block_addname( + xfs_da_args_t *args) /* directory op arguments */ +{ + xfs_dir2_data_free_t *bf; /* bestfree table in block */ + xfs_dir2_block_t *block; /* directory block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dabuf_t *bp; /* buffer for block */ + xfs_dir2_block_tail_t *btp; /* block tail */ + int compact; /* need to compact leaf ents */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_inode_t *dp; /* directory inode */ + xfs_dir2_data_unused_t *dup; /* block unused entry */ + int error; /* error return value */ + xfs_dir2_data_unused_t *enddup=NULL; /* unused at end of data */ + xfs_dahash_t hash; /* hash value of found entry */ + int high; /* high index for binary srch */ + int highstale; /* high stale index */ + int lfloghigh=0; /* last final leaf to log */ + int lfloglow=0; /* first final leaf to log */ + int len; /* length of the new entry */ + int low; /* low index for binary srch */ + int lowstale; /* low stale index */ + int mid=0; /* midpoint for binary srch */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log header */ + int needscan; /* need to rescan freespace */ + xfs_dir2_data_off_t *tagp; /* pointer to tag value */ + xfs_trans_t *tp; /* transaction structure */ + + xfs_dir2_trace_args("block_addname", args); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + /* + * Read the (one and only) directory block into dabuf bp. + */ + if ((error = + xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) { + return error; + } + ASSERT(bp != NULL); + block = bp->data; + /* + * Check the magic number, corrupted if wrong. + */ + if (INT_GET(block->hdr.magic, ARCH_CONVERT) != XFS_DIR2_BLOCK_MAGIC) { + xfs_da_brelse(tp, bp); + return XFS_ERROR(EFSCORRUPTED); + } + len = XFS_DIR2_DATA_ENTSIZE(args->namelen); + /* + * Set up pointers to parts of the block. + */ + bf = block->hdr.bestfree; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * No stale entries? Need space for entry and new leaf. + */ + if (INT_GET(btp->stale, ARCH_CONVERT) == 0) { + /* + * Tag just before the first leaf entry. + */ + tagp = (xfs_dir2_data_off_t *)blp - 1; + /* + * Data object just before the first leaf entry. + */ + enddup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT)); + /* + * If it's not free then can't do this add without cleaning up: + * the space before the first leaf entry needs to be free so it + * can be expanded to hold the pointer to the new entry. + */ + if (INT_GET(enddup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG) + dup = enddup = NULL; + /* + * Check out the biggest freespace and see if it's the same one. + */ + else { + dup = (xfs_dir2_data_unused_t *) + ((char *)block + INT_GET(bf[0].offset, ARCH_CONVERT)); + if (dup == enddup) { + /* + * It is the biggest freespace, is it too small + * to hold the new leaf too? + */ + if (INT_GET(dup->length, ARCH_CONVERT) < len + (uint)sizeof(*blp)) { + /* + * Yes, we use the second-largest + * entry instead if it works. + */ + if (INT_GET(bf[1].length, ARCH_CONVERT) >= len) + dup = (xfs_dir2_data_unused_t *) + ((char *)block + + INT_GET(bf[1].offset, ARCH_CONVERT)); + else + dup = NULL; + } + } else { + /* + * Not the same free entry, + * just check its length. + */ + if (INT_GET(dup->length, ARCH_CONVERT) < len) { + dup = NULL; + } + } + } + compact = 0; + } + /* + * If there are stale entries we'll use one for the leaf. + * Is the biggest entry enough to avoid compaction? + */ + else if (INT_GET(bf[0].length, ARCH_CONVERT) >= len) { + dup = (xfs_dir2_data_unused_t *) + ((char *)block + INT_GET(bf[0].offset, ARCH_CONVERT)); + compact = 0; + } + /* + * Will need to compact to make this work. + */ + else { + /* + * Tag just before the first leaf entry. + */ + tagp = (xfs_dir2_data_off_t *)blp - 1; + /* + * Data object just before the first leaf entry. + */ + dup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT)); + /* + * If it's not free then the data will go where the + * leaf data starts now, if it works at all. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + if (INT_GET(dup->length, ARCH_CONVERT) + (INT_GET(btp->stale, ARCH_CONVERT) - 1) * + (uint)sizeof(*blp) < len) + dup = NULL; + } else if ((INT_GET(btp->stale, ARCH_CONVERT) - 1) * (uint)sizeof(*blp) < len) + dup = NULL; + else + dup = (xfs_dir2_data_unused_t *)blp; + compact = 1; + } + /* + * If this isn't a real add, we're done with the buffer. + */ + if (args->justcheck) + xfs_da_brelse(tp, bp); + /* + * If we don't have space for the new entry & leaf ... + */ + if (!dup) { + /* + * Not trying to actually do anything, or don't have + * a space reservation: return no-space. + */ + if (args->justcheck || args->total == 0) + return XFS_ERROR(ENOSPC); + /* + * Convert to the next larger format. + * Then add the new entry in that format. + */ + error = xfs_dir2_block_to_leaf(args, bp); + xfs_da_buf_done(bp); + if (error) + return error; + return xfs_dir2_leaf_addname(args); + } + /* + * Just checking, and it would work, so say so. + */ + if (args->justcheck) + return 0; + needlog = needscan = 0; + /* + * If need to compact the leaf entries, do it now. + * Leave the highest-numbered stale entry stale. + * XXX should be the one closest to mid but mid is not yet computed. + */ + if (compact) { + int fromidx; /* source leaf index */ + int toidx; /* target leaf index */ + + for (fromidx = toidx = INT_GET(btp->count, ARCH_CONVERT) - 1, + highstale = lfloghigh = -1; + fromidx >= 0; + fromidx--) { + if (INT_GET(blp[fromidx].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) { + if (highstale == -1) + highstale = toidx; + else { + if (lfloghigh == -1) + lfloghigh = toidx; + continue; + } + } + if (fromidx < toidx) + blp[toidx] = blp[fromidx]; + toidx--; + } + lfloglow = toidx + 1 - (INT_GET(btp->stale, ARCH_CONVERT) - 1); + lfloghigh -= INT_GET(btp->stale, ARCH_CONVERT) - 1; + INT_MOD(btp->count, ARCH_CONVERT, -(INT_GET(btp->stale, ARCH_CONVERT) - 1)); + xfs_dir2_data_make_free(tp, bp, + (xfs_dir2_data_aoff_t)((char *)blp - (char *)block), + (xfs_dir2_data_aoff_t)((INT_GET(btp->stale, ARCH_CONVERT) - 1) * sizeof(*blp)), + &needlog, &needscan); + blp += INT_GET(btp->stale, ARCH_CONVERT) - 1; + INT_SET(btp->stale, ARCH_CONVERT, 1); + /* + * If we now need to rebuild the bestfree map, do so. + * This needs to happen before the next call to use_free. + */ + if (needscan) { + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, + &needlog, NULL); + needscan = 0; + } + } + /* + * Set leaf logging boundaries to impossible state. + * For the no-stale case they're set explicitly. + */ + else if (INT_GET(btp->stale, ARCH_CONVERT)) { + lfloglow = INT_GET(btp->count, ARCH_CONVERT); + lfloghigh = -1; + } + /* + * Find the slot that's first lower than our hash value, -1 if none. + */ + for (low = 0, high = INT_GET(btp->count, ARCH_CONVERT) - 1; low <= high; ) { + mid = (low + high) >> 1; + if ((hash = INT_GET(blp[mid].hashval, ARCH_CONVERT)) == args->hashval) + break; + if (hash < args->hashval) + low = mid + 1; + else + high = mid - 1; + } + while (mid >= 0 && INT_GET(blp[mid].hashval, ARCH_CONVERT) >= args->hashval) { + mid--; + } + /* + * No stale entries, will use enddup space to hold new leaf. + */ + if (INT_GET(btp->stale, ARCH_CONVERT) == 0) { + /* + * Mark the space needed for the new leaf entry, now in use. + */ + xfs_dir2_data_use_free(tp, bp, enddup, + (xfs_dir2_data_aoff_t) + ((char *)enddup - (char *)block + INT_GET(enddup->length, ARCH_CONVERT) - + sizeof(*blp)), + (xfs_dir2_data_aoff_t)sizeof(*blp), + &needlog, &needscan); + /* + * Update the tail (entry count). + */ + INT_MOD(btp->count, ARCH_CONVERT, +1); + /* + * If we now need to rebuild the bestfree map, do so. + * This needs to happen before the next call to use_free. + */ + if (needscan) { + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, + &needlog, NULL); + needscan = 0; + } + /* + * Adjust pointer to the first leaf entry, we're about to move + * the table up one to open up space for the new leaf entry. + * Then adjust our index to match. + */ + blp--; + mid++; + if (mid) + ovbcopy(&blp[1], blp, mid * sizeof(*blp)); + lfloglow = 0; + lfloghigh = mid; + } + /* + * Use a stale leaf for our new entry. + */ + else { + for (lowstale = mid; + lowstale >= 0 && + INT_GET(blp[lowstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR; + lowstale--) + continue; + for (highstale = mid + 1; + highstale < INT_GET(btp->count, ARCH_CONVERT) && + INT_GET(blp[highstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR && + (lowstale < 0 || mid - lowstale > highstale - mid); + highstale++) + continue; + /* + * Move entries toward the low-numbered stale entry. + */ + if (lowstale >= 0 && + (highstale == INT_GET(btp->count, ARCH_CONVERT) || + mid - lowstale <= highstale - mid)) { + if (mid - lowstale) + ovbcopy(&blp[lowstale + 1], &blp[lowstale], + (mid - lowstale) * sizeof(*blp)); + lfloglow = MIN(lowstale, lfloglow); + lfloghigh = MAX(mid, lfloghigh); + } + /* + * Move entries toward the high-numbered stale entry. + */ + else { + ASSERT(highstale < INT_GET(btp->count, ARCH_CONVERT)); + mid++; + if (highstale - mid) + ovbcopy(&blp[mid], &blp[mid + 1], + (highstale - mid) * sizeof(*blp)); + lfloglow = MIN(mid, lfloglow); + lfloghigh = MAX(highstale, lfloghigh); + } + INT_MOD(btp->stale, ARCH_CONVERT, -1); + } + /* + * Point to the new data entry. + */ + dep = (xfs_dir2_data_entry_t *)dup; + /* + * Fill in the leaf entry. + */ + INT_SET(blp[mid].hashval, ARCH_CONVERT, args->hashval); + INT_SET(blp[mid].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block)); + xfs_dir2_block_log_leaf(tp, bp, lfloglow, lfloghigh); + /* + * Mark space for the data entry used. + */ + xfs_dir2_data_use_free(tp, bp, dup, + (xfs_dir2_data_aoff_t)((char *)dup - (char *)block), + (xfs_dir2_data_aoff_t)len, &needlog, &needscan); + /* + * Create the new data entry. + */ + INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); + dep->namelen = args->namelen; + bcopy(args->name, dep->name, args->namelen); + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block)); + /* + * Clean up the bestfree array and log the header, tail, and entry. + */ + if (needscan) + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog, + NULL); + if (needlog) + xfs_dir2_data_log_header(tp, bp); + xfs_dir2_block_log_tail(tp, bp); + xfs_dir2_data_log_entry(tp, bp, dep); + xfs_dir2_data_check(dp, bp); + xfs_da_buf_done(bp); + return 0; +} + +/* + * Log leaf entries from the block. + */ +STATIC void +xfs_dir2_block_log_leaf( + xfs_trans_t *tp, /* transaction structure */ + xfs_dabuf_t *bp, /* block buffer */ + int first, /* index of first logged leaf */ + int last) /* index of last logged leaf */ +{ + xfs_dir2_block_t *block; /* directory block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_mount_t *mp; /* filesystem mount point */ + + mp = tp->t_mountp; + block = bp->data; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + xfs_da_log_buf(tp, bp, (uint)((char *)&blp[first] - (char *)block), + (uint)((char *)&blp[last + 1] - (char *)block - 1)); +} + +/* + * Log the block tail. + */ +STATIC void +xfs_dir2_block_log_tail( + xfs_trans_t *tp, /* transaction structure */ + xfs_dabuf_t *bp) /* block buffer */ +{ + xfs_dir2_block_t *block; /* directory block structure */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_mount_t *mp; /* filesystem mount point */ + + mp = tp->t_mountp; + block = bp->data; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + xfs_da_log_buf(tp, bp, (uint)((char *)btp - (char *)block), + (uint)((char *)(btp + 1) - (char *)block - 1)); +} + +/* + * Look up an entry in the block. This is the external routine, + * xfs_dir2_block_lookup_int does the real work. + */ +int /* error */ +xfs_dir2_block_lookup( + xfs_da_args_t *args) /* dir lookup arguments */ +{ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_inode_t *dp; /* incore inode */ + int ent; /* entry index */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + + xfs_dir2_trace_args("block_lookup", args); + /* + * Get the buffer, look up the entry. + * If not found (ENOENT) then return, have no buffer. + */ + if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) + return error; + dp = args->dp; + mp = dp->i_mount; + block = bp->data; + xfs_dir2_data_check(dp, bp); + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Get the offset from the leaf entry, to point to the data. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT))); + /* + * Fill in inode number, release the block. + */ + args->inumber = INT_GET(dep->inumber, ARCH_CONVERT); + xfs_da_brelse(args->trans, bp); + return XFS_ERROR(EEXIST); +} + +/* + * Internal block lookup routine. + */ +STATIC int /* error */ +xfs_dir2_block_lookup_int( + xfs_da_args_t *args, /* dir lookup arguments */ + xfs_dabuf_t **bpp, /* returned block buffer */ + int *entno) /* returned entry number */ +{ + xfs_dir2_dataptr_t addr; /* data entry address */ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_inode_t *dp; /* incore inode */ + int error; /* error return value */ + xfs_dahash_t hash; /* found hash value */ + int high; /* binary search high index */ + int low; /* binary search low index */ + int mid; /* binary search current idx */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + /* + * Read the buffer, return error if we can't get it. + */ + if ((error = + xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) { + return error; + } + ASSERT(bp != NULL); + block = bp->data; + xfs_dir2_data_check(dp, bp); + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Loop doing a binary search for our hash value. + * Find our entry, ENOENT if it's not there. + */ + for (low = 0, high = INT_GET(btp->count, ARCH_CONVERT) - 1; ; ) { + ASSERT(low <= high); + mid = (low + high) >> 1; + if ((hash = INT_GET(blp[mid].hashval, ARCH_CONVERT)) == args->hashval) + break; + if (hash < args->hashval) + low = mid + 1; + else + high = mid - 1; + if (low > high) { + ASSERT(args->oknoent); + xfs_da_brelse(tp, bp); + return XFS_ERROR(ENOENT); + } + } + /* + * Back up to the first one with the right hash value. + */ + while (mid > 0 && INT_GET(blp[mid - 1].hashval, ARCH_CONVERT) == args->hashval) { + mid--; + } + /* + * Now loop forward through all the entries with the + * right hash value looking for our name. + */ + do { + if ((addr = INT_GET(blp[mid].address, ARCH_CONVERT)) == XFS_DIR2_NULL_DATAPTR) + continue; + /* + * Get pointer to the entry from the leaf. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, addr)); + /* + * Compare, if it's right give back buffer & entry number. + */ + if (dep->namelen == args->namelen && + dep->name[0] == args->name[0] && + bcmp(dep->name, args->name, args->namelen) == 0) { + *bpp = bp; + *entno = mid; + return 0; + } + } while (++mid < INT_GET(btp->count, ARCH_CONVERT) && INT_GET(blp[mid].hashval, ARCH_CONVERT) == hash); + /* + * No match, release the buffer and return ENOENT. + */ + ASSERT(args->oknoent); + xfs_da_brelse(tp, bp); + return XFS_ERROR(ENOENT); +} + +/* + * Remove an entry from a block format directory. + * If that makes the block small enough to fit in shortform, transform it. + */ +int /* error */ +xfs_dir2_block_removename( + xfs_da_args_t *args) /* directory operation args */ +{ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf pointer */ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_inode_t *dp; /* incore inode */ + int ent; /* block leaf entry index */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log block header */ + int needscan; /* need to fixup bestfree */ + xfs_dir2_sf_hdr_t sfh; /* shortform header */ + int size; /* shortform size */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args("block_removename", args); + /* + * Look up the entry in the block. Gets the buffer and entry index. + * It will always be there, the vnodeops level does a lookup first. + */ + if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) { + return error; + } + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + block = bp->data; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Point to the data entry using the leaf entry. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT))); + /* + * Mark the data entry's space free. + */ + needlog = needscan = 0; + xfs_dir2_data_make_free(tp, bp, + (xfs_dir2_data_aoff_t)((char *)dep - (char *)block), + XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan); + /* + * Fix up the block tail. + */ + INT_MOD(btp->stale, ARCH_CONVERT, +1); + xfs_dir2_block_log_tail(tp, bp); + /* + * Remove the leaf entry by marking it stale. + */ + INT_SET(blp[ent].address, ARCH_CONVERT, XFS_DIR2_NULL_DATAPTR); + xfs_dir2_block_log_leaf(tp, bp, ent, ent); + /* + * Fix up bestfree, log the header if necessary. + */ + if (needscan) + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog, + NULL); + if (needlog) + xfs_dir2_data_log_header(tp, bp); + xfs_dir2_data_check(dp, bp); + /* + * See if the size as a shortform is good enough. + */ + if ((size = xfs_dir2_block_sfsize(dp, block, &sfh)) > + XFS_IFORK_DSIZE(dp)) { + xfs_da_buf_done(bp); + return 0; + } + /* + * If it works, do the conversion. + */ + return xfs_dir2_block_to_sf(args, bp, size, &sfh); +} + +/* + * Replace an entry in a V2 block directory. + * Change the inode number to the new value. + */ +int /* error */ +xfs_dir2_block_replace( + xfs_da_args_t *args) /* directory operation args */ +{ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_inode_t *dp; /* incore inode */ + int ent; /* leaf entry index */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + + xfs_dir2_trace_args("block_replace", args); + /* + * Lookup the entry in the directory. Get buffer and entry index. + * This will always succeed since the caller has already done a lookup. + */ + if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) { + return error; + } + dp = args->dp; + mp = dp->i_mount; + block = bp->data; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Point to the data entry we need to change. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT))); + ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) != args->inumber); + /* + * Change the inode number to the new value. + */ + INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); + xfs_dir2_data_log_entry(args->trans, bp, dep); + xfs_dir2_data_check(dp, bp); + xfs_da_buf_done(bp); + return 0; +} + +/* + * Qsort comparison routine for the block leaf entries. + */ +static int /* sort order */ +xfs_dir2_block_sort( + const void *a, /* first leaf entry */ + const void *b) /* second leaf entry */ +{ + const xfs_dir2_leaf_entry_t *la; /* first leaf entry */ + const xfs_dir2_leaf_entry_t *lb; /* second leaf entry */ + + la = a; + lb = b; + return INT_GET(la->hashval, ARCH_CONVERT) < INT_GET(lb->hashval, ARCH_CONVERT) ? -1 : + (INT_GET(la->hashval, ARCH_CONVERT) > INT_GET(lb->hashval, ARCH_CONVERT) ? 1 : 0); +} + +/* + * Convert a V2 leaf directory to a V2 block directory if possible. + */ +int /* error */ +xfs_dir2_leaf_to_block( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *lbp, /* leaf buffer */ + xfs_dabuf_t *dbp) /* data buffer */ +{ + xfs_dir2_data_off_t *bestsp; /* leaf bests table */ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_data_unused_t *dup; /* unused data entry */ + int error; /* error return value */ + int from; /* leaf from index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* file system mount point */ + int needlog; /* need to log data header */ + int needscan; /* need to scan for bestfree */ + xfs_dir2_sf_hdr_t sfh; /* shortform header */ + int size; /* bytes used */ + xfs_dir2_data_off_t *tagp; /* end of entry (tag) */ + int to; /* block/leaf to index */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_bb("leaf_to_block", args, lbp, dbp); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + leaf = lbp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC); + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + /* + * If there are data blocks other than the first one, take this + * opportunity to remove trailing empty data blocks that may have + * been left behind during no-space-reservation operations. + * These will show up in the leaf bests table. + */ + while (dp->i_d.di_size > mp->m_dirblksize) { + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + if (INT_GET(bestsp[INT_GET(ltp->bestcount, ARCH_CONVERT) - 1], ARCH_CONVERT) == + mp->m_dirblksize - (uint)sizeof(block->hdr)) { + if ((error = + xfs_dir2_leaf_trim_data(args, lbp, + (xfs_dir2_db_t)(INT_GET(ltp->bestcount, ARCH_CONVERT) - 1)))) + goto out; + } else { + error = 0; + goto out; + } + } + /* + * Read the data block if we don't already have it, give up if it fails. + */ + if (dbp == NULL && + (error = xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &dbp, + XFS_DATA_FORK))) { + goto out; + } + block = dbp->data; + ASSERT(INT_GET(block->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC); + /* + * Size of the "leaf" area in the block. + */ + size = (uint)sizeof(block->tail) + + (uint)sizeof(*lep) * (INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT)); + /* + * Look at the last data entry. + */ + tagp = (xfs_dir2_data_off_t *)((char *)block + mp->m_dirblksize) - 1; + dup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT)); + /* + * If it's not free or is too short we can't do it. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG || INT_GET(dup->length, ARCH_CONVERT) < size) { + error = 0; + goto out; + } + /* + * Start converting it to block form. + */ + INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_BLOCK_MAGIC); + needlog = 1; + needscan = 0; + /* + * Use up the space at the end of the block (blp/btp). + */ + xfs_dir2_data_use_free(tp, dbp, dup, mp->m_dirblksize - size, size, + &needlog, &needscan); + /* + * Initialize the block tail. + */ + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + INT_SET(btp->count, ARCH_CONVERT, INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT)); + INT_SET(btp->stale, ARCH_CONVERT, 0); + xfs_dir2_block_log_tail(tp, dbp); + /* + * Initialize the block leaf area. We compact out stale entries. + */ + lep = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + for (from = to = 0; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) { + if (INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + continue; + lep[to++] = leaf->ents[from]; + } + ASSERT(to == INT_GET(btp->count, ARCH_CONVERT)); + xfs_dir2_block_log_leaf(tp, dbp, 0, INT_GET(btp->count, ARCH_CONVERT) - 1); + /* + * Scan the bestfree if we need it and log the data block header. + */ + if (needscan) + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog, + NULL); + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + /* + * Pitch the old leaf block. + */ + error = xfs_da_shrink_inode(args, mp->m_dirleafblk, lbp); + lbp = NULL; + if (error) { + goto out; + } + /* + * Now see if the resulting block can be shrunken to shortform. + */ + if ((size = xfs_dir2_block_sfsize(dp, block, &sfh)) > + XFS_IFORK_DSIZE(dp)) { + error = 0; + goto out; + } + return xfs_dir2_block_to_sf(args, dbp, size, &sfh); +out: + if (lbp) + xfs_da_buf_done(lbp); + if (dbp) + xfs_da_buf_done(dbp); + return error; +} + +/* + * Convert the shortform directory to block form. + */ +int /* error */ +xfs_dir2_sf_to_block( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_dir2_db_t blkno; /* dir-relative block # (0) */ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_block_tail_t *btp; /* block tail pointer */ + char buf[XFS_DIR2_SF_MAX_SIZE]; /* sf buffer */ + xfs_dir2_data_entry_t *dep; /* data entry pointer */ + xfs_inode_t *dp; /* incore directory inode */ + int dummy; /* trash */ + xfs_dir2_data_unused_t *dup; /* unused entry pointer */ + int endoffset; /* end of data objects */ + int error; /* error return value */ + int i; /* index */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log block header */ + int needscan; /* need to scan block freespc */ + int newoffset; /* offset from current entry */ + int offset; /* target block offset */ + xfs_dir2_sf_entry_t *sfep; /* sf entry pointer */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + xfs_dir2_data_off_t *tagp; /* end of data entry */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args("sf_to_block", args); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Bomb out if the shortform directory is way too short. + */ + if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); + /* + * Copy the directory into the stack buffer. + * Then pitch the incore inode data so we can make extents. + */ + bcopy(sfp, buf, dp->i_df.if_bytes); + xfs_idata_realloc(dp, -dp->i_df.if_bytes, XFS_DATA_FORK); + dp->i_d.di_size = 0; + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + /* + * Reset pointer - old sfp is gone. + */ + sfp = (xfs_dir2_sf_t *)buf; + /* + * Add block 0 to the inode. + */ + error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno); + if (error) { + return error; + } + /* + * Initialize the data block. + */ + error = xfs_dir2_data_init(args, blkno, &bp); + if (error) { + return error; + } + block = bp->data; + INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_BLOCK_MAGIC); + /* + * Compute size of block "tail" area. + */ + i = (uint)sizeof(*btp) + + (INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t); + /* + * The whole thing is initialized to free by the init routine. + * Say we're using the leaf and tail area. + */ + dup = (xfs_dir2_data_unused_t *)block->u; + needlog = needscan = 0; + xfs_dir2_data_use_free(tp, bp, dup, mp->m_dirblksize - i, i, &needlog, + &needscan); + ASSERT(needscan == 0); + /* + * Fill in the tail. + */ + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + INT_SET(btp->count, ARCH_CONVERT, INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2); /* ., .. */ + INT_ZERO(btp->stale, ARCH_CONVERT); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + endoffset = (uint)((char *)blp - (char *)block); + /* + * Remove the freespace, we'll manage it. + */ + xfs_dir2_data_use_free(tp, bp, dup, + (xfs_dir2_data_aoff_t)((char *)dup - (char *)block), + INT_GET(dup->length, ARCH_CONVERT), &needlog, &needscan); + /* + * Create entry for . + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATA_DOT_OFFSET); + INT_SET(dep->inumber, ARCH_CONVERT, dp->i_ino); + dep->namelen = 1; + dep->name[0] = '.'; + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block)); + xfs_dir2_data_log_entry(tp, bp, dep); + INT_SET(blp[0].hashval, ARCH_CONVERT, xfs_dir_hash_dot); + INT_SET(blp[0].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block)); + /* + * Create entry for .. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATA_DOTDOT_OFFSET); + INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT)); + dep->namelen = 2; + dep->name[0] = dep->name[1] = '.'; + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block)); + xfs_dir2_data_log_entry(tp, bp, dep); + INT_SET(blp[1].hashval, ARCH_CONVERT, xfs_dir_hash_dotdot); + INT_SET(blp[1].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block)); + offset = XFS_DIR2_DATA_FIRST_OFFSET; + /* + * Loop over existing entries, stuff them in. + */ + if ((i = 0) == INT_GET(sfp->hdr.count, ARCH_CONVERT)) + sfep = NULL; + else + sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + /* + * Need to preserve the existing offset values in the sf directory. + * Insert holes (unused entries) where necessary. + */ + while (offset < endoffset) { + /* + * sfep is null when we reach the end of the list. + */ + if (sfep == NULL) + newoffset = endoffset; + else + newoffset = XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT); + /* + * There should be a hole here, make one. + */ + if (offset < newoffset) { + dup = (xfs_dir2_data_unused_t *) + ((char *)block + offset); + INT_SET(dup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + INT_SET(dup->length, ARCH_CONVERT, newoffset - offset); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t) + ((char *)dup - (char *)block)); + xfs_dir2_data_log_unused(tp, bp, dup); + (void)xfs_dir2_data_freeinsert((xfs_dir2_data_t *)block, + dup, &dummy); + offset += INT_GET(dup->length, ARCH_CONVERT); + continue; + } + /* + * Copy a real entry. + */ + dep = (xfs_dir2_data_entry_t *)((char *)block + newoffset); + INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT)); + dep->namelen = sfep->namelen; + bcopy(sfep->name, dep->name, dep->namelen); + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block)); + xfs_dir2_data_log_entry(tp, bp, dep); + INT_SET(blp[2 + i].hashval, ARCH_CONVERT, xfs_da_hashname((char *)sfep->name, sfep->namelen)); + INT_SET(blp[2 + i].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, + (char *)dep - (char *)block)); + offset = (int)((char *)(tagp + 1) - (char *)block); + if (++i == INT_GET(sfp->hdr.count, ARCH_CONVERT)) + sfep = NULL; + else + sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep); + } + /* + * Sort the leaf entries by hash value. + */ + qsort(blp, INT_GET(btp->count, ARCH_CONVERT), sizeof(*blp), xfs_dir2_block_sort); + /* + * Log the leaf entry area and tail. + * Already logged the header in data_init, ignore needlog. + */ + ASSERT(needscan == 0); + xfs_dir2_block_log_leaf(tp, bp, 0, INT_GET(btp->count, ARCH_CONVERT) - 1); + xfs_dir2_block_log_tail(tp, bp); + xfs_dir2_data_check(dp, bp); + xfs_da_buf_done(bp); + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir2_data.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir2_data.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir2_data.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir2_data.c Thu Apr 12 18:30:32 2001 @@ -0,0 +1,831 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_data.c + * Core data block handling routines for XFS V2 directories. + * See xfs_dir2_data.h for data structures. + */ +#include + +#ifdef DEBUG +/* + * Check the consistency of the data block. + * The input can also be a block-format directory. + * Pop an assert if we find anything bad. + */ +void +xfs_dir2_data_check( + xfs_inode_t *dp, /* incore inode pointer */ + xfs_dabuf_t *bp) /* data block's buffer */ +{ + xfs_dir2_dataptr_t addr; /* addr for leaf lookup */ + xfs_dir2_data_free_t *bf; /* bestfree table */ + xfs_dir2_block_tail_t *btp=NULL; /* block tail */ + int count; /* count of entries found */ + xfs_dir2_data_t *d; /* data block pointer */ + xfs_dir2_data_entry_t *dep; /* data entry */ + xfs_dir2_data_free_t *dfp; /* bestfree entry */ + xfs_dir2_data_unused_t *dup; /* unused entry */ + char *endp; /* end of useful data */ + int freeseen; /* mask of bestfrees seen */ + xfs_dahash_t hash; /* hash of current name */ + int i; /* leaf index */ + int lastfree; /* last entry was unused */ + xfs_dir2_leaf_entry_t *lep=NULL; /* block leaf entries */ + xfs_mount_t *mp; /* filesystem mount point */ + char *p; /* current data position */ + int stale; /* count of stale leaves */ + + mp = dp->i_mount; + d = bp->data; + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + bf = d->hdr.bestfree; + p = (char *)d->u; + if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d); + lep = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + endp = (char *)lep; + } else + endp = (char *)d + mp->m_dirblksize; + count = lastfree = freeseen = 0; + /* + * Account for zero bestfree entries. + */ + if (INT_GET(bf[0].length, ARCH_CONVERT) == 0) { + ASSERT(INT_GET(bf[0].offset, ARCH_CONVERT) == 0); + freeseen |= 1 << 0; + } + if (INT_GET(bf[1].length, ARCH_CONVERT) == 0) { + ASSERT(INT_GET(bf[1].offset, ARCH_CONVERT) == 0); + freeseen |= 1 << 1; + } + if (INT_GET(bf[2].length, ARCH_CONVERT) == 0) { + ASSERT(INT_GET(bf[2].offset, ARCH_CONVERT) == 0); + freeseen |= 1 << 2; + } + ASSERT(INT_GET(bf[0].length, ARCH_CONVERT) >= INT_GET(bf[1].length, ARCH_CONVERT)); + ASSERT(INT_GET(bf[1].length, ARCH_CONVERT) >= INT_GET(bf[2].length, ARCH_CONVERT)); + /* + * Loop over the data/unused entries. + */ + while (p < endp) { + dup = (xfs_dir2_data_unused_t *)p; + /* + * If it's unused, look for the space in the bestfree table. + * If we find it, account for that, else make sure it + * doesn't need to be there. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + ASSERT(lastfree == 0); + ASSERT(INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT) == + (char *)dup - (char *)d); + dfp = xfs_dir2_data_freefind(d, dup); + if (dfp) { + i = (int)(dfp - bf); + ASSERT((freeseen & (1 << i)) == 0); + freeseen |= 1 << i; + } else + ASSERT(INT_GET(dup->length, ARCH_CONVERT) <= INT_GET(bf[2].length, ARCH_CONVERT)); + p += INT_GET(dup->length, ARCH_CONVERT); + lastfree = 1; + continue; + } + /* + * It's a real entry. Validate the fields. + * If this is a block directory then make sure it's + * in the leaf section of the block. + * The linear search is crude but this is DEBUG code. + */ + dep = (xfs_dir2_data_entry_t *)p; + ASSERT(dep->namelen != 0); + ASSERT(xfs_dir_ino_validate(mp, INT_GET(dep->inumber, ARCH_CONVERT)) == 0); + ASSERT(INT_GET(*XFS_DIR2_DATA_ENTRY_TAG_P(dep), ARCH_CONVERT) == + (char *)dep - (char *)d); + count++; + lastfree = 0; + if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + addr = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + (xfs_dir2_data_aoff_t) + ((char *)dep - (char *)d)); + hash = xfs_da_hashname((char *)dep->name, dep->namelen); + for (i = 0; i < INT_GET(btp->count, ARCH_CONVERT); i++) { + if (INT_GET(lep[i].address, ARCH_CONVERT) == addr && + INT_GET(lep[i].hashval, ARCH_CONVERT) == hash) + break; + } + ASSERT(i < INT_GET(btp->count, ARCH_CONVERT)); + } + p += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + /* + * Need to have seen all the entries and all the bestfree slots. + */ + ASSERT(freeseen == 7); + if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + for (i = stale = 0; i < INT_GET(btp->count, ARCH_CONVERT); i++) { + if (INT_GET(lep[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + stale++; + if (i > 0) + ASSERT(INT_GET(lep[i].hashval, ARCH_CONVERT) >= INT_GET(lep[i - 1].hashval, ARCH_CONVERT)); + } + ASSERT(count == INT_GET(btp->count, ARCH_CONVERT) - INT_GET(btp->stale, ARCH_CONVERT)); + ASSERT(stale == INT_GET(btp->stale, ARCH_CONVERT)); + } +} +#endif + +/* + * Given a data block and an unused entry from that block, + * return the bestfree entry if any that corresponds to it. + */ +xfs_dir2_data_free_t * +xfs_dir2_data_freefind( + xfs_dir2_data_t *d, /* data block */ + xfs_dir2_data_unused_t *dup) /* data unused entry */ +{ + xfs_dir2_data_free_t *dfp; /* bestfree entry */ + xfs_dir2_data_aoff_t off; /* offset value needed */ +#if defined(DEBUG) && defined(__KERNEL__) + int matched; /* matched the value */ + int seenzero; /* saw a 0 bestfree entry */ +#endif + + off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)d); +#if defined(DEBUG) && defined(__KERNEL__) + /* + * Validate some consistency in the bestfree table. + * Check order, non-overlapping entries, and if we find the + * one we're looking for it has to be exact. + */ + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + for (dfp = &d->hdr.bestfree[0], seenzero = matched = 0; + dfp < &d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT]; + dfp++) { + if (INT_GET(dfp->offset, ARCH_CONVERT) == 0) { + ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == 0); + seenzero = 1; + continue; + } + ASSERT(seenzero == 0); + if (INT_GET(dfp->offset, ARCH_CONVERT) == off) { + matched = 1; + ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(dup->length, ARCH_CONVERT)); + } else if (off < INT_GET(dfp->offset, ARCH_CONVERT)) + ASSERT(off + INT_GET(dup->length, ARCH_CONVERT) <= INT_GET(dfp->offset, ARCH_CONVERT)); + else + ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) + INT_GET(dfp->length, ARCH_CONVERT) <= off); + ASSERT(matched || INT_GET(dfp->length, ARCH_CONVERT) >= INT_GET(dup->length, ARCH_CONVERT)); + if (dfp > &d->hdr.bestfree[0]) + ASSERT(INT_GET(dfp[-1].length, ARCH_CONVERT) >= INT_GET(dfp[0].length, ARCH_CONVERT)); + } +#endif + /* + * If this is smaller than the smallest bestfree entry, + * it can't be there since they're sorted. + */ + if (INT_GET(dup->length, ARCH_CONVERT) < INT_GET(d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT - 1].length, ARCH_CONVERT)) + return NULL; + /* + * Look at the three bestfree entries for our guy. + */ + for (dfp = &d->hdr.bestfree[0]; + dfp < &d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT]; + dfp++) { + if (INT_GET(dfp->offset, ARCH_CONVERT) == 0) + return NULL; + if (INT_GET(dfp->offset, ARCH_CONVERT) == off) + return dfp; + } + /* + * Didn't find it. This only happens if there are duplicate lengths. + */ + return NULL; +} + +/* + * Insert an unused-space entry into the bestfree table. + */ +xfs_dir2_data_free_t * /* entry inserted */ +xfs_dir2_data_freeinsert( + xfs_dir2_data_t *d, /* data block pointer */ + xfs_dir2_data_unused_t *dup, /* unused space */ + int *loghead) /* log the data header (out) */ +{ + xfs_dir2_data_free_t *dfp; /* bestfree table pointer */ + xfs_dir2_data_free_t new; /* new bestfree entry */ + +#ifdef __KERNEL__ + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); +#endif + dfp = d->hdr.bestfree; + INT_COPY(new.length, dup->length, ARCH_CONVERT); + INT_SET(new.offset, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dup - (char *)d)); + /* + * Insert at position 0, 1, or 2; or not at all. + */ + if (INT_GET(new.length, ARCH_CONVERT) > INT_GET(dfp[0].length, ARCH_CONVERT)) { + dfp[2] = dfp[1]; + dfp[1] = dfp[0]; + dfp[0] = new; + *loghead = 1; + return &dfp[0]; + } + if (INT_GET(new.length, ARCH_CONVERT) > INT_GET(dfp[1].length, ARCH_CONVERT)) { + dfp[2] = dfp[1]; + dfp[1] = new; + *loghead = 1; + return &dfp[1]; + } + if (INT_GET(new.length, ARCH_CONVERT) > INT_GET(dfp[2].length, ARCH_CONVERT)) { + dfp[2] = new; + *loghead = 1; + return &dfp[2]; + } + return NULL; +} + +/* + * Remove a bestfree entry from the table. + */ +void +xfs_dir2_data_freeremove( + xfs_dir2_data_t *d, /* data block pointer */ + xfs_dir2_data_free_t *dfp, /* bestfree entry pointer */ + int *loghead) /* out: log data header */ +{ +#ifdef __KERNEL__ + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); +#endif + /* + * It's the first entry, slide the next 2 up. + */ + if (dfp == &d->hdr.bestfree[0]) { + d->hdr.bestfree[0] = d->hdr.bestfree[1]; + d->hdr.bestfree[1] = d->hdr.bestfree[2]; + } + /* + * It's the second entry, slide the 3rd entry up. + */ + else if (dfp == &d->hdr.bestfree[1]) + d->hdr.bestfree[1] = d->hdr.bestfree[2]; + /* + * Must be the last entry. + */ + else + ASSERT(dfp == &d->hdr.bestfree[2]); + /* + * Clear the 3rd entry, must be zero now. + */ + INT_ZERO(d->hdr.bestfree[2].length, ARCH_CONVERT); + INT_ZERO(d->hdr.bestfree[2].offset, ARCH_CONVERT); + *loghead = 1; +} + +/* + * Given a data block, reconstruct its bestfree map. + */ +void +xfs_dir2_data_freescan( + xfs_mount_t *mp, /* filesystem mount point */ + xfs_dir2_data_t *d, /* data block pointer */ + int *loghead, /* out: log data header */ + char *aendp) /* in: caller's endp */ +{ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* active data entry */ + xfs_dir2_data_unused_t *dup; /* unused data entry */ + char *endp; /* end of block's data */ + char *p; /* current entry pointer */ + +#ifdef __KERNEL__ + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); +#endif + /* + * Start by clearing the table. + */ + bzero(d->hdr.bestfree, sizeof(d->hdr.bestfree)); + *loghead = 1; + /* + * Set up pointers. + */ + p = (char *)d->u; + if (aendp) + endp = aendp; + else if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d); + endp = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + } else + endp = (char *)d + mp->m_dirblksize; + /* + * Loop over the block's entries. + */ + while (p < endp) { + dup = (xfs_dir2_data_unused_t *)p; + /* + * If it's a free entry, insert it. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + ASSERT((char *)dup - (char *)d == + INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT)); + xfs_dir2_data_freeinsert(d, dup, loghead); + p += INT_GET(dup->length, ARCH_CONVERT); + } + /* + * For active entries, check their tags and skip them. + */ + else { + dep = (xfs_dir2_data_entry_t *)p; + ASSERT((char *)dep - (char *)d == + INT_GET(*XFS_DIR2_DATA_ENTRY_TAG_P(dep), ARCH_CONVERT)); + p += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + } +} + +/* + * Initialize a data block at the given block number in the directory. + * Give back the buffer for the created block. + */ +int /* error */ +xfs_dir2_data_init( + xfs_da_args_t *args, /* directory operation args */ + xfs_dir2_db_t blkno, /* logical dir block number */ + xfs_dabuf_t **bpp) /* output block buffer */ +{ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_data_t *d; /* pointer to block */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_data_unused_t *dup; /* unused entry pointer */ + int error; /* error return value */ + int i; /* bestfree index */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + int t; /* temp */ + + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + /* + * Get the buffer set up for the block. + */ + error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, blkno), -1, &bp, + XFS_DATA_FORK); + if (error) { + return error; + } + ASSERT(bp != NULL); + /* + * Initialize the header. + */ + d = bp->data; + INT_SET(d->hdr.magic, ARCH_CONVERT, XFS_DIR2_DATA_MAGIC); + INT_SET(d->hdr.bestfree[0].offset, ARCH_CONVERT, (xfs_dir2_data_off_t)sizeof(d->hdr)); + for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) { + INT_ZERO(d->hdr.bestfree[i].length, ARCH_CONVERT); + INT_ZERO(d->hdr.bestfree[i].offset, ARCH_CONVERT); + } + /* + * Set up an unused entry for the block's body. + */ + dup = &d->u[0].unused; + INT_SET(dup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + + t=mp->m_dirblksize - (uint)sizeof(d->hdr); + INT_SET(d->hdr.bestfree[0].length, ARCH_CONVERT, t); + INT_SET(dup->length, ARCH_CONVERT, t); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)dup - (char *)d)); + /* + * Log it and return it. + */ + xfs_dir2_data_log_header(tp, bp); + xfs_dir2_data_log_unused(tp, bp, dup); + *bpp = bp; + return 0; +} + +/* + * Log an active data entry from the block. + */ +void +xfs_dir2_data_log_entry( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* block buffer */ + xfs_dir2_data_entry_t *dep) /* data entry pointer */ +{ + xfs_dir2_data_t *d; /* data block pointer */ + + d = bp->data; + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + xfs_da_log_buf(tp, bp, (uint)((char *)dep - (char *)d), + (uint)((char *)(XFS_DIR2_DATA_ENTRY_TAG_P(dep) + 1) - + (char *)d - 1)); +} + +/* + * Log a data block header. + */ +void +xfs_dir2_data_log_header( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp) /* block buffer */ +{ + xfs_dir2_data_t *d; /* data block pointer */ + + d = bp->data; + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + xfs_da_log_buf(tp, bp, (uint)((char *)&d->hdr - (char *)d), + (uint)(sizeof(d->hdr) - 1)); +} + +/* + * Log a data unused entry. + */ +void +xfs_dir2_data_log_unused( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* block buffer */ + xfs_dir2_data_unused_t *dup) /* data unused pointer */ +{ + xfs_dir2_data_t *d; /* data block pointer */ + + d = bp->data; + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + /* + * Log the first part of the unused entry. + */ + xfs_da_log_buf(tp, bp, (uint)((char *)dup - (char *)d), + (uint)((char *)&dup->length + sizeof(dup->length) - + 1 - (char *)d)); + /* + * Log the end (tag) of the unused entry. + */ + xfs_da_log_buf(tp, bp, + (uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT) - (char *)d), + (uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT) - (char *)d + + sizeof(xfs_dir2_data_off_t) - 1)); +} + +/* + * Make a byte range in the data block unused. + * Its current contents are unimportant. + */ +void +xfs_dir2_data_make_free( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* block buffer */ + xfs_dir2_data_aoff_t offset, /* starting byte offset */ + xfs_dir2_data_aoff_t len, /* length in bytes */ + int *needlogp, /* out: log header */ + int *needscanp) /* out: regen bestfree */ +{ + xfs_dir2_data_t *d; /* data block pointer */ + xfs_dir2_data_free_t *dfp; /* bestfree pointer */ + char *endptr; /* end of data area */ + xfs_mount_t *mp; /* filesystem mount point */ + int needscan; /* need to regen bestfree */ + xfs_dir2_data_unused_t *newdup; /* new unused entry */ + xfs_dir2_data_unused_t *postdup; /* unused entry after us */ + xfs_dir2_data_unused_t *prevdup; /* unused entry before us */ + + mp = tp->t_mountp; + d = bp->data; + /* + * Figure out where the end of the data area is. + */ + if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC) + endptr = (char *)d + mp->m_dirblksize; + else { + xfs_dir2_block_tail_t *btp; /* block tail */ + + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d); + endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + } + /* + * If this isn't the start of the block, then back up to + * the previous entry and see if it's free. + */ + if (offset > sizeof(d->hdr)) { + xfs_dir2_data_off_t *tagp; /* tag just before us */ + + tagp = (xfs_dir2_data_off_t *)((char *)d + offset) - 1; + prevdup = (xfs_dir2_data_unused_t *)((char *)d + INT_GET(*tagp, ARCH_CONVERT)); + if (INT_GET(prevdup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG) + prevdup = NULL; + } else + prevdup = NULL; + /* + * If this isn't the end of the block, see if the entry after + * us is free. + */ + if ((char *)d + offset + len < endptr) { + postdup = + (xfs_dir2_data_unused_t *)((char *)d + offset + len); + if (INT_GET(postdup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG) + postdup = NULL; + } else + postdup = NULL; + ASSERT(*needscanp == 0); + needscan = 0; + /* + * Previous and following entries are both free, + * merge everything into a single free entry. + */ + if (prevdup && postdup) { + xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */ + + /* + * See if prevdup and/or postdup are in bestfree table. + */ + dfp = xfs_dir2_data_freefind(d, prevdup); + dfp2 = xfs_dir2_data_freefind(d, postdup); + /* + * We need a rescan unless there are exactly 2 free entries + * namely our two. Then we know what's happening, otherwise + * since the third bestfree is there, there might be more + * entries. + */ + needscan = INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT) != 0; + /* + * Fix up the new big freespace. + */ + INT_MOD(prevdup->length, ARCH_CONVERT, len + INT_GET(postdup->length, ARCH_CONVERT)); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(prevdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)prevdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, prevdup); + if (!needscan) { + /* + * Has to be the case that entries 0 and 1 are + * dfp and dfp2 (don't know which is which), and + * entry 2 is empty. + * Remove entry 1 first then entry 0. + */ + ASSERT(dfp && dfp2); + if (dfp == &d->hdr.bestfree[1]) { + dfp = &d->hdr.bestfree[0]; + ASSERT(dfp2 == dfp); + dfp2 = &d->hdr.bestfree[1]; + } + xfs_dir2_data_freeremove(d, dfp2, needlogp); + xfs_dir2_data_freeremove(d, dfp, needlogp); + /* + * Now insert the new entry. + */ + dfp = xfs_dir2_data_freeinsert(d, prevdup, needlogp); + ASSERT(dfp == &d->hdr.bestfree[0]); + ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(prevdup->length, ARCH_CONVERT)); + ASSERT(INT_GET(dfp[1].length, ARCH_CONVERT) == 0); + ASSERT(INT_GET(dfp[2].length, ARCH_CONVERT) == 0); + } + } + /* + * The entry before us is free, merge with it. + */ + else if (prevdup) { + dfp = xfs_dir2_data_freefind(d, prevdup); + INT_MOD(prevdup->length, ARCH_CONVERT, len); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(prevdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)prevdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, prevdup); + /* + * If the previous entry was in the table, the new entry + * is longer, so it will be in the table too. Remove + * the old one and add the new one. + */ + if (dfp) { + xfs_dir2_data_freeremove(d, dfp, needlogp); + (void)xfs_dir2_data_freeinsert(d, prevdup, needlogp); + } + /* + * Otherwise we need a scan if the new entry is big enough. + */ + else + needscan = INT_GET(prevdup->length, ARCH_CONVERT) > INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT); + } + /* + * The following entry is free, merge with it. + */ + else if (postdup) { + dfp = xfs_dir2_data_freefind(d, postdup); + newdup = (xfs_dir2_data_unused_t *)((char *)d + offset); + INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + INT_SET(newdup->length, ARCH_CONVERT, len + INT_GET(postdup->length, ARCH_CONVERT)); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup); + /* + * If the following entry was in the table, the new entry + * is longer, so it will be in the table too. Remove + * the old one and add the new one. + */ + if (dfp) { + xfs_dir2_data_freeremove(d, dfp, needlogp); + (void)xfs_dir2_data_freeinsert(d, newdup, needlogp); + } + /* + * Otherwise we need a scan if the new entry is big enough. + */ + else + needscan = INT_GET(newdup->length, ARCH_CONVERT) > INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT); + } + /* + * Neither neighbor is free. Make a new entry. + */ + else { + newdup = (xfs_dir2_data_unused_t *)((char *)d + offset); + INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + INT_SET(newdup->length, ARCH_CONVERT, len); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup); + (void)xfs_dir2_data_freeinsert(d, newdup, needlogp); + } + *needscanp = needscan; +} + +/* + * Take a byte range out of an existing unused space and make it un-free. + */ +void +xfs_dir2_data_use_free( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* data block buffer */ + xfs_dir2_data_unused_t *dup, /* unused entry */ + xfs_dir2_data_aoff_t offset, /* starting offset to use */ + xfs_dir2_data_aoff_t len, /* length to use */ + int *needlogp, /* out: need to log header */ + int *needscanp) /* out: need regen bestfree */ +{ + xfs_dir2_data_t *d; /* data block */ + xfs_dir2_data_free_t *dfp; /* bestfree pointer */ + int matchback; /* matches end of freespace */ + int matchfront; /* matches start of freespace */ + int needscan; /* need to regen bestfree */ + xfs_dir2_data_unused_t *newdup; /* new unused entry */ + xfs_dir2_data_unused_t *newdup2; /* another new unused entry */ + int oldlen; /* old unused entry's length */ + + d = bp->data; + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + ASSERT(INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG); + ASSERT(offset >= (char *)dup - (char *)d); + ASSERT(offset + len <= (char *)dup + INT_GET(dup->length, ARCH_CONVERT) - (char *)d); + ASSERT((char *)dup - (char *)d == INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT)); + /* + * Look up the entry in the bestfree table. + */ + dfp = xfs_dir2_data_freefind(d, dup); + oldlen = INT_GET(dup->length, ARCH_CONVERT); + ASSERT(dfp || oldlen <= INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT)); + /* + * Check for alignment with front and back of the entry. + */ + matchfront = (char *)dup - (char *)d == offset; + matchback = (char *)dup + oldlen - (char *)d == offset + len; + ASSERT(*needscanp == 0); + needscan = 0; + /* + * If we matched it exactly we just need to get rid of it from + * the bestfree table. + */ + if (matchfront && matchback) { + if (dfp) { + needscan = INT_GET(d->hdr.bestfree[2].offset, ARCH_CONVERT) != 0; + if (!needscan) + xfs_dir2_data_freeremove(d, dfp, needlogp); + } + } + /* + * We match the first part of the entry. + * Make a new entry with the remaining freespace. + */ + else if (matchfront) { + newdup = (xfs_dir2_data_unused_t *)((char *)d + offset + len); + INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + INT_SET(newdup->length, ARCH_CONVERT, oldlen - len); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup); + /* + * If it was in the table, remove it and add the new one. + */ + if (dfp) { + xfs_dir2_data_freeremove(d, dfp, needlogp); + dfp = xfs_dir2_data_freeinsert(d, newdup, needlogp); + ASSERT(dfp != NULL); + ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(newdup->length, ARCH_CONVERT)); + ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) == (char *)newdup - (char *)d); + /* + * If we got inserted at the last slot, + * that means we don't know if there was a better + * choice for the last slot, or not. Rescan. + */ + needscan = dfp == &d->hdr.bestfree[2]; + } + } + /* + * We match the last part of the entry. + * Trim the allocated space off the tail of the entry. + */ + else if (matchback) { + newdup = dup; + INT_SET(newdup->length, ARCH_CONVERT, (xfs_dir2_data_off_t) + (((char *)d + offset) - (char *)newdup)); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup); + /* + * If it was in the table, remove it and add the new one. + */ + if (dfp) { + xfs_dir2_data_freeremove(d, dfp, needlogp); + dfp = xfs_dir2_data_freeinsert(d, newdup, needlogp); + ASSERT(dfp != NULL); + ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(newdup->length, ARCH_CONVERT)); + ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) == (char *)newdup - (char *)d); + /* + * If we got inserted at the last slot, + * that means we don't know if there was a better + * choice for the last slot, or not. Rescan. + */ + needscan = dfp == &d->hdr.bestfree[2]; + } + } + /* + * Poking out the middle of an entry. + * Make two new entries. + */ + else { + newdup = dup; + INT_SET(newdup->length, ARCH_CONVERT, (xfs_dir2_data_off_t) + (((char *)d + offset) - (char *)newdup)); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup); + newdup2 = (xfs_dir2_data_unused_t *)((char *)d + offset + len); + INT_SET(newdup2->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + INT_SET(newdup2->length, ARCH_CONVERT, oldlen - len - INT_GET(newdup->length, ARCH_CONVERT)); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup2, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup2 - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup2); + /* + * If the old entry was in the table, we need to scan + * if the 3rd entry was valid, since these entries + * are smaller than the old one. + * If we don't need to scan that means there were 1 or 2 + * entries in the table, and removing the old and adding + * the 2 new will work. + */ + if (dfp) { + needscan = INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT) != 0; + if (!needscan) { + xfs_dir2_data_freeremove(d, dfp, needlogp); + (void)xfs_dir2_data_freeinsert(d, newdup, + needlogp); + (void)xfs_dir2_data_freeinsert(d, newdup2, + needlogp); + } + } + } + *needscanp = needscan; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir2_leaf.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir2_leaf.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir2_leaf.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir2_leaf.c Thu Apr 12 18:30:32 2001 @@ -0,0 +1,1471 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_leaf.c + * XFS directory version 2 implementation - single leaf form + * see xfs_dir2_leaf.h for data structures. + * These directories have multiple XFS_DIR2_DATA blocks and one + * XFS_DIR2_LEAF1 block containing the hash table and freespace map. + */ + +#include + + +/* + * Convert a block form directory to a leaf form directory. + */ +int /* error */ +xfs_dir2_block_to_leaf( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *dbp) /* input block's buffer */ +{ + xfs_dir2_data_off_t *bestsp; /* leaf's bestsp entries */ + xfs_dablk_t blkno; /* leaf block's bno */ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block's leaf entries */ + xfs_dir2_block_tail_t *btp; /* block's tail */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + xfs_dabuf_t *lbp; /* leaf block's buffer */ + xfs_dir2_db_t ldb; /* leaf block's bno */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf's tail */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log block header */ + int needscan; /* need to rescan bestfree */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_b("block_to_leaf", args, dbp); + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + /* + * Add the leaf block to the inode. + * This interface will only put blocks in the leaf/node range. + * Since that's empty now, we'll get the root (block 0 in range). + */ + if ((error = xfs_da_grow_inode(args, &blkno))) { + return error; + } + ldb = XFS_DIR2_DA_TO_DB(mp, blkno); + ASSERT(ldb == XFS_DIR2_LEAF_FIRSTDB(mp)); + /* + * Initialize the leaf block, get a buffer for it. + */ + if ((error = xfs_dir2_leaf_init(args, ldb, &lbp, XFS_DIR2_LEAF1_MAGIC))) { + return error; + } + ASSERT(lbp != NULL); + leaf = lbp->data; + block = dbp->data; + xfs_dir2_data_check(dp, dbp); + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Set the counts in the leaf header. + */ + INT_COPY(leaf->hdr.count, btp->count, ARCH_CONVERT); /* INT_: type change */ + INT_COPY(leaf->hdr.stale, btp->stale, ARCH_CONVERT); /* INT_: type change */ + /* + * Could compact these but I think we always do the conversion + * after squeezing out stale entries. + */ + bcopy(blp, leaf->ents, INT_GET(btp->count, ARCH_CONVERT) * sizeof(xfs_dir2_leaf_entry_t)); + xfs_dir2_leaf_log_ents(tp, lbp, 0, INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1); + needscan = 0; + needlog = 1; + /* + * Make the space formerly occupied by the leaf entries and block + * tail be free. + */ + xfs_dir2_data_make_free(tp, dbp, + (xfs_dir2_data_aoff_t)((char *)blp - (char *)block), + (xfs_dir2_data_aoff_t)((char *)block + mp->m_dirblksize - + (char *)blp), + &needlog, &needscan); + /* + * Fix up the block header, make it a data block. + */ + INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_DATA_MAGIC); + if (needscan) + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog, + NULL); + /* + * Set up leaf tail and bests table. + */ + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + INT_SET(ltp->bestcount, ARCH_CONVERT, 1); + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + INT_COPY(bestsp[0], block->hdr.bestfree[0].length, ARCH_CONVERT); + /* + * Log the data header and leaf bests table. + */ + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + xfs_dir2_leaf_check(dp, lbp); + xfs_dir2_data_check(dp, dbp); + xfs_dir2_leaf_log_bests(tp, lbp, 0, 0); + xfs_da_buf_done(lbp); + return 0; +} + +/* + * Add an entry to a leaf form directory. + */ +int /* error */ +xfs_dir2_leaf_addname( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_dir2_data_off_t *bestsp; /* freespace table in leaf */ + int compact; /* need to compact leaves */ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data block entry */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_data_unused_t *dup; /* data unused entry */ + int error; /* error return value */ + int grown; /* allocated new data block */ + int highstale; /* index of next stale leaf */ + int i; /* temporary, index */ + int index; /* leaf table position */ + xfs_dabuf_t *lbp; /* leaf's buffer */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + int length; /* length of new entry */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry table pointer */ + int lfloglow; /* low leaf logging index */ + int lfloghigh; /* high leaf logging index */ + int lowstale; /* index of prev stale leaf */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail pointer */ + xfs_mount_t *mp; /* filesystem mount point */ + int needbytes; /* leaf block bytes needed */ + int needlog; /* need to log data header */ + int needscan; /* need to rescan data free */ + xfs_dir2_data_off_t *tagp; /* end of data entry */ + xfs_trans_t *tp; /* transaction pointer */ + xfs_dir2_db_t use_block; /* data block number */ + + xfs_dir2_trace_args("leaf_addname", args); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + /* + * Read the leaf block. + */ + error = xfs_da_read_buf(tp, dp, mp->m_dirleafblk, -1, &lbp, + XFS_DATA_FORK); + if (error) { + return error; + } + ASSERT(lbp != NULL); + /* + * Look up the entry by hash value and name. + * We know it's not there, our caller has already done a lookup. + * So the index is of the entry to insert in front of. + * But if there are dup hash values the index is of the first of those. + */ + index = xfs_dir2_leaf_search_hash(args, lbp); + leaf = lbp->data; + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + length = XFS_DIR2_DATA_ENTSIZE(args->namelen); + /* + * See if there are any entries with the same hash value + * and space in their block for the new entry. + * This is good because it puts multiple same-hash value entries + * in a data block, improving the lookup of those entries. + */ + for (use_block = -1, lep = &leaf->ents[index]; + index < INT_GET(leaf->hdr.count, ARCH_CONVERT) && INT_GET(lep->hashval, ARCH_CONVERT) == args->hashval; + index++, lep++) { + if (INT_GET(lep->address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + continue; + i = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT)); + ASSERT(i < INT_GET(ltp->bestcount, ARCH_CONVERT)); + ASSERT(INT_GET(bestsp[i], ARCH_CONVERT) != NULLDATAOFF); + if (INT_GET(bestsp[i], ARCH_CONVERT) >= length) { + use_block = i; + break; + } + } + /* + * Didn't find a block yet, linear search all the data blocks. + */ + if (use_block == -1) { + for (i = 0; i < INT_GET(ltp->bestcount, ARCH_CONVERT); i++) { + /* + * Remember a block we see that's missing. + */ + if (INT_GET(bestsp[i], ARCH_CONVERT) == NULLDATAOFF && use_block == -1) + use_block = i; + else if (INT_GET(bestsp[i], ARCH_CONVERT) >= length) { + use_block = i; + break; + } + } + } + /* + * How many bytes do we need in the leaf block? + */ + needbytes = + (INT_GET(leaf->hdr.stale, ARCH_CONVERT) != 0 ? 0 : (uint)sizeof(leaf->ents[0])) + + (use_block != -1 ? 0 : (uint)sizeof(leaf->bests[0])); + /* + * Now kill use_block if it refers to a missing block, so we + * can use it as an indication of allocation needed. + */ + if (use_block != -1 && INT_GET(bestsp[use_block], ARCH_CONVERT) == NULLDATAOFF) + use_block = -1; + /* + * If we don't have enough free bytes but we can make enough + * by compacting out stale entries, we'll do that. + */ + if ((char *)bestsp - (char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] < needbytes && + INT_GET(leaf->hdr.stale, ARCH_CONVERT) > 1) { + compact = 1; + } + /* + * Otherwise if we don't have enough free bytes we need to + * convert to node form. + */ + else if ((char *)bestsp - (char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] < + needbytes) { + /* + * Just checking or no space reservation, give up. + */ + if (args->justcheck || args->total == 0) { + xfs_da_brelse(tp, lbp); + return XFS_ERROR(ENOSPC); + } + /* + * Convert to node form. + */ + error = xfs_dir2_leaf_to_node(args, lbp); + xfs_da_buf_done(lbp); + if (error) + return error; + /* + * Then add the new entry. + */ + return xfs_dir2_node_addname(args); + } + /* + * Otherwise it will fit without compaction. + */ + else + compact = 0; + /* + * If just checking, then it will fit unless we needed to allocate + * a new data block. + */ + if (args->justcheck) { + xfs_da_brelse(tp, lbp); + return use_block == -1 ? XFS_ERROR(ENOSPC) : 0; + } + /* + * If no allocations are allowed, return now before we've + * changed anything. + */ + if (args->total == 0 && use_block == -1) { + xfs_da_brelse(tp, lbp); + return XFS_ERROR(ENOSPC); + } + /* + * Need to compact the leaf entries, removing stale ones. + * Leave one stale entry behind - the one closest to our + * insertion index - and we'll shift that one to our insertion + * point later. + */ + if (compact) { + xfs_dir2_leaf_compact_x1(lbp, &index, &lowstale, &highstale, + &lfloglow, &lfloghigh); + } + /* + * There are stale entries, so we'll need log-low and log-high + * impossibly bad values later. + */ + else if (INT_GET(leaf->hdr.stale, ARCH_CONVERT)) { + lfloglow = INT_GET(leaf->hdr.count, ARCH_CONVERT); + lfloghigh = -1; + } + /* + * If there was no data block space found, we need to allocate + * a new one. + */ + if (use_block == -1) { + /* + * Add the new data block. + */ + if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, + &use_block))) { + xfs_da_brelse(tp, lbp); + return error; + } + /* + * Initialize the block. + */ + if ((error = xfs_dir2_data_init(args, use_block, &dbp))) { + xfs_da_brelse(tp, lbp); + return error; + } + /* + * If we're adding a new data block on the end we need to + * extend the bests table. Copy it up one entry. + */ + if (use_block >= INT_GET(ltp->bestcount, ARCH_CONVERT)) { + bestsp--; + ovbcopy(&bestsp[1], &bestsp[0], + INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(bestsp[0])); + INT_MOD(ltp->bestcount, ARCH_CONVERT, +1); + xfs_dir2_leaf_log_tail(tp, lbp); + xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1); + } + /* + * If we're filling in a previously empty block just log it. + */ + else + xfs_dir2_leaf_log_bests(tp, lbp, use_block, use_block); + data = dbp->data; + INT_COPY(bestsp[use_block], data->hdr.bestfree[0].length, ARCH_CONVERT); + grown = 1; + } + /* + * Already had space in some data block. + * Just read that one in. + */ + else { + if ((error = + xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, use_block), + -1, &dbp, XFS_DATA_FORK))) { + xfs_da_brelse(tp, lbp); + return error; + } + data = dbp->data; + grown = 0; + } + xfs_dir2_data_check(dp, dbp); + /* + * Point to the biggest freespace in our data block. + */ + dup = (xfs_dir2_data_unused_t *) + ((char *)data + INT_GET(data->hdr.bestfree[0].offset, ARCH_CONVERT)); + ASSERT(INT_GET(dup->length, ARCH_CONVERT) >= length); + needscan = needlog = 0; + /* + * Mark the initial part of our freespace in use for the new entry. + */ + xfs_dir2_data_use_free(tp, dbp, dup, + (xfs_dir2_data_aoff_t)((char *)dup - (char *)data), length, + &needlog, &needscan); + /* + * Initialize our new entry (at last). + */ + dep = (xfs_dir2_data_entry_t *)dup; + INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); + dep->namelen = args->namelen; + bcopy(args->name, dep->name, dep->namelen); + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)data)); + /* + * Need to scan fix up the bestfree table. + */ + if (needscan) + xfs_dir2_data_freescan(mp, data, &needlog, NULL); + /* + * Need to log the data block's header. + */ + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + xfs_dir2_data_log_entry(tp, dbp, dep); + /* + * If the bests table needs to be changed, do it. + * Log the change unless we've already done that. + */ + if (INT_GET(bestsp[use_block], ARCH_CONVERT) != INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT)) { + INT_COPY(bestsp[use_block], data->hdr.bestfree[0].length, ARCH_CONVERT); + if (!grown) + xfs_dir2_leaf_log_bests(tp, lbp, use_block, use_block); + } + /* + * Now we need to make room to insert the leaf entry. + * If there are no stale entries, we just insert a hole at index. + */ + if (INT_GET(leaf->hdr.stale, ARCH_CONVERT) == 0) { + /* + * lep is still good as the index leaf entry. + */ + if (index < INT_GET(leaf->hdr.count, ARCH_CONVERT)) + ovbcopy(lep, lep + 1, + (INT_GET(leaf->hdr.count, ARCH_CONVERT) - index) * sizeof(*lep)); + /* + * Record low and high logging indices for the leaf. + */ + lfloglow = index; + lfloghigh = INT_GET(leaf->hdr.count, ARCH_CONVERT); + INT_MOD(leaf->hdr.count, ARCH_CONVERT, +1); + } + /* + * There are stale entries. + * We will use one of them for the new entry. + * It's probably not at the right location, so we'll have to + * shift some up or down first. + */ + else { + /* + * If we didn't compact before, we need to find the nearest + * stale entries before and after our insertion point. + */ + if (compact == 0) { + /* + * Find the first stale entry before the insertion + * point, if any. + */ + for (lowstale = index - 1; + lowstale >= 0 && + INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) != + XFS_DIR2_NULL_DATAPTR; + lowstale--) + continue; + /* + * Find the next stale entry at or after the insertion + * point, if any. Stop if we go so far that the + * lowstale entry would be better. + */ + for (highstale = index; + highstale < INT_GET(leaf->hdr.count, ARCH_CONVERT) && + INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) != + XFS_DIR2_NULL_DATAPTR && + (lowstale < 0 || + index - lowstale - 1 >= highstale - index); + highstale++) + continue; + } + /* + * If the low one is better, use it. + */ + if (lowstale >= 0 && + (highstale == INT_GET(leaf->hdr.count, ARCH_CONVERT) || + index - lowstale - 1 < highstale - index)) { + ASSERT(index - lowstale - 1 >= 0); + ASSERT(INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) == + XFS_DIR2_NULL_DATAPTR); + /* + * Copy entries up to cover the stale entry + * and make room for the new entry. + */ + if (index - lowstale - 1 > 0) + ovbcopy(&leaf->ents[lowstale + 1], + &leaf->ents[lowstale], + (index - lowstale - 1) * sizeof(*lep)); + lep = &leaf->ents[index - 1]; + lfloglow = MIN(lowstale, lfloglow); + lfloghigh = MAX(index - 1, lfloghigh); + } + /* + * The high one is better, so use that one. + */ + else { + ASSERT(highstale - index >= 0); + ASSERT(INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) == + XFS_DIR2_NULL_DATAPTR); + /* + * Copy entries down to copver the stale entry + * and make room for the new entry. + */ + if (highstale - index > 0) + ovbcopy(&leaf->ents[index], + &leaf->ents[index + 1], + (highstale - index) * sizeof(*lep)); + lep = &leaf->ents[index]; + lfloglow = MIN(index, lfloglow); + lfloghigh = MAX(highstale, lfloghigh); + } + INT_MOD(leaf->hdr.stale, ARCH_CONVERT, -1); + } + /* + * Fill in the new leaf entry. + */ + INT_SET(lep->hashval, ARCH_CONVERT, args->hashval); + INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_DB_OFF_TO_DATAPTR(mp, use_block, INT_GET(*tagp, ARCH_CONVERT))); + /* + * Log the leaf fields and give up the buffers. + */ + xfs_dir2_leaf_log_header(tp, lbp); + xfs_dir2_leaf_log_ents(tp, lbp, lfloglow, lfloghigh); + xfs_dir2_leaf_check(dp, lbp); + xfs_da_buf_done(lbp); + xfs_dir2_data_check(dp, dbp); + xfs_da_buf_done(dbp); + return 0; +} + + +#ifdef DEBUG +/* + * Check the internal consistency of a leaf1 block. + * Pop an assert if something is wrong. + */ +void +xfs_dir2_leaf_check( + xfs_inode_t *dp, /* incore directory inode */ + xfs_dabuf_t *bp) /* leaf's buffer */ +{ + int i; /* leaf index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail pointer */ + xfs_mount_t *mp; /* filesystem mount point */ + int stale; /* count of stale leaves */ + + leaf = bp->data; + mp = dp->i_mount; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC); + /* + * This value is not restrictive enough. + * Should factor in the size of the bests table as well. + * We can deduce a value for that from di_size. + */ + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) <= XFS_DIR2_MAX_LEAF_ENTS(mp)); + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + /* + * Leaves and bests don't overlap. + */ + ASSERT((char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] <= + (char *)XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT)); + /* + * Check hash value order, count stale entries. + */ + for (i = stale = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); i++) { + if (i + 1 < INT_GET(leaf->hdr.count, ARCH_CONVERT)) + ASSERT(INT_GET(leaf->ents[i].hashval, ARCH_CONVERT) <= + INT_GET(leaf->ents[i + 1].hashval, ARCH_CONVERT)); + if (INT_GET(leaf->ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + stale++; + } + ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) == stale); +} +#endif /* DEBUG */ + +/* + * Compact out any stale entries in the leaf. + * Log the header and changed leaf entries, if any. + */ +void +xfs_dir2_leaf_compact( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *bp) /* leaf buffer */ +{ + int from; /* source leaf index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + int loglow; /* first leaf entry to log */ + int to; /* target leaf index */ + + leaf = bp->data; + if (INT_GET(leaf->hdr.stale, ARCH_CONVERT) == 0) { + return; + } + /* + * Compress out the stale entries in place. + */ + for (from = to = 0, loglow = -1; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) { + if (INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + continue; + /* + * Only actually copy the entries that are different. + */ + if (from > to) { + if (loglow == -1) + loglow = to; + leaf->ents[to] = leaf->ents[from]; + } + to++; + } + /* + * Update and log the header, log the leaf entries. + */ + ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) == from - to); + INT_MOD(leaf->hdr.count, ARCH_CONVERT, -(INT_GET(leaf->hdr.stale, ARCH_CONVERT))); + INT_SET(leaf->hdr.stale, ARCH_CONVERT, 0); + xfs_dir2_leaf_log_header(args->trans, bp); + if (loglow != -1) + xfs_dir2_leaf_log_ents(args->trans, bp, loglow, to - 1); +} + +/* + * Compact the leaf entries, removing stale ones. + * Leave one stale entry behind - the one closest to our + * insertion index - and the caller will shift that one to our insertion + * point later. + * Return new insertion index, where the remaining stale entry is, + * and leaf logging indices. + */ +void +xfs_dir2_leaf_compact_x1( + xfs_dabuf_t *bp, /* leaf buffer */ + int *indexp, /* insertion index */ + int *lowstalep, /* out: stale entry before us */ + int *highstalep, /* out: stale entry after us */ + int *lowlogp, /* out: low log index */ + int *highlogp) /* out: high log index */ +{ + int from; /* source copy index */ + int highstale; /* stale entry at/after index */ + int index; /* insertion index */ + int keepstale; /* source index of kept stale */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + int lowstale; /* stale entry before index */ + int newindex=0; /* new insertion index */ + int to; /* destination copy index */ + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) > 1); + index = *indexp; + /* + * Find the first stale entry before our index, if any. + */ + for (lowstale = index - 1; + lowstale >= 0 && + INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR; + lowstale--) + continue; + /* + * Find the first stale entry at or after our index, if any. + * Stop if the answer would be worse than lowstale. + */ + for (highstale = index; + highstale < INT_GET(leaf->hdr.count, ARCH_CONVERT) && + INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR && + (lowstale < 0 || index - lowstale > highstale - index); + highstale++) + continue; + /* + * Pick the better of lowstale and highstale. + */ + if (lowstale >= 0 && + (highstale == INT_GET(leaf->hdr.count, ARCH_CONVERT) || + index - lowstale <= highstale - index)) + keepstale = lowstale; + else + keepstale = highstale; + /* + * Copy the entries in place, removing all the stale entries + * except keepstale. + */ + for (from = to = 0; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) { + /* + * Notice the new value of index. + */ + if (index == from) + newindex = to; + if (from != keepstale && + INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) { + if (from == to) + *lowlogp = to; + continue; + } + /* + * Record the new keepstale value for the insertion. + */ + if (from == keepstale) + lowstale = highstale = to; + /* + * Copy only the entries that have moved. + */ + if (from > to) + leaf->ents[to] = leaf->ents[from]; + to++; + } + ASSERT(from > to); + /* + * If the insertion point was past the last entry, + * set the new insertion point accordingly. + */ + if (index == from) + newindex = to; + *indexp = newindex; + /* + * Adjust the leaf header values. + */ + INT_MOD(leaf->hdr.count, ARCH_CONVERT, -(from - to)); + INT_SET(leaf->hdr.stale, ARCH_CONVERT, 1); + /* + * Remember the low/high stale value only in the "right" + * direction. + */ + if (lowstale >= newindex) + lowstale = -1; + else + highstale = INT_GET(leaf->hdr.count, ARCH_CONVERT); + *highlogp = INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1; + *lowstalep = lowstale; + *highstalep = highstale; +} + +/* + * Initialize a new leaf block, leaf1 or leafn magic accepted. + */ +int +xfs_dir2_leaf_init( + xfs_da_args_t *args, /* operation arguments */ + xfs_dir2_db_t bno, /* directory block number */ + xfs_dabuf_t **bpp, /* out: leaf buffer */ + int magic) /* magic number for block */ +{ + xfs_dabuf_t *bp; /* leaf buffer */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + ASSERT(dp != NULL); + tp = args->trans; + mp = dp->i_mount; + ASSERT(bno >= XFS_DIR2_LEAF_FIRSTDB(mp) && + bno < XFS_DIR2_FREE_FIRSTDB(mp)); + /* + * Get the buffer for the block. + */ + error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, bno), -1, &bp, + XFS_DATA_FORK); + if (error) { + return error; + } + ASSERT(bp != NULL); + leaf = bp->data; + /* + * Initialize the header. + */ + INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, magic); + INT_ZERO(leaf->hdr.info.forw, ARCH_CONVERT); + INT_ZERO(leaf->hdr.info.back, ARCH_CONVERT); + INT_ZERO(leaf->hdr.count, ARCH_CONVERT); + INT_ZERO(leaf->hdr.stale, ARCH_CONVERT); + xfs_dir2_leaf_log_header(tp, bp); + /* + * If it's a leaf-format directory initialize the tail. + * In this case our caller has the real bests table to copy into + * the block. + */ + if (magic == XFS_DIR2_LEAF1_MAGIC) { + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + INT_SET(ltp->bestcount, ARCH_CONVERT, 0); + xfs_dir2_leaf_log_tail(tp, bp); + } + *bpp = bp; + return 0; +} + +/* + * Log the bests entries indicated from a leaf1 block. + */ +void +xfs_dir2_leaf_log_bests( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* leaf buffer */ + int first, /* first entry to log */ + int last) /* last entry to log */ +{ + xfs_dir2_data_off_t *firstb; /* pointer to first entry */ + xfs_dir2_data_off_t *lastb; /* pointer to last entry */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC); + ltp = XFS_DIR2_LEAF_TAIL_P(tp->t_mountp, leaf); + firstb = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT) + first; + lastb = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT) + last; + xfs_da_log_buf(tp, bp, (uint)((char *)firstb - (char *)leaf), + (uint)((char *)lastb - (char *)leaf + sizeof(*lastb) - 1)); +} + +/* + * Log the leaf entries indicated from a leaf1 or leafn block. + */ +void +xfs_dir2_leaf_log_ents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* leaf buffer */ + int first, /* first entry to log */ + int last) /* last entry to log */ +{ + xfs_dir2_leaf_entry_t *firstlep; /* pointer to first entry */ + xfs_dir2_leaf_entry_t *lastlep; /* pointer to last entry */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC || + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + firstlep = &leaf->ents[first]; + lastlep = &leaf->ents[last]; + xfs_da_log_buf(tp, bp, (uint)((char *)firstlep - (char *)leaf), + (uint)((char *)lastlep - (char *)leaf + sizeof(*lastlep) - 1)); +} + +/* + * Log the header of the leaf1 or leafn block. + */ +void +xfs_dir2_leaf_log_header( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp) /* leaf buffer */ +{ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC || + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + xfs_da_log_buf(tp, bp, (uint)((char *)&leaf->hdr - (char *)leaf), + (uint)(sizeof(leaf->hdr) - 1)); +} + +/* + * Log the tail of the leaf1 block. + */ +void +xfs_dir2_leaf_log_tail( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp) /* leaf buffer */ +{ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* filesystem mount point */ + + mp = tp->t_mountp; + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC); + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + xfs_da_log_buf(tp, bp, (uint)((char *)ltp - (char *)leaf), + (uint)(mp->m_dirblksize - 1)); +} + +/* + * Look up the entry referred to by args in the leaf format directory. + * Most of the work is done by the xfs_dir2_leaf_lookup_int routine which + * is also used by the node-format code. + */ +int +xfs_dir2_leaf_lookup( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data block entry */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + int index; /* found entry index */ + xfs_dabuf_t *lbp; /* leaf buffer */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args("leaf_lookup", args); + /* + * Look up name in the leaf block, returning both buffers and index. + */ + if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { + return error; + } + tp = args->trans; + dp = args->dp; + xfs_dir2_leaf_check(dp, lbp); + leaf = lbp->data; + /* + * Get to the leaf entry and contained data entry address. + */ + lep = &leaf->ents[index]; + /* + * Point to the data entry. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)dbp->data + + XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, INT_GET(lep->address, ARCH_CONVERT))); + /* + * Return the found inode number. + */ + args->inumber = INT_GET(dep->inumber, ARCH_CONVERT); + xfs_da_brelse(tp, dbp); + xfs_da_brelse(tp, lbp); + return XFS_ERROR(EEXIST); +} + +/* + * Look up name/hash in the leaf block. + * Fill in indexp with the found index, and dbpp with the data buffer. + * If not found dbpp will be NULL, and ENOENT comes back. + * lbpp will always be filled in with the leaf buffer unless there's an error. + */ +STATIC int /* error */ +xfs_dir2_leaf_lookup_int( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t **lbpp, /* out: leaf buffer */ + int *indexp, /* out: index in leaf block */ + xfs_dabuf_t **dbpp) /* out: data buffer */ +{ + xfs_dir2_db_t curdb; /* current data block number */ + xfs_dabuf_t *dbp; /* data buffer */ + xfs_dir2_data_entry_t *dep; /* data entry */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + int index; /* index in leaf block */ + xfs_dabuf_t *lbp; /* leaf buffer */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_dir2_db_t newdb; /* new data block number */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + /* + * Read the leaf block into the buffer. + */ + if ((error = + xfs_da_read_buf(tp, dp, mp->m_dirleafblk, -1, &lbp, + XFS_DATA_FORK))) { + return error; + } + *lbpp = lbp; + leaf = lbp->data; + xfs_dir2_leaf_check(dp, lbp); + /* + * Look for the first leaf entry with our hash value. + */ + index = xfs_dir2_leaf_search_hash(args, lbp); + /* + * Loop over all the entries with the right hash value + * looking to match the name. + */ + for (lep = &leaf->ents[index], dbp = NULL, curdb = -1; + index < INT_GET(leaf->hdr.count, ARCH_CONVERT) && INT_GET(lep->hashval, ARCH_CONVERT) == args->hashval; + lep++, index++) { + /* + * Skip over stale leaf entries. + */ + if (INT_GET(lep->address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + continue; + /* + * Get the new data block number. + */ + newdb = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT)); + /* + * If it's not the same as the old data block number, + * need to pitch the old one and read the new one. + */ + if (newdb != curdb) { + if (dbp) + xfs_da_brelse(tp, dbp); + if ((error = + xfs_da_read_buf(tp, dp, + XFS_DIR2_DB_TO_DA(mp, newdb), -1, &dbp, + XFS_DATA_FORK))) { + xfs_da_brelse(tp, lbp); + return error; + } + xfs_dir2_data_check(dp, dbp); + curdb = newdb; + } + /* + * Point to the data entry. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)dbp->data + + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT))); + /* + * If it matches then return it. + */ + if (dep->namelen == args->namelen && + dep->name[0] == args->name[0] && + bcmp(dep->name, args->name, args->namelen) == 0) { + *dbpp = dbp; + *indexp = index; + return 0; + } + } + /* + * No match found, return ENOENT. + */ + ASSERT(args->oknoent); + if (dbp) + xfs_da_brelse(tp, dbp); + xfs_da_brelse(tp, lbp); + return XFS_ERROR(ENOENT); +} + +/* + * Remove an entry from a leaf format directory. + */ +int /* error */ +xfs_dir2_leaf_removename( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_dir2_data_off_t *bestsp; /* leaf block best freespace */ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dir2_db_t db; /* data block number */ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data entry structure */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + xfs_dir2_db_t i; /* temporary data block # */ + int index; /* index into leaf entries */ + xfs_dabuf_t *lbp; /* leaf buffer */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log data header */ + int needscan; /* need to rescan data frees */ + xfs_dir2_data_off_t oldbest; /* old value of best free */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args("leaf_removename", args); + /* + * Lookup the leaf entry, get the leaf and data blocks read in. + */ + if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { + return error; + } + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + leaf = lbp->data; + data = dbp->data; + xfs_dir2_data_check(dp, dbp); + /* + * Point to the leaf entry, use that to point to the data entry. + */ + lep = &leaf->ents[index]; + db = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT)); + dep = (xfs_dir2_data_entry_t *) + ((char *)data + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT))); + needscan = needlog = 0; + oldbest = INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT); + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + ASSERT(INT_GET(bestsp[db], ARCH_CONVERT) == oldbest); + /* + * Mark the former data entry unused. + */ + xfs_dir2_data_make_free(tp, dbp, + (xfs_dir2_data_aoff_t)((char *)dep - (char *)data), + XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan); + /* + * We just mark the leaf entry stale by putting a null in it. + */ + INT_MOD(leaf->hdr.stale, ARCH_CONVERT, +1); + xfs_dir2_leaf_log_header(tp, lbp); + INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_NULL_DATAPTR); + xfs_dir2_leaf_log_ents(tp, lbp, index, index); + /* + * Scan the freespace in the data block again if necessary, + * log the data block header if necessary. + */ + if (needscan) + xfs_dir2_data_freescan(mp, data, &needlog, NULL); + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + /* + * If the longest freespace in the data block has changed, + * put the new value in the bests table and log that. + */ + if (INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) != oldbest) { + INT_COPY(bestsp[db], data->hdr.bestfree[0].length, ARCH_CONVERT); + xfs_dir2_leaf_log_bests(tp, lbp, db, db); + } + xfs_dir2_data_check(dp, dbp); + /* + * If the data block is now empty then get rid of the data block. + */ + if (INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) == + mp->m_dirblksize - (uint)sizeof(data->hdr)) { + ASSERT(db != mp->m_dirdatablk); + if ((error = xfs_dir2_shrink_inode(args, db, dbp))) { + /* + * Nope, can't get rid of it because it caused + * allocation of a bmap btree block to do so. + * Just go on, returning success, leaving the + * empty block in place. + */ + if (error == ENOSPC && args->total == 0) { + xfs_da_buf_done(dbp); + error = 0; + } + xfs_dir2_leaf_check(dp, lbp); + xfs_da_buf_done(lbp); + return error; + } + dbp = NULL; + /* + * If this is the last data block then compact the + * bests table by getting rid of entries. + */ + if (db == INT_GET(ltp->bestcount, ARCH_CONVERT) - 1) { + /* + * Look for the last active entry (i). + */ + for (i = db - 1; i > 0; i--) { + if (INT_GET(bestsp[i], ARCH_CONVERT) != NULLDATAOFF) + break; + } + /* + * Copy the table down so inactive entries at the + * end are removed. + */ + ovbcopy(bestsp, &bestsp[db - i], + (INT_GET(ltp->bestcount, ARCH_CONVERT) - (db - i)) * sizeof(*bestsp)); + INT_MOD(ltp->bestcount, ARCH_CONVERT, -(db - i)); + xfs_dir2_leaf_log_tail(tp, lbp); + xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1); + } else + INT_SET(bestsp[db], ARCH_CONVERT, NULLDATAOFF); + } + /* + * If the data block was not the first one, drop it. + */ + else if (db != mp->m_dirdatablk && dbp != NULL) { + xfs_da_buf_done(dbp); + dbp = NULL; + } + xfs_dir2_leaf_check(dp, lbp); + /* + * See if we can convert to block form. + */ + return xfs_dir2_leaf_to_block(args, lbp, dbp); +} + +/* + * Replace the inode number in a leaf format directory entry. + */ +int /* error */ +xfs_dir2_leaf_replace( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data block entry */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + int index; /* index of leaf entry */ + xfs_dabuf_t *lbp; /* leaf buffer */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args("leaf_replace", args); + /* + * Look up the entry. + */ + if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { + return error; + } + dp = args->dp; + leaf = lbp->data; + /* + * Point to the leaf entry, get data address from it. + */ + lep = &leaf->ents[index]; + /* + * Point to the data entry. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)dbp->data + + XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, INT_GET(lep->address, ARCH_CONVERT))); + ASSERT(args->inumber != INT_GET(dep->inumber, ARCH_CONVERT)); + /* + * Put the new inode number in, log it. + */ + INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); + tp = args->trans; + xfs_dir2_data_log_entry(tp, dbp, dep); + xfs_da_buf_done(dbp); + xfs_dir2_leaf_check(dp, lbp); + xfs_da_brelse(tp, lbp); + return 0; +} + +/* + * Return index in the leaf block (lbp) which is either the first + * one with this hash value, or if there are none, the insert point + * for that hash value. + */ +int /* index value */ +xfs_dir2_leaf_search_hash( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *lbp) /* leaf buffer */ +{ + xfs_dahash_t hash=0; /* hash from this entry */ + xfs_dahash_t hashwant; /* hash value looking for */ + int high; /* high leaf index */ + int low; /* low leaf index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + int mid=0; /* current leaf index */ + + leaf = lbp->data; +#ifndef __KERNEL__ + if (INT_GET(leaf->hdr.count, ARCH_CONVERT) == 0) + return 0; +#endif + /* + * Note, the table cannot be empty, so we have to go through the loop. + * Binary search the leaf entries looking for our hash value. + */ + for (lep = leaf->ents, low = 0, high = INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1, + hashwant = args->hashval; + low <= high; ) { + mid = (low + high) >> 1; + if ((hash = INT_GET(lep[mid].hashval, ARCH_CONVERT)) == hashwant) + break; + if (hash < hashwant) + low = mid + 1; + else + high = mid - 1; + } + /* + * Found one, back up through all the equal hash values. + */ + if (hash == hashwant) { + while (mid > 0 && INT_GET(lep[mid - 1].hashval, ARCH_CONVERT) == hashwant) { + mid--; + } + } + /* + * Need to point to an entry higher than ours. + */ + else if (hash < hashwant) + mid++; + return mid; +} + +/* + * Trim off a trailing data block. We know it's empty since the leaf + * freespace table says so. + */ +int /* error */ +xfs_dir2_leaf_trim_data( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *lbp, /* leaf buffer */ + xfs_dir2_db_t db) /* data block number */ +{ + xfs_dir2_data_off_t *bestsp; /* leaf bests table */ +#ifdef DEBUG + xfs_dir2_data_t *data; /* data block structure */ +#endif + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + /* + * Read the offending data block. We need its buffer. + */ + if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, db), -1, &dbp, + XFS_DATA_FORK))) { + return error; + } +#ifdef DEBUG + data = dbp->data; + ASSERT(INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC); +#endif + /* this seems to be an error + * data is only valid if DEBUG is defined? + * RMC 09/08/1999 + */ + + leaf = lbp->data; + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + ASSERT(INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) == + mp->m_dirblksize - (uint)sizeof(data->hdr)); + ASSERT(db == INT_GET(ltp->bestcount, ARCH_CONVERT) - 1); + /* + * Get rid of the data block. + */ + if ((error = xfs_dir2_shrink_inode(args, db, dbp))) { + ASSERT(error != ENOSPC); + xfs_da_brelse(tp, dbp); + return error; + } + /* + * Eliminate the last bests entry from the table. + */ + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + INT_MOD(ltp->bestcount, ARCH_CONVERT, -1); + ovbcopy(&bestsp[0], &bestsp[1], INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(*bestsp)); + xfs_dir2_leaf_log_tail(tp, lbp); + xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1); + return 0; +} + +/* + * Convert node form directory to leaf form directory. + * The root of the node form dir needs to already be a LEAFN block. + * Just return if we can't do anything. + */ +int /* error */ +xfs_dir2_node_to_leaf( + xfs_da_state_t *state) /* directory operation state */ +{ + xfs_da_args_t *args; /* operation arguments */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + xfs_dabuf_t *fbp; /* buffer for freespace block */ + xfs_fileoff_t fo; /* freespace file offset */ + xfs_dir2_free_t *free; /* freespace structure */ + xfs_dabuf_t *lbp; /* buffer for leaf block */ + xfs_dir2_leaf_tail_t *ltp; /* tail of leaf structure */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_mount_t *mp; /* filesystem mount point */ + int rval; /* successful free trim? */ + xfs_trans_t *tp; /* transaction pointer */ + + /* + * There's more than a leaf level in the btree, so there must + * be multiple leafn blocks. Give up. + */ + if (state->path.active > 1) + return 0; + args = state->args; + xfs_dir2_trace_args("node_to_leaf", args); + mp = state->mp; + dp = args->dp; + tp = args->trans; + /* + * Get the last offset in the file. + */ + if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK))) { + return error; + } + fo -= mp->m_dirblkfsbs; + /* + * If there are freespace blocks other than the first one, + * take this opportunity to remove trailing empty freespace blocks + * that may have been left behind during no-space-reservation + * operations. + */ + while (fo > mp->m_dirfreeblk) { + if ((error = xfs_dir2_node_trim_free(args, fo, &rval))) { + return error; + } + if (rval) + fo -= mp->m_dirblkfsbs; + else + return 0; + } + /* + * Now find the block just before the freespace block. + */ + if ((error = xfs_bmap_last_before(tp, dp, &fo, XFS_DATA_FORK))) { + return error; + } + /* + * If it's not the single leaf block, give up. + */ + if (XFS_FSB_TO_B(mp, fo) > XFS_DIR2_LEAF_OFFSET + mp->m_dirblksize) + return 0; + lbp = state->path.blk[0].bp; + leaf = lbp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + /* + * Read the freespace block. + */ + if ((error = xfs_da_read_buf(tp, dp, mp->m_dirfreeblk, -1, &fbp, + XFS_DATA_FORK))) { + return error; + } + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + ASSERT(INT_ISZERO(free->hdr.firstdb, ARCH_CONVERT)); + /* + * Now see if the leafn and free data will fit in a leaf1. + * If not, release the buffer and give up. + */ + if ((uint)sizeof(leaf->hdr) + + (INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT)) * (uint)sizeof(leaf->ents[0]) + + INT_GET(free->hdr.nvalid, ARCH_CONVERT) * (uint)sizeof(leaf->bests[0]) + + (uint)sizeof(leaf->tail) > + mp->m_dirblksize) { + xfs_da_brelse(tp, fbp); + return 0; + } + /* + * If the leaf has any stale entries in it, compress them out. + * The compact routine will log the header. + */ + if (INT_GET(leaf->hdr.stale, ARCH_CONVERT)) + xfs_dir2_leaf_compact(args, lbp); + else + xfs_dir2_leaf_log_header(tp, lbp); + INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, XFS_DIR2_LEAF1_MAGIC); + /* + * Set up the leaf tail from the freespace block. + */ + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + INT_COPY(ltp->bestcount, free->hdr.nvalid, ARCH_CONVERT); + /* + * Set up the leaf bests table. + */ + bcopy(free->bests, XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT), + INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(leaf->bests[0])); + xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1); + xfs_dir2_leaf_log_tail(tp, lbp); + xfs_dir2_leaf_check(dp, lbp); + /* + * Get rid of the freespace block. + */ + error = xfs_dir2_shrink_inode(args, XFS_DIR2_FREE_FIRSTDB(mp), fbp); + if (error) { + /* + * This can't fail here because it can only happen when + * punching out the middle of an extent, and this is an + * isolated block. + */ + ASSERT(error != ENOSPC); + return error; + } + fbp = NULL; + /* + * Now see if we can convert the single-leaf directory + * down to a block form directory. + * This routine always kills the dabuf for the leaf, so + * eliminate it from the path. + */ + error = xfs_dir2_leaf_to_block(args, lbp, NULL); + state->path.blk[0].bp = NULL; + return error; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir2_node.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir2_node.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir2_node.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir2_node.c Thu Apr 12 19:04:55 2001 @@ -0,0 +1,1955 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_node.c + * XFS directory implementation, version 2, node form files + * See data structures in xfs_dir2_node.h and xfs_da_btree.h. + */ + +#include + +/* + * Log entries from a freespace block. + */ +void +xfs_dir2_free_log_bests( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* freespace buffer */ + int first, /* first entry to log */ + int last) /* last entry to log */ +{ + xfs_dir2_free_t *free; /* freespace structure */ + + free = bp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + xfs_da_log_buf(tp, bp, + (uint)((char *)&free->bests[first] - (char *)free), + (uint)((char *)&free->bests[last] - (char *)free + + sizeof(free->bests[0]) - 1)); +} + +/* + * Log header from a freespace block. + */ +static void +xfs_dir2_free_log_header( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp) /* freespace buffer */ +{ + xfs_dir2_free_t *free; /* freespace structure */ + + free = bp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + xfs_da_log_buf(tp, bp, (uint)((char *)&free->hdr - (char *)free), + (uint)(sizeof(xfs_dir2_free_hdr_t) - 1)); +} + +/* + * Convert a leaf-format directory to a node-format directory. + * We need to change the magic number of the leaf block, and copy + * the freespace table out of the leaf block into its own block. + */ +int /* error */ +xfs_dir2_leaf_to_node( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *lbp) /* leaf buffer */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + xfs_dabuf_t *fbp; /* freespace buffer */ + xfs_dir2_db_t fdb; /* freespace block number */ + xfs_dir2_free_t *free; /* freespace structure */ + xfs_dir2_data_off_t *from; /* pointer to freespace entry */ + int i; /* leaf freespace index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* filesystem mount point */ + int n; /* count of live freespc ents */ + xfs_dir2_data_off_t off; /* freespace entry value */ + xfs_dir2_data_off_t *to; /* pointer to freespace entry */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_b("leaf_to_node", args, lbp); + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + /* + * Add a freespace block to the directory. + */ + if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, &fdb))) { + return error; + } + ASSERT(fdb == XFS_DIR2_FREE_FIRSTDB(mp)); + /* + * Get the buffer for the new freespace block. + */ + if ((error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fdb), -1, &fbp, + XFS_DATA_FORK))) { + return error; + } + ASSERT(fbp != NULL); + free = fbp->data; + leaf = lbp->data; + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + /* + * Initialize the freespace block header. + */ + INT_SET(free->hdr.magic, ARCH_CONVERT, XFS_DIR2_FREE_MAGIC); + INT_ZERO(free->hdr.firstdb, ARCH_CONVERT); + ASSERT(INT_GET(ltp->bestcount, ARCH_CONVERT) <= (uint)dp->i_d.di_size / mp->m_dirblksize); + INT_COPY(free->hdr.nvalid, ltp->bestcount, ARCH_CONVERT); + /* + * Copy freespace entries from the leaf block to the new block. + * Count active entries. + */ + for (i = n = 0, from = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT), to = free->bests; + i < INT_GET(ltp->bestcount, ARCH_CONVERT); i++, from++, to++) { + if ((off = INT_GET(*from, ARCH_CONVERT)) != NULLDATAOFF) + n++; + INT_SET(*to, ARCH_CONVERT, off); + } + INT_SET(free->hdr.nused, ARCH_CONVERT, n); + INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, XFS_DIR2_LEAFN_MAGIC); + /* + * Log everything. + */ + xfs_dir2_leaf_log_header(tp, lbp); + xfs_dir2_free_log_header(tp, fbp); + xfs_dir2_free_log_bests(tp, fbp, 0, INT_GET(free->hdr.nvalid, ARCH_CONVERT) - 1); + xfs_da_buf_done(fbp); + xfs_dir2_leafn_check(dp, lbp); + return 0; +} + +/* + * Add a leaf entry to a leaf block in a node-form directory. + * The other work necessary is done from the caller. + */ +static int /* error */ +xfs_dir2_leafn_add( + xfs_dabuf_t *bp, /* leaf buffer */ + xfs_da_args_t *args, /* operation arguments */ + int index) /* insertion pt for new entry */ +{ + int compact; /* compacting stale leaves */ + xfs_inode_t *dp; /* incore directory inode */ + int highstale; /* next stale entry */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + int lfloghigh; /* high leaf entry logging */ + int lfloglow; /* low leaf entry logging */ + int lowstale; /* previous stale entry */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_sb("leafn_add", args, index, bp); + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + leaf = bp->data; + /* + * If there are already the maximum number of leaf entries in + * the block, if there are no stale entries it won't fit. + * Caller will do a split. If there are stale entries we'll do + * a compact. + */ + if (INT_GET(leaf->hdr.count, ARCH_CONVERT) == XFS_DIR2_MAX_LEAF_ENTS(mp)) { + if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) + return XFS_ERROR(ENOSPC); + compact = INT_GET(leaf->hdr.stale, ARCH_CONVERT) > 1; + } else + compact = 0; + ASSERT(index == 0 || INT_GET(leaf->ents[index - 1].hashval, ARCH_CONVERT) <= args->hashval); + ASSERT(index == INT_GET(leaf->hdr.count, ARCH_CONVERT) || + INT_GET(leaf->ents[index].hashval, ARCH_CONVERT) >= args->hashval); + + if (args->justcheck) + return 0; + + /* + * Compact out all but one stale leaf entry. Leaves behind + * the entry closest to index. + */ + if (compact) { + xfs_dir2_leaf_compact_x1(bp, &index, &lowstale, &highstale, + &lfloglow, &lfloghigh); + } + /* + * Set impossible logging indices for this case. + */ + else if (!INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) { + lfloglow = INT_GET(leaf->hdr.count, ARCH_CONVERT); + lfloghigh = -1; + } + /* + * No stale entries, just insert a space for the new entry. + */ + if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) { + lep = &leaf->ents[index]; + if (index < INT_GET(leaf->hdr.count, ARCH_CONVERT)) + ovbcopy(lep, lep + 1, + (INT_GET(leaf->hdr.count, ARCH_CONVERT) - index) * sizeof(*lep)); + lfloglow = index; + lfloghigh = INT_GET(leaf->hdr.count, ARCH_CONVERT); + INT_MOD(leaf->hdr.count, ARCH_CONVERT, +1); + } + /* + * There are stale entries. We'll use one for the new entry. + */ + else { + /* + * If we didn't do a compact then we need to figure out + * which stale entry will be used. + */ + if (compact == 0) { + /* + * Find first stale entry before our insertion point. + */ + for (lowstale = index - 1; + lowstale >= 0 && + INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) != + XFS_DIR2_NULL_DATAPTR; + lowstale--) + continue; + /* + * Find next stale entry after insertion point. + * Stop looking if the answer would be worse than + * lowstale already found. + */ + for (highstale = index; + highstale < INT_GET(leaf->hdr.count, ARCH_CONVERT) && + INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) != + XFS_DIR2_NULL_DATAPTR && + (lowstale < 0 || + index - lowstale - 1 >= highstale - index); + highstale++) + continue; + } + /* + * Using the low stale entry. + * Shift entries up toward the stale slot. + */ + if (lowstale >= 0 && + (highstale == INT_GET(leaf->hdr.count, ARCH_CONVERT) || + index - lowstale - 1 < highstale - index)) { + ASSERT(INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) == + XFS_DIR2_NULL_DATAPTR); + ASSERT(index - lowstale - 1 >= 0); + if (index - lowstale - 1 > 0) + ovbcopy(&leaf->ents[lowstale + 1], + &leaf->ents[lowstale], + (index - lowstale - 1) * sizeof(*lep)); + lep = &leaf->ents[index - 1]; + lfloglow = MIN(lowstale, lfloglow); + lfloghigh = MAX(index - 1, lfloghigh); + } + /* + * Using the high stale entry. + * Shift entries down toward the stale slot. + */ + else { + ASSERT(INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) == + XFS_DIR2_NULL_DATAPTR); + ASSERT(highstale - index >= 0); + if (highstale - index > 0) + ovbcopy(&leaf->ents[index], + &leaf->ents[index + 1], + (highstale - index) * sizeof(*lep)); + lep = &leaf->ents[index]; + lfloglow = MIN(index, lfloglow); + lfloghigh = MAX(highstale, lfloghigh); + } + INT_MOD(leaf->hdr.stale, ARCH_CONVERT, -1); + } + /* + * Insert the new entry, log everything. + */ + INT_SET(lep->hashval, ARCH_CONVERT, args->hashval); + INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_DB_OFF_TO_DATAPTR(mp, args->blkno, args->index)); + xfs_dir2_leaf_log_header(tp, bp); + xfs_dir2_leaf_log_ents(tp, bp, lfloglow, lfloghigh); + xfs_dir2_leafn_check(dp, bp); + return 0; +} + +#ifdef DEBUG +/* + * Check internal consistency of a leafn block. + */ +void +xfs_dir2_leafn_check( + xfs_inode_t *dp, /* incore directory inode */ + xfs_dabuf_t *bp) /* leaf buffer */ +{ + int i; /* leaf index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_mount_t *mp; /* filesystem mount point */ + int stale; /* count of stale leaves */ + + leaf = bp->data; + mp = dp->i_mount; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) <= XFS_DIR2_MAX_LEAF_ENTS(mp)); + for (i = stale = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); i++) { + if (i + 1 < INT_GET(leaf->hdr.count, ARCH_CONVERT)) { + ASSERT(INT_GET(leaf->ents[i].hashval, ARCH_CONVERT) <= + INT_GET(leaf->ents[i + 1].hashval, ARCH_CONVERT)); + } + if (INT_GET(leaf->ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + stale++; + } + ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) == stale); +} +#endif /* DEBUG */ + +/* + * Return the last hash value in the leaf. + * Stale entries are ok. + */ +xfs_dahash_t /* hash value */ +xfs_dir2_leafn_lasthash( + xfs_dabuf_t *bp, /* leaf buffer */ + int *count) /* count of entries in leaf */ +{ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + if (count) + *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + if (INT_ISZERO(leaf->hdr.count, ARCH_CONVERT)) + return 0; + return INT_GET(leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); +} + +/* + * Look up a leaf entry in a node-format leaf block. + * If this is an addname then the extrablk in state is a freespace block, + * otherwise it's a data block. + */ +int +xfs_dir2_leafn_lookup_int( + xfs_dabuf_t *bp, /* leaf buffer */ + xfs_da_args_t *args, /* operation arguments */ + int *indexp, /* out: leaf entry index */ + xfs_da_state_t *state) /* state to fill in */ +{ + xfs_dabuf_t *curbp; /* current data/free buffer */ + xfs_dir2_db_t curdb; /* current data block number */ + xfs_dir2_db_t curfdb; /* current free block number */ + xfs_dir2_data_entry_t *dep; /* data block entry */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + int fi; /* free entry index */ + xfs_dir2_free_t *free=NULL; /* free block structure */ + int index; /* leaf entry index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + int length=0; /* length of new data entry */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_dir2_db_t newdb; /* new data block number */ + xfs_dir2_db_t newfdb; /* new free block number */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); +#ifdef __KERNEL__ + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) > 0); +#endif + xfs_dir2_leafn_check(dp, bp); + /* + * Look up the hash value in the leaf entries. + */ + index = xfs_dir2_leaf_search_hash(args, bp); + /* + * Do we have a buffer coming in? + */ + if (state->extravalid) + curbp = state->extrablk.bp; + else + curbp = NULL; + /* + * For addname, it's a free block buffer, get the block number. + */ + if (args->addname) { + curfdb = curbp ? state->extrablk.blkno : -1; + curdb = -1; + length = XFS_DIR2_DATA_ENTSIZE(args->namelen); + if ((free = (curbp ? curbp->data : NULL))) + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + } + /* + * For others, it's a data block buffer, get the block number. + */ + else { + curfdb = -1; + curdb = curbp ? state->extrablk.blkno : -1; + } + /* + * Loop over leaf entries with the right hash value. + */ + for (lep = &leaf->ents[index]; + index < INT_GET(leaf->hdr.count, ARCH_CONVERT) && INT_GET(lep->hashval, ARCH_CONVERT) == args->hashval; + lep++, index++) { + /* + * Skip stale leaf entries. + */ + if (INT_GET(lep->address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + continue; + /* + * Pull the data block number from the entry. + */ + newdb = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT)); + /* + * For addname, we're looking for a place to put the new entry. + * We want to use a data block with an entry of equal + * hash value to ours if there is one with room. + */ + if (args->addname) { + /* + * If this block isn't the data block we already have + * in hand, take a look at it. + */ + if (newdb != curdb) { + curdb = newdb; + /* + * Convert the data block to the free block + * holding its freespace information. + */ + newfdb = XFS_DIR2_DB_TO_FDB(mp, newdb); + /* + * If it's not the one we have in hand, + * read it in. + */ + if (newfdb != curfdb) { + /* + * If we had one before, drop it. + */ + if (curbp) + xfs_da_brelse(tp, curbp); + /* + * Read the free block. + */ + if ((error = xfs_da_read_buf(tp, dp, + XFS_DIR2_DB_TO_DA(mp, + newfdb), + -1, &curbp, + XFS_DATA_FORK))) { + return error; + } + curfdb = newfdb; + free = curbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == + XFS_DIR2_FREE_MAGIC); + ASSERT((INT_GET(free->hdr.firstdb, ARCH_CONVERT) % + XFS_DIR2_MAX_FREE_BESTS(mp)) == + 0); + ASSERT(INT_GET(free->hdr.firstdb, ARCH_CONVERT) <= curdb); + ASSERT(curdb < + INT_GET(free->hdr.firstdb, ARCH_CONVERT) + + INT_GET(free->hdr.nvalid, ARCH_CONVERT)); + } + /* + * Get the index for our entry. + */ + fi = XFS_DIR2_DB_TO_FDINDEX(mp, curdb); + /* + * If it has room, return it. + */ + if (INT_GET(free->bests[fi], ARCH_CONVERT) == NULLDATAOFF) { + return XFS_ERROR(EFSCORRUPTED); + } + if (INT_GET(free->bests[fi], ARCH_CONVERT) >= length) { + *indexp = index; + state->extravalid = 1; + state->extrablk.bp = curbp; + state->extrablk.blkno = curfdb; + state->extrablk.index = fi; + state->extrablk.magic = + XFS_DIR2_FREE_MAGIC; + ASSERT(args->oknoent); + return XFS_ERROR(ENOENT); + } + } + } + /* + * Not adding a new entry, so we really want to find + * the name given to us. + */ + else { + /* + * If it's a different data block, go get it. + */ + if (newdb != curdb) { + /* + * If we had a block before, drop it. + */ + if (curbp) + xfs_da_brelse(tp, curbp); + /* + * Read the data block. + */ + if ((error = + xfs_da_read_buf(tp, dp, + XFS_DIR2_DB_TO_DA(mp, newdb), -1, + &curbp, XFS_DATA_FORK))) { + return error; + } + xfs_dir2_data_check(dp, curbp); + curdb = newdb; + } + /* + * Point to the data entry. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)curbp->data + + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT))); + /* + * Compare the entry, return it if it matches. + */ + if (dep->namelen == args->namelen && + dep->name[0] == args->name[0] && + bcmp(dep->name, args->name, args->namelen) == 0) { + args->inumber = INT_GET(dep->inumber, ARCH_CONVERT); + *indexp = index; + state->extravalid = 1; + state->extrablk.bp = curbp; + state->extrablk.blkno = curdb; + state->extrablk.index = + (int)((char *)dep - + (char *)curbp->data); + state->extrablk.magic = XFS_DIR2_DATA_MAGIC; + return XFS_ERROR(EEXIST); + } + } + } + /* + * Didn't find a match. + * If we are holding a buffer, give it back in case our caller + * finds it useful. + */ + if ((state->extravalid = (curbp != NULL))) { + state->extrablk.bp = curbp; + state->extrablk.index = -1; + /* + * For addname, giving back a free block. + */ + if (args->addname) { + state->extrablk.blkno = curfdb; + state->extrablk.magic = XFS_DIR2_FREE_MAGIC; + } + /* + * For other callers, giving back a data block. + */ + else { + state->extrablk.blkno = curdb; + state->extrablk.magic = XFS_DIR2_DATA_MAGIC; + } + } + /* + * Return the final index, that will be the insertion point. + */ + *indexp = index; + ASSERT(index == INT_GET(leaf->hdr.count, ARCH_CONVERT) || args->oknoent); + return XFS_ERROR(ENOENT); +} + +/* + * Move count leaf entries from source to destination leaf. + * Log entries and headers. Stale entries are preserved. + */ +static void +xfs_dir2_leafn_moveents( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *bp_s, /* source leaf buffer */ + int start_s, /* source leaf index */ + xfs_dabuf_t *bp_d, /* destination leaf buffer */ + int start_d, /* destination leaf index */ + int count) /* count of leaves to copy */ +{ + xfs_dir2_leaf_t *leaf_d; /* destination leaf structure */ + xfs_dir2_leaf_t *leaf_s; /* source leaf structure */ + int stale; /* count stale leaves copied */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_bibii("leafn_moveents", args, bp_s, start_s, bp_d, + start_d, count); + /* + * Silently return if nothing to do. + */ + if (count == 0) { + return; + } + tp = args->trans; + leaf_s = bp_s->data; + leaf_d = bp_d->data; + /* + * If the destination index is not the end of the current + * destination leaf entries, open up a hole in the destination + * to hold the new entries. + */ + if (start_d < INT_GET(leaf_d->hdr.count, ARCH_CONVERT)) { + ovbcopy(&leaf_d->ents[start_d], &leaf_d->ents[start_d + count], + (INT_GET(leaf_d->hdr.count, ARCH_CONVERT) - start_d) * + sizeof(xfs_dir2_leaf_entry_t)); + xfs_dir2_leaf_log_ents(tp, bp_d, start_d + count, + count + INT_GET(leaf_d->hdr.count, ARCH_CONVERT) - 1); + } + /* + * If the source has stale leaves, count the ones in the copy range + * so we can update the header correctly. + */ + if (!INT_ISZERO(leaf_s->hdr.stale, ARCH_CONVERT)) { + int i; /* temp leaf index */ + + for (i = start_s, stale = 0; i < start_s + count; i++) { + if (INT_GET(leaf_s->ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + stale++; + } + } else + stale = 0; + /* + * Copy the leaf entries from source to destination. + */ + bcopy(&leaf_s->ents[start_s], &leaf_d->ents[start_d], + count * sizeof(xfs_dir2_leaf_entry_t)); + xfs_dir2_leaf_log_ents(tp, bp_d, start_d, start_d + count - 1); + /* + * If there are source entries after the ones we copied, + * delete the ones we copied by sliding the next ones down. + */ + if (start_s + count < INT_GET(leaf_s->hdr.count, ARCH_CONVERT)) { + ovbcopy(&leaf_s->ents[start_s + count], &leaf_s->ents[start_s], + count * sizeof(xfs_dir2_leaf_entry_t)); + xfs_dir2_leaf_log_ents(tp, bp_s, start_s, start_s + count - 1); + } + /* + * Update the headers and log them. + */ + INT_MOD(leaf_s->hdr.count, ARCH_CONVERT, -(count)); + INT_MOD(leaf_s->hdr.stale, ARCH_CONVERT, -(stale)); + INT_MOD(leaf_d->hdr.count, ARCH_CONVERT, count); + INT_MOD(leaf_d->hdr.stale, ARCH_CONVERT, stale); + xfs_dir2_leaf_log_header(tp, bp_s); + xfs_dir2_leaf_log_header(tp, bp_d); + xfs_dir2_leafn_check(args->dp, bp_s); + xfs_dir2_leafn_check(args->dp, bp_d); +} + +/* + * Determine the sort order of two leaf blocks. + * Returns 1 if both are valid and leaf2 should be before leaf1, else 0. + */ +int /* sort order */ +xfs_dir2_leafn_order( + xfs_dabuf_t *leaf1_bp, /* leaf1 buffer */ + xfs_dabuf_t *leaf2_bp) /* leaf2 buffer */ +{ + xfs_dir2_leaf_t *leaf1; /* leaf1 structure */ + xfs_dir2_leaf_t *leaf2; /* leaf2 structure */ + + leaf1 = leaf1_bp->data; + leaf2 = leaf2_bp->data; + ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + if (INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0 && + INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0 && + (INT_GET(leaf2->ents[0].hashval, ARCH_CONVERT) < INT_GET(leaf1->ents[0].hashval, ARCH_CONVERT) || + INT_GET(leaf2->ents[INT_GET(leaf2->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT) < + INT_GET(leaf1->ents[INT_GET(leaf1->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT))) + return 1; + return 0; +} + +/* + * Rebalance leaf entries between two leaf blocks. + * This is actually only called when the second block is new, + * though the code deals with the general case. + * A new entry will be inserted in one of the blocks, and that + * entry is taken into account when balancing. + */ +static void +xfs_dir2_leafn_rebalance( + xfs_da_state_t *state, /* btree cursor */ + xfs_da_state_blk_t *blk1, /* first btree block */ + xfs_da_state_blk_t *blk2) /* second btree block */ +{ + xfs_da_args_t *args; /* operation arguments */ + int count; /* count (& direction) leaves */ + int isleft; /* new goes in left leaf */ + xfs_dir2_leaf_t *leaf1; /* first leaf structure */ + xfs_dir2_leaf_t *leaf2; /* second leaf structure */ + int mid; /* midpoint leaf index */ +#ifdef DEBUG + int oldstale; /* old count of stale leaves */ +#endif + int oldsum; /* old total leaf count */ + int swap; /* swapped leaf blocks */ + + args = state->args; + /* + * If the block order is wrong, swap the arguments. + */ + if ((swap = xfs_dir2_leafn_order(blk1->bp, blk2->bp))) { + xfs_da_state_blk_t *tmp; /* temp for block swap */ + + tmp = blk1; + blk1 = blk2; + blk2 = tmp; + } + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + oldsum = INT_GET(leaf1->hdr.count, ARCH_CONVERT) + INT_GET(leaf2->hdr.count, ARCH_CONVERT); +#ifdef DEBUG + oldstale = INT_GET(leaf1->hdr.stale, ARCH_CONVERT) + INT_GET(leaf2->hdr.stale, ARCH_CONVERT); +#endif + mid = oldsum >> 1; + /* + * If the old leaf count was odd then the new one will be even, + * so we need to divide the new count evenly. + */ + if (oldsum & 1) { + xfs_dahash_t midhash; /* middle entry hash value */ + + if (mid >= INT_GET(leaf1->hdr.count, ARCH_CONVERT)) + midhash = INT_GET(leaf2->ents[mid - INT_GET(leaf1->hdr.count, ARCH_CONVERT)].hashval, ARCH_CONVERT); + else + midhash = INT_GET(leaf1->ents[mid].hashval, ARCH_CONVERT); + isleft = args->hashval <= midhash; + } + /* + * If the old count is even then the new count is odd, so there's + * no preferred side for the new entry. + * Pick the left one. + */ + else + isleft = 1; + /* + * Calculate moved entry count. Positive means left-to-right, + * negative means right-to-left. Then move the entries. + */ + count = INT_GET(leaf1->hdr.count, ARCH_CONVERT) - mid + (isleft == 0); + if (count > 0) + xfs_dir2_leafn_moveents(args, blk1->bp, + INT_GET(leaf1->hdr.count, ARCH_CONVERT) - count, blk2->bp, 0, count); + else if (count < 0) + xfs_dir2_leafn_moveents(args, blk2->bp, 0, blk1->bp, + INT_GET(leaf1->hdr.count, ARCH_CONVERT), count); + ASSERT(INT_GET(leaf1->hdr.count, ARCH_CONVERT) + INT_GET(leaf2->hdr.count, ARCH_CONVERT) == oldsum); + ASSERT(INT_GET(leaf1->hdr.stale, ARCH_CONVERT) + INT_GET(leaf2->hdr.stale, ARCH_CONVERT) == oldstale); + /* + * Mark whether we're inserting into the old or new leaf. + */ + if (INT_GET(leaf1->hdr.count, ARCH_CONVERT) < INT_GET(leaf2->hdr.count, ARCH_CONVERT)) + state->inleaf = swap; + else if (INT_GET(leaf1->hdr.count, ARCH_CONVERT) > INT_GET(leaf2->hdr.count, ARCH_CONVERT)) + state->inleaf = !swap; + else + state->inleaf = + swap ^ (args->hashval < INT_GET(leaf2->ents[0].hashval, ARCH_CONVERT)); + /* + * Adjust the expected index for insertion. + */ + if (!state->inleaf) + blk2->index = blk1->index - INT_GET(leaf1->hdr.count, ARCH_CONVERT); +} + +/* + * Remove an entry from a node directory. + * This removes the leaf entry and the data entry, + * and updates the free block if necessary. + */ +STATIC int /* error */ +xfs_dir2_leafn_remove( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *bp, /* leaf buffer */ + int index, /* leaf entry index */ + xfs_da_state_blk_t *dblk, /* data block */ + int *rval) /* resulting block needs join */ +{ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dir2_db_t db; /* data block number */ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data block entry */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + int longest; /* longest data free entry */ + int off; /* data block entry offset */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log data header */ + int needscan; /* need to rescan data frees */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_sb("leafn_remove", args, index, bp); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + /* + * Point to the entry we're removing. + */ + lep = &leaf->ents[index]; + /* + * Extract the data block and offset from the entry. + */ + db = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT)); + ASSERT(dblk->blkno == db); + off = XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT)); + ASSERT(dblk->index == off); + /* + * Kill the leaf entry by marking it stale. + * Log the leaf block changes. + */ + INT_MOD(leaf->hdr.stale, ARCH_CONVERT, +1); + xfs_dir2_leaf_log_header(tp, bp); + INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_NULL_DATAPTR); + xfs_dir2_leaf_log_ents(tp, bp, index, index); + /* + * Make the data entry free. Keep track of the longest freespace + * in the data block in case it changes. + */ + dbp = dblk->bp; + data = dbp->data; + dep = (xfs_dir2_data_entry_t *)((char *)data + off); + longest = INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT); + needlog = needscan = 0; + xfs_dir2_data_make_free(tp, dbp, off, + XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan); + /* + * Rescan the data block freespaces for bestfree. + * Log the data block header if needed. + */ + if (needscan) + xfs_dir2_data_freescan(mp, data, &needlog, NULL); + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + xfs_dir2_data_check(dp, dbp); + /* + * If the longest data block freespace changes, need to update + * the corresponding freeblock entry. + */ + if (longest < INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT)) { + int error; /* error return value */ + xfs_dabuf_t *fbp; /* freeblock buffer */ + xfs_dir2_db_t fdb; /* freeblock block number */ + int findex; /* index in freeblock entries */ + xfs_dir2_free_t *free; /* freeblock structure */ + int logfree; /* need to log free entry */ + + /* + * Convert the data block number to a free block, + * read in the free block. + */ + fdb = XFS_DIR2_DB_TO_FDB(mp, db); + if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fdb), + -1, &fbp, XFS_DATA_FORK))) { + return error; + } + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + ASSERT(INT_GET(free->hdr.firstdb, ARCH_CONVERT) == + XFS_DIR2_MAX_FREE_BESTS(mp) * + (fdb - XFS_DIR2_FREE_FIRSTDB(mp))); + /* + * Calculate which entry we need to fix. + */ + findex = XFS_DIR2_DB_TO_FDINDEX(mp, db); + longest = INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT); + /* + * If the data block is now empty we can get rid of it + * (usually). + */ + if (longest == mp->m_dirblksize - (uint)sizeof(data->hdr)) { + /* + * Try to punch out the data block. + */ + error = xfs_dir2_shrink_inode(args, db, dbp); + if (error == 0) { + dblk->bp = NULL; + data = NULL; + } + /* + * We can get ENOSPC if there's no space reservation. + * In this case just drop the buffer and some one else + * will eventually get rid of the empty block. + */ + else if (error == ENOSPC && args->total == 0) + xfs_da_buf_done(dbp); + else + return error; + } + /* + * If we got rid of the data block, we can eliminate that entry + * in the free block. + */ + if (data == NULL) { + /* + * One less used entry in the free table. + */ + INT_MOD(free->hdr.nused, ARCH_CONVERT, -1); + xfs_dir2_free_log_header(tp, fbp); + /* + * If this was the last entry in the table, we can + * trim the table size back. There might be other + * entries at the end referring to non-existent + * data blocks, get those too. + */ + if (findex == INT_GET(free->hdr.nvalid, ARCH_CONVERT) - 1) { + int i; /* free entry index */ + + for (i = findex - 1; + i >= 0 && INT_GET(free->bests[i], ARCH_CONVERT) == NULLDATAOFF; + i--) + continue; + INT_SET(free->hdr.nvalid, ARCH_CONVERT, i + 1); + logfree = 0; + } + /* + * Not the last entry, just punch it out. + */ + else { + INT_SET(free->bests[findex], ARCH_CONVERT, NULLDATAOFF); + logfree = 1; + } + /* + * If there are no useful entries left in the block, + * get rid of the block if we can. + */ + if (INT_GET(free->hdr.nused, ARCH_CONVERT) == 0) { + error = xfs_dir2_shrink_inode(args, fdb, fbp); + if (error == 0) { + fbp = NULL; + logfree = 0; + } else if (error != ENOSPC || args->total != 0) + return error; + /* + * It's possible to get ENOSPC if there is no + * space reservation. In this case some one + * else will eventually get rid of this block. + */ + } + } + /* + * Data block is not empty, just set the free entry to + * the new value. + */ + else { + INT_SET(free->bests[findex], ARCH_CONVERT, longest); + logfree = 1; + } + /* + * Log the free entry that changed, unless we got rid of it. + */ + if (logfree) + xfs_dir2_free_log_bests(tp, fbp, findex, findex); + /* + * Drop the buffer if we still have it. + */ + if (fbp) + xfs_da_buf_done(fbp); + } + xfs_dir2_leafn_check(dp, bp); + /* + * Return indication of whether this leaf block is emtpy enough + * to justify trying to join it with a neighbor. + */ + *rval = + ((uint)sizeof(leaf->hdr) + + (uint)sizeof(leaf->ents[0]) * + (INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT))) < + mp->m_dir_magicpct; + return 0; +} + +/* + * Split the leaf entries in the old block into old and new blocks. + */ +int /* error */ +xfs_dir2_leafn_split( + xfs_da_state_t *state, /* btree cursor */ + xfs_da_state_blk_t *oldblk, /* original block */ + xfs_da_state_blk_t *newblk) /* newly created block */ +{ + xfs_da_args_t *args; /* operation arguments */ + xfs_dablk_t blkno; /* new leaf block number */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + + /* + * Allocate space for a new leaf node. + */ + args = state->args; + mp = args->dp->i_mount; + ASSERT(args != NULL); + ASSERT(oldblk->magic == XFS_DIR2_LEAFN_MAGIC); + error = xfs_da_grow_inode(args, &blkno); + if (error) { + return error; + } + /* + * Initialize the new leaf block. + */ + error = xfs_dir2_leaf_init(args, XFS_DIR2_DA_TO_DB(mp, blkno), + &newblk->bp, XFS_DIR2_LEAFN_MAGIC); + if (error) { + return error; + } + newblk->blkno = blkno; + newblk->magic = XFS_DIR2_LEAFN_MAGIC; + /* + * Rebalance the entries across the two leaves, link the new + * block into the leaves. + */ + xfs_dir2_leafn_rebalance(state, oldblk, newblk); + error = xfs_da_blk_link(state, oldblk, newblk); + if (error) { + return error; + } + /* + * Insert the new entry in the correct block. + */ + if (state->inleaf) + error = xfs_dir2_leafn_add(oldblk->bp, args, oldblk->index); + else + error = xfs_dir2_leafn_add(newblk->bp, args, newblk->index); + /* + * Update last hashval in each block since we added the name. + */ + oldblk->hashval = xfs_dir2_leafn_lasthash(oldblk->bp, NULL); + newblk->hashval = xfs_dir2_leafn_lasthash(newblk->bp, NULL); + xfs_dir2_leafn_check(args->dp, oldblk->bp); + xfs_dir2_leafn_check(args->dp, newblk->bp); + return error; +} + +/* + * Check a leaf block and its neighbors to see if the block should be + * collapsed into one or the other neighbor. Always keep the block + * with the smaller block number. + * If the current block is over 50% full, don't try to join it, return 0. + * If the block is empty, fill in the state structure and return 2. + * If it can be collapsed, fill in the state structure and return 1. + * If nothing can be done, return 0. + */ +int /* error */ +xfs_dir2_leafn_toosmall( + xfs_da_state_t *state, /* btree cursor */ + int *action) /* resulting action to take */ +{ + xfs_da_state_blk_t *blk; /* leaf block */ + xfs_dablk_t blkno; /* leaf block number */ + xfs_dabuf_t *bp; /* leaf buffer */ + int bytes; /* bytes in use */ + int count; /* leaf live entry count */ + int error; /* error return value */ + int forward; /* sibling block direction */ + int i; /* sibling counter */ + xfs_da_blkinfo_t *info; /* leaf block header */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + int rval; /* result from path_shift */ + + /* + * Check for the degenerate case of the block being over 50% full. + * If so, it's not worth even looking to see if we might be able + * to coalesce with a sibling. + */ + blk = &state->path.blk[state->path.active - 1]; + info = blk->bp->data; + ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + leaf = (xfs_dir2_leaf_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT); + bytes = (uint)sizeof(leaf->hdr) + count * (uint)sizeof(leaf->ents[0]); + if (bytes > (state->blocksize >> 1)) { + /* + * Blk over 50%, don't try to join. + */ + *action = 0; + return 0; + } + /* + * Check for the degenerate case of the block being empty. + * If the block is empty, we'll simply delete it, no need to + * coalesce it with a sibling block. We choose (arbitrarily) + * to merge with the forward block unless it is NULL. + */ + if (count == 0) { + /* + * Make altpath point to the block we want to keep and + * path point to the block we want to drop (this one). + */ + forward = !INT_ISZERO(info->forw, ARCH_CONVERT); + bcopy(&state->path, &state->altpath, sizeof(state->path)); + error = xfs_da_path_shift(state, &state->altpath, forward, 0, + &rval); + if (error) + return error; + *action = rval ? 2 : 0; + return 0; + } + /* + * Examine each sibling block to see if we can coalesce with + * at least 25% free space to spare. We need to figure out + * whether to merge with the forward or the backward block. + * We prefer coalescing with the lower numbered sibling so as + * to shrink a directory over time. + */ + forward = INT_GET(info->forw, ARCH_CONVERT) < INT_GET(info->back, ARCH_CONVERT); + for (i = 0, bp = NULL; i < 2; forward = !forward, i++) { + blkno = forward ?INT_GET( info->forw, ARCH_CONVERT) : INT_GET(info->back, ARCH_CONVERT); + if (blkno == 0) + continue; + /* + * Read the sibling leaf block. + */ + if ((error = + xfs_da_read_buf(state->args->trans, state->args->dp, blkno, + -1, &bp, XFS_DATA_FORK))) { + return error; + } + ASSERT(bp != NULL); + /* + * Count bytes in the two blocks combined. + */ + leaf = (xfs_dir2_leaf_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT); + bytes = state->blocksize - (state->blocksize >> 2); + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + count += INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT); + bytes -= count * (uint)sizeof(leaf->ents[0]); + /* + * Fits with at least 25% to spare. + */ + if (bytes >= 0) + break; + xfs_da_brelse(state->args->trans, bp); + } + /* + * Didn't like either block, give up. + */ + if (i >= 2) { + *action = 0; + return 0; + } + /* + * Done with the sibling leaf block here, drop the dabuf + * so path_shift can get it. + */ + xfs_da_buf_done(bp); + /* + * Make altpath point to the block we want to keep (the lower + * numbered block) and path point to the block we want to drop. + */ + bcopy(&state->path, &state->altpath, sizeof(state->path)); + if (blkno < blk->blkno) + error = xfs_da_path_shift(state, &state->altpath, forward, 0, + &rval); + else + error = xfs_da_path_shift(state, &state->path, forward, 0, + &rval); + if (error) { + return error; + } + *action = rval ? 0 : 1; + return 0; +} + +/* + * Move all the leaf entries from drop_blk to save_blk. + * This is done as part of a join operation. + */ +void +xfs_dir2_leafn_unbalance( + xfs_da_state_t *state, /* cursor */ + xfs_da_state_blk_t *drop_blk, /* dead block */ + xfs_da_state_blk_t *save_blk) /* surviving block */ +{ + xfs_da_args_t *args; /* operation arguments */ + xfs_dir2_leaf_t *drop_leaf; /* dead leaf structure */ + xfs_dir2_leaf_t *save_leaf; /* surviving leaf structure */ + + args = state->args; + ASSERT(drop_blk->magic == XFS_DIR2_LEAFN_MAGIC); + ASSERT(save_blk->magic == XFS_DIR2_LEAFN_MAGIC); + drop_leaf = drop_blk->bp->data; + save_leaf = save_blk->bp->data; + ASSERT(INT_GET(drop_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + ASSERT(INT_GET(save_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + /* + * If there are any stale leaf entries, take this opportunity + * to purge them. + */ + if (INT_GET(drop_leaf->hdr.stale, ARCH_CONVERT)) + xfs_dir2_leaf_compact(args, drop_blk->bp); + if (INT_GET(save_leaf->hdr.stale, ARCH_CONVERT)) + xfs_dir2_leaf_compact(args, save_blk->bp); + /* + * Move the entries from drop to the appropriate end of save. + */ + drop_blk->hashval = INT_GET(drop_leaf->ents[INT_GET(drop_leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); + if (xfs_dir2_leafn_order(save_blk->bp, drop_blk->bp)) + xfs_dir2_leafn_moveents(args, drop_blk->bp, 0, save_blk->bp, 0, + INT_GET(drop_leaf->hdr.count, ARCH_CONVERT)); + else + xfs_dir2_leafn_moveents(args, drop_blk->bp, 0, save_blk->bp, + INT_GET(save_leaf->hdr.count, ARCH_CONVERT), INT_GET(drop_leaf->hdr.count, ARCH_CONVERT)); + save_blk->hashval = INT_GET(save_leaf->ents[INT_GET(save_leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); + xfs_dir2_leafn_check(args->dp, save_blk->bp); +} + +/* + * Top-level node form directory addname routine. + */ +int /* error */ +xfs_dir2_node_addname( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_da_state_blk_t *blk; /* leaf block for insert */ + int error; /* error return value */ + int rval; /* sub-return value */ + xfs_da_state_t *state; /* btree cursor */ + + xfs_dir2_trace_args("node_addname", args); + /* + * Allocate and initialize the state (btree cursor). + */ + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_dirblksize; + /* + * Look up the name. We're not supposed to find it, but + * this gives us the insertion point. + */ + error = xfs_da_node_lookup_int(state, &rval); + if (error) + rval = error; + if (rval != ENOENT) { + goto done; + } + /* + * Add the data entry to a data block. + * Extravalid is set to a freeblock found by lookup. + */ + rval = xfs_dir2_node_addname_int(args, + state->extravalid ? &state->extrablk : NULL); + if (rval) { + goto done; + } + blk = &state->path.blk[state->path.active - 1]; + ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); + /* + * Add the new leaf entry. + */ + rval = xfs_dir2_leafn_add(blk->bp, args, blk->index); + if (rval == 0) { + /* + * It worked, fix the hash values up the btree. + */ + if (!args->justcheck) + xfs_da_fixhashpath(state, &state->path); + } else { + /* + * It didn't work, we need to split the leaf block. + */ + if (args->total == 0) { + ASSERT(rval == ENOSPC); + goto done; + } + /* + * Split the leaf block and insert the new entry. + */ + rval = xfs_da_split(state); + } +done: + xfs_da_state_free(state); + return rval; +} + + +/* + * Add the data entry for a node-format directory name addition. + * The leaf entry is added in xfs_dir2_leafn_add. + * We may enter with a freespace block that the lookup found. + */ +STATIC int /* error */ +xfs_dir2_node_addname_int( + xfs_da_args_t *args, /* operation arguments */ + xfs_da_state_blk_t *fblk) /* optional freespace block */ +{ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dir2_db_t dbno; /* data block number */ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data entry pointer */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_data_unused_t *dup; /* data unused entry pointer */ + int error; /* error return value */ + xfs_dir2_db_t fbno; /* freespace block number */ + xfs_dabuf_t *fbp; /* freespace buffer */ + int findex; /* freespace entry index */ + xfs_dir2_db_t foundbno=0; /* found freespace block no */ + int foundindex=0; /* found freespace entry idx */ + xfs_dir2_free_t *free=NULL; /* freespace block structure */ + xfs_dir2_db_t ifbno; /* initial freespace block no */ + xfs_dir2_db_t lastfbno=0; /* highest freespace block no */ + int length; /* length of the new entry */ + int logfree; /* need to log free entry */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log data header */ + int needscan; /* need to rescan data frees */ + xfs_dir2_data_off_t *tagp; /* data entry tag pointer */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + length = XFS_DIR2_DATA_ENTSIZE(args->namelen); + /* + * If we came in with a freespace block that means that lookup + * found an entry with our hash value. This is the freespace + * block for that data entry. + */ + if (fblk) { + fbp = fblk->bp; + /* + * Remember initial freespace block number. + */ + ifbno = fblk->blkno; + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + findex = fblk->index; + /* + * This means the free entry showed that the data block had + * space for our entry, so we remembered it. + * Use that data block. + */ + if (findex >= 0) { + ASSERT(findex < INT_GET(free->hdr.nvalid, ARCH_CONVERT)); + ASSERT(INT_GET(free->bests[findex], ARCH_CONVERT) != NULLDATAOFF); + ASSERT(INT_GET(free->bests[findex], ARCH_CONVERT) >= length); + dbno = INT_GET(free->hdr.firstdb, ARCH_CONVERT) + findex; + } + /* + * The data block looked at didn't have enough room. + * We'll start at the beginning of the freespace entries. + */ + else { + dbno = -1; + findex = 0; + } + } + /* + * Didn't come in with a freespace block, so don't have a data block. + */ + else { + ifbno = dbno = -1; + fbp = NULL; + findex = 0; + } + /* + * If we don't have a data block yet, we're going to scan the + * freespace blocks looking for one. Figure out what the + * highest freespace block number is. + */ + if (dbno == -1) { + xfs_fileoff_t fo; /* freespace block number */ + + if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK))) + return error; + lastfbno = XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)fo); + fbno = ifbno; + foundindex = -1; + } + /* + * While we haven't identified a data block, search the freeblock + * data for a good data block. If we find a null freeblock entry, + * indicating a hole in the data blocks, remember that. + */ + while (dbno == -1) { + /* + * If we don't have a freeblock in hand, get the next one. + */ + if (fbp == NULL) { + /* + * Happens the first time through unless lookup gave + * us a freespace block to start with. + */ + if (++fbno == 0) + fbno = XFS_DIR2_FREE_FIRSTDB(mp); + /* + * If it's ifbno we already looked at it. + */ + if (fbno == ifbno) + fbno++; + /* + * If it's off the end we're done. + */ + if (fbno >= lastfbno) + break; + /* + * Read the block. There can be holes in the + * freespace blocks, so this might not succeed. + * This should be really rare, so there's no reason + * to avoid it. + */ + if ((error = xfs_da_read_buf(tp, dp, + XFS_DIR2_DB_TO_DA(mp, fbno), -1, &fbp, + XFS_DATA_FORK))) { + return error; + } + if (fbp == NULL) { + continue; + } + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + findex = 0; + } + /* + * Look at the current free entry. Is it good enough? + */ + if (INT_GET(free->bests[findex], ARCH_CONVERT) != NULLDATAOFF && + INT_GET(free->bests[findex], ARCH_CONVERT) >= length) + dbno = INT_GET(free->hdr.firstdb, ARCH_CONVERT) + findex; + else { + /* + * If we haven't found an empty entry yet, and this + * one is empty, remember this slot. + */ + if (foundindex == -1 && + INT_GET(free->bests[findex], ARCH_CONVERT) == NULLDATAOFF) { + foundindex = findex; + foundbno = fbno; + } + /* + * Are we done with the freeblock? + */ + if (++findex == INT_GET(free->hdr.nvalid, ARCH_CONVERT)) { + /* + * If there is space left in this freeblock, + * and we don't have an empty entry yet, + * remember this slot. + */ + if (foundindex == -1 && + findex < XFS_DIR2_MAX_FREE_BESTS(mp)) { + foundindex = findex; + foundbno = fbno; + } + /* + * Drop the block. + */ + xfs_da_brelse(tp, fbp); + fbp = NULL; + if (fblk && fblk->bp) + fblk->bp = NULL; + } + } + } + /* + * If we don't have a data block, and there's no free slot in a + * freeblock, we need to add a new freeblock. + */ + if (dbno == -1 && foundindex == -1) { + /* + * Not allowed to allocate, so return failure. + */ + if (args->justcheck || args->total == 0) { + return XFS_ERROR(ENOSPC); + } + /* + * Add the new freeblock. + */ + if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, + &fbno))) { + return error; + } + /* + * Get a buffer for the new block. + */ + if ((error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fbno), + -1, &fbp, XFS_DATA_FORK))) { + return error; + } + ASSERT(fbp != NULL); + /* + * Initialize the new block to be empty, and remember + * its first slot as our empty slot. + */ + free = fbp->data; + INT_SET(free->hdr.magic, ARCH_CONVERT, XFS_DIR2_FREE_MAGIC); + INT_SET(free->hdr.firstdb, ARCH_CONVERT, (fbno - XFS_DIR2_FREE_FIRSTDB(mp)) * + XFS_DIR2_MAX_FREE_BESTS(mp)); + INT_ZERO(free->hdr.nused, ARCH_CONVERT); + INT_ZERO(free->hdr.nvalid, ARCH_CONVERT); + foundindex = 0; + foundbno = fbno; + } + /* + * If we don't have a data block, and we don't have a freeblock buffer + * in hand (we dropped the one with the free slot in it), + * go read the freeblock again. + */ + if (dbno == -1 && fbp == NULL) { + /* + * We're going to use the empty slot we found before. + */ + findex = foundindex; + fbno = foundbno; + if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fbno), + -1, &fbp, XFS_DATA_FORK))) { + return error; + } + ASSERT(fbp != NULL); + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + } + /* + * If we don't have a data block, we need to allocate one and make + * the freespace entries refer to it. + */ + if (dbno == -1) { + /* + * Not allowed to allocate, return failure. + */ + if (args->justcheck || args->total == 0) { + /* + * Drop the freespace buffer unless it came from our + * caller. + */ + if (fblk == NULL || fblk->bp == NULL) + xfs_da_buf_done(fbp); + return XFS_ERROR(ENOSPC); + } + /* + * Allocate and initialize the new data block. + */ + if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, + &dbno)) || + (error = xfs_dir2_data_init(args, dbno, &dbp))) { + /* + * Drop the freespace buffer unless it came from our + * caller. + */ + if (fblk == NULL || fblk->bp == NULL) + xfs_da_buf_done(fbp); + return error; + } + /* + * If the freespace entry for this data block is not in the + * freespace block we have in hand, drop the one we have + * and get the right one. + */ + if (XFS_DIR2_DB_TO_FDB(mp, dbno) != fbno) { + xfs_da_brelse(tp, fbp); + if (fblk && fblk->bp) + fblk->bp = NULL; + fbno = XFS_DIR2_DB_TO_FDB(mp, dbno); + if ((error = xfs_da_read_buf(tp, dp, + XFS_DIR2_DB_TO_DA(mp, fbno), -1, &fbp, + XFS_DATA_FORK))) { + xfs_da_buf_done(dbp); + return error; + } + ASSERT(fbp != NULL); + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + } + /* + * Set the freespace block index from the data block number. + */ + findex = XFS_DIR2_DB_TO_FDINDEX(mp, dbno); + /* + * If it's after the end of the current entries in the + * freespace block, extend that table. + */ + if (findex >= INT_GET(free->hdr.nvalid, ARCH_CONVERT)) { + ASSERT(findex < XFS_DIR2_MAX_FREE_BESTS(mp)); + INT_SET(free->hdr.nvalid, ARCH_CONVERT, findex + 1); + /* + * Tag new entry so nused will go up. + */ + INT_SET(free->bests[findex], ARCH_CONVERT, NULLDATAOFF); + } + /* + * If this entry was for an empty data block + * (this should always be true) then update the header. + */ + if (INT_GET(free->bests[findex], ARCH_CONVERT) == NULLDATAOFF) { + INT_MOD(free->hdr.nused, ARCH_CONVERT, +1); + xfs_dir2_free_log_header(tp, fbp); + } + /* + * Update the real value in the table. + * We haven't allocated the data entry yet so this will + * change again. + */ + data = dbp->data; + INT_COPY(free->bests[findex], data->hdr.bestfree[0].length, ARCH_CONVERT); + logfree = 1; + } + /* + * We had a data block so we don't have to make a new one. + */ + else { + /* + * If just checking, we succeeded. + */ + if (args->justcheck) { + if (fblk == NULL || fblk->bp == NULL) + xfs_da_buf_done(fbp); + return 0; + } + /* + * Read the data block in. + */ + if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, dbno), + -1, &dbp, XFS_DATA_FORK))) { + if (fblk == NULL || fblk->bp == NULL) + xfs_da_buf_done(fbp); + return error; + } + data = dbp->data; + logfree = 0; + } + ASSERT(INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) >= length); + /* + * Point to the existing unused space. + */ + dup = (xfs_dir2_data_unused_t *) + ((char *)data + INT_GET(data->hdr.bestfree[0].offset, ARCH_CONVERT)); + needscan = needlog = 0; + /* + * Mark the first part of the unused space, inuse for us. + */ + xfs_dir2_data_use_free(tp, dbp, dup, + (xfs_dir2_data_aoff_t)((char *)dup - (char *)data), length, + &needlog, &needscan); + /* + * Fill in the new entry and log it. + */ + dep = (xfs_dir2_data_entry_t *)dup; + INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); + dep->namelen = args->namelen; + bcopy(args->name, dep->name, dep->namelen); + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)data)); + xfs_dir2_data_log_entry(tp, dbp, dep); + /* + * Rescan the block for bestfree if needed. + */ + if (needscan) + xfs_dir2_data_freescan(mp, data, &needlog, NULL); + /* + * Log the data block header if needed. + */ + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + /* + * If the freespace entry is now wrong, update it. + */ + if (INT_GET(free->bests[findex], ARCH_CONVERT) != INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT)) { + INT_COPY(free->bests[findex], data->hdr.bestfree[0].length, ARCH_CONVERT); + logfree = 1; + } + /* + * Log the freespace entry if needed. + */ + if (logfree) + xfs_dir2_free_log_bests(tp, fbp, findex, findex); + /* + * If the caller didn't hand us the freespace block, drop it. + */ + if (fblk == NULL || fblk->bp == NULL) + xfs_da_buf_done(fbp); + /* + * Return the data block and offset in args, then drop the data block. + */ + args->blkno = (xfs_dablk_t)dbno; + args->index = INT_GET(*tagp, ARCH_CONVERT); + xfs_da_buf_done(dbp); + return 0; +} + +/* + * Lookup an entry in a node-format directory. + * All the real work happens in xfs_da_node_lookup_int. + * The only real output is the inode number of the entry. + */ +int /* error */ +xfs_dir2_node_lookup( + xfs_da_args_t *args) /* operation arguments */ +{ + int error; /* error return value */ + int i; /* btree level */ + int rval; /* operation return value */ + xfs_da_state_t *state; /* btree cursor */ + + xfs_dir2_trace_args("node_lookup", args); + /* + * Allocate and initialize the btree cursor. + */ + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_dirblksize; + /* + * Fill in the path to the entry in the cursor. + */ + error = xfs_da_node_lookup_int(state, &rval); + if (error) + rval = error; + /* + * Release the btree blocks and leaf block. + */ + for (i = 0; i < state->path.active; i++) { + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + /* + * Release the data block if we have it. + */ + if (state->extravalid && state->extrablk.bp) { + xfs_da_brelse(args->trans, state->extrablk.bp); + state->extrablk.bp = NULL; + } + xfs_da_state_free(state); + return rval; +} + +/* + * Remove an entry from a node-format directory. + */ +int /* error */ +xfs_dir2_node_removename( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_da_state_blk_t *blk; /* leaf block */ + int error; /* error return value */ + int rval; /* operation return value */ + xfs_da_state_t *state; /* btree cursor */ + + xfs_dir2_trace_args("node_removename", args); + /* + * Allocate and initialize the btree cursor. + */ + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_dirblksize; + /* + * Look up the entry we're deleting, set up the cursor. + */ + error = xfs_da_node_lookup_int(state, &rval); + if (error) { + rval = error; + } + /* + * Didn't find it, upper layer screwed up. + */ + if (rval != EEXIST) { + xfs_da_state_free(state); + return rval; + } + blk = &state->path.blk[state->path.active - 1]; + ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); + ASSERT(state->extravalid); + /* + * Remove the leaf and data entries. + * Extrablk refers to the data block. + */ + error = xfs_dir2_leafn_remove(args, blk->bp, blk->index, + &state->extrablk, &rval); + if (error) { + return error; + } + /* + * Fix the hash values up the btree. + */ + xfs_da_fixhashpath(state, &state->path); + /* + * If we need to join leaf blocks, do it. + */ + if (rval && state->path.active > 1) + error = xfs_da_join(state); + /* + * If no errors so far, try conversion to leaf format. + */ + if (!error) + error = xfs_dir2_node_to_leaf(state); + xfs_da_state_free(state); + return error; +} + +/* + * Replace an entry's inode number in a node-format directory. + */ +int /* error */ +xfs_dir2_node_replace( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_da_state_blk_t *blk; /* leaf block */ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dir2_data_entry_t *dep; /* data entry changed */ + int error; /* error return value */ + int i; /* btree level */ + xfs_ino_t inum; /* new inode number */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry being changed */ + int rval; /* internal return value */ + xfs_da_state_t *state; /* btree cursor */ + + xfs_dir2_trace_args("node_replace", args); + /* + * Allocate and initialize the btree cursor. + */ + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_dirblksize; + inum = args->inumber; + /* + * Lookup the entry to change in the btree. + */ + error = xfs_da_node_lookup_int(state, &rval); + if (error) { + rval = error; + } + /* + * It should be found, since the vnodeops layer has looked it up + * and locked it. But paranoia is good. + */ + if (rval == EEXIST) { + /* + * Find the leaf entry. + */ + blk = &state->path.blk[state->path.active - 1]; + ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); + leaf = blk->bp->data; + lep = &leaf->ents[blk->index]; + ASSERT(state->extravalid); + /* + * Point to the data entry. + */ + data = state->extrablk.bp->data; + ASSERT(INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC); + dep = (xfs_dir2_data_entry_t *) + ((char *)data + + XFS_DIR2_DATAPTR_TO_OFF(state->mp, INT_GET(lep->address, ARCH_CONVERT))); + ASSERT(inum != INT_GET(dep->inumber, ARCH_CONVERT)); + /* + * Fill in the new inode number and log the entry. + */ + INT_SET(dep->inumber, ARCH_CONVERT, inum); + xfs_dir2_data_log_entry(args->trans, state->extrablk.bp, dep); + rval = 0; + } + /* + * Didn't find it, and we're holding a data block. Drop it. + */ + else if (state->extravalid) { + xfs_da_brelse(args->trans, state->extrablk.bp); + state->extrablk.bp = NULL; + } + /* + * Release all the buffers in the cursor. + */ + for (i = 0; i < state->path.active; i++) { + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + xfs_da_state_free(state); + return rval; +} + +/* + * Trim off a trailing empty freespace block. + * Return (in rvalp) 1 if we did it, 0 if not. + */ +int /* error */ +xfs_dir2_node_trim_free( + xfs_da_args_t *args, /* operation arguments */ + xfs_fileoff_t fo, /* free block number */ + int *rvalp) /* out: did something */ +{ + xfs_dabuf_t *bp; /* freespace buffer */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + xfs_dir2_free_t *free; /* freespace structure */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + /* + * Read the freespace block. + */ + if ((error = xfs_da_read_buf(tp, dp, (xfs_dablk_t)fo, -1, &bp, + XFS_DATA_FORK))) { + return error; + } + free = bp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + /* + * If there are used entries, there's nothing to do. + */ + if (INT_GET(free->hdr.nused, ARCH_CONVERT) > 0) { + xfs_da_brelse(tp, bp); + *rvalp = 0; + return 0; + } + /* + * Blow the block away. + */ + if ((error = + xfs_dir2_shrink_inode(args, XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)fo), + bp))) { + /* + * Can't fail with ENOSPC since that only happens with no + * space reservation, when breaking up an extent into two + * pieces. This is the last block of an extent. + */ + ASSERT(error != ENOSPC); + xfs_da_brelse(tp, bp); + return error; + } + /* + * Return that we succeeded. + */ + *rvalp = 1; + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir2_sf.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir2_sf.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir2_sf.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir2_sf.c Thu Apr 12 18:30:32 2001 @@ -0,0 +1,1106 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_sf.c + * Shortform directory implementation for v2 directories. + */ + +#include + + +/* + * Given a block directory (dp/block), calculate its size as a shortform (sf) + * directory and a header for the sf directory, if it will fit it the + * space currently present in the inode. If it won't fit, the output + * size is too big (but not accurate). + */ +int /* size for sf form */ +xfs_dir2_block_sfsize( + xfs_inode_t *dp, /* incore inode pointer */ + xfs_dir2_block_t *block, /* block directory data */ + xfs_dir2_sf_hdr_t *sfhp) /* output: header for sf form */ +{ + xfs_dir2_dataptr_t addr; /* data entry address */ + xfs_dir2_leaf_entry_t *blp; /* leaf area of the block */ + xfs_dir2_block_tail_t *btp; /* tail area of the block */ + int count; /* shortform entry count */ + xfs_dir2_data_entry_t *dep; /* data entry in the block */ + int i; /* block entry index */ + int i8count; /* count of big-inode entries */ + int isdot; /* entry is "." */ + int isdotdot; /* entry is ".." */ + xfs_mount_t *mp; /* mount structure pointer */ + int namelen; /* total name bytes */ + xfs_ino_t parent; /* parent inode number */ + int size=0; /* total computed size */ + + mp = dp->i_mount; + + count = i8count = namelen = 0; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + + /* + * Iterate over the block's data entries by using the leaf pointers. + */ + for (i = 0; i < INT_GET(btp->count, ARCH_CONVERT); i++) { + if ((addr = INT_GET(blp[i].address, ARCH_CONVERT)) == XFS_DIR2_NULL_DATAPTR) + continue; + /* + * Calculate the pointer to the entry at hand. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, addr)); + /* + * Detect . and .., so we can special-case them. + * . is not included in sf directories. + * .. is included by just the parent inode number. + */ + isdot = dep->namelen == 1 && dep->name[0] == '.'; + isdotdot = + dep->namelen == 2 && + dep->name[0] == '.' && dep->name[1] == '.'; +#if XFS_BIG_FILESYSTEMS + if (!isdot) + i8count += INT_GET(dep->inumber, ARCH_CONVERT) > XFS_DIR2_MAX_SHORT_INUM; +#endif + if (!isdot && !isdotdot) { + count++; + namelen += dep->namelen; + } else if (isdotdot) + parent = INT_GET(dep->inumber, ARCH_CONVERT); + /* + * Calculate the new size, see if we should give up yet. + */ + size = XFS_DIR2_SF_HDR_SIZE(i8count) + /* header */ + count + /* namelen */ + count * (uint)sizeof(xfs_dir2_sf_off_t) + /* offset */ + namelen + /* name */ + (i8count ? /* inumber */ + (uint)sizeof(xfs_dir2_ino8_t) * count : + (uint)sizeof(xfs_dir2_ino4_t) * count); + if (size > XFS_IFORK_DSIZE(dp)) + return size; /* size value is a failure */ + } + /* + * Create the output header, if it worked. + */ + sfhp->count = count; + sfhp->i8count = i8count; + XFS_DIR2_SF_PUT_INUMBER_ARCH((xfs_dir2_sf_t *)sfhp, &parent, &sfhp->parent, ARCH_CONVERT); + return size; +} + +/* + * Convert a block format directory to shortform. + * Caller has already checked that it will fit, and built us a header. + */ +int /* error */ +xfs_dir2_block_to_sf( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *bp, /* block buffer */ + int size, /* shortform directory size */ + xfs_dir2_sf_hdr_t *sfhp) /* shortform directory hdr */ +{ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_block_tail_t *btp; /* block tail pointer */ + xfs_dir2_data_entry_t *dep; /* data entry pointer */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_data_unused_t *dup; /* unused data pointer */ + char *endptr; /* end of data entries */ + int error; /* error return value */ + int logflags; /* inode logging flags */ + xfs_mount_t *mp; /* filesystem mount point */ + char *ptr; /* current data pointer */ + xfs_dir2_sf_entry_t *sfep; /* shortform entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + xfs_ino_t temp; + + xfs_dir2_trace_args_sb("block_to_sf", args, size, bp); + dp = args->dp; + mp = dp->i_mount; + + /* + * Make a copy of the block data, so we can shrink the inode + * and add local data. + */ + block = kmem_alloc(mp->m_dirblksize, KM_SLEEP); + bcopy(bp->data, block, mp->m_dirblksize); + logflags = XFS_ILOG_CORE; + if ((error = xfs_dir2_shrink_inode(args, mp->m_dirdatablk, bp))) { + ASSERT(error != ENOSPC); + goto out; + } + /* + * The buffer is now unconditionally gone, whether + * xfs_dir2_shrink_inode worked or not. + * + * Convert the inode to local format. + */ + dp->i_df.if_flags &= ~XFS_IFEXTENTS; + dp->i_df.if_flags |= XFS_IFINLINE; + dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; + ASSERT(dp->i_df.if_bytes == 0); + xfs_idata_realloc(dp, size, XFS_DATA_FORK); + logflags |= XFS_ILOG_DDATA; + /* + * Copy the header into the newly allocate local space. + */ + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + bcopy(sfhp, sfp, XFS_DIR2_SF_HDR_SIZE(sfhp->i8count)); + dp->i_d.di_size = size; + /* + * Set up to loop over the block's entries. + */ + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + ptr = (char *)block->u; + endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + /* + * Loop over the active and unused entries. + * Stop when we reach the leaf/tail portion of the block. + */ + while (ptr < endptr) { + /* + * If it's unused, just skip over it. + */ + dup = (xfs_dir2_data_unused_t *)ptr; + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + ptr += INT_GET(dup->length, ARCH_CONVERT); + continue; + } + dep = (xfs_dir2_data_entry_t *)ptr; + /* + * Skip . + */ + if (dep->namelen == 1 && dep->name[0] == '.') + ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) == dp->i_ino); + /* + * Skip .., but make sure the inode number is right. + */ + else if (dep->namelen == 2 && + dep->name[0] == '.' && dep->name[1] == '.') + ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) == + XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT)); + /* + * Normal entry, copy it into shortform. + */ + else { + sfep->namelen = dep->namelen; + XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, + (xfs_dir2_data_aoff_t) + ((char *)dep - (char *)block), ARCH_CONVERT); + bcopy(dep->name, sfep->name, dep->namelen); + temp=INT_GET(dep->inumber, ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &temp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep); + } + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + ASSERT((char *)sfep - (char *)sfp == size); + xfs_dir2_sf_check(args); +out: + xfs_trans_log_inode(args->trans, dp, logflags); + kmem_free(block, mp->m_dirblksize); + return error; +} + +/* + * Add a name to a shortform directory. + * There are two algorithms, "easy" and "hard" which we decide on + * before changing anything. + * Convert to block form if necessary, if the new entry won't fit. + */ +int /* error */ +xfs_dir2_sf_addname( + xfs_da_args_t *args) /* operation arguments */ +{ + int add_entsize; /* size of the new entry */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + int incr_isize; /* total change in size */ + int new_isize; /* di_size after adding name */ + int objchange; /* changing to 8-byte inodes */ + xfs_dir2_data_aoff_t offset; /* offset for new entry */ + int old_isize; /* di_size before adding name */ + int pick; /* which algorithm to use */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + xfs_dir2_sf_entry_t *sfep; /* shortform entry */ + + xfs_dir2_trace_args("sf_addname", args); + ASSERT(xfs_dir2_sf_lookup(args) == ENOENT); + dp = args->dp; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Make sure the shortform value has some of its header. + */ + if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); + /* + * Compute entry (and change in) size. + */ + add_entsize = XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, args->namelen); + incr_isize = add_entsize; +#if XFS_BIG_FILESYSTEMS + /* + * Do we have to change to 8 byte inodes? + */ + if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->hdr.i8count == 0) { + /* + * Yes, adjust the entry size and the total size. + */ + add_entsize += + (uint)sizeof(xfs_dir2_ino8_t) - + (uint)sizeof(xfs_dir2_ino4_t); + incr_isize += + (sfp->hdr.count + 2) * + ((uint)sizeof(xfs_dir2_ino8_t) - + (uint)sizeof(xfs_dir2_ino4_t)); + objchange = 1; + } else + objchange = 0; +#else + objchange = 0; +#endif + old_isize = (int)dp->i_d.di_size; + new_isize = old_isize + incr_isize; + /* + * Won't fit as shortform any more (due to size), + * or the pick routine says it won't (due to offset values). + */ + if (new_isize > XFS_IFORK_DSIZE(dp) || + (pick = + xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) { + /* + * Just checking or no space reservation, it doesn't fit. + */ + if (args->justcheck || args->total == 0) + return XFS_ERROR(ENOSPC); + /* + * Convert to block form then add the name. + */ + error = xfs_dir2_sf_to_block(args); + if (error) + return error; + return xfs_dir2_block_addname(args); + } + /* + * Just checking, it fits. + */ + if (args->justcheck) + return 0; + /* + * Do it the easy way - just add it at the end. + */ + if (pick == 1) + xfs_dir2_sf_addname_easy(args, sfep, offset, new_isize); + /* + * Do it the hard way - look for a place to insert the new entry. + * Convert to 8 byte inode numbers first if necessary. + */ + else { + ASSERT(pick == 2); +#if XFS_BIG_FILESYSTEMS + if (objchange) + xfs_dir2_sf_toino8(args); +#endif + xfs_dir2_sf_addname_hard(args, objchange, new_isize); + } + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + return 0; +} + +/* + * Add the new entry the "easy" way. + * This is copying the old directory and adding the new entry at the end. + * Since it's sorted by "offset" we need room after the last offset + * that's already there, and then room to convert to a block directory. + * This is already checked by the pick routine. + */ +STATIC void +xfs_dir2_sf_addname_easy( + xfs_da_args_t *args, /* operation arguments */ + xfs_dir2_sf_entry_t *sfep, /* pointer to new entry */ + xfs_dir2_data_aoff_t offset, /* offset to use for new ent */ + int new_isize) /* new directory size */ +{ + int byteoff; /* byte offset in sf dir */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + + dp = args->dp; + + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + byteoff = (int)((char *)sfep - (char *)sfp); + /* + * Grow the in-inode space. + */ + xfs_idata_realloc(dp, XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, args->namelen), + XFS_DATA_FORK); + /* + * Need to set up again due to realloc of the inode data. + */ + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff); + /* + * Fill in the new entry. + */ + sfep->namelen = args->namelen; + XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, offset, ARCH_CONVERT); + bcopy(args->name, sfep->name, sfep->namelen); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + /* + * Update the header and inode. + */ + sfp->hdr.count++; +#if XFS_BIG_FILESYSTEMS + if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) + sfp->hdr.i8count++; +#endif + dp->i_d.di_size = new_isize; + xfs_dir2_sf_check(args); +} + +/* + * Add the new entry the "hard" way. + * The caller has already converted to 8 byte inode numbers if necessary, + * in which case we need to leave the i8count at 1. + * Find a hole that the new entry will fit into, and copy + * the first part of the entries, the new entry, and the last part of + * the entries. + */ +/* ARGSUSED */ +STATIC void +xfs_dir2_sf_addname_hard( + xfs_da_args_t *args, /* operation arguments */ + int objchange, /* changing inode number size */ + int new_isize) /* new directory size */ +{ + int add_datasize; /* data size need for new ent */ + char buf[XFS_DIR2_SF_MAX_SIZE]; /* buffer for old */ + xfs_inode_t *dp; /* incore directory inode */ + int eof; /* reached end of old dir */ + int nbytes; /* temp for byte copies */ + xfs_dir2_data_aoff_t new_offset; /* next offset value */ + xfs_dir2_data_aoff_t offset; /* current offset value */ + int old_isize; /* previous di_size */ + xfs_dir2_sf_entry_t *oldsfep; /* entry in original dir */ + xfs_dir2_sf_t *oldsfp; /* original shortform dir */ + xfs_dir2_sf_entry_t *sfep; /* entry in new dir */ + xfs_dir2_sf_t *sfp; /* new shortform dir */ + + /* + * Copy the old directory to the stack buffer. + */ + dp = args->dp; + + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + old_isize = (int)dp->i_d.di_size; + oldsfp = (xfs_dir2_sf_t *)buf; + bcopy(sfp, oldsfp, old_isize); + /* + * Loop over the old directory finding the place we're going + * to insert the new entry. + * If it's going to end up at the end then oldsfep will point there. + */ + for (offset = XFS_DIR2_DATA_FIRST_OFFSET, + oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp), + add_datasize = XFS_DIR2_DATA_ENTSIZE(args->namelen), + eof = (char *)oldsfep == &buf[old_isize]; + !eof; + offset = new_offset + XFS_DIR2_DATA_ENTSIZE(oldsfep->namelen), + oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep), + eof = (char *)oldsfep == &buf[old_isize]) { + new_offset = XFS_DIR2_SF_GET_OFFSET_ARCH(oldsfep, ARCH_CONVERT); + if (offset + add_datasize <= new_offset) + break; + } + /* + * Get rid of the old directory, then allocate space for + * the new one. We do this so xfs_idata_realloc won't copy + * the data. + */ + xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK); + xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK); + /* + * Reset the pointer since the buffer was reallocated. + */ + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + /* + * Copy the first part of the directory, including the header. + */ + nbytes = (int)((char *)oldsfep - (char *)oldsfp); + bcopy(oldsfp, sfp, nbytes); + sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes); + /* + * Fill in the new entry, and update the header counts. + */ + sfep->namelen = args->namelen; + XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, offset, ARCH_CONVERT); + bcopy(args->name, sfep->name, sfep->namelen); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + sfp->hdr.count++; +#if XFS_BIG_FILESYSTEMS + if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange) + sfp->hdr.i8count++; +#endif + /* + * If there's more left to copy, do that. + */ + if (!eof) { + sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep); + bcopy(oldsfep, sfep, old_isize - nbytes); + } + dp->i_d.di_size = new_isize; + xfs_dir2_sf_check(args); +} + +/* + * Decide if the new entry will fit at all. + * If it will fit, pick between adding the new entry to the end (easy) + * or somewhere else (hard). + * Return 0 (won't fit), 1 (easy), 2 (hard). + */ +/*ARGSUSED*/ +STATIC int /* pick result */ +xfs_dir2_sf_addname_pick( + xfs_da_args_t *args, /* operation arguments */ + int objchange, /* inode # size changes */ + xfs_dir2_sf_entry_t **sfepp, /* out(1): new entry ptr */ + xfs_dir2_data_aoff_t *offsetp) /* out(1): new offset */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int holefit; /* found hole it will fit in */ + int i; /* entry number */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_dir2_data_aoff_t offset; /* data block offset */ + xfs_dir2_sf_entry_t *sfep; /* shortform entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + int size; /* entry's data size */ + int used; /* data bytes used */ + + dp = args->dp; + mp = dp->i_mount; + + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + size = XFS_DIR2_DATA_ENTSIZE(args->namelen); + offset = XFS_DIR2_DATA_FIRST_OFFSET; + sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + holefit = 0; + /* + * Loop over sf entries. + * Keep track of data offset and whether we've seen a place + * to insert the new entry. + */ + for (i = 0; i < sfp->hdr.count; i++) { + if (!holefit) + holefit = offset + size <= XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT); + offset = XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) + + XFS_DIR2_DATA_ENTSIZE(sfep->namelen); + sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep); + } + /* + * Calculate data bytes used excluding the new entry, if this + * was a data block (block form directory). + */ + used = offset + + (sfp->hdr.count + 3) * (uint)sizeof(xfs_dir2_leaf_entry_t) + + (uint)sizeof(xfs_dir2_block_tail_t); + /* + * If it won't fit in a block form then we can't insert it, + * we'll go back, convert to block, then try the insert and convert + * to leaf. + */ + if (used + (holefit ? 0 : size) > mp->m_dirblksize) + return 0; + /* + * If changing the inode number size, do it the hard way. + */ +#if XFS_BIG_FILESYSTEMS + if (objchange) { + return 2; + } +#else + ASSERT(objchange == 0); +#endif + /* + * If it won't fit at the end then do it the hard way (use the hole). + */ + if (used + size > mp->m_dirblksize) + return 2; + /* + * Do it the easy way. + */ + *sfepp = sfep; + *offsetp = offset; + return 1; +} + +#ifdef DEBUG +/* + * Check consistency of shortform directory, assert if bad. + */ +STATIC void +xfs_dir2_sf_check( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int i; /* entry number */ + int i8count; /* number of big inode#s */ + xfs_ino_t ino; /* entry inode number */ + int offset; /* data offset */ + xfs_dir2_sf_entry_t *sfep; /* shortform dir entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + + dp = args->dp; + + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + offset = XFS_DIR2_DATA_FIRST_OFFSET; + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT); + i8count = ino > XFS_DIR2_MAX_SHORT_INUM; + + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) { + ASSERT(XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) >= offset); + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + i8count += ino > XFS_DIR2_MAX_SHORT_INUM; + offset = + XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) + + XFS_DIR2_DATA_ENTSIZE(sfep->namelen); + } + ASSERT(i8count == sfp->hdr.i8count); +#if !XFS_BIG_FILESYSTEMS + ASSERT(i8count == 0); +#endif + ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size); + ASSERT(offset + + (sfp->hdr.count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) + + (uint)sizeof(xfs_dir2_block_tail_t) <= + dp->i_mount->m_dirblksize); +} +#endif /* DEBUG */ + +/* + * Create a new (shortform) directory. + */ +int /* error, always 0 */ +xfs_dir2_sf_create( + xfs_da_args_t *args, /* operation arguments */ + xfs_ino_t pino) /* parent inode number */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int i8count; /* parent inode is an 8-byte number */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + int size; /* directory size */ + + xfs_dir2_trace_args_i("sf_create", args, pino); + dp = args->dp; + + ASSERT(dp != NULL); + ASSERT(dp->i_d.di_size == 0); + /* + * If it's currently a zero-length extent file, + * convert it to local format. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) { + dp->i_df.if_flags &= ~XFS_IFEXTENTS; /* just in case */ + dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); + dp->i_df.if_flags |= XFS_IFINLINE; + } + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + ASSERT(dp->i_df.if_bytes == 0); + i8count = pino > XFS_DIR2_MAX_SHORT_INUM; + size = XFS_DIR2_SF_HDR_SIZE(i8count); + /* + * Make a buffer for the data. + */ + xfs_idata_realloc(dp, size, XFS_DATA_FORK); + /* + * Fill in the header, + */ + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + sfp->hdr.i8count = i8count; + /* + * Now can put in the inode number, since i8count is set. + */ + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &pino, &sfp->hdr.parent, ARCH_CONVERT); + sfp->hdr.count = 0; + dp->i_d.di_size = size; + xfs_dir2_sf_check(args); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + return 0; +} + +/* + * Lookup an entry in a shortform directory. + * Returns EEXIST if found, ENOENT if not found. + */ +int /* error */ +xfs_dir2_sf_lookup( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int i; /* entry index */ + xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + + xfs_dir2_trace_args("sf_lookup", args); + xfs_dir2_sf_check(args); + dp = args->dp; + + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Bail out if the directory is way too short. + */ + if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); + /* + * Special case for . + */ + if (args->namelen == 1 && args->name[0] == '.') { + args->inumber = dp->i_ino; + return XFS_ERROR(EEXIST); + } + /* + * Special case for .. + */ + if (args->namelen == 2 && + args->name[0] == '.' && args->name[1] == '.') { + args->inumber = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT); + return XFS_ERROR(EEXIST); + } + /* + * Loop over all the entries trying to match ours. + */ + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) { + if (sfep->namelen == args->namelen && + sfep->name[0] == args->name[0] && + bcmp(args->name, sfep->name, args->namelen) == 0) { + args->inumber = + XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + return XFS_ERROR(EEXIST); + } + } + /* + * Didn't find it. + */ + ASSERT(args->oknoent); + return XFS_ERROR(ENOENT); +} + +/* + * Remove an entry from a shortform directory. + */ +int /* error */ +xfs_dir2_sf_removename( + xfs_da_args_t *args) +{ + int byteoff; /* offset of removed entry */ + xfs_inode_t *dp; /* incore directory inode */ + int entsize; /* this entry's size */ + int i; /* shortform entry index */ + int newsize; /* new inode size */ + int oldsize; /* old inode size */ + xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + + xfs_dir2_trace_args("sf_removename", args); + dp = args->dp; + + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + oldsize = (int)dp->i_d.di_size; + /* + * Bail out if the directory is way too short. + */ + if (oldsize < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == oldsize); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(oldsize >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); + /* + * Loop over the old directory entries. + * Find the one we're deleting. + */ + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) { + if (sfep->namelen == args->namelen && + sfep->name[0] == args->name[0] && + bcmp(sfep->name, args->name, args->namelen) == 0) { + ASSERT(XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT) == + args->inumber); + break; + } + } + /* + * Didn't find it. + */ + if (i == sfp->hdr.count) { + return XFS_ERROR(ENOENT); + } + /* + * Calculate sizes. + */ + byteoff = (int)((char *)sfep - (char *)sfp); + entsize = XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, args->namelen); + newsize = oldsize - entsize; + /* + * Copy the part if any after the removed entry, sliding it down. + */ + if (byteoff + entsize < oldsize) + ovbcopy((char *)sfp + byteoff + entsize, (char *)sfp + byteoff, + oldsize - (byteoff + entsize)); + /* + * Fix up the header and file size. + */ + sfp->hdr.count--; + dp->i_d.di_size = newsize; + /* + * Reallocate, making it smaller. + */ + xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; +#if XFS_BIG_FILESYSTEMS + /* + * Are we changing inode number size? + */ + if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) { + if (sfp->hdr.i8count == 1) + xfs_dir2_sf_toino4(args); + else + sfp->hdr.i8count--; + } +#endif + xfs_dir2_sf_check(args); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + return 0; +} + +/* + * Replace the inode number of an entry in a shortform directory. + */ +int /* error */ +xfs_dir2_sf_replace( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int i; /* entry index */ +#if XFS_BIG_FILESYSTEMS || defined(DEBUG) + xfs_ino_t ino=0; /* entry old inode number */ +#endif + xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + + xfs_dir2_trace_args("sf_replace", args); + dp = args->dp; + + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Bail out if the shortform directory is way too small. + */ + if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); +#if XFS_BIG_FILESYSTEMS + /* + * New inode number is large, and need to convert to 8-byte inodes. + */ + if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->hdr.i8count == 0) { + int error; /* error return value */ + int newsize; /* new inode size */ + + newsize = + dp->i_df.if_bytes + + (sfp->hdr.count + 1) * + ((uint)sizeof(xfs_dir2_ino8_t) - + (uint)sizeof(xfs_dir2_ino4_t)); + /* + * Won't fit as shortform, convert to block then do replace. + */ + if (newsize > XFS_IFORK_DSIZE(dp)) { + error = xfs_dir2_sf_to_block(args); + if (error) { + return error; + } + return xfs_dir2_block_replace(args); + } + /* + * Still fits, convert to 8-byte now. + */ + xfs_dir2_sf_toino8(args); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + } +#endif + ASSERT(args->namelen != 1 || args->name[0] != '.'); + /* + * Replace ..'s entry. + */ + if (args->namelen == 2 && + args->name[0] == '.' && args->name[1] == '.') { +#if XFS_BIG_FILESYSTEMS || defined(DEBUG) + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT); + ASSERT(args->inumber != ino); +#endif + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber, &sfp->hdr.parent, ARCH_CONVERT); + } + /* + * Normal entry, look for the name. + */ + else { + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) { + if (sfep->namelen == args->namelen && + sfep->name[0] == args->name[0] && + bcmp(args->name, sfep->name, args->namelen) == 0) { +#if XFS_BIG_FILESYSTEMS || defined(DEBUG) + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + ASSERT(args->inumber != ino); +#endif + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + break; + } + } + /* + * Didn't find it. + */ + if (i == sfp->hdr.count) { + ASSERT(args->oknoent); + return XFS_ERROR(ENOENT); + } + } +#if XFS_BIG_FILESYSTEMS + /* + * See if the old number was large, the new number is small. + */ + if (ino > XFS_DIR2_MAX_SHORT_INUM && + args->inumber <= XFS_DIR2_MAX_SHORT_INUM) { + /* + * And the old count was one, so need to convert to small. + */ + if (sfp->hdr.i8count == 1) + xfs_dir2_sf_toino4(args); + else + sfp->hdr.i8count--; + } +#endif + xfs_dir2_sf_check(args); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); + return 0; +} + +#if XFS_BIG_FILESYSTEMS +/* + * Convert from 8-byte inode numbers to 4-byte inode numbers. + * The last 8-byte inode number is gone, but the count is still 1. + */ +STATIC void +xfs_dir2_sf_toino4( + xfs_da_args_t *args) /* operation arguments */ +{ + char *buf; /* old dir's buffer */ + xfs_inode_t *dp; /* incore directory inode */ + int i; /* entry index */ + xfs_ino_t ino; /* entry inode number */ + int newsize; /* new inode size */ + xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ + xfs_dir2_sf_t *oldsfp; /* old sf directory */ + int oldsize; /* old inode size */ + xfs_dir2_sf_entry_t *sfep; /* new sf entry */ + xfs_dir2_sf_t *sfp; /* new sf directory */ + + xfs_dir2_trace_args("sf_toino4", args); + dp = args->dp; + + /* + * Copy the old directory to the buffer. + * Then nuke it from the inode, and add the new buffer to the inode. + * Don't want xfs_idata_realloc copying the data here. + */ + oldsize = dp->i_df.if_bytes; + buf = kmem_alloc(oldsize, KM_SLEEP); + oldsfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(oldsfp->hdr.i8count == 1); + bcopy(oldsfp, buf, oldsize); + /* + * Compute the new inode size. + */ + newsize = + oldsize - + (oldsfp->hdr.count + 1) * + ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)); + xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); + xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); + /* + * Reset our pointers, the data has moved. + */ + oldsfp = (xfs_dir2_sf_t *)buf; + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + /* + * Fill in the new header. + */ + sfp->hdr.count = oldsfp->hdr.count; + sfp->hdr.i8count = 0; + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, &oldsfp->hdr.parent, ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, &sfp->hdr.parent, ARCH_CONVERT); + /* + * Copy the entries field by field. + */ + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp), + oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep), + oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep)) { + sfep->namelen = oldsfep->namelen; + sfep->offset = oldsfep->offset; + bcopy(oldsfep->name, sfep->name, sfep->namelen); + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, + XFS_DIR2_SF_INUMBERP(oldsfep), ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + } + /* + * Clean up the inode. + */ + kmem_free(buf, oldsize); + dp->i_d.di_size = newsize; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); +} + +/* + * Convert from 4-byte inode numbers to 8-byte inode numbers. + * The new 8-byte inode number is not there yet, we leave with the + * count 1 but no corresponding entry. + */ +STATIC void +xfs_dir2_sf_toino8( + xfs_da_args_t *args) /* operation arguments */ +{ + char *buf; /* old dir's buffer */ + xfs_inode_t *dp; /* incore directory inode */ + int i; /* entry index */ + xfs_ino_t ino; /* entry inode number */ + int newsize; /* new inode size */ + xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ + xfs_dir2_sf_t *oldsfp; /* old sf directory */ + int oldsize; /* old inode size */ + xfs_dir2_sf_entry_t *sfep; /* new sf entry */ + xfs_dir2_sf_t *sfp; /* new sf directory */ + + xfs_dir2_trace_args("sf_toino8", args); + dp = args->dp; + + /* + * Copy the old directory to the buffer. + * Then nuke it from the inode, and add the new buffer to the inode. + * Don't want xfs_idata_realloc copying the data here. + */ + oldsize = dp->i_df.if_bytes; + buf = kmem_alloc(oldsize, KM_SLEEP); + oldsfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(oldsfp->hdr.i8count == 0); + bcopy(oldsfp, buf, oldsize); + /* + * Compute the new inode size. + */ + newsize = + oldsize + + (oldsfp->hdr.count + 1) * + ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)); + xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); + xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); + /* + * Reset our pointers, the data has moved. + */ + oldsfp = (xfs_dir2_sf_t *)buf; + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + /* + * Fill in the new header. + */ + sfp->hdr.count = oldsfp->hdr.count; + sfp->hdr.i8count = 1; + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, &oldsfp->hdr.parent, ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, &sfp->hdr.parent, ARCH_CONVERT); + /* + * Copy the entries field by field. + */ + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp), + oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep), + oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep)) { + sfep->namelen = oldsfep->namelen; + sfep->offset = oldsfep->offset; + bcopy(oldsfep->name, sfep->name, sfep->namelen); + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, + XFS_DIR2_SF_INUMBERP(oldsfep), ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + } + /* + * Clean up the inode. + */ + kmem_free(buf, oldsize); + dp->i_d.di_size = newsize; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); +} +#endif /* XFS_BIG_FILESYSTEMS */ diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir_leaf.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir_leaf.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_dir_leaf.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_dir_leaf.c Thu Apr 12 18:30:32 2001 @@ -0,0 +1,1690 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * xfs_dir_leaf.c + * + * Routines to implement leaf blocks of directories as Btrees of hashed names. + */ + +/* + * Validate a given inode number. + */ +int +xfs_dir_ino_validate(xfs_mount_t *mp, xfs_ino_t ino) +{ + xfs_agblock_t agblkno; + xfs_agino_t agino; + xfs_agnumber_t agno; + int ino_ok; + int ioff; + + agno = XFS_INO_TO_AGNO(mp, ino); + agblkno = XFS_INO_TO_AGBNO(mp, ino); + ioff = XFS_INO_TO_OFFSET(mp, ino); + agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff); + ino_ok = + agno < mp->m_sb.sb_agcount && + agblkno < mp->m_sb.sb_agblocks && + agblkno != 0 && + ioff < (1 << mp->m_sb.sb_inopblog) && + XFS_AGINO_TO_INO(mp, agno, agino) == ino; + if (XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE, + XFS_RANDOM_DIR_INO_VALIDATE)) { + xfs_fs_cmn_err(CE_WARN, mp, + "Invalid inode number 0x%Lx\n", ino); + return XFS_ERROR(EFSCORRUPTED); + } + return 0; +} + +/* + * Create the initial contents of a shortform directory. + */ +int +xfs_dir_shortform_create(xfs_da_args_t *args, xfs_ino_t parent) +{ + xfs_dir_sf_hdr_t *hdr; + xfs_inode_t *dp; + + dp = args->dp; + ASSERT(dp != NULL); + ASSERT(dp->i_d.di_size == 0); + if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) { + dp->i_df.if_flags &= ~XFS_IFEXTENTS; /* just in case */ + dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); + dp->i_df.if_flags |= XFS_IFINLINE; + } + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + ASSERT(dp->i_df.if_bytes == 0); + xfs_idata_realloc(dp, sizeof(*hdr), XFS_DATA_FORK); + hdr = (xfs_dir_sf_hdr_t *)dp->i_df.if_u1.if_data; + XFS_DIR_SF_PUT_DIRINO_ARCH(&parent, &hdr->parent, ARCH_CONVERT); + + INT_ZERO(hdr->count, ARCH_CONVERT); + dp->i_d.di_size = sizeof(*hdr); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + return(0); +} + +/* + * Add a name to the shortform directory structure. + * Overflow from the inode has already been checked for. + */ +int +xfs_dir_shortform_addname(xfs_da_args_t *args) +{ + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + int i, offset, size; + xfs_inode_t *dp; + + dp = args->dp; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Catch the case where the conversion from shortform to leaf + * failed part way through. + */ + if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + sfe = &sf->list[0]; + for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) { + if (sfe->namelen == args->namelen && + args->name[0] == sfe->name[0] && + bcmp(args->name, sfe->name, args->namelen) == 0) + return(XFS_ERROR(EEXIST)); + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + + offset = (int)((char *)sfe - (char *)sf); + size = XFS_DIR_SF_ENTSIZE_BYNAME(args->namelen); + xfs_idata_realloc(dp, size, XFS_DATA_FORK); + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + sfe = (xfs_dir_sf_entry_t *)((char *)sf + offset); + + XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sfe->inumber, ARCH_CONVERT); + sfe->namelen = args->namelen; + bcopy(args->name, sfe->name, sfe->namelen); + INT_MOD(sf->hdr.count, ARCH_CONVERT, +1); + + dp->i_d.di_size += size; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + + return(0); +} + +/* + * Remove a name from the shortform directory structure. + */ +int +xfs_dir_shortform_removename(xfs_da_args_t *args) +{ + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + int base, size, i; + xfs_inode_t *dp; + + dp = args->dp; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Catch the case where the conversion from shortform to leaf + * failed part way through. + */ + if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + base = sizeof(xfs_dir_sf_hdr_t); + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + sfe = &sf->list[0]; + for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) { + size = XFS_DIR_SF_ENTSIZE_BYENTRY(sfe); + if (sfe->namelen == args->namelen && + sfe->name[0] == args->name[0] && + bcmp(sfe->name, args->name, args->namelen) == 0) + break; + base += size; + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + if (i < 0) { + ASSERT(args->oknoent); + return(XFS_ERROR(ENOENT)); + } + + if ((base + size) != dp->i_d.di_size) { + ovbcopy(&((char *)sf)[base+size], &((char *)sf)[base], + dp->i_d.di_size - (base+size)); + } + INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); + + xfs_idata_realloc(dp, -size, XFS_DATA_FORK); + dp->i_d.di_size -= size; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + + return(0); +} + +/* + * Look up a name in a shortform directory structure. + */ +int +xfs_dir_shortform_lookup(xfs_da_args_t *args) +{ + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + int i; + xfs_inode_t *dp; + + dp = args->dp; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Catch the case where the conversion from shortform to leaf + * failed part way through. + */ + if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + if (args->namelen == 2 && + args->name[0] == '.' && args->name[1] == '.') { + XFS_DIR_SF_GET_DIRINO_ARCH(&sf->hdr.parent, &args->inumber, ARCH_CONVERT); + return(XFS_ERROR(EEXIST)); + } + if (args->namelen == 1 && args->name[0] == '.') { + args->inumber = dp->i_ino; + return(XFS_ERROR(EEXIST)); + } + sfe = &sf->list[0]; + for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) { + if (sfe->namelen == args->namelen && + sfe->name[0] == args->name[0] && + bcmp(args->name, sfe->name, args->namelen) == 0) { + XFS_DIR_SF_GET_DIRINO_ARCH(&sfe->inumber, &args->inumber, ARCH_CONVERT); + return(XFS_ERROR(EEXIST)); + } + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + ASSERT(args->oknoent); + return(XFS_ERROR(ENOENT)); +} + +/* + * Convert from using the shortform to the leaf. + */ +int +xfs_dir_shortform_to_leaf(xfs_da_args_t *iargs) +{ + xfs_inode_t *dp; + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + xfs_da_args_t args; + xfs_ino_t inumber; + char *tmpbuffer; + int retval, i, size; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + + dp = iargs->dp; + /* + * Catch the case where the conversion from shortform to leaf + * failed part way through. + */ + if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + size = dp->i_df.if_bytes; + tmpbuffer = kmem_alloc(size, KM_SLEEP); + ASSERT(tmpbuffer != NULL); + + bcopy(dp->i_df.if_u1.if_data, tmpbuffer, size); + + sf = (xfs_dir_shortform_t *)tmpbuffer; + XFS_DIR_SF_GET_DIRINO_ARCH(&sf->hdr.parent, &inumber, ARCH_CONVERT); + + xfs_idata_realloc(dp, -size, XFS_DATA_FORK); + dp->i_d.di_size = 0; + xfs_trans_log_inode(iargs->trans, dp, XFS_ILOG_CORE); + retval = xfs_da_grow_inode(iargs, &blkno); + if (retval) + goto out; + + ASSERT(blkno == 0); + retval = xfs_dir_leaf_create(iargs, blkno, &bp); + if (retval) + goto out; + xfs_da_buf_done(bp); + + args.name = "."; + args.namelen = 1; + args.hashval = xfs_dir_hash_dot; + args.inumber = dp->i_ino; + args.dp = dp; + args.firstblock = iargs->firstblock; + args.flist = iargs->flist; + args.total = iargs->total; + args.whichfork = XFS_DATA_FORK; + args.trans = iargs->trans; + args.justcheck = 0; + args.addname = args.oknoent = 1; + retval = xfs_dir_leaf_addname(&args); + if (retval) + goto out; + + args.name = ".."; + args.namelen = 2; + args.hashval = xfs_dir_hash_dotdot; + args.inumber = inumber; + retval = xfs_dir_leaf_addname(&args); + if (retval) + goto out; + + sfe = &sf->list[0]; + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { + args.name = (char *)(sfe->name); + args.namelen = sfe->namelen; + args.hashval = xfs_da_hashname((char *)(sfe->name), + sfe->namelen); + XFS_DIR_SF_GET_DIRINO_ARCH(&sfe->inumber, &args.inumber, ARCH_CONVERT); + retval = xfs_dir_leaf_addname(&args); + if (retval) + goto out; + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + retval = 0; + +out: + kmem_free(tmpbuffer, size); + return(retval); +} + +/* + * Look up a name in a shortform directory structure, replace the inode number. + */ +int +xfs_dir_shortform_replace(xfs_da_args_t *args) +{ + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + xfs_inode_t *dp; + int i; + + dp = args->dp; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Catch the case where the conversion from shortform to leaf + * failed part way through. + */ + if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + if (args->namelen == 2 && + args->name[0] == '.' && args->name[1] == '.') { + /* XXX - replace assert? */ + XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sf->hdr.parent, ARCH_CONVERT); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); + return(0); + } + ASSERT(args->namelen != 1 || args->name[0] != '.'); + sfe = &sf->list[0]; + for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) { + if (sfe->namelen == args->namelen && + sfe->name[0] == args->name[0] && + bcmp(args->name, sfe->name, args->namelen) == 0) { + ASSERT(bcmp((char *)&args->inumber, + (char *)&sfe->inumber, sizeof(xfs_ino_t))); + XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sfe->inumber, ARCH_CONVERT); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); + return(0); + } + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + ASSERT(args->oknoent); + return(XFS_ERROR(ENOENT)); +} + +/* + * Convert a leaf directory to shortform structure + */ +int +xfs_dir_leaf_to_shortform(xfs_da_args_t *iargs) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_hdr_t *hdr; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + xfs_da_args_t args; + xfs_inode_t *dp; + xfs_ino_t parent; + char *tmpbuffer; + int retval, i; + xfs_dabuf_t *bp; + + dp = iargs->dp; + tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP); + ASSERT(tmpbuffer != NULL); + + retval = xfs_da_read_buf(iargs->trans, iargs->dp, 0, -1, &bp, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + bcopy(bp->data, tmpbuffer, XFS_LBSIZE(dp->i_mount)); + leaf = (xfs_dir_leafblock_t *)tmpbuffer; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + bzero(bp->data, XFS_LBSIZE(dp->i_mount)); + + /* + * Find and special case the parent inode number + */ + hdr = &leaf->hdr; + entry = &leaf->entries[0]; + for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; i >= 0; entry++, i--) { + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + if ((entry->namelen == 2) && + (namest->name[0] == '.') && + (namest->name[1] == '.')) { + XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &parent, ARCH_CONVERT); + INT_ZERO(entry->nameidx, ARCH_CONVERT); + } else if ((entry->namelen == 1) && (namest->name[0] == '.')) { + INT_ZERO(entry->nameidx, ARCH_CONVERT); + } + } + retval = xfs_da_shrink_inode(iargs, 0, bp); + if (retval) + goto out; + retval = xfs_dir_shortform_create(iargs, parent); + if (retval) + goto out; + + /* + * Copy the rest of the filenames + */ + entry = &leaf->entries[0]; + args.dp = dp; + args.firstblock = iargs->firstblock; + args.flist = iargs->flist; + args.total = iargs->total; + args.whichfork = XFS_DATA_FORK; + args.trans = iargs->trans; + args.justcheck = 0; + args.addname = args.oknoent = 1; + for (i = 0; i < INT_GET(hdr->count, ARCH_CONVERT); entry++, i++) { + if (INT_GET(entry->nameidx, ARCH_CONVERT) == 0) + continue; + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + args.name = (char *)(namest->name); + args.namelen = entry->namelen; + args.hashval = INT_GET(entry->hashval, ARCH_CONVERT); + XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &args.inumber, ARCH_CONVERT); + xfs_dir_shortform_addname(&args); + } + +out: + kmem_free(tmpbuffer, XFS_LBSIZE(dp->i_mount)); + return(retval); +} + +/* + * Convert from using a single leaf to a root node and a leaf. + */ +int +xfs_dir_leaf_to_node(xfs_da_args_t *args) +{ + xfs_dir_leafblock_t *leaf; + xfs_da_intnode_t *node; + xfs_inode_t *dp; + xfs_dabuf_t *bp1, *bp2; + xfs_dablk_t blkno; + int retval; + + dp = args->dp; + retval = xfs_da_grow_inode(args, &blkno); + ASSERT(blkno == 1); + if (retval) + return(retval); + retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp1, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp1 != NULL); + retval = xfs_da_get_buf(args->trans, args->dp, 1, -1, &bp2, + XFS_DATA_FORK); + if (retval) { + xfs_da_buf_done(bp1); + return(retval); + } + ASSERT(bp2 != NULL); + bcopy(bp1->data, bp2->data, XFS_LBSIZE(dp->i_mount)); + xfs_da_buf_done(bp1); + xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1); + + /* + * Set up the new root node. + */ + retval = xfs_da_node_create(args, 0, 1, &bp1, XFS_DATA_FORK); + if (retval) { + xfs_da_buf_done(bp2); + return(retval); + } + node = bp1->data; + leaf = bp2->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + INT_SET(node->btree[0].hashval, ARCH_CONVERT, INT_GET(leaf->entries[ INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)); + xfs_da_buf_done(bp2); + INT_SET(node->btree[0].before, ARCH_CONVERT, blkno); + INT_SET(node->hdr.count, ARCH_CONVERT, 1); + xfs_da_log_buf(args->trans, bp1, + XFS_DA_LOGRANGE(node, &node->btree[0], sizeof(node->btree[0]))); + xfs_da_buf_done(bp1); + + return(retval); +} + + +/*======================================================================== + * Routines used for growing the Btree. + *========================================================================*/ + +/* + * Create the initial contents of a leaf directory + * or a leaf in a node directory. + */ +int +xfs_dir_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_hdr_t *hdr; + xfs_inode_t *dp; + xfs_dabuf_t *bp; + int retval; + + dp = args->dp; + ASSERT(dp != NULL); + retval = xfs_da_get_buf(args->trans, dp, blkno, -1, &bp, XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + leaf = bp->data; + bzero((char *)leaf, XFS_LBSIZE(dp->i_mount)); + hdr = &leaf->hdr; + INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_DIR_LEAF_MAGIC); + INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount)); + if (INT_ISZERO(hdr->firstused, ARCH_CONVERT)) + INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount) - 1); + INT_SET(hdr->freemap[0].base, ARCH_CONVERT, sizeof(xfs_dir_leaf_hdr_t)); + INT_SET(hdr->freemap[0].size, ARCH_CONVERT, INT_GET(hdr->firstused, ARCH_CONVERT) - INT_GET(hdr->freemap[0].base, ARCH_CONVERT)); + + xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1); + + *bpp = bp; + return(0); +} + +/* + * Split the leaf node, rebalance, then add the new entry. + */ +int +xfs_dir_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, + xfs_da_state_blk_t *newblk) +{ + xfs_dablk_t blkno; + xfs_da_args_t *args; + int error; + + /* + * Allocate space for a new leaf node. + */ + args = state->args; + ASSERT(args != NULL); + ASSERT(oldblk->magic == XFS_DIR_LEAF_MAGIC); + error = xfs_da_grow_inode(args, &blkno); + if (error) + return(error); + error = xfs_dir_leaf_create(args, blkno, &newblk->bp); + if (error) + return(error); + newblk->blkno = blkno; + newblk->magic = XFS_DIR_LEAF_MAGIC; + + /* + * Rebalance the entries across the two leaves. + */ + xfs_dir_leaf_rebalance(state, oldblk, newblk); + error = xfs_da_blk_link(state, oldblk, newblk); + if (error) + return(error); + + /* + * Insert the new entry in the correct block. + */ + if (state->inleaf) { + error = xfs_dir_leaf_add(oldblk->bp, args, oldblk->index); + } else { + error = xfs_dir_leaf_add(newblk->bp, args, newblk->index); + } + + /* + * Update last hashval in each block since we added the name. + */ + oldblk->hashval = xfs_dir_leaf_lasthash(oldblk->bp, NULL); + newblk->hashval = xfs_dir_leaf_lasthash(newblk->bp, NULL); + return(error); +} + +/* + * Add a name to the leaf directory structure. + * + * Must take into account fragmented leaves and leaves where spacemap has + * lost some freespace information (ie: holes). + */ +int +xfs_dir_leaf_add(xfs_dabuf_t *bp, xfs_da_args_t *args, int index) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_hdr_t *hdr; + xfs_dir_leaf_map_t *map; + int tablesize, entsize, sum, i, tmp, error; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + ASSERT((index >= 0) && (index <= INT_GET(leaf->hdr.count, ARCH_CONVERT))); + hdr = &leaf->hdr; + entsize = XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen); + + /* + * Search through freemap for first-fit on new name length. + * (may need to figure in size of entry struct too) + */ + tablesize = (INT_GET(hdr->count, ARCH_CONVERT) + 1) * (uint)sizeof(xfs_dir_leaf_entry_t) + + (uint)sizeof(xfs_dir_leaf_hdr_t); + map = &hdr->freemap[XFS_DIR_LEAF_MAPSIZE-1]; + for (sum = 0, i = XFS_DIR_LEAF_MAPSIZE-1; i >= 0; map--, i--) { + if (tablesize > INT_GET(hdr->firstused, ARCH_CONVERT)) { + sum += INT_GET(map->size, ARCH_CONVERT); + continue; + } + if (INT_GET(map->size, ARCH_CONVERT) == 0) + continue; /* no space in this map */ + tmp = entsize; + if (INT_GET(map->base, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT)) + tmp += (uint)sizeof(xfs_dir_leaf_entry_t); + if (INT_GET(map->size, ARCH_CONVERT) >= tmp) { + if (!args->justcheck) + xfs_dir_leaf_add_work(bp, args, index, i); + return(0); + } + sum += INT_GET(map->size, ARCH_CONVERT); + } + + /* + * If there are no holes in the address space of the block, + * and we don't have enough freespace, then compaction will do us + * no good and we should just give up. + */ + if (!hdr->holes && (sum < entsize)) + return(XFS_ERROR(ENOSPC)); + + /* + * Compact the entries to coalesce free space. + * Pass the justcheck flag so the checking pass can return + * an error, without changing anything, if it won't fit. + */ + error = xfs_dir_leaf_compact(args->trans, bp, + args->total == 0 ? + entsize + + (uint)sizeof(xfs_dir_leaf_entry_t) : 0, + args->justcheck); + if (error) + return(error); + /* + * After compaction, the block is guaranteed to have only one + * free region, in freemap[0]. If it is not big enough, give up. + */ + if (INT_GET(hdr->freemap[0].size, ARCH_CONVERT) < + (entsize + (uint)sizeof(xfs_dir_leaf_entry_t))) + return(XFS_ERROR(ENOSPC)); + + if (!args->justcheck) + xfs_dir_leaf_add_work(bp, args, index, 0); + return(0); +} + +/* + * Add a name to a leaf directory structure. + */ +STATIC void +xfs_dir_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int index, + int mapindex) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_hdr_t *hdr; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + xfs_dir_leaf_map_t *map; + /* REFERENCED */ + xfs_mount_t *mp; + int tmp, i; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + hdr = &leaf->hdr; + ASSERT((mapindex >= 0) && (mapindex < XFS_DIR_LEAF_MAPSIZE)); + ASSERT((index >= 0) && (index <= INT_GET(hdr->count, ARCH_CONVERT))); + + /* + * Force open some space in the entry array and fill it in. + */ + entry = &leaf->entries[index]; + if (index < INT_GET(hdr->count, ARCH_CONVERT)) { + tmp = INT_GET(hdr->count, ARCH_CONVERT) - index; + tmp *= (uint)sizeof(xfs_dir_leaf_entry_t); + ovbcopy(entry, entry + 1, tmp); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry))); + } + INT_MOD(hdr->count, ARCH_CONVERT, +1); + + /* + * Allocate space for the new string (at the end of the run). + */ + map = &hdr->freemap[mapindex]; + mp = args->trans->t_mountp; + ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT(INT_GET(map->size, ARCH_CONVERT) >= XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen)); + ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); + INT_MOD(map->size, ARCH_CONVERT, -(XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen))); + INT_SET(entry->nameidx, ARCH_CONVERT, INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)); + INT_SET(entry->hashval, ARCH_CONVERT, args->hashval); + entry->namelen = args->namelen; + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); + + /* + * Copy the string and inode number into the new space. + */ + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &namest->inumber, ARCH_CONVERT); + bcopy(args->name, namest->name, args->namelen); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, namest, XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry))); + + /* + * Update the control info for this leaf node + */ + if (INT_GET(entry->nameidx, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT)) + INT_COPY(hdr->firstused, entry->nameidx, ARCH_CONVERT); + ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) >= ((INT_GET(hdr->count, ARCH_CONVERT)*sizeof(*entry))+sizeof(*hdr))); + tmp = (INT_GET(hdr->count, ARCH_CONVERT)-1) * (uint)sizeof(xfs_dir_leaf_entry_t) + + (uint)sizeof(xfs_dir_leaf_hdr_t); + map = &hdr->freemap[0]; + for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; map++, i++) { + if (INT_GET(map->base, ARCH_CONVERT) == tmp) { + INT_MOD(map->base, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_entry_t)); + INT_MOD(map->size, ARCH_CONVERT, -((uint)sizeof(xfs_dir_leaf_entry_t))); + } + } + INT_MOD(hdr->namebytes, ARCH_CONVERT, args->namelen); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); +} + +/* + * Garbage collect a leaf directory block by copying it to a new buffer. + */ +STATIC int +xfs_dir_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp, int musthave, + int justcheck) +{ + xfs_dir_leafblock_t *leaf_s, *leaf_d; + xfs_dir_leaf_hdr_t *hdr_s, *hdr_d; + xfs_mount_t *mp; + char *tmpbuffer; + char *tmpbuffer2=NULL; + int rval; + int lbsize; + + mp = trans->t_mountp; + lbsize = XFS_LBSIZE(mp); + tmpbuffer = kmem_alloc(lbsize, KM_SLEEP); + ASSERT(tmpbuffer != NULL); + bcopy(bp->data, tmpbuffer, lbsize); + + /* + * Make a second copy in case xfs_dir_leaf_moveents() + * below destroys the original. + */ + if (musthave || justcheck) { + tmpbuffer2 = kmem_alloc(lbsize, KM_SLEEP); + bcopy(bp->data, tmpbuffer2, lbsize); + } + bzero(bp->data, lbsize); + + /* + * Copy basic information + */ + leaf_s = (xfs_dir_leafblock_t *)tmpbuffer; + leaf_d = bp->data; + hdr_s = &leaf_s->hdr; + hdr_d = &leaf_d->hdr; + hdr_d->info = hdr_s->info; /* struct copy */ + INT_SET(hdr_d->firstused, ARCH_CONVERT, lbsize); + if (INT_GET(hdr_d->firstused, ARCH_CONVERT) == 0) + INT_SET(hdr_d->firstused, ARCH_CONVERT, lbsize - 1); + INT_ZERO(hdr_d->namebytes, ARCH_CONVERT); + INT_ZERO(hdr_d->count, ARCH_CONVERT); + hdr_d->holes = 0; + INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, sizeof(xfs_dir_leaf_hdr_t)); + INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, INT_GET(hdr_d->firstused, ARCH_CONVERT) - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); + + /* + * Copy all entry's in the same (sorted) order, + * but allocate filenames packed and in sequence. + * This changes the source (leaf_s) as well. + */ + xfs_dir_leaf_moveents(leaf_s, 0, leaf_d, 0, (int)INT_GET(hdr_s->count, ARCH_CONVERT), mp); + + if (musthave && INT_GET(hdr_d->freemap[0].size, ARCH_CONVERT) < musthave) + rval = XFS_ERROR(ENOSPC); + else + rval = 0; + + if (justcheck || rval == ENOSPC) { + ASSERT(tmpbuffer2); + bcopy(tmpbuffer2, bp->data, lbsize); + } else { + xfs_da_log_buf(trans, bp, 0, lbsize - 1); + } + + kmem_free(tmpbuffer, lbsize); + if (musthave || justcheck) + kmem_free(tmpbuffer2, lbsize); + return(rval); +} + +/* + * Redistribute the directory entries between two leaf nodes, + * taking into account the size of the new entry. + * + * NOTE: if new block is empty, then it will get the upper half of old block. + */ +STATIC void +xfs_dir_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2) +{ + xfs_da_state_blk_t *tmp_blk; + xfs_dir_leafblock_t *leaf1, *leaf2; + xfs_dir_leaf_hdr_t *hdr1, *hdr2; + int count, totallen, max, space, swap; + + /* + * Set up environment. + */ + ASSERT(blk1->magic == XFS_DIR_LEAF_MAGIC); + ASSERT(blk2->magic == XFS_DIR_LEAF_MAGIC); + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + + /* + * Check ordering of blocks, reverse if it makes things simpler. + */ + swap = 0; + if (xfs_dir_leaf_order(blk1->bp, blk2->bp)) { + tmp_blk = blk1; + blk1 = blk2; + blk2 = tmp_blk; + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + swap = 1; + } + hdr1 = &leaf1->hdr; + hdr2 = &leaf2->hdr; + + /* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. Then get + * the direction to copy and the number of elements to move. + */ + state->inleaf = xfs_dir_leaf_figure_balance(state, blk1, blk2, + &count, &totallen); + if (swap) + state->inleaf = !state->inleaf; + + /* + * Move any entries required from leaf to leaf: + */ + if (count < INT_GET(hdr1->count, ARCH_CONVERT)) { + /* + * Figure the total bytes to be added to the destination leaf. + */ + count = INT_GET(hdr1->count, ARCH_CONVERT) - count; /* number entries being moved */ + space = INT_GET(hdr1->namebytes, ARCH_CONVERT) - totallen; + space += count * ((uint)sizeof(xfs_dir_leaf_name_t)-1); + space += count * (uint)sizeof(xfs_dir_leaf_entry_t); + + /* + * leaf2 is the destination, compact it if it looks tight. + */ + max = INT_GET(hdr2->firstused, ARCH_CONVERT) - (uint)sizeof(xfs_dir_leaf_hdr_t); + max -= INT_GET(hdr2->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t); + if (space > max) { + xfs_dir_leaf_compact(state->args->trans, blk2->bp, + 0, 0); + } + + /* + * Move high entries from leaf1 to low end of leaf2. + */ + xfs_dir_leaf_moveents(leaf1, INT_GET(hdr1->count, ARCH_CONVERT) - count, + leaf2, 0, count, state->mp); + + xfs_da_log_buf(state->args->trans, blk1->bp, 0, + state->blocksize-1); + xfs_da_log_buf(state->args->trans, blk2->bp, 0, + state->blocksize-1); + + } else if (count > INT_GET(hdr1->count, ARCH_CONVERT)) { + /* + * Figure the total bytes to be added to the destination leaf. + */ + count -= INT_GET(hdr1->count, ARCH_CONVERT); /* number entries being moved */ + space = totallen - INT_GET(hdr1->namebytes, ARCH_CONVERT); + space += count * ((uint)sizeof(xfs_dir_leaf_name_t)-1); + space += count * (uint)sizeof(xfs_dir_leaf_entry_t); + + /* + * leaf1 is the destination, compact it if it looks tight. + */ + max = INT_GET(hdr1->firstused, ARCH_CONVERT) - (uint)sizeof(xfs_dir_leaf_hdr_t); + max -= INT_GET(hdr1->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t); + if (space > max) { + xfs_dir_leaf_compact(state->args->trans, blk1->bp, + 0, 0); + } + + /* + * Move low entries from leaf2 to high end of leaf1. + */ + xfs_dir_leaf_moveents(leaf2, 0, leaf1, (int)INT_GET(hdr1->count, ARCH_CONVERT), + count, state->mp); + + xfs_da_log_buf(state->args->trans, blk1->bp, 0, + state->blocksize-1); + xfs_da_log_buf(state->args->trans, blk2->bp, 0, + state->blocksize-1); + } + + /* + * Copy out last hashval in each block for B-tree code. + */ + blk1->hashval = INT_GET(leaf1->entries[ INT_GET(leaf1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + blk2->hashval = INT_GET(leaf2->entries[ INT_GET(leaf2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + + /* + * Adjust the expected index for insertion. + * GROT: this doesn't work unless blk2 was originally empty. + */ + if (!state->inleaf) { + blk2->index = blk1->index - INT_GET(leaf1->hdr.count, ARCH_CONVERT); + } +} + +/* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. + * GROT: Is this really necessary? With other than a 512 byte blocksize, + * GROT: there will always be enough room in either block for a new entry. + * GROT: Do a double-split for this case? + */ +STATIC int +xfs_dir_leaf_figure_balance(xfs_da_state_t *state, + xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2, + int *countarg, int *namebytesarg) +{ + xfs_dir_leafblock_t *leaf1, *leaf2; + xfs_dir_leaf_hdr_t *hdr1, *hdr2; + xfs_dir_leaf_entry_t *entry; + int count, max, totallen, half; + int lastdelta, foundit, tmp; + + /* + * Set up environment. + */ + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + hdr1 = &leaf1->hdr; + hdr2 = &leaf2->hdr; + foundit = 0; + totallen = 0; + + /* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. + */ + max = INT_GET(hdr1->count, ARCH_CONVERT) + INT_GET(hdr2->count, ARCH_CONVERT); + half = (max+1) * (uint)(sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1); + half += INT_GET(hdr1->namebytes, ARCH_CONVERT) + INT_GET(hdr2->namebytes, ARCH_CONVERT) + state->args->namelen; + half /= 2; + lastdelta = state->blocksize; + entry = &leaf1->entries[0]; + for (count = 0; count < max; entry++, count++) { + +#define XFS_DIR_ABS(A) (((A) < 0) ? -(A) : (A)) + /* + * The new entry is in the first block, account for it. + */ + if (count == blk1->index) { + tmp = totallen + (uint)sizeof(*entry) + + XFS_DIR_LEAF_ENTSIZE_BYNAME(state->args->namelen); + if (XFS_DIR_ABS(half - tmp) > lastdelta) + break; + lastdelta = XFS_DIR_ABS(half - tmp); + totallen = tmp; + foundit = 1; + } + + /* + * Wrap around into the second block if necessary. + */ + if (count == INT_GET(hdr1->count, ARCH_CONVERT)) { + leaf1 = leaf2; + entry = &leaf1->entries[0]; + } + + /* + * Figure out if next leaf entry would be too much. + */ + tmp = totallen + (uint)sizeof(*entry) + + XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry); + if (XFS_DIR_ABS(half - tmp) > lastdelta) + break; + lastdelta = XFS_DIR_ABS(half - tmp); + totallen = tmp; +#undef XFS_DIR_ABS + } + + /* + * Calculate the number of namebytes that will end up in lower block. + * If new entry not in lower block, fix up the count. + */ + totallen -= + count * (uint)(sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1); + if (foundit) { + totallen -= (sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1) + + state->args->namelen; + } + + *countarg = count; + *namebytesarg = totallen; + return(foundit); +} + +/*======================================================================== + * Routines used for shrinking the Btree. + *========================================================================*/ + +/* + * Check a leaf block and its neighbors to see if the block should be + * collapsed into one or the other neighbor. Always keep the block + * with the smaller block number. + * If the current block is over 50% full, don't try to join it, return 0. + * If the block is empty, fill in the state structure and return 2. + * If it can be collapsed, fill in the state structure and return 1. + * If nothing can be done, return 0. + */ +int +xfs_dir_leaf_toosmall(xfs_da_state_t *state, int *action) +{ + xfs_dir_leafblock_t *leaf; + xfs_da_state_blk_t *blk; + xfs_da_blkinfo_t *info; + int count, bytes, forward, error, retval, i; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + + /* + * Check for the degenerate case of the block being over 50% full. + * If so, it's not worth even looking to see if we might be able + * to coalesce with a sibling. + */ + blk = &state->path.blk[ state->path.active-1 ]; + info = blk->bp->data; + ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + leaf = (xfs_dir_leafblock_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes = (uint)sizeof(xfs_dir_leaf_hdr_t) + + count * (uint)sizeof(xfs_dir_leaf_entry_t) + + count * ((uint)sizeof(xfs_dir_leaf_name_t)-1) + + INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); + if (bytes > (state->blocksize >> 1)) { + *action = 0; /* blk over 50%, dont try to join */ + return(0); + } + + /* + * Check for the degenerate case of the block being empty. + * If the block is empty, we'll simply delete it, no need to + * coalesce it with a sibling block. We choose (aribtrarily) + * to merge with the forward block unless it is NULL. + */ + if (count == 0) { + /* + * Make altpath point to the block we want to keep and + * path point to the block we want to drop (this one). + */ + forward = !INT_ISZERO(info->forw, ARCH_CONVERT); + bcopy(&state->path, &state->altpath, sizeof(state->path)); + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + if (error) + return(error); + if (retval) { + *action = 0; + } else { + *action = 2; + } + return(0); + } + + /* + * Examine each sibling block to see if we can coalesce with + * at least 25% free space to spare. We need to figure out + * whether to merge with the forward or the backward block. + * We prefer coalescing with the lower numbered sibling so as + * to shrink a directory over time. + */ + forward = (INT_GET(info->forw, ARCH_CONVERT) < INT_GET(info->back, ARCH_CONVERT)); /* start with smaller blk num */ + for (i = 0; i < 2; forward = !forward, i++) { + if (forward) + blkno = INT_GET(info->forw, ARCH_CONVERT); + else + blkno = INT_GET(info->back, ARCH_CONVERT); + if (blkno == 0) + continue; + error = xfs_da_read_buf(state->args->trans, state->args->dp, + blkno, -1, &bp, + XFS_DATA_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + + leaf = (xfs_dir_leafblock_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes = state->blocksize - (state->blocksize>>2); + bytes -= INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + count += INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes -= INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); + bytes -= count * ((uint)sizeof(xfs_dir_leaf_name_t) - 1); + bytes -= count * (uint)sizeof(xfs_dir_leaf_entry_t); + bytes -= (uint)sizeof(xfs_dir_leaf_hdr_t); + if (bytes >= 0) + break; /* fits with at least 25% to spare */ + + xfs_da_brelse(state->args->trans, bp); + } + if (i >= 2) { + *action = 0; + return(0); + } + xfs_da_buf_done(bp); + + /* + * Make altpath point to the block we want to keep (the lower + * numbered block) and path point to the block we want to drop. + */ + bcopy(&state->path, &state->altpath, sizeof(state->path)); + if (blkno < blk->blkno) { + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + } else { + error = xfs_da_path_shift(state, &state->path, forward, + 0, &retval); + } + if (error) + return(error); + if (retval) { + *action = 0; + } else { + *action = 1; + } + return(0); +} + +/* + * Remove a name from the leaf directory structure. + * + * Return 1 if leaf is less than 37% full, 0 if >= 37% full. + * If two leaves are 37% full, when combined they will leave 25% free. + */ +int +xfs_dir_leaf_remove(xfs_trans_t *trans, xfs_dabuf_t *bp, int index) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_hdr_t *hdr; + xfs_dir_leaf_map_t *map; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + int before, after, smallest, entsize; + int tablesize, tmp, i; + xfs_mount_t *mp; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + hdr = &leaf->hdr; + mp = trans->t_mountp; + ASSERT((INT_GET(hdr->count, ARCH_CONVERT) > 0) && (INT_GET(hdr->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8))); + ASSERT((index >= 0) && (index < INT_GET(hdr->count, ARCH_CONVERT))); + ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) >= ((INT_GET(hdr->count, ARCH_CONVERT)*sizeof(*entry))+sizeof(*hdr))); + entry = &leaf->entries[index]; + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >= INT_GET(hdr->firstused, ARCH_CONVERT)); + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp)); + + /* + * Scan through free region table: + * check for adjacency of free'd entry with an existing one, + * find smallest free region in case we need to replace it, + * adjust any map that borders the entry table, + */ + tablesize = INT_GET(hdr->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t) + + (uint)sizeof(xfs_dir_leaf_hdr_t); + map = &hdr->freemap[0]; + tmp = INT_GET(map->size, ARCH_CONVERT); + before = after = -1; + smallest = XFS_DIR_LEAF_MAPSIZE - 1; + entsize = XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry); + for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; map++, i++) { + ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); + if (INT_GET(map->base, ARCH_CONVERT) == tablesize) { + INT_MOD(map->base, ARCH_CONVERT, -((uint)sizeof(xfs_dir_leaf_entry_t))); + INT_MOD(map->size, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_entry_t)); + } + + if ((INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)) == INT_GET(entry->nameidx, ARCH_CONVERT)) { + before = i; + } else if (INT_GET(map->base, ARCH_CONVERT) == (INT_GET(entry->nameidx, ARCH_CONVERT) + entsize)) { + after = i; + } else if (INT_GET(map->size, ARCH_CONVERT) < tmp) { + tmp = INT_GET(map->size, ARCH_CONVERT); + smallest = i; + } + } + + /* + * Coalesce adjacent freemap regions, + * or replace the smallest region. + */ + if ((before >= 0) || (after >= 0)) { + if ((before >= 0) && (after >= 0)) { + map = &hdr->freemap[before]; + INT_MOD(map->size, ARCH_CONVERT, entsize); + INT_MOD(map->size, ARCH_CONVERT, INT_GET(hdr->freemap[after].size, ARCH_CONVERT)); + INT_ZERO(hdr->freemap[after].base, ARCH_CONVERT); + INT_ZERO(hdr->freemap[after].size, ARCH_CONVERT); + } else if (before >= 0) { + map = &hdr->freemap[before]; + INT_MOD(map->size, ARCH_CONVERT, entsize); + } else { + map = &hdr->freemap[after]; + INT_COPY(map->base, entry->nameidx, ARCH_CONVERT); + INT_MOD(map->size, ARCH_CONVERT, entsize); + } + } else { + /* + * Replace smallest region (if it is smaller than free'd entry) + */ + map = &hdr->freemap[smallest]; + if (INT_GET(map->size, ARCH_CONVERT) < entsize) { + INT_COPY(map->base, entry->nameidx, ARCH_CONVERT); + INT_SET(map->size, ARCH_CONVERT, entsize); + } + } + + /* + * Did we remove the first entry? + */ + if (INT_GET(entry->nameidx, ARCH_CONVERT) == INT_GET(hdr->firstused, ARCH_CONVERT)) + smallest = 1; + else + smallest = 0; + + /* + * Compress the remaining entries and zero out the removed stuff. + */ + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + bzero((char *)namest, entsize); + xfs_da_log_buf(trans, bp, XFS_DA_LOGRANGE(leaf, namest, entsize)); + + INT_MOD(hdr->namebytes, ARCH_CONVERT, -(entry->namelen)); + tmp = (INT_GET(hdr->count, ARCH_CONVERT) - index) * (uint)sizeof(xfs_dir_leaf_entry_t); + ovbcopy(entry + 1, entry, tmp); + INT_MOD(hdr->count, ARCH_CONVERT, -1); + xfs_da_log_buf(trans, bp, + XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry))); + entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)]; + bzero((char *)entry, sizeof(xfs_dir_leaf_entry_t)); + + /* + * If we removed the first entry, re-find the first used byte + * in the name area. Note that if the entry was the "firstused", + * then we don't have a "hole" in our block resulting from + * removing the name. + */ + if (smallest) { + tmp = XFS_LBSIZE(mp); + entry = &leaf->entries[0]; + for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; i >= 0; entry++, i--) { + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >= INT_GET(hdr->firstused, ARCH_CONVERT)); + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp)); + if (INT_GET(entry->nameidx, ARCH_CONVERT) < tmp) + tmp = INT_GET(entry->nameidx, ARCH_CONVERT); + } + INT_SET(hdr->firstused, ARCH_CONVERT, tmp); + if (INT_GET(hdr->firstused, ARCH_CONVERT) == 0) + INT_SET(hdr->firstused, ARCH_CONVERT, tmp - 1); + } else { + hdr->holes = 1; /* mark as needing compaction */ + } + + xfs_da_log_buf(trans, bp, XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); + + /* + * Check if leaf is less than 50% full, caller may want to + * "join" the leaf with a sibling if so. + */ + tmp = (uint)sizeof(xfs_dir_leaf_hdr_t); + tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t); + tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) * ((uint)sizeof(xfs_dir_leaf_name_t) - 1); + tmp += INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); + if (tmp < mp->m_dir_magicpct) + return(1); /* leaf is < 37% full */ + return(0); +} + +/* + * Move all the directory entries from drop_leaf into save_leaf. + */ +void +xfs_dir_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk) +{ + xfs_dir_leafblock_t *drop_leaf, *save_leaf, *tmp_leaf; + xfs_dir_leaf_hdr_t *drop_hdr, *save_hdr, *tmp_hdr; + xfs_mount_t *mp; + char *tmpbuffer; + + /* + * Set up environment. + */ + mp = state->mp; + ASSERT(drop_blk->magic == XFS_DIR_LEAF_MAGIC); + ASSERT(save_blk->magic == XFS_DIR_LEAF_MAGIC); + drop_leaf = drop_blk->bp->data; + save_leaf = save_blk->bp->data; + ASSERT(INT_GET(drop_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + ASSERT(INT_GET(save_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + drop_hdr = &drop_leaf->hdr; + save_hdr = &save_leaf->hdr; + + /* + * Save last hashval from dying block for later Btree fixup. + */ + drop_blk->hashval = INT_GET(drop_leaf->entries[ drop_leaf->hdr.count-1 ].hashval, ARCH_CONVERT); + + /* + * Check if we need a temp buffer, or can we do it in place. + * Note that we don't check "leaf" for holes because we will + * always be dropping it, toosmall() decided that for us already. + */ + if (save_hdr->holes == 0) { + /* + * dest leaf has no holes, so we add there. May need + * to make some room in the entry array. + */ + if (xfs_dir_leaf_order(save_blk->bp, drop_blk->bp)) { + xfs_dir_leaf_moveents(drop_leaf, 0, save_leaf, 0, + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); + } else { + xfs_dir_leaf_moveents(drop_leaf, 0, + save_leaf, INT_GET(save_hdr->count, ARCH_CONVERT), + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); + } + } else { + /* + * Destination has holes, so we make a temporary copy + * of the leaf and add them both to that. + */ + tmpbuffer = kmem_alloc(state->blocksize, KM_SLEEP); + ASSERT(tmpbuffer != NULL); + bzero(tmpbuffer, state->blocksize); + tmp_leaf = (xfs_dir_leafblock_t *)tmpbuffer; + tmp_hdr = &tmp_leaf->hdr; + tmp_hdr->info = save_hdr->info; /* struct copy */ + INT_ZERO(tmp_hdr->count, ARCH_CONVERT); + INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize); + if (INT_GET(tmp_hdr->firstused, ARCH_CONVERT) == 0) + INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize - 1); + INT_ZERO(tmp_hdr->namebytes, ARCH_CONVERT); + if (xfs_dir_leaf_order(save_blk->bp, drop_blk->bp)) { + xfs_dir_leaf_moveents(drop_leaf, 0, tmp_leaf, 0, + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); + xfs_dir_leaf_moveents(save_leaf, 0, + tmp_leaf, INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), + (int)INT_GET(save_hdr->count, ARCH_CONVERT), mp); + } else { + xfs_dir_leaf_moveents(save_leaf, 0, tmp_leaf, 0, + (int)INT_GET(save_hdr->count, ARCH_CONVERT), mp); + xfs_dir_leaf_moveents(drop_leaf, 0, + tmp_leaf, INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); + } + bcopy(tmp_leaf, save_leaf, state->blocksize); + kmem_free(tmpbuffer, state->blocksize); + } + + xfs_da_log_buf(state->args->trans, save_blk->bp, 0, + state->blocksize - 1); + + /* + * Copy out last hashval in each block for B-tree code. + */ + save_blk->hashval = INT_GET(save_leaf->entries[ INT_GET(save_leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); +} + + +/*======================================================================== + * Routines used for finding things in the Btree. + *========================================================================*/ + +/* + * Look up a name in a leaf directory structure. + * This is the internal routine, it uses the caller's buffer. + * + * Note that duplicate keys are allowed, but only check within the + * current leaf node. The Btree code must check in adjacent leaf nodes. + * + * Return in *index the index into the entry[] array of either the found + * entry, or where the entry should have been (insert before that entry). + * + * Don't change the args->inumber unless we find the filename. + */ +int +xfs_dir_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args, int *index) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + int probe, span; + xfs_dahash_t hashval; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) < (XFS_LBSIZE(args->dp->i_mount)/8)); + + /* + * Binary search. (note: small blocks will skip this loop) + */ + hashval = args->hashval; + probe = span = INT_GET(leaf->hdr.count, ARCH_CONVERT) / 2; + for (entry = &leaf->entries[probe]; span > 4; + entry = &leaf->entries[probe]) { + span /= 2; + if (INT_GET(entry->hashval, ARCH_CONVERT) < hashval) + probe += span; + else if (INT_GET(entry->hashval, ARCH_CONVERT) > hashval) + probe -= span; + else + break; + } + ASSERT((probe >= 0) && \ + ((INT_GET(leaf->hdr.count, ARCH_CONVERT) == 0) || (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)))); + ASSERT((span <= 4) || (INT_GET(entry->hashval, ARCH_CONVERT) == hashval)); + + /* + * Since we may have duplicate hashval's, find the first matching + * hashval in the leaf. + */ + while ((probe > 0) && (INT_GET(entry->hashval, ARCH_CONVERT) >= hashval)) { + entry--; + probe--; + } + while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) && (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)) { + entry++; + probe++; + } + if ((probe == INT_GET(leaf->hdr.count, ARCH_CONVERT)) || (INT_GET(entry->hashval, ARCH_CONVERT) != hashval)) { + *index = probe; + ASSERT(args->oknoent); + return(XFS_ERROR(ENOENT)); + } + + /* + * Duplicate keys may be present, so search all of them for a match. + */ + while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) && (INT_GET(entry->hashval, ARCH_CONVERT) == hashval)) { + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + if (entry->namelen == args->namelen && + namest->name[0] == args->name[0] && + bcmp(args->name, namest->name, args->namelen) == 0) { + XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &args->inumber, ARCH_CONVERT); + *index = probe; + return(XFS_ERROR(EEXIST)); + } + entry++; + probe++; + } + *index = probe; + ASSERT(probe == INT_GET(leaf->hdr.count, ARCH_CONVERT) || args->oknoent); + return(XFS_ERROR(ENOENT)); +} + +/*======================================================================== + * Utility routines. + *========================================================================*/ + +/* + * Move the indicated entries from one leaf to another. + * NOTE: this routine modifies both source and destination leaves. + */ +/* ARGSUSED */ +STATIC void +xfs_dir_leaf_moveents(xfs_dir_leafblock_t *leaf_s, int start_s, + xfs_dir_leafblock_t *leaf_d, int start_d, + int count, xfs_mount_t *mp) +{ + xfs_dir_leaf_hdr_t *hdr_s, *hdr_d; + xfs_dir_leaf_entry_t *entry_s, *entry_d; + int tmp, i; + + /* + * Check for nothing to do. + */ + if (count == 0) + return; + + /* + * Set up environment. + */ + ASSERT(INT_GET(leaf_s->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + ASSERT(INT_GET(leaf_d->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + hdr_s = &leaf_s->hdr; + hdr_d = &leaf_d->hdr; + ASSERT((INT_GET(hdr_s->count, ARCH_CONVERT) > 0) && (INT_GET(hdr_s->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8))); + ASSERT(INT_GET(hdr_s->firstused, ARCH_CONVERT) >= + ((INT_GET(hdr_s->count, ARCH_CONVERT)*sizeof(*entry_s))+sizeof(*hdr_s))); + ASSERT(INT_GET(hdr_d->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8)); + ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= + ((INT_GET(hdr_d->count, ARCH_CONVERT)*sizeof(*entry_d))+sizeof(*hdr_d))); + + ASSERT(start_s < INT_GET(hdr_s->count, ARCH_CONVERT)); + ASSERT(start_d <= INT_GET(hdr_d->count, ARCH_CONVERT)); + ASSERT(count <= INT_GET(hdr_s->count, ARCH_CONVERT)); + + /* + * Move the entries in the destination leaf up to make a hole? + */ + if (start_d < INT_GET(hdr_d->count, ARCH_CONVERT)) { + tmp = INT_GET(hdr_d->count, ARCH_CONVERT) - start_d; + tmp *= (uint)sizeof(xfs_dir_leaf_entry_t); + entry_s = &leaf_d->entries[start_d]; + entry_d = &leaf_d->entries[start_d + count]; + bcopy(entry_s, entry_d, tmp); + } + + /* + * Copy all entry's in the same (sorted) order, + * but allocate filenames packed and in sequence. + */ + entry_s = &leaf_s->entries[start_s]; + entry_d = &leaf_d->entries[start_d]; + for (i = 0; i < count; entry_s++, entry_d++, i++) { + ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) >= INT_GET(hdr_s->firstused, ARCH_CONVERT)); + ASSERT(entry_s->namelen < MAXNAMELEN); + tmp = XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry_s); + INT_MOD(hdr_d->firstused, ARCH_CONVERT, -(tmp)); + entry_d->hashval = entry_s->hashval; /* INT_: direct copy */ + INT_COPY(entry_d->nameidx, hdr_d->firstused, ARCH_CONVERT); + entry_d->namelen = entry_s->namelen; + ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp)); + bcopy(XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)), + XFS_DIR_LEAF_NAMESTRUCT(leaf_d, INT_GET(entry_d->nameidx, ARCH_CONVERT)), tmp); + ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp)); + bzero((char *)XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)), + tmp); + INT_MOD(hdr_s->namebytes, ARCH_CONVERT, -(entry_d->namelen)); + INT_MOD(hdr_d->namebytes, ARCH_CONVERT, entry_d->namelen); + INT_MOD(hdr_s->count, ARCH_CONVERT, -1); + INT_MOD(hdr_d->count, ARCH_CONVERT, +1); + tmp = INT_GET(hdr_d->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t) + + (uint)sizeof(xfs_dir_leaf_hdr_t); + ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= tmp); + + } + + /* + * Zero out the entries we just copied. + */ + if (start_s == INT_GET(hdr_s->count, ARCH_CONVERT)) { + tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t); + entry_s = &leaf_s->entries[start_s]; + ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp)); + bzero((char *)entry_s, tmp); + } else { + /* + * Move the remaining entries down to fill the hole, + * then zero the entries at the top. + */ + tmp = INT_GET(hdr_s->count, ARCH_CONVERT) - count; + tmp *= (uint)sizeof(xfs_dir_leaf_entry_t); + entry_s = &leaf_s->entries[start_s + count]; + entry_d = &leaf_s->entries[start_s]; + bcopy(entry_s, entry_d, tmp); + + tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t); + entry_s = &leaf_s->entries[INT_GET(hdr_s->count, ARCH_CONVERT)]; + ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp)); + bzero((char *)entry_s, tmp); + } + + /* + * Fill in the freemap information + */ + INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_hdr_t)); + INT_MOD(hdr_d->freemap[0].base, ARCH_CONVERT, INT_GET(hdr_d->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t)); + INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, INT_GET(hdr_d->firstused, ARCH_CONVERT) - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); + INT_SET(hdr_d->freemap[1].base, ARCH_CONVERT, INT_ZERO(hdr_d->freemap[2].base, ARCH_CONVERT)); + INT_SET(hdr_d->freemap[1].size, ARCH_CONVERT, INT_ZERO(hdr_d->freemap[2].size, ARCH_CONVERT)); + hdr_s->holes = 1; /* leaf may not be compact */ +} + +/* + * Compare two leaf blocks "order". + */ +int +xfs_dir_leaf_order(xfs_dabuf_t *leaf1_bp, xfs_dabuf_t *leaf2_bp) +{ + xfs_dir_leafblock_t *leaf1, *leaf2; + + leaf1 = leaf1_bp->data; + leaf2 = leaf2_bp->data; + ASSERT((INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC) && + (INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC)); + if ((INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0) && (INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0) && + ((INT_GET(leaf2->entries[ 0 ].hashval, ARCH_CONVERT) < + INT_GET(leaf1->entries[ 0 ].hashval, ARCH_CONVERT)) || + (INT_GET(leaf2->entries[ INT_GET(leaf2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) < + INT_GET(leaf1->entries[ INT_GET(leaf1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)))) { + return(1); + } + return(0); +} + +/* + * Pick up the last hashvalue from a leaf block. + */ +xfs_dahash_t +xfs_dir_leaf_lasthash(xfs_dabuf_t *bp, int *count) +{ + xfs_dir_leafblock_t *leaf; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + if (count) + *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + if (INT_GET(leaf->hdr.count, ARCH_CONVERT) == 0) + return(0); + return(INT_GET(leaf->entries[ INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)); +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_ialloc.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_ialloc.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_ialloc.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_ialloc.c Thu Apr 12 18:30:32 2001 @@ -0,0 +1,1113 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * Internal functions. + */ + +/* + * Log specified fields for the inode given by bp and off. + */ +STATIC void +xfs_ialloc_log_di( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *bp, /* inode buffer */ + int off, /* index of inode in buffer */ + int fields) /* bitmask of fields to log */ +{ + int first; /* first byte number */ + int ioffset; /* off in bytes */ + int last; /* last byte number */ + xfs_mount_t *mp; /* mount point structure */ + static const short offsets[] = { /* field offsets */ + /* keep in sync with bits */ + offsetof(xfs_dinode_core_t, di_magic), + offsetof(xfs_dinode_core_t, di_mode), + offsetof(xfs_dinode_core_t, di_version), + offsetof(xfs_dinode_core_t, di_format), + offsetof(xfs_dinode_core_t, di_onlink), + offsetof(xfs_dinode_core_t, di_uid), + offsetof(xfs_dinode_core_t, di_gid), + offsetof(xfs_dinode_core_t, di_nlink), + offsetof(xfs_dinode_core_t, di_projid), + offsetof(xfs_dinode_core_t, di_pad), + offsetof(xfs_dinode_core_t, di_atime), + offsetof(xfs_dinode_core_t, di_mtime), + offsetof(xfs_dinode_core_t, di_ctime), + offsetof(xfs_dinode_core_t, di_size), + offsetof(xfs_dinode_core_t, di_nblocks), + offsetof(xfs_dinode_core_t, di_extsize), + offsetof(xfs_dinode_core_t, di_nextents), + offsetof(xfs_dinode_core_t, di_anextents), + offsetof(xfs_dinode_core_t, di_forkoff), + offsetof(xfs_dinode_core_t, di_aformat), + offsetof(xfs_dinode_core_t, di_dmevmask), + offsetof(xfs_dinode_core_t, di_dmstate), + offsetof(xfs_dinode_core_t, di_flags), + offsetof(xfs_dinode_core_t, di_gen), + offsetof(xfs_dinode_t, di_next_unlinked), + offsetof(xfs_dinode_t, di_u), + offsetof(xfs_dinode_t, di_a), + sizeof(xfs_dinode_t) + }; + + + ASSERT(offsetof(xfs_dinode_t, di_core) == 0); + ASSERT((fields & (XFS_DI_U|XFS_DI_A)) == 0); + mp = tp->t_mountp; + /* + * Get the inode-relative first and last bytes for these fields + */ + xfs_btree_offsets(fields, offsets, XFS_DI_NUM_BITS, &first, &last); + /* + * Convert to buffer offsets and log it. + */ + ioffset = off << mp->m_sb.sb_inodelog; + first += ioffset; + last += ioffset; + xfs_trans_log_buf(tp, bp, first, last); +} + +/* + * Allocation group level functions. + */ + +/* + * Allocate new inodes in the allocation group specified by agbp. + * Return 0 for success, else error code. + */ +STATIC int /* error code or 0 */ +xfs_ialloc_ag_alloc( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* alloc group buffer */ + int *alloc) +{ + xfs_agi_t *agi; /* allocation group header */ + xfs_alloc_arg_t args; /* allocation argument structure */ + int blks_per_cluster; /* fs blocks per inode cluster */ + xfs_btree_cur_t *cur; /* inode btree cursor */ + xfs_daddr_t d; /* disk addr of buffer */ + int error; + xfs_buf_t *fbuf; /* new free inodes' buffer */ + xfs_dinode_t *free; /* new free inode structure */ + int i; /* inode counter */ + int j; /* block counter */ + int nbufs; /* num bufs of new inodes */ + xfs_agino_t newino; /* new first inode's number */ + xfs_agino_t newlen; /* new number of inodes */ + int ninodes; /* num inodes per buf */ + xfs_agino_t thisino; /* current inode number, for loop */ + int version; /* inode version number to use */ + static xfs_timestamp_t ztime; /* zero xfs timestamp */ + int isaligned; /* inode allocation at stripe unit */ + /* boundary */ + xfs_dinode_core_t dic; /* a dinode_core to copy to new */ + /* inodes */ + + args.tp = tp; + args.mp = tp->t_mountp; + + /* + * Locking will ensure that we don't have two callers in here + * at one time. + */ + newlen = XFS_IALLOC_INODES(args.mp); + if (args.mp->m_maxicount && + args.mp->m_sb.sb_icount + newlen > args.mp->m_maxicount) + return XFS_ERROR(ENOSPC); + args.minlen = args.maxlen = XFS_IALLOC_BLOCKS(args.mp); + /* + * Set the alignment for the allocation. + * If stripe alignment is turned on then align at stripe unit + * boundary. + * If the cluster size is smaller than a filesystem block + * then we're doing I/O for inodes in filesystem block size pieces, + * so don't need alignment anyway. + */ + isaligned = 0; + if (args.mp->m_sinoalign) { + ASSERT(!(args.mp->m_flags & XFS_MOUNT_NOALIGN)); + args.alignment = args.mp->m_dalign; + isaligned = 1; + } else if (XFS_SB_VERSION_HASALIGN(&args.mp->m_sb) && + args.mp->m_sb.sb_inoalignmt >= + XFS_B_TO_FSBT(args.mp, XFS_INODE_CLUSTER_SIZE(args.mp))) + args.alignment = args.mp->m_sb.sb_inoalignmt; + else + args.alignment = 1; + agi = XFS_BUF_TO_AGI(agbp); + /* + * Need to figure out where to allocate the inode blocks. + * Ideally they should be spaced out through the a.g. + * For now, just allocate blocks up front. + */ + args.agbno = INT_GET(agi->agi_root, ARCH_CONVERT); + args.fsbno = XFS_AGB_TO_FSB(args.mp, INT_GET(agi->agi_seqno, ARCH_CONVERT), + args.agbno); + /* + * Allocate a fixed-size extent of inodes. + */ + args.type = XFS_ALLOCTYPE_NEAR_BNO; + args.mod = args.total = args.wasdel = args.isfl = args.userdata = + args.minalignslop = 0; + args.prod = 1; + /* + * Allow space for the inode btree to split. + */ + args.minleft = XFS_IN_MAXLEVELS(args.mp) - 1; + if ((error = xfs_alloc_vextent(&args))) + return error; + + /* + * If stripe alignment is turned on, then try again with cluster + * alignment. + */ + if (isaligned && args.fsbno == NULLFSBLOCK) { + args.type = XFS_ALLOCTYPE_NEAR_BNO; + args.agbno = INT_GET(agi->agi_root, ARCH_CONVERT); + args.fsbno = XFS_AGB_TO_FSB(args.mp, + INT_GET(agi->agi_seqno, ARCH_CONVERT), args.agbno); + if (XFS_SB_VERSION_HASALIGN(&args.mp->m_sb) && + args.mp->m_sb.sb_inoalignmt >= + XFS_B_TO_FSBT(args.mp, XFS_INODE_CLUSTER_SIZE(args.mp))) + args.alignment = args.mp->m_sb.sb_inoalignmt; + else + args.alignment = 1; + if ((error = xfs_alloc_vextent(&args))) + return error; + } + + if (args.fsbno == NULLFSBLOCK) { + *alloc = 0; + return 0; + } + ASSERT(args.len == args.minlen); + /* + * Convert the results. + */ + newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0); + /* + * Loop over the new block(s), filling in the inodes. + * For small block sizes, manipulate the inodes in buffers + * which are multiples of the blocks size. + */ + if (args.mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(args.mp)) { + blks_per_cluster = 1; + nbufs = (int)args.len; + ninodes = args.mp->m_sb.sb_inopblock; + } else { + blks_per_cluster = XFS_INODE_CLUSTER_SIZE(args.mp) / + args.mp->m_sb.sb_blocksize; + nbufs = (int)args.len / blks_per_cluster; + ninodes = blks_per_cluster * args.mp->m_sb.sb_inopblock; + } + /* + * Figure out what version number to use in the inodes we create. + * If the superblock version has caught up to the one that supports + * the new inode format, then use the new inode version. Otherwise + * use the old version so that old kernels will continue to be + * able to use the file system. + */ + if (XFS_SB_VERSION_HASNLINK(&args.mp->m_sb)) + version = XFS_DINODE_VERSION_2; + else + version = XFS_DINODE_VERSION_1; + for (j = 0; j < nbufs; j++) { + /* + * Get the block. + */ + d = XFS_AGB_TO_DADDR(args.mp, INT_GET(agi->agi_seqno, ARCH_CONVERT), + args.agbno + (j * blks_per_cluster)); + fbuf = xfs_trans_get_buf(tp, args.mp->m_ddev_targp, d, + args.mp->m_bsize * blks_per_cluster, + XFS_BUF_LOCK); + ASSERT(fbuf); + ASSERT(!XFS_BUF_GETERROR(fbuf)); + /* + * Loop over the inodes in this buffer. + */ + INT_SET(dic.di_magic, ARCH_CONVERT, XFS_DINODE_MAGIC); + INT_ZERO(dic.di_mode, ARCH_CONVERT); + INT_SET(dic.di_version, ARCH_CONVERT, version); + INT_ZERO(dic.di_format, ARCH_CONVERT); + INT_ZERO(dic.di_onlink, ARCH_CONVERT); + INT_ZERO(dic.di_uid, ARCH_CONVERT); + INT_ZERO(dic.di_gid, ARCH_CONVERT); + INT_ZERO(dic.di_nlink, ARCH_CONVERT); + INT_ZERO(dic.di_projid, ARCH_CONVERT); + bzero(&(dic.di_pad[0]),sizeof(dic.di_pad)); + INT_SET(dic.di_atime.t_sec, ARCH_CONVERT, ztime.t_sec); + INT_SET(dic.di_atime.t_nsec, ARCH_CONVERT, ztime.t_nsec); + + INT_SET(dic.di_mtime.t_sec, ARCH_CONVERT, ztime.t_sec); + INT_SET(dic.di_mtime.t_nsec, ARCH_CONVERT, ztime.t_nsec); + + INT_SET(dic.di_ctime.t_sec, ARCH_CONVERT, ztime.t_sec); + INT_SET(dic.di_ctime.t_nsec, ARCH_CONVERT, ztime.t_nsec); + + INT_ZERO(dic.di_size, ARCH_CONVERT); + INT_ZERO(dic.di_nblocks, ARCH_CONVERT); + INT_ZERO(dic.di_extsize, ARCH_CONVERT); + INT_ZERO(dic.di_nextents, ARCH_CONVERT); + INT_ZERO(dic.di_anextents, ARCH_CONVERT); + INT_ZERO(dic.di_forkoff, ARCH_CONVERT); + INT_ZERO(dic.di_aformat, ARCH_CONVERT); + INT_ZERO(dic.di_dmevmask, ARCH_CONVERT); + INT_ZERO(dic.di_dmstate, ARCH_CONVERT); + INT_ZERO(dic.di_flags, ARCH_CONVERT); + INT_ZERO(dic.di_gen, ARCH_CONVERT); + + for (i = 0; i < ninodes; i++) { + free = XFS_MAKE_IPTR(args.mp, fbuf, i); + bcopy (&dic, &(free->di_core), sizeof(xfs_dinode_core_t)); + INT_SET(free->di_next_unlinked, ARCH_CONVERT, NULLAGINO); + xfs_ialloc_log_di(tp, fbuf, i, + XFS_DI_CORE_BITS | XFS_DI_NEXT_UNLINKED); + } + xfs_trans_inode_alloc_buf(tp, fbuf); + } + INT_MOD(agi->agi_count, ARCH_CONVERT, newlen); + INT_MOD(agi->agi_freecount, ARCH_CONVERT, newlen); + mraccess(&args.mp->m_peraglock); + args.mp->m_perag[INT_GET(agi->agi_seqno, ARCH_CONVERT)].pagi_freecount += newlen; + mraccunlock(&args.mp->m_peraglock); + INT_SET(agi->agi_newino, ARCH_CONVERT, newino); + /* + * Insert records describing the new inode chunk into the btree. + */ + cur = xfs_btree_init_cursor(args.mp, tp, agbp, + INT_GET(agi->agi_seqno, ARCH_CONVERT), + XFS_BTNUM_INO, (xfs_inode_t *)0, 0); + for (thisino = newino; + thisino < newino + newlen; + thisino += XFS_INODES_PER_CHUNK) { + if ((error = xfs_inobt_lookup_eq(cur, thisino, + XFS_INODES_PER_CHUNK, XFS_INOBT_ALL_FREE, &i))) { + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; + } + ASSERT(i == 0); + if ((error = xfs_inobt_insert(cur, &i))) { + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; + } + ASSERT(i == 1); + } + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + /* + * Log allocation group header fields + */ + xfs_ialloc_log_agi(tp, agbp, + XFS_AGI_COUNT | XFS_AGI_FREECOUNT | XFS_AGI_NEWINO); + /* + * Modify/log superblock values for inode count and inode free count. + */ + xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, (long)newlen); + xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, (long)newlen); + *alloc = 1; + return 0; +} + +/* + * Select an allocation group to look for a free inode in, based on the parent + * inode and then mode. Return the allocation group buffer. + */ +STATIC xfs_buf_t * /* allocation group buffer */ +xfs_ialloc_ag_select( + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t parent, /* parent directory inode number */ + mode_t mode, /* bits set to indicate file type */ + int okalloc) /* ok to allocate more space */ +{ + xfs_buf_t *agbp; /* allocation group header buffer */ + xfs_agnumber_t agcount; /* number of ag's in the filesystem */ + xfs_agnumber_t agno; /* current ag number */ + int flags; /* alloc buffer locking flags */ + xfs_extlen_t ineed; /* blocks needed for inode allocation */ + xfs_extlen_t longest; /* longest extent available */ + xfs_mount_t *mp; /* mount point structure */ + int needspace; /* file mode implies space allocated */ + xfs_perag_t *pag; /* per allocation group data */ + xfs_agnumber_t pagno; /* parent (starting) ag number */ + + /* + * Files of these types need at least one block if length > 0 + * (and they won't fit in the inode, but that's hard to figure out). + */ + needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode); + mp = tp->t_mountp; + agcount = mp->m_sb.sb_agcount; + if (S_ISDIR(mode)) + pagno = atomicIncWithWrap((int *)&mp->m_agirotor, agcount); + else + pagno = XFS_INO_TO_AGNO(mp, parent); + ASSERT(pagno < agcount); + /* + * Loop through allocation groups, looking for one with a little + * free space in it. Note we don't look for free inodes, exactly. + * Instead, we include whether there is a need to allocate inodes + * to mean that blocks must be allocated for them, + * if none are currently free. + */ + agno = pagno; + flags = XFS_ALLOC_FLAG_TRYLOCK; + for (;;) { + mraccess(&mp->m_peraglock); + pag = &mp->m_perag[agno]; + if (!pag->pagi_init) { + if (xfs_ialloc_read_agi(mp, tp, agno, &agbp)) { + agbp = NULL; + mraccunlock(&mp->m_peraglock); + goto nextag; + } + } else + agbp = NULL; + /* + * Is there enough free space for the file plus a block + * of inodes (if we need to allocate some)? + */ + ineed = pag->pagi_freecount ? 0 : XFS_IALLOC_BLOCKS(mp); + if (ineed && !pag->pagf_init) { + if (agbp == NULL && + xfs_ialloc_read_agi(mp, tp, agno, &agbp)) { + agbp = NULL; + mraccunlock(&mp->m_peraglock); + goto nextag; + } + (void)xfs_alloc_pagf_init(mp, tp, agno, flags); + } + if (!ineed || pag->pagf_init) { + if (ineed && !(longest = pag->pagf_longest)) + longest = pag->pagf_flcount > 0; + if (!ineed || + (pag->pagf_freeblks >= needspace + ineed && + longest >= ineed && + okalloc)) { + if (agbp == NULL && + xfs_ialloc_read_agi(mp, tp, agno, &agbp)) { + agbp = NULL; + mraccunlock(&mp->m_peraglock); + goto nextag; + } + mraccunlock(&mp->m_peraglock); + return agbp; + } + } + mraccunlock(&mp->m_peraglock); + if (agbp) + xfs_trans_brelse(tp, agbp); +nextag: + /* + * No point in iterating over the rest, if we're shutting + * down. + */ + if (XFS_FORCED_SHUTDOWN(mp)) + return (xfs_buf_t *)0; + agno++; + if (agno == agcount) + agno = 0; + if (agno == pagno) { + if (flags == 0) + return (xfs_buf_t *)0; + flags = 0; + } + } +} + +/* + * Visible inode allocation functions. + */ + +/* + * Allocate an inode on disk. + * Mode is used to tell whether the new inode will need space, and whether + * it is a directory. + * + * The arguments IO_agbp and alloc_done are defined to work within + * the constraint of one allocation per transaction. + * xfs_dialloc() is designed to be called twice if it has to do an + * allocation to make more free inodes. On the first call, + * IO_agbp should be set to NULL. If an inode is available, + * i.e., xfs_dialloc() did not need to do an allocation, an inode + * number is returned. In this case, IO_agbp would be set to the + * current ag_buf and alloc_done set to false. + * If an allocation needed to be done, xfs_dialloc would return + * the current ag_buf in IO_agbp and set alloc_done to true. + * The caller should then commit the current transaction, allocate a new + * transaction, and call xfs_dialloc() again, passing in the previous + * value of IO_agbp. IO_agbp should be held across the transactions. + * Since the agbp is locked across the two calls, the second call is + * guaranteed to have a free inode available. + * + * Once we successfully pick an inode its number is returned and the + * on-disk data structures are updated. The inode itself is not read + * in, since doing so would break ordering constraints with xfs_reclaim. + */ +int +xfs_dialloc( + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t parent, /* parent inode (directory) */ + mode_t mode, /* mode bits for new inode */ + int okalloc, /* ok to allocate more space */ + xfs_buf_t **IO_agbp, /* in/out ag header's buffer */ + boolean_t *alloc_done, /* true if we needed to replenish + inode freelist */ + xfs_ino_t *inop) /* inode number allocated */ +{ + xfs_agnumber_t agcount; /* number of allocation groups */ + xfs_buf_t *agbp; /* allocation group header's buffer */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_agi_t *agi; /* allocation group header structure */ + xfs_btree_cur_t *cur; /* inode allocation btree cursor */ + int error; /* error return value */ + int i; /* result code */ + int ialloced; /* inode allocation status */ + int noroom = 0; /* no space for inode blk allocation */ + xfs_ino_t ino; /* fs-relative inode to be returned */ + /* REFERENCED */ + int j; /* result code */ + xfs_mount_t *mp; /* file system mount structure */ + int offset; /* index of inode in chunk */ + xfs_agino_t pagino; /* parent's a.g. relative inode # */ + xfs_agnumber_t pagno; /* parent's allocation group number */ + xfs_inobt_rec_t rec; /* inode allocation record */ + xfs_agnumber_t tagno; /* testing allocation group number */ + xfs_btree_cur_t *tcur; /* temp cursor */ + xfs_inobt_rec_t trec; /* temp inode allocation record */ + + + if (*IO_agbp == NULL) { + /* + * We do not have an agbp, so select an initial allocation + * group for inode allocation. + */ + agbp = xfs_ialloc_ag_select(tp, parent, mode, okalloc); + /* + * Couldn't find an allocation group satisfying the + * criteria, give up. + */ + if (!agbp) { + *inop = NULLFSINO; + return 0; + } + agi = XFS_BUF_TO_AGI(agbp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + } else { + /* + * Continue where we left off before. In this case, we + * know that the allocation group has free inodes. + */ + agbp = *IO_agbp; + agi = XFS_BUF_TO_AGI(agbp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + ASSERT(INT_GET(agi->agi_freecount, ARCH_CONVERT) > 0); + } + mp = tp->t_mountp; + agcount = mp->m_sb.sb_agcount; + agno = INT_GET(agi->agi_seqno, ARCH_CONVERT); + tagno = agno; + pagno = XFS_INO_TO_AGNO(mp, parent); + pagino = XFS_INO_TO_AGINO(mp, parent); + + /* + * If we have already hit the ceiling of inode blocks then clear + * okalloc so we scan all available agi structures for a free + * inode. + */ + + if (mp->m_maxicount && + mp->m_sb.sb_icount + XFS_IALLOC_INODES(mp) > mp->m_maxicount) { + noroom = 1; + okalloc = 0; + } + + /* + * Loop until we find an allocation group that either has free inodes + * or in which we can allocate some inodes. Iterate through the + * allocation groups upward, wrapping at the end. + */ + *alloc_done = B_FALSE; + while (INT_GET(agi->agi_freecount, ARCH_CONVERT) == 0) { + /* + * Don't do anything if we're not supposed to allocate + * any blocks, just go on to the next ag. + */ + if (okalloc) { + /* + * Try to allocate some new inodes in the allocation + * group. + */ + if ((error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced))) { + xfs_trans_brelse(tp, agbp); + if (error == ENOSPC) { + *inop = NULLFSINO; + return 0; + } else + return error; + } + if (ialloced) { + /* + * We successfully allocated some inodes, return + * the current context to the caller so that it + * can commit the current transaction and call + * us again where we left off. + */ + ASSERT(INT_GET(agi->agi_freecount, ARCH_CONVERT) > 0); + *alloc_done = B_TRUE; + *IO_agbp = agbp; + *inop = NULLFSINO; + return 0; + } + } + /* + * If it failed, give up on this ag. + */ + xfs_trans_brelse(tp, agbp); + /* + * Go on to the next ag: get its ag header. + */ +nextag: + if (++tagno == agcount) + tagno = 0; + if (tagno == agno) { + *inop = NULLFSINO; + return noroom ? ENOSPC : 0; + } + mraccess(&mp->m_peraglock); + error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp); + mraccunlock(&mp->m_peraglock); + if (error) + goto nextag; + agi = XFS_BUF_TO_AGI(agbp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + } + /* + * Here with an allocation group that has a free inode. + * Reset agno since we may have chosen a new ag in the + * loop above. + */ + agno = tagno; + *IO_agbp = NULL; + cur = xfs_btree_init_cursor(mp, tp, agbp, INT_GET(agi->agi_seqno, ARCH_CONVERT), + XFS_BTNUM_INO, (xfs_inode_t *)0, 0); + /* + * If pagino is 0 (this is the root inode allocation) use newino. + * This must work because we've just allocated some. + */ + if (!pagino) + pagino = INT_GET(agi->agi_newino, ARCH_CONVERT); +#ifdef DEBUG + if (cur->bc_nlevels == 1) { + int freecount = 0; + + if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + do { + if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + freecount += rec.ir_freecount; + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error0; + } while (i == 1); + + ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) || + XFS_FORCED_SHUTDOWN(mp)); + } +#endif + /* + * If in the same a.g. as the parent, try to get near the parent. + */ + if (pagno == agno) { + if ((error = xfs_inobt_lookup_le(cur, pagino, 0, 0, &i))) + goto error0; + if (i != 0 && + (error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &j, ARCH_NOCONVERT)) == 0 && + j == 1 && + rec.ir_freecount > 0) { + /* + * Found a free inode in the same chunk + * as parent, done. + */ + } + /* + * In the same a.g. as parent, but parent's chunk is full. + */ + else { + int doneleft; /* done, to the left */ + int doneright; /* done, to the right */ + + if (error) + goto error0; + ASSERT(i == 1); + ASSERT(j == 1); + /* + * Duplicate the cursor, search left & right + * simultaneously. + */ + if ((error = xfs_btree_dup_cursor(cur, &tcur))) + goto error0; + /* + * Search left with tcur, back up 1 record. + */ + if ((error = xfs_inobt_decrement(tcur, 0, &i))) + goto error1; + doneleft = !i; + if (!doneleft) { + if ((error = xfs_inobt_get_rec(tcur, + &trec.ir_startino, + &trec.ir_freecount, + &trec.ir_free, &i, ARCH_NOCONVERT))) + goto error1; + XFS_WANT_CORRUPTED_GOTO(i == 1, error1); + } + /* + * Search right with cur, go forward 1 record. + */ + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error1; + doneright = !i; + if (!doneright) { + if ((error = xfs_inobt_get_rec(cur, + &rec.ir_startino, + &rec.ir_freecount, + &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error1; + XFS_WANT_CORRUPTED_GOTO(i == 1, error1); + } + /* + * Loop until we find the closest inode chunk + * with a free one. + */ + while (!doneleft || !doneright) { + int useleft; /* using left inode + chunk this time */ + + /* + * Figure out which block is closer, + * if both are valid. + */ + if (!doneleft && !doneright) + useleft = + pagino - + (trec.ir_startino + + XFS_INODES_PER_CHUNK - 1) < + rec.ir_startino - pagino; + else + useleft = !doneleft; + /* + * If checking the left, does it have + * free inodes? + */ + if (useleft && trec.ir_freecount) { + /* + * Yes, set it up as the chunk to use. + */ + rec = trec; + xfs_btree_del_cursor(cur, + XFS_BTREE_NOERROR); + cur = tcur; + break; + } + /* + * If checking the right, does it have + * free inodes? + */ + if (!useleft && rec.ir_freecount) { + /* + * Yes, it's already set up. + */ + xfs_btree_del_cursor(tcur, + XFS_BTREE_NOERROR); + break; + } + /* + * If used the left, get another one + * further left. + */ + if (useleft) { + if ((error = xfs_inobt_decrement(tcur, 0, + &i))) + goto error1; + doneleft = !i; + if (!doneleft) { + if ((error = xfs_inobt_get_rec( + tcur, + &trec.ir_startino, + &trec.ir_freecount, + &trec.ir_free, &i, ARCH_NOCONVERT))) + goto error1; + XFS_WANT_CORRUPTED_GOTO(i == 1, + error1); + } + } + /* + * If used the right, get another one + * further right. + */ + else { + if ((error = xfs_inobt_increment(cur, 0, + &i))) + goto error1; + doneright = !i; + if (!doneright) { + if ((error = xfs_inobt_get_rec( + cur, + &rec.ir_startino, + &rec.ir_freecount, + &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error1; + XFS_WANT_CORRUPTED_GOTO(i == 1, + error1); + } + } + } + ASSERT(!doneleft || !doneright); + } + } + /* + * In a different a.g. from the parent. + * See if the most recently allocated block has any free. + */ + else if (INT_GET(agi->agi_newino, ARCH_CONVERT) != NULLAGINO) { + if ((error = xfs_inobt_lookup_eq(cur, + INT_GET(agi->agi_newino, ARCH_CONVERT), 0, 0, &i))) + goto error0; + if (i == 1 && + (error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &j, ARCH_NOCONVERT)) == 0 && + j == 1 && + rec.ir_freecount > 0) { + /* + * The last chunk allocated in the group still has + * a free inode. + */ + } + /* + * None left in the last group, search the whole a.g. + */ + else { + if (error) + goto error0; + if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) + goto error0; + ASSERT(i == 1); + for (;;) { + if ((error = xfs_inobt_get_rec(cur, + &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, + &i, ARCH_NOCONVERT))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (rec.ir_freecount > 0) + break; + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + } + } + offset = XFS_IALLOC_FIND_FREE(&rec.ir_free); + ASSERT(offset >= 0); + ASSERT(offset < XFS_INODES_PER_CHUNK); + ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) % + XFS_INODES_PER_CHUNK) == 0); + ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset); + XFS_INOBT_CLR_FREE(&rec, offset, ARCH_NOCONVERT); + rec.ir_freecount--; + if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount, + rec.ir_free))) + goto error0; + INT_MOD(agi->agi_freecount, ARCH_CONVERT, -1); + xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); + mraccess(&mp->m_peraglock); + mp->m_perag[tagno].pagi_freecount--; + mraccunlock(&mp->m_peraglock); +#ifdef DEBUG + if (cur->bc_nlevels == 1) { + int freecount = 0; + + if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) + goto error0; + do { + if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + freecount += rec.ir_freecount; + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error0; + } while (i == 1); + ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) || + XFS_FORCED_SHUTDOWN(mp)); + } +#endif + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1); + *inop = ino; + return 0; +error1: + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); +error0: + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; +} + + +/* + * Return the location of the inode in bno/off, for mapping it into a buffer. + */ +/*ARGSUSED*/ +int +xfs_dilocate( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t ino, /* inode to locate */ + xfs_fsblock_t *bno, /* output: block containing inode */ + int *len, /* output: num blocks in inode cluster */ + int *off, /* output: index in block of inode */ + uint flags) /* flags concerning inode lookup */ +{ + xfs_agblock_t agbno; /* block number of inode in the alloc group */ + xfs_buf_t *agbp; /* agi buffer */ + xfs_agino_t agino; /* inode number within alloc group */ + xfs_agnumber_t agno; /* allocation group number */ + int blks_per_cluster; /* num blocks per inode cluster */ + xfs_agblock_t chunk_agbno; /* first block in inode chunk */ + xfs_agino_t chunk_agino; /* first agino in inode chunk */ + __int32_t chunk_cnt; /* count of free inodes in chunk */ + xfs_inofree_t chunk_free; /* mask of free inodes in chunk */ + xfs_agblock_t cluster_agbno; /* first block in inode cluster */ + xfs_btree_cur_t *cur; /* inode btree cursor */ + int error; /* error code */ + int i; /* temp state */ + int offset; /* index of inode in its buffer */ + int offset_agbno; /* blks from chunk start to inode */ + + ASSERT(ino != NULLFSINO); + /* + * Split up the inode number into its parts. + */ + agno = XFS_INO_TO_AGNO(mp, ino); + agino = XFS_INO_TO_AGINO(mp, ino); + agbno = XFS_AGINO_TO_AGBNO(mp, agino); + if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || + ino != XFS_AGINO_TO_INO(mp, agno, agino)) + return XFS_ERROR(EINVAL); + if ((mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) || + !(flags & XFS_IMAP_LOOKUP)) { + offset = XFS_INO_TO_OFFSET(mp, ino); + ASSERT(offset < mp->m_sb.sb_inopblock); + *bno = XFS_AGB_TO_FSB(mp, agno, agbno); + *off = offset; + *len = 1; + return 0; + } + blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog; + if (*bno != NULLFSBLOCK) { + offset = XFS_INO_TO_OFFSET(mp, ino); + ASSERT(offset < mp->m_sb.sb_inopblock); + cluster_agbno = XFS_FSB_TO_AGBNO(mp, *bno); + *off = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + + offset; + *len = blks_per_cluster; + return 0; + } + if (mp->m_inoalign_mask) { + offset_agbno = agbno & mp->m_inoalign_mask; + chunk_agbno = agbno - offset_agbno; + } else { + mraccess(&mp->m_peraglock); + error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); + mraccunlock(&mp->m_peraglock); + if (error) + return error; + cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO, + (xfs_inode_t *)0, 0); + if ((error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i))) + goto error0; + if ((error = xfs_inobt_get_rec(cur, &chunk_agino, &chunk_cnt, + &chunk_free, &i, ARCH_NOCONVERT))) + goto error0; + if (i == 0) + error = XFS_ERROR(EINVAL); + xfs_trans_brelse(tp, agbp); + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + if (error) + return error; + chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_agino); + offset_agbno = agbno - chunk_agbno; + } + ASSERT(agbno >= chunk_agbno); + cluster_agbno = chunk_agbno + + ((offset_agbno / blks_per_cluster) * blks_per_cluster); + offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + + XFS_INO_TO_OFFSET(mp, ino); + *bno = XFS_AGB_TO_FSB(mp, agno, cluster_agbno); + *off = offset; + *len = blks_per_cluster; + return 0; +error0: + xfs_trans_brelse(tp, agbp); + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Compute and fill in value of m_in_maxlevels. + */ +void +xfs_ialloc_compute_maxlevels( + xfs_mount_t *mp) /* file system mount structure */ +{ + int level; + uint maxblocks; + uint maxleafents; + int minleafrecs; + int minnoderecs; + + maxleafents = (1LL << XFS_INO_AGINO_BITS(mp)) >> + XFS_INODES_PER_CHUNK_LOG; + minleafrecs = mp->m_alloc_mnr[0]; + minnoderecs = mp->m_alloc_mnr[1]; + maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; + for (level = 1; maxblocks > 1; level++) + maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; + mp->m_in_maxlevels = level; +} + +/* + * Log specified fields for the ag hdr (inode section) + */ +void +xfs_ialloc_log_agi( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *bp, /* allocation group header buffer */ + int fields) /* bitmask of fields to log */ +{ + int first; /* first byte number */ + int last; /* last byte number */ + static const short offsets[] = { /* field starting offsets */ + /* keep in sync with bit definitions */ + offsetof(xfs_agi_t, agi_magicnum), + offsetof(xfs_agi_t, agi_versionnum), + offsetof(xfs_agi_t, agi_seqno), + offsetof(xfs_agi_t, agi_length), + offsetof(xfs_agi_t, agi_count), + offsetof(xfs_agi_t, agi_root), + offsetof(xfs_agi_t, agi_level), + offsetof(xfs_agi_t, agi_freecount), + offsetof(xfs_agi_t, agi_newino), + offsetof(xfs_agi_t, agi_dirino), + offsetof(xfs_agi_t, agi_unlinked), + sizeof(xfs_agi_t) + }; +#ifdef DEBUG + xfs_agi_t *agi; /* allocation group header */ + + agi = XFS_BUF_TO_AGI(bp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == + XFS_AGI_MAGIC); +#endif + /* + * Compute byte offsets for the first and last fields. + */ + xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS, &first, &last); + /* + * Log the allocation group inode header buffer. + */ + xfs_trans_log_buf(tp, bp, first, last); +} + +/* + * Read in the allocation group header (inode allocation section) + */ +int +xfs_ialloc_read_agi( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_buf_t **bpp) /* allocation group hdr buf */ +{ + xfs_agi_t *agi; /* allocation group header */ + int agi_ok; /* agi is consistent */ + xfs_buf_t *bp; /* allocation group hdr buf */ + xfs_daddr_t d; /* disk block address */ + int error; +#ifdef DEBUG + int i; +#endif + xfs_perag_t *pag; /* per allocation group data */ + + + ASSERT(agno != NULLAGNUMBER); + d = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, 1, 0, &bp))) + return error; + ASSERT(bp && !XFS_BUF_GETERROR(bp)); + /* + * Validate the magic number of the agi block. + */ + agi = XFS_BUF_TO_AGI(bp); + agi_ok = + INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC && + XFS_AGI_GOOD_VERSION(INT_GET(agi->agi_versionnum, ARCH_CONVERT)); + if (XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IALLOC_READ_AGI, + XFS_RANDOM_IALLOC_READ_AGI)) { + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EFSCORRUPTED); + } + pag = &mp->m_perag[agno]; + if (!pag->pagi_init) { + pag->pagi_freecount = INT_GET(agi->agi_freecount, ARCH_CONVERT); + pag->pagi_init = 1; + } else { + /* + * It's possible for these to be out of sync if + * we are in the middle of a forced shutdown. + */ + ASSERT(pag->pagi_freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) + || XFS_FORCED_SHUTDOWN(mp)); + } +#ifdef DEBUG + for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) + ASSERT(INT_GET(agi->agi_unlinked[i], ARCH_CONVERT) != 0); +#endif + XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGI, XFS_AGI_REF); + *bpp = bp; + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_ialloc_btree.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_ialloc_btree.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_ialloc_btree.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_ialloc_btree.c Thu Apr 12 18:30:32 2001 @@ -0,0 +1,1552 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Inode allocation management for XFS. + */ +#include + +/* + * Insert one record/level. Return information to the caller + * allowing the next level up to proceed if necessary. + */ +STATIC int /* error */ +xfs_inobt_insrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to insert record at */ + xfs_agblock_t *bnop, /* i/o: block number inserted */ + xfs_inobt_rec_t *recp, /* i/o: record data inserted */ + xfs_btree_cur_t **curp, /* output: new cursor replacing cur */ + int *stat) /* success/failure */ +{ + xfs_inobt_block_t *block; /* btree block record/key lives in */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ + int i; /* loop index */ + xfs_inobt_key_t key; /* key value being inserted */ + xfs_inobt_key_t *kp=NULL; /* pointer to btree keys */ + xfs_agblock_t nbno; /* block number of allocated block */ + xfs_btree_cur_t *ncur; /* new cursor to be used at next lvl */ + xfs_inobt_key_t nkey; /* new key value, from split */ + xfs_inobt_rec_t nrec; /* new record value, for caller */ + int optr; /* old ptr value */ + xfs_inobt_ptr_t *pp; /* pointer to btree addresses */ + int ptr; /* index in btree block for this rec */ + xfs_inobt_rec_t *rp=NULL; /* pointer to btree records */ + + /* + * If we made it to the root level, allocate a new root block + * and we're done. + */ + if (level >= cur->bc_nlevels) { + error = xfs_inobt_newroot(cur, &i); + *bnop = NULLAGBLOCK; + *stat = i; + return error; + } + /* + * Make a key out of the record data to be inserted, and save it. + */ + key.ir_startino = recp->ir_startino; /* INT_: direct copy */ + optr = ptr = cur->bc_ptrs[level]; + /* + * If we're off the left edge, return failure. + */ + if (ptr == 0) { + *stat = 0; + return 0; + } + /* + * Get pointers to the btree buffer and block. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; + /* + * Check that the new entry is being inserted in the right place. + */ + if (ptr <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + if (level == 0) { + rp = XFS_INOBT_REC_ADDR(block, ptr, cur); + xfs_btree_check_rec(cur->bc_btnum, recp, rp); + } else { + kp = XFS_INOBT_KEY_ADDR(block, ptr, cur); + xfs_btree_check_key(cur->bc_btnum, &key, kp); + } + } +#endif + nbno = NULLAGBLOCK; + ncur = (xfs_btree_cur_t *)0; + /* + * If the block is full, we can't insert the new entry until we + * make the block un-full. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) == XFS_INOBT_BLOCK_MAXRECS(level, cur)) { + /* + * First, try shifting an entry to the right neighbor. + */ + if ((error = xfs_inobt_rshift(cur, level, &i))) + return error; + if (i) { + /* nothing */ + } + /* + * Next, try shifting an entry to the left neighbor. + */ + else { + if ((error = xfs_inobt_lshift(cur, level, &i))) + return error; + if (i) { + optr = ptr = cur->bc_ptrs[level]; + } else { + /* + * Next, try splitting the current block + * in half. If this works we have to + * re-set our variables because + * we could be in a different block now. + */ + if ((error = xfs_inobt_split(cur, level, &nbno, + &nkey, &ncur, &i))) + return error; + if (i) { + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, + block, level, bp))) + return error; +#endif + ptr = cur->bc_ptrs[level]; + nrec.ir_startino = nkey.ir_startino; /* INT_: direct copy */ + } else { + /* + * Otherwise the insert fails. + */ + *stat = 0; + return 0; + } + } + } + } + /* + * At this point we know there's room for our new entry in the block + * we're pointing at. + */ + if (level > 0) { + /* + * It's a non-leaf entry. Make a hole for the new data + * in the key and ptr regions of the block. + */ + kp = XFS_INOBT_KEY_ADDR(block, 1, cur); + pp = XFS_INOBT_PTR_ADDR(block, 1, cur); +#ifdef DEBUG + for (i = INT_GET(block->bb_numrecs, ARCH_CONVERT); i >= ptr; i--) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(pp[i - 1], ARCH_CONVERT), level))) + return error; + } +#endif + ovbcopy(&kp[ptr - 1], &kp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*kp)); + ovbcopy(&pp[ptr - 1], &pp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*pp)); + /* + * Now stuff the new data in, bump numrecs and log the new data. + */ +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, *bnop, level))) + return error; +#endif + kp[ptr - 1] = key; /* INT_: struct copy */ + INT_SET(pp[ptr - 1], ARCH_CONVERT, *bnop); + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_inobt_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + xfs_inobt_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + } else { + /* + * It's a leaf entry. Make a hole for the new record. + */ + rp = XFS_INOBT_REC_ADDR(block, 1, cur); + ovbcopy(&rp[ptr - 1], &rp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*rp)); + /* + * Now stuff the new record in, bump numrecs + * and log the new data. + */ + rp[ptr - 1] = *recp; /* INT_: struct copy */ + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_inobt_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + } + /* + * Log the new number of records in the btree header. + */ + xfs_inobt_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS); +#ifdef DEBUG + /* + * Check that the key/record is in the right place, now. + */ + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + if (level == 0) + xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1, + rp + ptr); + else + xfs_btree_check_key(cur->bc_btnum, kp + ptr - 1, + kp + ptr); + } +#endif + /* + * If we inserted at the start of a block, update the parents' keys. + */ + if (optr == 1 && (error = xfs_inobt_updkey(cur, &key, level + 1))) + return error; + /* + * Return the new block number, if any. + * If there is one, give back a record value and a cursor too. + */ + *bnop = nbno; + if (nbno != NULLAGBLOCK) { + *recp = nrec; /* INT_: struct copy */ + *curp = ncur; + } + *stat = 1; + return 0; +} + +/* + * Log header fields from a btree block. + */ +STATIC void +xfs_inobt_log_block( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *bp, /* buffer containing btree block */ + int fields) /* mask of fields: XFS_BB_... */ +{ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + static const short offsets[] = { /* table of offsets */ + offsetof(xfs_inobt_block_t, bb_magic), + offsetof(xfs_inobt_block_t, bb_level), + offsetof(xfs_inobt_block_t, bb_numrecs), + offsetof(xfs_inobt_block_t, bb_leftsib), + offsetof(xfs_inobt_block_t, bb_rightsib), + sizeof(xfs_inobt_block_t) + }; + + xfs_btree_offsets(fields, offsets, XFS_BB_NUM_BITS, &first, &last); + xfs_trans_log_buf(tp, bp, first, last); +} + +/* + * Log keys from a btree block (nonleaf). + */ +STATIC void +xfs_inobt_log_keys( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int kfirst, /* index of first key to log */ + int klast) /* index of last key to log */ +{ + xfs_inobt_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + xfs_inobt_key_t *kp; /* key pointer in btree block */ + int last; /* last byte offset logged */ + + block = XFS_BUF_TO_INOBT_BLOCK(bp); + kp = XFS_INOBT_KEY_ADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&kp[kfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&kp[klast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Log block pointer fields from a btree block (nonleaf). + */ +STATIC void +xfs_inobt_log_ptrs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int pfirst, /* index of first pointer to log */ + int plast) /* index of last pointer to log */ +{ + xfs_inobt_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + xfs_inobt_ptr_t *pp; /* block-pointer pointer in btree blk */ + + block = XFS_BUF_TO_INOBT_BLOCK(bp); + pp = XFS_INOBT_PTR_ADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&pp[pfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&pp[plast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Log records from a btree block (leaf). + */ +STATIC void +xfs_inobt_log_recs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int rfirst, /* index of first record to log */ + int rlast) /* index of last record to log */ +{ + xfs_inobt_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + xfs_inobt_rec_t *rp; /* record pointer for btree block */ + + block = XFS_BUF_TO_INOBT_BLOCK(bp); + rp = XFS_INOBT_REC_ADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&rp[rfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&rp[rlast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Lookup the record. The cursor is made to point to it, based on dir. + * Return 0 if can't find any such record, 1 for success. + */ +STATIC int /* error */ +xfs_inobt_lookup( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_lookup_t dir, /* <=, ==, or >= */ + int *stat) /* success/failure */ +{ + xfs_agblock_t agbno; /* a.g. relative btree block number */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_inobt_block_t *block=NULL; /* current btree block */ + int diff; /* difference for the current key */ + int error; /* error return value */ + int keyno=0; /* current key number */ + int level; /* level in the btree */ + xfs_mount_t *mp; /* file system mount point */ + + /* + * Get the allocation group header, and the root block number. + */ + mp = cur->bc_mp; + { + xfs_agi_t *agi; /* a.g. inode header */ + + agi = XFS_BUF_TO_AGI(cur->bc_private.i.agbp); + agno = INT_GET(agi->agi_seqno, ARCH_CONVERT); + agbno = INT_GET(agi->agi_root, ARCH_CONVERT); + } + /* + * Iterate over each level in the btree, starting at the root. + * For each level above the leaves, find the key we need, based + * on the lookup record, then follow the corresponding block + * pointer down to the next level. + */ + for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) { + xfs_buf_t *bp; /* buffer pointer for btree block */ + xfs_daddr_t d; /* disk address of btree block */ + + /* + * Get the disk address we're looking for. + */ + d = XFS_AGB_TO_DADDR(mp, agno, agbno); + /* + * If the old buffer at this level is for a different block, + * throw it away, otherwise just use it. + */ + bp = cur->bc_bufs[level]; + if (bp && XFS_BUF_ADDR(bp) != d) + bp = (xfs_buf_t *)0; + if (!bp) { + /* + * Need to get a new buffer. Read it, then + * set it in the cursor, releasing the old one. + */ + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + agno, agbno, 0, &bp, XFS_INO_BTREE_REF))) + return error; + xfs_btree_setbuf(cur, level, bp); + /* + * Point to the btree block, now that we have the buffer + */ + block = XFS_BUF_TO_INOBT_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, level, + bp))) + return error; + } else + block = XFS_BUF_TO_INOBT_BLOCK(bp); + /* + * If we already had a key match at a higher level, we know + * we need to use the first entry in this block. + */ + if (diff == 0) + keyno = 1; + /* + * Otherwise we need to search this block. Do a binary search. + */ + else { + int high; /* high entry number */ + xfs_inobt_key_t *kkbase=NULL;/* base of keys in block */ + xfs_inobt_rec_t *krbase=NULL;/* base of records in block */ + int low; /* low entry number */ + + /* + * Get a pointer to keys or records. + */ + if (level > 0) + kkbase = XFS_INOBT_KEY_ADDR(block, 1, cur); + else + krbase = XFS_INOBT_REC_ADDR(block, 1, cur); + /* + * Set low and high entry numbers, 1-based. + */ + low = 1; + if (!(high = INT_GET(block->bb_numrecs, ARCH_CONVERT))) { + /* + * If the block is empty, the tree must + * be an empty leaf. + */ + ASSERT(level == 0 && cur->bc_nlevels == 1); + cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE; + *stat = 0; + return 0; + } + /* + * Binary search the block. + */ + while (low <= high) { + xfs_agino_t startino; /* key value */ + + /* + * keyno is average of low and high. + */ + keyno = (low + high) >> 1; + /* + * Get startino. + */ + if (level > 0) { + xfs_inobt_key_t *kkp; + + kkp = kkbase + keyno - 1; + startino = INT_GET(kkp->ir_startino, ARCH_CONVERT); + } else { + xfs_inobt_rec_t *krp; + + krp = krbase + keyno - 1; + startino = INT_GET(krp->ir_startino, ARCH_CONVERT); + } + /* + * Compute difference to get next direction. + */ + diff = (int)startino - cur->bc_rec.i.ir_startino; + /* + * Less than, move right. + */ + if (diff < 0) + low = keyno + 1; + /* + * Greater than, move left. + */ + else if (diff > 0) + high = keyno - 1; + /* + * Equal, we're done. + */ + else + break; + } + } + /* + * If there are more levels, set up for the next level + * by getting the block number and filling in the cursor. + */ + if (level > 0) { + /* + * If we moved left, need the previous key number, + * unless there isn't one. + */ + if (diff > 0 && --keyno < 1) + keyno = 1; + agbno = INT_GET(*XFS_INOBT_PTR_ADDR(block, keyno, cur), ARCH_CONVERT); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, agbno, level))) + return error; +#endif + cur->bc_ptrs[level] = keyno; + } + } + /* + * Done with the search. + * See if we need to adjust the results. + */ + if (dir != XFS_LOOKUP_LE && diff < 0) { + keyno++; + /* + * If ge search and we went off the end of the block, but it's + * not the last block, we're in the wrong block. + */ + if (dir == XFS_LOOKUP_GE && + keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT) && + INT_GET(block->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + int i; + + cur->bc_ptrs[0] = keyno; + if ((error = xfs_inobt_increment(cur, 0, &i))) + return error; + ASSERT(i == 1); + *stat = 1; + return 0; + } + } + else if (dir == XFS_LOOKUP_LE && diff > 0) + keyno--; + cur->bc_ptrs[0] = keyno; + /* + * Return if we succeeded or not. + */ + if (keyno == 0 || keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT)) + *stat = 0; + else + *stat = ((dir != XFS_LOOKUP_EQ) || (diff == 0)); + return 0; +} + +/* + * Move 1 record left from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_inobt_lshift( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to shift record on */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef DEBUG + int i; /* loop index */ +#endif + xfs_inobt_key_t key; /* key value for leaf level upward */ + xfs_buf_t *lbp; /* buffer for left neighbor block */ + xfs_inobt_block_t *left; /* left neighbor btree block */ + xfs_inobt_key_t *lkp=NULL; /* key pointer for left block */ + xfs_inobt_ptr_t *lpp; /* address pointer for left block */ + xfs_inobt_rec_t *lrp=NULL; /* record pointer for left block */ + int nrec; /* new number of left block entries */ + xfs_buf_t *rbp; /* buffer for right (current) block */ + xfs_inobt_block_t *right; /* right (current) btree block */ + xfs_inobt_key_t *rkp=NULL; /* key pointer for right block */ + xfs_inobt_ptr_t *rpp=NULL; /* address pointer for right block */ + xfs_inobt_rec_t *rrp=NULL; /* record pointer for right block */ + + /* + * Set up variables for this block as "right". + */ + rbp = cur->bc_bufs[level]; + right = XFS_BUF_TO_INOBT_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + return error; +#endif + /* + * If we've got no left sibling then we can't shift an entry left. + */ + if (INT_GET(right->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * If the cursor entry is the one that would be moved, don't + * do it... it's too complicated. + */ + if (cur->bc_ptrs[level] <= 1) { + *stat = 0; + return 0; + } + /* + * Set up the left neighbor as "left". + */ + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, INT_GET(right->bb_leftsib, ARCH_CONVERT), 0, &lbp, + XFS_INO_BTREE_REF))) + return error; + left = XFS_BUF_TO_INOBT_BLOCK(lbp); + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; + /* + * If it's full, it can't take another entry. + */ + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) == XFS_INOBT_BLOCK_MAXRECS(level, cur)) { + *stat = 0; + return 0; + } + nrec = INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1; + /* + * If non-leaf, copy a key and a ptr to the left block. + */ + if (level > 0) { + lkp = XFS_INOBT_KEY_ADDR(left, nrec, cur); + rkp = XFS_INOBT_KEY_ADDR(right, 1, cur); + *lkp = *rkp; + xfs_inobt_log_keys(cur, lbp, nrec, nrec); + lpp = XFS_INOBT_PTR_ADDR(left, nrec, cur); + rpp = XFS_INOBT_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, INT_GET(*rpp, ARCH_CONVERT), level))) + return error; +#endif + *lpp = *rpp; /* INT_: no-change copy */ + xfs_inobt_log_ptrs(cur, lbp, nrec, nrec); + } + /* + * If leaf, copy a record to the left block. + */ + else { + lrp = XFS_INOBT_REC_ADDR(left, nrec, cur); + rrp = XFS_INOBT_REC_ADDR(right, 1, cur); + *lrp = *rrp; + xfs_inobt_log_recs(cur, lbp, nrec, nrec); + } + /* + * Bump and log left's numrecs, decrement and log right's numrecs. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, +1); + xfs_inobt_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); +#ifdef DEBUG + if (level > 0) + xfs_btree_check_key(cur->bc_btnum, lkp - 1, lkp); + else + xfs_btree_check_rec(cur->bc_btnum, lrp - 1, lrp); +#endif + INT_MOD(right->bb_numrecs, ARCH_CONVERT, -1); + xfs_inobt_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); + /* + * Slide the contents of right down one entry. + */ + if (level > 0) { +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i + 1], ARCH_CONVERT), + level))) + return error; + } +#endif + ovbcopy(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); + xfs_inobt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_inobt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } else { + ovbcopy(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_inobt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + key.ir_startino = rrp->ir_startino; /* INT_: direct copy */ + rkp = &key; + } + /* + * Update the parent key values of right. + */ + if ((error = xfs_inobt_updkey(cur, rkp, level + 1))) + return error; + /* + * Slide the cursor value left one. + */ + cur->bc_ptrs[level]--; + *stat = 1; + return 0; +} + +/* + * Allocate a new root block, fill it in. + */ +STATIC int /* error */ +xfs_inobt_newroot( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + xfs_agi_t *agi; /* a.g. inode header */ + xfs_alloc_arg_t args; /* allocation argument structure */ + xfs_inobt_block_t *block; /* one half of the old root block */ + xfs_buf_t *bp; /* buffer containing block */ + int error; /* error return value */ + xfs_inobt_key_t *kp; /* btree key pointer */ + xfs_agblock_t lbno; /* left block number */ + xfs_buf_t *lbp; /* left buffer pointer */ + xfs_inobt_block_t *left; /* left btree block */ + xfs_buf_t *nbp; /* new (root) buffer */ + xfs_inobt_block_t *new; /* new (root) btree block */ + int nptr; /* new value for key index, 1 or 2 */ + xfs_inobt_ptr_t *pp; /* btree address pointer */ + xfs_agblock_t rbno; /* right block number */ + xfs_buf_t *rbp; /* right buffer pointer */ + xfs_inobt_block_t *right; /* right btree block */ + xfs_inobt_rec_t *rp; /* btree record pointer */ + + ASSERT(cur->bc_nlevels < XFS_IN_MAXLEVELS(cur->bc_mp)); + + /* + * Get a block & a buffer. + */ + agi = XFS_BUF_TO_AGI(cur->bc_private.i.agbp); + args.tp = cur->bc_tp; + args.mp = cur->bc_mp; + args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.i.agno, + INT_GET(agi->agi_root, ARCH_CONVERT)); + args.mod = args.minleft = args.alignment = args.total = args.wasdel = + args.isfl = args.userdata = args.minalignslop = 0; + args.minlen = args.maxlen = args.prod = 1; + args.type = XFS_ALLOCTYPE_NEAR_BNO; + if ((error = xfs_alloc_vextent(&args))) + return error; + /* + * None available, we fail. + */ + if (args.fsbno == NULLFSBLOCK) { + *stat = 0; + return 0; + } + ASSERT(args.len == 1); + nbp = xfs_btree_get_bufs(args.mp, args.tp, args.agno, args.agbno, 0); + new = XFS_BUF_TO_INOBT_BLOCK(nbp); + /* + * Set the root data in the a.g. inode structure. + */ + INT_SET(agi->agi_root, ARCH_CONVERT, args.agbno); + INT_MOD(agi->agi_level, ARCH_CONVERT, 1); + xfs_ialloc_log_agi(args.tp, cur->bc_private.i.agbp, + XFS_AGI_ROOT | XFS_AGI_LEVEL); + /* + * At the previous root level there are now two blocks: the old + * root, and the new block generated when it was split. + * We don't know which one the cursor is pointing at, so we + * set up variables "left" and "right" for each case. + */ + bp = cur->bc_bufs[cur->bc_nlevels - 1]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, cur->bc_nlevels - 1, bp))) + return error; +#endif + if (INT_GET(block->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + /* + * Our block is left, pick up the right block. + */ + lbp = bp; + lbno = XFS_DADDR_TO_AGBNO(args.mp, XFS_BUF_ADDR(lbp)); + left = block; + rbno = INT_GET(left->bb_rightsib, ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(args.mp, args.tp, args.agno, + rbno, 0, &rbp, XFS_INO_BTREE_REF))) + return error; + bp = rbp; + right = XFS_BUF_TO_INOBT_BLOCK(rbp); + if ((error = xfs_btree_check_sblock(cur, right, + cur->bc_nlevels - 1, rbp))) + return error; + nptr = 1; + } else { + /* + * Our block is right, pick up the left block. + */ + rbp = bp; + rbno = XFS_DADDR_TO_AGBNO(args.mp, XFS_BUF_ADDR(rbp)); + right = block; + lbno = INT_GET(right->bb_leftsib, ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(args.mp, args.tp, args.agno, + lbno, 0, &lbp, XFS_INO_BTREE_REF))) + return error; + bp = lbp; + left = XFS_BUF_TO_INOBT_BLOCK(lbp); + if ((error = xfs_btree_check_sblock(cur, left, + cur->bc_nlevels - 1, lbp))) + return error; + nptr = 2; + } + /* + * Fill in the new block's btree header and log it. + */ + INT_SET(new->bb_magic, ARCH_CONVERT, xfs_magics[cur->bc_btnum]); + INT_SET(new->bb_level, ARCH_CONVERT, (__uint16_t)cur->bc_nlevels); + INT_SET(new->bb_numrecs, ARCH_CONVERT, 2); + INT_SET(new->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(new->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + xfs_inobt_log_block(args.tp, nbp, XFS_BB_ALL_BITS); + ASSERT(lbno != NULLAGBLOCK && rbno != NULLAGBLOCK); + /* + * Fill in the key data in the new root. + */ + kp = XFS_INOBT_KEY_ADDR(new, 1, cur); + if (INT_GET(left->bb_level, ARCH_CONVERT) > 0) { + kp[0] = *XFS_INOBT_KEY_ADDR(left, 1, cur); /* INT_: struct copy */ + kp[1] = *XFS_INOBT_KEY_ADDR(right, 1, cur); /* INT_: struct copy */ + } else { + rp = XFS_INOBT_REC_ADDR(left, 1, cur); + INT_COPY(kp[0].ir_startino, rp->ir_startino, ARCH_CONVERT); + rp = XFS_INOBT_REC_ADDR(right, 1, cur); + INT_COPY(kp[1].ir_startino, rp->ir_startino, ARCH_CONVERT); + } + xfs_inobt_log_keys(cur, nbp, 1, 2); + /* + * Fill in the pointer data in the new root. + */ + pp = XFS_INOBT_PTR_ADDR(new, 1, cur); + INT_SET(pp[0], ARCH_CONVERT, lbno); + INT_SET(pp[1], ARCH_CONVERT, rbno); + xfs_inobt_log_ptrs(cur, nbp, 1, 2); + /* + * Fix up the cursor. + */ + xfs_btree_setbuf(cur, cur->bc_nlevels, nbp); + cur->bc_ptrs[cur->bc_nlevels] = nptr; + cur->bc_nlevels++; + *stat = 1; + return 0; +} + +/* + * Move 1 record right from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_inobt_rshift( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to shift record on */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* loop index */ + xfs_inobt_key_t key; /* key value for leaf level upward */ + xfs_buf_t *lbp; /* buffer for left (current) block */ + xfs_inobt_block_t *left; /* left (current) btree block */ + xfs_inobt_key_t *lkp; /* key pointer for left block */ + xfs_inobt_ptr_t *lpp; /* address pointer for left block */ + xfs_inobt_rec_t *lrp; /* record pointer for left block */ + xfs_buf_t *rbp; /* buffer for right neighbor block */ + xfs_inobt_block_t *right; /* right neighbor btree block */ + xfs_inobt_key_t *rkp; /* key pointer for right block */ + xfs_inobt_ptr_t *rpp; /* address pointer for right block */ + xfs_inobt_rec_t *rrp=NULL; /* record pointer for right block */ + xfs_btree_cur_t *tcur; /* temporary cursor */ + + /* + * Set up variables for this block as "left". + */ + lbp = cur->bc_bufs[level]; + left = XFS_BUF_TO_INOBT_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; +#endif + /* + * If we've got no right sibling then we can't shift an entry right. + */ + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * If the cursor entry is the one that would be moved, don't + * do it... it's too complicated. + */ + if (cur->bc_ptrs[level] >= INT_GET(left->bb_numrecs, ARCH_CONVERT)) { + *stat = 0; + return 0; + } + /* + * Set up the right neighbor as "right". + */ + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, &rbp, + XFS_INO_BTREE_REF))) + return error; + right = XFS_BUF_TO_INOBT_BLOCK(rbp); + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + return error; + /* + * If it's full, it can't take another entry. + */ + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) == XFS_INOBT_BLOCK_MAXRECS(level, cur)) { + *stat = 0; + return 0; + } + /* + * Make a hole at the start of the right neighbor block, then + * copy the last left block entry to the hole. + */ + if (level > 0) { + lkp = XFS_INOBT_KEY_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + lpp = XFS_INOBT_PTR_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rkp = XFS_INOBT_KEY_ADDR(right, 1, cur); + rpp = XFS_INOBT_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1; i >= 0; i--) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + ovbcopy(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, INT_GET(*lpp, ARCH_CONVERT), level))) + return error; +#endif + *rkp = *lkp; /* INT_: no change copy */ + *rpp = *lpp; /* INT_: no change copy */ + xfs_inobt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + xfs_inobt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + } else { + lrp = XFS_INOBT_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rrp = XFS_INOBT_REC_ADDR(right, 1, cur); + ovbcopy(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + *rrp = *lrp; + xfs_inobt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + key.ir_startino = rrp->ir_startino; /* INT_: direct copy */ + rkp = &key; + } + /* + * Decrement and log left's numrecs, bump and log right's numrecs. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -1); + xfs_inobt_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); +#ifdef DEBUG + if (level > 0) + xfs_btree_check_key(cur->bc_btnum, rkp, rkp + 1); + else + xfs_btree_check_rec(cur->bc_btnum, rrp, rrp + 1); +#endif + xfs_inobt_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); + /* + * Using a temporary cursor, update the parent key values of the + * block on the right. + */ + if ((error = xfs_btree_dup_cursor(cur, &tcur))) + return error; + xfs_btree_lastrec(tcur, level); + if ((error = xfs_inobt_increment(tcur, level, &i)) || + (error = xfs_inobt_updkey(tcur, rkp, level + 1))) { + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; + } + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + *stat = 1; + return 0; +} + +/* + * Split cur/level block in half. + * Return new block number and its first record (to be inserted into parent). + */ +STATIC int /* error */ +xfs_inobt_split( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to split */ + xfs_agblock_t *bnop, /* output: block number allocated */ + xfs_inobt_key_t *keyp, /* output: first key of new block */ + xfs_btree_cur_t **curp, /* output: new cursor */ + int *stat) /* success/failure */ +{ + xfs_alloc_arg_t args; /* allocation argument structure */ + int error; /* error return value */ + int i; /* loop index/record number */ + xfs_agblock_t lbno; /* left (current) block number */ + xfs_buf_t *lbp; /* buffer for left block */ + xfs_inobt_block_t *left; /* left (current) btree block */ + xfs_inobt_key_t *lkp; /* left btree key pointer */ + xfs_inobt_ptr_t *lpp; /* left btree address pointer */ + xfs_inobt_rec_t *lrp; /* left btree record pointer */ + xfs_buf_t *rbp; /* buffer for right block */ + xfs_inobt_block_t *right; /* right (new) btree block */ + xfs_inobt_key_t *rkp; /* right btree key pointer */ + xfs_inobt_ptr_t *rpp; /* right btree address pointer */ + xfs_inobt_rec_t *rrp; /* right btree record pointer */ + + /* + * Set up left block (current one). + */ + lbp = cur->bc_bufs[level]; + args.tp = cur->bc_tp; + args.mp = cur->bc_mp; + lbno = XFS_DADDR_TO_AGBNO(args.mp, XFS_BUF_ADDR(lbp)); + /* + * Allocate the new block. + * If we can't do it, we're toast. Give up. + */ + args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.i.agno, lbno); + args.mod = args.minleft = args.alignment = args.total = args.wasdel = + args.isfl = args.userdata = args.minalignslop = 0; + args.minlen = args.maxlen = args.prod = 1; + args.type = XFS_ALLOCTYPE_NEAR_BNO; + if ((error = xfs_alloc_vextent(&args))) + return error; + if (args.fsbno == NULLFSBLOCK) { + *stat = 0; + return 0; + } + ASSERT(args.len == 1); + rbp = xfs_btree_get_bufs(args.mp, args.tp, args.agno, args.agbno, 0); + /* + * Set up the new block as "right". + */ + right = XFS_BUF_TO_INOBT_BLOCK(rbp); + /* + * "Left" is the current (according to the cursor) block. + */ + left = XFS_BUF_TO_INOBT_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; +#endif + /* + * Fill in the btree header for the new block. + */ + INT_SET(right->bb_magic, ARCH_CONVERT, xfs_magics[cur->bc_btnum]); + right->bb_level = left->bb_level; /* INT_: direct copy */ + INT_SET(right->bb_numrecs, ARCH_CONVERT, (__uint16_t)(INT_GET(left->bb_numrecs, ARCH_CONVERT) / 2)); + /* + * Make sure that if there's an odd number of entries now, that + * each new block will have the same number of entries. + */ + if ((INT_GET(left->bb_numrecs, ARCH_CONVERT) & 1) && + cur->bc_ptrs[level] <= INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1) + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); + i = INT_GET(left->bb_numrecs, ARCH_CONVERT) - INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1; + /* + * For non-leaf blocks, copy keys and addresses over to the new block. + */ + if (level > 0) { + lkp = XFS_INOBT_KEY_ADDR(left, i, cur); + lpp = XFS_INOBT_PTR_ADDR(left, i, cur); + rkp = XFS_INOBT_KEY_ADDR(right, 1, cur); + rpp = XFS_INOBT_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(lpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + bcopy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + bcopy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); + xfs_inobt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_inobt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + *keyp = *rkp; + } + /* + * For leaf blocks, copy records over to the new block. + */ + else { + lrp = XFS_INOBT_REC_ADDR(left, i, cur); + rrp = XFS_INOBT_REC_ADDR(right, 1, cur); + bcopy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_inobt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + keyp->ir_startino = rrp->ir_startino; /* INT_: direct copy */ + } + /* + * Find the left block number by looking in the buffer. + * Adjust numrecs, sibling pointers. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -(INT_GET(right->bb_numrecs, ARCH_CONVERT))); + right->bb_rightsib = left->bb_rightsib; /* INT_: direct copy */ + INT_SET(left->bb_rightsib, ARCH_CONVERT, args.agbno); + INT_SET(right->bb_leftsib, ARCH_CONVERT, lbno); + xfs_inobt_log_block(args.tp, rbp, XFS_BB_ALL_BITS); + xfs_inobt_log_block(args.tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); + /* + * If there's a block to the new block's right, make that block + * point back to right instead of to left. + */ + if (INT_GET(right->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_inobt_block_t *rrblock; /* rr btree block */ + xfs_buf_t *rrbp; /* buffer for rrblock */ + + if ((error = xfs_btree_read_bufs(args.mp, args.tp, args.agno, + INT_GET(right->bb_rightsib, ARCH_CONVERT), 0, &rrbp, + XFS_INO_BTREE_REF))) + return error; + rrblock = XFS_BUF_TO_INOBT_BLOCK(rrbp); + if ((error = xfs_btree_check_sblock(cur, rrblock, level, rrbp))) + return error; + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, args.agbno); + xfs_inobt_log_block(args.tp, rrbp, XFS_BB_LEFTSIB); + } + /* + * If the cursor is really in the right block, move it there. + * If it's just pointing past the last entry in left, then we'll + * insert there, so don't change anything in that case. + */ + if (cur->bc_ptrs[level] > INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1) { + xfs_btree_setbuf(cur, level, rbp); + cur->bc_ptrs[level] -= INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + /* + * If there are more levels, we'll need another cursor which refers + * the right block, no matter where this cursor was. + */ + if (level + 1 < cur->bc_nlevels) { + if ((error = xfs_btree_dup_cursor(cur, curp))) + return error; + (*curp)->bc_ptrs[level + 1]++; + } + *bnop = args.agbno; + *stat = 1; + return 0; +} + +/* + * Update keys at all levels from here to the root along the cursor's path. + */ +STATIC int /* error */ +xfs_inobt_updkey( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_inobt_key_t *keyp, /* new key value to update to */ + int level) /* starting level for update */ +{ + int ptr; /* index of key in block */ + + /* + * Go up the tree from this level toward the root. + * At each level, update the key value to the value input. + * Stop when we reach a level where the cursor isn't pointing + * at the first entry in the block. + */ + for (ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) { + xfs_buf_t *bp; /* buffer for block */ + xfs_inobt_block_t *block; /* btree block */ +#ifdef DEBUG + int error; /* error return value */ +#endif + xfs_inobt_key_t *kp; /* ptr to btree block keys */ + + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; +#endif + ptr = cur->bc_ptrs[level]; + kp = XFS_INOBT_KEY_ADDR(block, ptr, cur); + *kp = *keyp; + xfs_inobt_log_keys(cur, bp, ptr, ptr); + } + return 0; +} + +/* + * Externally visible routines. + */ + +/* + * Decrement cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_inobt_decrement( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat) /* success/failure */ +{ + xfs_inobt_block_t *block; /* btree block */ + int error; + int lev; /* btree level */ + + ASSERT(level < cur->bc_nlevels); + /* + * Read-ahead to the left at this level. + */ + xfs_btree_readahead(cur, level, XFS_BTCUR_LEFTRA); + /* + * Decrement the ptr at this level. If we're still in the block + * then we're done. + */ + if (--cur->bc_ptrs[level] > 0) { + *stat = 1; + return 0; + } + /* + * Get a pointer to the btree block. + */ + block = XFS_BUF_TO_INOBT_BLOCK(cur->bc_bufs[level]); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, + cur->bc_bufs[level]))) + return error; +#endif + /* + * If we just went off the left edge of the tree, return failure. + */ + if (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * March up the tree decrementing pointers. + * Stop when we don't go off the left edge of a block. + */ + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + if (--cur->bc_ptrs[lev] > 0) + break; + /* + * Read-ahead the left block, we're going to read it + * in the next loop. + */ + xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA); + } + /* + * If we went off the root then we are seriously confused. + */ + ASSERT(lev < cur->bc_nlevels); + /* + * Now walk back down the tree, fixing up the cursor's buffer + * pointers and key numbers. + */ + for (block = XFS_BUF_TO_INOBT_BLOCK(cur->bc_bufs[lev]); lev > level; ) { + xfs_agblock_t agbno; /* block number of btree block */ + xfs_buf_t *bp; /* buffer containing btree block */ + + agbno = INT_GET(*XFS_INOBT_PTR_ADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, agbno, 0, &bp, + XFS_INO_BTREE_REF))) + return error; + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_INOBT_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; + cur->bc_ptrs[lev] = INT_GET(block->bb_numrecs, ARCH_CONVERT); + } + *stat = 1; + return 0; +} + +/* + * Get the data from the pointed-to record. + */ +int /* error */ +xfs_inobt_get_rec( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agino_t *ino, /* output: starting inode of chunk */ + __int32_t *fcnt, /* output: number of free inodes */ + xfs_inofree_t *free, /* output: free inode mask */ + int *stat, /* output: success/failure */ + xfs_arch_t arch) /* input: architecture */ +{ + xfs_inobt_block_t *block; /* btree block */ + xfs_buf_t *bp; /* buffer containing btree block */ +#ifdef DEBUG + int error; /* error return value */ +#endif + int ptr; /* record number */ + xfs_inobt_rec_t *rec; /* record data */ + + bp = cur->bc_bufs[0]; + ptr = cur->bc_ptrs[0]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, 0, bp))) + return error; +#endif + /* + * Off the right end or left end, return failure. + */ + if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT) || ptr <= 0) { + *stat = 0; + return 0; + } + /* + * Point to the record and extract its data. + */ + rec = XFS_INOBT_REC_ADDR(block, ptr, cur); + ASSERT(arch == ARCH_NOCONVERT || arch == ARCH_CONVERT); + if (arch == ARCH_NOCONVERT) { + *ino = INT_GET(rec->ir_startino, ARCH_CONVERT); + *fcnt = INT_GET(rec->ir_freecount, ARCH_CONVERT); + *free = INT_GET(rec->ir_free, ARCH_CONVERT); + } else { + INT_COPY(*ino, rec->ir_startino, ARCH_CONVERT); + INT_COPY(*fcnt, rec->ir_freecount, ARCH_CONVERT); + INT_COPY(*free, rec->ir_free, ARCH_CONVERT); + } + *stat = 1; + return 0; +} + +/* + * Increment cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_inobt_increment( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat) /* success/failure */ +{ + xfs_inobt_block_t *block; /* btree block */ + xfs_buf_t *bp; /* buffer containing btree block */ + int error; /* error return value */ + int lev; /* btree level */ + + ASSERT(level < cur->bc_nlevels); + /* + * Read-ahead to the right at this level. + */ + xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); + /* + * Get a pointer to the btree block. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; +#endif + /* + * Increment the ptr at this level. If we're still in the block + * then we're done. + */ + if (++cur->bc_ptrs[level] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + *stat = 1; + return 0; + } + /* + * If we just went off the right edge of the tree, return failure. + */ + if (INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * March up the tree incrementing pointers. + * Stop when we don't go off the right edge of a block. + */ + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + bp = cur->bc_bufs[lev]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; +#endif + if (++cur->bc_ptrs[lev] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) + break; + /* + * Read-ahead the right block, we're going to read it + * in the next loop. + */ + xfs_btree_readahead(cur, lev, XFS_BTCUR_RIGHTRA); + } + /* + * If we went off the root then we are seriously confused. + */ + ASSERT(lev < cur->bc_nlevels); + /* + * Now walk back down the tree, fixing up the cursor's buffer + * pointers and key numbers. + */ + for (bp = cur->bc_bufs[lev], block = XFS_BUF_TO_INOBT_BLOCK(bp); + lev > level; ) { + xfs_agblock_t agbno; /* block number of btree block */ + + agbno = INT_GET(*XFS_INOBT_PTR_ADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, agbno, 0, &bp, + XFS_INO_BTREE_REF))) + return error; + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_INOBT_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; + cur->bc_ptrs[lev] = 1; + } + *stat = 1; + return 0; +} + +/* + * Insert the current record at the point referenced by cur. + * The cursor may be inconsistent on return if splits have been done. + */ +int /* error */ +xfs_inobt_insert( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* result value, 0 for failure */ + int level; /* current level number in btree */ + xfs_agblock_t nbno; /* new block number (split result) */ + xfs_btree_cur_t *ncur; /* new cursor (split result) */ + xfs_inobt_rec_t nrec; /* record being inserted this level */ + xfs_btree_cur_t *pcur; /* previous level's cursor */ + + level = 0; + nbno = NULLAGBLOCK; + INT_SET(nrec.ir_startino, ARCH_CONVERT, cur->bc_rec.i.ir_startino); + INT_SET(nrec.ir_freecount, ARCH_CONVERT, cur->bc_rec.i.ir_freecount); + INT_SET(nrec.ir_free, ARCH_CONVERT, cur->bc_rec.i.ir_free); + ncur = (xfs_btree_cur_t *)0; + pcur = cur; + /* + * Loop going up the tree, starting at the leaf level. + * Stop when we don't get a split block, that must mean that + * the insert is finished with this level. + */ + do { + /* + * Insert nrec/nbno into this level of the tree. + * Note if we fail, nbno will be null. + */ + if ((error = xfs_inobt_insrec(pcur, level++, &nbno, &nrec, &ncur, + &i))) { + if (pcur != cur) + xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); + return error; + } + /* + * See if the cursor we just used is trash. + * Can't trash the caller's cursor, but otherwise we should + * if ncur is a new cursor or we're about to be done. + */ + if (pcur != cur && (ncur || nbno == NULLAGBLOCK)) { + cur->bc_nlevels = pcur->bc_nlevels; + xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); + } + /* + * If we got a new cursor, switch to it. + */ + if (ncur) { + pcur = ncur; + ncur = (xfs_btree_cur_t *)0; + } + } while (nbno != NULLAGBLOCK); + *stat = i; + return 0; +} + +/* + * Lookup the record equal to ino in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_eq( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat) /* success/failure */ +{ + cur->bc_rec.i.ir_startino = ino; + cur->bc_rec.i.ir_freecount = fcnt; + cur->bc_rec.i.ir_free = free; + return xfs_inobt_lookup(cur, XFS_LOOKUP_EQ, stat); +} + +/* + * Lookup the first record greater than or equal to ino + * in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_ge( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat) /* success/failure */ +{ + cur->bc_rec.i.ir_startino = ino; + cur->bc_rec.i.ir_freecount = fcnt; + cur->bc_rec.i.ir_free = free; + return xfs_inobt_lookup(cur, XFS_LOOKUP_GE, stat); +} + +/* + * Lookup the first record less than or equal to ino + * in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_le( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat) /* success/failure */ +{ + cur->bc_rec.i.ir_startino = ino; + cur->bc_rec.i.ir_freecount = fcnt; + cur->bc_rec.i.ir_free = free; + return xfs_inobt_lookup(cur, XFS_LOOKUP_LE, stat); +} + +/* + * Update the record referred to by cur, to the value given + * by [ino, fcnt, free]. + * This either works (return 0) or gets an EFSCORRUPTED error. + */ +int /* error */ +xfs_inobt_update( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free) /* free inode mask */ +{ + xfs_inobt_block_t *block; /* btree block to update */ + xfs_buf_t *bp; /* buffer containing btree block */ + int error; /* error return value */ + int ptr; /* current record number (updating) */ + xfs_inobt_rec_t *rp; /* pointer to updated record */ + + /* + * Pick up the current block. + */ + bp = cur->bc_bufs[0]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, 0, bp))) + return error; +#endif + /* + * Get the address of the rec to be updated. + */ + ptr = cur->bc_ptrs[0]; + rp = XFS_INOBT_REC_ADDR(block, ptr, cur); + /* + * Fill in the new contents and log them. + */ + INT_SET(rp->ir_startino, ARCH_CONVERT, ino); + INT_SET(rp->ir_freecount, ARCH_CONVERT, fcnt); + INT_SET(rp->ir_free, ARCH_CONVERT, free); + xfs_inobt_log_recs(cur, bp, ptr, ptr); + /* + * Updating first record in leaf. Pass new key value up to our parent. + */ + if (ptr == 1) { + xfs_inobt_key_t key; /* key containing [ino] */ + + INT_SET(key.ir_startino, ARCH_CONVERT, ino); + if ((error = xfs_inobt_updkey(cur, &key, 1))) + return error; + } + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_inode.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_inode.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_inode.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_inode.c Mon Apr 16 17:53:46 2001 @@ -0,0 +1,1382 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +xfs_zone_t *xfs_ifork_zone; +xfs_zone_t *xfs_inode_zone; + +#ifdef DEBUG +void +xfs_inobp_check( + xfs_mount_t *mp, + xfs_buf_t *bp) +{ + int i; + int j; + xfs_dinode_t *dip; + + j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog; + + for (i = 0; i < j; i++) { + dip = (xfs_dinode_t *)xfs_buf_offset(bp, + i * mp->m_sb.sb_inodesize); + if (INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT)) { + xfs_fs_cmn_err(CE_ALERT, mp, + "Detected a bogus zero next_unlinked field in incore inode buffer 0x%p. About to pop an ASSERT.", + bp); + ASSERT(!INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT)); + } + } +} +#endif + + +/* + * This routine is called to map an inode to the buffer containing + * the on-disk version of the inode. It returns a pointer to the + * buffer containing the on-disk inode in the bpp parameter, and in + * the dip parameter it returns a pointer to the on-disk inode within + * that buffer. + * + * If a non-zero error is returned, then the contents of bpp and + * dipp are undefined. + * + * If the inode is new and has not yet been initialized, use xfs_imap() + * to determine the size and location of the buffer to read from disk. + * If the inode has already been mapped to its buffer and read in once, + * then use the mapping information stored in the inode rather than + * calling xfs_imap(). This allows us to avoid the overhead of looking + * at the inode btree for small block file systems (see xfs_dilocate()). + * We can tell whether the inode has been mapped in before by comparing + * its disk block address to 0. Only uninitialized inodes will have + * 0 for the disk block address. + */ +int +xfs_itobp( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_inode_t *ip, + xfs_dinode_t **dipp, + xfs_buf_t **bpp, + xfs_daddr_t bno) +{ + xfs_buf_t *bp; + int error; + xfs_imap_t imap; +#ifdef __KERNEL__ + int i; + int ni; +#endif + + if (ip->i_blkno == (xfs_daddr_t)0) { + /* + * Call the space management code to find the location of the + * inode on disk. + */ + imap.im_blkno = bno; + error = xfs_imap(mp, tp, ip->i_ino, &imap, XFS_IMAP_LOOKUP); + if (error != 0) { + return error; + } + + /* + * If the inode number maps to a block outside the bounds + * of the file system then return NULL rather than calling + * read_buf and panicing when we get an error from the + * driver. + */ + if ((imap.im_blkno + imap.im_len) > + XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) { + return XFS_ERROR(EINVAL); + } + + /* + * Fill in the fields in the inode that will be used to + * map the inode to its buffer from now on. + */ + ip->i_blkno = imap.im_blkno; + ip->i_len = imap.im_len; + ip->i_boffset = imap.im_boffset; + } else { + /* + * We've already mapped the inode once, so just use the + * mapping that we saved the first time. + */ + imap.im_blkno = ip->i_blkno; + imap.im_len = ip->i_len; + imap.im_boffset = ip->i_boffset; + } + ASSERT(bno == 0 || bno == imap.im_blkno); + + /* + * Read in the buffer. If tp is NULL, xfs_trans_read_buf() will + * default to just a read_buf() call. + */ + error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno, + (int)imap.im_len, XFS_BUF_LOCK, &bp); + + if (error) { + return error; + } +#ifdef __KERNEL__ + /* + * Validate the magic number and version of every inode in the buffer + * (if DEBUG kernel) or the first inode in the buffer, otherwise. + */ +#ifdef DEBUG + ni = BBTOB(imap.im_len) >> mp->m_sb.sb_inodelog; +#else + ni = 1; +#endif + for (i = 0; i < ni; i++) { + int di_ok; + xfs_dinode_t *dip; + + dip = (xfs_dinode_t *)xfs_buf_offset(bp, + (i << mp->m_sb.sb_inodelog)); + di_ok = INT_GET(dip->di_core.di_magic, ARCH_CONVERT) == XFS_DINODE_MAGIC && + XFS_DINODE_GOOD_VERSION(INT_GET(dip->di_core.di_version, ARCH_CONVERT)); + if (XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP, + XFS_RANDOM_ITOBP_INOTOBP)) { +#ifdef DEBUG + prdev("bad inode magic/vsn daddr 0x%Lx #%d (magic=%x)", + mp->m_dev, imap.im_blkno, i, + INT_GET(dip->di_core.di_magic, ARCH_CONVERT)); +#endif + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EFSCORRUPTED); + } + } +#endif /* __KERNEL__ */ + + xfs_inobp_check(mp, bp); + + /* + * Mark the buffer as an inode buffer now that it looks good + */ + XFS_BUF_SET_VTYPE(bp, B_FS_INO); + + /* + * Set *dipp to point to the on-disk inode in the buffer. + */ + *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset); + *bpp = bp; + return 0; +} + +/* + * Move inode type and inode format specific information from the + * on-disk inode to the in-core inode. For fifos, devs, and sockets + * this means set if_rdev to the proper value. For files, directories, + * and symlinks this means to bring in the in-line data or extent + * pointers. For a file in B-tree format, only the root is immediately + * brought in-core. The rest will be in-lined in if_extents when it + * is first referenced (see xfs_iread_extents()). + */ +STATIC int +xfs_iformat( + xfs_inode_t *ip, + xfs_dinode_t *dip, + int alloc_mode) +{ + xfs_attr_shortform_t *atp; + int size; + int error; + xfs_fsize_t di_size; + ip->i_df.if_ext_max = + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + error = 0; + + if (INT_GET(dip->di_core.di_nextents, ARCH_CONVERT) + + INT_GET(dip->di_core.di_anextents, ARCH_CONVERT) > + INT_GET(dip->di_core.di_nblocks, ARCH_CONVERT)) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt dinode %Lu, extent total = %d, nblocks = %Ld. Unmount and run xfs_repair.", + ip->i_ino, + (int)(INT_GET(dip->di_core.di_nextents, ARCH_CONVERT) + INT_GET(dip->di_core.di_anextents, ARCH_CONVERT)), + INT_GET(dip->di_core.di_nblocks, ARCH_CONVERT)); + return XFS_ERROR(EFSCORRUPTED); + } + + if (INT_GET(dip->di_core.di_forkoff, ARCH_CONVERT) > ip->i_mount->m_sb.sb_inodesize) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt dinode %Lu, forkoff = 0x%x. Unmount and run xfs_repair.", + ip->i_ino, (int)(INT_GET(dip->di_core.di_forkoff, ARCH_CONVERT))); + return XFS_ERROR(EFSCORRUPTED); + } + + switch (ip->i_d.di_mode & IFMT) { + case IFIFO: + case IFCHR: + case IFBLK: + case IFSOCK: + if (INT_GET(dip->di_core.di_format, ARCH_CONVERT) != XFS_DINODE_FMT_DEV) + return XFS_ERROR(EFSCORRUPTED); + ip->i_d.di_size = 0; + ip->i_df.if_u2.if_rdev = INT_GET(dip->di_u.di_dev, ARCH_CONVERT); + break; + + case IFREG: + case IFLNK: + case IFDIR: + switch (INT_GET(dip->di_core.di_format, ARCH_CONVERT)) { + case XFS_DINODE_FMT_LOCAL: + /* + * no local regular files yet + */ + if ((INT_GET(dip->di_core.di_mode, ARCH_CONVERT) & IFMT) == IFREG) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt inode (local format for regular file) %Lu. Unmount and run xfs_repair.", + ip->i_ino); + return XFS_ERROR(EFSCORRUPTED); + } + + di_size=INT_GET(dip->di_core.di_size, ARCH_CONVERT); + if (di_size > + XFS_DFORK_DSIZE_ARCH(dip, ip->i_mount, ARCH_CONVERT)) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt inode %Lu (bad size %Ld for local inode). Unmount and run xfs_repair.", + ip->i_ino, di_size); + return XFS_ERROR(EFSCORRUPTED); + } + + size = (int)di_size; + error = xfs_iformat_local(ip, dip, XFS_DATA_FORK, + size, alloc_mode); + break; + case XFS_DINODE_FMT_EXTENTS: + error = xfs_iformat_extents(ip, dip, XFS_DATA_FORK, + alloc_mode); + break; + case XFS_DINODE_FMT_BTREE: + error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK, + alloc_mode); + break; + default: + return XFS_ERROR(EFSCORRUPTED); + } + break; + + default: + return XFS_ERROR(EFSCORRUPTED); + } + if (error) { + return error; + } + if (!XFS_DFORK_Q_ARCH(dip, ARCH_CONVERT)) + return 0; + ASSERT(ip->i_afp == NULL); + ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, alloc_mode); + ip->i_afp->if_ext_max = + XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + switch (INT_GET(dip->di_core.di_aformat, ARCH_CONVERT)) { + case XFS_DINODE_FMT_LOCAL: + atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT); + size = (int)INT_GET(atp->hdr.totsize, ARCH_CONVERT); + error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size, + alloc_mode); + break; + case XFS_DINODE_FMT_EXTENTS: + error = xfs_iformat_extents(ip, dip, XFS_ATTR_FORK, + alloc_mode); + break; + case XFS_DINODE_FMT_BTREE: + error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK, + alloc_mode); + break; + default: + error = XFS_ERROR(EFSCORRUPTED); + break; + } + if (error) { + kmem_zone_free(xfs_ifork_zone, ip->i_afp); + ip->i_afp = NULL; + xfs_idestroy_fork(ip, XFS_DATA_FORK); + } + return error; +} + +/* + * The file is in-lined in the on-disk inode. + * If it fits into if_inline_data, then copy + * it there, otherwise allocate a buffer for it + * and copy the data there. Either way, set + * if_data to point at the data. + * If we allocate a buffer for the data, make + * sure that its size is a multiple of 4 and + * record the real size in i_real_bytes. + */ +STATIC int +xfs_iformat_local( + xfs_inode_t *ip, + xfs_dinode_t *dip, + int whichfork, + int size, + int alloc_mode) +{ + xfs_ifork_t *ifp; + int real_size; + + /* + * If the size is unreasonable, then something + * is wrong and we just bail out rather than crash in + * kmem_alloc() or bcopy() below. + */ + if (size > XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT)) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt inode %Lu (bad size %d for local fork, size = %d). Unmount and run xfs_repair.", + ip->i_ino, size, + XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT)); + return XFS_ERROR(EFSCORRUPTED); + } + ifp = XFS_IFORK_PTR(ip, whichfork); + real_size = 0; + if (size == 0) + ifp->if_u1.if_data = NULL; + else if (size <= sizeof(ifp->if_u2.if_inline_data)) + ifp->if_u1.if_data = ifp->if_u2.if_inline_data; + else { + real_size = roundup(size, 4); + ifp->if_u1.if_data = kmem_alloc(real_size, alloc_mode); + } + ifp->if_bytes = size; + ifp->if_real_bytes = real_size; + if (size) + bcopy(XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), ifp->if_u1.if_data, size); + ifp->if_flags &= ~XFS_IFEXTENTS; + ifp->if_flags |= XFS_IFINLINE; + return 0; +} + +/* + * The file consists of a set of extents all + * of which fit into the on-disk inode. + * If there are few enough extents to fit into + * the if_inline_ext, then copy them there. + * Otherwise allocate a buffer for them and copy + * them into it. Either way, set if_extents + * to point at the extents. + */ +STATIC int +xfs_iformat_extents( + xfs_inode_t *ip, + xfs_dinode_t *dip, + int whichfork, + int alloc_mode) +{ + xfs_ifork_t *ifp; + int nex; + int real_size; + int size; + + ifp = XFS_IFORK_PTR(ip, whichfork); + nex = XFS_DFORK_NEXTENTS_ARCH(dip, whichfork, ARCH_CONVERT); + size = nex * (uint)sizeof(xfs_bmbt_rec_t); + + /* + * If the number of extents is unreasonable, then something + * is wrong and we just bail out rather than crash in + * kmem_alloc() or bcopy() below. + */ + if (size < 0 || size > XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT)) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt inode %Lu ((a)extents = %d). Unmount and run xfs_repair.", + ip->i_ino, nex); + return XFS_ERROR(EFSCORRUPTED); + } + + real_size = 0; + if (nex == 0) + ifp->if_u1.if_extents = NULL; + else if (nex <= XFS_INLINE_EXTS) + ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; + else { + ifp->if_u1.if_extents = kmem_alloc(size, alloc_mode); + ASSERT(ifp->if_u1.if_extents != NULL); + real_size = size; + } + ifp->if_bytes = size; + ifp->if_real_bytes = real_size; + if (size) { + xfs_validate_extents( + (xfs_bmbt_rec_32_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), + nex, XFS_EXTFMT_INODE(ip)); + bcopy(XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), ifp->if_u1.if_extents, + size); + xfs_bmap_trace_exlist("xfs_iformat_extents", ip, nex, + whichfork); + if (whichfork != XFS_DATA_FORK || + XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE) + if (xfs_check_nostate_extents( + ifp->if_u1.if_extents, nex)) + return XFS_ERROR(EFSCORRUPTED); + } + ifp->if_flags |= XFS_IFEXTENTS; + return 0; +} + +/* + * The file has too many extents to fit into + * the inode, so they are in B-tree format. + * Allocate a buffer for the root of the B-tree + * and copy the root into it. The i_extents + * field will remain NULL until all of the + * extents are read in (when they are needed). + */ +STATIC int +xfs_iformat_btree( + xfs_inode_t *ip, + xfs_dinode_t *dip, + int whichfork, + int alloc_mode) +{ + xfs_bmdr_block_t *dfp; + xfs_ifork_t *ifp; + /* REFERENCED */ + int nrecs; + int size; + + ifp = XFS_IFORK_PTR(ip, whichfork); + dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT); + size = XFS_BMAP_BROOT_SPACE(dfp); + nrecs = XFS_BMAP_BROOT_NUMRECS(dfp); + + /* + * blow out if -- fork has less extents than can fit in + * fork (fork shouldn't be a btree format), root btree + * block has more records than can fit into the fork, + * or the number of extents is greater than the number of + * blocks. + */ + if (XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max + || XFS_BMDR_SPACE_CALC(nrecs) > + XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT) + || XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt inode %Lu (btree). Unmount and run xfs_repair.", + ip->i_ino); + return XFS_ERROR(EFSCORRUPTED); + } + + ifp->if_broot_bytes = size; + ifp->if_broot = kmem_alloc(size, alloc_mode); + ASSERT(ifp->if_broot != NULL); + /* + * Copy and convert from the on-disk structure + * to the in-memory structure. + */ + xfs_bmdr_to_bmbt(dfp, XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT), + ifp->if_broot, size); + ifp->if_flags &= ~XFS_IFEXTENTS; + ifp->if_flags |= XFS_IFBROOT; + + return 0; +} + +/* + * xfs_xlate_dinode_core - translate an xfs_inode_core_t between ondisk + * and native format + * + * buf = on-disk representation + * dip = native representation + * dir = direction - +ve -> disk to native + * -ve -> native to disk + * arch = on-disk architecture + */ + +void +xfs_xlate_dinode_core(xfs_caddr_t buf, xfs_dinode_core_t *dip, + int dir, xfs_arch_t arch) +{ + xfs_dinode_core_t *buf_core; + xfs_dinode_core_t *mem_core; + + ASSERT(dir); + + buf_core=(xfs_dinode_core_t*)buf; + mem_core=(xfs_dinode_core_t*)dip; + + if (arch == ARCH_NOCONVERT) { + if (dir>0) { + bcopy((xfs_caddr_t)buf_core, (xfs_caddr_t)mem_core, sizeof(xfs_dinode_core_t)); + } else { + bcopy((xfs_caddr_t)mem_core, (xfs_caddr_t)buf_core, sizeof(xfs_dinode_core_t)); + } + return; + } + + INT_XLATE(buf_core->di_magic, mem_core->di_magic, dir, arch); + INT_XLATE(buf_core->di_mode, mem_core->di_mode, dir, arch); + INT_XLATE(buf_core->di_version, mem_core->di_version, dir, arch); + INT_XLATE(buf_core->di_format, mem_core->di_format, dir, arch); + INT_XLATE(buf_core->di_onlink, mem_core->di_onlink, dir, arch); + INT_XLATE(buf_core->di_uid, mem_core->di_uid, dir, arch); + INT_XLATE(buf_core->di_gid, mem_core->di_gid, dir, arch); + INT_XLATE(buf_core->di_nlink, mem_core->di_nlink, dir, arch); + INT_XLATE(buf_core->di_projid, mem_core->di_projid, dir, arch); + + if (dir>0) { + bcopy(buf_core->di_pad, mem_core->di_pad, sizeof(buf_core->di_pad)); + } else { + bcopy(mem_core->di_pad, buf_core->di_pad, sizeof(buf_core->di_pad)); + } + + INT_XLATE(buf_core->di_atime.t_sec, mem_core->di_atime.t_sec, dir, arch); + INT_XLATE(buf_core->di_atime.t_nsec,mem_core->di_atime.t_nsec, dir, arch); + + INT_XLATE(buf_core->di_mtime.t_sec, mem_core->di_mtime.t_sec, dir, arch); + INT_XLATE(buf_core->di_mtime.t_nsec,mem_core->di_mtime.t_nsec, dir, arch); + + INT_XLATE(buf_core->di_ctime.t_sec, mem_core->di_ctime.t_sec, dir, arch); + INT_XLATE(buf_core->di_ctime.t_nsec,mem_core->di_ctime.t_nsec, dir, arch); + + INT_XLATE(buf_core->di_size, mem_core->di_size, dir, arch); + INT_XLATE(buf_core->di_nblocks, mem_core->di_nblocks, dir, arch); + INT_XLATE(buf_core->di_extsize, mem_core->di_extsize, dir, arch); + + INT_XLATE(buf_core->di_nextents, mem_core->di_nextents, dir, arch); + INT_XLATE(buf_core->di_anextents, mem_core->di_anextents, dir, arch); + INT_XLATE(buf_core->di_forkoff, mem_core->di_forkoff, dir, arch); + INT_XLATE(buf_core->di_aformat, mem_core->di_aformat, dir, arch); + INT_XLATE(buf_core->di_dmevmask, mem_core->di_dmevmask, dir, arch); + INT_XLATE(buf_core->di_dmstate, mem_core->di_dmstate, dir, arch); + INT_XLATE(buf_core->di_flags, mem_core->di_flags, dir, arch); + INT_XLATE(buf_core->di_gen, mem_core->di_gen, dir, arch); + +} + +/* + * Given a mount structure and an inode number, return a pointer + * to a newly allocated in-core inode coresponding to the given + * inode number. + * + * Initialize the inode's attributes and extent pointers if it + * already has them (it will not if the inode has no links). + */ +int +xfs_iread( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + xfs_inode_t **ipp, + xfs_daddr_t bno) +{ + xfs_buf_t *bp; + xfs_dinode_t *dip; + xfs_inode_t *ip; + int error; + int alloc_mode = tp ? KM_SLEEP : KM_SLEEP_IO; + + ASSERT(xfs_inode_zone != NULL); + + ip = kmem_zone_zalloc(xfs_inode_zone, alloc_mode); + ip->i_ino = ino; + ip->i_dev = mp->m_dev; + ip->i_mount = mp; + + /* + * Get pointer's to the on-disk inode and the buffer containing it. + * If the inode number refers to a block outside the file system + * then xfs_itobp() will return NULL. In this case we should + * return NULL as well. Set i_blkno to 0 so that xfs_itobp() will + * know that this is a new incore inode. + */ + error = xfs_itobp(mp, tp, ip, &dip, &bp, bno); + + if (error != 0) { + kmem_zone_free(xfs_inode_zone, ip); + return error; + } + + /* + * Initialize inode's trace buffers. + * Do this before xfs_iformat in case it adds entries. + */ +#ifdef XFS_BMAP_TRACE + ip->i_xtrace = ktrace_alloc(XFS_BMAP_KTRACE_SIZE, alloc_mode); +#endif +#ifdef XFS_BMBT_TRACE + ip->i_btrace = ktrace_alloc(XFS_BMBT_KTRACE_SIZE, alloc_mode); +#endif +#ifdef XFS_RW_TRACE + ip->i_rwtrace = ktrace_alloc(XFS_RW_KTRACE_SIZE, alloc_mode); +#endif +#ifdef XFS_STRAT_TRACE + ip->i_strat_trace = ktrace_alloc(XFS_STRAT_KTRACE_SIZE, alloc_mode); +#endif +#ifdef XFS_ILOCK_TRACE + ip->i_lock_trace = ktrace_alloc(XFS_ILOCK_KTRACE_SIZE, alloc_mode); +#endif +#ifdef XFS_DIR2_TRACE + ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, alloc_mode); +#endif + + /* + * If we got something that isn't an inode it means someone + * (nfs or dmi) has a stale handle. + */ + if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) { + kmem_zone_free(xfs_inode_zone, ip); + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EINVAL); + } + + /* + * If the on-disk inode is already linked to a directory + * entry, copy all of the inode into the in-core inode. + * xfs_iformat() handles copying in the inode format + * specific information. + * Otherwise, just get the truly permanent information. + */ + if (!INT_ISZERO(dip->di_core.di_mode, ARCH_CONVERT)) { + xfs_xlate_dinode_core((xfs_caddr_t)&dip->di_core, + &(ip->i_d), 1, ARCH_CONVERT); + error = xfs_iformat(ip, dip, alloc_mode); + if (error) { + kmem_zone_free(xfs_inode_zone, ip); + xfs_trans_brelse(tp, bp); + return error; + } + } else { + ip->i_d.di_magic = INT_GET(dip->di_core.di_magic, ARCH_CONVERT); + ip->i_d.di_version = INT_GET(dip->di_core.di_version, ARCH_CONVERT); + ip->i_d.di_gen = INT_GET(dip->di_core.di_gen, ARCH_CONVERT); + /* + * Make sure to pull in the mode here as well in + * case the inode is released without being used. + * This ensures that xfs_inactive() will see that + * the inode is already free and not try to mess + * with the uninitialized part of it. + */ + ip->i_d.di_mode = 0; + /* + * Initialize the per-fork minima and maxima for a new + * inode here. xfs_iformat will do it for old inodes. + */ + ip->i_df.if_ext_max = + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + } + + /* + * The inode format changed when we moved the link count and + * made it 32 bits long. If this is an old format inode, + * convert it in memory to look like a new one. If it gets + * flushed to disk we will convert back before flushing or + * logging it. We zero out the new projid field and the old link + * count field. We'll handle clearing the pad field (the remains + * of the old uuid field) when we actually convert the inode to + * the new format. We don't change the version number so that we + * can distinguish this from a real new format inode. + */ + if (ip->i_d.di_version == XFS_DINODE_VERSION_1) { + ip->i_d.di_nlink = ip->i_d.di_onlink; + ip->i_d.di_onlink = 0; + ip->i_d.di_projid = 0; + } + + ip->i_delayed_blks = 0; + + /* + * Mark the buffer containing the inode as something to keep + * around for a while. This helps to keep recently accessed + * meta-data in-core longer. + */ + XFS_BUF_SET_REF(bp, XFS_INO_REF); + + /* + * Use xfs_trans_brelse() to release the buffer containing the + * on-disk inode, because it was acquired with xfs_trans_read_buf() + * in xfs_itobp() above. If tp is NULL, this is just a normal + * brelse(). If we're within a transaction, then xfs_trans_brelse() + * will only release the buffer if it is not dirty within the + * transaction. It will be OK to release the buffer in this case, + * because inodes on disk are never destroyed and we will be + * locking the new in-core inode before putting it in the hash + * table where other processes can find it. Thus we don't have + * to worry about the inode being changed just because we released + * the buffer. + */ + xfs_trans_brelse(tp, bp); + *ipp = ip; + return 0; +} + +/* + * Read in extents from a btree-format inode. + * Allocate and fill in if_extents. Real work is done in xfs_bmap.c. + */ +int +xfs_iread_extents( + xfs_trans_t *tp, + xfs_inode_t *ip, + int whichfork) +{ + int error; + xfs_ifork_t *ifp; + size_t size; + + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) + return XFS_ERROR(EFSCORRUPTED); + size = XFS_IFORK_NEXTENTS(ip, whichfork) * (uint)sizeof(xfs_bmbt_rec_t); + ifp = XFS_IFORK_PTR(ip, whichfork); + /* + * We know that the size is legal (it's checked in iformat_btree) + */ + ifp->if_u1.if_extents = kmem_alloc(size, tp ? KM_SLEEP : KM_SLEEP_IO); + ASSERT(ifp->if_u1.if_extents != NULL); + ifp->if_lastex = NULLEXTNUM; + ifp->if_bytes = ifp->if_real_bytes = (int)size; + ifp->if_flags |= XFS_IFEXTENTS; + error = xfs_bmap_read_extents(tp, ip, whichfork); + if (error) { + kmem_free(ifp->if_u1.if_extents, size); + ifp->if_u1.if_extents = NULL; + ifp->if_bytes = ifp->if_real_bytes = 0; + ifp->if_flags &= ~XFS_IFEXTENTS; + return error; + } + xfs_validate_extents((xfs_bmbt_rec_32_t *)ifp->if_u1.if_extents, + XFS_IFORK_NEXTENTS(ip, whichfork), XFS_EXTFMT_INODE(ip)); + return 0; +} + +/* + * Reallocate the space for if_broot based on the number of records + * being added or deleted as indicated in rec_diff. Move the records + * and pointers in if_broot to fit the new size. When shrinking this + * will eliminate holes between the records and pointers created by + * the caller. When growing this will create holes to be filled in + * by the caller. + * + * The caller must not request to add more records than would fit in + * the on-disk inode root. If the if_broot is currently NULL, then + * if we adding records one will be allocated. The caller must also + * not request that the number of records go below zero, although + * it can go to zero. + * + * ip -- the inode whose if_broot area is changing + * ext_diff -- the change in the number of records, positive or negative, + * requested for the if_broot array. + */ +void +xfs_iroot_realloc( + xfs_inode_t *ip, + int rec_diff, + int whichfork) +{ + int cur_max; + xfs_ifork_t *ifp; + xfs_bmbt_block_t *new_broot; + int new_max; + size_t new_size; + char *np; + char *op; + + /* + * Handle the degenerate case quietly. + */ + if (rec_diff == 0) { + return; + } + + ifp = XFS_IFORK_PTR(ip, whichfork); + if (rec_diff > 0) { + /* + * If there wasn't any memory allocated before, just + * allocate it now and get out. + */ + if (ifp->if_broot_bytes == 0) { + new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(rec_diff); + ifp->if_broot = (xfs_bmbt_block_t*)kmem_alloc(new_size, + KM_SLEEP); + ifp->if_broot_bytes = (int)new_size; + return; + } + + /* + * If there is already an existing if_broot, then we need + * to realloc() it and shift the pointers to their new + * location. The records don't change location because + * they are kept butted up against the btree block header. + */ + cur_max = XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes); + new_max = cur_max + rec_diff; + new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max); + ifp->if_broot = (xfs_bmbt_block_t *) + kmem_realloc(ifp->if_broot, + new_size, + (size_t)XFS_BMAP_BROOT_SPACE_CALC(cur_max), /* old size */ + KM_SLEEP); + op = (char *)XFS_BMAP_BROOT_PTR_ADDR(ifp->if_broot, 1, + ifp->if_broot_bytes); + np = (char *)XFS_BMAP_BROOT_PTR_ADDR(ifp->if_broot, 1, + (int)new_size); + ifp->if_broot_bytes = (int)new_size; + ASSERT(ifp->if_broot_bytes <= + XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ); + ovbcopy(op, np, cur_max * (uint)sizeof(xfs_dfsbno_t)); + return; + } + + /* + * rec_diff is less than 0. In this case, we are shrinking the + * if_broot buffer. It must already exist. If we go to zero + * records, just get rid of the root and clear the status bit. + */ + ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0)); + cur_max = XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes); + new_max = cur_max + rec_diff; + ASSERT(new_max >= 0); + if (new_max > 0) + new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max); + else + new_size = 0; + if (new_size > 0) { + new_broot = (xfs_bmbt_block_t *)kmem_alloc(new_size, KM_SLEEP); + /* + * First copy over the btree block header. + */ + bcopy(ifp->if_broot, new_broot, sizeof(xfs_bmbt_block_t)); + } else { + new_broot = NULL; + ifp->if_flags &= ~XFS_IFBROOT; + } + + /* + * Only copy the records and pointers if there are any. + */ + if (new_max > 0) { + /* + * First copy the records. + */ + op = (char *)XFS_BMAP_BROOT_REC_ADDR(ifp->if_broot, 1, + ifp->if_broot_bytes); + np = (char *)XFS_BMAP_BROOT_REC_ADDR(new_broot, 1, + (int)new_size); + bcopy(op, np, new_max * (uint)sizeof(xfs_bmbt_rec_t)); + + /* + * Then copy the pointers. + */ + op = (char *)XFS_BMAP_BROOT_PTR_ADDR(ifp->if_broot, 1, + ifp->if_broot_bytes); + np = (char *)XFS_BMAP_BROOT_PTR_ADDR(new_broot, 1, + (int)new_size); + bcopy(op, np, new_max * (uint)sizeof(xfs_dfsbno_t)); + } + kmem_free(ifp->if_broot, ifp->if_broot_bytes); + ifp->if_broot = new_broot; + ifp->if_broot_bytes = (int)new_size; + ASSERT(ifp->if_broot_bytes <= + XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ); + return; +} + +/* + * This is called when the amount of space needed for if_extents + * is increased or decreased. The change in size is indicated by + * the number of extents that need to be added or deleted in the + * ext_diff parameter. + * + * If the amount of space needed has decreased below the size of the + * inline buffer, then switch to using the inline buffer. Otherwise, + * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer + * to what is needed. + * + * ip -- the inode whose if_extents area is changing + * ext_diff -- the change in the number of extents, positive or negative, + * requested for the if_extents array. + */ +void +xfs_iext_realloc( + xfs_inode_t *ip, + int ext_diff, + int whichfork) +{ + int byte_diff; + xfs_ifork_t *ifp; + int new_size; + uint rnew_size; + + if (ext_diff == 0) { + return; + } + + ifp = XFS_IFORK_PTR(ip, whichfork); + byte_diff = ext_diff * (uint)sizeof(xfs_bmbt_rec_t); + new_size = (int)ifp->if_bytes + byte_diff; + ASSERT(new_size >= 0); + + if (new_size == 0) { + if (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext) { + ASSERT(ifp->if_real_bytes != 0); + kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes); + } + ifp->if_u1.if_extents = NULL; + rnew_size = 0; + } else if (new_size <= sizeof(ifp->if_u2.if_inline_ext)) { + /* + * If the valid extents can fit in if_inline_ext, + * copy them from the malloc'd vector and free it. + */ + if (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext) { + /* + * For now, empty files are format EXTENTS, + * so the if_extents pointer is null. + */ + if (ifp->if_u1.if_extents) { + bcopy(ifp->if_u1.if_extents, + ifp->if_u2.if_inline_ext, new_size); + kmem_free(ifp->if_u1.if_extents, + ifp->if_real_bytes); + } + ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; + } + rnew_size = 0; + } else { + rnew_size = new_size; + if ((rnew_size & (rnew_size - 1)) != 0) + rnew_size = xfs_iroundup(rnew_size); + /* + * Stuck with malloc/realloc. + */ + if (ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext) { + ifp->if_u1.if_extents = (xfs_bmbt_rec_t *) + kmem_alloc(rnew_size, KM_SLEEP); + bcopy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents, + sizeof(ifp->if_u2.if_inline_ext)); + } else if (rnew_size != ifp->if_real_bytes) { + ifp->if_u1.if_extents = (xfs_bmbt_rec_t *) + kmem_realloc(ifp->if_u1.if_extents, + rnew_size, + ifp->if_real_bytes, + KM_SLEEP); + } + } + ifp->if_real_bytes = rnew_size; + ifp->if_bytes = new_size; +} + + +/* + * This is called when the amount of space needed for if_data + * is increased or decreased. The change in size is indicated by + * the number of bytes that need to be added or deleted in the + * byte_diff parameter. + * + * If the amount of space needed has decreased below the size of the + * inline buffer, then switch to using the inline buffer. Otherwise, + * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer + * to what is needed. + * + * ip -- the inode whose if_data area is changing + * byte_diff -- the change in the number of bytes, positive or negative, + * requested for the if_data array. + */ +void +xfs_idata_realloc( + xfs_inode_t *ip, + int byte_diff, + int whichfork) +{ + xfs_ifork_t *ifp; + int new_size; + int real_size; + + if (byte_diff == 0) { + return; + } + + ifp = XFS_IFORK_PTR(ip, whichfork); + new_size = (int)ifp->if_bytes + byte_diff; + ASSERT(new_size >= 0); + + if (new_size == 0) { + if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { + kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes); + } + ifp->if_u1.if_data = NULL; + real_size = 0; + } else if (new_size <= sizeof(ifp->if_u2.if_inline_data)) { + /* + * If the valid extents/data can fit in if_inline_ext/data, + * copy them from the malloc'd vector and free it. + */ + if (ifp->if_u1.if_data == NULL) { + ifp->if_u1.if_data = ifp->if_u2.if_inline_data; + } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { + ASSERT(ifp->if_real_bytes != 0); + bcopy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data, + new_size); + kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes); + ifp->if_u1.if_data = ifp->if_u2.if_inline_data; + } + real_size = 0; + } else { + /* + * Stuck with malloc/realloc. + * For inline data, the underlying buffer must be + * a multiple of 4 bytes in size so that it can be + * logged and stay on word boundaries. We enforce + * that here. + */ + real_size = roundup(new_size, 4); + if (ifp->if_u1.if_data == NULL) { + ASSERT(ifp->if_real_bytes == 0); + ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP); + } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { + /* + * Only do the realloc if the underlying size + * is really changing. + */ + if (ifp->if_real_bytes != real_size) { + ifp->if_u1.if_data = + kmem_realloc(ifp->if_u1.if_data, + real_size, + ifp->if_real_bytes, + KM_SLEEP); + } + } else { + ASSERT(ifp->if_real_bytes == 0); + ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP); + bcopy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data, + ifp->if_bytes); + } + } + ifp->if_real_bytes = real_size; + ifp->if_bytes = new_size; + ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); +} + + +/* + * Map inode to disk block and offset. + * + * mp -- the mount point structure for the current file system + * tp -- the current transaction + * ino -- the inode number of the inode to be located + * imap -- this structure is filled in with the information necessary + * to retrieve the given inode from disk + * flags -- flags to pass to xfs_dilocate indicating whether or not + * lookups in the inode btree were OK or not + */ +int +xfs_imap( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + xfs_imap_t *imap, + uint flags) +{ + xfs_fsblock_t fsbno; + int len; + int off; + int error; + + fsbno = imap->im_blkno ? + XFS_DADDR_TO_FSB(mp, imap->im_blkno) : NULLFSBLOCK; + error = xfs_dilocate(mp, tp, ino, &fsbno, &len, &off, flags); + if (error != 0) { + return error; + } + imap->im_blkno = XFS_FSB_TO_DADDR(mp, fsbno); + imap->im_len = XFS_FSB_TO_BB(mp, len); + imap->im_agblkno = XFS_FSB_TO_AGBNO(mp, fsbno); + imap->im_ioffset = (ushort)off; + imap->im_boffset = (ushort)(off << mp->m_sb.sb_inodelog); + return 0; +} + +void +xfs_idestroy_fork( + xfs_inode_t *ip, + int whichfork) +{ + xfs_ifork_t *ifp; + + ifp = XFS_IFORK_PTR(ip, whichfork); + if (ifp->if_broot != NULL) { + kmem_free(ifp->if_broot, ifp->if_broot_bytes); + ifp->if_broot = NULL; + } + + /* + * If the format is local, then we can't have an extents + * array so just look for an inline data array. If we're + * not local then we may or may not have an extents list, + * so check and free it up if we do. + */ + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) && + (ifp->if_u1.if_data != NULL)) { + ASSERT(ifp->if_real_bytes != 0); + kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes); + ifp->if_u1.if_data = NULL; + ifp->if_real_bytes = 0; + } + } else if ((ifp->if_flags & XFS_IFEXTENTS) && + (ifp->if_u1.if_extents != NULL) && + (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)) { + ASSERT(ifp->if_real_bytes != 0); + kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes); + ifp->if_u1.if_extents = NULL; + ifp->if_real_bytes = 0; + } + ASSERT(ifp->if_u1.if_extents == NULL || + ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext); + ASSERT(ifp->if_real_bytes == 0); + if (whichfork == XFS_ATTR_FORK) { + kmem_zone_free(xfs_ifork_zone, ip->i_afp); + ip->i_afp = NULL; + } +} + +/* + * xfs_iroundup: round up argument to next power of two + */ +uint +xfs_iroundup( + uint v) +{ + int i; + uint m; + + if ((v & (v - 1)) == 0) + return v; + ASSERT((v & 0x80000000) == 0); + if ((v & (v + 1)) == 0) + return v + 1; + for (i = 0, m = 1; i < 31; i++, m <<= 1) { + if (v & m) + continue; + v |= m; + if ((v & (v + 1)) == 0) + return v + 1; + } + ASSERT(0); + return( 0 ); +} + +/* + * xfs_iextents_copy() + * + * This is called to copy the REAL extents (as opposed to the delayed + * allocation extents) from the inode into the given buffer. It + * returns the number of bytes copied into the buffer. + * + * If there are no delayed allocation extents, then we can just + * bcopy() the extents into the buffer. Otherwise, we need to + * examine each extent in turn and skip those which are delayed. + */ +int +xfs_iextents_copy( + xfs_inode_t *ip, + xfs_bmbt_rec_32_t *buffer, + int whichfork) +{ + int copied; + xfs_bmbt_rec_32_t *dest_ep; + xfs_bmbt_rec_t *ep; +#ifdef DEBUG + xfs_exntfmt_t fmt = XFS_EXTFMT_INODE(ip); +#endif +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_iextents_copy"; +#endif + int i; + xfs_ifork_t *ifp; + int nrecs; + xfs_fsblock_t start_block; + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS)); + ASSERT(ifp->if_bytes > 0); + + nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + xfs_bmap_trace_exlist(fname, ip, nrecs, whichfork); + ASSERT(nrecs > 0); + if (nrecs == XFS_IFORK_NEXTENTS(ip, whichfork)) { + /* + * There are no delayed allocation extents, + * so just copy everything. + */ + ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); + ASSERT(ifp->if_bytes == + (XFS_IFORK_NEXTENTS(ip, whichfork) * + (uint)sizeof(xfs_bmbt_rec_t))); + bcopy(ifp->if_u1.if_extents, buffer, ifp->if_bytes); + xfs_validate_extents(buffer, nrecs, fmt); + return ifp->if_bytes; + } + + ASSERT(whichfork == XFS_DATA_FORK); + /* + * There are some delayed allocation extents in the + * inode, so copy the extents one at a time and skip + * the delayed ones. There must be at least one + * non-delayed extent. + */ + ASSERT(nrecs > ip->i_d.di_nextents); + ep = ifp->if_u1.if_extents; + dest_ep = buffer; + copied = 0; + for (i = 0; i < nrecs; i++) { + start_block = xfs_bmbt_get_startblock(ep); + if (ISNULLSTARTBLOCK(start_block)) { + /* + * It's a delayed allocation extent, so skip it. + */ + ep++; + continue; + } + + *dest_ep = *(xfs_bmbt_rec_32_t *)ep; + dest_ep++; + ep++; + copied++; + } + ASSERT(copied != 0); + ASSERT(copied == ip->i_d.di_nextents); + ASSERT((copied * (uint)sizeof(xfs_bmbt_rec_t)) <= XFS_IFORK_DSIZE(ip)); + xfs_validate_extents(buffer, copied, fmt); + + return (copied * (uint)sizeof(xfs_bmbt_rec_t)); +} + +/* + * Each of the following cases stores data into the same region + * of the on-disk inode, so only one of them can be valid at + * any given time. While it is possible to have conflicting formats + * and log flags, e.g. having XFS_ILOG_?DATA set when the fork is + * in EXTENTS format, this can only happen when the fork has + * changed formats after being modified but before being flushed. + * In these cases, the format always takes precedence, because the + * format indicates the current state of the fork. + */ +STATIC int +xfs_iflush_fork( + xfs_inode_t *ip, + xfs_dinode_t *dip, + xfs_inode_log_item_t *iip, + int whichfork, + xfs_buf_t *bp) +{ + char *cp; + xfs_ifork_t *ifp; + xfs_mount_t *mp; +#ifdef XFS_TRANS_DEBUG + int first; +#endif + static const short brootflag[2] = + { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT }; + static const short dataflag[2] = + { XFS_ILOG_DDATA, XFS_ILOG_ADATA }; + static const short extflag[2] = + { XFS_ILOG_DEXT, XFS_ILOG_AEXT }; + + if (iip == NULL) + return 0; + ifp = XFS_IFORK_PTR(ip, whichfork); + /* + * This can happen if we gave up in iformat in an error path, + * for the attribute fork. + */ + if (ifp == NULL) { + ASSERT(whichfork == XFS_ATTR_FORK); + return 0; + } + cp = XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT); + mp = ip->i_mount; + switch (XFS_IFORK_FORMAT(ip, whichfork)) { + case XFS_DINODE_FMT_LOCAL: + if ((iip->ili_format.ilf_fields & dataflag[whichfork]) && + (ifp->if_bytes > 0)) { + ASSERT(ifp->if_u1.if_data != NULL); + ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); + bcopy(ifp->if_u1.if_data, cp, ifp->if_bytes); + } + if (whichfork == XFS_DATA_FORK) { + if (XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp, dip)) { + return XFS_ERROR(EFSCORRUPTED); + } + } + break; + + case XFS_DINODE_FMT_EXTENTS: + ASSERT((ifp->if_flags & XFS_IFEXTENTS) || + !(iip->ili_format.ilf_fields & extflag[whichfork])); + ASSERT((ifp->if_u1.if_extents != NULL) || (ifp->if_bytes == 0)); + ASSERT((ifp->if_u1.if_extents == NULL) || (ifp->if_bytes > 0)); + if ((iip->ili_format.ilf_fields & extflag[whichfork]) && + (ifp->if_bytes > 0)) { + ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0); + (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_32_t *)cp, + whichfork); + } + break; + + case XFS_DINODE_FMT_BTREE: + if ((iip->ili_format.ilf_fields & brootflag[whichfork]) && + (ifp->if_broot_bytes > 0)) { + ASSERT(ifp->if_broot != NULL); + ASSERT(ifp->if_broot_bytes <= + (XFS_IFORK_SIZE(ip, whichfork) + + XFS_BROOT_SIZE_ADJ)); + xfs_bmbt_to_bmdr(ifp->if_broot, ifp->if_broot_bytes, + (xfs_bmdr_block_t *)cp, + XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_CONVERT)); + } + break; + + case XFS_DINODE_FMT_DEV: + if (iip->ili_format.ilf_fields & XFS_ILOG_DEV) { + ASSERT(whichfork == XFS_DATA_FORK); + INT_SET(dip->di_u.di_dev, ARCH_CONVERT, ip->i_df.if_u2.if_rdev); + } + break; + + case XFS_DINODE_FMT_UUID: + if (iip->ili_format.ilf_fields & XFS_ILOG_UUID) { + ASSERT(whichfork == XFS_DATA_FORK); + bcopy(&ip->i_df.if_u2.if_uuid, &dip->di_u.di_muuid, + sizeof(uuid_t)); + } + break; + + default: + ASSERT(0); + break; + } + + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_mount.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_mount.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_mount.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_mount.c Mon Apr 2 21:52:38 2001 @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * Mount initialization code establishing various mount + * fields from the superblock associated with the given + * mount structure. + */ +void +xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp) +{ + int i; + + mp->m_agfrotor = mp->m_agirotor = 0; + mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG; + mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT; + mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1; + mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog; + mp->m_litino = sbp->sb_inodesize - + ((uint)sizeof(xfs_dinode_core_t) + (uint)sizeof(xfs_agino_t)); + mp->m_blockmask = sbp->sb_blocksize - 1; + mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG; + mp->m_blockwmask = mp->m_blockwsize - 1; + + /* + * Setup for attributes, in case they get created. + * This value is for inodes getting attributes for the first time, + * the per-inode value is for old attribute values. + */ + ASSERT(sbp->sb_inodesize >= 256 && sbp->sb_inodesize <= 2048); + switch (sbp->sb_inodesize) { + case 256: + mp->m_attroffset = XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(2); + break; + case 512: + case 1024: + case 2048: + mp->m_attroffset = XFS_BMDR_SPACE_CALC(12); + break; + default: + ASSERT(0); + } + ASSERT(mp->m_attroffset < XFS_LITINO(mp)); + + for (i = 0; i < 2; i++) { + mp->m_alloc_mxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, + xfs_alloc, i == 0); + mp->m_alloc_mnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, + xfs_alloc, i == 0); + } + for (i = 0; i < 2; i++) { + mp->m_bmap_dmxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, + xfs_bmbt, i == 0); + mp->m_bmap_dmnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, + xfs_bmbt, i == 0); + } + for (i = 0; i < 2; i++) { + mp->m_inobt_mxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, + xfs_inobt, i == 0); + mp->m_inobt_mnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, + xfs_inobt, i == 0); + } + + mp->m_bsize = XFS_FSB_TO_BB(mp, 1); + mp->m_ialloc_inos = (int)MAX(XFS_INODES_PER_CHUNK, sbp->sb_inopblock); + mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog; +} + +static struct { + short offset; + short type; /* 0 = integer + * 1 = binary / string (no translation) + */ +} xfs_sb_info[] = { + { offsetof(xfs_sb_t, sb_magicnum), 0 }, + { offsetof(xfs_sb_t, sb_blocksize), 0 }, + { offsetof(xfs_sb_t, sb_dblocks), 0 }, + { offsetof(xfs_sb_t, sb_rblocks), 0 }, + { offsetof(xfs_sb_t, sb_rextents), 0 }, + { offsetof(xfs_sb_t, sb_uuid), 1 }, + { offsetof(xfs_sb_t, sb_logstart), 0 }, + { offsetof(xfs_sb_t, sb_rootino), 0 }, + { offsetof(xfs_sb_t, sb_rbmino), 0 }, + { offsetof(xfs_sb_t, sb_rsumino), 0 }, + { offsetof(xfs_sb_t, sb_rextsize), 0 }, + { offsetof(xfs_sb_t, sb_agblocks), 0 }, + { offsetof(xfs_sb_t, sb_agcount), 0 }, + { offsetof(xfs_sb_t, sb_rbmblocks), 0 }, + { offsetof(xfs_sb_t, sb_logblocks), 0 }, + { offsetof(xfs_sb_t, sb_versionnum), 0 }, + { offsetof(xfs_sb_t, sb_sectsize), 0 }, + { offsetof(xfs_sb_t, sb_inodesize), 0 }, + { offsetof(xfs_sb_t, sb_inopblock), 0 }, + { offsetof(xfs_sb_t, sb_fname[0]), 1 }, + { offsetof(xfs_sb_t, sb_blocklog), 0 }, + { offsetof(xfs_sb_t, sb_sectlog), 0 }, + { offsetof(xfs_sb_t, sb_inodelog), 0 }, + { offsetof(xfs_sb_t, sb_inopblog), 0 }, + { offsetof(xfs_sb_t, sb_agblklog), 0 }, + { offsetof(xfs_sb_t, sb_rextslog), 0 }, + { offsetof(xfs_sb_t, sb_inprogress), 0 }, + { offsetof(xfs_sb_t, sb_imax_pct), 0 }, + { offsetof(xfs_sb_t, sb_icount), 0 }, + { offsetof(xfs_sb_t, sb_ifree), 0 }, + { offsetof(xfs_sb_t, sb_fdblocks), 0 }, + { offsetof(xfs_sb_t, sb_frextents), 0 }, + { offsetof(xfs_sb_t, sb_uquotino), 0 }, + { offsetof(xfs_sb_t, sb_gquotino), 0 }, + { offsetof(xfs_sb_t, sb_qflags), 0 }, + { offsetof(xfs_sb_t, sb_flags), 0 }, + { offsetof(xfs_sb_t, sb_shared_vn), 0 }, + { offsetof(xfs_sb_t, sb_inoalignmt), 0 }, + { offsetof(xfs_sb_t, sb_unit), 0 }, + { offsetof(xfs_sb_t, sb_width), 0 }, + { offsetof(xfs_sb_t, sb_dirblklog), 0 }, + { offsetof(xfs_sb_t, sb_dummy), 1 }, + { sizeof(xfs_sb_t), 0 } +}; + +/* + * xfs_xlatesb + * data - on disk version of sb + * sb - a superblock + * dir - conversion direction: <0 - convert sb to buf + * >0 - convert buf to sb + * arch - architecture to read/write from/to buf + * fields - which fields to copy (bitmask) + */ +void +xfs_xlatesb(void *data, xfs_sb_t *sb, int dir, xfs_arch_t arch, + __int64_t fields) +{ + xfs_caddr_t buf_ptr; + xfs_caddr_t mem_ptr; + + ASSERT(dir); + ASSERT(fields); + + if (!fields) + return; + + buf_ptr=(xfs_caddr_t)data; + mem_ptr=(xfs_caddr_t)sb; + + while (fields) { + xfs_sb_field_t f; + int first; + int size; + + f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields); + first = xfs_sb_info[f].offset; + size = xfs_sb_info[f + 1].offset - first; + + ASSERT(xfs_sb_info[f].type==0 || xfs_sb_info[f].type==1); + + if (arch == ARCH_NOCONVERT || size==1 || xfs_sb_info[f].type==1) { + if (dir>0) { + bcopy(buf_ptr + first, mem_ptr + first, size); + } else { + bcopy(mem_ptr + first, buf_ptr + first, size); + } + } else { + switch (size) { + case 2: + INT_XLATE(*(__uint16_t*)(buf_ptr+first), + *(__uint16_t*)(mem_ptr+first), dir, arch); + break; + case 4: + INT_XLATE(*(__uint32_t*)(buf_ptr+first), + *(__uint32_t*)(mem_ptr+first), dir, arch); + break; + case 8: + INT_XLATE(*(__uint64_t*)(buf_ptr+first), + *(__uint64_t*)(mem_ptr+first), dir, arch); + break; + default: + ASSERT(0); + } + } + fields &= ~(1LL << f); + } + +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_rtalloc.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_rtalloc.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_rtalloc.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_rtalloc.c Thu Apr 12 18:30:32 2001 @@ -0,0 +1,835 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Free realtime space allocation for XFS. + */ +#include + + +/* + * Get a buffer for the bitmap or summary file block specified. + * The buffer is returned read and locked. + */ +STATIC int /* error */ +xfs_rtbuf_get( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t block, /* block number in bitmap or summary */ + int issum, /* is summary not bitmap */ + xfs_buf_t **bpp) /* output: buffer for the block */ +{ + xfs_buf_t *bp; /* block buffer, result */ + xfs_daddr_t d; /* disk addr of block */ + int error; /* error value */ + xfs_fsblock_t fsb; /* fs block number for block */ + xfs_inode_t *ip; /* bitmap or summary inode */ + + ip = issum ? mp->m_rsumip : mp->m_rbmip; + /* + * Map from the file offset (block) and inode number to the + * file system block. + */ + error = xfs_bmapi_single(tp, ip, XFS_DATA_FORK, &fsb, block); + if (error) { + return error; + } + ASSERT(fsb != NULLFSBLOCK); + /* + * Convert to disk address for buffer cache. + */ + d = XFS_FSB_TO_DADDR(mp, fsb); + /* + * Read the buffer. + */ + error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, + mp->m_bsize, 0, &bp); + if (error) { + return error; + } + ASSERT(bp && !XFS_BUF_GETERROR(bp)); + *bpp = bp; + return 0; +} + +/* + * Searching backward from start to limit, find the first block whose + * allocated/free state is different from start's. + */ +STATIC int /* error */ +xfs_rtfind_back( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to look at */ + xfs_rtblock_t limit, /* last block to look at */ + xfs_rtblock_t *rtblock) /* out: start block found */ +{ + xfs_rtword_t *b; /* current word in buffer */ + int bit; /* bit number in the word */ + xfs_rtblock_t block; /* bitmap block number */ + xfs_buf_t *bp; /* buf for the block */ + xfs_rtword_t *bufp; /* starting word in buffer */ + int error; /* error value */ + xfs_rtblock_t firstbit; /* first useful bit in the word */ + xfs_rtblock_t i; /* current bit number rel. to start */ + xfs_rtblock_t len; /* length of inspected area */ + xfs_rtword_t mask; /* mask of relevant bits for value */ + xfs_rtword_t want; /* mask for "good" values */ + xfs_rtword_t wdiff; /* difference from wanted value */ + int word; /* word number in the buffer */ + + /* + * Compute and read in starting bitmap block for starting block. + */ + block = XFS_BITTOBLOCK(mp, start); + error = xfs_rtbuf_get(mp, tp, block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + /* + * Get the first word's index & point to it. + */ + word = XFS_BITTOWORD(mp, start); + b = &bufp[word]; + bit = (int)(start & (XFS_NBWORD - 1)); + len = start - limit + 1; + /* + * Compute match value, based on the bit at start: if 1 (free) + * then all-ones, else all-zeroes. + */ + want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0; + /* + * If the starting position is not word-aligned, deal with the + * partial word. + */ + if (bit < XFS_NBWORD - 1) { + /* + * Calculate first (leftmost) bit number to look at, + * and mask for all the relevant bits in this word. + */ + firstbit = XFS_RTMAX((xfs_srtblock_t)(bit - len + 1), 0); + mask = (((xfs_rtword_t)1 << (bit - firstbit + 1)) - 1) << + firstbit; + /* + * Calculate the difference between the value there + * and what we're looking for. + */ + if ((wdiff = (*b ^ want) & mask)) { + /* + * Different. Mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i = bit - XFS_RTHIBIT(wdiff); + *rtblock = start - i + 1; + return 0; + } + i = bit - firstbit + 1; + /* + * Go on to previous block if that's where the previous word is + * and we need the previous word. + */ + if (--word == -1 && i < len) { + /* + * If done with this block, get the previous one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, --block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = XFS_BLOCKWMASK(mp); + b = &bufp[word]; + } else { + /* + * Go on to the previous word in the buffer. + */ + b--; + } + } else { + /* + * Starting on a word boundary, no partial word. + */ + i = 0; + } + /* + * Loop over whole words in buffers. When we use up one buffer + * we move on to the previous one. + */ + while (len - i >= XFS_NBWORD) { + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = *b ^ want)) { + /* + * Different, mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff); + *rtblock = start - i + 1; + return 0; + } + i += XFS_NBWORD; + /* + * Go on to previous block if that's where the previous word is + * and we need the previous word. + */ + if (--word == -1 && i < len) { + /* + * If done with this block, get the previous one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, --block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = XFS_BLOCKWMASK(mp); + b = &bufp[word]; + } else { + /* + * Go on to the previous word in the buffer. + */ + b--; + } + } + /* + * If not ending on a word boundary, deal with the last + * (partial) word. + */ + if (len - i) { + /* + * Calculate first (leftmost) bit number to look at, + * and mask for all the relevant bits in this word. + */ + firstbit = XFS_NBWORD - (len - i); + mask = (((xfs_rtword_t)1 << (len - i)) - 1) << firstbit; + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = (*b ^ want) & mask)) { + /* + * Different, mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff); + *rtblock = start - i + 1; + return 0; + } else + i = len; + } + /* + * No match, return that we scanned the whole area. + */ + xfs_trans_brelse(tp, bp); + *rtblock = start - i + 1; + return 0; +} + +/* + * Searching forward from start to limit, find the first block whose + * allocated/free state is different from start's. + */ +STATIC int /* error */ +xfs_rtfind_forw( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to look at */ + xfs_rtblock_t limit, /* last block to look at */ + xfs_rtblock_t *rtblock) /* out: start block found */ +{ + xfs_rtword_t *b; /* current word in buffer */ + int bit; /* bit number in the word */ + xfs_rtblock_t block; /* bitmap block number */ + xfs_buf_t *bp; /* buf for the block */ + xfs_rtword_t *bufp; /* starting word in buffer */ + int error; /* error value */ + xfs_rtblock_t i; /* current bit number rel. to start */ + xfs_rtblock_t lastbit; /* last useful bit in the word */ + xfs_rtblock_t len; /* length of inspected area */ + xfs_rtword_t mask; /* mask of relevant bits for value */ + xfs_rtword_t want; /* mask for "good" values */ + xfs_rtword_t wdiff; /* difference from wanted value */ + int word; /* word number in the buffer */ + + /* + * Compute and read in starting bitmap block for starting block. + */ + block = XFS_BITTOBLOCK(mp, start); + error = xfs_rtbuf_get(mp, tp, block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + /* + * Get the first word's index & point to it. + */ + word = XFS_BITTOWORD(mp, start); + b = &bufp[word]; + bit = (int)(start & (XFS_NBWORD - 1)); + len = limit - start + 1; + /* + * Compute match value, based on the bit at start: if 1 (free) + * then all-ones, else all-zeroes. + */ + want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0; + /* + * If the starting position is not word-aligned, deal with the + * partial word. + */ + if (bit) { + /* + * Calculate last (rightmost) bit number to look at, + * and mask for all the relevant bits in this word. + */ + lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); + mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; + /* + * Calculate the difference between the value there + * and what we're looking for. + */ + if ((wdiff = (*b ^ want) & mask)) { + /* + * Different. Mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i = XFS_RTLOBIT(wdiff) - bit; + *rtblock = start + i - 1; + return 0; + } + i = lastbit - bit; + /* + * Go on to next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * If done with this block, get the previous one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the previous word in the buffer. + */ + b++; + } + } else { + /* + * Starting on a word boundary, no partial word. + */ + i = 0; + } + /* + * Loop over whole words in buffers. When we use up one buffer + * we move on to the next one. + */ + while (len - i >= XFS_NBWORD) { + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = *b ^ want)) { + /* + * Different, mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_RTLOBIT(wdiff); + *rtblock = start + i - 1; + return 0; + } + i += XFS_NBWORD; + /* + * Go on to next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * If done with this block, get the next one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the next word in the buffer. + */ + b++; + } + } + /* + * If not ending on a word boundary, deal with the last + * (partial) word. + */ + if ((lastbit = len - i)) { + /* + * Calculate mask for all the relevant bits in this word. + */ + mask = ((xfs_rtword_t)1 << lastbit) - 1; + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = (*b ^ want) & mask)) { + /* + * Different, mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_RTLOBIT(wdiff); + *rtblock = start + i - 1; + return 0; + } else + i = len; + } + /* + * No match, return that we scanned the whole area. + */ + xfs_trans_brelse(tp, bp); + *rtblock = start + i - 1; + return 0; +} + +/* + * Mark an extent specified by start and len freed. + * Updates all the summary information as well as the bitmap. + */ +STATIC int /* error */ +xfs_rtfree_range( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to free */ + xfs_extlen_t len, /* length to free */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb) /* in/out: summary block number */ +{ + xfs_rtblock_t end; /* end of the freed extent */ + int error; /* error value */ + xfs_rtblock_t postblock; /* first block freed > end */ + xfs_rtblock_t preblock; /* first block freed < start */ + + end = start + len - 1; + /* + * Modify the bitmap to mark this extent freed. + */ + error = xfs_rtmodify_range(mp, tp, start, len, 1); + if (error) { + return error; + } + /* + * Assume we're freeing out of the middle of an allocated extent. + * We need to find the beginning and end of the extent so we can + * properly update the summary. + */ + error = xfs_rtfind_back(mp, tp, start, 0, &preblock); + if (error) { + return error; + } + /* + * Find the next allocated block (end of allocated extent). + */ + error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1, + &postblock); + /* + * If there are blocks not being freed at the front of the + * old extent, add summary data for them to be allocated. + */ + if (preblock < start) { + error = xfs_rtmodify_summary(mp, tp, + XFS_RTBLOCKLOG(start - preblock), + XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb); + if (error) { + return error; + } + } + /* + * If there are blocks not being freed at the end of the + * old extent, add summary data for them to be allocated. + */ + if (postblock > end) { + error = xfs_rtmodify_summary(mp, tp, + XFS_RTBLOCKLOG(postblock - end), + XFS_BITTOBLOCK(mp, end + 1), -1, rbpp, rsb); + if (error) { + return error; + } + } + /* + * Increment the summary information corresponding to the entire + * (new) free extent. + */ + error = xfs_rtmodify_summary(mp, tp, + XFS_RTBLOCKLOG(postblock + 1 - preblock), + XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb); + return error; +} + +/* + * Set the given range of bitmap bits to the given value. + * Do whatever I/O and logging is required. + */ +STATIC int /* error */ +xfs_rtmodify_range( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to modify */ + xfs_extlen_t len, /* length of extent to modify */ + int val) /* 1 for free, 0 for allocated */ +{ + xfs_rtword_t *b; /* current word in buffer */ + int bit; /* bit number in the word */ + xfs_rtblock_t block; /* bitmap block number */ + xfs_buf_t *bp; /* buf for the block */ + xfs_rtword_t *bufp; /* starting word in buffer */ + int error; /* error value */ + xfs_rtword_t *first; /* first used word in the buffer */ + int i; /* current bit number rel. to start */ + int lastbit; /* last useful bit in word */ + xfs_rtword_t mask; /* mask o frelevant bits for value */ + int word; /* word number in the buffer */ + + /* + * Compute starting bitmap block number. + */ + block = XFS_BITTOBLOCK(mp, start); + /* + * Read the bitmap block, and point to its data. + */ + error = xfs_rtbuf_get(mp, tp, block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + /* + * Compute the starting word's address, and starting bit. + */ + word = XFS_BITTOWORD(mp, start); + first = b = &bufp[word]; + bit = (int)(start & (XFS_NBWORD - 1)); + /* + * 0 (allocated) => all zeroes; 1 (free) => all ones. + */ + val = -val; + /* + * If not starting on a word boundary, deal with the first + * (partial) word. + */ + if (bit) { + /* + * Compute first bit not changed and mask of relevant bits. + */ + lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); + mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; + /* + * Set/clear the active bits. + */ + if (val) + *b |= mask; + else + *b &= ~mask; + i = lastbit - bit; + /* + * Go on to the next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * Log the changed part of this block. + * Get the next one. + */ + xfs_trans_log_buf(tp, bp, + (uint)((char *)first - (char *)bufp), + (uint)((char *)b - (char *)bufp)); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + first = b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the next word in the buffer + */ + b++; + } + } else { + /* + * Starting on a word boundary, no partial word. + */ + i = 0; + } + /* + * Loop over whole words in buffers. When we use up one buffer + * we move on to the next one. + */ + while (len - i >= XFS_NBWORD) { + /* + * Set the word value correctly. + */ + *b = val; + i += XFS_NBWORD; + /* + * Go on to the next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * Log the changed part of this block. + * Get the next one. + */ + xfs_trans_log_buf(tp, bp, + (uint)((char *)first - (char *)bufp), + (uint)((char *)b - (char *)bufp)); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + first = b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the next word in the buffer + */ + b++; + } + } + /* + * If not ending on a word boundary, deal with the last + * (partial) word. + */ + if ((lastbit = len - i)) { + /* + * Compute a mask of relevant bits. + */ + bit = 0; + mask = ((xfs_rtword_t)1 << lastbit) - 1; + /* + * Set/clear the active bits. + */ + if (val) + *b |= mask; + else + *b &= ~mask; + b++; + } + /* + * Log any remaining changed bytes. + */ + if (b > first) + xfs_trans_log_buf(tp, bp, (uint)((char *)first - (char *)bufp), + (uint)((char *)b - (char *)bufp - 1)); + return 0; +} + +/* + * Read and modify the summary information for a given extent size, + * bitmap block combination. + * Keeps track of a current summary block, so we don't keep reading + * it from the buffer cache. + */ +STATIC int /* error */ +xfs_rtmodify_summary( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + int log, /* log2 of extent size */ + xfs_rtblock_t bbno, /* bitmap block number */ + int delta, /* change to make to summary info */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb) /* in/out: summary block number */ +{ + xfs_buf_t *bp; /* buffer for the summary block */ + int error; /* error value */ + xfs_fsblock_t sb; /* summary fsblock */ + int so; /* index into the summary file */ + xfs_suminfo_t *sp; /* pointer to returned data */ + + /* + * Compute entry number in the summary file. + */ + so = XFS_SUMOFFS(mp, log, bbno); + /* + * Compute the block number in the summary file. + */ + sb = XFS_SUMOFFSTOBLOCK(mp, so); + /* + * If we have an old buffer, and the block number matches, use that. + */ + if (rbpp && *rbpp && *rsb == sb) + bp = *rbpp; + /* + * Otherwise we have to get the buffer. + */ + else { + /* + * If there was an old one, get rid of it first. + */ + if (rbpp && *rbpp) + xfs_trans_brelse(tp, *rbpp); + error = xfs_rtbuf_get(mp, tp, sb, 1, &bp); + if (error) { + return error; + } + /* + * Remember this buffer and block for the next call. + */ + if (rbpp) { + *rbpp = bp; + *rsb = sb; + } + } + /* + * Point to the summary information, modify and log it. + */ + sp = XFS_SUMPTR(mp, bp, so); + *sp += delta; + xfs_trans_log_buf(tp, bp, (uint)((char *)sp - (char *)XFS_BUF_PTR(bp)), + (uint)((char *)sp - (char *)XFS_BUF_PTR(bp) + sizeof(*sp) - 1)); + return 0; +} + +/* + * Free an extent in the realtime subvolume. Length is expressed in + * realtime extents, as is the block number. + */ +int /* error */ +xfs_rtfree_extent( + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number to free */ + xfs_extlen_t len) /* length of extent freed */ +{ + int error; /* error value */ + xfs_inode_t *ip; /* bitmap file inode */ + xfs_mount_t *mp; /* file system mount structure */ + xfs_fsblock_t sb; /* summary file block number */ + xfs_buf_t *sumbp; /* summary file block buffer */ + + mp = tp->t_mountp; + /* + * Synchronize by locking the bitmap inode. + */ + error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip); + if (error) { + return error; + } +#if defined(__KERNEL__) && defined(DEBUG) + /* + * Check to see that this whole range is currently allocated. + */ + { + int stat; /* result from checking range */ + + error = xfs_rtcheck_alloc_range(mp, tp, bno, len, &stat); + if (error) { + return error; + } + ASSERT(stat); + } +#endif + sumbp = NULL; + /* + * Free the range of realtime blocks. + */ + error = xfs_rtfree_range(mp, tp, bno, len, &sumbp, &sb); + if (error) { + return error; + } + /* + * Mark more blocks free in the superblock. + */ + xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len); + /* + * If we've now freed all the blocks, reset the file sequence + * number to 0. + */ + if (tp->t_frextents_delta + mp->m_sb.sb_frextents == + mp->m_sb.sb_rextents) { + if (!(ip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) + ip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM; + *(__uint64_t *)&ip->i_d.di_atime = 0; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + } + return 0; +} + +/* + * Initialize realtime fields in the mount structure. + */ +int /* error */ +xfs_rtmount_init( + xfs_mount_t *mp) /* file system mount structure */ +{ + xfs_buf_t *bp; /* buffer for last block of subvolume */ + xfs_daddr_t d; /* address of last block of subvolume */ + int error; /* error return value */ + xfs_sb_t *sbp; /* filesystem superblock copy in mount */ + + sbp = &mp->m_sb; + if (sbp->sb_rblocks == 0) + return 0; + if (!mp->m_rtdev) { + printk(KERN_WARNING + "XFS: This FS has an RT subvol - specify -o rtdev on mount\n"); + return XFS_ERROR(ENODEV); + } + mp->m_rsumlevels = sbp->sb_rextslog + 1; + mp->m_rsumsize = + (uint)sizeof(xfs_suminfo_t) * mp->m_rsumlevels * + sbp->sb_rbmblocks; + mp->m_rsumsize = roundup(mp->m_rsumsize, sbp->sb_blocksize); + mp->m_rbmip = mp->m_rsumip = NULL; + /* + * Check that the realtime section is an ok size. + */ + d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks); + if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_rblocks) { + printk(KERN_WARNING "XFS: RT mount - %llu != %llu\n", + XFS_BB_TO_FSB(mp, d), mp->m_sb.sb_rblocks); + return XFS_ERROR(E2BIG); + } + error = xfs_read_buf(mp, &mp->m_rtdev_targ, d - 1, 1, 0, &bp); + if (error) { + printk(KERN_WARNING + "XFS: RT mount - xfs_read_buf returned %d\n", error); + if (error == ENOSPC) + return XFS_ERROR(E2BIG); + return error; + } + xfs_buf_relse(bp); + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_rtbit.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_rtbit.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_rtbit.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_rtbit.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * XFS bit manipulation routines, used only in realtime code. + */ + +#include + +/* + * xfs_lowbit32: get low bit set out of 32-bit argument, -1 if none set. + */ +int +xfs_lowbit32( + __uint32_t v) +{ + int i; + + if (v & 0x0000ffff) + if (v & 0x000000ff) + i = 0; + else + i = 8; + else if (v & 0xffff0000) + if (v & 0x00ff0000) + i = 16; + else + i = 24; + else + return -1; + return i + xfs_lowbit[(v >> i) & 0xff]; +} diff -rNu linux-2.4.7/cmd/xfsprogs/libxfs/xfs_trans.c linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_trans.c --- linux-2.4.7/cmd/xfsprogs/libxfs/xfs_trans.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/libxfs/xfs_trans.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * Initialize the precomputed transaction reservation values + * in the mount structure. + */ +void +xfs_trans_init( + xfs_mount_t *mp) +{ + xfs_trans_reservations_t *resp; + + resp = &(mp->m_reservations); + resp->tr_write = + (uint)(XFS_CALC_WRITE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_itruncate = + (uint)(XFS_CALC_ITRUNCATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_rename = + (uint)(XFS_CALC_RENAME_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_link = (uint)XFS_CALC_LINK_LOG_RES(mp); + resp->tr_remove = + (uint)(XFS_CALC_REMOVE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_symlink = + (uint)(XFS_CALC_SYMLINK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_create = + (uint)(XFS_CALC_CREATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_mkdir = + (uint)(XFS_CALC_MKDIR_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_ifree = + (uint)(XFS_CALC_IFREE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_ichange = + (uint)(XFS_CALC_ICHANGE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_growdata = (uint)XFS_CALC_GROWDATA_LOG_RES(mp); + resp->tr_swrite = (uint)XFS_CALC_SWRITE_LOG_RES(mp); + resp->tr_writeid = (uint)XFS_CALC_WRITEID_LOG_RES(mp); + resp->tr_addafork = + (uint)(XFS_CALC_ADDAFORK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_attrinval = (uint)XFS_CALC_ATTRINVAL_LOG_RES(mp); + resp->tr_attrset = + (uint)(XFS_CALC_ATTRSET_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_attrrm = + (uint)(XFS_CALC_ATTRRM_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_clearagi = (uint)XFS_CALC_CLEAR_AGI_BUCKET_LOG_RES(mp); + resp->tr_growrtalloc = (uint)XFS_CALC_GROWRTALLOC_LOG_RES(mp); + resp->tr_growrtzero = (uint)XFS_CALC_GROWRTZERO_LOG_RES(mp); + resp->tr_growrtfree = (uint)XFS_CALC_GROWRTFREE_LOG_RES(mp); +} diff -rNu linux-2.4.7/cmd/xfsprogs/logprint/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/logprint/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/logprint/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/logprint/CVS/Entries Thu Jul 5 11:44:45 2001 @@ -0,0 +1,8 @@ +/Makefile/1.2/Mon Jan 15 06:52:52 2001/-ko/ +/log_misc.c/1.6/Fri Jun 22 13:39:31 2001// +/log_print_all.c/1.4/Tue Apr 10 06:02:37 2001/-ko/ +/log_print_trans.c/1.3/Tue Apr 10 06:02:37 2001// +/logprint.c/1.3/Wed May 9 06:56:06 2001// +/logprint.h/1.4/Wed May 9 06:56:06 2001/-ko/ +/xfs_log_recover.c/1.3/Thu Apr 12 23:42:32 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/logprint/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/logprint/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/logprint/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/logprint/CVS/Repository Thu Jul 5 11:44:44 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/logprint diff -rNu linux-2.4.7/cmd/xfsprogs/logprint/CVS/Root linux-2.4-xfs/cmd/xfsprogs/logprint/CVS/Root --- linux-2.4.7/cmd/xfsprogs/logprint/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/logprint/CVS/Root Thu Jul 5 11:44:44 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/logprint/Makefile linux-2.4-xfs/cmd/xfsprogs/logprint/Makefile --- linux-2.4.7/cmd/xfsprogs/logprint/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/logprint/Makefile Mon Jan 15 00:52:52 2001 @@ -0,0 +1,51 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = xfs_logprint + +CFILES = log_print_trans.c log_print_all.c log_misc.c logprint.c \ + xfs_log_recover.c +HFILES = logprint.h +LLDLIBS = $(LIBXFS) $(LIBUUID) +LLDFLAGS = -L$(TOPDIR)/libxfs + +default: $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_BIN_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/xfsprogs/logprint/log_misc.c linux-2.4-xfs/cmd/xfsprogs/logprint/log_misc.c --- linux-2.4.7/cmd/xfsprogs/logprint/log_misc.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/logprint/log_misc.c Fri Jun 22 08:39:31 2001 @@ -0,0 +1,1281 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "logprint.h" + +#define ZEROED_LOG (-4) +#define FULL_READ (-3) +#define PARTIAL_READ (-2) +#define BAD_HEADER (-1) +#define NO_ERROR (0) + +static int logBBsize; +char *trans_type[] = { + "", + "SETATTR", + "SETATTR_SIZE", + "INACTIVE", + "CREATE", + "CREATE_TRUNC", + "TRUNCATE_FILE", + "REMOVE", + "LINK", + "RENAME", + "MKDIR", + "RMDIR", + "SYMLINK", + "SET_DMATTRS", + "GROWFS", + "STRAT_WRITE", + "DIOSTRAT", + "WRITE_SYNC", + "WRITEID", + "ADDAFORK", + "ATTRINVAL", + "ATRUNCATE", + "ATTR_SET", + "ATTR_RM", + "ATTR_FLAG", + "CLEAR_AGI_BUCKET", + "QM_SBCHANGE", + "DUMMY1", + "DUMMY2", + "QM_QUOTAOFF", + "QM_DQALLOC", + "QM_SETQLIM", + "QM_DQCLUSTER", + "QM_QINOCREATE", + "QM_QUOTAOFF_END", + "SB_UNIT", + "FSYNC_TS", + "GROWFSRT_ALLOC", + "GROWFSRT_ZERO", + "GROWFSRT_FREE", + "SWAPEXT", +}; + +typedef struct xlog_split_item { + struct xlog_split_item *si_next; + struct xlog_split_item *si_prev; + xlog_tid_t si_tid; + int si_skip; +} xlog_split_item_t; + +xlog_split_item_t *split_list = 0; + +void +print_xlog_op_line(void) +{ + printf("--------------------------------------" + "--------------------------------------\n"); +} /* print_xlog_op_line */ + +void +print_xlog_record_line(void) +{ + printf("======================================" + "======================================\n"); +} /* print_xlog_record_line */ + +void +print_stars(void) +{ + printf("***********************************" + "***********************************\n"); +} /* print_xlog_record_line */ + +/* + * Given a pointer to a data segment, print out the data as if it were + * a log operation header. + */ +void +xlog_print_op_header(xlog_op_header_t *op_head, + int i, + xfs_caddr_t *ptr) +{ + xlog_op_header_t hbuf; + + /* + * bcopy because on 64/n32, partial reads can cause the op_head + * pointer to come in pointing to an odd-numbered byte + */ + bcopy(op_head, &hbuf, sizeof(xlog_op_header_t)); + op_head = &hbuf; + *ptr += sizeof(xlog_op_header_t); + printf("Oper (%d): tid: %x len: %d clientid: %s ", i, + INT_GET(op_head->oh_tid, ARCH_CONVERT), + INT_GET(op_head->oh_len, ARCH_CONVERT), + (op_head->oh_clientid == XFS_TRANSACTION ? "TRANS" : + (op_head->oh_clientid == XFS_LOG ? "LOG" : "ERROR"))); + printf("flags: "); + if (op_head->oh_flags) { + if (op_head->oh_flags & XLOG_START_TRANS) + printf("START "); + if (op_head->oh_flags & XLOG_COMMIT_TRANS) + printf("COMMIT "); + if (op_head->oh_flags & XLOG_WAS_CONT_TRANS) + printf("WAS_CONT "); + if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) + printf("UNMOUNT "); + if (op_head->oh_flags & XLOG_CONTINUE_TRANS) + printf("CONTINUE "); + if (op_head->oh_flags & XLOG_END_TRANS) + printf("END "); + } else { + printf("none"); + } + printf("\n"); +} /* xlog_print_op_header */ + + +void +xlog_print_add_to_trans(xlog_tid_t tid, + int skip) +{ + xlog_split_item_t *item; + + item = (xlog_split_item_t *)calloc(sizeof(xlog_split_item_t), 1); + item->si_tid = tid; + item->si_skip = skip; + item->si_next = split_list; + item->si_prev = 0; + if (split_list) + split_list->si_prev = item; + split_list = item; +} /* xlog_print_add_to_trans */ + + +int +xlog_print_find_tid(xlog_tid_t tid, uint was_cont) +{ + xlog_split_item_t *listp = split_list; + + if (!split_list) { + if (was_cont != 0) /* Not first time we have used this tid */ + return 1; + else + return 0; + } + while (listp) { + if (listp->si_tid == tid) + break; + listp = listp->si_next; + } + if (!listp) { + return 0; + } + if (--listp->si_skip == 0) { + if (listp == split_list) { /* delete at head */ + split_list = listp->si_next; + if (split_list) + split_list->si_prev = NULL; + } else { + if (listp->si_next) + listp->si_next->si_prev = listp->si_prev; + listp->si_prev->si_next = listp->si_next; + } + free(listp); + } + return 1; +} /* xlog_print_find_tid */ + +int +xlog_print_trans_header(xfs_caddr_t *ptr, int len) +{ + xfs_trans_header_t *h; + xfs_caddr_t cptr = *ptr; + __uint32_t magic; + char *magic_c = (char *)&magic; + + *ptr += len; + + magic=*(__uint32_t*)cptr; /* XXX INT_GET soon */ + + if (len >= 4) { +#if __BYTE_ORDER == __LITTLE_ENDIAN + printf("%c%c%c%c:", + magic_c[3], magic_c[2], magic_c[1], magic_c[0]); +#else + printf("%c%c%c%c:", + magic_c[0], magic_c[1], magic_c[2], magic_c[3]); +#endif + } + if (len != sizeof(xfs_trans_header_t)) { + printf(" Not enough data to decode further\n"); + return 1; + } + h = (xfs_trans_header_t *)cptr; + printf(" type: %s tid: %x num_items: %d\n", + trans_type[h->th_type], h->th_tid, h->th_num_items); + return 0; +} /* xlog_print_trans_header */ + + +int +xlog_print_trans_buffer(xfs_caddr_t *ptr, int len, int *i, int num_ops) +{ + xfs_buf_log_format_t *f; + xfs_buf_log_format_v1_t *old_f; + xfs_agi_t *agi; + xfs_agf_t *agf; + xfs_disk_dquot_t *dq; + xlog_op_header_t *head = 0; + int num, skip; + int super_block = 0; + int bucket, col, buckets; + __int64_t blkno; + xfs_buf_log_format_t lbuf; + int size, blen, map_size, struct_size; + long long x, y; + + /* + * bcopy to ensure 8-byte alignment for the long longs in + * buf_log_format_t structure + */ + bcopy(*ptr, &lbuf, MIN(sizeof(xfs_buf_log_format_t), len)); + f = &lbuf; + *ptr += len; + + if (f->blf_type == XFS_LI_BUF) { + blkno = f->blf_blkno; + size = f->blf_size; + blen = f->blf_len; + map_size = f->blf_map_size; + struct_size = sizeof(xfs_buf_log_format_t); + } else { + old_f = (xfs_buf_log_format_v1_t*)f; + blkno = old_f->blf_blkno; + size = old_f->blf_size; + blen = old_f->blf_len; + map_size = old_f->blf_map_size; + struct_size = sizeof(xfs_buf_log_format_v1_t); + } + switch (f->blf_type) { + case XFS_LI_BUF: + printf("BUF: "); + break; + case XFS_LI_6_1_BUF: + printf("6.1 BUF: "); + break; + case XFS_LI_5_3_BUF: + printf("5.3 BUF: "); + break; + default: + printf("UNKNOWN BUF: "); + break; + } + if (len >= struct_size) { + ASSERT((len - sizeof(struct_size)) % sizeof(int) == 0); + printf("#regs: %d start blkno: %lld (0x%llx) len: %d bmap size: %d\n", + size, (long long)blkno, (unsigned long long)blkno, blen, map_size); + if (blkno == 0) + super_block = 1; + } else { + ASSERT(len >= 4); /* must have at least 4 bytes if != 0 */ + printf("#regs: %d Not printing rest of data\n", f->blf_size); + return size; + } + num = size-1; + + /* Check if all regions in this log item were in the given LR ptr */ + if (*i+num > num_ops-1) { + skip = num - (num_ops-1-*i); + num = num_ops-1-*i; + } else { + skip = 0; + } + while (num-- > 0) { + (*i)++; + head = (xlog_op_header_t *)*ptr; + xlog_print_op_header(head, *i, ptr); + if (super_block) { + printf("SUPER BLOCK Buffer: "); + if (INT_GET(head->oh_len, ARCH_CONVERT) < 4*8) { + printf("Out of space\n"); + } else { + printf("\n"); + /* + * bcopy because *ptr may not be 8-byte aligned + */ + bcopy(*ptr, &x, sizeof(long long)); + bcopy(*ptr+8, &y, sizeof(long long)); + printf("icount: %lld ifree: %lld ", + INT_GET(x, ARCH_CONVERT), + INT_GET(y, ARCH_CONVERT)); + bcopy(*ptr+16, &x, sizeof(long long)); + bcopy(*ptr+24, &y, sizeof(long long)); + printf("fdblks: %lld frext: %lld\n", + INT_GET(x, ARCH_CONVERT), + INT_GET(y, ARCH_CONVERT)); + } + super_block = 0; + } else if (INT_GET(*(uint *)(*ptr), ARCH_CONVERT) == XFS_AGI_MAGIC) { + agi = (xfs_agi_t *)(*ptr); + printf("AGI Buffer: XAGI "); + if (INT_GET(head->oh_len, ARCH_CONVERT) < + sizeof(xfs_agi_t) - + XFS_AGI_UNLINKED_BUCKETS*sizeof(xfs_agino_t)) { + printf("out of space\n"); + } else { + printf("\n"); + printf("ver: %d ", + INT_GET(agi->agi_versionnum, ARCH_CONVERT)); + printf("seq#: %d len: %d cnt: %d root: %d\n", + INT_GET(agi->agi_seqno, ARCH_CONVERT), + INT_GET(agi->agi_length, ARCH_CONVERT), + INT_GET(agi->agi_count, ARCH_CONVERT), + INT_GET(agi->agi_root, ARCH_CONVERT)); + printf("level: %d free#: 0x%x newino: 0x%x\n", + INT_GET(agi->agi_level, ARCH_CONVERT), + INT_GET(agi->agi_freecount, ARCH_CONVERT), + INT_GET(agi->agi_newino, ARCH_CONVERT)); + if (INT_GET(head->oh_len, ARCH_CONVERT) == 128) { + buckets = 17; + } else if (INT_GET(head->oh_len, ARCH_CONVERT) == 256) { + buckets = 32 + 17; + } else { + if (head->oh_flags & XLOG_CONTINUE_TRANS) { + printf("AGI unlinked data skipped "); + printf("(CONTINUE set, no space)\n"); + continue; + } + buckets = XFS_AGI_UNLINKED_BUCKETS; + } + for (bucket = 0; bucket < buckets;) { + printf("bucket[%d - %d]: ", bucket, bucket+3); + for (col = 0; col < 4; col++, bucket++) { + if (bucket < buckets) { + printf("0x%x ", + INT_GET(agi->agi_unlinked[bucket], ARCH_CONVERT)); + } + } + printf("\n"); + } + } + } else if (INT_GET(*(uint *)(*ptr), ARCH_CONVERT) == XFS_AGF_MAGIC) { + agf = (xfs_agf_t *)(*ptr); + printf("AGF Buffer: XAGF "); + if (INT_GET(head->oh_len, ARCH_CONVERT) < sizeof(xfs_agf_t)) { + printf("Out of space\n"); + } else { + printf("\n"); + printf("ver: %d seq#: %d len: %d \n", + INT_GET(agf->agf_versionnum, ARCH_CONVERT), + INT_GET(agf->agf_seqno, ARCH_CONVERT), + INT_GET(agf->agf_length, ARCH_CONVERT)); + printf("root BNO: %d CNT: %d\n", + INT_GET(agf->agf_roots[XFS_BTNUM_BNOi], + ARCH_CONVERT), + INT_GET(agf->agf_roots[XFS_BTNUM_CNTi], + ARCH_CONVERT)); + printf("level BNO: %d CNT: %d\n", + INT_GET(agf->agf_levels[XFS_BTNUM_BNOi], + ARCH_CONVERT), + INT_GET(agf->agf_levels[XFS_BTNUM_CNTi], + ARCH_CONVERT)); + printf("1st: %d last: %d cnt: %d " + "freeblks: %d longest: %d\n", + INT_GET(agf->agf_flfirst, ARCH_CONVERT), + INT_GET(agf->agf_fllast, ARCH_CONVERT), + INT_GET(agf->agf_flcount, ARCH_CONVERT), + INT_GET(agf->agf_freeblks, ARCH_CONVERT), + INT_GET(agf->agf_longest, ARCH_CONVERT)); + } + } else if (INT_GET(*(uint *)(*ptr), ARCH_CONVERT) == XFS_DQUOT_MAGIC) { + dq = (xfs_disk_dquot_t *)(*ptr); + printf("DQUOT Buffer: DQ "); + if (INT_GET(head->oh_len, ARCH_CONVERT) < + sizeof(xfs_disk_dquot_t)) { + printf("Out of space\n"); + } + else { + printf("\n"); + printf("ver: %d flags: 0x%x id: %d \n", + INT_GET(dq->d_version, ARCH_CONVERT), + INT_GET(dq->d_flags, ARCH_CONVERT), + INT_GET(dq->d_id, ARCH_CONVERT)); + printf("blk limits hard: %llu soft: %llu\n", + (unsigned long long) + INT_GET(dq->d_blk_hardlimit, ARCH_CONVERT), + (unsigned long long) + INT_GET(dq->d_blk_softlimit, ARCH_CONVERT)); + printf("blk count: %llu warns: %d timer: %d\n", + (unsigned long long) + INT_GET(dq->d_bcount, ARCH_CONVERT), + INT_GET(dq->d_bwarns, ARCH_CONVERT), + INT_GET(dq->d_btimer, ARCH_CONVERT)); + printf("ino limits hard: %llu soft: %llu\n", + (unsigned long long) + INT_GET(dq->d_ino_hardlimit, ARCH_CONVERT), + (unsigned long long) + INT_GET(dq->d_ino_softlimit, ARCH_CONVERT)); + printf("ino count: %llu warns: %d timer: %d\n", + (unsigned long long) + INT_GET(dq->d_icount, ARCH_CONVERT), + INT_GET(dq->d_iwarns, ARCH_CONVERT), + INT_GET(dq->d_itimer, ARCH_CONVERT)); + } + } else { + printf("BUF DATA\n"); + if (print_data) { + uint *dp = (uint *)*ptr; + int nums = INT_GET(head->oh_len, ARCH_CONVERT) >> 2; + int i = 0; + + while (i < nums) { + if ((i % 8) == 0) + printf("%2x ", i); + printf("%8x ", *dp); + dp++; + i++; + if ((i % 8) == 0) + printf("\n"); + } + printf("\n"); + } + } + *ptr += INT_GET(head->oh_len, ARCH_CONVERT); + } + if (head && head->oh_flags & XLOG_CONTINUE_TRANS) + skip++; + return skip; +} /* xlog_print_trans_buffer */ + + +int +xlog_print_trans_efd(xfs_caddr_t *ptr, uint len) +{ + xfs_efd_log_format_t *f; + xfs_extent_t *ex; + int i; + xfs_efd_log_format_t lbuf; + + /* + * bcopy to ensure 8-byte alignment for the long longs in + * xfs_efd_log_format_t structure + */ + bcopy(*ptr, &lbuf, sizeof(xfs_efd_log_format_t)); + f = &lbuf; + *ptr += len; + if (len >= sizeof(xfs_efd_log_format_t)) { + printf("EFD: #regs: %d num_extents: %d id: 0x%llx\n", + f->efd_size, f->efd_nextents, (unsigned long long)f->efd_efi_id); + ex = f->efd_extents; + for (i=0; i< f->efd_size; i++) { + printf("(s: 0x%llx, l: %d) ", + (unsigned long long)ex->ext_start, ex->ext_len); + if (i % 4 == 3) printf("\n"); + ex++; + } + if (i % 4 != 0) printf("\n"); + return 0; + } else { + printf("EFD: Not enough data to decode further\n"); + return 1; + } +} /* xlog_print_trans_efd */ + + +int +xlog_print_trans_efi(xfs_caddr_t *ptr, uint len) +{ + xfs_efi_log_format_t *f; + xfs_extent_t *ex; + int i; + xfs_efi_log_format_t lbuf; + + /* + * bcopy to ensure 8-byte alignment for the long longs in + * xfs_efi_log_format_t structure + */ + bcopy(*ptr, &lbuf, sizeof(xfs_efi_log_format_t)); + f = &lbuf; + *ptr += len; + if (len >= sizeof(xfs_efi_log_format_t)) { + printf("EFI: #regs: %d num_extents: %d id: 0x%llx\n", + f->efi_size, f->efi_nextents, (unsigned long long)f->efi_id); + ex = f->efi_extents; + for (i=0; i< f->efi_size; i++) { + printf("(s: 0x%llx, l: %d) ", + (unsigned long long)ex->ext_start, ex->ext_len); + if (i % 4 == 3) printf("\n"); + ex++; + } + if (i % 4 != 0) printf("\n"); + return 0; + } else { + printf("EFI: Not enough data to decode further\n"); + return 1; + } +} /* xlog_print_trans_efi */ + + +int +xlog_print_trans_qoff(xfs_caddr_t *ptr, uint len) +{ + xfs_qoff_logformat_t *f; + xfs_qoff_logformat_t lbuf; + + bcopy(*ptr, &lbuf, sizeof(xfs_qoff_logformat_t)); + f = &lbuf; + *ptr += len; + if (len >= sizeof(xfs_qoff_logformat_t)) { + printf("QOFF: #regs: %d flags: 0x%x\n", f->qf_size, f->qf_flags); + return 0; + } else { + printf("QOFF: Not enough data to decode further\n"); + return 1; + } +} /* xlog_print_trans_qoff */ + + +void +xlog_print_trans_inode_core(xfs_dinode_core_t *ip) +{ + printf("INODE CORE\n"); + printf("magic 0x%hx mode 0%ho version %d format %d\n", + ip->di_magic, ip->di_mode, (int)ip->di_version, + (int)ip->di_format); + printf("nlink %hd uid %d gid %d\n", + ip->di_nlink, ip->di_uid, ip->di_gid); + printf("atime 0x%x mtime 0x%x ctime 0x%x\n", + ip->di_atime.t_sec, ip->di_mtime.t_sec, ip->di_ctime.t_sec); + printf("size 0x%llx nblocks 0x%llx extsize 0x%x nextents 0x%x\n", + (unsigned long long)ip->di_size, (unsigned long long)ip->di_nblocks, + ip->di_extsize, ip->di_nextents); + printf("naextents 0x%x forkoff %d dmevmask 0x%x dmstate 0x%hx\n", + ip->di_anextents, (int)ip->di_forkoff, ip->di_dmevmask, + ip->di_dmstate); + printf("flags 0x%x gen 0x%x\n", + ip->di_flags, ip->di_gen); +} + +void +xlog_print_dir_sf(xfs_dir_shortform_t *sfp, int size) +{ + xfs_ino_t ino; + int count; + int i; + char namebuf[257]; + xfs_dir_sf_entry_t *sfep; + + /* XXX need to determine whether this is v1 or v2, then + print appropriate structure */ + + printf("SHORTFORM DIRECTORY size %d\n", + size); + /* bail out for now */ + + return; + + printf("SHORTFORM DIRECTORY size %d count %d\n", + size, sfp->hdr.count); + bcopy(&(sfp->hdr.parent), &ino, sizeof(ino)); + printf(".. ino 0x%llx\n", (unsigned long long)INT_GET(ino, ARCH_CONVERT)); + + count = (uint)(sfp->hdr.count); + sfep = &(sfp->list[0]); + for (i = 0; i < count; i++) { + bcopy(&(sfep->inumber), &ino, sizeof(ino)); + bcopy((sfep->name), namebuf, sfep->namelen); + namebuf[sfep->namelen] = '\0'; + printf("%s ino 0x%llx namelen %d\n", + namebuf, (unsigned long long)ino, sfep->namelen); + sfep = XFS_DIR_SF_NEXTENTRY(sfep); + } +} + +int +xlog_print_trans_inode(xfs_caddr_t *ptr, int len, int *i, int num_ops) +{ + xfs_inode_log_format_t *f; + xfs_inode_log_format_t_v1 *old_f; + xfs_dinode_core_t dino; + xlog_op_header_t *op_head; + int version; + xfs_inode_log_format_t lbuf = {0}; + int mode; + int size; + + /* + * print inode type header region + * + * bcopy to ensure 8-byte alignment for the long longs in + * xfs_inode_log_format_t structure + * + * len can be smaller than xfs_inode_log_format_t sometimes... (?) + */ + bcopy(*ptr, &lbuf, MIN(sizeof(xfs_inode_log_format_t), len)); + version = lbuf.ilf_type; + f = &lbuf; + (*i)++; /* bump index */ + *ptr += len; + if (version == XFS_LI_5_3_INODE) { + old_f = (xfs_inode_log_format_t_v1 *)f; + if (len == sizeof(xfs_inode_log_format_t_v1)) { + printf("5.3 INODE: #regs: %d ino: 0x%llx flags: 0x%x dsize: %d\n", + old_f->ilf_size, (unsigned long long)old_f->ilf_ino, + old_f->ilf_fields, old_f->ilf_dsize); + } else { + ASSERT(len >= 4); /* must have at least 4 bytes if != 0 */ + printf("5.3 INODE: #regs: %d Not printing rest of data\n", + old_f->ilf_size); + return old_f->ilf_size; + } + } else { + if (len == sizeof(xfs_inode_log_format_t)) { + if (version == XFS_LI_6_1_INODE) + printf("6.1 INODE: "); + else printf("INODE: "); + printf("#regs: %d ino: 0x%llx flags: 0x%x dsize: %d\n", + f->ilf_size, (unsigned long long)f->ilf_ino, + f->ilf_fields, f->ilf_dsize); + printf(" blkno: %lld len: %d boff: %d\n", + (long long)f->ilf_blkno, f->ilf_len, f->ilf_boffset); + } else { + ASSERT(len >= 4); /* must have at least 4 bytes if != 0 */ + printf("INODE: #regs: %d Not printing rest of data\n", + f->ilf_size); + return f->ilf_size; + } + } + + if (*i >= num_ops) /* end of LR */ + return f->ilf_size-1; + + /* core inode comes 2nd */ + op_head = (xlog_op_header_t *)*ptr; + xlog_print_op_header(op_head, *i, ptr); + + if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) { + return f->ilf_size-1; + } + + bcopy(*ptr, &dino, sizeof(dino)); + mode = dino.di_mode & IFMT; + size = (int)dino.di_size; + xlog_print_trans_inode_core(&dino); + *ptr += sizeof(xfs_dinode_core_t); + + if (*i == num_ops-1 && f->ilf_size == 3) { + return 1; + } + + /* does anything come next */ + op_head = (xlog_op_header_t *)*ptr; + switch (f->ilf_fields & XFS_ILOG_NONCORE) { + case XFS_ILOG_DEXT: { + ASSERT(f->ilf_size == 3); + (*i)++; + xlog_print_op_header(op_head, *i, ptr); + printf("EXTENTS inode data\n"); + *ptr += INT_GET(op_head->oh_len, ARCH_CONVERT); + if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) { + return 1; + } + break; + } + case XFS_ILOG_DBROOT: { + ASSERT(f->ilf_size == 3); + (*i)++; + xlog_print_op_header(op_head, *i, ptr); + printf("BTREE inode data\n"); + *ptr += INT_GET(op_head->oh_len, ARCH_CONVERT); + if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) { + return 1; + } + break; + } + case XFS_ILOG_DDATA: { + ASSERT(f->ilf_size == 3); + (*i)++; + xlog_print_op_header(op_head, *i, ptr); + printf("LOCAL inode data\n"); + if (mode == IFDIR) { + xlog_print_dir_sf((xfs_dir_shortform_t*)*ptr, size); + } + *ptr += INT_GET(op_head->oh_len, ARCH_CONVERT); + if (XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) + return 1; + break; + } + case XFS_ILOG_DEV: { + ASSERT(f->ilf_size == 2); + printf("DEV inode: no extra region\n"); + break; + } + case XFS_ILOG_UUID: { + ASSERT(f->ilf_size == 2); + printf("UUID inode: no extra region\n"); + break; + } + case 0: { + ASSERT(f->ilf_size == 2); + break; + } + default: { + xlog_panic("xlog_print_trans_inode: illegal inode type"); + } + } + return 0; +} /* xlog_print_trans_inode */ + + +int +xlog_print_trans_dquot(xfs_caddr_t *ptr, int len, int *i, int num_ops) +{ + xfs_dq_logformat_t *f; + xfs_dq_logformat_t lbuf = {0}; + xfs_disk_dquot_t ddq; + xlog_op_header_t *head = NULL; + int num, skip; + + /* + * print dquot header region + * + * bcopy to ensure 8-byte alignment for the long longs in + * xfs_dq_logformat_t structure + */ + bcopy(*ptr, &lbuf, MIN(sizeof(xfs_dq_logformat_t), len)); + f = &lbuf; + (*i)++; /* bump index */ + *ptr += len; + + if (len == sizeof(xfs_dq_logformat_t)) { + printf("#regs: %d id: 0x%x", f->qlf_size, f->qlf_id); + printf(" blkno: %lld len: %d boff: %d\n", + (long long)f->qlf_blkno, f->qlf_len, f->qlf_boffset); + } else { + ASSERT(len >= 4); /* must have at least 4 bytes if != 0 */ + printf("DQUOT: #regs: %d Not printing rest of data\n", + f->qlf_size); + return f->qlf_size; + } + num = f->qlf_size-1; + + /* Check if all regions in this log item were in the given LR ptr */ + if (*i+num > num_ops-1) { + skip = num - (num_ops-1-*i); + num = num_ops-1-*i; + } else { + skip = 0; + } + + while (num-- > 0) { + head = (xlog_op_header_t *)*ptr; + xlog_print_op_header(head, *i, ptr); + ASSERT(INT_GET(head->oh_len, ARCH_CONVERT) == sizeof(xfs_disk_dquot_t)); + bcopy(*ptr, &ddq, sizeof(xfs_disk_dquot_t)); + printf("DQUOT: magic 0x%hx flags 0%ho\n", + INT_GET(ddq.d_magic, ARCH_CONVERT), + INT_GET(ddq.d_flags, ARCH_CONVERT)); + *ptr += INT_GET(head->oh_len, ARCH_CONVERT); + } + if (head && head->oh_flags & XLOG_CONTINUE_TRANS) + skip++; + return skip; +} /* xlog_print_trans_dquot */ + + +/****************************************************************************** + * + * Log print routines + * + ****************************************************************************** + */ + +void +xlog_print_lseek(xlog_t *log, int fd, xfs_daddr_t blkno, int whence) +{ +#define BBTOOFF64(bbs) (((xfs_off_t)(bbs)) << BBSHIFT) + xfs_off_t offset; + + if (whence == SEEK_SET) + offset = BBTOOFF64(blkno+log->l_logBBstart); + else + offset = BBTOOFF64(blkno); + if (lseek64(fd, offset, whence) < 0) { + fprintf(stderr, "%s: lseek64 to %llu failed: %s\n", + progname, (unsigned long long)offset, strerror(errno)); + exit(1); + } +} /* xlog_print_lseek */ + + +void +print_lsn(xfs_caddr_t string, + xfs_lsn_t *lsn, + xfs_arch_t arch) +{ + printf("%s: %u,%u", string, + CYCLE_LSN(*lsn, arch), BLOCK_LSN(*lsn, arch)); +} + + +int +xlog_print_record(int fd, + int num_ops, + int len, + int *read_type, + xfs_caddr_t *partial_buf, + xlog_rec_header_t *rhead) +{ + xlog_op_header_t *op_head; + xlog_rec_header_t *rechead; + xfs_caddr_t buf, ptr; + int read_len, skip; + int ret, n, i; + + if (print_no_print) + return NO_ERROR; + + if (!len) { + printf("\n"); + return NO_ERROR; + } + + /* read_len must read up to some block boundary */ + read_len = (int) BBTOB(BTOBB(len)); + + /* read_type => don't malloc() new buffer, use old one */ + if (*read_type == FULL_READ) { + if ((ptr = buf = (xfs_caddr_t)malloc(read_len)) == NULL) { + fprintf(stderr, "xlog_print_record: malloc failed\n"); + exit(1); + } + } else { + read_len -= *read_type; + buf = (xfs_caddr_t)((__psint_t)(*partial_buf) + (__psint_t)(*read_type)); + ptr = *partial_buf; + } + if ((ret = (int) read(fd, buf, read_len)) == -1) { + fprintf(stderr, "xlog_print_record: read error\n"); + exit(1); + } + /* Did we overflow the end? */ + if (*read_type == FULL_READ && + BLOCK_LSN(rhead->h_lsn, ARCH_CONVERT)+BTOBB(read_len) >= logBBsize) { + *read_type = BBTOB(logBBsize-BLOCK_LSN(rhead->h_lsn, ARCH_CONVERT)-1); + *partial_buf = buf; + return PARTIAL_READ; + } + + /* Did we read everything? */ + if ((ret == 0 && read_len != 0) || ret != read_len) { + *read_type = ret; + *partial_buf = buf; + return PARTIAL_READ; + } + if (*read_type != FULL_READ) + read_len += *read_type; + + /* Everything read in. Start from beginning of buffer */ + buf = ptr; + for (i = 0; ptr < buf + read_len; ptr += BBSIZE, i++) { + rechead = (xlog_rec_header_t *)ptr; + if (INT_GET(rechead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) { + xlog_print_lseek(0, fd, -read_len+i*BBSIZE, SEEK_CUR); + free(buf); + return -1; + } else { + if (INT_GET(rhead->h_cycle, ARCH_CONVERT) != + INT_GET(*(uint *)ptr, ARCH_CONVERT)) { + if (*read_type == FULL_READ) + return -1; + else if (INT_GET(rhead->h_cycle, ARCH_CONVERT) + 1 != + INT_GET(*(uint *)ptr, ARCH_CONVERT)) + return -1; + } + } + INT_SET(*(uint *)ptr, ARCH_CONVERT, + INT_GET(rhead->h_cycle_data[i], ARCH_CONVERT)); + } + ptr = buf; + for (i=0; ioh_flags, XLOG_WAS_CONT_TRANS) || + XLOG_SET(op_head->oh_flags, XLOG_CONTINUE_TRANS)) && + INT_GET(op_head->oh_len, ARCH_CONVERT) == 0)) { + for (n = 0; n < INT_GET(op_head->oh_len, ARCH_CONVERT); n++) { + printf("%c", *ptr); + ptr++; + } + printf("\n"); + continue; + } + if (xlog_print_find_tid(INT_GET(op_head->oh_tid, ARCH_CONVERT), + op_head->oh_flags & XLOG_WAS_CONT_TRANS)) { + printf("Left over region from split log item\n"); + ptr += INT_GET(op_head->oh_len, ARCH_CONVERT); + continue; + } + if (INT_GET(op_head->oh_len, ARCH_CONVERT) != 0) { + if (*(uint *)ptr == XFS_TRANS_HEADER_MAGIC) { + skip = xlog_print_trans_header(&ptr, + INT_GET(op_head->oh_len, ARCH_CONVERT)); + } else { + switch (*(unsigned short *)ptr) { + case XFS_LI_5_3_BUF: + case XFS_LI_6_1_BUF: + case XFS_LI_BUF: { + skip = xlog_print_trans_buffer(&ptr, + INT_GET(op_head->oh_len, ARCH_CONVERT), + &i, num_ops); + break; + } + case XFS_LI_5_3_INODE: + case XFS_LI_6_1_INODE: + case XFS_LI_INODE: { + skip = xlog_print_trans_inode(&ptr, + INT_GET(op_head->oh_len, ARCH_CONVERT), + &i, num_ops); + break; + } + case XFS_LI_DQUOT: { + skip = xlog_print_trans_dquot(&ptr, + INT_GET(op_head->oh_len, ARCH_CONVERT), + &i, num_ops); + break; + } + case XFS_LI_EFI: { + skip = xlog_print_trans_efi(&ptr, + INT_GET(op_head->oh_len, ARCH_CONVERT)); + break; + } + case XFS_LI_EFD: { + skip = xlog_print_trans_efd(&ptr, + INT_GET(op_head->oh_len, ARCH_CONVERT)); + break; + } + case XFS_LI_QUOTAOFF: { + skip = xlog_print_trans_qoff(&ptr, + INT_GET(op_head->oh_len, ARCH_CONVERT)); + break; + } + case XLOG_UNMOUNT_TYPE: { + printf("Unmount filesystem\n"); + skip = 0; + break; + } + default: { + fprintf(stderr, "%s: unknown log operation type (%x)\n", + progname, *(unsigned short *)ptr); + skip = 0; + ptr += INT_GET(op_head->oh_len, ARCH_CONVERT); + } + } /* switch */ + } /* else */ + if (skip != 0) + xlog_print_add_to_trans(INT_GET(op_head->oh_tid, ARCH_CONVERT), skip); + } + } + printf("\n"); + free(buf); + return NO_ERROR; +} /* xlog_print_record */ + + +int +xlog_print_rec_head(xlog_rec_header_t *head, int *len) +{ + int i; + char uub[64]; + int datalen,bbs; + + if (print_no_print) + return INT_GET(head->h_num_logops, ARCH_CONVERT); + + if (INT_ISZERO(head->h_magicno, ARCH_CONVERT)) + return ZEROED_LOG; + + if (INT_GET(head->h_magicno, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) { + printf("Header 0x%x wanted 0x%x\n", + INT_GET(head->h_magicno, ARCH_CONVERT), + XLOG_HEADER_MAGIC_NUM); + return BAD_HEADER; + } + + datalen=INT_GET(head->h_len, ARCH_CONVERT); + bbs=(datalen/BBSIZE)+(datalen%BBSIZE)?1:0; + + printf("cycle: %d version: %d ", + INT_GET(head->h_cycle, ARCH_CONVERT), + INT_GET(head->h_version, ARCH_CONVERT)); + print_lsn(" lsn", &head->h_lsn, ARCH_CONVERT); + print_lsn(" tail_lsn", &head->h_tail_lsn, ARCH_CONVERT); + printf("\n"); + printf("length of Log Record: %d prev offset: %d num ops: %d\n", + datalen, + INT_GET(head->h_prev_block, ARCH_CONVERT), + INT_GET(head->h_num_logops, ARCH_CONVERT)); + + if (print_overwrite) { + printf("cycle num overwrites: "); + for (i=0; i< bbs; i++) + printf("%d - 0x%x ", + i, + INT_GET(head->h_cycle_data[i], ARCH_CONVERT)); + printf("\n"); + } + + uuid_unparse(head->h_fs_uuid, uub); + printf("uuid: %s format: ", uub); + switch (INT_GET(head->h_fmt, ARCH_CONVERT)) { + case XLOG_FMT_UNKNOWN: + printf("unknown\n"); + break; + case XLOG_FMT_LINUX_LE: + printf("little endian linux\n"); + break; + case XLOG_FMT_LINUX_BE: + printf("big endian linux\n"); + break; + case XLOG_FMT_IRIX_BE: + printf("big endian irix\n"); + break; + default: + printf("? (%d)\n", INT_GET(head->h_fmt, ARCH_CONVERT)); + break; + } + + *len = INT_GET(head->h_len, ARCH_CONVERT); + return(INT_GET(head->h_num_logops, ARCH_CONVERT)); +} /* xlog_print_rec_head */ + +static void +print_xlog_bad_zeroed(xfs_daddr_t blkno) +{ + print_stars(); + printf("* ERROR: found data after zeroed blocks block=%-21lld *\n", + (long long)blkno); + print_stars(); + if (print_exit) + xlog_exit("Bad log - data after zeroed blocks"); +} /* print_xlog_bad_zeroed */ + +static void +print_xlog_bad_header(xfs_daddr_t blkno, xfs_caddr_t buf) +{ + print_stars(); + printf("* ERROR: header cycle=%-11d block=%-21lld *\n", + GET_CYCLE(buf, ARCH_CONVERT), (long long)blkno); + print_stars(); + if (print_exit) + xlog_exit("Bad log record header"); +} /* print_xlog_bad_header */ + +void +print_xlog_bad_data(xfs_daddr_t blkno) +{ + print_stars(); + printf("* ERROR: data block=%-21lld *\n", + (long long)blkno); + print_stars(); + if (print_exit) + xlog_exit("Bad data in log"); +} /* print_xlog_bad_data */ + + +/* + * This code is gross and needs to be rewritten. + */ +void xfs_log_print(xlog_t *log, + int fd, + int print_block_start) +{ + char hbuf[XLOG_HEADER_SIZE]; + int num_ops, len; + xfs_daddr_t block_end = 0, block_start, blkno, error; + int read_type = FULL_READ; + xfs_caddr_t partial_buf; + int zeroed = 0; + + logBBsize = log->l_logBBsize; + + /* + * Normally, block_start and block_end are the same value since we + * are printing the entire log. However, if the start block is given, + * we still end at the end of the logical log. + */ + if ((error = xlog_print_find_oldest(log, &block_end))) { + fprintf(stderr, "%s: problem finding oldest LR\n", progname); + return; + } + if (print_block_start == -1) + block_start = block_end; + else + block_start = print_block_start; + xlog_print_lseek(log, fd, block_start, SEEK_SET); + blkno = block_start; + + for (;;) { + if (read(fd, hbuf, 512) == 0) { + printf("%s: physical end of log\n", progname); + print_xlog_record_line(); + break; + } + if (print_only_data) { + printf("BLKNO: %lld\n", (long long)blkno); + xlog_recover_print_data(hbuf, 512); + blkno++; + goto loop; + } + num_ops = xlog_print_rec_head((xlog_rec_header_t *)hbuf, &len); + blkno++; + + if (zeroed && num_ops != ZEROED_LOG) { + printf("%s: after %d zeroed blocks\n", progname, zeroed); + /* once we find zeroed blocks - that's all we expect */ + print_xlog_bad_zeroed(blkno-1); + /* reset count since we're assuming previous zeroed blocks + * were bad + */ + zeroed = 0; + } + + if (num_ops == ZEROED_LOG || num_ops == BAD_HEADER) { + if (num_ops == ZEROED_LOG) { + zeroed++; + } else { + print_xlog_bad_header(blkno-1, hbuf); + } + + goto loop; + } + + error = xlog_print_record(fd, num_ops, len, &read_type, &partial_buf, + (xlog_rec_header_t *)hbuf); + switch (error) { + case 0: { + blkno += BTOBB(len); + if (print_block_start != -1 && + blkno >= block_end) /* If start specified, we */ + goto end; /* end early */ + break; + } + case -1: { + print_xlog_bad_data(blkno-1); + if (print_block_start != -1 && + blkno >= block_end) /* If start specified, */ + goto end; /* we end early */ + xlog_print_lseek(log, fd, blkno, SEEK_SET); + goto loop; + } + case PARTIAL_READ: { + print_xlog_record_line(); + printf("%s: physical end of log\n", progname); + print_xlog_record_line(); + blkno = 0; + xlog_print_lseek(log, fd, 0, SEEK_SET); + /* + * We may have hit the end of the log when we started at 0. + * In this case, just end. + */ + if (block_start == 0) + goto end; + goto partial_log_read; + } + default: xlog_panic("illegal value"); + } + print_xlog_record_line(); +loop: + if (blkno >= logBBsize) { + if (zeroed) { + printf("%s: skipped %d zeroed blocks\n", progname, zeroed); + if (zeroed == logBBsize) + printf("%s: totally zeroed log\n", progname); + + zeroed=0; + } + printf("%s: physical end of log\n", progname); + print_xlog_record_line(); + break; + } + } + + /* Do we need to print the first part of physical log? */ + if (block_start != 0) { + blkno = 0; + xlog_print_lseek(log, fd, 0, SEEK_SET); + for (;;) { + if (read(fd, hbuf, 512) == 0) { + xlog_panic("xlog_find_head: bad read"); + } + if (print_only_data) { + printf("BLKNO: %lld\n", (long long)blkno); + xlog_recover_print_data(hbuf, 512); + blkno++; + goto loop2; + } + num_ops = xlog_print_rec_head((xlog_rec_header_t *)hbuf, &len); + blkno++; + + if (num_ops == ZEROED_LOG || num_ops == BAD_HEADER) { + /* we only expect zeroed log entries at the end + * of the _physical_ log, so treat them the same + * as bad blocks here + */ + print_xlog_bad_header(blkno-1, hbuf); + + if (blkno >= block_end) + break; + continue; + } +partial_log_read: + error= xlog_print_record(fd, num_ops, len, &read_type, + &partial_buf, (xlog_rec_header_t *)hbuf); + if (read_type != FULL_READ) + len -= read_type; + read_type = FULL_READ; + if (!error) + blkno += BTOBB(len); + else { + print_xlog_bad_data(blkno-1); + xlog_print_lseek(log, fd, blkno, SEEK_SET); + goto loop2; + } + print_xlog_record_line(); +loop2: + if (blkno >= block_end) + break; + } + } + +end: + printf("%s: logical end of log\n", progname); + print_xlog_record_line(); +} diff -rNu linux-2.4.7/cmd/xfsprogs/logprint/log_print_all.c linux-2.4-xfs/cmd/xfsprogs/logprint/log_print_all.c --- linux-2.4.7/cmd/xfsprogs/logprint/log_print_all.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/logprint/log_print_all.c Tue Apr 10 01:02:37 2001 @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "logprint.h" + + +/* + * Start is defined to be the block pointing to the oldest valid log record. + * Used by log print code. Don't put in cmd/xfs/logprint/xfs_log_print.c + * since most of the bread routines live in kern/fs/xfs/xfs_log_recover only. + */ +int +xlog_print_find_oldest( + struct log *log, + xfs_daddr_t *last_blk) +{ + xfs_buf_t *bp; + xfs_daddr_t first_blk; + uint first_half_cycle, last_half_cycle; + int error; + + if (xlog_find_zeroed(log, &first_blk)) + return 0; + + first_blk = 0; /* read first block */ + bp = xlog_get_bp(1, log->l_mp); + xlog_bread(log, 0, 1, bp); + first_half_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + *last_blk = log->l_logBBsize-1; /* read last block */ + xlog_bread(log, *last_blk, 1, bp); + last_half_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + ASSERT(last_half_cycle != 0); + + if (first_half_cycle == last_half_cycle) { /* all cycle nos are same */ + *last_blk = 0; + } else { /* have 1st and last; look for middle cycle */ + error = xlog_find_cycle_start(log, bp, first_blk, + last_blk, last_half_cycle); + if (error) + return error; + } + + xlog_put_bp(bp); + return 0; +} /* xlog_print_find_oldest */ + + +void +xlog_recover_print_data( + xfs_caddr_t p, + int len) +{ + if (print_data) { + uint *dp = (uint *)p; + int nums = len >> 2; + int j = 0; + + while (j < nums) { + if ((j % 8) == 0) + printf("%2x ", j); + printf("%8x ", *dp); + dp++; + j++; + if ((j % 8) == 0) + printf("\n"); + } + printf("\n"); + } +} /* xlog_recover_print_data */ + + +STATIC void +xlog_recover_print_buffer( + xlog_recover_item_t *item) +{ + xfs_agi_t *agi; + xfs_agf_t *agf; + xfs_buf_log_format_v1_t *old_f; + xfs_buf_log_format_t *f; + xfs_caddr_t p; + int len, num, i; + xfs_daddr_t blkno; + xfs_disk_dquot_t *ddq; + + f = (xfs_buf_log_format_t *)item->ri_buf[0].i_addr; + old_f = (xfs_buf_log_format_v1_t *)f; + len = item->ri_buf[0].i_len; + printf(" "); + switch (f->blf_type) { + case XFS_LI_BUF: { + printf("BUF: "); + break; + } + case XFS_LI_6_1_BUF: { + printf("6.1 BUF: "); + break; + } + case XFS_LI_5_3_BUF: { + printf("5.3 BUF: "); + break; + } + } + if (f->blf_type == XFS_LI_BUF) { + printf("#regs:%d start blkno:0x%llx len:%d bmap size:%d\n", + f->blf_size, (long long)f->blf_blkno, f->blf_len, f->blf_map_size); + blkno = (xfs_daddr_t)f->blf_blkno; + } else { + printf("#regs:%d start blkno:0x%x len:%d bmap size:%d\n", + old_f->blf_size, old_f->blf_blkno, old_f->blf_len, + old_f->blf_map_size); + blkno = (xfs_daddr_t)old_f->blf_blkno; + } + num = f->blf_size-1; + i = 1; + while (num-- > 0) { + p = item->ri_buf[i].i_addr; + len = item->ri_buf[i].i_len; + i++; + if (blkno == 0) { /* super block */ + printf(" SUPER Block Buffer:\n"); + if (!print_buffer) continue; + printf(" icount:%Ld ifree:%Ld ", + INT_GET(*(long long *)(p), ARCH_CONVERT), + INT_GET(*(long long *)(p+8), ARCH_CONVERT)); + printf("fdblks:%Ld frext:%Ld\n", + INT_GET(*(long long *)(p+16), ARCH_CONVERT), + INT_GET(*(long long *)(p+24), ARCH_CONVERT)); + printf(" sunit:%u swidth:%u\n", + INT_GET(*(uint *)(p+56), ARCH_CONVERT), + INT_GET(*(uint *)(p+60), ARCH_CONVERT)); + } else if (INT_GET(*(uint *)p, ARCH_CONVERT) == XFS_AGI_MAGIC) { + agi = (xfs_agi_t *)p; + printf(" AGI Buffer: (XAGI)\n"); + if (!print_buffer) continue; + printf(" ver:%d ", + INT_GET(agi->agi_versionnum, ARCH_CONVERT)); + printf("seq#:%d len:%d cnt:%d root:%d\n", + INT_GET(agi->agi_seqno, ARCH_CONVERT), + INT_GET(agi->agi_length, ARCH_CONVERT), + INT_GET(agi->agi_count, ARCH_CONVERT), + INT_GET(agi->agi_root, ARCH_CONVERT)); + printf(" level:%d free#:0x%x newino:0x%x\n", + INT_GET(agi->agi_level, ARCH_CONVERT), + INT_GET(agi->agi_freecount, ARCH_CONVERT), + INT_GET(agi->agi_newino, ARCH_CONVERT)); + } else if (INT_GET(*(uint *)p, ARCH_CONVERT) == XFS_AGF_MAGIC) { + agf = (xfs_agf_t *)p; + printf(" AGF Buffer: (XAGF)\n"); + if (!print_buffer) continue; + printf(" ver:%d seq#:%d len:%d \n", + INT_GET(agf->agf_versionnum, ARCH_CONVERT), + INT_GET(agf->agf_seqno, ARCH_CONVERT), + INT_GET(agf->agf_length, ARCH_CONVERT)); + printf(" root BNO:%d CNT:%d\n", + INT_GET(agf->agf_roots[XFS_BTNUM_BNOi], + ARCH_CONVERT), + INT_GET(agf->agf_roots[XFS_BTNUM_CNTi], + ARCH_CONVERT)); + printf(" level BNO:%d CNT:%d\n", + INT_GET(agf->agf_levels[XFS_BTNUM_BNOi], + ARCH_CONVERT), + INT_GET(agf->agf_levels[XFS_BTNUM_CNTi], + ARCH_CONVERT)); + printf(" 1st:%d last:%d cnt:%d " + "freeblks:%d longest:%d\n", + INT_GET(agf->agf_flfirst, ARCH_CONVERT), + INT_GET(agf->agf_fllast, ARCH_CONVERT), + INT_GET(agf->agf_flcount, ARCH_CONVERT), + INT_GET(agf->agf_freeblks, ARCH_CONVERT), + INT_GET(agf->agf_longest, ARCH_CONVERT)); + } else if (*(uint *)p == XFS_DQUOT_MAGIC) { + ddq = (xfs_disk_dquot_t *)p; + printf(" DQUOT Buffer:\n"); + if (!print_buffer) continue; + printf(" UIDs 0x%lx-0x%lx\n", + (unsigned long)INT_GET(ddq->d_id, ARCH_CONVERT), + (unsigned long)INT_GET(ddq->d_id, ARCH_CONVERT) + + (BBTOB(f->blf_len) / sizeof(xfs_dqblk_t)) - 1); + } else { + printf(" BUF DATA\n"); + if (!print_buffer) continue; + xlog_recover_print_data(p, len); + } + } +} /* xlog_recover_print_buffer */ + +STATIC void +xlog_recover_print_quotaoff( + xlog_recover_item_t *item) +{ + xfs_qoff_logformat_t *qoff_f; + char str[20]; + + qoff_f = (xfs_qoff_logformat_t *)item->ri_buf[0].i_addr; + ASSERT(qoff_f); + if (qoff_f->qf_flags & XFS_UQUOTA_ACCT) + strcpy(str, "USER QUOTA"); + if (qoff_f->qf_flags & XFS_GQUOTA_ACCT) + strcat(str, "GROUP QUOTA"); + printf("\tQUOTAOFF: #regs:%d type:%s\n", + qoff_f->qf_size, str); +} + + +STATIC void +xlog_recover_print_dquot( + xlog_recover_item_t *item) +{ + xfs_dq_logformat_t *f; + xfs_disk_dquot_t *d; + + f = (xfs_dq_logformat_t *)item->ri_buf[0].i_addr; + ASSERT(f); + ASSERT(f->qlf_len == 1); + d = (xfs_disk_dquot_t *)item->ri_buf[1].i_addr; + printf("\tDQUOT: #regs:%d blkno:%lld boffset:%u id: %d\n", + f->qlf_size, (long long)f->qlf_blkno, f->qlf_boffset, f->qlf_id); + if (!print_quota) + return; + printf("\t\tmagic 0x%x\tversion 0x%x\tID 0x%x (%d)\t\n", + INT_GET(d->d_magic, ARCH_CONVERT), + INT_GET(d->d_version, ARCH_CONVERT), + INT_GET(d->d_id, ARCH_CONVERT), + INT_GET(d->d_id, ARCH_CONVERT)); + printf("\t\tblk_hard 0x%x\tblk_soft 0x%x\tino_hard 0x%x" + "\tino_soft 0x%x\n", + (int)INT_GET(d->d_blk_hardlimit, ARCH_CONVERT), + (int)INT_GET(d->d_blk_softlimit, ARCH_CONVERT), + (int)INT_GET(d->d_ino_hardlimit, ARCH_CONVERT), + (int)INT_GET(d->d_ino_softlimit, ARCH_CONVERT)); + printf("\t\tbcount 0x%x (%d) icount 0x%x (%d)\n", + (int)INT_GET(d->d_bcount, ARCH_CONVERT), + (int)INT_GET(d->d_bcount, ARCH_CONVERT), + (int)INT_GET(d->d_icount, ARCH_CONVERT), + (int)INT_GET(d->d_icount, ARCH_CONVERT)); + printf("\t\tbtimer 0x%x itimer 0x%x \n", + (int)INT_GET(d->d_btimer, ARCH_CONVERT), + (int)INT_GET(d->d_itimer, ARCH_CONVERT)); +} + +STATIC void +xlog_recover_print_inode_core( + xfs_dinode_core_t *di) +{ + printf(" CORE inode:\n"); + if (!print_inode) + return; + printf(" magic:%c%c mode:0x%x ver:%d format:%d " + "onlink:%d\n", + (di->di_magic>>8) & 0xff, di->di_magic & 0xff, + di->di_mode, di->di_version, di->di_format, di->di_onlink); + printf(" uid:%d gid:%d nlink:%d projid:%d\n", + di->di_uid, di->di_gid, di->di_nlink, (uint)di->di_projid); + printf(" atime:%d mtime:%d ctime:%d\n", + di->di_atime.t_sec, di->di_mtime.t_sec, di->di_ctime.t_sec); + printf(" size:0x%llx nblks:0x%llx exsize:%d " + "nextents:%d anextents:%d\n", (unsigned long long) + di->di_size, (unsigned long long)di->di_nblocks, + di->di_extsize, di->di_nextents, (int)di->di_anextents); + printf(" forkoff:%d dmevmask:0x%x dmstate:%d flags:0x%x " + "gen:%d\n", + (int)di->di_forkoff, di->di_dmevmask, (int)di->di_dmstate, + (int)di->di_flags, di->di_gen); +} /* xlog_recover_print_inode_core */ + + +STATIC void +xlog_recover_print_inode( + xlog_recover_item_t *item) +{ + xfs_inode_log_format_t *f; + int attr_index; + int hasdata; + int hasattr; + + f = (xfs_inode_log_format_t *)item->ri_buf[0].i_addr; + ASSERT(item->ri_buf[0].i_len == sizeof(xfs_inode_log_format_t)); + printf(" INODE: #regs:%d ino:0x%llx flags:0x%x dsize:%d\n", + f->ilf_size, (unsigned long long)f->ilf_ino, f->ilf_fields, + f->ilf_dsize); + + /* core inode comes 2nd */ + ASSERT(item->ri_buf[1].i_len == sizeof(xfs_dinode_core_t)); + xlog_recover_print_inode_core((xfs_dinode_core_t *) + item->ri_buf[1].i_addr); + + hasdata = (f->ilf_fields & XFS_ILOG_DFORK) != 0; + hasattr = (f->ilf_fields & XFS_ILOG_AFORK) != 0; + /* does anything come next */ + switch (f->ilf_fields & (XFS_ILOG_DFORK | XFS_ILOG_DEV | XFS_ILOG_UUID)) { + case XFS_ILOG_DEXT: { + ASSERT(f->ilf_size == 3 + hasattr); + printf(" DATA FORK EXTENTS inode data:\n"); + if (print_inode && print_data) { + xlog_recover_print_data(item->ri_buf[2].i_addr, + item->ri_buf[2].i_len); + } + break; + } + case XFS_ILOG_DBROOT: { + ASSERT(f->ilf_size == 3 + hasattr); + printf(" DATA FORK BTREE inode data:\n"); + if (print_inode && print_data) { + xlog_recover_print_data(item->ri_buf[2].i_addr, + item->ri_buf[2].i_len); + } + break; + } + case XFS_ILOG_DDATA: { + ASSERT(f->ilf_size == 3 + hasattr); + printf(" DATA FORK LOCAL inode data:\n"); + if (print_inode && print_data) { + xlog_recover_print_data(item->ri_buf[2].i_addr, + item->ri_buf[2].i_len); + } + break; + } + case XFS_ILOG_DEV: { + ASSERT(f->ilf_size == 2 + hasattr); + printf(" DEV inode: no extra region\n"); + break; + } + case XFS_ILOG_UUID: { + ASSERT(f->ilf_size == 2 + hasattr); + printf(" UUID inode: no extra region\n"); + break; + } + + + case 0: { + ASSERT(f->ilf_size == 2 + hasattr); + break; + } + default: { + xlog_panic("xlog_print_trans_inode: illegal inode type"); + } + } + + if (hasattr) { + attr_index = 2 + hasdata; + switch (f->ilf_fields & XFS_ILOG_AFORK) { + case XFS_ILOG_AEXT: { + ASSERT(f->ilf_size == 3 + hasdata); + printf(" ATTR FORK EXTENTS inode data:\n"); + if (print_inode && print_data) { + xlog_recover_print_data( + item->ri_buf[attr_index].i_addr, + item->ri_buf[attr_index].i_len); + } + break; + } + case XFS_ILOG_ABROOT: { + ASSERT(f->ilf_size == 3 + hasdata); + printf(" ATTR FORK BTREE inode data:\n"); + if (print_inode && print_data) { + xlog_recover_print_data( + item->ri_buf[attr_index].i_addr, + item->ri_buf[attr_index].i_len); + } + break; + } + case XFS_ILOG_ADATA: { + ASSERT(f->ilf_size == 3 + hasdata); + printf(" ATTR FORK LOCAL inode data:\n"); + if (print_inode && print_data) { + xlog_recover_print_data( + item->ri_buf[attr_index].i_addr, + item->ri_buf[attr_index].i_len); + } + break; + } + default: { + xlog_panic("xlog_print_trans_inode: " + "illegal inode log flag"); + } + } + } + +} /* xlog_recover_print_inode */ + + +STATIC void +xlog_recover_print_efd( + xlog_recover_item_t *item) +{ + xfs_efd_log_format_t *f; + xfs_extent_t *ex; + int i; + + f = (xfs_efd_log_format_t *)item->ri_buf[0].i_addr; + /* + * An xfs_efd_log_format structure contains a variable length array + * as the last field. Each element is of size xfs_extent_t. + */ + ASSERT(item->ri_buf[0].i_len == + sizeof(xfs_efd_log_format_t) + sizeof(xfs_extent_t) * + (f->efd_nextents-1)); + printf(" EFD: #regs: %d num_extents: %d id: 0x%llx\n", + f->efd_size, f->efd_nextents, (unsigned long long)f->efd_efi_id); + ex = f->efd_extents; + printf(" "); + for (i=0; i < f->efd_size; i++) { + printf("(s: 0x%llx, l: %d) ", + (unsigned long long) ex->ext_start, ex->ext_len); + if (i % 4 == 3) + printf("\n"); + ex++; + } + if (i % 4 != 0) printf("\n"); + return; +} /* xlog_recover_print_efd */ + + +STATIC void +xlog_recover_print_efi( + xlog_recover_item_t *item) +{ + xfs_efi_log_format_t *f; + xfs_extent_t *ex; + int i; + + f = (xfs_efi_log_format_t *)item->ri_buf[0].i_addr; + /* + * An xfs_efi_log_format structure contains a variable length array + * as the last field. Each element is of size xfs_extent_t. + */ + ASSERT(item->ri_buf[0].i_len == + sizeof(xfs_efi_log_format_t) + sizeof(xfs_extent_t) * + (f->efi_nextents-1)); + + printf(" EFI: #regs:%d num_extents:%d id:0x%llx\n", + f->efi_size, f->efi_nextents, (unsigned long long)f->efi_id); + ex = f->efi_extents; + printf(" "); + for (i=0; i< f->efi_nextents; i++) { + printf("(s: 0x%llx, l: %d) ", + (unsigned long long)ex->ext_start, ex->ext_len); + if (i % 4 == 3) printf("\n"); + ex++; + } + if (i % 4 != 0) printf("\n"); + return; +} /* xlog_recover_print_efi */ + +void +xlog_recover_print_logitem( + xlog_recover_item_t *item) +{ + switch (ITEM_TYPE(item)) { + case XFS_LI_BUF: + case XFS_LI_6_1_BUF: + case XFS_LI_5_3_BUF: { + xlog_recover_print_buffer(item); + break; + } + case XFS_LI_INODE: + case XFS_LI_6_1_INODE: + case XFS_LI_5_3_INODE: { + xlog_recover_print_inode(item); + break; + } + case XFS_LI_EFD: { + xlog_recover_print_efd(item); + break; + } + case XFS_LI_EFI: { + xlog_recover_print_efi(item); + break; + } + case XFS_LI_DQUOT: { + xlog_recover_print_dquot(item); + break; + } + case XFS_LI_QUOTAOFF: { + xlog_recover_print_quotaoff(item); + break; + } + default: { + printf("xlog_recover_print_logitem: illegal type\n"); + break; + } + } +} /* xlog_recover_print_logitem */ + +void +xlog_recover_print_item(xlog_recover_item_t *item) +{ + int i; + + switch (ITEM_TYPE(item)) { + case XFS_LI_BUF: { + printf("BUF"); + break; + } + case XFS_LI_INODE: { + printf("INO"); + break; + } + case XFS_LI_EFD: { + printf("EFD"); + break; + } + case XFS_LI_EFI: { + printf("EFI"); + break; + } + case XFS_LI_6_1_BUF: { + printf("6.1 BUF"); + break; + } + case XFS_LI_5_3_BUF: { + printf("5.3 BUF"); + break; + } + case XFS_LI_6_1_INODE: { + printf("6.1 INO"); + break; + } + case XFS_LI_5_3_INODE: { + printf("5.3 INO"); + break; + } + case XFS_LI_DQUOT: { + printf("DQ "); + break; + } + case XFS_LI_QUOTAOFF: { + printf("QOFF"); + break; + } + default: { + cmn_err(CE_PANIC, "xlog_recover_print_item: illegal type"); + break; + } + } + +/* type isn't filled in yet + printf("ITEM: type: %d cnt: %d total: %d ", + item->ri_type, item->ri_cnt, item->ri_total); +*/ + printf(": cnt:%d total:%d ", item->ri_cnt, item->ri_total); + for (i=0; iri_cnt; i++) { + printf("a:0x%lx len:%d ", + (long)item->ri_buf[i].i_addr, item->ri_buf[i].i_len); + } + printf("\n"); + xlog_recover_print_logitem(item); +} /* xlog_recover_print_item */ + +void +xlog_recover_print_trans(xlog_recover_t *trans, + xlog_recover_item_t *itemq, + int print) +{ + xlog_recover_item_t *first_item, *item; + + if (print < 3) + return; + + print_xlog_record_line(); + xlog_recover_print_trans_head(trans); + item = first_item = itemq; + do { + xlog_recover_print_item(item); + item = item->ri_next; + } while (first_item != item); +} /* xlog_recover_print_trans */ diff -rNu linux-2.4.7/cmd/xfsprogs/logprint/log_print_trans.c linux-2.4-xfs/cmd/xfsprogs/logprint/log_print_trans.c --- linux-2.4.7/cmd/xfsprogs/logprint/log_print_trans.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/logprint/log_print_trans.c Tue Apr 10 01:02:37 2001 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "logprint.h" + +void +xlog_recover_print_trans_head( + xlog_recover_t *tr) +{ + printf("TRANS: tid:0x%x type:%s #items:%d trans:0x%x q:0x%lx\n", + tr->r_log_tid, trans_type[tr->r_theader.th_type], + tr->r_theader.th_num_items, + tr->r_theader.th_tid, (long)tr->r_itemq); +} /* xlog_recover_print_trans_head */ + +int +xlog_recover_do_trans(xlog_t *log, + xlog_recover_t *trans, + int pass) +{ + xlog_recover_print_trans(trans, trans->r_itemq, 3); + return 0; +} /* xlog_recover_do_trans */ + +static int print_record_header=0; + +void +xfs_log_print_trans(xlog_t *log, + int print_block_start) +{ + xfs_daddr_t head_blk, tail_blk; + + if (xlog_find_tail(log, &head_blk, &tail_blk, 0)) + exit(1); + + printf(" log tail: %lld head: %lld state: %s\n", + (long long)tail_blk, + (long long)head_blk, + (tail_blk == head_blk)?"":""); + + if (print_block_start != -1) { + printf(" override tail: %lld\n", + (long long)print_block_start); + tail_blk = print_block_start; + } + printf("\n"); + + print_record_header=1; + if (xlog_do_recovery_pass(log, head_blk, tail_blk, XLOG_RECOVER_PASS1)) + exit(1); + +} /* xfs_log_print_trans */ + +static int +header_check_uuid(xfs_mount_t *mp, xlog_rec_header_t *head) +{ + char uu_log[64], uu_sb[64]; + + if (!uuid_compare(mp->m_sb.sb_uuid, head->h_fs_uuid)) return 0; + + uuid_unparse(mp->m_sb.sb_uuid, uu_sb); + uuid_unparse(head->h_fs_uuid, uu_log); + + printf("* ERROR: mismatched uuid in log\n" + "* SB : %s\n* log: %s\n", + uu_sb, uu_log); + + return 1; +} + +int +xlog_header_check_recover(xfs_mount_t *mp, xlog_rec_header_t *head) +{ + if (print_record_header) + printf("\nLOG REC AT LSN cycle %d block %d (0x%x, 0x%x)\n", + CYCLE_LSN(head->h_lsn, ARCH_CONVERT), + BLOCK_LSN(head->h_lsn, ARCH_CONVERT), + CYCLE_LSN(head->h_lsn, ARCH_CONVERT), + BLOCK_LSN(head->h_lsn, ARCH_CONVERT)); + + if (INT_GET(head->h_magicno, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) { + + printf("* ERROR: bad magic number in log header: 0x%x\n", + INT_GET(head->h_magicno, ARCH_CONVERT)); + + } else if (header_check_uuid(mp, head)) { + + /* failed - fall through */ + + } else if (INT_GET(head->h_fmt, ARCH_CONVERT) != XLOG_FMT) { + + printf("* ERROR: log format incompatible (log=%d, ours=%d)\n", + INT_GET(head->h_fmt, ARCH_CONVERT), XLOG_FMT); + + } else { + /* everything is ok */ + return 0; + } + + /* bail out now or just carry on regardless */ + if (print_exit) + xlog_exit("Bad log"); + + return 0; +} + +int +xlog_header_check_mount(xfs_mount_t *mp, xlog_rec_header_t *head) +{ + if (uuid_is_null(head->h_fs_uuid)) return 0; + if (header_check_uuid(mp, head)) { + /* bail out now or just carry on regardless */ + if (print_exit) + xlog_exit("Bad log"); + } + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/logprint/logprint.c linux-2.4-xfs/cmd/xfsprogs/logprint/logprint.c --- linux-2.4.7/cmd/xfsprogs/logprint/logprint.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/logprint/logprint.c Wed May 9 01:56:06 2001 @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "logprint.h" + +int print_data; +int print_only_data; +int print_inode; +int print_quota; +int print_buffer; +int print_transactions; +int print_overwrite; +int print_no_data; +int print_no_print; +int print_exit = 1; /* -e is now default. specify -c to override */ + +libxfs_init_t x; +xfs_mount_t mp; + +void +usage(void) +{ + fprintf(stderr, "Usage: %s [options...] \n\n\ +Options:\n\ + -c try to continue if error found in log\n\ + -l filename of external log\n\ + -n don't try and interpret log data\n\ + -o print buffer data in hex\n\ + -s block # to start printing\n\ + -v print \"overwrite\" data\n\ + -t print out transactional view\n\ + -b in transactional view, extract buffer info\n\ + -i in transactional view, extract inode info\n\ + -q in transactional view, extract quota info\n\ + -D print only data; no decoding\n\ + -V print version information\n", + progname); + exit(1); +} + +int +logstat(libxfs_init_t *x) +{ + int fd; + char buf[BBSIZE]; + xfs_sb_t *sb; + + /* On Linux we always read the superblock of the + * filesystem. We need this to get the length of the + * log. Otherwise we end up seeking forever. -- mkp + */ + if ((fd = open(x->dname, O_RDONLY)) == -1) { + fprintf(stderr, " Can't open device %s: %s\n", + x->dname, strerror(errno)); + exit(1); + } + lseek64(fd, 0, SEEK_SET); + if (read(fd, buf, sizeof(buf)) != sizeof(buf)) { + fprintf(stderr, " read of XFS superblock failed\n"); + exit(1); + } + close (fd); + + /* + * Conjure up a mount structure + */ + libxfs_xlate_sb(buf, &(mp.m_sb), 1, ARCH_CONVERT, XFS_SB_ALL_BITS); + sb = &(mp.m_sb); + mp.m_blkbb_log = sb->sb_blocklog - BBSHIFT; + + x->logBBsize = XFS_FSB_TO_BB(&mp, sb->sb_logblocks); + x->logBBstart = XFS_FSB_TO_DADDR(&mp, sb->sb_logstart); + + if (!x->logname && sb->sb_logstart == 0) { + fprintf(stderr, " external log device not specified\n\n"); + usage(); + /*NOTREACHED*/ + } + + if (x->logname && *x->logname) { /* External log */ + if ((fd = open(x->logname, O_RDONLY)) == -1) { + fprintf(stderr, "Can't open file %s: %s\n", + x->logname, strerror(errno)); + exit(1); + } + close(fd); + } else { /* Internal log */ + x->logdev = x->ddev; + } + + return 0; +} + +int +main(int argc, char **argv) +{ + int print_start = -1; + int c; + int logfd; + xlog_t log = {0}; + + progname = basename(argv[0]); + while ((c = getopt(argc, argv, "bel:iqnors:tDVvc")) != EOF) { + switch (c) { + case 'D': { + print_only_data++; + print_data++; + break; + } + case 'b': { + print_buffer++; + break; + } + case 'l': { + x.logname = optarg; + x.lisfile = 1; + break; + } + case 'c': { + /* default is to stop on error. + * -c turns this off. + */ + print_exit=0; + break; + } + case 'e': { + /* -e is now default + */ + print_exit++; + break; + } + case 'i': { + print_inode++; + break; + } + case 'q': { + print_quota++; + break; + } + case 'n': { + print_no_data++; + break; + } + case 'o': { + print_data++; + break; + } + case 's': { + print_start = atoi(optarg); + break; + } + case 't': { + print_transactions++; + break; + } + case 'V': { + printf("%s version %s\n", progname, VERSION); + break; + } + case 'v': { + print_overwrite++; + break; + } + case '?': { + usage(); + } + } + } + + if (argc - optind != 1) + usage(); + + x.dname = argv[optind]; + + if (x.dname == NULL) + usage(); + + x.notvolok = 1; + x.isreadonly = LIBXFS_ISINACTIVE; + x.notvolmsg = "You should never see this message.\n"; + + printf("xfs_logprint:\n"); + if (!libxfs_init(&x)) + exit(1); + + logstat(&x); + + logfd=(x.logfd<0)?(x.dfd):(x.logfd); + + printf(" data device: 0x%llx\n", (unsigned long long)x.ddev); + + if (x.logname) { + printf(" log file: \"%s\" ", x.logname); + } else { + printf(" log device: 0x%llx ", (unsigned long long)x.logdev); + } + + printf("daddr: %lld length: %lld\n\n", + (long long)x.logBBstart, (long long)x.logBBsize); + + ASSERT(x.logBBstart <= INT_MAX); + + /* init log structure */ + log.l_dev = x.logdev; + log.l_logsize = BBTOB(x.logBBsize); + log.l_logBBstart = x.logBBstart; + log.l_logBBsize = x.logBBsize; + log.l_mp = ∓ + + if (print_transactions) + xfs_log_print_trans(&log, print_start); + else + xfs_log_print(&log, logfd, print_start); + + exit(0); +} diff -rNu linux-2.4.7/cmd/xfsprogs/logprint/logprint.h linux-2.4-xfs/cmd/xfsprogs/logprint/logprint.h --- linux-2.4.7/cmd/xfsprogs/logprint/logprint.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/logprint/logprint.h Wed May 9 01:56:06 2001 @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef XFS_LOGPRINT_H +#define XFS_LOGPRINT_H + +#include + +/* + * define the userlevel xlog_t to be the subset of the kernel's + * xlog_t that we actually need to get our work done, avoiding + * the need to define any exotic kernel types in userland. + */ +typedef struct log { + xfs_lsn_t l_tail_lsn; /* lsn of 1st LR w/ unflush buffers */ + xfs_lsn_t l_last_sync_lsn;/* lsn of last LR on disk */ + xfs_mount_t *l_mp; /* mount point */ + dev_t l_dev; /* dev_t of log */ + xfs_daddr_t l_logBBstart; /* start block of log */ + int l_logsize; /* size of log in bytes */ + int l_logBBsize; /* size of log in 512 byte chunks */ + int l_roundoff; /* round off error of all iclogs */ + int l_curr_cycle; /* Cycle number of log writes */ + int l_prev_cycle; /* Cycle # b4 last block increment */ + int l_curr_block; /* current logical block of log */ + int l_prev_block; /* previous logical block of log */ + int l_iclog_size; /* size of log in bytes */ + int l_iclog_size_log;/* log power size of log */ + int l_iclog_bufs; /* number of iclog buffers */ + int l_grant_reserve_cycle; /* */ + int l_grant_reserve_bytes; /* */ + int l_grant_write_cycle; /* */ + int l_grant_write_bytes; /* */ +} xlog_t; + +#include +#include +#include +#include +#include + + +/* + * macros mapping kernel code to user code + */ +#define STATIC static +#define EFSCORRUPTED 990 +#define XFS_ERROR(e) (e) + +#if (__GNUC__ < 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ <= 95)) +# define xlog_warn(fmt,args...) \ + ( fprintf(stderr,fmt,## args), fputc('\n', stderr) ) +# define cmn_err(sev,fmt,args...) \ + xlog_warn(fmt,## args) +# define xlog_exit(fmt,args...) \ + ( xlog_warn(fmt,## args), exit(1) ) +# define xlog_panic(fmt,args...) \ + xlog_exit(fmt,## args) +#else +# define xlog_warn(...) \ + ( fprintf(stderr,__VA_ARGS__), fputc('\n', stderr) ) +# define cmn_err(sev,...) \ + xlog_warn(__VA_ARGS__) +# define xlog_exit(...) \ + ( xlog_warn(__VA_ARGS__), exit(1) ) +# define xlog_panic(...) \ + xlog_exit(__VA_ARGS__) +#endif + +#define xlog_get_bp(nbblks, mp) libxfs_getbuf(x.logdev, 0, (nbblks)) +#define xlog_put_bp(bp) libxfs_putbuf(bp) +#define xlog_bread(log,blkno,nbblks,bp) \ + (libxfs_readbufr(x.logdev, \ + (log)->l_logBBstart+(blkno), bp, (nbblks), 1), 0) + +#define kmem_zalloc(size, foo) calloc(size,1) +#define kmem_free(ptr, foo) free(ptr) +#define kmem_realloc(ptr, len, old, foo) realloc(ptr, len) + +/* command line flags */ +extern int print_data; +extern int print_only_data; +extern int print_inode; +extern int print_quota; +extern int print_buffer; +extern int print_transactions; +extern int print_overwrite; + +extern int print_exit; +extern int print_no_data; +extern int print_no_print; + +/* exports */ + +extern char *trans_type[]; + +/* libxfs parameters */ +extern libxfs_init_t x; + +extern void xfs_log_print_trans(xlog_t *log, + int print_block_start); + +extern void xfs_log_print( xlog_t *log, + int fd, + int print_block_start); + +extern int xlog_find_zeroed(xlog_t *log, xfs_daddr_t *blk_no); +extern int xlog_find_cycle_start(xlog_t *log, xfs_buf_t *bp, + xfs_daddr_t first_blk, xfs_daddr_t *last_blk, uint cycle); +extern int xlog_find_tail(xlog_t *log, xfs_daddr_t *head_blk, + xfs_daddr_t *tail_blk, int readonly); + +extern int xlog_test_footer(xlog_t *log); +extern int xlog_recover(xlog_t *log, int readonly); +extern void xlog_recover_print_data(xfs_caddr_t p, int len); +extern void xlog_recover_print_logitem(xlog_recover_item_t *item); +extern void xlog_recover_print_trans_head(xlog_recover_t *tr); +extern int xlog_print_find_oldest(xlog_t *log, xfs_daddr_t *last_blk); + +extern void print_xlog_op_line(void); +extern void print_xlog_record_line(void); +extern void print_stars(void); + +/* for transactional view */ +extern void xlog_recover_print_trans_head(xlog_recover_t *tr); + +extern void xlog_recover_print_trans( xlog_recover_t *trans, + xlog_recover_item_t *itemq, + int print); + +extern int xlog_do_recovery_pass( xlog_t *log, + xfs_daddr_t head_blk, + xfs_daddr_t tail_blk, + int pass); +extern int xlog_recover_do_trans( xlog_t *log, + xlog_recover_t *trans, + int pass); +extern int xlog_header_check_recover( xfs_mount_t *mp, + xlog_rec_header_t *head); +extern int xlog_header_check_mount( xfs_mount_t *mp, + xlog_rec_header_t *head); + +#endif /* XFS_LOGPRINT_H */ diff -rNu linux-2.4.7/cmd/xfsprogs/logprint/xfs_log_recover.c linux-2.4-xfs/cmd/xfsprogs/logprint/xfs_log_recover.c --- linux-2.4.7/cmd/xfsprogs/logprint/xfs_log_recover.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/logprint/xfs_log_recover.c Thu Apr 12 18:42:32 2001 @@ -0,0 +1,1245 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "logprint.h" + +/* + * This routine finds (to an approximation) the first block in the physical + * log which contains the given cycle. It uses a binary search algorithm. + * Note that the algorithm can not be perfect because the disk will not + * necessarily be perfect. + */ +int +xlog_find_cycle_start(xlog_t *log, + xfs_buf_t *bp, + xfs_daddr_t first_blk, + xfs_daddr_t *last_blk, + uint cycle) +{ + xfs_daddr_t mid_blk; + uint mid_cycle; + int error; + + mid_blk = BLK_AVG(first_blk, *last_blk); + while (mid_blk != first_blk && mid_blk != *last_blk) { + if ((error = xlog_bread(log, mid_blk, 1, bp))) + return error; + mid_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + if (mid_cycle == cycle) { + *last_blk = mid_blk; + /* last_half_cycle == mid_cycle */ + } else { + first_blk = mid_blk; + /* first_half_cycle == mid_cycle */ + } + mid_blk = BLK_AVG(first_blk, *last_blk); + } + ASSERT((mid_blk == first_blk && mid_blk+1 == *last_blk) || + (mid_blk == *last_blk && mid_blk-1 == first_blk)); + + return 0; +} /* xlog_find_cycle_start */ + + +/* + * Check that the range of blocks does not contain the cycle number + * given. The scan needs to occur from front to back and the ptr into the + * region must be updated since a later routine will need to perform another + * test. If the region is completely good, we end up returning the same + * last block number. + * + * Return -1 if we encounter no errors. This is an invalid block number + * since we don't ever expect logs to get this large. + */ + +STATIC xfs_daddr_t +xlog_find_verify_cycle( xlog_t *log, + xfs_daddr_t start_blk, + int nbblks, + uint stop_on_cycle_no) +{ + int i, j; + uint cycle; + xfs_buf_t *bp; + char *buf = NULL; + int error = 0; + int bufblks = nbblks; + + while (!(bp = xlog_get_bp(bufblks, log->l_mp))) { + /* can't get enough memory to do everything in one big buffer */ + bufblks >>= 1; + if (!bufblks) + return -ENOMEM; + } + + + for (i = start_blk; i < start_blk + nbblks; i += bufblks) { + if ((error = xlog_bread(log, i, bufblks, bp))) + goto out; + + buf = XFS_BUF_PTR(bp); + for (j = 0; j < bufblks; j++) { + cycle = GET_CYCLE(buf, ARCH_CONVERT); + if (cycle == stop_on_cycle_no) { + error = i; + goto out; + } + + buf += BBSIZE; + } + } + + error = -1; + +out: + xlog_put_bp(bp); + + return error; +} /* xlog_find_verify_cycle */ + + +/* + * Potentially backup over partial log record write. + * + * In the typical case, last_blk is the number of the block directly after + * a good log record. Therefore, we subtract one to get the block number + * of the last block in the given buffer. extra_bblks contains the number + * of blocks we would have read on a previous read. This happens when the + * last log record is split over the end of the physical log. + * + * extra_bblks is the number of blocks potentially verified on a previous + * call to this routine. + */ + +STATIC int +xlog_find_verify_log_record(xlog_t *log, + xfs_daddr_t start_blk, + xfs_daddr_t *last_blk, + int extra_bblks) +{ + xfs_daddr_t i; + xfs_buf_t *bp; + char *buf = NULL; + xlog_rec_header_t *head = NULL; + int error = 0; + int smallmem = 0; + int num_blks = *last_blk - start_blk; + + ASSERT(start_blk != 0 || *last_blk != start_blk); + + if (!(bp = xlog_get_bp(num_blks, log->l_mp))) { + if (!(bp = xlog_get_bp(1, log->l_mp))) + return -ENOMEM; + smallmem = 1; + buf = XFS_BUF_PTR(bp); + } else { + if ((error = xlog_bread(log, start_blk, num_blks, bp))) + goto out; + buf = XFS_BUF_PTR(bp) + (num_blks - 1) * BBSIZE; + } + + + for (i=(*last_blk)-1; i>=0; i--) { + if (i < start_blk) { + /* legal log record not found */ + xlog_warn("XFS: Log inconsistent (didn't find previous header)"); +#ifdef __KERNEL__ + ASSERT(0); +#endif + error = XFS_ERROR(EIO); + goto out; + } + + if (smallmem && (error = xlog_bread(log, i, 1, bp))) + goto out; + head = (xlog_rec_header_t*)buf; + + if (INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) + break; + + if (!smallmem) + buf -= BBSIZE; + } + + /* + * We hit the beginning of the physical log & still no header. Return + * to caller. If caller can handle a return of -1, then this routine + * will be called again for the end of the physical log. + */ + if (i == -1) { + error = -1; + goto out; + } + + /* we have the final block of the good log (the first block + * of the log record _before_ the head. So we check the uuid. + */ + + if ((error = xlog_header_check_mount(log->l_mp, head))) + goto out; + + /* + * We may have found a log record header before we expected one. + * last_blk will be the 1st block # with a given cycle #. We may end + * up reading an entire log record. In this case, we don't want to + * reset last_blk. Only when last_blk points in the middle of a log + * record do we update last_blk. + */ + if (*last_blk - i + extra_bblks + != BTOBB(INT_GET(head->h_len, ARCH_CONVERT))+1) + *last_blk = i; + +out: + xlog_put_bp(bp); + + return error; +} /* xlog_find_verify_log_record */ + +/* + * Head is defined to be the point of the log where the next log write + * write could go. This means that incomplete LR writes at the end are + * eliminated when calculating the head. We aren't guaranteed that previous + * LR have complete transactions. We only know that a cycle number of + * current cycle number -1 won't be present in the log if we start writing + * from our current block number. + * + * last_blk contains the block number of the first block with a given + * cycle number. + * + * Also called from xfs_log_print.c + * + * Return: zero if normal, non-zero if error. + */ +int +xlog_find_head(xlog_t *log, + xfs_daddr_t *return_head_blk) +{ + xfs_buf_t *bp; + xfs_daddr_t new_blk, first_blk, start_blk, last_blk, head_blk; + int num_scan_bblks; + uint first_half_cycle, last_half_cycle; + uint stop_on_cycle; + int error, log_bbnum = log->l_logBBsize; + + /* Is the end of the log device zeroed? */ + if ((error = xlog_find_zeroed(log, &first_blk)) == -1) { + *return_head_blk = first_blk; + + /* is the whole lot zeroed? */ + if (!first_blk) { + /* Linux XFS shouldn't generate totally zeroed logs - + * mkfs etc write a dummy unmount record to a fresh + * log so we can store the uuid in there + */ + xlog_warn("XFS: totally zeroed log\n"); + } + + return 0; + } else if (error) { + xlog_warn("XFS: empty log check failed"); + return error; + } + + first_blk = 0; /* get cycle # of 1st block */ + bp = xlog_get_bp(1,log->l_mp); + if (!bp) + return -ENOMEM; + if ((error = xlog_bread(log, 0, 1, bp))) + goto bp_err; + first_half_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + + last_blk = head_blk = log_bbnum-1; /* get cycle # of last block */ + if ((error = xlog_bread(log, last_blk, 1, bp))) + goto bp_err; + last_half_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + ASSERT(last_half_cycle != 0); + + /* + * If the 1st half cycle number is equal to the last half cycle number, + * then the entire log is stamped with the same cycle number. In this + * case, head_blk can't be set to zero (which makes sense). The below + * math doesn't work out properly with head_blk equal to zero. Instead, + * we set it to log_bbnum which is an illegal block number, but this + * value makes the math correct. If head_blk doesn't changed through + * all the tests below, *head_blk is set to zero at the very end rather + * than log_bbnum. In a sense, log_bbnum and zero are the same block + * in a circular file. + */ + if (first_half_cycle == last_half_cycle) { + /* + * In this case we believe that the entire log should have cycle + * number last_half_cycle. We need to scan backwards from the + * end verifying that there are no holes still containing + * last_half_cycle - 1. If we find such a hole, then the start + * of that hole will be the new head. The simple case looks like + * x | x ... | x - 1 | x + * Another case that fits this picture would be + * x | x + 1 | x ... | x + * In this case the head really is somwhere at the end of the + * log, as one of the latest writes at the beginning was incomplete. + * One more case is + * x | x + 1 | x ... | x - 1 | x + * This is really the combination of the above two cases, and the + * head has to end up at the start of the x-1 hole at the end of + * the log. + * + * In the 256k log case, we will read from the beginning to the + * end of the log and search for cycle numbers equal to x-1. We + * don't worry about the x+1 blocks that we encounter, because + * we know that they cannot be the head since the log started with + * x. + */ + head_blk = log_bbnum; + stop_on_cycle = last_half_cycle - 1; + } else { + /* + * In this case we want to find the first block with cycle number + * matching last_half_cycle. We expect the log to be some + * variation on + * x + 1 ... | x ... + * The first block with cycle number x (last_half_cycle) will be + * where the new head belongs. First we do a binary search for + * the first occurrence of last_half_cycle. The binary search + * may not be totally accurate, so then we scan back from there + * looking for occurrences of last_half_cycle before us. If + * that backwards scan wraps around the beginning of the log, + * then we look for occurrences of last_half_cycle - 1 at the + * end of the log. The cases we're looking for look like + * x + 1 ... | x | x + 1 | x ... + * ^ binary search stopped here + * or + * x + 1 ... | x ... | x - 1 | x + * <---------> less than scan distance + */ + stop_on_cycle = last_half_cycle; + if ((error = xlog_find_cycle_start(log, bp, first_blk, + &head_blk, last_half_cycle))) + goto bp_err; + } + + /* + * Now validate the answer. Scan back some number of maximum possible + * blocks and make sure each one has the expected cycle number. The + * maximum is determined by the total possible amount of buffering + * in the in-core log. The following number can be made tighter if + * we actually look at the block size of the filesystem. + */ + num_scan_bblks = BTOBB(XLOG_MAX_ICLOGS<= num_scan_bblks) { + /* + * We are guaranteed that the entire check can be performed + * in one buffer. + */ + start_blk = head_blk - num_scan_bblks; + new_blk = xlog_find_verify_cycle(log, start_blk, num_scan_bblks, + stop_on_cycle); + if (new_blk != -1) + head_blk = new_blk; + } else { /* need to read 2 parts of log */ + /* + * We are going to scan backwards in the log in two parts. First + * we scan the physical end of the log. In this part of the log, + * we are looking for blocks with cycle number last_half_cycle - 1. + * If we find one, then we know that the log starts there, as we've + * found a hole that didn't get written in going around the end + * of the physical log. The simple case for this is + * x + 1 ... | x ... | x - 1 | x + * <---------> less than scan distance + * If all of the blocks at the end of the log have cycle number + * last_half_cycle, then we check the blocks at the start of the + * log looking for occurrences of last_half_cycle. If we find one, + * then our current estimate for the location of the first + * occurrence of last_half_cycle is wrong and we move back to the + * hole we've found. This case looks like + * x + 1 ... | x | x + 1 | x ... + * ^ binary search stopped here + * Another case we need to handle that only occurs in 256k logs is + * x + 1 ... | x ... | x+1 | x ... + * ^ binary search stops here + * In a 256k log, the scan at the end of the log will see the x+1 + * blocks. We need to skip past those since that is certainly not + * the head of the log. By searching for last_half_cycle-1 we + * accomplish that. + */ + start_blk = log_bbnum - num_scan_bblks + head_blk; + ASSERT(head_blk <= INT_MAX && (xfs_daddr_t) num_scan_bblks-head_blk >= 0); + new_blk= xlog_find_verify_cycle(log, start_blk, + num_scan_bblks-(int)head_blk, (stop_on_cycle - 1)); + if (new_blk != -1) { + head_blk = new_blk; + goto bad_blk; + } + + /* + * Scan beginning of log now. The last part of the physical log + * is good. This scan needs to verify that it doesn't find the + * last_half_cycle. + */ + start_blk = 0; + ASSERT(head_blk <= INT_MAX); + new_blk = xlog_find_verify_cycle(log, start_blk, (int) head_blk, + stop_on_cycle); + if (new_blk != -1) + head_blk = new_blk; + } + +bad_blk: + /* + * Now we need to make sure head_blk is not pointing to a block in + * the middle of a log record. + */ + num_scan_bblks = BTOBB(XLOG_MAX_RECORD_BSIZE); + if (head_blk >= num_scan_bblks) { + start_blk = head_blk - num_scan_bblks; /* don't read head_blk */ + + /* start ptr at last block ptr before head_blk */ + if ((error = xlog_find_verify_log_record(log, + start_blk, + &head_blk, + 0)) == -1) { + error = XFS_ERROR(EIO); + goto bp_err; + } else if (error) + goto bp_err; + } else { + start_blk = 0; + ASSERT(head_blk <= INT_MAX); + if ((error = xlog_find_verify_log_record(log, + start_blk, + &head_blk, + 0)) == -1) { + /* We hit the beginning of the log during our search */ + start_blk = log_bbnum - num_scan_bblks + head_blk; + new_blk = log_bbnum; + ASSERT(start_blk <= INT_MAX && (xfs_daddr_t) log_bbnum-start_blk >= 0); + ASSERT(head_blk <= INT_MAX); + if ((error = xlog_find_verify_log_record(log, + start_blk, + &new_blk, + (int)head_blk)) == -1) { + error = XFS_ERROR(EIO); + goto bp_err; + } else if (error) + goto bp_err; + if (new_blk != log_bbnum) + head_blk = new_blk; + } else if (error) + goto bp_err; + } + + xlog_put_bp(bp); + if (head_blk == log_bbnum) + *return_head_blk = 0; + else + *return_head_blk = head_blk; + /* + * When returning here, we have a good block number. Bad block + * means that during a previous crash, we didn't have a clean break + * from cycle number N to cycle number N-1. In this case, we need + * to find the first block with cycle number N-1. + */ + return 0; + +bp_err: + xlog_put_bp(bp); + + if (error) + xlog_warn("XFS: failed to find log head"); + + return error; +} /* xlog_find_head */ + +/* + * Find the sync block number or the tail of the log. + * + * This will be the block number of the last record to have its + * associated buffers synced to disk. Every log record header has + * a sync lsn embedded in it. LSNs hold block numbers, so it is easy + * to get a sync block number. The only concern is to figure out which + * log record header to believe. + * + * The following algorithm uses the log record header with the largest + * lsn. The entire log record does not need to be valid. We only care + * that the header is valid. + * + * We could speed up search by using current head_blk buffer, but it is not + * available. + */ +int +xlog_find_tail(xlog_t *log, + xfs_daddr_t *head_blk, + xfs_daddr_t *tail_blk, + int readonly) +{ + xlog_rec_header_t *rhead; + xlog_op_header_t *op_head; + xfs_buf_t *bp; + int error, i, found; + xfs_daddr_t umount_data_blk; + xfs_daddr_t after_umount_blk; + xfs_lsn_t tail_lsn; + + found = error = 0; + + /* + * Find previous log record + */ + if ((error = xlog_find_head(log, head_blk))) + return error; + + bp = xlog_get_bp(1,log->l_mp); + if (!bp) + return -ENOMEM; + if (*head_blk == 0) { /* special case */ + if ((error = xlog_bread(log, 0, 1, bp))) + goto bread_err; + if (GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT) == 0) { + *tail_blk = 0; + /* leave all other log inited values alone */ + goto exit; + } + } + + /* + * Search backwards looking for log record header block + */ + ASSERT(*head_blk < INT_MAX); + for (i=(int)(*head_blk)-1; i>=0; i--) { + if ((error = xlog_bread(log, i, 1, bp))) + goto bread_err; + if (INT_GET(*(uint *)(XFS_BUF_PTR(bp)), ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) { + found = 1; + break; + } + } + /* + * If we haven't found the log record header block, start looking + * again from the end of the physical log. XXXmiken: There should be + * a check here to make sure we didn't search more than N blocks in + * the previous code. + */ + if (!found) { + for (i=log->l_logBBsize-1; i>=(int)(*head_blk); i--) { + if ((error = xlog_bread(log, i, 1, bp))) + goto bread_err; + if (INT_GET(*(uint*)(XFS_BUF_PTR(bp)), ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) { + found = 2; + break; + } + } + } + if (!found) { + xlog_warn("XFS: xlog_find_tail: couldn't find sync record"); + ASSERT(0); + return XFS_ERROR(EIO); + } + + /* find blk_no of tail of log */ + rhead = (xlog_rec_header_t *)XFS_BUF_PTR(bp); + *tail_blk = BLOCK_LSN(rhead->h_tail_lsn, ARCH_CONVERT); + + /* + * Reset log values according to the state of the log when we + * crashed. In the case where head_blk == 0, we bump curr_cycle + * one because the next write starts a new cycle rather than + * continuing the cycle of the last good log record. At this + * point we have guaranteed that all partial log records have been + * accounted for. Therefore, we know that the last good log record + * written was complete and ended exactly on the end boundary + * of the physical log. + */ + log->l_prev_block = i; + log->l_curr_block = (int)*head_blk; + log->l_curr_cycle = INT_GET(rhead->h_cycle, ARCH_CONVERT); + if (found == 2) + log->l_curr_cycle++; + log->l_tail_lsn = INT_GET(rhead->h_tail_lsn, ARCH_CONVERT); + log->l_last_sync_lsn = INT_GET(rhead->h_lsn, ARCH_CONVERT); + log->l_grant_reserve_cycle = log->l_curr_cycle; + log->l_grant_reserve_bytes = BBTOB(log->l_curr_block); + log->l_grant_write_cycle = log->l_curr_cycle; + log->l_grant_write_bytes = BBTOB(log->l_curr_block); + + /* + * Look for unmount record. If we find it, then we know there + * was a clean unmount. Since 'i' could be the last block in + * the physical log, we convert to a log block before comparing + * to the head_blk. + * + * Save the current tail lsn to use to pass to + * xlog_clear_stale_blocks() below. We won't want to clear the + * unmount record if there is one, so we pass the lsn of the + * unmount record rather than the block after it. + */ + after_umount_blk = (i + 2) % log->l_logBBsize; + tail_lsn = log->l_tail_lsn; + if (*head_blk == after_umount_blk && INT_GET(rhead->h_num_logops, ARCH_CONVERT) == 1) { + umount_data_blk = (i + 1) % log->l_logBBsize; + if ((error = xlog_bread(log, umount_data_blk, 1, bp))) { + goto bread_err; + } + op_head = (xlog_op_header_t *)XFS_BUF_PTR(bp); + if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) { + /* + * Set tail and last sync so that newly written + * log records will point recovery to after the + * current unmount record. + */ + ASSIGN_ANY_LSN(log->l_tail_lsn, log->l_curr_cycle, + after_umount_blk, ARCH_NOCONVERT); + ASSIGN_ANY_LSN(log->l_last_sync_lsn, log->l_curr_cycle, + after_umount_blk, ARCH_NOCONVERT); + *tail_blk = after_umount_blk; + } + } + +#ifdef __KERNEL__ + /* + * Make sure that there are no blocks in front of the head + * with the same cycle number as the head. This can happen + * because we allow multiple outstanding log writes concurrently, + * and the later writes might make it out before earlier ones. + * + * We use the lsn from before modifying it so that we'll never + * overwrite the unmount record after a clean unmount. + * + * Do this only if we are going to recover the filesystem + */ + if (!readonly) + error = xlog_clear_stale_blocks(log, tail_lsn); +#endif + +bread_err: +exit: + xlog_put_bp(bp); + + if (error) + xlog_warn("XFS: failed to locate log tail"); + + return error; +} /* xlog_find_tail */ + + +/* + * Is the log zeroed at all? + * + * The last binary search should be changed to perform an X block read + * once X becomes small enough. You can then search linearly through + * the X blocks. This will cut down on the number of reads we need to do. + * + * If the log is partially zeroed, this routine will pass back the blkno + * of the first block with cycle number 0. It won't have a complete LR + * preceding it. + * + * Return: + * 0 => the log is completely written to + * -1 => use *blk_no as the first block of the log + * >0 => error has occurred + */ +int +xlog_find_zeroed(struct log *log, + xfs_daddr_t *blk_no) +{ + xfs_buf_t *bp; + uint first_cycle, last_cycle; + xfs_daddr_t new_blk, last_blk, start_blk; + xfs_daddr_t num_scan_bblks; + int error, log_bbnum = log->l_logBBsize; + + error = 0; + /* check totally zeroed log */ + bp = xlog_get_bp(1,log->l_mp); + if (!bp) + return -ENOMEM; + if ((error = xlog_bread(log, 0, 1, bp))) + goto bp_err; + first_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + if (first_cycle == 0) { /* completely zeroed log */ + *blk_no = 0; + xlog_put_bp(bp); + return -1; + } + + /* check partially zeroed log */ + if ((error = xlog_bread(log, log_bbnum-1, 1, bp))) + goto bp_err; + last_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + if (last_cycle != 0) { /* log completely written to */ + xlog_put_bp(bp); + return 0; + } else if (first_cycle != 1) { + /* + * If the cycle of the last block is zero, the cycle of + * the first block must be 1. If it's not, maybe we're + * not looking at a log... Bail out. + */ + xlog_warn("XFS: Log inconsistent or not a log (last==0, first!=1)"); + return XFS_ERROR(EINVAL); + } + + /* we have a partially zeroed log */ + last_blk = log_bbnum-1; + if ((error = xlog_find_cycle_start(log, bp, 0, &last_blk, 0))) + goto bp_err; + + /* + * Validate the answer. Because there is no way to guarantee that + * the entire log is made up of log records which are the same size, + * we scan over the defined maximum blocks. At this point, the maximum + * is not chosen to mean anything special. XXXmiken + */ + num_scan_bblks = BTOBB(XLOG_MAX_ICLOGS<h_len, ARCH_CONVERT)); i++) { + INT_SET(*(uint *)dp, ARCH_CONVERT, INT_GET(*(uint *)&rhead->h_cycle_data[i], ARCH_CONVERT)); + dp += BBSIZE; + } +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + /* divide length by 4 to get # words */ + for (i=0; i < INT_GET(rhead->h_len, ARCH_CONVERT) >> 2; i++) { + chksum ^= INT_GET(*up, ARCH_CONVERT); + up++; + } + if (chksum != INT_GET(rhead->h_chksum, ARCH_CONVERT)) { + if (!INT_ISZERO(rhead->h_chksum, ARCH_CONVERT) || + ((log->l_flags & XLOG_CHKSUM_MISMATCH) == 0)) { + cmn_err(CE_DEBUG, + "XFS: LogR chksum mismatch: was (0x%x) is (0x%x)", + INT_GET(rhead->h_chksum, ARCH_CONVERT), chksum); + cmn_err(CE_DEBUG, +"XFS: Disregard message if filesystem was created with non-DEBUG kernel"); + log->l_flags |= XLOG_CHKSUM_MISMATCH; + } + } +#endif /* DEBUG && XFS_LOUD_RECOVERY */ +} /* xlog_unpack_data */ + + +STATIC xlog_recover_t * +xlog_recover_find_tid(xlog_recover_t *q, + xlog_tid_t tid) +{ + xlog_recover_t *p = q; + + while (p != NULL) { + if (p->r_log_tid == tid) + break; + p = p->r_next; + } + return p; +} /* xlog_recover_find_tid */ + +STATIC void +xlog_recover_put_hashq(xlog_recover_t **q, + xlog_recover_t *trans) +{ + trans->r_next = *q; + *q = trans; +} /* xlog_recover_put_hashq */ + +STATIC void +xlog_recover_new_tid(xlog_recover_t **q, + xlog_tid_t tid, + xfs_lsn_t lsn) +{ + xlog_recover_t *trans; + + trans = kmem_zalloc(sizeof(xlog_recover_t), 0); + trans->r_log_tid = tid; + trans->r_lsn = lsn; + xlog_recover_put_hashq(q, trans); +} /* xlog_recover_new_tid */ + + +STATIC int +xlog_recover_unlink_tid(xlog_recover_t **q, + xlog_recover_t *trans) +{ + xlog_recover_t *tp; + int found = 0; + + ASSERT(trans != 0); + if (trans == *q) { + *q = (*q)->r_next; + } else { + tp = *q; + while (tp != 0) { + if (tp->r_next == trans) { + found = 1; + break; + } + tp = tp->r_next; + } + if (!found) { + xlog_warn( + "XFS: xlog_recover_unlink_tid: trans not found"); + ASSERT(0); + return XFS_ERROR(EIO); + } + tp->r_next = tp->r_next->r_next; + } + return 0; +} /* xlog_recover_unlink_tid */ + +/* + * Free up any resources allocated by the transaction + * + * Remember that EFIs, EFDs, and IUNLINKs are handled later. + */ +STATIC void +xlog_recover_free_trans(xlog_recover_t *trans) +{ + xlog_recover_item_t *first_item, *item, *free_item; + int i; + + item = first_item = trans->r_itemq; + do { + free_item = item; + item = item->ri_next; + /* Free the regions in the item. */ + for (i = 0; i < free_item->ri_cnt; i++) { + kmem_free(free_item->ri_buf[i].i_addr, + free_item->ri_buf[i].i_len); + } + /* Free the item itself */ + kmem_free(free_item->ri_buf, + (free_item->ri_total * sizeof(xfs_log_iovec_t))); + kmem_free(free_item, sizeof(xlog_recover_item_t)); + } while (first_item != item); + /* Free the transaction recover structure */ + kmem_free(trans, sizeof(xlog_recover_t)); +} /* xlog_recover_free_trans */ + + +STATIC int +xlog_recover_commit_trans(xlog_t *log, + xlog_recover_t **q, + xlog_recover_t *trans, + int pass) +{ + int error; + + if ((error = xlog_recover_unlink_tid(q, trans))) + return error; + if ((error = xlog_recover_do_trans(log, trans, pass))) + return error; + xlog_recover_free_trans(trans); /* no error */ + return 0; +} /* xlog_recover_commit_trans */ + +STATIC void +xlog_recover_insert_item_backq(xlog_recover_item_t **q, + xlog_recover_item_t *item) +{ + if (*q == 0) { + item->ri_prev = item->ri_next = item; + *q = item; + } else { + item->ri_next = *q; + item->ri_prev = (*q)->ri_prev; + (*q)->ri_prev = item; + item->ri_prev->ri_next = item; + } +} /* xlog_recover_insert_item_backq */ + +STATIC void +xlog_recover_add_item(xlog_recover_item_t **itemq) +{ + xlog_recover_item_t *item; + + item = kmem_zalloc(sizeof(xlog_recover_item_t), 0); + xlog_recover_insert_item_backq(itemq, item); +} /* xlog_recover_add_item */ + +/* The next region to add is the start of a new region. It could be + * a whole region or it could be the first part of a new region. Because + * of this, the assumption here is that the type and size fields of all + * format structures fit into the first 32 bits of the structure. + * + * This works because all regions must be 32 bit aligned. Therefore, we + * either have both fields or we have neither field. In the case we have + * neither field, the data part of the region is zero length. We only have + * a log_op_header and can throw away the header since a new one will appear + * later. If we have at least 4 bytes, then we can determine how many regions + * will appear in the current log item. + */ +STATIC int +xlog_recover_add_to_trans(xlog_recover_t *trans, + xfs_caddr_t dp, + int len) +{ + xfs_inode_log_format_t *in_f; /* any will do */ + xlog_recover_item_t *item; + xfs_caddr_t ptr; + + if (!len) + return 0; + ptr = kmem_zalloc(len, 0); + bcopy(dp, ptr, len); + + in_f = (xfs_inode_log_format_t *)ptr; + item = trans->r_itemq; + if (item == 0) { + ASSERT(*(uint *)dp == XFS_TRANS_HEADER_MAGIC); + if (len == sizeof(xfs_trans_header_t)) + xlog_recover_add_item(&trans->r_itemq); + bcopy(dp, &trans->r_theader, len); /* s, d, l */ + return 0; + } + if (item->ri_prev->ri_total != 0 && + item->ri_prev->ri_total == item->ri_prev->ri_cnt) { + xlog_recover_add_item(&trans->r_itemq); + } + item = trans->r_itemq; + item = item->ri_prev; + + if (item->ri_total == 0) { /* first region to be added */ + item->ri_total = in_f->ilf_size; + ASSERT(item->ri_total <= XLOG_MAX_REGIONS_IN_ITEM); + item->ri_buf = kmem_zalloc((item->ri_total * + sizeof(xfs_log_iovec_t)), 0); + } + ASSERT(item->ri_total > item->ri_cnt); + /* Description region is ri_buf[0] */ + item->ri_buf[item->ri_cnt].i_addr = ptr; + item->ri_buf[item->ri_cnt].i_len = len; + item->ri_cnt++; + return 0; +} /* xlog_recover_add_to_trans */ + +STATIC int +xlog_recover_add_to_cont_trans(xlog_recover_t *trans, + xfs_caddr_t dp, + int len) +{ + xlog_recover_item_t *item; + xfs_caddr_t ptr, old_ptr; + int old_len; + + item = trans->r_itemq; + if (item == 0) { + /* finish copying rest of trans header */ + xlog_recover_add_item(&trans->r_itemq); + ptr = (xfs_caddr_t)&trans->r_theader+sizeof(xfs_trans_header_t)-len; + bcopy(dp, ptr, len); /* s, d, l */ + return 0; + } + item = item->ri_prev; + + old_ptr = item->ri_buf[item->ri_cnt-1].i_addr; + old_len = item->ri_buf[item->ri_cnt-1].i_len; + + ptr = kmem_realloc(old_ptr, len+old_len, old_len, 0); + bcopy(dp , &ptr[old_len], len); /* s, d, l */ + item->ri_buf[item->ri_cnt-1].i_len += len; + item->ri_buf[item->ri_cnt-1].i_addr = ptr; + return 0; +} /* xlog_recover_add_to_cont_trans */ + +STATIC int +xlog_recover_unmount_trans(xlog_recover_t *trans) +{ + /* Do nothing now */ + xlog_warn("XFS: xlog_recover_unmount_trans: Unmount LR"); + return( 0 ); +} /* xlog_recover_unmount_trans */ + + +STATIC int +xlog_recover_process_data(xlog_t *log, + xlog_recover_t *rhash[], + xlog_rec_header_t *rhead, + xfs_caddr_t dp, + int pass) +{ + xfs_caddr_t lp = dp+INT_GET(rhead->h_len, ARCH_CONVERT); + int num_logops = INT_GET(rhead->h_num_logops, ARCH_CONVERT); + xlog_op_header_t *ohead; + xlog_recover_t *trans; + xlog_tid_t tid; + int error; + unsigned long hash; + uint flags; + + /* check the log format matches our own - else we can't recover */ + if (xlog_header_check_recover(log->l_mp, rhead)) + return (XFS_ERROR(EIO)); + + while (dp < lp) { + ASSERT(dp + sizeof(xlog_op_header_t) <= lp); + ohead = (xlog_op_header_t *)dp; + dp += sizeof(xlog_op_header_t); + if (ohead->oh_clientid != XFS_TRANSACTION && + ohead->oh_clientid != XFS_LOG) { + xlog_warn("XFS: xlog_recover_process_data: bad clientid"); + ASSERT(0); + return (XFS_ERROR(EIO)); + } + tid = INT_GET(ohead->oh_tid, ARCH_CONVERT); + hash = XLOG_RHASH(tid); + trans = xlog_recover_find_tid(rhash[hash], tid); + if (trans == NULL) { /* not found; add new tid */ + if (ohead->oh_flags & XLOG_START_TRANS) + xlog_recover_new_tid(&rhash[hash], tid, INT_GET(rhead->h_lsn, ARCH_CONVERT)); + } else { + ASSERT(dp+INT_GET(ohead->oh_len, ARCH_CONVERT) <= lp); + flags = ohead->oh_flags & ~XLOG_END_TRANS; + if (flags & XLOG_WAS_CONT_TRANS) + flags &= ~XLOG_CONTINUE_TRANS; + switch (flags) { + case XLOG_COMMIT_TRANS: { + error = xlog_recover_commit_trans(log, &rhash[hash], + trans, pass); + break; + } + case XLOG_UNMOUNT_TRANS: { + error = xlog_recover_unmount_trans(trans); + break; + } + case XLOG_WAS_CONT_TRANS: { + error = xlog_recover_add_to_cont_trans(trans, dp, + INT_GET(ohead->oh_len, ARCH_CONVERT)); + break; + } + case XLOG_START_TRANS : { + xlog_warn("XFS: xlog_recover_process_data: bad transaction"); + ASSERT(0); + error = XFS_ERROR(EIO); + break; + } + case 0: + case XLOG_CONTINUE_TRANS: { + error = xlog_recover_add_to_trans(trans, dp, + INT_GET(ohead->oh_len, ARCH_CONVERT)); + break; + } + default: { + xlog_warn("XFS: xlog_recover_process_data: bad flag"); + ASSERT(0); + error = XFS_ERROR(EIO); + break; + } + } /* switch */ + if (error) + return error; + } /* if */ + dp += INT_GET(ohead->oh_len, ARCH_CONVERT); + num_logops--; + } + return( 0 ); +} /* xlog_recover_process_data */ + +/* + * Read the log from tail to head and process the log records found. + * Handle the two cases where the tail and head are in the same cycle + * and where the active portion of the log wraps around the end of + * the physical log separately. The pass parameter is passed through + * to the routines called to process the data and is not looked at + * here. + */ +int +xlog_do_recovery_pass(xlog_t *log, + xfs_daddr_t head_blk, + xfs_daddr_t tail_blk, + int pass) +{ + xlog_rec_header_t *rhead; + xfs_daddr_t blk_no; + xfs_caddr_t bufaddr; + xfs_buf_t *hbp, *dbp; + int error; + int bblks, split_bblks; + xlog_recover_t *rhash[XLOG_RHASH_SIZE]; + + error = 0; + hbp = xlog_get_bp(1,log->l_mp); + if (!hbp) + return -ENOMEM; + dbp = xlog_get_bp(BTOBB(XLOG_MAX_RECORD_BSIZE),log->l_mp); + if (!dbp) { + xlog_put_bp(hbp); + return -ENOMEM; + } + bzero(rhash, sizeof(rhash)); + if (tail_blk <= head_blk) { + for (blk_no = tail_blk; blk_no < head_blk; ) { + if ((error = xlog_bread(log, blk_no, 1, hbp))) + goto bread_err; + rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp); + ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); + ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX)); + bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); /* blocks in data section */ + if (bblks > 0) { + if ((error = xlog_bread(log, blk_no+1, bblks, dbp))) + goto bread_err; + xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log); + if ((error = xlog_recover_process_data(log, rhash, + rhead, XFS_BUF_PTR(dbp), + pass))) + goto bread_err; + } + blk_no += (bblks+1); + } + } else { + /* + * Perform recovery around the end of the physical log. When the head + * is not on the same cycle number as the tail, we can't do a sequential + * recovery as above. + */ + blk_no = tail_blk; + while (blk_no < log->l_logBBsize) { + + /* Read header of one block */ + if ((error = xlog_bread(log, blk_no, 1, hbp))) + goto bread_err; + rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp); + ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); + ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX)); + bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); + + /* LR body must have data or it wouldn't have been written */ + ASSERT(bblks > 0); + blk_no++; /* successfully read header */ + ASSERT(blk_no <= log->l_logBBsize); + + if ((INT_GET(rhead->h_magicno, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) || + (BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) > INT_MAX)) || + (bblks <= 0) || + (blk_no > log->l_logBBsize)) { + error = EFSCORRUPTED; + goto bread_err; + } + + /* Read in data for log record */ + if (blk_no+bblks <= log->l_logBBsize) { + if ((error = xlog_bread(log, blk_no, bblks, dbp))) + goto bread_err; + } else { + /* This log record is split across physical end of log */ + split_bblks = 0; + if (blk_no != log->l_logBBsize) { + + /* some data is before physical end of log */ + ASSERT(blk_no <= INT_MAX); + split_bblks = log->l_logBBsize - (int)blk_no; + ASSERT(split_bblks > 0); + if ((error = xlog_bread(log, blk_no, split_bblks, dbp))) + goto bread_err; + } + bufaddr = XFS_BUF_PTR(dbp); + XFS_BUF_SET_PTR(dbp, bufaddr + BBTOB(split_bblks), + BBTOB(bblks - split_bblks)); + if ((error = xlog_bread(log, 0, bblks - split_bblks, dbp))) + goto bread_err; + XFS_BUF_SET_PTR(dbp, bufaddr, XLOG_MAX_RECORD_BSIZE); + } + xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log); + if ((error = xlog_recover_process_data(log, rhash, + rhead, XFS_BUF_PTR(dbp), + pass))) + goto bread_err; + blk_no += bblks; + } + + ASSERT(blk_no >= log->l_logBBsize); + blk_no -= log->l_logBBsize; + + /* read first part of physical log */ + while (blk_no < head_blk) { + if ((error = xlog_bread(log, blk_no, 1, hbp))) + goto bread_err; + rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp); + ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); + ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX)); + bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); + ASSERT(bblks > 0); + if ((error = xlog_bread(log, blk_no+1, bblks, dbp))) + goto bread_err; + xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log); + if ((error = xlog_recover_process_data(log, rhash, + rhead, XFS_BUF_PTR(dbp), + pass))) + goto bread_err; + blk_no += (bblks+1); + } + } + +bread_err: + xlog_put_bp(dbp); + xlog_put_bp(hbp); + + return error; +} diff -rNu linux-2.4.7/cmd/xfsprogs/man/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/man/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/man/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/CVS/Entries Thu Jul 5 11:44:45 2001 @@ -0,0 +1,2 @@ +/Makefile/1.2/Mon Jan 15 06:52:52 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/man/CVS/Entries.Log linux-2.4-xfs/cmd/xfsprogs/man/CVS/Entries.Log --- linux-2.4.7/cmd/xfsprogs/man/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/CVS/Entries.Log Thu Jul 5 11:44:45 2001 @@ -0,0 +1,3 @@ +A D/man3//// +A D/man5//// +A D/man8//// diff -rNu linux-2.4.7/cmd/xfsprogs/man/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/man/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/man/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/CVS/Repository Thu Jul 5 11:44:45 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/man diff -rNu linux-2.4.7/cmd/xfsprogs/man/CVS/Root linux-2.4-xfs/cmd/xfsprogs/man/CVS/Root --- linux-2.4.7/cmd/xfsprogs/man/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/CVS/Root Thu Jul 5 11:44:45 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/man/Makefile linux-2.4-xfs/cmd/xfsprogs/man/Makefile --- linux-2.4.7/cmd/xfsprogs/man/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/Makefile Mon Jan 15 00:52:52 2001 @@ -0,0 +1,41 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +SUBDIRS = man3 man5 man8 + +default install install-dev : $(SUBDIRS) + $(SUBDIRS_MAKERULE) + +include $(BUILDRULES) diff -rNu linux-2.4.7/cmd/xfsprogs/man/man3/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/man/man3/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/man/man3/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man3/CVS/Entries Thu Jul 5 11:44:45 2001 @@ -0,0 +1,3 @@ +/Makefile/1.1/Mon Jan 15 06:52:52 2001/-ko/ +/handle.3/1.1/Mon Jan 15 06:52:52 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/man/man3/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/man/man3/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/man/man3/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man3/CVS/Repository Thu Jul 5 11:44:45 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/man/man3 diff -rNu linux-2.4.7/cmd/xfsprogs/man/man3/CVS/Root linux-2.4-xfs/cmd/xfsprogs/man/man3/CVS/Root --- linux-2.4.7/cmd/xfsprogs/man/man3/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man3/CVS/Root Thu Jul 5 11:44:45 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/man/man3/Makefile linux-2.4-xfs/cmd/xfsprogs/man/man3/Makefile --- linux-2.4.7/cmd/xfsprogs/man/man3/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man3/Makefile Mon Jan 15 00:52:52 2001 @@ -0,0 +1,50 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +MAN_SECTION = 3 + +MAN_PAGES = $(shell echo *.$(MAN_SECTION)) +MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) +LSRCFILES = $(MAN_PAGES) + +default : $(MAN_PAGES) + +include $(BUILDRULES) + +install : + +install-dev : default + $(INSTALL) -m 755 -d $(MAN_DEST) + $(INSTALL_MAN) diff -rNu linux-2.4.7/cmd/xfsprogs/man/man3/handle.3 linux-2.4-xfs/cmd/xfsprogs/man/man3/handle.3 --- linux-2.4.7/cmd/xfsprogs/man/man3/handle.3 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man3/handle.3 Mon Jan 15 00:52:52 2001 @@ -0,0 +1,196 @@ +.TH HANDLE 3 +.SH NAME +path_to_handle, path_to_fshandle, fd_to_handle, handle_to_fshandle, open_by_handle, readlink_by_handle, attr_multi_by_handle, attr_list_by_handle, fssetdm_by_handle, free_handle \- file handle operations +.SH C SYNOPSIS +.nf +.B #include +.B #include +.PP +.B "int path_to_handle (char *path, void **hanp," +.B " size_t *hlen);" +.PP +.B "int path_to_fshandle (char *path, void **hanp," +.B " size_t *hlen);" +.PP +.B "int fd_to_handle (int fd, void **hanp, size_t *hlen); +.PP +.B "int handle_to_fshandle (void *hanp, size_t hlen," +.B " void **fshanp, size_t *fshlen); +.PP +.B "int open_by_handle (void *hanp, size_t hlen," +.B " int oflag);" +.PP +.B "int readlink_by_handle (void *hanp, size_t hlen," +.B " void *buf, size_t bs); +.PP +.B "int attr_multi_by_handle (void *hanp, size_t hlen," +.B " void *buf, int rtrvcnt," +.B " int flags);" +.PP +.B "int attr_list_by_handle (void *hanp, size_t hlen," +.B " char *buf, size_t bufsiz," +.B " int flags," +.B " struct attrlist_cursor *cursor);" +.PP +.B "int fssetdm_by_handle (void *hanp, size_t hlen," +.B " struct fsdmidata *fssetdm);" +.PP +.B "void free_handle (void *hanp, size_t hlen); +.Op +.SH DESCRIPTION +.PP +These functions provide a way to perform certain +filesystem operations without using a file descriptor +to access filesystem objects. +They are intended for use by a limited set of system utilities +such as backup programs. +They are supported only by the XFS filesystem. +Link with the +.I libhandle +library to access these functions. +.sp +A +.I handle +uniquely identifies a filesystem object +or an entire filesystem. +There is one and only one +handle per filesystem or filesystem object. +Handles consist of some number of bytes. +The size of a handle +(i.e. the number of bytes comprising it) +varies by the type of handle +and may vary for different objects +of the same type. +The content of a handle is opaque to applications. +Since handle sizes vary +and their contents are opaque, +handles are described by two quantities, +a pointer and a size. +The size indicates the number of bytes +in the handle which are pointed to by the pointer. +.P +The \f2path_to_handle\f1() function +returns the handle for the object given by the +.I path +argument. +If the final component of the path name is a symbolic link, +the handle returned is that of the link itself. +.P +The \f2path_to_fshandle\f1() function +returns the handle for the filesystem +in which the object given by the +.I path +argument resides. +.P +The \f2fd_to_handle\f1() function +returns the handle for the object referenced by the +.I fd +argument, +which must be a valid file descriptor. +.P +The \f2handle_to_fshandle\f1() function +returns the handle for the filesystem +in which the object referenced by the +handle given by the +.I hanp +and +.I hlen +arguments resides. +.P +The \f2open_by_handle\f1() function +opens a file descriptor for the object referenced +by a handle. +It is analogous and identical to +.I open(2) +with the exception of accepting handles instead of path names. +.P +The \f2readlink_by_handle\f1() function +returns the contents of a symbolic link +referenced by a handle. +.P +The \f2attr_multi_by_handle\f1() function +manipulates multiple user attributes on a +filesystem object. +It is analogous and identical to +.I attr_multif(2) +except that a handle is specified instead of a file descriptor. +.P +The \f2attr_list_by_handle\f1() function returns +the names of the user attributes of a filesystem object. +It is analogous and identical to +.I attr_listf(2) +except that a handle is specified instead of a file descriptor. +.P +The \f2fssetdm_by_handle\f1() function sets the +di_dmevmask and di_dmstate fields in an XFS on-disk inode. +It is analogous to the \f2F_FSSETDM\f1 subfunction of +.I fcntl(2) +except that a handle is specified instead of a file descriptor. +.P +The \f2free_handle\f1() function +frees the storage allocated for handles +returned by the following functions: +\f2path_to_handle\f1(), +\f2path_to_fshandle\f1(), +\f2fd_to_handle\f1(), +and +\f2handle_to_fshandle\f1(). +.SH "SEE ALSO" +open(2), +readlink(2), +attr_multi(2), +attr_list(2), +fcntl(2). +.SH "DIAGNOSTICS" +.PP +The function +\f2free_handle\f1() +has no failure indication. +The other functions +return the value 0 to the calling process +if they succeed; +otherwise, they return the value -1 and set +.I errno +to indicate the error: +.sp +.TP 15 +.SM +\%[EACCES] +Search permission was denied for a component of +.IR path . +.TP 15 +.SM +\%[EBADF] +.I fd +is not a valid and open file descriptor. +.TP 15 +.SM +\%[EFAULT] +An argument pointed to an invalid address. +.TP 15 +.SM +\%[EINVAL] +.I path +is in a filesystem that does not support these functions. +.TP 15 +.SM +\%[ELOOP] +Too many symbolic links were encountered in translating the path name. +.TP 15 +.SM +\%[ENAMETOOLONG] +A component of +.I path +or the entire length of +.I path +exceeds filesystem limits. +.TP 15 +.SM +\%[ENOENT] +A component of +.I path +does not exist. +.TP 15 +.SM +\%[EPERM] +The caller does not have sufficient privileges. diff -rNu linux-2.4.7/cmd/xfsprogs/man/man5/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/man/man5/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/man/man5/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man5/CVS/Entries Thu Jul 5 11:44:45 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Mon Jan 15 06:52:52 2001/-ko/ +/xfs.5/1.2/Wed May 9 06:56:06 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/man/man5/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/man/man5/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/man/man5/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man5/CVS/Repository Thu Jul 5 11:44:45 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/man/man5 diff -rNu linux-2.4.7/cmd/xfsprogs/man/man5/CVS/Root linux-2.4-xfs/cmd/xfsprogs/man/man5/CVS/Root --- linux-2.4.7/cmd/xfsprogs/man/man5/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man5/CVS/Root Thu Jul 5 11:44:45 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/man/man5/Makefile linux-2.4-xfs/cmd/xfsprogs/man/man5/Makefile --- linux-2.4.7/cmd/xfsprogs/man/man5/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man5/Makefile Mon Jan 15 00:52:52 2001 @@ -0,0 +1,49 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +MAN_SECTION = 5 + +MAN_PAGES = $(shell echo *.$(MAN_SECTION)) +MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) +LSRCFILES = $(MAN_PAGES) + +default : $(MAN_PAGES) + +include $(BUILDRULES) + +install : default + $(INSTALL) -m 755 -d $(MAN_DEST) + $(INSTALL_MAN) +install-dev : diff -rNu linux-2.4.7/cmd/xfsprogs/man/man5/xfs.5 linux-2.4-xfs/cmd/xfsprogs/man/man5/xfs.5 --- linux-2.4.7/cmd/xfsprogs/man/man5/xfs.5 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man5/xfs.5 Wed May 9 01:56:06 2001 @@ -0,0 +1,111 @@ +.TH xfs 5 +.SH NAME +xfs \- layout of the XFS filesystem +.SH DESCRIPTION +An XFS filesystem can reside on a regular disk partition or on a +logical volume (see +.IR lvm (8)). +An XFS filesystem has up to three parts: +a data section, a log section, and a realtime section. +Using the default +.IR mkfs.xfs (8) +options, the realtime section is absent, and +the log area is contained within the data section. +For logical volume filesystems, +the realtime section is optional, +and the log section can be separate from the data section +or contained within it. +The filesystem sections are divided into a certain number of +.IR blocks , +whose size is specified at +.IR mkfs.xfs +time with the +.B \-b +option. +.PP +The data section contains all the filesystem metadata +(inodes, directories, indirect blocks) +as well as the user file data for ordinary (non-realtime) files +and the log area if the log is +.I internal +to the data section. +The data section is divided into a number of +\f2allocation groups\f1. +The number and size of the allocation groups are chosen by +.I mkfs.xfs +so that there is normally a small number of equal-sized groups. +The number of allocation groups controls the amount of parallelism +available in file and block allocation. +It should be increased from +the default if there is sufficient memory and a lot of allocation +activity. +The number of allocation groups should not be set very high, +since this can cause large amounts of CPU time to be used by +the filesystem, especially when the filesystem is nearly full. +More allocation groups are added (of the original size) when +.IR xfs_growfs (8) +is run. +.PP +The log section (or area, if it is internal to the data section) +is used to store changes to filesystem metadata while the +filesystem is running until those changes are made to the data +section. +It is written sequentially during normal operation and read only +during mount. +When mounting a filesystem after a crash, the log +is read to complete operations that were +in progress at the time of the crash. +.PP +The realtime section is used to store the data of realtime files. +These files had an attribute bit set through +.IR ioctl (2) +after file creation, before any data was written to the file. +The realtime section is divided into a number of +.I extents +of fixed size (specified at +.I mkfs.xfs +time). +Each file in the realtime section has an extent size that +is a multiple of the realtime section extent size. +.PP +Each allocation group contains several data structures. +The first sector contains the superblock. +For allocation groups after the first, +the superblock is just a copy and is not updated after +.IR mkfs.xfs . +The next three sectors contain information for block and inode +allocation within the allocation group. +Also contained within each allocation group are data structures +to locate free blocks and inodes; +these are located through the header structures. +.PP +Each XFS filesystem is labeled with a unique +universal identifier (UUID). +The UUID is stored in every allocation group header and +is used to help distinguish one XFS filesystem from another, +therefore you should avoid using +.I dd +or other block-by-block copying programs to copy XFS filesystems. +If two XFS filesystems on the same machine have the same UUID, +.I xfsdump +may become confused when doing incremental and resumed dumps +(refer to +.IR xfsdump (8) +for more details). +.I xfsdump +and +.I xfsrestore +are recommended for making copies of XFS filesystems. +.SH SEE ALSO +fs(5), +mkfs.xfs(8), +xfs_bmap(8), +xfs_check(8), +xfs_estimate(8), +xfs_growfs(8), +xfs_logprint(8), +xfs_repair(8), +xfsdump(8), +xfsrestore(8), +ioctl(2), +lvm(8). diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/man/man8/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/man/man8/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/CVS/Entries Thu Jul 5 11:44:46 2001 @@ -0,0 +1,15 @@ +/Makefile/1.2/Mon Jan 15 06:52:52 2001/-ko/ +/fsck.xfs.8/1.2/Thu Jan 25 03:35:58 2001/-ko/ +/mkfs.xfs.8/1.6/Wed May 16 10:25:13 2001/-ko/ +/xfs_admin.8/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_bmap.8/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_check.8/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_db.8/1.2/Thu Jan 25 03:35:58 2001/-ko/ +/xfs_freeze.8/1.2/Wed May 23 01:08:46 2001/-ko/ +/xfs_growfs.8/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_logprint.8/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_mkfile.8/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_ncheck.8/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_repair.8/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_rtcp.8/1.1/Wed May 9 06:56:06 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/man/man8/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/man/man8/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/CVS/Repository Thu Jul 5 11:44:45 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/man/man8 diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/CVS/Root linux-2.4-xfs/cmd/xfsprogs/man/man8/CVS/Root --- linux-2.4.7/cmd/xfsprogs/man/man8/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/CVS/Root Thu Jul 5 11:44:45 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/Makefile linux-2.4-xfs/cmd/xfsprogs/man/man8/Makefile --- linux-2.4.7/cmd/xfsprogs/man/man8/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/Makefile Mon Jan 15 00:52:52 2001 @@ -0,0 +1,50 @@ +#! gmake +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../.. +include $(TOPDIR)/include/builddefs + +MAN_SECTION = 8 + +MAN_PAGES = $(shell echo *.$(MAN_SECTION)) +MAN_DEST = $(PKG_MAN_DIR)/man$(MAN_SECTION) +LSRCFILES = $(MAN_PAGES) + +default : $(MAN_PAGES) + +include $(BUILDRULES) + +install : default + $(INSTALL) -m 755 -d $(MAN_DEST) + $(INSTALL_MAN) +install-dev : diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/fsck.xfs.8 linux-2.4-xfs/cmd/xfsprogs/man/man8/fsck.xfs.8 --- linux-2.4.7/cmd/xfsprogs/man/man8/fsck.xfs.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/fsck.xfs.8 Wed Jan 24 21:35:58 2001 @@ -0,0 +1,23 @@ +.TH fsck.xfs 8 +.SH NAME +fsck.xfs \- do nothing, successfully +.SH SYNOPSIS +.nf +\f3fsck.xfs\f1 [ \f3...\f1] +.fi +.SH DESCRIPTION +.I fsck.xfs +is called by the generic Linux +.IR fsck (8) +program at startup to check and repair an XFS filesystem. +XFS is a journaling filesystem and performs recovery at +.IR mount (8) +time if necessary, so +.I fsck.xfs +simply exits with a zero exit status. +.SH FILES +.IR /etc/fstab . +.SH SEE ALSO +fsck(8), +fstab(5), +xfs(5). diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/mkfs.xfs.8 linux-2.4-xfs/cmd/xfsprogs/man/man8/mkfs.xfs.8 --- linux-2.4.7/cmd/xfsprogs/man/man8/mkfs.xfs.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/mkfs.xfs.8 Wed May 16 05:25:13 2001 @@ -0,0 +1,561 @@ +.TH mkfs.xfs 8 +.SH NAME +mkfs.xfs \- construct an XFS filesystem +.SH SYNOPSIS +.nf +\f3mkfs.xfs\f1 [ \f3\-b\f1 subopt=value ] [ \f3\-d\f1 subopt[=value] ] + [ \f3\-i\f1 subopt=value ] [ \f3\-l\f1 subopt[=value] ] + [ \f3\-n\f1 subopt[=value] ] [ \f3\-p\f1 protofile ] [ \f3\-q\f1 ] + [ \f3\-r\f1 subopt[=value] ] [ \f3\-C\f1 ] [ \f3\-L\f1 label ] device +.fi +.SH DESCRIPTION +.I mkfs.xfs +constructs an XFS filesystem by writing on a special +file using the values found in the arguments of the command line. +It is invoked automatically by \f2mkfs\f1(8) when \f2mkfs\f1 is +given the \f3\-t xfs\f1 option. +.PP +In its simplest (and most commonly used form), the size of the +filesystem is determined from the disk driver. As an example, to make +a filesystem with an internal log on the first partition on the first +SCSI disk, use: +.PP +.nf + mkfs.xfs /dev/sda1 +.fi +.PP +The metadata log can be placed on another device to reduce the number +of disk seeks. To create a filesystem on the first partition on the +first SCSI disk with a 10000 block log located on the first partition +on the second SCSI disk, use: +.PP +.nf + mkfs.xfs -l logdev=/dev/sdb1,size=10000b /dev/sda1 +.fi +.PP +Each of the +.I subopt=value +elements in the argument list above can be given as multiple comma-separated +.I subopt=value +suboptions if multiple suboptions apply to the same option. +Equivalently, each main option can be given multiple times with +different suboptions. +For example, +.B \-l internal,size=10000b +and +.B \-l internal \-l size=10000b +are equivalent. +.PP +In the descriptions below, sizes are given in bytes, blocks, kilobytes, +or megabytes. +Sizes are treated as hexadecimal if prefixed by 0x or 0X, +octal if prefixed by 0, or decimal otherwise. +If suffixed with \f3b\f1 then the size is converted by multiplying it +by the filesystem's block size. +If suffixed with \f3k\f1 then the size is converted by multiplying it by 1024. +If suffixed with \f3m\f1 then the size is converted by multiplying it by +1048576 (1024 * 1024). +If suffixed with \f3g\f1 then the size is converted by multiplying it by +1073741824 (1024 * 1024 * 1024). +.TP +.B \-b +Block size options. +.IP +This option specifies the fundamental block size of the filesystem. +The valid suboptions are: +.BI log= value +and +\f3size=\f1\f2value\f1; +only one can be supplied. +The block size is specified either as a base two logarithm value with +.BR log= , +or in bytes with +.BR size= . +The default value is 4096 bytes (4 KB) on systems with a 4KB pagesize. +The minimum value for block size is 512; the maximum is 65536 (64 KB). +XFS on Linux currently only supports pagesize blocks. +.TP +.B \-d +Data section options. +.IP +These options specify the location, size, and other parameters of the +data section of the filesystem. +The valid suboptions are: +\f3agcount=\f1\f2value\f1, +\f3agsize=\f1\f2value\f1, +\f3file\f1[\f3=\f1\f2value\f1], +\f3name=\f1\f2value\f1, +\f3size=\f1\f2value\f1, +\f3sunit=\f1\f2value\f1, +\f3swidth=\f1\f2value\f1, +\f3su=\f1\f2value\f1, +\f3sw=\f1\f2value\f1, +and +\f3unwritten\f1[\f3=\f1\f2value\f1]. +.IP +The +.B agcount +suboption is used to specify the number of allocation groups. +The data section of the filesystem is divided into allocation groups +to improve the performance of XFS. +More allocation groups imply that more parallelism can be achieved +when allocating blocks and inodes. +The minimum allocation group size is 16 MB; +the maximum size is just under 4 GB. +The data section of the filesystem is divided into +.I agcount +allocation groups (default value 8, unless the filesystem is smaller +than 128 MB or larger than 8 GB). +Setting +.I agcount +to a very large number should be avoided, since this causes an unreasonable +amount of CPU time to be used when the filesystem is close to full. +.IP +The +.B agsize +suboption is an alternative to using +.B agcount. +The argument provided to +.B agsize +is the desired size of the allocation group expressed in bytes +(usually using the \f3m\f1 or \f3g\f1 suffixes). +This value must be a multiple of the filesystem block size, and +must be at least 16MB, and no more than 4GB, and may +be automatically adjusted to properly align with the stripe geometry. +The +.B agcount +suboption and the +.B agsize +suboption are mutually exclusive. +.IP +The +.B name +suboption can be used to specify the name of the special file containing +the filesystem. +In this case, the log section must be specified as +.B internal +(with a size, see the +.B \-l +option below) and there can be no real-time section. +.IP +The +.B file +suboption is used to specify that the file given by the +.B name +suboption is a regular file. +The suboption value is either 0 or 1, +with 1 signifying that the file is regular. +This suboption is used only to make a filesystem image. +If the value is omitted then 1 is assumed. +.IP +The +.B size +suboption is used to specify the size of the data section. +This suboption is required if +.B \-d file[=1] +is given. +Otherwise, it is only needed if the filesystem should occupy +less space than the size of the special file. +.IP +The +.B sunit +suboption is used to specify the stripe unit for a RAID device or a +logical volume. +The suboption value has to be specified in 512-byte block units. +Use the +.B su +suboption to specify the stripe unit size in bytes. +This suboption ensures that data allocations will be stripe unit aligned +when the current end of file is being extended and the file size is larger +than 512KB. +Also inode allocations and the internal log will be stripe unit aligned. +.IP +The +.B su +suboption is an alternative to using +.B sunit. +The +.B su +suboption is used to specify the stripe unit for a RAID device or a +striped logical volume. +The suboption value has to be specified in bytes, +(usually using the \f3m\f1 or \f3g\f1 suffixes). +This value must be a multiple of the filesystem block size. +.IP +The +.B swidth +suboption is used to specify the stripe width for a RAID device or a +striped logical volume. +The suboption value has to be specified in 512-byte block units. +Use the +.B sw +suboption to specify the stripe width size in bytes. +This suboption is required if +.B \-d sunit +has been specified and it has to be a multiple of the +.B \-d sunit +suboption. +The stripe width will be the preferred iosize returned in the +.IR stat (2) +system call. +.IP +The +.B sw +suboption is an alternative to using +.B swidth. +The +.B sw +suboption is used to specify the stripe width for a RAID device or +striped logical volume. +The suboption value is expressed as a multiplier of the stripe unit, +usually the same as the number of stripe members in the logical +volume configuration, or data disks in a RAID device. +.IP +When a filesystem is created on a logical volume device, +.I mkfs.xfs +will automatically query the logical volume for appropriate +.B sunit +and +.B swidth +values. +.IP +The +.B unwritten +suboption is used to specify whether unwritten extents are flagged as such, +or not. +The suboption value is either 0 or 1, with 1 signifying that unwritten +extent flagging should occur. +If the suboption is omitted, unwritten extent flagging is enabled. +If unwritten extents are flagged, filesystem write performance +will be negatively affected for preallocated file extents, since +extra filesystem transactions are required to convert extent flags +for the range of the file written. +This suboption should be disabled if the filesystem +needs to be used on operating system versions which do not support the +flagging capability. +.TP +.B \-i +Inode options. +.IP +This option specifies the inode size of the filesystem, and other +inode allocation parameters. +The XFS inode contains a fixed-size part and a variable-size part. +The variable-size part, whose size is affected by this option, can contain: +directory data, for small directories; +attribute data, for small attribute sets; +symbolic link data, for small symbolic links; +the extent list for the file, for files with a small number of extents; +and the root of a tree describing the location of extents for the file, +for files with a large number of extents. +.IP +The valid suboptions for specifying inode size are: +\f3log=\f1\f2value\f1, +\f3perblock=\f1\f2value\f1, +and +\f3size=\f1\f2value\f1; +only one can be supplied. +The inode size is specified either as a base two logarithm value with +.BR log= , +in bytes with +.BR size= , +or as the number fitting in a filesystem block with +.BR perblock= . +The mininum (and default) value is 256 bytes. +The maximum value is 2048 (2 KB) subject to the restriction that +the inode size cannot exceed one half of the filesystem block size. +.IP +The option \f3maxpct=\f1\f2value\f1 specifies the maximum percentage +of space in the filesystem that can be allocated to inodes. +The default value is 25%. +Setting the value to 0 means that +essentially all of the filesystem can become inode blocks. +.IP +The option +.BI align[= value ] +is used to specify that inode allocation is or is not aligned. +The value is either 0 or 1, +with 1 signifying that inodes are allocated aligned. +If the value is omitted, 1 is assumed. +The default is that inodes are aligned. +Aligned inode access is normally more efficient than unaligned access; +alignment must be established at the time the filesystem is created, +since inodes are allocated at that time. +This option can be used to turn off inode alignment when the +filesystem needs to be mountable by a version of IRIX +that does not have the inode alignment feature +(any release of IRIX before 6.2, and IRIX 6.2 without XFS patches). +.TP +.B \-l +Log section options. +.IP +These options specify the location, size, and other parameters of the +log section of the filesystem. +The valid suboptions are: +.BI internal[= value ] +and +\f3size=\f1\f2value\f1. +.IP +The +.B internal +suboption is used to specify that the log section is a piece of +the data section instead of being another device or logical volume. +The suboption value is either 0 or 1, +with 1 signifying that the log is internal. +If the value is omitted, 1 is assumed. +.IP +The +.B size +suboption is used to specify the size of the log section. +.IP +If the log is contained within the data section and +.B size +isn't specified, +.I mkfs.xfs +will try to select a suitable log size depending +on the size of the filesystem. The actual logsize depends on the +filesystem block size and the directory block size. +.IP +Otherwise, the +.B size +option is only needed if the log section of the filesystem +should occupy less space than the size of the special file. +The size is specified in bytes or blocks, with a \f3b\f1 suffix +meaning multiplication by the filesystem block size, as described above. +The overriding minimum value for size is 512 blocks. +With some combinations of filesystem block size, inode size, +and directory block size, the minimum log size is larger than 512 blocks. +.TP +.B \-n +Naming options. +.IP +These options specify the version and size parameters for the naming +(directory) area of the filesystem. +The valid suboptions are: +\f3log=\f1\f2value\f1, +\f3size=\f1\f2value\f1, +and +\f3version=\f1\f2value\f1. +The naming (directory) version is 1 or 2, +defaulting to 2 if unspecified. +With version 2 directories, +the directory block size can be any power of 2 size +from the filesystem block size up to 65536. +The block size is specified either as a base two logarithm value with +.BR log= , +or in bytes with +.BR size= . +The default size value for version 2 directories is 4096 bytes (4 KB), +unless the filesystem block size is larger than 4096, +in which case the default value is the filesystem block size. +For version 1 directories the block size is the same as the +filesystem block size. +.TP +\f3\-p\f1 \f2protofile\f1 +If the optional +.B \-p +.I protofile +argument is given, +.I mkfs.xfs +uses +.I protofile +as a prototype file +and takes its directions from that file. +The blocks and inodes +specifiers in the +.I protofile +are provided for backwards compatibility, but are otherwise unused. +The prototype file +contains tokens separated by spaces or +newlines. +A sample prototype specification follows (line numbers have been added to +aid in the explanation): +.nf +.sp .8v +.in +5 +\f71 /stand/\f1\f2diskboot\f1\f7 +2 4872 110 +3 d--777 3 1 +4 usr d--777 3 1 +5 sh ---755 3 1 /bin/sh +6 ken d--755 6 1 +7 $ +8 b0 b--644 3 1 0 0 +9 c0 c--644 3 1 0 0 +10 fifo p--644 3 1 +11 slink l--644 3 1 /a/symbolic/link +12 : This is a comment line +13 $ +14 $\f1 +.in -5 +.fi +.IP +Line 1 is a dummy string. +(It was formerly the bootfilename.) +It is present for backward +compatibility; boot blocks are not used on SGI systems. +.IP +Note that some string of characters must be present as the first line of +the proto file to cause it to be parsed correctly; the value +of this string is immaterial since it is ignored. +.IP +Line 2 contains two numeric values (formerly the numbers of blocks and inodes). +These are also merely for backward compatibility: two numeric values must +appear at this point for the proto file to be correctly parsed, +but their values are immaterial since they are ignored. +.IP +Lines 3-11 tell +.I mkfs.xfs +about files and directories to +be included in this filesystem. +Line 3 specifies the root directory. +Lines 4-6 and 8-10 specifies other directories and files. +Note the special symbolic link syntax on line 11. +.IP +The +.B $ +on line 7 tells +.I mkfs.xfs +to end the branch of the filesystem it is on, and continue +from the next higher directory. +It must be the last character +on a line. +The colon +on line 12 introduces a comment; all characters up until the +following newline are ignored. +Note that this means you cannot +have a file in a prototype file whose name contains a colon. +The +.B $ +on lines 13 and 14 end the process, since no additional +specifications follow. +.IP +File specifications give the mode, +the user ID, +the group ID, +and the initial contents of the file. +Valid syntax for the contents field +depends on the first character of the mode. +.IP +The mode for a file is specified by a 6-character string. +The first character +specifies the type of the file. +The character range is +.B \-bcdpl +to specify regular, block special, +character special, directory files, named pipes (fifos), and symbolic +links, respectively. +The second character of the mode +is either +.B u +or +.B \- +to specify setuserID mode or not. +The third is +.B g +or +.B \- +for the setgroupID mode. +The rest of the mode +is a three digit octal number giving the +owner, group, and other read, write, execute +permissions (see +.IR chmod (1)). +.IP +Two decimal number +tokens come after the mode; they specify the +user and group IDs of the owner of the file. +.IP +If the file is a regular file, +the next token of the specification can be a pathname +from which the contents and size are copied. +If the file is a block or character special file, +two decimal numbers +follow that give the major and minor device numbers. +If the file is a symbolic link, the next token of the specification +is used as the contents of the link. +If the file is a directory, +.I mkfs.xfs +makes the entries +.BR . "" +and +.B .. +and then +reads a list of names and +(recursively) +file specifications for the entries +in the directory. +As noted above, the scan is terminated with the +token +.BR $ . +.TP +.B \-q +Quiet option. +.IP +Normally +.I mkfs.xfs +prints the parameters of the filesystem +to be constructed; +the +.B \-q +flag suppresses this. +.TP +.B \-r +Real-time section options. +.IP +These options specify the location, size, and other parameters of the +real-time section of the filesystem. +The valid suboptions are: +.BI extsize= value +and +\f3size=\f1\f2value\f1. +.IP +The +.B extsize +suboption is used to specify the size of the blocks in the real-time +section of the filesystem. +This size must be a multiple of the filesystem block size. +The minimum allowed value is the filesystem block size +or 4 KB (whichever is larger); +the default value is the stripe width for striped volumes or 64 KB for +non-striped volumes; +the maximum allowed value is 1 GB. +The real-time extent size should be carefully chosen to match the +parameters of the physical media used. +.IP +The +.B size +suboption is used to specify the size of the real-time section. +This suboption is only needed if the real-time section of the +filesystem should occupy +less space than the size of the partition or logical volume containing the section. +.TP +.B \-C +Disable overlapping partition/volume checks. +.IP +By default \f2mkfs.xfs\f1 checks to see if the destination partition or logical +volume overlaps any mounted or reserved partitions in the system. If an +overlap or mount conflict is found, the user will be notified and prevented +from potentially corrupting the existing data. For systems with +a large number of disks, this additional checking may add noticable overhead +to the command's execution time. For situations where command performance is +necessary, this switch may be used to disable the safeguards. Due to the +potential for user-error causing corrupted filesystems or other on-disk +data corruption, we strongly discourage use of this switch in normal operation. +.TP +\f3\-L\f1 \f2label\f1 +Set the filesystem label. +XFS filesystem labels can be at most 12 characters long; if +.I label +is longer than 12 characters, +.I mkfs.xfs +will not proceed with creating the filesystem. Refer to the +.IR mount (8) +and +.IR xfs_admin (8) +manual entries for additional information. +.SH SEE ALSO +mkfs(8), +mount(8), +xfs_admin(8). +.SH BUGS +With a prototype file, it is not possible to specify hard links. diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/xfs_admin.8 linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_admin.8 --- linux-2.4.7/cmd/xfsprogs/man/man8/xfs_admin.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_admin.8 Sun Jan 14 23:36:03 2001 @@ -0,0 +1,68 @@ +.TH xfs_admin 8 +.SH NAME +xfs_admin \- change parameters of an XFS filesystem +.SH SYNOPSIS +.nf +\f3xfs_admin\f1 [ \f3-lu\f1] [ \f3\-L \f2label\f1 ] [ \f3\-U \f2uuid\f1 ] device +\f3xfs_admin \-f\f1 [ \f3-lu\f1] [ \f3\-L \f2label\f1 ] [ \f3\-U \f2uuid\f1 ] filename +.fi +.SH DESCRIPTION +.I xfs_admin +uses the +.IR xfs_db (8) +command to modify various parameters of a filesystem. +.PP +Devices that are mounted cannot be modified. +Administrators must unmount filesystems before +.I xfs_admin +or +.I xfs_db +can convert parameters. +A number of parameters of a mounted filesystem can be examined +and modified using the +.IR xfs_growfs (8) +command. +.SH OPTIONS +.TP 5 +\f3\-f\f1 +Specifies that the filesystem image to be processed is stored in a +regular file (see the \f2mkfs.xfs\f1 \f3\-d\f1 \f2file\f1 option). +.TP 5 +\f3\-l\f1 +Print the current filesystem label. +.TP 5 +\f3\-u\f1 +Print the current filesystem UUID (Universally Unique IDentifier). +.TP 5 +\f3\-L\f1 \f2label\f1 +Set the filesystem label. +XFS filesystem labels can be at most 12 characters long; if +.I label +is longer than 12 characters, +.I xfs_admin +will truncate it and print a warning message. +The filesystem label can be cleared using the special ``\c +.BR \-\- '' +value for +.IR label . +.TP 5 +\f3\-U\f1 \f2UUID\f1 +Set the UUID of the filesystem. +A sample UUID looks like this: "c1b9d5a2-f162-11cf-9ece-0020afc76f16". +The uuid may also be +.IR null , +which will set the filesystem UUID to the null UUID. +The uuid may also be +.IR generate , +which will generate a new UUID for the filesystem. +.PP +The +.IR mount (8) +manual entry describes how to mount a filesystem using its label or UUID, +rather than its block special device name. +.SH SEE ALSO +mkfs.xfs(8), +mount(8), +xfs_db(8), +xfs_growfs(8), +xfs(5). diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/xfs_bmap.8 linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_bmap.8 --- linux-2.4.7/cmd/xfsprogs/man/man8/xfs_bmap.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_bmap.8 Sun Jan 14 23:36:03 2001 @@ -0,0 +1,54 @@ +.TH xfs_bmap 8 +.SH NAME +xfs_bmap \- print block mapping for an XFS file +.SH SYNOPSIS +.nf +\f3xfs_bmap\f1 [ \f3\-a\f1 ] [ \f3\-l\f1 ] [ \f3\-d\f1 ] [ \f3\-n \f2nnn\f1 ] file ... +.fi +.SH DESCRIPTION +.I xfs_bmap +prints the map of disk blocks used by files in an XFS filesystem. +The map lists each \f2extent\fP used by the file, as well as regions +in the file that do not have any corresponding blocks (\f2hole\f1s). +Each line of the listings takes the following form: + +.Ex +\f2extent\f1\f7: [\f1\f2startoffset\f1\f7..\f1\f2endoffset\f1\f7]: \c +\f1\f2startblock\f1\f7..\f1\f2endblock\f1 +.Ee + +Holes are marked by replacing the \f2startblock..endblock\f1 with \f2hole\fP. +All the file offsets and disk blocks are in units of 512-byte blocks, +no matter what the filesystem's block size is. +.PP +If portions of the file have been migrated offline by +a DMAPI application, a DMAPI read event will be generated to +bring those portions back online before the disk block map is +printed. However if the \f3-d\f1 option is used, no DMAPI read event +will be generated for a DMAPI file and offline portions will be reported as holes. +.PP +If the \f3-l\f1 option is used, then + +.Ex +\f1\f2\f1\f7 \f1\f2blocks\f1\f7 +.Ee + +will be appended to each line. \f1\f2Nblocks\f1\f7 is the length +of the extent described on the line in units of 512-byte blocks. +.PP +If the \f3\-a\f1 option is given, information about the file's +attribute fork is printed instead of the default data fork. +.PP +If the \f3\-n \f2nnn\f1 option is given, \f3xfs_bmap\f1 obtains the extent +list of the file in groups of \f2nnn\f1 extents. +In the absence of \f3\-n\f1, \f3xfs_bmap\f1 queries the system for +the number of extents in the file and uses that value to compute +the group size. +.SH DIAGNOSTICS +.TP 10 +\f7fcntl(F_GETBMAPX) \f1\f2filename\f1\f7: Invalid argument\f1 +The file \f2filename\f1 is not in an XFS filesystem. +.SH SEE ALSO +fcntl(2), +lvm(8). + diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/xfs_check.8 linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_check.8 --- linux-2.4.7/cmd/xfsprogs/man/man8/xfs_check.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_check.8 Sun Jan 14 23:36:03 2001 @@ -0,0 +1,177 @@ +.TH xfs_check 8 +.SH NAME +xfs_check \- check XFS filesystem consistency +.SH SYNOPSIS +.nf +\f3xfs_check\f1 [ \f3\-i\f1 ino ] ... [ \f3\-b\f1 bno ] ... \c +[ \f3\-s\f1 ] [ \f3\-v\f1 ] xfs_special +.sp .8v +\f3xfs_check\f1 \f3\-f\f1 [ \f3\-i\f1 ino ] ... [ \f3\-b\f1 bno ] ... \c +[ \f3\-s\f1 ] [ \f3\-v\f1 ] file +.fi +.SH DESCRIPTION +.I xfs_check +checks whether an XFS filesystem is consistent. +It is normally run only when there is reason to believe that the +filesystem has a consistency problem. +The filesystem to be checked is specified by the +.I xfs_special +argument, which should be the disk or volume device for the filesystem. +Filesystems stored in files can also be checked, using the \f3\-f\f1 flag. +The filesystem should normally be unmounted or read-only +during the execution of +.IR xfs_check . +Otherwise, spurious problems are reported. +.PP +The options to \f2xfs_check\f1 are: +.TP 9 +.B \-f +Specifies that the special device is actually a file (see the +\f2mkfs.xfs\f1 \f3\-d\f1 \f2file\f1 option). +This might happen if an image copy +of a filesystem has been made into an ordinary file. +.TP +.B \-s +Specifies that only serious errors should be reported. +Serious errors are those that make it impossible to find major data +structures in the filesystem. +This option can be used to cut down the +amount of output when there is a serious problem, when the output might make it +difficult to see what the real problem is. +.TP +.B \-v +Specifies verbose output; it is impossibly long for a +reasonably-sized filesystem. +This option is intended for internal use only. +.TP +.BI \-i " ino" +Specifies verbose behavior for a +specific inode. +For instance, it can be used to locate all the blocks +associated with a given inode. +.TP +.BI \-b " bno" +Specifies verbose behavior for a specific filesystem block. +For instance, it can be used to determine what a specific block +is used for. +The block number is a "file system block number". +Conversion between disk addresses (i.e. addresses reported by +.IR xfs_bmap ) +and file system blocks may be accomplished using +.IR xfs_db 's +.B convert +command. +.PP +Any non-verbose output from +.I xfs_check +means that the filesystem has an inconsistency. +The filesystem can be repaired using either +.IR xfs_repair(8) +to fix the filesystem in place, +or by using +.IR xfsdump (8) +and +.IR mkfs.xfs (8) +to dump the filesystem, +make a new filesystem, +then use +.IR xfsrestore (8) +to restore the data onto the new filesystem. +Note that xfsdump may fail on a corrupt filesystem. +However, if the filesystem is mountable, xfsdump can +be used to try and save important data before +repairing the filesystem with xfs_repair. +If the filesystem is not mountable though, xfs_repair is +the only viable option. +.SH DIAGNOSTICS +Under one circumstance, +.I xfs_check +unfortunately might dump core +rather than produce useful output. +If the filesystem is completely corrupt, a core dump might +be produced instead of the message +.Ex +\f2xxx\f1\f7 is not a valid filesystem\f1 +.Ee +.PP +If the filesystem is very large (has many files) then +.I xfs_check +might run out of memory. +In this case the message +.Ex +out of memory +.Ee +is printed. +.PP +The following is a description of the most likely problems and the associated +messages. +Most of the diagnostics produced are only meaningful with an understanding +of the structure of the filesystem. +.TP +\f7agf_freeblks \f1\f2n\f1\f7, counted \f1\f2m\f1\f7 in ag \f1\f2a\f1 +The freeblocks count in the allocation group header for allocation group +.I a +doesn't match the number of blocks counted free. +.TP +\f7agf_longest \f1\f2n\f1\f7, counted \f1\f2m\f1\f7 in ag \f1\f2a\f1 +The longest free extent in the allocation group header for allocation group +.I a +doesn't match the longest free extent found in the allocation group. +.TP +\f7agi_count \f1\f2n\f1\f7, counted \f1\f2m\f1\f7 in ag \f1\f2a\f1 +The allocated inode count in the allocation group header for allocation group +.I a +doesn't match the number of inodes counted in the allocation group. +.TP +\f7agi_freecount \f1\f2n\f1\f7, counted \f1\f2m\f1\f7 in ag \f1\f2a\f1 +The free inode count in the allocation group header for allocation group +.I a +doesn't match the number of inodes counted free in the allocation group. +.TP +\f7block \f1\f2a/b\f1\f7 expected inum 0 got \f1\f2i\f1 +The block number is specified as a pair +(allocation group number, block in the allocation group). +The block is used multiple times (shared), between multiple inodes. +This message usually follows a message of the next type. +.TP +\f7block \f1\f2a/b\f1\f7 expected type unknown got \f1\f2y\f1 +The block is used multiple times (shared). +.TP +\f7block \f1\f2a/b\f1\f7 type unknown not expected\f1 +The block is unaccounted for (not in the freelist and not in use). +.TP +\f7link count mismatch for inode \f1\f2nnn\f1\f7 (name \f1\f2xxx\f1\f7), nlink \f1\f2m\f1\f7, counted \f1\f2n\f1 +The inode has a bad link count (number of references in directories). +.TP +\f7rtblock \f1\f2b\f1\f7 expected inum 0 got \f1\f2i\f1 +The block is used multiple times (shared), between multiple inodes. +This message usually follows a message of the next type. +.TP +\f7rtblock \f1\f2b\f1\f7 expected type unknown got \f1\f2y\f1 +The real-time block is used multiple times (shared). +.TP +\f7rtblock \f1\f2b\f1\f7 type unknown not expected\f1 +The real-time block is unaccounted for (not in the freelist and not in use). +.TP +\f7sb_fdblocks \f1\f2n\f1\f7, counted \f1\f2m\f1 +The number of free data blocks recorded +in the superblock doesn't match the number counted free in the filesystem. +.TP +\f7sb_frextents \f1\f2n\f1\f7, counted \f1\f2m\f1 +The number of free real-time extents recorded +in the superblock doesn't match the number counted free in the filesystem. +.TP +\f7sb_icount \f1\f2n\f1\f7, counted \f1\f2m\f1 +The number of allocated inodes recorded +in the superblock doesn't match the number allocated in the filesystem. +.TP +\f7sb_ifree \f1\f2n\f1\f7, counted \f1\f2m\f1 +The number of free inodes recorded +in the superblock doesn't match the number free in the filesystem. +.SH SEE ALSO +mkfs.xfs(8), +xfsdump(8), +xfsrestore(8), +xfs_ncheck(8), +xfs_repair(8), +xfs(5). diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/xfs_db.8 linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_db.8 --- linux-2.4.7/cmd/xfsprogs/man/man8/xfs_db.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_db.8 Wed Jan 24 21:35:58 2001 @@ -0,0 +1,1187 @@ +.TH xfs_db 8 +.SH NAME +xfs_db \- debug an XFS filesystem +.SH SYNOPSIS +.nf +\f3xfs_db\f1 [ \f3\-c\f1 cmd ] ... [ \f3\-p\f1 prog ] [ \f3\-r\f1 ] [ \f3\-x\f1 ] xfs_special +.sp .8v +\f3xfs_db\f1 \f3\-f\f1 [ \f3\-c\f1 cmd ] ... [ \f3\-p\f1 prog ] [ \f3\-f\f1 ] [ \f3\-r\f1 ] [ \f3\-x\f1 ] file +.fi +.SH DESCRIPTION +\f2xfs_db\f1 is used to examine an XFS filesystem. +Under rare circumstances it can also be used to modify an XFS filesystem, +but that task is normally left to \f2xfs_repair\f1(8) or to +scripts such as \f2xfs_chver\f1 that run \f2xfs_db\f1. +.PP +The options to \f2xfs_db\f1 are: +.TP 10 +\f3\-c\f1 \f2cmd\f1 +\f2xfs_db\f1 commands may be run interactively (the default) +or as arguments on the command line. +Multiple \f3\-c\f1 arguments may be given. +The commands are run in the sequence given, then the program exits. +This is the mechanism used to implement \f2xfs_check\f1(8). +.TP +\f3\-f\f1 +Specifies that the filesystem image to be processed is stored in a +regular file +(see the \f2mkfs.xfs\f1 \f3\-d\f1 \f2file\f1 option). +This might happen if an image copy +of a filesystem has been made into an ordinary file with \f2xfs_copy\f1(8). +.TP +\f3\-i\f1 +Allows execution on a mounted filesystem, provided it is mounted read-only. +Useful for shell scripts such as \f2xfs_check\f1(8), which must only +operate on filesystems in a guarenteed consistent state +(either unmounted or mounted read-only). +These semantics are slightly different to that of the \f3\-r\f1 option. +.TP +\f3\-p\f1 \f2prog\f1 +Set the program name for prompts and some error messages, +the default value is \f2xfs_db\f1. +.TP +\f3\-r\f1 +Open \f2file\f1 or \f2xfs_special\f1 read-only. +This option is required if \f2xfs_special\f1 is a mounted filesystem. +It is only necessary to omit this flag if a command that changes data +(\f3write\f1, \f3blocktrash\f1) is to be used. +.TP +\f3\-x\f1 +Specifies expert mode. +This enables the \f3write\f1 command. +.SH CONCEPTS +\f2xfs_db\f1 commands can be broken up into two classes. +Most commands are for the navigation and display of data structures in +the filesystem. +Other commands are for scanning the filesystem in some way. +.PP +Commands which are used to navigate the filesystem structure take arguments +which reflect the names of filesystem structure fields. +There can be multiple field names separated by dots when the underlying +structures are nested, as in C. +The field names can be indexed (as an array index) +if the underlying field is an array. +The array indices can be specified as a range, two numbers separated by a dash. +.PP +\f2xfs_db\f1 maintains a current address in the filesystem. +The granularity of the address is a filesystem structure. +This can be a filesystem block, +an inode or quota (smaller than a filesystem block), +or a directory block (could be larger than a filesystem block). +There are a variety of commands to set the current address. +Associated with the current address is the current data type, +which is the structural type of this data. +Commands which follow the structure of the filesystem always set the type +as well as the address. +Commands which examine pieces of an individual file (inode) need the current +inode to be set, this is done with the \f3inode\f1 command. +.PP +The current address/type information is actually maintained in a +stack that can be explicitly manipulated with the +\f3push\f1, \f3pop\f1, and \f3stack\f1 commands. +This allows for easy examination of a nested filesystem structure. +Also, the last several locations visited are stored in a ring buffer +which can be manipulated with the +\f3forward\f1, \f3back\f3, and \f3ring\f1 commands. +.PP +XFS filesystems are divided into a small number of allocation groups. +\f2xfs_db\f1 maintains a notion of the current allocation group which is +manipulated by some commands. +The initial allocation group is 0. +.SH COMMANDS +.PP +Many commands have extensive online help. +Use the \f3help\f1 command for more details on any command. +.TP 10 +\f3a\f1 +See the \f3addr\f1 command. +.TP +\f3ablock\f1 \f2filoff\f1 +Set current address to the offset \f2filoff\f1 (a filesystem block number) +in the attribute area of the current inode. +.TP +\f3addr\f1 [ \f2field-expression\f1 ] +Set current address to the value of the \f2field-expression\f1. +This is used to ``follow'' a reference in one structure to the object +being referred to. +If no argument is given the current address is printed. +.TP +\f3agf\f1 [ \f2agno\f1 ] +Set current address to the AGF block for allocation group \f2agno\f1. +If no argument is given use the current allocation group. +.TP +\f3agfl\f1 [ \f2agno\f1 ] +Set current address to the AGFL block for allocation group \f2agno\f1. +If no argument is given use the current allocation group. +.TP +\f3agi\f1 [ \f2agno\f1 ] +Set current address to the AGI block for allocation group \f2agno\f1. +If no argument is given use the current allocation group. +.TP +\f3b\f1 +See the \f3back\f1 command. +.TP +\f3back\f1 +Move to the previous location in the position ring. +.TP +\f3blockfree\f1 +Free block usage information collected by the last execution of the +\f3blockget\f1 command. +This must be done before another \f3blockget\f1 command can be given, +presumably with different arguments than the previous one. +.TP +\f3blockget\f1 [ \f3\-npsv\f1 ] [ \f3\-b\f1 \f2bno\f1 ] ... [ \f3\-i\f1 \f2ino\f1 ] ... +Get block usage and check filesystem consistency. +The information is saved for use by a subsequent +\f3blockuse\f1, \f3ncheck\f1, or \f3blocktrash\f1 command. +See \f2xfs_check\f1(8) for more information. +.br +The \f3\-b\f1 option is used to specify filesystem block numbers +about which verbose information should be printed. +.br +The \f3\-i\f1 option is used to specify inode numbers about which +verbose information should be printed. +.br +The \f3\-n\f1 option is used to save pathnames for inodes visited, +this is used to support the \f2xfs_ncheck\f1(8) command. +It also means that pathnames will be printed for inodes that have problems. +This option uses a lot of memory so is not enabled by default. +.br +The \f3\-p\f1 option causes error messages to be prefixed with the +filesystem name being processed. +This is useful if several copies of \f2xfs_db\f1 are run in parallel. +.br +The \f3\-s\f1 option restricts output to severe errors only. +This is useful if the output is too long otherwise. +.br +The \f3\-v\f1 option enables verbose output. +Messages will be printed for every block and inode processed. +.TP +\f3blocktrash\f1 [ \f3\-n\f1 \f2c\f1 ] [ \f3\-x\f1 \f2a\f1 ] [ \f3\-y\f1 \f2b\f1 ] [ \f3\-s\f1 \f2s\f1 ] [ \f3\-0123\f1 ] [ \f3\-t\f1 \f2t\f1 ] ... +Trash randomly selected filesystem metadata blocks. +Trashing occurs to randomly selected bits in the chosen blocks. +This command is available only in debugging versions of \f2xfs_db\f1. +It is useful for testing \f2xfs_repair\f1(8) and \f2xfs_check\f1(8). +.br +The \f3\-0\f1, \f3\-1\f1, \f3\-2\f1, and \f3\-3\f1 options (mutually exclusive) +set the operating mode for \f3blocktrash\f1. +In \f3\-0\f1 mode, changed bits are cleared. +In \f3\-1\f1 mode, changed bits are set. +In \f3\-2\f1 mode, changed bits are inverted. +In \f3\-3\f1 mode, changed bits are randomized. +.br +The \f3\-n\f1 option supplies the count of block-trashings to perform +(default 1). +.br +The \f3\-s\f1 option supplies a seed to the random processing. +.br +The \f3\-t\f1 option gives a type of blocks to be selected +for trashing. +Multiple \f3\-t\f1 options may be given. +If no \f3\-t\f1 options are given then all metadata types can be trashed. +.br +The \f3\-x\f1 option sets the minimum size of bit range to be trashed. +The default value is 1. +.br +The \f3\-y\f1 option sets the maximum size of bit range to be trashed. +The default value is 1024. +.TP +\f3blockuse\f1 [ \f3\-n\f1 ] [ \f3\-c\f1 \f2blockcount\f1 ] +Print usage for current filesystem block(s). +For each block, the type and (if any) inode are printed. +.br +The \f3\-c\f1 option specifies a count of blocks to process. +The default value is 1 (the current block only). +.br +The \f3\-n\f1 option specifies that file names should be printed. +The prior \f3blockget\f1 command must have also specified the \f3\-n\f1 option. +.TP +\f3bmap\f1 [ \f3\-a\f1 ] [ \f3\-d\f1 ] [ \f2block\f1 [ \f2len\f1 ] ] +Show the block map for the current inode. +The map display can be restricted to an area of the file with the +\f2block\f1 and \f2len\f1 arguments. +If \f2block\f1 is given and \f2len\f1 is omitted then 1 is assumed for len. +.br +The \f3\-a\f1 and \f3\-d\f1 options are used to select the attribute or data +area of the inode, if neither option is given then both areas are shown. +.TP +\f3check\f1 +See the \f3blockget\f1 command. +.TP +\f3convert\f1 \f2type\f1 \f2number\f1 [ \f2type\f1 \f2number\f1 ] ... \f2type\f1 +Convert from one address form to another. +The known \f2type\f1s, with alternate names, are: +\f3agblock\f1 or \f3agbno\f1 (filesystem block within an allocation group), +\f3agino\f1 or \f3aginode\f1 (inode number within an allocation group), +\f3agnumber\f1 or \f3agno\f1 (allocation group number), +\f3bboff\f1 or \f3daddroff\f1 (byte offset in a \f3daddr\f1), +\f3blkoff\f1 or \f3fsboff\f1 or \f3agboff\f1 (byte offset in a \f3agblock\f1 +or \f3fsblock\f1), +\f3byte\f1 or \f3fsbyte\f1 (byte address in filesystem), +\f3daddr\f1 or \f3bb\f1 (disk address, 512-byte blocks), +\f3fsblock\f1 or \f3fsb\f1 or \f3fsbno\f1 (filesystem block, see the +\f3fsblock\f1 command), +\f3ino\f1 or \f3inode\f1 (inode number), +\f3inoidx\f1 or \f3offset\f1 (index of inode in filesystem block), +and \f3inooff\f1 or \f3inodeoff\f1 (byte offset in inode). +Only conversions that ``make sense'' are allowed. +The compound form (with more than three arguments) is useful for +conversions such as +\f3convert\f1 \f3agno\f1 \f2ag\f1 \f3agbno\f1 \f2agb\f1 \f3fsblock\f1. +.TP +\f3daddr\f1 [ \f2d\f1 ] +Set current address to the daddr (512 byte block) given by \f2d\f1. +If no value for \f2d\f1 is given the current address is printed, +expressed as a daddr. +The type is set to \f3data\f1 (uninterpreted). +.TP +\f3dblock\f1 \f2filoff\f1 +Set current address to the offset \f2filoff\f1 (a filesystem block number) +in the data area of the current inode. +.TP +\f3debug\f1 [ \f2flagbits\f1 ] +Set debug option bits. +These are used for debugging \f2xfs_db\f1. +If no value is given for \f2flagbits\f1, print the current debug option bits. +These are for the use of the implementor. +.TP +\f3dquot\f1 [ \f2projectid_or_userid\f1 ] +Set current address to a project or user quota block. +.TP +\f3echo\f1 [ \f2arg\f1 ] ... +Echo the arguments to the output. +.TP +\f3f\f1 +See the \f3forward\f1 command. +.TP +\f3forward\f1 +Move forward to the next entry in the position ring. +.TP +\f3frag\f1 [ \f3\-adflqRrv\f1 ] +Get file fragmentation data. +This prints information about fragmentation of file data in the filesystem +(as opposed to fragmentation of freespace, +for which see the \f3freesp\f1 command). +Every file in the filesystem is examined to see how far from ideal +its extent mappings are. +A summary is printed giving the totals. +.br +The \f3\-v\f1 option sets verbosity, +every inode has information printed for it. +The remaining options select which inodes and extents are examined. +If no options are given then all are assumed set, +otherwise just those given are enabled. +.br +The \f3\-a\f1 option enables processing of attribute data. +.br +The \f3\-d\f1 option enables processing of directory data. +.br +The \f3\-f\f1 option enables processing of regular file data. +.br +The \f3\-l\f1 option enables processing of symbolic link data. +.br +The \f3\-q\f1 option enables processing of quota file data. +.br +The \f3\-R\f1 option enables processing of realtime control file data. +.br +The \f3\-r\f1 option enables processing of realtime file data. +.TP +\f3freesp\f1 [ \f3\-bcds\f1 ] [ \f3\-a\f1 \f2a\f1 ] ... [ \f3\-e\f1 \f2i\f1 ] [ \f3\-h\f1 \f2h1\f1 ] ... [ \f3\-m\f1 \f2m\f1 ] +Summarize free space for the filesystem. +The free blocks are examined and totalled, +and displayed in the form of a histogram, +with a count of extents in each range of free extent sizes. +.br +The \f3\-a\f1 \f2a\f1 option adds \f2a\f1 to the list of +allocation groups to be processed. +If no \f3\-a\f1 options are given then all allocation groups are processed. +.br +The \f3\-b\f1 option specifies that the histogram buckets are binary-sized, +with the starting sizes being the powers of 2. +.br +The \f3\-c\f1 option specifies that \f3freesp\f1 will search the +by-size (cnt) space Btree instead of the default by-block (bno) space Btree. +.br +The \f3\-d\f1 option specifies that every free extent will be displayed. +.br +The \f3\-e\f1 \f2i\f1 option specifies that the histogram buckets are +equal-sized, with the size specified as \f2i\f1. +.br +The \f3\-h\f1 \f2h1\f1 option specifies a starting block number +for a histogram bucket as \f2h1\f1. +Multiple \f3\-h\f1 options are given to specify the complete set of buckets. +.br +The \f3\-m\f1 \f2m\f1 option specifies that the histogram +starting block numbers are powers of \f2m\f1. +This is the general case of \f3\-b\f1. +.br +The \f3\-s\f1 option specifies that a final summary of total free extents, +free blocks, and the average free extent size is printed. +.TP +\f3fsb\f1 +See the \f3fsblock\f1 command. +.TP +\f3fsblock\f1 [ \f2fsb\f1 ] +Set current address to the fsblock value given by \f2fsb\f1. +If no value for \f2fsb\f1 is given the current address is printed, +expressed as an fsb. +The type is set to \f3data\f1 (uninterpreted). +XFS filesystem block numbers are computed +((\f2agno\f1 << \f2agshift\f1) | \f2agblock\f1) +where \f2agshift\f1 depends on the size of an allocation group. +Use the \f3convert\f1 command to convert to and from this form. +Block numbers given for file blocks +(for instance from the \f3bmap\f1 command) +are in this form. +.TP +\f3hash\f1 \f2string\f1 +Prints the hash value of \f2string\f1 using the hash function of the XFS +directory and attribute implementation. +.TP +\f3help\f1 [ \f2command\f1 ] +Print help for one or all commands. +.TP +\f3inode\f1 [ \f2inode#\f1 ] +Set the current inode number. +If no \f2inode#\f1 is given, print the current inode number. +.TP +\f3log\f1 [ \f3stop\f1 | \f3start\f1 \f2filename\f1 ] +Start logging output to \f2filename\f1, stop logging, +or print the current logging status. +.TP +\f3ncheck\f1 [ \f3\-s\f1 ] [ \f3\-i\f1 \f2ino\f1 ] ... +Print name-inode pairs. +A \f3blockget -n\f1 command must be run first to gather the information. +.br +The \f3\-i\f1 option specifies an inode number to be printed. +If no \f3\-i\f1 options are given then all inodes are printed. +.br +The \f3\-s\f1 option specifies that only setuid and setgid files are printed. +.TP +\f3p\f1 +See the \f3print\f1 command. +.TP +\f3pop\f1 +Pop location from the stack. +.TP +\f3print\f1 [ \f2field-expression\f1 ] ... +Print field values. +If no argument is given, print all fields in the current structure. +.TP +\f3push\f1 [ \f2command\f1 ] +Push location to the stack. +If \f2command\f1 is supplied, +set the current location to the results of \f2command\f1 +after pushing the old location. +.TP +\f3q\f1 +See the \f3quit\f1 command. +.TP +\f3quit\f1 +Exit \f2xfs_db\f1. +.TP +\f3ring\f1 [ \f2index\f1 ] +Show position ring (if no \f2index\f1 argument is given), +or move to a specific entry in the position ring given by \f2index\f1. +.TP +\f3sb\f1 [ \f2agno\f1 ] +Set current address to SB header in allocation group \f2agno\f1. +If no \f2agno\f1 is given use the current allocation group number. +.TP +\f3source\f1 \f2source-file\f1 +Process commands from \f2source-file\f1. +\f3source\f1 commands can be nested. +.TP +\f3stack\f1 +View the location stack. +.TP +\f3type\f1 [ \f2type\f1 ] +Set the current data type to \f2type\f1. +If no argument is given, show the current data type. +The possible data types are: +\f3agf\f1, \f3agfl\f1, \f3agi\f1, \f3attr\f1, \f3bmapbta\f1, \f3bmapbtd\f1, +\f3bnobt\f1, \f3cntbt\f1, \f3data\f1, \f3dir\f1, \f3dir2\f1, \f3dqblk\f1, +\f3inobt\f1, \f3inode\f1, \f3log\f1, \f3rtbitmap\f1, \f3rtsummary\f1, +\f3sb\f1, and \f3symlink\f1. +See the TYPES section below for more information on these data types. +.TP +\f3write\f1 [ \f2field or value\f1 ] ... +Write a value to disk. +Specific fields can be set in structures (struct mode), +or a block can be set to data values (data mode), +or a block can be set to string values (string mode, for symlink blocks). +The operation happens immediately: there is no buffering. +.br +Struct mode is in effect when the current type is structural, +i.e. not data. +For struct mode, the syntax is ``\f3write\f1 \f2field\f1 \f2value\f1''. +.br +Data mode is in effect when the current type is data. +In this case the contents of the block can be shifted or rotated left or right, +or filled with a sequence, a constant value, or a random value. +In this mode \f3write\f1 with no arguments gives more information on +the allowed commands. +.SH TYPES +This section gives the fields in each structure type and their meanings. +Note that some types of block cover multiple actual structures, +for instance directory blocks. +.TP 10 +\f3agf\f1 +The AGF block is the header for block allocation information; +it is in the second 512-byte block of each allocation group. +The following fields are defined: +.br +\f3magicnum\f1: AGF block magic number, 0x58414746 ('XAGF') +.br +\f3versionnum\f1: version number, currently 1 +.br +\f3seqno\f1: sequence number starting from 0 +.br +\f3length\f1: size in filesystem blocks of the allocation group. +All allocation groups except the last one of the filesystem have +the superblock's \f3agblocks\f1 value here +.br +\f3bnoroot\f1: block number of the root of the Btree holding free space +information sorted by block number +.br +\f3cntroot\f1: block number of the root of the Btree holding free space +information sorted by block count +.br +\f3bnolevel\f1: number of levels in the by-block-number Btree +.br +\f3cntlevel\f1: number of levels in the by-block-count Btree +.br +\f3flfirst\f1: index into the AGFL block of the first active entry +.br +\f3fllast\f1: index into the AGFL block of the last active entry +.br +\f3flcount\f1: count of active entries in the AGFL block +.br +\f3freeblks\f1: count of blocks represented in the freespace Btrees +.br +\f3longest\f1: longest free space represented in the freespace Btrees +.TP +\f3agfl\f1 +The AGFL block contains block numbers for use of the block allocator; +it is in the fourth 512-byte block of each allocation group. +Each entry in the active list is a block number within the allocation group +that can be used for any purpose if space runs low. +The AGF block fields \f3flfirst\f1, \f3fllast\f1, and \f3flcount\f1 +designate which entries are currently active. +Entry space is allocated in a circular manner within the AGFL block. +Fields defined: +.br +\f3bno\f1: array of all block numbers. +Even those which are not active are printed +.TP +\f3agi\f1 +The AGI block is the header for inode allocation information; +it is in the third 512-byte block of each allocation group. +Fields defined: +.br +\f3magicnum\f1: AGI block magic number, 0x58414749 ('XAGI') +.br +\f3versionnum\f1: version number, currently 1 +.br +\f3seqno\f1: sequence number starting from 0 +.br +\f3length\f1: size in filesystem blocks of the allocation group +.br +\f3count\f1: count of inodes allocated +.br +\f3root\f1: block number of the root of the Btree holding inode allocation +information +.br +\f3level\f1: number of levels in the inode allocation Btree +.br +\f3freecount\f1: count of allocated inodes that are not in use +.br +\f3newino\f1: last inode number allocated +.br +\f3dirino\f1: unused +.br +\f3unlinked\f1: an array of inode numbers within the allocation group. +The entries in the AGI block are the heads of lists which run through the +inode \f3next_unlinked\f1 field. +These inodes are to be unlinked the next time the filesystem is mounted +.TP +\f3attr\f1 +An attribute fork is organized as a Btree with the actual data +embedded in the leaf blocks. +The root of the Btree is found in block 0 of the fork. +The index (sort order) of the Btree is the hash value of the attribute name. +All the blocks contain a \f3blkinfo\f1 structure at the beginning, +see type \f3dir\f1 for a description. +Nonleaf blocks are identical in format to those for version 1 and +version 2 directories, see type \f3dir\f1 for a description. +Leaf blocks can refer to ``local'' or ``remote'' attribute values. +Local values are stored directly in the leaf block. +Remote values are stored in an independent block in the attribute fork +(with no structure). +Leaf blocks contain the following fields: +.br +\f3hdr\f1: header containing +a \f3blkinfo\f1 structure \f3info\f1 (magic number 0xfbee), +a \f3count\f1 of active entries, +\f3usedbytes\f1 total bytes of names and values, +the \f3firstused\f1 byte in the name area, +\f3holes\f1 set if the block needs compaction, +and array \f3freemap\f1 as for \f3dir\f1 leaf blocks +.br +\f3entries\f1: array of structures containing +a \f3hashval\f1, +\f3nameidx\f1 (index into the block of the name), +and flags \f3incomplete\f1, +\f3root\f1, +and \f3local\f1 +.br +\f3nvlist\f1: array of structures describing the attribute names and values. +Fields always present: +\f3valuelen\f1 (length of value in bytes), +\f3namelen\f1, +and \f3name\f1. +Fields present for local values: +\f3value\f1 (value string). +Fields present for remote values: +\f3valueblk\f1 (fork block number of containing the value). +.TP +\f3bmapbt\f1 +Files with many extents in their data or attribute fork will have the +extents described by the contents of a Btree for that fork, +instead of being stored directly in the inode. +Each bmap Btree starts with a root block contained within the inode. +The other levels of the Btree are stored in filesystem blocks. +The blocks are linked to sibling left and right blocks at each level, +as well as by pointers from parent to child blocks. +Each block contains the following fields: +.br +\f3magic\f1: bmap Btree block magic number, 0x424d4150 ('BMAP') +.br +\f3level\f1: level of this block above the leaf level +.br +\f3numrecs\f1: number of records or keys in the block +.br +\f3leftsib\f1: left (logically lower) sibling block, 0 if none +.br +\f3rightsib\f1: right (logically higher) sibling block, 0 if none +.br +\f3recs\f1: [leaf blocks only] array of extent records. +Each record contains +\f3startoff\f1, +\f3startblock\f1, +\f3blockcount\f1, +and \f3extentflag\f1 (1 if the extent is unwritten) +.br +\f3keys\f1: [nonleaf blocks only] array of key records. +These are the first key value of each block in the level below this one. +Each record contains \f3startoff\f1 +.br +\f3ptrs\f1: [nonleaf blocks only] array of child block pointers. +Each pointer is a filesystem block number to the next level in the Btree +.TP +\f3bnobt\f1 +There is one set of filesystem blocks forming the by-block-number allocation +Btree for each allocation group. +The root block of this Btree is designated by the \f3bnoroot\f1 field in the +coresponding AGF block. +The blocks are linked to sibling left and right blocks at each level, +as well as by pointers from parent to child blocks. +Each block has the following fields: +.br +\f3magic\f1: BNOBT block magic number, 0x41425442 ('ABTB') +.br +\f3level\f1: level number of this block, 0 is a leaf +.br +\f3numrecs\f1: number of data entries in the block +.br +\f3leftsib\f1: left (logically lower) sibling block, 0 if none +.br +\f3rightsib\f1: right (logically higher) sibling block, 0 if none +.br +\f3recs\f1: [leaf blocks only] array of freespace records. +Each record contains +\f3startblock\f1 +and \f3blockcount\f1 +.br +\f3keys\f1: [nonleaf blocks only] array of key records. +These are the first value of each block in the level below this one. +Each record contains +\f3startblock\f1 +and \f3blockcount\f1 +.br +\f3ptrs\f1: [nonleaf blocks only] array of child block pointers. +Each pointer is a block number within the allocation group to the next level +in the Btree +.TP +\f3cntbt\f1 +There is one set of filesystem blocks forming the by-block-count allocation +Btree for each allocation group. +The root block of this Btree is designated by the \cntroot\f1 field in the +coresponding AGF block. +The blocks are linked to sibling left and right blocks at each level, +as well as by pointers from parent to child blocks. +Each block has the following fields: +.br +\f3magic\f1: CNTBT block magic number, 0x41425443 ('ABTC') +.br +\f3level\f1: level number of this block, 0 is a leaf +.br +\f3numrecs\f1: number of data entries in the block +.br +\f3leftsib\f1: left (logically lower) sibling block, 0 if none +.br +\f3rightsib\f1: right (logically higher) sibling block, 0 if none +.br +\f3recs\f1: [leaf blocks only] array of freespace records. +Each record contains +\f3startblock\f1 +and \f3blockcount\f1 +.br +\f3keys\f1: [nonleaf blocks only] array of key records. +These are the first value of each block in the level below this one. +Each record contains +\f3blockcount\f1 +and \f3startblock\f1 +.br +\f3ptrs\f1: [nonleaf blocks only] array of child block pointers. +Each pointer is a block number within the allocation group to the next level +in the Btree +.TP +\f3data\f1 +User file blocks, and other blocks whose type is unknown, +have this type for display purposes in \f2xfs_db\f1. +The block data is displayed in hexadecimal format. +.TP +\f3dir\f1 +A version 1 directory is organized as a Btree with the directory data +embedded in the leaf blocks. +The root of the Btree is found in block 0 of the file. +The index (sort order) of the Btree is the hash value of the entry name. +All the blocks contain a \f3blkinfo\f1 structure at the beginning +with the following fields: +.br +\f3forw\f1: next sibling block +.br +\f3back\f1: previous sibling block +.br +\f3magic\f1: magic number for this block type +.sp +The nonleaf (node) blocks have the following fields: +.br +\f3hdr\f1: header containing +a \f3blkinfo\f1 structure \f3info\f1 (magic number 0xfebe), +the \f3count\f1 of active entries, +and the \f3level\f1 of this block above the leaves +.br +\f3btree\f1: array of entries containing +\f3hashval\f1 and +\f3before\f1 fields. +The \f3before\f1 value is a block number within the directory file to the +child block, +the \f3hashval\f1 is the last hash value in that block +.sp +The leaf blocks have the following fields: +.br +\f3hdr\f1: header containing +a \f3blkinfo\f1 structure \f3info\f1 (magic number 0xfeeb), +the \f3count\f1 of active entries, +\f3namebytes\f1 (total name string bytes), +\f3holes\f1 flag (block needs compaction), +and \f3freemap\f1 (array of \f3base\f1, \f3size\f1 entries for free regions) +.br +\f3entries\f1: array of structures containing +\f3hashval\f1, +\f3nameidx\f1 (byte index into the block of the name string), +and \f3namelen\f1 +.br +\f3namelist\f1: array of structures containing +\f3inumber\f1 +and \f3name\f1 +.TP +\f3dir2\f1 +A version 2 directory has four kinds of blocks. +Data blocks start at offset 0 in the file. +There are two kinds of data blocks: single-block directories have +the leaf information embedded at the end of the block, data blocks +in multi-block directories do not. +Node and leaf blocks start at offset 32GB (with either a single +leaf block or the root node block). +Freespace blocks start at offset 64GB. +The node and leaf blocks form a Btree, with references to the data +in the data blocks. +The freespace blocks form an index of longest free spaces within the +data blocks. +.sp +A single-block directory block contains the following fields: +.br +\f3bhdr\f1: header containing +\f3magic\f1 number 0x58443242 ('XD2B') +and an array \f3bestfree\f1 of the longest 3 free spaces in the block +(\f3offset\f1, \f3length\f1) +.br +\f3bu\f1: array of union structures. +Each element is either an entry or a freespace. +For entries, there are the following fields: +\f3inumber\f1, +\f3namelen\f1, +\f3name\f1, +and \f3tag\f1. +For freespace, there are the following fields: +\f3freetag\f1 (0xffff), +\f3length\f1, +and \f3tag\f1. +The \f3tag\f1 value is the byte offset in the block of the start +of the entry it is contained in +.br +\f3bleaf\f1: array of leaf entries containing +\f3hashval\f1 +and \f3address\f1. +The \f3address\f1 is a 64-bit word offset into the file +.br +\f3btail\f1: tail structure containing +the total \f3count\f1 of leaf entries +and \f3stale\f1 count of unused leaf entries +.sp +A data block contains the following fields: +.br +\f3dhdr\f1: +header containing +\f3magic\f1 number 0x58443244 ('XD2D') +and an array \f3bestfree\f1 of the longest 3 free spaces in the block +(\f3offset\f1, \f3length\f1) +.br +\f3du\f1: array of union structures as for \f3bu\f1 +.sp +Leaf blocks have two possible forms. +If the Btree consists of a single leaf then the freespace information +is in the leaf block, +otherwise it is in separate blocks and the root of the Btree is +a node block. +A leaf block contains the following fields: +.br +\f3lhdr\f1: header containing +a \f3blkinfo\f1 structure \f3info\f1 (magic number 0xd2f1 for the single +leaf case, 0xd2ff for the true Btree case), +the total \f3count\f1 of leaf entries, +and \f3stale\f1 count of unused leaf entries +.br +\f3lents\f1: leaf entries, as for \f3bleaf\f1 +.br +\f3lbests\f1: [single leaf only] +array of values which represent the longest freespace +in each data block in the directory +.br +\f3ltail\f1: [single leaf only] tail structure containing +\f3bestcount\f1 count of \f3lbests\f1 +.sp +A node block is identical to that for types \f3attr\f1 and \f3dir\f1. +.sp +A freespace block contains the following fields: +.br +\f3fhdr\f1: header containing +\f3magic\f1 number 0x58443246 ('XD2F'), +\f3firstdb\f1 first data block number covered by this freespace block, +\f3nvalid\f1 number of valid entries, +and \f3nused\f1 number of entries representing real data blocks +.br +\f3fbests\f1: array of values as for \f3lbests\f1 +.TP +\f3dqblk\f1 +The quota information is stored in files referred to by the superblock +\f3uquotino\f1 and \f3pquotino\f1 fields. +Each filesystem block in a quota file contains a constant number of +quota entries. +The quota entry size is currently 136 bytes, +so with a 4KB filesystem block size there are 30 quota entries per block. +The \f3dquot\f1 command is used to locate these entries in the filesystem. +The file entries are indexed by the user or project identifier +to determine the block and offset. +Each quota entry has the following fields: +.br +\f3magic\f1: magic number, 0x4451 ('DQ') +.br +\f3version\f1: version number, currently 1 +.br +\f3flags\f1: flags, values include +0x01 for user quota, +0x02 for project quota +.br +\f3id\f1: user or project identifier +.br +\f3blk_hardlimit\f1: absolute limit on blocks in use +.br +\f3blk_softlimit\f1: preferred limit on blocks in use +.br +\f3ino_hardlimit\f1: absolute limit on inodes in use +.br +\f3ino_softlimit\f1: preferred limit on inodes in use +.br +\f3bcount\f1: blocks actually in use +.br +\f3icount\f1: inodes actually in use +.br +\f3itimer\f1: time when service will be refused if soft limit is violated +for inodes +.br +\f3btimer\f1: time when service will be refused if soft limit is violated +for blocks +.br +\f3iwarns\f1: number of warnings issued about inode limit violations +.br +\f3bwarns\f1: number of warnings issued about block limit violations +.br +\f3rtb_hardlimit\f1: absolute limit on realtime blocks in use +.br +\f3rtb_softlimit\f1: preferred limit on realtime blocks in use +.br +\f3rtbcount\f1: realtime blocks actually in use +.br +\f3rtbtimer\f1: time when service will be refused if soft limit is violated +for realtime blocks +.br +\f3rtbwarns\f1: number of warnings issued about realtime block limit violations +.TP +\f3inobt\f1 +There is one set of filesystem blocks forming the inode allocation +Btree for each allocation group. +The root block of this Btree is designated by the \f3root\f1 field in the +coresponding AGI block. +The blocks are linked to sibling left and right blocks at each level, +as well as by pointers from parent to child blocks. +Each block has the following fields: +.br +\f3magic\f1: INOBT block magic number, 0x49414254 ('IABT') +.br +\f3level\f1: level number of this block, 0 is a leaf +.br +\f3numrecs\f1: number of data entries in the block +.br +\f3leftsib\f1: left (logically lower) sibling block, 0 if none +.br +\f3rightsib\f1: right (logically higher) sibling block, 0 if none +.br +\f3recs\f1: [leaf blocks only] array of inode records. +Each record contains +\f3startino\f1 allocation-group relative inode number, +\f3freecount\f1 count of free inodes in this chunk, +and \f3free\f1 bitmap, LSB corresponds to inode 0 +.br +\f3keys\f1: [nonleaf blocks only] array of key records. +These are the first value of each block in the level below this one. +Each record contains +\f3startino\f1 +.br +\f3ptrs\f1: [nonleaf blocks only] array of child block pointers. +Each pointer is a block number within the allocation group to the next level +in the Btree +.TP +\f3inode\f1 +Inodes are allocated in ``chunks'' of 64 inodes each. +Usually a chunk is multiple filesystem blocks, although there are cases +with large filesystem blocks where a chunk is less than one block. +The inode Btree (see \f3inobt\f1 above) +refers to the inode numbers per allocation group. +The inode numbers directly reflect the location of the inode block on disk. +Use the \f3inode\f1 command to point \f2xfs_db\f1 to a specific inode. +Each inode contains four regions: +\f3core\f1, +\f3next_unlinked\f1, +\f3u\f1, +and \f3a\f1. +\f3core\f1 contains the fixed information. +\f3next_unlinked\f1 is separated from the core due to +journaling considerations, see type \f3agi\f1 field \f3unlinked\f1. +\f3u\f1 is a union structure that is different in size and format depending +on the type and representation of the file data (``data fork''). +\f3a\f1 is an optional union structure to describe attribute data, +that is different in size, format, and location depending on the presence +and representation of attribute data, and the size of the \f3u\f1 data +(``attribute fork''). +\f2xfs_db\f1 automatically selects the proper union members based on +information in the inode. +.br +The following are fields in the inode core: +.br +\f3magic\f1: inode magic number, 0x494e ('IN') +.br +\f3mode\f1: mode and type of file, as described in \f3chmod\f1(2), +\f3mknod\f1(2), and \f3stat\f1(2) +.br +\f3version\f1: inode version, 1 or 2 +.br +\f3format\f1: format of \f3u\f1 union data +(0: dev_t, +1: local file \- in-inode directory or symlink, +2: extent list, +3: Btree root, +4: unique id [unused]) +.br +\f3nlinkv1\f1: number of links to the file in a version 1 inode +.br +\f3nlinkv2\f1: number of links to the file in a version 2 inode +.br +\f3projid\f1: owner's project id (version 2 inode only) +.br +\f3uid\f1: owner's user id +.br +\f3gid\f1: owner's group id +.br +\f3atime\f1: time last accessed (seconds and nanoseconds) +.br +\f3mtime\f1: time last modified +.br +\f3ctime\f1: time created or inode last modified +.br +\f3size\f1: number of bytes in the file +.br +\f3nblocks\f1: total number of blocks in the file including +indirect and attribute +.br +\f3extsize\f1: basic/minimum extent size for the file, used only for realtime +.br +\f3nextents\f1: number of extents in the data fork +.br +\f3naextents\f1: number of extents in the attribute fork +.br +\f3forkoff\f1: attribute fork offset in the inode, +in 64-bit words from the start of \f3u\f1 +.br +\f3aformat\f1: format of \f3a\f1 data +(1: local attribute data, +2: extent list, +3: Btree root) +.br +\f3dmevmask\f1: DMAPI event mask +.br +\f3dmstate\f1: DMAPI state information +.br +\f3newrtbm\f1: file is the realtime bitmap and is ``new'' format +.br +\f3prealloc\f1: file has preallocated data space after EOF +.br +\f3realtime\f1: file data is in the realtime subvolume +.br +\f3gen\f1: inode generation number +.sp +The following fields are in the \f3u\f1 data fork union: +.br +\f3bmbt\f1: bmap Btree root. +This looks like a \f3bmapbtd\f1 block with redundant information removed +.br +\f3bmx\f1: array of extent descriptors +.br +\f3dev\f1: dev_t for the block or character device +.br +\f3sfdir\f1: shortform (in-inode) version 1 directory. +This consists of +a \f3hdr\f1 containing +the \f3parent\f1 inode number +and a \f3count\f1 of active entries in the directory, +followed by +an array \f3list\f1 of \f3hdr\f1.\f3count\f1 entries. +Each such entry contains +\f3inumber\f1, +\f3namelen\f1, +and \f3name\f1 string +.br +\f3sfdir2\f1: shortform (in-inode) version 2 directory. +This consists of +a \f3hdr\f1 containing +a \f3count\f1 of active entries in the directory, +an \f3i8count\f1 of entries with inumbers that don't fit in a 32-bit value, +and the \f3parent\f1 inode number, +followed by +an array \f3list\f1 of \f3hdr\f1.\f3count\f1 entries. +Each such entry contains +\f3namelen\f1, +a saved \f3offset\f1 used when the directory is converted to a larger form, +a \f3name\f1 string, +and the \f3inumber\f1 +.br +\f3symlink\f1: symbolic link string value +.sp +The following fields are in the \f3a\f1 attribute fork union if it exists: +.br +\f3bmbt\f1: bmap Btree root, as above +.br +\f3bmx\f1: array of extent descriptors +.br +\f3sfattr\f1: shortform (in-inode) attribute values. +This consists of +a \f3hdr\f1 containing +a \f3totsize\f1 (total size in bytes) +and a \f3count\f1 of active entries, +followed by +an array \f3list\f1 of \f3hdr\f1.\f3count\f1 entries. +Each such entry contains +\f3namelen\f1, +\f3valuelen\f1, +\f3root\f1 flag, +\f3name\f1, +and \f3value\f1 +.TP +\f3log\f1 +Log blocks contain the journal entries for XFS. +It's not useful to examine these with \f2xfs_db\f1, +use \f2xfs_logprint\f1(8) instead. +.TP +\f3rtbitmap\f1 +If the filesystem has a realtime subvolume, then the \f3rbmino\f1 field +in the superblock refers to a file that contains the realtime bitmap. +Each bit in the bitmap file controls the allocation of a single realtime extent +(set == free). +The bitmap is processed in 32-bit words, +the LSB of a word is used for the first extent controlled by that bitmap word. +The \f3atime\f1 field of the realtime bitmap inode contains a counter +that is used to control where the next new realtime file will start. +.TP +\f3rtsummary\f1 +If the filesystem has a realtime subvolume, +then the \f3rsumino\f1 field in the superblock refers to a file +that contains the realtime summary data. +The summary file contains a two-dimensional array of 16-bit values. +Each value counts the number of free extent runs +(consecutive free realtime extents) +of a given range of sizes that starts in a given bitmap block. +The size ranges are binary buckets (low size in the bucket is a power of 2). +There are as many size ranges as are necessary given the size of the +realtime subvolume. +The first dimension is the size range, +the second dimension is the starting bitmap block number +(adjacent entries are for the same size, adjacent bitmap blocks). +.TP +\f3sb\f1 +There is one sb (superblock) structure per allocation group. +It is the first disk block in the allocation group. +Only the first one (block 0 of the filesystem) is actually used; +the other blocks are redundant information for \f2xfs_repair\f1(8) +to use if the first superblock is damaged. +Fields defined: +.br +\f3magicnum\f1: superblock magic number, 0x58465342 ('XFSB') +.br +\f3blocksize\f1: filesystem block size in bytes +.br +\f3dblocks\f1: number of filesystem blocks present in the data subvolume +.br +\f3rblocks\f1: number of filesystem blocks present in the realtime subvolume +.br +\f3rextents\f1: number of realtime extents that \f3rblocks\f1 contain +.br +\f3uuid\f1: unique identifier of the filesystem +.br +\f3logstart\f1: starting filesystem block number of the log (journal). +If this value is 0 the log is ``external'' +.br +\f3rootino\f1: root inode number +.br +\f3rbmino\f1: realtime bitmap inode number +.br +\f3rsumino\f1: realtime summary data inode number +.br +\f3rextsize\f1: realtime extent size in filesystem blocks +.br +\f3agblocks\f1: size of an allocation group in filesystem blocks +.br +\f3agcount\f1: number of allocation groups +.br +\f3rbmblocks\f1: number of realtime bitmap blocks +.br +\f3logblocks\f1: number of log blocks (filesystem blocks) +.br +\f3versionnum\f1: filesystem version information. +This value is currently 1, 2, 3, or 4 in the low 4 bits. +If the low bits are 4 then the other bits have additional meanings. +1 is the original value. +2 means that attributes were used. +3 means that version 2 inodes (large link counts) were used. +4 is the bitmask version of the version number. +In this case, the other bits are used as flags +(0x0010: attributes were used, +0x0020: version 2 inodes were used, +0x0040: quotas were used, +0x0080: inode cluster alignment is in force, +0x0100: data stripe alignment is in force, +0x0200: the \f3shared_vn\f1 field is used, +0x1000: unwritten extent tracking is on, +0x2000: version 2 directories are in use) +.br +\f3sectsize\f1: sector size in bytes, currently always 512. +This is the size of the superblock and the other header blocks +.br +\f3inodesize\f1: inode size in bytes +.br +\f3inopblock\f1: number of inodes per filesystem block +.br +\f3fname\f1: obsolete, filesystem name +.br +\f3fpack\f1: obsolete, filesystem pack name +.br +\f3blocklog\f1: log2 of \f3blocksize\f1 +.br +\f3sectlog\f1: log2 of \f3sectsize\f1 +.br +\f3inodelog\f1: log2 of \f3inodesize\f1 +.br +\f3inopblog\f1: log2 of \f3inopblock\f1 +.br +\f3agblklog\f1: log2 of \f3agblocks\f1 (rounded up) +.br +\f3rextslog\f1: log2 of \f3rextents\f1 +.br +\f3inprogress\f1: \f2mkfs.xfs\f1(8) aborted before completing this filesystem +.br +\f3imax_pct\f1: maximum percentage of filesystem space used for inode blocks +.br +\f3icount\f1: number of allocated inodes +.br +\f3ifree\f1: number of allocated inodes that are not in use +.br +\f3fdblocks\f1: number of free data blocks +.br +\f3frextents\f1: number of free realtime extents +.br +\f3uquotino\f1: user quota inode number +.br +\f3pquotino\f1: project quota inode number; this is currently unused +.br +\f3qflags\f1: quota status flags +(0x01: user quota accounting is on, +0x02: user quota limits are enforced, +0x04: quotacheck has been run on user quotas, +0x08: project quota accounting is on, +0x10: project quota limits are enforced, +0x20: quotacheck has been run on project quotas) +.br +\f3flags\f1: random flags. +0x01: only read-only mounts are allowed +.br +\f3shared_vn\f1: shared version number (shared readonly filesystems) +.br +\f3inoalignmt\f1: inode chunk alignment in filesystem blocks +.br +\f3unit\f1: stripe or RAID unit +.br +\f3width\f1: stripe or RAID width +.br +\f3dirblklog\f1: log2 of directory block size (filesystem blocks) +.TP +\f3symlink\f1 +Symbolic link blocks are used only when the symbolic link value does +not fit inside the inode. +The block content is just the string value. +Bytes past the logical end of the symbolic link value have arbitrary values. +.SH DIAGNOSTICS +Many messages can come from the \f3check\f1 (\f3blockget\f1) command; +these are documented in \f2xfs_check\f1(8). +.SH SEE ALSO +mkfs.xfs(8), +xfs_check(8), +xfs_copy(8), +xfs_logprint(8), +xfs_ncheck(8), +xfs_repair(8), +chmod(2), +mknod(2), +stat(2), +xfs(5). diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/xfs_freeze.8 linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_freeze.8 --- linux-2.4.7/cmd/xfsprogs/man/man8/xfs_freeze.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_freeze.8 Tue May 22 20:08:46 2001 @@ -0,0 +1,46 @@ +.TH xfs_freeze 8 +.SH NAME +xfs_freeze \- suspend access to an XFS filesystem +.SH SYNOPSIS +.nf +\f3xfs_freeze\f1 [ \f3\-fu\f1 ] mount-point +.fi +.SH DESCRIPTION +.I xfs_freeze +suspends and resumes access to an XFS filesystem (see +.IR xfs (5)). +The +.I mount-point +argument is the pathname of the directory where the filesystem +is mounted. +The filesystem must be mounted to be frozen (see +.IR mount (8)). +.I xfs_freeze +is intended to be used with volume managers and hardware raid devices +which support the creation of snapshots, +.I xfs_freeze +will halt new access to the filesystem and create a stable image on disk +suitable for using as a snapshot. +.PP +Using the \f3\-f\f1 option, the filesystem is locked out from new +modifications, write system calls are halted on entry, other calls +which modify the filesystem are halted at the start of a transaction, +all ongoing transactions in the filesystem are allowed to complete. +.PP +All dirty data is written out to disk, the log is flushed to disk and +all dirty metadata is written out. The \f3\-u\f1 option is then used +to unfreeze the filesystem and allow operations to continue. +.PP +The options to +.I xfs_freeze +are: +.TP +\f3\-f\f1 +Specifies that the filesystem should be frozen. +.TP +.B \-u +Specifies that the filesystem should be unfrozen and new modifications +allowed. +.SH SEE ALSO +lvm(8), +mount(8). diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/xfs_growfs.8 linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_growfs.8 --- linux-2.4.7/cmd/xfsprogs/man/man8/xfs_growfs.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_growfs.8 Sun Jan 14 23:36:03 2001 @@ -0,0 +1,135 @@ +.TH xfs_growfs 8 +.SH NAME +xfs_growfs, xfs_info \- expand an XFS filesystem +.SH SYNOPSIS +.nf +\f3xfs_growfs\f1 [ \f3\-dilnrxV\f1 ] [ \f3\-D\f1 size ] [ \f3\-e\f1 rtextsize ] + [ \f3\-L\f1 size ] [ \f3\-m\f1 maxpct ] [ \f3-t\f1 mtab ] + [ \f3\-R\f1 size ] mount-point +\f3xfs_info\f1 [ \f3-t\f1 mtab ] mount-point +.fi +.SH DESCRIPTION +.I xfs_growfs +expands an existing XFS filesystem (see +.IR xfs (5)). +The +.I mount-point +argument is the pathname of the directory where the filesystem +is mounted. +The filesystem must be mounted to be grown (see +.IR mount (8)). +The existing contents of the filesystem are undisturbed, and the added space +becomes available for additional file storage. +.PP +.I xfs_info +is equivalent to invoking +.I xfs_growfs +with the +.B \-n +option (see discussion below). +.PP +The options to +.I xfs_growfs +are: +.TP +\f3\-d\f1, \f3\-D\f1 \f2size\f1 +Specifies that the data section of the filesystem should be grown. +If the +.B \-D +.I size +option is given, the data section is grown to that size, otherwise +the data section is grown to the largest size possible. +The size +is expressed in +filesystem blocks. +.TP +.B \-e +Allows the real-time extent size to be specified. +In +.IR mkfs.xfs (8) +this is specified with +.B \-r +.BI extsize= nnnn. +.TP +.B \-i +The new log is an internal log +(inside the data section). +.TP +\f3\-l\f1, \f3\-L\f1 \f2size\f1 +Specifies that the log section of the filesystem should be grown, +shrunk, or moved. +If the +.B \-L +.I size +option is given, the log section is changed to be that size, +if possible. +The size is expressed in +filesystem blocks. +The size of an internal log must be smaller than the size +of an allocation group (this value is printed at \f2mkfs\f1(8) time). +If neither +.B \-i +nor +.B \-x +is given with +.BR \-l , +the log continues to be internal or external as it was before. +.TP +.B \-m +Specify a new value for the maximum percentage +of space in the filesystem that can be allocated as inodes. +In +.I mkfs.xfs +this is specified with +.B -i +.BI maxpct= nn. +.TP +.B \-n +Specifies that no change to the filesystem is to be made. +The filesystem geometry is printed, and argument checking is performed, +but no growth occurs. +.TP +\f3\-r\f1, \f3\-R\f1 \f2size\f1 +Specifies that the real-time section of the filesystem should be grown. +If the +.B \-R +.I size +option is given, the real-time section is grown to that size, otherwise +the real-time section is grown to the largest size possible. +The size +is expressed in +filesystem blocks. +The filesystem does not need to have contained a real-time section before +the \f2xfs_growfs\f1 operation. +.TP +.B \-t +Specifies an alternate mount table file (default is +.IR /etc/mtab ). +This is used when working with filesystems mounted without writing to +.I /etc/mtab +file - refer to +.BR mount (8) +for further details. +.TP +.PP +.I xfs_growfs +is most often used in conjunction with +logical volumes +(see +.IR lvm (8) +). +However, it can also be used on a regular disk partition, for example if a +partition has been enlarged while retaining the same starting block. +.SH PRACTICAL USE +Filesystems normally occupy all of the space on the device where they +reside. +In order to grow a filesystem, it is necessary to provide added +space for it to occupy. +Therefore there must be at least one spare new +disk partition available. +Adding the space is done through the mechanism of +logical volumes. +.SH SEE ALSO +mkfs.xfs(8), +lvm(8), +mount(8). diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/xfs_logprint.8 linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_logprint.8 --- linux-2.4.7/cmd/xfsprogs/man/man8/xfs_logprint.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_logprint.8 Sun Jan 14 23:36:03 2001 @@ -0,0 +1,86 @@ +.TH xfs_logprint 8 +.SH NAME +xfs_logprint \- print the log of an XFS filesystem +.SH SYNOPSIS +.nf +\f3xfs_logprint\f1 [ options ] device-name +\f3xfs_logprint \-f\f1 [ options ] filename +.fi +.SH DESCRIPTION +.I xfs_logprint +prints the log of an XFS filesystem (see +.IR xfs (5)). +The +.I device-name +argument is the pathname of the partition or logical volume +containing the filesystem. +The contents of the filesystem remain undisturbed. +There are two major modes of operation in +.IR xfs_logprint . +.PP +One mode is better for filesystem operation debugging. +It is called the transactional view and is enabled through the \f3\-t\f1 +option. +The transactional view prints only the portion of the log that +pertains to recovery. +In other words, it prints out complete transactions between the tail +and the head. +This view tries to display each transaction without +regard to how they are split across log records. +.PP +The second mode starts printing out information from the beginning of the log. +Some error blocks might print out in the beginning because the last log +record usually overlaps the oldest log record. +A message is +printed when the physical end of the log is reached and when the +logical end of the log is reached. +A log record view is displayed +one record at a time. +Transactions that span log records may not be +decoded fully. +.PP +Common options are: +.TP +\f3\-b\f1 +Extract and print buffer information. +Only used in transactional view. +.TP +\f3\-D\f1 +Don't decode anything; +just print data. +.TP +\f3\-e\f1 +Exit when an error is found in the log. +Normally, +.I xfs_logprint +tries to continue and unwind from bad logs. +However, sometimes it just dies in bad ways. +Using this option prevents core dumps. +.TP +\f3\-f\f1 +The log is a file. +.TP +\f3\-i\f1 +Extract and print inode information. +Only used in transactional view. +.TP +\f3\-q\f1 +Extract and print quota information. +Only used in transactional view. +.TP +\f3\-n\f1 +Don't try and interpret log data; +just interpret log header information. +.TP +\f3\-o\f1 +Also print buffer data in hex. +Normally, buffer data is just decoded, so better information can be printed. +.TP +\f3\-s\f1 \f2start-block\f1 +Override any notion of where to start printing. +.TP +\f3\-t\f1 +Print out the transactional view. +.SH SEE ALSO +mkfs.xfs(8), +mount(8). diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/xfs_mkfile.8 linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_mkfile.8 --- linux-2.4.7/cmd/xfsprogs/man/man8/xfs_mkfile.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_mkfile.8 Sun Jan 14 23:36:03 2001 @@ -0,0 +1,27 @@ +.TH xfs_mkfile 8 +.SH NAME +xfs_mkfile \- create an XFS file +.SH SYNOPSIS +.nf +\f3xfs_mkfile\f1 [\f3\-v\f1] [\f3\-n\f1] \c +\f2size\f1[\f3k\f1|\f3b\f1|\f3m\f1|\f3g\f1] \f2filename\f1... +.fi +.SH DESCRIPTION +.I xfs_mkfile +creates one or more files. +The file is padded with zeroes by +default. +The default size is in bytes, but it can be +flagged as kilobytes, blocks, megabytes, or gigabytes with the \f3k\f1, +\f3b\f1, \f3m\f1, or \f3g\f1 suffixes, respectively. +.SH OPTIONS +.TP +\f3\-v\f1 +Verbose. +Report the names and sizes of created files. +.TP +\f3\-n\f1 +No bytes. +Create a holey file - that is, +do not write out any data, just +seek to end of file and write a block. diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/xfs_ncheck.8 linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_ncheck.8 --- linux-2.4.7/cmd/xfsprogs/man/man8/xfs_ncheck.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_ncheck.8 Sun Jan 14 23:36:03 2001 @@ -0,0 +1,53 @@ +.TH xfs_ncheck 8 +.SH NAME +xfs_ncheck \- generate pathnames from i-numbers for XFS +.SH SYNOPSIS +.nf +\f3xfs_ncheck\f1 [ \f3\-i\f1 ino ] ... \c +[ \f3\-s\f1 ] xfs_special +.sp .8v +\f3xfs_ncheck\f1 \f3\-f\f1 [ \f3\-i\f1 ino ] ... \c +[ \f3\-s\f1 ] file +.fi +.SH DESCRIPTION +.I xfs_ncheck +with no +.B \-i +arguments generates an inode number and pathname list of all +files on the given filesystem. +Names of directory files are followed by +.BR /. . +The output is not sorted in any particular order. +The filesystem to be examined is specified by the +.I xfs_special +argument, which should be the disk or volume device for the filesystem. +Filesystems stored in files can also be checked, using the \f3\-f\f1 flag. +.PP +The options to \f2xfs_ncheck\f1 are: +.TP 9 +.B \-f +Specifies that the special device is actually a file (see the +\f2mkfs.xfs\f1 \f3\-d\f1 \f2file\f1 option). +This might happen if an image copy +of a filesystem has been made into an ordinary file. +.TP +.B \-s +Limits the report to special files and files with setuserid mode. +This option may be used to detect violations of security policy. +.TP +.BI \-i " ino" +Limits the report to only those files whose inode numbers follow. +May be given multiple times to select multiple inode numbers. +.PP +If the filesystem is seriously corrupted, or very busy and looks +like it is corrupt, a message of the form that would be generated by +.IR xfs_check (8) +may appear. +.PP +.I xfs_ncheck +is only useful with XFS filesystems. +.SH SEE ALSO +mkfs.xfs(8), +xfs_ncheck(8), +xfs_check(8), +xfs(5). diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/xfs_repair.8 linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_repair.8 --- linux-2.4.7/cmd/xfsprogs/man/man8/xfs_repair.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_repair.8 Sun Jan 14 23:36:03 2001 @@ -0,0 +1,353 @@ +.TH xfs_repair 8 +.SH NAME +xfs_repair \- repair an XFS filesystem +.SH SYNOPSIS +.nf +\f3xfs_repair\f1 [ \f3\-n\f1 ] [ \f3\-o\f1 subopt[=value] ] xfs_special +.sp .8v +\f3xfs_repair\f1 \f3\-f\f1 [ \f3\-n\f1 ] [ \f3\-o\f1 subopt[=value] ] ... file +.fi +.SH DESCRIPTION +.I xfs_repair +repairs corrupt or damaged XFS filesystems +(see +.IR xfs (5)). +The filesystem is specified using the +.I xfs_special +argument which should be the device name of the +disk partition or volume containing +the filesystem. +If given the name of a block device, +.I xfs_repair +will attempt to find the raw device associated +with the specified block device and will use the raw device +instead. +.PP +Regardless, the filesystem to be repaired +must be unmounted, +otherwise, the resulting filesystem may be inconsistent or corrupt. +.PP +The options to \f2xfs_repair\f1 are: +.TP +.B \-f +Specifies that the special device is actually a file (see the +\f2mkfs.xfs\f1 \f3\-d\f1 \f2file\f1 option). +This might happen if an image copy +of a filesystem has been copied or written into an ordinary file. +.TP +.B \-n +No modify mode. +Specifies that +.I xfs_repair +should not modify the filesystem but should only scan the +filesystem and indicate what repairs would have been made. +.TP +.B \-o +Override what the program might conclude about the filesystem +if left to its own devices. +.IP +The +.B assume_xfs +suboption +specifies that the filesystem is an XFS filesystem. +Normally, if +.I xfs_repair +cannot find an XFS superblock, it checks to see if the +filesystem is an EFS filesystem before it tries to +regenerate the XFS superblock. +If the +.B assume_xfs +option is in effect, +.I xfs_repair +will assume that the filesystem is an XFS filesystem and +will ignore an EFS superblock if one is found. +.SS Checks Performed +Inconsistencies corrected include the following: +.TP +1. +Inode and inode blockmap (addressing) checks: +bad magic number in inode, +bad magic numbers in inode blockmap blocks, +extents out of order, +incorrect number of records in inode blockmap blocks, +blocks claimed that are not in a legal data area of the filesystem, +blocks that are claimed by more than one inode. +.TP +2. +Inode allocation map checks: +bad magic number in inode map blocks, +inode state as indicated by map (free or in-use) inconsistent +with state indicated by the inode, +inodes referenced by the filesystem that do not appear in +the inode allocation map, +inode allocation map referencing blocks that do not appear +to contain inodes. +.TP +3. +Size checks: +number of blocks claimed by inode inconsistent with inode size, +directory size not block aligned, +inode size not consistent with inode format. +.TP +4. +Directory checks: +bad magic numbers in directory blocks, +incorrect number of entries in a directory block, +bad freespace information in a directory leaf block, +entry pointing to an unallocated (free) or out +of range inode, +overlapping entries, +missing or incorrect dot and dotdot entries, +entries out of hashvalue order, +incorrect internal directory pointers, +directory type not consistent with inode format and size. +.TP +5. +Pathname checks: +files or directories not referenced by a pathname starting from +the filesystem root, +illegal pathname components. +.TP +6. +Link count checks: +link counts that do not agree with the number of +directory references to the inode. +.TP +7. +Freemap checks: +blocks claimed free by the freemap but also claimed by an inode, +blocks unclaimed by any inode but not appearing in the freemap. +.TP +8. +Super Block checks: +total free block and/or free i-node count incorrect, +filesystem geometry inconsistent, +secondary and primary superblocks contradictory. +.PP +Orphaned files and directories (allocated, in-use but unreferenced) are +reconnected by placing them in the +.I lost+found +directory. +The name assigned is the inode number. +.SS Disk Errors +.I xfs_repair +aborts on most disk I/O errors. +Therefore, if you are trying +to repair a filesystem that was damaged due to a disk drive failure, +steps should be taken to ensure that +all blocks in the filesystem are readable and writeable +before attempting to use +.I xfs_repair +to repair the filesystem. +A possible method is using +.IR dd (8) +to copy the data onto a good disk. +.SS lost+found +The directory +.I lost+found +does not have to already exist in the filesystem being repaired. +If the directory does not exist, it is automatically created. +If the \f2lost+found\f1 directory already exists, +the \f2lost+found\f1 +directory is deleted and recreated every time \f2xfs_repair\f1 +runs. +This ensures that there are no name conflicts in \f2lost+found\f1. +However, if you rename a file in \f2lost+found\f1 and leave it there, +if \f2xfs_repair\f1 is run again, that file is renamed back to +its inode number. +.SS Corrupted Superblocks +XFS has both primary and secondary superblocks. +\f2xfs_repair\f1 uses information in the primary superblock +to automatically find and validate the primary superblock +against the secondary superblocks before proceeding. +Should the primary be too corrupted to be useful in locating +the secondary superblocks, the program scans the filesystem +until it finds and validates some secondary superblocks. +At that point, it generates a primary superblock. +.SS Quotas +If quotas are in use, it is possible that \f2xfs_repair\f1 will clear +some or all of the filesystem quota information. +If so, the program issues a warning just before it terminates. +If all quota information is lost, quotas are disabled and the +program issues a warning to that effect. +.PP +Note that \f2xfs_repair\f1 does not check the validity of quota limits. +It is recommended that you check the quota limit information manually +after \f2xfs_repair\f1. +Also, space usage information is automatically regenerated the +next time the filesystem is mounted with quotas turned on, so the +next quota mount of the filesystem may take some time. +.SH DIAGNOSTICS +.I xfs_repair +issues informative messages as it proceeds +indicating what it has found that is abnormal or any corrective +action that it has taken. +Most of the messages are completely understandable only to those +who are knowledgeable about the structure of the filesystem. +Some of the more common messages are explained here. +Note that the language of the messages is slightly different +if \f2xfs_repair\f1 is run in no-modify mode because the program is not +changing anything on disk. +No-modify mode indicates what it would do to repair the filesystem +if run without the no-modify flag. +.PP +disconnected inode \f3xxxx\f1, moving to \f2lost+found\f1 +.IP +An inode numbered +.B xxxx +was not connected to the filesystem +directory tree and was reconnected to the \f2lost+found\f1 directory. +The inode is assigned the name of its inode number (i-number). +If a \f2lost+found\f1 directory does not exist, it is automatically +created. +.PP +disconnected dir inode \f3xxxx\f1, moving to \f2lost+found\f1 +.IP +As above only the inode is a directory inode. +If a directory inode is attached to \f2lost+found\f1, all of its +children (if any) stay attached to the directory and therefore +get automatically reconnected when the directory is reconnected. +.PP +imap claims in-use inode \f3xxxx\f1 is free, correcting imap +.IP +The inode allocation map thinks that inode \f3xxxx\f1 is +free whereas examination of the inode indicates that the +inode may be in use (although it may be disconnected). +The program updates the inode allocation map. +.PP +imap claims free inode \f3xxxx\f1 is in use, correcting imap +.IP +The inode allocation map thinks that inode \f3xxxx\f1 is +in use whereas examination of the inode indicates that the +inode is not in use and therefore is free. +The program updates the inode allocation map. +.PP +resetting inode \f3xxxx\f1 nlinks from \f3x\f1 to \f3y\f1 +.IP +The program detected a mismatch between the +number of valid directory entries referencing inode \f3xxxx\f1 +and the number of references recorded in the inode and corrected the +the number in the inode. +.PP +\f3fork-type\f1 fork in ino \f3xxxx\f1 claims used block \f3yyyy\f1 +.IP +Inode \f3xxxx\f1 claims a block \f3yyyy\f1 that is used (claimed) +by either another inode or the filesystem itself for metadata storage. +The \f3fork-type\f1 is either \f3data\f1 or \f3attr\f1 +indicating whether the problem lies in the portion of the +inode that tracks regular data or the portion of the inode +that stores XFS attributes. +If the inode is a real-time (rt) inode, the message says so. +Any inode that claims blocks used by the filesystem is deleted. +If two or more inodes claim the same block, they are both deleted. +.PP +\f3fork-type\f1 fork in ino \f3xxxx\f1 claims dup extent ... +.IP +Inode \f3xxxx\f1 claims a block in an extent known to be +claimed more than once. +The offset in the inode, start and length of the extent is given. +The message is slightly different +if the inode is a real-time (rt) inode and the extent is therefore +a real-time (rt) extent. +.PP +inode \f3xxxx\f1 - bad extent ... +.IP +An extent record in the blockmap of inode \f3xxxx\f1 claims +blocks that are out of the legal range of the filesystem. +The message supplies the start, end, and file offset of +the extent. +The message is slightly different +if the extent is a real-time (rt) exent. +.PP +bad \f3fork-type\f1 fork in inode \f3xxxx\f1 +.IP +There was something structurally wrong or inconsistent with the +data structures that map offsets to filesystem blocks. +.PP +cleared inode \f3xxxx\f1 +.IP +There was something wrong with the inode that +was uncorrectable so the program freed the inode. +This usually happens because the inode claims +blocks that are used by something else or the inode itself +is badly corrupted. +Typically, this message +is preceded by one or more messages indicating why the +inode needed to be cleared. +.PP +bad attribute fork in inode \f3xxxx\f1, clearing attr fork +.IP +There was something wrong with the portion of the inode that +stores XFS attributes (the attribute fork) so the program reset +the attribute fork. +As a result of this, all attributes on that inode are lost. +.PP +correcting nextents for inode \f3xxxx\f1, was \f3x\f1 - counted \f3y\f1 +.IP +The program found that the number of extents used to store +the data in the inode is wrong and corrected the number. +The message refers to nextents if the count is wrong +on the number of extents used to store attribute information. +.PP +entry \f3"name"\f1 in dir \f3xxxx\f1 not consistent +with .. +value (\f3yyyy\f1) in dir ino \f3xxxx\f1, +junking entry \f3"name"\f1 in directory inode \f3xxxx\f1 +.IP +The entry \f3"name"\f1 in directory inode \f3xxxx\f1 references a +directory inode \f3yyyy\f1. +However, the ..\& entry in directory \f3yyyy\f1 does not point +back to directory \f3xxxx\f1, +so the program deletes the entry \f3"name"\f1 in directory inode +\f3xxxx\f1. +If the directory inode \f3yyyy\f1 winds up becoming a disconnected +inode as a result of this, it is moved to \f2lost+found\f1 later. +.PP +entry \f3"name"\f1 in dir \f3xxxx\f1 references already +connected dir ino \f3yyyy\f1, +junking entry \f3"name"\f1 in directory inode \f3xxxx\f1 +.IP +The entry \f3"name"\f1 in directory inode \f3xxxx\f1 points to a +directory inode \f3yyyy\f1 that is known to be a child of another +directory. +Therefore, the entry is invalid and is deleted. +This message refers to an entry in a small directory. +If this were a large directory, the last phrase would read +"will clear entry". +.PP +entry references free inode \f3xxxx\f1 in directory \f3yyyy\f1, +will clear entry +.IP +An entry in directory inode \f3yyyy\f1 references an inode \f3xxxx\f1 +that is known to be free. +The entry is therefore invalid and is deleted. +This message refers to a large directory. +If the directory were small, the message would read "junking entry ...". +.SH EXIT STATUS +.I xfs_repair -n +(no modify node) +will return a status of 1 if filesystem corruption was detected and +0 if no filesystem corruption was detected. +.I xfs_repair +run without the -n option will always return a status code of 0. +.SH BUGS +.I xfs_repair +does not do a thorough job on XFS extended attributes. +The structure of the attribute fork will be consistent, +but only the contents of attribute forks that will fit into +an inode are checked. +This limitation will be fixed in the future. +.PP +The no-modify mode (\f3\-n\f1 option) is not completely +accurate. +It does not catch inconsistencies in the freespace and inode +maps, particularly lost blocks or subtly corrupted maps (trees). +.PP +The no-modify mode can generate repeated warnings about +the same problems because it cannot fix the problems as they +are encountered. +.SH SEE ALSO +dd(1), +mkfs.xfs(8), +xfs_check(8), +xfs(5). diff -rNu linux-2.4.7/cmd/xfsprogs/man/man8/xfs_rtcp.8 linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_rtcp.8 --- linux-2.4.7/cmd/xfsprogs/man/man8/xfs_rtcp.8 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/man/man8/xfs_rtcp.8 Wed May 9 01:56:06 2001 @@ -0,0 +1,44 @@ +.TH xfs_rtcp 8 +.SH NAME +xfs_rtcp \- XFS realtime copy command +.SH SYNOPSIS +.nf +\f3xfs_rtcp\f1 [\f3\-e\f1 extsize] [\f3\-p\f1] \f2source\f1... \f2target\f1 +.fi +.SH DESCRIPTION +.I xfs_rtcp +copies a file to the realtime partition on an XFS filesystem. +If there is more than one +.I source +and +.IR target , +the final argument (the +.IR target ) +must be a directory which already exists. +.SH OPTIONS +.TP +\f3\-e\f1 extsize +Sets the extent size of the destination realtime file. +.TP +\f3\-p\f1 +Use if the size of the source file is not an even multiple of +the block size of the destination filesystem. +When +\f3\-p\f1 is specified +.I xfs_rtcp +will pad the destination file to a size which is an even multiple +of the filesystem block size. +This is necessary since the realtime file is created using +direct I/O and the minimum I/O is the filesystem block size. +.SH "SEE ALSO" +xfs(5), +mkfs.xfs(8), +mount(8). +.SH CAVEATS +Currently, realtime partitions are not supported under the Linux +version of XFS, and use of a realtime partition +.BR "WILL CAUSE CORRUPTION" +on the data partition. +As such, this command is made available for curious +.B "DEVELOPERS ONLY" +at this point in time. diff -rNu linux-2.4.7/cmd/xfsprogs/mkfile/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/mkfile/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/mkfile/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfile/CVS/Entries Thu Jul 5 11:44:46 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Mon Jan 15 06:52:52 2001/-ko/ +/xfs_mkfile.c/1.4/Wed May 9 06:56:06 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/mkfile/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/mkfile/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/mkfile/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfile/CVS/Repository Thu Jul 5 11:44:46 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/mkfile diff -rNu linux-2.4.7/cmd/xfsprogs/mkfile/CVS/Root linux-2.4-xfs/cmd/xfsprogs/mkfile/CVS/Root --- linux-2.4.7/cmd/xfsprogs/mkfile/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfile/CVS/Root Thu Jul 5 11:44:46 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/mkfile/Makefile linux-2.4-xfs/cmd/xfsprogs/mkfile/Makefile --- linux-2.4.7/cmd/xfsprogs/mkfile/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfile/Makefile Mon Jan 15 00:52:52 2001 @@ -0,0 +1,46 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = xfs_mkfile +CFILES = xfs_mkfile.c + +default: $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_BIN_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/xfsprogs/mkfile/xfs_mkfile.c linux-2.4-xfs/cmd/xfsprogs/mkfile/xfs_mkfile.c --- linux-2.4.7/cmd/xfsprogs/mkfile/xfs_mkfile.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfile/xfs_mkfile.c Wed May 9 01:56:06 2001 @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Make file utility for xfs. + */ + +#include +#include +#include +#include +#include + +#define MAXBUFFERSIZE (256 * 1024) + +static void usage(void); +static char *progname; + +int +main(int argc, char **argv) +{ + int fd; + loff_t result; + loff_t size = 0; + loff_t mult = 0; + int bytes = 0; + loff_t wrote = 0; + int len = 0; + int c; + int errflg = 0; + int errs = 0; + int nobytes = 0; + int prealloc = 0; + int verbose = 0; + struct dioattr da; + void *buf = NULL; + int buflen = 0, nbuflen; + int bufalign = 0, nbufalign, bufmin; + int oflags; + xfs_flock64_t flck; + + progname = basename(argv[0]); + while ((c = getopt(argc, argv, "npvV")) != EOF) { + switch(c) { + case 'n': + nobytes++; + break; + case 'p': + prealloc++; + break; + case 'v': + verbose++; + break; + case 'V': + printf("%s version %s\n", progname, VERSION); + break; + default: + errflg++; + break; + } + } + + if (argc < optind + 2 || errflg) + usage(); + + mult = 1; + + len = strlen(argv[optind]); + + if (isalpha(argv[optind][len-1])) { + switch (argv[optind][len-1]) { + case 'k': + case 'K': + mult = 1024; + break; + case 'b': + case 'B': + mult = 512; + break; + case 'm': + case 'M': + mult = 1024; + mult *= 1024; + break; + case 'g': + case 'G': + mult = 1024; + mult *= 1024; + mult *= 1024; + break; + default: + fprintf(stderr, "unknown size %s\n", argv[optind]); + usage(); + } + + argv[optind][len-1] = '\0'; + } + + size = atoll(argv[optind]) * mult; + + optind++; + + while (optind < argc) { + if (verbose) + fprintf(stdout, "%s %lld bytes %s\n", + argv[optind], (long long)size, + prealloc + ? "(pre-allocated)" + : ""); + + oflags = O_CREAT|O_TRUNC|O_WRONLY|(nobytes ? 0 : O_DIRECT); + + fd = open(argv[optind], oflags, 0600); + + if ( (oflags & O_DIRECT) + && ( (fd < 0 && errno == EINVAL) + || ioctl(fd, XFS_IOC_DIOINFO, &da) < 0)) { + + close(fd); + + oflags &= ~O_DIRECT; + + fd = open(argv[optind], oflags, 0600); + } + + if (fd < 0) { + perror(argv[optind]); + optind++; + errs++; + continue; + } + + if (size == 0) { + close(fd); + optind++; + continue; + } + + if ((result = lseek64(fd, size - 1, SEEK_SET)) < 0LL) { + /* + * This check doesn't actually work for 6.2 + * efs and nfs2, although it should. + */ + fprintf(stderr, "lseek64 error, result = %lld\n", + (long long)result); + if (errno) + perror(argv[optind]); + errs++; + } else if (nobytes) { + if (write(fd, "", 1) < 0) { + perror(argv[optind]); + errs++; + } + } else { + flck.l_whence = SEEK_SET; + flck.l_start = 0LL; + flck.l_len = size; +#if 0 + (void)ioctl(fd, XFS_IOC_RESVSP64, &flck); + + if (prealloc) { + if ( close(fd) < 0 ) { + perror(argv[optind]); + unlink(argv[optind]); + errs++; + } + + optind++; + + continue; + } +#endif + if (oflags & O_DIRECT) { + nbufalign = da.d_mem; + + if ( da.d_miniosz <= MAXBUFFERSIZE + && MAXBUFFERSIZE <= da.d_maxiosz) + nbuflen = MAXBUFFERSIZE; + else if (da.d_maxiosz < MAXBUFFERSIZE) + nbuflen = da.d_maxiosz; + else + nbuflen = da.d_miniosz; + + bufmin = da.d_miniosz; + } else { + nbuflen = MAXBUFFERSIZE; + nbufalign = sizeof(long); + bufmin = 0; + } + + if (nbuflen > buflen || nbufalign > bufalign) { + if (buf) + free(buf); + buf = memalign(nbufalign, nbuflen); + buflen = nbuflen; + bzero(buf, nbuflen); + nbufalign = bufalign; + } + + wrote = 0; + + lseek64(fd, 0LL, SEEK_SET); + + while (wrote < size) { + if (size - wrote >= buflen) + bytes = buflen; + else if (bufmin) + bytes = roundup(size - wrote, bufmin); + else + bytes = size - wrote; + + len = write(fd, buf, bytes); + + if (len < 0) { + perror(argv[optind]); + unlink(argv[optind]); + errs++; + break; + } + + wrote += len; + } + + if (wrote > size && ftruncate64(fd, size) < 0) { + perror(argv[optind]); + unlink(argv[optind]); + errs++; + } + } + + if ( close(fd) < 0 ) { + perror(argv[optind]); + unlink(argv[optind]); + errs++; + } + + optind++; + } + + return errs != 0; +} + +static void +usage(void) +{ + fprintf(stderr, "%s: [-npv] [] ...\n", progname); + exit(2); +} diff -rNu linux-2.4.7/cmd/xfsprogs/mkfs/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/mkfs/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/mkfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfs/CVS/Entries Thu Jul 5 11:44:48 2001 @@ -0,0 +1,11 @@ +/Makefile/1.3/Thu Apr 19 04:57:33 2001/-ko/ +/fstyp.c/1.1/Thu Apr 19 04:57:33 2001/-ko/ +/maxtrres.c/1.2/Mon Apr 9 07:41:10 2001/-ko/ +/mountinfo.c/1.3/Tue Jul 3 04:33:45 2001/-ko/ +/mountinfo.h/1.2/Tue Jul 3 04:33:45 2001/-ko/ +/proto.c/1.3/Wed May 9 06:56:06 2001/-ko/ +/proto.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/volume.h/1.1/Mon Jan 15 05:36:03 2001/-ko/ +/xfs_mkfs.c/1.12/Tue May 15 03:43:23 2001// +/xfs_mkfs.h/1.1/Mon Jan 15 05:36:03 2001// +D diff -rNu linux-2.4.7/cmd/xfsprogs/mkfs/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/mkfs/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/mkfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfs/CVS/Repository Thu Jul 5 11:44:46 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/mkfs diff -rNu linux-2.4.7/cmd/xfsprogs/mkfs/CVS/Root linux-2.4-xfs/cmd/xfsprogs/mkfs/CVS/Root --- linux-2.4.7/cmd/xfsprogs/mkfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfs/CVS/Root Thu Jul 5 11:44:46 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/mkfs/Makefile linux-2.4-xfs/cmd/xfsprogs/mkfs/Makefile --- linux-2.4.7/cmd/xfsprogs/mkfs/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfs/Makefile Wed Apr 18 23:57:33 2001 @@ -0,0 +1,67 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = mkfs.xfs +MAXTRRES = maxtrres +FSTYP = fstyp + +CFILES = xfs_mkfs.c mountinfo.c proto.c +HFILES = xfs_mkfs.h mountinfo.h proto.h volume.h +LCFLAGS = $(USELVM) +LLDLIBS = $(LIBXFS) $(LIBUUID) $(LIBLVM) +LLDFLAGS = -L$(TOPDIR)/libxfs + +MAXTRLIBS = $(LIBXFS) $(LIBUUID) +LSRCFILES = $(MAXTRRES).c $(FSTYP).c +LDIRT = $(MAXTRRES) $(MAXTRRES).h $(FSTYP) + +default: $(MAXTRRES).h $(CMDTARGET) + +include $(BUILDRULES) + +$(MAXTRRES): + $(CCF) $@.c -o $@ $(LDFLAGS) $(MAXTRLIBS) + +$(MAXTRRES).h: $(MAXTRRES) + LD_LIBRARY_PATH=../libxfs; export LD_LIBRARY_PATH; \ + ./$(MAXTRRES) > $@ || ( rm -f $@ && exit 1 ) + +$(FSTYP): $(CMDTARGET) + $(CCF) $@.c -o $@ $(LDFLAGS) mountinfo.o + +install: default + $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_SBIN_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/xfsprogs/mkfs/fstyp.c linux-2.4-xfs/cmd/xfsprogs/mkfs/fstyp.c --- linux-2.4.7/cmd/xfsprogs/mkfs/fstyp.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfs/fstyp.c Wed Apr 18 23:57:33 2001 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include + +#include "mountinfo.h" + +/* + * fstyp allows the user to determine the filesystem identifier of + * mounted or unmounted filesystems using heuristics. + * + * The filesystem type is required by mount(2) and sometimes by mount(8) + * to mount filesystems of different types. fstyp uses exactly the same + * heuristics that mount does to determine whether the supplied device + * special file is of a known filesystem type. If it is, fstyp prints + * on standard output the usual filesystem identifier for that type and + * exits with a zero return code. If no filesystem is identified, fstyp + * prints "Unknown" to indicate failure and exits with a non-zero status. + * + * WARNING: The use of heuristics implies that the result of fstyp is not + * guaranteed to be accurate. + */ + +int +main(int argc, char *argv[]) +{ + char *type; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", basename(argv[0])); + exit(1); + } + + if (access(argv[1], R_OK) < 0) { + perror(argv[1]); + exit(1); + } + + if ((type = mnt_known_fs_type(argv[1])) == NULL) { + printf("Unknown\n"); + exit(1); + } + printf("%s\n", type); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfsprogs/mkfs/maxtrres.c linux-2.4-xfs/cmd/xfsprogs/mkfs/maxtrres.c --- linux-2.4.7/cmd/xfsprogs/mkfs/maxtrres.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfs/maxtrres.c Mon Apr 9 02:41:10 2001 @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * maxtrres + * + * Compute the maximum transaction reservation for every legal + * combination of block size, inode size, directory version, + * and directory block size. + * Generates a table compiled into mkfs, to control the default + * and minimum log sizes. + */ + +#include +#include "xfs_mkfs.h" + +xfs_trans_reservations_t tr_count = { + XFS_WRITE_LOG_COUNT, /* extent alloc trans */ + XFS_ITRUNCATE_LOG_COUNT, /* truncate trans */ + XFS_RENAME_LOG_COUNT, /* rename trans */ + XFS_LINK_LOG_COUNT, /* link trans */ + XFS_REMOVE_LOG_COUNT, /* unlink trans */ + XFS_SYMLINK_LOG_COUNT, /* symlink trans */ + XFS_CREATE_LOG_COUNT, /* create trans */ + XFS_MKDIR_LOG_COUNT, /* mkdir trans */ + XFS_DEFAULT_LOG_COUNT, /* inode free trans */ + XFS_DEFAULT_LOG_COUNT, /* inode update trans */ + XFS_DEFAULT_LOG_COUNT, /* fs data section grow trans */ + XFS_DEFAULT_LOG_COUNT, /* sync write inode trans */ + XFS_ADDAFORK_LOG_COUNT, /* cvt inode to attributed trans */ + XFS_DEFAULT_LOG_COUNT, /* write setuid/setgid file */ + XFS_ATTRINVAL_LOG_COUNT, /* attr fork buffer invalidation */ + XFS_ATTRSET_LOG_COUNT, /* set/create an attribute */ + XFS_ATTRRM_LOG_COUNT, /* remove an attribute */ + XFS_DEFAULT_LOG_COUNT, /* clear bad agi unlinked ino bucket */ + XFS_DEFAULT_PERM_LOG_COUNT, /* grow realtime allocations */ + XFS_DEFAULT_LOG_COUNT, /* grow realtime zeroing */ + XFS_DEFAULT_LOG_COUNT, /* grow realtime freeing */ +}; + +static int +max_trans_res( + xfs_mount_t *mp, + int *mul) +{ + uint *p; + uint *q; + int rval; + xfs_trans_reservations_t *tr; + xfs_da_args_t args; + int local; + int size; + int nblks; + int res; + + nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); + + /* + * Fill in the arg structure for this request. + */ + bzero(&args, sizeof(args)); + args.name = NULL; + args.namelen = MAXNAMELEN; + args.value = NULL; + args.valuelen = 65536; + args.flags = 0; + args.hashval = 0; + args.dp = NULL; + args.firstblock = NULL; + args.flist = NULL; + args.whichfork = XFS_ATTR_FORK; + args.oknoent = 1; + + /* + * Determine space new attribute will use, and if it will be + * inline or out of line. + */ + size = libxfs_attr_leaf_newentsize( + &args, mp->m_sb.sb_blocksize, &local); + + if (local) { + printf("Uh-oh.. attribute is local\n"); + } else { + /* Out of line attribute, cannot double split, but make + * room for the attribute value itself. + */ + nblks += XFS_B_TO_FSB(mp, size); + nblks += XFS_NEXTENTADD_SPACE_RES(mp, size, XFS_ATTR_FORK); + } + res = XFS_ATTRSET_LOG_RES(mp, nblks); +#if 0 + printf("size = %d nblks = %d res = %d\n", size, nblks, res); +#endif + mp->m_reservations.tr_attrset = res; + + for (rval = 0, tr = &mp->m_reservations, p = (uint *)tr, + q = (uint *)&tr_count; + p < (uint *)(tr + 1); + p++, q++) { + if ((int)*p > rval) { + rval = (int)*p; + *mul = (int)*q; + } + } + return rval; +} + +int +main(int argc, char **argv) +{ + int bl; + int dl; + int dv; + int i; + int il; + xfs_mount_t m; + xfs_sb_t *sbp; + int mul; + + progname = basename(argv[0]); + if (argc > 1) { + fprintf(stderr, "Usage: %s\n", progname); + return 1; + } + memset(&m, 0, sizeof(m)); + sbp = &m.m_sb; + sbp->sb_magicnum = XFS_SB_MAGIC; + sbp->sb_sectlog = 9; + sbp->sb_sectsize = 1 << sbp->sb_sectlog; + for (bl = XFS_MIN_BLOCKSIZE_LOG; bl <= XFS_MAX_BLOCKSIZE_LOG; bl++) { + sbp->sb_blocklog = bl; + sbp->sb_blocksize = 1 << bl; + sbp->sb_agblocks = XFS_AG_MIN_BYTES / (1 << bl); + for (il = XFS_DINODE_MIN_LOG; il <= XFS_DINODE_MAX_LOG; il++) { + if ((1 << il) > (1 << bl) / XFS_MIN_INODE_PERBLOCK) + continue; + sbp->sb_inodelog = il; + sbp->sb_inopblog = bl - il; + sbp->sb_inodesize = 1 << il; + sbp->sb_inopblock = 1 << (bl - il); + for (dl = bl; dl <= XFS_MAX_BLOCKSIZE_LOG; dl++) { + sbp->sb_dirblklog = dl - bl; + for (dv = 1; dv <= 2; dv++) { + if (dv == 1 && dl != bl) + continue; + sbp->sb_versionnum = + XFS_SB_VERSION_4 | + (dv == 2 ? + XFS_SB_VERSION_DIRV2BIT : + 0); + libxfs_mount(&m, sbp, 0, 0, 0, 0); + i = max_trans_res(&m, &mul); + printf( + "#define\tMAXTRRES_B%d_I%d_D%d_V%d\t%lld\t" + "/* LOG_FACTOR %d */\n", + bl, il, dl, dv, (long long) + XFS_B_TO_FSB(&m, i), mul); + libxfs_umount(&m); + } + } + } + } + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/mkfs/mountinfo.c linux-2.4-xfs/cmd/xfsprogs/mkfs/mountinfo.c --- linux-2.4.7/cmd/xfsprogs/mkfs/mountinfo.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfs/mountinfo.c Mon Jul 2 23:33:45 2001 @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include "mountinfo.h" + +int +mnt_check_init(mnt_check_state_t **check_state) { + return(0); +} + +int +mnt_find_mount_conflicts(mnt_check_state_t *check_state, char *name) { + FILE *f; + struct mntent *mnt; + + /* FIXME: this is poorly written code ... nathans TODO */ + /* - should prefer procfs and also use stat not strcmp */ + + if ((f = setmntent (MOUNTED, "r")) == NULL) { + return 0; + } + + while ((mnt = getmntent (f)) != NULL) { + if (strcmp (name, mnt->mnt_fsname) == 0) { + break; + } + } + endmntent (f); + if (mnt) + return(1); + return 0; +} + +int +mnt_causes_test(mnt_check_state_t *check_state, int cause) { + switch(cause) { + case MNT_CAUSE_MOUNTED: + return(1); + + default: + fprintf(stderr, "mnt_causes_test: unknown cause %d\n", cause); + exit(99); + } +} + +void +mnt_causes_show(mnt_check_state_t *check_state, FILE *fp, char *prefix) +{ + fprintf(fp, "mnt_causes_show: not implemented. Called with %s\n", + prefix); + exit(98); +} + +void +mnt_plist_show(mnt_check_state_t *check_state, FILE *fp, char *prefix) +{ + /* + * Need to do some work for volume mgmt. + */ +} + +int +mnt_check_end(mnt_check_state_t *check_state) +{ + return(0); +} + +char * +mnt_known_fs_type(const char *device) +{ + static char *fstype (const char *); + return fstype(device); +} + + +/* + * From mount(8) source by Andries Brouwer. Hacked for XFS by mkp. + * Recent sync's to mount source: + * - util-linux-2.10o ... 06 Sep 00 + * - util-linux-2.10r ... 06 Dec 00 + */ + +#define SIZE(a) (sizeof(a)/sizeof(a[0])) + +static inline unsigned short +swapped(unsigned short a) { + return (a>>8) | (a<<8); +} + +static inline int +assemble4le(unsigned char *p) { + return (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24)); +} + +/* + Probes the device and attempts to determine the type of filesystem + contained within. + + Original routine by ; made into a function + for mount(8) by Mike Grupenhoff . + Read the superblock only once - aeb + Added iso9660, romfs, qnx4, udf, swap - aeb + Added a test for high sierra (iso9660) - quinlan@bucknell.edu + Corrected the test for xiafs - aeb + Added ufs from a patch by jj. But maybe there are several types of ufs? + Added ntfs from a patch by Richard Russon. + Added a very weak heuristic for vfat - aeb + Added xfs - 2000-03-21 Martin K. Petersen + Added cramfs, hfs, hpfs, adfs - Sepp Wijnands + Added ext3 - Andrew Morton +*/ + +/* udf magic - I find that trying to mount garbage as an udf fs + causes a very large kernel delay, almost killing the machine. + So, we do not try udf unless there is positive evidence that it + might work. Try iso9660 first, it is much more likely. + Strings below taken from ECMA 167. */ +static char +*udf_magic[] = { "BEA01", "BOOT2", "CD001", "CDW02", "NSR02", + "NSR03", "TEA01" }; + +static int +may_be_udf(const char *id) { + char **m; + + for (m = udf_magic; m - udf_magic < SIZE(udf_magic); m++) + if (!strncmp(*m, id, 5)) + return 1; + return 0; +} + +static int +may_be_swap(const char *s) { + return (strncmp(s-10, "SWAP-SPACE", 10) == 0 || + strncmp(s-10, "SWAPSPACE2", 10) == 0); +} + +/* rather weak necessary condition */ +static int +may_be_adfs(const u_char *s) { + u_char *p; + int sum; + + p = (u_char *) s + 511; + sum = 0; + while(--p != s) + sum = (sum >> 8) + (sum & 0xff) + *p; + + return (sum == p[511]); +} + +static int is_reiserfs_magic_string (struct reiserfs_super_block * rs) +{ + return (!strncmp (rs->s_magic, REISERFS_SUPER_MAGIC_STRING, + strlen ( REISERFS_SUPER_MAGIC_STRING)) || + !strncmp (rs->s_magic, REISER2FS_SUPER_MAGIC_STRING, + strlen ( REISER2FS_SUPER_MAGIC_STRING))); +} + +static char * +fstype(const char *device) { + int fd; + char *type = NULL; + union { + struct minix_super_block ms; + struct ext_super_block es; + struct ext2_super_block e2s; + struct reiserfs_super_block rs; + } sb; + union { + struct xiafs_super_block xiasb; + char romfs_magic[8]; + char qnx4fs_magic[10]; /* ignore first 4 bytes */ + long bfs_magic; + struct ntfs_super_block ntfssb; + struct fat_super_block fatsb; + struct xfs_super_block xfsb; + struct cramfs_super_block cramfssb; + } xsb; + struct ufs_super_block ufssb; + union { + struct iso_volume_descriptor iso; + struct hs_volume_descriptor hs; + } isosb; + struct hfs_super_block hfssb; + struct hpfs_super_block hpfssb; + struct adfs_super_block adfssb; + struct stat statbuf; + + /* opening and reading an arbitrary unknown path can have + undesired side effects - first check that `device' refers + to a block device */ + if (stat (device, &statbuf) || !S_ISBLK(statbuf.st_mode)) + return 0; + + fd = open(device, O_RDONLY); + if (fd < 0) + return 0; + + if (lseek(fd, 1024, SEEK_SET) != 1024 + || read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb)) + goto io_error; + + /* ext2 has magic in little-endian on disk, so "swapped" is + superfluous; however, there have existed strange byteswapped + PPC ext2 systems */ + if (ext2magic(sb.e2s) == EXT2_SUPER_MAGIC + || ext2magic(sb.e2s) == EXT2_PRE_02B_MAGIC + || ext2magic(sb.e2s) == swapped(EXT2_SUPER_MAGIC)) { + type = "ext2"; + + /* maybe even ext3? */ + if ((assemble4le(sb.e2s.s_feature_compat) + & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && + assemble4le(sb.e2s.s_journal_inum) != 0) + type = "ext3,ext2"; + } + + else if (minixmagic(sb.ms) == MINIX_SUPER_MAGIC + || minixmagic(sb.ms) == MINIX_SUPER_MAGIC2 + || minixmagic(sb.ms) == swapped(MINIX_SUPER_MAGIC2)) + type = "minix"; + + else if (extmagic(sb.es) == EXT_SUPER_MAGIC) + type = "ext"; + + if (!type) { + if (lseek(fd, REISERFS_DISK_OFFSET_IN_BYTES, SEEK_SET) != + REISERFS_DISK_OFFSET_IN_BYTES + || read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb)) + goto io_error; + if (is_reiserfs_magic_string(&sb.rs)) + type = "reiserfs"; + } + + if (!type) { + if (lseek(fd, REISERFS_OLD_DISK_OFFSET_IN_BYTES, SEEK_SET) != + REISERFS_OLD_DISK_OFFSET_IN_BYTES + || read(fd, (char *) &sb, sizeof(sb)) != sizeof(sb)) + goto io_error; + if (is_reiserfs_magic_string(&sb.rs)) + type = "reiserfs"; + } + + if (!type) { + if (lseek(fd, 0, SEEK_SET) != 0 + || read(fd, (char *) &xsb, sizeof(xsb)) != sizeof(xsb)) + goto io_error; + + if (xiafsmagic(xsb.xiasb) == _XIAFS_SUPER_MAGIC) + type = "xiafs"; + else if(!strncmp(xsb.romfs_magic, "-rom1fs-", 8)) + type = "romfs"; + else if(!strncmp(xsb.xfsb.s_magic, XFS_SUPER_MAGIC, 4)) + type = "xfs"; + else if(!strncmp(xsb.qnx4fs_magic+4, "QNX4FS", 6)) + type = "qnx4fs"; + else if(xsb.bfs_magic == 0x1badface) + type = "bfs"; + else if(!strncmp(xsb.ntfssb.s_magic, NTFS_SUPER_MAGIC, + sizeof(xsb.ntfssb.s_magic))) + type = "ntfs"; + else if(cramfsmagic(xsb.cramfssb) == CRAMFS_SUPER_MAGIC) + type = "cramfs"; + else if ((!strncmp(xsb.fatsb.s_os, "MSDOS", 5) || + !strncmp(xsb.fatsb.s_os, "MSWIN", 5) || + !strncmp(xsb.fatsb.s_os, "MTOOL", 5) || + !strncmp(xsb.fatsb.s_os, "mkdosfs", 7) || + !strncmp(xsb.fatsb.s_os, "kmkdosfs", 8) || + /* Michal Svec: created by fdformat, old msdos utility for + formatting large (1.7) floppy disks. */ + !strncmp(xsb.fatsb.s_os, "CH-FOR18", 8)) + && (!strncmp(xsb.fatsb.s_fs, "FAT12 ", 8) || + !strncmp(xsb.fatsb.s_fs, "FAT16 ", 8) || + !strncmp(xsb.fatsb.s_fs2, "FAT32 ", 8))) + type = "vfat"; /* only guessing - might as well be fat or umsdos */ + } + + if (!type) { + if (lseek(fd, 8192, SEEK_SET) != 8192 + || read(fd, (char *) &ufssb, sizeof(ufssb)) != sizeof(ufssb)) + goto io_error; + + if (ufsmagic(ufssb) == UFS_SUPER_MAGIC) /* also test swapped version? */ + type = "ufs"; + } + + if (!type) { + if (lseek(fd, 0x8000, SEEK_SET) != 0x8000 + || read(fd, (char *) &isosb, sizeof(isosb)) != sizeof(isosb)) + goto io_error; + + if(strncmp(isosb.iso.id, ISO_STANDARD_ID, sizeof(isosb.iso.id)) == 0 + || strncmp(isosb.hs.id, HS_STANDARD_ID, sizeof(isosb.hs.id)) == 0) + type = "iso9660"; + else if (may_be_udf(isosb.iso.id)) + type = "udf"; + } + + if (!type) { + if (lseek(fd, 0x400, SEEK_SET) != 0x400 + || read(fd, (char *) &hfssb, sizeof(hfssb)) != sizeof(hfssb)) + goto io_error; + + /* also check if block size is equal to 512 bytes, + since the hfs driver currently only has support + for block sizes of 512 bytes long, and to be + more accurate (sb magic is only a short int) */ + if ((hfsmagic(hfssb) == HFS_SUPER_MAGIC && + hfsblksize(hfssb) == 0x20000) || + (swapped(hfsmagic(hfssb)) == HFS_SUPER_MAGIC && + hfsblksize(hfssb) == 0x200)) + type = "hfs"; + } + + if (!type) { + if (lseek(fd, 0x2000, SEEK_SET) != 0x2000 + || read(fd, (char *) &hpfssb, sizeof(hpfssb)) != sizeof(hpfssb)) + goto io_error; + + if (hpfsmagic(hpfssb) == HPFS_SUPER_MAGIC) + type = "hpfs"; + } + + if (!type) { + if (lseek(fd, 0xc00, SEEK_SET) != 0xc00 + || read(fd, (char *) &adfssb, sizeof(adfssb)) != sizeof(adfssb)) + goto io_error; + + /* only a weak test */ + if (may_be_adfs((u_char *) &adfssb) + && (adfsblksize(adfssb) >= 8 && + adfsblksize(adfssb) <= 10)) + type = "adfs"; + } + + if (!type) { + /* perhaps the user tries to mount the swap space + on a new disk; warn her before she does mkfs on it */ + int pagesize = getpagesize(); + int rd; + char buf[32768]; + + rd = pagesize; + if (rd < 8192) + rd = 8192; + if (rd > sizeof(buf)) + rd = sizeof(buf); + if (lseek(fd, 0, SEEK_SET) != 0 + || read(fd, buf, rd) != rd) + goto io_error; + if (may_be_swap(buf+pagesize) || + may_be_swap(buf+4096) || may_be_swap(buf+8192)) + type = "swap"; + } + + close (fd); + return(type); + +io_error: + close(fd); + return 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/mkfs/mountinfo.h linux-2.4-xfs/cmd/xfsprogs/mkfs/mountinfo.h --- linux-2.4.7/cmd/xfsprogs/mkfs/mountinfo.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfs/mountinfo.h Mon Jul 2 23:33:45 2001 @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * mountinfo.h + * Header for disk volume/partition check routines + */ + +#define MNT_CAUSE_NONE 0x00 +#define MNT_CAUSE_MOUNTED 0x01 /* partition already mounted */ +#define MNT_CAUSE_OVERLAP 0x02 /* partitions overlap */ +#define MNT_CAUSE_NODEV 0x04 /* no /dev/rdsk /dev/dsk entry */ +#define MNT_CAUSE_UNUSED 0x08 /* unallocated partition */ +#define MNT_CAUSE_MULTIMOUNT 0x10 /* multiple owners */ +#define MNT_CAUSE_LVOL_OWNED 0x20 /* owned by logical vol */ +#define MNT_CAUSE_XVM_MNT 0x40 /* mounted xvm subvolume */ +#define MNT_CAUSE_XVM_PART 0x80 /* xvm-owned partition */ +#define MNT_CAUSE__END 0x100 /* last entry */ + +typedef struct mnt_check_state_s { + /* unused, remains from IRIX */ +} mnt_check_state_t; + +/* prototypes */ +int mnt_check_init(mnt_check_state_t **); +int mnt_find_mount_conflicts(mnt_check_state_t *, char *); +int mnt_causes_test(mnt_check_state_t *, int); +void mnt_causes_show(mnt_check_state_t *, FILE *, char *); +void mnt_plist_show(mnt_check_state_t *, FILE *, char *); +int mnt_check_end(mnt_check_state_t *); +char *mnt_known_fs_type(const char *); + +#undef XFS_SUPER_MAGIC + +/* + * From mount(8) source by Andries Brouwer. Hacked for XFS by mkp. + * Recent sync's to mount source: + * - util-linux-2.10o ... 06 Sep 00 + * - util-linux-2.10r ... 06 Dec 00 + * - util-linux-2.11g ... 02 Jul 01 + */ + +/* Including became more and more painful. + Below a very abbreviated version of some declarations, + only designed to be able to check a magic number + in case no filesystem type was given. */ + +#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ +#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ +struct minix_super_block { + u_char s_dummy[16]; + u_char s_magic[2]; +}; +#define minixmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8)) + +#define ISODCL(from, to) (to - from + 1) +#define ISO_STANDARD_ID "CD001" +struct iso_volume_descriptor { + char type[ISODCL(1,1)]; /* 711 */ + char id[ISODCL(2,6)]; + char version[ISODCL(7,7)]; + char data[ISODCL(8,2048)]; +}; + +#define HS_STANDARD_ID "CDROM" +struct hs_volume_descriptor { + char foo[ISODCL ( 1, 8)]; /* 733 */ + char type[ISODCL ( 9, 9)]; /* 711 */ + char id[ISODCL ( 10, 14)]; + char version[ISODCL ( 15, 15)]; /* 711 */ + char data[ISODCL(16,2048)]; +}; + +#define EXT_SUPER_MAGIC 0x137D +struct ext_super_block { + u_char s_dummy[56]; + u_char s_magic[2]; +}; +#define extmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8)) + +#define EXT2_PRE_02B_MAGIC 0xEF51 +#define EXT2_SUPER_MAGIC 0xEF53 +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 +struct ext2_super_block { + u_char s_dummy1[56]; + u_char s_magic[2]; + u_char s_dummy2[34]; + u_char s_feature_compat[4]; + u_char s_feature_incompat[4]; + u_char s_feature_ro_compat[4]; + u_char s_uuid[16]; + u_char s_volume_name[16]; + u_char s_dummy3[88]; + u_char s_journal_inum[4]; /* ext3 only */ +}; +#define ext2magic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8)) + +struct reiserfs_super_block +{ + u_char s_block_count[4]; + u_char s_free_blocks[4]; + u_char s_root_block[4]; + u_char s_journal_block[4]; + u_char s_journal_dev[4]; + u_char s_orig_journal_size[4]; + u_char s_journal_trans_max[4]; + u_char s_journal_block_count[4]; + u_char s_journal_max_batch[4]; + u_char s_journal_max_commit_age[4]; + u_char s_journal_max_trans_age[4]; + u_char s_blocksize[2]; + u_char s_oid_maxsize[2]; + u_char s_oid_cursize[2]; + u_char s_state[2]; + u_char s_magic[12]; +}; +#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs" +#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" +#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024) +/* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */ +#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024) + +#define _XIAFS_SUPER_MAGIC 0x012FD16D +struct xiafs_super_block { + u_char s_boot_segment[512]; /* 1st sector reserved for boot */ + u_char s_dummy[60]; + u_char s_magic[4]; +}; +#define xiafsmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8) + \ + (((uint) s.s_magic[2]) << 16) + \ + (((uint) s.s_magic[3]) << 24)) + +/* From jj@sunsite.ms.mff.cuni.cz Mon Mar 23 15:19:05 1998 */ +#define UFS_SUPER_MAGIC 0x00011954 +struct ufs_super_block { + u_char s_dummy[0x55c]; + u_char s_magic[4]; +}; +#define ufsmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8) + \ + (((uint) s.s_magic[2]) << 16) + \ + (((uint) s.s_magic[3]) << 24)) + +/* From Richard.Russon@ait.co.uk Wed Feb 24 08:05:27 1999 */ +#define NTFS_SUPER_MAGIC "NTFS" +struct ntfs_super_block { + u_char s_dummy[3]; + u_char s_magic[4]; +}; + +/* From inspection of a few FAT filesystems - aeb */ +/* Unfortunately I find almost the same thing on an extended partition; + it looks like a primary has some directory entries where the extended + has a partition table: IO.SYS, MSDOS.SYS, WINBOOT.SYS */ +struct fat_super_block { + u_char s_dummy[3]; + u_char s_os[8]; /* "MSDOS5.0" or "MSWIN4.0" or "MSWIN4.1" */ + /* mtools-3.9.4 writes "MTOOL394" */ + u_char s_dummy2[32]; + u_char s_label[11]; /* for DOS? */ + u_char s_fs[8]; /* "FAT12 " or "FAT16 " or all zero */ + /* OS/2 BM has "FAT " here. */ + u_char s_dummy3[9]; + u_char s_label2[11]; /* for Windows? */ + u_char s_fs2[8]; /* garbage or "FAT32 " */ +}; + +#define XFS_SUPER_MAGIC "XFSB" +struct xfs_super_block { + u_char s_magic[4]; + u_char s_dummy[28]; + u_char s_uuid[16]; + u_char s_dummy2[60]; + u_char s_fname[12]; +}; + +#define CRAMFS_SUPER_MAGIC 0x28cd3d45 +struct cramfs_super_block { + u_char s_magic[4]; + u_char s_dummy[12]; + u_char s_id[16]; +}; +#define cramfsmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8) + \ + (((uint) s.s_magic[2]) << 16) + \ + (((uint) s.s_magic[3]) << 24)) + +#define HFS_SUPER_MAGIC 0x4244 +struct hfs_super_block { + u_char s_magic[2]; + u_char s_dummy[18]; + u_char s_blksize[4]; +}; +#define hfsmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8)) +#define hfsblksize(s) ((uint) s.s_blksize[0] + \ + (((uint) s.s_blksize[1]) << 8) + \ + (((uint) s.s_blksize[2]) << 16) + \ + (((uint) s.s_blksize[3]) << 24)) + +#define HPFS_SUPER_MAGIC 0xf995e849 +struct hpfs_super_block { + u_char s_magic[4]; + u_char s_magic2[4]; +}; +#define hpfsmagic(s) ((uint) s.s_magic[0] + (((uint) s.s_magic[1]) << 8) + \ + (((uint) s.s_magic[2]) << 16) + \ + (((uint) s.s_magic[3]) << 24)) + +struct adfs_super_block { + u_char s_dummy[448]; + u_char s_blksize[1]; + u_char s_dummy2[62]; + u_char s_checksum[1]; +}; +#define adfsblksize(s) ((uint) s.s_blksize[0]) diff -rNu linux-2.4.7/cmd/xfsprogs/mkfs/proto.c linux-2.4-xfs/cmd/xfsprogs/mkfs/proto.c --- linux-2.4.7/cmd/xfsprogs/mkfs/proto.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfs/proto.c Wed May 9 01:56:06 2001 @@ -0,0 +1,767 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "proto.h" + +/* + * Prototypes for internal functions. + */ +extern long long cvtnum(int blocksize, char *s); +extern void parseproto(xfs_mount_t *mp, xfs_inode_t *pip, char **pp, + char *name); +static long getnum(char **pp); +static char *getstr(char **pp); +static void fail(char *msg, int i); +static void getres(xfs_trans_t *tp, uint blocks); +static void rsvfile(xfs_mount_t *mp, xfs_inode_t *ip, long long len); +static int newfile(xfs_trans_t *tp, xfs_inode_t *ip, xfs_bmap_free_t *flist, + xfs_fsblock_t *first, int dolocal, int logit, char *buf, int len); +static char *newregfile(char **pp, int *len); +static void rtinit(xfs_mount_t *mp); +static long filesize(int fd); + +/* + * Use this for block reservations needed for mkfs's conditions + * (basically no fragmentation). + */ +#define MKFS_BLOCKRES_INODE \ + ((uint)(XFS_IALLOC_BLOCKS(mp) + (XFS_IN_MAXLEVELS(mp) - 1))) +#define MKFS_BLOCKRES(rb) \ + ((uint)(MKFS_BLOCKRES_INODE + XFS_DA_NODE_MAXDEPTH + \ + (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1) + (rb))) + + +char * +setup_proto( + char *fname) +{ + char *buf; + static char dflt[] = "d--755 0 0 $"; + int fd; + long size; + + if (!fname) + return dflt; + if ((fd = open(fname, O_RDONLY)) < 0 || (size = filesize(fd)) < 0) { + fprintf(stderr, "%s: failed to open %s: %s\n", + progname, fname, strerror(errno)); + exit(1); + } + buf = malloc(size + 1); + if (read(fd, buf, size) < size) { + fprintf(stderr, "%s: read failed on %s: %s\n", + progname, fname, strerror(errno)); + exit(1); + } + if (buf[size - 1] != '\n') { + fprintf(stderr, "%s: proto file %s premature EOF\n", + progname, fname); + exit(1); + } + buf[size] = '\0'; + /* + * Skip past the stuff there for compatibility, a string and 2 numbers. + */ + (void)getstr(&buf); /* boot image name */ + (void)getnum(&buf); /* block count */ + (void)getnum(&buf); /* inode count */ + return buf; +} + +static long +getnum( + char **pp) +{ + char *s; + + s = getstr(pp); + return atol(s); +} + +static void +fail( + char *msg, + int i) +{ + fprintf(stderr, "%s: %s %d\n", progname, msg, i); + ASSERT(0); + exit(1); +} + +static void +getres( + xfs_trans_t *tp, + uint blocks) +{ + int i; + xfs_mount_t *mp; + uint r; + + mp = tp->t_mountp; + for (i = 0, r = MKFS_BLOCKRES(blocks); r >= blocks; r--) { + i = libxfs_trans_reserve(tp, r, 0, 0, 0, 0); + if (i == 0) + return; + } + res_failed(i); + /* NOTREACHED */ +} + +static char * +getstr( + char **pp) +{ + int c; + char *p; + char *rval; + + p = *pp; + while ((c = *p)) { + switch (c) { + case ' ': + case '\t': + case '\n': + p++; + continue; + case ':': + p++; + while (*p++ != '\n') + ; + continue; + default: + rval = p; + while (c != ' ' && c != '\t' && c != '\n' && c != '\0') + c = *++p; + *p++ = '\0'; + *pp = p; + return rval; + } + } + if (!c) { + fprintf(stderr, "%s: premature EOF in prototype file\n", + progname); + exit(1); + } + return NULL; +} + +static void +rsvfile( + xfs_mount_t *mp, + xfs_inode_t *ip, + long long llen) +{ + int error; + xfs_trans_t *tp; + + error = libxfs_alloc_file_space(ip, 0, llen, 1, 0); + + if (error) { + fail("error reserving space for a file", error); + exit(1); + } + + /* + * update the inode timestamp, mode, and prealloc flag bits + */ + tp = libxfs_trans_alloc(mp, 0); + + libxfs_trans_ijoin(tp, ip, 0); + libxfs_trans_ihold(tp, ip); + + ip->i_d.di_mode &= ~ISUID; + + /* + * Note that we don't have to worry about mandatory + * file locking being disabled here because we only + * clear the ISGID bit if the Group execute bit is + * on, but if it was on then mandatory locking wouldn't + * have been enabled. + */ + if (ip->i_d.di_mode & (IEXEC >> 3)) + ip->i_d.di_mode &= ~ISGID; + + libxfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; + + libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + libxfs_trans_commit(tp, 0, NULL); +} + +static int +newfile( + xfs_trans_t *tp, + xfs_inode_t *ip, + xfs_bmap_free_t *flist, + xfs_fsblock_t *first, + int dolocal, + int logit, + char *buf, + int len) +{ + xfs_buf_t *bp; + xfs_daddr_t d; + int error; + int flags; + xfs_bmbt_irec_t map; + xfs_mount_t *mp; + xfs_extlen_t nb; + int nmap; + + flags = 0; + mp = ip->i_mount; + if (dolocal && len <= XFS_IFORK_DSIZE(ip)) { + libxfs_idata_realloc(ip, len, XFS_DATA_FORK); + if (buf) + bcopy(buf, ip->i_df.if_u1.if_data, len); + ip->i_d.di_size = len; + ip->i_df.if_flags &= ~XFS_IFEXTENTS; + ip->i_df.if_flags |= XFS_IFINLINE; + ip->i_d.di_format = XFS_DINODE_FMT_LOCAL; + flags = XFS_ILOG_DDATA; + } else if (len > 0) { + nb = XFS_B_TO_FSB(mp, len); + nmap = 1; + error = libxfs_bmapi(tp, ip, 0, nb, XFS_BMAPI_WRITE, first, nb, + &map, &nmap, flist); + if (error) { + fail("error allocating space for a file", error); + } + if (nmap != 1) { + fprintf(stderr, "%s: cannot allocate space for file\n", + progname); + exit(1); + } + d = XFS_FSB_TO_DADDR(mp, map.br_startblock); + bp = libxfs_trans_get_buf(logit ? tp : 0, mp->m_dev, d, + nb << mp->m_blkbb_log, 0); + bcopy(buf, XFS_BUF_PTR(bp), len); + if (len < XFS_BUF_COUNT(bp)) + bzero(XFS_BUF_PTR(bp) + len, XFS_BUF_COUNT(bp) - len); + if (logit) + libxfs_trans_log_buf(tp, bp, 0, XFS_BUF_COUNT(bp) - 1); + else + libxfs_writebuf(bp, 1); + } + ip->i_d.di_size = len; + return flags; +} + +static char * +newregfile( + char **pp, + int *len) +{ + char *buf; + int fd; + char *fname; + long size; + + fname = getstr(pp); + if ((fd = open(fname, O_RDONLY)) < 0 || (size = filesize(fd)) < 0) { + fprintf(stderr, "%s: cannot open %s: %s\n", + progname, fname, strerror(errno)); + exit(1); + } + if ((*len = (int)size)) { + buf = malloc(size); + if (read(fd, buf, size) < size) { + fprintf(stderr, "%s: read failed on %s: %s\n", + progname, fname, strerror(errno)); + exit(1); + } + } else + buf = 0; + close(fd); + return buf; +} + +static void +newdirent( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_inode_t *pip, + char *name, + int namelen, + xfs_ino_t inum, + xfs_fsblock_t *first, + xfs_bmap_free_t *flist, + xfs_extlen_t total) +{ + int error; + + if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) + error = libxfs_dir2_createname(tp, pip, name, namelen, + inum, first, flist, total); + else + error = libxfs_dir_createname(tp, pip, name, namelen, + inum, first, flist, total); + if (error) + fail("directory createname error", error); +} + +static void +newdirectory( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_inode_t *dp, + xfs_inode_t *pdp) +{ + int error; + + if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) + error = libxfs_dir2_init(tp, dp, pdp); + else + error = libxfs_dir_init(tp, dp, pdp); + if (error) + fail("directory create error", error); +} + +void +parseproto( + xfs_mount_t *mp, + xfs_inode_t *pip, + char **pp, + char *name) +{ +#define IF_REGULAR 0 +#define IF_RESERVED 1 +#define IF_BLOCK 2 +#define IF_CHAR 3 +#define IF_DIRECTORY 4 +#define IF_SYMLINK 5 +#define IF_FIFO 6 + + char *buf; + int committed; + int error; + xfs_fsblock_t first; + int flags; + xfs_bmap_free_t flist; + int fmt; + int i; + xfs_inode_t *ip; + int len; + long long llen; + int majdev; + int mindev; + int mode; + char *mstr; + xfs_trans_t *tp; + int val; + int isroot = 0; + cred_t creds; + char *value; + + bzero(&creds, sizeof(creds)); + mstr = getstr(pp); + switch (mstr[0]) { + case '-': + fmt = IF_REGULAR; + break; + case 'r': + fmt = IF_RESERVED; + break; + case 'b': + fmt = IF_BLOCK; + break; + case 'c': + fmt = IF_CHAR; + break; + case 'd': + fmt = IF_DIRECTORY; + break; + case 'l': + fmt = IF_SYMLINK; + break; + case 'p': + fmt = IF_FIFO; + break; + default: + fprintf(stderr, "%s: bad format string %s\n", progname, mstr); + exit(1); + } + mode = 0; + switch (mstr[1]) { + case '-': + break; + case 'u': + mode |= ISUID; + break; + default: + fprintf(stderr, "%s: bad format string %s\n", progname, mstr); + exit(1); + } + switch (mstr[2]) { + case '-': + break; + case 'g': + mode |= ISGID; + break; + default: + fprintf(stderr, "%s: bad format string %s\n", progname, mstr); + exit(1); + } + val = 0; + for (i = 3; i < 6; i++) { + if (mstr[i] < '0' || mstr[i] > '7') { + fprintf(stderr, "%s: bad format string %s\n", + progname, mstr); + exit(1); + } + val = val * 8 + mstr[i] - '0'; + } + mode |= val; + creds.cr_uid = (int)getnum(pp); + creds.cr_gid = (int)getnum(pp); + tp = libxfs_trans_alloc(mp, 0); + flags = XFS_ILOG_CORE; + XFS_BMAP_INIT(&flist, &first); + switch (fmt) { + case IF_REGULAR: + buf = newregfile(pp, &len); + getres(tp, XFS_B_TO_FSB(mp, len)); + error = libxfs_inode_alloc(&tp, pip, mode|IFREG, 1, + mp->m_dev, &creds, &ip); + if (error) + fail("Inode allocation failed", error); + flags |= newfile(tp, ip, &flist, &first, 0, 0, buf, len); + if (buf) + free(buf); + libxfs_trans_ijoin(tp, pip, 0); + i = strlen(name); + newdirent(mp, tp, pip, name, i, ip->i_ino, &first, &flist, 1); + libxfs_trans_ihold(tp, pip); + break; + + case IF_RESERVED: /* pre-allocated space only */ + value = getstr(pp); + llen = cvtnum(mp->m_sb.sb_blocksize, value); + getres(tp, XFS_B_TO_FSB(mp, llen)); + + error = libxfs_inode_alloc(&tp, pip, mode|IFREG, 1, + mp->m_dev, &creds, &ip); + if (error) + fail("Inode pre-allocation failed", error); + + libxfs_trans_ijoin(tp, pip, 0); + + i = strlen(name); + newdirent(mp, tp, pip, name, i, ip->i_ino, &first, &flist, 1); + libxfs_trans_ihold(tp, pip); + libxfs_trans_log_inode(tp, ip, flags); + + error = libxfs_bmap_finish(&tp, &flist, first, &committed); + if (error) + fail("Pre-allocated file creation failed", error); + libxfs_trans_commit(tp, 0, NULL); + rsvfile(mp, ip, llen); + return; + + case IF_BLOCK: + getres(tp, 0); + majdev = (int)getnum(pp); + mindev = (int)getnum(pp); + error = libxfs_inode_alloc(&tp, pip, mode|IFBLK, 1, + makedev(majdev, mindev), &creds, &ip); + if (error) { + fail("Inode allocation failed", error); + } + libxfs_trans_ijoin(tp, pip, 0); + i = strlen(name); + newdirent(mp, tp, pip, name, i, ip->i_ino, &first, &flist, 1); + libxfs_trans_ihold(tp, pip); + flags |= XFS_ILOG_DEV; + break; + + case IF_CHAR: + getres(tp, 0); + majdev = (int)getnum(pp); + mindev = (int)getnum(pp); + error = libxfs_inode_alloc(&tp, pip, mode|IFCHR, 1, + makedev(majdev, mindev), &creds, &ip); + if (error) + fail("Inode allocation failed", error); + libxfs_trans_ijoin(tp, pip, 0); + i = strlen(name); + newdirent(mp, tp, pip, name, i, ip->i_ino, &first, &flist, 1); + libxfs_trans_ihold(tp, pip); + flags |= XFS_ILOG_DEV; + break; + + case IF_FIFO: + getres(tp, 0); + error = libxfs_inode_alloc(&tp, pip, mode|IFIFO, 1, + mp->m_dev, &creds, &ip); + if (error) + fail("Inode allocation failed", error); + libxfs_trans_ijoin(tp, pip, 0); + i = strlen(name); + newdirent(mp, tp, pip, name, i, ip->i_ino, &first, &flist, 1); + libxfs_trans_ihold(tp, pip); + break; + case IF_SYMLINK: + buf = getstr(pp); + len = (int)strlen(buf); + getres(tp, XFS_B_TO_FSB(mp, len)); + error = libxfs_inode_alloc(&tp, pip, mode|IFLNK, 1, + mp->m_dev, &creds, &ip); + if (error) + fail("Inode allocation failed", error); + flags |= newfile(tp, ip, &flist, &first, 1, 1, buf, len); + libxfs_trans_ijoin(tp, pip, 0); + i = strlen(name); + newdirent(mp, tp, pip, name, i, ip->i_ino, &first, &flist, 1); + libxfs_trans_ihold(tp, pip); + break; + case IF_DIRECTORY: + getres(tp, 0); + error = libxfs_inode_alloc(&tp, pip, mode|IFDIR, 1, + mp->m_dev, &creds, &ip); + if (error) + fail("Inode allocation failed", error); + ip->i_d.di_nlink++; /* account for . */ + if (!pip) { + pip = ip; + mp->m_sb.sb_rootino = ip->i_ino; + libxfs_mod_sb(tp, XFS_SB_ROOTINO); + mp->m_rootip = ip; + isroot = 1; + } else { + libxfs_trans_ijoin(tp, pip, 0); + i = strlen(name); + newdirent(mp, tp, pip, name, i, ip->i_ino, + &first, &flist, 1); + pip->i_d.di_nlink++; + libxfs_trans_ihold(tp, pip); + libxfs_trans_log_inode(tp, pip, XFS_ILOG_CORE); + } + newdirectory(mp, tp, ip, pip); + libxfs_trans_log_inode(tp, ip, flags); + error = libxfs_bmap_finish(&tp, &flist, first, &committed); + if (error) + fail("Directory creation failed", error); + libxfs_trans_ihold(tp, ip); + libxfs_trans_commit(tp, 0, NULL); + /* + * RT initialization. Do this here to ensure that + * the RT inodes get placed after the root inode. + */ + if (isroot) + rtinit(mp); + tp = NULL; + for (;;) { + name = getstr(pp); + if (strcmp(name, "$") == 0) + break; + parseproto(mp, ip, pp, name); + } + libxfs_iput(ip, 0); + return; + } + libxfs_trans_log_inode(tp, ip, flags); + error = libxfs_bmap_finish(&tp, &flist, first, &committed); + if (error) { + fail("Error encountered creating file from prototype", error); + } + libxfs_trans_commit(tp, 0, NULL); +} + +/* + * Allocate the realtime bitmap and summary inodes, and fill in data if any. + */ +static void +rtinit( + xfs_mount_t *mp) +{ + xfs_dfiloff_t bno; + int committed; + xfs_dfiloff_t ebno; + xfs_bmbt_irec_t *ep; + int error; + xfs_fsblock_t first; + xfs_bmap_free_t flist; + int i; + xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP]; + xfs_extlen_t nsumblocks; + int nmap; + xfs_inode_t *rbmip; + xfs_inode_t *rsumip; + xfs_trans_t *tp; + cred_t creds; + + /* + * First, allocate the inodes. + */ + tp = libxfs_trans_alloc(mp, 0); + if ((i = libxfs_trans_reserve(tp, MKFS_BLOCKRES_INODE, 0, 0, 0, 0))) + res_failed(i); + bzero(&creds, sizeof(creds)); + error = libxfs_inode_alloc(&tp, mp->m_rootip, IFREG, 1, + mp->m_dev, &creds, &rbmip); + if (error) { + fail("Realtime bitmap inode allocation failed", error); + } + /* + * Do our thing with rbmip before allocating rsumip, + * because the next call to ialloc() may + * commit the transaction in which rbmip was allocated. + */ + mp->m_sb.sb_rbmino = rbmip->i_ino; + rbmip->i_d.di_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize; + rbmip->i_d.di_flags = XFS_DIFLAG_NEWRTBM; + *(__uint64_t *)&rbmip->i_d.di_atime = 0; + libxfs_trans_log_inode(tp, rbmip, XFS_ILOG_CORE); + libxfs_mod_sb(tp, XFS_SB_RBMINO); + libxfs_trans_ihold(tp, rbmip); + mp->m_rbmip = rbmip; + error = libxfs_inode_alloc(&tp, mp->m_rootip, IFREG, 1, + mp->m_dev, &creds, &rsumip); + if (error) { + fail("Realtime bitmap inode allocation failed", error); + } + mp->m_sb.sb_rsumino = rsumip->i_ino; + rsumip->i_d.di_size = mp->m_rsumsize; + libxfs_trans_log_inode(tp, rsumip, XFS_ILOG_CORE); + libxfs_mod_sb(tp, XFS_SB_RSUMINO); + libxfs_trans_ihold(tp, rsumip); + libxfs_trans_commit(tp, 0, NULL); + mp->m_rsumip = rsumip; + /* + * Next, give the bitmap file some zero-filled blocks. + */ + tp = libxfs_trans_alloc(mp, 0); + if ((i = libxfs_trans_reserve(tp, mp->m_sb.sb_rbmblocks + + (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1), 0, 0, 0, 0))) + res_failed(i); + libxfs_trans_ijoin(tp, rbmip, 0); + bno = 0; + XFS_BMAP_INIT(&flist, &first); + while (bno < mp->m_sb.sb_rbmblocks) { + nmap = XFS_BMAP_MAX_NMAP; + error = libxfs_bmapi(tp, rbmip, bno, + (xfs_extlen_t)(mp->m_sb.sb_rbmblocks - bno), + XFS_BMAPI_WRITE, &first, mp->m_sb.sb_rbmblocks, + map, &nmap, &flist); + if (error) { + fail("Allocation of the realtime bitmap failed", error); + } + for (i = 0, ep = map; i < nmap; i++, ep++) { + libxfs_device_zero(mp->m_dev, + XFS_FSB_TO_DADDR(mp, ep->br_startblock), + XFS_FSB_TO_BB(mp, ep->br_blockcount)); + bno += ep->br_blockcount; + } + } + + error = libxfs_bmap_finish(&tp, &flist, first, &committed); + if (error) { + fail("Allocation of the realtime bitmap failed", error); + } + libxfs_trans_commit(tp, 0, NULL); + /* + * Give the summary file some zero-filled blocks. + */ + tp = libxfs_trans_alloc(mp, 0); + nsumblocks = mp->m_rsumsize >> mp->m_sb.sb_blocklog; + if ((i = libxfs_trans_reserve(tp, + nsumblocks + (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1), + 0, 0, 0, 0))) + res_failed(i); + libxfs_trans_ijoin(tp, rsumip, 0); + bno = 0; + XFS_BMAP_INIT(&flist, &first); + while (bno < nsumblocks) { + nmap = XFS_BMAP_MAX_NMAP; + error = libxfs_bmapi(tp, rsumip, bno, + (xfs_extlen_t)(nsumblocks - bno), + XFS_BMAPI_WRITE, &first, nsumblocks, + map, &nmap, &flist); + if (error) { + fail("Allocation of the realtime bitmap failed", error); + } + for (i = 0, ep = map; i < nmap; i++, ep++) { + libxfs_device_zero(mp->m_dev, + XFS_FSB_TO_DADDR(mp, ep->br_startblock), + XFS_FSB_TO_BB(mp, ep->br_blockcount)); + bno += ep->br_blockcount; + } + } + error = libxfs_bmap_finish(&tp, &flist, first, &committed); + if (error) { + fail("Allocation of the realtime bitmap failed", error); + } + libxfs_trans_commit(tp, 0, NULL); + /* + * Free the whole area using transactions. + * Do one transaction per bitmap block. + */ + for (bno = 0; bno < mp->m_sb.sb_rextents; bno = ebno) { + tp = libxfs_trans_alloc(mp, 0); + if ((i = libxfs_trans_reserve(tp, 0, 0, 0, 0, 0))) + res_failed(i); + XFS_BMAP_INIT(&flist, &first); + ebno = XFS_RTMIN(mp->m_sb.sb_rextents, + bno + NBBY * mp->m_sb.sb_blocksize); + error = libxfs_rtfree_extent(tp, bno, (xfs_extlen_t)(ebno-bno)); + if (error) { + fail("Error initializing the realtime bitmap", error); + } + error = libxfs_bmap_finish(&tp, &flist, first, &committed); + if (error) { + fail("Error initializing the realtime bitmap", error); + } + libxfs_trans_commit(tp, 0, NULL); + } +} + +void +res_failed( + int err) +{ + fprintf(stderr, "%s: ran out of disk space!\n", progname); + ASSERT(0); + exit(1); +} + +static long +filesize( + int fd) +{ + struct stat64 stb; + + if (fstat64(fd, &stb) < 0) + return -1; + return (long)stb.st_size; +} diff -rNu linux-2.4.7/cmd/xfsprogs/mkfs/proto.h linux-2.4-xfs/cmd/xfsprogs/mkfs/proto.h --- linux-2.4.7/cmd/xfsprogs/mkfs/proto.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfs/proto.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +char *setup_proto(char *fname); +void parseproto(xfs_mount_t *mp, xfs_inode_t *pip, char **pp, char *name); +void res_failed(int err); diff -rNu linux-2.4.7/cmd/xfsprogs/mkfs/volume.h linux-2.4-xfs/cmd/xfsprogs/mkfs/volume.h --- linux-2.4.7/cmd/xfsprogs/mkfs/volume.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfs/volume.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,66 @@ +#ifndef __SYS_VOLUME_H__ +#define __SYS_VOLUME_H__ + +/************************************************************************** + * * + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + * * + **************************************************************************/ + +/* + * Subvolume Types for all volume managers. + * + * There is a maximum of 255 subvolumes. 0 is reserved. + * Note: SVTYPE_LOG, SVTYPE_DATA, SVTYPE_RT values matches XLV. + * Do not change - Colin Ngam + */ +typedef enum sv_type_e { + SVTYPE_ALL =0, /* special: denotes all sv's */ + SVTYPE_LOG =1, /* XVM Log subvol type */ + SVTYPE_DATA, /* XVM Data subvol type */ + SVTYPE_RT, /* XVM Real Time subvol type */ + SVTYPE_SWAP, /* swap area */ + SVTYPE_RSVD5, /* reserved 5 */ + SVTYPE_RSVD6, /* reserved 6 */ + SVTYPE_RSVD7, /* reserved 7 */ + SVTYPE_RSVD8, /* reserved 8 */ + SVTYPE_RSVD9, /* reserved 9 */ + SVTYPE_RSVD10, /* reserved 10 */ + SVTYPE_RSVD11, /* reserved 11 */ + SVTYPE_RSVD12, /* reserved 12 */ + SVTYPE_RSVD13, /* reserved 13 */ + SVTYPE_RSVD14, /* reserved 14 */ + SVTYPE_RSVD15, /* reserved 15 */ + SVTYPE_USER1, /* First User Defined Subvol Type */ + SVTYPE_LAST =255 +} sv_type_t; + +#endif /* __SYS_VOLUME_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/mkfs/xfs_mkfs.c linux-2.4-xfs/cmd/xfsprogs/mkfs/xfs_mkfs.c --- linux-2.4.7/cmd/xfsprogs/mkfs/xfs_mkfs.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfs/xfs_mkfs.c Mon May 14 22:43:23 2001 @@ -0,0 +1,2182 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include "xfs_mkfs.h" +#include "proto.h" +#include "volume.h" +#include "maxtrres.h" +#include "mountinfo.h" + +#if HAVE_LIBLVM + #include "lvm_user.h" + + char *cmd; /* Not used. liblvm is broken */ + int opt_d; /* Same thing */ +#endif + +#include "md-int.h" + +/* + * Prototypes for internal functions. + */ +static void conflict(char opt, char *tab[], int oldidx, int newidx); +static void illegal(char *value, char *opt); +static void reqval(char opt, char *tab[], int idx); +static void respec(char opt, char *tab[], int idx); +static void unknown(char opt, char *s); +static int ispow2(unsigned int i); +static int max_trans_res(xfs_mount_t *mp); + +/* + * option tables for getsubopt calls + */ +char *bopts[] = { +#define B_LOG 0 + "log", +#define B_SIZE 1 + "size", + NULL +}; + +char *dopts[] = { +#define D_AGCOUNT 0 + "agcount", +#define D_FILE 1 + "file", +#define D_NAME 2 + "name", +#define D_SIZE 3 + "size", +#define D_SUNIT 4 + "sunit", +#define D_SWIDTH 5 + "swidth", +#define D_UNWRITTEN 6 + "unwritten", +#define D_AGSIZE 7 + "agsize", +#define D_SU 8 + "su", +#define D_SW 9 + "sw", + NULL +}; + +char *iopts[] = { +#define I_ALIGN 0 + "align", +#define I_LOG 1 + "log", +#define I_MAXPCT 2 + "maxpct", +#define I_PERBLOCK 3 + "perblock", +#define I_SIZE 4 + "size", + NULL +}; + +char *lopts[] = { +#define L_AGNUM 0 + "agnum", +#define L_INTERNAL 1 + "internal", +#define L_SIZE 2 + "size", +#define L_DEV 3 + "logdev", +#ifdef MKFS_SIMULATION +#define L_FILE 4 + "file", +#define L_NAME 5 + "name", +#endif + NULL +}; + +char *nopts[] = { +#define N_LOG 0 + "log", +#define N_SIZE 1 + "size", +#define N_VERSION 2 + "version", + NULL, +}; + +char *ropts[] = { +#define R_EXTSIZE 0 + "extsize", +#define R_SIZE 1 + "size", +#define R_DEV 2 + "rtdev", +#ifdef MKFS_SIMULATION +#define R_FILE 3 + "file", +#define R_NAME 4 + "name", +#endif + NULL +}; + +/* + * max transaction reservation values + * version 1: + * first dimension log(blocksize) (base XFS_MIN_BLOCKSIZE_LOG) + * second dimension log(inodesize) (base XFS_DINODE_MIN_LOG) + * version 2: + * first dimension log(blocksize) (base XFS_MIN_BLOCKSIZE_LOG) + * second dimension log(inodesize) (base XFS_DINODE_MIN_LOG) + * third dimension log(dirblocksize) (base XFS_MIN_BLOCKSIZE_LOG) + */ +#define DFL_B (XFS_MAX_BLOCKSIZE_LOG + 1 - XFS_MIN_BLOCKSIZE_LOG) +#define DFL_I (XFS_DINODE_MAX_LOG + 1 - XFS_DINODE_MIN_LOG) +#define DFL_D (XFS_MAX_BLOCKSIZE_LOG + 1 - XFS_MIN_BLOCKSIZE_LOG) + +static const int max_trres_v1[DFL_B][DFL_I] = { + { MAXTRRES_B9_I8_D9_V1, 0, 0, 0 }, + { MAXTRRES_B10_I8_D10_V1, MAXTRRES_B10_I9_D10_V1, 0, 0 }, + { MAXTRRES_B11_I8_D11_V1, MAXTRRES_B11_I9_D11_V1, + MAXTRRES_B11_I10_D11_V1, 0 }, + { MAXTRRES_B12_I8_D12_V1, MAXTRRES_B12_I9_D12_V1, + MAXTRRES_B12_I10_D12_V1, MAXTRRES_B12_I11_D12_V1 }, + { MAXTRRES_B13_I8_D13_V1, MAXTRRES_B13_I9_D13_V1, + MAXTRRES_B13_I10_D13_V1, MAXTRRES_B13_I11_D13_V1 }, + { MAXTRRES_B14_I8_D14_V1, MAXTRRES_B14_I9_D14_V1, + MAXTRRES_B14_I10_D14_V1, MAXTRRES_B14_I11_D14_V1 }, + { MAXTRRES_B15_I8_D15_V1, MAXTRRES_B15_I9_D15_V1, + MAXTRRES_B15_I10_D15_V1, MAXTRRES_B15_I11_D15_V1 }, + { MAXTRRES_B16_I8_D16_V1, MAXTRRES_B16_I9_D16_V1, + MAXTRRES_B16_I10_D16_V1, MAXTRRES_B16_I11_D16_V1 }, +}; + +static const int max_trres_v2[DFL_B][DFL_I][DFL_D] = { + { { MAXTRRES_B9_I8_D9_V2, MAXTRRES_B9_I8_D10_V2, MAXTRRES_B9_I8_D11_V2, + MAXTRRES_B9_I8_D12_V2, MAXTRRES_B9_I8_D13_V2, MAXTRRES_B9_I8_D14_V2, + MAXTRRES_B9_I8_D15_V2, MAXTRRES_B9_I8_D16_V2 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 } }, + { { 0, MAXTRRES_B10_I8_D10_V2, MAXTRRES_B10_I8_D11_V2, + MAXTRRES_B10_I8_D12_V2, MAXTRRES_B10_I8_D13_V2, + MAXTRRES_B10_I8_D14_V2, MAXTRRES_B10_I8_D15_V2, + MAXTRRES_B10_I8_D16_V2 }, + { 0, MAXTRRES_B10_I9_D10_V2, MAXTRRES_B10_I9_D11_V2, + MAXTRRES_B10_I9_D12_V2, MAXTRRES_B10_I9_D13_V2, + MAXTRRES_B10_I9_D14_V2, MAXTRRES_B10_I9_D15_V2, + MAXTRRES_B10_I9_D16_V2 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 } }, + { { 0, 0, MAXTRRES_B11_I8_D11_V2, MAXTRRES_B11_I8_D12_V2, + MAXTRRES_B11_I8_D13_V2, MAXTRRES_B11_I8_D14_V2, + MAXTRRES_B11_I8_D15_V2, MAXTRRES_B11_I8_D16_V2 }, + { 0, 0, MAXTRRES_B11_I9_D11_V2, MAXTRRES_B11_I9_D12_V2, + MAXTRRES_B11_I9_D13_V2, MAXTRRES_B11_I9_D14_V2, + MAXTRRES_B11_I9_D15_V2, MAXTRRES_B11_I9_D16_V2 }, + { 0, 0, MAXTRRES_B11_I10_D11_V2, MAXTRRES_B11_I10_D12_V2, + MAXTRRES_B11_I10_D13_V2, MAXTRRES_B11_I10_D14_V2, + MAXTRRES_B11_I10_D15_V2, MAXTRRES_B11_I10_D16_V2 }, + { 0, 0, 0, 0, 0, 0, 0, 0 } }, + { { 0, 0, 0, MAXTRRES_B12_I8_D12_V2, MAXTRRES_B12_I8_D13_V2, + MAXTRRES_B12_I8_D14_V2, MAXTRRES_B12_I8_D15_V2, + MAXTRRES_B12_I8_D16_V2 }, + { 0, 0, 0, MAXTRRES_B12_I9_D12_V2, MAXTRRES_B12_I9_D13_V2, + MAXTRRES_B12_I9_D14_V2, MAXTRRES_B12_I9_D15_V2, + MAXTRRES_B12_I9_D16_V2 }, + { 0, 0, 0, MAXTRRES_B12_I10_D12_V2, MAXTRRES_B12_I10_D13_V2, + MAXTRRES_B12_I10_D14_V2, MAXTRRES_B12_I10_D15_V2, + MAXTRRES_B12_I10_D16_V2 }, + { 0, 0, 0, MAXTRRES_B12_I11_D12_V2, MAXTRRES_B12_I11_D13_V2, + MAXTRRES_B12_I11_D14_V2, MAXTRRES_B12_I11_D15_V2, + MAXTRRES_B12_I11_D16_V2 } }, + { { 0, 0, 0, 0, MAXTRRES_B13_I8_D13_V2, MAXTRRES_B13_I8_D14_V2, + MAXTRRES_B13_I8_D15_V2, MAXTRRES_B13_I8_D16_V2 }, + { 0, 0, 0, 0, MAXTRRES_B13_I9_D13_V2, MAXTRRES_B13_I9_D14_V2, + MAXTRRES_B13_I9_D15_V2, MAXTRRES_B13_I9_D16_V2 }, + { 0, 0, 0, 0, MAXTRRES_B13_I10_D13_V2, MAXTRRES_B13_I10_D14_V2, + MAXTRRES_B13_I10_D15_V2, MAXTRRES_B13_I10_D16_V2 }, + { 0, 0, 0, 0, MAXTRRES_B13_I11_D13_V2, MAXTRRES_B13_I11_D14_V2, + MAXTRRES_B13_I11_D15_V2, MAXTRRES_B13_I11_D16_V2 } }, + { { 0, 0, 0, 0, 0, MAXTRRES_B14_I8_D14_V2, MAXTRRES_B14_I8_D15_V2, + MAXTRRES_B14_I8_D16_V2 }, + { 0, 0, 0, 0, 0, MAXTRRES_B14_I9_D14_V2, MAXTRRES_B14_I9_D15_V2, + MAXTRRES_B14_I9_D16_V2 }, + { 0, 0, 0, 0, 0, MAXTRRES_B14_I10_D14_V2, MAXTRRES_B14_I10_D15_V2, + MAXTRRES_B14_I10_D16_V2 }, + { 0, 0, 0, 0, 0, MAXTRRES_B14_I11_D14_V2, MAXTRRES_B14_I11_D15_V2, + MAXTRRES_B14_I11_D16_V2 } }, + { { 0, 0, 0, 0, 0, 0, MAXTRRES_B15_I8_D15_V2, MAXTRRES_B15_I8_D16_V2 }, + { 0, 0, 0, 0, 0, 0, MAXTRRES_B15_I9_D15_V2, MAXTRRES_B15_I9_D16_V2 }, + { 0, 0, 0, 0, 0, 0, MAXTRRES_B15_I10_D15_V2, + MAXTRRES_B15_I10_D16_V2 }, + { 0, 0, 0, 0, 0, 0, MAXTRRES_B15_I11_D15_V2, + MAXTRRES_B15_I11_D16_V2 } }, + { { 0, 0, 0, 0, 0, 0, 0, MAXTRRES_B16_I8_D16_V2 }, + { 0, 0, 0, 0, 0, 0, 0, MAXTRRES_B16_I9_D16_V2 }, + { 0, 0, 0, 0, 0, 0, 0, MAXTRRES_B16_I10_D16_V2 }, + { 0, 0, 0, 0, 0, 0, 0, MAXTRRES_B16_I11_D16_V2, } }, +}; + +/* + * Use this before we have a superblock, else would use XFS_DTOBT + */ +#define DTOBT(d) ((xfs_drfsbno_t)((d) >> (blocklog - BBSHIFT))) + +/* + * Use this for block reservations needed for mkfs's conditions + * (basically no fragmentation). + */ +#define MKFS_BLOCKRES_INODE \ + ((uint)(XFS_IALLOC_BLOCKS(mp) + (XFS_IN_MAXLEVELS(mp) - 1))) +#define MKFS_BLOCKRES(rb) \ + ((uint)(MKFS_BLOCKRES_INODE + XFS_DA_NODE_MAXDEPTH + \ + (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1) + (rb))) + +static void +get_subvol_stripe_wrapper(char *dfile, int type, int *sunit, int *swidth) +{ + struct stat64 sb; + struct md_array_info_s md; +#if HAVE_LIBLVM + lv_t *lv; + char *vgname; +#endif + + if (!dfile) + return; + + if (stat64 (dfile, &sb)) { + fprintf (stderr, "Could not stat %s\n", dfile); + usage(); + } + + /* MD volume */ + if (sb.st_rdev >> 8 == MD_MAJOR) { + int fd; + + /* Open device */ + fd = open (dfile, O_RDONLY); + if (fd == -1) + return; + + /* Is this thing on... */ + if (ioctl (fd, GET_ARRAY_INFO, &md)) { + fprintf (stderr, "Error getting array info from %s\n", + dfile); + usage(); + } + + /* Check state */ + if (md.state) { + fprintf (stderr, "MD array %s not in clean state\n", + dfile); + usage(); + } + + /* Deduct a disk from stripe width on RAID4/5 */ + if (md.level == 4 || md.level == 5) + md.nr_disks--; + + /* Update sizes */ + *sunit = md.chunk_size >> 9; + *swidth = *sunit * md.nr_disks; + + return; + } + +#if HAVE_LIBLVM + /* LVM volume */ + if (sb.st_rdev >> 8 == LVM_BLK_MAJOR) { + + /* Find volume group */ + if (! (vgname = vg_name_of_lv (dfile))) { + fprintf (stderr, "Can't find volume group for %s\n", + dfile); + usage(); + } + + /* Logical volume */ + if (! lvm_tab_lv_check_exist (dfile)) { + fprintf (stderr, "Logical volume %s doesn't exist!\n", + dfile); + usage(); + } + + /* Get status */ + if (lv_status_byname (vgname, dfile, &lv) < 0 || lv == NULL) { + fprintf (stderr, "Could not get status info from %s\n", + dfile); + usage(); + } + + /* Check that data is consistent */ + if (lv_check_consistency (lv) < 0) { + fprintf (stderr, "Logical volume %s is inconsistent\n", + dfile); + usage(); + } + + /* Update sizes */ + *sunit = lv->lv_stripesize; + *swidth = lv->lv_stripes * lv->lv_stripesize; + + return; + } +#endif /* HAVE_LIBLVM */ +} + + +static void +calc_stripe_factors(int dsu, int dsw, int *dsunit, int *dswidth) +{ + if (*dsunit || *dswidth) { + if (dsu || dsw) { + fprintf(stderr, + "su/sw should not be used in conjunction with sunit/swidth\n"); + usage(); + } + + if ((*dsunit && !*dswidth) || (!*dsunit && *dswidth)) { + fprintf(stderr, + "both sunit and swidth options have to be specified\n"); + usage(); + } + } + + if (dsu || dsw) { + if (*dsunit || *dswidth) { + fprintf(stderr, + "sunit/swidth should not be used in conjunction with su/sw\n"); + usage(); + } + + if ((dsu && !dsw) || (!dsu && dsw)) { + fprintf(stderr, + "both su and sw options have to be specified\n"); + usage(); + } + + if (dsu % BBSIZE) { + fprintf(stderr, "su must be a multiple of %d\n", + BBSIZE); + usage(); + } + + *dsunit = (int)BTOBBT(dsu); + *dswidth = *dsunit * dsw; + } + + if (*dsunit && (*dswidth % *dsunit != 0)) { + fprintf(stderr, + "stripe width (%d) has to be a multiple of the stripe unit (%d)\n", + *dswidth, *dsunit); + usage(); + } +} + +static int +get_default_blocksize(void) +{ + size_t pagesize = getpagesize(); + int i; + + /* default is between 4K and 16K */ + for (i = 12; i <= 16; i++) + if ((1 << i) == pagesize) + return pagesize; + return (1 << XFS_DFL_BLOCKSIZE_LOG); +} + + +int +main(int argc, char **argv) +{ + __uint64_t agcount; + xfs_agf_t *agf; + xfs_agi_t *agi; + xfs_agnumber_t agno; + __uint64_t agsize; + xfs_alloc_rec_t *arec; + xfs_btree_sblock_t *block; + int blflag; + int blocklog; + int blocksize; + int bsflag; + int bsize; + xfs_buf_t *buf; + int c; + int daflag; + int dasize; + xfs_drfsbno_t dblocks; + char *dfile; + int dirblocklog; + int dirblocksize; + int dirversion; + int do_overlap_checks; + char *dsize; + int dsu; + int dsw; + int dsunit; + int dswidth; + int extent_flagging; + int force_fs_overwrite; + int i; + int iaflag; + int ilflag; + int imaxpct; + int imflag; + int inodelog; + int inopblock; + int ipflag; + int isflag; + int isize; + char *label = NULL; + int laflag; + int lalign; + int ldflag; + int liflag; + xfs_agnumber_t logagno; + xfs_drfsbno_t logblocks; + char *logfile; + int loginternal; + char *logsize; + xfs_dfsbno_t logstart; + int lsflag; + int min_logblocks; + mnt_check_state_t *mnt_check_state; + int mnt_partition_count; + xfs_mount_t *mp; + xfs_mount_t mbuf; + xfs_extlen_t nbmblocks; + int nlflag; + int nodsflag; + xfs_alloc_rec_t *nrec; + int nsflag; + int nvflag; + char *p; + char *protofile; + char *protostring; + int qflag; + xfs_drfsbno_t rtblocks; + xfs_extlen_t rtextblocks; + xfs_drtbno_t rtextents; + char *rtextsize; + char *rtfile; + char *rtsize; + xfs_sb_t *sbp; + int sectlog; + __uint64_t tmp_agsize; + __uint64_t tmp_logblocks; + uuid_t uuid; + int worst_freelist; + libxfs_init_t xi; + int xlv_dsunit; + int xlv_dswidth; + + progname = basename(argv[0]); + agcount = 8; + blflag = bsflag = 0; + dasize = daflag = 0; + blocksize = get_default_blocksize(); + blocklog = libxfs_highbit32(blocksize); + agsize = daflag = dblocks = 0; + ilflag = imflag = ipflag = isflag = 0; + liflag = laflag = lsflag = ldflag = 0; + loginternal = 1; + logagno = logblocks = rtblocks = 0; + nlflag = nsflag = nvflag = 0; + dirblocklog = dirblocksize = dirversion = 0; + qflag = 0; + imaxpct = inodelog = inopblock = isize = 0; + iaflag = XFS_IFLAG_ALIGN; + bzero(&xi, sizeof(xi)); + xi.notvolok = 1; + xi.setblksize = 1; + dfile = logfile = rtfile = NULL; + dsize = logsize = rtsize = rtextsize = protofile = NULL; + opterr = 0; + dsu = dsw = dsunit = dswidth = nodsflag = lalign = 0; + do_overlap_checks = 1; + extent_flagging = 0; + force_fs_overwrite = 0; + worst_freelist = 0; + + while ((c = getopt(argc, argv, "b:d:i:l:L:n:p:qr:CfV")) != EOF) { + switch (c) { + case 'C': + do_overlap_checks = 0; + break; + case 'f': + force_fs_overwrite = 1; + break; + case 'b': + p = optarg; + while (*p != '\0') { + char *value; + + switch (getsubopt(&p, (constpp)bopts, &value)) { + case B_LOG: + if (!value) + reqval('b', bopts, B_LOG); + if (blflag) + respec('b', bopts, B_LOG); + if (bsflag) + conflict('b', bopts, B_SIZE, + B_LOG); + blocklog = atoi(value); + if (blocklog <= 0) + illegal(value, "b log"); + blocksize = 1 << blocklog; + blflag = 1; + break; + case B_SIZE: + if (!value) + reqval('b', bopts, B_SIZE); + if (bsflag) + respec('b', bopts, B_SIZE); + if (blflag) + conflict('b', bopts, B_LOG, + B_SIZE); + blocksize = cvtnum(0, value); + if (blocksize <= 0 || + !ispow2(blocksize)) + illegal(value, "b size"); + blocklog = libxfs_highbit32(blocksize); + bsflag = 1; + break; + default: + unknown('b', value); + } + } + break; + case 'd': + p = optarg; + while (*p != '\0') { + char *value; + + switch (getsubopt(&p, (constpp)dopts, &value)) { + case D_AGCOUNT: + if (!value) + reqval('d', dopts, D_AGCOUNT); + if (daflag) + respec('d', dopts, D_AGCOUNT); + agcount = (__uint64_t)atoll(value); + if ((__int64_t)agcount <= 0) + illegal(value, "d agcount"); + daflag = 1; + break; + case D_AGSIZE: + if (!value) + reqval('d', dopts, D_AGSIZE); + if (dasize) + respec('d', dopts, D_AGSIZE); + if (blflag || bsflag) + agsize = cvtnum(blocksize, + value); + else + agsize = cvtnum(0, value); + dasize = 1; + break; + case D_FILE: + if (!value) + value = "1"; + xi.disfile = atoi(value); + if (xi.disfile < 0 || xi.disfile > 1) + illegal(value, "d file"); + if (xi.disfile) + xi.dcreat = 1; + break; + case D_NAME: + if (!value) + reqval('d', dopts, D_NAME); + if (xi.dname) + respec('d', dopts, D_NAME); + xi.dname = value; + break; + case D_SIZE: + if (!value) + reqval('d', dopts, D_SIZE); + if (dsize) + respec('d', dopts, D_SIZE); + dsize = value; + break; + case D_SUNIT: + if (!value) + reqval('d', dopts, D_SUNIT); + if (dsunit) + respec('d', dopts, D_SUNIT); + if (blflag || bsflag) + dsunit = cvtnum(blocksize, + value); + else + dsunit = cvtnum(0, value); + break; + case D_SWIDTH: + if (!value) + reqval('d', dopts, D_SWIDTH); + if (dswidth) + respec('d', dopts, D_SWIDTH); + if (blflag || bsflag) + dswidth = cvtnum(blocksize, + value); + else + dswidth = cvtnum(0, value); + break; + case D_SU: + if (!value) + reqval('d', dopts, D_SU); + if (dsu) + respec('d', dopts, D_SU); + dsu = cvtnum(0, value); + break; + case D_SW: + if (!value) + reqval('d', dopts, D_SW); + if (dsw) + respec('d', dopts, D_SW); + dsw = cvtnum(0, value); + break; + case D_UNWRITTEN: + if (!value) + reqval('d', dopts, D_UNWRITTEN); + i = atoi(value); + if (i < 0 || i > 1) + illegal(value, "d unwritten"); + extent_flagging = i; + break; + default: + unknown('d', value); + } + } + break; + case 'i': + p = optarg; + while (*p != '\0') { + char *value; + + switch (getsubopt(&p, (constpp)iopts, &value)) { + case I_ALIGN: + if (!value) + value = "1"; + iaflag = atoi(value); + if (iaflag < 0 || iaflag > 1) + illegal(value, "i align"); + break; + case I_LOG: + if (!value) + reqval('i', iopts, I_LOG); + if (ilflag) + respec('i', iopts, I_LOG); + if (ipflag) + conflict('i', iopts, I_PERBLOCK, + I_LOG); + if (isflag) + conflict('i', iopts, I_SIZE, + I_LOG); + inodelog = atoi(value); + if (inodelog <= 0) + illegal(value, "i log"); + isize = 1 << inodelog; + ilflag = 1; + break; + case I_MAXPCT: + if (!value) + reqval('i', iopts, I_MAXPCT); + if (imflag) + respec('i', iopts, I_MAXPCT); + imaxpct = atoi(value); + if (imaxpct < 0 || imaxpct > 100) + illegal(value, "i maxpct"); + imflag = 1; + break; + case I_PERBLOCK: + if (!value) + reqval('i', iopts, I_PERBLOCK); + if (ilflag) + conflict('i', iopts, I_LOG, + I_PERBLOCK); + if (ipflag) + respec('i', iopts, I_PERBLOCK); + if (isflag) + conflict('i', iopts, I_SIZE, + I_PERBLOCK); + inopblock = atoi(value); + if (inopblock < + XFS_MIN_INODE_PERBLOCK || + !ispow2(inopblock)) + illegal(value, "i perblock"); + ipflag = 1; + break; + case I_SIZE: + if (!value) + reqval('i', iopts, I_SIZE); + if (ilflag) + conflict('i', iopts, I_LOG, + I_SIZE); + if (ipflag) + conflict('i', iopts, I_PERBLOCK, + I_SIZE); + if (isflag) + respec('i', iopts, I_SIZE); + isize = cvtnum(0, value); + if (isize <= 0 || !ispow2(isize)) + illegal(value, "i size"); + inodelog = libxfs_highbit32(isize); + isflag = 1; + break; + default: + unknown('i', value); + } + } + break; + case 'l': + p = optarg; + while (*p != '\0') { + char *value; + + switch (getsubopt(&p, (constpp)lopts, &value)) { + case L_AGNUM: + if (laflag) + respec('l', lopts, L_AGNUM); + + if (ldflag) + conflict('l', lopts, L_AGNUM, L_DEV); + + logagno = atoi(value); + laflag = 1; + break; + case L_DEV: + if (!value) { + fprintf (stderr, "Must specify log device\n"); + usage(); + } + + if (laflag) + conflict('l', lopts, L_AGNUM, L_DEV); + + if (liflag) + conflict('l', lopts, L_INTERNAL, L_DEV); + + ldflag = 1; + loginternal = 0; + logfile = value; + xi.logname = value; + break; +#ifdef HAVE_VOLUME_MANAGER + case L_FILE: + if (!value) + value = "1"; + if (loginternal) + conflict('l', lopts, L_INTERNAL, + L_FILE); + xi.lisfile = atoi(value); + if (xi.lisfile < 0 || xi.lisfile > 1) + illegal(value, "l file"); + if (xi.lisfile) + xi.lcreat = 1; + break; +#endif + case L_INTERNAL: + if (!value) + value = "1"; + + if (ldflag) + conflict('l', lopts, L_INTERNAL, L_DEV); +#ifdef HAVE_VOLUME_MANAGER + if (xi.logname) + conflict('l', lopts, L_NAME, + L_INTERNAL); + if (xi.lisfile) + conflict('l', lopts, L_FILE, + L_INTERNAL); +#endif + if (liflag) + respec('l', lopts, L_INTERNAL); + loginternal = atoi(value); + if (loginternal < 0 || loginternal > 1) + illegal(value, "l internal"); + liflag = 1; + break; +#ifdef HAVE_VOLUME_MANAGER + case L_NAME: + if (!value) + reqval('l', lopts, L_NAME); + if (loginternal) + conflict('l', lopts, L_INTERNAL, + L_NAME); + if (xi.logname) + respec('l', lopts, L_NAME); + xi.logname = value; + break; +#endif + case L_SIZE: + if (!value) + reqval('l', lopts, L_SIZE); + if (logsize) + respec('l', lopts, L_SIZE); + logsize = value; + lsflag = 1; + break; + default: + unknown('l', value); + } + } + break; + case 'L': + if (strlen(optarg) > sizeof(sbp->sb_fname)) + illegal(optarg, "L"); + label = optarg; + break; + case 'n': + p = optarg; + while (*p != '\0') { + char *value; + + switch (getsubopt(&p, (constpp)nopts, &value)) { + case N_LOG: + if (!value) + reqval('n', nopts, N_LOG); + if (nlflag) + respec('n', nopts, N_LOG); + if (nsflag) + conflict('n', nopts, N_SIZE, + N_LOG); + dirblocklog = atoi(value); + if (dirblocklog <= 0) + illegal(value, "n log"); + dirblocksize = 1 << dirblocklog; + nlflag = 1; + break; + case N_SIZE: + if (!value) + reqval('n', nopts, N_SIZE); + if (nsflag) + respec('n', nopts, N_SIZE); + if (nlflag) + conflict('n', nopts, N_LOG, + N_SIZE); + dirblocksize = cvtnum(0, value); + if (dirblocksize <= 0 || + !ispow2(dirblocksize)) + illegal(value, "n size"); + dirblocklog = + libxfs_highbit32(dirblocksize); + nsflag = 1; + break; + case N_VERSION: + if (!value) + reqval('n', nopts, N_VERSION); + if (nvflag) + respec('n', nopts, N_VERSION); + dirversion = atoi(value); + if (dirversion < 1 || dirversion > 2) + illegal(value, "n version"); + nvflag = 1; + break; + default: + unknown('n', value); + } + } + break; + case 'p': + if (protofile) + respec('p', 0, 0); + protofile = optarg; + break; + case 'q': + qflag = 1; + break; + case 'r': + p = optarg; + while (*p != '\0') { + char *value; + + switch (getsubopt(&p, (constpp)ropts, &value)) { + case R_EXTSIZE: + if (!value) + reqval('r', ropts, R_EXTSIZE); + if (rtextsize) + respec('r', ropts, R_EXTSIZE); + rtextsize = value; + break; + case R_DEV: + if (!value) + reqval('r', ropts, R_DEV); + xi.rtname = value; + break; +#ifdef HAVE_VOLUME_MANAGER + case R_FILE: + if (!value) + value = "1"; + xi.risfile = atoi(value); + if (xi.risfile < 0 || xi.risfile > 1) + illegal(value, "r file"); + if (xi.risfile) + xi.rcreat = 1; + break; + case R_NAME: + if (!value) + reqval('r', ropts, R_NAME); + if (xi.rtname) + respec('r', ropts, R_NAME); + xi.rtname = value; + break; +#endif + case R_SIZE: + if (!value) + reqval('r', ropts, R_SIZE); + if (rtsize) + respec('r', ropts, R_SIZE); + rtsize = value; + break; + + default: + unknown('r', value); + } + } + break; + case 'V': + printf("%s version %s\n", progname, VERSION); + break; + case '?': + unknown(optopt, ""); + } + } + if (argc - optind > 1) { + fprintf(stderr, "extra arguments\n"); + usage(); + } else if (argc - optind == 1) { + dfile = xi.volname = argv[optind]; + if (xi.dname) { + fprintf(stderr, + "cannot specify both %s and -d name=%s\n", + xi.volname, xi.dname); + usage(); + } + } else + dfile = xi.dname; + /* option post-processing */ + if (blocksize < XFS_MIN_BLOCKSIZE || blocksize > XFS_MAX_BLOCKSIZE) { + fprintf(stderr, "illegal block size %d\n", blocksize); + usage(); + } + if (!nvflag) + dirversion = (nsflag || nlflag) ? 2 : XFS_DFL_DIR_VERSION; + switch (dirversion) { + case 1: + if ((nsflag || nlflag) && dirblocklog != blocklog) { + fprintf(stderr, "illegal directory block size %d\n", + dirblocksize); + usage(); + } + break; + case 2: + if (nsflag || nlflag) { + if (dirblocksize < blocksize || + dirblocksize > XFS_MAX_BLOCKSIZE) { + fprintf(stderr, + "illegal directory block size %d\n", + dirblocksize); + usage(); + } + } else { + if (blocksize < (1 << XFS_MIN_REC_DIRSIZE)) + dirblocklog = XFS_MIN_REC_DIRSIZE; + else + dirblocklog = blocklog; + dirblocksize = 1 << dirblocklog; + } + break; + } + + if (daflag && dasize) { + fprintf(stderr, + "both -d agcount= and agsize= specified, use one or the other\n"); + usage(); + } + + if (!daflag) + agcount = 8; + + if (xi.disfile && (!dsize || !xi.dname)) { + fprintf(stderr, + "if -d file then -d name and -d size are required\n"); + usage(); + } + if (dsize) { + __uint64_t dbytes; + + dbytes = cvtnum(blocksize, dsize); + if (dbytes % XFS_MIN_BLOCKSIZE) { + fprintf(stderr, + "illegal data length %lld, not a multiple of %d\n", + (long long)dbytes, XFS_MIN_BLOCKSIZE); + usage(); + } + dblocks = (xfs_drfsbno_t)(dbytes >> blocklog); + if (dbytes % blocksize) + fprintf(stderr, + "warning: data length %lld not a multiple of %d, truncated to %lld\n", + (long long)dbytes, blocksize, + (long long)(dblocks << blocklog)); + } + if (ipflag) { + inodelog = blocklog - libxfs_highbit32(inopblock); + isize = 1 << inodelog; + } else if (!ilflag && !isflag) { + inodelog = XFS_DINODE_DFL_LOG; + isize = 1 << inodelog; + } +#ifdef HAVE_VOLUME_MANAGER + if (xi.lisfile && (!logsize || !xi.logname)) { + fprintf(stderr, + "if -l file then -l name and -l size are required\n"); + usage(); + } +#endif + if (logsize) { + __uint64_t logbytes; + + logbytes = cvtnum(blocksize, logsize); + if (logbytes % XFS_MIN_BLOCKSIZE) { + fprintf(stderr, + "illegal log length %lld, not a multiple of %d\n", + (long long)logbytes, XFS_MIN_BLOCKSIZE); + usage(); + } + logblocks = (xfs_drfsbno_t)(logbytes >> blocklog); + if (logbytes % blocksize) + fprintf(stderr, + "warning: log length %lld not a multiple of %d, truncated to %lld\n", + (long long)logbytes, blocksize, + (long long)(logblocks << blocklog)); + } +#ifdef HAVE_VOLUME_MANAGER + if (xi.risfile && (!rtsize || !xi.rtname)) { + fprintf(stderr, + "if -r file then -r name and -r size are required\n"); + usage(); + } +#endif + if (rtsize) { + __uint64_t rtbytes; + + rtbytes = cvtnum(blocksize, rtsize); + if (rtbytes % XFS_MIN_BLOCKSIZE) { + fprintf(stderr, + "illegal rt length %lld, not a multiple of %d\n", + (long long)rtbytes, XFS_MIN_BLOCKSIZE); + usage(); + } + rtblocks = (xfs_drfsbno_t)(rtbytes >> blocklog); + if (rtbytes % blocksize) + fprintf(stderr, + "warning: rt length %lld not a multiple of %d, truncated to %lld\n", + (long long)rtbytes, blocksize, + (long long)(rtblocks << blocklog)); + } + /* + * If specified, check rt extent size against its constraints. + */ + if (rtextsize) { + __uint64_t rtextbytes; + + rtextbytes = cvtnum(blocksize, rtextsize); + if (rtextbytes % blocksize) { + fprintf(stderr, + "illegal rt extent size %lld, not a multiple of %d\n", + (long long)rtextbytes, blocksize); + usage(); + } + if (rtextbytes > XFS_MAX_RTEXTSIZE) { + fprintf(stderr, + "rt extent size %s too large, maximum %d\n", + rtextsize, XFS_MAX_RTEXTSIZE); + usage(); + } + if (rtextbytes < XFS_MIN_RTEXTSIZE) { + fprintf(stderr, + "rt extent size %s too small, minimum %d\n", + rtextsize, XFS_MIN_RTEXTSIZE); + usage(); + } + rtextblocks = (xfs_extlen_t)(rtextbytes >> blocklog); + } else { + /* + * If realtime extsize has not been specified by the user, + * and the underlying volume is striped, then set rtextblocks + * to the stripe width. + */ + int dummy1, rswidth; + __uint64_t rtextbytes; + dummy1 = rswidth = 0; + + if (!xi.disfile) + get_subvol_stripe_wrapper(dfile, SVTYPE_RT, &dummy1, + &rswidth); + + /* check that rswidth is a multiple of fs blocksize */ + if (rswidth && !(BBTOB(rswidth) % blocksize)) { + rswidth = DTOBT(rswidth); + rtextbytes = rswidth << blocklog; + if (XFS_MIN_RTEXTSIZE <= rtextbytes && + (rtextbytes <= XFS_MAX_RTEXTSIZE)) { + rtextblocks = rswidth; + } else { + rtextblocks = XFS_DFL_RTEXTSIZE >> blocklog; + } + } else + rtextblocks = XFS_DFL_RTEXTSIZE >> blocklog; + } + + /* + * Check some argument sizes against mins, maxes. + */ + if (isize > blocksize / XFS_MIN_INODE_PERBLOCK || + isize < XFS_DINODE_MIN_SIZE || + isize > XFS_DINODE_MAX_SIZE) { + int maxsz; + + fprintf(stderr, "illegal inode size %d\n", isize); + maxsz = MIN(blocksize / XFS_MIN_INODE_PERBLOCK, + XFS_DINODE_MAX_SIZE); + if (XFS_DINODE_MIN_SIZE == maxsz) + fprintf(stderr, + "allowable inode size with %d byte blocks is %d\n", + blocksize, XFS_DINODE_MIN_SIZE); + else + fprintf(stderr, + "allowable inode size with %d byte blocks is between %d and %d\n", + blocksize, XFS_DINODE_MIN_SIZE, maxsz); + usage(); + } + + calc_stripe_factors(dsu, dsw, &dsunit, &dswidth); + + /* other global variables */ + sectlog = 9; /* i.e. 512 bytes */ + + /* + * Initialize. This will open the log and rt devices as well. + */ + if (!libxfs_init(&xi)) + usage(); + if (!xi.ddev) { + fprintf(stderr, "no device name given in argument list\n"); + usage(); + } + + /* + * Check whether this partition contains a known filesystem. + */ + + if (force_fs_overwrite == 0) { + char *fstyp; + int fsfound = 0; + + fstyp = (char *) mnt_known_fs_type (dfile); + + if (fstyp != NULL) { + fprintf(stderr, "%s: " + "%s appears to contain an existing filesystem (%s).\n", + progname, dfile, fstyp); + fsfound = 1; + } + + if (logfile && *logfile) { + fstyp = (char *) mnt_known_fs_type (logfile); + + if (fstyp != NULL) { + fprintf(stderr, "%s: " + "%s appears to contain an existing filesystem (%s).\n", + progname, logfile, fstyp); + fsfound = 1; + } + } + + if (xi.rtname && *xi.rtname) { + fstyp = (char *) mnt_known_fs_type (xi.rtname); + + if (fstyp != NULL) { + fprintf(stderr, "%s: " + "%s appears to contain an existing filesystem (%s).\n", + progname, xi.rtname, fstyp); + fsfound = 1; + } + } + + if (fsfound) { + fprintf(stderr, "%s: " + "Use the -f option to force overwrite\n", + progname); + exit(1); + } + } + + if (!xi.disfile && do_overlap_checks) { + /* + * do partition overlap check + * If this is a straight file we assume that it's been created + * before the call to mnt_check_init() + */ + + if (mnt_check_init(&mnt_check_state) == -1) { + fprintf(stderr, + "unable to initialize mount checking " + "routines, bypassing protection checks.\n"); + } else { + mnt_partition_count = mnt_find_mount_conflicts( + mnt_check_state, dfile); + + /* + * ignore -1 return codes, since 3rd party devices + * may not be part of hinv. + */ + if (mnt_partition_count > 0) { + if (mnt_causes_test(mnt_check_state, MNT_CAUSE_MOUNTED)) { + fprintf(stderr, "%s: " + "%s is already in use.\n", + progname, dfile); + } else if (mnt_causes_test(mnt_check_state, MNT_CAUSE_OVERLAP)) { + fprintf(stderr, "%s: " + "%s overlaps partition(s) " + "already in use.\n", + progname, dfile); + } else { + mnt_causes_show(mnt_check_state, stderr, progname); + } + fprintf(stderr, "\n"); + fflush(stderr); + mnt_plist_show(mnt_check_state, stderr, progname); + fprintf(stderr, "\n"); + } + mnt_check_end(mnt_check_state); + if (mnt_partition_count > 0) { + usage(); + } + } + } + + if (!liflag && !ldflag) + loginternal = xi.logdev == 0; + if (xi.logname) + logfile = xi.logname; + else if (loginternal) + logfile = "internal log"; + else if (xi.volname && xi.logdev) + logfile = "volume log"; + else if (!ldflag) { + fprintf(stderr, "no log subvolume or internal log\n"); + usage(); + } + if (xi.rtname) + rtfile = xi.rtname; + else + if (xi.volname && xi.rtdev) + rtfile = "volume rt"; + else if (!xi.rtdev) + rtfile = "none"; + if (dsize && xi.dsize > 0 && dblocks > DTOBT(xi.dsize)) { + fprintf(stderr, +"size %s specified for data subvolume is too large, maximum is %lld blocks\n", + dsize, (long long)DTOBT(xi.dsize)); + usage(); + } else if (!dsize && xi.dsize > 0) + dblocks = DTOBT(xi.dsize); + else if (!dsize) { + fprintf(stderr, "can't get size of data subvolume\n"); + usage(); + } + if (dblocks < XFS_MIN_DATA_BLOCKS) { + fprintf(stderr, + "size %lld of data subvolume is too small, minimum %d blocks\n", + (long long)dblocks, XFS_MIN_DATA_BLOCKS); + usage(); + } + if (xi.logdev && loginternal) { + fprintf(stderr, "can't have both external and internal logs\n"); + usage(); + } + if (dirversion == 1) + i = max_trres_v1[blocklog - XFS_MIN_BLOCKSIZE_LOG] + [inodelog - XFS_DINODE_MIN_LOG]; + else + i = max_trres_v2[blocklog - XFS_MIN_BLOCKSIZE_LOG] + [inodelog - XFS_DINODE_MIN_LOG] + [dirblocklog - XFS_MIN_BLOCKSIZE_LOG]; + min_logblocks = MAX(XFS_MIN_LOG_BLOCKS, i * XFS_MIN_LOG_FACTOR); + if (logsize && xi.logBBsize > 0 && logblocks > DTOBT(xi.logBBsize)) { + fprintf(stderr, +"size %s specified for log subvolume is too large, maximum is %lld blocks\n", + logsize, (long long)DTOBT(xi.logBBsize)); + usage(); + } else if (!logsize && xi.logBBsize > 0) + logblocks = DTOBT(xi.logBBsize); + else if (logsize && !xi.logdev && !loginternal) { + fprintf(stderr, + "size specified for non-existent log subvolume\n"); + usage(); + } else if (loginternal && logsize && logblocks >= dblocks) { + fprintf(stderr, "size %lld too large for internal log\n", + (long long)logblocks); + usage(); + } else if (!loginternal && !xi.logdev) + logblocks = 0; + else if (loginternal && !logsize) { + /* + * logblocks grows from min_logblocks to XFS_MAX_LOG_BLOCKS + * at 1TB + * + * 8192 = 1TB / MAX_LOG_BYTES + */ + logblocks = (dblocks << blocklog) / 8192; + logblocks = logblocks >> blocklog; + logblocks = MAX(min_logblocks, logblocks); + logblocks = MAX(logblocks, + MAX(XFS_DFL_LOG_SIZE, i * XFS_DFL_LOG_FACTOR)); + logblocks = MIN(logblocks, XFS_MAX_LOG_BLOCKS); + if ((logblocks << blocklog) > XFS_MAX_LOG_BYTES) { + logblocks = XFS_MAX_LOG_BYTES >> blocklog; + } + } + if (logblocks < min_logblocks) { + fprintf(stderr, + "log size %lld blocks too small, minimum size is %d blocks\n", + (long long)logblocks, min_logblocks); + usage(); + } + if (logblocks > XFS_MAX_LOG_BLOCKS) { + fprintf(stderr, + "log size %lld blocks too large, maximum size is %d blocks\n", + (long long)logblocks, XFS_MAX_LOG_BLOCKS); + usage(); + } + if ((logblocks << blocklog) > XFS_MAX_LOG_BYTES) { + fprintf(stderr, + "log size %lld bytes too large, maximum size is %d bytes\n", + (long long)(logblocks << blocklog), XFS_MAX_LOG_BYTES); + usage(); + } + if (rtsize && xi.rtsize > 0 && rtblocks > DTOBT(xi.rtsize)) { + fprintf(stderr, +"size %s specified for rt subvolume is too large, maximum is %lld blocks\n", + rtsize, (long long)DTOBT(xi.rtsize)); + usage(); + } else if (!rtsize && xi.rtsize > 0) + rtblocks = DTOBT(xi.rtsize); + else if (rtsize && !xi.rtdev) { + fprintf(stderr, + "size specified for non-existent rt subvolume\n"); + usage(); + } + if (xi.rtdev) { + rtextents = rtblocks / rtextblocks; + nbmblocks = (xfs_extlen_t)howmany(rtextents, NBBY * blocksize); + } else { + rtextents = rtblocks = 0; + nbmblocks = 0; + } + + if (dasize) { + /* + * If the specified agsize isn't a multiple of fs blks, + * complain. + */ + if (agsize % blocksize) { + fprintf(stderr, + "agsize (%lld) not a multiple of fs blk size (%d)\n", + (long long)agsize, blocksize); + usage(); + } + + agsize /= blocksize; + + /* + * If the specified agsize is too small, or too large, + * complain. + */ + if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) { + fprintf(stderr, + "agsize (%lldb) too small, need at least %lld blocks\n", + (long long)agsize, + (long long)XFS_AG_MIN_BLOCKS(blocklog)); + usage(); + } + + if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) { + fprintf(stderr, + "agsize (%lldb) too big, maximum is %lld blocks\n", + (long long)agsize, + (long long)XFS_AG_MAX_BLOCKS(blocklog)); + usage(); + } + + if (agsize > dblocks) { + fprintf(stderr, + "agsize (%lldb) too big, data area is %lld blocks\n", + (long long)agsize, (long long)dblocks); + usage(); + } + + agcount = dblocks / agsize + (dblocks % agsize != 0); + } else { + agsize = dblocks / agcount + (dblocks % agcount != 0); + } + + /* + * If the ag size is too small, complain if agcount/agsize was + * specified, and fix it otherwise. + */ + if (agsize < XFS_AG_MIN_BLOCKS(blocklog)) { + if (daflag || dasize) { + fprintf(stderr, + "too many allocation groups for size = %lld\n", + (long long)agsize); + fprintf(stderr, "need at most %lld allocation groups\n", + (long long) + (dblocks / XFS_AG_MIN_BLOCKS(blocklog) + + (dblocks % XFS_AG_MIN_BLOCKS(blocklog) != 0))); + usage(); + } + agsize = XFS_AG_MIN_BLOCKS(blocklog); + if (dblocks < agsize) + agcount = 1; + else + agcount = dblocks / agsize; + + agsize = dblocks / agcount + (dblocks % agcount != 0); + } + + /* + * If the ag size is too large, complain if agcount/agsize was + * specified, and fix it otherwise. + */ + else if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) { + if (daflag || dasize) { + fprintf(stderr, "too few allocation groups for size = %lld\n", + (long long)agsize); + fprintf(stderr, + "need at least %lld allocation groups\n", + (long long) + (dblocks / XFS_AG_MAX_BLOCKS(blocklog) + + (dblocks % XFS_AG_MAX_BLOCKS(blocklog) != 0))); + usage(); + } + agsize = XFS_AG_MAX_BLOCKS(blocklog); + agcount = dblocks / agsize + (dblocks % agsize != 0); + } + /* + * If agcount was not specified, and agsize is larger than + * we'd like, make it the size we want. + */ + if (!daflag && !dasize && + (agsize > XFS_AG_BEST_BLOCKS(blocklog, dblocks))) { + agsize = XFS_AG_BEST_BLOCKS(blocklog, dblocks); + agcount = dblocks / agsize + (dblocks % agsize != 0); + } + /* + * If agcount is too large, make it smaller. + */ + if (agcount > XFS_MAX_AGNUMBER + 1) { + agcount = XFS_MAX_AGNUMBER + 1; + agsize = dblocks / agcount + (dblocks % agcount != 0); + + if (dasize || daflag) + fprintf(stderr, + "agsize set to %lld, agcount %lld > max (%lld)\n", + (long long)agsize, (long long)agcount, + (long long)XFS_MAX_AGNUMBER+1); + + if (agsize > XFS_AG_MAX_BLOCKS(blocklog)) { + /* + * We're confused. + */ + fprintf(stderr, "%s: can't compute agsize/agcount\n", + progname); + exit(1); + } + } + + xlv_dsunit = xlv_dswidth = 0; + if (!xi.disfile) + get_subvol_stripe_wrapper(dfile, SVTYPE_DATA, &xlv_dsunit, + &xlv_dswidth); + if (dsunit) { + + if (xlv_dsunit && xlv_dsunit != dsunit) { + fprintf(stderr, "%s: " + "Specified data stripe unit %d is not the same as the xlv stripe unit %d\n", + progname, dsunit, xlv_dsunit); + exit(1); + } + if (xlv_dswidth && xlv_dswidth != dswidth) { + fprintf(stderr, "%s: " +"Specified data stripe width (%d) is not the same as the xlv stripe width (%d)\n", + progname, dswidth, xlv_dswidth); + exit(1); + } + } else { + dsunit = xlv_dsunit; + dswidth = xlv_dswidth; + nodsflag = 1; + } + + /* + * If dsunit is a multiple of fs blocksize, then check that is a + * multiple of the agsize too + */ + if (dsunit && !(BBTOB(dsunit) % blocksize) && + dswidth && !(BBTOB(dswidth) % blocksize)) { + + /* convert from 512 byte blocks to fs blocksize */ + dsunit = DTOBT(dsunit); + dswidth = DTOBT(dswidth); + + /* + * agsize is not a multiple of dsunit + */ + if ((agsize % dsunit) != 0) { + /* + * Round up to stripe unit boundary. Also make sure + * that agsize is still larger than + * XFS_AG_MIN_BLOCKS(blocklog) + */ + tmp_agsize = ((agsize + (dsunit - 1))/ dsunit) * dsunit; + /* + * Round down to stripe unit boundary if rounding up + * created an AG size that is larger than the AG max. + */ + if (tmp_agsize > XFS_AG_MAX_BLOCKS(blocklog)) + tmp_agsize = ((agsize) / dsunit) * dsunit; + if ((tmp_agsize >= XFS_AG_MIN_BLOCKS(blocklog)) && + (tmp_agsize <= XFS_AG_MAX_BLOCKS(blocklog)) && + !daflag) { + agsize = tmp_agsize; + agcount = dblocks/agsize + + (dblocks % agsize != 0); + if (dasize || daflag) + fprintf(stderr, + "agsize rounded to %lld, swidth = %d\n", + (long long)agsize, dswidth); + } else { + if (nodsflag) { + dsunit = dswidth = 0; + } else { + fprintf(stderr, +"Allocation group size %lld is not a multiple of the stripe unit %d\n", + (long long)agsize, dsunit); + exit(1); + } + } + } + } else { + if (nodsflag) + dsunit = dswidth = 0; + else { + fprintf(stderr, "%s: " +"Stripe unit(%d) or stripe width(%d) is not a multiple of the block size(%d)\n", + progname, dsunit, dswidth, blocksize); + exit(1); + } + } + + protostring = setup_proto(protofile); + bsize = 1 << (blocklog - BBSHIFT); + buf = libxfs_getbuf(xi.ddev, XFS_SB_DADDR, 1); + mp = &mbuf; + sbp = &mp->m_sb; + bzero(mp, sizeof(xfs_mount_t)); + sbp->sb_blocklog = (__uint8_t)blocklog; + sbp->sb_agblklog = (__uint8_t)libxfs_log2_roundup((unsigned int)agsize); + mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT; + if (loginternal) { + if (logblocks > agsize - XFS_PREALLOC_BLOCKS(mp)) { + fprintf(stderr, + "internal log size %lld too large, must fit in allocation group\n", + (long long)logblocks); + usage(); + } + if (laflag) { + if (logagno >= agcount) { + fprintf(stderr, + "log ag number %d too large, must be less than %lld\n", + logagno, (long long)agcount); + usage(); + } + } else + logagno = (xfs_agnumber_t)(agcount / 2); + + logstart = XFS_AGB_TO_FSB(mp, logagno, XFS_PREALLOC_BLOCKS(mp)); + /* + * Align the logstart at stripe unit boundary. + */ + if (dsunit && ((logstart % dsunit) != 0)) { + logstart = ((logstart + (dsunit - 1))/dsunit) * dsunit; + /* + * Make sure that the log size is a multiple of the + * stripe unit + */ + if ((logblocks % dsunit) != 0) { + if (!lsflag) { + tmp_logblocks = ((logblocks + (dsunit - 1)) + / dsunit) * dsunit; + /* + * If the log is too large, round down + * instead of round up + */ + if ((tmp_logblocks > XFS_MAX_LOG_BLOCKS) || + ((tmp_logblocks << blocklog) > XFS_MAX_LOG_BYTES)) { + tmp_logblocks = (logblocks / dsunit) * dsunit; + } + logblocks = tmp_logblocks; + } else { + fprintf(stderr, + "internal log size %lld is not a multiple of the stripe unit %d\n", + (long long)logblocks, dsunit); + usage(); + } + } + + if (logblocks > agsize-XFS_FSB_TO_AGBNO(mp,logstart)) { + fprintf(stderr, + "Due to stripe alignment, the internal log size %lld is too large.\n" + "Must fit in allocation group\n", + (long long)logblocks); + usage(); + } + lalign = 1; + } + } else + logstart = 0; + + if (label) + strncpy(sbp->sb_fname, label, sizeof(sbp->sb_fname)); + sbp->sb_magicnum = XFS_SB_MAGIC; + sbp->sb_blocksize = blocksize; + sbp->sb_dblocks = dblocks; + sbp->sb_rblocks = rtblocks; + sbp->sb_rextents = rtextents; + uuid_generate(uuid); + uuid_copy(sbp->sb_uuid, uuid); + sbp->sb_logstart = logstart; + sbp->sb_rootino = sbp->sb_rbmino = sbp->sb_rsumino = NULLFSINO; + sbp->sb_rextsize = rtextblocks; + sbp->sb_agblocks = (xfs_agblock_t)agsize; + sbp->sb_agcount = (xfs_agnumber_t)agcount; + sbp->sb_rbmblocks = nbmblocks; + sbp->sb_logblocks = (xfs_extlen_t)logblocks; + sbp->sb_sectsize = 1 << sectlog; + sbp->sb_inodesize = (__uint16_t)isize; + sbp->sb_inopblock = (__uint16_t)(blocksize / isize); + sbp->sb_sectlog = (__uint8_t)sectlog; + sbp->sb_inodelog = (__uint8_t)inodelog; + sbp->sb_inopblog = (__uint8_t)(blocklog - inodelog); + sbp->sb_rextslog = + (__uint8_t)(rtextents ? + libxfs_highbit32((unsigned int)rtextents) : 0); + sbp->sb_inprogress = 1; /* mkfs is in progress */ + sbp->sb_imax_pct = imflag ? imaxpct : XFS_DFL_IMAXIMUM_PCT; + sbp->sb_icount = 0; + sbp->sb_ifree = 0; + sbp->sb_fdblocks = dblocks - agcount * XFS_PREALLOC_BLOCKS(mp) - + (loginternal ? logblocks : 0); + sbp->sb_frextents = 0; /* will do a free later */ + sbp->sb_uquotino = sbp->sb_gquotino = 0; + sbp->sb_qflags = 0; + sbp->sb_unit = dsunit; + sbp->sb_width = dswidth; + if (dirversion == 2) + sbp->sb_dirblklog = dirblocklog - blocklog; + if (iaflag) { + sbp->sb_inoalignmt = XFS_INODE_BIG_CLUSTER_SIZE >> blocklog; + iaflag = sbp->sb_inoalignmt != 0; + } else + sbp->sb_inoalignmt = 0; + sbp->sb_versionnum = + XFS_SB_VERSION_MKFS(iaflag, dsunit != 0, extent_flagging, + dirversion == 2); + + bzero(XFS_BUF_PTR(buf), BBSIZE); + libxfs_xlate_sb(XFS_BUF_PTR(buf), sbp, -1, ARCH_CONVERT, + XFS_SB_ALL_BITS); + libxfs_writebuf(buf, 1); + + if (!qflag) + printf( + "meta-data=%-22s isize=%-6d agcount=%lld, agsize=%lld blks\n" + "data =%-22s bsize=%-6d blocks=%lld, imaxpct=%d\n" + " =%-22s sunit=%-6d swidth=%d blks, unwritten=%d\n" + "naming =version %-14d bsize=%-6d\n" + "log =%-22s bsize=%-6d blocks=%lld\n" + "realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n", + dfile, isize, (long long)agcount, (long long)agsize, + "", blocksize, (long long)dblocks, sbp->sb_imax_pct, + "", dsunit, dswidth, extent_flagging, + dirversion, dirversion == 1 ? blocksize : dirblocksize, + logfile, 1 << blocklog, (long long)logblocks, + rtfile, rtextblocks << blocklog, + (long long)rtblocks, (long long)rtextents); + /* + * If the data area is a file, then grow it out to its final size + * so that the reads for the end of the device in the mount code + * will succeed. + */ + if (xi.disfile && ftruncate64(xi.dfd, dblocks * blocksize) < 0) { + fprintf(stderr, "%s: Growing the data section file failed\n", + progname); + exit(1); + } + /* + * Zero the log if there is one. + */ + if (loginternal) + xi.logdev = xi.ddev; + if (xi.logdev) + libxfs_log_clear( + xi.logdev, + XFS_FSB_TO_DADDR(mp, logstart), + (xfs_extlen_t)XFS_FSB_TO_BB(mp, logblocks), + &sbp->sb_uuid, + XLOG_FMT); + + mp = libxfs_mount(mp, sbp, xi.ddev, xi.logdev, xi.rtdev, 1); + if (!mp) { + fprintf(stderr, "%s: mount initialization failed\n", progname); + exit(1); + } + if (xi.logdev && + XFS_FSB_TO_B(mp, logblocks) < + XFS_MIN_LOG_FACTOR * max_trans_res(mp)) { + fprintf(stderr, "%s: log size (%lld) is too small for " + "transaction reservations\n", + progname, (long long)logblocks); + exit(1); + } + + for (agno = 0; agno < agcount; agno++) { + /* + * Superblock. + */ + buf = libxfs_getbuf(xi.ddev, + XFS_AG_DADDR(mp, agno, XFS_SB_DADDR), 1); + bzero(XFS_BUF_PTR(buf), BBSIZE); + libxfs_xlate_sb(XFS_BUF_PTR(buf), sbp, -1, ARCH_CONVERT, + XFS_SB_ALL_BITS); + libxfs_writebuf(buf, 1); + + /* + * AG header block: freespace + */ + buf = libxfs_getbuf(mp->m_dev, + XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR), 1); + agf = XFS_BUF_TO_AGF(buf); + bzero(agf, BBSIZE); + if (agno == agcount - 1) + agsize = dblocks - (xfs_drfsbno_t)(agno * agsize); + INT_SET(agf->agf_magicnum, ARCH_CONVERT, XFS_AGF_MAGIC); + INT_SET(agf->agf_versionnum, ARCH_CONVERT, XFS_AGF_VERSION); + INT_SET(agf->agf_seqno, ARCH_CONVERT, agno); + INT_SET(agf->agf_length, ARCH_CONVERT, (xfs_agblock_t)agsize); + INT_SET(agf->agf_roots[XFS_BTNUM_BNOi], ARCH_CONVERT, + XFS_BNO_BLOCK(mp)); + INT_SET(agf->agf_roots[XFS_BTNUM_CNTi], ARCH_CONVERT, + XFS_CNT_BLOCK(mp)); + INT_SET(agf->agf_levels[XFS_BTNUM_BNOi], ARCH_CONVERT, 1); + INT_SET(agf->agf_levels[XFS_BTNUM_CNTi], ARCH_CONVERT, 1); + INT_SET(agf->agf_flfirst, ARCH_CONVERT, 0); + INT_SET(agf->agf_fllast, ARCH_CONVERT, XFS_AGFL_SIZE - 1); + INT_SET(agf->agf_flcount, ARCH_CONVERT, 0); + nbmblocks = (xfs_extlen_t)(agsize - XFS_PREALLOC_BLOCKS(mp)); + INT_SET(agf->agf_freeblks, ARCH_CONVERT, nbmblocks); + INT_SET(agf->agf_longest, ARCH_CONVERT, nbmblocks); + if (loginternal && agno == logagno) { + INT_MOD(agf->agf_freeblks, ARCH_CONVERT, -logblocks); + INT_SET(agf->agf_longest, ARCH_CONVERT, agsize - + XFS_FSB_TO_AGBNO(mp, logstart) - logblocks); + } + if (XFS_MIN_FREELIST(agf, mp) > worst_freelist) + worst_freelist = XFS_MIN_FREELIST(agf, mp); + libxfs_writebuf(buf, 1); + + /* + * AG header block: inodes + */ + buf = libxfs_getbuf(mp->m_dev, + XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR), 1); + agi = XFS_BUF_TO_AGI(buf); + bzero(agi, BBSIZE); + INT_SET(agi->agi_magicnum, ARCH_CONVERT, XFS_AGI_MAGIC); + INT_SET(agi->agi_versionnum, ARCH_CONVERT, XFS_AGI_VERSION); + INT_SET(agi->agi_seqno, ARCH_CONVERT, agno); + INT_SET(agi->agi_length, ARCH_CONVERT, (xfs_agblock_t)agsize); + INT_SET(agi->agi_count, ARCH_CONVERT, 0); + INT_SET(agi->agi_root, ARCH_CONVERT, XFS_IBT_BLOCK(mp)); + INT_SET(agi->agi_level, ARCH_CONVERT, 1); + INT_SET(agi->agi_freecount, ARCH_CONVERT, 0); + INT_SET(agi->agi_newino, ARCH_CONVERT, NULLAGINO); + INT_SET(agi->agi_dirino, ARCH_CONVERT, NULLAGINO); + for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) + INT_SET(agi->agi_unlinked[i], ARCH_CONVERT, NULLAGINO); + libxfs_writebuf(buf, 1); + + /* + * BNO btree root block + */ + buf = libxfs_getbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, agno, XFS_BNO_BLOCK(mp)), + bsize); + block = XFS_BUF_TO_SBLOCK(buf); + bzero(block, blocksize); + INT_SET(block->bb_magic, ARCH_CONVERT, XFS_ABTB_MAGIC); + INT_SET(block->bb_level, ARCH_CONVERT, 0); + INT_SET(block->bb_numrecs, ARCH_CONVERT, 1); + INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + arec = XFS_BTREE_REC_ADDR(blocksize, xfs_alloc, block, 1, + XFS_BTREE_BLOCK_MAXRECS(blocksize, xfs_alloc, 1)); + INT_SET(arec->ar_startblock, ARCH_CONVERT, + XFS_PREALLOC_BLOCKS(mp)); + if (loginternal && agno == logagno) { + if (lalign) { + /* + * Have to insert two records + */ + INT_SET(arec->ar_blockcount, ARCH_CONVERT, + (xfs_extlen_t)(XFS_FSB_TO_AGBNO( + mp, logstart) + - (INT_GET(arec->ar_startblock, + ARCH_CONVERT)))); + nrec = arec + 1; + INT_SET(nrec->ar_startblock, ARCH_CONVERT, + INT_GET(arec->ar_startblock, + ARCH_CONVERT) + + INT_GET(arec->ar_blockcount, + ARCH_CONVERT)); + arec = nrec; + INT_MOD(block->bb_numrecs, ARCH_CONVERT, 1); + } + INT_MOD(arec->ar_startblock, ARCH_CONVERT, logblocks); + } + INT_SET(arec->ar_blockcount, ARCH_CONVERT, + (xfs_extlen_t)(agsize - + INT_GET(arec->ar_startblock, ARCH_CONVERT))); + libxfs_writebuf(buf, 1); + + /* + * CNT btree root block + */ + buf = libxfs_getbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, agno, XFS_CNT_BLOCK(mp)), + bsize); + block = XFS_BUF_TO_SBLOCK(buf); + bzero(block, blocksize); + INT_SET(block->bb_magic, ARCH_CONVERT, XFS_ABTC_MAGIC); + INT_SET(block->bb_level, ARCH_CONVERT, 0); + INT_SET(block->bb_numrecs, ARCH_CONVERT, 1); + INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + arec = XFS_BTREE_REC_ADDR(blocksize, xfs_alloc, block, 1, + XFS_BTREE_BLOCK_MAXRECS(blocksize, xfs_alloc, 1)); + INT_SET(arec->ar_startblock, ARCH_CONVERT, + XFS_PREALLOC_BLOCKS(mp)); + if (loginternal && agno == logagno) { + if (lalign) { + INT_SET(arec->ar_blockcount, ARCH_CONVERT, + (xfs_extlen_t)( XFS_FSB_TO_AGBNO( + mp, logstart) - (INT_GET( + arec->ar_startblock, ARCH_CONVERT)) ) + ); + nrec = arec + 1; + INT_SET(nrec->ar_startblock, ARCH_CONVERT, + INT_GET(arec->ar_startblock, ARCH_CONVERT) + + INT_GET(arec->ar_blockcount, ARCH_CONVERT)); + arec = nrec; + INT_MOD(block->bb_numrecs, ARCH_CONVERT, 1); + } + INT_MOD(arec->ar_startblock, ARCH_CONVERT, logblocks); + } + INT_SET(arec->ar_blockcount, ARCH_CONVERT, (xfs_extlen_t) + (agsize - INT_GET(arec->ar_startblock, ARCH_CONVERT))); + libxfs_writebuf(buf, 1); + /* + * INO btree root block + */ + buf = libxfs_getbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, agno, XFS_IBT_BLOCK(mp)), + bsize); + block = XFS_BUF_TO_SBLOCK(buf); + bzero(block, blocksize); + INT_SET(block->bb_magic, ARCH_CONVERT, XFS_IBT_MAGIC); + INT_SET(block->bb_level, ARCH_CONVERT, 0); + INT_SET(block->bb_numrecs, ARCH_CONVERT, 0); + INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + libxfs_writebuf(buf, 1); + } + + /* + * Touch last block, make fs the right size if it's a file. + */ + buf = libxfs_getbuf(mp->m_dev, + (xfs_daddr_t)XFS_FSB_TO_BB(mp, dblocks - 1LL), bsize); + bzero(XFS_BUF_PTR(buf), blocksize); + libxfs_writebuf(buf, 1); + + /* + * Make sure we can write the last block in the realtime area. + */ + if (mp->m_rtdev && rtblocks > 0) { + buf = libxfs_getbuf(mp->m_rtdev, + XFS_FSB_TO_BB(mp, rtblocks - 1LL), bsize); + bzero(XFS_BUF_PTR(buf), blocksize); + libxfs_writebuf(buf, 1); + } + /* + * BNO, CNT free block list + */ + for (agno = 0; agno < agcount; agno++) { + xfs_alloc_arg_t args; + xfs_trans_t *tp; + + bzero(&args, sizeof(args)); + args.tp = tp = libxfs_trans_alloc(mp, 0); + args.mp = mp; + args.agno = agno; + args.alignment = 1; + args.minalignslop = UINT_MAX; + args.pag = &mp->m_perag[agno]; + if ((i = libxfs_trans_reserve(tp, worst_freelist, 0, 0, 0, 0))) + res_failed(i); + libxfs_alloc_fix_freelist(&args, 0); + libxfs_trans_commit(tp, 0, NULL); + } + /* + * Allocate the root inode and anything else in the proto file. + */ + mp->m_rootip = NULL; + parseproto(mp, NULL, &protostring, NULL); + + /* + * protect ourselves against possible stupidity + */ + if (XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino) != 0) { + fprintf(stderr, "%s: root inode not created in AG 0, " + "created in AG %u", + progname, XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino)); + exit(1); + } + + /* + * write out multiple copies of superblocks with the rootinode field set + */ + if (mp->m_sb.sb_agcount > 1) { + /* + * the last superblock + */ + buf = libxfs_readbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, mp->m_sb.sb_agcount-1, + XFS_SB_DADDR), + BTOBB(mp->m_sb.sb_sectsize), 1); + INT_SET((XFS_BUF_TO_SBP(buf))->sb_rootino, + ARCH_CONVERT, mp->m_sb.sb_rootino); + libxfs_writebuf(buf, 1); + /* + * and one in the middle for luck + */ + if (mp->m_sb.sb_agcount > 2) { + buf = libxfs_readbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, (mp->m_sb.sb_agcount-1)/2, + XFS_SB_DADDR), + BTOBB(mp->m_sb.sb_sectsize), 1); + INT_SET((XFS_BUF_TO_SBP(buf))->sb_rootino, + ARCH_CONVERT, mp->m_sb.sb_rootino); + libxfs_writebuf(buf, 1); + } + } + + /* + * Mark the filesystem ok. + */ + buf = libxfs_getsb(mp, 1); + (XFS_BUF_TO_SBP(buf))->sb_inprogress = 0; + libxfs_writebuf(buf, 1); + + libxfs_umount(mp); + if (xi.rtdev) + libxfs_device_close(xi.rtdev); + if (xi.logdev && xi.logdev != xi.ddev) + libxfs_device_close(xi.logdev); + libxfs_device_close(xi.ddev); + + return 0; +} + +static void +conflict( + char opt, + char *tab[], + int oldidx, + int newidx) +{ + fprintf(stderr, "Cannot specify both -%c %s and -%c %s\n", + opt, tab[oldidx], opt, tab[newidx]); + usage(); +} + + +static void +illegal( + char *value, + char *opt) +{ + fprintf(stderr, "Illegal value %s for -%s option\n", value, opt); + usage(); +} + +static int +ispow2( + unsigned int i) +{ + return (i & (i - 1)) == 0; +} + +static void +reqval( + char opt, + char *tab[], + int idx) +{ + fprintf(stderr, "-%c %s option requires a value\n", opt, tab[idx]); + usage(); +} + +static void +respec( + char opt, + char *tab[], + int idx) +{ + fprintf(stderr, "-%c ", opt); + if (tab) + fprintf(stderr, "%s ", tab[idx]); + fprintf(stderr, "option respecified\n"); + usage(); +} + +static void +unknown( + char opt, + char *s) +{ + fprintf(stderr, "unknown option -%c %s\n", opt, s); + usage(); +} + +static int +max_trans_res( + xfs_mount_t *mp) +{ + uint *p; + int rval; + xfs_trans_reservations_t *tr; + + tr = &mp->m_reservations; + + for (rval = 0, p = (uint *)tr; p < (uint *)(tr + 1); p++) { + if ((int)*p > rval) + rval = (int)*p; + } + return rval; +} + +long long +cvtnum( + int blocksize, + char *s) +{ + long long i; + char *sp; + extern void usage(void); + + i = strtoll(s, &sp, 0); + if (i == 0 && sp == s) + return -1LL; + if (*sp == '\0') + return i; + + if (*sp == 'b' && sp[1] == '\0') { + if (blocksize) + return i * blocksize; + + fprintf(stderr, "blocksize not available yet.\n"); + usage(); + } + + if (*sp == 'k' && sp[1] == '\0') + return 1024LL * i; + if (*sp == 'm' && sp[1] == '\0') + return 1024LL * 1024LL * i; + if (*sp == 'g' && sp[1] == '\0') + return 1024LL * 1024LL * 1024LL * i; + return -1LL; +} + +void +usage(void) +{ + fprintf(stderr, "Usage: %s\n\ +/* blocksize */ [-b log=n|size=num]\n\ +/* data subvol */ [-d agcount=n,agsize=n,file,name=xxx,size=num,\n\ + sunit=value,swidth=value,unwritten=0|1,\n\ + su=value,sw=value]\n\ +/* inode size */ [-i log=n|perblock=n|size=num,maxpct=n]\n\ +/* log subvol */ [-l agnum=n,internal,size=num,logdev=xxx]\n\ +/* naming */ [-n log=n|size=num|version=n]\n\ +/* label */ [-L label (maximum 12 characters)]\n\ +/* prototype file */ [-p fname]\n\ +/* quiet */ [-q]\n\ +/* version */ [-V]\n\ +/* realtime subvol */ [-r extsize=num,size=num,rtdev=xxx]\n\ + devicename\n\ + is required unless -d name=xxx is given.\n\ +Internal log by default, size is scaled from 1,000 blocks to 32,768 blocks\n\ +based on the filesystem size. Default log reaches its largest size at 1TB.\n\ +This can be overridden with the -l options or using a volume manager with a\n\ +log subvolume.\n\ + is xxx (bytes), or xxxb (blocks), or xxxk (xxx KB), or xxxm (xxx MB)\n\ + is xxx (512 blocks).\n", + progname); + exit(1); +} diff -rNu linux-2.4.7/cmd/xfsprogs/mkfs/xfs_mkfs.h linux-2.4-xfs/cmd/xfsprogs/mkfs/xfs_mkfs.h --- linux-2.4.7/cmd/xfsprogs/mkfs/xfs_mkfs.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/mkfs/xfs_mkfs.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_MKFS_H__ +#define __XFS_MKFS_H__ + +#define XFS_DFL_BLOCKSIZE_LOG 12 /* 4096 byte blocks */ +#define XFS_DINODE_DFL_LOG 8 /* 256 byte inodes */ +#define XFS_MIN_DATA_BLOCKS 100 +#define XFS_MIN_INODE_PERBLOCK 2 /* min inodes per block */ +#define XFS_DFL_IMAXIMUM_PCT 25 /* max % of space for inodes */ +#define XFS_IFLAG_ALIGN 1 /* -i align defaults on */ +#define XFS_MIN_REC_DIRSIZE 12 /* 4096 byte dirblocks (V2) */ +#define XFS_DFL_DIR_VERSION 2 /* default directory version */ +#define XFS_DFL_LOG_SIZE 1000 /* default log size, blocks */ +#define XFS_MIN_LOG_FACTOR 3 /* min log size factor */ +#define XFS_DFL_LOG_FACTOR 16 /* default log size, factor */ + /* with max trans reservation */ +extern void usage (void); +extern long long cvtnum (int blocksize, char *s); + +#endif /* __XFS_MKFS_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/repair/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/repair/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/repair/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/CVS/Entries Thu Jul 5 11:44:59 2001 @@ -0,0 +1,48 @@ +/Makefile/1.2/Mon Jan 15 06:52:52 2001/-ko/ +/README/1.1/Mon Jan 15 05:36:03 2001// +/agheader.c/1.2/Tue Apr 3 02:52:38 2001// +/agheader.h/1.1/Mon Jan 15 05:36:03 2001// +/attr_repair.c/1.4/Wed May 9 06:56:06 2001// +/attr_repair.h/1.2/Mon Jan 15 06:52:52 2001// +/avl.c/1.3/Thu Apr 12 23:49:04 2001// +/avl.h/1.1/Mon Jan 15 05:36:03 2001// +/avl64.c/1.3/Thu Apr 12 23:49:04 2001// +/avl64.h/1.1/Mon Jan 15 05:36:03 2001// +/bmap.c/1.1/Mon Jan 15 05:36:03 2001// +/bmap.h/1.1/Mon Jan 15 05:36:03 2001// +/dino_chunks.c/1.2/Thu Apr 12 23:49:04 2001// +/dinode.c/1.3/Mon Apr 9 07:41:10 2001// +/dinode.h/1.1/Mon Jan 15 05:36:03 2001// +/dir.c/1.3/Thu Apr 12 23:49:04 2001// +/dir.h/1.1/Mon Jan 15 05:36:03 2001// +/dir2.c/1.3/Thu Apr 12 23:49:04 2001// +/dir2.h/1.1/Mon Jan 15 05:36:03 2001// +/dir_stack.c/1.2/Thu Apr 12 23:49:04 2001// +/dir_stack.h/1.1/Mon Jan 15 05:36:03 2001// +/err_protos.h/1.1/Mon Jan 15 05:36:03 2001// +/globals.c/1.1/Mon Jan 15 05:36:03 2001// +/globals.h/1.2/Tue Apr 3 02:52:38 2001// +/incore.c/1.1/Mon Jan 15 05:36:03 2001// +/incore.h/1.1/Mon Jan 15 05:36:03 2001// +/incore_bmc.c/1.1/Mon Jan 15 05:36:03 2001// +/incore_ext.c/1.1/Mon Jan 15 05:36:03 2001// +/incore_ino.c/1.2/Mon Apr 9 07:41:10 2001// +/init.c/1.2/Fri Mar 9 05:38:39 2001// +/io.c/1.2/Wed May 9 06:56:06 2001// +/phase1.c/1.1/Mon Jan 15 05:36:03 2001// +/phase2.c/1.1/Mon Jan 15 05:36:03 2001// +/phase3.c/1.2/Thu Apr 12 23:49:04 2001// +/phase4.c/1.3/Thu Apr 12 23:49:04 2001// +/phase5.c/1.1/Mon Jan 15 05:36:03 2001// +/phase6.c/1.5/Wed May 9 06:56:06 2001// +/phase7.c/1.1/Mon Jan 15 05:36:03 2001// +/protos.h/1.1/Mon Jan 15 05:36:03 2001// +/rt.c/1.1/Mon Jan 15 05:36:03 2001// +/rt.h/1.1/Mon Jan 15 05:36:03 2001// +/sb.c/1.4/Wed May 9 06:56:06 2001// +/scan.c/1.2/Thu Apr 12 23:49:04 2001// +/scan.h/1.1/Mon Jan 15 05:36:03 2001// +/versions.c/1.2/Tue Apr 3 02:52:38 2001// +/versions.h/1.1/Mon Jan 15 05:36:03 2001// +/xfs_repair.c/1.2/Tue Apr 3 02:52:38 2001// +D diff -rNu linux-2.4.7/cmd/xfsprogs/repair/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/repair/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/repair/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/CVS/Repository Thu Jul 5 11:44:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/repair diff -rNu linux-2.4.7/cmd/xfsprogs/repair/CVS/Root linux-2.4-xfs/cmd/xfsprogs/repair/CVS/Root --- linux-2.4.7/cmd/xfsprogs/repair/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/CVS/Root Thu Jul 5 11:44:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/repair/Makefile linux-2.4-xfs/cmd/xfsprogs/repair/Makefile --- linux-2.4.7/cmd/xfsprogs/repair/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/Makefile Mon Jan 15 00:52:52 2001 @@ -0,0 +1,73 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = xfs_repair + +HFILES = agheader.h attr_repair.h avl.h avl64.h bmap.h dinode.h dir.h \ + dir2.h dir_stack.h err_protos.h globals.h incore.h protos.h rt.h \ + scan.h versions.h + +CFILES = agheader.c attr_repair.c avl.c avl64.c bmap.c dino_chunks.c \ + dinode.c dir.c dir2.c dir_stack.c globals.c incore.c \ + incore_bmc.c init.c incore_ext.c incore_ino.c io.c phase1.c \ + phase2.c phase3.c phase4.c phase5.c phase6.c phase7.c rt.c sb.c \ + scan.c versions.c xfs_repair.c + +LLDLIBS = $(LIBXFS) $(LIBUUID) +LLDFLAGS = -L$(TOPDIR)/libxfs + +default: $(CMDTARGET) + +include $(BUILDRULES) + +# +# Tracing flags: +# -DXR_BMAP_DBG incore block bitmap debugging +# -DXR_INODE_TRACE inode processing +# -DXR_BMAP_TRACE bmap btree processing +# -DXR_DIR_TRACE directory processing +# -DXR_DUP_TRACE duplicate extent processing +# -DXR_BCNT_TRACE incore bcnt freespace btree building +# -DXR_BLD_FREE_TRACE building on-disk freespace (bcnt/bno) btrees +# -DXR_BLD_INO_TRACE building on-disk inode allocation btrees +# -DXR_BLD_ADD_EXTENT track phase 5 block extent creation +# -DXR_BCKPTR_DBG parent list debugging info +# +CFLAGS += -DAVL_USER_MODE -DAVL_FUTURE_ENHANCEMENTS + +install: default + $(INSTALL) -m 755 -d $(PKG_SBIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_SBIN_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/xfsprogs/repair/README linux-2.4-xfs/cmd/xfsprogs/repair/README --- linux-2.4.7/cmd/xfsprogs/repair/README Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/README Sun Jan 14 23:36:03 2001 @@ -0,0 +1,718 @@ +A living document. The basic algorithm. + +TODO: (D == DONE) + +0) Need to bring some sanity into the case of flags that can + be set in the secondaries at mkfs time but reset or cleared + in the primary later in the filesystem's life. + +0) Clear the persistent read-only bit if set. Clear the + shared bit if set and the version number is zero. This + brings the filesystem back to a known state. + +0) make sure that superblock geometry code checks the logstart + value against whether or not we have an internal log. + If we have an internal log and a logdev, that's ok. + (Maybe we just aren't using it). If we have an external + log (logstart == 0) but no logdev, that's right out. + +0) write secondary superblock search code. Rewrite initial + superblock parsing code to be less complicated. Just + use variables to indicate primary, secondary, etc., + and use a function to get the SB given a specific location + or something. + +2) For inode alignment, if the SB bit is set and the + inode alignment size field in the SB is set, then + believe that the fs inodes MUST be aligned and + disallow any non-aligned inodes. Likewise, if + the SB bit isn't set (or earlier version) and + the inode alignment size field is zero, then + never set the bit even if the inodes are aligned. + Note that the bits and alignment values are + replicated in the secondary superblocks. + +0) add feature specification options to parse_arguments + +0) add logic to add_inode_ref(), add_inode_reached() + to detect nlink overflows in cases where the fs + (or user had indicated fs) doesn't support new nlinks. + +6) check to make sure that the inodes containing btree blocks + with # recs < minrecs aren't legit -- e.g. the only + descendant of a root block. + +7) inode di_size value sanity checking -- should always be less than + the biggest filebno offset mentioned in the bmaps. Doesn't + have to be equal though since we're allowed to overallocate + (it just wastes a little space). This is for both regular + files and directories (have to modify the existing directory + check). + + Add tracking of largest offset in bmap scanning code. Compare + value against di_size. Should be >= di_size. + + Alternatively, you could pass the inode into down through + the extent record processing layer and make the checks + there. + + Add knowledge of quota inodes. size of quota inode is + always zero. We should maintain that. + +8) Basic quota stuff. + + Invariants + if quota feature bit is set, the quota inodes + if set, should point to disconnected, 0 len inodes. + +D - if quota inodes exist, the quota bits must be + turned on. It's ok for the quota flags to be + zeroed but they should be in a legal state + (see xfs_quota.h). + +D - if the quota flags are non-zero, the corresponding + quota inodes must exist. + + quota inodes are never deleted, only their space + is freed. + + if quotas are being downgraded, then check quota inodes + at the end of phase 3. If they haven't been cleared yet, + clear them. Regardless, then clear sb flags (quota inode + fields, quota flags, and quota bit). + + +5) look at verify_inode_chunk(). it's probably really broken. + + +9) Complicated quota stuff. Add code to bmap scan code to + track used blocks. Add another pair of AVL trees + to track user and project quota limits. Set AVL + trees up at the beginning of phase 3. Quota inodes + can be rebuilt or corrected later if damaged. + + +D - 0) fix directory processing. phase 3, if an entry references + a free inode, *don't* mark it used. wait for the rest of + phase 3 processing to hit that inode. If it looks like it's + in use, we'll mark in use then. If not, we'll clear it and + mark the inode map. then in phase 4, you can depend on the + inode map. should probably set the parent info in phase 4. + So we have a check_dups flag. Maybe we should change the + name of check_dir to discover_inodes. During phase 3 + (discover_inodes == 1), uncertain inodes are added to list. + During phase 4 (discover_inodes == 0), they aren't. And + we never mark inodes in use from the directory code. + During phase 4, we shouldn't complain about names with + a leading '/' since we made those names in phase 3. + + Have to change dino_chunks.c (parent setting), dinode.c + and dir.c. + +D - 0) make sure we don't screw up filesystems with real-time inodes. + remember to initialize real-time map with all blocks XR_E_FREE. + +D - 4) check contents of symlinks as well as lengths in process_symlinks() + in dinode.c. Right now, we only check lengths. + + +D - 1) Feature mismatches -- for quotas and attributes, + if the stuff exists in the filesystem, set the + superblock version bits. + +D - 0) rewrite directory leaf block holemap comparison code. + probably should just check the leaf block hole info + against our incore bitmap. If the hole flag is not + set, then we know that there can only be one hole and + it has to be between the entry table and the top of heap. + If the hole flag is set, then it's ok if the on-disk + holemap doesn't describe everything as long as what + it does describe doesn't conflict with reality. + +D - 0) rewrite setting nlinks handling -- for version 1 + inodes, set both nlinks and onlinks (zero projid + and pad) if we have to change anything. For + version 2, I think we're ok. + +D - 0) Put awareness of quota inode into mark_standalone_inodes. + + +D - 8) redo handling of superblocks with bad version numbers. need + to bail out (without harming) fs's that have sbs that + are newer than we are. + +D - 0) How do we handle feature mismatches between fs and + superblock? For nlink, check each inode after you + know it's good. If onlinks is 0 and nlinks is > 0 + and it's a version 2 inode, then it really is a version + 2 inode and the nlinks flag in the SB needs to be set. + If it's a version 2 inode and the SB agrees but onlink + is non-zero, then clear onlink. + +D - 3) keep cumulative counts of freeblocks, inodes, etc. to set in + the superblock at the end of phase 5. Remember that + agf freeblock counters don't include blocks used by + the non-root levels of the freespace trees but that + the sb free block counters include those. + +D - 0) Do parent setting in directory code (called by phase 3). + actually, I put it in process_inode_set and propagated + the parent up to it from the process_dinode/process_dir + routines. seemed cleaner than pushing the irec down + and letting them bang on it. + +D - 0) If we clear a file in phase 4, make sure that if it's + a directory that the parent info is cleared also. + +D - 0) put inode tree flashover (call to add_ino_backptrs) into phase 5. + +D - 0) do set/get_inode_parent functions in incore_ino.c. + also do is/set/ inode_processed. + +D - 0) do a versions.c to extract feature info and set global vars + from the superblock version number and possibly feature bits + +D - 0) change longform_dir_entry_check + shortform_dir_entry_check + to return a count of how many illegal '/' entries exist. + if > 0, then process_dirstack needs to call prune_dir_entry + with a hash value of 0 to delete the entries. + +D - 0) add the "processed" bitfield + to the backptrs_t struct that gets attached after + phase 4. + +D- ) Phase 6 !!! + +D - 0) look at usage of XFS_MAKE_IPTR(). It does the right + arithmetic assuming you count your offsets from the + beginning of the buffer. + + +D - 0) look at references to XFS_INODES_PER_CHUNK. change the + ones that really mean sizeof(__uint64_t)*NBBY to + something else (like that only defined as a constant + INOS_PER_IREC. this isn't as important since + XFS_INODES_PER_CHUNK will never chang + + +D - 0) look at junk_zerolen_dir_leaf_entries() to make sure it isn't hosing + the freemap since it assumed that bytes between the + end of the table and firstused didn't show up in the + freemap when they actually do. + +D - 0) track down XFS_INO_TO_OFFSET() usage. I don't think I'm + using it right. (e.g. I think + it gives you the offset of an inode into a block but + on small block filesystems, I may be reading in inodes + in multiblock buffers and working from the start of + the buffer plus I'm using it to get offsets into + my ino_rec's which may not be a good idea since I + use 64-inode ino_rec's whereas the offset macro + works off blocksize). + +D - 0.0) put buffer -> dirblock conversion macros into xfs kernel code + +D - 0.2) put in sibling pointer checking and path fixup into + bmap (long form) scan routines in scan.c +D - 0.3) find out if bmap btrees with only root blocks are legal. I'm + betting that they're not because they'd be extent inodes + instead. If that's the case, rip some code out of + process_btinode() + + +Algorithm (XXX means not done yet): + +Phase 1 -- get a superblock and zero log + + get a superblock -- either read in primary or + find a secondary (ag header), check ag headers + + To find secondary: + + Go for brute force and read in the filesystem N meg + at a time looking for a superblock. as a + slight optimization, we could maybe skip + ahead some number of blocks to try and get + towards the end of the first ag. + + After you find a secondary, try and find at least + other ags as a verification that the + secondary is a good superblock. + +XXX - Ugh. Have to take growfs'ed filesystems into account. + The root superblock geometry info may not be right if + recovery hasn't run or it's been trashed. The old ag's + may or may not be right since the system could have crashed + during growfs or the bwrite() to the superblocks could have + failed and the buffer been reused. So we need to check + to see if another ag exists beyond the "last" ag + to see if a growfs happened. If not, then we know that + the geometry info is good and treat the fs as a non-growfs'ed + fs. If we do have inconsistencies, then the smaller geometry + is the old fs and the larger the new. We can check the + new superblocks to see if they're good. If not, then we + know the system crashed at or soon after the growfs and + we can choose to either accept the new geometry info or + trash it and truncate the fs back to the old geometry + parameters. + + Cross-check geometry information in secondary sb's with + primary to ensure that it's correct. + + Use sim code to allow mount filesystems *without* reading + in root inode. This sets up the xfs_mount_t structure + and allows us to use XFS_* macros that we wouldn't + otherwise be able to use. + + Note, I split phase 1 and 2 into separate pieces because I want + to initialize the xfs_repair incore data structures after phase 1. + + parse superblock version and feature flags and set appropriate + global vars to reflect the flags (attributes, quotas, etc.) + + Workaround for the mkfs "not zeroing the superblock buffer" bug. + Determine what field is the last valid non-zero field in + the superblock. The trick here is to be able to differentiate + the last valid non-zero field in the primary superblock and + secondaries because they may not be the same. Fields in + the primary can be set as the filesystem gets upgraded but + the upgrades won't touch the secondaries. This means that + we need to find some number of secondaries and check them. + So we do the checking here and the setting in phase2. + +Phase 2 -- check integrity of allocation group allocation structures + + zero the log if in no modify mode + + sanity check ag headers -- superblocks match, agi isn't + trashed -- the agf and agfl + don't really matter because we can + just recreate them later. + + Zero part of the superblock buffer if necessary + + Walk the freeblock trees to get an + initial idea of what the fs thinks is free. + Files that disagree (claim free'd blocks) + can be salvaged or deleted. If the btree is + internally inconsistent, when in doubt, mark + blocks free. If they're used, they'll be stolen + back later. don't have to check sibling pointers + for each level since we're going to regenerate + all the trees anyway. + Walk the inode allocation trees and + make sure they're ok, otherwise the sim + inode routines will probably just barf. + mark inode allocation tree blocks and ag header + blocks as used blocks. If the trees are + corrupted, this phase will generate "uncertain" + inode chunks. Those chunks go on a list and + will have to verified later. Record the blocks + that are used to detect corruption and multiply + claimed blocks. These trees will be regenerated + later. Mark the blocks containing inodes referenced + by uncorrupted inode trees as being used by inodes. + The other blocks will get marked when/if the inodes + are verified. + + calculate root and realtime inode numbers from the + filesystem geometry, fix up mount structure's + incore superblock if they're wrong. + +ASSUMPTION: at end of phase 2, we've got superblocks and ag headers + that are not garbage (some data in them like counters and the + freeblock and inode trees may be inconsistent but the header + is readable and otherwise makes sense). + +XXX if in no_modify mode, check for blocks claimed by one freespace + btree and not the other + +Phase 3 -- traverse inodes to make the inodes, bmaps and freespace maps + consistent. For each ag, use either the incore inode map or + scan the ag for inodes. + Let's use the incore inode map, now that we've made one + up in phase2. If we lose the maps, we'll locate inodes + when we traverse the directory heirarchy. If we lose both, + we could scan the disk. Ugh. Maybe make that a command-line + option that we support later. + + ASSUMPTION: we know if the ag allocation btrees are intact (phase 2) + + First - Walk and clear the ag unlinked lists. We'll process + the inodes later. Check and make sure that the unlinked + lists reference known inodes. If not, add to the list + of uncertain inodes. + + Second, check the uncertain inode list generated in phase2 and + above and get them into the inode tree if they're good. + The incore inode cluster tree *always* has good + clusters (alignment, etc.) in it. + + Third, make sure that the root inode is known. If not, + and we know the inode number from the superblock, + discover that inode and it's chunk. + + Then, walk the incore inode-cluster tree. + + Maintain an in-core bitmap over the entire fs for block allocation. + + traverse each inode, make sure inode mode field matches free/allocated + bit in the incore inode allocation tree. If there's a mismatch, + assume that the inode is in use. + + - for each in-use inode, traverse each bmap/dir/attribute + map or tree. Maintain a map (extent list?) for the + current inode. + + - For each block marked as used, check to see if already known + (referenced by another file or directory) and sanity + check the contents of the block as well if possible + (in the case of meta-blocks). + + - if the inode claims already used blocks, mark the blocks + as multiply claimed (duplicate) and go on. the inode + will be cleared in phase 4. + + - if metablocks are garbaged, clear the inode after + traversing what you can of the bmap and + proceed to next inode. We don't have to worry + about trashing the maps or trees in cleared inodes + because the blocks will show up as free in the + ag freespace trees that we set up in phase 5. + + - clear the di_next_unlinked pointer -- all unlinked + but active files go bye-bye. + + - All blocks start out unknown. We need the last state + in case we run into a case where we need to step + on a block to store filesystem meta-data and it + turns out later that it's referenced by some inode's + bmap. In that case, the inode loses because we've + already trashed the block. This shouldn't happen + in the first version unless some inode has a bogus + bmap referencing blocks in the ag header but the + 4th state will keep us from inadvertently doing + something stupid in that case. + + - If inode is allocated, mark all blocks allocated to the + current inode as allocated in the incore freespace + bitmap. + + - If inode is good and a directory, scan through it to + find leaf entries and discover any unknown inodes. + + For shortform, we correct what we can. + + If the directory is corrupt, we try and fix it in + place. If it has zero good entries, then we blast it. + + All unknown inodes get put onto the uncertain inode + list. This is safe because we only put inodes onto + the list when we're processing known inodes so the + uncertain inode list isn't in use. + + We fix only one problem -- an entry that has + a mathematically invalid inode numbers in them. + If that's the case, we replace the inode number + with NULLFSINO and we'll fix up the entry in + phase 6. + + That info may conflict with the inode information, + but we'll straighten out any inconsistencies there + in phase4 when we process the inodes again. + + Errors involving bogus forward/back links, + zero-length entries make the directory get + trashed. + + if an entry references a free inode, ignore that + fact for now. wait for the rest of phase 3 + processing to hit that inode. If it looks like it's + in use, we'll mark in use then. If not, we'll + clear it and mark the inode map. then in phase + 4, you can depend on the inode map. + + Entries that point to non-existent or free + inodes, and extra blocks in the directory + will get fixed in place in a later pass. + + Entries that point to a quota inode are + marked TBD. + + If the directory internally points to the same + block twice, the directory gets blown away. + + Note that processing uncertain inodes can add more inodes + to the uncertain list if they're directories. So we loop + until the uncertain list is empty. + + During inode verification, if the inode blocks are unknown, + mark then as in-use by inodes. + +XXX HEURISTIC -- if we blow an inode away that has space, + assume that the freespace btree is now out of wack. + If it was ok earlier, it's certain to be wrong now. + And the odds of this space free cancelling out the + existing error is so small I'm willing to ignore it. + Should probably do this via a global var and complain + about this later. + +Assumption: All known inodes are now marked as in-use or free. Any + inodes that we haven't found by now are hosed (lost) since + we can't reach them via either the inode btrees or via directory + entries. + + Directories are semi-clean. All '.' entries are good. + Root '..' entry is good if root inode exists. All entries + referencing non-existent inodes, free inodes, etc. + +XXX verify that either quota inode is 0 or NULLFSINO or + if sb quota flag is non zero, verify that quota inode + is NULLFSINO or is referencing a used, but disconnected + inode. + +XXX if in no_modify mode, check for unclaimed blocks + +- Phase 4 - Check for inodes referencing duplicate blocks + + At this point, all known duplicate blocks are marked in + the block map. However, some of the claimed blocks in + the bmap may in fact be free because they belong to inodes + that have to be cleared either due to being a trashed + directory or because it's the first inode to claim a + block that was then claimed later. There's a similar + problem with meta-data blocks that are referenced by + inode bmaps that are going to be freed once the inode + (or directory) gets cleared. + + So at this point, we collect the duplicate blocks into + extents and put them into the duplicate extent list. + + Mark the ag header blocks as in use. + + We then process each inode twice -- the first time + we check to see if the inode claims a duplicate extent + and we do NOT set the block bitmap. If the inode claims + a duplicate extent, we clear the inode. Since the bitmap + hasn't been set, that automatically frees all blocks associated + with the cleared inode. If the inode is ok, process it a second + time and set the bitmap since we know that this inode will live. + + The unlinked list gets cleared in every inode at this point as + well. We no longer need to preserve it since we've discovered + every inode we're going to find from it. + + verify existence of root inode. if it exists, check for + existence of "lost+found". If it exists, mark the entry + to be deleted, and clear the inode. All the inodes that + were connected to the lost+found will be reconnected later. + +XXX HEURISTIC -- if we blow an inode away that has space, + assume that the freespace btree is now out of wack. + If it was ok earlier, it's certain to be wrong now. + And the odds of this space free cancelling out the + existing error is so small I'm willing to ignore it. + Should probably do this via a global var and complain + about this later. + + Clear the quota inodes if the inode btree says that + they're not in use. The space freed will get picked + up by phase 5. + +XXX Clear the quota inodes if the filesystem is being downgraded. + +- Phase 5 - Build inode allocation trees, freespace trees and + agfl's for each ag. After this, we should be able to + unmount the filesystem and remount it for real. + + For each ag: (if no in no_modify mode) + + scan bitmap first to figure out number of extents. + + calculate space required for all trees. Start with inode trees. + Setup the btree cursor which includes the list of preallocated + blocks. As a by-product, this will delete the extents required + for the inode tree from the incore extent tree. + + Calculate how many extents will be required to represent the + remaining free extent tree on disk (twice, one for bybno and + one for bycnt). You have to iterate on this because consuming + extents can alter the number of blocks required to represent + the remaining extents. If there's slop left over, you can + put it in the agfl though. + + Then, manually build the trees, agi, agfs, and agfls. + +XXX if in no_modify mode, scan the on-disk inode allocation + trees and compare against the incore versions. Don't have + to scan the freespace trees because we caught the problems + there in phase2 and phase3. But if we cleared any inodes + with space during phases 3 or 4, now is the time to complain. + +XXX - Free duplicate extent lists. ??? + +Assumptions: at this point, sim code having to do with inode + creation/modification/deletion and space allocation + work because the inode maps, space maps, and bmaps + for all files in the filesystem are good. The only + structures that are screwed up are the directory contents, + which means that lookup may not work for beans, the + root inode which exists but may be completely bogus and + the link counts on all inodes which may also be bogus. + + Free the bitmap, the freespace tree. + + Flash the incore inode tree over from parent list to having + full backpointers. + + realtime processing, if any -- + + (Skip to below if running in no_modify mode). + + Generate the realtime bitmap from the incore realtime + extent map and slam the info into the realtime bitmap + inode. Generate summary info from the realtime extent map. + +XXX if in no_modify mode, compare contents of realtime bitmap + inode to the incore realtime extent map. generate the + summary info from the incore realtime extent map. + compare against the contents of the realtime summary inode. + complain if bad. + + reset superblock counters, sync version numbers + +- Phase 6 - directory traversal -- check reference counts, + attach disconnected inodes, fix up bogus directories + + Assumptions: all on-disk space and inode trees are structurally + sound. Incore and on-disk inode trees agree on whether + an inode is in use. + + Directories are structurally sound. All hashvalues + are monotonically increasing and interior nodes are + correct so lookups work. All legal directory entries + point to inodes that are in use and exist. Shortform + directories are fine except that the links haven't been + checked for conflicts (cycles, ".." being correct, etc.). + Longform directories haven't been checked for those problems + either PLUS longform directories may still contain + entries beginning with '/'. No zero-length entries + exist (they've been deleted or converted to '/'). + + Root directory may or may not exist. orphange may + or may not exist. Contents of either may be completely + bogus. + + Entries may point to free or non-existent inodes. + + At this we point, we may need new incore structures and + may be able to trash an old one (like the filesystem + block map) + + If '/' is trashed, then reinitialize it. + + If no realtime inodes, make them and if necessary, slam the + summary info into the realtime summary + inode. Ditto with the realtime bitmap inode. + + Make orphanage (lost+found ???). + + Traverse each directory from '/' (unless it was created). + Check directory structure and each directory entry. + If the entry is bogus (points to a non-existent or + free inode, for example), mark that entry TBD. Maintain + link counts on all inodes. Currently, traversal is + depth-first. + + Mark every inode reached as "reached" (includes + bumping up link counts). + + If a entry points to a directory but the parent (..) + disagrees, then blow away the entry. if the directory + being pointed to winds up disconnected, it'll be moved + to the orphanage (and the link count incremented to + account for the link and the reached bit set then). + + If an entry points to a directory that we've already + reached, then some entry is bad and should be blown + away. It's easiest to blow away the current entry + plus since presumably the parent entry in the + reached directory points to another directory, + then it's far more likely that the current + entry is bogus (otherwise the parent should point + at it). + + If an entry points to a non-existent of free inode, + blow the entry away. + + Every time a good entry is encountered update the + link count for the inode that the entry points to. + + After traversal, scan incore inode map for directories not + reached. Go to first one and try and find it's root + by following .. entries. Once at root, run traversal + algorithm. When algorithm terminates, move subtree + root inode to the orphanage. Repeat as necessary + until all disconnected directories are attached. + + Move all disconnected inodes to orphanage. + +- Phase 7: reset reference counts if required. + + Now traverse the on-disk inodes again, and make sure on-disk + reference counts are correct. Reset if necessary. + + SKIP all unused inodes -- that also makes us + skip the orphanage inode which we think is + unused but is really used. However, the ref counts + on that should be right so that's ok. + +--- + +multiple TB xfs_repair + +modify above to work in a couple of AGs at a time. The bitmaps +should span only the current set of AGs. + +The key it scan the inode bmaps and keep a list of inodes +that span multiple AG sets and keep the list in a data structure +that's keyed off AG set # as well as inode # and also has a bit +to indicate whether or not the inode will be cleared. + +Then in each AG set, when doing duplicate extent processing, +you have to process all multi-AG-set inodes that claim blocks in +the current AG set. If there's a conflict, you mark clear the +inode in the current AG and you mark the multi-AG inode as +"to be cleared". + +After going through all AGs, you can clear the to-be-cleared +multi-AG-set inodes and pull them off the list. + +When building up the AG freespace trees, you walk the bmaps +of all multi-AG-set inodes that are in the AG-set and include +blocks claimed in the AG by the inode as used. + +This probably involves adding a phase 3-0 which would have to +check all the inodes to see which ones are multi-AG-set inodes +and set up the multi-AG-set inode data structure. Plus the +process_dinode routines may have to be altered just a bit +to do the right thing if running in tera-byte mode (call +out to routines that check the multi-AG-set inodes when +appropriate). + +To make things go faster, phase 3-0 could probably run +in parallel. It should be possible to run phases 2-5 +in parallel as well once the appropriate synchronization +is added to the incore routines and the static directory +leaf block bitmap is changed to be on the stack. + +Phase 7 probably can be in parallel as well. + +By in parallel, I mean that assuming that an AG-set +contains 4 AGs, you could run 4 threads, 1 per AG +in parallel to process the AG set. + +I don't see how phase 6 can be run in parallel though. + +And running Phase 8 in parallel is just silly. + diff -rNu linux-2.4.7/cmd/xfsprogs/repair/agheader.c linux-2.4-xfs/cmd/xfsprogs/repair/agheader.c --- linux-2.4.7/cmd/xfsprogs/repair/agheader.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/agheader.c Mon Apr 2 21:52:38 2001 @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "globals.h" +#include "agheader.h" +#include "protos.h" +#include "err_protos.h" + +int +verify_set_agf(xfs_mount_t *mp, xfs_agf_t *agf, xfs_agnumber_t i) +{ + xfs_drfsbno_t agblocks; + int retval = 0; + + /* check common fields */ + + if (INT_GET(agf->agf_magicnum, ARCH_CONVERT) != XFS_AGF_MAGIC) { + retval = XR_AG_AGF; + do_warn("bad magic # 0x%x for agf %d\n", INT_GET(agf->agf_magicnum, ARCH_CONVERT), i); + + if (!no_modify) + INT_SET(agf->agf_magicnum, ARCH_CONVERT, XFS_AGF_MAGIC); + } + + if (!XFS_AGF_GOOD_VERSION(INT_GET(agf->agf_versionnum, ARCH_CONVERT))) { + retval = XR_AG_AGF; + do_warn("bad version # %d for agf %d\n", + INT_GET(agf->agf_versionnum, ARCH_CONVERT), i); + + if (!no_modify) + INT_SET(agf->agf_versionnum, ARCH_CONVERT, XFS_AGF_VERSION); + } + + if (INT_GET(agf->agf_seqno, ARCH_CONVERT) != i) { + retval = XR_AG_AGF; + do_warn("bad sequence # %d for agf %d\n", INT_GET(agf->agf_seqno, ARCH_CONVERT), i); + + if (!no_modify) + INT_SET(agf->agf_seqno, ARCH_CONVERT, i); + } + + if (INT_GET(agf->agf_length, ARCH_CONVERT) != mp->m_sb.sb_agblocks) { + if (i != mp->m_sb.sb_agcount - 1) { + retval = XR_AG_AGF; + do_warn("bad length %d for agf %d, should be %d\n", + INT_GET(agf->agf_length, ARCH_CONVERT), i, mp->m_sb.sb_agblocks); + if (!no_modify) + INT_SET(agf->agf_length, ARCH_CONVERT, mp->m_sb.sb_agblocks); + } else { + agblocks = mp->m_sb.sb_dblocks - + (xfs_drfsbno_t) mp->m_sb.sb_agblocks * i; + + if (INT_GET(agf->agf_length, ARCH_CONVERT) != agblocks) { + retval = XR_AG_AGF; + do_warn( + "bad length %d for agf %d, should be %llu\n", + INT_GET(agf->agf_length, ARCH_CONVERT), i, agblocks); + if (!no_modify) + INT_SET(agf->agf_length, ARCH_CONVERT, (xfs_agblock_t) agblocks); + } + } + } + + /* + * check first/last AGF fields. if need be, lose the free + * space in the AGFL, we'll reclaim it later. + */ + if (INT_GET(agf->agf_flfirst, ARCH_CONVERT) >= XFS_AGFL_SIZE) { + do_warn("flfirst %d in agf %d too large (max = %d)\n", + INT_GET(agf->agf_flfirst, ARCH_CONVERT), i, XFS_AGFL_SIZE); + if (!no_modify) + INT_ZERO(agf->agf_flfirst, ARCH_CONVERT); + } + + if (INT_GET(agf->agf_fllast, ARCH_CONVERT) >= XFS_AGFL_SIZE) { + do_warn("fllast %d in agf %d too large (max = %d)\n", + INT_GET(agf->agf_fllast, ARCH_CONVERT), i, XFS_AGFL_SIZE); + if (!no_modify) + INT_ZERO(agf->agf_fllast, ARCH_CONVERT); + } + + /* don't check freespace btrees -- will be checked by caller */ + + return(retval); +} + +int +verify_set_agi(xfs_mount_t *mp, xfs_agi_t *agi, xfs_agnumber_t i) +{ + xfs_drfsbno_t agblocks; + int retval = 0; + + /* check common fields */ + + if (INT_GET(agi->agi_magicnum, ARCH_CONVERT) != XFS_AGI_MAGIC) { + retval = XR_AG_AGI; + do_warn("bad magic # 0x%x for agi %d\n", INT_GET(agi->agi_magicnum, ARCH_CONVERT), i); + + if (!no_modify) + INT_SET(agi->agi_magicnum, ARCH_CONVERT, XFS_AGI_MAGIC); + } + + if (!XFS_AGI_GOOD_VERSION(INT_GET(agi->agi_versionnum, ARCH_CONVERT))) { + retval = XR_AG_AGI; + do_warn("bad version # %d for agi %d\n", + INT_GET(agi->agi_versionnum, ARCH_CONVERT), i); + + if (!no_modify) + INT_SET(agi->agi_versionnum, ARCH_CONVERT, XFS_AGI_VERSION); + } + + if (INT_GET(agi->agi_seqno, ARCH_CONVERT) != i) { + retval = XR_AG_AGI; + do_warn("bad sequence # %d for agi %d\n", INT_GET(agi->agi_seqno, ARCH_CONVERT), i); + + if (!no_modify) + INT_SET(agi->agi_seqno, ARCH_CONVERT, i); + } + + if (INT_GET(agi->agi_length, ARCH_CONVERT) != mp->m_sb.sb_agblocks) { + if (i != mp->m_sb.sb_agcount - 1) { + retval = XR_AG_AGI; + do_warn("bad length # %d for agi %d, should be %d\n", + INT_GET(agi->agi_length, ARCH_CONVERT), i, mp->m_sb.sb_agblocks); + if (!no_modify) + INT_SET(agi->agi_length, ARCH_CONVERT, mp->m_sb.sb_agblocks); + } else { + agblocks = mp->m_sb.sb_dblocks - + (xfs_drfsbno_t) mp->m_sb.sb_agblocks * i; + + if (INT_GET(agi->agi_length, ARCH_CONVERT) != agblocks) { + retval = XR_AG_AGI; + do_warn( + "bad length # %d for agi %d, should be %llu\n", + INT_GET(agi->agi_length, ARCH_CONVERT), i, agblocks); + if (!no_modify) + INT_SET(agi->agi_length, ARCH_CONVERT, (xfs_agblock_t) agblocks); + } + } + } + + /* don't check inode btree -- will be checked by caller */ + + return(retval); +} + +/* + * superblock comparison - compare arbitrary superblock with + * filesystem mount-point superblock + * + * the verified fields include id and geometry. + + * the inprogress fields, version numbers, and counters + * are allowed to differ as well as all fields after the + * counters to cope with the pre-6.5 mkfs non-bzeroed + * secondary superblock sectors. + */ + +int +compare_sb(xfs_mount_t *mp, xfs_sb_t *sb) +{ + fs_geometry_t fs_geo, sb_geo; + + get_sb_geometry(&fs_geo, &mp->m_sb); + get_sb_geometry(&sb_geo, sb); + + if (memcmp(&fs_geo, &sb_geo, + (char *) &fs_geo.sb_shared_vn - (char *) &fs_geo)) + return(XR_SB_GEO_MISMATCH); + + return(XR_OK); +} + +/* + * possible fields that may have been set at mkfs time, + * sb_inoalignmt, sb_unit, sb_width. We know that + * the quota inode fields in the secondaries should be zero. + * Likewise, the sb_flags and sb_shared_vn should also be + * zero and the shared version bit should be cleared for + * current mkfs's. + * + * And everything else in the buffer beyond sb_width should + * be zeroed. + */ +int +secondary_sb_wack(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb, + xfs_agnumber_t i) +{ + int do_bzero; + int size; + int *ip; + int rval; + + rval = do_bzero = 0; + + /* + * mkfs's that stamped a feature bit besides the ones in the mask + * (e.g. were pre-6.5 beta) could leave garbage in the secondary + * superblock sectors. Anything stamping the shared fs bit or better + * into the secondaries is ok and should generate clean secondary + * superblock sectors. so only run the bzero check on the + * potentially garbaged secondaries. + */ + if (pre_65_beta || + (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK) == 0 || + sb->sb_versionnum < XFS_SB_VERSION_4) { + /* + * check for garbage beyond the last field set by the + * pre-6.5 mkfs's. Don't blindly use sizeof(sb). + * Use field addresses instead so this code will still + * work against older filesystems when the superblock + * gets rev'ed again with new fields appended. + */ + size = (__psint_t)&sb->sb_width + sizeof(sb->sb_width) + - (__psint_t)sb; + for (ip = (int *)((__psint_t)sb + size); + ip < (int *)((__psint_t)sb + mp->m_sb.sb_sectsize); + ip++) { + if (*ip) { + do_bzero = 1; + break; + } + } + + if (do_bzero) { + rval |= XR_AG_SB_SEC; + if (!no_modify) { + do_warn( + "zeroing unused portion of secondary superblock %d sector\n", + i); + bzero((void *)((__psint_t)sb + size), + mp->m_sb.sb_sectsize - size); + } else + do_warn( + "would zero unused portion of secondary superblock %d sector\n", + i); + } + } + + /* + * now look for the fields we can manipulate directly. + * if we did a bzero and that bzero could have included + * the field in question, just silently reset it. otherwise, + * complain. + * + * for now, just zero the flags field since only + * the readonly flag is used + */ + if (sb->sb_flags) { + if (!no_modify) + sb->sb_flags = 0; + if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) { + rval |= XR_AG_SB; + do_warn("bad flags field in superblock %d\n", i); + } else + rval |= XR_AG_SB_SEC; + } + + /* + * quota inodes and flags in secondary superblocks + * are never set by mkfs. However, they could be set + * in a secondary if a fs with quotas was growfs'ed since + * growfs copies the new primary into the secondaries. + */ + if (sb->sb_inprogress == 1 && sb->sb_uquotino) { + if (!no_modify) + sb->sb_uquotino = 0; + if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) { + rval |= XR_AG_SB; + do_warn( + "non-null user quota inode field in superblock %d\n", + i); + } else + rval |= XR_AG_SB_SEC; + } + + if (sb->sb_inprogress == 1 && sb->sb_gquotino) { + if (!no_modify) + sb->sb_gquotino = 0; + if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) { + rval |= XR_AG_SB; + do_warn( + "non-null group quota inode field in superblock %d\n", + i); + } else + rval |= XR_AG_SB_SEC; + } + + if (sb->sb_inprogress == 1 && sb->sb_qflags) { + if (!no_modify) + sb->sb_qflags = 0; + if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) { + rval |= XR_AG_SB; + do_warn("non-null quota flags in superblock %d\n", i); + } else + rval |= XR_AG_SB_SEC; + } + + /* + * if the secondaries agree on a stripe unit/width or inode + * alignment, those fields ought to be valid since they are + * written at mkfs time (and the corresponding sb version bits + * are set). + */ + if (!XFS_SB_VERSION_HASSHARED(sb) && sb->sb_shared_vn != 0) { + if (!no_modify) + sb->sb_shared_vn = 0; + if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) { + rval |= XR_AG_SB; + do_warn("bad shared version number in superblock %d\n", + i); + } else + rval |= XR_AG_SB_SEC; + } + + if (!XFS_SB_VERSION_HASALIGN(sb) && sb->sb_inoalignmt != 0) { + if (!no_modify) + sb->sb_inoalignmt = 0; + if (sb->sb_versionnum & XR_PART_SECSB_VNMASK || !do_bzero) { + rval |= XR_AG_SB; + do_warn("bad inode alignment field in superblock %d\n", + i); + } else + rval |= XR_AG_SB_SEC; + } + + if (!XFS_SB_VERSION_HASDALIGN(sb) && + (sb->sb_unit != 0 || sb->sb_width != 0)) { + if (!no_modify) + sb->sb_unit = sb->sb_width = 0; + if (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK || !do_bzero) { + rval |= XR_AG_SB; + do_warn( + "bad stripe unit/width fields in superblock %d\n", + i); + } else + rval |= XR_AG_SB_SEC; + } + + return(rval); +} + +/* + * verify and reset the ag header if required. + * + * lower 4 bits of rval are set depending on what got modified. + * (see agheader.h for more details) + * + * NOTE -- this routine does not tell the user that it has + * altered things. Rather, it is up to the caller to do so + * using the bits encoded into the return value. + */ + +int +verify_set_agheader(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb, + xfs_agf_t *agf, xfs_agi_t *agi, xfs_agnumber_t i) +{ + int rval = 0; + int status = XR_OK; + int status_sb = XR_OK; + + status = verify_sb(sb, (i == 0)); + + if (status != XR_OK) { + do_warn("bad on-disk superblock %d - %s\n", + i, err_string(status)); + } + + status_sb = compare_sb(mp, sb); + + if (status_sb != XR_OK) { + do_warn("primary and secondary superblock %d conflict - %s\n", + i, err_string(status_sb)); + } + + if (status != XR_OK || status_sb != XR_OK) { + if (!no_modify) { + *sb = mp->m_sb; + + /* + * clear the more transient fields + */ + sb->sb_inprogress = 1; + + sb->sb_icount = 0; + sb->sb_ifree = 0; + sb->sb_fdblocks = 0; + sb->sb_frextents = 0; + + sb->sb_qflags = 0; + } + + rval |= XR_AG_SB; + } + + rval |= secondary_sb_wack(mp, sbuf, sb, i); + + rval |= verify_set_agf(mp, agf, i); + rval |= verify_set_agi(mp, agi, i); + + return(rval); +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/agheader.h linux-2.4-xfs/cmd/xfsprogs/repair/agheader.h --- linux-2.4.7/cmd/xfsprogs/repair/agheader.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/agheader.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +typedef struct fs_geometry { + /* + * these types should match the superblock types + */ + __uint32_t sb_blocksize; /* blocksize (bytes) */ + xfs_drfsbno_t sb_dblocks; /* # data blocks */ + xfs_drfsbno_t sb_rblocks; /* # realtime blocks */ + xfs_drtbno_t sb_rextents; /* # realtime extents */ + uuid_t sb_uuid; /* fs uuid */ + xfs_dfsbno_t sb_logstart; /* starting log block # */ + xfs_agblock_t sb_rextsize; /* realtime extent size (blocks )*/ + xfs_agblock_t sb_agblocks; /* # of blocks per ag */ + xfs_agnumber_t sb_agcount; /* # of ags */ + xfs_extlen_t sb_rbmblocks; /* # of rt bitmap blocks */ + xfs_extlen_t sb_logblocks; /* # of log blocks */ + __uint16_t sb_sectsize; /* volume sector size (bytes) */ + __uint16_t sb_inodesize; /* inode size (bytes) */ + __uint8_t sb_imax_pct; /* max % of fs for inode space */ + + /* + * these don't have to match the superblock types but are placed + * before sb_shared_vn because these values don't have to be + * checked manually. These variables will be set only on + * filesystems with dependably good (fully initialized) + * secondary superblock sectors, will be stamped in all + * superblocks at mkfs time, and are features that cannot + * be downgraded unless all superblocks in the filesystem + * are rewritten. + */ + int sb_extflgbit; /* extent flag feature bit set */ + + /* + * fields after this point have to be checked manually in compare_sb() + */ + __uint8_t sb_shared_vn; /* shared version number */ + xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */ + __uint32_t sb_unit; /* stripe or raid unit */ + __uint32_t sb_width; /* stripe or width unit */ + + /* + * these don't have to match, they track superblock properties + * that could have been upgraded and/or downgraded during + * run-time so that the primary superblock has them but the + * secondaries do not. + * Plus, they have associated data fields whose data fields may + * be corrupt in cases where the filesystem was made on a + * pre-6.5 campus alpha mkfs and the feature was enabled on + * the filesystem later. + */ + int sb_ialignbit; /* sb has inode alignment bit set */ + int sb_salignbit; /* sb has stripe alignment bit set */ + int sb_sharedbit; /* sb has inode alignment bit set */ + + int sb_fully_zeroed; /* has zeroed secondary sb sectors */ +} fs_geometry_t; + +typedef struct fs_geo_list { + struct fs_geo_list *next; + int refs; + int index; + fs_geometry_t geo; +} fs_geo_list_t; + +/* + * fields for sb_last_nonzero + */ + +#define XR_SB_COUNTERS 0x0001 +#define XR_SB_INOALIGN 0x0002 +#define XR_SB_SALIGN 0x0004 + +/* + * what got modified by verify_set_* routines + */ + +#define XR_AG_SB 0x1 +#define XR_AG_AGF 0x2 +#define XR_AG_AGI 0x4 +#define XR_AG_SB_SEC 0x8 + + diff -rNu linux-2.4.7/cmd/xfsprogs/repair/attr_repair.c linux-2.4-xfs/cmd/xfsprogs/repair/attr_repair.c --- linux-2.4.7/cmd/xfsprogs/repair/attr_repair.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/attr_repair.c Wed May 9 01:56:06 2001 @@ -0,0 +1,1084 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "globals.h" +#include "err_protos.h" +#include "attr_repair.h" +#include "dir.h" +#include "dinode.h" +#include "bmap.h" + +static int acl_valid(struct acl *aclp); +static int mac_valid(mac_t lp); + + +/* + * For attribute repair, there are 3 formats to worry about. First, is + * shortform attributes which reside in the inode. Second is the leaf + * form, and lastly the btree. Much of this models after the directory + * structure so code resembles the directory repair cases. + * For shortform case, if an attribute looks corrupt, it is removed. + * If that leaves the shortform down to 0 attributes, it's okay and + * will appear to just have a null attribute fork. Some checks are done + * for validity of the value field based on what the security needs are. + * Calls will be made out to mac_valid or acl_valid libc libraries if + * the security attributes exist. They will be cleared if invalid. No + * other values will be checked. The DMF folks do not have current + * requirements, but may in the future. + * + * For leaf block attributes, it requires more processing. One sticky + * point is that the attributes can be local (within the leaf) or + * remote (outside the leaf in other blocks). Thinking of local only + * if you get a bad attribute, and want to delete just one, its a-okay + * if it remains large enough to still be a leaf block attribute. Otherwise, + * it may have to be converted to shortform. How to convert this and when + * is an issue. This call is happening in Phase3. Phase5 will capture empty + * blocks, but Phase6 allows you to use the simulation library which knows + * how to handle attributes in the kernel for converting formats. What we + * could do is mark an attribute to be cleared now, but in phase6 somehow + * have it cleared for real and then the format changed to shortform if + * applicable. Since this requires more work than I anticipate can be + * accomplished for the next release, we will instead just say any bad + * attribute in the leaf block will make the entire attribute fork be + * cleared. The simplest way to do that is to ignore the leaf format, and + * call clear_dinode_attr to just make a shortform attribute fork with + * zero entries. + * + * Another issue with handling repair on leaf attributes is the remote + * blocks. To make sure that they look good and are not used multiple times + * by the attribute fork, some mechanism to keep track of all them is necessary. + * Do this in the future, time permitting. For now, note that there is no + * check for remote blocks and their allocations. + * + * For btree formatted attributes, the model can follow directories. That + * would mean go down the tree to the leftmost leaf. From there moving down + * the links and processing each. They would call back up the tree, to verify + * that the tree structure is okay. Any problems will result in the attribute + * fork being emptied and put in shortform format. + */ + +/* + * This routine just checks what security needs are for attribute values + * only called when root flag is set, otherwise these names could exist in + * in user attribute land without a conflict. + * If value is non-zero, then a remote attribute is being passed in + */ + +int +valuecheck(char *namevalue, char *value, int namelen, int valuelen) +{ + /* for proper alignment issues, get the structs and bcopy the values */ + mac_label macl; + struct acl thisacl; + void *valuep; + int clearit = 0; + + if ((strncmp(namevalue, SGI_ACL_FILE, SGI_ACL_FILE_SIZE) == 0) || + (strncmp(namevalue, SGI_ACL_DEFAULT, + SGI_ACL_DEFAULT_SIZE) == 0)) { + if (value == NULL) { + bzero(&thisacl, sizeof(struct acl)); + bcopy(namevalue+namelen, &thisacl, valuelen); + valuep = &thisacl; + } else + valuep = value; + + if (acl_valid((struct acl *) valuep) != 0) { /* 0 means valid */ + clearit = 1; + do_warn("entry contains illegal value in attribute named SGI_ACL_FILE or SGI_ACL_DEFAULT\n"); + } + } else if (strncmp(namevalue, SGI_MAC_FILE, SGI_MAC_FILE_SIZE) == 0) { + if (value == NULL) { + bzero(&macl, sizeof(mac_label)); + bcopy(namevalue+namelen, &macl, valuelen); + valuep = &macl; + } else + valuep = value; + + if (mac_valid((mac_label *) valuep) != 1) { /* 1 means valid */ + /* + *if sysconf says MAC enabled, + * temp = mac_from_text("msenhigh/mintlow", NULL) + * copy it to value, update valuelen, totsize + * This causes pushing up or down of all following + * attributes, forcing a attribute format change!! + * else clearit = 1; + */ + clearit = 1; + do_warn("entry contains illegal value in attribute named SGI_MAC_LABEL\n"); + } + } else if (strncmp(namevalue, SGI_CAP_FILE, SGI_CAP_FILE_SIZE) == 0) { + if ( valuelen != sizeof(cap_set_t)) { + clearit = 1; + do_warn("entry contains illegal value in attribute named SGI_CAP_FILE\n"); + } + } + + return(clearit); +} + + +/* + * this routine validates the attributes in shortform format. + * a non-zero return repair value means certain attributes are bogus + * and were cleared if possible. Warnings do not generate error conditions + * if you cannot modify the structures. repair is set to 1, if anything + * was fixed. + */ +int +process_shortform_attr( + xfs_ino_t ino, + xfs_dinode_t *dip, + int *repair) +{ + xfs_attr_shortform_t *asf; + xfs_attr_sf_entry_t *currententry, *nextentry, *tempentry; + int i, junkit; + int currentsize, remainingspace; + + *repair = 0; + + asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT); + + /* Assumption: hdr.totsize is less than a leaf block and was checked + * by lclinode for valid sizes. Check the count though. + */ + if (INT_GET(asf->hdr.count, ARCH_CONVERT) == 0) + /* then the total size should just be the header length */ + if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) != sizeof(xfs_attr_sf_hdr_t)) { + /* whoops there's a discrepancy. Clear the hdr */ + if (!no_modify) { + do_warn("there are no attributes in the fork for inode %llu \n", ino); + INT_SET(asf->hdr.totsize, ARCH_CONVERT, + sizeof(xfs_attr_sf_hdr_t)); + *repair = 1; + return(1); + } else { + do_warn("would junk the attribute fork since the count is 0 for inode %llu\n",ino); + return(1); + } + } + + currentsize = sizeof(xfs_attr_sf_hdr_t); + remainingspace = INT_GET(asf->hdr.totsize, ARCH_CONVERT) - currentsize; + nextentry = &asf->list[0]; + for (i = 0; i < INT_GET(asf->hdr.count, ARCH_CONVERT); i++) { + currententry = nextentry; + junkit = 0; + + /* don't go off the end if the hdr.count was off */ + if ((currentsize + (sizeof(xfs_attr_sf_entry_t) - 1)) > + INT_GET(asf->hdr.totsize, ARCH_CONVERT)) + break; /* get out and reset count and totSize */ + + /* if the namelen is 0, can't get to the rest of the entries */ + if (INT_GET(currententry->namelen, ARCH_CONVERT) == 0) { + do_warn("zero length name entry in attribute fork, "); + if (!no_modify) { + do_warn("truncating attributes for inode %llu to %d \n", ino, i); + *repair = 1; + break; /* and then update hdr fields */ + } else { + do_warn("would truncate attributes for inode %llu to %d \n", ino, i); + break; + } + } else { + /* It's okay to have a 0 length valuelen, but do a + * rough check to make sure we haven't gone outside of + * totsize. + */ + if ((remainingspace < INT_GET(currententry->namelen, ARCH_CONVERT)) || + ((remainingspace - INT_GET(currententry->namelen, ARCH_CONVERT)) + < INT_GET(currententry->valuelen, ARCH_CONVERT))) { + do_warn("name or value attribute lengths are too large, \n"); + if (!no_modify) { + do_warn(" truncating attributes for inode %llu to %d \n", ino, i); + *repair = 1; + break; /* and then update hdr fields */ + } else { + do_warn(" would truncate attributes for inode %llu to %d \n", ino, i); + break; + } + } + } + + /* namecheck checks for / and null terminated for file names. + * attributes names currently follow the same rules. + */ + if (namecheck((char *)¤tentry->nameval[0], + INT_GET(currententry->namelen, ARCH_CONVERT))) { + do_warn("entry contains illegal character in shortform attribute name\n"); + junkit = 1; + } + + if (INT_GET(currententry->flags, ARCH_CONVERT) & XFS_ATTR_INCOMPLETE) { + do_warn("entry has INCOMPLETE flag on in shortform attribute\n"); + junkit = 1; + } + + /* Only check values for root security attributes */ + if (INT_GET(currententry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT) + junkit = valuecheck((char *)¤tentry->nameval[0], NULL, + INT_GET(currententry->namelen, ARCH_CONVERT), INT_GET(currententry->valuelen, ARCH_CONVERT)); + + remainingspace = remainingspace - + XFS_ATTR_SF_ENTSIZE(currententry); + + if (junkit) { + if (!no_modify) { + /* get rid of only this entry */ + do_warn("removing attribute entry %d for inode %llu \n", i, ino); + tempentry = (xfs_attr_sf_entry_t *) + ((__psint_t) currententry + + XFS_ATTR_SF_ENTSIZE(currententry)); + memmove(currententry,tempentry,remainingspace); + INT_MOD(asf->hdr.count, ARCH_CONVERT, -1); + i--; /* no worries, it will wrap back to 0 */ + *repair = 1; + continue; /* go back up now */ + } else { + do_warn("would remove attribute entry %d for inode %llu \n", i, ino); + } + } + + /* Let's get ready for the next entry... */ + nextentry = (xfs_attr_sf_entry_t *) + ((__psint_t) nextentry + + XFS_ATTR_SF_ENTSIZE(currententry)); + currentsize = currentsize + XFS_ATTR_SF_ENTSIZE(currententry); + + } /* end the loop */ + + + if (INT_GET(asf->hdr.count, ARCH_CONVERT) != i) { + if (no_modify) { + do_warn("would have corrected attribute entry count in inode %llu from %d to %d\n", + ino, INT_GET(asf->hdr.count, ARCH_CONVERT), i); + } else { + do_warn("corrected attribute entry count in inode %llu, was %d, now %d\n", + ino, INT_GET(asf->hdr.count, ARCH_CONVERT), i); + INT_SET(asf->hdr.count, ARCH_CONVERT, i); + *repair = 1; + } + } + + /* ASSUMPTION: currentsize <= totsize */ + if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) != currentsize) { + if (no_modify) { + do_warn("would have corrected attribute totsize in inode %llu from %d to %d\n", + ino, INT_GET(asf->hdr.totsize, ARCH_CONVERT), currentsize); + } else { + do_warn("corrected attribute entry totsize in inode %llu, was %d, now %d\n", + ino, INT_GET(asf->hdr.totsize, ARCH_CONVERT), currentsize); + INT_SET(asf->hdr.totsize, ARCH_CONVERT, currentsize); + *repair = 1; + } + } + + return(*repair); +} + +/* This routine brings in blocks from disk one by one and assembles them + * in the value buffer. If get_bmapi gets smarter later to return an extent + * or list of extents, that would be great. For now, we don't expect too + * many blocks per remote value, so one by one is sufficient. + */ +static int +rmtval_get(xfs_mount_t *mp, xfs_ino_t ino, blkmap_t *blkmap, + xfs_dablk_t blocknum, int valuelen, char* value) +{ + xfs_dfsbno_t bno; + xfs_buf_t *bp; + int clearit = 0, i = 0, length = 0, amountdone = 0; + + /* ASSUMPTION: valuelen is a valid number, so use it for looping */ + /* Note that valuelen is not a multiple of blocksize */ + while (amountdone < valuelen) { + bno = blkmap_get(blkmap, blocknum + i); + if (bno == NULLDFSBNO) { + do_warn("remote block for attributes of inode %llu" + " is missing\n", ino); + clearit = 1; + break; + } + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + do_warn("can't read remote block for attributes" + " of inode %llu\n", ino); + clearit = 1; + break; + } + ASSERT(mp->m_sb.sb_blocksize == XFS_BUF_COUNT(bp)); + length = MIN(XFS_BUF_COUNT(bp), valuelen - amountdone); + bcopy(XFS_BUF_PTR(bp), value, length); + amountdone += length; + value += length; + i++; + libxfs_putbuf(bp); + } + return (clearit); +} + +/* + * freespace map for directory and attribute leaf blocks (1 bit per byte) + * 1 == used, 0 == free + */ +static da_freemap_t attr_freemap[DA_BMAP_SIZE]; + +/* The block is read in. The magic number and forward / backward + * links are checked by the caller process_leaf_attr. + * If any problems occur the routine returns with non-zero. In + * this case the next step is to clear the attribute fork, by + * changing it to shortform and zeroing it out. Forkoff need not + * be changed. + */ + +int +process_leaf_attr_block( + xfs_mount_t *mp, + xfs_attr_leafblock_t *leaf, + xfs_dablk_t da_bno, + xfs_ino_t ino, + blkmap_t *blkmap, + xfs_dahash_t last_hashval, + xfs_dahash_t *current_hashval, + int *repair) +{ + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_local_t *local; + xfs_attr_leaf_name_remote_t *remotep; + int i, start, stop, clearit, usedbs, firstb, thissize; + + clearit = usedbs = 0; + *repair = 0; + firstb = mp->m_sb.sb_blocksize; + stop = sizeof(xfs_attr_leaf_hdr_t); + + /* does the count look sorta valid? */ + if (INT_GET(leaf->hdr.count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t) + + sizeof(xfs_attr_leaf_hdr_t) + > XFS_LBSIZE(mp)) { + do_warn("bad attribute count %d in attr block %u, inode %llu\n", + (int) INT_GET(leaf->hdr.count, ARCH_CONVERT), + da_bno, ino); + return (1); + } + + init_da_freemap(attr_freemap); + (void) set_da_freemap(mp, attr_freemap, 0, stop); + + /* go thru each entry checking for problems */ + for (i = 0, entry = &leaf->entries[0]; + i < INT_GET(leaf->hdr.count, ARCH_CONVERT); + i++, entry++) { + + /* check if index is within some boundary. */ + if (INT_GET(entry->nameidx, ARCH_CONVERT) > XFS_LBSIZE(mp)) { + do_warn("bad attribute nameidx %d in attr block %u, inode %llu\n", + (int)INT_GET(entry->nameidx, ARCH_CONVERT), + da_bno,ino); + clearit = 1; + break; + } + + if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_INCOMPLETE) { + /* we are inconsistent state. get rid of us */ + do_warn("attribute entry #%d in attr block %u, inode %llu is INCOMPLETE\n", + i, da_bno, ino); + clearit = 1; + break; + } + + /* mark the entry used */ + start = (__psint_t)&leaf->entries[i] - (__psint_t)leaf; + stop = start + sizeof(xfs_attr_leaf_entry_t); + if (set_da_freemap(mp, attr_freemap, start, stop)) { + do_warn("attribute entry %d in attr block %u, inode %llu claims already used space\n", + i,da_bno,ino); + clearit = 1; + break; /* got an overlap */ + } + + if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_LOCAL) { + + local = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); + if ((INT_GET(local->namelen, ARCH_CONVERT) == 0) || + (namecheck((char *)&local->nameval[0], + INT_GET(local->namelen, ARCH_CONVERT)))) { + do_warn("attribute entry %d in attr block %u, inode %llu has bad name (namelen = %d)\n", + i, da_bno, ino, (int) INT_GET(local->namelen, ARCH_CONVERT)); + + clearit = 1; + break; + }; + + /* Check on the hash value. Checking ordering of hash values + * is not necessary, since one wrong one clears the whole + * fork. If the ordering's wrong, it's caught here or + * the kernel code has a bug with transaction logging + * or attributes itself. For paranoia reasons, let's check + * ordering anyway in case both the name value and the + * hashvalue were wrong but matched. Unlikely, however. + */ + if (INT_GET(entry->hashval, ARCH_CONVERT) != + libxfs_da_hashname((char *)&local->nameval[0], + INT_GET(local->namelen, ARCH_CONVERT)) || + (INT_GET(entry->hashval, ARCH_CONVERT) + < last_hashval)) { + do_warn("bad hashvalue for attribute entry %d in attr block %u, inode %llu\n", + i, da_bno, ino); + clearit = 1; + break; + } + + /* Only check values for root security attributes */ + if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT) + if (valuecheck((char *)&local->nameval[0], NULL, + INT_GET(local->namelen, ARCH_CONVERT), INT_GET(local->valuelen, ARCH_CONVERT))) { + do_warn("bad security value for attribute entry %d in attr block %u, inode %llu\n", + i,da_bno,ino); + clearit = 1; + break; + }; + thissize = XFS_ATTR_LEAF_ENTSIZE_LOCAL( + INT_GET(local->namelen, ARCH_CONVERT), INT_GET(local->valuelen, ARCH_CONVERT)); + + } else { + /* do the remote case */ + remotep = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i); + thissize = XFS_ATTR_LEAF_ENTSIZE_REMOTE( + INT_GET(remotep->namelen, ARCH_CONVERT)); + + if ((INT_GET(remotep->namelen, ARCH_CONVERT) == 0) || + (namecheck((char *)&remotep->name[0], + INT_GET(remotep->namelen, ARCH_CONVERT))) || + (INT_GET(entry->hashval, ARCH_CONVERT) + != libxfs_da_hashname( + (char *)&remotep->name[0], + INT_GET(remotep->namelen, ARCH_CONVERT))) || + (INT_GET(entry->hashval, ARCH_CONVERT) + < last_hashval) || + (INT_GET(remotep->valueblk, ARCH_CONVERT) == 0)) { + do_warn("inconsistent remote attribute entry %d in attr block %u, ino %llu\n", + i, da_bno, ino); + clearit = 1; + break; + }; + + if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT) { + char* value; + if ((value = malloc(INT_GET(remotep->valuelen, ARCH_CONVERT)))==NULL){ + do_warn("cannot malloc enough for remotevalue attribute for inode %llu\n",ino); + do_warn("SKIPPING this remote attribute\n"); + continue; + } + if (rmtval_get(mp, ino, blkmap, + INT_GET(remotep->valueblk, ARCH_CONVERT), + INT_GET(remotep->valuelen, ARCH_CONVERT), value)) { + do_warn("remote attribute get failed for entry %d, inode %llu\n", i,ino); + clearit = 1; + free(value); + break; + } + if (valuecheck((char *)&remotep->name[0], value, + INT_GET(remotep->namelen, ARCH_CONVERT), INT_GET(remotep->valuelen, ARCH_CONVERT))){ + do_warn("remote attribute value check failed for entry %d, inode %llu\n", i, ino); + clearit = 1; + free(value); + break; + } + free(value); + } + } + + *current_hashval = last_hashval + = INT_GET(entry->hashval, ARCH_CONVERT); + + if (set_da_freemap(mp, attr_freemap, INT_GET(entry->nameidx, ARCH_CONVERT), + INT_GET(entry->nameidx, ARCH_CONVERT) + thissize)) { + do_warn("attribute entry %d in attr block %u, inode %llu claims used space\n", + i, da_bno, ino); + clearit = 1; + break; /* got an overlap */ + } + usedbs += thissize; + if (INT_GET(entry->nameidx, ARCH_CONVERT) < firstb) + firstb = INT_GET(entry->nameidx, ARCH_CONVERT); + + } /* end the loop */ + + if (!clearit) { + /* verify the header information is correct */ + + /* if the holes flag is set, don't reset first_used unless it's + * pointing to used bytes. we're being conservative here + * since the block will get compacted anyhow by the kernel. + */ + + if ( (INT_GET(leaf->hdr.holes, ARCH_CONVERT) == 0 + && firstb != INT_GET(leaf->hdr.firstused, ARCH_CONVERT)) + || INT_GET(leaf->hdr.firstused, ARCH_CONVERT) > firstb) { + if (!no_modify) { + do_warn("- resetting first used heap value from %d to %d in block %u of attribute fork of inode %llu\n", + (int)INT_GET(leaf->hdr.firstused, + ARCH_CONVERT), firstb, + da_bno, ino); + INT_SET(leaf->hdr.firstused, + ARCH_CONVERT, firstb); + *repair = 1; + } else { + do_warn("- would reset first used value from %d to %d in block %u of attribute fork of inode %llu\n", + (int)INT_GET(leaf->hdr.firstused, + ARCH_CONVERT), firstb, + da_bno, ino); + } + } + + if (usedbs != INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT)) { + if (!no_modify) { + do_warn("- resetting usedbytes cnt from %d to %d in block %u of attribute fork of inode %llu\n", + (int)INT_GET(leaf->hdr.usedbytes, + ARCH_CONVERT), usedbs, da_bno, ino); + INT_SET(leaf->hdr.usedbytes, + ARCH_CONVERT, usedbs); + *repair = 1; + } else { + do_warn("- would reset usedbytes cnt from %d to %d in block %u of attribute fork of %llu\n", + (int)INT_GET(leaf->hdr.usedbytes, + ARCH_CONVERT), usedbs,da_bno,ino); + } + } + + /* there's a lot of work in process_leaf_dir_block to go thru + * checking for holes and compacting if appropiate. I don't think + * attributes need all that, so let's just leave the holes. If + * we discover later that this is a good place to do compaction + * we can add it then. + */ + } + return (clearit); /* and repair */ +} + + +/* + * returns 0 if the attribute fork is ok, 1 if it has to be junked. + */ +int +process_leaf_attr_level(xfs_mount_t *mp, + da_bt_cursor_t *da_cursor) +{ + int repair; + xfs_attr_leafblock_t *leaf; + xfs_buf_t *bp; + xfs_ino_t ino; + xfs_dfsbno_t dev_bno; + xfs_dablk_t da_bno; + xfs_dablk_t prev_bno; + xfs_dahash_t current_hashval = 0; + xfs_dahash_t greatest_hashval; + + da_bno = da_cursor->level[0].bno; + ino = da_cursor->ino; + prev_bno = 0; + + do { + repair = 0; + dev_bno = blkmap_get(da_cursor->blkmap, da_bno); + /* + * 0 is the root block and no block + * pointer can point to the root block of the btree + */ + ASSERT(da_bno != 0); + + if (dev_bno == NULLDFSBNO) { + do_warn("can't map block %u for attribute fork " + "for inode %llu\n", da_bno, ino); + goto error_out; + } + + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dev_bno), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + do_warn("can't read file block %u (fsbno %llu) for" + " attribute fork of inode %llu\n", + da_bno, dev_bno, ino); + goto error_out; + } + + leaf = (xfs_attr_leafblock_t *)XFS_BUF_PTR(bp); + + /* check magic number for leaf directory btree block */ + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + != XFS_ATTR_LEAF_MAGIC) { + do_warn("bad attribute leaf magic %#x for inode %llu\n", + leaf->hdr.info.magic, ino); + libxfs_putbuf(bp); + goto error_out; + } + + /* + * for each block, process the block, verify it's path, + * then get next block. update cursor values along the way + */ + if (process_leaf_attr_block(mp, leaf, da_bno, ino, + da_cursor->blkmap, current_hashval, + &greatest_hashval, &repair)) { + libxfs_putbuf(bp); + goto error_out; + } + + /* + * index can be set to hdr.count so match the + * indexes of the interior blocks -- which at the + * end of the block will point to 1 after the final + * real entry in the block + */ + da_cursor->level[0].hashval = greatest_hashval; + da_cursor->level[0].bp = bp; + da_cursor->level[0].bno = da_bno; + da_cursor->level[0].index + = INT_GET(leaf->hdr.count, ARCH_CONVERT); + da_cursor->level[0].dirty = repair; + + if (INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != prev_bno) { + do_warn("bad sibling back pointer for block %u in " + "attribute fork for inode %llu\n", da_bno, ino); + libxfs_putbuf(bp); + goto error_out; + } + + prev_bno = da_bno; + da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT); + + if (da_bno != 0 && verify_da_path(mp, da_cursor, 0)) { + libxfs_putbuf(bp); + goto error_out; + } + + current_hashval = greatest_hashval; + + if (repair && !no_modify) { + libxfs_writebuf(bp, 0); + } + else { + libxfs_putbuf(bp); + } + } while (da_bno != 0); + + if (verify_final_da_path(mp, da_cursor, 0)) { + /* + * verify the final path up (right-hand-side) if still ok + */ + do_warn("bad hash path in attribute fork for inode %llu\n", + da_cursor->ino); + goto error_out; + } + + /* releases all buffers holding interior btree blocks */ + release_da_cursor(mp, da_cursor, 0); + return(0); + +error_out: + /* release all buffers holding interior btree blocks */ + err_release_da_cursor(mp, da_cursor, 0); + return(1); +} + + +/* + * a node directory is a true btree -- where the attribute fork + * has gotten big enough that it is represented as a non-trivial (e.g. + * has more than just a block) btree. + * + * Note that if we run into any problems, we will trash the attribute fork. + * + * returns 0 if things are ok, 1 if bad + * Note this code has been based off process_node_dir. + */ +int +process_node_attr( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + blkmap_t *blkmap) +{ + xfs_dablk_t bno; + int error = 0; + da_bt_cursor_t da_cursor; + + /* + * try again -- traverse down left-side of tree until we hit + * the left-most leaf block setting up the btree cursor along + * the way. Then walk the leaf blocks left-to-right, calling + * a parent-verification routine each time we traverse a block. + */ + bzero(&da_cursor, sizeof(da_bt_cursor_t)); + da_cursor.active = 0; + da_cursor.type = 0; + da_cursor.ino = ino; + da_cursor.dip = dip; + da_cursor.greatest_bno = 0; + da_cursor.blkmap = blkmap; + + /* + * now process interior node. don't have any buffers held in this path. + */ + error = traverse_int_dablock(mp, &da_cursor, &bno, XFS_ATTR_FORK); + if (error == 0) + return(1); /* 0 means unsuccessful */ + + /* + * now pass cursor and bno into leaf-block processing routine + * the leaf dir level routine checks the interior paths + * up to the root including the final right-most path. + */ + + return (process_leaf_attr_level(mp, &da_cursor)); +} + +/* + * Start processing for a leaf or fuller btree. + * A leaf directory is one where the attribute fork is too big for + * the inode but is small enough to fit into one btree block + * outside the inode. This code is modelled after process_leaf_dir_block. + * + * returns 0 if things are ok, 1 if bad (attributes needs to be junked) + * repair is set, if anything was changed, but attributes can live thru it + */ + +int +process_longform_attr( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + blkmap_t *blkmap, + int *repair) /* out - 1 if something was fixed */ +{ + xfs_attr_leafblock_t *leaf; + xfs_dfsbno_t bno; + xfs_buf_t *bp; + xfs_dahash_t next_hashval; + int repairlinks = 0; + + *repair = 0; + + bno = blkmap_get(blkmap, 0); + + if ( bno == NULLDFSBNO ) { + if (INT_GET(dip->di_core.di_anextents, ARCH_CONVERT) == 0 && + dip->di_core.di_aformat == XFS_DINODE_FMT_EXTENTS ) + /* it's okay the kernel can handle this state */ + return(0); + else { + do_warn("block 0 of inode %llu attribute fork" + " is missing\n", ino); + return(1); + } + } + /* FIX FOR bug 653709 -- EKN */ + if (mp->m_sb.sb_agcount < XFS_FSB_TO_AGNO(mp, bno)) { + do_warn("agno of attribute fork of inode %llu out of " + "regular partition\n", ino); + return(1); + } + + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + do_warn("can't read block 0 of inode %llu attribute fork\n", + ino); + return(1); + } + + /* verify leaf block */ + leaf = (xfs_attr_leafblock_t *)XFS_BUF_PTR(bp); + + /* check sibling pointers in leaf block or root block 0 before + * we have to release the btree block + */ + if ( INT_GET(leaf->hdr.info.forw, ARCH_CONVERT) != 0 + || INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != 0) { + if (!no_modify) { + do_warn("clearing forw/back pointers in block 0 " + "for attributes in inode %llu\n", ino); + repairlinks = 1; + INT_SET(leaf->hdr.info.forw, ARCH_CONVERT, 0); + INT_SET(leaf->hdr.info.back, ARCH_CONVERT, 0); + } else { + do_warn("would clear forw/back pointers in block 0 " + "for attributes in inode %llu\n", ino); + } + } + + /* + * use magic number to tell us what type of attribute this is. + * it's possible to have a node or leaf attribute in either an + * extent format or btree format attribute fork. + */ + switch (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)) { + case XFS_ATTR_LEAF_MAGIC: /* leaf-form attribute */ + if (process_leaf_attr_block(mp, leaf, 0, ino, blkmap, + 0, &next_hashval, repair)) { + /* the block is bad. lose the attribute fork. */ + libxfs_putbuf(bp); + return(1); + } + *repair = *repair || repairlinks; + break; + + case XFS_DA_NODE_MAGIC: /* btree-form attribute */ + /* must do this now, to release block 0 before the traversal */ + if (repairlinks) { + *repair = 1; + libxfs_writebuf(bp, 0); + } else + libxfs_putbuf(bp); + return (process_node_attr(mp, ino, dip, blkmap)); /* + repair */ + default: + do_warn("bad attribute leaf magic # %#x for dir ino %llu\n", + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), ino); + libxfs_putbuf(bp); + return(1); + } + + if (*repair && !no_modify) + libxfs_writebuf(bp, 0); + else + libxfs_putbuf(bp); + + return(0); /* repair may be set */ +} + + +static void +xfs_acl_get_endian(struct acl *aclp) +{ + struct acl_entry *ace, *end; + + /* do the endian conversion */ + INT_SET(aclp->acl_cnt, ARCH_CONVERT, aclp->acl_cnt); + + /* loop thru ACEs of ACL */ + end = &aclp->acl_entry[0]+aclp->acl_cnt; + for (ace=&aclp->acl_entry[0]; ace < end; ace++) { + INT_SET(ace->ae_tag, ARCH_CONVERT, ace->ae_tag); + INT_SET(ace->ae_id, ARCH_CONVERT, ace->ae_id); + INT_SET(ace->ae_perm, ARCH_CONVERT, ace->ae_perm); + } +} + +/* + * returns 1 if attributes got cleared + * and 0 if things are ok. + */ +int +process_attributes( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + blkmap_t *blkmap, + int *repair) /* returned if we did repair */ +{ + int err; + xfs_dinode_core_t *dinoc; + /* REFERENCED */ + xfs_attr_shortform_t *asf; + + dinoc = &dip->di_core; + asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT); + + if (dinoc->di_aformat == XFS_DINODE_FMT_LOCAL) { + ASSERT(INT_GET(asf->hdr.totsize, ARCH_CONVERT) <= XFS_DFORK_ASIZE_ARCH(dip, mp, ARCH_CONVERT)); + err = process_shortform_attr(ino, dip, repair); + } else if (dinoc->di_aformat == XFS_DINODE_FMT_EXTENTS || + dinoc->di_aformat == XFS_DINODE_FMT_BTREE) { + err = process_longform_attr(mp, ino, dip, blkmap, + repair); + /* if err, convert this to shortform and clear it */ + /* if repair and no error, it's taken care of */ + } else { + do_warn("illegal attribute format %d, ino %llu\n", + dinoc->di_aformat, ino); + err = 1; + } + return (err); /* and repair */ +} + +/* + * Validate an ACL + */ +static int +acl_valid (struct acl *aclp) +{ + struct acl_entry *entry, *e; + int user = 0, group = 0, other = 0, mask = 0, mask_required = 0; + int i, j; + + if (aclp == NULL) + goto acl_invalid; + + xfs_acl_get_endian(aclp); + + if (aclp->acl_cnt > ACL_MAX_ENTRIES) + goto acl_invalid; + + for (i = 0; i < aclp->acl_cnt; i++) + { + + entry = &aclp->acl_entry[i]; + + switch (entry->ae_tag) + { + case ACL_USER_OBJ: + if (user++) + goto acl_invalid; + break; + case ACL_GROUP_OBJ: + if (group++) + goto acl_invalid; + break; + case ACL_OTHER_OBJ: + if (other++) + goto acl_invalid; + break; + case ACL_USER: + case ACL_GROUP: + for (j = i + 1; j < aclp->acl_cnt; j++) + { + e = &aclp->acl_entry[j]; + if (e->ae_id == entry->ae_id && e->ae_tag == entry->ae_tag) + goto acl_invalid; + } + mask_required++; + break; + case ACL_MASK: + if (mask++) + goto acl_invalid; + break; + default: + goto acl_invalid; + } + } + if (!user || !group || !other || (mask_required && !mask)) + goto acl_invalid; + else + return 0; +acl_invalid: + errno = EINVAL; + return (-1); +} + +/* + * Check a category or division set to ensure that all values are in + * ascending order and each division or category appears only once. + */ +static int +__check_setvalue(const unsigned short *list, unsigned short count) +{ + unsigned short i; + + for (i = 1; i < count ; i++) + if (list[i] <= list[i-1]) + return -1; + return 0; +} + + +/* + * mac_valid(lp) + * check the validity of a mac label + */ +static int +mac_valid(mac_t lp) +{ + if (lp == NULL) + return (0); + + /* + * if the total category set and division set is greater than 250 + * report error + */ + if ((lp->ml_catcount + lp->ml_divcount) > MAC_MAX_SETS) + return(0); + + /* + * check whether the msentype value is valid, and do they have + * appropriate level, category association. + */ + switch (lp->ml_msen_type) { + case MSEN_ADMIN_LABEL: + case MSEN_EQUAL_LABEL: + case MSEN_HIGH_LABEL: + case MSEN_MLD_HIGH_LABEL: + case MSEN_LOW_LABEL: + case MSEN_MLD_LOW_LABEL: + if (lp->ml_level != 0 || lp->ml_catcount > 0 ) + return (0); + break; + case MSEN_TCSEC_LABEL: + case MSEN_MLD_LABEL: + if (lp->ml_catcount > 0 && + __check_setvalue(lp->ml_list, + lp->ml_catcount) == -1) + return (0); + break; + case MSEN_UNKNOWN_LABEL: + default: + return (0); + } + + /* + * check whether the minttype value is valid, and do they have + * appropriate grade, division association. + */ + switch (lp->ml_mint_type) { + case MINT_BIBA_LABEL: + if (lp->ml_divcount > 0 && + __check_setvalue(lp->ml_list + lp->ml_catcount, + lp->ml_divcount) == -1) + return(0); + break; + case MINT_EQUAL_LABEL: + case MINT_HIGH_LABEL: + case MINT_LOW_LABEL: + if (lp->ml_grade != 0 || lp->ml_divcount > 0 ) + return(0); + break; + default: + return(0); + } + + return (1); +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/attr_repair.h linux-2.4-xfs/cmd/xfsprogs/repair/attr_repair.h --- linux-2.4.7/cmd/xfsprogs/repair/attr_repair.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/attr_repair.h Mon Jan 15 00:52:52 2001 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef _XR_ATTRREPAIR_H +#define _XR_ATTRREPAIR_H + +struct blkmap; + +#define SGI_ACL_FILE "SGI_ACL_FILE" +#define SGI_ACL_DEFAULT "SGI_ACL_DEFAULT" +#define SGI_ACL_FILE_SIZE 12 +#define SGI_ACL_DEFAULT_SIZE 15 + +#define ACL_MAX_ENTRIES 25 +#define ACL_USER_OBJ 0x01 /* owner */ +#define ACL_USER 0x02 /* additional users */ +#define ACL_GROUP_OBJ 0x04 /* group */ +#define ACL_GROUP 0x08 /* additional groups */ +#define ACL_MASK 0x10 /* mask entry */ +#define ACL_OTHER_OBJ 0x20 /* other entry */ + +typedef ushort acl_perm_t; +typedef int acl_type_t; +typedef int acl_tag_t; + +/* + * On-disk representation of an ACL. + */ +struct acl_entry { + acl_tag_t ae_tag; + uid_t ae_id; + acl_perm_t ae_perm; +}; + +typedef struct acl_entry * acl_entry_t; + +struct acl { + int acl_cnt; /* Number of entries */ + struct acl_entry acl_entry[ACL_MAX_ENTRIES]; +}; + +int +process_attributes( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + struct blkmap *blkmap, + int *repair); + +#endif /* _XR_ATTRREPAIR_H */ diff -rNu linux-2.4.7/cmd/xfsprogs/repair/avl.c linux-2.4-xfs/cmd/xfsprogs/repair/avl.c --- linux-2.4.7/cmd/xfsprogs/repair/avl.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/avl.c Thu Apr 12 18:49:04 2001 @@ -0,0 +1,1465 @@ +/************************************************************************** + * * + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + * * + **************************************************************************/ + +#include + +#if defined(STAND_ALONE_DEBUG) || defined(AVL_USER_MODE_DEBUG) +#define AVL_DEBUG +#endif + +#include "avl.h" + +#define CERT ASSERT + +#ifdef AVL_DEBUG + +static void +avl_checknode( + register avltree_desc_t *tree, + register avlnode_t *np) +{ + register avlnode_t *back = np->avl_back; + register avlnode_t *forw = np->avl_forw; + register avlnode_t *nextino = np->avl_nextino; + register int bal = np->avl_balance; + + ASSERT(bal != AVL_BALANCE || (!back && !forw) || (back && forw)); + ASSERT(bal != AVL_FORW || forw); + ASSERT(bal != AVL_BACK || back); + + if (forw) { + ASSERT(AVL_START(tree, np) < AVL_START(tree, forw)); + ASSERT(np->avl_forw->avl_parent == np); + ASSERT(back || bal == AVL_FORW); + } else { + ASSERT(bal != AVL_FORW); + ASSERT(bal == AVL_BALANCE || back); + ASSERT(bal == AVL_BACK || !back); + } + + if (back) { + ASSERT(AVL_START(tree, np) > AVL_START(tree, back)); + ASSERT(np->avl_back->avl_parent == np); + ASSERT(forw || bal == AVL_BACK); + } else { + ASSERT(bal != AVL_BACK); + ASSERT(bal == AVL_BALANCE || forw); + ASSERT(bal == AVL_FORW || !forw); + } + + if (nextino == NULL) + ASSERT(forw == NULL); + else + ASSERT(AVL_END(tree, np) <= AVL_START(tree, nextino)); +} + +static void +avl_checktree( + register avltree_desc_t *tree, + register avlnode_t *root) +{ + register avlnode_t *nlast, *nnext, *np; + __psunsigned_t offset = 0; + __psunsigned_t end; + + nlast = nnext = root; + + ASSERT(!nnext || nnext->avl_parent == NULL); + + while (nnext) { + + avl_checknode(tree, nnext); + end = AVL_END(tree, nnext); + + if (end <= offset) { + if ((np = nnext->avl_forw) && np != nlast) { + nlast = nnext; + nnext = np; + } else { + nlast = nnext; + nnext = nnext->avl_parent; + } + continue; + } + + nlast = nnext; + if (np = nnext->avl_back) { + if (AVL_END(tree, np) > offset) { + nnext = np; + continue; + } + } + + np = nnext; + nnext = nnext->avl_forw; + if (!nnext) + nnext = np->avl_parent; + + offset = end; + } +} +#else /* ! AVL_DEBUG */ +#define avl_checktree(t,x) +#endif /* AVL_DEBUG */ + + +/* + * Reset balance for np up through tree. + * ``direction'' is the way that np's balance + * is headed after the deletion of one of its children -- + * e.g., deleting a avl_forw child sends avl_balance toward AVL_BACK. + * Called only when deleting a node from the tree. + */ +static void +retreat( + avltree_desc_t *tree, + register avlnode_t *np, + register int direction) +{ + register avlnode_t **rootp = &tree->avl_root; + register avlnode_t *parent; + register avlnode_t *child; + register avlnode_t *tmp; + register int bal; + + do { + ASSERT(direction == AVL_BACK || direction == AVL_FORW); + + if (np->avl_balance == AVL_BALANCE) { + np->avl_balance = direction; + return; + } + + parent = np->avl_parent; + + /* + * If balance is being restored, no local node + * reorganization is necessary, but may be at + * a higher node. Reset direction and continue. + */ + if (direction != np->avl_balance) { + np->avl_balance = AVL_BALANCE; + if (parent) { + if (parent->avl_forw == np) + direction = AVL_BACK; + else + direction = AVL_FORW; + + np = parent; + continue; + } + return; + } + + /* + * Imbalance. If a avl_forw node was removed, direction + * (and, by reduction, np->avl_balance) is/was AVL_BACK. + */ + if (np->avl_balance == AVL_BACK) { + + ASSERT(direction == AVL_BACK); + child = np->avl_back; + bal = child->avl_balance; + + if (bal != AVL_FORW) /* single LL */ { + /* + * np gets pushed down to lesser child's + * avl_forw branch. + * + * np-> -D +B + * / \ / \ + * child-> B deleted A -D + * / \ / + * A C C + */ +#ifdef AVL_PRINT + if (!(tree->avl_flags & AVLF_DUPLICITY)) + cmn_err(CE_CONT, "!LL delete b 0x%x c 0x%x\n", + np, child); +#endif + np->avl_back = child->avl_forw; + if (child->avl_forw) + child->avl_forw->avl_parent = np; + child->avl_forw = np; + + if (parent) { + if (parent->avl_forw == np) { + parent->avl_forw = child; + direction = AVL_BACK; + } else { + ASSERT(parent->avl_back == np); + parent->avl_back = child; + direction = AVL_FORW; + } + } else { + ASSERT(*rootp == np); + *rootp = child; + } + np->avl_parent = child; + child->avl_parent = parent; + + if (bal == AVL_BALANCE) { + np->avl_balance = AVL_BACK; + child->avl_balance = AVL_FORW; + return; + } else { + np->avl_balance = AVL_BALANCE; + child->avl_balance = AVL_BALANCE; + np = parent; + avl_checktree(tree, *rootp); + continue; + } + } + + /* child->avl_balance == AVL_FORW double LR rotation + * + * child's avl_forw node gets promoted up, along with + * its avl_forw subtree + * + * np-> -G C + * / \ / \ + * child-> +B H -B G + * / \ \ / / \ + * A +C deleted A D H + * \ + * D + */ +#ifdef AVL_PRINT + if (!(tree->avl_flags & AVLF_DUPLICITY)) + cmn_err(CE_CONT, "!LR delete b 0x%x c 0x%x t 0x%x\n", + np, child, child->avl_forw); +#endif + tmp = child->avl_forw; + bal = tmp->avl_balance; + + child->avl_forw = tmp->avl_back; + if (tmp->avl_back) + tmp->avl_back->avl_parent = child; + + tmp->avl_back = child; + child->avl_parent = tmp; + + np->avl_back = tmp->avl_forw; + if (tmp->avl_forw) + tmp->avl_forw->avl_parent = np; + tmp->avl_forw = np; + + if (bal == AVL_FORW) + child->avl_balance = AVL_BACK; + else + child->avl_balance = AVL_BALANCE; + + if (bal == AVL_BACK) + np->avl_balance = AVL_FORW; + else + np->avl_balance = AVL_BALANCE; + + goto next; + } + + ASSERT(np->avl_balance == AVL_FORW && direction == AVL_FORW); + + child = np->avl_forw; + bal = child->avl_balance; + + if (bal != AVL_BACK) /* single RR */ { + /* + * np gets pushed down to greater child's + * avl_back branch. + * + * np-> +B -D + * / \ / \ + * deleted D <-child +B E + * / \ \ + * C E C + */ +#ifdef AVL_PRINT + if (!(tree->avl_flags & AVLF_DUPLICITY)) + cmn_err(CE_CONT, "!RR delete b 0x%x c 0x%x\n", + np, child); +#endif + np->avl_forw = child->avl_back; + if (child->avl_back) + child->avl_back->avl_parent = np; + child->avl_back = np; + + if (parent) { + if (parent->avl_forw == np) { + parent->avl_forw = child; + direction = AVL_BACK; + } else { + ASSERT(parent->avl_back == np); + parent->avl_back = child; + direction = AVL_FORW; + } + } else { + ASSERT(*rootp == np); + *rootp = child; + } + np->avl_parent = child; + child->avl_parent = parent; + + if (bal == AVL_BALANCE) { + np->avl_balance = AVL_FORW; + child->avl_balance = AVL_BACK; + return; + } else { + np->avl_balance = AVL_BALANCE; + child->avl_balance = AVL_BALANCE; + np = parent; + avl_checktree(tree, *rootp); + continue; + } + } + + /* child->avl_balance == AVL_BACK double RL rotation */ +#ifdef AVL_PRINT + if (!(tree->avl_flags & AVLF_DUPLICITY)) + cmn_err(CE_CONT, "!RL delete b 0x%x c 0x%x t 0x%x\n", + np, child, child->avl_back); +#endif + tmp = child->avl_back; + bal = tmp->avl_balance; + + child->avl_back = tmp->avl_forw; + if (tmp->avl_forw) + tmp->avl_forw->avl_parent = child; + + tmp->avl_forw = child; + child->avl_parent = tmp; + + np->avl_forw = tmp->avl_back; + if (tmp->avl_back) + tmp->avl_back->avl_parent = np; + tmp->avl_back = np; + + if (bal == AVL_BACK) + child->avl_balance = AVL_FORW; + else + child->avl_balance = AVL_BALANCE; + + if (bal == AVL_FORW) + np->avl_balance = AVL_BACK; + else + np->avl_balance = AVL_BALANCE; +next: + np->avl_parent = tmp; + tmp->avl_balance = AVL_BALANCE; + tmp->avl_parent = parent; + + if (parent) { + if (parent->avl_forw == np) { + parent->avl_forw = tmp; + direction = AVL_BACK; + } else { + ASSERT(parent->avl_back == np); + parent->avl_back = tmp; + direction = AVL_FORW; + } + } else { + ASSERT(*rootp == np); + *rootp = tmp; + return; + } + + np = parent; + avl_checktree(tree, *rootp); + } while (np); +} + +/* + * Remove node from tree. + * avl_delete does the local tree manipulations, + * calls retreat() to rebalance tree up to its root. + */ +void +avl_delete( + register avltree_desc_t *tree, + register avlnode_t *np) +{ + register avlnode_t *forw = np->avl_forw; + register avlnode_t *back = np->avl_back; + register avlnode_t *parent = np->avl_parent; + register avlnode_t *nnext; + + + if (np->avl_back) { + /* + * a left child exits, then greatest left descendent's nextino + * is pointing to np; make it point to np->nextino. + */ + nnext = np->avl_back; + while (nnext) { + if (!nnext->avl_forw) + break; /* can't find anything bigger */ + nnext = nnext->avl_forw; + } + } else + if (np->avl_parent) { + /* + * find nearest ancestor with lesser value. That ancestor's + * nextino is pointing to np; make it point to np->nextino + */ + nnext = np->avl_parent; + while (nnext) { + if (AVL_END(tree, nnext) <= AVL_END(tree, np)) + break; + nnext = nnext->avl_parent; + } + } else + nnext = NULL; + + if (nnext) { + ASSERT(nnext->avl_nextino == np); + nnext->avl_nextino = np->avl_nextino; + /* + * Something preceeds np; np cannot be firstino. + */ + ASSERT(tree->avl_firstino != np); + } + else { + /* + * Nothing preceeding np; after deletion, np's nextino + * is firstino of tree. + */ + ASSERT(tree->avl_firstino == np); + tree->avl_firstino = np->avl_nextino; + } + + + /* + * Degenerate cases... + */ + if (forw == NULL) { + forw = back; + goto attach; + } + + if (back == NULL) { +attach: + if (forw) + forw->avl_parent = parent; + if (parent) { + if (parent->avl_forw == np) { + parent->avl_forw = forw; + retreat(tree, parent, AVL_BACK); + } else { + ASSERT(parent->avl_back == np); + parent->avl_back = forw; + retreat(tree, parent, AVL_FORW); + } + } else { + ASSERT(tree->avl_root == np); + tree->avl_root = forw; + } + avl_checktree(tree, tree->avl_root); + return; + } + + /* + * Harder case: children on both sides. + * If back's avl_forw pointer is null, just have back + * inherit np's avl_forw tree, remove np from the tree + * and adjust balance counters starting at back. + * + * np-> xI xH (befor retreat()) + * / \ / \ + * back-> H J G J + * / / \ / \ + * G ? ? ? ? + * / \ + * ? ? + */ + if ((forw = back->avl_forw) == NULL) { + /* + * AVL_FORW retreat below will set back's + * balance to AVL_BACK. + */ + back->avl_balance = np->avl_balance; + back->avl_forw = forw = np->avl_forw; + forw->avl_parent = back; + back->avl_parent = parent; + + if (parent) { + if (parent->avl_forw == np) + parent->avl_forw = back; + else { + ASSERT(parent->avl_back == np); + parent->avl_back = back; + } + } else { + ASSERT(tree->avl_root == np); + tree->avl_root = back; + } + + /* + * back is taking np's place in the tree, and + * has therefore lost a avl_back node (itself). + */ + retreat(tree, back, AVL_FORW); + avl_checktree(tree, tree->avl_root); + return; + } + + /* + * Hardest case: children on both sides, and back's + * avl_forw pointer isn't null. Find the immediately + * inferior buffer by following back's avl_forw line + * to the end, then have it inherit np's avl_forw tree. + * + * np-> xI xH + * / \ / \ + * G J back-> G J (before retreat()) + * / \ / \ + * F ?... F ?1 + * / \ + * ? H <-forw + * / + * ?1 + */ + while ((back = forw->avl_forw)) + forw = back; + + /* + * Will be adjusted by retreat() below. + */ + forw->avl_balance = np->avl_balance; + + /* + * forw inherits np's avl_forw... + */ + forw->avl_forw = np->avl_forw; + np->avl_forw->avl_parent = forw; + + /* + * ... forw's parent gets forw's avl_back... + */ + back = forw->avl_parent; + back->avl_forw = forw->avl_back; + if (forw->avl_back) + forw->avl_back->avl_parent = back; + + /* + * ... forw gets np's avl_back... + */ + forw->avl_back = np->avl_back; + np->avl_back->avl_parent = forw; + + /* + * ... and forw gets np's parent. + */ + forw->avl_parent = parent; + + if (parent) { + if (parent->avl_forw == np) + parent->avl_forw = forw; + else + parent->avl_back = forw; + } else { + ASSERT(tree->avl_root == np); + tree->avl_root = forw; + } + + /* + * What used to be forw's parent is the starting + * point for rebalancing. It has lost a avl_forw node. + */ + retreat(tree, back, AVL_BACK); + avl_checktree(tree, tree->avl_root); +} + + +/* + * avl_findanyrange: + * + * Given range r [start, end), find any range which is contained in r. + * if checklen is non-zero, then only ranges of non-zero length are + * considered in finding a match. + */ +avlnode_t * +avl_findanyrange( + register avltree_desc_t *tree, + register __psunsigned_t start, + register __psunsigned_t end, + int checklen) +{ + register avlnode_t *np = tree->avl_root; + + /* np = avl_findadjacent(tree, start, AVL_SUCCEED); */ + while (np) { + if (start < AVL_START(tree, np)) { + if (np->avl_back) { + np = np->avl_back; + continue; + } + /* if we were to add node with start, would + * have a growth of AVL_BACK + */ + /* if succeeding node is needed, this is it. + */ + break; + } + if (start >= AVL_END(tree, np)) { + if (np->avl_forw) { + np = np->avl_forw; + continue; + } + /* if we were to add node with start, would + * have a growth of AVL_FORW; + */ + /* we are looking for a succeeding node; + * this is nextino. + */ + np = np->avl_nextino; + break; + } + /* AVL_START(tree, np) <= start < AVL_END(tree, np) */ + break; + } + if (np) { + if (checklen == AVL_INCLUDE_ZEROLEN) { + if (end <= AVL_START(tree, np)) { + /* something follows start, but is + * is entierly after the range (end) + */ + return(NULL); + } + /* np may stradle [start, end) */ + return(np); + } + /* + * find non-zero length region + */ + while (np && (AVL_END(tree, np) - AVL_START(tree, np) == 0) + && (AVL_START(tree, np) < end)) + np = np->avl_nextino; + + if ((np == NULL) || (AVL_START(tree, np) >= end)) + return NULL; + return(np); + } + /* + * nothing succeeds start, all existing ranges are before start. + */ + return NULL; +} + + +/* + * Returns a pointer to range which contains value. + */ +avlnode_t * +avl_findrange( + register avltree_desc_t *tree, + register __psunsigned_t value) +{ + register avlnode_t *np = tree->avl_root; + + while (np) { + if (value < AVL_START(tree, np)) { + np = np->avl_back; + continue; + } + if (value >= AVL_END(tree, np)) { + np = np->avl_forw; + continue; + } + ASSERT(AVL_START(tree, np) <= value && + value < AVL_END(tree, np)); + return np; + } + return NULL; +} + + +/* + * Returns a pointer to node which contains exact value. + */ +avlnode_t * +avl_find( + register avltree_desc_t *tree, + register __psunsigned_t value) +{ + register avlnode_t *np = tree->avl_root; + register __psunsigned_t nvalue; + + while (np) { + nvalue = AVL_START(tree, np); + if (value < nvalue) { + np = np->avl_back; + continue; + } + if (value == nvalue) { + return np; + } + np = np->avl_forw; + } + return NULL; +} + + +/* + * Balance buffer AVL tree after attaching a new node to root. + * Called only by avl_insert. + */ +static void +avl_balance( + register avlnode_t **rootp, + register avlnode_t *np, + register int growth) +{ + /* + * At this point, np points to the node to which + * a new node has been attached. All that remains is to + * propagate avl_balance up the tree. + */ + for ( ; ; ) { + register avlnode_t *parent = np->avl_parent; + register avlnode_t *child; + + CERT(growth == AVL_BACK || growth == AVL_FORW); + + /* + * If the buffer was already balanced, set avl_balance + * to the new direction. Continue if there is a + * parent after setting growth to reflect np's + * relation to its parent. + */ + if (np->avl_balance == AVL_BALANCE) { + np->avl_balance = growth; + if (parent) { + if (parent->avl_forw == np) + growth = AVL_FORW; + else { + ASSERT(parent->avl_back == np); + growth = AVL_BACK; + } + + np = parent; + continue; + } + break; + } + + if (growth != np->avl_balance) { + /* + * Subtree is now balanced -- no net effect + * in the size of the subtree, so leave. + */ + np->avl_balance = AVL_BALANCE; + break; + } + + if (growth == AVL_BACK) { + + child = np->avl_back; + CERT(np->avl_balance == AVL_BACK && child); + + if (child->avl_balance == AVL_BACK) { /* single LL */ + /* + * ``A'' just got inserted; + * np points to ``E'', child to ``C'', + * and it is already AVL_BACK -- + * child will get promoted to top of subtree. + + np-> -E C + / \ / \ + child-> -C F -B E + / \ / / \ + -B D A D F + / + A + + Note that child->avl_parent and + avl_balance get set in common code. + */ + np->avl_parent = child; + np->avl_balance = AVL_BALANCE; + np->avl_back = child->avl_forw; + if (child->avl_forw) + child->avl_forw->avl_parent = np; + child->avl_forw = np; + } else { + /* + * double LR + * + * child's avl_forw node gets promoted to + * the top of the subtree. + + np-> -E C + / \ / \ + child-> +B F -B E + / \ / / \ + A +C A D F + \ + D + + */ + register avlnode_t *tmp = child->avl_forw; + + CERT(child->avl_balance == AVL_FORW && tmp); + + child->avl_forw = tmp->avl_back; + if (tmp->avl_back) + tmp->avl_back->avl_parent = child; + + tmp->avl_back = child; + child->avl_parent = tmp; + + np->avl_back = tmp->avl_forw; + if (tmp->avl_forw) + tmp->avl_forw->avl_parent = np; + + tmp->avl_forw = np; + np->avl_parent = tmp; + + if (tmp->avl_balance == AVL_BACK) + np->avl_balance = AVL_FORW; + else + np->avl_balance = AVL_BALANCE; + + if (tmp->avl_balance == AVL_FORW) + child->avl_balance = AVL_BACK; + else + child->avl_balance = AVL_BALANCE; + + /* + * Set child to point to tmp since it is + * now the top of the subtree, and will + * get attached to the subtree parent in + * the common code below. + */ + child = tmp; + } + + } else /* growth == AVL_BACK */ { + + /* + * This code is the mirror image of AVL_FORW above. + */ + + child = np->avl_forw; + CERT(np->avl_balance == AVL_FORW && child); + + if (child->avl_balance == AVL_FORW) { /* single RR */ + np->avl_parent = child; + np->avl_balance = AVL_BALANCE; + np->avl_forw = child->avl_back; + if (child->avl_back) + child->avl_back->avl_parent = np; + child->avl_back = np; + } else { + /* + * double RL + */ + register avlnode_t *tmp = child->avl_back; + + ASSERT(child->avl_balance == AVL_BACK && tmp); + + child->avl_back = tmp->avl_forw; + if (tmp->avl_forw) + tmp->avl_forw->avl_parent = child; + + tmp->avl_forw = child; + child->avl_parent = tmp; + + np->avl_forw = tmp->avl_back; + if (tmp->avl_back) + tmp->avl_back->avl_parent = np; + + tmp->avl_back = np; + np->avl_parent = tmp; + + if (tmp->avl_balance == AVL_FORW) + np->avl_balance = AVL_BACK; + else + np->avl_balance = AVL_BALANCE; + + if (tmp->avl_balance == AVL_BACK) + child->avl_balance = AVL_FORW; + else + child->avl_balance = AVL_BALANCE; + + child = tmp; + } + } + + child->avl_parent = parent; + child->avl_balance = AVL_BALANCE; + + if (parent) { + if (parent->avl_back == np) + parent->avl_back = child; + else + parent->avl_forw = child; + } else { + ASSERT(*rootp == np); + *rootp = child; + } + + break; + } +} + +static +avlnode_t * +avl_insert_find_growth( + register avltree_desc_t *tree, + register __psunsigned_t start, /* range start at start, */ + register __psunsigned_t end, /* exclusive */ + register int *growthp) /* OUT */ +{ + avlnode_t *root = tree->avl_root; + register avlnode_t *np; + + np = root; + ASSERT(np); /* caller ensures that there is atleast one node in tree */ + + for ( ; ; ) { + CERT(np->avl_parent || root == np); + CERT(!np->avl_parent || root != np); + CERT(!(np->avl_back) || np->avl_back->avl_parent == np); + CERT(!(np->avl_forw) || np->avl_forw->avl_parent == np); + CERT(np->avl_balance != AVL_FORW || np->avl_forw); + CERT(np->avl_balance != AVL_BACK || np->avl_back); + CERT(np->avl_balance != AVL_BALANCE || + np->avl_back == NULL || np->avl_forw); + CERT(np->avl_balance != AVL_BALANCE || + np->avl_forw == NULL || np->avl_back); + + if (AVL_START(tree, np) >= end) { + if (np->avl_back) { + np = np->avl_back; + continue; + } + *growthp = AVL_BACK; + break; + } + + if (AVL_END(tree, np) <= start) { + if (np->avl_forw) { + np = np->avl_forw; + continue; + } + *growthp = AVL_FORW; + break; + } + /* found exact match -- let caller decide if it is an error */ + return(NULL); + } + return(np); +} + + +static void +avl_insert_grow( + register avltree_desc_t *tree, + register avlnode_t *parent, + register avlnode_t *newnode, + register int growth) +{ + register avlnode_t *nnext; + register __psunsigned_t start = AVL_START(tree, newnode); + + if (growth == AVL_BACK) { + + parent->avl_back = newnode; + /* + * we are growing to the left; previous in-order to newnode is + * closest ancestor with lesser value. Before this + * insertion, this ancestor will be pointing to + * newnode's parent. After insertion, next in-order to newnode + * is the parent. + */ + newnode->avl_nextino = parent; + nnext = parent; + while (nnext) { + if (AVL_END(tree, nnext) <= start) + break; + nnext = nnext->avl_parent; + } + if (nnext) { + /* + * nnext will be null if newnode is + * the least element, and hence very first in the list. + */ + ASSERT(nnext->avl_nextino == parent); + nnext->avl_nextino = newnode; + } + } + else { + parent->avl_forw = newnode; + newnode->avl_nextino = parent->avl_nextino; + parent->avl_nextino = newnode; + } +} + + +avlnode_t * +avl_insert( + register avltree_desc_t *tree, + register avlnode_t *newnode) +{ + register avlnode_t *np; + register __psunsigned_t start = AVL_START(tree, newnode); + register __psunsigned_t end = AVL_END(tree, newnode); + int growth; + + ASSERT(newnode); + ASSERT(start <= end); + + /* + * Clean all pointers for sanity; some will be reset as necessary. + */ + newnode->avl_nextino = NULL; + newnode->avl_parent = NULL; + newnode->avl_forw = NULL; + newnode->avl_back = NULL; + newnode->avl_balance = AVL_BALANCE; + + if ((np = tree->avl_root) == NULL) { /* degenerate case... */ + tree->avl_root = newnode; + tree->avl_firstino = newnode; + return newnode; + } + + if ((np = avl_insert_find_growth(tree, start, end, &growth)) == NULL) { + if (start != end) { /* non-zero length range */ +#ifdef AVL_USER_MODE + printf( + "avl_insert: Warning! duplicate range [0x%llx,0x%lx)\n", + (unsigned long long)start, (unsigned long)end); +#else + /* + * lockmetering tree can't afford printfs here. + */ + if (!(tree->avl_flags & AVLF_DUPLICITY)) + cmn_err(CE_CONT, + "!avl_insert: Warning! duplicate range [0x%x,0x%x)\n", + start, end); +#endif + } + return(NULL); + } + + avl_insert_grow(tree, np, newnode, growth); + if (growth == AVL_BACK) { + /* + * Growing to left. if np was firstino, newnode will be firstino + */ + if (tree->avl_firstino == np) + tree->avl_firstino = newnode; + } +#ifdef notneeded + else + if (growth == AVL_FORW) + /* + * Cannot possibly be firstino; there is somebody to our left. + */ + ; +#endif + + newnode->avl_parent = np; + CERT(np->avl_forw == newnode || np->avl_back == newnode); + + avl_balance(&tree->avl_root, np, growth); + + avl_checktree(tree, tree->avl_root); + + return newnode; +} + +/* + * + * avl_insert_immediate(tree, afterp, newnode): + * insert newnode immediately into tree immediately after afterp. + * after insertion, newnode is right child of afterp. + */ +void +avl_insert_immediate( + avltree_desc_t *tree, + avlnode_t *afterp, + avlnode_t *newnode) +{ + /* + * Clean all pointers for sanity; some will be reset as necessary. + */ + newnode->avl_nextino = NULL; + newnode->avl_parent = NULL; + newnode->avl_forw = NULL; + newnode->avl_back = NULL; + newnode->avl_balance = AVL_BALANCE; + + if (afterp == NULL) { + tree->avl_root = newnode; + tree->avl_firstino = newnode; + return; + } + + ASSERT(afterp->avl_forw == NULL); + avl_insert_grow(tree, afterp, newnode, AVL_FORW); /* grow to right */ + CERT(afterp->avl_forw == newnode); + avl_balance(&tree->avl_root, afterp, AVL_FORW); + avl_checktree(tree, tree->avl_root); +} + + +/* + * Returns first in order node + */ +avlnode_t * +avl_firstino(register avlnode_t *root) +{ + register avlnode_t *np; + + if ((np = root) == NULL) + return NULL; + + while (np->avl_back) + np = np->avl_back; + return np; +} + +#ifdef AVL_USER_MODE +/* + * leave this as a user-mode only routine until someone actually + * needs it in the kernel + */ + +/* + * Returns last in order node + */ +avlnode_t * +avl_lastino(register avlnode_t *root) +{ + register avlnode_t *np; + + if ((np = root) == NULL) + return NULL; + + while (np->avl_forw) + np = np->avl_forw; + return np; +} +#endif + +void +avl_init_tree(avltree_desc_t *tree, avlops_t *ops) +{ + tree->avl_root = NULL; + tree->avl_firstino = NULL; + tree->avl_ops = ops; +} + +#ifdef AVL_DEBUG +static void +avl_printnode(avltree_desc_t *tree, avlnode_t *np, int nl) +{ + printf("[%d-%d]%c", AVL_START(tree, np), + (AVL_END(tree, np) - 1), nl ? '\n' : ' '); +} +#endif +#ifdef STAND_ALONE_DEBUG + +struct avl_debug_node { + avlnode_t avl_node; + xfs_off_t avl_start; + unsigned int avl_size; +} + +avlops_t avl_debug_ops = { + avl_debug_start, + avl_debug_end, +} + +static __psunsigned_t +avl_debug_start(avlnode_t *node) +{ + return (__psunsigned_t)(struct avl_debug_node *)node->avl_start; +} + +static __psunsigned_t +avl_debug_end(avlnode_t *node) +{ + return (__psunsigned_t) + ((struct avl_debug_node *)node->avl_start + + (struct avl_debug_node *)node->avl_size); +} + +avl_debug_node freenodes[100]; +avl_debug_node *freehead = &freenodes[0]; + +static avlnode_t * +alloc_avl_debug_node() +{ + freehead->avl_balance = AVL_BALANCE; + freehead->avl_parent = freehead->avl_forw = freehead->avl_back = NULL; + return(freehead++); +} + +static void +avl_print(avltree_desc_t *tree, avlnode_t *root, int depth) +{ + int i; + + if (!root) + return; + if (root->avl_forw) + avl_print(tree, root->avl_forw, depth+5); + for (i = 0; i < depth; i++) + putchar((int) ' '); + avl_printnode(tree, root,1); + if (root->avl_back) + avl_print(tree, root->avl_back, depth+5); +} + +main() +{ + int i, j; + avlnode_t *np; + avltree_desc_t tree; + char linebuf[256], cmd[256]; + + avl_init_tree(&tree, &avl_debug_ops); + + for (i = 100; i > 0; i = i - 10) + { + np = alloc__debug_avlnode(); + ASSERT(np); + np->avl_start = i; + np->avl_size = 10; + avl_insert(&tree, np); + } + avl_print(&tree, tree.avl_root, 0); + + for (np = tree.avl_firstino; np != NULL; np = np->avl_nextino) + avl_printnode(&tree, np, 0); + printf("\n"); + + while (1) { + printf("Command [fpdir] : "); + fgets(linebuf, 256, stdin); + if (feof(stdin)) break; + cmd[0] = NULL; + if (sscanf(linebuf, "%[fpdir]%d", cmd, &i) != 2) + continue; + switch (cmd[0]) { + case 'd': + case 'f': + printf("end of range ? "); + fgets(linebuf, 256, stdin); + j = atoi(linebuf); + + if (i == j) j = i+1; + np = avl_findinrange(&tree,i,j); + if (np) { + avl_printnode(&tree, np, 1); + if (cmd[0] == 'd') + avl_delete(&tree, np); + } else + printf("Cannot find %d\n", i); + break; + case 'p': + avl_print(&tree, tree.avl_root, 0); + for (np = tree.avl_firstino; + np != NULL; np = np->avl_nextino) + avl_printnode(&tree, np, 0); + printf("\n"); + break; + case 'i': + np = alloc_avlnode(); + ASSERT(np); + np->avl_start = i; + printf("size of range ? "); + fgets(linebuf, 256, stdin); + j = atoi(linebuf); + + np->avl_size = j; + avl_insert(&tree, np); + break; + case 'r': { + avlnode_t *b, *e, *t; + int checklen; + + printf("End of range ? "); + fgets(linebuf, 256, stdin); + j = atoi(linebuf); + + printf("checklen 0/1 ? "); + fgets(linebuf, 256, stdin); + checklen = atoi(linebuf); + + + b = avl_findanyrange(&tree, i, j, checklen); + if (b) { + printf("Found something\n"); + t = b; + while (t) { + if (t != b && + AVL_START(&tree, t) >= j) + break; + avl_printnode(&tree, t, 0); + t = t->avl_nextino; + } + printf("\n"); + } + } + } + } +} +#endif + +/* + * Given a tree, find value; will find return range enclosing value, + * or range immediately succeeding value, + * or range immediately preceeding value. + */ +avlnode_t * +avl_findadjacent( + register avltree_desc_t *tree, + register __psunsigned_t value, + register int dir) +{ + register avlnode_t *np = tree->avl_root; + + while (np) { + if (value < AVL_START(tree, np)) { + if (np->avl_back) { + np = np->avl_back; + continue; + } + /* if we were to add node with value, would + * have a growth of AVL_BACK + */ + if (dir == AVL_SUCCEED) { + /* if succeeding node is needed, this is it. + */ + return(np); + } + if (dir == AVL_PRECEED) { + /* + * find nearest ancestor with lesser value. + */ + np = np->avl_parent; + while (np) { + if (AVL_END(tree, np) <= value) + break; + np = np->avl_parent; + } + return(np); + } + ASSERT(dir == AVL_SUCCEED || dir == AVL_PRECEED); + break; + } + if (value >= AVL_END(tree, np)) { + if (np->avl_forw) { + np = np->avl_forw; + continue; + } + /* if we were to add node with value, would + * have a growth of AVL_FORW; + */ + if (dir == AVL_SUCCEED) { + /* we are looking for a succeeding node; + * this is nextino. + */ + return(np->avl_nextino); + } + if (dir == AVL_PRECEED) { + /* looking for a preceeding node; this is it. */ + return(np); + } + ASSERT(dir == AVL_SUCCEED || dir == AVL_PRECEED); + } + /* AVL_START(tree, np) <= value < AVL_END(tree, np) */ + return(np); + } + return NULL; +} + + +#ifdef AVL_FUTURE_ENHANCEMENTS +/* + * avl_findranges: + * + * Given range r [start, end), find all ranges in tree which are contained + * in r. At return, startp and endp point to first and last of + * a chain of elements which describe the contained ranges. Elements + * in startp ... endp are in sort order, and can be accessed by + * using avl_nextino. + */ + +void +avl_findranges( + register avltree_desc_t *tree, + register __psunsigned_t start, + register __psunsigned_t end, + avlnode_t **startp, + avlnode_t **endp) +{ + register avlnode_t *np; + + np = avl_findadjacent(tree, start, AVL_SUCCEED); + if (np == NULL /* nothing succeding start */ + || (np && (end <= AVL_START(tree, np)))) + /* something follows start, + but... is entirely after end */ + { + *startp = NULL; + *endp = NULL; + return; + } + + *startp = np; + + /* see if end is in this region itself */ + if (end <= AVL_END(tree, np) || + np->avl_nextino == NULL || + (np->avl_nextino && + (end <= AVL_START(tree, np->avl_nextino)))) { + *endp = np; + return; + } + /* have to munge for end */ + /* + * note: have to look for (end - 1), since + * findadjacent will look for exact value, and does not + * care about the fact that end is actually one more + * than the value actually being looked for; thus feed it one less. + */ + *endp = avl_findadjacent(tree, (end-1), AVL_PRECEED); + ASSERT(*endp); +} + +#endif /* AVL_FUTURE_ENHANCEMENTS */ diff -rNu linux-2.4.7/cmd/xfsprogs/repair/avl.h linux-2.4-xfs/cmd/xfsprogs/repair/avl.h --- linux-2.4.7/cmd/xfsprogs/repair/avl.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/avl.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,143 @@ +/************************************************************************** + * * + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + * * + **************************************************************************/ +#ifndef __SYS_AVL_H__ +#define __SYS_AVL_H__ + + +typedef struct avlnode { + struct avlnode *avl_forw; /* pointer to right child (> parent) */ + struct avlnode *avl_back; /* pointer to left child (< parent) */ + struct avlnode *avl_parent; /* parent pointer */ + struct avlnode *avl_nextino; /* next in-order; NULL terminated list*/ + char avl_balance; /* tree balance */ +} avlnode_t; + +/* + * avl-tree operations + */ +typedef struct avlops { + __psunsigned_t (*avl_start)(avlnode_t *); + __psunsigned_t (*avl_end)(avlnode_t *); +} avlops_t; + +#define AVL_START(tree, n) (*(tree)->avl_ops->avl_start)(n) +#define AVL_END(tree, n) (*(tree)->avl_ops->avl_end)(n) + +/* + * tree descriptor: + * root points to the root of the tree. + * firstino points to the first in the ordered list. + */ +typedef struct avltree_desc { + avlnode_t *avl_root; + avlnode_t *avl_firstino; + avlops_t *avl_ops; + short avl_flags; +} avltree_desc_t; + +/* possible values for avl_balance */ + +#define AVL_BACK 1 +#define AVL_BALANCE 0 +#define AVL_FORW 2 + +/* possible values for avl_flags */ + +#define AVLF_DUPLICITY 0x0001 /* no warnings on insert dups */ + +/* + * 'Exported' avl tree routines + */ +avlnode_t +*avl_insert( + avltree_desc_t *tree, + avlnode_t *newnode); + +void +avl_delete( + avltree_desc_t *tree, + avlnode_t *np); + +void +avl_insert_immediate( + avltree_desc_t *tree, + avlnode_t *afterp, + avlnode_t *newnode); + +void +avl_init_tree( + avltree_desc_t *tree, + avlops_t *ops); + +avlnode_t * +avl_findrange( + avltree_desc_t *tree, + __psunsigned_t value); + +avlnode_t * +avl_find( + avltree_desc_t *tree, + __psunsigned_t value); + +avlnode_t * +avl_findanyrange( + avltree_desc_t *tree, + __psunsigned_t start, + __psunsigned_t end, + int checklen); + + +avlnode_t * +avl_findadjacent( + avltree_desc_t *tree, + __psunsigned_t value, + int dir); + +#ifdef AVL_FUTURE_ENHANCEMENTS +void +avl_findranges( + register avltree_desc_t *tree, + register __psunsigned_t start, + register __psunsigned_t end, + avlnode_t **startp, + avlnode_t **endp); +#endif + +#define AVL_PRECEED 0x1 +#define AVL_SUCCEED 0x2 + +#define AVL_INCLUDE_ZEROLEN 0x0000 +#define AVL_EXCLUDE_ZEROLEN 0x0001 + +#endif /* __SYS_AVL_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/repair/avl64.c linux-2.4-xfs/cmd/xfsprogs/repair/avl64.c --- linux-2.4.7/cmd/xfsprogs/repair/avl64.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/avl64.c Thu Apr 12 18:49:04 2001 @@ -0,0 +1,1458 @@ +/************************************************************************** + * * + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + * * + **************************************************************************/ + +/* to allow use by user-level utilities */ + +#ifdef STAND_ALONE_DEBUG +#define AVL_USER_MODE +#endif + +#if defined(STAND_ALONE_DEBUG) || defined(AVL_USER_MODE_DEBUG) +#define AVL_DEBUG +#endif + +#include +#include +#include "avl64.h" + +#define CERT ASSERT + +#ifdef AVL_DEBUG + +static void +avl64_checknode( + register avl64tree_desc_t *tree, + register avl64node_t *np) +{ + register avl64node_t *back = np->avl_back; + register avl64node_t *forw = np->avl_forw; + register avl64node_t *nextino = np->avl_nextino; + register int bal = np->avl_balance; + + ASSERT(bal != AVL_BALANCE || (!back && !forw) || (back && forw)); + ASSERT(bal != AVL_FORW || forw); + ASSERT(bal != AVL_BACK || back); + + if (forw) { + ASSERT(AVL_START(tree, np) < AVL_START(tree, forw)); + ASSERT(np->avl_forw->avl_parent == np); + ASSERT(back || bal == AVL_FORW); + } else { + ASSERT(bal != AVL_FORW); + ASSERT(bal == AVL_BALANCE || back); + ASSERT(bal == AVL_BACK || !back); + } + + if (back) { + ASSERT(AVL_START(tree, np) > AVL_START(tree, back)); + ASSERT(np->avl_back->avl_parent == np); + ASSERT(forw || bal == AVL_BACK); + } else { + ASSERT(bal != AVL_BACK); + ASSERT(bal == AVL_BALANCE || forw); + ASSERT(bal == AVL_FORW || !forw); + } + + if (nextino == NULL) + ASSERT(forw == NULL); + else + ASSERT(AVL_END(tree, np) <= AVL_START(tree, nextino)); +} + +static void +avl64_checktree( + register avl64tree_desc_t *tree, + register avl64node_t *root) +{ + register avl64node_t *nlast, *nnext, *np; + __uint64_t offset = 0; + __uint64_t end; + + nlast = nnext = root; + + ASSERT(!nnext || nnext->avl_parent == NULL); + + while (nnext) { + + avl64_checknode(tree, nnext); + end = AVL_END(tree, nnext); + + if (end <= offset) { + if ((np = nnext->avl_forw) && np != nlast) { + nlast = nnext; + nnext = np; + } else { + nlast = nnext; + nnext = nnext->avl_parent; + } + continue; + } + + nlast = nnext; + if (np = nnext->avl_back) { + if (AVL_END(tree, np) > offset) { + nnext = np; + continue; + } + } + + np = nnext; + nnext = nnext->avl_forw; + if (!nnext) + nnext = np->avl_parent; + + offset = end; + } +} +#else /* ! AVL_DEBUG */ +#define avl64_checktree(t,x) +#endif /* AVL_DEBUG */ + + +/* + * Reset balance for np up through tree. + * ``direction'' is the way that np's balance + * is headed after the deletion of one of its children -- + * e.g., deleting a avl_forw child sends avl_balance toward AVL_BACK. + * Called only when deleting a node from the tree. + */ +static void +retreat( + avl64tree_desc_t *tree, + register avl64node_t *np, + register int direction) +{ + register avl64node_t **rootp = &tree->avl_root; + register avl64node_t *parent; + register avl64node_t *child; + register avl64node_t *tmp; + register int bal; + + do { + ASSERT(direction == AVL_BACK || direction == AVL_FORW); + + if (np->avl_balance == AVL_BALANCE) { + np->avl_balance = direction; + return; + } + + parent = np->avl_parent; + + /* + * If balance is being restored, no local node + * reorganization is necessary, but may be at + * a higher node. Reset direction and continue. + */ + if (direction != np->avl_balance) { + np->avl_balance = AVL_BALANCE; + if (parent) { + if (parent->avl_forw == np) + direction = AVL_BACK; + else + direction = AVL_FORW; + + np = parent; + continue; + } + return; + } + + /* + * Imbalance. If a avl_forw node was removed, direction + * (and, by reduction, np->avl_balance) is/was AVL_BACK. + */ + if (np->avl_balance == AVL_BACK) { + + ASSERT(direction == AVL_BACK); + child = np->avl_back; + bal = child->avl_balance; + + if (bal != AVL_FORW) /* single LL */ { + /* + * np gets pushed down to lesser child's + * avl_forw branch. + * + * np-> -D +B + * / \ / \ + * child-> B deleted A -D + * / \ / + * A C C + cmn_err(CE_CONT, "!LL delete b 0x%x c 0x%x\n", + np, child); + */ + + np->avl_back = child->avl_forw; + if (child->avl_forw) + child->avl_forw->avl_parent = np; + child->avl_forw = np; + + if (parent) { + if (parent->avl_forw == np) { + parent->avl_forw = child; + direction = AVL_BACK; + } else { + ASSERT(parent->avl_back == np); + parent->avl_back = child; + direction = AVL_FORW; + } + } else { + ASSERT(*rootp == np); + *rootp = child; + } + np->avl_parent = child; + child->avl_parent = parent; + + if (bal == AVL_BALANCE) { + np->avl_balance = AVL_BACK; + child->avl_balance = AVL_FORW; + return; + } else { + np->avl_balance = AVL_BALANCE; + child->avl_balance = AVL_BALANCE; + np = parent; + avl64_checktree(tree, *rootp); + continue; + } + } + + /* child->avl_balance == AVL_FORW double LR rotation + * + * child's avl_forw node gets promoted up, along with + * its avl_forw subtree + * + * np-> -G C + * / \ / \ + * child-> +B H -B G + * / \ \ / / \ + * A +C deleted A D H + * \ + * D + cmn_err(CE_CONT, "!LR delete b 0x%x c 0x%x t 0x%x\n", + np, child, child->avl_forw); + */ + + tmp = child->avl_forw; + bal = tmp->avl_balance; + + child->avl_forw = tmp->avl_back; + if (tmp->avl_back) + tmp->avl_back->avl_parent = child; + + tmp->avl_back = child; + child->avl_parent = tmp; + + np->avl_back = tmp->avl_forw; + if (tmp->avl_forw) + tmp->avl_forw->avl_parent = np; + tmp->avl_forw = np; + + if (bal == AVL_FORW) + child->avl_balance = AVL_BACK; + else + child->avl_balance = AVL_BALANCE; + + if (bal == AVL_BACK) + np->avl_balance = AVL_FORW; + else + np->avl_balance = AVL_BALANCE; + + goto next; + } + + ASSERT(np->avl_balance == AVL_FORW && direction == AVL_FORW); + + child = np->avl_forw; + bal = child->avl_balance; + + if (bal != AVL_BACK) /* single RR */ { + /* + * np gets pushed down to greater child's + * avl_back branch. + * + * np-> +B -D + * / \ / \ + * deleted D <-child +B E + * / \ \ + * C E C + cmn_err(CE_CONT, "!RR delete b 0x%x c 0x%x\n", + np, child); + */ + + np->avl_forw = child->avl_back; + if (child->avl_back) + child->avl_back->avl_parent = np; + child->avl_back = np; + + if (parent) { + if (parent->avl_forw == np) { + parent->avl_forw = child; + direction = AVL_BACK; + } else { + ASSERT(parent->avl_back == np); + parent->avl_back = child; + direction = AVL_FORW; + } + } else { + ASSERT(*rootp == np); + *rootp = child; + } + np->avl_parent = child; + child->avl_parent = parent; + + if (bal == AVL_BALANCE) { + np->avl_balance = AVL_FORW; + child->avl_balance = AVL_BACK; + return; + } else { + np->avl_balance = AVL_BALANCE; + child->avl_balance = AVL_BALANCE; + np = parent; + avl64_checktree(tree, *rootp); + continue; + } + } + + /* child->avl_balance == AVL_BACK double RL rotation + cmn_err(CE_CONT, "!RL delete b 0x%x c 0x%x t 0x%x\n", + np, child, child->avl_back); + */ + + tmp = child->avl_back; + bal = tmp->avl_balance; + + child->avl_back = tmp->avl_forw; + if (tmp->avl_forw) + tmp->avl_forw->avl_parent = child; + + tmp->avl_forw = child; + child->avl_parent = tmp; + + np->avl_forw = tmp->avl_back; + if (tmp->avl_back) + tmp->avl_back->avl_parent = np; + tmp->avl_back = np; + + if (bal == AVL_BACK) + child->avl_balance = AVL_FORW; + else + child->avl_balance = AVL_BALANCE; + + if (bal == AVL_FORW) + np->avl_balance = AVL_BACK; + else + np->avl_balance = AVL_BALANCE; +next: + np->avl_parent = tmp; + tmp->avl_balance = AVL_BALANCE; + tmp->avl_parent = parent; + + if (parent) { + if (parent->avl_forw == np) { + parent->avl_forw = tmp; + direction = AVL_BACK; + } else { + ASSERT(parent->avl_back == np); + parent->avl_back = tmp; + direction = AVL_FORW; + } + } else { + ASSERT(*rootp == np); + *rootp = tmp; + return; + } + + np = parent; + avl64_checktree(tree, *rootp); + } while (np); +} + +/* + * Remove node from tree. + * avl_delete does the local tree manipulations, + * calls retreat() to rebalance tree up to its root. + */ +void +avl64_delete( + register avl64tree_desc_t *tree, + register avl64node_t *np) +{ + register avl64node_t *forw = np->avl_forw; + register avl64node_t *back = np->avl_back; + register avl64node_t *parent = np->avl_parent; + register avl64node_t *nnext; + + + if (np->avl_back) { + /* + * a left child exits, then greatest left descendent's nextino + * is pointing to np; make it point to np->nextino. + */ + nnext = np->avl_back; + while (nnext) { + if (!nnext->avl_forw) + break; /* can't find anything bigger */ + nnext = nnext->avl_forw; + } + } else + if (np->avl_parent) { + /* + * find nearest ancestor with lesser value. That ancestor's + * nextino is pointing to np; make it point to np->nextino + */ + nnext = np->avl_parent; + while (nnext) { + if (AVL_END(tree, nnext) <= AVL_END(tree, np)) + break; + nnext = nnext->avl_parent; + } + } else + nnext = NULL; + + if (nnext) { + ASSERT(nnext->avl_nextino == np); + nnext->avl_nextino = np->avl_nextino; + /* + * Something preceeds np; np cannot be firstino. + */ + ASSERT(tree->avl_firstino != np); + } + else { + /* + * Nothing preceeding np; after deletion, np's nextino + * is firstino of tree. + */ + ASSERT(tree->avl_firstino == np); + tree->avl_firstino = np->avl_nextino; + } + + + /* + * Degenerate cases... + */ + if (forw == NULL) { + forw = back; + goto attach; + } + + if (back == NULL) { +attach: + if (forw) + forw->avl_parent = parent; + if (parent) { + if (parent->avl_forw == np) { + parent->avl_forw = forw; + retreat(tree, parent, AVL_BACK); + } else { + ASSERT(parent->avl_back == np); + parent->avl_back = forw; + retreat(tree, parent, AVL_FORW); + } + } else { + ASSERT(tree->avl_root == np); + tree->avl_root = forw; + } + avl64_checktree(tree, tree->avl_root); + return; + } + + /* + * Harder case: children on both sides. + * If back's avl_forw pointer is null, just have back + * inherit np's avl_forw tree, remove np from the tree + * and adjust balance counters starting at back. + * + * np-> xI xH (befor retreat()) + * / \ / \ + * back-> H J G J + * / / \ / \ + * G ? ? ? ? + * / \ + * ? ? + */ + if ((forw = back->avl_forw) == NULL) { + /* + * AVL_FORW retreat below will set back's + * balance to AVL_BACK. + */ + back->avl_balance = np->avl_balance; + back->avl_forw = forw = np->avl_forw; + forw->avl_parent = back; + back->avl_parent = parent; + + if (parent) { + if (parent->avl_forw == np) + parent->avl_forw = back; + else { + ASSERT(parent->avl_back == np); + parent->avl_back = back; + } + } else { + ASSERT(tree->avl_root == np); + tree->avl_root = back; + } + + /* + * back is taking np's place in the tree, and + * has therefore lost a avl_back node (itself). + */ + retreat(tree, back, AVL_FORW); + avl64_checktree(tree, tree->avl_root); + return; + } + + /* + * Hardest case: children on both sides, and back's + * avl_forw pointer isn't null. Find the immediately + * inferior buffer by following back's avl_forw line + * to the end, then have it inherit np's avl_forw tree. + * + * np-> xI xH + * / \ / \ + * G J back-> G J (before retreat()) + * / \ / \ + * F ?... F ?1 + * / \ + * ? H <-forw + * / + * ?1 + */ + while ((back = forw->avl_forw)) + forw = back; + + /* + * Will be adjusted by retreat() below. + */ + forw->avl_balance = np->avl_balance; + + /* + * forw inherits np's avl_forw... + */ + forw->avl_forw = np->avl_forw; + np->avl_forw->avl_parent = forw; + + /* + * ... forw's parent gets forw's avl_back... + */ + back = forw->avl_parent; + back->avl_forw = forw->avl_back; + if (forw->avl_back) + forw->avl_back->avl_parent = back; + + /* + * ... forw gets np's avl_back... + */ + forw->avl_back = np->avl_back; + np->avl_back->avl_parent = forw; + + /* + * ... and forw gets np's parent. + */ + forw->avl_parent = parent; + + if (parent) { + if (parent->avl_forw == np) + parent->avl_forw = forw; + else + parent->avl_back = forw; + } else { + ASSERT(tree->avl_root == np); + tree->avl_root = forw; + } + + /* + * What used to be forw's parent is the starting + * point for rebalancing. It has lost a avl_forw node. + */ + retreat(tree, back, AVL_BACK); + avl64_checktree(tree, tree->avl_root); +} + + +/* + * avl_findanyrange: + * + * Given range r [start, end), find any range which is contained in r. + * if checklen is non-zero, then only ranges of non-zero length are + * considered in finding a match. + */ +avl64node_t * +avl64_findanyrange( + register avl64tree_desc_t *tree, + register __uint64_t start, + register __uint64_t end, + int checklen) +{ + register avl64node_t *np = tree->avl_root; + + /* np = avl64_findadjacent(tree, start, AVL_SUCCEED); */ + while (np) { + if (start < AVL_START(tree, np)) { + if (np->avl_back) { + np = np->avl_back; + continue; + } + /* if we were to add node with start, would + * have a growth of AVL_BACK + */ + /* if succeeding node is needed, this is it. + */ + break; + } + if (start >= AVL_END(tree, np)) { + if (np->avl_forw) { + np = np->avl_forw; + continue; + } + /* if we were to add node with start, would + * have a growth of AVL_FORW; + */ + /* we are looking for a succeeding node; + * this is nextino. + */ + np = np->avl_nextino; + break; + } + /* AVL_START(tree, np) <= start < AVL_END(tree, np) */ + break; + } + if (np) { + if (checklen == AVL_INCLUDE_ZEROLEN) { + if (end <= AVL_START(tree, np)) { + /* something follows start, but is + * is entierly after the range (end) + */ + return(NULL); + } + /* np may stradle [start, end) */ + return(np); + } + /* + * find non-zero length region + */ + while (np && (AVL_END(tree, np) - AVL_START(tree, np) == 0) + && (AVL_START(tree, np) < end)) + np = np->avl_nextino; + + if ((np == NULL) || (AVL_START(tree, np) >= end)) + return NULL; + return(np); + } + /* + * nothing succeeds start, all existing ranges are before start. + */ + return NULL; +} + + +/* + * Returns a pointer to range which contains value. + */ +avl64node_t * +avl64_findrange( + register avl64tree_desc_t *tree, + register __uint64_t value) +{ + register avl64node_t *np = tree->avl_root; + + while (np) { + if (value < AVL_START(tree, np)) { + np = np->avl_back; + continue; + } + if (value >= AVL_END(tree, np)) { + np = np->avl_forw; + continue; + } + ASSERT(AVL_START(tree, np) <= value && + value < AVL_END(tree, np)); + return np; + } + return NULL; +} + + +/* + * Returns a pointer to node which contains exact value. + */ +avl64node_t * +avl64_find( + register avl64tree_desc_t *tree, + register __uint64_t value) +{ + register avl64node_t *np = tree->avl_root; + register __uint64_t nvalue; + + while (np) { + nvalue = AVL_START(tree, np); + if (value < nvalue) { + np = np->avl_back; + continue; + } + if (value == nvalue) { + return np; + } + np = np->avl_forw; + } + return NULL; +} + + +/* + * Balance buffer AVL tree after attaching a new node to root. + * Called only by avl_insert. + */ +static void +avl64_balance( + register avl64node_t **rootp, + register avl64node_t *np, + register int growth) +{ + /* + * At this point, np points to the node to which + * a new node has been attached. All that remains is to + * propagate avl_balance up the tree. + */ + for ( ; ; ) { + register avl64node_t *parent = np->avl_parent; + register avl64node_t *child; + + CERT(growth == AVL_BACK || growth == AVL_FORW); + + /* + * If the buffer was already balanced, set avl_balance + * to the new direction. Continue if there is a + * parent after setting growth to reflect np's + * relation to its parent. + */ + if (np->avl_balance == AVL_BALANCE) { + np->avl_balance = growth; + if (parent) { + if (parent->avl_forw == np) + growth = AVL_FORW; + else { + ASSERT(parent->avl_back == np); + growth = AVL_BACK; + } + + np = parent; + continue; + } + break; + } + + if (growth != np->avl_balance) { + /* + * Subtree is now balanced -- no net effect + * in the size of the subtree, so leave. + */ + np->avl_balance = AVL_BALANCE; + break; + } + + if (growth == AVL_BACK) { + + child = np->avl_back; + CERT(np->avl_balance == AVL_BACK && child); + + if (child->avl_balance == AVL_BACK) { /* single LL */ + /* + * ``A'' just got inserted; + * np points to ``E'', child to ``C'', + * and it is already AVL_BACK -- + * child will get promoted to top of subtree. + + np-> -E C + / \ / \ + child-> -C F -B E + / \ / / \ + -B D A D F + / + A + + Note that child->avl_parent and + avl_balance get set in common code. + */ + np->avl_parent = child; + np->avl_balance = AVL_BALANCE; + np->avl_back = child->avl_forw; + if (child->avl_forw) + child->avl_forw->avl_parent = np; + child->avl_forw = np; + } else { + /* + * double LR + * + * child's avl_forw node gets promoted to + * the top of the subtree. + + np-> -E C + / \ / \ + child-> +B F -B E + / \ / / \ + A +C A D F + \ + D + + */ + register avl64node_t *tmp = child->avl_forw; + + CERT(child->avl_balance == AVL_FORW && tmp); + + child->avl_forw = tmp->avl_back; + if (tmp->avl_back) + tmp->avl_back->avl_parent = child; + + tmp->avl_back = child; + child->avl_parent = tmp; + + np->avl_back = tmp->avl_forw; + if (tmp->avl_forw) + tmp->avl_forw->avl_parent = np; + + tmp->avl_forw = np; + np->avl_parent = tmp; + + if (tmp->avl_balance == AVL_BACK) + np->avl_balance = AVL_FORW; + else + np->avl_balance = AVL_BALANCE; + + if (tmp->avl_balance == AVL_FORW) + child->avl_balance = AVL_BACK; + else + child->avl_balance = AVL_BALANCE; + + /* + * Set child to point to tmp since it is + * now the top of the subtree, and will + * get attached to the subtree parent in + * the common code below. + */ + child = tmp; + } + + } else /* growth == AVL_BACK */ { + + /* + * This code is the mirror image of AVL_FORW above. + */ + + child = np->avl_forw; + CERT(np->avl_balance == AVL_FORW && child); + + if (child->avl_balance == AVL_FORW) { /* single RR */ + np->avl_parent = child; + np->avl_balance = AVL_BALANCE; + np->avl_forw = child->avl_back; + if (child->avl_back) + child->avl_back->avl_parent = np; + child->avl_back = np; + } else { + /* + * double RL + */ + register avl64node_t *tmp = child->avl_back; + + ASSERT(child->avl_balance == AVL_BACK && tmp); + + child->avl_back = tmp->avl_forw; + if (tmp->avl_forw) + tmp->avl_forw->avl_parent = child; + + tmp->avl_forw = child; + child->avl_parent = tmp; + + np->avl_forw = tmp->avl_back; + if (tmp->avl_back) + tmp->avl_back->avl_parent = np; + + tmp->avl_back = np; + np->avl_parent = tmp; + + if (tmp->avl_balance == AVL_FORW) + np->avl_balance = AVL_BACK; + else + np->avl_balance = AVL_BALANCE; + + if (tmp->avl_balance == AVL_BACK) + child->avl_balance = AVL_FORW; + else + child->avl_balance = AVL_BALANCE; + + child = tmp; + } + } + + child->avl_parent = parent; + child->avl_balance = AVL_BALANCE; + + if (parent) { + if (parent->avl_back == np) + parent->avl_back = child; + else + parent->avl_forw = child; + } else { + ASSERT(*rootp == np); + *rootp = child; + } + + break; + } +} + +static +avl64node_t * +avl64_insert_find_growth( + register avl64tree_desc_t *tree, + register __uint64_t start, /* range start at start, */ + register __uint64_t end, /* exclusive */ + register int *growthp) /* OUT */ +{ + avl64node_t *root = tree->avl_root; + register avl64node_t *np; + + np = root; + ASSERT(np); /* caller ensures that there is atleast one node in tree */ + + for ( ; ; ) { + CERT(np->avl_parent || root == np); + CERT(!np->avl_parent || root != np); + CERT(!(np->avl_back) || np->avl_back->avl_parent == np); + CERT(!(np->avl_forw) || np->avl_forw->avl_parent == np); + CERT(np->avl_balance != AVL_FORW || np->avl_forw); + CERT(np->avl_balance != AVL_BACK || np->avl_back); + CERT(np->avl_balance != AVL_BALANCE || + np->avl_back == NULL || np->avl_forw); + CERT(np->avl_balance != AVL_BALANCE || + np->avl_forw == NULL || np->avl_back); + + if (AVL_START(tree, np) >= end) { + if (np->avl_back) { + np = np->avl_back; + continue; + } + *growthp = AVL_BACK; + break; + } + + if (AVL_END(tree, np) <= start) { + if (np->avl_forw) { + np = np->avl_forw; + continue; + } + *growthp = AVL_FORW; + break; + } + /* found exact match -- let caller decide if it is an error */ + return(NULL); + } + return(np); +} + + +static void +avl64_insert_grow( + register avl64tree_desc_t *tree, + register avl64node_t *parent, + register avl64node_t *newnode, + register int growth) +{ + register avl64node_t *nnext; + register __uint64_t start = AVL_START(tree, newnode); + + if (growth == AVL_BACK) { + + parent->avl_back = newnode; + /* + * we are growing to the left; previous in-order to newnode is + * closest ancestor with lesser value. Before this + * insertion, this ancestor will be pointing to + * newnode's parent. After insertion, next in-order to newnode + * is the parent. + */ + newnode->avl_nextino = parent; + nnext = parent; + while (nnext) { + if (AVL_END(tree, nnext) <= start) + break; + nnext = nnext->avl_parent; + } + if (nnext) { + /* + * nnext will be null if newnode is + * the least element, and hence very first in the list. + */ + ASSERT(nnext->avl_nextino == parent); + nnext->avl_nextino = newnode; + } + } + else { + parent->avl_forw = newnode; + newnode->avl_nextino = parent->avl_nextino; + parent->avl_nextino = newnode; + } +} + + +avl64node_t * +avl64_insert( + register avl64tree_desc_t *tree, + register avl64node_t *newnode) +{ + register avl64node_t *np; + register __uint64_t start = AVL_START(tree, newnode); + register __uint64_t end = AVL_END(tree, newnode); + int growth; + + ASSERT(newnode); + /* + * Clean all pointers for sanity; some will be reset as necessary. + */ + newnode->avl_nextino = NULL; + newnode->avl_parent = NULL; + newnode->avl_forw = NULL; + newnode->avl_back = NULL; + newnode->avl_balance = AVL_BALANCE; + + if ((np = tree->avl_root) == NULL) { /* degenerate case... */ + tree->avl_root = newnode; + tree->avl_firstino = newnode; + return newnode; + } + + if ((np = avl64_insert_find_growth(tree, start, end, &growth)) + == NULL) { + if (start != end) { /* non-zero length range */ +#ifdef AVL_USER_MODE + printf("avl_insert: Warning! duplicate range [0x%llx,0x%llx)\n", + (unsigned long long)start, (unsigned long long)end); +#else + cmn_err(CE_CONT, + "!avl_insert: Warning! duplicate range [0x%llx,0x%llx)\n", + start, end); +#endif + } + return(NULL); + } + + avl64_insert_grow(tree, np, newnode, growth); + if (growth == AVL_BACK) { + /* + * Growing to left. if np was firstino, newnode will be firstino + */ + if (tree->avl_firstino == np) + tree->avl_firstino = newnode; + } +#ifdef notneeded + else + if (growth == AVL_FORW) + /* + * Cannot possibly be firstino; there is somebody to our left. + */ + ; +#endif + + newnode->avl_parent = np; + CERT(np->avl_forw == newnode || np->avl_back == newnode); + + avl64_balance(&tree->avl_root, np, growth); + + avl64_checktree(tree, tree->avl_root); + + return newnode; +} + +/* + * + * avl64_insert_immediate(tree, afterp, newnode): + * insert newnode immediately into tree immediately after afterp. + * after insertion, newnode is right child of afterp. + */ +void +avl64_insert_immediate( + avl64tree_desc_t *tree, + avl64node_t *afterp, + avl64node_t *newnode) +{ + /* + * Clean all pointers for sanity; some will be reset as necessary. + */ + newnode->avl_nextino = NULL; + newnode->avl_parent = NULL; + newnode->avl_forw = NULL; + newnode->avl_back = NULL; + newnode->avl_balance = AVL_BALANCE; + + if (afterp == NULL) { + tree->avl_root = newnode; + tree->avl_firstino = newnode; + return; + } + + ASSERT(afterp->avl_forw == NULL); + avl64_insert_grow(tree, afterp, newnode, AVL_FORW); /* grow to right */ + CERT(afterp->avl_forw == newnode); + avl64_balance(&tree->avl_root, afterp, AVL_FORW); + avl64_checktree(tree, tree->avl_root); +} + + +/* + * Returns first in order node + */ +avl64node_t * +avl64_firstino(register avl64node_t *root) +{ + register avl64node_t *np; + + if ((np = root) == NULL) + return NULL; + + while (np->avl_back) + np = np->avl_back; + return np; +} + +#ifdef AVL_USER_MODE +/* + * leave this as a user-mode only routine until someone actually + * needs it in the kernel + */ + +/* + * Returns last in order node + */ +avl64node_t * +avl64_lastino(register avl64node_t *root) +{ + register avl64node_t *np; + + if ((np = root) == NULL) + return NULL; + + while (np->avl_forw) + np = np->avl_forw; + return np; +} +#endif + +void +avl64_init_tree(avl64tree_desc_t *tree, avl64ops_t *ops) +{ + tree->avl_root = NULL; + tree->avl_firstino = NULL; + tree->avl_ops = ops; +} + +#ifdef AVL_DEBUG +static void +avl64_printnode(avl64tree_desc_t *tree, avl64node_t *np, int nl) +{ + printf("[%d-%d]%c", AVL_START(tree, np), + (AVL_END(tree, np) - 1), nl ? '\n' : ' '); +} +#endif +#ifdef STAND_ALONE_DEBUG + +struct avl_debug_node { + avl64node_t avl_node; + xfs_off_t avl_start; + unsigned int avl_size; +} + +avl64ops_t avl_debug_ops = { + avl_debug_start, + avl_debug_end, +} + +static __uint64_t +avl64_debug_start(avl64node_t *node) +{ + return (__uint64_t)(struct avl_debug_node *)node->avl_start; +} + +static __uint64_t +avl64_debug_end(avl64node_t *node) +{ + return (__uint64_t) + ((struct avl_debug_node *)node->avl_start + + (struct avl_debug_node *)node->avl_size); +} + +avl_debug_node freenodes[100]; +avl_debug_node *freehead = &freenodes[0]; + +static avl64node_t * +alloc_avl64_debug_node() +{ + freehead->avl_balance = AVL_BALANCE; + freehead->avl_parent = freehead->avl_forw = freehead->avl_back = NULL; + return(freehead++); +} + +static void +avl64_print(avl64tree_desc_t *tree, avl64node_t *root, int depth) +{ + int i; + + if (!root) + return; + if (root->avl_forw) + avl64_print(tree, root->avl_forw, depth+5); + for (i = 0; i < depth; i++) + putchar((int) ' '); + avl64_printnode(tree, root,1); + if (root->avl_back) + avl64_print(tree, root->avl_back, depth+5); +} + +main() +{ + int i, j; + avl64node_t *np; + avl64tree_desc_t tree; + char linebuf[256], cmd[256]; + + avl64_init_tree(&tree, &avl_debug_ops); + + for (i = 100; i > 0; i = i - 10) + { + np = alloc__debug_avlnode(); + ASSERT(np); + np->avl_start = i; + np->avl_size = 10; + avl64_insert(&tree, np); + } + avl64_print(&tree, tree.avl_root, 0); + + for (np = tree.avl_firstino; np != NULL; np = np->avl_nextino) + avl64_printnode(&tree, np, 0); + printf("\n"); + + while (1) { + printf("Command [fpdir] : "); + fgets(linebuf, 256, stdin); + if (feof(stdin)) break; + cmd[0] = NULL; + if (sscanf(linebuf, "%[fpdir]%d", cmd, &i) != 2) + continue; + switch (cmd[0]) { + case 'd': + case 'f': + printf("end of range ? "); + fgets(linebuf, 256, stdin); + j = atoi(linebuf); + + if (i == j) j = i+1; + np = avl64_findinrange(&tree,i,j); + if (np) { + avl64_printnode(&tree, np, 1); + if (cmd[0] == 'd') + avl64_delete(&tree, np); + } else + printf("Cannot find %d\n", i); + break; + case 'p': + avl64_print(&tree, tree.avl_root, 0); + for (np = tree.avl_firstino; + np != NULL; np = np->avl_nextino) + avl64_printnode(&tree, np, 0); + printf("\n"); + break; + case 'i': + np = alloc_avlnode(); + ASSERT(np); + np->avl_start = i; + printf("size of range ? "); + fgets(linebuf, 256, stdin); + j = atoi(linebuf); + + np->avl_size = j; + avl64_insert(&tree, np); + break; + case 'r': { + avl64node_t *b, *e, *t; + int checklen; + + printf("End of range ? "); + fgets(linebuf, 256, stdin); + j = atoi(linebuf); + + printf("checklen 0/1 ? "); + fgets(linebuf, 256, stdin); + checklen = atoi(linebuf); + + + b = avl64_findanyrange(&tree, i, j, checklen); + if (b) { + printf("Found something\n"); + t = b; + while (t) { + if (t != b && + AVL_START(&tree, t) >= j) + break; + avl64_printnode(&tree, t, 0); + t = t->avl_nextino; + } + printf("\n"); + } + } + } + } +} +#endif + +/* + * Given a tree, find value; will find return range enclosing value, + * or range immediately succeeding value, + * or range immediately preceeding value. + */ +avl64node_t * +avl64_findadjacent( + register avl64tree_desc_t *tree, + register __uint64_t value, + register int dir) +{ + register avl64node_t *np = tree->avl_root; + + while (np) { + if (value < AVL_START(tree, np)) { + if (np->avl_back) { + np = np->avl_back; + continue; + } + /* if we were to add node with value, would + * have a growth of AVL_BACK + */ + if (dir == AVL_SUCCEED) { + /* if succeeding node is needed, this is it. + */ + return(np); + } + if (dir == AVL_PRECEED) { + /* + * find nearest ancestor with lesser value. + */ + np = np->avl_parent; + while (np) { + if (AVL_END(tree, np) <= value) + break; + np = np->avl_parent; + } + return(np); + } + ASSERT(dir == AVL_SUCCEED || dir == AVL_PRECEED); + break; + } + if (value >= AVL_END(tree, np)) { + if (np->avl_forw) { + np = np->avl_forw; + continue; + } + /* if we were to add node with value, would + * have a growth of AVL_FORW; + */ + if (dir == AVL_SUCCEED) { + /* we are looking for a succeeding node; + * this is nextino. + */ + return(np->avl_nextino); + } + if (dir == AVL_PRECEED) { + /* looking for a preceeding node; this is it. */ + return(np); + } + ASSERT(dir == AVL_SUCCEED || dir == AVL_PRECEED); + } + /* AVL_START(tree, np) <= value < AVL_END(tree, np) */ + return(np); + } + return NULL; +} + + +#ifdef AVL_FUTURE_ENHANCEMENTS +/* + * avl_findranges: + * + * Given range r [start, end), find all ranges in tree which are contained + * in r. At return, startp and endp point to first and last of + * a chain of elements which describe the contained ranges. Elements + * in startp ... endp are in sort order, and can be accessed by + * using avl_nextino. + */ + +void +avl64_findranges( + register avl64tree_desc_t *tree, + register __uint64_t start, + register __uint64_t end, + avl64node_t **startp, + avl64node_t **endp) +{ + register avl64node_t *np; + + np = avl64_findadjacent(tree, start, AVL_SUCCEED); + if (np == NULL /* nothing succeding start */ + || (np && (end <= AVL_START(tree, np)))) + /* something follows start, + but... is entirely after end */ + { + *startp = NULL; + *endp = NULL; + return; + } + + *startp = np; + + /* see if end is in this region itself */ + if (end <= AVL_END(tree, np) || + np->avl_nextino == NULL || + (np->avl_nextino && + (end <= AVL_START(tree, np->avl_nextino)))) { + *endp = np; + return; + } + /* have to munge for end */ + /* + * note: have to look for (end - 1), since + * findadjacent will look for exact value, and does not + * care about the fact that end is actually one more + * than the value actually being looked for; thus feed it one less. + */ + *endp = avl64_findadjacent(tree, (end-1), AVL_PRECEED); + ASSERT(*endp); +} + +#endif /* AVL_FUTURE_ENHANCEMENTS */ diff -rNu linux-2.4.7/cmd/xfsprogs/repair/avl64.h linux-2.4-xfs/cmd/xfsprogs/repair/avl64.h --- linux-2.4.7/cmd/xfsprogs/repair/avl64.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/avl64.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,151 @@ +/************************************************************************** + * * + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + * * + **************************************************************************/ +#ifndef __XR_AVL64_H__ +#define __XR_AVL64_H__ + +#include + +typedef struct avl64node { + struct avl64node *avl_forw; /* pointer to right child (> parent) */ + struct avl64node *avl_back; /* pointer to left child (< parent) */ + struct avl64node *avl_parent; /* parent pointer */ + struct avl64node *avl_nextino; /* next in-order; NULL terminated list*/ + char avl_balance; /* tree balance */ +} avl64node_t; + +/* + * avl-tree operations + */ +typedef struct avl64ops { + __uint64_t (*avl_start)(avl64node_t *); + __uint64_t (*avl_end)(avl64node_t *); +} avl64ops_t; + +/* + * avoid complaints about multiple def's since these are only used by + * the avl code internally + */ +#ifndef AVL_START +#define AVL_START(tree, n) (*(tree)->avl_ops->avl_start)(n) +#define AVL_END(tree, n) (*(tree)->avl_ops->avl_end)(n) +#endif + +/* + * tree descriptor: + * root points to the root of the tree. + * firstino points to the first in the ordered list. + */ +typedef struct avl64tree_desc { + avl64node_t *avl_root; + avl64node_t *avl_firstino; + avl64ops_t *avl_ops; +} avl64tree_desc_t; + +/* possible values for avl_balance */ + +#define AVL_BACK 1 +#define AVL_BALANCE 0 +#define AVL_FORW 2 + +/* + * 'Exported' avl tree routines + */ +avl64node_t +*avl64_insert( + avl64tree_desc_t *tree, + avl64node_t *newnode); + +void +avl64_delete( + avl64tree_desc_t *tree, + avl64node_t *np); + +void +avl64_insert_immediate( + avl64tree_desc_t *tree, + avl64node_t *afterp, + avl64node_t *newnode); + +void +avl64_init_tree( + avl64tree_desc_t *tree, + avl64ops_t *ops); + +avl64node_t * +avl64_findrange( + avl64tree_desc_t *tree, + __uint64_t value); + +avl64node_t * +avl64_find( + avl64tree_desc_t *tree, + __uint64_t value); + +avl64node_t * +avl64_findanyrange( + avl64tree_desc_t *tree, + __uint64_t start, + __uint64_t end, + int checklen); + + +avl64node_t * +avl64_findadjacent( + avl64tree_desc_t *tree, + __uint64_t value, + int dir); + +#ifdef AVL_FUTURE_ENHANCEMENTS +void +avl64_findranges( + register avl64tree_desc_t *tree, + register __uint64_t start, + register __uint64_t end, + avl64node_t **startp, + avl64node_t **endp); +#endif + +/* + * avoid complaints about multiple def's since these are only used by + * the avl code internally + */ +#ifndef AVL_PRECEED +#define AVL_PRECEED 0x1 +#define AVL_SUCCEED 0x2 + +#define AVL_INCLUDE_ZEROLEN 0x0000 +#define AVL_EXCLUDE_ZEROLEN 0x0001 +#endif + +#endif /* __XR_AVL64_H__ */ diff -rNu linux-2.4.7/cmd/xfsprogs/repair/bmap.c linux-2.4-xfs/cmd/xfsprogs/repair/bmap.c --- linux-2.4.7/cmd/xfsprogs/repair/bmap.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/bmap.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "err_protos.h" +#include "bmap.h" + +/* + * Block mapping code taken from xfs_db. + */ + +/* + * Append an extent to the block entry. + */ +void +blkent_append( + blkent_t **entp, + xfs_dfsbno_t b, + xfs_dfilblks_t c) +{ + blkent_t *ent; + size_t size; + int i; + + ent = *entp; + size = BLKENT_SIZE(c + ent->nblks); + if ((*entp = ent = realloc(ent, size)) == NULL) { + do_warn("realloc failed in blkent_append (%u bytes)\n", size); + return; + } + for (i = 0; i < c; i++) + ent->blks[ent->nblks + i] = b + i; + ent->nblks += c; +} + +/* + * Make a new block entry. + */ +blkent_t * +blkent_new( + xfs_dfiloff_t o, + xfs_dfsbno_t b, + xfs_dfilblks_t c) +{ + blkent_t *ent; + int i; + + if ((ent = malloc(BLKENT_SIZE(c))) == NULL) { + do_warn("malloc failed in blkent_new (%u bytes)\n", + BLKENT_SIZE(c)); + return ent; + } + ent->nblks = c; + ent->startoff = o; + for (i = 0; i < c; i++) + ent->blks[i] = b + i; + return ent; +} + +/* + * Prepend an extent to the block entry. + */ +void +blkent_prepend( + blkent_t **entp, + xfs_dfsbno_t b, + xfs_dfilblks_t c) +{ + int i; + blkent_t *newent; + blkent_t *oldent; + + oldent = *entp; + if ((newent = malloc(BLKENT_SIZE(oldent->nblks + c))) == NULL) { + do_warn("malloc failed in blkent_prepend (%u bytes)\n", + BLKENT_SIZE(oldent->nblks + c)); + *entp = newent; + return; + } + newent->nblks = oldent->nblks + c; + newent->startoff = oldent->startoff - c; + for (i = 0; i < c; i++) + newent->blks[i] = b + c; + for (; i < oldent->nblks + c; i++) + newent->blks[i] = oldent->blks[i - c]; + free(oldent); + *entp = newent; +} + +/* + * Allocate a block map. + */ +blkmap_t * +blkmap_alloc( + xfs_extnum_t nex) +{ + blkmap_t *blkmap; + + if (nex < 1) + nex = 1; + if ((blkmap = malloc(BLKMAP_SIZE(nex))) == NULL) { + do_warn("malloc failed in blkmap_alloc (%u bytes)\n", + BLKMAP_SIZE(nex)); + return blkmap; + } + blkmap->naents = nex; + blkmap->nents = 0; + return blkmap; +} + +/* + * Free a block map. + */ +void +blkmap_free( + blkmap_t *blkmap) +{ + blkent_t **entp; + xfs_extnum_t i; + + if (blkmap == NULL) + return; + for (i = 0, entp = blkmap->ents; i < blkmap->nents; i++, entp++) + free(*entp); + free(blkmap); +} + +/* + * Get one entry from a block map. + */ +xfs_dfsbno_t +blkmap_get( + blkmap_t *blkmap, + xfs_dfiloff_t o) +{ + blkent_t *ent; + blkent_t **entp; + int i; + + for (i = 0, entp = blkmap->ents; i < blkmap->nents; i++, entp++) { + ent = *entp; + if (o >= ent->startoff && o < ent->startoff + ent->nblks) + return ent->blks[o - ent->startoff]; + } + return NULLDFSBNO; +} + +/* + * Get a chunk of entries from a block map. + */ +int +blkmap_getn( + blkmap_t *blkmap, + xfs_dfiloff_t o, + xfs_dfilblks_t nb, + bmap_ext_t **bmpp) +{ + bmap_ext_t *bmp; + blkent_t *ent; + xfs_dfiloff_t ento; + blkent_t **entp; + int i; + int nex; + + for (i = nex = 0, bmp = NULL, entp = blkmap->ents; + i < blkmap->nents; + i++, entp++) { + ent = *entp; + if (ent->startoff >= o + nb) + break; + if (ent->startoff + ent->nblks <= o) + continue; + for (ento = ent->startoff; + ento < ent->startoff + ent->nblks && ento < o + nb; + ento++) { + if (ento < o) + continue; + if (bmp && + bmp[nex - 1].startoff + bmp[nex - 1].blockcount == + ento && + bmp[nex - 1].startblock + bmp[nex - 1].blockcount == + ent->blks[ento - ent->startoff]) + bmp[nex - 1].blockcount++; + else { + bmp = realloc(bmp, ++nex * sizeof(*bmp)); + if (bmp == NULL) { + do_warn("realloc failed in blkmap_getn" + " (%u bytes)\n", + nex * sizeof(*bmp)); + continue; + } + bmp[nex - 1].startoff = ento; + bmp[nex - 1].startblock = + ent->blks[ento - ent->startoff]; + bmp[nex - 1].blockcount = 1; + bmp[nex - 1].flag = 0; + } + } + } + *bmpp = bmp; + return nex; +} + +/* + * Make a block map larger. + */ +void +blkmap_grow( + blkmap_t **blkmapp, + blkent_t **entp, + blkent_t *newent) +{ + blkmap_t *blkmap; + size_t size; + int i; + int idx; + + blkmap = *blkmapp; + idx = (int)(entp - blkmap->ents); + if (blkmap->naents == blkmap->nents) { + size = BLKMAP_SIZE(blkmap->nents + 1); + if ((*blkmapp = blkmap = realloc(blkmap, size)) == NULL) { + do_warn("realloc failed in blkmap_grow (%u bytes)\n", + size); + return; + } + blkmap->naents++; + } + for (i = blkmap->nents; i > idx; i--) + blkmap->ents[i] = blkmap->ents[i - 1]; + blkmap->ents[idx] = newent; + blkmap->nents++; +} + +/* + * Return the last offset in a block map. + */ +xfs_dfiloff_t +blkmap_last_off( + blkmap_t *blkmap) +{ + blkent_t *ent; + + if (!blkmap->nents) + return NULLDFILOFF; + ent = blkmap->ents[blkmap->nents - 1]; + return ent->startoff + ent->nblks; +} + +/* + * Return the next offset in a block map. + */ +xfs_dfiloff_t +blkmap_next_off( + blkmap_t *blkmap, + xfs_dfiloff_t o, + int *t) +{ + blkent_t *ent; + blkent_t **entp; + + if (!blkmap->nents) + return NULLDFILOFF; + if (o == NULLDFILOFF) { + *t = 0; + ent = blkmap->ents[0]; + return ent->startoff; + } + entp = &blkmap->ents[*t]; + ent = *entp; + if (o < ent->startoff + ent->nblks - 1) + return o + 1; + entp++; + if (entp >= &blkmap->ents[blkmap->nents]) + return NULLDFILOFF; + (*t)++; + ent = *entp; + return ent->startoff; +} + +/* + * Set a block value in a block map. + */ +void +blkmap_set_blk( + blkmap_t **blkmapp, + xfs_dfiloff_t o, + xfs_dfsbno_t b) +{ + blkmap_t *blkmap; + blkent_t *ent; + blkent_t **entp; + blkent_t *nextent; + + blkmap = *blkmapp; + for (entp = blkmap->ents; entp < &blkmap->ents[blkmap->nents]; entp++) { + ent = *entp; + if (o < ent->startoff - 1) { + ent = blkent_new(o, b, 1); + blkmap_grow(blkmapp, entp, ent); + return; + } + if (o == ent->startoff - 1) { + blkent_prepend(entp, b, 1); + return; + } + if (o >= ent->startoff && o < ent->startoff + ent->nblks) { + ent->blks[o - ent->startoff] = b; + return; + } + if (o > ent->startoff + ent->nblks) + continue; + blkent_append(entp, b, 1); + if (entp == &blkmap->ents[blkmap->nents - 1]) + return; + ent = *entp; + nextent = entp[1]; + if (ent->startoff + ent->nblks < nextent->startoff) + return; + blkent_append(entp, nextent->blks[0], nextent->nblks); + blkmap_shrink(blkmap, &entp[1]); + return; + } + ent = blkent_new(o, b, 1); + blkmap_grow(blkmapp, entp, ent); +} + +/* + * Set an extent into a block map. + */ +void +blkmap_set_ext( + blkmap_t **blkmapp, + xfs_dfiloff_t o, + xfs_dfsbno_t b, + xfs_dfilblks_t c) +{ + blkmap_t *blkmap; + blkent_t *ent; + blkent_t **entp; + xfs_extnum_t i; + + blkmap = *blkmapp; + if (!blkmap->nents) { + blkmap->ents[0] = blkent_new(o, b, c); + blkmap->nents = 1; + return; + } + entp = &blkmap->ents[blkmap->nents - 1]; + ent = *entp; + if (ent->startoff + ent->nblks == o) { + blkent_append(entp, b, c); + return; + } + if (ent->startoff + ent->nblks < o) { + ent = blkent_new(o, b, c); + blkmap_grow(blkmapp, &blkmap->ents[blkmap->nents], ent); + return; + } + for (i = 0; i < c; i++) + blkmap_set_blk(blkmapp, o + i, b + i); +} + +/* + * Make a block map smaller. + */ +void +blkmap_shrink( + blkmap_t *blkmap, + blkent_t **entp) +{ + int i; + int idx; + + free(*entp); + idx = (int)(entp - blkmap->ents); + for (i = idx + 1; i < blkmap->nents; i++) + blkmap->ents[i] = blkmap->ents[i - 1]; + blkmap->nents--; +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/bmap.h linux-2.4-xfs/cmd/xfsprogs/repair/bmap.h --- linux-2.4.7/cmd/xfsprogs/repair/bmap.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/bmap.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Block mapping code taken from xfs_db. + */ + +/* + * Block map entry. + */ +typedef struct blkent { + xfs_dfiloff_t startoff; + xfs_dfilblks_t nblks; + xfs_dfsbno_t blks[1]; +} blkent_t; +#define BLKENT_SIZE(n) \ + (offsetof(blkent_t, blks) + (sizeof(xfs_dfsbno_t) * (n))) + +/* + * Block map. + */ +typedef struct blkmap { + int naents; + int nents; + blkent_t *ents[1]; +} blkmap_t; +#define BLKMAP_SIZE(n) \ + (offsetof(blkmap_t, ents) + (sizeof(blkent_t *) * (n))) + +/* + * Extent descriptor. + */ +typedef struct bmap_ext { + xfs_dfiloff_t startoff; + xfs_dfsbno_t startblock; + xfs_dfilblks_t blockcount; + int flag; +} bmap_ext_t; + +void blkent_append(blkent_t **entp, xfs_dfsbno_t b, + xfs_dfilblks_t c); +blkent_t *blkent_new(xfs_dfiloff_t o, xfs_dfsbno_t b, xfs_dfilblks_t c); +void blkent_prepend(blkent_t **entp, xfs_dfsbno_t b, + xfs_dfilblks_t c); +blkmap_t *blkmap_alloc(xfs_extnum_t); +void blkmap_free(blkmap_t *blkmap); +xfs_dfsbno_t blkmap_get(blkmap_t *blkmap, xfs_dfiloff_t o); +int blkmap_getn(blkmap_t *blkmap, xfs_dfiloff_t o, + xfs_dfilblks_t nb, bmap_ext_t **bmpp); +void blkmap_grow(blkmap_t **blkmapp, blkent_t **entp, + blkent_t *newent); +xfs_dfiloff_t blkmap_last_off(blkmap_t *blkmap); +xfs_dfiloff_t blkmap_next_off(blkmap_t *blkmap, xfs_dfiloff_t o, int *t); +void blkmap_set_blk(blkmap_t **blkmapp, xfs_dfiloff_t o, + xfs_dfsbno_t b); +void blkmap_set_ext(blkmap_t **blkmapp, xfs_dfiloff_t o, + xfs_dfsbno_t b, xfs_dfilblks_t c); +void blkmap_shrink(blkmap_t *blkmap, blkent_t **entp); diff -rNu linux-2.4.7/cmd/xfsprogs/repair/dino_chunks.c linux-2.4-xfs/cmd/xfsprogs/repair/dino_chunks.c --- linux-2.4.7/cmd/xfsprogs/repair/dino_chunks.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/dino_chunks.c Thu Apr 12 18:49:04 2001 @@ -0,0 +1,1178 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "avl.h" +#include "globals.h" +#include "agheader.h" +#include "incore.h" +#include "protos.h" +#include "err_protos.h" +#include "dir.h" +#include "dinode.h" +#include "versions.h" + +/* + * validates inode block or chunk, returns # of good inodes + * the dinodes are verified using verify_uncertain_dinode() which + * means only the basic inode info is checked, no fork checks. + */ + +int +check_aginode_block(xfs_mount_t *mp, + xfs_agnumber_t agno, + xfs_agblock_t agbno) +{ + + xfs_dinode_t *dino_p; + int i; + int cnt = 0; + xfs_buf_t *bp; + + /* + * it's ok to read these possible inode blocks in one at + * a time because they don't belong to known inodes (if + * they did, we'd know about them courtesy of the incore inode + * tree and we wouldn't be here and we stale the buffers out + * so no one else will overlap them. + */ + bp = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + do_warn("cannot read agbno (%u/%u), disk block %lld\n", agno, + agbno, (xfs_daddr_t)XFS_AGB_TO_DADDR(mp, agno, agbno)); + return(0); + } + + for (i = 0; i < mp->m_sb.sb_inopblock; i++) { + dino_p = XFS_MAKE_IPTR(mp, bp, i); + if (!verify_uncertain_dinode(mp, dino_p, agno, + XFS_OFFBNO_TO_AGINO(mp, agbno, i))) + cnt++; + } + + libxfs_putbuf(bp); + return(cnt); +} + +int +check_inode_block(xfs_mount_t *mp, + xfs_ino_t ino) +{ + return(check_aginode_block(mp, XFS_INO_TO_AGNO(mp, ino), + XFS_INO_TO_AGBNO(mp, ino))); +} + +/* + * tries to establish if the inode really exists in a valid + * inode chunk. returns number of new inodes if things are good + * and 0 if bad. start is the start of the discovered inode chunk. + * routine assumes that ino is a legal inode number + * (verified by verify_inum()). If the inode chunk turns out + * to be good, this routine will put the inode chunk into + * the good inode chunk tree if required. + * + * the verify_(ag)inode* family of routines are utility + * routines called by check_uncertain_aginodes() and + * process_uncertain_aginodes(). + */ +int +verify_inode_chunk(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_ino_t *start_ino) +{ + xfs_agnumber_t agno; + xfs_agino_t agino; + xfs_agino_t start_agino; + xfs_agblock_t agbno; + xfs_agblock_t start_agbno = 0; + xfs_agblock_t end_agbno; + xfs_agblock_t max_agbno; + xfs_agblock_t cur_agbno; + xfs_agblock_t chunk_start_agbno; + xfs_agblock_t chunk_stop_agbno; + ino_tree_node_t *irec_before_p = NULL; + ino_tree_node_t *irec_after_p = NULL; + ino_tree_node_t *irec_p; + ino_tree_node_t *irec_next_p; + int irec_cnt; + int ino_cnt = 0; + int num_blks; + int i; + int j; + int state; + + agno = XFS_INO_TO_AGNO(mp, ino); + agino = XFS_INO_TO_AGINO(mp, ino); + agbno = XFS_INO_TO_AGBNO(mp, ino); + *start_ino = NULLFSINO; + + ASSERT(XFS_IALLOC_BLOCKS(mp) > 0); + + if (agno == mp->m_sb.sb_agcount - 1) + max_agbno = mp->m_sb.sb_dblocks - + (xfs_drfsbno_t) mp->m_sb.sb_agblocks * agno; + else + max_agbno = mp->m_sb.sb_agblocks; + + /* + * is the inode beyond the end of the AG? + */ + if (agbno >= max_agbno) + return(0); + + /* + * check for the easy case, inodes per block >= XFS_INODES_PER_CHUNK + * (multiple chunks per block) + */ + if (XFS_IALLOC_BLOCKS(mp) == 1) { + if (agbno > max_agbno) + return(0); + + if (check_inode_block(mp, ino) == 0) + return(0); + + switch (state = get_agbno_state(mp, agno, agbno)) { + case XR_E_INO: + do_warn("uncertain inode block %d/%d already known\n", + agno, agbno); + break; + case XR_E_UNKNOWN: + case XR_E_FREE1: + case XR_E_FREE: + set_agbno_state(mp, agno, agbno, XR_E_INO); + break; + case XR_E_MULT: + case XR_E_INUSE: + case XR_E_INUSE_FS: + case XR_E_FS_MAP: + /* + * if block is already claimed, forget it. + */ + do_warn( + "inode block %d/%d multiply claimed, (state %d)\n", + agno, agbno, state); + set_agbno_state(mp, agno, agbno, XR_E_MULT); + return(0); + default: + do_warn("inode block %d/%d bad state, (state %d)\n", + agno, agbno, state); + set_agbno_state(mp, agno, agbno, XR_E_INO); + break; + } + + start_agino = XFS_OFFBNO_TO_AGINO(mp, agbno, 0); + *start_ino = XFS_AGINO_TO_INO(mp, agno, start_agino); + + /* + * put new inode record(s) into inode tree + */ + for (j = 0; j < chunks_pblock; j++) { + if ((irec_p = find_inode_rec(agno, start_agino)) + == NULL) { + irec_p = set_inode_free_alloc(agno, + start_agino); + for (i = 1; i < XFS_INODES_PER_CHUNK; i++) + set_inode_free(irec_p, i); + } + if (start_agino <= agino && agino < + start_agino + XFS_INODES_PER_CHUNK) + set_inode_used(irec_p, agino - start_agino); + + start_agino += XFS_INODES_PER_CHUNK; + ino_cnt += XFS_INODES_PER_CHUNK; + } + + return(ino_cnt); + } else if (fs_aligned_inodes) { + /* + * next easy case -- aligned inode filesystem. + * just check out the chunk + */ + start_agbno = rounddown(XFS_INO_TO_AGBNO(mp, ino), + fs_ino_alignment); + end_agbno = start_agbno + XFS_IALLOC_BLOCKS(mp); + + /* + * if this fs has aligned inodes but the end of the + * chunk is beyond the end of the ag, this is a bad + * chunk + */ + if (end_agbno > max_agbno) + return(0); + + /* + * check out all blocks in chunk + */ + ino_cnt = 0; + for (cur_agbno = start_agbno; cur_agbno < end_agbno; + cur_agbno++) { + ino_cnt += check_aginode_block(mp, agno, cur_agbno); + } + + /* + * if we lose either 2 blocks worth of inodes or >25% of + * the chunk, just forget it. + */ + if (ino_cnt < XFS_INODES_PER_CHUNK - 2 * mp->m_sb.sb_inopblock + || ino_cnt < XFS_INODES_PER_CHUNK - 16) + return(0); + + /* + * ok, put the record into the tree. we know that it's + * not already there since the inode is guaranteed + * not to be in the tree. + */ + start_agino = XFS_OFFBNO_TO_AGINO(mp, start_agbno, 0); + *start_ino = XFS_AGINO_TO_INO(mp, agno, start_agino); + + irec_p = set_inode_free_alloc(agno, + XFS_OFFBNO_TO_AGINO(mp, start_agbno, 0)); + + for (i = 1; i < XFS_INODES_PER_CHUNK; i++) + set_inode_free(irec_p, i); + + ASSERT(start_agino <= agino && + start_agino + XFS_INODES_PER_CHUNK > agino); + + set_inode_used(irec_p, agino - start_agino); + + return(XFS_INODES_PER_CHUNK); + } + + /* + * hard case -- pre-6.3 filesystem. + * set default start/end agbnos and ensure agbnos are legal. + * we're setting a range [start_agbno, end_agbno) such that + * a discovered inode chunk completely within that range + * would include the inode passed into us. + */ + if (XFS_IALLOC_BLOCKS(mp) > 1) { + if (agino > XFS_IALLOC_INODES(mp)) + start_agbno = agbno - XFS_IALLOC_BLOCKS(mp) + 1; + else + start_agbno = 1; + } + + end_agbno = agbno + XFS_IALLOC_BLOCKS(mp); + + if (end_agbno > max_agbno) + end_agbno = max_agbno; + + /* + * search tree for known inodes within +/- 1 inode chunk range + */ + irec_before_p = irec_after_p = NULL; + + find_inode_rec_range(agno, XFS_OFFBNO_TO_AGINO(mp, start_agbno, 0), + XFS_OFFBNO_TO_AGINO(mp, end_agbno, mp->m_sb.sb_inopblock - 1), + &irec_before_p, &irec_after_p); + + /* + * if we have known inode chunks in our search range, establish + * their start and end-points to tighten our search range. range + * is [start, end) -- e.g. max/end agbno is one beyond the + * last block to be examined. the avl routines work this way. + */ + if (irec_before_p) { + /* + * only one inode record in the range, move one boundary in + */ + if (irec_before_p == irec_after_p) { + if (irec_before_p->ino_startnum < agino) + start_agbno = XFS_AGINO_TO_AGBNO(mp, + irec_before_p->ino_startnum + + XFS_INODES_PER_CHUNK); + else + end_agbno = XFS_AGINO_TO_AGBNO(mp, + irec_before_p->ino_startnum); + } + + /* + * find the start of the gap in the search range (which + * should contain our unknown inode). if the only irec + * within +/- 1 chunks starts after the inode we're + * looking for, skip this stuff since the end_agbno + * of the range has already been trimmed in to not + * include that irec. + */ + if (irec_before_p->ino_startnum < agino) { + irec_p = irec_before_p; + irec_next_p = next_ino_rec(irec_p); + + while(irec_next_p != NULL && + irec_p->ino_startnum + XFS_INODES_PER_CHUNK == + irec_next_p->ino_startnum) { + irec_p = irec_next_p; + irec_next_p = next_ino_rec(irec_next_p); + } + + start_agbno = XFS_AGINO_TO_AGBNO(mp, + irec_p->ino_startnum) + + XFS_IALLOC_BLOCKS(mp); + + /* + * we know that the inode we're trying to verify isn't + * in an inode chunk so the next ino_rec marks the end + * of the gap -- is it within the search range? + */ + if (irec_next_p != NULL && + agino + XFS_IALLOC_INODES(mp) >= + irec_next_p->ino_startnum) + end_agbno = XFS_AGINO_TO_AGBNO(mp, + irec_next_p->ino_startnum); + } + + ASSERT(start_agbno < end_agbno); + } + + /* + * if the gap is too small to contain a chunk, we lose. + * this means that inode chunks known to be good surround + * the inode in question and that the space between them + * is too small for a legal inode chunk + */ + if (end_agbno - start_agbno < XFS_IALLOC_BLOCKS(mp)) + return(0); + + /* + * now grunge around the disk, start at the inode block and + * go in each direction until you hit a non-inode block or + * run into a range boundary. A non-inode block is block + * with *no* good inodes in it. Unfortunately, we can't + * co-opt bad blocks into inode chunks (which might take + * care of disk blocks that turn into zeroes) because the + * filesystem could very well allocate two inode chunks + * with a one block file in between and we'd zap the file. + * We're better off just losing the rest of the + * inode chunk instead. + */ + for (cur_agbno = agbno; cur_agbno >= start_agbno; cur_agbno--) { + /* + * if the block has no inodes, it's a bad block so + * break out now without decrementing cur_agbno so + * chunk start blockno will be set to the last good block + */ + if (!(irec_cnt = check_aginode_block(mp, agno, cur_agbno))) + break; + ino_cnt += irec_cnt; + } + + chunk_start_agbno = cur_agbno + 1; + + for (cur_agbno = agbno + 1; cur_agbno < end_agbno; cur_agbno++) { + /* + * if the block has no inodes, it's a bad block so + * break out now without incrementing cur_agbno so + * chunk start blockno will be set to the block + * immediately after the last good block. + */ + if (!(irec_cnt = check_aginode_block(mp, agno, cur_agbno))) + break; + ino_cnt += irec_cnt; + } + + chunk_stop_agbno = cur_agbno; + + num_blks = chunk_stop_agbno - chunk_start_agbno; + + if (num_blks < XFS_IALLOC_BLOCKS(mp) || ino_cnt == 0) + return(0); + + /* + * XXX - later - if the entire range is selected and they're all + * good inodes, keep searching in either direction. + * until you the range of inodes end, then split into chunks + * for now, just take one chunk's worth starting at the lowest + * possible point and hopefully we'll pick the rest up later. + * + * XXX - if we were going to fix up an inode chunk for + * any good inodes in the chunk, this is where we would + * do it. For now, keep it simple and lose the rest of + * the chunk + */ + + if (num_blks % XFS_IALLOC_BLOCKS(mp) != 0) { + num_blks = rounddown(num_blks, XFS_IALLOC_BLOCKS(mp)); + chunk_stop_agbno = chunk_start_agbno + num_blks; + } + + /* + * ok, we've got a candidate inode chunk. now we have to + * verify that we aren't trying to use blocks that are already + * in use. If so, mark them as multiply claimed since odds + * are very low that we found this chunk by stumbling across + * user data -- we're probably here as a result of a directory + * entry or an iunlinked pointer + */ + for (j = 0, cur_agbno = chunk_start_agbno; + cur_agbno < chunk_stop_agbno; cur_agbno++) { + switch (state = get_agbno_state(mp, agno, cur_agbno)) { + case XR_E_MULT: + case XR_E_INUSE: + case XR_E_INUSE_FS: + case XR_E_FS_MAP: + do_warn( + "inode block %d/%d multiply claimed, (state %d)\n", + agno, cur_agbno, state); + set_agbno_state(mp, agno, cur_agbno, XR_E_MULT); + j = 1; + break; + case XR_E_INO: + do_error( + "uncertain inode block overlap, agbno = %d, ino = %llu\n", + agbno, ino); + break; + default: + break; + } + + if (j) + return(0); + } + + /* + * ok, chunk is good. put the record into the tree if required, + * and fill in the bitmap. All inodes will be marked as "free" + * except for the one that led us to discover the chunk. That's + * ok because we'll override the free setting later if the + * contents of the inode indicate it's in use. + */ + start_agino = XFS_OFFBNO_TO_AGINO(mp, chunk_start_agbno, 0); + *start_ino = XFS_AGINO_TO_INO(mp, agno, start_agino); + + ASSERT(find_inode_rec(agno, start_agino) == NULL); + + irec_p = set_inode_free_alloc(agno, start_agino); + for (i = 1; i < XFS_INODES_PER_CHUNK; i++) + set_inode_free(irec_p, i); + + ASSERT(start_agino <= agino && + start_agino + XFS_INODES_PER_CHUNK > agino); + + set_inode_used(irec_p, agino - start_agino); + + for (cur_agbno = chunk_start_agbno; + cur_agbno < chunk_stop_agbno; cur_agbno++) { + switch (state = get_agbno_state(mp, agno, cur_agbno)) { + case XR_E_INO: + do_error("uncertain inode block %llu already known\n", + XFS_AGB_TO_FSB(mp, agno, cur_agbno)); + break; + case XR_E_UNKNOWN: + case XR_E_FREE1: + case XR_E_FREE: + set_agbno_state(mp, agno, cur_agbno, XR_E_INO); + break; + case XR_E_MULT: + case XR_E_INUSE: + case XR_E_INUSE_FS: + case XR_E_FS_MAP: + do_error( + "inode block %d/%d multiply claimed, (state %d)\n", + agno, cur_agbno, state); + break; + default: + do_warn("inode block %d/%d bad state, (state %d)\n", + agno, cur_agbno, state); + set_agbno_state(mp, agno, cur_agbno, XR_E_INO); + break; + } + } + + return(ino_cnt); +} + +/* + * same as above only for ag inode chunks + */ +int +verify_aginode_chunk(xfs_mount_t *mp, + xfs_agnumber_t agno, + xfs_agino_t agino, + xfs_agino_t *agino_start) +{ + xfs_ino_t ino; + int res; + + res = verify_inode_chunk(mp, XFS_AGINO_TO_INO(mp, agno, agino), &ino); + + if (res) + *agino_start = XFS_INO_TO_AGINO(mp, ino); + else + *agino_start = NULLAGINO; + + return(res); +} + +/* + * this does the same as the two above only it returns a pointer + * to the inode record in the good inode tree + */ +ino_tree_node_t * +verify_aginode_chunk_irec(xfs_mount_t *mp, + xfs_agnumber_t agno, + xfs_agino_t agino) +{ + xfs_agino_t start_agino; + ino_tree_node_t *irec = NULL; + + if (verify_aginode_chunk(mp, agno, agino, &start_agino)) + irec = find_inode_rec(agno, start_agino); + + return(irec); +} + + + +/* + * processes an inode allocation chunk/block, returns 1 on I/O errors, + * 0 otherwise + * + * *bogus is set to 1 if the entire set of inodes is bad. + */ +/* ARGSUSED */ +int +process_inode_chunk(xfs_mount_t *mp, xfs_agnumber_t agno, int num_inos, + ino_tree_node_t *first_irec, int ino_discovery, + int check_dups, int extra_attr_check, int *bogus) +{ + xfs_ino_t parent; + ino_tree_node_t *ino_rec; + xfs_buf_t *bp; + xfs_dinode_t *dino; + int icnt; + int status; + int is_used; + int state; + int done; + int ino_dirty; + int irec_offset; + int ibuf_offset; + xfs_agino_t agino; + xfs_agblock_t agbno; + int dirty = 0; + int cleared = 0; + int isa_dir = 0; + + ASSERT(first_irec != NULL); + ASSERT(XFS_AGINO_TO_OFFSET(mp, first_irec->ino_startnum) == 0); + + *bogus = 0; + ASSERT(XFS_IALLOC_BLOCKS(mp) > 0); + + /* + * get all blocks required to read in this chunk (may wind up + * having to process more chunks in a multi-chunk per block fs) + */ + agbno = XFS_AGINO_TO_AGBNO(mp, first_irec->ino_startnum); + + bp = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, agbno), + XFS_FSB_TO_BB(mp, XFS_IALLOC_BLOCKS(mp)), 0); + if (!bp) { + do_warn("cannot read inode %llu, disk block %lld, cnt %d\n", + XFS_AGINO_TO_INO(mp, agno, first_irec->ino_startnum), + XFS_AGB_TO_DADDR(mp, agno, agbno), + (int)XFS_FSB_TO_BB(mp, XFS_IALLOC_BLOCKS(mp))); + return(1); + } + + /* + * set up first irec + */ + ino_rec = first_irec; + /* + * initialize counters + */ + irec_offset = 0; + ibuf_offset = 0; + icnt = 0; + status = 0; + done = 0; + + /* + * verify inode chunk if necessary + */ + if (ino_discovery) { + while (!done) { + /* + * make inode pointer + */ + dino = XFS_MAKE_IPTR(mp, bp, icnt); + agino = irec_offset + ino_rec->ino_startnum; + + /* + * we always think that the root and realtime + * inodes are verified even though we may have + * to reset them later to keep from losing the + * chunk that they're in + */ + if (verify_dinode(mp, dino, agno, agino) == 0 || + (agno == 0 && + (mp->m_sb.sb_rootino == agino || + mp->m_sb.sb_rsumino == agino || + mp->m_sb.sb_rbmino == agino))) + status++; + + irec_offset++; + icnt++; + + if (icnt == XFS_IALLOC_INODES(mp) && + irec_offset == XFS_INODES_PER_CHUNK) { + /* + * done! - finished up irec and block + * simultaneously + */ + libxfs_putbuf(bp); + done = 1; + break; + } else if (irec_offset == XFS_INODES_PER_CHUNK) { + /* + * get new irec (multiple chunks per block fs) + */ + ino_rec = next_ino_rec(ino_rec); + ASSERT(ino_rec->ino_startnum == agino + 1); + irec_offset = 0; + } + } + + /* + * if chunk/block is bad, blow it off. the inode records + * will be deleted by the caller if appropriate. + */ + if (!status) { + *bogus = 1; + if (!done) /* already free'd */ + libxfs_putbuf(bp); + return(0); + } + + /* + * reset irec and counters + */ + ino_rec = first_irec; + + irec_offset = 0; + ibuf_offset = 0; + icnt = 0; + status = 0; + done = 0; + + /* nathans TODO ... memory leak here?: */ + + /* + * get first block + */ + bp = libxfs_readbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, agno, agbno), + XFS_FSB_TO_BB(mp, XFS_IALLOC_BLOCKS(mp)), 0); + if (!bp) { + do_warn("can't read inode %llu, disk block %lld, " + "cnt %d\n", XFS_AGINO_TO_INO(mp, agno, agino), + XFS_AGB_TO_DADDR(mp, agno, agbno), + (int)XFS_FSB_TO_BB(mp, XFS_IALLOC_BLOCKS(mp))); + return(1); + } + } + + /* + * mark block as an inode block in the incore bitmap + */ + switch (state = get_agbno_state(mp, agno, agbno)) { + case XR_E_INO: /* already marked */ + break; + case XR_E_UNKNOWN: + case XR_E_FREE: + case XR_E_FREE1: + set_agbno_state(mp, agno, agbno, XR_E_INO); + break; + case XR_E_BAD_STATE: + do_error("bad state in block map %d\n", state); + break; + default: + set_agbno_state(mp, agno, agbno, XR_E_MULT); + do_warn("inode block %llu multiply claimed, state was %d\n", + XFS_AGB_TO_FSB(mp, agno, agbno), state); + break; + } + + while (!done) { + /* + * make inode pointer + */ + dino = XFS_MAKE_IPTR(mp, bp, icnt); + agino = irec_offset + ino_rec->ino_startnum; + + is_used = 3; + ino_dirty = 0; + parent = 0; + + status = process_dinode(mp, dino, agno, agino, + is_inode_free(ino_rec, irec_offset), + &ino_dirty, &cleared, &is_used, + ino_discovery, check_dups, + extra_attr_check, &isa_dir, &parent); + + ASSERT(is_used != 3); + if (ino_dirty) + dirty = 1; + /* + * XXX - if we want to try and keep + * track of whether we need to bang on + * the inode maps (instead of just + * blindly reconstructing them like + * we do now, this is where to start. + */ + if (is_used) { + if (is_inode_free(ino_rec, irec_offset)) { + if (verbose || no_modify || + XFS_AGINO_TO_INO(mp, agno, agino) != + old_orphanage_ino) { + do_warn("imap claims in-use inode %llu" + " is free, ", + XFS_AGINO_TO_INO(mp, agno, + agino)); + } + + if (verbose || (!no_modify && + XFS_AGINO_TO_INO(mp, agno, agino) != + old_orphanage_ino)) + do_warn("correcting imap\n"); + else + do_warn("would correct imap\n"); + } + set_inode_used(ino_rec, irec_offset); + } else { + set_inode_free(ino_rec, irec_offset); + } + + /* + * if we lose the root inode, or it turns into + * a non-directory, that allows us to double-check + * later whether or not we need to reinitialize it. + */ + if (isa_dir) { + set_inode_isadir(ino_rec, irec_offset); + /* + * we always set the parent but + * we may as well wait until + * phase 4 (no inode discovery) + * because the parent info will + * be solid then. + */ + if (!ino_discovery) { + ASSERT(parent != 0); + set_inode_parent(ino_rec, irec_offset, parent); + ASSERT(parent == + get_inode_parent(ino_rec, irec_offset)); + } + } else { + clear_inode_isadir(ino_rec, irec_offset); + } + + if (status) { + if (mp->m_sb.sb_rootino == + XFS_AGINO_TO_INO(mp, agno, agino)) { + need_root_inode = 1; + + if (!no_modify) { + do_warn("cleared root inode %llu\n", + XFS_AGINO_TO_INO(mp, agno, + agino)); + } else { + do_warn("would clear root inode %llu\n", + XFS_AGINO_TO_INO(mp, agno, + agino)); + } + } else if (mp->m_sb.sb_rbmino == + XFS_AGINO_TO_INO(mp, agno, agino)) { + need_rbmino = 1; + + if (!no_modify) { + do_warn("cleared realtime bitmap " + "inode %llu\n", + XFS_AGINO_TO_INO(mp, agno, + agino)); + } else { + do_warn("would clear realtime bitmap " + "inode %llu\n", + XFS_AGINO_TO_INO(mp, agno, + agino)); + } + } else if (mp->m_sb.sb_rsumino == + XFS_AGINO_TO_INO(mp, agno, agino)) { + need_rsumino = 1; + + if (!no_modify) { + do_warn("cleared realtime summary " + "inode %llu\n", + XFS_AGINO_TO_INO(mp, agno, + agino)); + } else { + do_warn("would clear realtime summary " + "inode %llu\n", + XFS_AGINO_TO_INO(mp, agno, + agino)); + } + } else if (!no_modify) { + do_warn("cleared inode %llu\n", + XFS_AGINO_TO_INO(mp, agno, agino)); + } else { + do_warn("would have cleared inode %llu\n", + XFS_AGINO_TO_INO(mp, agno, agino)); + } + } + + irec_offset++; + ibuf_offset++; + icnt++; + + if (icnt == XFS_IALLOC_INODES(mp) && + irec_offset == XFS_INODES_PER_CHUNK) { + /* + * done! - finished up irec and block simultaneously + */ + if (dirty && !no_modify) + libxfs_writebuf(bp, 0); + else + libxfs_putbuf(bp); + + done = 1; + break; + } else if (ibuf_offset == mp->m_sb.sb_inopblock) { + /* + * mark block as an inode block in the incore bitmap + * and reset inode buffer offset counter + */ + ibuf_offset = 0; + agbno++; + + switch (state = get_agbno_state(mp, agno, agbno)) { + case XR_E_INO: /* already marked */ + break; + case XR_E_UNKNOWN: + case XR_E_FREE: + case XR_E_FREE1: + set_agbno_state(mp, agno, agbno, XR_E_INO); + break; + case XR_E_BAD_STATE: + do_error( "bad state in block map %d\n", + state); + break; + default: + set_agbno_state(mp, agno, agbno, XR_E_MULT); + do_warn("inode block %llu multiply claimed, " + "state was %d\n", + XFS_AGB_TO_FSB(mp, agno, agbno), state); + break; + } + + } else if (irec_offset == XFS_INODES_PER_CHUNK) { + /* + * get new irec (multiple chunks per block fs) + */ + ino_rec = next_ino_rec(ino_rec); + ASSERT(ino_rec->ino_startnum == agino + 1); + irec_offset = 0; + } + } + return(0); +} + +/* + * check all inodes mentioned in the ag's incore inode maps. + * the map may be incomplete. If so, we'll catch the missing + * inodes (hopefully) when we traverse the directory tree. + * check_dirs is set to 1 if directory inodes should be + * processed for internal consistency, parent setting and + * discovery of unknown inodes. this only happens + * in phase 3. check_dups is set to 1 if we're looking for + * inodes that reference duplicate blocks so we can trash + * the inode right then and there. this is set only in + * phase 4 after we've run through and set the bitmap once. + */ +void +process_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno, + int ino_discovery, int check_dups, int extra_attr_check) +{ + int num_inos, bogus; + ino_tree_node_t *ino_rec, *first_ino_rec, *prev_ino_rec; + + first_ino_rec = ino_rec = findfirst_inode_rec(agno); + while (ino_rec != NULL) { + /* + * paranoia - step through inode records until we step + * through a full allocation of inodes. this could + * be an issue in big-block filesystems where a block + * can hold more than one inode chunk. make sure to + * grab the record corresponding to the beginning of + * the next block before we call the processing routines. + */ + num_inos = XFS_INODES_PER_CHUNK; + while (num_inos < XFS_IALLOC_INODES(mp) && ino_rec != NULL) { + ASSERT(ino_rec != NULL); + /* + * inodes chunks will always be aligned and sized + * correctly + */ + if ((ino_rec = next_ino_rec(ino_rec)) != NULL) + num_inos += XFS_INODES_PER_CHUNK; + } + + ASSERT(num_inos == XFS_IALLOC_INODES(mp)); + + if (process_inode_chunk(mp, agno, num_inos, first_ino_rec, + ino_discovery, check_dups, extra_attr_check, &bogus)) { + /* XXX - i/o error, we've got a problem */ + abort(); + } + + if (!bogus) + first_ino_rec = ino_rec = next_ino_rec(ino_rec); + else { + /* + * inodes pointed to by this record are + * completely bogus, blow the records for + * this chunk out. + * the inode block(s) will get reclaimed + * in phase 4 when the block map is + * reconstructed after inodes claiming + * duplicate blocks are deleted. + */ + num_inos = 0; + ino_rec = first_ino_rec; + while (num_inos < XFS_IALLOC_INODES(mp) && + ino_rec != NULL) { + prev_ino_rec = ino_rec; + + if ((ino_rec = next_ino_rec(ino_rec)) != NULL) + num_inos += XFS_INODES_PER_CHUNK; + + get_inode_rec(agno, prev_ino_rec); + free_inode_rec(agno, prev_ino_rec); + } + + first_ino_rec = ino_rec; + } + } +} + +/* + * verify the uncertain inode list for an ag. + * Good inodes get moved into the good inode tree. + * returns 0 if there are no uncertain inode records to + * be processed, 1 otherwise. This routine destroys the + * the entire uncertain inode tree for the ag as a side-effect. + */ +void +check_uncertain_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno) +{ + ino_tree_node_t *irec; + ino_tree_node_t *nrec; + xfs_agino_t start; + xfs_agino_t i; + xfs_agino_t agino; + int got_some; + + nrec = NULL; + got_some = 0; + + clear_uncertain_ino_cache(agno); + + if ((irec = findfirst_uncertain_inode_rec(agno)) == NULL) + return; + + /* + * the trick here is to find a contiguous range + * of inodes, make sure that it doesn't overlap + * with a known to exist chunk, and then make + * sure it is a number of entire chunks. + * we check on-disk once we have an idea of what's + * going on just to double-check. + * + * process the uncertain inode record list and look + * on disk to see if the referenced inodes are good + */ + + do_warn("found inodes not in the inode allocation tree\n"); + + do { + /* + * check every confirmed (which in this case means + * inode that we really suspect to be an inode) inode + */ + for (i = 0; i < XFS_INODES_PER_CHUNK; i++) { + if (!is_inode_confirmed(irec, i)) + continue; + + agino = i + irec->ino_startnum; + + if (verify_aginum(mp, agno, agino)) + continue; + + if (nrec != NULL && nrec->ino_startnum <= agino && + agino < nrec->ino_startnum + + XFS_INODES_PER_CHUNK) + continue; + + if ((nrec = find_inode_rec(agno, agino)) == NULL) + if (!verify_aginum(mp, agno, agino)) + if (verify_aginode_chunk(mp, agno, + agino, &start)) + got_some = 1; + } + + get_uncertain_inode_rec(agno, irec); + free_inode_rec(agno, irec); + + irec = findfirst_uncertain_inode_rec(agno); + } while (irec != NULL); + + if (got_some) + do_warn("found inodes not in the inode allocation tree\n"); + + return; +} + +/* + * verify and process the uncertain inodes for an ag. + * this is different from check_ in that we can't just + * move the good inodes into the good inode tree and let + * process_aginodes() deal with them because this gets called + * after process_aginodes() has been run on the ag inode tree. + * So we have to process the inodes as well as verify since + * we don't want to rerun process_aginodes() on a tree that has + * mostly been processed. + * + * Note that if this routine does process some inodes, it can + * add uncertain inodes to any ag which would require that + * the routine be called again to process those newly-added + * uncertain inodes. + * + * returns 0 if no inodes were processed and 1 if inodes + * were processed (and it is possible that new uncertain + * inodes were discovered). + * + * as a side-effect, this routine tears down the uncertain + * inode tree for the ag. + */ +int +process_uncertain_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno) +{ + ino_tree_node_t *irec; + ino_tree_node_t *nrec; + xfs_agino_t agino; + int i; + int bogus; + int cnt; + int got_some; + +#ifdef XR_INODE_TRACE + fprintf(stderr, "in process_uncertain_aginodes, agno = %d\n", agno); +#endif + + got_some = 0; + + clear_uncertain_ino_cache(agno); + + if ((irec = findfirst_uncertain_inode_rec(agno)) == NULL) + return(0); + + nrec = NULL; + + do { + /* + * check every confirmed inode + */ + for (cnt = i = 0; i < XFS_INODES_PER_CHUNK; i++) { + if (!is_inode_confirmed(irec, i)) + continue; + cnt++; + agino = i + irec->ino_startnum; +#ifdef XR_INODE_TRACE + fprintf(stderr, "ag inode = %d (0x%x)\n", agino, agino); +#endif + /* + * skip over inodes already processed (in the + * good tree), bad inode numbers, and inode numbers + * pointing to bogus inodes + */ + if (verify_aginum(mp, agno, agino)) + continue; + + if (nrec != NULL && nrec->ino_startnum <= agino && + agino < nrec->ino_startnum + + XFS_INODES_PER_CHUNK) + continue; + + if ((nrec = find_inode_rec(agno, agino)) != NULL) + continue; + + /* + * verify the chunk. if good, it will be + * added to the good inode tree. + */ + if ((nrec = verify_aginode_chunk_irec(mp, + agno, agino)) == NULL) + continue; + + got_some = 1; + + /* + * process the inode record we just added + * to the good inode tree. The inode + * processing may add more records to the + * uncertain inode lists. + */ + if (process_inode_chunk(mp, agno, XFS_IALLOC_INODES(mp), + nrec, 1, 0, 0, &bogus)) { + /* XXX - i/o error, we've got a problem */ + abort(); + } + } + + ASSERT(cnt != 0); + /* + * now return the uncertain inode record to the free pool + * and pull another one off the list for processing + */ + get_uncertain_inode_rec(agno, irec); + free_inode_rec(agno, irec); + + irec = findfirst_uncertain_inode_rec(agno); + } while (irec != NULL); + + if (got_some) + do_warn("found inodes not in the inode allocation tree\n"); + + return(1); +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/dinode.c linux-2.4-xfs/cmd/xfsprogs/repair/dinode.c --- linux-2.4.7/cmd/xfsprogs/repair/dinode.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/dinode.c Mon Apr 9 02:41:10 2001 @@ -0,0 +1,2915 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "avl.h" +#include "globals.h" +#include "agheader.h" +#include "incore.h" +#include "protos.h" +#include "err_protos.h" +#include "dir.h" +#include "dir2.h" +#include "dinode.h" +#include "scan.h" +#include "versions.h" +#include "attr_repair.h" +#include "bmap.h" + +/* + * inode clearing routines + */ + +/* + * return the offset into the inode where the attribute fork starts + */ +/* ARGSUSED */ +int +calc_attr_offset(xfs_mount_t *mp, xfs_dinode_t *dino) +{ + xfs_dinode_core_t *dinoc = &dino->di_core; + int offset = ((__psint_t) &dino->di_u) + - (__psint_t)dino; + + /* + * don't worry about alignment when calculating offset + * because the data fork is already 8-byte aligned + */ + switch (dinoc->di_format) { + case XFS_DINODE_FMT_DEV: + offset += sizeof(dev_t); + break; + case XFS_DINODE_FMT_LOCAL: + offset += INT_GET(dinoc->di_size, ARCH_CONVERT); + break; + case XFS_DINODE_FMT_UUID: + offset += sizeof(uuid_t); + break; + case XFS_DINODE_FMT_EXTENTS: + offset += INT_GET(dinoc->di_nextents, ARCH_CONVERT) * sizeof(xfs_bmbt_rec_32_t); + break; + case XFS_DINODE_FMT_BTREE: + offset += INT_GET(dino->di_u.di_bmbt.bb_numrecs, ARCH_CONVERT) * sizeof(xfs_bmbt_rec_32_t); + break; + default: + do_error("Unknown inode format.\n"); + abort(); + break; + } + + return(offset); +} + +/* ARGSUSED */ +int +clear_dinode_attr(xfs_mount_t *mp, xfs_dinode_t *dino, xfs_ino_t ino_num) +{ + xfs_dinode_core_t *dinoc = &dino->di_core; + + ASSERT(dinoc->di_forkoff != 0); + + if (!no_modify) + fprintf(stderr, "clearing inode %llu attributes \n", + (unsigned long long)ino_num); + else + fprintf(stderr, "would have cleared inode %llu attributes\n", + (unsigned long long)ino_num); + + if (INT_GET(dinoc->di_anextents, ARCH_CONVERT) != 0) { + if (no_modify) + return(1); + INT_ZERO(dinoc->di_anextents, ARCH_CONVERT); + } + + if (dinoc->di_aformat != XFS_DINODE_FMT_EXTENTS) { + if (no_modify) + return(1); + dinoc->di_aformat = XFS_DINODE_FMT_EXTENTS; + } + + /* get rid of the fork by clearing forkoff */ + + /* Originally, when the attr repair code was added, the fork was cleared + * by turning it into shortform status. This meant clearing the + * hdr.totsize/count fields and also changing aformat to LOCAL + * (vs EXTENTS). Over various fixes, the aformat and forkoff have + * been updated to not show an attribute fork at all, however. + * It could be possible that resetting totsize/count are not needed, + * but just to be safe, leave it in for now. + */ + + if (!no_modify) { + xfs_attr_shortform_t *asf = (xfs_attr_shortform_t *) + XFS_DFORK_APTR_ARCH(dino, ARCH_CONVERT); + INT_SET(asf->hdr.totsize, ARCH_CONVERT, + sizeof(xfs_attr_sf_hdr_t)); + INT_SET(asf->hdr.count, ARCH_CONVERT, 0); + dinoc->di_forkoff = 0; /* got to do this after asf is set */ + } + + /* + * always returns 1 since the fork gets zapped + */ + return(1); +} + +/* ARGSUSED */ +int +clear_dinode_core(xfs_dinode_core_t *dinoc, xfs_ino_t ino_num) +{ + int dirty = 0; + + if (INT_GET(dinoc->di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) { + dirty = 1; + + if (no_modify) + return(1); + + INT_SET(dinoc->di_magic, ARCH_CONVERT, XFS_DINODE_MAGIC); + } + + if (!XFS_DINODE_GOOD_VERSION(dinoc->di_version) || + (!fs_inode_nlink && dinoc->di_version > XFS_DINODE_VERSION_1)) { + dirty = 1; + + if (no_modify) + return(1); + + dinoc->di_version = (fs_inode_nlink) ? XFS_DINODE_VERSION_2 + : XFS_DINODE_VERSION_1; + } + + if (INT_GET(dinoc->di_mode, ARCH_CONVERT) != 0) { + dirty = 1; + + if (no_modify) + return(1); + + INT_ZERO(dinoc->di_mode, ARCH_CONVERT); + } + + if (INT_GET(dinoc->di_flags, ARCH_CONVERT) != 0) { + dirty = 1; + + if (no_modify) + return(1); + + INT_ZERO(dinoc->di_flags, ARCH_CONVERT); + } + + if (INT_GET(dinoc->di_dmevmask, ARCH_CONVERT) != 0) { + dirty = 1; + + if (no_modify) + return(1); + + INT_ZERO(dinoc->di_dmevmask, ARCH_CONVERT); + } + + if (dinoc->di_forkoff != 0) { + dirty = 1; + + if (no_modify) + return(1); + + dinoc->di_forkoff = 0; + } + + if (dinoc->di_format != XFS_DINODE_FMT_EXTENTS) { + dirty = 1; + + if (no_modify) + return(1); + + dinoc->di_format = XFS_DINODE_FMT_EXTENTS; + } + + if (dinoc->di_aformat != XFS_DINODE_FMT_EXTENTS) { + dirty = 1; + + if (no_modify) + return(1); + + dinoc->di_aformat = XFS_DINODE_FMT_EXTENTS; + } + + if (INT_GET(dinoc->di_size, ARCH_CONVERT) != 0) { + dirty = 1; + + if (no_modify) + return(1); + + INT_ZERO(dinoc->di_size, ARCH_CONVERT); + } + + if (INT_GET(dinoc->di_nblocks, ARCH_CONVERT) != 0) { + dirty = 1; + + if (no_modify) + return(1); + + INT_ZERO(dinoc->di_nblocks, ARCH_CONVERT); + } + + if (INT_GET(dinoc->di_onlink, ARCH_CONVERT) != 0) { + dirty = 1; + + if (no_modify) + return(1); + + INT_ZERO(dinoc->di_onlink, ARCH_CONVERT); + } + + if (INT_GET(dinoc->di_nextents, ARCH_CONVERT) != 0) { + dirty = 1; + + if (no_modify) + return(1); + + INT_ZERO(dinoc->di_nextents, ARCH_CONVERT); + } + + if (INT_GET(dinoc->di_anextents, ARCH_CONVERT) != 0) { + dirty = 1; + + if (no_modify) + return(1); + + INT_ZERO(dinoc->di_anextents, ARCH_CONVERT); + } + + if (dinoc->di_version > XFS_DINODE_VERSION_1 && + INT_GET(dinoc->di_nlink, ARCH_CONVERT) != 0) { + dirty = 1; + + if (no_modify) + return(1); + + INT_ZERO(dinoc->di_nlink, ARCH_CONVERT); + } + + return(dirty); +} + +/* ARGSUSED */ +int +clear_dinode_unlinked(xfs_mount_t *mp, xfs_dinode_t *dino) +{ + + if (dino->di_next_unlinked != NULLAGINO) { + if (!no_modify) + dino->di_next_unlinked = NULLAGINO; + return(1); + } + + return(0); +} + +/* + * this clears the unlinked list too so it should not be called + * until after the agi unlinked lists are walked in phase 3. + * returns > zero if the inode has been altered while being cleared + */ +int +clear_dinode(xfs_mount_t *mp, xfs_dinode_t *dino, xfs_ino_t ino_num) +{ + int dirty; + + dirty = clear_dinode_core(&dino->di_core, ino_num); + dirty += clear_dinode_unlinked(mp, dino); + + /* and clear the forks */ + + if (dirty && !no_modify) + bzero(&dino->di_u, XFS_LITINO(mp)); + + return(dirty); +} + + +/* + * misc. inode-related utility routines + */ + +/* + * returns 0 if inode number is valid, 1 if bogus + */ +int +verify_inum(xfs_mount_t *mp, + xfs_ino_t ino) +{ + xfs_agnumber_t agno; + xfs_agino_t agino; + xfs_agblock_t agbno; + xfs_sb_t *sbp = &mp->m_sb;; + + /* range check ag #, ag block. range-checking offset is pointless */ + + agno = XFS_INO_TO_AGNO(mp, ino); + agino = XFS_INO_TO_AGINO(mp, ino); + agbno = XFS_AGINO_TO_AGBNO(mp, agino); + + if (ino == 0 || ino == NULLFSINO) + return(1); + + if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) + return(1); + + if (agno >= sbp->sb_agcount || + (agno < sbp->sb_agcount && agbno >= sbp->sb_agblocks) || + (agno == sbp->sb_agcount && agbno >= sbp->sb_dblocks - + (sbp->sb_agcount-1) * sbp->sb_agblocks) || + (agbno == 0)) + return(1); + + return(0); +} + +/* + * have a separate routine to ensure that we don't accidentally + * lose illegally set bits in the agino by turning it into an FSINO + * to feed to the above routine + */ +int +verify_aginum(xfs_mount_t *mp, + xfs_agnumber_t agno, + xfs_agino_t agino) +{ + xfs_agblock_t agbno; + xfs_sb_t *sbp = &mp->m_sb;; + + /* range check ag #, ag block. range-checking offset is pointless */ + + if (agino == 0 || agino == NULLAGINO) + return(1); + + /* + * agino's can't be too close to NULLAGINO because the min blocksize + * is 9 bits and at most 1 bit of that gets used for the inode offset + * so if the agino gets shifted by the # of offset bits and compared + * to the legal agbno values, a bogus agino will be too large. there + * will be extra bits set at the top that shouldn't be set. + */ + agbno = XFS_AGINO_TO_AGBNO(mp, agino); + + if (agno >= sbp->sb_agcount || + (agno < sbp->sb_agcount && agbno >= sbp->sb_agblocks) || + (agno == sbp->sb_agcount && agbno >= sbp->sb_dblocks - + (sbp->sb_agcount-1) * sbp->sb_agblocks) || + (agbno == 0)) + return(1); + + return(0); +} + +/* + * return 1 if block number is good, 0 if out of range + */ +int +verify_dfsbno(xfs_mount_t *mp, + xfs_dfsbno_t fsbno) +{ + xfs_agnumber_t agno; + xfs_agblock_t agbno; + xfs_sb_t *sbp = &mp->m_sb;; + + /* range check ag #, ag block. range-checking offset is pointless */ + + agno = XFS_FSB_TO_AGNO(mp, fsbno); + agbno = XFS_FSB_TO_AGBNO(mp, fsbno); + + if (agno >= sbp->sb_agcount || + (agno < sbp->sb_agcount && agbno >= sbp->sb_agblocks) || + (agno == sbp->sb_agcount && agbno >= sbp->sb_dblocks - + (sbp->sb_agcount-1) * sbp->sb_agblocks)) + return(0); + + return(1); +} + +int +verify_agbno(xfs_mount_t *mp, + xfs_agnumber_t agno, + xfs_agblock_t agbno) +{ + xfs_sb_t *sbp = &mp->m_sb;; + + /* range check ag #, ag block. range-checking offset is pointless */ + + if (agno >= sbp->sb_agcount || + (agno < sbp->sb_agcount && agbno >= sbp->sb_agblocks) || + (agno == sbp->sb_agcount && agbno >= sbp->sb_dblocks - + (sbp->sb_agcount-1) * sbp->sb_agblocks)) + return(0); + + return(1); +} + +void +convert_extent( + xfs_bmbt_rec_32_t *rp, + xfs_dfiloff_t *op, /* starting offset (blockno in file) */ + xfs_dfsbno_t *sp, /* starting block (fs blockno) */ + xfs_dfilblks_t *cp, /* blockcount */ + int *fp) /* extent flag */ +{ + xfs_bmbt_irec_t irec, *s = &irec; + /* Just use the extent parsing routine from the kernel */ + libxfs_bmbt_get_all((xfs_bmbt_rec_t *)rp, s); + + if (fs_has_extflgbit) { + if (s->br_state == XFS_EXT_UNWRITTEN) { + *fp = 1; + } else { + *fp = 0; + } + } else { + *fp = 0; + } + *op = s->br_startoff; + *sp = s->br_startblock; + *cp = s->br_blockcount; +} + +/* + * return address of block fblock if it's within the range described + * by the extent list. Otherwise, returns a null address. + */ +/* ARGSUSED */ +xfs_dfsbno_t +get_bmbt_reclist( + xfs_mount_t *mp, + xfs_bmbt_rec_32_t *rp, + int numrecs, + xfs_dfiloff_t fblock) +{ + int i; + xfs_dfilblks_t cnt; + xfs_dfiloff_t off_bno; + xfs_dfsbno_t start; + int flag; + + for (i = 0; i < numrecs; i++, rp++) { + convert_extent(rp, &off_bno, &start, &cnt, &flag); + if (off_bno >= fblock && off_bno + cnt < fblock) + return(start + fblock - off_bno); + } + + return(NULLDFSBNO); +} + +/* + * return 1 if inode should be cleared, 0 otherwise + * if check_dups should be set to 1, that implies that + * the primary purpose of this call is to see if the + * file overlaps with any duplicate extents (in the + * duplicate extent list). + */ +/* ARGSUSED */ +int +process_bmbt_reclist_int( + xfs_mount_t *mp, + xfs_bmbt_rec_32_t *rp, + int numrecs, + int type, + xfs_ino_t ino, + xfs_drfsbno_t *tot, + blkmap_t **blkmapp, + xfs_dfiloff_t *first_key, + xfs_dfiloff_t *last_key, + int check_dups, + int whichfork) +{ + xfs_dfsbno_t b; + xfs_drtbno_t ext; + xfs_dfilblks_t c; /* count */ + xfs_dfilblks_t cp = 0; /* prev count */ + xfs_dfsbno_t s; /* start */ + xfs_dfsbno_t sp = 0; /* prev start */ + xfs_dfiloff_t o = 0; /* offset */ + xfs_dfiloff_t op = 0; /* prev offset */ + char *ftype; + char *forkname; + int i; + int state; + int flag; /* extent flag */ + + if (whichfork == XFS_DATA_FORK) + forkname = "data"; + else + forkname = "attr"; + + if (type == XR_INO_RTDATA) + ftype = "real-time"; + else + ftype = "regular"; + + for (i = 0; i < numrecs; i++, rp++) { + convert_extent(rp, &o, &s, &c, &flag); + if (i == 0) + *last_key = *first_key = o; + else + *last_key = o; + if (i > 0 && op + cp > o) { + do_warn( +"bmap rec out of order, inode %llu entry %d [o s c] [%llu %llu %llu], %d [%llu %llu %llu]\n", + ino, i, o, s, c, i-1, op, sp, cp); + return(1); + } + op = o; + cp = c; + sp = s; + + /* + * check numeric validity of the extent + */ + if (c == 0) { + do_warn( + "zero length extent (off = %llu, fsbno = %llu) in ino %llu\n", + o, s, ino); + return(1); + } + if (type == XR_INO_RTDATA) { + if (s >= mp->m_sb.sb_rblocks) { + do_warn( +"inode %llu - bad rt extent starting block number %llu, offset %llu\n", + ino, s, o); + return(1); + } + if (s + c - 1 >= mp->m_sb.sb_rblocks) { + do_warn( +"inode %llu - bad rt extent last block number %llu, offset %llu\n", + ino, s + c - 1, o); + return(1); + } + if (s + c - 1 < s) { + do_warn( +"inode %llu - bad rt extent overflows - start %llu, end %llu, offset %llu\n", + ino, s, s + c - 1, o); + return(1); + } + } else { + if (!verify_dfsbno(mp, s)) { + do_warn( +"inode %llu - bad extent starting block number %llu, offset %llu\n", + ino, s, o); + return(1); + } + if (!verify_dfsbno(mp, s + c - 1)) { + do_warn( +"inode %llu - bad extent last block number %llu, offset %llu\n", + ino, s + c - 1, o); + return(1); + } + if (s + c - 1 < s) { + do_warn( +"inode %llu - bad extent overflows - start %llu, end %llu, offset %llu\n", + ino, s, s + c - 1, o); + return(1); + } + if (o >= fs_max_file_offset) { + do_warn( +"inode %llu - extent offset too large - start %llu, count %llu, offset %llu\n", + ino, s, c, o); + return(1); + } + } + + /* + * realtime file data fork + */ + if (type == XR_INO_RTDATA && whichfork == XFS_DATA_FORK) { + /* + * XXX - verify that the blocks listed in the record + * are multiples of an extent + */ + if (s % mp->m_sb.sb_rextsize != 0 || + c % mp->m_sb.sb_rextsize != 0) { + do_warn( +"malformed rt inode extent [%llu %llu] (fs rtext size = %u)\n", + s, c, mp->m_sb.sb_rextsize); + return(1); + } + + /* + * XXX - set the appropriate number of extents + */ + for (b = s; b < s + c; b += mp->m_sb.sb_rextsize) { + ext = (xfs_drtbno_t) b / mp->m_sb.sb_rextsize; + + if (check_dups == 1) { + if (search_rt_dup_extent(mp, ext)) { + do_warn( +"data fork in rt ino %llu claims dup rt extent, off - %llu, start - %llu, count %llu\n", + ino, o, s, c); + return(1); + } + continue; + } + + state = get_rtbno_state(mp, ext); + + switch (state) { + case XR_E_FREE: +/* XXX - turn this back on after we + run process_rtbitmap() in phase2 + do_warn( + "%s fork in rt ino %llu claims free rt block %llu\n", + forkname, ino, ext); +*/ + /* fall through ... */ + case XR_E_UNKNOWN: + set_rtbno_state(mp, ext, XR_E_INUSE); + break; + case XR_E_BAD_STATE: + do_error( + "bad state in rt block map %llu\n", ext); + abort(); + break; + case XR_E_FS_MAP: + case XR_E_INO: + case XR_E_INUSE_FS: + do_error( + "%s fork in rt inode %llu found metadata block %llu in %s bmap\n", + forkname, ino, ext, ftype); + case XR_E_INUSE: + case XR_E_MULT: + set_rtbno_state(mp, ext, XR_E_MULT); + do_warn( + "%s fork in rt inode %llu claims used rt block %llu\n", + forkname, ino, ext); + return(1); + case XR_E_FREE1: + default: + do_error( + "illegal state %d in %s block map %llu\n", + state, ftype, b); + } + } + + /* + * bump up the block counter + */ + *tot += c; + + /* + * skip rest of loop processing since that's + * all for regular file forks and attr forks + */ + continue; + } + + + /* + * regular file data fork or attribute fork + */ + if (blkmapp && *blkmapp) + blkmap_set_ext(blkmapp, o, s, c); + for (b = s; b < s + c; b++) { + if (check_dups == 1) { + /* + * if we're just checking the bmap for dups, + * return if we find one, otherwise, continue + * checking each entry without setting the + * block bitmap + */ + if (search_dup_extent(mp, + XFS_FSB_TO_AGNO(mp, b), + XFS_FSB_TO_AGBNO(mp, b))) { + do_warn( +"%s fork in ino %llu claims dup extent, off - %llu, start - %llu, cnt %llu\n", + forkname, ino, o, s, c); + return(1); + } + continue; + } + + /* FIX FOR BUG 653709 -- EKN + * realtime attribute fork, should be valid block number + * in regular data space, not realtime partion. + */ + if (type == XR_INO_RTDATA && whichfork == XFS_ATTR_FORK) { + if (mp->m_sb.sb_agcount < XFS_FSB_TO_AGNO(mp, b)) + return(1); + } + + state = get_fsbno_state(mp, b); + switch (state) { + case XR_E_FREE: + case XR_E_FREE1: + do_warn( + "%s fork in ino %llu claims free block %llu\n", + forkname, ino, (__uint64_t) b); + /* fall through ... */ + case XR_E_UNKNOWN: + set_fsbno_state(mp, b, XR_E_INUSE); + break; + case XR_E_BAD_STATE: + do_error("bad state in block map %llu\n", b); + abort(); + break; + case XR_E_FS_MAP: + case XR_E_INO: + case XR_E_INUSE_FS: + do_warn( + "%s fork in inode %llu claims metadata block %llu\n", + forkname, ino, (__uint64_t) b); + return(1); + case XR_E_INUSE: + case XR_E_MULT: + set_fsbno_state(mp, b, XR_E_MULT); + do_warn( + "%s fork in %s inode %llu claims used block %llu\n", + forkname, ftype, ino, (__uint64_t) b); + return(1); + default: + do_error("illegal state %d in block map %llu\n", + state, b); + abort(); + } + } + *tot += c; + } + + return(0); +} + +/* + * return 1 if inode should be cleared, 0 otherwise, sets block bitmap + * as a side-effect + */ +int +process_bmbt_reclist( + xfs_mount_t *mp, + xfs_bmbt_rec_32_t *rp, + int numrecs, + int type, + xfs_ino_t ino, + xfs_drfsbno_t *tot, + blkmap_t **blkmapp, + xfs_dfiloff_t *first_key, + xfs_dfiloff_t *last_key, + int whichfork) +{ + return(process_bmbt_reclist_int(mp, rp, numrecs, type, ino, tot, + blkmapp, first_key, last_key, 0, + whichfork)); +} + +/* + * return 1 if inode should be cleared, 0 otherwise, does not set + * block bitmap + */ +int +scan_bmbt_reclist( + xfs_mount_t *mp, + xfs_bmbt_rec_32_t *rp, + int numrecs, + int type, + xfs_ino_t ino, + xfs_drfsbno_t *tot, + int whichfork) +{ + xfs_dfiloff_t first_key = 0; + xfs_dfiloff_t last_key = 0; + + return(process_bmbt_reclist_int(mp, rp, numrecs, type, ino, tot, + NULL, &first_key, &last_key, 1, + whichfork)); +} + +/* + * these two are meant for routines that read and work with inodes + * one at a time where the inodes may be in any order (like walking + * the unlinked lists to look for inodes). the caller is responsible + * for writing/releasing the buffer. + */ +xfs_buf_t * +get_agino_buf(xfs_mount_t *mp, + xfs_agnumber_t agno, + xfs_agino_t agino, + xfs_dinode_t **dipp) +{ + ino_tree_node_t *irec; + xfs_buf_t *bp; + int size; + + if ((irec = find_inode_rec(agno, agino)) == NULL) + return(NULL); + + size = XFS_FSB_TO_BB(mp, MAX(1, XFS_INODES_PER_CHUNK/inodes_per_block)); + bp = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, + XFS_AGINO_TO_AGBNO(mp, irec->ino_startnum)), size, 0); + if (!bp) { + do_warn("cannot read inode (%u/%u), disk block %lld\n", + agno, irec->ino_startnum, + XFS_AGB_TO_DADDR(mp, agno, + XFS_AGINO_TO_AGBNO(mp, irec->ino_startnum))); + return(NULL); + } + + *dipp = XFS_MAKE_IPTR(mp, bp, agino - + XFS_OFFBNO_TO_AGINO(mp, XFS_AGINO_TO_AGBNO(mp, + irec->ino_startnum), + 0)); + + return(bp); +} + +/* + * these next routines return the filesystem blockno of the + * block containing the block "bno" in the file whose bmap + * tree (or extent list) is rooted by "rootblock". + * + * the next routines are utility routines for the third + * routine, get_bmapi(). + */ +/* ARGSUSED */ +xfs_dfsbno_t +getfunc_extlist(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + xfs_dfiloff_t bno, + int whichfork) +{ + xfs_dfiloff_t fbno; + xfs_dfilblks_t bcnt; + xfs_dfsbno_t fsbno; + xfs_dfsbno_t final_fsbno = NULLDFSBNO; + xfs_bmbt_rec_32_t *rootblock = (xfs_bmbt_rec_32_t *) + XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT); + xfs_extnum_t nextents = XFS_DFORK_NEXTENTS_ARCH(dip, whichfork, ARCH_CONVERT); + int i; + int flag; + + for (i = 0; i < nextents; i++) { + convert_extent(rootblock + i, &fbno, &fsbno, &bcnt, &flag); + + if (fbno <= bno && bno < fbno + bcnt) { + final_fsbno = bno - fbno + fsbno; + break; + } + } + + return(final_fsbno); +} + +xfs_dfsbno_t +getfunc_btree(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + xfs_dfiloff_t bno, + int whichfork) +{ + int i; + int prev_level; + int flag; + int found; + xfs_bmbt_rec_32_t *rec; + xfs_bmbt_ptr_t *pp; + xfs_bmbt_key_t *key; + xfs_bmdr_key_t *rkey; + xfs_bmdr_ptr_t *rp; + xfs_dfiloff_t fbno; + xfs_dfsbno_t fsbno; + xfs_dfilblks_t bcnt; + xfs_buf_t *bp; + xfs_dfsbno_t final_fsbno = NULLDFSBNO; + xfs_bmbt_block_t *block; + xfs_bmdr_block_t *rootblock = (xfs_bmdr_block_t *) + XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT); + + ASSERT(rootblock->bb_level != 0); + /* + * deal with root block, it's got a slightly different + * header structure than interior nodes. We know that + * a btree should have at least 2 levels otherwise it + * would be an extent list. + */ + rkey = XFS_BTREE_KEY_ADDR( + XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_CONVERT), + xfs_bmdr, rootblock, 1, + XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_SIZE_ARCH(dip, + mp, whichfork, ARCH_CONVERT), + xfs_bmdr, 1)); + rp = XFS_BTREE_PTR_ADDR( + XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_CONVERT), + xfs_bmdr, rootblock, 1, + XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_SIZE_ARCH(dip, + mp, whichfork, ARCH_CONVERT), + xfs_bmdr, 1)); + for (found = -1, i = 0; i < rootblock->bb_numrecs - 1; i++) { + if (rkey[i].br_startoff <= bno + && bno < rkey[i+1].br_startoff) { + found = i; + break; + } + } + if (i == rootblock->bb_numrecs - 1 && bno >= rkey[i].br_startoff) + found = i; + + ASSERT(found != -1); + + fsbno = INT_GET(rp[found], ARCH_CONVERT); + + ASSERT(verify_dfsbno(mp, fsbno)); + + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + do_error("cannot read bmap block %llu\n", fsbno); + return(NULLDFSBNO); + } + block = XFS_BUF_TO_BMBT_BLOCK(bp); + + /* + * ok, now traverse any interior btree nodes + */ + prev_level = rootblock->bb_level; + + while (INT_GET(block->bb_level, ARCH_CONVERT) > 0) { + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) < prev_level); + + prev_level = INT_GET(block->bb_level, ARCH_CONVERT); + + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > + mp->m_bmap_dmxr[1]) { + do_warn("# of bmap records in inode %llu exceeds max " + "(%u, max - %u)\n", + ino, INT_GET(block->bb_numrecs, ARCH_CONVERT), + mp->m_bmap_dmxr[1]); + libxfs_putbuf(bp); + return(NULLDFSBNO); + } + if (verbose && INT_GET(block->bb_numrecs, ARCH_CONVERT) < + mp->m_bmap_dmnr[1]) { + do_warn("- # of bmap records in inode %llu < than min " + "(%u, min - %u), proceeding ...\n", + ino, INT_GET(block->bb_numrecs, ARCH_CONVERT), + mp->m_bmap_dmnr[1]); + } + key = XFS_BTREE_KEY_ADDR(mp->m_sb.sb_blocksize, + xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]); + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, + xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]); + for ( found = -1, i = 0; + i < INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1; + i++) { + if (INT_GET(key[i].br_startoff, ARCH_CONVERT) <= bno && + bno < INT_GET(key[i+1].br_startoff, ARCH_CONVERT)) { + found = i; + break; + } + } + if (i == INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1 && + bno >= INT_GET(key[i].br_startoff, ARCH_CONVERT)) + found = i; + + ASSERT(found != -1); + fsbno = INT_GET(pp[found], ARCH_CONVERT); + + ASSERT(verify_dfsbno(mp, fsbno)); + + /* + * release current btree block and read in the + * next btree block to be traversed + */ + libxfs_putbuf(bp); + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + do_error("cannot read bmap block %llu\n", fsbno); + return(NULLDFSBNO); + } + block = XFS_BUF_TO_BMBT_BLOCK(bp); + } + + /* + * current block must be a leaf block + */ + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) == 0); + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_bmap_dmxr[0]) { + do_warn("# of bmap records in inode %llu greater than max " + "(%u, max - %u)\n", + ino, INT_GET(block->bb_numrecs, ARCH_CONVERT), + mp->m_bmap_dmxr[0]); + libxfs_putbuf(bp); + return(NULLDFSBNO); + } + if (verbose && INT_GET(block->bb_numrecs, ARCH_CONVERT) < + mp->m_bmap_dmnr[0]) + do_warn("- # of bmap records in inode %llu < min " + "(%u, min - %u), continuing...\n", + ino, INT_GET(block->bb_numrecs, ARCH_CONVERT), + mp->m_bmap_dmnr[0]); + + rec = (xfs_bmbt_rec_32_t *)XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, + xfs_bmbt, block, 1, mp->m_bmap_dmxr[0]); + for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) { + convert_extent(rec + i, &fbno, &fsbno, &bcnt, &flag); + + if (fbno <= bno && bno < fbno + bcnt) { + final_fsbno = bno - fbno + fsbno; + break; + } + } + libxfs_putbuf(bp); + + if (final_fsbno == NULLDFSBNO) + do_warn("could not map block %llu\n", bno); + + return(final_fsbno); +} + +/* + * this could be smarter. maybe we should have an open inode + * routine that would get the inode buffer and return back + * an inode handle. I'm betting for the moment that this + * is used only by the directory and attribute checking code + * and that the avl tree find and buffer cache search are + * relatively cheap. If they're too expensive, we'll just + * have to fix this and add an inode handle to the da btree + * cursor. + * + * caller is responsible for checking doubly referenced blocks + * and references to holes + */ +xfs_dfsbno_t +get_bmapi(xfs_mount_t *mp, xfs_dinode_t *dino_p, + xfs_ino_t ino_num, xfs_dfiloff_t bno, int whichfork) +{ + xfs_dfsbno_t fsbno; + + switch (XFS_DFORK_FORMAT_ARCH(dino_p, whichfork, ARCH_CONVERT)) { + case XFS_DINODE_FMT_EXTENTS: + fsbno = getfunc_extlist(mp, ino_num, dino_p, bno, whichfork); + break; + case XFS_DINODE_FMT_BTREE: + fsbno = getfunc_btree(mp, ino_num, dino_p, bno, whichfork); + break; + case XFS_DINODE_FMT_LOCAL: + do_error("get_bmapi() called for local inode %llu\n", ino_num); + fsbno = NULLDFSBNO; + break; + default: + /* + * shouldn't happen + */ + do_error("bad inode format for inode %llu\n", ino_num); + fsbno = NULLDFSBNO; + } + + return(fsbno); +} + +/* + * higher level inode processing stuff starts here: + * first, one utility routine for each type of inode + */ + +/* + * return 1 if inode should be cleared, 0 otherwise + */ +/* ARGSUSED */ +int +process_btinode( + xfs_mount_t *mp, + xfs_agnumber_t agno, + xfs_agino_t ino, + xfs_dinode_t *dip, + int type, + int *dirty, + xfs_drfsbno_t *tot, + __uint64_t *nex, + blkmap_t **blkmapp, + int whichfork, + int check_dups) +{ + xfs_bmdr_block_t *dib; + xfs_dfiloff_t last_key; + xfs_dfiloff_t first_key = 0; + xfs_ino_t lino; + xfs_bmbt_ptr_t *pp; + xfs_bmbt_key_t *pkey; + char *forkname; + int i; + bmap_cursor_t cursor; + + dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT); + lino = XFS_AGINO_TO_INO(mp, agno, ino); + *tot = 0; + *nex = 0; + + if (whichfork == XFS_DATA_FORK) + forkname = "data"; + else + forkname = "attr"; + + if (INT_GET(dib->bb_level, ARCH_CONVERT) == 0) { + /* + * This should never happen since a btree inode + * has to have at least one other block in the + * bmap in addition to the root block in the + * inode's data fork. + * + * XXX - if we were going to fix up the inode, + * we'd try to treat the fork as an interior + * node and see if we could get an accurate + * level value from one of the blocks pointed + * to by the pointers in the fork. For now + * though, we just bail (and blow out the inode). + */ + do_warn("bad level 0 in inode %llu bmap btree root block\n", + XFS_AGINO_TO_INO(mp, agno, ino)); + return(1); + } + /* + * use bmdr/dfork_dsize since the root block is in the data fork + */ + init_bm_cursor(&cursor, INT_GET(dib->bb_level, ARCH_CONVERT) + 1); + + if (XFS_BMDR_SPACE_CALC(INT_GET(dib->bb_numrecs, ARCH_CONVERT)) > + ((whichfork == XFS_DATA_FORK) ? + XFS_DFORK_DSIZE_ARCH(dip, mp, ARCH_CONVERT) : + XFS_DFORK_ASIZE_ARCH(dip, mp, ARCH_CONVERT))) { + do_warn( +"indicated size of %s btree root (%d bytes) > space in inode %llu %s fork\n", + forkname, XFS_BMDR_SPACE_CALC(INT_GET(dib->bb_numrecs, ARCH_CONVERT)), + lino, forkname); + return(1); + } + + pp = XFS_BTREE_PTR_ADDR(XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_CONVERT), + xfs_bmdr, dib, 1, + XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_CONVERT), + xfs_bmdr, 0)); + pkey = XFS_BTREE_KEY_ADDR(XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_CONVERT), + xfs_bmdr, dib, 1, + XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_CONVERT), + xfs_bmdr, 0)); + + last_key = NULLDFILOFF; + + for (i = 0; i < INT_GET(dib->bb_numrecs, ARCH_CONVERT); i++) { + /* + * XXX - if we were going to do more to fix up the inode + * btree, we'd do it right here. For now, if there's a + * problem, we'll bail out and presumably clear the inode. + */ + if (!verify_dfsbno(mp, INT_GET(pp[i], ARCH_CONVERT))) { + do_warn("bad bmap btree ptr 0x%llx in ino %llu\n", + INT_GET(pp[i], ARCH_CONVERT), lino); + return(1); + } + + if (scan_lbtree((xfs_dfsbno_t)INT_GET(pp[i], ARCH_CONVERT), INT_GET(dib->bb_level, ARCH_CONVERT), + scanfunc_bmap, type, whichfork, + lino, tot, nex, blkmapp, &cursor, + 1, check_dups)) + return(1); + /* + * fix key (offset) mismatches between the keys in root + * block records and the first key of each child block. + * fixes cases where entries have been shifted between + * blocks but the parent hasn't been updated + */ + if (check_dups == 0 && + cursor.level[INT_GET(dib->bb_level, ARCH_CONVERT)-1].first_key != + INT_GET(pkey[i].br_startoff, ARCH_CONVERT)) { + if (!no_modify) { + do_warn( +"correcting key in bmbt root (was %llu, now %llu) in inode %llu %s fork\n", + INT_GET(pkey[i].br_startoff, ARCH_CONVERT), + cursor.level[INT_GET(dib->bb_level, ARCH_CONVERT)-1].first_key, + XFS_AGINO_TO_INO(mp, agno, ino), + forkname); + *dirty = 1; + INT_SET(pkey[i].br_startoff, ARCH_CONVERT, cursor.level[INT_GET(dib->bb_level, ARCH_CONVERT)-1].first_key); + } else { + do_warn( +"bad key in bmbt root (is %llu, would reset to %llu) in inode %llu %s fork\n", + INT_GET(pkey[i].br_startoff, ARCH_CONVERT), + cursor.level[INT_GET(dib->bb_level, ARCH_CONVERT)-1].first_key, + XFS_AGINO_TO_INO(mp, agno, ino), + forkname); + } + } + /* + * make sure that keys are in ascending order. blow out + * inode if the ordering doesn't hold + */ + if (check_dups == 0) { + if (last_key != NULLDFILOFF && last_key >= + cursor.level[INT_GET(dib->bb_level, ARCH_CONVERT)-1].first_key) { + do_warn( + "out of order bmbt root key %llu in inode %llu %s fork\n", + first_key, + XFS_AGINO_TO_INO(mp, agno, ino), + forkname); + return(1); + } + last_key = cursor.level[INT_GET(dib->bb_level, ARCH_CONVERT)-1].first_key; + } + } + /* + * Check that the last child block's forward sibling pointer + * is NULL. + */ + if (check_dups == 0 && + cursor.level[0].right_fsbno != NULLDFSBNO) { + do_warn( + "bad fwd (right) sibling pointer (saw %llu should be NULLDFSBNO)\n", + cursor.level[0].right_fsbno); + do_warn( + "\tin inode %u (%s fork) bmap btree block %llu\n", + XFS_AGINO_TO_INO(mp, agno, ino), forkname, + cursor.level[0].fsbno); + return(1); + } + + return(0); +} + +/* + * return 1 if inode should be cleared, 0 otherwise + */ +/* ARGSUSED */ +int +process_exinode( + xfs_mount_t *mp, + xfs_agnumber_t agno, + xfs_agino_t ino, + xfs_dinode_t *dip, + int type, + int *dirty, + xfs_drfsbno_t *tot, + __uint64_t *nex, + blkmap_t **blkmapp, + int whichfork, + int check_dups) +{ + xfs_ino_t lino; + xfs_bmbt_rec_32_t *rp; + xfs_dfiloff_t first_key; + xfs_dfiloff_t last_key; + + lino = XFS_AGINO_TO_INO(mp, agno, ino); + rp = (xfs_bmbt_rec_32_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT); + *tot = 0; + *nex = XFS_DFORK_NEXTENTS_ARCH(dip, whichfork, ARCH_CONVERT); + /* + * XXX - if we were going to fix up the btree record, + * we'd do it right here. For now, if there's a problem, + * we'll bail out and presumably clear the inode. + */ + if (check_dups == 0) + return(process_bmbt_reclist(mp, rp, *nex, type, lino, + tot, blkmapp, &first_key, &last_key, + whichfork)); + else + return(scan_bmbt_reclist(mp, rp, *nex, type, lino, tot, + whichfork)); +} + +/* + * return 1 if inode should be cleared, 0 otherwise + */ +/* ARGSUSED */ +int +process_lclinode( + xfs_mount_t *mp, + xfs_agnumber_t agno, + xfs_agino_t ino, + xfs_dinode_t *dip, + int type, + int *dirty, + xfs_drfsbno_t *tot, + __uint64_t *nex, + blkmap_t **blkmapp, + int whichfork, + int check_dups) +{ + xfs_attr_shortform_t *asf; + xfs_dinode_core_t *dic; + xfs_ino_t lino; + + *tot = 0; + *nex = 0; /* local inodes have 0 extents */ + + dic = &dip->di_core; + lino = XFS_AGINO_TO_INO(mp, agno, ino); + if (whichfork == XFS_DATA_FORK && + INT_GET(dic->di_size, ARCH_CONVERT) > XFS_DFORK_DSIZE_ARCH(dip, mp, ARCH_CONVERT)) { + do_warn( + "local inode %llu data fork is too large (size = %lld, max = %d)\n", + lino, INT_GET(dic->di_size, ARCH_CONVERT), XFS_DFORK_DSIZE_ARCH(dip, mp, ARCH_CONVERT)); + return(1); + } else if (whichfork == XFS_ATTR_FORK) { + asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT); + if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) > XFS_DFORK_ASIZE_ARCH(dip, mp, ARCH_CONVERT)) { + do_warn( + "local inode %llu attr fork too large (size %d, max = %d)\n", + lino, INT_GET(asf->hdr.totsize, ARCH_CONVERT), + XFS_DFORK_ASIZE_ARCH(dip, mp, ARCH_CONVERT)); + return(1); + } + if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) < sizeof(xfs_attr_sf_hdr_t)) { + do_warn( + "local inode %llu attr too small (size = %d, min size = %d)\n", + lino, INT_GET(asf->hdr.totsize, ARCH_CONVERT), + sizeof(xfs_attr_sf_hdr_t)); + return(1); + } + } + + return(0); +} + +int +process_symlink_extlist(xfs_mount_t *mp, xfs_ino_t lino, xfs_dinode_t *dino) +{ + xfs_dfsbno_t start; /* start */ + xfs_dfilblks_t cnt; /* count */ + xfs_dfiloff_t offset; /* offset */ + xfs_dfiloff_t expected_offset; + xfs_bmbt_rec_32_t *rp; + int numrecs; + int i; + int max_blocks; + int whichfork = XFS_DATA_FORK; + int flag; + + if (INT_GET(dino->di_core.di_size, ARCH_CONVERT) <= XFS_DFORK_SIZE_ARCH(dino, mp, whichfork, ARCH_CONVERT)) { + if (dino->di_core.di_format == XFS_DINODE_FMT_LOCAL) { + return(0); + } else { + do_warn( +"mismatch between format (%d) and size (%lld) in symlink ino %llu\n", + dino->di_core.di_format, + INT_GET(dino->di_core.di_size, ARCH_CONVERT), + lino); + return(1); + } + } else if (dino->di_core.di_format == XFS_DINODE_FMT_LOCAL) { + do_warn( +"mismatch between format (%d) and size (%lld) in symlink inode %llu\n", + dino->di_core.di_format, + INT_GET(dino->di_core.di_size, ARCH_CONVERT), + lino); + return(1); + } + + rp = (xfs_bmbt_rec_32_t *)XFS_DFORK_PTR_ARCH(dino, whichfork, ARCH_CONVERT); + numrecs = XFS_DFORK_NEXTENTS_ARCH(dino, whichfork, ARCH_CONVERT); + + /* + * the max # of extents in a symlink inode is equal to the + * number of max # of blocks required to store the symlink + */ + if (numrecs > max_symlink_blocks) { + do_warn( + "bad number of extents (%d) in symlink %llu data fork\n", + numrecs, lino); + return(1); + } + + max_blocks = max_symlink_blocks; + expected_offset = 0; + + for (i = 0; numrecs > 0; i++, numrecs--) { + convert_extent(rp, &offset, &start, &cnt, &flag); + + if (offset != expected_offset) { + do_warn( + "bad extent #%d offset (%llu) in symlink %llu data fork\n", + i, offset, lino); + return(1); + } + if (cnt == 0 || cnt > max_blocks) { + do_warn( + "bad extent #%d count (%llu) in symlink %llu data fork\n", + i, cnt, lino); + return(1); + } + + max_blocks -= cnt; + expected_offset += cnt; + } + + return(0); +} + +/* + * takes a name and length and returns 1 if the name contains + * a \0, returns 0 otherwise + */ +int +null_check(char *name, int length) +{ + int i; + + ASSERT(length < MAXPATHLEN); + + for (i = 0; i < length; i++, name++) { + if (*name == '\0') + return(1); + } + + return(0); +} + +/* + * like usual, returns 0 if everything's ok and 1 if something's + * bogus + */ +int +process_symlink(xfs_mount_t *mp, xfs_ino_t lino, xfs_dinode_t *dino, + blkmap_t *blkmap) +{ + xfs_dfsbno_t fsbno; + xfs_dinode_core_t *dinoc = &dino->di_core; + xfs_buf_t *bp = NULL; + char *symlink, *cptr, *buf_data; + int i, size, amountdone; + char data[MAXPATHLEN]; + + /* + * check size against kernel symlink limits. we know + * size is consistent with inode storage format -- e.g. + * the inode is structurally ok so we don't have to check + * for that + */ + if (INT_GET(dinoc->di_size, ARCH_CONVERT) >= MAXPATHLEN) { + do_warn("symlink in inode %llu too long (%lld chars)\n", + lino, INT_GET(dinoc->di_size, ARCH_CONVERT)); + return(1); + } + + /* + * have to check symlink component by component. + * get symlink contents into data area + */ + symlink = &data[0]; + if (INT_GET(dinoc->di_size, ARCH_CONVERT) + <= XFS_DFORK_DSIZE_ARCH(dino, mp, ARCH_CONVERT)) { + /* + * local symlink, just copy the symlink out of the + * inode into the data area + */ + bcopy((char *)XFS_DFORK_DPTR_ARCH(dino, ARCH_CONVERT), + symlink, INT_GET(dinoc->di_size, ARCH_CONVERT)); + } else { + /* + * stored in a meta-data file, have to bmap one block + * at a time and copy the symlink into the data area + */ + i = size = amountdone = 0; + cptr = symlink; + + while (amountdone < INT_GET(dinoc->di_size, ARCH_CONVERT)) { + fsbno = blkmap_get(blkmap, i); + if (fsbno != NULLDFSBNO) + bp = libxfs_readbuf(mp->m_dev, + XFS_FSB_TO_DADDR(mp, fsbno), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp || fsbno == NULLDFSBNO) { + do_warn("cannot read inode %llu, file block %d," + " disk block %llu\n", lino, i, fsbno); + return(1); + } + + buf_data = (char *)XFS_BUF_PTR(bp); + size = MIN(INT_GET(dinoc->di_size, ARCH_CONVERT) + - amountdone, (int)XFS_FSB_TO_BB(mp, 1)*BBSIZE); + bcopy(buf_data, cptr, size); + cptr += size; + amountdone += size; + i++; + libxfs_putbuf(bp); + } + } + data[INT_GET(dinoc->di_size, ARCH_CONVERT)] = '\0'; + + /* + * check for nulls + */ + if (null_check(symlink, (int) INT_GET(dinoc->di_size, ARCH_CONVERT))) { + do_warn("found illegal null character in symlink inode %llu\n", + lino); + return(1); + } + + /* + * check for any component being too long + */ + if (INT_GET(dinoc->di_size, ARCH_CONVERT) >= MAXNAMELEN) { + cptr = strchr(symlink, '/'); + + while (cptr != NULL) { + if (cptr - symlink >= MAXNAMELEN) { + do_warn( + "component of symlink in inode %llu too long\n", + lino); + return(1); + } + symlink = cptr + 1; + cptr = strchr(symlink, '/'); + } + + if (strlen(symlink) >= MAXNAMELEN) { + do_warn("component of symlink in inode %llu too long\n", + lino); + return(1); + } + } + + return(0); +} + +/* + * called to process the set of misc inode special inode types + * that have no associated data storage (fifos, pipes, devices, etc.). + */ +/* ARGSUSED */ +int +process_misc_ino_types(xfs_mount_t *mp, + xfs_dinode_t *dino, + xfs_ino_t lino, + int type) +{ + /* + * disallow mountpoint inodes until such time as the + * kernel actually allows them to be created (will + * probably require a superblock version rev, sigh). + */ + if (type == XR_INO_MOUNTPOINT) { + do_warn("inode %llu has bad inode type (IFMNT)\n", lino); + return(1); + } + + /* + * must also have a zero size + */ + if (INT_GET(dino->di_core.di_size, ARCH_CONVERT) != 0) { + switch (type) { + case XR_INO_CHRDEV: + do_warn("size of character device inode %llu != 0 " + "(%lld bytes)\n", lino, + INT_GET(dino->di_core.di_size, ARCH_CONVERT)); + break; + case XR_INO_BLKDEV: + do_warn("size of block device inode %llu != 0 " + "(%lld bytes)\n", lino, + INT_GET(dino->di_core.di_size, ARCH_CONVERT)); + break; + case XR_INO_SOCK: + do_warn("size of socket inode %llu != 0 " + "(%lld bytes)\n", lino, + INT_GET(dino->di_core.di_size, ARCH_CONVERT)); + break; + case XR_INO_FIFO: + do_warn("size of fifo inode %llu != 0 " + "(%lld bytes)\n", lino, + INT_GET(dino->di_core.di_size, ARCH_CONVERT)); + break; + default: + do_warn("Internal error - process_misc_ino_types, " + "illegal type %d\n", type); + abort(); + } + + return(1); + } + + return(0); +} + +int +process_misc_ino_types_blocks(xfs_drfsbno_t totblocks, xfs_ino_t lino, int type) +{ + /* + * you can not enforce all misc types have zero data fork blocks + * by checking dino->di_core.di_nblocks because atotblocks (attribute + * blocks) are part of nblocks. We must check this later when atotblocks + * has been calculated or by doing a simple check that anExtents == 0. + * We must also guarantee that totblocks is 0. Thus nblocks checking + * will be done later in process_dinode_int for misc types. + */ + + if (totblocks != 0) { + switch (type) { + case XR_INO_CHRDEV: + do_warn( + "size of character device inode %llu != 0 (%llu blocks)\n", + lino, totblocks); + break; + case XR_INO_BLKDEV: + do_warn( + "size of block device inode %llu != 0 (%llu blocks)\n", + lino, totblocks); + break; + case XR_INO_SOCK: + do_warn( + "size of socket inode %llu != 0 (%llu blocks)\n", + lino, totblocks); + break; + case XR_INO_FIFO: + do_warn( + "size of fifo inode %llu != 0 (%llu blocks)\n", + lino, totblocks); + break; + default: + return(0); + } + return(1); + } + return (0); +} + +/* + * returns 0 if the inode is ok, 1 if the inode is corrupt + * check_dups can be set to 1 *only* when called by the + * first pass of the duplicate block checking of phase 4. + * *dirty is set > 0 if the dinode has been altered and + * needs to be written out. + * + * for detailed, info, look at process_dinode() comments. + */ +/* ARGSUSED */ +int +process_dinode_int(xfs_mount_t *mp, + xfs_dinode_t *dino, + xfs_agnumber_t agno, + xfs_agino_t ino, + int was_free, /* 1 if inode is currently free */ + int *dirty, /* out == > 0 if inode is now dirty */ + int *cleared, /* out == 1 if inode was cleared */ + int *used, /* out == 1 if inode is in use */ + int verify_mode, /* 1 == verify but don't modify inode */ + int uncertain, /* 1 == inode is uncertain */ + int ino_discovery, /* 1 == check dirs for unknown inodes */ + int check_dups, /* 1 == check if inode claims + * duplicate blocks */ + int extra_attr_check, /* 1 == do attribute format and value checks */ + int *isa_dir, /* out == 1 if inode is a directory */ + xfs_ino_t *parent) /* out -- parent if ino is a dir */ +{ + xfs_drfsbno_t totblocks = 0; + xfs_drfsbno_t atotblocks = 0; + xfs_dinode_core_t *dinoc; + char *rstring; + int type; + int rtype; + int do_rt; + int err; + int retval = 0; + __uint64_t nextents; + __uint64_t anextents; + xfs_ino_t lino; + const int is_free = 0; + const int is_used = 1; + int repair = 0; + blkmap_t *ablkmap = NULL; + blkmap_t *dblkmap = NULL; + static char okfmts[] = { + 0, /* free inode */ + 1 << XFS_DINODE_FMT_DEV, /* FIFO */ + 1 << XFS_DINODE_FMT_DEV, /* CHR */ + 0, /* type 3 unused */ + (1 << XFS_DINODE_FMT_LOCAL) | + (1 << XFS_DINODE_FMT_EXTENTS) | + (1 << XFS_DINODE_FMT_BTREE), /* DIR */ + 0, /* type 5 unused */ + 1 << XFS_DINODE_FMT_DEV, /* BLK */ + 0, /* type 7 unused */ + (1 << XFS_DINODE_FMT_EXTENTS) | + (1 << XFS_DINODE_FMT_BTREE), /* REG */ + 0, /* type 9 unused */ + (1 << XFS_DINODE_FMT_LOCAL) | + (1 << XFS_DINODE_FMT_EXTENTS), /* LNK */ + 0, /* type 11 unused */ + 1 << XFS_DINODE_FMT_DEV, /* SOCK */ + 0, /* type 13 unused */ + 1 << XFS_DINODE_FMT_UUID, /* MNT */ + 0 /* type 15 unused */ + }; + + retval = 0; + totblocks = atotblocks = 0; + *dirty = *isa_dir = *cleared = 0; + *used = is_used; + type = rtype = XR_INO_UNKNOWN; + rstring = NULL; + do_rt = 0; + + dinoc = &dino->di_core; + lino = XFS_AGINO_TO_INO(mp, agno, ino); + + /* + * if in verify mode, don't modify the inode. + * + * if correcting, reset stuff that has known values + * + * if in uncertain mode, be silent on errors since we're + * trying to find out if these are inodes as opposed + * to assuming that they are. Just return the appropriate + * return code in that case. + */ + + if (INT_GET(dinoc->di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) { + retval++; + if (!verify_mode) { + do_warn("bad magic number 0x%x on inode %llu, ", + INT_GET(dinoc->di_magic, ARCH_CONVERT), lino); + if (!no_modify) { + do_warn("resetting magic number\n"); + *dirty = 1; + INT_SET(dinoc->di_magic, ARCH_CONVERT, XFS_DINODE_MAGIC); + } else { + do_warn("would reset magic number\n"); + } + } else if (!uncertain) { + do_warn("bad magic number 0x%x on inode %llu\n", + INT_GET(dinoc->di_magic, ARCH_CONVERT), lino); + } + } + + if (!XFS_DINODE_GOOD_VERSION(dinoc->di_version) || + (!fs_inode_nlink && dinoc->di_version > XFS_DINODE_VERSION_1)) { + retval++; + if (!verify_mode) { + do_warn("bad version number 0x%x on inode %llu, ", + dinoc->di_version, lino); + if (!no_modify) { + do_warn("resetting version number\n"); + *dirty = 1; + dinoc->di_version = (fs_inode_nlink) ? + XFS_DINODE_VERSION_2 : + XFS_DINODE_VERSION_1; + } else { + do_warn("would reset version number\n"); + } + } else if (!uncertain) { + do_warn("bad version number 0x%x on inode %llu\n", + dinoc->di_version, lino); + } + } + + /* + * blow out of here if the inode size is < 0 + */ + if (INT_GET(dinoc->di_size, ARCH_CONVERT) < 0) { + retval++; + if (!verify_mode) { + do_warn("bad (negative) size %lld on inode %llu\n", + INT_GET(dinoc->di_size, ARCH_CONVERT), lino); + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + *cleared = 1; + } else { + *dirty = 1; + *cleared = 1; + } + *used = is_free; + } else if (!uncertain) { + do_warn("bad (negative) size %lld on inode %llu\n", + INT_GET(dinoc->di_size, ARCH_CONVERT), lino); + } + + return(1); + } + + /* + * was_free value is not meaningful if we're in verify mode + */ + if (!verify_mode && INT_GET(dinoc->di_mode, ARCH_CONVERT) == 0 && was_free == 1) { + /* + * easy case, inode free -- inode and map agree, clear + * it just in case to ensure that format, etc. are + * set correctly + */ + if (!no_modify) { + err = clear_dinode(mp, dino, lino); + if (err) { + *dirty = 1; + *cleared = 1; + } + } + *used = is_free; + return(0); + } else if (!verify_mode && INT_GET(dinoc->di_mode, ARCH_CONVERT) == 0 && was_free == 0) { + /* + * the inode looks free but the map says it's in use. + * clear the inode just to be safe and mark the inode + * free. + */ + do_warn("imap claims a free inode %llu is in use, ", lino); + + if (!no_modify) { + do_warn("correcting imap and clearing inode\n"); + + err = clear_dinode(mp, dino, lino); + if (err) { + retval++; + *dirty = 1; + *cleared = 1; + } + } else { + do_warn("would correct imap and clear inode\n"); + + *dirty = 1; + *cleared = 1; + } + + *used = is_free; + + return(retval > 0 ? 1 : 0); + } + + /* + * because of the lack of any write ordering guarantee, it's + * possible that the core got updated but the forks didn't. + * so rather than be ambitious (and probably incorrect), + * if there's an inconsistency, we get conservative and + * just pitch the file. blow off checking formats of + * free inodes since technically any format is legal + * as we reset the inode when we re-use it. + */ + if (INT_GET(dinoc->di_mode, ARCH_CONVERT) != 0 && + ((((INT_GET(dinoc->di_mode, ARCH_CONVERT) & IFMT) >> 12) > 15) || + dinoc->di_format < XFS_DINODE_FMT_DEV || + dinoc->di_format > XFS_DINODE_FMT_UUID || + (!(okfmts[(INT_GET(dinoc->di_mode, ARCH_CONVERT) & IFMT) >> 12] & + (1 << dinoc->di_format))))) { + /* bad inode format */ + retval++; + if (!uncertain) + do_warn("bad inode format in inode %llu\n", lino); + if (!verify_mode) { + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + ASSERT(*dirty > 0); + } + } + *cleared = 1; + *used = is_free; + + return(retval > 0 ? 1 : 0); + } + + if (verify_mode) + return(retval > 0 ? 1 : 0); + + /* + * clear the next unlinked field if necessary on a good + * inode only during phase 4 -- when checking for inodes + * referencing duplicate blocks. then it's safe because + * we've done the inode discovery and have found all the inodes + * we're going to find. check_dups is set to 1 only during + * phase 4. Ugly. + */ + if (check_dups && !no_modify) + *dirty += clear_dinode_unlinked(mp, dino); + + /* set type and map type info */ + + switch (INT_GET(dinoc->di_mode, ARCH_CONVERT) & IFMT) { + case IFDIR: + type = XR_INO_DIR; + *isa_dir = 1; + break; + case IFREG: + if (INT_GET(dinoc->di_flags, ARCH_CONVERT) & XFS_DIFLAG_REALTIME) + type = XR_INO_RTDATA; + else if (lino == mp->m_sb.sb_rbmino) + type = XR_INO_RTBITMAP; + else if (lino == mp->m_sb.sb_rsumino) + type = XR_INO_RTSUM; + else + type = XR_INO_DATA; + break; + case IFLNK: + type = XR_INO_SYMLINK; + break; + case IFCHR: + type = XR_INO_CHRDEV; + break; + case IFBLK: + type = XR_INO_BLKDEV; + break; + case IFSOCK: + type = XR_INO_SOCK; + break; + case IFIFO: + type = XR_INO_FIFO; + break; + case IFMNT: + type = XR_INO_MOUNTPOINT; + break; + default: + type = XR_INO_UNKNOWN; + do_warn("Unexpected inode type %#o inode %llu\n", + (int) (INT_GET(dinoc->di_mode, ARCH_CONVERT) & IFMT), lino); + abort(); + break; + } + + /* + * type checks for root, realtime inodes, and quota inodes + */ + if (lino == mp->m_sb.sb_rootino && type != XR_INO_DIR) { + do_warn("bad inode type for root inode %llu, ", lino); + type = XR_INO_DIR; + + if (!no_modify) { + do_warn("resetting to directory\n"); + INT_MOD_EXPR(dinoc->di_mode, ARCH_CONVERT, &= ~(INT_GET(dinoc->di_mode, ARCH_CONVERT) & IFMT)); + INT_MOD_EXPR(dinoc->di_mode, ARCH_CONVERT, |= INT_GET(dinoc->di_mode, ARCH_CONVERT) & IFDIR); + } else { + do_warn("would reset to directory\n"); + } + } else if (lino == mp->m_sb.sb_rsumino) { + do_rt = 1; + rstring = "summary"; + rtype = XR_INO_RTSUM; + } else if (lino == mp->m_sb.sb_rbmino) { + do_rt = 1; + rstring = "bitmap"; + rtype = XR_INO_RTBITMAP; + } else if (lino == mp->m_sb.sb_uquotino) { + if (type != XR_INO_DATA) { + do_warn("user quota inode has bad type 0x%x\n", + INT_GET(dinoc->di_mode, ARCH_CONVERT) & IFMT); + + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + ASSERT(*dirty > 0); + } + + *cleared = 1; + *used = is_free; + *isa_dir = 0; + + mp->m_sb.sb_uquotino = NULLFSINO; + + return(1); + } + } else if (lino == mp->m_sb.sb_gquotino) { + if (type != XR_INO_DATA) { + do_warn("group quota inode has bad type 0x%x\n", + INT_GET(dinoc->di_mode, ARCH_CONVERT) & IFMT); + + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + ASSERT(*dirty > 0); + } + + *cleared = 1; + *used = is_free; + *isa_dir = 0; + + mp->m_sb.sb_gquotino = NULLFSINO; + + return(1); + } + } + + if (do_rt && type != rtype) { + type = XR_INO_DATA; + + do_warn("bad inode type for realtime %s inode %llu, ", + rstring, lino); + + if (!no_modify) { + do_warn("resetting to regular file\n"); + INT_MOD_EXPR(dinoc->di_mode, ARCH_CONVERT, &= ~(INT_GET(dinoc->di_mode, ARCH_CONVERT) & IFMT)); + INT_MOD_EXPR(dinoc->di_mode, ARCH_CONVERT, |= INT_GET(dinoc->di_mode, ARCH_CONVERT) & IFREG); + } else { + do_warn("would reset to regular file\n"); + } + } + + /* + * only realtime inodes should have extsize set + */ + if (type != XR_INO_RTDATA && INT_GET(dinoc->di_extsize, ARCH_CONVERT) != 0) { + do_warn( +"bad non-zero extent size value %u for non-realtime inode %llu,", + INT_GET(dinoc->di_extsize, ARCH_CONVERT), lino); + + if (!no_modify) { + do_warn("resetting to zero\n"); + INT_ZERO(dinoc->di_extsize, ARCH_CONVERT); + *dirty = 1; + } else { + do_warn("would reset to zero\n"); + } + } + + /* + * for realtime inodes, check sizes to see that + * they are consistent with the # of realtime blocks. + * also, verify that they contain only one extent and + * are extent format files. If anything's wrong, clear + * the inode -- we'll recreate it in phase 6. + */ + if (do_rt && INT_GET(dinoc->di_size, ARCH_CONVERT) + != mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize) { + do_warn("bad size %llu for realtime %s inode %llu\n", + INT_GET(dinoc->di_size, ARCH_CONVERT), rstring, lino); + + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + ASSERT(*dirty > 0); + } + + *cleared = 1; + *used = is_free; + *isa_dir = 0; + + return(1); + } + + if (do_rt && mp->m_sb.sb_rblocks == 0 && INT_GET(dinoc->di_nextents, ARCH_CONVERT) != 0) { + do_warn("bad # of extents (%u) for realtime %s inode %llu\n", + INT_GET(dinoc->di_nextents, ARCH_CONVERT), rstring, lino); + + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + ASSERT(*dirty > 0); + } + + *cleared = 1; + *used = is_free; + *isa_dir = 0; + + return(1); + } + + /* + * Setup nextents and anextents for blkmap_alloc calls. + */ + nextents = INT_GET(dinoc->di_nextents, ARCH_CONVERT); + if (nextents > INT_GET(dinoc->di_nblocks, ARCH_CONVERT) || nextents > XFS_MAX_INCORE_EXTENTS) + nextents = 1; + anextents = INT_GET(dinoc->di_anextents, ARCH_CONVERT); + if (anextents > INT_GET(dinoc->di_nblocks, ARCH_CONVERT) || anextents > XFS_MAX_INCORE_EXTENTS) + anextents = 1; + + /* + * general size/consistency checks: + * + * if the size <= size of the data fork, directories must be + * local inodes unlike regular files which would be extent inodes. + * all the other mentioned types have to have a zero size value. + * + * if the size and format don't match, get out now rather than + * risk trying to process a non-existent extents or btree + * type data fork. + */ + switch (type) { + case XR_INO_DIR: + if (INT_GET(dinoc->di_size, ARCH_CONVERT) <= XFS_DFORK_DSIZE_ARCH(dino, mp, ARCH_CONVERT) + && dinoc->di_format != XFS_DINODE_FMT_LOCAL) { + do_warn( +"mismatch between format (%d) and size (%lld) in directory ino %llu\n", + dinoc->di_format, + INT_GET(dinoc->di_size, ARCH_CONVERT), + lino); + + if (!no_modify) { + *dirty += clear_dinode(mp, + dino, lino); + ASSERT(*dirty > 0); + } + + *cleared = 1; + *used = is_free; + *isa_dir = 0; + + return(1); + } + if (dinoc->di_format != XFS_DINODE_FMT_LOCAL) + dblkmap = blkmap_alloc(nextents); + break; + case XR_INO_SYMLINK: + if (process_symlink_extlist(mp, lino, dino)) { + do_warn("bad data fork in symlink %llu\n", lino); + + if (!no_modify) { + *dirty += clear_dinode(mp, + dino, lino); + ASSERT(*dirty > 0); + } + + *cleared = 1; + *used = is_free; + *isa_dir = 0; + + return(1); + } + if (dinoc->di_format != XFS_DINODE_FMT_LOCAL) + dblkmap = blkmap_alloc(nextents); + break; + case XR_INO_CHRDEV: /* fall through to FIFO case ... */ + case XR_INO_BLKDEV: /* fall through to FIFO case ... */ + case XR_INO_SOCK: /* fall through to FIFO case ... */ + case XR_INO_MOUNTPOINT: /* fall through to FIFO case ... */ + case XR_INO_FIFO: + if (process_misc_ino_types(mp, dino, lino, type)) { + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + ASSERT(*dirty > 0); + } + + *cleared = 1; + *used = is_free; + *isa_dir = 0; + + return(1); + } + break; + case XR_INO_RTDATA: + /* + * if we have no realtime blocks, any inode claiming + * to be a real-time file is bogus + */ + if (mp->m_sb.sb_rblocks == 0) { + do_warn( + "found inode %llu claiming to be a real-time file\n", + lino); + + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + ASSERT(*dirty > 0); + } + + *cleared = 1; + *used = is_free; + *isa_dir = 0; + + return(1); + } + break; + case XR_INO_RTBITMAP: + if (INT_GET(dinoc->di_size, ARCH_CONVERT) != (__int64_t) mp->m_sb.sb_rbmblocks * + mp->m_sb.sb_blocksize) { + do_warn( + "realtime bitmap inode %llu has bad size %lld (should be %lld)\n", + lino, INT_GET(dinoc->di_size, ARCH_CONVERT), + (__int64_t) mp->m_sb.sb_rbmblocks * + mp->m_sb.sb_blocksize); + + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + ASSERT(*dirty > 0); + } + + *cleared = 1; + *used = is_free; + *isa_dir = 0; + + return(1); + } + dblkmap = blkmap_alloc(nextents); + break; + case XR_INO_RTSUM: + if (INT_GET(dinoc->di_size, ARCH_CONVERT) != mp->m_rsumsize) { + do_warn( + "realtime summary inode %llu has bad size %lld (should be %d)\n", + lino, INT_GET(dinoc->di_size, ARCH_CONVERT), mp->m_rsumsize); + + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + ASSERT(*dirty > 0); + } + + *cleared = 1; + *used = is_free; + *isa_dir = 0; + + return(1); + } + dblkmap = blkmap_alloc(nextents); + break; + default: + break; + } + + /* + * check for illegal values of forkoff + */ + err = 0; + if (dinoc->di_forkoff != 0) { + switch (dinoc->di_format) { + case XFS_DINODE_FMT_DEV: + if (dinoc->di_forkoff != + (roundup(sizeof(dev_t), 8) >> 3)) { + do_warn( + "bad attr fork offset %d in dev inode %llu, should be %d\n", + (int) dinoc->di_forkoff, + lino, + (int) (roundup(sizeof(dev_t), 8) >> 3)); + err = 1; + } + break; + case XFS_DINODE_FMT_UUID: + if (dinoc->di_forkoff != + (roundup(sizeof(uuid_t), 8) >> 3)) { + do_warn( + "bad attr fork offset %d in uuid inode %llu, should be %d\n", + (int) dinoc->di_forkoff, + lino, + (int)(roundup(sizeof(uuid_t), 8) >> 3)); + err = 1; + } + break; + case XFS_DINODE_FMT_LOCAL: /* fall through ... */ + case XFS_DINODE_FMT_EXTENTS: /* fall through ... */ + case XFS_DINODE_FMT_BTREE: + if (dinoc->di_forkoff != mp->m_attroffset >> 3) { + do_warn( + "bad attr fork offset %d in inode %llu, should be %d\n", + (int) dinoc->di_forkoff, + lino, + (int) (mp->m_attroffset >> 3)); + err = 1; + } + break; + default: + do_error("unexpected inode format %d\n", + (int) dinoc->di_format); + break; + } + } + + if (err) { + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + ASSERT(*dirty > 0); + } + + *cleared = 1; + *used = is_free; + *isa_dir = 0; + blkmap_free(dblkmap); + return(1); + } + + /* + * check data fork -- if it's bad, clear the inode + */ + nextents = 0; + switch (dinoc->di_format) { + case XFS_DINODE_FMT_LOCAL: + err = process_lclinode(mp, agno, ino, dino, type, + dirty, &totblocks, &nextents, &dblkmap, + XFS_DATA_FORK, check_dups); + break; + case XFS_DINODE_FMT_EXTENTS: + err = process_exinode(mp, agno, ino, dino, type, + dirty, &totblocks, &nextents, &dblkmap, + XFS_DATA_FORK, check_dups); + break; + case XFS_DINODE_FMT_BTREE: + err = process_btinode(mp, agno, ino, dino, type, + dirty, &totblocks, &nextents, &dblkmap, + XFS_DATA_FORK, check_dups); + break; + case XFS_DINODE_FMT_DEV: /* fall through */ + case XFS_DINODE_FMT_UUID: + err = 0; + break; + default: + do_error("unknown format %d, ino %llu (mode = %d)\n", + dinoc->di_format, lino, INT_GET(dinoc->di_mode, ARCH_CONVERT)); + } + + if (err) { + /* + * problem in the data fork, clear out the inode + * and get out + */ + do_warn("bad data fork in inode %llu\n", lino); + + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + ASSERT(*dirty > 0); + } + + *cleared = 1; + *used = is_free; + *isa_dir = 0; + blkmap_free(dblkmap); + + return(1); + } + + if (check_dups) { + /* + * if check_dups was non-zero, we have to + * re-process data fork to set bitmap since the + * bitmap wasn't set the first time through + */ + switch (dinoc->di_format) { + case XFS_DINODE_FMT_LOCAL: + err = process_lclinode(mp, agno, ino, dino, type, + dirty, &totblocks, &nextents, &dblkmap, + XFS_DATA_FORK, 0); + break; + case XFS_DINODE_FMT_EXTENTS: + err = process_exinode(mp, agno, ino, dino, type, + dirty, &totblocks, &nextents, &dblkmap, + XFS_DATA_FORK, 0); + break; + case XFS_DINODE_FMT_BTREE: + err = process_btinode(mp, agno, ino, dino, type, + dirty, &totblocks, &nextents, &dblkmap, + XFS_DATA_FORK, 0); + break; + case XFS_DINODE_FMT_DEV: /* fall through */ + case XFS_DINODE_FMT_UUID: + err = 0; + break; + default: + do_error("unknown format %d, ino %llu (mode = %d)\n", + dinoc->di_format, lino, INT_GET(dinoc->di_mode, ARCH_CONVERT)); + } + + if (no_modify && err != 0) { + *cleared = 1; + *used = is_free; + *isa_dir = 0; + blkmap_free(dblkmap); + + return(1); + } + + ASSERT(err == 0); + } + + /* + * check attribute fork if necessary. attributes are + * always stored in the regular filesystem. + */ + + if (!XFS_DFORK_Q_ARCH(dino, ARCH_CONVERT) && dinoc->di_aformat != XFS_DINODE_FMT_EXTENTS) { + do_warn("bad attribute format %d in inode %llu, ", + dinoc->di_aformat, lino); + if (!no_modify) { + do_warn("resetting value\n"); + dinoc->di_aformat = XFS_DINODE_FMT_EXTENTS; + *dirty = 1; + } else + do_warn("would reset value\n"); + anextents = 0; + } else if (XFS_DFORK_Q_ARCH(dino, ARCH_CONVERT)) { + switch (dinoc->di_aformat) { + case XFS_DINODE_FMT_LOCAL: + anextents = 0; + err = process_lclinode(mp, agno, ino, dino, + type, dirty, &atotblocks, &anextents, &ablkmap, + XFS_ATTR_FORK, check_dups); + break; + case XFS_DINODE_FMT_EXTENTS: + ablkmap = blkmap_alloc(anextents); + anextents = 0; + err = process_exinode(mp, agno, ino, dino, + type, dirty, &atotblocks, &anextents, &ablkmap, + XFS_ATTR_FORK, check_dups); + break; + case XFS_DINODE_FMT_BTREE: + ablkmap = blkmap_alloc(anextents); + anextents = 0; + err = process_btinode(mp, agno, ino, dino, + type, dirty, &atotblocks, &anextents, &ablkmap, + XFS_ATTR_FORK, check_dups); + break; + default: + anextents = 0; + do_warn("illegal attribute format %d, ino %llu\n", + dinoc->di_aformat, lino); + err = 1; + break; + } + + if (err) { + /* + * clear the attribute fork if necessary. we can't + * clear the inode because we've already put the + * inode space info into the blockmap. + * + * XXX - put the inode onto the "move it" list and + * log the the attribute scrubbing + */ + do_warn("bad attribute fork in inode %llu", lino); + + if (!no_modify) { + if (delete_attr_ok) { + do_warn(", clearing attr fork\n"); + *dirty += clear_dinode_attr(mp, + dino, lino); + } else { + do_warn("\n"); + *dirty += clear_dinode(mp, + dino, lino); + } + ASSERT(*dirty > 0); + } else { + do_warn(", would clear attr fork\n"); + } + + atotblocks = 0; + anextents = 0; + + if (delete_attr_ok) { + if (!no_modify) + dinoc->di_aformat = XFS_DINODE_FMT_LOCAL; + } else { + *cleared = 1; + *used = is_free; + *isa_dir = 0; + blkmap_free(dblkmap); + blkmap_free(ablkmap); + } + return(1); + + } else if (check_dups) { + switch (dinoc->di_aformat) { + case XFS_DINODE_FMT_LOCAL: + err = process_lclinode(mp, agno, ino, dino, + type, dirty, &atotblocks, &anextents, + &ablkmap, XFS_ATTR_FORK, 0); + break; + case XFS_DINODE_FMT_EXTENTS: + err = process_exinode(mp, agno, ino, dino, + type, dirty, &atotblocks, &anextents, + &ablkmap, XFS_ATTR_FORK, 0); + break; + case XFS_DINODE_FMT_BTREE: + err = process_btinode(mp, agno, ino, dino, + type, dirty, &atotblocks, &anextents, + &ablkmap, XFS_ATTR_FORK, 0); + break; + default: + do_error("illegal attribute fmt %d, ino %llu\n", + dinoc->di_aformat, lino); + } + + if (no_modify && err != 0) { + *cleared = 1; + *used = is_free; + *isa_dir = 0; + blkmap_free(dblkmap); + blkmap_free(ablkmap); + + return(1); + } + + ASSERT(err == 0); + } + + /* + * do attribute semantic-based consistency checks now + */ + + /* get this only in phase 3, not in both phase 3 and 4 */ + if (extra_attr_check) { + if ((err = process_attributes(mp, lino, dino, ablkmap, + &repair))) { + do_warn("problem with attribute contents in inode %llu\n",lino); + if(!repair) { + /* clear attributes if not done already */ + if (!no_modify) { + *dirty += clear_dinode_attr( + mp, dino, lino); + dinoc->di_aformat = + XFS_DINODE_FMT_LOCAL; + } else { + do_warn("would clear attr fork\n"); + } + atotblocks = 0; + anextents = 0; + } + else { + *dirty = 1; /* it's been repaired */ + } + } + } + blkmap_free(ablkmap); + + } else + anextents = 0; + + /* + * enforce totblocks is 0 for misc types + */ + if (process_misc_ino_types_blocks(totblocks, lino, type)) { + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + ASSERT(*dirty > 0); + } + *cleared = 1; + *used = is_free; + *isa_dir = 0; + blkmap_free(dblkmap); + + return(1); + } + + /* + * correct space counters if required + */ + if (totblocks + atotblocks != INT_GET(dinoc->di_nblocks, ARCH_CONVERT)) { + if (!no_modify) { + do_warn("correcting nblocks for inode %llu, was %llu - counted %llu\n", + lino, INT_GET(dinoc->di_nblocks, ARCH_CONVERT), + totblocks + atotblocks); + *dirty = 1; + INT_SET(dinoc->di_nblocks, ARCH_CONVERT, totblocks + atotblocks); + } else { + do_warn( + "bad nblocks %llu for inode %llu, would reset to %llu\n", + INT_GET(dinoc->di_nblocks, ARCH_CONVERT), lino, + totblocks + atotblocks); + } + } + + if (nextents > MAXEXTNUM) { + do_warn("too many data fork extents (%llu) in inode %llu\n", + nextents, lino); + + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + ASSERT(*dirty > 0); + } + *cleared = 1; + *used = is_free; + *isa_dir = 0; + blkmap_free(dblkmap); + + return(1); + } + if (nextents != INT_GET(dinoc->di_nextents, ARCH_CONVERT)) { + if (!no_modify) { + do_warn("correcting nextents for inode %llu, was %d - counted %llu\n", + lino, INT_GET(dinoc->di_nextents, ARCH_CONVERT), nextents); + *dirty = 1; + INT_SET(dinoc->di_nextents, ARCH_CONVERT, (xfs_extnum_t) nextents); + } else { + do_warn( + "bad nextents %d for inode %llu, would reset to %llu\n", + INT_GET(dinoc->di_nextents, ARCH_CONVERT), lino, nextents); + } + } + + if (anextents > MAXAEXTNUM) { + do_warn("too many attr fork extents (%llu) in inode %llu\n", + anextents, lino); + + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + ASSERT(*dirty > 0); + } + *cleared = 1; + *used = is_free; + *isa_dir = 0; + blkmap_free(dblkmap); + + return(1); + } + if (anextents != INT_GET(dinoc->di_anextents, ARCH_CONVERT)) { + if (!no_modify) { + do_warn("correcting anextents for inode %llu, was %d - counted %llu\n", + lino, INT_GET(dinoc->di_anextents, ARCH_CONVERT), anextents); + *dirty = 1; + INT_SET(dinoc->di_anextents, ARCH_CONVERT, (xfs_aextnum_t) anextents); + } else { + do_warn( + "bad anextents %d for inode %llu, would reset to %llu\n", + INT_GET(dinoc->di_anextents, ARCH_CONVERT), lino, anextents); + } + } + + /* + * do any semantic type-based checking here + */ + switch (type) { + case XR_INO_DIR: + if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) + err = process_dir2(mp, lino, dino, ino_discovery, + dirty, "", parent, dblkmap); + else + err = process_dir(mp, lino, dino, ino_discovery, + dirty, "", parent, dblkmap); + if (err) + do_warn( + "problem with directory contents in inode %llu\n", + lino); + break; + case XR_INO_RTBITMAP: + /* process_rtbitmap XXX */ + err = 0; + break; + case XR_INO_RTSUM: + /* process_rtsummary XXX */ + err = 0; + break; + case XR_INO_SYMLINK: + if ((err = process_symlink(mp, lino, dino, dblkmap))) + do_warn("problem with symbolic link in inode %llu\n", + lino); + break; + case XR_INO_DATA: /* fall through to FIFO case ... */ + case XR_INO_RTDATA: /* fall through to FIFO case ... */ + case XR_INO_CHRDEV: /* fall through to FIFO case ... */ + case XR_INO_BLKDEV: /* fall through to FIFO case ... */ + case XR_INO_SOCK: /* fall through to FIFO case ... */ + case XR_INO_FIFO: + err = 0; + break; + default: + printf("Unexpected inode type\n"); + abort(); + } + + blkmap_free(dblkmap); + + if (err) { + /* + * problem in the inode type-specific semantic + * checking, clear out the inode and get out + */ + if (!no_modify) { + *dirty += clear_dinode(mp, dino, lino); + ASSERT(*dirty > 0); + } + *cleared = 1; + *used = is_free; + *isa_dir = 0; + + return(1); + } + + /* + * check nlinks feature, if it's a version 1 inode, + * just leave nlinks alone. even if it's set wrong, + * it'll be reset when read in. + */ + if (dinoc->di_version > XFS_DINODE_VERSION_1 && !fs_inode_nlink) { + /* + * do we have a fs/inode version mismatch with a valid + * version 2 inode here that has to stay version 2 or + * lose links? + */ + if (INT_GET(dinoc->di_nlink, ARCH_CONVERT) > XFS_MAXLINK_1) { + /* + * yes. are nlink inodes allowed? + */ + if (fs_inode_nlink_allowed) { + /* + * yes, update status variable which will + * cause sb to be updated later. + */ + fs_inode_nlink = 1; + do_warn( + "version 2 inode %llu claims > %u links,", + lino, XFS_MAXLINK_1); + if (!no_modify) { + do_warn( + "updating superblock version number\n"); + } else { + do_warn( + "would update superblock version number\n"); + } + } else { + /* + * no, have to convert back to onlinks + * even if we lose some links + */ + do_warn( + "WARNING: version 2 inode %llu claims > %u links,", + lino, XFS_MAXLINK_1); + if (!no_modify) { + do_warn( + "converting back to version 1,\n\tthis may destroy %d links\n", + INT_GET(dinoc->di_nlink, ARCH_CONVERT) + - XFS_MAXLINK_1); + + dinoc->di_version = + XFS_DINODE_VERSION_1; + INT_SET(dinoc->di_nlink, ARCH_CONVERT, XFS_MAXLINK_1); + INT_SET(dinoc->di_onlink, ARCH_CONVERT, XFS_MAXLINK_1); + + *dirty = 1; + } else { + do_warn( + "would convert back to version 1,\n\tthis might destroy %d links\n", + INT_GET(dinoc->di_nlink, ARCH_CONVERT) + - XFS_MAXLINK_1); + } + } + } else { + /* + * do we have a v2 inode that we could convert back + * to v1 without losing any links? if we do and + * we have a mismatch between superblock bits and the + * version bit, alter the version bit in this case. + * + * the case where we lost links was handled above. + */ + do_warn("found version 2 inode %llu, ", lino); + if (!no_modify) { + do_warn("converting back to version 1\n"); + + dinoc->di_version = + XFS_DINODE_VERSION_1; + INT_SET(dinoc->di_onlink, ARCH_CONVERT, INT_GET(dinoc->di_nlink, ARCH_CONVERT)); + + *dirty = 1; + } else { + do_warn("would convert back to version 1\n"); + } + } + } + + /* + * ok, if it's still a version 2 inode, it's going + * to stay a version 2 inode. it should have a zero + * onlink field, so clear it. + */ + if (dinoc->di_version > XFS_DINODE_VERSION_1 && + INT_GET(dinoc->di_onlink, ARCH_CONVERT) > 0 && fs_inode_nlink > 0) { + if (!no_modify) { + do_warn( +"clearing obsolete nlink field in version 2 inode %llu, was %d, now 0\n", + lino, INT_GET(dinoc->di_onlink, ARCH_CONVERT)); + INT_ZERO(dinoc->di_onlink, ARCH_CONVERT); + *dirty = 1; + } else { + do_warn( +"would clear obsolete nlink field in version 2 inode %llu, currently %d\n", + lino, INT_GET(dinoc->di_onlink, ARCH_CONVERT)); + *dirty = 1; + } + } + + return(retval > 0 ? 1 : 0); +} + +/* + * returns 1 if inode is used, 0 if free. + * performs any necessary salvaging actions. + * note that we leave the generation count alone + * because nothing we could set it to would be + * guaranteed to be correct so the best guess for + * the correct value is just to leave it alone. + * + * The trick is detecting empty files. For those, + * the core and the forks should all be in the "empty" + * or zero-length state -- a zero or possibly minimum length + * (in the case of dirs) extent list -- although inline directories + * and symlinks might be handled differently. So it should be + * possible to sanity check them against each other. + * + * If the forks are an empty extent list though, then forget it. + * The file is toast anyway since we can't recover its storage. + * + * Parameters: + * Ins: + * mp -- mount structure + * dino -- pointer to on-disk inode structure + * agno/ino -- inode numbers + * free -- whether the map thinks the inode is free (1 == free) + * ino_discovery -- whether we should examine directory + * contents to discover new inodes + * check_dups -- whether we should check to see if the + * inode references duplicate blocks + * if so, we compare the inode's claimed + * blocks against the contents of the + * duplicate extent list but we don't + * set the bitmap. If not, we set the + * bitmap and try and detect multiply + * claimed blocks using the bitmap. + * Outs: + * dirty -- whether we changed the inode (1 == yes) + * cleared -- whether we cleared the inode (1 == yes). In + * no modify mode, if we would have cleared it + * used -- 1 if the inode is used, 0 if free. In no modify + * mode, whether the inode should be used or free + * isa_dir -- 1 if the inode is a directory, 0 if not. In + * no modify mode, if the inode would be a dir or not. + * + * Return value -- 0 if the inode is good, 1 if it is/was corrupt + */ + +int +process_dinode(xfs_mount_t *mp, + xfs_dinode_t *dino, + xfs_agnumber_t agno, + xfs_agino_t ino, + int was_free, + int *dirty, + int *cleared, + int *used, + int ino_discovery, + int check_dups, + int extra_attr_check, + int *isa_dir, + xfs_ino_t *parent) +{ + const int verify_mode = 0; + const int uncertain = 0; + +#ifdef XR_INODE_TRACE + fprintf(stderr, "processing inode %d/%d\n", agno, ino); +#endif + return(process_dinode_int(mp, dino, agno, ino, was_free, dirty, + cleared, used, verify_mode, uncertain, + ino_discovery, check_dups, extra_attr_check, + isa_dir, parent)); +} + +/* + * a more cursory check, check inode core, *DON'T* check forks + * this basically just verifies whether the inode is an inode + * and whether or not it has been totally trashed. returns 0 + * if the inode passes the cursory sanity check, 1 otherwise. + */ +int +verify_dinode(xfs_mount_t *mp, + xfs_dinode_t *dino, + xfs_agnumber_t agno, + xfs_agino_t ino) +{ + xfs_ino_t parent; + int cleared = 0; + int used = 0; + int dirty = 0; + int isa_dir = 0; + const int verify_mode = 1; + const int check_dups = 0; + const int ino_discovery = 0; + const int uncertain = 0; + + return(process_dinode_int(mp, dino, agno, ino, 0, &dirty, + &cleared, &used, verify_mode, + uncertain, ino_discovery, check_dups, + 0, &isa_dir, &parent)); +} + +/* + * like above only for inode on the uncertain list. it sets + * the uncertain flag which makes process_dinode_int quieter. + * returns 0 if the inode passes the cursory sanity check, 1 otherwise. + */ +int +verify_uncertain_dinode(xfs_mount_t *mp, + xfs_dinode_t *dino, + xfs_agnumber_t agno, + xfs_agino_t ino) +{ + xfs_ino_t parent; + int cleared = 0; + int used = 0; + int dirty = 0; + int isa_dir = 0; + const int verify_mode = 1; + const int check_dups = 0; + const int ino_discovery = 0; + const int uncertain = 1; + + return(process_dinode_int(mp, dino, agno, ino, 0, &dirty, + &cleared, &used, verify_mode, + uncertain, ino_discovery, check_dups, + 0, &isa_dir, &parent)); +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/dinode.h linux-2.4-xfs/cmd/xfsprogs/repair/dinode.h --- linux-2.4.7/cmd/xfsprogs/repair/dinode.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/dinode.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef _XR_DINODE_H +#define _XR_DINODE_H + +struct blkmap; + +int +verify_agbno(xfs_mount_t *mp, + xfs_agnumber_t agno, + xfs_agblock_t agbno); + +int +verify_dfsbno(xfs_mount_t *mp, + xfs_dfsbno_t fsbno); + +void +convert_extent( + xfs_bmbt_rec_32_t *rp, + xfs_dfiloff_t *op, /* starting offset (blockno in file) */ + xfs_dfsbno_t *sp, /* starting block (fs blockno) */ + xfs_dfilblks_t *cp, /* blockcount */ + int *fp); /* extent flag */ + +int +process_bmbt_reclist(xfs_mount_t *mp, + xfs_bmbt_rec_32_t *rp, + int numrecs, + int type, + xfs_ino_t ino, + xfs_drfsbno_t *tot, + struct blkmap **blkmapp, + __uint64_t *first_key, + __uint64_t *last_key, + int whichfork); + +int +scan_bmbt_reclist( + xfs_mount_t *mp, + xfs_bmbt_rec_32_t *rp, + int numrecs, + int type, + xfs_ino_t ino, + xfs_drfsbno_t *tot, + int whichfork); + +int +verify_inode_chunk(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_ino_t *start_ino); + +int verify_aginode_chunk(xfs_mount_t *mp, + xfs_agnumber_t agno, + xfs_agino_t agino, + xfs_agino_t *agino_start); + +int +clear_dinode(xfs_mount_t *mp, xfs_dinode_t *dino, xfs_ino_t ino_num); + +void +update_rootino(xfs_mount_t *mp); + +int +process_dinode(xfs_mount_t *mp, + xfs_dinode_t *dino, + xfs_agnumber_t agno, + xfs_agino_t ino, + int was_free, + int *dirty, + int *tossit, + int *used, + int check_dirs, + int check_dups, + int extra_attr_check, + int *isa_dir, + xfs_ino_t *parent); + +int +verify_dinode(xfs_mount_t *mp, + xfs_dinode_t *dino, + xfs_agnumber_t agno, + xfs_agino_t ino); + +int +verify_uncertain_dinode(xfs_mount_t *mp, + xfs_dinode_t *dino, + xfs_agnumber_t agno, + xfs_agino_t ino); + +int +verify_inum(xfs_mount_t *mp, + xfs_ino_t ino); + +int +verify_aginum(xfs_mount_t *mp, + xfs_agnumber_t agno, + xfs_agino_t agino); + +int +process_uncertain_aginodes(xfs_mount_t *mp, + xfs_agnumber_t agno); +void +process_aginodes(xfs_mount_t *mp, + xfs_agnumber_t agno, + int check_dirs, + int check_dups, + int extra_attr_check); + +void +check_uncertain_aginodes(xfs_mount_t *mp, + xfs_agnumber_t agno); + +xfs_buf_t * +get_agino_buf(xfs_mount_t *mp, + xfs_agnumber_t agno, + xfs_agino_t agino, + xfs_dinode_t **dipp); + +xfs_dfsbno_t +get_bmapi(xfs_mount_t *mp, + xfs_dinode_t *dip, + xfs_ino_t ino_num, + xfs_dfiloff_t bno, + int whichfork ); + +#endif /* _XR_DINODE_H */ diff -rNu linux-2.4.7/cmd/xfsprogs/repair/dir.c linux-2.4-xfs/cmd/xfsprogs/repair/dir.c --- linux-2.4.7/cmd/xfsprogs/repair/dir.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/dir.c Thu Apr 12 18:49:04 2001 @@ -0,0 +1,3033 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "avl.h" +#include "globals.h" +#include "agheader.h" +#include "incore.h" +#include "protos.h" +#include "err_protos.h" +#include "dinode.h" +#include "dir.h" +#include "bmap.h" + +#if XFS_DIR_LEAF_MAPSIZE >= XFS_ATTR_LEAF_MAPSIZE +#define XR_DA_LEAF_MAPSIZE XFS_DIR_LEAF_MAPSIZE +#else +#define XR_DA_LEAF_MAPSIZE XFS_ATTR_LEAF_MAPSIZE +#endif + + + +typedef struct da_hole_map { + int lost_holes; + int num_holes; + struct { + int base; + int size; + } hentries[XR_DA_LEAF_MAPSIZE]; +} da_hole_map_t; + +/* + * takes a name and length (name need not be null-terminated) + * and returns 1 if the name contains a '/' or a \0, returns 0 + * otherwise + */ +int +namecheck(char *name, int length) +{ + char *c; + int i; + + ASSERT(length < MAXNAMELEN); + + for (c = name, i = 0; i < length; i++, c++) { + if (*c == '/' || *c == '\0') + return(1); + } + + return(0); +} + +/* + * this routine performs inode discovery and tries to fix things + * in place. available redundancy -- inode data size should match + * used directory space in inode. returns number of valid directory + * entries. a non-zero return value means the directory is bogus + * and should be blasted. + */ +/* ARGSUSED */ +int +process_shortform_dir( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + int ino_discovery, + int *dino_dirty, /* out - 1 if dinode buffer dirty? */ + xfs_ino_t *parent, /* out - NULLFSINO if entry doesn't exist */ + char *dirname, /* directory pathname */ + int *repair) /* out - 1 if dir was fixed up */ +{ + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe; + xfs_ino_t lino; + int max_size; + __int64_t ino_dir_size; + int num_entries; + int ino_off; + int namelen; + int i; + int junkit; + int tmp_len; + int tmp_elen; + int bad_sfnamelen; + ino_tree_node_t *irec_p; + char name[MAXNAMELEN + 1]; + +#ifdef XR_DIR_TRACE + fprintf(stderr, "process_shortform_dir - inode %llu\n", ino); +#endif + + sf = &dip->di_u.di_dirsf; + + max_size = XFS_DFORK_DSIZE_ARCH(dip, mp, ARCH_CONVERT); + num_entries = INT_GET(sf->hdr.count, ARCH_CONVERT); + ino_dir_size = INT_GET(dip->di_core.di_size, ARCH_CONVERT); + *repair = 0; + + ASSERT(ino_dir_size <= max_size); + + /* + * check for bad entry count + */ + if (num_entries * sizeof(xfs_dir_sf_entry_t) + sizeof(xfs_dir_sf_hdr_t) + > max_size || num_entries == 0) + num_entries = 0xFF; + + /* + * run through entries, stop at first bad entry, don't need + * to check for .. since that's encoded in its own field + */ + sf_entry = next_sfe = &sf->list[0]; + for (i = 0; i < num_entries && ino_dir_size > + (__psint_t)next_sfe - (__psint_t)sf; i++) { + tmp_sfe = NULL; + sf_entry = next_sfe; + junkit = 0; + bad_sfnamelen = 0; + XFS_DIR_SF_GET_DIRINO_ARCH(&sf_entry->inumber, &lino, ARCH_CONVERT); + + /* + * if entry points to self, junk it since only '.' or '..' + * should do that and shortform dirs don't contain either + * entry. if inode number is invalid, trash entry. + * if entry points to special inodes, trash it. + * if inode is unknown but number is valid, + * add it to the list of uncertain inodes. don't + * have to worry about an entry pointing to a + * deleted lost+found inode because the entry was + * deleted at the same time that the inode was cleared. + */ + if (lino == ino) { + junkit = 1; + } else if (verify_inum(mp, lino)) { + /* + * junk the entry, mark lino as NULL since it's bad + */ + do_warn("invalid inode number %llu in directory %llu\n", + lino, ino); + lino = NULLFSINO; + junkit = 1; + } else if (lino == mp->m_sb.sb_rbmino) { + do_warn( + "entry in shorform dir %llu references realtime bitmap inode %llu\n", + ino, lino); + junkit = 1; + } else if (lino == mp->m_sb.sb_rsumino) { + do_warn( + "entry in shorform dir %llu references realtime summary inode %llu\n", + ino, lino); + junkit = 1; + } else if (lino == mp->m_sb.sb_uquotino) { + do_warn( + "entry in shorform dir %llu references user quota inode %llu\n", + ino, lino); + junkit = 1; + } else if (lino == mp->m_sb.sb_gquotino) { + do_warn( + "entry in shorform dir %llu references group quota inode %llu\n", + ino, lino); + junkit = 1; + } else if ((irec_p = find_inode_rec(XFS_INO_TO_AGNO(mp, lino), + XFS_INO_TO_AGINO(mp, lino))) != NULL) { + /* + * if inode is marked free and we're in inode + * discovery mode, leave the entry alone for now. + * if the inode turns out to be used, we'll figure + * that out when we scan it. If the inode really + * is free, we'll hit this code again in phase 4 + * after we've finished inode discovery and blow + * out the entry then. + */ + ino_off = XFS_INO_TO_AGINO(mp, lino) - + irec_p->ino_startnum; + ASSERT(is_inode_confirmed(irec_p, ino_off)); + + if (!ino_discovery && is_inode_free(irec_p, ino_off)) { + do_warn( + "entry references free inode %llu in shortform directory %llu\n", + lino, ino); + junkit = 1; + } + } else if (ino_discovery) { + /* + * put the inode on the uncertain list. we'll + * pull the inode off the list and check it later. + * if the inode turns out be bogus, we'll delete + * this entry in phase 6. + */ + add_inode_uncertain(mp, lino, 0); + } else { + /* + * blow the entry out. we know about all + * undiscovered entries now (past inode discovery + * phase) so this is clearly a bogus entry. + */ + do_warn( + "entry references non-existent inode %llu in shortform dir %llu\n", + lino, ino); + junkit = 1; + } + + namelen = sf_entry->namelen; + + if (namelen == 0) { + /* + * if we're really lucky, this is + * the last entry in which case we + * can use the dir size to set the + * namelen value. otherwise, forget + * it because we're not going to be + * able to find the next entry. + */ + bad_sfnamelen = 1; + + if (i == num_entries - 1) { + namelen = ino_dir_size - + ((__psint_t) &sf_entry->name[0] - + (__psint_t) sf); + if (!no_modify) { + do_warn( + "zero length entry in shortform dir %llu, resetting to %d\n", + ino, namelen); + sf_entry->namelen = namelen; + } else { + do_warn( + "zero length entry in shortform dir %llu, would set to %d\n", + ino, namelen); + } + } else { + do_warn( + "zero length entry in shortform dir %llu", + ino); + if (!no_modify) + do_warn(", junking %d entries\n", + num_entries - i); + else + do_warn(", would junk %d entries\n", + num_entries - i); + /* + * don't process the rest of the directory, + * break out of processing looop + */ + break; + } + } else if ((__psint_t) sf_entry - (__psint_t) sf + + + XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry) + > ino_dir_size) { + bad_sfnamelen = 1; + + if (i == num_entries - 1) { + namelen = ino_dir_size - + ((__psint_t) &sf_entry->name[0] - + (__psint_t) sf); + do_warn( + "size of last entry overflows space left in in shortform dir %llu, ", + ino); + if (!no_modify) { + do_warn("resetting to %d\n", + namelen); + sf_entry->namelen = namelen; + *dino_dirty = 1; + } else { + do_warn("would reset to %d\n", + namelen); + } + } else { + do_warn( + "size of entry #%d overflows space left in in shortform dir %llu\n", + i, ino); + if (!no_modify) { + if (i == num_entries - 1) + do_warn("junking entry #%d\n", + i); + else + do_warn( + "junking %d entries\n", + num_entries - i); + } else { + if (i == num_entries - 1) + do_warn( + "would junk entry #%d\n", + i); + else + do_warn( + "would junk %d entries\n", + num_entries - i); + } + + break; + } + } + + /* + * check for illegal chars in name. + * no need to check for bad length because + * the length value is stored in a byte + * so it can't be too big, it can only wrap + */ + if (namecheck((char *)&sf_entry->name[0], namelen)) { + /* + * junk entry + */ + do_warn( + "entry contains illegal character in shortform dir %llu\n", + ino); + junkit = 1; + } + + /* + * junk the entry by copying up the rest of the + * fork over the current entry and decrementing + * the entry count. if we're in no_modify mode, + * just issue the warning instead. then continue + * the loop with the next_sfe pointer set to the + * correct place in the fork and other counters + * properly set to reflect the deletion if it + * happened. + */ + if (junkit) { + bcopy(sf_entry->name, name, namelen); + name[namelen] = '\0'; + + if (!no_modify) { + tmp_elen = XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry); + INT_MOD(dip->di_core.di_size, ARCH_CONVERT, -(tmp_elen)); + ino_dir_size -= tmp_elen; + + tmp_sfe = (xfs_dir_sf_entry_t *) + ((__psint_t) sf_entry + tmp_elen); + tmp_len = max_size - ((__psint_t) tmp_sfe + - (__psint_t) sf); + + memmove(sf_entry, tmp_sfe, tmp_len); + + INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); + num_entries--; + bzero((void *) ((__psint_t) sf_entry + tmp_len), + tmp_elen); + + /* + * reset the tmp value to the current + * pointer so we'll process the entry + * we just moved up + */ + tmp_sfe = sf_entry; + + /* + * WARNING: drop the index i by one + * so it matches the decremented count + * for accurate comparisons later + */ + i--; + + *dino_dirty = 1; + *repair = 1; + + do_warn( + "junking entry \"%s\" in directory inode %llu\n", + name, ino); + } else { + do_warn( + "would have junked entry \"%s\" in directory inode %llu\n", + name, ino); + } + } + + /* + * go onto next entry unless we've just junked an + * entry in which the current entry pointer points + * to an unprocessed entry. have to take into zero-len + * entries into account in no modify mode since we + * calculate size based on next_sfe. + */ + next_sfe = (tmp_sfe == NULL) + ? (xfs_dir_sf_entry_t *) ((__psint_t) sf_entry + + ((!bad_sfnamelen) + ? XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry) + : sizeof(xfs_dir_sf_entry_t) - 1 + + namelen)) + : tmp_sfe; + } + + /* sync up sizes and entry counts */ + + if (INT_GET(sf->hdr.count, ARCH_CONVERT) != i) { + if (no_modify) { +do_warn("would have corrected entry count in directory %llu from %d to %d\n", + ino, INT_GET(sf->hdr.count, ARCH_CONVERT), i); + } else { +do_warn("corrected entry count in directory %llu, was %d, now %d\n", + ino, INT_GET(sf->hdr.count, ARCH_CONVERT), i); + INT_SET(sf->hdr.count, ARCH_CONVERT, i); + *dino_dirty = 1; + *repair = 1; + } + } + + if ((__psint_t) next_sfe - (__psint_t) sf != ino_dir_size) { + if (no_modify) { + do_warn( + "would have corrected directory %llu size from %lld to %lld\n", + ino, (__int64_t) ino_dir_size, + (__int64_t)((__psint_t) next_sfe - (__psint_t) sf)); + } else { + do_warn( + "corrected directory %llu size, was %lld, now %lld\n", + ino, (__int64_t) ino_dir_size, + (__int64_t)((__psint_t) next_sfe - (__psint_t) sf)); + + INT_SET(dip->di_core.di_size, ARCH_CONVERT, (xfs_fsize_t) + ((__psint_t) next_sfe - (__psint_t) sf)); + *dino_dirty = 1; + *repair = 1; + } + } + /* + * check parent (..) entry + */ + XFS_DIR_SF_GET_DIRINO_ARCH(&sf->hdr.parent, parent, ARCH_CONVERT); + + /* + * if parent entry is bogus, null it out. we'll fix it later . + */ + if (verify_inum(mp, *parent)) { + *parent = NULLFSINO; + + do_warn( + "bogus .. inode number (%llu) in directory inode %llu,", + *parent, ino); + if (!no_modify) { + do_warn("clearing inode number\n"); + + XFS_DIR_SF_PUT_DIRINO_ARCH(parent, &sf->hdr.parent, ARCH_CONVERT); + *dino_dirty = 1; + *repair = 1; + } else { + do_warn("would clear inode number\n"); + } + } else if (ino == mp->m_sb.sb_rootino && ino != *parent) { + /* + * root directories must have .. == . + */ + if (!no_modify) { + do_warn( + "corrected root directory %llu .. entry, was %llu, now %llu\n", + ino, *parent, ino); + *parent = ino; + XFS_DIR_SF_PUT_DIRINO_ARCH(parent, &sf->hdr.parent, ARCH_CONVERT); + *dino_dirty = 1; + *repair = 1; + } else { + do_warn( + "would have corrected root directory %llu .. entry from %llu to %llu\n", + ino, *parent, ino); + } + } else if (ino == *parent && ino != mp->m_sb.sb_rootino) { + /* + * likewise, non-root directories can't have .. pointing + * to . + */ + *parent = NULLFSINO; + do_warn("bad .. entry in dir ino %llu, points to self,", + ino); + if (!no_modify) { + do_warn(" clearing inode number\n"); + + XFS_DIR_SF_PUT_DIRINO_ARCH(parent, &sf->hdr.parent, ARCH_CONVERT); + *dino_dirty = 1; + *repair = 1; + } else { + do_warn(" would clear inode number\n"); + } + } + + return(0); +} + +/* + * freespace map for directory leaf blocks (1 bit per byte) + * 1 == used, 0 == free + */ +static da_freemap_t dir_freemap[DA_BMAP_SIZE]; + +#if 0 +unsigned char * +alloc_da_freemap(xfs_mount_t *mp) +{ + unsigned char *freemap; + + if ((freemap = malloc(mp->m_sb.sb_blocksize)) == NULL) + return(NULL); + + bzero(freemap, mp->m_sb.sb_blocksize/NBBY); + + return(freemap); +} +#endif + +void +init_da_freemap(da_freemap_t *dir_freemap) +{ + bzero(dir_freemap, sizeof(da_freemap_t) * DA_BMAP_SIZE); +} + +/* + * sets directory freemap, returns 1 if there is a conflict + * returns 0 if everything's good. the range [start, stop) is set. + * right now, we just use the static array since only one directory + * block will be processed at once even though the interface allows + * you to pass in arbitrary da_freemap_t array's. + * + * Within a char, the lowest bit of the char represents the byte with + * the smallest address + */ +int +set_da_freemap(xfs_mount_t *mp, da_freemap_t *map, int start, int stop) +{ + const da_freemap_t mask = 0x1; + int i; + + if (start > stop) { + /* + * allow == relation since [x, x) claims 1 byte + */ + do_warn("bad range claimed [%d, %d) in da block\n", + start, stop); + return(1); + } + + if (stop > mp->m_sb.sb_blocksize) { + do_warn( + "byte range end [%d %d) in da block larger than blocksize %d\n", + start, stop, mp->m_sb.sb_blocksize); + return(1); + } + + for (i = start; i < stop; i ++) { + if (map[i / NBBY] & (mask << i % NBBY)) { + do_warn("multiply claimed byte %d in da block\n", i); + return(1); + } + map[i / NBBY] |= (mask << i % NBBY); + } + + return(0); +} + +/* + * returns 0 if holemap is consistent with reality (as expressed by + * the da_freemap_t). returns 1 if there's a conflict. + */ +int +verify_da_freemap(xfs_mount_t *mp, da_freemap_t *map, da_hole_map_t *holes, + xfs_ino_t ino, xfs_dablk_t da_bno) +{ + int i, j, start, len; + const da_freemap_t mask = 0x1; + + for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; i++) { + if (holes->hentries[i].size == 0) + continue; + + start = holes->hentries[i].base; + len = holes->hentries[i].size; + + if (start >= mp->m_sb.sb_blocksize || + start + len > mp->m_sb.sb_blocksize) { + do_warn( + "hole (start %d, len %d) out of range, block %d, dir ino %llu\n", + start, len, da_bno, ino); + return(1); + } + + for (j = start; j < start + len; j++) { + if ((map[j / NBBY] & (mask << (j % NBBY))) != 0) { + /* + * bad news -- hole claims a used byte is free + */ + do_warn( + "hole claims used byte %d, block %d, dir ino %llu\n", + j, da_bno, ino); + return(1); + } + } + } + + return(0); +} + +void +process_da_freemap(xfs_mount_t *mp, da_freemap_t *map, da_hole_map_t *holes) +{ + int i, j, in_hole, start, length, smallest, num_holes; + const da_freemap_t mask = 0x1; + + num_holes = in_hole = start = length = 0; + + for (i = 0; i < mp->m_sb.sb_blocksize; i++) { + if ((map[i / NBBY] & (mask << (i % NBBY))) == 0) { + /* + * byte is free (unused) + */ + if (in_hole == 1) + continue; + /* + * start of a new hole + */ + in_hole = 1; + start = i; + } else { + /* + * byte is used + */ + if (in_hole == 0) + continue; + /* + * end of a hole + */ + in_hole = 0; + /* + * if the hole disappears, throw it away + */ + length = i - start; + + if (length <= 0) + continue; + + num_holes++; + + for (smallest = j = 0; j < XR_DA_LEAF_MAPSIZE; j++) { + if (holes->hentries[j].size < + holes->hentries[smallest].size) + smallest = j; + + } + if (length > holes->hentries[smallest].size) { + holes->hentries[smallest].base = start; + holes->hentries[smallest].size = length; + } + } + } + + /* + * see if we have a big hole at the end + */ + if (in_hole == 1) { + /* + * duplicate of hole placement code above + */ + length = i - start; + + if (length > 0) { + num_holes++; + + for (smallest = j = 0; j < XR_DA_LEAF_MAPSIZE; j++) { + if (holes->hentries[j].size < + holes->hentries[smallest].size) + smallest = j; + + } + if (length > holes->hentries[smallest].size) { + holes->hentries[smallest].base = start; + holes->hentries[smallest].size = length; + } + } + } + + holes->lost_holes = MAX(num_holes - XR_DA_LEAF_MAPSIZE, 0); + holes->num_holes = num_holes; + + return; +} + +/* + * returns 1 if the hole info doesn't match, 0 if it does + */ +/* ARGSUSED */ +int +compare_da_freemaps(xfs_mount_t *mp, da_hole_map_t *holemap, + da_hole_map_t *block_hmap, int entries, + xfs_ino_t ino, xfs_dablk_t da_bno) +{ + int i, k, res, found; + + res = 0; + + /* + * we chop holemap->lost_holes down to being two-valued + * value (1 or 0) for the test because the filesystem + * value is two-valued + */ + if ((holemap->lost_holes > 0 ? 1 : 0) != block_hmap->lost_holes) { + if (verbose) { + do_warn( + "- derived hole value %d, saw %d, block %d, dir ino %llu\n", + holemap->lost_holes, block_hmap->lost_holes, + da_bno, ino); + res = 1; + } else + return(1); + } + + for (i = 0; i < entries; i++) { + for (found = k = 0; k < entries; k++) { + if (holemap->hentries[i].base == + block_hmap->hentries[k].base + && holemap->hentries[i].size == + block_hmap->hentries[k].size) + found = 1; + } + if (!found) { + if (verbose) { + do_warn( +"- derived hole (base %d, size %d) in block %d, dir inode %llu not found\n", + holemap->hentries[i].base, + holemap->hentries[i].size, + da_bno, ino); + res = 1; + } else + return(1); + } + } + + return(res); +} + +#if 0 +void +test(xfs_mount_t *mp) +{ + int i = 0; + da_hole_map_t holemap; + + init_da_freemap(dir_freemap); + bzero(&holemap, sizeof(da_hole_map_t)); + + set_da_freemap(mp, dir_freemap, 0, 50); + set_da_freemap(mp, dir_freemap, 100, 126); + set_da_freemap(mp, dir_freemap, 126, 129); + set_da_freemap(mp, dir_freemap, 130, 131); + set_da_freemap(mp, dir_freemap, 150, 160); + process_da_freemap(mp, dir_freemap, &holemap); + + return; +} +#endif + + +/* + * walk tree from root to the left-most leaf block reading in + * blocks and setting up cursor. passes back file block number of the + * left-most leaf block if successful (bno). returns 1 if successful, + * 0 if unsuccessful. + */ +int +traverse_int_dablock(xfs_mount_t *mp, + da_bt_cursor_t *da_cursor, + xfs_dablk_t *rbno, + int whichfork) +{ + xfs_dablk_t bno; + int i; + xfs_da_intnode_t *node; + xfs_dfsbno_t fsbno; + xfs_buf_t *bp; + + /* + * traverse down left-side of tree until we hit the + * left-most leaf block setting up the btree cursor along + * the way. + */ + bno = 0; + i = -1; + node = NULL; + da_cursor->active = 0; + + do { + /* + * read in each block along the way and set up cursor + */ + fsbno = blkmap_get(da_cursor->blkmap, bno); + + if (fsbno == NULLDFSBNO) + goto error_out; + + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + if (whichfork == XFS_DATA_FORK) + do_warn("can't read block %u (fsbno %llu) for " + "directory inode %llu\n", + bno, fsbno, da_cursor->ino); + else + do_warn("can't read block %u (fsbno %llu) for " + "attrbute fork of inode %llu\n", + bno, fsbno, da_cursor->ino); + goto error_out; + } + + node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp); + + if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) { + do_warn("bad dir/attr magic number in inode %llu, file " + "bno = %u, fsbno = %llu\n", da_cursor->ino, bno, fsbno); + libxfs_putbuf(bp); + goto error_out; + } + if (INT_GET(node->hdr.count, ARCH_CONVERT) > XFS_DA_NODE_ENTRIES(mp)) { + do_warn("bad record count in inode %llu, count = %d, max = %d\n", + da_cursor->ino, INT_GET(node->hdr.count, ARCH_CONVERT), + XFS_DA_NODE_ENTRIES(mp)); + libxfs_putbuf(bp); + goto error_out; + } + + /* + * maintain level counter + */ + if (i == -1) + i = da_cursor->active = INT_GET(node->hdr.level, ARCH_CONVERT); + else { + if (INT_GET(node->hdr.level, ARCH_CONVERT) == i - 1) { + i--; + } else { + if (whichfork == XFS_DATA_FORK) + do_warn("bad directory btree for directory " + "inode %llu\n", da_cursor->ino); + else + do_warn("bad attribute fork btree for " + "inode %llu\n", da_cursor->ino); + libxfs_putbuf(bp); + goto error_out; + } + } + + da_cursor->level[i].hashval = + INT_GET(node->btree[0].hashval, ARCH_CONVERT); + da_cursor->level[i].bp = bp; + da_cursor->level[i].bno = bno; + da_cursor->level[i].index = 0; +#ifdef XR_DIR_TRACE + da_cursor->level[i].n = XFS_BUF_TO_DA_INTNODE(bp); +#endif + + /* + * set up new bno for next level down + */ + bno = INT_GET(node->btree[0].before, ARCH_CONVERT); + } while(node != NULL && i > 1); + + /* + * now return block number and get out + */ + *rbno = da_cursor->level[0].bno = bno; + return(1); + +error_out: + while (i > 1 && i <= da_cursor->active) { + libxfs_putbuf(da_cursor->level[i].bp); + i++; + } + + return(0); +} + +/* + * blow out buffer for this level and all the rest above as well + * if error == 0, we are not expecting to encounter any unreleased + * buffers (e.g. if we do, it's a mistake). if error == 1, we're + * in an error-handling case so unreleased buffers may exist. + */ +void +release_da_cursor_int(xfs_mount_t *mp, + da_bt_cursor_t *cursor, + int prev_level, + int error) +{ + int level = prev_level + 1; + + if (cursor->level[level].bp != NULL) { + if (!error) { + do_warn("release_da_cursor_int got unexpected non-null bp, " + "dabno = %u\n", cursor->level[level].bno); + } + ASSERT(error != 0); + + libxfs_putbuf(cursor->level[level].bp); + cursor->level[level].bp = NULL; + } + + if (level < cursor->active) + release_da_cursor_int(mp, cursor, level, error); + + return; +} + +void +release_da_cursor(xfs_mount_t *mp, + da_bt_cursor_t *cursor, + int prev_level) +{ + release_da_cursor_int(mp, cursor, prev_level, 0); +} + +void +err_release_da_cursor(xfs_mount_t *mp, + da_bt_cursor_t *cursor, + int prev_level) +{ + release_da_cursor_int(mp, cursor, prev_level, 1); +} + +/* + * like traverse_int_dablock only it does far less checking + * and doesn't maintain the cursor. Just gets you to the + * leftmost block in the directory. returns the fsbno + * of that block if successful, NULLDFSBNO if not. + */ +xfs_dfsbno_t +get_first_dblock_fsbno(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dino) +{ + xfs_dablk_t bno; + int i; + xfs_da_intnode_t *node; + xfs_dfsbno_t fsbno; + xfs_buf_t *bp; + + /* + * traverse down left-side of tree until we hit the + * left-most leaf block setting up the btree cursor along + * the way. + */ + bno = 0; + i = -1; + node = NULL; + + fsbno = get_bmapi(mp, dino, ino, bno, XFS_DATA_FORK); + + if (fsbno == NULLDFSBNO) { + do_warn("bmap of block #%u of inode %llu failed\n", + bno, ino); + return(fsbno); + } + + if (INT_GET(dino->di_core.di_size, ARCH_CONVERT) <= XFS_LBSIZE(mp)) + return(fsbno); + + do { + /* + * walk down left side of btree, release buffers as you + * go. if the root block is a leaf (single-level btree), + * just return it. + * + */ + + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + do_warn("can't read block %u (fsbno %llu) for directory " + "inode %llu\n", bno, fsbno, ino); + return(NULLDFSBNO); + } + + node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp); + + if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) { + do_warn("bad dir/attr magic number in inode %llu, file " + "bno = %u, fsbno = %llu\n", ino, bno, fsbno); + libxfs_putbuf(bp); + return(NULLDFSBNO); + } + + if (i == -1) + i = INT_GET(node->hdr.level, ARCH_CONVERT); + bno = INT_GET(node->btree[0].before, ARCH_CONVERT); + + libxfs_putbuf(bp); + + fsbno = get_bmapi(mp, dino, ino, bno, XFS_DATA_FORK); + + if (fsbno == NULLDFSBNO) { + do_warn("bmap of block #%u of inode %llu failed\n", bno, ino); + return(NULLDFSBNO); + } + + i--; + } while(i > 0); + + return(fsbno); +} + +/* + * make sure that all entries in all blocks along the right side of + * of the tree are used and hashval's are consistent. level is the + * level of the descendent block. returns 0 if good (even if it had + * to be fixed up), and 1 if bad. The right edge of the tree is + * technically a block boundary. this routine should be used then + * instead of verify_da_path(). + */ +int +verify_final_da_path(xfs_mount_t *mp, + da_bt_cursor_t *cursor, + const int p_level) +{ + xfs_da_intnode_t *node; + int bad = 0; + int entry; + int this_level = p_level + 1; + +#ifdef XR_DIR_TRACE + fprintf(stderr, "in verify_final_da_path, this_level = %d\n", + this_level); +#endif + /* + * the index should point to the next "unprocessed" entry + * in the block which should be the final (rightmost) entry + */ + entry = cursor->level[this_level].index; + node = (xfs_da_intnode_t *)XFS_BUF_PTR(cursor->level[this_level].bp); + /* + * check internal block consistency on this level -- ensure + * that all entries are used, encountered and expected hashvals + * match, etc. + */ + if (entry != INT_GET(node->hdr.count, ARCH_CONVERT) - 1) { + do_warn("directory/attribute block used/count inconsistency - %d/%hu\n", + entry, INT_GET(node->hdr.count, ARCH_CONVERT)); + bad++; + } + /* + * hash values monotonically increasing ??? + */ + if (cursor->level[this_level].hashval >= + INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) { + do_warn("directory/attribute block hashvalue inconsistency, " + "expected > %u / saw %u\n", cursor->level[this_level].hashval, + INT_GET(node->btree[entry].hashval, ARCH_CONVERT)); + bad++; + } + if (INT_GET(node->hdr.info.forw, ARCH_CONVERT) != 0) { + do_warn("bad directory/attribute forward block pointer, expected 0, " + "saw %u\n", INT_GET(node->hdr.info.forw, ARCH_CONVERT)); + bad++; + } + if (bad) { + do_warn("bad directory block in dir ino %llu\n", cursor->ino); + return(1); + } + /* + * keep track of greatest block # -- that gets + * us the length of the directory + */ + if (cursor->level[this_level].bno > cursor->greatest_bno) + cursor->greatest_bno = cursor->level[this_level].bno; + + /* + * ok, now check descendant block number against this level + */ + if (cursor->level[p_level].bno != + INT_GET(node->btree[entry].before, ARCH_CONVERT)) { +#ifdef XR_DIR_TRACE + fprintf(stderr, "bad directory btree pointer, child bno should be %d, " + "block bno is %d, hashval is %u\n", + INT_GET(node->btree[entry].before, ARCH_CONVERT), + cursor->level[p_level].bno, + cursor->level[p_level].hashval); + fprintf(stderr, "verify_final_da_path returns 1 (bad) #1a\n"); +#endif + return(1); + } + + if (cursor->level[p_level].hashval != + INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) { + if (!no_modify) { + do_warn("correcting bad hashval in non-leaf dir/attr block\n"); + do_warn("\tin (level %d) in inode %llu.\n", + this_level, cursor->ino); + INT_SET(node->btree[entry].hashval, ARCH_CONVERT, + cursor->level[p_level].hashval); + cursor->level[this_level].dirty++; + } else { + do_warn("would correct bad hashval in non-leaf dir/attr " + "block\n\tin (level %d) in inode %llu.\n", + this_level, cursor->ino); + } + } + + /* + * release/write buffer + */ + ASSERT(cursor->level[this_level].dirty == 0 || + (cursor->level[this_level].dirty && !no_modify)); + + if (cursor->level[this_level].dirty && !no_modify) + libxfs_writebuf(cursor->level[this_level].bp, 0); + else + libxfs_putbuf(cursor->level[this_level].bp); + + cursor->level[this_level].bp = NULL; + + /* + * bail out if this is the root block (top of tree) + */ + if (this_level >= cursor->active) { +#ifdef XR_DIR_TRACE + fprintf(stderr, "verify_final_da_path returns 0 (ok)\n"); +#endif + return(0); + } + /* + * set hashvalue to correctl reflect the now-validated + * last entry in this block and continue upwards validation + */ + cursor->level[this_level].hashval = + INT_GET(node->btree[entry].hashval, ARCH_CONVERT); + return(verify_final_da_path(mp, cursor, this_level)); +} + +/* + * Verifies the path from a descendant block up to the root. + * Should be called when the descendant level traversal hits + * a block boundary before crossing the boundary (reading in a new + * block). + * + * the directory/attr btrees work differently to the other fs btrees. + * each interior block contains records that are + * pairs. The bno is a file bno, not a filesystem bno. The last + * hashvalue in the block will be . BUT unlike + * the freespace btrees, the *last* value in each block gets + * propagated up the tree instead of the first value in each block. + * that is, the interior records point to child blocks and the *greatest* + * hash value contained by the child block is the one the block above + * uses as the key for the child block. + * + * level is the level of the descendent block. returns 0 if good, + * and 1 if bad. The descendant block may be a leaf block. + * + * the invariant here is that the values in the cursor for the + * levels beneath this level (this_level) and the cursor index + * for this level *must* be valid. + * + * that is, the hashval/bno info is accurate for all + * DESCENDANTS and match what the node[index] information + * for the current index in the cursor for this level. + * + * the index values in the cursor for the descendant level + * are allowed to be off by one as they will reflect the + * next entry at those levels to be processed. + * + * the hashvalue for the current level can't be set until + * we hit the last entry in the block so, it's garbage + * until set by this routine. + * + * bno and bp for the current block/level are always valid + * since they have to be set so we can get a buffer for the + * block. + */ +int +verify_da_path(xfs_mount_t *mp, + da_bt_cursor_t *cursor, + const int p_level) +{ + xfs_da_intnode_t *node; + xfs_da_intnode_t *newnode; + xfs_dfsbno_t fsbno; + xfs_dablk_t dabno; + xfs_buf_t *bp; + int bad; + int entry; + int this_level = p_level + 1; + + /* + * index is currently set to point to the entry that + * should be processed now in this level. + */ + entry = cursor->level[this_level].index; + node = (xfs_da_intnode_t *)XFS_BUF_PTR(cursor->level[this_level].bp); + + /* + * if this block is out of entries, validate this + * block and move on to the next block. + * and update cursor value for said level + */ + if (entry >= INT_GET(node->hdr.count, ARCH_CONVERT)) { + /* + * update the hash value for this level before + * validating it. bno value should be ok since + * it was set when the block was first read in. + */ + cursor->level[this_level].hashval = + INT_GET(node->btree[entry - 1].hashval, ARCH_CONVERT); + + /* + * keep track of greatest block # -- that gets + * us the length of the directory + */ + if (cursor->level[this_level].bno > cursor->greatest_bno) + cursor->greatest_bno = cursor->level[this_level].bno; + + /* + * validate the path for the current used-up block + * before we trash it + */ + if (verify_da_path(mp, cursor, this_level)) + return(1); + /* + * ok, now get the next buffer and check sibling pointers + */ + dabno = INT_GET(node->hdr.info.forw, ARCH_CONVERT); + ASSERT(dabno != 0); + fsbno = blkmap_get(cursor->blkmap, dabno); + + if (fsbno == NULLDFSBNO) { + do_warn("can't get map info for block %u of directory " + "inode %llu\n", dabno, cursor->ino); + return(1); + } + + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + do_warn("can't read block %u (%llu) for directory inode %llu\n", + dabno, fsbno, cursor->ino); + return(1); + } + + newnode = (xfs_da_intnode_t *)XFS_BUF_PTR(bp); + /* + * verify magic number and back pointer, sanity-check + * entry count, verify level + */ + bad = 0; + if (INT_GET(newnode->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) { + do_warn("bad magic number %x in block %u (%llu) for directory " + "inode %llu\n", + INT_GET(newnode->hdr.info.magic, ARCH_CONVERT), + dabno, fsbno, cursor->ino); + bad++; + } + if (INT_GET(newnode->hdr.info.back, ARCH_CONVERT) != + cursor->level[this_level].bno) { + do_warn("bad back pointer in block %u (%llu) for directory " + "inode %llu\n", dabno, fsbno, cursor->ino); + bad++; + } + if (INT_GET(newnode->hdr.count, ARCH_CONVERT) > + XFS_DA_NODE_ENTRIES(mp)) { + do_warn("entry count %d too large in block %u (%llu) for " + "directory inode %llu\n", + INT_GET(newnode->hdr.count, ARCH_CONVERT), + dabno, fsbno, cursor->ino); + bad++; + } + if (INT_GET(newnode->hdr.level, ARCH_CONVERT) != this_level) { + do_warn("bad level %d in block %u (%llu) for directory inode " + "%llu\n", INT_GET(newnode->hdr.level, ARCH_CONVERT), + dabno, fsbno, cursor->ino); + bad++; + } + if (bad) { +#ifdef XR_DIR_TRACE + fprintf(stderr, "verify_da_path returns 1 (bad) #4\n"); +#endif + libxfs_putbuf(bp); + return(1); + } + /* + * update cursor, write out the *current* level if + * required. don't write out the descendant level + */ + ASSERT(cursor->level[this_level].dirty == 0 || + (cursor->level[this_level].dirty && !no_modify)); + + if (cursor->level[this_level].dirty && !no_modify) + libxfs_writebuf(cursor->level[this_level].bp, 0); + else + libxfs_putbuf(cursor->level[this_level].bp); + cursor->level[this_level].bp = bp; + cursor->level[this_level].dirty = 0; + cursor->level[this_level].bno = dabno; + cursor->level[this_level].hashval = + INT_GET(newnode->btree[0].hashval, ARCH_CONVERT); +#ifdef XR_DIR_TRACE + cursor->level[this_level].n = newnode; +#endif + node = newnode; + + entry = cursor->level[this_level].index = 0; + } + /* + * ditto for block numbers + */ + if (cursor->level[p_level].bno != + INT_GET(node->btree[entry].before, ARCH_CONVERT)) { +#ifdef XR_DIR_TRACE + fprintf(stderr, "bad directory btree pointer, child bno should be %d, " + "block bno is %d, hashval is %u\n", + INT_GET(node->btree[entry].before, ARCH_CONVERT), + cursor->level[p_level].bno, + cursor->level[p_level].hashval); + fprintf(stderr, "verify_da_path returns 1 (bad) #1a\n"); +#endif + return(1); + } + /* + * ok, now validate last hashvalue in the descendant + * block against the hashval in the current entry + */ + if (cursor->level[p_level].hashval != + INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) { + if (!no_modify) { + do_warn("correcting bad hashval in interior dir/attr block\n"); + do_warn("\tin (level %d) in inode %llu.\n", + this_level, cursor->ino); + INT_SET(node->btree[entry].hashval, ARCH_CONVERT, + cursor->level[p_level].hashval); + cursor->level[this_level].dirty++; + } else { + do_warn("would correct bad hashval in interior dir/attr " + "block\n\tin (level %d) in inode %llu.\n", + this_level, cursor->ino); + } + } + /* + * increment index for this level to point to next entry + * (which should point to the next descendant block) + */ + cursor->level[this_level].index++; +#ifdef XR_DIR_TRACE + fprintf(stderr, "verify_da_path returns 0 (ok)\n"); +#endif + return(0); +} + +#if 0 +/* + * handles junking directory leaf block entries that have zero lengths + * buf_dirty is an in/out, set to 1 if the leaf was modified. + * we do NOT initialize it to zero if nothing happened because it + * may be already set by the caller. Assumes that the block + * has been compacted before calling this routine. + */ +void +junk_zerolen_dir_leaf_entries( + xfs_mount_t *mp, + xfs_dir_leafblock_t *leaf, + xfs_ino_t ino, + int *buf_dirty) +{ + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + xfs_dir_leaf_hdr_t *hdr; + xfs_dir_leaf_map_t *map; + xfs_ino_t tmp_ino; + int bytes; + int tmp_bytes; + int current_hole = 0; + int i; + int j; + int tmp; + int start; + int before; + int after; + int smallest; + int tablesize; + + entry = &leaf->entries[0]; + hdr = &leaf->hdr; + + /* + * we can convert the entries to one character entries + * as long as we have space. Once we run out, then + * we have to delete really delete (copy over) an entry. + * however, that frees up some space that we could use ... + * + * so the idea is, we'll use up space from all the holes, + * potentially leaving each hole too small to do any good. + * then if need to, we'll delete entries and use that space + * up from the top-most byte down. that may leave a 4th hole + * but we can represent that by correctly setting the value + * of firstused. that leaves any hole between the end of + * the entry list and firstused so it doesn't have to be + * recorded in the hole map. + */ + + for (bytes = i = 0; i < INT_GET(hdr->count, ARCH_CONVERT); entry++, i++) { + /* + * skip over entries that are good or already converted + */ + if (entry->namelen != 0) + continue; + + *buf_dirty = 1; +#if 0 + /* + * try and use up existing holes first until they get + * too small, then set bytes to the # of bytes between + * the current heap beginning and the last used byte + * in the entry table. + */ + if (bytes < sizeof(xfs_dir_leaf_name_t) && + current_hole < XFS_DIR_LEAF_MAPSIZE) { + /* + * skip over holes that are too small + */ + while (current_hole < XFS_DIR_LEAF_MAPSIZE && + INT_GET(hdr->freemap[current_hole].size, ARCH_CONVERT) < + sizeof(xfs_dir_leaf_name_t)) { + current_hole++; + } + + if (current_hole < XFS_DIR_LEAF_MAPSIZE) + bytes = INT_GET(hdr->freemap[current_hole].size, ARCH_CONVERT); + else + bytes = (int) INT_GET(hdr->firstused, ARCH_CONVERT) - + ((__psint_t) &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)] - + (__psint_t) leaf); + } +#endif + current_hole = 0; + + for (map = &hdr->freemap[0]; + current_hole < XFS_DIR_LEAF_MAPSIZE && + INT_GET(map->size, ARCH_CONVERT) < sizeof(xfs_dir_leaf_name_t); + map++) { + current_hole++; + } + + /* + * if we can use an existing hole, do it. otherwise, + * delete entries until the deletions create a big enough + * hole to convert another entry. then use up those bytes + * bytes until you run low. then delete entries again ... + */ + if (current_hole < XFS_DIR_LEAF_MAPSIZE) { + ASSERT(sizeof(xfs_dir_leaf_name_t) <= bytes); + + do_warn("marking bad entry in directory inode %llu\n", + ino); + + entry->namelen = 1; + INT_SET(entry->nameidx, ARCH_CONVERT, INT_GET(hdr->freemap[current_hole].base, ARCH_CONVERT) + + bytes - sizeof(xfs_dir_leaf_name_t)); + + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + tmp_ino = NULLFSINO; + XFS_DIR_SF_PUT_DIRINO_ARCH(&tmp_ino, &namest->inumber, ARCH_CONVERT); + namest->name[0] = '/'; + + if (INT_GET(entry->nameidx, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT)) + INT_SET(hdr->firstused, ARCH_CONVERT, INT_GET(entry->nameidx, ARCH_CONVERT)); + INT_MOD(hdr->freemap[current_hole].size, ARCH_CONVERT, -(sizeof(xfs_dir_leaf_name_t))); + INT_MOD(hdr->namebytes, ARCH_CONVERT, +1); + } else { + /* + * delete the table entry and try and account for the + * space in the holemap. don't have to update namebytes + * or firstused since we're not actually deleting any + * bytes from the heap. following code swiped from + * xfs_dir_leaf_remove() in xfs_dir_leaf.c + */ + INT_MOD(hdr->count, ARCH_CONVERT, -1); + do_warn( + "deleting zero length entry in directory inode %llu\n", + ino); + /* + * overwrite the bad entry unless it's the + * last entry in the list (highly unlikely). + * zero out the free'd bytes. + */ + if (INT_GET(hdr->count, ARCH_CONVERT) - i > 0) { + memmove(entry, entry + 1, (INT_GET(hdr->count, ARCH_CONVERT) - i) * + sizeof(xfs_dir_leaf_entry_t)); + } + bzero((void *) ((__psint_t) entry + + (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1) * + sizeof(xfs_dir_leaf_entry_t)), + sizeof(xfs_dir_leaf_entry_t)); + + start = (__psint_t) &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)] - + (__psint_t) &leaf; + tablesize = sizeof(xfs_dir_leaf_entry_t) * + (INT_GET(hdr->count, ARCH_CONVERT) + 1) + sizeof(xfs_dir_leaf_hdr_t); + map = &hdr->freemap[0]; + tmp = INT_GET(map->size, ARCH_CONVERT); + before = after = -1; + smallest = XFS_DIR_LEAF_MAPSIZE - 1; + for (j = 0; j < XFS_DIR_LEAF_MAPSIZE; map++, j++) { + ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); + if (INT_GET(map->base, ARCH_CONVERT) == tablesize) { + INT_MOD(map->base, ARCH_CONVERT, -(sizeof(xfs_dir_leaf_entry_t))); + INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t)); + } + + if ((INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)) == start) { + before = j; + } else if (INT_GET(map->base, ARCH_CONVERT) == start + + sizeof(xfs_dir_leaf_entry_t)) { + after = j; + } else if (INT_GET(map->size, ARCH_CONVERT) < tmp) { + tmp = INT_GET(map->size, ARCH_CONVERT); + smallest = j; + } + } + + /* + * Coalesce adjacent freemap regions, + * or replace the smallest region. + */ + if ((before >= 0) || (after >= 0)) { + if ((before >= 0) && (after >= 0)) { + map = &hdr->freemap[before]; + INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t)); + INT_MOD(map->size, ARCH_CONVERT, INT_GET(hdr->freemap[after].size, ARCH_CONVERT)); + INT_ZERO(hdr->freemap[after].base, ARCH_CONVERT); + INT_ZERO(hdr->freemap[after].size, ARCH_CONVERT); + } else if (before >= 0) { + map = &hdr->freemap[before]; + INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t)); + } else { + map = &hdr->freemap[after]; + INT_SET(map->base, ARCH_CONVERT, start); + INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t)); + } + } else { + /* + * Replace smallest region + * (if it is smaller than free'd entry) + */ + map = &hdr->freemap[smallest]; + if (INT_GET(map->size, ARCH_CONVERT) < sizeof(xfs_dir_leaf_entry_t)) { + INT_SET(map->base, ARCH_CONVERT, start); + INT_SET(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t)); + } + /* + * mark as needing compaction + */ + hdr->holes = 1; + } +#if 0 + /* + * do we have to delete stuff or is there + * room for deletions? + */ + ASSERT(current_hole == XFS_DIR_LEAF_MAPSIZE); + + /* + * here, bytes == number of unused bytes from + * end of list to top (beginning) of heap + * (firstused). It's ok to leave extra + * unused bytes in that region because they + * wind up before firstused (which we reset + * appropriately + */ + if (bytes < sizeof(xfs_dir_leaf_name_t)) { + /* + * have to delete an entry because + * we have no room to convert it to + * a bad entry + */ + do_warn( + "deleting entry in directory inode %llu\n", + ino); + /* + * overwrite the bad entry unless it's the + * last entry in the list (highly unlikely). + */ + if (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1> 0) { + memmove(entry, entry + 1, + (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1) * + sizeof(xfs_dir_leaf_entry_t)); + } + bzero((void *) ((__psint_t) entry + + (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1) * + sizeof(xfs_dir_leaf_entry_t)), + sizeof(xfs_dir_leaf_entry_t)); + + /* + * bump up free byte count, drop other + * index vars since the table just + * shrank by one entry and we don't + * want to miss any as we walk the table + */ + bytes += sizeof(xfs_dir_leaf_entry_t); + INT_MOD(leaf->hdr.count, ARCH_CONVERT, -1); + entry--; + i--; + } else { + /* + * convert entry using the bytes in between + * the end of the entry table and the heap + */ + entry->namelen = 1; + INT_MOD(leaf->hdr.firstused, ARCH_CONVERT, -(sizeof(xfs_dir_leaf_name_t))); + INT_SET(entry->nameidx, ARCH_CONVERT, INT_GET(leaf->hdr.firstused, ARCH_CONVERT)); + + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, + INT_GET(entry->nameidx, ARCH_CONVERT)); + tmp_ino = NULLFSINO; + XFS_DIR_SF_PUT_DIRINO_ARCH(&tmp_ino, + &namest->inumber, ARCH_CONVERT); + namest->name[0] = '/'; + + bytes -= sizeof(xfs_dir_leaf_entry_t); + } +#endif + } + } + + return; +} +#endif + +static char dirbuf[64 * 1024]; + +/* + * called by both node dir and leaf dir processing routines + * validates all contents *but* the sibling pointers (forw/back) + * and the magic number. + * + * returns 0 if the directory is ok or has been brought to the + * stage that it can be fixed up later (in phase 6), + * 1 if it has to be junked. + * + * Right now we fix a lot of things (TBD == to be deleted). + * + * incorrect . entries - inode # is corrected + * entries with mismatched hashvalue/name strings - hashvalue reset + * entries whose hashvalues are out-of-order - entry marked TBD + * .. entries with invalid inode numbers - entry marked TBD + * entries with invalid inode numbers - entry marked TBD + * multiple . entries - all but the first entry are marked TBD + * zero-length entries - entry is deleted + * entries with an out-of-bounds name index ptr - entry is deleted + * + * entries marked TBD have the first character of the name (which + * lives in the heap) have the first character in the name set + * to '/' -- an illegal value. + * + * entries deleted right here are deleted by blowing away the entry + * (but leaving the heap untouched). any space that was used + * by the deleted entry will be reclaimed by the block freespace + * (da_freemap) processing code. + * + * if two entries claim the same space in the heap (say, due to + * bad entry name index pointers), we lose the directory. We could + * try harder to fix this but it'll do for now. + */ +/* ARGSUSED */ +int +process_leaf_dir_block( + xfs_mount_t *mp, + xfs_dir_leafblock_t *leaf, + xfs_dablk_t da_bno, + xfs_ino_t ino, + xfs_dahash_t last_hashval, /* last hashval encountered */ + int ino_discovery, + blkmap_t *blkmap, + int *dot, + int *dotdot, + xfs_ino_t *parent, + int *buf_dirty, /* is buffer dirty? */ + xfs_dahash_t *next_hashval) /* greatest hashval in block */ +{ + xfs_ino_t lino; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_entry_t *s_entry; + xfs_dir_leaf_entry_t *d_entry; + xfs_dir_leafblock_t *new_leaf; + char *first_byte; + xfs_dir_leaf_name_t *namest; + ino_tree_node_t *irec_p; + int num_entries; + xfs_dahash_t hashval; + int i; + int nm_illegal; + int bytes; + int start; + int stop; + int res = 0; + int ino_off; + int first_used; + int bytes_used; + int reset_holes; + int zero_len_entries; + char fname[MAXNAMELEN + 1]; + da_hole_map_t holemap; + da_hole_map_t bholemap; +#if 0 + unsigned char *dir_freemap; +#endif + +#ifdef XR_DIR_TRACE + fprintf(stderr, "\tprocess_leaf_dir_block - ino %llu\n", ino); +#endif + + /* + * clear static dir block freespace bitmap + */ + init_da_freemap(dir_freemap); + +#if 0 + /* + * XXX - alternatively, do this for parallel usage. + * set up block freespace map. head part of dir leaf block + * including all entries are packed so we can use sizeof + * and not worry about alignment. + */ + + if ((dir_freemap = alloc_da_freemap(mp)) == NULL) { + do_error("couldn't allocate directory block freemap\n"); + abort(); + } +#endif + + *buf_dirty = 0; + first_used = mp->m_sb.sb_blocksize; + zero_len_entries = 0; + bytes_used = 0; + + i = stop = sizeof(xfs_dir_leaf_hdr_t); + if (set_da_freemap(mp, dir_freemap, 0, stop)) { + do_warn( +"directory block header conflicts with used space in directory inode %llu\n", + ino); + return(1); + } + + /* + * verify structure: monotonically increasing hash value for + * all leaf entries, indexes for all entries must be within + * this fs block (trivially true for 64K blocks). also track + * used space so we can check the freespace map. check for + * zero-length entries. for now, if anything's wrong, we + * junk the directory and we'll pick up no-longer referenced + * inodes on a later pass. + */ + for (i = 0, entry = &leaf->entries[0]; + i < INT_GET(leaf->hdr.count, ARCH_CONVERT); + i++, entry++) { + /* + * check that the name index isn't out of bounds + * if it is, delete the entry since we can't + * grab the inode #. + */ + if (INT_GET(entry->nameidx, ARCH_CONVERT) >= mp->m_sb.sb_blocksize) { + if (!no_modify) { + *buf_dirty = 1; + + if (INT_GET(leaf->hdr.count, ARCH_CONVERT) > 1) { + do_warn( +"nameidx %d for entry #%d, bno %d, ino %llu > fs blocksize, deleting entry\n", + INT_GET(entry->nameidx, ARCH_CONVERT), i, da_bno, ino); + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) > i); + + bytes = (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i) * + sizeof(xfs_dir_leaf_entry_t); + + /* + * compress table unless we're + * only dealing with 1 entry + * (the last one) in which case + * just zero it. + */ + if (bytes > + sizeof(xfs_dir_leaf_entry_t)) { + memmove(entry, entry + 1, + bytes); + bzero((void *) + ((__psint_t) entry + bytes), + sizeof(xfs_dir_leaf_entry_t)); + } else { + bzero(entry, + sizeof(xfs_dir_leaf_entry_t)); + } + + /* + * sync vars to match smaller table. + * don't have to worry about freespace + * map since we haven't set it for + * this entry yet. + */ + INT_MOD(leaf->hdr.count, ARCH_CONVERT, -1); + i--; + entry--; + } else { + do_warn( +"nameidx %d, entry #%d, bno %d, ino %llu > fs blocksize, marking entry bad\n", + INT_GET(entry->nameidx, ARCH_CONVERT), i, da_bno, ino); + INT_SET(entry->nameidx, ARCH_CONVERT, mp->m_sb.sb_blocksize - + sizeof(xfs_dir_leaf_name_t)); + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, + INT_GET(entry->nameidx, ARCH_CONVERT)); + lino = NULLFSINO; + XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, + &namest->inumber, ARCH_CONVERT); + namest->name[0] = '/'; + } + } else { + do_warn( +"nameidx %d, entry #%d, bno %d, ino %llu > fs blocksize, would delete entry\n", + INT_GET(entry->nameidx, ARCH_CONVERT), i, da_bno, ino); + } + continue; + } + /* + * inode processing -- make sure the inode + * is in our tree or we add it to the uncertain + * list if the inode # is valid. if namelen is 0, + * we can still try for the inode as long as nameidx + * is ok. + */ + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &lino, ARCH_CONVERT); + + /* + * we may have to blow out an entry because of bad + * inode numbers. do NOT touch the name until after + * we've computed the hashvalue and done a namecheck() + * on the name. + */ + if (!ino_discovery && lino == NULLFSINO) { + /* + * don't do a damned thing. We already + * found this (or did it ourselves) during + * phase 3. + */ + } else if (verify_inum(mp, lino)) { + /* + * bad inode number. clear the inode + * number and the entry will get removed + * later. We don't trash the directory + * since it's still structurally intact. + */ + do_warn( +"invalid ino number %llu in dir ino %llu, entry #%d, bno %d\n", + lino, ino, i, da_bno); + if (!no_modify) { + do_warn( + "\tclearing ino number in entry %d...\n", i); + + lino = NULLFSINO; + XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, &namest->inumber, ARCH_CONVERT); + *buf_dirty = 1; + } else { + do_warn( + "\twould clear ino number in entry %d...\n", i); + } + } else if (lino == mp->m_sb.sb_rbmino) { + do_warn( +"entry #%d, bno %d in directory %llu references realtime bitmap inode %llu\n", + i, da_bno, ino, lino); + if (!no_modify) { + do_warn( + "\tclearing ino number in entry %d...\n", i); + + lino = NULLFSINO; + XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, &namest->inumber, ARCH_CONVERT); + *buf_dirty = 1; + } else { + do_warn( + "\twould clear ino number in entry %d...\n", i); + } + } else if (lino == mp->m_sb.sb_rsumino) { + do_warn( +"entry #%d, bno %d in directory %llu references realtime summary inode %llu\n", + i, da_bno, ino, lino); + if (!no_modify) { + do_warn( + "\tclearing ino number in entry %d...\n", i); + + lino = NULLFSINO; + XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, &namest->inumber, ARCH_CONVERT); + *buf_dirty = 1; + } else { + do_warn( + "\twould clear ino number in entry %d...\n", i); + } + } else if (lino == mp->m_sb.sb_uquotino) { + do_warn( +"entry #%d, bno %d in directory %llu references user quota inode %llu\n", + i, da_bno, ino, lino); + if (!no_modify) { + do_warn( + "\tclearing ino number in entry %d...\n", i); + + lino = NULLFSINO; + XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, &namest->inumber, ARCH_CONVERT); + *buf_dirty = 1; + } else { + do_warn( + "\twould clear ino number in entry %d...\n", i); + } + } else if (lino == mp->m_sb.sb_gquotino) { + do_warn( +"entry #%d, bno %d in directory %llu references group quota inode %llu\n", + i, da_bno, ino, lino); + if (!no_modify) { + do_warn( + "\tclearing ino number in entry %d...\n", i); + + lino = NULLFSINO; + XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, &namest->inumber, ARCH_CONVERT); + *buf_dirty = 1; + } else { + do_warn( + "\twould clear ino number in entry %d...\n", i); + } + } else if (lino == old_orphanage_ino) { + /* + * do nothing, silently ignore it, entry has + * already been marked TBD since old_orphanage_ino + * is set non-zero. + */ + } else if ((irec_p = find_inode_rec( + XFS_INO_TO_AGNO(mp, lino), + XFS_INO_TO_AGINO(mp, lino))) != NULL) { + /* + * inode recs should have only confirmed + * inodes in them + */ + ino_off = XFS_INO_TO_AGINO(mp, lino) - + irec_p->ino_startnum; + ASSERT(is_inode_confirmed(irec_p, ino_off)); + /* + * if inode is marked free and we're in inode + * discovery mode, leave the entry alone for now. + * if the inode turns out to be used, we'll figure + * that out when we scan it. If the inode really + * is free, we'll hit this code again in phase 4 + * after we've finished inode discovery and blow + * out the entry then. + */ + if (!ino_discovery && is_inode_free(irec_p, ino_off)) { + if (!no_modify) { + do_warn( +"entry references free inode %llu in directory %llu, will clear entry\n", + lino, ino); + lino = NULLFSINO; + XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, + &namest->inumber, ARCH_CONVERT); + *buf_dirty = 1; + } else { + do_warn( +"entry references free inode %llu in directory %llu, would clear entry\n", + lino, ino); + } + } + } else if (ino_discovery) { + add_inode_uncertain(mp, lino, 0); + } else { + do_warn( + "bad ino number %llu in dir ino %llu, entry #%d, bno %d\n", + lino, ino, i, da_bno); + if (!no_modify) { + do_warn("clearing inode number...\n"); + lino = NULLFSINO; + XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, &namest->inumber, ARCH_CONVERT); + *buf_dirty = 1; + } else { + do_warn("would clear inode number...\n"); + } + } + /* + * if we have a zero-length entry, trash it. + * we may lose the inode (chunk) if we don't + * finish the repair successfully and the inode + * isn't mentioned anywhere else (like in the inode + * tree) but the alternative is to risk losing the + * entire directory by trying to use the next byte + * to turn the entry into a 1-char entry. That's + * probably a safe bet but if it didn't work, we'd + * lose the entire directory the way we currently do + * things. (Maybe we should change that later :-). + */ + if (entry->namelen == 0) { + *buf_dirty = 1; + + if (INT_GET(leaf->hdr.count, ARCH_CONVERT) > 1) { + do_warn( + "entry #%d, dir inode %llu, has zero-len name, deleting entry\n", + i, ino); + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) > i); + + bytes = (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i) * + sizeof(xfs_dir_leaf_entry_t); + + /* + * compress table unless we're + * only dealing with 1 entry + * (the last one) in which case + * just zero it. + */ + if (bytes > sizeof(xfs_dir_leaf_entry_t)) { + memmove(entry, entry + 1, + bytes); + bzero((void *) + ((__psint_t) entry + bytes), + sizeof(xfs_dir_leaf_entry_t)); + } else { + bzero(entry, + sizeof(xfs_dir_leaf_entry_t)); + } + + /* + * sync vars to match smaller table. + * don't have to worry about freespace + * map since we haven't set it for + * this entry yet. + */ + INT_MOD(leaf->hdr.count, ARCH_CONVERT, -1); + i--; + entry--; + } else { + /* + * if it's the only entry, preserve the + * inode number for now + */ + do_warn( + "entry #%d, dir inode %llu, has zero-len name, marking entry bad\n", + i, ino); + INT_SET(entry->nameidx, ARCH_CONVERT, mp->m_sb.sb_blocksize - + sizeof(xfs_dir_leaf_name_t)); + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, + INT_GET(entry->nameidx, ARCH_CONVERT)); + XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, &namest->inumber, ARCH_CONVERT); + namest->name[0] = '/'; + } + } else if (INT_GET(entry->nameidx, ARCH_CONVERT) + entry->namelen > XFS_LBSIZE(mp)) { + do_warn( +"bad size, entry #%d in dir inode %llu, block %u -- entry overflows block\n", + i, ino, da_bno); + + return(1); + } + + start = (__psint_t)&leaf->entries[i] - (__psint_t)leaf;; + stop = start + sizeof(xfs_dir_leaf_entry_t); + + if (set_da_freemap(mp, dir_freemap, start, stop)) { + do_warn( +"dir entry slot %d in block %u conflicts with used space in dir inode %llu\n", + i, da_bno, ino); + return(1); + } + + /* + * check if the name is legal. if so, then + * check that the name and hashvalues match. + * + * if the name is illegal, we don't check the + * hashvalue computed from it. we just make + * sure that the hashvalue in the entry is + * monotonically increasing wrt to the previous + * entry. + * + * Note that we do NOT have to check the length + * because the length is stored in a one-byte + * unsigned int which max's out at MAXNAMELEN + * making it impossible for the stored length + * value to be out of range. + */ + bcopy(namest->name, fname, entry->namelen); + fname[entry->namelen] = '\0'; + hashval = libxfs_da_hashname(fname, entry->namelen); + + /* + * only complain about illegal names in phase 3 (when + * inode discovery is turned on). Otherwise, we'd complain + * a lot during phase 4. If the name is illegal, leave + * the hash value in that entry alone. + */ + nm_illegal = namecheck(fname, entry->namelen); + + if (ino_discovery && nm_illegal) { + /* + * junk the entry, illegal name + */ + if (!no_modify) { + do_warn( + "illegal name \"%s\" in directory inode %llu, entry will be cleared\n", + fname, ino); + namest->name[0] = '/'; + *buf_dirty = 1; + } else { + do_warn( + "illegal name \"%s\" in directory inode %llu, entry would be cleared\n", + fname, ino); + } + } else if (!nm_illegal && INT_GET(entry->hashval, ARCH_CONVERT) != hashval) { + /* + * try resetting the hashvalue to the correct + * value for the string, if the string has been + * corrupted, too, that will get picked up next + */ + do_warn("\tmismatched hash value for entry \"%s\"\n", + fname); + if (!no_modify) { + do_warn( + "\t\tin directory inode %llu. resetting hash value.\n", + ino); + INT_SET(entry->hashval, ARCH_CONVERT, hashval); + *buf_dirty = 1; + } else { + do_warn( + "\t\tin directory inode %llu. would reset hash value.\n", + ino); + } + } + + /* + * now we can mark entries with NULLFSINO's bad + */ + if (!no_modify && lino == NULLFSINO) { + namest->name[0] = '/'; + *buf_dirty = 1; + } + + /* + * regardless of whether the entry has or hasn't been + * marked for deletion, the hash value ordering must + * be maintained. + */ + if (INT_GET(entry->hashval, ARCH_CONVERT) < last_hashval) { + /* + * blow out the entry -- set hashval to sane value + * and set the first character in the string to + * the illegal value '/'. Reset the hash value + * to the last hashvalue so that verify_da_path + * will fix up the interior pointers correctly. + * the entry will be deleted later (by routines + * that need only the entry #). We keep the + * inode number in the entry so we can attach + * the inode to the orphanage later. + */ + do_warn("\tbad hash ordering for entry \"%s\"\n", + fname); + if (!no_modify) { + do_warn( + "\t\tin directory inode %llu. will clear entry\n", + ino); + INT_SET(entry->hashval, ARCH_CONVERT, last_hashval); + namest->name[0] = '/'; + *buf_dirty = 1; + } else { + do_warn( + "\t\tin directory inode %llu. would clear entry\n", + ino); + } + } + + *next_hashval = last_hashval = INT_GET(entry->hashval, ARCH_CONVERT); + + /* + * if heap data conflicts with something, + * blow it out and skip the rest of the loop + */ + if (set_da_freemap(mp, dir_freemap, INT_GET(entry->nameidx, ARCH_CONVERT), + INT_GET(entry->nameidx, ARCH_CONVERT) + sizeof(xfs_dir_leaf_name_t) + + entry->namelen - 1)) { + do_warn( +"name \"%s\" (block %u, slot %d) conflicts with used space in dir inode %llu\n", + fname, da_bno, i, ino); + if (!no_modify) { + entry->namelen = 0; + *buf_dirty = 1; + + do_warn( + "will clear entry \"%s\" (#%d) in directory inode %llu\n", + fname, i, ino); + } else { + do_warn( + "would clear entry \"%s\" (#%d)in directory inode %llu\n", + fname, i, ino); + } + continue; + } + + /* + * keep track of heap stats (first byte used, total bytes used) + */ + if (INT_GET(entry->nameidx, ARCH_CONVERT) < first_used) + first_used = INT_GET(entry->nameidx, ARCH_CONVERT); + bytes_used += entry->namelen; + + /* + * special . or .. entry processing + */ + if (entry->namelen == 2 && namest->name[0] == '.' && + namest->name[1] == '.') { + /* + * the '..' case + */ + if (!*dotdot) { + (*dotdot)++; + *parent = lino; +#ifdef XR_DIR_TRACE + fprintf(stderr, "process_leaf_dir_block found .. entry (parent) = %llu\n", lino); +#endif + /* + * what if .. == .? legal only in + * the root inode. blow out entry + * and set parent to NULLFSINO otherwise. + */ + if (ino == lino && + ino != mp->m_sb.sb_rootino) { + *parent = NULLFSINO; + do_warn( + "bad .. entry in dir ino %llu, points to self", + ino); + if (!no_modify) { + do_warn("will clear entry\n"); + + namest->name[0] = '/'; + *buf_dirty = 1; + } else { + do_warn("would clear entry\n"); + } + } else if (ino != lino && + ino == mp->m_sb.sb_rootino) { + /* + * we have to make sure that . == .. + * in the root inode + */ + if (!no_modify) { + do_warn( + "correcting .. entry in root inode %llu, was %llu\n", + ino, *parent); + XFS_DIR_SF_PUT_DIRINO_ARCH( + &ino, + &namest->inumber, ARCH_CONVERT); + *buf_dirty = 1; + } else { + do_warn( + "bad .. entry (%llu) in root inode %llu should be %llu\n", + *parent, + ino, ino); + } + } + } else { + /* + * can't fix the directory unless we know + * which .. entry is the right one. Both + * have valid inode numbers, match the hash + * value and the hash values are ordered + * properly or we wouldn't be here. So + * since both seem equally valid, trash + * this one. + */ + if (!no_modify) { + do_warn( +"multiple .. entries in directory inode %llu, will clear second entry\n", + ino); + namest->name[0] = '/'; + *buf_dirty = 1; + } else { + do_warn( +"multiple .. entries in directory inode %llu, would clear second entry\n", + ino); + } + } + } else if (entry->namelen == 1 && namest->name[0] == '.') { + /* + * the '.' case + */ + if (!*dot) { + (*dot)++; + if (lino != ino) { + if (!no_modify) { + do_warn( + ". in directory inode %llu has wrong value (%llu), fixing entry...\n", + ino, lino); + XFS_DIR_SF_PUT_DIRINO_ARCH(&ino, + &namest->inumber, ARCH_CONVERT); + *buf_dirty = 1; + } else { + do_warn( + ". in directory inode %llu has wrong value (%llu)\n", + ino, lino); + } + } + } else { + do_warn( + "multiple . entries in directory inode %llu\n", + ino); + /* + * mark entry as to be junked. + */ + if (!no_modify) { + do_warn( + "will clear one . entry in directory inode %llu\n", + ino); + namest->name[0] = '/'; + *buf_dirty = 1; + } else { + do_warn( + "would clear one . entry in directory inode %llu\n", + ino); + } + } + } else { + /* + * all the rest -- make sure only . references self + */ + if (lino == ino) { + do_warn( + "entry \"%s\" in directory inode %llu points to self, ", + fname, ino); + if (!no_modify) { + do_warn("will clear entry\n"); + namest->name[0] = '/'; + *buf_dirty = 1; + } else { + do_warn("would clear entry\n"); + } + } + } + } + + /* + * compare top of heap values and reset as required. if the + * holes flag is set, don't reset first_used unless it's + * pointing to used bytes. we're being conservative here + * since the block will get compacted anyhow by the kernel. + */ + if ((leaf->hdr.holes == 0 && first_used != INT_GET(leaf->hdr.firstused, ARCH_CONVERT)) || + INT_GET(leaf->hdr.firstused, ARCH_CONVERT) > first_used) { + if (!no_modify) { + if (verbose) + do_warn( +"- resetting first used heap value from %d to %d in block %u of dir ino %llu\n", + (int) INT_GET(leaf->hdr.firstused, ARCH_CONVERT), first_used, + da_bno, ino); + INT_SET(leaf->hdr.firstused, ARCH_CONVERT, first_used); + *buf_dirty = 1; + } else { + if (verbose) + do_warn( +"- would reset first used value from %d to %d in block %u of dir ino %llu\n", + (int) INT_GET(leaf->hdr.firstused, ARCH_CONVERT), first_used, + da_bno, ino); + } + } + + if (bytes_used != INT_GET(leaf->hdr.namebytes, ARCH_CONVERT)) { + if (!no_modify) { + if (verbose) + do_warn( +"- resetting namebytes cnt from %d to %d in block %u of dir inode %llu\n", + (int) INT_GET(leaf->hdr.namebytes, ARCH_CONVERT), bytes_used, + da_bno, ino); + INT_SET(leaf->hdr.namebytes, ARCH_CONVERT, bytes_used); + *buf_dirty = 1; + } else { + if (verbose) + do_warn( +"- would reset namebytes cnt from %d to %d in block %u of dir inode %llu\n", + (int) INT_GET(leaf->hdr.namebytes, ARCH_CONVERT), bytes_used, + da_bno, ino); + } + } + + /* + * If the hole flag is not set, then we know that there can + * be no lost holes. If the hole flag is set, then it's ok + * if the on-disk holemap doesn't describe everything as long + * as what it does describe doesn't conflict with reality. + */ + + reset_holes = 0; + + bholemap.lost_holes = leaf->hdr.holes; + for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; i++) { + bholemap.hentries[i].base = INT_GET(leaf->hdr.freemap[i].base, ARCH_CONVERT); + bholemap.hentries[i].size = INT_GET(leaf->hdr.freemap[i].size, ARCH_CONVERT); + } + + /* + * Ok, now set up our own freespace list + * (XFS_DIR_LEAF_MAPSIZE (3) * biggest regions) + * and see if they match what's in the block + */ + bzero(&holemap, sizeof(da_hole_map_t)); + process_da_freemap(mp, dir_freemap, &holemap); + + if (zero_len_entries) { + reset_holes = 1; + } else if (leaf->hdr.holes == 0) { + if (holemap.lost_holes > 0) { + if (verbose) + do_warn( + "- found unexpected lost holes in block %u, dir inode %llu\n", + da_bno, ino); + + reset_holes = 1; + } else if (compare_da_freemaps(mp, &holemap, &bholemap, + XFS_DIR_LEAF_MAPSIZE, ino, da_bno)) { + if (verbose) + do_warn( + "- hole info non-optimal in block %u, dir inode %llu\n", + da_bno, ino); + reset_holes = 1; + } + } else if (verify_da_freemap(mp, dir_freemap, &holemap, ino, da_bno)) { + if (verbose) + do_warn( + "- hole info incorrect in block %u, dir inode %llu\n", + da_bno, ino); + reset_holes = 1; + } + + if (reset_holes) { + /* + * have to reset block hole info + */ + if (verbose) { + do_warn( + "- existing hole info for block %d, dir inode %llu (base, size) - \n", + da_bno, ino); + do_warn("- \t"); + for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; i++) { + do_warn( + "- (%d, %d) ", bholemap.hentries[i].base, + bholemap.hentries[i].size); + } + do_warn("- holes flag = %d\n", bholemap.lost_holes); + } + + if (!no_modify) { + if (verbose) + do_warn( + "- compacting block %u in dir inode %llu\n", + da_bno, ino); + + new_leaf = (xfs_dir_leafblock_t *) &dirbuf[0]; + + /* + * copy leaf block header + */ + bcopy(&leaf->hdr, &new_leaf->hdr, + sizeof(xfs_dir_leaf_hdr_t)); + + /* + * reset count in case we have some zero length entries + * that are being junked + */ + num_entries = 0; + first_used = XFS_LBSIZE(mp); + first_byte = (char *) new_leaf + + (__psint_t) XFS_LBSIZE(mp); + + /* + * copy entry table and pack names starting from the end + * of the block + */ + for (i = 0, s_entry = &leaf->entries[0], + d_entry = &new_leaf->entries[0]; + i < INT_GET(leaf->hdr.count, ARCH_CONVERT); + i++, s_entry++) { + /* + * skip zero-length entries + */ + if (s_entry->namelen == 0) + continue; + + bytes = sizeof(xfs_dir_leaf_name_t) + + s_entry->namelen - 1; + + if ((__psint_t) first_byte - bytes < + sizeof(xfs_dir_leaf_entry_t) + + (__psint_t) d_entry) { + do_warn( + "not enough space in block %u of dir inode %llu for all entries\n", + da_bno, ino); + break; + } + + first_used -= bytes; + first_byte -= bytes; + + INT_SET(d_entry->nameidx, ARCH_CONVERT, first_used); + INT_SET(d_entry->hashval, ARCH_CONVERT, INT_GET(s_entry->hashval, ARCH_CONVERT)); + d_entry->namelen = s_entry->namelen; + d_entry->pad2 = 0; + + bcopy((char *) leaf + INT_GET(s_entry->nameidx, ARCH_CONVERT), + first_byte, bytes); + + num_entries++; + d_entry++; + } + + ASSERT((char *) first_byte >= (char *) d_entry); + ASSERT(first_used <= XFS_LBSIZE(mp)); + + /* + * zero space between end of table and top of heap + */ + bzero(d_entry, (__psint_t) first_byte + - (__psint_t) d_entry); + + /* + * reset header info + */ + if (num_entries != INT_GET(new_leaf->hdr.count, ARCH_CONVERT)) + INT_SET(new_leaf->hdr.count, ARCH_CONVERT, num_entries); + + INT_SET(new_leaf->hdr.firstused, ARCH_CONVERT, first_used); + new_leaf->hdr.holes = 0; + new_leaf->hdr.pad1 = 0; + + INT_SET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT, (__psint_t) d_entry + - (__psint_t) new_leaf); + INT_SET(new_leaf->hdr.freemap[0].size, ARCH_CONVERT, (__psint_t) first_byte + - (__psint_t) d_entry); + + ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) < first_used); + ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) == + (__psint_t) (&new_leaf->entries[0]) + - (__psint_t) new_leaf + + i * sizeof(xfs_dir_leaf_entry_t)); + ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT(INT_GET(new_leaf->hdr.freemap[0].size, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) + + INT_GET(new_leaf->hdr.freemap[0].size, ARCH_CONVERT) == first_used); + + INT_ZERO(new_leaf->hdr.freemap[1].base, ARCH_CONVERT); + INT_ZERO(new_leaf->hdr.freemap[1].size, ARCH_CONVERT); + INT_ZERO(new_leaf->hdr.freemap[2].base, ARCH_CONVERT); + INT_ZERO(new_leaf->hdr.freemap[2].size, ARCH_CONVERT); + + /* + * final step, copy block back + */ + bcopy(new_leaf, leaf, mp->m_sb.sb_blocksize); + + *buf_dirty = 1; + } else { + if (verbose) + do_warn( + "- would compact block %u in dir inode %llu\n", + da_bno, ino); + } + } +#if 0 + if (!no_modify) { + /* + * now take care of deleting or marking the entries with + * zero-length namelen's + */ + junk_zerolen_dir_leaf_entries(mp, leaf, ino, buf_dirty); + } +#endif +#ifdef XR_DIR_TRACE + fprintf(stderr, "process_leaf_dir_block returns %d\n", res); +#endif + return((res > 0) ? 1 : 0); +} + +/* + * returns 0 if the directory is ok, 1 if it has to be junked. + */ +int +process_leaf_dir_level(xfs_mount_t *mp, + da_bt_cursor_t *da_cursor, + int ino_discovery, + int *repair, + int *dot, + int *dotdot, + xfs_ino_t *parent) +{ + xfs_dir_leafblock_t *leaf; + xfs_buf_t *bp; + xfs_ino_t ino; + xfs_dfsbno_t dev_bno; + xfs_dablk_t da_bno; + xfs_dablk_t prev_bno; + int res = 0; + int buf_dirty = 0; + xfs_daddr_t bd_addr; + xfs_dahash_t current_hashval = 0; + xfs_dahash_t greatest_hashval; + +#ifdef XR_DIR_TRACE + fprintf(stderr, "process_leaf_dir_level - ino %llu\n", da_cursor->ino); +#endif + *repair = 0; + da_bno = da_cursor->level[0].bno; + ino = da_cursor->ino; + prev_bno = 0; + + do { + dev_bno = blkmap_get(da_cursor->blkmap, da_bno); + /* + * directory code uses 0 as the NULL block pointer + * since 0 is the root block and no directory block + * pointer can point to the root block of the btree + */ + ASSERT(da_bno != 0); + + if (dev_bno == NULLDFSBNO) { + do_warn("can't map block %u for directory inode %llu\n", + da_bno, ino); + goto error_out; + } + + bd_addr = (xfs_daddr_t)XFS_FSB_TO_DADDR(mp, dev_bno); + + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dev_bno), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + do_warn("can't read file block %u (fsbno %llu, daddr %lld) " + "for directory inode %llu\n", + da_bno, dev_bno, (__int64_t) bd_addr, ino); + goto error_out; + } + + leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp); + + /* + * check magic number for leaf directory btree block + */ + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) { + do_warn("bad directory leaf magic # %#x for dir ino %llu\n", + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), ino); + libxfs_putbuf(bp); + goto error_out; + } + /* + * keep track of greatest block # -- that gets + * us the length of the directory + */ + if (da_bno > da_cursor->greatest_bno) + da_cursor->greatest_bno = da_bno; + + buf_dirty = 0; + /* + * for each block, process the block, verify it's path, + * then get next block. update cursor values along the way + */ + if (process_leaf_dir_block(mp, leaf, da_bno, ino, + current_hashval, ino_discovery, + da_cursor->blkmap, dot, dotdot, parent, + &buf_dirty, &greatest_hashval)) { + libxfs_putbuf(bp); + goto error_out; + } + + /* + * index can be set to hdr.count so match the + * indexes of the interior blocks -- which at the + * end of the block will point to 1 after the final + * real entry in the block + */ + da_cursor->level[0].hashval = greatest_hashval; + da_cursor->level[0].bp = bp; + da_cursor->level[0].bno = da_bno; + da_cursor->level[0].index = INT_GET(leaf->hdr.count, ARCH_CONVERT); + da_cursor->level[0].dirty = buf_dirty; + + if (INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != prev_bno) { + do_warn("bad sibling back pointer for directory block %u " + "in directory inode %llu\n", da_bno, ino); + libxfs_putbuf(bp); + goto error_out; + } + + prev_bno = da_bno; + da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT); + + if (da_bno != 0) + if (verify_da_path(mp, da_cursor, 0)) { + libxfs_putbuf(bp); + goto error_out; + } + + current_hashval = greatest_hashval; + + ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify)); + + if (buf_dirty && !no_modify) { + *repair = 1; + libxfs_writebuf(bp, 0); + } + else + libxfs_putbuf(bp); + } while (da_bno != 0 && res == 0); + + if (verify_final_da_path(mp, da_cursor, 0)) { + /* + * verify the final path up (right-hand-side) if still ok + */ + do_warn("bad hash path in directory %llu\n", da_cursor->ino); + goto error_out; + } + +#ifdef XR_DIR_TRACE + fprintf(stderr, "process_leaf_dir_level returns %d (%s)\n", + res, ((res) ? "bad" : "ok")); +#endif + /* + * redundant but just for testing + */ + release_da_cursor(mp, da_cursor, 0); + + return(res); + +error_out: + /* + * release all buffers holding interior btree blocks + */ + err_release_da_cursor(mp, da_cursor, 0); + + return(1); +} + +/* + * a node directory is a true btree directory -- where the directory + * has gotten big enough that it is represented as a non-trivial (e.g. + * has more than just a root block) btree. + * + * Note that if we run into any problems, we trash the + * directory. Even if it's the root directory, + * we'll be able to traverse all the disconnected + * subtrees later (phase 6). + * + * one day, if we actually fix things, we'll set repair to 1 to + * indicate that we have or that we should. + * + * dirname can be set to NULL if the name is unknown (or to + * the string representation of the inode) + * + * returns 0 if things are ok, 1 if bad (directory needs to be junked) + */ +/* ARGSUSED */ +int +process_node_dir( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + int ino_discovery, + blkmap_t *blkmap, + int *dot, + int *dotdot, + xfs_ino_t *parent, /* out - parent ino # or NULLFSINO */ + char *dirname, + int *repair) +{ + xfs_dablk_t bno; + int error = 0; + da_bt_cursor_t da_cursor; + +#ifdef XR_DIR_TRACE + fprintf(stderr, "process_node_dir - ino %llu\n", ino); +#endif + *repair = *dot = *dotdot = 0; + *parent = NULLFSINO; + + /* + * try again -- traverse down left-side of tree until we hit + * the left-most leaf block setting up the btree cursor along + * the way. Then walk the leaf blocks left-to-right, calling + * a parent-verification routine each time we traverse a block. + */ + bzero(&da_cursor, sizeof(da_bt_cursor_t)); + + da_cursor.active = 0; + da_cursor.type = 0; + da_cursor.ino = ino; + da_cursor.dip = dip; + da_cursor.greatest_bno = 0; + da_cursor.blkmap = blkmap; + + /* + * now process interior node + */ + + error = traverse_int_dablock(mp, &da_cursor, &bno, XFS_DATA_FORK); + + if (error == 0) + return(1); + + /* + * now pass cursor and bno into leaf-block processing routine + * the leaf dir level routine checks the interior paths + * up to the root including the final right-most path. + */ + + error = process_leaf_dir_level(mp, &da_cursor, ino_discovery, + repair, dot, dotdot, parent); + + if (error) + return(1); + + /* + * sanity check inode size + */ + if (INT_GET(dip->di_core.di_size, ARCH_CONVERT) < + (da_cursor.greatest_bno + 1) * mp->m_sb.sb_blocksize) { + if ((xfs_fsize_t) (da_cursor.greatest_bno + * mp->m_sb.sb_blocksize) > UINT_MAX) { + do_warn( +"out of range internal directory block numbers (inode %llu)\n", + ino); + return(1); + } + + do_warn( +"setting directory inode (%llu) size to %llu bytes, was %lld bytes\n", + ino, + (xfs_dfiloff_t) (da_cursor.greatest_bno + 1) + * mp->m_sb.sb_blocksize, + INT_GET(dip->di_core.di_size, ARCH_CONVERT)); + + INT_SET(dip->di_core.di_size, ARCH_CONVERT, (xfs_fsize_t) + (da_cursor.greatest_bno + 1) * mp->m_sb.sb_blocksize); + } + return(0); +} + +/* + * a leaf directory is one where the directory is too big for + * the inode data fork but is small enough to fit into one + * directory btree block (filesystem block) outside the inode + * + * returns NULLFSINO if the directory is cannot be salvaged + * and the .. ino if things are ok (even if the directory had + * to be altered to make it ok). + * + * dirname can be set to NULL if the name is unknown (or to + * the string representation of the inode) + * + * returns 0 if things are ok, 1 if bad (directory needs to be junked) + */ +/* ARGSUSED */ +int +process_leaf_dir( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + int ino_discovery, + int *dino_dirty, + blkmap_t *blkmap, + int *dot, /* out - 1 if there is a dot, else 0 */ + int *dotdot, /* out - 1 if there's a dotdot, else 0 */ + xfs_ino_t *parent, /* out - parent ino # or NULLFSINO */ + char *dirname, /* in - directory pathname */ + int *repair) /* out - 1 if something was fixed */ +{ + xfs_dir_leafblock_t *leaf; + xfs_dahash_t next_hashval; + xfs_dfsbno_t bno; + xfs_buf_t *bp; + int buf_dirty = 0; + +#ifdef XR_DIR_TRACE + fprintf(stderr, "process_leaf_dir - ino %llu\n", ino); +#endif + *repair = *dot = *dotdot = 0; + *parent = NULLFSINO; + + bno = blkmap_get(blkmap, 0); + if (bno == NULLDFSBNO) { + do_warn("block 0 for directory inode %llu is missing\n", ino); + return(1); + } + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + do_warn("can't read block 0 for directory inode %llu\n", ino); + return(1); + } + /* + * verify leaf block + */ + leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp); + + /* + * check magic number for leaf directory btree block + */ + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) { + do_warn("bad directory leaf magic # %#x for dir ino %llu\n", + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), ino); + libxfs_putbuf(bp); + return(1); + } + + if (process_leaf_dir_block(mp, leaf, 0, ino, 0, ino_discovery, blkmap, + dot, dotdot, parent, &buf_dirty, &next_hashval)) { + /* + * the block is bad. lose the directory. + * XXX - later, we should try and just lose + * the block without losing the entire directory + */ + ASSERT(*dotdot == 0 || (*dotdot == 1 && *parent != NULLFSINO)); + libxfs_putbuf(bp); + return(1); + } + + /* + * check sibling pointers in leaf block (above doesn't do it) + */ + if (INT_GET(leaf->hdr.info.forw, ARCH_CONVERT) != 0 || + INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != 0) { + if (!no_modify) { + do_warn("clearing forw/back pointers for directory inode " + "%llu\n", ino); + buf_dirty = 1; + INT_ZERO(leaf->hdr.info.forw, ARCH_CONVERT); + INT_ZERO(leaf->hdr.info.back, ARCH_CONVERT); + } else { + do_warn("would clear forw/back pointers for directory inode " + "%llu\n", ino); + } + } + + ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify)); + + if (buf_dirty && !no_modify) + libxfs_writebuf(bp, 0); + else + libxfs_putbuf(bp); + + return(0); +} + +/* + * returns 1 if things are bad (directory needs to be junked) + * and 0 if things are ok. If ino_discovery is 1, add unknown + * inodes to uncertain inode list. + */ +int +process_dir( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + int ino_discovery, + int *dino_dirty, + char *dirname, + xfs_ino_t *parent, + blkmap_t *blkmap) +{ + int dot; + int dotdot; + int repair = 0; + int res = 0; + + *parent = NULLFSINO; + dot = dotdot = 0; + + /* + * branch off depending on the type of inode. This routine + * is only called ONCE so all the subordinate routines will + * fix '.' and junk '..' if they're bogus. + */ + if (INT_GET(dip->di_core.di_size, ARCH_CONVERT) <= XFS_DFORK_DSIZE_ARCH(dip, mp, ARCH_CONVERT)) { + dot = 1; + dotdot = 1; + if (process_shortform_dir(mp, ino, dip, ino_discovery, + dino_dirty, parent, dirname, &repair)) { + res = 1; + } + } else if (INT_GET(dip->di_core.di_size, ARCH_CONVERT) <= XFS_LBSIZE(mp)) { + if (process_leaf_dir(mp, ino, dip, ino_discovery, + dino_dirty, blkmap, &dot, &dotdot, + parent, dirname, &repair)) { + res = 1; + } + } else { + if (process_node_dir(mp, ino, dip, ino_discovery, + blkmap, &dot, &dotdot, + parent, dirname, &repair)) { + res = 1; + } + } + /* + * bad . entries in all directories will be fixed up in phase 6 + */ + if (dot == 0) { + do_warn("no . entry for directory %llu\n", ino); + } + + /* + * shortform dirs always have a .. entry. .. for all longform + * directories will get fixed in phase 6. .. for other shortform + * dirs also get fixed there. .. for a shortform root was + * fixed in place since we know what it should be + */ + if (dotdot == 0 && ino != mp->m_sb.sb_rootino) { + do_warn("no .. entry for directory %llu\n", ino); + } else if (dotdot == 0 && ino == mp->m_sb.sb_rootino) { + do_warn("no .. entry for root directory %llu\n", ino); + need_root_dotdot = 1; + } + +#ifdef XR_DIR_TRACE + fprintf(stderr, "(process_dir), parent of %llu is %llu\n", ino, parent); +#endif + return(res); +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/dir.h linux-2.4-xfs/cmd/xfsprogs/repair/dir.h --- linux-2.4.7/cmd/xfsprogs/repair/dir.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/dir.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef _XR_DIR_H +#define _XR_DIR_H + +struct blkmap; + +/* 1 bit per byte, max XFS blocksize == 64K bits / NBBY */ +#define DA_BMAP_SIZE 8192 + +typedef unsigned char da_freemap_t; + +/* + * the cursor gets passed up and down the da btree processing + * routines. The interior block processing routines use the + * cursor to determine if the pointers to and from the preceding + * and succeeding sibling blocks are ok and whether the values in + * the current block are consistent with the entries in the parent + * nodes. When a block is traversed, a parent-verification routine + * is called to verify if the next logical entry in the next level up + * is consistent with the greatest hashval in the next block of the + * current level. The verification routine is itself recursive and + * calls itself if it has to traverse an interior block to get + * the next logical entry. The routine recurses upwards through + * the tree until it finds a block where it can simply step to + * the next entry. The hashval in that entry should be equal to + * the hashval being passed to it (the greatest hashval in the block + * that the entry points to). If that isn't true, then the tree + * is blown and we need to trash it, salvage and trash it, or fix it. + * Currently, we just trash it. + */ +typedef struct da_level_state { + xfs_buf_t *bp; /* block bp */ +#ifdef XR_DIR_TRACE + xfs_da_intnode_t *n; /* bp data */ +#endif + xfs_dablk_t bno; /* file block number */ + xfs_dahash_t hashval; /* last verified hashval */ + int index; /* current index in block */ + int dirty; /* is buffer dirty ? (1 == yes) */ +} da_level_state_t; + +typedef struct da_bt_cursor { + int active; /* highest level in tree (# levels-1) */ + int type; /* 0 if dir, 1 if attr */ + xfs_ino_t ino; + xfs_dablk_t greatest_bno; + xfs_dinode_t *dip; + da_level_state_t level[XFS_DA_NODE_MAXDEPTH]; + struct blkmap *blkmap; +} da_bt_cursor_t; + + +/* ROUTINES */ + +void +err_release_da_cursor( + xfs_mount_t *mp, + da_bt_cursor_t *cursor, + int prev_level); + +xfs_dfsbno_t +get_first_dblock_fsbno( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dino); + +void +init_da_freemap( + da_freemap_t *dir_freemap); + +int +namecheck( + char *name, + int length); + +int +process_shortform_dir( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + int ino_discovery, + int *dino_dirty, /* is dinode buffer dirty? */ + xfs_ino_t *parent, /* out - NULLFSINO if entry doesn't exist */ + char *dirname, /* directory pathname */ + int *repair); /* out - 1 if dir was fixed up */ + +int +process_dir( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + int ino_discovery, + int *dirty, + char *dirname, + xfs_ino_t *parent, + struct blkmap *blkmap); + +void +release_da_cursor( + xfs_mount_t *mp, + da_bt_cursor_t *cursor, + int prev_level); + +int +set_da_freemap( + xfs_mount_t *mp, da_freemap_t *map, + int start, int stop); + +int +traverse_int_dablock( + xfs_mount_t *mp, + da_bt_cursor_t *da_cursor, + xfs_dablk_t *rbno, + int whichfork); + +int +verify_da_path( + xfs_mount_t *mp, + da_bt_cursor_t *cursor, + const int p_level); + +int +verify_final_da_path( + xfs_mount_t *mp, + da_bt_cursor_t *cursor, + const int p_level); + + +#endif /* _XR_DIR_H */ diff -rNu linux-2.4.7/cmd/xfsprogs/repair/dir2.c linux-2.4-xfs/cmd/xfsprogs/repair/dir2.c --- linux-2.4.7/cmd/xfsprogs/repair/dir2.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/dir2.c Thu Apr 12 18:49:04 2001 @@ -0,0 +1,2070 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "avl.h" +#include "globals.h" +#include "incore.h" +#include "err_protos.h" +#include "dinode.h" +#include "dir.h" +#include "dir2.h" +#include "bmap.h" + +/* + * Tag bad directory entries with this. + * We can't tag them with -1 since that will look like a + * data_unused_t instead of a data_entry_t. + */ +#define BADFSINO ((xfs_ino_t)0xfeffffffffffffffULL) + +/* + * Known bad inode list. These are seen when the leaf and node + * block linkages are incorrect. + */ +typedef struct dir2_bad { + xfs_ino_t ino; + struct dir2_bad *next; +} dir2_bad_t; +dir2_bad_t *dir2_bad_list; + +void +dir2_add_badlist( + xfs_ino_t ino) +{ + dir2_bad_t *l; + + if ((l = malloc(sizeof(dir2_bad_t))) == NULL) { + do_error("malloc failed (%u bytes) dir2_add_badlist:ino %llu\n", + sizeof(dir2_bad_t), ino); + exit(1); + } + l->next = dir2_bad_list; + dir2_bad_list = l; + l->ino = ino; +} + +int +dir2_is_badino( + xfs_ino_t ino) +{ + dir2_bad_t *l; + + for (l = dir2_bad_list; l; l = l->next) + if (l->ino == ino) + return 1; + return 0; +} + +/* + * Multibuffer handling. + * V2 directory blocks can be noncontiguous, needing multiple buffers. + */ +xfs_dabuf_t * +da_read_buf( + xfs_mount_t *mp, + int nex, + bmap_ext_t *bmp) +{ + xfs_buf_t *bp; + xfs_buf_t **bplist; + xfs_dabuf_t *dabuf; + int i; + int off; + + bplist = calloc(nex, sizeof(*bplist)); + if (bplist == NULL) { + do_error("couldn't malloc dir2 buffer list\n"); + exit(1); + } + for (i = 0; i < nex; i++) { + bplist[i] = libxfs_readbuf(mp->m_dev, + XFS_FSB_TO_DADDR(mp, bmp[i].startblock), + XFS_FSB_TO_BB(mp, bmp[i].blockcount), 0); + if (!bplist[i]) + goto failed; + } + dabuf = malloc(XFS_DA_BUF_SIZE(nex)); + if (dabuf == NULL) { + do_error("couldn't malloc dir2 buffer header\n"); + exit(1); + } + dabuf->dirty = 0; + dabuf->nbuf = nex; + if (nex == 1) { + bp = bplist[0]; + dabuf->bbcount = (short)BTOBB(XFS_BUF_COUNT(bp)); + dabuf->data = XFS_BUF_PTR(bp); + dabuf->bps[0] = bp; + } else { + for (i = 0, dabuf->bbcount = 0; i < nex; i++) { + dabuf->bps[i] = bp = bplist[i]; + dabuf->bbcount += BTOBB(XFS_BUF_COUNT(bp)); + } + dabuf->data = malloc(BBTOB(dabuf->bbcount)); + if (dabuf->data == NULL) { + do_error("couldn't malloc dir2 buffer data\n"); + exit(1); + } + for (i = off = 0; i < nex; i++, off += XFS_BUF_COUNT(bp)) { + bp = bplist[i]; + bcopy(XFS_BUF_PTR(bp), (char *)dabuf->data + off, + XFS_BUF_COUNT(bp)); + } + } + return dabuf; +failed: + for (i = 0; i < nex; i++) + libxfs_putbuf(bplist[i]); + free(bplist); + return NULL; +} + +static void +da_buf_clean( + xfs_dabuf_t *dabuf) +{ + xfs_buf_t *bp; + int i; + int off; + + if (dabuf->dirty) { + dabuf->dirty = 0; + for (i=off=0; i < dabuf->nbuf; i++, off += XFS_BUF_COUNT(bp)) { + bp = dabuf->bps[i]; + bcopy((char *)dabuf->data + off, XFS_BUF_PTR(bp), + XFS_BUF_COUNT(bp)); + } + } +} + +static void +da_buf_done( + xfs_dabuf_t *dabuf) +{ + da_buf_clean(dabuf); + if (dabuf->nbuf > 1) + free(dabuf->data); + free(dabuf); +} + +int +da_bwrite( + xfs_mount_t *mp, + xfs_dabuf_t *dabuf) +{ + xfs_buf_t *bp; + xfs_buf_t **bplist; + int e; + int error; + int i; + int nbuf; + + if ((nbuf = dabuf->nbuf) == 1) { + bplist = &bp; + bp = dabuf->bps[0]; + } else { + bplist = malloc(nbuf * sizeof(*bplist)); + if (bplist == NULL) { + do_error("couldn't malloc dir2 buffer list\n"); + exit(1); + } + bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist)); + } + da_buf_done(dabuf); + for (i = error = 0; i < nbuf; i++) { + e = libxfs_writebuf(bplist[i], 0); + if (e) + error = e; + } + if (bplist != &bp) + free(bplist); + return error; +} + +void +da_brelse( + xfs_dabuf_t *dabuf) +{ + xfs_buf_t *bp; + xfs_buf_t **bplist; + int i; + int nbuf; + + if ((nbuf = dabuf->nbuf) == 1) { + bplist = &bp; + bp = dabuf->bps[0]; + } else { + bplist = malloc(nbuf * sizeof(*bplist)); + if (bplist == NULL) { + do_error("couldn't malloc dir2 buffer list\n"); + exit(1); + } + bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist)); + } + da_buf_done(dabuf); + for (i = 0; i < nbuf; i++) + libxfs_putbuf(bplist[i]); + if (bplist != &bp) + free(bplist); +} + +/* + * walk tree from root to the left-most leaf block reading in + * blocks and setting up cursor. passes back file block number of the + * left-most leaf block if successful (bno). returns 1 if successful, + * 0 if unsuccessful. + */ +int +traverse_int_dir2block(xfs_mount_t *mp, + dir2_bt_cursor_t *da_cursor, + xfs_dablk_t *rbno) +{ + bmap_ext_t *bmp; + xfs_dablk_t bno; + xfs_dabuf_t *bp; + int i; + int nex; + xfs_da_intnode_t *node; + + /* + * traverse down left-side of tree until we hit the + * left-most leaf block setting up the btree cursor along + * the way. + */ + bno = mp->m_dirleafblk; + i = -1; + node = NULL; + da_cursor->active = 0; + + do { + /* + * read in each block along the way and set up cursor + */ + nex = blkmap_getn(da_cursor->blkmap, bno, mp->m_dirblkfsbs, + &bmp); + + if (nex == 0) + goto error_out; + + bp = da_read_buf(mp, nex, bmp); + free(bmp); + if (bp == NULL) { + do_warn("can't read block %u for directory inode " + "%llu\n", + bno, da_cursor->ino); + goto error_out; + } + + node = bp->data; + + if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) == + XFS_DIR2_LEAFN_MAGIC) { + if ( i != -1 ) { + do_warn("found non-root LEAFN node in inode " + "%llu bno = %u\n", + da_cursor->ino, bno); + } + if (INT_GET(node->hdr.level, ARCH_CONVERT) >= 1) { + do_warn("LEAFN node level is %d inode %llu " + "bno = %u\n", + INT_GET(node->hdr.level, ARCH_CONVERT), + da_cursor->ino, bno); + } + *rbno = 0; + da_brelse(bp); + return(1); + } else if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) != + XFS_DA_NODE_MAGIC) { + da_brelse(bp); + do_warn("bad dir magic number 0x%x in inode %llu " + "bno = %u\n", + INT_GET(node->hdr.info.magic, ARCH_CONVERT), + da_cursor->ino, bno); + goto error_out; + } + if (INT_GET(node->hdr.count, ARCH_CONVERT) > + XFS_DA_NODE_ENTRIES(mp)) { + da_brelse(bp); + do_warn("bad record count in inode %llu, count = %d, " + "max = %d\n", da_cursor->ino, + INT_GET(node->hdr.count, ARCH_CONVERT), + XFS_DA_NODE_ENTRIES(mp)); + goto error_out; + } + + /* + * maintain level counter + */ + if (i == -1) + i = da_cursor->active = + INT_GET(node->hdr.level, ARCH_CONVERT); + else { + if (INT_GET(node->hdr.level, ARCH_CONVERT) == i - 1) { + i--; + } else { + do_warn("bad directory btree for directory " + "inode %llu\n", + da_cursor->ino); + da_brelse(bp); + goto error_out; + } + } + + da_cursor->level[i].hashval = + INT_GET(node->btree[0].hashval, ARCH_CONVERT); + da_cursor->level[i].bp = bp; + da_cursor->level[i].bno = bno; + da_cursor->level[i].index = 0; + + /* + * set up new bno for next level down + */ + bno = INT_GET(node->btree[0].before, ARCH_CONVERT); + } while (node != NULL && i > 1); + + /* + * now return block number and get out + */ + *rbno = da_cursor->level[0].bno = bno; + return(1); + +error_out: + while (i > 1 && i <= da_cursor->active) { + da_brelse(da_cursor->level[i].bp); + i++; + } + + return(0); +} + +/* + * blow out buffer for this level and all the rest above as well + * if error == 0, we are not expecting to encounter any unreleased + * buffers (e.g. if we do, it's a mistake). if error == 1, we're + * in an error-handling case so unreleased buffers may exist. + */ +void +release_dir2_cursor_int(xfs_mount_t *mp, + dir2_bt_cursor_t *cursor, + int prev_level, + int error) +{ + int level = prev_level + 1; + + if (cursor->level[level].bp != NULL) { + if (!error) { + do_warn("release_dir2_cursor_int got unexpected " + "non-null bp, dabno = %u\n", + cursor->level[level].bno); + } + ASSERT(error != 0); + + da_brelse(cursor->level[level].bp); + cursor->level[level].bp = NULL; + } + + if (level < cursor->active) + release_dir2_cursor_int(mp, cursor, level, error); + + return; +} + +void +release_dir2_cursor(xfs_mount_t *mp, + dir2_bt_cursor_t *cursor, + int prev_level) +{ + release_dir2_cursor_int(mp, cursor, prev_level, 0); +} + +void +err_release_dir2_cursor(xfs_mount_t *mp, + dir2_bt_cursor_t *cursor, + int prev_level) +{ + release_dir2_cursor_int(mp, cursor, prev_level, 1); +} + +/* + * make sure that all entries in all blocks along the right side of + * of the tree are used and hashval's are consistent. level is the + * level of the descendent block. returns 0 if good (even if it had + * to be fixed up), and 1 if bad. The right edge of the tree is + * technically a block boundary. This routine should be used then + * instead of verify_dir2_path(). + */ +int +verify_final_dir2_path(xfs_mount_t *mp, + dir2_bt_cursor_t *cursor, + const int p_level) +{ + xfs_da_intnode_t *node; + int bad = 0; + int entry; + int this_level = p_level + 1; + + /* + * the index should point to the next "unprocessed" entry + * in the block which should be the final (rightmost) entry + */ + entry = cursor->level[this_level].index; + node = (xfs_da_intnode_t *)(cursor->level[this_level].bp->data); + /* + * check internal block consistency on this level -- ensure + * that all entries are used, encountered and expected hashvals + * match, etc. + */ + if (entry != INT_GET(node->hdr.count, ARCH_CONVERT) - 1) { + do_warn("directory block used/count inconsistency - %d / %hu\n", + entry, INT_GET(node->hdr.count, ARCH_CONVERT)); + bad++; + } + /* + * hash values monotonically increasing ??? + */ + if (cursor->level[this_level].hashval >= INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) { + do_warn("directory/attribute block hashvalue inconsistency, " + "expected > %u / saw %u\n", + cursor->level[this_level].hashval, + INT_GET(node->btree[entry].hashval, ARCH_CONVERT)); + bad++; + } + if (INT_GET(node->hdr.info.forw, ARCH_CONVERT) != 0) { + do_warn("bad directory/attribute forward block pointer, " + "expected 0, saw %u\n", + INT_GET(node->hdr.info.forw, ARCH_CONVERT)); + bad++; + } + if (bad) { + do_warn("bad directory block in inode %llu\n", cursor->ino); + return(1); + } + /* + * keep track of greatest block # -- that gets + * us the length of the directory + */ + if (cursor->level[this_level].bno > cursor->greatest_bno) + cursor->greatest_bno = cursor->level[this_level].bno; + + /* + * ok, now check descendant block number against this level + */ + if (cursor->level[p_level].bno != INT_GET(node->btree[entry].before, ARCH_CONVERT)) { + return(1); + } + + if (cursor->level[p_level].hashval != INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) { + if (!no_modify) { + do_warn("correcting bad hashval in non-leaf dir " + "block\n"); + do_warn("\tin (level %d) in inode %llu.\n", + this_level, cursor->ino); + INT_SET(node->btree[entry].hashval, ARCH_CONVERT, cursor->level[p_level].hashval); + cursor->level[this_level].dirty++; + } else { + do_warn("would correct bad hashval in non-leaf dir " + "block\n"); + do_warn("\tin (level %d) in inode %llu.\n", + this_level, cursor->ino); + } + } + + /* + * release/write buffer + */ + ASSERT(cursor->level[this_level].dirty == 0 || + (cursor->level[this_level].dirty && !no_modify)); + + if (cursor->level[this_level].dirty && !no_modify) + da_bwrite(mp, cursor->level[this_level].bp); + else + da_brelse(cursor->level[this_level].bp); + + cursor->level[this_level].bp = NULL; + + /* + * bail out if this is the root block (top of tree) + */ + if (this_level >= cursor->active) { + return(0); + } + /* + * set hashvalue to correctl reflect the now-validated + * last entry in this block and continue upwards validation + */ + cursor->level[this_level].hashval = INT_GET(node->btree[entry].hashval, ARCH_CONVERT); + + return(verify_final_dir2_path(mp, cursor, this_level)); +} + +/* + * Verifies the path from a descendant block up to the root. + * Should be called when the descendant level traversal hits + * a block boundary before crossing the boundary (reading in a new + * block). + * + * the directory/attr btrees work differently to the other fs btrees. + * each interior block contains records that are + * pairs. The bno is a file bno, not a filesystem bno. The last + * hashvalue in the block will be . BUT unlike + * the freespace btrees, the *last* value in each block gets + * propagated up the tree instead of the first value in each block. + * that is, the interior records point to child blocks and the *greatest* + * hash value contained by the child block is the one the block above + * uses as the key for the child block. + * + * level is the level of the descendent block. returns 0 if good, + * and 1 if bad. The descendant block may be a leaf block. + * + * the invariant here is that the values in the cursor for the + * levels beneath this level (this_level) and the cursor index + * for this level *must* be valid. + * + * that is, the hashval/bno info is accurate for all + * DESCENDANTS and match what the node[index] information + * for the current index in the cursor for this level. + * + * the index values in the cursor for the descendant level + * are allowed to be off by one as they will reflect the + * next entry at those levels to be processed. + * + * the hashvalue for the current level can't be set until + * we hit the last entry in the block so, it's garbage + * until set by this routine. + * + * bno and bp for the current block/level are always valid + * since they have to be set so we can get a buffer for the + * block. + */ +int +verify_dir2_path(xfs_mount_t *mp, + dir2_bt_cursor_t *cursor, + const int p_level) +{ + xfs_da_intnode_t *node; + xfs_da_intnode_t *newnode; + xfs_dablk_t dabno; + xfs_dabuf_t *bp; + int bad; + int entry; + int this_level = p_level + 1; + bmap_ext_t *bmp; + int nex; + + /* + * index is currently set to point to the entry that + * should be processed now in this level. + */ + entry = cursor->level[this_level].index; + node = cursor->level[this_level].bp->data; + + /* + * if this block is out of entries, validate this + * block and move on to the next block. + * and update cursor value for said level + */ + if (entry >= INT_GET(node->hdr.count, ARCH_CONVERT)) { + /* + * update the hash value for this level before + * validating it. bno value should be ok since + * it was set when the block was first read in. + */ + cursor->level[this_level].hashval = + INT_GET(node->btree[entry - 1].hashval, ARCH_CONVERT); + + /* + * keep track of greatest block # -- that gets + * us the length of the directory + */ + if (cursor->level[this_level].bno > cursor->greatest_bno) + cursor->greatest_bno = cursor->level[this_level].bno; + + /* + * validate the path for the current used-up block + * before we trash it + */ + if (verify_dir2_path(mp, cursor, this_level)) + return(1); + /* + * ok, now get the next buffer and check sibling pointers + */ + dabno = INT_GET(node->hdr.info.forw, ARCH_CONVERT); + ASSERT(dabno != 0); + nex = blkmap_getn(cursor->blkmap, dabno, mp->m_dirblkfsbs, + &bmp); + if (nex == 0) { + do_warn("can't get map info for block %u of directory " + "inode %llu\n", + dabno, cursor->ino); + return(1); + } + + bp = da_read_buf(mp, nex, bmp); + + if (bp == NULL) { + do_warn("can't read block %u for directory inode " + "%llu\n", + dabno, cursor->ino); + return(1); + } + + newnode = bp->data; + /* + * verify magic number and back pointer, sanity-check + * entry count, verify level + */ + bad = 0; + if (INT_GET(newnode->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) { + do_warn("bad magic number %x in block %u for directory " + "inode %llu\n", + INT_GET(newnode->hdr.info.magic, ARCH_CONVERT), dabno, cursor->ino); + bad++; + } + if (INT_GET(newnode->hdr.info.back, ARCH_CONVERT) != cursor->level[this_level].bno) { + do_warn("bad back pointer in block %u for directory " + "inode %llu\n", + dabno, cursor->ino); + bad++; + } + if (INT_GET(newnode->hdr.count, ARCH_CONVERT) > XFS_DA_NODE_ENTRIES(mp)) { + do_warn("entry count %d too large in block %u for " + "directory inode %llu\n", + INT_GET(newnode->hdr.count, ARCH_CONVERT), dabno, cursor->ino); + bad++; + } + if (INT_GET(newnode->hdr.level, ARCH_CONVERT) != this_level) { + do_warn("bad level %d in block %u for directory inode " + "%llu\n", + INT_GET(newnode->hdr.level, ARCH_CONVERT), dabno, cursor->ino); + bad++; + } + if (bad) { + da_brelse(bp); + return(1); + } + /* + * update cursor, write out the *current* level if + * required. don't write out the descendant level + */ + ASSERT(cursor->level[this_level].dirty == 0 || + (cursor->level[this_level].dirty && !no_modify)); + + if (cursor->level[this_level].dirty && !no_modify) + da_bwrite(mp, cursor->level[this_level].bp); + else + da_brelse(cursor->level[this_level].bp); + cursor->level[this_level].bp = bp; + cursor->level[this_level].dirty = 0; + cursor->level[this_level].bno = dabno; + cursor->level[this_level].hashval = INT_GET(newnode->btree[0].hashval, ARCH_CONVERT); + node = newnode; + + entry = cursor->level[this_level].index = 0; + } + /* + * ditto for block numbers + */ + if (cursor->level[p_level].bno != INT_GET(node->btree[entry].before, ARCH_CONVERT)) { + return(1); + } + /* + * ok, now validate last hashvalue in the descendant + * block against the hashval in the current entry + */ + if (cursor->level[p_level].hashval != INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) { + if (!no_modify) { + do_warn("correcting bad hashval in interior dir " + "block\n"); + do_warn("\tin (level %d) in inode %llu.\n", + this_level, cursor->ino); + INT_SET(node->btree[entry].hashval, ARCH_CONVERT, cursor->level[p_level].hashval); + cursor->level[this_level].dirty++; + } else { + do_warn("would correct bad hashval in interior dir " + "block\n"); + do_warn("\tin (level %d) in inode %llu.\n", + this_level, cursor->ino); + } + } + /* + * increment index for this level to point to next entry + * (which should point to the next descendant block) + */ + cursor->level[this_level].index++; + return(0); +} + +/* + * Fix up a shortform directory which was in long form (i8count set) + * and is now in short form (i8count clear). + * Return pointer to the end of the data when done. + */ +void +process_sf_dir2_fixi8( + xfs_dir2_sf_t *sfp, + xfs_dir2_sf_entry_t **next_sfep) +{ + xfs_ino_t ino; + xfs_dir2_sf_t *newsfp; + xfs_dir2_sf_entry_t *newsfep; + xfs_dir2_sf_t *oldsfp; + xfs_dir2_sf_entry_t *oldsfep; + int oldsize; + + newsfp = sfp; + oldsize = (__psint_t)*next_sfep - (__psint_t)sfp; + oldsfp = malloc(oldsize); + if (oldsfp == NULL) { + do_error("couldn't malloc dir2 shortform copy\n"); + exit(1); + } + memmove(oldsfp, newsfp, oldsize); + INT_SET(newsfp->hdr.count, ARCH_CONVERT, INT_GET(oldsfp->hdr.count, ARCH_CONVERT)); + newsfp->hdr.i8count = 0; + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, &oldsfp->hdr.parent, ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(newsfp, &ino, &newsfp->hdr.parent, ARCH_CONVERT); + oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp); + newsfep = XFS_DIR2_SF_FIRSTENTRY(newsfp); + while ((int)((char *)oldsfep - (char *)oldsfp) < oldsize) { + newsfep->namelen = oldsfep->namelen; + XFS_DIR2_SF_PUT_OFFSET_ARCH(newsfep, + XFS_DIR2_SF_GET_OFFSET_ARCH(oldsfep, ARCH_CONVERT), ARCH_CONVERT); + memmove(newsfep->name, oldsfep->name, newsfep->namelen); + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, + XFS_DIR2_SF_INUMBERP(oldsfep), ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(newsfp, &ino, + XFS_DIR2_SF_INUMBERP(newsfep), ARCH_CONVERT); + oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep); + newsfep = XFS_DIR2_SF_NEXTENTRY(newsfp, newsfep); + } + *next_sfep = newsfep; + free(oldsfp); +} + +/* + * Regenerate legal (minimal) offsets for the shortform directory. + */ +static void +process_sf_dir2_fixoff( + xfs_dinode_t *dip) +{ + int i; + int offset; + xfs_dir2_sf_entry_t *sfep; + xfs_dir2_sf_t *sfp; + + for (i = 0, sfp = &dip->di_u.di_dir2sf, + sfep = XFS_DIR2_SF_FIRSTENTRY(sfp), + offset = XFS_DIR2_DATA_FIRST_OFFSET; + i < INT_GET(sfp->hdr.count, ARCH_CONVERT); + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) { + XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, offset, ARCH_CONVERT); + offset += XFS_DIR2_DATA_ENTSIZE(sfep->namelen); + } +} + +/* + * this routine performs inode discovery and tries to fix things + * in place. available redundancy -- inode data size should match + * used directory space in inode. + * a non-zero return value means the directory is bogus and should be blasted. + */ +/* ARGSUSED */ +static int +process_sf_dir2( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + int ino_discovery, + int *dino_dirty, /* out - 1 if dinode buffer dirty */ + char *dirname, /* directory pathname */ + xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */ + int *repair) /* out - 1 if dir was fixed up */ +{ + int bad_offset; + int bad_sfnamelen; + int i; + int i8; + __int64_t ino_dir_size; + int ino_off; + ino_tree_node_t *irec_p; + int junkit; + char *junkreason = NULL; + xfs_ino_t lino; + int max_size; + char name[MAXNAMELEN + 1]; + int namelen; + xfs_dir2_sf_entry_t *next_sfep; + int num_entries; + int offset; + xfs_dir2_sf_t *sfp; + xfs_dir2_sf_entry_t *sfep; + int tmp_elen; + int tmp_len; + xfs_dir2_sf_entry_t *tmp_sfep; + xfs_ino_t zero = 0; + + sfp = &dip->di_u.di_dir2sf; + max_size = XFS_DFORK_DSIZE_ARCH(dip, mp, ARCH_CONVERT); + num_entries = INT_GET(sfp->hdr.count, ARCH_CONVERT); + ino_dir_size = INT_GET(dip->di_core.di_size, ARCH_CONVERT); + offset = XFS_DIR2_DATA_FIRST_OFFSET; + i8 = bad_offset = *repair = 0; + + ASSERT(ino_dir_size <= max_size); + + /* + * check for bad entry count + */ + if (num_entries * XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, 1) + + XFS_DIR2_SF_HDR_SIZE(0) > max_size || + num_entries == 0) + num_entries = 0xFF; + + /* + * run through entries, stop at first bad entry, don't need + * to check for .. since that's encoded in its own field + */ + sfep = next_sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + for (i = 0; + i < num_entries && ino_dir_size > (char *)next_sfep - (char *)sfp; + i++) { + tmp_sfep = NULL; + sfep = next_sfep; + junkit = 0; + bad_sfnamelen = 0; + lino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + /* + * if entry points to self, junk it since only '.' or '..' + * should do that and shortform dirs don't contain either + * entry. if inode number is invalid, trash entry. + * if entry points to special inodes, trash it. + * if inode is unknown but number is valid, + * add it to the list of uncertain inodes. don't + * have to worry about an entry pointing to a + * deleted lost+found inode because the entry was + * deleted at the same time that the inode was cleared. + */ + if (lino == ino) { + junkit = 1; + junkreason = "current"; + } else if (verify_inum(mp, lino)) { + junkit = 1; + junkreason = "invalid"; + } else if (lino == mp->m_sb.sb_rbmino) { + junkit = 1; + junkreason = "realtime bitmap"; + } else if (lino == mp->m_sb.sb_rsumino) { + junkit = 1; + junkreason = "realtime summary"; + } else if (lino == mp->m_sb.sb_uquotino) { + junkit = 1; + junkreason = "user quota"; + } else if (lino == mp->m_sb.sb_gquotino) { + junkit = 1; + junkreason = "group quota"; + } else if ((irec_p = find_inode_rec(XFS_INO_TO_AGNO(mp, lino), + XFS_INO_TO_AGINO(mp, lino))) != NULL) { + /* + * if inode is marked free and we're in inode + * discovery mode, leave the entry alone for now. + * if the inode turns out to be used, we'll figure + * that out when we scan it. If the inode really + * is free, we'll hit this code again in phase 4 + * after we've finished inode discovery and blow + * out the entry then. + */ + ino_off = XFS_INO_TO_AGINO(mp, lino) - + irec_p->ino_startnum; + ASSERT(is_inode_confirmed(irec_p, ino_off)); + if (is_inode_free(irec_p, ino_off) && !ino_discovery) { + junkit = 1; + junkreason = "free"; + } + } else if (ino_discovery) { + /* + * put the inode on the uncertain list. we'll + * pull the inode off the list and check it later. + * if the inode turns out be bogus, we'll delete + * this entry in phase 6. + */ + add_inode_uncertain(mp, lino, 0); + } else { + /* + * blow the entry out. we know about all + * undiscovered entries now (past inode discovery + * phase) so this is clearly a bogus entry. + */ + junkit = 1; + junkreason = "non-existent"; + } + namelen = sfep->namelen; + if (junkit) + do_warn("entry \"%*.*s\" in shortform directory %llu " + "references %s inode %llu\n", + namelen, namelen, sfep->name, ino, junkreason, + lino); + if (namelen == 0) { + /* + * if we're really lucky, this is + * the last entry in which case we + * can use the dir size to set the + * namelen value. otherwise, forget + * it because we're not going to be + * able to find the next entry. + */ + bad_sfnamelen = 1; + + if (i == num_entries - 1) { + namelen = ino_dir_size - + ((__psint_t) &sfep->name[0] - + (__psint_t) sfp); + if (!no_modify) { + do_warn("zero length entry in " + "shortform dir %llu, resetting " + "to %d\n", + ino, namelen); + sfep->namelen = namelen; + } else { + do_warn("zero length entry in " + "shortform dir %llu, would set " + "to %d\n", + ino, namelen); + } + } else { + do_warn("zero length entry in shortform dir " + "%llu", + ino); + if (!no_modify) + do_warn(", junking %d entries\n", + num_entries - i); + else + do_warn(", would junk %d entries\n", + num_entries - i); + /* + * don't process the rest of the directory, + * break out of processing looop + */ + break; + } + } else if ((__psint_t) sfep - (__psint_t) sfp + + + XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep) + > ino_dir_size) { + bad_sfnamelen = 1; + + if (i == num_entries - 1) { + namelen = ino_dir_size - + ((__psint_t) &sfep->name[0] - + (__psint_t) sfp); + do_warn("size of last entry overflows space " + "left in in shortform dir %llu, ", + ino); + if (!no_modify) { + do_warn("resetting to %d\n", + namelen); + sfep->namelen = namelen; + *dino_dirty = 1; + } else { + do_warn("would reset to %d\n", + namelen); + } + } else { + do_warn("size of entry #%d overflows space " + "left in in shortform dir %llu\n", + i, ino); + if (!no_modify) { + if (i == num_entries - 1) + do_warn("junking entry #%d\n", + i); + else + do_warn("junking %d entries\n", + num_entries - i); + } else { + if (i == num_entries - 1) + do_warn("would junk entry " + "#%d\n", + i); + else + do_warn("would junk %d " + "entries\n", + num_entries - i); + } + + break; + } + } + + /* + * check for illegal chars in name. + * no need to check for bad length because + * the length value is stored in a byte + * so it can't be too big, it can only wrap + */ + if (namecheck((char *)&sfep->name[0], namelen)) { + /* + * junk entry + */ + do_warn("entry contains illegal character in shortform " + "dir %llu\n", + ino); + junkit = 1; + } + + if (XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) < offset) { + do_warn("entry contains offset out of order in " + "shortform dir %llu\n", + ino); + bad_offset = 1; + } + offset = XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) + + XFS_DIR2_DATA_ENTSIZE(namelen); + + /* + * junk the entry by copying up the rest of the + * fork over the current entry and decrementing + * the entry count. if we're in no_modify mode, + * just issue the warning instead. then continue + * the loop with the next_sfep pointer set to the + * correct place in the fork and other counters + * properly set to reflect the deletion if it + * happened. + */ + if (junkit) { + bcopy(sfep->name, name, namelen); + name[namelen] = '\0'; + + if (!no_modify) { + tmp_elen = + XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep); + INT_MOD(dip->di_core.di_size, ARCH_CONVERT, -(tmp_elen)); + ino_dir_size -= tmp_elen; + + tmp_sfep = (xfs_dir2_sf_entry_t *) + ((__psint_t) sfep + tmp_elen); + tmp_len = max_size - ((__psint_t) tmp_sfep + - (__psint_t) sfp); + + memmove(sfep, tmp_sfep, tmp_len); + + INT_MOD(sfp->hdr.count, ARCH_CONVERT, -1); + num_entries--; + bzero((void *) ((__psint_t) sfep + tmp_len), + tmp_elen); + + /* + * reset the tmp value to the current + * pointer so we'll process the entry + * we just moved up + */ + tmp_sfep = sfep; + + /* + * WARNING: drop the index i by one + * so it matches the decremented count + * for accurate comparisons later + */ + i--; + + *dino_dirty = 1; + *repair = 1; + + do_warn("junking entry \"%s\" in directory " + "inode %llu\n", + name, ino); + } else { + do_warn("would have junked entry \"%s\" in " + "directory inode %llu\n", + name, ino); + } + } else if (lino > XFS_DIR2_MAX_SHORT_INUM) + i8++; + /* + * go onto next entry unless we've just junked an + * entry in which the current entry pointer points + * to an unprocessed entry. have to take into zero-len + * entries into account in no modify mode since we + * calculate size based on next_sfep. + */ + next_sfep = (tmp_sfep == NULL) + ? (xfs_dir2_sf_entry_t *) ((__psint_t) sfep + + ((!bad_sfnamelen) + ? XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, + sfep) + : XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, + namelen))) + : tmp_sfep; + } + + /* sync up sizes and entry counts */ + + if (INT_GET(sfp->hdr.count, ARCH_CONVERT) != i) { + if (no_modify) { + do_warn("would have corrected entry count in directory " + "%llu from %d to %d\n", + ino, INT_GET(sfp->hdr.count, ARCH_CONVERT), i); + } else { + do_warn("corrected entry count in directory %llu, was " + "%d, now %d\n", + ino, INT_GET(sfp->hdr.count, ARCH_CONVERT), i); + INT_SET(sfp->hdr.count, ARCH_CONVERT, i); + *dino_dirty = 1; + *repair = 1; + } + } + + if (sfp->hdr.i8count != i8) { + if (no_modify) { + do_warn("would have corrected i8 count in directory " + "%llu from %d to %d\n", + ino, sfp->hdr.i8count, i8); + } else { + do_warn("corrected i8 count in directory %llu, was %d, " + "now %d\n", + ino, sfp->hdr.i8count, i8); + if (i8 == 0) + process_sf_dir2_fixi8(sfp, &next_sfep); + else + sfp->hdr.i8count = i8; + *dino_dirty = 1; + *repair = 1; + } + } + + if ((__psint_t) next_sfep - (__psint_t) sfp != ino_dir_size) { + if (no_modify) { + do_warn("would have corrected directory %llu size from " + "%lld to %lld\n", + ino, (__int64_t) ino_dir_size, + (__int64_t)((__psint_t)next_sfep - + (__psint_t)sfp)); + } else { + do_warn("corrected directory %llu size, was %lld, now " + "%lld\n", + ino, (__int64_t) ino_dir_size, + (__int64_t)((__psint_t)next_sfep - + (__psint_t)sfp)); + + INT_SET(dip->di_core.di_size, ARCH_CONVERT, (xfs_fsize_t)((__psint_t)next_sfep - + (__psint_t)sfp)); + *dino_dirty = 1; + *repair = 1; + } + } + if (offset + (INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2) * sizeof(xfs_dir2_leaf_entry_t) + + sizeof(xfs_dir2_block_tail_t) > mp->m_dirblksize) { + do_warn("directory %llu offsets too high\n", ino); + bad_offset = 1; + } + if (bad_offset) { + if (no_modify) { + do_warn("would have corrected entry offsets in " + "directory %llu\n", + ino); + } else { + do_warn("corrected entry offsets in directory %llu\n", + ino); + process_sf_dir2_fixoff(dip); + *dino_dirty = 1; + *repair = 1; + } + } + + /* + * check parent (..) entry + */ + *parent = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT); + + /* + * if parent entry is bogus, null it out. we'll fix it later . + */ + if (verify_inum(mp, *parent)) { + + do_warn("bogus .. inode number (%llu) in directory inode " + "%llu, ", + *parent, ino); + *parent = NULLFSINO; + if (!no_modify) { + do_warn("clearing inode number\n"); + + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &zero, &sfp->hdr.parent, ARCH_CONVERT); + *dino_dirty = 1; + *repair = 1; + } else { + do_warn("would clear inode number\n"); + } + } else if (ino == mp->m_sb.sb_rootino && ino != *parent) { + /* + * root directories must have .. == . + */ + if (!no_modify) { + do_warn("corrected root directory %llu .. entry, was " + "%llu, now %llu\n", + ino, *parent, ino); + *parent = ino; + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, parent, &sfp->hdr.parent, ARCH_CONVERT); + *dino_dirty = 1; + *repair = 1; + } else { + do_warn("would have corrected root directory %llu .. " + "entry from %llu to %llu\n", + ino, *parent, ino); + } + } else if (ino == *parent && ino != mp->m_sb.sb_rootino) { + /* + * likewise, non-root directories can't have .. pointing + * to . + */ + *parent = NULLFSINO; + do_warn("bad .. entry in directory inode %llu, points to " + "self,", + ino); + if (!no_modify) { + do_warn(" clearing inode number\n"); + + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &zero, &sfp->hdr.parent, ARCH_CONVERT); + *dino_dirty = 1; + *repair = 1; + } else { + do_warn(" would clear inode number\n"); + } + } + + return(0); +} + +/* + * Process one directory data block. + */ +/* ARGSUSED */ +static int +process_dir2_data( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + int ino_discovery, + char *dirname, /* directory pathname */ + xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */ + xfs_dabuf_t *bp, + int *dot, /* out - 1 if there is a dot, else 0 */ + int *dotdot, /* out - 1 if there's a dotdot, else 0 */ + xfs_dablk_t da_bno, + char *endptr) +{ + int badbest; + xfs_dir2_data_free_t *bf; + int clearino; + char *clearreason = NULL; + xfs_dir2_data_t *d; + xfs_dir2_data_entry_t *dep; + xfs_dir2_data_free_t *dfp; + xfs_dir2_data_unused_t *dup; + int freeseen; + int i; + int ino_off; + ino_tree_node_t *irec_p; + int junkit; + int lastfree; + int nm_illegal; + char *ptr; + + d = bp->data; + bf = d->hdr.bestfree; + ptr = (char *)d->u; + badbest = lastfree = freeseen = 0; + if (INT_GET(bf[0].length, ARCH_CONVERT) == 0) { + badbest |= INT_GET(bf[0].offset, ARCH_CONVERT) != 0; + freeseen |= 1 << 0; + } + if (INT_GET(bf[1].length, ARCH_CONVERT) == 0) { + badbest |= INT_GET(bf[1].offset, ARCH_CONVERT) != 0; + freeseen |= 1 << 1; + } + if (INT_GET(bf[2].length, ARCH_CONVERT) == 0) { + badbest |= INT_GET(bf[2].offset, ARCH_CONVERT) != 0; + freeseen |= 1 << 2; + } + badbest |= INT_GET(bf[0].length, ARCH_CONVERT) < INT_GET(bf[1].length, ARCH_CONVERT); + badbest |= INT_GET(bf[1].length, ARCH_CONVERT) < INT_GET(bf[2].length, ARCH_CONVERT); + while (ptr < endptr) { + dup = (xfs_dir2_data_unused_t *)ptr; + /* + * If it's unused, look for the space in the bestfree table. + * If we find it, account for that, else make sure it doesn't + * need to be there. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + if (ptr + INT_GET(dup->length, ARCH_CONVERT) > endptr || INT_GET(dup->length, ARCH_CONVERT) == 0 || + (INT_GET(dup->length, ARCH_CONVERT) & (XFS_DIR2_DATA_ALIGN - 1))) + break; + if (INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT) != + (char *)dup - (char *)d) + break; + badbest |= lastfree != 0; + dfp = xfs_dir2_data_freefind(d, dup); + if (dfp) { + i = dfp - bf; + badbest |= (freeseen & (1 << i)) != 0; + freeseen |= 1 << i; + } else + badbest |= INT_GET(dup->length, ARCH_CONVERT) > INT_GET(bf[2].length, ARCH_CONVERT); + ptr += INT_GET(dup->length, ARCH_CONVERT); + lastfree = 1; + continue; + } + dep = (xfs_dir2_data_entry_t *)ptr; + if (ptr + XFS_DIR2_DATA_ENTSIZE(dep->namelen) > endptr) + break; + if (INT_GET(*XFS_DIR2_DATA_ENTRY_TAG_P(dep), ARCH_CONVERT) != (char *)dep - (char *)d) + break; + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + lastfree = 0; + } + /* + * Dropped out before we processed everything, give up. + * Phase 6 will kill this block if we don't kill the inode. + */ + if (ptr != endptr) { + do_warn("corrupt block %u in directory inode %llu\n", + da_bno, ino); + if (!no_modify) + do_warn("\twill junk block\n"); + else + do_warn("\twould junk block\n"); + return 1; + } + ptr = (char *)d->u; + /* + * Process the entries now. + */ + while (ptr < endptr) { + dup = (xfs_dir2_data_unused_t *)ptr; + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + ptr += INT_GET(dup->length, ARCH_CONVERT); + continue; + } + dep = (xfs_dir2_data_entry_t *)ptr; + /* + * We may have to blow out an entry because of bad inode + * numbers. Do NOT touch the name until after we've computed + * the hashvalue and done a namecheck() on the name. + */ + if (!ino_discovery && INT_GET(dep->inumber, ARCH_CONVERT) == BADFSINO) { + /* + * Don't do a damned thing. We already found this + * (or did it ourselves) during phase 3. + */ + clearino = 0; + } else if (verify_inum(mp, INT_GET(dep->inumber, ARCH_CONVERT))) { + /* + * Bad inode number. Clear the inode number and the + * entry will get removed later. We don't trash the + * directory since it's still structurally intact. + */ + clearino = 1; + clearreason = "invalid"; + } else if (INT_GET(dep->inumber, ARCH_CONVERT) == mp->m_sb.sb_rbmino) { + clearino = 1; + clearreason = "realtime bitmap"; + } else if (INT_GET(dep->inumber, ARCH_CONVERT) == mp->m_sb.sb_rsumino) { + clearino = 1; + clearreason = "realtime summary"; + } else if (INT_GET(dep->inumber, ARCH_CONVERT) == mp->m_sb.sb_uquotino) { + clearino = 1; + clearreason = "user quota"; + } else if (INT_GET(dep->inumber, ARCH_CONVERT) == mp->m_sb.sb_gquotino) { + clearino = 1; + clearreason = "group quota"; + } else if (INT_GET(dep->inumber, ARCH_CONVERT) == old_orphanage_ino) { + /* + * Do nothing, silently ignore it, entry has already + * been marked TBD since old_orphanage_ino is set + * non-zero. + */ + clearino = 0; + } else if ((irec_p = find_inode_rec( + XFS_INO_TO_AGNO(mp, INT_GET(dep->inumber, ARCH_CONVERT)), + XFS_INO_TO_AGINO(mp, INT_GET(dep->inumber, ARCH_CONVERT)))) != NULL) { + /* + * Inode recs should have only confirmed inodes in them. + */ + ino_off = + XFS_INO_TO_AGINO(mp, INT_GET(dep->inumber, ARCH_CONVERT)) - + irec_p->ino_startnum; + ASSERT(is_inode_confirmed(irec_p, ino_off)); + /* + * If inode is marked free and we're in inode discovery + * mode, leave the entry alone for now. If the inode + * turns out to be used, we'll figure that out when we + * scan it. If the inode really is free, we'll hit this + * code again in phase 4 after we've finished inode + * discovery and blow out the entry then. + */ + if (!ino_discovery && is_inode_free(irec_p, ino_off)) { + clearino = 1; + clearreason = "free"; + } else + clearino = 0; + } else if (ino_discovery) { + add_inode_uncertain(mp, INT_GET(dep->inumber, ARCH_CONVERT), 0); + clearino = 0; + } else { + clearino = 1; + clearreason = "non-existent"; + } + if (clearino) + do_warn("entry \"%*.*s\" at block %u offset %d in " + "directory inode %llu references %s inode " + "%llu\n", + dep->namelen, dep->namelen, dep->name, + da_bno, (char *)ptr - (char *)d, ino, + clearreason, INT_GET(dep->inumber, ARCH_CONVERT)); + /* + * If the name length is 0 (illegal) make it 1 and blast + * the entry. + */ + if (dep->namelen == 0) { + do_warn("entry at block %u offset %d in directory " + "inode %llu has 0 namelength\n", + da_bno, (char *)ptr - (char *)d, ino); + if (!no_modify) + dep->namelen = 1; + clearino = 1; + } + /* + * If needed to clear the inode number, do it now. + */ + if (clearino) { + if (!no_modify) { + do_warn("\tclearing inode number in entry at " + "offset %d...\n", + (char *)ptr - (char *)d); + INT_SET(dep->inumber, ARCH_CONVERT, BADFSINO); + bp->dirty = 1; + } else { + do_warn("\twould clear inode number in entry " + "at offset %d...\n", + (char *)ptr - (char *)d); + } + } + /* + * Only complain about illegal names in phase 3 (when inode + * discovery is turned on). Otherwise, we'd complain a lot + * during phase 4. + */ + junkit = INT_GET(dep->inumber, ARCH_CONVERT) == BADFSINO; + nm_illegal = namecheck((char *)dep->name, dep->namelen); + if (ino_discovery && nm_illegal) { + do_warn("entry at block %u offset %d in directory " + "inode %llu has illegal name \"%*.*s\": ", + da_bno, (char *)ptr - (char *)d, ino, + dep->namelen, dep->namelen, dep->name); + junkit = 1; + } + /* + * Now we can mark entries with BADFSINO's bad. + */ + if (!no_modify && INT_GET(dep->inumber, ARCH_CONVERT) == BADFSINO) { + dep->name[0] = '/'; + bp->dirty = 1; + junkit = 0; + } + /* + * Special .. entry processing. + */ + if (dep->namelen == 2 && + dep->name[0] == '.' && dep->name[1] == '.') { + if (!*dotdot) { + (*dotdot)++; + *parent = INT_GET(dep->inumber, ARCH_CONVERT); + /* + * What if .. == .? Legal only in the root + * inode. Blow out entry and set parent to + * NULLFSINO otherwise. + */ + if (ino == INT_GET(dep->inumber, ARCH_CONVERT) && + ino != mp->m_sb.sb_rootino) { + *parent = NULLFSINO; + do_warn("bad .. entry in directory " + "inode %llu, points to self: ", + ino); + junkit = 1; + } + /* + * We have to make sure that . == .. in the + * root inode. + */ + else if (ino != INT_GET(dep->inumber, ARCH_CONVERT) && + ino == mp->m_sb.sb_rootino) { + do_warn("bad .. entry in root " + "directory inode %llu, was " + "%llu: ", + ino, INT_GET(dep->inumber, ARCH_CONVERT)); + if (!no_modify) { + do_warn("correcting\n"); + INT_SET(dep->inumber, ARCH_CONVERT, ino); + bp->dirty = 1; + } else { + do_warn("would correct\n"); + } + } + } + /* + * Can't fix the directory unless we know which .. + * entry is the right one. Both have valid inode + * numbers or we wouldn't be here. So since both + * seem equally valid, trash this one. + */ + else { + do_warn("multiple .. entries in directory " + "inode %llu: ", + ino); + junkit = 1; + } + } + /* + * Special . entry processing. + */ + else if (dep->namelen == 1 && dep->name[0] == '.') { + if (!*dot) { + (*dot)++; + if (INT_GET(dep->inumber, ARCH_CONVERT) != ino) { + do_warn("bad . entry in directory " + "inode %llu, was %llu: ", + ino, INT_GET(dep->inumber, ARCH_CONVERT)); + if (!no_modify) { + do_warn("correcting\n"); + INT_SET(dep->inumber, ARCH_CONVERT, ino); + bp->dirty = 1; + } else { + do_warn("would correct\n"); + } + } + } else { + do_warn("multiple . entries in directory " + "inode %llu: ", + ino); + junkit = 1; + } + } + /* + * All other entries -- make sure only . references self. + */ + else if (INT_GET(dep->inumber, ARCH_CONVERT) == ino) { + do_warn("entry \"%*.*s\" in directory inode %llu " + "points to self: ", + dep->namelen, dep->namelen, dep->name, ino); + junkit = 1; + } + /* + * Clear junked entries. + */ + if (junkit) { + if (!no_modify) { + dep->name[0] = '/'; + bp->dirty = 1; + do_warn("clearing entry\n"); + } else { + do_warn("would clear entry\n"); + } + } + /* + * Advance to the next entry. + */ + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + /* + * Check the bestfree table. + */ + if (freeseen != 7 || badbest) { + do_warn("bad bestfree table in block %u in directory inode " + "%llu: ", + da_bno, ino); + if (!no_modify) { + do_warn("repairing table\n"); + libxfs_dir2_data_freescan(mp, d, &i, endptr); + bp->dirty = 1; + } else { + do_warn("would repair table\n"); + } + } + return 0; +} + +/* + * Process a block-format directory. + */ +/* ARGSUSED */ +static int +process_block_dir2( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + int ino_discovery, + int *dino_dirty, /* out - 1 if dinode buffer dirty */ + char *dirname, /* directory pathname */ + xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */ + blkmap_t *blkmap, + int *dot, /* out - 1 if there is a dot, else 0 */ + int *dotdot, /* out - 1 if there's a dotdot, else 0 */ + int *repair) /* out - 1 if something was fixed */ +{ + xfs_dir2_block_t *block; + xfs_dir2_leaf_entry_t *blp; + bmap_ext_t *bmp; + xfs_dabuf_t *bp; + xfs_dir2_block_tail_t *btp; + int nex; + int rval; + + *repair = *dot = *dotdot = 0; + *parent = NULLFSINO; + nex = blkmap_getn(blkmap, mp->m_dirdatablk, mp->m_dirblkfsbs, &bmp); + if (nex == 0) { + do_warn("block %u for directory inode %llu is missing\n", + mp->m_dirdatablk, ino); + return 1; + } + bp = da_read_buf(mp, nex, bmp); + free(bmp); + if (bp == NULL) { + do_warn("can't read block %u for directory inode %llu\n", + mp->m_dirdatablk, ino); + return 1; + } + /* + * Verify the block + */ + block = bp->data; + if (INT_GET(block->hdr.magic, ARCH_CONVERT) != XFS_DIR2_BLOCK_MAGIC) + do_warn("bad directory block magic # %#x in block %u for " + "directory inode %llu\n", + INT_GET(block->hdr.magic, ARCH_CONVERT), mp->m_dirdatablk, ino); + /* + * process the data area + * this also checks & fixes the bestfree + */ + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Don't let this go past the end of the block. + */ + if ((char *)blp > (char *)btp) + blp = (xfs_dir2_leaf_entry_t *)btp; + rval = process_dir2_data(mp, ino, dip, ino_discovery, dirname, parent, + bp, dot, dotdot, mp->m_dirdatablk, (char *)blp); + if (bp->dirty && !no_modify) { + *repair = 1; + da_bwrite(mp, bp); + } else + da_brelse(bp); + return rval; +} + +/* + * Validates leaf contents, node format directories only. + * magic number and sibling pointers checked by caller. + * Returns 0 if block is ok, 1 if the block is bad. + * Looking for: out of order hash values, bad stale counts. + */ +static int +process_leaf_block_dir2( + xfs_mount_t *mp, + xfs_dir2_leaf_t *leaf, + xfs_dablk_t da_bno, + xfs_ino_t ino, + xfs_dahash_t last_hashval, + xfs_dahash_t *next_hashval) +{ + int i; + int stale; + + for (i = stale = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); i++) { + if ((char *)&leaf->ents[i] >= (char *)leaf + mp->m_dirblksize) { + do_warn("bad entry count in block %u of directory " + "inode %llu\n", + da_bno, ino); + return 1; + } + if (INT_GET(leaf->ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + stale++; + else if (INT_GET(leaf->ents[i].hashval, ARCH_CONVERT) < last_hashval) { + do_warn("bad hash ordering in block %u of directory " + "inode %llu\n", + da_bno, ino); + return 1; + } + *next_hashval = last_hashval = INT_GET(leaf->ents[i].hashval, ARCH_CONVERT); + } + if (stale != INT_GET(leaf->hdr.stale, ARCH_CONVERT)) { + do_warn("bad stale count in block %u of directory inode %llu\n", + da_bno, ino); + return 1; + } + return 0; +} + +/* + * Returns 0 if the directory is ok, 1 if it has to be rebuilt. + */ +static int +process_leaf_level_dir2( + xfs_mount_t *mp, + dir2_bt_cursor_t *da_cursor, + int *repair) +{ + bmap_ext_t *bmp; + xfs_dabuf_t *bp; + int buf_dirty; + xfs_dahash_t current_hashval; + xfs_dablk_t da_bno; + xfs_dahash_t greatest_hashval; + xfs_ino_t ino; + xfs_dir2_leaf_t *leaf; + int nex; + xfs_dablk_t prev_bno; + + da_bno = da_cursor->level[0].bno; + ino = da_cursor->ino; + prev_bno = 0; + bmp = NULL; + current_hashval = 0; + buf_dirty = 0; + + do { + nex = blkmap_getn(da_cursor->blkmap, da_bno, mp->m_dirblkfsbs, + &bmp); + /* + * Directory code uses 0 as the NULL block pointer since 0 + * is the root block and no directory block pointer can point + * to the root block of the btree. + */ + ASSERT(da_bno != 0); + + if (nex == 0) { + do_warn("can't map block %u for directory inode %llu\n", + da_bno, ino); + goto error_out; + } + bp = da_read_buf(mp, nex, bmp); + free(bmp); + bmp = NULL; + if (bp == NULL) { + do_warn("can't read file block %u for directory inode " + "%llu\n", + da_bno, ino); + goto error_out; + } + leaf = bp->data; + /* + * Check magic number for leaf directory btree block. + */ + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR2_LEAFN_MAGIC) { + do_warn("bad directory leaf magic # %#x for directory " + "inode %llu block %u\n", + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), ino, da_bno); + da_brelse(bp); + goto error_out; + } + buf_dirty = 0; + /* + * For each block, process the block, verify its path, + * then get next block. Update cursor values along the way. + */ + if (process_leaf_block_dir2(mp, leaf, da_bno, ino, + current_hashval, &greatest_hashval)) { + da_brelse(bp); + goto error_out; + } + /* + * Index can be set to hdr.count so match the indices of the + * interior blocks -- which at the end of the block will point + * to 1 after the final real entry in the block. + */ + da_cursor->level[0].hashval = greatest_hashval; + da_cursor->level[0].bp = bp; + da_cursor->level[0].bno = da_bno; + da_cursor->level[0].index = INT_GET(leaf->hdr.count, ARCH_CONVERT); + da_cursor->level[0].dirty = buf_dirty; + + if (INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != prev_bno) { + do_warn("bad sibling back pointer for block %u in " + "directory inode %llu\n", + da_bno, ino); + da_brelse(bp); + goto error_out; + } + prev_bno = da_bno; + da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT); + if (da_bno != 0) { + if (verify_dir2_path(mp, da_cursor, 0)) { + da_brelse(bp); + goto error_out; + } + } + current_hashval = greatest_hashval; + ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify)); + if (buf_dirty && !no_modify) { + *repair = 1; + da_bwrite(mp, bp); + } else + da_brelse(bp); + } while (da_bno != 0); + if (verify_final_dir2_path(mp, da_cursor, 0)) { + /* + * Verify the final path up (right-hand-side) if still ok. + */ + do_warn("bad hash path in directory %llu\n", ino); + goto error_out; + } + /* + * Redundant but just for testing. + */ + release_dir2_cursor(mp, da_cursor, 0); + return 0; + +error_out: + /* + * Release all buffers holding interior btree blocks. + */ + err_release_dir2_cursor(mp, da_cursor, 0); + if (bmp) + free(bmp); + return 1; +} + +/* + * Return 1 if the directory's leaf/node space is corrupted and + * needs to be rebuilt, 0 if it's ok. + */ +static int +process_node_dir2( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + blkmap_t *blkmap, + int *repair) +{ + xfs_dablk_t bno; + dir2_bt_cursor_t da_cursor; + + /* + * Try again -- traverse down left-side of tree until we hit the + * left-most leaf block setting up the btree cursor along the way. + * Then walk the leaf blocks left-to-right, calling a parent + * verification routine each time we traverse a block. + */ + bzero(&da_cursor, sizeof(da_cursor)); + da_cursor.ino = ino; + da_cursor.dip = dip; + da_cursor.blkmap = blkmap; + + /* + * Now process interior node. + */ + if (traverse_int_dir2block(mp, &da_cursor, &bno) == 0) + return 1; + + /* + * Skip directories with a root marked XFS_DIR2_LEAFN_MAGIC + */ + if (bno == 0) { + release_dir2_cursor(mp, &da_cursor, 0); + return 0; + } else { + /* + * Now pass cursor and bno into leaf-block processing routine. + * The leaf dir level routine checks the interior paths up to + * the root including the final right-most path. + */ + return process_leaf_level_dir2(mp, &da_cursor, repair); + } +} + +/* + * Process leaf and node directories. + * Process the data blocks then, if it's a node directory, check + * the consistency of those blocks. + */ +static int +process_leaf_node_dir2( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + int ino_discovery, + char *dirname, /* directory pathname */ + xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */ + blkmap_t *blkmap, + int *dot, /* out - 1 if there is a dot, else 0 */ + int *dotdot, /* out - 1 if there's a dotdot, else 0 */ + int *repair, /* out - 1 if something was fixed */ + int isnode) /* node directory not leaf */ +{ + bmap_ext_t *bmp; + xfs_dabuf_t *bp; + xfs_dir2_data_t *data; + xfs_dfiloff_t dbno; + int good; + int i; + xfs_dfiloff_t ndbno; + int nex; + int t; + + *repair = *dot = *dotdot = good = 0; + *parent = NULLFSINO; + ndbno = NULLDFILOFF; + while ((dbno = blkmap_next_off(blkmap, ndbno, &t)) < mp->m_dirleafblk) { + nex = blkmap_getn(blkmap, dbno, mp->m_dirblkfsbs, &bmp); + ndbno = dbno + mp->m_dirblkfsbs - 1; + if (nex == 0) { + do_warn("block %llu for directory inode %llu is " + "missing\n", + dbno, ino); + continue; + } + bp = da_read_buf(mp, nex, bmp); + free(bmp); + if (bp == NULL) { + do_warn("can't read block %llu for directory inode " + "%llu\n", + dbno, ino); + continue; + } + data = bp->data; + if (INT_GET(data->hdr.magic, ARCH_CONVERT) != XFS_DIR2_DATA_MAGIC) + do_warn("bad directory block magic # %#x in block %llu " + "for directory inode %llu\n", + INT_GET(data->hdr.magic, ARCH_CONVERT), dbno, ino); + i = process_dir2_data(mp, ino, dip, ino_discovery, dirname, + parent, bp, dot, dotdot, (xfs_dablk_t)dbno, + (char *)data + mp->m_dirblksize); + if (i == 0) + good++; + if (bp->dirty && !no_modify) { + *repair = 1; + da_bwrite(mp, bp); + } else + da_brelse(bp); + } + if (good == 0) + return 1; + if (!isnode) + return 0; + if (dir2_is_badino(ino)) + return 0; + + if (process_node_dir2(mp, ino, dip, blkmap, repair)) + dir2_add_badlist(ino); + return 0; + +} + +/* + * Returns 1 if things are bad (directory needs to be junked) + * and 0 if things are ok. If ino_discovery is 1, add unknown + * inodes to uncertain inode list. + */ +int +process_dir2( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + int ino_discovery, + int *dino_dirty, + char *dirname, + xfs_ino_t *parent, + blkmap_t *blkmap) +{ + int dot; + int dotdot; + xfs_dfiloff_t last; + int repair; + int res; + + *parent = NULLFSINO; + dot = dotdot = 0; + last = 0; + + /* + * branch off depending on the type of inode. This routine + * is only called ONCE so all the subordinate routines will + * fix '.' and junk '..' if they're bogus. + */ + if (blkmap) + last = blkmap_last_off(blkmap); + if (INT_GET(dip->di_core.di_size, ARCH_CONVERT) <= XFS_DFORK_DSIZE_ARCH(dip, mp, ARCH_CONVERT) && + dip->di_core.di_format == XFS_DINODE_FMT_LOCAL) { + dot = dotdot = 1; + res = process_sf_dir2(mp, ino, dip, ino_discovery, dino_dirty, + dirname, parent, &repair); + } else if (last == mp->m_dirblkfsbs && + (dip->di_core.di_format == XFS_DINODE_FMT_EXTENTS || + dip->di_core.di_format == XFS_DINODE_FMT_BTREE)) { + res = process_block_dir2(mp, ino, dip, ino_discovery, + dino_dirty, dirname, parent, blkmap, &dot, &dotdot, + &repair); + } else if (last >= mp->m_dirleafblk + mp->m_dirblkfsbs && + (dip->di_core.di_format == XFS_DINODE_FMT_EXTENTS || + dip->di_core.di_format == XFS_DINODE_FMT_BTREE)) { + res = process_leaf_node_dir2(mp, ino, dip, ino_discovery, + dirname, parent, blkmap, &dot, &dotdot, &repair, + last > mp->m_dirleafblk + mp->m_dirblkfsbs); + } else { + do_warn("bad size/format for directory %llu\n", ino); + return 1; + } + /* + * bad . entries in all directories will be fixed up in phase 6 + */ + if (dot == 0) { + do_warn("no . entry for directory %llu\n", ino); + } + + /* + * shortform dirs always have a .. entry. .. for all longform + * directories will get fixed in phase 6. .. for other shortform + * dirs also get fixed there. .. for a shortform root was + * fixed in place since we know what it should be + */ + if (dotdot == 0 && ino != mp->m_sb.sb_rootino) { + do_warn("no .. entry for directory %llu\n", ino); + } else if (dotdot == 0 && ino == mp->m_sb.sb_rootino) { + do_warn("no .. entry for root directory %llu\n", ino); + need_root_dotdot = 1; + } + + ASSERT((ino != mp->m_sb.sb_rootino && ino != *parent) || + (ino == mp->m_sb.sb_rootino && + (ino == *parent || need_root_dotdot == 1))); + + return res; +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/dir2.h linux-2.4-xfs/cmd/xfsprogs/repair/dir2.h --- linux-2.4.7/cmd/xfsprogs/repair/dir2.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/dir2.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef _XR_DIR2_H +#define _XR_DIR2_H + +struct blkmap; +struct bmap_ext; + +/* + * the cursor gets passed up and down the da btree processing + * routines. The interior block processing routines use the + * cursor to determine if the pointers to and from the preceding + * and succeeding sibling blocks are ok and whether the values in + * the current block are consistent with the entries in the parent + * nodes. When a block is traversed, a parent-verification routine + * is called to verify if the next logical entry in the next level up + * is consistent with the greatest hashval in the next block of the + * current level. The verification routine is itself recursive and + * calls itself if it has to traverse an interior block to get + * the next logical entry. The routine recurses upwards through + * the tree until it finds a block where it can simply step to + * the next entry. The hashval in that entry should be equal to + * the hashval being passed to it (the greatest hashval in the block + * that the entry points to). If that isn't true, then the tree + * is blown and we need to trash it, salvage and trash it, or fix it. + * Currently, we just trash it. + */ +typedef struct dir2_level_state { + xfs_dabuf_t *bp; /* block bp */ + xfs_dablk_t bno; /* file block number */ + xfs_dahash_t hashval; /* last verified hashval */ + int index; /* current index in block */ + int dirty; /* is buffer dirty ? (1 == yes) */ +} dir2_level_state_t; + +typedef struct dir2_bt_cursor { + int active; /* highest level in tree (# levels-1) */ + int type; /* 0 if dir, 1 if attr */ + xfs_ino_t ino; + xfs_dablk_t greatest_bno; + xfs_dinode_t *dip; + dir2_level_state_t level[XFS_DA_NODE_MAXDEPTH]; + struct blkmap *blkmap; +} dir2_bt_cursor_t; + + +/* ROUTINES */ + +void +err_release_dir2_cursor( + xfs_mount_t *mp, + dir2_bt_cursor_t *cursor, + int prev_level); + +xfs_dabuf_t * +da_read_buf( + xfs_mount_t *mp, + int nex, + struct bmap_ext *bmp); + +int +da_bwrite( + xfs_mount_t *mp, + xfs_dabuf_t *bp); + +void +da_brelse( + xfs_dabuf_t *bp); + +int +process_dir2( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dip, + int ino_discovery, + int *dirty, + char *dirname, + xfs_ino_t *parent, + struct blkmap *blkmap); + +void +process_sf_dir2_fixi8( + xfs_dir2_sf_t *sfp, + xfs_dir2_sf_entry_t **next_sfep); + +void +dir2_add_badlist( + xfs_ino_t ino); + +int +dir2_is_badino( + xfs_ino_t ino); + +#endif /* _XR_DIR2_H */ diff -rNu linux-2.4.7/cmd/xfsprogs/repair/dir_stack.c linux-2.4-xfs/cmd/xfsprogs/repair/dir_stack.c --- linux-2.4.7/cmd/xfsprogs/repair/dir_stack.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/dir_stack.c Thu Apr 12 18:49:04 2001 @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "dir_stack.h" +#include "err_protos.h" + +/* + * a directory stack for holding directories while + * we traverse filesystem hierarchy subtrees. + * names are kind of misleading as this is really + * implemented as an inode stack. so sue me... + */ + +static dir_stack_t dirstack_freelist; +static int dirstack_init = 0; + +void +dir_stack_init(dir_stack_t *stack) +{ + stack->cnt = 0; + stack->head = NULL; + + if (dirstack_init == 0) { + dirstack_init = 1; + dir_stack_init(&dirstack_freelist); + } + + stack->cnt = 0; + stack->head = NULL; + + return; +} + +static void +dir_stack_push(dir_stack_t *stack, dir_stack_elem_t *elem) +{ + ASSERT(stack->cnt > 0 || (stack->cnt == 0 && stack->head == NULL)); + + elem->next = stack->head; + stack->head = elem; + stack->cnt++; + + return; +} + +static dir_stack_elem_t * +dir_stack_pop(dir_stack_t *stack) +{ + dir_stack_elem_t *elem; + + if (stack->cnt == 0) { + ASSERT(stack->head == NULL); + return(NULL); + } + + elem = stack->head; + + ASSERT(elem != NULL); + + stack->head = elem->next; + elem->next = NULL; + stack->cnt--; + + return(elem); +} + +void +push_dir(dir_stack_t *stack, xfs_ino_t ino) +{ + dir_stack_elem_t *elem; + + if (dirstack_freelist.cnt == 0) { + if ((elem = malloc(sizeof(dir_stack_elem_t))) == NULL) { + do_error( + "couldn't malloc dir stack element, try more swap\n"); + exit(1); + } + } else { + elem = dir_stack_pop(&dirstack_freelist); + } + + elem->ino = ino; + + dir_stack_push(stack, elem); + + return; +} + +xfs_ino_t +pop_dir(dir_stack_t *stack) +{ + dir_stack_elem_t *elem; + xfs_ino_t ino; + + elem = dir_stack_pop(stack); + + if (elem == NULL) + return(NULLFSINO); + + ino = elem->ino; + elem->ino = NULLFSINO; + + dir_stack_push(&dirstack_freelist, elem); + + return(ino); +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/dir_stack.h linux-2.4-xfs/cmd/xfsprogs/repair/dir_stack.h --- linux-2.4.7/cmd/xfsprogs/repair/dir_stack.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/dir_stack.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +typedef struct dir_stack_elem { + xfs_ino_t ino; + struct dir_stack_elem *next; +} dir_stack_elem_t; + +typedef struct dir_stack { + int cnt; + dir_stack_elem_t *head; +} dir_stack_t; + + +void dir_stack_init(dir_stack_t *stack); + +void push_dir(dir_stack_t *stack, xfs_ino_t ino); +xfs_ino_t pop_dir(dir_stack_t *stack); diff -rNu linux-2.4.7/cmd/xfsprogs/repair/err_protos.h linux-2.4-xfs/cmd/xfsprogs/repair/err_protos.h --- linux-2.4.7/cmd/xfsprogs/repair/err_protos.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/err_protos.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +void do_abort(char const *, ...); /* abort, internal error */ +void do_error(char const *, ...); /* abort, system error */ +void do_warn(char const *, ...); /* issue warning */ +void do_log(char const *, ...); /* issue log message */ diff -rNu linux-2.4.7/cmd/xfsprogs/repair/globals.c linux-2.4-xfs/cmd/xfsprogs/repair/globals.c --- linux-2.4.7/cmd/xfsprogs/repair/globals.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/globals.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#define EXTERN +#include "globals.h" + diff -rNu linux-2.4.7/cmd/xfsprogs/repair/globals.h linux-2.4-xfs/cmd/xfsprogs/repair/globals.h --- linux-2.4.7/cmd/xfsprogs/repair/globals.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/globals.h Mon Apr 2 21:52:38 2001 @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef _XFS_REPAIR_GLOBAL_H +#define _XFS_REPAIR_GLOBAL_H + +#ifndef EXTERN +#define EXTERN extern +#endif + +/* useful macros */ + +#define rounddown(x, y) (((x)/(y))*(y)) + +/* error flags */ + +#define XR_OK 0 /* good */ +#define XR_BAD_MAGIC 1 /* bad magic number */ +#define XR_BAD_BLOCKSIZE 2 /* bad block size */ +#define XR_BAD_BLOCKLOG 3 /* bad sb_blocklog field */ +#define XR_BAD_VERSION 4 /* bad version number */ +#define XR_BAD_INPROGRESS 5 /* in progress set */ +#define XR_BAD_FS_SIZE_DATA 6 /* ag sizes, number, fs size mismatch */ +#define XR_BAD_INO_SIZE_DATA 7 /* bad inode size or perblock fields */ +#define XR_BAD_SECT_SIZE_DATA 8 /* bad sector size info */ +#define XR_AGF_GEO_MISMATCH 9 /* agf info conflicts with sb */ +#define XR_AGI_GEO_MISMATCH 10 /* agf info conflicts with sb */ +#define XR_SB_GEO_MISMATCH 11 /* sb geo conflicts with fs sb geo */ +#define XR_EOF 12 /* seeked beyond EOF */ +#define XR_BAD_RT_GEO_DATA 13 /* realtime geometry inconsistent */ +#define XR_BAD_INO_MAX_PCT 14 /* max % of inodes > 100% */ +#define XR_BAD_INO_ALIGN 15 /* bad inode alignment value */ +#define XR_INSUFF_SEC_SB 16 /* not enough matching secondary sbs */ +#define XR_BAD_SB_UNIT 17 /* bad stripe unit */ +#define XR_BAD_SB_WIDTH 18 /* bad stripe width */ +#define XR_BAD_SVN 19 /* bad shared version number */ +#define XR_BAD_ERR_CODE 20 /* Bad error code */ + +/* XFS filesystem (il)legal values */ + +#define XR_LOG2BSIZE_MIN 9 /* min/max fs blocksize (log2) */ +#define XR_LOG2BSIZE_MAX 16 /* 2^XR_* == blocksize */ + +#define NUM_SBS 8 /* max # of sbs to verify */ +#define NUM_AGH_SECTS 4 /* # of components in an ag header */ + +#define MEM_ALIGN 128 /* I/O buf alignment - a cache line */ + +/* + * secondary sb mask -- if the secondary sb feature bits has a + * the partial sb mask bit set, then you depend on the fields + * in it up to and including sb_inoalignmt but the unused part of the + * sector may have trash in it. If the sb has any bits set that are in + * the good mask, then the entire sb and sector are good (was bzero'ed + * by mkfs). The third mask is for filesystems made by pre-6.5 campus + * alpha mkfs's. Those are rare so we'll check for those under + * a special option. + */ +#define XR_PART_SECSB_VNMASK 0x0F80 /* >= XFS_SB_VERSION_ALIGNBIT */ +#define XR_GOOD_SECSB_VNMASK 0x0F00 /* >= XFS_SB_VERSION_DALIGNBIT */ +#define XR_ALPHA_SECSB_VNMASK 0x0180 /* DALIGN|ALIGN bits */ + +/* global variables for xfs_repair */ + +/* arguments and argument flag variables */ + +EXTERN char *fs_name; /* name of filesystem */ +EXTERN int verbose; /* verbose flag, mostly for debugging */ + + +/* for reading stuff in manually (bypassing libsim) */ + +EXTERN char *iobuf; /* large buffer */ +EXTERN int iobuf_size; +EXTERN char *smallbuf; /* small (1-4 page) buffer */ +EXTERN int smallbuf_size; +EXTERN char *sb_bufs[NUM_SBS]; /* superblock buffers */ +EXTERN int sbbuf_size; + +/* direct I/O info */ + +EXTERN int minio_align; /* min I/O size and alignment */ +EXTERN int mem_align; /* memory alignment */ +EXTERN int max_iosize; /* max I/O size */ + +/* file descriptors */ + +EXTERN int fs_fd; /* filesystem fd */ + +/* command-line flags */ + +EXTERN int verbose; +EXTERN int no_modify; +EXTERN int isa_file; +EXTERN int dumpcore; /* abort, not exit on fatal errs */ +EXTERN int delete_attr_ok; /* can clear attrs w/o clearing files */ +EXTERN int force_geo; /* can set geo on low confidence info */ +EXTERN int assume_xfs; /* assume we have an xfs fs */ +EXTERN int pre_65_beta; /* fs was mkfs'ed by a version earlier * than 6.5-beta */ +EXTERN char *log_name; /* Name of log device */ +EXTERN int log_spec; /* Log dev specified as option */ + +/* misc status variables */ + +EXTERN int primary_sb_modified; +EXTERN int bad_ino_btree; +EXTERN int clear_sunit; +EXTERN int fs_is_dirty; + +/* for hunting down the root inode */ + +EXTERN int need_root_inode; +EXTERN int need_root_dotdot; + +EXTERN int need_rbmino; +EXTERN int need_rsumino; + +EXTERN int lost_quotas; +EXTERN int have_uquotino; +EXTERN int have_gquotino; +EXTERN int lost_uquotino; +EXTERN int lost_gquotino; + +EXTERN xfs_agino_t first_prealloc_ino; +EXTERN xfs_agino_t last_prealloc_ino; +EXTERN xfs_agblock_t bnobt_root; +EXTERN xfs_agblock_t bcntbt_root; +EXTERN xfs_agblock_t inobt_root; + +/* configuration vars -- fs geometry dependent */ + +EXTERN int inodes_per_block; +EXTERN int inodes_per_cluster; /* inodes per inode buffer */ +EXTERN unsigned int glob_agcount; +EXTERN int chunks_pblock; /* # of 64-ino chunks per allocation */ +EXTERN int max_symlink_blocks; +EXTERN __int64_t fs_max_file_offset; + +/* block allocation bitmaps */ + +EXTERN __uint64_t **ba_bmap; /* see incore.h */ +EXTERN __uint64_t *rt_ba_bmap; /* see incore.h */ + +/* realtime info */ + +EXTERN xfs_rtword_t *btmcompute; +EXTERN xfs_suminfo_t *sumcompute; + +/* inode tree records have full or partial backptr fields ? */ + +EXTERN int full_backptrs; /* + * if 1, use backptrs_t component + * of ino_un union, if 0, use + * parent_list_t component. see + * incore.h for more details + */ + +#define ORPHANAGE "lost+found" + +/* superblock counters */ + +EXTERN __uint64_t sb_icount; /* allocated (made) inodes */ +EXTERN __uint64_t sb_ifree; /* free inodes */ +EXTERN __uint64_t sb_fdblocks; /* free data blocks */ +EXTERN __uint64_t sb_frextents; /* free realtime extents */ + +EXTERN xfs_ino_t orphanage_ino; +EXTERN xfs_ino_t old_orphanage_ino; + +/* superblock geometry info */ + +EXTERN xfs_extlen_t sb_inoalignmt; +EXTERN __uint32_t sb_unit; +EXTERN __uint32_t sb_width; + +#endif /* _XFS_REPAIR_GLOBAL_H */ diff -rNu linux-2.4.7/cmd/xfsprogs/repair/incore.c linux-2.4-xfs/cmd/xfsprogs/repair/incore.c --- linux-2.4.7/cmd/xfsprogs/repair/incore.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/incore.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "avl.h" +#include "globals.h" +#include "incore.h" +#include "agheader.h" +#include "protos.h" +#include "err_protos.h" + +/* + * push a block allocation record onto list. assumes list + * if set to NULL if empty. + */ +void +record_allocation(ba_rec_t *addr, ba_rec_t *list) +{ + addr->next = list; + list = addr; + + return; +} + +void +free_allocations(ba_rec_t *list) +{ + ba_rec_t *current = list; + + while (list != NULL) { + list = list->next; + free(current); + current = list; + } + + return; +} + +/* ba bmap setupstuff. setting/getting state is in incore.h */ + +void +setup_bmap(xfs_agnumber_t agno, xfs_agblock_t numblocks, xfs_drtbno_t rtblocks) +{ + int i; + xfs_drfsbno_t size; + + ba_bmap = (__uint64_t**)malloc(agno*sizeof(__uint64_t *)); + if (!ba_bmap) { + do_error("couldn't allocate block map pointers\n"); + return; + } + for (i = 0; i < agno; i++) { + int size; + + size = roundup(numblocks * (NBBY/XR_BB),sizeof(__uint64_t)); + + ba_bmap[i] = (__uint64_t*)memalign(sizeof(__uint64_t), size); + if (!ba_bmap[i]) { + do_error("couldn't allocate block map, size = %d\n", + numblocks); + return; + } + bzero(ba_bmap[i], size); + } + + if (rtblocks == 0) { + rt_ba_bmap = NULL; + return; + } + + size = roundup(rtblocks * (NBBY/XR_BB), sizeof(__uint64_t)); + + rt_ba_bmap=(__uint64_t*)memalign(sizeof(__uint64_t), size); + if (!rt_ba_bmap) { + do_error( + "couldn't allocate real-time block map, size = %llu\n", + rtblocks); + return; + } + + /* + * start all real-time as free blocks + */ + set_bmap_rt(rtblocks); + + return; +} + +/* ARGSUSED */ +void +teardown_rt_bmap(xfs_mount_t *mp) +{ + if (rt_ba_bmap != NULL) { + free(rt_ba_bmap); + rt_ba_bmap = NULL; + } + + return; +} + +/* ARGSUSED */ +void +teardown_ag_bmap(xfs_mount_t *mp, xfs_agnumber_t agno) +{ + ASSERT(ba_bmap[agno] != NULL); + + free(ba_bmap[agno]); + ba_bmap[agno] = NULL; + + return; +} + +/* ARGSUSED */ +void +teardown_bmap_finish(xfs_mount_t *mp) +{ + free(ba_bmap); + ba_bmap = NULL; + + return; +} + +void +teardown_bmap(xfs_mount_t *mp) +{ + xfs_agnumber_t i; + + for (i = 0; i < mp->m_sb.sb_agcount; i++) { + teardown_ag_bmap(mp, i); + } + + teardown_rt_bmap(mp); + teardown_bmap_finish(mp); + + return; +} + +/* + * block map initialization routines -- realtime, log, fs + */ +void +set_bmap_rt(xfs_drtbno_t num) +{ + xfs_drtbno_t j; + xfs_drtbno_t size; + + /* + * for now, initialize all realtime blocks to be free + * (state == XR_E_FREE) + */ + size = howmany(num * (NBBY/XR_BB), sizeof(__uint64_t)); + + for (j = 0; j < size; j++) + rt_ba_bmap[j] = 0x2222222222222222LL; + + return; +} + +void +set_bmap_log(xfs_mount_t *mp) +{ + xfs_dfsbno_t logend, i; + + if (mp->m_sb.sb_logstart == 0) + return; + + logend = mp->m_sb.sb_logstart + mp->m_sb.sb_logblocks; + + for (i = mp->m_sb.sb_logstart; i < logend ; i++) { + set_fsbno_state(mp, i, XR_E_INUSE_FS); + } + + return; +} + +void +set_bmap_fs(xfs_mount_t *mp) +{ + xfs_agnumber_t i; + xfs_agblock_t j; + xfs_agblock_t end; + + /* + * AG header is 4 sectors + */ + end = howmany(4 * mp->m_sb.sb_sectsize, mp->m_sb.sb_blocksize); + + for (i = 0; i < mp->m_sb.sb_agcount; i++) + for (j = 0; j < end; j++) + set_agbno_state(mp, i, j, XR_E_INUSE_FS); + + return; +} + +#if 0 +void +set_bmap_fs_bt(xfs_mount_t *mp) +{ + xfs_agnumber_t i; + xfs_agblock_t j; + xfs_agblock_t begin; + xfs_agblock_t end; + + begin = bnobt_root; + end = inobt_root + 1; + + for (i = 0; i < mp->m_sb.sb_agcount; i++) { + /* + * account for btree roots + */ + for (j = begin; j < end; j++) + set_agbno_state(mp, i, j, XR_E_INUSE_FS); + } + + return; +} +#endif + +void +incore_init(xfs_mount_t *mp) +{ + int agcount = mp->m_sb.sb_agcount; + extern void incore_ino_init(xfs_mount_t *); + extern void incore_ext_init(xfs_mount_t *); + + /* init block alloc bmap */ + + setup_bmap(agcount, mp->m_sb.sb_agblocks, mp->m_sb.sb_rextents); + incore_ino_init(mp); + incore_ext_init(mp); + + /* initialize random globals now that we know the fs geometry */ + + inodes_per_block = mp->m_sb.sb_inopblock; + + return; +} + +#if defined(XR_BMAP_TRACE) || defined(XR_BMAP_DBG) +int +get_agbno_state(xfs_mount_t *mp, xfs_agnumber_t agno, + xfs_agblock_t ag_blockno) +{ + __uint64_t *addr; + + addr = ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM; + + return((*addr >> (((ag_blockno)%XR_BB_NUM)*XR_BB)) & XR_BB_MASK); +} + +void set_agbno_state(xfs_mount_t *mp, xfs_agnumber_t agno, + xfs_agblock_t ag_blockno, int state) +{ + __uint64_t *addr; + + addr = ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM; + + *addr = (((*addr) & + (~((__uint64_t) XR_BB_MASK << (((ag_blockno)%XR_BB_NUM)*XR_BB)))) | + (((__uint64_t) (state)) << (((ag_blockno)%XR_BB_NUM)*XR_BB))); +} + +int +get_fsbno_state(xfs_mount_t *mp, xfs_dfsbno_t blockno) +{ + return(get_agbno_state(mp, XFS_FSB_TO_AGNO(mp, blockno), + XFS_FSB_TO_AGBNO(mp, blockno))); +} + +void +set_fsbno_state(xfs_mount_t *mp, xfs_dfsbno_t blockno, int state) +{ + set_agbno_state(mp, XFS_FSB_TO_AGNO(mp, blockno), + XFS_FSB_TO_AGBNO(mp, blockno), state); + + return; +} +#endif diff -rNu linux-2.4.7/cmd/xfsprogs/repair/incore.h linux-2.4-xfs/cmd/xfsprogs/repair/incore.h --- linux-2.4.7/cmd/xfsprogs/repair/incore.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/incore.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,564 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * contains definition information. implementation (code) + * is spread out in separate files. + */ + +/* + * block allocation lists + */ +typedef struct ba_rec { + void *addr; + struct ba_rec *next; +} ba_rec_t; + +void record_allocation(ba_rec_t *addr, ba_rec_t *list); +void free_allocations(ba_rec_t *list); + +/* + * block bit map defs -- track state of each filesystem block. + * ba_bmap is an array of bitstrings declared in the globals.h file. + * the bitstrings are broken up into 64-bit chunks. one bitstring per AG. + */ +#define BA_BMAP_SIZE(x) (howmany(x, 4)) + +void set_bmap_rt(xfs_drfsbno_t numblocks); +void set_bmap_log(xfs_mount_t *mp); +void set_bmap_fs(xfs_mount_t *mp); +void teardown_bmap(xfs_mount_t *mp); + +void teardown_rt_bmap(xfs_mount_t *mp); +void teardown_ag_bmap(xfs_mount_t *mp, xfs_agnumber_t agno); +void teardown_bmap_finish(xfs_mount_t *mp); + +/* blocks are numbered from zero */ + +/* block records fit into __uint64_t's units */ + +#define XR_BB_UNIT 64 /* number of bits/unit */ +#define XR_BB 4 /* bits per block record */ +#define XR_BB_NUM (XR_BB_UNIT/XR_BB) /* number of records per unit */ +#define XR_BB_MASK 0xF /* block record mask */ + +/* + * bitstring ops -- set/get block states, either in filesystem + * bno's or in agbno's. turns out that fsbno addressing is + * more convenient when dealing with bmap extracted addresses + * and agbno addressing is more convenient when dealing with + * meta-data extracted addresses. So the fsbno versions use + * mtype (which can be one of the block map types above) to + * set the correct block map while the agbno versions assume + * you want to use the regular block map. + */ + +#if defined(XR_BMAP_TRACE) || defined(XR_BMAP_DBG) +/* + * implemented as functions for debugging purposes + */ +int get_agbno_state(xfs_mount_t *mp, xfs_agnumber_t agno, + xfs_agblock_t ag_blockno); +void set_agbno_state(xfs_mount_t *mp, xfs_agnumber_t agno, + xfs_agblock_t ag_blockno, int state); + +int get_fsbno_state(xfs_mount_t *mp, xfs_dfsbno_t blockno); +void set_fsbno_state(xfs_mount_t *mp, xfs_dfsbno_t blockno, int state); +#else +/* + * implemented as macros for performance purposes + */ + +#define get_agbno_state(mp, agno, ag_blockno) \ + ((int) (*(ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM) \ + >> (((ag_blockno)%XR_BB_NUM)*XR_BB)) \ + & XR_BB_MASK) +#define set_agbno_state(mp, agno, ag_blockno, state) \ + *(ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM) = \ + ((*(ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM) & \ + (~((__uint64_t) XR_BB_MASK << (((ag_blockno)%XR_BB_NUM)*XR_BB)))) | \ + (((__uint64_t) (state)) << (((ag_blockno)%XR_BB_NUM)*XR_BB))) + +#define get_fsbno_state(mp, blockno) \ + get_agbno_state(mp, XFS_FSB_TO_AGNO(mp, (blockno)), \ + XFS_FSB_TO_AGBNO(mp, (blockno))) +#define set_fsbno_state(mp, blockno, state) \ + set_agbno_state(mp, XFS_FSB_TO_AGNO(mp, (blockno)), \ + XFS_FSB_TO_AGBNO(mp, (blockno)), (state)) + + +#define get_agbno_rec(mp, agno, ag_blockno) \ + (*(ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM)) +#endif /* XR_BMAP_TRACE */ + +/* + * these work in real-time extents (e.g. fsbno == rt extent number) + */ +#define get_rtbno_state(mp, fsbno) \ + ((*(rt_ba_bmap + (fsbno)/XR_BB_NUM) >> \ + (((fsbno)%XR_BB_NUM)*XR_BB)) & XR_BB_MASK) +#define set_rtbno_state(mp, fsbno, state) \ + *(rt_ba_bmap + (fsbno)/XR_BB_NUM) = \ + ((*(rt_ba_bmap + (fsbno)/XR_BB_NUM) & \ + (~((__uint64_t) XR_BB_MASK << (((fsbno)%XR_BB_NUM)*XR_BB)))) | \ + (((__uint64_t) (state)) << (((fsbno)%XR_BB_NUM)*XR_BB))) + + +/* + * extent tree definitions + * right now, there are 3 trees per AG, a bno tree, a bcnt tree + * and a tree for dup extents. If the code is modified in the + * future to use an extent tree instead of a bitmask for tracking + * fs blocks, then we could lose the dup extent tree if we labelled + * each extent with the inode that owned it. + */ + +typedef unsigned char extent_state_t; + +typedef struct extent_tree_node { + avlnode_t avl_node; + xfs_agblock_t ex_startblock; /* starting block (agbno) */ + xfs_extlen_t ex_blockcount; /* number of blocks in extent */ + extent_state_t ex_state; /* see state flags below */ + + struct extent_tree_node *next; /* for bcnt extent lists */ +#if 0 + xfs_ino_t ex_inode; /* owner, NULL if free or */ + /* multiply allocated */ +#endif +} extent_tree_node_t; + +typedef struct rt_extent_tree_node { + avlnode_t avl_node; + xfs_drtbno_t rt_startblock; /* starting realtime block */ + xfs_extlen_t rt_blockcount; /* number of blocks in extent */ + extent_state_t rt_state; /* see state flags below */ + +#if 0 + xfs_ino_t ex_inode; /* owner, NULL if free or */ + /* multiply allocated */ +#endif +} rt_extent_tree_node_t; + +/* extent states, prefix with XR_ to avoid conflict with buffer cache defines */ + +#define XR_E_UNKNOWN 0 /* unknown state */ +#define XR_E_FREE1 1 /* free block (marked by one fs space tree) */ +#define XR_E_FREE 2 /* free block (marked by both fs space trees) */ +#define XR_E_INUSE 3 /* extent used by file/dir data or metadata */ +#define XR_E_INUSE_FS 4 /* extent used by fs ag header or log */ +#define XR_E_MULT 5 /* extent is multiply referenced */ +#define XR_E_INO 6 /* extent used by inodes (inode blocks) */ +#define XR_E_FS_MAP 7 /* extent used by fs space/inode maps */ +#define XR_E_BAD_STATE 8 + +/* separate state bit, OR'ed into high (4th) bit of ex_state field */ + +#define XR_E_WRITTEN 0x8 /* extent has been written out, can't reclaim */ +#define good_state(state) (((state) & (~XR_E_WRITTEN)) >= XR_E_UNKNOWN && \ + ((state) & (~XR_E_WRITTEN) < XF_E_BAD_STATE)) +#define written(state) ((state) & XR_E_WRITTEN) +#define set_written(state) (state) &= XR_E_WRITTEN + +/* + * bno extent tree functions + */ +void +add_bno_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, + xfs_extlen_t blockcount); + +extent_tree_node_t * +findfirst_bno_extent(xfs_agnumber_t agno); + +extent_tree_node_t * +find_bno_extent(xfs_agnumber_t agno, xfs_agblock_t agbno); + +extent_tree_node_t * +findfirst_bno_extent(xfs_agnumber_t agno); + +#define findnext_bno_extent(exent_ptr) \ + ((extent_tree_node_t *) ((exent_ptr)->avl_node.avl_nextino)) + +void +get_bno_extent(xfs_agnumber_t agno, extent_tree_node_t *ext); + +/* + * bcnt tree functions + */ +void +add_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, + xfs_extlen_t blockcount); + +extent_tree_node_t * +findfirst_bcnt_extent(xfs_agnumber_t agno); + +extent_tree_node_t * +find_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t agbno); + +extent_tree_node_t * +findbiggest_bcnt_extent(xfs_agnumber_t agno); + +extent_tree_node_t * +findnext_bcnt_extent(xfs_agnumber_t agno, extent_tree_node_t *ext); + +extent_tree_node_t * +get_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, + xfs_extlen_t blockcount); + +/* + * duplicate extent tree functions + */ +void add_dup_extent(xfs_agnumber_t agno, + xfs_agblock_t startblock, + xfs_extlen_t blockcount); + +int search_dup_extent(xfs_mount_t *mp, + xfs_agnumber_t agno, + xfs_agblock_t agbno); + +void add_rt_dup_extent(xfs_drtbno_t startblock, + xfs_extlen_t blockcount); + +int search_rt_dup_extent(xfs_mount_t *mp, + xfs_drtbno_t bno); + +/* + * extent/tree recyling and deletion routines + */ + +/* + * return an extent node to the extent node free list + */ +void release_extent_tree_node(extent_tree_node_t *node); + +/* + * recycle all the nodes in the per-AG tree + */ +void release_dup_extent_tree(xfs_agnumber_t agno); +void release_agbno_extent_tree(xfs_agnumber_t agno); +void release_agbcnt_extent_tree(xfs_agnumber_t agno); + +/* + * realtime duplicate extent tree - this one actually frees the memory + */ +void free_rt_dup_extent_tree(xfs_mount_t *mp); + +/* + * per-AG extent trees shutdown routine -- all (bno, bcnt and dup) + * at once. this one actually frees the memory instead of just recyling + * the nodes. + */ +void incore_ext_teardown(xfs_mount_t *mp); + +/* + * inode definitions + */ + +/* inode types */ + +#define XR_INO_UNKNOWN 0 /* unknown */ +#define XR_INO_DIR 1 /* directory */ +#define XR_INO_RTDATA 2 /* realtime file */ +#define XR_INO_RTBITMAP 3 /* realtime bitmap inode */ +#define XR_INO_RTSUM 4 /* realtime summary inode */ +#define XR_INO_DATA 5 /* regular file */ +#define XR_INO_SYMLINK 6 /* symlink */ +#define XR_INO_CHRDEV 7 /* character device */ +#define XR_INO_BLKDEV 8 /* block device */ +#define XR_INO_SOCK 9 /* socket */ +#define XR_INO_FIFO 10 /* fifo */ +#define XR_INO_MOUNTPOINT 11 /* mountpoint */ + +/* inode allocation tree */ + +/* + * Inodes in the inode allocation trees are allocated in chunks. + * Those groups can be easily duplicated in our trees. + * Disconnected inodes are harder. We can do one of two + * things in that case: if we know the inode allocation btrees + * are good, then we can disallow directory references to unknown + * inode chunks. If the inode allocation trees have been trashed or + * we feel like being aggressive, then as we hit unknown inodes, + * we can search on the disk for all contiguous inodes and see if + * they fit into chunks. Before putting them into the inode tree, + * we can scan each inode starting at the earliest inode to see which + * ones are good. This protects us from the pathalogical case of + * inodes appearing in user-data. We still may have to mark the + * inodes as "possibly fake" so that if a file claims the blocks, + * we decide to believe the inodes, especially if they're not + * connected. + */ + +#define PLIST_CHUNK_SIZE 4 + +typedef xfs_ino_t parent_entry_t; + +typedef struct parent_list { + __uint64_t pmask; + parent_entry_t *pentries; +#ifdef DEBUG + short cnt; +#endif +} parent_list_t; + +typedef struct backptrs { + __uint64_t ino_reached; /* bit == 1 if reached */ + __uint64_t ino_processed; /* reference checked bit mask */ + __uint32_t nlinks[XFS_INODES_PER_CHUNK]; + parent_list_t *parents; +} backptrs_t; + +typedef struct ino_tree_node { + avlnode_t avl_node; + xfs_agino_t ino_startnum; /* starting inode # */ + xfs_inofree_t ir_free; /* inode free bit mask */ + __uint64_t ino_confirmed; /* confirmed bitmask */ + __uint64_t ino_isa_dir; /* bit == 1 if a directory */ + union { + backptrs_t *backptrs; + parent_list_t *plist; + } ino_un; +} ino_tree_node_t; + +#define INOS_PER_IREC (sizeof(__uint64_t) * NBBY) +void add_ino_backptrs(xfs_mount_t *mp); + +/* + * return an inode record to the free inode record pool + */ +void free_inode_rec(xfs_agnumber_t agno, ino_tree_node_t *ino_rec); + +/* + * get pulls the inode record from the good inode tree + */ +void get_inode_rec(xfs_agnumber_t agno, ino_tree_node_t *ino_rec); + +ino_tree_node_t *findfirst_inode_rec(xfs_agnumber_t agno); +ino_tree_node_t *find_inode_rec(xfs_agnumber_t agno, xfs_agino_t ino); +void find_inode_rec_range(xfs_agnumber_t agno, + xfs_agino_t start_ino, xfs_agino_t end_ino, + ino_tree_node_t **first, ino_tree_node_t **last); + +/* + * set inode states -- setting an inode to used or free also + * automatically marks it as "existing". Note -- all the inode + * add/set/get routines assume a valid inode number. + */ +ino_tree_node_t *set_inode_used_alloc(xfs_agnumber_t agno, xfs_agino_t ino); +ino_tree_node_t *set_inode_free_alloc(xfs_agnumber_t agno, xfs_agino_t ino); + +void print_inode_list(xfs_agnumber_t agno); +void print_uncertain_inode_list(xfs_agnumber_t agno); + +/* + * separate trees for uncertain inodes (they may not exist). + */ +ino_tree_node_t *findfirst_uncertain_inode_rec(xfs_agnumber_t agno); +void add_inode_uncertain(xfs_mount_t *mp, + xfs_ino_t ino, int free); +void add_aginode_uncertain(xfs_agnumber_t agno, + xfs_agino_t agino, int free); +void get_uncertain_inode_rec(xfs_agnumber_t agno, + ino_tree_node_t *ino_rec); +void clear_uncertain_ino_cache(xfs_agnumber_t agno); + +/* + * return next in-order inode tree node. takes an "ino_tree_node_t *" + */ +#define next_ino_rec(ino_node_ptr) \ + ((ino_tree_node_t *) ((ino_node_ptr)->avl_node.avl_nextino)) +/* + * return the next linked inode (forward avl tree link)-- meant to be used + * by linked list routines (uncertain inode routines/records) + */ +#define next_link_rec(ino_node_ptr) \ + ((ino_tree_node_t *) ((ino_node_ptr)->avl_node.avl_forw)) + +/* + * Bit manipulations for processed field + */ +#define XFS_INOPROC_MASK(i) ((__uint64_t)1 << (i)) +#define XFS_INOPROC_MASKN(i,n) ((__uint64_t)((1 << (n)) - 1) << (i)) + +#define XFS_INOPROC_IS_PROC(rp, i) \ + (((rp)->ino_un.backptrs->ino_processed & XFS_INOPROC_MASK((i))) == 0LL \ + ? 0 : 1) +#define XFS_INOPROC_SET_PROC(rp, i) \ + ((rp)->ino_un.backptrs->ino_processed |= XFS_INOPROC_MASK((i))) +/* +#define XFS_INOPROC_CLR_PROC(rp, i) \ + ((rp)->ino_un.backptrs->ino_processed &= ~XFS_INOPROC_MASK((i))) +*/ + +/* + * same for ir_confirmed. + */ +#define XFS_INOCF_MASK(i) ((__uint64_t)1 << (i)) +#define XFS_INOCF_MASKN(i,n) ((__uint64_t)((1 << (n)) - 1) << (i)) + +#define XFS_INOCF_IS_CF(rp, i) \ + (((rp)->ino_confirmed & XFS_INOCF_MASK((i))) == 0LL \ + ? 0 : 1) +#define XFS_INOCF_SET_CF(rp, i) \ + ((rp)->ino_confirmed |= XFS_INOCF_MASK((i))) +#define XFS_INOCF_CLR_CF(rp, i) \ + ((rp)->ino_confirmed &= ~XFS_INOCF_MASK((i))) + +/* + * same for backptr->ino_reached + */ +#define XFS_INO_RCHD_MASK(i) ((__uint64_t)1 << (i)) + +#define XFS_INO_RCHD_IS_RCHD(rp, i) \ + (((rp)->ino_un.backptrs->ino_reached & XFS_INO_RCHD_MASK((i))) == 0LL \ + ? 0 : 1) +#define XFS_INO_RCHD_SET_RCHD(rp, i) \ + ((rp)->ino_un.backptrs->ino_reached |= XFS_INO_RCHD_MASK((i))) +#define XFS_INO_RCHD_CLR_RCHD(rp, i) \ + ((rp)->ino_un.backptrs->ino_reached &= ~XFS_INO_RCHD_MASK((i))) +/* + * set/clear/test is inode a directory inode + */ +#define XFS_INO_ISADIR_MASK(i) ((__uint64_t)1 << (i)) + +#define inode_isadir(ino_rec, ino_offset) \ + (((ino_rec)->ino_isa_dir & XFS_INO_ISADIR_MASK((ino_offset))) == 0LL \ + ? 0 : 1) +#define set_inode_isadir(ino_rec, ino_offset) \ + ((ino_rec)->ino_isa_dir |= XFS_INO_ISADIR_MASK((ino_offset))) +#define clear_inode_isadir(ino_rec, ino_offset) \ + ((ino_rec)->ino_isa_dir &= ~XFS_INO_ISADIR_MASK((ino_offset))) + + +/* + * set/clear/test is inode known to be valid (although perhaps corrupt) + */ +#define clear_inode_confirmed(ino_rec, ino_offset) \ + XFS_INOCF_CLR_CF((ino_rec), (ino_offset)) + +#define set_inode_confirmed(ino_rec, ino_offset) \ + XFS_INOCF_SET_CF((ino_rec), (ino_offset)) + +#define is_inode_confirmed(ino_rec, ino_offset) \ + XFS_INOCF_IS_CF(ino_rec, ino_offset) + +/* + * set/clear/test is inode free or used + */ +#define set_inode_free(ino_rec, ino_offset) \ + XFS_INOCF_SET_CF((ino_rec), (ino_offset)), \ + XFS_INOBT_SET_FREE((ino_rec), (ino_offset),(ARCH_NOCONVERT)) + +#define set_inode_used(ino_rec, ino_offset) \ + XFS_INOCF_SET_CF((ino_rec), (ino_offset)), \ + XFS_INOBT_CLR_FREE((ino_rec), (ino_offset),(ARCH_NOCONVERT)) + +#define is_inode_used(ino_rec, ino_offset) \ + !XFS_INOBT_IS_FREE((ino_rec), (ino_offset),(ARCH_NOCONVERT)) + +#define is_inode_free(ino_rec, ino_offset) \ + XFS_INOBT_IS_FREE((ino_rec), (ino_offset),(ARCH_NOCONVERT)) + +/* + * add_inode_reached() is set on inode I only if I has been reached + * by an inode P claiming to be the parent and if I is a directory, + * the .. link in the I says that P is I's parent. + * + * add_inode_ref() is called every time a link to an inode is + * detected and drop_inode_ref() is called every time a link to + * an inode that we've counted is removed. + */ + +void add_inode_reached(ino_tree_node_t *ino_rec, int ino_offset); +void add_inode_ref(ino_tree_node_t *ino_rec, int ino_offset); +void drop_inode_ref(ino_tree_node_t *ino_rec, int ino_offset); +int is_inode_reached(ino_tree_node_t *ino_rec, int ino_offset); +int is_inode_referenced(ino_tree_node_t *ino_rec, int ino_offset); +__uint32_t num_inode_references(ino_tree_node_t *ino_rec, int ino_offset); + +/* + * has an inode been processed for phase 6 (reference count checking)? + * add_inode_refchecked() is set on an inode when it gets traversed + * during the reference count phase (6). It's set so that if the inode + * is a directory, it's traversed (and it's links counted) only once. + */ +#ifndef XR_INO_REF_DEBUG +#define add_inode_refchecked(ino, ino_rec, ino_offset) \ + XFS_INOPROC_SET_PROC((ino_rec), (ino_offset)) +#define is_inode_refchecked(ino, ino_rec, ino_offset) \ + (XFS_INOPROC_IS_PROC(ino_rec, ino_offset) == 0LL ? 0 : 1) +#else +void add_inode_refchecked(xfs_ino_t ino, + ino_tree_node_t *ino_rec, int ino_offset); +int is_inode_refchecked(xfs_ino_t ino, + ino_tree_node_t *ino_rec, int ino_offset); +#endif /* XR_INO_REF_DEBUG */ + +/* + * set/get inode number of parent -- works for directory inodes only + */ +void set_inode_parent(ino_tree_node_t *irec, int ino_offset, + xfs_ino_t ino); +#if 0 +void clear_inode_parent(ino_tree_node_t *irec, int offset); +#endif +xfs_ino_t get_inode_parent(ino_tree_node_t *irec, int ino_offset); + +/* + * bmap cursor for tracking and fixing bmap btrees. All xfs btrees number + * the levels with 0 being the leaf and every level up being 1 greater. + */ + +#define XR_MAX_BMLEVELS 10 /* XXX - rcc need to verify number */ + +typedef struct bm_level_state { + xfs_dfsbno_t fsbno; + xfs_dfsbno_t left_fsbno; + xfs_dfsbno_t right_fsbno; + __uint64_t first_key; + __uint64_t last_key; +/* + int level; + __uint64_t prev_last_key; + xfs_buf_t *bp; + xfs_bmbt_block_t *block; +*/ +} bm_level_state_t; + +typedef struct bm_cursor { + int num_levels; + xfs_ino_t ino; + xfs_dinode_t *dip; + bm_level_state_t level[XR_MAX_BMLEVELS]; +} bmap_cursor_t; + +void init_bm_cursor(bmap_cursor_t *cursor, int num_level); diff -rNu linux-2.4.7/cmd/xfsprogs/repair/incore_bmc.c linux-2.4-xfs/cmd/xfsprogs/repair/incore_bmc.c --- linux-2.4.7/cmd/xfsprogs/repair/incore_bmc.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/incore_bmc.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "avl.h" +#include "globals.h" +#include "incore.h" +#include "agheader.h" +#include "protos.h" +#include "err_protos.h" + +void +init_bm_cursor(bmap_cursor_t *cursor, int num_levels) +{ + int i; + + bzero(cursor, sizeof(bmap_cursor_t)); + cursor->ino = NULLFSINO; + cursor->num_levels = num_levels; + + for (i = 0; i < XR_MAX_BMLEVELS; i++) { + cursor->level[i].fsbno = NULLDFSBNO; + cursor->level[i].right_fsbno = NULLDFSBNO; + cursor->level[i].left_fsbno = NULLDFSBNO; + cursor->level[i].first_key = NULLDFILOFF; + cursor->level[i].last_key = NULLDFILOFF; + } +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/incore_ext.c linux-2.4-xfs/cmd/xfsprogs/repair/incore_ext.c --- linux-2.4.7/cmd/xfsprogs/repair/incore_ext.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/incore_ext.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,1000 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "avl.h" +#include "globals.h" +#include "incore.h" +#include "agheader.h" +#include "protos.h" +#include "err_protos.h" +#include "avl64.h" +#define ALLOC_NUM_EXTS 100 + +/* + * paranoia -- account for any weird padding, 64/32-bit alignment, etc. + */ +typedef struct extent_alloc_rec { + ba_rec_t alloc_rec; + extent_tree_node_t extents[ALLOC_NUM_EXTS]; +} extent_alloc_rec_t; + +typedef struct rt_extent_alloc_rec { + ba_rec_t alloc_rec; + rt_extent_tree_node_t extents[ALLOC_NUM_EXTS]; +} rt_extent_alloc_rec_t; + +/* + * note: there are 4 sets of incore things handled here: + * block bitmaps, extent trees, uncertain inode list, + * and inode tree. The tree-based code uses the AVL + * tree package used by the IRIX kernel VM code + * (sys/avl.h). The inode list code uses the same records + * as the inode tree code for convenience. The bitmaps + * and bitmap operators are mostly macros defined in incore.h. + * There are one of everything per AG except for extent + * trees. There's one duplicate extent tree, one bno and + * one bcnt extent tree per AG. Not all of the above exist + * through all phases. The duplicate extent tree gets trashed + * at the end of phase 4. The bno/bcnt trees don't appear until + * phase 5. The uncertain inode list goes away at the end of + * phase 3. The inode tree and bno/bnct trees go away after phase 5. + */ +typedef struct ext_flist_s { + extent_tree_node_t *list; + int cnt; +} ext_flist_t; + +static ext_flist_t ext_flist; + +typedef struct rt_ext_flist_s { + rt_extent_tree_node_t *list; + int cnt; +} rt_ext_flist_t; + +static rt_ext_flist_t rt_ext_flist; + +static avl64tree_desc_t *rt_ext_tree_ptr; /* dup extent tree for rt */ + +static avltree_desc_t **extent_tree_ptrs; /* array of extent tree ptrs */ + /* one per ag for dups */ +static avltree_desc_t **extent_bno_ptrs; /* + * array of extent tree ptrs + * one per ag for free extents + * sorted by starting block + * number + */ +static avltree_desc_t **extent_bcnt_ptrs; /* + * array of extent tree ptrs + * one per ag for free extents + * sorted by size + */ + +/* + * list of allocated "blocks" for easy freeing later + */ +static ba_rec_t *ba_list; +static ba_rec_t *rt_ba_list; + +/* + * extent tree stuff is avl trees of duplicate extents, + * sorted in order by block number. there is one tree per ag. + */ + +static extent_tree_node_t * +mk_extent_tree_nodes(xfs_agblock_t new_startblock, + xfs_extlen_t new_blockcount, extent_state_t new_state) +{ + int i; + extent_tree_node_t *new; + extent_alloc_rec_t *rec; + + if (ext_flist.cnt == 0) { + ASSERT(ext_flist.list == NULL); + + if ((rec = malloc(sizeof(extent_alloc_rec_t))) == NULL) + do_error("couldn't allocate new extent descriptors.\n"); + + record_allocation(&rec->alloc_rec, ba_list); + + new = &rec->extents[0]; + + for (i = 0; i < ALLOC_NUM_EXTS; i++) { + new->avl_node.avl_nextino = (avlnode_t *) + ext_flist.list; + ext_flist.list = new; + ext_flist.cnt++; + new++; + } + } + + ASSERT(ext_flist.list != NULL); + + new = ext_flist.list; + ext_flist.list = (extent_tree_node_t *) new->avl_node.avl_nextino; + ext_flist.cnt--; + new->avl_node.avl_nextino = NULL; + + /* initialize node */ + + new->ex_startblock = new_startblock; + new->ex_blockcount = new_blockcount; + new->ex_state = new_state; + new->next = NULL; + + return(new); +} + +void +release_extent_tree_node(extent_tree_node_t *node) +{ + node->avl_node.avl_nextino = (avlnode_t *) ext_flist.list; + ext_flist.list = node; + ext_flist.cnt++; + + return; +} + +/* + * routines to recycle all nodes in a tree. it walks the tree + * and puts all nodes back on the free list so the nodes can be + * reused. the duplicate and bno/bcnt extent trees for each AG + * are recycled after they're no longer needed to save memory + */ +void +release_extent_tree(avltree_desc_t *tree) +{ + extent_tree_node_t *ext; + extent_tree_node_t *tmp; + extent_tree_node_t *lext; + extent_tree_node_t *ltmp; + + if (tree->avl_firstino == NULL) + return; + + ext = (extent_tree_node_t *) tree->avl_firstino; + + while (ext != NULL) { + tmp = (extent_tree_node_t *) ext->avl_node.avl_nextino; + + /* + * ext->next is guaranteed to be set only in bcnt trees + */ + if (ext->next != NULL) { + lext = ext->next; + while (lext != NULL) { + ltmp = lext->next; + release_extent_tree_node(lext); + lext = ltmp; + } + } + + release_extent_tree_node(ext); + ext = tmp; + } + + tree->avl_root = tree->avl_firstino = NULL; + + return; +} + +/* + * top-level (visible) routines + */ +void +release_dup_extent_tree(xfs_agnumber_t agno) +{ + release_extent_tree(extent_tree_ptrs[agno]); + + return; +} + +void +release_agbno_extent_tree(xfs_agnumber_t agno) +{ + release_extent_tree(extent_bno_ptrs[agno]); + + return; +} + +void +release_agbcnt_extent_tree(xfs_agnumber_t agno) +{ + release_extent_tree(extent_bcnt_ptrs[agno]); + + return; +} + +/* + * the next 4 routines manage the trees of free extents -- 2 trees + * per AG. The first tree is sorted by block number. The second + * tree is sorted by extent size. This is the bno tree. + */ +void +add_bno_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, + xfs_extlen_t blockcount) +{ + extent_tree_node_t *ext; + + ASSERT(extent_bno_ptrs != NULL); + ASSERT(extent_bno_ptrs[agno] != NULL); + + ext = mk_extent_tree_nodes(startblock, blockcount, XR_E_FREE); + + if (avl_insert(extent_bno_ptrs[agno], (avlnode_t *) ext) == NULL) { + do_error("xfs_repair: duplicate bno extent range\n"); + } +} + +extent_tree_node_t * +findfirst_bno_extent(xfs_agnumber_t agno) +{ + ASSERT(extent_bno_ptrs != NULL); + ASSERT(extent_bno_ptrs[agno] != NULL); + + return((extent_tree_node_t *) extent_bno_ptrs[agno]->avl_firstino); +} + +extent_tree_node_t * +find_bno_extent(xfs_agnumber_t agno, xfs_agblock_t startblock) +{ + ASSERT(extent_bno_ptrs != NULL); + ASSERT(extent_bno_ptrs[agno] != NULL); + + return((extent_tree_node_t *) avl_find(extent_bno_ptrs[agno], + startblock)); +} + +/* + * delete a node that's in the tree (pointer obtained by a find routine) + */ +void +get_bno_extent(xfs_agnumber_t agno, extent_tree_node_t *ext) +{ + ASSERT(extent_bno_ptrs != NULL); + ASSERT(extent_bno_ptrs[agno] != NULL); + + avl_delete(extent_bno_ptrs[agno], &ext->avl_node); + + return; +} + +/* + * normalizing constant for bcnt size -> address conversion (see avl ops) + * used by the AVL tree code to convert sizes and must be used when + * doing an AVL search in the tree (e.g. avl_findrange(s)) + */ +#define MAXBCNT 0xFFFFFFFF +#define BCNT_ADDR(cnt) ((unsigned int) MAXBCNT - (cnt)) + +/* + * the next 4 routines manage the trees of free extents -- 2 trees + * per AG. The first tree is sorted by block number. The second + * tree is sorted by extent size. This is the bcnt tree. + */ +void +add_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, + xfs_extlen_t blockcount) +{ + extent_tree_node_t *ext, *prev, *current, *top; + xfs_agblock_t tmp_startblock; + xfs_extlen_t tmp_blockcount; + extent_state_t tmp_state; + + ASSERT(extent_bcnt_ptrs != NULL); + ASSERT(extent_bcnt_ptrs[agno] != NULL); + + ext = mk_extent_tree_nodes(startblock, blockcount, XR_E_FREE); + + ASSERT(ext->next == NULL); + +#ifdef XR_BCNT_TRACE + fprintf(stderr, "adding bcnt: agno = %d, start = %u, count = %u\n", + agno, startblock, blockcount); +#endif + if ((current = (extent_tree_node_t *) avl_find(extent_bcnt_ptrs[agno], + blockcount)) != NULL) { + /* + * avl tree code doesn't handle dups so insert + * onto linked list in increasing startblock order + */ + top = prev = current; + while (current != NULL && + startblock > current->ex_startblock) { + prev = current; + current = current->next; + } + + if (top == current) { + ASSERT(top == prev); + /* + * swap the values of to-be-inserted element + * and the values of the head of the list. + * then insert as the 2nd element on the list. + * + * see the comment in get_bcnt_extent() + * as to why we have to do this. + */ + tmp_startblock = top->ex_startblock; + tmp_blockcount = top->ex_blockcount; + tmp_state = top->ex_state; + + top->ex_startblock = ext->ex_startblock; + top->ex_blockcount = ext->ex_blockcount; + top->ex_state = ext->ex_state; + + ext->ex_startblock = tmp_startblock; + ext->ex_blockcount = tmp_blockcount; + ext->ex_state = tmp_state; + + current = top->next; + prev = top; + } + + prev->next = ext; + ext->next = current; + + return; + } + + if (avl_insert(extent_bcnt_ptrs[agno], (avlnode_t *) ext) == NULL) { + do_error("xfs_repair: duplicate bno extent range\n"); + } + + return; +} + +extent_tree_node_t * +findfirst_bcnt_extent(xfs_agnumber_t agno) +{ + ASSERT(extent_bcnt_ptrs != NULL); + ASSERT(extent_bcnt_ptrs[agno] != NULL); + + return((extent_tree_node_t *) extent_bcnt_ptrs[agno]->avl_firstino); +} + +extent_tree_node_t * +findbiggest_bcnt_extent(xfs_agnumber_t agno) +{ + extern avlnode_t *avl_lastino(avlnode_t *root); + + ASSERT(extent_bcnt_ptrs != NULL); + ASSERT(extent_bcnt_ptrs[agno] != NULL); + + return((extent_tree_node_t *) avl_lastino(extent_bcnt_ptrs[agno]->avl_root)); +} + +extent_tree_node_t * +findnext_bcnt_extent(xfs_agnumber_t agno, extent_tree_node_t *ext) +{ + avlnode_t *nextino; + + if (ext->next != NULL) { + ASSERT(ext->ex_blockcount == ext->next->ex_blockcount); + ASSERT(ext->ex_startblock < ext->next->ex_startblock); + return(ext->next); + } else { + /* + * have to look at the top of the list to get the + * correct avl_nextino pointer since that pointer + * is maintained and altered by the AVL code. + */ + nextino = avl_find(extent_bcnt_ptrs[agno], ext->ex_blockcount); + ASSERT(nextino != NULL); + if (nextino->avl_nextino != NULL) { + ASSERT(ext->ex_blockcount < ((extent_tree_node_t *) + nextino->avl_nextino)->ex_blockcount); + } + return((extent_tree_node_t *) nextino->avl_nextino); + } +} + +/* + * this is meant to be called after you walk the bno tree to + * determine exactly which extent you want (so you'll know the + * desired value for startblock when you call this routine). + */ +extent_tree_node_t * +get_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, + xfs_extlen_t blockcount) +{ + extent_tree_node_t *ext, *prev, *top; + xfs_agblock_t tmp_startblock; + xfs_extlen_t tmp_blockcount; + extent_state_t tmp_state; + + prev = NULL; + ASSERT(extent_bcnt_ptrs != NULL); + ASSERT(extent_bcnt_ptrs[agno] != NULL); + + if ((ext = (extent_tree_node_t *) avl_find(extent_bcnt_ptrs[agno], + blockcount)) == NULL) + return(NULL); + + top = ext; + + if (ext->next != NULL) { + /* + * pull it off the list + */ + while (ext != NULL && startblock != ext->ex_startblock) { + prev = ext; + ext = ext->next; + } + ASSERT(ext != NULL); + if (ext == top) { + /* + * this node is linked into the tree so we + * swap the core values so we can delete + * the next item on the list instead of + * the head of the list. This is because + * the rest of the tree undoubtedly has + * pointers to the piece of memory that + * is the head of the list so pulling + * the item out of the list and hence + * the avl tree would be a bad idea. + * + * (cheaper than the alternative, a tree + * delete of this node followed by a tree + * insert of the next node on the list). + */ + tmp_startblock = ext->next->ex_startblock; + tmp_blockcount = ext->next->ex_blockcount; + tmp_state = ext->next->ex_state; + + ext->next->ex_startblock = ext->ex_startblock; + ext->next->ex_blockcount = ext->ex_blockcount; + ext->next->ex_state = ext->ex_state; + + ext->ex_startblock = tmp_startblock; + ext->ex_blockcount = tmp_blockcount; + ext->ex_state = tmp_state; + + ext = ext->next; + prev = top; + } + /* + * now, a simple list deletion + */ + prev->next = ext->next; + ext->next = NULL; + } else { + /* + * no list, just one node. simply delete + */ + avl_delete(extent_bcnt_ptrs[agno], &ext->avl_node); + } + + ASSERT(ext->ex_startblock == startblock); + ASSERT(ext->ex_blockcount == blockcount); + return(ext); +} + +/* + * the next 2 routines manage the trees of duplicate extents -- 1 tree + * per AG + */ +void +add_dup_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, + xfs_extlen_t blockcount) +{ + extent_tree_node_t *first, *last, *ext, *next_ext; + xfs_agblock_t new_startblock; + xfs_extlen_t new_blockcount; + + ASSERT(agno < glob_agcount); + +#ifdef XR_DUP_TRACE + fprintf(stderr, "Adding dup extent - %d/%d %d\n", agno, startblock, blockcount); +#endif + avl_findranges(extent_tree_ptrs[agno], startblock - 1, + startblock + blockcount + 1, + (avlnode_t **) &first, (avlnode_t **) &last); + /* + * find adjacent and overlapping extent blocks + */ + if (first == NULL && last == NULL) { + /* nothing, just make and insert new extent */ + + ext = mk_extent_tree_nodes(startblock, blockcount, XR_E_MULT); + + if (avl_insert(extent_tree_ptrs[agno], + (avlnode_t *) ext) == NULL) { + do_error("xfs_repair: duplicate extent range\n"); + } + + return; + } + + ASSERT(first != NULL && last != NULL); + + /* + * find the new composite range, delete old extent nodes + * as we go + */ + new_startblock = startblock; + new_blockcount = blockcount; + + for (ext = first; + ext != (extent_tree_node_t *) last->avl_node.avl_nextino; + ext = next_ext) { + /* + * preserve the next inorder node + */ + next_ext = (extent_tree_node_t *) ext->avl_node.avl_nextino; + /* + * just bail if the new extent is contained within an old one + */ + if (ext->ex_startblock <= startblock && + ext->ex_blockcount >= blockcount) + return; + /* + * now check for overlaps and adjacent extents + */ + if (ext->ex_startblock + ext->ex_blockcount >= startblock + || ext->ex_startblock <= startblock + blockcount) { + + if (ext->ex_startblock < new_startblock) + new_startblock = ext->ex_startblock; + + if (ext->ex_startblock + ext->ex_blockcount > + new_startblock + new_blockcount) + new_blockcount = ext->ex_startblock + + ext->ex_blockcount - + new_startblock; + + avl_delete(extent_tree_ptrs[agno], (avlnode_t *) ext); + continue; + } + } + + ext = mk_extent_tree_nodes(new_startblock, new_blockcount, XR_E_MULT); + + if (avl_insert(extent_tree_ptrs[agno], (avlnode_t *) ext) == NULL) { + do_error("xfs_repair: duplicate extent range\n"); + } + + return; +} + +/* + * returns 1 if block is a dup, 0 if not + */ +/* ARGSUSED */ +int +search_dup_extent(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agblock_t agbno) +{ + ASSERT(agno < glob_agcount); + + if (avl_findrange(extent_tree_ptrs[agno], agbno) != NULL) + return(1); + + return(0); +} + +static __psunsigned_t +avl_ext_start(avlnode_t *node) +{ + return((__psunsigned_t) + ((extent_tree_node_t *) node)->ex_startblock); +} + +static __psunsigned_t +avl_ext_end(avlnode_t *node) +{ + return((__psunsigned_t) ( + ((extent_tree_node_t *) node)->ex_startblock + + ((extent_tree_node_t *) node)->ex_blockcount)); +} + +/* + * convert size to an address for the AVL tree code -- the bigger the size, + * the lower the address so the biggest extent will be first in the tree + */ +static __psunsigned_t +avl_ext_bcnt_start(avlnode_t *node) +{ +/* + return((__psunsigned_t) (BCNT_ADDR(((extent_tree_node_t *) + node)->ex_blockcount))); +*/ + return((__psunsigned_t) ((extent_tree_node_t *)node)->ex_blockcount); +} + +static __psunsigned_t +avl_ext_bcnt_end(avlnode_t *node) +{ +/* + return((__psunsigned_t) (BCNT_ADDR(((extent_tree_node_t *) + node)->ex_blockcount))); +*/ + return((__psunsigned_t) ((extent_tree_node_t *)node)->ex_blockcount); +} + +avlops_t avl_extent_bcnt_tree_ops = { + avl_ext_bcnt_start, + avl_ext_bcnt_end +}; + +avlops_t avl_extent_tree_ops = { + avl_ext_start, + avl_ext_end +}; + +/* + * for real-time extents -- have to dup code since realtime extent + * startblocks can be 64-bit values. + */ +static rt_extent_tree_node_t * +mk_rt_extent_tree_nodes(xfs_drtbno_t new_startblock, + xfs_extlen_t new_blockcount, extent_state_t new_state) +{ + int i; + rt_extent_tree_node_t *new; + rt_extent_alloc_rec_t *rec; + + if (rt_ext_flist.cnt == 0) { + ASSERT(rt_ext_flist.list == NULL); + + if ((rec = malloc(sizeof(rt_extent_alloc_rec_t))) == NULL) + do_error("couldn't allocate new extent descriptors.\n"); + + record_allocation(&rec->alloc_rec, rt_ba_list); + + new = &rec->extents[0]; + + for (i = 0; i < ALLOC_NUM_EXTS; i++) { + new->avl_node.avl_nextino = (avlnode_t *) + rt_ext_flist.list; + rt_ext_flist.list = new; + rt_ext_flist.cnt++; + new++; + } + } + + ASSERT(rt_ext_flist.list != NULL); + + new = rt_ext_flist.list; + rt_ext_flist.list = (rt_extent_tree_node_t *) new->avl_node.avl_nextino; + rt_ext_flist.cnt--; + new->avl_node.avl_nextino = NULL; + + /* initialize node */ + + new->rt_startblock = new_startblock; + new->rt_blockcount = new_blockcount; + new->rt_state = new_state; + + return(new); +} + +#if 0 +void +release_rt_extent_tree_node(rt_extent_tree_node_t *node) +{ + node->avl_node.avl_nextino = (avlnode_t *) rt_ext_flist.list; + rt_ext_flist.list = node; + rt_ext_flist.cnt++; + + return; +} + +void +release_rt_extent_tree() +{ + extent_tree_node_t *ext; + extent_tree_node_t *tmp; + extent_tree_node_t *lext; + extent_tree_node_t *ltmp; + avl64tree_desc_t *tree; + + tree = rt_extent_tree_ptr; + + if (tree->avl_firstino == NULL) + return; + + ext = (extent_tree_node_t *) tree->avl_firstino; + + while (ext != NULL) { + tmp = (extent_tree_node_t *) ext->avl_node.avl_nextino; + release_rt_extent_tree_node(ext); + ext = tmp; + } + + tree->avl_root = tree->avl_firstino = NULL; + + return; +} +#endif + +/* + * don't need release functions for realtime tree teardown + * since we only have one tree, not one per AG + */ +/* ARGSUSED */ +void +free_rt_dup_extent_tree(xfs_mount_t *mp) +{ + ASSERT(mp->m_sb.sb_rblocks != 0); + + free_allocations(rt_ba_list); + free(rt_ext_tree_ptr); + + rt_ba_list = NULL; + rt_ext_tree_ptr = NULL; + + return; +} + +/* + * add a duplicate real-time extent + */ +void +add_rt_dup_extent(xfs_drtbno_t startblock, xfs_extlen_t blockcount) +{ + rt_extent_tree_node_t *first, *last, *ext, *next_ext; + xfs_drtbno_t new_startblock; + xfs_extlen_t new_blockcount; + + avl64_findranges(rt_ext_tree_ptr, startblock - 1, + startblock + blockcount + 1, + (avl64node_t **) &first, (avl64node_t **) &last); + /* + * find adjacent and overlapping extent blocks + */ + if (first == NULL && last == NULL) { + /* nothing, just make and insert new extent */ + + ext = mk_rt_extent_tree_nodes(startblock, + blockcount, XR_E_MULT); + + if (avl64_insert(rt_ext_tree_ptr, + (avl64node_t *) ext) == NULL) { + do_error("xfs_repair: duplicate extent range\n"); + } + + return; + } + + ASSERT(first != NULL && last != NULL); + + /* + * find the new composite range, delete old extent nodes + * as we go + */ + new_startblock = startblock; + new_blockcount = blockcount; + + for (ext = first; + ext != (rt_extent_tree_node_t *) last->avl_node.avl_nextino; + ext = next_ext) { + /* + * preserve the next inorder node + */ + next_ext = (rt_extent_tree_node_t *) ext->avl_node.avl_nextino; + /* + * just bail if the new extent is contained within an old one + */ + if (ext->rt_startblock <= startblock && + ext->rt_blockcount >= blockcount) + return; + /* + * now check for overlaps and adjacent extents + */ + if (ext->rt_startblock + ext->rt_blockcount >= startblock + || ext->rt_startblock <= startblock + blockcount) { + + if (ext->rt_startblock < new_startblock) + new_startblock = ext->rt_startblock; + + if (ext->rt_startblock + ext->rt_blockcount > + new_startblock + new_blockcount) + new_blockcount = ext->rt_startblock + + ext->rt_blockcount - + new_startblock; + + avl64_delete(rt_ext_tree_ptr, (avl64node_t *) ext); + continue; + } + } + + ext = mk_rt_extent_tree_nodes(new_startblock, + new_blockcount, XR_E_MULT); + + if (avl64_insert(rt_ext_tree_ptr, (avl64node_t *) ext) == NULL) { + do_error("xfs_repair: duplicate extent range\n"); + } + + return; +} + +/* + * returns 1 if block is a dup, 0 if not + */ +/* ARGSUSED */ +int +search_rt_dup_extent(xfs_mount_t *mp, xfs_drtbno_t bno) +{ + if (avl64_findrange(rt_ext_tree_ptr, bno) != NULL) + return(1); + + return(0); +} + +static __uint64_t +avl64_rt_ext_start(avl64node_t *node) +{ + return(((rt_extent_tree_node_t *) node)->rt_startblock); +} + +static __uint64_t +avl64_ext_end(avl64node_t *node) +{ + return(((rt_extent_tree_node_t *) node)->rt_startblock + + ((rt_extent_tree_node_t *) node)->rt_blockcount); +} + +avl64ops_t avl64_extent_tree_ops = { + avl64_rt_ext_start, + avl64_ext_end +}; + +void +incore_ext_init(xfs_mount_t *mp) +{ + int i; + xfs_agnumber_t agcount = mp->m_sb.sb_agcount; + + ba_list = NULL; + rt_ba_list = NULL; + + if ((extent_tree_ptrs = malloc(agcount * + sizeof(avltree_desc_t *))) == NULL) + do_error("couldn't malloc dup extent tree descriptor table\n"); + + if ((extent_bno_ptrs = malloc(agcount * + sizeof(avltree_desc_t *))) == NULL) + do_error("couldn't malloc free by-bno extent tree descriptor table\n"); + + if ((extent_bcnt_ptrs = malloc(agcount * + sizeof(avltree_desc_t *))) == NULL) + do_error("couldn't malloc free by-bcnt extent tree descriptor table\n"); + + for (i = 0; i < agcount; i++) { + if ((extent_tree_ptrs[i] = + malloc(sizeof(avltree_desc_t))) == NULL) + do_error("couldn't malloc dup extent tree descriptor\n"); + if ((extent_bno_ptrs[i] = + malloc(sizeof(avltree_desc_t))) == NULL) + do_error("couldn't malloc bno extent tree descriptor\n"); + if ((extent_bcnt_ptrs[i] = + malloc(sizeof(avltree_desc_t))) == NULL) + do_error("couldn't malloc bcnt extent tree descriptor\n"); + } + + for (i = 0; i < agcount; i++) { + avl_init_tree(extent_tree_ptrs[i], &avl_extent_tree_ops); + avl_init_tree(extent_bno_ptrs[i], &avl_extent_tree_ops); + avl_init_tree(extent_bcnt_ptrs[i], &avl_extent_bcnt_tree_ops); + } + + if ((rt_ext_tree_ptr = malloc(sizeof(avltree_desc_t))) == NULL) + do_error("couldn't malloc dup rt extent tree descriptor\n"); + + avl64_init_tree(rt_ext_tree_ptr, &avl64_extent_tree_ops); + + ext_flist.cnt = 0; + ext_flist.list = NULL; + + return; +} + +/* + * this routine actually frees all the memory used to track per-AG trees + */ +void +incore_ext_teardown(xfs_mount_t *mp) +{ + xfs_agnumber_t i; + + free_allocations(ba_list); + + for (i = 0; i < mp->m_sb.sb_agcount; i++) { + free(extent_tree_ptrs[i]); + free(extent_bno_ptrs[i]); + free(extent_bcnt_ptrs[i]); + } + + free(extent_bcnt_ptrs); + free(extent_bno_ptrs); + free(extent_tree_ptrs); + + extent_bcnt_ptrs = extent_bno_ptrs = extent_tree_ptrs = NULL; + + return; +} + +int +count_extents(xfs_agnumber_t agno, avltree_desc_t *tree, int whichtree) +{ + extent_tree_node_t *node; + int i = 0; + + node = (extent_tree_node_t *) tree->avl_firstino; + + while (node != NULL) { + i++; + if (whichtree) + node = findnext_bcnt_extent(agno, node); + else + node = findnext_bno_extent(node); + } + + return(i); +} + +int +count_bno_extents_blocks(xfs_agnumber_t agno, uint *numblocks) +{ + __uint64_t nblocks; + extent_tree_node_t *node; + int i = 0; + + ASSERT(agno < glob_agcount); + + nblocks = 0; + + node = (extent_tree_node_t *) extent_bno_ptrs[agno]->avl_firstino; + + while (node != NULL) { + nblocks += node->ex_blockcount; + i++; + node = findnext_bno_extent(node); + } + + *numblocks = nblocks; + return(i); +} + +int +count_bno_extents(xfs_agnumber_t agno) +{ + ASSERT(agno < glob_agcount); + return(count_extents(agno, extent_bno_ptrs[agno], 0)); +} + +int +count_bcnt_extents(xfs_agnumber_t agno) +{ + ASSERT(agno < glob_agcount); + return(count_extents(agno, extent_bcnt_ptrs[agno], 1)); +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/incore_ino.c linux-2.4-xfs/cmd/xfsprogs/repair/incore_ino.c --- linux-2.4.7/cmd/xfsprogs/repair/incore_ino.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/incore_ino.c Mon Apr 9 02:41:10 2001 @@ -0,0 +1,834 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "avl.h" +#include "globals.h" +#include "incore.h" +#include "agheader.h" +#include "protos.h" +#include "err_protos.h" + +extern avlnode_t *avl_firstino(avlnode_t *root); + +/* + * array of inode tree ptrs, one per ag + */ +static avltree_desc_t **inode_tree_ptrs; + +/* + * ditto for uncertain inodes + */ +static avltree_desc_t **inode_uncertain_tree_ptrs; + +#define ALLOC_NUM_INOS 100 + +/* free lists -- inode nodes and extent nodes */ + +typedef struct ino_flist_s { + ino_tree_node_t *list; + ino_tree_node_t *last; + long long cnt; +} ino_flist_t; + +static ino_flist_t ino_flist; /* free list must be initialized before use */ + +/* + * next is the uncertain inode list -- a sorted (in ascending order) + * list of inode records sorted on the starting inode number. There + * is one list per ag. + */ + +/* + * common code for creating inode records for use by trees and lists. + * called only from add_inodes and add_inodes_uncertain + * + * IMPORTANT: all inodes (inode records) start off as free and + * unconfirmed. + */ +/* ARGSUSED */ +static ino_tree_node_t * +mk_ino_tree_nodes(xfs_agino_t starting_ino) +{ + int i; + ino_tree_node_t *new; + avlnode_t *node; + + if (ino_flist.cnt == 0) { + ASSERT(ino_flist.list == NULL); + + if ((new = malloc(sizeof(ino_tree_node_t[ALLOC_NUM_INOS]))) + == NULL) + do_error("inode map malloc failed\n"); + + for (i = 0; i < ALLOC_NUM_INOS; i++) { + new->avl_node.avl_nextino = + (avlnode_t *) ino_flist.list; + ino_flist.list = new; + ino_flist.cnt++; + new++; + } + } + + ASSERT(ino_flist.list != NULL); + + new = ino_flist.list; + ino_flist.list = (ino_tree_node_t *) new->avl_node.avl_nextino; + ino_flist.cnt--; + node = &new->avl_node; + node->avl_nextino = node->avl_forw = node->avl_back = NULL; + + /* initialize node */ + + new->ino_startnum = 0; + new->ino_confirmed = 0; + new->ino_isa_dir = 0; + new->ir_free = (xfs_inofree_t) - 1; + new->ino_un.backptrs = NULL; + + return(new); +} + +/* + * return inode record to free list, will be initialized when + * it gets pulled off list + */ +static void +free_ino_tree_node(ino_tree_node_t *ino_rec) +{ + ino_rec->avl_node.avl_nextino = NULL; + ino_rec->avl_node.avl_forw = NULL; + ino_rec->avl_node.avl_back = NULL; + + if (ino_flist.list != NULL) { + ASSERT(ino_flist.cnt > 0); + ino_rec->avl_node.avl_nextino = (avlnode_t *) ino_flist.list; + } else { + ASSERT(ino_flist.cnt == 0); + ino_rec->avl_node.avl_nextino = NULL; + } + + ino_flist.list = ino_rec; + ino_flist.cnt++; + + if (ino_rec->ino_un.backptrs != NULL) { + if (full_backptrs && ino_rec->ino_un.backptrs->parents != NULL) + free(ino_rec->ino_un.backptrs->parents); + if (ino_rec->ino_un.plist != NULL) + free(ino_rec->ino_un.plist); + } + + return; +} + +/* + * last referenced cache for uncertain inodes + */ +static ino_tree_node_t **last_rec; + +/* + * ok, the uncertain inodes are a set of trees just like the + * good inodes but all starting inode records are (arbitrarily) + * aligned on XFS_CHUNK_PER_INODE boundaries to prevent overlaps. + * this means we may have partials records in the tree (e.g. records + * without 64 confirmed uncertain inodes). Tough. + * + * free is set to 1 if the inode is thought to be free, 0 if used + */ +void +add_aginode_uncertain(xfs_agnumber_t agno, xfs_agino_t ino, int free) +{ + ino_tree_node_t *ino_rec; + xfs_agino_t s_ino; + int offset; + + ASSERT(agno < glob_agcount); + ASSERT(last_rec != NULL); + + s_ino = rounddown(ino, XFS_INODES_PER_CHUNK); + + /* + * check for a cache hit + */ + if (last_rec[agno] != NULL && last_rec[agno]->ino_startnum == s_ino) { + offset = ino - s_ino; + if (free) + set_inode_free(last_rec[agno], offset); + else + set_inode_used(last_rec[agno], offset); + + return; + } + + /* + * check to see if record containing inode is already in the tree. + * if not, add it + */ + if ((ino_rec = (ino_tree_node_t *) + avl_findrange(inode_uncertain_tree_ptrs[agno], + s_ino)) == NULL) { + ino_rec = mk_ino_tree_nodes(s_ino); + ino_rec->ino_startnum = s_ino; + + if (avl_insert(inode_uncertain_tree_ptrs[agno], + (avlnode_t *) ino_rec) == NULL) { + do_error("xfs_repair: duplicate inode range\n"); + } + } + + if (free) + set_inode_free(ino_rec, ino - s_ino); + else + set_inode_used(ino_rec, ino - s_ino); + + /* + * set cache entry + */ + last_rec[agno] = ino_rec; + + return; +} + +/* + * like add_aginode_uncertain() only it needs an xfs_mount_t * + * to perform the inode number conversion. + */ +void +add_inode_uncertain(xfs_mount_t *mp, xfs_ino_t ino, int free) +{ + add_aginode_uncertain(XFS_INO_TO_AGNO(mp, ino), + XFS_INO_TO_AGINO(mp, ino), free); +} + +/* + * pull the indicated inode record out of the uncertain inode tree + */ +void +get_uncertain_inode_rec(xfs_agnumber_t agno, ino_tree_node_t *ino_rec) +{ + ASSERT(inode_tree_ptrs != NULL); + ASSERT(inode_tree_ptrs[agno] != NULL); + + avl_delete(inode_uncertain_tree_ptrs[agno], &ino_rec->avl_node); + + ino_rec->avl_node.avl_nextino = NULL; + ino_rec->avl_node.avl_forw = NULL; + ino_rec->avl_node.avl_back = NULL; +} + +ino_tree_node_t * +findfirst_uncertain_inode_rec(xfs_agnumber_t agno) +{ + return((ino_tree_node_t *) + inode_uncertain_tree_ptrs[agno]->avl_firstino); +} + +void +clear_uncertain_ino_cache(xfs_agnumber_t agno) +{ + last_rec[agno] = NULL; + + return; +} + + +/* + * next comes the inode trees. One per ag. AVL trees + * of inode records, each inode record tracking 64 inodes + */ +/* + * set up an inode tree record for a group of inodes that will + * include the requested inode. + * + * does NOT error-check for duplicate records. Caller is + * responsible for checking that. + * + * ino must be the start of an XFS_INODES_PER_CHUNK (64) inode chunk + * + * Each inode resides in a 64-inode chunk which can be part + * one or more chunks (MAX(64, inodes-per-block). The fs allocates + * in chunks (as opposed to 1 chunk) when a block can hold more than + * one chunk (inodes per block > 64). Allocating in one chunk pieces + * causes us problems when it takes more than one fs block to contain + * an inode chunk because the chunks can start on *any* block boundary. + * So we assume that the caller has a clue because at this level, we + * don't. + */ +static ino_tree_node_t * +add_inode(xfs_agnumber_t agno, xfs_agino_t ino) +{ + ino_tree_node_t *ino_rec; + + /* no record exists, make some and put them into the tree */ + + ino_rec = mk_ino_tree_nodes(ino); + ino_rec->ino_startnum = ino; + + if (avl_insert(inode_tree_ptrs[agno], + (avlnode_t *) ino_rec) == NULL) { + do_error("xfs_repair: duplicate inode range\n"); + } + + return(ino_rec); +} + +/* + * pull the indicated inode record out of the inode tree + */ +void +get_inode_rec(xfs_agnumber_t agno, ino_tree_node_t *ino_rec) +{ + ASSERT(inode_tree_ptrs != NULL); + ASSERT(inode_tree_ptrs[agno] != NULL); + + avl_delete(inode_tree_ptrs[agno], &ino_rec->avl_node); + + ino_rec->avl_node.avl_nextino = NULL; + ino_rec->avl_node.avl_forw = NULL; + ino_rec->avl_node.avl_back = NULL; +} + +/* + * free the designated inode record (return it to the free pool) + */ +/* ARGSUSED */ +void +free_inode_rec(xfs_agnumber_t agno, ino_tree_node_t *ino_rec) +{ + free_ino_tree_node(ino_rec); + + return; +} + +/* + * returns the inode record desired containing the inode + * returns NULL if inode doesn't exist. The tree-based find + * routines do NOT pull records out of the tree. + */ +ino_tree_node_t * +find_inode_rec(xfs_agnumber_t agno, xfs_agino_t ino) +{ + return((ino_tree_node_t *) + avl_findrange(inode_tree_ptrs[agno], ino)); +} + +void +find_inode_rec_range(xfs_agnumber_t agno, xfs_agino_t start_ino, + xfs_agino_t end_ino, ino_tree_node_t **first, + ino_tree_node_t **last) +{ + *first = *last = NULL; + + avl_findranges(inode_tree_ptrs[agno], start_ino, + end_ino, (avlnode_t **) first, (avlnode_t **) last); + return; +} + +/* + * if ino doesn't exist, it must be properly aligned -- on a + * filesystem block boundary or XFS_INODES_PER_CHUNK boundary, + * whichever alignment is larger. + */ +ino_tree_node_t * +set_inode_used_alloc(xfs_agnumber_t agno, xfs_agino_t ino) +{ + ino_tree_node_t *ino_rec; + + /* + * check alignment -- the only way to detect this + * is too see if the chunk overlaps another chunk + * already in the tree + */ + ino_rec = add_inode(agno, ino); + + ASSERT(ino_rec != NULL); + ASSERT(ino >= ino_rec->ino_startnum && + ino - ino_rec->ino_startnum < XFS_INODES_PER_CHUNK); + + set_inode_used(ino_rec, ino - ino_rec->ino_startnum); + + return(ino_rec); +} + +ino_tree_node_t * +set_inode_free_alloc(xfs_agnumber_t agno, xfs_agino_t ino) +{ + ino_tree_node_t *ino_rec; + + ino_rec = add_inode(agno, ino); + + ASSERT(ino_rec != NULL); + ASSERT(ino >= ino_rec->ino_startnum && + ino - ino_rec->ino_startnum < XFS_INODES_PER_CHUNK); + + set_inode_free(ino_rec, ino - ino_rec->ino_startnum); + + return(ino_rec); +} + +ino_tree_node_t * +findfirst_inode_rec(xfs_agnumber_t agno) +{ + return((ino_tree_node_t *) inode_tree_ptrs[agno]->avl_firstino); +} + +void +print_inode_list_int(xfs_agnumber_t agno, int uncertain) +{ + ino_tree_node_t *ino_rec; + + if (!uncertain) { + fprintf(stderr, "good inode list is --\n"); + ino_rec = findfirst_inode_rec(agno); + } else { + fprintf(stderr, "uncertain inode list is --\n"); + ino_rec = findfirst_uncertain_inode_rec(agno); + } + + if (ino_rec == NULL) { + fprintf(stderr, "agno %d -- no inodes\n", agno); + return; + } + + printf("agno %d\n", agno); + + while(ino_rec != NULL) { + fprintf(stderr, + "\tptr = %lx, start = 0x%x, free = 0x%llx, confirmed = 0x%llx\n", + (unsigned long)ino_rec, + ino_rec->ino_startnum, + (unsigned long long)ino_rec->ir_free, + (unsigned long long)ino_rec->ino_confirmed); + if (ino_rec->ino_startnum == 0) + ino_rec = ino_rec; + ino_rec = next_ino_rec(ino_rec); + } +} + +void +print_inode_list(xfs_agnumber_t agno) +{ + print_inode_list_int(agno, 0); +} + +void +print_uncertain_inode_list(xfs_agnumber_t agno) +{ + print_inode_list_int(agno, 1); +} + +/* + * set parent -- use a bitmask and a packed array. The bitmask + * indicate which inodes have an entry in the array. An inode that + * is the Nth bit set in the mask is stored in the Nth location in + * the array where N starts at 0. + */ +void +set_inode_parent(ino_tree_node_t *irec, int offset, xfs_ino_t parent) +{ + int i; + int cnt; + int target; + __uint64_t bitmask; + parent_entry_t *tmp; + + ASSERT(full_backptrs == 0); + + if (irec->ino_un.plist == NULL) { + irec->ino_un.plist = + (parent_list_t*)malloc(sizeof(parent_list_t)); + if (!irec->ino_un.plist) + do_error("couldn't malloc parent list table\n"); + + irec->ino_un.plist->pmask = 1LL << offset; + irec->ino_un.plist->pentries = + (xfs_ino_t*)memalign(sizeof(xfs_ino_t), sizeof(xfs_ino_t)); + if (!irec->ino_un.plist->pentries) + do_error("couldn't memalign pentries table\n"); +#ifdef DEBUG + irec->ino_un.plist->cnt = 1; +#endif + irec->ino_un.plist->pentries[0] = parent; + + return; + } + + if (irec->ino_un.plist->pmask & (1LL << offset)) { + bitmask = 1LL; + target = 0; + + for (i = 0; i < offset; i++) { + if (irec->ino_un.plist->pmask & bitmask) + target++; + bitmask <<= 1; + } +#ifdef DEBUG + ASSERT(target < irec->ino_un.plist->cnt); +#endif + irec->ino_un.plist->pentries[target] = parent; + + return; + } + + bitmask = 1LL; + cnt = target = 0; + + for (i = 0; i < XFS_INODES_PER_CHUNK; i++) { + if (irec->ino_un.plist->pmask & bitmask) { + cnt++; + if (i < offset) + target++; + } + + bitmask <<= 1; + } + +#ifdef DEBUG + ASSERT(cnt == irec->ino_un.plist->cnt); +#endif + ASSERT(cnt >= target); + + tmp = (xfs_ino_t*)memalign(sizeof(xfs_ino_t), (cnt + 1) * sizeof(xfs_ino_t)); + if (!tmp) + do_error("couldn't memalign pentries table\n"); + + (void) bcopy(irec->ino_un.plist->pentries, tmp, + target * sizeof(parent_entry_t)); + + if (cnt > target) + (void) bcopy(irec->ino_un.plist->pentries + target, + tmp + target + 1, + (cnt - target) * sizeof(parent_entry_t)); + + free(irec->ino_un.plist->pentries); + + irec->ino_un.plist->pentries = tmp; + +#ifdef DEBUG + irec->ino_un.plist->cnt++; +#endif + irec->ino_un.plist->pentries[target] = parent; + irec->ino_un.plist->pmask |= (1LL << offset); + + return; +} + +#if 0 +/* + * not needed for now since we don't set the parent info + * until phase 4 -- at which point we know that the directory + * inode won't be going away -- so we won't ever need to clear + * directory parent data that we set. + */ +void +clear_inode_parent(ino_tree_node_t *irec, int offset) +{ + ASSERT(full_backptrs == 0); + ASSERT(irec->ino_un.plist != NULL); + + return; +} +#endif + +xfs_ino_t +get_inode_parent(ino_tree_node_t *irec, int offset) +{ + __uint64_t bitmask; + parent_list_t *ptbl; + int i; + int target; + + if (full_backptrs) + ptbl = irec->ino_un.backptrs->parents; + else + ptbl = irec->ino_un.plist; + + if (ptbl->pmask & (1LL << offset)) { + bitmask = 1LL; + target = 0; + + for (i = 0; i < offset; i++) { + if (ptbl->pmask & bitmask) + target++; + bitmask <<= 1; + } +#ifdef DEBUG + ASSERT(target < ptbl->cnt); +#endif + return(ptbl->pentries[target]); + } + + return(0LL); +} + +/* + * code that deals with the inode descriptor appendages -- the back + * pointers, link counts and reached bits for phase 6 and phase 7. + */ + +void +add_inode_reached(ino_tree_node_t *ino_rec, int ino_offset) +{ + ASSERT(ino_rec->ino_un.backptrs != NULL); + + ino_rec->ino_un.backptrs->nlinks[ino_offset]++; + XFS_INO_RCHD_SET_RCHD(ino_rec, ino_offset); + + ASSERT(is_inode_reached(ino_rec, ino_offset)); + + return; +} + +int +is_inode_reached(ino_tree_node_t *ino_rec, int ino_offset) +{ + ASSERT(ino_rec->ino_un.backptrs != NULL); + return(XFS_INO_RCHD_IS_RCHD(ino_rec, ino_offset)); +} + +void +add_inode_ref(ino_tree_node_t *ino_rec, int ino_offset) +{ + ASSERT(ino_rec->ino_un.backptrs != NULL); + + ino_rec->ino_un.backptrs->nlinks[ino_offset]++; + + return; +} + +void +drop_inode_ref(ino_tree_node_t *ino_rec, int ino_offset) +{ + ASSERT(ino_rec->ino_un.backptrs != NULL); + ASSERT(ino_rec->ino_un.backptrs->nlinks[ino_offset] > 0); + + if (--ino_rec->ino_un.backptrs->nlinks[ino_offset] == 0) + XFS_INO_RCHD_CLR_RCHD(ino_rec, ino_offset); + + return; +} + +int +is_inode_referenced(ino_tree_node_t *ino_rec, int ino_offset) +{ + ASSERT(ino_rec->ino_un.backptrs != NULL); + return(ino_rec->ino_un.backptrs->nlinks[ino_offset] > 0); +} + +__uint32_t +num_inode_references(ino_tree_node_t *ino_rec, int ino_offset) +{ + ASSERT(ino_rec->ino_un.backptrs != NULL); + return(ino_rec->ino_un.backptrs->nlinks[ino_offset]); +} + +#if 0 +static backptrs_t *bptrs; +static int bptrs_index; +#define BPTR_ALLOC_NUM 1000 + +backptrs_t * +get_backptr(void) +{ + backptrs_t *bptr; + + if (bptrs_index == BPTR_ALLOC_NUM) { + ASSERT(bptrs == NULL); + + if ((bptrs = malloc(sizeof(backptrs_t[BPTR_ALLOC_NUM]))) + == NULL) { + do_error("couldn't malloc ino rec backptrs.\n"); + } + + bptrs_index = 0; + } + + ASSERT(bptrs != NULL); + + bptr = &bptrs[bptrs_index]; + bptrs_index++; + + if (bptrs_index == BPTR_ALLOC_NUM) + bptrs = NULL; + + bzero(bptr, sizeof(backptrs_t)); + + return(bptr); +} +#endif + +backptrs_t * +get_backptr(void) +{ + backptrs_t *ptr; + + if ((ptr = malloc(sizeof(backptrs_t))) == NULL) + do_error("could not malloc back pointer table\n"); + + bzero(ptr, sizeof(backptrs_t)); + + return(ptr); +} + +void +add_ino_backptrs(xfs_mount_t *mp) +{ +#ifdef XR_BCKPTR_DBG + xfs_ino_t ino; + int j, k; +#endif /* XR_BCKPTR_DBG */ + ino_tree_node_t *ino_rec; + parent_list_t *tmp; + xfs_agnumber_t i; + + for (i = 0; i < mp->m_sb.sb_agcount; i++) { + ino_rec = findfirst_inode_rec(i); + + while (ino_rec != NULL) { + tmp = ino_rec->ino_un.plist; + ino_rec->ino_un.backptrs = get_backptr(); + ino_rec->ino_un.backptrs->parents = tmp; + +#ifdef XR_BCKPTR_DBG + if (tmp != NULL) { + k = 0; + for (j = 0; j < XFS_INODES_PER_CHUNK; j++) { + ino = XFS_AGINO_TO_INO(mp, i, + ino_rec->ino_startnum + j); + if (ino == 25165846) { + do_warn("THERE 1 !!!\n"); + } + if (tmp->pentries[j] != 0) { + k++; + do_warn( + "inode %llu - parent %llu\n", + ino, + tmp->pentries[j]); + if (ino == 25165846) { + do_warn("THERE!!!\n"); + } + } + } + + if (k != tmp->cnt) { + do_warn( + "ERROR - count = %d, counted %d\n", + tmp->cnt, k); + } + } +#endif /* XR_BCKPTR_DBG */ + ino_rec = next_ino_rec(ino_rec); + } + } + + full_backptrs = 1; + + return; +} + +static __psunsigned_t +avl_ino_start(avlnode_t *node) +{ + return((__psunsigned_t) ((ino_tree_node_t *) node)->ino_startnum); +} + +static __psunsigned_t +avl_ino_end(avlnode_t *node) +{ + return((__psunsigned_t) ( + ((ino_tree_node_t *) node)->ino_startnum + + XFS_INODES_PER_CHUNK)); +} + +avlops_t avl_ino_tree_ops = { + avl_ino_start, + avl_ino_end +}; + +void +incore_ino_init(xfs_mount_t *mp) +{ + int i; + int agcount = mp->m_sb.sb_agcount; + + if ((inode_tree_ptrs = malloc(agcount * + sizeof(avltree_desc_t *))) == NULL) + do_error("couldn't malloc inode tree descriptor table\n"); + if ((inode_uncertain_tree_ptrs = malloc(agcount * + sizeof(avltree_desc_t *))) == NULL) + do_error("couldn't malloc uncertain ino tree descriptor table\n"); + + for (i = 0; i < agcount; i++) { + if ((inode_tree_ptrs[i] = + malloc(sizeof(avltree_desc_t))) == NULL) + do_error("couldn't malloc inode tree descriptor\n"); + if ((inode_uncertain_tree_ptrs[i] = + malloc(sizeof(avltree_desc_t))) == NULL) + do_error( + "couldn't malloc uncertain ino tree descriptor\n"); + } + for (i = 0; i < agcount; i++) { + avl_init_tree(inode_tree_ptrs[i], &avl_ino_tree_ops); + avl_init_tree(inode_uncertain_tree_ptrs[i], &avl_ino_tree_ops); + } + + ino_flist.cnt = 0; + ino_flist.list = NULL; + + if ((last_rec = malloc(sizeof(ino_tree_node_t *) * agcount)) == NULL) + do_error("couldn't malloc uncertain inode cache area\n"); + + bzero(last_rec, sizeof(ino_tree_node_t *) * agcount); + + full_backptrs = 0; + + return; +} + +#ifdef XR_INO_REF_DEBUG +void +add_inode_refchecked(xfs_ino_t ino, ino_tree_node_t *ino_rec, int ino_offset) +{ + XFS_INOPROC_SET_PROC((ino_rec), (ino_offset)); + + ASSERT(is_inode_refchecked(ino, ino_rec, ino_offset)); + + return; +} + +int +is_inode_refchecked(xfs_ino_t ino, ino_tree_node_t *ino_rec, int ino_offset) +{ + return(XFS_INOPROC_IS_PROC(ino_rec, ino_offset) == 0LL ? 0 : 1); +} +#endif /* XR_INO_REF_DEBUG */ diff -rNu linux-2.4.7/cmd/xfsprogs/repair/init.c linux-2.4-xfs/cmd/xfsprogs/repair/init.c --- linux-2.4.7/cmd/xfsprogs/repair/init.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/init.c Thu Mar 8 23:38:39 2001 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "globals.h" +#include "agheader.h" +#include "protos.h" +#include "err_protos.h" + +void +xfs_init(libxfs_init_t *args) +{ + memset(args, 0, sizeof(libxfs_init_t)); + + if (isa_file) { + args->disfile = 1; + args->dname = fs_name; + args->volname = NULL; + } else { + args->disfile = 0; + args->volname = fs_name; + args->dname = NULL; + } + + if (log_spec) { /* External log specified */ + args->logname = log_name; + args->lisfile = (isa_file?1:0); + /* XXX assume data file also means log file */ + /* REVISIT: Need to do fs sanity / log validity checking */ + } + + args->notvolmsg = "you should never get this message - %s"; + args->notvolok = 1; + args->setblksize = 1; + + if (no_modify) + args->isreadonly = (LIBXFS_ISREADONLY | LIBXFS_ISINACTIVE); + + if (!libxfs_init(args)) + do_error("couldn't initialize XFS library\n"); +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/io.c linux-2.4-xfs/cmd/xfsprogs/repair/io.c --- linux-2.4.7/cmd/xfsprogs/repair/io.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/io.c Wed May 9 01:56:06 2001 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "globals.h" +#include "agheader.h" +#include "protos.h" +#include "err_protos.h" + +void +io_init(void) +{ + int i; + + /* open up filesystem device */ + + ASSERT(fs_name != NULL && *fs_name != '\0'); + + if ((fs_fd = open (fs_name, O_RDWR)) < 0) { + do_error("couldn't open filesystem \"%s\"\n", + fs_name); + } + + /* initialize i/o buffers */ + + iobuf_size = 1000 * 1024; + smallbuf_size = 4 * 4096; /* enough for an ag */ + + /* + * sbbuf_size must be < XFS_MIN_AG_BLOCKS (64) * smallest block size, + * otherwise you might get an EOF when reading in the sb/agf from + * the last ag if that ag is small + */ + sbbuf_size = 2 * 4096; /* 2 * max sector size */ + + if ((iobuf = malloc(iobuf_size)) == NULL) + do_error("couldn't malloc io buffer\n"); + + if ((smallbuf = malloc(smallbuf_size)) == NULL) + do_error("couldn't malloc secondary io buffer\n"); + + for (i = 0; i < NUM_SBS; i++) { + if ((sb_bufs[i] = malloc(sbbuf_size)) == NULL) + do_error("couldn't malloc sb io buffers\n"); + } +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/phase1.c linux-2.4-xfs/cmd/xfsprogs/repair/phase1.c --- linux-2.4.7/cmd/xfsprogs/repair/phase1.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/phase1.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "globals.h" +#include "agheader.h" +#include "protos.h" +#include "err_protos.h" + +void +no_sb(void) +{ + do_warn("Sorry, could not find valid secondary superblock\n"); + do_warn("Exiting now.\n"); + exit(1); +} + +char * +alloc_ag_buf(int size) +{ + char *bp; + + bp = (char *)memalign(MEM_ALIGN, size); + if (!bp) + do_error("could not allocate ag header buffer (%d bytes)\n", + size); + return(bp); +} + +/* + * this has got to be big enough to hold 4 sectors + */ +#define MAX_SECTSIZE (512 * 1024) + +/* ARGSUSED */ +void +phase1(xfs_mount_t *mp) +{ + xfs_sb_t *sb; + char *ag_bp; + int rval; + + io_init(); + + do_log("Phase 1 - find and verify superblock...\n"); + + primary_sb_modified = 0; + need_root_inode = 0; + need_root_dotdot = 0; + need_rbmino = 0; + need_rsumino = 0; + lost_quotas = 0; + old_orphanage_ino = (xfs_ino_t) 0; + + /* + * get AG 0 into ag header buf + */ + ag_bp = alloc_ag_buf(MAX_SECTSIZE); + sb = (xfs_sb_t *) ag_bp; + + if (get_sb(sb, 0LL, MAX_SECTSIZE, 0) == XR_EOF) { + do_error("error reading primary superblock\n"); + } + + /* + * is this really an sb, verify internal consistency + */ + if ((rval = verify_sb(sb, 1)) != XR_OK) { + do_warn("bad primary superblock - %s !!!\n", + err_string(rval)); + if (!find_secondary_sb(sb)) + no_sb(); + primary_sb_modified = 1; + } else if ((rval = verify_set_primary_sb(sb, 0, + &primary_sb_modified)) != XR_OK) { + do_warn("couldn't verify primary superblock - %s !!!\n", + err_string(rval)); + if (!find_secondary_sb(sb)) + no_sb(); + primary_sb_modified = 1; + } + + if (primary_sb_modified) { + if (!no_modify) { + do_warn("writing modified primary superblock\n"); + write_primary_sb(sb, sb->sb_sectsize); + } else { + do_warn("would write modified primary superblock\n"); + } + } + + /* + * misc. global var initialization + */ + sb_ifree = sb_icount = sb_fdblocks = sb_frextents = 0; + + free(sb); +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/phase2.c linux-2.4-xfs/cmd/xfsprogs/repair/phase2.c --- linux-2.4.7/cmd/xfsprogs/repair/phase2.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/phase2.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "avl.h" +#include "globals.h" +#include "agheader.h" +#include "protos.h" +#include "err_protos.h" +#include "incore.h" + +void set_mp(xfs_mount_t *mpp); +void scan_ag(xfs_agnumber_t agno); + +static void +zero_log(xfs_mount_t *mp, libxfs_init_t *args) +{ + int logdev = (mp->m_sb.sb_logstart == 0) ? args->logdev : args->ddev; + + libxfs_log_clear(logdev, + XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart), + (xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks), + &mp->m_sb.sb_uuid, + XLOG_FMT); +} + +/* + * ok, at this point, the fs is mounted but the root inode may be + * trashed and the ag headers haven't been checked. So we have + * a valid xfs_mount_t and superblock but that's about it. That + * means we can use macros that use mount/sb fields in calculations + * but I/O or btree routines that depend on space maps or inode maps + * being correct are verboten. + */ + +void +phase2(xfs_mount_t *mp, libxfs_init_t *args) +{ + xfs_agnumber_t i; + xfs_agblock_t b; + int j; + ino_tree_node_t *ino_rec; + + /* now we can start using the buffer cache routines */ + set_mp(mp); + + /* Check whether this fs has internal or external log */ + if (mp->m_sb.sb_logstart == 0) { + if (!args->logname) { + fprintf (stderr, + "This filesystem has an external log. " + "Specify log device with the -l option.\n"); + exit (1); + } + + fprintf (stderr, "Phase 2 - using external log on %s\n", + args->logname); + } else + fprintf (stderr, "Phase 2 - using internal log\n"); + + /* Zero log if applicable */ + if (!no_modify) { + do_log(" - zero log...\n"); + zero_log(mp, args); + } + + do_log(" - scan filesystem freespace and inode maps...\n"); + + /* + * account for space used by ag headers and log if internal + */ + set_bmap_log(mp); + set_bmap_fs(mp); + + bad_ino_btree = 0; + + for (i = 0; i < mp->m_sb.sb_agcount; i++) { + scan_ag(i); +#ifdef XR_INODE_TRACE + print_inode_list(i); +#endif + } + + /* + * make sure we know about the root inode chunk + */ + if ((ino_rec = find_inode_rec(0, mp->m_sb.sb_rootino)) == NULL) { + ASSERT(mp->m_sb.sb_rbmino == mp->m_sb.sb_rootino + 1 && + mp->m_sb.sb_rsumino == mp->m_sb.sb_rootino + 2); + do_warn("root inode chunk not found\n"); + + /* + * mark the first 3 used, the rest are free + */ + ino_rec = set_inode_used_alloc(0, + (xfs_agino_t) mp->m_sb.sb_rootino); + set_inode_used(ino_rec, 1); + set_inode_used(ino_rec, 2); + + for (j = 3; j < XFS_INODES_PER_CHUNK; j++) + set_inode_free(ino_rec, j); + + /* + * also mark blocks + */ + for (b = 0; b < mp->m_ialloc_blks; b++) { + set_agbno_state(mp, 0, + b + XFS_INO_TO_AGBNO(mp, mp->m_sb.sb_rootino), + XR_E_INO); + } + } else { + do_log(" - found root inode chunk\n"); + + /* + * blocks are marked, just make sure they're in use + */ + if (is_inode_free(ino_rec, 0)) { + do_warn("root inode marked free, "); + set_inode_used(ino_rec, 0); + if (!no_modify) + do_warn("correcting\n"); + else + do_warn("would correct\n"); + } + + if (is_inode_free(ino_rec, 1)) { + do_warn("realtime bitmap inode marked free, "); + set_inode_used(ino_rec, 1); + if (!no_modify) + do_warn("correcting\n"); + else + do_warn("would correct\n"); + } + + if (is_inode_free(ino_rec, 2)) { + do_warn("realtime summary inode marked free, "); + set_inode_used(ino_rec, 2); + if (!no_modify) + do_warn("correcting\n"); + else + do_warn("would correct\n"); + } + } +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/phase3.c linux-2.4-xfs/cmd/xfsprogs/repair/phase3.c --- linux-2.4.7/cmd/xfsprogs/repair/phase3.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/phase3.c Thu Apr 12 18:49:04 2001 @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "avl.h" +#include "globals.h" +#include "agheader.h" +#include "incore.h" +#include "protos.h" +#include "err_protos.h" +#include "dinode.h" + +/* + * walks an unlinked list, returns 1 on an error (bogus pointer) or + * I/O error + */ +int +walk_unlinked_list(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agino_t start_ino) +{ + xfs_buf_t *bp; + xfs_dinode_t *dip; + xfs_agino_t current_ino = start_ino; + xfs_agblock_t agbno; + int state; + + while (current_ino != NULLAGINO) { + if (!verify_aginum(mp, agno, current_ino)) + return(1); + if ((bp = get_agino_buf(mp, agno, current_ino, &dip)) == NULL) + return(1); + /* + * if this looks like a decent inode, then continue + * following the unlinked pointers. If not, bail. + */ + if (verify_dinode(mp, dip, agno, current_ino) == 0) { + /* + * check if the unlinked list points to an unknown + * inode. if so, put it on the uncertain inode list + * and set block map appropriately. + */ + if (find_inode_rec(agno, current_ino) == NULL) { + add_aginode_uncertain(agno, current_ino, 1); + agbno = XFS_AGINO_TO_AGBNO(mp, current_ino); + + switch (state = get_agbno_state(mp, + agno, agbno)) { + case XR_E_UNKNOWN: + case XR_E_FREE: + case XR_E_FREE1: + set_agbno_state(mp, agno, agbno, + XR_E_INO); + break; + case XR_E_BAD_STATE: + do_error( + "bad state in block map %d\n", + state); + abort(); + break; + default: + /* + * the block looks like inodes + * so be conservative and try + * to scavenge what's in there. + * if what's there is completely + * bogus, it'll show up later + * and the inode will be trashed + * anyway, hopefully without + * losing too much other data + */ + set_agbno_state(mp, agno, agbno, + XR_E_INO); + break; + } + } + current_ino = dip->di_next_unlinked; + } else { + current_ino = NULLAGINO;; + } + libxfs_putbuf(bp); + } + + return(0); +} + +void +process_agi_unlinked(xfs_mount_t *mp, xfs_agnumber_t agno) +{ + xfs_agnumber_t i; + xfs_buf_t *bp; + xfs_agi_t *agip; + int err = 0; + int agi_dirty = 0; + + bp = libxfs_readbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR), + mp->m_sb.sb_sectsize/BBSIZE, 0); + if (!bp) { + do_error("cannot read agi block %lld for ag %u\n", + XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR), agno); + exit(1); + } + + agip = XFS_BUF_TO_AGI(bp); + + ASSERT(no_modify || INT_GET(agip->agi_seqno, ARCH_CONVERT) == agno); + + for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) { + if (INT_GET(agip->agi_unlinked[i], ARCH_CONVERT) != NULLAGINO) { + err += walk_unlinked_list(mp, agno, + INT_GET(agip->agi_unlinked[i], ARCH_CONVERT)); + /* + * clear the list + */ + if (!no_modify) { + INT_SET(agip->agi_unlinked[i], ARCH_CONVERT, NULLAGINO); + agi_dirty = 1; + } + } + } + + if (err) + do_warn("error following ag %d unlinked list\n", agno); + + ASSERT(agi_dirty == 0 || (agi_dirty && !no_modify)); + + if (agi_dirty && !no_modify) + libxfs_writebuf(bp, 0); + else + libxfs_putbuf(bp); +} + +void +phase3(xfs_mount_t *mp) +{ + int i, j; + + printf("Phase 3 - for each AG...\n"); + if (!no_modify) + printf(" - scan and clear agi unlinked lists...\n"); + else + printf(" - scan (but don't clear) agi unlinked lists...\n"); + + /* + * first, let's look at the possibly bogus inodes + */ + for (i = 0; i < mp->m_sb.sb_agcount; i++) { + /* + * walk unlinked list to add more potential inodes to list + */ + process_agi_unlinked(mp, i); + check_uncertain_aginodes(mp, i); + } + + /* ok, now that the tree's ok, let's take a good look */ + + printf( + " - process known inodes and perform inode discovery...\n"); + + for (i = 0; i < mp->m_sb.sb_agcount; i++) { + do_log(" - agno = %d\n", i); + /* + * turn on directory processing (inode discovery) and + * attribute processing (extra_attr_check) + */ + process_aginodes(mp, i, 1, 0, 1); + } + + /* + * process newly discovered inode chunks + */ + printf(" - process newly discovered inodes...\n"); + do { + /* + * have to loop until no ag has any uncertain + * inodes + */ + j = 0; + for (i = 0; i < mp->m_sb.sb_agcount; i++) { + j += process_uncertain_aginodes(mp, i); +#ifdef XR_INODE_TRACE + fprintf(stderr, + "\t\t phase 3 - process_uncertain_inodes returns %d\n", j); +#endif + } + } while (j != 0); +} + diff -rNu linux-2.4.7/cmd/xfsprogs/repair/phase4.c linux-2.4-xfs/cmd/xfsprogs/repair/phase4.c --- linux-2.4.7/cmd/xfsprogs/repair/phase4.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/phase4.c Thu Apr 12 18:49:04 2001 @@ -0,0 +1,1337 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "avl.h" +#include "globals.h" +#include "agheader.h" +#include "incore.h" +#include "protos.h" +#include "err_protos.h" +#include "dinode.h" +#include "dir.h" +#include "bmap.h" +#include "versions.h" +#include "dir2.h" + + +/* ARGSUSED */ +int +lf_block_delete_orphanage(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dir_leafblock_t *leaf, + int *dirty, + xfs_buf_t *rootino_bp, + int *rbuf_dirty) +{ + xfs_dir_leaf_entry_t *entry; + xfs_dinode_t *dino; + xfs_buf_t *bp; + ino_tree_node_t *irec; + xfs_ino_t lino; + xfs_dir_leaf_name_t *namest; + xfs_agino_t agino; + xfs_agnumber_t agno; + xfs_agino_t root_agino; + xfs_agnumber_t root_agno; + int i; + int ino_offset; + int ino_dirty; + int use_rbuf; + int len; + char fname[MAXNAMELEN + 1]; + int res; + + entry = &leaf->entries[0]; + *dirty = 0; + use_rbuf = 0; + res = 0; + root_agno = XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino); + root_agino = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino); + + for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, + INT_GET(entry->nameidx, ARCH_CONVERT)); + XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &lino, ARCH_CONVERT); + bcopy(namest->name, fname, entry->namelen); + fname[entry->namelen] = '\0'; + + if (fname[0] != '/' && !strcmp(fname, ORPHANAGE)) { + agino = XFS_INO_TO_AGINO(mp, lino); + agno = XFS_INO_TO_AGNO(mp, lino); + + old_orphanage_ino = lino; + + irec = find_inode_rec(agno, agino); + + /* + * if the orphange inode is in the tree, + * get it, clear it, and mark it free. + * the inodes in the orphanage will get + * reattached to the new orphanage. + */ + if (irec != NULL) { + ino_offset = agino - irec->ino_startnum; + + /* + * check if we have to use the root inode + * buffer or read one in ourselves. Note + * that the root inode is always the first + * inode of the chunk that it's in so there + * are two possible cases where lost+found + * might be in the same buffer as the root + * inode. One case is a large block + * filesystem where the two inodes are + * in different inode chunks but wind + * up in the same block (multiple chunks + * per block) and the second case (one or + * more blocks per chunk) is where the two + * inodes are in the same chunk. Note that + * inodes are allocated on disk in units + * of MAX(XFS_INODES_PER_CHUNK,sb_inopblock). + */ + if (XFS_INO_TO_FSB(mp, mp->m_sb.sb_rootino) + == XFS_INO_TO_FSB(mp, lino) || + (agno == root_agno && + agino < root_agino + XFS_INODES_PER_CHUNK)) { + use_rbuf = 1; + bp = rootino_bp; + dino = XFS_MAKE_IPTR(mp, bp, agino - + XFS_INO_TO_AGINO(mp, + mp->m_sb.sb_rootino)); + } else { + len = (int)XFS_FSB_TO_BB(mp, + MAX(1, XFS_INODES_PER_CHUNK/ + inodes_per_block)); + bp = libxfs_readbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, agno, + XFS_AGINO_TO_AGBNO(mp, + irec->ino_startnum)), + len, 0); + if (!bp) + do_error("couldn't read %s inode %llu\n", + ORPHANAGE, lino); + + /* + * get the agbno containing the first + * inode in the chunk. In multi-block + * chunks, this gets us the offset + * relative to the beginning of a + * properly aligned buffer. In + * multi-chunk blocks, this gets us + * the correct block number. Then + * turn the block number back into + * an agino and calculate the offset + * from there to feed to make the iptr. + * the last term in effect rounds down + * to the first agino in the buffer. + */ + dino = XFS_MAKE_IPTR(mp, bp, + agino - XFS_OFFBNO_TO_AGINO(mp, + XFS_AGINO_TO_AGBNO(mp, + irec->ino_startnum), + 0)); + } + + do_warn(" - clearing existing \"%s\" inode\n", + ORPHANAGE); + + ino_dirty = clear_dinode(mp, dino, lino); + + if (!use_rbuf) { + ASSERT(ino_dirty == 0 || + (ino_dirty && !no_modify)); + + if (ino_dirty && !no_modify) + libxfs_writebuf(bp, 0); + else + libxfs_putbuf(bp); + } else { + if (ino_dirty) + *rbuf_dirty = 1; + } + + if (inode_isadir(irec, ino_offset)) + clear_inode_isadir(irec, ino_offset); + + set_inode_free(irec, ino_offset); + } + + /* + * regardless of whether the inode num is good or + * bad, mark the entry to be junked so the + * createname in phase 6 will succeed. + */ + namest->name[0] = '/'; + *dirty = 1; + do_warn(" - marking entry \"%s\" to be deleted\n", fname); + res++; + } + } + + return(res); +} + +int +longform_delete_orphanage(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dino, + xfs_buf_t *rootino_bp, + int *rbuf_dirty) +{ + xfs_dir_leafblock_t *leaf; + xfs_buf_t *bp; + xfs_dfsbno_t fsbno; + xfs_dablk_t da_bno; + int dirty; + int res; + + da_bno = 0; + *rbuf_dirty = 0; + + if ((fsbno = get_first_dblock_fsbno(mp, ino, dino)) == NULLDFSBNO) { + do_error("couldn't map first leaf block of directory inode %llu\n", ino); + exit(1); + } + + /* + * cycle through the entire directory looking to delete + * every "lost+found" entry. make sure to catch duplicate + * entries. + * + * We could probably speed this up by doing a smarter lookup + * to get us to the first block that contains the hashvalue + * of "lost+found" but what the heck. that would require a + * double lookup for each level. and how big can '/' get??? + * It's probably not worth it. + */ + res = 0; + + do { + ASSERT(fsbno != NULLDFSBNO); + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + do_error("can't read block %u (fsbno %llu) for directory inode " + "%llu\n", da_bno, fsbno, ino); + exit(1); + } + + leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp); + + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) { + do_error("bad magic # (0x%x) for directory leaf block " + "(bno %u fsbno %llu)\n", + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), + da_bno, fsbno); + exit(1); + } + + da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT); + + res += lf_block_delete_orphanage(mp, ino, leaf, &dirty, + rootino_bp, rbuf_dirty); + + ASSERT(dirty == 0 || (dirty && !no_modify)); + + if (dirty && !no_modify) + libxfs_writebuf(bp, 0); + else + libxfs_putbuf(bp); + + if (da_bno != 0) + fsbno = get_bmapi(mp, dino, ino, da_bno, XFS_DATA_FORK); + + } while (da_bno != 0); + + return(res); +} + +/* + * returns 1 if a deletion happened, 0 otherwise. + */ +/* ARGSUSED */ +int +shortform_delete_orphanage(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *root_dino, + xfs_buf_t *rootino_bp, + int *ino_dirty) +{ + xfs_dir_shortform_t *sf; + xfs_dinode_t *dino; + xfs_dir_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe; + xfs_buf_t *bp; + xfs_ino_t lino; + xfs_agino_t agino; + xfs_agino_t root_agino; + int max_size; + xfs_agnumber_t agno; + xfs_agnumber_t root_agno; + int ino_dir_size; + ino_tree_node_t *irec; + int ino_offset; + int i; + int dirty; + int tmp_len; + int tmp_elen; + int len; + int use_rbuf; + char fname[MAXNAMELEN + 1]; + int res; + + sf = &root_dino->di_u.di_dirsf; + *ino_dirty = 0; + res = 0; + irec = NULL; + ino_dir_size = INT_GET(root_dino->di_core.di_size, ARCH_CONVERT); + max_size = XFS_DFORK_DSIZE_ARCH(root_dino, mp, ARCH_CONVERT); + use_rbuf = 0; + root_agno = XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino); + root_agino = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino); + + /* + * run through entries looking for "lost+found". + */ + sf_entry = next_sfe = &sf->list[0]; + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT) && ino_dir_size > + (__psint_t)next_sfe - (__psint_t)sf; i++) { + tmp_sfe = NULL; + sf_entry = next_sfe; + XFS_DIR_SF_GET_DIRINO_ARCH(&sf_entry->inumber, &lino, ARCH_CONVERT); + bcopy(sf_entry->name, fname, sf_entry->namelen); + fname[sf_entry->namelen] = '\0'; + + if (!strcmp(ORPHANAGE, fname)) { + agno = XFS_INO_TO_AGNO(mp, lino); + agino = XFS_INO_TO_AGINO(mp, lino); + + irec = find_inode_rec(agno, agino); + + /* + * if the orphange inode is in the tree, + * get it, clear it, and mark it free. + * the inodes in the orphanage will get + * reattached to the new orphanage. + */ + if (irec != NULL) { + do_warn(" - clearing existing \"%s\" inode\n", + ORPHANAGE); + + ino_offset = agino - irec->ino_startnum; + + /* + * check if we have to use the root inode + * buffer or read one in ourselves. Note + * that the root inode is always the first + * inode of the chunk that it's in so there + * are two possible cases where lost+found + * might be in the same buffer as the root + * inode. One case is a large block + * filesystem where the two inodes are + * in different inode chunks but wind + * up in the same block (multiple chunks + * per block) and the second case (one or + * more blocks per chunk) is where the two + * inodes are in the same chunk. Note that + * inodes are allocated on disk in units + * of MAX(XFS_INODES_PER_CHUNK,sb_inopblock). + */ + if (XFS_INO_TO_FSB(mp, mp->m_sb.sb_rootino) + == XFS_INO_TO_FSB(mp, lino) || + (agno == root_agno && + agino < root_agino + XFS_INODES_PER_CHUNK)) { + use_rbuf = 1; + bp = rootino_bp; + + dino = XFS_MAKE_IPTR(mp, bp, agino - + XFS_INO_TO_AGINO(mp, + mp->m_sb.sb_rootino)); + } else { + len = (int)XFS_FSB_TO_BB(mp, + MAX(1, XFS_INODES_PER_CHUNK/ + inodes_per_block)); + bp = libxfs_readbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, agno, + XFS_AGINO_TO_AGBNO(mp, + irec->ino_startnum)), + len, 0); + if (!bp) + do_error("could not read %s inode " + "%llu\n", ORPHANAGE, lino); + /* + * get the agbno containing the first + * inode in the chunk. In multi-block + * chunks, this gets us the offset + * relative to the beginning of a + * properly aligned buffer. In + * multi-chunk blocks, this gets us + * the correct block number. Then + * turn the block number back into + * an agino and calculate the offset + * from there to feed to make the iptr. + * the last term in effect rounds down + * to the first agino in the buffer. + */ + dino = XFS_MAKE_IPTR(mp, bp, + agino - XFS_OFFBNO_TO_AGINO(mp, + XFS_AGINO_TO_AGBNO(mp, + irec->ino_startnum), + 0)); + } + + dirty = clear_dinode(mp, dino, lino); + + ASSERT(dirty == 0 || (dirty && !no_modify)); + + /* + * if we read the lost+found inode in to + * it, get rid of it here. if the lost+found + * inode is in the root inode buffer, the + * buffer will be marked dirty anyway since + * the lost+found entry in the root inode is + * also being deleted which makes the root + * inode buffer automatically dirty. + */ + if (!use_rbuf) { + dino = NULL; + if (dirty && !no_modify) + libxfs_writebuf(bp, 0); + else + libxfs_putbuf(bp); + } + + if (inode_isadir(irec, ino_offset)) + clear_inode_isadir(irec, ino_offset); + + set_inode_free(irec, ino_offset); + } + + do_warn(" - deleting existing \"%s\" entry\n", + ORPHANAGE); + + /* + * note -- exactly the same deletion code as in + * process_shortform_dir() + */ + tmp_elen = XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry); + INT_MOD(root_dino->di_core.di_size, ARCH_CONVERT, -(tmp_elen)); + + tmp_sfe = (xfs_dir_sf_entry_t *) + ((__psint_t) sf_entry + tmp_elen); + tmp_len = max_size - ((__psint_t) tmp_sfe + - (__psint_t) sf); + + memmove(sf_entry, tmp_sfe, tmp_len); + + INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); + + bzero((void *) ((__psint_t) sf_entry + tmp_len), + tmp_elen); + + /* + * set the tmp value to the current + * pointer so we'll process the entry + * we just moved up + */ + tmp_sfe = sf_entry; + + /* + * WARNING: drop the index i by one + * so it matches the decremented count for + * accurate comparisons in the loop test. + * mark root inode as dirty to make deletion + * permanent. + */ + i--; + + *ino_dirty = 1; + res++; + + } + next_sfe = (tmp_sfe == NULL) + ? (xfs_dir_sf_entry_t *) ((__psint_t) sf_entry + + XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry)) + : tmp_sfe; + } + + return(res); +} + +/* ARGSUSED */ +int +lf2_block_delete_orphanage(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dir2_data_t *data, + int *dirty, + xfs_buf_t *rootino_bp, + int *rbuf_dirty) +{ + xfs_dinode_t *dino; + xfs_buf_t *bp; + ino_tree_node_t *irec; + xfs_ino_t lino; + xfs_agino_t agino; + xfs_agnumber_t agno; + xfs_agino_t root_agino; + xfs_agnumber_t root_agno; + int ino_offset; + int ino_dirty; + int use_rbuf; + int len; + char fname[MAXNAMELEN + 1]; + int res; + char *ptr; + char *endptr; + xfs_dir2_block_tail_t *btp; + xfs_dir2_data_entry_t *dep; + xfs_dir2_data_unused_t *dup; + + ptr = (char *)data->u; + if (INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)data); + endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + } else + endptr = (char *)data + mp->m_dirblksize; + *dirty = 0; + use_rbuf = 0; + res = 0; + root_agno = XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino); + root_agino = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino); + + while (ptr < endptr) { + dup = (xfs_dir2_data_unused_t *)ptr; + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + if (ptr + INT_GET(dup->length, ARCH_CONVERT) > endptr || + INT_GET(dup->length, ARCH_CONVERT) == 0 || + (INT_GET(dup->length, ARCH_CONVERT) & + (XFS_DIR2_DATA_ALIGN - 1))) + break; + ptr += INT_GET(dup->length, ARCH_CONVERT); + continue; + } + dep = (xfs_dir2_data_entry_t *)ptr; + lino = INT_GET(dep->inumber, ARCH_CONVERT); + bcopy(dep->name, fname, dep->namelen); + fname[dep->namelen] = '\0'; + + if (fname[0] != '/' && !strcmp(fname, ORPHANAGE)) { + agino = XFS_INO_TO_AGINO(mp, lino); + agno = XFS_INO_TO_AGNO(mp, lino); + + old_orphanage_ino = lino; + + irec = find_inode_rec(agno, agino); + + /* + * if the orphange inode is in the tree, + * get it, clear it, and mark it free. + * the inodes in the orphanage will get + * reattached to the new orphanage. + */ + if (irec != NULL) { + ino_offset = agino - irec->ino_startnum; + + /* + * check if we have to use the root inode + * buffer or read one in ourselves. Note + * that the root inode is always the first + * inode of the chunk that it's in so there + * are two possible cases where lost+found + * might be in the same buffer as the root + * inode. One case is a large block + * filesystem where the two inodes are + * in different inode chunks but wind + * up in the same block (multiple chunks + * per block) and the second case (one or + * more blocks per chunk) is where the two + * inodes are in the same chunk. Note that + * inodes are allocated on disk in units + * of MAX(XFS_INODES_PER_CHUNK,sb_inopblock). + */ + if (XFS_INO_TO_FSB(mp, mp->m_sb.sb_rootino) + == XFS_INO_TO_FSB(mp, lino) || + (agno == root_agno && + agino < root_agino + XFS_INODES_PER_CHUNK)) { + use_rbuf = 1; + bp = rootino_bp; + dino = XFS_MAKE_IPTR(mp, bp, agino - + XFS_INO_TO_AGINO(mp, + mp->m_sb.sb_rootino)); + } else { + len = (int)XFS_FSB_TO_BB(mp, + MAX(1, XFS_INODES_PER_CHUNK/ + inodes_per_block)); + bp = libxfs_readbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, agno, + XFS_AGINO_TO_AGBNO(mp, + irec->ino_startnum)), + len, 0); + if (!bp) + do_error("couldn't read %s inode %llu\n", + ORPHANAGE, lino); + + /* + * get the agbno containing the first + * inode in the chunk. In multi-block + * chunks, this gets us the offset + * relative to the beginning of a + * properly aligned buffer. In + * multi-chunk blocks, this gets us + * the correct block number. Then + * turn the block number back into + * an agino and calculate the offset + * from there to feed to make the iptr. + * the last term in effect rounds down + * to the first agino in the buffer. + */ + dino = XFS_MAKE_IPTR(mp, bp, + agino - XFS_OFFBNO_TO_AGINO(mp, + XFS_AGINO_TO_AGBNO(mp, + irec->ino_startnum), + 0)); + } + + do_warn(" - clearing existing \"%s\" inode\n", + ORPHANAGE); + + ino_dirty = clear_dinode(mp, dino, lino); + + if (!use_rbuf) { + ASSERT(ino_dirty == 0 || + (ino_dirty && !no_modify)); + + if (ino_dirty && !no_modify) + libxfs_writebuf(bp, 0); + else + libxfs_putbuf(bp); + } else { + if (ino_dirty) + *rbuf_dirty = 1; + } + + if (inode_isadir(irec, ino_offset)) + clear_inode_isadir(irec, ino_offset); + + set_inode_free(irec, ino_offset); + + } + + /* + * regardless of whether the inode num is good or + * bad, mark the entry to be junked so the + * createname in phase 6 will succeed. + */ + dep->name[0] = '/'; + *dirty = 1; + do_warn( + " - marking entry \"%s\" to be deleted\n", + fname); + res++; + } + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + + return(res); +} + +int +longform2_delete_orphanage(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *dino, + xfs_buf_t *rootino_bp, + int *rbuf_dirty) +{ + xfs_dir2_data_t *data; + xfs_dabuf_t *bp; + xfs_dfsbno_t fsbno; + xfs_dablk_t da_bno; + int dirty; + int res; + bmap_ext_t *bmp; + int i; + + da_bno = 0; + *rbuf_dirty = 0; + fsbno = NULLDFSBNO; + bmp = malloc(mp->m_dirblkfsbs * sizeof(*bmp)); + if (!bmp) { + do_error( + "malloc failed (%u bytes) in longform2_delete_orphanage, ino %llu\n", + mp->m_dirblkfsbs * sizeof(*bmp), ino); + exit(1); + } + + /* + * cycle through the entire directory looking to delete + * every "lost+found" entry. make sure to catch duplicate + * entries. + * + * We could probably speed this up by doing a smarter lookup + * to get us to the first block that contains the hashvalue + * of "lost+found" but what the heck. that would require a + * double lookup for each level. and how big can '/' get??? + * It's probably not worth it. + */ + res = 0; + + for (da_bno = 0; + da_bno < XFS_B_TO_FSB(mp, INT_GET(dino->di_core.di_size, ARCH_CONVERT)); + da_bno += mp->m_dirblkfsbs) { + for (i = 0; i < mp->m_dirblkfsbs; i++) { + fsbno = get_bmapi(mp, dino, ino, da_bno + i, + XFS_DATA_FORK); + if (fsbno == NULLDFSBNO) + break; + bmp[i].startoff = da_bno + i; + bmp[i].startblock = fsbno; + bmp[i].blockcount = 1; + bmp[i].flag = 0; + } + if (fsbno == NULLDFSBNO) + continue; + bp = da_read_buf(mp, mp->m_dirblkfsbs, bmp); + if (bp == NULL) { + do_error( + "can't read block %u (fsbno %llu) for directory inode %llu\n", + da_bno, bmp[0].startblock, ino); + exit(1); + } + + data = (xfs_dir2_data_t *)bp->data; + + if (INT_GET(data->hdr.magic, ARCH_CONVERT) != XFS_DIR2_DATA_MAGIC && + INT_GET(data->hdr.magic, ARCH_CONVERT) != XFS_DIR2_BLOCK_MAGIC) { + do_error( + "bad magic # (0x%x) for directory data block (bno %u fsbno %llu)\n", + INT_GET(data->hdr.magic, ARCH_CONVERT), da_bno, bmp[0].startblock); + exit(1); + } + + res += lf2_block_delete_orphanage(mp, ino, data, &dirty, + rootino_bp, rbuf_dirty); + + ASSERT(dirty == 0 || (dirty && !no_modify)); + + if (dirty && !no_modify) + da_bwrite(mp, bp); + else + da_brelse(bp); + } + free(bmp); + + return(res); +} + +/* + * returns 1 if a deletion happened, 0 otherwise. + */ +/* ARGSUSED */ +int +shortform2_delete_orphanage(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dinode_t *root_dino, + xfs_buf_t *rootino_bp, + int *ino_dirty) +{ + xfs_dir2_sf_t *sf; + xfs_dinode_t *dino; + xfs_dir2_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe; + xfs_buf_t *bp; + xfs_ino_t lino; + xfs_agino_t agino; + xfs_agino_t root_agino; + int max_size; + xfs_agnumber_t agno; + xfs_agnumber_t root_agno; + int ino_dir_size; + ino_tree_node_t *irec; + int ino_offset; + int i; + int dirty; + int tmp_len; + int tmp_elen; + int len; + int use_rbuf; + char fname[MAXNAMELEN + 1]; + int res; + + sf = &root_dino->di_u.di_dir2sf; + *ino_dirty = 0; + irec = NULL; + ino_dir_size = INT_GET(root_dino->di_core.di_size, ARCH_CONVERT); + max_size = XFS_DFORK_DSIZE_ARCH(root_dino, mp, ARCH_CONVERT); + use_rbuf = 0; + res = 0; + root_agno = XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino); + root_agino = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino); + + /* + * run through entries looking for "lost+found". + */ + sf_entry = next_sfe = XFS_DIR2_SF_FIRSTENTRY(sf); + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT) && ino_dir_size > + (__psint_t)next_sfe - (__psint_t)sf; i++) { + tmp_sfe = NULL; + sf_entry = next_sfe; + lino = XFS_DIR2_SF_GET_INUMBER_ARCH(sf, + XFS_DIR2_SF_INUMBERP(sf_entry), ARCH_CONVERT); + bcopy(sf_entry->name, fname, sf_entry->namelen); + fname[sf_entry->namelen] = '\0'; + + if (!strcmp(ORPHANAGE, fname)) { + agno = XFS_INO_TO_AGNO(mp, lino); + agino = XFS_INO_TO_AGINO(mp, lino); + + irec = find_inode_rec(agno, agino); + + /* + * if the orphange inode is in the tree, + * get it, clear it, and mark it free. + * the inodes in the orphanage will get + * reattached to the new orphanage. + */ + if (irec != NULL) { + do_warn(" - clearing existing \"%s\" inode\n", + ORPHANAGE); + + ino_offset = agino - irec->ino_startnum; + + /* + * check if we have to use the root inode + * buffer or read one in ourselves. Note + * that the root inode is always the first + * inode of the chunk that it's in so there + * are two possible cases where lost+found + * might be in the same buffer as the root + * inode. One case is a large block + * filesystem where the two inodes are + * in different inode chunks but wind + * up in the same block (multiple chunks + * per block) and the second case (one or + * more blocks per chunk) is where the two + * inodes are in the same chunk. Note that + * inodes are allocated on disk in units + * of MAX(XFS_INODES_PER_CHUNK,sb_inopblock). + */ + if (XFS_INO_TO_FSB(mp, mp->m_sb.sb_rootino) + == XFS_INO_TO_FSB(mp, lino) || + (agno == root_agno && + agino < root_agino + XFS_INODES_PER_CHUNK)) { + use_rbuf = 1; + bp = rootino_bp; + + dino = XFS_MAKE_IPTR(mp, bp, agino - + XFS_INO_TO_AGINO(mp, + mp->m_sb.sb_rootino)); + } else { + len = (int)XFS_FSB_TO_BB(mp, + MAX(1, XFS_INODES_PER_CHUNK/ + inodes_per_block)); + bp = libxfs_readbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, agno, + XFS_AGINO_TO_AGBNO(mp, + irec->ino_startnum)), + len, 0); + if (!bp) + do_error("could not read %s inode " + "%llu\n", ORPHANAGE, lino); + /* + * get the agbno containing the first + * inode in the chunk. In multi-block + * chunks, this gets us the offset + * relative to the beginning of a + * properly aligned buffer. In + * multi-chunk blocks, this gets us + * the correct block number. Then + * turn the block number back into + * an agino and calculate the offset + * from there to feed to make the iptr. + * the last term in effect rounds down + * to the first agino in the buffer. + */ + dino = XFS_MAKE_IPTR(mp, bp, + agino - XFS_OFFBNO_TO_AGINO(mp, + XFS_AGINO_TO_AGBNO(mp, + irec->ino_startnum), + 0)); + } + + dirty = clear_dinode(mp, dino, lino); + + ASSERT(dirty == 0 || (dirty && !no_modify)); + + /* + * if we read the lost+found inode in to + * it, get rid of it here. if the lost+found + * inode is in the root inode buffer, the + * buffer will be marked dirty anyway since + * the lost+found entry in the root inode is + * also being deleted which makes the root + * inode buffer automatically dirty. + */ + if (!use_rbuf) { + dino = NULL; + if (dirty && !no_modify) + libxfs_writebuf(bp, 0); + else + libxfs_putbuf(bp); + } + + + if (inode_isadir(irec, ino_offset)) + clear_inode_isadir(irec, ino_offset); + + set_inode_free(irec, ino_offset); + } + + do_warn(" - deleting existing \"%s\" entry\n", + ORPHANAGE); + + /* + * note -- exactly the same deletion code as in + * process_shortform_dir() + */ + tmp_elen = XFS_DIR2_SF_ENTSIZE_BYENTRY(sf, sf_entry); + INT_MOD(root_dino->di_core.di_size, ARCH_CONVERT, -(tmp_elen)); + + tmp_sfe = (xfs_dir2_sf_entry_t *) + ((__psint_t) sf_entry + tmp_elen); + tmp_len = max_size - ((__psint_t) tmp_sfe + - (__psint_t) sf); + + memmove(sf_entry, tmp_sfe, tmp_len); + + INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); + if (lino > XFS_DIR2_MAX_SHORT_INUM) + sf->hdr.i8count--; + + bzero((void *) ((__psint_t) sf_entry + tmp_len), + tmp_elen); + + /* + * set the tmp value to the current + * pointer so we'll process the entry + * we just moved up + */ + tmp_sfe = sf_entry; + + /* + * WARNING: drop the index i by one + * so it matches the decremented count for + * accurate comparisons in the loop test. + * mark root inode as dirty to make deletion + * permanent. + */ + i--; + + *ino_dirty = 1; + + res++; + } + next_sfe = (tmp_sfe == NULL) + ? (xfs_dir2_sf_entry_t *) ((__psint_t) sf_entry + + XFS_DIR2_SF_ENTSIZE_BYENTRY(sf, sf_entry)) + : tmp_sfe; + } + + return(res); +} + +void +delete_orphanage(xfs_mount_t *mp) +{ + xfs_ino_t ino; + xfs_dinode_t *dino; + xfs_buf_t *dbp; + int dirty, res, len; + + ASSERT(!no_modify); + + dbp = NULL; + dirty = res = 0; + ino = mp->m_sb.sb_rootino; + + /* + * we know the root is in use or we wouldn't be here + */ + len = (int)XFS_FSB_TO_BB(mp, + MAX(1, XFS_INODES_PER_CHUNK/inodes_per_block)); + dbp = libxfs_readbuf(mp->m_dev, + XFS_FSB_TO_DADDR(mp, XFS_INO_TO_FSB(mp, ino)), len, 0); + if (!dbp) { + do_error("could not read buffer for root inode %llu " + "(daddr %lld, size %d)\n", ino, + XFS_FSB_TO_DADDR(mp, XFS_INO_TO_FSB(mp, ino)), + XFS_FSB_TO_BB(mp, 1)); + } + + /* + * we also know that the root inode is always the first inode + * allocated in the system, therefore it'll be at the beginning + * of the root inode chunk + */ + dino = XFS_MAKE_IPTR(mp, dbp, 0); + + switch (dino->di_core.di_format) { + case XFS_DINODE_FMT_EXTENTS: + case XFS_DINODE_FMT_BTREE: + if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) + res = longform2_delete_orphanage(mp, ino, dino, dbp, + &dirty); + else + res = longform_delete_orphanage(mp, ino, dino, dbp, + &dirty); + break; + case XFS_DINODE_FMT_LOCAL: + if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) + res = shortform2_delete_orphanage(mp, ino, dino, dbp, + &dirty); + else + res = shortform_delete_orphanage(mp, ino, dino, dbp, + &dirty); + ASSERT((res == 0 && dirty == 0) || (res == 1 && dirty == 1)); + break; + default: + break; + } + + if (res) { + switch (dino->di_core.di_version) { + case XFS_DINODE_VERSION_1: + INT_MOD(dino->di_core.di_onlink, ARCH_CONVERT, -1); + INT_SET(dino->di_core.di_nlink, ARCH_CONVERT, + INT_GET(dino->di_core.di_onlink, ARCH_CONVERT)); + break; + case XFS_DINODE_VERSION_2: + INT_MOD(dino->di_core.di_nlink, ARCH_CONVERT, -1); + break; + default: + do_error("unknown version #%d in root inode\n", + dino->di_core.di_version); + } + + dirty = 1; + } + + if (dirty) + libxfs_writebuf(dbp, 0); + else + libxfs_putbuf(dbp); +} + +/* + * null out quota inode fields in sb if they point to non-existent inodes. + * this isn't as redundant as it looks since it's possible that the sb field + * might be set but the imap and inode(s) agree that the inode is + * free in which case they'd never be cleared so the fields wouldn't + * be cleared by process_dinode(). + */ +void +quotino_check(xfs_mount_t *mp) +{ + ino_tree_node_t *irec; + + if (mp->m_sb.sb_uquotino != NULLFSINO && mp->m_sb.sb_uquotino != 0) { + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_uquotino), + XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino)); + + if (irec == NULL || is_inode_free(irec, + mp->m_sb.sb_uquotino - irec->ino_startnum)) { + mp->m_sb.sb_uquotino = NULLFSINO; + lost_uquotino = 1; + } else + lost_uquotino = 0; + } + + if (mp->m_sb.sb_gquotino != NULLFSINO && mp->m_sb.sb_gquotino != 0) { + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_gquotino), + XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino)); + + if (irec == NULL || is_inode_free(irec, + mp->m_sb.sb_gquotino - irec->ino_startnum)) { + mp->m_sb.sb_gquotino = NULLFSINO; + lost_gquotino = 1; + } else + lost_gquotino = 0; + } +} + +void +quota_sb_check(xfs_mount_t *mp) +{ + /* + * if the sb says we have quotas and we lost both, + * signal a superblock downgrade. that will cause + * the quota flags to get zeroed. (if we only lost + * one quota inode, do nothing and complain later.) + * + * if the sb says we have quotas but we didn't start out + * with any quota inodes, signal a superblock downgrade. + * + * The sb downgrades are so that older systems can mount + * the filesystem. + * + * if the sb says we don't have quotas but it looks like + * we do have quota inodes, then signal a superblock upgrade. + * + * if the sb says we don't have quotas and we have no + * quota inodes, then leave will enough alone. + */ + + if (fs_quotas && + (mp->m_sb.sb_uquotino == NULLFSINO || mp->m_sb.sb_uquotino == 0) && + (mp->m_sb.sb_gquotino == NULLFSINO || mp->m_sb.sb_gquotino == 0)) { + lost_quotas = 1; + fs_quotas = 0; + } else if (!verify_inum(mp, mp->m_sb.sb_uquotino) && + !verify_inum(mp, mp->m_sb.sb_gquotino)) { + fs_quotas = 1; + } +} + + +void +phase4(xfs_mount_t *mp) +{ + ino_tree_node_t *irec; + xfs_drtbno_t bno; + xfs_drtbno_t rt_start; + xfs_extlen_t rt_len; + xfs_agnumber_t i; + xfs_agblock_t j; + xfs_agblock_t ag_end; + xfs_agblock_t extent_start; + xfs_extlen_t extent_len; + int ag_hdr_len = 4 * mp->m_sb.sb_sectsize; + int ag_hdr_block; + int bstate; + int count_bcnt_extents(xfs_agnumber_t agno); + int count_bno_extents(xfs_agnumber_t agno); + + ag_hdr_block = howmany(ag_hdr_len, mp->m_sb.sb_blocksize); + + printf("Phase 4 - check for duplicate blocks...\n"); + printf(" - setting up duplicate extent list...\n"); + + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino), + XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino)); + + /* + * we always have a root inode, even if it's free... + * if the root is free, forget it, lost+found is already gone + */ + if (is_inode_free(irec, 0) || !inode_isadir(irec, 0)) { + need_root_inode = 1; + if (no_modify) + do_warn("root inode would be lost\n"); + else + do_warn("root inode lost\n"); + } + + /* + * have to delete lost+found first so that blocks used + * by lost+found don't show up as used + */ + if (!no_modify) { + printf(" - clear lost+found (if it exists) ...\n"); + if (!need_root_inode) + delete_orphanage(mp); + } + + for (i = 0; i < mp->m_sb.sb_agcount; i++) { + ag_end = (i < mp->m_sb.sb_agcount - 1) ? mp->m_sb.sb_agblocks : + mp->m_sb.sb_dblocks - + (xfs_drfsbno_t) mp->m_sb.sb_agblocks * i; + extent_start = extent_len = 0; + /* + * set up duplicate extent list for this ag + */ + for (j = ag_hdr_block; j < ag_end; j++) { + + bstate = get_agbno_state(mp, i, j); + + switch (bstate) { + case XR_E_BAD_STATE: + default: + do_warn("unknown block state, ag %d, \ +block %d\n", + i, j); + /* fall through .. */ + case XR_E_UNKNOWN: + case XR_E_FREE1: + case XR_E_FREE: + case XR_E_INUSE: + case XR_E_INUSE_FS: + case XR_E_INO: + case XR_E_FS_MAP: + if (extent_start == 0) + continue; + else { + /* + * add extent and reset extent state + */ + add_dup_extent(i, extent_start, + extent_len); + extent_start = 0; + extent_len = 0; + } + break; + case XR_E_MULT: + if (extent_start == 0) { + extent_start = j; + extent_len = 1; + } else if (extent_len == MAXEXTLEN) { + add_dup_extent(i, extent_start, + extent_len); + extent_start = j; + extent_len = 1; + } else + extent_len++; + break; + } + } + /* + * catch tail-case, extent hitting the end of the ag + */ + if (extent_start != 0) + add_dup_extent(i, extent_start, extent_len); + } + + /* + * initialize realtime bitmap + */ + rt_start = 0; + rt_len = 0; + + for (bno = 0; bno < mp->m_sb.sb_rextents; bno++) { + + bstate = get_rtbno_state(mp, bno); + + switch (bstate) { + case XR_E_BAD_STATE: + default: + do_warn("unknown rt extent state, extent %llu\n", bno); + /* fall through .. */ + case XR_E_UNKNOWN: + case XR_E_FREE1: + case XR_E_FREE: + case XR_E_INUSE: + case XR_E_INUSE_FS: + case XR_E_INO: + case XR_E_FS_MAP: + if (rt_start == 0) + continue; + else { + /* + * add extent and reset extent state + */ + add_rt_dup_extent(rt_start, rt_len); + rt_start = 0; + rt_len = 0; + } + break; + case XR_E_MULT: + if (rt_start == 0) { + rt_start = bno; + rt_len = 1; + } else if (rt_len == MAXEXTLEN) { + /* + * large extent case + */ + add_rt_dup_extent(rt_start, rt_len); + rt_start = bno; + rt_len = 1; + } else + rt_len++; + break; + } + } + + /* + * catch tail-case, extent hitting the end of the ag + */ + if (rt_start != 0) + add_rt_dup_extent(rt_start, rt_len); + + /* + * initialize bitmaps for all AGs + */ + for (i = 0; i < mp->m_sb.sb_agcount; i++) { + ag_end = (i < mp->m_sb.sb_agcount - 1) ? mp->m_sb.sb_agblocks : + mp->m_sb.sb_dblocks - + (xfs_drfsbno_t) mp->m_sb.sb_agblocks * i; + /* + * now reset the bitmap for all ags + */ + bzero(ba_bmap[i], roundup(mp->m_sb.sb_agblocks*(NBBY/XR_BB), + sizeof(__uint64_t))); + for (j = 0; j < ag_hdr_block; j++) + set_agbno_state(mp, i, j, XR_E_INUSE_FS); + } + set_bmap_rt(mp->m_sb.sb_rextents); + set_bmap_log(mp); + set_bmap_fs(mp); + + printf(" - check for inodes claiming duplicate blocks...\n"); + for (i = 0; i < mp->m_sb.sb_agcount; i++) { + /* + * ok, now process the inodes -- signal 2-pass check per inode. + * first pass checks if the inode conflicts with a known + * duplicate extent. if so, the inode is cleared and second + * pass is skipped. second pass sets the block bitmap + * for all blocks claimed by the inode. directory + * and attribute processing is turned OFF since we did that + * already in phase 3. + */ + do_log(" - agno = %d\n", i); + process_aginodes(mp, i, 0, 1, 0); + + /* + * now recycle the per-AG duplicate extent records + */ + release_dup_extent_tree(i); + } + + /* + * free up memory used to track trealtime duplicate extents + */ + if (rt_start != 0) + free_rt_dup_extent_tree(mp); + + /* + * ensure consistency of quota inode pointers in superblock, + * make sure they point to real inodes + */ + quotino_check(mp); + quota_sb_check(mp); +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/phase5.c linux-2.4-xfs/cmd/xfsprogs/repair/phase5.c --- linux-2.4.7/cmd/xfsprogs/repair/phase5.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/phase5.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,1633 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "avl.h" +#include "globals.h" +#include "agheader.h" +#include "incore.h" +#include "protos.h" +#include "err_protos.h" +#include "dinode.h" +#include "rt.h" +#include "versions.h" + +/* + * we maintain the current slice (path from root to leaf) + * of the btree incore. when we need a new block, we ask + * the block allocator for the address of a block on that + * level, map the block in, and set up the appropriate + * pointers (child, silbing, etc.) and keys that should + * point to the new block. + */ +typedef struct bt_stat_level { + /* + * set in setup_cursor routine and maintained in the tree-building + * routines + */ + xfs_buf_t *buf_p; /* 2 buffer pointers to ... */ + xfs_buf_t *prev_buf_p; + xfs_agblock_t agbno; /* current block being filled */ + xfs_agblock_t prev_agbno; /* previous block */ + /* + * set in calculate/init cursor routines for each btree level + */ + int num_recs_tot; /* # tree recs in level */ + int num_blocks; /* # tree blocks in level */ + int num_recs_pb; /* num_recs_tot / num_blocks */ + int modulo; /* num_recs_tot % num_blocks */ +} bt_stat_level_t; + +typedef struct bt_status { + int init; /* cursor set up once? */ + int num_levels; /* # of levels in btree */ + xfs_extlen_t num_tot_blocks; /* # blocks alloc'ed for tree */ + xfs_extlen_t num_free_blocks;/* # blocks currently unused */ + + xfs_agblock_t root; /* root block */ + /* + * list of blocks to be used to set up this tree + * and pointer to the first unused block on the list + */ + xfs_agblock_t *btree_blocks; /* block list */ + xfs_agblock_t *free_btree_blocks; /* first unused block */ + /* + * per-level status info + */ + bt_stat_level_t level[XFS_BTREE_MAXLEVELS]; +} bt_status_t; + + +int +mk_incore_fstree(xfs_mount_t *mp, xfs_agnumber_t agno) +{ + int in_extent; + int num_extents; + xfs_agblock_t extent_start; + xfs_extlen_t extent_len; + xfs_agblock_t agbno; + xfs_agblock_t ag_end; + uint free_blocks; +#ifdef XR_BLD_FREE_TRACE + int old_state; + int state = XR_E_BAD_STATE; +#endif + + /* + * scan the bitmap for the ag looking for continuous + * extents of free blocks. At this point, we know + * that blocks in the bitmap are either set to an + * "in use" state or set to unknown (0) since the + * bmaps were bzero'ed in phase 4 and only blocks + * being used by inodes, inode bmaps, ag headers, + * and the files themselves were put into the bitmap. + * + */ + ASSERT(agno < mp->m_sb.sb_agcount); + + extent_start = extent_len = 0; + in_extent = 0; + num_extents = free_blocks = 0; + + if (agno < mp->m_sb.sb_agcount - 1) + ag_end = mp->m_sb.sb_agblocks; + else + ag_end = mp->m_sb.sb_dblocks - + mp->m_sb.sb_agblocks * (mp->m_sb.sb_agcount - 1); + + /* + * ok, now find the number of extents, keep track of the + * largest extent. + */ + for (agbno = 0; agbno < ag_end; agbno++) { +#if 0 + old_state = state; + state = get_agbno_state(mp, agno, agbno); + if (state != old_state) { + fprintf(stderr, "agbno %u - new state is %d\n", + agbno, state); + } +#endif + if (get_agbno_state(mp, agno, agbno) < XR_E_INUSE) { + free_blocks++; + if (in_extent == 0) { + /* + * found the start of a free extent + */ + in_extent = 1; + num_extents++; + extent_start = agbno; + extent_len = 1; + } else { + extent_len++; + } + } else { + if (in_extent) { + /* + * free extent ends here, add extent to the + * 2 incore extent (avl-to-be-B+) trees + */ + in_extent = 0; +#if defined(XR_BLD_FREE_TRACE) && defined(XR_BLD_ADD_EXTENT) + fprintf(stderr, "adding extent %u [%u %u]\n", + agno, extent_start, extent_len); +#endif + add_bno_extent(agno, extent_start, extent_len); + add_bcnt_extent(agno, extent_start, extent_len); + } + } + } + if (in_extent) { + /* + * free extent ends here + */ + in_extent = 0; +#if defined(XR_BLD_FREE_TRACE) && defined(XR_BLD_ADD_EXTENT) + fprintf(stderr, "adding extent %u [%u %u]\n", + agno, extent_start, extent_len); +#endif + add_bno_extent(agno, extent_start, extent_len); + add_bcnt_extent(agno, extent_start, extent_len); + } + + return(num_extents); +} + +/* ARGSUSED */ +xfs_agblock_t +get_next_blockaddr(xfs_agnumber_t agno, int level, bt_status_t *curs) +{ + ASSERT(curs->free_btree_blocks < curs->btree_blocks + + curs->num_tot_blocks); + ASSERT(curs->num_free_blocks > 0); + + curs->num_free_blocks--; + return(*curs->free_btree_blocks++); +} + +/* + * set up the dynamically allocated block allocation data in the btree + * cursor that depends on the info in the static portion of the cursor. + * allocates space from the incore bno/bcnt extent trees and sets up + * the first path up the left side of the tree. Also sets up the + * cursor pointer to the btree root. called by init_freespace_cursor() + * and init_ino_cursor() + */ +/* ARGSUSED */ +void +setup_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *curs) +{ + int j; + unsigned int u; + xfs_extlen_t big_extent_len; + xfs_agblock_t big_extent_start; + extent_tree_node_t *ext_ptr; + extent_tree_node_t *bno_ext_ptr; + xfs_extlen_t blocks_allocated; + xfs_agblock_t *agb_ptr; + + /* + * get the number of blocks we need to allocate, then + * set up block number array, set the free block pointer + * to the first block in the array, and null the array + */ + big_extent_len = curs->num_tot_blocks; + blocks_allocated = 0; + + ASSERT(big_extent_len > 0); + + if ((curs->btree_blocks = malloc(sizeof(xfs_agblock_t *) + * big_extent_len)) == NULL) { + do_error("could not set up btree block array\n"); + exit(1); + } + + agb_ptr = curs->free_btree_blocks = curs->btree_blocks; + + for (j = 0; j < curs->num_free_blocks; j++, agb_ptr++) + *agb_ptr = NULLAGBLOCK; + + /* + * grab the smallest extent and use it up, then get the + * next smallest. This mimics the init_*_cursor code. + */ + if ((ext_ptr = findfirst_bcnt_extent(agno)) == NULL) { + do_error("error - not enough free space in filesystem\n"); + exit(1); + } + + agb_ptr = curs->btree_blocks; + j = curs->level[0].num_blocks; + + /* + * set up the free block array + */ + while (blocks_allocated < big_extent_len) { + /* + * use up the extent we've got + */ + for (u = 0; u < ext_ptr->ex_blockcount && + blocks_allocated < big_extent_len; u++) { + ASSERT(agb_ptr < curs->btree_blocks + + curs->num_tot_blocks); + *agb_ptr++ = ext_ptr->ex_startblock + u; + blocks_allocated++; + } + + /* + * if we only used part of this last extent, then we + * need only to reset the extent in the extent + * trees and we're done + */ + if (u < ext_ptr->ex_blockcount) { + big_extent_start = ext_ptr->ex_startblock + u; + big_extent_len = ext_ptr->ex_blockcount - u; + + ASSERT(big_extent_len > 0); + + bno_ext_ptr = find_bno_extent(agno, + ext_ptr->ex_startblock); + ASSERT(bno_ext_ptr != NULL); + get_bno_extent(agno, bno_ext_ptr); + release_extent_tree_node(bno_ext_ptr); + + ext_ptr = get_bcnt_extent(agno, ext_ptr->ex_startblock, + ext_ptr->ex_blockcount); + release_extent_tree_node(ext_ptr); +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, "releasing extent: %u [%u %u]\n", + agno, ext_ptr->ex_startblock, + ext_ptr->ex_blockcount); + fprintf(stderr, "blocks_allocated = %d\n", + blocks_allocated); +#endif + + add_bno_extent(agno, big_extent_start, big_extent_len); + add_bcnt_extent(agno, big_extent_start, big_extent_len); + + return; + } + /* + * delete the used-up extent from both extent trees and + * find next biggest extent + */ +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, "releasing extent: %u [%u %u]\n", + agno, ext_ptr->ex_startblock, ext_ptr->ex_blockcount); +#endif + bno_ext_ptr = find_bno_extent(agno, ext_ptr->ex_startblock); + ASSERT(bno_ext_ptr != NULL); + get_bno_extent(agno, bno_ext_ptr); + release_extent_tree_node(bno_ext_ptr); + + ext_ptr = get_bcnt_extent(agno, ext_ptr->ex_startblock, + ext_ptr->ex_blockcount); + ASSERT(ext_ptr != NULL); + release_extent_tree_node(ext_ptr); + + ext_ptr = findfirst_bcnt_extent(agno); + } +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, "blocks_allocated = %d\n", + blocks_allocated); +#endif +} + +void +write_cursor(bt_status_t *curs) +{ + int i; + + for (i = 0; i < curs->num_levels; i++) { +#if defined(XR_BLD_FREE_TRACE) || defined(XR_BLD_INO_TRACE) + fprintf(stderr, "writing bt block %u\n", curs->level[i].agbno); +#endif + if (curs->level[i].prev_buf_p != NULL) { + ASSERT(curs->level[i].prev_agbno != NULLAGBLOCK); + libxfs_writebuf(curs->level[i].prev_buf_p, 0); + } + libxfs_writebuf(curs->level[i].buf_p, 0); + } +} + +void +finish_cursor(bt_status_t *curs) +{ + ASSERT(curs->num_free_blocks == 0); + free(curs->btree_blocks); +} + +/* + * no-cursor versions of the XFS equivalents. The address calculators + * should be used only for interior btree nodes. + * these are adapted from xfs_alloc_btree.h and xfs_tree.h + */ +#define XR_ALLOC_KEY_ADDR(mp, bp, i) \ + (xfs_alloc_key_t *) ((char *) (bp) + sizeof(xfs_alloc_block_t) \ + + ((i)-1) * sizeof(xfs_alloc_key_t)) + +#define XR_ALLOC_PTR_ADDR(mp, bp, i) \ + (xfs_alloc_ptr_t *) ((char *) (bp) + sizeof(xfs_alloc_block_t) \ + + (mp)->m_alloc_mxr[1] * sizeof(xfs_alloc_key_t) \ + + ((i)-1) * sizeof(xfs_alloc_ptr_t)) + +#define XR_ALLOC_BLOCK_MAXRECS(mp, level) \ + XFS_BTREE_BLOCK_MAXRECS((mp)->m_sb.sb_blocksize, \ + xfs_alloc, (level) == 0) + +/* + * this calculates a freespace cursor for an ag. + * btree_curs is an in/out. returns the number of + * blocks that will show up in the AGFL. + */ + +int +calculate_freespace_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, + xfs_agblock_t *extents, bt_status_t *btree_curs) +{ + xfs_extlen_t blocks_needed; /* a running count */ + xfs_extlen_t blocks_allocated_pt; /* per tree */ + xfs_extlen_t blocks_allocated_total; /* for both trees */ + xfs_agblock_t num_extents; + int i; + int extents_used; + int extra_blocks; + bt_stat_level_t *lptr; + bt_stat_level_t *p_lptr; + extent_tree_node_t *ext_ptr; + int level; +#ifdef XR_BLD_FREE_TRACE + int old_state; + int state = XR_E_BAD_STATE; +#endif +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, + "in init_freespace_cursor, agno = %d\n", agno); +#endif + + num_extents = *extents; + extents_used = 0; + + ASSERT(num_extents != 0); + + lptr = &btree_curs->level[0]; + btree_curs->init = 1; + + /* + * figure out how much space we need for the leaf level + * of the tree and set up the cursor for the leaf level + * (note that the same code is duplicated further down) + */ + lptr->num_blocks = howmany(num_extents, XR_ALLOC_BLOCK_MAXRECS(mp, 0)); + lptr->num_recs_pb = num_extents / lptr->num_blocks; + lptr->modulo = num_extents % lptr->num_blocks; + lptr->num_recs_tot = num_extents; + level = 1; + + /* + * if we need more levels, set them up. # of records + * per level is the # of blocks in the level below it + */ + if (lptr->num_blocks > 1) { + for (; btree_curs->level[level - 1].num_blocks > 1 + && level < XFS_BTREE_MAXLEVELS; + level++) { + lptr = &btree_curs->level[level]; + p_lptr = &btree_curs->level[level - 1]; + lptr->num_blocks = howmany(p_lptr->num_blocks, + XR_ALLOC_BLOCK_MAXRECS(mp, level)); + lptr->modulo = p_lptr->num_blocks + % lptr->num_blocks; + lptr->num_recs_pb = p_lptr->num_blocks + / lptr->num_blocks; + lptr->num_recs_tot = p_lptr->num_blocks; + } + } + + ASSERT(lptr->num_blocks == 1); + btree_curs->num_levels = level; + + /* + * ok, now we have a hypothetical cursor that + * will work for both the bno and bcnt trees. + * now figure out if using up blocks to set up the + * trees will perturb the shape of the freespace tree. + * if so, we've over-allocated. the freespace trees + * as they will be *after* accounting for the free space + * we've used up will need fewer blocks to to represent + * than we've allocated. We can use the AGFL to hold + * XFS_AGFL_SIZE (128) blocks but that's it. + * Thus we limit things to XFS_AGFL_SIZE/2 for each of the 2 btrees. + * if the number of extra blocks is more than that, + * we'll have to be called again. + */ + for (blocks_needed = 0, i = 0; i < level; i++) { + blocks_needed += btree_curs->level[i].num_blocks; + } + + /* + * record the # of blocks we've allocated + */ + blocks_allocated_pt = blocks_needed; + blocks_needed *= 2; + blocks_allocated_total = blocks_needed; + + /* + * figure out how many free extents will be used up by + * our space allocation + */ + if ((ext_ptr = findfirst_bcnt_extent(agno)) == NULL) { + do_error("can't rebuild fs trees -- not enough free space " + "on ag %u\n", agno); + exit(1); + } + + i = 0; + while (ext_ptr != NULL && blocks_needed > 0) { + if (ext_ptr->ex_blockcount <= blocks_needed) { + blocks_needed -= ext_ptr->ex_blockcount; + extents_used++; + } else { + blocks_needed = 0; + } + + ext_ptr = findnext_bcnt_extent(agno, ext_ptr); + +#ifdef XR_BLD_FREE_TRACE + if (ext_ptr != NULL) { + fprintf(stderr, "got next extent [%u %u]\n", + ext_ptr->ex_startblock, ext_ptr->ex_blockcount); + } else { + fprintf(stderr, "out of extents\n"); + } +#endif + } + if (blocks_needed > 0) { + do_error("ag %u - not enough free space to build freespace " + "btrees\n", agno); + exit(1); + } + + ASSERT(num_extents >= extents_used); + + num_extents -= extents_used; + + /* + * see if the number of leaf blocks will change as a result + * of the number of extents changing + */ + if (howmany(num_extents, XR_ALLOC_BLOCK_MAXRECS(mp, 0)) + != btree_curs->level[0].num_blocks) { + /* + * yes -- recalculate the cursor. If the number of + * excess (overallocated) blocks is < XFS_AGFL_SIZE/2, we're ok. + * we can put those into the AGFL. we don't try + * and get things to converge exactly (reach a + * state with zero excess blocks) because there + * exist pathological cases which will never + * converge. first, check for the zero-case. + */ + if (num_extents == 0) { + /* + * ok, we've used up all the free blocks + * trying to lay out the leaf level. go + * to a one block (empty) btree and put the + * already allocated blocks into the AGFL + */ + if (btree_curs->level[0].num_blocks != 1) { + /* + * we really needed more blocks because + * the old tree had more than one level. + * this is bad. + */ + do_warn("not enough free blocks left to " + "describe all free blocks in AG %u\n", + agno); + } +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, + "ag %u -- no free extents, alloc'ed %d\n", + agno, blocks_allocated_pt); +#endif + lptr->num_blocks = 1; + lptr->modulo = 0; + lptr->num_recs_pb = 0; + lptr->num_recs_tot = 0; + + btree_curs->num_levels = 1; + + /* + * don't reset the allocation stats, assume + * they're all extra blocks + * don't forget to return the total block count + * not the per-tree block count. these are the + * extras that will go into the AGFL. subtract + * two for the root blocks. + */ + btree_curs->num_tot_blocks = blocks_allocated_pt; + btree_curs->num_free_blocks = blocks_allocated_pt; + + *extents = 0; + + return(blocks_allocated_total - 2); + } + + lptr = &btree_curs->level[0]; + lptr->num_blocks = howmany(num_extents, + XR_ALLOC_BLOCK_MAXRECS(mp, 0)); + lptr->num_recs_pb = num_extents / lptr->num_blocks; + lptr->modulo = num_extents % lptr->num_blocks; + lptr->num_recs_tot = num_extents; + level = 1; + + /* + * if we need more levels, set them up + */ + if (lptr->num_blocks > 1) { + for (level = 1; btree_curs->level[level-1].num_blocks + > 1 && level < XFS_BTREE_MAXLEVELS; + level++) { + lptr = &btree_curs->level[level]; + p_lptr = &btree_curs->level[level-1]; + lptr->num_blocks = howmany(p_lptr->num_blocks, + XR_ALLOC_BLOCK_MAXRECS(mp, + level)); + lptr->modulo = p_lptr->num_blocks + % lptr->num_blocks; + lptr->num_recs_pb = p_lptr->num_blocks + / lptr->num_blocks; + lptr->num_recs_tot = p_lptr->num_blocks; + } + } + ASSERT(lptr->num_blocks == 1); + btree_curs->num_levels = level; + + /* + * now figure out the number of excess blocks + */ + for (blocks_needed = 0, i = 0; i < level; i++) { + blocks_needed += btree_curs->level[i].num_blocks; + } + blocks_needed *= 2; + + ASSERT(blocks_allocated_total >= blocks_needed); + extra_blocks = blocks_allocated_total - blocks_needed; + } else { + if (extents_used > 0) { + /* + * reset the leaf level geometry to account + * for consumed extents. we can leave the + * rest of the cursor alone since the number + * of leaf blocks hasn't changed. + */ + lptr = &btree_curs->level[0]; + + lptr->num_recs_pb = num_extents / lptr->num_blocks; + lptr->modulo = num_extents % lptr->num_blocks; + lptr->num_recs_tot = num_extents; + } + + extra_blocks = 0; + } + + btree_curs->num_tot_blocks = blocks_allocated_pt; + btree_curs->num_free_blocks = blocks_allocated_pt; + + *extents = num_extents; + + return(extra_blocks); +} + +void +prop_freespace_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, + bt_status_t *btree_curs, xfs_agblock_t startblock, + xfs_extlen_t blockcount, int level, __uint32_t magic) +{ + xfs_alloc_block_t *bt_hdr; + xfs_alloc_key_t *bt_key; + xfs_alloc_ptr_t *bt_ptr; + xfs_agblock_t agbno; + bt_stat_level_t *lptr; + + level++; + + if (level >= btree_curs->num_levels) + return; + + lptr = &btree_curs->level[level]; + bt_hdr = XFS_BUF_TO_ALLOC_BLOCK(lptr->buf_p); + + if (INT_GET(bt_hdr->bb_numrecs, ARCH_CONVERT) == 0) { + /* + * only happens once when initializing the + * left-hand side of the tree. + */ + prop_freespace_cursor(mp, agno, btree_curs, startblock, + blockcount, level, magic); + } + + if (INT_GET(bt_hdr->bb_numrecs, ARCH_CONVERT) == + lptr->num_recs_pb + (lptr->modulo > 0)) { + /* + * write out current prev block, grab us a new block, + * and set the rightsib pointer of current block + */ +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, " %d ", lptr->prev_agbno); +#endif + if (lptr->prev_agbno != NULLAGBLOCK) { + ASSERT(lptr->prev_buf_p != NULL); + libxfs_writebuf(lptr->prev_buf_p, 0); + } + lptr->prev_agbno = lptr->agbno;; + lptr->prev_buf_p = lptr->buf_p; + agbno = get_next_blockaddr(agno, level, btree_curs); + + INT_SET(bt_hdr->bb_rightsib, ARCH_CONVERT, agbno); + + lptr->buf_p = libxfs_getbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, agno, agbno), + XFS_FSB_TO_BB(mp, 1)); + lptr->agbno = agbno; + + if (lptr->modulo) + lptr->modulo--; + + /* + * initialize block header + */ + bt_hdr = XFS_BUF_TO_ALLOC_BLOCK(lptr->buf_p); + bzero(bt_hdr, mp->m_sb.sb_blocksize); + + INT_SET(bt_hdr->bb_magic, ARCH_CONVERT, magic); + INT_SET(bt_hdr->bb_level, ARCH_CONVERT, level); + INT_SET(bt_hdr->bb_leftsib, ARCH_CONVERT, lptr->prev_agbno); + INT_SET(bt_hdr->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + INT_ZERO(bt_hdr->bb_numrecs, ARCH_CONVERT); + + /* + * propagate extent record for first extent in new block up + */ + prop_freespace_cursor(mp, agno, btree_curs, startblock, + blockcount, level, magic); + } + /* + * add extent info to current block + */ + INT_MOD(bt_hdr->bb_numrecs, ARCH_CONVERT, +1); + + bt_key = XR_ALLOC_KEY_ADDR(mp, bt_hdr, + INT_GET(bt_hdr->bb_numrecs, ARCH_CONVERT)); + bt_ptr = XR_ALLOC_PTR_ADDR(mp, bt_hdr, + INT_GET(bt_hdr->bb_numrecs, ARCH_CONVERT)); + + INT_SET(bt_key->ar_startblock, ARCH_CONVERT, startblock); + INT_SET(bt_key->ar_blockcount, ARCH_CONVERT, blockcount); + INT_SET(*bt_ptr, ARCH_CONVERT, btree_curs->level[level-1].agbno); +} + +/* + * rebuilds a freespace tree given a cursor and magic number of type + * of tree to build (bno or bcnt). returns the number of free blocks + * represented by the tree. + */ +xfs_extlen_t +build_freespace_tree(xfs_mount_t *mp, xfs_agnumber_t agno, + bt_status_t *btree_curs, __uint32_t magic) +{ + xfs_agnumber_t i; + xfs_agblock_t j; + xfs_alloc_block_t *bt_hdr; + xfs_alloc_rec_t *bt_rec; + int level; + xfs_agblock_t agbno; + extent_tree_node_t *ext_ptr; + bt_stat_level_t *lptr; + xfs_extlen_t freeblks; + +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, "in build_freespace_tree, agno = %d\n", agno); +#endif + level = btree_curs->num_levels; + freeblks = 0; + + ASSERT(level > 0); + + /* + * initialize the first block on each btree level + */ + for (i = 0; i < level; i++) { + lptr = &btree_curs->level[i]; + + agbno = get_next_blockaddr(agno, i, btree_curs); + lptr->buf_p = libxfs_getbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, agno, agbno), + XFS_FSB_TO_BB(mp, 1)); + + if (i == btree_curs->num_levels - 1) + btree_curs->root = agbno; + + lptr->agbno = agbno; + lptr->prev_agbno = NULLAGBLOCK; + lptr->prev_buf_p = NULL; + /* + * initialize block header + */ + bt_hdr = XFS_BUF_TO_ALLOC_BLOCK(lptr->buf_p); + bzero(bt_hdr, mp->m_sb.sb_blocksize); + + INT_SET(bt_hdr->bb_magic, ARCH_CONVERT, magic); + INT_SET(bt_hdr->bb_level, ARCH_CONVERT, i); + INT_SET(bt_hdr->bb_leftsib, ARCH_CONVERT, + bt_hdr->bb_rightsib = NULLAGBLOCK); + INT_ZERO(bt_hdr->bb_numrecs, ARCH_CONVERT); + } + /* + * run along leaf, setting up records. as we have to switch + * blocks, call the prop_freespace_cursor routine to set up the new + * pointers for the parent. that can recurse up to the root + * if required. set the sibling pointers for leaf level here. + */ + if (magic == XFS_ABTB_MAGIC) + ext_ptr = findfirst_bno_extent(agno); + else + ext_ptr = findfirst_bcnt_extent(agno); + +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, "bft, agno = %d, start = %u, count = %u\n", + agno, ext_ptr->ex_startblock, ext_ptr->ex_blockcount); +#endif + + lptr = &btree_curs->level[0]; + + for (i = 0; i < btree_curs->level[0].num_blocks; i++) { + /* + * block initialization, lay in block header + */ + bt_hdr = XFS_BUF_TO_ALLOC_BLOCK(lptr->buf_p); + bzero(bt_hdr, mp->m_sb.sb_blocksize); + + INT_SET(bt_hdr->bb_magic, ARCH_CONVERT, magic); + INT_ZERO(bt_hdr->bb_level, ARCH_CONVERT); + INT_SET(bt_hdr->bb_leftsib, ARCH_CONVERT, lptr->prev_agbno); + INT_SET(bt_hdr->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(bt_hdr->bb_numrecs, ARCH_CONVERT, + lptr->num_recs_pb + (lptr->modulo > 0)); +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, "bft, bb_numrecs = %d\n", + INT_GET(bt_hdr->bb_numrecs, ARCH_CONVERT)); +#endif + + if (lptr->modulo > 0) + lptr->modulo--; + + /* + * initialize values in the path up to the root if + * this is a multi-level btree + */ + if (btree_curs->num_levels > 1) + prop_freespace_cursor(mp, agno, btree_curs, + ext_ptr->ex_startblock, + ext_ptr->ex_blockcount, + 0, magic); + + bt_rec = (xfs_alloc_rec_t *) ((char *) bt_hdr + + sizeof(xfs_alloc_block_t)); + for (j = 0; j < INT_GET(bt_hdr->bb_numrecs,ARCH_CONVERT); j++) { + ASSERT(ext_ptr != NULL); + INT_SET(bt_rec[j].ar_startblock, ARCH_CONVERT, + ext_ptr->ex_startblock); + INT_SET(bt_rec[j].ar_blockcount, ARCH_CONVERT, + ext_ptr->ex_blockcount); + freeblks += ext_ptr->ex_blockcount; + if (magic == XFS_ABTB_MAGIC) + ext_ptr = findnext_bno_extent(ext_ptr); + else + ext_ptr = findnext_bcnt_extent(agno, ext_ptr); +#if 0 +#ifdef XR_BLD_FREE_TRACE + if (ext_ptr == NULL) + fprintf(stderr, "null extent pointer, j = %d\n", + j); + else + fprintf(stderr, + "bft, agno = %d, start = %u, count = %u\n", + agno, ext_ptr->ex_startblock, + ext_ptr->ex_blockcount); +#endif +#endif + } + + if (ext_ptr != NULL) { + /* + * get next leaf level block + */ + if (lptr->prev_buf_p != NULL) { +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, " writing fst agbno %u\n", + lptr->prev_agbno); +#endif + ASSERT(lptr->prev_agbno != NULLAGBLOCK); + libxfs_writebuf(lptr->prev_buf_p, 0); + } + lptr->prev_buf_p = lptr->buf_p; + lptr->prev_agbno = lptr->agbno; + + INT_SET(bt_hdr->bb_rightsib, ARCH_CONVERT, lptr->agbno = + get_next_blockaddr(agno, 0, btree_curs)); + + lptr->buf_p = libxfs_getbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, agno, lptr->agbno), + XFS_FSB_TO_BB(mp, 1)); + } + } + + return(freeblks); +} + +/* + * no-cursor versions of the XFS equivalents. The address calculators + * should be used only for interior btree nodes. + * these are adapted from xfs_ialloc_btree.h and xfs_tree.h + */ +#define XR_INOBT_KEY_ADDR(mp, bp, i) \ + (xfs_inobt_key_t *) ((char *) (bp) + sizeof(xfs_inobt_block_t) \ + + ((i)-1) * sizeof(xfs_inobt_key_t)) + +#define XR_INOBT_PTR_ADDR(mp, bp, i) \ + (xfs_inobt_ptr_t *) ((char *) (bp) + sizeof(xfs_inobt_block_t) \ + + (mp)->m_inobt_mxr[1] * sizeof(xfs_inobt_key_t) \ + + ((i)-1) * sizeof(xfs_inobt_ptr_t)) + +#define XR_INOBT_BLOCK_MAXRECS(mp, level) \ + XFS_BTREE_BLOCK_MAXRECS((mp)->m_sb.sb_blocksize, \ + xfs_inobt, (level) == 0) + +/* + * we don't have to worry here about how chewing up free extents + * may perturb things because inode tree building happens before + * freespace tree building. + */ +void +init_ino_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, + __uint64_t *num_inos, __uint64_t *num_free_inos) +{ + __uint64_t ninos; + __uint64_t nfinos; + ino_tree_node_t *ino_rec; + int num_recs; + int level; + bt_stat_level_t *lptr; + bt_stat_level_t *p_lptr; + xfs_extlen_t blocks_allocated; + int i; + + *num_inos = *num_free_inos = 0; + ninos = nfinos = 0; + + lptr = &btree_curs->level[0]; + btree_curs->init = 1; + + if ((ino_rec = findfirst_inode_rec(agno)) == NULL) { + /* + * easy corner-case -- no inode records + */ + lptr->num_blocks = 1; + lptr->modulo = 0; + lptr->num_recs_pb = 0; + lptr->num_recs_tot = 0; + + btree_curs->num_levels = 1; + btree_curs->num_tot_blocks = btree_curs->num_free_blocks = 1; + + setup_cursor(mp, agno, btree_curs); + + return; + } + + /* + * build up statistics + */ + for (num_recs = 0; ino_rec != NULL; ino_rec = next_ino_rec(ino_rec)) { + ninos += XFS_INODES_PER_CHUNK; + num_recs++; + for (i = 0; i < XFS_INODES_PER_CHUNK; i++) { + ASSERT(is_inode_confirmed(ino_rec, i)); + if (is_inode_free(ino_rec, i)) + nfinos++; + } + } + + blocks_allocated = lptr->num_blocks = howmany(num_recs, + XR_INOBT_BLOCK_MAXRECS(mp, 0)); + + lptr->modulo = num_recs % lptr->num_blocks; + lptr->num_recs_pb = num_recs / lptr->num_blocks; + lptr->num_recs_tot = num_recs; + level = 1; + + if (lptr->num_blocks > 1) { + for (; btree_curs->level[level-1].num_blocks > 1 + && level < XFS_BTREE_MAXLEVELS; + level++) { + lptr = &btree_curs->level[level]; + p_lptr = &btree_curs->level[level - 1]; + lptr->num_blocks = howmany(p_lptr->num_blocks, + XR_INOBT_BLOCK_MAXRECS(mp, level)); + lptr->modulo = p_lptr->num_blocks % lptr->num_blocks; + lptr->num_recs_pb = p_lptr->num_blocks + / lptr->num_blocks; + lptr->num_recs_tot = p_lptr->num_blocks; + + blocks_allocated += lptr->num_blocks; + } + } + ASSERT(lptr->num_blocks == 1); + btree_curs->num_levels = level; + + btree_curs->num_tot_blocks = btree_curs->num_free_blocks + = blocks_allocated; + + setup_cursor(mp, agno, btree_curs); + + *num_inos = ninos; + *num_free_inos = nfinos; + + return; +} + +void +prop_ino_cursor(xfs_mount_t *mp, xfs_agnumber_t agno, bt_status_t *btree_curs, + xfs_agino_t startino, int level) +{ + xfs_inobt_block_t *bt_hdr; + xfs_inobt_key_t *bt_key; + xfs_inobt_ptr_t *bt_ptr; + xfs_agblock_t agbno; + bt_stat_level_t *lptr; + + level++; + + if (level >= btree_curs->num_levels) + return; + + lptr = &btree_curs->level[level]; + bt_hdr = XFS_BUF_TO_INOBT_BLOCK(lptr->buf_p); + + if (INT_GET(bt_hdr->bb_numrecs, ARCH_CONVERT) == 0) { + /* + * this only happens once to initialize the + * first path up the left side of the tree + * where the agbno's are already set up + */ + prop_ino_cursor(mp, agno, btree_curs, startino, level); + } + + if (INT_GET(bt_hdr->bb_numrecs, ARCH_CONVERT) == + lptr->num_recs_pb + (lptr->modulo > 0)) { + /* + * write out current prev block, grab us a new block, + * and set the rightsib pointer of current block + */ +#ifdef XR_BLD_INO_TRACE + fprintf(stderr, " ino prop agbno %d ", lptr->prev_agbno); +#endif + if (lptr->prev_agbno != NULLAGBLOCK) { + ASSERT(lptr->prev_buf_p != NULL); + libxfs_writebuf(lptr->prev_buf_p, 0); + } + lptr->prev_agbno = lptr->agbno;; + lptr->prev_buf_p = lptr->buf_p; + agbno = get_next_blockaddr(agno, level, btree_curs); + + INT_SET(bt_hdr->bb_rightsib, ARCH_CONVERT, agbno); + + lptr->buf_p = libxfs_getbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, agno, agbno), + XFS_FSB_TO_BB(mp, 1)); + lptr->agbno = agbno; + + if (lptr->modulo) + lptr->modulo--; + + /* + * initialize block header + */ + bt_hdr = XFS_BUF_TO_INOBT_BLOCK(lptr->buf_p); + bzero(bt_hdr, mp->m_sb.sb_blocksize); + + INT_SET(bt_hdr->bb_magic, ARCH_CONVERT, XFS_IBT_MAGIC); + INT_SET(bt_hdr->bb_level, ARCH_CONVERT, level); + INT_SET(bt_hdr->bb_leftsib, ARCH_CONVERT, lptr->prev_agbno); + INT_SET(bt_hdr->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + INT_ZERO(bt_hdr->bb_numrecs, ARCH_CONVERT); + /* + * propagate extent record for first extent in new block up + */ + prop_ino_cursor(mp, agno, btree_curs, startino, level); + } + /* + * add inode info to current block + */ + INT_MOD(bt_hdr->bb_numrecs, ARCH_CONVERT, +1); + + bt_key = XR_INOBT_KEY_ADDR(mp, bt_hdr, + INT_GET(bt_hdr->bb_numrecs, ARCH_CONVERT)); + bt_ptr = XR_INOBT_PTR_ADDR(mp, bt_hdr, + INT_GET(bt_hdr->bb_numrecs, ARCH_CONVERT)); + + INT_SET(bt_key->ir_startino, ARCH_CONVERT, startino); + INT_SET(*bt_ptr, ARCH_CONVERT, btree_curs->level[level-1].agbno); +} + +void +build_agi(xfs_mount_t *mp, xfs_agnumber_t agno, + bt_status_t *btree_curs, xfs_agino_t first_agino, + xfs_agino_t count, xfs_agino_t freecount) +{ + xfs_buf_t *agi_buf; + xfs_agi_t *agi; + int i; + + agi_buf = libxfs_getbuf(mp->m_dev, + XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR), + mp->m_sb.sb_sectsize/BBSIZE); + agi = XFS_BUF_TO_AGI(agi_buf); + bzero(agi, mp->m_sb.sb_sectsize); + + INT_SET(agi->agi_magicnum, ARCH_CONVERT, XFS_AGI_MAGIC); + INT_SET(agi->agi_versionnum, ARCH_CONVERT, XFS_AGI_VERSION); + INT_SET(agi->agi_seqno, ARCH_CONVERT, agno); + if (agno < mp->m_sb.sb_agcount - 1) + INT_SET(agi->agi_length, ARCH_CONVERT, mp->m_sb.sb_agblocks); + else + INT_SET(agi->agi_length, ARCH_CONVERT, mp->m_sb.sb_dblocks - + (xfs_drfsbno_t) mp->m_sb.sb_agblocks * agno); + INT_SET(agi->agi_count, ARCH_CONVERT, count); + INT_SET(agi->agi_root, ARCH_CONVERT, btree_curs->root); + INT_SET(agi->agi_level, ARCH_CONVERT, btree_curs->num_levels); + INT_SET(agi->agi_freecount, ARCH_CONVERT, freecount); + INT_SET(agi->agi_newino, ARCH_CONVERT, first_agino); + INT_SET(agi->agi_dirino, ARCH_CONVERT, NULLAGINO); + + for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) { + INT_SET(agi->agi_unlinked[i], ARCH_CONVERT, NULLAGINO); + } + + libxfs_writebuf(agi_buf, 0); +} + +/* + * rebuilds an inode tree given a cursor. We're lazy here and call + * the routine that builds the agi + */ +void +build_ino_tree(xfs_mount_t *mp, xfs_agnumber_t agno, + bt_status_t *btree_curs) +{ + xfs_agnumber_t i; + xfs_agblock_t j; + xfs_agblock_t agbno; + xfs_agino_t first_agino; + xfs_inobt_block_t *bt_hdr; + xfs_inobt_rec_t *bt_rec; + ino_tree_node_t *ino_rec; + bt_stat_level_t *lptr; + xfs_agino_t count = 0; + xfs_agino_t freecount = 0; + int inocnt; + int k; + int level = btree_curs->num_levels; + + for (i = 0; i < level; i++) { + lptr = &btree_curs->level[i]; + + agbno = get_next_blockaddr(agno, i, btree_curs); + lptr->buf_p = libxfs_getbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, agno, agbno), + XFS_FSB_TO_BB(mp, 1)); + + if (i == btree_curs->num_levels - 1) + btree_curs->root = agbno; + + lptr->agbno = agbno; + lptr->prev_agbno = NULLAGBLOCK; + lptr->prev_buf_p = NULL; + /* + * initialize block header + */ + bt_hdr = XFS_BUF_TO_INOBT_BLOCK(lptr->buf_p); + bzero(bt_hdr, mp->m_sb.sb_blocksize); + + INT_SET(bt_hdr->bb_magic, ARCH_CONVERT, XFS_IBT_MAGIC); + INT_SET(bt_hdr->bb_level, ARCH_CONVERT, i); + INT_SET(bt_hdr->bb_leftsib, ARCH_CONVERT, + bt_hdr->bb_rightsib = NULLAGBLOCK); + INT_ZERO(bt_hdr->bb_numrecs, ARCH_CONVERT); + } + /* + * run along leaf, setting up records. as we have to switch + * blocks, call the prop_ino_cursor routine to set up the new + * pointers for the parent. that can recurse up to the root + * if required. set the sibling pointers for leaf level here. + */ + ino_rec = findfirst_inode_rec(agno); + + if (ino_rec != NULL) + first_agino = ino_rec->ino_startnum; + else + first_agino = NULLAGINO; + + lptr = &btree_curs->level[0]; + + for (i = 0; i < lptr->num_blocks; i++) { + /* + * block initialization, lay in block header + */ + bt_hdr = XFS_BUF_TO_INOBT_BLOCK(lptr->buf_p); + bzero(bt_hdr, mp->m_sb.sb_blocksize); + + INT_SET(bt_hdr->bb_magic, ARCH_CONVERT, XFS_IBT_MAGIC); + INT_ZERO(bt_hdr->bb_level, ARCH_CONVERT); + INT_SET(bt_hdr->bb_leftsib, ARCH_CONVERT, lptr->prev_agbno); + INT_SET(bt_hdr->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(bt_hdr->bb_numrecs, ARCH_CONVERT, + lptr->num_recs_pb + (lptr->modulo > 0)); + + if (lptr->modulo > 0) + lptr->modulo--; + + if (lptr->num_recs_pb > 0) + prop_ino_cursor(mp, agno, btree_curs, + ino_rec->ino_startnum, 0); + + bt_rec = (xfs_inobt_rec_t *) ((char *) bt_hdr + + sizeof(xfs_inobt_block_t)); + for (j = 0; j < INT_GET(bt_hdr->bb_numrecs,ARCH_CONVERT); j++) { + ASSERT(ino_rec != NULL); + INT_SET(bt_rec[j].ir_startino, ARCH_CONVERT, + ino_rec->ino_startnum); + INT_SET(bt_rec[j].ir_free, ARCH_CONVERT, + ino_rec->ir_free); + + inocnt = 0; + for (k = 0; k < sizeof(xfs_inofree_t)*NBBY; k++) { + ASSERT(is_inode_confirmed(ino_rec, k)); + inocnt += is_inode_free(ino_rec, k); + } + + INT_SET(bt_rec[j].ir_freecount, ARCH_CONVERT, inocnt); + freecount += inocnt; + count += XFS_INODES_PER_CHUNK; + ino_rec = next_ino_rec(ino_rec); + } + + if (ino_rec != NULL) { + /* + * get next leaf level block + */ + if (lptr->prev_buf_p != NULL) { +#ifdef XR_BLD_INO_TRACE + fprintf(stderr, "writing inobt agbno %u\n", + lptr->prev_agbno); +#endif + ASSERT(lptr->prev_agbno != NULLAGBLOCK); + libxfs_writebuf(lptr->prev_buf_p, 0); + } + lptr->prev_buf_p = lptr->buf_p; + lptr->prev_agbno = lptr->agbno; + + INT_SET(bt_hdr->bb_rightsib, ARCH_CONVERT, lptr->agbno= + get_next_blockaddr(agno, 0, btree_curs)); + + lptr->buf_p = libxfs_getbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, agno, lptr->agbno), + XFS_FSB_TO_BB(mp, 1)); + } + } + + build_agi(mp, agno, btree_curs, first_agino, count, freecount); +} + +/* + * build both the agf and the agfl for an agno given both + * btree cursors + */ +void +build_agf_agfl(xfs_mount_t *mp, + xfs_agnumber_t agno, + bt_status_t *bno_bt, + bt_status_t *bcnt_bt, + xfs_extlen_t freeblks, /* # free blocks in tree */ + int lostblocks) /* # blocks that will be lost */ +{ + extent_tree_node_t *ext_ptr; + xfs_buf_t *agf_buf, *agfl_buf; + int i; + int j; + xfs_agfl_t *agfl; + xfs_agf_t *agf; + + agf_buf = libxfs_getbuf(mp->m_dev, + XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR), + mp->m_sb.sb_sectsize/BBSIZE); + agf = XFS_BUF_TO_AGF(agf_buf); + bzero(agf, mp->m_sb.sb_sectsize); + +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, "agf = 0x%x, agf_buf->b_un.b_addr = 0x%x\n", + (__psint_t) agf, (__psint_t) agf_buf->b_un.b_addr); +#endif + + /* + * set up fixed part of agf + */ + INT_SET(agf->agf_magicnum, ARCH_CONVERT, XFS_AGF_MAGIC); + INT_SET(agf->agf_versionnum, ARCH_CONVERT, XFS_AGF_VERSION); + INT_SET(agf->agf_seqno, ARCH_CONVERT, agno); + + if (agno < mp->m_sb.sb_agcount - 1) + INT_SET(agf->agf_length, ARCH_CONVERT, mp->m_sb.sb_agblocks); + else + INT_SET(agf->agf_length, ARCH_CONVERT, mp->m_sb.sb_dblocks - + (xfs_drfsbno_t) mp->m_sb.sb_agblocks * agno); + + INT_SET(agf->agf_roots[XFS_BTNUM_BNO], ARCH_CONVERT, bno_bt->root); + INT_SET(agf->agf_levels[XFS_BTNUM_BNO], ARCH_CONVERT, + bno_bt->num_levels); + INT_SET(agf->agf_roots[XFS_BTNUM_CNT], ARCH_CONVERT, bcnt_bt->root); + INT_SET(agf->agf_levels[XFS_BTNUM_CNT], ARCH_CONVERT, + bcnt_bt->num_levels); + INT_SET(agf->agf_freeblks, ARCH_CONVERT, freeblks); + +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, "bno root = %u, bcnt root = %u, indices = %u %u\n", + INT_GET(agf->agf_roots[XFS_BTNUM_BNO], ARCH_CONVERT), + INT_GET(agf->agf_roots[XFS_BTNUM_CNT], ARCH_CONVERT), + XFS_BTNUM_BNO, + XFS_BTNUM_CNT); +#endif + + /* + * do we have left-over blocks in the btree cursors that should + * be used to fill the AGFL? + */ + if (bno_bt->num_free_blocks > 0 || bcnt_bt->num_free_blocks > 0) { + /* + * yes - grab the AGFL buffer + */ + agfl_buf = libxfs_getbuf(mp->m_dev, + XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR), + mp->m_sb.sb_sectsize/BBSIZE); + agfl = XFS_BUF_TO_AGFL(agfl_buf); + bzero(agfl, mp->m_sb.sb_sectsize); + /* + * ok, now grab as many blocks as we can + */ + i = j = 0; + while (bno_bt->num_free_blocks > 0 && i < XFS_AGFL_SIZE) { + INT_SET(agfl->agfl_bno[i], ARCH_CONVERT, + get_next_blockaddr(agno, 0, bno_bt)); + i++; + } + + while (bcnt_bt->num_free_blocks > 0 && i < XFS_AGFL_SIZE) { + INT_SET(agfl->agfl_bno[i], ARCH_CONVERT, + get_next_blockaddr(agno, 0, bcnt_bt)); + i++; + } + /* + * now throw the rest of the blocks away and complain + */ + while (bno_bt->num_free_blocks > 0) { + (void) get_next_blockaddr(agno, 0, bno_bt); + j++; + } + while (bcnt_bt->num_free_blocks > 0) { + (void) get_next_blockaddr(agno, 0, bcnt_bt); + j++; + } + + if (j > 0) { + if (j == lostblocks) + do_warn("lost %d blocks in ag %u\n", j, agno); + else + do_warn("thought we were going to lose %d " + "blocks in ag %u, actually lost %d\n", + lostblocks, j, agno); + } + + INT_ZERO(agf->agf_flfirst, ARCH_CONVERT); + INT_SET(agf->agf_fllast, ARCH_CONVERT, i - 1); + INT_SET(agf->agf_flcount, ARCH_CONVERT, i); + +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, "writing agfl for ag %u\n", agno); +#endif + + libxfs_writebuf(agfl_buf, 0); + } else { + INT_ZERO(agf->agf_flfirst, ARCH_CONVERT); + INT_SET(agf->agf_fllast, ARCH_CONVERT, XFS_AGFL_SIZE - 1); + INT_ZERO(agf->agf_flcount, ARCH_CONVERT); + } + + ext_ptr = findbiggest_bcnt_extent(agno); + INT_SET(agf->agf_longest, ARCH_CONVERT, + (ext_ptr != NULL) ? ext_ptr->ex_blockcount : 0); + + ASSERT(INT_GET(agf->agf_roots[XFS_BTNUM_BNOi], ARCH_CONVERT) != + INT_GET(agf->agf_roots[XFS_BTNUM_CNTi], ARCH_CONVERT)); + + libxfs_writebuf(agf_buf, 0); + +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, "wrote agf for ag %u, error = %d\n", agno, error); +#endif +} + +/* + * update the superblock counters, sync the sb version numbers and + * feature bits to the filesystem, and sync up the on-disk superblock + * to match the incore superblock. + */ +void +sync_sb(xfs_mount_t *mp) +{ + xfs_sb_t *sbp; + xfs_buf_t *bp; + + bp = libxfs_getsb(mp, 0); + if (!bp) + do_error("couldn't get superblock\n"); + + sbp = XFS_BUF_TO_SBP(bp); + + mp->m_sb.sb_icount = sb_icount; + mp->m_sb.sb_ifree = sb_ifree; + mp->m_sb.sb_fdblocks = sb_fdblocks; + mp->m_sb.sb_frextents = sb_frextents; + + update_sb_version(mp); + + *sbp = mp->m_sb; + libxfs_xlate_sb(XFS_BUF_PTR(bp), sbp, -1, ARCH_CONVERT, + XFS_SB_ALL_BITS); + libxfs_writebuf(bp, 0); +} + +/* + * make sure the root and realtime inodes show up allocated + * even if they've been freed. they get reinitialized in phase6. + */ +void +keep_fsinos(xfs_mount_t *mp) +{ + ino_tree_node_t *irec; + int i; + + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino), + XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino)); + + for (i = 0; i < 3; i++) + set_inode_used(irec, i); +} + +void +phase5(xfs_mount_t *mp) +{ + __uint64_t num_inos; + __uint64_t num_free_inos; + bt_status_t bno_btree_curs; + bt_status_t bcnt_btree_curs; + bt_status_t ino_btree_curs; + xfs_agnumber_t agno; + int extra_blocks = 0; + uint num_freeblocks; + xfs_extlen_t freeblks1; + xfs_extlen_t freeblks2; + xfs_agblock_t num_extents; + extern int count_bno_extents(xfs_agnumber_t); + extern int count_bno_extents_blocks(xfs_agnumber_t, uint *); +#ifdef XR_BLD_FREE_TRACE + extern int count_bcnt_extents(xfs_agnumber_t); +#endif + + do_log("Phase 5 - rebuild AG headers and trees...\n"); + +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, "inobt level 1, maxrec = %d, minrec = %d\n", + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_inobt, 0), + XFS_BTREE_BLOCK_MINRECS(mp->m_sb.sb_blocksize, xfs_inobt, 0) + ); + fprintf(stderr, "inobt level 0 (leaf), maxrec = %d, minrec = %d\n", + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_inobt, 1), + XFS_BTREE_BLOCK_MINRECS(mp->m_sb.sb_blocksize, xfs_inobt, 1) + ); + fprintf(stderr, "xr inobt level 0 (leaf), maxrec = %d\n", + XR_INOBT_BLOCK_MAXRECS(mp, 0)); + fprintf(stderr, "xr inobt level 1 (int), maxrec = %d\n", + XR_INOBT_BLOCK_MAXRECS(mp, 1)); + fprintf(stderr, "bnobt level 1, maxrec = %d, minrec = %d\n", + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_alloc, 0), + XFS_BTREE_BLOCK_MINRECS(mp->m_sb.sb_blocksize, xfs_alloc, 0)); + fprintf(stderr, "bnobt level 0 (leaf), maxrec = %d, minrec = %d\n", + XFS_BTREE_BLOCK_MAXRECS(mp->m_sb.sb_blocksize, xfs_alloc, 1), + XFS_BTREE_BLOCK_MINRECS(mp->m_sb.sb_blocksize, xfs_alloc, 1)); +#endif + + /* + * make sure the root and realtime inodes show up allocated + */ + keep_fsinos(mp); + + for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { + /* + * build up incore bno and bcnt extent btrees + */ + num_extents = mk_incore_fstree(mp, agno); + +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, "# of bno extents is %d\n", + count_bno_extents(agno)); +#endif + + if (num_extents == 0) { + /* + * XXX - what we probably should do here is pick an + * inode for a regular file in the allocation group + * that has space allocated and shoot it by traversing + * the bmap list and putting all its extents on the + * incore freespace trees, clearing the inode, + * and clearing the in-use bit in the incore inode + * tree. Then try mk_incore_fstree() again. + */ + do_error("unable to rebuild AG %u. " + "Not enough free space in on-disk AG.\n", agno); + } + + /* + * done with the AG bitmap, toss it... + */ + teardown_ag_bmap(mp, agno); + + /* + * ok, now set up the btree cursors for the + * on-disk btrees (includs pre-allocating all + * required blocks for the trees themselves) + */ + init_ino_cursor(mp, agno, &ino_btree_curs, + &num_inos, &num_free_inos); + + sb_icount += num_inos; + sb_ifree += num_free_inos; + + num_extents = count_bno_extents_blocks(agno, &num_freeblocks); + /* + * lose two blocks per AG -- the space tree roots + * are counted as allocated since the space trees + * always have roots + */ + sb_fdblocks += num_freeblocks - 2; + + if (num_extents == 0) { + /* + * XXX - what we probably should do here is pick an + * inode for a regular file in the allocation group + * that has space allocated and shoot it by traversing + * the bmap list and putting all its extents on the + * incore freespace trees, clearing the inode, + * and clearing the in-use bit in the incore inode + * tree. Then try mk_incore_fstree() again. + */ + do_error("unable to rebuild AG %u. No free space.\n", + agno); + exit(1); + } + +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, "# of bno extents is %d\n", num_extents); +#endif + + /* + * track blocks that we might really lose + */ + extra_blocks = calculate_freespace_cursor(mp, agno, + &num_extents, &bno_btree_curs); + + /* + * freespace btrees live in the "free space" but + * the filesystem treats AGFL blocks as allocated + * since they aren't described by the freespace trees + */ + + /* + * see if we can fit all the extra blocks into the AGFL + */ + extra_blocks = (extra_blocks - XFS_AGFL_SIZE > 0) + ? extra_blocks - XFS_AGFL_SIZE + : 0; + + if (extra_blocks > 0) { + do_warn("lost %d blocks in agno %d, sorry.\n", + extra_blocks, agno); + sb_fdblocks -= extra_blocks; + } + + bcnt_btree_curs = bno_btree_curs; + + setup_cursor(mp, agno, &bno_btree_curs); + setup_cursor(mp, agno, &bcnt_btree_curs); + +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, "# of bno extents is %d\n", + count_bno_extents(agno)); + fprintf(stderr, "# of bcnt extents is %d\n", + count_bcnt_extents(agno)); +#endif + /* + * now rebuild the freespace trees + */ + freeblks1 = build_freespace_tree(mp, agno, &bno_btree_curs, + XFS_ABTB_MAGIC); +#ifdef XR_BLD_FREE_TRACE + fprintf(stderr, "# of free blocks == %d\n", freeblks1); +#endif + write_cursor(&bno_btree_curs); + + freeblks2 = build_freespace_tree(mp, agno, &bcnt_btree_curs, + XFS_ABTC_MAGIC); + write_cursor(&bcnt_btree_curs); + + ASSERT(freeblks1 == freeblks2); + + /* + * set up agf and agfl + */ + build_agf_agfl(mp, agno, &bno_btree_curs, + &bcnt_btree_curs, freeblks1, extra_blocks); + /* + * build inode allocation tree. this also build the agi + */ + build_ino_tree(mp, agno, &ino_btree_curs); + write_cursor(&ino_btree_curs); + /* + * tear down cursors + */ + finish_cursor(&bno_btree_curs); + finish_cursor(&ino_btree_curs); + finish_cursor(&bcnt_btree_curs); + /* + * release the incore per-AG bno/bcnt trees so + * the extent nodes can be recycled + */ + release_agbno_extent_tree(agno); + release_agbcnt_extent_tree(agno); + } + + if (mp->m_sb.sb_rblocks) { + do_log( + " - generate realtime summary info and bitmap...\n"); + rtinit(mp); + generate_rtinfo(mp, btmcompute, sumcompute); + teardown_rt_bmap(mp); + } + + do_log(" - reset superblock...\n"); + + /* + * sync superblock counter and set version bits correctly + */ + sync_sb(mp); + + bad_ino_btree = 0; +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/phase6.c linux-2.4-xfs/cmd/xfsprogs/repair/phase6.c --- linux-2.4.7/cmd/xfsprogs/repair/phase6.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/phase6.c Wed May 9 01:56:06 2001 @@ -0,0 +1,3970 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "avl.h" +#include "globals.h" +#include "agheader.h" +#include "incore.h" +#include "dir.h" +#include "dir2.h" +#include "dir_stack.h" +#include "protos.h" +#include "err_protos.h" +#include "dinode.h" +#include "versions.h" + +static cred_t zerocr; +static int orphanage_entered; + +/* + * Data structures and routines to keep track of directory entries + * and whether their leaf entry has been seen + */ +typedef struct dir_hash_ent { + struct dir_hash_ent *next; /* pointer to next entry */ + xfs_dir2_leaf_entry_t ent; /* address and hash value */ + short junkit; /* name starts with / */ + short seen; /* have seen leaf entry */ +} dir_hash_ent_t; + +typedef struct dir_hash_tab { + int size; /* size of hash table */ + dir_hash_ent_t *tab[1];/* actual hash table, variable size */ +} dir_hash_tab_t; +#define DIR_HASH_TAB_SIZE(n) \ + (offsetof(dir_hash_tab_t, tab) + (sizeof(dir_hash_ent_t *) * (n))) +#define DIR_HASH_FUNC(t,a) ((a) % (t)->size) + +/* + * Track the contents of the freespace table in a directory. + */ +typedef struct freetab { + int naents; + int nents; + struct freetab_ent { + xfs_dir2_data_off_t v; + short s; + } ents[1]; +} freetab_t; +#define FREETAB_SIZE(n) \ + (offsetof(freetab_t, ents) + (sizeof(struct freetab_ent) * (n))) + +#define DIR_HASH_CK_OK 0 +#define DIR_HASH_CK_DUPLEAF 1 +#define DIR_HASH_CK_BADHASH 2 +#define DIR_HASH_CK_NODATA 3 +#define DIR_HASH_CK_NOLEAF 4 +#define DIR_HASH_CK_BADSTALE 5 + +static void +dir_hash_add( + dir_hash_tab_t *hashtab, + xfs_dahash_t hash, + xfs_dir2_dataptr_t addr, + int junk) +{ + int i; + dir_hash_ent_t *p; + + i = DIR_HASH_FUNC(hashtab, addr); + if ((p = malloc(sizeof(*p))) == NULL) { + do_error("malloc failed in dir_hash_add (%u bytes)\n", + sizeof(*p)); + exit(1); + } + p->next = hashtab->tab[i]; + hashtab->tab[i] = p; + if (!(p->junkit = junk)) + p->ent.hashval = hash; + p->ent.address = addr; + p->seen = 0; +} + +static int +dir_hash_unseen( + dir_hash_tab_t *hashtab) +{ + int i; + dir_hash_ent_t *p; + + for (i = 0; i < hashtab->size; i++) { + for (p = hashtab->tab[i]; p; p = p->next) { + if (p->seen == 0) + return 1; + } + } + return 0; +} + +static int +dir_hash_check( + dir_hash_tab_t *hashtab, + xfs_inode_t *ip, + int seeval) +{ + static char *seevalstr[] = { + "ok", + "duplicate leaf", + "hash value mismatch", + "no data entry", + "no leaf entry", + "bad stale count", + }; + + if (seeval == DIR_HASH_CK_OK && dir_hash_unseen(hashtab)) + seeval = DIR_HASH_CK_NOLEAF; + if (seeval == DIR_HASH_CK_OK) + return 0; + do_warn("bad hash table for directory inode %llu (%s): ", ip->i_ino, + seevalstr[seeval]); + if (!no_modify) + do_warn("rebuilding\n"); + else + do_warn("would rebuild\n"); + return 1; +} + +static void +dir_hash_done( + dir_hash_tab_t *hashtab) +{ + int i; + dir_hash_ent_t *n; + dir_hash_ent_t *p; + + for (i = 0; i < hashtab->size; i++) { + for (p = hashtab->tab[i]; p; p = n) { + n = p->next; + free(p); + } + } + free(hashtab); +} + +static dir_hash_tab_t * +dir_hash_init( + xfs_fsize_t size) +{ + dir_hash_tab_t *hashtab; + int hsize; + + hsize = size / (16 * 4); + if (hsize > 1024) + hsize = 1024; + else if (hsize < 16) + hsize = 16; + if ((hashtab = calloc(DIR_HASH_TAB_SIZE(hsize), 1)) == NULL) { + do_error("calloc failed in dir_hash_init\n"); + exit(1); + } + hashtab->size = hsize; + return hashtab; +} + +static int +dir_hash_see( + dir_hash_tab_t *hashtab, + xfs_dahash_t hash, + xfs_dir2_dataptr_t addr) +{ + int i; + dir_hash_ent_t *p; + + i = DIR_HASH_FUNC(hashtab, addr); + for (p = hashtab->tab[i]; p; p = p->next) { + if (p->ent.address != addr) + continue; + if (p->seen) + return DIR_HASH_CK_DUPLEAF; + if (p->junkit == 0 && p->ent.hashval != hash) + return DIR_HASH_CK_BADHASH; + p->seen = 1; + return DIR_HASH_CK_OK; + } + return DIR_HASH_CK_NODATA; +} + +static int +dir_hash_see_all( + dir_hash_tab_t *hashtab, + xfs_dir2_leaf_entry_t *ents, + int count, + int stale) +{ + int i; + int j; + int rval; + + for (i = j = 0; i < count; i++) { + if (INT_GET(ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) { + j++; + continue; + } + rval = dir_hash_see(hashtab, INT_GET(ents[i].hashval, ARCH_CONVERT), INT_GET(ents[i].address, ARCH_CONVERT)); + if (rval != DIR_HASH_CK_OK) + return rval; + } + return j == stale ? DIR_HASH_CK_OK : DIR_HASH_CK_BADSTALE; +} + + +/* + * Version 1 or 2 directory routine wrappers +*/ +static void +dir_init(xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *dp, xfs_inode_t *pdp) +{ + if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) + libxfs_dir2_init(tp, dp, pdp); + else + libxfs_dir_init(tp, dp, pdp); +} + +static int +dir_createname(xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *pip, + char *name, int namelen, xfs_ino_t inum, xfs_fsblock_t *first, + xfs_bmap_free_t *flist, xfs_extlen_t total) +{ + if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) + return libxfs_dir2_createname(tp, pip, name, namelen, + inum, first, flist, total); + else + return libxfs_dir_createname(tp, pip, name, namelen, + inum, first, flist, total); +} + +static int +dir_lookup(xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *dp, char *name, + int namelen, xfs_ino_t *inum) +{ + if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) + return libxfs_dir2_lookup(tp, dp, name, namelen, inum); + else + return libxfs_dir_lookup(tp, dp, name, namelen, inum); +} + +static int +dir_replace(xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *dp, char *name, + int namelen, xfs_ino_t inum, xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, xfs_extlen_t total) +{ + if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) + return libxfs_dir2_replace(tp, dp, name, namelen, inum, + firstblock, flist, total); + else + return libxfs_dir_replace(tp, dp, name, namelen, inum, + firstblock, flist, total); +} + +static int +dir_removename(xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *dp, char *name, + int namelen, xfs_ino_t inum, xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, xfs_extlen_t total) +{ + if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) + return libxfs_dir2_removename(tp, dp, name, namelen, inum, + firstblock, flist, total); + else + return libxfs_dir_removename(tp, dp, name, namelen, inum, + firstblock, flist, total); +} + +static int +dir_bogus_removename(xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *dp, + char *name, xfs_fsblock_t *firstblock, xfs_bmap_free_t *flist, + xfs_extlen_t total, xfs_dahash_t hashval, int namelen) +{ + if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) + return libxfs_dir2_bogus_removename(tp, dp, name, firstblock, + flist, total, hashval, namelen); + else + return libxfs_dir_bogus_removename(tp, dp, name, firstblock, + flist, total, hashval, namelen); +} + + +static void +res_failed( + int err) +{ + if (err == ENOSPC) { + do_error("ran out of disk space!\n"); + } else + do_error("xfs_trans_reserve returned %d\n", err); +} + +void +mk_rbmino(xfs_mount_t *mp) +{ + xfs_trans_t *tp; + xfs_inode_t *ip; + xfs_bmbt_irec_t *ep; + xfs_fsblock_t first; + int i; + int nmap; + int committed; + int error; + xfs_bmap_free_t flist; + xfs_dfiloff_t bno; + xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP]; + + /* + * first set up inode + */ + tp = libxfs_trans_alloc(mp, 0); + + if ((i = libxfs_trans_reserve(tp, 10, 0, 0, 0, 0))) + res_failed(i); + + error = libxfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, &ip); + if (error) { + do_error("couldn't iget realtime bitmap inode -- error - %d\n", + error); + } + + bzero(&ip->i_d, sizeof(xfs_dinode_core_t)); + + ip->i_d.di_magic = XFS_DINODE_MAGIC; + ip->i_d.di_mode = IFREG; + ip->i_d.di_version = XFS_DINODE_VERSION_1; + ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; + ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; + + ip->i_d.di_nlink = 1; /* account for sb ptr */ + + /* + * now the ifork + */ + ip->i_df.if_flags = XFS_IFEXTENTS; + ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0; + ip->i_df.if_u1.if_extents = NULL; + + ip->i_d.di_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize; + + /* + * commit changes + */ + libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + libxfs_trans_ihold(tp, ip); + libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, NULL); + + /* + * then allocate blocks for file and fill with zeroes (stolen + * from mkfs) + */ + tp = libxfs_trans_alloc(mp, 0); + if ((error = libxfs_trans_reserve(tp, mp->m_sb.sb_rbmblocks + + (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1), 0, 0, 0, 0))) + res_failed(error); + + libxfs_trans_ijoin(tp, ip, 0); + bno = 0; + XFS_BMAP_INIT(&flist, &first); + while (bno < mp->m_sb.sb_rbmblocks) { + nmap = XFS_BMAP_MAX_NMAP; + error = libxfs_bmapi(tp, ip, bno, + (xfs_extlen_t)(mp->m_sb.sb_rbmblocks - bno), + XFS_BMAPI_WRITE, &first, mp->m_sb.sb_rbmblocks, + map, &nmap, &flist); + if (error) { + do_error("couldn't allocate realtime bitmap - err %d\n", + error); + } + for (i = 0, ep = map; i < nmap; i++, ep++) { + libxfs_device_zero(mp->m_dev, + XFS_FSB_TO_DADDR(mp, ep->br_startblock), + XFS_FSB_TO_BB(mp, ep->br_blockcount)); + bno += ep->br_blockcount; + } + } + error = libxfs_bmap_finish(&tp, &flist, first, &committed); + if (error) { + do_error( + "allocation of the realtime bitmap failed, error = %d\n", + error); + } + libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0); +} + +int +fill_rbmino(xfs_mount_t *mp) +{ + xfs_buf_t *bp; + xfs_trans_t *tp; + xfs_inode_t *ip; + xfs_rtword_t *bmp; + xfs_fsblock_t first; + int nmap; + int error; + xfs_dfiloff_t bno; + xfs_bmbt_irec_t map; + + bmp = btmcompute; + bno = 0; + + tp = libxfs_trans_alloc(mp, 0); + + if ((error = libxfs_trans_reserve(tp, 10, 0, 0, 0, 0))) + res_failed(error); + + error = libxfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, &ip); + if (error) { + do_error("couldn't iget realtime bitmap inode -- error - %d\n", + error); + } + + while (bno < mp->m_sb.sb_rbmblocks) { + /* + * fill the file one block at a time + */ + nmap = 1; + error = libxfs_bmapi(tp, ip, bno, 1, XFS_BMAPI_WRITE, + &first, 1, &map, &nmap, NULL); + if (error || nmap != 1) { + do_error( + "couldn't map realtime bitmap block %llu - err %d\n", + bno, error); + } + + ASSERT(map.br_startblock != HOLESTARTBLOCK); + + error = libxfs_trans_read_buf( + mp, tp, mp->m_dev, + XFS_FSB_TO_DADDR(mp, map.br_startblock), + XFS_FSB_TO_BB(mp, 1), 1, &bp); + + if (error) { + do_warn( + "can't access block %llu (fsbno %llu) of realtime bitmap inode %llu\n", + bno, map.br_startblock, mp->m_sb.sb_rbmino); + return(1); + } + + bcopy(bmp, XFS_BUF_PTR(bp), mp->m_sb.sb_blocksize); + + libxfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1); + + bmp = (xfs_rtword_t *)((__psint_t) bmp + mp->m_sb.sb_blocksize); + bno++; + } + + libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0); + + return(0); +} + +int +fill_rsumino(xfs_mount_t *mp) +{ + xfs_buf_t *bp; + xfs_trans_t *tp; + xfs_inode_t *ip; + xfs_suminfo_t *smp; + xfs_fsblock_t first; + int nmap; + int error; + xfs_dfiloff_t bno; + xfs_dfiloff_t end_bno; + xfs_bmbt_irec_t map; + + smp = sumcompute; + bno = 0; + end_bno = mp->m_rsumsize >> mp->m_sb.sb_blocklog; + + tp = libxfs_trans_alloc(mp, 0); + + if ((error = libxfs_trans_reserve(tp, 10, 0, 0, 0, 0))) + res_failed(error); + + error = libxfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0, &ip); + if (error) { + do_error("couldn't iget realtime summary inode -- error - %d\n", + error); + } + + while (bno < end_bno) { + /* + * fill the file one block at a time + */ + nmap = 1; + error = libxfs_bmapi(tp, ip, bno, 1, XFS_BMAPI_WRITE, + &first, 1, &map, &nmap, NULL); + if (error || nmap != 1) { + do_error( + "couldn't map realtime summary inode block %llu - err %d\n", + bno, error); + } + + ASSERT(map.br_startblock != HOLESTARTBLOCK); + + error = libxfs_trans_read_buf( + mp, tp, mp->m_dev, + XFS_FSB_TO_DADDR(mp, map.br_startblock), + XFS_FSB_TO_BB(mp, 1), 1, &bp); + + if (error) { + do_warn( + "can't access block %llu (fsbno %llu) of realtime summary inode %llu\n", + bno, map.br_startblock, mp->m_sb.sb_rsumino); + return(1); + } + + bcopy(smp, XFS_BUF_PTR(bp), mp->m_sb.sb_blocksize); + + libxfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1); + + smp = (xfs_suminfo_t *)((__psint_t)smp + mp->m_sb.sb_blocksize); + bno++; + } + + libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0); + + return(0); +} + +void +mk_rsumino(xfs_mount_t *mp) +{ + xfs_trans_t *tp; + xfs_inode_t *ip; + xfs_bmbt_irec_t *ep; + xfs_fsblock_t first; + int i; + int nmap; + int committed; + int error; + int nsumblocks; + xfs_bmap_free_t flist; + xfs_dfiloff_t bno; + xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP]; + + /* + * first set up inode + */ + tp = libxfs_trans_alloc(mp, 0); + + if ((i = libxfs_trans_reserve(tp, 10, XFS_ICHANGE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_MKDIR_LOG_COUNT))) + res_failed(i); + + error = libxfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0, &ip); + if (error) { + do_error("couldn't iget realtime summary inode -- error - %d\n", + error); + } + + bzero(&ip->i_d, sizeof(xfs_dinode_core_t)); + + ip->i_d.di_magic = XFS_DINODE_MAGIC; + ip->i_d.di_mode = IFREG; + ip->i_d.di_version = XFS_DINODE_VERSION_1; + ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; + ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; + + ip->i_d.di_nlink = 1; /* account for sb ptr */ + + /* + * now the ifork + */ + ip->i_df.if_flags = XFS_IFEXTENTS; + ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0; + ip->i_df.if_u1.if_extents = NULL; + + ip->i_d.di_size = mp->m_rsumsize; + + /* + * commit changes + */ + libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + libxfs_trans_ihold(tp, ip); + libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0); + + /* + * then allocate blocks for file and fill with zeroes (stolen + * from mkfs) + */ + tp = libxfs_trans_alloc(mp, 0); + XFS_BMAP_INIT(&flist, &first); + + nsumblocks = mp->m_rsumsize >> mp->m_sb.sb_blocklog; + if ((error = libxfs_trans_reserve(tp, + mp->m_sb.sb_rbmblocks + + (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1), + BBTOB(128), 0, XFS_TRANS_PERM_LOG_RES, + XFS_DEFAULT_PERM_LOG_COUNT))) + res_failed(error); + + libxfs_trans_ijoin(tp, ip, 0); + bno = 0; + XFS_BMAP_INIT(&flist, &first); + while (bno < nsumblocks) { + nmap = XFS_BMAP_MAX_NMAP; + error = libxfs_bmapi(tp, ip, bno, + (xfs_extlen_t)(nsumblocks - bno), + XFS_BMAPI_WRITE, &first, nsumblocks, + map, &nmap, &flist); + if (error) { + do_error( + "couldn't allocate realtime summary inode - err %d\n", + error); + } + for (i = 0, ep = map; i < nmap; i++, ep++) { + libxfs_device_zero(mp->m_dev, + XFS_FSB_TO_DADDR(mp, ep->br_startblock), + XFS_FSB_TO_BB(mp, ep->br_blockcount)); + do_error("dev_zero of rtbitmap failed\n"); + bno += ep->br_blockcount; + } + } + error = libxfs_bmap_finish(&tp, &flist, first, &committed); + if (error) { + do_error( + "allocation of the realtime summary ino failed, err = %d\n", + error); + } + libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0); +} + +/* + * makes a new root directory. + */ +void +mk_root_dir(xfs_mount_t *mp) +{ + xfs_trans_t *tp; + xfs_inode_t *ip; + int i; + int error; + const mode_t mode = 0755; + + tp = libxfs_trans_alloc(mp, 0); + ip = NULL; + + if ((i = libxfs_trans_reserve(tp, 10, XFS_ICHANGE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_MKDIR_LOG_COUNT))) + res_failed(i); + + error = libxfs_trans_iget(mp, tp, mp->m_sb.sb_rootino, 0, &ip); + if (error) { + do_error("could not iget root inode -- error - %d\n", error); + } + + /* + * take care of the core -- initialization from xfs_ialloc() + */ + bzero(&ip->i_d, sizeof(xfs_dinode_core_t)); + + ip->i_d.di_magic = XFS_DINODE_MAGIC; + ip->i_d.di_mode = (__uint16_t) mode|IFDIR; + ip->i_d.di_version = XFS_DINODE_VERSION_1; + ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; + ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; + + ip->i_d.di_nlink = 1; /* account for . */ + + libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + + /* + * now the ifork + */ + ip->i_df.if_flags = XFS_IFEXTENTS; + ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0; + ip->i_df.if_u1.if_extents = NULL; + + mp->m_rootip = ip; + + /* + * initialize the directory + */ + dir_init(mp, tp, ip, ip); + + libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0); +} + +/* + * orphanage name == lost+found + */ +xfs_ino_t +mk_orphanage(xfs_mount_t *mp) +{ + xfs_ino_t ino; + xfs_trans_t *tp; + xfs_inode_t *ip; + xfs_inode_t *pip; + xfs_fsblock_t first; + int i; + int committed; + int error; + xfs_bmap_free_t flist; + const int mode = 0755; + const int uid = 0; + const int gid = 0; + int nres; + + tp = libxfs_trans_alloc(mp, 0); + XFS_BMAP_INIT(&flist, &first); + + nres = XFS_MKDIR_SPACE_RES(mp, strlen(ORPHANAGE)); + if ((i = libxfs_trans_reserve(tp, nres, XFS_MKDIR_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_MKDIR_LOG_COUNT))) + res_failed(i); + + /* + * use iget/ijoin instead of trans_iget because the ialloc + * wrapper can commit the transaction and start a new one + */ + if ((i = libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip, 0))) + do_error("%d - couldn't iget root inode to make %s\n", + i, ORPHANAGE); + + error = libxfs_inode_alloc(&tp, pip, mode|IFDIR, + 1, mp->m_dev, &zerocr, &ip); + + if (error) { + do_error("%s inode allocation failed %d\n", + ORPHANAGE, error); + } + + ip->i_d.di_uid = uid; + ip->i_d.di_gid = gid; + ip->i_d.di_nlink++; /* account for . */ + + /* + * now that we know the transaction will stay around, + * add the root inode to it + */ + libxfs_trans_ijoin(tp, pip, 0); + + /* + * create the actual entry + */ + if ((error = dir_createname(mp, tp, pip, ORPHANAGE, + strlen(ORPHANAGE), ip->i_ino, &first, &flist, nres))) { + do_warn("can't make %s, createname error %d, will try later\n", + ORPHANAGE, error); + orphanage_entered = 0; + } else + orphanage_entered = 1; + + /* + * bump up the link count in the root directory to account + * for .. in the new directory + */ + pip->i_d.di_nlink++; + + libxfs_trans_log_inode(tp, pip, XFS_ILOG_CORE); + dir_init(mp, tp, ip, pip); + libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + + error = libxfs_bmap_finish(&tp, &flist, first, &committed); + if (error) { + do_error("%s directory creation failed -- bmapf error %d\n", + ORPHANAGE, error); + } + + ino = ip->i_ino; + + libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0); + + /* need libxfs_iput here? - nathans TODO - possible memory leak? */ + + return(ino); +} + +/* + * move a file to the orphange. the orphanage is guaranteed + * at this point to only have file in it whose name == file inode # + */ +void +mv_orphanage(xfs_mount_t *mp, + xfs_ino_t dir_ino, /* orphange inode # */ + xfs_ino_t ino, /* inode # to be moved */ + int isa_dir) /* 1 if inode is a directory */ +{ + xfs_ino_t entry_ino_num; + xfs_inode_t *dir_ino_p; + xfs_inode_t *ino_p; + xfs_trans_t *tp; + xfs_fsblock_t first; + xfs_bmap_free_t flist; + int err; + int committed; + char fname[MAXPATHLEN + 1]; + int nres; + + sprintf(fname, "%llu", (unsigned long long)ino); + + if ((err = libxfs_iget(mp, NULL, dir_ino, 0, &dir_ino_p, 0))) + do_error("%d - couldn't iget orphanage inode\n", err); + + tp = libxfs_trans_alloc(mp, 0); + + if ((err = libxfs_iget(mp, NULL, ino, 0, &ino_p, 0))) + do_error("%d - couldn't iget disconnected inode\n", err); + + if (isa_dir) { + nres = XFS_DIRENTER_SPACE_RES(mp, strlen(fname)) + + XFS_DIRENTER_SPACE_RES(mp, 2); + if ((err = dir_lookup(mp, tp, ino_p, "..", 2, + &entry_ino_num))) { + ASSERT(err == ENOENT); + + if ((err = libxfs_trans_reserve(tp, nres, + XFS_RENAME_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_RENAME_LOG_COUNT))) + do_error( + "space reservation failed (%d), filesystem may be out of space\n", + err); + + libxfs_trans_ijoin(tp, dir_ino_p, 0); + libxfs_trans_ijoin(tp, ino_p, 0); + + XFS_BMAP_INIT(&flist, &first); + if ((err = dir_createname(mp, tp, dir_ino_p, fname, + strlen(fname), ino, &first, + &flist, nres))) + do_error( + "name create failed in %s (%d), filesystem may be out of space\n", + ORPHANAGE, err); + + dir_ino_p->i_d.di_nlink++; + libxfs_trans_log_inode(tp, dir_ino_p, XFS_ILOG_CORE); + + if ((err = dir_createname(mp, tp, ino_p, "..", 2, + dir_ino, &first, &flist, nres))) + do_error( + "creation of .. entry failed (%d), filesystem may be out of space\n", + err); + + ino_p->i_d.di_nlink++; + libxfs_trans_log_inode(tp, ino_p, XFS_ILOG_CORE); + + if ((err = libxfs_bmap_finish(&tp, &flist, first, &committed))) + do_error( + "bmap finish failed (err - %d), filesystem may be out of space\n", + err); + + libxfs_trans_commit(tp, + XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0); + } else { + if ((err = libxfs_trans_reserve(tp, nres, + XFS_RENAME_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_RENAME_LOG_COUNT))) + do_error( + "space reservation failed (%d), filesystem may be out of space\n", + err); + + libxfs_trans_ijoin(tp, dir_ino_p, 0); + libxfs_trans_ijoin(tp, ino_p, 0); + + XFS_BMAP_INIT(&flist, &first); + + if ((err = dir_createname(mp, tp, dir_ino_p, fname, + strlen(fname), ino, &first, + &flist, nres))) + do_error( + "name create failed in %s (%d), filesystem may be out of space\n", + ORPHANAGE, err); + + dir_ino_p->i_d.di_nlink++; + libxfs_trans_log_inode(tp, dir_ino_p, XFS_ILOG_CORE); + + /* + * don't replace .. value if it already points + * to us. that'll pop a libxfs/kernel ASSERT. + */ + if (entry_ino_num != dir_ino) { + if ((err = dir_replace(mp, tp, ino_p, "..", + 2, dir_ino, &first, + &flist, nres))) + do_error( + "name replace op failed (%d), filesystem may be out of space\n", + err); + } + + if ((err = libxfs_bmap_finish(&tp, &flist, first, + &committed))) + do_error( + "bmap finish failed (%d), filesystem may be out of space\n", + err); + + libxfs_trans_commit(tp, + XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0); + } + } else { + /* + * use the remove log reservation as that's + * more accurate. we're only creating the + * links, we're not doing the inode allocation + * also accounted for in the create + */ + nres = XFS_DIRENTER_SPACE_RES(mp, strlen(fname)); + if ((err = libxfs_trans_reserve(tp, nres, XFS_REMOVE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT))) + do_error( + "space reservation failed (%d), filesystem may be out of space\n", + err); + + libxfs_trans_ijoin(tp, dir_ino_p, 0); + libxfs_trans_ijoin(tp, ino_p, 0); + + XFS_BMAP_INIT(&flist, &first); + if ((err = dir_createname(mp, tp, dir_ino_p, fname, + strlen(fname), ino, &first, &flist, nres))) + do_error( + "name create failed in %s (%d), filesystem may be out of space\n", + ORPHANAGE, err); + ASSERT(err == 0); + + ino_p->i_d.di_nlink = 1; + libxfs_trans_log_inode(tp, ino_p, XFS_ILOG_CORE); + + if ((err = libxfs_bmap_finish(&tp, &flist, first, &committed))) + do_error( + "bmap finish failed (%d), filesystem may be out of space\n", + err); + + libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0); + } +} + +/* + * like get_first_dblock_fsbno only it uses the simulation code instead + * of raw I/O. + * + * Returns the fsbno of the first (leftmost) block in the directory leaf. + * sets *bno to the directory block # corresponding to the returned fsbno. + */ +xfs_dfsbno_t +map_first_dblock_fsbno(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_inode_t *ip, + xfs_dablk_t *bno) +{ + xfs_fsblock_t fblock; + xfs_da_intnode_t *node; + xfs_buf_t *bp; + xfs_dablk_t da_bno; + xfs_dfsbno_t fsbno; + xfs_bmbt_irec_t map; + int nmap; + int i; + int error; + char *ftype; + + /* + * traverse down left-side of tree until we hit the + * left-most leaf block setting up the btree cursor along + * the way. + */ + da_bno = 0; + *bno = 0; + i = -1; + node = NULL; + fblock = NULLFSBLOCK; + ftype = "dir"; + + nmap = 1; + error = libxfs_bmapi(NULL, ip, (xfs_fileoff_t) da_bno, 1, + XFS_BMAPI_METADATA, &fblock, 0, + &map, &nmap, NULL); + if (error || nmap != 1) { + if (!no_modify) + do_error( +"can't map block %d in %s inode %llu, xfs_bmapi returns %d, nmap = %d\n", + da_bno, ftype, ino, error, nmap); + else { + do_warn( +"can't map block %d in %s inode %llu, xfs_bmapi returns %d, nmap = %d\n", + da_bno, ftype, ino, error, nmap); + return(NULLDFSBNO); + } + } + + if ((fsbno = map.br_startblock) == HOLESTARTBLOCK) { + if (!no_modify) + do_error("block %d in %s ino %llu doesn't exist\n", + da_bno, ftype, ino); + else { + do_warn("block %d in %s ino %llu doesn't exist\n", + da_bno, ftype, ino); + return(NULLDFSBNO); + } + } + + if (ip->i_d.di_size <= XFS_LBSIZE(mp)) + return(fsbno); + + if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) + return(fsbno); + + do { + /* + * walk down left side of btree, release buffers as you + * go. if the root block is a leaf (single-level btree), + * just return it. + * + */ + + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), + XFS_FSB_TO_BB(mp, 1), 0); + + if (!bp) { + do_warn( + "can't read block %u (fsbno %llu) for directory inode %llu\n", + da_bno, fsbno, ino); + return(NULLDFSBNO); + } + + node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp); + + if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) { + libxfs_putbuf(bp); + do_warn( +"bad dir/attr magic number in inode %llu, file bno = %u, fsbno = %llu\n", + ino, da_bno, fsbno); + return(NULLDFSBNO); + } + + if (i == -1) + i = INT_GET(node->hdr.level, ARCH_CONVERT); + + da_bno = INT_GET(node->btree[0].before, ARCH_CONVERT); + + libxfs_putbuf(bp); + bp = NULL; + + nmap = 1; + error = libxfs_bmapi(NULL, ip, (xfs_fileoff_t) da_bno, 1, + XFS_BMAPI_METADATA, &fblock, 0, + &map, &nmap, NULL); + if (error || nmap != 1) { + if (!no_modify) + do_error( + "can't map block %d in %s ino %llu, xfs_bmapi returns %d, nmap = %d\n", + da_bno, ftype, ino, error, nmap); + else { + do_warn( + "can't map block %d in %s ino %llu, xfs_bmapi returns %d, nmap = %d\n", + da_bno, ftype, ino, error, nmap); + return(NULLDFSBNO); + } + } + if ((fsbno = map.br_startblock) == HOLESTARTBLOCK) { + if (!no_modify) + do_error( + "block %d in %s inode %llu doesn't exist\n", + da_bno, ftype, ino); + else { + do_warn( + "block %d in %s inode %llu doesn't exist\n", + da_bno, ftype, ino); + return(NULLDFSBNO); + } + } + + i--; + } while(i > 0); + + *bno = da_bno; + return(fsbno); +} + +/* + * scan longform directory and prune first bad entry. returns 1 if + * it had to remove something, 0 if it made it all the way through + * the directory. prune_lf_dir_entry does all the necessary bmap calls. + * + * hashval is an in/out -- starting hashvalue in, hashvalue of the + * deleted entry (if there was one) out + * + * this routine can NOT be called if running in no modify mode + */ +int +prune_lf_dir_entry(xfs_mount_t *mp, xfs_ino_t ino, xfs_inode_t *ip, + xfs_dahash_t *hashval) +{ + xfs_dfsbno_t fsbno; + int i; + int index; + int error; + int namelen; + xfs_bmap_free_t free_list; + xfs_fsblock_t first_block; + xfs_buf_t *bp; + xfs_dir_leaf_name_t *namest; + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_entry_t *entry; + xfs_trans_t *tp; + xfs_dablk_t da_bno; + xfs_fsblock_t fblock; + int committed; + int nmap; + xfs_bmbt_irec_t map; + char fname[MAXNAMELEN + 1]; + char *ftype; + int nres; + + /* + * ok, this is kind of a schizoid routine. we use our + * internal bmapi routines to walk the directory. when + * we find a bogus entry, we release the buffer so + * the simulation code doesn't deadlock and use the + * sim code to remove the entry. That will cause an + * extra bmap traversal to map the block but I think + * that's preferable to hacking the bogus removename + * function to be really different and then trying to + * maintain both versions as time goes on. + * + * first, grab the dinode and find the right leaf block. + */ + + ftype = "dir"; + da_bno = 0; + bp = NULL; + namest = NULL; + fblock = NULLFSBLOCK; + + fsbno = map_first_dblock_fsbno(mp, ino, ip, &da_bno); + + /* + * now go foward along the leaves of the btree looking + * for an entry beginning with '/' + */ + do { + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), + XFS_FSB_TO_BB(mp, 1), 0); + + if (!bp) { + do_error( + "can't read directory inode %llu (leaf) block %u (fsbno %llu)\n", + ino, da_bno, fsbno); + /* NOTREACHED */ + } + + leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp); + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + entry = &leaf->entries[0]; + + for (index = -1, i = 0; + i < INT_GET(leaf->hdr.count, ARCH_CONVERT) && index == -1; + i++) { + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + if (namest->name[0] != '/') + entry++; + else + index = i; + } + + /* + * if we got a bogus entry, exit loop with a pointer to + * the leaf block buffer. otherwise, keep trying blocks + */ + da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT); + + if (index == -1) { + if (bp != NULL) { + libxfs_putbuf(bp); + bp = NULL; + } + + /* + * map next leaf block unless we've run out + */ + if (da_bno != 0) { + nmap = 1; + error = libxfs_bmapi(NULL, ip, + (xfs_fileoff_t) da_bno, 1, + XFS_BMAPI_METADATA, &fblock, 0, + &map, &nmap, NULL); + if (error || nmap != 1) + do_error( +"can't map block %d in directory %llu, xfs_bmapi returns %d, nmap = %d\n", + da_bno, ino, error, nmap); + if ((fsbno = map.br_startblock) + == HOLESTARTBLOCK) { + do_error( + "%s ino %llu block %d doesn't exist\n", + ftype, ino, da_bno); + } + } + } + } while (da_bno != 0 && index == -1); + + /* + * if we hit the edge of the tree with no bad entries, we're done + * and the buffer was released. + */ + if (da_bno == 0 && index == -1) + return(0); + + ASSERT(index >= 0); + ASSERT(entry == &leaf->entries[index]); + ASSERT(namest == XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT))); + + /* + * snag the info we need out of the directory then release all buffers + */ + bcopy(namest->name, fname, entry->namelen); + fname[entry->namelen] = '\0'; + *hashval = INT_GET(entry->hashval, ARCH_CONVERT); + namelen = entry->namelen; + + libxfs_putbuf(bp); + + /* + * ok, now the hard part, blow away the index'th entry in this block + * + * allocate a remove transaction for it. that's not quite true since + * we're only messing with one inode, not two but... + */ + + tp = libxfs_trans_alloc(mp, XFS_TRANS_REMOVE); + + nres = XFS_REMOVE_SPACE_RES(mp); + error = libxfs_trans_reserve(tp, nres, XFS_REMOVE_LOG_RES(mp), + 0, XFS_TRANS_PERM_LOG_RES, + XFS_REMOVE_LOG_COUNT); + if (error) + res_failed(error); + + libxfs_trans_ijoin(tp, ip, 0); + libxfs_trans_ihold(tp, ip); + + XFS_BMAP_INIT(&free_list, &first_block); + + error = dir_bogus_removename(mp, tp, ip, fname, + &first_block, &free_list, nres, *hashval, namelen); + + if (error) { + do_error( +"couldn't remove bogus entry \"%s\" in\n\tdirectory inode %llu, errno = %d\n", + fname, ino, error); + /* NOTREACHED */ + } + + error = libxfs_bmap_finish(&tp, &free_list, first_block, &committed); + + ASSERT(error == 0); + + libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0); + + return(1); +} + +/* + * process a leaf block, also checks for .. entry + * and corrects it to match what we think .. should be + */ +void +lf_block_dir_entry_check(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_dir_leafblock_t *leaf, + int *dirty, + int *num_illegal, + int *need_dot, + dir_stack_t *stack, + ino_tree_node_t *current_irec, + int current_ino_offset) +{ + xfs_dir_leaf_entry_t *entry; + ino_tree_node_t *irec; + xfs_ino_t lino; + xfs_ino_t parent; + xfs_dir_leaf_name_t *namest; + int i; + int junkit; + int ino_offset; + int nbad; + char fname[MAXNAMELEN + 1]; + + entry = &leaf->entries[0]; + *dirty = 0; + nbad = 0; + + /* + * look at each entry. reference inode pointed to by each + * entry in the incore inode tree. + * if not a directory, set reached flag, increment link count + * if a directory and reached, mark entry as to be deleted. + * if a directory, check to see if recorded parent + * matches current inode #, + * if so, then set reached flag, increment link count + * of current and child dir inodes, push the child + * directory inode onto the directory stack. + * if current inode != parent, then mark entry to be deleted. + * + * return + */ + for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { + /* + * snag inode #, update link counts, and make sure + * this isn't a loop if the child is a directory + */ + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + + /* + * skip bogus entries (leading '/'). they'll be deleted + * later + */ + if (namest->name[0] == '/') { + nbad++; + continue; + } + + junkit = 0; + + XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &lino, ARCH_CONVERT); + bcopy(namest->name, fname, entry->namelen); + fname[entry->namelen] = '\0'; + + ASSERT(lino != NULLFSINO); + + /* + * skip the '..' entry since it's checked when the + * directory is reached by something else. if it never + * gets reached, it'll be moved to the orphanage and we'll + * take care of it then. + */ + if (entry->namelen == 2 && namest->name[0] == '.' && + namest->name[1] == '.') { + continue; + } + ASSERT(no_modify || !verify_inum(mp, lino)); + + /* + * special case the . entry. we know there's only one + * '.' and only '.' points to itself because bogus entries + * got trashed in phase 3 if there were > 1. + * bump up link count for '.' but don't set reached + * until we're actually reached by another directory + * '..' is already accounted for or will be taken care + * of when directory is moved to orphanage. + */ + if (ino == lino) { + ASSERT(namest->name[0] == '.' && entry->namelen == 1); + add_inode_ref(current_irec, current_ino_offset); + *need_dot = 0; + continue; + } + + /* + * special case the "lost+found" entry if pointing + * to where we think lost+found should be. if that's + * the case, that's the one we created in phase 6. + * just skip it. no need to process it and it's .. + * link is already accounted for. + */ + + if (lino == orphanage_ino && strcmp(fname, ORPHANAGE) == 0) + continue; + + /* + * skip entries with bogus inumbers if we're in no modify mode + */ + if (no_modify && verify_inum(mp, lino)) + continue; + + /* + * ok, now handle the rest of the cases besides '.' and '..' + */ + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, lino), + XFS_INO_TO_AGINO(mp, lino)); + + if (irec == NULL) { + nbad++; + do_warn( + "entry \"%s\" in dir inode %llu points to non-existent inode, ", + fname, ino); + + if (!no_modify) { + namest->name[0] = '/'; + *dirty = 1; + do_warn("marking entry to be junked\n"); + } else { + do_warn("would junk entry\n"); + } + + continue; + } + + ino_offset = XFS_INO_TO_AGINO(mp, lino) - irec->ino_startnum; + + /* + * if it's a free inode, blow out the entry. + * by now, any inode that we think is free + * really is free. + */ + if (is_inode_free(irec, ino_offset)) { + /* + * don't complain if this entry points to the old + * and now-free lost+found inode + */ + if (verbose || no_modify || lino != old_orphanage_ino) + do_warn( + "entry \"%s\" in dir inode %llu points to free inode %llu", + fname, ino, lino); + nbad++; + + if (!no_modify) { + if (verbose || lino != old_orphanage_ino) + do_warn(", marking entry to be junked\n"); + + else + do_warn("\n"); + namest->name[0] = '/'; + *dirty = 1; + } else { + do_warn(", would junk entry\n"); + } + + continue; + } + + /* + * check easy case first, regular inode, just bump + * the link count and continue + */ + if (!inode_isadir(irec, ino_offset)) { + add_inode_reached(irec, ino_offset); + continue; + } + + parent = get_inode_parent(irec, ino_offset); + ASSERT(parent != 0); + + /* + * bump up the link counts in parent and child + * directory but if the link doesn't agree with + * the .. in the child, blow out the entry. + * if the directory has already been reached, + * blow away the entry also. + */ + if (is_inode_reached(irec, ino_offset)) { + junkit = 1; + do_warn( +"entry \"%s\" in dir %llu points to an already connected dir inode %llu,\n", + fname, ino, lino); + } else if (parent == ino) { + add_inode_reached(irec, ino_offset); + add_inode_ref(current_irec, current_ino_offset); + + if (!is_inode_refchecked(lino, irec, ino_offset)) + push_dir(stack, lino); + } else { + junkit = 1; + do_warn( +"entry \"%s\" in dir ino %llu not consistent with .. value (%llu) in ino %llu,\n", + fname, ino, parent, lino); + } + + if (junkit) { + junkit = 0; + nbad++; + + if (!no_modify) { + namest->name[0] = '/'; + *dirty = 1; + if (verbose || lino != old_orphanage_ino) + do_warn("\twill clear entry \"%s\"\n", + fname); + } else { + do_warn("\twould clear entry \"%s\"\n", fname); + } + } + } + + *num_illegal += nbad; +} + +/* + * succeeds or dies, inode never gets dirtied since all changes + * happen in file blocks. the inode size and other core info + * is already correct, it's just the leaf entries that get altered. + */ +void +longform_dir_entry_check(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_inode_t *ip, + int *num_illegal, + int *need_dot, + dir_stack_t *stack, + ino_tree_node_t *irec, + int ino_offset) +{ + xfs_dir_leafblock_t *leaf; + xfs_buf_t *bp; + xfs_dfsbno_t fsbno; + xfs_fsblock_t fblock; + xfs_dablk_t da_bno; + int dirty; + int nmap; + int error; + int skipit; + xfs_bmbt_irec_t map; + char *ftype; + + da_bno = 0; + fblock = NULLFSBLOCK; + *need_dot = 1; + ftype = "dir"; + + fsbno = map_first_dblock_fsbno(mp, ino, ip, &da_bno); + + if (fsbno == NULLDFSBNO && no_modify) { + do_warn("cannot map block 0 of directory inode %llu\n", ino); + return; + } + + do { + ASSERT(fsbno != NULLDFSBNO); + skipit = 0; + + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno), + XFS_FSB_TO_BB(mp, 1), 0); + + if (!bp) { + do_error( + "can't read block %u (fsbno %llu) for directory inode %llu\n", + da_bno, fsbno, ino); + /* NOTREACHED */ + } + + leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp); + + da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT); + + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) { + if (!no_modify) { + do_error( + "bad magic # (0x%x) for dir ino %llu leaf block (bno %u fsbno %llu)\n", + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), + ino, da_bno, fsbno); + /* NOTREACHED */ + } else { + /* + * this block's bad but maybe the + * forward pointer is good... + */ + skipit = 1; + dirty = 0; + } + } + + if (!skipit) + lf_block_dir_entry_check(mp, ino, leaf, &dirty, + num_illegal, need_dot, stack, + irec, ino_offset); + + ASSERT(dirty == 0 || (dirty && !no_modify)); + + if (dirty && !no_modify) + libxfs_writebuf(bp, 0); + else + libxfs_putbuf(bp); + bp = NULL; + + if (da_bno != 0) { + nmap = 1; + error = libxfs_bmapi(NULL, ip, (xfs_fileoff_t)da_bno, 1, + XFS_BMAPI_METADATA, &fblock, 0, + &map, &nmap, NULL); + if (error || nmap != 1) { + if (!no_modify) + do_error( +"can't map leaf block %d in dir %llu, xfs_bmapi returns %d, nmap = %d\n", + da_bno, ino, error, nmap); + else { + do_warn( +"can't map leaf block %d in dir %llu, xfs_bmapi returns %d, nmap = %d\n", + da_bno, ino, error, nmap); + return; + } + } + if ((fsbno = map.br_startblock) == HOLESTARTBLOCK) { + if (!no_modify) + do_error( + "block %d in %s ino %llu doesn't exist\n", + da_bno, ftype, ino); + else { + do_warn( + "block %d in %s ino %llu doesn't exist\n", + da_bno, ftype, ino); + return; + } + } + } + } while (da_bno != 0); +} + +/* + * Kill a block in a version 2 inode. + * Makes its own transaction. + */ +static void +dir2_kill_block( + xfs_mount_t *mp, + xfs_inode_t *ip, + xfs_dablk_t da_bno, + xfs_dabuf_t *bp) +{ + xfs_da_args_t args; + int committed; + int error; + xfs_fsblock_t firstblock; + xfs_bmap_free_t flist; + int nres; + xfs_trans_t *tp; + + tp = libxfs_trans_alloc(mp, 0); + nres = XFS_REMOVE_SPACE_RES(mp); + error = libxfs_trans_reserve(tp, nres, XFS_REMOVE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); + if (error) + res_failed(error); + libxfs_trans_ijoin(tp, ip, 0); + libxfs_trans_ihold(tp, ip); + libxfs_da_bjoin(tp, bp); + bzero(&args, sizeof(args)); + XFS_BMAP_INIT(&flist, &firstblock); + args.dp = ip; + args.trans = tp; + args.firstblock = &firstblock; + args.flist = &flist; + args.whichfork = XFS_DATA_FORK; + if (da_bno >= mp->m_dirleafblk && da_bno < mp->m_dirfreeblk) + error = libxfs_da_shrink_inode(&args, da_bno, bp); + else + error = libxfs_dir2_shrink_inode(&args, + XFS_DIR2_DA_TO_DB(mp, da_bno), bp); + if (error) + do_error("shrink_inode failed inode %llu block %u\n", + ip->i_ino, da_bno); + libxfs_bmap_finish(&tp, &flist, firstblock, &committed); + libxfs_trans_commit(tp, 0, 0); +} + +/* + * process a data block, also checks for .. entry + * and corrects it to match what we think .. should be + */ +static void +longform_dir2_entry_check_data( + xfs_mount_t *mp, + xfs_inode_t *ip, + int *num_illegal, + int *need_dot, + dir_stack_t *stack, + ino_tree_node_t *current_irec, + int current_ino_offset, + xfs_dabuf_t **bpp, + dir_hash_tab_t *hashtab, + freetab_t **freetabp, + xfs_dablk_t da_bno, + int isblock) +{ + xfs_dir2_dataptr_t addr; + xfs_dir2_leaf_entry_t *blp; + xfs_dabuf_t *bp; + xfs_dir2_block_tail_t *btp; + int committed; + xfs_dir2_data_t *d; + xfs_dir2_db_t db; + xfs_dir2_data_entry_t *dep; + xfs_dir2_data_unused_t *dup; + char *endptr; + int error; + xfs_fsblock_t firstblock; + xfs_bmap_free_t flist; + char fname[MAXNAMELEN + 1]; + freetab_t *freetab; + int i; + int ino_offset; + ino_tree_node_t *irec; + int junkit; + int lastfree; + int len; + int nbad; + int needlog; + int needscan; + xfs_ino_t parent; + char *ptr; + xfs_trans_t *tp; + int wantmagic; + + bp = *bpp; + d = bp->data; + ptr = (char *)d->u; + nbad = 0; + needscan = needlog = 0; + freetab = *freetabp; + if (isblock) { + btp = XFS_DIR2_BLOCK_TAIL_P(mp, d); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + endptr = (char *)blp; + if (endptr > (char *)btp) + endptr = (char *)btp; + wantmagic = XFS_DIR2_BLOCK_MAGIC; + } else { + endptr = (char *)d + mp->m_dirblksize; + wantmagic = XFS_DIR2_DATA_MAGIC; + } + db = XFS_DIR2_DA_TO_DB(mp, da_bno); + if (freetab->naents <= db) { + struct freetab_ent e; + + *freetabp = freetab = realloc(freetab, FREETAB_SIZE(db + 1)); + if (!freetab) { + do_error( + "realloc failed in longform_dir2_entry_check_data (%u bytes)\n", + FREETAB_SIZE(db + 1)); + exit(1); + } + e.v = NULLDATAOFF; + e.s = 0; + for (i = freetab->naents; i < db; i++) + freetab->ents[i] = e; + freetab->naents = db + 1; + } + if (freetab->nents < db + 1) + freetab->nents = db + 1; + while (ptr < endptr) { + dup = (xfs_dir2_data_unused_t *)ptr; + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + if (ptr + INT_GET(dup->length, ARCH_CONVERT) > endptr || INT_GET(dup->length, ARCH_CONVERT) == 0 || + (INT_GET(dup->length, ARCH_CONVERT) & (XFS_DIR2_DATA_ALIGN - 1))) + break; + if (INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT) != + (char *)dup - (char *)d) + break; + ptr += INT_GET(dup->length, ARCH_CONVERT); + if (ptr >= endptr) + break; + } + dep = (xfs_dir2_data_entry_t *)ptr; + if (ptr + XFS_DIR2_DATA_ENTSIZE(dep->namelen) > endptr) + break; + if (INT_GET(*XFS_DIR2_DATA_ENTRY_TAG_P(dep), ARCH_CONVERT) != (char *)dep - (char *)d) + break; + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + if (ptr != endptr) { + do_warn("corrupt block %u in directory inode %llu: ", + da_bno, ip->i_ino); + if (!no_modify) { + do_warn("junking block\n"); + dir2_kill_block(mp, ip, da_bno, bp); + } else { + do_warn("would junk block\n"); + libxfs_da_brelse(NULL, bp); + } + freetab->ents[db].v = NULLDATAOFF; + *bpp = NULL; + return; + } + tp = libxfs_trans_alloc(mp, 0); + error = libxfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); + if (error) + res_failed(error); + libxfs_trans_ijoin(tp, ip, 0); + libxfs_trans_ihold(tp, ip); + libxfs_da_bjoin(tp, bp); + if (isblock) + libxfs_da_bhold(tp, bp); + XFS_BMAP_INIT(&flist, &firstblock); + if (INT_GET(d->hdr.magic, ARCH_CONVERT) != wantmagic) { + do_warn("bad directory block magic # %#x for directory inode " + "%llu block %d: ", + INT_GET(d->hdr.magic, ARCH_CONVERT), ip->i_ino, da_bno); + if (!no_modify) { + do_warn("fixing magic # to %#x\n", wantmagic); + INT_SET(d->hdr.magic, ARCH_CONVERT, wantmagic); + needlog = 1; + } else + do_warn("would fix magic # to %#x\n", wantmagic); + } + lastfree = 0; + ptr = (char *)d->u; + /* + * look at each entry. reference inode pointed to by each + * entry in the incore inode tree. + * if not a directory, set reached flag, increment link count + * if a directory and reached, mark entry as to be deleted. + * if a directory, check to see if recorded parent + * matches current inode #, + * if so, then set reached flag, increment link count + * of current and child dir inodes, push the child + * directory inode onto the directory stack. + * if current inode != parent, then mark entry to be deleted. + */ + while (ptr < endptr) { + dup = (xfs_dir2_data_unused_t *)ptr; + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + if (lastfree) { + do_warn("directory inode %llu block %u has " + "consecutive free entries: ", + ip->i_ino, da_bno); + if (!no_modify) { + do_warn("joining together\n"); + len = INT_GET(dup->length, ARCH_CONVERT); + libxfs_dir2_data_use_free(tp, bp, dup, + ptr - (char *)d, len, &needlog, + &needscan); + libxfs_dir2_data_make_free(tp, bp, + ptr - (char *)d, len, &needlog, + &needscan); + } else + do_warn("would join together\n"); + } + ptr += INT_GET(dup->length, ARCH_CONVERT); + lastfree = 1; + continue; + } + addr = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, db, ptr - (char *)d); + dep = (xfs_dir2_data_entry_t *)ptr; + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + lastfree = 0; + dir_hash_add(hashtab, + libxfs_da_hashname((char *)dep->name, dep->namelen), + addr, dep->name[0] == '/'); + /* + * skip bogus entries (leading '/'). they'll be deleted + * later + */ + if (dep->name[0] == '/') { + nbad++; + continue; + } + junkit = 0; + bcopy(dep->name, fname, dep->namelen); + fname[dep->namelen] = '\0'; + ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) != NULLFSINO); + /* + * skip the '..' entry since it's checked when the + * directory is reached by something else. if it never + * gets reached, it'll be moved to the orphanage and we'll + * take care of it then. + */ + if (dep->namelen == 2 && dep->name[0] == '.' && + dep->name[1] == '.') + continue; + ASSERT(no_modify || !verify_inum(mp, INT_GET(dep->inumber, ARCH_CONVERT))); + /* + * special case the . entry. we know there's only one + * '.' and only '.' points to itself because bogus entries + * got trashed in phase 3 if there were > 1. + * bump up link count for '.' but don't set reached + * until we're actually reached by another directory + * '..' is already accounted for or will be taken care + * of when directory is moved to orphanage. + */ + if (ip->i_ino == INT_GET(dep->inumber, ARCH_CONVERT)) { + ASSERT(dep->name[0] == '.' && dep->namelen == 1); + add_inode_ref(current_irec, current_ino_offset); + *need_dot = 0; + continue; + } + /* + * special case the "lost+found" entry if pointing + * to where we think lost+found should be. if that's + * the case, that's the one we created in phase 6. + * just skip it. no need to process it and it's .. + * link is already accounted for. + */ + if (INT_GET(dep->inumber, ARCH_CONVERT) == orphanage_ino && + strcmp(fname, ORPHANAGE) == 0) + continue; + /* + * skip entries with bogus inumbers if we're in no modify mode + */ + if (no_modify && verify_inum(mp, INT_GET(dep->inumber, ARCH_CONVERT))) + continue; + /* + * ok, now handle the rest of the cases besides '.' and '..' + */ + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, INT_GET(dep->inumber, ARCH_CONVERT)), + XFS_INO_TO_AGINO(mp, INT_GET(dep->inumber, ARCH_CONVERT))); + if (irec == NULL) { + nbad++; + do_warn("entry \"%s\" in directory inode %llu points " + "to non-existent inode, ", + fname, ip->i_ino); + if (!no_modify) { + dep->name[0] = '/'; + libxfs_dir2_data_log_entry(tp, bp, dep); + do_warn("marking entry to be junked\n"); + } else { + do_warn("would junk entry\n"); + } + continue; + } + ino_offset = + XFS_INO_TO_AGINO(mp, INT_GET(dep->inumber, ARCH_CONVERT)) - irec->ino_startnum; + /* + * if it's a free inode, blow out the entry. + * by now, any inode that we think is free + * really is free. + */ + if (is_inode_free(irec, ino_offset)) { + /* + * don't complain if this entry points to the old + * and now-free lost+found inode + */ + if (verbose || no_modify || + INT_GET(dep->inumber, ARCH_CONVERT) != old_orphanage_ino) + do_warn("entry \"%s\" in directory inode %llu " + "points to free inode %llu", + fname, ip->i_ino, INT_GET(dep->inumber, ARCH_CONVERT)); + nbad++; + if (!no_modify) { + if (verbose || + INT_GET(dep->inumber, ARCH_CONVERT) != old_orphanage_ino) + do_warn(", marking entry to be " + "junked\n"); + else + do_warn("\n"); + dep->name[0] = '/'; + libxfs_dir2_data_log_entry(tp, bp, dep); + } else { + do_warn(", would junk entry\n"); + } + continue; + } + /* + * check easy case first, regular inode, just bump + * the link count and continue + */ + if (!inode_isadir(irec, ino_offset)) { + add_inode_reached(irec, ino_offset); + continue; + } + parent = get_inode_parent(irec, ino_offset); + ASSERT(parent != 0); + /* + * bump up the link counts in parent and child + * directory but if the link doesn't agree with + * the .. in the child, blow out the entry. + * if the directory has already been reached, + * blow away the entry also. + */ + if (is_inode_reached(irec, ino_offset)) { + junkit = 1; + do_warn("entry \"%s\" in dir %llu points to an already " + "connected directory inode %llu,\n", fname, + ip->i_ino, INT_GET(dep->inumber, ARCH_CONVERT)); + } else if (parent == ip->i_ino) { + add_inode_reached(irec, ino_offset); + add_inode_ref(current_irec, current_ino_offset); + if (!is_inode_refchecked(INT_GET(dep->inumber, ARCH_CONVERT), irec, + ino_offset)) + push_dir(stack, INT_GET(dep->inumber, ARCH_CONVERT)); + } else { + junkit = 1; + do_warn("entry \"%s\" in directory inode %llu not " + "consistent with .. value (%llu) in ino " + "%llu,\n", + fname, ip->i_ino, parent, INT_GET(dep->inumber, ARCH_CONVERT)); + } + if (junkit) { + junkit = 0; + nbad++; + if (!no_modify) { + dep->name[0] = '/'; + libxfs_dir2_data_log_entry(tp, bp, dep); + if (verbose || + INT_GET(dep->inumber, ARCH_CONVERT) != old_orphanage_ino) + do_warn("\twill clear entry \"%s\"\n", + fname); + } else { + do_warn("\twould clear entry \"%s\"\n", fname); + } + } + } + *num_illegal += nbad; + if (needscan) + libxfs_dir2_data_freescan(mp, d, &needlog, NULL); + if (needlog) + libxfs_dir2_data_log_header(tp, bp); + libxfs_bmap_finish(&tp, &flist, firstblock, &committed); + libxfs_trans_commit(tp, 0, 0); + freetab->ents[db].v = INT_GET(d->hdr.bestfree[0].length, ARCH_CONVERT); + freetab->ents[db].s = 0; +} + +/* + * Check contents of leaf-form block. + */ +int +longform_dir2_check_leaf( + xfs_mount_t *mp, + xfs_inode_t *ip, + dir_hash_tab_t *hashtab, + freetab_t *freetab) +{ + int badtail; + xfs_dir2_data_off_t *bestsp; + xfs_dabuf_t *bp; + xfs_dablk_t da_bno; + int i; + xfs_dir2_leaf_t *leaf; + xfs_dir2_leaf_tail_t *ltp; + int seeval; + + da_bno = mp->m_dirleafblk; + if (libxfs_da_read_bufr(NULL, ip, da_bno, -1, &bp, XFS_DATA_FORK)) { + do_error("can't read block %u for directory inode %llu\n", + da_bno, ip->i_ino); + /* NOTREACHED */ + } + leaf = bp->data; + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR2_LEAF1_MAGIC || + INT_GET(leaf->hdr.info.forw, ARCH_CONVERT) || INT_GET(leaf->hdr.info.back, ARCH_CONVERT) || + INT_GET(leaf->hdr.count, ARCH_CONVERT) < INT_GET(leaf->hdr.stale, ARCH_CONVERT) || + INT_GET(leaf->hdr.count, ARCH_CONVERT) > XFS_DIR2_MAX_LEAF_ENTS(mp) || + (char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] > (char *)bestsp) { + do_warn("leaf block %u for directory inode %llu bad header\n", + da_bno, ip->i_ino); + libxfs_da_brelse(NULL, bp); + return 1; + } + seeval = dir_hash_see_all(hashtab, leaf->ents, INT_GET(leaf->hdr.count, ARCH_CONVERT), + INT_GET(leaf->hdr.stale, ARCH_CONVERT)); + if (dir_hash_check(hashtab, ip, seeval)) { + libxfs_da_brelse(NULL, bp); + return 1; + } + badtail = freetab->nents != INT_GET(ltp->bestcount, ARCH_CONVERT); + for (i = 0; !badtail && i < INT_GET(ltp->bestcount, ARCH_CONVERT); i++) { + freetab->ents[i].s = 1; + badtail = freetab->ents[i].v != INT_GET(bestsp[i], ARCH_CONVERT); + } + if (badtail) { + do_warn("leaf block %u for directory inode %llu bad tail\n", + da_bno, ip->i_ino); + libxfs_da_brelse(NULL, bp); + return 1; + } + libxfs_da_brelse(NULL, bp); + return 0; +} + +/* + * Check contents of the node blocks (leaves) + * Looks for matching hash values for the data entries. + */ +int +longform_dir2_check_node( + xfs_mount_t *mp, + xfs_inode_t *ip, + dir_hash_tab_t *hashtab, + freetab_t *freetab) +{ + xfs_dabuf_t *bp; + xfs_dablk_t da_bno; + xfs_dir2_db_t fdb; + xfs_dir2_free_t *free; + int i; + xfs_dir2_leaf_t *leaf; + xfs_fileoff_t next_da_bno; + int seeval = 0; + int used; + + for (da_bno = mp->m_dirleafblk, next_da_bno = 0; + next_da_bno != NULLFILEOFF && da_bno < mp->m_dirfreeblk; + da_bno = (xfs_dablk_t)next_da_bno) { + next_da_bno = da_bno + mp->m_dirblkfsbs - 1; + if (libxfs_bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK)) + break; + if (libxfs_da_read_bufr(NULL, ip, da_bno, -1, &bp, + XFS_DATA_FORK)) { + do_error("can't read block %u for directory inode " + "%llu\n", + da_bno, ip->i_ino); + /* NOTREACHED */ + } + leaf = bp->data; + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR2_LEAFN_MAGIC) { + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) { + libxfs_da_brelse(NULL, bp); + continue; + } + do_warn("unknown magic number %#x for block %u in " + "directory inode %llu\n", + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), da_bno, ip->i_ino); + libxfs_da_brelse(NULL, bp); + return 1; + } + if (INT_GET(leaf->hdr.count, ARCH_CONVERT) < INT_GET(leaf->hdr.stale, ARCH_CONVERT) || + INT_GET(leaf->hdr.count, ARCH_CONVERT) > XFS_DIR2_MAX_LEAF_ENTS(mp)) { + do_warn("leaf block %u for directory inode %llu bad " + "header\n", + da_bno, ip->i_ino); + libxfs_da_brelse(NULL, bp); + return 1; + } + seeval = dir_hash_see_all(hashtab, leaf->ents, INT_GET(leaf->hdr.count, ARCH_CONVERT), + INT_GET(leaf->hdr.stale, ARCH_CONVERT)); + libxfs_da_brelse(NULL, bp); + if (seeval != DIR_HASH_CK_OK) + return 1; + } + if (dir_hash_check(hashtab, ip, seeval)) + return 1; + for (da_bno = mp->m_dirfreeblk, next_da_bno = 0; + next_da_bno != NULLFILEOFF; + da_bno = (xfs_dablk_t)next_da_bno) { + next_da_bno = da_bno + mp->m_dirblkfsbs - 1; + if (libxfs_bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK)) + break; + if (libxfs_da_read_bufr(NULL, ip, da_bno, -1, &bp, + XFS_DATA_FORK)) { + do_error("can't read block %u for directory inode " + "%llu\n", + da_bno, ip->i_ino); + /* NOTREACHED */ + } + free = bp->data; + fdb = XFS_DIR2_DA_TO_DB(mp, da_bno); + if (INT_GET(free->hdr.magic, ARCH_CONVERT) != XFS_DIR2_FREE_MAGIC || + INT_GET(free->hdr.firstdb, ARCH_CONVERT) != + (fdb - XFS_DIR2_FREE_FIRSTDB(mp)) * + XFS_DIR2_MAX_FREE_BESTS(mp) || + INT_GET(free->hdr.nvalid, ARCH_CONVERT) < INT_GET(free->hdr.nused, ARCH_CONVERT)) { + do_warn("free block %u for directory inode %llu bad " + "header\n", + da_bno, ip->i_ino); + libxfs_da_brelse(NULL, bp); + return 1; + } + for (i = used = 0; i < INT_GET(free->hdr.nvalid, ARCH_CONVERT); i++) { + if (i + INT_GET(free->hdr.firstdb, ARCH_CONVERT) >= freetab->nents || + freetab->ents[i + INT_GET(free->hdr.firstdb, ARCH_CONVERT)].v != + INT_GET(free->bests[i], ARCH_CONVERT)) { + do_warn("free block %u entry %i for directory " + "ino %llu bad\n", + da_bno, i, ip->i_ino); + libxfs_da_brelse(NULL, bp); + return 1; + } + used += INT_GET(free->bests[i], ARCH_CONVERT) != NULLDATAOFF; + freetab->ents[i + INT_GET(free->hdr.firstdb, ARCH_CONVERT)].s = 1; + } + if (used != INT_GET(free->hdr.nused, ARCH_CONVERT)) { + do_warn("free block %u for directory inode %llu bad " + "nused\n", + da_bno, ip->i_ino); + libxfs_da_brelse(NULL, bp); + return 1; + } + libxfs_da_brelse(NULL, bp); + } + for (i = 0; i < freetab->nents; i++) { + if (freetab->ents[i].s == 0) { + do_warn("missing freetab entry %u for directory inode " + "%llu\n", + i, ip->i_ino); + return 1; + } + } + return 0; +} + +/* + * Rebuild a directory: set up. + * Turn it into a node-format directory with no contents in the + * upper area. Also has correct freespace blocks. + */ +void +longform_dir2_rebuild_setup( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_inode_t *ip, + freetab_t *freetab) +{ + xfs_da_args_t args; + int committed; + xfs_dir2_data_t *data; + xfs_dabuf_t *dbp; + int error; + xfs_dir2_db_t fbno; + xfs_dabuf_t *fbp; + xfs_fsblock_t firstblock; + xfs_bmap_free_t flist; + xfs_dir2_free_t *free; + int i; + int j; + xfs_dablk_t lblkno; + xfs_dabuf_t *lbp; + xfs_dir2_leaf_t *leaf; + int nres; + xfs_trans_t *tp; + + tp = libxfs_trans_alloc(mp, 0); + nres = XFS_DAENTER_SPACE_RES(mp, XFS_DATA_FORK); + error = libxfs_trans_reserve(tp, + nres, XFS_CREATE_LOG_RES(mp), 0, XFS_TRANS_PERM_LOG_RES, + XFS_CREATE_LOG_COUNT); + if (error) + res_failed(error); + libxfs_trans_ijoin(tp, ip, 0); + libxfs_trans_ihold(tp, ip); + XFS_BMAP_INIT(&flist, &firstblock); + if (libxfs_da_read_buf(tp, ip, mp->m_dirdatablk, -2, &dbp, + XFS_DATA_FORK)) { + do_error("can't read block %u for directory inode %llu\n", + mp->m_dirdatablk, ino); + /* NOTREACHED */ + } + if (dbp && (data = dbp->data)->hdr.magic == XFS_DIR2_BLOCK_MAGIC) { + xfs_dir2_block_t *block; + xfs_dir2_leaf_entry_t *blp; + xfs_dir2_block_tail_t *btp; + int needlog; + int needscan; + + INT_SET(data->hdr.magic, ARCH_CONVERT, XFS_DIR2_DATA_MAGIC); + block = (xfs_dir2_block_t *)data; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + needlog = needscan = 0; + libxfs_dir2_data_make_free(tp, dbp, (char *)blp - (char *)block, + (char *)block + mp->m_dirblksize - (char *)blp, + &needlog, &needscan); + if (needscan) + libxfs_dir2_data_freescan(mp, data, &needlog, NULL); + libxfs_da_log_buf(tp, dbp, 0, mp->m_dirblksize - 1); + } + bzero(&args, sizeof(args)); + args.trans = tp; + args.dp = ip; + args.whichfork = XFS_DATA_FORK; + args.firstblock = &firstblock; + args.flist = &flist; + args.total = nres; + if ((error = libxfs_da_grow_inode(&args, &lblkno)) || + (error = libxfs_da_get_buf(tp, ip, lblkno, -1, &lbp, XFS_DATA_FORK))) { + do_error("can't add btree block to directory inode %llu\n", + ino); + /* NOTREACHED */ + } + leaf = lbp->data; + bzero(leaf, mp->m_dirblksize); + INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, XFS_DIR2_LEAFN_MAGIC); + libxfs_da_log_buf(tp, lbp, 0, mp->m_dirblksize - 1); + libxfs_bmap_finish(&tp, &flist, firstblock, &committed); + libxfs_trans_commit(tp, 0, 0); + + for (i = 0; i < freetab->nents; i += XFS_DIR2_MAX_FREE_BESTS(mp)) { + tp = libxfs_trans_alloc(mp, 0); + nres = XFS_DAENTER_SPACE_RES(mp, XFS_DATA_FORK); + error = libxfs_trans_reserve(tp, + nres, XFS_CREATE_LOG_RES(mp), 0, XFS_TRANS_PERM_LOG_RES, + XFS_CREATE_LOG_COUNT); + if (error) + res_failed(error); + libxfs_trans_ijoin(tp, ip, 0); + libxfs_trans_ihold(tp, ip); + XFS_BMAP_INIT(&flist, &firstblock); + bzero(&args, sizeof(args)); + args.trans = tp; + args.dp = ip; + args.whichfork = XFS_DATA_FORK; + args.firstblock = &firstblock; + args.flist = &flist; + args.total = nres; + if ((error = libxfs_dir2_grow_inode(&args, XFS_DIR2_FREE_SPACE, + &fbno)) || + (error = libxfs_da_get_buf(tp, ip, XFS_DIR2_DB_TO_DA(mp, fbno), + -1, &fbp, XFS_DATA_FORK))) { + do_error("can't add free block to directory inode " + "%llu\n", + ino); + /* NOTREACHED */ + } + free = fbp->data; + bzero(free, mp->m_dirblksize); + INT_SET(free->hdr.magic, ARCH_CONVERT, XFS_DIR2_FREE_MAGIC); + INT_SET(free->hdr.firstdb, ARCH_CONVERT, i); + INT_SET(free->hdr.nvalid, ARCH_CONVERT, XFS_DIR2_MAX_FREE_BESTS(mp)); + if (i + INT_GET(free->hdr.nvalid, ARCH_CONVERT) > freetab->nents) + INT_SET(free->hdr.nvalid, ARCH_CONVERT, freetab->nents - i); + for (j = 0; j < INT_GET(free->hdr.nvalid, ARCH_CONVERT); j++) { + INT_SET(free->bests[j], ARCH_CONVERT, freetab->ents[i + j].v); + if (INT_GET(free->bests[j], ARCH_CONVERT) != NULLDATAOFF) + INT_MOD(free->hdr.nused, ARCH_CONVERT, +1); + } + libxfs_da_log_buf(tp, fbp, 0, mp->m_dirblksize - 1); + libxfs_bmap_finish(&tp, &flist, firstblock, &committed); + libxfs_trans_commit(tp, 0, 0); + } +} + +/* + * Rebuild the entries from a single data block. + */ +void +longform_dir2_rebuild_data( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_inode_t *ip, + xfs_dablk_t da_bno) +{ + xfs_dabuf_t *bp; + xfs_dir2_block_tail_t *btp; + int committed; + xfs_dir2_data_t *data; + xfs_dir2_db_t dbno; + xfs_dir2_data_entry_t *dep; + xfs_dir2_data_unused_t *dup; + char *endptr; + int error; + xfs_dir2_free_t *fblock; + xfs_dabuf_t *fbp; + xfs_dir2_db_t fdb; + int fi; + xfs_fsblock_t firstblock; + xfs_bmap_free_t flist; + int needlog; + int needscan; + int nres; + char *ptr; + xfs_trans_t *tp; + + if (libxfs_da_read_buf(NULL, ip, da_bno, da_bno == 0 ? -2 : -1, &bp, + XFS_DATA_FORK)) { + do_error("can't read block %u for directory inode %llu\n", + da_bno, ino); + /* NOTREACHED */ + } + if (da_bno == 0 && bp == NULL) + /* + * The block was punched out. + */ + return; + ASSERT(bp); + dbno = XFS_DIR2_DA_TO_DB(mp, da_bno); + fdb = XFS_DIR2_DB_TO_FDB(mp, dbno); + if (libxfs_da_read_buf(NULL, ip, XFS_DIR2_DB_TO_DA(mp, fdb), -1, &fbp, + XFS_DATA_FORK)) { + do_error("can't read block %u for directory inode %llu\n", + XFS_DIR2_DB_TO_DA(mp, fdb), ino); + /* NOTREACHED */ + } + data = malloc(mp->m_dirblksize); + if (!data) { + do_error( + "malloc failed in longform_dir2_rebuild_data (%u bytes)\n", + mp->m_dirblksize); + exit(1); + } + bcopy(bp->data, data, mp->m_dirblksize); + ptr = (char *)data->u; + if (INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)data); + endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + } else + endptr = (char *)data + mp->m_dirblksize; + fblock = fbp->data; + fi = XFS_DIR2_DB_TO_FDINDEX(mp, dbno); + tp = libxfs_trans_alloc(mp, 0); + error = libxfs_trans_reserve(tp, 0, XFS_CREATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); + if (error) + res_failed(error); + libxfs_trans_ijoin(tp, ip, 0); + libxfs_trans_ihold(tp, ip); + libxfs_da_bjoin(tp, bp); + libxfs_da_bhold(tp, bp); + libxfs_da_bjoin(tp, fbp); + libxfs_da_bhold(tp, fbp); + XFS_BMAP_INIT(&flist, &firstblock); + needlog = needscan = 0; + bzero(((xfs_dir2_data_t *)(bp->data))->hdr.bestfree, + sizeof(data->hdr.bestfree)); + libxfs_dir2_data_make_free(tp, bp, (xfs_dir2_data_aoff_t)sizeof(data->hdr), + mp->m_dirblksize - sizeof(data->hdr), &needlog, &needscan); + ASSERT(needscan == 0); + libxfs_dir2_data_log_header(tp, bp); + INT_SET(fblock->bests[fi], ARCH_CONVERT, + INT_GET(((xfs_dir2_data_t *)(bp->data))->hdr.bestfree[0].length, ARCH_CONVERT)); + libxfs_dir2_free_log_bests(tp, fbp, fi, fi); + libxfs_bmap_finish(&tp, &flist, firstblock, &committed); + libxfs_trans_commit(tp, 0, 0); + + while (ptr < endptr) { + dup = (xfs_dir2_data_unused_t *)ptr; + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + ptr += INT_GET(dup->length, ARCH_CONVERT); + continue; + } + dep = (xfs_dir2_data_entry_t *)ptr; + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + if (dep->name[0] == '/') + continue; + tp = libxfs_trans_alloc(mp, 0); + nres = XFS_CREATE_SPACE_RES(mp, dep->namelen); + error = libxfs_trans_reserve(tp, nres, XFS_CREATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); + if (error) + res_failed(error); + libxfs_trans_ijoin(tp, ip, 0); + libxfs_trans_ihold(tp, ip); + libxfs_da_bjoin(tp, bp); + libxfs_da_bhold(tp, bp); + libxfs_da_bjoin(tp, fbp); + libxfs_da_bhold(tp, fbp); + XFS_BMAP_INIT(&flist, &firstblock); + error = dir_createname(mp, tp, ip, (char *)dep->name, + dep->namelen, INT_GET(dep->inumber, ARCH_CONVERT), + &firstblock, &flist, nres); + ASSERT(error == 0); + libxfs_bmap_finish(&tp, &flist, firstblock, &committed); + libxfs_trans_commit(tp, 0, 0); + } + libxfs_da_brelse(NULL, bp); + libxfs_da_brelse(NULL, fbp); + free(data); +} + +/* + * Finish the rebuild of a directory. + * Stuff / in and then remove it, this forces the directory to end + * up in the right format. + */ +void +longform_dir2_rebuild_finish( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_inode_t *ip) +{ + int committed; + int error; + xfs_fsblock_t firstblock; + xfs_bmap_free_t flist; + int nres; + xfs_trans_t *tp; + + tp = libxfs_trans_alloc(mp, 0); + nres = XFS_CREATE_SPACE_RES(mp, 1); + error = libxfs_trans_reserve(tp, nres, XFS_CREATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); + if (error) + res_failed(error); + libxfs_trans_ijoin(tp, ip, 0); + libxfs_trans_ihold(tp, ip); + XFS_BMAP_INIT(&flist, &firstblock); + error = dir_createname(mp, tp, ip, "/", 1, ino, + &firstblock, &flist, nres); + ASSERT(error == 0); + libxfs_bmap_finish(&tp, &flist, firstblock, &committed); + libxfs_trans_commit(tp, 0, 0); + + /* could kill trailing empty data blocks here */ + + tp = libxfs_trans_alloc(mp, 0); + nres = XFS_REMOVE_SPACE_RES(mp); + error = libxfs_trans_reserve(tp, nres, XFS_REMOVE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); + if (error) + res_failed(error); + libxfs_trans_ijoin(tp, ip, 0); + libxfs_trans_ihold(tp, ip); + XFS_BMAP_INIT(&flist, &firstblock); + error = dir_removename(mp, tp, ip, "/", 1, ino, + &firstblock, &flist, nres); + ASSERT(error == 0); + libxfs_bmap_finish(&tp, &flist, firstblock, &committed); + libxfs_trans_commit(tp, 0, 0); +} + +/* + * Rebuild a directory. + * Remove all the non-data blocks. + * Re-initialize to (empty) node form. + * Loop over the data blocks reinserting each entry. + * Force the directory into the right format. + */ +void +longform_dir2_rebuild( + xfs_mount_t *mp, + xfs_ino_t ino, + xfs_inode_t *ip, + int *num_illegal, + freetab_t *freetab, + int isblock) +{ + xfs_dabuf_t *bp; + xfs_dablk_t da_bno; + xfs_fileoff_t next_da_bno; + + do_warn("rebuilding directory inode %llu\n", ino); + for (da_bno = mp->m_dirleafblk, next_da_bno = isblock ? NULLFILEOFF : 0; + next_da_bno != NULLFILEOFF; + da_bno = (xfs_dablk_t)next_da_bno) { + next_da_bno = da_bno + mp->m_dirblkfsbs - 1; + if (libxfs_bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK)) + break; + if (libxfs_da_get_buf(NULL, ip, da_bno, -1, &bp, XFS_DATA_FORK)) { + do_error("can't get block %u for directory inode " + "%llu\n", + da_bno, ino); + /* NOTREACHED */ + } + dir2_kill_block(mp, ip, da_bno, bp); + } + longform_dir2_rebuild_setup(mp, ino, ip, freetab); + for (da_bno = mp->m_dirdatablk, next_da_bno = 0; + da_bno < mp->m_dirleafblk && next_da_bno != NULLFILEOFF; + da_bno = (xfs_dablk_t)next_da_bno) { + next_da_bno = da_bno + mp->m_dirblkfsbs - 1; + if (libxfs_bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK)) + break; + longform_dir2_rebuild_data(mp, ino, ip, da_bno); + } + longform_dir2_rebuild_finish(mp, ino, ip); + *num_illegal = 0; +} + +/* + * succeeds or dies, inode never gets dirtied since all changes + * happen in file blocks. the inode size and other core info + * is already correct, it's just the leaf entries that get altered. + * XXX above comment is wrong for v2 - need to see why it matters + */ +void +longform_dir2_entry_check(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_inode_t *ip, + int *num_illegal, + int *need_dot, + dir_stack_t *stack, + ino_tree_node_t *irec, + int ino_offset) +{ + xfs_dir2_block_t *block; + xfs_dir2_leaf_entry_t *blp; + xfs_dabuf_t *bp; + xfs_dir2_block_tail_t *btp; + xfs_dablk_t da_bno; + freetab_t *freetab; + dir_hash_tab_t *hashtab; + int i; + int isblock; + int isleaf; + xfs_fileoff_t next_da_bno; + int seeval; + int fixit; + + *need_dot = 1; + freetab = malloc(FREETAB_SIZE(ip->i_d.di_size / mp->m_dirblksize)); + if (!freetab) { + do_error( + "malloc failed in longform_dir2_entry_check (%u bytes)\n", + FREETAB_SIZE(ip->i_d.di_size / mp->m_dirblksize)); + exit(1); + } + freetab->naents = ip->i_d.di_size / mp->m_dirblksize; + freetab->nents = 0; + for (i = 0; i < freetab->naents; i++) { + freetab->ents[i].v = NULLDATAOFF; + freetab->ents[i].s = 0; + } + libxfs_dir2_isblock(NULL, ip, &isblock); + libxfs_dir2_isleaf(NULL, ip, &isleaf); + hashtab = dir_hash_init(ip->i_d.di_size); + for (da_bno = 0, next_da_bno = 0; + next_da_bno != NULLFILEOFF && da_bno < mp->m_dirleafblk; + da_bno = (xfs_dablk_t)next_da_bno) { + next_da_bno = da_bno + mp->m_dirblkfsbs - 1; + if (libxfs_bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK)) + break; + if (libxfs_da_read_bufr(NULL, ip, da_bno, -1, &bp, + XFS_DATA_FORK)) { + do_error("can't read block %u for directory inode " + "%llu\n", + da_bno, ino); + /* NOTREACHED */ + } + longform_dir2_entry_check_data(mp, ip, num_illegal, need_dot, + stack, irec, ino_offset, &bp, hashtab, &freetab, da_bno, + isblock); + /* it releases the buffer unless isblock is set */ + } + fixit = (*num_illegal != 0) || dir2_is_badino(ino); + if (isblock) { + ASSERT(bp); + block = bp->data; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + seeval = dir_hash_see_all(hashtab, blp, INT_GET(btp->count, ARCH_CONVERT), INT_GET(btp->stale, ARCH_CONVERT)); + if (dir_hash_check(hashtab, ip, seeval)) + fixit |= 1; + libxfs_da_brelse(NULL, bp); + } else if (isleaf) { + fixit |= longform_dir2_check_leaf(mp, ip, hashtab, freetab); + } else { + fixit |= longform_dir2_check_node(mp, ip, hashtab, freetab); + } + dir_hash_done(hashtab); + if (!no_modify && fixit) + longform_dir2_rebuild(mp, ino, ip, num_illegal, freetab, + isblock); + free(freetab); +} + +/* + * shortform directory processing routines -- entry verification and + * bad entry deletion (pruning). + */ +void +shortform_dir_entry_check(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_inode_t *ip, + int *ino_dirty, + dir_stack_t *stack, + ino_tree_node_t *current_irec, + int current_ino_offset) +{ + xfs_ino_t lino; + xfs_ino_t parent; + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe; + xfs_ifork_t *ifp; + ino_tree_node_t *irec; + int max_size; + int ino_offset; + int i; + int junkit; + int tmp_len; + int tmp_elen; + int bad_sfnamelen; + int namelen; + int bytes_deleted; + char fname[MAXNAMELEN + 1]; + + ifp = &ip->i_df; + sf = (xfs_dir_shortform_t *) ifp->if_u1.if_data; + *ino_dirty = 0; + bytes_deleted = 0; + + max_size = ifp->if_bytes; + ASSERT(ip->i_d.di_size <= ifp->if_bytes); + + /* + * no '.' entry in shortform dirs, just bump up ref count by 1 + * '..' was already (or will be) accounted for and checked when + * the directory is reached or will be taken care of when the + * directory is moved to orphanage. + */ + add_inode_ref(current_irec, current_ino_offset); + + /* + * now run through entries, stop at first bad entry, don't need + * to skip over '..' since that's encoded in its own field and + * no need to worry about '.' since it doesn't exist. + */ + sf_entry = next_sfe = &sf->list[0]; + if (sf == NULL) { + junkit = 1; + do_warn("shortform dir inode %llu has null data entries \n", ino); + + } + else { + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT) && max_size > + (__psint_t)next_sfe - (__psint_t)sf; + sf_entry = next_sfe, i++) { + junkit = 0; + bad_sfnamelen = 0; + tmp_sfe = NULL; + + XFS_DIR_SF_GET_DIRINO_ARCH(&sf_entry->inumber, &lino, ARCH_CONVERT); + + namelen = sf_entry->namelen; + + ASSERT(no_modify || namelen > 0); + + if (no_modify && namelen == 0) { + /* + * if we're really lucky, this is + * the last entry in which case we + * can use the dir size to set the + * namelen value. otherwise, forget + * it because we're not going to be + * able to find the next entry. + */ + bad_sfnamelen = 1; + + if (i == INT_GET(sf->hdr.count, ARCH_CONVERT) - 1) { + namelen = ip->i_d.di_size - + ((__psint_t) &sf_entry->name[0] - + (__psint_t) sf); + } else { + /* + * don't process the rest of the directory, + * break out of processing looop + */ + break; + } + } else if (no_modify && (__psint_t) sf_entry - (__psint_t) sf + + + XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry) + > ip->i_d.di_size) { + bad_sfnamelen = 1; + + if (i == INT_GET(sf->hdr.count, ARCH_CONVERT) - 1) { + namelen = ip->i_d.di_size - + ((__psint_t) &sf_entry->name[0] - + (__psint_t) sf); + } else { + /* + * don't process the rest of the directory, + * break out of processing looop + */ + break; + } + } + + bcopy(sf_entry->name, fname, sf_entry->namelen); + fname[sf_entry->namelen] = '\0'; + + ASSERT(no_modify || lino != NULLFSINO); + ASSERT(no_modify || !verify_inum(mp, lino)); + + /* + * special case the "lost+found" entry if it's pointing + * to where we think lost+found should be. if that's + * the case, that's the one we created in phase 6. + * just skip it. no need to process it and its .. + * link is already accounted for. Also skip entries + * with bogus inode numbers if we're in no modify mode. + */ + + if ((lino == orphanage_ino && strcmp(fname, ORPHANAGE) == 0) + || (no_modify && verify_inum(mp, lino))) { + next_sfe = (xfs_dir_sf_entry_t *) + ((__psint_t) sf_entry + + XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry)); + continue; + } + + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, lino), + XFS_INO_TO_AGINO(mp, lino)); + + if (irec == NULL && no_modify) { + do_warn( +"entry \"%s\" in shortform dir %llu references non-existent ino %llu\n", + fname, ino, lino); + do_warn("would junk entry\n"); + continue; + } + + ASSERT(irec != NULL); + + ino_offset = XFS_INO_TO_AGINO(mp, lino) - irec->ino_startnum; + + /* + * if it's a free inode, blow out the entry. + * by now, any inode that we think is free + * really is free. + */ + if (is_inode_free(irec, ino_offset)) { + /* + * don't complain if this entry points to the old + * and now-free lost+found inode + */ + if (verbose || no_modify || lino != old_orphanage_ino) + do_warn( + "entry \"%s\" in shortform dir inode %llu points to free inode %llu\n", + fname, ino, lino); + + if (!no_modify) { + junkit = 1; + } else { + do_warn("would junk entry \"%s\"\n", + fname); + } + } else if (!inode_isadir(irec, ino_offset)) { + /* + * check easy case first, regular inode, just bump + * the link count and continue + */ + add_inode_reached(irec, ino_offset); + + next_sfe = (xfs_dir_sf_entry_t *) + ((__psint_t) sf_entry + + XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry)); + continue; + } else { + parent = get_inode_parent(irec, ino_offset); + + /* + * bump up the link counts in parent and child. + * directory but if the link doesn't agree with + * the .. in the child, blow out the entry + */ + if (is_inode_reached(irec, ino_offset)) { + junkit = 1; + do_warn( + "entry \"%s\" in dir %llu references already connected dir ino %llu,\n", + fname, ino, lino); + } else if (parent == ino) { + add_inode_reached(irec, ino_offset); + add_inode_ref(current_irec, current_ino_offset); + + if (!is_inode_refchecked(lino, irec, + ino_offset)) + push_dir(stack, lino); + } else { + junkit = 1; + do_warn( +"entry \"%s\" in dir %llu not consistent with .. value (%llu) in dir ino %llu,\n", + fname, ino, parent, lino); + } + } + + if (junkit) { + if (!no_modify) { + tmp_elen = XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry); + tmp_sfe = (xfs_dir_sf_entry_t *) + ((__psint_t) sf_entry + tmp_elen); + tmp_len = max_size - ((__psint_t) tmp_sfe + - (__psint_t) sf); + max_size -= tmp_elen; + bytes_deleted += tmp_elen; + + memmove(sf_entry, tmp_sfe, tmp_len); + + INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); + bzero((void *) ((__psint_t) sf_entry + tmp_len), + tmp_elen); + + /* + * set the tmp value to the current + * pointer so we'll process the entry + * we just moved up + */ + tmp_sfe = sf_entry; + + /* + * WARNING: drop the index i by one + * so it matches the decremented count for + * accurate comparisons in the loop test + */ + i--; + + *ino_dirty = 1; + + if (verbose || lino != old_orphanage_ino) + do_warn( + "junking entry \"%s\" in directory inode %llu\n", + fname, lino); + } else { + do_warn("would junk entry \"%s\"\n", fname); + } + } + + /* + * go onto next entry unless we've just junked an + * entry in which the current entry pointer points + * to an unprocessed entry. have to take into entries + * with bad namelen into account in no modify mode since we + * calculate size based on next_sfe. + */ + ASSERT(no_modify || bad_sfnamelen == 0); + + next_sfe = (tmp_sfe == NULL) + ? (xfs_dir_sf_entry_t *) ((__psint_t) sf_entry + + ((!bad_sfnamelen) + ? XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry) + : sizeof(xfs_dir_sf_entry_t) - 1 + + namelen)) + : tmp_sfe; + } + } + + /* + * sync up sizes if required + */ + if (*ino_dirty) { + ASSERT(bytes_deleted > 0); + ASSERT(!no_modify); + libxfs_idata_realloc(ip, -bytes_deleted, XFS_DATA_FORK); + ip->i_d.di_size -= bytes_deleted; + } + + if (ip->i_d.di_size != ip->i_df.if_bytes) { + ASSERT(ip->i_df.if_bytes == (xfs_fsize_t) + ((__psint_t) next_sfe - (__psint_t) sf)); + ip->i_d.di_size = (xfs_fsize_t) + ((__psint_t) next_sfe - (__psint_t) sf); + do_warn( + "setting size to %lld bytes to reflect junked entries\n", + ip->i_d.di_size); + *ino_dirty = 1; + } +} + +/* ARGSUSED */ +void +prune_sf_dir_entry(xfs_mount_t *mp, xfs_ino_t ino, xfs_inode_t *ip) +{ + /* REFERENCED */ + xfs_ino_t lino; + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe; + xfs_ifork_t *ifp; + int max_size; + int i; + int tmp_len; + int tmp_elen; + int bytes_deleted; + char fname[MAXNAMELEN + 1]; + + ifp = &ip->i_df; + sf = (xfs_dir_shortform_t *) ifp->if_u1.if_data; + bytes_deleted = 0; + + max_size = ifp->if_bytes; + ASSERT(ip->i_d.di_size <= ifp->if_bytes); + + /* + * now run through entries and delete every bad entry + */ + sf_entry = next_sfe = &sf->list[0]; + + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT) && max_size > + (__psint_t)next_sfe - (__psint_t)sf; + sf_entry = next_sfe, i++) { + tmp_sfe = NULL; + + XFS_DIR_SF_GET_DIRINO_ARCH(&sf_entry->inumber, &lino, ARCH_CONVERT); + + bcopy(sf_entry->name, fname, sf_entry->namelen); + fname[sf_entry->namelen] = '\0'; + + if (sf_entry->name[0] == '/') { + if (!no_modify) { + tmp_elen = XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry); + tmp_sfe = (xfs_dir_sf_entry_t *) + ((__psint_t) sf_entry + tmp_elen); + tmp_len = max_size - ((__psint_t) tmp_sfe + - (__psint_t) sf); + max_size -= tmp_elen; + bytes_deleted += tmp_elen; + + memmove(sf_entry, tmp_sfe, tmp_len); + + INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); + bzero((void *) ((__psint_t) sf_entry + tmp_len), + tmp_elen); + + /* + * set the tmp value to the current + * pointer so we'll process the entry + * we just moved up + */ + tmp_sfe = sf_entry; + + /* + * WARNING: drop the index i by one + * so it matches the decremented count for + * accurate comparisons in the loop test + */ + i--; + } + } + next_sfe = (tmp_sfe == NULL) + ? (xfs_dir_sf_entry_t *) ((__psint_t) sf_entry + + XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry)) + : tmp_sfe; + } + + /* + * sync up sizes if required + */ + if (bytes_deleted > 0) { + libxfs_idata_realloc(ip, -bytes_deleted, XFS_DATA_FORK); + ip->i_d.di_size -= bytes_deleted; + } + + if (ip->i_d.di_size != ip->i_df.if_bytes) { + ASSERT(ip->i_df.if_bytes == (xfs_fsize_t) + ((__psint_t) next_sfe - (__psint_t) sf)); + ip->i_d.di_size = (xfs_fsize_t) + ((__psint_t) next_sfe - (__psint_t) sf); + do_warn( + "setting size to %lld bytes to reflect junked entries\n", + ip->i_d.di_size); + } +} + +/* + * shortform directory v2 processing routines -- entry verification and + * bad entry deletion (pruning). + */ +void +shortform_dir2_entry_check(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_inode_t *ip, + int *ino_dirty, + dir_stack_t *stack, + ino_tree_node_t *current_irec, + int current_ino_offset) +{ + xfs_ino_t lino; + xfs_ino_t parent; + xfs_dir2_sf_t *sfp; + xfs_dir2_sf_entry_t *sfep, *next_sfep, *tmp_sfep; + xfs_ifork_t *ifp; + ino_tree_node_t *irec; + int max_size; + int ino_offset; + int i; + int junkit; + int tmp_len; + int tmp_elen; + int bad_sfnamelen; + int namelen; + int bytes_deleted; + char fname[MAXNAMELEN + 1]; + int i8; + + ifp = &ip->i_df; + sfp = (xfs_dir2_sf_t *) ifp->if_u1.if_data; + *ino_dirty = 0; + bytes_deleted = i8 = 0; + + max_size = ifp->if_bytes; + ASSERT(ip->i_d.di_size <= ifp->if_bytes); + + /* + * no '.' entry in shortform dirs, just bump up ref count by 1 + * '..' was already (or will be) accounted for and checked when + * the directory is reached or will be taken care of when the + * directory is moved to orphanage. + */ + add_inode_ref(current_irec, current_ino_offset); + + /* + * now run through entries, stop at first bad entry, don't need + * to skip over '..' since that's encoded in its own field and + * no need to worry about '.' since it doesn't exist. + */ + sfep = next_sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + + for (i = 0; i < INT_GET(sfp->hdr.count, ARCH_CONVERT) && max_size > + (__psint_t)next_sfep - (__psint_t)sfp; + sfep = next_sfep, i++) { + junkit = 0; + bad_sfnamelen = 0; + tmp_sfep = NULL; + + lino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + + namelen = sfep->namelen; + + ASSERT(no_modify || namelen > 0); + + if (no_modify && namelen == 0) { + /* + * if we're really lucky, this is + * the last entry in which case we + * can use the dir size to set the + * namelen value. otherwise, forget + * it because we're not going to be + * able to find the next entry. + */ + bad_sfnamelen = 1; + + if (i == INT_GET(sfp->hdr.count, ARCH_CONVERT) - 1) { + namelen = ip->i_d.di_size - + ((__psint_t) &sfep->name[0] - + (__psint_t) sfp); + } else { + /* + * don't process the rest of the directory, + * break out of processing loop + */ + break; + } + } else if (no_modify && (__psint_t) sfep - (__psint_t) sfp + + + XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep) + > ip->i_d.di_size) { + bad_sfnamelen = 1; + + if (i == INT_GET(sfp->hdr.count, ARCH_CONVERT) - 1) { + namelen = ip->i_d.di_size - + ((__psint_t) &sfep->name[0] - + (__psint_t) sfp); + } else { + /* + * don't process the rest of the directory, + * break out of processing loop + */ + break; + } + } + + bcopy(sfep->name, fname, sfep->namelen); + fname[sfep->namelen] = '\0'; + + ASSERT(no_modify || (lino != NULLFSINO && lino != 0)); + ASSERT(no_modify || !verify_inum(mp, lino)); + + /* + * special case the "lost+found" entry if it's pointing + * to where we think lost+found should be. if that's + * the case, that's the one we created in phase 6. + * just skip it. no need to process it and its .. + * link is already accounted for. Also skip entries + * with bogus inode numbers if we're in no modify mode. + */ + + if ((lino == orphanage_ino && strcmp(fname, ORPHANAGE) == 0) + || (no_modify && verify_inum(mp, lino))) { + next_sfep = (xfs_dir2_sf_entry_t *) + ((__psint_t) sfep + + XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep)); + continue; + } + + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, lino), + XFS_INO_TO_AGINO(mp, lino)); + + if (irec == NULL && no_modify) { + do_warn("entry \"%s\" in shortform directory %llu " + "references non-existent inode %llu\n", + fname, ino, lino); + do_warn("would junk entry\n"); + continue; + } + + ASSERT(irec != NULL); + + ino_offset = XFS_INO_TO_AGINO(mp, lino) - irec->ino_startnum; + + /* + * if it's a free inode, blow out the entry. + * by now, any inode that we think is free + * really is free. + */ + if (is_inode_free(irec, ino_offset)) { + /* + * don't complain if this entry points to the old + * and now-free lost+found inode + */ + if (verbose || no_modify || lino != old_orphanage_ino) + do_warn("entry \"%s\" in shortform directory " + "inode %llu points to free inode " + "%llu\n", + fname, ino, lino); + + if (!no_modify) { + junkit = 1; + } else { + do_warn("would junk entry \"%s\"\n", + fname); + } + } else if (!inode_isadir(irec, ino_offset)) { + /* + * check easy case first, regular inode, just bump + * the link count and continue + */ + add_inode_reached(irec, ino_offset); + + next_sfep = (xfs_dir2_sf_entry_t *) + ((__psint_t) sfep + + XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep)); + continue; + } else { + parent = get_inode_parent(irec, ino_offset); + + /* + * bump up the link counts in parent and child. + * directory but if the link doesn't agree with + * the .. in the child, blow out the entry + */ + if (is_inode_reached(irec, ino_offset)) { + junkit = 1; + do_warn("entry \"%s\" in directory inode %llu " + "references already connected inode " + "%llu,\n", + fname, ino, lino); + } else if (parent == ino) { + add_inode_reached(irec, ino_offset); + add_inode_ref(current_irec, current_ino_offset); + + if (!is_inode_refchecked(lino, irec, + ino_offset)) + push_dir(stack, lino); + } else { + junkit = 1; + do_warn("entry \"%s\" in directory inode %llu " + "not consistent with .. value (%llu) " + "in inode %llu,\n", + fname, ino, parent, lino); + } + } + + if (junkit) { + if (!no_modify) { + tmp_elen = XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep); + tmp_sfep = (xfs_dir2_sf_entry_t *) + ((__psint_t) sfep + tmp_elen); + tmp_len = max_size - ((__psint_t) tmp_sfep + - (__psint_t) sfp); + max_size -= tmp_elen; + bytes_deleted += tmp_elen; + + memmove(sfep, tmp_sfep, tmp_len); + + INT_MOD(sfp->hdr.count, ARCH_CONVERT, -1); + bzero((void *) ((__psint_t) sfep + tmp_len), + tmp_elen); + + /* + * set the tmp value to the current + * pointer so we'll process the entry + * we just moved up + */ + tmp_sfep = sfep; + + /* + * WARNING: drop the index i by one + * so it matches the decremented count for + * accurate comparisons in the loop test + */ + i--; + + *ino_dirty = 1; + + if (verbose || lino != old_orphanage_ino) + do_warn("junking entry \"%s\" in " + "directory inode %llu\n", + fname, lino); + } else { + do_warn("would junk entry \"%s\"\n", fname); + } + } else if (lino > XFS_DIR2_MAX_SHORT_INUM) + i8++; + + /* + * go onto next entry unless we've just junked an + * entry in which the current entry pointer points + * to an unprocessed entry. have to take into entries + * with bad namelen into account in no modify mode since we + * calculate size based on next_sfep. + */ + ASSERT(no_modify || bad_sfnamelen == 0); + + next_sfep = (tmp_sfep == NULL) + ? (xfs_dir2_sf_entry_t *) ((__psint_t) sfep + + ((!bad_sfnamelen) + ? XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep) + : XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, namelen))) + : tmp_sfep; + } + + if (sfp->hdr.i8count != i8) { + if (no_modify) { + do_warn("would fix i8count in inode %llu\n", ino); + } else { + if (i8 == 0) { + tmp_sfep = next_sfep; + process_sf_dir2_fixi8(sfp, &tmp_sfep); + bytes_deleted += + (__psint_t)next_sfep - + (__psint_t)tmp_sfep; + next_sfep = tmp_sfep; + } else + sfp->hdr.i8count = i8; + *ino_dirty = 1; + do_warn("fixing i8count in inode %llu\n", ino); + } + } + + /* + * sync up sizes if required + */ + if (*ino_dirty) { + ASSERT(bytes_deleted > 0); + ASSERT(!no_modify); + libxfs_idata_realloc(ip, -bytes_deleted, XFS_DATA_FORK); + ip->i_d.di_size -= bytes_deleted; + } + + if (ip->i_d.di_size != ip->i_df.if_bytes) { + ASSERT(ip->i_df.if_bytes == (xfs_fsize_t) + ((__psint_t) next_sfep - (__psint_t) sfp)); + ip->i_d.di_size = (xfs_fsize_t) + ((__psint_t) next_sfep - (__psint_t) sfp); + do_warn("setting size to %lld bytes to reflect junked " + "entries\n", + ip->i_d.di_size); + *ino_dirty = 1; + } +} + +/* + * processes all directories reachable via the inodes on the stack + * returns 0 if things are good, 1 if there's a problem + */ +void +process_dirstack(xfs_mount_t *mp, dir_stack_t *stack) +{ + xfs_bmap_free_t flist; + xfs_fsblock_t first; + xfs_ino_t ino; + xfs_inode_t *ip; + xfs_trans_t *tp; + xfs_dahash_t hashval; + ino_tree_node_t *irec; + int ino_offset, need_dot, committed; + int dirty, num_illegal, error, nres; + + /* + * pull directory inode # off directory stack + * + * open up directory inode, check all entries, + * then call prune_dir_entries to remove all + * remaining illegal directory entries. + */ + + while ((ino = pop_dir(stack)) != NULLFSINO) { + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, ino), + XFS_INO_TO_AGINO(mp, ino)); + ASSERT(irec != NULL); + + ino_offset = XFS_INO_TO_AGINO(mp, ino) - irec->ino_startnum; + + ASSERT(!is_inode_refchecked(ino, irec, ino_offset)); + + if ((error = libxfs_iget(mp, NULL, ino, 0, &ip, 0))) { + if (!no_modify) + do_error("couldn't map inode %llu, err = %d\n", + ino, error); + else { + do_warn("couldn't map inode %llu, err = %d\n", + ino, error); + /* + * see below for what we're doing if this + * is root. Why do we need to do this here? + * to ensure that the root doesn't show up + * as being disconnected in the no_modify case. + */ + if (mp->m_sb.sb_rootino == ino) { + add_inode_reached(irec, 0); + add_inode_ref(irec, 0); + } + } + + add_inode_refchecked(ino, irec, 0); + continue; + } + + need_dot = dirty = num_illegal = 0; + + if (mp->m_sb.sb_rootino == ino) { + /* + * mark root inode reached and bump up + * link count for root inode to account + * for '..' entry since the root inode is + * never reached by a parent. we know + * that root's '..' is always good -- + * guaranteed by phase 3 and/or below. + */ + add_inode_reached(irec, ino_offset); + /* + * account for link for the orphanage + * "lost+found". if we're running in + * modify mode and it already existed, + * we deleted it so it's '..' reference + * never got counted. so add it here if + * we're going to create lost+found. + * + * if we're running in no_modify mode, + * we never deleted lost+found and we're + * not going to create it so do nothing. + * + * either way, the counts will match when + * we look at the root inode's nlinks + * field and compare that to our incore + * count in phase 7. + */ + if (!no_modify) + add_inode_ref(irec, ino_offset); + } + + add_inode_refchecked(ino, irec, ino_offset); + + /* + * look for bogus entries + */ + switch (ip->i_d.di_format) { + case XFS_DINODE_FMT_EXTENTS: + case XFS_DINODE_FMT_BTREE: + /* + * also check for missing '.' in longform dirs. + * missing .. entries are added if required when + * the directory is connected to lost+found. but + * we need to create '.' entries here. + */ + if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) + longform_dir2_entry_check(mp, ino, ip, + &num_illegal, &need_dot, + stack, irec, + ino_offset); + else + longform_dir_entry_check(mp, ino, ip, + &num_illegal, &need_dot, + stack, irec, + ino_offset); + break; + case XFS_DINODE_FMT_LOCAL: + tp = libxfs_trans_alloc(mp, 0); + /* + * using the remove reservation is overkill + * since at most we'll only need to log the + * inode but it's easier than wedging a + * new define in ourselves. + */ + nres = no_modify ? 0 : XFS_REMOVE_SPACE_RES(mp); + error = libxfs_trans_reserve(tp, nres, + XFS_REMOVE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_REMOVE_LOG_COUNT); + if (error) + res_failed(error); + + libxfs_trans_ijoin(tp, ip, 0); + libxfs_trans_ihold(tp, ip); + + if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb)) + shortform_dir2_entry_check(mp, ino, ip, &dirty, + stack, irec, + ino_offset); + else + shortform_dir_entry_check(mp, ino, ip, &dirty, + stack, irec, + ino_offset); + + ASSERT(dirty == 0 || (dirty && !no_modify)); + if (dirty) { + libxfs_trans_log_inode(tp, ip, + XFS_ILOG_CORE | XFS_ILOG_DDATA); + libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES + |XFS_TRANS_SYNC, 0); + } else { + libxfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES); + } + break; + default: + break; + } + + hashval = 0; + + if (!no_modify && !orphanage_entered && + ino == mp->m_sb.sb_rootino) { + do_warn("re-entering %s into root directory\n", + ORPHANAGE); + tp = libxfs_trans_alloc(mp, 0); + nres = XFS_MKDIR_SPACE_RES(mp, strlen(ORPHANAGE)); + error = libxfs_trans_reserve(tp, nres, + XFS_MKDIR_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_MKDIR_LOG_COUNT); + if (error) + res_failed(error); + libxfs_trans_ijoin(tp, ip, 0); + libxfs_trans_ihold(tp, ip); + XFS_BMAP_INIT(&flist, &first); + if ((error = dir_createname(mp, tp, ip, ORPHANAGE, + strlen(ORPHANAGE), + orphanage_ino, &first, &flist, + nres))) + do_error("can't make %s entry in root inode " + "%llu, createname error %d\n", + ORPHANAGE, ino, error); + libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + error = libxfs_bmap_finish(&tp, &flist, first, &committed); + ASSERT(error == 0); + libxfs_trans_commit(tp, + XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_SYNC, 0); + orphanage_entered = 1; + } + + /* + * if we have to create a .. for /, do it now *before* + * we delete the bogus entries, otherwise the directory + * could transform into a shortform dir which would + * probably cause the simulation to choke. Even + * if the illegal entries get shifted around, it's ok + * because the entries are structurally intact and in + * in hash-value order so the simulation won't get confused + * if it has to move them around. + */ + if (!no_modify && need_root_dotdot && + ino == mp->m_sb.sb_rootino) { + ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_LOCAL); + + do_warn("recreating root directory .. entry\n"); + + tp = libxfs_trans_alloc(mp, 0); + ASSERT(tp != NULL); + + nres = XFS_MKDIR_SPACE_RES(mp, 2); + error = libxfs_trans_reserve(tp, nres, + XFS_MKDIR_LOG_RES(mp), + 0, + XFS_TRANS_PERM_LOG_RES, + XFS_MKDIR_LOG_COUNT); + + if (error) + res_failed(error); + + libxfs_trans_ijoin(tp, ip, 0); + libxfs_trans_ihold(tp, ip); + + XFS_BMAP_INIT(&flist, &first); + + if ((error = dir_createname(mp, tp, ip, "..", 2, + ip->i_ino, &first, &flist, nres))) + do_error( +"can't make \"..\" entry in root inode %llu, createname error %d\n", + ino, error); + + libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + + error = libxfs_bmap_finish(&tp, &flist, first, + &committed); + ASSERT(error == 0); + libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES + |XFS_TRANS_SYNC, 0); + + need_root_dotdot = 0; + } else if (need_root_dotdot && ino == mp->m_sb.sb_rootino) { + do_warn("would recreate root directory .. entry\n"); + } + + /* + * delete any illegal entries -- which should only exist + * if the directory is a longform directory. bogus + * shortform directory entries were deleted in phase 4. + */ + if (!no_modify && num_illegal > 0) { + ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_LOCAL); + ASSERT(!XFS_SB_VERSION_HASDIRV2(&mp->m_sb)); + + while (num_illegal > 0 && ip->i_d.di_format != + XFS_DINODE_FMT_LOCAL) { + prune_lf_dir_entry(mp, ino, ip, &hashval); + num_illegal--; + } + + /* + * handle case where we've deleted so many + * entries that the directory has changed from + * a longform to a shortform directory. have + * to allocate a transaction since we're working + * with the incore data fork. + */ + if (num_illegal > 0) { + ASSERT(ip->i_d.di_format == + XFS_DINODE_FMT_LOCAL); + tp = libxfs_trans_alloc(mp, 0); + /* + * using the remove reservation is overkill + * since at most we'll only need to log the + * inode but it's easier than wedging a + * new define in ourselves. 10 block fs + * space reservation is also overkill but + * what the heck... + */ + nres = XFS_REMOVE_SPACE_RES(mp); + error = libxfs_trans_reserve(tp, nres, + XFS_REMOVE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_REMOVE_LOG_COUNT); + if (error) + res_failed(error); + + libxfs_trans_ijoin(tp, ip, 0); + libxfs_trans_ihold(tp, ip); + + prune_sf_dir_entry(mp, ino, ip); + + libxfs_trans_log_inode(tp, ip, + XFS_ILOG_CORE | XFS_ILOG_DDATA); + ASSERT(error == 0); + libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES + |XFS_TRANS_SYNC, 0); + } + } + + /* + * if we need to create the '.' entry, do so only if + * the directory is a longform dir. it it's been + * turned into a shortform dir, then the inode is ok + * since shortform dirs have no '.' entry and the inode + * has already been committed by prune_lf_dir_entry(). + */ + if (need_dot) { + /* + * bump up our link count but don't + * bump up the inode link count. chances + * are good that even though we lost '.' + * the inode link counts reflect '.' so + * leave the inode link count alone and if + * it turns out to be wrong, we'll catch + * that in phase 7. + */ + add_inode_ref(irec, ino_offset); + + if (no_modify) { + do_warn( + "would create missing \".\" entry in dir ino %llu\n", + ino); + } else if (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) { + /* + * need to create . entry in longform dir. + */ + do_warn( + "creating missing \".\" entry in dir ino %llu\n", + ino); + + tp = libxfs_trans_alloc(mp, 0); + ASSERT(tp != NULL); + + nres = XFS_MKDIR_SPACE_RES(mp, 1); + error = libxfs_trans_reserve(tp, nres, + XFS_MKDIR_LOG_RES(mp), + 0, + XFS_TRANS_PERM_LOG_RES, + XFS_MKDIR_LOG_COUNT); + + if (error) + res_failed(error); + + libxfs_trans_ijoin(tp, ip, 0); + libxfs_trans_ihold(tp, ip); + + XFS_BMAP_INIT(&flist, &first); + + if ((error = dir_createname(mp, tp, ip, ".", + 1, ip->i_ino, &first, &flist, + nres))) + do_error( + "can't make \".\" entry in dir ino %llu, createname error %d\n", + ino, error); + + libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + + error = libxfs_bmap_finish(&tp, &flist, first, + &committed); + ASSERT(error == 0); + libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES + |XFS_TRANS_SYNC, 0); + } + } + + libxfs_iput(ip, 0); + } +} + +/* + * mark realtime bitmap and summary inodes as reached. + * quota inode will be marked here as well + */ +void +mark_standalone_inodes(xfs_mount_t *mp) +{ + ino_tree_node_t *irec; + int offset; + + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rbmino), + XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rbmino)); + + ASSERT(irec != NULL); + + offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rbmino) - + irec->ino_startnum; + + add_inode_reached(irec, offset); + + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rsumino), + XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rsumino)); + + offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rsumino) - + irec->ino_startnum; + + ASSERT(irec != NULL); + + add_inode_reached(irec, offset); + + if (fs_quotas) { + if (mp->m_sb.sb_uquotino + && mp->m_sb.sb_uquotino != NULLFSINO) { + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, + mp->m_sb.sb_uquotino), + XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino)); + offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino) + - irec->ino_startnum; + add_inode_reached(irec, offset); + } + if (mp->m_sb.sb_gquotino + && mp->m_sb.sb_gquotino != NULLFSINO) { + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, + mp->m_sb.sb_gquotino), + XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino)); + offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino) + - irec->ino_startnum; + add_inode_reached(irec, offset); + } + } +} + +void +phase6(xfs_mount_t *mp) +{ + xfs_ino_t ino; + ino_tree_node_t *irec; + dir_stack_t stack; + int i; + int j; + + bzero(&zerocr, sizeof(cred_t)); + + do_log("Phase 6 - check inode connectivity...\n"); + + if (!no_modify) + teardown_bmap_finish(mp); + else + teardown_bmap(mp); + + incore_ext_teardown(mp); + + add_ino_backptrs(mp); + + /* + * verify existence of root directory - if we have to + * make one, it's ok for the incore data structs not to + * know about it since everything about it (and the other + * inodes in its chunk if a new chunk was created) are ok + */ + if (need_root_inode) { + if (!no_modify) { + do_warn("reinitializing root directory\n"); + mk_root_dir(mp); + need_root_inode = 0; + need_root_dotdot = 0; + } else { + do_warn("would reinitialize root directory\n"); + } + } + + if (need_rbmino) { + if (!no_modify) { + do_warn("reinitializing realtime bitmap inode\n"); + mk_rbmino(mp); + need_rbmino = 0; + } else { + do_warn("would reinitialize realtime bitmap inode\n"); + } + } + + if (need_rsumino) { + if (!no_modify) { + do_warn("reinitializing realtime summary inode\n"); + mk_rsumino(mp); + need_rsumino = 0; + } else { + do_warn("would reinitialize realtime summary inode\n"); + } + } + + if (!no_modify) { + do_log( + " - resetting contents of realtime bitmap and summary inodes\n"); + if (fill_rbmino(mp)) { + do_warn( + "Warning: realtime bitmap may be inconsistent\n"); + } + + if (fill_rsumino(mp)) { + do_warn( + "Warning: realtime bitmap may be inconsistent\n"); + } + } + + /* + * make orphanage (it's guaranteed to not exist now) + */ + if (!no_modify) { + do_log(" - ensuring existence of %s directory\n", + ORPHANAGE); + orphanage_ino = mk_orphanage(mp); + } + + dir_stack_init(&stack); + + mark_standalone_inodes(mp); + + /* + * push root dir on stack, then go + */ + if (!need_root_inode) { + do_log(" - traversing filesystem starting at / ... \n"); + + push_dir(&stack, mp->m_sb.sb_rootino); + process_dirstack(mp, &stack); + + do_log(" - traversal finished ... \n"); + } else { + ASSERT(no_modify != 0); + + do_log( +" - root inode lost, cannot make new one in no modify mode ... \n"); + do_log( +" - skipping filesystem traversal from / ... \n"); + } + + do_log(" - traversing all unattached subtrees ... \n"); + + irec = find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino), + XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino)); + + /* + * we always have a root inode, even if it's free... + * if the root is free, forget it, lost+found is already gone + */ + if (is_inode_free(irec, 0) || !inode_isadir(irec, 0)) { + need_root_inode = 1; + } + + /* + * then process all unreached inodes + * by walking incore inode tree + * + * get next unreached directory inode # from + * incore list + * push inode on dir stack + * call process_dirstack + */ + for (i = 0; i < glob_agcount; i++) { + irec = findfirst_inode_rec(i); + + if (irec == NULL) + continue; + + while (irec != NULL) { + for (j = 0; j < XFS_INODES_PER_CHUNK; j++) { + if (!is_inode_confirmed(irec, j)) + continue; + /* + * skip directories that have already been + * processed, even if they haven't been + * reached. If they are reachable, we'll + * pick them up when we process their parent. + */ + ino = XFS_AGINO_TO_INO(mp, i, + j + irec->ino_startnum); + if (inode_isadir(irec, j) && + !is_inode_refchecked(ino, + irec, j)) { + push_dir(&stack, ino); + process_dirstack(mp, &stack); + } + } + irec = next_ino_rec(irec); + } + } + + do_log(" - traversals finished ... \n"); + do_log(" - moving disconnected inodes to lost+found ... \n"); + + /* + * move all disconnected inodes to the orphanage + */ + for (i = 0; i < glob_agcount; i++) { + irec = findfirst_inode_rec(i); + + if (irec == NULL) + continue; + + while (irec != NULL) { + for (j = 0; j < XFS_INODES_PER_CHUNK; j++) { + ASSERT(is_inode_confirmed(irec, j)); + if (is_inode_free(irec, j)) + continue; + if (!is_inode_reached(irec, j)) { + ASSERT(inode_isadir(irec, j) || + num_inode_references(irec, j) + == 0); + ino = XFS_AGINO_TO_INO(mp, i, + j + irec->ino_startnum); + if (inode_isadir(irec, j)) + do_warn( + "disconnected dir inode %llu, ", + ino); + else + do_warn( + "disconnected inode %llu, ", + ino); + if (!no_modify) { + do_warn("moving to %s\n", + ORPHANAGE); + mv_orphanage(mp, orphanage_ino, + ino, + inode_isadir(irec, j)); + } else { + do_warn("would move to %s\n", + ORPHANAGE); + } + /* + * for read-only case, even though + * the inode isn't really reachable, + * set the flag (and bump our link + * count) anyway to fool phase 7 + */ + add_inode_reached(irec, j); + } + } + irec = next_ino_rec(irec); + } + } +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/phase7.c linux-2.4-xfs/cmd/xfsprogs/repair/phase7.c --- linux-2.4.7/cmd/xfsprogs/repair/phase7.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/phase7.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "avl.h" +#include "globals.h" +#include "agheader.h" +#include "incore.h" +#include "protos.h" +#include "err_protos.h" +#include "dinode.h" +#include "versions.h" + +/* dinoc is a pointer to the IN-CORE dinode core */ +void +set_nlinks(xfs_dinode_core_t *dinoc, + xfs_ino_t ino, + __uint32_t nrefs, + int *dirty) +{ + if (!no_modify) { + if (INT_GET(dinoc->di_nlink, ARCH_NOCONVERT) != nrefs) { + *dirty = 1; + do_warn("resetting inode %llu nlinks from %d to %d\n", + ino, INT_GET(dinoc->di_nlink, ARCH_NOCONVERT), nrefs); + + if (nrefs > XFS_MAXLINK_1) { + ASSERT(fs_inode_nlink); + do_warn( +"nlinks %d will overflow v1 ino, ino %llu will be converted to version 2\n", + nrefs, ino); + + } + INT_SET(dinoc->di_nlink, ARCH_NOCONVERT, nrefs); + } + } else { + if (INT_GET(dinoc->di_nlink, ARCH_NOCONVERT) != nrefs) + do_warn( + "would have reset inode %llu nlinks from %d to %d\n", + ino, INT_GET(dinoc->di_nlink, ARCH_NOCONVERT), nrefs); + } +} + +void +phase7(xfs_mount_t *mp) +{ + ino_tree_node_t *irec; + xfs_inode_t *ip; + xfs_trans_t *tp; + int i; + int j; + int error; + int dirty; + xfs_ino_t ino; + __uint32_t nrefs; + + if (!no_modify) + printf("Phase 7 - verify and correct link counts...\n"); + else + printf("Phase 7 - verify link counts...\n"); + + tp = libxfs_trans_alloc(mp, XFS_TRANS_REMOVE); + + error = libxfs_trans_reserve(tp, (no_modify ? 0 : 10), + XFS_REMOVE_LOG_RES(mp), 0, XFS_TRANS_PERM_LOG_RES, + XFS_REMOVE_LOG_COUNT); + + ASSERT(error == 0); + + /* + * for each ag, look at each inode 1 at a time using the + * sim code. if the number of links is bad, reset it, + * log the inode core, commit the transaction, and + * allocate a new transaction + */ + for (i = 0; i < glob_agcount; i++) { + irec = findfirst_inode_rec(i); + + while (irec != NULL) { + for (j = 0; j < XFS_INODES_PER_CHUNK; j++) { + ASSERT(is_inode_confirmed(irec, j)); + + if (is_inode_free(irec, j)) + continue; + + ASSERT(no_modify || is_inode_reached(irec, j)); + ASSERT(no_modify || + is_inode_referenced(irec, j)); + + nrefs = num_inode_references(irec, j); + + ino = XFS_AGINO_TO_INO(mp, i, + irec->ino_startnum + j); + + error = libxfs_trans_iget(mp, tp, ino, 0, &ip); + + if (error) { + if (!no_modify) + do_error( + "couldn't map inode %llu, err = %d\n", + ino, error); + else { + do_warn( + "couldn't map inode %llu, err = %d, can't compare link counts\n", + ino, error); + continue; + } + } + + dirty = 0; + + /* + * compare and set links for all inodes + * but the lost+found inode. we keep + * that correct as we go. + */ + if (ino != orphanage_ino) + set_nlinks(&ip->i_d, ino, nrefs, + &dirty); + + if (!dirty) { + libxfs_trans_iput(tp, ip, 0); + } else { + libxfs_trans_log_inode(tp, ip, + XFS_ILOG_CORE); + /* + * no need to do a bmap finish since + * we're not allocating anything + */ + ASSERT(error == 0); + error = libxfs_trans_commit(tp, + XFS_TRANS_RELEASE_LOG_RES| + XFS_TRANS_SYNC, NULL); + + ASSERT(error == 0); + + tp = libxfs_trans_alloc(mp, + XFS_TRANS_REMOVE); + + error = libxfs_trans_reserve(tp, + (no_modify ? 0 : 10), + XFS_REMOVE_LOG_RES(mp), + 0, XFS_TRANS_PERM_LOG_RES, + XFS_REMOVE_LOG_COUNT); + ASSERT(error == 0); + } + } + irec = next_ino_rec(irec); + } + } + + /* + * always have one unfinished transaction coming out + * of the loop. cancel it. + */ + libxfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES); +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/protos.h linux-2.4-xfs/cmd/xfsprogs/repair/protos.h --- linux-2.4.7/cmd/xfsprogs/repair/protos.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/protos.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +void xfs_init(libxfs_init_t *args); +void io_init(void); + +int verify_sb(xfs_sb_t *sb, + int is_primary_sb); +int verify_set_primary_sb(xfs_sb_t *root_sb, + int sb_index, + int *sb_modified); +int get_sb(xfs_sb_t *sbp, + xfs_off_t off, + int size, + xfs_agnumber_t agno); +void write_primary_sb(xfs_sb_t *sbp, + int size); + +int find_secondary_sb(xfs_sb_t *sb); + +int check_growfs(xfs_off_t off, int bufnum, xfs_agnumber_t agnum); + +void get_sb_geometry(fs_geometry_t *geo, + xfs_sb_t *sbp); + +char *alloc_ag_buf(int size); + +void print_inode_list(xfs_agnumber_t i); +char * err_string(int err_code); + diff -rNu linux-2.4.7/cmd/xfsprogs/repair/rt.c linux-2.4-xfs/cmd/xfsprogs/repair/rt.c --- linux-2.4.7/cmd/xfsprogs/repair/rt.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/rt.c Sun Jan 14 23:36:03 2001 @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "avl.h" +#include "globals.h" +#include "agheader.h" +#include "incore.h" +#include "dinode.h" +#include "protos.h" +#include "err_protos.h" +#include "rt.h" + +#define xfs_highbit64 libxfs_highbit64 /* for XFS_RTBLOCKLOG macro */ + +void +rtinit(xfs_mount_t *mp) +{ + if (mp->m_sb.sb_rblocks == 0) + return; + + /* + * realtime init -- blockmap initialization is + * handled by incore_init() + */ + /* + sumfile = calloc(mp->m_rsumsize, 1); + */ + if ((btmcompute = calloc(mp->m_sb.sb_rbmblocks * + mp->m_sb.sb_blocksize, 1)) == NULL) + do_error( + "couldn't allocate memory for incore realtime bitmap.\n"); + + if ((sumcompute = calloc(mp->m_rsumsize, 1)) == NULL) + do_error( + "couldn't allocate memory for incore realtime summary info.\n"); +} + +/* + * generate the real-time bitmap and summary info based on the + * incore realtime extent map. + */ +int +generate_rtinfo(xfs_mount_t *mp, + xfs_rtword_t *words, + xfs_suminfo_t *sumcompute) +{ + xfs_drtbno_t extno; + xfs_drtbno_t start_ext; + int bitsperblock; + int bmbno; + xfs_rtword_t freebit; + xfs_rtword_t bits; + int start_bmbno; + int i; + int offs; + int log; + int len; + int in_extent; + + ASSERT(mp->m_rbmip == NULL); + + bitsperblock = mp->m_sb.sb_blocksize * NBBY; + extno = start_ext = 0; + bmbno = in_extent = start_bmbno = 0; + + /* + * slower but simple, don't play around with trying to set + * things one word at a time, just set bit as required. + * Have to * track start and end (size) of each range of + * free extents to set the summary info properly. + */ + while (extno < mp->m_sb.sb_rextents) { + freebit = 1; + *words = 0; + bits = 0; + for (i = 0; i < sizeof(xfs_rtword_t) * NBBY && + extno < mp->m_sb.sb_rextents; i++, extno++) { + if (get_rtbno_state(mp, extno) == XR_E_FREE) { + sb_frextents++; + bits |= freebit; + + if (in_extent == 0) { + start_ext = extno; + start_bmbno = bmbno; + in_extent = 1; + } + } else if (in_extent == 1) { + len = (int) (extno - start_ext); + log = XFS_RTBLOCKLOG(len); + offs = XFS_SUMOFFS(mp, log, start_bmbno); + sumcompute[offs]++; + in_extent = 0; + } + + freebit <<= 1; + } + *words = bits; + words++; + + if (extno % bitsperblock == 0) + bmbno++; + } + if (in_extent == 1) { + len = (int) (extno - start_ext); + log = XFS_RTBLOCKLOG(len); + offs = XFS_SUMOFFS(mp, log, start_bmbno); + sumcompute[offs]++; + } + + return(0); +} + +#if 0 +/* + * returns 1 if bad, 0 if good + */ +int +check_summary(xfs_mount_t *mp) +{ + xfs_drfsbno_t bno; + xfs_suminfo_t *csp; + xfs_suminfo_t *fsp; + int log; + int error = 0; + + error = 0; + csp = sumcompute; + fsp = sumfile; + for (log = 0; log < mp->m_rsumlevels; log++) { + for (bno = 0; + bno < mp->m_sb.sb_rbmblocks; + bno++, csp++, fsp++) { + if (*csp != *fsp) { + do_warn( + "rt summary mismatch, size %d block %llu, file: %d, computed: %d\n", + log, bno, *fsp, *csp); + error = 1; + } + } + } + + return(error); +} + +/* + * examine the real-time bitmap file and compute summary + * info off it. Should probably be changed to compute + * the summary information off the incore computed bitmap + * instead of the realtime bitmap file + */ +void +process_rtbitmap(xfs_mount_t *mp, + xfs_dinode_t *dino, + blkmap_t *blkmap) +{ + int error; + int bit; + int bitsperblock; + int bmbno; + int end_bmbno; + xfs_dfsbno_t bno; + xfs_buf_t *bp; + xfs_drtbno_t extno; + int i; + int len; + int log; + int offs; + int prevbit; + int start_bmbno; + int start_bit; + xfs_rtword_t *words; + + ASSERT(mp->m_rbmip == NULL); + + bitsperblock = mp->m_sb.sb_blocksize * NBBY; + prevbit = 0; + extno = 0; + error = 0; + + end_bmbno = howmany(INT_GET(dino->di_core.di_size, ARCH_CONVERT), mp->m_sb.sb_blocksize); + + for (bmbno = 0; bmbno < end_bmbno; bmbno++) { + bno = blkmap_get(blkmap, bmbno); + + if (bno == NULLDFSBNO) { + do_warn("can't find block %d for rtbitmap inode\n", + bmbno); + error = 1; + continue; + } + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno), + XFS_FSB_TO_BB(mp, 1)); + if (!bp) { + do_warn("can't read block %d for rtbitmap inode\n", + bmbno); + error = 1; + continue; + } + words = (xfs_rtword_t *)bp->b_un.b_addr; + for (bit = 0; + bit < bitsperblock && extno < mp->m_sb.sb_rextents; + bit++, extno++) { + if (isset(words, bit)) { + set_rtbno_state(mp, extno, XR_E_FREE); + sb_frextents++; + if (prevbit == 0) { + start_bmbno = bmbno; + start_bit = bit; + prevbit = 1; + } + } else if (prevbit == 1) { + len = (bmbno - start_bmbno) * bitsperblock + + (bit - start_bit); + log = XFS_RTBLOCKLOG(len); + offs = XFS_SUMOFFS(mp, log, start_bmbno); + sumcompute[offs]++; + prevbit = 0; + } + } + libxfs_putbuf(bp); + if (extno == mp->m_sb.sb_rextents) + break; + } + if (prevbit == 1) { + len = (bmbno - start_bmbno) * bitsperblock + (bit - start_bit); + log = XFS_RTBLOCKLOG(len); + offs = XFS_SUMOFFS(mp, log, start_bmbno); + sumcompute[offs]++; + } +} + +/* + * copy the real-time summary file data into memory + */ +void +process_rtsummary(xfs_mount_t *mp, + xfs_dinode_t *dino, + blkmap_t *blkmap) +{ + xfs_fsblock_t bno; + xfs_buf_t *bp; + char *bytes; + int sumbno; + + for (sumbno = 0; sumbno < blkmap->count; sumbno++) { + bno = blkmap_get(blkmap, sumbno); + if (bno == NULLDFSBNO) { + do_warn("block %d for rtsummary inode is missing\n", + sumbno); + error++; + continue; + } + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno), + XFS_FSB_TO_BB(mp, 1)); + if (!bp) { + do_warn("can't read block %d for rtsummary inode\n", + sumbno); + error++; + continue; + } + bytes = bp->b_un.b_addr; + bcopy(bytes, (char *)sumfile + sumbno * mp->m_sb.sb_blocksize, + mp->m_sb.sb_blocksize); + libxfs_putbuf(bp); + } +} +#endif diff -rNu linux-2.4.7/cmd/xfsprogs/repair/rt.h linux-2.4-xfs/cmd/xfsprogs/repair/rt.h --- linux-2.4.7/cmd/xfsprogs/repair/rt.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/rt.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +struct blkmap; + +void +rtinit(xfs_mount_t *mp); + +int +generate_rtinfo(xfs_mount_t *mp, + xfs_rtword_t *words, + xfs_suminfo_t *sumcompute); + +#if 0 + +int +check_summary(xfs_mount_t *mp); + +void +process_rtbitmap(xfs_mount_t *mp, + xfs_dinode_t *dino, + struct blkmap *blkmap); + +void +process_rtsummary(xfs_mount_t *mp, + struct blkmap *blkmap); +#endif diff -rNu linux-2.4.7/cmd/xfsprogs/repair/sb.c linux-2.4-xfs/cmd/xfsprogs/repair/sb.c --- linux-2.4.7/cmd/xfsprogs/repair/sb.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/sb.c Wed May 9 01:56:06 2001 @@ -0,0 +1,823 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include "agheader.h" +#include "globals.h" +#include "protos.h" +#include "err_protos.h" + + +/* + * copy the fields of a superblock that are present in primary and + * secondaries -- preserve fields that are different in the primary. + */ +void +copy_sb(xfs_sb_t *source, xfs_sb_t *dest) +{ + xfs_ino_t rootino; + xfs_ino_t rbmino; + xfs_ino_t rsumino; + xfs_ino_t uquotino; + xfs_ino_t gquotino; + __uint16_t versionnum; + + rootino = dest->sb_rootino; + rbmino = dest->sb_rbmino; + rsumino = dest->sb_rsumino; + uquotino = dest->sb_uquotino; + gquotino = dest->sb_gquotino; + + versionnum = dest->sb_versionnum; + + *dest = *source; + + dest->sb_rootino = rootino; + dest->sb_rbmino = rbmino; + dest->sb_rsumino = rsumino; + dest->sb_uquotino = uquotino; + dest->sb_gquotino = gquotino; + + dest->sb_versionnum = versionnum; + + /* + * copy over version bits that are stamped into all + * secondaries and cannot be changed at run time in + * the primary superblock + */ + if (XFS_SB_VERSION_HASDALIGN(source)) + XFS_SB_VERSION_ADDDALIGN(dest); + if (XFS_SB_VERSION_HASEXTFLGBIT(source)) + XFS_SB_VERSION_ADDEXTFLGBIT(dest); + + /* + * these are all supposed to be zero or will get reset anyway + */ + dest->sb_icount = 0; + dest->sb_ifree = 0; + dest->sb_fdblocks = 0; + dest->sb_frextents = 0; + + bzero(source->sb_fname, 12); +} + +#define BSIZE (1024 * 1024) + +/* + * find a secondary superblock, copy it into the sb buffer + */ +int +find_secondary_sb(xfs_sb_t *rsb) +{ + xfs_off_t off; + xfs_sb_t *sb; + xfs_sb_t bufsb; + char *c_bufsb; + int done; + int i; + int dirty; + int retval; + int bsize; + + do_warn("\nattempting to find secondary superblock...\n"); + + sb = (xfs_sb_t *) memalign(MEM_ALIGN, BSIZE); + if (!sb) { + do_error( + "error finding secondary superblock -- failed to memalign buffer\n"); + exit(1); + } + + bzero(&bufsb, sizeof(xfs_sb_t)); + retval = 0; + dirty = 0; + bsize = 0; + + /* + * skip first sector since we know that's bad + */ + for (done = 0, off = XFS_AG_MIN_BYTES; !done ; off += bsize) { + /* + * read disk 1 MByte at a time. + */ + if (lseek64(fs_fd, off, SEEK_SET) != off) { + done = 1; + } + + if (!done && (bsize = read(fs_fd, sb, BSIZE)) == 0) { + done = 1; + } + + do_warn("."); + + /* + * check the buffer 512 bytes at a time since + * we don't know how big the sectors really are. + */ + for (i = 0; !done && i < bsize; i += BBSIZE) { + c_bufsb = (char *) sb + i; + libxfs_xlate_sb(c_bufsb, &bufsb, 1, ARCH_CONVERT, + XFS_SB_ALL_BITS); + + if (verify_sb(&bufsb, 0) != XR_OK) + continue; + + do_warn("found candidate secondary superblock...\n"); + + /* + * found one. now verify it by looking + * for other secondaries. + */ + bcopy(&bufsb, rsb, bufsb.sb_sectsize); + rsb->sb_inprogress = 0; + clear_sunit = 1; + + if (verify_set_primary_sb(rsb, 0, &dirty) == XR_OK) { + do_warn("verified secondary superblock...\n"); + done = 1; + retval = 1; + } else { + do_warn( + "unable to verify superblock, continuing...\n"); + } + } + } + + free(sb); + return(retval); +} + +/* + * calculate what inode alignment field ought to be + * based on internal superblock info + */ +int +calc_ino_align(xfs_sb_t *sb) +{ + xfs_extlen_t align; + + align = XFS_INODE_BIG_CLUSTER_SIZE >> sb->sb_blocklog; + + return(align); +} + +/* + * verify a superblock -- does not verify root inode # + * can only check that geometry info is internally + * consistent. because of growfs, that's no guarantee + * of correctness (e.g. geometry may have changed) + * + * fields verified or consistency checked: + * + * sb_magicnum + * + * sb_versionnum + * + * sb_inprogress + * + * sb_blocksize (as a group) + * sb_blocklog + * + * geometry info - sb_dblocks (as a group) + * sb_agcount + * sb_agblocks + * sb_agblklog + * + * inode info - sb_inodesize (x-checked with geo info) + * sb_inopblock + * + * sector size info - + * sb_sectsize + * sb_sectlog + * + * not checked here - + * sb_rootino + * sb_fname + * sb_fpack + * sb_logstart + * sb_uuid + * + * ALL real-time fields + * final 4 summary counters + */ + +int +verify_sb(xfs_sb_t *sb, int is_primary_sb) +{ + __uint32_t bsize; + xfs_extlen_t align; + int i; + + /* check magic number and version number */ + + if (sb->sb_magicnum != XFS_SB_MAGIC) + return(XR_BAD_MAGIC); + + if (!XFS_SB_GOOD_VERSION(sb)) + return(XR_BAD_VERSION); + + /* does sb think mkfs really finished ? */ + + if (is_primary_sb && sb->sb_inprogress == 1) + return(XR_BAD_INPROGRESS); + + /* check to make sure blocksize is legal 2^N, 9 <= N <= 16 */ + + if (sb->sb_blocksize == 0) + return(XR_BAD_BLOCKSIZE); + + bsize = 1; + + for (i = 0; bsize < sb->sb_blocksize && i < 32; i++) { + bsize <<= 1; + } + + if (i < XR_LOG2BSIZE_MIN || i > XR_LOG2BSIZE_MAX) + return(XR_BAD_BLOCKSIZE); + + /* check sb blocksize field against sb blocklog field */ + + if (i != sb->sb_blocklog) + return(XR_BAD_BLOCKLOG); + + /* sanity check ag count, size fields against data size field */ + + if (sb->sb_dblocks == 0 || + sb->sb_dblocks > sb->sb_agcount * sb->sb_agblocks || + sb->sb_dblocks < (sb->sb_agcount - 1) + * sb->sb_agblocks + XFS_MIN_AG_BLOCKS) + return(XR_BAD_FS_SIZE_DATA); + + if (sb->sb_agblklog != (__uint8_t)libxfs_log2_roundup(sb->sb_agblocks)) + return(XR_BAD_FS_SIZE_DATA); + + if (sb->sb_inodesize < XFS_DINODE_MIN_SIZE || + sb->sb_inodesize > XFS_DINODE_MAX_SIZE || + sb->sb_inopblock != howmany(sb->sb_blocksize,sb->sb_inodesize)) + return(XR_BAD_INO_SIZE_DATA); + + /* check sector size against log(sector size) field */ + + bsize = 1; + + for (i = 0; bsize < sb->sb_sectsize && i < 15; i++) { + bsize <<= 1; + } + + if (sb->sb_sectsize == 0 || i == 16 || + sb->sb_sectsize != (1 << i)) + return(XR_BAD_SECT_SIZE_DATA); + + /* + * real-time extent size is always set + */ + if (sb->sb_rextsize * sb->sb_blocksize > XFS_MAX_RTEXTSIZE) + return(XR_BAD_RT_GEO_DATA); + + if (sb->sb_rextsize * sb->sb_blocksize < XFS_MIN_RTEXTSIZE) + return(XR_BAD_RT_GEO_DATA); + + if (sb->sb_rblocks == 0) { + if (sb->sb_rextents != 0) + return(XR_BAD_RT_GEO_DATA); + + if (sb->sb_rbmblocks != 0) + return(XR_BAD_RT_GEO_DATA); + + if (sb->sb_rextslog != 0) + return(XR_BAD_RT_GEO_DATA); + + if (sb->sb_frextents != 0) + return(XR_BAD_RT_GEO_DATA); + } else { + /* + * if we have a real-time partition, sanity-check geometry + */ + if (sb->sb_rblocks / sb->sb_rextsize != sb->sb_rextents) + return(XR_BAD_RT_GEO_DATA); + + if (sb->sb_rextslog != + libxfs_highbit32((unsigned int)sb->sb_rextents)) + return(XR_BAD_RT_GEO_DATA); + + if (sb->sb_rbmblocks != (xfs_extlen_t) howmany(sb->sb_rextents, + NBBY * sb->sb_blocksize)) + return(XR_BAD_RT_GEO_DATA); + } + + /* + * verify correctness of inode alignment if it's there + */ + if (XFS_SB_VERSION_HASALIGN(sb)) { + align = calc_ino_align(sb); + + if (align != sb->sb_inoalignmt) + return(XR_BAD_INO_ALIGN); + } + + /* + * verify max. % of inodes (sb_imax_pct) + */ + if (sb->sb_imax_pct > 100) + return(XR_BAD_INO_MAX_PCT); + + /* + * verify stripe alignment fields if present + */ + if (XFS_SB_VERSION_HASDALIGN(sb)) { + if ((!sb->sb_unit && sb->sb_width) || + (sb->sb_unit && sb->sb_agblocks % sb->sb_unit)) + return(XR_BAD_SB_UNIT); + if ((sb->sb_unit && !sb->sb_width) || + (sb->sb_width && sb->sb_unit && sb->sb_width % sb->sb_unit)) + return(XR_BAD_SB_WIDTH); + } + + /* + * if shared bit is set, verify that the version number is sane + */ + if (XFS_SB_VERSION_HASSHARED(sb)) { + if (sb->sb_shared_vn > XFS_SB_MAX_SHARED_VN) + return(XR_BAD_SVN); + } + + /* + * mkfs's that stamped a feature bit besides the ones in the + * mask below could leave garbage in the secondary superblock + * sectors. Anything stamping the shared fs bit or better into + * the secondaries is ok and should generate clean secondary + * superblock sectors. + * + * check primary and clean secondary superblocks more strictly + */ + if (is_primary_sb || sb->sb_versionnum & XR_PART_SECSB_VNMASK) { + /* + * return errors if shared vn or alignment fields + * are set without their feature bits being set + */ + if ((!pre_65_beta && (sb->sb_versionnum & XR_PART_SECSB_VNMASK)) || + (pre_65_beta && (sb->sb_versionnum & XR_ALPHA_SECSB_VNMASK))) { + /* + * shared version # and inode alignment fields + * should be valid + */ + if (sb->sb_shared_vn && !XFS_SB_VERSION_HASSHARED(sb)) + return(XR_BAD_SVN); + if (sb->sb_inoalignmt && !XFS_SB_VERSION_HASALIGN(sb)) + return(XR_BAD_INO_ALIGN); + } + if ((!pre_65_beta && + (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK)) || + (pre_65_beta && + (sb->sb_versionnum & XFS_SB_VERSION_DALIGNBIT))) { + /* + * stripe alignment values should be valid + */ + if (sb->sb_unit && !XFS_SB_VERSION_HASDALIGN(sb)) + return(XR_BAD_SB_UNIT); + if (sb->sb_width && !XFS_SB_VERSION_HASDALIGN(sb)) + return(XR_BAD_SB_WIDTH); + } + +#if 0 + /* + * checks involving later superblock fields get added here... + */ + if (sb->sb_versionnum & XR_GOOD_SECSB_VNMASK) { + } +#endif + } + + return(XR_OK); +} + +void +write_primary_sb(xfs_sb_t *sbp, int size) +{ + void *buf; + + if (no_modify) + return; + + if ((buf = calloc(size, 1)) == NULL) { + do_error("failed to malloc superblock buffer\n"); + return; + } + + if (lseek64(fs_fd, 0LL, SEEK_SET) != 0LL) { + free(buf); + do_error("couldn't seek to offset 0 in filesystem\n"); + } + + libxfs_xlate_sb(buf, sbp, -1, ARCH_CONVERT, XFS_SB_ALL_BITS); + + if (write(fs_fd, buf, size) != size) { + free(buf); + do_error("primary superblock write failed!\n"); + } + + free(buf); +} + +/* + * get a possible superblock -- don't check for internal consistency + */ +int +get_sb(xfs_sb_t *sbp, xfs_off_t off, int size, xfs_agnumber_t agno) +{ + int error, rval; + void *buf; + + if ((buf = calloc(size, 1)) == NULL) { + do_error( + "error reading superblock %u -- failed to malloc buffer\n", + agno, off); + exit(1); + } + + /* try and read it first */ + + if (lseek64(fs_fd, off, SEEK_SET) != off) { + do_warn( + "error reading superblock %u -- seek to offset %lld failed\n", + agno, off); + return(XR_EOF); + } + + if ((rval = read(fs_fd, buf, size)) != size) { + error = errno; + do_warn( +"superblock read failed, offset %lld, size %d, ag %u, rval %d\n", + off, size, rval, agno); + do_error("%s\n", strerror(error)); + } + libxfs_xlate_sb(buf, sbp, 1, ARCH_CONVERT, XFS_SB_ALL_BITS); + free(buf); + + return (verify_sb(sbp, 0)); +} + +#if 0 +int +check_growfs(xfs_off_t off, int bufnum, xfs_agnumber_t agnum) +{ + int rval; + + ASSERT(bufnum < NUM_SBS); + + /* try and read it first */ + + if (lseek64(fs_fd, off, SEEK_SET) != off) + return(XR_EOF); + + if ((rval = read(fs_fd, sb_bufs[bufnum], sbbuf_size)) != sbbuf_size) { + /* + * we didn't get a full block so the filesystem + * could not have been grown. return a non-XR_OK + * result code. + */ + return(XR_EOF); + } + + return(get_sb(off, bufnum, agnum)); +} +#endif +/* returns element on list with highest reference count */ + +fs_geo_list_t * +get_best_geo(fs_geo_list_t *list) +{ + int cnt = 0; + fs_geo_list_t *current, *rval = NULL; + + current = list; + + while (current != NULL) { + if (current->refs > cnt) { + rval = current; + cnt = current->refs; + } + current = current->next; + } + + return(rval); +} + +/* adds geometry info to linked list. returns (sometimes new) head of list */ + +fs_geo_list_t * +add_geo(fs_geo_list_t *list, fs_geometry_t *geo_p, int index) +{ + fs_geo_list_t *current = list; + + while (current != NULL) { + if (memcmp(geo_p, ¤t->geo, sizeof(fs_geometry_t)) == 0) { + current->refs++; + return(list); + } + + current = current->next; + } + + if ((current = malloc(sizeof(fs_geo_list_t))) == NULL) { + do_error("couldn't malloc geometry structure\n"); + exit(1); + } + + current->geo = *geo_p; + current->refs = 1; + current->next = list; + current->index = index; + + return(current); +} + +void +free_geo(fs_geo_list_t *list) +{ + fs_geo_list_t *next; + fs_geo_list_t *current; + + current = list; + + for (current = list; current != NULL; current = next) { + next = current->next; + free(current); + } +} + +void +get_sb_geometry(fs_geometry_t *geo, xfs_sb_t *sbp) +{ + bzero(geo, sizeof(fs_geometry_t)); + + /* + * blindly set fields that we know are always good + */ + geo->sb_blocksize = sbp->sb_blocksize; + geo->sb_dblocks = sbp->sb_dblocks; + geo->sb_rblocks = sbp->sb_rblocks; + geo->sb_rextents = sbp->sb_rextents; + geo->sb_logstart = sbp->sb_logstart; + geo->sb_rextsize = sbp->sb_rextsize; + geo->sb_agblocks = sbp->sb_agblocks; + geo->sb_agcount = sbp->sb_agcount; + geo->sb_rbmblocks = sbp->sb_rbmblocks; + geo->sb_logblocks = sbp->sb_logblocks; + geo->sb_sectsize = sbp->sb_sectsize; + geo->sb_inodesize = sbp->sb_inodesize; + + if (XFS_SB_VERSION_HASALIGN(sbp)) + geo->sb_ialignbit = 1; + + if (XFS_SB_VERSION_HASSHARED(sbp) || + sbp->sb_versionnum & XR_PART_SECSB_VNMASK) + geo->sb_sharedbit = 1; + + if (XFS_SB_VERSION_HASDALIGN(sbp)) + geo->sb_salignbit = 1; + + if (XFS_SB_VERSION_HASEXTFLGBIT(sbp)) + geo->sb_extflgbit = 1; + + /* + * protect against pre-6.5 mkfs-generated garbaged + * fields in the secondary superblocks. pay attention + * to those fields if and only if their corresponding + * feature bits are set in the feature bits of the + * version number or we can deduce from the version bits + * that are set that our field was properly initialized + * because a field after the field we care about was + * properly initialized as well. + */ + + /* + * inode alignment field lives before the data alignment field + */ + if ((!pre_65_beta && (sbp->sb_versionnum & XR_PART_SECSB_VNMASK)) || + (pre_65_beta && (sbp->sb_versionnum & XR_ALPHA_SECSB_VNMASK))) + geo->sb_inoalignmt = sbp->sb_inoalignmt; + + if ((!pre_65_beta && (sbp->sb_versionnum & XR_GOOD_SECSB_VNMASK)) || + (pre_65_beta && XFS_SB_VERSION_HASDALIGN(sbp))) { + geo->sb_unit = sbp->sb_unit; + geo->sb_width = sbp->sb_width; + } + + /* + * shared vn always set if either ino or data alignment is on + * since that field lives between the quota and inode alignment + * fields + */ + if (sbp->sb_versionnum & XR_PART_SECSB_VNMASK) + geo->sb_shared_vn = sbp->sb_shared_vn; + + /* + * superblock fields located after sb_widthfields get set + * into the geometry structure only if we can determine + * from the features enabled in this superblock whether + * or not the sector was bzero'd at mkfs time. + */ + if ((!pre_65_beta && (sbp->sb_versionnum & XR_GOOD_SECSB_VNMASK)) || + (pre_65_beta && (sbp->sb_versionnum & XR_ALPHA_SECSB_VNMASK))) { + geo->sb_fully_zeroed = 1; + } +} + +/* + * the way to verify that a primary sb is consistent with the + * filesystem is find the secondaries given the info in the + * primary and compare the geometries in the secondaries against + * the geometry indicated by the primary. + * + * returns 1 if bad, 0 if ok + */ +int +verify_set_primary_sb(xfs_sb_t *rsb, + int sb_index, + int *sb_modified) +{ + xfs_off_t off; + fs_geometry_t geo; + xfs_sb_t *sb; + fs_geo_list_t *list; + fs_geo_list_t *current; + char *checked; + xfs_agnumber_t agno; + int num_sbs; + int skip; + int size; + int num_ok; + int retval; + int round; + + /* + * select the number of secondaries to try for + */ + num_sbs = MIN(NUM_SBS, rsb->sb_agcount); + skip = howmany(num_sbs, rsb->sb_agcount); + size = NUM_AGH_SECTS * rsb->sb_sectsize; + retval = 0; + list = NULL; + num_ok = 0; + *sb_modified = 0; + + sb = (xfs_sb_t *) alloc_ag_buf(size); + checked = calloc(rsb->sb_agcount, sizeof(char)); + if (!checked) { + do_error("calloc failed in verify_set_primary_sb\n"); + exit(1); + } + + /* + * put the primary sb geometry info onto the geometry list + */ + checked[sb_index] = 1; + get_sb_geometry(&geo, rsb); + list = add_geo(list, &geo, sb_index); + + /* + * grab N secondaries. check them off as we get them + * so we only process each one once + */ + for (round = 0; round < skip; round++) { + for (agno = round; agno < rsb->sb_agcount; agno += skip) { + if (checked[agno]) + continue; + + off = (xfs_off_t)agno * rsb->sb_agblocks << rsb->sb_blocklog; + + checked[agno] = 1; + + if (get_sb(sb, off, size, agno) == XR_EOF) { + retval = 1; + goto out; + } + + if (verify_sb(sb, 0) == XR_OK) { + /* + * save away geometry info. + * don't bother checking the sb + * against the agi/agf as the odds + * of the sb being corrupted in a way + * that it is internally consistent + * but not consistent with the rest + * of the filesystem is really really low. + */ + get_sb_geometry(&geo, sb); + list = add_geo(list, &geo, agno); + num_ok++; + } + } + } + + /* + * see if we have enough superblocks to bother with + */ + if (num_ok < num_sbs / 2) + return(XR_INSUFF_SEC_SB); + + current = get_best_geo(list); + + /* + * check that enough sbs agree that we're willing to + * go with this geometry. if not, print out the + * geometry and a message about the force option. + */ + switch (num_sbs) { + case 2: + /* + * all them have to be right. if not, report geometry + * and get out unless force option is in effect (-F) + */ + if (current->refs != 2) { + if (!force_geo) { + do_warn("Only two AGs detected and they do not match - cannot proceed.\n"); + exit(1); + } + } + break; + case 1: + /* + * just report the geometry info and get out. + * refuse to run further unless the force (-F) + * option is in effect. + */ + if (!force_geo) { + do_warn("Only one AG detected - cannot proceed.\n"); + exit(1); + } + default: + /* + * at least half of the probed superblocks have + * to agree. if they don't, this fs is probably + * too far gone anyway considering the fact that + * XFS normally doesn't alter the secondary superblocks. + */ + if (current->refs < num_sbs / 2) { + do_warn("Not enough matching superblocks - cannot proceed.\n"); + exit(1); + } + } + + /* + * set the geometry into primary superblock if necessary. + */ + + if (current->index != sb_index) { + *sb_modified = 1; + off = current->index * current->geo.sb_agblocks + * current->geo.sb_blocksize; + if (get_sb(sb, off, current->geo.sb_sectsize, + current->index) != XR_OK) + do_error("could not read superblock\n"); + + copy_sb(sb, rsb); + + /* + * turn off inprogress bit since this is the primary. + * also save away values that we need to ensure are + * consistent in the other secondaries. + */ + rsb->sb_inprogress = 0; + sb_inoalignmt = sb->sb_inoalignmt; + sb_unit = sb->sb_unit; + sb_width = sb->sb_width; + } + + free_geo(list); +out: + free(sb); + free(checked); + return(retval); +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/scan.c linux-2.4-xfs/cmd/xfsprogs/repair/scan.c --- linux-2.4.7/cmd/xfsprogs/repair/scan.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/scan.c Thu Apr 12 18:49:04 2001 @@ -0,0 +1,1279 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "avl.h" +#include "globals.h" +#include "agheader.h" +#include "incore.h" +#include "protos.h" +#include "err_protos.h" +#include "dinode.h" +#include "scan.h" +#include "versions.h" +#include "bmap.h" + +extern int verify_set_agheader(xfs_mount_t *mp, xfs_buf_t *sbuf, xfs_sb_t *sb, + xfs_agf_t *agf, xfs_agi_t *agi, xfs_agnumber_t i); + +static xfs_mount_t *mp = NULL; +static xfs_extlen_t bno_agffreeblks; +static xfs_extlen_t cnt_agffreeblks; +static xfs_extlen_t bno_agflongest; +static xfs_extlen_t cnt_agflongest; +static xfs_agino_t agicount; +static xfs_agino_t agifreecount; + +void +set_mp(xfs_mount_t *mpp) +{ + mp = mpp; +} + +void +scan_sbtree( + xfs_agblock_t root, + int nlevels, + xfs_agnumber_t agno, + int suspect, + void (*func)(xfs_btree_sblock_t *block, + int level, + xfs_agblock_t bno, + xfs_agnumber_t agno, + int suspect, + int isroot), + int isroot) +{ + xfs_buf_t *bp; + + bp = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, root), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + do_error("can't read btree block %d/%d\n", agno, root); + return; + } + (*func)((xfs_btree_sblock_t *)XFS_BUF_PTR(bp), + nlevels - 1, root, agno, suspect, isroot); + libxfs_putbuf(bp); +} + +/* + * returns 1 on bad news (inode needs to be cleared), 0 on good + */ +int +scan_lbtree( + xfs_dfsbno_t root, + int nlevels, + int (*func)(xfs_btree_lblock_t *block, + int level, + int type, + int whichfork, + xfs_dfsbno_t bno, + xfs_ino_t ino, + xfs_drfsbno_t *tot, + __uint64_t *nex, + blkmap_t **blkmapp, + bmap_cursor_t *bm_cursor, + int isroot, + int check_dups, + int *dirty), + int type, + int whichfork, + xfs_ino_t ino, + xfs_drfsbno_t *tot, + __uint64_t *nex, + blkmap_t **blkmapp, + bmap_cursor_t *bm_cursor, + int isroot, + int check_dups) +{ + xfs_buf_t *bp; + int err; + int dirty = 0; + + bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, root), + XFS_FSB_TO_BB(mp, 1), 0); + if (!bp) { + do_error("can't read btree block %d/%d\n", + XFS_FSB_TO_AGNO(mp, root), + XFS_FSB_TO_AGBNO(mp, root)); + return(1); + } + err = (*func)((xfs_btree_lblock_t *)XFS_BUF_PTR(bp), nlevels - 1, + type, whichfork, root, ino, tot, nex, blkmapp, + bm_cursor, isroot, check_dups, &dirty); + + ASSERT(dirty == 0 || (dirty && !no_modify)); + + if (dirty && !no_modify) + libxfs_writebuf(bp, 0); + else + libxfs_putbuf(bp); + + return(err); +} + +int +scanfunc_bmap( + xfs_btree_lblock_t *ablock, + int level, + int type, + int whichfork, + xfs_dfsbno_t bno, + xfs_ino_t ino, + xfs_drfsbno_t *tot, + __uint64_t *nex, + blkmap_t **blkmapp, + bmap_cursor_t *bm_cursor, + int isroot, + int check_dups, + int *dirty) +{ + xfs_bmbt_block_t *block = (xfs_bmbt_block_t *)ablock; + int i; + int err; + xfs_bmbt_ptr_t *pp; + xfs_bmbt_key_t *pkey; + xfs_bmbt_rec_32_t *rp; + xfs_dfiloff_t first_key; + xfs_dfiloff_t last_key; + char *forkname; + + if (whichfork == XFS_DATA_FORK) + forkname = "data"; + else + forkname = "attr"; + + /* + * unlike the ag freeblock btrees, if anything looks wrong + * in an inode bmap tree, just bail. it's possible that + * we'll miss a case where the to-be-toasted inode and + * another inode are claiming the same block but that's + * highly unlikely. + */ + if (INT_GET(block->bb_magic, ARCH_CONVERT) != XFS_BMAP_MAGIC) { + do_warn( + "bad magic # %#x in inode %llu (%s fork) bmbt block %llu\n", + INT_GET(block->bb_magic, ARCH_CONVERT), ino, forkname, bno); + return(1); + } + if (INT_GET(block->bb_level, ARCH_CONVERT) != level) { + do_warn( + "expected level %d got %d in inode %llu, (%s fork) bmbt block %llu\n", + level, INT_GET(block->bb_level, ARCH_CONVERT), ino, forkname, bno); + return(1); + } + + if (check_dups == 0) { + /* + * check sibling pointers. if bad we have a conflict + * between the sibling pointers and the child pointers + * in the parent block. blow out the inode if that happens + */ + if (bm_cursor->level[level].fsbno != NULLDFSBNO) { + /* + * this is not the first block on this level + * so the cursor for this level has recorded the + * values for this's block left-sibling. + */ + if (bno != bm_cursor->level[level].right_fsbno) { + do_warn( + "bad fwd (right) sibling pointer (saw %llu parent block says %llu)\n", + bm_cursor->level[level].right_fsbno, + bno); + do_warn( + "\tin inode %llu (%s fork) bmap btree block %llu\n", + ino, forkname, + bm_cursor->level[level].fsbno); + return(1); + } + if (INT_GET(block->bb_leftsib, ARCH_CONVERT) != + bm_cursor->level[level].fsbno) { + do_warn( + "bad back (left) sibling pointer (saw %llu parent block says %llu)\n", + INT_GET(block->bb_leftsib, ARCH_CONVERT), + bm_cursor->level[level].fsbno); + do_warn( + "\tin inode %llu (%s fork) bmap btree block %llu\n", + ino, forkname, bno); + return(1); + } + } else { + /* + * This is the first or only block on this level. + * Check that the left sibling pointer is NULL + */ + if (INT_GET(block->bb_leftsib, ARCH_CONVERT) != + NULLDFSBNO) { + do_warn( + "bad back (left) sibling pointer (saw %llu should be NULL (0))\n", + INT_GET(block->bb_leftsib, ARCH_CONVERT)); + do_warn( + "\tin inode %llu (%s fork) bmap btree block %llu\n", + ino, forkname, bno); + return(1); + } + } + + /* + * update cursor block pointers to reflect this block + */ + bm_cursor->level[level].fsbno = bno; + bm_cursor->level[level].left_fsbno = INT_GET(block->bb_leftsib, ARCH_CONVERT); + bm_cursor->level[level].right_fsbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + + switch (get_fsbno_state(mp, bno)) { + case XR_E_UNKNOWN: + case XR_E_FREE1: + case XR_E_FREE: + set_fsbno_state(mp, bno, XR_E_INUSE); + break; + case XR_E_FS_MAP: + case XR_E_INUSE: + /* + * we'll try and continue searching here since + * the block looks like it's been claimed by file + * to store user data, a directory to store directory + * data, or the space allocation btrees but since + * we made it here, the block probably + * contains btree data. + */ + set_fsbno_state(mp, bno, XR_E_MULT); + do_warn( + "inode 0x%llx bmap block 0x%llx claimed, state is %d\n", + ino, (__uint64_t) bno, + get_fsbno_state(mp, bno)); + break; + case XR_E_MULT: + case XR_E_INUSE_FS: + set_fsbno_state(mp, bno, XR_E_MULT); + do_warn( + "inode 0x%llx bmap block 0x%llx claimed, state is %d\n", + ino, (__uint64_t) bno, + get_fsbno_state(mp, bno)); + /* + * if we made it to here, this is probably a bmap block + * that is being used by *another* file as a bmap block + * so the block will be valid. Both files should be + * trashed along with any other file that impinges on + * any blocks referenced by either file. So we + * continue searching down this btree to mark all + * blocks duplicate + */ + break; + case XR_E_BAD_STATE: + default: + do_warn( + "bad state %d, inode 0x%llx bmap block 0x%llx\n", + get_fsbno_state(mp, bno), + ino, (__uint64_t) bno); + break; + } + } else { + /* + * attribute fork for realtime files is in the regular + * filesystem + */ + if (type != XR_INO_RTDATA || whichfork != XFS_DATA_FORK) { + if (search_dup_extent(mp, XFS_FSB_TO_AGNO(mp, bno), + XFS_FSB_TO_AGBNO(mp, bno))) + return(1); + } else { + if (search_rt_dup_extent(mp, bno)) + return(1); + } + } + (*tot)++; + if (level == 0) { + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_bmap_dmxr[0] || + (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_bmap_dmnr[0])) { +do_warn("inode 0x%llx bad # of bmap records (%u, min - %u, max - %u)\n", + ino, INT_GET(block->bb_numrecs, ARCH_CONVERT), + mp->m_bmap_dmnr[0], mp->m_bmap_dmxr[0]); + return(1); + } + rp = (xfs_bmbt_rec_32_t *) + XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, + block, 1, mp->m_bmap_dmxr[0]); + *nex += INT_GET(block->bb_numrecs, ARCH_CONVERT); + /* + * XXX - if we were going to fix up the btree record, + * we'd do it right here. For now, if there's a problem, + * we'll bail out and presumably clear the inode. + */ + if (check_dups == 0) { + err = process_bmbt_reclist(mp, rp, INT_GET(block->bb_numrecs, ARCH_CONVERT), + type, ino, tot, blkmapp, + &first_key, &last_key, + whichfork); + if (err) + return(1); + /* + * check that key ordering is monotonically increasing. + * if the last_key value in the cursor is set to + * NULLDFILOFF, then we know this is the first block + * on the leaf level and we shouldn't check the + * last_key value. + */ + if (first_key <= bm_cursor->level[level].last_key && + bm_cursor->level[level].last_key != + NULLDFILOFF) { + do_warn( +"out-of-order bmap key (file offset) in inode %llu, %s fork, fsbno %llu\n", + ino, forkname, bno); + return(1); + } + /* + * update cursor keys to reflect this block. + * don't have to check if last_key is > first_key + * since that gets checked by process_bmbt_reclist. + */ + bm_cursor->level[level].first_key = first_key; + bm_cursor->level[level].last_key = last_key; + + return(0); + } else + return(scan_bmbt_reclist(mp, rp, INT_GET(block->bb_numrecs, ARCH_CONVERT), + type, ino, tot, whichfork)); + } + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_bmap_dmxr[1] || + (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_bmap_dmnr[1])) { +do_warn("inode 0x%llx bad # of bmap records (%u, min - %u, max - %u)\n", + ino, INT_GET(block->bb_numrecs, ARCH_CONVERT), + mp->m_bmap_dmnr[1], mp->m_bmap_dmxr[1]); + return(1); + } + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, 1, + mp->m_bmap_dmxr[1]); + pkey = XFS_BTREE_KEY_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, 1, + mp->m_bmap_dmxr[1]); + + last_key = NULLDFILOFF; + + for (i = 0, err = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) { + /* + * XXX - if we were going to fix up the interior btree nodes, + * we'd do it right here. For now, if there's a problem, + * we'll bail out and presumably clear the inode. + */ + if (!verify_dfsbno(mp, INT_GET(pp[i], ARCH_CONVERT))) { + do_warn("bad bmap btree ptr 0x%llx in ino %llu\n", + INT_GET(pp[i], ARCH_CONVERT), ino); + return(1); + } + + err = scan_lbtree(INT_GET(pp[i], ARCH_CONVERT), level, scanfunc_bmap, type, whichfork, + ino, tot, nex, blkmapp, bm_cursor, 0, + check_dups); + if (err) + return(1); + + /* + * fix key (offset) mismatches between the first key + * in the child block (as recorded in the cursor) and the + * key in the interior node referencing the child block. + * + * fixes cases where entries have been shifted between + * child blocks but the parent hasn't been updated. We + * don't have to worry about the key values in the cursor + * not being set since we only look at the key values of + * our child and those are guaranteed to be set by the + * call to scan_lbtree() above. + */ + if (check_dups == 0 && INT_GET(pkey[i].br_startoff, ARCH_CONVERT) != + bm_cursor->level[level-1].first_key) { + if (!no_modify) { + do_warn( + "correcting bt key (was %llu, now %llu) in inode %llu\n", + INT_GET(pkey[i].br_startoff, ARCH_CONVERT), + bm_cursor->level[level-1].first_key, + ino); + do_warn("\t\t%s fork, btree block %llu\n", + forkname, bno); + *dirty = 1; + INT_SET(pkey[i].br_startoff, ARCH_CONVERT, bm_cursor->level[level-1].first_key); + } else { + do_warn( +"bad btree key (is %llu, should be %llu) in inode %llu\n", + INT_GET(pkey[i].br_startoff, ARCH_CONVERT), + bm_cursor->level[level-1].first_key, + ino); + do_warn("\t\t%s fork, btree block %llu\n", + forkname, bno); + } + } + } + + /* + * Check that the last child block's forward sibling pointer + * is NULL. + */ + if (check_dups == 0 && + bm_cursor->level[level - 1].right_fsbno != NULLDFSBNO) { + do_warn( + "bad fwd (right) sibling pointer (saw %llu should be NULLDFSBNO)\n", + bm_cursor->level[level - 1].right_fsbno); + do_warn( + "\tin inode %llu (%s fork) bmap btree block %llu\n", + ino, forkname, + bm_cursor->level[level].fsbno); + return(1); + } + + /* + * update cursor keys to reflect this block + */ + if (check_dups == 0) { + bm_cursor->level[level].first_key = + INT_GET(pkey[0].br_startoff, ARCH_CONVERT); + i = INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1; + bm_cursor->level[level].last_key = + INT_GET(pkey[i].br_startoff, ARCH_CONVERT); + } + + return(0); +} + +void +scanfunc_bno( + xfs_btree_sblock_t *ablock, + int level, + xfs_agblock_t bno, + xfs_agnumber_t agno, + int suspect, + int isroot + ) +{ + xfs_agblock_t b; + xfs_alloc_block_t *block = (xfs_alloc_block_t *)ablock; + int i; + xfs_alloc_ptr_t *pp; + xfs_alloc_rec_t *rp; + int hdr_errors = 0; + int numrecs; + int state; + + if (INT_GET(block->bb_magic, ARCH_CONVERT) != XFS_ABTB_MAGIC) { + do_warn("bad magic # %#x in btbno block %d/%d\n", + INT_GET(block->bb_magic, ARCH_CONVERT), agno, bno); + hdr_errors++; + if (suspect) + return; + } + if (INT_GET(block->bb_level, ARCH_CONVERT) != level) { + do_warn("expected level %d got %d in btbno block %d/%d\n", + level, INT_GET(block->bb_level, ARCH_CONVERT), agno, bno); + hdr_errors++; + if (suspect) + return; + } + + /* + * check for btree blocks multiply claimed + */ + state = get_agbno_state(mp, agno, bno); + + switch (state) { + case XR_E_UNKNOWN: + set_agbno_state(mp, agno, bno, XR_E_FS_MAP); + break; + default: + set_agbno_state(mp, agno, bno, XR_E_MULT); + do_warn( +"bno freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n", + state, agno, bno, suspect); + return; + } + + if (level == 0) { + numrecs = INT_GET(block->bb_numrecs, ARCH_CONVERT); + + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_alloc_mxr[0]) { + numrecs = mp->m_alloc_mxr[0]; + hdr_errors++; + } + if (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_alloc_mnr[0]) { + numrecs = mp->m_alloc_mnr[0]; + hdr_errors++; + } + + if (hdr_errors) + suspect++; + + rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, + 1, mp->m_alloc_mxr[0]); + for (i = 0; i < numrecs; i++) { + if (INT_GET(rp[i].ar_blockcount, ARCH_CONVERT) == 0 || + INT_GET(rp[i].ar_startblock, ARCH_CONVERT) == 0 || + !verify_agbno(mp, agno, INT_GET(rp[i].ar_startblock, ARCH_CONVERT)) || + INT_GET(rp[i].ar_blockcount, ARCH_CONVERT) > MAXEXTLEN) + continue; + + bno_agffreeblks += INT_GET(rp[i].ar_blockcount, ARCH_CONVERT); + if (INT_GET(rp[i].ar_blockcount, ARCH_CONVERT) > bno_agflongest) + bno_agflongest = INT_GET(rp[i].ar_blockcount, ARCH_CONVERT); + for (b = INT_GET(rp[i].ar_startblock, ARCH_CONVERT); + b < INT_GET(rp[i].ar_startblock, ARCH_CONVERT) + INT_GET(rp[i].ar_blockcount, ARCH_CONVERT); + b++) { + if (get_agbno_state(mp, agno, b) + == XR_E_UNKNOWN) + set_agbno_state(mp, agno, b, + XR_E_FREE1); + else { +do_warn("block (%d,%d) multiply claimed by bno space tree, state - %d\n", + agno, b, get_agbno_state(mp, agno, b)); + } + } + } + return; + } + + /* + * interior record + */ + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, 1, + mp->m_alloc_mxr[1]); + + numrecs = INT_GET(block->bb_numrecs, ARCH_CONVERT); + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_alloc_mxr[1]) { + numrecs = mp->m_alloc_mxr[1]; + hdr_errors++; + } + if (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_alloc_mnr[1]) { + numrecs = mp->m_alloc_mnr[1]; + hdr_errors++; + } + + /* + * don't pass bogus tree flag down further if this block + * looked ok. bail out if two levels in a row look bad. + */ + + if (suspect && !hdr_errors) + suspect = 0; + + if (hdr_errors) { + if (suspect) + return; + else suspect++; + } + + for (i = 0; i < numrecs; i++) { + /* + * XXX - put sibling detection right here. + * we know our sibling chain is good. So as we go, + * we check the entry before and after each entry. + * If either of the entries references a different block, + * check the sibling pointer. If there's a sibling + * pointer mismatch, try and extract as much data + * as possible. + */ + if (INT_GET(pp[i], ARCH_CONVERT) != 0 && verify_agbno(mp, agno, INT_GET(pp[i], ARCH_CONVERT))) + scan_sbtree(INT_GET(pp[i], ARCH_CONVERT), level, agno, suspect, + scanfunc_bno, 0); + } +} + +void +scanfunc_cnt( + xfs_btree_sblock_t *ablock, + int level, + xfs_agblock_t bno, + xfs_agnumber_t agno, + int suspect, + int isroot + ) +{ + xfs_alloc_block_t *block; + xfs_alloc_ptr_t *pp; + xfs_alloc_rec_t *rp; + xfs_agblock_t b; + int i; + int hdr_errors; + int numrecs; + int state; + + block = (xfs_alloc_block_t *)ablock; + hdr_errors = 0; + + if (INT_GET(block->bb_magic, ARCH_CONVERT) != XFS_ABTC_MAGIC) { + do_warn("bad magic # %#x in btcnt block %d/%d\n", + INT_GET(block->bb_magic, ARCH_CONVERT), agno, bno); + hdr_errors++; + if (suspect) + return; + } + if (INT_GET(block->bb_level, ARCH_CONVERT) != level) { + do_warn("expected level %d got %d in btcnt block %d/%d\n", + level, INT_GET(block->bb_level, ARCH_CONVERT), agno, bno); + hdr_errors++; + if (suspect) + return; + } + + /* + * check for btree blocks multiply claimed + */ + state = get_agbno_state(mp, agno, bno); + + switch (state) { + case XR_E_UNKNOWN: + set_agbno_state(mp, agno, bno, XR_E_FS_MAP); + break; + default: + set_agbno_state(mp, agno, bno, XR_E_MULT); + do_warn( +"bcnt freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n", + state, agno, bno, suspect); + return; + } + + if (level == 0) { + numrecs = INT_GET(block->bb_numrecs, ARCH_CONVERT); + + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_alloc_mxr[0]) { + numrecs = mp->m_alloc_mxr[0]; + hdr_errors++; + } + if (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_alloc_mnr[0]) { + numrecs = mp->m_alloc_mnr[0]; + hdr_errors++; + } + + if (hdr_errors) + suspect++; + + rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, + 1, mp->m_alloc_mxr[0]); + for (i = 0; i < numrecs; i++) { + if (INT_GET(rp[i].ar_blockcount, ARCH_CONVERT) == 0 || + INT_GET(rp[i].ar_startblock, ARCH_CONVERT) == 0 || + !verify_agbno(mp, agno, INT_GET(rp[i].ar_startblock, ARCH_CONVERT)) || + INT_GET(rp[i].ar_blockcount, ARCH_CONVERT) > MAXEXTLEN) + continue; + + cnt_agffreeblks += INT_GET(rp[i].ar_blockcount, ARCH_CONVERT); + if (INT_GET(rp[i].ar_blockcount, ARCH_CONVERT) > cnt_agflongest) + cnt_agflongest = INT_GET(rp[i].ar_blockcount, ARCH_CONVERT); + for (b = INT_GET(rp[i].ar_startblock, ARCH_CONVERT); + b < INT_GET(rp[i].ar_startblock, ARCH_CONVERT) + INT_GET(rp[i].ar_blockcount, ARCH_CONVERT); + b++) { + state = get_agbno_state(mp, agno, b); + /* + * no warning messages -- we'll catch + * FREE1 blocks later + */ + switch (state) { + case XR_E_FREE1: + set_agbno_state(mp, agno, b, XR_E_FREE); + break; + case XR_E_UNKNOWN: + set_agbno_state(mp, agno, b, + XR_E_FREE1); + break; + default: + do_warn( + "block (%d,%d) already used, state %d\n", + agno, b, state); + break; + } + } + } + return; + } + + /* + * interior record + */ + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, block, 1, + mp->m_alloc_mxr[1]); + + numrecs = INT_GET(block->bb_numrecs, ARCH_CONVERT); + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_alloc_mxr[1]) { + numrecs = mp->m_alloc_mxr[1]; + hdr_errors++; + } + if (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_alloc_mnr[1]) { + numrecs = mp->m_alloc_mnr[1]; + hdr_errors++; + } + + /* + * don't pass bogus tree flag down further if this block + * looked ok. bail out if two levels in a row look bad. + */ + + if (suspect && !hdr_errors) + suspect = 0; + + if (hdr_errors) { + if (suspect) + return; + else suspect++; + } + + for (i = 0; i < numrecs; i++) + if (INT_GET(pp[i], ARCH_CONVERT) != 0 && verify_agbno(mp, agno, INT_GET(pp[i], ARCH_CONVERT))) + scan_sbtree(INT_GET(pp[i], ARCH_CONVERT), level, agno, + suspect, scanfunc_cnt, 0); +} + +/* + * this one walks the inode btrees sucking the info there into + * the incore avl tree. We try and rescue corrupted btree records + * to minimize our chances of losing inodes. Inode info from potentially + * corrupt sources could be bogus so rather than put the info straight + * into the tree, instead we put it on a list and try and verify the + * info in the next phase by examining what's on disk. At that point, + * we'll be able to figure out what's what and stick the corrected info + * into the tree. We do bail out at some point and give up on a subtree + * so as to avoid walking randomly all over the ag. + * + * Note that it's also ok if the free/inuse info wrong, we can correct + * that when we examine the on-disk inode. The important thing is to + * get the start and alignment of the inode chunks right. Those chunks + * that we aren't sure about go into the uncertain list. + */ +void +scanfunc_ino( + xfs_btree_sblock_t *ablock, + int level, + xfs_agblock_t bno, + xfs_agnumber_t agno, + int suspect, + int isroot + ) +{ + xfs_ino_t lino; + xfs_inobt_block_t *block; + int i; + xfs_agino_t ino; + xfs_agblock_t agbno; + int j; + int nfree; + int off; + int numrecs; + int state; + xfs_inobt_ptr_t *pp; + xfs_inobt_rec_t *rp; + ino_tree_node_t *ino_rec, *first_rec, *last_rec; + int hdr_errors; + + block = (xfs_inobt_block_t *)ablock; + hdr_errors = 0; + + if (INT_GET(block->bb_magic, ARCH_CONVERT) != XFS_IBT_MAGIC) { + do_warn("bad magic # %#x in inobt block %d/%d\n", + INT_GET(block->bb_magic, ARCH_CONVERT), agno, bno); + hdr_errors++; + bad_ino_btree = 1; + if (suspect) + return; + } + if (INT_GET(block->bb_level, ARCH_CONVERT) != level) { + do_warn("expected level %d got %d in inobt block %d/%d\n", + level, INT_GET(block->bb_level, ARCH_CONVERT), agno, bno); + hdr_errors++; + bad_ino_btree = 1; + if (suspect) + return; + } + + /* + * check for btree blocks multiply claimed, any unknown/free state + * is ok in the bitmap block. + */ + state = get_agbno_state(mp, agno, bno); + + switch (state) { + case XR_E_UNKNOWN: + case XR_E_FREE1: + case XR_E_FREE: + set_agbno_state(mp, agno, bno, XR_E_FS_MAP); + break; + default: + set_agbno_state(mp, agno, bno, XR_E_MULT); + do_warn( +"inode btree block claimed (state %d), agno %d, bno %d, suspect %d\n", + state, agno, bno, suspect); + } + + numrecs = INT_GET(block->bb_numrecs, ARCH_CONVERT); + + /* + * leaf record in btree + */ + if (level == 0) { + /* check for trashed btree block */ + + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_inobt_mxr[0]) { + numrecs = mp->m_inobt_mxr[0]; + hdr_errors++; + } + if (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_inobt_mnr[0]) { + numrecs = mp->m_inobt_mnr[0]; + hdr_errors++; + } + + if (hdr_errors) { + bad_ino_btree = 1; + do_warn("dubious inode btree block header %d/%d\n", + agno, bno); + suspect++; + } + + rp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_inobt, block, + 1, mp->m_inobt_mxr[0]); + + /* + * step through the records, each record points to + * a chunk of inodes. The start of inode chunks should + * be block-aligned. Each inode btree rec should point + * to the start of a block of inodes or the start of a group + * of INODES_PER_CHUNK (64) inodes. off is the offset into + * the block. skip processing of bogus records. + */ + for (i = 0; i < numrecs; i++) { + ino = INT_GET(rp[i].ir_startino, ARCH_CONVERT); + off = XFS_AGINO_TO_OFFSET(mp, ino); + agbno = XFS_AGINO_TO_AGBNO(mp, ino); + lino = XFS_AGINO_TO_INO(mp, agno, ino); + /* + * on multi-block block chunks, all chunks start + * at the beginning of the block. with multi-chunk + * blocks, all chunks must start on 64-inode boundaries + * since each block can hold N complete chunks. if + * fs has aligned inodes, all chunks must start + * at a fs_ino_alignment*N'th agbno. skip recs + * with badly aligned starting inodes. + */ + if (ino == 0 || + (inodes_per_block <= XFS_INODES_PER_CHUNK && + off != 0) || + (inodes_per_block > XFS_INODES_PER_CHUNK && + off % XFS_INODES_PER_CHUNK != 0) || + (fs_aligned_inodes && + agbno % fs_ino_alignment != 0)) { + do_warn( + "badly aligned inode rec (starting inode = %llu)\n", + lino); + suspect++; + } + + /* + * verify numeric validity of inode chunk first + * before inserting into a tree. don't have to + * worry about the overflow case because the + * starting ino number of a chunk can only get + * within 255 inodes of max (NULLAGINO). if it + * gets closer, the agino number will be illegal + * as the agbno will be too large. + */ + if (verify_aginum(mp, agno, ino)) { + do_warn( +"bad starting inode # (%llu (0x%x 0x%x)) in ino rec, skipping rec\n", + lino, agno, ino); + suspect++; + continue; + } + + if (verify_aginum(mp, agno, + ino + XFS_INODES_PER_CHUNK - 1)) { + do_warn( +"bad ending inode # (%llu (0x%x 0x%x)) in ino rec, skipping rec\n", + lino + XFS_INODES_PER_CHUNK - 1, + agno, ino + XFS_INODES_PER_CHUNK - 1); + suspect++; + continue; + } + + /* + * set state of each block containing inodes + */ + if (off == 0 && !suspect) { + for (j = 0; + j < XFS_INODES_PER_CHUNK; + j += mp->m_sb.sb_inopblock) { + agbno = XFS_AGINO_TO_AGBNO(mp, ino + j); + state = get_agbno_state(mp, + agno, agbno); + + if (state == XR_E_UNKNOWN) { + set_agbno_state(mp, agno, + agbno, XR_E_INO); + } else if (state == XR_E_INUSE_FS && + agno == 0 && + ino + j >= first_prealloc_ino && + ino + j < last_prealloc_ino) { + set_agbno_state(mp, agno, + agbno, XR_E_INO); + } else { + do_warn( +"inode chunk claims used block, inobt block - agno %d, bno %d, inopb %d\n", + agno, bno, + mp->m_sb.sb_inopblock); + suspect++; + /* + * XXX - maybe should mark + * block a duplicate + */ + continue; + } + } + } + /* + * ensure only one avl entry per chunk + */ + find_inode_rec_range(agno, ino, + ino + XFS_INODES_PER_CHUNK, + &first_rec, + &last_rec); + if (first_rec != NULL) { + /* + * this chunk overlaps with one (or more) + * already in the tree + */ + do_warn( +"inode rec for ino %llu (%d/%d) overlaps existing rec (start %d/%d)\n", + lino, agno, ino, + agno, first_rec->ino_startnum); + suspect++; + + /* + * if the 2 chunks start at the same place, + * then we don't have to put this one + * in the uncertain list. go to the next one. + */ + if (first_rec->ino_startnum == ino) + continue; + } + + agicount += XFS_INODES_PER_CHUNK; + agifreecount += INT_GET(rp[i].ir_freecount, ARCH_CONVERT); + nfree = 0; + + /* + * now mark all the inodes as existing and free or used. + * if the tree is suspect, put them into the uncertain + * inode tree. + */ + if (!suspect) { + if (XFS_INOBT_IS_FREE(&rp[i], 0, ARCH_CONVERT)) { + nfree++; + ino_rec = set_inode_free_alloc(agno, + ino); + } else { + ino_rec = set_inode_used_alloc(agno, + ino); + } + for (j = 1; j < XFS_INODES_PER_CHUNK; j++) { + if (XFS_INOBT_IS_FREE(&rp[i], j, ARCH_CONVERT)) { + nfree++; + set_inode_free(ino_rec, j); + } else { + set_inode_used(ino_rec, j); + } + } + } else { + for (j = 0; j < XFS_INODES_PER_CHUNK; j++) { + if (XFS_INOBT_IS_FREE(&rp[i], j, ARCH_CONVERT)) { + nfree++; + add_aginode_uncertain(agno, + ino + j, 1); + } else { + add_aginode_uncertain(agno, + ino + j, 0); + } + } + } + + if (nfree != INT_GET(rp[i].ir_freecount, ARCH_CONVERT)) { + do_warn( "ir_freecount/free mismatch, inode chunk \ +%d/%d, freecount %d nfree %d\n", + agno, ino, INT_GET(rp[i].ir_freecount, ARCH_CONVERT), nfree); + } + } + + if (suspect) + bad_ino_btree = 1; + + return; + } + + /* + * interior record, continue on + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_inobt_mxr[1]) { + numrecs = mp->m_inobt_mxr[1]; + hdr_errors++; + } + if (isroot == 0 && INT_GET(block->bb_numrecs, ARCH_CONVERT) < mp->m_inobt_mnr[1]) { + numrecs = mp->m_inobt_mnr[1]; + hdr_errors++; + } + + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_inobt, block, 1, + mp->m_inobt_mxr[1]); + + /* + * don't pass bogus tree flag down further if this block + * looked ok. bail out if two levels in a row look bad. + */ + + if (suspect && !hdr_errors) + suspect = 0; + + if (hdr_errors) { + bad_ino_btree = 1; + if (suspect) + return; + else suspect++; + } + + for (i = 0; i < numrecs; i++) { + if (INT_GET(pp[i], ARCH_CONVERT) != 0 && verify_agbno(mp, agno, INT_GET(pp[i], ARCH_CONVERT))) + scan_sbtree(INT_GET(pp[i], ARCH_CONVERT), level, agno, suspect, + scanfunc_ino, 0); + } +} + +void +scan_freelist( + xfs_agf_t *agf) +{ + xfs_agfl_t *agfl; + xfs_buf_t *agflbuf; + xfs_agblock_t bno; + int count; + int i; + + if (XFS_SB_BLOCK(mp) != XFS_AGFL_BLOCK(mp) && + XFS_AGF_BLOCK(mp) != XFS_AGFL_BLOCK(mp) && + XFS_AGI_BLOCK(mp) != XFS_AGFL_BLOCK(mp)) + set_agbno_state(mp, INT_GET(agf->agf_seqno, ARCH_CONVERT), + XFS_AGFL_BLOCK(mp), XR_E_FS_MAP); + if (INT_GET(agf->agf_flcount, ARCH_CONVERT) == 0) + return; + agflbuf = libxfs_readbuf(mp->m_dev, + XFS_AG_DADDR(mp, INT_GET(agf->agf_seqno, ARCH_CONVERT), + XFS_AGFL_DADDR), 1, 0); + if (!agflbuf) { + do_abort("can't read agfl block for ag %d\n", + INT_GET(agf->agf_seqno, ARCH_CONVERT)); + return; + } + agfl = XFS_BUF_TO_AGFL(agflbuf); + i = INT_GET(agf->agf_flfirst, ARCH_CONVERT); + count = 0; + for (;;) { + bno = INT_GET(agfl->agfl_bno[i], ARCH_CONVERT); + if (verify_agbno(mp, INT_GET(agf->agf_seqno,ARCH_CONVERT), bno)) + set_agbno_state(mp, + INT_GET(agf->agf_seqno, ARCH_CONVERT), + bno, XR_E_FREE); + else + do_warn("bad agbno %u in agfl, agno %d\n", + bno, INT_GET(agf->agf_seqno, ARCH_CONVERT)); + count++; + if (i == INT_GET(agf->agf_fllast, ARCH_CONVERT)) + break; + if (++i == XFS_AGFL_SIZE) + i = 0; + } + if (count != INT_GET(agf->agf_flcount, ARCH_CONVERT)) { + do_warn("freeblk count %d != flcount %d in ag %d\n", count, + INT_GET(agf->agf_flcount, ARCH_CONVERT), + INT_GET(agf->agf_seqno, ARCH_CONVERT)); + } + libxfs_putbuf(agflbuf); +} + +void +scan_ag( + xfs_agnumber_t agno) +{ + xfs_agf_t *agf; + xfs_buf_t *agfbuf; + int agf_dirty; + xfs_agi_t *agi; + xfs_buf_t *agibuf; + int agi_dirty; + xfs_sb_t *sb; + xfs_buf_t *sbbuf; + int sb_dirty; + int status; + + cnt_agffreeblks = cnt_agflongest = 0; + bno_agffreeblks = bno_agflongest = 0; + + agi_dirty = agf_dirty = sb_dirty = 0; + + agicount = agifreecount = 0; + + sbbuf = libxfs_readbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_SB_DADDR), + 1, 0); + if (!sbbuf) { + do_error("can't get root superblock for ag %d\n", agno); + return; + } + + sb = (xfs_sb_t *)calloc(BBSIZE, 1); + if (!sb) { + do_error("can't allocate memory for superblock\n"); + libxfs_putbuf(sbbuf); + return; + } + libxfs_xlate_sb(XFS_BUF_TO_SBP(sbbuf), sb, 1, ARCH_CONVERT, + XFS_SB_ALL_BITS); + + agfbuf = libxfs_readbuf(mp->m_dev, + XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR), 1, 0); + if (!agfbuf) { + do_error("can't read agf block for ag %d\n", agno); + libxfs_putbuf(sbbuf); + free(sb); + return; + } + agf = XFS_BUF_TO_AGF(agfbuf); + + agibuf = libxfs_readbuf(mp->m_dev, + XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR), 1, 0); + if (!agibuf) { + do_error("can't read agi block for ag %d\n", agno); + libxfs_putbuf(agfbuf); + libxfs_putbuf(sbbuf); + free(sb); + return; + } + agi = XFS_BUF_TO_AGI(agibuf); + + /* fix up bad ag headers */ + + status = verify_set_agheader(mp, sbbuf, sb, agf, agi, agno); + + if (status & XR_AG_SB_SEC) { + if (!no_modify) + sb_dirty = 1; + /* + * clear bad sector bit because we don't want + * to skip further processing. we just want to + * ensure that we write out the modified sb buffer. + */ + status &= ~XR_AG_SB_SEC; + } + if (status & XR_AG_SB) { + if (!no_modify) + sb_dirty = 1; + else + do_warn("would "); + + do_warn("reset bad sb for ag %d\n", agno); + } + if (status & XR_AG_AGF) { + if (!no_modify) + agf_dirty = 1; + else + do_warn("would "); + + do_warn("reset bad agf for ag %d\n", agno); + } + if (status & XR_AG_AGI) { + if (!no_modify) + agi_dirty = 1; + else + do_warn("would "); + + do_warn("reset bad agi for ag %d\n", agno); + } + + if (status && no_modify) { + libxfs_putbuf(agibuf); + libxfs_putbuf(agfbuf); + libxfs_putbuf(sbbuf); + free(sb); + + do_warn("bad uncorrected agheader %d, skipping ag...\n", agno); + + return; + } + + scan_freelist(agf); + + if (INT_GET(agf->agf_roots[XFS_BTNUM_BNO], ARCH_CONVERT) != 0 && + verify_agbno(mp, agno, INT_GET(agf->agf_roots[XFS_BTNUM_BNO], ARCH_CONVERT))) + scan_sbtree(INT_GET(agf->agf_roots[XFS_BTNUM_BNO], ARCH_CONVERT), + INT_GET(agf->agf_levels[XFS_BTNUM_BNO], ARCH_CONVERT), + agno, 0, scanfunc_bno, 1); + else + do_warn("bad agbno %u for btbno root, agno %d\n", + INT_GET(agf->agf_roots[XFS_BTNUM_BNO], ARCH_CONVERT), agno); + + if (INT_GET(agf->agf_roots[XFS_BTNUM_CNT], ARCH_CONVERT) != 0 && + verify_agbno(mp, agno, INT_GET(agf->agf_roots[XFS_BTNUM_CNT], ARCH_CONVERT))) + scan_sbtree(INT_GET(agf->agf_roots[XFS_BTNUM_CNT], ARCH_CONVERT), + INT_GET(agf->agf_levels[XFS_BTNUM_CNT], ARCH_CONVERT), + agno, 0, scanfunc_cnt, 1); + else + do_warn("bad agbno %u for btbcnt root, agno %d\n", + INT_GET(agf->agf_roots[XFS_BTNUM_CNT], ARCH_CONVERT), agno); + + if (INT_GET(agi->agi_root, ARCH_CONVERT) != 0 && verify_agbno(mp, agno, INT_GET(agi->agi_root, ARCH_CONVERT))) + scan_sbtree(INT_GET(agi->agi_root, ARCH_CONVERT), INT_GET(agi->agi_level, ARCH_CONVERT), agno, 0, + scanfunc_ino, 1); + else + do_warn("bad agbno %u for inobt root, agno %d\n", + INT_GET(agi->agi_root, ARCH_CONVERT), agno); + + ASSERT(agi_dirty == 0 || (agi_dirty && !no_modify)); + + if (agi_dirty && !no_modify) + libxfs_writebuf(agibuf, 0); + else + libxfs_putbuf(agibuf); + + ASSERT(agf_dirty == 0 || (agf_dirty && !no_modify)); + + if (agf_dirty && !no_modify) + libxfs_writebuf(agfbuf, 0); + else + libxfs_putbuf(agfbuf); + + ASSERT(sb_dirty == 0 || (sb_dirty && !no_modify)); + + if (sb_dirty && !no_modify) { + libxfs_xlate_sb(XFS_BUF_PTR(sbbuf), sb, -1, ARCH_CONVERT, + XFS_SB_ALL_BITS); + libxfs_writebuf(sbbuf, 0); + } else + libxfs_putbuf(sbbuf); + free(sb); +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/scan.h linux-2.4-xfs/cmd/xfsprogs/repair/scan.h --- linux-2.4.7/cmd/xfsprogs/repair/scan.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/scan.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef _XR_SCAN_H +#define _XR_SCAN_H + +struct blkmap; + +void scan_sbtree( + xfs_agblock_t root, + int nlevels, + xfs_agnumber_t agno, + int suspect, + void (*func)(xfs_btree_sblock_t *block, + int level, + xfs_agblock_t bno, + xfs_agnumber_t agno, + int suspect, + int isroot), + int isroot); + +int scan_lbtree( + xfs_dfsbno_t root, + int nlevels, + int (*func)(xfs_btree_lblock_t *block, + int level, + int type, + int whichfork, + xfs_dfsbno_t bno, + xfs_ino_t ino, + xfs_drfsbno_t *tot, + __uint64_t *nex, + struct blkmap **blkmapp, + bmap_cursor_t *bm_cursor, + int isroot, + int check_dups, + int *dirty), + int type, + int whichfork, + xfs_ino_t ino, + xfs_drfsbno_t *tot, + __uint64_t *nex, + struct blkmap **blkmapp, + bmap_cursor_t *bm_cursor, + int isroot, + int check_dups); + +int scanfunc_bmap( + xfs_btree_lblock_t *ablock, + int level, + int type, + int whichfork, + xfs_dfsbno_t bno, + xfs_ino_t ino, + xfs_drfsbno_t *tot, + __uint64_t *nex, + struct blkmap **blkmapp, + bmap_cursor_t *bm_cursor, + int isroot, + int check_dups, + int *dirty); + +void scanfunc_bno( + xfs_btree_sblock_t *ablock, + int level, + xfs_agblock_t bno, + xfs_agnumber_t agno, + int suspect, + int isroot); + +void scanfunc_cnt( + xfs_btree_sblock_t *ablock, + int level, + xfs_agblock_t bno, + xfs_agnumber_t agno, + int suspect, + int isroot); + +void +scanfunc_ino( + xfs_btree_sblock_t *ablock, + int level, + xfs_agblock_t bno, + xfs_agnumber_t agno, + int suspect, + int isroot); + +#endif /* _XR_SCAN_H */ diff -rNu linux-2.4.7/cmd/xfsprogs/repair/versions.c linux-2.4-xfs/cmd/xfsprogs/repair/versions.c --- linux-2.4.7/cmd/xfsprogs/repair/versions.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/versions.c Mon Apr 2 21:52:38 2001 @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#define EXTERN +#include "versions.h" +#undef EXTERN +#include "err_protos.h" +#include "globals.h" + +void +update_sb_version(xfs_mount_t *mp) +{ + xfs_sb_t *sb; + __uint16_t vn; + + sb = &mp->m_sb; + + if (fs_attributes) { + if (!XFS_SB_VERSION_HASATTR(sb)) { + ASSERT(fs_attributes_allowed); + + XFS_SB_VERSION_ADDATTR(sb); + } + } + + if (fs_inode_nlink) { + if (!XFS_SB_VERSION_HASNLINK(sb)) { + ASSERT(fs_inode_nlink_allowed); + + XFS_SB_VERSION_ADDNLINK(sb); + } + } + + /* + * fix up the superblock version number and feature bits, + * turn off quota bits and flags if the filesystem doesn't + * have quotas. + */ + if (fs_quotas) { + if (!XFS_SB_VERSION_HASQUOTA(sb)) { + ASSERT(fs_quotas_allowed); + + XFS_SB_VERSION_ADDQUOTA(sb); + } + + /* + * protect against stray bits in the quota flag field + */ + if (sb->sb_qflags & ~(XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD| + XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT| + XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD)) { + /* + * update the incore superblock, if we're in + * no_modify mode, it'll never get flushed out + * so this is ok. + */ + do_warn("bogus quota flags 0x%x set in superblock", + sb->sb_qflags & ~(XFS_UQUOTA_ACCT| + XFS_UQUOTA_ENFD| + XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT| + XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD)); + + sb->sb_qflags &= (XFS_UQUOTA_ACCT| + XFS_UQUOTA_ENFD| + XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT| + XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD); + + if (!no_modify) + do_warn(", bogus flags will be cleared\n"); + else + do_warn(", bogus flags would be cleared\n"); + } + } else { + sb->sb_qflags = 0; + + if (XFS_SB_VERSION_HASQUOTA(sb)) { + lost_quotas = 1; + vn = sb->sb_versionnum; + vn &= ~XFS_SB_VERSION_QUOTABIT; + + if (!(vn & XFS_SB_VERSION_ALLFBITS)) + vn = XFS_SB_VERSION_TOOLD(vn); + + ASSERT(vn != 0); + sb->sb_versionnum = vn; + } + } + + if (!fs_aligned_inodes) { + if (XFS_SB_VERSION_HASALIGN(sb)) { + if (XFS_SB_VERSION_NUM(sb) == XFS_SB_VERSION_4) + XFS_SB_VERSION_SUBALIGN(sb); + } + } +} + +/* + * returns 0 if things are fine, 1 if we don't understand + * this superblock version. Sets superblock geometry-dependent + * global variables. + */ +int +parse_sb_version(xfs_sb_t *sb) +{ + int issue_warning; + + fs_attributes = 0; + fs_inode_nlink = 0; + fs_quotas = 0; + fs_aligned_inodes = 0; + fs_sb_feature_bits = 0; + fs_ino_alignment = 0; + fs_has_extflgbit = 0; + have_uquotino = 0; + have_gquotino = 0; + issue_warning = 0; + + /* + * ok, check to make sure that the sb isn't newer + * than we are + */ + if (XFS_SB_VERSION_HASEXTFLGBIT(sb)) { + fs_has_extflgbit = 1; + if (!fs_has_extflgbit_allowed) { + issue_warning = 1; + do_warn( + "This filesystem has uninitialized extent flags.\n"); + } + } + + if (XFS_SB_VERSION_HASSHARED(sb)) { + fs_shared = 1; + if (!fs_shared_allowed) { + issue_warning = 1; + do_warn("This filesystem is marked shared.\n"); + } + } + + if (issue_warning) { + do_warn( +"This filesystem uses 6.5 feature(s) not yet supported in this release.\n\ +Please run a 6.5 version of xfs_repair.\n"); + return(1); + } + + if (!XFS_SB_GOOD_VERSION(sb)) { + do_warn( + "WARNING: unknown superblock version %d\n", XFS_SB_VERSION_NUM(sb)); + do_warn( + "This filesystem contains features not understood by this program.\n"); + return(1); + } + + if (XFS_SB_VERSION_NUM(sb) == XFS_SB_VERSION_4) { + if (!fs_sb_feature_bits_allowed) { + do_warn( + "WARNING: you have disallowed superblock feature bits disallowed\n"); + do_warn( + "\tbut this superblock has feature bits. The superblock\n"); + + if (!no_modify) { + do_warn( + "\twill be downgraded. This may cause loss of filesystem meta-data\n"); + } else { + do_warn( + "\twould be downgraded. This might cause loss of filesystem\n"); + do_warn( + "\tmeta-data.\n"); + } + } else { + fs_sb_feature_bits = 1; + } + } + + if (XFS_SB_VERSION_HASATTR(sb)) { + if (!fs_attributes_allowed) { + do_warn( + "WARNING: you have disallowed attributes but this filesystem\n"); + if (!no_modify) { + do_warn( + "\thas attributes. The filesystem will be downgraded and\n"); + do_warn( + "\tall attributes will be removed.\n"); + } else { + do_warn( + "\thas attributes. The filesystem would be downgraded and\n"); + do_warn( + "\tall attributes would be removed.\n"); + } + } else { + fs_attributes = 1; + } + } + + if (XFS_SB_VERSION_HASNLINK(sb)) { + if (!fs_inode_nlink_allowed) { + do_warn( + "WARNING: you have disallowed version 2 inodes but this filesystem\n"); + if (!no_modify) { + do_warn( + "\thas version 2 inodes. The filesystem will be downgraded and\n"); + do_warn( + "\tall version 2 inodes will be converted to version 1 inodes.\n"); + do_warn( + "\tThis may cause some hard links to files to be destroyed\n"); + } else { + do_warn( + "\thas version 2 inodes. The filesystem would be downgraded and\n"); + do_warn( + "\tall version 2 inodes would be converted to version 1 inodes.\n"); + do_warn( + "\tThis might cause some hard links to files to be destroyed\n"); + } + } else { + fs_inode_nlink = 1; + } + } + + if (XFS_SB_VERSION_HASQUOTA(sb)) { + if (!fs_quotas_allowed) { + do_warn( + "WARNING: you have disallowed quotas but this filesystem\n"); + if (!no_modify) { + do_warn( + "\thas quotas. The filesystem will be downgraded and\n"); + do_warn( + "\tall quota information will be removed.\n"); + } else { + do_warn( + "\thas quotas. The filesystem would be downgraded and\n"); + do_warn( + "\tall quota information would be removed.\n"); + } + } else { + fs_quotas = 1; + + if (sb->sb_uquotino != 0 && + sb->sb_uquotino != NULLFSINO) + have_uquotino = 1; + + if (sb->sb_gquotino != 0 && + sb->sb_gquotino != NULLFSINO) + have_gquotino = 1; + } + } + + if (XFS_SB_VERSION_HASALIGN(sb)) { + if (fs_aligned_inodes_allowed) { + fs_aligned_inodes = 1; + fs_ino_alignment = sb->sb_inoalignmt; + } else { + do_warn( + "WARNING: you have disallowed aligned inodes but this filesystem\n"); + if (!no_modify) { + do_warn( + "\thas aligned inodes. The filesystem will be downgraded.\n"); + do_warn( +"\tThis will permanently degrade the performance of this filesystem.\n"); + } else { + do_warn( + "\thas aligned inodes. The filesystem would be downgraded.\n"); + do_warn( +"\tThis would permanently degrade the performance of this filesystem.\n"); + } + } + } + + /* + * calculate maximum file offset for this geometry + */ + fs_max_file_offset = 0x7fffffffffffffffLL >> sb->sb_blocklog; + + return(0); +} diff -rNu linux-2.4.7/cmd/xfsprogs/repair/versions.h linux-2.4-xfs/cmd/xfsprogs/repair/versions.h --- linux-2.4.7/cmd/xfsprogs/repair/versions.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/versions.h Sun Jan 14 23:36:03 2001 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef _XR_VERSIONS_H +#define _XR_VERSIONS_H + +#ifndef EXTERN +#define EXTERN extern +#endif /* EXTERN */ + +/* + * possible XFS filesystem features + * + * attributes (6.2) + * inode version 2 (32-bit link counts) (6.2) + * quotas (6.2+) + * aligned inodes (6.2+) + * + * bitmask fields happend after 6.2. + */ + +/* + * filesystem feature global vars, set to 1 if the feature + * is *allowed*, 0 otherwise. These can be set via command-line + * options + */ + +EXTERN int fs_attributes_allowed; +EXTERN int fs_inode_nlink_allowed; +EXTERN int fs_quotas_allowed; +EXTERN int fs_aligned_inodes_allowed; +EXTERN int fs_sb_feature_bits_allowed; +EXTERN int fs_has_extflgbit_allowed; +EXTERN int fs_shared_allowed; + +/* + * filesystem feature global vars, set to 1 if the feature + * is on, 0 otherwise + */ + +EXTERN int fs_attributes; +EXTERN int fs_inode_nlink; +EXTERN int fs_quotas; +EXTERN int fs_aligned_inodes; +EXTERN int fs_sb_feature_bits; +EXTERN int fs_has_extflgbit; +EXTERN int fs_shared; + +/* + * inode chunk alignment, fsblocks + */ + +EXTERN xfs_extlen_t fs_ino_alignment; + +/* + * modify superblock to reflect current state of global fs + * feature vars above + */ +void update_sb_version(xfs_mount_t *mp); + +/* + * parse current sb to set above feature vars + */ +int parse_sb_version(xfs_sb_t *sb); + +#endif /* _XR_VERSIONS_H */ diff -rNu linux-2.4.7/cmd/xfsprogs/repair/xfs_repair.c linux-2.4-xfs/cmd/xfsprogs/repair/xfs_repair.c --- linux-2.4.7/cmd/xfsprogs/repair/xfs_repair.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/repair/xfs_repair.c Mon Apr 2 21:52:38 2001 @@ -0,0 +1,582 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include "avl.h" +#include "avl64.h" +#include "globals.h" +#include "versions.h" +#include "agheader.h" +#include "protos.h" +#include "incore.h" +#include "err_protos.h" + +#define rounddown(x, y) (((x)/(y))*(y)) + +extern void phase1(xfs_mount_t *); +extern void phase2(xfs_mount_t *, libxfs_init_t *); +extern void phase3(xfs_mount_t *); +extern void phase4(xfs_mount_t *); +extern void phase5(xfs_mount_t *); +extern void phase6(xfs_mount_t *); +extern void phase7(xfs_mount_t *); +extern void incore_init(xfs_mount_t *); + +#define XR_MAX_SECT_SIZE (64 * 1024) + +/* + * option tables for getsubopt calls + */ + +/* + * -o (user-supplied override options) + */ + +char *o_opts[] = { +#define ASSUME_XFS 0 + "assume_xfs", +#define PRE_65_BETA 1 + "fs_is_pre_65_beta", + NULL +}; + +static void +usage(void) +{ + do_warn("Usage: %s [-nV] [-o subopt[=value]] [-l logdevice] devname\n", + progname); + exit(1); +} + +static char *err_message[] = { + "no error", + "bad magic number", + "bad blocksize field", + "bad blocksize log field", + "bad version number", + "filesystem mkfs-in-progress bit set", + "inconsistent filesystem geometry information", + "bad inode size or inconsistent with number of inodes/block", + "bad sector size", + "AGF geometry info conflicts with filesystem geometry", + "AGI geometry info conflicts with filesystem geometry", + "AG superblock geometry info conflicts with filesystem geometry", + "attempted to perform I/O beyond EOF", + "inconsistent filesystem geometry in realtime filesystem component", + "maximum indicated percentage of inodes > 100%", + "inconsistent inode alignment value", + "not enough secondary superblocks with matching geometry", + "bad stripe unit in superblock", + "bad stripe width in superblock", + "bad shared version number in superblock" +}; + +char * +err_string(int err_code) +{ + if (err_code < XR_OK || err_code >= XR_BAD_ERR_CODE) + do_abort("bad error code - %d\n", err_code); + + return(err_message[err_code]); +} + +static void +noval(char opt, char *tbl[], int idx) +{ + do_warn("-%c %s option cannot have a value\n", opt, tbl[idx]); + usage(); +} + +static void +respec(char opt, char *tbl[], int idx) +{ + do_warn("-%c ", opt); + if (tbl) + do_warn("%s ", tbl[idx]); + do_warn("option respecified\n"); + usage(); +} + +static void +unknown(char opt, char *s) +{ + do_warn("unknown option -%c %s\n", opt, s); + usage(); +} + +/* + * sets only the global argument flags and variables + */ +void +process_args(int argc, char **argv) +{ + char *p; + int c; + + log_spec = 0; + fs_is_dirty = 0; + verbose = 0; + no_modify = 0; + isa_file = 0; + dumpcore = 0; + full_backptrs = 0; + delete_attr_ok = 1; + force_geo = 0; + assume_xfs = 0; + clear_sunit = 0; + sb_inoalignmt = 0; + sb_unit = 0; + sb_width = 0; + fs_attributes_allowed = 1; + fs_inode_nlink_allowed = 1; + fs_quotas_allowed = 1; + fs_aligned_inodes_allowed = 1; + fs_sb_feature_bits_allowed = 1; + fs_has_extflgbit_allowed = 1; + pre_65_beta = 0; + fs_shared_allowed = 1; + + /* + * XXX have to add suboption processing here + * attributes, quotas, nlinks, aligned_inos, sb_fbits + */ + while ((c = getopt(argc, argv, "o:fnDvVl:")) != EOF) { + switch (c) { + case 'D': + dumpcore = 1; + break; + case 'o': + p = optarg; + while (*p != '\0') { + char *val; + + switch (getsubopt(&p, (constpp)o_opts, &val)) { + case ASSUME_XFS: + if (val) + noval('o', o_opts, ASSUME_XFS); + if (assume_xfs) + respec('o', o_opts, ASSUME_XFS); + assume_xfs = 1; + break; + case PRE_65_BETA: + if (val) + noval('o', o_opts, PRE_65_BETA); + if (pre_65_beta) + respec('o', o_opts, + PRE_65_BETA); + pre_65_beta = 1; + break; + default: + unknown('o', val); + break; + } + } + break; + case 'l': + log_name = optarg; + log_spec = 1; + break; + case 'f': + isa_file = 1; + break; + case 'n': + no_modify = 1; + break; + case 'v': + verbose = 1; + break; + case 'V': + printf("%s version %s\n", progname, VERSION); + break; + case '?': + usage(); + } + } + + if (argc - optind != 1) + usage(); + + if ((fs_name = argv[optind]) == NULL) + usage(); +} + +void +do_msg(int do_abort, char const *msg, va_list args) +{ + vfprintf(stderr, msg, args); + + if (do_abort) { + if (dumpcore) + abort(); + exit(1); + } +} + +void +do_error(char const *msg, ...) +{ + va_list args; + + fprintf(stderr, "\nfatal error -- "); + + va_start(args, msg); + do_msg(1, msg, args); +} + +/* + * like do_error, only the error is internal, no system + * error so no oserror processing + */ +void +do_abort(char const *msg, ...) +{ + va_list args; + + va_start(args, msg); + do_msg(1, msg, args); +} + +void +do_warn(char const *msg, ...) +{ + va_list args; + + fs_is_dirty = 1; + + va_start(args, msg); + do_msg(0, msg, args); + va_end(args); +} + +/* no formatting */ + +void +do_log(char const *msg, ...) +{ + va_list args; + + va_start(args, msg); + do_msg(0, msg, args); + va_end(args); +} + +void +calc_mkfs(xfs_mount_t *mp) +{ + xfs_agblock_t fino_bno; + int do_inoalign; + + do_inoalign = mp->m_sinoalign; + + /* + * pre-calculate geometry of ag 0. We know what it looks + * like because we know what mkfs does -- 3 btree roots, + * and some number of blocks to prefill the agfl. + */ + bnobt_root = howmany(4 * mp->m_sb.sb_sectsize, mp->m_sb.sb_blocksize); + bcntbt_root = bnobt_root + 1; + inobt_root = bnobt_root + 2; + fino_bno = inobt_root + XFS_MIN_FREELIST_RAW(1, 1, mp) + 1; + + /* + * ditto the location of the first inode chunks in the fs ('/') + */ + if (XFS_SB_VERSION_HASDALIGN(&mp->m_sb) && do_inoalign) { + first_prealloc_ino = XFS_OFFBNO_TO_AGINO(mp, roundup(fino_bno, + mp->m_sb.sb_unit), 0); + } else if (XFS_SB_VERSION_HASALIGN(&mp->m_sb) && + mp->m_sb.sb_inoalignmt > 1) { + first_prealloc_ino = XFS_OFFBNO_TO_AGINO(mp, + roundup(fino_bno, + mp->m_sb.sb_inoalignmt), + 0); + } else { + first_prealloc_ino = XFS_OFFBNO_TO_AGINO(mp, fino_bno, 0); + } + + ASSERT(XFS_IALLOC_BLOCKS(mp) > 0); + + if (XFS_IALLOC_BLOCKS(mp) > 1) + last_prealloc_ino = first_prealloc_ino + XFS_INODES_PER_CHUNK; + else + last_prealloc_ino = XFS_OFFBNO_TO_AGINO(mp, fino_bno + 1, 0); + + /* + * now the first 3 inodes in the system + */ + if (mp->m_sb.sb_rootino != first_prealloc_ino) { + do_warn( + "sb root inode value %llu inconsistent with calculated value %llu\n", + mp->m_sb.sb_rootino, first_prealloc_ino); + + if (!no_modify) + do_warn( + "resetting superblock root inode pointer to %llu\n", + first_prealloc_ino); + else + do_warn( + "would reset superblock root inode pointer to %llu\n", + first_prealloc_ino); + + /* + * just set the value -- safe since the superblock + * doesn't get flushed out if no_modify is set + */ + mp->m_sb.sb_rootino = first_prealloc_ino; + } + + if (mp->m_sb.sb_rbmino != first_prealloc_ino + 1) { + do_warn( +"sb realtime bitmap inode %llu inconsistent with calculated value %llu\n", + mp->m_sb.sb_rbmino, first_prealloc_ino + 1); + + if (!no_modify) + do_warn( + "resetting superblock realtime bitmap ino pointer to %llu\n", + first_prealloc_ino + 1); + else + do_warn( + "would reset superblock realtime bitmap ino pointer to %llu\n", + first_prealloc_ino + 1); + + /* + * just set the value -- safe since the superblock + * doesn't get flushed out if no_modify is set + */ + mp->m_sb.sb_rbmino = first_prealloc_ino + 1; + } + + if (mp->m_sb.sb_rsumino != first_prealloc_ino + 2) { + do_warn( +"sb realtime summary inode %llu inconsistent with calculated value %llu\n", + mp->m_sb.sb_rsumino, first_prealloc_ino + 2); + + if (!no_modify) + do_warn( + "resetting superblock realtime summary ino pointer to %llu\n", + first_prealloc_ino + 2); + else + do_warn( + "would reset superblock realtime summary ino pointer to %llu\n", + first_prealloc_ino + 2); + + /* + * just set the value -- safe since the superblock + * doesn't get flushed out if no_modify is set + */ + mp->m_sb.sb_rsumino = first_prealloc_ino + 2; + } + +} + +int +main(int argc, char **argv) +{ + libxfs_init_t args; + xfs_mount_t *temp_mp; + xfs_mount_t *mp; + xfs_sb_t *sb; + xfs_buf_t *sbp; + xfs_mount_t xfs_m; + + progname = basename(argv[0]); + + temp_mp = &xfs_m; + setbuf(stdout, NULL); + + process_args(argc, argv); + xfs_init(&args); + + /* do phase1 to make sure we have a superblock */ + phase1(temp_mp); + + if (no_modify && primary_sb_modified) { + do_warn("primary superblock would have been modified.\n"); + do_warn("cannot proceed further in no_modify mode.\n"); + do_warn("exiting now.\n"); + exit(1); + } + + /* prepare the mount structure */ + sbp = libxfs_readbuf(args.ddev, XFS_SB_DADDR, 1, 0); + memset(&xfs_m, 0, sizeof(xfs_mount_t)); + sb = &xfs_m.m_sb; + libxfs_xlate_sb(XFS_BUF_PTR(sbp), sb, 1, ARCH_CONVERT, XFS_SB_ALL_BITS); + + mp = libxfs_mount(&xfs_m, sb, args.ddev, args.logdev, args.rtdev, 0); + + if (!mp) { + fprintf(stderr, "%s: cannot repair this filesystem. Sorry.\n", + progname); + exit(1); + } + libxfs_putbuf(sbp); + + /* + * set XFS-independent status vars from the mount/sb structure + */ + glob_agcount = mp->m_sb.sb_agcount; + + chunks_pblock = mp->m_sb.sb_inopblock / XFS_INODES_PER_CHUNK; + max_symlink_blocks = howmany(MAXPATHLEN - 1, mp->m_sb.sb_blocksize); + inodes_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog; + + /* + * calculate what mkfs would do to this filesystem + */ + calc_mkfs(mp); + + /* + * check sb filesystem stats and initialize in-core data structures + */ + incore_init(mp); + + if (parse_sb_version(&mp->m_sb)) { + do_warn( + "Found unsupported filesystem features. Exiting now.\n"); + return(1); + } + + /* make sure the per-ag freespace maps are ok so we can mount the fs */ + + phase2(mp, &args); + + phase3(mp); + + phase4(mp); + + if (no_modify) + printf("No modify flag set, skipping phase 5\n"); + else + phase5(mp); + + if (!bad_ino_btree) { + phase6(mp); + + phase7(mp); + } else { + do_warn( + "Inode allocation btrees are too corrupted, skipping phases 6 and 7\n"); + } + + if (lost_quotas && !have_uquotino && !have_gquotino) { + if (!no_modify) { + do_warn( + "Warning: no quota inodes were found. Quotas disabled.\n"); + } else { + do_warn( + "Warning: no quota inodes were found. Quotas would be disabled.\n"); + } + } else if (lost_quotas) { + if (!no_modify) { + do_warn( + "Warning: quota inodes were cleared. Quotas disabled.\n"); + } else { + do_warn( +"Warning: quota inodes would be cleared. Quotas would be disabled.\n"); + } + } else { + if (lost_uquotino) { + if (!no_modify) { + do_warn( + "Warning: user quota information was cleared.\n"); + do_warn( +"User quotas can not be enforced until limit information is recreated.\n"); + } else { + do_warn( + "Warning: user quota information would be cleared.\n"); + do_warn( +"User quotas could not be enforced until limit information was recreated.\n"); + } + } + + if (lost_gquotino) { + if (!no_modify) { + do_warn( + "Warning: group quota information was cleared.\n"); + do_warn( +"Group quotas can not be enforced until limit information is recreated.\n"); + } else { + do_warn( + "Warning: group quota information would be cleared.\n"); + do_warn( +"Group quotas could not be enforced until limit information was recreated.\n"); + } + } + } + + if (no_modify) { + do_log( + "No modify flag set, skipping filesystem flush and exiting.\n"); + if (fs_is_dirty) + return(1); + + return(0); + } + + /* + * Clear the quota flags if they're on. + */ + sbp = libxfs_getsb(mp, 0); + if (!sbp) + do_error("couldn't get superblock\n"); + + sb = XFS_BUF_TO_SBP(sbp); + + if (sb->sb_qflags & (XFS_UQUOTA_CHKD|XFS_GQUOTA_CHKD)) { + do_warn( + "Note - quota info will be regenerated on next quota mount.\n"); + sb->sb_qflags &= ~(XFS_UQUOTA_CHKD|XFS_GQUOTA_CHKD); + } + + if (clear_sunit) { + do_warn( +"Note - stripe unit (%d) and width (%d) fields have been reset.\n" +"Please set with mount -o sunit=,swidth=\n", + sb->sb_unit, sb->sb_width); + sb->sb_unit = 0; + sb->sb_width = 0; + } + + libxfs_writebuf(sbp, 0); + + libxfs_umount(mp); + if (args.rtdev) + libxfs_device_close(args.rtdev); + if (args.logdev) + libxfs_device_close(args.logdev); + libxfs_device_close(args.ddev); + + do_log("done\n"); + + return(0); +} diff -rNu linux-2.4.7/cmd/xfsprogs/rtcp/CVS/Entries linux-2.4-xfs/cmd/xfsprogs/rtcp/CVS/Entries --- linux-2.4.7/cmd/xfsprogs/rtcp/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/rtcp/CVS/Entries Thu Jul 5 11:44:59 2001 @@ -0,0 +1,3 @@ +/Makefile/1.1/Wed May 9 06:56:06 2001/-ko/ +/xfs_rtcp.c/1.1/Wed May 9 06:56:06 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfsprogs/rtcp/CVS/Repository linux-2.4-xfs/cmd/xfsprogs/rtcp/CVS/Repository --- linux-2.4.7/cmd/xfsprogs/rtcp/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/rtcp/CVS/Repository Thu Jul 5 11:44:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfsprogs/rtcp diff -rNu linux-2.4.7/cmd/xfsprogs/rtcp/CVS/Root linux-2.4-xfs/cmd/xfsprogs/rtcp/CVS/Root --- linux-2.4.7/cmd/xfsprogs/rtcp/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/rtcp/CVS/Root Thu Jul 5 11:44:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfsprogs/rtcp/Makefile linux-2.4-xfs/cmd/xfsprogs/rtcp/Makefile --- linux-2.4.7/cmd/xfsprogs/rtcp/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/rtcp/Makefile Wed May 9 01:56:06 2001 @@ -0,0 +1,46 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CMDTARGET = xfs_rtcp +CFILES = xfs_rtcp.c + +default: $(CMDTARGET) + +include $(BUILDRULES) + +install: default + $(INSTALL) -m 755 -d $(PKG_BIN_DIR) + $(INSTALL) -m 755 $(CMDTARGET) $(PKG_BIN_DIR) +install-dev: diff -rNu linux-2.4.7/cmd/xfsprogs/rtcp/xfs_rtcp.c linux-2.4-xfs/cmd/xfsprogs/rtcp/xfs_rtcp.c --- linux-2.4.7/cmd/xfsprogs/rtcp/xfs_rtcp.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfsprogs/rtcp/xfs_rtcp.c Wed May 9 01:56:06 2001 @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include + +int rtcp(char *, char *, int); +int xfsrtextsize(char *path); + +int pflag; +char *progname; + +void +usage() +{ + fprintf(stderr, "%s [-e extsize] [-p] source target\n", progname); + exit(2); +} + +int +main(int argc, char **argv) +{ + register int c, i, r, errflg = 0; + struct stat s2; + int eflag; + int extsize = - 1; + + progname = basename(argv[0]); + + while ((c = getopt(argc, argv, "pe:V")) != EOF) { + switch (c) { + case 'e': + eflag = 1; + extsize = atoi(optarg); + break; + case 'p': + pflag = 1; + break; + case 'V': + printf("%s version %s\n", progname, VERSION); + break; + default: + errflg++; + } + } + + /* + * Check for sufficient arguments or a usage error. + */ + argc -= optind; + argv = &argv[optind]; + + if (argc < 2) { + fprintf(stderr, "%s: must specify files to copy\n", progname); + errflg++; + } + + if (errflg) + usage(); + + /* + * If there is more than a source and target, + * the last argument (the target) must be a directory + * which really exists. + */ + if (argc > 2) { + if (stat(argv[argc-1], &s2) < 0) { + fprintf(stderr, "%s: stat of %s failed\n", + progname, argv[argc-1]); + exit(2); + } + + if (!S_ISDIR(s2.st_mode)) { + fprintf(stderr, "%s: final argument is not directory\n", + progname); + usage(); + } + } + + /* + * Perform a multiple argument rtcp by + * multiple invocations of rtcp(). + */ + r = 0; + for (i = 0; i < argc-1; i++) + r += rtcp(argv[i], argv[argc-1], extsize); + + /* + * Show errors by nonzero exit code. + */ + exit(r?2:0); +} + +int +rtcp( char *source, char *target, int fextsize) +{ + int fromfd, tofd, readct, writect, iosz, reopen; + int remove = 0, rtextsize; + char *sp, *fbuf, *ptr; + char tbuf[ PATH_MAX ]; + struct stat s1, s2; + struct fsxattr fsxattr; + struct dioattr dioattr; + + /* + * While source or target have trailing /, remove them + * unless only "/". + */ + sp = source + strlen(source); + if (sp) { + while (*--sp == '/' && sp > source) + *sp = '\0'; + } + sp = target + strlen(target); + if (sp) { + while (*--sp == '/' && sp > target) + *sp = '\0'; + } + + if ( stat(source, &s1) ) { + fprintf(stderr, "%s: failed stat on\n", progname); + perror(source); + return( -1); + } + + /* + * check for a realtime partition + */ + sprintf(tbuf,"%s",target); + if ( stat(target, &s2) ) { + if (!S_ISDIR(s2.st_mode)) { + /* take out target file name */ + if ((ptr = strrchr(tbuf, '/')) != NULL) + *ptr = '\0'; + else + sprintf(tbuf, "."); + } + } + + if ( (rtextsize = xfsrtextsize( tbuf )) <= 0 ) { + fprintf(stderr, "%s: %s filesystem has no realtime partition\n", + progname, tbuf); + return( -1 ); + } + + /* + * check if target is a directory + */ + sprintf(tbuf,"%s",target); + if ( !stat(target, &s2) ) { + if (S_ISDIR(s2.st_mode)) { + sprintf(tbuf,"%s/%s",target, basename(source)); + } + } + + if ( stat(tbuf, &s2) ) { + /* + * create the file if it does not exist + */ + if ( (tofd = open(tbuf, O_RDWR|O_CREAT|O_DIRECT, 0666)) < 0 ) { + fprintf(stderr, "%s: Open of %s failed.\n", + progname, tbuf); + return( -1 ); + } + remove = 1; + + /* + * mark the file as a realtime file + */ + fsxattr.fsx_xflags = XFS_XFLAG_REALTIME; + if (fextsize != -1 ) + fsxattr.fsx_extsize = fextsize; + else + fsxattr.fsx_extsize = 0; + + if ( ioctl( tofd, XFS_IOC_FSSETXATTR, &fsxattr) ) { + fprintf(stderr, "%s: Set attributes on %s failed.\n", + progname, tbuf); + close( tofd ); + unlink( tbuf ); + return( -1 ); + } + } else { + /* + * open existing file + */ + if ( (tofd = open(tbuf, O_RDWR|O_DIRECT)) < 0 ) { + fprintf(stderr, "%s: Open of %s failed.\n", + progname, tbuf); + return( -1 ); + } + + if ( ioctl( tofd, XFS_IOC_FSGETXATTR, &fsxattr) ) { + fprintf(stderr, "%s: Get attributes of %s failed.\n", + progname, tbuf); + close( tofd ); + return( -1 ); + } + + /* + * check if the existing file is already a realtime file + */ + if ( !(fsxattr.fsx_xflags & XFS_XFLAG_REALTIME) ) { + fprintf(stderr, "%s: %s is not a realtime file.\n", + progname, tbuf); + return( -1 ); + } + + /* + * check for matching extent size + */ + if ( (fextsize != -1) && (fsxattr.fsx_extsize != fextsize) ) { + fprintf(stderr, "%s: %s file extent size is %d, " + "instead of %d.\n", + progname, tbuf, fsxattr.fsx_extsize, fextsize); + return( -1 ); + } + } + + /* + * open the source file + */ + reopen = 0; + if ( (fromfd = open(source, O_RDONLY|O_DIRECT)) < 0 ) { + fprintf(stderr, "%s: Open of %s source failed.\n", + progname, source); + close( tofd ); + if (remove) + unlink( tbuf ); + return( -1 ); + } + + fsxattr.fsx_xflags = 0; + fsxattr.fsx_extsize = 0; + if ( ioctl( fromfd, XFS_IOC_FSGETXATTR, &fsxattr) ) { + reopen = 1; + } else { + if (! (fsxattr.fsx_xflags & XFS_XFLAG_REALTIME) ){ + fprintf(stderr, "%s: %s is not a realtime file.\n", + progname, source); + reopen = 1; + } + } + + if (reopen) { + close( fromfd ); + if ( (fromfd = open(source, O_RDONLY )) < 0 ) { + fprintf(stderr, "%s: Open of %s source failed.\n", + progname, source); + close( tofd ); + if (remove) + unlink( tbuf ); + return( -1 ); + } + } + + /* + * get direct I/O parameters + */ + if ( ioctl( tofd, XFS_IOC_DIOINFO, &dioattr) ) { + fprintf(stderr, "%s: Could not get direct I/O information.\n", + progname); + close( fromfd ); + close( tofd ); + if ( remove ) + unlink( tbuf ); + return( -1 ); + } + + if ( rtextsize % dioattr.d_miniosz ) { + fprintf(stderr, "%s: extent size %d not a multiple of %d.\n", + progname, rtextsize, dioattr.d_miniosz); + close( fromfd ); + close( tofd ); + if ( remove ) + unlink( tbuf ); + return( -1 ); + } + + /* + * Check that the source file size is a multiple of the + * file system block size. + */ + if ( s1.st_size % dioattr.d_miniosz ) { + printf("The size of %s is not a multiple of %d.\n", + source, dioattr.d_miniosz); + if ( pflag ) { + printf("%s will be padded to %lld bytes.\n", + tbuf, + (((s1.st_size / dioattr.d_miniosz) + 1) * + dioattr.d_miniosz) ); + + } else { + printf("Use the -p option to pad %s " + "to a size which is a multiple of %d bytes.\n", + tbuf, dioattr.d_miniosz); + close( fromfd ); + close( tofd ); + if ( remove ) + unlink( tbuf ); + return( -1 ); + } + } + + iosz = dioattr.d_miniosz; + fbuf = memalign( dioattr.d_mem, iosz); + bzero (fbuf, iosz); + + /* + * read the entire source file + */ + while ( ( readct = read( fromfd, fbuf, iosz) ) != 0 ) { + /* + * if there is a read error - break + */ + if (readct < 0 ) { + break; + } + + /* + * if there is a short read, pad to a block boundary + */ + if ( readct != iosz ) { + if ( (readct % dioattr.d_miniosz) != 0 ) { + readct = ( (readct/dioattr.d_miniosz) + 1 ) * + dioattr.d_miniosz; + } + } + + /* + * write to target file + */ + writect = write( tofd, fbuf, readct); + + if ( writect != readct ) { + fprintf(stderr, "%s: Write error.\n", progname); + close(fromfd); + close(tofd); + free( fbuf ); + return( -1 ); + } + + bzero( fbuf, iosz); + } + + close(fromfd); + close(tofd); + free( fbuf ); + return( 0 ); +} + +/* + * Determine the realtime extent size of the XFS file system + */ +int +xfsrtextsize( char *path) +{ + int fd, rval, rtextsize; + xfs_fsop_geom_t geo; + + fd = open( path, O_RDONLY ); + if ( fd < 0 ) { + fprintf(stderr, "%s: Could not open ", progname); + perror(path); + return -1; + } + rval = ioctl(fd, XFS_IOC_FSGEOMETRY, &geo ); + close(fd); + + rtextsize = geo.rtextsize * geo.blocksize; + + if ( rval < 0 ) + return -1; + return rtextsize; +} diff -rNu linux-2.4.7/cmd/xfstests/001 linux-2.4-xfs/cmd/xfstests/001 --- linux-2.4.7/cmd/xfstests/001 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/001 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,314 @@ +#! /bin/sh +# +# XFS QA Test No. 001 +# $Id: 1.1 $ +# +# Random file copier to produce chains of identical files so the head +# and the tail cna be diff'd at then end of each iteration. +# +# Exercises creat, write and unlink for a variety of directory sizes, and +# checks for data corruption. +# +# run [config] +# +# config has one line per file with filename and byte size, else use +# the default one below. +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=kenmcd@bruce.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +tmp=/tmp/$$ +here=`pwd` +status=1 +done_cleanup=false +trap "_cleanup; rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# real QA test starts here + +verbose=true + +if [ $# -eq 0 ] +then + # use the default config + # + cat <$tmp.config +# pathname size in bytes +# +small 10 +big 102400 +sub/small 10 +sub/big 102400 +# +sub/a 1 +sub/b 2 +sub/c 4 +sub/d 8 +sub/e 16 +sub/f 32 +sub/g 64 +sub/h 128 +sub/i 256 +sub/j 512 +sub/k 1024 +sub/l 2048 +sub/m 4096 +sub/n 8192 +# +sub/a00 100 +sub/b00 200 +sub/c00 400 +sub/d00 800 +sub/e00 1600 +sub/f00 3200 +sub/g00 6400 +sub/h00 12800 +sub/i00 25600 +sub/j00 51200 +sub/k00 102400 +sub/l00 204800 +sub/m00 409600 +sub/n00 819200 +# +sub/a000 1000 +sub/e000 16000 +sub/h000 128000 +sub/k000 1024000 +End-of-File +elif [ $# -eq 1 ] +then + if [ -f $1 ] + then + cp $1 $tmp.config + else + echo "Error: cannot open config \"$1\"" + exit 1 + fi +else + echo "Usage: run [config]" + exit 1 +fi + +ncopy=200 # number of file copies in the chain step + +_setup() +{ + if mkdir -p $TEST_DIR/$$ + then + : + else + echo "Error: cannot mkdir \"$TEST_DIR/$$\"" + exit 1 + fi + cd $TEST_DIR/$$ + + $verbose && echo -n "setup " + sed -e '/^#/d' $tmp.config \ + | while read file nbytes + do + dir=`dirname $file` + if [ "$dir" != "." ] + then + if [ ! -d $dir ] + then + if mkdir $dir + then + : + else + $verbose && echo + echo "Error: cannot mkdir \"$dir\"" + exit 1 + fi + fi + fi + rm -f $file + if $here/src/fill $file $file $nbytes + then + : + else + $verbose && echo + echo "Error: cannot create \"$file\"" + exit 1 + fi + $verbose && echo -n "." + done + $verbose && echo +} + +_mark_iteration() +{ + $verbose && echo -n "mark_iteration " + sed -e '/^#/d' $tmp.config \ + | while read file nbytes + do + if [ ! -f $file ] + then + $verbose && echo + echo "Error: $file vanished!" + touch $tmp.bad + continue + fi + sed -e "s/ [0-9][0-9]* / $1 /" <$file >$file.tmp + mv $file.tmp $file + $verbose && echo -n "." + done + $verbose && echo +} + +# for each file, make a number of copies forming a chain like foo.0, +# foo.1, foo.2, ... foo.N +# +# files are chosen at random, so the lengths of the chains are different +# +# then rename foo.N to foo.last and remove all of the other files in +# the chain +# +_chain() +{ + $AWK_PROG <$tmp.config ' +BEGIN { nfile = 0 } +/^\#/ { next } + { file[nfile] = $1 + link[nfile] = 0 + nfile++ + } +END { srand('$iter') + for (i=0; i < '$ncopy'; i++) { + # choose a file at random, and add one copy to that chain + j = -1 + while (j < 0 || j >= nfile) + j = int(rand() * nfile) + if (link[j] == 0) { + printf "if [ ! -f %s ]; then echo \"%s missing!\"; exit; fi\n",file[j],file[j] + printf "if [ -f %s.0 ]; then echo \"%s.0 already present!\"; exit; fi\n",file[j],file[j] + printf "cp %s %s.0\n",file[j],file[j] + } + else { + printf "if [ ! -f %s.%d ]; then echo \"%s.%d missing!\"; exit; fi\n",file[j],link[j]-1,file[j],link[j]-1 + printf "if [ -f %s.%d ]; then echo \"%s.%d already present!\"; exit; fi\n",file[j],link[j],file[j],link[j] + printf "cp %s.%d %s.%d\n",file[j],link[j]-1,file[j],link[j] + } + link[j]++ + } + # close all the chains, and remove all of the files except + # the head of the chain + for (j=0; j 0) + printf "mv %s.%d %s.last\n",file[j],link[j]-1,file[j] + for (i=0; i/dev/null 2>&1 + then + $verbose && echo -n "." + else + $verbose && echo + echo "Error: corruption for $file ..." + diff -c $file $file.last + touch $tmp.bad + fi + else + $verbose && echo -n "." + fi + done + $verbose && echo +} + +_cleanup() +{ + # cleanup + # + if $done_cleanup + then + : + elif [ $status -eq 0 ] + then + $verbose && echo "cleanup" + cd / + rm -rf $TEST_DIR/$$ + done_cleanup=true + fi +} + +status=0 +_cleanup +status=1 +done_cleanup=false + +_setup + +# do the test +# +for iter in 1 2 3 4 5 +do + echo -n "iter $iter chain ... " + _chain + _check + if [ -f $tmp.bad ] + then + echo "Fatal error: test abandoned without changes" + exit 1 + fi +done + +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/001.out linux-2.4-xfs/cmd/xfstests/001.out --- linux-2.4.7/cmd/xfstests/001.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/001.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,9 @@ +QA output created by 001 +cleanup +setup .................................... +iter 1 chain ... check .................................... +iter 2 chain ... check .................................... +iter 3 chain ... check .................................... +iter 4 chain ... check .................................... +iter 5 chain ... check .................................... +cleanup diff -rNu linux-2.4.7/cmd/xfstests/002 linux-2.4-xfs/cmd/xfstests/002 --- linux-2.4.7/cmd/xfstests/002 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/002 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,88 @@ +#! /bin/sh +# +# XFS QA Test No. 002 +# $Id: 1.1 $ +# +# simple inode link count test for a regular file +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=kenmcd@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +tmp=/tmp/$$ +here=`pwd` +status=0 # success is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# real QA test starts here + +echo "Silence is goodness ..." + +# ensure target directory exists +mkdir `dirname $TEST_DIR/$tmp` 2>/dev/null + +touch $TEST_DIR/$tmp.1 +for l in 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +do + ln $TEST_DIR/$tmp.1 $TEST_DIR/$tmp.$l + x=`src/lstat64 $TEST_DIR/$tmp.1 | sed -n -e '/ Links: /s/.*Links: *//p'` + if [ "$l" -ne $x ] + then + echo "Arrgh, created link #$l and lstat64 looks like ..." + src/lstat64 $TEST_DIR/$tmp.1 + status=1 + fi +done + +for l in 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 +do + x=`src/lstat64 $TEST_DIR/$tmp.1 | sed -n -e '/ Links: /s/.*Links: *//p'` + if [ "$l" -ne $x ] + then + echo "Arrgh, about to remove link #$l and lstat64 looks like ..." + src/lstat64 $TEST_DIR/$tmp.1 + status=1 + fi + rm -f $TEST_DIR/$tmp.$l +done + +# success, all done +exit diff -rNu linux-2.4.7/cmd/xfstests/002.out linux-2.4-xfs/cmd/xfstests/002.out --- linux-2.4.7/cmd/xfstests/002.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/002.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,2 @@ +QA output created by 002 +Silence is goodness ... diff -rNu linux-2.4.7/cmd/xfstests/003 linux-2.4-xfs/cmd/xfstests/003 --- linux-2.4.7/cmd/xfstests/003 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/003 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,104 @@ +#! /bin/sh +# +# XFS QA Test No. 003 +# $Id: 1.1 $ +# +# exercise xfs_db bug #784078 +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=nathans@melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +tmp=/tmp/$$ +here=`pwd` +status=0 # success is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +_need_to_be_root + +# real QA test starts here + +PATH=".:$PATH" + +[ -f core ] && rm -f core +[ -f core ] && echo "Warning: can't nuke existing core file!" + +test_done() +{ + sts=$? + [ -f core ] && echo "FAILED - core file" + [ ! -f core -a $sts != 0 ] && echo "FAILED - non-zero exit status" + rm -f core +} + +# real QA test starts here + +echo "=== TEST 1 ===" +xfs_db -r -c 'pop' -c 'type sb' $TEST_DEV +test_done + +echo "=== TEST 2 ===" +xfs_db -r -c 'push sb' $TEST_DEV +test_done + +echo "=== TEST 3 ===" +xfs_db -r -c 'pop' -c 'push sb' $TEST_DEV +test_done + +echo "=== TEST 4 ===" +xfs_db -r -c 'type sb' -c 'print' $TEST_DEV +test_done + +echo "=== TEST 5 ===" +xfs_db -r -c 'inode 128' -c 'push' -c 'type' $TEST_DEV >$tmp.out 2>&1 +test_done +if ! grep -q "current type is \"inode\"" $tmp.out +then + cat $tmp.out +fi + +echo "=== TEST 6 ===" +xfs_db -r -c 'sb' -c 'a' $TEST_DEV >$tmp.out 2>&1 # don't care about output +test_done + +echo "=== TEST 7 ===" +xfs_db -r -c 'ring' $TEST_DEV +test_done diff -rNu linux-2.4.7/cmd/xfstests/003.out linux-2.4-xfs/cmd/xfstests/003.out --- linux-2.4.7/cmd/xfstests/003.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/003.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,12 @@ +QA output created by 003 +=== TEST 1 === +no current object +=== TEST 2 === +=== TEST 3 === +=== TEST 4 === +no current object +no current type +=== TEST 5 === +=== TEST 6 === +=== TEST 7 === +no entries in location ring. diff -rNu linux-2.4.7/cmd/xfstests/004 linux-2.4-xfs/cmd/xfstests/004 --- linux-2.4.7/cmd/xfstests/004 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/004 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,139 @@ +#! /bin/sh +# XFS QA Test No. 004 +# $Id: 1.1 $ +# +# exercise xfs_db bug #789674 and other freesp functionality +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=nathans@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 + +_cleanup() +{ + umount $SCRATCH_MNT + rm -f $tmp.* + exit $status +} +trap "_cleanup" 0 1 2 3 15 + +_populate_scratch() +{ + mkfs -t xfs -f $SCRATCH_DEV >/dev/null 2>&1 + mount -t xfs $SCRATCH_DEV $SCRATCH_MNT + dd if=/dev/zero of=$SCRATCH_MNT/foo count=200 bs=4096 >/dev/null 2>&1 & + dd if=/dev/zero of=$SCRATCH_MNT/goo count=400 bs=4096 >/dev/null 2>&1 & + dd if=/dev/zero of=$SCRATCH_MNT/moo count=800 bs=4096 >/dev/null 2>&1 & + wait + umount $SCRATCH_MNT # flush everything + mount -t xfs $SCRATCH_DEV $SCRATCH_MNT # and then remount +} + + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_need_to_be_root +_require_scratch + +# real QA test starts here +rm -f $seq.full + +_populate_scratch + +eval `df -P -T --block-size=512 $SCRATCH_MNT 2>&1 \ + | $AWK_PROG 'END { printf "blocks=%u used=%u avail=%u\n", $3, $4, $5 }'` +echo "df gave: blocks=$blocks used=$used avail=$avail" >>$seq.full + +blksize=`xfs_db -r -c sb -c p $SCRATCH_DEV |grep blocksize |sed -e 's/.*= *//'` +if [ -z "$blksize" ] +then + echo "Arrgh ... cannot determine blocksize for $fs, xfs_db reports" + xfs_db -r -c sb -c p $SCRATCH_DEV + status=1 + continue +fi +echo "blocksize from xfs_db is '$blksize'" >>$seq.full + +xfs_db -r -c "freesp -s" $SCRATCH_DEV >$tmp.xfs_db +echo "xfs_db for $SCRATCH_DEV" >>$seq.full +cat $tmp.xfs_db >>$seq.full + +# check the 'blocks' field from freesp command is OK +perl -ne ' + BEGIN { $avail ='$avail' * 512; + $answer="(no xfs_db free blocks line?)" } + /free blocks (\d+)$/ || next; + $freesp = $1 * '$blksize'; + if ($freesp == $avail) { $answer = "yes"; } + else { $answer = "no ($freesp != $avail)"; } + END { print "$answer\n" } + ' <$tmp.xfs_db >$tmp.ans +ans="`cat $tmp.ans`" +echo "Checking blocks column same as df: $ans" +if [ "$ans" != yes ] +then + echo "Error: $SCRATCH_DEV: freesp mismatch: $ans" + echo "xfs_db output ..." + cat $tmp.xfs_db + status=1 +fi + +# check the 'pct' field from freesp command is good +perl -ne ' + BEGIN { $percent = 0; } + /free/ && next; # skip over free extent size number + if (/\s+(\d+\.\d+)$/) { + $percent += $1; + } + END { $percent += 0.5; print int($percent), "\n" } # round up +' <$tmp.xfs_db >$tmp.ans +ans="`cat $tmp.ans`" +echo "Checking percent column yields 100: $ans" +if [ "$ans" != 100 ] +then + echo "Error: $SCRATCH_DEV: pct mismatch: $ans (expected 100)" + echo "xfs_db output ..." + cat $tmp.xfs_db + status=1 +fi + +exit diff -rNu linux-2.4.7/cmd/xfstests/004.out linux-2.4-xfs/cmd/xfstests/004.out --- linux-2.4.7/cmd/xfstests/004.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/004.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,3 @@ +QA output created by 004 +Checking blocks column same as df: yes +Checking percent column yields 100: 100 diff -rNu linux-2.4.7/cmd/xfstests/005 linux-2.4-xfs/cmd/xfstests/005 --- linux-2.4.7/cmd/xfstests/005 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/005 Thu Apr 5 22:14:36 2001 @@ -0,0 +1,95 @@ +#! /bin/sh +# XFS QA Test No. 005 +# $Id: 1.1 $ +# +# Test symlinks & ELOOP +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +# +# note ELOOP limit used to be 32 but changed to 8. Who know what +# it might be next. +# + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_cleanup() +{ + cd $TEST_DIR + rm -f symlink_{0,1,2,3}{0,1,2,3,4,5,6,7,8,9} symlink_self empty_file +} + +_touch() +{ + touch $@ 2>&1 | sed \ + -e "s/creating \`//g" \ + -e "s/setting times of \`//g" \ + -e "s/'//g" +} + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# real QA test starts here + +cd $TEST_DIR + +o=empty_file +_touch $o +for f in symlink_{0,1,2,3}{0,1,2,3,4,5,6,7,8,9} +do + ln -s $o $f + o=$f +done + +ln -s symlink_self symlink_self + +echo "*** touch deep symlinks" +echo "" +_touch symlink_{0,1,2,3}{0,1,2,3,4,5,6,7,8,9} +echo "" +echo "*** touch recusive symlinks" +echo "" +_touch symlink_self + +exit diff -rNu linux-2.4.7/cmd/xfstests/005.out linux-2.4-xfs/cmd/xfstests/005.out --- linux-2.4.7/cmd/xfstests/005.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/005.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,39 @@ +QA output created by 005 +*** touch deep symlinks + +touch: symlink_08: Too many levels of symbolic links +touch: symlink_09: Too many levels of symbolic links +touch: symlink_10: Too many levels of symbolic links +touch: symlink_11: Too many levels of symbolic links +touch: symlink_12: Too many levels of symbolic links +touch: symlink_13: Too many levels of symbolic links +touch: symlink_14: Too many levels of symbolic links +touch: symlink_15: Too many levels of symbolic links +touch: symlink_16: Too many levels of symbolic links +touch: symlink_17: Too many levels of symbolic links +touch: symlink_18: Too many levels of symbolic links +touch: symlink_19: Too many levels of symbolic links +touch: symlink_20: Too many levels of symbolic links +touch: symlink_21: Too many levels of symbolic links +touch: symlink_22: Too many levels of symbolic links +touch: symlink_23: Too many levels of symbolic links +touch: symlink_24: Too many levels of symbolic links +touch: symlink_25: Too many levels of symbolic links +touch: symlink_26: Too many levels of symbolic links +touch: symlink_27: Too many levels of symbolic links +touch: symlink_28: Too many levels of symbolic links +touch: symlink_29: Too many levels of symbolic links +touch: symlink_30: Too many levels of symbolic links +touch: symlink_31: Too many levels of symbolic links +touch: symlink_32: Too many levels of symbolic links +touch: symlink_33: Too many levels of symbolic links +touch: symlink_34: Too many levels of symbolic links +touch: symlink_35: Too many levels of symbolic links +touch: symlink_36: Too many levels of symbolic links +touch: symlink_37: Too many levels of symbolic links +touch: symlink_38: Too many levels of symbolic links +touch: symlink_39: Too many levels of symbolic links + +*** touch recusive symlinks + +touch: symlink_self: Too many levels of symbolic links diff -rNu linux-2.4.7/cmd/xfstests/006 linux-2.4-xfs/cmd/xfstests/006 --- linux-2.4.7/cmd/xfstests/006 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/006 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,89 @@ +#! /bin/sh +# XFS QA Test No. 006 +# $Id: 1.1 $ +# +# permname +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_cleanup() +{ + rm -rf $TEST_DIR/permname.$$ +} + +_count() +{ + $AWK_PROG ' + BEGIN { count = 0 } + { count ++ } + END { print count " files created" } + ' +} + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# real QA test starts here + + +mkdir $TEST_DIR/permname.$$ + +echo "" +echo "single thread permname" +echo "----------------------" +mkdir $TEST_DIR/permname.$$/a +cd $TEST_DIR/permname.$$/a +$here/src/permname -c 4 -l 6 -p 1 || echo "permname returned $?" +find . | _count + +echo "" +echo "multi thread permname" +echo "----------------------" +mkdir $TEST_DIR/permname.$$/b +cd $TEST_DIR/permname.$$/b +$here/src/permname -c 4 -l 6 -p 4 || echo "permname returned $?" +find . | _count + +exit diff -rNu linux-2.4.7/cmd/xfstests/006.out linux-2.4-xfs/cmd/xfstests/006.out --- linux-2.4.7/cmd/xfstests/006.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/006.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,11 @@ +QA output created by 006 + +single thread permname +---------------------- +alpha size = 4, name length = 6, total files = 4096, nproc=1 +4097 files created + +multi thread permname +---------------------- +alpha size = 4, name length = 6, total files = 4096, nproc=4 +4097 files created diff -rNu linux-2.4.7/cmd/xfstests/007 linux-2.4-xfs/cmd/xfstests/007 --- linux-2.4.7/cmd/xfstests/007 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/007 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,90 @@ +#! /bin/sh +# XFS QA Test No. 007 +# $Id: 1.1 $ +# +# drive the src/nametest program +# which does a heap of open(create)/unlink/stat +# and checks that error codes make sense with its +# memory of the files created. +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sherman.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_cleanup() +{ + rm -f $tmp.* + rm -rf $TEST_DIR/$seq +} + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# real QA test starts here +status=1 # default failure +sourcefile=$tmp.nametest +seed=1 +iterations=100000 +num_filenames=100 + +# need to create an input file with a list of +# filenames on each line +i=1 +while [ $i -le $num_filenames ]; do + echo "nametest.$i" >>$sourcefile + i=`expr $i + 1` +done + +mkdir $TEST_DIR/$seq +cd $TEST_DIR/$seq +$here/src/nametest -l $sourcefile -s $seed -i $iterations -z + + +#optional stuff if your test has verbose output to help resolve problems +#echo +#echo "If failure, check $seq.full (this) and $seq.full.ok (reference)" + + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/007.out linux-2.4-xfs/cmd/xfstests/007.out --- linux-2.4.7/cmd/xfstests/007.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/007.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,22 @@ +QA output created by 007 +.Seed = 1 (use "-s 1" to re-execute this test) +....................................................................... +......................................................................... +......................................................................... +......................................................................... +......................................................................... +......................................................................... +......................................................................... +......................................................................... +......................................................................... +......................................................................... +......................................................................... +......................................................................... +......................................................................... +.................................................... +creates: 18736 OK, 18802 EEXIST ( 37538 total, 50% EEXIST) +removes: 18675 OK, 19927 ENOENT ( 38602 total, 51% ENOENT) +lookups: 12000 OK, 11860 ENOENT ( 23860 total, 49% ENOENT) +total : 49411 OK, 50589 w/error (100000 total, 50% w/error) + +cleanup: 61 removes diff -rNu linux-2.4.7/cmd/xfstests/008 linux-2.4-xfs/cmd/xfstests/008 --- linux-2.4.7/cmd/xfstests/008 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/008 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,98 @@ +#! /bin/sh +# XFS QA Test No. 008 +# $Id: 1.1 $ +# +# randholes test +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "rm -f $tmp.*; _cleanup; exit \$status" 0 1 2 3 15 + +_cleanup() +{ + rm -rf $TEST_DIR/randholes.$$.* +} + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_do_test() +{ + _n="$1" + _holes="$2" + _param="$3" + + out=$TEST_DIR/randholes.$$.$_n + echo "" + echo "randholes.$_n : $_param" + echo "------------------------------------------" + if $here/src/randholes $_param $out >$tmp.out + then + # quick check - how many holes did we get? + count=`xfs_bmap $out | egrep -c ': hole'` + # blocks can end up adjacent, therefore number of holes varies + _within_tolerance "holes" $count $_holes 10% -v + else + echo " randholes returned $? - see $seq.out.full" + echo "--------------------------------------" >>$here/$seq.out.full + echo "$_n - output from randholes:" >>$here/$seq.out.full + echo "--------------------------------------" >>$here/$seq.out.full + cat $tmp.out >>$here/$seq.out.full + echo "--------------------------------------" >>$here/$seq.out.full + echo "$_n - output from bmap:" >>$here/$seq.out.full + echo "--------------------------------------" >>$here/$seq.out.full + xfs_bmap -vvv $out >>$here/$seq.out.full + status=1 + fi +} + +# real QA test starts here + +rm -f $here/$seq.out.full + +_do_test 1 50 "-l 5000000 -c 50 -b 4096" +_do_test 2 100 "-l 10000000 -c 100 -b 4096" +_do_test 3 100 "-l 10000000 -c 100 -b 512" # test partial pages + +# success, all done +exit diff -rNu linux-2.4.7/cmd/xfstests/008.out linux-2.4-xfs/cmd/xfstests/008.out --- linux-2.4.7/cmd/xfstests/008.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/008.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,13 @@ +QA output created by 008 + +randholes.1 : -l 5000000 -c 50 -b 4096 +------------------------------------------ +holes is in range + +randholes.2 : -l 10000000 -c 100 -b 4096 +------------------------------------------ +holes is in range + +randholes.3 : -l 10000000 -c 100 -b 512 +------------------------------------------ +holes is in range diff -rNu linux-2.4.7/cmd/xfstests/009 linux-2.4-xfs/cmd/xfstests/009 --- linux-2.4.7/cmd/xfstests/009 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/009 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,197 @@ +#! /bin/sh +# XFS QA Test No. 009 +# $Id: 1.1 $ +# +# alloc test +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_cleanup() +{ + echo "*** unmount" + umount $SCRATCH_MNT +} + +_block_filter() +{ + sed -e 's/[0-9][0-9]*\.\.[0-9][0-9]*/BLOCKRANGE/g' +} + +_init() +{ + echo "*** mkfs" + if ! mkfs -t xfs -f $SCRATCH_DEV >$tmp.out 2>&1 + then + cat $tmp.out + echo "failed to mkfs $SCRATCH_DEV" + exit 1 + fi + + echo "*** mount" + if ! mount $SCRATCH_DEV $SCRATCH_MNT -t xfs + then + echo "failed to mount $SCRATCH_DEV" + exit 1 + fi +} + +_filesize() +{ + ls -l $1 | $AWK_PROG '{print "filesize = " $5}' +} + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# real QA test starts here + +_require_scratch + +_init +out=$SCRATCH_MNT/$$.tmp + +# since we're using a clean FS here, we make some assumptions +# about availability of contiguous blocks + +# also interesting to note is that ALLOC == FREE. seriously. +# the _length is ignored_ in irix. the file is allocated up +# to the specified offset, and zero filled if previously +# unallocated. the file is truncated at the specified point. + +echo "*** test 1 - reservations cleared on O_TRUNC" +rm -f $out +cat <" + if ! $here/src/dirstress -d $out -f $count $args >$tmp.out 2>&1 + then + echo " dirstress failed" + echo "*** TEST $test -d $out -f $count $args" >>$seq.out.full + cat $tmp.out >>$seq.out.full + status=1 + fi +} + +# dirstress doesn't check returns - this is a crash & burn test. + +count=1000 +_test 1 "-p 1 -n 1" $count +_test 2 "-p 5 -n 1" $count +_test 3 "-p 5 -n 5" $count + +# if error +exit diff -rNu linux-2.4.7/cmd/xfstests/011.out linux-2.4-xfs/cmd/xfstests/011.out --- linux-2.4.7/cmd/xfstests/011.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/011.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,4 @@ +QA output created by 011 +*** TEST 1 -p 1 -n 1 -f +*** TEST 2 -p 5 -n 1 -f +*** TEST 3 -p 5 -n 5 -f diff -rNu linux-2.4.7/cmd/xfstests/012 linux-2.4-xfs/cmd/xfstests/012 --- linux-2.4.7/cmd/xfstests/012 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/012 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,131 @@ +#! /bin/sh +# XFS QA Test No. 012 +# $Id: 1.1 $ +# +# holes +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "rm -f $tmp.*; _cleanup; exit \$status" 0 1 2 3 15 + +_cleanup() +{ + rm -rf $TEST_DIR/holes.$$.* +} + +_filesize() +{ + ls -l $1 | $AWK_PROG '{print " filesize = " $5}' +} + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_do_test() +{ + _n="$1" + _param="$2" + _count="$3" + + failed=0 + + out=$TEST_DIR/holes.$$.$_n + echo "" + echo "holes.$_n : $_param" + echo "-----------------------------------------------" + if ! $here/src/holes $_param $out >$tmp.out + then + echo " holes returned $? - see $seq.out.full" + failed=1 + status=1 + fi + + + if [ $failed -eq 0 ] + then + # quick check - how many holes did we get? + count=`xfs_bmap $out | egrep -c ': hole'` + echo " $count hole(s) detected" + # and how big was the file? + _filesize $out + + if [ $count -ne $_count ] + then + echo " unexpected number of holes - see $seq.out.full" + status=1 + failed=1 + fi + fi + + if [ $failed -eq 1 ] + then + echo "--------------------------------------" >>$here/$seq.out.full + echo "$_n - output from holes:" >>$here/$seq.out.full + echo "--------------------------------------" >>$here/$seq.out.full + cat $tmp.out >>$here/$seq.out.full + echo "--------------------------------------" >>$here/$seq.out.full + echo "$_n - output from bmap:" >>$here/$seq.out.full + echo "--------------------------------------" >>$here/$seq.out.full + xfs_bmap -vvv $out >>$here/$seq.out.full + echo "--------------------------------------" >>$here/$seq.out.full + echo "$_n - output from ls -li:" >>$here/$seq.out.full + echo "--------------------------------------" >>$here/$seq.out.full + ls -li $out >>$here/$seq.out.full + status=1 + fi +} + +# real QA test starts here + +rm -f $here/$seq.out.full + +# small & fairly dense +_do_test 1 "-l 40960000 -b 40960 -i 10 -c 1" 100 + +# big & sparse +_do_test 2 "-l 409600000 -b 40960 -i 1000 -c 1" 10 + +# no holes, but a very nasty way to write a file (lots of extents) +_do_test 3 "-l 40960000 -b 40960 -i 10 -c 10" 0 + +exit diff -rNu linux-2.4.7/cmd/xfstests/012.out linux-2.4-xfs/cmd/xfstests/012.out --- linux-2.4.7/cmd/xfstests/012.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/012.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,16 @@ +QA output created by 012 + +holes.1 : -l 40960000 -b 40960 -i 10 -c 1 +----------------------------------------------- + 100 hole(s) detected + filesize = 40960000 + +holes.2 : -l 409600000 -b 40960 -i 1000 -c 1 +----------------------------------------------- + 10 hole(s) detected + filesize = 409600000 + +holes.3 : -l 40960000 -b 40960 -i 10 -c 10 +----------------------------------------------- + 0 hole(s) detected + filesize = 40960000 diff -rNu linux-2.4.7/cmd/xfstests/013 linux-2.4-xfs/cmd/xfstests/013 --- linux-2.4.7/cmd/xfstests/013 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/013 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,141 @@ +#! /bin/sh +# XFS QA Test No. 013 +# $Id: 1.1 $ +# +# fsstress +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_cleanup() +{ + # we might get here with a RO FS + mount -o remount,rw $TEST_DEV >/dev/null 2>&1 + # now kill! + rm -rf $TEST_DIR/fsstress.$$.* +} + +_filesize() +{ + ls -l $1 | $AWK_PROG '{print " filesize = " $5}' +} + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_do_test() +{ + _n="$1" + _param="$2" + _count="$3" + + failed=0 + + out=$TEST_DIR/fsstress.$$.$_n + rm -rf $out + if ! mkdir $out + then + echo " failed to mkdir $out" + status=1 + exit + fi + + echo "" + echo "-----------------------------------------------" + echo "fsstress.$_n : $_param" + echo "-----------------------------------------------" + # -v >$tmp.out + if ! $here/src/fsstress $_param $FSSTRESS_AVOID -n $_count -d $out >/dev/null 2>&1 + then + echo " fsstress (count=$_count) returned $? - see $seq.full" + + echo "--------------------------------------" >>$here/$seq.full + echo "$_n - output from fsstress:" >>$here/$seq.full + echo "--------------------------------------" >>$here/$seq.full + echo "" >>$here/$seq.full + #cat $tmp.out >>$here/$seq.full + status=1 + fi + + _check_fs $TEST_DEV +} + + +# real QA test starts here + +rm -f $here/$seq.full +echo "berevity is wit..." + +count=1000 + +_check_fs $TEST_DEV + +# the default + +_do_test 1 "-r" $count + +# and the default with multiprocess + +_do_test 2 "-p 5 -r" $count + +# from Glen's notes + +_do_test 3 "-p 4 -z -f rmdir=10 -f link=10 -f creat=10 -f mkdir=10 -f rename=30 -f stat=30 -f unlink=30 -f truncate=20" $count + +exit + +# Test with error injection: +# +# (error injection) +# fsstress -n 1000 -d $scratch -p 4 -z -f rmdir=10 -f link=10 -f creat=10 \ +# -f mkdir=10 -f rename=30 -f stat=30 -f unlink=30 -f truncate=20 \ +# -e 1 +# +# Error values 1 - 6 test IFLUSH +# 1 - corrupt buffer being flushed to di_core.di_magic +# 2 - corrupt inode being flushed i_d.di_magic +# 3 - corrupt IFREG format check +# 4 - corrupt IFDIR format check +# 5 - corrupt i_d.di_nextents +# 6 - corrupt i_d.di_forkoff > sb_inodesize diff -rNu linux-2.4.7/cmd/xfstests/013.out linux-2.4-xfs/cmd/xfstests/013.out --- linux-2.4.7/cmd/xfstests/013.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/013.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,14 @@ +QA output created by 013 +berevity is wit... + +----------------------------------------------- +fsstress.1 : -r +----------------------------------------------- + +----------------------------------------------- +fsstress.2 : -p 5 -r +----------------------------------------------- + +----------------------------------------------- +fsstress.3 : -p 4 -z -f rmdir=10 -f link=10 -f creat=10 -f mkdir=10 -f rename=30 -f stat=30 -f unlink=30 -f truncate=20 +----------------------------------------------- diff -rNu linux-2.4.7/cmd/xfstests/014 linux-2.4-xfs/cmd/xfstests/014 --- linux-2.4.7/cmd/xfstests/014 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/014 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,73 @@ +#! /bin/sh +# XFS QA Test No. 014 +# $Id: 1.1 $ +# +# truncfile +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "rm -f $tmp.*; _cleanup; exit \$status" 0 1 2 3 15 + +_cleanup() +{ + rm -rf $TEST_DIR/truncfile.$$.* +} + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + + +echo "berevity is wit..." + +echo "------" +echo "test 1" +echo "------" +if ! src/truncfile -c 10000 $TEST_DIR/truncfile.$$.0 >$tmp.out 2>&1 +then + out=`cat $tmp.out` + echo "truncfile returned $? : \"$out\"" +else + echo "OK" +fi + +exit diff -rNu linux-2.4.7/cmd/xfstests/014.out linux-2.4-xfs/cmd/xfstests/014.out --- linux-2.4.7/cmd/xfstests/014.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/014.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,6 @@ +QA output created by 014 +berevity is wit... +------ +test 1 +------ +OK diff -rNu linux-2.4.7/cmd/xfstests/015 linux-2.4-xfs/cmd/xfstests/015 --- linux-2.4.7/cmd/xfstests/015 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/015 Mon May 14 18:31:15 2001 @@ -0,0 +1,148 @@ +#! /bin/sh +# XFS QA Test No. 015 +# $Id: 1.1 $ +# +# check out-of-space behaviour +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # success is the default! + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_cleanup() +{ + umount $SCRATCH_MNT +} + +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_free() +{ + _df_dir $SCRATCH_MNT | $AWK_PROG '{ print $5 }' +} + +_filter_dd() +{ + $AWK_PROG ' + /records in/ { next } + /records out/ { next } + /No space left on device/ { print " !!! disk full (expected)" + next } + { print " *** " $0 } + ' +} + +# real QA test starts here +_require_scratch + +mkfs -t xfs -f -d size=50m $SCRATCH_DEV >/dev/null +mount -t xfs $SCRATCH_DEV $SCRATCH_MNT +out=$SCRATCH_MNT/fillup.$$ +rm -f $seq.full + +free0=`_free` +if [ -z "$free0" ] +then + echo " *** failed to get free space (0)" + exit 1 +fi +echo "free space at start $free0" >> $seq.full + +echo "fill disk:" # well, filesystem really - not disk + +dd if=/dev/zero of=$out bs=1024k 2>&1 | _filter_dd + +echo "check free space:" + +free1=`_free` +if [ -z "$free1" ] +then + echo " *** failed to get free space (1)" + exit 1 +fi +echo "free space after fill $free1" >> $seq.full + +if [ ! -e $out ] +then + echo " *** file not created" + exit 1 +fi + +if [ ! -s $out ] +then + echo " *** file created with zero length" + ls -l $out + exit 1 +fi + +echo "delete fill:" + +if ! rm $out +then + echo " *** file not deleted" + exit 1 +fi + +if [ -e $out ] +then + echo " *** file still exists" + ls -l $out + exit 1 +fi + +echo "check free space:" + +free2=`_free` +if [ -z "$free2" ] +then + echo " *** failed to get free space (2)" + exit 1 +fi +echo "free space after delete $free2" >> $seq.full + +echo -n " !!! " +_within_tolerance "free space" $free2 $free0 1% -v + +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/015.out linux-2.4-xfs/cmd/xfstests/015.out --- linux-2.4.7/cmd/xfstests/015.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/015.out Mon May 14 18:31:15 2001 @@ -0,0 +1,7 @@ +QA output created by 015 +fill disk: + !!! disk full (expected) +check free space: +delete fill: +check free space: + !!! free space is in range diff -rNu linux-2.4.7/cmd/xfstests/016 linux-2.4-xfs/cmd/xfstests/016 --- linux-2.4.7/cmd/xfstests/016 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/016 Mon Apr 23 02:37:39 2001 @@ -0,0 +1,208 @@ +#! /bin/sh +# XFS QA Test No. 016 +# $Id: 1.1 $ +# +# test end of log overwrite bug #796141 +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +# +# pv 796141 +# +# create a new FS, mostly fill the log. Then wrap the log back to the +# start bit by bit to force wiping of stale blocks near the end of the +# log. Check the block after the log ends to check for corruption +# +# assumptions : +# - given we're only touching a single inode, the block after the +# log which is in the middle ag should never be touched. +# if it changes, we assume the log is writing over it +# + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 + +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_cleanup() +{ + echo "*** unmount" + umount $SCRATCH_MNT 2>/dev/null +} + +_block_filter() +{ + sed -e 's/[0-9][0-9]*\.\.[0-9][0-9]*/BLOCKRANGE/g' +} + +_init() +{ + echo "*** reset partition" + $here/src/devzero -b 2048 -n 50 -v 198 $SCRATCH_DEV + echo "*** mkfs" + if ! mkfs -t xfs -f -d size=50m -l size=512b $SCRATCH_DEV >$tmp.out 2>&1 + then + cat $tmp.out + echo "failed to mkfs $SCRATCH_DEV" + exit 1 + fi +} + +_log_traffic() +{ + count=$1 + echo "*** generate log traffic" + + out=$SCRATCH_MNT/$$.tmp + + echo " *** mount" + if ! mount $SCRATCH_DEV $SCRATCH_MNT -t xfs + then + echo "failed to mount $SCRATCH_DEV" + exit 1 + fi + + # having any quota enabled (acct/enfd) means extra log traffic - evil! + $here/src/feature -U $SCRATCH_DEV && \ + _notrun "Quota are enabled, test needs controlled log traffic" + $here/src/feature -G $SCRATCH_DEV && \ + _notrun "Quota are enabled, test needs controlled log traffic" + + echo " *** fiddle" + while [ $count -ge 0 ] + do + touch $out + rm $out + let "count = count - 1" + done + + echo " *** unmount" + if ! umount $SCRATCH_DEV + then + echo "failed to unmount $SCRATCH_DEV" + exit 1 + fi +} + +_log_size() +{ + xfs_logprint -tb $SCRATCH_DEV | $AWK_PROG ' + /log device/ { print $7} + ' +} + +_log_head() +{ + xfs_logprint -tb $SCRATCH_DEV | $AWK_PROG ' + /head:/ { print $5 } + ' +} + +_after_log() +{ + xfs_db -r $1 -c "sb" -c "print" | $AWK_PROG ' + /logstart/ { logstart = $3 } + /logblocks/ { logblocks = $3 } + END { + print logstart + logblocks + } + ' +} + +_check_corrupt() +{ + f="c6c6c6c6" + echo "*** check for corruption" + echo "expect $f..." >>$seq.full + xfs_db -r $1 -c "fsblock $2" -c "print" | head | tee -a $seq.full | \ + grep -q -v "$f $f $f $f $f $f $f $f" && \ + _fail "!!! block $2 corrupted!" +} + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# real QA test starts here + +rm -f $seq.full + +_require_scratch +_init + +block=`_after_log $SCRATCH_DEV` +echo "fsblock after log = $block" >>$seq.full +_check_corrupt $SCRATCH_DEV $block + +size=`_log_size` +echo "log size = $size BB" >>$seq.full +head=`_log_head` +echo "log position = $head" >>$seq.full + +[ $size -eq 4096 ] || \ + _fail "!!! unexpected log size $size" +[ $head -eq 2 ] || \ + _fail "!!! unexpected initial log position $head" + +echo " lots of traffic" >>$seq.full +_log_traffic 850 +head=`_log_head` +echo "log position = $head" >>$seq.full + +[ $head -gt 3850 -a $head -lt 4050 ] || \ + _fail "!!! unexpected log position $head" + +for c in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +do + echo " little traffic" >>$seq.full + _log_traffic 2 + head=`_log_head` + echo "log position = $head" >>$seq.full + _check_corrupt $SCRATCH_DEV $block +done + +[ $head -lt 1000 ] || \ + _fail "!!! unexpected log position $head" + + +# happy exit +rm $seq.full +status=0 +exit 0 diff -rNu linux-2.4.7/cmd/xfstests/016.out linux-2.4-xfs/cmd/xfstests/016.out --- linux-2.4.7/cmd/xfstests/016.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/016.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,115 @@ +QA output created by 016 +*** reset partition +Wrote 51200.00Kb (value 0xc6) +*** mkfs +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** generate log traffic + *** mount + *** fiddle + *** unmount +*** check for corruption +*** unmount diff -rNu linux-2.4.7/cmd/xfstests/017 linux-2.4-xfs/cmd/xfstests/017 --- linux-2.4.7/cmd/xfstests/017 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/017 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,109 @@ +#! /bin/sh +# XFS QA Test No. 017 +# $Id: 1.1 $ +# +# test remount ro - pv 795642 +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 + +_cleanup() +{ + echo "*** unmount" + umount $SCRATCH_MNT 2>/dev/null +} +trap "_cleanup; rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +_clean_log() +{ + echo "" >>$seq.full + echo "*** xfs_logprint ***" >>$seq.full + echo "" >>$seq.full + xfs_logprint -tb $1 | tee -a $seq.full \ + | head | grep -q "" || _fail "DIRTY LOG" +} + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# real QA test starts here + +_require_scratch + +echo "*** init FS" + +rm -f $seq.full +umount $SCRATCH_DEV >/dev/null 2>&1 +echo "*** MKFS ***" >>$seq.full +echo "" >>$seq.full +mkfs -t xfs -f $SCRATCH_DEV >>$seq.full 2>&1 \ + || _fail "mkfs failed" +mount -t xfs $SCRATCH_DEV $SCRATCH_MNT >>$seq.full 2>&1 \ + || _fail "mount failed" + +echo "*** test" + +for l in 0 1 2 3 4 +do + echo " *** test $l" + src/fsstress -d $SCRATCH_MNT -n 1000 $FSSTRESS_AVOID >>$seq.full + + mount -o remount,ro $SCRATCH_DEV \ + || _fail "remount ro failed" + + _clean_log $SCRATCH_DEV + + echo "" >>$seq.full + echo "*** XFS_CHECK ***" >>$seq.full + echo "" >>$seq.full + xfs_check $SCRATCH_DEV >>$seq.full 2>&1 \ + || _fail "xfs_check failed" + mount -o remount,rw $SCRATCH_DEV \ + || _fail "remount rw failed" +done + +echo "*** done" +# happy exit +rm -f $seq.full +status=0 +exit 0 diff -rNu linux-2.4.7/cmd/xfstests/017.out linux-2.4-xfs/cmd/xfstests/017.out --- linux-2.4.7/cmd/xfstests/017.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/017.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,10 @@ +QA output created by 017 +*** init FS +*** test + *** test 0 + *** test 1 + *** test 2 + *** test 3 + *** test 4 +*** done +*** unmount diff -rNu linux-2.4.7/cmd/xfstests/018 linux-2.4-xfs/cmd/xfstests/018 --- linux-2.4.7/cmd/xfstests/018 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/018 Tue May 22 01:07:23 2001 @@ -0,0 +1,146 @@ +#! /bin/sh +# XFS QA Test No. 018 +# $Id: 1.1 $ +# +# xfs_logprint test +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_cleanup() +{ + echo "*** unmount" + umount $SCRATCH_MNT 2>/dev/null +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_full() +{ + echo "" >>$seq.full + echo "*** $* ***" >>$seq.full + echo "" >>$seq.full +} + +_clean_log() +{ + _full "clean_log : xfs_logprint" + xfs_logprint -t $1 | tee -a $seq.full \ + | head | grep -q "" || _fail "DIRTY LOG" +} + +_filter_logprint() +{ + sed ' + s/data device: 0x[0-9a-f][0-9a-f]*/data device: /; + s/log device: 0x[0-9a-f][0-9a-f]*/log device: /; + s/daddr: [0-9][0-9]*/daddr: /; + s/length: [0-9][0-9]*/length: /; + s/length: [0-9][0-9]*/length: /; + s/^cycle num overwrites: .*$/cycle num overwrites: /; + s/tid: [0-9a-f][0-9a-f]*/tid: /; + s/tid:0x[0-9a-f][0-9a-f]*/tid:/; + s/q:0x[0-9a-f][0-9a-f]*/q:/; + s/a:0x[0-9a-f][0-9a-f]*/a:/g; + s/blkno:0x[0-9a-f][0-9a-f]*/blkno:/g; + s/blkno: [0-9][0-9]* (0x[0-9a-f]*)/blkno: ()/g; + s/blkno: [0-9][0-9]*/blkno: /g; + s/boff: [0-9][0-9]*/boff: /g; + s/len: *[0-9][0-9]*/len:/g; + s/skipped [0-9][0-9]* zeroed blocks/skipped zeroed blocks/; + s/atime:[0-9a-fx]* *mtime:[0-9a-fx]* *ctime:[0-9a-fx]*/atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x83 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x8000 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:QM_DQALLOC #items:6 trans:0x0 q: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x83 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x8000 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + +LOG REC AT LSN cycle 1 block (0x1, 0xf) +============================================================================ +TRANS: tid: type:QM_SBCHANGE #items:1 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x84 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x85 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:24 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x86 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:36 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x87 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:44 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x88 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:52 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x89 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:60 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8a flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:72 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8b flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:80 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8c flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:88 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8d flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:96 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8e flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:108 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8f flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:116 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x90 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:124 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x91 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:132 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x92 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:144 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x93 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:152 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:10 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x94 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x95 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x96 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x97 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x98 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x4f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x99 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9a flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9b flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9c flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9d flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9e flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9f flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa0 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa1 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa2 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa3 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa4 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa5 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa6 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x8f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa7 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa8 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa9 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaa flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xab flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xac flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xad flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xae flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaf flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb0 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb1 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb2 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb3 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0xcf) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb4 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb5 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb6 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb7 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb8 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb9 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xba flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbb flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbc flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbd flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbe flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbf flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x10f) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe0 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe1 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe2 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe3 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe4 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe5 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe6 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x14f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe7 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe8 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe9 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xea flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xeb flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xec flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xed flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xee flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xef flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf0 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x18f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf1 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf2 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf3 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf4 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf5 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf6 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf7 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf8 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf9 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x1cf) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfa flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfb flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfc flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfd flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfe flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xff flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x100 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x101 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x102 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x20f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x103 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x104 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x105 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x106 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x107 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x236) +### xfs_logprint -t -b -s 0 output ### +xfs_logprint: + data device: + log device: daddr: length: + + log tail: 568 head: 568 state: + override tail: 0 + + +LOG REC AT LSN cycle 1 block (0x1, 0x0) + +LOG REC AT LSN cycle 1 block (0x1, 0x2) +============================================================================ +TRANS: tid: type:QM_QINOCREATE #items:4 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3c newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x83 flags:0x1 dsize:0 + CORE inode: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:QM_DQALLOC #items:6 trans:0x0 q: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x83 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) + ver:1 seq#:0 len: + root BNO:1 CNT:2 + level BNO:1 CNT:1 + 1st: last: cnt: freeblks: longest: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: + +LOG REC AT LSN cycle 1 block (0x1, 0xf) +============================================================================ +TRANS: tid: type:QM_SBCHANGE #items:1 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3b newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x84 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:16 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3a newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x85 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:24 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x39 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x86 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:36 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x38 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x87 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:44 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x37 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x88 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:52 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x36 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x89 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:60 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x35 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8a flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:72 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x34 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8b flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:80 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x33 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8c flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:88 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x32 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8d flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:96 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x31 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8e flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:108 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x30 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8f flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:116 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2f newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x90 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:124 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2e newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x91 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:132 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2d newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x92 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:144 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2c newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x93 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:152 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:10 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2b newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x94 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) + ver:1 seq#:0 len: + root BNO:1 CNT:2 + level BNO:1 CNT:1 + 1st: last: cnt: freeblks: longest: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2a newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x95 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x29 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x96 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x28 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x97 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x27 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x98 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x4f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x26 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x99 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x25 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9a flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x24 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9b flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x23 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9c flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x22 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9d flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x21 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9e flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x20 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9f flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1f newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa0 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1e newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa1 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1d newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa2 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1c newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa3 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1b newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa4 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1a newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa5 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x19 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa6 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x8f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x18 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa7 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x17 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa8 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x16 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa9 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x15 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaa flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x14 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xab flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x13 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xac flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x12 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xad flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x11 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xae flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x10 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaf flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xf newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb0 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xe newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb1 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xd newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb2 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xc newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb3 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0xcf) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xb newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb4 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xa newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb5 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x9 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb6 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x8 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb7 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x7 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb8 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x6 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb9 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x5 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xba flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x4 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbb flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbc flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbd flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbe flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x0 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbf flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x10f) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x40 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) + ver:1 seq#:0 len: + root BNO:1 CNT:2 + level BNO:1 CNT:1 + 1st: last: cnt: freeblks: longest: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3f newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe0 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3e newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe1 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3d newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe2 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3c newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe3 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3b newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe4 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3a newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe5 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x39 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe6 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x14f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x38 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe7 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x37 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe8 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x36 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe9 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x35 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xea flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x34 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xeb flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x33 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xec flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x32 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xed flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x31 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xee flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x30 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xef flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2f newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf0 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x18f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2e newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf1 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2d newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf2 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2c newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf3 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2b newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf4 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2a newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf5 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x29 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf6 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x28 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf7 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x27 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf8 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x26 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf9 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x1cf) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x25 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfa flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x24 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfb flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x23 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfc flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x22 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfd flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x21 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfe flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x20 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xff flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1f newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x100 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1e newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x101 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1d newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x102 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x20f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1c newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x103 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1b newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x104 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1a newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x105 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x19 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x106 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x18 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x107 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x236) +*** unmount diff -rNu linux-2.4.7/cmd/xfstests/018.noquota linux-2.4-xfs/cmd/xfstests/018.noquota --- linux-2.4.7/cmd/xfstests/018.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/018.noquota Mon Apr 23 02:37:39 2001 @@ -0,0 +1,12503 @@ +QA output created by 018 +*** init FS +### xfs_logprint output ### +xfs_logprint: + data device: + log device: daddr: length: + +cycle: 1 version: 1 lsn: 1,0 tail_lsn: 1,0 +length of Log Record: 20 prev offset: -1 num ops: 1 +uuid: format: +---------------------------------------------------------------------------- +Oper (0): tid: len: clientid: LOG flags: UNMOUNT +Unmount filesystem + +============================================================================ +cycle: 1 version: 1 lsn: 1,2 tail_lsn: 1,2 +length of Log Record: 32256 prev offset: 0 num ops: 380 +uuid: format: +---------------------------------------------------------------------------- +Oper (0): tid: len: clientid: TRANS flags: START +---------------------------------------------------------------------------- +Oper (1): tid: len: clientid: TRANS flags: none +TRAN: type: CREATE tid: num_items: 5 +---------------------------------------------------------------------------- +Oper (2): tid: len: clientid: TRANS flags: none +BUF: #regs: 2 start blkno: () len: bmap size: 1 +Oper (3): tid: len: clientid: TRANS flags: none +AGI Buffer: XAGI +ver: 1 seq#: 0 len: cnt: 64 root: 3 +level: 1 free#: 0x3c newino: 0x80 +bucket[0 - 3]: 0xffffffff 0xffffffff 0xffffffff 0xffffffff +bucket[4 - 7]: 0xffffffff 0xffffffff 0xffffffff 0xffffffff +bucket[8 - 11]: 0xffffffff 0xffffffff 0xffffffff 0xffffffff +bucket[12 - 15]: 0xffffffff 0xffffffff 0xffffffff 0xffffffff +bucket[16 - 19]: 0xffffffff +---------------------------------------------------------------------------- +Oper (4): tid: len: clientid: TRANS flags: none +BUF: #regs: 2 start blkno: () len: bmap size: 2 +Oper (5): tid: len: clientid: TRANS flags: none +BUF DATA +---------------------------------------------------------------------------- +Oper (6): tid: len: clientid: TRANS flags: none +INODE: #regs: 2 ino: 0x83 flags: 0x1 dsize: 0 + blkno: len: boff: +Oper (7): tid: len: clientid: TRANS flags: none +INODE CORE +magic 0x494e mode 0100644 version 1 format 2 +nlink 1 uid 0 gid 0 +atime len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x83 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x84 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:24 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x85 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:36 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x86 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:44 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x87 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:52 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x88 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:60 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x89 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:72 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8a flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:80 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8b flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:88 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8c flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:96 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8d flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:108 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8e flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:116 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8f flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:124 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x90 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:132 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x91 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:144 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x92 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:152 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:9 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x93 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x94 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x95 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x96 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x97 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x98 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x99 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9a flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + +LOG REC AT LSN cycle 1 block (0x1, 0x42) +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9b flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9c flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9d flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9e flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9f flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa0 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa1 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa2 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa3 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa4 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa5 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa6 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa7 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa8 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa9 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaa flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + +LOG REC AT LSN cycle 1 block (0x1, 0x82) +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xab flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xac flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xad flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xae flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaf flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb0 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb1 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb2 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb3 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb4 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb5 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb6 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb7 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb8 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + +LOG REC AT LSN cycle 1 block (0x1, 0xc2) +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb9 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xba flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbb flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbc flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbd flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbe flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbf flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe0 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + +LOG REC AT LSN cycle 1 block (0x1, 0x102) +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe1 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe2 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe3 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe4 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe5 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe6 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe7 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe8 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe9 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xea flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xeb flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + +LOG REC AT LSN cycle 1 block (0x1, 0x142) +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xec flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xed flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xee flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xef flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf0 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf1 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf2 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf3 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf4 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf5 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf6 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + +LOG REC AT LSN cycle 1 block (0x1, 0x182) +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf7 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf8 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf9 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfa flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfb flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfc flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfd flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfe flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xff flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + +LOG REC AT LSN cycle 1 block (0x1, 0x1c2) +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x100 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x101 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x102 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x103 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x104 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x105 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x106 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + +LOG REC AT LSN cycle 1 block (0x1, 0x1f0) +### xfs_logprint -t -b -s 0 output ### +xfs_logprint: + data device: + log device: daddr: length: + + log tail: 498 head: 498 state: + override tail: 0 + + +LOG REC AT LSN cycle 1 block (0x1, 0x0) + +LOG REC AT LSN cycle 1 block (0x1, 0x2) +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3c newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x83 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:16 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3b newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x84 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:24 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3a newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x85 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:36 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x39 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x86 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:44 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x38 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x87 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:52 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x37 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x88 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:60 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x36 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x89 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:72 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x35 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8a flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:80 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x34 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8b flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:88 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x33 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8c flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:96 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x32 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8d flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:108 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x31 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8e flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:116 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x30 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8f flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:124 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2f newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x90 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:132 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2e newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x91 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:144 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:5 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2d newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x92 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:152 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:9 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2c newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x93 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) + ver:1 seq#:0 len: + root BNO:1 CNT:2 + level BNO:1 CNT:1 + 1st: last: cnt: freeblks: longest: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2b newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x94 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2a newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x95 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x29 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x96 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x28 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x97 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x27 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x98 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x26 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x99 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x25 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9a flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: + +LOG REC AT LSN cycle 1 block (0x1, 0x42) +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x24 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9b flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x23 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9c flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x22 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9d flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x21 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9e flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x20 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9f flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1f newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa0 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1e newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa1 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1d newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa2 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1c newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa3 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1b newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa4 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1a newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa5 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x19 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa6 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x18 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa7 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x17 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa8 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x16 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa9 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x15 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaa flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: + +LOG REC AT LSN cycle 1 block (0x1, 0x82) +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x14 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xab flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x13 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xac flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x12 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xad flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x11 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xae flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x10 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaf flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xf newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb0 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xe newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb1 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xd newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb2 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xc newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb3 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xb newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb4 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xa newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb5 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x9 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb6 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x8 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb7 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x7 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb8 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: + +LOG REC AT LSN cycle 1 block (0x1, 0xc2) +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x6 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb9 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x5 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xba flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x4 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbb flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbc flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbd flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbe flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x0 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbf flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x40 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) + ver:1 seq#:0 len: + root BNO:1 CNT:2 + level BNO:1 CNT:1 + 1st: last: cnt: freeblks: longest: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3f newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe0 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: + +LOG REC AT LSN cycle 1 block (0x1, 0x102) +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3e newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe1 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3d newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe2 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3c newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe3 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3b newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe4 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3a newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe5 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x39 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe6 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x38 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe7 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x37 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe8 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x36 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe9 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x35 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xea flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x34 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xeb flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: + +LOG REC AT LSN cycle 1 block (0x1, 0x142) +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x33 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xec flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x32 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xed flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x31 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xee flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x30 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xef flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2f newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf0 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2e newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf1 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2d newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf2 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2c newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf3 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2b newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf4 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2a newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf5 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x29 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf6 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: + +LOG REC AT LSN cycle 1 block (0x1, 0x182) +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x28 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf7 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x27 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf8 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x26 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf9 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x25 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfa flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x24 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfb flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x23 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfc flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x22 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfd flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x21 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfe flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x20 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xff flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: + +LOG REC AT LSN cycle 1 block (0x1, 0x1c2) +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1f newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x100 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1e newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x101 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1d newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x102 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1c newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x103 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1b newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x104 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1a newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x105 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x19 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x106 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: + +LOG REC AT LSN cycle 1 block (0x1, 0x1f0) +*** unmount diff -rNu linux-2.4.7/cmd/xfstests/018.ugquota linux-2.4-xfs/cmd/xfstests/018.ugquota --- linux-2.4.7/cmd/xfstests/018.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/018.ugquota Mon Apr 23 02:37:39 2001 @@ -0,0 +1,14644 @@ +QA output created by 018 +*** init FS +### xfs_logprint output ### +xfs_logprint: + data device: + log device: daddr: length: + +cycle: 1 version: 1 lsn: 1,0 tail_lsn: 1,0 +length of Log Record: 20 prev offset: -1 num ops: 1 +uuid: format: +---------------------------------------------------------------------------- +Oper (0): tid: len: clientid: LOG flags: UNMOUNT +Unmount filesystem + +============================================================================ +cycle: 1 version: 1 lsn: 1,2 tail_lsn: 1,2 +length of Log Record: 12248 prev offset: 0 num ops: 54 +uuid: format: +---------------------------------------------------------------------------- +Oper (0): tid: len: clientid: TRANS flags: START +---------------------------------------------------------------------------- +Oper (1): tid: len: clientid: TRANS flags: none +TRAN: type: QM_QINOCREATE tid: num_items: 4 +---------------------------------------------------------------------------- +Oper (2): tid: len: clientid: TRANS flags: none +BUF: #regs: 2 start blkno: () len: bmap size: 1 +Oper (3): tid: len: clientid: TRANS flags: none +AGI Buffer: XAGI +ver: 1 seq#: 0 len: cnt: 64 root: 3 +level: 1 free#: 0x3c newino: 0x80 +bucket[0 - 3]: 0xffffffff 0xffffffff 0xffffffff 0xffffffff +bucket[4 - 7]: 0xffffffff 0xffffffff 0xffffffff 0xffffffff +bucket[8 - 11]: 0xffffffff 0xffffffff 0xffffffff 0xffffffff +bucket[12 - 15]: 0xffffffff 0xffffffff 0xffffffff 0xffffffff +bucket[16 - 19]: 0xffffffff +---------------------------------------------------------------------------- +Oper (4): tid: len: clientid: TRANS flags: none +BUF: #regs: 2 start blkno: () len: bmap size: 2 +Oper (5): tid: len: clientid: TRANS flags: none +BUF DATA +---------------------------------------------------------------------------- +Oper (6): tid: len: clientid: TRANS flags: none +INODE: #regs: 2 ino: 0x83 flags: 0x1 dsize: 0 + blkno: len: boff: +Oper (7): tid: len: clientid: TRANS flags: none +INODE CORE +magic 0x494e mode 0100000 version 1 format 2 +nlink 1 uid 0 gid 0 +atime len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x83 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x8000 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:QM_QINOCREATE #items:4 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x84 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x8000 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:QM_DQALLOC #items:6 trans:0x0 q: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x83 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x8000 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:QM_DQALLOC #items:6 trans:0x0 q: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x84 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x8000 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + +LOG REC AT LSN cycle 1 block (0x1, 0x1b) +============================================================================ +TRANS: tid: type:QM_SBCHANGE #items:1 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x85 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x86 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:24 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x87 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:36 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x88 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:44 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x89 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:52 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8a flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:60 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8b flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:72 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8c flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:80 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8d flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:88 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8e flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:96 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8f flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:108 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x90 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:116 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x91 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:124 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x92 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:132 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x93 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:144 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x94 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:152 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:11 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x95 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x96 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x97 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x5b) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x98 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x99 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9a flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9b flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9c flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9d flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9e flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9f flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa0 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa1 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa2 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa3 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa4 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa5 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x9b) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa6 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa7 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa8 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa9 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaa flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xab flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xac flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xad flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xae flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaf flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb0 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb1 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb2 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0xdb) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb3 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb4 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb5 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb6 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb7 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb8 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb9 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xba flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbb flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbc flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbd flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x11b) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbe flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbf flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x100 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x101 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x102 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x103 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x104 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x15b) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x105 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x106 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x107 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x108 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x109 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x10a flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x10b flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x10c flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x10d flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x19b) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x10e flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x10f flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x110 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x111 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x112 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x113 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x114 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x115 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x116 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x1db) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x117 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x118 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x119 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x11a flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x11b flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x11c flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x11d flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x11e flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x11f flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x21b) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x120 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x121 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x122 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x123 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x124 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x125 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x126 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x127 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x25b) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x128 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x260) +### xfs_logprint -t -b -s 0 output ### +xfs_logprint: + data device: + log device: daddr: length: + + log tail: 610 head: 610 state: + override tail: 0 + + +LOG REC AT LSN cycle 1 block (0x1, 0x0) + +LOG REC AT LSN cycle 1 block (0x1, 0x2) +============================================================================ +TRANS: tid: type:QM_QINOCREATE #items:4 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3c newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x83 flags:0x1 dsize:0 + CORE inode: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:QM_QINOCREATE #items:4 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3b newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x84 flags:0x1 dsize:0 + CORE inode: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:QM_DQALLOC #items:6 trans:0x0 q: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x83 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) + ver:1 seq#:0 len: + root BNO:1 CNT:2 + level BNO:1 CNT:1 + 1st: last: cnt: freeblks: longest: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:QM_DQALLOC #items:6 trans:0x0 q: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x84 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) + ver:1 seq#:0 len: + root BNO:1 CNT:2 + level BNO:1 CNT:1 + 1st: last: cnt: freeblks: longest: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: + +LOG REC AT LSN cycle 1 block (0x1, 0x1b) +============================================================================ +TRANS: tid: type:QM_SBCHANGE #items:1 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3a newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x85 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:16 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x39 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x86 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:24 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x38 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x87 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:36 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x37 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x88 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:44 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x36 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x89 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:52 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x35 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8a flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:60 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x34 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8b flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:72 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x33 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8c flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:80 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x32 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8d flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:88 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x31 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8e flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:96 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x30 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8f flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:108 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2f newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x90 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:116 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2e newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x91 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:124 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2d newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x92 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:132 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2c newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x93 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:144 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2b newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x94 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:152 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:11 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2a newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x95 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) + ver:1 seq#:0 len: + root BNO:1 CNT:2 + level BNO:1 CNT:1 + 1st: last: cnt: freeblks: longest: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x29 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x96 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x28 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x97 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x5b) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x27 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x98 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x26 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x99 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x25 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9a flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x24 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9b flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x23 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9c flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x22 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9d flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x21 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9e flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x20 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9f flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1f newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa0 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1e newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa1 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1d newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa2 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1c newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa3 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1b newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa4 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1a newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa5 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x9b) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x19 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa6 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x18 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa7 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x17 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa8 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x16 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa9 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x15 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaa flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x14 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xab flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x13 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xac flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x12 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xad flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x11 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xae flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x10 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaf flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xf newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb0 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xe newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb1 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xd newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb2 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0xdb) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xc newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb3 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xb newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb4 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xa newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb5 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x9 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb6 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x8 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb7 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x7 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb8 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x6 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb9 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x5 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xba flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x4 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbb flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbc flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbd flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x11b) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbe flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x0 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbf flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x40 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) + ver:1 seq#:0 len: + root BNO:1 CNT:2 + level BNO:1 CNT:1 + 1st: last: cnt: freeblks: longest: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3f newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x100 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3e newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x101 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3d newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x102 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3c newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x103 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3b newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x104 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x15b) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3a newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x105 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x39 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x106 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x38 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x107 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x37 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x108 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x36 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x109 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x35 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x10a flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x34 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x10b flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x33 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x10c flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x32 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x10d flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x19b) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x31 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x10e flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x30 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x10f flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2f newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x110 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2e newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x111 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2d newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x112 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2c newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x113 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2b newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x114 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2a newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x115 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x29 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x116 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x1db) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x28 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x117 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x27 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x118 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x26 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x119 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x25 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x11a flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x24 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x11b flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x23 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x11c flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x22 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x11d flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x21 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x11e flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x20 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x11f flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x21b) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1f newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x120 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1e newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x121 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1d newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x122 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1c newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x123 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1b newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x124 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1a newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x125 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x19 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x126 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x18 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x127 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x25b) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x17 newino:0x100 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x128 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:104 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x260) +*** unmount diff -rNu linux-2.4.7/cmd/xfstests/018.usrquota linux-2.4-xfs/cmd/xfstests/018.usrquota --- linux-2.4.7/cmd/xfstests/018.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/018.usrquota Mon Apr 23 02:37:39 2001 @@ -0,0 +1,13541 @@ +QA output created by 018 +*** init FS +### xfs_logprint output ### +xfs_logprint: + data device: + log device: daddr: length: + +cycle: 1 version: 1 lsn: 1,0 tail_lsn: 1,0 +length of Log Record: 20 prev offset: -1 num ops: 1 +uuid: format: +---------------------------------------------------------------------------- +Oper (0): tid: len: clientid: LOG flags: UNMOUNT +Unmount filesystem + +============================================================================ +cycle: 1 version: 1 lsn: 1,2 tail_lsn: 1,2 +length of Log Record: 6124 prev offset: 0 num ops: 27 +uuid: format: +---------------------------------------------------------------------------- +Oper (0): tid: len: clientid: TRANS flags: START +---------------------------------------------------------------------------- +Oper (1): tid: len: clientid: TRANS flags: none +TRAN: type: QM_QINOCREATE tid: num_items: 4 +---------------------------------------------------------------------------- +Oper (2): tid: len: clientid: TRANS flags: none +BUF: #regs: 2 start blkno: () len: bmap size: 1 +Oper (3): tid: len: clientid: TRANS flags: none +AGI Buffer: XAGI +ver: 1 seq#: 0 len: cnt: 64 root: 3 +level: 1 free#: 0x3c newino: 0x80 +bucket[0 - 3]: 0xffffffff 0xffffffff 0xffffffff 0xffffffff +bucket[4 - 7]: 0xffffffff 0xffffffff 0xffffffff 0xffffffff +bucket[8 - 11]: 0xffffffff 0xffffffff 0xffffffff 0xffffffff +bucket[12 - 15]: 0xffffffff 0xffffffff 0xffffffff 0xffffffff +bucket[16 - 19]: 0xffffffff +---------------------------------------------------------------------------- +Oper (4): tid: len: clientid: TRANS flags: none +BUF: #regs: 2 start blkno: () len: bmap size: 2 +Oper (5): tid: len: clientid: TRANS flags: none +BUF DATA +---------------------------------------------------------------------------- +Oper (6): tid: len: clientid: TRANS flags: none +INODE: #regs: 2 ino: 0x83 flags: 0x1 dsize: 0 + blkno: len: boff: +Oper (7): tid: len: clientid: TRANS flags: none +INODE CORE +magic 0x494e mode 0100000 version 1 format 2 +nlink 1 uid 0 gid 0 +atime len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x83 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x8000 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:QM_DQALLOC #items:6 trans:0x0 q: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x83 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x8000 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + +LOG REC AT LSN cycle 1 block (0x1, 0xf) +============================================================================ +TRANS: tid: type:QM_SBCHANGE #items:1 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x84 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x85 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:24 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x86 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:36 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x87 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:44 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x88 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:52 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x89 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:60 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8a flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:72 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8b flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:80 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8c flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:88 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8d flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:96 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8e flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:108 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8f flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:116 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x90 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:124 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x91 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:132 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x92 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:144 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x93 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:152 + CORE inode: + magic:IN mode:0x41ed ver:1 format:1 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:10 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x94 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x95 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x96 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x97 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x98 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x4f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x99 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9a flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9b flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9c flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9d flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9e flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9f flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa0 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa1 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa2 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa3 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa4 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa5 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa6 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x8f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa7 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa8 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa9 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaa flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xab flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xac flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xad flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xae flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaf flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb0 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb1 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb2 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb3 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0xcf) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb4 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb5 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb6 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb7 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb8 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb9 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xba flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbb flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbc flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbd flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbe flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbf flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x10f) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe0 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe1 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe2 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe3 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe4 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe5 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe6 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x14f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe7 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe8 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe9 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xea flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xeb flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xec flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xed flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xee flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xef flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf0 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x18f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf1 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf2 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf3 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf4 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf5 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf6 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf7 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf8 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf9 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x1cf) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfa flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfb flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfc flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfd flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfe flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xff flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x100 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x101 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x102 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x20f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x103 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x104 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x105 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x106 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x107 flags:0x1 dsize:0 + CORE inode: + magic:IN mode:0x81a4 ver:1 format:2 onlink:1 + uid:0 gid:0 nlink:1 projid:0 + atime: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + magic:IN mode:0x41ed ver:1 format:2 onlink:2 + uid:0 gid:0 nlink:2 projid:0 + atime: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x236) +### xfs_logprint -t -b -s 0 output ### +xfs_logprint: + data device: + log device: daddr: length: + + log tail: 568 head: 568 state: + override tail: 0 + + +LOG REC AT LSN cycle 1 block (0x1, 0x0) + +LOG REC AT LSN cycle 1 block (0x1, 0x2) +============================================================================ +TRANS: tid: type:QM_QINOCREATE #items:4 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3c newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x83 flags:0x1 dsize:0 + CORE inode: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:QM_DQALLOC #items:6 trans:0x0 q: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x83 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) + ver:1 seq#:0 len: + root BNO:1 CNT:2 + level BNO:1 CNT:1 + 1st: last: cnt: freeblks: longest: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: + +LOG REC AT LSN cycle 1 block (0x1, 0xf) +============================================================================ +TRANS: tid: type:QM_SBCHANGE #items:1 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3b newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x84 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:16 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3a newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x85 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:24 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x39 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x86 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:36 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x38 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x87 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:44 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x37 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x88 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:52 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x36 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x89 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:60 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x35 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8a flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:72 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x34 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8b flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:80 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x33 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8c flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:88 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x32 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8d flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:96 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x31 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8e flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:108 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x30 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x8f flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:116 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2f newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x90 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:124 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2e newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x91 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:132 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2d newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x92 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:144 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:6 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2c newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x93 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x3 dsize:152 + CORE inode: + DATA FORK LOCAL inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:10 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2b newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x94 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) + ver:1 seq#:0 len: + root BNO:1 CNT:2 + level BNO:1 CNT:1 + 1st: last: cnt: freeblks: longest: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2a newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x95 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x29 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x96 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x28 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x97 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x27 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x98 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x4f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x26 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x99 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x25 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9a flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x24 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9b flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x23 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9c flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x22 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9d flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x21 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9e flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x20 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x9f flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1f newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa0 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1e newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa1 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1d newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa2 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1c newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa3 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1b newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa4 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1a newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa5 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x19 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa6 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x8f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x18 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa7 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x17 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa8 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x16 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xa9 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x15 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaa flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x14 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xab flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x13 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xac flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x12 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xad flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x11 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xae flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x10 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xaf flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xf newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb0 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xe newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb1 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xd newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb2 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xc newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb3 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0xcf) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xb newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb4 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0xa newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb5 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x9 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb6 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x8 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb7 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x7 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb8 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x6 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xb9 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x5 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xba flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x4 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbb flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x3 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbc flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x2 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbd flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x1 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbe flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:64 root:3 + level:1 free#:0x0 newino:0x80 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xbf flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x10f) +============================================================================ +TRANS: tid: type:CREATE #items:8 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x40 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGF Buffer: (XAGF) + ver:1 seq#:0 len: + root BNO:1 CNT:2 + level BNO:1 CNT:1 + 1st: last: cnt: freeblks: longest: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:33 total:33 a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: a: len: + BUF: #regs:33 start blkno: len: bmap size:3 + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3f newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe0 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3e newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe1 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3d newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe2 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3c newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe3 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3b newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe4 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x3a newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe5 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x39 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe6 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x14f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x38 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe7 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x37 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe8 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x36 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xe9 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x35 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xea flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x34 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xeb flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x33 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xec flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x32 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xed flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x31 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xee flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x30 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xef flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2f newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf0 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x18f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2e newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf1 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2d newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf2 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2c newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf3 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2b newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf4 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x2a newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf5 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x29 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf6 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x28 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf7 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x27 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf8 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x26 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xf9 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x1cf) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x25 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfa flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x24 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfb flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x23 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfc flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x22 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfd flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x21 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xfe flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x20 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0xff flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1f newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x100 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1e newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x101 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1d newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x102 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x20f) +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1c newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x103 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1b newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x104 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x1a newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x105 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x19 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x106 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 +============================================================================ +TRANS: tid: type:CREATE #items:7 trans:0x0 q: +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + AGI Buffer: (XAGI) + ver:1 seq#:0 len: cnt:128 root:3 + level:1 free#:0x18 newino:0xe0 +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:2 + BUF DATA +INO: cnt:2 total:2 a: len: a: len: + INODE: #regs:2 ino:0x107 flags:0x1 dsize:0 + CORE inode: +INO: cnt:3 total:3 a: len: a: len: a: len: + INODE: #regs:3 ino:0x80 flags:0x5 dsize:16 + CORE inode: + DATA FORK EXTENTS inode data: +BUF: cnt:3 total:3 a: len: a: len: a: len: + BUF: #regs:3 start blkno: len: bmap size:2 + BUF DATA + BUF DATA +BUF: cnt:2 total:2 a: len: a: len: + BUF: #regs:2 start blkno: len: bmap size:1 + SUPER Block Buffer: + icount: ifree: fdblks: frext: + sunit: swidth: +DQ : cnt:2 total:2 a: len: a: len: + DQUOT: #regs:2 blkno:96 boffset:0 id: 0 + +LOG REC AT LSN cycle 1 block (0x1, 0x236) +*** unmount diff -rNu linux-2.4.7/cmd/xfstests/019 linux-2.4-xfs/cmd/xfstests/019 --- linux-2.4.7/cmd/xfstests/019 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/019 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,162 @@ +#! /bin/sh +# XFS QA Test No. 019 +# $Id: 1.1 $ +# +# mkfs protofile test +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +seqfull="$seq.full" +status=1 # failure is the default! +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_cleanup() +{ + echo "*** unmount" + umount $SCRATCH_MNT 2>/dev/null + rm -f $tmp.* +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_full() +{ + echo "" >>$seqfull + echo "*** $* ***" >>$seqfull + echo "" >>$seqfull +} + +_filter_stat() +{ + sed ' + /^Access:/d; + /^Modify:/d; + /^Change:/d; + s/Device: *[0-9][0-9]*,[0-9][0-9]*/Device: /; + s/Inode: *[0-9][0-9]*/Inode: /; + ' | tr -s ' ' +} + +# real QA test starts here + +_require_scratch + +protofile=$tmp.proto +tempfile=$tmp.file + +echo fish >$tempfile +$here/src/devzero -b 2048 -n 2 $tempfile.2 -c -v 44 + +cat >$protofile </dev/null 2>&1 + + _full "mkfs" + mkfs -t xfs -f $VERSION -p $protofile $SCRATCH_DEV >>$seqfull 2>&1 \ + || _fail "mkfs failed" + + echo "*** check FS" + _check_fs $SCRATCH_DEV + + echo "*** mount FS" + _full " mount" + mount -t xfs $SCRATCH_DEV $SCRATCH_MNT >>$seqfull 2>&1 \ + || _fail "mount failed" + + echo "*** verify FS" + (cd $SCRATCH_MNT ; find . | sort \ + | xargs $here/src/lstat64 | _filter_stat) + diff -q $SCRATCH_MNT/bigfile $tempfile.2 \ + || _fail "bigfile corrupted" + + echo "*** unmount FS" + _full "umount" + umount $SCRATCH_DEV >>$seqfull 2>&1 \ + || _fail "umount failed" + + echo "*** check FS" + _check_fs $SCRATCH_DEV +} + +_verify_fs 1 +_verify_fs 2 + +echo "*** done" +rm $seqfull +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/019.out linux-2.4-xfs/cmd/xfstests/019.out --- linux-2.4.7/cmd/xfstests/019.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/019.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,164 @@ +QA output created by 019 +Wrote 2048.00Kb (value 0x2c) +*** create FS version 1 +*** check FS +*** mount FS +*** verify FS + File: "." + Size: 4096 Filetype: Directory + Mode: (0777/drwxrwxrwx) Uid: (3) Gid: (1) +Device: Inode: Links: 3 + + File: "./bigfile" + Size: 2097152 Filetype: Regular File + Mode: (0666/-rw-rw-rw-) Uid: (3) Gid: (0) +Device: Inode: Links: 1 + + File: "./block_device" + Size: 0 Filetype: Block Device + Mode: (0012/b-----x-w-) Uid: (3) Gid: (1) +Device: Inode: Links: 1 Device type: 161,162 + + File: "./char_device" + Size: 0 Filetype: Character Device + Mode: (0345/c-wxr--r-x) Uid: (3) Gid: (1) +Device: Inode: Links: 1 Device type: 177,178 + + File: "./directory" + Size: 4096 Filetype: Directory + Mode: (0755/drwxr-xr-x) Uid: (3) Gid: (1) +Device: Inode: Links: 2 + + File: "./directory/file_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_0" + Size: 5 Filetype: Regular File + Mode: (0755/-rwxr-xr-x) Uid: (3) Gid: (1) +Device: Inode: Links: 1 + + File: "./directory/file_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_1" + Size: 5 Filetype: Regular File + Mode: (0755/-rwxr-xr-x) Uid: (3) Gid: (1) +Device: Inode: Links: 1 + + File: "./directory/file_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_2" + Size: 5 Filetype: Regular File + Mode: (0755/-rwxr-xr-x) Uid: (3) Gid: (1) +Device: Inode: Links: 1 + + File: "./directory/file_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_3" + Size: 5 Filetype: Regular File + Mode: (0755/-rwxr-xr-x) Uid: (3) Gid: (1) +Device: Inode: Links: 1 + + File: "./directory/file_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_4" + Size: 5 Filetype: Regular File + Mode: (0755/-rwxr-xr-x) Uid: (3) Gid: (1) +Device: Inode: Links: 1 + + File: "./pipe" + Size: 0 Filetype: Fifo File + Mode: (0670/frw-rwx---) Uid: (0) Gid: (0) +Device: Inode: Links: 1 + + File: "./setgid" + Size: 5 Filetype: Regular File + Mode: (2666/-rw-rwsrw-) Uid: (0) Gid: (0) +Device: Inode: Links: 1 + + File: "./setugid" + Size: 5 Filetype: Regular File + Mode: (6666/-rwsrwsrw-) Uid: (0) Gid: (0) +Device: Inode: Links: 1 + + File: "./setuid" + Size: 5 Filetype: Regular File + Mode: (4666/-rwsrw-rw-) Uid: (0) Gid: (0) +Device: Inode: Links: 1 + + File: "./symlink" + Size: 7 Filetype: Symbolic Link + Mode: (0123/l--x-w--wx) Uid: (0) Gid: (0) +Device: Inode: Links: 1 +*** unmount FS +*** check FS +*** create FS version 2 +*** check FS +*** mount FS +*** verify FS + File: "." + Size: 138 Filetype: Directory + Mode: (0777/drwxrwxrwx) Uid: (3) Gid: (1) +Device: Inode: Links: 3 + + File: "./bigfile" + Size: 2097152 Filetype: Regular File + Mode: (0666/-rw-rw-rw-) Uid: (3) Gid: (0) +Device: Inode: Links: 1 + + File: "./block_device" + Size: 0 Filetype: Block Device + Mode: (0012/b-----x-w-) Uid: (3) Gid: (1) +Device: Inode: Links: 1 Device type: 161,162 + + File: "./char_device" + Size: 0 Filetype: Character Device + Mode: (0345/c-wxr--r-x) Uid: (3) Gid: (1) +Device: Inode: Links: 1 Device type: 177,178 + + File: "./directory" + Size: 4096 Filetype: Directory + Mode: (0755/drwxr-xr-x) Uid: (3) Gid: (1) +Device: Inode: Links: 2 + + File: "./directory/file_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_0" + Size: 5 Filetype: Regular File + Mode: (0755/-rwxr-xr-x) Uid: (3) Gid: (1) +Device: Inode: Links: 1 + + File: "./directory/file_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_1" + Size: 5 Filetype: Regular File + Mode: (0755/-rwxr-xr-x) Uid: (3) Gid: (1) +Device: Inode: Links: 1 + + File: "./directory/file_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_2" + Size: 5 Filetype: Regular File + Mode: (0755/-rwxr-xr-x) Uid: (3) Gid: (1) +Device: Inode: Links: 1 + + File: "./directory/file_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_3" + Size: 5 Filetype: Regular File + Mode: (0755/-rwxr-xr-x) Uid: (3) Gid: (1) +Device: Inode: Links: 1 + + File: "./directory/file_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_4" + Size: 5 Filetype: Regular File + Mode: (0755/-rwxr-xr-x) Uid: (3) Gid: (1) +Device: Inode: Links: 1 + + File: "./pipe" + Size: 0 Filetype: Fifo File + Mode: (0670/frw-rwx---) Uid: (0) Gid: (0) +Device: Inode: Links: 1 + + File: "./setgid" + Size: 5 Filetype: Regular File + Mode: (2666/-rw-rwsrw-) Uid: (0) Gid: (0) +Device: Inode: Links: 1 + + File: "./setugid" + Size: 5 Filetype: Regular File + Mode: (6666/-rwsrwsrw-) Uid: (0) Gid: (0) +Device: Inode: Links: 1 + + File: "./setuid" + Size: 5 Filetype: Regular File + Mode: (4666/-rwsrw-rw-) Uid: (0) Gid: (0) +Device: Inode: Links: 1 + + File: "./symlink" + Size: 7 Filetype: Symbolic Link + Mode: (0123/l--x-w--wx) Uid: (0) Gid: (0) +Device: Inode: Links: 1 +*** unmount FS +*** check FS +*** done +*** unmount diff -rNu linux-2.4.7/cmd/xfstests/020 linux-2.4-xfs/cmd/xfstests/020 --- linux-2.4.7/cmd/xfstests/020 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/020 Fri Jan 19 11:15:32 2001 @@ -0,0 +1,206 @@ +#! /bin/sh +# XFS QA Test No. 020 +# $Id: 1.1 $ +# +# extended attributes +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "rm -f $tmp.* $testfile; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_filter() +{ + sed "s#$TEST_DIR[^ :]*##g; + s#$tmp[^ :]*##g; + s#/proc[^ :]*##g" $1 +} + +_attr() +{ + attr $* 2>$tmp.err >$tmp.out + exit=$? + _filter $tmp.out + _filter $tmp.err 1>&2 + return $exit +} + +_attr_list() +{ + file=$1 + + echo " *** print attributes" + if ! _attr -l $file >$tmp.raw + then + echo " !!! error return" + return 1 + fi + + $AWK_PROG -v file=$file ' + { + print substr($2,2,length($2)-2) + count++ + } + END { + exit count + } + ' <$tmp.raw >$tmp.list + + echo " *** $? attribute(s)" + for l in `cat $tmp.list` + do + if ! _attr -g $l $file >$tmp.raw + then + echo " *** $l" + echo " !!! error return" + return 1 + fi + $AWK_PROG ' + NR==1 { + print " *** field: " substr($2,2,length($2)-2) \ + " length: " $5 + next + } + { + print " ::: " $0 + } + ' <$tmp.raw + + done +} + + +# real QA test starts here + +testfile=$TEST_DIR/attribute_$$ + +echo "*** list non-existant file" +_attr_list $testfile + +echo "*** list non-xfs file (in /proc)" +_attr_list /proc/devices + +echo "*** list empty file" +touch $testfile +_attr_list $testfile + +echo "*** query non-existant attribute" +_attr -g "nonexistant" $testfile 2>&1 + +echo "*** one attribute" +echo "fish" | _attr -s fish $testfile +_attr_list $testfile + +echo "*** replace attribute" +echo "fish3" | _attr -s fish $testfile +_attr_list $testfile + +echo "*** add attribute" +echo "fish2" | _attr -s snrub $testfile +_attr_list $testfile + +echo "*** remove attribute" +_attr -r fish $testfile +_attr_list $testfile + +echo "*** add lots of attributes" +v=0 +while [ $v -lt 1000 ] +do + echo "value_$v" | attr -s "attribute_$v" $testfile >/dev/null + if [ $? -ne 0 ] + then + echo "!!! failed to add \"attribute_$v\"" + exit 1 + fi + + let "v = v + 1" +done + +echo "*** check" +# don't print it all out... +attr -l $testfile \ + | $AWK_PROG '{ l++ } END {print " *** " l " attribute(s)" }' + +echo "*** remove lots of attributes" +v=0 +while [ $v -lt 1000 ] +do + if ! attr -r "attribute_$v" $testfile >/dev/null + then + echo "!!! failed to add \"attribute_$v\"" + exit 1 + fi + + let "v = v + 1" +done + +_attr_list $testfile + +echo "*** really long value" +dd if=/dev/zero bs=1024 count=100 2>/dev/null \ + | _attr -s "long_attr" $testfile >/dev/null + +_attr -g "long_attr" $testfile | tail -n +2 | od -t x1 +_attr -r "long_attr" $testfile >/dev/null + + +echo "*** set/get/remove really long names (expect failure)" +short="XXXXXXXXXX" +long="$short$short$short$short$short$short$short$short$short$short" +vlong="$long$long$long" + +_attr -s $vlong -V fish $testfile 2>&1 >/dev/null +_attr -g $vlong $testfile 2>&1 >/dev/null +_attr -r $vlong $testfile 2>&1 >/dev/null + +echo "*** check final" + +_attr_list $testfile + +echo "*** delete" +rm -f $testfile + +exit diff -rNu linux-2.4.7/cmd/xfstests/020.out linux-2.4-xfs/cmd/xfstests/020.out --- linux-2.4.7/cmd/xfstests/020.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/020.out Sun May 6 21:35:35 2001 @@ -0,0 +1,81 @@ +QA output created by 020 +*** list non-existant file + *** print attributes +attr_list: No such file or directory +Could not list attributes for + !!! error return +*** list non-xfs file (in /proc) + *** print attributes +attr_list: Operation not supported +Could not list attributes for + !!! error return +*** list empty file + *** print attributes + *** 0 attribute(s) +*** query non-existant attribute +attr_get: No data available +Could not get "nonexistant" for +*** one attribute +Attribute "fish" set to a 5 byte value for : +fish + + *** print attributes + *** 1 attribute(s) + *** field: fish length: 5 + ::: fish + ::: +*** replace attribute +Attribute "fish" set to a 6 byte value for : +fish3 + + *** print attributes + *** 1 attribute(s) + *** field: fish length: 6 + ::: fish3 + ::: +*** add attribute +Attribute "snrub" set to a 6 byte value for : +fish2 + + *** print attributes + *** 2 attribute(s) + *** field: fish length: 6 + ::: fish3 + ::: + *** field: snrub length: 6 + ::: fish2 + ::: +*** remove attribute + *** print attributes + *** 1 attribute(s) + *** field: snrub length: 6 + ::: fish2 + ::: +*** add lots of attributes +*** check + *** 1001 attribute(s) +*** remove lots of attributes + *** print attributes + *** 1 attribute(s) + *** field: snrub length: 6 + ::: fish2 + ::: +*** really long value +0000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +* +0200000 0a +0200001 +*** set/get/remove really long names (expect failure) +attr_set: Bad address +Could not set "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" for +attr_get: Bad address +Could not get "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" for +attr_remove: Bad address +Could not remove "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" for +*** check final + *** print attributes + *** 1 attribute(s) + *** field: snrub length: 6 + ::: fish2 + ::: +*** delete diff -rNu linux-2.4.7/cmd/xfstests/021 linux-2.4-xfs/cmd/xfstests/021 --- linux-2.4.7/cmd/xfstests/021 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/021 Fri Jan 19 11:15:32 2001 @@ -0,0 +1,126 @@ +#! /bin/sh +# XFS QA Test No. 021 +# $Id: 1.1 $ +# +# xfs_db type attr test (pv 797508 linux-xfs & IRIX) +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_cleanup() +{ + echo "*** unmount" + umount $SCRATCH_MNT 2>/dev/null + rm -f $tmp.* +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_s() +{ + echo $2 | attr -s $1 $testfile >/dev/null +} + +_attr() +{ + attr $* 2>$tmp.err >$tmp.out + exit=$? + sed "s#$SCRATCH_MNT[^ .:]*##g; s#$tmp[^ :]*##g;" $tmp.out + sed "s#$SCRATCH_MNT[^ .:]*##g; s#$tmp[^ :]*##g;" $tmp.err 1>&2 + return $exit +} + +# real QA test starts here + +_require_scratch + + +echo "*** mkfs" + +rm -f $seq.full +umount $SCRATCH_DEV >/dev/null 2>&1 + +mkfs -t xfs -f $SCRATCH_DEV >/dev/null \ + || _fail "mkfs failed" + +echo "*** mount FS" +mount -t xfs $SCRATCH_DEV $SCRATCH_MNT >/dev/null \ + || _fail "mount failed" + +testfile=$SCRATCH_MNT/testfile +echo "*** make test file 1" + +touch $testfile.1 +echo "v1" | _attr -s "a1" $testfile.1 >/dev/null +echo "v2--" | _attr -s "a2--" $testfile.1 >/dev/null +_attr -l $testfile.1 +inum_1=`ls -li $testfile.1 | $AWK_PROG '{ print $1 }'` + +echo "*** make test file 2" + +touch $testfile.2 +echo "value_1" | _attr -s "a1" $testfile.2 >/dev/null +echo "value_2" | _attr -s "a2-----" $testfile.2 >/dev/null + +(echo start ; dd if=/dev/zero bs=65525 count=1 ; echo end ) \ + | _attr -s "a3" $testfile.2 >/dev/null + +_attr -l $testfile.2 +inum_2=`ls -li $testfile.2 | $AWK_PROG '{ print $1 }'` + +echo "*** unmount FS" +umount $SCRATCH_DEV >>$seq.full 2>&1 \ + || _fail "umount failed" + +echo "*** dump attributes (1)" + +xfs_db -r -c "inode $inum_1" -c "print a.sfattr" $SCRATCH_DEV + +echo "*** dump attributes (2)" + +xfs_db -r -c "inode $inum_2" -c "a a.bmx[0].startblock" -c "print" $SCRATCH_DEV + +echo "*** done" +rm $seq.full +exit diff -rNu linux-2.4.7/cmd/xfstests/021.out linux-2.4-xfs/cmd/xfstests/021.out --- linux-2.4.7/cmd/xfstests/021.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/021.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,50 @@ +QA output created by 021 +*** mkfs +*** mount FS +*** make test file 1 +Attribute "a1" has a 3 byte value for .1 +Attribute "a2--" has a 5 byte value for .1 +*** make test file 2 +1+0 records in +1+0 records out +Attribute "a1" has a 8 byte value for .2 +Attribute "a3" has a 65535 byte value for .2 +Attribute "a2-----" has a 8 byte value for .2 +*** unmount FS +*** dump attributes (1) +a.sfattr.hdr.totsize = 24 +a.sfattr.hdr.count = 2 +a.sfattr.list[0].namelen = 2 +a.sfattr.list[0].valuelen = 3 +a.sfattr.list[0].root = 0 +a.sfattr.list[0].name = "a1" +a.sfattr.list[0].value = "v1\d" +a.sfattr.list[1].namelen = 4 +a.sfattr.list[1].valuelen = 5 +a.sfattr.list[1].root = 0 +a.sfattr.list[1].name = "a2--" +a.sfattr.list[1].value = "v2--\d" +*** dump attributes (2) +hdr.info.forw = 0 +hdr.info.back = 0 +hdr.info.magic = 0xfbee +hdr.count = 3 +hdr.usedbytes = 52 +hdr.firstused = 4044 +hdr.holes = 0 +hdr.freemap[0-2] = [base,size] 0:[56,3988] 1:[0,0] 2:[0,0] +entries[0-2] = [hashval,nameidx,incomplete,root,local] 0:[0x30b1,4080,0,0,1] 1:[0x30b3,4044,0,0,0] 2:[0xd5aad33f,4060,0,0,1] +nvlist[0].valuelen = 8 +nvlist[0].namelen = 2 +nvlist[0].name = "a1" +nvlist[0].value = "value_1\d" +nvlist[1].valueblk = 0x1 +nvlist[1].valuelen = 65535 +nvlist[1].namelen = 2 +nvlist[1].name = "a3" +nvlist[2].valuelen = 8 +nvlist[2].namelen = 7 +nvlist[2].name = "a2-----" +nvlist[2].value = "value_2\d" +*** done +*** unmount diff -rNu linux-2.4.7/cmd/xfstests/022 linux-2.4-xfs/cmd/xfstests/022 --- linux-2.4.7/cmd/xfstests/022 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/022 Thu Feb 1 22:31:55 2001 @@ -0,0 +1,66 @@ +#! /bin/sh +# XFS QA Test No. 022 +# $Id: 1.1 $ +# +# Test out a level 0 dump/restore to a tape of a subdir +# i.e. it is testing out drive_scsitape.c +# +# Use src/fsstress to create a directory structure with a mix of files +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sherman.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "rm -rf $tmp.*; exit \$status" 0 1 2 3 15 + +. ./common.rc +. ./common.dump + +# real QA test starts here + +_require_tape $TAPE_DEV +_create_dumpdir_stress +_erase_hard +_do_dump_sub +_do_restore +_ls_compare_sub + +# success, all done +exit diff -rNu linux-2.4.7/cmd/xfstests/022.grpquota linux-2.4-xfs/cmd/xfstests/022.grpquota --- linux-2.4.7/cmd/xfstests/022.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/022.grpquota Thu May 24 00:36:12 2001 @@ -0,0 +1,58 @@ +QA output created by 022 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fsstress. + +----------------------------------------------- +fsstress : -f link=10 -f creat=10 -f mkdir=10 -f truncate=5 -f symlink=10 +----------------------------------------------- +Erasing tape +Dumping to tape... +xfsdump -s DUMP_SUBDIR -f TAPE_DEV -M stress_tape_media -L stress_022 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_022" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_022 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/022.noquota linux-2.4-xfs/cmd/xfstests/022.noquota --- linux-2.4.7/cmd/xfstests/022.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/022.noquota Thu May 24 00:36:12 2001 @@ -0,0 +1,56 @@ +QA output created by 022 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fsstress. + +----------------------------------------------- +fsstress : -f link=10 -f creat=10 -f mkdir=10 -f truncate=5 -f symlink=10 +----------------------------------------------- +Erasing tape +Dumping to tape... +xfsdump -s DUMP_SUBDIR -f TAPE_DEV -M stress_tape_media -L stress_022 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_022" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_022 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: restore complete: SECS seconds elapsed +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/022.ugquota linux-2.4-xfs/cmd/xfstests/022.ugquota --- linux-2.4.7/cmd/xfstests/022.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/022.ugquota Thu May 24 00:36:12 2001 @@ -0,0 +1,60 @@ +QA output created by 022 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fsstress. + +----------------------------------------------- +fsstress : -f link=10 -f creat=10 -f mkdir=10 -f truncate=5 -f symlink=10 +----------------------------------------------- +Erasing tape +Dumping to tape... +xfsdump -s DUMP_SUBDIR -f TAPE_DEV -M stress_tape_media -L stress_022 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_022" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_022 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/022.usrquota linux-2.4-xfs/cmd/xfstests/022.usrquota --- linux-2.4.7/cmd/xfstests/022.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/022.usrquota Thu May 24 00:36:12 2001 @@ -0,0 +1,58 @@ +QA output created by 022 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fsstress. + +----------------------------------------------- +fsstress : -f link=10 -f creat=10 -f mkdir=10 -f truncate=5 -f symlink=10 +----------------------------------------------- +Erasing tape +Dumping to tape... +xfsdump -s DUMP_SUBDIR -f TAPE_DEV -M stress_tape_media -L stress_022 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_022" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_022 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: restore complete: SECS seconds elapsed +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/023 linux-2.4-xfs/cmd/xfstests/023 --- linux-2.4.7/cmd/xfstests/023 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/023 Thu Feb 1 22:31:55 2001 @@ -0,0 +1,66 @@ +#! /bin/sh +# XFS QA Test No. 023 +# $Id: 1.1 $ +# +# To test xfsdump/restore to tape using a directory with +# files with data created by src/fill. +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@bruce.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "rm -rf $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +_require_tape $TAPE_DEV +_create_dumpdir_fill +_erase_hard +_do_dump_sub +_do_restore +_diff_compare_sub +_ls_compare_sub + +# success, all done +exit diff -rNu linux-2.4.7/cmd/xfstests/023.grpquota linux-2.4-xfs/cmd/xfstests/023.grpquota --- linux-2.4.7/cmd/xfstests/023.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/023.grpquota Thu May 24 00:36:12 2001 @@ -0,0 +1,92 @@ +QA output created by 023 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -s DUMP_SUBDIR -f TAPE_DEV -M stress_tape_media -L stress_023 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_023" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_023 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/023.noquota linux-2.4-xfs/cmd/xfstests/023.noquota --- linux-2.4.7/cmd/xfstests/023.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/023.noquota Thu May 24 00:36:12 2001 @@ -0,0 +1,90 @@ +QA output created by 023 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -s DUMP_SUBDIR -f TAPE_DEV -M stress_tape_media -L stress_023 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_023" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_023 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/023.ugquota linux-2.4-xfs/cmd/xfstests/023.ugquota --- linux-2.4.7/cmd/xfstests/023.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/023.ugquota Thu May 24 00:36:12 2001 @@ -0,0 +1,94 @@ +QA output created by 023 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -s DUMP_SUBDIR -f TAPE_DEV -M stress_tape_media -L stress_023 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_023" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_023 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/023.usrquota linux-2.4-xfs/cmd/xfstests/023.usrquota --- linux-2.4.7/cmd/xfstests/023.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/023.usrquota Thu May 24 00:36:12 2001 @@ -0,0 +1,92 @@ +QA output created by 023 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -s DUMP_SUBDIR -f TAPE_DEV -M stress_tape_media -L stress_023 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_023" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_023 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/024 linux-2.4-xfs/cmd/xfstests/024 --- linux-2.4.7/cmd/xfstests/024 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/024 Thu Feb 1 22:31:55 2001 @@ -0,0 +1,67 @@ +#! /bin/sh +# XFS QA Test No. 024 +# $Id: 1.1 $ +# +# Test out incremental dumps +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@bruce.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +_require_tape $TAPE_DEV +_create_dumpdir_fill +_erase_hard +_do_dump +_append_dumpdir_fill +_erase_hard +_do_dump_incremental +_do_restore +_diff_compare + +# success, all done +exit diff -rNu linux-2.4.7/cmd/xfstests/024.grpquota linux-2.4-xfs/cmd/xfstests/024.grpquota --- linux-2.4.7/cmd/xfstests/024.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/024.grpquota Thu May 24 00:36:12 2001 @@ -0,0 +1,127 @@ +QA output created by 024 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L stress_024 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_024" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Erasing tape +Dumping incrementally to tape... +xfsdump -l1 -f TAPE_DEV -M stress_tape_media -L stress_024 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 1 incremental dump of HOSTNAME:SCRATCH_MNT based on level 0 dump begun DATE +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_024" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_024 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Only in DUMP_DIR: big +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Only in DUMP_DIR/sub: a00 +Only in DUMP_DIR/sub: a000 +Only in DUMP_DIR/sub: b +Only in DUMP_DIR/sub: b00 +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Only in DUMP_DIR/sub: c00 +Only in DUMP_DIR/sub: d +Only in DUMP_DIR/sub: d00 +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Only in DUMP_DIR/sub: e00 +Only in DUMP_DIR/sub: e000 +Only in DUMP_DIR/sub: f +Only in DUMP_DIR/sub: f00 +Only in DUMP_DIR/sub: g +Only in DUMP_DIR/sub: g00 +Only in DUMP_DIR/sub: h +Only in DUMP_DIR/sub: h00 +Only in DUMP_DIR/sub: h000 +Only in DUMP_DIR/sub: i +Only in DUMP_DIR/sub: i00 +Only in DUMP_DIR/sub: j +Only in DUMP_DIR/sub: j00 +Only in DUMP_DIR/sub: k +Only in DUMP_DIR/sub: k00 +Only in DUMP_DIR/sub: k000 +Only in DUMP_DIR/sub: l +Only in DUMP_DIR/sub: l00 +Only in DUMP_DIR/sub: m +Only in DUMP_DIR/sub: m00 +Only in DUMP_DIR/sub: n +Only in DUMP_DIR/sub: n00 +Only in DUMP_DIR/sub: small +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/024.noquota linux-2.4-xfs/cmd/xfstests/024.noquota --- linux-2.4.7/cmd/xfstests/024.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/024.noquota Thu May 24 00:36:12 2001 @@ -0,0 +1,123 @@ +QA output created by 024 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L stress_024 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_024" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Erasing tape +Dumping incrementally to tape... +xfsdump -l1 -f TAPE_DEV -M stress_tape_media -L stress_024 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 1 incremental dump of HOSTNAME:SCRATCH_MNT based on level 0 dump begun DATE +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_024" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_024 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Only in DUMP_DIR: big +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Only in DUMP_DIR/sub: a00 +Only in DUMP_DIR/sub: a000 +Only in DUMP_DIR/sub: b +Only in DUMP_DIR/sub: b00 +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Only in DUMP_DIR/sub: c00 +Only in DUMP_DIR/sub: d +Only in DUMP_DIR/sub: d00 +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Only in DUMP_DIR/sub: e00 +Only in DUMP_DIR/sub: e000 +Only in DUMP_DIR/sub: f +Only in DUMP_DIR/sub: f00 +Only in DUMP_DIR/sub: g +Only in DUMP_DIR/sub: g00 +Only in DUMP_DIR/sub: h +Only in DUMP_DIR/sub: h00 +Only in DUMP_DIR/sub: h000 +Only in DUMP_DIR/sub: i +Only in DUMP_DIR/sub: i00 +Only in DUMP_DIR/sub: j +Only in DUMP_DIR/sub: j00 +Only in DUMP_DIR/sub: k +Only in DUMP_DIR/sub: k00 +Only in DUMP_DIR/sub: k000 +Only in DUMP_DIR/sub: l +Only in DUMP_DIR/sub: l00 +Only in DUMP_DIR/sub: m +Only in DUMP_DIR/sub: m00 +Only in DUMP_DIR/sub: n +Only in DUMP_DIR/sub: n00 +Only in DUMP_DIR/sub: small +Only in SCRATCH_MNT: RESTORE_SUBDIR diff -rNu linux-2.4.7/cmd/xfstests/024.ugquota linux-2.4-xfs/cmd/xfstests/024.ugquota --- linux-2.4.7/cmd/xfstests/024.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/024.ugquota Thu May 24 00:36:12 2001 @@ -0,0 +1,131 @@ +QA output created by 024 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L stress_024 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_024" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Erasing tape +Dumping incrementally to tape... +xfsdump -l1 -f TAPE_DEV -M stress_tape_media -L stress_024 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 1 incremental dump of HOSTNAME:SCRATCH_MNT based on level 0 dump begun DATE +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_024" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_024 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Only in DUMP_DIR: big +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Only in DUMP_DIR/sub: a00 +Only in DUMP_DIR/sub: a000 +Only in DUMP_DIR/sub: b +Only in DUMP_DIR/sub: b00 +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Only in DUMP_DIR/sub: c00 +Only in DUMP_DIR/sub: d +Only in DUMP_DIR/sub: d00 +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Only in DUMP_DIR/sub: e00 +Only in DUMP_DIR/sub: e000 +Only in DUMP_DIR/sub: f +Only in DUMP_DIR/sub: f00 +Only in DUMP_DIR/sub: g +Only in DUMP_DIR/sub: g00 +Only in DUMP_DIR/sub: h +Only in DUMP_DIR/sub: h00 +Only in DUMP_DIR/sub: h000 +Only in DUMP_DIR/sub: i +Only in DUMP_DIR/sub: i00 +Only in DUMP_DIR/sub: j +Only in DUMP_DIR/sub: j00 +Only in DUMP_DIR/sub: k +Only in DUMP_DIR/sub: k00 +Only in DUMP_DIR/sub: k000 +Only in DUMP_DIR/sub: l +Only in DUMP_DIR/sub: l00 +Only in DUMP_DIR/sub: m +Only in DUMP_DIR/sub: m00 +Only in DUMP_DIR/sub: n +Only in DUMP_DIR/sub: n00 +Only in DUMP_DIR/sub: small +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/024.usrquota linux-2.4-xfs/cmd/xfstests/024.usrquota --- linux-2.4.7/cmd/xfstests/024.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/024.usrquota Thu May 24 00:36:12 2001 @@ -0,0 +1,127 @@ +QA output created by 024 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L stress_024 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_024" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Erasing tape +Dumping incrementally to tape... +xfsdump -l1 -f TAPE_DEV -M stress_tape_media -L stress_024 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 1 incremental dump of HOSTNAME:SCRATCH_MNT based on level 0 dump begun DATE +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_024" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_024 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Only in DUMP_DIR: big +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Only in DUMP_DIR/sub: a00 +Only in DUMP_DIR/sub: a000 +Only in DUMP_DIR/sub: b +Only in DUMP_DIR/sub: b00 +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Only in DUMP_DIR/sub: c00 +Only in DUMP_DIR/sub: d +Only in DUMP_DIR/sub: d00 +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Only in DUMP_DIR/sub: e00 +Only in DUMP_DIR/sub: e000 +Only in DUMP_DIR/sub: f +Only in DUMP_DIR/sub: f00 +Only in DUMP_DIR/sub: g +Only in DUMP_DIR/sub: g00 +Only in DUMP_DIR/sub: h +Only in DUMP_DIR/sub: h00 +Only in DUMP_DIR/sub: h000 +Only in DUMP_DIR/sub: i +Only in DUMP_DIR/sub: i00 +Only in DUMP_DIR/sub: j +Only in DUMP_DIR/sub: j00 +Only in DUMP_DIR/sub: k +Only in DUMP_DIR/sub: k00 +Only in DUMP_DIR/sub: k000 +Only in DUMP_DIR/sub: l +Only in DUMP_DIR/sub: l00 +Only in DUMP_DIR/sub: m +Only in DUMP_DIR/sub: m00 +Only in DUMP_DIR/sub: n +Only in DUMP_DIR/sub: n00 +Only in DUMP_DIR/sub: small +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas diff -rNu linux-2.4.7/cmd/xfstests/025 linux-2.4-xfs/cmd/xfstests/025 --- linux-2.4.7/cmd/xfstests/025 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/025 Thu Feb 1 22:31:55 2001 @@ -0,0 +1,64 @@ +#! /bin/sh +# XFS QA Test No. 025 +# $Id: 1.1 $ +# +# Test dump/restore using -m option (min strategy) +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@bruce.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +_require_tape $TAPE_DEV +_create_dumpdir_fill +_erase_hard +_do_dump_min +_do_restore_min +_diff_compare + +# success, all done +exit diff -rNu linux-2.4.7/cmd/xfstests/025.grpquota linux-2.4-xfs/cmd/xfstests/025.grpquota --- linux-2.4.7/cmd/xfstests/025.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/025.grpquota Thu May 24 00:36:12 2001 @@ -0,0 +1,87 @@ +QA output created by 025 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -m -b 1048576 -l0 -f TAPE_DEV -M stress_tape_media -L stress_025 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_025" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -m -b 1048576 -f TAPE_DEV -L stress_025 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/025.noquota linux-2.4-xfs/cmd/xfstests/025.noquota --- linux-2.4.7/cmd/xfstests/025.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/025.noquota Thu May 24 00:36:12 2001 @@ -0,0 +1,84 @@ +QA output created by 025 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -m -b 1048576 -l0 -f TAPE_DEV -M stress_tape_media -L stress_025 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_025" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -m -b 1048576 -f TAPE_DEV -L stress_025 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR diff -rNu linux-2.4.7/cmd/xfstests/025.ugquota linux-2.4-xfs/cmd/xfstests/025.ugquota --- linux-2.4.7/cmd/xfstests/025.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/025.ugquota Thu May 24 00:36:12 2001 @@ -0,0 +1,90 @@ +QA output created by 025 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -m -b 1048576 -l0 -f TAPE_DEV -M stress_tape_media -L stress_025 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_025" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -m -b 1048576 -f TAPE_DEV -L stress_025 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/025.usrquota linux-2.4-xfs/cmd/xfstests/025.usrquota --- linux-2.4.7/cmd/xfstests/025.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/025.usrquota Thu May 24 00:36:12 2001 @@ -0,0 +1,87 @@ +QA output created by 025 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -m -b 1048576 -l0 -f TAPE_DEV -M stress_tape_media -L stress_025 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_025" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -m -b 1048576 -f TAPE_DEV -L stress_025 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas diff -rNu linux-2.4.7/cmd/xfstests/026 linux-2.4-xfs/cmd/xfstests/026 --- linux-2.4.7/cmd/xfstests/026 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/026 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,62 @@ +#! /bin/sh +# XFS QA Test No. 026 +# $Id: 1.1 $ +# +# Test xfsdump/xfsrestore to a dump file (as opposed to a tape) +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@bruce.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +_create_dumpdir_fill +_do_dump_file +_do_restore_file +_diff_compare + +# success, all done +exit diff -rNu linux-2.4.7/cmd/xfstests/026.grpquota linux-2.4-xfs/cmd/xfstests/026.grpquota --- linux-2.4.7/cmd/xfstests/026.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/026.grpquota Tue May 22 01:07:23 2001 @@ -0,0 +1,77 @@ +QA output created by 026 +Creating directory system to dump using src/fill. +Setup .................................... +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L stress_026 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_026" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Restoring from file... +xfsrestore -f DUMP_FILE -L stress_026 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/026.noquota linux-2.4-xfs/cmd/xfstests/026.noquota --- linux-2.4.7/cmd/xfstests/026.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/026.noquota Tue May 22 01:02:29 2001 @@ -0,0 +1,74 @@ +QA output created by 026 +Creating directory system to dump using src/fill. +Setup .................................... +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L stress_026 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_026" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Restoring from file... +xfsrestore -f DUMP_FILE -L stress_026 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR diff -rNu linux-2.4.7/cmd/xfstests/026.ugquota linux-2.4-xfs/cmd/xfstests/026.ugquota --- linux-2.4.7/cmd/xfstests/026.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/026.ugquota Tue May 22 01:07:23 2001 @@ -0,0 +1,80 @@ +QA output created by 026 +Creating directory system to dump using src/fill. +Setup .................................... +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L stress_026 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_026" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Restoring from file... +xfsrestore -f DUMP_FILE -L stress_026 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/026.usrquota linux-2.4-xfs/cmd/xfstests/026.usrquota --- linux-2.4.7/cmd/xfstests/026.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/026.usrquota Tue May 22 01:07:23 2001 @@ -0,0 +1,77 @@ +QA output created by 026 +Creating directory system to dump using src/fill. +Setup .................................... +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L stress_026 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_026" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Restoring from file... +xfsrestore -f DUMP_FILE -L stress_026 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas diff -rNu linux-2.4.7/cmd/xfstests/027 linux-2.4-xfs/cmd/xfstests/027 --- linux-2.4.7/cmd/xfstests/027 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/027 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,61 @@ +#! /bin/sh +# XFS QA Test No. 027 +# $Id: 1.1 $ +# +# Test out "xfsdump | xfsrestore" +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sherman.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +_create_dumpdir_fill +_do_dump_restore +_diff_compare_sub + +# success, all done +exit diff -rNu linux-2.4.7/cmd/xfstests/027.grpquota linux-2.4-xfs/cmd/xfstests/027.grpquota --- linux-2.4.7/cmd/xfstests/027.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/027.grpquota Tue May 22 01:07:23 2001 @@ -0,0 +1,84 @@ +QA output created by 027 +Creating directory system to dump using src/fill. +Setup .................................... +xfsdump|xfsrestore ... +xfsdump -s DUMP_SUBDIR - SCRATCH_MNT | xfsrestore - RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: searching media for dump +xfsrestore: examining media file 0 +xfsrestore: dump description: +xfsrestore: hostname: HOSTNAME +xfsrestore: mount point: SCRATCH_MNT +xfsrestore: volume: SCRATCH_DEV +xfsrestore: session time: TIME +xfsrestore: level: 0 +xfsrestore: session label: "" +xfsrestore: media label: "" +xfsrestore: file system id: ID +xfsrestore: session id: ID +xfsrestore: media id: ID +xfsrestore: searching media for directory dump +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical diff -rNu linux-2.4.7/cmd/xfstests/027.noquota linux-2.4-xfs/cmd/xfstests/027.noquota --- linux-2.4.7/cmd/xfstests/027.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/027.noquota Tue May 22 01:02:53 2001 @@ -0,0 +1,82 @@ +QA output created by 027 +Creating directory system to dump using src/fill. +Setup .................................... +xfsdump|xfsrestore ... +xfsdump -s DUMP_SUBDIR - SCRATCH_MNT | xfsrestore - RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: searching media for dump +xfsrestore: examining media file 0 +xfsrestore: dump description: +xfsrestore: hostname: HOSTNAME +xfsrestore: mount point: SCRATCH_MNT +xfsrestore: volume: SCRATCH_DEV +xfsrestore: session time: TIME +xfsrestore: level: 0 +xfsrestore: session label: "" +xfsrestore: media label: "" +xfsrestore: file system id: ID +xfsrestore: session id: ID +xfsrestore: media id: ID +xfsrestore: searching media for directory dump +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: restore complete: SECS seconds elapsed +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical diff -rNu linux-2.4.7/cmd/xfstests/027.ugquota linux-2.4-xfs/cmd/xfstests/027.ugquota --- linux-2.4.7/cmd/xfstests/027.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/027.ugquota Tue May 22 01:07:23 2001 @@ -0,0 +1,86 @@ +QA output created by 027 +Creating directory system to dump using src/fill. +Setup .................................... +xfsdump|xfsrestore ... +xfsdump -s DUMP_SUBDIR - SCRATCH_MNT | xfsrestore - RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: searching media for dump +xfsrestore: examining media file 0 +xfsrestore: dump description: +xfsrestore: hostname: HOSTNAME +xfsrestore: mount point: SCRATCH_MNT +xfsrestore: volume: SCRATCH_DEV +xfsrestore: session time: TIME +xfsrestore: level: 0 +xfsrestore: session label: "" +xfsrestore: media label: "" +xfsrestore: file system id: ID +xfsrestore: session id: ID +xfsrestore: media id: ID +xfsrestore: searching media for directory dump +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical diff -rNu linux-2.4.7/cmd/xfstests/027.usrquota linux-2.4-xfs/cmd/xfstests/027.usrquota --- linux-2.4.7/cmd/xfstests/027.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/027.usrquota Tue May 22 01:07:23 2001 @@ -0,0 +1,84 @@ +QA output created by 027 +Creating directory system to dump using src/fill. +Setup .................................... +xfsdump|xfsrestore ... +xfsdump -s DUMP_SUBDIR - SCRATCH_MNT | xfsrestore - RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: searching media for dump +xfsrestore: examining media file 0 +xfsrestore: dump description: +xfsrestore: hostname: HOSTNAME +xfsrestore: mount point: SCRATCH_MNT +xfsrestore: volume: SCRATCH_DEV +xfsrestore: session time: TIME +xfsrestore: level: 0 +xfsrestore: session label: "" +xfsrestore: media label: "" +xfsrestore: file system id: ID +xfsrestore: session id: ID +xfsrestore: media id: ID +xfsrestore: searching media for directory dump +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: restore complete: SECS seconds elapsed +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical diff -rNu linux-2.4.7/cmd/xfstests/028 linux-2.4-xfs/cmd/xfstests/028 --- linux-2.4.7/cmd/xfstests/028 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/028 Tue May 22 01:59:30 2001 @@ -0,0 +1,91 @@ +#! /bin/sh +# XFS QA Test No. 028 +# $Id: 1.1 $ +# +# To test out xfsinvutil +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sherman.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +# wipe test dir clean first +# so dump can be real quick +_wipe_fs +_setup_seq_out + +# +# Create 5 dumps +# and on the 3rd dump note the date +# which we'll use to prune against using xfsinvutil +# +i=0 +while [ $i -lt 5 ]; do + _do_dump_file -L "session.$i" + if [ $i -eq 2 ]; then + sleep 1 + middate=`date '+%m/%d/%Y %T'` + fi + rm $dump_file + sleep 2 + i=`expr $i + 1` +done + +echo "middate = $middate" >>$seq.full + +# +# Now do the xfsinvutil and +# look and the inventory before and after +# to see if it did the job +# +_dump_inventory +_do_invutil -n +_dump_inventory + + +# success, all done +exit diff -rNu linux-2.4.7/cmd/xfstests/028.grpquota linux-2.4-xfs/cmd/xfstests/028.grpquota --- linux-2.4.7/cmd/xfstests/028.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/028.grpquota Tue May 22 01:59:30 2001 @@ -0,0 +1,328 @@ +QA output created by 028 +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.0 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.0" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.1 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.1" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.2 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.2" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.3 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.3" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.4 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.4" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +file system 0: + fs id: ID + session 0: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.0" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 1: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.1" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 2: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.2" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 3: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.3" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 4: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.4" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID +Processing file /var/xfsdump/inventory/UUIDstab + Found entry for HOSTNAME:SCRATCH_MNT + processing index file + /var/xfsdump/inventory/UUID.InvIndex + Checking access for + /var/xfsdump/inventory/UUID.StObj + Mount point match + Session 0: HOSTNAME:SCRATCH_MNT +------------------------------------------------- +Pruning this matching entry: +UUID : ID +MOUNT POINT : HOSTNAME:SCRATCH_MNT +DEV PATH : HOSTNAME:SCRATCH_DEV +LABEL : session.0 +TIME OF DUMP : TIME +------------------------------------------------- + + Session 1: HOSTNAME:SCRATCH_MNT +------------------------------------------------- +Pruning this matching entry: +UUID : ID +MOUNT POINT : HOSTNAME:SCRATCH_MNT +DEV PATH : HOSTNAME:SCRATCH_DEV +LABEL : session.1 +TIME OF DUMP : TIME +------------------------------------------------- + + Session 2: HOSTNAME:SCRATCH_MNT +------------------------------------------------- +Pruning this matching entry: +UUID : ID +MOUNT POINT : HOSTNAME:SCRATCH_MNT +DEV PATH : HOSTNAME:SCRATCH_DEV +LABEL : session.2 +TIME OF DUMP : TIME +------------------------------------------------- + + Session 3: HOSTNAME:SCRATCH_MNT + Session 4: HOSTNAME:SCRATCH_MNT +file system 0: + fs id: ID + session 0: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.3" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 1: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.4" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID diff -rNu linux-2.4.7/cmd/xfstests/028.noquota linux-2.4-xfs/cmd/xfstests/028.noquota --- linux-2.4.7/cmd/xfstests/028.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/028.noquota Tue May 22 19:12:03 2001 @@ -0,0 +1,323 @@ +QA output created by 028 +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.0 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.0" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : 0 bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.1 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.1" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : 0 bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.2 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.2" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : 0 bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.3 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.3" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : 0 bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.4 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.4" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : 0 bytes +xfsdump: dump complete: SECS seconds elapsed +file system 0: + fs id: ID + session 0: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.0" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 1: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.1" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 2: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.2" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 3: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.3" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 4: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.4" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID +Processing file /var/xfsdump/inventory/UUIDstab + Found entry for HOSTNAME:SCRATCH_MNT + processing index file + /var/xfsdump/inventory/UUID.InvIndex + Checking access for + /var/xfsdump/inventory/UUID.StObj + Mount point match + Session 0: HOSTNAME:SCRATCH_MNT +------------------------------------------------- +Pruning this matching entry: +UUID : ID +MOUNT POINT : HOSTNAME:SCRATCH_MNT +DEV PATH : HOSTNAME:SCRATCH_DEV +LABEL : session.0 +TIME OF DUMP : TIME +------------------------------------------------- + + Session 1: HOSTNAME:SCRATCH_MNT +------------------------------------------------- +Pruning this matching entry: +UUID : ID +MOUNT POINT : HOSTNAME:SCRATCH_MNT +DEV PATH : HOSTNAME:SCRATCH_DEV +LABEL : session.1 +TIME OF DUMP : TIME +------------------------------------------------- + + Session 2: HOSTNAME:SCRATCH_MNT +------------------------------------------------- +Pruning this matching entry: +UUID : ID +MOUNT POINT : HOSTNAME:SCRATCH_MNT +DEV PATH : HOSTNAME:SCRATCH_DEV +LABEL : session.2 +TIME OF DUMP : TIME +------------------------------------------------- + + Session 3: HOSTNAME:SCRATCH_MNT + Session 4: HOSTNAME:SCRATCH_MNT +file system 0: + fs id: ID + session 0: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.3" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 1: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.4" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID diff -rNu linux-2.4.7/cmd/xfstests/028.ugquota linux-2.4-xfs/cmd/xfstests/028.ugquota --- linux-2.4.7/cmd/xfstests/028.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/028.ugquota Tue May 22 01:59:30 2001 @@ -0,0 +1,333 @@ +QA output created by 028 +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.0 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.0" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.1 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.1" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.2 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.2" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.3 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.3" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.4 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.4" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +file system 0: + fs id: ID + session 0: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.0" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 1: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.1" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 2: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.2" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 3: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.3" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 4: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.4" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID +Processing file /var/xfsdump/inventory/UUIDstab + Found entry for HOSTNAME:SCRATCH_MNT + processing index file + /var/xfsdump/inventory/UUID.InvIndex + Checking access for + /var/xfsdump/inventory/UUID.StObj + Mount point match + Session 0: HOSTNAME:SCRATCH_MNT +------------------------------------------------- +Pruning this matching entry: +UUID : ID +MOUNT POINT : HOSTNAME:SCRATCH_MNT +DEV PATH : HOSTNAME:SCRATCH_DEV +LABEL : session.0 +TIME OF DUMP : TIME +------------------------------------------------- + + Session 1: HOSTNAME:SCRATCH_MNT +------------------------------------------------- +Pruning this matching entry: +UUID : ID +MOUNT POINT : HOSTNAME:SCRATCH_MNT +DEV PATH : HOSTNAME:SCRATCH_DEV +LABEL : session.1 +TIME OF DUMP : TIME +------------------------------------------------- + + Session 2: HOSTNAME:SCRATCH_MNT +------------------------------------------------- +Pruning this matching entry: +UUID : ID +MOUNT POINT : HOSTNAME:SCRATCH_MNT +DEV PATH : HOSTNAME:SCRATCH_DEV +LABEL : session.2 +TIME OF DUMP : TIME +------------------------------------------------- + + Session 3: HOSTNAME:SCRATCH_MNT + Session 4: HOSTNAME:SCRATCH_MNT +file system 0: + fs id: ID + session 0: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.3" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 1: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.4" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID diff -rNu linux-2.4.7/cmd/xfstests/028.usrquota linux-2.4-xfs/cmd/xfstests/028.usrquota --- linux-2.4.7/cmd/xfstests/028.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/028.usrquota Tue May 22 01:59:30 2001 @@ -0,0 +1,328 @@ +QA output created by 028 +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.0 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.0" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.1 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.1" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.2 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.2" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.3 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.3" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L session.4 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "session.4" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +file system 0: + fs id: ID + session 0: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.0" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 1: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.1" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 2: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.2" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 3: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.3" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 4: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.4" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID +Processing file /var/xfsdump/inventory/UUIDstab + Found entry for HOSTNAME:SCRATCH_MNT + processing index file + /var/xfsdump/inventory/UUID.InvIndex + Checking access for + /var/xfsdump/inventory/UUID.StObj + Mount point match + Session 0: HOSTNAME:SCRATCH_MNT +------------------------------------------------- +Pruning this matching entry: +UUID : ID +MOUNT POINT : HOSTNAME:SCRATCH_MNT +DEV PATH : HOSTNAME:SCRATCH_DEV +LABEL : session.0 +TIME OF DUMP : TIME +------------------------------------------------- + + Session 1: HOSTNAME:SCRATCH_MNT +------------------------------------------------- +Pruning this matching entry: +UUID : ID +MOUNT POINT : HOSTNAME:SCRATCH_MNT +DEV PATH : HOSTNAME:SCRATCH_DEV +LABEL : session.1 +TIME OF DUMP : TIME +------------------------------------------------- + + Session 2: HOSTNAME:SCRATCH_MNT +------------------------------------------------- +Pruning this matching entry: +UUID : ID +MOUNT POINT : HOSTNAME:SCRATCH_MNT +DEV PATH : HOSTNAME:SCRATCH_DEV +LABEL : session.2 +TIME OF DUMP : TIME +------------------------------------------------- + + Session 3: HOSTNAME:SCRATCH_MNT + Session 4: HOSTNAME:SCRATCH_MNT +file system 0: + fs id: ID + session 0: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.3" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID + session 1: + mount point: HOSTNAME:SCRATCH_MNT + device: HOSTNAME:SCRATCH_DEV + time: TIME + session label: "session.4" + session id: ID + level: 0 + resumed: NO + subtree: NO + streams: 1 + stream 0: + pathname: DUMP_FILE + start: ino INO offset 0 + end: ino INO offset 0 + interrupted: NO + media files: 1 + media file 0: + mfile index: 0 + mfile type: data + mfile size: NUM + mfile start: ino INO offset 0 + mfile end: ino INO offset 0 + media label: "stress_tape_media" + media id: ID diff -rNu linux-2.4.7/cmd/xfstests/029 linux-2.4-xfs/cmd/xfstests/029 --- linux-2.4.7/cmd/xfstests/029 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/029 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,85 @@ +#! /bin/sh +# XFS QA Test No. 029 +# $Id: 1.1 $ +# +# exercise mkfs log (internal/external) zeroing +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=nathans@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +mkfs_args="" +logp_args="" +if [ ! -z "$SCRATCH_LOGDEV" ] # test external log if possible +then + mkfs_args="-l logdev=$SCRATCH_LOGDEV,size=1200b" + logp_args="-l $SCRATCH_LOGDEV" +fi + +_filter_logprint() +{ + perl -ne ' + s/data device: ([\w|\/]+)/data device: DDEV/; + s/log device: ([\w|\/]+) daddr: (\d+) length: (\d+)/log device: LDEV daddr: XXX length: XXX/; + s/log file: "([\w|\/]+)" daddr: (\d+) length: (\d+)/log device: LDEV daddr: XXX length: XXX/; + s/skipped (\w+) zeroed blocks/skipped XXX zeroed blocks/; + s/^uuid: *[0-9a-f-][0-9a-f-]* *format: *.*$/uuid: format: /; + print; + ' +} + +# real QA test starts here +# +_require_scratch + +echo +mkfs -t xfs -f $mkfs_args $SCRATCH_DEV | _filter_mkfs 2>/dev/null + +echo +xfs_logprint $logp_args $SCRATCH_DEV | _filter_logprint + +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/029.out linux-2.4-xfs/cmd/xfstests/029.out --- linux-2.4.7/cmd/xfstests/029.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/029.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,26 @@ +QA output created by 029 + +meta-data=DDEV isize=XXX agcount=N, agsize=XXX blks +data = bsize=XXX blocks=XXX, imaxpct=PCT + = sunit=XXX swidth=XXX, unwritten=X +naming =VERN bsize=XXX +log =LDEV bsize=XXX blocks=XXX +realtime =RDEV extsz=XXX blocks=XXX, rtextents=XXX + +xfs_logprint: + data device: DDEV + log device: LDEV daddr: XXX length: XXX + +cycle: 1 version: 1 lsn: 1,0 tail_lsn: 1,0 +length of Log Record: 20 prev offset: -1 num ops: 1 +uuid: format: +---------------------------------------------------------------------------- +Oper (0): tid: b0c0d0d0 len: 8 clientid: LOG flags: UNMOUNT +Unmount filesystem + +============================================================================ +xfs_logprint: skipped XXX zeroed blocks +xfs_logprint: physical end of log +============================================================================ +xfs_logprint: logical end of log +============================================================================ diff -rNu linux-2.4.7/cmd/xfstests/030 linux-2.4-xfs/cmd/xfstests/030 --- linux-2.4.7/cmd/xfstests/030 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/030 Mon Apr 23 02:37:39 2001 @@ -0,0 +1,111 @@ +#! /bin/sh +# XFS QA Test No. 030 +# $Id: 1.3 $ +# +# exercise xfs_repair repairing broken filesystems +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=nathans@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + umount $SCRATCH_DEV 2>/dev/null + rm -f $tmp.* +} + +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.repair + +# nuke the superblock, AGI, AGF, AGFL; then try repair the damage +# +_check_ag() +{ + for structure in 'sb 0' 'agf 0' 'agi 0' 'agfl 0' + do + echo "Corrupting $structure - setting bits to $1" + _check_repair $1 "$structure" + done +} + +# real QA test starts here +_require_scratch + +# first we need to ensure there are no bogus secondary +# superblocks between the primary and first secondary +# superblock (hanging around from earlier tests)... +# +size="-d size=100m" +mkfs -t xfs -f $size $SCRATCH_DEV >/dev/null 2>&1 +if [ $? -ne 0 ] # probably don't have a big enough scratch +then + _notrun "SCRATCH_DEV too small, results would be non-deterministic" +else + mount -t xfs $SCRATCH_DEV $SCRATCH_MNT + src/feature -U $SCRATCH_DEV && \ + _notrun "Quota are enabled, test needs controlled sb recovery" + src/feature -G $SCRATCH_DEV && \ + _notrun "Quota are enabled, test needs controlled sb recovery" + umount $SCRATCH_DEV +fi +clear="" +eval `xfs_db -r -c "sb 1" -c stack $SCRATCH_DEV | perl -ne ' + if (/byte offset (\d+), length (\d+)/) { + print "clear=", $1 / 512, "\n"; exit + }'` +[ -z "$clear" ] && echo "Cannot calculate length to clear" +src/devzero -v -1 -n "$clear" $SCRATCH_DEV >/dev/null + +# now kick off the real repair test... +# +mkfs -t xfs -f $size $SCRATCH_DEV | _filter_mkfs 2>$tmp.mkfs +source $tmp.mkfs +_check_ag 0 +_check_ag -1 + + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/030.out linux-2.4-xfs/cmd/xfstests/030.out --- linux-2.4.7/cmd/xfstests/030.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/030.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,295 @@ +QA output created by 030 +meta-data=DDEV isize=XXX agcount=N, agsize=XXX blks +data = bsize=XXX blocks=XXX, imaxpct=PCT + = sunit=XXX swidth=XXX, unwritten=X +naming =VERN bsize=XXX +log =LDEV bsize=XXX blocks=XXX +realtime =RDEV extsz=XXX blocks=XXX, rtextents=XXX +Corrupting sb 0 - setting bits to 0 +Wrote 0.50Kb (value 0x0) +Phase 1 - find and verify superblock... +bad primary superblock - bad magic number !!! + +attempting to find secondary superblock... +found candidate secondary superblock... +verified secondary superblock... +writing modified primary superblock +sb root inode value INO inconsistent with calculated value INO +resetting superblock root inode pointer to INO +sb realtime bitmap inode INO inconsistent with calculated value INO +resetting superblock realtime bitmap ino pointer to INO +sb realtime summary inode INO inconsistent with calculated value INO +resetting superblock realtime summary ino pointer to INO +Phase 2 - using internal log + - zero log... + - scan filesystem freespace and inode maps... + - found root inode chunk +Phase 3 - for each AG... + - scan and clear agi unlinked lists... + - process known inodes and perform inode discovery... + - process newly discovered inodes... +Phase 4 - check for duplicate blocks... + - setting up duplicate extent list... + - clear lost+found (if it exists) ... + - check for inodes claiming duplicate blocks... +Phase 5 - rebuild AG headers and trees... + - reset superblock... +Phase 6 - check inode connectivity... + - resetting contents of realtime bitmap and summary inodes + - ensuring existence of lost+found directory + - traversing filesystem starting at / ... + - traversal finished ... + - traversing all unattached subtrees ... + - traversals finished ... + - moving disconnected inodes to lost+found ... +Phase 7 - verify and correct link counts... +Note - stripe unit (0) and width (0) fields have been reset. +Please set with mount -o sunit=,swidth= +done +Corrupting agf 0 - setting bits to 0 +Wrote 0.50Kb (value 0x0) +Phase 1 - find and verify superblock... +Phase 2 - using internal log + - zero log... + - scan filesystem freespace and inode maps... +bad magic # 0x0 for agf 0 +bad version # 0 for agf 0 +bad length 0 for agf 0, should be LENGTH +reset bad agf for ag 0 +bad agbno AGBNO for btbno root, agno 0 +bad agbno AGBNO for btbcnt root, agno 0 + - found root inode chunk +Phase 3 - for each AG... + - scan and clear agi unlinked lists... + - process known inodes and perform inode discovery... + - process newly discovered inodes... +Phase 4 - check for duplicate blocks... + - setting up duplicate extent list... + - clear lost+found (if it exists) ... + - clearing existing "lost+found" inode + - deleting existing "lost+found" entry + - check for inodes claiming duplicate blocks... +Phase 5 - rebuild AG headers and trees... + - reset superblock... +Phase 6 - check inode connectivity... + - resetting contents of realtime bitmap and summary inodes + - ensuring existence of lost+found directory + - traversing filesystem starting at / ... + - traversal finished ... + - traversing all unattached subtrees ... + - traversals finished ... + - moving disconnected inodes to lost+found ... +Phase 7 - verify and correct link counts... +done +Corrupting agi 0 - setting bits to 0 +Wrote 0.50Kb (value 0x0) +Phase 1 - find and verify superblock... +Phase 2 - using internal log + - zero log... + - scan filesystem freespace and inode maps... +bad magic # 0x0 for agi 0 +bad version # 0 for agi 0 +bad length # 0 for agi 0, should be LENGTH +reset bad agi for ag 0 +bad agbno AGBNO for inobt root, agno 0 +root inode chunk not found +Phase 3 - for each AG... + - scan and clear agi unlinked lists... +error following ag 0 unlinked list + - process known inodes and perform inode discovery... +imap claims in-use inode 131 is free, correcting imap + - process newly discovered inodes... +Phase 4 - check for duplicate blocks... + - setting up duplicate extent list... + - clear lost+found (if it exists) ... + - clearing existing "lost+found" inode + - deleting existing "lost+found" entry + - check for inodes claiming duplicate blocks... +Phase 5 - rebuild AG headers and trees... + - reset superblock... +Phase 6 - check inode connectivity... + - resetting contents of realtime bitmap and summary inodes + - ensuring existence of lost+found directory + - traversing filesystem starting at / ... + - traversal finished ... + - traversing all unattached subtrees ... + - traversals finished ... + - moving disconnected inodes to lost+found ... +Phase 7 - verify and correct link counts... +done +Corrupting agfl 0 - setting bits to 0 +Wrote 0.50Kb (value 0x0) +Phase 1 - find and verify superblock... +Phase 2 - using internal log + - zero log... + - scan filesystem freespace and inode maps... + - found root inode chunk +Phase 3 - for each AG... + - scan and clear agi unlinked lists... + - process known inodes and perform inode discovery... + - process newly discovered inodes... +Phase 4 - check for duplicate blocks... + - setting up duplicate extent list... + - clear lost+found (if it exists) ... + - clearing existing "lost+found" inode + - deleting existing "lost+found" entry + - check for inodes claiming duplicate blocks... +Phase 5 - rebuild AG headers and trees... + - reset superblock... +Phase 6 - check inode connectivity... + - resetting contents of realtime bitmap and summary inodes + - ensuring existence of lost+found directory + - traversing filesystem starting at / ... + - traversal finished ... + - traversing all unattached subtrees ... + - traversals finished ... + - moving disconnected inodes to lost+found ... +Phase 7 - verify and correct link counts... +done +Corrupting sb 0 - setting bits to -1 +Wrote 0.50Kb (value 0xffffffff) +Phase 1 - find and verify superblock... +bad primary superblock - bad magic number !!! + +attempting to find secondary superblock... +found candidate secondary superblock... +verified secondary superblock... +writing modified primary superblock +sb root inode value INO inconsistent with calculated value INO +resetting superblock root inode pointer to INO +sb realtime bitmap inode INO inconsistent with calculated value INO +resetting superblock realtime bitmap ino pointer to INO +sb realtime summary inode INO inconsistent with calculated value INO +resetting superblock realtime summary ino pointer to INO +Phase 2 - using internal log + - zero log... + - scan filesystem freespace and inode maps... + - found root inode chunk +Phase 3 - for each AG... + - scan and clear agi unlinked lists... + - process known inodes and perform inode discovery... + - process newly discovered inodes... +Phase 4 - check for duplicate blocks... + - setting up duplicate extent list... + - clear lost+found (if it exists) ... + - clearing existing "lost+found" inode + - deleting existing "lost+found" entry + - check for inodes claiming duplicate blocks... +Phase 5 - rebuild AG headers and trees... + - reset superblock... +Phase 6 - check inode connectivity... + - resetting contents of realtime bitmap and summary inodes + - ensuring existence of lost+found directory + - traversing filesystem starting at / ... + - traversal finished ... + - traversing all unattached subtrees ... + - traversals finished ... + - moving disconnected inodes to lost+found ... +Phase 7 - verify and correct link counts... +Note - stripe unit (0) and width (0) fields have been reset. +Please set with mount -o sunit=,swidth= +done +Corrupting agf 0 - setting bits to -1 +Wrote 0.50Kb (value 0xffffffff) +Phase 1 - find and verify superblock... +Phase 2 - using internal log + - zero log... + - scan filesystem freespace and inode maps... +bad magic # 0xffffffff for agf 0 +bad version # -1 for agf 0 +bad sequence # -1 for agf 0 +bad length -1 for agf 0, should be LENGTH +flfirst -1 in agf 0 too large (max = MAX) +fllast -1 in agf 0 too large (max = MAX) +reset bad agf for ag 0 +freeblk count 1 != flcount -1 in ag 0 +bad agbno AGBNO for btbno root, agno 0 +bad agbno AGBNO for btbcnt root, agno 0 + - found root inode chunk +Phase 3 - for each AG... + - scan and clear agi unlinked lists... + - process known inodes and perform inode discovery... + - process newly discovered inodes... +Phase 4 - check for duplicate blocks... + - setting up duplicate extent list... + - clear lost+found (if it exists) ... + - clearing existing "lost+found" inode + - deleting existing "lost+found" entry + - check for inodes claiming duplicate blocks... +Phase 5 - rebuild AG headers and trees... + - reset superblock... +Phase 6 - check inode connectivity... + - resetting contents of realtime bitmap and summary inodes + - ensuring existence of lost+found directory + - traversing filesystem starting at / ... + - traversal finished ... + - traversing all unattached subtrees ... + - traversals finished ... + - moving disconnected inodes to lost+found ... +Phase 7 - verify and correct link counts... +done +Corrupting agi 0 - setting bits to -1 +Wrote 0.50Kb (value 0xffffffff) +Phase 1 - find and verify superblock... +Phase 2 - using internal log + - zero log... + - scan filesystem freespace and inode maps... +bad magic # 0xffffffff for agi 0 +bad version # -1 for agi 0 +bad sequence # -1 for agi 0 +bad length # -1 for agi 0, should be LENGTH +reset bad agi for ag 0 +bad agbno AGBNO for inobt root, agno 0 +root inode chunk not found +Phase 3 - for each AG... + - scan and clear agi unlinked lists... + - process known inodes and perform inode discovery... +imap claims in-use inode 131 is free, correcting imap + - process newly discovered inodes... +Phase 4 - check for duplicate blocks... + - setting up duplicate extent list... + - clear lost+found (if it exists) ... + - clearing existing "lost+found" inode + - deleting existing "lost+found" entry + - check for inodes claiming duplicate blocks... +Phase 5 - rebuild AG headers and trees... + - reset superblock... +Phase 6 - check inode connectivity... + - resetting contents of realtime bitmap and summary inodes + - ensuring existence of lost+found directory + - traversing filesystem starting at / ... + - traversal finished ... + - traversing all unattached subtrees ... + - traversals finished ... + - moving disconnected inodes to lost+found ... +Phase 7 - verify and correct link counts... +done +Corrupting agfl 0 - setting bits to -1 +Wrote 0.50Kb (value 0xffffffff) +Phase 1 - find and verify superblock... +Phase 2 - using internal log + - zero log... + - scan filesystem freespace and inode maps... + - found root inode chunk +Phase 3 - for each AG... + - scan and clear agi unlinked lists... + - process known inodes and perform inode discovery... + - process newly discovered inodes... +Phase 4 - check for duplicate blocks... + - setting up duplicate extent list... + - clear lost+found (if it exists) ... + - clearing existing "lost+found" inode + - deleting existing "lost+found" entry + - check for inodes claiming duplicate blocks... +Phase 5 - rebuild AG headers and trees... + - reset superblock... +Phase 6 - check inode connectivity... + - resetting contents of realtime bitmap and summary inodes + - ensuring existence of lost+found directory + - traversing filesystem starting at / ... + - traversal finished ... + - traversing all unattached subtrees ... + - traversals finished ... + - moving disconnected inodes to lost+found ... +Phase 7 - verify and correct link counts... +done diff -rNu linux-2.4.7/cmd/xfstests/031 linux-2.4-xfs/cmd/xfstests/031 --- linux-2.4.7/cmd/xfstests/031 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/031 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,133 @@ +#! /bin/sh +# XFS QA Test No. 031 +# $Id: 1.1 $ +# +# exercise xfs_repair - ensure repeated use doesn't corrupt +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=nathans@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 +rm -f $seq.full + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_check_repair() +{ + xfs_repair $SCRATCH_DEV >$tmp.0 2>&1 + for i in 1 2 3 4 + do + echo "Repairing, iteration $i" | tee -a $seq.full + xfs_repair $SCRATCH_DEV 2>&1 | tee -a $seq.full >$tmp.$i + diff $tmp.0 $tmp.$i + # echo all interesting stuff... + perl -ne ' + s/(rebuilding directory inode) (\d+)/\1 INO/g; + /^\S+/ && print; + ' $tmp.$i + done + echo +} + +# prototype file to create various directory forms +_create_proto() +{ + total=$1 + count=0 + + cat >$tmp.proto <>$tmp.proto <>$tmp.proto +} + +# real QA test starts here +# +_require_scratch + +MKFSV1="-t xfs -f -p $tmp.proto -n version=1 $SCRATCH_DEV" +MKFSV2="-t xfs -f -p $tmp.proto -n version=2 $SCRATCH_DEV" + +# sanity test - default + one root directory entry +_create_proto 0 +echo "=== version 1, one entry" +mkfs $MKFSV1 | _filter_mkfs >/dev/null 2>&1 +_check_repair +echo "=== version 2, one entry (shortform)" +mkfs $MKFSV2 | _filter_mkfs >/dev/null 2>&1 +_check_repair + +# block-form root directory & repeat +_create_proto 20 +echo "=== version 1, twenty entries" +mkfs $MKFSV1 | _filter_mkfs >/dev/null 2>&1 +_check_repair +echo "=== version 2, twenty entries (block form)" +mkfs $MKFSV2 | _filter_mkfs >/dev/null 2>&1 +_check_repair + +# leaf-form root directory & repeat +_create_proto 1000 +echo "=== version 1, thousand entries" +mkfs $MKFSV1 | _filter_mkfs >/dev/null 2>&1 +_check_repair +echo "=== version 2, thousand entries (leaf form)" +mkfs $MKFSV2 | _filter_mkfs >/dev/null 2>&1 +_check_repair + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/031.out linux-2.4-xfs/cmd/xfstests/031.out --- linux-2.4.7/cmd/xfstests/031.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/031.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,237 @@ +QA output created by 031 +=== version 1, one entry +Repairing, iteration 1 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done +Repairing, iteration 2 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done +Repairing, iteration 3 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done +Repairing, iteration 4 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done + +=== version 2, one entry (shortform) +Repairing, iteration 1 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done +Repairing, iteration 2 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done +Repairing, iteration 3 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done +Repairing, iteration 4 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done + +=== version 1, twenty entries +Repairing, iteration 1 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done +Repairing, iteration 2 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done +Repairing, iteration 3 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done +Repairing, iteration 4 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done + +=== version 2, twenty entries (block form) +Repairing, iteration 1 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +rebuilding directory inode INO +Phase 7 - verify and correct link counts... +done +Repairing, iteration 2 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +rebuilding directory inode INO +Phase 7 - verify and correct link counts... +done +Repairing, iteration 3 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +rebuilding directory inode INO +Phase 7 - verify and correct link counts... +done +Repairing, iteration 4 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +rebuilding directory inode INO +Phase 7 - verify and correct link counts... +done + +=== version 1, thousand entries +Repairing, iteration 1 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done +Repairing, iteration 2 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done +Repairing, iteration 3 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done +Repairing, iteration 4 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +Phase 7 - verify and correct link counts... +done + +=== version 2, thousand entries (leaf form) +Repairing, iteration 1 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +rebuilding directory inode INO +Phase 7 - verify and correct link counts... +done +Repairing, iteration 2 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +rebuilding directory inode INO +Phase 7 - verify and correct link counts... +done +Repairing, iteration 3 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +rebuilding directory inode INO +Phase 7 - verify and correct link counts... +done +Repairing, iteration 4 +Phase 1 - find and verify superblock... +Phase 2 - using internal log +Phase 3 - for each AG... +Phase 4 - check for duplicate blocks... +Phase 5 - rebuild AG headers and trees... +Phase 6 - check inode connectivity... +rebuilding directory inode INO +Phase 7 - verify and correct link counts... +done + diff -rNu linux-2.4.7/cmd/xfstests/032 linux-2.4-xfs/cmd/xfstests/032 --- linux-2.4.7/cmd/xfstests/032 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/032 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,89 @@ +#! /bin/sh +# XFS QA Test No. 032 +# $Id: 1.1 $ +# +# cross check mkfs detection of foreign filesystems +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=nathans@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 +rm -f $seq.full + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# real QA test starts here +# +_require_scratch + +echo "Silence is golden." +for fs in `echo /sbin/mkfs.* | sed -e 's/.sbin.mkfs.//g'` +do + preop="" # for special input needs + preargs="" # for any special pre-device options + postargs="" # for any special post-device options + + # minix mkfs fails for large devices, restrict to 2000 blocks + [ $fs = "minix" ] && postargs=2000 + # these folk prompt before writing + [ $fs = "jfs" ] && preop="echo Y |" + [ $fs = "reiserfs" ] && preop="echo y |" + + # overwite the first few Kb - should blow away superblocks + src/devzero -n 20 $SCRATCH_DEV >/dev/null + + # create a filesystem of this type + echo "=== Creating $fs filesystem..." >>$seq.full + echo " ( mkfs -t $fs $SCRATCH_DEV )" >>$seq.full + eval $preop mkfs -t $fs $preargs $SCRATCH_DEV $postargs >>$seq.full 2>&1 + + # next, ensure we don't overwrite it + echo "=== Attempting XFS overwrite of $fs..." >>$seq.full + mkfs -t xfs $SCRATCH_DEV >>$seq.full 2>&1 + + [ $? -eq 0 ] && echo "Failed - overwrote fs type ${fs}!" +done + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/032.out linux-2.4-xfs/cmd/xfstests/032.out --- linux-2.4.7/cmd/xfstests/032.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/032.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,2 @@ +QA output created by 032 +Silence is golden. diff -rNu linux-2.4.7/cmd/xfstests/033 linux-2.4-xfs/cmd/xfstests/033 --- linux-2.4.7/cmd/xfstests/033 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/033 Mon Apr 23 02:37:39 2001 @@ -0,0 +1,96 @@ +#! /bin/sh +# XFS QA Test No. 033 +# $Id: 1.1 $ +# +# exercise xfs_repair repairing broken filesystems (root inodes) +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=nathans@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + umount $SCRATCH_DEV 2>/dev/null + rm -f $tmp.* +} + +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.repair + +# nuke the root, rt bitmap, and rt summary inodes +# +_check_root_inos() +{ + echo "Corrupting root inode - setting bits to $1" + _check_repair $1 "inode $rootino" + echo "Corrupting rt bitmap inode - setting bits to $1" + _check_repair $1 "inode $rbmino" + echo "Corrupting rt summary inode - setting bits to $1" + _check_repair $1 "inode $rsumino" +} + +# real QA test starts here +_require_scratch + +# devzero blows away 512byte blocks, so make 512byte inodes +mkfs -t xfs -f -i size=512 $SCRATCH_DEV | _filter_mkfs 2>/dev/null +`xfs_db -r -c sb -c p $SCRATCH_DEV | grep 'ino = ' | \ + sed -e 's/ //g' -e 's/^/export /'` + +# check we won't get any quota inodes setup on mount +mount -t xfs $SCRATCH_DEV $SCRATCH_MNT +src/feature -U $SCRATCH_DEV && \ + _notrun "Quota are enabled, test needs controlled sb recovery" +src/feature -G $SCRATCH_DEV && \ + _notrun "Quota are enabled, test needs controlled sb recovery" +umount $SCRATCH_DEV + +# rootino, rbmino, and rsumino are now set (lets blow em away!) +_check_root_inos 0 +_check_root_inos -1 + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/033.out linux-2.4-xfs/cmd/xfstests/033.out --- linux-2.4.7/cmd/xfstests/033.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/033.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,229 @@ +QA output created by 033 +meta-data=DDEV isize=XXX agcount=N, agsize=XXX blks +data = bsize=XXX blocks=XXX, imaxpct=PCT + = sunit=XXX swidth=XXX, unwritten=X +naming =VERN bsize=XXX +log =LDEV bsize=XXX blocks=XXX +realtime =RDEV extsz=XXX blocks=XXX, rtextents=XXX +Corrupting root inode - setting bits to 0 +Wrote 0.50Kb (value 0x0) +Phase 1 - find and verify superblock... +Phase 2 - using internal log + - zero log... + - scan filesystem freespace and inode maps... + - found root inode chunk +Phase 3 - for each AG... + - scan and clear agi unlinked lists... + - process known inodes and perform inode discovery... +bad magic number 0x0 on inode INO +bad version number 0x0 on inode INO +bad magic number 0x0 on inode INO, resetting magic number +bad version number 0x0 on inode INO, resetting version number +imap claims a free inode INO is in use, correcting imap and clearing inode +cleared root inode INO + - process newly discovered inodes... +Phase 4 - check for duplicate blocks... + - setting up duplicate extent list... +root inode lost + - clear lost+found (if it exists) ... + - check for inodes claiming duplicate blocks... +Phase 5 - rebuild AG headers and trees... + - reset superblock... +Phase 6 - check inode connectivity... +reinitializing root directory + - resetting contents of realtime bitmap and summary inodes + - ensuring existence of lost+found directory + - traversing filesystem starting at / ... + - traversal finished ... + - traversing all unattached subtrees ... + - traversals finished ... + - moving disconnected inodes to lost+found ... +Phase 7 - verify and correct link counts... +resetting inode INO nlinks from 2 to 3 +done +Corrupting rt bitmap inode - setting bits to 0 +Wrote 0.50Kb (value 0x0) +Phase 1 - find and verify superblock... +Phase 2 - using internal log + - zero log... + - scan filesystem freespace and inode maps... + - found root inode chunk +Phase 3 - for each AG... + - scan and clear agi unlinked lists... + - process known inodes and perform inode discovery... +bad magic number 0x0 on inode INO +bad version number 0x0 on inode INO +bad magic number 0x0 on inode INO, resetting magic number +bad version number 0x0 on inode INO, resetting version number +imap claims a free inode INO is in use, correcting imap and clearing inode +cleared realtime bitmap inode INO + - process newly discovered inodes... +Phase 4 - check for duplicate blocks... + - setting up duplicate extent list... + - clear lost+found (if it exists) ... + - clearing existing "lost+found" inode + - deleting existing "lost+found" entry + - check for inodes claiming duplicate blocks... +Phase 5 - rebuild AG headers and trees... + - reset superblock... +Phase 6 - check inode connectivity... +reinitializing realtime bitmap inode + - resetting contents of realtime bitmap and summary inodes + - ensuring existence of lost+found directory + - traversing filesystem starting at / ... + - traversal finished ... + - traversing all unattached subtrees ... + - traversals finished ... + - moving disconnected inodes to lost+found ... +Phase 7 - verify and correct link counts... +done +Corrupting rt summary inode - setting bits to 0 +Wrote 0.50Kb (value 0x0) +Phase 1 - find and verify superblock... +Phase 2 - using internal log + - zero log... + - scan filesystem freespace and inode maps... + - found root inode chunk +Phase 3 - for each AG... + - scan and clear agi unlinked lists... + - process known inodes and perform inode discovery... +bad magic number 0x0 on inode INO +bad version number 0x0 on inode INO +bad magic number 0x0 on inode INO, resetting magic number +bad version number 0x0 on inode INO, resetting version number +imap claims a free inode INO is in use, correcting imap and clearing inode +cleared realtime summary inode INO + - process newly discovered inodes... +Phase 4 - check for duplicate blocks... + - setting up duplicate extent list... + - clear lost+found (if it exists) ... + - clearing existing "lost+found" inode + - deleting existing "lost+found" entry + - check for inodes claiming duplicate blocks... +Phase 5 - rebuild AG headers and trees... + - reset superblock... +Phase 6 - check inode connectivity... +reinitializing realtime summary inode + - resetting contents of realtime bitmap and summary inodes + - ensuring existence of lost+found directory + - traversing filesystem starting at / ... + - traversal finished ... + - traversing all unattached subtrees ... + - traversals finished ... + - moving disconnected inodes to lost+found ... +Phase 7 - verify and correct link counts... +done +Corrupting root inode - setting bits to -1 +Wrote 0.50Kb (value 0xffffffff) +Phase 1 - find and verify superblock... +Phase 2 - using internal log + - zero log... + - scan filesystem freespace and inode maps... + - found root inode chunk +Phase 3 - for each AG... + - scan and clear agi unlinked lists... + - process known inodes and perform inode discovery... +bad magic number 0xffff on inode INO +bad version number 0xffffffff on inode INO +bad (negative) size -1 on inode INO +bad magic number 0xffff on inode INO, resetting magic number +bad version number 0xffffffff on inode INO, resetting version number +bad (negative) size -1 on inode INO +cleared root inode INO + - process newly discovered inodes... +Phase 4 - check for duplicate blocks... + - setting up duplicate extent list... +root inode lost + - clear lost+found (if it exists) ... + - check for inodes claiming duplicate blocks... +Phase 5 - rebuild AG headers and trees... + - reset superblock... +Phase 6 - check inode connectivity... +reinitializing root directory + - resetting contents of realtime bitmap and summary inodes + - ensuring existence of lost+found directory + - traversing filesystem starting at / ... + - traversal finished ... + - traversing all unattached subtrees ... + - traversals finished ... + - moving disconnected inodes to lost+found ... +disconnected dir inode INO, moving to lost+found +Phase 7 - verify and correct link counts... +resetting inode INO nlinks from 2 to 3 +done +Corrupting rt bitmap inode - setting bits to -1 +Wrote 0.50Kb (value 0xffffffff) +Phase 1 - find and verify superblock... +Phase 2 - using internal log + - zero log... + - scan filesystem freespace and inode maps... + - found root inode chunk +Phase 3 - for each AG... + - scan and clear agi unlinked lists... + - process known inodes and perform inode discovery... +bad magic number 0xffff on inode INO +bad version number 0xffffffff on inode INO +bad (negative) size -1 on inode INO +bad magic number 0xffff on inode INO, resetting magic number +bad version number 0xffffffff on inode INO, resetting version number +bad (negative) size -1 on inode INO +cleared realtime bitmap inode INO + - process newly discovered inodes... +Phase 4 - check for duplicate blocks... + - setting up duplicate extent list... + - clear lost+found (if it exists) ... + - clearing existing "lost+found" inode + - deleting existing "lost+found" entry + - check for inodes claiming duplicate blocks... +Phase 5 - rebuild AG headers and trees... + - reset superblock... +Phase 6 - check inode connectivity... +reinitializing realtime bitmap inode + - resetting contents of realtime bitmap and summary inodes + - ensuring existence of lost+found directory + - traversing filesystem starting at / ... + - traversal finished ... + - traversing all unattached subtrees ... + - traversals finished ... + - moving disconnected inodes to lost+found ... +disconnected dir inode INO, moving to lost+found +Phase 7 - verify and correct link counts... +done +Corrupting rt summary inode - setting bits to -1 +Wrote 0.50Kb (value 0xffffffff) +Phase 1 - find and verify superblock... +Phase 2 - using internal log + - zero log... + - scan filesystem freespace and inode maps... + - found root inode chunk +Phase 3 - for each AG... + - scan and clear agi unlinked lists... + - process known inodes and perform inode discovery... +bad magic number 0xffff on inode INO +bad version number 0xffffffff on inode INO +bad (negative) size -1 on inode INO +bad magic number 0xffff on inode INO, resetting magic number +bad version number 0xffffffff on inode INO, resetting version number +bad (negative) size -1 on inode INO +cleared realtime summary inode INO + - process newly discovered inodes... +Phase 4 - check for duplicate blocks... + - setting up duplicate extent list... + - clear lost+found (if it exists) ... + - clearing existing "lost+found" inode + - deleting existing "lost+found" entry + - check for inodes claiming duplicate blocks... +Phase 5 - rebuild AG headers and trees... + - reset superblock... +Phase 6 - check inode connectivity... +reinitializing realtime summary inode + - resetting contents of realtime bitmap and summary inodes + - ensuring existence of lost+found directory + - traversing filesystem starting at / ... + - traversal finished ... + - traversing all unattached subtrees ... + - traversals finished ... + - moving disconnected inodes to lost+found ... +disconnected dir inode INO, moving to lost+found +Phase 7 - verify and correct link counts... +done diff -rNu linux-2.4.7/cmd/xfstests/034 linux-2.4-xfs/cmd/xfstests/034 --- linux-2.4.7/cmd/xfstests/034 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/034 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,104 @@ +#! /bin/sh +# XFS QA Test No. 034 +# $Id: 1.1 $ +# +# pv 801241 - check for reference leaks from the *handle ioctls +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=root@leesa.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + echo "*** unmount" + umount $SCRATCH_MNT 2>/dev/null +} +trap "_cleanup; rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# real QA test starts here + +_require_scratch + +echo "*** init FS" + +rm -f $seq.full +umount $SCRATCH_DEV >/dev/null 2>&1 +echo "*** MKFS ***" >>$seq.full +echo "" >>$seq.full +mkfs -t xfs -f $SCRATCH_DEV >>$seq.full 2>&1 \ + || _fail "mkfs failed" +mount -t xfs $SCRATCH_DEV $SCRATCH_MNT >>$seq.full 2>&1 \ + || _fail "mount failed" + +echo "*** test" + +_check_fs $SCRATCH_DEV + +if ! touch $SCRATCH_MNT/fish +then + echo "!!! failed to touch fish" + exit +fi + +if ! src/ioctl $SCRATCH_MNT $SCRATCH_MNT/fish >/dev/null 2>&1 +then + echo "!!! failed to run ioctl test program" + exit +fi + +if ! rm $SCRATCH_MNT/fish +then + echo "!!! failed to remove fish" + exit +fi + +# pv 801241 causes corruption here (inode left in agi_unlinked list) +_check_fs $SCRATCH_DEV + +echo "*** done" +# happy exit +rm -f $seq.full +status=0 +exit 0 diff -rNu linux-2.4.7/cmd/xfstests/034.out linux-2.4-xfs/cmd/xfstests/034.out --- linux-2.4.7/cmd/xfstests/034.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/034.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,5 @@ +QA output created by 034 +*** init FS +*** test +*** done +*** unmount diff -rNu linux-2.4.7/cmd/xfstests/035 linux-2.4-xfs/cmd/xfstests/035 --- linux-2.4.7/cmd/xfstests/035 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/035 Thu Feb 1 22:31:55 2001 @@ -0,0 +1,68 @@ +#! /bin/sh +# XFS QA Test No. 035 +# $Id: 1.1 $ +# +# Test doing multiple dumps to tape and restoring the 2nd one +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sagan.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +_require_tape $TAPE_DEV +_create_dumpdir_fill +_erase_hard +_do_dump -L $seq.1 +_rewind +_create_dumpdir_fill2 +_do_dump -L $seq.2 +_do_restore -L $seq.2 +_diff_compare + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/035.grpquota linux-2.4-xfs/cmd/xfstests/035.grpquota --- linux-2.4.7/cmd/xfstests/035.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/035.grpquota Thu May 24 00:36:12 2001 @@ -0,0 +1,102 @@ +QA output created by 035 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L 035.1 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "035.1" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Creating directory system to dump using src/fill. +Setup .... +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L 035.2 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "035.2" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: preparing drive +xfsdump: positioned at media file 0: dump 0, stream 0 +xfsdump: positioned at media file 1: dump 0, stream 0 +xfsdump: positioned at media file 2: dump 0, stream 0 +xfsdump: stream terminator found +xfsdump: creating dump session media file 0 (media 0, file 2) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 3) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 4) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L 035.2 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: examining media file 1 +xfsrestore: examining media file 2 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/biggg and RESTORE_DIR/DUMP_SUBDIR/biggg are identical +Files DUMP_DIR/smalll and RESTORE_DIR/DUMP_SUBDIR/smalll are identical +Files DUMP_DIR/sub/biggg and RESTORE_DIR/DUMP_SUBDIR/sub/biggg are identical +Files DUMP_DIR/sub/smalll and RESTORE_DIR/DUMP_SUBDIR/sub/smalll are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/035.noquota linux-2.4-xfs/cmd/xfstests/035.noquota --- linux-2.4.7/cmd/xfstests/035.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/035.noquota Thu May 24 00:36:12 2001 @@ -0,0 +1,98 @@ +QA output created by 035 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L 035.1 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "035.1" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Creating directory system to dump using src/fill. +Setup .... +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L 035.2 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "035.2" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: preparing drive +xfsdump: positioned at media file 0: dump 0, stream 0 +xfsdump: positioned at media file 1: dump 0, stream 0 +xfsdump: positioned at media file 2: dump 0, stream 0 +xfsdump: stream terminator found +xfsdump: creating dump session media file 0 (media 0, file 2) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 3) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 4) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L 035.2 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: examining media file 1 +xfsrestore: examining media file 2 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/biggg and RESTORE_DIR/DUMP_SUBDIR/biggg are identical +Files DUMP_DIR/smalll and RESTORE_DIR/DUMP_SUBDIR/smalll are identical +Files DUMP_DIR/sub/biggg and RESTORE_DIR/DUMP_SUBDIR/sub/biggg are identical +Files DUMP_DIR/sub/smalll and RESTORE_DIR/DUMP_SUBDIR/sub/smalll are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR diff -rNu linux-2.4.7/cmd/xfstests/035.ugquota linux-2.4-xfs/cmd/xfstests/035.ugquota --- linux-2.4.7/cmd/xfstests/035.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/035.ugquota Thu May 24 00:36:12 2001 @@ -0,0 +1,106 @@ +QA output created by 035 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L 035.1 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "035.1" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Creating directory system to dump using src/fill. +Setup .... +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L 035.2 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "035.2" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: preparing drive +xfsdump: positioned at media file 0: dump 0, stream 0 +xfsdump: positioned at media file 1: dump 0, stream 0 +xfsdump: positioned at media file 2: dump 0, stream 0 +xfsdump: stream terminator found +xfsdump: creating dump session media file 0 (media 0, file 2) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 3) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 4) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L 035.2 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: examining media file 1 +xfsrestore: examining media file 2 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/biggg and RESTORE_DIR/DUMP_SUBDIR/biggg are identical +Files DUMP_DIR/smalll and RESTORE_DIR/DUMP_SUBDIR/smalll are identical +Files DUMP_DIR/sub/biggg and RESTORE_DIR/DUMP_SUBDIR/sub/biggg are identical +Files DUMP_DIR/sub/smalll and RESTORE_DIR/DUMP_SUBDIR/sub/smalll are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/035.usrquota linux-2.4-xfs/cmd/xfstests/035.usrquota --- linux-2.4.7/cmd/xfstests/035.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/035.usrquota Thu May 24 00:36:12 2001 @@ -0,0 +1,102 @@ +QA output created by 035 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L 035.1 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "035.1" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Creating directory system to dump using src/fill. +Setup .... +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L 035.2 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "035.2" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: preparing drive +xfsdump: positioned at media file 0: dump 0, stream 0 +xfsdump: positioned at media file 1: dump 0, stream 0 +xfsdump: positioned at media file 2: dump 0, stream 0 +xfsdump: stream terminator found +xfsdump: creating dump session media file 0 (media 0, file 2) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 3) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 4) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L 035.2 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: examining media file 1 +xfsrestore: examining media file 2 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/biggg and RESTORE_DIR/DUMP_SUBDIR/biggg are identical +Files DUMP_DIR/smalll and RESTORE_DIR/DUMP_SUBDIR/smalll are identical +Files DUMP_DIR/sub/biggg and RESTORE_DIR/DUMP_SUBDIR/sub/biggg are identical +Files DUMP_DIR/sub/smalll and RESTORE_DIR/DUMP_SUBDIR/sub/smalll are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas diff -rNu linux-2.4.7/cmd/xfstests/036 linux-2.4-xfs/cmd/xfstests/036 --- linux-2.4.7/cmd/xfstests/036 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/036 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,65 @@ +#! /bin/sh +# XFS QA Test No. 036 +# $Id: 1.1 $ +# +# Test xfsdump/restore minrmt to a remote IRIX tape +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sherman.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +_require_tape $RMT_IRIXTAPE_DEV +_create_dumpdir_fill +_erase_soft +_do_dump_min -o -F +_do_restore_min +_diff_compare + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/036.grpquota linux-2.4-xfs/cmd/xfstests/036.grpquota --- linux-2.4.7/cmd/xfstests/036.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/036.grpquota Thu May 24 00:36:12 2001 @@ -0,0 +1,87 @@ +QA output created by 036 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -m -b 1048576 -l0 -f TAPE_DEV -M stress_tape_media -L stress_036 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_036" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -m -b 1048576 -f TAPE_DEV -L stress_036 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/036.noquota linux-2.4-xfs/cmd/xfstests/036.noquota --- linux-2.4.7/cmd/xfstests/036.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/036.noquota Thu May 24 00:36:12 2001 @@ -0,0 +1,84 @@ +QA output created by 036 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -m -b 1048576 -l0 -f TAPE_DEV -M stress_tape_media -L stress_036 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_036" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -m -b 1048576 -f TAPE_DEV -L stress_036 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR diff -rNu linux-2.4.7/cmd/xfstests/036.ugquota linux-2.4-xfs/cmd/xfstests/036.ugquota --- linux-2.4.7/cmd/xfstests/036.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/036.ugquota Thu May 24 00:36:12 2001 @@ -0,0 +1,90 @@ +QA output created by 036 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -m -b 1048576 -l0 -f TAPE_DEV -M stress_tape_media -L stress_036 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_036" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -m -b 1048576 -f TAPE_DEV -L stress_036 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/036.usrquota linux-2.4-xfs/cmd/xfstests/036.usrquota --- linux-2.4.7/cmd/xfstests/036.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/036.usrquota Thu May 24 00:36:12 2001 @@ -0,0 +1,87 @@ +QA output created by 036 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -m -b 1048576 -l0 -f TAPE_DEV -M stress_tape_media -L stress_036 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_036" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -m -b 1048576 -f TAPE_DEV -L stress_036 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas diff -rNu linux-2.4.7/cmd/xfstests/037 linux-2.4-xfs/cmd/xfstests/037 --- linux-2.4.7/cmd/xfstests/037 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/037 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,65 @@ +#! /bin/sh +# XFS QA Test No. 037 +# $Id: 1.1 $ +# +# Test xfsdump/restore minrmt to a remote linux tape +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sherman.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +_require_tape $RMT_TAPE_DEV +_create_dumpdir_fill +_erase_soft +_do_dump_min -o -F +_do_restore_min +_diff_compare + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/037.grpquota linux-2.4-xfs/cmd/xfstests/037.grpquota --- linux-2.4.7/cmd/xfstests/037.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/037.grpquota Thu May 24 00:36:12 2001 @@ -0,0 +1,87 @@ +QA output created by 037 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -m -b 1048576 -l0 -f TAPE_DEV -M stress_tape_media -L stress_037 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_037" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -m -b 1048576 -f TAPE_DEV -L stress_037 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/037.noquota linux-2.4-xfs/cmd/xfstests/037.noquota --- linux-2.4.7/cmd/xfstests/037.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/037.noquota Thu May 24 00:36:12 2001 @@ -0,0 +1,84 @@ +QA output created by 037 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -m -b 1048576 -l0 -f TAPE_DEV -M stress_tape_media -L stress_037 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_037" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -m -b 1048576 -f TAPE_DEV -L stress_037 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR diff -rNu linux-2.4.7/cmd/xfstests/037.ugquota linux-2.4-xfs/cmd/xfstests/037.ugquota --- linux-2.4.7/cmd/xfstests/037.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/037.ugquota Thu May 24 00:36:12 2001 @@ -0,0 +1,90 @@ +QA output created by 037 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -m -b 1048576 -l0 -f TAPE_DEV -M stress_tape_media -L stress_037 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_037" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -m -b 1048576 -f TAPE_DEV -L stress_037 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/037.usrquota linux-2.4-xfs/cmd/xfstests/037.usrquota --- linux-2.4.7/cmd/xfstests/037.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/037.usrquota Thu May 24 00:36:12 2001 @@ -0,0 +1,87 @@ +QA output created by 037 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -m -b 1048576 -l0 -f TAPE_DEV -M stress_tape_media -L stress_037 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_037" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -m -b 1048576 -f TAPE_DEV -L stress_037 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas diff -rNu linux-2.4.7/cmd/xfstests/038 linux-2.4-xfs/cmd/xfstests/038 --- linux-2.4.7/cmd/xfstests/038 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/038 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,65 @@ +#! /bin/sh +# XFS QA Test No. 038 +# $Id: 1.1 $ +# +# Test xfsdump/restore to a remote linux tape +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sherman.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +_require_tape $RMT_TAPE_DEV +_create_dumpdir_fill +_erase_hard +_do_dump +_do_restore +_diff_compare + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/038.grpquota linux-2.4-xfs/cmd/xfstests/038.grpquota --- linux-2.4.7/cmd/xfstests/038.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/038.grpquota Thu May 24 00:36:12 2001 @@ -0,0 +1,91 @@ +QA output created by 038 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L stress_038 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_038" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 245760 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_038 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/038.noquota linux-2.4-xfs/cmd/xfstests/038.noquota --- linux-2.4.7/cmd/xfstests/038.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/038.noquota Thu May 24 00:36:12 2001 @@ -0,0 +1,88 @@ +QA output created by 038 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L stress_038 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_038" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 245760 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_038 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR diff -rNu linux-2.4.7/cmd/xfstests/038.ugquota linux-2.4-xfs/cmd/xfstests/038.ugquota --- linux-2.4.7/cmd/xfstests/038.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/038.ugquota Thu May 24 00:36:12 2001 @@ -0,0 +1,94 @@ +QA output created by 038 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L stress_038 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_038" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 245760 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_038 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/038.usrquota linux-2.4-xfs/cmd/xfstests/038.usrquota --- linux-2.4.7/cmd/xfstests/038.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/038.usrquota Thu May 24 00:36:12 2001 @@ -0,0 +1,91 @@ +QA output created by 038 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -l0 -f TAPE_DEV -M stress_tape_media -L stress_038 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_038" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 245760 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_038 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas diff -rNu linux-2.4.7/cmd/xfstests/039 linux-2.4-xfs/cmd/xfstests/039 --- linux-2.4.7/cmd/xfstests/039 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/039 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,65 @@ +#! /bin/sh +# XFS QA Test No. 039 +# $Id: 1.1 $ +# +# Test xfsdump/restore to a remote IRIX tape +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sherman.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +_require_tape $RMT_IRIXTAPE_DEV +_create_dumpdir_fill +_erase_soft +_do_dump -o -F +_do_restore +_diff_compare + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/039.grpquota linux-2.4-xfs/cmd/xfstests/039.grpquota --- linux-2.4.7/cmd/xfstests/039.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/039.grpquota Thu May 24 00:36:12 2001 @@ -0,0 +1,92 @@ +QA output created by 039 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -l0 -f TAPE_DEV -M stress_tape_media -L stress_039 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_039" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 245760 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_039 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/039.noquota linux-2.4-xfs/cmd/xfstests/039.noquota --- linux-2.4.7/cmd/xfstests/039.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/039.noquota Thu May 24 00:36:12 2001 @@ -0,0 +1,89 @@ +QA output created by 039 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -l0 -f TAPE_DEV -M stress_tape_media -L stress_039 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_039" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 245760 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_039 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR diff -rNu linux-2.4.7/cmd/xfstests/039.ugquota linux-2.4-xfs/cmd/xfstests/039.ugquota --- linux-2.4.7/cmd/xfstests/039.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/039.ugquota Thu May 24 00:36:12 2001 @@ -0,0 +1,95 @@ +QA output created by 039 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -l0 -f TAPE_DEV -M stress_tape_media -L stress_039 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_039" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 245760 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_039 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/039.usrquota linux-2.4-xfs/cmd/xfstests/039.usrquota --- linux-2.4.7/cmd/xfstests/039.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/039.usrquota Thu May 24 00:36:12 2001 @@ -0,0 +1,92 @@ +QA output created by 039 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -l0 -f TAPE_DEV -M stress_tape_media -L stress_039 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_039" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 245760 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_039 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas diff -rNu linux-2.4.7/cmd/xfstests/040 linux-2.4-xfs/cmd/xfstests/040 --- linux-2.4.7/cmd/xfstests/040 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/040 Fri Feb 23 21:45:21 2001 @@ -0,0 +1,83 @@ +#! /bin/sh +# XFS QA Test No. 040 +# $Id: 1.1 $ +# +# srcdiff test +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# real QA test starts here + +cd `pwd` + +if [ -z "$WORKAREA" ] +then + _notrun "Can't run srcdiff without WORKAREA set" +fi + +if [ ! -f $WORKAREA/cmd/xfstests/tools/srcdiff ] +then + _notrun "Can't find srcdiff tool under \"$WORKAREA\"" +fi + +if [ ! -d $WORKAREA/linux/fs/xfs ] +then + _notrun "Can't find XFS source under \"$WORKAREA\"" +fi + +if [ ! -d $WORKAREA/cmd/xfsprogs/include ] +then + _notrun "Can't find XFS command headers under \"$WORKAREA\"" +fi + +cd $WORKAREA/cmd/xfstests/tools +perl ./srcdiff -q + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/040.out linux-2.4-xfs/cmd/xfstests/040.out --- linux-2.4.7/cmd/xfstests/040.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/040.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,7 @@ +QA output created by 040 + +=== Checking headers === + +=== Checking libxfs code === + +=== Checking logprint code === diff -rNu linux-2.4.7/cmd/xfstests/041 linux-2.4-xfs/cmd/xfstests/041 --- linux-2.4.7/cmd/xfstests/041 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/041 Sun Apr 29 18:27:46 2001 @@ -0,0 +1,108 @@ +#! /bin/sh +# XFS QA Test No. 041 +# $Id: 041,v 1.3 2000/09/27 00:24:17 ajag Exp ajag $ +# +# growfs QA tests - repeatedly fill/grow the filesystem +# check the filesystem contents after each operation +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +set +x +# creator +owner=ajag@melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + umount $SCRATCH_MNT + rm -f $tmp.* +} +trap "_cleanup ; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# real QA test starts here + +_require_scratch + +_fill() +{ + if [ $# -ne 1 ]; then echo "Usage: _fill \"path\"" 1>&2 ; exit 1; fi + _do "Fill filesystem" \ + "src/fill2fs --verbose --dir=$1 --seed=0 --filesize=65536 --stddev=32768 --list=- >>$tmp.manifest" +} + +_do_die_on_error=message_only +rm -f $seq.full +#agsize=16 +agsize=32 +echo -n "Make $agsize megabyte filesystem on SCRATCH_DEV and mount... " +_do "mkfs -t xfs -d size=${agsize}m,agcount=1 -l internal -f $SCRATCH_DEV" +_do "mount -t xfs $SCRATCH_DEV $SCRATCH_MNT" +echo "done" + +# full allocation group -> partial; partial -> expand partial + new partial; +# partial -> expand partial; partial -> full +# 17 -> 33 -> 35 -> 48 megabytes, converted to fs blocks below +# for size in 4352 8448 8960 12288 +# 33 -> 67 -> 75 -> 96 converted to fs blocks: +for size in 8448 17512 19200 24576 +do + _fill $SCRATCH_MNT/fill_$size + _do "Grow filesystem to $size blocks" "xfs_growfs -D ${size} $SCRATCH_MNT" + echo -n "Flush filesystem... " + _do "umount $SCRATCH_MNT" + _do "mount -t xfs $SCRATCH_DEV $SCRATCH_MNT" + echo "done" + echo -n "Check files... " + if ! _do "src/fill2fs_check $tmp.manifest"; then + echo "fail (see $seq.full)" + _do "cat $tmp.manifest" + _do "ls -altrR $SCRATCH_MNT" + _do "dd if=$SCRATCH_DEV bs=4096 count=$size | gzip -9 > $seq.fsimage.gz" + status=1 ; exit + fi + echo "done" +done + +# success, all done +echo "Growfs tests passed." +status=0 ; exit diff -rNu linux-2.4.7/cmd/xfstests/041.out linux-2.4-xfs/cmd/xfstests/041.out --- linux-2.4.7/cmd/xfstests/041.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/041.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,19 @@ +QA output created by 041 +Make 32 megabyte filesystem on SCRATCH_DEV and mount... done +Fill filesystem... done +Grow filesystem to 8448 blocks... done +Flush filesystem... done +Check files... done +Fill filesystem... done +Grow filesystem to 17512 blocks... done +Flush filesystem... done +Check files... done +Fill filesystem... done +Grow filesystem to 19200 blocks... done +Flush filesystem... done +Check files... done +Fill filesystem... done +Grow filesystem to 24576 blocks... done +Flush filesystem... done +Check files... done +Growfs tests passed. diff -rNu linux-2.4.7/cmd/xfstests/042 linux-2.4-xfs/cmd/xfstests/042 --- linux-2.4.7/cmd/xfstests/042 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/042 Tue Apr 3 20:45:38 2001 @@ -0,0 +1,160 @@ +#! /bin/sh +# XFS QA Test No. 042 +# $Id: 042,v 1.2 2000/09/27 00:24:22 ajag Exp ajag $ +# +# xfs_fsr QA tests +# create a large fragmented file and check that xfs_fsr doesn't corrupt +# it or the other contents of the filesystem +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +set +x +# creator +owner=ajag@melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +_cleanup() +{ + umount $SCRATCH_MNT + rm -f $tmp.* +} +trap "_cleanup ; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# real QA test starts here + +_require_scratch + +_cull_files() +{ + perl -e "\$manifest=\"$tmp.manifest\";" -e ' + open MANIFEST, $manifest; + @in = ; + close MANIFEST; + open MANIFEST, ">$manifest"; + for ($i = 0; $i < @in; $i++) { + if (($i+1) % 2 == 0) { + # remove every second file + chomp($s = $in[$i]); + if (unlink($s) != 1) { + print "_cull_files: could not delete \"$s\"\n"; + exit(1); + } + } + else { + print MANIFEST $in[$i]; + } + } + close MANIFEST; + exit(0);' +} + +# create a large contiguous file using dd +# use fill2fs to fill the filesystem up with 4k sized files +# fill any remaining space using dd +# delete every second 4k file - remaining free space should be fragmented +# use fill2 to generate a very large file - run it until it fails producing a truncated file +# delete the dd-generated file +# run xfs_fsr on the filesystem +# check checksums for remaining files +# create 3 minimum sized (16Mb) allocation groups +# xfs_repair is going to need three to verify the superblock + +rm -f $seq.full +bmap_cmd="xfs_bmap -v" +mnt_cmd="mount -t xfs $SCRATCH_DEV $SCRATCH_MNT" +_do_die_on_error=message_only + +echo -n "Make a 48 megabyte filesystem on SCRATCH_DEV and mount... " +_do "mkfs -t xfs -d size=48m,agcount=3 -l internal -f $SCRATCH_DEV" +_do "$mnt_cmd" +echo "done" + +echo -n "Reserve 16 1Mb unfragmented regions... " +for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 +do + _do "dd if=/dev/zero of=$SCRATCH_MNT/hole$i bs=4096 count=256" + _do "dd if=/dev/zero of=$SCRATCH_MNT/space$i bs=4096 count=1" + _do "$bmap_cmd $SCRATCH_MNT/hole$i" +done +echo "done" + +# set up filesystem +echo -n "Fill filesystem with 4k files, generate manifest... " +fill_options="--verbose --seed=0 --filesize=4096 --stddev=0 --sync=1000000" +_do "src/fill2fs $fill_options --dir=$SCRATCH_MNT/fill --list=- > $tmp.manifest" +echo "done" +# flush the filesystem - make sure there is no space "lost" to pre-allocation +_do "umount $SCRATCH_MNT" +_do "$mnt_cmd" +echo -n "Use up any further available space using dd... " +_do "dd if=/dev/zero of=$SCRATCH_MNT/pad bs=4096" +echo "done" + +# create fragmented file +_do "Delete every second file" "_cull_files" +echo -n "Create one very large file... " +_do "src/fill2 -d nbytes=16000000,file=$SCRATCH_MNT/fragmented" +echo "done" +_do "$bmap_cmd $SCRATCH_MNT/fragmented" +_do "sum $SCRATCH_MNT/fragmented >$tmp.sum1" +_do "Remove other files" "rm -rf $SCRATCH_MNT/{pad,hole*}" + +# defragment +_do "Run xfs_fsr on filesystem" "xfs_fsr -v $SCRATCH_DEV" +_do "$bmap_cmd $SCRATCH_MNT/fragmented" +_do "Check 4k files" "src/fill2fs_check $tmp.manifest" + +# check +echo -n "Check large file... " +_do "sum $SCRATCH_MNT/fragmented >$tmp.sum2" +if ! _do "diff $tmp.sum1 $tmp.sum2"; then + echo "fail" + echo "File is corrupt/missing after fsr. Test failed see $seq.full" + status=1; exit +fi +echo "done" +_do "Checking filesystem" "_check_fs $SCRATCH_DEV" + +# success, all done +echo "xfs_fsr tests passed." +status=0 ; exit diff -rNu linux-2.4.7/cmd/xfstests/042.out linux-2.4-xfs/cmd/xfstests/042.out --- linux-2.4.7/cmd/xfstests/042.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/042.out Fri Feb 23 22:10:47 2001 @@ -0,0 +1,13 @@ +QA output created by 042 +Make a 48 megabyte filesystem on SCRATCH_DEV and mount... done +Reserve 16 1Mb unfragmented regions... done +Fill filesystem with 4k files, generate manifest... done +Use up any further available space using dd... done +Delete every second file... done +Create one very large file... done +Remove other files... done +Run xfs_fsr on filesystem... done +Check 4k files... done +Check large file... done +Checking filesystem... done +xfs_fsr tests passed. diff -rNu linux-2.4.7/cmd/xfstests/043 linux-2.4-xfs/cmd/xfstests/043 --- linux-2.4.7/cmd/xfstests/043 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/043 Thu Feb 1 22:31:55 2001 @@ -0,0 +1,69 @@ +#! /bin/sh +# XFS QA Test No. 043 +# $Id: 1.1 $ +# +# Test out xfsdump/restore but rmv inventory prior to restore. +# This checks that the on-disk inventory can be successfully +# rebuilt from the on-tape inventory. +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sherman.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +_require_tape $TAPE_DEV +_create_dumpdir_fill +_erase_hard +_do_dump_sub +rm -rf /var/xfsdump/inventory # delete it - let cleanup fix it +_do_restore +_diff_compare_sub +_ls_compare_sub + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/043.grpquota linux-2.4-xfs/cmd/xfstests/043.grpquota --- linux-2.4.7/cmd/xfstests/043.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/043.grpquota Thu May 24 00:36:12 2001 @@ -0,0 +1,107 @@ +QA output created by 043 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -s DUMP_SUBDIR -f TAPE_DEV -M stress_tape_media -L stress_043 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_043" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_043 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: searching media for dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: found dump matching specified label: +xfsrestore: hostname: HOSTNAME +xfsrestore: mount point: SCRATCH_MNT +xfsrestore: volume: SCRATCH_DEV +xfsrestore: session time: TIME +xfsrestore: level: 0 +xfsrestore: session label: "stress_043" +xfsrestore: media label: "stress_tape_media" +xfsrestore: file system id: ID +xfsrestore: session id: ID +xfsrestore: media id: ID +xfsrestore: searching media for directory dump +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: examining media file 1 +xfsrestore: incorporating on-media session inventory into online inventory +xfsrestore: /var/xfsdump/inventory created +xfsrestore: using on-media session inventory +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/043.noquota linux-2.4-xfs/cmd/xfstests/043.noquota --- linux-2.4.7/cmd/xfstests/043.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/043.noquota Thu May 24 00:36:12 2001 @@ -0,0 +1,105 @@ +QA output created by 043 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -s DUMP_SUBDIR -f TAPE_DEV -M stress_tape_media -L stress_043 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_043" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_043 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: searching media for dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: found dump matching specified label: +xfsrestore: hostname: HOSTNAME +xfsrestore: mount point: SCRATCH_MNT +xfsrestore: volume: SCRATCH_DEV +xfsrestore: session time: TIME +xfsrestore: level: 0 +xfsrestore: session label: "stress_043" +xfsrestore: media label: "stress_tape_media" +xfsrestore: file system id: ID +xfsrestore: session id: ID +xfsrestore: media id: ID +xfsrestore: searching media for directory dump +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: examining media file 1 +xfsrestore: incorporating on-media session inventory into online inventory +xfsrestore: /var/xfsdump/inventory created +xfsrestore: using on-media session inventory +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/043.ugquota linux-2.4-xfs/cmd/xfstests/043.ugquota --- linux-2.4.7/cmd/xfstests/043.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/043.ugquota Thu May 24 00:36:12 2001 @@ -0,0 +1,109 @@ +QA output created by 043 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -s DUMP_SUBDIR -f TAPE_DEV -M stress_tape_media -L stress_043 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_043" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_043 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: searching media for dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: found dump matching specified label: +xfsrestore: hostname: HOSTNAME +xfsrestore: mount point: SCRATCH_MNT +xfsrestore: volume: SCRATCH_DEV +xfsrestore: session time: TIME +xfsrestore: level: 0 +xfsrestore: session label: "stress_043" +xfsrestore: media label: "stress_tape_media" +xfsrestore: file system id: ID +xfsrestore: session id: ID +xfsrestore: media id: ID +xfsrestore: searching media for directory dump +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: examining media file 1 +xfsrestore: incorporating on-media session inventory into online inventory +xfsrestore: /var/xfsdump/inventory created +xfsrestore: using on-media session inventory +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/043.usrquota linux-2.4-xfs/cmd/xfstests/043.usrquota --- linux-2.4.7/cmd/xfstests/043.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/043.usrquota Thu May 24 00:36:12 2001 @@ -0,0 +1,107 @@ +QA output created by 043 +Put scsi tape driver into variable block size mode +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -s DUMP_SUBDIR -f TAPE_DEV -M stress_tape_media -L stress_043 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_043" +xfsdump: ino map phase 1: parsing subtree selections +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: pruning unneeded subtrees +xfsdump: ino map phase 4: estimating dump size +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 1048576 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_043 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: searching media for dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: found dump matching specified label: +xfsrestore: hostname: HOSTNAME +xfsrestore: mount point: SCRATCH_MNT +xfsrestore: volume: SCRATCH_DEV +xfsrestore: session time: TIME +xfsrestore: level: 0 +xfsrestore: session label: "stress_043" +xfsrestore: media label: "stress_tape_media" +xfsrestore: file system id: ID +xfsrestore: session id: ID +xfsrestore: media id: ID +xfsrestore: searching media for directory dump +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: examining media file 1 +xfsrestore: incorporating on-media session inventory into online inventory +xfsrestore: /var/xfsdump/inventory created +xfsrestore: using on-media session inventory +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/044 linux-2.4-xfs/cmd/xfstests/044 --- linux-2.4.7/cmd/xfstests/044 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/044 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,171 @@ +#! /bin/sh +# XFS QA Test No. 041 +# $Id: 1.1 $ +# +# external log uuid/format tests +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# real QA test starts here + +_require_logdev + +_filter_logprint() +{ + perl -ne ' + s/data device: ([\w|\/]+)/data device: DDEV/; + s/log device: ([\w|\/]+) daddr: (\d+) length: (\d+)/log device: LDEV daddr: XXX length: XXX/; + s/log file: "([\w|\/]+)" daddr: (\d+) length: (\d+)/log device: LDEV daddr: XXX length: XXX/; + s/uuid: ([abcdef\d-]+)\s+format: (.+)/uuid: UUID format: FORMAT/; + s/skipped (\w+) zeroed blocks/skipped XXX zeroed blocks/; + print; + ' +} + +_check_mount() +{ + echo " *** mount (expect success)" + if ! mount -t xfs -o logdev=$SCRATCH_LOGDEV $SCRATCH_DEV $SCRATCH_MNT + then + echo " !!! mount failed (expecting success)" + status=1 + exit + fi + + echo " *** umount" + if ! umount $SCRATCH_DEV + then + echo " !!! umount failed (expecting success)" + status=1 + exit + fi +} + +_check_no_mount() +{ + echo " *** mount (expect failure)" + if mount -t xfs -o logdev=$SCRATCH_LOGDEV $SCRATCH_DEV $SCRATCH_MNT >$tmp.err 2>&1 + then + cat $tmp.err + echo " !!! mount succeeded (expecting failure)" + status=1 + exit + fi +} + +_check_require_logdev() +{ + echo " *** mount without logdev (expect failure)" + if mount -t xfs $SCRATCH_DEV $SCRATCH_MNT >$tmp.err 2>&1 + then + cat $tmp.err + echo " !!! mount succeeded (expecting failure)" + status=1 + exit + fi +} + + + +# real QA test starts here +# +_require_scratch + +echo -e -n "\n\r*** XFS QA 044 - expect mount failure messages\n\r\n\r" >/dev/console + +echo "*** mkfs" +mkfs -t xfs -f -l logdev=$SCRATCH_LOGDEV,size=4096b $SCRATCH_DEV | _filter_mkfs 2>/dev/null +_check_mount +_check_require_logdev + +echo "*** set uuid" +xfs_db -x $SCRATCH_DEV -l $SCRATCH_LOGDEV -c "uuid 02020202-0202-0202-0202-020202020202" \ + || _unexpected +_check_mount + +echo "*** zero log" +$here/src/loggen -z 100 >$SCRATCH_LOGDEV +_check_mount + +echo "*** write clean log" +$here/src/loggen -u 2 -f 1 -m 1 -z 100 >$SCRATCH_LOGDEV +_check_mount + +echo "*** write clean log (different format)" +$here/src/loggen -u 2 -f 99 -m 1 -z 100 >$SCRATCH_LOGDEV +_check_mount + +echo "*** write clean log (different uuid)" +$here/src/loggen -u 7 -m 1 -z 100 >$SCRATCH_LOGDEV +_check_no_mount + +echo "*** write clean log (different uuid & format)" +$here/src/loggen -u 7 -f 99 -m 1 -z 100 >$SCRATCH_LOGDEV +_check_no_mount + +echo "*** write dirty log" +$here/src/loggen -u 2 -e 1 -z 100 >$SCRATCH_LOGDEV +_check_mount + +echo "*** write dirty log (different format)" +$here/src/loggen -u 2 -f 99 -e 1 -z 100 >$SCRATCH_LOGDEV +_check_no_mount + +echo "*** write dirty log (irix style)" +$here/src/loggen -u 0 -f 0 -e 1 -z 100 >$SCRATCH_LOGDEV +_check_no_mount + +echo "*** write large dirty log" +$here/src/loggen -u 2 -e 16000 -z 100 >$SCRATCH_LOGDEV +_check_mount + +echo -e -n "\n\r*** XFS QA 044 - done\n\r\n\r" >/dev/console + +status=0 +# if error +exit diff -rNu linux-2.4.7/cmd/xfstests/044.out linux-2.4-xfs/cmd/xfstests/044.out --- linux-2.4.7/cmd/xfstests/044.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/044.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,66 @@ +QA output created by 044 +*** mkfs +meta-data=DDEV isize=XXX agcount=N, agsize=XXX blks +data = bsize=XXX blocks=XXX, imaxpct=PCT + = sunit=XXX swidth=XXX, unwritten=X +naming =VERN bsize=XXX +log =LDEV bsize=XXX blocks=XXX +realtime =RDEV extsz=XXX blocks=XXX, rtextents=XXX + *** mount (expect success) + *** umount + *** mount without logdev (expect failure) +*** set uuid +clearing log and setting uuid +writing all SBs +new uuid = 02020202-0202-0202-0202-020202020202 + *** mount (expect success) + *** umount +*** zero log +*** loggen + *** zero block (1BB) x 100 + *** mount (expect success) + *** umount +*** write clean log +*** loggen + *** unmount record (2BB) x 1 + *** zero block (1BB) x 100 + *** mount (expect success) + *** umount +*** write clean log (different format) +*** loggen + *** unmount record (2BB) x 1 + *** zero block (1BB) x 100 + *** mount (expect success) + *** umount +*** write clean log (different uuid) +*** loggen + *** unmount record (2BB) x 1 + *** zero block (1BB) x 100 + *** mount (expect failure) +*** write clean log (different uuid & format) +*** loggen + *** unmount record (2BB) x 1 + *** zero block (1BB) x 100 + *** mount (expect failure) +*** write dirty log +*** loggen + *** empty record (2BB) x 1 + *** zero block (1BB) x 100 + *** mount (expect success) + *** umount +*** write dirty log (different format) +*** loggen + *** empty record (2BB) x 1 + *** zero block (1BB) x 100 + *** mount (expect failure) +*** write dirty log (irix style) +*** loggen + *** empty record (2BB) x 1 + *** zero block (1BB) x 100 + *** mount (expect failure) +*** write large dirty log +*** loggen + *** empty record (2BB) x 16000 + *** zero block (1BB) x 100 + *** mount (expect success) + *** umount diff -rNu linux-2.4.7/cmd/xfstests/045 linux-2.4-xfs/cmd/xfstests/045 --- linux-2.4.7/cmd/xfstests/045 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/045 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,97 @@ +#! /bin/sh +# XFS QA Test No. 045 +# $Id: 1.1 $ +# +# test mount of two FSes with identical UUID and mount with unknown option +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_get_uuid() +{ + xfs_db -r $1 -c "uuid" | $AWK_PROG ' + /^uuid/ { print $3 } + ' +} + +# real QA test starts here + +_require_scratch + +echo "*** get uuid" +uuid=`_get_uuid $TEST_DEV` +echo "*** mkfs" +if ! mkfs -t xfs -f $SCRATCH_DEV >$tmp.out 2>&1 +then + cat $tmp.out + echo "!!! failed to mkfs on $SCRATCH_DEV" + exit +fi + +echo "*** mount fs with bad mount option (expect failure)" +if mount -t xfs $SCRATCH_DEV $SCRATCH_MNT -o foobar >$tmp.out 2>&1 +then + cat $tmp.out + echo "!!! mount succeeded (expecting failure)" + exit +fi + +echo "*** duplicate uuid" +xfs_db -x $SCRATCH_DEV -c "uuid $uuid" >/dev/null + +echo "*** mount fs with duplicate uuid (expect failure)" +if mount -t xfs $SCRATCH_DEV $SCRATCH_MNT >$tmp.out 2>&1 +then + cat $tmp.out + echo "!!! mount succeeded (expecting failure)" + exit +fi + +echo "*** ok!" +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/045.out linux-2.4-xfs/cmd/xfstests/045.out --- linux-2.4.7/cmd/xfstests/045.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/045.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,7 @@ +QA output created by 045 +*** get uuid +*** mkfs +*** mount fs with bad mount option (expect failure) +*** duplicate uuid +*** mount fs with duplicate uuid (expect failure) +*** ok! diff -rNu linux-2.4.7/cmd/xfstests/046 linux-2.4-xfs/cmd/xfstests/046 --- linux-2.4.7/cmd/xfstests/046 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/046 Sun Jan 14 23:01:19 2001 @@ -0,0 +1,63 @@ +#! /bin/sh +# XFS QA Test No. 046 +# $Id: 1.1 $ +# +# check on symlinks permissions +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sherman.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +_create_dumpdir_symlinks +_do_dump_file +_do_restore_file +_ls_compare_sub + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/046.grpquota linux-2.4-xfs/cmd/xfstests/046.grpquota --- linux-2.4.7/cmd/xfstests/046.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/046.grpquota Tue May 22 01:07:23 2001 @@ -0,0 +1,40 @@ +QA output created by 046 +Creating directory system of symlinks to dump. +Setup .... +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L stress_046 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_046" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Restoring from file... +xfsrestore -f DUMP_FILE -L stress_046 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/046.noquota linux-2.4-xfs/cmd/xfstests/046.noquota --- linux-2.4.7/cmd/xfstests/046.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/046.noquota Tue May 22 01:03:12 2001 @@ -0,0 +1,38 @@ +QA output created by 046 +Creating directory system of symlinks to dump. +Setup .... +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L stress_046 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_046" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : 0 bytes +xfsdump: dump complete: SECS seconds elapsed +Restoring from file... +xfsrestore -f DUMP_FILE -L stress_046 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: restore complete: SECS seconds elapsed +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/046.ugquota linux-2.4-xfs/cmd/xfstests/046.ugquota --- linux-2.4.7/cmd/xfstests/046.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/046.ugquota Tue May 22 01:07:23 2001 @@ -0,0 +1,42 @@ +QA output created by 046 +Creating directory system of symlinks to dump. +Setup .... +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L stress_046 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_046" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Restoring from file... +xfsrestore -f DUMP_FILE -L stress_046 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/046.usrquota linux-2.4-xfs/cmd/xfstests/046.usrquota --- linux-2.4.7/cmd/xfstests/046.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/046.usrquota Tue May 22 01:07:23 2001 @@ -0,0 +1,40 @@ +QA output created by 046 +Creating directory system of symlinks to dump. +Setup .... +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L stress_046 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_046" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Restoring from file... +xfsrestore -f DUMP_FILE -L stress_046 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: restore complete: SECS seconds elapsed +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/047 linux-2.4-xfs/cmd/xfstests/047 --- linux-2.4.7/cmd/xfstests/047 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/047 Tue May 22 01:59:30 2001 @@ -0,0 +1,99 @@ +#! /bin/sh +# XFS QA Test No. 047 +# $Id: 1.1 $ +# +# invutil with interactive responses +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sherman.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +# wipe test dir clean first +# so dump can be real quick +_wipe_fs +_setup_seq_out + +# +# Create 5 dumps +# and on the 3rd dump note the date +# which we'll use to prune against using xfsinvutil +# +i=0 +while [ $i -lt 5 ]; do + _do_dump_file -L "session.$i" + if [ $i -eq 2 ]; then + sleep 1 + middate=`date '+%m/%d/%Y %T'` + fi + rm $dump_file + sleep 2 + i=`expr $i + 1` +done + +echo "middate = $middate" >>$seq.full + +# Only say No to 1st question to prune +cat >$tmp.input < /dev/null 2>&1 + umount $SCRATCH_MNT/test > /dev/null 2>&1 + rm -f $tmp.* + + if [ -w $seq.full ] + then + echo "--- mounts at end (after cleanup)" >> $seq.full + mount >> $seq.full + fi +} + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "_cleanup ; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_log() +{ + echo "--- $*" + echo "--- $*" >> $seq.full +} + +# real QA test starts here + +_require_scratch +_require_loop + +rm -f $seq.full + +echo "(dev=$SCRATCH_DEV, mount=$SCRATCH_MNT)" >> $seq.full +echo "" >> $seq.full + +echo "--- mounts" >> $seq.full +mount >> $seq.full + +_log "Create ext2 fs on scratch" +mkfs -t ext2 $SCRATCH_DEV >> $seq.full 2>&1 \ + || _fail "!!! failed to mkfs ext2" + +_log "Mount ext2 fs on scratch" +mount -t ext2 $SCRATCH_DEV $SCRATCH_MNT >> $seq.full 2>&1 \ + || _fail "!!! failed to mount" + +_log "Create xfs fs in file on scratch" +mkfs -t xfs -d file,name=$SCRATCH_MNT/test.xfs,size=20m >> $seq.full 2>&1 \ + || _fail "!!! failed to mkfs xfs" + +_log "Make mount points" +mkdir $SCRATCH_MNT/test $SCRATCH_MNT/test2 >> $seq.full 2>&1 \ + || _fail "!!! failed to make mount points" + +_log "Mount xfs via loop" +mount -t xfs -o loop $SCRATCH_MNT/test.xfs $SCRATCH_MNT/test >> $seq.full 2>&1 \ + || _fail "!!! failed to loop mount xfs" + +_log "stress" +src/fsstress -d $SCRATCH_MNT/test -n 1000 $FSSTRESS_AVOID >> $seq.full 2>&1 \ + || _fail "!!! stress failed" + +_log "clean" +rm -rf $SCRATCH_MNT/test/* >> $seq.full 2>&1 \ + || _fail "!!! clean failed" + +_log "create file for ext2 fs" +dd if=/dev/zero of=$SCRATCH_MNT/test/test.ext2 bs=1024 count=10240 >> $seq.full 2>&1 \ + || _fail "!!! create file failed" + +_log "Create ext2 fs in file on looped xfs" +echo y | mkfs -t ext2 $SCRATCH_MNT/test/test.ext2 >> $seq.full 2>&1 \ + || _fail "!!! failed to mkfs ext2 on xfs" + +_log "Mount ext2 on xfs via loop" +mount -t ext2 -o loop $SCRATCH_MNT/test/test.ext2 $SCRATCH_MNT/test2 >> $seq.full 2>&1 \ + || _fail "!!! failed to loop mount xfs" + +_log "stress ext2 on xfs via loop" +src/fsstress -d $SCRATCH_MNT/test2 -n 1000 $FSSTRESS_AVOID >> $seq.full 2>&1 \ + || _fail "!!! stress ext2 failed" + +_log "clean" +rm -rf $SCRATCH_MNT/test/* >> $seq.full 2>&1 \ + || _fail "!!! clean failed" + +_log "umount ext2 on xfs" +umount $SCRATCH_MNT/test2 >> $seq.full 2>&1 \ + || _fail "!!! umount ext2 failed" + +_log "umount xfs" +umount $SCRATCH_MNT/test >> $seq.full 2>&1 \ + || _fail "!!! umount xfs failed" + +echo "--- mounts at end (before cleanup)" >> $seq.full +mount >> $seq.full + +rm -f $seq.full +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/049.out linux-2.4-xfs/cmd/xfstests/049.out --- linux-2.4.7/cmd/xfstests/049.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/049.out Sun Jan 14 23:01:19 2001 @@ -0,0 +1,15 @@ +QA output created by 049 +--- Create ext2 fs on scratch +--- Mount ext2 fs on scratch +--- Create xfs fs in file on scratch +--- Make mount points +--- Mount xfs via loop +--- stress +--- clean +--- create file for ext2 fs +--- Create ext2 fs in file on looped xfs +--- Mount ext2 on xfs via loop +--- stress ext2 on xfs via loop +--- clean +--- umount ext2 on xfs +--- umount xfs diff -rNu linux-2.4.7/cmd/xfstests/050 linux-2.4-xfs/cmd/xfstests/050 --- linux-2.4.7/cmd/xfstests/050 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/050 Wed Apr 11 01:10:08 2001 @@ -0,0 +1,145 @@ +#! /bin/sh +# XFS QA Test No. 050 +# $Id: 1.1 $ +# +# Exercises basic XFS quota functionality +# MOUNT_OPTIONS env var switches the test type (uid/gid/acct/enfd) +# options are: (-o) usrquota, grpquota, uqnoenforce, gqnoenforce +# default is: usrquota +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=nathans@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.quota + +_cleanup() +{ + echo; echo "*** unmount" + umount $SCRATCH_MNT 2>/dev/null + rm -f $tmp.* +} +trap "_cleanup; exit \$status" 0 1 2 3 15 +rm -f $seq.out +cp /dev/null $seq.full +chmod a+rwx $seq.full # arbitrary users will write here + +_require_scratch +_require_quota + +# setup a default run +if [ -z "$MOUNT_OPTIONS" ]; then + MOUNT_OPTIONS="-o usrquota"; export MOUNT_OPTIONS +fi + +# real QA test starts here +mkfs -t xfs -f $SCRATCH_DEV | _filter_mkfs 2>$tmp.mkfs +cat $tmp.mkfs >>$seq.full + +# keep the blocksize and data size for dd later +. $tmp.mkfs + +_qmount + +# setup exactly what it is we'll be testing +if src/feature -u $SCRATCH_DEV +then + type=u ; eval `_choose_uid`; ln $seq.usrquota $seq.out +elif src/feature -g $SCRATCH_DEV +then + type=g ; eval `_choose_gid`; ln $seq.grpquota $seq.out +elif src/feature -U $SCRATCH_DEV +then + type=u ; eval `_choose_uid`; ln $seq.uqnoenforce $seq.out +elif src/feature -G $SCRATCH_DEV +then + type=g ; eval `_choose_gid`; ln $seq.gqnoenforce $seq.out +else + _notrun "No quota support at mount time" +fi + +echo "Using output from '" `ls -l $seq.out` "'" >>$seq.full +echo "and using type=$type id=$id" >>$seq.full + +echo +echo "*** report no quota settings" | tee -a $seq.full +repquota -$type $SCRATCH_DEV | _filter_repquota + +echo +echo "*** report initial settings" | tee -a $seq.full +_file_as_id $SCRATCH_MNT/initme $id $type 1024 0 +setquota -$type $id 100 500 4 10 $SCRATCH_DEV +repquota -$type $SCRATCH_DEV | _filter_repquota + +echo +echo "*** push past the soft inode limit" | tee -a $seq.full +_file_as_id $SCRATCH_MNT/softie1 $id $type 1024 0 +_file_as_id $SCRATCH_MNT/softie2 $id $type 1024 0 +_qmount +repquota -$type $SCRATCH_DEV | _filter_repquota + +echo +echo "*** push past the soft block limit" | tee -a $seq.full +_file_as_id $SCRATCH_MNT/softie $id $type 1024 140 +_qmount +repquota -$type $SCRATCH_DEV | _filter_repquota + +echo +echo "*** push past the hard inode limit (expect EDQUOT)" | tee -a $seq.full +for i in 1 2 3 4 5 6 7 8 9 10 11 12 +do + _file_as_id $SCRATCH_MNT/hard$i $id $type 1024 0 +done +_qmount +repquota -$type $SCRATCH_DEV | _filter_repquota + +echo +echo "*** push past the hard block limit (expect EDQUOT)" | tee -a $seq.full +_file_as_id $SCRATCH_MNT/softie $id $type 1024 540 +_qmount +repquota -$type $SCRATCH_DEV | _filter_repquota + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/050.gqnoenforce linux-2.4-xfs/cmd/xfstests/050.gqnoenforce --- linux-2.4.7/cmd/xfstests/050.gqnoenforce Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/050.gqnoenforce Mon Apr 23 02:37:39 2001 @@ -0,0 +1,74 @@ +QA output created by 050 +meta-data=DDEV isize=XXX agcount=N, agsize=XXX blks +data = bsize=XXX blocks=XXX, imaxpct=PCT + = sunit=XXX swidth=XXX, unwritten=X +naming =VERN bsize=XXX +log =LDEV bsize=XXX blocks=XXX +realtime =RDEV extsz=XXX blocks=XXX, rtextents=XXX + +*** report no quota settings +*** Report for group quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +Group used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 + + + +*** report initial settings +*** Report for group quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +Group used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] -- 0 100 500 1 4 10 + + + +*** push past the soft inode limit +*** Report for group quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +Group used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] -- 0 100 500 3 4 10 + + + +*** push past the soft block limit +*** Report for group quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +Group used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] +- 140 100 500 4 4 10 + + + +*** push past the hard inode limit (expect EDQUOT) +*** Report for group quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +Group used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 4 0 0 3 0 0 +[NAME] ++ 140 100 500 16 4 10 + + + +*** push past the hard block limit (expect EDQUOT) +*** Report for group quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +Group used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 4 0 0 3 0 0 +[NAME] ++ 540 100 500 16 4 10 + + + +*** unmount diff -rNu linux-2.4.7/cmd/xfstests/050.grpquota linux-2.4-xfs/cmd/xfstests/050.grpquota --- linux-2.4.7/cmd/xfstests/050.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/050.grpquota Mon Apr 23 02:37:39 2001 @@ -0,0 +1,74 @@ +QA output created by 050 +meta-data=DDEV isize=XXX agcount=N, agsize=XXX blks +data = bsize=XXX blocks=XXX, imaxpct=PCT + = sunit=XXX swidth=XXX, unwritten=X +naming =VERN bsize=XXX +log =LDEV bsize=XXX blocks=XXX +realtime =RDEV extsz=XXX blocks=XXX, rtextents=XXX + +*** report no quota settings +*** Report for group quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +Group used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 + + + +*** report initial settings +*** Report for group quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +Group used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] -- 0 100 500 1 4 10 + + + +*** push past the soft inode limit +*** Report for group quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +Group used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] -- 0 100 500 3 4 10 + + + +*** push past the soft block limit +*** Report for group quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +Group used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] +- 140 100 500 7days 4 4 10 7days + + + +*** push past the hard inode limit (expect EDQUOT) +*** Report for group quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +Group used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] ++ 140 100 500 7days 10 4 10 7days + + + +*** push past the hard block limit (expect EDQUOT) +*** Report for group quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +Group used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] ++ 448 100 500 7days 10 4 10 7days + + + +*** unmount diff -rNu linux-2.4.7/cmd/xfstests/050.uqnoenforce linux-2.4-xfs/cmd/xfstests/050.uqnoenforce --- linux-2.4.7/cmd/xfstests/050.uqnoenforce Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/050.uqnoenforce Wed Apr 11 01:10:08 2001 @@ -0,0 +1,74 @@ +QA output created by 050 +meta-data=DDEV isize=XXX agcount=N, agsize=XXX blks +data = bsize=XXX blocks=XXX, imaxpct=PCT + = sunit=XXX swidth=XXX, unwritten=X +naming =VERN bsize=XXX +log =LDEV bsize=XXX blocks=XXX +realtime =RDEV extsz=XXX blocks=XXX, rtextents=XXX + +*** report no quota settings +*** Report for user quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +User used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 + + + +*** report initial settings +*** Report for user quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +User used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] -- 0 100 500 1 4 10 + + + +*** push past the soft inode limit +*** Report for user quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +User used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] -- 0 100 500 3 4 10 + + + +*** push past the soft block limit +*** Report for user quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +User used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] +- 140 100 500 4 4 10 + + + +*** push past the hard inode limit (expect EDQUOT) +*** Report for user quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +User used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 4 0 0 3 0 0 +[NAME] ++ 140 100 500 16 4 10 + + + +*** push past the hard block limit (expect EDQUOT) +*** Report for user quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +User used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 4 0 0 3 0 0 +[NAME] ++ 540 100 500 16 4 10 + + + +*** unmount diff -rNu linux-2.4.7/cmd/xfstests/050.usrquota linux-2.4-xfs/cmd/xfstests/050.usrquota --- linux-2.4.7/cmd/xfstests/050.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/050.usrquota Wed Apr 11 01:10:08 2001 @@ -0,0 +1,74 @@ +QA output created by 050 +meta-data=DDEV isize=XXX agcount=N, agsize=XXX blks +data = bsize=XXX blocks=XXX, imaxpct=PCT + = sunit=XXX swidth=XXX, unwritten=X +naming =VERN bsize=XXX +log =LDEV bsize=XXX blocks=XXX +realtime =RDEV extsz=XXX blocks=XXX, rtextents=XXX + +*** report no quota settings +*** Report for user quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +User used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 + + + +*** report initial settings +*** Report for user quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +User used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] -- 0 100 500 1 4 10 + + + +*** push past the soft inode limit +*** Report for user quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +User used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] -- 0 100 500 3 4 10 + + + +*** push past the soft block limit +*** Report for user quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +User used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] +- 140 100 500 7days 4 4 10 7days + + + +*** push past the hard inode limit (expect EDQUOT) +*** Report for user quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +User used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] ++ 140 100 500 7days 10 4 10 7days + + + +*** push past the hard block limit (expect EDQUOT) +*** Report for user quotas on device [DEVICE] +Block grace time: 7days; Inode grace time: 7days + Block limits File limits +User used soft hard grace used soft hard grace +---------------------------------------------------------------------- +[NAME] -- 0 0 0 3 0 0 +[NAME] ++ 448 100 500 7days 10 4 10 7days + + + +*** unmount diff -rNu linux-2.4.7/cmd/xfstests/051 linux-2.4-xfs/cmd/xfstests/051 --- linux-2.4.7/cmd/xfstests/051 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/051 Mon Apr 30 20:01:05 2001 @@ -0,0 +1,307 @@ +#! /bin/sh +# XFS QA Test No. 051 +# $Id: 1.1 $ +# +# Test out ACLs. +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sgi.com + +seq=`basename $0` + +here=`pwd` +tmp=/tmp/$$ +runas=$here/src/runas +status=1 # FAILure is the default! +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.attr + +_cleanup() +{ + rm -f $tmp.* + rm -rf $TEST_DIR/$seq.dir1 +} + +# ----- +# minimal access ACL has ACEs: USER_OBJ, GROUP_OBJ, OTHER_OBJ +# This is set with chacl(1) and can be changed by chmod(1). +# +# Test that this is being set for ACL and for std unix permissions +# Test that we can get back the same ACL. +# Test std permissions for rwx. +# ----- +# +# Test out default ACLs and that the ACL is being PASSed +# onto the children of the dir. +# +# ----- +# Test out access check for extended ACLs. +# -> 3 extra ACEs: MASK, GROUP, USER +# -> the GROUP compares with egid of process _and_ the supplementary +# groups (as found in /etc/group) +# +# Test that mask works for USER, GROUP, GROUP_OBJ +# Test that the ACE type priority is working +# -> this would be done by simultaneously matching on ACEs +# -> interesting if it allows user to specify ACEs in any order +# +rm -f $seq.full + +_need_to_be_root +_acl_setup_ids + +[ -x /bin/chacl ] || _notrun "chacl command not found" +[ -x $runas ] || _notrun "$runas executable not found" + +# get dir +cd $TEST_DIR +rm -rf $seq.dir1 +mkdir $seq.dir1 +cd $seq.dir1 + +# test if acl_get syscall is operational +# and hence the ACL config has been turned on +touch syscalltest +if chacl -l syscalltest 2>&1 | tee -a $here/$seq.full | grep 'Function not implemented' >/dev/null +then + cd $here + _notrun "requires kernel ACL support" +fi + +#------------------------------------------------------- +# real QA test starts here +echo "QA output created by $seq" + +echo "" +echo "=== Test minimal ACE ===" + +echo "Setup file" +# Note: as this is a shell script, +# will need read and execute permission set +# in order to execute it. +touch file1 +cat <file1 +#!/bin/sh +echo "Test was executed" +EOF +chmod u=rwx file1 +chmod g=rw- file1 +chmod o=r-- file1 +chown $acl1.$acl2 file1 +_acl_ls file1 + +echo "" +echo "--- Test get and set of ACL ---" +chacl -l file1 | _acl_filter_id +echo "Expect to FAIL" +chacl u::r--,g::rwx,o:rw- file1 2>&1 +echo "Expect to PASS" +chacl u::r--,g::rwx,o::rw- file1 2>&1 +chacl -l file1 | _acl_filter_id + +echo "" +echo "--- Test sync of ACL with std permissions ---" +_acl_ls file1 +chmod u+w file1 +_acl_ls file1 +chacl -l file1 | _acl_filter_id + +echo "" +echo "--- Test owner permissions ---" +chacl u::r-x,g::---,o::--- file1 2>&1 +chacl -l file1 | _acl_filter_id +# change to owner +echo "Expect to PASS" +$runas -u $acl1 -g $acl1 ./file1 2>&1 +echo "Expect to FAIL" +$runas -u $acl2 -g $acl2 ./file1 2>&1 + +echo "" +echo "--- Test group permissions ---" +chacl u::---,g::r-x,o::--- file1 2>&1 +chacl -l file1 | _acl_filter_id +echo "Expect to FAIL - acl1 is owner" +$runas -u $acl1 -g $acl1 ./file1 2>&1 +echo "Expect to PASS - acl2 matches group" +$runas -u $acl2 -g $acl2 ./file1 2>&1 +echo "Expect to PASS - acl2 matches sup group" +$runas -u $acl2 -g $acl3 -s $acl2 ./file1 2>&1 +echo "Expect to FAIL - acl3 is not in group" +$runas -u $acl3 -g $acl3 ./file1 2>&1 + +echo "" +echo "--- Test other permissions ---" +chacl u::---,g::---,o::r-x file1 2>&1 +chacl -l file1 | _acl_filter_id +echo "Expect to FAIL - acl1 is owner" +$runas -u $acl1 -g $acl1 ./file1 2>&1 +echo "Expect to FAIL - acl2 is in group" +$runas -u $acl2 -g $acl2 ./file1 2>&1 +echo "Expect to FAIL - acl2 is in sup. group" +$runas -u $acl2 -g $acl3 -s $acl2 ./file1 2>&1 +echo "Expect to PASS - acl3 is not owner or in group" +$runas -u $acl3 -g $acl3 ./file1 2>&1 + +#------------------------------------------------------- + +echo "" +echo "=== Test Extended ACLs ===" + +echo "" +echo "--- Test adding a USER ACE ---" +echo "Expect to FAIL as no MASK provided" +chacl u::---,g::---,o::---,u:$acl2:r-x file1 2>&1 | _acl_filter_id +echo "Ensure that ACL has not been changed" +chacl -l file1 | _acl_filter_id +echo "Expect to PASS - USER ACE matches user" +chacl u::---,g::---,o::---,u:$acl2:r-x,m::rwx file1 2>&1 +chacl -l file1 | _acl_filter_id +$runas -u $acl2 -g $acl2 ./file1 2>&1 +echo "Expect to FAIL - USER ACE does not match user" +$runas -u $acl3 -g $acl3 ./file1 2>&1 + +echo "" +echo "--- Test adding a GROUP ACE ---" +echo "Expect to FAIL as no MASK provided" +chacl u::---,g::---,o::---,g:$acl2:r-x file1 2>&1 | _acl_filter_id +echo "Ensure that ACL has not been changed" +chacl -l file1 | _acl_filter_id +chacl u::---,g::---,o::---,g:$acl2:r-x,m::rwx file1 2>&1 +chacl -l file1 | _acl_filter_id +echo "Expect to PASS - GROUP ACE matches group" +$runas -u $acl2 -g $acl2 ./file1 2>&1 +echo "Expect to PASS - GROUP ACE matches sup group" +$runas -u $acl2 -g $acl1 -s $acl2 ./file1 2>&1 +echo "Expect to FAIL - GROUP ACE does not match group" +$runas -u $acl3 -g $acl3 ./file1 2>&1 + +#------------------------------------------------------- + +echo "" +echo "--- Test MASK ---" + +# group +chacl u::---,g::---,o::---,g:$acl2:r-x,m::-w- file1 2>&1 +chacl -l file1 | _acl_filter_id +echo "Expect to FAIL as MASK prohibits execution" +$runas -u $acl2 -g $acl2 ./file1 2>&1 + +# user +chacl u::---,g::---,o::---,u:$acl2:r-x,m::-w- file1 2>&1 +echo "Expect to FAIL as MASK prohibits execution" +$runas -u $acl2 -g $acl2 ./file1 2>&1 + +# user +chacl u::---,g::---,o::---,u:$acl2:r-x,m::r-x file1 2>&1 +echo "Expect to PASS as MASK allows execution" +$runas -u $acl2 -g $acl2 ./file1 2>&1 + +#------------------------------------------------------- + +echo "" +echo "--- Test ACE priority ---" + +chacl o::rwx,g::rwx,u:$acl1:rwx,u::---,m::rwx file1 2>&1 +echo "Expect to FAIL as should match on owner" +$runas -u $acl1 -g $acl2 ./file1 2>&1 + +chacl o::---,g::---,u:$acl2:rwx,u::---,m::rwx file1 2>&1 +echo "Expect to PASS as should match on user" +$runas -u $acl2 -g $acl2 ./file1 2>&1 + + +#------------------------------------------------------- + +echo "" +echo "=== Test can read ACLs without access permissions ===" +# This was a bug in kernel code where syscred wasn't being used +# to override the capabilities +chacl o::---,g::---,u::--- file1 2>&1 +chacl -l file1 | _acl_filter_id + +#------------------------------------------------------- + +echo "" +echo "=== Test Default ACLs ===" +# make test clearer by testing with and without umask +umask 0 + +mkdir acldir +chacl -b "u::rwx,g::rwx,o::rwx" "u::r-x,g::r--,o::---" acldir 2>&1 +chacl -l acldir | _acl_filter_id +cd acldir + +touch file2 +_acl_ls file2 +chacl -l file2 | _acl_filter_id + +#ensure that umask is not having an effect +#so set it and see +umask 722 +touch file3 +_acl_ls file3 +chacl -l file3 | _acl_filter_id + +cd .. +umask 022 + + +#------------------------------------------------------- + +echo "" +echo "=== Removing ACLs ===" +chacl -l file1 | _acl_filter_id +chacl -l acldir | _acl_filter_id +chacl -l acldir/file2 | _acl_filter_id +echo "Remove ACLs..." +chacl -R file1 +chacl -B acldir +chacl -R acldir/file2 +chacl -l file1 | _acl_filter_id +chacl -l acldir | _acl_filter_id +chacl -l acldir/file2 | _acl_filter_id + +#------------------------------------------------------- + + + + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/051.out linux-2.4-xfs/cmd/xfstests/051.out --- linux-2.4.7/cmd/xfstests/051.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/051.out Mon Apr 30 20:01:05 2001 @@ -0,0 +1,106 @@ +QA output created by 051 + +=== Test minimal ACE === +Setup file +-rwxrw-r-- id1 id2 file1 + +--- Test get and set of ACL --- +file1 [] +Expect to FAIL +chacl: "u::r--,g::rwx,o:rw-" is an invalid ACL specification. +Expect to PASS +file1 [u::r--,g::rwx,o::rw-] + +--- Test sync of ACL with std permissions --- +-r--rwxrw- id1 id2 file1 +-rw-rwxrw- id1 id2 file1 +file1 [u::rw-,g::rwx,o::rw-] + +--- Test owner permissions --- +file1 [u::r-x,g::---,o::---] +Expect to PASS +Test was executed +Expect to FAIL +./file1: Permission denied + +--- Test group permissions --- +file1 [u::---,g::r-x,o::---] +Expect to FAIL - acl1 is owner +./file1: Permission denied +Expect to PASS - acl2 matches group +Test was executed +Expect to PASS - acl2 matches sup group +Test was executed +Expect to FAIL - acl3 is not in group +./file1: Permission denied + +--- Test other permissions --- +file1 [u::---,g::---,o::r-x] +Expect to FAIL - acl1 is owner +./file1: Permission denied +Expect to FAIL - acl2 is in group +./file1: Permission denied +Expect to FAIL - acl2 is in sup. group +./file1: Permission denied +Expect to PASS - acl3 is not owner or in group +Test was executed + +=== Test Extended ACLs === + +--- Test adding a USER ACE --- +Expect to FAIL as no MASK provided +chacl: "u::---,g::---,o::---,u:id2:r-x" is an invalid ACL specification. +Ensure that ACL has not been changed +file1 [u::---,g::---,o::r-x] +Expect to PASS - USER ACE matches user +file1 [u::---,g::---,o::---,u:id2:r-x,m::rwx] +Test was executed +Expect to FAIL - USER ACE does not match user +./file1: Permission denied + +--- Test adding a GROUP ACE --- +Expect to FAIL as no MASK provided +chacl: "u::---,g::---,o::---,g:id2:r-x" is an invalid ACL specification. +Ensure that ACL has not been changed +file1 [u::---,g::---,o::---,u:id2:r-x,m::rwx] +file1 [u::---,g::---,o::---,g:id2:r-x,m::rwx] +Expect to PASS - GROUP ACE matches group +Test was executed +Expect to PASS - GROUP ACE matches sup group +Test was executed +Expect to FAIL - GROUP ACE does not match group +./file1: Permission denied + +--- Test MASK --- +file1 [u::---,g::---,o::---,g:id2:r-x,m::-w-] +Expect to FAIL as MASK prohibits execution +./file1: Permission denied +Expect to FAIL as MASK prohibits execution +./file1: Permission denied +Expect to PASS as MASK allows execution +Test was executed + +--- Test ACE priority --- +Expect to FAIL as should match on owner +./file1: Permission denied +Expect to PASS as should match on user +Test was executed + +=== Test can read ACLs without access permissions === +file1 [o::---,g::---,u::---] + +=== Test Default ACLs === +acldir [u::rwx,g::rwx,o::rwx/u::r-x,g::r--,o::---] +-r--r----- 0 0 file2 +file2 [u::r--,g::r--,o::---] +-r--r----- 0 0 file3 +file3 [u::r--,g::r--,o::---] + +=== Removing ACLs === +file1 [o::---,g::---,u::---] +acldir [u::rwx,g::rwx,o::rwx/u::r-x,g::r--,o::---] +acldir/file2 [u::r--,g::r--,o::---] +Remove ACLs... +file1 [] +acldir [] +acldir/file2 [] diff -rNu linux-2.4.7/cmd/xfstests/052 linux-2.4-xfs/cmd/xfstests/052 --- linux-2.4.7/cmd/xfstests/052 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/052 Wed Apr 11 01:10:08 2001 @@ -0,0 +1,140 @@ +#! /bin/sh +# XFS QA Test No. 052 +# $Id: 1.1 $ +# +# Ensure that quota(1) displays blocksizes matching ondisk dquots. +# +# MOUNT_OPTIONS can be set to grpquota to test group quota, +# defaults to usrquota if MOUNT_OPTIONS is not set. +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=nathans@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.quota + +_cleanup() +{ + umount $SCRATCH_MNT 2>/dev/null + rm -f $tmp.* +} +trap "_cleanup; exit \$status" 0 1 2 3 15 +rm -f $seq.full + +_require_scratch +_require_quota + +# setup a default run +if [ -z "$MOUNT_OPTIONS" ]; then + MOUNT_OPTIONS="-o usrquota"; export MOUNT_OPTIONS +fi + +# real QA test starts here +mkfs -t xfs -f $SCRATCH_DEV | _filter_mkfs 2>$tmp.mkfs +cat $tmp.mkfs >>$seq.full +chmod a+w $seq.full # arbitrary users will write here + +# keep the blocksize from mkfs ($dbsize) +. $tmp.mkfs + +_qmount + +# setup user/group to test +if src/feature -U $SCRATCH_DEV ; then + type=u ; eval `_choose_uid` +elif src/feature -G $SCRATCH_DEV ; then + type=g ; eval `_choose_gid` +else + _notrun "No quota support at mount time" +fi + +# create 100 (fs-blocksize) blocks +_file_as_id $SCRATCH_MNT/foo $id $type $dbsize 220 +sync + +# set limit at 1001 (1k) blocks +setquota -$type $id 1001 1001 10 10 $SCRATCH_DEV + +# cross check blks, softblks, hardblks <-> quota, xfs_db +quota -$type $id | tee -a $seq.full | perl -ne ' + if (m,^\s*'$SCRATCH_DEV'\s+(\d+)\s+(\d+)\s+(\d+), || + ($next == 1 && m,^\s+(\d+)\s+(\d+)\s+(\d+),)) { + print "used_blocks=", $1, "\n"; + print "soft_blocks=", $2, "\n"; + print "hard_blocks=", $3, "\n"; + $next = 0; + } + elsif (m,^\s*'$SCRATCH_DEV',) { # devfs (long) names + $next = 1; + }' | LC_COLLATE=POSIX sort >$tmp.quota + +echo ===quota output >> $seq.full +cat $tmp.quota >> $seq.full +[ ! -s $tmp.quota ] && echo "warning: quota output file is empty" + +umount $SCRATCH_MNT + +# note - does (insitu) conversion from fs blocks to 1K blocks +xfs_db -rc "dquot -$type $id" -c p $SCRATCH_DEV | tee -a $seq.full | perl -ne ' + if (/^diskdq.bcount = (\d+)$/) { + print "used_blocks=", $1 * '$dbsize' / 1024, "\n"; + } + elsif (/^diskdq.blk_hardlimit = (\d+)$/) { + print "hard_blocks=", $1 * '$dbsize' / 1024, "\n"; + } + elsif (/^diskdq.blk_softlimit = (\d+)$/) { + print "soft_blocks=", $1 * '$dbsize' / 1024, "\n"; + }' | LC_COLLATE=POSIX sort >$tmp.xfs_db + +echo ===xfs_db output >> $seq.full +cat $tmp.xfs_db >> $seq.full +[ ! -s $tmp.xfs_db ] && echo "warning: xfs_db output file is empty" + +echo Comparing out of quota and xfs_db +diff $tmp.quota $tmp.xfs_db +[ $? -eq 0 ] && echo OK. + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/052.out linux-2.4-xfs/cmd/xfstests/052.out --- linux-2.4.7/cmd/xfstests/052.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/052.out Tue Mar 20 01:17:52 2001 @@ -0,0 +1,9 @@ +QA output created by 052 +meta-data=DDEV isize=XXX agcount=N, agsize=XXX blks +data = bsize=XXX blocks=XXX, imaxpct=PCT + = sunit=XXX swidth=XXX, unwritten=X +naming =VERN bsize=XXX +log =LDEV bsize=XXX blocks=XXX +realtime =RDEV extsz=XXX blocks=XXX, rtextents=XXX +Comparing out of quota and xfs_db +OK. diff -rNu linux-2.4.7/cmd/xfstests/053 linux-2.4-xfs/cmd/xfstests/053 --- linux-2.4.7/cmd/xfstests/053 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/053 Sun Apr 1 19:41:31 2001 @@ -0,0 +1,105 @@ +#! /bin/sh +# XFS QA Test No. 053 +# $Id: 1.1 $ +# +# xfs_repair breaks acls +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=ajag@bruce.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.attr + +# real QA test starts here +_require_scratch +_acl_setup_ids +_do_die_on_error=y +test=$SCRATCH_MNT/test + +# make filesystem on scratch using the defaults +_do 'make filesystem on $SCRATCH_DEV' \ + 'mkfs -t xfs -f $SCRATCH_DEV' +_do 'mount filesytem' \ + 'mount -t xfs $SCRATCH_DEV $SCRATCH_MNT' + +# create test files and set acls +acls=" +u::r--,g::rwx,o::rw- +u::r-x,g::---,o::--- +u::---,g::r-x,o::--- +u::---,g::---,o::r-x +u::---,g::r-x,o::rwx +u::---,g::---,o::---,u:$acl2:r-x,m::rwx +u::rwx,g::r-x,o::r-- +u::---,g::---,o::---,g:$acl2:r-x,m::-w-" + +i=0 +for acl in $acls +do + _do "touch $test.$i" + _do "chacl $acl $test.$i" + i=`expr $i + 1` +done + +list_acls() +{ + i=0 + for acl in $acls + do + chacl -l $test.$i | _acl_filter_id | sed -e "s!$SCRATCH_MNT!\$SCRATCH_MNT!" + i=`expr $i + 1` + done +} + +echo "acls before repair:" +list_acls +_do 'unmount $SCRATCH_DEV' 'umount $SCRATCH_DEV' +_do 'repair filesystem' 'xfs_repair $SCRATCH_DEV' +_do 'mount filesytem' 'mount -t xfs $SCRATCH_DEV $SCRATCH_MNT' +echo "acls after repair: " +list_acls + +# success, all done +status=0; exit diff -rNu linux-2.4.7/cmd/xfstests/053.out linux-2.4-xfs/cmd/xfstests/053.out --- linux-2.4.7/cmd/xfstests/053.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/053.out Sun Apr 1 19:41:31 2001 @@ -0,0 +1,24 @@ +QA output created by 053 +make filesystem on $SCRATCH_DEV... done +mount filesytem... done +acls before repair: +$SCRATCH_MNT/test.0 [u::r--,g::rwx,o::rw-] +$SCRATCH_MNT/test.1 [u::r-x,g::---,o::---] +$SCRATCH_MNT/test.2 [u::---,g::r-x,o::---] +$SCRATCH_MNT/test.3 [u::---,g::---,o::r-x] +$SCRATCH_MNT/test.4 [u::---,g::r-x,o::rwx] +$SCRATCH_MNT/test.5 [u::---,g::---,o::---,u:id2:r-x,m::rwx] +$SCRATCH_MNT/test.6 [u::rwx,g::r-x,o::r--] +$SCRATCH_MNT/test.7 [u::---,g::---,o::---,g:id2:r-x,m::-w-] +unmount $SCRATCH_DEV... done +repair filesystem... done +mount filesytem... done +acls after repair: +$SCRATCH_MNT/test.0 [u::r--,g::rwx,o::rw-] +$SCRATCH_MNT/test.1 [u::r-x,g::---,o::---] +$SCRATCH_MNT/test.2 [u::---,g::r-x,o::---] +$SCRATCH_MNT/test.3 [u::---,g::---,o::r-x] +$SCRATCH_MNT/test.4 [u::---,g::r-x,o::rwx] +$SCRATCH_MNT/test.5 [u::---,g::---,o::---,u:id2:r-x,m::rwx] +$SCRATCH_MNT/test.6 [u::rwx,g::r-x,o::r--] +$SCRATCH_MNT/test.7 [u::---,g::---,o::---,g:id2:r-x,m::-w-] diff -rNu linux-2.4.7/cmd/xfstests/054 linux-2.4-xfs/cmd/xfstests/054 --- linux-2.4.7/cmd/xfstests/054 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/054 Tue May 22 19:13:55 2001 @@ -0,0 +1,141 @@ +#! /bin/sh +# XFS QA Test No. 054 +# $Id: 1.1 $ +# +# Check behavior of chown with both user and group quota enabled, +# and changing both user and group together via chown(2). +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=nathans@sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.quota + +_cleanup() +{ + umount $SCRATCH_MNT 2>/dev/null + rm -f $tmp.* +} +trap "_cleanup; exit \$status" 0 1 2 3 15 +cp /dev/null $seq.full +chmod ugo+rwx $seq.full + +_require_scratch + +_filter_stat() +{ + sed " + /^Access:/d; + /^Modify:/d; + /^Change:/d; + s/Device: *[0-9][0-9]*,[0-9][0-9]*/Device: /; + s/Inode: *[0-9][0-9]*/Inode: /; + s,$SCRATCH_MNT,,; + " | tr -s ' ' +} + +_exercise() +{ + mkfs -t xfs -f $SCRATCH_DEV >/dev/null 2>&1 + _qmount + + umask 022 + touch $SCRATCH_MNT/testfile + if src/feature -c $SCRATCH_MNT/testfile; then + : + else + _notrun "Installed fileutils doesn't support 32 bit uids/gids" + fi + + chown 12345 $SCRATCH_MNT/testfile + chgrp 54321 $SCRATCH_MNT/testfile + src/lstat64 $SCRATCH_MNT/testfile | _filter_stat + + chown 34567 $SCRATCH_MNT/testfile + chgrp 76543 $SCRATCH_MNT/testfile + src/lstat64 $SCRATCH_MNT/testfile | _filter_stat + + chown 56789 $SCRATCH_MNT/testfile + chgrp 98765 $SCRATCH_MNT/testfile + src/lstat64 $SCRATCH_MNT/testfile | _filter_stat + + # finally give back to original owners + chown 12345 $SCRATCH_MNT/testfile + chgrp 54321 $SCRATCH_MNT/testfile + src/lstat64 $SCRATCH_MNT/testfile | _filter_stat + + echo + umount $SCRATCH_MNT 2>/dev/null +} + +# real QA test starts here +mkfs -t xfs -f $SCRATCH_DEV >/dev/null 2>&1 +MOUNT_OPTIONS="-o usrquota,grpquota"; export MOUNT_OPTIONS +_qmount +if src/feature -G $SCRATCH_DEV ; then + : +else + _notrun "No quota support at mount time" +fi +umount $SCRATCH_MNT 2>/dev/null + +MOUNT_OPTIONS=""; export MOUNT_OPTIONS +echo "*** Default mount options" +_exercise + +MOUNT_OPTIONS="-o usrquota"; export MOUNT_OPTIONS +echo "*** User quota mount option" +_exercise + +MOUNT_OPTIONS="-o grpquota"; export MOUNT_OPTIONS +echo "*** Group quota mount option" +_exercise + +MOUNT_OPTIONS="-o usrquota,grpquota"; export MOUNT_OPTIONS +echo "*** User and Group quota mount options" +_exercise + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/054.out linux-2.4-xfs/cmd/xfstests/054.out --- linux-2.4.7/cmd/xfstests/054.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/054.out Wed Apr 4 00:42:33 2001 @@ -0,0 +1,73 @@ +QA output created by 054 +*** Default mount options + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (12345) Gid: (54321) +Device: Inode: Links: 1 + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (34567) Gid: (76543) +Device: Inode: Links: 1 + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (56789) Gid: (98765) +Device: Inode: Links: 1 + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (12345) Gid: (54321) +Device: Inode: Links: 1 + +*** User quota mount option + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (12345) Gid: (54321) +Device: Inode: Links: 1 + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (34567) Gid: (76543) +Device: Inode: Links: 1 + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (56789) Gid: (98765) +Device: Inode: Links: 1 + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (12345) Gid: (54321) +Device: Inode: Links: 1 + +*** Group quota mount option + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (12345) Gid: (54321) +Device: Inode: Links: 1 + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (34567) Gid: (76543) +Device: Inode: Links: 1 + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (56789) Gid: (98765) +Device: Inode: Links: 1 + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (12345) Gid: (54321) +Device: Inode: Links: 1 + +*** User and Group quota mount options + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (12345) Gid: (54321) +Device: Inode: Links: 1 + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (34567) Gid: (76543) +Device: Inode: Links: 1 + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (56789) Gid: (98765) +Device: Inode: Links: 1 + File: "/testfile" + Size: 0 Filetype: Regular File + Mode: (0644/-rw-r--r--) Uid: (12345) Gid: (54321) +Device: Inode: Links: 1 + diff -rNu linux-2.4.7/cmd/xfstests/055 linux-2.4-xfs/cmd/xfstests/055 --- linux-2.4.7/cmd/xfstests/055 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/055 Wed May 9 03:38:23 2001 @@ -0,0 +1,65 @@ +#! /bin/sh +# XFS QA Test No. 039 +# $Id: 1.1 $ +# +# Test xfsdump/restore to a remote IRIX tape using RMT user +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sherman.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +_require_tape $RMT_TAPE_USER@$RMT_IRIXTAPE_DEV +_create_dumpdir_fill +_erase_soft +_do_dump -o -F +_do_restore +_diff_compare + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/055.grpquota linux-2.4-xfs/cmd/xfstests/055.grpquota --- linux-2.4.7/cmd/xfstests/055.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/055.grpquota Thu May 24 00:36:12 2001 @@ -0,0 +1,92 @@ +QA output created by 055 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -l0 -f TAPE_DEV -M stress_tape_media -L stress_055 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_055" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 245760 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_055 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/055.noquota linux-2.4-xfs/cmd/xfstests/055.noquota --- linux-2.4.7/cmd/xfstests/055.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/055.noquota Thu May 24 00:36:12 2001 @@ -0,0 +1,89 @@ +QA output created by 055 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -l0 -f TAPE_DEV -M stress_tape_media -L stress_055 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_055" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 245760 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_055 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR diff -rNu linux-2.4.7/cmd/xfstests/055.ugquota linux-2.4-xfs/cmd/xfstests/055.ugquota --- linux-2.4.7/cmd/xfstests/055.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/055.ugquota Thu May 24 00:36:12 2001 @@ -0,0 +1,95 @@ +QA output created by 055 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -l0 -f TAPE_DEV -M stress_tape_media -L stress_055 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_055" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 245760 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_055 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas +Only in RESTORE_DIR: xfsdump_quotas_group diff -rNu linux-2.4.7/cmd/xfstests/055.usrquota linux-2.4-xfs/cmd/xfstests/055.usrquota --- linux-2.4.7/cmd/xfstests/055.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/055.usrquota Thu May 24 00:36:12 2001 @@ -0,0 +1,92 @@ +QA output created by 055 +Creating directory system to dump using src/fill. +Setup .................................... +Erasing tape +Dumping to tape... +xfsdump -o -F -l0 -f TAPE_DEV -M stress_tape_media -L stress_055 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_055" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: preparing drive +xfsdump: WARNING: media may contain data. Overwrite option specified +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dumping session inventory +xfsdump: beginning inventory media file +xfsdump: media file 1 (media 0, file 1) +xfsdump: ending inventory media file +xfsdump: inventory media file size NUM bytes +xfsdump: writing stream terminator +xfsdump: beginning media stream terminator +xfsdump: media file 2 (media 0, file 2) +xfsdump: ending media stream terminator +xfsdump: media stream terminator size 245760 bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Rewinding tape +Restoring from tape... +xfsrestore -f TAPE_DEV -L stress_055 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: preparing drive +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: restore complete: SECS seconds elapsed +Comparing dump directory with restore directory +Files DUMP_DIR/big and RESTORE_DIR/DUMP_SUBDIR/big are identical +Files DUMP_DIR/small and RESTORE_DIR/DUMP_SUBDIR/small are identical +Files DUMP_DIR/sub/a and RESTORE_DIR/DUMP_SUBDIR/sub/a are identical +Files DUMP_DIR/sub/a00 and RESTORE_DIR/DUMP_SUBDIR/sub/a00 are identical +Files DUMP_DIR/sub/a000 and RESTORE_DIR/DUMP_SUBDIR/sub/a000 are identical +Files DUMP_DIR/sub/b and RESTORE_DIR/DUMP_SUBDIR/sub/b are identical +Files DUMP_DIR/sub/b00 and RESTORE_DIR/DUMP_SUBDIR/sub/b00 are identical +Files DUMP_DIR/sub/big and RESTORE_DIR/DUMP_SUBDIR/sub/big are identical +Files DUMP_DIR/sub/c and RESTORE_DIR/DUMP_SUBDIR/sub/c are identical +Files DUMP_DIR/sub/c00 and RESTORE_DIR/DUMP_SUBDIR/sub/c00 are identical +Files DUMP_DIR/sub/d and RESTORE_DIR/DUMP_SUBDIR/sub/d are identical +Files DUMP_DIR/sub/d00 and RESTORE_DIR/DUMP_SUBDIR/sub/d00 are identical +Files DUMP_DIR/sub/e and RESTORE_DIR/DUMP_SUBDIR/sub/e are identical +Files DUMP_DIR/sub/e00 and RESTORE_DIR/DUMP_SUBDIR/sub/e00 are identical +Files DUMP_DIR/sub/e000 and RESTORE_DIR/DUMP_SUBDIR/sub/e000 are identical +Files DUMP_DIR/sub/f and RESTORE_DIR/DUMP_SUBDIR/sub/f are identical +Files DUMP_DIR/sub/f00 and RESTORE_DIR/DUMP_SUBDIR/sub/f00 are identical +Files DUMP_DIR/sub/g and RESTORE_DIR/DUMP_SUBDIR/sub/g are identical +Files DUMP_DIR/sub/g00 and RESTORE_DIR/DUMP_SUBDIR/sub/g00 are identical +Files DUMP_DIR/sub/h and RESTORE_DIR/DUMP_SUBDIR/sub/h are identical +Files DUMP_DIR/sub/h00 and RESTORE_DIR/DUMP_SUBDIR/sub/h00 are identical +Files DUMP_DIR/sub/h000 and RESTORE_DIR/DUMP_SUBDIR/sub/h000 are identical +Files DUMP_DIR/sub/i and RESTORE_DIR/DUMP_SUBDIR/sub/i are identical +Files DUMP_DIR/sub/i00 and RESTORE_DIR/DUMP_SUBDIR/sub/i00 are identical +Files DUMP_DIR/sub/j and RESTORE_DIR/DUMP_SUBDIR/sub/j are identical +Files DUMP_DIR/sub/j00 and RESTORE_DIR/DUMP_SUBDIR/sub/j00 are identical +Files DUMP_DIR/sub/k and RESTORE_DIR/DUMP_SUBDIR/sub/k are identical +Files DUMP_DIR/sub/k00 and RESTORE_DIR/DUMP_SUBDIR/sub/k00 are identical +Files DUMP_DIR/sub/k000 and RESTORE_DIR/DUMP_SUBDIR/sub/k000 are identical +Files DUMP_DIR/sub/l and RESTORE_DIR/DUMP_SUBDIR/sub/l are identical +Files DUMP_DIR/sub/l00 and RESTORE_DIR/DUMP_SUBDIR/sub/l00 are identical +Files DUMP_DIR/sub/m and RESTORE_DIR/DUMP_SUBDIR/sub/m are identical +Files DUMP_DIR/sub/m00 and RESTORE_DIR/DUMP_SUBDIR/sub/m00 are identical +Files DUMP_DIR/sub/n and RESTORE_DIR/DUMP_SUBDIR/sub/n are identical +Files DUMP_DIR/sub/n00 and RESTORE_DIR/DUMP_SUBDIR/sub/n00 are identical +Files DUMP_DIR/sub/small and RESTORE_DIR/DUMP_SUBDIR/sub/small are identical +Only in SCRATCH_MNT: RESTORE_SUBDIR +Only in RESTORE_DIR: xfsdump_quotas diff -rNu linux-2.4.7/cmd/xfstests/056 linux-2.4-xfs/cmd/xfstests/056 --- linux-2.4.7/cmd/xfstests/056 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/056 Mon May 14 23:05:35 2001 @@ -0,0 +1,63 @@ +#! /bin/sh +# XFS QA Test No. 026 +# $Id: 1.1 $ +# +# Test xfsdump/xfsrestore to a dump file (as opposed to a tape) +# and test restoring various permissions/modes +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@bruce.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=0 # success is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.dump + +# real QA test starts here + +_create_dumpdir_fill_perm +_do_dump_file +_do_restore_file +_ls_compare_sub + +# success, all done +exit diff -rNu linux-2.4.7/cmd/xfstests/056.grpquota linux-2.4-xfs/cmd/xfstests/056.grpquota --- linux-2.4.7/cmd/xfstests/056.grpquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/056.grpquota Tue May 22 19:24:55 2001 @@ -0,0 +1,40 @@ +QA output created by 056 +Creating directory system to dump using src/fill. +Setup .......... +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L stress_056 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_056" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Restoring from file... +xfsrestore -f DUMP_FILE -L stress_056 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/056.noquota linux-2.4-xfs/cmd/xfstests/056.noquota --- linux-2.4.7/cmd/xfstests/056.noquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/056.noquota Tue May 22 01:03:38 2001 @@ -0,0 +1,38 @@ +QA output created by 056 +Creating directory system to dump using src/fill. +Setup .......... +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L stress_056 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_056" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Restoring from file... +xfsrestore -f DUMP_FILE -L stress_056 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: restore complete: SECS seconds elapsed +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/056.ugquota linux-2.4-xfs/cmd/xfstests/056.ugquota --- linux-2.4.7/cmd/xfstests/056.ugquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/056.ugquota Tue May 22 19:24:55 2001 @@ -0,0 +1,42 @@ +QA output created by 056 +Creating directory system to dump using src/fill. +Setup .......... +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L stress_056 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: saving group quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_056" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Restoring from file... +xfsrestore -f DUMP_FILE -L stress_056 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: group quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas_group' +xfsrestore: restore complete: SECS seconds elapsed +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/056.usrquota linux-2.4-xfs/cmd/xfstests/056.usrquota --- linux-2.4.7/cmd/xfstests/056.usrquota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/056.usrquota Tue May 22 01:07:23 2001 @@ -0,0 +1,40 @@ +QA output created by 056 +Creating directory system to dump using src/fill. +Setup .......... +Dumping to file... +xfsdump -f DUMP_FILE -M stress_tape_media -L stress_056 SCRATCH_MNT +xfsdump: version 3.0 - Running single-threaded +xfsdump: saving user quota information for: SCRATCH_MNT +xfsdump: level 0 dump of HOSTNAME:SCRATCH_MNT +xfsdump: dump date: DATE +xfsdump: session id: ID +xfsdump: session label: "stress_056" +xfsdump: ino map phase 1: skipping (no subtrees specified) +xfsdump: ino map phase 2: constructing initial dump list +xfsdump: ino map phase 3: skipping (no pruning necessary) +xfsdump: ino map phase 4: skipping (size estimated in phase 2) +xfsdump: ino map phase 5: skipping (only one dump stream) +xfsdump: ino map construction complete +xfsdump: estimated dump size: NUM bytes +xfsdump: /var/xfsdump/inventory created +xfsdump: creating dump session media file 0 (media 0, file 0) +xfsdump: dumping ino map +xfsdump: dumping directories +xfsdump: dumping non-directory files +xfsdump: ending media file +xfsdump: media file size NUM bytes +xfsdump: dump size (non-dir files) : NUM bytes +xfsdump: dump complete: SECS seconds elapsed +Restoring from file... +xfsrestore -f DUMP_FILE -L stress_056 RESTORE_DIR +xfsrestore: version 3.0 - Running single-threaded +xfsrestore: using online session inventory +xfsrestore: searching media for directory dump +xfsrestore: examining media file 0 +xfsrestore: reading directories +xfsrestore: directory post-processing +xfsrestore: restoring non-directory files +xfsrestore: user quota information written to 'SCRATCH_MNT/restore.PID/xfsdump_quotas' +xfsrestore: restore complete: SECS seconds elapsed +Comparing listing of dump directory with restore directory +Files TMP.dump_dir and TMP.restore_dir are identical diff -rNu linux-2.4.7/cmd/xfstests/057 linux-2.4-xfs/cmd/xfstests/057 --- linux-2.4.7/cmd/xfstests/057 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/057 Tue May 29 02:08:24 2001 @@ -0,0 +1,128 @@ +#! /bin/sh +# XFS QA Test No. 057 +# $Id: 1.1 $ +# +# Test out the different acl_get semantics +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sherman.melbourne.sgi.com + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter +. ./common.attr + +seq=`basename $0` +echo "QA output created by $seq" + +_cleanup() +{ + rm -f $tmp.* + rm -rf $TEST_DIR/$seq.dir1 +} + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "_cleanup; exit \$status" 0 1 2 3 15 + +acl_get=$here/src/acl_get + +_get_file() +{ + _file=$1 + + ls -ln $_file | awk '{ print $1, $3, $4, $NF }' + echo "" + + echo "access, default, irix-semantics" + $acl_get -adi $_file + echo "" + + echo "access, default, linux-semantics" + $acl_get -ad $_file + echo "" + + echo "access, fd, irix-semantics" + $acl_get -afi $_file + echo "" + + echo "access, fd, linux-semantics" + $acl_get -af $_file + echo "" +} + +_acl_on() +{ + # test if acl_get syscall is operational + # and hence the ACL config has been turned on + touch syscalltest + if $acl_get -l syscalltest 2>&1 | tee -a $here/$seq.full \ + | grep 'Function not implemented' >/dev/null + then + cd $here + _notrun "requires kernel ACL support" + fi +} + +# real QA test starts here +rm -f $seq.full + +_need_to_be_root + +[ -x $acl_get ] || _notrun "$acl_get command not found" +[ -x /bin/chacl ] || _notrun "chacl command not found" + +# get dir +cd $TEST_DIR +rm -rf $seq.dir1 +mkdir $seq.dir1 +cd $seq.dir1 + +_acl_on + +touch file1 +chmod 752 file1 +_get_file file1 + +# ensure that full blown acls' get/set work, not just minimal ones +_acl_setup_ids +chacl u::rwx,g::rw-,o::---,u:$acl1:r-x,g:$acl1:r--,m::rwx file1 2>&1 +chacl -l file1 | _acl_filter_id +_get_file file1 | _acl_filter_id + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/057.out linux-2.4-xfs/cmd/xfstests/057.out --- linux-2.4.7/cmd/xfstests/057.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/057.out Tue May 29 02:08:24 2001 @@ -0,0 +1,34 @@ +QA output created by 057 +-rwxr-x-w- 0 0 file1 + +access, default, irix-semantics +file1: access irix-empty +file1: default irix-empty + +access, default, linux-semantics +file1: access u::rwx,g::r-x,o::-w- +file1: default linux-empty + +access, fd, irix-semantics +file1: access irix-empty + +access, fd, linux-semantics +file1: access u::rwx,g::r-x,o::-w- + +file1 [u::rwx,g::rw-,o::---,u:id1:r-x,g:id1:r--,m::rwx] +-rwxrwx--- 0 0 file1 + +access, default, irix-semantics +file1: access u::rwx,g::rw-,o::---,u:id1:r-x,g:id1:r--,m::rwx +file1: default irix-empty + +access, default, linux-semantics +file1: access u::rwx,g::rw-,o::---,u:id1:r-x,g:id1:r--,m::rwx +file1: default linux-empty + +access, fd, irix-semantics +file1: access u::rwx,g::rw-,o::---,u:id1:r-x,g:id1:r--,m::rwx + +access, fd, linux-semantics +file1: access u::rwx,g::rw-,o::---,u:id1:r-x,g:id1:r--,m::rwx + diff -rNu linux-2.4.7/cmd/xfstests/058 linux-2.4-xfs/cmd/xfstests/058 --- linux-2.4.7/cmd/xfstests/058 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/058 Tue May 29 02:08:24 2001 @@ -0,0 +1,60 @@ +#! /bin/sh +# XFS QA Test No. 058 +# $Id: 1.1 $ +# +# Test some libacl functions. +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=tes@sherman.melbourne.sgi.com + +seq=`basename $0` +echo "QA output created by $seq" + +here=`pwd` +tmp=/tmp/$$ +status=1 # failure is the default! +trap "rm -f $tmp.*; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# real QA test starts here + +src/acl_test + +# success, all done +status=0 +exit diff -rNu linux-2.4.7/cmd/xfstests/058.out linux-2.4-xfs/cmd/xfstests/058.out --- linux-2.4.7/cmd/xfstests/058.out Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/058.out Wed Jun 20 00:19:09 2001 @@ -0,0 +1,243 @@ +QA output created by 058 +*** test out creating an ACL *** +Test acl_init(ACL_MAX_ENTRIES+1) +acl_test: acl_init(max+1): Invalid argument +Test acl_init(-1) +acl_test: acl_init(-1): Invalid argument +Test acl_init(0) +Test acl_create_entry(NULL, ...) +acl_test: acl_create_entry(NULL,ace1): Invalid argument +Test acl_create_entry(..., NULL) +acl_test: acl_create_entry(NULL,ace1): Invalid argument +Test acl_create_entry(acl1, ace1) +acl_test: acl_create_entry(*null,ace1): Invalid argument +0: creating ace +ACL[n=1]: 0: +1: creating ace +ACL[n=2]: 0: 1: +2: creating ace +ACL[n=3]: 0: 1: 2: +3: creating ace +ACL[n=4]: 0: 1: 2: 3: +4: creating ace +ACL[n=5]: 0: 1: 2: 3: 4: +5: creating ace +ACL[n=6]: 0: 1: 2: 3: 4: 5: +6: creating ace +ACL[n=7]: 0: 1: 2: 3: 4: 5: 6: +7: creating ace +ACL[n=8]: 0: 1: 2: 3: 4: 5: 6: 7: +8: creating ace +ACL[n=9]: 0: 1: 2: 3: 4: 5: 6: 7: 8: +9: creating ace +ACL[n=10]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: +10: creating ace +ACL[n=11]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: +11: creating ace +ACL[n=12]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: +12: creating ace +ACL[n=13]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: +13: creating ace +ACL[n=14]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: +14: creating ace +ACL[n=15]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: +15: creating ace +ACL[n=16]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: +16: creating ace +ACL[n=17]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: +17: creating ace +ACL[n=18]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: +18: creating ace +ACL[n=19]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: +19: creating ace +ACL[n=20]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: +20: creating ace +ACL[n=21]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: +21: creating ace +ACL[n=22]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: +22: creating ace +ACL[n=23]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: +23: creating ace +ACL[n=24]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: +24: creating ace +ACL[n=25]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: +25: creating ace +acl_test: acl_create_entry: Cannot allocate memory +ACL[n=25]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: +26: creating ace +acl_test: acl_create_entry: Cannot allocate memory +ACL[n=25]: 0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: +*** test out getting ACEs *** +Get 1st entry on filled ACL +acl_get_entry -> 1 +1: +Get 2th entry on filled ACL +acl_get_entry -> 1 +2: +Get 3th entry on filled ACL +acl_get_entry -> 1 +3: +Get 4th entry on filled ACL +acl_get_entry -> 1 +4: +Get 5th entry on filled ACL +acl_get_entry -> 1 +5: +Get 6th entry on filled ACL +acl_get_entry -> 1 +6: +Get 7th entry on filled ACL +acl_get_entry -> 1 +7: +Get 8th entry on filled ACL +acl_get_entry -> 1 +8: +Get 9th entry on filled ACL +acl_get_entry -> 1 +9: +Get 10th entry on filled ACL +acl_get_entry -> 1 +10: +Get 11th entry on filled ACL +acl_get_entry -> 1 +11: +Get 12th entry on filled ACL +acl_get_entry -> 1 +12: +Get 13th entry on filled ACL +acl_get_entry -> 1 +13: +Get 14th entry on filled ACL +acl_get_entry -> 1 +14: +Get 15th entry on filled ACL +acl_get_entry -> 1 +15: +Get 16th entry on filled ACL +acl_get_entry -> 1 +16: +Get 17th entry on filled ACL +acl_get_entry -> 1 +17: +Get 18th entry on filled ACL +acl_get_entry -> 1 +18: +Get 19th entry on filled ACL +acl_get_entry -> 1 +19: +Get 20th entry on filled ACL +acl_get_entry -> 1 +20: +Get 21th entry on filled ACL +acl_get_entry -> 1 +21: +Get 22th entry on filled ACL +acl_get_entry -> 1 +22: +Get 23th entry on filled ACL +acl_get_entry -> 1 +23: +Get 24th entry on filled ACL +acl_get_entry -> 1 +24: +Get 25th entry on filled ACL +acl_get_entry -> 1 +25: +Get 26th entry on filled ACL +acl_get_entry -> 0 +Get 27th entry on filled ACL +acl_get_entry -> 0 +dump empty ACL +Get 1st entry on filled ACL +acl_get_entry -> 0 +Get 2th entry on filled ACL +acl_get_entry -> 0 +fill an ACL with known bogus values +Get 1st entry on filled ACL +acl_get_entry -> 1 +1: +Get 2th entry on filled ACL +acl_get_entry -> 1 +2: +Get 3th entry on filled ACL +acl_get_entry -> 1 +3: +Get 4th entry on filled ACL +acl_get_entry -> 1 +4: +Get 5th entry on filled ACL +acl_get_entry -> 1 +5: +Get 6th entry on filled ACL +acl_get_entry -> 1 +6: +Get 7th entry on filled ACL +acl_get_entry -> 1 +7: +Get 8th entry on filled ACL +acl_get_entry -> 1 +8: +Get 9th entry on filled ACL +acl_get_entry -> 1 +9: +Get 10th entry on filled ACL +acl_get_entry -> 1 +10: +Get 11th entry on filled ACL +acl_get_entry -> 1 +11: +Get 12th entry on filled ACL +acl_get_entry -> 1 +12: +Get 13th entry on filled ACL +acl_get_entry -> 1 +13: +Get 14th entry on filled ACL +acl_get_entry -> 1 +14: +Get 15th entry on filled ACL +acl_get_entry -> 1 +15: +Get 16th entry on filled ACL +acl_get_entry -> 1 +16: +Get 17th entry on filled ACL +acl_get_entry -> 1 +17: +Get 18th entry on filled ACL +acl_get_entry -> 1 +18: +Get 19th entry on filled ACL +acl_get_entry -> 1 +19: +Get 20th entry on filled ACL +acl_get_entry -> 1 +20: +Get 21th entry on filled ACL +acl_get_entry -> 1 +21: +Get 22th entry on filled ACL +acl_get_entry -> 1 +22: +Get 23th entry on filled ACL +acl_get_entry -> 1 +23: +Get 24th entry on filled ACL +acl_get_entry -> 1 +24: +Get 25th entry on filled ACL +acl_get_entry -> 1 +25: +Get 26th entry on filled ACL +acl_get_entry -> 0 +Get 27th entry on filled ACL +acl_get_entry -> 0 +*** test out ACL to text for empty ACL*** +acl_to_text(empty_acl,NULL) -> "" +acl_to_text(empty_acl,NULL) -> "", len = 0 +acl_to_text(NULL,NULL) -> "NULL" +*** test out acl_get_qualifier *** +uid = 1 +uid = 1 +uidp is NULL: Invalid argument +uidp is NULL: Invalid argument diff -rNu linux-2.4.7/cmd/xfstests/CVS/Entries linux-2.4-xfs/cmd/xfstests/CVS/Entries --- linux-2.4.7/cmd/xfstests/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/CVS/Entries Thu Jul 5 11:45:48 2001 @@ -0,0 +1,192 @@ +/001/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/001.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/002/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/002.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/003/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/003.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/004/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/004.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/005/1.3/Fri Apr 6 03:14:36 2001/-ko/ +/005.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/006/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/006.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/007/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/007.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/008/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/008.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/009/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/009.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/010/1.2/Tue Mar 27 06:57:37 2001/-ko/ +/010.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/011/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/011.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/012/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/012.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/013/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/013.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/014/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/014.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/015/1.2/Mon May 14 23:31:15 2001/-ko/ +/015.out/1.2/Mon May 14 23:31:15 2001/-ko/ +/016/1.3/Mon Apr 23 07:37:39 2001/-ko/ +/016.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/017/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/017.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/018/1.6/Tue May 22 06:07:23 2001/-ko/ +/018.grpquota/1.2/Mon Apr 23 07:37:39 2001/-ko/ +/018.noquota/1.3/Mon Apr 23 07:37:39 2001/-ko/ +/018.ugquota/1.2/Mon Apr 23 07:37:39 2001/-ko/ +/018.usrquota/1.4/Mon Apr 23 07:37:39 2001/-ko/ +/019/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/019.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/020/1.2/Fri Jan 19 17:15:32 2001/-ko/ +/020.out/1.2/Mon May 7 02:35:35 2001/-ko/ +/021/1.2/Fri Jan 19 17:15:32 2001/-ko/ +/021.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/022/1.2/Fri Feb 2 04:31:55 2001/-ko/ +/022.grpquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/022.noquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/022.ugquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/022.usrquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/023/1.2/Fri Feb 2 04:31:55 2001/-ko/ +/023.grpquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/023.noquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/023.ugquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/023.usrquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/024/1.2/Fri Feb 2 04:31:55 2001/-ko/ +/024.grpquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/024.noquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/024.ugquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/024.usrquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/025/1.2/Fri Feb 2 04:31:55 2001/-ko/ +/025.grpquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/025.noquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/025.ugquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/025.usrquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/026/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/026.grpquota/1.1/Tue May 22 06:07:23 2001/-ko/ +/026.noquota/1.1/Tue May 22 06:02:29 2001/-ko/ +/026.ugquota/1.1/Tue May 22 06:07:23 2001/-ko/ +/026.usrquota/1.1/Tue May 22 06:07:23 2001/-ko/ +/027/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/027.grpquota/1.1/Tue May 22 06:07:23 2001/-ko/ +/027.noquota/1.1/Tue May 22 06:02:53 2001/-ko/ +/027.ugquota/1.1/Tue May 22 06:07:23 2001/-ko/ +/027.usrquota/1.1/Tue May 22 06:07:23 2001/-ko/ +/028/1.2/Tue May 22 06:59:30 2001/-ko/ +/028.grpquota/1.1/Tue May 22 06:59:30 2001/-ko/ +/028.noquota/1.2/Wed May 23 00:12:03 2001/-ko/ +/028.ugquota/1.1/Tue May 22 06:59:30 2001/-ko/ +/028.usrquota/1.1/Tue May 22 06:59:30 2001/-ko/ +/029/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/029.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/030/1.2/Mon Apr 23 07:37:39 2001/-ko/ +/030.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/031/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/031.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/032/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/032.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/033/1.2/Mon Apr 23 07:37:39 2001/-ko/ +/033.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/034/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/034.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/035/1.2/Fri Feb 2 04:31:55 2001/-ko/ +/035.grpquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/035.noquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/035.ugquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/035.usrquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/036/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/036.grpquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/036.noquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/036.ugquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/036.usrquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/037/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/037.grpquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/037.noquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/037.ugquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/037.usrquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/038/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/038.grpquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/038.noquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/038.ugquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/038.usrquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/039/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/039.grpquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/039.noquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/039.ugquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/039.usrquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/040/1.3/Sat Feb 24 03:45:21 2001/-ko/ +/040.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/041/1.6/Sun Apr 29 23:27:46 2001/-ko/ +/041.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/042/1.5/Wed Apr 4 01:45:38 2001/-ko/ +/042.out/1.3/Sat Feb 24 04:10:47 2001/-ko/ +/043/1.2/Fri Feb 2 04:31:55 2001/-ko/ +/043.grpquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/043.noquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/043.ugquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/043.usrquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/044/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/044.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/045/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/045.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/046/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/046.grpquota/1.1/Tue May 22 06:07:23 2001/-ko/ +/046.noquota/1.1/Tue May 22 06:03:12 2001/-ko/ +/046.ugquota/1.1/Tue May 22 06:07:23 2001/-ko/ +/046.usrquota/1.1/Tue May 22 06:07:23 2001/-ko/ +/047/1.2/Tue May 22 06:59:30 2001/-ko/ +/047.grpquota/1.1/Tue May 22 06:59:30 2001/-ko/ +/047.noquota/1.1/Tue May 22 06:59:30 2001/-ko/ +/047.ugquota/1.1/Tue May 22 06:59:30 2001/-ko/ +/047.usrquota/1.1/Tue May 22 06:59:30 2001/-ko/ +/048/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/048.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/049/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/049.out/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/050/1.8/Wed Apr 11 06:10:08 2001/-ko/ +/050.gqnoenforce/1.3/Mon Apr 23 07:37:39 2001/-ko/ +/050.grpquota/1.3/Mon Apr 23 07:37:39 2001/-ko/ +/050.uqnoenforce/1.3/Wed Apr 11 06:10:08 2001/-ko/ +/050.usrquota/1.3/Wed Apr 11 06:10:08 2001/-ko/ +/051/1.7/Tue May 1 01:01:05 2001/-ko/ +/051.out/1.8/Tue May 1 01:01:05 2001/-ko/ +/052/1.2/Wed Apr 11 06:10:08 2001/-ko/ +/052.out/1.1/Tue Mar 20 07:17:52 2001/-ko/ +/053/1.1/Mon Apr 2 00:41:31 2001/-ko/ +/053.out/1.1/Mon Apr 2 00:41:31 2001/-ko/ +/054/1.3/Wed May 23 00:13:55 2001/-ko/ +/054.out/1.1/Wed Apr 4 05:42:33 2001/-ko/ +/055/1.1/Wed May 9 08:38:23 2001/-ko/ +/055.grpquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/055.noquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/055.ugquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/055.usrquota/1.1/Thu May 24 05:36:12 2001/-ko/ +/056/1.1/Tue May 15 04:05:35 2001/-ko/ +/056.grpquota/1.2/Wed May 23 00:24:55 2001/-ko/ +/056.noquota/1.1/Tue May 22 06:03:38 2001/-ko/ +/056.ugquota/1.2/Wed May 23 00:24:55 2001/-ko/ +/056.usrquota/1.1/Tue May 22 06:07:23 2001/-ko/ +/057/1.2/Tue May 29 07:08:24 2001/-ko/ +/057.out/1.2/Tue May 29 07:08:24 2001/-ko/ +/058/1.1/Tue May 29 07:08:24 2001/-ko/ +/058.out/1.3/Wed Jun 20 05:19:09 2001/-ko/ +/Makefile/1.3/Wed Mar 21 01:52:40 2001/-ko/ +/README/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/VERSION/1.1/Tue Jan 16 04:10:42 2001/-ko/ +/check/1.2/Tue May 22 06:07:23 2001/-ko/ +/common/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/common.attr/1.2/Fri Apr 6 03:23:12 2001/-ko/ +/common.config/1.7/Wed May 9 08:38:23 2001/-ko/ +/common.dump/1.11/Thu May 24 05:36:12 2001/-ko/ +/common.filter/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/common.quota/1.9/Wed Jul 4 06:57:38 2001/-ko/ +/common.rc/1.10/Tue May 22 06:07:23 2001/-ko/ +/common.repair/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/configure.in/1.8/Fri Jun 15 14:25:43 2001/-ko/ +/group/1.11/Tue May 29 07:08:24 2001/-ko/ +/install-sh/1.1/Fri Jan 19 02:33:50 2001/-ko/ +/new/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/remake/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/soak/1.1/Mon Jan 15 05:01:19 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/CVS/Entries.Log linux-2.4-xfs/cmd/xfstests/CVS/Entries.Log --- linux-2.4.7/cmd/xfstests/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/CVS/Entries.Log Thu Jul 5 11:46:04 2001 @@ -0,0 +1,5 @@ +A D/crash//// +A D/dmapi//// +A D/include//// +A D/src//// +A D/tools//// diff -rNu linux-2.4.7/cmd/xfstests/CVS/Repository linux-2.4-xfs/cmd/xfstests/CVS/Repository --- linux-2.4.7/cmd/xfstests/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/CVS/Repository Thu Jul 5 11:44:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests diff -rNu linux-2.4.7/cmd/xfstests/CVS/Root linux-2.4-xfs/cmd/xfstests/CVS/Root --- linux-2.4.7/cmd/xfstests/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/CVS/Root Thu Jul 5 11:44:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/Makefile linux-2.4-xfs/cmd/xfstests/Makefile --- linux-2.4.7/cmd/xfstests/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/Makefile Tue Mar 20 19:52:40 2001 @@ -0,0 +1,70 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = . +HAVE_BUILDDEFS = $(shell test -f $(TOPDIR)/include/builddefs && echo yes || echo no) + +ifeq ($(HAVE_BUILDDEFS), yes) +include $(TOPDIR)/include/builddefs +endif + +TESTS = $(shell sed -n -e '/^[0-9][0-9][0-9]*/s/ .*//p' group) +CONFIGURE = configure include/builddefs +LSRCFILES = configure configure.in +LDIRT = *.bad *.new *.core *.full *.raw core a.out *.bak \ + check.log check.time config.* conftest* + +SUBDIRS = include src + +default: $(CONFIGURE) new remake check $(TESTS) +ifeq ($(HAVE_BUILDDEFS), no) + $(MAKE) -C . $@ +else + $(SUBDIRS_MAKERULE) +endif + +ifeq ($(HAVE_BUILDDEFS), yes) +include $(BUILDRULES) +else +clean: # if configure hasn't run, nothing to clean +endif + +$(CONFIGURE): configure.in include/builddefs.in + rm -f config.cache + autoconf + ./configure + +install install-dev: default + $(SUBDIRS_MAKERULE) + +realclean distclean: clean + rm -f $(LDIRT) $(CONFIGURE) diff -rNu linux-2.4.7/cmd/xfstests/README linux-2.4-xfs/cmd/xfstests/README --- linux-2.4.7/cmd/xfstests/README Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/README Sun Jan 14 23:01:19 2001 @@ -0,0 +1,174 @@ +______________________ +USING THE XFS QA SUITE +______________________ + +Preparing system for tests: + + - compile XFS into your kernel or load XFS modules + - install user tools including mkfs.xfs, xfs_db & xfs_bmap + + - create two partitions to use for testing + - one TEST partition + - format as XFS, mount & optionally populate with + NON-IMPORTANT stuff + - one SCRATCH partition + - leave empty and expect this partition to be clobbered + by some tests. + + (these must be two DIFFERENT partitions) + + - setup your environment + - setenv TEST_DEV "device containing TEST PARTITION" + - setenv TEST_DIR "mount point of TEST PARTITION" + - setenv SCRATCH_DEV "device containing SCRATCH PARTITION" + - setenv SCRATCH_MNT "mount point for SCRATCH PARTITION" + - setenv TAPE_DEV "tape device for testing xfsdump" + - setenv RMT_TAPE_DEV "remote tape device for testing xfsdump" + - setenv RMT_IRIXTAPE_DEV "remote IRIX tape device for testing xfsdump" + - optionally: + - setenv SCRATCH_LOGDEV "device for external log" + - setenv SCRATCH_RTDEV "device for realtime data" + - or add a case to the switch in common.config assigning + these variables based on the hostname of your test + machine + + - if testing xfsdump, make sure the tape devices have a + tape which can be overwritten. + + - make sure $TEST_DEV is a mounted XFS partition + - make sure that $SCRATCH_DEV contains nothing useful + +Running tests: + + - cd cmd/xfs/stress + - ./check 001 002 003 ... + + The check script tests the return value of each script, and + compares the output against the expected output. If the output + is not as expected, a diff will be output and an .out.bad file + will be produced for the failing test. + + Unexpected console messages, crashes and hangs may be considered + to be failures but are not necesarily detected by the QA system. + +__________________________ +ADDING TO THE XFS QA SUITE +__________________________ + + +Creating new tests scripts: + + Use the "new" script. + +Test script environment: + + When developing a new test script keep the following things in + mind. All of the environment variables and shell procedures are + available to the script once the "common.rc" file has been + sourced. + + 1. The tests are run from an arbitrary directory. If you want to + do operations on an XFS filesystem (good idea, eh?), then do + one of the following: + + (a) Create directories and files at will in the directory + $TEST_DIR ... this is within an XFS filesystem and world + writeable. You should cleanup when your test is done, + e.g. use a _cleanup shell procedure in the trap ... see + 001 for an example. If you need to know, the $TEST_DIR + direcotry is within the filesystem on the block device + $TEST_DEV. + + (b) mkfs a new XFS filesystem on $SCRATCH_DEV, and mount this + on $SCRATCH_MNT. Call the the _require_scratch function + on startup if you require use of the scratch partition. + _require_scratch does some checks on $SCRATCH_DEV & + $SCRATCH_MNT and makes sure they're unmounted. You should + cleanup when your test is done, and in particular unmount + $SCRATCH_MNT. + Tests can make use of $SCRATCH_LOGDEV and $SCRATCH_RTDEV + for testing external log and realtime volumes - however, + these tests need to simply "pass" (e.g. cat $seq.out; exit + - or default to an internal log) in the common case where + these variables are not set. + + 2. You can safely create temporary files that are not part of the + filesystem tests (e.g. to catch output, prepare lists of things + to do, etc.) in files named $tmp.. The standard test + script framework created by "new" will initialize $tmp and + cleanup on exit. + + 3. By default, tests are run as the same uid as the person + executing the control script "check" that runs the test scripts. + + If you need to be root, add a call to the shell procedure + _need_to_be_root ... this will do nothing or exit with an + error message depending on your current uid. + + 4. Some other useful shell procedures: + + _get_fqdn - echo the host's fully qualified + domain name + + _get_pids_by_name - one argument is a process name, and + return all of the matching pids on + standard output + + _within_tolerance - fancy numerical "close enough is good + enough" filter for deterministic + output ... see comments in + common.filter for an explanation + + _filter_date - turn ctime(3) format dates into the + string DATE for deterministic + output + +Verified output: + + Each test script has a numerical name, e.g. 007, and an associated + verified output, e.g. 007.out. + + It is important that the verified output is deterministic, and + part of the job of the test script is to filter the output to + make this so. Examples of the sort of things that need filtering: + + - dates + - pids + - hostnames + - filesystem names + - timezones + - variable directory contents + - imprecise numbers, especially sizes and times + + Use the "remake" script to recreate the verified output for one + or more tests. + +Pass/failure: + + The script "check" may be used to run one or more tests. + + Test number $seq is deemed to "pass" when: + (a) no "core" file is created, + (b) the file $seq.notrun is not created, + (c) the exit status is 0, and + (d) the output matches the verified output. + + In the "not run" case (b), the $seq.notrun file should contain a + short one-line summary of why the test was not run. The standard + output is not checked, so this can be used for a more verbose + explanation and to provide feedback when the QA test is run + interactively. + + + To force a non-zero exit status use: + status=1 + exit + + Note that: + exit 1 + won't have the desired effect becuase of the way the exit trap + works. + + The recent pass/fail history is maintained in the file "check.log". + The elapsed time for the most recent pass for each test is kept + in "check.time". diff -rNu linux-2.4.7/cmd/xfstests/VERSION linux-2.4-xfs/cmd/xfstests/VERSION --- linux-2.4.7/cmd/xfstests/VERSION Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/VERSION Mon Jan 15 22:10:42 2001 @@ -0,0 +1,7 @@ +# +# This file is used by configure to get version information +# +PKG_MAJOR=1 +PKG_MINOR=0 +PKG_REVISION=0 +PKG_BUILD=0 diff -rNu linux-2.4.7/cmd/xfstests/check linux-2.4-xfs/cmd/xfstests/check --- linux-2.4.7/cmd/xfstests/check Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/check Tue May 22 01:07:23 2001 @@ -0,0 +1,279 @@ +#!/bin/sh + +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# +# Control script for QA +# +# $Header: /build2/depot/linux/pcp/dev/qa/RCS/check,v 2.32 1999/10/18 06:58:20 kenmcd Exp $ +# + +tmp=/tmp/$$ +status=0 +needwrap=true +try=0 +n_bad=0 +bad="" +notrun="" +interrupt=true + +# generic initialization +iam=check +if ! . ./common.rc +then + echo "check: failed to source common.rc" + exit 1 +fi + +if [ $UID -ne 0 ] +then + echo "check: QA must be run as root" + exit 1 +fi + +_wallclock() +{ + date "+%H %M %S" | $AWK_PROG '{ print $1*3600 + $2*60 + $3 }' +} + +_timestamp() +{ + now=`date "+%D-%T"` + echo -n " [$now]" +} + +_wrapup() +{ + # for hangcheck ... + # remove files that were used by hangcheck + # + [ -f /tmp/check.pid ] && rm -rf /tmp/check.pid + [ -f /tmp/check.sts ] && rm -rf /tmp/check.sts + + if $showme + then + : + elif $needwrap + then + if [ -f check.time -a -f $tmp.time ] + then + cat check.time $tmp.time \ + | $AWK_PROG ' + { t[$1] = $2 } +END { if (NR > 0) { + for (i in t) print i " " t[i] + } + }' \ + | sort -n >$tmp.out + mv $tmp.out check.time + fi + + if [ -f $tmp.expunged ] + then + notrun=`wc -l <$tmp.expunged | sed -e 's/ *//g'` + try=`expr $try - $notrun` + list=`echo "$list" | sed -f $tmp.expunged` + fi + + echo "" >>check.log + date >>check.log + echo $list | fmt | sed -e 's/^/ /' >>check.log + $interrupt && echo "Interrupted!" >>check.log + + if [ ! -z "$notrun" ] + then + echo "Not run:$notrun" + echo "Not run:$notrun" >>check.log + fi + if [ ! -z "$n_bad" -a $n_bad != 0 ] + then + echo "Failures:$bad" + echo "Failed $n_bad of $try tests" + echo "Failures:$bad" | fmt >>check.log + echo "Failed $n_bad of $try tests" >>check.log + else + echo "Passed all $try tests" + echo "Passed all $try tests" >>check.log + fi + needwrap=false + fi + + rm -f $tmp.* +} + +trap "_wrapup; exit \$status" 0 1 2 3 15 + +# for hangcheck ... +# Save pid of check in a well known place, so that hangcheck can be sure it +# has the right pid (getting the pid from ps output is not reliable enough). +# +rm -rf /tmp/check.pid +echo $$ >/tmp/check.pid + +# for hangcheck ... +# Save the status of check in a well known place, so that hangcheck can be +# sure to know where check is up to (getting test number from ps output is +# not reliable enough since the trace stuff has been introduced). +# +rm -rf /tmp/check.sts +echo "preamble" >/tmp/check.sts + +# don't leave old full output behind on a clean run +rm -f check.full + +# by default don't output timestamps +timestamp=false + +. ./common + +[ -f check.time ] || touch check.time + +if [ ! -z "$MOUNT_OPTIONS" ] +then + echo "check: \$MOUNT_OPTIONS specified - \"$MOUNT_OPTIONS\"" + umount $TEST_DEV + # call the overridden mount - make sure the FS starts as + # the same as we'll set it later. + if ! mount -t xfs $TEST_DEV $TEST_DIR >$tmp.err 2>&1 + then + echo "our mount ..." + cat $tmp.err + # call the normal mount + echo "normal mount ..." + /bin/mount -t xfs $TEST_DEV $TEST_DIR + echo "check: failed to mount \$TEST_DEV using specified mount options" + exit 1 + fi +fi + +seq="check" +_check_fs $TEST_DEV + +for seq in $list +do + err=false + echo -n "$seq" + if $showme + then + echo + continue + elif [ -f expunged ] && $expunge && egrep "^$seq([ ]|\$)" expunged >/dev/null + then + echo " - expunged" + rm -f $seq.out.bad + echo "/^$seq\$/d" >>$tmp.expunged + elif [ ! -f $seq ] + then + echo " - no such test?" + echo "/^$seq\$/d" >>$tmp.expunged + else + # really going to try and run this one + # + rm -f $seq.out.bad + lasttime=`sed -n -e "/^$seq /s/.* //p" /tmp/check.sts + + start=`_wallclock` + $timestamp && _timestamp + sh $seq >$tmp.rawout 2>&1 + sts=$? + $timestamp && _timestamp + stop=`_wallclock` + + _fix_malloc <$tmp.rawout >$tmp.out + rm -f $tmp.rawout + + if [ -f core ] + then + echo -n " [dumped core]" + mv core $seq.core + err=true + fi + + if [ -f $seq.notrun ] + then + echo -n " [not run] " + cat $seq.notrun + notrun="$notrun $seq" + else + if [ $sts -ne 0 ] + then + echo -n " [failed, exit status $sts]" + err=true + fi + if [ ! -f $seq.out ] + then + echo " - no qualified output" + err=true + else + if diff $seq.out $tmp.out >/dev/null 2>&1 + then + echo "" + if $err + then + : + else + echo "$seq `expr $stop - $start`" >>$tmp.time + fi + else + echo " - output mismatch (see $seq.out.bad)" + mv $tmp.out $seq.out.bad + $diff $seq.out $seq.out.bad + err=true + fi + fi + fi + + fi + + # come here for each test, except when $showme is true + # + if $err + then + bad="$bad $seq" + n_bad=`expr $n_bad + 1` + quick=false + fi + [ -f $seq.notrun ] || try=`expr $try + 1` + + seq="after_$seq" + _check_fs $TEST_DEV + +done + +interrupt=false +status=`expr $n_bad` +exit diff -rNu linux-2.4.7/cmd/xfstests/common linux-2.4-xfs/cmd/xfstests/common --- linux-2.4.7/cmd/xfstests/common Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/common Sun Jan 14 23:01:19 2001 @@ -0,0 +1,287 @@ +##/bin/sh +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# common procedures for QA scripts +# +# $Header: /disk7/depot/linux/pcp/dev/qa/RCS/common,v 2.52 2000/04/05 18:24:51 kenmcd Exp $ +# + +_setenvironment() +{ + MSGVERB="text:action" + export MSGVERB +} + +here=`pwd` +rm -f $here/$iam.out +_setenvironment + +check=${check-true} + +if $check +then + if make >/tmp/$$.make 2>&1 + then + : + else + cat /tmp/$$.make + echo "Warning: make failed -- some tests may be missing" + warn=1 + fi + rm -f /tmp/$$.make +fi + +diff=diff +if [ ! -z "$DISPLAY" ] +then + which xdiff >/dev/null 2>&1 && diff=xdiff + which gdiff >/dev/null 2>&1 && diff=gdiff + which tkdiff >/dev/null 2>&1 && diff=tkdiff +fi +verbose=false +quick=${quick-false} +group=false +xgroup=false +showme=false +sortme=false +expunge=true +have_test_arg=false +rm -f $tmp.list $tmp.tmp $tmp.sed + +for r +do + + if $group + then + # arg after -g + group_list=`sed -n /dev/null + then + : + else + echo "$t" >>$tmp.list + fi + done + group=false + continue + + elif $xgroup + then + # arg after -x + [ ! -s $tmp.list ] && ls [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] >$tmp.list 2>/dev/null + group_list=`sed -n $tmp.tmp + mv $tmp.tmp $tmp.list + numsed=0 + rm -f $tmp.sed + fi + echo "/^$t\$/d" >>$tmp.sed + numsed=`expr $numsed + 1` + done + sed -f $tmp.sed <$tmp.list >$tmp.tmp + mv $tmp.tmp $tmp.list + xgroup=false + continue + fi + + xpand=true + case "$r" + in + + -\?) # usage + echo "Usage: $0 [options] [testlist]"' + +common options + -v verbose + +check options + -g group[,group...] include tests from these groups + -l line mode diff [xdiff] + -n show me, do not run tests + -q quick, no checks (you are on your own) + -T output timestamps + -x group[,group...] exclude tests from these groups +' + exit 0 + ;; + + -g) # -g group ... pick from group file + group=true + xpand=false + ;; + + -l) # line mode for diff, not gdiff over modems + diff=diff + xpand=false + ;; + + -q) # "quick", no checks (you are on your own) + quick=true + xpand=false + ;; + + -n) # show me, don't do it + showme=true + xpand=false + ;; + + -T) # turn on timestamp output + timestamp=true + xpand=false + ;; + + -v) + verbose=true + xpand=false + ;; + + -x) # -x group ... exclude from group file + xgroup=true + xpand=false + ;; + + '[0-9][0-9][0-9] [0-9][0-9][0-9][0-9]') + echo "No tests?" + status=1 + exit $status + ;; + + [0-9]*-[0-9]*) + eval `echo $r | sed -e 's/^/start=/' -e 's/-/ end=/'` + ;; + + [0-9]*-) + eval `echo $r | sed -e 's/^/start=/' -e 's/-//'` + end=`echo [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] | sed -e 's/\[0-9]//g' -e 's/ *$//' -e 's/.* //'` + if [ -z "$end" ] + then + echo "No tests in range \"$r\"?" + status=1 + exit $status + fi + ;; + + *) + start=$r + end=$r + ;; + + esac + + if $xpand + then + have_test_arg=true + $AWK_PROG /dev/null + then + # in group file ... OK + echo $id >>$tmp.list + else + if [ -f expunged ] && $expunge && egrep "^$id([ ]|\$)" expunged >/dev/null + then + # expunged ... will be reported, but not run, later + echo $id >>$tmp.list + else + # oops + echo "$id - unknown test, ignored" + fi + fi + done + fi + +done + +if [ -s $tmp.list ] +then + # found some valid test numbers ... this is good + : +else + if $have_test_arg + then + # had test numbers, but none in group file ... do nothing + touch $tmp.list + else + # no test numbers, do everything from group file + sed -n -e '/^[0-9][0-9][0-9]*/s/[ ].*//p' $tmp.list + fi +fi + +# should be sort -n, but this did not work for Linux when this +# was ported from IRIX +# +list=`sort $tmp.list` +rm -f $tmp.list $tmp.tmp $tmp.sed + +if $quick +then + : +else + + if ( cd src; make -i ) + then + : + else + echo + echo ":----------------------------------------------" + echo ": Warning: make failed in src -- some tests may fail as a result" + echo ":----------------------------------------------" + echo + warn=1 + fi + +fi diff -rNu linux-2.4.7/cmd/xfstests/common.attr linux-2.4-xfs/cmd/xfstests/common.attr --- linux-2.4.7/cmd/xfstests/common.attr Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/common.attr Thu Apr 5 22:23:12 2001 @@ -0,0 +1,78 @@ +##/bin/sh + +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +# common extended attribute and ACL support + +# pick three unused user/group ids, store them as $acl[1-3] +# +_acl_setup_ids() +{ + eval `cat /etc/passwd /etc/group | awk -F: ' + { ids[$3]=1 } + END { + j=1 + for(i=1; i<1000000 && j<=3;i++){ + if (! (i in ids)) { + printf "acl%d=%d;", j, i; + j++ + } + } + }'` +} + +# filter for the acl ids selected above +# +_acl_filter_id() +{ + sed \ + -e "s/u:$acl1/u:id1/" \ + -e "s/u:$acl2/u:id2/" \ + -e "s/u:$acl3/u:id3/" \ + -e "s/g:$acl1/g:id1/" \ + -e "s/g:$acl2/g:id2/" \ + -e "s/g:$acl3/g:id3/" \ + -e "s/ $acl1 / id1 /" \ + -e "s/ $acl2 / id2 /" \ + -e "s/ $acl3 / id3 /" +} + +# filtered ls +# +_acl_ls() +{ + ls -ln $* | awk '{ print $1, $3, $4, $NF }' | _acl_filter_id +} + +# make sure this script returns success +/bin/true diff -rNu linux-2.4.7/cmd/xfstests/common.config linux-2.4-xfs/cmd/xfstests/common.config --- linux-2.4.7/cmd/xfstests/common.config Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/common.config Wed May 9 03:38:23 2001 @@ -0,0 +1,202 @@ +##/bin/sh + +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +# +# setup and check for config parameters, and in particular +# +# TEST_DIR - scratch test directory that is in an already +# mounted XFS file system, needs to be be world +# writeable +# TEST_DEV - device for file system containing TEST_DIR +# SCRATCH_DEV - device you can make a scratch file system on +# SCRATCH_MNT - mount point for scratch file system +# +# and optionally: +# SCRATCH_LOGDEV - scratch log device for external log testing +# SCRATCH_RTDEV - scratch rt dev (only for testing cmds currently) +# TAPE_DEV - the tape device for the xfsdump tests +# RMT_TAPE_DEV - the remote tape device for the xfsdump tests +# RMT_IRIXTAPE_DEV - the IRIX remote tape device for the xfsdump tests +# RMT_TAPE_USER - remote user for tape device +# + +# +# - This script is shared by the stress test system and the auto-qa +# system +# - TEST_DEV & TEST_DIR must be assigned. +# - this script shouldn't make any assertions about filesystem +# validity or mountedness. +# + +_readlink() +{ + if [ $# -ne 1 ] + then + echo "Usage: _readlink filename" 1>&2 + exit 1 + fi + + perl -e "\$in=\"$1\";" -e ' + $lnk = readlink($in); + if ($lnk =~ m!^/.*!) { + print "$lnk\n"; + } + else { + chomp($dir = `dirname $in`); + print "$dir/$lnk\n"; + }' +} + + +case `hostname -s` +in + fuzzy) + TEST_DEV=/dev/sda6 + TEST_DIR=/mnt/xfs1 + SCRATCH_DEV=/dev/sda5 + SCRATCH_MNT=/mnt/xfs0 + SCRATCH_LOGDEV=/dev/sda7 + TAPE_DEV=/dev/st0 + RMT_TAPE_DEV=fuzzy:/dev/st0 + RMT_IRIXTAPE_DEV=snort:/dev/tape + RMT_TAPE_USER=guest + ;; + bruce) + TEST_DEV=/dev/sda10 + TEST_DIR=/mnt/xfs1 + SCRATCH_DEV=/dev/sda9 + SCRATCH_MNT=/mnt/xfs0 + SCRATCH_LOGDEV=/dev/sda11 + TAPE_DEV=/dev/st0 + RMT_TAPE_DEV=bruce:/dev/st0 + RMT_IRIXTAPE_DEV=snort:/dev/tape + ;; + sherman) + TEST_DEV=/dev/sda10 + TEST_DIR=/mnt/xfs1 + SCRATCH_DEV=/dev/sda9 + SCRATCH_MNT=/mnt/xfs0 + ;; + sagan) + TEST_DEV=/dev/sda6 + TEST_DIR=/mnt/xfs0 + SCRATCH_DEV=/dev/sda7 + SCRATCH_MNT=/mnt/xfs1 + TAPE_DEV=/dev/st0 + RMT_TAPE_DEV=sagan:/dev/st0 + RMT_IRIXTAPE_DEV=snort:/dev/tape + RMT_TAPE_USER=guest + ;; + leesa) + TEST_DEV=/dev/xfs_test + TEST_DIR=/mnt/xfs_test + SCRATCH_DEV=/dev/xfs_scratch + SCRATCH_MNT=/mnt/xfs_scratch + SCRATCH_LOGDEV=/dev/xfs_log + ;; + troppo) + TEST_DEV=/dev/hdb13 + TEST_DIR=/mnt/test + SCRATCH_DEV=/dev/hdb14 + SCRATCH_MNT=/mnt/scratch + SCRATCH_RTDEV=/dev/hdb15 + SCRATCH_LOGDEV=/dev/hdb16 + ;; + lord) + TEST_DIR=/xfs + TEST_DEV=/dev/sda4 + SCRATCH_DEV=/dev/hda2 + SCRATCH_MNT=/xfs1 + ;; + lumpy) + TEST_DEV=/dev/sdc5 + TEST_DIR=/mnt/scratch_0 + SCRATCH_DEV=/dev/sdc7 + SCRATCH_MNT=/mnt/scratch_2 + ;; + bongo) + TEST_DEV=/dev/hda8 + TEST_DIR=/xfs1 + SCRATCH_DEV=/dev/hda9 + SCRATCH_MNT=/xfs2 + SCRATCH_LOGDEV=/dev/hda10 + SCRATCH_RTDEV=/dev/hda11 + ;; + snowy) + TEST_DEV=/dev/sda7 + TEST_DIR=/mnt/xfs0 + SCRATCH_DEV=/dev/sda8 + SCRATCH_MNT=/mnt/xfs1 + SCRATCH_LOGDEV=/dev/sda9 + ;; + + *) + echo "common.config: Error: need to define parameters for host `hostname -s`" + exit 1 + ;; +esac + +if [ ! -b "$TEST_DEV" ] +then + echo "common.config: Error: \$TEST_DEV ($TEST_DEV) is not a block device" + exit 1 +fi + +if [ ! -d "$TEST_DIR" ] +then + echo "common.config: Error: \$TEST_DIR ($TEST_DIR) is not a directory" + exit 1 +fi + +if [ ! -z "$SCRATCH_DEV" -a ! -b "$SCRATCH_DEV" ] +then + echo "common.config: Error: \$SCRATCH_DEV ($SCRATCH_DEV) is not a block device" + exit 1 +fi + +if [ ! -z "$SCRATCH_DEV" -a ! -d "$SCRATCH_MNT" ] +then + echo "common.config: Error: \$SCRATCH_MNT ($SCRATCH_MNT) is not a directory" + exit 1 +fi + +# if devfs is running expand the full /dev/.. pathname - this is what will be +# returned by utilities such as mount +[ -L "$TEST_DEV" ] && TEST_DEV=`_readlink $TEST_DEV` +[ -L "$SCRATCH_DEV" ] && SCRATCH_DEV=`_readlink $SCRATCH_DEV` +[ -L "$SCRATCH_LOGDEV" ] && SCRATCH_LOGDEV=`_readlink $SCRATCH_LOGDEV` +[ -L "$SCRATCH_RTDEV" ] && SCRATCH_RTDEV=`_readlink $SCRATCH_LOGDEV` + +# make sure this script returns success +/bin/true diff -rNu linux-2.4.7/cmd/xfstests/common.dump linux-2.4-xfs/cmd/xfstests/common.dump --- linux-2.4.7/cmd/xfstests/common.dump Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/common.dump Thu May 24 00:36:12 2001 @@ -0,0 +1,922 @@ +##/bin/sh + +# +# Functions useful for xfsdump/xfsrestore tests +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +# --- initializations --- +rm -f $seq.full + +if [ -n "$DEBUGDUMP" ]; then + _dump_debug=-v5 + _restore_debug=-v5 + _invutil_debug=-d +fi + +# Use dump/restore in qa directory for debugging +#PATH=".:$PATH" +#export PATH +#which xfsdump +#which xfsrestore + +# status returned for not run tests +NOTRUNSTS=2 + +# name those directories +dump_dir=$SCRATCH_MNT/dump.$$ +dump_file=$tmp.dumpfile +dump_sdir=dump.$$ +restore_dir=$SCRATCH_MNT/restore.$$ +restore_sdir=restore.$$ + +dumptape=$TAPE_DEV +media_label="stress_tape_media" +session_label="stress_$seq" + +nobody=4 # define this uid/gid as a number + +_need_to_be_root + +# install our cleaner +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# start inventory from a known base - move it aside for test +if [ -d /var/xfsdump/inventory ]; then + if [ -d /var/xfsdump/inventory.$seq ]; then + rm -rf /var/xfsdump/inventory.$seq + fi + mv /var/xfsdump/inventory /var/xfsdump/inventory.$seq +fi + + +# +# do a remote/local mt +# +_mt() +{ + op=$1 + if _isrmt; then + # REMOTE + _rmtdev=`echo $dumptape | awk -F: '{print $2}'` + + if echo $dumptape | grep '@' >/dev/null; then + _spec=`echo $dumptape | awk -F: '{print $1}'` + _rmtuser=`echo $_spec | awk -F@ '{print $1}'` + _rmthost=`echo $_spec | awk -F@ '{print $2}'` + rsh -n -l $_rmtuser $_rmthost "mt -t $_rmtdev $op" + else + _rmthost=`echo $dumptape | awk -F: '{print $1}'` + rsh -n $_rmthost "mt -t $_rmtdev $op" + fi + else + #LOCAL + mt -t $dumptape $op + fi +} + +_check_onl() +{ + _limit=10 + i=0 + while [ $i -lt $_limit ]; do + echo "Checking online..." >>$seq.full + if _mt status >$tmp.status 2>&1; then + break; + else + sleep 2 + fi + i=`expr $i + 1` + done + + + if [ $i -eq $_limit ]; then + echo "ERROR: mt -f $dumptape failed" + cat $tmp.status + + echo "mt -f $dumptape failed" >$seq.notrun + status=$NOTRUNSTS + exit + fi + + + if egrep -i 'onl|ready' $tmp.status | grep -iv 'not ready' >/dev/null; then + : + else + echo "ERROR: $dumptape is not online" + cat $tmp.status + + echo "dumptape, $dumptape, is not online" >$seq.notrun + status=$NOTRUNSTS + exit + fi +} + +_wait_tape() +{ + echo "Wait for tape, $dumptape, ..." >>$seq.full + + i=0 + while [ $i -lt 20 ]; do + echo "Checking status..." >>$seq.full + if _mt status 2>&1 | tee -a $seq.full | egrep -i "onl|ready" >/dev/null; then + break; + else + sleep 2 + fi + i=`expr $i + 1` + done +} + +# +# Keep trying so we know we really have rewound +# +_rewind() +{ + echo "Initiate rewind..." >>$seq.full + _wait_tape + _mt rewind >/dev/null + _wait_tape +} + +# +# Do a custom erase because: +# (i) some machines don't support it +# (ii) some machines take forever to do it +# +_erase_soft() +{ + echo "Erasing tape" | tee -a $seq.full + _rewind + _mt weof 3 + _rewind +} + +_erase_hard() +{ + echo "Erasing tape" | tee -a $seq.full + _mt erase +} + +_isrmt() +{ + echo $dumptape | grep ':' >/dev/null +} + +# +# Get tape ready +# +_set_variable() +{ + if _isrmt; then + : + else + # LOCAL + echo "Put scsi tape driver into variable block size mode" + mt -f $dumptape setblk 0 + fi +} + +_require_tape() +{ + dumptape=$1 + + if [ -z "$dumptape" ]; then + echo "This test requires a dump tape - none was specified" + echo "No dump tape specified" >$seq.notrun + status=$NOTRUNSTS + exit + fi + + _check_onl + _set_variable +} + +_error() +{ + echo "Error: $*" | tee -a $seq.full + echo "(see $seq.full for details)" + status=1 + exit +} + +_wipe_fs() +{ + _require_scratch + + mkfs -t xfs -f $SCRATCH_DEV >>$seq.full ||\ + _error "mkfs failed" + + mount -t xfs $SCRATCH_DEV $SCRATCH_MNT >>$seq.full ||\ + _error "mount failed" +} + +# +# Cleanup created dirs and files +# Called by trap +# +_cleanup() +{ + cd $here + rm -f $tmp.* + + if [ -n "$DEBUGDUMP" ]; then + # save it for inspection + tar -zcvf $seq.inventory.tgz /var/xfsdump/inventory + ls -lR /var/xfsdump/inventory >$seq.inventory.ls + fi + + # put inventory dir back + if [ -d /var/xfsdump/inventory.$seq ]; then + rm -rf /var/xfsdump/inventory # get rid of new one + mv /var/xfsdump/inventory.$seq /var/xfsdump/inventory + fi + + if [ $status -ne $NOTRUNSTS ]; then + # Sleep added to stop _check_fs from complaining that the + # scratch_dev is still busy + sleep 10 + + _check_fs $SCRATCH_DEV + fi +} + +_stable_fs() +{ +# umount $SCRATCH_MNT >/dev/null +# mount $SCRATCH_MNT >/dev/null + sync; sync; sleep 15 +} + +# +# Run src/fsstress to create a mixture of +# files,dirs,links,symlinks +# +# Pinched from test 013. +# +_create_dumpdir_stress() +{ + echo "Creating directory system to dump using src/fsstress." + + _wipe_fs + _setup_seq_out + + _param="-f link=10 -f creat=10 -f mkdir=10 -f truncate=5 -f symlink=10" + _count=200 + rm -rf $dump_dir + if ! mkdir $dump_dir; then + echo " failed to mkdir $dump_dir" + status=1 + exit + fi + echo "" + echo "-----------------------------------------------" + echo "fsstress : $_param" + echo "-----------------------------------------------" + if ! $here/src/fsstress $_param $FSSTRESS_AVOID -n $_count -d $dump_dir >$tmp.out 2>&1 + then + echo " fsstress (count=$_count) returned $? - see $seq.full" + + echo "--------------------------------------" >>$here/$seq.full + echo "output from fsstress:" >>$here/$seq.full + echo "--------------------------------------" >>$here/$seq.full + cat $tmp.out >>$here/$seq.full + status=1 + fi + + _stable_fs +} + +_mk_fillconfig1() +{ + cat <$tmp.config +# pathname size in bytes owner group +# +small 10 $nobody $nobody +big 102400 daemon sys +sub/small 10 bin bin +sub/big 102400 $nobody sys +# +sub/a 1 $nobody $nobody +sub/b 2 $nobody $nobody +sub/c 4 $nobody $nobody +sub/d 8 $nobody $nobody +sub/e 16 $nobody $nobody +sub/f 32 $nobody $nobody +sub/g 64 $nobody $nobody +sub/h 128 $nobody $nobody +sub/i 256 $nobody $nobody +sub/j 512 $nobody $nobody +sub/k 1024 $nobody $nobody +sub/l 2048 $nobody $nobody +sub/m 4096 $nobody $nobody +sub/n 8192 $nobody $nobody +# +sub/a00 100 $nobody $nobody +sub/b00 200 $nobody $nobody +sub/c00 400 $nobody $nobody +sub/d00 800 $nobody $nobody +sub/e00 1600 $nobody $nobody +sub/f00 3200 $nobody $nobody +sub/g00 6400 $nobody $nobody +sub/h00 12800 $nobody $nobody +sub/i00 25600 $nobody $nobody +sub/j00 51200 $nobody $nobody +sub/k00 102400 $nobody $nobody +sub/l00 204800 $nobody $nobody +sub/m00 409600 $nobody $nobody +sub/n00 819200 $nobody $nobody +# +sub/a000 1000 $nobody $nobody +sub/e000 16000 $nobody $nobody +sub/h000 128000 $nobody $nobody +sub/k000 1024000 $nobody $nobody +End-of-File +} + +_mk_fillconfig2() +{ + cat <$tmp.config +# pathname size in bytes +# +smalll 10 $nobody $nobody +biggg 102400 $nobody $nobody +sub/smalll 10 $nobody $nobody +sub/biggg 102400 $nobody $nobody +End-of-File +} + +_mk_fillconfig_perm() +{ + cat <$tmp.config +# pathname size/dir user group mode +# +file_suid 10 $nobody $nobody 04777 +file_guid 10 $nobody $nobody 02777 +file_sticky 10 $nobody $nobody 01777 +file_mix1 10 $nobody $nobody 761 +file_mix2 10 $nobody $nobody 642 +dir_suid d $nobody $nobody 04777 +dir_guid d $nobody $nobody 02777 +dir_sticky d $nobody $nobody 01777 +dir_mix1 d $nobody $nobody 761 +dir_mix2 d $nobody $nobody 642 +End-of-File +} + +# +# Create a bunch of directories/files of different sizes +# filled with data. +# +# Pinched from test 001. +# +_do_create_dumpdir_fill() +{ + echo "Creating directory system to dump using src/fill." + + if mkdir -p $dump_dir + then + : + else + echo "Error: cannot mkdir \"$dump_dir\"" + exit 1 + fi + cd $dump_dir + + $verbose && echo -n "Setup " + sed -e '/^#/d' $tmp.config \ + | while read file nbytes owner group perms + do + if [ $nbytes = "d" ]; then + # create a directory + dir=$file + if [ ! -d $dir ] + then + if mkdir $dir + then + : + else + $verbose && echo + echo "Error: cannot mkdir \"$dir\"" + exit 1 + fi + fi + else + # create a directory/file + dir=`dirname $file` + if [ "$dir" != "." ] + then + if [ ! -d $dir ] + then + if mkdir $dir + then + : + else + $verbose && echo + echo "Error: cannot mkdir \"$dir\"" + exit 1 + fi + fi + fi + rm -f $file + if $here/src/fill $file $file $nbytes + then + : + else + $verbose && echo + echo "Error: cannot create \"$file\"" + exit 1 + fi + fi + if [ -n "$owner" -a -n "$group" ]; then + chown $owner.$group $file + fi + if [ -n "$perms" ]; then + chmod $perms $file + fi + $verbose && echo -n "." + done + $verbose && echo + + cd $here +} + + +_create_dumpdir_fill() +{ + _wipe_fs + _setup_seq_out + _mk_fillconfig1 + _do_create_dumpdir_fill + _stable_fs +} + +_create_dumpdir_fill2() +{ + _wipe_fs + _setup_seq_out + _mk_fillconfig2 + _do_create_dumpdir_fill + _stable_fs +} + +_create_dumpdir_fill_perm() +{ + _wipe_fs + _setup_seq_out + _mk_fillconfig_perm + _do_create_dumpdir_fill + _stable_fs +} + + + +# +# Append a subset of the fill'ed files +# So we can see if just these get dumped on an incremental +# +_append_dumpdir_fill() +{ + cd $dump_dir + cat <$tmp.config +# pathname +# +small +sub/big +# +sub/a +sub/c +sub/e +End-of-File + sed -e '/^#/d' $tmp.config \ + | while read file + do + echo 'Extra text' >>$file + done + + cd $here +} + +_do_create_dump_symlinks() +{ + echo "Creating directory system of symlinks to dump." + + if mkdir -p $dump_dir + then + : + else + echo "Error: cannot mkdir \"$dump_dir\"" + exit 1 + fi + cd $dump_dir + + $verbose && echo -n "Setup " + sed -e '/^#/d' $tmp.config \ + | while read file nbytes owner group owner2 group2 perms perms2 + do + dir=`dirname $file` + if [ "$dir" != "." ] + then + if [ ! -d $dir ] + then + if mkdir $dir + then + : + else + $verbose && echo + echo "Error: cannot mkdir \"$dir\"" + exit 1 + fi + fi + fi + rm -f $file + touch $file + + # Do chmod on symlink using umask. + # This won't do the right thing as it subtracts permissions. + # However, I don't care, as long as I get some different perms + # for testing. + if [ -n "$perms2" ]; then + omask=`umask` + umask $perms2 + fi + ln -s $file $file-link + if [ -n "$perms2" ]; then + umask $omask + fi + + if [ -n "$owner" -a -n "$group" ]; then + chown $owner.$group $file + fi + if [ -n "$owner" -a -n "$group" ]; then + chown -h $owner.$group $file-link + fi + if [ -n "$perms" ]; then + chmod $perms $file + fi + $verbose && echo -n "." + done + $verbose && echo + + cd $here +} + +_mk_symlink_config() +{ + cat <$tmp.config +# path size owner1 group1 owner2 group2 perm1 perm2 +# +a 0 $nobody $nobody daemon sys 124 421 +b 0 daemon sys bin bin 347 743 +sub/a 0 bin bin $nobody sys 777 777 +sub/b 0 $nobody sys $nobody $nobody 367 763 +End-of-File +} + +_create_dumpdir_symlinks() +{ + _wipe_fs + _setup_seq_out + _mk_symlink_config + _do_create_dump_symlinks + _stable_fs +} + +# +# Filter for ls +# Filter out dates on symlinks +# +_ls_filter() +{ + $AWK_PROG '/^l/ { date = $8; sub(date,"DATE"); print} + {print}' \ + | sed -e 's/total [0-9][0-9]*/total TOTAL/' +} + + +# +# Filter out the non-deterministic dump msgs from +# xfsdump and xfsrestore +# +_dump_filter() +{ + sed \ + -e "s/`hostname`/HOSTNAME/" \ + -e "s#$SCRATCH_DEV#SCRATCH_DEV#" \ + -e "s#$dumptape#TAPE_DEV#" \ + -e "s#$SCRATCH_MNT#SCRATCH_MNT#" \ + -e "s#$dump_file#DUMP_FILE#" \ + -e 's/id:[ ]*[0-9a-f-]*/id: ID/' \ + -e 's/time:[ ].*/time: TIME/' \ + -e 's/date:[ ].*/date: DATE/' \ + -e 's/dump begun .*/dump begun DATE/' \ + -e 's/[0-9][0-9]* seconds/SECS seconds/' \ + -e 's/restore.[0-9][0-9]*/restore.PID/' \ + -e 's/ino [0-9][0-9]*/ino INO/' \ + -e '/: dump size/s/[1-9][0-9]*/NUM/' \ + -e '/dump size:/s/[1-9][0-9]*/NUM/' \ + -e '/media file size/s/[1-9][0-9]*/NUM/' \ + -e '/mfile size:[ ]*/s/[1-9][0-9]*/NUM/' \ + -e '/\/dev\/tty/d' \ + -e '/inventory session uuid/d' \ + +} + +_invutil_filter() +{ + _dump_filter \ + | sed \ + -e 's/UUID[ ]*:[ ][0-9a-f-]*/UUID : ID/' \ + -e 's/TIME OF DUMP[ ]*:.*/TIME OF DUMP : TIME/' \ + -e 's/HOSTNAME:SCRATCH_MNT.*/HOSTNAME:SCRATCH_MNT/' \ + -e 's#inventory/[0-9a-f-]*#inventory/UUID#' \ + +} + +_dir_filter() +{ + sed \ + -e "s#$dump_file#DUMP_FILE#" \ + -e "s#$SCRATCH_DEV#SCRATCH_DEV#" \ + -e "s#$dumptape#TAPE_DEV#" \ + -e "s#$dump_dir#DUMP_DIR#g" \ + -e "s#$restore_dir#RESTORE_DIR#g" \ + -e "s#$SCRATCH_MNT#SCRATCH_MNT#g" \ + -e "s#$dump_sdir#DUMP_SUBDIR#g" \ + -e "s#$restore_sdir#RESTORE_SUBDIR#g" \ + +} + +_parse_args() +{ + OPTIND=0 + dump_args="" + while getopts "f:FL:o" c $* + do + case $c + in + f) + [ -z "$OPTARG" ] && _error "missing argument for -f" + dumptape=$OPTARG + ;; + L) + [ -z "$OPTARG" ] && _error "missing argument for -L" + session_label=$OPTARG + ;; + o) + dump_args="$dump_args -o" + ;; + F) + dump_args="$dump_args -F" + ;; + \?) + _error "invalid argument" + ;; + esac + done +} + + +# +# Dump a subdir +# +_do_dump_sub() +{ + _parse_args $* + + echo "Dumping to tape..." + opts="$_dump_debug$dump_args -s $dump_sdir -f $dumptape -M $media_label -L $session_label $SCRATCH_MNT" + echo "xfsdump $opts" | _dir_filter + xfsdump $opts 2>&1 | tee -a $seq.full | _dump_filter +} + +# +# Do full level 0 dump +# +_do_dump() +{ + _parse_args $* + + echo "Dumping to tape..." + opts="$_dump_debug$dump_args -l0 -f $dumptape -M $media_label -L $session_label $SCRATCH_MNT" + echo "xfsdump $opts" | _dir_filter + xfsdump $opts 2>&1 | tee -a $seq.full | _dump_filter +} + + +# +# Do full dump with -m +# +_do_dump_min() +{ + _parse_args $* + + echo "Dumping to tape..." + onemeg=1048576 + opts="$_dump_debug$dump_args -m -b $onemeg -l0 -f $dumptape -M $media_label -L $session_label $SCRATCH_MNT" + echo "xfsdump $opts" | _dir_filter + xfsdump $opts 2>&1 | tee -a $seq.full | _dump_filter +} + +# +# Do level 1 incremental dump +# +_do_dump_incremental() +{ + _parse_args $* + + echo "Dumping incrementally to tape..." + opts="$_dump_debug$dump_args -l1 -f $dumptape -M $media_label -L $session_label $SCRATCH_MNT" + echo "xfsdump $opts" | _dir_filter + xfsdump $opts 2>&1 | tee -a $seq.full | _dump_filter +} + +# +# Do full dump to file +# +_do_dump_file() +{ + _parse_args $* + + echo "Dumping to file..." + opts="$_dump_debug$dump_args -f $dump_file -M $media_label -L $session_label $SCRATCH_MNT" + echo "xfsdump $opts" | _dir_filter + xfsdump $opts 2>&1 | tee -a $seq.full | _dump_filter +} + + +_prepare_restore_dir() +{ + rm -rf $restore_dir + if ! mkdir $restore_dir; then + echo " failed to mkdir $restore_dir" + status=1 + exit + fi +} + + +# +# Get tape ready and restore dir +# +_prepare_restore() +{ + _prepare_restore_dir + + echo "Rewinding tape" + _rewind +} + +# +# Restore the tape into $restore_dir +# +_do_restore() +{ + _parse_args $* + _prepare_restore + + + echo "Restoring from tape..." + opts="$_restore_debug$dump_args -f $dumptape -L $session_label $restore_dir" + echo "xfsrestore $opts" | _dir_filter + xfsrestore $opts 2>&1 | tee -a $seq.full | _dump_filter +} + +# +# Restore the tape into $restore_dir using -m +# +_do_restore_min() +{ + _parse_args $* + _prepare_restore + + echo "Restoring from tape..." + onemeg=1048576 + opts="$_restore_debug$dump_args -m -b $onemeg -f $dumptape -L $session_label $restore_dir" + echo "xfsrestore $opts" | _dir_filter + xfsrestore $opts 2>&1 | tee -a $seq.full | _dump_filter +} + +# +# Restore the tape from a dump file +# +_do_restore_file() +{ + _parse_args $* + _prepare_restore_dir + + echo "Restoring from file..." + opts="$_restore_debug$dumpargs -f $dump_file -L $session_label $restore_dir" + echo "xfsrestore $opts" | _dir_filter + xfsrestore $opts 2>&1 | tee -a $seq.full | _dump_filter +} + +# +# Do xfsdump piped into xfsrestore - xfsdump | xfsrestore +# +# Use -s as we want to dump and restore to the same xfs partition +# +_do_dump_restore() +{ + _parse_args $* + _prepare_restore_dir + echo "xfsdump|xfsrestore ..." + restore_opts="$_restore_debug - $restore_dir" + dump_opts="$_dump_debug$dump_args -s $dump_sdir - $SCRATCH_MNT" + echo "xfsdump $dump_opts | xfsrestore $restore_opts" | _dir_filter + xfsdump $dump_opts 2>$tmp.dump.mlog | xfsrestore $restore_opts 2>&1 | tee -a $seq.full | _dump_filter + _dump_filter <$tmp.dump.mlog +} + +# +# Compare dumped subdirectory with restored dir +# using ls -lR. +# Thus no contents are compared but permissions, sizes, +# owners, etc... are. +# +_ls_compare_sub() +{ + # + # verify we got back what we dumped + # + echo "Comparing listing of dump directory with restore directory" + ls -lR $dump_dir | tee -a $seq.full | _ls_filter >$tmp.dump_dir + ls -lR $restore_dir/$dump_sdir | tee -a $seq.full | _ls_filter \ + | sed -e "s#$restore_sdir\/##" >$tmp.restore_dir + + diff -cs $tmp.dump_dir $tmp.restore_dir | sed -e "s#$tmp#TMP#g" +} + + +# +# Compare using recursive diff the files of the dumped +# subdirectory. +# This one will compare the contents. +# +_diff_compare_sub() +{ + echo "Comparing dump directory with restore directory" + diff -rs $dump_dir $restore_dir/$dump_sdir | _dir_filter +} + +# +# Compare using recursive diff the files of the dumped +# filesystem +# +_diff_compare() +{ + echo "Comparing dump directory with restore directory" + diff -rs $SCRATCH_MNT $restore_dir | _dir_filter +} + +# +# Check out the dump inventory +# +_dump_inventory() +{ + xfsdump $_dump_debug -I | tee -a $seq.full | _dump_filter +} + +# +# Do the xfsinvutil cmd with debug and filters +# Need to set variable: "$middate" to the invutil date +# +_do_invutil() +{ + host=`hostname` + echo "xfsinvutil $_invutil_debug -M $host:$SCRATCH_MNT \"$middate\" $*" >$seq.full + xfsinvutil $_invutil_debug -M $host:$SCRATCH_MNT "$middate" $* \ + | tee -a $seq.full | _invutil_filter +} + +# make sure this script returns success +/bin/true diff -rNu linux-2.4.7/cmd/xfstests/common.filter linux-2.4-xfs/cmd/xfstests/common.filter --- linux-2.4.7/cmd/xfstests/common.filter Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/common.filter Sun Jan 14 23:01:19 2001 @@ -0,0 +1,180 @@ +##/bin/sh + +# +# standard filters +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# + +# Checks that given_value is in range of correct_value +/- tolerance. +# Tolerance can be an absolute value or a percentage of the correct value +# (see examples with tolerances below). +# Outputs suitable message to stdout if it's not in range. +# +# A verbose option, -v, may be used as the LAST argument +# +# e.g. +# foo: 0.0298 = 0.03 +/- 5% +# _within_tolerance "foo" 0.0298 0.03 5% +# +# foo: 0.0298 = 0.03 +/- 0.01 +# _within_tolerance "foo" 0.0298 0.03 0.01 +# +# foo: 0.0298 = 0.03 -0.01 +0.002 +# _within_tolerance "foo" 0.0298 0.03 0.01 0.002 +# +# foo: verbose output of 0.0298 = 0.03 +/- 5% +# _within_tolerance "foo" 0.0298 0.03 5% -v +_within_tolerance() +{ + _name=$1 + _given_val=$2 + _correct_val=$3 + _mintol=$4 + _maxtol=$_mintol + _verbose=0 + _debug=false + + # maxtol arg is optional + # verbose arg is optional + if [ $# -ge 5 ] + then + if [ "$5" = "-v" ] + then + _verbose=1 + else + _maxtol=$5 + fi + fi + if [ $# -ge 6 ] + then + [ "$6" = "-v" ] && _verbose=1 + fi + + # find min with or without % + _mintolerance=`echo $_mintol | sed -e 's/%//'` + if [ $_mintol = $_mintolerance ] + then + _min=`echo "scale=5; $_correct_val-$_mintolerance" | bc` + else + _min=`echo "scale=5; $_correct_val-$_mintolerance*0.01*$_correct_val" | bc` + fi + + # find max with or without % + _maxtolerance=`echo $_maxtol | sed -e 's/%//'` + if [ $_maxtol = $_maxtolerance ] + then + _max=`echo "scale=5; $_correct_val+$_maxtolerance" | bc` + else + _max=`echo "scale=5; $_correct_val+$_maxtolerance*0.01*$_correct_val" | bc` + fi + + $_debug && echo "min = $_min" + $_debug && echo "max = $_max" + + cat <$tmp.bc.1 +scale=5; +if ($_min <= $_given_val) 1; +if ($_min > $_given_val) 0; +EOF + + cat <$tmp.bc.2 +scale=5; +if ($_given_val <= $_max) 1; +if ($_given_val > $_max) 0; +EOF + + _above_min=`bc <$tmp.bc.1` + _below_max=`bc <$tmp.bc.2` + + rm -f $tmp.bc.[12] + + _in_range=`expr $_above_min \& $_below_max` + + # fix up min, max precision for output + # can vary for 5.3, 6.2 + _min=`echo $_min | sed -e 's/0*$//'` # get rid of trailling zeroes + _max=`echo $_max | sed -e 's/0*$//'` # get rid of trailling zeroes + + if [ $_in_range -eq 1 ] + then + [ $_verbose -eq 1 ] && echo $_name is in range + return 0 + else + [ $_verbose -eq 1 ] && echo $_name has value of $_given_val + [ $_verbose -eq 1 ] && echo $_name is NOT in range $_min .. $_max + return 1 + fi +} + +# ctime(3) dates +# +_filter_date() +{ + sed \ + -e 's/[A-Z][a-z][a-z] [A-z][a-z][a-z] *[0-9][0-9]* [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9][0-9][0-9]$/DATE/' +} + +# prints filtered output on stdout, values (use eval) on stderr +# +_filter_mkfs() +{ + set - + perl -ne ' + if (/^meta-data=([\w|\/]+)\s+isize=(\d+)\s+agcount=(\d+), agsize=(\d+) blks/) { + print STDERR "ddev=$1\nisize=$2\nagcount=$3\nagsize=$4\n"; + print STDOUT "meta-data=DDEV isize=XXX agcount=N, agsize=XXX blks\n"; + } + if (/^data\s+=\s+bsize=(\d+)\s+blocks=(\d+), imaxpct=(\d+)/) { + print STDERR "dbsize=$1\ndblocks=$2\nimaxpct=$3\n"; + print STDOUT "data = bsize=XXX blocks=XXX, imaxpct=PCT\n"; + } + if (/^\s+=\s+sunit=(\d+)\s+swidth=(\d+) blks, unwritten=(\d)/) { + print STDERR "sunit=$1\nswidth=$2\nunwritten=$3\n"; + print STDOUT " = sunit=XXX swidth=XXX, unwritten=X\n"; + } + if (/^naming\s+=version\s+(\d+)\s+bsize=(\d+)/) { + print STDERR "dirversion=$1\ndirbsize=$2\n"; + print STDOUT "naming =VERN bsize=XXX\n"; + } + if (/^log\s+=(internal log|[\w|\/]+)\s+bsize=(\d+)\s+blocks=(\d+)/) { + print STDERR "ldev=\"$1\"\nlbsize=$2\nlblocks=$3\n"; + print STDOUT "log =LDEV bsize=XXX blocks=XXX\n"; + } + if (/^realtime\s+=([\w|\/]+)\s+extsz=(\d+)\s+blocks=(\d+), rtextents=(\d+)/) { + print STDERR "rtdev=$1\nrtextsz=$2\nrtblocks=$3\nrtextents=$4\n"; + print STDOUT "realtime =RDEV extsz=XXX blocks=XXX, rtextents=XXX\n"; + }' +} + +# make sure this script returns success +/bin/true diff -rNu linux-2.4.7/cmd/xfstests/common.quota linux-2.4-xfs/cmd/xfstests/common.quota --- linux-2.4.7/cmd/xfstests/common.quota Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/common.quota Wed Jul 4 01:57:38 2001 @@ -0,0 +1,106 @@ +##/bin/sh +# +# Functions useful for quota tests +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +# +# checks that the XFS quota support in the kernel is enabled +# and that we have valid quota user tools installed. +# +_require_quota() +{ + src/feature -q $TEST_DEV + [ $? -ne 0 ] && _notrun "Installed kernel does not support XFS quota" + + [ ! -x /sbin/quotaon ] && _notrun "Quota user tools not installed" + + /sbin/quotaon -x 2>&1 | grep "option requires an argument -- x" >/dev/null + [ $? -ne 0 ] && _notrun "Installed quota tools do not support XFS" +} + +# create a file as a specific user (uid) +# takes filename, id, type (u/g), blocksize, blockcount +# +_file_as_id() +{ + [ $# != 5 ] && _notrun "broken call to _file_as_id in test $seq" + + if [ $3 = u ] + then + magik='$>' # perlspeak for effective uid + elif [ $3 = g ] + then + magik='$)' # perlspeak for effective gid + else + _notrun "broken type in call to _file_as_id in test $seq" + fi + + perl </dev/null 2>&1 + \$| = 1; + $magik = $2; + exec "dd if=/dev/zero of=$1 bs=$4 count=$5"; +EOF +# for debugging the above euid change, try... [need write in cwd] +# exec "dd if=/dev/zero of=$1 bs=$4 count=$5 >>$seq.full 2>&1"; +} + +_choose_uid() +{ + perl -ne '@a = split(/:/); END { printf "id=%d name=%s\n", $a[2],$a[0] }' \ + /etc/passwd +} + +_choose_gid() +{ + perl -ne '@a = split(/:/); END { printf "id=%d name=%s\n", $a[2],$a[0] }' \ + /etc/group +} + +_filter_repquota() +{ + perl -ne " + s/^(\w+)\s+([-|+])/[NAME] \2/g; + s,$SCRATCH_DEV,[DEVICE],g; + print" +} + +_qmount() +{ + umount $SCRATCH_DEV >/dev/null 2>&1 + mount -t xfs $SCRATCH_DEV $SCRATCH_MNT || _fail "qmount failed" + chmod ugo+rwx $SCRATCH_MNT + [ -x /usr/sbin/quot ] && quot $SCRATCH_DEV >>$seq.full 2>&1 +} + +# make sure this script returns success +/bin/true diff -rNu linux-2.4.7/cmd/xfstests/common.rc linux-2.4-xfs/cmd/xfstests/common.rc --- linux-2.4.7/cmd/xfstests/common.rc Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/common.rc Tue May 22 01:07:23 2001 @@ -0,0 +1,612 @@ +##/bin/sh + +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +# we need common.config +if ! . ./common.config +then + echo "$iam: failed to source common.config" + exit 1 +fi + +# make sure we have a standard umask +umask 022 + +# awk +AWK_PROG=awk + +# ps +PS_HAVE_BSD=false +PS_ALL_FLAGS=-efw + +# host os +PLATFORM=linux + +# extra parameters for fsstress +FSSTRESS_AVOID="-f resvsp=0 -f unresvsp=0" + +# env variables for mem checking +#EF_PROTECT_FREE=1 # efence +#export EF_PROTECT_FREE +# Not used because we get weird errors of form: +# ElectricFence Exiting: mmap() failed: Cannot allocate memory + +export AWK_PROG PS_HAVE_BSD PS_ALL_FLAGS PLATFORM + +# we override mount so we can specify mount options + +mount() +{ + case "$*" + in + *remount*) + /bin/mount $* + ;; + *ext2*) + /bin/mount $* + ;; + *xfs*) + /bin/mount $* $MOUNT_OPTIONS + ;; + *) + /bin/mount $* + ;; + esac +} + +# + +_get_pids_by_name() +{ + if [ $# -ne 1 ] + then + echo "Usage: _get_pids_by_name process-name" 1>&2 + exit 1 + fi + + # Algorithm ... all ps(1) variants have a time of the form MM:SS or + # HH:MM:SS before the psargs field, use this as the search anchor. + # + # Matches with $1 (process-name) occur if the first psarg is $1 + # or ends in /$1 ... the matching uses sed's regular expressions, + # so passing a regex into $1 will work. + + ps $PS_ALL_FLAGS \ + | sed -n \ + -e 's/$/ /' \ + -e 's/[ ][ ]*/ /g' \ + -e 's/^ //' \ + -e 's/^[^ ]* //' \ + -e "/[0-9]:[0-9][0-9] *[^ ]*\/$1 /s/ .*//p" \ + -e "/[0-9]:[0-9][0-9] *$1 /s/ .*//p" +} + +# fqdn for localhost +# +_get_fqdn() +{ + host=`hostname` + nslookup $host | $AWK_PROG '{ if ($1 == "Name:") print $2 }' +} + +# fix malloc libs output +# +_fix_malloc() +{ + # filter out the Electric Fence notice + perl -e ' + while (<>) { + if (defined $o && /^\s+Electric Fence/) { + chomp($o); + print "$o"; + undef $o; + next; + } + print $o if (defined $o); + + $o=$_; + } + print $o if (defined $o); + ' +} + +# check if run as root +# +_need_to_be_root() +{ + id=`id | sed -e 's/(.*//' -e 's/.*=//'` + if [ "$id" -ne 0 ] + then + echo "Arrgh ... you need to be root (not uid=$id) to run this test" + exit 1 + fi +} + + +# +# _df_device : get an IRIX style df line for a given device +# +# - returns "" if not mounted +# - returns fs type in field two (ala IRIX) +# - joins line together if split by fancy df formatting +# - strips header etc +# + +_df_device() +{ + if [ $# -ne 1 ] + then + echo "Usage: _df_device device" 1>&2 + exit 1 + fi + + df -T 2>/dev/null | $AWK_PROG -v what=$1 ' + match($1,what) && NF==1 { + v=$1 + getline + print v, $0 + exit + } + match($1,what) { + print + exit + } + ' +} + +# +# _df_dir : get an IRIX style df line for device where a directory resides +# +# - returns fs type in field two (ala IRIX) +# - joins line together if split by fancy df formatting +# - strips header etc +# + +_df_dir() +{ + if [ $# -ne 1 ] + then + echo "Usage: _df_dir device" 1>&2 + exit 1 + fi + + df -T $1 2>/dev/null | $AWK_PROG -v what=$1 ' + NR == 2 && NF==1 { + v=$1 + getline + print v, $0; + exit 0 + } + NR == 2 { + print; + exit 0 + } + {} + ' + # otherwise, nada +} + +# return percentage used disk space for mounted device + +_used() +{ + if [ $# -ne 1 ] + then + echo "Usage: _used device" 1>&2 + exit 1 + fi + + _df_device $1 | $AWK_PROG '{ sub("%", "") ; print $6 }' +} + +# return the FS type of a mounted device +# +_fs_type() +{ + if [ $# -ne 1 ] + then + echo "Usage: _fs_type device" 1>&2 + exit 1 + fi + + _df_device $1 | $AWK_PROG '{ print $2 }' +} + +# return the FS mount options of a mounted device +# +_fs_options() +{ + if [ $# -ne 1 ] + then + echo "Usage: _fs_options device" 1>&2 + exit 1 + fi + + $AWK_PROG -v dev=$1 ' + match($1,dev) { print $4 } + ' &2 + exit 1 + fi + + [ -b $1 ] && src/lstat64 $1 | $AWK_PROG '/Device type:/ { print $9 }' +} + +# Do a command, log it to $seq.full, optionally test return status +# and die if command fails. If called with one argument _do executes the +# command, logs it, and returns its exit status. With two arguments _do +# first prints the message passed in the first argument, and then "done" +# or "fail" depending on the return status of the command passed in the +# second argument. If the command fails and the variable _do_die_on_error +# is set to "always" or the two argument form is used and _do_die_on_error +# is set to "message_only" _do will print an error message to +# $seq.out and exit. + +_do() +{ + if [ $# -eq 1 ]; then + _cmd=$1 + elif [ $# -eq 2 ]; then + _note=$1 + _cmd=$2 + echo -n "$_note... " + else + echo "Usage: _do [note] cmd" 1>&2 + status=1; exit + fi + + (eval "echo '---' \"$_cmd\"") >>$seq.full + (eval "$_cmd") >$tmp._out 2>&1; ret=$? + cat $tmp._out | _fix_malloc >>$seq.full + if [ $# -eq 2 ]; then + if [ $ret -eq 0 ]; then + echo "done" + else + echo "fail" + fi + fi + if [ $ret -ne 0 ] \ + && [ "$_do_die_on_error" = "always" \ + -o \( $# -eq 2 -a "$_do_die_on_error" = "message_only" \) ] + then + [ $# -ne 2 ] && echo + eval "echo \"$_cmd\" failed \(returned $ret\): see $seq.full" + status=1; exit + fi + + return $ret +} + +# bail out, setting up .notrun file +# +_notrun() +{ + echo "$*" >$seq.notrun + echo "$seq not run: $*" + status=0 + exit +} + +# just plain bail out +# +_fail() +{ + echo "$*" | tee -a $seq.full + echo "(see $seq.full for details)" + status=1 + exit 1 +} + +# this test needs a scratch partition - check we're ok & unmount it +# +_require_scratch() +{ + + if [ -z "$SCRATCH_DEV" -o "`_is_block_dev $SCRATCH_DEV`" = "" ] + then + _notrun "this test requires a valid \$SCRATCH_DEV" + fi + + if [ "`_is_block_dev $SCRATCH_DEV`" = "`_is_block_dev $TEST_DEV`" ] + then + _notrun "this test requires a valid \$SCRATCH_DEV" + fi + + # mounted? + if mount | grep -q $SCRATCH_DEV + then + # if it's mounted, make sure its on $SCRATCH_MNT + if ! mount | grep $SCRATCH_DEV | grep -q $SCRATCH_MNT + then + echo "\$SCRATCH_DEV is mounted but not on \$SCRATCH_MNT - aborting" + exit 1 + fi + + # and then unmount it + + if ! umount $SCRATCH_DEV + then + echo "failed to unmount $SCRATCH_DEV" + exit 1 + fi + fi + + # should be ok now + +} + +# this test needs a logdev +# +_require_logdev() +{ + if [ -z "$SCRATCH_LOGDEV" -o ! -b "$SCRATCH_LOGDEV" ] + then + _notrun "This test requires a valid \$SCRATCH_LOGDEV" + fi +} + +# this test requires loopback device support +# +_require_loop() +{ + if grep loop /proc/devices >/dev/null 2>&1 + then + : + else + _notrun "This test requires loopback device support" + fi +} + + +# check that a FS is mounted as XFS. if so, return mount point +# +_xfs_mounted() +{ + if [ $# -ne 1 ] + then + echo "Usage: _xfs_mounted device" 1>&2 + exit 1 + fi + + device=$1 + + if mount | grep $device | $AWK_PROG ' + /type xfs/ { print $3 ; exit 0 } + END { exit 1 } + ' + then + echo "_xfs_mounted: $device is not a mounted XFS FS" + exit 1 + fi +} + + +# setup the .out file link, depending on which form of quota is +# enabled as this often influences how the test output appears. +# [NB: SCRATCH_DEV must be mounted for this to work] +# +_setup_seq_out() +{ + # this lets us phase use of this into the dump/restore tests easier... + [ -f $seq.ugquota -a -f $seq.noquota -a $seq.usrquota -a $seq.grpquota ] \ + || return + + rm -f $seq.out + if src/feature -U $SCRATCH_DEV + then + if src/feature -G $SCRATCH_DEV + then + ln $seq.ugquota $seq.out + else + ln $seq.usrquota $seq.out + fi + elif src/feature -G $SCRATCH_DEV + then + ln $seq.grpquota $seq.out + else + ln $seq.noquota $seq.out + fi +} + + +# remount a FS to a new mode (ro or rw) +# +_remount() +{ + if [ $# -ne 2 ] + then + echo "Usage: _remount device ro/rw" 1>&2 + exit 1 + fi + device=$1 + mode=$2 + + if ! mount -o remount,$mode $device + then + echo "_remount: failed to remount filesystem on $device as $mode" + exit 1 + fi + + # we might like to check here later + #options=`_fs_options $device` + +} + +# run xfs_check on a FS. +# +# if the filesystem is mounted, it's either remounted ro before being +# checked or it's unmounted and then remounted +# + +USE_REMOUNT=0 + +_check_fs() +{ + if [ $# -ne 1 ] + then + echo "Usage: _check_fs device" 1>&2 + exit 1 + fi + + device=$1 + type=`_fs_type $device` + ok=1 + + if [ "$type" = "xfs" ] + then + # mounted... + + if [ $USE_REMOUNT -eq 0 ] + then + mountpoint=`_xfs_mounted $device` + umount $device + else + _remount $device ro + fi + fi + + xfs_logprint -t $device 2>&1 | tee $tmp.fs_check | grep -q "" + if [ $? -ne 0 ] + then + echo "_check_fs: filesystem on $device has dirty log (see $seq.full)" + + echo "_check_fs: filesystem on $device has dirty log" >>$seq.full + echo "*** xfs_logprint -t output ***" >>$seq.full + cat $tmp.fs_check >>$seq.full + echo "*** end xfs_logprint output" >>$seq.full + + ok=0 + fi + + + xfs_check $device 2>&1 | _fix_malloc >$tmp.fs_check + if [ -s $tmp.fs_check ] + then + echo "_check_fs: filesystem on $device is inconsistent (c) (see $seq.full)" + + echo "_check_fs: filesystem on $device is inconsistent" >>$seq.full + echo "*** xfs_check output ***" >>$seq.full + cat $tmp.fs_check >>$seq.full + echo "*** end xfs_check output" >>$seq.full + + ok=0 + fi + + if ! xfs_repair -n $device >$tmp.fs_check 2>&1 + then + echo "_check_fs: filesystem on $device is inconsistent (r) (see $seq.full)" + + echo "_check_fs: filesystem on $device is inconsistent" >>$seq.full + echo "*** xfs_repair -n output ***" >>$seq.full + cat $tmp.fs_check | _fix_malloc >>$seq.full + echo "*** end xfs_repair output" >>$seq.full + + ok=0 + fi + rm -f $tmp.fs_check + + if [ $ok -eq 0 ] + then + echo "*** mount output ***" >>$seq.full + mount >>$seq.full + echo "*** end mount output" >>$seq.full + fi + + if [ "$type" = "xfs" ] + then + # mounted... + if [ $USE_REMOUNT -eq 0 ] + then + if ! mount -t xfs $device $mountpoint + then + echo "!!! failed to remount $device on $mountpoint" + ok=0 + fi + else + _remount $device rw + fi + fi + + [ $ok -eq 0 ] && exit 1 + return 0 +} + +################################################################################ + +[ -d /usr/bsd ] && PATH=$PATH:/usr/bsd +[ -d /usr/freeware/bin ] && PATH=$PATH:/usr/freeware/bin + +if [ "$iam" != new ] +then + + # make some further configuration checks here + + if [ "$TEST_DEV" = "" ] + then + echo "common.rc: Error: \$TEST_DEV is not set" + exit 1 + fi + + if [ "`_fs_type $TEST_DEV`" != "xfs" ] + then + echo "common.rc: Error: \$TEST_DEV ($TEST_DEV) is not a MOUNTED XFS filesystem" + df -T $TEST_DEV + exit 1 + fi + +fi + +# check for some required biunaries on our $PATH +# +for exec in mkfs.xfs xfs_logprint xfs_check xfs_repair xfs_db +do + if which $exec >/dev/null 2>&1 + then + : + else + echo "common.rc: cannot find $exec on \$PATH=$PATH" + exit 1 + fi +done + +# make sure this script returns success +/bin/true diff -rNu linux-2.4.7/cmd/xfstests/common.repair linux-2.4-xfs/cmd/xfstests/common.repair --- linux-2.4.7/cmd/xfstests/common.repair Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/common.repair Sun Jan 14 23:01:19 2001 @@ -0,0 +1,103 @@ +##/bin/sh + +# +# Functions useful for xfs_repair tests +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +_zero_position() +{ + value=$1 + struct="$2" + + # set values for off/len variables provided by db + eval `xfs_db -r -c "$struct" -c stack $SCRATCH_DEV | perl -ne ' + if (/byte offset (\d+), length (\d+)/) { + print "offset=$1\nlength=$2\n"; exit + }'` + if [ -z "$offset" -o -z "$length" ]; then + echo "cannot calculate offset ($offset) or length ($length)" + exit + fi + length=`expr $length / 512` + src/devzero -v $value -b 1 -n $length -o $offset $SCRATCH_DEV +} + +_filter_repair() +{ + perl -ne ' +# for sb +/- agno = / && next; # remove each AG line (variable number) +s/(pointer to) (\d+)/\1 INO/; +s/(sb root inode value) (\d+)/\1 INO/; +s/(realtime bitmap inode) (\d+)/\1 INO/; +s/(realtime summary inode) (\d+)/\1 INO/; +s/(inconsistent with calculated value) (\d+)/\1 INO/; +s/\.+(found)/\1/g; # remove "searching" output +# for agf + agi +s/(bad length -{0,1}\d+ for ag. 0, should be) (\d+)/\1 LENGTH/; +s/(bad length # -{0,1}\d+ for ag. 0, should be) (\d+)/\1 LENGTH/; +s/(bad agbno) (\d+)/\1 AGBNO/g; +s/(max =) (\d+)/\1 MAX/g; +# for root inos +s/(on inode) (\d+)/\1 INO/g; +s/(imap claims a free inode) (\d+)/\1 INO/; +s/(cleared root inode) (\d+)/\1 INO/; +s/(resetting inode) (\d+)/\1 INO/; +s/(disconnected dir inode) (\d+)/\1 INO/; + print;' +} + +_filter_dd() +{ + fgrep -v records # lose records in/out lines +} + +# do some controlled corrupting & ensure repair recovers us +# +_check_repair() +{ + value=$1 + structure="$2" + _zero_position $value "$structure" + xfs_repair $SCRATCH_DEV 2>&1 | _filter_repair + # some basic sanity checks... + _check_fs $SCRATCH_DEV + mount -t xfs $SCRATCH_DEV $SCRATCH_MNT #mount + dd if=/bin/sh of=$SCRATCH_MNT/sh 2>&1 |_filter_dd #open,write + dd if=$SCRATCH_MNT/sh of=/dev/null 2>&1 |_filter_dd #read + rm -f $SCRATCH_MNT/sh #unlink + umount $SCRATCH_MNT #umount +} + +# make sure this script returns success +/bin/true diff -rNu linux-2.4.7/cmd/xfstests/configure.in linux-2.4-xfs/cmd/xfstests/configure.in --- linux-2.4.7/cmd/xfstests/configure.in Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/configure.in Fri Jun 15 09:25:43 2001 @@ -0,0 +1,246 @@ +dnl unpacking check - this file must exist +AC_INIT(src/fsstress.c) +pkg_name="xfstests" +AC_SUBST(pkg_name) + +# +# Note: the following environment variables may be set to override the +# defaults (to change paths and/or executables, build parameters, etc): +# +# DEBUG OPTIMIZER MAKE CC LD TAR ZIP RPM AWK SED ECHO +# MALLOCLIB DISTRIBUTION PACKAGE_BUILDER PREFIX ROOT_PREFIX +# + +DEBUG=${DEBUG:-'-DDEBUG'} # -DNDEBUG +OPTIMIZER=${OPTIMIZER:-'-g'} # (-O1 enforced default) +MALLOCLIB=${MALLOCLIB:-''} # /usr/lib/libefence.a + +dnl Debug build? +debug_build="$DEBUG" +AC_SUBST(debug_build) + +dnl Optimization options? +opt_build="$OPTIMIZER" +AC_SUBST(opt_build) + +dnl Alternate malloc library? +malloc_lib="$MALLOCLIB" +AC_SUBST(malloc_lib) + +dnl Set version +. ./VERSION + +pkg_version=${PKG_MAJOR}.${PKG_MINOR}.${PKG_REVISION} +pkg_release=$PKG_BUILD +AC_SUBST(pkg_version) +AC_SUBST(pkg_release) + +pkg_distribution="SGI ProPack" +test -z "$DISTRIBUTION" || pkg_distribution="$DISTRIBUTION" +AC_SUBST(pkg_distribution) + +pkg_builder=`id -u -n`@`hostname -f` +test -z "$PACKAGE_BUILDER" || pkg_builder="$PACKAGE_BUILDER" +AC_SUBST(pkg_builder) + +dnl check if user wants their own C compiler +test -z "$CC" && AC_PROG_CC +cc=$CC +AC_SUBST(cc) + +dnl check if users wants their own make +test -z "$MAKE" && AC_PATH_PROG(MAKE, make, /usr/bin/make) +make=$MAKE +AC_SUBST(make) + +dnl check if users wants their own linker +test -z "$LD" && AC_PATH_PROG(LD, ld, /usr/bin/ld) +ld=$LD +AC_SUBST(ld) + +dnl check if the tar program is available +test -z "$TAR" && AC_PATH_PROG(TAR, tar) +tar=$TAR +AC_SUBST(tar) + +dnl check if the gzip program is available +test -z "$ZIP" && AC_PATH_PROG(ZIP, gzip, /bin/gzip) +zip=$ZIP +AC_SUBST(zip) + +dnl check if the rpm program is available +test -z "$RPM" && AC_PATH_PROG(RPM, rpm, /bin/rpm) +rpm=$RPM +AC_SUBST(rpm) + +dnl .. and what version is rpm +rpm_version=0 +test -x $RPM && \ + rpm_version=`$RPM --version | awk '{print $NF}' | awk -F. '{print $1}'` +AC_SUBST(rpm_version) + +dnl check if the makedepend program is available +test -z "$MAKEDEPEND" && AC_PATH_PROG(MAKEDEPEND, makedepend, /bin/true) +makedepend=$MAKEDEPEND +AC_SUBST(makedepend) + +dnl check if symbolic links are supported +AC_PROG_LN_S + +dnl check if user wants their own awk, sed and echo +test -z "$AWK" && AC_PATH_PROG(AWK, awk, /bin/awk) +awk=$AWK +AC_SUBST(awk) +test -z "$SED" && AC_PATH_PROG(SED, sed, /bin/sed) +sed=$SED +AC_SUBST(sed) +test -z "$ECHO" && AC_PATH_PROG(ECHO, echo, /bin/echo) +echo=$ECHO +AC_SUBST(echo) + +CPPFLAGS="-I/usr/include/xfs" +AC_SUBST(CPPFLAGS) + +dnl Checks for UUID header and library. +AC_CHECK_HEADER(uuid/uuid.h,, [ + echo + echo 'FATAL ERROR: could not find a valid UUID header.' + echo 'Install either the e2fsprogs-devel (rpm) or the uuid-dev (deb) package.' + exit 1 +]) +AC_CHECK_LIB(uuid, uuid_generate,, [ + echo + echo 'FATAL ERROR: could not find a valid UUID library.' + echo 'Install either the e2fsprogs-devel (rpm) or the uuid-dev (deb) package.' + exit 1 +]) +libuuid="/usr/lib/libuuid.a" +AC_SUBST(libuuid) + +dnl Checks for base XFS headers and libraries. +AC_CHECK_HEADER(xfs/libxfs.h,, [ + echo + echo 'FATAL ERROR: could not find a valid XFS library header.' + echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.' + exit 1 +]) +AC_CHECK_LIB(xfs, libxfs_init,, [ + echo + echo 'FATAL ERROR: could not find a valid XFS base library.' + echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.' + exit 1 +]) +AC_CHECK_HEADER(xfs/handle.h,, [ + echo + echo 'FATAL ERROR: could not find a valid XFS handle header.' + echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.' + exit 1 +]) +AC_CHECK_LIB(handle, path_to_handle,, [ + echo + echo 'FATAL ERROR: could not find a valid XFS handle library.' + echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.' + exit 1 +]) +libxfs="-lxfs" +libhdl="-lhandle" +AC_SUBST(libxfs) +AC_SUBST(libhdl) + +dnl Checks for Extended Attributes header and library. +AC_CHECK_HEADER(attr/attributes.h,, [ + echo + echo 'FATAL ERROR: could not find a valid Extended Attributes header.' + echo 'Install either the attr-devel (rpm) or the attr-dev (deb) package.' + exit 1 +]) +AC_CHECK_LIB(attr, attr_get,, [ + echo + echo 'FATAL ERROR: could not find a valid Extended Attributes library.' + echo 'Install either the attr-devel (rpm) or the attr-dev (deb) package.' + exit 1 +]) +libattr="/usr/lib/libattr.a" +AC_SUBST(libattr) + +dnl Checks for Access Control List header and library. +AC_CHECK_HEADER(sys/acl.h,, [ + echo + echo 'FATAL ERROR: could not find a valid Access Control List header.' + echo 'Install either the acl-devel (rpm) or the acl-dev (deb) package.' + exit 1 +]) +AC_CHECK_LIB(acl, acl_get,, [ + echo + echo 'FATAL ERROR: could not find a valid Access Control List library.' + echo 'Install either the acl-devel (rpm) or the acl-dev (deb) package.' + exit 1 +]) +libacl="/usr/lib/libacl.a" +AC_SUBST(libacl) + +dnl Checks for GNU database manager header and library. +libgdbm="" +have_db=true +AC_CHECK_HEADER(gdbm/ndbm.h,, [ have_db=false ]) +if test $have_db = "true" -a -f /usr/lib/libgdbm.a; then + libgdbm="/usr/lib/libgdbm.a" +fi +AC_SUBST(libgdbm) +AC_SUBST(have_db) + +dnl alternate root and usr prefixes +test -z "$ROOT_PREFIX" && ROOT_PREFIX="" +root_prefix="$ROOT_PREFIX" +test -z "$PREFIX" && PREFIX="/usr" +prefix="$PREFIX" + +dnl man pages (source) +dnl also check if man page source is gzipped +dnl (usually on Debian, but not Redhat pre-7.0) +pkg_man_dir=${prefix}/share/man +have_zipped_manpages=false +for d in ${prefix}/share/man ${prefix}/man ; do + if test -f $d/man1/man.1.gz + then + pkg_man_dir=$d + have_zipped_manpages=true + break + fi +done +AC_SUBST(pkg_man_dir) +AC_SUBST(have_zipped_manpages) + +dnl binaries +pkg_bin_dir=${prefix}/sbin +AC_SUBST(pkg_bin_dir) + +dnl static libraries +pkg_lib_dir=${prefix}/lib +AC_SUBST(pkg_lib_dir) + +dnl runtime shared system libraries +pkg_slib_dir=${root_prefix}/lib +AC_SUBST(pkg_slib_dir) + +dnl system binaries +pkg_sbin_dir=${root_prefix}/sbin +AC_SUBST(pkg_sbin_dir) + +dnl include files +pkg_inc_dir=${prefix}/include +AC_SUBST(pkg_inc_dir) + +dnl doc directory +pkg_doc_dir=${prefix}/share/doc/${pkg_name} +AC_SUBST(pkg_doc_dir) + + +dnl +dnl output files +dnl + +AC_OUTPUT( \ +dnl Build definitions for use in Makefiles + include/builddefs \ +) diff -rNu linux-2.4.7/cmd/xfstests/crash/CVS/Entries linux-2.4-xfs/cmd/xfstests/crash/CVS/Entries --- linux-2.4.7/cmd/xfstests/crash/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/crash/CVS/Entries Thu Jul 5 11:45:48 2001 @@ -0,0 +1,4 @@ +/README/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/rc.sysinit/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/xfscrash/1.1/Mon Jan 15 05:01:19 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/crash/CVS/Repository linux-2.4-xfs/cmd/xfstests/crash/CVS/Repository --- linux-2.4.7/cmd/xfstests/crash/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/crash/CVS/Repository Thu Jul 5 11:45:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/crash diff -rNu linux-2.4.7/cmd/xfstests/crash/CVS/Root linux-2.4-xfs/cmd/xfstests/crash/CVS/Root --- linux-2.4.7/cmd/xfstests/crash/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/crash/CVS/Root Thu Jul 5 11:45:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/crash/README linux-2.4-xfs/cmd/xfstests/crash/README --- linux-2.4.7/cmd/xfstests/crash/README Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/crash/README Sun Jan 14 23:01:19 2001 @@ -0,0 +1,151 @@ +############ +# xfscrash # crash testing setup for XFS +############ + +*** disclaimers *** + + work-in-progress, buyer-beware, your-mileage-may-vary, this-is-a-hack + +*** what xfscrash does *** + + xfscrash allows realistic testing of XFS log recovery and XFS check/repair + by generating log activity on an XFS partition, then rebooting the machine + at a random point. When the machine comes back up, xfscrash is restarted + and then tests either the log recovery or xfs_repair on the dirtied + filesystem. All going well the process continues. + +*** getting ready for crash testing *** + + Most filesystems (ext2 included) can't withstand having the machine + they're running on rebooted while they're active. So the crash test + machine needs to have all filesystems other than the test FS mounted + read-only so they won't get trashed when the machine reboots. + +*** mouting FSes read-only *** + + Following is a recipe for making a redhat linux (6.2) machine with a single + ext2 FS mounted on root able to be booted read-only. Your Mileage May + Vary - don't try this on an important machine. + + The idea is to move anything that needs to be r/w into the /initrd_init + directory, replacing the moved directories with links to the moved ones. + That way the /initrd_init directory may be copied to a ramdisk, and + mounted over /initrd on the root FS which never gets remounted r/w. + + # go to single user + init 1 + + # make a mount point for the ramdisk + mkdir /initrd + + # link across to the /initrd_init directory for when + # the ramdisk isn't mounted + ln -s /initrd_init/dev . + ln -s /initrd_init/etc . + ln -s /initrd_init/proc . + ln -s /initrd_init/sbin . + ln -s /initrd_init/tmp . + ln -s /initrd_init/var . + + # make the /initrd_init directory + mkdir /initrd_init + cd /initrd_init + + + # move /dev + mv /dev . + ln -s /dev /initrd/dev + + # move /etc + mv /etc . + ln -s /etc /initrd/etc + + # make proc mount + mkdir proc + + # move /tmp + mkdir tmp + rm -rf /tmp + ln -s /tmp /initrd/tmp + + # link /sbin + ln -s /sbin . + + # setup a tree for parts of /var + mkdir var var/cache var/lock var/lock/console var/lock/subsys + mkdir var/log var/preserve var/run + + touch /var/run/utmp /var/log/utmp /var/log/wtmp + + # move parts of /var + rm -rf /var/cache /var/lock /var/log /var/preserve /var/run + ln -s /initrd/var/cache /var/cache + ln -s /initrd/var/lock /var/lock + ln -s /initrd/var/log /var/log + ln -s /initrd/var/preserve /var/preserve + ln -s /initrd/var/run /var/run + + # make a mount for /var/shm + mkdir var/shm + ln -s /var/shm /initrd/var/shm + + # move /var/spool + mkdir var/spool + mkdir var/spool/mail var/spool/anacron var/spool/at var/spool/lpd + mkdir var/spool/rwho var/spool/mqueue var/spool/cron + rm -rf /var/spool + ln -s /var/spool /initrd/var/spool + + # move /var/tmp + mkdir var/tmp + rm -rf /var/tmp + ln -s /var/tmp /initrd/var/tmp + + # trim /dev - too many inodes here - remove anything you don't need + # (small ramdisk has a small number of inodes) + rm -rf /initrd/dev/<....> + + All going well, all the directories you've made should link through + /initrd and into /initrd_init, and the machine should come back up + if you restart it. + + You want to keep the contents of /initrd_init to a minimum because + this stuff has to fit into the ramdisk. + +*** getting the ramdisk going *** + + See the rc.sysinit file for some details of what to do to get the + ro-root/ramdisk up and running. + + Once everything is going, the root FS should never be remounted to + r/w on boot and should be in r/o mode when the machine comes up. + + All going well, any open files have been redirected through the + symlinks onto the ramdisk, so you should be able to remount the + root FS to r/w and then remount it back to r/o. + + Since there's no r/w filesystems mounted, it should be ok to + reboot the machine with 'reboot -fn' and everything should come + back without dirty filesystems and without having to fsck. + +*** starting xfscrash *** + + The simplest way to restart xfscrash on reboot is to start it + in the background from rc.local. The script logs to /dev/tty1, + /dev/console & a logfile by default, so the output should be + easy to find. + + Link the xfscrash directory off an NFS mounted FS so you can make + changes while the machine is rebooting and so you can touch the + 'stop' and 'start' control files. + + To configure the system, change the parameters in the configuration + section of the 'xfscrash' script. + + To start the system, touch the 'start' control file and then either + reboot or manually run the 'xfscrash' script. + + To stop the system, touch the 'stop' control file and wait for the + next cycle to start when the control file will be checked and + the test terminated. + diff -rNu linux-2.4.7/cmd/xfstests/crash/rc.sysinit linux-2.4-xfs/cmd/xfstests/crash/rc.sysinit --- linux-2.4.7/cmd/xfstests/crash/rc.sysinit Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/crash/rc.sysinit Sun Jan 14 23:01:19 2001 @@ -0,0 +1,74 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# xfscrash - control the XFS crash tests +# + +# this is an example of what to add to rc.sysinit on a redhat linux +# system to get the ro-root/ramdisk system up and running + +if [ -f /initrd.active ] +then + echo "*** MAKE RAMDISK ***" + dd if=/dev/zero of=/dev/ram0 bs=1024k count=4 + mkfs -i 1024 /dev/ram0 4096 + echo "*** MOUNT RAMDISK ***" + mount -n -w /dev/ram0 /mnt + echo "*** INIT RAMDISK ***" + cp -a /initrd_init/* /mnt + rm -f /mnt/00_INITRD_REAL + touch /mnt/00_INITRD_RAMDISK + umount -n /mnt + echo "*** REMOUNT RAMDISK ***" + mount -n /dev/ram0 /initrd + + echo "*** FIX MTAB ***" + >/etc/mtab + rm -f /etc/mtab~ /etc/mtab~~ + mount -f -o ro / + mount -f -o rw /dev/ram0 /initrd +else + # old code + + # Remount the root filesystem read-write. + action "Remounting root filesystem in read-write mode" mount -n -o remount,rw / + + # Clear mtab + >/etc/mtab + + # Remove stale backups + rm -f /etc/mtab~ /etc/mtab~~ + + # Enter root and /proc into mtab. + mount -f / + mount -f /proc + +fi diff -rNu linux-2.4.7/cmd/xfstests/crash/xfscrash linux-2.4-xfs/cmd/xfstests/crash/xfscrash --- linux-2.4.7/cmd/xfstests/crash/xfscrash Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/crash/xfscrash Sun Jan 14 23:01:19 2001 @@ -0,0 +1,552 @@ +#!/bin/sh +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# xfscrash - control the XFS crash tests +# + + ####################### +### configuration stuff ######################################################## + ####################### + +# remount, repair or corrupt +MODE=remount +# where to find xfscrash +XFSCRASH=/xfscrash +# put log files here +LOG=$XFSCRASH +# put output to these places +OUTPUT="$LOG/xfscrash.log /dev/tty1 /dev/console" +# awk... +AWK_PROG=gawk +# clear FS if >= this percent full at start of run. 100 is a good +# number - only used on corrupt test so far +FULL_LIMIT=80 + +case `hostname -s` +in + leesa) + # mount test partition here + TEST_MNT=/mnt/arch0 + # build test partition here + TEST_DEV=/dev/hda6 + # backup test partition to here (or empty) + BACKUP_DEV=/dev/hda8 + # backup block size for dd + BACKUP_BS=1024k + # base stress time + STRESS_TIME=60 + # stress random time + STRESS_RANDOM=60 + ;; + lumpy) + # mount test partition here + TEST_MNT=/mnt/scratch_0 + # build test partition here + TEST_DEV=/dev/sdc5 + # backup test partition to here (or empty) + BACKUP_DEV= ;#/dev/sdc6 + # backup block size for dd + BACKUP_BS=10240k + # base stress time + STRESS_TIME=360 + # stress random time + STRESS_RANDOM=360 + ;; + *) + echo "!!! no configuration data for host `hostname -s`" + exit 1 + ;; +esac + +# avoid stress + +AVOID="-f resvsp=0 -f unresvsp=0" + +# DIY stress command +STRESS="/usr/local/bin/fsstress -d $TEST_MNT/stress -n 10000000 -p 1 $AVOID" +#STRESS="/usr/local/bin/randholes -l 10000000 -c 100000 -b 512 $TEST_MNT/stress/holes" + +# stress command for the corrupt test +CORRUPT_STRESS="/usr/local/bin/fsstress -d $TEST_MNT/stress -n 10000 -p 1 $AVOID" + +########################################################################### + +reboot=-1 + +_log() +{ + tee -a $OUTPUT > /dev/null +} + +_echo() +{ + echo "$*" | _log +} + +_mount() +{ + _echo " *** Mounting $TEST_DEV on $TEST_MNT" + if ! mount -t xfs $TEST_DEV $TEST_MNT + then + _echo " !!! unable to mount" + exit 1 + fi +} + +_unmount() +{ + _echo " *** Unmounting $TEST_DEV" + if ! umount $TEST_DEV &> /dev/null + then + _echo " !!! unable to unmount" + exit 1 + fi +} + +_check() +{ + expect=$1 + fail=0 + + if [ $expect -eq 0 ] + then + _echo " *** Checking FS (expecting clean fs)" + else + _echo " *** Checking FS (expecting dirty fs)" + fi + + + if [ $expect -eq 0 ] + then + _echo " *** xfs_check ($LOG/check_clean.out)" + xfs_check $TEST_DEV &> $LOG/check_clean.out || fail=1 + [ -s /tmp/xfs_check_clean.out ] && fail=1 + else + _echo " *** xfs_check ($LOG/check_dirty.out)" + xfs_check $TEST_DEV &> $LOG/check_dirty.out || fail=1 + fi + + if [ $fail -eq 0 -a $expect -eq 0 ] + then + _echo " *** xfs_repair -n ($LOG/repair_clean.out)" + xfs_repair -n $TEST_DEV &> $LOG/repair_clean.out || fail=1 + fi + + if [ $fail -eq 0 ] + then + _echo " *** FS checks ok" + else + if [ $expect -eq 0 ] + then + _echo " !!! FS check failed - inconsistent FS" + _echo " !!! (see $LOG/*.out for details)" + exit 1 + else + _echo " *** inconsistent fs (as expected)" + fi + fi +} + +_check_core() +{ + if [ -e core ] + then + _echo " !!! core file found!" + exit 1 + fi +} + +_repair() +{ + rm -f core + _echo " *** repair" + _echo " *** repair pass 1 (RO)" + xfs_repair -n $TEST_DEV &> $LOG/repair_1.out \ + && _echo " !!! no errors found (eh?)" \ + || _echo " *** errors found (expected)" + + _check_core + + _echo " *** repair pass 2 (RW)" + + if xfs_repair $TEST_DEV &> $LOG/repair_2.out + then + _echo " *** FS checks ok (now)" + else + _echo " !!! xfs_repair returned error code" + _echo " !!! (see $LOG/repair_*.out for details)" + exit 1 + fi + + _check_core + + _echo " *** repair pass 3 (RO)" + if xfs_repair -n $TEST_DEV &> $LOG/repair_3.out + then + _echo " *** FS checks ok" + else + _echo " !!! errors found after repair (unexpected)" + _echo " !!! (see $LOG/repair_*.out for details)" + exit 1 + fi + + _check_core +} + +_cleanup() +{ + rm -f $XFSCRASH/counter $XFSCRASH/start $XFSCRASH/stop $XFSCRASH/active + + if [ $reboot != -1 ] + then + kill $reboot + fi + +} + +_random() +{ + od -tu -N 4 /dev/random | gawk -v v=$1 'NR==1 { print $2 % v }' +} + +_backup() +{ + if [ $count -ne 1 -a "$BACKUP_DEV" != "" ] + then + _echo " *** Backing up $TEST_DEV to $BACKUP_DEV" + if ! dd if=$TEST_DEV of=$BACKUP_DEV bs=$BACKUP_BS &> $LOG/dd.out + then + _echo " !!! unable to backup fs" + _echo " !!! (see $LOG/dd.out)" + exit 1 + fi + else + _echo " *** skipping back up step" + fi +} + +_logprint() +{ + _echo " *** dumping log to $LOG/logprint.out" + rm -f core + xfs_logprint $TEST_DEV &> $LOG/logprint.out + if [ -e core ] + then + _echo " !!! xfs_logprint dumped core" + echo "" >> $LOG/logprint.out + echo "*** CORE DUMPED ***" >> $LOG/logprint.out + echo "" >> $LOG/logprint.out + fi + + _echo " *** dumping log (-t -i) to $LOG/logprint_inode.out" + + rm -f core + xfs_logprint -t -i $TEST_DEV &> $LOG/logprint_inode.out + if [ -e core ] + then + _echo " !!! xfs_logprint dumped core" + echo "" >> $LOG/logprint_inode.out + echo "*** CORE DUMPED ***" >> $LOG/logprint_inode.out + echo "" >> $LOG/logprint_inode.out + fi + + _echo " *** dumping log (-t -b) to $LOG/logprint_buf.out" + + rm -f core + xfs_logprint -t -b $TEST_DEV &> $LOG/logprint_buf.out + if [ -e core ] + then + _echo " !!! xfs_logprint dumped core" + echo "" >> $LOG/logprint_buf.out + echo "*** CORE DUMPED ***" >> $LOG/logprint_buf.out + echo "" >> $LOG/logprint_buf.out + fi +} +# +# _df_device : get an IRIX style df line for a given device +# +# - returns "" if not mounted +# - returns fs type in field two (ala IRIX) +# - joins line together if split by fancy df formatting +# - strips header etc +# + +_df_device() +{ + if [ $# -ne 1 ] + then + echo "Usage: _df_device device" >&2 + exit 1 + fi + + df -T 2> /dev/null | $AWK_PROG -v what=$1 ' + match($1,what) && NF==1 { + v=$1 + getline + print v, $0 + exit + } + match($1,what) { + print + exit + } + ' +} + +# +# _df_dir : get an IRIX style df line for device where a directory resides +# +# - returns fs type in field two (ala IRIX) +# - joins line together if split by fancy df formatting +# - strips header etc +# + +_df_dir() +{ + if [ $# -ne 1 ] + then + echo "Usage: _df_dir device" >&2 + exit 1 + fi + + df -T $1 2> /dev/null | $AWK_PROG -v what=$1 ' + NR == 2 && NF==1 { + v=$1 + getline + print v, $0; + exit 0 + } + NR == 2 { + print; + exit 0 + } + {} + ' + # otherwise, nada +} + +# return percentage used disk space for mounted device + +_used() +{ + if [ $# -ne 1 ] + then + echo "Usage: _used device" >&2 + exit 1 + fi + + _df_device $1 | $AWK_PROG '{ sub("%", "") ; print $6 }' +} + +_check_free() +{ + used=`_used $TEST_DEV` + + if [ $used -ge $FULL_LIMIT ] + then + _echo " *** $used % used on $TEST_DEV - deleting files" + rm -rf $TEST_MNT/stress + fi +} + +# loop, stressing, unounting and checking +# no (expected) rebooting... +_corrupt() +{ + count=0 + + # don't want to restart if we reboot... + _cleanup + + while true + do + + if [ -e $XFSCRASH/stop ] + then + _echo "### XFS Crash stopped " + exit 0 + fi + + _echo "*** run $count" + let "count = count + 1" + + _check 0 + _mount + + _check_free + + $CORRUPT_STRESS | _log + + _unmount + done +} + +########################################################################### + +_echo "" +_echo "" +echo "XFSCRASH [output to $OUTPUT]" +_echo "" + +if [ "$1" = "start" ] +then + touch $XFSCRASH/start +fi + +if [ "$1" = "stop" ] +then + touch $XFSCRASH/stop +fi + + +trap "_cleanup; exit \$status" 0 1 2 3 15 + + +if [ -e $XFSCRASH/stop ] +then + _echo "### XFS Crash stopped " + exit 0 +fi + +if [ -e $XFSCRASH/start ] +then + _echo "### XFS Crash started " + _cleanup + rm -f $LOG/*.out $LOG/*.log core + + touch $XFSCRASH/active + + _echo " *** Building fresh XFS FS" + umount $TEST_DEV &> /dev/null + if ! mkfs -t xfs -f $TEST_DEV &> $LOG/mkfs.out + then + _echo " !!! unable to mkfs" + _echo " !!! (see $LOG/mkfs.out)" + exit 1 + fi +fi + +if [ ! -e $XFSCRASH/active ] +then + _echo "### XFS Crash inactive " + exit 0 +fi + + +if [ -r $XFSCRASH/counter ] +then + count=`cat $XFSCRASH/counter` +else + count=0 +fi +_echo "### Crash test run $count (mode=$MODE, log=$LOG/{*.out,*.log})" + +let "count = count +1" +echo $count > $XFSCRASH/counter + +# real test starts here + +_echo " *** Checking for R/O root" +if ! mount | grep "on / type" | grep -q "(ro)" +then + _echo " !!! root not mounted readonly" + exit 1 +fi + +_echo " *** Loading XFS modules" +if ! modprobe xfs +then + _echo " !!! unable to modprobe xfs" + exit 1 +fi + +_echo " *** Unmounting $TEST_DEV" +umount $TEST_DEV &> /dev/null + +_logprint +if [ $MODE != "corrupt" ] +then + _backup +fi + +case $MODE +in + remount) + _check 1 # expect errors + _mount + _unmount + ;; + repair) + _repair + ;; + corrupt) + _corrupt + exit 0 + ;; + *) + _echo "xfscrash: MODE must be remount or repair" + exit 1 + ;; +esac + +_check 0 # don't expect errors +_mount + +_echo " *** Cleaning XFS FS" +if ! rm -rf $TEST_MNT/stress $TEST_MNT/lost+found &> $LOG/clean.out +then + _echo " !!! unable to clean XFS FS" + _echo " !!! (see $LOG/clean.out)" + exit 1 +fi + +_echo " *** Making stress directory" +if ! mkdir $TEST_MNT/stress +then + _echo " !!! unable to mkdir stress" + exit 1 +fi + +let "bang = STRESS_TIME + `_random $STRESS_RANDOM`" + +_echo " *** Preparing random reboot (in $bang seconds)" +( + sleep $bang + _echo " *** BANG ****" + reboot -fn +) & +reboot=$! + +_echo " *** Causing stress & waiting for the inevitable" +$STRESS | _log + +exit 0 diff -rNu linux-2.4.7/cmd/xfstests/dmapi/CVS/Entries linux-2.4-xfs/cmd/xfstests/dmapi/CVS/Entries --- linux-2.4.7/cmd/xfstests/dmapi/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/CVS/Entries Thu Jul 5 11:45:48 2001 @@ -0,0 +1,3 @@ +/Makefile/1.1/Wed Mar 7 22:43:23 2001/-ko/ +/README/1.1/Wed Jan 17 01:24:14 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/dmapi/CVS/Entries.Log linux-2.4-xfs/cmd/xfstests/dmapi/CVS/Entries.Log --- linux-2.4.7/cmd/xfstests/dmapi/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/CVS/Entries.Log Thu Jul 5 11:45:48 2001 @@ -0,0 +1 @@ +A D/src//// diff -rNu linux-2.4.7/cmd/xfstests/dmapi/CVS/Repository linux-2.4-xfs/cmd/xfstests/dmapi/CVS/Repository --- linux-2.4.7/cmd/xfstests/dmapi/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/CVS/Repository Thu Jul 5 11:45:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/dmapi diff -rNu linux-2.4.7/cmd/xfstests/dmapi/CVS/Root linux-2.4-xfs/cmd/xfstests/dmapi/CVS/Root --- linux-2.4.7/cmd/xfstests/dmapi/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/CVS/Root Thu Jul 5 11:45:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/dmapi/Makefile linux-2.4-xfs/cmd/xfstests/dmapi/Makefile --- linux-2.4.7/cmd/xfstests/dmapi/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/Makefile Wed Mar 7 16:43:23 2001 @@ -0,0 +1,51 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +CONFIGURE = $(TOPDIR)/include/builddefs + +SUBDIRS = \ + src/common/lib \ + src/common/cmd \ + src/simple \ + src/sample_hsm \ + src/suite1/cmd \ + src/suite2/src + + +default: + $(SUBDIRS_MAKERULE) + +include $(BUILDRULES) + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/README linux-2.4-xfs/cmd/xfstests/dmapi/README --- linux-2.4.7/cmd/xfstests/dmapi/README Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/README Tue Jan 16 19:24:14 2001 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + + +The tests in this directory are a collection of suites that were developed +over the time the DMAPI spec was being created and when DMAPI was being +implemented on Irix. In many cases, each suite was built on an earlier suite. +Many of these tests have been ported to work with XFS/DMAPI on linux 2.4; many +are untouched from their Irix versions. diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/CVS/Entries linux-2.4-xfs/cmd/xfstests/dmapi/src/CVS/Entries --- linux-2.4.7/cmd/xfstests/dmapi/src/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/CVS/Entries Thu Jul 5 11:45:48 2001 @@ -0,0 +1 @@ +D diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/CVS/Entries.Log linux-2.4-xfs/cmd/xfstests/dmapi/src/CVS/Entries.Log --- linux-2.4.7/cmd/xfstests/dmapi/src/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/CVS/Entries.Log Thu Jul 5 11:45:56 2001 @@ -0,0 +1,5 @@ +A D/common//// +A D/sample_hsm//// +A D/simple//// +A D/suite1//// +A D/suite2//// diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/CVS/Repository linux-2.4-xfs/cmd/xfstests/dmapi/src/CVS/Repository --- linux-2.4.7/cmd/xfstests/dmapi/src/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/CVS/Repository Thu Jul 5 11:45:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/dmapi/src diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/CVS/Root linux-2.4-xfs/cmd/xfstests/dmapi/src/CVS/Root --- linux-2.4.7/cmd/xfstests/dmapi/src/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/CVS/Root Thu Jul 5 11:45:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/CVS/Entries linux-2.4-xfs/cmd/xfstests/dmapi/src/common/CVS/Entries --- linux-2.4.7/cmd/xfstests/dmapi/src/common/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/CVS/Entries Thu Jul 5 11:45:48 2001 @@ -0,0 +1 @@ +D diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/CVS/Entries.Log linux-2.4-xfs/cmd/xfstests/dmapi/src/common/CVS/Entries.Log --- linux-2.4.7/cmd/xfstests/dmapi/src/common/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/CVS/Entries.Log Thu Jul 5 11:45:48 2001 @@ -0,0 +1,2 @@ +A D/cmd//// +A D/lib//// diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/CVS/Repository linux-2.4-xfs/cmd/xfstests/dmapi/src/common/CVS/Repository --- linux-2.4.7/cmd/xfstests/dmapi/src/common/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/CVS/Repository Thu Jul 5 11:45:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/dmapi/src/common diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/CVS/Root linux-2.4-xfs/cmd/xfstests/dmapi/src/common/CVS/Root --- linux-2.4.7/cmd/xfstests/dmapi/src/common/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/CVS/Root Thu Jul 5 11:45:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/CVS/Entries linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/CVS/Entries --- linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/CVS/Entries Thu Jul 5 11:45:48 2001 @@ -0,0 +1,6 @@ +/Makefile/1.1/Wed Mar 7 22:43:23 2001/-ko/ +/read_invis.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/set_region.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/set_return_on_destroy.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/write_invis.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/CVS/Repository linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/CVS/Repository --- linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/CVS/Repository Thu Jul 5 11:45:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/CVS/Root linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/CVS/Root --- linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/CVS/Root Thu Jul 5 11:45:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/Makefile linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/Makefile --- linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/Makefile Wed Mar 7 16:43:23 2001 @@ -0,0 +1,47 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../../../.. +include $(TOPDIR)/include/builddefs + +TARGETS = read_invis set_region set_return_on_destroy write_invis +CFILES = $(TARGETS:=.c) +LDIRT = $(TARGETS) + +default: $(TARGETS) + +include $(BUILDRULES) + +CPPFLAGS = -I $(TOPDIR)/dmapi/src/common -I /usr/include/xfs + +LDLIBS = -ldm -lhandle -ldmtest +LDFLAGS += -L $(TOPDIR)/dmapi/src/common/lib diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/read_invis.c linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/read_invis.c --- linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/read_invis.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/read_invis.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include + +#include +#include +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_read_invis(). The +command line is: + + read_invis [-o offset] [-l length] [-s sid] pathname + +where: +'offset' is the offset of the start of the write (0 is the default), +'length' is the length of the write in bytes (1 is the default), +'sid' is the session ID whose events you you are interested in. +'pathname' is the name of the file to be written. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-o offset] [-l length] " + "[-s sid] pathname\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *pathname = NULL; + dm_off_t offset = 0; + dm_size_t length = 1; + char *bufp = NULL; + void *hanp; + size_t hlen; + dm_ssize_t rc; + char *name; + int opt; + int i; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "o:l:s:")) != EOF) { + switch (opt) { + case 'o': + offset = atol(optarg); + break; + case 'l': + length = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + pathname = argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file's handle. */ + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for file %s\n", pathname); + exit(1); + } + + if (length > 0) { + /* In case it is a realtime file, align the buffer on a + sufficiently big boundary. + */ + if ((bufp = memalign(4096, length)) == NULL) { + fprintf(stderr, "malloc of %llu bytes failed\n", length); + exit(1); + } + memset(bufp, '\0', length); + } + + rc = dm_read_invis(sid, hanp, hlen, DM_NO_TOKEN, offset, length, bufp); + + if (rc < 0) { + fprintf(stderr, "dm_read_invis failed, %s\n", strerror(errno)); + exit(1); + } else if (rc != length) { + fprintf(stderr, "expected to read %lld bytes, actually " + "read %lld\n", length, rc); + exit(1); + } + for (i = 0; i < rc; i++) { + if (isprint(bufp[i])) { + fprintf(stdout, "%c", bufp[i]); + } else { + fprintf(stdout, "\\%03d", bufp[i]); + } + } + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/set_region.c linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/set_region.c --- linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/set_region.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/set_region.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_set_region(). The +command line is: + + set_region [-n nelem] [-o offset] [-l length] [-s sid] pathname [event...] + +where pathname is the name of a file, nelem is the number of regions to pass +in the call, offset is the offset of the start of +the managed region, and length is the length. sid is the session ID whose +events you you are interested in, and event is zero or more managed region +events to set. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + +static struct { + char *name; + int value; +} rg_events[3] = { + { "DM_REGION_READ", DM_REGION_READ }, + { "DM_REGION_WRITE", DM_REGION_WRITE }, + { "DM_REGION_TRUNCATE", DM_REGION_TRUNCATE } +}; +static int nevents = sizeof(rg_events)/sizeof(rg_events[0]); + + +static void +usage(void) +{ + int i; + + fprintf(stderr, "usage:\t%s [-n nelem] [-o offset] [-l length] " + "[-s sid] pathname [event...]\n", Progname); + fprintf(stderr, "possible events are:\n"); + for (i = 0; i < nevents; i++) + fprintf(stderr, "%s (0x%x)\n", rg_events[i].name, rg_events[i].value); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_region_t region = { 0, 0, 0 }; + dm_sessid_t sid = DM_NO_SESSION; + char *pathname = NULL; + u_int exactflag; + u_int nelem = 1; + void *hanp; + size_t hlen; + char *name; + int opt; + int i; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "n:o:l:s:")) != EOF) { + switch (opt) { + case 'n': + nelem = atol(optarg); + break; + case 'o': + region.rg_offset = atol(optarg); + break; + case 'l': + region.rg_size = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 > argc) + usage(); + pathname = argv[optind++]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file's handle. */ + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for file %s\n", pathname); + exit(1); + } + + for (; optind < argc; optind++) { + if (strspn(argv[optind], "0123456789") == strlen(argv[optind])){ + region.rg_flags |= atol(argv[optind]); + continue; + } + for (i = 0; i < nevents; i++) { + if (!strcmp(argv[optind], rg_events[i].name)) + break; + } + if (i == nevents) { + fprintf(stderr, "invalid event %s\n", argv[optind]); + exit(1); + } + region.rg_flags |= rg_events[i].value; + } + + if (dm_set_region(sid, hanp, hlen, DM_NO_TOKEN, nelem, ®ion, + &exactflag)) { + fprintf(stderr, "dm_set_region failed, %s\n", + strerror(errno)); + exit(1); + } + fprintf(stdout, "exactflag is %s\n", + exactflag == DM_TRUE ? "True" : "False"); + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/set_return_on_destroy.c linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/set_return_on_destroy.c --- linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/set_return_on_destroy.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/set_return_on_destroy.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_set_return_on_destroy(). The +command line is: + + set_return_on_destroy [-s sid] pathname [attr] + +where pathname is the name of a file which resides in the filesystem of +interest. attr is the name of the DMAPI attribute; if none is specified, +then set-return-on-destroy will be disabled for the filesystem. +sid is the session ID whose attribute you are interested in setting. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-s sid] pathname [attr]\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *pathname; + dm_attrname_t *attrnamep = NULL; + dm_boolean_t enable = DM_FALSE; + void *hanp; + size_t hlen; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "s:")) != EOF) { + switch (opt) { + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind == argc || optind + 2 < argc) + usage(); + pathname = argv[optind++]; + if (optind < argc) { + enable = DM_TRUE; + attrnamep = (dm_attrname_t *)argv[optind++]; + } + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file's handle. */ + + if (dm_path_to_fshandle(pathname, &hanp, &hlen)) { + fprintf(stderr, "can't get filesystem handle for file %s, %s\n", + pathname, strerror(errno)); + exit(1); + } + + if (dm_set_return_on_destroy(sid, hanp, hlen, DM_NO_TOKEN, + attrnamep, enable)) { + fprintf(stderr, "dm_set_return_on_destroy failed, %s\n", + strerror(errno)); + exit(1); + } + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/write_invis.c linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/write_invis.c --- linux-2.4.7/cmd/xfstests/dmapi/src/common/cmd/write_invis.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/cmd/write_invis.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_write_invis(). The +command line is: + + write_invis [-c char] [-o offset] [-l length] [-s sid] pathname + +where: +'char' is the character to use as a repeated pattern ('X' is the default), +'offset' is the offset of the start of the write (0 is the default), +'length' is the length of the write in bytes (1 is the default), +'sid' is the session ID whose events you you are interested in. +'pathname' is the name of the file to be written. + +DM_WRITE_SYNC is is not supported. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-c char] [-o offset] [-l length] " + "[-s sid] pathname\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *pathname = NULL; + dm_off_t offset = 0; + dm_size_t length = 1; + u_char ch = 'X'; + void *bufp = NULL; + void *hanp; + size_t hlen; + dm_ssize_t rc; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "c:o:l:s:")) != EOF) { + switch (opt) { + case 'c': + ch = *optarg; + break; + case 'o': + offset = atol(optarg); + break; + case 'l': + length = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + pathname = argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file's handle. */ + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for file %s\n", pathname); + exit(1); + } + + if (length > 0) { + /* In case it is a realtime file, align the buffer on a + sufficiently big boundary. + */ + if ((bufp = memalign(4096, length)) == NULL) { + fprintf(stderr, "malloc of %llu bytes failed\n", length); + exit(1); + } + memset(bufp, ch, length); + } + + rc = dm_write_invis(sid, hanp, hlen, DM_NO_TOKEN, 0, offset, length, bufp); + + if (rc < 0) { + fprintf(stderr, "dm_write_invis failed, %s\n", strerror(errno)); + exit(1); + } else if (rc != length) { + fprintf(stderr, "expected to write %lld bytes, actually " + "wrote %lld\n", length, rc); + exit(1); + } + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/CVS/Entries linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/CVS/Entries --- linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/CVS/Entries Thu Jul 5 11:45:51 2001 @@ -0,0 +1,8 @@ +/Makefile/1.1/Wed Mar 7 22:43:23 2001/-ko/ +/dmport.h/1.2/Wed Mar 7 22:43:23 2001/-ko/ +/find_session.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/hsm.h/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/print.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/stubs.c/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/util.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/CVS/Repository linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/CVS/Repository --- linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/CVS/Repository Thu Jul 5 11:45:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/CVS/Root linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/CVS/Root --- linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/CVS/Root Thu Jul 5 11:45:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/Makefile linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/Makefile --- linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/Makefile Wed Mar 7 16:43:23 2001 @@ -0,0 +1,47 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../../../.. +include $(TOPDIR)/include/builddefs + +STATICLIBTARGET = libdmtest.a + +HFILES = hsm.h dmport.h +CFILES = find_session.c print.c stubs.c util.c +LDIRT = $(STATICLIBTARGET) + +default: $(STATICLIBTARGET) + +include $(BUILDRULES) + +CPPFLAGS = -I .. -I /usr/include/xfs + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/dmport.h linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/dmport.h --- linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/dmport.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/dmport.h Wed Mar 7 16:43:23 2001 @@ -0,0 +1,901 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef _DMFSAPI_DMPORT_H +#define _DMFSAPI_DMPORT_H + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************** + * * + * DMF's use of DMAPI is based upon the X/Open document * + * Systems Management: Data Storage Managment (XDSM) API * + * dated February 1997. However, no implementation of DMAPI perfectly * + * matches the spec. Each implementation has some functions that it * + * didn't implement, non-standard functions that it added, differences * + * in function parameter types, return value types, number and order of * + * parameters, etc. There are also differences in the formats of some * + * of the DMAPI structures used by those functions. Finally, there are * + * many scalar values for which DMAPI assigned no particular size. For * + * example, a dm_fsid_t is 32 bits under Veritas and 64 bits under SGI. * + * * + * To hide the differences as much as possible, this include file tries * + * to shoehorn each DMAPI implementation into the XDSM mold as much as * + * possible. Functions which are not compatible with the XDSM spec are * + * redefined using wrapper routines to make them conform to the spec. * + * Functions which were not implemented have stubs defined which return * + * ENOSYS (see file stubs.c for all wrappers and stubs). In dmport.h, * + * missing structures and scalers are defined, incompatible typedefs are * + * redefined, etc. * + * * + * The goal is to reduce as much as possible the number of #ifdefs that * + * have to be added to DMF to handle specific DMAPI implementations. * + * Some #ifdefs may still be required because of semantic differences * + * between the XDSM spec definition and the actual implementation. * + * * + * Following all the implementation-specific definitions, dmport.h * + * includes a complete set of prototypes for all functions that are part * + * of the XDSM specification. This is done as a double-check. Should * + * any of the actual implementations change, the compiler should tip us * + * off by complaining about imcompatible function redefinitions. * + * * + **************************************************************************/ + + +/* ---------------- Veritas-specific hack documentation ----------------- + +The following functions have no prototypes in the Veritas include file +. They do not link either. + +extern int dm_handle_is_valid(void *, size_t); + + +The following functions have prototypes in , but +they do not link. + +extern int dm_getall_disp(dm_sessid_t, size_t, void *, size_t *); +extern int dm_getall_dmattr(dm_sessid_t, void *, size_t, + dm_token_t, size_t, void *, size_t *); + + +The following functions have no prototypes in but do link. + +extern int dm_obj_ref_hold(dm_sessid_t, dm_token_t, void *, size_t); +extern int dm_obj_ref_rele(dm_sessid_t, dm_token_t, void *, size_t); +extern int dm_obj_ref_query(dm_sessid_t, dm_token_t, void *, size_t); + + +The following Veritas prototypes are different in some way from the +spec prototypes, either in parameter types, return value types, or in +some semantic way. Look below to see the spec versions of the prototypes. + +extern int dm_downgrade_right(dm_sessid_t, void *, size_t, + dm_token_t, int, dm_right_t); +extern int dm_get_config_events(void *, size_t, u_int, + dm_eventset_t *, u_int *); +extern int dm_get_events(dm_sessid_t, u_int, int, size_t, void *, size_t *); +extern int dm_get_mountinfo(dm_sessid_t, dm_token_t, void *, size_t, + size_t, void *, size_t *); +extern int dm_init_service(void); +extern int dm_make_handle(dev_t , long, long, void **, size_t *); +extern int dm_make_fshandle(dev_t , void **, size_t *); +extern dev_t dm_handle_to_dev(void *, size_t); +extern long dm_handle_to_fgen(void *, size_t); +extern long dm_handle_to_ino(void *, size_t); +extern int dm_pending(dm_sessid_t, void *, size_t, dm_token_t, int); +extern dm_ssize_t dm_read_invis(dm_sessid_t, void *, size_t, + dm_token_t, dm_off_t, dm_ssize_t, void *); +extern dm_ssize_t dm_write_invis(dm_sessid_t, void *, size_t, + dm_token_t, dm_off_t, dm_ssize_t, void *, int); +extern int dm_request_right(dm_sessid_t, void *, size_t, + dm_token_t, int, dm_right_t); +extern int dm_set_inherit(dm_sessid_t, void *, size_t, + dm_token_t, dm_attrname_t *, u_int); +extern int dm_set_return_ondestroy(dm_sessid_t, void *, size_t, + dm_token_t, dm_attrname_t *, int); +extern int dm_upgrade_right(dm_sessid_t, void *, size_t, + dm_token_t, int, dm_right_t); +extern int dm_set_region(dm_sessid_t, void *, size_t, + dm_token_t, u_int, dm_region_t *, u_int *); +extern dm_ssize_t dm_sync_by_handle(dm_sessid_t, void *, size_t, dm_token_t); + + +The following Veritas prototype exists in but +does not appear in the spec. + +extern void dm_attach_event(dm_sessid_t, dm_token_t); + +The following functions exist in the Veritas library libdmi.a, but have no +prototypes within . Their function is unknown. + +dm_attach_event_nofork +dm_event_query +dm_event_valid +dm_get_disp +dm_set_resident +dmregion_compare +kdm_get_eventinfo +kdm_get_sessioninfo + +-------------- end of Veritas-specific hack documentation --------------- */ + +#ifdef VERITAS_21 + +#include + +#include + +/* Rename functions whose prototypes clash with the XDSM standard. (Library + routines map from XDSM functions back to Veritas functions.) +*/ + +#define dm_downgrade_right xvfs_dm_downgrade_right +#define dm_fd_to_handle xvfs_dm_fd_to_handle +#define dm_get_events xvfs_dm_get_events +#define dm_get_mountinfo xvfs_dm_get_mountinfo +#define dm_handle_to_ino xvfs_dm_handle_to_ino +#define dm_init_service xvfs_dm_init_service +#define dm_make_fshandle xvfs_dm_make_fshandle +#define dm_make_handle xvfs_dm_make_handle +#define dm_path_to_fshandle xvfs_dm_path_to_fshandle +#define dm_path_to_handle xvfs_dm_path_to_handle +#define dm_pending xvfs_dm_pending +#define dm_read_invis xvfs_dm_read_invis +#define dm_write_invis xvfs_dm_write_invis +#define dm_request_right xvfs_dm_request_right +#define dm_set_inherit xvfs_dm_set_inherit +#define dm_set_region xvfs_dm_set_region +#define dm_sync_by_handle xvfs_dm_sync_by_handle +#define dm_upgrade_right xvfs_dm_upgrade_right + + +#define DM_ATTR_NAME_SIZE 8 +#undef DM_ATTRNAME_SIZE +#define DM_VER_STR_CONTENTS "Veritas DMAPI V1.0" + +#define DM_EV_WAIT 0x1 +#define DM_RR_WAIT 0x1 +#undef DM_WAIT +#undef DM_NOWAIT +#undef DM_EVENT_NOWAIT + +#define DM_CONFIG_INHERIT_ATTRIBS (DM_CONFIG_LOCK_UPGRADE + 1) +#undef DM_CONFIG_INHERIT +#define DM_CONFIG_MAX_HANDLE_SIZE (DM_CONFIG_INHERIT_ATTRIBS + 1) +#undef DM_CONFIG_MAX_FILE_HANDLE_SIZE +#define DM_CONFIG_MAX_ATTR_ON_DESTROY (DM_CONFIG_MAX_HANDLE_SIZE + 1) +#undef DM_CONFIG_MAX_ATTR_BYTES_ON_DESTROY +#define DM_CONFIG_OBJ_REF (DM_CONFIG_MAX_ATTR_ON_DESTROY + 1) +#define DM_CONFIG_DTIME_OVERLOAD (DM_CONFIG_OBJ_REF + 1) +#undef DM_CONFIG_MAX + +#define DM_AT_DTIME DM_AT_DTIMES + +/* In the dm_fileattr_t structure, Veritas used 'timeval' structures for all + the time fields while XDSM uses 'time_t' structures. Define some symbols + that can be used for the time fields with all implementation types. +*/ + +#define FA_ATIME fa_atime.tv_sec +#define FA_MTIME fa_atime.tv_sec +#define FA_CTIME fa_ctime.tv_sec +#define FA_DTIME fa_dtime.tv_sec + +#define DM_WRITE_SYNC 0x1 /* used in dm_write_invis() */ + +#define DM_UNMOUNT_FORCE 0x1 /* ne_mode field in dm_namesp_event_t */ + +/* Rename one event to match the XDSM standard. */ + +#define DM_EVENT_CLOSE (DM_EVENT_DESTROY + 1) +#undef DM_EVENT_CLOSED + +/* DM_EVENT_CANCEL is defined above DM_EVENT_MAX, and is unsupported. */ + +#undef DM_REGION_VALIDFLAG + +/* Add missing typedefs */ + +typedef u_int dm_boolean_t; +typedef dev_t dm_fsid_t; /* This could be made a uint64_t with work! */ +typedef long dm_igen_t; +typedef long dm_ino_t; +typedef u_int dm_sequence_t; + + +/* Define missing fields within the various event structures. */ + +#define ev_sequence ev_token /* for compilation only! Won't work! */ + +#define ds_handle te_handle /* fix fields in dm_destroy_event_t */ +#define ds_attrname te_attrname +#define ds_attrcopy te_attrdata + + +struct dm_cancel_event { /* define missing dm_cancel_event_t */ + dm_sequence_t ce_sequence; + dm_token_t ce_token; +}; +typedef struct dm_cancel_event dm_cancel_event_t; + + +struct dm_mount_event { /* define missing dm_mount_event_t */ + mode_t me_mode; + dm_vardata_t me_handle1; + dm_vardata_t me_handle2; + dm_vardata_t me_name1; + dm_vardata_t me_name2; + dm_vardata_t me_roothandle; +}; +typedef struct dm_mount_event dm_mount_event_t; + + +/* Add the missing dm_timestruct_t structure used by dm_pending. */ + +struct dm_timestruct { + time_t dm_tv_sec; + int dm_tv_nsec; +}; +typedef struct dm_timestruct dm_timestruct_t; + +#endif + + + +/* -------------------- SGI-specific hack documentation ------------------- + + There are various fields within DMAPI structures that are not supported. + Fill in this information someday. + + The following functions have prototypes defined in and have + entry points defined in libdm.so, but they are not actually implemented + within the kernel. They all return ENOSYS if called. + + dm_clear_inherit + dm_create_by_handle + dm_get_bulkall + dm_getall_inherit + dm_mkdir_by_handle + dm_set_inherit + dm_symlink_by_handle + + The DMAPI functions which deal with rights do not work as described in + the specification. While the functions exist and are callable, they + always return successfully without actually obtaining any locks within + the filesystem. + + dm_downgrade_right + dm_query_right + dm_release_right + dm_request_right + dm_upgrade_right + + The following non-standard SGI prototype is added to the DMAPI interface + so that real-time files may be migrated and recalled. + + dm_get_dioinfo + +-------------- end of SGI-specific hack documentation --------------- */ + +#ifdef __sgi + +#include + +/* In the dm_fileattr_t structure, Veritas used 'timeval' structures for all + the time fields while XDSM uses 'time_t' structures. Define some symbols + that can be used for the time fields with all implementation types. +*/ + +#define FA_ATIME fa_atime +#define FA_MTIME fa_mtime +#define FA_CTIME fa_ctime +#define FA_DTIME fa_dtime + +#endif /* __sgi */ + +#ifdef linux + +#include + +/* In the dm_fileattr_t structure, Veritas used 'timeval' structures for all + the time fields while XDSM uses 'time_t' structures. Define some symbols + that can be used for the time fields with all implementation types. +*/ + +#define FA_ATIME fa_atime +#define FA_MTIME fa_mtime +#define FA_CTIME fa_ctime +#define FA_DTIME fa_dtime + +#endif /* linux */ + +/* ----------------------- XDSM standard prototypes ----------------------- */ + +/* The following list provides the prototypes for all functions defined in + the DMAPI interface spec from X/Open (XDSM) dated February 1997. They + are here to force compiler errors in case the Veritas or SGI DMAPI + prototypes should ever change without our knowing about it. +*/ + +extern int +dm_clear_inherit( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep); + +extern int +dm_create_by_handle( + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname); + +extern int +dm_create_session( + dm_sessid_t oldsid, + char *sessinfop, + dm_sessid_t *newsidp); + +extern int +dm_create_userevent( + dm_sessid_t sid, + size_t msglen, + void *msgdatap, + dm_token_t *tokenp); + +extern int +dm_destroy_session( + dm_sessid_t sid); + +extern int +dm_downgrade_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern int +dm_fd_to_handle( + int fd, + void **hanpp, + size_t *hlenp); + +extern int +dm_find_eventmsg( + dm_sessid_t sid, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_allocinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t *offp, + u_int nelem, + dm_extent_t *extentp, + u_int *nelemp); + +extern int +dm_get_bulkall( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrname_t *attrnamep, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_bulkattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_config( + void *hanp, + size_t hlen, + dm_config_t flagname, + dm_size_t *retvalp); + +extern int +dm_get_config_events( + void *hanp, + size_t hlen, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp); + +extern int +dm_get_dirattrs( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp); + +extern int +dm_get_events( + dm_sessid_t sid, + u_int maxmsgs, + u_int flags, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_fileattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_stat_t *statp); + +extern int +dm_get_mountinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_region( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_region_t *regbufp, + u_int *nelemp); + +extern int +dm_getall_disp( + dm_sessid_t sid, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_getall_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_getall_inherit( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_inherit_t *inheritbufp, + u_int *nelemp); + +extern int +dm_getall_sessions( + u_int nelem, + dm_sessid_t *sidbufp, + u_int *nelemp); + +extern int +dm_getall_tokens( + dm_sessid_t sid, + u_int nelem, + dm_token_t *tokenbufp, + u_int *nelemp); + +extern int +dm_handle_cmp( + void *hanp1, + size_t hlen1, + void *hanp2, + size_t hlen2); + +extern void +dm_handle_free( + void *hanp, + size_t hlen); + +extern u_int +dm_handle_hash( + void *hanp, + size_t hlen); + +extern dm_boolean_t +dm_handle_is_valid( + void *hanp, + size_t hlen); + +extern int +dm_handle_to_fshandle( + void *hanp, + size_t hlen, + void **fshanpp, + size_t *fshlenp); + +extern int +dm_handle_to_fsid( + void *hanp, + size_t hlen, + dm_fsid_t *fsidp); + +extern int +dm_handle_to_igen( + void *hanp, + size_t hlen, + dm_igen_t *igenp); + +extern int +dm_handle_to_ino( + void *hanp, + size_t hlen, + dm_ino_t *inop); + +extern int +dm_handle_to_path( + void *dirhanp, + size_t dirhlen, + void *targhanp, + size_t targhlen, + size_t buflen, + char *pathbufp, + size_t *rlenp); + +extern int +dm_init_attrloc( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrloc_t *locp); + +extern int +dm_init_service( + char **versionstrpp); + +extern int +dm_make_fshandle( + dm_fsid_t *fsidp, + void **hanpp, + size_t *hlenp); + +extern int +dm_make_handle( + dm_fsid_t *fsidp, + dm_ino_t *inop, + dm_igen_t *igenp, + void **hanpp, + size_t *hlenp); + +extern int +dm_mkdir_by_handle( + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname); + +extern int +dm_move_event( + dm_sessid_t srcsid, + dm_token_t token, + dm_sessid_t targetsid, + dm_token_t *rtokenp); + +extern int +dm_obj_ref_hold( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +extern int +dm_obj_ref_query( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +extern int +dm_obj_ref_rele( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +extern int +dm_path_to_fshandle( + char *path, + void **hanpp, + size_t *hlenp); + +extern int +dm_path_to_handle( + char *path, + void **hanpp, + size_t *hlenp); + +extern int +dm_pending( + dm_sessid_t sid, + dm_token_t token, + dm_timestruct_t *delay); + +extern int +dm_probe_hole( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + dm_off_t *roffp, + dm_size_t *rlenp); + +extern int +dm_punch_hole( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len); + +extern int +dm_query_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_right_t *rightp); + +extern int +dm_query_session( + dm_sessid_t sid, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern dm_ssize_t +dm_read_invis( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + void *bufp); + +extern int +dm_release_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern int +dm_remove_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int setdtime, + dm_attrname_t *attrnamep); + +extern int +dm_request_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int flags, + dm_right_t right); + +extern int +dm_respond_event( + dm_sessid_t sid, + dm_token_t token, + dm_response_t response, + int reterror, + size_t buflen, + void *respbufp); + +extern int +dm_send_msg( + dm_sessid_t targetsid, + dm_msgtype_t msgtype, + size_t buflen, + void *bufp); + +extern int +dm_set_disp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + u_int maxevent); + +extern int +dm_set_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + int setdtime, + size_t buflen, + void *bufp); + +extern int +dm_set_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + u_int maxevent); + +extern int +dm_set_fileattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_fileattr_t *attrp); + +extern int +dm_set_inherit( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + mode_t mode); + +extern int +dm_set_region( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_region_t *regbufp, + dm_boolean_t *exactflagp); + +extern int +dm_set_return_on_destroy( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + dm_boolean_t enable); + +extern int +dm_symlink_by_handle( + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname, + char *path); + +extern int +dm_sync_by_handle( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern int +dm_upgrade_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern dm_ssize_t +dm_write_invis( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int flags, + dm_off_t off, + dm_size_t len, + void *bufp); + + +#ifdef __cplusplus +} +#endif + +#endif /* _DMFSAPI_DMPORT_H */ diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/find_session.c linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/find_session.c --- linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/find_session.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/find_session.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include + +/******************************************************************************* +* +* NAME +* find_test_session - find or create a test DMAPI session. +* +* DESCRIPTION +* find_test_session() is used to find a test DMAPI session to +* use. There is only one test session per host; all test processes +* share the same session. If the session does not already exist, +* then the first process to call find_test_session() causes +* the session to be created. +* +* Note: It is possible for N different programs to call this routine +* at the same time. Each would find that a test session does not +* exist, and each one would then create a new test session. Since +* excess test sessions are not automatically released on death of +* process, we need to make sure that we don't leave such excess +* sessions around. So, after creating a session we go back and find +* the test session with the lowest session number. If it is ours, +* great; we are done. If not, then we must destroy our session +* and use the one with the lower session ID. There is still a risk +* here of creating a session and crashing before it can be removed +* again. To deal with this, the daemon will periodically remove all +* test sessions except for the one with the lowest ID value. +* +* RETURN VALUE +* None. +* +*******************************************************************************/ + +#define TEST_MSG "DMAPI test session" + +static int +session_compare( +const void *a, +const void *b) +{ + return(*((dm_sessid_t *)a) - *((dm_sessid_t *)b)); +} + +extern void +find_test_session( + dm_sessid_t *session) +{ + char buffer[DM_SESSION_INFO_LEN]; + dm_sessid_t *sidbuf = NULL; + dm_sessid_t new_session; + u_int allocelem = 0; + u_int nelem; + size_t rlen; + int error; + u_int i; + + /* Retrieve the list of all active sessions on the host. */ + + nelem = 100; /* a reasonable first guess */ + do { + if (allocelem < nelem) { + allocelem = nelem; + sidbuf = realloc(sidbuf, nelem * sizeof(*sidbuf)); + if (sidbuf == NULL) { + fprintf(stderr, "realloc of %d bytes failed\n", + nelem * sizeof(*sidbuf)); + exit(1); + } + } + error = dm_getall_sessions(allocelem, sidbuf, &nelem); + } while (error < 0 && errno == E2BIG); + + /* If an error occurred, translate it into something meaningful. */ + + if (error < 0) { + fprintf(stderr, "unexpected dm_getall_sessions failure, %s\n", + strerror(errno)); + free(sidbuf); + exit(1); + } + + /* We have the list of all active sessions. Scan the list looking + for an existing "test" session that we can use. The list must + first be sorted in case other processes happen to be creating test + sessions at the same time; we need to make sure that we pick the one + with the lowest session ID. + */ + + qsort(sidbuf, nelem, sizeof(sidbuf[0]), session_compare); + + for (i = 0; i < nelem; i++) { + error = dm_query_session(sidbuf[i], sizeof(buffer), + buffer, &rlen); + if (error < 0) { + fprintf(stderr, "unexpected dm_query_session " + "failure, %s\n", strerror(errno)); + free(sidbuf); + exit(1); + } + + if (!strncmp(buffer, TEST_MSG, strlen(TEST_MSG))) + break; + } + if (i < nelem) { + *session = (dm_sessid_t)sidbuf[i]; + free(sidbuf); + return; + } + + /* No test session exists, so we have to create one ourselves. */ + + if (dm_create_session(DM_NO_SESSION, TEST_MSG, &new_session) != 0) { + fprintf(stderr, "dm_create_session failed, %s\n", + strerror(errno)); + free(sidbuf); + exit(1); + } + + /* Now re-retrieve the list of active sessions. */ + + do { + if (allocelem < nelem) { + allocelem = nelem; + sidbuf = realloc(sidbuf, nelem * sizeof(*sidbuf)); + if (sidbuf == NULL) { + fprintf(stderr, "realloc of %d bytes failed\n", + nelem * sizeof(*sidbuf)); + exit(1); + } + } + error = dm_getall_sessions(allocelem, sidbuf, &nelem); + } while (error < 0 && errno == E2BIG); + + if (error < 0) { + fprintf(stderr, "dm_getall_sessions failed, %s\n", + strerror(errno)); + free(sidbuf); + exit(1); + } + + /* Sort the session ID list into ascending ID order, then find the + test session with the lowest session ID. We better find at + least one since we created one! + */ + + qsort(sidbuf, nelem, sizeof(sidbuf[0]), session_compare); + + for (i = 0; i < nelem; i++) { + error = dm_query_session(sidbuf[i], sizeof(buffer), + buffer, &rlen); + if (error < 0) { + fprintf(stderr, "dm_query_session failed, %s\n", + strerror(errno)); + free(sidbuf); + exit(1); + } + if (!strncmp(buffer, TEST_MSG, strlen(TEST_MSG))) + break; + } + if (i == nelem) { + fprintf(stderr, "can't find the session we created\n"); + free(sidbuf); + exit(1); + } + *session = (dm_sessid_t)sidbuf[i]; + free(sidbuf); + + /* If the session we are going to use is not the one we created, + then we need to get rid of the created one. + */ + + if (*session != new_session) { + if ((new_session) != 0) { + fprintf(stderr, "dm_destroy_session failed, %s\n", + strerror(errno)); + exit(1); + } + } +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/hsm.h linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/hsm.h --- linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/hsm.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/hsm.h Tue Jan 16 19:24:14 2001 @@ -0,0 +1,166 @@ +/* + * Defines and structures for our pseudo HSM example + * + * This code was written by Peter Lawthers, and placed in the public + * domain for use by DMAPI implementors and app writers. + * + * Standard disclaimer: + * THIS SOFTWARE IS PROVIDED ``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. + */ + +#ifndef _LIB_HSM_H +#define _LIB_HSM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include +#include +#include +#include + +#include + +#define HANDLE_LEN 64 /* Swag for this example */ +#define HANDLE_STR ((HANDLE_LEN * 2) + 1) /* handle as ascii, plus null */ +#define IBUFSIZE 1024 /* input buffer size */ +#define CHUNKSIZE (1024*1024*4) /* write size */ +#define FENCEPOST_SIZE ((dm_size_t)(1024*8)) +#define ALL_AVAIL_MSGS 0 + +/* + * Actions to be performed by the worker bees + */ +#define RESTORE_FILE "-r" +#define INVAL_FILE "-i" + +#define WORKER_BEE "wbee" + + +/* + * Names of DM attribute used for storing location of a file's data. + * DM attributes are 8 bytes, including NULL. + */ + +#define DLOC_HAN "dhanloc" /* staging file handle */ +#define DLOC_HANLEN "dhanlen" /* staging handle length */ + +/* + * Default log file + */ +#define LOG_DEFAULT "/tmp/dmig_log" + +struct ev_name_to_value { + char *name; /* name of event */ + dm_eventtype_t value; /* value of event */ +}; + +extern struct ev_name_to_value ev_names[]; +extern int ev_namecnt; + + +struct rt_name_to_value { + char *name; /* name of right */ + dm_right_t value; /* value of right */ +}; + +extern struct rt_name_to_value rt_names[]; +extern int rt_namecnt; + + +extern void hantoa(void *hanp, size_t hlen, char *handle_str); +extern int atohan(char *handle_str, void **hanpp, size_t *hlenp); +extern void print_handle(void *hanp, size_t hlen); +extern void print_victim(void *hanp, size_t hlen, dm_off_t fsize); +extern void errno_msg(char *fmt, ...); +extern void err_msg(char *fmt, ...); +extern int setup_dmapi(dm_sessid_t *sid); +extern int get_dmchange(dm_sessid_t sid, void *hanp, size_t hlen, + dm_token_t token, u_int *change_start); +extern int save_filedata(dm_sessid_t sid, void *hanp, size_t hlen, + int stg_fd, dm_size_t fsize); +extern int restore_filedata(dm_sessid_t sid, void *hanp, size_t hlen, + dm_token_t token, void *stg_hanp, size_t stg_hlen, dm_off_t off); + +extern void find_test_session(dm_sessid_t *session); + +void +print_one_mount_event( + void *msg); + +int +print_one_message( + dm_eventmsg_t *msg); + +int +handle_message( + dm_sessid_t sid, + dm_eventmsg_t *msg); + +extern char *date_to_string( + time_t timeval); + +extern char *mode_to_string( + mode_t mode); + +extern mode_t field_to_mode( + mode_t mode); + +extern int validate_state( + dm_stat_t *dmstat, + char *pathname, + int report_errors); + +extern char *emask_to_string( + dm_eventset_t emask); + +extern char *xflags_to_string( + u_int xflags); + +extern void print_state( + dm_stat_t *dmstat); + +extern void print_line( + dm_stat_t *dmstat); + +extern dm_eventtype_t +ev_name_to_value( + char *name); + +extern char * +ev_value_to_name( + dm_eventtype_t event); + +extern int +rt_name_to_value( + char *name, + dm_right_t *rightp); + +extern char * +rt_value_to_name( + dm_right_t right); + +extern int +opaque_to_handle( + char *name, + void **hanpp, + size_t *hlenp); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIB_HSM_H */ diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/print.c linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/print.c --- linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/print.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/print.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,618 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include + +#include + +#include + +#include +#ifdef linux +#define MAXNAMELEN 256 +#endif + + /* + * Define some standard formats for the printf statements below. + */ + +#define HDR "%s: token=%d sequence=%d\n" +#define VALS "\t%-15s %s\n" +#define VALD "\t%-15s %d\n" +#define VALLLD "\t%-15s %lld\n" + + +/* + Convert a mode_t field into a printable string. + + Returns non-zero if the mode_t is invalid. The string is + returned in *ptr, whether there is an error or not. +*/ + +int +format_mode( + mode_t mode, + char **ptr) +{ +static char modestr[100]; + char *typestr; + int error = 0; + + if (S_ISFIFO(mode)) typestr = "FIFO"; + else if(S_ISCHR (mode)) typestr = "Character Device"; + else if(S_ISBLK (mode)) typestr = "Block Device"; + else if(S_ISDIR (mode)) typestr = "Directory"; + else if(S_ISREG (mode)) typestr = "Regular File"; + else if(S_ISLNK (mode)) typestr = "Symbolic Link"; + else if(S_ISSOCK(mode)) typestr = "Socket"; + else { + typestr = ""; + error++; + } + + sprintf(modestr, "mode %06o: perm %c%c%c %c%c%c %c%c%c %c%c%c, type %s", + mode, + mode & S_ISUID ? 's':' ', + mode & S_ISGID ? 'g':' ', + mode & S_ISVTX ? 't':' ', + mode & S_IRUSR ? 'r':'-', + mode & S_IWUSR ? 'w':'-', + mode & S_IXUSR ? 'x':'-', + mode & S_IRGRP ? 'r':'-', + mode & S_IWGRP ? 'w':'-', + mode & S_IXGRP ? 'x':'-', + mode & S_IROTH ? 'r':'-', + mode & S_IWOTH ? 'w':'-', + mode & S_IXOTH ? 'x':'-', + typestr); + *ptr = modestr; + return(error); +} + + +void +print_one_mount_event( + void *msg) +{ + void *hanp1, *hanp2, *hanp3; + size_t hlen1, hlen2, hlen3; + char hans1[HANDLE_STR], hans2[HANDLE_STR], hans3[HANDLE_STR]; + void *namp1, *namp2; + size_t nlen1, nlen2; + char nams1[MAXNAMELEN], nams2[MAXNAMELEN]; + mode_t mode; + +#if VERITAS_21 + dm_namesp_event_t *msg_ne = (dm_namesp_event_t *)msg; + +/* + msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *); +*/ + hanp1 = DM_GET_VALUE(msg_ne, ne_handle1, void *); + hlen1 = DM_GET_LEN (msg_ne, ne_handle1); + hanp2 = DM_GET_VALUE(msg_ne, ne_handle2, void *); + hlen2 = DM_GET_LEN (msg_ne, ne_handle2); + namp1 = DM_GET_VALUE(msg_ne, ne_name1, void *); + nlen1 = DM_GET_LEN (msg_ne, ne_name1); + namp2 = DM_GET_VALUE(msg_ne, ne_name2, void *); + nlen2 = DM_GET_LEN (msg_ne, ne_name2); + hanp3 = NULL; + hlen3 = 0; + mode = msg_ne->ne_mode; +#else + dm_mount_event_t *msg_me = (dm_mount_event_t *)msg; + + hanp1 = DM_GET_VALUE(msg_me, me_handle1, void *); + hlen1 = DM_GET_LEN(msg_me, me_handle1); + hanp2 = DM_GET_VALUE(msg_me, me_handle2, void *); + hlen2 = DM_GET_LEN(msg_me, me_handle2); + namp1 = DM_GET_VALUE(msg_me, me_name1, void *); + nlen1 = DM_GET_LEN(msg_me, me_name1); + namp2 = DM_GET_VALUE(msg_me, me_name2, void *); + nlen2 = DM_GET_LEN(msg_me, me_name2); + hanp3 = DM_GET_VALUE(msg_me, me_roothandle, void *); + hlen3 = DM_GET_LEN(msg_me, me_roothandle); + mode = msg_me->me_mode; +#endif /* VERITAS_21 */ + + if (hanp1 && hlen1) { + hantoa(hanp1, hlen1, hans1); + } else { + sprintf(hans1, "", hlen1); + } + if (hanp2 && hlen2) { + hantoa(hanp2, hlen2, hans2); + } else { + sprintf(hans2, "", hlen2); + } + if (hanp3 && hlen3) { + hantoa(hanp3, hlen3, hans3); + } else { + sprintf(hans3, "", hlen3); + } + if (namp1 && nlen1) { + strncpy(nams1, namp1, nlen1); + if (nlen1 != sizeof(nams1)) + nams1[nlen1] = '\0'; + } else { + sprintf(nams1, "", nlen1); + } + if (namp2 && nlen2) { + strncpy(nams2, namp2, nlen2); + if (nlen2 != sizeof(nams2)) + nams2[nlen2] = '\0'; + } else { + sprintf(nams2, "", nlen2); + } + + printf(VALS VALS VALS VALS VALS VALD, + "fs handle", hans1, + "mtpt handle", hans2, + "mtpt path", nams1, + "media desig", nams2, + "root handle", hans3, + "mode", mode); +} + + +static int +print_one_data_event( + dm_data_event_t *msg_de) +{ + char handle[HANDLE_STR]; + void *hanp; + size_t hlen; + + hanp = DM_GET_VALUE(msg_de, de_handle, void *); + hlen = DM_GET_LEN (msg_de, de_handle); + + if (hanp && hlen) { + hantoa(hanp, hlen, handle); + } else { + sprintf(handle, "", hlen); + } + + printf(VALS VALLLD VALLLD, + "file handle", handle, + "offset", msg_de->de_offset, + "length", msg_de->de_length); + + return(0); +} + + +int +print_one_message( + dm_eventmsg_t *msg) +{ + int pkt_error = 0; + dm_namesp_event_t *msg_ne; + void *hanp1, *hanp2, *namp1, *namp2; + u_int hlen1, hlen2, nlen1, nlen2; + char hans1[HANDLE_STR], hans2[HANDLE_STR]; + char nams1[MAXNAMELEN], nams2[MAXNAMELEN]; + + /***** USER EVENTS *****/ + + if (msg->ev_type == DM_EVENT_USER) { + char *privp; + u_int plen, i; + + printf(HDR, + "user", msg->ev_token, msg->ev_sequence); + + /* print private data as ascii or hex if it exists DM_CONFIG_MAX_MESSAGE_DATA */ + + privp = DM_GET_VALUE(msg, ev_data, char *); + plen = DM_GET_LEN (msg, ev_data); + if (plen) { + for (i = 0; i < plen; i++) { + if (!isprint(privp[i]) && !isspace(privp[i])) + break; + } + if (i == plen - 1 && privp[i] == '\0') { + printf(VALS, + "privdata", privp); + } else { + printf("\t%-15s ", "privdata"); + for (i = 0; i < plen; i++) { + printf("%.2x", privp[i]); + } + printf("\n"); + } + } else { + printf(VALS, + "privdata", ""); + } + + /***** CANCEL EVENT *****/ + +/* Not implemented on SGI or Veritas */ + + } else if (msg->ev_type == DM_EVENT_CANCEL) { + dm_cancel_event_t *msg_ce; + + msg_ce = DM_GET_VALUE(msg, ev_data, dm_cancel_event_t *); + printf(HDR VALD VALD, + "cancel", msg->ev_token, msg->ev_sequence, + "sequence", msg_ce->ce_sequence, + "token", msg_ce->ce_token); + + /***** DATA EVENTS *****/ + + } else if (msg->ev_type == DM_EVENT_READ || + msg->ev_type == DM_EVENT_WRITE || + msg->ev_type == DM_EVENT_TRUNCATE) { + dm_data_event_t *msg_de; + + msg_de = DM_GET_VALUE(msg, ev_data, dm_data_event_t *); + + switch (msg->ev_type) { + case DM_EVENT_READ: + printf(HDR, "read", msg->ev_token, msg->ev_sequence); + break; + + case DM_EVENT_WRITE: + printf(HDR, "write", msg->ev_token, msg->ev_sequence); + break; + + case DM_EVENT_TRUNCATE: + printf(HDR, "truncate", msg->ev_token, + msg->ev_sequence); + break; + default: break; + } + print_one_data_event(msg_de); + + /***** DESTROY EVENT *****/ + + } else if (msg->ev_type == DM_EVENT_DESTROY) { + dm_destroy_event_t *msg_ds; + char attrname[DM_ATTR_NAME_SIZE + 1]; + u_char *copy; + u_int clen; + u_int i; + + msg_ds= DM_GET_VALUE(msg, ev_data, dm_destroy_event_t *); + hanp1 = DM_GET_VALUE(msg_ds, ds_handle, void *); + hlen1 = DM_GET_LEN (msg_ds, ds_handle); + if (hanp1 && hlen1) { + hantoa(hanp1, hlen1, hans1); + } else { + sprintf(hans1, "", hlen1); + } + if (msg_ds->ds_attrname.an_chars[0] != '\0') { + strncpy(attrname, (char *)msg_ds->ds_attrname.an_chars, sizeof(attrname)); + } else { + strcpy(attrname, ""); + } + printf(HDR VALS VALS, + "destroy", msg->ev_token, msg->ev_sequence, + "handle", hans1, + "attrname", attrname); + copy = DM_GET_VALUE(msg_ds, ds_attrcopy, u_char *); + clen = DM_GET_LEN (msg_ds, ds_attrcopy); + if (copy && clen) { + printf("\t%-15s ", "attrcopy"); + for (i = 0; i < clen; i++) { + printf("%.2x", copy[i]); + } + printf("\n"); + } else { + printf(VALS, "attrcopy", ""); + } + + /***** MOUNT EVENT *****/ + + } else if (msg->ev_type == DM_EVENT_MOUNT) { + void *msg_body; + + printf(HDR, "mount", msg->ev_token, msg->ev_sequence); +#if !VERITAS_21 + msg_body = DM_GET_VALUE(msg, ev_data, dm_mount_event_t *); +#else /* VERITAS_21 */ + msg_body = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *); +#endif /* VERITAS_21 */ + print_one_mount_event(msg_body); + + /***** NAMESPACE EVENTS *****/ + + } else { + char *type; + + msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *); + hanp1 = DM_GET_VALUE(msg_ne, ne_handle1, void *); + hlen1 = DM_GET_LEN (msg_ne, ne_handle1); + hanp2 = DM_GET_VALUE(msg_ne, ne_handle2, void *); + hlen2 = DM_GET_LEN (msg_ne, ne_handle2); + namp1 = DM_GET_VALUE(msg_ne, ne_name1, void *); + nlen1 = DM_GET_LEN (msg_ne, ne_name1); + namp2 = DM_GET_VALUE(msg_ne, ne_name2, void *); + nlen2 = DM_GET_LEN (msg_ne, ne_name2); + + if (hanp1 && hlen1) { + hantoa(hanp1, hlen1, hans1); + } + if (hanp2 && hlen2) { + hantoa(hanp2, hlen2, hans2); + } + if (namp1 && nlen1) { + strncpy(nams1, namp1, nlen1); + if (nlen1 != sizeof(nams1)) + nams1[nlen1] = '\0'; + } + if (namp2 && nlen2) { + strncpy(nams2, namp2, nlen2); + if (nlen2 != sizeof(nams2)) + nams2[nlen2] = '\0'; + } + + if (msg->ev_type == DM_EVENT_PREUNMOUNT || + msg->ev_type == DM_EVENT_UNMOUNT) { + if (msg_ne->ne_mode == 0) { + type = "NOFORCE"; +#if !VERITAS_21 + } else if (msg_ne->ne_mode == DM_UNMOUNT_FORCE) { +#else + } else if (msg_ne->ne_mode > 0) { +#endif + type = "FORCE"; + } else { + type = "UNKNOWN"; + pkt_error++; + } + } else if (msg->ev_type == DM_EVENT_CREATE || + msg->ev_type == DM_EVENT_POSTCREATE || + msg->ev_type == DM_EVENT_REMOVE || + msg->ev_type == DM_EVENT_POSTREMOVE) { + if (format_mode(msg_ne->ne_mode, &type)) { + pkt_error++; + } + } + + switch(msg->ev_type) { + + case DM_EVENT_PREUNMOUNT: + printf(HDR VALS VALS VALS, + "preunmount", msg->ev_token, msg->ev_sequence, + "fs handle", hans1, + "root dir", hans2, + "unmount mode", type); + break; + + case DM_EVENT_UNMOUNT: + printf(HDR VALS VALS VALD, + "unmount", msg->ev_token, msg->ev_sequence, + "fs handle", hans1, + "unmount mode", type, + "retcode", msg_ne->ne_retcode); + break; + + case DM_EVENT_NOSPACE: + printf(HDR VALS, + "nospace", msg->ev_token, msg->ev_sequence, + "fs handle", hans1); + break; + + case DM_EVENT_DEBUT: /* not supported on SGI */ + printf(HDR VALS, + "debut", msg->ev_token, msg->ev_sequence, + "object", hans1); + break; + + case DM_EVENT_CREATE: + printf(HDR VALS VALS VALS, + "create", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "mode bits", type); + break; + + case DM_EVENT_POSTCREATE: + printf(HDR VALS VALS VALS VALS VALD, + "postcreate", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "new object", hans2, + "name", nams1, + "mode bits", type, + "retcode", msg_ne->ne_retcode); + break; + + case DM_EVENT_REMOVE: + printf(HDR VALS VALS VALS, + "remove", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "mode bits", type); + break; + + case DM_EVENT_POSTREMOVE: + printf(HDR VALS VALS VALS VALD, + "postremove", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "mode bits", type, + "retcode", msg_ne->ne_retcode); + break; + + case DM_EVENT_RENAME: + printf(HDR VALS VALS VALS VALS, + "rename", msg->ev_token, msg->ev_sequence, + "old parent", hans1, + "new parent", hans2, + "old name", nams1, + "new name", nams2); + break; + + case DM_EVENT_POSTRENAME: + printf(HDR VALS VALS VALS VALS VALD, + "postrename", msg->ev_token, msg->ev_sequence, + "old parent", hans1, + "new parent", hans2, + "old name", nams1, + "new name", nams2, + "retcode", msg_ne->ne_retcode); + break; + + case DM_EVENT_SYMLINK: + printf(HDR VALS VALS VALS, + "symlink", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "contents", nams2); + break; + + case DM_EVENT_POSTSYMLINK: + printf(HDR VALS VALS VALS VALS VALD, + "postsymlink", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "new object", hans2, + "name", nams1, + "contents", nams2, + "retcode", msg_ne->ne_retcode); + break; + + case DM_EVENT_LINK: + printf(HDR VALS VALS VALS, + "link", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "source", hans2, + "name", nams1); + break; + + case DM_EVENT_POSTLINK: + printf(HDR VALS VALS VALS VALD, + "postlink", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "source", hans2, + "name", nams1, + "retcode", msg_ne->ne_retcode); + break; + + case DM_EVENT_ATTRIBUTE: + printf(HDR VALS, + "attribute", msg->ev_token, msg->ev_sequence, + "object", hans1); + break; + + case DM_EVENT_CLOSE: /* not supported on SGI */ + printf(HDR VALS, + "close", msg->ev_token, msg->ev_sequence, + "object", hans1); + break; + + default: + pkt_error++; + printf(HDR VALD, + "", msg->ev_token, msg->ev_sequence, + "ev_type", msg->ev_type); + break; + } + } + return(pkt_error); +} + + +int +handle_message( + dm_sessid_t sid, + dm_eventmsg_t *msg) +{ + dm_response_t response; + int respond, respcode; + int error = 0; + + if (print_one_message(msg)) + error++; + + /* Set the defaults for responding to events. */ + + respond = 1; + response = DM_RESP_CONTINUE; + respcode = 0; + + /***** USER EVENTS *****/ + + switch (msg->ev_type) { + case DM_EVENT_USER: + if (msg->ev_token == DM_INVALID_TOKEN) + respond = 0; + break; + + case DM_EVENT_CANCEL: + case DM_EVENT_DESTROY: + case DM_EVENT_POSTCREATE: + case DM_EVENT_POSTREMOVE: + case DM_EVENT_POSTRENAME: + case DM_EVENT_POSTSYMLINK: + case DM_EVENT_POSTLINK: + case DM_EVENT_ATTRIBUTE: + case DM_EVENT_CLOSE: + respond = 0; + break; + + case DM_EVENT_MOUNT: + case DM_EVENT_READ: + case DM_EVENT_WRITE: + case DM_EVENT_TRUNCATE: + case DM_EVENT_PREUNMOUNT: + case DM_EVENT_UNMOUNT: + case DM_EVENT_DEBUT: + case DM_EVENT_CREATE: + case DM_EVENT_REMOVE: + case DM_EVENT_RENAME: + case DM_EVENT_SYMLINK: + case DM_EVENT_LINK: + break; + + case DM_EVENT_NOSPACE: + response = DM_RESP_ABORT; + respcode = ENOSPC; + break; + + default: + if (msg->ev_token == DM_INVALID_TOKEN) + respond = 0; + break; + } + + /* Respond to those messages which require a response. */ + + if (respond) { + if (dm_respond_event(sid, msg->ev_token, response, respcode, 0, 0)) { + errno_msg("Can't respond to event"); + } + } + return(error); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/stubs.c linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/stubs.c --- linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/stubs.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/stubs.c Tue Jan 16 19:24:14 2001 @@ -0,0 +1,517 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + + +/* See dmport.h for a description of why all these wrapper routines are + necessary. Because SGI defines stub routines for all functions it didn't + implement, no SGI-specific wrappers are required. +*/ + + +#ifdef VERITAS_21 + +/* The Veritas version of dm_downgrade_right has two additional parameters + not defined in the XDSM spec. Provide values that make dm_downgrade_right + work according to the spec. +*/ + +extern int +xvfs_dm_downgrade_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ +#undef dm_downgrade_right + return(dm_downgrade_right(sid, hanp, hlen, token, 0, DM_RIGHT_SHARED)); +} + + +/* The last byte in a Veritas handle is a 'pad' byte which they don't bother + to initialize to zero. As a result, you can't do binary compares of + two handles to see if they are the same. This stub (along with others) + forces the pad byte to zero so that binary compares are possible +*/ + +extern int +xvfs_dm_fd_to_handle( + int fd, + void **hanpp, + size_t *hlenp) +{ +#undef dm_fd_to_handle + int rc; + + if ((rc = dm_fd_to_handle(fd, hanpp, hlenp)) == 0) { + if (*hlenp == 16) { + char *cp = (char *)*hanpp; + cp[15] = '\0'; + } + } + return(rc); +} + + +/* The Veritas version of dm_get_config_events has a slightly different name. +*/ + +extern int +dm_get_config_events( + void *hanp, + size_t hlen, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp) +{ + return(dm_get_config_event(hanp, hlen, nelem, eventsetp, nelemp)); +} + + +/* In version 2.1 uflags was defined as 'int nowait', so a value of zero in + this field means that the caller wants to wait. In XDSM this was reversed, + where if the bottom bit of uflags is set then the caller wants to wait. + This routine makes the conversion. +*/ + +extern int +xvfs_dm_get_events( + dm_sessid_t sid, + u_int maxmsgs, + u_int uflags, + size_t buflen, + void *bufp, + size_t *rlenp) +{ +#undef dm_get_events + int nowait = 1; + + if (uflags & DM_EV_WAIT) + nowait = 0; + + return(dm_get_events(sid, maxmsgs, nowait, buflen, bufp, rlenp)); +} + + +/* The Veritas version of dm_get_mountinfo has the parameters in a different + order than in the XDSM spec. Hide this in the wrapper. +*/ + +extern int +xvfs_dm_get_mountinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp) +{ +#undef dm_get_mountinfo + return(dm_get_mountinfo(sid, token, hanp, hlen, buflen, bufp, rlenp)); +} + + +/* Veritas does not support the dm_getall_disp function. Furthermore, their + dm_dispinfo_t structure is missing the _link field that is needed for the + DM_STEP_TO_NEXT() macro to work. +*/ + +extern int +dm_getall_disp( + dm_sessid_t sid, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + return(ENOSYS); +} + + +/* Veritas does not support the dm_getall_dmattr function. Furthermore, their + dm_attrlist_t structure is missing the _link field that is needed for the + DM_STEP_TO_NEXT() macro to work. +*/ + +extern int +dm_getall_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + return(ENOSYS); +} + + +/* Veritas does not support dm_handle_is_valid. We emulate it by checking + fields which have known values, as DMF uses this a lot. +*/ + +extern dm_boolean_t +dm_handle_is_valid( + void *hanp, + size_t hlen) +{ + char *cp = (char *)hanp; + + if (hlen != 16) { + return(DM_FALSE); + } + if (cp[15] != '\0') { + return(DM_FALSE); + } + switch (cp[14]) { + case 1: + case 2: + case 4: + break; + default: + return(DM_FALSE); + } + switch (cp[13]) { + case 0: + case 1: + break; + default: + return(DM_FALSE); + } + return(DM_TRUE); +} + + +/* Veritas uses a dev_t for their dm_fsid_t, and named their routines + accordingly. Hide this in the wrapper. Note that a dev_t is 32 bits + and the SGI dm_fsid_t is defined to be a uint64_t. If this gets to + be a problem (e.g. %x verus %llx), the Veritas dm_fsid_t could be made + to match SGI with a little casting here and there. +*/ + +extern int +dm_handle_to_fsid( + void *hanp, + size_t hlen, + dm_fsid_t *fsidp) +{ + dev_t dev; + + dev = dm_handle_to_dev(hanp, hlen); + *fsidp = (dm_fsid_t)dev; + return(0); +} + + +/* The Veritas dm_handle_to_fgen returns a long which is really the + file's generation number. dm_igen_t is typedef'd to be a long also, + so the cast here is safe. +*/ + +extern int +dm_handle_to_igen( + void *hanp, + size_t hlen, + dm_igen_t *igenp) +{ +#undef dm_handle_to_igen + long igen; + + igen = (dm_igen_t)dm_handle_to_fgen(hanp, hlen); + *igenp = (dm_igen_t)igen; + return(0); +} + + +/* Veritas uses a long for their dm_ino_t, which is really an ino_t. + Hide this in the wrapper. Note that a ino_t is 32 bits and the SGI + dm_ino_t is defined to be a uint64_t. If this gets to be a problem + (e.g. %x verus %llx), the Veritas dm_ino_t could be made to match SGI + with a little casting here and there. +*/ + + +extern int +xvfs_dm_handle_to_ino( + void *hanp, + size_t hlen, + dm_ino_t *inop) +{ +#undef dm_handle_to_ino + long ino; + + ino = (dm_ino_t)dm_handle_to_ino(hanp, hlen); + *inop = (dm_ino_t)ino; + return(0); +} + + +/* Version 2.1 of the spec did not specify the versionstrpp parameter. This + code makes the routine appear to work correctly to the caller, but it + is not really able to do the runtime check that the parameter is + supposed to provide. +*/ + +extern int +xvfs_dm_init_service( + char **versionstrpp) +{ +#undef dm_init_service + *versionstrpp = DM_VER_STR_CONTENTS; + return(dm_init_service()); +} + + +extern int +xvfs_dm_make_fshandle( + dm_fsid_t *fsidp, + void **hanpp, + size_t *hlenp) +{ +#undef dm_make_fshandle + dev_t dev; + + dev = (dev_t)*fsidp; + return(dm_make_fshandle(dev, hanpp, hlenp)); +} + + +extern int +xvfs_dm_make_handle( + dm_fsid_t *fsidp, + dm_ino_t *inop, + dm_igen_t *igenp, + void **hanpp, + size_t *hlenp) +{ +#undef dm_make_handle + dev_t dev; + long ino; + long igen; + + dev = (dev_t)*fsidp; + ino = (long)*inop; + igen = (long)*igenp; + return(dm_make_handle(dev, ino, igen, hanpp, hlenp)); +} + + +/* The last byte in a Veritas handle is a 'pad' byte which they don't bother + to initialize to zero. As a result, you can't do binary compares of + two handles to see if they are the same. This stub (along with others) + forces the pad byte to zero so that binary compares are possible +*/ + +extern int +xvfs_dm_path_to_fshandle( + char *path, + void **fshanpp, + size_t *fshlenp) +{ +#undef dm_path_to_fshandle + int rc; + + if ((rc = dm_path_to_fshandle(path, fshanpp, fshlenp)) == 0) { + if (*fshlenp == 16) { + char *cp = (char *)*fshanpp; + cp[15] = '\0'; + } + } + return(rc); +} + + +/* The last byte in a Veritas handle is a 'pad' byte which they don't bother + to initialize to zero. As a result, you can't do binary compares of + two handles to see if they are the same. This stub (along with others) + forces the pad byte to zero so that binary compares are possible +*/ + +extern int +xvfs_dm_path_to_handle( + char *path, + void **hanpp, + size_t *hlenp) +{ +#undef dm_path_to_handle + int rc; + + if ((rc = dm_path_to_handle(path, hanpp, hlenp)) == 0) { + if (*hlenp == 16) { + char *cp = (char *)*hanpp; + cp[15] = '\0'; + } + } + return(rc); +} + + +/* Veritas has a prototype for this function even though it is not + implemented. +*/ + +extern int +xvfs_dm_pending( + dm_sessid_t sid, + dm_token_t token, + dm_timestruct_t *delay) +{ +#undef dm_pending + return(ENOSYS); +} + + +extern int +xvfs_dm_read_invis( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + void *bufp) +{ +#undef dm_read_invis + return(dm_read_invis(sid, hanp, hlen, token, off, (dm_ssize_t)len, bufp)); +} + + +/* In version 2.1 uflags was defined as 'int nowait', so a value of zero in + this field means that the caller wants to wait. In XDSM this was reversed, + where if the bottom bit of uflags is set then the caller wants to wait. + This routine makes the conversion. +*/ + +extern int +xvfs_dm_request_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int uflags, + dm_right_t right) +{ +#undef dm_request_right + int nowait = 1; + + if (uflags & DM_RR_WAIT) + nowait = 0; + return(dm_request_right(sid, hanp, hlen, token, nowait, right)); +} + + +extern int +xvfs_dm_set_inherit( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + mode_t mode) +{ +#undef dm_set_inherit + return(dm_set_inherit(sid, hanp, hlen, token, attrnamep, (u_int)mode)); +} + + +extern int +xvfs_dm_set_region( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_region_t *regbufp, + dm_boolean_t *exactflagp) +{ +#undef dm_set_region + return(dm_set_region(sid, hanp, hlen, token, nelem, regbufp, (u_int *)exactflagp)); +} + + +extern int +dm_set_return_on_destroy( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + dm_boolean_t enable) +{ + return(dm_set_return_ondestroy(sid, hanp, hlen, token, attrnamep, (int)enable)); +} + + +extern int +xvfs_dm_sync_by_handle( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ +#undef dm_sync_by_handle + return((int)dm_sync_by_handle(sid, hanp, hlen, token)); +} + +extern int +xvfs_dm_upgrade_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ +#undef dm_upgrade_right + return(dm_upgrade_right(sid, hanp, hlen, token, 0, DM_RIGHT_EXCL)); +} + + +extern int +xvfs_dm_write_invis( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int flags, + dm_off_t off, + dm_size_t len, + void *bufp) +{ +#undef dm_write_invis + return(dm_write_invis(sid, hanp, hlen, token, off, (dm_ssize_t)len, bufp, flags)); +} + +#endif diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/util.c linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/util.c --- linux-2.4.7/cmd/xfstests/dmapi/src/common/lib/util.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/common/lib/util.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,978 @@ +/* + * Utility routines + * + * This code was written by Peter Lawthers, and placed in the public + * domain for use by DMAPI implementors and app writers. + * + * Standard disclaimer: + * THIS SOFTWARE IS PROVIDED ``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 + +#include +#include + +#include + +#include +#include +#ifdef linux +#include +#define S_IAMB (S_IRWXU|S_IRWXG|S_IRWXO) +#endif + +#define S_MASK (S_ISUID|S_ISGID|S_ISVTX|S_IAMB) + +extern char *Progname; +extern int errno; + +void err_msg(char *, ...); +void errno_msg(char *, ...); + +struct ev_name_to_value ev_names[] = { + { "DM_EVENT_CANCEL", DM_EVENT_CANCEL }, + { "DM_EVENT_MOUNT", DM_EVENT_MOUNT }, + { "DM_EVENT_PREUNMOUNT", DM_EVENT_PREUNMOUNT }, + { "DM_EVENT_UNMOUNT", DM_EVENT_UNMOUNT }, + { "DM_EVENT_DEBUT", DM_EVENT_DEBUT }, + { "DM_EVENT_CREATE", DM_EVENT_CREATE }, + { "DM_EVENT_CLOSE", DM_EVENT_CLOSE }, + { "DM_EVENT_POSTCREATE", DM_EVENT_POSTCREATE }, + { "DM_EVENT_REMOVE", DM_EVENT_REMOVE }, + { "DM_EVENT_POSTREMOVE", DM_EVENT_POSTREMOVE }, + { "DM_EVENT_RENAME", DM_EVENT_RENAME }, + { "DM_EVENT_POSTRENAME", DM_EVENT_POSTRENAME }, + { "DM_EVENT_LINK", DM_EVENT_LINK }, + { "DM_EVENT_POSTLINK", DM_EVENT_POSTLINK }, + { "DM_EVENT_SYMLINK", DM_EVENT_SYMLINK }, + { "DM_EVENT_POSTSYMLINK", DM_EVENT_POSTSYMLINK }, + { "DM_EVENT_READ", DM_EVENT_READ }, + { "DM_EVENT_WRITE", DM_EVENT_WRITE }, + { "DM_EVENT_TRUNCATE", DM_EVENT_TRUNCATE }, + { "DM_EVENT_ATTRIBUTE", DM_EVENT_ATTRIBUTE }, + { "DM_EVENT_DESTROY", DM_EVENT_DESTROY }, + { "DM_EVENT_NOSPACE", DM_EVENT_NOSPACE }, + { "DM_EVENT_USER", DM_EVENT_USER } +}; + +int ev_namecnt = sizeof(ev_names) / sizeof(ev_names[0]); + +dm_eventtype_t +ev_name_to_value( + char *name) +{ + int i; + + for (i = 0; i < ev_namecnt; i++) { + if (!strcmp(name, ev_names[i].name)) + return(ev_names[i].value); + } + return(DM_EVENT_INVALID); +} + +char * +ev_value_to_name( + dm_eventtype_t event) +{ + static char buffer[100]; + int i; + + for (i = 0; i < ev_namecnt; i++) { + if (event == ev_names[i].value) + return(ev_names[i].name); + } + sprintf(buffer, "Unknown Event Number %d\n", event); + return(buffer); +} + + + +struct rt_name_to_value rt_names[] = { + { "DM_RIGHT_NULL", DM_RIGHT_NULL }, + { "DM_RIGHT_SHARED", DM_RIGHT_SHARED }, + { "DM_RIGHT_EXCL", DM_RIGHT_EXCL } +}; + +int rt_namecnt = sizeof(rt_names) / sizeof(rt_names[0]); + +int +rt_name_to_value( + char *name, + dm_right_t *rightp) +{ + int i; + + for (i = 0; i < rt_namecnt; i++) { + if (!strcmp(name, rt_names[i].name)) { + *rightp = rt_names[i].value; + return(0); + } + } + return(1); +} + + +char * +rt_value_to_name( + dm_right_t right) +{ + int i; + + for (i = 0; i < rt_namecnt; i++) { + if (right == rt_names[i].value) + return(rt_names[i].name); + } + return(NULL); +} + + +/* + * Convert a handle from (possibly) binary to ascii. + */ +void +hantoa( + void *hanp, + size_t hlen, + char *handle_str) +{ + int i; + u_char *cp; + + cp = (u_char *)hanp; + for (i=0;i HANDLE_LEN * 2){ + return(EBADF); + } + + while (*handle_str && *(handle_str + 1)) { + if (i == HANDLE_LEN){ + return(EBADF); + } + cur_char[0] = *handle_str; + cur_char[1] = *(handle_str + 1); + cur_char[2] = '\0'; + num = strtol(cur_char, (char **)0, 16); + handle[i++] = num & 0xff; + handle_str += 2; + } + if (*handle_str){ + return(EBADF); + } + *hlenp = i; + if ((*hanpp = malloc(*hlenp)) == NULL) + return(ENOMEM); + memcpy(*hanpp, handle, *hlenp); + return(0); +} + + +int +opaque_to_handle( + char *name, + void **hanpp, + size_t *hlenp) +{ + if (atohan(name, hanpp, hlenp)) { + /* not a handle */ + } else if (dm_handle_is_valid(*hanpp, *hlenp) == DM_FALSE) { + dm_handle_free(*hanpp, *hlenp); + /* not a handle */ + } else { + return(0); + } + + /* Perhaps it is a pathname */ + + if (dm_path_to_handle(name, hanpp, hlenp)) { + return(errno); + } + return(0); +} + + +void +print_handle( + void *hanp, + size_t hlen) +{ + char handle_str[HANDLE_STR]; + + if (hlen > HANDLE_LEN) { + printf("-- invalid hlen length %d --\n", hlen); + return; + } + + printf("print_handle: "); + printf("%d\t", hlen); + hantoa(hanp, hlen, handle_str); + printf("%s\n ", handle_str); +} + +void +print_victim( + void *hanp, + size_t hlen, + dm_off_t fsize) +{ + char handle_str[HANDLE_STR]; + + if (hlen > HANDLE_LEN) { + printf("-- invalid length --\n"); + return; + } + + printf("%d\t", hlen); + hantoa(hanp, hlen, handle_str); + printf("%s ", handle_str); + printf("\t%lld \n", fsize); +} + + +/* + * Print out a simple error message, and include the errno + * string with it. + */ +void +errno_msg(char *fmt, ...) +{ + va_list ap; + int old_errno; + + old_errno = errno; + fprintf(stderr, "%s: ", Progname); + + va_start(ap, fmt ); + vfprintf(stderr, fmt, ap); + va_end(ap); + + errno = old_errno; + perror("\n\tError"); +} + +/* + * Print out a simple error message + */ +void +err_msg(char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "%s: ", Progname); + + va_start(ap, fmt ); + vfprintf(stderr, fmt, ap); + va_end(ap); + +} + + +/* + * Initialize the interface to the DMAPI + */ +int +setup_dmapi(dm_sessid_t *sidp) +{ + char *cp; + + if (dm_init_service(&cp) == -1) { + err_msg("%s/%d: Can't init dmapi", __FILE__, __LINE__); + return(1); + } + if (strcmp(cp, DM_VER_STR_CONTENTS)) { + err_msg("%s/%d: Compiled for a different version", __FILE__, __LINE__); + return(1); + } + + find_test_session(sidp); + return(0); +} + +/* + * Get the file's change indicator + */ +int +get_dmchange( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int *change_start) +{ + int error; + dm_stat_t statbuf; + + + error = dm_get_fileattr(sid, hanp, hlen, token, DM_AT_CFLAG, &statbuf); + if (error == -1) { + errno_msg("%s/%d: Can't stat file (%d)", __FILE__, __LINE__, errno); + return(1); + } + *change_start = statbuf.dt_change; + return(0); +} + + +/* + * Write a file's data to the staging file. We write the file out + * in 4meg chunks. + */ +int +save_filedata( + dm_sessid_t sid, + void *hanp, + size_t hlen, + int stg_fd, + dm_size_t fsize) +{ + char *filebuf; + int i, nbufs; + int retval; + dm_ssize_t nread, lastbuf; + ssize_t nwrite; + dm_off_t off; + + nbufs = fsize / CHUNKSIZE; + off = 0; + retval = 0; + filebuf = malloc(CHUNKSIZE); + if (filebuf == NULL) { + err_msg("%s/%d: Can't alloc memory for file buffer", __FILE__, __LINE__); + goto out; + } + + for (i = 0; idt_dev != statb.st_dev) { + if (report_errors) { + fprintf(stdout, "ERROR:dmstat->dt_dev 0x%llx, " + "statb.st_dev 0x%llx\n", + (uint64_t)dmstat->dt_dev, + (uint64_t)statb.st_dev); + } + errors++; + } + if (dmstat->dt_ino != statb.st_ino) { + if (report_errors) { + fprintf(stdout, "ERROR:dmstat->dt_ino %llx, " +#if defined(linux) || (defined(__sgi) && (_MIPS_SIM != _MIPS_SIM_ABI32)) + "statb.st_ino %llx\n", +#else + "statb.st_ino %x\n", +#endif + dmstat->dt_ino, statb.st_ino); + } + errors++; + } + if ((dmstat->dt_mode & S_IFMT) != field_to_mode(statb.st_mode)) { + if (report_errors) { + fprintf(stdout, "ERROR:dmstat->dt_mode (mode) %s, " + "statb.st_mode (mode) %s\n", + mode_to_string(dmstat->dt_mode), + mode_to_string(field_to_mode(statb.st_mode))); + } + errors++; + } + if ((dmstat->dt_mode & S_MASK) != (statb.st_mode & S_MASK)) { + if (report_errors) { + fprintf(stdout, "ERROR:dmstat->dt_mode (perm) 0%o, " + "statb.st_mode (perm) 0%o\n", + dmstat->dt_mode & S_MASK, + statb.st_mode & S_MASK); + } + errors++; + } + if (dmstat->dt_nlink != statb.st_nlink) { + if (report_errors) { + fprintf(stdout, "ERROR:dmstat->dt_nlink %d, " + "statb.st_nlink %d\n", dmstat->dt_nlink, + statb.st_nlink); + } + errors++; + } + if (dmstat->dt_uid != statb.st_uid) { + if (report_errors) { + fprintf(stdout, "ERROR:dmstat->dt_uid %d, " + "statb.st_uid %d\n", dmstat->dt_uid, + statb.st_uid); + } + errors++; + } + if (dmstat->dt_gid != statb.st_gid) { + if (report_errors) { + fprintf(stdout, "ERROR:dmstat->dt_gid %d, " + "statb.st_gid %d\n", dmstat->dt_gid, + statb.st_gid); + } + errors++; + } + if (dmstat->dt_rdev != statb.st_rdev) { + if (report_errors) { + fprintf(stdout, "ERROR:dmstat->dt_rdev 0x%llx, " + "statb.st_rdev 0x%llx\n", + (uint64_t)dmstat->dt_rdev, + (uint64_t)statb.st_rdev); + } + errors++; + } + if (dmstat->dt_size != statb.st_size) { + if (report_errors) { + fprintf(stdout, "ERROR:dmstat->dt_size %lld, " +#if defined(linux) || (defined(__sgi) && (_MIPS_SIM != _MIPS_SIM_ABI32)) + "statb.st_size %lld\n", +#else + "statb.st_size %d\n", +#endif + dmstat->dt_size, statb.st_size); + } + errors++; + } + if (dmstat->dt_atime != statb.st_atime) { + if (report_errors) { + fprintf(stdout, "ERROR:dmstat->dt_atime %ld, " + "statb.st_atime %ld\n", dmstat->dt_atime, + statb.st_atime); + } + errors++; + } + if (dmstat->dt_mtime != statb.st_mtime) { + if (report_errors) { + fprintf(stdout, "ERROR:dmstat->dt_mtime %ld, " + "statb.st_mtime %ld\n", dmstat->dt_mtime, + statb.st_mtime); + } + errors++; + } + if (dmstat->dt_ctime != statb.st_ctime) { + if (report_errors) { + fprintf(stdout, "ERROR:dmstat->dt_ctime %ld, " + "statb.st_ctime %ld\n", dmstat->dt_ctime, + statb.st_ctime); + } + errors++; + } + if (dmstat->dt_dtime != statb.st_ctime) { + if (report_errors) { + fprintf(stdout, "ERROR:dmstat->dt_dtime %ld, " + "statb.st_ctime %ld\n", dmstat->dt_dtime, + statb.st_ctime); + } + errors++; + } + if (dmstat->dt_blksize != statb.st_blksize) { + if (report_errors) { + fprintf(stdout, "ERROR:dmstat->dt_blksize %d, " + "statb.st_blksize %ld\n", dmstat->dt_blksize, + statb.st_blksize); + } + errors++; + } + if (dmstat->dt_blocks != statb.st_blocks) { + if (report_errors) { + fprintf(stdout, "ERROR:dmstat->dt_blocks %lld, " +#if defined(linux) || (defined(__sgi) && (_MIPS_SIM != _MIPS_SIM_ABI32)) + "statb.st_blocks %lld\n", +#else + "statb.st_blocks %d\n", +#endif + dmstat->dt_blocks, statb.st_blocks); + } + errors++; + } + + if (errors && report_errors) + fprintf(stdout, "There were %d differences\n", errors); + return(errors); +} + + +extern char * +date_to_string( + time_t timeval) +{ +static char buffer[21]; + char *tmstr; + + if (timeval == (time_t)0) { + strcpy(buffer, "0"); + } else { + tmstr = asctime(localtime(&timeval)); + tmstr += 4; + strncpy(buffer, tmstr, 20); + buffer[20] = '\0'; + } + return(buffer); +} + + +extern char * +mode_to_string( + mode_t mode) +{ +static char buffer[256]; + + switch (mode & S_IFMT) { + + case S_IFBLK: + return("S_IFBLK"); + + case S_IFREG: + return("S_IFREG"); + + case S_IFDIR: + return("S_IFDIR"); + + case S_IFCHR: + return("S_IFCHR"); + + case S_IFIFO: + return("S_IFIFO"); + + case S_IFLNK: + return("S_IFLNK"); + + case S_IFSOCK: + return("S_IFSOCK"); + + default: + sprintf(buffer, "Invalid mode 0%o", mode & S_IFMT); + return(buffer); + } +} + + +extern char * +emask_to_string( + dm_eventset_t emask) +{ +static char buffer[256]; + char *name; + int len = 0; + int i; + + for (i = 0; i < 32; i++) { + if (!DMEV_ISSET(i, emask)) + continue; + + switch (i) { + case DM_EVENT_CREATE: + name = "DM_EVENT_CREATE"; + break; + case DM_EVENT_POSTCREATE: + name = "DM_EVENT_POSTCREATE"; + break; + case DM_EVENT_REMOVE: + name = "DM_EVENT_REMOVE"; + break; + case DM_EVENT_POSTREMOVE: + name = "DM_EVENT_POSTREMOVE"; + break; + case DM_EVENT_RENAME: + name = "DM_EVENT_RENAME"; + break; + case DM_EVENT_POSTRENAME: + name = "DM_EVENT_POSTRENAME"; + break; + case DM_EVENT_LINK: + name = "DM_EVENT_LINK"; + break; + case DM_EVENT_POSTLINK: + name = "DM_EVENT_POSTLINK"; + break; + case DM_EVENT_SYMLINK: + name = "DM_EVENT_SYMLINK"; + break; + case DM_EVENT_POSTSYMLINK: + name = "DM_EVENT_POSTSYMLINK"; + break; + case DM_EVENT_READ: + name = "DM_EVENT_READ"; + break; + case DM_EVENT_WRITE: + name = "DM_EVENT_WRITE"; + break; + case DM_EVENT_TRUNCATE: + name = "DM_EVENT_TRUNCATE"; + break; + case DM_EVENT_ATTRIBUTE: + name = "DM_EVENT_ATTRIBUTE"; + break; + case DM_EVENT_DESTROY: + name = "DM_EVENT_DESTROY"; + break; + default: + fprintf(stderr, "Unknown event type %d\n", i); + exit(1); + } + sprintf(buffer + len, "%c%s", (len ? '|' : '('), name); + len = strlen(buffer); + } + + if (len == 0) { + sprintf(buffer, "(none)"); + } else { + sprintf(buffer + len, ")"); + } + return(buffer); +} + + +#if defined(__sgi) || defined(linux) + +extern char * +xflags_to_string( + u_int xflags) +{ +static char buffer[256]; + int len = 0; + + if (xflags & ~(DM_XFLAG_REALTIME|DM_XFLAG_PREALLOC|DM_XFLAG_HASATTR)) { + sprintf(buffer, "Invalid xflags 0%o", xflags); + return(buffer); + } + + if (xflags & DM_XFLAG_REALTIME) { + sprintf(buffer + len, "%cREALTIME", (len ? '|' : '(')); + len = strlen(buffer); + } + if (xflags & DM_XFLAG_PREALLOC) { + sprintf(buffer + len, "%cPREALLOC", (len ? '|' : '(')); + len = strlen(buffer); + } + if (xflags & DM_XFLAG_HASATTR) { + sprintf(buffer + len, "%cHASATTR", (len ? '|' : '(')); + len = strlen(buffer); + } + if (len == 0) { + sprintf(buffer, "(none)"); + } else { + sprintf(buffer + len, ")"); + } + return(buffer); +} + +#endif + + +extern void +print_state( + dm_stat_t *dmstat) +{ + /* Print all the stat block fields. */ + + fprintf(stdout, "dt_dev 0x%llx\n", (uint64_t)dmstat->dt_dev); + fprintf(stdout, "dt_ino %llx\n", dmstat->dt_ino); + fprintf(stdout, "dt_mode (type) %s\n", + mode_to_string(dmstat->dt_mode)); + fprintf(stdout, "dt_mode (perm) 0%o\n", dmstat->dt_mode & S_MASK); + fprintf(stdout, "dt_nlink %d\n", dmstat->dt_nlink); + fprintf(stdout, "dt_uid %d\n", dmstat->dt_uid); + fprintf(stdout, "dt_gid %d\n", dmstat->dt_gid); + fprintf(stdout, "dt_rdev 0x%llx\n", (uint64_t)dmstat->dt_rdev); + fprintf(stdout, "dt_size %lld\n", dmstat->dt_size); + + fprintf(stdout, "dt_atime %s\n", + date_to_string(dmstat->dt_atime)); + fprintf(stdout, "dt_mtime %s\n", + date_to_string(dmstat->dt_mtime)); + fprintf(stdout, "dt_ctime %s\n", + date_to_string(dmstat->dt_ctime)); + + fprintf(stdout, "dt_blksize %d\n", dmstat->dt_blksize); + fprintf(stdout, "dt_blocks %lld\n", dmstat->dt_blocks); + +#if defined(__sgi) || defined(linux) + fprintf(stdout, "dt_xfs_igen %d\n", dmstat->dt_xfs_igen); + fprintf(stdout, "dt_xfs_xflags %s\n", + xflags_to_string(dmstat->dt_xfs_xflags)); + fprintf(stdout, "dt_xfs_extsize %d\n", dmstat->dt_xfs_extsize); + fprintf(stdout, "dt_xfs_extents %d\n", dmstat->dt_xfs_extents); + fprintf(stdout, "dt_xfs_aextents %d\n", dmstat->dt_xfs_aextents); +#endif + + fputc('\n', stdout); + + /* Print all other fields. */ + + fprintf(stdout, "emask %s\n", + emask_to_string(dmstat->dt_emask)); + fprintf(stdout, "nevents %d\n", dmstat->dt_nevents); + fprintf(stdout, "pmanreg %d\n", dmstat->dt_pmanreg); + fprintf(stdout, "pers %d\n", dmstat->dt_pers); + fprintf(stdout, "dt_dtime %s\n", + date_to_string(dmstat->dt_dtime)); + fprintf(stdout, "change %d\n", dmstat->dt_change); +} + + +extern void +print_line( + dm_stat_t *dmstat) +{ + fprintf(stdout, "0x%llx|", (uint64_t)dmstat->dt_dev); + fprintf(stdout, "%llx|", dmstat->dt_ino); + fprintf(stdout, "%s|", mode_to_string(dmstat->dt_mode)); + fprintf(stdout, "0%o|", dmstat->dt_mode & S_MASK); + fprintf(stdout, "%d|", dmstat->dt_nlink); + fprintf(stdout, "%d|", dmstat->dt_uid); + fprintf(stdout, "%d|", dmstat->dt_gid); + fprintf(stdout, "0x%llx|", (uint64_t)dmstat->dt_rdev); + fprintf(stdout, "%lld|", dmstat->dt_size); + + fprintf(stdout, "%s|", date_to_string(dmstat->dt_atime)); + fprintf(stdout, "%s|", date_to_string(dmstat->dt_mtime)); + fprintf(stdout, "%s|", date_to_string(dmstat->dt_ctime)); + + fprintf(stdout, "%d|", dmstat->dt_blksize); + fprintf(stdout, "%lld|", dmstat->dt_blocks); + + fprintf(stdout, "%d|", dmstat->dt_xfs_igen); + fprintf(stdout, "%s|", xflags_to_string(dmstat->dt_xfs_xflags)); + fprintf(stdout, "%d|", dmstat->dt_xfs_extsize); + fprintf(stdout, "%d|", dmstat->dt_xfs_extents); + fprintf(stdout, "%d|", dmstat->dt_xfs_aextents); + + /* Print all other fields. */ + + fprintf(stdout, "%s|", emask_to_string(dmstat->dt_emask)); + fprintf(stdout, "%d|", dmstat->dt_nevents); + fprintf(stdout, "%d|", dmstat->dt_pmanreg); + fprintf(stdout, "%d|", dmstat->dt_pers); + fprintf(stdout, "%s|", date_to_string(dmstat->dt_dtime)); + fprintf(stdout, "%d", dmstat->dt_change); + + fputc('\n', stdout); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/CVS/Entries linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/CVS/Entries --- linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/CVS/Entries Thu Jul 5 11:45:53 2001 @@ -0,0 +1,10 @@ +/Makefile/1.1/Wed Mar 7 22:43:23 2001/-ko/ +/README/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/migfind.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/migin.c/1.2/Wed Mar 7 22:43:23 2001/-ko/ +/migout.c/1.2/Wed Mar 7 22:43:23 2001/-ko/ +/mls.c/1.2/Wed Mar 7 22:43:23 2001/-ko/ +/mrmean.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/print_event.c/1.2/Wed Mar 7 22:43:23 2001/-ko/ +/wbee.c/1.2/Wed Mar 7 22:43:23 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/CVS/Repository linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/CVS/Repository --- linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/CVS/Repository Thu Jul 5 11:45:51 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/CVS/Root linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/CVS/Root --- linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/CVS/Root Thu Jul 5 11:45:51 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/Makefile linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/Makefile --- linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/Makefile Wed Mar 7 16:43:23 2001 @@ -0,0 +1,47 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../../.. +include $(TOPDIR)/include/builddefs + +TARGETS = migfind migin migout mls mrmean print_event wbee +CFILES = $(TARGETS:=.c) +LDIRT = $(TARGETS) + +default: $(TARGETS) + +include $(BUILDRULES) + +CPPFLAGS = -I $(TOPDIR)/dmapi/src/common -I /usr/include/xfs + +LDLIBS = -ldm -lhandle -ldmtest +LDFLAGS += -L $(TOPDIR)/dmapi/src/common/lib diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/README linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/README --- linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/README Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/README Tue Jan 16 19:24:14 2001 @@ -0,0 +1,62 @@ +The files in this directory comprise a simple HSM example that uses +the DMAPI. These files are distributed in the hope that they will be +useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. These programs +have been tested on an SGI platform (as of April 1995) and found +to be suitably functional; however, there is no guarantee that they +do, in fact, provide the functationality that is advertised. This +is a long winded way of saying they probably have bugs; if you +find 'em, fix 'em. + +Okay, now that we have the disclaimers out of the way, here are the details. + + migfind + ======= +This will find all files of a specified size, and print out the handles. +It is normally used like this: + migfind -s 800k /migfs >& cand_file + +This example will find all files greater than 800K in the /migfs filesystem, +and put the handles (converted to ascii) in the file 'cand_file'. The output +consists of three fields per line: + handle length filehandle file size in bytes + + migout + ====== +migout reads a list of handles as created by migfind, and migrates +the files data. The data is stored in files that are located in +another directory. The usage is + migout /dmapi_fs/stagedir < cand_file + +This will all the files specified by handle in 'cand_file', and +put their data in files located under the directory /dmapi_fs/stagedir'. +The staging directory must be on a filesystem that supports +the dmapi; the reason for this is to allow for a simplification +in the code that stores the location of the data as a DM attribute +(file handles are easier than path names). + + migin + ===== +This daemon waits for DMAPI events and dispatches worker bees +to actually stage the data in. The usage is: + migin -l dmapi_log /migfs +migin will fork/exec a 'wbee' to either bring the data back from +the staging directory, or to invalidate the file. + + +Other programs: +There are a couple of other programs in this directory. + + mrmean + ====== +Simplist cleanup/debugging tool that will print information about +the active sessions. If desired, it can also respond to outstanding +events and destroy sessions that may have been left around from +a process exiting unexpectedly. + + mls + === +Simple ls type program to display information about a file, such +as the managed region info, allocation info, event lists, and +file handle. + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/migfind.c linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/migfind.c --- linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/migfind.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/migfind.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,280 @@ +/* + * Simple utility to find all files above a certain size in + * a filesystem. The output is to stdout, and is of the form: + * filehandle length filehandle file size in bytes + * + * The list is not sorted in any way. + * + * This code was written by Peter Lawthers, and placed in the public + * domain for use by DMAPI implementors and app writers. + * + * Standard disclaimer: + * THIS SOFTWARE IS PROVIDED ``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 +#include +#include +#include +#include + +#include + +#include + +#define NUMLEN 16 /* arbitrary max len of input size */ +#define MAX_K (((u_int)LONG_MAX + 1) / 1024) +#define MAX_M (((u_int)LONG_MAX + 1) / (1024*1024)) + + + +extern char *optarg; +extern int optind, optopt, opterr; +char *Progname; + +extern void print_victim(void *, size_t, dm_off_t); +extern void err_msg(char *, ...); +extern void errno_msg(char *, ...); + +int setup_dmapi(dm_sessid_t *); +int scan_fs(dm_sessid_t, void *, size_t, dm_off_t); +int verify_size(char *, dm_off_t *); +void usage(char *); + +void +usage( + char *prog) +{ + fprintf(stderr, "Usage: %s ", prog); + fprintf(stderr, " [-s file threshold]"); + fprintf(stderr, " filesystem\n"); +} + +/* + * Convert an input string on the form 10m or 128K to something reasonable + */ +int +verify_size( + char *str, + dm_off_t *sizep) +{ + char *cp; + dm_off_t size; + + if (strlen(str) > NUMLEN) { + printf("Size %s is invalid \n", str); + return(1); + } + + size = strtol(str,0,0); + if (size < 0 || size >= LONG_MAX ) { + printf("Size %lld is invalid \n", size); + return(1); + } + + cp = str; + while (isdigit(*cp)) + cp++; + if (*cp == 'k' || *cp == 'K') { + if ( size >= (u_int) MAX_K) { + printf("Size %lld is invalid\n", size); + return(1); + } + size *= 1024; + } else if (*cp == 'm' || *cp == 'M') { + if ( size >= (u_int) MAX_M) { + printf("Size %lld is invalid\n", size); + return(1); + } + size *= (1024*1024); + } + *sizep = size; + return(0); +} + + + +int +main( + int argc, + char *argv[]) +{ + + int c; + int error; + dm_off_t size; + char *fsname; + dm_sessid_t sid; + void *fs_hanp; + size_t fs_hlen; + char *sizep = "0"; + + + Progname = argv[0]; + size = 0; + + while ((c = getopt(argc, argv, "s:")) != EOF) { + switch (c) { + case 's': + sizep = optarg; + break; + + case '?': + default: + usage(Progname); + exit(1); + } + } + if (optind >= argc) { + usage(Progname); + exit(1); + } + /* + * Verify the input size string is legit + */ + error = verify_size(sizep, &size); + if (error) + exit(1); + + fsname = argv[optind]; + + /* + * Now we have our filesystem name and possibly a size threshold + * to look for. Init the dmapi, and get a filesystem handle so + * we can scan the filesystem + */ + error = setup_dmapi(&sid); + if (error) + exit(1); + + if (dm_path_to_fshandle(fsname, &fs_hanp, &fs_hlen) == -1) { + errno_msg("Can't get filesystem handle"); + exit(1); + } + + + + /* + * Get the attributes of all files in the filesystem + */ + error = scan_fs(sid, fs_hanp, fs_hlen, size); + if (error) + exit(1); + + + /* + * We're done, so we can shut down our session. + */ + if (dm_destroy_session(sid) == -1) { + errno_msg("Can't close session"); + exit(1); + } + + return(0); + +} + +/* + * Get the attributes for all the files in a filesystem in bulk, + * and print out the handles and sizes of any that meet our target + * criteria. + * + * We are not interested in file names; if we were, then we would + * have to do a dm_get_dirattrs() on each directroy, then use + * dm_handle_to_path() to get the pathname. + */ +int +scan_fs( + dm_sessid_t sid, + void *fs_hanp, + size_t fs_hlen, + dm_off_t target_size) +{ + u_int mask; /* attributes to scan for */ + dm_stat_t *dm_statbuf, *sbuf; /* attributes buffer */ + dm_attrloc_t locp; /* opaque location in fs */ + size_t rlenp; /* ret length of stat info */ + size_t buflen; /* length of stat buffer */ + void *hanp; /* file handle */ + size_t hlen; /* file handle */ + int more; /* loop terminator */ + int error; + + + /* + * Size the stat buffer to return info on 1K files at a time + */ + buflen = sizeof(dm_stat_t) * 1024; +#ifdef VERITAS_21 + if (buflen > 65536) + buflen = 65536; +#endif + dm_statbuf = (dm_stat_t *)calloc(1, buflen); + if (dm_statbuf == NULL) { + err_msg("Can't get memory for stat buffer"); + return(1); + } + + + /* + * Initialize the offset opaque offset cookie that + * we use in successive calls to dm_get_bulkattr() + */ + error = dm_init_attrloc(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, &locp); + if (error == -1) { + errno_msg("%s/%d: Can't initialize offset cookie (%d)", __FILE__, __LINE__, errno); + free(dm_statbuf); + return(1); + } + + /* + * Set our stat mask so that we'll only get the normal stat(2) + * info and the file's handle + */ + mask = DM_AT_HANDLE | DM_AT_STAT; + do { + more = dm_get_bulkattr(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, + mask, &locp, buflen, dm_statbuf, &rlenp); + if (more == -1) { + errno_msg("%s/%d: Can't get bulkattr for filesystem", __FILE__, __LINE__, errno); + break; + } + + /* + * Walk through the stat buffer and pull out files + * that are of interest + * + * The stat buffer is variable length, so we must + * use the DM_STEP_TO_NEXT macro to access each individual + * dm_stat_t structure in the returned buffer. + */ + sbuf = dm_statbuf; + while (sbuf != NULL) { + if (S_ISREG(sbuf->dt_mode) && + sbuf->dt_size >= target_size) { + hanp = DM_GET_VALUE(sbuf, dt_handle, void *); + hlen = DM_GET_LEN(sbuf, dt_handle); + + print_victim(hanp, hlen, sbuf->dt_size); + } + sbuf = DM_STEP_TO_NEXT(sbuf, dm_stat_t *); + } + } while (more == 1); + + free(dm_statbuf); + if (more == -1) + return(1); + + return(0); +} + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/migin.c linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/migin.c --- linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/migin.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/migin.c Wed Mar 7 16:43:23 2001 @@ -0,0 +1,489 @@ +/* + * Master migration daemon + * + * The master migration daemon waits for events on a file and + * spawns a child process to handle the event + * + * This code was written by Peter Lawthers, and placed in the public + * domain for use by DMAPI implementors and app writers. + * + * Standard disclaimer: + * THIS SOFTWARE IS PROVIDED ``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 +#include +#include + +#include +#include +#include +#include + +#include + +extern char *optarg; +extern int optind, optopt, opterr; +extern int errno; +char *Progname; +int Verbose; + +extern int setup_dmapi(dm_sessid_t *); +extern void err_msg(char *, ...); +extern void errno_msg(char *, ...); + +void event_loop(dm_sessid_t); +int set_events(dm_sessid_t, void *, size_t); +int mk_daemon(char *); +void spawn_kid(dm_sessid_t, dm_token_t, char *); +void migin_exit(int); +void usage(char *); + + +void +usage( + char *prog) +{ + fprintf(stderr, "Usage: %s ", prog); + fprintf(stderr, " <-v verbose> "); + fprintf(stderr, " <-l logfile> "); + fprintf(stderr, "filesystem \n"); +} + + +int +main( + int argc, + char *argv[]) +{ + + int c; + int error; + char *fsname, *logfile; + dm_sessid_t sid; + void *fs_hanp; + size_t fs_hlen; + + + Progname = argv[0]; + fsname = NULL; + logfile = NULL; + + while ((c = getopt(argc, argv, "vl:")) != EOF) { + switch (c) { + case 'v': + Verbose = 1; + break; + case 'l': + logfile = optarg; + break; + case '?': + default: + usage(Progname); + exit(1); + } + } + if (optind >= argc) { + usage(Progname); + exit(1); + } + fsname = argv[optind]; + if (fsname == NULL) { + usage(Progname); + exit(1); + } + /* + * If no logfile name is specified, we'll just send + * all output to some file in /tmp + */ + if (logfile == NULL) + logfile = LOG_DEFAULT; + + + /* + * Now we have our filesystem name and possibly a size threshold + * to look for. Init the dmapi, and get a filesystem handle so + * we can set up our events + */ + error = setup_dmapi(&sid); + if (error) + exit(1); + + if (dm_path_to_fshandle(fsname, &fs_hanp, &fs_hlen) == -1) { + errno_msg("Can't get filesystem handle"); + exit(1); + } + + /* + * Turn ourselves into a daemon + */ + error = mk_daemon(logfile); + if (error) + exit(1); + + + /* + * Set the event disposition so that our session will receive + * the managed region events (read, write, and truncate) + */ + error = set_events(sid, fs_hanp, fs_hlen); + if (error) + exit(1); + + + /* + * Now wait forever for messages, spawning kids to + * do the actual work + */ + event_loop(sid); + return(0); +} + +/* + * Main event loop processing + */ +void +event_loop( + dm_sessid_t sid) +{ + void *msgbuf; + size_t bufsize, rlen; + int error; + dm_eventmsg_t *msg; + + /* + * We take a swag at a buffer size. If it's wrong, we can + * always resize it + */ + bufsize = sizeof(dm_eventmsg_t) + sizeof(dm_data_event_t) + HANDLE_LEN; + bufsize *= 16; + msgbuf = (void *)malloc(bufsize); + if (msgbuf == NULL) { + err_msg("Can't allocate memory for buffer"); + goto out; + } + + for (;;) { + error = dm_get_events(sid, ALL_AVAIL_MSGS, DM_EV_WAIT, bufsize, + msgbuf, &rlen); + if (error == -1) { + if (errno == E2BIG) { + free(msgbuf); + msgbuf = (void *)malloc(rlen); + if (msgbuf == NULL) { + err_msg("Can't resize msg buffer"); + goto out; + } + continue; + } + errno_msg("Error getting events from DMAPI"); + goto out; + } + + /* + * Walk thru the message buffer, pull out each individual + * message, and dispatch the messages to child processes + * with the sid, token, and data. The children will + * respond to the events. + */ + msg = (dm_eventmsg_t *)msgbuf; + while (msg != NULL ) { + if (Verbose) { + fprintf(stderr, "Received %s, token %d\n", + (msg->ev_type == DM_EVENT_READ ? "read" : + (msg->ev_type == DM_EVENT_WRITE ? "write" : "trunc")), msg->ev_token); + } + switch (msg->ev_type) { + + case DM_EVENT_READ: + spawn_kid(sid, msg->ev_token, RESTORE_FILE); + break; + + case DM_EVENT_WRITE: + case DM_EVENT_TRUNCATE: + spawn_kid(sid, msg->ev_token, INVAL_FILE); + break; + + default: + err_msg("Invalid msg type %d\n", msg->ev_type); + break; + } + msg = DM_STEP_TO_NEXT(msg, dm_eventmsg_t *); + } + } +out: + if (msgbuf != NULL) + free(msgbuf); + + migin_exit(0); +} + +/* + * Fork and exec our worker bee to work on the file. If + * there is any error in fork/exec'ing the file, we have to + * supply the error return to the event. Once the child gets + * started, he/she/it will respond to the event for us. + */ +void +spawn_kid( + dm_sessid_t sid, + dm_token_t token, + char *action) +{ + pid_t pid; + char sidbuf[sizeof(dm_sessid_t)]; + char tokenbuf[sizeof(dm_token_t)]; + + pid = fork(); + if (pid == 0) { + /* + * We're in the child. Try and exec the worker bee + */ + sprintf(sidbuf, "%d", sid); + sprintf(tokenbuf, "%d", token); + if (Verbose) { + fprintf(stderr, "execl(%s, %s, %s, -s, %s, -t, %s, 0)\n", + WORKER_BEE, WORKER_BEE, action, sidbuf, + tokenbuf); + } + if (execl(WORKER_BEE, WORKER_BEE, action, "-s", sidbuf, + "-t", tokenbuf, NULL)) + { + (void)dm_respond_event(sid, token, DM_RESP_ABORT, + errno, 0, 0); + exit(1); + } + } + + if (pid < 0) { + err_msg("Can't fork worker bee"); + (void)dm_respond_event(sid, token, DM_RESP_ABORT, errno, + 0, 0); + return; + } + return; + +} + + +/* + * Set the event disposition of the managed region events + */ +int +set_events( + dm_sessid_t sid, + void *fs_hanp, + size_t fs_hlen) +{ + dm_eventset_t eventlist; + + DMEV_ZERO(eventlist); + DMEV_SET(DM_EVENT_READ, eventlist); + DMEV_SET(DM_EVENT_WRITE, eventlist); + DMEV_SET(DM_EVENT_TRUNCATE, eventlist); + + if (dm_set_disp(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, &eventlist, + DM_EVENT_MAX) == -1) + { + errno_msg("Can't set event disposition"); + return(1); + } + return(0); +} + + + + +/* + * Dissassociate ourselves from our tty, and close all files + */ +int +mk_daemon( + char *logfile) +{ + int fd; + int i; + struct rlimit lim; + struct sigaction act; + +#ifdef NOTYET + if ((pid = fork()) == -1) + return (-1); + if (pid) + exit(0); + + (void) setsid(); + + (void) chdir("/"); + +#endif /* NOTYET */ + /* + * Determine how many open files we've got and close + * then all + */ + if (getrlimit(RLIMIT_NOFILE, &lim) < 0 ) { + errno_msg("Can't determine max number of open files"); + return(1); + } + for (i=0; i 0) + ; + + fprintf(stdout, "\n"); + + /* + * Now search for our session and try and shut it down. We + * could just as easily make the session ID a global, but + * this demonstrates how sessions can be queried + */ + nsessions = 4; + sidbuf = (dm_sessid_t *)malloc(nsessions * sizeof(dm_sessid_t)); + if (sidbuf == NULL) { + err_msg("Can't alloc mem to shut down session"); + goto out; + } + error = dm_getall_sessions(nsessions, sidbuf, &nret); + if (error == -1) { + if (errno != E2BIG) { + errno_msg("Can't get list of active sessions"); + goto out; + } + free(sidbuf); + nsessions = nret; + sidbuf = (dm_sessid_t *)malloc(nsessions * sizeof(dm_sessid_t)); + if (sidbuf == NULL) { + err_msg("Can't alloc mem to shut down session"); + goto out; + } + error = dm_getall_sessions(nsessions, sidbuf, &nret); + if (error == -1) { + errno_msg("Can't get list of active sessions"); + goto out; + } + } + + /* + * Now we have all the active sessions in our system. + * Query each one until we find ourselves. + */ + sid = sidbuf; + buflen = DM_SESSION_INFO_LEN; + infobuf = malloc(buflen); + if (infobuf == NULL) { + err_msg("Can't alloc memory for session info buffer"); + goto out; + } + + /* + * When we registered our session, we just hammered the last component + * of the path name, so that's all we look for here. This prevents + * mismatches when running at ./migin or some other such foo + */ + cp = strrchr(Progname, '/'); + if (cp) + cp++; + else + cp = Progname; + + + found = 0; + for (i=0; i +#include +#include + +#include +#include +#include +#include + +#include + +extern char *optarg; +extern int optind, optopt, opterr; +char *Progname; +int Verbose; + +int mig_files(dm_sessid_t, char *); +int mk_nonrez(dm_sessid_t, void *, size_t, dm_token_t, dm_off_t); +int set_mrgns(dm_sessid_t, void *, size_t, dm_token_t, dm_off_t, + dm_off_t *); +void clear_mrgns(dm_sessid_t, void *, dm_size_t, dm_token_t); +int lock_file(dm_sessid_t, void *, size_t, dm_right_t, dm_token_t *); +void unlock_file(dm_sessid_t, dm_token_t); +int get_dmchange(dm_sessid_t, void *, size_t, dm_token_t, u_int *); +int create_stgfile(char *, void *, size_t, char *, int *); +int setup_dmapi(dm_sessid_t *); +int save_filedata(dm_sessid_t, void *, size_t, int, dm_size_t); +int extract_fields(char *, char *, size_t *, dm_size_t *); +int save_dataloc(dm_sessid_t, void *, size_t, dm_token_t, char *); + +void usage(char *); + +void +usage( + char *prog) +{ + fprintf(stderr, "Usage: %s ", prog); + fprintf(stderr, " <-v verbose> "); + fprintf(stderr, "\n"); +} + + +int +main( + int argc, + char *argv[]) +{ + + int c; + int error; + char *stage_dir; + dm_sessid_t sid; + + + error = 0; + Progname = argv[0]; + stage_dir = NULL; + + while ((c = getopt(argc, argv, "v")) != EOF) { + switch (c) { + case 'v': + Verbose++; + break; + + case '?': + default: + usage(Progname); + exit(1); + } + } + if (optind >= argc) { + usage(Progname); + exit(1); + } + stage_dir = argv[optind]; + if (stage_dir == NULL) { + usage(Progname); + exit(1); + } + + /* + * Init the dmapi, and get a session. + */ + error = setup_dmapi(&sid); + if (error) + exit(1); + + /* + * Migrate all the files given to us via stdin + */ + error = mig_files(sid, stage_dir); + + + if (dm_destroy_session(sid)) + errno_msg("Can't shut down session, line=%d, errno=%d", __LINE__, errno); + + return(error); +} + +/* + * Migrate all the files given in stdin + */ + +int +mig_files( + dm_sessid_t sid, + char *stage_dir) +{ + void *hanp; + size_t hlen; + dm_size_t fsize; + int error; + u_int change_start, change_end; + int stg_fd; /* staging file descriptor */ + dm_off_t off; /* starting offset */ + dm_token_t token; /* file token */ + char ibuf[IBUFSIZE]; + char handle_buf[HANDLE_LEN]; + char stgpath[MAXPATHLEN]; + + /* + * Read all the lines in std input and migrate each file. + * This simple-minded migout does no batching, sorting, or + * anything else that a real HSM might do. + */ + while (fgets(ibuf, IBUFSIZE, stdin) != NULL) { + error = extract_fields(ibuf, handle_buf, &hlen, &fsize); + if (error) { + err_msg("%s/%d: mangled input line, '%s' ", __FILE__, __LINE__, ibuf); + continue; + } + hanp = (void *)handle_buf; + if (Verbose) { + print_handle(hanp, hlen); + } + + /* + * Create and open the file in the staging directory. + */ + error = create_stgfile(stage_dir, hanp, hlen, stgpath, &stg_fd); + if (error) + continue; + + /* + * Get the file's DMAPI change indicator so that we + * can tell if it changed (either via a data mod, or + * a DM attribute update) while we are staging it out + */ + error = get_dmchange(sid, hanp, hlen, DM_NO_TOKEN, + &change_start); + if (error) { + close(stg_fd); + continue; + } + + /* + * Write all the file's data to our file in the + * staging directory. In a real HSM, the data would + * be copied off to tertiary storage somewhere. + * + * The staging file descriptor will be closed for us + * in all cases. + */ + error = save_filedata(sid, hanp, hlen, stg_fd, fsize); + if (error) + continue; + + + /* + * Get exclusive access to the file so we can blow + * away its data + */ + error = lock_file(sid, hanp, hlen, DM_RIGHT_EXCL, &token); + if (error) { + err_msg("Can't get exclusive access to file, ignoring"); + continue; + } + + /* + * Make sure the file did not change + */ + error = get_dmchange(sid, hanp, hlen, token, &change_end); + if (error) { + unlock_file(sid, token); + continue; + } + if (change_start != change_end) { + unlock_file(sid, token); + err_msg("File changed during stageout, ignoring"); + continue; + } + + /* + * Save the location of the data (the staging file) + * in a private DM attribute so that we can get the + * file back in the future + */ + error = save_dataloc(sid, hanp, hlen, token, stgpath); + if (error) { + err_msg("Can't save location of file data"); + unlock_file(sid, token); + continue; + } + + + /* + * Set up the managed regions on the file so that + * a foray past the fencepost will cause an event to + * be generated. + */ + error = set_mrgns(sid, hanp, hlen, token, fsize, &off); + if (error) { + unlock_file(sid, token); + err_msg("Can't set managed regions"); + continue; + } + + /* + * Now we can safely blow away the data. + */ + error = mk_nonrez(sid, hanp, hlen, token, off); + if (error) { + clear_mrgns(sid, hanp, hlen, token); + } + + /* + * Unlock the file, which releases the token + */ + unlock_file(sid, token); + + } + + return(0); +} + + +/* + * Remove the data for a file + */ +int +mk_nonrez( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off) +{ + int error; + + error = dm_punch_hole(sid, hanp, hlen, token, off, 0); + if (error == -1) { + errno_msg("Can't punch hole in file, line=%d, errno=%d", __LINE__, errno); + return(1); + } + return(0); +} + + +/* + * Set up the managed regions on a file. We try to leave some of the + * file resident; the actual amount left on-disk is dependent + * on the rounding enforced by the DMAPI implementation. + */ +int +set_mrgns( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t fsize, + dm_off_t *start_off) +{ + dm_off_t rroff; + dm_size_t rlenp; + dm_region_t rgn; + u_int exact_flag; + int error; + + if (fsize > FENCEPOST_SIZE) { + error = dm_probe_hole(sid, hanp, hlen, token, FENCEPOST_SIZE, 0, + &rroff, &rlenp); + if (error == -1) { + errno_msg("Can't probe hole in file, line=%d, errno=%d", __LINE__, errno); + return(1); + } + } else { + rroff = 0; + } + *start_off = rroff; + + /* + * Now we know what the DMAPI and filesystem will support with + * respect to rounding of holes. We try to set our managed region + * to begin at this offset and continue to the end of the file. + * We set the event mask so that we'll trap on all events that + * occur in the managed region. + * + * Note that some implementations may not be able to support + * a managed region that starts someplace other than the beginning + * of the file. If we really cared, we could check the exact_flag. + */ + rgn.rg_offset = rroff; + rgn.rg_size = 0; + rgn.rg_flags = DM_REGION_READ | DM_REGION_WRITE | DM_REGION_TRUNCATE; + error = dm_set_region(sid, hanp, hlen, token, 1, &rgn, &exact_flag); + if (error == -1) { + errno_msg("Can't set managed region, line=%d, errno=%d", __LINE__, errno); + return(1); + } + return(0); +} + + +/* + * Clear a managed region on a file + */ +void +clear_mrgns( + dm_sessid_t sid, + void *hanp, + dm_size_t hlen, + dm_token_t token) +{ + dm_region_t rgn; + u_int exact_flag; + int error; + + rgn.rg_offset = 0; + rgn.rg_size = 0; + rgn.rg_flags = DM_REGION_NOEVENT; + error = dm_set_region(sid, hanp, hlen, token, 1, &rgn, &exact_flag); + if (error) + errno_msg("Can't clear managed regions from file, line=%d, errno=%d", __LINE__, errno); + + return; +} + + +/* + * File rights are accessed via a token. The token must be associated + * with a synchronous event message. So, to obtain either shared or + * exclusive rights to a file, we first associate a token with a message, + * and then request our desired right + */ +int +lock_file( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_right_t right, + dm_token_t *token) +{ + int error; + + error = dm_create_userevent(sid, (size_t)0, (void *)0, token); + if (error == -1) { + errno_msg("Can't create user event for token context, line=%d, errno=%d", __LINE__, errno); + return(1); + } + error = dm_request_right(sid, hanp, hlen, *token, DM_RR_WAIT, right); + if (error == -1) { + errno_msg("Can't get requested right for token, line=%d, errno=%d", __LINE__, errno); + return(1); + } + return(0); +} + + +/* + * Release the lock on a file + */ +void +unlock_file( + dm_sessid_t sid, + dm_token_t token) +{ + int error; + + error = dm_respond_event(sid, token, DM_RESP_CONTINUE, 0, 0, 0); + if (error == -1) + errno_msg("Can't respond to event and release token, line=%d, errno=%d", __LINE__, errno); + + return; +} + + +int +create_stgfile( + char *stage_dir, + void *hanp, + size_t hlen, + char *path, + int *stg_fd) +{ + char handle_str[HANDLE_STR]; + + if (hlen > HANDLE_LEN) { + err_msg("Handle length (%d) too long for file", hlen); + return(1); + } + + strcpy(path, stage_dir); + strcat(path, "/"); + hantoa(hanp, hlen, handle_str); + + /* + * Concat the ascii representation of the file handle + * (which is two times longer than the binary version) + * onto the staging path name + */ + strncat(path, (char *)handle_str, hlen*2); + + if ( (*stg_fd = open(path, O_RDWR | O_CREAT, 0644)) < 0) { + errno_msg("Can't open file %s, line=%d, errno=%d\n", path, __LINE__, errno); + return(1); + } + + return(0); +} + + +/* + * Extract the three fields from the input line. THe input is of + * the form + * filehandle length filehandle file size + * + * The length of the file handle is expected to be less than 64 bytes. + */ +int +extract_fields( + char *ibuf, + char *handle_buf, + size_t *hlen, + dm_size_t *fsize) +{ + char *cp, *start; + size_t len; + char *hanp; + + /* + * Skip any leading white space, and check the length + * of the file handle + */ + cp = ibuf; + while (!isalnum(*cp)) + cp++; + + start = cp; + while (isalnum(*cp)) + cp++; + *cp = '\0'; + + len = strtol(start, 0, 0); + if (len > HANDLE_LEN) { + err_msg("%s/%d: Handle length %d too long in input line", __FILE__, __LINE__, len); + return(1); + } + + *hlen = len; + + /* + * Skip over white space, and extract the file handle + */ + while (!isalnum(*cp)) + cp++; + hanp = cp; + + /* + * Skip over the ascii length of the file handle, and + * then extract the file's length + */ + cp += len*2; + *cp = '\0'; + + atohan( hanp, (void**)&handle_buf, &len ); + + + /* skip over white space */ + while (!isalnum(*cp)) + cp++; + + /* read file length */ + start = cp; + while (isalnum(*cp)) + cp++; + *cp = '\0'; + + *fsize = strtol(start, 0, 0); + + return(0); + +} + + +/* + * Save the location of the file's data so that we can find + * it again when we're staging the file back in. Rather than store + * the full pathname of the staging file, we just store the handle. + * This means the staging dir must be on a filesystem that supports + * the DMAPI. + */ +int +save_dataloc( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + char *stgpath) +{ + void *stg_hanp; + size_t stg_hlen; + int error; + dm_attrname_t hanp_attrname; + dm_attrname_t hlen_attrname; + + if (dm_path_to_handle(stgpath, &stg_hanp, &stg_hlen) == -1) { + errno_msg("Can't get handle for path %s, line=%d, errno=%d", stgpath, __LINE__, errno); + return(1); + } + + /* + * Since handles are in two parts, they become two attributes. + * This can be useful, since we can extract the length + * separately when we stage the file back in + */ + memcpy((void *)&hanp_attrname.an_chars[0], DLOC_HAN, DM_ATTR_NAME_SIZE); + error = dm_set_dmattr(sid, hanp, hlen, token, &hanp_attrname, + 0, stg_hlen, stg_hanp); + if (error == -1) { + errno_msg("Can't set DM attr of staging filehandle, line=%d, errno=%d",__LINE__, errno); + return(1); + } + + memcpy((void *)&hlen_attrname.an_chars[0], DLOC_HANLEN, DM_ATTR_NAME_SIZE); + error = dm_set_dmattr(sid, hanp, hlen, token, &hlen_attrname, + 0, sizeof(stg_hlen), (void *)&stg_hlen); + if (error == -1) { + errno_msg("Can't set DM attr of staging filehandle length, line=%d, errno=%d", __LINE__, errno); + return(1); + } + return(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/mls.c linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/mls.c --- linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/mls.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/mls.c Wed Mar 7 16:43:23 2001 @@ -0,0 +1,320 @@ +/* + * Simple util to print out DMAPI info about a file + * + * This code was written by Peter Lawthers, and placed in the public + * domain for use by DMAPI implementors and app writers. + * + * Standard disclaimer: + * THIS SOFTWARE IS PROVIDED ``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 +#include + +#include +#include +#include +#include + +#include + +#define MAX_RGNS 8 /* Arbitrary for this release */ +#define NUM_EXTENTS 4 + +extern char *optarg; +extern int optind, optopt, opterr; +char *Progname; + +void usage(char *); +int mr_info(dm_sessid_t, void *, size_t); +int alloc_info(dm_sessid_t, void *, size_t); +int event_info(dm_sessid_t, void *, size_t); +int handle_info(dm_sessid_t, void *, size_t); + +extern int setup_dmapi(dm_sessid_t *); +extern void errno_msg(char *, ...); +extern void print_handle(void *, size_t); + + +void +usage( + char *prog) +{ + fprintf(stderr, "Usage: %s filename \n ", prog); + fprintf(stderr, "\t-m managed region info\n"); + fprintf(stderr, "\t-a allocation info\n"); + fprintf(stderr, "\t-e event info\n"); + fprintf(stderr, "\t-h handle\n"); +} + + +int +main( + int argc, + char *argv[]) +{ + int c; + int error; + int mr_flag, alloc_flag, handle_flag, event_flag; + void *hanp; + size_t hlen; + char *filename; + dm_sessid_t sid; + + + Progname = argv[0]; + mr_flag = alloc_flag = handle_flag = event_flag = 0; + + while ((c = getopt(argc, argv, "maeh")) != EOF) { + switch (c) { + case 'm': + mr_flag = 1; + break; + case 'a': + alloc_flag = 1; + break; + case 'e': + event_flag = 1; + break; + case 'h': + handle_flag = 1; + break; + case '?': + default: + usage(Progname); + exit(1); + } + } + if (optind >= argc) { + usage(Progname); + exit(1); + } + filename = argv[optind]; + if (filename == NULL) { + usage(Progname); + exit(1); + } + + + /* + * Set up our link to the DMAPI, and get a handle for + * the file we want to query + */ + error = setup_dmapi(&sid); + if (error) + exit(1); + + if (dm_path_to_handle(filename, &hanp, &hlen) == -1) { + printf("Can't get handle for path %s", filename); + error = 1; + goto out; + } + + printf("File %s:\n", filename); + if (mr_flag) { + error = mr_info(sid, hanp, hlen); + if (error) { + error = 1; + goto out; + } + } + if (alloc_flag) { + error = alloc_info(sid, hanp, hlen); + if (error) { + error = 1; + goto out; + } + } + if (event_flag) { + error = event_info(sid, hanp, hlen); + if (error) { + error = 1; + goto out; + } + } + if (handle_flag) { + error = handle_info(sid, hanp, hlen); + if (error) { + error = 1; + goto out; + } + } + +out: + if (dm_destroy_session(sid)) { + errno_msg("Can't shut down session"); + error = 1; + } + + return(error); +} + +/* + * Get the complete list of all managed regions for a file. For now, + * we know that most implementations only support a small number of + * regions, so we don't handle the E2BIG error here. + */ +int +mr_info( + dm_sessid_t sid, + void *hanp, + size_t hlen) +{ + u_int i; + u_int ret; + dm_region_t rgn[MAX_RGNS]; + + memset((char *)&rgn, 0, (sizeof(dm_region_t) * MAX_RGNS)); + if (dm_get_region(sid, hanp, hlen, DM_NO_TOKEN, MAX_RGNS, rgn, &ret)) { + errno_msg("Can't get list of managed regions"); + return(1); + } + printf("\n"); + for (i=0; i +#include +#include +#include + +#include + +#include +#include + +extern char *optarg; +extern int optind, opterr, optopt; +extern int errno; + +int Verbose; +char *Progname; + +extern void err_msg(char *, ...); +extern void errno_msg(char *, ...); + +int get_sessions(dm_sessid_t **, u_int *); +int get_tokens(dm_sessid_t, dm_token_t **, u_int *); +void print_session(dm_sessid_t); +void print_tokens(dm_sessid_t); +void kill_session(dm_sessid_t); + +void +usage(char *s) +{ + fprintf(stderr, "Usage: %s \n", s); + fprintf(stderr, "\t-t list tokens\n"); + fprintf(stderr, "\t-l list sessions\n"); + fprintf(stderr, "\t-k kill sessions\n"); + fprintf(stderr, "\t-s \n"); + fprintf(stderr, "\t-v verbose (for kill)\n"); +} + +int +main( + int argc, + char *argv[]) +{ + int c; + int error; + u_int i, nsids; + int list_flag, kill_flag, token_flag, sid_flag; + dm_sessid_t *sidbuf, *sidp, onesid; + char *cp; + + + Progname = argv[0]; + list_flag = sid_flag = kill_flag = token_flag = 0; + + while ((c = getopt(argc, argv, "vlkts:")) != EOF) { + switch (c) { + case 'l': + list_flag = 1; + break; + case 'k': + kill_flag = 1; + break; + case 't': + token_flag = 1; + break; + case 's': + if (sscanf(optarg, "%d", &onesid) <=0 ) { + err_msg("Can't convert sid %s", optarg); + exit(2); + } + sid_flag = 1; + break; + case 'v': + Verbose = 1; + break; + case '?': + default: + usage(Progname); + exit(1); + } + } + if (!list_flag && !sid_flag && !kill_flag && !token_flag) { + usage(Progname); + exit(1); + } + + if (dm_init_service(&cp) == -1) { + err_msg("Can't init dmapi"); + return(1); + } + if (strcmp(cp, DM_VER_STR_CONTENTS)) { + err_msg("Compiled for a different version"); + return(1); + } + + + /* + * Get the list of all sessions in the system + */ + error = get_sessions(&sidbuf, &nsids); + if (error) + exit(1); + + /* + * Walk through the list of sessions do what is right + */ + sidp = sidbuf; + for (i=0; i +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#ifdef linux +#define MAXNAMELEN 256 +#endif + +extern int optind; +extern int errno; + +void usage (char *); +int main (int, char **); +void event_loop (dm_sessid_t, int); +int handle_message (dm_sessid_t, dm_eventmsg_t *); +static int format_mode(mode_t mode, char **ptr); +static int get_fs_handle (char *, void **, size_t *); +static int set_disposition(dm_sessid_t, void *, size_t); +static int set_events (dm_sessid_t, void *, size_t); +static int clear_events (dm_sessid_t, void *, size_t); +int finish_responding(dm_sessid_t); +int establish_handler(void); +void exit_handler (int); + +/* + * Keep these global so the exit_handler and err_msg routines can get to them + */ +char *Progname; +int Sleep = 0; +int Verbose; +dm_sessid_t sid = 0; +dm_sessid_t oldsid = 0; +char *fsname; + + +void +usage( + char *prog) +{ + fprintf(stderr, "Usage: %s ", prog); + fprintf(stderr, " <-S oldsid> <-v verbose> "); + fprintf(stderr, "filesystem \n"); +} + + +int +main( + int argc, + char *argv[]) +{ + + int c; + int error; + void *fs_hanp; + size_t fs_hlen; + + + Progname = argv[0]; + fsname = NULL; + + while ((c = getopt(argc, argv, "vs:S:")) != EOF) { + switch (c) { + case 's': + Sleep = atoi(optarg); + break; + case 'S': + oldsid = atoi(optarg); + break; + case 'v': + Verbose = 1; + break; + case '?': + default: + usage(Progname); + exit(1); + } + } + if (optind >= argc) { + usage(Progname); + exit(1); + } + fsname = argv[optind]; + if (fsname == NULL) { + usage(Progname); + exit(1); + } + + /* + * Establish an exit handler + */ + error = establish_handler(); + if (error) + exit(1); + + /* + * Init the dmapi, and get a filesystem handle so + * we can set up our events + */ + + if (oldsid) { + sid = oldsid; + } else { + error = setup_dmapi(&sid); + if (error) + exit(1); + } + + error = get_fs_handle(fsname, &fs_hanp, &fs_hlen); + if (error) + goto cleanup; + + /* + * Set the event disposition so that our session will receive + * all the events for the given file system + */ + error = set_disposition(sid, fs_hanp, fs_hlen); + if (error) + goto cleanup; + + /* + * Enable monitoring for all events in the given file system + */ + error = set_events(sid, fs_hanp, fs_hlen); + if (error) + goto cleanup; + + /* + * Now sit in an infinite loop, reporting on any events that occur. + * The program is exited after a signal through exit_handler(). + */ + printf("\n"); + event_loop(sid, 1 /*waitflag*/); + + /* + * If we get here, cleanup after the event_loop failure + */ + cleanup: + exit_handler(0); + return(1); +} + + +/* + * Main event loop processing + * + * The waitflag argument is set to 1 when we call this from main(). + * In this case, continuously process incoming events, + * blocking if there are none available. + * In the exit_handler(), call this routine with waitflag=0. + * Just try to read the events once in this case with no blocking. + */ +void +event_loop( + dm_sessid_t sid, + int waitflag) +{ + void *msgbuf; + size_t bufsize, rlen; + int error; + dm_eventmsg_t *msg; + int count; + + /* + * We take a swag at a buffer size. If it's wrong, we can + * always resize it + */ + bufsize = sizeof(dm_eventmsg_t) + sizeof(dm_data_event_t) + HANDLE_LEN; + bufsize *= 16; + msgbuf = (void *)malloc(bufsize); + if (msgbuf == NULL) { + err_msg("Can't allocate memory for buffer"); + goto out; + } + + for (;;) { + again: + error = dm_get_events(sid, ALL_AVAIL_MSGS, waitflag ? DM_EV_WAIT:0, + bufsize, msgbuf, &rlen); + if (error) { + if (errno == EAGAIN) { + if (waitflag) { + goto again; + } else { + goto out; + } + } + if (errno == E2BIG) { + free(msgbuf); + msgbuf = (void *)malloc(rlen); + if (msgbuf == NULL) { + err_msg("Can't resize msg buffer"); + goto out; + } + goto again; + } + errno_msg("Error getting events from DMAPI"); + goto out; + } + + /* + * Walk through the message buffer, pull out each individual + * message, and dispatch the messages to handle_message(), + * which will respond to the events. + */ + count = 0; + msg = (dm_eventmsg_t *)msgbuf; + while (msg != NULL ) { + + count++; + error = handle_message(sid, msg); + if (error) + goto out; + + msg = DM_STEP_TO_NEXT(msg, dm_eventmsg_t *); + } + if (count != 1 && Verbose) + err_msg("Found %d events in one call to dm_get_events\n", count); + } + + out: + if (msgbuf != NULL) + free(msgbuf); +} + + +/* + * First, weed out the events which return interesting structures. + * If it's not one of those, unpack the dm_namesp_event structure + * and display the contents. + */ +int +handle_message( + dm_sessid_t sid, + dm_eventmsg_t *msg) +{ + int pkt_error = 0; + int error; + dm_response_t response; + int respond, respcode; + dm_namesp_event_t *msg_ne; + void *hanp1, *hanp2, *namp1, *namp2; + u_int hlen1, hlen2, nlen1, nlen2; + char hans1[HANDLE_STR], hans2[HANDLE_STR]; + char nams1[MAXNAMELEN], nams2[MAXNAMELEN]; + char rooth[MAXNAMELEN]; + + /* + * Define some standard formats for the printf statements below. + */ + +#define HDR "%s: token %d sequence %d\n" +#define VALS "\t%-15s %s\n" +#define VALD "\t%-15s %d\n" +#define VALLLD "\t%-15s %lld\n" + + /* + * Set the defaults for responding to events + */ + respond = 1; + response = DM_RESP_CONTINUE; + respcode = 0; + + /***** USER EVENTS *****/ + + if (msg->ev_type == DM_EVENT_USER) { + char *privp; + u_int plen, i; + + printf(HDR, + "user", msg->ev_token, msg->ev_sequence); + + /* print private data as ascii or hex if it exists DM_CONFIG_MAX_MESSAGE_DATA */ + + privp = DM_GET_VALUE(msg, ev_data, char *); + plen = DM_GET_LEN (msg, ev_data); + if (plen) { + for (i = 0; i < plen; i++) { + if (!isprint(privp[i]) && !isspace(privp[i])) + break; + } + if (i == plen - 1 && privp[i] == '\0') { + printf(VALS, + "privdata", privp); + } else { + printf("\t%-15s ", "privdata"); + for (i = 0; i < plen; i++) { + printf("%.2x", privp[i]); + } + printf("\n"); + } + } else { + printf(VALS, + "privdata", ""); + } + + if (msg->ev_token == DM_INVALID_TOKEN) /* async dm_send_msg event */ + respond = 0; + } + + /***** CANCEL EVENT *****/ + +/* Not implemented on SGI or Veritas */ + + else if (msg->ev_type == DM_EVENT_CANCEL) { + dm_cancel_event_t *msg_ce; + + msg_ce = DM_GET_VALUE(msg, ev_data, dm_cancel_event_t *); + printf(HDR VALD VALD, + "cancel", msg->ev_token, msg->ev_sequence, + "sequence", msg_ce->ce_sequence, + "token", msg_ce->ce_token); + respond = 0; + } + + /***** DATA EVENTS *****/ + + else if (msg->ev_type == DM_EVENT_READ || + msg->ev_type == DM_EVENT_WRITE || + msg->ev_type == DM_EVENT_TRUNCATE) { + dm_data_event_t *msg_de; + + msg_de = DM_GET_VALUE(msg, ev_data, dm_data_event_t *); + hanp1 = DM_GET_VALUE(msg_de, de_handle, void *); + hlen1 = DM_GET_LEN (msg_de, de_handle); + if (hanp1 && hlen1) { + hantoa(hanp1, hlen1, hans1); + } else { + sprintf(hans1, "", hlen1); + } + + switch(msg->ev_type) { + + case DM_EVENT_READ: + printf(HDR VALS VALLLD VALLLD, + "read", msg->ev_token, msg->ev_sequence, + "file handle", hans1, + "offset", msg_de->de_offset, + "length", msg_de->de_length); + break; + + case DM_EVENT_WRITE: + printf(HDR VALS VALLLD VALLLD, + "write", msg->ev_token, msg->ev_sequence, + "file handle", hans1, + "offset", msg_de->de_offset, + "length", msg_de->de_length); + break; + + case DM_EVENT_TRUNCATE: + printf(HDR VALS VALLLD VALLLD, + "truncate", msg->ev_token, msg->ev_sequence, + "file handle", hans1, + "offset", msg_de->de_offset, + "length", msg_de->de_length); + break; + default: break; + } + } + + /***** DESTROY EVENT *****/ + + else if (msg->ev_type == DM_EVENT_DESTROY) { + dm_destroy_event_t *msg_ds; + char attrname[DM_ATTR_NAME_SIZE + 1]; + u_char *copy; + u_int clen; + u_int i; + + msg_ds= DM_GET_VALUE(msg, ev_data, dm_destroy_event_t *); + hanp1 = DM_GET_VALUE(msg_ds, ds_handle, void *); + hlen1 = DM_GET_LEN (msg_ds, ds_handle); + if (hanp1 && hlen1) { + hantoa(hanp1, hlen1, hans1); + } else { + sprintf(hans1, "", hlen1); + } + if (msg_ds->ds_attrname.an_chars[0] == '\0') { + strncpy(attrname, (char *)msg_ds->ds_attrname.an_chars, sizeof(attrname)); + } else { + strcpy(attrname, ""); + } + printf(HDR VALS VALS, + "destroy", msg->ev_token, msg->ev_sequence, + "handle", hans1, + "attrname", attrname); + copy = DM_GET_VALUE(msg_ds, ds_attrcopy, u_char *); + clen = DM_GET_LEN (msg_ds, ds_attrcopy); + if (copy && clen) { + printf("\t%-15s ", "attrcopy"); + for (i = 0; i < clen; i++) { + printf("%.2x", copy[i]); + } + printf("\n"); + } else { + printf(VALS, "attrcopy", ""); + } + respond = 0; + } + + /***** MOUNT EVENT *****/ + + else if (msg->ev_type == DM_EVENT_MOUNT) { + mode_t mode; + void *rootp; + u_int rlen; +#if !VERITAS_21 + dm_mount_event_t *msg_me; + + msg_me = DM_GET_VALUE(msg, ev_data, dm_mount_event_t *); + hanp1 = DM_GET_VALUE(msg_me, me_handle1, void *); + hlen1 = DM_GET_LEN (msg_me, me_handle1); + hanp2 = DM_GET_VALUE(msg_me, me_handle2, void *); + hlen2 = DM_GET_LEN (msg_me, me_handle2); + namp1 = DM_GET_VALUE(msg_me, me_name1, void *); + nlen1 = DM_GET_LEN (msg_me, me_name1); + namp2 = DM_GET_VALUE(msg_me, me_name2, void *); + nlen2 = DM_GET_LEN (msg_me, me_name2); + rootp = DM_GET_VALUE(msg_me, me_roothandle, void *); + rlen = DM_GET_LEN (msg_me, me_roothandle); + mode = msg_me->me_mode; + +#else /* VERITAS_21 */ + /* + * This is supposed to return the special dm_mount_event structure + * but SGI doesn't define it. Therefore, I'm guessing it returns a + * regular old namespace event. + */ + msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *); + hanp1 = DM_GET_VALUE(msg_ne, ne_handle1, void *); + hlen1 = DM_GET_LEN (msg_ne, ne_handle1); + hanp2 = DM_GET_VALUE(msg_ne, ne_handle2, void *); + hlen2 = DM_GET_LEN (msg_ne, ne_handle2); + namp1 = DM_GET_VALUE(msg_ne, ne_name1, void *); + nlen1 = DM_GET_LEN (msg_ne, ne_name1); + namp2 = DM_GET_VALUE(msg_ne, ne_name2, void *); + nlen2 = DM_GET_LEN (msg_ne, ne_name2); + rootp = NULL; + rlen = 0; + mode = msg_ne->ne_mode; +#endif /* ifdef VERITAS_21 */ + + if (hanp1 && hlen1) + hantoa(hanp1, hlen1, hans1); + if (hanp2 && hlen2) + hantoa(hanp2, hlen2, hans2); + if (namp1 && nlen1) { + strncpy(nams1, namp1, nlen1); + if (nlen1 != sizeof(nams1)) + nams1[nlen1] = '\0'; + } + if (namp2 && nlen2) { + strncpy(nams2, namp2, nlen2); + if (nlen2 != sizeof(nams2)) + nams2[nlen2] = '\0'; + } + if (rootp && rlen) + hantoa(rootp, rlen, rooth); + + printf(HDR VALS VALS VALS VALS VALS VALS, + "mount", msg->ev_token, msg->ev_sequence, + "fs handle", hans1, + "mtpt handle", hans2, + "mtpt path", nams1, + "media desig", nams2, + "mode", mode ? "RW" : "RDONLY", + "root handle", rooth); + } + + /***** NAMESPACE EVENTS *****/ + + else { + char *type; + + msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *); + hanp1 = DM_GET_VALUE(msg_ne, ne_handle1, void *); + hlen1 = DM_GET_LEN (msg_ne, ne_handle1); + hanp2 = DM_GET_VALUE(msg_ne, ne_handle2, void *); + hlen2 = DM_GET_LEN (msg_ne, ne_handle2); + namp1 = DM_GET_VALUE(msg_ne, ne_name1, void *); + nlen1 = DM_GET_LEN (msg_ne, ne_name1); + namp2 = DM_GET_VALUE(msg_ne, ne_name2, void *); + nlen2 = DM_GET_LEN (msg_ne, ne_name2); + + if (hanp1 && hlen1) { + hantoa(hanp1, hlen1, hans1); + } + if (hanp2 && hlen2) { + hantoa(hanp2, hlen2, hans2); + } + if (namp1 && nlen1) { + strncpy(nams1, namp1, nlen1); + if (nlen1 != sizeof(nams1)) + nams1[nlen1] = '\0'; + } + if (namp2 && nlen2) { + strncpy(nams2, namp2, nlen2); + if (nlen2 != sizeof(nams2)) + nams2[nlen2] = '\0'; + } + + if (msg->ev_type == DM_EVENT_PREUNMOUNT || + msg->ev_type == DM_EVENT_UNMOUNT) { + if (msg_ne->ne_mode == 0) { + type = "NOFORCE"; +#if !VERITAS_21 + } else if (msg_ne->ne_mode == DM_UNMOUNT_FORCE) { +#else + } else if (msg_ne->ne_mode > 0) { +#endif + type = "FORCE"; + } else { + type = "UNKNOWN"; + pkt_error++; + } + } else if (msg->ev_type == DM_EVENT_CREATE || + msg->ev_type == DM_EVENT_POSTCREATE || + msg->ev_type == DM_EVENT_REMOVE || + msg->ev_type == DM_EVENT_POSTREMOVE) { + if (format_mode(msg_ne->ne_mode, &type)) { + pkt_error++; + } + } + + switch(msg->ev_type) { + + case DM_EVENT_PREUNMOUNT: + printf(HDR VALS VALS VALS, + "preunmount", msg->ev_token, msg->ev_sequence, + "fs handle", hans1, + "root dir", hans2, + "unmount mode", type); + break; + + case DM_EVENT_UNMOUNT: + printf(HDR VALS VALS VALD, + "unmount", msg->ev_token, msg->ev_sequence, + "fs handle", hans1, + "unmount mode", type, + "retcode", msg_ne->ne_retcode); + break; + + case DM_EVENT_NOSPACE: + printf(HDR VALS, + "nospace", msg->ev_token, msg->ev_sequence, + "fs handle", hans1); + response = DM_RESP_ABORT; + respcode = ENOSPC; + break; + + case DM_EVENT_DEBUT: /* not supported on SGI */ + printf(HDR VALS, + "debut", msg->ev_token, msg->ev_sequence, + "object", hans1); + break; + + case DM_EVENT_CREATE: + printf(HDR VALS VALS VALS, + "create", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "mode bits", type); + break; + + case DM_EVENT_POSTCREATE: + printf(HDR VALS VALS VALS VALS VALD, + "postcreate", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "new object", hans2, + "name", nams1, + "mode bits", type, + "retcode", msg_ne->ne_retcode); + respond = 0; + break; + + case DM_EVENT_REMOVE: + printf(HDR VALS VALS VALS, + "remove", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "mode bits", type); + break; + + case DM_EVENT_POSTREMOVE: + printf(HDR VALS VALS VALS VALD, + "postremove", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "mode bits", type, + "retcode", msg_ne->ne_retcode); + respond = 0; + break; + + case DM_EVENT_RENAME: + printf(HDR VALS VALS VALS VALS, + "rename", msg->ev_token, msg->ev_sequence, + "old parent", hans1, + "new parent", hans2, + "old name", nams1, + "new name", nams2); + break; + + case DM_EVENT_POSTRENAME: + printf(HDR VALS VALS VALS VALS VALD, + "postrename", msg->ev_token, msg->ev_sequence, + "old parent", hans1, + "new parent", hans2, + "old name", nams1, + "new name", nams2, + "retcode", msg_ne->ne_retcode); + respond = 0; + break; + + case DM_EVENT_SYMLINK: + printf(HDR VALS VALS VALS, + "symlink", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "contents", nams2); + break; + + case DM_EVENT_POSTSYMLINK: + printf(HDR VALS VALS VALS VALS VALD, + "postsymlink", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "new object", hans2, + "name", nams1, + "contents", nams2, + "retcode", msg_ne->ne_retcode); + respond = 0; + break; + + case DM_EVENT_LINK: + printf(HDR VALS VALS VALS, + "link", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "source", hans2, + "name", nams1); + break; + + case DM_EVENT_POSTLINK: + printf(HDR VALS VALS VALS VALD, + "postlink", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "source", hans2, + "name", nams1, + "retcode", msg_ne->ne_retcode); + respond = 0; + break; + + case DM_EVENT_ATTRIBUTE: + printf(HDR VALS, + "attribute", msg->ev_token, msg->ev_sequence, + "object", hans1); + respond = 0; + break; + + case DM_EVENT_CLOSE: /* not supported on SGI */ + printf(HDR VALS, + "close", msg->ev_token, msg->ev_sequence, + "object", hans1); + respond = 0; + break; + + default: + pkt_error++; + printf(HDR VALD, + "", msg->ev_token, msg->ev_sequence, + "ev_type", msg->ev_type); + if (msg->ev_token == DM_INVALID_TOKEN) + respond = 0; + break; + } + } + + /* + * Now respond to those messages which require a response + */ + if (respond) { + if (Sleep) { + err_msg("Sleeping for %d seconds!\n", Sleep); + sleep(Sleep); + } + error = dm_respond_event(sid, msg->ev_token, response, respcode, 0, 0); + if (error) { + errno_msg("Can't respond to event"); + return error; + } + } + + return 0; +} + + +/* + Convert a mode_t field into a printable string. + + Returns non-zero if the mode_t is invalid. The string is + returned in *ptr, whether there is an error or not. +*/ + +static int +format_mode( + mode_t mode, + char **ptr) +{ +static char modestr[100]; + char *typestr; + int error = 0; + + if (S_ISFIFO(mode)) typestr = "FIFO"; + else if(S_ISCHR (mode)) typestr = "Character Device"; + else if(S_ISBLK (mode)) typestr = "Block Device"; + else if(S_ISDIR (mode)) typestr = "Directory"; + else if(S_ISREG (mode)) typestr = "Regular File"; + else if(S_ISLNK (mode)) typestr = "Symbolic Link"; + else if(S_ISSOCK(mode)) typestr = "Socket"; + else { + typestr = ""; + error++; + } + + sprintf(modestr, "mode %06o: perm %c%c%c %c%c%c %c%c%c %c%c%c, type %s", + mode, + mode & S_ISUID ? 's':' ', + mode & S_ISGID ? 'g':' ', + mode & S_ISVTX ? 't':' ', + mode & S_IRUSR ? 'r':'-', + mode & S_IWUSR ? 'w':'-', + mode & S_IXUSR ? 'x':'-', + mode & S_IRGRP ? 'r':'-', + mode & S_IWGRP ? 'w':'-', + mode & S_IXGRP ? 'x':'-', + mode & S_IROTH ? 'r':'-', + mode & S_IWOTH ? 'w':'-', + mode & S_IXOTH ? 'x':'-', + typestr); + *ptr = modestr; + return(error); +} + + +static int +get_fs_handle( + char *fsname, + void **fs_hanpp, + size_t *fs_hlenp) +{ + char hans[HANDLE_STR]; + + if (dm_path_to_fshandle(fsname, fs_hanpp, fs_hlenp) == -1) { + errno_msg("Can't get filesystem handle"); + return 1; + } + if (Verbose) { + hantoa(*fs_hanpp, *fs_hlenp, hans); + err_msg("File system handle for %s: %s\n", fsname, hans); + } + return 0; +} + + +/* + Set the event disposition for this filesystem to include all valid + DMAPI events so that we receive all events for this filesystem. + Also set DM_EVENT_MOUNT disposition for the global handle. + It does not make sense to specify DM_EVENT_USER in the disposition + mask since a session is always unconditionally registered for these + events. + + Returns non-zero on error. +*/ + +static int +set_disposition( + dm_sessid_t sid, + void *fs_hanp, + size_t fs_hlen) +{ + dm_eventset_t eventlist; + + if (Verbose) { + err_msg("Setting event disposition to send all " + "events to this session\n"); + } + + /* DM_EVENT_MOUNT must be sent in a separate request using the global + handle. If we ever support more than one filesystem at a time, this + request should be moved out of this routine to a place where it is + issued just once. + */ + + DMEV_ZERO(eventlist); + DMEV_SET(DM_EVENT_MOUNT, eventlist); + + if (dm_set_disp(sid, DM_GLOBAL_HANP, DM_GLOBAL_HLEN, DM_NO_TOKEN, + &eventlist, DM_EVENT_MAX) == -1) { + errno_msg("Can't set event disposition for mount"); + return(1); + } + + DMEV_ZERO(eventlist); + + /* File system administration events. */ + + DMEV_SET(DM_EVENT_PREUNMOUNT, eventlist); + DMEV_SET(DM_EVENT_UNMOUNT, eventlist); + DMEV_SET(DM_EVENT_NOSPACE, eventlist); + + /* While DM_EVENT_DEBUT is optional, it appears that the spec always + lets it be specified in a dm_set_disp call; its just that the + event will never be seen on some platforms. + */ + + DMEV_SET(DM_EVENT_DEBUT, eventlist); + + + /* Namespace events. */ + + DMEV_SET(DM_EVENT_CREATE, eventlist); + DMEV_SET(DM_EVENT_POSTCREATE, eventlist); + DMEV_SET(DM_EVENT_REMOVE, eventlist); + DMEV_SET(DM_EVENT_POSTREMOVE, eventlist); + DMEV_SET(DM_EVENT_RENAME, eventlist); + DMEV_SET(DM_EVENT_POSTRENAME, eventlist); + DMEV_SET(DM_EVENT_LINK, eventlist); + DMEV_SET(DM_EVENT_POSTLINK, eventlist); + DMEV_SET(DM_EVENT_SYMLINK, eventlist); + DMEV_SET(DM_EVENT_POSTSYMLINK, eventlist); + + /* Managed region data events. */ + + DMEV_SET(DM_EVENT_READ, eventlist); + DMEV_SET(DM_EVENT_WRITE, eventlist); + DMEV_SET(DM_EVENT_TRUNCATE, eventlist); + + /* Metadata events. */ + + DMEV_SET(DM_EVENT_ATTRIBUTE, eventlist); +#if ! defined ( __sgi ) && ! defined ( VERITAS_21 ) && !defined(linux) + DMEV_SET(DM_EVENT_CANCEL, eventlist); /* not supported on SGI */ +#endif +#if !defined(__sgi) && !defined(linux) + DMEV_SET(DM_EVENT_CLOSE, eventlist); /* not supported on SGI */ +#endif + DMEV_SET(DM_EVENT_DESTROY, eventlist); + + /* Pseudo-events. */ + + /* DM_EVENT_USER - always enabled - causes EINVAL if specified */ + + if (dm_set_disp(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, + &eventlist, DM_EVENT_MAX) == -1) { + errno_msg("Can't set event disposition for filesystem"); + return(1); + } + return(0); +} + + +/* + Enable event generation on each valid filesystem-based DMAPI event + within the given file system. + + Returns non-zero on errors. +*/ + +static int +set_events( + dm_sessid_t sid, + void *fs_hanp, + size_t fs_hlen) +{ + dm_eventset_t eventlist; + + if (Verbose) { + err_msg("Setting event list to enable all events " + "for this file system\n"); + } + DMEV_ZERO(eventlist); + + /* File system administration events. */ + + /* DM_EVENT_MOUNT - always enabled on the global handle - causes + EINVAL if specified. + */ + DMEV_SET(DM_EVENT_PREUNMOUNT, eventlist); + DMEV_SET(DM_EVENT_UNMOUNT, eventlist); + DMEV_SET(DM_EVENT_NOSPACE, eventlist); + /* DM_EVENT_DEBUT - always enabled - causes EINVAL if specified. */ + + /* Namespace events. */ + + DMEV_SET(DM_EVENT_CREATE, eventlist); + DMEV_SET(DM_EVENT_POSTCREATE, eventlist); + DMEV_SET(DM_EVENT_REMOVE, eventlist); + DMEV_SET(DM_EVENT_POSTREMOVE, eventlist); + DMEV_SET(DM_EVENT_RENAME, eventlist); + DMEV_SET(DM_EVENT_POSTRENAME, eventlist); + DMEV_SET(DM_EVENT_LINK, eventlist); + DMEV_SET(DM_EVENT_POSTLINK, eventlist); + DMEV_SET(DM_EVENT_SYMLINK, eventlist); + DMEV_SET(DM_EVENT_POSTSYMLINK, eventlist); + + /* Managed region data events. These are not settable by + dm_set_eventlist on a filesystem basis. They are meant + to be set using dm_set_region on regular files only. + However, in the SGI implementation, they are filesystem-settable. + Since this is useful for testing purposes, do it. + */ + + /* DM_EVENT_READ */ + /* DM_EVENT_WRITE */ + /* DM_EVENT_TRUNCATE */ + + /* Metadata events. */ + + DMEV_SET(DM_EVENT_ATTRIBUTE, eventlist); +#if ! defined ( __sgi ) && ! defined ( VERITAS_21 ) && !defined(linux) + DMEV_SET(DM_EVENT_CANCEL, eventlist); /* not supported on SGI */ +#endif +#if !defined(__sgi) && !defined(linux) + DMEV_SET(DM_EVENT_CLOSE, eventlist); /* not supported on SGI */ +#endif + DMEV_SET(DM_EVENT_DESTROY, eventlist); + + /* Pseudo-events. */ + + /* DM_EVENT_USER - always enabled - causes EINVAL if specified */ + + if (dm_set_eventlist(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, + &eventlist, DM_EVENT_MAX) == -1) { + errno_msg("Can't set event list"); + return(1); + } + return(0); +} + + +/* + Disable monitoring for all events in the DMAPI for the given + file system. This is done before exiting so that future + operations won't hang waiting for their events to be handled. + + Returns non-zero on errors. +*/ + +static int +clear_events( + dm_sessid_t sid, + void *fs_hanp, + size_t fs_hlen) +{ + dm_eventset_t eventlist; + + if (Verbose) { + err_msg("Clearing event list to disable all events " + "for this filesystem\n"); + } + DMEV_ZERO(eventlist); + + if (dm_set_eventlist(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, + &eventlist, DM_EVENT_MAX) == -1) { + errno_msg("Can't clear event list"); + return(1); + } + return(0); +} + + +/* + * Respond to any events which haven't been handled yet. + * dm_getall_tokens provides a list of tokens for the outstanding events. + * dm_find_eventmsg uses the token to lookup the corresponding message. + * The message is passed to handle_message() for normal response processing. + */ +int +finish_responding( + dm_sessid_t sid) +{ + int error = 0; + u_int nbytes, ntokens = 0, ret_ntokens, i; + dm_token_t *tokenbuf = NULL; + size_t buflen, ret_buflen; + char *msgbuf = NULL; + dm_eventmsg_t *msg; + + if (Verbose) + err_msg("Responding to any outstanding delivered event messages\n"); + + /* + * Initial sizes for the token and message buffers + */ + ret_buflen = 16 * (sizeof(dm_eventmsg_t) + sizeof(dm_data_event_t) + + HANDLE_LEN); + ret_ntokens = 16; + + /* + * The E2BIG dance... + * Take a guess at how large to make the buffer, starting with ret_ntokens. + * If the routine returns E2BIG, use the returned size and try again. + * If we're already using the returned size, double it and try again. + */ + do { + ntokens = (ntokens != ret_ntokens) ? ret_ntokens : ntokens*2; + nbytes = ntokens * (sizeof(dm_token_t) + sizeof(dm_vardata_t)); + tokenbuf = malloc(nbytes); + if (tokenbuf == NULL) { + err_msg("Can't malloc %d bytes for tokenbuf\n", nbytes); + error = 1; + goto out; + } + error = dm_getall_tokens(sid, ntokens, tokenbuf, &ret_ntokens); + } while (error && errno == E2BIG); + + if (error) { + errno_msg("Can't get all outstanding tokens"); + goto out; + } + + for (i = 0; i < ret_ntokens; i++) { + if (Verbose) + err_msg("Responding to outstanding event for token %d\n",(int)*tokenbuf); + + /* + * The E2BIG dance reprise... + */ + do { + buflen = (buflen != ret_buflen) ? ret_buflen : buflen * 2; + msgbuf = malloc(buflen); + if (msgbuf == NULL) { + err_msg("Can't malloc %d bytes for msgbuf\n", buflen); + error = 1; + goto out; + } + error = dm_find_eventmsg(sid, *tokenbuf, buflen, msgbuf, &ret_buflen); + } while (error && errno == E2BIG); + if (error) { + errno_msg("Can't find the event message for token %d", (int)*tokenbuf); + goto out; + } + + msg = (dm_eventmsg_t *) msgbuf; + while (msg != NULL) { + error = handle_message(sid, msg); + if (error) + goto out; + msg = DM_STEP_TO_NEXT(msg, dm_eventmsg_t *); + } + + tokenbuf++; + } + + out: + if (tokenbuf) + free(tokenbuf); + if (msgbuf) + free(msgbuf); + return error; +} + + +/* + * Establish an exit handler since we run in an infinite loop + */ +int +establish_handler(void) +{ + struct sigaction act; + + /* + * Set up signals so that we can wait for spawned children + */ + act.sa_handler = exit_handler; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + + (void)sigaction(SIGHUP, &act, NULL); + (void)sigaction(SIGINT, &act, NULL); + (void)sigaction(SIGQUIT, &act, NULL); + (void)sigaction(SIGTERM, &act, NULL); + (void)sigaction(SIGUSR1, &act, NULL); + (void)sigaction(SIGUSR1, &act, NULL); + (void)sigaction(SIGUSR2, &act, NULL); + + return(0); +} + + +/* + * Exit gracefully + * + * Stop events from being generated for the given file system + * Respond to any events that were delivered but unanswered + * (the event loop may have been in the middle of taking care of the event) + * Try getting any undelivered events but don't block if none are there + * (the file system may have generated an event after we killed dm_get_events) + * Shutdown the session using the global "sid" variable. + */ +void +exit_handler(int x) +{ + int error; + void *fs_hanp; + size_t fs_hlen; + + if (Verbose) + printf("\n"), + err_msg("Exiting...\n"); + + error = get_fs_handle(fsname, &fs_hanp, &fs_hlen); + + if (!error) { + error = clear_events(sid, fs_hanp, fs_hlen); + if (error) + /* just keep going */ ; + } + + error = finish_responding(sid); + if (error) + /* just keep going */ ; + + err_msg("Processing any undelivered event messages\n"); + event_loop(sid, 0 /*waitflag*/); + + err_msg("Shutting down the session\n"); + if (sid != 0) { + error = dm_destroy_session(sid); + if (error == -1) { + errno_msg("Can't shut down session - use 'mrmean -kv' to clean up!"); + } + } + + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/wbee.c linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/wbee.c --- linux-2.4.7/cmd/xfstests/dmapi/src/sample_hsm/wbee.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/sample_hsm/wbee.c Wed Mar 7 16:43:23 2001 @@ -0,0 +1,595 @@ +/* + * Worker bees. + * + * The bees perform the grunt work of handling a file event + * + * This code was written by Peter Lawthers, and placed in the public + * domain for use by DMAPI implementors and app writers. + * + * Standard disclaimer: + * THIS SOFTWARE IS PROVIDED ``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 +#include +#include + +#include +#include +#include +#include + +#include + +extern char *optarg; +extern int optind, optopt, opterr; +extern int errno; +char *Progname; +int Verbose; + +extern int restore_filedata(dm_sessid_t, void *, size_t, dm_token_t, + void *, size_t, dm_off_t); +extern int get_dmchange(dm_sessid_t, void *, size_t, dm_token_t, u_int *); +extern int setup_dmapi(dm_sessid_t *); +extern void err_msg(char *, ...); +extern void errno_msg(char *, ...); + +int stagein_file(dm_sessid_t, dm_token_t, dm_eventmsg_t *); +int inval_file(dm_sessid_t, dm_token_t, dm_eventmsg_t *); +int check_lockstate(dm_sessid_t, void *, size_t, dm_token_t); +int clear_mrgns(dm_sessid_t, void *, size_t, dm_token_t); +int find_msg(dm_sessid_t, dm_token_t, dm_eventmsg_t **); +int get_stghandle(dm_sessid_t, void *, size_t, dm_token_t, void **, + size_t *); +void usage(char *); + + + +void +usage( + char *prog) +{ + fprintf(stderr, "Usage: %s ", prog); + fprintf(stderr, " <-i invalidate file> "); + fprintf(stderr, " <-r restore file> "); + fprintf(stderr, "[-s sid] [-t token] \n"); +} + + +int +main( + int argc, + char *argv[]) +{ + + dm_eventmsg_t *msgheader; + char *sid_str, *token_str; + dm_sessid_t sid; + dm_token_t token; + int c; + int error; + int restore_flag, inval_flag; + char *cp; + + Progname = argv[0]; + sid_str = NULL; + token_str = NULL; + restore_flag = 0; + inval_flag = 0; + + while ((c = getopt(argc, argv, "s:t:ri")) != EOF) { + switch (c) { + case 'r': + restore_flag++; + break; + + case 'i': + inval_flag++; + break; + + case 's': + sid_str = optarg; + break; + + case 't': + token_str = optarg; + break; + + case '?': + default: + usage(Progname); + exit(1); + } + } + if (optind < argc) { + usage(Progname); + exit(1); + } + if (sid_str == NULL || token_str == NULL) { + usage(Progname); + exit(1); + } + if ((restore_flag > 0) && (inval_flag > 0)) { + usage(Progname); + exit(1); + } + + if (sscanf(sid_str, "%d", &sid) <= 0) { + err_msg("Can't convert sid"); + exit(1); + } + if (sscanf(token_str, "%d", &token) <= 0) { + err_msg("Can't convert token"); + exit(1); + } + + /* + * Now we have our session and token. We just need to + * let the DMAPI know we exist so we can use the interface. + * We don't need to create a session since we'll be using + * the session of our parent. + */ + error = dm_init_service(&cp); + if (error == -1) { + errno_msg("Can't init DMAPI"); + exit(1); + } + if (strcmp(cp, DM_VER_STR_CONTENTS)) { + err_msg("Compiled for a different version"); + exit(1); + } + + /* + * Find the message our caller wants us to handle + */ + error = find_msg(sid, token, &msgheader); + if (error) + exit(1); + + /* + * Now service the particular event type + */ + if (restore_flag) + error = stagein_file(sid, token, msgheader); + else + error = inval_file(sid, token, msgheader); + + return(error); +} + + +/* + * Find the data event message that correponds to the token. + * + * RETURNS: + * A pointer to malloc'd memory that contains the message + * we're supposed to handle in the 'msgheader' param. + */ +int +find_msg( + dm_sessid_t sid, + dm_token_t token, + dm_eventmsg_t **msgheader) +{ + void *buf; + size_t buflen, rlen; + int error; + + /* + * Malloc a buffer that we think is large enough for + * the common message header and the event specific part. + * If it's not large enough, we can always resize it. + */ + buflen = sizeof(dm_eventmsg_t) + sizeof(dm_data_event_t) + HANDLE_LEN; + buf = (void *)malloc(buflen); + if (buf == NULL) { + err_msg("Can't alloc memory for event buffer"); + return(1); + } + + error = dm_find_eventmsg(sid, token, buflen, buf, &rlen); + if (error == -1) { + if (errno != E2BIG) { + free(buf); + errno_msg("Can't obtain message from token"); + return(1); + } + free(buf); + buflen = rlen; + buf = (void *)malloc(buflen); + if (buf == NULL) { + err_msg("Can't resize event buffer"); + return(1); + } + error = dm_find_eventmsg(sid, token, buflen, buf, &rlen); + if (error == -1) { + errno_msg("Can't get message with resized buffer"); + return(1); + } + } + + *msgheader = (dm_eventmsg_t *)buf; + return(0); +} + + +/* + * Check the lock state associated with the file. If the token + * does not reference exclusive access, try to upgrade our lock. + * If we can't upgrade, drop the lock and start over + */ +int +check_lockstate( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ + int error; + dm_right_t right; + u_int change_start, change_end; + + error = dm_query_right(sid, hanp, hlen, token, &right); + if (error == -1) { + errno_msg("Can't query file access rights"); + return(1); + } +#if defined(__sgi) || defined(linux) + /* + * There are no access rights on the SGI. 1 means it's + * there. + */ + if (right == DM_RIGHT_SHARED) + return 0; +#endif + + if (right != DM_RIGHT_EXCL) { + error = dm_request_right(sid, hanp, hlen, token, 0, + DM_RIGHT_EXCL); + if (error == -1) { + if (errno != EAGAIN) { + errno_msg("Can't upgrade lock"); + return(1); + } + error = get_dmchange(sid, hanp, hlen, token, + &change_start); + if (error) + return(1); + + + error = dm_release_right(sid, hanp, hlen, token); + if (error == -1) { + errno_msg("Can't release file access rights"); + return(1); + } + error = dm_request_right(sid, hanp, hlen, token, + DM_RR_WAIT, DM_RIGHT_EXCL); + if (error == -1) { + errno_msg("Can't get exclusive right to file"); + return(1); + } + + /* + * If the file changed while we slept, then someone + * must have modified the file + */ + error = get_dmchange(sid, hanp, hlen, token, + &change_end); + if (error == -1) + return(1); + + if (change_start != change_end) { + err_msg("File changed while waiting for lock"); + return(1); + } + } + } + return(0); +} + + +/* + * Stage in the data for a file + */ +int +stagein_file( + dm_sessid_t sid, + dm_token_t token, + dm_eventmsg_t *msgheader) +{ + + void *stg_hanp, *hanp; + size_t stg_hlen, hlen; + int error, ret_errno; + dm_response_t reply; + dm_data_event_t *msg; + + /* + * Extract the event-specific info from the message header, + * then get the file handle. + */ + msg = DM_GET_VALUE(msgheader, ev_data, dm_data_event_t *); + hanp = DM_GET_VALUE(msg, de_handle, void *); + hlen = DM_GET_LEN(msg, de_handle); + + /* + * Check our permissions. We need exclusive access to the + * file to stage it back in. + */ + error = check_lockstate(sid, hanp, hlen, token); + if (error) + goto out; + + /* + * get the staging file handle from it's DM attributes + */ + stg_hanp = NULL; + error = get_stghandle(sid, hanp, hlen, token, &stg_hanp, &stg_hlen); + if (error) + goto out; + + /* + * We keep the exclusive lock held for the *entire* duration + * of the stagein. This is not required, but just quick and + * [sl]easy. For a large file, it is typically better to release + * the lock, and have a sliding window of managed regions to allow + * people to consume the data as it is being read in. + */ + error = restore_filedata(sid, hanp, hlen, token, stg_hanp, stg_hlen, + msg->de_offset); + if (error) + goto out; + + /* + * Now that the data is restored, and while we still have exclusive + * access to the file, clear the managed regions. + */ + error = clear_mrgns(sid, hanp, hlen, token); + if (error) + goto out; + +out: + if (stg_hanp) + free((char *)stg_hanp); + + /* + * Figure out what our response to the event will be. Once + * we've responded to the event, the token is no longer valid. + * On error, we pick the (less than helpful) errno EIO to signal + * to the user that something went wrong. + */ + if (error) { + reply = DM_RESP_ABORT; + ret_errno = EIO; + } else { + reply = DM_RESP_CONTINUE; + ret_errno = 0; + } + (void)dm_respond_event(sid, token, reply, ret_errno, 0, 0); + + return(ret_errno); + +} + +/* + * Turn off event monitoring for a file. In a real HSM, we would + * probably want to either invalidate the file's data on + * tertiary storage, or start some aging process so that it will + * eventually go away. + * + * The assumption is that for write and truncate events, the file + * data is about to be invalidated. + */ +int +inval_file( + dm_sessid_t sid, + dm_token_t token, + dm_eventmsg_t *msgheader) +{ + dm_data_event_t *msg; + void *hanp; + size_t hlen; + int error, ret_errno; + dm_response_t reply; + + /* + * Extract the event-specific info from the message header, + * then get the file handle. + */ + msg = DM_GET_VALUE(msgheader, ev_data, dm_data_event_t *); + hanp = DM_GET_VALUE(msg, de_handle, void *); + hlen = DM_GET_LEN(msg, de_handle); + + /* + * Check our permissions. We need exclusive access to the + * file to clear our managed regions. + */ + error = check_lockstate(sid, hanp, hlen, token); + if (error) + goto out; + + /* + * Clear all the managed regions for the file. + */ + error = clear_mrgns(sid, hanp, hlen, token); + +out: + /* + * Figure out what our response to the event will be. Once + * we've responded to the event, the token is no longer valid. + * On error, we pick the (less than helpful) errno EIO to signal + * to the user that something went wrong. + */ + if (error) { + reply = DM_RESP_ABORT; + ret_errno = EIO; + } else { + reply = DM_RESP_CONTINUE; + ret_errno = 0; + } + (void)dm_respond_event(sid, token, reply, ret_errno, 0, 0); + + return(ret_errno); +} + +/* + * Clear all of the managed regions for a file. + */ +int +clear_mrgns( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ + dm_region_t *rgn; + u_int nregions, nret; + u_int exact_flag; + int i; + int error, retval; + + /* + * We take a guess first and assume there is only one managed + * region per file. There should'nt be more than this, but + * it never hurts to check, since we want to make sure that + * all regions are turned off. + * + * The main purpose of this is to demonstrate the use of the + * E2BIG paradigm. + */ + retval = 1; + nregions = 1; + rgn = (dm_region_t *)malloc(nregions * sizeof(dm_region_t)); + if (rgn == NULL) { + err_msg("Can't allocate memory for region buffers"); + goto out; + } + + error = dm_get_region(sid, hanp, hlen, token, nregions, rgn, &nret); + if (error == -1) { + if (errno != E2BIG) { + errno_msg("Can't get list of managed regions for file"); + goto out; + } + + /* + * Now we know how many managed regions there are, so we can + * resize our buffer + */ + nregions = nret; + free(rgn); + rgn = (dm_region_t *)malloc(nregions * sizeof(dm_region_t)); + if (rgn == NULL) { + err_msg("Can't resize region buffers"); + goto out; + } + error = dm_get_region(sid, hanp, hlen, token, nregions, rgn, + &nret); + if (error == -1) { + errno_msg("Can't get list of managed regions for file"); + goto out; + } + } + + /* + * Clear all the managed regions + */ + for (i=0; irg_offset = 0; + rgn->rg_size = 0; + rgn->rg_flags = DM_REGION_NOEVENT; + rgn++; + } + error = dm_set_region(sid, hanp, hlen, token, nregions, rgn, + &exact_flag); + if (error == -1) { + errno_msg("Can't clear list of managed regions for file"); + } + retval = 0; + +out: + if (rgn != NULL) + free(rgn); + + return(retval); +} + + +/* + * Extract the staging file handle from a file's DM attributes + */ +int +get_stghandle( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + void **stg_hanp, + size_t *stg_hlen) +{ + void *han_buf; + size_t han_len; + int error; + size_t rlen; + dm_attrname_t hanp_attrname; + dm_attrname_t hlen_attrname; + + /* + * First get the length of the file handle, so we + * can size our buffer correctly + */ + memcpy((void *)&hlen_attrname.an_chars[0], DLOC_HANLEN, DM_ATTR_NAME_SIZE); + error = dm_get_dmattr(sid, hanp, hlen, token, &hlen_attrname, + sizeof(size_t), &han_len, &rlen); + if (error == -1) { + /* + * On any error, even E2BIG, we bail since the size of + * the file handle should be a constant + */ + errno_msg("Can't get size of staging file handle"); + return(1); + } + if (rlen != sizeof(size_t)) { + err_msg("File handle length component incorrect"); + return(1); + } + + /* + * Malloc space for our staging file handle, and + * extract it from our DM attributes + */ + han_buf = (void *)malloc(han_len); + if (han_buf == NULL) { + err_msg("Can't alloc memory for file handle"); + return(1); + } + + memcpy((void *)&hanp_attrname.an_chars[0], DLOC_HAN, DM_ATTR_NAME_SIZE); + error = dm_get_dmattr(sid, hanp, hlen, token, &hanp_attrname, + han_len, han_buf, &rlen); + if (error == -1) { + errno_msg("Can't get staging file handle"); + free(han_buf); + return(1); + } + if (rlen != han_len) { + err_msg("File handle is incorrect length"); + free(han_buf); + return(1); + } + *stg_hanp = han_buf; + *stg_hlen = han_len; + return(0); +} + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/simple/CVS/Entries linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/CVS/Entries --- linux-2.4.7/cmd/xfstests/dmapi/src/simple/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/CVS/Entries Thu Jul 5 11:45:53 2001 @@ -0,0 +1,8 @@ +/Makefile/1.1/Wed Mar 7 22:43:23 2001/-ko/ +/dm_create_session.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/dm_destroy_session.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/dm_find_eventmsg.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/dm_getall_sessions.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/dm_getall_tokens.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/dm_query_session.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/simple/CVS/Repository linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/CVS/Repository --- linux-2.4.7/cmd/xfstests/dmapi/src/simple/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/CVS/Repository Thu Jul 5 11:45:53 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/dmapi/src/simple diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/simple/CVS/Root linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/CVS/Root --- linux-2.4.7/cmd/xfstests/dmapi/src/simple/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/CVS/Root Thu Jul 5 11:45:53 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/simple/Makefile linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/Makefile --- linux-2.4.7/cmd/xfstests/dmapi/src/simple/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/Makefile Wed Mar 7 16:43:23 2001 @@ -0,0 +1,48 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../../.. +include $(TOPDIR)/include/builddefs + +TARGETS = dm_create_session dm_destroy_session dm_find_eventmsg \ + dm_getall_sessions dm_getall_tokens dm_query_session +CFILES = $(TARGETS:=.c) +LDIRT = $(TARGETS) + +default: $(TARGETS) + +include $(BUILDRULES) + +CPPFLAGS = -I $(TOPDIR)/dmapi/src/common -I /usr/include/xfs + +LDLIBS = -ldm -lhandle +LDFLAGS += -L $(TOPDIR)/dmapi/src/common/lib diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/simple/dm_create_session.c linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/dm_create_session.c --- linux-2.4.7/cmd/xfstests/dmapi/src/simple/dm_create_session.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/dm_create_session.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#include +#include +#include +#include +#ifdef linux +#include +#else +#include +#endif + +int +main( int argc, char **argv ) +{ + extern char *optarg; + int c; + int ret; + dm_sessid_t oldsid = DM_NO_SESSION; + dm_sessid_t newsid = 0; + char *sessinfo = "test1"; + char *versionstr; + + while( (c = getopt(argc, argv, "hs:i:")) != -1 ) { + switch(c){ + case 's': + oldsid = atoi( optarg ); + break; + case 'i': + sessinfo = optarg; + break; + case 'h': + fprintf(stderr, "Usage: %s [-s oldsid] [-i sessinfo_txt]\n", argv[0]); + exit(2); + } + } + + if( dm_init_service( &versionstr ) < 0 ) + exit(1); + + ret = dm_create_session( oldsid, sessinfo, &newsid); + printf( "ret=%d\n", ret ); + printf( "newsid=%d\n", newsid ); + exit(0); +} + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/simple/dm_destroy_session.c linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/dm_destroy_session.c --- linux-2.4.7/cmd/xfstests/dmapi/src/simple/dm_destroy_session.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/dm_destroy_session.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#include +#include +#include +#include +#ifdef linux +#include +#else +#include +#endif + +int +main( int argc, char **argv ) +{ + extern char *optarg; + int c; + int ret; + dm_sessid_t sid = 0; + char *versionstr; + + while( (c = getopt(argc, argv, "hs:")) != -1 ) { + switch(c){ + case 's': + sid = atoi( optarg ); + break; + case 'h': + fprintf(stderr, "Usage: %s <-s sid>\n", argv[0] ); + exit(2); + } + } + + if( sid == 0 ){ + fprintf(stderr, "%s: must specify -s\n", argv[0] ); + exit(1); + } + + if( dm_init_service( &versionstr ) < 0 ) + exit(1); + + ret = dm_destroy_session( sid ); + printf( "ret=%d\n", ret ); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/simple/dm_find_eventmsg.c linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/dm_find_eventmsg.c --- linux-2.4.7/cmd/xfstests/dmapi/src/simple/dm_find_eventmsg.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/dm_find_eventmsg.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#include +#include +#include +#include +#ifdef linux +#include +#else +#include +#endif + +int +main( int argc, char **argv ) +{ + extern char *optarg; + int c; + int ret; + dm_sessid_t sid = 0; + dm_token_t token = 0; + dm_eventmsg_t msg; + size_t rlen; + int buflen = sizeof(dm_eventmsg_t) + 100; + char *versionstr; + + while( (c = getopt(argc, argv, "hs:t:l:q")) != -1 ) { + switch(c){ + case 's': + sid = atoi( optarg ); + break; + case 't': + token = atoi( optarg ); + break; + case 'l': + buflen = atoi( optarg ); + break; + case 'q': + printf("dm_eventmsg_t=%d\n", sizeof(dm_eventmsg_t) ); + exit(0); + case 'h': + fprintf(stderr, "Usage: %s <-s sid> <-t token> [-l buflen]\n", argv[0]); + fprintf(stderr, " %s -q\n", argv[0]); + exit(2); + } + } + + if( sid == 0 ){ + fprintf(stderr, "%s: must specify -s\n", argv[0] ); + exit(1); + } + + if( token == 0 ){ + fprintf(stderr, "%s: must specify -t\n", argv[0] ); + exit(1); + } + + if( dm_init_service( &versionstr ) < 0 ) + exit(1); + + ret = dm_find_eventmsg( sid, token, buflen, &msg, &rlen ); + printf( "ret=%d\n", ret ); + printf( "rlen=%d\n", rlen ); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/simple/dm_getall_sessions.c linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/dm_getall_sessions.c --- linux-2.4.7/cmd/xfstests/dmapi/src/simple/dm_getall_sessions.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/dm_getall_sessions.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#include +#include +#include +#include +#include +#include +#ifdef linux +#include +#else +#include +#endif + +int +main( int argc, char **argv ) +{ + extern char *optarg; + int c; + int ret; + dm_sessid_t *sidbuf; + u_int nelem = 100; + u_int rnelem = 0; + int i; + char *versionstr; + int anyway = 0; /* attempt to show this many elements anyway, + * even if it looks like nothing was returned. + */ + + while( (c = getopt(argc, argv, "hn:x:")) != -1 ) { + switch(c){ + case 'n': + nelem = atoi( optarg ); + break; + case 'x': + anyway = atoi( optarg ); + break; + case 'h': + fprintf(stderr, "Usage: %s [-n nelem]\n", argv[0]); + exit(2); + } + } + + if( (sidbuf = malloc( sizeof(*sidbuf) * nelem )) == NULL ){ + fprintf(stderr, "%s: malloc failed\n", argv[0] ); + exit(1); + } + + memset( sidbuf, 0, sizeof(*sidbuf) * nelem ); + + if( dm_init_service( &versionstr ) < 0 ) + exit(1); + + ret = dm_getall_sessions( nelem, sidbuf, &rnelem ); + printf( "ret=%d\n", ret ); + printf( "rnelem=%d\n", rnelem ); + + /* user wants us to try to show a specific number of elements */ + if( anyway > 0 ) + rnelem = anyway; + + printf("sids=\""); + for( i = 0; i < rnelem; i++ ){ + printf("%d ", sidbuf[i]); + } + printf("\"\n"); + exit(0); +} + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/simple/dm_getall_tokens.c linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/dm_getall_tokens.c --- linux-2.4.7/cmd/xfstests/dmapi/src/simple/dm_getall_tokens.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/dm_getall_tokens.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#include +#include +#include +#include +#include +#ifdef linux +#include +#else +#include +#endif + +int +main( int argc, char **argv ) +{ + extern char *optarg; + int c; + int ret; + dm_token_t *tokenbuf; + u_int nelem = 100; + u_int rnelem = 0; + dm_sessid_t sid = 0; + int i; + char *versionstr; + + while( (c = getopt(argc, argv, "hs:n:")) != -1 ) { + switch(c){ + case 's': + sid = atoi( optarg ); + break; + case 'n': + nelem = atoi( optarg ); + break; + case 'h': + fprintf(stderr, "Usage: %s <-s sid> [-n nelem]\n", argv[0]); + exit(2); + } + } + + if( sid == 0 ){ + fprintf(stderr, "%s: must specify -s\n", argv[0] ); + exit(1); + } + + if( (tokenbuf = malloc( sizeof(dm_token_t) * nelem )) == NULL ){ + fprintf(stderr, "%s: malloc failed\n", argv[0] ); + exit(1); + } + + if( dm_init_service( &versionstr ) < 0 ) + exit(1); + + ret = dm_getall_tokens( sid, nelem, tokenbuf, &rnelem ); + printf( "ret=%d\n", ret ); + printf( "rnelem=%d\n", rnelem ); + + printf("tokens=\""); + for( i = 0; i < rnelem; i++ ){ + printf("%d ", (int)(tokenbuf+i)); + } + printf("\"\n"); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/simple/dm_query_session.c linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/dm_query_session.c --- linux-2.4.7/cmd/xfstests/dmapi/src/simple/dm_query_session.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/simple/dm_query_session.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#include +#include +#include +#include +#ifdef linux +#include +#else +#include +#endif + +int +main( int argc, char **argv ) +{ + extern char *optarg; + int c; + int ret; + char *sessinfo; + size_t rlen = 0; + dm_sessid_t sid = 0; + int buflen = 100; + char *versionstr; + + while( (c = getopt(argc, argv, "hs:l:")) != -1 ) { + switch(c){ + case 's': + sid = atoi( optarg ); + break; + case 'l': + buflen = atoi( optarg ); + break; + case 'h': + fprintf(stderr, "Usage: %s <-s sid> [-l buflen]\n", argv[0]); + exit(2); + } + } + + if( sid == 0 ){ + fprintf(stderr, "%s: must specify -s\n", argv[0] ); + exit(1); + } + + if( (sessinfo = malloc( sizeof(char*) * buflen )) == NULL ){ + fprintf(stderr, "%s: malloc failed\n", argv[0] ); + exit(1); + } + + if( dm_init_service( &versionstr ) < 0 ) + exit(1); + + ret = dm_query_session( sid, buflen, sessinfo, &rlen ); + printf( "ret=%d\n", ret ); + printf( "rlen=%d\n", rlen ); + if( ret != -1 ) + printf( "sessinfo=%s\n", sessinfo ); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/CVS/Entries linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/CVS/Entries --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/CVS/Entries Thu Jul 5 11:45:53 2001 @@ -0,0 +1,2 @@ +/function_coverage/1.1/Wed Jan 17 01:24:14 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/CVS/Entries.Log linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/CVS/Entries.Log --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/CVS/Entries.Log Thu Jul 5 11:45:53 2001 @@ -0,0 +1 @@ +A D/cmd//// diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/CVS/Repository linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/CVS/Repository --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/CVS/Repository Thu Jul 5 11:45:53 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1 diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/CVS/Root linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/CVS/Root --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/CVS/Root Thu Jul 5 11:45:53 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/CVS/Entries linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/CVS/Entries --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/CVS/Entries Thu Jul 5 11:45:56 2001 @@ -0,0 +1,50 @@ +/Makefile/1.1/Wed Mar 7 22:43:23 2001/-ko/ +/create_userevent.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/dm_handle.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/downgrade_right.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/fd_to_handle.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/get_allocinfo.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/get_config_events.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/get_dirattrs.c/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/get_dmattr.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/get_eventlist.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/get_events.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/get_fileattr.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/get_mountinfo.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/get_region.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/getall_disp.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/getall_dmattr.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/handle_to_fshandle.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/handle_to_path.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/init_service.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/link_test.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/make_rt_sparse.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/make_sparse.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/obj_ref_hold.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/obj_ref_query.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/obj_ref_rele.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/path_to_fshandle.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/path_to_handle.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/pending.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/print_event.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/print_fshandle.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/probe_hole.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/punch_hole.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/query_right.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/randomize_file.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/release_right.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/remove_dmattr.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/request_right.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/respond_event.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/rwt.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/security_hole.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/security_hole2.c/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/set_disp.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/set_dmattr.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/set_eventlist.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/set_fileattr.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/struct_test.c/1.3/Thu Mar 8 17:52:41 2001/-ko/ +/sync_by_handle.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/test_assumption.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +/upgrade_right.c/1.2/Thu Mar 8 17:52:41 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/CVS/Repository linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/CVS/Repository --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/CVS/Repository Thu Jul 5 11:45:53 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/CVS/Root linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/CVS/Root --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/CVS/Root Thu Jul 5 11:45:53 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/Makefile linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/Makefile --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/Makefile Wed Mar 7 16:43:23 2001 @@ -0,0 +1,102 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = ../../../.. +include $(TOPDIR)/include/builddefs + +# things needing -ldm -lhandle -ldmtest +DM_TARGS = \ + test_assumption \ + get_eventlist \ + set_eventlist \ + set_disp \ + get_region \ + get_dmattr \ + set_dmattr \ + remove_dmattr \ + probe_hole \ + punch_hole \ + get_fileattr \ + sync_by_handle \ + getall_dmattr \ + set_fileattr \ + path_to_handle \ + path_to_fshandle \ + get_mountinfo \ + getall_disp \ + get_events \ + dm_handle \ + handle_to_fshandle \ + get_config_events \ + get_allocinfo \ + create_userevent \ + request_right \ + release_right \ + upgrade_right \ + query_right \ + downgrade_right \ + obj_ref_hold \ + obj_ref_rele \ + obj_ref_query \ + print_event + +# things needing -ldm -lhandle +NT_TARGS = \ + fd_to_handle \ + handle_to_path \ + init_service \ + pending \ + print_fshandle \ + respond_event + +# things needing -ldm -ldmtest +NTDM_TARGS = \ + make_sparse \ + randomize_file \ + rwt \ + struct_test + + +TARGETS = $(DM_TARGS) $(NT_TARGS) $(NTDM_TARGS) link_test + +CFILES = $(TARGETS:=.c) +LDIRT = $(TARGETS) + +default: $(TARGETS) + +include $(BUILDRULES) + +CPPFLAGS = -I $(TOPDIR)/dmapi/src/common -I /usr/include/xfs + +LDLIBS = -ldm -lhandle -ldmtest +LDFLAGS += -L $(TOPDIR)/dmapi/src/common/lib + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/create_userevent.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/create_userevent.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/create_userevent.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/create_userevent.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function create_userevent(). The +command line is: + + create_userevent [-s sid] string + +where string is the msgdata to be stored in the event. +sid is the session ID to use for the event. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-s sid] string\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *string; + dm_token_t token; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "s:")) != EOF) { + switch (opt) { + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + string = argv[optind++]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + if (dm_create_userevent(sid, strlen(string)+ 1, string, &token)) { + fprintf(stderr, "dm_create_userevent failed, %s\n", + strerror(errno)); + exit(1); + } + + fprintf(stdout, "New token %d\n", token); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/dm_handle.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/dm_handle.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/dm_handle.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/dm_handle.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include + +#include + +#include + +/*--------------------------------------------------------------------------- + +Test program used to test all the DMAPI functions in dm_handle.c. The +command line is: + + dm_handle pathname + +where pathname is the name of a file. If any function fails, an error message +containing the work ERROR will be written to stderr. + +Tested DMAPI functions are: + dm_fd_to_handle + dm_handle_cmp + dm_handle_free + dm_handle_hash + dm_handle_is_valid + dm_handle_to_fshandle + dm_handle_to_fsid + dm_handle_to_ino + dm_handle_to_igen + dm_make_handle + dm_make_fshandle + dm_path_to_handle + dm_path_to_fshandle + +----------------------------------------------------------------------------*/ + + +char *Progname; + + + +int +main( + int argc, + char **argv) +{ + char *pathname; + char *name; + void *hanp1, *hanp2, *hanp3, *fshanp1, *fshanp2, *fshanp3; + size_t hlen1, hlen2, hlen3, fshlen1, fshlen2, fshlen3; + u_int hash1, hash2, hash3, fshash1, fshash2, fshash3; + dm_fsid_t fsid; + dm_ino_t ino; + dm_igen_t igen; + char buffer[100]; + char buffer1[100]; + char fsbuffer1[100]; + char buffer2[100]; + char fsbuffer2[100]; + char buffer3[100]; + char fsbuffer3[100]; + int fd; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + if (argc != 2) { + fprintf(stderr, "usage: %s path\n", argv[0]); + exit(1); + } + pathname = argv[1]; + + (void)dm_init_service(&name); + + if (dm_path_to_handle(pathname, &hanp1, &hlen1) != 0) { + fprintf(stderr, "dm_path_to_handle failed, %s\n", + strerror(errno)); + exit(1); + } + hash1 = dm_handle_hash(hanp1, hlen1); + hantoa(hanp1, hlen1, buffer1); + fprintf(stdout, " han1: hash %u value %s (dm_path_to_handle)\n", + hash1, buffer1); + if (dm_handle_is_valid(hanp1, hlen1) == DM_FALSE) { + fprintf(stderr, "ERROR: han1 is not valid\n"); + } + + if (dm_path_to_fshandle(pathname, &fshanp1, &fshlen1) != 0) { + fprintf(stderr, "dm_path_to_fshandle failed, %s\n", + strerror(errno)); + exit(1); + } + fshash1 = dm_handle_hash(fshanp1, fshlen1); + hantoa(fshanp1, fshlen1, fsbuffer1); + fprintf(stdout, "fshan1: hash %u value %s (dm_path_to_fshandle\n", + fshash1, fsbuffer1); + if (dm_handle_is_valid(fshanp1, fshlen1) == DM_FALSE) { + fprintf(stderr, "ERROR: fshan1 is not valid\n"); + } + + if ((fd = open(pathname, O_RDONLY)) < 0) { + fprintf(stderr, "open of %s failed, %s\n", pathname, + strerror(errno)); + exit(1); + } + if (dm_fd_to_handle(fd, &hanp2, &hlen2) != 0) { + fprintf(stderr, "dm_fd_to_handle failed, %s\n", + strerror(errno)); + exit(1); + } + (void)close(fd); + hash2 = dm_handle_hash(hanp2, hlen2); + hantoa(hanp2, hlen2, buffer2); + fprintf(stdout, " han2: hash %u value %s (dm_fd_to_handle)\n", + hash2, buffer2); + if (dm_handle_is_valid(hanp2, hlen2) == DM_FALSE) { + fprintf(stderr, "ERROR: han2 is not valid\n"); + } + + if (dm_handle_to_fshandle(hanp2, hlen2, &fshanp2, &fshlen2) != 0) { + fprintf(stderr, "dm_handle_to_fshandle failed, %s\n", + strerror(errno)); + exit(1); + } + fshash2 = dm_handle_hash(fshanp2, fshlen2); + hantoa(fshanp2, fshlen2, fsbuffer2); + fprintf(stdout, "fshan2: hash %u value %s (dm_handle_to_fshandle)\n", + fshash2, fsbuffer2); + if (dm_handle_is_valid(fshanp2, fshlen2) == DM_FALSE) { + fprintf(stderr, "ERROR: fshan2 is not valid\n"); + } + + if (dm_handle_cmp(hanp1, hlen1, hanp2, hlen2)) { + fprintf(stderr, "ERROR: han1 and han2 differ in dm_handle_cmp\n"); + } + if (strcmp(buffer1, buffer2)) { + fprintf(stderr, "ERROR: han1 and han2 differ in strcmp\n"); + } + if (hash1 != hash2) { + fprintf(stderr, "ERROR: hash1 and hash2 differ\n"); + } + + if (dm_handle_cmp(fshanp1, fshlen1, fshanp2, fshlen2)) { + fprintf(stderr, "ERROR: fshan1 and fshan2 differ in dm_handle_cmp\n"); + } + if (strcmp(fsbuffer1, fsbuffer2)) { + fprintf(stderr, "ERROR: fshan1 and fshan2 differ in strcmp\n"); + } + if (fshash1 != fshash2) { + fprintf(stderr, "ERROR: fshash1 and fshash2 differ\n"); + } + + /* Break the handle into its component parts and display them. Use + hantoa() instead of printing the parts directly because some are + 32 bits on Veritas and 64 bits on SGI. + */ + + if (dm_handle_to_fsid(hanp1, hlen1, &fsid) != 0) { + fprintf(stderr, "dm_handle_to_fsid failed, %s\n", + strerror(errno)); + exit(1); + } + hantoa(&fsid, sizeof(fsid), buffer); + fprintf(stdout, "fsid %s (dm_handle_to_fsid)\n", buffer); + + if (dm_handle_to_ino(hanp1, hlen1, &ino) != 0) { + fprintf(stderr, "dm_handle_to_ino failed, %s\n", + strerror(errno)); + exit(1); + } + hantoa(&ino, sizeof(ino), buffer); + fprintf(stdout, "ino %s (dm_handle_to_ino)\n", buffer); + + if (dm_handle_to_igen(hanp1, hlen1, &igen) != 0) { + fprintf(stderr, "dm_handle_to_igen failed, %s\n", + strerror(errno)); + exit(1); + } + hantoa(&igen, sizeof(igen), buffer); + fprintf(stdout, "igen %s (dm_handle_to_igen)\n", buffer); + + /* Now use the parts to remake the handle and verify we get the same + answer. + */ + + if (dm_make_handle(&fsid, &ino, &igen, &hanp3, &hlen3) != 0) { + fprintf(stderr, "dm_make_handle failed, %s\n", + strerror(errno)); + exit(1); + } + hash3 = dm_handle_hash(hanp3, hlen3); + hantoa(hanp3, hlen3, buffer3); + fprintf(stdout, " han3: hash %u value %s (dm_make_handle)\n", + hash3, buffer3); + if (dm_handle_is_valid(hanp3, hlen3) == DM_FALSE) { + fprintf(stderr, "ERROR: han3 is not valid\n"); + } + + if (dm_handle_cmp(hanp1, hlen1, hanp3, hlen3)) { + fprintf(stderr, "ERROR: hanp1 and hanp3 differ in dm_handle_cmp\n"); + } + if (strcmp(buffer1, buffer3)) { + fprintf(stderr, "ERROR: hanp1 and hanp3 differ in strcmp\n"); + } + if (hash1 != hash3) { + fprintf(stderr, "ERROR: hash1 and hash3 differ\n"); + } + + if (dm_make_fshandle(&fsid, &fshanp3, &fshlen3) != 0) { + fprintf(stderr, "dm_make_fshandle failed, %s\n", + strerror(errno)); + exit(1); + } + fshash3 = dm_handle_hash(fshanp3, fshlen3); + hantoa(fshanp3, fshlen3, fsbuffer3); + fprintf(stdout, "fshan3: hash %u value %s (dm_make_fshandle)\n", + fshash3, fsbuffer3); + if (dm_handle_is_valid(fshanp3, fshlen3) == DM_FALSE) { + fprintf(stderr, "ERROR: fshan3 is not valid\n"); + } + + if (dm_handle_cmp(fshanp1, fshlen1, fshanp3, fshlen3)) { + fprintf(stderr, "ERROR: fshan1 and fshan3 differ in dm_handle_cmp\n"); + } + if (strcmp(fsbuffer1, fsbuffer3)) { + fprintf(stderr, "ERROR: fshan1 and fshan3 differ in strcmp\n"); + } + if (fshash1 != fshash3) { + fprintf(stderr, "ERROR: fshash1 and fshash3 differ\n"); + } + + dm_handle_free(hanp1, hlen1); + dm_handle_free(hanp2, hlen2); + dm_handle_free(hanp3, hlen3); + dm_handle_free(fshanp1, fshlen1); + dm_handle_free(fshanp2, fshlen2); + dm_handle_free(fshanp3, fshlen3); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/downgrade_right.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/downgrade_right.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/downgrade_right.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/downgrade_right.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_downgrade_right(). The +command line is: + + downgrade_right {-F} [-s sid] token {pathname|handle} + +where: +-F + when a pathname is specified, -F indicates that its filesystem handle + should be used rather than its file object handle. +sid + is the dm_sessid_t to use rather than the default test session. +token + is the dm_token_t to use. +{pathname|handle} + is either a handle, or is the pathname of a file whose handle is + to be used. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-F] [-s sid] token {pathname|handle}\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t token; + char *object; + void *hanp; + size_t hlen; + int Fflag = 0; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "Fs:")) != EOF) { + switch (opt) { + case 'F': + Fflag++; + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) + usage(); + token = atol(argv[optind++]); + object = argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file or filesystem's handle. */ + + if (opaque_to_handle(object, &hanp, &hlen)) { + fprintf(stderr, "can't get handle from %s\n", object); + exit(1); + } + if (Fflag) { + void *fshanp; + size_t fshlen; + + if (dm_handle_to_fshandle(hanp, hlen, &fshanp, &fshlen)) { + fprintf(stderr, "can't get filesystem handle from %s\n", + object); + exit(1); + } + dm_handle_free(hanp, hlen); + hanp = fshanp; + hlen = fshlen; + } + + if (dm_downgrade_right(sid, hanp, hlen, token)) { + fprintf(stderr, "dm_downgrade_right failed, %s\n", + strerror(errno)); + return(1); + } + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/fd_to_handle.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/fd_to_handle.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/fd_to_handle.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/fd_to_handle.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* Given a file object's pathname, print the object's handle. */ + +#include +#include + +#include +#include +#include +#include + +#include + +#include + +static void +hantoa( + void *hanp, + size_t hlen, + char *handle_str) +{ + u_char *cp= (u_char *)hanp; + int i; + + for (i = 0;i < hlen; i++, handle_str += 2) + sprintf(handle_str, "%.2x", *cp++); + *handle_str = '\0'; +} + +int +main( + int argc, + char **argv) +{ + char *name; + void *hanp; + size_t hlen; + char buffer[100]; + int fd; + + if (argc != 2) { + fprintf(stderr, "usage: %s path\n", argv[0]); + exit(1); + } + + (void)dm_init_service(&name); + + if ((fd = open(argv[1], O_RDONLY)) < 0) { + fprintf(stderr, "open of %s failed, %s\n", argv[1], + strerror(errno)); + exit(1); + } + if (dm_fd_to_handle(fd, &hanp, &hlen) != 0) { + fprintf(stderr, "dm_fd_to_handle failed, %s\n", + strerror(errno)); + exit(1); + } + hantoa(hanp, hlen, buffer); + + fprintf(stdout, "handle %s, path %s\n", buffer, argv[1]); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_allocinfo.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_allocinfo.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_allocinfo.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_allocinfo.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include + +#include + +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_get_allocinfo(). The +command line is: + + get_allocinfo [-D] [-n nelem] [-o offp] [-s sid] pathname + +where pathname is the name of a file, 'offp' is a byte offset from the +beginning of the file where you want to start dumping, and 'nelem' allows +you to specify how many extent structures to use in each dm_get_allocinfo +call. + +The code checks the returned extents as much as possible for errors. +It detects bad ex_type values, verifies that there is always a trailing +hole at the end of the file, that the ex_offset of each extent matches the +ex_offset+ex_length of the previous extent, and that ex_offset+ex_length +is always an even multiple of 512. It verifies that all ex_offset values +after the first fall on a 512-byte boundary. It verifies that the '*offp' +value returned by dm_get_allocinfo() is 0 at the end of the file, and +equals ex_offset+ex_length of the last extent if not at the end of the file. +Any error is reported to stderr, and the program then terminates with a +non-zero exit status. + +The program produces output similar to xfs_bmap in order to make comparison +easier. Here is some sample output. + +f1: offset 1 + rc 0, nelemp 17 + 0: [0..127]: resv [1..511] + +Line 1 gives the name of the file and the byte offset within the file where +the dump started. Line 2 appears once for each dm_get_allocinfo() call, +giving the return value (rc) and the number of extents which were returned. +Line 3 is repeated once for each extent. The first field "0:" is the extent +number. The second field "[0..127]:" give the starting and ending block for +the extent in 512-byte units. The third field is either "resv" to indicate +allocated space or "hole" if the extent is a hole. The fourth field +"[1..511]" only appears if the dump did not start with byte zero of the +first block. In that case, the first number shows the actual byte offset +within the block (1 in this case). The second number should always be +511 since we always dump to the end of a block. + +Possible tests +-------------- + +Dump some holey files and compare the output of this program with xfs_bmap. + +Produce a file with holes, and perform the following tests using just one +extent (-e 1). + Dump extents from beginning of the file. + Dump from byte 1 of the file. + Dump from the last byte of the first extent. + Dump from the first byte of the second extent. + Dump from the middle of the second extent. + Dump the first byte of the last extent. + Dump the last byte of the last extent. + Dump the first byte after the last extent. + Dump starting at an offset way past the end of the file. + +Produce a fragmented file with many adjacent DM_EXTENT_RES extents. + Repeat the above tests. + +Produce a GRIO file with holes. + Repeat the above tests. + +Run the following shell script. + +#!/bin/ksh + +# Dump the same holey file $max times, each time using one less extent +# structure than the previous time. The grep and diff code +# checks to make sure that you get the same answer each time, no matter +# how many extents you use. If all is okay, The only messages you will +# see are the "trial $num" messages. + +max=20 # should be bigger than the number extents in the file + +num=$max +while [ $num -gt 0 ] +do + echo "trial $num" + ./test_alloc -e $num f1 | grep '\[' > x.$num + if [ $num -lt $max ] + then + diff x.$num x.$max + fi + num=`expr $num - 1` +done + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + +static int print_alloc(dm_sessid_t sid, void* hanp, size_t hlen, + char *pathname, dm_off_t startoff, u_int nelem); + +char *Progname; +int Dflag = 0; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-D] [-n nelem] [-o off] [-s sid] " + "pathname\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_off_t startoff = 0; /* starting offset */ + u_int nelem = 100; + char *pathname; + void *hanp; + size_t hlen; + dm_stat_t sbuf; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "Dn:o:s:")) != EOF) { + switch(opt) { + case 'D': + Dflag++; + break; + case 'n': + nelem = atol(optarg); + break; + case 'o': + startoff = atoll(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + pathname = argv[optind]; + + if (dm_init_service(&name)) { + fprintf(stderr, "dm_init_service failed, %s\n", + strerror(errno)); + exit(1); + } + + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file's handle and verify that it is a regular file. */ + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for %s\n", pathname); + exit(1); + } + if (dm_get_fileattr(sid, hanp, hlen, DM_NO_TOKEN, DM_AT_STAT, &sbuf)) { + fprintf(stderr, "dm_get_fileattr failed\n"); + exit(1); + } + if (!S_ISREG(sbuf.dt_mode)) { + fprintf(stderr, "%s is not a regular file\n", pathname); + exit(1); + } + + /* Print the allocation. */ + + if (print_alloc(sid, hanp, hlen, pathname, startoff, nelem)) + exit(1); + + dm_handle_free(hanp, hlen); + exit(0); +} + + +static int +print_alloc( + dm_sessid_t sid, + void *hanp, + size_t hlen, + char *pathname, + dm_off_t startoff, + u_int nelem) +{ + dm_off_t endoff; + dm_extent_t *extent; + u_int nelemp; + u_int num = 0; + u_int i; + char *type = NULL; + int rc; + + fprintf(stdout, "%s: starting offset %lld\n", pathname, startoff); + + /* Allocate space for the number of extents requested by the user. */ + + if ((extent = malloc(nelem * sizeof(*extent))) == NULL) { + fprintf(stderr, "can't malloc extent structures\n"); + return(1); + } + + rc = 1; + endoff = startoff; + + while (rc != 0) { + rc = dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN, &startoff, + nelem, extent, &nelemp); + + if (rc < 0) { + fprintf(stderr, "dm_get_allocinfo failed, %s\n", + strerror(errno)); + return(1); + } + + fprintf(stdout, "\treturned %d, nelemp %d\n", rc, nelemp); + if (Dflag && nelemp) + fprintf(stdout, " ex_type ex_offset ex_length\n"); + + /* Note: it is possible for nelemp to be zero! */ + + for (i = 0; i < nelemp; i++) { + /* The extent must either be reserved space or a hole. + */ + + switch (extent[i].ex_type) { + case DM_EXTENT_RES: + type = "resv"; + break; + case DM_EXTENT_HOLE: + type = "hole"; + break; + default: + fprintf(stderr, "invalid extent type %d\n", + extent[i].ex_type); + return(1); + } + + if (!Dflag) { + fprintf(stdout, "\t%d: [%lld..%lld]: %s", num, + extent[i].ex_offset / 512, + (extent[i].ex_offset + + extent[i].ex_length - 1) / 512, type); + if ((extent[i].ex_offset % 512 != 0) || + (endoff % 512 != 0)) { + fprintf(stdout, "\t[%lld..%lld]\n", + extent[i].ex_offset % 512, + (endoff-1) % 512); + } else { + fprintf(stdout, "\n"); + } + } else { + fprintf(stdout, "%5s %13lld %13lld\n", + type, extent[i].ex_offset, + extent[i].ex_length); + } + + /* The ex_offset of the first extent should match the + 'startoff' specified by the caller. The ex_offset + in subsequent extents should always match + (ex_offset + ex_length) of the previous extent, + and should always start on a 512 byte boundary. + */ + + if (extent[i].ex_offset != endoff) { + fprintf(stderr, "new extent (%lld)is not " + "adjacent to previous one (%lld)\n", + extent[i].ex_offset, endoff); + return(1); + } + if (num && (extent[i].ex_offset % 512) != 0) { + fprintf(stderr, "non-initial ex_offset (%lld) " + "is not a 512-byte multiple\n", + extent[i].ex_offset); + return(1); + } + + /* Non-initial extents should have ex_length values + that are an even multiple of 512. The initial + extent should be a multiple of 512 less the offset + into the starting 512-byte block. + */ + + if (((extent[i].ex_offset % 512) + extent[i].ex_length) % 512 != 0) { + fprintf(stderr, "ex_length is incorrect based " + "upon the ex_offset\n"); + return(1); + } + + endoff = extent[i].ex_offset + extent[i].ex_length; + num++; /* count of extents printed */ + } + + /* If not yet at end of file, the startoff parameter should + match the ex_offset plus ex_length of the last extent + retrieved. + */ + + if (rc && startoff != endoff) { + fprintf(stderr, "startoff is %lld, should be %lld\n", + startoff, endoff); + return(1); + } + + /* If we are at end of file, the last extent should be a + hole. + */ + + if (!rc && type && strcmp(type, "hole")) { + fprintf(stderr, "file didn't end with a hole\n"); + return(1); + } + } + + /* At end of file, startoff should always equal zero. */ + + if (startoff != 0) { + fprintf(stderr, "ERROR: startoff was not zero at end of file\n"); + return(1); + } + return(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_config_events.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_config_events.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_config_events.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_config_events.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_get_config_events(). The +command line is: + + get_config_events [-n nelem] handle + +where handle is the handle of a file or filesystem, and nelem is the value +to use for the nelem parameter to dm_get_eventlist(). + +----------------------------------------------------------------------------*/ + +extern int optind; +extern char *optarg; + + +char *Progname; + + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-n nelem] handle\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + u_int nelem = DM_EVENT_MAX; + char *han_str; + dm_eventset_t eventset; + void *hanp; + size_t hlen; + u_int nelemp; + char *name; + int error; + int opt; + int i; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "n:")) != EOF) { + switch (opt) { + case 'n': + nelem = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + han_str = argv[optind]; + if ((error = atohan(han_str, &hanp, &hlen)) != 0) { + fprintf(stderr, "atohan() failed, %s\n", strerror(error)); + return(1); + } + + if (dm_init_service(&name)) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + return(1); + } + + DMEV_ZERO(eventset); + + if (dm_get_config_events(hanp, hlen, nelem, &eventset, &nelemp)) { + fprintf(stderr, "dm_get_config_events failed, %s\n", + strerror(errno)); + return(1); + } + + fprintf(stdout, "Events supported (0x%llx), nelemp %d:\n", + eventset, nelemp); + + for (i = 0; i < nelemp; i++) { + if (!DMEV_ISSET(i, eventset)) + continue; + switch (i) { + case DM_EVENT_CANCEL: + fprintf(stdout, "DM_EVENT_CANCEL"); + break; + case DM_EVENT_MOUNT: + fprintf(stdout, "DM_EVENT_MOUNT"); + break; + case DM_EVENT_PREUNMOUNT: + fprintf(stdout, "DM_EVENT_PREUNMOUNT"); + break; + case DM_EVENT_UNMOUNT: + fprintf(stdout, "DM_EVENT_UNMOUNT"); + break; + case DM_EVENT_DEBUT: + fprintf(stdout, "DM_EVENT_DEBUT"); + break; + case DM_EVENT_CREATE: + fprintf(stdout, "DM_EVENT_CREATE"); + break; + case DM_EVENT_CLOSE: + fprintf(stdout, "DM_EVENT_CLOSE"); + break; + case DM_EVENT_POSTCREATE: + fprintf(stdout, "DM_EVENT_POSTCREATE"); + break; + case DM_EVENT_REMOVE: + fprintf(stdout, "DM_EVENT_REMOVE"); + break; + case DM_EVENT_POSTREMOVE: + fprintf(stdout, "DM_EVENT_POSTREMOVE"); + break; + case DM_EVENT_RENAME: + fprintf(stdout, "DM_EVENT_RENAME"); + break; + case DM_EVENT_POSTRENAME: + fprintf(stdout, "DM_EVENT_POSTRENAME"); + break; + case DM_EVENT_LINK: + fprintf(stdout, "DM_EVENT_LINK"); + break; + case DM_EVENT_POSTLINK: + fprintf(stdout, "DM_EVENT_POSTLINK"); + break; + case DM_EVENT_SYMLINK: + fprintf(stdout, "DM_EVENT_SYMLINK"); + break; + case DM_EVENT_POSTSYMLINK: + fprintf(stdout, "DM_EVENT_POSTSYMLINK"); + break; + case DM_EVENT_READ: + fprintf(stdout, "DM_EVENT_READ"); + break; + case DM_EVENT_WRITE: + fprintf(stdout, "DM_EVENT_WRITE"); + break; + case DM_EVENT_TRUNCATE: + fprintf(stdout, "DM_EVENT_TRUNCATE"); + break; + case DM_EVENT_ATTRIBUTE: + fprintf(stdout, "DM_EVENT_ATTRIBUTE"); + break; + case DM_EVENT_DESTROY: + fprintf(stdout, "DM_EVENT_DESTROY"); + break; + case DM_EVENT_NOSPACE: + fprintf(stdout, "DM_EVENT_NOSPACE"); + break; + case DM_EVENT_USER: + fprintf(stdout, "DM_EVENT_USER"); + break; + case DM_EVENT_MAX: + fprintf(stdout, "DM_EVENT_23"); + break; + } + fprintf(stdout, " (%d)\n", i); + } + + dm_handle_free(hanp, hlen); + return(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_dirattrs.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_dirattrs.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_dirattrs.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_dirattrs.c Tue Jan 16 19:24:14 2001 @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_get_dirattrs(). The +command line is: + + get_dirattrs [-b buflen] [-l loc] [-s sid] dirpath + +where dirpath is the name of a directory, buflen is the size of the buffer +to use in the call, loc is a starting location, and sid is the session ID +whose attributes you are interested in. + +----------------------------------------------------------------------------*/ + +extern char *sys_errlist[]; +extern int optind; +extern char *optarg; + + +char *Progname; + +static void +usage(void) +{ + int i; + + fprintf(stderr, "usage:\t%s [-b buflen] [-l loc] [-s sid] dirpath\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_attrloc_t loc = 0; + char *dirpath; + char buffer[100]; + void *bufp; + size_t buflen = 10000; + u_int mask; + size_t rlenp; + void *hanp; + size_t hlen; + char *name; + int error; + int opt; + int i; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "b:l:s:")) != EOF) { + switch (opt) { + case 'b': + buflen = atol(optarg); + break; + case 'l': + loc = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + dirpath = argv[optind++]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the diretory's handle. */ + + if (dm_path_to_handle(dirpath, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for file %s, %s\n", + dirpath, strerror(errno)); + exit(1); + } + + if ((bufp = malloc(buflen == 0 ? 1 : buflen)) == NULL) { + fprintf(stderr, "malloc failed, %s\n", strerror(errno)); + exit(1); + } + + mask = DM_AT_HANDLE|DM_AT_EMASK|DM_AT_PMANR|DM_AT_PATTR|DM_AT_DTIME|DM_AT_CFLAG|DM_AT_STAT; + + if ((error = dm_get_dirattrs(sid, hanp, hlen, DM_NO_TOKEN, mask, + &loc, buflen, bufp, &rlenp)) < 0) { + if (errno == E2BIG) { + fprintf(stderr, "dm_get_dirattrs buffer too small, " + "should be %d bytes\n", rlenp); + } else { + fprintf(stderr, "dm_get_dirattrs failed, %s\n", + strerror(errno)); + } + exit(1); + } + fprintf(stdout, "rc = %d, rlenp is %d, loc is %lld\n", error, + rlenp, loc); + if (rlenp > 0) { + dm_stat_t *statp; + + statp = (dm_stat_t *)bufp; + while (statp != NULL) { + + hantoa((char *)statp + statp->dt_handle.vd_offset, + statp->dt_handle.vd_length, buffer); + fprintf(stdout, "handle %s\n", buffer); + fprintf(stdout, "name %s\n", + (char *)statp + statp->dt_compname.vd_offset); + print_line(statp); + + statp = DM_STEP_TO_NEXT(statp, dm_stat_t *); + } + } + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_dmattr.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_dmattr.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_dmattr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_dmattr.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_get_dmattr(). The +command line is: + + get_dmattr [-b buflen] [-s sid] [-t token] pathname attr + +where pathname is the name of a file, buflen is the size of the buffer to use +in the call, attr is the name of the DMAPI attribute, and sid is the session ID +whose attributes you you are interested in. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-b buflen] [-s sid] [-t token] " + "pathname attr\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t token = DM_NO_TOKEN; + char *pathname; + dm_attrname_t *attrnamep; + void *bufp; + size_t buflen = 10000; + size_t rlenp; + void *hanp; + size_t hlen; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "b:s:t:")) != EOF) { + switch (opt) { + case 'b': + buflen = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case 't': + token = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) + usage(); + pathname = argv[optind++]; + attrnamep = (dm_attrname_t *)argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file's handle. */ + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for file %s, %s\n", + pathname, strerror(errno)); + exit(1); + } + + if (buflen > 0) { + if ((bufp = malloc(buflen)) == NULL) { + fprintf(stderr, "malloc failed, %s\n", strerror(errno)); + exit(1); + } + } + + if (dm_get_dmattr(sid, hanp, hlen, token, attrnamep, buflen, + bufp, &rlenp)) { + if (errno == E2BIG) { + fprintf(stderr, "dm_get_dmattr buffer too small, " + "should be %d bytes\n", rlenp); + } else { + fprintf(stderr, "dm_get_dmattr failed, %s\n", + strerror(errno)); + } + exit(1); + } + fprintf(stdout, "rlenp is %d, value is '%s'\n", rlenp, (char*)bufp); + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_eventlist.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_eventlist.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_eventlist.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_eventlist.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_get_eventlist(). The +command line is: + + get_eventlist [-F] [-n nelem] [-s sid] [-t token] {pathname|handle} + +where: +{pathname|handle} + is the pathname of a file or filesystem or a handle. +-n nelem + is the value to use for the nelem parameter to dm_get_eventlist(). +-s sid + is the dm_sessid_t to use in place of the default test session. +-t token + is the dm_token_t to use in place of DM_NO_TOKEN. +-F + is used when a pathname is specified to indicate that you want its + filesystem handle, not its file handle. + +----------------------------------------------------------------------------*/ + +extern int optind; +extern char *optarg; + + +char *Progname; + + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-F] [-n nelem] [-s sid] [-t token] " + "{pathname|handle}\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t token = DM_NO_TOKEN; + u_int nelem = DM_EVENT_MAX; + char *object; + dm_eventset_t eventset; + void *hanp; + size_t hlen; + u_int nelemp; + char *name; + int Fflag = 0; + int error; + int opt; + int i; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "Fn:s:t:")) != EOF) { + switch (opt) { + case 'F': + Fflag++; + break; + case 'n': + nelem = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case 't': + token = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + object = argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + + if ((error = opaque_to_handle(object, &hanp, &hlen)) != 0) { + fprintf(stderr, "can't get a handle from %s, %s\n", + object, strerror(error)); + return(1); + } + + if (Fflag) { + void *fshanp; + size_t fshlen; + + if (dm_handle_to_fshandle(hanp, hlen, &fshanp, &fshlen)) { + fprintf(stderr, "can't get filesystem handle from %s\n", + object); + exit(1); + } + dm_handle_free(hanp, hlen); + hanp = fshanp; + hlen = fshlen; + } + + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + DMEV_ZERO(eventset); + + if (dm_get_eventlist(sid, hanp, hlen, token, nelem, + &eventset, &nelemp)) { + fprintf(stderr, "dm_get_eventlist failed, %s\n", + strerror(errno)); + return(1); + } + +#ifdef VERITAS_21 + fprintf(stdout, "Events on object %s (0x%x), nelemp %d:\n", +#else + fprintf(stdout, "Events on object %s (0x%llx), nelemp %d:\n", +#endif + object, eventset, nelemp); + + for (i = 0; i < nelemp; i++) { + if (!DMEV_ISSET(i, eventset)) + continue; + switch (i) { + case DM_EVENT_CANCEL: + fprintf(stdout, "DM_EVENT_CANCEL"); + break; + case DM_EVENT_MOUNT: + fprintf(stdout, "DM_EVENT_MOUNT"); + break; + case DM_EVENT_PREUNMOUNT: + fprintf(stdout, "DM_EVENT_PREUNMOUNT"); + break; + case DM_EVENT_UNMOUNT: + fprintf(stdout, "DM_EVENT_UNMOUNT"); + break; + case DM_EVENT_DEBUT: + fprintf(stdout, "DM_EVENT_DEBUT"); + break; + case DM_EVENT_CREATE: + fprintf(stdout, "DM_EVENT_CREATE"); + break; + case DM_EVENT_CLOSE: + fprintf(stdout, "DM_EVENT_CLOSE"); + break; + case DM_EVENT_POSTCREATE: + fprintf(stdout, "DM_EVENT_POSTCREATE"); + break; + case DM_EVENT_REMOVE: + fprintf(stdout, "DM_EVENT_REMOVE"); + break; + case DM_EVENT_POSTREMOVE: + fprintf(stdout, "DM_EVENT_POSTREMOVE"); + break; + case DM_EVENT_RENAME: + fprintf(stdout, "DM_EVENT_RENAME"); + break; + case DM_EVENT_POSTRENAME: + fprintf(stdout, "DM_EVENT_POSTRENAME"); + break; + case DM_EVENT_LINK: + fprintf(stdout, "DM_EVENT_LINK"); + break; + case DM_EVENT_POSTLINK: + fprintf(stdout, "DM_EVENT_POSTLINK"); + break; + case DM_EVENT_SYMLINK: + fprintf(stdout, "DM_EVENT_SYMLINK"); + break; + case DM_EVENT_POSTSYMLINK: + fprintf(stdout, "DM_EVENT_POSTSYMLINK"); + break; + case DM_EVENT_READ: + fprintf(stdout, "DM_EVENT_READ"); + break; + case DM_EVENT_WRITE: + fprintf(stdout, "DM_EVENT_WRITE"); + break; + case DM_EVENT_TRUNCATE: + fprintf(stdout, "DM_EVENT_TRUNCATE"); + break; + case DM_EVENT_ATTRIBUTE: + fprintf(stdout, "DM_EVENT_ATTRIBUTE"); + break; + case DM_EVENT_DESTROY: + fprintf(stdout, "DM_EVENT_DESTROY"); + break; + case DM_EVENT_NOSPACE: + fprintf(stdout, "DM_EVENT_NOSPACE"); + break; + case DM_EVENT_USER: + fprintf(stdout, "DM_EVENT_USER"); + break; + case DM_EVENT_MAX: + fprintf(stdout, "DM_EVENT_23"); + break; + } + fprintf(stdout, " (%d)\n", i); + } + + dm_handle_free(hanp, hlen); + return(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_events.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_events.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_events.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_events.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_get_events(). The +command line is: + + get_events [-b buflen] [-m maxmsgs] [-f] sid + +where buflen is the size of the buffer to use, maxmsgs is the number of messages +to read, -f, if selected, is DM_EV_WAIT, and sid is the session ID +whose dispositions you are interested in. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-b buflen] [-m maxmsgs] [-f] sid\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_eventmsg_t *msg; + dm_sessid_t sid; + u_int flags = 0; + void *bufp; + size_t buflen = 10000; + u_int maxmsgs = 1; + size_t rlenp; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "b:m:f")) != EOF) { + switch (opt) { + case 'b': + buflen = atol(optarg); + break; + case 'm': + maxmsgs = atol(optarg); + break; + case 'f': + flags = DM_EV_WAIT; + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + sid = atol(argv[optind]); + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + + if (buflen > 0) { + if ((bufp = malloc(buflen)) == NULL) { + fprintf(stderr, "malloc failed, %s\n", strerror(errno)); + exit(1); + } + } + + if (dm_get_events(sid, maxmsgs, flags, buflen, bufp, &rlenp)) { + if (errno == E2BIG) { + fprintf(stderr, "dm_get_events buffer too small, " + "should be %d bytes\n", rlenp); + } else { + fprintf(stderr, "dm_get_events failed, (%d)%s\n", + errno, strerror(errno)); + } + exit(1); + } + fprintf(stdout, "rlenp is %d\n", rlenp); + + if (rlenp == 0) + return(0); + + msg = bufp; + while (msg != NULL) { + print_one_message(msg); + msg = DM_STEP_TO_NEXT(msg, dm_eventmsg_t *); + } + return(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_fileattr.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_fileattr.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_fileattr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_fileattr.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include + +#include +#include + +extern int optind; +extern int opterr; +extern char *optarg; + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "Usage: %s [-a|-A] [-s sid] [-t token] pathname\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t token = DM_NO_TOKEN; +/* char buffer[500];*/ + void *hanp; + size_t hlen; + dm_stat_t dmstat; + char *pathname; + int a_flag = 0; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + opterr = 0; + while ((opt = getopt(argc, argv, "Aas:t:")) != EOF) { + switch (opt) { + case 'A': + a_flag = 2; + break; + case 'a': + a_flag = 1; + break; + case 's': + sid = atol(optarg); + break; + case 't': + token = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) { + usage(); + } + pathname = argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + if (!a_flag) { + fprintf(stdout, "path %s\n", pathname); + + /* Get the file's state, print it, then verify it against + what is in the file's stat block. + */ + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stderr, "dm_path_to_handle failed, %s\n", + strerror(errno)); + exit(1); + } + + if (dm_get_fileattr(sid, hanp, hlen, token, + DM_AT_EMASK|DM_AT_PMANR|DM_AT_PATTR|DM_AT_DTIME|DM_AT_CFLAG|DM_AT_STAT, + &dmstat)) { + fprintf(stderr, "dm_get_fileattr failed, %s\n", + strerror(errno)); + exit(1); + } + + print_state(&dmstat); + (void)validate_state(&dmstat, pathname, 1); +/* XXX Shut off for now + } else { + if ((rc = filesys_bulkscan_init(pathname, &scanp)) != 0) { + fprintf(stderr, "filesys_bulkscan failed, %s\n", + fileio_err_image(rc)); + exit(1); + } + for (;;) { + rc = filesys_bulkscan_read(scanp, &fhandle, &fullstat); + if (rc != FILEIO_NOERROR) + break; + + (void)fhandle_to_buffer(&fhandle, buffer, sizeof(buffer)); + if (a_flag == 1) { + fprintf(stdout, "handle %s\n", buffer); + print_state(&fullstat); + fprintf(stdout, "--------------------------\n"); + } else { + fprintf(stdout, "%s|", buffer); + print_line(&fullstat); + } + } + + if (rc != FILEIO_ENDOFSCAN) { + fprintf(stderr, "filesys_bulkscan_read failed, %s\n", + fileio_err_image(rc)); + exit(1); + } + if ((rc = filesys_bulkscan_close(&scanp)) != 0) { + fprintf(stderr, "filesys_bulkscan_close failed, %s\n", + fileio_err_image(rc)); + exit(1); + } +XXX Shut off for now. */ + } + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_mountinfo.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_mountinfo.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_mountinfo.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_mountinfo.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include + +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_get_mountinfo(). The +command line is: + + get_mountinfo [-b buflen] [-s sid] pathname + +where pathname is the name of a file, buflen is the size of the buffer to use +in the call, and sid is the session ID whose attributes you are interested in. + +----------------------------------------------------------------------------*/ + + /* + * Define some standard formats for the printf statements below. + */ + +#define HDR "%s: token %d sequence %d\n" +#define VALS "\t%-15s %s\n" +#define VALD "\t%-15s %d\n" +#ifdef __sgi +#define VALLLD "\t%-15s %lld\n" +#else +#define VALLLD "\t%-15s %ld\n" +#endif + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-b buflen] [-s sid] pathname\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *pathname; + void *bufp; + size_t buflen = 10000; + size_t rlenp; + void *fshanp; + size_t fshlen; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "b:s:")) != EOF) { + switch (opt) { + case 'b': + buflen = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + pathname = argv[optind++]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file's handle. */ + + if (dm_path_to_fshandle(pathname, &fshanp, &fshlen)) { + fprintf(stderr, "can't get fshandle for file %s, %s\n", + pathname, strerror(errno)); + exit(1); + } + + if (buflen > 0) { + if ((bufp = malloc(buflen)) == NULL) { + fprintf(stderr, "malloc failed, %s\n", strerror(errno)); + exit(1); + } + } + + if (dm_get_mountinfo(sid, fshanp, fshlen, DM_NO_TOKEN, buflen, + bufp, &rlenp)) { + if (errno == E2BIG) { + fprintf(stderr, "dm_get_mountinfo buffer too small, " + "should be %d bytes\n", rlenp); + } else { + fprintf(stderr, "dm_get_mountinfo failed, %s\n", + strerror(errno)); + } + exit(1); + } + fprintf(stdout, "rlenp is %d\n", rlenp); + print_one_mount_event(bufp); + + dm_handle_free(fshanp, fshlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_region.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_region.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/get_region.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/get_region.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_set_region(). The +command line is: + + get_region [-n nelem] [-s sid] pathname + +where pathname is the name of a file, nelem is the number of regions to pass +in the call, and sid is the session ID whose events you you are interested in. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-n nelem] [-s sid] pathname\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_region_t *regbufp = NULL; + char *pathname = NULL; + u_int nelemp; + u_int nelem = 1; + void *hanp; + size_t hlen; + char *name; + int opt; + int i; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "n:s:")) != EOF) { + switch (opt) { + case 'n': + nelem = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + pathname = argv[optind++]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file's handle. */ + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for file %s\n", pathname); + exit(1); + } + + if (nelem > 0) { + if ((regbufp = calloc(nelem, sizeof(*regbufp))) == NULL) { + fprintf(stderr, "calloc failed, %s\n", strerror(errno)); + exit(1); + } + } + + if (dm_get_region(sid, hanp, hlen, DM_NO_TOKEN, nelem, regbufp, + &nelemp)) { + fprintf(stderr, "dm_get_region failed, %s\n", + strerror(errno)); + exit(1); + } + fprintf(stdout, "%d regions\n", nelemp); + + for (i = 0; i < nelemp; i++) { +#ifdef VERITAS_21 + fprintf(stdout, "offset %d, size %d, flags 0x%x\n", +#else + fprintf(stdout, "offset %lld, size %lld, flags 0x%x\n", +#endif + regbufp[i].rg_offset, regbufp[i].rg_size, + regbufp[i].rg_flags); + } + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/getall_disp.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/getall_disp.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/getall_disp.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/getall_disp.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_getall_disp(). The +command line is: + + getall_disp [-b buflen] sid + +where buflen is the size of the buffer to use, and sid is the session ID +whose dispositions you you are interested in. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-b buflen] sid\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_dispinfo_t *disp; + dm_sessid_t sid; + void *bufp; + size_t buflen = 10000; + void *hanp; + size_t hlen; + char hans1[HANDLE_STR]; + size_t rlenp; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "b:")) != EOF) { + switch (opt) { + case 'b': + buflen = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + sid = atol(argv[optind]); + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + + if (buflen > 0) { + if ((bufp = malloc(buflen)) == NULL) { + fprintf(stderr, "malloc failed, %s\n", strerror(errno)); + exit(1); + } + } + + if (dm_getall_disp(sid, buflen, bufp, &rlenp)) { + if (errno == E2BIG) { + fprintf(stderr, "dm_getall_disp buffer too small, " + "should be %d bytes\n", rlenp); + } else { + fprintf(stderr, "dm_getall_disp failed, %s\n", + strerror(errno)); + } + exit(1); + } + fprintf(stdout, "rlenp is %d\n", rlenp); + if (rlenp == 0) + return(0); + + disp = bufp; + while (disp != NULL) { + hanp = DM_GET_VALUE(disp, di_fshandle, void *); + hlen = DM_GET_LEN(disp, di_fshandle); + if (hanp && hlen) { + hantoa(hanp, hlen, hans1); + } else { + sprintf(hans1, "", hlen); + } + printf("%-15s %s dm_eventset_t 0%llo\n", + "fshandle", hans1, + disp->di_eventset); + + disp = DM_STEP_TO_NEXT(disp, dm_dispinfo_t *); + } + return(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/getall_dmattr.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/getall_dmattr.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/getall_dmattr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/getall_dmattr.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_getall_dmattr(). The +command line is: + + getall_dmattr [-b buflen] [-s sid] pathname + +where pathname is the name of a file, buflen is the size of the buffer to use +in the call, and sid is the session ID whose attributes you are interested in. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-b buflen] [-s sid] pathname\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *pathname; + void *bufp; + size_t buflen = 10000; + size_t rlenp; + void *hanp; + size_t hlen; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "b:s:")) != EOF) { + switch (opt) { + case 'b': + buflen = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + pathname = argv[optind++]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file's handle. */ + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for file %s, %s\n", + pathname, strerror(errno)); + exit(1); + } + + if ((bufp = malloc(buflen == 0 ? 1 : buflen)) == NULL) { + fprintf(stderr, "malloc failed, %s\n", strerror(errno)); + exit(1); + } + + if (dm_getall_dmattr(sid, hanp, hlen, DM_NO_TOKEN, buflen, + bufp, &rlenp)) { + if (errno == E2BIG) { + fprintf(stderr, "dm_getall_dmattr buffer too small, " + "should be %d bytes\n", rlenp); + } else { + fprintf(stderr, "dm_getall_dmattr failed, %s\n", + strerror(errno)); + } + exit(1); + } + fprintf(stdout, "rlenp is %d\n", rlenp); + if (rlenp > 0) { + dm_attrlist_t *attrlist; + + fprintf(stdout, "DMAPI attributes are:\n"); + + attrlist = (dm_attrlist_t *)bufp; + while (attrlist != NULL) { + fprintf(stdout, "Name: %s, length %d, value '%s'\n", + attrlist->al_name.an_chars, + DM_GET_LEN(attrlist, al_data), + DM_GET_VALUE(attrlist, al_data, char *)); + + attrlist = DM_STEP_TO_NEXT(attrlist, dm_attrlist_t *); + } + } + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/handle_to_fshandle.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/handle_to_fshandle.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/handle_to_fshandle.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/handle_to_fshandle.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* Given an object's handle, print the filesystem handle. */ + +#include + +#include + +/*--------------------------------------------------------------------------- + +Test program used to test dm_handle_to_fshandle(). The command line is: + + path_to_fshandle handle + +where handle is an object's handle. + +----------------------------------------------------------------------------*/ + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s handle\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + char *han_str; + char *name; + void *hanp, *fshanp; + size_t hlen, fshlen; + char buffer[100]; + int error; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + if (argc != 2) + usage(); + han_str = argv[1]; + + (void)dm_init_service(&name); + + if ((error = atohan(han_str, &hanp, &hlen)) != 0) { + fprintf(stderr, "atohan() failed, %s\n", strerror(error)); + return(1); + } + + if (dm_handle_to_fshandle(hanp, hlen, &fshanp, &fshlen) != 0) { + fprintf(stderr, "dm_handle_to_fshandle failed, %s\n", + strerror(errno)); + return(1); + } + hantoa(fshanp, fshlen, buffer); + fprintf(stdout, "%s\n", buffer); + + dm_handle_free(hanp, hlen); + dm_handle_free(fshanp, fshlen); + return(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/handle_to_path.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/handle_to_path.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/handle_to_path.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/handle_to_path.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include + +#include + +#include +#ifdef linux +#include +#endif + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_handle_to_path(). The +command line is: + + handle_to_path [-b buflen] dirpath objpath + +There are two parameters. The first is the pathname of a directory, +and the second is the pathname of a file, directory, or symbolic link +within that directory. The second parameter can also be the same as +the first if you want to specify "." (this is how EMASS uses it). +Pathnames can either be relative or full. + +buflen is the size of the buffer to use in the call. + +This program will return the full pathname of the object which is the +second parameter using the dm_handle_to_path() function. + +The program should work successfully for files, directories, and +symbolic links, and does not have to work for any other type of +object. It doesn't have to work across mount points. There shouldn't +be any "/." crud on the end of the returned pathname either. + +----------------------------------------------------------------------------*/ + +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-b buflen] dirpath objpath\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + char *dirpath; + char *objpath; + void *hanp1, *hanp2, *hanp1a; + size_t hlen1, hlen2, hlen1a; + void *pathbufp; + size_t buflen = 1024; + size_t rlenp; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "b:")) != EOF) { + switch (opt) { + case 'b': + buflen = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) + usage(); + dirpath = argv[optind++]; + objpath = argv[optind]; + + if (dm_init_service(&name)) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + return(1); + } + + if (dm_path_to_handle(dirpath, &hanp1, &hlen1)) { + fprintf(stderr, "dm_path_to_handle failed for %s, (%d) %s\n", + dirpath, errno, strerror(errno)); + return(1); + } + if (path_to_handle(dirpath, &hanp1a, &hlen1a)) { + fprintf(stderr, "path_to_handle failed for %s, (%d) %s\n", + dirpath, errno, strerror(errno)); + return(1); + } + if(hlen1 != hlen1a){ + fprintf(stderr, "dm_path_to_handle != path_to_handle, %d != %d\n", + hlen1, hlen1a); + } + if( memcmp(hanp1, hanp1a, hlen1) != 0 ){ + fprintf(stderr, "dm_path_to_handle != path_to_handle, handles differ\n"); + } + if (dm_path_to_handle(objpath, &hanp2, &hlen2)) { + fprintf(stderr, "dm_path_to_handle failed for %s, (%d) %s\n", + objpath, errno, strerror(errno)); + return(1); + } + + if ((pathbufp = malloc(buflen == 0 ? 1 : buflen)) == NULL) { + fprintf(stderr, "malloc failed\n"); + return(1); + } + + if (dm_handle_to_path(hanp1, hlen1, hanp2, hlen2, + buflen, pathbufp, &rlenp)) { + if (errno == E2BIG) { + fprintf(stderr, "dm_handle_to_path buffer too small, " + "should be %d bytes\n", rlenp); + } else { + fprintf(stderr, "dm_handle_to_path failed, (%d) %s\n", + errno, strerror(errno)); + } + return(1); + } + fprintf(stderr, "rlenp is %d, pathbufp is %s\n", rlenp, (char*)pathbufp); + if (strlen(pathbufp) + 1 != rlenp) { + fprintf(stderr, "rlenp is %d, should be %d\n", rlenp, + strlen(pathbufp) + 1); + return(1); + } + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/init_service.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/init_service.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/init_service.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/init_service.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include + +/*--------------------------------------------------------------------------- + +Test program used to test dm_init_service(). The command line is: + + init_service + +----------------------------------------------------------------------------*/ + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + char *name; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + if (argc != 1) + usage(); + + (void)dm_init_service(&name); + fprintf(stdout, "%s\n", name); + + return(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/link_test.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/link_test.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/link_test.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/link_test.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +/* + The variable 'flags' was used with two different meanings within + the spec. Sometimes it was an int, and sometimes a u_int. I + changed all the u_int references to use the new symbol uflags. + + The variable 'rlenp' was also used with two different meanings; + sometimes size_t, and sometimes dm_size_t. I introduced the new + symbol 'dmrlenp' for the dm_size_t cases. +*/ + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid, oldsid, targetsid, *newsidp, *sidbufp; + dm_token_t token, *tokenp, *rtokenp, *tokenbufp; + dm_attrname_t *attrnamep; + dm_off_t off, *offp, *roffp; + dm_extent_t *extentp; + dm_inherit_t *inheritbufp; + dm_stat_t *statp; + dm_size_t len, *dmrlenp, *retvalp; + dm_attrloc_t *locp; + dm_eventset_t *eventsetp; + dm_config_t flagname; + dm_region_t *regbufp; + dm_response_t response; + dm_right_t right, *rightp; + dm_igen_t igen, *igenp; + dm_msgtype_t msgtype; + dm_fileattr_t *attrp; + dm_boolean_t enable, *exactflagp; + dm_timestruct_t *delay; + mode_t mode; + size_t hlen, dirhlen, hlen1, hlen2, targhlen, *fshlenp, *hlenp; + size_t msglen, buflen, *rlenp; + u_int nelem, mask, maxmsgs, uflags, *nelemp, maxevent; + void *hanp, *dirhanp, *hanp1, *hanp2, *targhanp; + void *msgdatap, *bufp, **hanpp, *respbufp, **fshanpp; + dm_fsid_t fsid, *fsidp; + dm_ino_t ino, *inop; + char *cname, *sessinfop, *path, *pathbufp, **versionstrpp; + int flags, fd, setdtime, reterror; + u_int urc; + int rc; + dm_ssize_t ssrc; + +/* Definitions per the prototypes in dmport.h, in the same order. */ + + rc = dm_clear_inherit(sid, hanp, hlen, token, attrnamep); + rc = dm_create_by_handle(sid, dirhanp, dirhlen, token, + hanp, hlen, cname); + rc = dm_create_session(oldsid, sessinfop, newsidp); + rc = dm_create_userevent(sid, msglen, msgdatap, tokenp); + rc = dm_destroy_session(sid); + rc = dm_downgrade_right(sid, hanp, hlen, token); + rc = dm_fd_to_handle(fd, hanpp, hlenp); + rc = dm_find_eventmsg(sid, token, buflen, bufp, rlenp); + rc = dm_get_allocinfo(sid, hanp, hlen, + token, offp, nelem, extentp, nelemp); + rc = dm_get_bulkall(sid, hanp, hlen, token, mask, attrnamep, + locp, buflen, bufp, rlenp); + rc = dm_get_bulkattr(sid, hanp, hlen, token, mask, locp, buflen, + bufp, rlenp); + rc = dm_get_config(hanp, hlen, flagname, retvalp); + rc = dm_get_config_events(hanp, hlen, nelem, eventsetp, nelemp); + rc = dm_get_dirattrs(sid, hanp, hlen, token, mask, locp, buflen, + bufp, rlenp); + rc = dm_get_dmattr(sid, hanp, hlen, token, attrnamep, buflen, + bufp, rlenp); + rc = dm_get_eventlist(sid, hanp, hlen, token, nelem, eventsetp, nelemp); + rc = dm_get_events(sid, maxmsgs, flags, buflen, bufp, rlenp); + rc = dm_get_fileattr(sid, hanp, hlen, token, mask, statp); + rc = dm_get_mountinfo(sid, hanp, hlen, token, buflen, bufp, rlenp); + rc = dm_get_region(sid, hanp, hlen, token, nelem, regbufp, nelemp); + rc = dm_getall_disp(sid, buflen, bufp, rlenp); + rc = dm_getall_dmattr(sid, hanp, hlen, token, buflen, bufp, rlenp); + rc = dm_getall_inherit(sid, hanp, hlen, + token, nelem, inheritbufp, nelemp); + rc = dm_getall_sessions(nelem, sidbufp, nelemp); + rc = dm_getall_tokens(sid, nelem, tokenbufp, nelemp); + rc = dm_handle_cmp(hanp1, hlen1, hanp2, hlen2); + dm_handle_free(hanp, hlen); + urc = dm_handle_hash(hanp, hlen); + rc = dm_handle_is_valid(hanp, hlen); + rc = dm_handle_to_fshandle(hanp, hlen, fshanpp, fshlenp); + rc = dm_handle_to_fsid(hanp, hlen, fsidp); + rc = dm_handle_to_igen(hanp, hlen, igenp); + rc = dm_handle_to_ino(hanp, hlen, inop); + rc = dm_handle_to_path(dirhanp, dirhlen, targhanp, targhlen, + buflen, pathbufp, rlenp); + rc = dm_init_attrloc(sid, hanp, hlen, token, locp); + rc = dm_init_service(versionstrpp); + rc = dm_make_handle(&fsid, &ino, &igen, hanpp, hlenp); + rc = dm_make_fshandle(&fsid, hanpp, hlenp); + rc = dm_mkdir_by_handle(sid, dirhanp, dirhlen, token, + hanp, hlen, cname); + rc = dm_move_event(sid, token, targetsid, rtokenp); + rc = dm_obj_ref_hold(sid, token, hanp, hlen); + rc = dm_obj_ref_query(sid, token, hanp, hlen); + rc = dm_obj_ref_rele(sid, token, hanp, hlen); + rc = dm_path_to_fshandle(path, hanpp, hlenp); + rc = dm_path_to_handle(path, hanpp, hlenp); + rc = dm_pending(sid, token, delay); + rc = dm_probe_hole(sid, hanp, hlen, token, off, len, roffp, dmrlenp); + rc = dm_punch_hole(sid, hanp, hlen, token, off, len); + rc = dm_query_right(sid, hanp, hlen, token, rightp); + rc = dm_query_session(sid, buflen, bufp, rlenp); + ssrc = dm_read_invis(sid, hanp, hlen, token, off, len, bufp); + rc = dm_release_right(sid, hanp, hlen, token); + rc = dm_remove_dmattr(sid, hanp, hlen, token, setdtime, attrnamep); + rc = dm_request_right(sid, hanp, hlen, token, uflags, right); + rc = dm_respond_event(sid, token, response, reterror, buflen, respbufp); + rc = dm_send_msg(sid, msgtype, buflen, bufp); + rc = dm_set_disp(sid, hanp, hlen, token, eventsetp, maxevent); + rc = dm_set_dmattr(sid, hanp, hlen, + token, attrnamep, setdtime, buflen, bufp); + rc = dm_set_eventlist(sid, hanp, hlen, token, eventsetp, maxevent); + rc = dm_set_fileattr(sid, hanp, hlen, token, mask, attrp); + rc = dm_set_inherit(sid, hanp, hlen, token, attrnamep, mode); + rc = dm_set_region(sid, hanp, hlen, token, nelem, regbufp, exactflagp); + rc = dm_set_return_on_destroy(sid, hanp, hlen, + token, attrnamep, enable); + rc = dm_symlink_by_handle(sid, dirhanp, dirhlen, token, + hanp, hlen, cname, path); + rc = dm_sync_by_handle(sid, hanp, hlen, token); + rc = dm_upgrade_right(sid, hanp, hlen, token); + ssrc = dm_write_invis(sid, hanp, hlen, flags, token, off, len, bufp); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/make_rt_sparse.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/make_rt_sparse.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/make_rt_sparse.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/make_rt_sparse.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Create file with XFS_XFLAG_REALTIME set. + */ + +#include +#ifdef __sgi +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include + + +/* Note: In order to figure out the filesystem geometry, you have to run this + program as root. Creating the file itself can be done by anyone. +*/ + + +static char * prog; + +static void +Usage(void) +{ + fprintf(stderr,"Usage: %s filename\n", prog); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + xfs_fsop_geom_t geom; + struct fsxattr fsx; + struct dioattr dio; + char *pathname; + u_int buflen; + char *buf; + ssize_t offset; + ssize_t count; + int fd; + int i; + + if (prog = strrchr(argv[0], '/')) { + *prog++; + } else { + prog = argv[0]; + } + + if (argc != 2) + Usage(); + pathname = argv[1]; + + /* Create the file. */ + + if ((fd = open(pathname, O_RDWR|O_CREAT|O_EXCL|O_DIRECT, 0600)) < 0) { + fprintf(stderr,"%s: Cannot open %s, %s\n", prog, + pathname, strerror(errno)); + exit(1); + } + + /* Determine the filesystem's realtime partition geometry. */ + + if (syssgi(SGI_XFS_FSOPERATIONS, fd, XFS_FS_GEOMETRY, NULL, &geom)) { + fprintf(stderr,"%s: syssgi(,XFS_FS_GEOMETRY) failed, %s\n", + prog, strerror(errno)); + exit(1); + } + + /* Make the file a realtime file. */ + + fsx.fsx_xflags = 1; /*XFS_XFLAG_REALTIME*/ + fsx.fsx_extsize = 4 * geom.blocksize * geom.rtextsize; + if (fcntl(fd, F_FSSETXATTR, &fsx) < 0) { + fprintf(stderr,"%s: fcntl(,F_FSSETXATTR) failed, %s\n", prog, + strerror(errno)); + exit(1); + } + + /* Obtain the direct I/O parameters. */ + + if (fcntl(fd, F_DIOINFO, &dio) < 0) { + fprintf(stderr,"%s: fcntl(,F_DIOINFO) failed,%s\n", + prog, strerror(errno)); + exit(1); + } + fprintf(stdout, "%s: file %s direct io requirements.\n", prog, + pathname); + fprintf(stdout, "%7d memory alignment.\n", dio.d_mem); + fprintf(stdout, "%7d minimum io size.\n", dio.d_miniosz); + fprintf(stdout, "%7d maximum io size.\n", dio.d_maxiosz); + + if (fcntl(fd, F_FSGETXATTR, &fsx) < 0) { + fprintf(stderr,"%s: fcntl(,F_FSGETXATTR) failed, %s\n", prog, + strerror(errno)); + exit(1); + } + fprintf(stdout, "%7d realtime extent size.\n", fsx.fsx_extsize); + + /* Malloc and zero a buffer to use for writes. */ + + buflen = dio.d_miniosz; + if ((buf = memalign(dio.d_mem, buflen)) == NULL) { + fprintf(stderr,"%s: memalign(%d,%d) returned NULL\n", + prog, dio.d_mem, buflen); + exit(1); + } + memset(buf, '\0', buflen); + + for (i = 0; i < 10; i += 2) { + offset = i * fsx.fsx_extsize; + if (lseek(fd, offset, SEEK_SET) < 0) { + fprintf(stderr, "seek to %d failed, %s\n", offset, + strerror(errno)); + exit(1); + } + if ((count = write(fd, buf, buflen)) < 0) { + fprintf(stderr, "write of %d bytes failed at offset " + "%d, , %s\n", buflen, offset, strerror(errno)); + exit(1); + } + if (count != buflen) { + fprintf(stderr, "expected to write %d bytes at offset " + "%d, actually wrote %d\n", buflen, offset, + count); + exit(1); + } + } + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/make_sparse.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/make_sparse.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/make_sparse.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/make_sparse.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +static char * prog; + +static void +Usage(void) +{ + fprintf(stderr,"Usage: %s filename\n", prog); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + char *pathname; + u_int buflen; + char *buf; + ssize_t offset; + ssize_t count; + int fd; + int i; + + prog = argv[0]; + + if (argc != 2) + Usage(); + pathname = argv[1]; + + /* Create the file and make it a regular file. */ + + if ((fd = open(pathname, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0) { + fprintf(stderr,"%s: Cannot open %s, %s\n", prog, + pathname, strerror(errno)); + exit(1); + } + + /* Malloc and zero a buffer to use for writes. */ + + buflen = 1; + if ((buf = malloc(buflen)) == NULL) { + fprintf(stderr,"%s: malloc(%d) returned NULL\n", + prog, buflen); + exit(1); + } + memset(buf, '\0', buflen); + + for (i = 0; i < 200; i += 2) { + offset = i * 65536; + if (lseek(fd, offset, SEEK_SET) < 0) { + fprintf(stderr, "seek to %d failed, %s\n", offset, + strerror(errno)); + exit(1); + } + if ((count = write(fd, buf, buflen)) < 0) { + fprintf(stderr, "write of %d bytes failed at offset " + "%d, , %s\n", buflen, offset, strerror(errno)); + exit(1); + } + if (count != buflen) { + fprintf(stderr, "expected to write %d bytes at offset " + "%d, actually wrote %d\n", buflen, offset, + count); + exit(1); + } + } + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/obj_ref_hold.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/obj_ref_hold.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/obj_ref_hold.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/obj_ref_hold.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_obj_ref_hold(). The +command line is: + + obj_ref_hold {-F} [-s sid] token {pathname|handle} + +where: +-F + when a pathname is specified, -F indicates that its filesystem handle + should be used rather than its file object handle. +sid + is the dm_sessid_t to use rather than the default test session. +token + is the dm_token_t to use. +{pathname|handle} + is either a handle, or is the pathname of a file whose handle is + to be used. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-F] [-s sid] token {pathname|handle}\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t token; + char *object; + void *hanp; + size_t hlen; + int Fflag = 0; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "Fs:")) != EOF) { + switch (opt) { + case 'F': + Fflag++; + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) + usage(); + token = atol(argv[optind++]); + object = argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file or filesystem's handle. */ + + if (opaque_to_handle(object, &hanp, &hlen)) { + fprintf(stderr, "can't get handle from %s\n", object); + exit(1); + } + if (Fflag) { + void *fshanp; + size_t fshlen; + + if (dm_handle_to_fshandle(hanp, hlen, &fshanp, &fshlen)) { + fprintf(stderr, "can't get filesystem handle from %s\n", + object); + exit(1); + } + dm_handle_free(hanp, hlen); + hanp = fshanp; + hlen = fshlen; + } + + if (dm_obj_ref_hold(sid, token, hanp, hlen)) { + fprintf(stderr, "dm_obj_ref_hold failed, %s\n", + strerror(errno)); + return(1); + } + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/obj_ref_query.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/obj_ref_query.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/obj_ref_query.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/obj_ref_query.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_obj_ref_query(). The +command line is: + + obj_ref_query {-F} [-s sid] token {pathname|handle} + +where: +-F + when a pathname is specified, -F indicates that its filesystem handle + should be used rather than its file object handle. +sid + is the dm_sessid_t to use rather than the default test session. +token + is the dm_token_t to use. +{pathname|handle} + is either a handle, or is the pathname of a file whose handle is + to be used. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-F] [-s sid] token {pathname|handle}\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t token; + char *object; + void *hanp; + size_t hlen; + int Fflag = 0; + char *name; + int error; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "Fs:")) != EOF) { + switch (opt) { + case 'F': + Fflag++; + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) + usage(); + token = atol(argv[optind++]); + object = argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file or filesystem's handle. */ + + if (opaque_to_handle(object, &hanp, &hlen)) { + fprintf(stderr, "can't get handle from %s\n", object); + exit(1); + } + if (Fflag) { + void *fshanp; + size_t fshlen; + + if (dm_handle_to_fshandle(hanp, hlen, &fshanp, &fshlen)) { + fprintf(stderr, "can't get filesystem handle from %s\n", + object); + exit(1); + } + dm_handle_free(hanp, hlen); + hanp = fshanp; + hlen = fshlen; + } + + if ((error = dm_obj_ref_query(sid, token, hanp, hlen)) < 0) { + fprintf(stderr, "dm_obj_ref_query failed, %s\n", + strerror(errno)); + return(1); + } + + if (error == 1) { + fprintf(stdout, "there is a hold\n"); + } else { + fprintf(stdout, "there is no hold\n"); + } + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/obj_ref_rele.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/obj_ref_rele.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/obj_ref_rele.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/obj_ref_rele.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_obj_ref_rele(). The +command line is: + + obj_ref_rele {-F} [-s sid] token {pathname|handle} + +where: +-F + when a pathname is specified, -F indicates that its filesystem handle + should be used rather than its file object handle. +sid + is the dm_sessid_t to use rather than the default test session. +token + is the dm_token_t to use. +{pathname|handle} + is either a handle, or is the pathname of a file whose handle is + to be used. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-F] [-s sid] token {pathname|handle}\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t token; + char *object; + void *hanp; + size_t hlen; + int Fflag = 0; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "Fs:")) != EOF) { + switch (opt) { + case 'F': + Fflag++; + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) + usage(); + token = atol(argv[optind++]); + object = argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file or filesystem's handle. */ + + if (opaque_to_handle(object, &hanp, &hlen)) { + fprintf(stderr, "can't get handle from %s\n", object); + exit(1); + } + if (Fflag) { + void *fshanp; + size_t fshlen; + + if (dm_handle_to_fshandle(hanp, hlen, &fshanp, &fshlen)) { + fprintf(stderr, "can't get filesystem handle from %s\n", + object); + exit(1); + } + dm_handle_free(hanp, hlen); + hanp = fshanp; + hlen = fshlen; + } + + if (dm_obj_ref_rele(sid, token, hanp, hlen)) { + fprintf(stderr, "dm_obj_ref_rele failed, %s\n", + strerror(errno)); + return(1); + } + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/path_to_fshandle.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/path_to_fshandle.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/path_to_fshandle.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/path_to_fshandle.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* Given a file object's pathname, print the filesystem handle. */ + +#include + +#include + +/*--------------------------------------------------------------------------- + +Test program used to test dm_path_to_fshandle(). The command line is: + + path_to_fshandle pathname + +where pathname is the name of a file, directory, or symlink. + +----------------------------------------------------------------------------*/ + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s pathname\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + char *pathname; + char *name; + void *fshanp; + size_t fshlen; + char buffer[100]; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + if (argc != 2) + usage(); + pathname = argv[1]; + + (void)dm_init_service(&name); + + if (dm_path_to_fshandle(pathname, &fshanp, &fshlen) != 0) { + fprintf(stderr, "dm_path_to_fshandle failed, %s\n", + strerror(errno)); + return(1); + } + hantoa(fshanp, fshlen, buffer); + fprintf(stdout, "%s\n", buffer); + + dm_handle_free(fshanp, fshlen); + return(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/path_to_handle.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/path_to_handle.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/path_to_handle.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/path_to_handle.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* Given a file object's pathname, print the object's handle. */ + +#include + +#include + +/*--------------------------------------------------------------------------- + +Test program used to test dm_path_to_handle(). The command line is: + + path_to_handle pathname + +where pathname is the name of a file, directory, or symlink. + +----------------------------------------------------------------------------*/ + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s pathname\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + char *pathname; + char *name; + void *hanp; + size_t hlen; + char buffer[100]; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + if (argc != 2) + usage(); + pathname = argv[1]; + + (void)dm_init_service(&name); + + if (dm_path_to_handle(pathname, &hanp, &hlen) != 0) { + fprintf(stderr, "dm_path_to_handle failed, %s\n", + strerror(errno)); + return(1); + } + hantoa(hanp, hlen, buffer); + fprintf(stdout, "%s\n", buffer); + + dm_handle_free(hanp, hlen); + return(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/pending.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/pending.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/pending.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/pending.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_pending(). The +command line is: + + pending sid token + +where sid is the session ID whose event you are responding to. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s sid token\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid; + char *name; + dm_token_t token; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + if (argc != 3) + usage(); + + sid = atol(argv[1]); + token = atol(argv[2]); + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + + if (dm_pending(sid, token, NULL)) { + fprintf(stderr, "dm_pending failed, %s\n", strerror(errno)); + exit(1); + } + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/print_event.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/print_event.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/print_event.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/print_event.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,1192 @@ + + +/* + * eventloop.c + * + * Joseph Jackson + * 25-Jun-1996 + * + * Monitor all events for a file system. + * When one arrives, print a message with all the details. + * If the message is synchronous, always reply with DM_RESP_CONTINUE + * (This program doesn't perform any real file system or HSM work.) + * + * This is a simplification of the "migin.c" example program. + * The original code was by Peter Lawthers: + * This code was written by Peter Lawthers, and placed in the public + * domain for use by DMAPI implementors and app writers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + /* + * Define some standard formats for the printf statements below. + */ + +#define HDR "%s: token %d sequence %d\n" +#define VALS "\t%-15s %s\n" +#define VALD "\t%-15s %d\n" +#define VALLLD "\t%-15s %lld\n" + +extern int optind; +extern int errno; + +void usage (char *); +int main (int, char **); +static void event_loop (dm_sessid_t, int); +int handle_message (dm_sessid_t, dm_eventmsg_t *); +static int format_mode(mode_t mode, char **ptr); +static int get_fs_handle (char *, void **, size_t *); +static int set_disposition(dm_sessid_t, void *, size_t); +static int set_events (dm_sessid_t, void *, size_t); +static int clear_events (dm_sessid_t, void *, size_t); +int finish_responding(dm_sessid_t); +int establish_handler(void); +void exit_handler (int); + +#define MAXNAMELEN 256 + +/* + * Keep these global so the exit_handler and err_msg routines can get to them + */ +char *Progname; +int Sleep = 0; +int Verbose; +dm_sessid_t sid = 0; +dm_sessid_t oldsid = 0; +char *fsname; + + +void +usage( + char *prog) +{ + fprintf(stderr, "Usage: %s ", prog); + fprintf(stderr, " <-S oldsid> <-v verbose> "); + fprintf(stderr, "filesystem \n"); +} + + +int +main( + int argc, + char *argv[]) +{ + + int c; + int error; + void *fs_hanp; + size_t fs_hlen; + + +/* Progname = argv[0];*/ Progname = "print_event"; + fsname = NULL; + + while ((c = getopt(argc, argv, "vs:S:")) != EOF) { + switch (c) { + case 's': + Sleep = atoi(optarg); + break; + case 'S': + oldsid = atoi(optarg); + break; + case 'v': + Verbose = 1; + break; + case '?': + default: + usage(Progname); + exit(1); + } + } + if (optind >= argc) { + usage(Progname); + exit(1); + } + fsname = argv[optind]; + if (fsname == NULL) { + usage(Progname); + exit(1); + } + + /* + * Establish an exit handler + */ + error = establish_handler(); + if (error) + exit(1); + + /* + * Init the dmapi, and get a filesystem handle so + * we can set up our events + */ + + if (oldsid) { + sid = oldsid; + } else { + error = setup_dmapi(&sid); + if (error) + exit(1); + } + + error = get_fs_handle(fsname, &fs_hanp, &fs_hlen); + if (error) + goto cleanup; + + /* + * Set the event disposition so that our session will receive + * all the events for the given file system + */ + error = set_disposition(sid, fs_hanp, fs_hlen); + if (error) + goto cleanup; + + /* + * Enable monitoring for all events in the given file system + */ + error = set_events(sid, fs_hanp, fs_hlen); + if (error) + goto cleanup; + + /* + * Now sit in an infinite loop, reporting on any events that occur. + * The program is exited after a signal through exit_handler(). + */ + printf("\n"); + event_loop(sid, 1 /*waitflag*/); + + /* + * If we get here, cleanup after the event_loop failure + */ + cleanup: + exit_handler(0); + return(1); +} + + +/* + * Main event loop processing + * + * The waitflag argument is set to 1 when we call this from main(). + * In this case, continuously process incoming events, + * blocking if there are none available. + * In the exit_handler(), call this routine with waitflag=0. + * Just try to read the events once in this case with no blocking. + */ + +static void +event_loop( + dm_sessid_t sid, + int waitflag) +{ + void *msgbuf; + size_t bufsize; + int error; + dm_eventmsg_t *msg; + int count; + + /* + * We take a swag at a buffer size. If it's wrong, we can + * always resize it + */ + + bufsize = sizeof(dm_eventmsg_t) + sizeof(dm_data_event_t) + HANDLE_LEN; + bufsize *= 50; + msgbuf = (void *)malloc(bufsize); + if (msgbuf == NULL) { + err_msg("Can't allocate memory for buffer"); + return; + } + + for (;;) { + error = dm_get_events(sid, ALL_AVAIL_MSGS, + waitflag ? DM_EV_WAIT:0, bufsize, msgbuf, &bufsize); + if (error) { + if (errno == EAGAIN) { + if (waitflag) + continue; + break; + } + if (errno == E2BIG) { + free(msgbuf); + msgbuf = (void *)malloc(bufsize); + if (msgbuf == NULL) { + err_msg("Can't resize msg buffer"); + return; + } + continue; + } + errno_msg("Error getting events from DMAPI (%d)", errno); + break; + } + + /* + * Walk through the message buffer, pull out each individual + * message, and dispatch the messages to handle_message(), + * which will respond to the events. + */ + + count = 0; + msg = (dm_eventmsg_t *)msgbuf; + while (msg != NULL ) { + count++; + error = handle_message(sid, msg); + if (error) { + free(msgbuf); + return; + } + msg = DM_STEP_TO_NEXT(msg, dm_eventmsg_t *); + } + if (count != 1 && Verbose) { + err_msg("Found %d events in one call to " + "dm_get_events\n", count); + } + } + if (msgbuf != NULL) + free(msgbuf); +} + + +void +print_one_mount_event( + void *msg) +{ + void *hanp1, *hanp2, *hanp3; + size_t hlen1, hlen2, hlen3; + char hans1[HANDLE_STR], hans2[HANDLE_STR], hans3[HANDLE_STR]; + void *namp1, *namp2; + size_t nlen1, nlen2; + char nams1[MAXNAMELEN], nams2[MAXNAMELEN]; + mode_t mode; + +#if VERITAS_21 + dm_namesp_event_t *msg_ne = (dm_namesp_event_t *)msg; + +/* + msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *); +*/ + hanp1 = DM_GET_VALUE(msg_ne, ne_handle1, void *); + hlen1 = DM_GET_LEN (msg_ne, ne_handle1); + hanp2 = DM_GET_VALUE(msg_ne, ne_handle2, void *); + hlen2 = DM_GET_LEN (msg_ne, ne_handle2); + namp1 = DM_GET_VALUE(msg_ne, ne_name1, void *); + nlen1 = DM_GET_LEN (msg_ne, ne_name1); + namp2 = DM_GET_VALUE(msg_ne, ne_name2, void *); + nlen2 = DM_GET_LEN (msg_ne, ne_name2); + hanp3 = NULL; + hlen3 = 0; + mode = msg_ne->ne_mode; +#else + dm_mount_event_t *msg_me = (dm_mount_event_t *)msg; + + hanp1 = DM_GET_VALUE(msg_me, me_handle1, void *); + hlen1 = DM_GET_LEN(msg_me, me_handle1); + hanp2 = DM_GET_VALUE(msg_me, me_handle2, void *); + hlen2 = DM_GET_LEN(msg_me, me_handle2); + namp1 = DM_GET_VALUE(msg_me, me_name1, void *); + nlen1 = DM_GET_LEN(msg_me, me_name1); + namp2 = DM_GET_VALUE(msg_me, me_name2, void *); + nlen2 = DM_GET_LEN(msg_me, me_name2); + hanp3 = DM_GET_VALUE(msg_me, me_roothandle, void *); + hlen3 = DM_GET_LEN(msg_me, me_roothandle); + mode = msg_me->me_mode; +#endif /* VERITAS_21 */ + + if (hanp1 && hlen1) { + hantoa(hanp1, hlen1, hans1); + } else { + sprintf(hans1, "", hlen1); + } + if (hanp2 && hlen2) { + hantoa(hanp2, hlen2, hans2); + } else { + sprintf(hans2, "", hlen2); + } + if (hanp3 && hlen3) { + hantoa(hanp3, hlen3, hans3); + } else { + sprintf(hans3, "", hlen3); + } + if (namp1 && nlen1) { + strncpy(nams1, namp1, nlen1); + if (nlen1 != sizeof(nams1)) + nams1[nlen1] = '\0'; + } else { + sprintf(nams1, "", nlen1); + } + if (namp2 && nlen2) { + strncpy(nams2, namp2, nlen2); + if (nlen2 != sizeof(nams2)) + nams2[nlen2] = '\0'; + } else { + sprintf(nams2, "", nlen2); + } + + printf(VALS VALS VALS VALS VALS VALD, + "fs handle", hans1, + "mtpt handle", hans2, + "mtpt path", nams1, + "media desig", nams2, + "root handle", hans3, + "mode", mode); +} + + +/* + * First, weed out the events which return interesting structures. + * If it's not one of those, unpack the dm_namesp_event structure + * and display the contents. + */ +int +handle_message( + dm_sessid_t sid, + dm_eventmsg_t *msg) +{ + int pkt_error = 0; + int error; + dm_response_t response; + int respond, respcode; + dm_namesp_event_t *msg_ne; +#if !VERITAS_21 + dm_mount_event_t *msg_me; +#endif + void *hanp1, *hanp2, *namp1, *namp2; + u_int hlen1, hlen2, nlen1, nlen2; + char hans1[HANDLE_STR], hans2[HANDLE_STR]; + char nams1[MAXNAMELEN], nams2[MAXNAMELEN]; + + /* + * Set the defaults for responding to events + */ + respond = 1; + response = DM_RESP_CONTINUE; + respcode = 0; + + /***** USER EVENTS *****/ + + if (msg->ev_type == DM_EVENT_USER) { + char *privp; + u_int plen, i; + + printf(HDR, + "user", msg->ev_token, msg->ev_sequence); + + /* print private data as ascii or hex if it exists DM_CONFIG_MAX_MESSAGE_DATA */ + + privp = DM_GET_VALUE(msg, ev_data, char *); + plen = DM_GET_LEN (msg, ev_data); + if (plen) { + for (i = 0; i < plen; i++) { + if (!isprint(privp[i]) && !isspace(privp[i])) + break; + } + if (i == plen - 1 && privp[i] == '\0') { + printf(VALS, + "privdata", privp); + } else { + printf("\t%-15s ", "privdata"); + for (i = 0; i < plen; i++) { + printf("%.2x", privp[i]); + } + printf("\n"); + } + } else { + printf(VALS, + "privdata", ""); + } + + if (msg->ev_token == DM_INVALID_TOKEN) /* async dm_send_msg event */ + respond = 0; + } + + /***** CANCEL EVENT *****/ + +/* Not implemented on SGI or Veritas */ + + else if (msg->ev_type == DM_EVENT_CANCEL) { + dm_cancel_event_t *msg_ce; + + msg_ce = DM_GET_VALUE(msg, ev_data, dm_cancel_event_t *); + printf(HDR VALD VALD, + "cancel", msg->ev_token, msg->ev_sequence, + "sequence", msg_ce->ce_sequence, + "token", msg_ce->ce_token); + respond = 0; + } + + /***** DATA EVENTS *****/ + + else if (msg->ev_type == DM_EVENT_READ || + msg->ev_type == DM_EVENT_WRITE || + msg->ev_type == DM_EVENT_TRUNCATE) { + dm_data_event_t *msg_de; + + msg_de = DM_GET_VALUE(msg, ev_data, dm_data_event_t *); + hanp1 = DM_GET_VALUE(msg_de, de_handle, void *); + hlen1 = DM_GET_LEN (msg_de, de_handle); + if (hanp1 && hlen1) { + hantoa(hanp1, hlen1, hans1); + } else { + sprintf(hans1, "", hlen1); + } + + switch(msg->ev_type) { + + case DM_EVENT_READ: + printf(HDR VALS VALLLD VALLLD, + "read", msg->ev_token, msg->ev_sequence, + "file handle", hans1, + "offset", msg_de->de_offset, + "length", msg_de->de_length); + break; + + case DM_EVENT_WRITE: + printf(HDR VALS VALLLD VALLLD, + "write", msg->ev_token, msg->ev_sequence, + "file handle", hans1, + "offset", msg_de->de_offset, + "length", msg_de->de_length); + break; + + case DM_EVENT_TRUNCATE: + printf(HDR VALS VALLLD VALLLD, + "truncate", msg->ev_token, msg->ev_sequence, + "file handle", hans1, + "offset", msg_de->de_offset, + "length", msg_de->de_length); + break; + default: break; + } + } + + /***** DESTROY EVENT *****/ + + else if (msg->ev_type == DM_EVENT_DESTROY) { + dm_destroy_event_t *msg_ds; + char attrname[DM_ATTR_NAME_SIZE + 1]; + u_char *copy; + u_int clen; + u_int i; + + msg_ds= DM_GET_VALUE(msg, ev_data, dm_destroy_event_t *); + hanp1 = DM_GET_VALUE(msg_ds, ds_handle, void *); + hlen1 = DM_GET_LEN (msg_ds, ds_handle); + if (hanp1 && hlen1) { + hantoa(hanp1, hlen1, hans1); + } else { + sprintf(hans1, "", hlen1); + } + if (msg_ds->ds_attrname.an_chars[0] != '\0') { + strncpy(attrname, (char *)msg_ds->ds_attrname.an_chars, sizeof(attrname)); + } else { + strcpy(attrname, ""); + } + printf(HDR VALS VALS, + "destroy", msg->ev_token, msg->ev_sequence, + "handle", hans1, + "attrname", attrname); + copy = DM_GET_VALUE(msg_ds, ds_attrcopy, u_char *); + clen = DM_GET_LEN (msg_ds, ds_attrcopy); + if (copy && clen) { + printf("\t%-15s ", "attrcopy"); + for (i = 0; i < clen; i++) { + printf("%.2x", copy[i]); + } + printf("\n"); + } else { + printf(VALS, "attrcopy", ""); + } + respond = 0; + } + + /***** MOUNT EVENT *****/ + + else if (msg->ev_type == DM_EVENT_MOUNT) { + printf(HDR, "mount", msg->ev_token, msg->ev_sequence); +#if !VERITAS_21 + msg_me = DM_GET_VALUE(msg, ev_data, dm_mount_event_t *); + print_one_mount_event(msg_me); +#else /* VERITAS_21 */ + msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *); + print_one_mount_event(msg_ne); +#endif /* VERITAS_21 */ + } + + /***** NAMESPACE EVENTS *****/ + + else { + char *type; + + msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *); + hanp1 = DM_GET_VALUE(msg_ne, ne_handle1, void *); + hlen1 = DM_GET_LEN (msg_ne, ne_handle1); + hanp2 = DM_GET_VALUE(msg_ne, ne_handle2, void *); + hlen2 = DM_GET_LEN (msg_ne, ne_handle2); + namp1 = DM_GET_VALUE(msg_ne, ne_name1, void *); + nlen1 = DM_GET_LEN (msg_ne, ne_name1); + namp2 = DM_GET_VALUE(msg_ne, ne_name2, void *); + nlen2 = DM_GET_LEN (msg_ne, ne_name2); + + if (hanp1 && hlen1) { + hantoa(hanp1, hlen1, hans1); + } + if (hanp2 && hlen2) { + hantoa(hanp2, hlen2, hans2); + } + if (namp1 && nlen1) { + strncpy(nams1, namp1, nlen1); + if (nlen1 != sizeof(nams1)) + nams1[nlen1] = '\0'; + } + if (namp2 && nlen2) { + strncpy(nams2, namp2, nlen2); + if (nlen2 != sizeof(nams2)) + nams2[nlen2] = '\0'; + } + + if (msg->ev_type == DM_EVENT_PREUNMOUNT || + msg->ev_type == DM_EVENT_UNMOUNT) { + if (msg_ne->ne_mode == 0) { + type = "NOFORCE"; +#if !VERITAS_21 + } else if (msg_ne->ne_mode == DM_UNMOUNT_FORCE) { +#else + } else if (msg_ne->ne_mode > 0) { +#endif + type = "FORCE"; + } else { + type = "UNKNOWN"; + pkt_error++; + } + } else if (msg->ev_type == DM_EVENT_CREATE || + msg->ev_type == DM_EVENT_POSTCREATE || + msg->ev_type == DM_EVENT_REMOVE || + msg->ev_type == DM_EVENT_POSTREMOVE) { + if (format_mode(msg_ne->ne_mode, &type)) { + pkt_error++; + } + } + + switch(msg->ev_type) { + + case DM_EVENT_PREUNMOUNT: + printf(HDR VALS VALS VALS, + "preunmount", msg->ev_token, msg->ev_sequence, + "fs handle", hans1, + "root dir", hans2, + "unmount mode", type); + break; + + case DM_EVENT_UNMOUNT: + printf(HDR VALS VALS VALD, + "unmount", msg->ev_token, msg->ev_sequence, + "fs handle", hans1, + "unmount mode", type, + "retcode", msg_ne->ne_retcode); + break; + + case DM_EVENT_NOSPACE: + printf(HDR VALS, + "nospace", msg->ev_token, msg->ev_sequence, + "fs handle", hans1); + response = DM_RESP_ABORT; + respcode = ENOSPC; + break; + + case DM_EVENT_DEBUT: /* not supported on SGI */ + printf(HDR VALS, + "debut", msg->ev_token, msg->ev_sequence, + "object", hans1); + break; + + case DM_EVENT_CREATE: + printf(HDR VALS VALS VALS, + "create", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "mode bits", type); + break; + + case DM_EVENT_POSTCREATE: + printf(HDR VALS VALS VALS VALS VALD, + "postcreate", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "new object", hans2, + "name", nams1, + "mode bits", type, + "retcode", msg_ne->ne_retcode); + respond = 0; + break; + + case DM_EVENT_REMOVE: + printf(HDR VALS VALS VALS, + "remove", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "mode bits", type); + break; + + case DM_EVENT_POSTREMOVE: + printf(HDR VALS VALS VALS VALD, + "postremove", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "mode bits", type, + "retcode", msg_ne->ne_retcode); + respond = 0; + break; + + case DM_EVENT_RENAME: + printf(HDR VALS VALS VALS VALS, + "rename", msg->ev_token, msg->ev_sequence, + "old parent", hans1, + "new parent", hans2, + "old name", nams1, + "new name", nams2); + break; + + case DM_EVENT_POSTRENAME: + printf(HDR VALS VALS VALS VALS VALD, + "postrename", msg->ev_token, msg->ev_sequence, + "old parent", hans1, + "new parent", hans2, + "old name", nams1, + "new name", nams2, + "retcode", msg_ne->ne_retcode); + respond = 0; + break; + + case DM_EVENT_SYMLINK: + printf(HDR VALS VALS VALS, + "symlink", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "contents", nams2); + break; + + case DM_EVENT_POSTSYMLINK: + printf(HDR VALS VALS VALS VALS VALD, + "postsymlink", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "new object", hans2, + "name", nams1, + "contents", nams2, + "retcode", msg_ne->ne_retcode); + respond = 0; + break; + + case DM_EVENT_LINK: + printf(HDR VALS VALS VALS, + "link", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "source", hans2, + "name", nams1); + break; + + case DM_EVENT_POSTLINK: + printf(HDR VALS VALS VALS VALD, + "postlink", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "source", hans2, + "name", nams1, + "retcode", msg_ne->ne_retcode); + respond = 0; + break; + + case DM_EVENT_ATTRIBUTE: + printf(HDR VALS, + "attribute", msg->ev_token, msg->ev_sequence, + "object", hans1); + respond = 0; + break; + + case DM_EVENT_CLOSE: /* not supported on SGI */ + printf(HDR VALS, + "close", msg->ev_token, msg->ev_sequence, + "object", hans1); + respond = 0; + break; + + default: + pkt_error++; + printf(HDR VALD, + "", msg->ev_token, msg->ev_sequence, + "ev_type", msg->ev_type); + if (msg->ev_token == DM_INVALID_TOKEN) + respond = 0; + break; + } + } + + /* + * Now respond to those messages which require a response + */ + if (respond) { + error = dm_respond_event(sid, msg->ev_token, response, respcode, 0, 0); + if (error) { + errno_msg("Can't respond to event"); + return error; + } + if (Sleep) { + err_msg("Sleeping for %d seconds!\n", Sleep); + sleep(Sleep); + } + } + + return 0; +} + + +/* + Convert a mode_t field into a printable string. + + Returns non-zero if the mode_t is invalid. The string is + returned in *ptr, whether there is an error or not. +*/ + +static int +format_mode( + mode_t mode, + char **ptr) +{ +static char modestr[100]; + char *typestr; + int error = 0; + + if (S_ISFIFO(mode)) typestr = "FIFO"; + else if(S_ISCHR (mode)) typestr = "Character Device"; + else if(S_ISBLK (mode)) typestr = "Block Device"; + else if(S_ISDIR (mode)) typestr = "Directory"; + else if(S_ISREG (mode)) typestr = "Regular File"; + else if(S_ISLNK (mode)) typestr = "Symbolic Link"; + else if(S_ISSOCK(mode)) typestr = "Socket"; + else { + typestr = ""; + error++; + } + + sprintf(modestr, "mode %06o: perm %c%c%c %c%c%c %c%c%c %c%c%c, type %s", + mode, + mode & S_ISUID ? 's':' ', + mode & S_ISGID ? 'g':' ', + mode & S_ISVTX ? 't':' ', + mode & S_IRUSR ? 'r':'-', + mode & S_IWUSR ? 'w':'-', + mode & S_IXUSR ? 'x':'-', + mode & S_IRGRP ? 'r':'-', + mode & S_IWGRP ? 'w':'-', + mode & S_IXGRP ? 'x':'-', + mode & S_IROTH ? 'r':'-', + mode & S_IWOTH ? 'w':'-', + mode & S_IXOTH ? 'x':'-', + typestr); + *ptr = modestr; + return(error); +} + + +static int +get_fs_handle( + char *fsname, + void **fs_hanpp, + size_t *fs_hlenp) +{ + char hans[HANDLE_STR]; + + if (dm_path_to_fshandle(fsname, fs_hanpp, fs_hlenp) == -1) { + errno_msg("Can't get filesystem handle"); + return 1; + } + if (Verbose) { + hantoa(*fs_hanpp, *fs_hlenp, hans); + err_msg("File system handle for %s: %s\n", fsname, hans); + } + return 0; +} + + +/* + Set the event disposition for this filesystem to include all valid + DMAPI events so that we receive all events for this filesystem. + Also set DM_EVENT_MOUNT disposition for the global handle. + It does not make sense to specify DM_EVENT_USER in the disposition + mask since a session is always unconditionally registered for these + events. + + Returns non-zero on error. +*/ + +static int +set_disposition( + dm_sessid_t sid, + void *fs_hanp, + size_t fs_hlen) +{ + dm_eventset_t eventlist; + + if (Verbose) { + err_msg("Setting event disposition to send all " + "events to this session\n"); + } + + /* DM_EVENT_MOUNT must be sent in a separate request using the global + handle. If we ever support more than one filesystem at a time, this + request should be moved out of this routine to a place where it is + issued just once. + */ + + DMEV_ZERO(eventlist); + DMEV_SET(DM_EVENT_MOUNT, eventlist); + + if (dm_set_disp(sid, DM_GLOBAL_HANP, DM_GLOBAL_HLEN, DM_NO_TOKEN, + &eventlist, DM_EVENT_MAX) == -1) { + errno_msg("Can't set event disposition for mount"); + return(1); + } + + DMEV_ZERO(eventlist); + + /* File system administration events. */ + + DMEV_SET(DM_EVENT_PREUNMOUNT, eventlist); + DMEV_SET(DM_EVENT_UNMOUNT, eventlist); + DMEV_SET(DM_EVENT_NOSPACE, eventlist); + + /* While DM_EVENT_DEBUT is optional, it appears that the spec always + lets it be specified in a dm_set_disp call; its just that the + event will never be seen on some platforms. + */ + + DMEV_SET(DM_EVENT_DEBUT, eventlist); + + + /* Namespace events. */ + + DMEV_SET(DM_EVENT_CREATE, eventlist); + DMEV_SET(DM_EVENT_POSTCREATE, eventlist); + DMEV_SET(DM_EVENT_REMOVE, eventlist); + DMEV_SET(DM_EVENT_POSTREMOVE, eventlist); + DMEV_SET(DM_EVENT_RENAME, eventlist); + DMEV_SET(DM_EVENT_POSTRENAME, eventlist); + DMEV_SET(DM_EVENT_LINK, eventlist); + DMEV_SET(DM_EVENT_POSTLINK, eventlist); + DMEV_SET(DM_EVENT_SYMLINK, eventlist); + DMEV_SET(DM_EVENT_POSTSYMLINK, eventlist); + + /* Managed region data events. */ + + DMEV_SET(DM_EVENT_READ, eventlist); + DMEV_SET(DM_EVENT_WRITE, eventlist); + DMEV_SET(DM_EVENT_TRUNCATE, eventlist); + + /* Metadata events. */ + + DMEV_SET(DM_EVENT_ATTRIBUTE, eventlist); +#if ! defined ( __sgi ) && ! defined ( VERITAS_21 ) && !defined(linux) + DMEV_SET(DM_EVENT_CANCEL, eventlist); /* not supported on SGI */ +#endif +#if !defined( __sgi) && !defined(linux) + DMEV_SET(DM_EVENT_CLOSE, eventlist); /* not supported on SGI */ +#endif + DMEV_SET(DM_EVENT_DESTROY, eventlist); + + /* Pseudo-events. */ + + /* DM_EVENT_USER - always enabled - causes EINVAL if specified */ + + if (dm_set_disp(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, + &eventlist, DM_EVENT_MAX) == -1) { + errno_msg("Can't set event disposition for filesystem"); + return(1); + } + return(0); +} + + +/* + Enable event generation on each valid filesystem-based DMAPI event + within the given file system. + + Returns non-zero on errors. +*/ + +static int +set_events( + dm_sessid_t sid, + void *fs_hanp, + size_t fs_hlen) +{ + dm_eventset_t eventlist; + + if (Verbose) { + err_msg("Setting event list to enable all events " + "for this file system\n"); + } + DMEV_ZERO(eventlist); + + /* File system administration events. */ + + /* DM_EVENT_MOUNT - always enabled on the global handle - causes + EINVAL if specified. + */ + DMEV_SET(DM_EVENT_PREUNMOUNT, eventlist); + DMEV_SET(DM_EVENT_UNMOUNT, eventlist); + DMEV_SET(DM_EVENT_NOSPACE, eventlist); + /* DM_EVENT_DEBUT - always enabled - causes EINVAL if specified. */ + + /* Namespace events. */ + + DMEV_SET(DM_EVENT_CREATE, eventlist); + DMEV_SET(DM_EVENT_POSTCREATE, eventlist); + DMEV_SET(DM_EVENT_REMOVE, eventlist); + DMEV_SET(DM_EVENT_POSTREMOVE, eventlist); + DMEV_SET(DM_EVENT_RENAME, eventlist); + DMEV_SET(DM_EVENT_POSTRENAME, eventlist); + DMEV_SET(DM_EVENT_LINK, eventlist); + DMEV_SET(DM_EVENT_POSTLINK, eventlist); + DMEV_SET(DM_EVENT_SYMLINK, eventlist); + DMEV_SET(DM_EVENT_POSTSYMLINK, eventlist); + + /* Managed region data events. These are not settable by + dm_set_eventlist on a filesystem basis. They are meant + to be set using dm_set_region on regular files only. + However, in the SGI implementation, they are filesystem-settable. + Since this is useful for testing purposes, do it. + */ + + /* DM_EVENT_READ */ + /* DM_EVENT_WRITE */ + /* DM_EVENT_TRUNCATE */ + + /* Metadata events. */ + + DMEV_SET(DM_EVENT_ATTRIBUTE, eventlist); +#if ! defined ( __sgi ) && ! defined ( VERITAS_21 ) && ! defined(linux) + DMEV_SET(DM_EVENT_CANCEL, eventlist); /* not supported on SGI */ +#endif +#if !defined( __sgi) && !defined(linux) + DMEV_SET(DM_EVENT_CLOSE, eventlist); /* not supported on SGI */ +#endif + DMEV_SET(DM_EVENT_DESTROY, eventlist); + + /* Pseudo-events. */ + + /* DM_EVENT_USER - always enabled - causes EINVAL if specified */ + + if (dm_set_eventlist(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, + &eventlist, DM_EVENT_MAX) == -1) { + errno_msg("Can't set event list"); + return(1); + } + return(0); +} + + +/* + Disable monitoring for all events in the DMAPI for the given + file system. This is done before exiting so that future + operations won't hang waiting for their events to be handled. + + Returns non-zero on errors. +*/ + +static int +clear_events( + dm_sessid_t sid, + void *fs_hanp, + size_t fs_hlen) +{ + dm_eventset_t eventlist; + + if (Verbose) { + err_msg("Clearing event list to disable all events " + "for this filesystem\n"); + } + DMEV_ZERO(eventlist); + + if (dm_set_eventlist(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, + &eventlist, DM_EVENT_MAX) == -1) { + errno_msg("Can't clear event list"); + return(1); + } + return(0); +} + + +/* + * Respond to any events which haven't been handled yet. + * dm_getall_tokens provides a list of tokens for the outstanding events. + * dm_find_eventmsg uses the token to lookup the corresponding message. + * The message is passed to handle_message() for normal response processing. + */ +int +finish_responding( + dm_sessid_t sid) +{ + int error = 0; + u_int nbytes, ntokens = 0, ret_ntokens, i; + dm_token_t *tokenbuf = NULL; + size_t buflen, ret_buflen; + char *msgbuf = NULL; + dm_eventmsg_t *msg; + + if (Verbose) + err_msg("Responding to any outstanding delivered event messages\n"); + + /* + * Initial sizes for the token and message buffers + */ + ret_buflen = 16 * (sizeof(dm_eventmsg_t) + sizeof(dm_data_event_t) + + HANDLE_LEN); + ret_ntokens = 16; + + /* + * The E2BIG dance... + * Take a guess at how large to make the buffer, starting with ret_ntokens. + * If the routine returns E2BIG, use the returned size and try again. + * If we're already using the returned size, double it and try again. + */ + do { + ntokens = (ntokens != ret_ntokens) ? ret_ntokens : ntokens*2; + nbytes = ntokens * (sizeof(dm_token_t) + sizeof(dm_vardata_t)); + tokenbuf = malloc(nbytes); + if (tokenbuf == NULL) { + err_msg("Can't malloc %d bytes for tokenbuf\n", nbytes); + error = 1; + goto out; + } + error = dm_getall_tokens(sid, ntokens, tokenbuf, &ret_ntokens); + } while (error && errno == E2BIG); + + if (error) { + errno_msg("Can't get all outstanding tokens"); + goto out; + } + + for (i = 0; i < ret_ntokens; i++) { + if (Verbose) + err_msg("Responding to outstanding event for token %d\n",(int)*tokenbuf); + + /* + * The E2BIG dance reprise... + */ + do { + buflen = (buflen != ret_buflen) ? ret_buflen : buflen * 2; + msgbuf = malloc(buflen); + if (msgbuf == NULL) { + err_msg("Can't malloc %d bytes for msgbuf\n", buflen); + error = 1; + goto out; + } + error = dm_find_eventmsg(sid, *tokenbuf, buflen, msgbuf, &ret_buflen); + } while (error && errno == E2BIG); + if (error) { + errno_msg("Can't find the event message for token %d", (int)*tokenbuf); + goto out; + } + + msg = (dm_eventmsg_t *) msgbuf; + while (msg != NULL) { + error = handle_message(sid, msg); + if (error) + goto out; + msg = DM_STEP_TO_NEXT(msg, dm_eventmsg_t *); + } + + tokenbuf++; + } + + out: + if (tokenbuf) + free(tokenbuf); + if (msgbuf) + free(msgbuf); + return error; +} + + +/* + * Establish an exit handler since we run in an infinite loop + */ +int +establish_handler(void) +{ + struct sigaction act; + + /* + * Set up signals so that we can wait for spawned children + */ + act.sa_handler = exit_handler; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + + (void)sigaction(SIGHUP, &act, NULL); + (void)sigaction(SIGINT, &act, NULL); + (void)sigaction(SIGQUIT, &act, NULL); + (void)sigaction(SIGTERM, &act, NULL); + (void)sigaction(SIGUSR1, &act, NULL); + (void)sigaction(SIGUSR1, &act, NULL); + (void)sigaction(SIGUSR2, &act, NULL); + + return(0); +} + + +/* + * Exit gracefully + * + * Stop events from being generated for the given file system + * Respond to any events that were delivered but unanswered + * (the event loop may have been in the middle of taking care of the event) + * Try getting any undelivered events but don't block if none are there + * (the file system may have generated an event after we killed dm_get_events) + * Shutdown the session using the global "sid" variable. + */ +void +exit_handler(int x) +{ + int error; + void *fs_hanp; + size_t fs_hlen; + + if (Verbose) + printf("\n"), + err_msg("Exiting...\n"); + + error = get_fs_handle(fsname, &fs_hanp, &fs_hlen); + + if (!error) { + error = clear_events(sid, fs_hanp, fs_hlen); + if (error) + /* just keep going */ ; + } + + error = finish_responding(sid); + if (error) + /* just keep going */ ; + + err_msg("Processing any undelivered event messages\n"); + event_loop(sid, 0 /*waitflag*/); + + err_msg("Shutting down the session\n"); + if (sid != 0) { + error = dm_destroy_session(sid); + if (error == -1) { + errno_msg("Can't shut down session - use 'mrmean -kv' to clean up!"); + } + } + + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/print_fshandle.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/print_fshandle.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/print_fshandle.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/print_fshandle.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* Given a file pathname, print the filesystem handle and the uuid_t for + the filesystem that contains the file. +*/ + +#include +#include +#ifdef __sgi +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include + + +static void +hantoa( + void *hanp, + size_t hlen, + char *handle_str) +{ + u_char *cp= (u_char *)hanp; + int i; + + for (i = 0;i < hlen; i++, handle_str += 2) + sprintf(handle_str, "%.2x", *cp++); + *handle_str = '\0'; +} + +int +main( + int argc, + char **argv) +{ +#ifdef __sgi + xfs_fsop_geom_t geom; + char *uuid_str; + u_int status; +#endif + char *name; + int fd; + void *fshanp; + size_t fshlen; + char buffer[100]; + + if (argc != 2) { + fprintf(stderr, "usage: %s path\n", argv[0]); + exit(1); + } + (void)dm_init_service(&name); + + if (dm_path_to_fshandle(argv[1], &fshanp, &fshlen) != 0) { + fprintf(stderr, "dm_path_to_fshandle failed, %s\n", + strerror(errno)); + } + hantoa(fshanp, fshlen, buffer); + + if ((fd = open(argv[1], O_RDONLY)) < 0) { + fprintf(stderr, "Open of %s failed, %s\n", argv[1], + strerror(errno)); + exit(1); + } + +#ifdef __sgi + syssgi(SGI_XFS_FSOPERATIONS, fd, XFS_FS_GEOMETRY, NULL, &geom); + + uuid_to_string(&geom.uuid, &uuid_str, &status); + + fprintf(stdout, "fshandle %s, uuid %s, %s\n", + buffer, uuid_str, argv[1]); +#endif + fprintf(stdout, "fshandle %s, %s\n", + buffer, argv[1]); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/probe_hole.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/probe_hole.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/probe_hole.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/probe_hole.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_probe_hole(). The +command line is: + + probe_hole [-o offset] [-l length] [-s sid] pathname + +where pathname is the name of a file, offset is the offset of the start of +the proposed punch, and length is the length of the punch. sid is the +session ID whose events you you are interested in. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-o offset] [-l length] " + "[-s sid] pathname\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *pathname = NULL; + dm_off_t offset = 0; + dm_size_t length = 0; + dm_off_t roffp; + dm_size_t rlenp; + void *hanp; + size_t hlen; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "o:l:s:")) != EOF) { + switch (opt) { + case 'o': + offset = atol(optarg); + break; + case 'l': + length = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + pathname = argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file's handle. */ + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for file %s\n", pathname); + exit(1); + } + + if (dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length, + &roffp, &rlenp)) { + fprintf(stderr, "dm_probe_hole failed, %s\n", + strerror(errno)); + exit(1); + } + fprintf(stdout, "roffp is %lld, rlenp is %lld\n", roffp, rlenp); + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/punch_hole.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/punch_hole.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/punch_hole.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/punch_hole.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_punch_hole(). The +command line is: + + punch_hole [-o offset] [-l length] [-s sid] pathname + +where pathname is the name of a file, offset is the offset of the start of +the punch, and length is the length of the punch. sid is the +session ID whose events you you are interested in. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-o offset] [-l length] " + "[-s sid] pathname\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *pathname = NULL; + dm_off_t offset = 0; + dm_size_t length = 0; + void *hanp; + size_t hlen; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "o:l:s:")) != EOF) { + switch (opt) { + case 'o': + offset = atol(optarg); + break; + case 'l': + length = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + pathname = argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file's handle. */ + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for file %s\n", pathname); + exit(1); + } + + if (dm_punch_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length)) { + fprintf(stderr, "dm_punch_hole failed, %s\n", + strerror(errno)); + exit(1); + } + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/query_right.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/query_right.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/query_right.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/query_right.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_query_right(). The +command line is: + + query_right [-F] [-s sid] token {pathname|handle} + +where +-F + when a pathname is specified, -F indicates that its filesystem handle + should be used rather than its file object handle. +sid + is the dm_sessid_t to use rather than the default test session. +token + is the dm_token_t to use. +{pathname|handle} + is either a handle, or is the pathname of a file whose handle is + to be used. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-F] [-s sid] token " + "{pathname|handle}\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t token; + dm_right_t right; + char *object; + void *hanp; + size_t hlen; + int Fflag = 0; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "Fs:")) != EOF) { + switch (opt) { + case 'F': + Fflag++; + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) + usage(); + token = atol(argv[optind++]); + object = argv[optind++]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file or filesystem's handle. */ + + if (opaque_to_handle(object, &hanp, &hlen)) { + fprintf(stderr, "can't get handle from %s\n", object); + exit(1); + } + if (Fflag) { + void *fshanp; + size_t fshlen; + + if (dm_handle_to_fshandle(hanp, hlen, &fshanp, &fshlen)) { + fprintf(stderr, "can't get filesystem handle from %s\n", + object); + exit(1); + } + dm_handle_free(hanp, hlen); + hanp = fshanp; + hlen = fshlen; + } + + if (dm_query_right(sid, hanp, hlen, token, &right)) { + fprintf(stderr, "dm_query_right failed, %s\n", + strerror(errno)); + return(1); + } + + fprintf(stderr, "right is %s\n", rt_value_to_name(right)); + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/randomize_file.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/randomize_file.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/randomize_file.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/randomize_file.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include +#include +#include + +/* + This program reads the file specified on the command line and + produces a new file on stdout which contains the lines from the + input file scrambled into a random order. This is useful for + 'randomizing' a database to simulate the kind of I/O that will + occur when many records have been added and deleted over time. +*/ + +#define FIELD_WIDTH 21 + +static char buffer[4096]; + +int +main( + int argc, + char **argv) +{ + FILE *infile; + FILE *tmpfile; + char *path; + int line_count = 0; + int i; + int j; + + if (argc != 2) { + fprintf(stderr, "Usage: %s infile\n", argv[0]); + exit(1); + } + + /* Read through the input file and count how many lines are present. */ + + if ((infile = fopen(argv[1], "r")) == NULL) { + fprintf(stderr, "can't open %s\n", argv[1]); + exit(1); + } + for (;;) { + if (fgets(buffer, sizeof(buffer), infile) == NULL) { + if (!ferror(infile)) + break; + fprintf(stderr, "Error on infile\n"); + exit(1); + } + line_count++; + } + fprintf(stderr, "%d lines in input file\n", line_count); + + /* Create a temp file. Copy the input file to the temp file, + prepending a random number in the range + 0 <= X <= linecount-1 + to each line copied. + */ + + path = tmpnam(NULL); + if ((tmpfile = fopen(path, "w")) == NULL) { + fprintf(stderr, "error opening temp file %s\n", path); + exit(1); + } + rewind(infile); + srand48((long)getpid()); + + for (i = line_count - 1; i >= 0; i--) { + if (fgets(buffer, sizeof(buffer), infile) == NULL) { + if (!ferror(infile)) + break; + fprintf(stderr, "Error on infile\n"); + exit(1); + } + j = (int)(drand48() * (float)i); + fprintf(tmpfile, "%*d ", FIELD_WIDTH - 1, j); + fputs(buffer, tmpfile); + } + if (fclose(infile)) { + fprintf(stderr, "close of input file failed\n"); + exit(1); + } + if (fclose(tmpfile)) { + fprintf(stderr, "close of temp file %s failed\n", path); + exit(1); + } + fprintf(stderr, "random mapping complete\n"); + + /* Use the system sort routine to sort the file into order on the + first field, effectively randomizing the lines. + */ + + sprintf(buffer, "sort +0 -1 -o %s %s", path, path); + if (system(buffer)) { + fprintf(stderr, "sort call failed\n"); + exit(1); + } + fprintf(stderr, "sort complete\n"); + + /* Copy the temp file to stdout, removing the prepended field. */ + + if ((tmpfile = fopen(path, "rw")) == NULL) { + fprintf(stderr, "error reopening temp file %s\n", path); + exit(1); + } + + for (i = 0; i < line_count; i++) { + if (fgets(buffer, sizeof(buffer), tmpfile) == NULL) { + if (!ferror(tmpfile)) + break; + fprintf(stderr, "Error on tmpfile\n"); + exit(1); + } + if (fputs(buffer + FIELD_WIDTH, stdout) < 0) { + fprintf(stderr, "Error on outfile\n"); + exit(1); + } + } + if (unlink(path)) { + fprintf(stderr, "can't unlink %s\n", path); + exit(1); + } + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/release_right.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/release_right.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/release_right.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/release_right.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_release_right(). The +command line is: + + release_right {-F} [-s sid] token {pathname|handle} + +where: +-F + when a pathname is specified, -F indicates that its filesystem handle + should be used rather than its file object handle. +sid + is the dm_sessid_t to use rather than the default test session. +token + is the dm_token_t to use. +{pathname|handle} + is either a handle, or is the pathname of a file whose handle is + to be used. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-F] [-s sid] token {pathname|handle}\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t token; + char *object; + void *hanp; + size_t hlen; + int Fflag = 0; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "Fs:")) != EOF) { + switch (opt) { + case 'F': + Fflag++; + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) + usage(); + token = atol(argv[optind++]); + object = argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file or filesystem's handle. */ + + if (opaque_to_handle(object, &hanp, &hlen)) { + fprintf(stderr, "can't get handle from %s\n", object); + exit(1); + } + if (Fflag) { + void *fshanp; + size_t fshlen; + + if (dm_handle_to_fshandle(hanp, hlen, &fshanp, &fshlen)) { + fprintf(stderr, "can't get filesystem handle from %s\n", + object); + exit(1); + } + dm_handle_free(hanp, hlen); + hanp = fshanp; + hlen = fshlen; + } + + if (dm_release_right(sid, hanp, hlen, token)) { + fprintf(stderr, "dm_release_right failed, %s\n", + strerror(errno)); + return(1); + } + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/remove_dmattr.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/remove_dmattr.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/remove_dmattr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/remove_dmattr.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_remove_dmattr(). The +command line is: + + remove_dmattr [-s sid] [-u] pathname attr + +where pathname is the name of a file, attr is the name of the DMAPI attribute, +and sid is the session ID whose attributes you are interested in. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-s sid] [-u] pathname attr\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *pathname; + dm_attrname_t *attrnamep; + int setdtime = 0; + void *hanp; + size_t hlen; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "s:u")) != EOF) { + switch (opt) { + case 's': + sid = atol(optarg); + break; + case 'u': + setdtime = 1; + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) + usage(); + pathname = argv[optind++]; + attrnamep = (dm_attrname_t *)argv[optind++]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file's handle. */ + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for file %s\n", pathname); + exit(1); + } + + if (dm_remove_dmattr(sid, hanp, hlen, DM_NO_TOKEN, setdtime, + attrnamep)) { + fprintf(stderr, "dm_remove_dmattr failed, %s\n", + strerror(errno)); + exit(1); + } + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/request_right.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/request_right.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/request_right.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/request_right.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_request_right(). The +command line is: + + request_right [-F] [-w] [-s sid] token {pathname|handle} right + +where +-F + when a pathname is specified, -F indicates that its filesystem handle + should be used rather than its file object handle. +-w + if specified, the DM_RR_WAIT flag will be used. +sid + is the dm_sessid_t to use rather than the default test session. +token + is the dm_token_t to use. +{pathname|handle} + is either a handle, or is the pathname of a file whose handle is + to be used. +right + is the dm_right_t to use. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + int i; + + fprintf(stderr, "usage:\t%s [-F] [-w] [-s sid] token " + "{pathname|handle} right\n", Progname); + fprintf(stderr, "possible rights are:\n"); + for (i = 0; i < rt_namecnt; i++) { + fprintf(stderr, "%s (%d)\n", rt_names[i].name, + rt_names[i].value); + } + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t token; + dm_right_t right; + char *object; + char *rightstr; + void *hanp; + size_t hlen; + int Fflag = 0; + int wflag = 0; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "Fws:")) != EOF) { + switch (opt) { + case 'F': + Fflag++; + break; + case 'w': + wflag++; + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 3 != argc) + usage(); + token = atol(argv[optind++]); + object = argv[optind++]; + rightstr = argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file or filesystem's handle. */ + + if (opaque_to_handle(object, &hanp, &hlen)) { + fprintf(stderr, "can't get handle from %s\n", object); + exit(1); + } + if (Fflag) { + void *fshanp; + size_t fshlen; + + if (dm_handle_to_fshandle(hanp, hlen, &fshanp, &fshlen)) { + fprintf(stderr, "can't get filesystem handle from %s\n", + object); + exit(1); + } + dm_handle_free(hanp, hlen); + hanp = fshanp; + hlen = fshlen; + } + + if (rt_name_to_value(rightstr, &right)) { + fprintf(stderr, "invalid right %s\n", rightstr); + usage(); + } + + if (dm_request_right(sid, hanp, hlen, token, + (wflag ? DM_RR_WAIT : 0), right)) { + fprintf(stderr, "dm_request_right failed, %s\n", + strerror(errno)); + return(1); + } + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/respond_event.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/respond_event.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/respond_event.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/respond_event.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_respond_event(). The +command line is: + + respond_event sid token response reterror + +where sid is the session ID whose event you are responding to. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s sid token response reterror\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid; + char *name; + dm_token_t token; + dm_response_t response; + int reterror; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + if (argc != 5) + usage(); + + sid = atol(argv[1]); + token = atol(argv[2]); + response = (dm_response_t)atoi(argv[3]); + reterror = atol(argv[4]); + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + + if (dm_respond_event(sid, token, response, reterror, 0, NULL)) { + fprintf(stderr, "dm_respond_event failed, %d/%s\n", + errno, strerror(errno)); + exit(1); + } + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/rwt.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/rwt.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/rwt.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/rwt.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +/*--------------------------------------------------------------------------- + +Test program used to test DMAPI by issuing read, write, and trunc calls to a +file. The command line is: + + rwt [-r|-w|-t] [-o offset] [-l length] pathname + +where: +-r + indicates that a read should be done (the default if none specified) +-w + indiates that a write should be done +-t + indicates that a truncate should be done, in which case the -l + parameter is ignored. +-o offset + offset at which to begin the read, write or truncate (default is 0). +-l length + the length in bytes to read or write (default is 1). +pathname + the file to be used by the test. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-r|-w|-t] [-o offset] [-l length] " + "pathname\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + char *pathname = NULL; + off_t offset = 0; + size_t length = 1; + u_char ch = 'X'; + void *bufp = NULL; + off_t seek_off; + int rflag = 0; + int wflag = 0; + int tflag = 0; + int fd; + ssize_t rc; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "rwto:l:")) != EOF) { + switch (opt) { + case 'r': + rflag++; + break; + case 'w': + wflag++; + break; + case 't': + tflag++; + break; + case 'o': + offset = atol(optarg); + break; + case 'l': + length = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + if (rflag + wflag + tflag > 1) + usage(); + pathname = argv[optind]; + + if ((fd = open(pathname, O_RDWR)) < 0) { + fprintf(stderr, "open of %s failed, %s\n", pathname, + strerror(errno)); + exit(1); + } + if (length > 0) { + if ((bufp = malloc(length)) == NULL) { + fprintf(stderr, "malloc of %d bytes failed\n", length); + exit(1); + } + if (wflag) + memset(bufp, ch, length); + } + + if (!tflag) { + if ((seek_off = lseek(fd, offset, SEEK_SET)) < 0) { + fprintf(stderr, "seek failed, %s\n", strerror(errno)); + exit(1); + } + if (seek_off != offset) { + fprintf(stderr, + "seeked to offset %lld, actually " + "arrived at %lld\n", + (int64_t)offset, (int64_t)seek_off); + exit(1); + } + } + + if (wflag) { + if ((rc = write(fd, bufp, length)) < 0) { + fprintf(stderr, "write failed, %s\n", strerror(errno)); + exit(1); + } + if (rc != length) { + fprintf(stderr, "expected to write %d bytes, actually " + "wrote %d bytes\n", length, rc); + exit(1); + } + } else if (tflag) { + if (ftruncate(fd, offset) != 0) { + fprintf(stderr, "truncate failed, %s\n", + strerror(errno)); + exit(1); + } + } else { + if ((rc = read(fd, bufp, length)) < 0) { + fprintf(stderr, "read failed, %s\n", strerror(errno)); + exit(1); + } + if (rc != length) { + fprintf(stderr, "expected to read %d bytes, actually " + "read %d bytes\n", length, rc); + exit(1); + } + } + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/security_hole.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/security_hole.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/security_hole.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/security_hole.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include + +#include + +/* + To read unallocated disk blocks in a filesystem, do + cc -o test thisfile.c + ./test myfile + cat myfile +*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + +static char *Progname; + + +static void +usage(void) +{ + int i; + + fprintf(stderr, "usage:\t%s [-s size] pathname\n", Progname); + fprintf(stderr, "\t-s size\t\tsize of file (default 10,000,000 bytes)\n"); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + char *pathname = NULL; + off_t size = 10000000; + char buff[1]; + int method = F_RESVSP; + flock_t flock; + int opt; + int fd; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "s:")) != EOF) { + switch (opt) { + case 's': + size = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + pathname = argv[optind]; + + /* Create the file and write one byte at a large offset to create a + big hole in the middle of the file. + */ + + if ((fd = open(pathname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) { + perror("open failed"); + exit(1); + } + if (lseek(fd, size, 0) < 0) { + perror("lseek failed"); + exit(1); + } + buff[0] = '\0'; + if (write(fd, buff, 1) != 1) { + perror("write failed"); + exit(1); + } + + /* Now fill in the hole with uninitialized blocks. */ + + flock.l_whence = 0; + flock.l_start = 0; + flock.l_len = size; + + if (fcntl(fd, method, &flock) < 0) { + perror("fcntl failed"); + exit(1); + } + printf("%s created\n", pathname); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/security_hole2.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/security_hole2.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/security_hole2.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/security_hole2.c Tue Jan 16 19:24:14 2001 @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include + +/* + To read unallocated disk blocks in a filesystem, do + cc -o test thisfile.c + ./test myfile + cat myfile +*/ + +extern char *sys_errlist[]; +extern int optind; +extern char *optarg; + +static char *Progname; + + +static void +usage(void) +{ + int i; + + fprintf(stderr, "usage:\t%s [-s size] pathname\n", Progname); + fprintf(stderr, "\t-s size\t\tsize of file (default 10,000,000 bytes)\n"); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + char *pathname = NULL; + off_t size = 10000000; + char buff[1]; + int method = F_RESVSP; + flock_t flock; + int opt; + int fd; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "s:")) != EOF) { + switch (opt) { + case 's': + size = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + pathname = argv[optind]; + + /* Create the file and write one byte at a large offset to create a + big hole in the middle of the file. + */ + + if ((fd = open(pathname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) { + perror("open failed"); + exit(1); + } + + /* First allocate uninitialized blocks. */ + + flock.l_whence = 0; + flock.l_start = 0; + flock.l_len = size; + + if (fcntl(fd, method, &flock) < 0) { + perror("fcntl failed"); + exit(1); + } + + /* Now seek out and write the byte. */ + + if (lseek(fd, size, 0) < 0) { + perror("lseek failed"); + exit(1); + } + buff[0] = '\0'; + if (write(fd, buff, 1) != 1) { + perror("write failed"); + exit(1); + } + printf("%s created\n", pathname); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/set_disp.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/set_disp.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/set_disp.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/set_disp.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_set_eventlist(). The +command line is: + + set_disp [-m max] [-s sid] [-t token] {pathname|handle} [event...] + set_disp [-m max] [-s sid] -G [DM_EVENT_MOUNT] + +where +{pathname|handle} + is the name of a file or handle whose filesystem is of interest. +-G + if the global handle should be used +max + is the value to use for the maxevent parameter of dm_set_disp(), +sid + is the dm_sessid_t to use rather than the default test session. +token + is the dm_token_t to use in place of DM_NO_TOKEN. +event + is zero or more events to set. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + int i; + + fprintf(stderr, "usage:\t%s [-m max] [-s sid] [-t token] " + "{pathname|handle} [event...]\n", Progname); + fprintf(stderr, "usage:\t%s [-m max] [-s sid] -G [DM_EVENT_MOUNT]\n", + Progname); + fprintf(stderr, "possible events are:\n"); + for (i = 0; i < ev_namecnt; i++) { + fprintf(stderr, "%s (%d)\n", ev_names[i].name, + ev_names[i].value); + } + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t token = DM_NO_TOKEN; + u_int maxevent = DM_EVENT_MAX; + dm_eventset_t eventset; + void *fshanp; + size_t fshlen; + int Gflag = 0; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "Gm:s:t:")) != EOF) { + switch (opt) { + case 'G': + Gflag++; + break; + case 'm': + maxevent = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case 't': + token = atol(optarg); + break; + case '?': + usage(); + } + } + if (Gflag && token != DM_NO_TOKEN) + usage(); + if (optind + (Gflag ? 0 : 1) > argc) + usage(); + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + DMEV_ZERO(eventset); + + /* Get the file or filesystem's handle. */ + + if (Gflag) { + fshanp = DM_GLOBAL_HANP; + fshlen = DM_GLOBAL_HLEN; + } else { + char *object; + void *hanp; + size_t hlen; + + object = argv[optind++]; + + if (opaque_to_handle(object, &hanp, &hlen)) { + fprintf(stderr, "can't get handle from %s\n", object); + exit(1); + } + if (dm_handle_to_fshandle(hanp, hlen, &fshanp, &fshlen)) { + fprintf(stderr, "can't get filesystem handle from %s\n", + object); + exit(1); + } + dm_handle_free(hanp, hlen); + } + + for (; optind < argc; optind++) { + dm_eventtype_t event; + + event = ev_name_to_value(argv[optind]); + if (event == DM_EVENT_INVALID) { + fprintf(stderr, "invalid event %s\n", argv[optind]); + usage(); + } + DMEV_SET(event, eventset); + } + + if (dm_set_disp(sid, fshanp, fshlen, token, &eventset, maxevent)) { + fprintf(stderr, "dm_set_disp failed, %s\n", + strerror(errno)); + exit(1); + } + + if (!Gflag) + dm_handle_free(fshanp, fshlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/set_dmattr.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/set_dmattr.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/set_dmattr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/set_dmattr.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_set_dmattr(). The +command line is: + + set_dmattr [-b buflen] [-s sid] [-u] pathname attr value + +where pathname is the name of a file, buflen is the size of the buffer to use +in the call, attr is the name of the DMAPI attribute, -u is selected if +setdtime should be updated, and sid is the session ID whose attributes you +are interested in. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-b buflen] [-s sid] [-u] pathname " + "attr value\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *pathname; + dm_attrname_t *attrnamep; + char *bufp; + size_t buflen; + int bflag = 0; + int setdtime = 0; + void *hanp; + size_t hlen; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "b:s:u")) != EOF) { + switch (opt) { + case 'b': + bflag++; + buflen = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case 'u': + setdtime = 1; + break; + case '?': + usage(); + } + } + if (optind + 3 != argc) + usage(); + pathname = argv[optind++]; + attrnamep = (dm_attrname_t *)argv[optind++]; + bufp = argv[optind]; + if (!bflag) + buflen = strlen(bufp) + 1; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file's handle. */ + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for file %s, %s\n", + pathname, strerror(errno)); + exit(1); + } + + if (dm_set_dmattr(sid, hanp, hlen, DM_NO_TOKEN, attrnamep, setdtime, + buflen, bufp)) { + fprintf(stderr, "dm_set_dmattr failed, %s\n", + strerror(errno)); + exit(1); + } + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/set_eventlist.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/set_eventlist.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/set_eventlist.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/set_eventlist.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_set_eventlist(). The +command line is: + + set_eventlist [-F] [-m max] [-s sid] [-t token] {pathname|handle} event [...] + +where: +{pathname|handle} + is either the pathname of a file or a handle. +max + is the value to use for the maxevent parameter of dm_set_eventlist(). +sid + is the dm_sessid_t value to use. +token + is the dm_token_t value to use (DM_NO_TOKEN is the default). +event + is one or more events to set. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + int i; + + fprintf(stderr, "usage:\t%s [-F] [-m max] [-s sid] " + "{pathname|handle} event [...]\n", Progname); + fprintf(stderr, "possible events are:\n"); + for (i = 0; i < ev_namecnt; i++) { + fprintf(stderr, "%s (%d)\n", ev_names[i].name, + ev_names[i].value); + } + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t token = DM_NO_TOKEN; + char *object; + dm_eventset_t eventset; + void *hanp; + size_t hlen; + int Fflag = 0; + u_int maxevent = DM_EVENT_MAX; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "Fm:s:t:")) != EOF) { + switch (opt) { + case 'F': + Fflag++; + break; + case 'm': + maxevent = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case 't': + token = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 > argc) + usage(); + object = argv[optind++]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + DMEV_ZERO(eventset); + + /* Get the file's handle or convert the external handle. */ + + if (opaque_to_handle(object, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for %s\n", object); + exit(1); + } + + if (Fflag) { + void *fshanp; + size_t fshlen; + + if (dm_handle_to_fshandle(hanp, hlen, &fshanp, &fshlen)) { + fprintf(stderr, "can't get filesystem handle from %s\n", + object); + exit(1); + } + dm_handle_free(hanp, hlen); + hanp = fshanp; + hlen = fshlen; + } + + for (; optind < argc; optind++) { + dm_eventtype_t event; + + event = ev_name_to_value(argv[optind]); + if (event == DM_EVENT_INVALID) { + fprintf(stderr, "invalid event %s\n", argv[optind]); + usage(); + } + DMEV_SET(event, eventset); + } + + if (dm_set_eventlist(sid, hanp, hlen, token, &eventset, maxevent)) { + fprintf(stderr, "dm_set_eventlist failed, %s\n", + strerror(errno)); + exit(1); + } + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/set_fileattr.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/set_fileattr.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/set_fileattr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/set_fileattr.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include + +#include +#include + + + +extern int optind; +extern int opterr; +extern char *optarg; + +static char *Progname; + +#define MIN_HD_DATE 19800101 +#define MIN_HD_TMSTAMP 315554400 /* timestamp of 19800101 */ + +static int dayno, day_of_week; +static int leap_year; + +/* + * The following table is used for USA daylight savings time and + * gives the day number of the first day after the Sunday of the + * change. + */ +static struct { + int yrbgn; + int daylb; + int dayle; +} daytab[] = { + {1987, 96, 303}, /* new legislation - 1st Sun in April */ + {1976, 119, 303}, /* normal Last Sun in Apr - last Sun in Oct */ + {1975, 58, 303}, /* 1975: Last Sun in Feb - last Sun in Oct */ + {1974, 5, 333}, /* 1974: Jan 6 - last Sun. in Nov */ + {1970, 119, 303}, /* start GMT */ +}; +#define DAYTABSIZE (sizeof(daytab)/sizeof(daytab[0])) + + +/****************************************************************************** +* NAME +* dysize +* +* DESCRIPTION +* Return number of days in year y. +* +******************************************************************************/ + +int +dysize(int y) +{ + int temp; + temp = (y%4)==0; + if (temp) { + if ( (y%100)==0) + temp = ( (y%400) != 0); + } + return(365+temp); +} + +/****************************************************************************** +* NAME +* sunday +* +* DESCRIPTION +* sunday - return sunday daynumber. Argument d is the day number of the +* first Sunday on or before the special day. Variables leap_year, dayno, +* and day_of_week must have been set before sunday is called. +* +* RETURN VALUE +* The sunday daynumber. +* +******************************************************************************/ + +static int +sunday(int d) +{ + if(d >= 58) + d += leap_year; + return(d - (d - dayno + day_of_week + 700) % 7); +} + + +extern long +cnvdate(int mon, int mday, int year, int hour, int min, int sec) +{ + int t, i; + int daylbegin, daylend; + int ly_correction; /* Leap Year Correction */ + int dl_correction; /* Daylight Savings Time Correction */ + long s; + static int days[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; + + days[2] = 28; + + /* Verify Input Parameters. */ + + /* Set year. */ + + if( year < 0) { + return(-1); + } + if( year < 100) { + if (year < 70) year += 2000; + else year += 1900; + } + if (year < 1970) { + return(-1); + } + if( year>2099 ) { + return(-1); + } + + if (dysize(year) == 366) { + leap_year = 1; + days[2]++; + } else + leap_year = 0; + /* + * Set ly_correction = number of leap year days from 1/1/1970 to + * 1/1/year. + */ + ly_correction = ((year-1969) / 4); + + /* Check Month */ + + if( (mon < 1) || (mon > 12)) { + return(-1); + } + + /* Check Day */ + + if ( (mday < 1) || (mday > days[mon]) ) { + return(-1); + } + + /* Check Time */ + + if( (hour<0) || (hour>23)) { + return(-1); + } + if( (min<0) || (min>59)) { + return(-1); + } + if( (sec<0) || (sec>59)) { + return(-1); + } + + /* Calculate Correction for Daylight Savings Time (U.S.) */ + + dayno = mday-1; + for (t=0; tDAYTABSIZE) + return(-1); + } + daylbegin = daytab[i].daylb; + daylend = daytab[i].dayle; + + daylbegin = sunday(daylbegin); + daylend = sunday(daylend); + if(daylight && + (dayno>daylbegin || (dayno==daylbegin && hour>=2)) && + (dayno 12) + return(0); + day = l % 100; + + /* Note: invalid day numbers are caught in cnvdate */ + + ptr+=8; + + l = strtol(ptr, &last_char, 10); + if (l < 0 || l>235959 || *last_char != '\0') + return(0); + hr = l / 10000; + if (hr > 23) + return(0); + l = l % 10000; + mn = l / 100; + if (mn > 59) + return(0); + sec = l % 100; + if (sec > 59) + return(0); + + /* Get timestamp. */ + + (void)tzset(); + if ((*timestamp = cnvdate(mon, day, yr, hr, mn, sec)) < 0) { + return(0); + } + + return(1); +} + + +/* Cracks dates in the form: NNs, NNm, NNh, or NNd which are interpreted + as NN seconds, minutes, hours, or days prior to the current time, + respectively. +*/ + +static int +get_relative_date( + char *ptr, + time_t *timestamp) +{ + int l; + char *last_char; + + if (!isdigit(*ptr)) + return(0); + l = strtol (ptr, &last_char, 10); + (void) time(timestamp); + if (strcmp(last_char, "s") == 0) + /* do nothing */; + else if (strcmp(last_char, "m") == 0) + l = l * 60; + else if (strcmp(last_char, "h") == 0) + l = l * 60 * 60; + else if (strcmp(last_char, "d") == 0) + l = l * 60 * 60 * 24; + else + return(0); + *timestamp -= l; + if (*timestamp < MIN_HD_TMSTAMP) + return(0); + return(1); +} + + +static void +usage(void) +{ + fprintf(stderr, "Usage: %s [-M mode] [-u uid] [-g gid] [-a atime] \\\n" + "\t[-m mtime] [-c ctime] [-d dtime] [-S size] [-s sid] pathname\n", + Progname); + fprintf(stderr, "\nDates can either be absolute:\n"); + fprintf(stderr, "\t\tYYYYMMDD or YYYYMMDDHHMMSS\n"); + fprintf(stderr, "or relative (prior to) the current time:\n"); + fprintf(stderr, "\tNNs (seconds), NNm (minutes), NNh (hours), " + " or NNd (days)\n"); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + void *hanp; + size_t hlen; + dm_fileattr_t fileattr; + u_int mask = 0; + char *pathname; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + opterr = 0; + while ((opt = getopt(argc, argv, "M:u:g:a:m:c:d:S:s:")) != EOF) { + switch (opt) { + case 'M': + mask |= DM_AT_MODE; + fileattr.fa_mode = strtol (optarg, NULL, 8); + break; + case 'u': + mask |= DM_AT_UID; + fileattr.fa_uid = atol(optarg); + break; + case 'g': + mask |= DM_AT_GID; + fileattr.fa_gid = atol(optarg); + break; + case 'a': + mask |= DM_AT_ATIME; + if (get_absolute_date(optarg, &fileattr.FA_ATIME)) + break; + if (get_relative_date(optarg, &fileattr.FA_ATIME)) + break; + usage(); + case 'm': + mask |= DM_AT_MTIME; + if (get_absolute_date(optarg, &fileattr.FA_MTIME)) + break; + if (get_relative_date(optarg, &fileattr.FA_MTIME)) + break; + usage(); + case 'c': + mask |= DM_AT_CTIME; + if (get_absolute_date(optarg, &fileattr.FA_CTIME)) + break; + if (get_relative_date(optarg, &fileattr.FA_CTIME)) + break; + usage(); + case 'd': + mask |= DM_AT_DTIME; + if (get_absolute_date(optarg, &fileattr.FA_DTIME)) + break; + if (get_relative_date(optarg, &fileattr.FA_DTIME)) + break; + usage(); + case 'S': + mask |= DM_AT_SIZE; + fileattr.fa_size = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) { + usage(); + } + pathname = argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stderr, "dm_path_to_handle failed, %s\n", + strerror(errno)); + exit(1); + } + + if (dm_set_fileattr(sid, hanp, hlen, DM_NO_TOKEN, mask, &fileattr)) { + fprintf(stderr, "dm_set_fileattr failed, %s\n", + strerror(errno)); + exit(1); + } + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/struct_test.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/struct_test.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/struct_test.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/struct_test.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include + +#ifdef linux +#include +#else +#include +#endif + +/* The purpose of this test is to make sure that each field in each structure + defined in dmi.h is properly aligned so that there is no dead space, and + that the sizes and offsets of those fields remain constant no matter what + mode the program is compiled with, i.e. -32, -n32 or -64. + + Run the program with no parameters. If everything is correct, no message + will start with the word "ERROR:". Compile and run the test in each of + the three mods and diff the outputs. They must all be identical. + + Note: this test cannot detect the addition of new structures to dmi.h, so + it will have to periodically be compared with dmi.h manually to ensure that + all the structures are still being validated! +*/ + +#define S_START(struct_name) { offset = 0; s_name = #struct_name; } + +#define S_NEXT(struct_name, field_name) \ +{ \ + struct_name X; \ + \ + f_name = #field_name; \ + printf("field %s.%s offset is %d\n", s_name, f_name, offset); \ + if (offsetof(struct_name, field_name) != offset) { \ + printf("ERROR: field %s should be %d\n", \ + #struct_name "." #field_name, \ + offsetof(struct_name, field_name)); \ + } \ + offset = offsetof(struct_name, field_name) + sizeof(X.field_name); \ +} + +#define S_END(struct_name) \ +{ \ + printf("struct %s size is %d\n", s_name, offset); \ + if (sizeof(struct_name) != offset) { \ + printf("ERROR: struct %s should be %d\n", \ + s_name, sizeof(struct_name)); \ + } \ +} + + + +int main( + int argc, + char **argv) +{ + char *s_name = NULL; + char *f_name = NULL; + int offset = 0; + + + S_START(dm_vardata_t); + S_NEXT(dm_vardata_t, vd_offset); + S_NEXT(dm_vardata_t, vd_length); + S_END(dm_vardata_t); + + + S_START(dm_attrname_t); + S_NEXT(dm_attrname_t, an_chars); + S_END(dm_attrname_t); + + + S_START(dm_attrlist_t); + S_NEXT(dm_attrlist_t, _link); + S_NEXT(dm_attrlist_t, al_name); + S_NEXT(dm_attrlist_t, al_data); + S_END(dm_attrlist_t); + + + S_START(dm_dispinfo_t); + S_NEXT(dm_dispinfo_t, _link); + S_NEXT(dm_dispinfo_t, di_pad1); + S_NEXT(dm_dispinfo_t, di_fshandle); + S_NEXT(dm_dispinfo_t, di_eventset); + S_END(dm_dispinfo_t); + + + S_START(dm_eventmsg_t); + S_NEXT(dm_eventmsg_t, _link); + S_NEXT(dm_eventmsg_t, ev_type); + S_NEXT(dm_eventmsg_t, ev_token); + S_NEXT(dm_eventmsg_t, ev_sequence); + S_NEXT(dm_eventmsg_t, ev_data); + S_END(dm_eventmsg_t); + + + S_START(dm_cancel_event_t); + S_NEXT(dm_cancel_event_t, ce_sequence); + S_NEXT(dm_cancel_event_t, ce_token); + S_END(dm_cancel_event_t); + + + S_START(dm_data_event_t); + S_NEXT(dm_data_event_t, de_handle); + S_NEXT(dm_data_event_t, de_offset); + S_NEXT(dm_data_event_t, de_length); + S_END(dm_data_event_t); + + + S_START(dm_destroy_event_t); + S_NEXT(dm_destroy_event_t, ds_handle); + S_NEXT(dm_destroy_event_t, ds_attrname); + S_NEXT(dm_destroy_event_t, ds_attrcopy); + S_END(dm_destroy_event_t); + + + S_START(dm_mount_event_t); + S_NEXT(dm_mount_event_t, me_mode); + S_NEXT(dm_mount_event_t, me_handle1); + S_NEXT(dm_mount_event_t, me_handle2); + S_NEXT(dm_mount_event_t, me_name1); + S_NEXT(dm_mount_event_t, me_name2); + S_NEXT(dm_mount_event_t, me_roothandle); + S_END(dm_mount_event_t); + + + S_START(dm_namesp_event_t); + S_NEXT(dm_namesp_event_t, ne_mode); + S_NEXT(dm_namesp_event_t, ne_handle1); + S_NEXT(dm_namesp_event_t, ne_handle2); + S_NEXT(dm_namesp_event_t, ne_name1); + S_NEXT(dm_namesp_event_t, ne_name2); + S_NEXT(dm_namesp_event_t, ne_retcode); + S_END(dm_namesp_event_t); + + + S_START(dm_extent_t); + S_NEXT(dm_extent_t, ex_type); + S_NEXT(dm_extent_t, ex_pad1); + S_NEXT(dm_extent_t, ex_offset); + S_NEXT(dm_extent_t, ex_length); + S_END(dm_extent_t); + + + S_START(dm_fileattr_t); + S_NEXT(dm_fileattr_t, fa_mode); + S_NEXT(dm_fileattr_t, fa_uid); + S_NEXT(dm_fileattr_t, fa_gid); + S_NEXT(dm_fileattr_t, fa_atime); + S_NEXT(dm_fileattr_t, fa_mtime); + S_NEXT(dm_fileattr_t, fa_ctime); + S_NEXT(dm_fileattr_t, fa_dtime); + S_NEXT(dm_fileattr_t, fa_pad1); + S_NEXT(dm_fileattr_t, fa_size); + S_END(dm_fileattr_t); + + + S_START(dm_inherit_t); + S_NEXT(dm_inherit_t, ih_name); + S_NEXT(dm_inherit_t, ih_filetype); + S_END(dm_inherit_t); + + + S_START(dm_region_t); + S_NEXT(dm_region_t, rg_offset); + S_NEXT(dm_region_t, rg_size); + S_NEXT(dm_region_t, rg_flags); + S_NEXT(dm_region_t, rg_pad1); + S_END(dm_region_t); + + + S_START(dm_stat_t); + S_NEXT(dm_stat_t, _link); + S_NEXT(dm_stat_t, dt_handle); + S_NEXT(dm_stat_t, dt_compname); + S_NEXT(dm_stat_t, dt_nevents); + S_NEXT(dm_stat_t, dt_emask); + S_NEXT(dm_stat_t, dt_pers); + S_NEXT(dm_stat_t, dt_pmanreg); + S_NEXT(dm_stat_t, dt_dtime); + S_NEXT(dm_stat_t, dt_change); + S_NEXT(dm_stat_t, dt_pad1); + + S_NEXT(dm_stat_t, dt_dev); + S_NEXT(dm_stat_t, dt_ino); + S_NEXT(dm_stat_t, dt_mode); + S_NEXT(dm_stat_t, dt_nlink); + S_NEXT(dm_stat_t, dt_uid); + S_NEXT(dm_stat_t, dt_gid); + S_NEXT(dm_stat_t, dt_rdev); + S_NEXT(dm_stat_t, dt_pad2); + S_NEXT(dm_stat_t, dt_size); + S_NEXT(dm_stat_t, dt_atime); + S_NEXT(dm_stat_t, dt_mtime); + S_NEXT(dm_stat_t, dt_ctime); + S_NEXT(dm_stat_t, dt_blksize); + S_NEXT(dm_stat_t, dt_blocks); + + S_NEXT(dm_stat_t, dt_pad3); + S_NEXT(dm_stat_t, dt_fstype); + + S_NEXT(dm_stat_t, dt_xfs_igen); + S_NEXT(dm_stat_t, dt_xfs_xflags); + S_NEXT(dm_stat_t, dt_xfs_extsize); + S_NEXT(dm_stat_t, dt_xfs_extents); + S_NEXT(dm_stat_t, dt_xfs_aextents); + S_NEXT(dm_stat_t, dt_xfs_dmstate); + S_END(dm_stat_t); + + + S_START(dm_xstat_t); + S_NEXT(dm_xstat_t, dx_statinfo); + S_NEXT(dm_xstat_t, dx_attrdata); + S_END(dm_xstat_t); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/sync_by_handle.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/sync_by_handle.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/sync_by_handle.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/sync_by_handle.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_sync_by_handle(). The +command line is: + + sync_by_handle [-s sid] pathname + +where: +'sid' is the session ID to use for the call. +'pathname' is the name of the file to be sync'd. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-s sid] pathname\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *pathname = NULL; + void *hanp; + size_t hlen; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "s:")) != EOF) { + switch (opt) { + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + pathname = argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file's handle. */ + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for file %s\n", pathname); + exit(1); + } + + if (dm_sync_by_handle(sid, hanp, hlen, DM_NO_TOKEN)) { + fprintf(stderr, "dm_sync_by_handle failed, %s\n", + strerror(errno)); + exit(1); + } + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/test_assumption.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/test_assumption.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/test_assumption.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/test_assumption.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include + +#include + +/* + Test that the new session ID is correctly returned to the caller on + dm_create_session when the oldsid parameter is not DM_NO_SESSION. + + Test to make sure that DM_NO_TOKEN does not work if the session ID + is invalid. + + Both are needed so that session assumption works correctly. The + test creates a session, queries the session, assumes the session, + then attempts to check the event list of the old session ID while + using DM_NO_TOKEN. + + The only parameter is the pathname of a DMAPI filesystem. If it is + working correctly, you should get the error message: + + SUCCESS! + + Any message containing the word FAILURE indicates a problem. +*/ + +char *Progname; +dm_sessid_t sid = DM_NO_SESSION; /* session ID of original session */ +dm_sessid_t newsid = DM_NO_SESSION; /* session ID after session resumed */ +dm_eventset_t eventlist; + +int +main( + int argc, + char **argv) +{ + char buffer[DM_SESSION_INFO_LEN]; + void *hanp; + size_t hlen; + u_int nelem; + size_t rlen; + + Progname = argv[0]; + + if (argc != 2) { + fprintf(stderr, "usage:\t%s filesystem\n", Progname); + exit(1); + } + + /* Initialize the DMAPI interface and obtain a session ID, then verify + that the filesystem supports DMAPI. + */ + + if (setup_dmapi(&sid)) + exit(1); + + if (dm_path_to_handle(argv[1], &hanp, &hlen)) { + perror("FAILURE: can't get handle for filesystem"); + exit(1); + } + + /* Query the session just to make sure things are working okay. */ + + if (dm_query_session(sid, sizeof(buffer), buffer, &rlen)) { + errno_msg("FAILURE: can't query the original session ID %d", + sid); + exit(1); + } + fprintf(stdout, "Initial session ID: %d\n", sid); + fprintf(stdout, "Initial session message length: '%d'\n", rlen); + if (rlen > 0) { + fprintf(stdout, "Initial session message: '%s'\n", buffer); + } + + /* Now try to assume the session. */ + + if (dm_create_session(sid, "this is a new message", &newsid)) { + fprintf(stderr, "FAILURE: can't assume session %d\n", sid); + exit(1); + } + + /* Now query the new session. */ + + if (dm_query_session(newsid, sizeof(buffer), buffer, &rlen)) { + errno_msg("FAILURE: can't query the assumed session ID %d", + newsid); + exit(1); + } + fprintf(stdout, "Assumed session ID: %d\n", newsid); + fprintf(stdout, "Assumed session message length: '%d'\n", rlen); + if (rlen > 0) { + fprintf(stdout, "Assumed session message: '%s'\n", buffer); + } + + /* Get rid of the new session as we are done with it. */ + + if (dm_destroy_session(newsid)) { + fprintf(stderr, "FAILURE: Can't shut down assumed session %d\n", + newsid); + exit(1); + } + + /* Now verify that DM_NO_TOKEN will not work with the old session ID, + which is now invalid. + */ + + DMEV_ZERO(eventlist); + + if (dm_get_eventlist(sid, hanp, hlen, DM_NO_TOKEN, DM_EVENT_MAX, + &eventlist, &nelem) == 0) { + fprintf(stderr, "FAILURE: dm_get_eventlist() worked when it " + "should have failed!\n"); + } +#ifdef VERITAS_21 + if (errno != ESRCH) { +#else + if (errno != EINVAL) { +#endif + errno_msg("FAILURE: unexpected errno"); + exit(1); + } + fprintf(stdout, "SUCCESS!\n"); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/upgrade_right.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/upgrade_right.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/cmd/upgrade_right.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/cmd/upgrade_right.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_upgrade_right(). The +command line is: + + upgrade_right {-F} [-s sid] token {pathname|handle} + +where: +-F + when a pathname is specified, -F indicates that its filesystem handle + should be used rather than its file object handle. +sid + is the dm_sessid_t to use rather than the default test session. +token + is the dm_token_t to use. +{pathname|handle} + is either a handle, or is the pathname of a file whose handle is + to be used. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-F] [-s sid] token {pathname|handle}\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t token; + char *object; + void *hanp; + size_t hlen; + int Fflag = 0; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "Fs:")) != EOF) { + switch (opt) { + case 'F': + Fflag++; + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) + usage(); + token = atol(argv[optind++]); + object = argv[optind]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file or filesystem's handle. */ + + if (opaque_to_handle(object, &hanp, &hlen)) { + fprintf(stderr, "can't get handle from %s\n", object); + exit(1); + } + if (Fflag) { + void *fshanp; + size_t fshlen; + + if (dm_handle_to_fshandle(hanp, hlen, &fshanp, &fshlen)) { + fprintf(stderr, "can't get filesystem handle from %s\n", + object); + exit(1); + } + dm_handle_free(hanp, hlen); + hanp = fshanp; + hlen = fshlen; + } + + if (dm_upgrade_right(sid, hanp, hlen, token)) { + fprintf(stderr, "dm_upgrade_right failed, %s\n", + strerror(errno)); + return(1); + } + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite1/function_coverage linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/function_coverage --- linux-2.4.7/cmd/xfstests/dmapi/src/suite1/function_coverage Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite1/function_coverage Tue Jan 16 19:24:14 2001 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* functions for which there is a test program. */ + +dm_downgrade_right( +dm_fd_to_handle( +dm_get_allocinfo( +dm_get_config_events( +dm_get_dmattr( +dm_get_eventlist( +dm_get_events( +dm_get_fileattr( +dm_get_mountinfo( +dm_get_region( +dm_getall_disp( +dm_getall_dmattr( +dm_handle_cmp( +dm_handle_free( +dm_handle_hash( +dm_handle_is_valid( +dm_handle_to_fshandle( +dm_handle_to_fsid( +dm_handle_to_igen( +dm_handle_to_ino( +dm_handle_to_path( +dm_init_service( +dm_make_handle( +dm_make_fshandle( +dm_path_to_fshandle( +dm_path_to_handle( +dm_obj_ref_hold( +dm_obj_ref_query( +dm_obj_ref_rele( +dm_pending( +dm_probe_hole( +dm_punch_hole( +dm_read_invis( +dm_release_right( +dm_request_right( +dm_remove_dmattr( +dm_respond_event( +dm_set_disp( +dm_set_dmattr( +dm_set_eventlist( +dm_set_fileattr( +dm_set_region( +dm_set_return_on_destroy( +dm_sync_by_handle( +dm_upgrade_right( +dm_write_invis( + + +/* Functions which don't yet have a specific test program. */ + +dm_create_session( +dm_create_userevent( +dm_destroy_session( +dm_find_eventmsg( +dm_get_bulkattr( +dm_get_config( +dm_get_dirattrs( +dm_getall_sessions( +dm_getall_tokens( +dm_init_attrloc( +dm_move_event( +dm_query_session( +dm_send_msg( + +/* Non-standard SGI additions to the DMAPI interface. */ + +dm_get_dioinfo diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/CVS/Entries linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/CVS/Entries --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/CVS/Entries Thu Jul 5 11:45:57 2001 @@ -0,0 +1,6 @@ +/DMAPI_aliases/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/README/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/README_for_check_dmapi/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/create_cpio/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/menu_test/1.1/Wed Jan 17 01:24:14 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/CVS/Entries.Log linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/CVS/Entries.Log --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/CVS/Entries.Log Thu Jul 5 11:45:58 2001 @@ -0,0 +1,5 @@ +A D/bindir//// +A D/data//// +A D/dist//// +A D/lib//// +A D/src//// diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/CVS/Repository linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/CVS/Repository --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/CVS/Repository Thu Jul 5 11:45:56 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2 diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/CVS/Root linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/CVS/Root --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/CVS/Root Thu Jul 5 11:45:56 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/DMAPI_aliases linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/DMAPI_aliases --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/DMAPI_aliases Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/DMAPI_aliases Tue Jan 16 19:24:14 2001 @@ -0,0 +1,147 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +#--------------------------------------------------------------------------- +# CONFIGURATION SECTION: +# Configure this script by changing the variables in this section. +# Please change ONLY this section! +#--------------------------------------------------------------------------- + +# Base directory: +base_dir="~jayw/test" + +# Primary username: +p_user="jayw" + +# Path to the mountpoint of the test filesystem: +m_main="/dmitest" + +# m_main concatenated with d_name == the full test directory path +# +# EXAMPLE: If m_main is "/dmitest", and the test directory +# is "/dmitest/test", set this to "/test" +# +d_name="/test" + +# Path to the mountpoint of the nfs2 test filesystem: +m_nfs2="/dmiv2" + +# Path to the mountpoint of the nfs3 test filesystem: +m_nfs3="/dmiv3" + +# Path to the mountpoint of the realtime test filesystem: +m_rt="/dmf" +# Path to the realtime test directory: +d_rt="$m_rt/kcm" + +#-------------------------------------------------------------------- +# END OF CONFIGURATION SECTION: +# No changes should be made past this point! Please change only +# the above shell variables to configure this script. +#-------------------------------------------------------------------- + +# Path to the "bindir" directory: +bin="$base_dir/bindir" + +# Path to the "generic file" (a copy of ls): +ls_path="$bin/ls_to_copy" + +# Path to the main test directory: +d_main="$m_main$d_name" + +# Path to the nfs2 test directory: +d_nfs2="$m_nfs2$d_name" + +# Path to the nfs3 test directory: +d_nfs3="$m_nfs2$d_name" + +#--------------------------------------------------------------------------- +# Tests that run without a daemon +#--------------------------------------------------------------------------- + +# Automated C programs to test DMAPI functions +alias do_dmattr="$bin/test_dmattr $ls_path $tdir" +alias do_eventlist="$bin/test_eventlist $ls_path $tdir" +alias do_fileattr="$bin/test_fileattr $ls_path $tdir" +alias do_hole="$bin/test_hole $ls_path $tdir" +alias do_invis="$bin/test_invis $ls_path $tdir" +alias do_region="$bin/test_region $ls_path $tdir" +alias do_efault="$bin/test_efault $ls_path $tdir" +alias do_rights="$bin/test_rights $ls_path $tdir" + +# Verbose versions of the above +alias dov_dmattr="$bin/test_dmattr -v $ls_path $tdir" +alias dov_eventlist="$bin/test_eventlist -v $ls_path $tdir" +alias dov_fileattr="$bin/test_fileattr -v $ls_path $tdir" +alias dov_hole="$bin/test_hole -v $ls_path $tdir" +alias dov_invis="$bin/test_invis -v $ls_path $tdir" +alias dov_region="$bin/test_region -v $ls_path $tdir" +alias dov_efault="$bin/efault -v $ls_path $tdir" +alias dov_rights="$bin/test_rights -v $ls_path $tdir" + +# Scripts to test dm_get_allocinfo +alias do_allocinfo_1="$bin/test_allocinfo_1 $bin $tdir" +alias do_allocinfo_2="$bin/test_allocinfo_2 $bin $tdir" + +#------------------------------------------------------------------------------------------------- +# Tests that load a DMAPI daemon and examine the generated events +#------------------------------------------------------------------------------------------------- + +# Standard battery of tests: +alias do_standard="$bin/run_test -u $p_user -f standard.dat $bin $tdir $mdir" +alias do_standard_nfs2="$bin/run_test -u $p_user -F nfs2 -M $m_nfs2 -R $tdir -f standard_nfs.dat $bin $d_nfs2 $mdir" +alias do_standard_nfs3="$bin/run_test -u $p_user -F nfs3 -M $m_nfs3 -R $tdir -f standard_nfs.dat $bin $d_nfs3 $mdir" + +# Some other, more specific tests: +alias do_main="$bin/run_test -u $p_user $bin $tdir $mdir" +alias do_nfs2="$bin/run_test -u $p_user -F nfs2 -M $m_nfs2 -R $tdir -f nfs.dat $bin $d_nfs2 $mdir" +alias do_nfs3="$bin/run_test -u $p_user -F nfs3 -M $m_nfs3 -R $tdir -f nfs.dat $bin $d_nfs3 $mdir" + +alias do_pending="$bin/run_test -u $p_user -f pending.dat $bin $tdir $mdir" +alias do_pending_nfs2="$bin/run_test -u $p_user -F nfs2 -M $m_nfs2 -R $tdir -f pending_nfs.dat $bin $d_nfs2 $mdir" +alias do_pending_nfs3="$bin/run_test -u $p_user -F nfs3 -M $m_nfs3 -R $tdir -f pending_nfs.dat $bin $d_nfs3 $mdir" + +alias do_failure="$bin/run_test -u $p_user -f fail.dat $bin $tdir $mdir" +alias do_failure_nfs2="$bin/run_test -u $p_user -F nfs2 -M $m_nfs2 -R $tdir -f fail.dat $bin $d_nfs2 $mdir" +alias do_failure_nfs3="$bin/run_test -u $p_user -F nfs3 -M $m_nfs3 -R $tdir -f fail.dat $bin $d_nfs3 $mdir" + +# Realtime test: +alias do_realtime="$bin/run_test -u $p_user -f realtime.dat $bin $m_rt $d_rt" + +# Small event queue test: Set dm_max_queued to about 5 or so before running! +alias do_smallq="$bin/run_test -u $p_user -s 2 -f smallq.dat $bin $tdir $mdir" + +#------------------------------------------------------------------------------------------------- +# Additional tools (these are NOT tests): +#------------------------------------------------------------------------------------------------- + +alias check_for_daemon="ps -el | grep daemon" +alias do_daemon="$bin/dm_test_daemon $mdir" diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/README linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/README --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/README Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/README Tue Jan 16 19:24:14 2001 @@ -0,0 +1,633 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + + + DMAPI Test Suite + Informational File + ------------------ + +I) Getting Started + + A) Extracting from DMAPI_test.cpio + + 1) Create a new directory for storing the tests. We will refer to + this as the "base" directory. The base directory can be + located anywhere; it does NOT need to be in a DMAPI filesystem. + + 2) Move the archive file DMAPI_test.cpio to the base directory + and execute the following command to extract from the archive: + + cpio -icvd < DMAPI_test.cpio + + 3) There should now be several files and subdirectories in the base + directory, including the file "file_list". Read this file for a + complete listing of which files should be present in which + directories. Compare "file_list" with the output of "ls -Rpl" + to be sure that you have the necessary files. + + 4) The base directory contains the files and programs that are of + immediate use for testing. The "bindir" subdirectory contains + the test programs and datafiles. The "lib" and "src" subdirectories + contain C libraries and source code for the C programs. + + B) Checking the Existence and Version of DMAPI + + The program check_dmapi can verify that you have the correct + version of DMAPI installed. NOTE: it can only be run as root. + Execute this command (from the "base" directory): + + bindir/check_dmapi + + It should report that you have a current version of DMAPI. If it + does not, it will also suggest which components of your DMAPI are + not current, and where to find a patch to update them. + + C) Configuration + + 1) Creating the Test Directories + + a) The Test Filesystem + + Mount a DMAPI filesystem, or use an existing one. + This filesystem's mount info MUST be listed in /etc/fstab. + + Write down the path to this filesystem's mountpoint, and label + it as "m_main" for future use. + + b) The Main Test Directory + + Create a new directory in the "m_main" filesystem. + + Write down the path to this directory. Note ONLY the part + that comes AFTER "m_main". Label this as "d_name". + + EXAMPLE: You have a DMAPI filesystem /dmi_main + You name the test directory /dmi_main/test_dir + "m_main" is /dmi_main + "d_name" is /test_dir + + c) The Cross-NFS Test Directories + + For NFS tests, all you must do is create two empty directories + (one for nfs2, one for nfs3). They do NOT need to be in a + DMAPI filesystem. + + Your main test directory will be mounted across NFS, into these + two directories. Normally, the tests will do this automatically. + However, if you need to do this mount manually, the command + would look like this example: + + mount -t nfs2 localhost:/dmi_main /dmi_nfs2 + + Write down the paths to these nfs2 and nfs3 test directories. + Label them "m_nfs2" and "m_nfs3" respectively. + + c) The Realtime Test Filesystem and Directory + + If you wish to test realtime i/o, you'll need a filesystem + mounted with a realtime partition, and a directory in that + filesystem. + + Label the path to the filesystem mountpoint as "m_rt". + Label the path to the test directory as "d_rt". + + 2) Configuring menu_test + + The Korn-shell script named menu_test is an interface to the + other test programs. At the beginning of the script, there + is a "configuration section", in which is sets several variables + for use in the rest of the script. + + Open menu_test in any text editor and change the following + variable assignments in the configuration section: + + a) base_dir: + Set this to the pathname of your "base" directory + (where you un-archived "DMAPI_test.cpio"). + + b) p_user: + Tests that do not run as root will run as this "primary" user. + Set this to any username. + + c) m_main: + The mountpoint of the main test filesystem. + Set this to the value of "m_main" that you wrote down above. + + d) d_name: + m_main concatenated with d_name is the main test directory path. + Set this to the value for "d_name" that you wrote down above. + + e) m_nfs2: + The mountpoint of the nfs2 test filesystem. + Set this to the value of "m_nfs2" that you wrote down above. + + f) m_nfs2: + The mountpoint of the nfs3 test filesystem. + Set this to the value of "m_nfs3" that you wrote down above. + + g) m_rt: + The mountpoint of the realtime test filesystem. + Set this to the value of "m_rt" that you wrote down above. + + h) d_rt: + The path to the realtime test directory. + Set this to the value of "d_rt" that you wrote down above. + + 3) Configuring "DMAPI_aliases" + + This is an optional alternative to the menu interface. It runs + as a Korn shell "dot" script and creates an alias to each test. + It was made for those who wish to run tests directly from the + command line. + + DMAPI_aliases has exactly the same configuration section as + menu_test. If you wish to use DMAPI_aliases, make the same + changes to its configuration section. + +II) Running the Tests + + A) Using "menu_test" to run tests + + 1) You must be superuser, using the Korn shell, to run menu_test. + You also must have adjusted the variables in menu_test's + "configuration section", as was explained above. + + 2) menu_test is (surprise!) menu based. Choose options by entering + their numbers. + + 3) The names of the menu options explain which DMAPI functions + or DMAPI events are being tested. Some of the options, labeled + accordingly, run more than one test programs. + + 4) See section SECTION# for a list of the test scripts and programs, + and a brief explanation of each script or program's function. + + B) Using "DMAPI_aliases" to run tests + + 1) NOTE: The aliases in DMAPI_aliases are meant to be used by + those who are familiar with the test programs and wish to run + them more directly. [Designer's note: I included the alias + file more out of nostalgia than necessity.] + + 2) You should be superuser, using the Korn shell, to run DMAPI_aliases. + You also must have adjusted the variables in DMAPI_aliases's + "configuration section", as was explained above. + + 3) DMAPI_aliases should be invoked as a Korn shell "dot" script: + + . ./DMAPI_aliases + + It sets an alias for each test program; each alias begins with + the characters "do_" and is followed by some appropriate name. + Read DMAPI_aliases, or execute "alias | grep do", to + + 4) "Verbose mode" + In the menu of function tests, one of the options is an on/off + toggle of "verbose mode". When verbose mode is on, the function + tests will print semi-explanatory output. Verbose mode affects + only the function tests (this does include check_dmapi). + + 5) "Pausing after each command" + In the menu of event tests, one of the options is a toggle of + "pausing after each command". When this is on, the event tests + will pause for a carriage return after running each command. + This affects only the event tests. + + C) Running tests directly + + 1) For the VERY adventurous, all the tests in the "bindir" directory + can be run directly from the command line. Only some of the files + in "bindir" are test scripts/programs. Read section III for a list + of function tests and section IV for a list of run_test (.dat) + testfiles. + + 2) Running a test program without parameters will produce a list of + correct options. (The exception to this is check_dmapi, which + normally has no parameters. check_dmapi takes only one option, + [-v] for verbose output.) + + 3) It is suggested that you read a program's source before running + it directly. (The source of the C programs is included in the + "src" directory.) Specifically, in each source file, an initial + comment explains the program's options/parameters in detail. + +III) DMAPI Function tests: + + This section offers a terse description of the DMAPI function tests. + For those tests written in C, the source code is given in the "src" + directory. The ksh scripts can, of course, be read directly. + In all cases except check_dmapi, running the program without + parameters will produce a list of correct options. + + A) check_dmapi + Written in: C + Test of: presence (and correct version) of DMAPI library and kernel. + Options: [-v] flag for verbose output. + + B) test_dmattr + Written in: C + Test of: dm_get_dmattr, dm_set_dmattr, dm_remove_dmattr. + + C) test_efault + Written in: C + Test of: various bad function calls that should generate EFAULT, + according to the DMAPI specification. + + D) test_eventlist + Written in: C + Test of: dm_get_eventlist, dm_set_eventlist. + + E) test_fileattr + Written in: C + Test of: dm_get_fileattr, dm_set_fileattr, + dm_get_dirattrs, dm_get_bulkattr. + + F) test_hole + Written in: C + Test of: dm_probe_hole, dm_punch_hole. + + G) test_invis + Written in: C + Test of: dm_read_invis, dm_write_invis. + + H) test_region + Written in: C + Test of: dm_get_region, dm_set,region. + + I) test_rights + Written in: C + Test of: various bad function calls that should generate EACCES, + and other conditions pertaining to DMAPI rights. + + J) test_allocinfo_1 + Written in: ksh + Test of: dm_get_allocinfo. + + K) test_allocinfo_2 + Written in: ksh + Test of: dm_get_allocinfo. + +IV) DMAPI Event tests and the "run_test" ksh script + + A) How to use the "run_test" script + + 1) A quick description of run_test's behavior: + run_test invokes a DMAPI daemon (as a ksh coprocess). It then + proceeds in a loop, in which it reads a command from a "testfile", + executes that command, reads a description of expected events from + the testfile, and compares the expected events with the actual + events, as returned by the DMAPI daemon. + + 2) You must be superuser, using the Korn shell, to execute run_test. + + 3) Executing run_test without parameters will produce a list of + correct options. For a much more in-depth explanation of the + options to run_test, read its own initial comment. + + B) The existing .dat testfiles + + 1) fail.dat + Tests the events from: a user trying to access files owned + by someone else (in this case, root). + + 2) main.dat + Tests the events from: events getting DM_RESP_ABORT, dm_send_msg(), + invisible i/o, and direct i/o. + + 3) nfs.dat + Tests the events from: events getting DM_RESP_ABORT over nfs, + EAGAIN over nfs. + + 4) pending.dat + Tests the events from: running dm_pending() while trying to + do standard i/o. + + 5) pending_nfs.dat + Tests the events from: running dm_pending() while trying to + do standard i/o over NFS + + 6) realtime.dat + Tests the events from: Invisible, direct, and standard i/o + on realtime files in a realtime filesystem. + + 7) smallq.dat + Tests the events from: Slow i/o due to a small event queue. + + 8) standard.dat + Tests the events from: various kinds of standard i/o, + memory-mapped i/o and remounting the filesystem. + + 9) standard_nfs.dat + Tests the events from: various kinds of standard i/o, over NFS. + + C) How to write new ".dat" testfiles + + 1) Overview + + A testfile contains a complete description of a DMAPI event test. + Testfiles are divided into sections: the first two contain + test initialization, while the remaining sections each contain ONE + command, followed by a list of expected events. + + The following is a description of testfile syntax. If you wish to + fully understand testfile syntax, PLEASE examine the existing + testfiles and the "run_test" script. + + 2) Event information variables + + a) From the daemon, "run_test" gets information about DMAPI events. + This information is stored in event information variables. + + b) NOTE: event information variables are not persistent. + After "run_test" has compared the expected and actual events + for a command, and before it executes the next command, it + unsets the values of all these variables. + + c) Most of these variables are arrays, indexed by the number of + the event (starting with 0). For example, if the initial event + is a read event, then we have "event[0]" set to "read", and + "file_handle[0]" set to the handle of whatever file was read. + + d) "event_count" is a special variable. It holds the number of + events that were generated by the most recent command. + + e) These are all the event information variables: + + contents event event_count fs_handle handle length + offset media_designator mode mountpoint_handle + mountpoint_path msg_str name new_name new_parent + parent_handle ret_code root_handle sequence token + tries_left unmount_mode + + f) PLEASE examine the run_test script to see which variables + are set by which events. (The scheme corresponds, roughly, + to the "Event Types" section of the DMAPI specification.) + + 3) Testfile section 1: List of required files + + a) A testfile's first section is a list of the files it requires. + If these files are not present in the "bindir" directory, + "run_test" will abort the test and inform the user of which + files are missing. + + b) Each line of this section may contain ANY NUMBER of filenames. + + c) Lines beginning with // will be treated as comments. The + entirety of such lines will be ignored. + + d) The last line of this section should begin with three hyphens + --- Other characters on that line will be ignored. + + 4) Testfile section 2: Initialization commands + + a) A testfile's second section consists of a list of commands. + "run_test" will execute these commands before starting the + DMAPI daemon. Any necessary initialization should be done + here. + + b) Each line of this section should be ONE shell command. + + c) Lines beginning with // will be treated as comments. + The entirety of such lines will be ignored. + + d) The last line of this section should begin with three hyphens + "---" Other characters on that line will be ignored. + + 5) Testfile sections 3 and on: Individual tests + + a) The remaining sections of a testfile consist of a single + shell command, followed by descriptions of events that should + be generated by the command. + + b) Comments + + 1) Comments are valid ONLY before the command. + + 2) Lines beginning with // will be treated as comments. + The entirety of such lines will be ignored. + + 3) Lines beginning with @@ will be treated as "print" comments. + Such lines will not be parsed, but they will be printed to + standard output during the test. This is useful for + describing what each test does. + + c) Valid grammar for the command itself + + 1) Standard command syntax: + This should be ONE shell command, on a line by itself. + + 2) Alternate command syntax: + A) run_as_root: + If the test is preceded by the metacommand "run_as_root" + (on a line by itself) then the command will be run as + root rather than as "p_user". The command should still + be one command on a line by itself. + + B) run_without_test: + If the test is preceded by the metacommand + "run_without_test" (on a line by itself), then ALL + subsequent lines in the section will be executed as + commands, and NO testing will be performed. Note that + the commands will be executed as root. This is useful + for re-initialization sections during a test. + NOTE: A testfile cannot end with a "run_without_test" + section. The last section must contain a test. + + d) Valid grammar for the "expected events" lines + + 1) [variable_name] [value] + This specifies that the variable [variable_name] should be + set to [value]. + + 2) [variable_name_1] matches [variable_name_2] + This specifies that both variables should be set to + the same value. A list of valid variables + + 3) [variable_name] store_in [string] + This specifies that the contents of [variable_name] + should be stored in a variable named [string]. + The variable [string] can then be referenced as a + variable in later tests. + + EXAMPLE: if two commands deal with the file "foobar", + you might want to check that they both use the same handle. + In the first section, write + "handle[0] store_in old_handle_0" + In the second section, write + "old_handle_0 matches handle[0]" + + 4) failure + This specifies that the command is expected to fail + (return some non-zero exit status). If "failure" + is not specified, the command is expected to succeed. + + e) The last line of these sections should begin with three + hyphens "---". Other characters on that line will be ignored. + + 6) Sending messages to the DMAPI daemon + + a) Overview + Normally, run_test only reads from the DMAPI daemon, and never + sends messages back. However, sometimes we need the daemon to + execute some function or change its behavior in some way. This + is accomplished by calling "send_msg" as a command in the + testfile. The test daemon has been coded to respond to the + following user events generated by send_msg: + + b) unfriendly_X + Replace X here with an integer, as in "send_msg unfriendly_6". + This causes the daemon to respond to all messages (other than + user events) with DM_RESP_ABORT instead of DM_RESP_CONTINUE, + and with errno X. If the message is just "unfriendly", the + default errno is EBADMSG. + + c) friendly + This returns the test_daemon to normal operation after it + was set to be "unfriendly". + + d) countdown_X_Y + Replace X and Y with integers, as in "send_msg countdown_6_8". + This causes the daemon to respond to the next X messages (other + than user events) with DM_RESP_ABORT instead of DM_RESP_CONTINUE, + and with errno Y. If the message is just "countdown", the + default count is 5 and the default errno is EAGAIN. + + e) pending_X + Replace X here with an integer, as in "send_msg pending_4". + This causes the daemon to call dm_pending() rather than + responding to the next X messages. If the message is just + "pending", the default count is 1. After the count reaches + zero, the messages will be responded to. + + f) reset_fs + This message MUST be sent after remounting the test filesystem. + It causes the daemon to re-register for all events. + + g) over + This message is sent by run_test itself, and should not be + sent in a testfile. "send_msg over" is called after each + command is executed, as an indicator that the batch of events + from that command is complete. When run_test sees a user + event with the data "over", it knows to stop reading events + and move on to the next command. + + 7) Other "helper functions" for testfiles + + a) ctf (create test files) + purpose: creates 20 copies of "bindir/ls_to_copy". + parameters: location of "bindir", location of target directory. + written in: ksh + + b) crttf (create realtime test files) + purpose: creates 10 realtime files. + parameters: location of "bindir", location of target directory. + written in: ksh + + c) stf (setup test files) + purpose: set dm attributes and managed regions on target files. + parameters: location of "bindir", pathnames of target files. + written in: ksh + + d) fcntl + purpose: do fcntl() syscall + parameters: see "usage" by running without parameters. + written in: C (source not included) + + e) open_test + purpose: do open() syscall + parameters: see "usage" by running without parameters. + written in: C + + f) rd + purpose: do read() syscall + parameters: see "usage" by running without parameters. + written in: C (source not included) + + g) new_wf + purpose: do write() syscall (new version of wf) + parameters: see "usage" by running without parameters. + written in: C (source not included) + + h) wf + purpose: do write() syscall + parameters: see "usage" by running without parameters. + written in: C (source not included) + + i) truncate + purpose: truncate a file + parameters: see "usage" by running without parameters. + written in: C (source not included) + + j) read_invis + purpose: do dm_read_invis() + parameters: see "usage" by running without parameters. + written in: C + + k) write_invis + purpose: do dm_write_invis(). + parameters: see "usage" by running without parameters. + written in: C + + l) set_region + purpose: do dm_set_region() + parameters: see "usage" by running without parameters. + written in: C + + m) set_return_on_destroy + purpose: do dm_set_return_on_destroy() + parameters: see "usage" by running without parameters. + written in: C + + n) ctest.c + purpose: test memory mapping used by cc during compilation + (really a helper file, not a helper function) + + o) mmap_cp + purpose: test memory mapping by using it to copy a file + parameters: source pathname, destination pathname + written in: C (source not included) + + p) dump_allocinfo + purpose: test dm_get_allocinfo by using it to dump + a list of file extents, much like to xfs_bmap. + parameters: see "usage" by running without parameters + written in: C + + q) mm_fill + purpose: fill a filesystem, using memory-mapped i/o + parameters: pathname of target file + written in: C + + r) make_holey + purpose: create a hole-filled file, using wf + parameters: path to "bindir", pathname of target file, + count of how many holes should be created + written in: ksh diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/README_for_check_dmapi linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/README_for_check_dmapi --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/README_for_check_dmapi Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/README_for_check_dmapi Tue Jan 16 19:24:14 2001 @@ -0,0 +1,60 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +### README for check_dmapi ### + +check_dmapi tests the version of DMAPI library & kernel code. + +command line: check_dmapi [-v] +(v is a verbose-output flag) + +Functionality: + +1) Ensures that the user is running as root, using getuid(). + +2) Tries to stat() /usr/include/sys/dmi.h to verify its + presence and its size. + +3) Verifies the presence of the DMAPI kernel, using a + direct call to dmi(). The call is invalid, so it should + return EINVAL if the kernel code is in place, ENOPKG if not. + +4) Determines the status of the kernel (if it is present) using + a direct call to dmi(). The call is invalid, and uses an opcode + not present in the old kernel. So ENOSYS means old kernel; + EINVAL means new kernel. + +5) Determines the status of the library by calling dm_init_service(). + If this fails, libraries are missing. In the old library, this call + did not change its "name" parameter, but in the new library it does. + Same name means old library; changed name means new library. + +6) Outputs its findings. diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/CVS/Entries linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/CVS/Entries --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/CVS/Entries Thu Jul 5 11:45:57 2001 @@ -0,0 +1,8 @@ +/crttf/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/ctf/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/make_holey/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/run_test/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/stf/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/test_allocinfo_1/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/test_allocinfo_2/1.1/Wed Jan 17 01:24:14 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/CVS/Repository linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/CVS/Repository --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/CVS/Repository Thu Jul 5 11:45:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/CVS/Root linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/CVS/Root --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/CVS/Root Thu Jul 5 11:45:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/crttf linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/crttf --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/crttf Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/crttf Tue Jan 16 19:24:14 2001 @@ -0,0 +1,43 @@ +#!/bin/ksh + +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +if [[ $# != 2 ]] +then print -u2 "USAGE: ${0##*/} bindir testdir" + exit 2 +fi + +for i in 0 1 2 3 4 5 6 7 8 9 + do + $1/new_wf -l 32768 -b 4096 -R $2/realtime.$i + done + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/ctf linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/ctf --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/ctf Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/ctf Tue Jan 16 19:24:14 2001 @@ -0,0 +1,44 @@ +#!/bin/ksh + +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +if [[ $# != 2 ]] +then print -u2 "USAGE: ${0##*/} bindir testdir" + exit 2 +fi + +for i in 0 1 2 3 4 5 6 7 8 9 + do + cp $1/ls_to_copy $2/ls"$i" + cp $1/ls_to_copy $2/ll"$i" + done + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/make_holey linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/make_holey --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/make_holey Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/make_holey Tue Jan 16 19:24:14 2001 @@ -0,0 +1,57 @@ +#!/bin/ksh + +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +if [[ $# != 3 ]] +then print "usage: ${0##*/} bindir target_file count" + exit 1 +fi + +typeset -i offset +typeset -i length +typeset -i count + +RANDOM=$SECONDS +offset=0 +length=$RANDOM +count=$3 + +while (( count > 0 )) +do + print "Count: $count" + $1/wf -l $length -L $offset -b 512 $2 + (( offset = RANDOM * 512 + offset + length )) + (( length = RANDOM )) + (( count = count - 1 )) +done + + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/run_test linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/run_test --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/run_test Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/run_test Tue Jan 16 19:24:14 2001 @@ -0,0 +1,552 @@ +#!/bin/ksh + +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +#-----------------------------------------------------------------# +# run_test: a ksh script for testing the DMAPI. +# +# USAGE: run_test [-p] [-x] [-u user] +# [-F fs_type -M fs_mtpt -R "real" directory] +# [-f datafile] [-s sleeptime] +# bindir testdir fsdir +# +# p: Causes pausing after every test (not just ones with errors). +# +# x: Prints an execution trace as the script runs. +# +# user: Most tests don't need root access, so they will be run +# under this username. +# +# (NOTE: the following three must be used together) +# +# fs_type: For NFS tests; the type of filesystem (ie nfs2, nfs3). +# +# fs_mtpt: For NFS tests, the path to the mount of your +# "real" filesystem. +# (ie, "mount -t nfs2 localhost:/dmitest $fs_mtpt") +# +# "real" directory: For NFS tests, the path to the "real" test directory. +# +# datafile: The name of the file which contains the tests to run. +# +# sleeptime: time, in seconds, for the daemon to sleep after +# responding to an event. (Useful for testing small +# outstanding-events queues.) +# +# bindir: The path to the directory that holds dm_test_daemon, send_msg, +# the datafile, and any other files required by the datafile. +# +# testdir: The path to the test directory. All DMAPI testing +# occurs here -- this is where the tests will actually +# be run. (For NFS tests, this will be an NFS mount +# of the "real" directory.) +# +# fsdir: The path name of the test filesystem. The daemon will start +# using this path, and the mount and unmount of the DMAPI +# filesystem will be done here. (Even for NFS tests, this +# should still be the same test filesystem.) +# +#-----------------------------------------------------------------# + +# For most reads, we'll want spaces to be the field separators. +IFS=" " + +typeset -i fail_flag +typeset -i pause_flag +typeset -i sleeptime + +# To run tests that don't require root access, we'll change to +# a user specified by lname. +lname=$LOGNAME + +# Set the default external files to use. +datafile=main.dat +sleeptime=0 + +unset fs_type fs_mtpt +real_dir=set_me_later + +# Parse the command-line options +while getopts :pxu:F:M:R:f:b:s: option +do case $option in + p) pause_flag=1;; + x) set -x;; + u) lname=$OPTARG;; + F) fs_type=$OPTARG;; + M) fs_mtpt=$OPTARG;; + R) real_dir=$OPTARG;; + f) datafile=$OPTARG;; + b) bindir=$OPTARG;; + s) sleeptime=$OPTARG;; + :) print -u2 "${0##*/}: $OPTARG requires a value" + exit 2;; + \?) print -nu2 "USAGE: ${0##*/} [-p] [-x] [-u user] " + print -nu2 "[-F fs type -M mountpoint directory -R \"real\" directory] " + print -u2 "[-s sleeptime] [-f datafile] bindir testdir fsdir" + exit 2;; + esac +done + +# Shift out the examined options, then check that we have +# exactly three arguments left: (the paths to the "bindir", +# the test directory, and the filesystem). +shift OPTIND-1 +if [[ $# != 3 ]] +then print -nu2 "USAGE: ${0##*/} [-p] [-x] [-u user] " + print -nu2 "[-F fs type -M mountpoint directory -R \"real\" directory] " + print -u2 "[-s sleeptime] [-f datafile] bindir testdir fsdir" + exit 2 +fi + +# For NFS tests, $2 will be an NFS mount of the test directory; +# real_dir should be the test directory's actual path. +# Otherwise, real_dir should just be $2. +if [[ $real_dir = set_me_later ]] +then real_dir=$2 +fi + +# Check bindir for the existence of our three critical external files. +error_count=0 +for i in dm_test_daemon send_msg $datafile +do + if [[ ! ( -r "$1/$i" ) ]] + then if ((error_count==0)) + then print "Aborting: the directory $1/ is missing critical files:" + fi + print "$1/$i" + (( error_count = error_count + 1 )) + fi +done +if (( error_count > 0 )) +then exit 1 +fi + +# Open the datafile on file descriptor 3 +exec 3< $1/$datafile + +# Read datafile and determine what files it needs from bindir; +# then, check for the existence of these files. +error_count=0 +while read -u3 file_list +do case $file_list in + ---*) break;; + //*) continue;; + *) for i in $file_list + do if [[ ! ( -r "$1/$i" ) ]] + then if ((error_count==0)) + then print "The directory $1/ is missing these files:" + fi + print "$1/$i" + (( error_count = error_count + 1 )) + fi + done;; + esac +done +if (( error_count > 0 )) + then exit 1 +fi + +# Run initialization stuff without daemon. +while read -u3 cmd +do case $cmd in + //*) continue;; + ---*) break;; + *) eval "$cmd";; + esac +done + +# If we're testing over nfs, remount the filesystem to clear the cache. +case $fs_type in + nfs2) print "Clearing nfs2 cache by remounting filesystem..." + eval "umount $fs_mtpt" + eval "mount -t nfs2 localhost:$3 $fs_mtpt";; + nfs3) print "Clearing nfs3 cache by remounting filesystem..." + eval "umount $fs_mtpt" + eval "mount -t nfs3 localhost:$3 $fs_mtpt";; + *) if [[ $fs_type != "" ]] + then print "ERROR: $fs_type not a known or testable filesystem type" + fi;; +esac + + +# Check with the user before starting up daemon +print "\n** Using testfile ${datafile##*/} **" +print "** Using userid $lname for tests not requiring root access **" +print "Press enter to begin, or enter q or n to abort..." +read go +case "$go" in + n|N|q|Q) exit 1;; + *);; +esac + +# Now, the user will need ownership of the test directory +# ($2, not $real_dir, since real_dir is accessed only as root). +eval "chown $lname $2" + +# Now it's time to begin running the daemon as a coprocess. +# The daemon will use a : as its internal field separator. +IFS=":" +if (($sleeptime > 0)) then + $1/dm_test_daemon -s $sleeptime $3 |& +else + $1/dm_test_daemon $3 |& +fi + +#Keep track of the coprocess id... "$!" may change. +coproc=$! + +# Initialize the count of errors +error_count=0; + +# dm_test_daemon starts with a spurious line feed. +read -p junk + +# Finally, we've reached the actual loop to read in the testfile. +while true +do + clear + while read -u3 cmd + do + case $cmd in + run_without_test) + while read -u3 cmd + do case $cmd in + ---*) clear; continue 2;; + //*) continue;; + @@*) cmd=${cmd#@@*} + print "!! ${cmd# *}" + continue;; + *) eval $cmd;; + esac + done;; + run_as_root) + read -u3 cmd + root_flag=1 + break;; + //*) continue;; + @@*) cmd=${cmd#@@*} + print "!! ${cmd# *}" + continue;; + *) root_flag=0 + break;; + esac + done + if (( $root_flag == 1 )) + then print "Command to execute (as root):\n\n $cmd\n" + eval "$cmd" + else print "Command to execute:\n\n $cmd\n" + eval "su $lname -c \"$cmd\"" + fi + + # Note failure of the command. Also, send a message + # that the command is done. We will know we're done + # reading from the daemon when we see this message. + fail_flag=$? + $1/send_msg over + print + + # Reset variables for reading this command. + event_count=0 + unset contents event fs_handle handle length offset + unset media_designator mode mountpoint_handle + unset mountpoint_path msg_str name new_name new_parent + unset parent_handle ret_code root_handle sequence token + unset tries_left unmount_mode + + # Read events, report them, and store their data. + while true + do + read -p event[event_count] + case "${event[event_count]}" in + mount) + print "Report: found mount event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk fs_handle[event_count] + read -p junk mountpoint_handle[event_count] + read -p junk mountpoint_path[event_count] + read -p junk media_designator[event_count] + read -p junk root_handle[event_count] + read -p junk mode[event_count] + read -p junk;; + preunmount) + print "Report: found preunmount event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk fs_handle[event_count] + read -p junk root_handle[event_count] + read -p junk unmount_mode[event_count] + read -p junk;; + unmount) + print "Report: found unmount event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk fs_handle[event_count] + read -p junk unmount_mode[event_count] + read -p junk ret_code[event_count] + read -p junk;; + nospace) + print "Report: found nospace event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk fs_handle[event_count] + read -p junk;; + create|remove) + print "Report: found ${event[event_count]} event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk parent_handle[event_count] + read -p junk name[event_count] + read -p junk mode[event_count] + read -p junk;; + postcreate) + print "Report: found postcreate event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk parent_handle[event_count] + read -p junk handle[event_count] + read -p junk name[event_count] + read -p junk mode[event_count] + read -p junk ret_code[event_count] + read -p junk;; + postremove) + print "Report: found postremove event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk parent_handle[event_count] + read -p junk name[event_count] + read -p junk mode[event_count] + read -p junk ret_code[event_count] + read -p junk;; + rename) + print "Report: found rename event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk parent_handle[event_count] + read -p junk new_parent[event_count] + read -p junk name[event_count] + read -p junk new_name[event_count] + read -p junk;; + postrename) + print "Report: found postrename event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk parent_handle[event_count] + read -p junk new_parent[event_count] + read -p junk name[event_count] + read -p junk new_name[event_count] + read -p junk ret_code[event_count] + read -p junk;; + symlink) + print "Report: found symlink event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk parent_handle[event_count] + read -p junk name[event_count] + read -p junk contents[event_count] + read -p junk;; + postsymlink) + print "Report: found postsymlink event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk parent_handle[event_count] + read -p junk handle[event_count] + read -p junk name[event_count] + read -p junk contents[event_count] + read -p junk ret_code[event_count] + read -p junk;; + link) + print "Report: found link event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk parent_handle[event_count] + read -p junk handle[event_count] + read -p junk name[event_count] + read -p junk;; + postlink) + print "Report: found postlink event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk parent_handle[event_count] + read -p junk handle[event_count] + read -p junk name[event_count] + read -p junk ret_code[event_count] + read -p junk;; + read|write|truncate) + print "Report: found ${event[event_count]} event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk handle[event_count] + read -p junk offset[event_count] + read -p junk length[event_count] + read -p junk;; + attribute) + print "Report: found attribute event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk handle[event_count] + read -p junk;; + destroy) + print "Report: found destroy event." + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk handle[event_count] + read -p junk name[event_count] + read -p junk contents[event_count] + read -p junk;; + user) + read -p junk token[event_count] + read -p junk sequence[event_count] + read -p junk msg_str[event_count] + case "${msg_str[event_count]}" in + "over") read -p junk + event[event_count]=end_of_tests + print "Report: found \"end of test\" user event. " + break;; + *) print "Report: found user event. " + read -p junk;; + esac;; + pending) + read -p junk tries_left[event_count] + print -n "Report: process pending. " + print "Tries left: ${tries_left[event_count]}" + read -p junk;; + *) + print -n "Report: found ${event[event_count]} event. " + print "(unknown to this version)" + while read -p msg_str[event_count] + do case "${msg_str[event_count]}" in + "end_of_message") break;; + *);; + esac + done;; + esac + ((event_count=event_count+1)) + done + ((old_error_count=error_count)); + + IFS=" " + + while read -u3 val_one val_two val_tre + do case $val_one in + ---*) if [[ $fail_flag != -1 ]] + then if [[ $fail_flag != 0 ]] + then print -n "ERROR: command failed; it was " + print "expected to succeed." + ((error_count=error_count+1)) + fi + fi + if (( error_count>old_error_count || pause_flag==1 )) + then print "\nEnter q to quit, or press enter to continue..." + read go + case "$go" in + q|Q) break;; + *);; + esac + fi + IFS=":" + continue 2;; + failure) + if [[ $fail_flag = 0 ]] + then print "ERROR: command succeeded; it was expected to fail." + ((error_count=error_count+1)) + else print "Note: command is expected to fail." + fi + fail_flag=-1;; + *) case $val_two in + matches) + if [[ $(eval "print $"{$val_one}) = $(eval "print $"{$val_tre}) ]] + then print "Report: $val_one and $val_tre match; both are " + if [[ $(eval "print $"{$val_one}) = "" ]] + then print "unset" + else print "$(eval "print $"{$val_one})" + fi + else print -n "ERROR: $val_one was " + if [[ $(eval "print $"{$val_one}) = "" ]] + then print -n "unset " + else print -n "equal to $(eval "print $"{$val_one})" + fi + print -n ", while $val_tre was " + if [[ $(eval "print $"{$val_tre}) = "" ]] + then print "unset." + else print "equal to $(eval "print $"{$val_tre})." + fi + ((error_count=error_count+1)) + fi;; + store_in) + eval ${val_tre}=$(eval "print $"{$val_one}) + print -n "Report: value of ${val_one} copied into " + print "${val_tre}.";; + *) + if [[ $(eval "print $"{$val_one}) = $val_two ]] + then : + else if [[ "$val_one" = event_count ]] + then print -n "ERROR: expected $val_two event(s), " + print "but found $event_count." + else print -n "ERROR: $val_one was " + if [[ $(eval "print $"{$val_one}) = "" ]] + then print -n "unset " + else print -n "equal to $(eval "print $"{$val_one}) " + fi + print "rather than $val_two as expected." + fi + ((error_count=error_count+1)) + fi;; + esac;; + esac + done + if [[ $fail_flag != -1 ]] + then if [[ $fail_flag != 0 ]] + then print -n "ERROR: command failed; it was " + print "expected to succeed." + ((error_count=error_count+1)) + fi + fi + if (( error_count>old_error_count || pause_flag==1 )) + then print "\nTests complete. Press enter to quit..." + read go + fi + break +done + +# Close the datafile +exec 3<&- + +# End the daemon +kill $coproc +wait $coproc + +clear +if ((error_count==1)) +then print "Test result: 1 error found." +else print "Test result: $error_count errors found." +fi diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/stf linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/stf --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/stf Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/stf Tue Jan 16 19:24:14 2001 @@ -0,0 +1,41 @@ +#!/bin/ksh +# +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +sr_dir=$1 +shift 1 + +for i in $* + do + attr -Rq -s SGI_DMI_test -V123456789abcdefghijklmnopqrstuvwxyz $i + $sr_dir/set_region $i DM_REGION_READ DM_REGION_WRITE DM_REGION_TRUNCATE > /dev/null + done diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/test_allocinfo_1 linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/test_allocinfo_1 --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/test_allocinfo_1 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/test_allocinfo_1 Tue Jan 16 19:24:14 2001 @@ -0,0 +1,100 @@ +#!/bin/ksh + +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + + +# Dump the same holey file using both xfs_bmap and +# dump_allocinfo (a C wrapper for get_allocinfo). +# Run awk on the xfs_bmap output, since xfs_bmap +# gives specific block allocation info that get_allocinfo +# does not. Then diff the two outputs. + +if [[ $# != 2 ]] +then print "USAGE: ${0##*/} bindir testdir" + exit 1 +fi + +# Check bindir for needed programs. +if [[ ! ( -r "$1/wf" ) ]] +then print "Aborting: necessary program wf is not in $1/." + if [[ ! ( -r "$1/dump_allocinfo" ) ]] + then print " necessary program dump_allocinfo is also missing." + fi + exit 1 +fi +if [[ ! ( -r "$1/dump_allocinfo" ) ]] +then print "Aborting: necessary program dump_allocinfo is not in $1/." + exit 1 +fi + +print "Comparison test (get_allocinfo vs. xfs_bmap) beginning..." + +typeset -i offset +typeset -i length +typeset -i count + +RANDOM=$SECONDS +offset=0 +length=$RANDOM +count=100 +filename=DMAPI_test_allocinfo + +# Create a random holey file +while (( count > 0 )) +do + $1/wf -l $length -L $offset -b 512 $2/$filename > /dev/null + (( offset = RANDOM * 512 + offset + length )) + (( length = RANDOM )) + (( count = count - 1 )) +done + +# Get output from xfs_bmap +xfs_bmap $2/DMAPI_test_allocinfo > $2/$filename.xfs + +# Get output from dump_allocinfo (DMAPI) +$1/dump_allocinfo $2/DMAPI_test_allocinfo > $2/$filename.da + +# Alter xfs_bmap ouput to match get_allocinfo +awk '{ if (NR > 1) + if ($3 == "hole") + print $1, $2, $3 + else + print $1, $2, "resv" +}' $2/DMAPI_test_allocinfo.xfs > $2/$filename.ok + +# Compare the ouput +diff -w $2/$filename.ok $2/$filename.da + +# Remove the test file +rm $2/$filename* + +print "Test complete." diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/test_allocinfo_2 linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/test_allocinfo_2 --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/bindir/test_allocinfo_2 Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/bindir/test_allocinfo_2 Tue Jan 16 19:24:14 2001 @@ -0,0 +1,100 @@ +#!/bin/ksh + +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +# Dump the same holey file a random number of times, each time +# using one less extent structure than the previous time. +# The grep and diff code checks to make sure that you get the +# same answer each time, no matter how many extents you use. + +typeset -i offset +typeset -i length +typeset -i max + +# Verify correct usage +if [[ $# != 2 ]] +then print "usage: ${0##*/} bindir testdir" + exit 1 +fi + +# Check bindir for needed programs. +if [[ ! ( -r "$1/wf" ) ]] +then print "Aborting: necessary program wf is not in $1/." + if [[ ! ( -r "$1/dump_allocinfo" ) ]] + then print " necessary program dump_allocinfo is also missing." + fi + exit 1 +fi +if [[ ! ( -r "$1/dump_allocinfo" ) ]] +then print "Aborting: necessary program dump_allocinfo is not in $1/." + exit 1 +fi + +print "Multiple-buffer-sizes test of get_allocinfo beginning..." + +RANDOM=$SECONDS +offset=0 +length=$RANDOM +filename=DMAPI_alloc_test_2 +((max = $RANDOM/256)) +count=$max + +# Holey file creation: put about $max holes into the file. +while (( count > 0 )) +do + $1/wf -l $length -L $offset -b 512 $2/$filename > /dev/null + (( offset = RANDOM * 512 + offset + length )) + (( length = RANDOM )) + (( count = count - 1 )) +done +count=$max + +# Now count down from $max to 1 and try dump_allocinfo with a buffer that +# can hold that many dm_extent_t structures. +while [[ $count > 0 ]] +do + $1/dump_allocinfo -n $count $2/$filename | grep '\[' > $2/x.$count + if (( count < max )) + then diff $2/x.$count $2/x.$max > /dev/null + if [[ $? != 0 ]] + then print "ERROR in trial #$count:" + diff $2/x.$count $2/x.$max + fi + rm $2/x.$count + fi + (( count = count - 1 )) +done + +rm $2/x.$max +rm $2/$filename + +print "Test complete." diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/create_cpio linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/create_cpio --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/create_cpio Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/create_cpio Tue Jan 16 19:24:14 2001 @@ -0,0 +1,37 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +rm /home/hickory43/jayw/test/dist/DMAPI_test.cpio +cd /home/hickory43/jayw/test +find * \( ! -name '*.o' ! -name '*~' ! -name './dist/*' \) | cpio -oc > /home/hickory43/jayw/test/dist/DMAPI_test.cpio +cp /home/hickory43/jayw/test/README /home/hickory43/jayw/test/dist/README +cd /home/hickory43/jayw/test/dist + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/CVS/Entries linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/CVS/Entries --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/CVS/Entries Thu Jul 5 11:45:57 2001 @@ -0,0 +1,10 @@ +/fail.dat/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/main.dat/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/nfs.dat/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/pending.dat/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/pending_nfs.dat/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/realtime.dat/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/smallq.dat/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/standard.dat/1.1/Wed Jan 17 01:24:14 2001/-ko/ +/standard_nfs.dat/1.1/Wed Jan 17 01:24:14 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/CVS/Repository linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/CVS/Repository --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/CVS/Repository Thu Jul 5 11:45:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/CVS/Root linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/CVS/Root --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/CVS/Root Thu Jul 5 11:45:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/fail.dat linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/fail.dat --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/fail.dat Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/fail.dat Tue Jan 16 19:24:14 2001 @@ -0,0 +1,118 @@ +// +// Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of version 2 of the GNU General Public License as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it would be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// Further, this software is distributed without any warranty that it is +// free of the rightful claim of any third person regarding infringement +// or the like. Any license provided herein, whether implied or +// otherwise, applies only to this software file. Patent licenses, if +// any, provided herein do not apply to combinations of this program with +// other software, or any other product whatsoever. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write the Free Software Foundation, Inc., 59 +// Temple Place - Suite 330, Boston MA 02111-1307, USA. +// +// Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +// Mountain View, CA 94043, or: +// +// http://www.sgi.com +// +// For further information regarding this notice, see: +// +// http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +// This test will use the following files: +// +ctf stf ls_to_copy ctest.c +fcntl open_test truncate rd wf +set_region set_return_on_destroy +-------------------------------------------- +// These setup commands are run before the daemon starts. +// They reset the file structure of the test directory +// to a known state, and they ensure that the NFS +// +rm $real_dir/??? +$1/ctf $1 $real_dir +$1/stf $1 $real_dir/l?? +rm $real_dir/ctest.c +cp $1/ctest.c $real_dir +chown $lname $real_dir/* +$1/set_return_on_destroy $real_dir test +rmdir $real_dir/fail_tempdir/fail_subdir +rm $real_dir/fail_tempdir/* +rmdir $real_dir/fail_tempdir +mkdir $real_dir/fail_tempdir +mkdir $real_dir/fail_tempdir/fail_subdir +echo "Temporary file" > $real_dir/fail_tempdir/temp_file +chown root $real_dir/fail_tempdir +-------------------------------------------- +@@ Failure checks (1 of 8): symlink +@@ +ln -s $2/fail_tempdir/temp_file $2/fail_tempdir/failed_symlink +event_count 2 +event[0] symlink +event[1] postsymlink +ret_code[1] 13 +failure +-------------------------------------------- +@@ Failure checks (2 of 8): link +@@ +ln $2/fail_tempdir/temp_file $2/fail_tempdir/failed_link +event_count 2 +event[0] link +event[1] postlink +ret_code[1] 13 +failure +-------------------------------------------- +@@ Failure checks (3 of 8): mkdir +@@ +mkdir $2/fail_tempdir/failed_subdir +event_count 2 +event[0] create +event[1] postcreate +ret_code[1] 13 +failure +-------------------------------------------- +@@ Failure checks (4 of 8): rmdir +@@ +rmdir $2/fail_tempdir/fail_subdir +event_count 2 +event[0] remove +event[1] postremove +ret_code[1] 13 +failure +-------------------------------------------- +@@ Failure checks (5 of 8): open +@@ +$1/open_test $2/fail_tempdir/temp_file o_rdwr +event_count 0 +failure +-------------------------------------------- +@@ Failure checks (6 of 8): open/create +@@ +$1/open_test $2/fail_tempdir/temp_file o_rdwr o_creat +event_count 0 +failure +-------------------------------------------- +@@ Failure checks (7 of 8): open/truncate +@@ +$1/open_test $2/fail_tempdir/temp_file o_rdwr o_trunc +event_count 0 +failure +-------------------------------------------- +@@ Failure checks (8 of 8): remove +@@ +rm -f $2/fail_tempdir/temp_file +event_count 2 +event[0] remove +event[1] postremove +ret_code[1] 13 +failure diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/main.dat linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/main.dat --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/main.dat Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/main.dat Tue Jan 16 19:24:14 2001 @@ -0,0 +1,159 @@ +// +// Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of version 2 of the GNU General Public License as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it would be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// Further, this software is distributed without any warranty that it is +// free of the rightful claim of any third person regarding infringement +// or the like. Any license provided herein, whether implied or +// otherwise, applies only to this software file. Patent licenses, if +// any, provided herein do not apply to combinations of this program with +// other software, or any other product whatsoever. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write the Free Software Foundation, Inc., 59 +// Temple Place - Suite 330, Boston MA 02111-1307, USA. +// +// Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +// Mountain View, CA 94043, or: +// +// http://www.sgi.com +// +// For further information regarding this notice, see: +// +// http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +// This test will use the following files: +// +ctf stf ls_to_copy ctest.c +fcntl open_test truncate rd wf +read_invis write_invis +set_region set_return_on_destroy +-------------------------------------------- +// These setup commands are run before the daemon starts. +// They reset the file structure of the test directory +// to a known state. +// +rm $real_dir/??? +rm $real_dir/ctest.c +$1/ctf $1 $real_dir +$1/stf $1 $real_dir/l?? +cp $1/ctest.c $real_dir +chown $lname $real_dir/l?? +chown $lname $real_dir/ctest.c +$1/set_return_on_destroy $real_dir test +-------------------------------------------- +@@ Aborted events testing (1 of 7): +@@ Read ls0 successfully. +@@ +$1/open_test $2/ls0 o_rdwr +event_count 1 +event[0] read +-------------------------------------------- +@@ Aborted events testing (2 of 7): +@@ Set the daemon to halt events with DM_RESP_ABORT +@@ and errno EEXIST. +@@ +run_as_root +$1/send_msg unfriendly_17 +event_count 1 +event[0] user +msg_str[0] unfriendly_17 +-------------------------------------------- +@@ Aborted events testing (3 of 7): +@@ Try to read ls0. this should fail with EEXIST. +@@ +$1/open_test $2/ls0 o_rdwr +event_count 1 +event[0] read +failure +-------------------------------------------- +@@ Aborted events testing (4 of 7): +@@ Try to read ls1. This should fail with EEXIST. +@@ +$1/open_test $2/ls1 o_rdwr o_trunc +event_count 1 +event[0] truncate +failure +-------------------------------------------- +@@ Aborted events testing (5 of 7): +@@ Reset the daemon to respond with DM_RESP_CONTINUE. +@@ +run_as_root +$1/send_msg friendly +event_count 1 +event[0] user +msg_str[0] friendly +-------------------------------------------- +@@ Aborted events testing (6 of 7): +@@ Again, try to read ls0. This should succeed. +@@ +$1/open_test $2/ls0 o_rdwr +event_count 1 +event[0] read +-------------------------------------------- +@@ Aborted events testing (7 of 7): +@@ Again, try to read ls1. This time, +@@ it should succeed. +@@ +$1/open_test $2/ls1 o_rdwr o_trunc +event_count 2 +event[0] truncate +event[1] attribute +-------------------------------------------- +@@ dm_send_msg test +@@ +run_as_root +$1/send_msg dmapi-test-foo-abc123 +event_count 1 +event[0] user +msg_str[0] dmapi-test-foo-abc123 +-------------------------------------------- +@@ Test of invisible i/o (1 of 2): write +@@ +run_as_root +$1/write_invis -o 64 -l 16 $2/ls0 +event_count 0 +-------------------------------------------- +@@ Test of invisible i/o (2 of 2): read +@@ +run_as_root +$1/read_invis -o 64 -l 16 $2/ls0 +event_count 0 +-------------------------------------------- +@@ Test of direct i/o (1 of 2): write +@@ +$1/wf -l 327680 -b 32768 -d $2/ls9 +event_count 10 +event[0] write +event[1] write +event[2] write +event[3] write +event[4] write +event[5] write +event[6] write +event[7] write +event[8] write +event[9] write +-------------------------------------------- +@@ Test of direct i/o (2 of 2): read +@@ +$1/rd -b 32768 -d $2/ls9 +event_count 11 +event[0] read +event[1] read +event[2] read +event[3] read +event[4] read +event[5] read +event[6] read +event[7] read +event[8] read +event[9] read +event[10] read diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/nfs.dat linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/nfs.dat --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/nfs.dat Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/nfs.dat Tue Jan 16 19:24:14 2001 @@ -0,0 +1,174 @@ +// +// Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of version 2 of the GNU General Public License as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it would be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// Further, this software is distributed without any warranty that it is +// free of the rightful claim of any third person regarding infringement +// or the like. Any license provided herein, whether implied or +// otherwise, applies only to this software file. Patent licenses, if +// any, provided herein do not apply to combinations of this program with +// other software, or any other product whatsoever. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write the Free Software Foundation, Inc., 59 +// Temple Place - Suite 330, Boston MA 02111-1307, USA. +// +// Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +// Mountain View, CA 94043, or: +// +// http://www.sgi.com +// +// For further information regarding this notice, see: +// +// http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +// This test will use the following files: +// +ctf stf ls_to_copy ctest.c +fcntl open_test truncate rd wf +set_region set_return_on_destroy +-------------------------------------------- +// These setup commands are run before the daemon starts. +// They reset the file structure of the test directory +// to a known state. +// +rm $real_dir/??? +$1/ctf $1 $real_dir +$1/stf $1 $real_dir/l?? +chown $lname $real_dir/l?? +$1/set_return_on_destroy $real_dir test +-------------------------------------------- +@@ Aborted events testing (1 of 7): +@@ Bring ls0 across NFS, causing it to be cached. +@@ +$1/open_test $2/ls0 o_rdwr +event_count 1 +event[0] read +-------------------------------------------- +@@ Aborted events testing (2 of 7): +@@ Set the daemon to halt events with DM_RESP_ABORT +@@ and errno EEXIST. +@@ +run_as_root +$1/send_msg unfriendly_17 +event_count 1 +event[0] user +msg_str[0] unfriendly_17 +-------------------------------------------- +@@ Aborted events testing (3 of 7): +@@ Try to read ls0. Since it is cached, this should succeed. +@@ and should not generate any events. +@@ +$1/open_test $2/ls0 o_rdwr +event_count 0 +-------------------------------------------- +@@ Aborted events testing (4 of 7): +@@ Try to read ls1. This should fail with EEXIST. +@@ +$1/open_test $2/ls1 o_rdwr o_trunc +event_count 1 +event[0] truncate +failure +-------------------------------------------- +@@ Aborted events testing (5 of 7): +@@ Reset the daemon to respond with DM_RESP_CONTINUE. +@@ +run_as_root +$1/send_msg friendly +event_count 1 +event[0] user +msg_str[0] friendly +-------------------------------------------- +@@ Aborted events testing (6 of 7): +@@ Again, try to read ls0. It will be in the cache, +@@ so no events should occur. +@@ +$1/open_test $2/ls0 o_rdwr +event_count 0 +-------------------------------------------- +@@ Aborted events testing (7 of 7): +@@ Again, try to read ls1. This time, +@@ it should succeed. +@@ +$1/open_test $2/ls1 o_rdwr o_trunc +event_count 2 +event[0] truncate +event[1] attribute +-------------------------------------------- +@@ dm_send_msg test +@@ +run_as_root +$1/send_msg dmapi-test-foo-abc123 +event_count 1 +event[0] user +msg_str[0] dmapi-test-foo-abc123 +-------------------------------------------- +@@ NFS test: DM_RESP_ABORT (1 of 3) +@@ +// For the next two events, respond with +// DM_RESP_ABORT and errno 4 The first +// open test of ls1 should fail; the +// second should succeed. +// +run_as_root +$1/send_msg countdown_2_4 +event_count 1 +event[0] user +msg_str[0] countdown_2_4 +-------------------------------------------- +@@ NFS test: DM_RESP_ABORT (2 of 3) +@@ +$1/open_test $2/ls2 o_rdwr +event_count 1 +event[0] read +failure +-------------------------------------------- +@@ NFS test: DM_RESP_ABORT (3 of 3) +@@ +$1/open_test $2/ls2 o_rdwr +event_count 1 +event[0] read +-------------------------------------------- +@@ NFS test: EAGAIN (1 of 4) +@@ +// For the next two events, respond with +// DM_RESP_ABORT and errno 11 -- EAGAIN. +// NFS should retry sending the event as +// long as EAGAIN is returned. +// +run_as_root +$1/send_msg countdown_2_11 +event_count 1 +event[0] user +msg_str[0] countdown_2_11 +-------------------------------------------- +@@ NFS test: EAGAIN (2 of 4) +@@ +$1/open_test $2/ls3 o_rdwr +event_count 2 +event[0] read +event[1] read +-------------------------------------------- +@@ NFS test: EAGAIN (3 of 4) +@@ +run_as_root +$1/send_msg countdown_4_11 +event_count 1 +event[0] user +msg_str[0] countdown_4_11 +-------------------------------------------- +@@ NFS test: EAGAIN (4 of 4) +@@ +$1/open_test $2/ls4 o_rdwr +event_count 4 +event[0] read +event[1] read +event[2] read +event[3] read diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/pending.dat linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/pending.dat --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/pending.dat Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/pending.dat Tue Jan 16 19:24:14 2001 @@ -0,0 +1,90 @@ +// +// Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of version 2 of the GNU General Public License as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it would be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// Further, this software is distributed without any warranty that it is +// free of the rightful claim of any third person regarding infringement +// or the like. Any license provided herein, whether implied or +// otherwise, applies only to this software file. Patent licenses, if +// any, provided herein do not apply to combinations of this program with +// other software, or any other product whatsoever. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write the Free Software Foundation, Inc., 59 +// Temple Place - Suite 330, Boston MA 02111-1307, USA. +// +// Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +// Mountain View, CA 94043, or: +// +// http://www.sgi.com +// +// For further information regarding this notice, see: +// +// http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +// This test will use the following files: +// +ctf stf ls_to_copy set_region +-------------------------------------------- +// These setup commands are run before the daemon starts. +// They reset the file structure of the test directory +// to a known state. +// +rm $real_dir/??? +$1/ctf $1 $real_dir +$1/stf $1 $real_dir/l?? +chown $lname $real_dir/l?? +-------------------------------------------- +@@ Pending test (1 of 5): +@@ +// Run "pending" for the next 3 events, +// so that a non-blocking open_test +// will see EAGAIN three times before +// it can finish. +// +run_as_root +$1/send_msg pending_3 +event_count 1 +event[0] user +msg_str[0] pending_3 +-------------------------------------------- +@@ Pending test (2 of 5): +@@ (should fail) +@@ +$1/open_test $2/ls1 o_rdwr o_nonblock +event_count 1 +event[0] pending +tries_left[0] 2 +failure +-------------------------------------------- +@@ Pending test (3 of 5): +@@ (should fail) +@@ +$1/open_test $2/ls1 o_rdwr o_ndelay +event_count 1 +event[0] pending +tries_left[0] 1 +failure +-------------------------------------------- +@@ Pending test (4 of 5): +@@ (should fail) +@@ +$1/open_test $2/ls1 o_rdwr o_nonblock o_ndelay +event_count 1 +event[0] pending +tries_left[0] 0 +failure +-------------------------------------------- +@@ Pending test (5 of 5): +@@ (should succeed) +@@ +$1/open_test $2/ls1 o_rdwr o_nonblock +event_count 1 +event[0] read diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/pending_nfs.dat linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/pending_nfs.dat --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/pending_nfs.dat Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/pending_nfs.dat Tue Jan 16 19:24:14 2001 @@ -0,0 +1,72 @@ +// +// Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of version 2 of the GNU General Public License as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it would be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// Further, this software is distributed without any warranty that it is +// free of the rightful claim of any third person regarding infringement +// or the like. Any license provided herein, whether implied or +// otherwise, applies only to this software file. Patent licenses, if +// any, provided herein do not apply to combinations of this program with +// other software, or any other product whatsoever. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write the Free Software Foundation, Inc., 59 +// Temple Place - Suite 330, Boston MA 02111-1307, USA. +// +// Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +// Mountain View, CA 94043, or: +// +// http://www.sgi.com +// +// For further information regarding this notice, see: +// +// http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +// This test will use the following files: +// +ctf stf ls_to_copy set_region +-------------------------------------------- +// These setup commands are run before the daemon starts. +// They reset the file structure of the test directory +// to a known state. +// +rm $real_dir/??? +$1/ctf $1 $real_dir +$1/stf $1 $real_dir/l?? +chown $lname $real_dir/l?? +-------------------------------------------- +@@ NFS test: pending (1 of 2) +@@ +// Run "pending" for the next 3 events, +// so that ls0 will trigger 3 pending +// pseudo-events before succeeding +// +run_as_root +$1/send_msg pending_3 +event_count 1 +event[0] user +msg_str[0] pending_3 +-------------------------------------------- +@@ NFS test: pending (2 of 2) +@@ +@@ (this will take a while...) +@@ +$2/ls0 -l $real_dir +event_count 7 +event[0] pending +event[1] pending +event[2] pending +event[3] read +event[4] read +event[5] read +event[6] read +tries_left[0] 2 +tries_left[1] 1 +tries_left[2] 0 diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/realtime.dat linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/realtime.dat --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/realtime.dat Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/realtime.dat Tue Jan 16 19:24:14 2001 @@ -0,0 +1,139 @@ +// +// Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of version 2 of the GNU General Public License as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it would be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// Further, this software is distributed without any warranty that it is +// free of the rightful claim of any third person regarding infringement +// or the like. Any license provided herein, whether implied or +// otherwise, applies only to this software file. Patent licenses, if +// any, provided herein do not apply to combinations of this program with +// other software, or any other product whatsoever. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write the Free Software Foundation, Inc., 59 +// Temple Place - Suite 330, Boston MA 02111-1307, USA. +// +// Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +// Mountain View, CA 94043, or: +// +// http://www.sgi.com +// +// For further information regarding this notice, see: +// +// http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +// This test will use the following files: +// +stf crttf new_wf +fcntl open_test truncate rd wf +read_invis write_invis +set_region set_return_on_destroy +-------------------------------------------- +// These setup commands are run before the daemon starts. +// They reset the file structure of the test directory +// to a known state. +// +rm $real_dir/realtime.? +$1/crttf $1 $real_dir +chown $lname $real_dir/* +$1/stf $1 $real_dir/realtime.? +$1/set_return_on_destroy $real_dir test +-------------------------------------------- +@@ Test of invisible i/o (1 of 2): write +@@ +run_as_root +$1/write_invis -o 64 -l 16 $2/realtime.0 +event_count 0 +-------------------------------------------- +@@ Test of invisible i/o (2 of 2): read +@@ +run_as_root +$1/read_invis -o 64 -l 16 $2/realtime.0 +event_count 0 +-------------------------------------------- +@@ Test of direct i/o (1 of 2): write +@@ +$1/wf -l 327680 -b 32768 -d $2/realtime.1 +event_count 10 +event[0] write +event[1] write +event[2] write +event[3] write +event[4] write +event[5] write +event[6] write +event[7] write +event[8] write +event[9] write +-------------------------------------------- +@@ Test of direct i/o (2 of 2): read +@@ +$1/rd -b 32768 -d $2/realtime.1 +event_count 11 +event[0] read +event[1] read +event[2] read +event[3] read +event[4] read +event[5] read +event[6] read +event[7] read +event[8] read +event[9] read +event[10] read +-------------------------------------------- +@@ Standard i/o tests (1 of 7): open +@@ +$1/open_test $2/realtime.2 o_rdwr +event_count 1 +event[0] read +-------------------------------------------- +@@ Standard i/o tests (2 of 7): open/trunc +@@ +$1/open_test $2/realtime.3 o_rdwr o_trunc +event_count 2 +event[0] truncate +event[1] attribute +-------------------------------------------- +@@ Standard i/o tests (3 of 7): open/trunc/create +@@ +$1/open_test $2/realtime.4 o_rdwr o_trunc o_creat +event_count 1 +event[0] truncate +-------------------------------------------- +@@ Standard i/o tests (4 of 7): open/create +@@ +$1/open_test $2/realtime.5 o_rdwr o_creat +event_count 1 +event[0] read +-------------------------------------------- +@@ Standard i/o tests (5 of 7): append #1 +@@ +echo j >> $2/realtime.6 +event_count 1 +event[0] write +file_handle[0] store_in ls4temp +-------------------------------------------- +@@ Standard i/o tests (6 of 7): append #2 +@@ +echo w >> $2/realtime.6 +event_count 1 +event[0] write +file_handle[0] matches ls4temp +-------------------------------------------- +@@ Standard i/o tests (7 of 7): remove +@@ +/bin/rm $2/realtime.6 +event_count 3 +event[0] remove +event[1] destroy +event[2] postremove +name[1] test +contents[1] 123456789abcdefghijklmnopqrstuvwxyz diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/smallq.dat linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/smallq.dat --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/smallq.dat Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/smallq.dat Tue Jan 16 19:24:14 2001 @@ -0,0 +1,106 @@ +// +// Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of version 2 of the GNU General Public License as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it would be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// Further, this software is distributed without any warranty that it is +// free of the rightful claim of any third person regarding infringement +// or the like. Any license provided herein, whether implied or +// otherwise, applies only to this software file. Patent licenses, if +// any, provided herein do not apply to combinations of this program with +// other software, or any other product whatsoever. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write the Free Software Foundation, Inc., 59 +// Temple Place - Suite 330, Boston MA 02111-1307, USA. +// +// Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +// Mountain View, CA 94043, or: +// +// http://www.sgi.com +// +// For further information regarding this notice, see: +// +// http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +// This test will use the following files: +// +ctf stf ls_to_copy ctest.c +fcntl open_test truncate rd wf mmap_cp +read_invis write_invis +set_region set_return_on_destroy +-------------------------------------------- +// These setup commands are run before the daemon starts. +// They reset the file structure of the test directory +// to a known state. +// +rm $real_dir/??? +$1/ctf $1 $real_dir +$1/stf $1 $real_dir/l?? +rm $real_dir/ctest.c +cp $1/ctest.c $real_dir +chown $lname $real_dir/l?? +chown $lname $real_dir/ctest.c +$1/set_return_on_destroy $real_dir test +print +print "Please resize your DMAPI event queue to hold about 2 to 10 events." +-------------------------------------------- +@@ Slow i/o test: Do 10 open_tests +@@ +run_without_test +$1/open_test $2/ls0 o_rdwr & +$1/open_test $2/ls0 o_rdwr & +$1/open_test $2/ls0 o_rdwr & +$1/open_test $2/ls0 o_rdwr & +$1/open_test $2/ls0 o_rdwr & +$1/open_test $2/ls0 o_rdwr & +$1/open_test $2/ls0 o_rdwr & +$1/open_test $2/ls0 o_rdwr & +$1/open_test $2/ls0 o_rdwr & +$1/open_test $2/ls0 o_rdwr & +-------------------------------------------- +@@ Slow i/o test: Append ten bytes to ls1 +@@ +run_without_test +echo J >> $2/ls1 & +echo a >> $2/ls1 & +echo y >> $2/ls1 & +echo w >> $2/ls1 & +echo a >> $2/ls1 & +echo s >> $2/ls1 & +echo h >> $2/ls1 & +echo e >> $2/ls1 & +echo r >> $2/ls1 & +echo e >> $2/ls1 & +-------------------------------------------- +@@ Slow i/o test: Do one more, then stand back and wait! +@@ +$1/open_test $2/ls0 o_rdwr +event_count 21 +event[0] read +event[1] read +event[2] read +event[3] read +event[4] read +event[5] read +event[6] read +event[7] read +event[8] read +event[9] read +event[10] write +event[11] write +event[12] write +event[13] write +event[14] write +event[15] write +event[16] write +event[17] write +event[18] write +event[19] write +event[20] read diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/standard.dat linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/standard.dat --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/standard.dat Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/standard.dat Tue Jan 16 19:24:14 2001 @@ -0,0 +1,323 @@ +// +// Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of version 2 of the GNU General Public License as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it would be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// Further, this software is distributed without any warranty that it is +// free of the rightful claim of any third person regarding infringement +// or the like. Any license provided herein, whether implied or +// otherwise, applies only to this software file. Patent licenses, if +// any, provided herein do not apply to combinations of this program with +// other software, or any other product whatsoever. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write the Free Software Foundation, Inc., 59 +// Temple Place - Suite 330, Boston MA 02111-1307, USA. +// +// Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +// Mountain View, CA 94043, or: +// +// http://www.sgi.com +// +// For further information regarding this notice, see: +// +// http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +// This test will use the following files: +// +ctf stf ls_to_copy ctest.c +fcntl open_test truncate rd wf mmap_cp +read_invis write_invis +set_region set_return_on_destroy +-------------------------------------------- +// These setup commands are run before the daemon starts. +// They reset the file structure of the test directory +// to a known state. +// +rm $real_dir/??? +rm $real_dir/mmap_cp_testfile +$1/ctf $1 $real_dir +$1/stf $1 $real_dir/l?? +rm $real_dir/ctest.c +cp $1/ctest.c $real_dir +chown $lname $real_dir/l?? +chown $lname $real_dir/ctest.c +$1/set_return_on_destroy $real_dir test +-------------------------------------------- +@@ Memory-mapped copying test: (1 of 3) +@@ +$1/mmap_cp $2/ll1 $2/mmap_cp_testfile +event_count 3 +event[0] create +event[1] postcreate +event[2] read +-------------------------------------------- +@@ Memory-mapped copying test: (2 of 3) +@@ +$1/mmap_cp $2/ll1 $2/mmap_cp_testfile +event_count 1 +event[0] read +-------------------------------------------- +@@ Memory-mapped copying test: (3 of 3) +@@ +$1/mmap_cp $2/ll1 $2/ll2 +event_count 2 +event[0] read +event[1] write +-------------------------------------------- +@@ Preunmount/unmount test +@@ (note: if you abort before the next test, the +@@ filesystem will remain unmounted) +@@ +run_as_root +umount $3 +event_count 2 +event[0] preunmount +event[1] unmount +fs_handle[0] matches fs_handle[1] +fs_handle[0] store_in fsh +root_handle[0] store_in rh +unmount_mode[0] NOFORCE +unmount_mode[1] NOFORCE +-------------------------------------------- +@@ Mount test +@@ (Note: assorted settings will be restored in next tests) +@@ +run_as_root +mount $3 +event_count 1 +event[0] mount +fs_handle[0] matches fsh +mountpoint_handle[0] +mountpoint_path[0] /dmitest +mode[0] 0 +root_handle matches rh +-------------------------------------------- +@@ (after remount: restoring event dispositions on fs) +@@ +run_as_root +$1/send_msg reset_fs +event_count 1 +event[0] user +msg_str[0] reset_fs +-------------------------------------------- +@@ (after remount: restoring managed regions on files +@@ and setting destroy events to return "test" attribute) +@@ +run_without_test +$1/stf $1 $real_dir/l?? +$1/set_return_on_destroy $real_dir test +------------------------------------------- +@@ Standard i/o tests (1 of 26): open +@@ +$1/open_test $2/ls0 o_rdwr +event_count 1 +event[0] read +-------------------------------------------- +@@ Standard i/o tests (2 of 26): open/trunc +@@ +$1/open_test $2/ls1 o_rdwr o_trunc +event_count 2 +event[0] truncate +event[1] attribute +-------------------------------------------- +@@ Standard i/o tests (3 of 26): open/trunc/create +@@ +$1/open_test $2/ls2 o_rdwr o_trunc o_creat +event_count 1 +event[0] truncate +-------------------------------------------- +@@ Standard i/o tests (4 of 26): open/create +@@ +$1/open_test $2/ls3 o_rdwr o_creat +event_count 1 +event[0] read +-------------------------------------------- +@@ Standard i/o tests (5 of 26): new file +@@ +$1/open_test $2/LS3 o_rdwr o_creat +event_count 2 +event[0] create +event[1] postcreate +-------------------------------------------- +@@ Standard i/o tests (6 of 26): append #1 +@@ +echo j >> $2/ls4 +event_count 1 +event[0] write +file_handle[0] store_in ls4temp +-------------------------------------------- +@@ Standard i/o tests (7 of 26): append #2 +@@ +echo j >> $2/ls4 +event_count 1 +event[0] write +file_handle[0] matches ls4temp +-------------------------------------------- +@@ Standard i/o tests (8 of 26): remove +@@ +/bin/rm $2/ls4 +event_count 3 +event[0] remove +event[1] destroy +event[2] postremove +name[1] test +contents[1] 123456789abcdefghijklmnopqrstuvwxyz +-------------------------------------------- +@@ Standard i/o tests (9 of 26): link +@@ +ln $2/ls5 $2/LS5 +event_count 2 +event[0] link +event[1] postlink +-------------------------------------------- +@@ Standard i/o tests (10 of 26): deleting link +@@ +/bin/rm $2/LS5 +event_count 2 +event[0] remove +event[1] postremove +-------------------------------------------- +@@ Standard i/o tests (11 of 26): return_on_destroy #1 +@@ +run_without_test +$1/set_return_on_destroy $real_dir +-------------------------------------------- +@@ Standard i/o tests (12 of 26): return_on_destroy #2 +@@ +/bin/rm $2/ls5 +event_count 3 +event[0] remove +event[1] destroy +event[2] postremove +name[1] +contents[1] +-------------------------------------------- +@@ Standard i/o tests (13 of 26) +@@ +$1/fcntl f_freesp -o 99999 -l 199999 $2/ls6 +event_count 2 +event[0] truncate +event[1] attribute +-------------------------------------------- +@@ Standard i/o tests (14 of 26) +@@ +$1/fcntl f_freesp -o 1000 -l 10000 $2/ls6 +event_count 2 +event[0] truncate +event[1] attribute +-------------------------------------------- +@@ Standard i/o tests (15 of 26) truncate #1 +@@ +$1/truncate $2/ls7 99999 +event_count 2 +event[0] truncate +event[1] attribute +-------------------------------------------- +@@ Standard i/o tests (16 of 26) truncate #2 +@@ +$1/truncate $2/ls7 1000 +event_count 2 +event[0] truncate +event[1] attribute +-------------------------------------------- +@@ Standard i/o tests (17 of 26) execute +@@ +$2/ls8 -l $real_dir +event[0] read +event[1] read +event[2] read +event[3] read +event[4] read +offset[0] 0 +length[0] 29604 +file_handle[0] matches file_handle[1] +file_handle[0] matches file_handle[2] +file_handle[0] matches file_handle[3] +-------------------------------------------- +@@ Standard i/o tests (18 of 26) symlink +@@ +ln -s $2/junk $2/symlink +event_count 2 +event[0] symlink +event[1] postsymlink +-------------------------------------------- +@@ Standard i/o tests (19 of 26) deleting symlink +@@ +/bin/rm $2/symlink +event_count 3 +event[0] remove +event[1] destroy +event[2] postremove +-------------------------------------------- +@@ Standard i/o tests (20 of 26) mkdir +@@ +mkdir $2/unlikely-named-test-dir +event_count 2 +event[0] create +event[1] postcreate +-------------------------------------------- +@@ Standard i/o tests (21 of 26) rmdir +@@ +rmdir $2/unlikely-named-test-dir +event_count 3 +event[0] remove +event[1] destroy +event[2] postremove +-------------------------------------------- +@@ Standard i/o tests (22 of 26) rename +@@ +mv $2/ls8 $2/LS8 +event_count 2 +event[0] rename +event[1] postrename +-------------------------------------------- +@@ Standard i/o tests (23 of 26) copy (new) +@@ +cp $2/ls9 $2/LS9 +event_count 9 +event[0] create +event[1] postcreate +event[2] attribute +event[3] read +event[4] read +event[5] read +event[6] read +event[7] read +event[8] attribute +-------------------------------------------- +@@ Standard i/o tests (24 of 26) copy (onto old) +@@ +cp $2/LS9 $2/ls9 +event_count 5 +event[0] truncate +event[1] write +event[2] write +event[3] write +event[4] write +-------------------------------------------- +@@ Standard i/o tests (25 of 26) memory-mapped i/o +@@ +// Note to self: don't check event_count +// +cc -o $2/ll0 $2/ctest.c +event[0] truncate +event[1] write +event[2] attribute +event[3] read +event[4] write +-------------------------------------------- +@@ Standard i/o tests (26 of 26) executing +@@ +$2/ll0 +event[0] read +event[1] read +event[2] read +event[3] read +event[4] read diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/standard_nfs.dat linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/standard_nfs.dat --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/data/standard_nfs.dat Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/data/standard_nfs.dat Tue Jan 16 19:24:14 2001 @@ -0,0 +1,247 @@ +// +// Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of version 2 of the GNU General Public License as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it would be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// Further, this software is distributed without any warranty that it is +// free of the rightful claim of any third person regarding infringement +// or the like. Any license provided herein, whether implied or +// otherwise, applies only to this software file. Patent licenses, if +// any, provided herein do not apply to combinations of this program with +// other software, or any other product whatsoever. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write the Free Software Foundation, Inc., 59 +// Temple Place - Suite 330, Boston MA 02111-1307, USA. +// +// Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +// Mountain View, CA 94043, or: +// +// http://www.sgi.com +// +// For further information regarding this notice, see: +// +// http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + +// This test will use the following files: +// +ctf stf ls_to_copy ctest.c +fcntl open_test truncate rd wf +read_invis write_invis +set_region set_return_on_destroy +-------------------------------------------- +// These setup commands are run before the daemon starts. +// They reset the file structure of the test directory +// to a known state. +// +rm $real_dir/??? +$1/ctf $1 $real_dir +$1/stf $1 $real_dir/l?? +rm $real_dir/ctest.c +cp $1/ctest.c $real_dir +chown $lname $real_dir/l?? +chown $lname $real_dir/ctest.c +$1/set_return_on_destroy $real_dir test +-------------------------------------------- +@@ Standard i/o tests (1 of 26): open +@@ +$1/open_test $2/ls0 o_rdwr +event_count 1 +event[0] read +-------------------------------------------- +@@ Standard i/o tests (2 of 26): open/trunc +@@ +$1/open_test $2/ls1 o_rdwr o_trunc +event_count 2 +event[0] truncate +event[1] attribute +-------------------------------------------- +@@ Standard i/o tests (3 of 26): open/trunc/create +@@ +$1/open_test $2/ls2 o_rdwr o_trunc o_creat +event_count 1 +event[0] truncate +-------------------------------------------- +@@ Standard i/o tests (4 of 26): open/create +@@ +$1/open_test $2/ls3 o_rdwr o_creat +event_count 1 +event[0] read +-------------------------------------------- +@@ Standard i/o tests (5 of 26): new file +@@ +$1/open_test $2/LS3 o_rdwr o_creat +event_count 2 +event[0] create +event[1] postcreate +-------------------------------------------- +@@ Standard i/o tests (6 of 26): append #1 +@@ +echo j >> $2/ls4 +event_count 2 +event[0] read +event[1] write +file_handle[0] store_in ls4temp +-------------------------------------------- +@@ Standard i/o tests (7 of 26): append #2 +@@ +echo j >> $2/ls4 +event_count 1 +event[0] write +file_handle[0] matches ls4temp +-------------------------------------------- +@@ Standard i/o tests (8 of 26): remove +@@ +/bin/rm $2/ls4 +event_count 3 +event[0] remove +event[1] destroy +event[2] postremove +name[1] test +contents[1] 123456789abcdefghijklmnopqrstuvwxyz +-------------------------------------------- +@@ Standard i/o tests (9 of 26): link +@@ +ln $2/ls5 $2/LS5 +event_count 2 +event[0] link +event[1] postlink +-------------------------------------------- +@@ Standard i/o tests (10 of 26): deleting link +@@ +/bin/rm $2/LS5 +event_count 2 +event[0] remove +event[1] postremove +-------------------------------------------- +@@ Standard i/o tests (11 of 26): return_on_destroy #1 +@@ +run_without_test +$1/set_return_on_destroy $real_dir +-------------------------------------------- +@@ Standard i/o tests (12 of 26): return_on_destroy #2 +@@ +/bin/rm $2/ls5 +event_count 3 +event[0] remove +event[1] destroy +event[2] postremove +name[1] +contents[1] +-------------------------------------------- +@@ Standard i/o tests (13 of 26) +@@ +$1/fcntl f_freesp -o 99999 -l 199999 $2/ls6 +event_count 2 +event[0] truncate +event[1] attribute +-------------------------------------------- +@@ Standard i/o tests (14 of 26) +@@ +$1/fcntl f_freesp -o 1000 -l 10000 $2/ls6 +event_count 2 +event[0] truncate +event[1] attribute +-------------------------------------------- +@@ Standard i/o tests (15 of 26) truncate #1 +@@ +$1/truncate $2/ls7 99999 +event_count 2 +event[0] truncate +event[1] attribute +-------------------------------------------- +@@ Standard i/o tests (16 of 26) truncate #2 +@@ +$1/truncate $2/ls7 1000 +event_count 2 +event[0] truncate +event[1] attribute +-------------------------------------------- +@@ Standard i/o tests (17 of 26) execute +@@ +$2/ls8 -l $real_dir +event_count 4 +event[0] read +event[1] read +event[2] read +event[3] read +-------------------------------------------- +@@ Standard i/o tests (18 of 26) symlink +@@ +ln -s $2/junk $2/symlink +event_count 2 +event[0] symlink +event[1] postsymlink +-------------------------------------------- +@@ Standard i/o tests (19 of 26) deleting symlink +@@ +/bin/rm $2/symlink +event_count 3 +event[0] remove +event[1] destroy +event[2] postremove +-------------------------------------------- +@@ Standard i/o tests (20 of 26) mkdir +@@ +mkdir $2/unlikely-named-test-dir +event_count 2 +event[0] create +event[1] postcreate +-------------------------------------------- +@@ Standard i/o tests (21 of 26) rmdir +@@ +rmdir $2/unlikely-named-test-dir +event_count 3 +event[0] remove +event[1] destroy +event[2] postremove +-------------------------------------------- +@@ Standard i/o tests (22 of 26) rename +@@ +mv $2/ls8 $2/LS8 +event_count 2 +event[0] rename +event[1] postrename +-------------------------------------------- +@@ Standard i/o tests (23 of 26) copy (new) +@@ +cp $2/ls9 $2/LS9 +event_count 8 +event[0] create +event[1] postcreate +event[2] attribute +event[3] read +event[4] read +event[5] read +event[6] read +event[7] attribute +-------------------------------------------- +@@ Standard i/o tests (24 of 26) copy (onto old) +@@ +cp $2/LS9 $2/ls9 +event_count 5 +event[0] truncate +event[1] write +event[2] write +event[3] write +event[4] write +-------------------------------------------- +@@ Standard i/o tests (25 of 26) memory-mapped i/o +@@ +// Note to self: don't check event_count +// +cc -o $2/ll0 $2/ctest.c +event[0] truncate +event[1] attribute +event[2] write +-------------------------------------------- +@@ Standard i/o tests (26 of 26) executing +@@ +$2/ll0 +event_count 0 diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/dist/CVS/Entries linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/dist/CVS/Entries --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/dist/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/dist/CVS/Entries Thu Jul 5 11:45:57 2001 @@ -0,0 +1,2 @@ +/README/1.1/Wed Jan 17 01:24:14 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/dist/CVS/Repository linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/dist/CVS/Repository --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/dist/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/dist/CVS/Repository Thu Jul 5 11:45:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/dist diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/dist/CVS/Root linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/dist/CVS/Root --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/dist/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/dist/CVS/Root Thu Jul 5 11:45:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/dist/README linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/dist/README --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/dist/README Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/dist/README Tue Jan 16 19:24:14 2001 @@ -0,0 +1,463 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + + DMAPI Test Suite + Informational File + ------------------ + +I) Getting Started + + A) Extracting from DMAPI_test.cpio + + 1) Create a new directory for storing the tests. We will refer to + this as the "base" directory. The base directory can be + located anywhere; it does NOT need to be in a DMAPI filesystem. + + 2) Move the archive file DMAPI_test.cpio to the base directory + and execute the following command to extract from the archive: + + cat DMAPI_test.cpio | cpio -icd + + 3) There should now be several files and subdirectories in the base + directory, including the file "file_list". Read this file for a + complete listing of which files should be present in which + directories. Compare "file_list" with the output of "ls -Rpl" + to be sure that you have the necessary files. + + 4) The base directory contains the files and programs that are of + immediate use for testing. The "bindir" subdirectory contains + the test programs and datafiles. The "lib" and "src" subdirectories + contain C libraries and source code for the C programs. + + B) Checking the Existence and Version of DMAPI + + The program check_dmapi can verify that you have the correct + version of DMAPI installed. Note: it can only be run as root. + Execute this command (from the "base" directory): + + bindir/check_dmapi + + It should report that you have a current version of DMAPI. If it + does not, it will also suggest which components of your DMAPI are + not current, and where to find a patch to update them. + + C) Configuration + + 1) Creating the Test Directories + + a) The Test Filesystem + + Mount a DMAPI filesystem, or use an existing one. + This filesystem's mount info MUST be listed in /etc/fstab. + + Write down the path to this filesystem's mountpoint, and label + it as "m_main" for future use. + + b) The Main Test Directory + + Create a new directory in the "m_main" filesystem. + + Write down the path to this directory. Note ONLY the part + that comes AFTER "m_main". Label this as "d_name". + + EXAMPLE: You have a DMAPI filesystem /dmi_main + You name the test directory /dmi_main/test_dir + "m_main" is /dmi_main + "d_name" is /test_dir + + c) The Cross-NFS Test Directories + + For NFS tests, all you must do is create two empty directories + (one for nfs2, one for nfs3). They do NOT need to be in a + DMAPI filesystem. + + Your main test directory will be mounted across NFS, into these + two directories. Normally, the tests will do this automatically. + However, if you need to do this mount manually, the command + would look like this example: + + mount -t nfs2 localhost:/dmi_main /dmi_nfs2 + + Write down the paths to these nfs2 and nfs3 test directories. + Label them "m_nfs2" and "m_nfs3" respectively. + + c) The Realtime Test Filesystem and Directory + + If you wish to test realtime i/o, you'll need a filesystem + mounted with a realtime partition, and a directory in that + filesystem. + + Label the path to the filesystem mountpoint as "m_rt". + Label the path to the test directory as "d_rt". + + 2) Configuring menu_test + + The Korn-shell script named menu_test is an interface to the + other test programs. At the beginning of the script, there + is a "configuration section", in which is sets several variables + for use in the rest of the script. + + Open menu_test in any text editor and change the following + variable assignments in the configuration section: + + a) base_dir: + Set this to the pathname of your "base" directory + (where you un-archived "DMAPI_test.cpio"). + + b) p_user: + Tests that do not run as root will run as this "primary" user. + Set this to any username. + + c) m_main: + The mountpoint of the main test filesystem. + Set this to the value of "m_main" that you wrote down above. + + d) d_name: + m_main concatenated with d_name is the main test directory path. + Set this to the value for "d_name" that you wrote down above. + + e) m_nfs2: + The mountpoint of the nfs2 test filesystem. + Set this to the value of "m_nfs2" that you wrote down above. + + f) m_nfs2: + The mountpoint of the nfs3 test filesystem. + Set this to the value of "m_nfs3" that you wrote down above. + + g) m_rt: + The mountpoint of the realtime test filesystem. + Set this to the value of "m_rt" that you wrote down above. + + h) d_rt: + The path to the realtime test directory. + Set this to the value of "d_rt" that you wrote down above. + + 3) Configuring "DMAPI_aliases" + + This is an optional alternative to the menu interface. It runs + as a Korn shell "dot" script and creates an alias to each test. + It was made for those who wish to run tests directly from the + command line. + + DMAPI_aliases has exactly the same configuration section as + menu_test. If you wish to use DMAPI_aliases, make the same + changes to its configuration section. + +II) Running the Tests + + A) Using "menu_test" to run tests + + 1) You must be superuser, using the Korn shell, to run menu_test. + You also must have adjusted the variables in menu_test's + "configuration section", as was explained above. + + 2) menu_test is (surprise!) menu based. Choose options by entering + their numbers. + + 3) The names of the menu options explain which DMAPI functions + or DMAPI events are being tested. Some of the options, labeled + accordingly, run more than one test programs. + + 4) See section SECTION# for a list of the test scripts and programs, + and a brief explanation of each script or program's function. + + B) Using "DMAPI_aliases" to run tests + + 1) NOTE: The aliases in DMAPI_aliases are meant to be used by + those who are familiar with the test programs and wish to run + them more directly. [Designer's note: I included the alias + file more out of nostalgia than necessity.] + + 2) You should be superuser, using the Korn shell, to run DMAPI_aliases. + You also must have adjusted the variables in DMAPI_aliases's + "configuration section", as was explained above. + + 3) DMAPI_aliases should be invoked as a Korn shell "dot" script: + + . ./DMAPI_aliases + + It sets an alias for each test program; each alias begins with + the characters "do_" and is followed by some appropriate name. + Read DMAPI_aliases, or execute "alias | grep do", to + + C) Running tests directly + + 1) For the VERY adventurous, all the tests in the "bindir" directory + can be run directly from the command line. Only some of the files + in "bindir" are test scripts/programs. Read section III for a list + of function tests and section IV for a list of run_test (.dat) + testfiles. + + 2) Running a test program without parameters will produce a list of + correct options. (The exception to this is check_dmapi, which + normally has no parameters. check_dmapi takes only one option, + [-v] for verbose output.) + + 3) It is suggested that you read a program's source before running + it directly. (The source of the C programs is included in the + "src" directory.) Specificually, in each source file, an initial + comment explains the program's options/parameters in detail. + +III) DMAPI Function tests: + + This section offers a terse description of the DMAPI function tests. + For those tests written in C, the source code is given in the "src" + directory. The ksh scripts can, of course, be read directly. + In all cases except check_dmapi, running the program without + parameters will produce a list of correct options. + + A) check_dmapi + Written in: C + Test of: presence (and correct version) of DMAPI library and kernel. + Options: [-v] flag for verbose output. + + B) test_dmattr + Written in: C + Test of: dm_get_dmattr, dm_set_dmattr, dm_remove_dmattr. + + C) test_efault + Written in: C + Test of: various bad function calls that should generate EFAULT, + according to the DMAPI specification. + + D) test_eventlist + Written in: C + Test of: dm_get_eventlist, dm_set_eventlist. + + E) test_fileattr + Written in: C + Test of: dm_get_fileattr, dm_set_fileattr, + dm_get_dirattrs, dm_get_bulkattr. + + F) test_hole + Written in: C + Test of: dm_probe_hole, dm_punch_hole. + + G) test_invis + Written in: C + Test of: dm_read_invis, dm_write_invis. + + H) test_region + Written in: C + Test of: dm_get_region, dm_set,region. + + I) test_rights + Written in: C + Test of: various bad function calls that should generate EACCES, + and other conditions pertaining to DMAPI rights. + + J) test_allocinfo_1 + Written in: ksh + Test of: dm_get_allocinfo. + + K) test_allocinfo_2 + Written in: ksh + Test of: dm_get_allocinfo. + +IV) DMAPI Event tests and the "run_test" ksh script + + A) How to use the "run_test" script + + 1) A quick description of run_test's behavior: + run_test invokes a DMAPI daemon (as a ksh coprocess). It then + reads a "testfile", which contains a description of the test. + + 2) You must be superuser, using the Korn shell, to execute run_test. + + 3) Executing run_test without parameters will produce a list of + correct options. For a much more in-depth explanation of the + options to run_test, read its own initial comment. + + B) The existing .dat testfiles + + 1) fail.dat + 2) main.dat + 3) nfs.dat + 4) old_nfs3.dat + 5) pending.dat + 6) pending_nfs.dat + 7) realtime.dat + 8) smallq.dat + 9) standard.dat + 10) standard_nfs.dat + + C) How to write ".dat" testfiles + + 1) Overview + + A testfile contains a complete description of a DMAPI event test. + Testfiles are divided into sections: the first two contain + test initialization, while the remaining sections each contain ONE + command, followed by a list of expected events. + + The following is a description of testfile syntax. If you wish to + fully understand testfile syntax, PLEASE examine the existing + testfiles and the "run_test" script. + + 2) Event information variables + + a) From the daemon, "run_test" gets information about DMAPI events. + This information is stored in event information variables. + + b) NOTE: event information variables are not persistant. + After "run_test" has compared the expected and actual events + for a command, and before it executes the next command, it + unsets the values of all these variables. + + c) Most of these variables are arrays, indexed by the number of + the event (starting with 0). For example, if the initial event + is a read event, then we have "event[0]" set to "read", and + "file_handle[0]" set to the handle of whatever file was read. + + d) "event_count" is a special variable. It holds the number of + events that were generated by the most recent command. + + e) These are all the event information variables: + + contents event event_count fs_handle handle length + offset media_designator mode mountpoint_handle + mountpoint_path msg_str name new_name new_parent + parent_handle ret_code root_handle sequence token + tries_left unmount_mode + + f) PLEASE examine the run_test script to see which variables + are set by which events. (The scheme corresponds, roughly, + to the "Event Types" section of the DMAPI specification.) + + 3) Testfile section 1: List of required files + + a) A testfile's first section is a list of the files it requires. + If these files are not present in the "bindir" directory, + "run_test" will abort the test and inform the user of which + files are missing. + + b) Each line of this section may contain ANY NUMBER of filenames. + + c) Lines beginning with // will be treated as comments. The + entirety of such lines will be ignored. + + d) The last line of this section should begin with three hyphens + --- Other characters on that line will be ignored. + + 4) Testfile section 2: Initialization commands + + a) A testfile's second section consists of a list of commands. + "run_test" will execute these commands before starting the + DMAPI daemon. Any necessary initialization should be done + here. + + b) Each line of this section should be ONE shell command. + + c) Lines beginning with // will be treated as comments. + The entirety of such lines will be ignored. + + d) The last line of this section should begin with three hyphens + "---" Other characters on that line will be ignored. + + 5) Testfile sections 3 and on: Individual tests + + a) The remaining sections of a testfile consist of a single + shell command, followed by descriptions of events that should + be generated by the command. + + b) Comments + + 1) Comments are valid ONLY before the command. + + 2) Lines beginning with // will be treated as comments. + The entirety of such lines will be ignored. + + 3) Lines beginning with @@ will be treated as "print" comments. + Such lines will not be parsed, but they will be printed to + standard output during the test. This is useful for + describing what each test does. + + c) Valid grammar for the command itself + + 1) Standard command syntax: + This should be ONE shell command, on a line by itself. + + 2) Alternate command syntax: + + A) run_as_root: + If the test is preceeded by the metacommand "run_as_root" + (on a line by itself) then the command will be run as + root rather than as "p_user". The command should still + be one command on a line by itself. + + B) run_without_test: + If the test is preceeded by the metacommand + "run_without_test" (on a line by itself), then ALL + subsequent lines in the section will be executed as + commands, and NO testing will be performed. Note that + the commands will be executed as root. This is useful + for re-initialization sections during a test. + + d) Valid grammar for the "expected events" lines + + 1) [variable_name] [value] + This specifies that the variable [variable_name] should be + set to [value]. + + 2) [variable_name_1] matches [variable_name_2] + This specifies that both variables should be set to + the same value. A list of valid variables + + 3) [variable_name] store_in [string] + This specifies that the contents of [variable_name] + should be stored in a variable named [string]. + The variable [string] can then be referenced as a + variable in later tests. + + EXAMPLE: if two commands deal with the file "foobar", + you might want to check that they both use the same handle. + In the first section, write + "handle[0] store_in old_handle_0" + In the second section, write + "old_handle_0 matches handle[0]" + + 4) failure + This specifies that the command is expected to fail + (return some non-zero exit status). If "failure" + is not specified, the command is expected to succeed. + + e) The last line of these sections should begin with three + hyphens "---". Other characters on that line will be ignored. + + 6) Sending messages to the DMAPI daemon + + + 7) Other "helper functions" for testfiles + + + + + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/lib/CVS/Entries linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/lib/CVS/Entries --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/lib/CVS/Entries Thu Jul 5 11:45:58 2001 @@ -0,0 +1,2 @@ +/errtest.h/1.1/Wed Jan 17 01:24:14 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/lib/CVS/Repository linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/lib/CVS/Repository --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/lib/CVS/Repository Thu Jul 5 11:45:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/lib diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/lib/CVS/Root linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/lib/CVS/Root --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/lib/CVS/Root Thu Jul 5 11:45:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/lib/errtest.h linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/lib/errtest.h --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/lib/errtest.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/lib/errtest.h Tue Jan 16 19:24:14 2001 @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __ERRTEST_SEEN +#define __ERRTEST_SEEN + +#include +#include +#include +#include + +#define NUM_ERRS 100 + +void* handle_clone(void* src_hanp, u_int hlen ); + +char * +errno_names[] = { + "ERROR_0", + "EPERM", + "ENOENT", + "ESRCH", + "EINTR", + "EIO", + "ENXIO", + "E2BIG", + "ENOEXEC", + "EBADF", + "ECHILD", + "EAGAIN", + "ENOMEM", + "EACCES", + "EFAULT", + "ENOTBLK", + "EBUSY", + "EEXIST", + "EXDEV", + "ENODEV", + "ENOTDIR", + "EISDIR", + "EINVAL", + "ENFILE", + "EMFILE", + "ENOTTY", + "ETXTBSY", + "EFBIG", + "ENOSPC", + "ESPIPE", + "EROFS", + "EMLINK", + "EPIPE", + "EDOM", + "ERANGE", + "ENOMSG", + "EIDRM", + "ECHRNG", + "EL2NSYNC", + "EL3HLT", + "EL3RST", + "ELNRNG", + "EUNATCH", + "ENOCSI", + "EL2HLT", + "EDEADLK", + "ENOLCK", + "ERROR_47", + "ERROR_48", + "ERROR_49", + "EBADE", + "EBADR", + "EXFULL", + "ENOANO", + "EBADRQC", + "EBADSLT", + "EDEADLOCK", + "EBFONT", + "ERROR_58", + "ERROR_59", + "ENOSTR", + "ENODATA", + "ETIME", + "ENOSR", + "ENONET", + "ENOPKG", + "EREMOTE", + "ENOLINK", + "EADV", + "ESRMNT", + "ECOMM", + "EPROTO", + "ERROR_72", + "ERROR_73", + "EMULTIHOP", + "ERROR_75", + "ERROR_76", + "EBADMSG", + "ENAMETOOLONG", + "EOVERFLOW", + "ENOTUNIQ", + "EBADFD", + "EREMCHG", + "ELIBACC", + "ELIBBAD", + "ELIBSCN", + "ELIBMAX", + "ELIBEXEC", + "EILSEQ", + "ENOSYS", + "ELOOP", + "ERESTART", + "ESTRPIPE", + "ENOTEMPTY", + "EUSERS", + "ENOTSOCK", + "EDESTADDRREQ", + "EMSGSIZE", + "EPROTOTYPE", + "ENOPROTOOPT" }; + +#define ERR_NAME \ + ((errno +#include +#ifdef linux +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef linux +#include +#endif + +/*--------------------------------------------------------------------------- +Automated test of version of DMAPI libraries & kernels + +The command line is: + + check_dmapi [-v] + +where v is a verbose-output flag +----------------------------------------------------------------------------*/ +#ifdef linux +#define CREATE_DESTROY_OPCODE DM_DESTROY_SESSION +#define SET_DISP_OPCODE DM_SET_DISP +#else +#define CREATE_DESTROY_OPCODE 5 +#define SET_DISP_OPCODE 46 +#endif + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + +char *Progname; + +int dmi(int, ...); + +static void +usage(void) +{ + int i; + + fprintf(stderr, "usage:\t%s [-v]\n" + "\t(use the v switch for verbose output)\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t old_sid = -1; + dm_sessid_t sid; + void *hanp; + size_t hlen; + dm_token_t token = DM_NO_TOKEN; + int Vflag = 0; + char *name = "old"; + char *junk = "test junk"; + int opt; + int i; + int kernel_status=-1; + int library_status=-1L; + dm_size_t retval; + struct stat stat_buf; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "v")) != EOF) { + switch (opt) { + case 'v': + Vflag++; + break; + case '?': + usage(); + } + } + if (optind != argc) + usage(); + + + if (geteuid()!=0) { + printf("You are running as user #%d. " + "You must be root to run this diagnostic.\n", geteuid()); + exit(1); + } + + /*-------------------------------- + * EXAMINE /usr/include/sys/dmi.h: + *-------------------------------- + */ +#ifdef __sgi +#define DMAPI_HDR "/usr/include/sys/dmi.h" + + if (stat(DMAPI_HDR, &stat_buf)==-1){ + if (errno==ENOENT) { + printf( "You are missing a vital DMAPI file: %s\n", DMAPI_HDR); + } + else { + printf( "ERROR: could not stat %s (%s)\n", DMAPI_HDR, strerror(errno)); + } + } + else { + if (stat_buf.st_size <= 15000) { + printf("You appear to have an old version of a vital DMAPI file: %s\n", DMAPI_HDR); + } + else if (Vflag) { + printf("(You appear to have the correct version of %s\n", DMAPI_HDR); + } + } +#endif + + /*-------------------------- + * RESOLVE KERNEL PRESENCE: + *-------------------------- + */ + if (dmi(CREATE_DESTROY_OPCODE, old_sid, junk, &sid) >= 0) { + printf("ERROR: invalid kernel create/destroy_session call " + "succeeded!\n"); + exit(1); + } + else if (errno==ENOPKG) { + kernel_status=0; + } + else if (errno==EINVAL){ + if (Vflag) printf("(create/destroy_session call verifies " + "that you have DMAPI in kernel)\n"); + } + else { + printf("ERROR: kernel create/destroy_session call produced " + "unexpected errno, (%d) %s\n", errno, strerror(errno)); + } + + /*---------------------------------- + * RESOLVE KERNEL STATUS IF PRESENT: + *---------------------------------- + */ + if (kernel_status==-1 && + dmi(SET_DISP_OPCODE, + (dm_sessid_t) 0, + (void*) 0, + (size_t) 0, + (dm_token_t) 0, + (dm_eventset_t) 0, + (u_int) 0) >= 0) { + printf("ERROR: invalid kernel set_disp call suceeded!\n"); + } + else { + if (errno==ENOSYS) { + if (Vflag) + printf("(kernel set_disp call indicates old kernel)\n"); + kernel_status=1; + } + else if (errno==ENOPKG) { + if (Vflag) + printf("(kernel set_disp call indicates no kernel)\n"); + kernel_status=0; + } + else if (errno==EINVAL) { + if (Vflag) + printf("(kernel set_disp call indicates new kernel)\n"); + kernel_status=2; + } + else { + printf("ERROR: kernel set_disp call failed: (%d) %s\n", + errno, strerror(errno)); + exit(1); + } + } + + /*------------------------- + * RESOLVE LIBRARY STATUS: + *------------------------- + */ + if (dm_init_service(&name) == -1) { + fprintf(stderr, "ERROR: can't inititalize the DMAPI (%s).\n", + strerror(errno)); + library_status=0; + } + else if (strcmp(name, DM_VER_STR_CONTENTS)) { + if (Vflag) + printf("(dm_init_service suggests that " + "you have an old library)\n"); + library_status=1; + } + else { + if (Vflag) + printf("(dm_init_service suggests that " + "you have a new library)\n"); + library_status=2; + } + + if (Vflag) printf("(dm_init_service returned %s)\n", name); + + /*------------------------- + * MAKE A DIAGNOSIS: + *------------------------- + */ + + if (library_status==2 && kernel_status==2){ + printf("DIAGNOSIS: Tests show a current version of " + "DMAPI is installed.\n"); + } + else if (library_status==1 && kernel_status==1) { + printf("DIAGNOSIS: Tests show that you have an outdated " + "installation of DMAPI.\nUpgrades to both kernel and " + "library routines will be necessary.\n"); + } + else if (library_status==0 && kernel_status==0) { + printf("DIAGNOSIS: Tests show that NO components of the DMAPI " + "are installed!\nUpgrades to both kernel and " + "library routines will be necessary.\n"); + } + else { + printf("DIAGNOSIS: Tests show that:\n" + "Your DMAPI kernel routines are "); + switch (kernel_status) { + case 0: printf ("missing (not installed).\n"); + break; + case 1: printf ("outdated.\n"); + break; + case 2: printf ("current.\n "); + break; + default: printf("[ERROR!].\n"); + } + printf("Your DMAPI library is "); + switch (library_status) { + case 0: printf ("missing (not installed).\n"); + break; + case 1: printf ("outdated.\n"); + break; + case 2: printf ("current.\n"); + break; + default: printf("[ERROR!].\n"); + } + } +#ifndef linux + if (library_status!=2 || kernel_status!=2){ + printf("Please install XFS patch 1907 (for IRIX 6.2) or " + "patch 2287 (for IRIX 6.4).\n"); + } +#endif +} + + + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/dm_test_daemon.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/dm_test_daemon.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/dm_test_daemon.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/dm_test_daemon.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,1326 @@ + + +/* + * dm_test_daemon.c + * + * Joseph Jackson + * 25-Jun-1996 + * + * Additions: + * Jay Woodward + * 6-Aug-1997 + * + * Monitor all events for a file system. + * When one arrives, print a message with all the details. + * If the message is synchronous, always reply with DM_RESP_CONTINUE + * (This program doesn't perform any real file system or HSM work.) + * + * This is a simplification of the "migin.c" example program. + * The original code was by Peter Lawthers: + * This code was written by Peter Lawthers, and placed in the public + * domain for use by DMAPI implementors and app writers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef linux +#define MAXNAMELEN 256 +#endif + + /* + * Define some standard formats for the printf statements below. + */ + +#define HDR "%s\ntoken :%d\nsequence :%d\n" +#define VALS "%-15s:%s\n" +#define VALD "%-15s:%d\n" +#define VALLLD "%-15s:%lld\n" + +extern int optind; +extern int errno; + +void usage (char *); +int main (int, char **); +static void event_loop (dm_sessid_t, int); +int handle_message (dm_sessid_t, dm_eventmsg_t *); +static int format_mode(mode_t mode, char **ptr); +static int get_fs_handle (char *, void **, size_t *); +static int set_disposition(dm_sessid_t, void *, size_t); +static int set_events (dm_sessid_t, void *, size_t); +static int clear_events (dm_sessid_t, void *, size_t); +int finish_responding(dm_sessid_t); +int establish_handler(void); +void exit_handler (int); + +/* + * Keep these global so the exit_handler and err_msg routines can get to them + */ +char *Progname; +int Sleep = 0; +int Verbose; +dm_sessid_t sid = 0; +dm_sessid_t oldsid = 0; +char *fsname; +int friendly=1; +int unfriendly_errno=EBADMSG; +int unfriendly_count=0; +int pending_count=0; +int token_arr[10]; +int arr_top=0; + +void +usage( + char *prog) +{ + fprintf(stderr, "Usage: %s ", prog); + fprintf(stderr, "<-s sleeptime> <-S oldsid> <-v verbose> "); + fprintf(stderr, "filesystem \n"); +} + + +int +main( + int argc, + char *argv[]) +{ + + int c; + int error; + void *fs_hanp; + size_t fs_hlen; + char buf[BUFSIZ + 8]; + + Progname = argv[0]; + fsname = NULL; + + while ((c = getopt(argc, argv, "vs:S:")) != EOF) { + switch (c) { + case 's': + Sleep = atoi(optarg); + break; + case 'S': + oldsid = atoi(optarg); + break; + case 'v': + Verbose = 1; + break; + case '?': + default: + usage(Progname); + exit(1); + } + } + if (optind >= argc) { + usage(Progname); + exit(1); + } + fsname = argv[optind]; + if (fsname == NULL) { + usage(Progname); + exit(1); + } + + /* + * Establish an exit handler + */ + error = establish_handler(); + if (error) + exit(1); + + /* + * Init the dmapi, and get a filesystem handle so + * we can set up our events + */ + + if (oldsid) { + sid = oldsid; + } else { + error = setup_dmapi(&sid); + if (error) + exit(1); + } + + error = get_fs_handle(fsname, &fs_hanp, &fs_hlen); + if (error) + goto cleanup; + + /* + * Set the event disposition so that our session will receive + * all the events for the given file system + */ + error = set_disposition(sid, fs_hanp, fs_hlen); + if (error) + goto cleanup; + + /* + * Enable monitoring for all events in the given file system + */ + error = set_events(sid, fs_hanp, fs_hlen); + if (error) + goto cleanup; + + /* + * Set line buffering!! + */ + error = setvbuf(stdout, buf, _IOLBF, BUFSIZ); + if (error) + goto cleanup; + + /* + * Now sit in an infinite loop, reporting on any events that occur. + * The program is exited after a signal through exit_handler(). + */ + printf("\n"); + event_loop(sid, 1 /*waitflag*/); + + /* + * If we get here, cleanup after the event_loop failure + */ + cleanup: + exit_handler(0); + return(1); +} + + +/* + * Main event loop processing + * + * The waitflag argument is set to 1 when we call this from main(). + * In this case, continuously process incoming events, + * blocking if there are none available. + * In the exit_handler(), call this routine with waitflag=0. + * Just try to read the events once in this case with no blocking. + */ + +static void +event_loop( + dm_sessid_t sid, + int waitflag) +{ + void *msgbuf; + size_t bufsize; + int error; + dm_eventmsg_t *msg; + int count; + + /* + * We take a swag at a buffer size. If it's wrong, we can + * always resize it + */ + + bufsize = sizeof(dm_eventmsg_t) + sizeof(dm_data_event_t) + HANDLE_LEN; + bufsize *= 50; + msgbuf = (void *)malloc(bufsize); + if (msgbuf == NULL) { + err_msg("Can't allocate memory for buffer"); + return; + } + + for (;;) { + error = dm_get_events(sid, ALL_AVAIL_MSGS, + waitflag ? DM_EV_WAIT:0, bufsize, msgbuf, &bufsize); + if (error) { + if (errno == EAGAIN) { + if (waitflag) + continue; + break; + } + if (errno == E2BIG) { + free(msgbuf); + msgbuf = (void *)malloc(bufsize); + if (msgbuf == NULL) { + err_msg("Can't resize msg buffer"); + return; + } + continue; + } + errno_msg("Error getting events from DMAPI"); + break; + } + + /* + * Walk through the message buffer, pull out each individual + * message, and dispatch the messages to handle_message(), + * which will respond to the events. + */ + + count = 0; + msg = (dm_eventmsg_t *)msgbuf; + while (msg != NULL ) { + count++; + error = handle_message(sid, msg); + if (error) { + free(msgbuf); + return; + } + printf("end_of_message\n"); + msg = DM_STEP_TO_NEXT(msg, dm_eventmsg_t *); + } + if (count != 1 && Verbose) { + err_msg("Found %d events in one call to " + "dm_get_events\n", count); + } + } + if (msgbuf != NULL) + free(msgbuf); +} + + +void +print_one_mount_event( + void *msg) +{ + void *hanp1, *hanp2, *hanp3; + size_t hlen1, hlen2, hlen3; + char hans1[HANDLE_STR], hans2[HANDLE_STR], hans3[HANDLE_STR]; + void *namp1, *namp2; + size_t nlen1, nlen2; + char nams1[MAXNAMELEN], nams2[MAXNAMELEN]; + mode_t mode; + +#if VERITAS + dm_namesp_event_t *msg_ne = (dm_namesp_event_t *)msg; + + msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *); + hanp1 = DM_GET_VALUE(msg_ne, ne_handle1, void *); + hlen1 = DM_GET_LEN (msg_ne, ne_handle1); + hanp2 = DM_GET_VALUE(msg_ne, ne_handle2, void *); + hlen2 = DM_GET_LEN (msg_ne, ne_handle2); + namp1 = DM_GET_VALUE(msg_ne, ne_name1, void *); + nlen1 = DM_GET_LEN (msg_ne, ne_name1); + namp2 = DM_GET_VALUE(msg_ne, ne_name2, void *); + nlen2 = DM_GET_LEN (msg_ne, ne_name2); + rootp = NULL; + rlen = 0; + mode = msg_ne->ne_mode; +#else + dm_mount_event_t *msg_me = (dm_mount_event_t *)msg; + + hanp1 = DM_GET_VALUE(msg_me, me_handle1, void *); + hlen1 = DM_GET_LEN(msg_me, me_handle1); + hanp2 = DM_GET_VALUE(msg_me, me_handle2, void *); + hlen2 = DM_GET_LEN(msg_me, me_handle2); + namp1 = DM_GET_VALUE(msg_me, me_name1, void *); + nlen1 = DM_GET_LEN(msg_me, me_name1); + namp2 = DM_GET_VALUE(msg_me, me_name2, void *); + nlen2 = DM_GET_LEN(msg_me, me_name2); + hanp3 = DM_GET_VALUE(msg_me, me_roothandle, void *); + hlen3 = DM_GET_LEN(msg_me, me_roothandle); + mode = msg_me->me_mode; +#endif /* VERITAS */ + + if (hanp1 && hlen1) { + hantoa(hanp1, hlen1, hans1); + } else { + sprintf(hans1, "", hlen1); + } + if (hanp2 && hlen2) { + hantoa(hanp2, hlen2, hans2); + } else { + sprintf(hans2, "", hlen2); + } + if (hanp3 && hlen3) { + hantoa(hanp3, hlen3, hans3); + } else { + sprintf(hans3, "", hlen3); + } + if (namp1 && nlen1) { + strncpy(nams1, namp1, nlen1); + if (nlen1 != sizeof(nams1)) + nams1[nlen1] = '\0'; + } else { + sprintf(nams1, "", nlen1); + } + if (namp2 && nlen2) { + strncpy(nams2, namp2, nlen2); + if (nlen2 != sizeof(nams2)) + nams2[nlen2] = '\0'; + } else { + sprintf(nams2, "", nlen2); + } + + printf(VALS VALS VALS VALS VALS VALD, + "fs handle", hans1, + "mtpt handle", hans2, + "mtpt path", nams1, + "media desig", nams2, + "root handle", hans3, + "mode", mode); +} + + +/* + * First, weed out the events which return interesting structures. + * If it's not one of those, unpack the dm_namesp_event structure + * and display the contents. + */ +int +handle_message( + dm_sessid_t sid, + dm_eventmsg_t *msg) +{ + int pkt_error = 0; + int error; + dm_response_t response; + int respond, respcode; + dm_namesp_event_t *msg_ne; +#if !VERITAS + dm_mount_event_t *msg_me; +#endif + void *hanp1, *hanp2, *namp1, *namp2; + u_int hlen1, hlen2, nlen1, nlen2; + char hans1[HANDLE_STR], hans2[HANDLE_STR]; + char nams1[MAXNAMELEN], nams2[MAXNAMELEN]; + void *fs_hanp; + size_t fs_hlen; + dm_timestruct_t *pending_time; + + /* + * Set the defaults for responding to events + */ + + /***************************************************** + * If the daemon is feeling unfriendly, it will + * respond (when necessary) with DM_RESP_ABORT, rather + * than the standard DM_RESP_CONTINUE. + * + * While unfriendly, the daemon normally returns + * a respcode of "unfriendly_errno". This defaults to + * EBADMSG but can be set when unfriendly mode is + * activated. + *****************************************************/ + + respond = 1; + if (unfriendly_count==0) { + response = friendly ? DM_RESP_CONTINUE : DM_RESP_ABORT; + respcode = friendly ? 0 : unfriendly_errno; + } + else if (unfriendly_count > 0) { + if (unfriendly_count-- == 0) { + response = DM_RESP_CONTINUE; + respcode = 0; + } + else { + response = DM_RESP_ABORT; + respcode = unfriendly_errno; + } + } + + if (pending_count >= 0) { + if (msg->ev_type != DM_EVENT_USER) { + if (pending_count-- == 0) { + int i; + for (i=arr_top; i>=0; --i) { + dm_respond_event(sid, token_arr[i], + DM_RESP_CONTINUE, 0, 0, 0); + } + response = DM_RESP_CONTINUE; + respcode = 0; + } + else { + if (pending_count<10) { + token_arr[pending_count]=msg->ev_token; + } + pending_time = malloc(sizeof(dm_timestruct_t)); + pending_time->dm_tv_sec=0; + pending_time->dm_tv_nsec=0; + dm_pending(sid, msg->ev_token, pending_time); + printf("pending\ntries left\t:%d\n",pending_count); + return 0; + } + } + } + + /***** USER EVENTS *****/ + + if (msg->ev_type == DM_EVENT_USER) { + char *privp; + u_int plen, i; + + printf(HDR, + "user", msg->ev_token, msg->ev_sequence); + + /* print private data as ascii or hex if it exists + DM_CONFIG_MAX_MESSAGE_DATA */ + + privp = DM_GET_VALUE(msg, ev_data, char *); + plen = DM_GET_LEN (msg, ev_data); + if (plen) { + for (i = 0; i < plen; i++) { + if (!isprint(privp[i]) && !isspace(privp[i])) + break; + } + if (i == plen - 1 && privp[i] == '\0') { + /***************************************************** + * Here, we check the messages from send_message. + * Some of them have special meanings. + *****************************************************/ + if (strncmp(privp, "over", 4)==0) { + response = DM_RESP_CONTINUE; + respcode = 0; + } + else if (strncmp(privp, "pending", 7)==0){ + if (strlen(privp)>8) { + sscanf(privp, "pending%*c%d", &pending_count); + } + else { + pending_count=1; + } + arr_top=pending_count-1; + } + else if (strncmp(privp, "reset_fs", 8)==0){ + if (get_fs_handle(fsname, &fs_hanp, &fs_hlen)){ + strcpy(privp, "error"); + } + else if (set_disposition(sid, fs_hanp, fs_hlen)){ + strcpy(privp, "error"); + } + else if (set_events(sid, fs_hanp, fs_hlen)){ + strcpy(privp, "error"); + } + } + else if (strncmp(privp, "friendly", 8)==0) { + friendly = 1; + response = DM_RESP_CONTINUE; + respcode = 0; + } + else if (strncmp(privp, "unfriendly", 10)==0) { + friendly = 0; + response = DM_RESP_CONTINUE; + respcode = 0; + if (strlen(privp)>11) { + sscanf(privp, "unfriendly%*c%d", &unfriendly_errno); + } + else { + unfriendly_errno=EBADMSG; + } + } + else if (strncmp(privp, "countdown", 9)==0) { + response = DM_RESP_CONTINUE; + respcode = 0; + + if (strlen(privp)>10) { + sscanf(privp, "countdown%*c%d%*c%d", + &unfriendly_count, &unfriendly_errno); + } + else { + unfriendly_count=5; + unfriendly_errno=EAGAIN; + } + } + + + printf(VALS, + "privdata", privp); + + } else { + printf("privdata :"); + for (i = 0; i < plen; i++) { + printf("%.2x", privp[i]); + } + printf("\n"); + } + } else { + printf(VALS, + "privdata", ""); + } + + if (msg->ev_token == DM_INVALID_TOKEN) /* async dm_send_msg event */ + respond = 0; + } + + /***** CANCEL EVENT *****/ + +/* Not implemented on SGI or Veritas */ + + else if (msg->ev_type == DM_EVENT_CANCEL) { + dm_cancel_event_t *msg_ce; + + msg_ce = DM_GET_VALUE(msg, ev_data, dm_cancel_event_t *); + printf(HDR VALD VALD, + "cancel", msg->ev_token, msg->ev_sequence, + "sequence", msg_ce->ce_sequence, + "token", msg_ce->ce_token); + respond = 0; + } + + /***** DATA EVENTS *****/ + + else if (msg->ev_type == DM_EVENT_READ || + msg->ev_type == DM_EVENT_WRITE || + msg->ev_type == DM_EVENT_TRUNCATE) { + dm_data_event_t *msg_de; + + msg_de = DM_GET_VALUE(msg, ev_data, dm_data_event_t *); + hanp1 = DM_GET_VALUE(msg_de, de_handle, void *); + hlen1 = DM_GET_LEN (msg_de, de_handle); + if (hanp1 && hlen1) { + hantoa(hanp1, hlen1, hans1); + } else { + sprintf(hans1, "", hlen1); + } + + switch(msg->ev_type) { + + case DM_EVENT_READ: + printf(HDR VALS VALLLD VALLLD, + "read", msg->ev_token, msg->ev_sequence, + "file handle", hans1, + "offset", msg_de->de_offset, + "length", msg_de->de_length); + break; + + case DM_EVENT_WRITE: + printf(HDR VALS VALLLD VALLLD, + "write", msg->ev_token, msg->ev_sequence, + "file handle", hans1, + "offset", msg_de->de_offset, + "length", msg_de->de_length); + break; + + case DM_EVENT_TRUNCATE: + printf(HDR VALS VALLLD VALLLD, + "truncate", msg->ev_token, msg->ev_sequence, + "file handle", hans1, + "offset", msg_de->de_offset, + "length", msg_de->de_length); + break; + default: break; + } + } + + /***** DESTROY EVENT *****/ + + else if (msg->ev_type == DM_EVENT_DESTROY) { + dm_destroy_event_t *msg_ds; + char attrname[DM_ATTR_NAME_SIZE + 1]; + u_char *copy; + u_int clen; + u_int i; + + msg_ds= DM_GET_VALUE(msg, ev_data, dm_destroy_event_t *); + hanp1 = DM_GET_VALUE(msg_ds, ds_handle, void *); + hlen1 = DM_GET_LEN (msg_ds, ds_handle); + if (hanp1 && hlen1) { + hantoa(hanp1, hlen1, hans1); + } else { + sprintf(hans1, "", hlen1); + } + if (msg_ds->ds_attrname.an_chars[0] != '\0') { + strncpy(attrname, (char *)msg_ds->ds_attrname.an_chars, sizeof(attrname)); + } else { + strcpy(attrname, ""); + } + printf(HDR VALS VALS, + "destroy", msg->ev_token, msg->ev_sequence, + "handle", hans1, + "attrname", attrname); + copy = DM_GET_VALUE(msg_ds, ds_attrcopy, u_char *); + clen = DM_GET_LEN (msg_ds, ds_attrcopy); + if (copy && clen) { + printf("attrcopy :"); + for (i = 0; i < clen; i++) { + /* Old version: printf("%.2x", copy[i]); */ + printf("%c", copy[i]); + } + printf("\n"); + } else { + printf(VALS, "attrcopy", ""); + } + respond = 0; + } + + /***** MOUNT EVENT *****/ + + else if (msg->ev_type == DM_EVENT_MOUNT) { + printf(HDR, "mount", msg->ev_token, msg->ev_sequence); +#if !VERITAS + msg_me = DM_GET_VALUE(msg, ev_data, dm_mount_event_t *); + print_one_mount_event(msg_me); +#else /* VERITAS */ + msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *); + print_one_mount_event(msg_ne); +#endif /* VERITAS */ + } + + /***** NAMESPACE EVENTS *****/ + + else { + char *type; + + msg_ne = DM_GET_VALUE(msg, ev_data, dm_namesp_event_t *); + hanp1 = DM_GET_VALUE(msg_ne, ne_handle1, void *); + hlen1 = DM_GET_LEN (msg_ne, ne_handle1); + hanp2 = DM_GET_VALUE(msg_ne, ne_handle2, void *); + hlen2 = DM_GET_LEN (msg_ne, ne_handle2); + namp1 = DM_GET_VALUE(msg_ne, ne_name1, void *); + nlen1 = DM_GET_LEN (msg_ne, ne_name1); + namp2 = DM_GET_VALUE(msg_ne, ne_name2, void *); + nlen2 = DM_GET_LEN (msg_ne, ne_name2); + + if (hanp1 && hlen1) { + hantoa(hanp1, hlen1, hans1); + } + if (hanp2 && hlen2) { + hantoa(hanp2, hlen2, hans2); + } + if (namp1 && nlen1) { + strncpy(nams1, namp1, nlen1); + if (nlen1 != sizeof(nams1)) + nams1[nlen1] = '\0'; + } + if (namp2 && nlen2) { + strncpy(nams2, namp2, nlen2); + if (nlen2 != sizeof(nams2)) + nams2[nlen2] = '\0'; + } + + if (msg->ev_type == DM_EVENT_PREUNMOUNT || + msg->ev_type == DM_EVENT_UNMOUNT) { + if (msg_ne->ne_mode == 0) { + type = "NOFORCE"; +#if !VERITAS + } else if (msg_ne->ne_mode == DM_UNMOUNT_FORCE) { +#else + } else if (msg_ne->ne_mode > 0) { +#endif + type = "FORCE"; + } else { + type = "UNKNOWN"; + pkt_error++; + } + } else if (msg->ev_type == DM_EVENT_CREATE || + msg->ev_type == DM_EVENT_POSTCREATE || + msg->ev_type == DM_EVENT_REMOVE || + msg->ev_type == DM_EVENT_POSTREMOVE) { + if (format_mode(msg_ne->ne_mode, &type)) { + pkt_error++; + } + } + + switch(msg->ev_type) { + + case DM_EVENT_PREUNMOUNT: + printf(HDR VALS VALS VALS, + "preunmount", msg->ev_token, msg->ev_sequence, + "fs handle", hans1, + "root dir", hans2, + "unmount mode", type); + break; + + case DM_EVENT_UNMOUNT: + printf(HDR VALS VALS VALD, + "unmount", msg->ev_token, msg->ev_sequence, + "fs handle", hans1, + "unmount mode", type, + "retcode", msg_ne->ne_retcode); + break; + + case DM_EVENT_NOSPACE: + printf(HDR VALS, + "nospace", msg->ev_token, msg->ev_sequence, + "fs handle", hans1); + response = DM_RESP_ABORT; + respcode = ENOSPC; + break; + + case DM_EVENT_DEBUT: /* not supported on SGI */ + printf(HDR VALS, + "debut", msg->ev_token, msg->ev_sequence, + "object", hans1); + break; + + case DM_EVENT_CREATE: + printf(HDR VALS VALS VALS, + "create", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "mode bits", type); + break; + + case DM_EVENT_POSTCREATE: + printf(HDR VALS VALS VALS VALS VALD, + "postcreate", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "new object", hans2, + "name", nams1, + "mode bits", type, + "retcode", msg_ne->ne_retcode); + respond = 0; + break; + + case DM_EVENT_REMOVE: + printf(HDR VALS VALS VALS, + "remove", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "mode bits", type); + break; + + case DM_EVENT_POSTREMOVE: + printf(HDR VALS VALS VALS VALD, + "postremove", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "mode bits", type, + "retcode", msg_ne->ne_retcode); + respond = 0; + break; + + case DM_EVENT_RENAME: + printf(HDR VALS VALS VALS VALS, + "rename", msg->ev_token, msg->ev_sequence, + "old parent", hans1, + "new parent", hans2, + "old name", nams1, + "new name", nams2); + break; + + case DM_EVENT_POSTRENAME: + printf(HDR VALS VALS VALS VALS VALD, + "postrename", msg->ev_token, msg->ev_sequence, + "old parent", hans1, + "new parent", hans2, + "old name", nams1, + "new name", nams2, + "retcode", msg_ne->ne_retcode); + respond = 0; + break; + + case DM_EVENT_SYMLINK: + printf(HDR VALS VALS VALS, + "symlink", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "name", nams1, + "contents", nams2); + break; + + case DM_EVENT_POSTSYMLINK: + printf(HDR VALS VALS VALS VALS VALD, + "postsymlink", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "new object", hans2, + "name", nams1, + "contents", nams2, + "retcode", msg_ne->ne_retcode); + respond = 0; + break; + + case DM_EVENT_LINK: + printf(HDR VALS VALS VALS, + "link", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "source", hans2, + "name", nams1); + break; + + case DM_EVENT_POSTLINK: + printf(HDR VALS VALS VALS VALD, + "postlink", msg->ev_token, msg->ev_sequence, + "parent dir", hans1, + "source", hans2, + "name", nams1, + "retcode", msg_ne->ne_retcode); + respond = 0; + break; + + case DM_EVENT_ATTRIBUTE: + printf(HDR VALS, + "attribute", msg->ev_token, msg->ev_sequence, + "object", hans1); + respond = 0; + break; + + case DM_EVENT_CLOSE: /* not supported on SGI */ + printf(HDR VALS, + "close", msg->ev_token, msg->ev_sequence, + "object", hans1); + respond = 0; + break; + + default: + pkt_error++; + printf(HDR VALD, + "", msg->ev_token, msg->ev_sequence, + "ev_type", msg->ev_type); + if (msg->ev_token == DM_INVALID_TOKEN) + respond = 0; + break; + } + } + + /* + * Now respond to those messages which require a response + */ + if (respond) { + if (Sleep) sleep(Sleep); /* Slow things down here */ + + error = dm_respond_event(sid, msg->ev_token, response, respcode, 0, 0); + if (error) { + errno_msg("Can't respond to event"); + return error; + } + } + + return 0; +} + + +/* + Convert a mode_t field into a printable string. + + Returns non-zero if the mode_t is invalid. The string is + returned in *ptr, whether there is an error or not. +*/ + +static int +format_mode( + mode_t mode, + char **ptr) +{ +static char modestr[100]; + char *typestr; + int error = 0; + + if (S_ISFIFO(mode)) typestr = "FIFO"; + else if(S_ISCHR (mode)) typestr = "Character Device"; + else if(S_ISBLK (mode)) typestr = "Block Device"; + else if(S_ISDIR (mode)) typestr = "Directory"; + else if(S_ISREG (mode)) typestr = "Regular File"; + else if(S_ISLNK (mode)) typestr = "Symbolic Link"; + else if(S_ISSOCK(mode)) typestr = "Socket"; + else { + typestr = ""; + error++; + } + + sprintf(modestr, "mode %06o (perm %c%c%c %c%c%c %c%c%c %c%c%c) " + "type %s", + mode, + mode & S_ISUID ? 's':' ', + mode & S_ISGID ? 'g':' ', + mode & S_ISVTX ? 't':' ', + mode & S_IRUSR ? 'r':'-', + mode & S_IWUSR ? 'w':'-', + mode & S_IXUSR ? 'x':'-', + mode & S_IRGRP ? 'r':'-', + mode & S_IWGRP ? 'w':'-', + mode & S_IXGRP ? 'x':'-', + mode & S_IROTH ? 'r':'-', + mode & S_IWOTH ? 'w':'-', + mode & S_IXOTH ? 'x':'-', + typestr); + *ptr = modestr; + return(error); +} + + +static int +get_fs_handle( + char *fsname, + void **fs_hanpp, + size_t *fs_hlenp) +{ + char hans[HANDLE_STR]; + + if (dm_path_to_fshandle(fsname, fs_hanpp, fs_hlenp) == -1) { + errno_msg("Can't get filesystem handle"); + return 1; + } + if (Verbose) { + hantoa(*fs_hanpp, *fs_hlenp, hans); + err_msg("File system handle for %s: %s\n", fsname, hans); + } + return 0; +} + + +/* + Set the event disposition for this filesystem to include all valid + DMAPI events so that we receive all events for this filesystem. + Also set DM_EVENT_MOUNT disposition for the global handle. + It does not make sense to specify DM_EVENT_USER in the disposition + mask since a session is always unconditionally registered for these + events. + + Returns non-zero on error. +*/ + +static int +set_disposition( + dm_sessid_t sid, + void *fs_hanp, + size_t fs_hlen) +{ + dm_eventset_t eventlist; + + if (Verbose) { + err_msg("Setting event disposition to send all " + "events to this session\n"); + } + + /* DM_EVENT_MOUNT must be sent in a separate request using the global + handle. If we ever support more than one filesystem at a time, this + request should be moved out of this routine to a place where it is + issued just once. + */ + + DMEV_ZERO(eventlist); + DMEV_SET(DM_EVENT_MOUNT, eventlist); + + if (dm_set_disp(sid, DM_GLOBAL_HANP, DM_GLOBAL_HLEN, DM_NO_TOKEN, + &eventlist, DM_EVENT_MAX) == -1) { + errno_msg("Can't set event disposition for mount"); + return(1); + } + + DMEV_ZERO(eventlist); + + /* File system administration events. */ + + DMEV_SET(DM_EVENT_PREUNMOUNT, eventlist); + DMEV_SET(DM_EVENT_UNMOUNT, eventlist); + DMEV_SET(DM_EVENT_NOSPACE, eventlist); + + /* While DM_EVENT_DEBUT is optional, it appears that the spec always + lets it be specified in a dm_set_disp call; its just that the + event will never be seen on some platforms. + */ + + DMEV_SET(DM_EVENT_DEBUT, eventlist); + + + /* Namespace events. */ + + DMEV_SET(DM_EVENT_CREATE, eventlist); + DMEV_SET(DM_EVENT_POSTCREATE, eventlist); + DMEV_SET(DM_EVENT_REMOVE, eventlist); + DMEV_SET(DM_EVENT_POSTREMOVE, eventlist); + DMEV_SET(DM_EVENT_RENAME, eventlist); + DMEV_SET(DM_EVENT_POSTRENAME, eventlist); + DMEV_SET(DM_EVENT_LINK, eventlist); + DMEV_SET(DM_EVENT_POSTLINK, eventlist); + DMEV_SET(DM_EVENT_SYMLINK, eventlist); + DMEV_SET(DM_EVENT_POSTSYMLINK, eventlist); + + /* Managed region data events. */ + + DMEV_SET(DM_EVENT_READ, eventlist); + DMEV_SET(DM_EVENT_WRITE, eventlist); + DMEV_SET(DM_EVENT_TRUNCATE, eventlist); + + /* Metadata events. */ + + DMEV_SET(DM_EVENT_ATTRIBUTE, eventlist); +#if ! defined ( __sgi ) && ! defined ( VERITAS ) && ! defined(linux) + DMEV_SET(DM_EVENT_CANCEL, eventlist); /* not supported on SGI */ +#endif +#if !defined(__sgi) && !defined(linux) + DMEV_SET(DM_EVENT_CLOSE, eventlist); /* not supported on SGI */ +#endif + DMEV_SET(DM_EVENT_DESTROY, eventlist); + + /* Pseudo-events. */ + + /* DM_EVENT_USER - always enabled - causes EINVAL if specified */ + + if (dm_set_disp(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, + &eventlist, DM_EVENT_MAX) == -1) { + errno_msg("Can't set event disposition for filesystem"); + return(1); + } + return(0); +} + + +/* + Enable event generation on each valid filesystem-based DMAPI event + within the given file system. + + Returns non-zero on errors. +*/ + +static int +set_events( + dm_sessid_t sid, + void *fs_hanp, + size_t fs_hlen) +{ + dm_eventset_t eventlist; + + if (Verbose) { + err_msg("Setting event list to enable all events " + "for this file system\n"); + } + DMEV_ZERO(eventlist); + + /* File system administration events. */ + + /* DM_EVENT_MOUNT - always enabled on the global handle - causes + EINVAL if specified. + */ + DMEV_SET(DM_EVENT_PREUNMOUNT, eventlist); + DMEV_SET(DM_EVENT_UNMOUNT, eventlist); + DMEV_SET(DM_EVENT_NOSPACE, eventlist); + /* DM_EVENT_DEBUT - always enabled - causes EINVAL if specified. */ + + /* Namespace events. */ + + DMEV_SET(DM_EVENT_CREATE, eventlist); + DMEV_SET(DM_EVENT_POSTCREATE, eventlist); + DMEV_SET(DM_EVENT_REMOVE, eventlist); + DMEV_SET(DM_EVENT_POSTREMOVE, eventlist); + DMEV_SET(DM_EVENT_RENAME, eventlist); + DMEV_SET(DM_EVENT_POSTRENAME, eventlist); + DMEV_SET(DM_EVENT_LINK, eventlist); + DMEV_SET(DM_EVENT_POSTLINK, eventlist); + DMEV_SET(DM_EVENT_SYMLINK, eventlist); + DMEV_SET(DM_EVENT_POSTSYMLINK, eventlist); + + /* Managed region data events. These are not settable by + dm_set_eventlist on a filesystem basis. They are meant + to be set using dm_set_region on regular files only. + However, in the SGI implementation, they are filesystem-settable. + Since this is useful for testing purposes, do it. + */ + + /* DM_EVENT_READ */ + /* DM_EVENT_WRITE */ + /* DM_EVENT_TRUNCATE */ + + /* Metadata events. */ + + DMEV_SET(DM_EVENT_ATTRIBUTE, eventlist); +#if ! defined ( __sgi ) && ! defined ( VERITAS ) && !defined(linux) + DMEV_SET(DM_EVENT_CANCEL, eventlist); /* not supported on SGI */ +#endif +#if !defined(__sgi) && !defined(linux) + DMEV_SET(DM_EVENT_CLOSE, eventlist); /* not supported on SGI */ +#endif + DMEV_SET(DM_EVENT_DESTROY, eventlist); + + /* Pseudo-events. */ + + /* DM_EVENT_USER - always enabled - causes EINVAL if specified */ + + if (dm_set_eventlist(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, + &eventlist, DM_EVENT_MAX) == -1) { + errno_msg("Can't set event list"); + return(1); + } + return(0); +} + + +/* + Disable monitoring for all events in the DMAPI for the given + file system. This is done before exiting so that future + operations won't hang waiting for their events to be handled. + + Returns non-zero on errors. +*/ + +static int +clear_events( + dm_sessid_t sid, + void *fs_hanp, + size_t fs_hlen) +{ + dm_eventset_t eventlist; + + if (Verbose) { + err_msg("Clearing event list to disable all events " + "for this filesystem\n"); + } + DMEV_ZERO(eventlist); + + if (dm_set_eventlist(sid, fs_hanp, fs_hlen, DM_NO_TOKEN, + &eventlist, DM_EVENT_MAX) == -1) { + errno_msg("Can't clear event list"); + return(1); + } + return(0); +} + + +/* + * Respond to any events which haven't been handled yet. + * dm_getall_tokens provides a list of tokens for the outstanding events. + * dm_find_eventmsg uses the token to lookup the corresponding message. + * The message is passed to handle_message() for normal response processing. + */ +int +finish_responding( + dm_sessid_t sid) +{ + int error = 0; + u_int nbytes, ntokens = 0, ret_ntokens, i; + dm_token_t *tokenbuf = NULL; + size_t buflen, ret_buflen; + char *msgbuf = NULL; + dm_eventmsg_t *msg; + + if (Verbose) + err_msg("Responding to any outstanding delivered event messages\n"); + + /* + * Initial sizes for the token and message buffers + */ + ret_buflen = 16 * (sizeof(dm_eventmsg_t) + sizeof(dm_data_event_t) + + HANDLE_LEN); + ret_ntokens = 16; + + /* + * The E2BIG dance... + * Take a guess at how large to make the buffer, starting with ret_ntokens. + * If the routine returns E2BIG, use the returned size and try again. + * If we're already using the returned size, double it and try again. + */ + do { + ntokens = (ntokens != ret_ntokens) ? ret_ntokens : ntokens*2; + nbytes = ntokens * (sizeof(dm_token_t) + sizeof(dm_vardata_t)); + tokenbuf = malloc(nbytes); + if (tokenbuf == NULL) { + err_msg("Can't malloc %d bytes for tokenbuf\n", nbytes); + error = 1; + goto out; + } + error = dm_getall_tokens(sid, ntokens, tokenbuf, &ret_ntokens); + } while (error && errno == E2BIG); + + if (error) { + errno_msg("Can't get all outstanding tokens"); + goto out; + } + + for (i = 0; i < ret_ntokens; i++) { + if (Verbose) + err_msg("Responding to outstanding event for token %d\n",(int)*tokenbuf); + + /* + * The E2BIG dance reprise... + */ + do { + buflen = (buflen != ret_buflen) ? ret_buflen : buflen * 2; + msgbuf = malloc(buflen); + if (msgbuf == NULL) { + err_msg("Can't malloc %d bytes for msgbuf\n", buflen); + error = 1; + goto out; + } + error = dm_find_eventmsg(sid, *tokenbuf, buflen, msgbuf, &ret_buflen); + } while (error && errno == E2BIG); + if (error) { + errno_msg("Can't find the event message for token %d", (int)*tokenbuf); + goto out; + } + + msg = (dm_eventmsg_t *) msgbuf; + while (msg != NULL) { + error = handle_message(sid, msg); + if (error) + goto out; + msg = DM_STEP_TO_NEXT(msg, dm_eventmsg_t *); + } + + tokenbuf++; + } + + out: + if (tokenbuf) + free(tokenbuf); + if (msgbuf) + free(msgbuf); + return error; +} + + +/* + * Establish an exit handler since we run in an infinite loop + */ +int +establish_handler(void) +{ + struct sigaction act; + + /* + * Set up signals so that we can wait for spawned children + */ + act.sa_handler = exit_handler; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + + (void)sigaction(SIGHUP, &act, NULL); + (void)sigaction(SIGINT, &act, NULL); + (void)sigaction(SIGQUIT, &act, NULL); + (void)sigaction(SIGTERM, &act, NULL); + (void)sigaction(SIGUSR1, &act, NULL); + (void)sigaction(SIGUSR1, &act, NULL); + (void)sigaction(SIGUSR2, &act, NULL); + + return(0); +} + + +/* + * Exit gracefully + * + * Stop events from being generated for the given file system + * Respond to any events that were delivered but unanswered + * (the event loop may have been in the middle of taking care of the event) + * Try getting any undelivered events but don't block if none are there + * (the file system may have generated an event after we killed dm_get_events) + * Shutdown the session using the global "sid" variable. + */ +void +exit_handler(int x) +{ + int error; + void *fs_hanp; + size_t fs_hlen; + + if (Verbose) + printf("\n"), + err_msg("Exiting...\n"); + + error = get_fs_handle(fsname, &fs_hanp, &fs_hlen); + + if (!error) { + error = clear_events(sid, fs_hanp, fs_hlen); + if (error) + /* just keep going */ ; + } + + error = finish_responding(sid); + if (error) + /* just keep going */ ; + + err_msg("Processing any undelivered event messages\n"); + event_loop(sid, 0 /*waitflag*/); + + err_msg("Shutting down the session\n"); + if (sid != 0) { + error = dm_destroy_session(sid); + if (error == -1) { + errno_msg("Can't shut down session - use 'mrmean -kv' to clean up!"); + } + } + + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/dump_allocinfo.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/dump_allocinfo.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/dump_allocinfo.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/dump_allocinfo.c Tue Jan 16 19:24:14 2001 @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_get_allocinfo(). The +command line is: + + dump_allocinfo [-D] [-n nelem] [-o offp] [-s sid] pathname + +where pathname is the name of a file, 'offp' is a byte offset from the +beginning of the file where you want to start dumping, and 'nelem' allows +you to specify how many extent structures to use in each dm_get_allocinfo +call. + +The code checks the returned extents as much as possible for errors. +It detects bad ex_type values, verifies that there is always a trailing +hole at the end of the file, that the ex_offset of each extent matches the +ex_offset+ex_length of the previous extent, and that ex_offset+ex_length +is always an even multiple of 512. It verifies that all ex_offset values +after the first fall on a 512-byte boundary. It verifies that the '*offp' +value returned by dm_get_allocinfo() is 0 at the end of the file, and +equals ex_offset+ex_length of the last extent if not at the end of the file. +Any error is reported to stderr, and the program then terminates with a +non-zero exit status. + +The program produces output similar to xfs_bmap in order to make comparison +easier. Here is some sample output. + +f1: offset 1 + rc 0, nelemp 17 + 0: [0..127]: resv [1..511] + +Line 1 gives the name of the file and the byte offset within the file where +the dump started. Line 2 appears once for each dm_get_allocinfo() call, +giving the return value (rc) and the number of extents which were returned. +Line 3 is repeated once for each extent. The first field "0:" is the extent +number. The second field "[0..127]:" give the starting and ending block for +the extent in 512-byte units. The third field is either "resv" to indicate +allocated space or "hole" if the extent is a hole. The fourth field +"[1..511]" only appears if the dump did not start with byte zero of the +first block. In that case, the first number shows the actual byte offset +within the block (1 in this case). The second number should always be +511 since we always dump to the end of a block. + +Possible tests +-------------- + +Run the test scripts "test_allocinfo_1" and "test_allocinfo_2". +(The former compares dump_allocinfo output with xfs_bmap output. The latter +compares various dump_allocinfo outputs, from trials with many different +buffer sizes). + +Produce a file with holes, and perform the following tests using just one +extent (-e 1). + Dump extents from beginning of the file. + Dump from byte 1 of the file. + Dump from the last byte of the first extent. + Dump from the first byte of the second extent. + Dump from the middle of the second extent. + Dump the first byte of the last extent. + Dump the last byte of the last extent. + Dump the first byte after the last extent. + Dump starting at an offset way past the end of the file. + +Produce a fragmented file with many adjacent DM_EXTENT_RES extents. + Repeat the above tests. + +Produce a GRIO file with holes. + Repeat the above tests. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + +static int print_alloc(dm_sessid_t sid, void* hanp, size_t hlen, + char *pathname, dm_off_t startoff, u_int nelem); + +char *Progname; +int Dflag = 0; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-D] [-n nelem] [-o off] [-s sid] " + "pathname\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_off_t startoff = 0; /* starting offset */ + u_int nelem = 100; + char *pathname; + void *hanp; + size_t hlen; + dm_stat_t sbuf; + char *name; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "Dn:o:s:")) != EOF) { + switch(opt) { + case 'D': + Dflag++; + break; + case 'n': + nelem = atol(optarg); + break; + case 'o': + startoff = atoll(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + pathname = argv[optind]; + + if (dm_init_service(&name)) { + fprintf(stderr, "dm_init_service failed, %s\n", + strerror(errno)); + exit(1); + } + + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the file's handle and verify that it is a regular file. */ + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for %s\n", pathname); + exit(1); + } + if (dm_get_fileattr(sid, hanp, hlen, DM_NO_TOKEN, DM_AT_STAT, &sbuf)) { + fprintf(stderr, "dm_get_fileattr failed\n"); + exit(1); + } + if (!S_ISREG(sbuf.dt_mode)) { + fprintf(stderr, "%s is not a regular file\n", pathname); + exit(1); + } + + /* Print the allocation. */ + + if (print_alloc(sid, hanp, hlen, pathname, startoff, nelem)) + exit(1); + + dm_handle_free(hanp, hlen); + exit(0); +} + + +static int +print_alloc( + dm_sessid_t sid, + void *hanp, + size_t hlen, + char *pathname, + dm_off_t startoff, + u_int nelem) +{ + dm_off_t endoff; + dm_extent_t *extent; + u_int nelemp; + u_int num = 0; + u_int i; + char *type = NULL; + int rc; + + if (Dflag) fprintf(stdout, "%s: starting offset %lld\n", pathname, startoff); + + /* Allocate space for the number of extents requested by the user. */ + + if ((extent = malloc(nelem * sizeof(*extent))) == NULL) { + fprintf(stderr, "can't malloc extent structures\n"); + return(1); + } + + rc = 1; + endoff = startoff; + + while (rc != 0) { + rc = dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN, &startoff, + nelem, extent, &nelemp); + if (rc < 0) { + fprintf(stderr, "dm_get_allocinfo failed, %s\n", + strerror(errno)); + return(1); + } + + if (Dflag) fprintf(stdout, "\treturned %d, nelemp %d\n", rc, nelemp); + + if (Dflag && nelemp) + fprintf(stdout, " ex_type ex_offset ex_length\n"); + + /* Note: it is possible for nelemp to be zero! */ + + for (i = 0; i < nelemp; i++) { + /* The extent must either be reserved space or a hole. */ + switch (extent[i].ex_type) { + case DM_EXTENT_RES: + type = "resv"; + break; + case DM_EXTENT_HOLE: + type = "hole"; + break; + default: + fprintf(stderr, "invalid extent type %d\n", + extent[i].ex_type); + return(1); + } + + if (i!=nelemp-1 || rc!=0) { + if (!Dflag) { + fprintf(stdout, "\t%d: [%lld..%lld]: %s", num, + extent[i].ex_offset / 512, + (extent[i].ex_offset + + extent[i].ex_length - 1) / 512, type); + if ((extent[i].ex_offset % 512 != 0) || + (endoff % 512 != 0)) { + fprintf(stdout, "\t[%lld..%lld]\n", + extent[i].ex_offset % 512, + (endoff-1) % 512); + } else { + fprintf(stdout, "\n"); + } + } else { + fprintf(stdout, "%5s %13lld %13lld\n", + type, extent[i].ex_offset, + extent[i].ex_length); + } + } + /* The ex_offset of the first extent should match the + 'startoff' specified by the caller. The ex_offset + in subsequent extents should always match + (ex_offset + ex_length) of the previous extent, + and should always start on a 512 byte boundary. + */ + + if (extent[i].ex_offset != endoff) { + fprintf(stderr, "new extent (%lld)is not " + "adjacent to previous one (%lld)\n", + extent[i].ex_offset, endoff); + return(1); + } + if (num && (extent[i].ex_offset % 512) != 0) { + fprintf(stderr, "non-initial ex_offset (%lld) " + "is not a 512-byte multiple\n", + extent[i].ex_offset); + return(1); + } + + /* Non-initial extents should have ex_length values + that are an even multiple of 512. The initial + extent should be a multiple of 512 less the offset + into the starting 512-byte block. + */ + + if (((extent[i].ex_offset % 512) + extent[i].ex_length) % 512 != 0) { + fprintf(stderr, "ex_length is incorrect based " + "upon the ex_offset\n"); + return(1); + } + + endoff = extent[i].ex_offset + extent[i].ex_length; + num++; /* count of extents printed */ + } + + /* If not yet at end of file, the startoff parameter should + match the ex_offset plus ex_length of the last extent + retrieved. + */ + + if (rc && startoff != endoff) { + fprintf(stderr, "startoff is %lld, should be %lld\n", + startoff, endoff); + return(1); + } + + /* If we are at end of file, the last extent should be a + hole. + */ + + if (!rc && type && strcmp(type, "hole")) { + fprintf(stderr, "file didn't end with a hole\n"); + return(1); + } + } + + /* At end of file, startoff should always equal zero. */ + + if (startoff != 0) { + fprintf(stderr, "startoff was not zero at end of file\n"); + return(1); + } + return(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/invis_test.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/invis_test.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/invis_test.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/invis_test.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#include +#include + +#include + +#include +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +For manually testing DMAPI functions dm_write_invis() and dm_read_invis() + +The command line is: + + invis_test [-Rrv] [-l len] [-o offset] [-s sid] ls_path pathname + +where: + -R + reuse existing test file + -r + use dm_invis_read, default is dm_invis_write. + len + length of read/write + offset + offset in file for read/write + sid + is the session ID whose events you you are interested in. + ls_path + is the path to a specific copy of ls, important only for its size + pathname + is the filesystem to use for the test. + +DM_WRITE_SYNC is is not supported. +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-Rrv] [-l len] [-o offset] [-s sid] ls_path pathname\n", + Progname); + exit(1); +} + +#define BUFSZ 100 + +int +main( + int argc, + char **argv) +{ + int Vflag=0; + dm_sessid_t sid = DM_NO_SESSION; + char *dir_name = NULL; + char *ls_path = NULL; + char *name; + char ch = 'A'; + char test_file[128]; + char command[1024]; + void *hanp; + size_t hlen; + char buf[BUFSZ]; + dm_ssize_t rc; + dm_off_t offset = 0; + dm_size_t length = BUFSZ; + int opt; + int reading = 0; /* writing is the default */ + int exitstat=0; + dm_size_t errblockstart, errblockend; + int in_err_block; + int i; + int reuse_file = 0; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "Rvs:rl:o:")) != EOF) { + switch (opt) { + case 'v': + Vflag++; + break; + case 'r': + reading++; + break; + case 'R': + reuse_file++; + break; + case 'l': + length = atoi(optarg); + break; + case 'o': + offset = atoi(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) + usage(); + ls_path = argv[optind]; + dir_name = argv[optind+1]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + sprintf(test_file, "%s/DMAPI_test_file", dir_name); + if( (!reading) && (!reuse_file) ){ + sprintf(command, "cp %s %s\n", ls_path, test_file); + system(command); + } + + if (dm_path_to_handle(test_file, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for %s; bypassing test\n", + test_file); + exit(1); + } + + if( Vflag ) + printf("using length = %llu\n", length ); + if( length > BUFSZ ){ + fprintf(stderr, "length(%llu) > BUFSZ(%d)\n", length, BUFSZ); + exit(1); + } + + if( reading ){ + memset(buf, '\0', BUFSZ); + + rc = dm_read_invis(sid, hanp, hlen, DM_NO_TOKEN, + offset, length, buf); + if( rc < 0 ){ + fprintf(stderr, "dm_read_invis failed, (err=%d)\n", errno); + dm_handle_free(hanp, hlen); + exit(1); + } + if( rc != length ){ + fprintf(stderr, "dm_read_invis read %lld bytes, wanted to write %lld bytes\n", + rc, length ); + dm_handle_free(hanp, hlen); + exitstat++; + } + else { + printf("dm_read_invis read %lld bytes\n", rc); + } + + in_err_block = 0; + errblockstart = errblockend = 0; + for( i=0; i < length; ++i ){ + if( in_err_block ){ + if( buf[i] != ch ){ + /* still in the err block */ + errblockend = i; + } + else { + /* end of bad block */ + fprintf(stderr, "read err block: byte %lld to %lld\n", errblockstart, errblockend); + in_err_block = 0; + } + } + else if( buf[i] != ch ){ + /* enter err block */ + errblockstart = i; + in_err_block = 1; + } + } + if( in_err_block ){ + /* end of bad block */ + fprintf(stderr, "read err block: byte %lld to %lld\n", errblockstart, errblockend); + in_err_block = 0; + } + } + else { + + memset(buf, ch, BUFSZ); + + rc = dm_write_invis(sid, hanp, hlen, DM_NO_TOKEN, + 0, offset, length, buf); + if( rc < 0 ){ + fprintf(stderr, "dm_write_invis failed, (err=%d)\n", errno); + dm_handle_free(hanp, hlen); + exit(1); + } + if( rc != length ){ + fprintf(stderr, "dm_write_invis wrote %lld bytes, wanted to write %lld bytes\n", + rc, length ); + dm_handle_free(hanp, hlen); + exit(1); + } + printf("dm_write_invis wrote %lld bytes\n", rc); + } + + dm_handle_free(hanp, hlen); + exit(exitstat); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/mm_fill.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/mm_fill.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/mm_fill.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/mm_fill.c Tue Jan 16 19:24:14 2001 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +/* + * mmap_fill + * + * use memory mapping to fill a filesystem! :) + */ +#include +#include +#include +#include +#include +#include +#include + + +char * progname; +int fd; /* file descriptor */ +addr_t ptr; /* mapped pointers */ +off_t off; +long long junk[512] = { -1 }; +long long counter; + +main(int argc, char * argv[]) +{ + int i; + for (i=0; i<512; i++) junk[i]=-1; + + + if ((progname = strrchr(argv[0], '/')) == NULL) + progname = argv[0]; + else + progname++; + + if (argc < 2) { + fprintf(stderr,"Usage: %s filename\n", progname); + exit(1); + } + + fd = open(argv[1], O_RDWR|O_CREAT, 0644); + if (fd < 0) { + fprintf(stderr,"%s: cannot open %s\n", progname, argv[1]); + perror(argv[1]); + exit(3); + } + + ptr = mmap64(NULL, (size_t)(0x10000000), PROT_WRITE, MAP_SHARED|MAP_AUTOGROW, fd, 0); + if (ptr == MAP_FAILED) { + fprintf(stderr,"%s: cannot mmap64 %s\n", progname, argv[1]); + perror(argv[1]); + exit(3); + } + + for(counter=0; ; counter++) { + junk[0] = counter; + bcopy(junk, ptr, sizeof(junk)); + ptr+=sizeof(junk); + } + printf("%s complete.\n", progname); + return 0; +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/mmap.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/mmap.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/mmap.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/mmap.c Tue Jan 16 19:24:14 2001 @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +/* + * This routine simulates + * + * cp file1 file2 + * + * + * It is a demo program which does the copy by memory mapping each of the + * files and then doing a byte at a time memory copy. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + + +char * Progname; +off_t len; /* length of file 1 */ +off_t offset = 0; +int print_flags_set = 1; + +typedef struct fflag { + int arg; /* != 0 if ars specified */ + int value; /* flags value */ +} fflag_t; + + +typedef enum ftype { /* flag bit types */ + FL_MAP, FL_PROT, FL_OPEN, FL_MAX +} ftype_t; + +typedef struct mfile { + fflag_t flags[FL_MAX]; + char *path; + int fd; + struct stat st; + addr_t p; +} mfile_t; + + +#define FLAG(symbol,type) { # symbol , symbol, type } +#define MAP_NONE 0 + +static struct { + char *name; + int value; + ftype_t type; +} Flags[] = { + FLAG(O_RDONLY, FL_OPEN), + FLAG(O_WRONLY, FL_OPEN), + FLAG(O_RDWR, FL_OPEN), + FLAG(O_NDELAY, FL_OPEN), + FLAG(O_NONBLOCK, FL_OPEN), + FLAG(O_APPEND, FL_OPEN), + FLAG(O_SYNC, FL_OPEN), + FLAG(O_TRUNC, FL_OPEN), + FLAG(O_CREAT, FL_OPEN), + FLAG(O_DIRECT, FL_OPEN), + FLAG(PROT_NONE, FL_PROT), + FLAG(PROT_READ, FL_PROT), + FLAG(PROT_WRITE, FL_PROT), + FLAG(PROT_EXEC, FL_PROT), + FLAG(PROT_EXECUTE, FL_PROT), + FLAG(MAP_SHARED, FL_MAP), + FLAG(MAP_PRIVATE, FL_MAP), + FLAG(MAP_FIXED, FL_MAP), + FLAG(MAP_RENAME, FL_MAP), + FLAG(MAP_AUTOGROW, FL_MAP), + FLAG(MAP_LOCAL, FL_MAP), + FLAG(MAP_AUTORESRV, FL_MAP), + FLAG(MAP_NONE, FL_MAP), +}; + +int num_Flags = sizeof(Flags)/sizeof(Flags[0]); + + +mfile_t *ifile, *ofile; +mfile_t *hfile; /* Hack job */ +static int hack = 0; + +static mfile_t *new_mfile(void); +static int mfile_opt(char * s, mfile_t * f); +static void print_flags(char *s, mfile_t *f); +static void Usage(void); + +main(int argc, char * argv[]) +{ + int opt; + + if ((Progname = strrchr(argv[0], '/')) == NULL) + Progname = argv[0]; + else + Progname++; + + ifile = new_mfile(); + ofile = new_mfile(); + hfile = new_mfile(); + if (ifile == NULL || ofile == NULL || hfile == NULL) { + fprintf(stderr,"%s: malloc failure.\n", Progname); + exit (1); + } + + /* Set default flags */ + ifile->flags[FL_MAP].value = MAP_PRIVATE; + ifile->flags[FL_PROT].value = PROT_READ; + ifile->flags[FL_OPEN].value = O_RDONLY; + ofile->flags[FL_MAP].value = MAP_SHARED|MAP_AUTOGROW; + ofile->flags[FL_PROT].value = PROT_WRITE; + ofile->flags[FL_OPEN].value = O_RDWR|O_CREAT; + + while ((opt = getopt(argc, argv, "i:o:h:d")) != EOF) { + switch(opt) { + case 'i': + if (mfile_opt(optarg, ifile) != 0) { + fprintf(stderr, "%s: Invalid -i option %s\n", + Progname, optarg); + Usage(); + } + break; + + case 'o': + if (mfile_opt(optarg, ofile) != 0) { + fprintf(stderr, "%s: Invalid -o option %s\n", + Progname, optarg); + Usage(); + } + break; + + case 'h': + if (mfile_opt(optarg, hfile) != 0) { + fprintf(stderr, "%s: Invalid -h option %s\n", + Progname, optarg); + Usage(); + } + hack = 1; + break; + + case 'd': + print_flags_set ^= 1; + break; + case '?': + Usage(); + } + } + + if (optind+1 > argc) + Usage(); + + ifile->path = argv[optind++]; + ofile->path = argv[optind++]; + + if (optind != argc) /* Extra args on command line */ + Usage(); + + if (stat(ifile->path, &(ifile->st)) < 0) { + fprintf(stderr,"%s: stat of %s failed.\n", + Progname, ifile->path); + perror(ifile->path); + exit(2); + } + + len = ifile->st.st_size; + + ifile->fd = open(ifile->path, ifile->flags[FL_OPEN].value); + if (ifile->fd < 0) { + fprintf(stderr,"%s: cannot open %s\n", Progname, ifile->path); + perror(ifile->path); + exit(2); + } + + + ofile->fd = open(ofile->path, ofile->flags[FL_OPEN].value, 0644); + if (ofile->fd < 0) { + fprintf(stderr,"%s: cannot open %s\n", Progname, ofile->path); + perror(ofile->path); + exit(3); + } + + if (print_flags_set) { + print_flags("Input ", ifile); + print_flags("Output", ofile); + if (hack) + print_flags("Hack ", hfile); + } + + + ifile->p = mmap(NULL, len, ifile->flags[FL_PROT].value, + ifile->flags[FL_MAP].value, ifile->fd, 0); + if (ifile->p == MAP_FAILED) { + fprintf(stderr,"%s: cannot mmap %s\n", Progname, ifile->path); + perror(ifile->path); + exit(2); + } + + ofile->p = mmap(NULL, len, ofile->flags[FL_PROT].value, + ofile->flags[FL_MAP].value , ofile->fd, 0); + if (ofile->p == MAP_FAILED) { + fprintf(stderr,"%s: cannot mmap %s\n", Progname, ofile->path); + perror(ofile->path); + exit(3); + } + + if (hack) { + int error; + + error = mprotect(ofile->p, len, hfile->flags[FL_PROT].value); + if (error) { + fprintf(stderr,"%s: mprotect call failed.\n", Progname); + perror("mprotect"); + exit(3); + } + } + + bcopy(ifile->p, ofile->p, len); + + printf("%s complete.\n", Progname); + return 0; +} + +static mfile_t * +new_mfile(void) +{ + mfile_t *ptr = (mfile_t *)malloc(sizeof(*ptr)); + if (ptr) + bzero(ptr, sizeof *ptr); + + return ptr; +} + + +static int +mfile_opt(char * s, mfile_t *f) +{ + int i; + ftype_t type; + + for (i = 0; i < num_Flags; i++) { + if(!strcasecmp(Flags[i].name, s)) { + + /* Zero value if this is 1st arg of this type */ + + type = Flags[i].type; + if (f->flags[type].arg++ == 0) + f->flags[type].value = 0; + f->flags[type].value |= Flags[i].value; + return 0; + } + } + return -1; /* error - string not found */ +} + +static void +Usage(void) +{ + int i; + + fprintf(stderr, + "Usage: %s [-d] [-i flag] [-i flag] [-o flag] ... file1 file2\n", + Progname); + fprintf(stderr, "Valid flag values are:\n"); + + for (i = 0; i < num_Flags; i++) { + fprintf(stderr,"%15s",Flags[i].name); + if ((i+1)%4 == 0 || i == num_Flags-1) + fprintf(stderr,"\n"); + else + fprintf(stderr,","); + } + exit(1); +} + +static void +print_flags(char *s, mfile_t *f) +{ + int i; + ftype_t type; + + printf("DEBUG - %s flags:\n", s); + for (i = 0; i < num_Flags; i++) { + type = Flags[i].type; + if (type == FL_OPEN && Flags[i].value == O_RDONLY && + ((f->flags[type].value) & 3) == 0) + /* Hack to print out O_RDONLY */ + printf("\t%s\n", Flags[i].name); + else if ((Flags[i].value & (f->flags[type].value)) != 0) + printf("\t%s\n", Flags[i].name); + } +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/mmap_cp.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/mmap_cp.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/mmap_cp.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/mmap_cp.c Tue Jan 16 19:24:14 2001 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +/* + * mmap_fill + * + * use memory mapping to fill a filesystem! :) + */ +#include +#include +#include +#include +#include +#include +#include + + +char * progname; +int fd; /* file descriptor */ +addr_t ptr; /* mapped pointers */ +long long junk[512]; + +main(int argc, char * argv[]) +{ + printf("Sizeof junk = %d \n", junk); + exit(0); + + if ((progname = strrchr(argv[0], '/')) == NULL) + progname = argv[0]; + else + progname++; + + if (argc < 2) { + fprintf(stderr,"Usage: %s filename\n", progname); + exit(1); + } + + fd = open(argv[1], O_RDWR|O_CREAT, 0644); + if (fd < 0) { + fprintf(stderr,"%s: cannot open %s\n", progname, argv[1]); + perror(argv[1]); + exit(3); + } + + ptr = mmap(NULL, len, PROT_WRITE, MAP_SHARED|MAP_AUTOGROW , fd, 0); + if (ptr == MAP_FAILED) { + fprintf(stderr,"%s: cannot mmap %s\n", progname, argv[1]); + perror(argv[1]); + exit(3); + } + + while (1) { + bcopy(junk, ptr, size_of(junk)); + ptr+=size_of(junk); + } + printf("%s complete.\n", progname); + return 0; +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/region_test.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/region_test.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/region_test.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/region_test.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Manual test for the DMAPI functions dm_set_region() and dm_get_region(). + +The command line is: + + region_test [-Rv] [-s sid] [-l len] [-o offset] ls_path directory + +where + -R + reuse the existing test file + pathname + is the name of a file + ls_path + is the path to a specific copy of ls, important only for its size + sid + is the session ID whose events you you are interested in. +----------------------------------------------------------------------------*/ + +#define NELEM 1 + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-Rv] [-s sid] [-l len] [-o offset] ls_path pathname\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *dir_name = NULL; + char *ls_path = NULL; + char command[1024]; + char test_file[128]; + int opt; + int Vflag = 0; + dm_region_t region = { 0, 0, 0 }; + char *name; + int reuse_file = 0; + void *hanp; + size_t hlen; + dm_boolean_t exactflag; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "vo:l:s:R")) != EOF) { + switch (opt) { + case 'v': + Vflag++; + break; + case 'R': + reuse_file++; + break; + case 'o': + region.rg_offset = atol(optarg); + break; + case 'l': + region.rg_size = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 > argc) + usage(); + ls_path = argv[optind]; + dir_name = argv[optind+1]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + sprintf(test_file, "%s/DMAPI_test_file", dir_name); + if( !reuse_file ){ + sprintf(command, "cp %s %s\n", ls_path, test_file); + system(command); + } + + if (dm_path_to_handle(test_file, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for file %s\n", test_file); + exit(1); + } + + region.rg_flags = DM_REGION_READ | DM_REGION_WRITE | DM_REGION_TRUNCATE; + if( dm_set_region( sid, hanp, hlen, DM_NO_TOKEN, NELEM, + ®ion, &exactflag ) ){ + fprintf(stderr, "dm_set_region failed, err=%d\n", errno); + dm_handle_free(hanp,hlen); + exit(1); + } + if( exactflag == DM_FALSE ) + fprintf(stderr, "exact flag was false\n"); + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/send_msg.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/send_msg.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/send_msg.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/send_msg.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function send_msg(). +The command line is: + + send_msg [-a] [-s sid] string + +where string is the msgdata to be stored in the event. +sid is the session ID to use for the event. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-a] [-s sid] string\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *string; + char *name; + int opt; + dm_msgtype_t msgtype = DM_MSGTYPE_SYNC; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "as:")) != EOF) { + switch (opt) { + case 'a': + msgtype = DM_MSGTYPE_ASYNC; + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 1 != argc) + usage(); + string = argv[optind++]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + if (dm_send_msg(sid, msgtype, strlen(string)+ 1, string)) { + fprintf(stderr, "dm_send_msg failed, %s\n", + strerror(errno)); + exit(1); + } + + exit(0); +} + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/test_dmattr.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/test_dmattr.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/test_dmattr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/test_dmattr.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,533 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include + +#include +#include + +#include +#include + + +/*--------------------------------------------------------------------------- +Automated test of the DMAPI functions: + dm_set_dmattr() + dm_get_dmattr() + dm_remove_dmattr() + +The command line is: + + test_dmattr [-v] [-n num] [-l length] [-s sid] directory + +where + ls_path + is the path to a specific copy of ls, important only for its size + directory + is the pathname to a DMAPI filesystem + num + is the number of files to create for the test. + length + is the length of the attribute value for the test. + sid + is the session ID whose attributes you are interested in. + +----------------------------------------------------------------------------*/ + +#define VALUE_LENGTH 22 +#define NUM_ITERATIONS 50 +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-v] [-n number] [-l length] " + "[-s sid] ls_path pathname\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *dir_name; + char *ls_path; + dm_attrname_t *attrnamep; + size_t buflen=VALUE_LENGTH; + char *bufp; + int setdtime = 0; + size_t rlenp; + void *hanp; + size_t hlen; + char *name; + int opt; + int i=0; + int j=0; + int Vflag=0; + int num_iter = NUM_ITERATIONS; + char test_file[128]; + char command[128]; + char **test_array; + dm_size_t config_retval; + dm_token_t test_token; + struct stat *statbuf; + struct stat *checkbuf; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "vn:l:s:")) != EOF) { + switch (opt) { + case 'v': + Vflag++; + break; + case 'n': + num_iter = atoi(optarg); + break; + case 'l': + buflen = atoi(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) + usage(); + ls_path = argv[optind]; + dir_name = argv[optind+1]; + + bufp = + (char *)(malloc (buflen * sizeof(char))); + statbuf = + (struct stat *)(malloc (num_iter * sizeof(struct stat))); + checkbuf = + (struct stat *)(malloc (num_iter * sizeof(struct stat))); + test_array = + (char **)(malloc (num_iter * sizeof(char *))); + if (bufp==NULL || test_array==NULL || + statbuf==NULL || checkbuf==NULL) { + printf("Malloc failed\n"); + exit(1); + } + for (i=0; i +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +/*--------------------------------------------------------------------------- +Automated search for EFAULT in the following DMAPI commands: + dm_get_allocinfo + dm_get_config + dm_get_config_events + dm_getall_dmattr + dm_init_attrloc + +There are other EFAULT tests, in the programs that test individual +DMAPI functions. Those other tests are referenced in comments in this source. + +The command line is: + test_efault [-s sid] [-v] ls_path pathname + +where: + sid + is the session ID whose events you you are interested in. + ls_path + is the path to a copy of ls, which will be copied as a test file. + pathname + is the filesystem to use for the test. +----------------------------------------------------------------------------*/ + +extern int optind; +extern int opterr; +extern char *optarg; + +char *Progname; +int Vflag=0; + +static void +usage(void) +{ + fprintf(stderr, + "Usage: %s [-v] [-s sid] ls_path pathname\n", + Progname); + exit(1); +} + + +int +main(int argc, char **argv) { + + dm_sessid_t sid = DM_NO_SESSION; + void *hanp; + size_t hlen; + char *name; + char *ls_path; + char *pathname; + char test_file[100]; + char command[100]; + int opt; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + opterr = 0; + while ((opt = getopt(argc, argv, "vn:s:")) != EOF) { + switch (opt) { + case 'v': + Vflag++; + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) { + usage(); + } + ls_path = argv[optind]; + pathname = argv[optind+1]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + printf("Beginning EFAULT testing...\n"); + + /*----------------------------------*\ + |* ## Traditional errno tests ## *| + \*----------------------------------*/ + sprintf(test_file, "%s/DMAPI_EFAULT_test_file", pathname); + sprintf(command, "cp %s %s\n", ls_path, test_file); + system(command); + + if (dm_path_to_handle(test_file, &hanp, &hlen)) { + fprintf(stderr, "ERROR: can't get handle for %s; %s\n", + test_file, ERR_NAME); + goto abort_test; + } + + + /*--------------------------------------------------------- + * get_allocinfo + *--------------------------------------------------------- + */ + { dm_off_t off=0; + u_int nelem=1; + dm_extent_t extent; + u_int nelem_ret; + + ERRTEST(EFAULT, "get_allocinfo (bad offp)", + dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN, + (dm_off_t*)(-1000), + nelem, &extent, &nelem_ret)) + ERRTEST(EFAULT, "get_allocinfo (bad extentp)", + dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN, + &off, nelem, (dm_extent_t*)(-1000), + &nelem_ret)) + ERRTEST(EFAULT, "get_allocinfo (bad nelemp)", + dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN, + &off, nelem, &extent, + (u_int*)(-1000))) + } + + /*------------------------------------------------------ + * get_bulkattr: see test_fileattr.c + *------------------------------------------------------ + * get_config + *------------------------------------------------------ + */ + ERRTEST(EFAULT, "get_config", + dm_get_config(hanp, hlen, DM_CONFIG_BULKALL, + (dm_size_t*)(-1000))) + /*--------------------------------------------------------- + * get_config_events + *--------------------------------------------------------- + */ + { + u_int nelem=5; + u_int *nelemp; + dm_eventset_t *eventsetp; + eventsetp = (dm_eventset_t *)malloc(nelem*sizeof(dm_eventset_t)); + if (eventsetp == NULL) { + printf("Couldn't malloc for config_events tests: %s\n", ERR_NAME); + } + else { + ERRTEST(EFAULT, "get_config_events (bad eventsetp)", + dm_get_config_events(hanp, hlen, nelem, + (dm_eventset_t*)(-1000), nelemp)) + ERRTEST(EFAULT, "get_config_events (bad nelemp)", + dm_get_config_events(hanp, hlen, nelem, eventsetp, + (u_int*)(-1000))) + } + } + /*--------------------------------------------------------- + * get_dirattrs: see test_fileattr.c + *--------------------------------------------------------- + * get_fileattr: see test_fileattr.c + *--------------------------------------------------------- + * get_region: see test_region.c + *--------------------------------------------------------- + * getall_dmattr + *--------------------------------------------------------- + */ + { + size_t buflen = 5; + void *bufp = (void *)malloc(buflen*sizeof(dm_attrlist_t)); + size_t *rlenp; + ERRTEST(EFAULT, "getall_dmattr (NULL handle)", + dm_getall_dmattr(sid, NULL, hlen, DM_NO_TOKEN, + buflen, bufp, rlenp)) + ERRTEST(EFAULT, "getall_dmattr (incremented bufp)", + dm_getall_dmattr(sid, hanp, hlen, DM_NO_TOKEN, + buflen, (void*)((char*)(bufp)+1), rlenp)) + ERRTEST(EFAULT, "getall_dmattr (bad bufp)", + dm_getall_dmattr(sid, hanp, hlen, DM_NO_TOKEN, + buflen, (void*)(-1000), rlenp)) + ERRTEST(EFAULT, "getall_dmattr (bad rlenp)", + dm_getall_dmattr(sid, hanp, hlen, DM_NO_TOKEN, + buflen, bufp, (size_t*)(-1000))) + } + /*--------------------------------------------------------- + * init_attrloc + *--------------------------------------------------------- + */ + ERRTEST(ENOTSUP, "init_attrloc", + dm_init_attrloc(sid, hanp, hlen, DM_NO_TOKEN, + (dm_attrloc_t*)(-1000))) + /*--------------------------------------------------------- + * probe_hole: see test_hole.c + *--------------------------------------------------------- + * remove_dmattr: see test_dmattr.c + *--------------------------------------------------------- + * set_dmattr: see test_dmattr.c + *--------------------------------------------------------- + * set_eventlist: see test_eventlist.c + *--------------------------------------------------------- + * set_region: see test_region.c + *--------------------------------------------------------- + */ + +abort_test: + sprintf(command, "rm %s\n", test_file); + system(command); + + printf("EFAULT testing complete.\n"); + + exit(0); +} + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/test_eventlist.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/test_eventlist.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/test_eventlist.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/test_eventlist.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_set_eventlist(). The +command line is: + + test_eventlist [-v] [-s sid] [-t token] directory + +where: +ls_path + is the path to a specific copy of ls, important only for its size +directory + is the pathname to a DMAPI filesystem. +sid + is the dm_sessid_t value to use. +token + is the dm_token_t value to use (DM_NO_TOKEN is the default). +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + +int check_one_event (dm_sessid_t, void*, size_t, dm_token_t, + dm_eventtype_t, int); + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-v] [-s sid] [-t token]" + "ls_path directory \n", Progname); + /* fprintf(stderr, "possible events are:\n"); + for (i = 0; i < ev_namecnt; i++) { + fprintf(stderr, "%s (%d)\n", ev_names[i].name, + ev_names[i].value); + } + */ + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t token = DM_NO_TOKEN; + char object[128]; + void *hanp; + size_t hlen; + int Vflag = 0; + char *name; + int opt; + int error; + void *fshanp; + size_t fshlen; + int i; + char command[128]; + char *ls_path; + char *dir_name; + dm_token_t test_token = DM_NO_TOKEN; + dm_eventset_t eventset; + void *test_vp; + u_int nelemp; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "s:t:uv")) != EOF) { + switch (opt) { + case 's': + sid = atol(optarg); + break; + case 't': + token = atol(optarg); + break; + case 'u': + Vflag=2; + break; + case 'v': + if (Vflag==0) Vflag=1; + break; + case '?': + usage(); + } + } + + if (optind + 2 != argc) + usage(); + ls_path = argv[optind]; + dir_name = argv[optind+1]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't initialize the DMAPI\n"); + exit(1); + } + + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the directory handle */ + if (dm_path_to_handle(dir_name, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for %s\n", dir_name); + exit(1); + } + + /***********************************************\ + |* Test to run on a FILE... *| + \***********************************************/ + + printf("File test beginning...\n"); + sprintf(object, "%s/VeryLongUnlikelyFilename.DMAPIFOO", dir_name); + sprintf(command, "cp %s %s \n", ls_path, object); + system(command); + + if (dm_path_to_handle(object, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for %s\n; aborting test", + object); + } + else { + for (i = 0; i < ev_namecnt; i++) { + error = check_one_event(sid, hanp, hlen, token, + ev_names[i].value, Vflag); + switch (ev_names[i].value){ + case DM_EVENT_ATTRIBUTE: case DM_EVENT_DESTROY: + if (error) { + fprintf(stderr, "ERROR: %s failed on a file!\n", + ev_names[i].name); + } + break; + default: + if (!error) { + fprintf(stderr, "ERROR: %s succeeded on a file!\n", + ev_names[i].name); + } + } + } + /*------------------------*\ + |* ## Errno subtests ## *| + \*------------------------*/ + printf("\t(errno subtests beginning...)\n"); + DMEV_ZERO(eventset); + DMEV_SET(DM_EVENT_ATTRIBUTE, eventset); + /*---------------------------------------------------------*/ + EXCLTEST("set", hanp, hlen, test_token, + dm_set_eventlist(sid, hanp, hlen, test_token, + &eventset, DM_EVENT_MAX)) + /*---------------------------------------------------------*/ + if ((test_vp = handle_clone(hanp, hlen)) == NULL) { + fprintf(stderr, + "Cannot create a test handle (%s); skipping EBADF test\n", + ERR_NAME); + } + else { + /* Alter the handle copy to make it (presumably) invalid */ + ((char *) test_vp)[hlen/2]++; + ERRTEST(EBADF, + "set", + dm_set_eventlist(sid, test_vp, hlen, token, + &eventset, DM_EVENT_MAX)) + dm_handle_free(test_vp, hlen); + } + /*---------------------------------------------------------*/ +#ifdef VERITAS_21 + /* Veritas gets a segmentation fault if hanp is NULL or if the + &eventset is out of range. + */ + fprintf(stderr, "\tERROR testing for EFAULT in set (bad hanp): " + "Veritas gets a segmentation fault.\n"); + fprintf(stderr, "\tERROR testing for EFAULT in set (bad eventset): " + "Veritas gets a segmentation fault.\n"); +#else + ERRTEST(EFAULT, + "set", + dm_set_eventlist(sid, NULL, hlen, token, + &eventset, DM_EVENT_MAX)) + ERRTEST(EFAULT, + "set", + dm_set_eventlist(sid, hanp, hlen, token, + (dm_eventset_t*)(-1000), DM_EVENT_MAX)) +#endif + /*---------------------------------------------------------*/ + ERRTEST(EINVAL, + "set (bad session)", + dm_set_eventlist(-100, hanp, hlen, token, + &eventset, DM_EVENT_MAX)) + /*---------------------------------------------------------*/ + ERRTEST(EINVAL, + "set (bad token)", + dm_set_eventlist(sid, hanp, hlen, 0, + &eventset, DM_EVENT_MAX)) + /*---------------------------------------------------------*/ +#if 0 + PROBLEM: too-small buffer does not produce E2BIG + { + dm_eventset_t *small_evsp = malloc(0); + if (dm_handle_to_fshandle(hanp, hlen, &fshanp, &fshlen)) { + fprintf(stderr, + "can't get filesystem handle from %s; aborting test\n", + dir_name); + } + else { + check_one_event(sid, fshanp, fshlen, token, + DM_EVENT_CREATE, Vflag); + ERRTEST(E2BIG, + "(broken) get", + dm_get_eventlist(sid, fshanp, fshlen, token, + DM_EVENT_MAX, small_evsp, &nelemp)) + check_one_event(sid, fshanp, fshlen, token, + DM_EVENT_INVALID, Vflag); + } + } +#endif + /*---------------------------------------------------------*/ + SHAREDTEST("get", hanp, hlen, test_token, + dm_get_eventlist(sid, hanp, hlen, test_token, + DM_EVENT_MAX, &eventset, &nelemp)) + /*---------------------------------------------------------*/ + ERRTEST(EBADF, + "get", + dm_get_eventlist(sid, test_vp, hlen, token, DM_EVENT_MAX, + &eventset, &nelemp)) + /*---------------------------------------------------------*/ +#ifdef VERITAS_21 + /* Veritas gets a segmentation fault if hanp is NULL. */ + + fprintf(stderr, "\tERROR testing for EFAULT in get (bad hanp): " + "Veritas gets a segmentation fault.\n"); +#else + ERRTEST(EFAULT, + "get", + dm_get_eventlist(sid, NULL, hlen, token, DM_EVENT_MAX, + &eventset, &nelemp )) +#endif + /*---------------------------------------------------------*/ + ERRTEST(EINVAL, + "get (bad session)", + dm_get_eventlist(-100, hanp, hlen, token, DM_EVENT_MAX, + &eventset, &nelemp)) + /*---------------------------------------------------------*/ + ERRTEST(EINVAL, + "get (bad token)", + dm_get_eventlist(sid, hanp, hlen, 0, DM_EVENT_MAX, + &eventset, &nelemp)) + /*---------------------------------------------------------*/ + printf("\t(errno subtests complete)\n"); + /*---------------------*\ + |* End of errno tests *| + \*---------------------*/ + + /* Finally, use DM_EVENT_INVALID to delete events... */ + check_one_event(sid, hanp, hlen, token, DM_EVENT_INVALID, Vflag); + } + sprintf(command, "rm %s \n", object); + system(command); + printf("\tFile test complete.\n"); + if (Vflag) printf("\n"); + + /***********************************************\ + |* Test to run on a DIRECTORY... *| + \***********************************************/ + + printf("Directory test beginning...\n"); + sprintf(object, "%s/VeryLongUnlikelyDirectoryName.DMAPIFOO", + dir_name); + sprintf(command, "mkdir %s \n", object); + system(command); + + if (opaque_to_handle(object, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for %s\n; aborting test", + object); + } + else { + for (i = 0; i < ev_namecnt; i++) { + error = check_one_event(sid, hanp, hlen, token, + ev_names[i].value, Vflag); + switch (ev_names[i].value){ + case DM_EVENT_CREATE: case DM_EVENT_POSTCREATE: + case DM_EVENT_REMOVE: case DM_EVENT_POSTREMOVE: + case DM_EVENT_RENAME: case DM_EVENT_POSTRENAME: + case DM_EVENT_LINK: case DM_EVENT_POSTLINK: + case DM_EVENT_SYMLINK: case DM_EVENT_POSTSYMLINK: + case DM_EVENT_ATTRIBUTE: case DM_EVENT_DESTROY: + if (error) { + fprintf(stderr, "ERROR: %s failed on a directory!\n", + ev_names[i].name); + } + break; + default: + if (!error) { + fprintf(stderr, "ERROR: %s succeeded on a directory!\n", + ev_names[i].name); + } + } + } + /* Use DM_EVENT_INVALID to delete events... */ + check_one_event(sid, hanp, hlen, token, DM_EVENT_INVALID, Vflag); + } + sprintf(object, "%s/VeryLongUnlikelyDirectoryName.DMAPIFOO", dir_name); + sprintf(command, "rmdir %s\n", object); + system(command); + printf("\tDirectory test complete.\n"); + if (Vflag) printf("\n"); + + /***********************************************\ + |* Test to run on a FILESYSTEM... *| + \***********************************************/ + + printf("Filesystem test beginning...\n"); + + if (dm_handle_to_fshandle(hanp, hlen, &fshanp, &fshlen)) { + fprintf(stderr, + "can't get filesystem handle from %s; aborting test\n", + dir_name); + } + else { + for (i = 0; i < ev_namecnt; i++) { + error = check_one_event(sid, fshanp, fshlen, token, + ev_names[i].value, Vflag); + switch (ev_names[i].value){ + case DM_EVENT_PREUNMOUNT: case DM_EVENT_UNMOUNT: + case DM_EVENT_NOSPACE: case DM_EVENT_DEBUT: + case DM_EVENT_CREATE: case DM_EVENT_POSTCREATE: + case DM_EVENT_REMOVE: case DM_EVENT_POSTREMOVE: + case DM_EVENT_RENAME: case DM_EVENT_POSTRENAME: + case DM_EVENT_LINK: case DM_EVENT_POSTLINK: + case DM_EVENT_SYMLINK: case DM_EVENT_POSTSYMLINK: + case DM_EVENT_ATTRIBUTE: case DM_EVENT_DESTROY: + if (error) { + fprintf(stderr, "ERROR: %s failed on a filesystem!\n", + ev_names[i].name); + } + break; + default: + if (!error) { + fprintf(stderr, "ERROR: %s succeeded on a filesystem!\n", + ev_names[i].name); + } + } + } + /* Use DM_EVENT_INVALID to delete events... */ + check_one_event(sid, fshanp, fshlen, token, DM_EVENT_INVALID, Vflag); + } + printf("\tFilesystem test complete.\n"); + + /***********************************************\ + |* End of tests! *| + \***********************************************/ + + dm_handle_free(fshanp, fshlen); + dm_handle_free(hanp, hlen); + exit(0); +} + +/*------------------------------------------------------------------- + check_one_event: + + Using dm_set_eventlist, set a single event on the object + indicated by the handle. + + Using dm_get_eventlist, check to see that the single event + was set correctly. + -------------------------------------------------------------------*/ + +int +check_one_event ( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventtype_t event, + int Vflag ) +{ + dm_eventset_t eventset; + dm_eventset_t check_eventset; + u_int nelemp; + int set_count = 0; + int i; + + DMEV_ZERO(eventset); + DMEV_ZERO(check_eventset); + + if (event != DM_EVENT_INVALID) { + DMEV_SET(event, eventset); + } + + if (dm_set_eventlist(sid, hanp, hlen, token, + &eventset, DM_EVENT_MAX)) { + if (Vflag){ + fprintf(stdout, " note: %s could not be set (%s)\n", + ev_value_to_name(event), errno_names[errno]); + } + return (-1); + } + + if (dm_get_eventlist(sid, hanp, hlen, token, + DM_EVENT_MAX, &check_eventset, &nelemp)) { + if (Vflag){ + fprintf(stdout, "dm_get_eventlist failed, %s\n", + errno_names[errno]); + } + return (-2); + } + + /* For each element, see that get_eventlist agrees + * with set_eventlist; if not, make noise. + */ + for (i = 0; i < ev_namecnt; i++) { + int set = DMEV_ISSET(ev_names[i].value, eventset); + int found = DMEV_ISSET(ev_names[i].value, check_eventset); + if (set && !found) { + fprintf(stderr, "ERROR: event %s was set but not found.\n", + ev_names[i].name); + return (-3); + } + else if (!set && found) { + fprintf(stderr, "ERROR: Found unexpected event %s \n", + ev_names[i].name); + return (-4); + } + else if ((Vflag == 2) && !set && !found) { + fprintf(stderr, "clear: %s\n", + ev_names[i].name); + } + else if (Vflag && set && found) { + fprintf(stderr, " SET: %s\n", ev_names[i].name); + set_count++; + } + } + if (Vflag && set_count == 0) { + fprintf(stderr, "\t(All events cleared)\n"); + } + return 0; +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/test_fileattr.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/test_fileattr.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/test_fileattr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/test_fileattr.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,715 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + + +/*--------------------------------------------------------------------------- +Automated test of the DMAPI functions: + dm_set_fileattr() + dm_get_fileattr() + dm_get_bulkattr() + dm_get_dirattrs() + +The command line is: + test_fileattr [-s sid] [-n num_files] [-v] ls_path pathname + +where: + sid + is the session ID whose events you you are interested in. + num_files + is the number of test files to create. + ls_path + is the path to a copy of ls, which will be copied as a test file. + pathname + is the filesystem to use for the test. +----------------------------------------------------------------------------*/ + +#define SET_MASK DM_AT_ATIME|DM_AT_MTIME|DM_AT_CTIME|DM_AT_DTIME|\ + DM_AT_UID|DM_AT_GID|DM_AT_MODE|DM_AT_SIZE + +#define GET_MASK DM_AT_EMASK|DM_AT_PMANR|DM_AT_PATTR|\ + DM_AT_DTIME|DM_AT_CFLAG|DM_AT_STAT + +extern int optind; +extern int opterr; +extern char *optarg; + +char *Progname; +int Vflag=0; + + +int +comp_stat ( dm_stat_t expected, + dm_stat_t found, + int i) +{ + int good=0; + if (found.dt_mode != expected.dt_mode) { + fprintf(stderr, + "ERROR: get #%d, expected mode %ld, but found %ld\n", + i, (long)expected.dt_mode, (long)found.dt_mode); + } + else good++; + if (found.dt_uid != expected.dt_uid) { + fprintf(stderr, + "ERROR: get #%d, expected uid %ld, but found %ld\n", + i, (long)expected.dt_uid, (long)found.dt_uid); + } + else good++; + if (found.dt_gid != expected.dt_gid) { + fprintf(stderr, + "ERROR: get #%d, expected gid %ld, but found %ld\n", + i, (long)expected.dt_gid, (long)found.dt_gid); + } + else good++; + if (found.dt_atime != expected.dt_atime) { + fprintf(stderr, + "ERROR: get #%d, expected atime %ld, but found %ld\n", + i, expected.dt_atime, found.dt_atime); + } + else good++; + if (found.dt_mtime != expected.dt_mtime) { + fprintf(stderr, + "ERROR: get #%d, expected mtime %ld, but found %ld\n", + i, expected.dt_mtime, found.dt_mtime); + } + else good++; + if (found.dt_ctime != expected.dt_ctime) { + fprintf(stderr, + "ERROR: get #%d, expected ctime %ld, but found %ld\n", + i, expected.dt_ctime, found.dt_ctime); + } + else good++; + + /* NOTE: dtime gets set to ctime */ + + if (found.dt_dtime != expected.dt_ctime) { + fprintf(stderr, + "ERROR: get #%d, expected dtime %ld, but found %ld\n", + i, expected.dt_ctime, found.dt_dtime); + } + else good++; + if (found.dt_size != expected.dt_size) { + fprintf(stderr, + "ERROR: get #%d, expected size %lld, but found %lld\n", + i, expected.dt_size, found.dt_size); + } + else good++; + if (Vflag){ + if (good==8) { + fprintf(stderr, "report: get #%d had no errors.\n",i); + } else { + fprintf(stderr, "report: %d tests correct for get #%d.\n", + good, i); + } + } + return(good); +} + + +static void +usage(void) +{ + fprintf(stderr, + "Usage: %s [-v] [-s sid] [-n num_files] ls_path pathname\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t test_token = DM_NO_TOKEN; + void *hanp; + size_t hlen; + char *ls_path; + char *pathname; + char test_file[100]; + char command[100]; + int num_files=50; + dm_stat_t *stat_arr; + dm_stat_t dmstat; + dm_fileattr_t fileattr; + char *name; + int opt; + int oops=1; + int i=0; + dm_attrloc_t loc; + size_t buflen = 16*sizeof(dm_stat_t); + size_t rlen; + void *bufp; + dm_stat_t *statbuf; + int loops=0; + void *fs_hanp; + size_t fs_hlen; + void *targhanp; + size_t targhlen; + char check_name[100]; + char *chk_name_p; + int chk_num; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + opterr = 0; + while ((opt = getopt(argc, argv, "vn:s:")) != EOF) { + switch (opt) { + case 'v': + Vflag++; + break; + case 'n': + num_files = atoi(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) { + usage(); + } + ls_path = argv[optind]; + pathname = argv[optind+1]; + + /* Seed the random number generator */ + srand((unsigned int)time(NULL)); + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Dynamically allocate stat_arr; */ + stat_arr = + (dm_stat_t *)malloc(num_files * sizeof(dm_stat_t)); + + printf("Beginning file attribute tests...\n"); + + /* Fill in the dm_stat blocks with lots of junk... + */ + for (i=0; i +#include + +#include +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Test program used to test the DMAPI function dm_punch_hole(). The +command line is: + + test_hole [-v] [-s sid] pathname + +where + ls_path + is the path to a specific copy of ls, important only for its size + pathname + is the path to the test filesystem + sid + is the session ID whose events you you are interested in. + +----------------------------------------------------------------------------*/ + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-v] [-s sid] ls_path directoryname\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *pathname = NULL; + char *ls_path = NULL; + dm_off_t offset = 0; + dm_off_t ex_off = 0; + dm_extent_t extent[20]; + u_int nelem; + dm_size_t length = 0; + void *hanp; + size_t hlen; + dm_token_t test_token; + char *name; + int opt; + int Vflag = 0; + char filename[128]; + char command[128]; + dm_off_t roff; + dm_size_t rlen; + dm_off_t blocksize = 5; + void *test_vp; + struct stat buf; + struct stat checkbuf; + + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "vs:")) != EOF) { + switch (opt) { + case 'v': + Vflag++; + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) + usage(); + ls_path = argv[optind]; + pathname = argv[optind+1]; + + if (dm_init_service(&name) == -1) { + fprintf(stdout, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get the directory handle. */ + + if (dm_path_to_handle(pathname, &hanp, &hlen)) { + fprintf(stdout, + "ERROR: can't get handle for directory %s\n", pathname); + exit(1); + } + + printf("Hole test beginning...\n"); + sprintf(filename, "%s/VeryLongUnlikelyFilename.HOLETEST", pathname); + sprintf(command, "cp %s %s \n", ls_path, filename); + system(command); + + if (dm_path_to_handle(filename, &hanp, &hlen)) { + fprintf(stdout, "can't get handle for %s\n; aborting test", + filename); + + sprintf(command, "rm %s \n", filename); + system(command); + fprintf(stdout, "\tHole test aborted.\n"); + + dm_handle_free(hanp, hlen); + exit(1); + } + + /* ## Get the block size using a length-1 probe. ## */ + dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 1, 0, + &blocksize, &rlen); + + if (blocksize==0) { + fprintf(stdout, "Error: block size appears to be 0!\n"); + + sprintf(command, "rm %s \n", filename); + system(command); + fprintf(stdout, "\tHole test aborted.\n"); + + dm_handle_free(hanp, hlen); + exit(1); + } + + /* Check that dm_probe_hole returns an extent from the next + * highest multiple of the block size, to the end of the file + */ + for (offset = 0; offset < 29604; offset++) { + if (dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length, + &roff, &rlen)) { + fprintf(stdout, "dm_probe_hole failed on pass %lld (%s)\n", + (long long)offset, ERR_NAME); + } + else { + if (rlen != 0) { + fprintf(stdout, + "Error: hole did not extend to end of file!\n"); + } + if (blocksize*(roff/blocksize) != roff) { + fprintf(stdout, + "Error: offset not a multiple of block size!\n"); + } + } + } + + /* Be sure dm_punch_hole doesn't change the time stamp, + * and verify that dm_get_allocinfo shows a hole + * followed by an extent to the end of the file. + */ + for(offset = 28672; offset > 0; offset-=blocksize) { + if (stat(filename, &buf)){ + fprintf(stdout, + "Error: unable to stat the test file; %s (1st)\n", + filename); + continue; + } + if (dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length, + &roff, &rlen)) { + fprintf(stdout, "dm_probe_hole failed, %s\n", + ERR_NAME); + continue; + } + if (roff != offset) { + fprintf(stdout, + "Error: presumed offset was not %lld.\n", + (long long)(roff)); + } + if (dm_punch_hole(sid, hanp, hlen, DM_NO_TOKEN, + roff, length)) { + fprintf(stdout, "dm_punch_hole failed, %s\n", + ERR_NAME); + continue; + } + if (stat(filename, &checkbuf)){ + fprintf(stdout, + "Error: unable to stat the test file. (2nd)\n"); + continue; + } + else { + /* COMPARE BUF AND CHECKBUF! */ +#ifdef linux + if ((buf.st_atime == checkbuf.st_atime) && + (buf.st_mtime == checkbuf.st_mtime) && + (buf.st_ctime == checkbuf.st_ctime)) +#else + if ((buf.st_atim.tv_sec == checkbuf.st_atim.tv_sec) && + (buf.st_atim.tv_nsec == checkbuf.st_atim.tv_nsec) && + (buf.st_mtim.tv_sec == checkbuf.st_mtim.tv_sec) && + (buf.st_mtim.tv_nsec == checkbuf.st_mtim.tv_nsec) && + (buf.st_ctim.tv_sec == checkbuf.st_ctim.tv_sec) && + (buf.st_ctim.tv_nsec == checkbuf.st_ctim.tv_nsec)) +#endif + { + if (Vflag) { + fprintf(stdout, + "\tTime stamp unchanged by hole from offset %lld.\n", + (long long)(offset)); + } + } + else { + fprintf(stdout, + "Error: punch_hole changed file's time stamp.\n"); + } + ex_off=0; + if ((dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN, + &ex_off, 1, extent, &nelem) == 1) && + (extent->ex_type == DM_EXTENT_RES) && + (dm_get_allocinfo(sid, hanp, hlen, DM_NO_TOKEN, + &ex_off, 1, extent, &nelem) == 0) && + (extent->ex_type == DM_EXTENT_HOLE)) { + if (extent->ex_offset == roff){ + if (Vflag) { + fprintf(stdout, "\tVerified hole at %lld\n", + (long long)(extent->ex_offset)); + } + } + else { + fprintf(stdout, "\tError: get_allocinfo found hole at %lld\n", + (long long)(extent->ex_offset)); + } + } + else { + fprintf(stdout, "\tError: get_allocinfo did not find an " + "extent followed by a hole!\n"); + } + } + } + /*------------------------*\ + |* ## Errno subtests ## *| + \*------------------------*/ + fprintf(stdout, "\t(beginning errno subtests...)\n"); + /*---------------------------------------------------------*/ + ERRTEST(E2BIG, + "probe (from past EOF)", + dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 30000, length, + &roff, &rlen)) + /*---------------------------------------------------------*/ +#if 0 + PROBLEM: No error is produced. + off+len >= filesize should produce E2BIG... + + ERRTEST(E2BIG, + "probe (to past EOF)", + dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, 15000, 150000, + &roff, &rlen)) +#endif + /*---------------------------------------------------------*/ + SHAREDTEST("probe", hanp, hlen, test_token, + dm_probe_hole(sid, hanp, hlen, test_token, + 0, 0, &roff, &rlen)) + /*---------------------------------------------------------*/ + EXCLTEST("punch", hanp, hlen, test_token, + dm_punch_hole(sid, hanp, hlen, test_token, 0, 0)) + /*---------------------------------------------------------*/ + ERRTEST(EAGAIN, + "punch", + dm_punch_hole(sid, hanp, hlen, DM_NO_TOKEN, + 1, length)) + /*---------------------------------------------------------*/ + if ((test_vp = handle_clone(hanp, hlen)) == NULL) { + fprintf(stderr, + "Cannot create a test handle (%s); skipping EBADF test\n", + ERR_NAME); + } + else { + ((char *) test_vp)[hlen/2]++; + ERRTEST(EBADF, + "probe", + dm_probe_hole(sid, test_vp, hlen, DM_NO_TOKEN, + offset, length, + &roff, &rlen)) + ERRTEST(EBADF, + "punch", + dm_punch_hole(sid, test_vp, hlen, DM_NO_TOKEN, + offset, length)) + } + dm_handle_free(test_vp, hlen); + /*---------------------------------------------------------*/ + ERRTEST(EFAULT, + "probe (null handle)", + dm_probe_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length, + &roff, &rlen)) + ERRTEST(EFAULT, + "probe (bad rlen)", + dm_probe_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length, + &roff, (dm_size_t*)(-1000))) + ERRTEST(EFAULT, + "probe (bad roff)", + dm_probe_hole(sid, hanp, hlen, DM_NO_TOKEN, offset, length, + (dm_off_t*)(-1000), &rlen)) + /*---------------------------------------------------------*/ + ERRTEST(EFAULT, + "punch", + dm_punch_hole(sid, 0, hlen, DM_NO_TOKEN, offset, length)) + /*---------------------------------------------------------*/ + ERRTEST(EINVAL, + "probe (bad session)", + dm_probe_hole(-100, hanp, hlen, DM_NO_TOKEN, offset, length, + &roff, &rlen)) + /*---------------------------------------------------------*/ + ERRTEST(EINVAL, + "probe (bad token)", + dm_probe_hole(sid, hanp, hlen, 0, offset, length, + &roff, &rlen)) + /*---------------------------------------------------------*/ + ERRTEST(EINVAL, + "probe (bad token 2)", + dm_probe_hole(sid, hanp, hlen, 0, offset, length, + &roff, &rlen)) + /*---------------------------------------------------------*/ + fprintf(stdout, "\t(errno subtests complete)\n"); + + + sprintf(command, "rm %s \n", filename); + system(command); + printf("Hole test complete.\n"); + + dm_handle_free(hanp, hlen); + exit(0); +} + diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/test_invis.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/test_invis.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/test_invis.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/test_invis.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,507 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include + +#include +#include + +#include +#include +#include + +/*--------------------------------------------------------------------------- + +Automated test of the DMAPI functions dm_write_invis() and dm_read_invis() + +The command line is: + + test_invis [-s sid] [-v] ls_path pathname + +where: + sid + is the session ID whose events you you are interested in. + ls_path + is the path to a specific copy of ls, important only for its size + pathname + is the filesystem to use for the test. + +DM_WRITE_SYNC is is not supported. +----------------------------------------------------------------------------*/ + +#define OFF_MAX 50 +#define OFF_STEP 5 +#define LEN_MAX 50 +#define LEN_STEP 5 + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-v] [-s sid] ls_path pathname\n", + Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_sessid_t sid = DM_NO_SESSION; + char *dir_name = NULL; + char *ls_path = NULL; + dm_off_t offset = 0; + dm_size_t length = 1; + dm_size_t curlength = 0; + u_char ch; + void *bufp = NULL; + void *hanp; + size_t hlen; + dm_ssize_t rc; + char *name; + char test_file[128]; + char command[128]; + int opt; + int i; + int j; + int k; + int Vflag=0; + struct stat statbuf; + struct stat checkbuf; + dm_token_t test_token; + void* test_vp; + int cont; + int error_reported; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "vs:")) != EOF) { + switch (opt) { + case 'v': + Vflag++; + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) + usage(); + ls_path = argv[optind]; + dir_name = argv[optind+1]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /* Get a random character for read/write tests */ + srand((unsigned int)time(NULL)); + ch = (char)rand(); + + printf("Invisible read/write tests beginning...\n"); + + /* File creation loop*/ + for(i=0; i (b) ? (a) : (b)) + length = max((dm_size_t)(i), length); + offset = (dm_off_t)(j); + + sprintf(test_file, "%s/DMAPI_invis_test_file.%02d%02d", + dir_name, i, j); + + if (stat(test_file, &statbuf)){ + fprintf(stdout, + "Error: unable to stat test file; %s (before test)\n", + test_file); + continue; + } + + if (dm_path_to_handle(test_file, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for %s; bypassing test\n", + test_file); + continue; + } + + if (length > curlength) { + if(curlength>0) + free(bufp); + if ((bufp = malloc(length)) == NULL) { + fprintf(stderr, "malloc of %llu bytes failed\n", length); + continue; + } + curlength = length; + memset(bufp, ch, length); + } + + rc = dm_write_invis(sid, hanp, hlen, DM_NO_TOKEN, + 0, offset, length, bufp); + cont = 0; + if (rc < 0) { + fprintf(stderr, "dm_write_invis failed, %s\n", ERR_NAME); + cont=1; + } else if (rc != length) { + fprintf(stderr, "expected to write %lld bytes, actually " + "wrote %lld\n", length, rc); + cont=1; + } + if(cont) + continue; + + /* Timestamp checking, part 1 */ + if (stat(test_file, &checkbuf)){ + fprintf(stdout, + "Error: unable to stat the test file; %s (after write)\n", + test_file); + } + else { +#ifdef __sgi + if ((statbuf.st_atim.tv_sec == checkbuf.st_atim.tv_sec) && + (statbuf.st_atim.tv_nsec == checkbuf.st_atim.tv_nsec) && + (statbuf.st_mtim.tv_sec == checkbuf.st_mtim.tv_sec) && + (statbuf.st_mtim.tv_nsec == checkbuf.st_mtim.tv_nsec) && + (statbuf.st_ctim.tv_sec == checkbuf.st_ctim.tv_sec) && + (statbuf.st_ctim.tv_nsec == checkbuf.st_ctim.tv_nsec)) +#else + if ((statbuf.st_atime == checkbuf.st_atime) && + (statbuf.st_mtime == checkbuf.st_mtime) && + (statbuf.st_ctime == checkbuf.st_ctime)) +#endif + { + if (Vflag) { + printf("Report: time stamp unchanged by write\n"); + } + } + else { + printf("Error: time stamp changed by write\n"); + } + } + + rc = dm_read_invis(sid, hanp, hlen, DM_NO_TOKEN, + offset, length, bufp); + if (rc < 0) { + fprintf(stderr, "dm_read_invis failed, %s\n", ERR_NAME); + continue; + } + else if (rc != length) { + fprintf(stderr, "expected to read %lld bytes, actually " + "wrote %lld\n", length, rc); + continue; + } + else { + /* Be sure the buffer is filled with the test char */ + error_reported = 0; + for (k=0; k + +#include +#include + +#include +#include + + +/*--------------------------------------------------------------------------- + +Automated test of the DMAPI functions dm_set_region() and dm_get_region(). + +The command line is: + + test_region [-s sid] ls_path directory + +where + pathname + is the name of a file + ls_path + is the path to a specific copy of ls, important only for its size + sid + is the session ID whose events you you are interested in. +----------------------------------------------------------------------------*/ + +#define NELEM 1 + +#ifndef linux +extern char *sys_errlist[]; +#endif +extern int optind; +extern char *optarg; + + +char *Progname; + + +u_int reg_flags[8] = {DM_REGION_NOEVENT, + DM_REGION_READ, + DM_REGION_WRITE, + DM_REGION_TRUNCATE, + DM_REGION_READ | DM_REGION_WRITE, + DM_REGION_READ | DM_REGION_TRUNCATE, + DM_REGION_WRITE | DM_REGION_TRUNCATE, + DM_REGION_READ | DM_REGION_WRITE | DM_REGION_TRUNCATE}; + + + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s [-s sid] ls_path pathname\n", Progname); + exit(1); +} + + +int +main( + int argc, + char **argv) +{ + dm_region_t region = { 0, 0, 0 }; + dm_region_t checkregion = { 0, 0, 0 }; + dm_sessid_t sid = DM_NO_SESSION; + char *dir_name = NULL; + char *ls_path = NULL; + char object[128]; + char command[128]; + u_int exactflag; + u_int nelem_read = 0; + void *hanp; + size_t hlen; + char *name; + int opt; + int i; + int Vflag = 0; + dm_token_t test_token = DM_NO_TOKEN; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + /* Crack and validate the command line options. */ + + while ((opt = getopt(argc, argv, "vo:l:s:")) != EOF) { + switch (opt) { + case 'v': + Vflag++; + break; + case 'o': + region.rg_offset = atol(optarg); + break; + case 'l': + region.rg_size = atol(optarg); + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 > argc) + usage(); + ls_path = argv[optind]; + dir_name = argv[optind+1]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + /***********************************************\ + |* Beginning the testing of set/get_region... *| + \***********************************************/ + + printf("Region test beginning...\n"); + sprintf(object, "%s/VeryLongUnlikelyFilename.REGIONTEST", dir_name); + sprintf(command, "cp %s %s \n", ls_path, object); + system(command); + + /* Get the test file's handle. */ + if (dm_path_to_handle(object, &hanp, &hlen)) { + fprintf(stderr, "can't get handle for file %s\n", object); + exit(1); + } + /* Loop over all possible region flag combinations, + * setting and getting. See what works! + */ + for (i = 0; i < 8; i++) { + region.rg_flags = reg_flags[i]; + if (dm_set_region(sid, hanp, hlen, DM_NO_TOKEN, NELEM, + ®ion, &exactflag)) { + fprintf(stderr, "dm_set_region failed, %s\n", + ERR_NAME); + continue; + } + if (exactflag != DM_TRUE){ + fprintf(stdout, "oops...exactflag was false!\n"); + } + if (dm_get_region(sid, hanp, hlen, DM_NO_TOKEN, NELEM, + &checkregion, &nelem_read)) { + fprintf(stderr, "dm_get_region failed, %s\n", + ERR_NAME); + continue; + } + if (region.rg_flags != checkregion.rg_flags) { + fprintf(stdout, "set region flags %d, but found %d\n", + region.rg_flags, checkregion.rg_flags); + } + else if (Vflag) { + fprintf(stdout, "Test #%d okay\n", i); + } + } + + /*************************************\ + |* Correct-input testing complete. *| + |* Beginning improper-input testing. *| + \*************************************/ + printf("\t(errno subtests beginning...)\n"); + region.rg_flags = 7; + + /**** SET tests ****/ + /*---------------------------------------------------------*/ + ERRTEST(E2BIG, + "set", + dm_set_region(sid, hanp, hlen, DM_NO_TOKEN, + 2, ®ion, &exactflag)) + ERRTEST(E2BIG, + "set", + dm_set_region(sid, hanp, hlen, DM_NO_TOKEN, + -1, ®ion, &exactflag)) + /*---------------------------------------------------------*/ + EXCLTEST("set", hanp, hlen, test_token, + dm_set_region(sid, hanp, hlen, test_token, + NELEM, ®ion, &exactflag)) + /*---------------------------------------------------------*/ + ERRTEST(EFAULT, + "set", + dm_set_region(sid, hanp, hlen, DM_NO_TOKEN, + NELEM, (dm_region_t*)(-1000), &exactflag)) + ERRTEST(EFAULT, + "set", + dm_set_region(sid, hanp, hlen, DM_NO_TOKEN, + NELEM, ®ion, (dm_boolean_t*)(-1000))) + /*---------------------------------------------------------*/ + ERRTEST(EINVAL, + "set (bad session id)", + dm_set_region(-100, hanp, hlen, DM_NO_TOKEN, + NELEM, ®ion, &exactflag)) + /*---------------------------------------------------------*/ + + /**** GET tests ****/ + /*---------------------------------------------------------*/ + ERRTEST (E2BIG, + "get", + dm_get_region(sid, hanp, hlen, DM_NO_TOKEN, + 0, &checkregion, &nelem_read)) + /*---------------------------------------------------------*/ + ERRTEST(EFAULT, + "get (bad handle)", + dm_get_region(sid, NULL, hlen, DM_NO_TOKEN, + NELEM, &checkregion, &nelem_read)) + /*---------------------------------------------------------*/ + ERRTEST(EFAULT, + "get (bad regbufp)", + dm_get_region(sid, hanp, hlen, DM_NO_TOKEN, + NELEM, (dm_region_t *)(-1000), &nelem_read)) + /*---------------------------------------------------------*/ + ERRTEST(EFAULT, + "get (bad nelemp)", + dm_get_region(sid, hanp, hlen, DM_NO_TOKEN, + NELEM, &checkregion, (u_int *)(-1000))) + /*---------------------------------------------------------*/ + SHAREDTEST("get", hanp, hlen, test_token, + dm_get_region(sid, hanp, hlen, test_token, + NELEM, &checkregion, &nelem_read)) + /*---------------------------------------------------------*/ + ERRTEST(EINVAL, + "get", + dm_get_region(-100, hanp, hlen, DM_NO_TOKEN, + NELEM, &checkregion, &nelem_read)) + /*---------------------------------------------------------*/ + printf("\t(errno subtests complete)\n"); + /**********************************\ + |* End of improper-input testing. *| + \**********************************/ + + sprintf(command, "rm %s \n", object); + system(command); + printf("Region test complete.\n"); + + /***********************************\ + |* End of set/get_region testing. *| + \***********************************/ + + dm_handle_free(hanp, hlen); + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/test_rights.c linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/test_rights.c --- linux-2.4.7/cmd/xfstests/dmapi/src/suite2/src/test_rights.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/dmapi/src/suite2/src/test_rights.c Thu Mar 8 11:52:41 2001 @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +/*--------------------------------------------------------------------------- +Automated test of access rights, involving many DMAPI functions + +The command line is: + test_rights [-s sid] [-v] ls_path pathname + +where: + sid + is the session ID whose events you you are interested in. + ls_path + is the path to a copy of ls, which will be copied as a test file. + pathname + is the filesystem to use for the test. +----------------------------------------------------------------------------*/ + +#define NUM_TOKENS 4 + +extern int optind; +extern int opterr; +extern char *optarg; + +char *Progname; +int Vflag=0; + +static void +usage(void) +{ + fprintf(stderr, + "Usage: %s [-v] [-s sid] ls_path pathname\n", + Progname); + exit(1); +} + + +int +main(int argc, char **argv) { + + dm_sessid_t sid = DM_NO_SESSION; + dm_token_t token[NUM_TOKENS]; + dm_token_t test_token; + void *fs_hanp; + size_t fs_hlen; + void *dir_hanp; + size_t dir_hlen; + void *ap; + size_t alen; + void *bp; + size_t blen; + void *cp; + size_t clen; + char *name; + char *ls_path; + char *pathname; + char fname_a[100]; + char fname_b[100]; + char fname_c[100]; + char command[150]; + int opt; + int i=0; + + if (Progname = strrchr(argv[0], '/')) { + Progname++; + } else { + Progname = argv[0]; + } + + opterr = 0; + while ((opt = getopt(argc, argv, "vn:s:")) != EOF) { + switch (opt) { + case 'v': + Vflag++; + break; + case 's': + sid = atol(optarg); + break; + case '?': + usage(); + } + } + if (optind + 2 != argc) { + usage(); + } + ls_path = argv[optind]; + pathname = argv[optind+1]; + + if (dm_init_service(&name) == -1) { + fprintf(stderr, "Can't inititalize the DMAPI\n"); + exit(1); + } + if (sid == DM_NO_SESSION) + find_test_session(&sid); + + printf("Beginning access rights testing...\n"); + + sprintf(fname_a, "%s/DMAPI_rights_test_file_a", pathname); + sprintf(command, "cp %s %s\n", ls_path, fname_a); + system(command); + + if (dm_path_to_handle(fname_a, &ap, &alen)) { + fprintf(stderr, "ERROR: can't get handle for %s; %s\n", + fname_a, ERR_NAME); + goto abort_test; + } + + sprintf(fname_b, "%s/DMAPI_rights_test_file_b", pathname); + sprintf(command, "cp %s %s\n", ls_path, fname_b); + system(command); + + if (dm_path_to_handle(fname_b, &bp, &blen)) { + fprintf(stderr, "ERROR: can't get handle for %s; %s\n", + fname_b, ERR_NAME); + goto abort_test; + } + + sprintf(fname_c, "%s/DMAPI_rights_test_file_c", pathname); + sprintf(command, "cp %s %s\n", ls_path, fname_c); + system(command); + + if (dm_path_to_handle(fname_c, &cp, &clen)) { + fprintf(stderr, "ERROR: can't get handle for %s; %s\n", + fname_c, ERR_NAME); + goto abort_test; + } + + if (dm_path_to_fshandle(pathname, &fs_hanp, &fs_hlen)) { + fprintf(stderr, "ERROR: can't get handle for %s; %s\n", + pathname, ERR_NAME); + goto abort_test; + } + + sprintf(pathname, "%s/DMAPI_rights_test_dir", pathname); + sprintf(command, "mkdir %s\n", pathname); + system(command); + + if (dm_path_to_handle(pathname, &dir_hanp, &dir_hlen)) { + fprintf(stderr, "ERROR: can't get handle for %s; %s\n", + pathname, ERR_NAME); + goto abort_test; + } + + /* Test remaining functions for appropriate + * right requirements... + *------------------------------------------------------------*/ + { + dm_off_t off = (dm_off_t)0; + dm_extent_t extent; + u_int nelem_ret; + SHAREDTEST("get_allocinfo", ap, alen, test_token, + dm_get_allocinfo(sid, ap, alen, test_token, + &off, 1, &extent, &nelem_ret)) + } + /*------------------------------------------------------------*/ + { + void *bufp=(void*)malloc(5*sizeof(dm_attrlist_t)); + size_t rlen; + SHAREDTEST("getall_dmattr", ap, alen, test_token, + dm_getall_dmattr(sid, ap, alen, test_token, + 5, bufp, &rlen)) + } + /*------------------------------------------------------------*/ + { + dm_attrloc_t loc; + SHAREDTEST("init_attrloc", dir_hanp, dir_hlen, test_token, + dm_init_attrloc(sid, dir_hanp, dir_hlen, test_token, + &loc)) + } + /*------------------------------------------------------------*/ +#if 0 + mkdir_by_handle is NOT SUPPORTED in current SGI DMAPI + + { + SHAREDTEST("mkdir_by_handle", fs_hanp, fs_hlen, test_token, + dm_mkdir_by_handle(sid, fs_hanp, fs_hlen, test_token, + dir_hanp, dir_hlen, "FUBAR_DIR")) + } +#endif + /*------------------------------------------------------------*/ + { dm_eventset_t eventset; + DMEV_ZERO(eventset); + EXCLTEST("set_disp", fs_hanp, fs_hlen, test_token, + dm_set_disp(sid, fs_hanp, fs_hlen, test_token, + &eventset, DM_EVENT_MAX)) + } + /*------------------------------------------------------------*/ + { dm_attrname_t attrname={"TEST"}; + EXCLTEST("set_return...", fs_hanp, fs_hlen, test_token, + dm_set_return_on_destroy(sid, fs_hanp, fs_hlen, test_token, + &attrname, DM_TRUE)) + } + /*------------------------------------------------------------*/ + + /* Create the tokens */ + for (i=1; i $$f.gz; \ + fi; \ + done + +INSTALL_MAN = \ + @for d in $(MAN_PAGES); do \ + first=true; \ + for m in `$(AWK) '/^\.SH NAME/ {ok=1; next} ok {print; exit}' $$d \ + | sed -e 's/,/ /g' -e 's/\\-.*//' -e 's/\\\f[0-9]//g' -e 's/ / /g;q'`; \ + do \ + [ -z "$$m" -o "$$m" = "\\" ] && continue; \ + t=$(MAN_DEST)/$$m.$(MAN_SECTION); \ + if $$first; then \ + if $(HAVE_ZIPPED_MANPAGES); then \ + $(ZIP) --best -c $$d > $$d.gz; _sfx=.gz; \ + fi; \ + u=$$m.$(MAN_SECTION)$$_sfx; \ + echo $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ + $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \ + else \ + echo $(INSTALL) -S $$u $${t}$$_sfx; \ + $(INSTALL) -S $$u $${t}$$_sfx; \ + fi; \ + first=false; \ + done; \ + done + +DIST_MAKERULE = \ + $(MAKEF) -C build dist + +SOURCE_MAKERULE = \ + @test -z "$$DIR" && DIR="."; \ + for f in $(SRCFILES) ""; do \ + if test ! -z "$$f"; then $(ECHO) $$DIR/$$f; fi;\ + done; \ + for d in `echo $(SUBDIRS)` ; do \ + if test -d "$$d" -a ! -z "$$d"; then \ + $(MAKEF) DIR=$$DIR/$$d -C $$d $@ || exit $$?; \ + fi; \ + done + +endif + +# +# For targets that should always be rebuilt, +# define a target that is never up-to-date. +# Targets needing this should depend on $(_FORCE) +_FORCE = __force_build diff -rNu linux-2.4.7/cmd/xfstests/include/buildrules linux-2.4-xfs/cmd/xfstests/include/buildrules --- linux-2.4.7/cmd/xfstests/include/buildrules Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/include/buildrules Mon Jan 15 22:10:42 2001 @@ -0,0 +1,77 @@ +# +# Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as published +# by the Free Software Fondation. +# +# This program is distributed in the hope that it would be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. Further, any license provided herein, +# whether implied or otherwise, is limited to this program in accordance with +# the express provisions of the GNU General Public License. Patent licenses, +# if any, provided herein do not apply to combinations of this program with +# other product or programs, or any other product whatsoever. This program is +# distributed without any warranty that the program is delivered free of the +# rightful claim of any third person by way of infringement or the like. See +# the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write the Free Software Foundation, Inc., 59 Temple +# Place - Suite 330, Boston MA 02111-1307, USA. +# Common build rules for gmake +# +ifndef _BUILDRULES_INCLUDED_ +_BUILDRULES_INCLUDED_ = 1 + +include $(TOPDIR)/include/builddefs + +# +# Standard targets +# +ifdef CMDTARGET +$(CMDTARGET) : $(SUBDIRS) $(OBJECTS) + $(CCF) -o $(CMDTARGET) $(LDFLAGS) $(OBJECTS) $(LDLIBS) +$(CMDTARGET).static : $(SUBDIRS) $(OBJECTS) + $(CCF) -static -o $(CMDTARGET).static $(LDFLAGS) $(OBJECTS) $(LDLIBS) +endif + +ifdef LIBTARGET +$(LIBTARGET) : $(SUBDIRS) $(OBJECTS) + $(CC) $(LDFLAGS) -fPIC -shared -Wl,-soname,$(LIBTARGET) -o $(LIBTARGET) $(OBJECTS) $(LDLIBS) +endif + +ifdef STATICLIBTARGET +$(STATICLIBTARGET) : $(SUBDIRS) $(OBJECTS) + $(AR) crf $(STATICLIBTARGET) $? +endif + +clean clobber : $(SUBDIRS) + rm -f $(DIRT) + $(SUBDIRS_MAKERULE) + +# Never blow away subdirs +ifdef SUBDIRS +.PRECIOUS: $(SUBDIRS) +$(SUBDIRS): + $(SUBDIRS_MAKERULE) +endif + +source : + $(SOURCE_MAKERULE) + +endif + +$(_FORCE): + +.PHONY : depend + +depend : $(CFILES) $(HFILES) + $(SUBDIRS_MAKERULE) + touch dep + $(MAKEDEPEND) -fdep -- $(CFLAGS) -- $(CFILES) + +# Include dep, but only if it exists +ifeq ($(shell test -f dep && echo dep), dep) +include dep +endif diff -rNu linux-2.4.7/cmd/xfstests/install-sh linux-2.4-xfs/cmd/xfstests/install-sh --- linux-2.4.7/cmd/xfstests/install-sh Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/install-sh Thu Jan 18 20:33:50 2001 @@ -0,0 +1,273 @@ +#! /bin/sh +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +# +# This script emulates bsd install and also recognises +# two environment variables, with the following semantics :- +# +# $DIST_MANIFEST - if set, the name of the file to append manifest +# information in the following format: +# File : f mode owner group src target +# Directory: d mode owner group target +# Symlink : l linkval target +# +# $DIST_ROOT - if set, prepend to target +# +# The sematics of all combinations of these two variables +# are as follows: +# +# $DIST_MANIFEST? $DIST_ROOT? | Copy? Append Manifest? +# -----------------------------+-------------------------- +# not set not set | yes no +# not set set | yes no +# set not set | no yes +# set set | yes yes +# +_usage() { + echo "Usage: $prog [-o owner] [-g group] [-m mode] -d directory" + echo "or $prog [-D] [-o owner] [-g group] [-m mode] file directory/file" + echo "or $prog [-o owner] [-g group] [-m mode] file [file ...] directory" + echo "or $prog -S file target (creates \"target\" symlink)" + echo "" + echo "The \$DIST_MANIFEST and \$DIST_ROOT environment variables affect the" + echo "behaviour of this command - see comments in the script." + echo "The -D flag is only available for the second usage, and causes" + echo "the target directory to be created before installing the file." + echo "" + exit 1 +} + +_chown () +{ + _st=255 + if [ $# -eq 3 ] ; then + chown $1:$2 $3 + _st=$? + if [ $_st -ne 0 ] ; then + if [ $REAL_UID != '0' ] ; then + if [ ! -f $DIST_ROOT/.chown.quite ] ; then + echo '===============================================' + echo Ownership of files under ${DIST_ROOT:-/} + echo cannot be changed + echo '===============================================' + if [ -n "$DIST_ROOT" ] ; then + touch $DIST_ROOT/.chown.quite + fi + fi + _st=0 + fi + fi + fi + + return $_st +} + + +_manifest () +{ + echo $* | sed -e 's/\/\//\//g' >>${DIST_MANIFEST:-/dev/null} +} + +prog=`basename $0` +HERE=`pwd` +dflag=false +Dflag=false +Sflag=false +DIRMODE=755 +FILEMODE=644 +OWNER=`id -u` +GROUP=`id -g` +REAL_UID=$OWNER + +# default is to install and don't append manifest +INSTALL=true +MANIFEST=: + +[ -n "$DIST_MANIFEST" -a -z "$DIST_ROOT" ] && INSTALL=false +[ -n "$DIST_MANIFEST" ] && MANIFEST="_manifest" + +[ $# -eq 0 ] && _usage + +if $INSTALL +then + CP=cp; LN=ln; MKDIR=mkdir; CHMOD=chmod; CHOWN=_chown +else + CP=true; LN=true; MKDIR=true; CHMOD=true; CHOWN=true +fi + +[ -n "$DIST_ROOT" -a $REAL_UID -ne 0 ] && CHOWN=true + +while getopts "Dcm:d:S:o:g:" c $* +do + case $c in + c) + ;; + g) + GROUP=$OPTARG + ;; + o) + OWNER=$OPTARG + ;; + m) + DIRMODE=`expr $OPTARG` + FILEMODE=$DIRMODE + ;; + D) + Dflag=true + ;; + S) + symlink=$OPTARG + Sflag=true + ;; + d) + dir=$DIST_ROOT/$OPTARG + dflag=true + ;; + *) + _usage + ;; + esac +done + +shift `expr $OPTIND - 1` + +status=0 +if $dflag +then + # + # first usage + # + $MKDIR -p $dir + status=$? + if [ $status -eq 0 ] + then + $CHMOD $DIRMODE $dir + status=$? + fi + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir + status=$? + fi + $MANIFEST d $DIRMODE $OWNER $GROUP ${dir#$DIST_ROOT} +elif $Sflag +then + # + # fourth usage (symlink) + # + if [ $# -ne 1 ] + then + _usage + else + target=$DIST_ROOT/$1 + fi + $LN -s -f $symlink $target + status=$? + $MANIFEST l $symlink ${target#$DIST_ROOT} +else + list="" + dir="" + if [ $# -eq 2 ] + then + # + # second usage + # + f=$1 + dir=$DIST_ROOT/$2 + if $Dflag + then + mkdir -p `dirname $dir` + fi + $CP $f $dir + status=$? + if [ $status -eq 0 ] + then + if [ -f $dir/$f ] + then + $CHMOD $FILEMODE $dir/$f + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir/$f + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f + else + $CHMOD $FILEMODE $dir + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$dir ${dir#$DIST_ROOT} + fi + fi + else + # + # third usage + # + n=1 + while [ $# -gt 0 ] + do + if [ $# -gt 1 ] + then + list="$list $1" + else + dir=$DIST_ROOT/$1 + fi + shift + done + + # echo DIR=$dir list=\"$list\" + for f in $list + do + $CP $f $dir + status=$? + if [ $status -eq 0 ] + then + $CHMOD $FILEMODE $dir/$f + status=$? + if [ $status -eq 0 ] + then + $CHOWN $OWNER $GROUP $dir/$f + status=$? + fi + $MANIFEST f $FILEMODE $OWNER $GROUP $HERE/$f ${dir#$DIST_ROOT}/$f + fi + [ $status -ne 0 ] && break + done + fi +fi + +exit $status diff -rNu linux-2.4.7/cmd/xfstests/new linux-2.4-xfs/cmd/xfstests/new --- linux-2.4.7/cmd/xfstests/new Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/new Sun Jan 14 23:01:19 2001 @@ -0,0 +1,209 @@ +#! /bin/sh +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# +# Make a new test +# +# $Header: /build2/depot/linux/pcp/dev/qa/RCS/new,v 2.22 1999/10/06 19:16:53 kenmcd Exp $ +# + +# generic initialization +iam=new +. ./common.rc + +trap "rm -f /tmp/$$.; exit" 0 1 2 3 15 + +_cleanup() +{ + : +} + +if [ ! -f group ] +then + echo "Creating the group index ..." + cat <<'End-of-File' >group +# QA groups control +# +# $Id: new,v 2.22 1999/10/06 19:16:53 kenmcd Exp $ +# +# define groups and default group owners +# do not start group name with a digit +# + +# catch-all +# +other some-user-login + +# test-group association ... one line per test +# +End-of-File +fi + +if [ ! -w group ] +then + chmod u+w group + echo "Warning: making the index file \"group\" writeable" +fi + +if make +then + : +else + echo "Warning: make failed -- some tests may be missing" +fi + +last=`grep '^[0-9][0-9]* ' group | sort | tail -1 | sed -e 's/[ ].*//'` +id=`$AWK_PROG $id +#! /bin/sh +# XFS QA Test No. $id +# \$rcsId\$ +# +# what am I here for? +# +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=$USER@`_get_fqdn` + +seq=\`basename \$0\` +echo "QA output created by \$seq" + +here=\`pwd\` +tmp=/tmp/\$\$ +status=1 # failure is the default! +trap "rm -f \$tmp.*; exit \\\$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +# real QA test starts here + +# if error +exit + +# optional stuff if your test has verbose output to help resolve problems +#echo +#echo "If failure, check \$seq.full (this) and \$seq.full.ok (reference)" + +# success, all done +status=0 +exit +End-of-File + +sleep 2 # latency to read messages to this point +echo "" + +chmod 755 $id +${EDITOR-vi} $id + +if [ $# -eq 0 ] +then + while true + do + echo -n "Add to group(s) [other] (? for list): " + read ans + [ -z "$ans" ] && ans=other + if [ "X$ans" = "X?" ] + then + $AWK_PROG /dev/null + then + : + else + echo "Warning: group \"$g\" not defined in ./group" + fi + done + ans="$*" +fi + +echo -n "Adding $id to group index ..." +echo "$id $ans" >>group +echo " done." + +exit 0 diff -rNu linux-2.4.7/cmd/xfstests/remake linux-2.4-xfs/cmd/xfstests/remake --- linux-2.4.7/cmd/xfstests/remake Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/remake Sun Jan 14 23:01:19 2001 @@ -0,0 +1,87 @@ +#! /bin/sh +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# +# Rebuild NNN.out files +# +# $Header: /build2/depot/linux/pcp/dev/qa/RCS/remake,v 2.11 1999/09/20 03:42:19 kenmcd Exp $ +# + +tmp=/tmp/$$ +trap "rm -f NO-PREVIOUS-OUTPUT $tmp.*; exit" 0 1 2 3 15 + +# generic initialization +iam=remake +. ./common.rc + +. ./common + +[ -f check.time ] || touch check.time + +for seq in $list +do + if [ ! -f $seq ] + then + echo "Remake: cannot find \"$seq\"" + else + echo -n "$seq" + lasttime=`sed -n -e "/^$seq /s/.* //p" $seq.new 2>&1 + then + if [ -f $seq.out ] + then + $diff $seq.out $seq.new + rm -f $seq.out.bad + else + touch NO-PREVIOUS-OUTPUT + $diff NO-PREVIOUS-OUTPUT $seq.new + rm -f NO-PREVIOUS-OUTPUT + fi + echo "" + [ -f $seq.out ] && mv $seq.out $seq.bak + if [ -f $seq.full ] + then + [ -f $seq.full.ok ] && mv $seq.full.ok $seq.full.bak + mv $seq.full $seq.full.ok + fi + mv $seq.new $seq.out + else + echo " - failed (exit status $?)" + sed 's/^/ /' $seq.new + exit 1 + fi + fi +done + +exit 0 diff -rNu linux-2.4.7/cmd/xfstests/soak linux-2.4-xfs/cmd/xfstests/soak --- linux-2.4.7/cmd/xfstests/soak Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/soak Sun Jan 14 23:01:19 2001 @@ -0,0 +1,152 @@ +#!/bin/sh +#----------------------------------------------------------------------- +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +#----------------------------------------------------------------------- +# +# creator +owner=dxm@sgi.com + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +tmp=/tmp/$$ +seq=soak +status=1 # failure is the default! + +_cleanup() +{ + echo " *** umount" + umount $SCRATCH_DEV >/dev/null 2>&1 +} + +trap "_cleanup; exit \$status" 0 1 2 3 15 + +ROOT="." +LOG="$ROOT/soak.log" +FULL="$ROOT/soak.full" + +_log() +{ + echo "$*" 1>&2 + echo "$*" >>$LOG + echo "$*" >>$FULL +} + +_logp() +{ + tee -a $FULL +} + +_fail() +{ + _log "$*" + status=1 + exit 1 +} + +_require_scratch + +passes=-1 +stress=100000 +proc=1 + +if [ $# -gt 0 ] +then + passes=$1 + if [ $# -gt 1 ] + then + stress=$2 + if [ $# -gt 2 ] + then + proc=$3 + fi + fi +fi + +echo "" >$FULL +echo "" >$LOG +_log "*** soak test started (passes=$passes, stress=$stress, proc=$proc)" +_log "*** (`date`)" + + +_log " *** init" +_log " *** unmounting scratch device" + +umount $SCRATCH_DEV 2>&1 | _fix_malloc >>$FULL + +_log " *** clean scratch device" + +mkfs -t xfs -f $SCRATCH_DEV 2>&1 | _fix_malloc >>$FULL \ + || _fail " !!! failed to mkfs SCRATCH_DEV" + +pass=1 + +while [ $pass -le $passes -o $passes -lt 0 ] +do + _log " *** pass $pass (`date`)" + + _log " *** check" + _check_fs $SCRATCH_DEV + + _log " *** mounting scratch device" + + if ! mount -t xfs $SCRATCH_DEV $SCRATCH_MNT 2>&1 | _logp + then + _fail " !!! failed to mount" + fi + + if [ $pass != 1 ] + then + _log " *** cleanup" + rm -rf $SCRATCH_MNT/soak_test \ + || _fail " !!! couldn't delete old dir" + + _log " *** check" + _check_fs $SCRATCH_DEV + fi + + _log " *** mkdir" + mkdir $SCRATCH_MNT/soak_test \ + || _fail " !!! couldn't delete old dir" + + _log " *** stress" + src/fsstress -d $SCRATCH_MNT/soak_test -p $proc -n $stress $FSSTRESS_AVOID 2>&1 | \ + _fix_malloc >>$FULL + + _log " *** unmounting scratch device" + + umount $SCRATCH_DEV 2>&1 | _logp \ + || _fail " !!! failed to umount" + + let "pass = pass + 1" +done + diff -rNu linux-2.4.7/cmd/xfstests/src/CVS/Entries linux-2.4-xfs/cmd/xfstests/src/CVS/Entries --- linux-2.4.7/cmd/xfstests/src/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/CVS/Entries Thu Jul 5 11:46:04 2001 @@ -0,0 +1,29 @@ +/Makefile/1.6/Tue May 29 07:08:24 2001/-ko/ +/acl_get.c/1.2/Wed Jun 13 01:49:41 2001/-ko/ +/acl_test.c/1.4/Wed Jun 20 05:19:09 2001/-ko/ +/alloc.c/1.2/Mon Mar 26 07:07:33 2001/-ko/ +/bstat.c/1.2/Wed May 9 07:03:16 2001/-ko/ +/dbtest.c/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/devzero.c/1.2/Wed May 9 07:03:16 2001/-ko/ +/dirstress.c/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/fault.c/1.2/Wed May 9 07:03:16 2001/-ko/ +/feature.c/1.3/Tue May 22 04:50:41 2001/-ko/ +/fill.c/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/fill2.c/1.3/Wed May 9 07:03:16 2001/-ko/ +/fill2attr/1.1/Fri Feb 9 04:00:02 2001/-ko/ +/fill2fs/1.4/Wed Apr 4 01:45:38 2001/-ko/ +/fill2fs_check/1.3/Thu Apr 26 23:48:06 2001/-ko/ +/fsstress.c/1.3/Mon Mar 5 20:18:45 2001/-ko/ +/global.h/1.2/Wed May 9 07:03:16 2001/-ko/ +/holes.c/1.2/Wed May 9 07:03:16 2001/-ko/ +/ioctl.c/1.2/Wed May 9 07:03:16 2001/-ko/ +/loggen.c/1.2/Wed May 9 07:03:16 2001/-ko/ +/lstat64.c/1.2/Mon Mar 26 07:07:33 2001/-ko/ +/nametest.c/1.3/Wed May 9 07:03:16 2001/-ko/ +/permname.c/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/randholes.c/1.2/Wed May 9 07:03:16 2001/-ko/ +/random.c/1.1/Mon Jan 15 05:01:19 2001/-ko/ +/runas.c/1.2/Tue Feb 20 08:07:09 2001/-ko/ +/truncfile.c/1.2/Wed May 9 07:03:16 2001/-ko/ +/usemem.c/1.1/Mon Jan 15 05:01:19 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/src/CVS/Repository linux-2.4-xfs/cmd/xfstests/src/CVS/Repository --- linux-2.4.7/cmd/xfstests/src/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/CVS/Repository Thu Jul 5 11:46:00 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/src diff -rNu linux-2.4.7/cmd/xfstests/src/CVS/Root linux-2.4-xfs/cmd/xfstests/src/CVS/Root --- linux-2.4.7/cmd/xfstests/src/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/CVS/Root Thu Jul 5 11:46:00 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/src/Makefile linux-2.4-xfs/cmd/xfstests/src/Makefile --- linux-2.4.7/cmd/xfstests/src/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/Makefile Tue May 29 02:08:24 2001 @@ -0,0 +1,89 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +TOPDIR = .. +include $(TOPDIR)/include/builddefs + +TARGETS = alloc acl_get acl_test bstat devzero dirstress fault feature \ + fsstress fill fill2 holes ioctl loggen lstat64 nametest permname \ + randholes runas truncfile usemem +ifeq ($(HAVE_DB), true) +TARGETS += dbtest +endif + +CFILES = $(TARGETS:=.c) random.c +HFILES = global.h +LDIRT = $(TARGETS) + +default: $(TARGETS) + +include $(BUILDRULES) + +install install-dev: default + +# binaries using non-default objects/libs need an entry below +# +RANDHOLES_OBJECTS = randholes.o random.o +randholes: $(HFILES) $(RANDHOLES_OBJECTS) + $(CCF) -o $@ $(LDFLAGS) $(RANDHOLES_OBJECTS) $(LDLIBS) + +TRUNCFILE_OBJECTS = truncfile.o random.o +truncfile: $(HFILES) $(TRUNCFILE_OBJECTS) + $(CCF) -o $@ $(LDFLAGS) $(TRUNCFILE_OBJECTS) $(LDLIBS) + +FSSTRESS_OBJECTS = fsstress.o random.o $(LIBATTR) +fsstress: $(HFILES) $(FSSTRESS_OBJECTS) + $(CCF) -o $@ $(LDFLAGS) $(FSSTRESS_OBJECTS) $(LDLIBS) + +DBTEST_OBJECTS = dbtest.o random.o +dbtest: $(HFILES) $(DBTEST_OBJECTS) + $(CCF) -o $@ $(LDFLAGS) $(DBTEST_OBJECTS) $(LIBGDBM) $(LDLIBS) + +NAMETEST_OBJECTS = nametest.o random.o +nametest: $(HFILES) $(NAMETEST_OBJECTS) + $(CCF) -o $@ $(LDFLAGS) $(NAMETEST_OBJECTS) $(LDLIBS) + +BSTAT_OBJECTS = bstat.o +bstat: $(HFILES) $(BSTAT_OBJECTS) + $(CCF) -o $@ $(LDFLAGS) $(BSTAT_OBJECTS) $(LIBHANDLE) $(LDLIBS) + +LOGGEN_OBJECTS = loggen.o $(LIBXFS) +loggen: $(HFILES) $(LOGGEN_OBJECTS) + $(CCF) -o $@ $(LDFLAGS) $(LOGGEN_OBJECTS) $(LDLIBS) + +ACLGET_OBJECTS = acl_get.o $(LIBACL) +acl_get: $(HFILES) $(ACLGET_OBJECTS) + $(CCF) -o $@ $(LDFLAGS) $(ACLGET_OBJECTS) $(LDLIBS) + +ACLTEST_OBJECTS = acl_test.o $(LIBACL) +acl_test: $(HFILES) $(ACLTEST_OBJECTS) + $(CCF) -o $@ $(LDFLAGS) $(ACLTEST_OBJECTS) $(LDLIBS) diff -rNu linux-2.4.7/cmd/xfstests/src/acl_get.c linux-2.4-xfs/cmd/xfstests/src/acl_get.c --- linux-2.4.7/cmd/xfstests/src/acl_get.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/acl_get.c Tue Jun 12 20:49:41 2001 @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This prog is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This prog is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this prog with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this prog; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Get an access or default acl on a file + * using IRIX semantics or Linux semantics + */ + +#include "global.h" + +#include +#include +#include +#include +#include + +char *prog; + +void usage(void) +{ + fprintf(stderr, "usage: %s [-a] [-d] [-f] [-i] path\n" + "flags:\n" + " -a - get access ACL\n" + " -d - get default ACL\n" + " -f - get access ACL using file descriptor\n" + " -i - use irix semantics\n" + ,prog); + +} + + + +int +main(int argc, char **argv) +{ + int c; + char *file; + int getaccess = 0; + int getdefault = 0; + int irixsemantics = 0; + int usefd = 0; + int fd = -1; + acl_t acl; + char *buf_acl; + + prog = basename(argv[0]); + + while ((c = getopt(argc, argv, "adif")) != -1) { + switch (c) { + case 'a': + getaccess = 1; + break; + case 'd': + getdefault = 1; + break; + case 'i': + irixsemantics = 1; + break; + case 'f': + usefd = 1; + break; + case '?': + usage(); + return 1; + } + } + + if (getdefault && usefd) { + fprintf(stderr, "%s: -f and -d are not compatible\n", prog); + return 1; + } + + /* need path */ + if (optind == argc) { + usage(); + exit(1); + } + else { + file = argv[optind]; + } + + if (irixsemantics) { + acl_set_compat(ACL_COMPAT_IRIXGET); + } + + if (usefd) { + fd = open(file, O_RDONLY); + if (fd < 0) { + fprintf (stderr, "%s: error opening \"%s\": %s\n", + prog, file, strerror(errno)); + usage(); + return 1; + + } + } + + if (getaccess) { + if (usefd) { + acl = acl_get_fd(fd); + } + else { + acl = acl_get_file(file, ACL_TYPE_ACCESS); + } + if (acl == NULL) { + fprintf (stderr, "%s: error getting access ACL on \"%s\": %s\n", + prog, file, strerror(errno)); + return 0; + } + if (irixsemantics && acl->acl_cnt == ACL_NOT_PRESENT) { + buf_acl = strdup("irix-empty"); + } + else { + buf_acl = acl_to_short_text (acl, (ssize_t *) NULL); + if (buf_acl == NULL) { + fprintf (stderr, "%s: error converting ACL to short text " + "for file \"%s\": %s\n", + prog, file, strerror(errno)); + return 0; + } + } + printf("%s: access %s\n", file, buf_acl); + acl_free(acl); + acl_free(buf_acl); + } + + if (getdefault) { + acl = acl_get_file(file, ACL_TYPE_DEFAULT); + if (acl == NULL) { + fprintf (stderr, "%s: error getting default ACL on \"%s\": %s\n", + prog, file, strerror(errno)); + return 0; + } + if (irixsemantics && acl->acl_cnt == ACL_NOT_PRESENT) { + buf_acl = strdup("irix-empty"); + } + else if (!irixsemantics && acl->acl_cnt == 0) { + buf_acl = strdup("linux-empty"); + } + else { + buf_acl = acl_to_short_text (acl, (ssize_t *) NULL); + if (buf_acl == NULL) { + fprintf (stderr, "%s: error converting ACL to short text " + "for file \"%s\": %s\n", + prog, file, strerror(errno)); + return 0; + } + } + printf("%s: default %s\n", file, buf_acl); + acl_free(acl); + acl_free(buf_acl); + } + + return 0; +} diff -rNu linux-2.4.7/cmd/xfstests/src/acl_test.c linux-2.4-xfs/cmd/xfstests/src/acl_test.c --- linux-2.4.7/cmd/xfstests/src/acl_test.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/acl_test.c Wed Jun 20 00:19:09 2001 @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This prog is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This prog is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this prog with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this prog; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Test our various libacl functions. + * Use IRIX semantics or Linux semantics if pertinent. + */ + +#include "global.h" + +#include +#include + +char *prog; +int irixsemantics = 0; + +void usage(void) +{ + fprintf(stderr, "usage: %s\n" + " -i - use irix semantics\n" + ,prog); + +} + +void +print_err(char *msg) +{ + printf("%s: %s: %s\n", prog, msg, strerror(errno)); +} + +void +dump_ace(acl_entry_t ace) +{ + printf("", + ace->ae_tag, ace->ae_id, ace->ae_perm); +} + +void +dump_acl(acl_t acl) +{ + int i; + printf("ACL[n=%d]: ", acl->acl_cnt); + for (i=0;iacl_cnt;i++) { + acl_entry_t ace = &acl->acl_entry[i]; + printf("%d: ", i); + dump_ace(ace); + printf(" "); + } + printf("\n"); + +} + +void +dump_acl_by_entry(acl_t acl) +{ + int sts, i; + acl_entry_t ace; + + printf("Get 1st entry on filled ACL\n"); + sts = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace); + printf("acl_get_entry -> %d\n", sts); + if (sts > 0) { + printf("1: "); dump_ace(ace); printf("\n"); + } + + for(i=2;i<=acl->acl_cnt+2;i++) { + printf("Get %dth entry on filled ACL\n", i); + sts = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace); + printf("acl_get_entry -> %d\n", sts); + if (sts > 0) { + printf("%d: ",i); dump_ace(ace); printf("\n"); + } + } +} + +/* + * create a full acl with entries with known bogus values + */ +acl_t +create_filled_acl(void) +{ + acl_t acl; + int i; + + acl = acl_init(ACL_MAX_ENTRIES); + + for(i=0;iacl_entry[i]; + ace->ae_tag = i; + ace->ae_id = i+1; + ace->ae_perm = i+2; + acl->acl_cnt++; + } + return acl; +} + +void +test_acl_get_qualifier(void) +{ + struct acl_entry ace; + uid_t *uidp; + + printf("*** test out acl_get_qualifier ***\n"); + + /* simple ace */ + ace.ae_tag = ACL_USER; + ace.ae_id = 1; + ace.ae_perm = 1; + + /* make sure we can get uid and free it */ + uidp = acl_get_qualifier(&ace); + printf("uid = %d\n", *uidp); + acl_free(uidp); + + /* change to another valid tag with a qualifier */ + ace.ae_tag = ACL_GROUP; + uidp = acl_get_qualifier(&ace); + printf("uid = %d\n", *uidp); + acl_free(uidp); + + /* let's get some errors */ + + ace.ae_tag = ACL_USER_OBJ; + uidp = acl_get_qualifier(&ace); + if (uidp == NULL) + printf("uidp is NULL: %s\n", strerror(errno)); + else + printf("Error: uidp is NOT NULL\n"); + + uidp = acl_get_qualifier(NULL); + if (uidp == NULL) + printf("uidp is NULL: %s\n", strerror(errno)); + else + printf("Error: uidp is NOT NULL\n"); +} + +int +main(int argc, char **argv) +{ + int c, i; + acl_t acl1, acl2, acl3; + acl_entry_t ace1; + + prog = basename(argv[0]); + + while ((c = getopt(argc, argv, "i")) != -1) { + switch (c) { + case 'i': + irixsemantics = 1; + break; + case '?': + usage(); + return 1; + } + } + + if (irixsemantics) { + acl_set_compat(ACL_COMPAT_IRIXGET); + } + + /* ---------------------------------------------- */ + printf("*** test out creating an ACL ***\n"); + + printf("Test acl_init(ACL_MAX_ENTRIES+1)\n"); + acl1 = acl_init(ACL_MAX_ENTRIES+1); + if (acl1 == NULL) { + print_err("acl_init(max+1)"); + } + printf("Test acl_init(-1)\n"); + acl1 = acl_init(-1); + if (acl1 == NULL) { + print_err("acl_init(-1)"); + } + printf("Test acl_init(0)\n"); + acl1 = acl_init(0); + if (acl1 == NULL) { + print_err("acl_init(0)"); + } + + printf("Test acl_create_entry(NULL, ...)\n"); + if (acl_create_entry(NULL, &ace1) == -1) { + print_err("acl_create_entry(NULL,ace1)"); + } + printf("Test acl_create_entry(..., NULL)\n"); + if (acl_create_entry(&acl1, NULL) == -1) { + print_err("acl_create_entry(NULL,ace1)"); + } + printf("Test acl_create_entry(acl1, ace1)\n"); + acl1 = NULL; + if (acl_create_entry(&acl1, &ace1) == -1) { + print_err("acl_create_entry(*null,ace1)"); + } + + acl_free(acl1); + acl1 = acl_init(0); + for (i=0;i<=ACL_MAX_ENTRIES+1;i++) { + printf("%d: creating ace\n", i); + if (acl_create_entry(&acl1, &ace1) == -1) { + print_err("acl_create_entry"); + } + dump_acl(acl1); + } + + /* ---------------------------------------------- */ + printf("*** test out getting ACEs ***\n"); + + dump_acl_by_entry(acl1); + + printf("dump empty ACL\n"); + acl2 = acl_init(0); + if (acl2 == NULL) { + print_err("acl_init(0)"); + } + dump_acl_by_entry(acl2); + + printf("fill an ACL with known bogus values\n"); + acl3 = create_filled_acl(); + dump_acl_by_entry(acl3); + + /* ---------------------------------------------- */ + printf("*** test out ACL to text for empty ACL***\n"); + { + char *text; + ssize_t len; + acl_t empty_acl = acl_init(0); + text = acl_to_text(empty_acl, NULL); + printf("acl_to_text(empty_acl,NULL) -> \"%s\"\n", text); + text = acl_to_text(empty_acl, &len); + printf("acl_to_text(empty_acl,NULL) -> \"%s\", len = %u\n", text, len); + text = acl_to_text(NULL, NULL); + printf("acl_to_text(NULL,NULL) -> \"%s\"\n", text==NULL?"NULL":text); + } + /* NOTE: Other tests will test out the text for ACLs with ACEs. + * So don't have to test it here. + * It is simplest to choose ids not in /etc/passwd /etc/group + * which is done already in a script. + */ + + test_acl_get_qualifier(); + + return 0; +} diff -rNu linux-2.4.7/cmd/xfstests/src/alloc.c linux-2.4-xfs/cmd/xfstests/src/alloc.c --- linux-2.4.7/cmd/xfstests/src/alloc.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/alloc.c Mon Mar 26 01:07:33 2001 @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "global.h" + +#define FSBTOBB(f) (OFFTOBBT(FSBTOOFF(f))) +#define BBTOFSB(b) (OFFTOFSB(BBTOOFF(b))) +#define OFFTOFSB(o) ((o) / blocksize) +#define FSBTOOFF(f) ((f) * blocksize) + +void usage(void) +{ + printf("usage: alloc [-b blocksize] [-d dir] [-f file] [-n] [-r] [-t]\n" + "flags:\n" + " -n - non-interractive mode\n" + " -r - real time file\n" + " -t - truncate on open\n" + "\n" + "commands:\n" + " r [offset] [length] - reserve\n" + " u [offset] [length] - unreserve\n" + " a [offset] [length] - alloc *** identical to free\n" + " f [offset] [length] - free *** identical to alloc\n" + " m/p [offset] [length] - print map\n" + " s - sync file\n" + " t [offset] - truncate\n" + " q - quit\n" + " h/? - this help\n"); + +} + +int fd; +int blocksize = 0; + +/* params are in bytes */ +void map(off64_t off, off64_t len) +{ + struct getbmap bm[2]={{0}}; + + bm[0].bmv_count = 2; + bm[0].bmv_offset = OFFTOBB(off); + if (len==(off64_t)-1) { /* unsigned... */ + bm[0].bmv_length = -1; + printf(" MAP off=%lld, len=%lld [%lld-]\n", + (__s64)off, (__s64)len, + (__s64)BBTOFSB(bm[0].bmv_offset)); + } else { + bm[0].bmv_length = OFFTOBB(len); + printf(" MAP off=%lld, len=%lld [%lld,%lld]\n", + (__s64)off, (__s64)len, + (__s64)BBTOFSB(bm[0].bmv_offset), + (__s64)BBTOFSB(bm[0].bmv_length)); + } + + printf(" [ofs,count]: start..end\n"); + for (;;) { + if (ioctl(fd, XFS_IOC_GETBMAP, bm) < 0) { + perror("getbmap"); + break; + } + if (bm[0].bmv_entries == 0) + break; + printf(" [%lld,%lld]: ", + (__s64)BBTOFSB(bm[1].bmv_offset), + (__s64)BBTOFSB(bm[1].bmv_length)); + if (bm[1].bmv_block == -1) + printf("hole"); + else + printf("%lld..%lld", + (__s64)BBTOFSB(bm[1].bmv_block), + (__s64)BBTOFSB(bm[1].bmv_block + + bm[1].bmv_length - 1)); + printf("\n"); + } +} + +int +main(int argc, char **argv) +{ + int c; + char *dirname = NULL; + int done = 0; + struct flock64 f; + char *filename = NULL; + off64_t len; + char line[1024]; + off64_t off; + int oflags; + static char *opnames[] = + { "freesp", "allocsp", "unresvsp", "resvsp" }; + int opno; + static int optab[] = + { XFS_IOC_FREESP64, XFS_IOC_ALLOCSP64, XFS_IOC_UNRESVSP64, XFS_IOC_RESVSP64 }; + int rflag = 0; + struct statvfs64 svfs; + int tflag = 0; + int nflag = 0; + int unlinkit = 0; + __int64_t v; + + while ((c = getopt(argc, argv, "b:d:f:rtn")) != -1) { + switch (c) { + case 'b': + blocksize = atoi(optarg); + break; + case 'd': + if (filename) { + printf("can't specify both -d and -f\n"); + exit(1); + } + dirname = optarg; + break; + case 'f': + if (dirname) { + printf("can't specify both -d and -f\n"); + exit(1); + } + filename = optarg; + break; + case 'r': + rflag = 1; + break; + case 't': + tflag = 1; + break; + case 'n': + nflag++; + break; + default: + printf("unknown option\n"); + usage(); + exit(1); + } + } + if (!dirname && !filename) + dirname = "."; + if (!filename) { + static char tmpfile[] = "allocXXXXXX"; + + mkstemp(tmpfile); + filename = malloc(strlen(tmpfile) + strlen(dirname) + 2); + sprintf(filename, "%s/%s", dirname, tmpfile); + unlinkit = 1; + } + oflags = O_RDWR | O_CREAT | (tflag ? O_TRUNC : 0); + fd = open(filename, oflags, 0666); + if (!nflag) { + printf("alloc:\n"); + printf(" filename %s\n", filename); + } + if (fd < 0) { + perror(filename); + exit(1); + } + if (unlinkit) + unlink(filename); + if (!blocksize) { + if (fstatvfs64(fd, &svfs) < 0) { + perror(filename); + exit(1); + } + blocksize = (int)svfs.f_bsize; + } + if (blocksize<0) { + fprintf(stderr,"illegal blocksize %d\n", blocksize); + exit(1); + } + printf(" blocksize %d\n", blocksize); + if (rflag) { + struct fsxattr a; + + if (ioctl(fd, XFS_IOC_FSGETXATTR, &a) < 0) { + perror("XFS_IOC_FSGETXATTR"); + exit(1); + } + a.fsx_xflags |= XFS_XFLAG_REALTIME; + if (ioctl(fd, XFS_IOC_FSSETXATTR, &a) < 0) { + perror("XFS_IOC_FSSETXATTR"); + exit(1); + } + } + while (!done) { + char *p; + + if (!nflag) printf("alloc> "); + fflush(stdout); + if (!fgets(line, 1024, stdin)) break; + + p=line+strlen(line); + if (p!=line&&p[-1]=='\n') p[-1]=0; + + opno = 0; + switch (line[0]) { + case 'r': + opno++; + case 'u': + opno++; + case 'a': + opno++; + case 'f': + v = strtoll(&line[2], &p, 0); + if (*p == 'b') { + off = FSBTOOFF(v); + p++; + } else + off = v; + f.l_whence = SEEK_SET; + f.l_start = off; + if (*p == '\0') + v = -1; + else + v = strtoll(p, &p, 0); + if (*p == 'b') { + len = FSBTOOFF(v); + p++; + } else + len = v; + + printf(" CMD %s, off=%lld, len=%lld\n", + opnames[opno], (__s64)off, (__s64)len); + + f.l_len = len; + c = ioctl(fd, optab[opno], &f); + if (c < 0) { + perror(opnames[opno]); + break; + } + + map(off,len); + break; + case 'p': + case 'm': + p = &line[1]; + v = strtoll(p, &p, 0); + if (*p == 'b') { + off = FSBTOOFF(v); + p++; + } else + off = v; + if (*p == '\0') + len = -1; + else { + v = strtoll(p, &p, 0); + if (*p == 'b') + len = FSBTOOFF(v); + else + len = v; + } + map(off,len); + break; + case 't': + p = &line[1]; + v = strtoll(p, &p, 0); + if (*p == 'b') + off = FSBTOOFF(v); + else + off = v; + printf(" TRUNCATE off=%lld\n", (__s64)off); + if (ftruncate64(fd, off) < 0) { + perror("ftruncate"); + break; + } + break; + case 's': + printf(" SYNC\n"); + fsync(fd); + break; + case 'q': + printf(" QUIT\n"); + done = 1; + break; + case '?': + case 'h': + usage(); + break; + default: + printf("unknown command '%s'\n", line); + break; + } + } + if (!nflag) printf("\n"); + close(fd); + exit(0); + /* NOTREACHED */ +} diff -rNu linux-2.4.7/cmd/xfstests/src/bstat.c linux-2.4-xfs/cmd/xfstests/src/bstat.c --- linux-2.4.7/cmd/xfstests/src/bstat.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/bstat.c Wed May 9 02:03:16 2001 @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include + +void +dotime(void *ti, char *s) +{ + char *c; + xfs_bstime_t *t; + + t = (xfs_bstime_t *)ti; + + c = ctime(&t->tv_sec); + printf("\t%s %19.19s.%09d %s", s, c, t->tv_nsec, c + 20); +} + +void +printbstat(xfs_bstat_t *sp) +{ + printf("ino %lld mode %#o nlink %d uid %d gid %d rdev %#x\n", + sp->bs_ino, sp->bs_mode, sp->bs_nlink, + sp->bs_uid, sp->bs_gid, sp->bs_rdev); + printf("\tblksize %d size %lld blocks %lld xflags %#x extsize %d\n", + sp->bs_blksize, sp->bs_size, sp->bs_blocks, + sp->bs_xflags, sp->bs_extsize); + dotime(&sp->bs_atime, "atime"); + dotime(&sp->bs_mtime, "mtime"); + dotime(&sp->bs_ctime, "ctime"); + printf( "\textents %d %d gen %d\n", + sp->bs_extents, sp->bs_aextents, sp->bs_gen); + printf( "\tDMI: event mask 0x%08x state 0x%04x\n", + sp->bs_dmevmask, sp->bs_dmstate); +} + +void +printstat(struct stat64 *sp) +{ + printf("ino %lld mode %#o nlink %d uid %d gid %d rdev %#x\n", + (xfs_ino_t)sp->st_ino, sp->st_mode, sp->st_nlink, + sp->st_uid, sp->st_gid, (unsigned int)sp->st_rdev); + printf("\tblksize %llu size %lld blocks %lld\n", + (__uint64_t)sp->st_blksize, sp->st_size, sp->st_blocks); + dotime(&sp->st_atime, "atime"); + dotime(&sp->st_mtime, "mtime"); + dotime(&sp->st_ctime, "ctime"); +} + +int +main(int argc, char **argv) +{ + __s32 count; + int total = 0; + int fsfd; + int i; + __s64 last = 0; + char *name; + int nent; + int debug = 0; + int quiet = 0; + int statit = 0; + int verbose = 0; + xfs_bstat_t *t; + int ret; + jdm_fshandle_t *fshandlep = NULL; + int fd; + struct stat64 sb; + int nread; + char *cc_readlinkbufp; + int cc_readlinkbufsz; + int c; + xfs_fsop_bulkreq_t bulkreq; + + while ((c = getopt(argc, argv, "cdl:qv")) != -1) { + switch (c) { + case 'q': + quiet = 1; + break; + case 'v': + verbose = 1; + break; + case 'c': + statit = 1; + break; + case 'd': + debug = 1; + break; + case 'l': + last = atoi(optarg); + break; + case '?': + printf("usage: xfs_bstat [-c] [-q] [-v] [ dir [ batch_size ]]\n"); + printf(" -c Check the results against stat(3) output\n"); + printf(" -q Quiet\n"); + printf(" -l _num_ Inode to start with\n"); + printf(" -v Verbose output\n"); + exit(1); + } + } + argc -= optind; + argv += optind; + + if (argc < 1) + name = "."; + else + name = *argv; + + fsfd = open(name, O_RDONLY); + if (fsfd < 0) { + perror(name); + exit(1); + } + if (argc < 2) + nent = 4096; + else + nent = atoi(*++argv); + + if (verbose) + printf("Bulkstat test on %s, batch size=%d statcheck=%d\n", + name, nent, statit); + + if (statit) { + fshandlep = jdm_getfshandle( name ); + if (! fshandlep) { + printf("unable to construct sys handle for %s: %s\n", + name, strerror(errno)); + return -1; + } + } + + t = malloc(nent * sizeof(*t)); + + if (verbose) + printf( + "XFS_IOC_FSBULKSTAT test: last=%lld nent=%d\n", last, nent); + + bulkreq.lastip = &last; + bulkreq.icount = nent; + bulkreq.ubuffer = t; + bulkreq.ocount = &count; + + while ((ret = ioctl(fsfd, XFS_IOC_FSBULKSTAT, &bulkreq)) == 0) { + total += count; + + if (verbose) + printf( + "XFS_IOC_FSBULKSTAT test: last=%lld ret=%d count=%d total=%d\n", + last, ret, count, total); + if (count == 0) + exit(0); + + if ( quiet && ! statit ) + continue; + + for (i = 0; i < count; i++) { + if (! quiet) { + printbstat(&t[i]); + } + + if (statit) { + switch(t[i].bs_mode & S_IFMT) { + case S_IFLNK: + cc_readlinkbufsz = MAXPATHLEN; + cc_readlinkbufp = (char *)calloc( + 1, + cc_readlinkbufsz); + nread = jdm_readlink( + fshandlep, + &t[i], + cc_readlinkbufp, + cc_readlinkbufsz); + if (verbose && nread > 0) + printf( + "readlink: ino %lld: <%*s>\n", + t[i].bs_ino, + nread, + cc_readlinkbufp); + free(cc_readlinkbufp); + if ( nread < 0 ) { + printf( + "could not read symlink ino %llu\n", + t[i].bs_ino ); + printbstat(&t[i]); + } + break; + + case S_IFCHR: + case S_IFBLK: + case S_IFIFO: + case S_IFSOCK: + break; + + case S_IFREG: + case S_IFDIR: + fd = jdm_open( fshandlep, &t[i], O_RDONLY); + if (fd < 0) { + printf( + "unable to open handle ino %lld: %s\n", + t[i].bs_ino, strerror(errno)); + continue; + } + if (fstat64(fd, &sb) < 0) { + printf( + "unable to stat ino %lld: %s\n", + t[i].bs_ino, strerror(errno)); + } + close(fd); + + /* + * Don't compare blksize or blocks, + * they are used differently by stat + * and bstat. + */ + if ( (t[i].bs_ino != sb.st_ino) || + (t[i].bs_mode != sb.st_mode) || + (t[i].bs_nlink != sb.st_nlink) || + (t[i].bs_uid != sb.st_uid) || + (t[i].bs_gid != sb.st_gid) || + (t[i].bs_rdev != sb.st_rdev) || + (t[i].bs_size != sb.st_size) || + /* (t[i].bs_blksize != sb.st_blksize) || */ + (t[i].bs_mtime.tv_sec != sb.st_mtime) || + (t[i].bs_ctime.tv_sec != sb.st_ctime) ) { + printf("\nstat/bstat missmatch\n"); + printbstat(&t[i]); + printstat(&sb); + } + } + } + } + + if (debug) + break; + } + + if (fsfd) + close(fsfd); + + if (ret < 0 ) + perror("ioctl(XFS_IOC_FSBULKSTAT)"); + + if (verbose) + printf( + "XFS_IOC_FSBULKSTAT test: last=%lld nent=%d ret=%d count=%d\n", + last, nent, ret, count); + + return 1; +} diff -rNu linux-2.4.7/cmd/xfstests/src/dbtest.c linux-2.4-xfs/cmd/xfstests/src/dbtest.c --- linux-2.4.7/cmd/xfstests/src/dbtest.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/dbtest.c Sun Jan 14 23:01:19 2001 @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "global.h" +#include + +/* #define WorkDir "/xfs" */ +#define DBNAME "DBtest" +#define DBRECS 100000 +#define LOOPS 100 + +typedef struct _myDB { + char data[976]; + unsigned short checksum; + long align; +} myDB; + +int InitDbmLookup(int); +int DoDbmLookup(void); +void CleanupDbmLookup(void); +void DoSysError(char *, int); +int creatDbRec(myDB *); +unsigned short calccksum(char *, int); +void CkSumError(char *, unsigned short, unsigned short); +int InsertKey(unsigned short *, int, unsigned short); +void DumpKeys(int, unsigned short); + +DBM *dbm; +int numDbmEntries, keyIdx, Dups = 0, Errors = 0; +unsigned short *KeyArray, *DupsArray; +int debugflg = 0; /* are we in debugging mode? */ +int errflg = 0; /* usage option errors */ +int ignoreflg = 1; /* ignore errors in lookup; default = on */ +int loops = LOOPS; +int randseed = 0; + +int +main(int argc, char *argv[]) +{ + int numrecs = DBRECS, c, l; + + while ((c = getopt(argc, argv, "idn:l:s:")) != EOF) { + switch(c) { + case 'i': + ignoreflg++; break; + case 'd': + debugflg++; break; + case 'n': + numrecs = atoi(optarg); + numrecs = (numrecs < 1) ? DBRECS : numrecs; + break; + case 'l': + loops = atoi(optarg); + loops = (loops < 1) ? LOOPS : loops; + break; + case 's': + randseed = atoi(optarg); + randseed = (randseed < 0) ? 0 : randseed; + break; + case '?': + errflg++; + break; + } + } + if (errflg) { + printf("Usage: dbtest [-di] [-n number] [-l loop] [-s randseed]\n"); + exit(0); + } + if (optind > argc) { + printf("Extra arguments ignored\n"); + for ( ; optindchecksum, KeyArray[j]); + + if (content.dsize == 0) { + printf("\nrec #%-8d: key = %4x (%d)\n", i, KeyArray[j], j); + DoSysError("\ndbm_fetch", content.dsize); + } + if (dbp->checksum != KeyArray[j]) + CkSumError("KeySequential", dbp->checksum, KeyArray[j]); + if ((tmpck = calccksum(dbp->data, sizeof(dbp->data))) != KeyArray[j]) + CkSumError("DataSequential", tmpck, KeyArray[j]); + if (++j >= keyIdx) + j = 0; + } + printf("\n\n\tRandom lookups...\n"); + for(i=0; ichecksum, KeyArray[n]); + + if (content.dsize == 0) + DoSysError("\ndbm_fetch", content.dsize); + if (dbp->checksum != KeyArray[n]) + CkSumError("KeyRand", dbp->checksum, KeyArray[n]); + if ((tmpck = calccksum(dbp->data, sizeof(dbp->data))) != KeyArray[n]) + CkSumError("DataRand", tmpck, KeyArray[n]); + } + return i; +} + +void CleanupDbmLookup(void) +{ + char filename[100]; + int rc; + + dbm_close(dbm); + sprintf(filename, "%s-%d.dir", DBNAME, getpid()); + rc = unlink(filename); + if (rc) DoSysError("\nunlink", rc); + sprintf(filename, "%s-%d.pag", DBNAME, getpid()); + rc = unlink(filename); + if (rc) DoSysError("\nunlink", rc); +} + +void DoSysError(char *msg, int rc) +{ + perror(msg); + fprintf(stderr, "Bailing out! status = %d\n", rc); + exit(-1); +} + +int creatDbRec(myDB *dbp) +{ + static int once = 0; + int i, j; + long *ptr; + long timeseed; + + if (!once) { + once++; + if ( !randseed ) { + timeseed = time(0); + printf("\tusing %ld as seed for srandom()...\n\n", + timeseed); + srandom(timeseed); + } else + srandom(randseed); + } + ptr = (long *)&(dbp->data); + j = sizeof(dbp->data) / sizeof(long); + for (i=0; i < j; i++, ptr++) { + *ptr = random(); + } + for (i=(j*sizeof(long)); idata); i++) + dbp->data[i] = (char)time(0); + + dbp->checksum = calccksum(dbp->data, sizeof(dbp->data)); + return 0; +} + +unsigned short calccksum(char *ptr, int size) +{ + unsigned short sum; + int i, n; + + sum = 0; + n = ((size > 100) ? 100 : size); + for (i=0; i> 1) + 0x8000; + else + sum >>= 1; + sum += (unsigned short)*ptr; + sum &= 0xffff; + } + return sum; +} + +/*ARGSUSED*/ +void CkSumError(char *msg, unsigned short ck1, unsigned short ck2) +{ + Errors++; + printf("%s\n\tChecksum error, %u != %u, Total errors = %d\n", + msg, ck1, ck2, Errors); + exit(1); +} + +int InsertKey(unsigned short *k, int idx, unsigned short val) +{ +/* + int i, found=0; +*/ + + return( (k[idx] = val) ); + +/* + for (i=0; i +#include + +int +main(int argc, char **argv) +{ + off_t offset = 0; + int blksize = 4096; + long long maxblks = -1; /* no limit */ + long long nblks = 0; + int value = 0; + int sts = 0; + int fd; + char *z; + char *path; + int oflags = O_WRONLY; + + char *progname; + + if (strrchr(argv[0],'/')) + progname = strrchr(argv[0],'/')+1; + else + progname = argv[0]; + + while ((fd = getopt(argc, argv, "b:n:o:v:ct")) != EOF) { + switch (fd) { + case 'b': + blksize = atoi(optarg) * 512; + break; + case 'n': + maxblks = atoll(optarg); + break; + case 'o': + offset = atoll(optarg); + break; + case 'v': + value = atoi(optarg); + break; + case 'c': + oflags |= O_CREAT; + break; + case 't': + oflags |= O_TRUNC; + break; + default: + sts++; + } + } + if (sts || argc - optind != 1) { + fprintf(stderr, + "Usage: %s [-b N*512] [-n N] [-o off] [-v val] " + " [-c] [-t] \n", + progname); + fprintf(stderr," -c: create -t: truncate\n"); + exit(1); + } + + path = argv[optind]; + + if ((fd = open(path, oflags)) < 0) { + fprintf(stderr, + "error opening \"%s\": %s\n", + path, strerror(errno)); + exit(1); + } + if ((lseek64(fd, offset, SEEK_SET)) < 0) { + fprintf(stderr, "%s: error seeking to offset %llu " + "on \"%s\": %s\n", + progname, offset, path, strerror(errno)); + exit(1); + } + + if ((z = memalign(getpagesize(), blksize)) == NULL) { + fprintf(stderr, "%s: can't memalign %u bytes: %s\n", + progname, blksize, strerror(errno)); + exit(1); + } + memset(z, value, blksize); + errno = 0; + for (;;) { + if (nblks++ == maxblks) + break; + if ((sts = write(fd, z, blksize)) < blksize) { + if (errno == ENOSPC || sts >= 0) + break; + fprintf(stderr, "%s: write failed: %s\n", + progname, strerror(errno)); + break; + } + } + printf("Wrote %.2fKb (value 0x%x)\n", + (double) ((--nblks) * blksize) / 1024, value); + free(z); + return 0; +} diff -rNu linux-2.4.7/cmd/xfstests/src/dirstress.c linux-2.4-xfs/cmd/xfstests/src/dirstress.c --- linux-2.4.7/cmd/xfstests/src/dirstress.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/dirstress.c Sun Jan 14 23:01:19 2001 @@ -0,0 +1,449 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + + /* + * This is mostly a "crash & burn" test. -v turns on verbosity + * and -c actually fails on errors - but expected errors aren't + * expected... + */ + +#include "global.h" + +int verbose; +int pid; + +int checkflag=0; + +#define MKNOD_DEV 0 + +static int dirstress(char *dirname, int dirnum, int nfiles, int keep); +static int create_entries(int nfiles); +static int scramble_entries(int nfiles); +static int remove_entries(int nfiles); + +int +main( + int argc, + char *argv[]) +{ + char *dirname; + int nprocs; + int nfiles; + int c; + int errflg; + int i; + long seed; + int childpid; + int nprocs_per_dir; + int keep; + int status, istatus; + + pid=getpid(); + + errflg = 0; + dirname = NULL; + nprocs = 4; + nfiles = 100; + seed = time(NULL); + nprocs_per_dir = 1; + keep = 0; + verbose = 0; + while ((c = getopt(argc, argv, "d:p:f:s:n:kvc")) != EOF) { + switch(c) { + case 'p': + nprocs = atoi(optarg); + break; + case 'f': + nfiles = atoi(optarg); + break; + case 'n': + nprocs_per_dir = atoi(optarg); + break; + case 'd': + dirname = optarg; + break; + case 's': + seed = strtol(optarg, NULL, 0); + break; + case 'k': + keep = 1; + break; + case '?': + errflg++; + break; + case 'v': + verbose++; + break; + case 'c': + checkflag++; + break; + } + } + if (errflg || (dirname == NULL)) { + printf("Usage: dirstress [-d dir] [-p nprocs] [-f nfiles] [-n procs per dir]\n" + " [-v] [-s seed] [-k] [-c]\n"); + exit(0); + } + + printf("** [%d] Using seed %ld\n", pid, seed); + srandom(seed); + + for (i = 0; i < nprocs; i++) { + if (verbose) fprintf(stderr,"** [%d] fork\n", pid); + childpid = fork(); + if (childpid < 0) { + perror("Fork failed"); + exit(errno); + } + if (childpid == 0) { + int r; + /* child */ + pid=getpid(); + + if (verbose) fprintf(stderr,"** [%d] forked\n", pid); + r=dirstress(dirname, i / nprocs_per_dir, nfiles, keep); + if (verbose) fprintf(stderr,"** [%d] exit\n", pid); + exit(r); + } + } + if (verbose) fprintf(stderr,"** [%d] wait\n", pid); + istatus=0; + + /* wait & reap children, accumulating error results */ + while (wait(&status) != -1) + istatus+=status/256; + + printf("INFO: Dirstress complete\n"); + if (verbose) fprintf(stderr,"** [%d] exit %d\n", pid, istatus); + return istatus; +} + + + +int +dirstress( + char *dirname, + int dirnum, + int nfiles, + int keep) +{ + int error; + char buf[1024]; + int r; + + sprintf(buf, "%s/stressdir", dirname); + if (verbose) fprintf(stderr,"** [%d] mkdir %s 0777\n", pid, buf); + error = mkdir(buf, 0777); + if (error && (errno != EEXIST)) { + perror("Create stressdir directory failed"); + return 1; + } + + if (verbose) fprintf(stderr,"** [%d] chdir %s\n", pid, buf); + error = chdir(buf); + if (error) { + perror("Cannot chdir to main directory"); + return 1; + } + + sprintf(buf, "stress.%d", dirnum); + if (verbose) fprintf(stderr,"** [%d] mkdir %s 0777\n", pid, buf); + error = mkdir(buf, 0777); + if (error && (errno != EEXIST)) { + perror("Create pid directory failed"); + return 1; + } + + if (verbose) fprintf(stderr,"** [%d] chdir %s\n", pid, buf); + error = chdir(buf); + if (error) { + perror("Cannot chdir to dirnum directory"); + return 1; + } + + r=1; /* assume failure */ + if (verbose) fprintf(stderr,"** [%d] create entries\n", pid); + if (create_entries(nfiles)) { + printf("!! [%d] create failed\n", pid); + } else { + if (verbose) fprintf(stderr,"** [%d] scramble entries\n", pid); + if (scramble_entries(nfiles)) { + printf("!! [%d] scramble failed\n", pid); + } else { + if (keep) { + if (verbose) fprintf(stderr,"** [%d] keep entries\n", pid); + r=0; /* success */ + } else { + if (verbose) fprintf(stderr,"** [%d] remove entries\n", pid); + if (remove_entries(nfiles)) { + printf("!! [%d] remove failed\n", pid); + } else { + r=0; /* success */ + } + } + } + } + + if (verbose) fprintf(stderr,"** [%d] chdir ..\n", pid); + error = chdir(".."); + if (error) { + perror("Cannot chdir out of pid directory"); + return 1; + } + + if (!keep) { + sprintf(buf, "stress.%d", dirnum); + if (verbose) fprintf(stderr,"** [%d] rmdir %s\n", pid, buf); + if (rmdir(buf)) { + perror("rmdir"); + if (checkflag) return 1; + } + } + + if (verbose) fprintf(stderr,"** [%d] chdir ..\n", pid); + error = chdir(".."); + if (error) { + perror("Cannot chdir out of working directory"); + return 1; + } + + if (!keep) { + if (verbose) fprintf(stderr,"** [%d] rmdir stressdir\n", pid); + if (rmdir("stressdir")) { + perror("rmdir"); + if (checkflag) return 1; + } + } + + return r; +} + +int +create_entries( + int nfiles) +{ + int i; + int fd; + char buf[1024]; + + for (i = 0; i < nfiles; i++) { + sprintf(buf, "XXXXXXXXXXXX.%d", i); + switch (i % 4) { + case 0: + /* + * Create a file + */ + if (verbose) fprintf(stderr,"** [%d] creat %s\n", pid, buf); + fd = creat(buf, 0666); + if (fd > 0) { + if (verbose) fprintf(stderr,"** [%d] close %s\n", pid, buf); + close(fd); + } else { + fprintf(stderr,"!! [%d] close %s failed\n", pid, buf); + perror("close"); + if (checkflag) return 1; + } + + break; + case 1: + /* + * Make a directory. + */ + if (verbose) fprintf(stderr,"** [%d] mkdir %s 0777\n", pid, buf); + if (mkdir(buf, 0777)) { + fprintf(stderr,"!! [%d] mkdir %s 0777 failed\n", pid, buf); + perror("mkdir"); + if (checkflag) return 1; + } + + break; + case 2: + /* + * Make a symlink + */ + if (verbose) fprintf(stderr,"** [%d] symlink %s %s\n", pid, buf, buf); + if (symlink(buf, buf)) { + fprintf(stderr,"!! [%d] symlink %s %s failed\n", pid, buf, buf); + perror("symlink"); + if (checkflag) return 1; + } + + break; + case 3: + /* + * Make a dev node + */ + if (verbose) fprintf(stderr,"** [%d] mknod %s 0x%x\n", pid, buf, MKNOD_DEV); + if (mknod(buf, S_IFCHR | 0666, MKNOD_DEV)) { + fprintf(stderr,"!! [%d] mknod %s 0x%x failed\n", pid, buf, MKNOD_DEV); + perror("mknod"); + if (checkflag) return 1; + } + + break; + default: + break; + } + } + return 0; +} + + +int +scramble_entries( + int nfiles) +{ + int i; + char buf[1024]; + char buf1[1024]; + long r; + int fd; + + for (i = 0; i < nfiles * 2; i++) { + switch (i % 5) { + case 0: + /* + * rename two random entries + */ + r = random() % nfiles; + sprintf(buf, "XXXXXXXXXXXX.%ld", r); + r = random() % nfiles; + sprintf(buf1, "XXXXXXXXXXXX.%ld", r); + + if (verbose) fprintf(stderr,"** [%d] rename %s %s\n", pid, buf, buf1); + if (rename(buf, buf1)) { + perror("rename"); + if (checkflag) return 1; + } + break; + case 1: + /* + * unlink a random entry + */ + r = random() % nfiles; + sprintf(buf, "XXXXXXXXXXXX.%ld", r); + if (verbose) fprintf(stderr,"** [%d] unlink %s\n", pid, buf); + if (unlink(buf)) { + fprintf(stderr,"!! [%d] unlink %s failed\n", pid, buf); + perror("unlink"); + if (checkflag) return 1; + } + break; + case 2: + /* + * rmdir a random entry + */ + r = random() % nfiles; + sprintf(buf, "XXXXXXXXXXXX.%ld", r); + if (verbose) fprintf(stderr,"** [%d] rmdir %s\n", pid, buf); + if (rmdir(buf)) { + fprintf(stderr,"!! [%d] rmdir %s failed\n", pid, buf); + perror("rmdir"); + if (checkflag) return 1; + } + break; + case 3: + /* + * create a random entry + */ + r = random() % nfiles; + sprintf(buf, "XXXXXXXXXXXX.%ld", r); + + if (verbose) fprintf(stderr,"** [%d] creat %s 0666\n", pid, buf); + fd = creat(buf, 0666); + if (fd > 0) { + if (verbose) fprintf(stderr,"** [%d] close %s\n", pid, buf); + if (close(fd)) { + fprintf(stderr,"!! [%d] close %s failed\n", pid, buf); + perror("close"); + if (checkflag) return 1; + } + } else { + fprintf(stderr,"!! [%d] creat %s 0666 failed\n", pid, buf); + perror("creat"); + if (checkflag) return 1; + } + break; + case 4: + /* + * mkdir a random entry + */ + r = random() % nfiles; + sprintf(buf, "XXXXXXXXXXXX.%ld", r); + if (verbose) fprintf(stderr,"** [%d] mkdir %s\n", pid, buf); + if (mkdir(buf, 0777)) { + fprintf(stderr,"!! [%d] mkdir %s failed\n", pid, buf); + perror("mkdir"); + if (checkflag) return 1; + } + break; + default: + break; + } + } + return 0; +} + +int +remove_entries( + int nfiles) +{ + int i; + char buf[1024]; + struct stat statb; + int error; + + for (i = 0; i < nfiles; i++) { + sprintf(buf, "XXXXXXXXXXXX.%d", i); + error = lstat(buf, &statb); + if (error) { + /* ignore this one */ + continue; + } + if (S_ISDIR(statb.st_mode)) { + if (verbose) fprintf(stderr,"** [%d] rmdir %s\n", pid, buf); + if (rmdir(buf)) { + fprintf(stderr,"!! [%d] rmdir %s failed\n", pid, buf); + perror("rmdir"); + if (checkflag) return 1; + } + } else { + if (verbose) fprintf(stderr,"** [%d] unlink %s\n", pid, buf); + if (unlink(buf)) { + fprintf(stderr,"!! [%d] unlink %s failed\n", pid, buf); + perror("unlink"); + if (checkflag) return 1; + } + } + } + return 0; +} diff -rNu linux-2.4.7/cmd/xfstests/src/fault.c linux-2.4-xfs/cmd/xfstests/src/fault.c --- linux-2.4.7/cmd/xfstests/src/fault.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/fault.c Wed May 9 02:03:16 2001 @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +void expect_error(int r, int err) +{ + if (r<0) { + if (errno == err) { + printf(" --- got error %d as expected\n", err); + } else { + perror(" !!! unexpected error"); + } + } else { + printf(" !!! success instead of error %d as expected\n", err); + } +} + +int +main(int argc, char **argv) +{ + int fsfd; + + if (argc != 2) { + fprintf(stderr,"usage: %s \n", + argv[0]); + exit(0); + } + + fsfd = open(argv[1], O_RDONLY); + if (fsfd < 0) { + perror("open"); + exit(1); + } + + printf("--- ioctl with bad output address\n"); + expect_error(ioctl(fsfd, XFS_IOC_FSCOUNTS, NULL), EFAULT); + printf("--- ioctl with bad input address\n"); + expect_error(ioctl(fsfd, XFS_IOC_SET_RESBLKS, NULL), EFAULT); + + close(fsfd); + + return 0; +} diff -rNu linux-2.4.7/cmd/xfstests/src/feature.c linux-2.4-xfs/cmd/xfstests/src/feature.c --- linux-2.4.7/cmd/xfstests/src/feature.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/feature.c Mon May 21 23:50:41 2001 @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Test for filesystem features on given mount point or device + * -c test for 32bit chown support (via libc) + * -q test for quota support (kernel compile option) + * -u test for user quota enforcement support (mount option) + * -g test for group quota enforcement support (mount option) + * -U test for user quota accounting support (mount option) + * -G test for group quota accounting support (mount option) + * Return code: 0 is true, anything else is error/not supported + */ + +#include +#include +#include + +int verbose = 0; + +void +usage(void) +{ + fprintf(stderr, "Usage: feature [-v] - \n"); + fprintf(stderr, " feature [-v] -c \n"); + exit(1); +} + +int check_big_ID(char *filename) +{ + struct stat64 sbuf; + + memset(&sbuf, 0, sizeof(struct stat64)); + if (lstat64(filename, &sbuf) < 0) { + fprintf(stderr, "lstat64 failed on "); + perror(filename); + return(1); + } + + /* 98789 is greater than 2^16 (65536) */ + if ((__u32)sbuf.st_uid == 98789 || (__u32)sbuf.st_gid == 98789) + return(0); + if (verbose) + fprintf(stderr, "lstat64 on %s gave uid=%d, gid=%d\n", + filename, sbuf.st_uid, sbuf.st_gid); + return(1); +} + +int +haschown32(char *filename) +{ + if (check_big_ID(filename) == 0) + return(0); + + if (chown(filename, 98789, 98789) < 0) { + fprintf(stderr, "chown failed on "); + perror(filename); + return(1); + } + + if (check_big_ID(filename) == 0) + return(0); + return (1); +} + +int +hasxfsquota(int type, int q, char *device) +{ + fs_quota_stat_t qstat; + int qcmd; + + memset(&qstat, 0, sizeof(fs_quota_stat_t)); + qcmd = QCMD(Q_XGETQSTAT, type); + if (quotactl(qcmd, device, 0, (caddr_t)&qstat) < 0) { + if (verbose) + perror("quotactl"); + return (1); + } + else if (q == 0) + return (0); + else if (q == XFS_QUOTA_UDQ_ENFD && qstat.qs_flags & XFS_QUOTA_UDQ_ENFD) + return (0); + else if (q == XFS_QUOTA_GDQ_ENFD && qstat.qs_flags & XFS_QUOTA_GDQ_ENFD) + return (0); + else if (q == XFS_QUOTA_UDQ_ACCT && qstat.qs_flags & XFS_QUOTA_UDQ_ACCT) + return (0); + else if (q == XFS_QUOTA_GDQ_ACCT && qstat.qs_flags & XFS_QUOTA_GDQ_ACCT) + return (0); + if (verbose) + fprintf(stderr, "quota type (%d) not available\n", q); + return (1); +} + +int +main(int argc, char **argv) +{ + int c; + int cflag = 0; + int gflag = 0; + int Gflag = 0; + int qflag = 0; + int uflag = 0; + int Uflag = 0; + char *fs; + + while ((c = getopt(argc, argv, "cgGquUv")) != EOF) { + switch (c) { + case 'c': + cflag++; + break; + case 'g': + gflag++; + break; + case 'G': + Gflag++; + break; + case 'q': + qflag++; + break; + case 'u': + uflag++; + break; + case 'U': + Uflag++; + break; + case 'v': + verbose++; + break; + default: + usage(); + } + } + + if (!cflag && !uflag && !gflag && !qflag && !Uflag && !Gflag) + usage(); + if (optind != argc-1) + usage(); + fs = argv[argc-1]; + + if (cflag) + return(haschown32(fs)); + if (qflag) + return(hasxfsquota(0, 0, fs)); + if (gflag) + return(hasxfsquota(GRPQUOTA, XFS_QUOTA_GDQ_ENFD, fs)); + if (uflag) + return(hasxfsquota(USRQUOTA, XFS_QUOTA_UDQ_ENFD, fs)); + if (Gflag) + return(hasxfsquota(GRPQUOTA, XFS_QUOTA_GDQ_ACCT, fs)); + if (Uflag) + return(hasxfsquota(USRQUOTA, XFS_QUOTA_UDQ_ACCT, fs)); + + fprintf(stderr, "feature: dunno what you're doing?\n"); + return(1); +} diff -rNu linux-2.4.7/cmd/xfstests/src/fill.c linux-2.4-xfs/cmd/xfstests/src/fill.c --- linux-2.4.7/cmd/xfstests/src/fill.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/fill.c Sun Jan 14 23:01:19 2001 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include + +/* + * fill pathname key nbyte + * + * use key to seed random number generator so data is deterministic + * + * lines are at most 72 bytes long so diff(1) does not choke + */ + +int +main(int argc, char **argv) +{ + FILE *f; + unsigned int seed; + long i; + int nbyte; + char *hdr; + char *hp; + char c; + + /* quick and dirty, no args checking */ + if ((f = fopen(argv[1], "w")) == NULL) { + fprintf(stderr, "fill: cannot create \"%s\": %s\n", argv[1], strerror(errno)); + exit(1); + } + seed = 0; + i = 0; + while (argv[2][i]) { + seed <<= 8; + seed |= argv[2][i]; + i++; + } + srand(seed); + + nbyte = atoi(argv[3]); + + /* + * line format + * + * byte offset @ start of this line XXXXXXXXXXXX + * test iteration number XXXX + * key (usually file name) argv[2] + * random bytes to fill the line + */ + + hdr = (char *)malloc(12+1+4+1+strlen(argv[2])+1+1); + sprintf(hdr, "%012ld %04d %s ", (long int)0, 0, argv[2]); + hp = hdr; + + for (i = 0; i < nbyte-1; i++) { + if (*hp) { + c = *hp; + hp++; + } + else if ((i % 72) == 71) + c = '\n'; + else + c = 32+(rand() % (128-32)); + fputc(c, f); + if (c == '\n') { + hp = hdr; + sprintf(hdr, "%012ld %04d %s ", i+1, 0, argv[2]); + } + } + fputc('\n', f); + + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/src/fill2.c linux-2.4-xfs/cmd/xfstests/src/fill2.c --- linux-2.4.7/cmd/xfstests/src/fill2.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/fill2.c Wed May 9 02:03:16 2001 @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + + +/* + * fill2: + * Derived from fill.c, adds command line options, block boundary marking + * and allows me to tweak to suit fill2fs without breaking other qa tests. + * This version marks block boundaries (512, 1k, 4k and 16k) within the file + * using characters guaranteed not to appear anywhere else, this may allow + * simple checks in future which can inspect these offsets and ensure one of + * of the four characters is present. Also fixes off-by-one error in fill.c + * and is more careful about checking when write operations fail - this is + * needed by fill2fs to ensure that the number of bytes written is accurately + * determined. + * + * To compile standalone on IRIX: cc -DTOOL_ONLY -o fill2 fill2.c -lgen + * + * $Id$ + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef TOOL_ONLY +#include +#else +#define constpp char * const * +#endif /* TOOL_ONLY */ + +#define N(x) (sizeof(x)/sizeof(x[0])) + +/* function prototypes */ +static void illegal(char *, char *); +static void reqval(char, char * [], int); +static void respec(char, char * [], int); +static void unknown(char, char *); +static void usage(void); +static char *progname; + +char *dopts[] = { "nbytes", "linelength", "seed", "file", NULL }; +enum { D_NBYTES, D_LINELENGTH, D_SEED, D_FILE, D_ISSET, D_NUM }; +int dflags[D_NUM] = { 0 }; +char *bopts[] = { "512", "1k", "4k", "16k" }; +enum { B_512, B_1K, B_4K, B_16K, B_ISSET, B_NUM }; +int bflags[B_NUM] = { 0 }; + + +/* + * block boundaries + * + */ + +/* block boundaries which should be flagged in the output file */ +/* flag is the character that should be used to indicate each type */ +/* of block boundary */ + + +struct s_block_type { + int mark; + int size; + char flag; +}; + +static struct s_block_type btypes[] = { + { 0, 512, '!' }, /* 512 */ + { 0, 1024, '"' }, /* 1k */ + { 0, 4096, '#' }, /* 4k */ + { 0, 16384, '$' }, /* 16k */ +}; + +/* + * main + * + */ + +int +main(int argc, char **argv) +{ + int status = 0; /* return status */ + int c; /* current option character */ + char *p; /* for getsubopt calls */ + long nbytes; /* total number of bytes to write */ + int dlen; /* length of normal output data line */ + const char *dseed = NULL; /* input string for seeding rand */ + unsigned int seed; /* seed for output data */ + char *dfile = NULL; /* where to write output */ + + FILE *f; /* output file */ + char *dbuf; /* output line buffer */ + char bbuf[50]; /* block boundary string */ + char *active = NULL; /* active buffer to copy out of */ + size_t hlen; /* header length (bytes+key) in output */ + /* lines */ + char *hptr; /* pointer to end of header */ + char *ptr; /* current position to copy from */ + int blktype = 0; /* current block boundary type */ + int boundary; /* set if current output char lies on */ + /* block boundary */ + long i; + int j; + int l = 0; + + + /* defaults */ + progname = basename(argv[0]); + nbytes = 1024 * 1024; + dlen = 73; /* includes the trailing newline */ + + while ((c = getopt(argc, argv, "d:b:")) != EOF) { + switch (c) { + case 'd': + if (dflags[D_ISSET]) + respec('d', NULL, 0); + dflags[D_ISSET] = 1; + + p = optarg; + while (*p != '\0') { + char *value; + switch (getsubopt(&p, (constpp)dopts, &value)) { + case D_NBYTES: + if (! value) reqval('d', dopts, D_NBYTES); + if (dflags[D_NBYTES]) respec('d', dopts, D_NBYTES); + dflags[D_NBYTES] = 1; + nbytes = strtol(value, &ptr, 10); + if (ptr == value) illegal(value, "d nbytes"); + break; + + case D_LINELENGTH: + if (! value) reqval('d', dopts, D_LINELENGTH); + if (dflags[D_LINELENGTH]) respec('d', dopts, D_LINELENGTH); + dflags[D_LINELENGTH] = 1; + dlen = (int) strtol(value, &ptr, 10) + 1; + if (ptr == value) illegal(value, "d linelength"); + break; + + case D_SEED: + if (! value) reqval('d', dopts, D_SEED); + if (dflags[D_SEED]) respec('D', dopts, D_SEED); + dflags[D_SEED] = 1; + dseed = value; + break; + + case D_FILE: + if (! value) reqval('d', dopts, D_FILE); + if (dflags[D_FILE]) respec('d', dopts, D_FILE); + dflags[D_FILE] = 1; + dfile = value; + break; + + default: + unknown('d', value); + } + } + break; + + case 'b': + if (bflags[B_ISSET]) + respec('b', NULL, 0); + bflags[B_ISSET] = 1; + + p = optarg; + while (*p != '\0') { + char *value; + switch (getsubopt(&p, (constpp)bopts, &value)) { + case B_512: + if (value) illegal(value, "b 512"); + if (bflags[B_512]) respec('b', bopts, B_512); + bflags[B_512] = 1; + btypes[0].mark = 1; + break; + + case B_1K: + if (value) illegal(value, "b 1k"); + if (bflags[B_1K]) respec('b', bopts, B_1K); + bflags[B_1K] = 1; + btypes[1].mark = 1; + break; + + case B_4K: + if (value) illegal(value, "b 4k"); + if (bflags[B_4K]) respec('b', bopts, B_4K); + bflags[B_4K] = 1; + btypes[2].mark = 1; + break; + + case B_16K: + if (value) illegal(value, "b 16k"); + if (bflags[B_16K]) respec('b', bopts, B_16K); + bflags[B_16K] = 1; + btypes[3].mark = 1; + break; + + default: + unknown('b', value); + break; + } + } + break; + + case '?': + usage(); + } + } + + if (dflags[D_FILE] && optind != argc) + usage(); + + if (! dflags[D_FILE] && argc - optind != 1) + usage(); + + if (! dflags[D_FILE]) + dfile = argv[optind]; + + if ((f = fopen(dfile, "w")) == NULL) { + fprintf(stderr, "fill2: cannot create \"%s\": %s\n", + dfile, strerror(errno)); + status = 1; + goto cleanup; + } + + if (! dflags[D_SEED]) + dseed = dfile; + + /* seed is an ascii string */ + seed = 0; + i = 0; + while (dseed[i]) { + seed <<= 8; + seed |= dseed[i]; + i++; + } + srand(seed); + + + /* normal data line format: XXXXXXXXXXXX CCCC...CCC CCCCCCCCCCCC...CCC */ + /* block boundary format: CXXXXXXX */ + + dbuf = (char *) malloc(dlen + 1); + hlen = 12+1+strlen(dseed)+1; + assert(hlen < dlen); + hptr = dbuf + hlen; + + for (i = 0; i < nbytes; i++) { + + + /* is this a block boundary? check largest to smallest */ + boundary = 0; + for (j = N(btypes) - 1; j >= 0; j--) { + if (btypes[j].mark) { + /* first time through or just before a block boundary? */ + if (i == 0 || i % btypes[j].size == btypes[j].size - 1) { + boundary = 1; + blktype = j; + break; + } + } + } + + + /* are there block boundaries to check? */ + /* is this the first time through? */ + /* block boundaries take priority over other output */ + if (bflags[B_ISSET] && (i == 0 || boundary)) { + sprintf(bbuf, "%s%c%07ld\n", + i ? "\n" : "", + btypes[blktype].flag, + /* remember i is one less than block boundary */ + i ? (i+1) / btypes[blktype].size : 0); + active = bbuf; + ptr = bbuf; + } + /* are we at the start of a new line? */ + else if (i == 0 + || (active == bbuf && *ptr == '\0') + || (active == dbuf && l == dlen)) + { + sprintf(dbuf, "%012ld %s ", i, dseed); + assert(*hptr == '\0'); + for (ptr = hptr; ptr != dbuf + dlen - 1; ptr++) { + /* characters upto 126 '~' are used */ + /* do not use !"#$ - leave free for use as block markers */ + *ptr = 37 + (rand() % (127 - 37)); + } + *ptr++ = '\n'; + *ptr = '\0'; + assert(ptr == dbuf + dlen); + active = dbuf; + ptr = dbuf; + l = 0; + } + else { + /* continue copying from the active buffer */ + } + + /* output one new character from current buffer */ + if (fputc(*ptr++, f) == EOF) { + fprintf(stderr, "fill2: could not write character to \"%s\": %s\n", + dfile, strerror(errno)); + status = 1; + goto cleanup; + } + if (active == dbuf) l++; + + } + + cleanup: + + /* close file and flush buffers - check if this fails */ + if (fclose(f) != 0) { + fprintf(stderr, "fill2: fclose() on \"%s\" failed: %s\n", + dfile, strerror(errno)); + status = 1; + } + exit(status); +} + + + +/* + * suboption checking functions + * + */ + +static void +illegal(char *value, char *opt) +{ + fprintf(stderr, "%s: Error: Illegal value \"%s\" for -%s option\n", + progname, value, opt); + usage(); +} +static void +reqval(char opt, char *tab[], int idx) +{ + fprintf(stderr, "%s: Error: -%c %s option requires a value\n", + progname, opt, tab[idx]); + usage(); +} +static void +respec(char opt, char *tab[], int idx) +{ + fprintf(stderr, "%s: Error: ", progname); + fprintf(stderr, "-%c ", opt); + if (tab) fprintf(stderr, "%s ", tab[idx]); + fprintf(stderr, "option respecified\n"); + usage(); +} +static void +unknown(char opt, char *s) +{ + fprintf(stderr, "%s: Error: Unknown option -%c %s\n", progname, opt, s); + usage(); +} +static void +usage(void) +{ + fprintf(stderr, "Usage: %s [options] filename\n" +"Options:\n" +" -d [nbytes=num,linelength=num, output data properties\n" +" seed=string,file=name]\n" +" -b [512,1k,4k,16k] where to mark block boundaries\n", progname); + exit(2); +} diff -rNu linux-2.4.7/cmd/xfstests/src/fill2attr linux-2.4-xfs/cmd/xfstests/src/fill2attr --- linux-2.4.7/cmd/xfstests/src/fill2attr Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/fill2attr Thu Feb 8 22:00:02 2001 @@ -0,0 +1,144 @@ +#!/usr/bin/perl -w +# + +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# + +# +# fill2attr: +# +# $Id$ +# + +use File::Basename; + + +# returns numbers with a normal distribution +sub normal { + my($mean) = $_[0]; + my($stddev) = $_[1]; + + $x = -6.0; + for (my $i = 0; $i < 12; $i++) { + $x += rand; + } + + $x = $mean + $stddev * $x; + return $x; +} + + +# +# determine script location and find fill2 +# +chomp($cwd = `pwd`); +chomp($_ = `which fill2 2>&1 | head -1`); +if (-x $_) { + # look in the path + $fill2 = fill2; +} +else { + # in the same directory - get absolute path + chomp($dirname = dirname $0); + if ($dirname =~ m!^/.*!) { + $fill2 = $dirname . "/fill2"; + } + else { + # relative + $fill2 = $cwd . "/" . $dirname . "/fill2"; + } + if (! -x $fill2) { + die("Error: $0: can't find fill2, tried \"$fill2\"\n"); + } +} + + +# for each file attach a random number of attributes +# each filled with a random amount of data +# attribute name is the checksum of the data stored within +# the attribute + +$status = 0; # return status + +while (<>) { + + chomp($file = $_); + die("Error: $0: $file not found\n") + if ( ! -e $file); + + if ($0 =~ /fill2attr$/) { + + # attach attributes to this file + my $num = abs(int(normal(3, 1))); + my $seed = 1; + my $verbose = 1; + my $tmp = "/tmp/fill2attr$$"; + + for (my $i = 0; $i < $num; $i++) { + my $size = abs(int(normal(256, 200))); + my $cmd = "$fill2 -d nbytes=$size,linelength=72,seed=$seed -b 4k $tmp"; + $cmd .= " > /dev/null 2>&1" if (! $verbose); + + if (system($cmd) != 0) { + die("Error $0: can't create $tmp\n"); + } + + chomp($_ = `sum -r $tmp`); + ($sum) = split(/\s+/); + if (system("cat $tmp | attr -s $sum $file > /dev/null 2>&1") != 0) { + die("Error $0: could not attach attribute:\n" . `cat $tmp` . "\n"); + } + } + } + elsif ($0 =~ /fill2attr_check/) { + + # get the attributes for this file + $cmd = "attr -q -l $file |"; + open LIST, $cmd; + @labels = ; + close LIST or die("Error listing attributes: $!"); + chomp(@labels); + + # check attribute contents + foreach my $label (@labels) { + ($sum) = split(/\s+/, `attr -q -g $label $file | sum -r`); + if ($sum ne $label) { + warn("Attribute \"$label\" does not match " . + "attribute contents for file $file\n"); + $status = 1; + } + } + } +} + +exit($status); diff -rNu linux-2.4.7/cmd/xfstests/src/fill2fs linux-2.4-xfs/cmd/xfstests/src/fill2fs --- linux-2.4.7/cmd/xfstests/src/fill2fs Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/fill2fs Tue Apr 3 20:45:38 2001 @@ -0,0 +1,378 @@ +#!/usr/bin/perl -w +# + +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# + +# +# fill2fs: +# Fill a filesystem, or write a specified number of bits. +# Script runs deterministically given a seed for the random number +# generator. Will generate the same set of directories and files, +# with the only source of variation the precise point at which the +# filesystem fills up. When used with XFS filesystems, and when +# the filesize is small, XFS pre-allocation may cause the filesystem +# to "fill up" before the actual disk space is gone. Using this +# script repeatedly, with a delay between invocations, to account +# for extent flushing, will allow more of the filesystem to be filled. +# +# All generated files are checksummed and this sum is stored in the +# filename (files are named: ..data. +# Normally script is invoked using the --list option, which causes all +# data files to be written to standard output (--list=-) or a file +# (--list=filename). This list can be fed into fill2fs_check, which +# recomputes the checksums and flags any errors. +# +# The --stddev=0 forces all files to be precisely --filesize bytes in +# length, some other value (--stddev=val) produces filesizes with a +# normal distribution with standard deviation val. If not specified +# most file sizes are set to lie within 30% of the requested file size. +# +# fill2fs is not guaranteed to write the requested number of bytes, or +# fill the filesystem completely. However, it and fill2 are both very +# careful about establishing when write operations fail. When the +# --verbose option is used the number of bytes "actually written" +# is guaranteed to be the number of bytes on disk. +# +# $Id$ +# + +use Getopt::Long; +use File::Basename; + +chomp($os = `uname`); + +# +# fsinfo: get filesystem info put it into the global namespace, initialises: +# $dev, $type, $blocks, $used, $avail, $cap, $mnt, $mnt_options +# $fsblocks, $fsblocksize, $agblocks, $agcount, $imax_pct, $logblocks +# $logstart, $internal +# +# if $verbose is set then output fs info to STDERR +# + +sub fsinfo { + my($file) = $_[0]; + + # filesystem space and mount point + + $cmd = "df" if ($os =~ /IRIX/); + $cmd = "df -P -T --block-size=512" if ($os =~ /Linux/); + chomp($_ = `$cmd $file | tail -1`); + $n = ($dev, $type, $blocks, $used, $avail, $cap, $mnt) = split(/ +/); + die("df failed") if ($n != 7); + + if ($fscheck && $type ne "xfs") { + die("Error: $progname: filesystem is not xfs") + } + + # how was this filesystem mounted + $_ = `grep $dev /etc/mtab`; + @mtab = split(/ +/); + $mnt_options = $mtab[3]; + + # if we're running as root run xfs_db on the filesystem + if ($> == 0) { + # xfs_db: read only, use the default superblock, print everything + die("Error: $progname: can't read device: \"$dev\"\n") if (! -r $dev); + $_=`xfs_db -r -c sb -c p $dev`; + # multiline matching ^$ refers to individual lines... + /^dblocks = (\d+)$/m; $fsblocks=$1; + /^blocksize = (\d+)$/m; $fsblocksize=$1; + /^agblocks = (\d+)$/m; $agblocks=$1; + /^agcount = (\d+)$/m; $agcount=$1; + /^imax_pct = (\d+)$/m; $imax_pct=$1; + /^logblocks = (\d+)$/m; $logblocks=$1; + /^logstart = (\d+)$/m; $logstart=$1; + $internal = $logstart > 0 ? " (internal)" : ""; + + $verbose && print STDERR <<"EOF" +Filesystem information: + type=$type; device=$dev + mount point=$mnt; mount options=$mnt_options + percent full=$cap; size (512 byte blocks)=$blocks; used=$used; avail=$avail + total filesystem size (fs blocks)=$fsblocks; fs block size=$fsblocksize; imax_pct=$imax_pct + agcount=$agcount; agblocks=$agblocks; logblocks=$logblocks; logstart=$logstart$internal +EOF + } +} + + +# returns numbers with a normal distribution +sub normal { + my($mean) = $_[0]; + my($stddev) = $_[1]; + + $x = -6.0; + for ($i = 0; $i < 12; $i++) { + $x += rand; + } + + $x = $mean + $stddev * $x; + return $x; +} + +# +# determine script location and find fill2 +# + +chomp($cwd = `pwd`); +chomp($_ = `which fill2 2>&1 | head -1`); +if (-x $_) { + # look in the path + $fill2 = fill2; +} +else { + # in the same directory - get absolute path + chomp($dirname = dirname $0); + if ($dirname =~ m!^/.*!) { + $fill2 = $dirname . "/fill2"; + } + else { + # relative + $fill2 = $cwd . "/" . $dirname . "/fill2"; + } + if (! -x $fill2) { + die("Error: $progname: can't find fill2, tried \"$fill2\"\n"); + } +} + +# +# process/check args +# + +$progname=$0; +GetOptions("bytes=f" => \$bytes, + "dir=s" => \$root, + "filesize=i" => \$filesize, + "force!" => \$force, + "help!" => \$help, + "list=s" => \$list, + "fscheck!" => \$fscheck, + "percent=f" => \$percentage, + "seed=i" => \$seed, + "stddev=i" => \$stddev, + "sync=i" => \$sync_bytes, + "verbose!" => \$verbose); + + +# check/remove output directory, get filesystem info +if (defined $help + || (! defined $root && @ARGV != 1) + || (defined $root && @ARGV == 1)) +{ + # newline at end of die message suppresses line number + print STDERR <<"EOF"; +Usage: $progname [options] root_dir +Options: + --bytes=num total number of bytes to write + --dir=name where to write files + --filesize=num set all files to num bytes in size + --force overwrite any existing files + --help print this help message + --list=filename store created files to filename (- for stdout) + --percent=num percentage of filesystem to fill + --seed=num seed for random number generator + --stddev set file size standard deviation + --sync=num sync every num bytes written + --verbose verbose output +EOF + exit(1) unless defined $help; + # otherwise... + exit(0); + +} + + +# +# lots of boring argument checking +# + +# root directory and filesystem info +$root = $ARGV[0] if (@ARGV == 1); +if (-e $root) { + if (! $force) { + die("Error: $progname: \"$root\" already exists\n"); + } + else { + $verbose && print STDERR "Removing \"$root\"... "; + system("rm -rf $root"); + $verbose && print STDERR "done\n"; + } +} +chomp($root_dir = dirname $root); +fsinfo $root_dir; + +# $list can be "-" for stdout, perl open ">-" opens stdout +open LIST, ">$list" if (defined $list); + +# how many bytes should we write +if (defined $bytes && defined $percentage) { + die("Error: $progname: can't specify --bytes and --percent\n"); +} +# check percentage +if (defined $percentage && ($percentage < 0 || $percentage > 100)) { + die("Error: $progname: invalid percentage\n"); +} +if (! defined $bytes && ! defined $percentage) { + $bytes = $avail * 512; + $verbose && print STDERR <<"EOF"; +Neither --bytes nor --percent specified: filling filesystem ($bytes bytes) +EOF +} +elsif (! defined $bytes) { + $bytes = int($blocks * 512 * $percentage / 100.0); +} +if (($bytes > $blocks * 512) || (! $force && $bytes > $avail * 512)) +{ + die("Error: $progname: not enough free disk space, disk is $cap full\n"); +} + + + +# +# To get fix sized files set stddev to 0. The default is to make most files +# within 30% of the requested filesize (or 4k if filesize is not specified). +# Set the standard deviation to be half of the required percentage: ~95% of +# samples lie within 2 standard deviations of the mean. +# + +$filesize = 4096 if (! defined $filesize); +die("Error: $progname: --filesize must be >= 1 byte") if ($filesize < 1); +$stddev = 0.5 * 0.3 * $filesize if (! defined $stddev); +$seed = time ^ $$ if (! defined $seed); +srand $seed; +umask 0000; +mkdir $root, 0777; +chdir $root; +$total = 0; +$files = 0; +$dirs = 0; +$d = 0; +$sync_cnt = 1; + +# +# fill filesystem +# + +$verbose && print STDERR "Writing $bytes bytes (seed is $seed)... "; +while ($total < $bytes) { + $r = rand(3.0); + + if (($d == 0 && $r < 0.5) || ($d > 0 && $r >= 0.0 && $r < 2.4)) { + # create a new data file + $n = sprintf("%04d", $names[$d]++); + if ($stddev == 0) { + $size = $filesize; + } + else { + $size = int(normal($filesize, $stddev)); + } + $left = $bytes - $total; + $size = 0 if ($size < 0); + $size = $left if ($size > $left); + + # fill2 will fail if the filesystem is full - not an error! + $cmd = "$fill2 -d nbytes=$size,linelength=72,seed=$n -b 4k $n"; + $cmd .= " > /dev/null 2>&1" if (! $verbose); + if (system($cmd) != 0) { + if ($verbose) { + warn("can't create a file - assuming filesystem is full\n"); + } + if (-e $n && unlink($n) != 1) { + warn("couldn't delete \"$n\""); + } + last; + } + $_ = `sum -r $n`; + ($sum) = split(/ +/); + $name = "$n.$sum.data"; + $cmd = "mv $n $name"; # perl rename failed earlier than using mv + $cmd .= " > /dev/null 2>&1" if (! $verbose); + if (system($cmd) != 0) { + if ($verbose) { + warn("can't rename a file - assuming filesystem is full\n"); + } + if (-e $name && unlink($name) != 1) { + warn("couldn't delete \"$name\""); + } + last; + } + if (defined $list) { + chomp($_ = `pwd`); + printf LIST ("%s/%s\n", $_, $name); + } + $total += $size; + $files++; + + if (defined $sync_bytes && int($total / $sync_bytes) > $sync_cnt) { + $sync_cnt++; + system("sync"); + } + } + # note that if d==0 create directories more frequently than files + elsif (($d == 0 && $r >= 0.5) || ($d > 0 && $r >= 2.4 && $r < 2.7)) { + # create a new directory and descend + $name = sprintf("%04d.d", $names[$d]++); + if (! mkdir($name, 0777)) { + warn("can't make a directory - assuming filesystem is full\n"); + last; + } + chdir($name) or die(); + $d++; + $dirs++; + } + elsif ($r >= 2.7 && $r < 3.0) { + # pop up to the parent directory same probability as descend + die("Error: $progname: panic: shouldn't be here!") if ($d == 0); + chdir("..") or die(); + $d--; + } +} +# make sure we return to the original working directory +chdir($cwd) or die(); +$verbose && print STDERR "done\n"; +$verbose && print STDERR "$total bytes (in $files files and $dirs directories) were actually written\n"; +close LIST; +exit(0) if ($total = $bytes); +exit(1) if ($total == 0); +exit(2) if ($total > 0 && $total < $bytes); + +# - to sum all generated data: +# find /home/fill/ -name \*data | xargs ls -al | awk '{total = total + $5; } END { printf("total = %d bytes\n", total); }' +# - to find any files not of the required size +# find . -name \*data -a \! -size 4096c +# - count new files +# find ./fill -name \*.data | wc +# - count new directories +# find ./fill -name \*.d | wc diff -rNu linux-2.4.7/cmd/xfstests/src/fill2fs_check linux-2.4-xfs/cmd/xfstests/src/fill2fs_check --- linux-2.4.7/cmd/xfstests/src/fill2fs_check Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/fill2fs_check Thu Apr 26 18:48:06 2001 @@ -0,0 +1,64 @@ +#!/usr/bin/perl -w +# + +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# + +# +# fill2fs_check: +# Read a manifest generated by fill2fs from the command +# line or stdin, checksum every file listed +# +# $Id: fill2fs_check,v 1.1 2001/04/26 23:46:25 ajag Exp ajag $ +# + +use File::Basename; + +$status = 0; + +file: while (<>) { + chomp; + if ( ! -e $_) { + print "$0: $_ not found\n"; + $status = 1; next file; + } + (undef, $expected) = split(/\./, basename $_); + chomp($sum = `sum -r $_`); + ($actual) = split(/\s+/, $sum); + if ($actual != $expected) { + print "$0: checksum is wrong for \"$_\"\n"; + $status = 1; next file; + } +} + +exit($status); diff -rNu linux-2.4.7/cmd/xfstests/src/fsstress.c linux-2.4-xfs/cmd/xfstests/src/fsstress.c --- linux-2.4.7/cmd/xfstests/src/fsstress.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/fsstress.c Mon Mar 5 14:18:45 2001 @@ -0,0 +1,2490 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "global.h" + +#define XFS_ERRTAG_MAX 17 + +typedef enum { + OP_ALLOCSP, + OP_ATTR_REMOVE, + OP_ATTR_SET, + OP_BULKSTAT, + OP_BULKSTAT1, + OP_CHOWN, + OP_CREAT, + OP_DREAD, + OP_DWRITE, + OP_FDATASYNC, + OP_FREESP, + OP_FSYNC, + OP_GETDENTS, + OP_LINK, + OP_MKDIR, + OP_MKNOD, + OP_READ, + OP_READLINK, + OP_RENAME, + OP_RESVSP, + OP_RMDIR, + OP_STAT, + OP_SYMLINK, + OP_SYNC, + OP_TRUNCATE, + OP_UNLINK, + OP_UNRESVSP, + OP_WRITE, + OP_LAST +} opty_t; + +typedef void (*opfnc_t)(int, long); + +typedef struct opdesc { + opty_t op; + char *name; + opfnc_t func; + int freq; + int iswrite; +} opdesc_t; + +typedef struct fent { + int id; + int parent; +} fent_t; + +typedef struct flist { + int nfiles; + int nslots; + int tag; + fent_t *fents; +} flist_t; + +typedef struct pathname { + int len; + char *path; +} pathname_t; + +#define FT_DIR 0 +#define FT_DIRm (1 << FT_DIR) +#define FT_REG 1 +#define FT_REGm (1 << FT_REG) +#define FT_SYM 2 +#define FT_SYMm (1 << FT_SYM) +#define FT_DEV 3 +#define FT_DEVm (1 << FT_DEV) +#define FT_RTF 4 +#define FT_RTFm (1 << FT_RTF) +#define FT_nft 5 +#define FT_ANYm ((1 << FT_nft) - 1) +#define FT_REGFILE (FT_REGm | FT_RTFm) +#define FT_NOTDIR (FT_ANYm & ~FT_DIRm) + +#define FLIST_SLOT_INCR 16 +#define NDCACHE 64 + +#define MAXFSIZE ((1ULL << 63) - 1ULL) +#define MAXFSIZE32 ((1ULL << 40) - 1ULL) + +void allocsp_f(int, long); +void attr_remove_f(int, long); +void attr_set_f(int, long); +void bulkstat_f(int, long); +void bulkstat1_f(int, long); +void chown_f(int, long); +void creat_f(int, long); +void dread_f(int, long); +void dwrite_f(int, long); +void fdatasync_f(int, long); +void freesp_f(int, long); +void fsync_f(int, long); +void getdents_f(int, long); +void link_f(int, long); +void mkdir_f(int, long); +void mknod_f(int, long); +void read_f(int, long); +void readlink_f(int, long); +void rename_f(int, long); +void resvsp_f(int, long); +void rmdir_f(int, long); +void stat_f(int, long); +void symlink_f(int, long); +void sync_f(int, long); +void truncate_f(int, long); +void unlink_f(int, long); +void unresvsp_f(int, long); +void write_f(int, long); + +opdesc_t ops[] = { + { OP_ALLOCSP, "allocsp", allocsp_f, 1, 1 }, + { OP_ATTR_REMOVE, "attr_remove", attr_remove_f, /* 1 */ 0, 1 }, + { OP_ATTR_SET, "attr_set", attr_set_f, /* 2 */ 0, 1 }, + { OP_BULKSTAT, "bulkstat", bulkstat_f, 1, 0 }, + { OP_BULKSTAT1, "bulkstat1", bulkstat1_f, 1, 0 }, + { OP_CHOWN, "chown", chown_f, 3, 1 }, + { OP_CREAT, "creat", creat_f, 4, 1 }, + { OP_DREAD, "dread", dread_f, 4, 0 }, + { OP_DWRITE, "dwrite", dwrite_f, 4, 1 }, + { OP_FDATASYNC, "fdatasync", fdatasync_f, 1, 1 }, + { OP_FREESP, "freesp", freesp_f, 1, 1 }, + { OP_FSYNC, "fsync", fsync_f, 1, 1 }, + { OP_GETDENTS, "getdents", getdents_f, 1, 0 }, + { OP_LINK, "link", link_f, 1, 1 }, + { OP_MKDIR, "mkdir", mkdir_f, 2, 1 }, + { OP_MKNOD, "mknod", mknod_f, 2, 1 }, + { OP_READ, "read", read_f, 1, 0 }, + { OP_READLINK, "readlink", readlink_f, 1, 0 }, + { OP_RENAME, "rename", rename_f, 2, 1 }, + { OP_RESVSP, "resvsp", resvsp_f, 1, 1 }, + { OP_RMDIR, "rmdir", rmdir_f, 1, 1 }, + { OP_STAT, "stat", stat_f, 1, 0 }, + { OP_SYMLINK, "symlink", symlink_f, 2, 1 }, + { OP_SYNC, "sync", sync_f, 1, 0 }, + { OP_TRUNCATE, "truncate", truncate_f, 2, 1 }, + { OP_UNLINK, "unlink", unlink_f, 1, 1 }, + { OP_UNRESVSP, "unresvsp", unresvsp_f, 1, 1 }, + { OP_WRITE, "write", write_f, 4, 1 }, +}, *ops_end; + +flist_t flist[FT_nft] = { + { 0, 0, 'd', NULL }, + { 0, 0, 'f', NULL }, + { 0, 0, 'l', NULL }, + { 0, 0, 'c', NULL }, + { 0, 0, 'r', NULL }, +}; + +int dcache[NDCACHE]; +int errrange; +int errtag; +opty_t *freq_table; +int freq_table_size; +xfs_fsop_geom_t geom; +char *homedir; +int *ilist; +int ilistlen; +off64_t maxfsize; +char *myprog; +int namerand; +int nameseq; +int nops; +int nproc = 1; +int operations = 1; +int procid; +int rtpct; +unsigned long seed = 0; +ino_t top_ino; +int verbose = 0; + +void add_to_flist(int, int, int); +void append_pathname(pathname_t *, char *); +int attr_list_path(pathname_t *, char *, const int, int, + attrlist_cursor_t *); +int attr_remove_path(pathname_t *, const char *, int); +int attr_set_path(pathname_t *, const char *, const char *, const int, int); +void check_cwd(void); +int creat_path(pathname_t *, mode_t); +void dcache_enter(int, int); +void dcache_init(void); +fent_t *dcache_lookup(int); +void dcache_purge(int); +void del_from_flist(int, int); +int dirid_to_name(char *, int); +void doproc(void); +void fent_to_name(pathname_t *, flist_t *, fent_t *); +void fix_parent(int, int); +void free_pathname(pathname_t *); +int generate_fname(fent_t *, int, pathname_t *, int *, int *); +int get_fname(int, long, pathname_t *, flist_t **, fent_t **, int *); +void init_pathname(pathname_t *); +int lchown_path(pathname_t *, uid_t, gid_t); +int link_path(pathname_t *, pathname_t *); +int lstat64_path(pathname_t *, struct stat64 *); +void make_freq_table(void); +int mkdir_path(pathname_t *, mode_t); +int mknod_path(pathname_t *, mode_t, dev_t); +void namerandpad(int, char *, int); +int open_path(pathname_t *, int); +DIR *opendir_path(pathname_t *); +void process_freq(char *); +int readlink_path(pathname_t *, char *, size_t); +int rename_path(pathname_t *, pathname_t *); +int rmdir_path(pathname_t *); +void separate_pathname(pathname_t *, char *, pathname_t *); +void show_ops(int, char *); +int stat64_path(pathname_t *, struct stat64 *); +int symlink_path(const char *, pathname_t *); +int truncate64_path(pathname_t *, off64_t); +int unlink_path(pathname_t *); +void usage(void); +void write_freq(void); +void zero_freq(void); + +int main(int argc, char **argv) +{ + char buf[10]; + int c; + char *dirname = NULL; + int fd; + int i; + int j; + char *p; + int stat; + struct timeval t; + ptrdiff_t srval; + int nousage=0; + xfs_error_injection_t err_inj; + + errrange = errtag = 0; + umask(0); + nops = sizeof(ops) / sizeof(ops[0]); + ops_end = &ops[nops]; + myprog = argv[0]; + while ((c = getopt(argc, argv, "d:e:f:i:n:p:rs:vwzHS")) != -1) { + switch (c) { + case 'd': + dirname = optarg; + break; + case 'e': + sscanf(optarg, "%d", &errtag); + if (errtag < 0) { + errtag = -errtag; + errrange = 1; + } else if (errtag == 0) + errtag = -1; + if (errtag >= XFS_ERRTAG_MAX) { + fprintf(stderr, + "error tag %d too large (max %d)\n", + errtag, XFS_ERRTAG_MAX - 1); + exit(1); + } + break; + case 'f': + process_freq(optarg); + break; + case 'i': + ilist = realloc(ilist, ++ilistlen * sizeof(*ilist)); + ilist[ilistlen - 1] = strtol(optarg, &p, 16); + break; + case 'n': + operations = atoi(optarg); + break; + case 'p': + nproc = atoi(optarg); + break; + case 'r': + namerand = 1; + break; + case 's': + seed = strtoul(optarg, NULL, 0); + break; + case 'v': + verbose = 1; + break; + case 'w': + write_freq(); + break; + case 'z': + zero_freq(); + break; + case 'S': + show_ops(0, NULL); + printf("\n"); + nousage=1; + break; + case '?': + fprintf(stderr, "%s - invalid parameters\n", + myprog); + /* fall through */ + case 'H': + usage(); + exit(1); + } + } + + if (!dirname) { + /* no directory specified */ + if (!nousage) usage(); + exit(1); + } + + (void)mkdir(dirname, 0777); + if (chdir(dirname) < 0) { + perror(dirname); + exit(1); + } + sprintf(buf, "fss%x", getpid()); + fd = creat(buf, 0666); + if (lseek64(fd, (off64_t)(MAXFSIZE32 + 1ULL), SEEK_SET) < 0) + maxfsize = (off64_t)MAXFSIZE32; + else + maxfsize = (off64_t)MAXFSIZE; + make_freq_table(); + dcache_init(); + setlinebuf(stdout); + if (!seed) { + gettimeofday(&t, (void *)NULL); + seed = (int)t.tv_sec ^ (int)t.tv_usec; + printf("seed = %ld\n", seed); + } + i = ioctl(fd, XFS_IOC_FSGEOMETRY, &geom); + if (i >= 0 && geom.rtblocks) + rtpct = MIN(MAX(geom.rtblocks * 100 / + (geom.rtblocks + geom.datablocks), 1), 99); + else + rtpct = 0; + if (errtag != 0) { + if (errrange == 0) { + if (errtag <= 0) { + srandom(seed); + j = random() % 100; + + for (i = 0; i < j; i++) + (void) random(); + + errtag = (random() % (XFS_ERRTAG_MAX-1)) + 1; + } + } else { + srandom(seed); + j = random() % 100; + + for (i = 0; i < j; i++) + (void) random(); + + errtag += (random() % (XFS_ERRTAG_MAX - errtag)); + } + printf("Injecting failure on tag #%d\n", errtag); + err_inj.errtag = errtag; + err_inj.fd = fd; + srval = ioctl(fd, XFS_IOC_ERROR_INJECTION, &err_inj); + if (srval < -1) { + perror("fsstress - XFS_SYSSGI error injection call"); + close(fd); + unlink(buf); + exit(1); + } + } else + close(fd); + unlink(buf); + for (i = 0; i < nproc; i++) { + if (fork() == 0) { + procid = i; + doproc(); + return 0; + } + } + while (wait(&stat) > 0) + continue; + if (errtag != 0) { + err_inj.errtag = 0; + err_inj.fd = fd; + if((srval = ioctl(fd, XFS_IOC_ERROR_CLEARALL, &err_inj)) != 0) { + fprintf(stderr, "Bad ej clear on %d (%d).\n", fd, errno); + perror("fsstress - XFS_SYSSGI clear error injection call"); + close(fd); + exit(1); + } + close(fd); + } + + return 0; +} + +void +add_to_flist(int ft, int id, int parent) +{ + fent_t *fep; + flist_t *ftp; + + ftp = &flist[ft]; + if (ftp->nfiles == ftp->nslots) { + ftp->nslots += FLIST_SLOT_INCR; + ftp->fents = realloc(ftp->fents, ftp->nslots * sizeof(fent_t)); + } + fep = &ftp->fents[ftp->nfiles++]; + fep->id = id; + fep->parent = parent; +} + +void +append_pathname(pathname_t *name, char *str) +{ + int len; + + len = strlen(str); +#ifdef DEBUG + if (len && *str == '/' && name->len == 0) { + fprintf(stderr, "fsstress: append_pathname failure\n"); + chdir(homedir); + abort(); + /* NOTREACHED */ + } +#endif + name->path = realloc(name->path, name->len + 1 + len); + strcpy(&name->path[name->len], str); + name->len += len; +} + +int +attr_list_path(pathname_t *name, char *buffer, const int buffersize, int flags, + attrlist_cursor_t *cursor) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + int rval; + + rval = attr_list(name->path, buffer, buffersize, flags, cursor); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = attr_list_path(&newname, buffer, buffersize, flags, + cursor); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +int +attr_remove_path(pathname_t *name, const char *attrname, int flags) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + int rval; + + rval = attr_remove(name->path, attrname, flags); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = attr_remove_path(&newname, attrname, flags); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +int +attr_set_path(pathname_t *name, const char *attrname, const char *attrvalue, + const int valuelength, int flags) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + int rval; + + rval = attr_set(name->path, attrname, attrvalue, valuelength, flags); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = attr_set_path(&newname, attrname, attrvalue, valuelength, + flags); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +void +check_cwd(void) +{ +#ifdef DEBUG + struct stat64 statbuf; + + if (stat64(".", &statbuf) == 0 && statbuf.st_ino == top_ino) + return; + chdir(homedir); + fprintf(stderr, "fsstress: check_cwd failure\n"); + abort(); + /* NOTREACHED */ +#endif +} + +int +creat_path(pathname_t *name, mode_t mode) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + int rval; + + rval = creat(name->path, mode); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = creat_path(&newname, mode); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +void +dcache_enter(int dirid, int slot) +{ + dcache[dirid % NDCACHE] = slot; +} + +void +dcache_init(void) +{ + int i; + + for (i = 0; i < NDCACHE; i++) + dcache[i] = -1; +} + +fent_t * +dcache_lookup(int dirid) +{ + fent_t *fep; + int i; + + i = dcache[dirid % NDCACHE]; + if (i >= 0 && (fep = &flist[FT_DIR].fents[i])->id == dirid) + return fep; + return NULL; +} + +void +dcache_purge(int dirid) +{ + int *dcp; + + dcp = &dcache[dirid % NDCACHE]; + if (*dcp >= 0 && flist[FT_DIR].fents[*dcp].id == dirid) + *dcp = -1; +} + +void +del_from_flist(int ft, int slot) +{ + flist_t *ftp; + + ftp = &flist[ft]; + if (ft == FT_DIR) + dcache_purge(ftp->fents[slot].id); + if (slot != ftp->nfiles - 1) { + if (ft == FT_DIR) + dcache_purge(ftp->fents[ftp->nfiles - 1].id); + ftp->fents[slot] = ftp->fents[--ftp->nfiles]; + } else + ftp->nfiles--; +} + +fent_t * +dirid_to_fent(int dirid) +{ + fent_t *efep; + fent_t *fep; + flist_t *flp; + + if ((fep = dcache_lookup(dirid))) + return fep; + flp = &flist[FT_DIR]; + for (fep = flp->fents, efep = &fep[flp->nfiles]; fep < efep; fep++) { + if (fep->id == dirid) { + dcache_enter(dirid, fep - flp->fents); + return fep; + } + } + return NULL; +} + +void +doproc(void) +{ + struct stat64 statbuf; + char buf[10]; + int opno; + int rval; + opdesc_t *p; + + sprintf(buf, "p%x", procid); + (void)mkdir(buf, 0777); + if (chdir(buf) < 0 || stat64(".", &statbuf) < 0) { + perror(buf); + _exit(1); + } + top_ino = statbuf.st_ino; + homedir = getcwd(NULL, -1); + seed += procid; + srandom(seed); + if (namerand) + namerand = random(); + for (opno = 0; opno < operations; opno++) { + p = &ops[freq_table[random() % freq_table_size]]; + p->func(opno, random()); + /* + * test for forced shutdown by stat'ing the test + * directory. If this stat returns EIO, assume + * the forced shutdown happened. + */ + if (errtag != 0 && opno % 100 == 0) { + rval = stat64(".", &statbuf); + if (rval == EIO) { + fprintf(stderr, "Detected EIO\n"); + return; + } + } + } +} + +void +fent_to_name(pathname_t *name, flist_t *flp, fent_t *fep) +{ + char buf[MAXNAMELEN]; + int i; + fent_t *pfep; + + if (fep == NULL) + return; + if (fep->parent != -1) { + pfep = dirid_to_fent(fep->parent); + fent_to_name(name, &flist[FT_DIR], pfep); + append_pathname(name, "/"); + } + i = sprintf(buf, "%c%x", flp->tag, fep->id); + namerandpad(fep->id, buf, i); + append_pathname(name, buf); +} + +void +fix_parent(int oldid, int newid) +{ + fent_t *fep; + flist_t *flp; + int i; + int j; + + for (i = 0, flp = flist; i < FT_nft; i++, flp++) { + for (j = 0, fep = flp->fents; j < flp->nfiles; j++, fep++) { + if (fep->parent == oldid) + fep->parent = newid; + } + } +} + +void +free_pathname(pathname_t *name) +{ + if (name->path) { + free(name->path); + name->path = NULL; + name->len = 0; + } +} + +int +generate_fname(fent_t *fep, int ft, pathname_t *name, int *idp, int *v) +{ + char buf[MAXNAMELEN]; + flist_t *flp; + int id; + int j; + int len; + + flp = &flist[ft]; + len = sprintf(buf, "%c%x", flp->tag, id = nameseq++); + namerandpad(id, buf, len); + if (fep) { + fent_to_name(name, &flist[FT_DIR], fep); + append_pathname(name, "/"); + } + append_pathname(name, buf); + *idp = id; + *v = verbose; + for (j = 0; !*v && j < ilistlen; j++) { + if (ilist[j] == id) { + *v = 1; + break; + } + } + return 1; +} + +int +get_fname(int which, long r, pathname_t *name, flist_t **flpp, fent_t **fepp, + int *v) +{ + int c; + fent_t *fep; + flist_t *flp; + int i; + int j; + int x; + + for (i = 0, c = 0, flp = flist; i < FT_nft; i++, flp++) { + if (which & (1 << i)) + c += flp->nfiles; + } + if (c == 0) { + if (flpp) + *flpp = NULL; + if (fepp) + *fepp = NULL; + *v = verbose; + return 0; + } + x = (int)(r % c); + for (i = 0, c = 0, flp = flist; i < FT_nft; i++, flp++) { + if (which & (1 << i)) { + if (x < c + flp->nfiles) { + fep = &flp->fents[x - c]; + if (name) + fent_to_name(name, flp, fep); + if (flpp) + *flpp = flp; + if (fepp) + *fepp = fep; + *v = verbose; + for (j = 0; !*v && j < ilistlen; j++) { + if (ilist[j] == fep->id) { + *v = 1; + break; + } + } + return 1; + } + c += flp->nfiles; + } + } +#ifdef DEBUG + fprintf(stderr, "fsstress: get_fname failure\n"); + abort(); +#endif + return -1; + /* NOTREACHED */ +} + +void +init_pathname(pathname_t *name) +{ + name->len = 0; + name->path = NULL; +} + +int +lchown_path(pathname_t *name, uid_t owner, gid_t group) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + int rval; + + rval = lchown(name->path, owner, group); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = lchown_path(&newname, owner, group); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +int +link_path(pathname_t *name1, pathname_t *name2) +{ + char buf1[MAXNAMELEN]; + char buf2[MAXNAMELEN]; + int down1; + pathname_t newname1; + pathname_t newname2; + int rval; + + rval = link(name1->path, name2->path); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name1, buf1, &newname1); + separate_pathname(name2, buf2, &newname2); + if (strcmp(buf1, buf2) == 0) { + if (chdir(buf1) == 0) { + rval = link_path(&newname1, &newname2); + chdir(".."); + } + } else { + if (strcmp(buf1, "..") == 0) + down1 = 0; + else if (strcmp(buf2, "..") == 0) + down1 = 1; + else if (strlen(buf1) == 0) + down1 = 0; + else if (strlen(buf2) == 0) + down1 = 1; + else + down1 = MAX(newname1.len, 3 + name2->len) <= + MAX(3 + name1->len, newname2.len); + if (down1) { + free_pathname(&newname2); + append_pathname(&newname2, "../"); + append_pathname(&newname2, name2->path); + if (chdir(buf1) == 0) { + rval = link_path(&newname1, &newname2); + chdir(".."); + } + } else { + free_pathname(&newname1); + append_pathname(&newname1, "../"); + append_pathname(&newname1, name1->path); + if (chdir(buf2) == 0) { + rval = link_path(&newname1, &newname2); + chdir(".."); + } + } + } + free_pathname(&newname1); + free_pathname(&newname2); + return rval; +} + +int +lstat64_path(pathname_t *name, struct stat64 *sbuf) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + int rval; + + rval = lstat64(name->path, sbuf); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = lstat64_path(&newname, sbuf); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +void +make_freq_table(void) +{ + int f; + int i; + opdesc_t *p; + + for (p = ops, f = 0; p < ops_end; p++) + f += p->freq; + freq_table = malloc(f * sizeof(*freq_table)); + freq_table_size = f; + for (p = ops, i = 0; p < ops_end; p++) { + for (f = 0; f < p->freq; f++, i++) + freq_table[i] = p->op; + } +} + +int +mkdir_path(pathname_t *name, mode_t mode) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + int rval; + + rval = mkdir(name->path, mode); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = mkdir_path(&newname, mode); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +int +mknod_path(pathname_t *name, mode_t mode, dev_t dev) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + int rval; + + rval = mknod(name->path, mode, dev); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = mknod_path(&newname, mode, dev); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +void +namerandpad(int id, char *buf, int i) +{ + int bucket; + static int buckets[] = + { 2, 4, 8, 16, 32, 64, 128, MAXNAMELEN - 1 }; + int padlen; + int padmod; + + if (namerand == 0) + return; + bucket = (id ^ namerand) % (sizeof(buckets) / sizeof(buckets[0])); + padmod = buckets[bucket] + 1 - i; + if (padmod <= 0) + return; + padlen = (id ^ namerand) % padmod; + if (padlen) { + memset(&buf[i], 'X', padlen); + buf[i + padlen] = '\0'; + } +} + +int +open_path(pathname_t *name, int oflag) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + int rval; + + rval = open(name->path, oflag); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = open_path(&newname, oflag); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +DIR * +opendir_path(pathname_t *name) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + DIR *rval; + + rval = opendir(name->path); + if (rval || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = opendir_path(&newname); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +void +process_freq(char *arg) +{ + opdesc_t *p; + char *s; + + s = strchr(arg, '='); + if (s == NULL) { + fprintf(stderr, "bad argument '%s'\n", arg); + exit(1); + } + *s++ = '\0'; + for (p = ops; p < ops_end; p++) { + if (strcmp(arg, p->name) == 0) { + p->freq = atoi(s); + return; + } + } + fprintf(stderr, "can't find op type %s for -f\n", arg); + exit(1); +} + +int +readlink_path(pathname_t *name, char *lbuf, size_t lbufsiz) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + int rval; + + rval = readlink(name->path, lbuf, lbufsiz); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = readlink_path(&newname, lbuf, lbufsiz); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +int +rename_path(pathname_t *name1, pathname_t *name2) +{ + char buf1[MAXNAMELEN]; + char buf2[MAXNAMELEN]; + int down1; + pathname_t newname1; + pathname_t newname2; + int rval; + + rval = rename(name1->path, name2->path); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name1, buf1, &newname1); + separate_pathname(name2, buf2, &newname2); + if (strcmp(buf1, buf2) == 0) { + if (chdir(buf1) == 0) { + rval = rename_path(&newname1, &newname2); + chdir(".."); + } + } else { + if (strcmp(buf1, "..") == 0) + down1 = 0; + else if (strcmp(buf2, "..") == 0) + down1 = 1; + else if (strlen(buf1) == 0) + down1 = 0; + else if (strlen(buf2) == 0) + down1 = 1; + else + down1 = MAX(newname1.len, 3 + name2->len) <= + MAX(3 + name1->len, newname2.len); + if (down1) { + free_pathname(&newname2); + append_pathname(&newname2, "../"); + append_pathname(&newname2, name2->path); + if (chdir(buf1) == 0) { + rval = rename_path(&newname1, &newname2); + chdir(".."); + } + } else { + free_pathname(&newname1); + append_pathname(&newname1, "../"); + append_pathname(&newname1, name1->path); + if (chdir(buf2) == 0) { + rval = rename_path(&newname1, &newname2); + chdir(".."); + } + } + } + free_pathname(&newname1); + free_pathname(&newname2); + return rval; +} + +int +rmdir_path(pathname_t *name) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + int rval; + + rval = rmdir(name->path); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = rmdir_path(&newname); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +void +separate_pathname(pathname_t *name, char *buf, pathname_t *newname) +{ + char *slash; + + init_pathname(newname); + slash = strchr(name->path, '/'); + if (slash == NULL) { + buf[0] = '\0'; + return; + } + *slash = '\0'; + strcpy(buf, name->path); + *slash = '/'; + append_pathname(newname, slash + 1); +} + +#define WIDTH 80 + +void +show_ops(int flag, char *lead_str) +{ + opdesc_t *p; + + if (flag<0) { + /* print in list form */ + int x = WIDTH; + + for (p = ops; p < ops_end; p++) { + if (lead_str != NULL && x+strlen(p->name)>=WIDTH-5) + x=printf("%s%s", (p==ops)?"":"\n", lead_str); + x+=printf("%s ", p->name); + } + printf("\n"); + } else { + int f; + for (f = 0, p = ops; p < ops_end; p++) + f += p->freq; + + if (f == 0) + flag = 1; + + for (p = ops; p < ops_end; p++) { + if (flag != 0 || p->freq > 0) { + if (lead_str != NULL) + printf("%s", lead_str); + printf("%20s %d/%d %s\n", + p->name, p->freq, f, + (p->iswrite == 0) ? " " : "write op"); + } + } + } +} + +int +stat64_path(pathname_t *name, struct stat64 *sbuf) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + int rval; + + rval = stat64(name->path, sbuf); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = stat64_path(&newname, sbuf); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +int +symlink_path(const char *name1, pathname_t *name) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + int rval; + + if (!strcmp(name1, name->path)) { + printf("yikes! %s %s\n", name1, name->path); + return 0; + } + + rval = symlink(name1, name->path); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = symlink_path(name1, &newname); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +int +truncate64_path(pathname_t *name, off64_t length) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + int rval; + + rval = truncate64(name->path, length); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = truncate64_path(&newname, length); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +int +unlink_path(pathname_t *name) +{ + char buf[MAXNAMELEN]; + pathname_t newname; + int rval; + + rval = unlink(name->path); + if (rval >= 0 || errno != ENAMETOOLONG) + return rval; + separate_pathname(name, buf, &newname); + if (chdir(buf) == 0) { + rval = unlink_path(&newname); + chdir(".."); + } + free_pathname(&newname); + return rval; +} + +void +usage(void) +{ + printf("Usage: %s -H or\n", myprog); + printf(" %s [-d dir][-e errtg][-f op_name=freq][-n nops]\n", + myprog); + printf(" [-p nproc][-r len][-s seed][-v][-w][-z][-S]\n"); + printf("where\n"); + printf(" -d dir specifies the base directory for operations\n"); + printf(" -e errtg specifies error injection stuff\n"); + printf(" -f op_name=freq changes the frequency of option name to freq\n"); + printf(" the valid operation names are:\n"); + show_ops(-1, " "); + printf(" -n nops specifies the no. of operations per process (default 1)\n"); + printf(" -p nproc specifies the no. of processes (default 1)\n"); + printf(" -r specifies random name padding\n"); + printf(" -s seed specifies the seed for the random generator (default random)\n"); + printf(" -v specifies verbose mode\n"); + printf(" -w zeros frequencies of non-write operations\n"); + printf(" -z zeros frequencies of all operations\n"); + printf(" -S prints the table of operations (omitting zero frequency)\n"); + printf(" -H prints usage and exits\n"); +} + +void +write_freq(void) +{ + opdesc_t *p; + + for (p = ops; p < ops_end; p++) { + if (!p->iswrite) + p->freq = 0; + } +} + +void +zero_freq(void) +{ + opdesc_t *p; + + for (p = ops; p < ops_end; p++) + p->freq = 0; +} + +void +allocsp_f(int opno, long r) +{ + int e; + pathname_t f; + int fd; + struct flock64 fl; + __int64_t lr; + off64_t off; + struct stat64 stb; + int v; + + init_pathname(&f); + if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { + if (v) + printf("%d/%d: allocsp - no filename\n", procid, opno); + free_pathname(&f); + return; + } + fd = open_path(&f, O_RDWR); + e = fd < 0 ? errno : 0; + check_cwd(); + if (fd < 0) { + if (v) + printf("%d/%d: allocsp - open %s failed %d\n", + procid, opno, f.path, e); + free_pathname(&f); + return; + } + if (fstat64(fd, &stb) < 0) { + if (v) + printf("%d/%d: allocsp - fstat64 %s failed %d\n", + procid, opno, f.path, errno); + free_pathname(&f); + close(fd); + return; + } + lr = ((__int64_t)random() << 32) + random(); + off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE)); + off %= maxfsize; + fl.l_whence = SEEK_SET; + fl.l_start = off; + fl.l_len = 0; + e = ioctl(fd, XFS_IOC_ALLOCSP64, &fl) < 0 ? errno : 0; + if (v) + printf("%d/%d: ioctl(XFS_IOC_ALLOCSP64) %s %lld 0 %d\n", + procid, opno, f.path, off, e); + free_pathname(&f); + close(fd); +} + +void +attr_remove_f(int opno, long r) +{ + attrlist_ent_t *aep; + attrlist_t *alist; + char *aname; + char buf[4096]; + attrlist_cursor_t cursor; + int e; + int ent; + pathname_t f; + int total; + int v; + int which; + + init_pathname(&f); + if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) + append_pathname(&f, "."); + total = 0; + bzero(&cursor, sizeof(cursor)); + do { + e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW, + &cursor); + check_cwd(); + if (e) + break; + alist = (attrlist_t *)buf; + total += alist->al_count; + } while (alist->al_more); + if (total == 0) { + if (v) + printf("%d/%d: attr_remove - no attrs for %s\n", + procid, opno, f.path); + free_pathname(&f); + return; + } + which = (int)(random() % total); + bzero(&cursor, sizeof(cursor)); + ent = 0; + aname = NULL; + do { + e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW, + &cursor); + check_cwd(); + if (e) + break; + alist = (attrlist_t *)buf; + if (which < ent + alist->al_count) { + aep = (attrlist_ent_t *) + &buf[alist->al_offset[which - ent]]; + aname = aep->a_name; + break; + } + ent += alist->al_count; + } while (alist->al_more); + if (aname == NULL) { + if (v) + printf( + "%d/%d: attr_remove - name %d not found at %s\n", + procid, opno, which, f.path); + free_pathname(&f); + return; + } + e = attr_remove_path(&f, aname, ATTR_DONTFOLLOW) < 0 ? errno : 0; + check_cwd(); + if (v) + printf("%d/%d: attr_remove %s %s %d\n", + procid, opno, f.path, aname, e); + free_pathname(&f); +} + +void +attr_set_f(int opno, long r) +{ + char aname[10]; + char *aval; + int e; + pathname_t f; + int len; + static int lengths[] = { 10, 100, 1000, 10000 }; + int li; + int v; + + init_pathname(&f); + if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) + append_pathname(&f, "."); + sprintf(aname, "a%x", nameseq++); + li = (int)(random() % (sizeof(lengths) / sizeof(lengths[0]))); + len = (int)(random() % lengths[li]); + if (len == 0) + len = 1; + aval = malloc(len); + memset(aval, nameseq & 0xff, len); + e = attr_set_path(&f, aname, aval, len, ATTR_DONTFOLLOW) < 0 ? + errno : 0; + check_cwd(); + free(aval); + if (v) + printf("%d/%d: attr_set %s %s %d\n", procid, opno, f.path, + aname, e); + free_pathname(&f); +} + +void +bulkstat_f(int opno, long r) +{ + int count; + int fd; + __uint64_t last; + int nent; + xfs_bstat_t *t; + __int64_t total; + xfs_fsop_bulkreq_t bsr; + + last = 0; + nent = (r % 999) + 2; + t = malloc(nent * sizeof(*t)); + fd = open(".", O_RDONLY); + total = 0; + + bsr.lastip=&last; + bsr.icount=nent; + bsr.ubuffer=t; + bsr.ocount=&count; + + while (ioctl(fd, XFS_IOC_FSBULKSTAT, &bsr) == 0 && count > 0) + total += count; + free(t); + if (verbose) + printf("%d/%d: bulkstat nent %d total %lld\n", + procid, opno, nent, total); + close(fd); +} + +void +bulkstat1_f(int opno, long r) +{ + int e; + pathname_t f; + int fd; + int good; + __uint64_t ino; + struct stat64 s; + xfs_bstat_t t; + int v; + xfs_fsop_bulkreq_t bsr; + + + good = random() & 1; + if (good) { + /* use an inode we know exists */ + init_pathname(&f); + if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) + append_pathname(&f, "."); + ino = stat64_path(&f, &s) < 0 ? (ino64_t)r : s.st_ino; + check_cwd(); + free_pathname(&f); + } else { + /* + * pick a random inode + * + * note this can generate kernel warning messages + * since bulkstat_one will read the disk block that + * would contain a given inode even if that disk + * block doesn't contain inodes. + * + * this is detected later, but not until after the + * warning is displayed. + * + * "XFS: device 0x825- bad inode magic/vsn daddr 0x0 #0" + * + */ + ino = (ino64_t)r; + v = verbose; + } + fd = open(".", O_RDONLY); + + bsr.lastip=&ino; + bsr.icount=1; + bsr.ubuffer=&t; + bsr.ocount=NULL; + + e = ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bsr) < 0 ? errno : 0; + if (v) + printf("%d/%d: bulkstat1 %s ino %lld %d\n", + procid, opno, good?"real":"random", (int64_t)ino, e); + close(fd); +} + +void +chown_f(int opno, long r) +{ + int e; + pathname_t f; + int nbits; + uid_t u; + int v; + + init_pathname(&f); + if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) + append_pathname(&f, "."); + u = (uid_t)random(); + nbits = (int)(random() % 32); + u &= (1 << nbits) - 1; + e = lchown_path(&f, u, -1) < 0 ? errno : 0; + check_cwd(); + if (v) + printf("%d/%d: chown %s %d %d\n", procid, opno, f.path, u, e); + free_pathname(&f); +} + +void +creat_f(int opno, long r) +{ + struct fsxattr a; + int e; + int e1; + int extsize; + pathname_t f; + int fd; + fent_t *fep; + int id; + int parid; + int type; + int v; + int v1; + + if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v1)) + parid = -1; + else + parid = fep->id; + init_pathname(&f); + type = rtpct ? ((random() % 100) > rtpct ? FT_REG : FT_RTF) : FT_REG; + if (type == FT_RTF) + extsize = (random() % 10) + 1; + else + extsize = 0; + e = generate_fname(fep, type, &f, &id, &v); + v |= v1; + if (!e) { + if (v) { + fent_to_name(&f, &flist[FT_DIR], fep); + printf("%d/%d: creat - no filename from %s\n", + procid, opno, f.path); + } + free_pathname(&f); + return; + } + fd = creat_path(&f, 0666); + e = fd < 0 ? errno : 0; + e1 = 0; + check_cwd(); + if (fd >= 0) { + if (extsize && ioctl(fd, XFS_IOC_FSGETXATTR, &a) >= 0) { + a.fsx_xflags |= XFS_XFLAG_REALTIME; + a.fsx_extsize = + geom.rtextsize * geom.blocksize * extsize; + if (ioctl(fd, XFS_IOC_FSSETXATTR, &a) < 0) + e1 = errno; + } + add_to_flist(type, id, parid); + close(fd); + } + if (v) + printf("%d/%d: creat %s x:%d %d %d\n", procid, opno, f.path, + extsize ? a.fsx_extsize : 0, e, e1); + free_pathname(&f); +} + +void +dread_f(int opno, long r) +{ + __int64_t align; + char *buf; + struct dioattr diob; + int e; + pathname_t f; + int fd; + size_t len; + __int64_t lr; + off64_t off; + struct stat64 stb; + int v; + + init_pathname(&f); + if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { + if (v) + printf("%d/%d: dread - no filename\n", procid, opno); + free_pathname(&f); + return; + } + fd = open_path(&f, O_RDONLY|O_DIRECT); + e = fd < 0 ? errno : 0; + check_cwd(); + if (fd < 0) { + if (v) + printf("%d/%d: dread - open %s failed %d\n", + procid, opno, f.path, e); + free_pathname(&f); + return; + } + if (fstat64(fd, &stb) < 0) { + if (v) + printf("%d/%d: dread - fstat64 %s failed %d\n", + procid, opno, f.path, errno); + free_pathname(&f); + close(fd); + return; + } + if (stb.st_size == 0) { + if (v) + printf("%d/%d: dread - %s zero size\n", procid, opno, + f.path); + free_pathname(&f); + close(fd); + return; + } + if (ioctl(fd, XFS_IOC_DIOINFO, &diob) < 0) { + if (v) + printf( + "%d/%d: dread - ioctl(fd, XFS_IOC_DIOINFO) %s failed %d\n", + procid, opno, f.path, errno); + free_pathname(&f); + close(fd); + return; + } + align = (__int64_t)diob.d_miniosz; + lr = ((__int64_t)random() << 32) + random(); + off = (off64_t)(lr % stb.st_size); + off -= (off % align); + lseek64(fd, off, SEEK_SET); + len = (random() % (getpagesize() * 32)) + 1; + len -= (len % align); + if (len <= 0) + len = align; + else if (len > diob.d_maxiosz) + len = diob.d_maxiosz; + buf = memalign(diob.d_mem, len); + e = read(fd, buf, len) < 0 ? errno : 0; + free(buf); + if (v) + printf("%d/%d: dread %s [%lld,%d] %d\n", + procid, opno, f.path, off, len, e); + free_pathname(&f); + close(fd); +} + +void +dwrite_f(int opno, long r) +{ + __int64_t align; + char *buf; + struct dioattr diob; + int e; + pathname_t f; + int fd; + size_t len; + __int64_t lr; + off64_t off; + struct stat64 stb; + int v; + + init_pathname(&f); + if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { + if (v) + printf("%d/%d: dwrite - no filename\n", procid, opno); + free_pathname(&f); + return; + } + fd = open_path(&f, O_WRONLY|O_DIRECT); + e = fd < 0 ? errno : 0; + check_cwd(); + if (fd < 0) { + if (v) + printf("%d/%d: dwrite - open %s failed %d\n", + procid, opno, f.path, e); + free_pathname(&f); + return; + } + if (fstat64(fd, &stb) < 0) { + if (v) + printf("%d/%d: dwrite - fstat64 %s failed %d\n", + procid, opno, f.path, errno); + free_pathname(&f); + close(fd); + return; + } + if (ioctl(fd, XFS_IOC_DIOINFO, &diob) < 0) { + if (v) + printf( + "%d/%d: dwrite - ioctl(fd, XFS_IOC_DIOINFO) %s failed %d\n", + procid, opno, f.path, errno); + free_pathname(&f); + close(fd); + return; + } + align = (__int64_t)diob.d_miniosz; + lr = ((__int64_t)random() << 32) + random(); + off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE)); + off -= (off % align); + lseek64(fd, off, SEEK_SET); + len = (random() % (getpagesize() * 32)) + 1; + len -= (len % align); + if (len <= 0) + len = align; + else if (len > diob.d_maxiosz) + len = diob.d_maxiosz; + buf = memalign(diob.d_mem, len); + off %= maxfsize; + lseek64(fd, off, SEEK_SET); + memset(buf, nameseq & 0xff, len); + e = write(fd, buf, len) < 0 ? errno : 0; + free(buf); + if (v) + printf("%d/%d: dwrite %s [%lld,%d] %d\n", + procid, opno, f.path, off, len, e); + free_pathname(&f); + close(fd); +} + +void +fdatasync_f(int opno, long r) +{ + int e; + pathname_t f; + int fd; + int v; + + init_pathname(&f); + if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { + if (v) + printf("%d/%d: fdatasync - no filename\n", + procid, opno); + free_pathname(&f); + return; + } + fd = open_path(&f, O_WRONLY); + e = fd < 0 ? errno : 0; + check_cwd(); + if (fd < 0) { + if (v) + printf("%d/%d: fdatasync - open %s failed %d\n", + procid, opno, f.path, e); + free_pathname(&f); + return; + } + e = fdatasync(fd) < 0 ? errno : 0; + if (v) + printf("%d/%d: fdatasync %s %d\n", procid, opno, f.path, e); + free_pathname(&f); + close(fd); +} + +void +freesp_f(int opno, long r) +{ + int e; + pathname_t f; + int fd; + struct flock64 fl; + __int64_t lr; + off64_t off; + struct stat64 stb; + int v; + + init_pathname(&f); + if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { + if (v) + printf("%d/%d: freesp - no filename\n", procid, opno); + free_pathname(&f); + return; + } + fd = open_path(&f, O_RDWR); + e = fd < 0 ? errno : 0; + check_cwd(); + if (fd < 0) { + if (v) + printf("%d/%d: freesp - open %s failed %d\n", + procid, opno, f.path, e); + free_pathname(&f); + return; + } + if (fstat64(fd, &stb) < 0) { + if (v) + printf("%d/%d: freesp - fstat64 %s failed %d\n", + procid, opno, f.path, errno); + free_pathname(&f); + close(fd); + return; + } + lr = ((__int64_t)random() << 32) + random(); + off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE)); + off %= maxfsize; + fl.l_whence = SEEK_SET; + fl.l_start = off; + fl.l_len = 0; + e = ioctl(fd, XFS_IOC_FREESP64, &fl) < 0 ? errno : 0; + if (v) + printf("%d/%d: ioctl(XFS_IOC_FREESP64) %s %lld 0 %d\n", + procid, opno, f.path, off, e); + free_pathname(&f); + close(fd); +} + +void +fsync_f(int opno, long r) +{ + int e; + pathname_t f; + int fd; + int v; + + init_pathname(&f); + if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { + if (v) + printf("%d/%d: fsync - no filename\n", procid, opno); + free_pathname(&f); + return; + } + fd = open_path(&f, O_WRONLY); + e = fd < 0 ? errno : 0; + check_cwd(); + if (fd < 0) { + if (v) + printf("%d/%d: fsync - open %s failed %d\n", + procid, opno, f.path, e); + free_pathname(&f); + return; + } + e = fsync(fd) < 0 ? errno : 0; + if (v) + printf("%d/%d: fsync %s %d\n", procid, opno, f.path, e); + free_pathname(&f); + close(fd); +} + +void +getdents_f(int opno, long r) +{ + DIR *dir; + pathname_t f; + int v; + + init_pathname(&f); + if (!get_fname(FT_DIRm, r, &f, NULL, NULL, &v)) + append_pathname(&f, "."); + dir = opendir_path(&f); + check_cwd(); + if (dir == NULL) { + if (v) + printf("%d/%d: getdents - can't open %s\n", + procid, opno, f.path); + free_pathname(&f); + return; + } + while (readdir64(dir) != NULL) + continue; + if (v) + printf("%d/%d: getdents %s 0\n", procid, opno, f.path); + free_pathname(&f); + closedir(dir); +} + +void +link_f(int opno, long r) +{ + int e; + pathname_t f; + fent_t *fep; + flist_t *flp; + int id; + pathname_t l; + int parid; + int v; + int v1; + + init_pathname(&f); + if (!get_fname(FT_NOTDIR, r, &f, &flp, NULL, &v1)) { + if (v1) + printf("%d/%d: link - no file\n", procid, opno); + free_pathname(&f); + return; + } + if (!get_fname(FT_DIRm, random(), NULL, NULL, &fep, &v)) + parid = -1; + else + parid = fep->id; + v |= v1; + init_pathname(&l); + e = generate_fname(fep, flp - flist, &l, &id, &v1); + v |= v1; + if (!e) { + if (v) { + fent_to_name(&l, &flist[FT_DIR], fep); + printf("%d/%d: link - no filename from %s\n", + procid, opno, l.path); + } + free_pathname(&l); + free_pathname(&f); + return; + } + e = link_path(&f, &l) < 0 ? errno : 0; + check_cwd(); + if (e == 0) + add_to_flist(flp - flist, id, parid); + if (v) + printf("%d/%d: link %s %s %d\n", procid, opno, f.path, l.path, + e); + free_pathname(&l); + free_pathname(&f); +} + +void +mkdir_f(int opno, long r) +{ + int e; + pathname_t f; + fent_t *fep; + int id; + int parid; + int v; + int v1; + + if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v)) + parid = -1; + else + parid = fep->id; + init_pathname(&f); + e = generate_fname(fep, FT_DIR, &f, &id, &v1); + v |= v1; + if (!e) { + if (v) { + fent_to_name(&f, &flist[FT_DIR], fep); + printf("%d/%d: mkdir - no filename from %s\n", + procid, opno, f.path); + } + free_pathname(&f); + return; + } + e = mkdir_path(&f, 0777) < 0 ? errno : 0; + check_cwd(); + if (e == 0) + add_to_flist(FT_DIR, id, parid); + if (v) + printf("%d/%d: mkdir %s %d\n", procid, opno, f.path, e); + free_pathname(&f); +} + +void +mknod_f(int opno, long r) +{ + int e; + pathname_t f; + fent_t *fep; + int id; + int parid; + int v; + int v1; + + if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v)) + parid = -1; + else + parid = fep->id; + init_pathname(&f); + e = generate_fname(fep, FT_DEV, &f, &id, &v1); + v |= v1; + if (!e) { + if (v) { + fent_to_name(&f, &flist[FT_DIR], fep); + printf("%d/%d: mknod - no filename from %s\n", + procid, opno, f.path); + } + free_pathname(&f); + return; + } + e = mknod_path(&f, S_IFCHR|0444, 0) < 0 ? errno : 0; + check_cwd(); + if (e == 0) + add_to_flist(FT_DEV, id, parid); + if (v) + printf("%d/%d: mknod %s %d\n", procid, opno, f.path, e); + free_pathname(&f); +} + +void +read_f(int opno, long r) +{ + char *buf; + int e; + pathname_t f; + int fd; + size_t len; + __int64_t lr; + off64_t off; + struct stat64 stb; + int v; + + init_pathname(&f); + if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { + if (v) + printf("%d/%d: read - no filename\n", procid, opno); + free_pathname(&f); + return; + } + fd = open_path(&f, O_RDONLY); + e = fd < 0 ? errno : 0; + check_cwd(); + if (fd < 0) { + if (v) + printf("%d/%d: read - open %s failed %d\n", + procid, opno, f.path, e); + free_pathname(&f); + return; + } + if (fstat64(fd, &stb) < 0) { + if (v) + printf("%d/%d: read - fstat64 %s failed %d\n", + procid, opno, f.path, errno); + free_pathname(&f); + close(fd); + return; + } + if (stb.st_size == 0) { + if (v) + printf("%d/%d: read - %s zero size\n", procid, opno, + f.path); + free_pathname(&f); + close(fd); + return; + } + lr = ((__int64_t)random() << 32) + random(); + off = (off64_t)(lr % stb.st_size); + lseek64(fd, off, SEEK_SET); + len = (random() % (getpagesize() * 32)) + 1; + buf = malloc(len); + e = read(fd, buf, len) < 0 ? errno : 0; + free(buf); + if (v) + printf("%d/%d: read %s [%lld,%d] %d\n", + procid, opno, f.path, off, len, e); + free_pathname(&f); + close(fd); +} + +void +readlink_f(int opno, long r) +{ + char buf[PATH_MAX]; + int e; + pathname_t f; + int v; + + init_pathname(&f); + if (!get_fname(FT_SYMm, r, &f, NULL, NULL, &v)) { + if (v) + printf("%d/%d: readlink - no filename\n", procid, opno); + free_pathname(&f); + return; + } + e = readlink_path(&f, buf, PATH_MAX) < 0 ? errno : 0; + check_cwd(); + if (v) + printf("%d/%d: readlink %s %d\n", procid, opno, f.path, e); + free_pathname(&f); +} + +void +rename_f(int opno, long r) +{ + fent_t *dfep; + int e; + pathname_t f; + fent_t *fep; + flist_t *flp; + int id; + pathname_t newf; + int oldid; + int parid; + int v; + int v1; + + init_pathname(&f); + if (!get_fname(FT_ANYm, r, &f, &flp, &fep, &v1)) { + if (v1) + printf("%d/%d: rename - no filename\n", procid, opno); + free_pathname(&f); + return; + } + if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v)) + parid = -1; + else + parid = dfep->id; + v |= v1; + init_pathname(&newf); + e = generate_fname(dfep, flp - flist, &newf, &id, &v1); + v |= v1; + if (!e) { + if (v) { + fent_to_name(&f, &flist[FT_DIR], dfep); + printf("%d/%d: rename - no filename from %s\n", + procid, opno, f.path); + } + free_pathname(&newf); + free_pathname(&f); + return; + } + e = rename_path(&f, &newf) < 0 ? errno : 0; + check_cwd(); + if (e == 0) { + if (flp - flist == FT_DIR) { + oldid = fep->id; + fix_parent(oldid, id); + } + del_from_flist(flp - flist, fep - flp->fents); + add_to_flist(flp - flist, id, parid); + } + if (v) + printf("%d/%d: rename %s to %s %d\n", procid, opno, f.path, + newf.path, e); + free_pathname(&newf); + free_pathname(&f); +} + +void +resvsp_f(int opno, long r) +{ + int e; + pathname_t f; + int fd; + struct flock64 fl; + __int64_t lr; + off64_t off; + struct stat64 stb; + int v; + + init_pathname(&f); + if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { + if (v) + printf("%d/%d: resvsp - no filename\n", procid, opno); + free_pathname(&f); + return; + } + fd = open_path(&f, O_RDWR); + e = fd < 0 ? errno : 0; + check_cwd(); + if (fd < 0) { + if (v) + printf("%d/%d: resvsp - open %s failed %d\n", + procid, opno, f.path, e); + free_pathname(&f); + return; + } + if (fstat64(fd, &stb) < 0) { + if (v) + printf("%d/%d: resvsp - fstat64 %s failed %d\n", + procid, opno, f.path, errno); + free_pathname(&f); + close(fd); + return; + } + lr = ((__int64_t)random() << 32) + random(); + off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE)); + off %= maxfsize; + fl.l_whence = SEEK_SET; + fl.l_start = off; + fl.l_len = (off64_t)(random() % (1024 * 1024)); + e = ioctl(fd, XFS_IOC_RESVSP64, &fl) < 0 ? errno : 0; + if (v) + printf("%d/%d: ioctl(XFS_IOC_RESVSP64) %s %lld %lld %d\n", + procid, opno, f.path, off, fl.l_len, e); + free_pathname(&f); + close(fd); +} + +void +rmdir_f(int opno, long r) +{ + int e; + pathname_t f; + fent_t *fep; + int v; + + init_pathname(&f); + if (!get_fname(FT_DIRm, r, &f, NULL, &fep, &v)) { + if (v) + printf("%d/%d: rmdir - no directory\n", procid, opno); + free_pathname(&f); + return; + } + e = rmdir_path(&f) < 0 ? errno : 0; + check_cwd(); + if (e == 0) + del_from_flist(FT_DIR, fep - flist[FT_DIR].fents); + if (v) + printf("%d/%d: rmdir %s %d\n", procid, opno, f.path, e); + free_pathname(&f); +} + +void +stat_f(int opno, long r) +{ + int e; + pathname_t f; + struct stat64 stb; + int v; + + init_pathname(&f); + if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) { + if (v) + printf("%d/%d: stat - no entries\n", procid, opno); + free_pathname(&f); + return; + } + e = lstat64_path(&f, &stb) < 0 ? errno : 0; + check_cwd(); + if (v) + printf("%d/%d: stat %s %d\n", procid, opno, f.path, e); + free_pathname(&f); +} + +void +symlink_f(int opno, long r) +{ + int e; + pathname_t f; + fent_t *fep; + int i; + int id; + int len; + int parid; + int v; + int v1; + char *val; + + if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v)) + parid = -1; + else + parid = fep->id; + init_pathname(&f); + e = generate_fname(fep, FT_SYM, &f, &id, &v1); + v |= v1; + if (!e) { + if (v) { + fent_to_name(&f, &flist[FT_DIR], fep); + printf("%d/%d: symlink - no filename from %s\n", + procid, opno, f.path); + } + free_pathname(&f); + return; + } + len = (int)(random() % PATH_MAX); + val = malloc(len + 1); + if (len) + memset(val, 'x', len); + val[len] = '\0'; + for (i = 10; i < len - 1; i += 10) + val[i] = '/'; + e = symlink_path(val, &f) < 0 ? errno : 0; + check_cwd(); + if (e == 0) + add_to_flist(FT_SYM, id, parid); + free(val); + if (v) + printf("%d/%d: symlink %s %d\n", procid, opno, f.path, e); + free_pathname(&f); +} + +/* ARGSUSED */ +void +sync_f(int opno, long r) +{ + sync(); + if (verbose) + printf("%d/%d: sync\n", procid, opno); +} + +void +truncate_f(int opno, long r) +{ + int e; + pathname_t f; + __int64_t lr; + off64_t off; + struct stat64 stb; + int v; + + init_pathname(&f); + if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { + if (v) + printf("%d/%d: truncate - no filename\n", procid, opno); + free_pathname(&f); + return; + } + e = stat64_path(&f, &stb) < 0 ? errno : 0; + check_cwd(); + if (e > 0) { + if (v) + printf("%d/%d: truncate - stat64 %s failed %d\n", + procid, opno, f.path, e); + free_pathname(&f); + return; + } + lr = ((__int64_t)random() << 32) + random(); + off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE)); + off %= maxfsize; + e = truncate64_path(&f, off) < 0 ? errno : 0; + check_cwd(); + if (v) + printf("%d/%d: truncate %s %lld %d\n", procid, opno, f.path, + off, e); + free_pathname(&f); +} + +void +unlink_f(int opno, long r) +{ + int e; + pathname_t f; + fent_t *fep; + flist_t *flp; + int v; + + init_pathname(&f); + if (!get_fname(FT_NOTDIR, r, &f, &flp, &fep, &v)) { + if (v) + printf("%d/%d: unlink - no file\n", procid, opno); + free_pathname(&f); + return; + } + e = unlink_path(&f) < 0 ? errno : 0; + check_cwd(); + if (e == 0) + del_from_flist(flp - flist, fep - flp->fents); + if (v) + printf("%d/%d: unlink %s %d\n", procid, opno, f.path, e); + free_pathname(&f); +} + +void +unresvsp_f(int opno, long r) +{ + int e; + pathname_t f; + int fd; + struct flock64 fl; + __int64_t lr; + off64_t off; + struct stat64 stb; + int v; + + init_pathname(&f); + if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { + if (v) + printf("%d/%d: unresvsp - no filename\n", procid, opno); + free_pathname(&f); + return; + } + fd = open_path(&f, O_RDWR); + e = fd < 0 ? errno : 0; + check_cwd(); + if (fd < 0) { + if (v) + printf("%d/%d: unresvsp - open %s failed %d\n", + procid, opno, f.path, e); + free_pathname(&f); + return; + } + if (fstat64(fd, &stb) < 0) { + if (v) + printf("%d/%d: unresvsp - fstat64 %s failed %d\n", + procid, opno, f.path, errno); + free_pathname(&f); + close(fd); + return; + } + lr = ((__int64_t)random() << 32) + random(); + off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE)); + off %= maxfsize; + fl.l_whence = SEEK_SET; + fl.l_start = off; + fl.l_len = (off64_t)(random() % (1 << 20)); + e = ioctl(fd, XFS_IOC_UNRESVSP64, &fl) < 0 ? errno : 0; + if (v) + printf("%d/%d: ioctl(XFS_IOC_UNRESVSP64) %s %lld %lld %d\n", + procid, opno, f.path, off, fl.l_len, e); + free_pathname(&f); + close(fd); +} + +void +write_f(int opno, long r) +{ + char *buf; + int e; + pathname_t f; + int fd; + size_t len; + __int64_t lr; + off64_t off; + struct stat64 stb; + int v; + + init_pathname(&f); + if (!get_fname(FT_REGm, r, &f, NULL, NULL, &v)) { + if (v) + printf("%d/%d: write - no filename\n", procid, opno); + free_pathname(&f); + return; + } + fd = open_path(&f, O_WRONLY); + e = fd < 0 ? errno : 0; + check_cwd(); + if (fd < 0) { + if (v) + printf("%d/%d: write - open %s failed %d\n", + procid, opno, f.path, e); + free_pathname(&f); + return; + } + if (fstat64(fd, &stb) < 0) { + if (v) + printf("%d/%d: write - fstat64 %s failed %d\n", + procid, opno, f.path, errno); + free_pathname(&f); + close(fd); + return; + } + lr = ((__int64_t)random() << 32) + random(); + off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE)); + off %= maxfsize; + lseek64(fd, off, SEEK_SET); + len = (random() % (getpagesize() * 32)) + 1; + buf = malloc(len); + memset(buf, nameseq & 0xff, len); + e = write(fd, buf, len) < 0 ? errno : 0; + free(buf); + if (v) + printf("%d/%d: write %s [%lld,%d] %d\n", + procid, opno, f.path, off, len, e); + free_pathname(&f); + close(fd); +} diff -rNu linux-2.4.7/cmd/xfstests/src/global.h linux-2.4-xfs/cmd/xfstests/src/global.h --- linux-2.4.7/cmd/xfstests/src/global.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/global.h Wed May 9 02:03:16 2001 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef GLOBAL_H +#define GLOBAL_H + +/* xfs-specific includes */ + +#include +#include + +/* libc includes */ + +#include +#include +#include +#include +#include +#include +#include + +#endif diff -rNu linux-2.4.7/cmd/xfstests/src/holes.c linux-2.4-xfs/cmd/xfstests/src/holes.c --- linux-2.4.7/cmd/xfstests/src/holes.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/holes.c Wed May 9 02:03:16 2001 @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "global.h" + +int verbose; /* print lots of debugging info */ + +void usage(char *progname); +void writeblks(int fd, long filesize, int blocksize, + int interleave, int base, int rev); +int readblks(int fd, long filesize, int blocksize, + int interleave, int count); + +void +usage(char *progname) +{ + fprintf(stderr, "usage: %s [-l filesize] [-b blocksize] [-i interleave]\n" + "\t\t[-c count] [-r(everse)] [-v(erbose)] filename\n", + progname); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int interleave, blocksize, count, rev, i, ch, fd; + long filesize; + char *filename = NULL; + int errs; + + filesize = 1024*1024; + blocksize = 4096; + count = interleave = 4; + rev = verbose = 0; + while ((ch = getopt(argc, argv, "b:l:i:c:rv")) != EOF) { + switch(ch) { + case 'b': blocksize = atoi(optarg); break; + case 'c': count = atoi(optarg); break; + case 'i': interleave = atoi(optarg); break; + case 'l': filesize = atol(optarg); break; + case 'v': verbose++; break; + case 'r': rev++; break; + default: usage(argv[0]); break; + } + } + if (optind == argc-1) + filename = argv[optind]; + else + usage(argv[0]); + if ((filesize % (blocksize*interleave)) != 0) { + filesize -= filesize % (blocksize * interleave); + printf("filesize not a multiple of blocksize*interleave,\n"); + printf("reducing filesize to %ld\n", filesize); + } + if (count > interleave) { + count = interleave; + printf("count of passes is too large, setting to %d\n", count); + } else if (count < 1) { + count = 1; + printf("count of passes is too small, setting to %d\n", count); + } + + if ((fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) { + perror("open"); + return 1; + } + for (i = 0; i < count; i++) { + writeblks(fd, filesize, blocksize, interleave, i, rev); + } + errs=readblks(fd, filesize, blocksize, interleave, count); + if (close(fd) < 0) { + perror("close"); + return 1; + } + if (errs) { + printf("%d errors detected during readback\n", errs); + return 1; + } + return 0; +} + +void +writeblks(int fd, long filesize, int blocksize, int interleave, int base, int rev) +{ + long offset; + char *buffer; + + if ((buffer = calloc(1, blocksize)) == NULL) { + perror("malloc"); + exit(1); + } + + if (rev) { + offset = (filesize-blocksize) - (base * blocksize); + } else { + offset = base * blocksize; + } + for (;;) { + if (lseek(fd, offset, SEEK_SET) < 0) { + perror("lseek"); + exit(1); + } + *(long *)buffer = *(long *)(buffer+256) = offset; + if (write(fd, buffer, blocksize) < blocksize) { + perror("write"); + exit(1); + } + if (verbose) { + printf("writing data at offset=%ld, delta=%d, value 0x%lx and 0x%lx\n", + offset-base*blocksize, base, + *(long *)buffer, + *(long *)(buffer+256)); + } + + if (rev) { + offset -= interleave*blocksize; + if (offset < 0) + break; + } else { + offset += interleave*blocksize; + if (offset >= filesize) + break; + } + } + + { + /* pad file out to full length */ + char *zero=""; + if (lseek(fd, filesize-1, SEEK_SET)<0) { + perror("lseek"); + exit(1); + } + if (write(fd, zero, 1)!=1) { + perror("write"); + exit(1); + } + } + + free(buffer); +} + +int +readblks(int fd, long filesize, int blocksize, int interleave, int count) +{ + long offset; + char *buffer, *tmp; + int xfer, i; + int errs=0; + + if ((buffer = calloc(interleave, blocksize)) == NULL) { + perror("malloc"); + exit(1); + } + xfer = interleave * blocksize; + + if (lseek(fd, (long)0, SEEK_SET) < 0) { + perror("lseek"); + exit(1); + } + for (offset = 0; offset < filesize; offset += xfer) { + if ((i = read(fd, buffer, xfer) < xfer)) { + if (i == 0) + break; + if (i < 0) + perror("read"); + printf("short read: %d of %d bytes read\n", i, xfer); + + exit(1); + } + for (tmp = buffer, i = 0; i < count; i++, tmp += blocksize) { + if ( (*(long *)tmp != (offset+i*blocksize)) || + (*(long *)(tmp+256) != (offset+i*blocksize)) ) { + printf("mismatched data at offset=%ld, delta=%d, expected 0x%lx, got 0x%lx and 0x%lx\n", + offset, i, + offset+i*blocksize, + *(long *)tmp, + *(long *)(tmp+256)); + errs++; + } + } + } + + free(buffer); + return errs; +} diff -rNu linux-2.4.7/cmd/xfstests/src/ioctl.c linux-2.4-xfs/cmd/xfstests/src/ioctl.c --- linux-2.4.7/cmd/xfstests/src/ioctl.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/ioctl.c Wed May 9 02:03:16 2001 @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include + +/* simple test program to try out a bunch of ioctls: + * XFS_IOC_FSCOUNTS + * XFS_IOC_GET_RESBLKS + * XFS_IOC_SET_RESBLKS + * XFS_IOC_PATH_TO_FSHANDLE + * XFS_IOC_PATH_TO_HANDLE + * XFS_IOC_FD_TO_HANDLE + * XFS_IOC_OPEN_BY_HANDLE + * XFS_IOC_READLINK_BY_HANDLE +*/ + + +void fscounts(int fsfd) +{ + xfs_fsop_counts_t counts; + int ret; + + ret=ioctl(fsfd, XFS_IOC_FSCOUNTS, &counts); + if (ret) { + perror("ioctl(XFS_IOC_FSCOUNTS)"); + exit(1); + } + + printf("XFS_IOC_FSCOUNTS-\n freedata: %lld freertx: %lld freeino: %lld allocino: %lld\n", + counts.freedata, counts.freertx, counts.freeino, counts.allocino); +} + +__u64 getresblks(int fsfd) +{ + xfs_fsop_resblks_t res; + int ret; + + ret=ioctl(fsfd, XFS_IOC_GET_RESBLKS, &res); + if (ret) { + perror("ioctl(XFS_IOC_GET_RESBLKS)"); + exit(1); + } + + printf("XFS_IOC_GET_RESBLKS-\n resblks: %lld blksavail: %lld\n", + res.resblks, res.resblks_avail); + + return res.resblks; +} + +__u64 setresblks(int fsfd, __u64 blks) +{ + xfs_fsop_resblks_t res; + int ret; + + res.resblks=blks; + ret=ioctl(fsfd, XFS_IOC_SET_RESBLKS, &res); + if (ret) { + perror("ioctl(XFS_IOC_SET_RESBLKS)"); + exit(1); + } + + printf("XFS_IOC_SET_RESBLKS-\n resblks: %lld blksavail: %lld\n", + res.resblks, res.resblks_avail); + + return res.resblks; +} + +void handle_print(void *handle, int handlen) +{ + char *p=handle; + if (!handle||!handlen) { + printf("%s",handle?"":""); + return; + }; + + printf("#"); + while (handlen--) + printf("%02x", *p++); +} + +void stat_print(int fd) +{ + struct stat buf; + + if (fstat(fd, &buf)) { + perror("stat"); + exit(1); + } + printf("dev: %llu ino: %llu mode: %o\n", + (__u64)buf.st_dev, (__u64)buf.st_ino, buf.st_mode); +} + + +void handle(int fsfd, char *path) +{ + xfs_fsop_handlereq_t handle; + char buffer[1024]; + char link[1024]; + int ret; + __u32 len; + __u32 linklen; + int fd; + + handle.path=path; + handle.ohandle=buffer; + handle.ohandlen=&len; + ret=ioctl(fsfd, XFS_IOC_PATH_TO_FSHANDLE, &handle); + if (ret) { + perror("ioctl(XFS_IOC_PATH_TO_FSHANDLE)"); + exit(1); + } + printf("XFS_IOC_PATH_TO_FSHANDLE-\n handle: "); + handle_print(handle.ohandle, *handle.ohandlen); + printf("\n"); + + fd=open(path,O_RDONLY); + if (fd<0) { + perror("open"); + exit(1); + } + handle.path=NULL; + handle.fd=fd; + handle.ohandle=buffer; + handle.ohandlen=&len; + ret=ioctl(fsfd, XFS_IOC_FD_TO_HANDLE, &handle); + if (ret) { + perror("ioctl(XFS_IOC_FD_TO_HANDLE)"); + exit(1); + } + + printf("XFS_IOC_FD_TO_HANDLE-\n path: %s\n handle: ", path); + handle_print(handle.ohandle, *handle.ohandlen); + printf("\n"); + + close(fd); + + handle.path=NULL; + handle.fd=-1; + handle.ihandle=buffer; + handle.ihandlen=len; + handle.ohandle=NULL; + handle.ohandlen=NULL; + ret=ioctl(fsfd, XFS_IOC_OPEN_BY_HANDLE, &handle); + if (ret<0) { + perror("ioctl(XFS_IOC_OPEN_BY_HANDLE)"); + exit(1); + } + printf("XFS_IOC_OPEN_BY_HANDLE-\n handle: "); + handle_print(handle.ihandle, handle.ihandlen); + printf("\n fd: %d\n stat- ", ret); + stat_print(ret); + close(ret); + + handle.path=path; + handle.ohandle=buffer; + handle.ohandlen=&len; + ret=ioctl(fsfd, XFS_IOC_PATH_TO_HANDLE, &handle); + if (ret) { + perror("ioctl(XFS_IOC_PATH_TO_HANDLE)"); + exit(1); + } + printf("XFS_IOC_PATH_TO_HANDLE-\n path: %s\n handle: ", path); + handle_print(handle.ohandle, *handle.ohandlen); + printf("\n"); + + handle.path=NULL; + handle.fd=-1; + handle.ihandle=buffer; + handle.ihandlen=len; + handle.ohandle=link; + linklen=sizeof(link); + handle.ohandlen=&linklen; + ret=ioctl(fsfd, XFS_IOC_READLINK_BY_HANDLE, &handle); + if (ret<0) { + perror("ioctl(XFS_IOC_READLINK_BY_HANDLE)"); + fprintf(stderr,"ERROR IGNORED\n"); + } else { + printf("XFS_IOC_READLINK_BY_HANDLE-\n handle: "); + handle_print(handle.ihandle, handle.ihandlen); + printf("\n link=\"%*.*s\"\n", + ret, ret, (char*)handle.ohandle); + } +} + +int +main(int argc, char **argv) +{ + int fsfd; + + if (argc != 3) { + fprintf(stderr,"usage: %s \n", + argv[0]); + exit(0); + } + + fsfd = open(argv[1], O_RDONLY); + if (fsfd < 0) { + perror("open"); + exit(1); + } + + /* XFS_IOC_FSCOUNTS */ + fscounts(fsfd); + /* XFS_IOC_GET_RESBLKS & XFS_IOC_SET_RESBLKS */ + getresblks(fsfd); + setresblks(fsfd, 1000); + getresblks(fsfd); + setresblks(fsfd, 0); + /* XFS_IOC_FSINUMBERS */ + + /* NYI in kernel */ + + /* XFS_IOC_PATH_TO_FSHANDLE */ + /* XFS_IOC_PATH_TO_HANDLE */ + /* XFS_IOC_FD_TO_HANDLE */ + /* XFS_IOC_OPEN_BY_HANDLE */ + /* XFS_IOC_READLINK_BY_HANDLE */ + handle(fsfd, argv[2]); + + return 0; +} diff -rNu linux-2.4.7/cmd/xfstests/src/loggen.c linux-2.4-xfs/cmd/xfstests/src/loggen.c --- linux-2.4.7/cmd/xfstests/src/loggen.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/loggen.c Wed May 9 02:03:16 2001 @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * + * loggen: Generate log entries. Very much incomplete. The empty log + * record is a bit of a misnomer since we need to jump through + * hoops to get a log record that parses ok yet does nothing. + * + * - dxm 29/09/00 + */ + +#include +#include +#include +#include + +void +usage() +{ + fprintf(stderr,"Usage: loggen\n" + " set up parameters before writing record(s):\n" + " -f f - set format\n" + " -u u - set uuid\n" + " -c c - set cycle\n" + " -b b - set block\n" + " -C c - set tail cycle\n" + " -B b - set tail block\n" + " write log record(s):\n" + " -z n - write n zero block(s) (1BB)\n" + " -e n - write n empty record(s) (2BB)\n" + " -m n - write n unmount record(s) (2BB)\n" + "\n" + " redirect stdout to external log partition, or pipe to\n" + " dd with appropriate parameters to stuff into internal log.\n" + ); + exit(1); +} + +int bufblocks = 0; +void *buf = NULL; +int param_cycle = 1; +int param_block = 0; +int param_tail_cycle = 1; +int param_tail_block = 0; +int param_fmt = XLOG_FMT; +uuid_t param_uuid = {0}; + +void +loggen_alloc(int blocks) +{ + if (!(buf=realloc(buf, blocks*BBSIZE))) { + fprintf(stderr,"failed to allocate %d block(s)\n", blocks); + exit(1); + } + memset(buf, 0, blocks*BBSIZE); + bufblocks=blocks; +} + +void +loggen_write() +{ + if (!buf) { + fprintf(stderr,"no buffer allocated\n"); + exit(1); + } + + if (fwrite(buf, BBSIZE, bufblocks, stdout) != bufblocks) { + perror("fwrite"); + exit(1); + } + +} + +void +loggen_zero(int count) +{ + if (!count) count=1; + + fprintf(stderr," *** zero block (1BB) x %d\n", count); + loggen_alloc(1); + while (count--) + loggen_write(count); +} + +void +loggen_unmount(int count) +{ + xlog_rec_header_t *head; + xlog_op_header_t *op; + /* the data section must be 32 bit size aligned */ + struct { + __uint16_t magic; + __uint16_t pad1; + __uint32_t pad2; /* may as well make it 64 bits */ + } magic = { XLOG_UNMOUNT_TYPE, 0, 0 }; + + if (!count) count=1; + + fprintf(stderr," *** unmount record (2BB) x %d\n", count); + loggen_alloc(2); + + head = (xlog_rec_header_t *)buf; + op = (xlog_op_header_t *)(((char*)buf)+BBSIZE); + + /* note that oh_tid actually contains the cycle number + * and the tid is stored in h_cycle_data[0] - that's the + * way things end up on disk. + */ + + INT_SET(head->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM); + INT_SET(head->h_cycle, ARCH_CONVERT, param_cycle); + INT_SET(head->h_version, ARCH_CONVERT, 1); + INT_SET(head->h_len, ARCH_CONVERT, 20); + INT_SET(head->h_chksum, ARCH_CONVERT, 0); + INT_SET(head->h_prev_block, ARCH_CONVERT, -1); + INT_SET(head->h_num_logops, ARCH_CONVERT, 1); + INT_SET(head->h_cycle_data[0], ARCH_CONVERT, 0xb0c0d0d0); + INT_SET(head->h_fmt, ARCH_CONVERT, param_fmt); + + ASSIGN_ANY_LSN(head->h_tail_lsn, + param_tail_cycle, param_tail_block, ARCH_CONVERT); + + memcpy(head->h_fs_uuid, param_uuid, sizeof(uuid_t)); + + /* now a log unmount op */ + INT_SET(op->oh_tid, ARCH_CONVERT, param_cycle); + INT_SET(op->oh_len, ARCH_CONVERT, sizeof(magic)); + INT_SET(op->oh_clientid, ARCH_CONVERT, XFS_LOG); + INT_SET(op->oh_flags, ARCH_CONVERT, XLOG_UNMOUNT_TRANS); + INT_SET(op->oh_res2, ARCH_CONVERT, 0); + + /* and the data for this op */ + + memcpy(op+1, &magic, sizeof(magic)); + + while (count--) { + ASSIGN_ANY_LSN(head->h_lsn, + param_cycle, param_block++, ARCH_CONVERT); + + loggen_write(count); + } +} + +void +loggen_empty(int count) +{ + xlog_rec_header_t *head; + xlog_op_header_t *op1, *op2, *op3, *op4, *op5; + xfs_trans_header_t *trans; + xfs_buf_log_format_t *blf; + int *data; + char *p; + + if (!count) count=1; + + fprintf(stderr," *** empty record (2BB) x %d\n", count); + loggen_alloc(2); + + p=(char*)buf; + head = (xlog_rec_header_t *)p; p+=BBSIZE; + op1 = (xlog_op_header_t *)p; p+=sizeof(xlog_op_header_t); + op2 = (xlog_op_header_t *)p; p+=sizeof(xlog_op_header_t); + trans = (xfs_trans_header_t *)p; p+=sizeof(xfs_trans_header_t); + op3 = (xlog_op_header_t *)p; p+=sizeof(xlog_op_header_t); + blf = (xfs_buf_log_format_t*)p; p+=sizeof(xfs_buf_log_format_t); + op4 = (xlog_op_header_t *)p; p+=sizeof(xlog_op_header_t); + data = (int *)p; p+=sizeof(int); + op5 = (xlog_op_header_t *)p; p+=sizeof(xlog_op_header_t); + + /* note that oh_tid actually contains the cycle number + * and the tid is stored in h_cycle_data[0] - that's the + * way things end up on disk. + */ + + INT_SET(head->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM); + INT_SET(head->h_cycle, ARCH_CONVERT, param_cycle); + INT_SET(head->h_version, ARCH_CONVERT, 1); + INT_SET(head->h_len, ARCH_CONVERT, 5*sizeof(xlog_op_header_t) + + sizeof(xfs_trans_header_t)+ + sizeof(xfs_buf_log_format_t)+ + sizeof(int)); + INT_SET(head->h_chksum, ARCH_CONVERT, 0); + INT_SET(head->h_prev_block, ARCH_CONVERT, -1); + INT_SET(head->h_num_logops, ARCH_CONVERT, 5); + INT_SET(head->h_cycle_data[0], ARCH_CONVERT, 0xb0c0d0d0); + INT_SET(head->h_fmt, ARCH_CONVERT, param_fmt); + + ASSIGN_ANY_LSN(head->h_tail_lsn, + param_tail_cycle, param_tail_block, ARCH_CONVERT); + + memcpy(head->h_fs_uuid, param_uuid, sizeof(uuid_t)); + + /* start */ + INT_SET(op1->oh_tid, ARCH_CONVERT, 1); + INT_SET(op1->oh_len, ARCH_CONVERT, 0); + INT_SET(op1->oh_clientid, ARCH_CONVERT, XFS_TRANSACTION); + INT_SET(op1->oh_flags, ARCH_CONVERT, XLOG_START_TRANS); + INT_SET(op1->oh_res2, ARCH_CONVERT, 0); + /* dummy */ + INT_SET(op2->oh_tid, ARCH_CONVERT, 0xb0c0d0d0); + INT_SET(op2->oh_len, ARCH_CONVERT, sizeof(xfs_trans_header_t)); + INT_SET(op2->oh_clientid, ARCH_CONVERT, XFS_TRANSACTION); + INT_SET(op2->oh_flags, ARCH_CONVERT, 0); + INT_SET(op2->oh_res2, ARCH_CONVERT, 0); + /* dummy transaction - this stuff doesn't get endian converted */ + trans->th_magic = XFS_TRANS_MAGIC; + trans->th_type = XFS_TRANS_DUMMY1; + trans->th_tid = 0; + trans->th_num_items = 1; + /* buffer */ + INT_SET(op3->oh_tid, ARCH_CONVERT, 0xb0c0d0d0); + INT_SET(op3->oh_len, ARCH_CONVERT, sizeof(xfs_buf_log_format_t)); + INT_SET(op3->oh_clientid, ARCH_CONVERT, XFS_TRANSACTION); + INT_SET(op3->oh_flags, ARCH_CONVERT, 0); + INT_SET(op3->oh_res2, ARCH_CONVERT, 0); + /* an empty buffer too */ + blf->blf_type = XFS_LI_BUF; + blf->blf_size = 2; + blf->blf_flags = XFS_BLI_CANCEL; + blf->blf_blkno = 1; + blf->blf_map_size = 1; + blf->blf_data_map[0]= 0; + /* commit */ + INT_SET(op4->oh_tid, ARCH_CONVERT, 0xb0c0d0d0); + INT_SET(op4->oh_len, ARCH_CONVERT, sizeof(int)); + INT_SET(op4->oh_clientid, ARCH_CONVERT, XFS_TRANSACTION); + INT_SET(op4->oh_flags, ARCH_CONVERT, 0); + INT_SET(op4->oh_res2, ARCH_CONVERT, 0); + /* and the data */ + *data=*(int*)(char*)"FISH"; /* this won't get written (I hope) */ + /* commit */ + INT_SET(op5->oh_tid, ARCH_CONVERT, 0xb0c0d0d0); + INT_SET(op5->oh_len, ARCH_CONVERT, 0); + INT_SET(op5->oh_clientid, ARCH_CONVERT, XFS_TRANSACTION); + INT_SET(op5->oh_flags, ARCH_CONVERT, XLOG_COMMIT_TRANS); + INT_SET(op5->oh_res2, ARCH_CONVERT, 0); + + while (count--) { + ASSIGN_ANY_LSN(head->h_lsn, + param_cycle, param_block++, ARCH_CONVERT); + + loggen_write(count); + } +} + +int +main(int argc, char *argv[]) +{ + int c; + + fprintf(stderr,"*** loggen\n"); + + if (argc<2) usage(); + + while ((c = getopt(argc, argv, "f:u:c:b:C:B:z:e:m:")) != -1) { + switch (c) { + case 'f': + param_fmt=atoi(optarg); + break; + case 'u': + memset(param_uuid, atoi(optarg), sizeof(param_uuid)); + break; + case 'c': + param_cycle=atoi(optarg); + break; + case 'b': + param_block=atoi(optarg); + break; + case 'C': + param_tail_cycle=atoi(optarg); + break; + case 'B': + param_tail_block=atoi(optarg); + break; + + case 'z': + loggen_zero(atoi(optarg)); + break; + case 'e': + loggen_empty(atoi(optarg)); + break; + case 'm': + loggen_unmount(atoi(optarg)); + break; + + default: + fprintf(stderr, "unknown option\n"); + usage(); + } + } + return 0; +} + + diff -rNu linux-2.4.7/cmd/xfstests/src/lstat64.c linux-2.4-xfs/cmd/xfstests/src/lstat64.c --- linux-2.4.7/cmd/xfstests/src/lstat64.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/lstat64.c Mon Mar 26 01:07:33 2001 @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include + +long timebuf; + +void +timesince(long timesec) +{ + long d_since; /* days */ + long h_since; /* hours */ + long m_since; /* minutes */ + long s_since; /* seconds */ + + s_since = timebuf - timesec; + d_since = s_since / 86400l ; + s_since -= d_since * 86400l ; + h_since = s_since / 3600l ; + s_since -= h_since * 3600l ; + m_since = s_since / 60l ; + s_since -= m_since * 60l ; + + printf("(%05ld.%02ld:%02ld:%02ld)\n", + d_since, h_since, m_since, s_since); +} + +int +main(int argc, char **argv) +{ + struct stat64 sbuf; + char mode[10]; + int i; + + time(&timebuf); + + for (i = 1; i < argc; i++) { + + if( lstat64(argv[i], &sbuf) < 0) { + perror(argv[i]); + continue; + } + + printf(" File: \"%s\"\n", argv[i]); + printf(" Size: %-10llu", sbuf.st_size); + + strcpy(mode,"----------"); + if (sbuf.st_mode & (S_IEXEC>>6)) + mode[9] = 'x'; + if (sbuf.st_mode & (S_IWRITE>>6)) + mode[8] = 'w'; + if (sbuf.st_mode & (S_IREAD>>6)) + mode[7] = 'r'; + if (sbuf.st_mode & (S_IEXEC>>3)) + mode[6] = 'x'; + if (sbuf.st_mode & (S_IWRITE>>3)) + mode[5] = 'w'; + if (sbuf.st_mode & (S_IREAD>>3)) + mode[4] = 'r'; + if (sbuf.st_mode & S_IEXEC) + mode[3] = 'x'; + if (sbuf.st_mode & S_IWRITE) + mode[2] = 'w'; + if (sbuf.st_mode & S_IREAD) + mode[1] = 'r'; + if (sbuf.st_mode & S_ISVTX) + mode[9] = 't'; + if (sbuf.st_mode & S_ISGID) + mode[6] = 's'; + if (sbuf.st_mode & S_ISUID) + mode[3] = 's'; + + printf(" Filetype: "); + switch (sbuf.st_mode & S_IFMT) { + case S_IFSOCK: + puts("Socket"); + mode[0] = 's'; + break; + case S_IFDIR: + puts("Directory"); + mode[0] = 'd'; + break; + case S_IFCHR: + puts("Character Device"); + mode[0] = 'c'; + break; + case S_IFBLK: + puts("Block Device"); + mode[0] = 'b'; + break; + case S_IFREG: + puts("Regular File"); + mode[0] = '-'; + break; + case S_IFLNK: + puts("Symbolic Link"); + mode[0] = 'l'; + break; + case S_IFIFO: + puts("Fifo File"); + mode[0] = 'f'; + break; + default: + puts("Unknown"); + mode[0] = '?'; + } + + printf(" Mode: (%04o/%s)", sbuf.st_mode & 07777, mode); + printf(" Uid: (%d)", sbuf.st_uid); + printf(" Gid: (%d)\n", sbuf.st_gid); + printf("Device: %2d,%-2d", major(sbuf.st_dev), + minor(sbuf.st_dev)); + printf(" Inode: %-10llu", (unsigned long long)sbuf.st_ino); + printf("Links: %-5d", sbuf.st_nlink); + + if ( ((sbuf.st_mode & S_IFMT) == S_IFCHR) + || ((sbuf.st_mode & S_IFMT) == S_IFBLK) ) + printf(" Device type: %2d,%-2d\n", + major(sbuf.st_rdev), minor(sbuf.st_rdev)); + else + printf("\n"); + + printf("Access: %.24s",ctime(&sbuf.st_atime)); + timesince(sbuf.st_atime); + printf("Modify: %.24s",ctime(&sbuf.st_mtime)); + timesince(sbuf.st_mtime); + printf("Change: %.24s",ctime(&sbuf.st_ctime)); + timesince(sbuf.st_ctime); + + if (i+1 < argc) + printf("\n"); + } + if (i == 1) { + fprintf(stderr, "Usage: lstat64 filename...\n"); + exit(1); + } + exit(0); +} diff -rNu linux-2.4.7/cmd/xfstests/src/nametest.c linux-2.4-xfs/cmd/xfstests/src/nametest.c --- linux-2.4.7/cmd/xfstests/src/nametest.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/nametest.c Wed May 9 02:03:16 2001 @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "global.h" + +/* + * nametest.c + * + * Run a fully automatic, random test of the directory routines. + * + * Given an input file of a list of filenames (one per line) + * It does a number of iterations of operations + * chosen pseudo-randomly in certain percentages: + * creating (open), + * deleting (unlink) and + * looking up (stat) + * on a pseudo-randomly chosen filename (from input file). + * + * The percentage thresholds for operation selection change + * every iterations. + * e.g. + * If had 100 names then: + * iterations: + * 1-100: pct_remove = 33; pct_create = 33; + * 101-200: pct_remove = 60; pct_create = 20; + * 201-300: pct_remove = 20; pct_create = 60; + * 301-400: pct_remove = 33; pct_create = 33; + * 401-500: pct_remove = 60; pct_create = 20; + * 501-600: pct_remove = 20; pct_create = 60; + * etc... + * + * op > (pct_remove + pct_create) => auto_lookup(ip); + * op > pct_remove => auto_create(ip); + * t => auto_remove(ip); + * + * Each iteration an op is chosen as shown above + * and a filename is randomly chosen. + * + * The operation is done and any error codes are + * verified considering whether file exists (info.exists) + * or not. The stat(3) call also compares inode number. + */ + + +#define DOT_COUNT 100 /* print a '.' every X operations */ + +struct info { + ino64_t inumber; + char *name; + short namelen; + short exists; +} *table; + +char *table_data; /* char string storage for info table */ + +int good_adds, good_rms, good_looks, good_tot; /* ops that suceeded */ +int bad_adds, bad_rms, bad_looks, bad_tot; /* ops that failed */ + +int verbose; + +int auto_lookup(struct info *); +int auto_create(struct info *); +int auto_remove(struct info *); + +void usage(void); + +void +usage(void) +{ + printf("usage: nametest [-l srcfile] [-i iterations] [-s seed] [-z] [-v]\n"); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + char *sourcefile, *c; + int totalnames, iterations, zeroout; + int zone, op, pct_remove=0, pct_create=0, ch, i, retval, fd; + struct stat64 statb; + struct info *ip; + int seed, linedots; + + linedots = zeroout = verbose = 0; + seed = (int)time(NULL) % 1000; + iterations = 100000; + sourcefile = "input"; + while ((ch = getopt(argc, argv, "l:i:s:zv")) != EOF) { + switch (ch) { + case 'l': sourcefile = optarg; break; + case 's': seed = atoi(optarg); break; + case 'i': iterations = atoi(optarg); break; + case 'z': zeroout++; break; + case 'v': verbose++; break; + default: usage(); break; + } + } + + /* + * Read in the source file. + */ + if (stat64(sourcefile, &statb) < 0) { + perror(sourcefile); + usage(); + return 1; + } + if ((table_data = malloc(statb.st_size)) == NULL) { + perror("calloc"); + return 1; + } + if ((fd = open(sourcefile, O_RDONLY)) < 0) { + perror(sourcefile); + return 1; + } + if (read(fd, table_data, statb.st_size) < 0) { + perror(sourcefile); + return 1; + } + close(fd); + + /* + * Allocate space for the info table and fill it in. + */ + + /* + * Add up number of lines in file + * and replace '\n' by '\0' + */ + totalnames = 0; + for (c = table_data, i = 0; i < statb.st_size; c++, i++) { + if (*c == '\n') { + *c = 0; + totalnames++; + } + } + if (!totalnames) { + printf("no names found in input file\n"); + return 1; + } + + table = (struct info *)calloc(totalnames+1, sizeof(struct info)); + if (table == NULL) { + perror("calloc"); + return 1; + } + /* + * Copy over names from file (in ) into name fields + * of info structures in . + */ + ip = table; + ip->name = c = table_data; + for (i = 0; i < totalnames; ) { + if (*c++ == 0) { + ip++; + ip->name = c; + i++; + } else { + ip->namelen++; + } + } + /* + * Check table of names. + * Name are of files and not commands. + * + * ??? I guess use of an input file with commands + * has been done before ??? + * "touch fred" => "fred" + * "rm fred" => error + * "ls fred" => error + */ + for (ip = table, i = 0; i < totalnames; ip++, i++) { + if (strncmp(ip->name, "touch ", strlen("touch ")) == 0) { + /* make name skip over "touch " string */ + ip->name += strlen("touch "); + ip->namelen -= strlen("touch "); + } else if (strncmp(ip->name, "rm ", strlen("rm ")) == 0) { + printf("bad input file, \"rm\" cmds not allowed\n"); + return 1; + } else if (strncmp(ip->name, "ls ", strlen("ls ")) == 0) { + printf("bad input file, \"ls\" cmds not allowed\n"); + return 1; + } + } + + /* + * Run random transactions against the directory. + */ + zone = -1; + printf("Seed = %d (use \"-s %d\" to re-execute this test)\n", seed, seed); + srandom(seed); + + for (i = 0; i < iterations; i++) { + /* + * The distribution of transaction types changes over time. + * At first we have an equal distribution which gives us + * a steady state directory of 50% total size. + * Later, we have an unequal distribution which gives us + * more creates than removes, growing the directory. + * Later still, we have an unequal distribution which gives + * us more removes than creates, shrinking the directory. + */ + if ((i % totalnames) == 0) { + zone++; + switch(zone % 3) { + case 0: pct_remove = 20; pct_create = 60; break; + case 1: pct_remove = 33; pct_create = 33; break; + case 2: pct_remove = 60; pct_create = 20; break; + } + } + + /* + * Choose an operation based on the current distribution. + */ + ip = &table[ random() % totalnames ]; + op = random() % 100; + if (op > (pct_remove + pct_create)) { + retval = auto_lookup(ip); + } else if (op > pct_remove) { + retval = auto_create(ip); + } else { + retval = auto_remove(ip); + } + + /* output '.' every DOT_COUNT ops + * and output '\n" every 72 dots + */ + if ((i % DOT_COUNT) == 0) { + if (linedots++ == 72) { + linedots = 0; + write(1, "\n", 1); + } + write(1, ".", 1); + fflush(stdout); + } + } + printf("\n"); + + printf("creates: %6d OK, %6d EEXIST (%6d total, %2d%% EEXIST)\n", + good_adds, bad_adds, good_adds + bad_adds, + (good_adds+bad_adds) + ? (bad_adds*100) / (good_adds+bad_adds) + : 0); + printf("removes: %6d OK, %6d ENOENT (%6d total, %2d%% ENOENT)\n", + good_rms, bad_rms, good_rms + bad_rms, + (good_rms+bad_rms) + ? (bad_rms*100) / (good_rms+bad_rms) + : 0); + printf("lookups: %6d OK, %6d ENOENT (%6d total, %2d%% ENOENT)\n", + good_looks, bad_looks, good_looks + bad_looks, + (good_looks+bad_looks) + ? (bad_looks*100) / (good_looks+bad_looks) + : 0); + good_tot = good_looks + good_adds + good_rms; + bad_tot = bad_looks + bad_adds + bad_rms; + printf("total : %6d OK, %6d w/error (%6d total, %2d%% w/error)\n", + good_tot, bad_tot, good_tot + bad_tot, + (good_tot + bad_tot) + ? (bad_tot*100) / (good_tot+bad_tot) + : 0); + + /* + * If asked to clear the directory out after the run, + * remove everything that is left. + */ + if (zeroout) { + good_rms = 0; + for (ip = table, i = 0; i < totalnames; ip++, i++) { + if (!ip->exists) + continue; + good_rms++; + retval = unlink(ip->name); + if (retval < 0) { + if (errno == ENOENT) { + printf("\"%s\"(%llu) not removed, should have existed\n", ip->name, (unsigned long long)ip->inumber); + } else { + printf("\"%s\"(%llu) on remove: ", ip->name, (unsigned long long)ip->inumber); + perror("unlink"); + } + } + + if ((good_rms % DOT_COUNT) == 0) { + write(1, ".", 1); + fflush(stdout); + } + } + printf("\ncleanup: %6d removes\n", good_rms); + } + return 0; +} + +int +auto_lookup(struct info *ip) +{ + struct stat64 statb; + int retval; + + retval = stat64(ip->name, &statb); + if (retval >= 0) { + good_looks++; + retval = 0; + if (ip->exists == 0) { + printf("\"%s\"(%llu) lookup, should not exist\n", + ip->name, (unsigned long long)statb.st_ino); + retval = 1; + } else if (ip->inumber != statb.st_ino) { + printf("\"%s\"(%llu) lookup, should be inumber %llu\n", + ip->name, (unsigned long long)statb.st_ino, + (unsigned long long)ip->inumber); + retval = 1; + } else if (verbose) { + printf("\"%s\"(%llu) lookup ok\n", + ip->name, (unsigned long long)statb.st_ino); + } + } else if (errno == ENOENT) { + bad_looks++; + retval = 0; + if (ip->exists == 1) { + printf("\"%s\"(%llu) lookup, should exist\n", + ip->name, (unsigned long long)ip->inumber); + retval = 1; + } else if (verbose) { + printf("\"%s\"(%llu) lookup ENOENT ok\n", + ip->name, (unsigned long long)ip->inumber); + } + } else { + retval = errno; + printf("\"%s\"(%llu) on lookup: ", + ip->name, (unsigned long long)ip->inumber); + perror("stat64"); + } + return(retval); +} + +int +auto_create(struct info *ip) +{ + struct stat64 statb; + int retval; + + retval = open(ip->name, O_RDWR|O_EXCL|O_CREAT, 0666); + if (retval >= 0) { + close(retval); + good_adds++; + retval = 0; + if (stat64(ip->name, &statb) < 0) { + perror("stat64"); + exit(1); + } + if (ip->exists == 1) { + printf("\"%s\"(%llu) created, but already existed as inumber %llu\n", ip->name, (unsigned long long)statb.st_ino, (unsigned long long)ip->inumber); + retval = 1; + } else if (verbose) { + printf("\"%s\"(%llu) create new ok\n", + ip->name, (unsigned long long)statb.st_ino); + } + ip->exists = 1; + ip->inumber = statb.st_ino; + } else if (errno == EEXIST) { + bad_adds++; + retval = 0; + if (ip->exists == 0) { + if (stat64(ip->name, &statb) < 0) { + perror("stat64"); + exit(1); + } + printf("\"%s\"(%llu) not created, should not exist\n", + ip->name, (unsigned long long)statb.st_ino); + retval = 1; + } else if (verbose) { + printf("\"%s\"(%llu) not created ok\n", + ip->name, (unsigned long long)ip->inumber); + } + ip->exists = 1; + } else { + retval = errno; + printf("\"%s\"(%llu) on create: ", + ip->name, (unsigned long long)ip->inumber); + perror("creat"); + } + return(retval); +} + +int +auto_remove(struct info *ip) +{ + int retval; + + retval = unlink(ip->name); + if (retval >= 0) { + good_rms++; + retval = 0; + if (ip->exists == 0) { + printf("\"%s\"(%llu) removed, should not have existed\n", + ip->name, (unsigned long long)ip->inumber); + retval = 1; + } else if (verbose) { + printf("\"%s\"(%llu) remove ok\n", + ip->name, (unsigned long long)ip->inumber); + } + ip->exists = 0; + ip->inumber = 0; + } else if (errno == ENOENT) { + bad_rms++; + retval = 0; + if (ip->exists == 1) { + printf("\"%s\"(%llu) not removed, should have existed\n", + ip->name, (unsigned long long)ip->inumber); + retval = 1; + } else if (verbose) { + printf("\"%s\"(%llu) not removed ok\n", + ip->name, (unsigned long long)ip->inumber); + } + ip->exists = 0; + } else { + retval = errno; + printf("\"%s\"(%llu) on remove: ", + ip->name, (unsigned long long)ip->inumber); + perror("unlink"); + } + return(retval); +} diff -rNu linux-2.4.7/cmd/xfstests/src/permname.c linux-2.4-xfs/cmd/xfstests/src/permname.c --- linux-2.4.7/cmd/xfstests/src/permname.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/permname.c Sun Jan 14 23:01:19 2001 @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "global.h" + +char *alpha; +int asize = 1; +int asplit; +char *buf; +int dflag; +int len = 1; +int nproc = 1; +int nflag; +int vflag; +int pid; + +void mkf(int idx, int p); + +int +main(int argc, char **argv) +{ + int a; + int stat; + long long tot; + int usage=0; + char * argv0=argv[0]; + + argc--; + argv++; + pid=getpid(); + + if (!argc) usage++; + while (argc) { + if (strcmp(*argv, "-c") == 0) { + argc--; + argv++; + asize = atoi(*argv); + if (asize > 64 || asize < 1) { + fprintf(stderr, "bad alpha size %s\n", *argv); + return 1; + } + } else if (strcmp(*argv, "-d") == 0) { + dflag = 1; + } else if (strcmp(*argv, "-l") == 0) { + argc--; + argv++; + len = atoi(*argv); + if (len < 1) { + fprintf(stderr, "bad name length %s\n", *argv); + return 1; + } + } else if (strcmp(*argv, "-p") == 0) { + argc--; + argv++; + nproc = atoi(*argv); + if (nproc < 1) { + fprintf(stderr, "bad process count %s\n", + *argv); + return 1; + } + } else if (strcmp(*argv, "-n") == 0) { + nflag = 1; + } else if (strcmp(*argv, "-v") == 0) { + vflag = 1; + } else if (strcmp(*argv, "-h") == 0) { + usage++; + } else { + fprintf(stderr,"unknown switch \"%s\"\n", *argv); + usage++; + } + argc--; + argv++; + } + + if (usage) { + fprintf(stderr,"permname: usage %s [-c alpha size] [-l name length] " + "[-p proc count] [-n] [-v] [-d] [-h]\n", argv0); + fprintf(stderr," -n : don't actually perform action\n"); + fprintf(stderr," -v : be verbose\n"); + fprintf(stderr," -d : create directories, not files\n"); + exit(1); + } + + if (asize % nproc) { + fprintf(stderr, + "alphabet size must be multiple of process count\n"); + return 1; + } + asplit = asize / nproc; + alpha = malloc(asize + 1); + buf = malloc(len + 1); + for (a = 0, tot = 1; a < len; a++) + tot *= asize; + if (vflag) fprintf(stderr,"[%d] ",pid); + fprintf(stderr, + "alpha size = %d, name length = %d, total files = %lld, nproc=%d\n", + asize, len, tot, nproc); + fflush(stderr); + for (a = 0; a < asize; a++) { + if (a < 26) + alpha[a] = 'a' + a; + else if (a < 52) + alpha[a] = 'A' + a - 26; + else if (a < 62) + alpha[a] = '0' + a - 52; + else if (a == 62) + alpha[62] = '_'; + else if (a == 63) + alpha[63] = '@'; + } + for (a = 0; a < nproc; a++) { + int r=fork(); + if (r<0) { + perror("fork"); + exit(1); + } + if (!r) { + pid=getpid(); + mkf(0, a); + return 0; + } + } + while (1) { + int r=wait(&stat); + if (r<0) { + if (errno==ECHILD) break; + perror("wait"); + exit(1); + } + if (!r) break; + } + + return 0; +} + +void +mkf(int idx, int p) +{ + int i; + int last; + + last = (idx == len - 1); + if (last) { + buf[len] = '\0'; + for (i = p * asplit; i < (p + 1) * asplit; i++) { + buf[idx] = alpha[i]; + + if (dflag) { + if (vflag) printf("[%d] mkdir %s\n", pid, buf); + if (!nflag) { + if (mkdir(buf, 0777)<0) { + perror("mkdir"); + exit(1); + } + } + } else { + if (vflag) printf("[%d] touch %s\n", pid, buf); + if (!nflag) { + int f=creat(buf, 0666); + if (f<0) { + perror("creat"); + exit(1); + } + if (close(f)) { + perror("close"); + exit(1); + } + } + } + } + } else { + for (i = 0; i < asize; i++) { + buf[idx] = alpha[i]; + mkf(idx + 1, p); + } + } +} diff -rNu linux-2.4.7/cmd/xfstests/src/randholes.c linux-2.4-xfs/cmd/xfstests/src/randholes.c --- linux-2.4.7/cmd/xfstests/src/randholes.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/randholes.c Wed May 9 02:03:16 2001 @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "global.h" + +unsigned char *valid; /* Bit-vector array showing which blocks have been written */ +int nvalid; /* number of bytes in valid array */ +#define SETBIT(ARRAY, N) ((ARRAY)[(N)/8] |= (1 << ((N)%8))) +#define BITVAL(ARRAY, N) ((ARRAY)[(N)/8] & (1 << ((N)%8))) + +off64_t filesize; +int blocksize; +int count; +int verbose; +int wsync; +int direct; +int alloconly; +int rt; +int extsize; +int preserve; +int test; +off64_t fileoffset; +struct dioattr diob; +struct fsxattr rtattr; + +#define READ_XFER 10 /* block to read at a time when checking */ + +void usage(char *progname); +int findblock(void); +void writeblks(int fd); +int readblks(int fd); +void dumpblock(int *buffer, off64_t offset, int blocksize); + +void +usage(char *progname) +{ + fprintf(stderr, "usage: %s [-l filesize] [-b blocksize] [-c count] [-o write offset] [-s seed] [-x extentsize] [-w] [-v] [-d] [-r] [-a] [-p] filename\n", + progname); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int seed, ch, fd, oflags; + char *filename = NULL; + int r; + + filesize = ((off64_t)256)*1024*1024; + blocksize = 512; + count = filesize/blocksize; + verbose = 0; + wsync = 0; + seed = time(NULL); + test = 0; + while ((ch = getopt(argc, argv, "b:l:s:c:o:x:vwdrapt")) != EOF) { + switch(ch) { + case 'b': blocksize = atoi(optarg); break; + case 'l': filesize = strtoll(optarg, NULL, 16); break; + case 's': seed = atoi(optarg); break; + case 'c': count = atoi(optarg); break; + case 'o': fileoffset = strtoll(optarg, NULL, 16); break; + case 'x': extsize = atoi(optarg); break; + case 'v': verbose++; break; + case 'w': wsync++; break; + case 'd': direct++; break; + case 'r': rt++; break; + case 'a': alloconly++; break; + case 'p': preserve++; break; + case 't': test++; preserve++; break; + default: usage(argv[0]); break; + } + } + if (optind == argc-1) + filename = argv[optind]; + else + usage(argv[0]); + if ((filesize % blocksize) != 0) { + filesize -= filesize % blocksize; + printf("filesize not a multiple of blocksize, reducing filesize to %lld\n", + filesize); + } + if ((fileoffset % blocksize) != 0) { + fileoffset -= fileoffset % blocksize; + printf("fileoffset not a multiple of blocksize, reducing fileoffset to %lld\n", + fileoffset); + } + if (count > (filesize/blocksize)) { + count = (filesize/blocksize); + printf("count of blocks written is too large, setting to %d\n", + count); + } else if (count < 1) { + count = 1; + printf("count of blocks written is too small, setting to %d\n", + count); + } + printf("randholes: Seed = %d (use \"-s %d\" to re-execute this test)\n", seed, seed); + srandom(seed); + + printf("randholes: blocksize=%d, filesize=%Ld, seed=%d\n" + "randholes: count=%d, offset=%Ld, extsize=%d\n", + blocksize, filesize, seed, count, fileoffset, extsize); + printf("randholes: verbose=%d, wsync=%d, direct=%d, rt=%d, alloconly=%d, preserve=%d, test=%d\n", + verbose, wsync, direct, rt, alloconly, preserve, test); + + /* + * Open the file, write rand block in random places, read them all + * back to check for correctness, then close the file. + */ + nvalid = (filesize / blocksize) / 8 + 1; + if ((valid = (unsigned char *)calloc(1, (unsigned)nvalid)) == NULL) { + perror("malloc"); + return 1; + } + if (rt) + direct++; + + oflags=test?(O_RDONLY):(O_RDWR | O_CREAT); + oflags |= (preserve ? 0 : O_TRUNC) | + (wsync ? O_SYNC : 0) | + (direct ? O_DIRECT : 0); + + if ((fd = open(filename, oflags, 0666)) < 0) { + perror("open"); + return 1; + } + if (rt) { + if (ioctl(fd, XFS_IOC_FSGETXATTR, &rtattr) < 0) { + perror("ioctl(XFS_IOC_FSGETXATTR)"); + return 1; + } + if ((rtattr.fsx_xflags & XFS_XFLAG_REALTIME) == 0 || + (extsize && rtattr.fsx_extsize != extsize * blocksize)) { + rtattr.fsx_xflags |= XFS_XFLAG_REALTIME; + if (extsize) + rtattr.fsx_extsize = extsize * blocksize; + if (ioctl(fd, XFS_IOC_FSSETXATTR, &rtattr) < 0) { + perror("ioctl(XFS_IOC_FSSETXATTR)"); + return 1; + } + } + } + if (direct) { + if (ioctl(fd, XFS_IOC_DIOINFO, &diob) < 0) { + perror("ioctl(XFS_IOC_FIOINFO)"); + return 1; + } + if (blocksize % diob.d_miniosz) { + fprintf(stderr, "blocksize %d must be a multiple of %d for direct I/O\n", blocksize, diob.d_miniosz); + return 1; + } + } + printf(test?"write (skipped)\n":"write\n"); + writeblks(fd); + printf("readback\n"); + r=readblks(fd); + if (close(fd) < 0) { + perror("close"); + return 1; + } + free(valid); + + if (r) { + printf("randholes: %d errors found during readback\n", r); + return 2; + } else { + printf("randholes: ok\n"); + return 0; + } +} + +void +writeblks(int fd) +{ + off64_t offset; + char *buffer; + int block; + struct flock64 fl; + + if (direct) + buffer = memalign(diob.d_mem, blocksize); + else + buffer = malloc(blocksize); + if (buffer == NULL) { + perror("malloc"); + exit(1); + } + memset(buffer, 0, blocksize); + + for ( ; count > 0; count--) { + if (verbose && ((count % 100) == 0)) { + printf("."); + fflush(stdout); + } + block = findblock(); + offset = (off64_t)block * blocksize; + if (alloconly) { + if (test) continue; + + fl.l_start = offset; + fl.l_len = blocksize; + fl.l_whence = 0; + if (ioctl(fd, XFS_IOC_RESVSP64, &fl) < 0) { + perror("ioctl(XFS_IOC_RESVSP64)"); + exit(1); + } + continue; + } + SETBIT(valid, block); + if (!test) { + if (lseek64(fd, fileoffset + offset, SEEK_SET) < 0) { + perror("lseek"); + exit(1); + } + } + *(off64_t *)buffer = *(off64_t *)(buffer+256) = + fileoffset + offset; + if (!test) { + if (write(fd, buffer, blocksize) < blocksize) { + perror("write"); + exit(1); + } + } + if (test && verbose>1) printf("NOT "); + if (verbose > 1) { + printf("writing data at offset=%llx, value 0x%llx and 0x%llx\n", + fileoffset + offset, + *(off64_t *)buffer, *(off64_t *)(buffer+256)); + } + } + + free(buffer); +} + +int +readblks(int fd) +{ + long offset; + char *buffer, *tmp; + int xfer, block, i; + int err=0; + + if (alloconly) + return 0; + xfer = READ_XFER*blocksize; + if (direct) + buffer = memalign(diob.d_mem, xfer); + else + buffer = malloc(xfer); + if (buffer == NULL) { + perror("malloc"); + exit(1); + } + memset(buffer, 0, xfer); + if (verbose) + printf("\n"); + + if (lseek64(fd, fileoffset, SEEK_SET) < 0) { + perror("lseek"); + exit(1); + } + for (offset = 0, block = 0; offset < filesize; offset += xfer) { + if ((i = read(fd, buffer, xfer) < xfer)) { + if (i < 2) + break; + perror("read"); + exit(1); + } + for (tmp = buffer, i = 0; i < READ_XFER; i++, block++, tmp += blocksize) { + if (verbose && ((block % 100) == 0)) { + printf("+"); + fflush(stdout); + } + if (BITVAL(valid, block) == 0) { + if ((*(off64_t *)tmp != 0LL) || + (*(off64_t *)(tmp+256) != 0LL)) { + printf("mismatched data at offset=%llx, expected 0x%llx, got 0x%llx and 0x%llx\n", + fileoffset + block * blocksize, + 0LL, + *(off64_t *)tmp, + *(off64_t *)(tmp+256)); + err++; + } + } else { + if ( (*(off64_t *)tmp != + fileoffset + block * blocksize) || + (*(off64_t *)(tmp+256) != + fileoffset + block * blocksize) ) { + printf("mismatched data at offset=%llx, expected 0x%llx, got 0x%llx and 0x%llx\n", + fileoffset + block * blocksize, + fileoffset + block * blocksize, + *(off64_t *)tmp, + *(off64_t *)(tmp+256)); + err++; + } + } + if (verbose > 2) { + printf("block %d blocksize %d\n", block, + blocksize); + dumpblock((int *)tmp, + fileoffset + block * blocksize, + blocksize); + } + } + } + if (verbose) + printf("\n"); + + free(buffer); + return err; +} + +int +findblock(void) +{ + int block, numblocks; + + numblocks = filesize / blocksize; + block = random() % numblocks; + if (BITVAL(valid, block) == 0) + return(block); + + for ( ; BITVAL(valid, block) != 0; block++) { + if (block == (numblocks-1)) + block = -1; + } + if (block == -1) + printf("returning block -1\n"); + return(block); +} + +void +dumpblock(int *buffer, off64_t offset, int blocksize) +{ + int i; + + for (i = 0; i < (blocksize / 16); i++) { + printf("%llx: 0x%08x 0x%08x 0x%08x 0x%08x\n", + offset, *buffer, *(buffer + 1), *(buffer + 2), + *(buffer + 3)); + offset += 16; + buffer += 4; + } +} diff -rNu linux-2.4.7/cmd/xfstests/src/random.c linux-2.4-xfs/cmd/xfstests/src/random.c --- linux-2.4.7/cmd/xfstests/src/random.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/random.c Sun Jan 14 23:01:19 2001 @@ -0,0 +1,239 @@ +/************************************************************************** + * + * random.c -- pseudo random number generator + * Copyright (C) 1994 Chris Wallace (csw@bruce.cs.monash.edu.au) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + **************************************************************************/ + + +/* + * modified by dxm@sgi.com so that this file acts as a drop in replacement + * for srandom and random. + */ + +/* + * A random number generator called as a function by + * random (iseed) or irandm (iseed) + * The parameter should be a pointer to a 2-element long vector. + * The first function returns a double uniform in 0 .. 1. + * The second returns a long integer uniform in 0 .. 2**31-1 + * Both update iseed[] in exactly the same way. + * iseed[] must be a 2-element integer vector. + * The initial value of the second element may be anything. + * + * The period of the random sequence is 2**32 * (2**32-1) + * The table mt[0:127] is defined by mt[i] = 69069 ** (128-i) + */ + +#define MASK ((long) 593970775) +/* or in hex, 23674657 */ + +#define SCALE ((double) 1.0 / (1024.0 * 1024.0 * 1024.0 * 2.0)) +/* i.e. 2 to power -31 */ + +static long mt [128] = { + 902906369, + 2030498053, + -473499623, + 1640834941, + 723406961, + 1993558325, + -257162999, + -1627724755, + 913952737, + 278845029, + 1327502073, + -1261253155, + 981676113, + -1785280363, + 1700077033, + 366908557, + -1514479167, + -682799163, + 141955545, + -830150595, + 317871153, + 1542036469, + -946413879, + -1950779155, + 985397153, + 626515237, + 530871481, + 783087261, + -1512358895, + 1031357269, + -2007710807, + -1652747955, + -1867214463, + 928251525, + 1243003801, + -2132510467, + 1874683889, + -717013323, + 218254473, + -1628774995, + -2064896159, + 69678053, + 281568889, + -2104168611, + -165128239, + 1536495125, + -39650967, + 546594317, + -725987007, + 1392966981, + 1044706649, + 687331773, + -2051306575, + 1544302965, + -758494647, + -1243934099, + -75073759, + 293132965, + -1935153095, + 118929437, + 807830417, + -1416222507, + -1550074071, + -84903219, + 1355292929, + -380482555, + -1818444007, + -204797315, + 170442609, + -1636797387, + 868931593, + -623503571, + 1711722209, + 381210981, + -161547783, + -272740131, + -1450066095, + 2116588437, + 1100682473, + 358442893, + -1529216831, + 2116152005, + -776333095, + 1265240893, + -482278607, + 1067190005, + 333444553, + 86502381, + 753481377, + 39000101, + 1779014585, + 219658653, + -920253679, + 2029538901, + 1207761577, + -1515772851, + -236195711, + 442620293, + 423166617, + -1763648515, + -398436623, + -1749358155, + -538598519, + -652439379, + 430550625, + -1481396507, + 2093206905, + -1934691747, + -962631983, + 1454463253, + -1877118871, + -291917555, + -1711673279, + 201201733, + -474645415, + -96764739, + -1587365199, + 1945705589, + 1303896393, + 1744831853, + 381957665, + 2135332261, + -55996615, + -1190135011, + 1790562961, + -1493191723, + 475559465, + 69069 + }; + +double +_random (long is [2]) +{ + long it, leh, nit; + + it = is [0]; + leh = is [1]; + if (it <= 0) + it = (it + it) ^ MASK; + else + it = it + it; + nit = it - 1; +/* to ensure all-ones pattern omitted */ + leh = leh * mt[nit & 127] + nit; + is [0] = it; is [1] = leh; + if (leh < 0) leh = ~leh; + return (SCALE * ((long) (leh | 1))); +} + + + +long +_irandm (long is [2]) +{ + long it, leh, nit; + + it = is [0]; + leh = is [1]; + if (it <= 0) + it = (it + it) ^ MASK; + else + it = it + it; + nit = it - 1; +/* to ensure all-ones pattern omitted */ + leh = leh * mt[nit & 127] + nit; + is [0] = it; is [1] = leh; + if (leh < 0) leh = ~leh; + return (leh); +} + +/* + * make this a drop in replacement for random and srandom + * + * XXX not thread safe I guess. + */ + +static long saved_seed[2]; + +long random(void) +{ + return _irandm(saved_seed); +} + +void srandom(unsigned seed) +{ + saved_seed[0]=seed; + saved_seed[1]=0; + _irandm(saved_seed); +} + diff -rNu linux-2.4.7/cmd/xfstests/src/runas.c linux-2.4-xfs/cmd/xfstests/src/runas.c --- linux-2.4.7/cmd/xfstests/src/runas.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/runas.c Tue Feb 20 02:07:09 2001 @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Run a command with a particular + * - effective user id + * - effective group id + * - supplementary group list + */ + +#include "global.h" +#include + + + +char *prog; + +void usage(void) +{ + fprintf(stderr, "usage: %s [-u uid] [-g gid] [-s gid] cmd\n" + "flags:\n" + " -u - effective user-id\n" + " -g - effective group-id\n" + " -s - supplementary group-id\n", prog); + +} + +#define SUP_MAX 20 + +int +main(int argc, char **argv) +{ + int c; + uid_t uid = -1; + gid_t gid = -1; + int pid; + char **cmd; + gid_t sgids[SUP_MAX]; + int sup_cnt = 0; + int status; + + prog = basename(argv[0]); + + while ((c = getopt(argc, argv, "u:g:s:")) != -1) { + switch (c) { + case 'u': + uid = atoi(optarg); + break; + case 'g': + gid = atoi(optarg); + break; + case 's': + if (sup_cnt+1 > SUP_MAX) { + fprintf(stderr, "%s: too many sup groups\n", prog); + exit(1); + } + sgids[sup_cnt++] = atoi(optarg); + break; + case '?': + usage(); + exit(1); + } + } + + /* build up the cmd */ + if (optind == argc) { + usage(); + exit(1); + } + else { + char **p; + p = cmd = (char **)malloc(sizeof(char *) * (argc - optind + 1)); + for ( ; optind < argc; optind++, p++) { + *p = strdup(argv[optind]); + } + *p = NULL; + } + + if (gid != -1) { + if (setegid(gid) == -1) { + fprintf(stderr, "%s: setegid(%d) failed: %s\n", + prog, gid, strerror(errno)); + exit(1); + } + } + + if (sup_cnt > 0) { + if (setgroups(sup_cnt, sgids) == -1) { + fprintf(stderr, "%s: setgroups() failed: %s\n", + prog, strerror(errno)); + exit(1); + } + } + + if (uid != -1) { + if (seteuid(uid) == -1) { + fprintf(stderr, "%s: seteuid(%d) failed: %s\n", + prog, uid, strerror(errno)); + exit(1); + } + } + + pid = fork(); + if (pid == -1) { + fprintf(stderr, "%s: fork failed: %s\n", + prog, strerror(errno)); + exit(1); + } + if (pid == 0) { + execv(cmd[0], cmd); + fprintf(stderr, "%s: %s\n", cmd[0], strerror(errno)); + exit(errno); + } + + wait(&status); + if (WIFSIGNALED(status)) { + fprintf(stderr, "%s: command terminated with signal %d\n", + prog, WTERMSIG(status)); + exit(1); + } + else if (WIFEXITED(status)) { + exit(WEXITSTATUS(status)); + } + else { + fprintf(stderr, "%s: command bizarre wait status 0x%x\n", + prog, status); + exit(1); + } + + exit(0); + /* NOTREACHED */ +} diff -rNu linux-2.4.7/cmd/xfstests/src/truncfile.c linux-2.4-xfs/cmd/xfstests/src/truncfile.c --- linux-2.4.7/cmd/xfstests/src/truncfile.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/truncfile.c Wed May 9 02:03:16 2001 @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "global.h" + +long filesize; +int blocksize; +int count; +int verbose; +off64_t fileoffset; + +void usage(char *progname); +void writeblk(int fd); +void truncfile(int fd); + +void +usage(char *progname) +{ + fprintf(stderr, "usage: %s [-l filesize] [-b blocksize] [-c count] [-s seed] [-o fileoffset (hex)] [-v] filename\n", + progname); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int seed, i, ch, fd; + char *filename = NULL; + + filesize = 256*1024*1024; + blocksize = 512; + count = filesize/blocksize; + verbose = 0; + fileoffset = 0; + seed = time(NULL); + while ((ch = getopt(argc, argv, "b:l:s:c:o:v")) != EOF) { + switch(ch) { + case 'b': blocksize = atoi(optarg); break; + case 'l': filesize = atol(optarg); break; + case 's': seed = atoi(optarg); break; + case 'c': count = atoi(optarg); break; + case 'o': fileoffset = strtoll(optarg, NULL, 16); break; + case 'v': verbose++; break; + default: usage(argv[0]); break; + } + } + if (optind == argc-1) + filename = argv[optind]; + else + usage(argv[0]); + printf("Seed = %d (use \"-s %d\" to re-execute this test)\n", seed, seed); + srandom(seed); + + /* + * Open the file, write rand block in random places, truncate the file, + * repeat ad-nauseum, then close the file. + */ + if ((fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) { + perror("open"); + return 1; + } + for (i = 0; i < count; i++) { + writeblk(fd); + truncfile(fd); + if (verbose && ((i % 100) == 0)) { + printf("."); + fflush(stdout); + } + } + if (close(fd) < 0) { + perror("close"); + return 1; + } + return 0; +} + +void +writeblk(int fd) +{ + off_t offset; + static char *buffer = NULL; + + if ((buffer == NULL) && ((buffer = calloc(1, blocksize)) == NULL)) { + perror("malloc"); + exit(1); + } + + offset = random() % filesize; + if (lseek64(fd, (off64_t)(fileoffset + offset), SEEK_SET) < 0) { + perror("lseek"); + exit(1); + } + *(long *)buffer = *(long *)(buffer+256) = (long)offset; + if (write(fd, buffer, blocksize) < blocksize) { + perror("write"); + exit(1); + } + if (verbose > 1) + printf("writing data at offset=%llx\n", + (fileoffset + offset)); +} + +void +truncfile(int fd) +{ + off_t offset; + + offset = random() % filesize; + if (ftruncate64(fd, (off64_t)(fileoffset + offset)) < 0) { + perror("truncate"); + exit(1); + } + if (verbose > 1) + printf("truncated file to offset %llx\n", + (fileoffset + offset)); +} diff -rNu linux-2.4.7/cmd/xfstests/src/usemem.c linux-2.4-xfs/cmd/xfstests/src/usemem.c --- linux-2.4.7/cmd/xfstests/src/usemem.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/src/usemem.c Sun Jan 14 23:01:19 2001 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * + * usemem: allocate and lock a chunk of memory effectively removing + * it from the usable physical memory range + * + * - dxm 04/10/00 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +void +usage(char *argv0) +{ + fprintf(stderr,"Usage: %s \n", argv0); + exit(1); +} + +static void +signalled(int sig) +{ + printf("*** signal\n"); +} + +int +main(int argc, char *argv[]) +{ + int mb; + char *buf; + + if (argc!=2) usage(argv[0]); + mb=atoi(argv[1]); + if (mb<=0) usage(argv[0]); + + buf=malloc(mb*1024*1024); + if (!buf) { + perror("malloc"); + exit(1); + } + if (mlock(buf,mb*1024*1024)) { + perror("mlock"); + exit(1); + } + + printf("%s: %d mb locked - interrupt to release\n", argv[0], mb); + signal(SIGINT, signalled); + pause(); + printf("%s: %d mb unlocked\n", argv[0], mb); + + return 0; +} + + diff -rNu linux-2.4.7/cmd/xfstests/tools/CVS/Entries linux-2.4-xfs/cmd/xfstests/tools/CVS/Entries --- linux-2.4.7/cmd/xfstests/tools/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/tools/CVS/Entries Thu Jul 5 11:46:04 2001 @@ -0,0 +1,8 @@ +/README.auto-qa/1.4/Mon Feb 5 23:18:11 2001/-ko/ +/auto-qa/1.17/Wed Jul 4 00:09:07 2001/-ko/ +/db-walk/1.1/Mon Jan 15 05:23:30 2001/-ko/ +/fs-walk/1.1/Mon Jan 15 05:23:30 2001/-ko/ +/interop/1.1/Mon Jan 15 05:23:30 2001/-ko/ +/srcdiff/1.7/Fri Jun 1 06:33:04 2001/-ko/ +/srctest/1.2/Thu Mar 29 06:30:35 2001/-ko/ +D diff -rNu linux-2.4.7/cmd/xfstests/tools/CVS/Repository linux-2.4-xfs/cmd/xfstests/tools/CVS/Repository --- linux-2.4.7/cmd/xfstests/tools/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/tools/CVS/Repository Thu Jul 5 11:46:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/cmd/xfstests/tools diff -rNu linux-2.4.7/cmd/xfstests/tools/CVS/Root linux-2.4-xfs/cmd/xfstests/tools/CVS/Root --- linux-2.4.7/cmd/xfstests/tools/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/tools/CVS/Root Thu Jul 5 11:46:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/cmd/xfstests/tools/README.auto-qa linux-2.4-xfs/cmd/xfstests/tools/README.auto-qa --- linux-2.4.7/cmd/xfstests/tools/README.auto-qa Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/tools/README.auto-qa Mon Feb 5 17:18:11 2001 @@ -0,0 +1,71 @@ +Quick guide to auto-qa dxm 04/10/2000 +______________________ ______________ + + + - pick/create a user to run auto-qa and check they + can use ptools to check out of the tree + - add your host to cmd/xfstests/common.config + - add your host to cmd/xfstests/tools/auto-qa + check both these files in + - make a directory "$HOME/qa" + - make a workarea "$HOME/qa/linux-xfs" for linux-xfs + (easiest to copy one from elsewhere) + - cd $HOME/qa ; ln -s linux-xfs/cmd/xfstests/tools/auto-qa . + (auto-qa must be a link into it's own source tree + so it can update itself) + - copy an appropriate .config file to + $HOME/qa/$HOSTNAME.config + - You'll need a hacked version of 'su' in $HOME/qa that + lets your user su to root/root without a password + (if you want to run from cron, it mustn't require + /dev/tty). Warning - this is a massive security + hole. + - chown root.root $HOME/qa/su + - chmod 6755 $HOME/qa/su + - add the soon to be kernel to /etc/lilo.conf + + image=/boot/vmlinuz-2.4.0-xfs-qa + label=linux-xfs-qa + append = "console=ttyS0,38400n8" + + - $HOME/qa/auto-qa init + +At this point, the script should update the workarea, clean it, +rebuild it, install it and reboot. + +Then run + + - $HOME/qa/auto-qa restarted + +And the tests should happen... and all pass, of course. + +To get it going automagically: + + - add some lines to the appropriate user's crontab: + + 0 4 * * * $HOME/qa/auto-qa cron-init + 30 4 * * * $HOME/qa/auto-qa cron-restarted + +Notes: + - if MODULAR=1 in auto-qa XFS and pagebuf are expected to + be modules. if MODULAR=0 they should be built into + the kernel + - the test device is cleaned at the start of the QA run + (to stop nightly QA being stuffed up if someone + leaves the device inconsistant etc) + - I'm using a hacked su because PCP sudo won't set the + gid properly, and normal linux su won't run + without a tty even if PAM is pissed-off. + - The QA is restarted after reboot by a second cron entry + to avoid the test being able to get itself into + some stupid loop and so that it's always started + by the appropriate user. You might have to make + the second cron run later if your build takes ages. + - Point the email addresses somewhere appropriate + - When run in "cron-init" or "init" states, the script + will p_tupdate itself and restart. If you start + with an empty source tree, you'll need to check + out the cmd/xfstests/tools/auto-qa script before it'll + work (duh). + +good luck. diff -rNu linux-2.4.7/cmd/xfstests/tools/auto-qa linux-2.4-xfs/cmd/xfstests/tools/auto-qa --- linux-2.4.7/cmd/xfstests/tools/auto-qa Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/tools/auto-qa Tue Jul 3 19:09:07 2001 @@ -0,0 +1,558 @@ +#!/bin/sh +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +# automatic qa system. 31/08/00 dxm@sgi.com + +# configuration (you could tune this) + +EXTRA="-xfs-qa" +BOOT="/boot" +SOAK_PASSES="-1" +SOAK_STRESS="10000" +SOAK_PROC="3" + + +_log() +{ + echo "$*" >&2 + echo "$*" >> $LOG +} + +_fail() +{ + if [ "$started" = "1" ] + then + echo "auto-qa stopped" | wall + started=0 + fi + + _log "$*" + + # send special email if a cron'd qa run fails + case $state + in + cron*) + mail -s "xfs qa status report" $ADMINEMAIL \ + < $LOG 2>&1 + ;; + esac + + status=1 + exit 1 +} + +_get_kernel_version() +{ + [ -x $WORKAREA ] \ + || _fail "can't access workarea $WORKAREA" + [ -r $WORKAREA/linux/Makefile ] \ + || _fail "can't read makefile $WORKAREA/linux/Makefile" + + eval `awk ' + BEGIN { FS = "[ \t=]+" } + /^VERSION =/ { a=$2 } + /^PATCHLEVEL =/ { b=$2 } + /^SUBLEVEL =/ { c=$2 } + /^EXTRAVERSION =/ { d=$2 } + END { + print "VERSION=" a "." b "." c d " ; SVERSION=" a "." b "." c + } + ' < $WORKAREA/linux/Makefile` +} + +# this should be constant + +ROOT="$HOME/qa" +HOST=`hostname -s` +if [ ! -z "$CVSROOT" ]; then + WORKAREA="$ROOT/linux-2.4-xfs" +else + [ -z "$WORKAREA" ] && WORKAREA="$ROOT/linux-xfs" +fi +export WORKAREA + + +export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin/ptools:/usr/local/bin" +STATE=$ROOT/qa.state +QADIR="$WORKAREA/cmd/xfstests" +SUDO="su -c" +CONFIG="$ROOT/$HOST.config" +COMMON_CONFIG="$WORKAREA/cmd/xfstests/common.config" +SH="/bin/sh" +LOG="$ROOT/qa.log" + +# need to add auto-qa hosts here + +case $HOST +in + fuzzy) + EMAIL="nathans@larry" + ADMINEMAIL="nathans@larry" + MODULAR=1 + ;; + bruce) + EMAIL="dxm@larry" + ADMINEMAIL="dxm@larry" + MODULAR=1 + ;; + sagan) + EMAIL="dxm@larry" + ADMINEMAIL="dxm@larry" + MODULAR=0 + ;; + troppo) + EMAIL="nathans@larry" + ADMINEMAIL="nathans@larry" + MODULAR=0 + ;; + goldfish) + EMAIL="nathans@larry" + ADMINEMAIL="nathans@larry" + MODULAR=1 + ;; + *) + _fail "auto-qa: no configuration information for host '$HOST'" + ;; +esac + +# do some cleanup on exit + +_cleanup() +{ + umount $SCRATCH_DEV &> /dev/null + umount $TEST_DEV &> /dev/null + if [ "$started" = 1 ] + then + echo "auto-qa stopped" | wall + started=0 + fi +} +status=1 +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# clean exit + +_success() +{ + status=0 + exit 0 +} + +_get_state() +{ + state=`cat $STATE` +} + +_set_state() +{ + echo $1 > $STATE + _get_state +} + +_change_state() +{ + new=$1 + + case $state + in + *-*) + case $new + in + *-*) + _set_state $new + ;; + *) + _set_state `echo $state | sed "s/-.*$/-$new/"` + ;; + esac + ;; + *) + _set_state $new + ;; + esac +} + +_sudo() +{ + $ROOT/su -c "$*" < /dev/null ;# HACK - we need a hacked su at the mo +} + +_restart() +{ + # erk - why won't this thing reboot reliably?? + exec $ROOT/su -c "(shutdown -r 2 \"auto-qa rebooting\" ; sleep 10 ; reboot ; sleep 10 ; reboot )&" < /dev/null +} + +_update_autoqa_file() +{ + SELF="$ROOT/auto-qa" + SELF_UPDATE="cmd/xfstests/tools/auto-qa" + if [ -z "$CVSROOT" ]; then + cmd="p_tupdate $SELF_UPDATE" + else + cmd="cvs -z3 update $SELF_UPDATE" + fi + exec $SH -c "cd $WORKAREA ; $cmd; chmod +x $SELF_UPDATE ; exec $SELF" +} + +_update_workarea() +{ + if [ -z "$CVSROOT" ]; then + _log " *** p_tupdate" + cd $WORKAREA + p_tupdate 2>&1 \ + || _fail " !!! p_tupdate failed" + + _log " *** p_check/p_purge" + cd $WORKAREA + p_check -s | p_purge -yiu 2>&1 \ + || _fail " !!! p_check/p_purge failed" + + _log " *** non-trunk files" + cd $WORKAREA + p_list -c 2>&1 \ + || _fail " !!! p_list failed" + else + _log " *** cvs update" + cd $WORKAREA + cvs -z3 update -d + fi +} + + +_log "*** linux-xfs QA (`date`)" + +_get_state + +# check preconditions for starting state +case $1 +in + cron-init) + case $state + in + *done) + ;; + *) + _fail " !!! cron-init while not in \"*done\" state" + ;; + esac + ;; + cron-restarted) + # we don't auto restart after reboot, but cron the restart + # to happen a bit later - it's much easier and safer that way + if [ $state != "cron-restarted" ] + then + _fail " !!! cron-restarted while not in \"cron-restarted\" state" + fi + ;; +esac + +if [ "$1" != "" ] +then + _set_state $1 +fi + +[ $UID -eq 0 ] && _fail " !!! QA most be run as a normal user" +[ -d $ROOT ] || _fail " !!! QA root \"$ROOT\" not found" +[ -d $WORKAREA ] || _fail " !!! QA workarea \"$WORKAREA\" not found" +[ -r $CONFIG ] || _fail " !!! Can't read config file $CONFIG" +. $COMMON_CONFIG || _fail " !!! Couldn't source $COMMON_CONFIG" + +_get_kernel_version +IMAGE="$BOOT/vmlinuz$EXTRA" +SYSTEMMAP="$BOOT/System.map-$VERSION$EXTRA" +MODULES="/lib/modules/$SVERSION" + +cd $ROOT + +started=1 +echo "auto-qa started" | wall + +while true +do + _get_state + + _log " *** state $state start (`date`)" + _log " (user=$USER, host=$HOST)" + new_state="" + + case $state + in + *init) + echo "" > $ROOT/qa.log + echo "" > $ROOT/qa.full + _log "******************************************************" + _log "QA init $VERSION (`date`)" + _log "******************************************************" + _log "--- kernel ($IMAGE)" + _log "--- modules ($MODULES)" + + _change_state "inited" + _update_autoqa_file + ;; + + *inited) + _log " *** QA initialized" + new_state="update" + ;; + + *update) + _update_workarea + new_state="clean" + ;; + + *clean) + # we need to configure or else we might fail to clean + for pkg in attr acl xfsprogs xfsdump xfstests + do + cd $WORKAREA/cmd/$pkg + _log " *** clean $pkg tools" + make realclean 2>&1 \ + || _fail " !!! clean $pkg failed" + done + + _log " *** clean linux" + cd $WORKAREA/linux + make mrproper 2>&1 \ + || _fail " !!! clean linux failed" + + _log " *** install configuration file" + cp -f $CONFIG $WORKAREA/linux/.config 2>&1 \ + || _fail " !!! failed to install config" + + _log " *** remove version file" + rm -f include/linux/version.h 2>&1 \ + || _fail " !!! failed to clean version" + + new_state="reconfig" + ;; + + *reconfig) + + _log " *** reconfig kernel" + + _change_state "clean" ; # we better start from scratch if this fails + + cd $WORKAREA/linux + # we want to use default options for any new config options. + echo -e "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" | \ + make EXTRAVERSION=$EXTRA oldconfig 2>&1 \ + || _fail " !!! reconfig oldconfig failed" + make EXTRAVERSION=$EXTRA dep 2>&1 \ + || _fail " !!! reconfig dep failed" + + new_state="build" + ;; + + *build) + _log " *** build kernel" + + _change_state "clean" ; # we better start from scratch if this fails + + cd $WORKAREA/linux + make -j2 EXTRAVERSION=$EXTRA bzImage 2>&1 \ + || _fail " !!! build bzImage failed" + make -j2 EXTRAVERSION=$EXTRA modules 2>&1 \ + || _fail " !!! build modules failed" + + _log " *** build and install tools" + for pkg in attr acl xfsprogs xfsdump xfstests + do + cd $WORKAREA/cmd/$pkg + + # use e-fence - but this will only take effect on configure + export MALLOCLIB=/usr/lib/libefence.a + make configure 2>&1 \ + || _fail " !!! configure $pkg failed" + make default 2>&1 \ + || _fail " !!! build $pkg failed" + + _sudo make install install-dev 2>&1 \ + || _fail " !!! install $pkg failed" + done + + new_state="install" + ;; + + *install) + _log " *** blat old modules" + + _sudo rm -rf $MODULES + + _log " *** install kernel" + cd $WORKAREA/linux + _sudo cp -f $WORKAREA/linux/arch/i386/boot/bzImage $IMAGE 2>&1 \ + || _fail " !!! install kernel failed" + _sudo cp -f $WORKAREA/linux/System.map $SYSTEMMAP 2>&1 \ + || _fail " !!! install kernel failed" + _sudo make EXTRAVERSION=$EXTRA modules_install 2>&1 \ + || _fail " !!! install modules failed" + + _log " *** reinit lilo" + _sudo /sbin/lilo 2>&1 \ + || _fail " !!! reinit lilo failed" + new_state="restart" + ;; + + *restart) + _log " *** select qa kernel" + _sudo /sbin/lilo -R linux-xfs-qa 2>&1 \ + || _fail " !!! lilo failed" + + _log " *** prepare to restart" + _change_state "restarted" + + _log " *** restarting" + + _restart # doesn't return + ;; + + *restarted) + _log " *** QA reentered after restart" + + new_state="check" + ;; + + *check) + uname=`uname -ar` + _log " *** uname $uname" + _log " *** user tools" + ls -l /sbin/*xfs* /usr/sbin/*xfs* 2>&1 + _log " *** kernel" + ls -l /boot/*$EXTRA* 2>&1 + _log " *** kernel modules" + ls -l /lib/modules/$SVERSION$EXTRA/kernel/fs/pagebuf/* \ + /lib/modules/$SVERSION$EXTRA/kernel/fs/xfs/* \ + /lib/modules/$SVERSION$EXTRA/kernel/fs/xfs_support/* + + if [ $MODULAR -eq 0 ] + then + new_state="reset" + else + new_state="probe" + fi + ;; + + *probe) + _log " *** modules dependencies" + + _sudo depmod -a 2>&1 \ + || _fail " !!! failed to depmod -a" + + _log " *** unmounting XFS mounts" + + _sudo umount -a -t xfs 2>&1 + + _log " *** removing modules" + + for m in xfsidbg xfs pagebuf kdbm_pg kdbm_vm + do + _sudo rmmod $m 2> /dev/null + done + + _log " *** installing modules" + + _sudo modprobe xfs 2>&1 \ + || _fail " !!! failed to modprobe xfs" + + new_state="reset" + ;; + + *reset) + + _log " *** unmounting TEST_DEV" + + _sudo umount $TEST_DEV 2>&1 + + _log " *** unmounting SCRATCH_DEV" + + _sudo umount $SCRATCH_DEV 2>&1 + + _log " *** clean TEST_DEV" + + _sudo mkfs -t xfs -f $TEST_DEV 2>&1 \ + || _fail " !!! failed to mkfs TEST_DEV" + + _log " *** mounting TEST_DEV" + + _sudo mount -t xfs $TEST_DEV $TEST_DIR 2>&1 \ + || _fail " !!! failed to mount" + + new_state="run" + ;; + + + soak-run) + cd $QADIR + + _log " *** run soak test" + _sudo ./soak $SOAK_PASSES $SOAK_STRESS $SOAK_PROC\ + || _fail " !!! failed to run soak test" + + new_state="done" + ;; + + *run) + cd $QADIR + + _log " *** run tests" + _sudo ./check -l -g auto 2>&1 | tee $ROOT/qa.out + + _log "" + _log " *** send status mail" + mail -s "xfs qa status report" $EMAIL < $ROOT/qa.out 2>&1 + + new_state="done" + ;; + + *done) + _log "*** QA run complete" + + _success + ;; + + *nothing) + new_state="done" + _log " *** do nothing" + ;; + + *) + _fail " !!! unknown state $state" + ;; + esac + + _log " *** state $state done (`date`)" + [ "$new_state" = "" ] && _fail " !!! no new state set" + _change_state $new_state + +done diff -rNu linux-2.4.7/cmd/xfstests/tools/db-walk linux-2.4-xfs/cmd/xfstests/tools/db-walk --- linux-2.4.7/cmd/xfstests/tools/db-walk Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/tools/db-walk Sun Jan 14 23:23:30 2001 @@ -0,0 +1,211 @@ +#!/usr/bin/perl -w + +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +# +# use db to try to traverse the entire filesystem starting at the root +# +# dxm 5/10/00 + +my $device; +my $rootino; +my $agcount; +my $versionnum; +my $dir_version; +my @dir_inodes; +my @bmap_blocks; +my @block_inodes; +my $mode; + +sub db($) +{ + my ($args)=@_; + my ($ret); + + $ret=`xfs_db -r $args $device 2> /dev/null`; + die "ERROR executing xfs_db -r $args $device" if ($?); + + return $ret; +} + +sub fmt($) +{ + my ($text)=@_; + my $c=0; + print " "; + foreach (split("\n",$text)) { + s/^core\.//; + + if ($c+length($_) >= 70) { + $c=0; + print ",\n "; + } + if ($c) { + print ", "; + $c+=2; + } + print "$_"; + $c+=length($_)+2; + } + print "\n"; +} + +sub inode($) +{ + my ($num)=@_; + my ($t); + + @dir_inodes=(); + + $t=db("-c \"inode $num\" -c \"print\""); + print " *** Inode $num\n"; + fmt($t); + + ($mode)= $t=~ /^core.mode = (\d+)$/m; + + if ($t=~ /a\.bmx/m) { + bmap("inode $num","attr"); + foreach (@bmap_blocks) { + attr_block($_); + } + } + if (eval "$mode & 040000") { + if ( $t=~ /sfdir/m) { + while ($t=~ /inumber(?:\.i[48])? = (\d+)$/mg) { + push(@dir_inodes,$1); + } + } + if ( $t=~ /u\.bmx/m) { + bmap("inode $num","dir"); + foreach (@bmap_blocks) { + dir_block($_); + push(@dir_inodes,@block_inodes); + } + } + } else { + bmap("inode $num","file") if ( $t=~ /u\.bmx/m); + } +} + +sub bmap($$) +{ + my ($cmd,$type)=@_; + my ($t); + + @bmap_blocks=(); + + $flag=($type eq "attr")?"-a":""; + + $t=db("-c \"$cmd\" -c \"bmap $flag\""); + print " *** bmap $type $cmd\n"; + fmt($t); + + if ($type eq "dir" || $type eq "attr") { + while ($t=~ /startblock (\d+) \(.+\) count (\d+)/mg) { + for ($b=$1;$b<$1+$2;$b++) { + push(@bmap_blocks,$b); + } + } + } +} + +sub dir_block($) +{ + my ($num)=@_; + my ($t); + + @block_inodes=(); + + $type=($dir_version==2)?"dir2":"dir"; + + $t=db("-c \"fsblock $num\" -c \"type $type\" -c \"print\""); + print " *** $type block $num\n"; + # need to drop . and .. + ($self)= $t=~ /\[(\d+)\].name = \"\.\"/m; + ($parent)= $t=~ /\[(\d+)\].name = \"\.\.\"/m; + fmt($t); + + + while ($t=~ /\[(\d+)\].inumber = (\d+)/mg) { + next if (defined $self && $1 == $self); + next if (defined $parent && $1 == $parent); + push(@block_inodes, $2); + } +} + +sub attr_block($) +{ + my ($num)=@_; + my ($t); + + $t=db("-c \"fsblock $num\" -c \"type attr\" -c \"print\""); + print " *** attr block $num\n"; + + fmt($t); +} + +sub sb($) +{ + my ($num)=@_; + my ($t); + + $t=db("-c \"sb $num\" -c \"print\""); + print " *** SB $num\n"; + fmt($t); + + ($rootino)= $t=~ /^rootino = (\d+)$/m; + ($agcount)= $t=~ /^agcount = (\d+)$/m; + ($versionnum)= $t=~ /^versionnum = (0x[\da-f]+)$/m; + $dir_version = (eval "$versionnum & 0x2000")?2:1; +} + +die "Usage: $0 \n" unless (@ARGV == 1); + +$device=shift @ARGV; +die "can't read $device\n" unless (-r $device); +die "$device is not a block device\n" unless (-b _); + +chomp($HOST = `hostname -s`); + +print "*** db-walk host $HOST device $device\n"; + +sb(0); +for ($ag=1;$ag<$agcount;$ag++) { + sb($ag); +} + +@inodes=($rootino); +while ($_ = shift @inodes) { + inode($_); + push(@inodes,@dir_inodes); +} diff -rNu linux-2.4.7/cmd/xfstests/tools/fs-walk linux-2.4-xfs/cmd/xfstests/tools/fs-walk --- linux-2.4.7/cmd/xfstests/tools/fs-walk Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/tools/fs-walk Sun Jan 14 23:23:30 2001 @@ -0,0 +1,117 @@ +#!/usr/bin/perl -w + +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# + +# +# traverse the entire filesystem dumping info. +# +# dxm 5/10/00 +use MD5; +use Getopt::Std; + +my %opt; + +sub scan($) +{ + my ($file)=@_; + my ($md5)=new MD5; + my (@stat); + + unless (@stat=lstat("$file")) { + printf("%-" . ($opt{v}?65:32) . "s $file\n", "!!! could not lstat"); + return; + } + + $stat[0]=$stat[8]=""; # wipe the device and access time + $md5->reset; + $md5->add(join(" ",@stat)); + + print join(" ",@stat), "\n"; + + if ($opt{v}) { + print $md5->hexdigest . " "; + $md5->reset; + } + + if (-l "$file") { + if (!defined($link = readlink $file)) { + printf("%-32s $file\n", "!!! could not readlink"); + return; + } + $md5->add($link); + } elsif (-f "$file") { + if (!open(FILE, "$file")) { + printf("%-32s $file\n", "!!! could not read"); + return; + } + $md5->addfile(FILE); + close (FILE); + } + print $md5->hexdigest . " $file\n"; +} + +getopts('vs', \%opt); + +die "Usage: $0 \n" unless (@ARGV == 1); + +$dir=shift @ARGV; +die "can't read $dir\n" unless (-r $dir); +die "$dir is not a directory\n" unless (-d _); + +chomp($HOST = `hostname -s`); + +print "*** fs-walk host $HOST dir $dir\n"; + +@todo=$dir; +while ($dir = shift @todo) { + scan($dir); + unless (opendir(DIR,$dir)) { + printf("%-" . ($opt{v}?65:32) . "s $dir\n", "!!! could not opendir"); + next; + } + unless (@all=readdir(DIR)) { + printf("%-" . ($opt{v}?65:32) . "s $dir\n", "!!! could not readdir"); + next; + } + closedir(DIR); + @dirs=grep(-d "$dir/$_" && !-l "$dir/$_", @all); + foreach (@all) { + next if /^\.\.?$/; + scan("$dir/$_"); + } + + foreach (grep(!/^\.\.?$/, @dirs)) { + push (@todo,"$dir/$_"); + } +} + diff -rNu linux-2.4.7/cmd/xfstests/tools/interop linux-2.4-xfs/cmd/xfstests/tools/interop --- linux-2.4.7/cmd/xfstests/tools/interop Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/tools/interop Sun Jan 14 23:23:30 2001 @@ -0,0 +1,99 @@ +#!/usr/sbin/perl + +sub setup() +{ + $PATH="$PATH:/usr/local/bin/ptools:/sbin:/usr/sbin"; + $DISPLAY="clouds:0"; + + if ("$HOST" eq "bruce") { + $TOOLS="/home/dxm/isms/slinx-xfs/cmd/xfs/tools"; + $SCRATCH_DEV="/dev/sdf1"; + $SCRATCH_MNT="/mnt/xfs3"; + $MKFS="/sbin/mkfs -t xfs -f"; + $SUDO="/home/dxm/su -c"; + $MOUNT="/bin/mount -t xfs"; + $UMOUNT="/bin/umount"; + $MKFS_EXTRA="-f"; + } elsif ("$HOST" eq "whack") { + $TOOLS="/hosts/snort/build1/people/dxm/isms/slinx-xfs/cmd/xfs/tools"; + $SCRATCH_DEV="/dev/dsk/20000080e5114459/lun2s0/c2p1"; + $SCRATCH_MNT="/lun2"; + $MKFS="/sbin/mkfs"; + $SUDO="su root -c"; + $MOUNT="/sbin/mount -t xfs"; + $UMOUNT="/sbin/umount"; + $MKFS_EXTRA=""; + } else { + die "unconfigured host \"$HOST\"\n" + } +} + +sub run_no_check(@) +{ + system(@_); +} + +sub run(@) +{ + system(@_) == 0 + || die "ERROR \"" . join(" ",@_) . "\" returned error\n"; +} + +sub run_expect_fail(@) +{ + system(@_) == 0 + && die "ERROR \"" . join(" ",@_) . "\" returned non-error\n"; +} + +sub umount_no_check() +{ + run_no_check("umount $SCRATCH_DEV"); +} + +sub umount() +{ + run("umount $SCRATCH_DEV"); +} + +sub mount($) +{ + my ($ops)=@_; + run("mount -t xfs $ops $SCRATCH_DEV $SCRATCH_MNT"); +} + +chomp($HOST=`hostname -s`); + +die "usage: $ARGV0 [parameters]\n" unless (scalar(@ARGV)); +print "*** $HOST: Interop started\n"; +print " *** ", join(" ", @ARGV), "\n"; + +setup(); + +$op=shift(@ARGV); + +umount_no_check(); + +if ($op eq "init") { + + run("mkfs -t xfs $MKFS_EXTRA $SCRATCH_DEV"); + +} elsif ($op eq "test") { + + run("xfs_repair -n $SCRATCH_DEV"); + +} elsif ($op eq "easy") { + + mount(""); + system("mount"); + mkdir("$SCRATCH_MNT/fish",0777); + +} elsif ($op eq "check") { + + mount("-o ro"); + system("cd $SCRATCH_MNT ; $TOOLS/fs-walk ."); + +} else { + die "unknown operation \"$op\"\n"; +} + +umount_no_check(); diff -rNu linux-2.4.7/cmd/xfstests/tools/srcdiff linux-2.4-xfs/cmd/xfstests/tools/srcdiff --- linux-2.4.7/cmd/xfstests/tools/srcdiff Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/tools/srcdiff Fri Jun 1 01:33:04 2001 @@ -0,0 +1,270 @@ +#!/usr/bin/perl -w +use strict; +# +# srcdiff is used to compare current user level code with the current +# kernel code and advise of any differences between files which are +# sharing some or all of their content. +# +# There are two classes of sharing which we will check - header files +# in the include directory, which must be exactly the same (use diff) +# and source files which contain routines which must be exactly the +# same (but the userland file is always a subset of the kernel file, +# and hence a more flexible mechanism to "diff" is required). +# +# NB: to cross check that srcdiff is finding all the functions in the +# user source file, providing you have "mkproto" installed, you +# can "cd cmd/xfsprogs/libxfs" and cut&paste this in a bourne shell: +# $ for file in xfs_*.c; do +# > mkproto -nps < $file | perl -ne ' +# > END { print " $count\t- " } +# > s/^.* (xfs\w+|\*xfs\w+|xlog\w+|\*xlog\w+) \(.*/\1/ && { $count++ }' +# > echo $file +# > done +# (compare this to "srcdiff | fgrep Total:") ... repeat for logprint. +# + +die "WORKAREA not set" unless defined $ENV{'WORKAREA'}; +chdir $ENV{'WORKAREA'}; +my $xdiff = $ENV{'XDIFF'}; +my $quiet=0; +my $usage=0; + +foreach (@ARGV) { + if (/^-q$/) { + $quiet++; + } else { + print STDERR "Illegal option $_\n"; + $usage++; + } +} + +if ($usage) { + print STDERR "Usage: $0 [-q]\n"; + exit 1; +} + +my @difflist = qw( + xfs_ag.h xfs_alloc.h xfs_alloc_btree.h xfs_arch.h + xfs_attr_leaf.h xfs_attr_sf.h xfs_bit.h xfs_bmap.h + xfs_bmap_btree.h xfs_btree.h xfs_buf_item.h + xfs_da_btree.h xfs_dfrag.h xfs_dinode.h xfs_dir.h + xfs_dir2.h xfs_dir2_block.h xfs_dir2_data.h + xfs_dir2_leaf.h xfs_dir2_node.h xfs_dir2_sf.h + xfs_dir_leaf.h xfs_dir_sf.h xfs_dqblk.h xfs_dquot_item.h + xfs_extfree_item.h xfs_ialloc.h xfs_imap.h + xfs_ialloc_btree.h xfs_inode.h xfs_inode_item.h + xfs_inum.h xfs_log.h xfs_log_priv.h xfs_log_recover.h + xfs_mount.h xfs_quota.h xfs_rtalloc.h + xfs_sb.h xfs_trans.h xfs_trans_space.h xfs_types.h +); + +sub straightdiff { + my ( $file, $prefix1, $prefix2 ) = @_; + + `diff $prefix1/$file $prefix2/$file >/dev/null 2>&1`; + if (!$quiet) { + print sprintf("\t%-35s ... ", $file); + if ($? != 0) { print "FAILED\n"; } + else { print "ok\n"; } + } elsif ($? != 0) { + printf("\t%-35s ... ", $file); + print "FAILED\n"; + } +} + +print "\n=== Checking headers ===\n"; +foreach (@difflist) { + straightdiff $_, 'cmd/xfsprogs/include', 'linux/fs/xfs'; +} +straightdiff 'xfs_cred.h', 'cmd/xfsprogs/include', 'linux/fs/xfs/linux'; +straightdiff 'xfs_fs.h', 'cmd/xfsprogs/include', 'linux/include/linux'; +straightdiff 'attr_kern.h', 'cmd/attr/include', 'linux/fs/xfs/linux'; +straightdiff 'attributes.h', 'cmd/attr/include', 'linux/include/linux'; +straightdiff 'dmapi_kern.h', 'cmd/dmapi/include', 'linux/include/linux'; +straightdiff 'dmapi.h', 'cmd/dmapi/include', 'linux/include/linux'; +straightdiff 'acl.h', 'cmd/acl/include', 'linux/fs/xfs/linux'; +straightdiff 'arch.h', 'cmd/xfsprogs/include', 'linux/fs/xfs_support'; +straightdiff 'xqm.h', 'cmd/xfsprogs/include', 'linux/include/linux'; + +# +# setstate +# Implements a tri-state FSA, see comments for state transitions +# (knows about the way the XFS kernel code is written, & makes +# some assumptions so as to not need to parse generic C code). +# Accepts one line at a time from a source file, picking out the +# function bodies so they can be subsequently compared. +# + +my $line; # line number in current source file +my $state; # current FSA state +my $funcbody; # current function body (contents) + +sub setstate { + my ( $newline ) = @_; + $line++; + + # - state 0: + # if line looks like start of a function, transition to 1 + # & squirrel line away as line 1 of current function + if ($state == 0) { + if ($newline =~ m/^[xfs|xlog]/) { + $state = 1; + $funcbody = $newline; + } + } + + # - state 1: + # if line looks like start of a function, stay here + # & squirrel line away as line 1 of current function + # otherwise if line isn't start of function body, + # squirrel line away as next line of current function + # (args/..., but not sure this is a real function yet) + # otherwise (start of function) + # squirrel line away as next line of current function + # transition to state 2 + elsif ($state == 1) { + if ($newline =~ m/^[xfs|xlog]/) { + $funcbody = $newline; + } + elsif ($newline =~ m/^\{/) { + $state = 2; + $funcbody .= $newline; + } + } + + # - state 2: + # if line looks like end of function body, + # squirrel line away as last line of current function + # tell someone we have a complete function ready + # transition to state 0 + # otherwise + # squirrel line away as next line of current function + elsif ($state == 2) { + $funcbody .= $newline; + if ($newline =~ m/^\}/) { + $state = 0; + return $funcbody; + } + } + + else { + die "unknown state transition"; + } + return undef; # i.e. not at end of a function +} + +sub listfuncs { + my ( $file ) = @_; + my @funcs; + + $funcbody = ''; + $state = $line = 0; + + open(USER, "$file") || die "cannot open $file"; + while () { + my $func = setstate($_); + push @funcs, $func if (defined($func)); # store function away + } + close USER; + return @funcs; +} + +sub hashfuncs { + my ( $file ) = @_; + my %funcs; + + $funcbody = ''; + $state = $line = 0; + + open(KERN, "$file") || die "cannot open $file"; + while () { + my $func = setstate($_); + if (defined($func)) { + $func =~ m/^([xfs|xlog]\w+)\s*\(/; + next unless defined($1); + my $name = $1; + if (defined($func)) { + $funcs{$name} = $func; # store function away + } + } + } + close KERN; + return %funcs; +} + +sub diffme { + my ( $sa, $sb ) = @_; + + return unless defined($xdiff); + + open(FILEA, "> /tmp/diff.user.$$") || die "cannot write to /tmp/diff.user.$$"; + open(FILEB, "> /tmp/diff.kern.$$") || die "cannot write to /tmp/diff.kern.$$"; + print FILEA $sa; + print FILEB $sb; + close FILEA; + close FILEB; + `$xdiff /tmp/diff.user.$$ /tmp/diff.kern.$$`; + unlink ("/tmp/diff.user.$$","/tmp/diff.kern.$$"); +} + +sub functiondiff { + my ( $file, $prefix1, $prefix2 ) = @_; + my $plural = ''; + my $count = 0; + my $name; + my $found = 0; + + print "\n=== Checking $file routines ===\n" unless ($quiet); + + # iterate over user funcs, match up to kernel funcs + # + my @user = listfuncs "$prefix1/$file"; + my %kern = hashfuncs "$prefix2/$file"; + + foreach my $userfunc (@user) { + + $userfunc =~ m/^([xfs|xlog]\w+)\s*\(/; + next unless (defined($1)); + $name = $1; + $count++; + + if (exists($kern{$name})) { + if ($userfunc ne $kern{$name}) { + print "\n=== $file routines ===\n" + if (!$found++ && $quiet); + + printf("\t%-35s ... ", $name); + print "FAILED\n"; + diffme $userfunc, $kern{$name}; + } + elsif (!$quiet) { + printf("\t%-35s ... ", $name); + print "ok\n"; + } + } + else { + print "Cannot find kernel function $userfunc"; + print " in file $prefix2/$file\n"; + } + } + ($count != 1) && ( $plural = 's' ); + print "( Total: $count routine$plural checked in $file )\n" unless ($quiet); +} + +# cmd/xfsprogs/{libxfs,logprint}/* fs/xfs/* +my @funclist = qw( + xfs_alloc.c xfs_alloc_btree.c xfs_attr_leaf.c xfs_bit.c + xfs_bmap.c xfs_bmap_btree.c xfs_btree.c xfs_da_btree.c + xfs_dir.c xfs_dir2.c xfs_dir2_block.c xfs_dir2_data.c + xfs_dir2_leaf.c xfs_dir2_node.c xfs_dir2_sf.c + xfs_dir_leaf.c xfs_ialloc.c xfs_ialloc_btree.c + xfs_inode.c xfs_rtalloc.c xfs_rtbit.c xfs_mount.c + xfs_trans.c +); + +print "\n=== Checking libxfs code ===\n"; +foreach (@funclist) { + functiondiff $_, 'cmd/xfsprogs/libxfs', 'linux/fs/xfs'; +} +print "\n=== Checking logprint code ===\n"; +functiondiff 'xfs_log_recover.c', 'cmd/xfsprogs/logprint', 'linux/fs/xfs'; diff -rNu linux-2.4.7/cmd/xfstests/tools/srctest linux-2.4-xfs/cmd/xfstests/tools/srctest --- linux-2.4.7/cmd/xfstests/tools/srctest Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/cmd/xfstests/tools/srctest Thu Mar 29 00:30:35 2001 @@ -0,0 +1,86 @@ +#!/bin/sh -x +# +# Simple script which does the following: +# o Generates a src tarball from a WORKAREA +# o Copies it over to ~/test and unpacks it +# o Generates a src tarball from src tarball +# o Compares the build status' ... reports problems +# o removes ~/test +# + +package="$1" +tmpdir="$HOME/test" + +if [ -z "$package" ] +then + echo "srctest requires one argument - package name" + exit 1 +fi + +if [ -z "$WORKAREA" ] +then + echo "WORKAREA is not set -- aborting." + exit 1 +fi + +if [ -d $tmpdir ] +then + echo "$tmpdir exists already -- aborting." + exit 1 +else + mkdir $tmpdir + if [ ! -d $tmpdir ] + then + echo "Cannot create $tmpdir -- aborting." + exit 1 + fi +fi + +# +# Pleasantries are now out of the way, lets proceed. +# NB: If something goes wrong we'll leave the unpacked +# source alone for consumption by a human. +# + +_cleanup() +{ + if [ $status -eq 0 ] + then + rm -fr $tmpdir + else + echo "Problem? -- leaving $tmpdir for inspection" + fi +} + +_buildme() +{ + cd $1 + + if ./Makepkgs + then + : + else + echo Makepkgs thinks theres a problem in $1 + exit 1 + fi + + if [ ! -f build/$package-*.src.tar.gz ] + then + echo Makepkgs failed to create build/package-*.src.tar.gz + exit 1 + fi +} + +status=1 +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# first, build from the WORKAREA +_buildme $WORKAREA/cmd/$package + +cd $tmpdir +gunzip < $WORKAREA/cmd/$package/build/$package-*.src.tar.gz | tar xf - + +# now, cross check the src build +_buildme $tmpdir/$package-* + +status=0 diff -rNu linux-2.4.7/linux/CVS/Entries linux-2.4-xfs/linux/CVS/Entries --- linux-2.4.7/linux/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/CVS/Entries Thu Jul 5 11:46:06 2001 @@ -0,0 +1,8 @@ +/COPYING/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/CREDITS/1.58/Thu Jul 5 06:13:42 2001/-ko/ +/MAINTAINERS/1.62/Thu Jun 28 05:21:16 2001/-ko/ +/Makefile/1.99/Thu Jul 5 06:13:42 2001/-ko/ +/README/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/REPORTING-BUGS/1.5/Wed May 2 06:22:13 2001/-ko/ +/Rules.make/1.13/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/CVS/Entries.Log linux-2.4-xfs/linux/CVS/Entries.Log --- linux-2.4.7/linux/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/CVS/Entries.Log Thu Jul 5 12:08:09 2001 @@ -0,0 +1,13 @@ +A D/Documentation//// +A D/arch//// +A D/drivers//// +A D/fs//// +A D/include//// +A D/init//// +A D/ipc//// +A D/kdb//// +A D/kernel//// +A D/lib//// +A D/mm//// +A D/net//// +A D/scripts//// diff -rNu linux-2.4.7/linux/CVS/Repository linux-2.4-xfs/linux/CVS/Repository --- linux-2.4.7/linux/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/CVS/Repository Thu Jul 5 11:46:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux diff -rNu linux-2.4.7/linux/CVS/Root linux-2.4-xfs/linux/CVS/Root --- linux-2.4.7/linux/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/CVS/Root Thu Jul 5 11:46:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/CVS/Entries linux-2.4-xfs/linux/Documentation/CVS/Entries --- linux-2.4.7/linux/Documentation/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/CVS/Entries Thu Jul 5 11:46:24 2001 @@ -0,0 +1,88 @@ +/00-INDEX/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/BUG-HUNTING/1.3/Tue Dec 7 03:15:49 1999/-ko/ +/Changes/1.40/Thu Jun 28 05:21:16 2001/-ko/ +/CodingStyle/1.3/Wed Oct 6 23:00:36 1999/-ko/ +/Configure.help/1.86/Tue Jul 3 02:33:57 2001/-ko/ +/DMA-mapping.txt/1.9/Tue May 29 19:53:13 2001/-ko/ +/IO-mapping.txt/1.5/Fri Jan 5 18:42:30 2001/-ko/ +/IRQ-affinity.txt/1.1/Sun Feb 27 22:13:56 2000/-ko/ +/LVM-HOWTO/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/README.DAC960/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/README.moxa/1.1/Fri Jan 21 19:18:03 2000/-ko/ +/README.nsp_cs.eng/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/SAK.txt/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/SubmittingDrivers/1.4/Wed May 2 06:22:13 2001/-ko/ +/SubmittingPatches/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/VGA-softcursor.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/binfmt_misc.txt/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/cachetlb.txt/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/cciss.txt/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/computone.txt/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/cpqarray.txt/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/devices.txt/1.9/Tue May 29 19:53:13 2001/-ko/ +/digiboard.txt/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/digiepca.txt/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/dnotify.txt/1.3/Wed May 2 06:22:13 2001/-ko/ +/exception.txt/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/floppy.txt/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/ftape.txt/1.3/Mon Nov 8 22:55:41 1999/-ko/ +/hayes-esp.txt/1.3/Mon Nov 8 22:55:41 1999/-ko/ +/highuid.txt/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/i810_rng.txt/1.2/Wed May 2 06:22:13 2001/-ko/ +/ide.txt/1.6/Sun Feb 27 22:13:56 2000/-ko/ +/initrd.txt/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/ioctl-number.txt/1.17/Tue May 29 19:53:13 2001/-ko/ +/isapnp.txt/1.5/Wed May 2 06:22:13 2001/-ko/ +/java.txt/1.4/Thu Jun 28 05:21:16 2001/-ko/ +/joystick-api.txt/1.7/Wed May 2 06:22:13 2001/-ko/ +/joystick-parport.txt/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/joystick.txt/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/kernel-doc-nano-HOWTO.txt/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/kernel-docs.txt/1.8/Fri Jun 29 22:21:45 2001/-ko/ +/kernel-parameters.txt/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/kmod.txt/1.3/Sun Jan 9 23:56:19 2000/-ko/ +/locks.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/logo.gif/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/logo.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/magic-number.txt/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/mandatory.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mca.txt/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/md.txt/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/memory.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mkdev.cciss/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/mkdev.ida/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/modules.txt/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/moxa-smartio/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/mtrr.txt/1.5/Wed May 2 06:22:13 2001/-ko/ +/nbd.txt/1.3/Sun Aug 29 02:07:15 1999/-ko/ +/nfsroot.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/nmi_watchdog.txt/1.3/Wed Oct 4 11:42:46 2000/-ko/ +/oops-tracing.txt/1.7/Mon Oct 23 18:56:35 2000/-ko/ +/paride.txt/1.3/Tue Jan 11 18:48:48 2000/-ko/ +/parport-lowlevel.txt/1.1/Sun Feb 27 22:13:56 2000/-ko/ +/parport.txt/1.13/Tue May 29 19:53:13 2001/-ko/ +/pci.txt/1.13/Fri Jun 29 22:21:45 2001/-ko/ +/pcwd-watchdog.txt/1.3/Fri Jul 9 06:35:44 1999/-ko/ +/pm.txt/1.4/Wed May 2 06:22:13 2001/-ko/ +/ramdisk.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/riscom8.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/rtc.txt/1.5/Tue May 29 19:53:13 2001/-ko/ +/scsi-generic.txt/1.8/Tue May 29 19:53:13 2001/-ko/ +/scsi.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/serial-console.txt/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/sgi-visws.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/smart-config.txt/1.3/Mon Aug 30 00:17:07 1999/-ko/ +/smp.tex/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/smp.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sonypi.txt/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/specialix.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/spinlocks.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/stallion.txt/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/svga.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sx.txt/1.2/Tue May 2 21:09:12 2000/-ko/ +/sysrq.txt/1.10/Tue May 29 19:53:13 2001/-ko/ +/unicode.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/watchdog.txt/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/xterm-linux.xpm/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/zorro.txt/1.2/Wed Nov 1 21:35:42 2000/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/CVS/Entries.Log linux-2.4-xfs/linux/Documentation/CVS/Entries.Log --- linux-2.4.7/linux/Documentation/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/CVS/Entries.Log Thu Jul 5 11:46:59 2001 @@ -0,0 +1,26 @@ +A D/DocBook//// +A D/arm//// +A D/cdrom//// +A D/cris//// +A D/fb//// +A D/filesystems//// +A D/i2c//// +A D/i386//// +A D/ia64//// +A D/isdn//// +A D/kbuild//// +A D/kdb//// +A D/m68k//// +A D/mips//// +A D/networking//// +A D/parisc//// +A D/power//// +A D/powerpc//// +A D/s390//// +A D/sound//// +A D/sparc//// +A D/sysctl//// +A D/telephony//// +A D/usb//// +A D/video4linux//// +A D/vm//// diff -rNu linux-2.4.7/linux/Documentation/CVS/Repository linux-2.4-xfs/linux/Documentation/CVS/Repository --- linux-2.4.7/linux/Documentation/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/CVS/Repository Thu Jul 5 11:46:06 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation diff -rNu linux-2.4.7/linux/Documentation/CVS/Root linux-2.4-xfs/linux/Documentation/CVS/Root --- linux-2.4.7/linux/Documentation/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/CVS/Root Thu Jul 5 11:46:06 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/Changes linux-2.4-xfs/linux/Documentation/Changes --- linux-2.4.7/linux/Documentation/Changes Wed Jun 27 15:37:05 2001 +++ linux-2.4-xfs/linux/Documentation/Changes Thu Jun 28 00:21:16 2001 @@ -54,6 +54,7 @@ o util-linux 2.10o # fdformat --version o modutils 2.4.2 # insmod -V o e2fsprogs 1.19 # tune2fs +o xfsprogs 1.2.0 # xfs_db -V o reiserfsprogs 3.x.0j # reiserfsck 2>&1|grep reiserfsprogs o pcmcia-cs 3.1.21 # cardmgr -V o PPP 2.4.0 # pppd --version @@ -173,6 +174,14 @@ versions of mkreiserfs, resize_reiserfs, debugreiserfs and reiserfsck. These utils work on both i386 and alpha platforms. +Xfsprogs +-------- + +The latest version of xfsprogs contains mkfs.xfs, xfs_db, and the +xfs_repair utilities, among others, for the XFS filesystem. It is +architecture independent and any version from 1.2.0 onward should +work correctly with this version of the XFS kernel code. + Pcmcia-cs --------- @@ -317,6 +326,11 @@ Reiserfsprogs ------------- o + +Xfsprogs +-------- +o +o LVM toolset ----------- diff -rNu linux-2.4.7/linux/Documentation/Configure.help linux-2.4-xfs/linux/Documentation/Configure.help --- linux-2.4.7/linux/Documentation/Configure.help Mon Jul 2 16:07:55 2001 +++ linux-2.4-xfs/linux/Documentation/Configure.help Mon Jul 2 21:33:57 2001 @@ -132,6 +132,26 @@ If you have system with several CPU's, you do not need to say Y here: APIC will be used automatically. +Default NMI Watchdog Active on Uniprocessors +CONFIG_UP_NMI_WATCHDOG + The NMI (Non Maskable Interrupt) watchdog detects if a cpu is + spinning with normal interrupts disabled. To the outside world the + machine appears to be hung and you cannot use the keyboard to get its + attention. The NMI watchdog forcibly interrupts after approximately + 5 seconds, dropping the machine into a suitable error message which + helps to diagnose the problem. + + On SMP the NMI watchdog is generated using the IO-APIC which is + always available, so on SMP the NMI watchdog defaults to on. On UP + the NMI watchdog requires the use of MSR performance counter 1 which + conflicts with people doing performance monitoring. On UP the + default is no NMI watchdog. + + If you want the NMI watchdog to default to on for uniprocessors, say + Y here. Even if you say N here, you can boot with the NMI watchdog + active and you can activate or deactivate it on the fly, see + Documentation/nmi_watchdog.txt. + Kernel math emulation CONFIG_MATH_EMULATION Linux can emulate a math coprocessor (used for floating point @@ -10222,6 +10242,18 @@ http://www.linuxdoc.org/docs.html#howto . Probably the quota support is only useful for multi user systems. If unsure, say N. +POSIX Access Control List support +CONFIG_FS_POSIX_ACL + ACLs provide a mechanism for finer grained access control than the + traditional UNIX discretionary access control mechanism. + An ACL is a list of users and/or groups and their access rights, + which is associated with a file or directory. ACLs are optional. + In addition to the ACL used to mediate access, a directory may have + a second ACL which defines the default initial ACL for files created + in that directory. Files have only the single access control ACL. + + If unsure, say N. + Memory Technology Device (MTD) support CONFIG_MTD Memory Technology Devices are flash, RAM and similar chips, often @@ -12413,6 +12445,71 @@ Say Y here if you want to try writing to UFS partitions. This is experimental, so you should back up your UFS partitions beforehand. +Page Buffer support +CONFIG_PAGE_BUF + Say Y here if you want to use the XFS filesystem. + + The pagebuf module provides an abstract buffer cache model on top + of the Linux page cache. Cached blocks for a file are hashed to the + inode for that file, and can be held dirty in delayed write mode in + the page cache. Cached metadata blocks for a file system are hashed + to the inode for the mounted device. The page_buf module assembles + buffer (page_buf_t) objects on demand to aggregate such cached pages + for I/O. + + If you want to compile the Page Buffer support as a module ( = + code which can be inserted in and removed from the running kernel + whenever you want), say M here and read Documentation/modules.txt. + The module will be called pagebuf.o. + +SGI XFS file system support +CONFIG_XFS_FS + XFS is a high performance journaling filesystem which originated + on the SGI IRIX platform. It is completely multi-threaded, can + support large files and large filesystems, extended attributes, + variable block sizes, is extent based, and makes extensive use of + Btrees (directories, extents, free space) to aid both performance + and scalability. + + Refer to the documentation at http://oss.sgi.com/projects/xfs/ + for complete details. This implementation is on-disk compatible + with the IRIX version of XFS. + + If you want to compile this file system as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want), say M here and read Documentation/modules.txt. The modules + will be called xfs.o and xfs_support.o. Be aware however that the + file system of your root partition cannot be compiled as a module, + and so this could be dangerous. + +Enable XFS DMAPI +CONFIG_XFS_DMAPI + The Data Management API is a system interface used to implement + the interface defined in the X/Open document: + "Systems Management: Data Storage Management (XDSM) API", + dated February 1997. This interface is used by hierarchical + storage management systems. + + If unsure, say N. + +Enable XFS Quota +CONFIG_XFS_QUOTA + If you say Y here, you will be able to set per user limits for disk + usage (also called disk quotas) under XFS. XFS considers quota + information as filesystem metadata and uses journaling to provide + a higher level guarantee of consistency. The on-disk quota file + format is also compatible with the IRIX version of XFS, allowing + filesystems to be migrated between Linux and IRIX without need for + any conversion. + +Enable XFS Realtime Subdevice +CONFIG_XFS_RT + If you say Y here you will be able to mount and use XFS filesystems + which contain a realtime subvolume. The realtime subvolume is a + separate area of disk space where only file data is stored. The + realtime subvolume is designed to provide very deterministic + data rates suitable for media streaming applications. + Advanced partition selection CONFIG_PARTITION_ADVANCED Say Y here if you would like to use hard disks under Linux which @@ -15643,6 +15740,40 @@ send a BREAK and then within 5 seconds a command keypress. The keys are documented in Documentation/sysrq.txt. Don't say Y unless you really know what this hack does. + +Kernel Debugging support +CONFIG_KDB + This option provides a built-in kernel debugger. The built-in + kernel debugger contains commands which allow memory to be examined, + instructions to be disassembled and breakpoints to be set. For details, + see Documentation/kdb/kdb.mm and the manual pages kdb_bt, kdb_ss, etc. + Kdb can also be used via the serial port. Set up the system to + have a serial console (see Documentation/serial-console.txt). + The Control-A key sequence on the serial port will cause the + kernel debugger to be entered with input from the serial port and + output to the serial console. Selecting this option will + automatically set CONFIG_KALLSYMS. If unsure, say N. + +KDB off by default +CONFIG_KDB_OFF + Normally kdb is activated by default, as long as CONFIG_KDB is set. + If you want to ship a kernel with kdb support but only have kdb + turned on when the user requests it then select this option. When + compiled with CONFIG_KDB_OFF, kdb ignores all events unless you boot + with kdb=on or you echo "1" > /proc/sys/kernel/kdb. This option also + works in reverse, if kdb is normally activated, you can boot with + kdb=off or echo "0" > /proc/sys/kernel/kdb to deactivate kdb. If + unsure, say N. + +Load all symbols for debugging +CONFIG_KALLSYMS + Normally only exported symbols are available to modules. For + debugging you may want all symbols, not just the exported ones. If + you say Y here then extra data is added to the kernel and modules, + this data lists all the non-stack symbols in the kernel or module + and can be used by any debugger. You need modutils >= 2.3.11 to use + this option. See "man kallsyms" for the data format, it adds 10-20% + to the size of the kernel and the loaded modules. If unsure, say N. ISDN subsystem CONFIG_ISDN diff -rNu linux-2.4.7/linux/Documentation/DocBook/CVS/Entries linux-2.4-xfs/linux/Documentation/DocBook/CVS/Entries --- linux-2.4.7/linux/Documentation/DocBook/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/DocBook/CVS/Entries Thu Jul 5 11:46:31 2001 @@ -0,0 +1,20 @@ +/Makefile/1.15/Tue Jul 3 02:33:57 2001/-ko/ +/deviceiobook.tmpl/1.2/Tue May 29 19:53:13 2001/-ko/ +/kernel-api.tmpl/1.10/Tue May 29 19:53:13 2001/-ko/ +/kernel-hacking.tmpl/1.5/Tue May 29 19:53:13 2001/-ko/ +/kernel-locking.tmpl/1.6/Tue May 29 19:53:13 2001/-ko/ +/mcabook.tmpl/1.1/Wed Mar 15 18:02:00 2000/-ko/ +/mousedrivers.tmpl/1.2/Fri Jan 5 18:42:30 2001/-ko/ +/parport-multi.fig/1.1/Wed Mar 15 18:02:00 2000/-ko/ +/parport-share.fig/1.1/Wed Mar 15 18:02:00 2000/-ko/ +/parport-structure.fig/1.1/Wed Mar 15 18:02:00 2000/-ko/ +/parportbook.tmpl/1.4/Wed May 2 06:22:13 2001/-ko/ +/procfs-guide.tmpl/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/procfs_example.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sis900.tmpl/1.1/Wed Jan 3 01:43:05 2001/-ko/ +/tulip-user.tmpl/1.1/Wed May 2 06:22:13 2001/-ko/ +/via-audio.tmpl/1.2/Wed Nov 1 21:35:42 2000/-ko/ +/videobook.tmpl/1.5/Fri Jan 5 18:42:30 2001/-ko/ +/wanbook.tmpl/1.1/Wed Mar 15 18:02:00 2000/-ko/ +/z8530book.tmpl/1.2/Fri Jan 5 18:42:30 2001/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/DocBook/CVS/Repository linux-2.4-xfs/linux/Documentation/DocBook/CVS/Repository --- linux-2.4.7/linux/Documentation/DocBook/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/DocBook/CVS/Repository Thu Jul 5 11:46:24 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/DocBook diff -rNu linux-2.4.7/linux/Documentation/DocBook/CVS/Root linux-2.4-xfs/linux/Documentation/DocBook/CVS/Root --- linux-2.4.7/linux/Documentation/DocBook/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/DocBook/CVS/Root Thu Jul 5 11:46:24 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/arm/CVS/Entries linux-2.4-xfs/linux/Documentation/arm/CVS/Entries --- linux-2.4.7/linux/Documentation/arm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/arm/CVS/Entries Thu Jul 5 11:46:31 2001 @@ -0,0 +1,4 @@ +/Netwinder/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README/1.6/Wed May 2 06:22:13 2001/-ko/ +/Setup/1.2/Tue May 2 21:09:12 2000/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/arm/CVS/Entries.Log linux-2.4-xfs/linux/Documentation/arm/CVS/Entries.Log --- linux-2.4.7/linux/Documentation/arm/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/arm/CVS/Entries.Log Thu Jul 5 11:46:32 2001 @@ -0,0 +1,3 @@ +A D/SA1100//// +A D/empeg//// +A D/nwfpe//// diff -rNu linux-2.4.7/linux/Documentation/arm/CVS/Repository linux-2.4-xfs/linux/Documentation/arm/CVS/Repository --- linux-2.4.7/linux/Documentation/arm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/arm/CVS/Repository Thu Jul 5 11:46:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/arm diff -rNu linux-2.4.7/linux/Documentation/arm/CVS/Root linux-2.4-xfs/linux/Documentation/arm/CVS/Root --- linux-2.4.7/linux/Documentation/arm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/arm/CVS/Root Thu Jul 5 11:46:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/arm/SA1100/CVS/Entries linux-2.4-xfs/linux/Documentation/arm/SA1100/CVS/Entries --- linux-2.4.7/linux/Documentation/arm/SA1100/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/arm/SA1100/CVS/Entries Thu Jul 5 11:46:32 2001 @@ -0,0 +1,14 @@ +/Assabet/1.1/Fri May 26 01:26:22 2000/-ko/ +/Brutus/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/CERF/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/GraphicsClient/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/Itsy/1.1/Sat Oct 23 02:00:20 1999/-ko/ +/LART/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/PLEB/1.1/Sat Oct 23 02:00:20 1999/-ko/ +/Pangolin/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/Tifon/1.1/Sat Oct 23 02:00:20 1999/-ko/ +/Victor/1.1/Sat Oct 23 02:00:20 1999/-ko/ +/empeg/1.1/Sat Oct 23 02:00:20 1999/-ko/ +/nanoEngine/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/serial_UART/1.1/Sun Dec 17 19:15:00 2000/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/arm/SA1100/CVS/Repository linux-2.4-xfs/linux/Documentation/arm/SA1100/CVS/Repository --- linux-2.4.7/linux/Documentation/arm/SA1100/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/arm/SA1100/CVS/Repository Thu Jul 5 11:46:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/arm/SA1100 diff -rNu linux-2.4.7/linux/Documentation/arm/SA1100/CVS/Root linux-2.4-xfs/linux/Documentation/arm/SA1100/CVS/Root --- linux-2.4.7/linux/Documentation/arm/SA1100/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/arm/SA1100/CVS/Root Thu Jul 5 11:46:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/arm/empeg/CVS/Entries linux-2.4-xfs/linux/Documentation/arm/empeg/CVS/Entries --- linux-2.4.7/linux/Documentation/arm/empeg/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/arm/empeg/CVS/Entries Thu Jul 5 11:46:32 2001 @@ -0,0 +1,4 @@ +/README/1.1/Sat Oct 23 02:00:20 1999/-ko/ +/ir.txt/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/mkdevs/1.1/Sat Oct 23 02:00:20 1999/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/arm/empeg/CVS/Repository linux-2.4-xfs/linux/Documentation/arm/empeg/CVS/Repository --- linux-2.4.7/linux/Documentation/arm/empeg/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/arm/empeg/CVS/Repository Thu Jul 5 11:46:32 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/arm/empeg diff -rNu linux-2.4.7/linux/Documentation/arm/empeg/CVS/Root linux-2.4-xfs/linux/Documentation/arm/empeg/CVS/Root --- linux-2.4.7/linux/Documentation/arm/empeg/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/arm/empeg/CVS/Root Thu Jul 5 11:46:32 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/arm/nwfpe/CVS/Entries linux-2.4-xfs/linux/Documentation/arm/nwfpe/CVS/Entries --- linux-2.4.7/linux/Documentation/arm/nwfpe/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/arm/nwfpe/CVS/Entries Thu Jul 5 11:46:32 2001 @@ -0,0 +1,5 @@ +/NOTES/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/README.FPE/1.3/Sat Oct 23 02:00:20 1999/-ko/ +/TODO/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/arm/nwfpe/CVS/Repository linux-2.4-xfs/linux/Documentation/arm/nwfpe/CVS/Repository --- linux-2.4.7/linux/Documentation/arm/nwfpe/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/arm/nwfpe/CVS/Repository Thu Jul 5 11:46:32 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/arm/nwfpe diff -rNu linux-2.4.7/linux/Documentation/arm/nwfpe/CVS/Root linux-2.4-xfs/linux/Documentation/arm/nwfpe/CVS/Root --- linux-2.4.7/linux/Documentation/arm/nwfpe/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/arm/nwfpe/CVS/Root Thu Jul 5 11:46:32 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/cdrom/CVS/Entries linux-2.4-xfs/linux/Documentation/cdrom/CVS/Entries --- linux-2.4.7/linux/Documentation/cdrom/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/cdrom/CVS/Entries Thu Jul 5 11:46:36 2001 @@ -0,0 +1,16 @@ +/00-INDEX/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Makefile/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/aztcd/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cdrom-standard.tex/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/cdu31a/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cm206/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/gscd/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ide-cd/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/isp16/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mcd/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mcdx/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/optcd/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sbpcd/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sjcd/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sonycd535/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/cdrom/CVS/Repository linux-2.4-xfs/linux/Documentation/cdrom/CVS/Repository --- linux-2.4.7/linux/Documentation/cdrom/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/cdrom/CVS/Repository Thu Jul 5 11:46:32 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/cdrom diff -rNu linux-2.4.7/linux/Documentation/cdrom/CVS/Root linux-2.4-xfs/linux/Documentation/cdrom/CVS/Root --- linux-2.4.7/linux/Documentation/cdrom/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/cdrom/CVS/Root Thu Jul 5 11:46:32 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/cris/CVS/Entries linux-2.4-xfs/linux/Documentation/cris/CVS/Entries --- linux-2.4.7/linux/Documentation/cris/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/cris/CVS/Entries Thu Jul 5 11:46:36 2001 @@ -0,0 +1,2 @@ +/README/1.3/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/cris/CVS/Repository linux-2.4-xfs/linux/Documentation/cris/CVS/Repository --- linux-2.4.7/linux/Documentation/cris/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/cris/CVS/Repository Thu Jul 5 11:46:36 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/cris diff -rNu linux-2.4.7/linux/Documentation/cris/CVS/Root linux-2.4-xfs/linux/Documentation/cris/CVS/Root --- linux-2.4.7/linux/Documentation/cris/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/cris/CVS/Root Thu Jul 5 11:46:36 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/fb/CVS/Entries linux-2.4-xfs/linux/Documentation/fb/CVS/Entries --- linux-2.4.7/linux/Documentation/fb/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/fb/CVS/Entries Thu Jul 5 11:46:37 2001 @@ -0,0 +1,11 @@ +/00-INDEX/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/aty128fb.txt/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/clgenfb.txt/1.4/Thu Jan 6 21:20:23 2000/-ko/ +/framebuffer.txt/1.8/Tue May 29 19:53:13 2001/-ko/ +/internals.txt/1.3/Mon Aug 30 00:17:07 1999/-ko/ +/matroxfb.txt/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/modedb.txt/1.2/Fri Jun 2 00:22:59 2000/-ko/ +/sa1100fb.txt/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/tgafb.txt/1.2/Tue May 2 21:09:12 2000/-ko/ +/vesafb.txt/1.3/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/fb/CVS/Repository linux-2.4-xfs/linux/Documentation/fb/CVS/Repository --- linux-2.4.7/linux/Documentation/fb/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/fb/CVS/Repository Thu Jul 5 11:46:36 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/fb diff -rNu linux-2.4.7/linux/Documentation/fb/CVS/Root linux-2.4-xfs/linux/Documentation/fb/CVS/Root --- linux-2.4.7/linux/Documentation/fb/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/fb/CVS/Root Thu Jul 5 11:46:36 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/filesystems/00-INDEX linux-2.4-xfs/linux/Documentation/filesystems/00-INDEX --- linux-2.4.7/linux/Documentation/filesystems/00-INDEX Wed Jun 20 13:10:27 2001 +++ linux-2.4-xfs/linux/Documentation/filesystems/00-INDEX Thu Jun 21 10:45:04 2001 @@ -44,3 +44,5 @@ - info on using the VFAT filesystem used in Windows NT and Windows 95 vfs.txt - Overview of the Virtual File System +xfs.txt + - info amd mount options for the XFS filesystem. diff -rNu linux-2.4.7/linux/Documentation/filesystems/CVS/Entries linux-2.4-xfs/linux/Documentation/filesystems/CVS/Entries --- linux-2.4.7/linux/Documentation/filesystems/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/filesystems/CVS/Entries Thu Jul 5 11:46:41 2001 @@ -0,0 +1,24 @@ +/00-INDEX/1.9/Thu Jun 21 15:45:04 2001/-ko/ +/Locking/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/adfs.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/affs.txt/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/bfs.txt/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/coda.txt/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/cramfs.txt/1.3/Fri May 26 01:52:46 2000/-ko/ +/ext2.txt/1.2/Wed May 2 06:22:13 2001/-ko/ +/fat_cvf.txt/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/hpfs.txt/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/isofs.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ncpfs.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ntfs.txt/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/proc.txt/1.7/Wed May 2 06:22:13 2001/-ko/ +/romfs.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/smbfs.txt/1.3/Mon Oct 18 06:25:48 1999/-ko/ +/sysv-fs.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/udf.txt/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/ufs.txt/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/umsdos.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/vfat.txt/1.5/Wed May 2 06:22:13 2001/-ko/ +/vfs.txt/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/xfs.txt/1.6/Fri Jun 29 22:29:47 2001/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/filesystems/CVS/Entries.Log linux-2.4-xfs/linux/Documentation/filesystems/CVS/Entries.Log --- linux-2.4.7/linux/Documentation/filesystems/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/filesystems/CVS/Entries.Log Thu Jul 5 11:46:41 2001 @@ -0,0 +1 @@ +A D/devfs//// diff -rNu linux-2.4.7/linux/Documentation/filesystems/CVS/Repository linux-2.4-xfs/linux/Documentation/filesystems/CVS/Repository --- linux-2.4.7/linux/Documentation/filesystems/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/filesystems/CVS/Repository Thu Jul 5 11:46:37 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/filesystems diff -rNu linux-2.4.7/linux/Documentation/filesystems/CVS/Root linux-2.4-xfs/linux/Documentation/filesystems/CVS/Root --- linux-2.4.7/linux/Documentation/filesystems/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/filesystems/CVS/Root Thu Jul 5 11:46:37 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/filesystems/devfs/CVS/Entries linux-2.4-xfs/linux/Documentation/filesystems/devfs/CVS/Entries --- linux-2.4.7/linux/Documentation/filesystems/devfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/filesystems/devfs/CVS/Entries Thu Jul 5 11:46:42 2001 @@ -0,0 +1,6 @@ +/ChangeLog/1.9/Thu Jun 21 15:45:04 2001/-ko/ +/README/1.7/Wed Jun 13 03:24:09 2001/-ko/ +/ToDo/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/boot-options/1.2/Fri May 26 01:14:50 2000/-ko/ +/rc.devfs/1.1/Thu Feb 17 20:30:57 2000/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/filesystems/devfs/CVS/Repository linux-2.4-xfs/linux/Documentation/filesystems/devfs/CVS/Repository --- linux-2.4.7/linux/Documentation/filesystems/devfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/filesystems/devfs/CVS/Repository Thu Jul 5 11:46:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/filesystems/devfs diff -rNu linux-2.4.7/linux/Documentation/filesystems/devfs/CVS/Root linux-2.4-xfs/linux/Documentation/filesystems/devfs/CVS/Root --- linux-2.4.7/linux/Documentation/filesystems/devfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/filesystems/devfs/CVS/Root Thu Jul 5 11:46:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/filesystems/xfs.txt linux-2.4-xfs/linux/Documentation/filesystems/xfs.txt --- linux-2.4.7/linux/Documentation/filesystems/xfs.txt Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/filesystems/xfs.txt Fri Jun 29 17:29:47 2001 @@ -0,0 +1,111 @@ + +The SGI XFS Filesystem +====================== + +XFS is a high performance journaling filesystem which originated +on the SGI IRIX platform. It is completely multi-threaded, can +support large files and large filesystems, extended attributes, +variable block sizes, is extent based, and makes extensive use of +Btrees (directories, extents, free space) to aid both performance +and scalability. + +Refer to the documentation at http://oss.sgi.com/projects/xfs/ +for further details. This implementation is on-disk compatible +with the IRIX version of XFS. + + +Options +======= + +When mounting an XFS filesystem, the following options are accepted. + + biosize=size + Sets the preferred buffered I/O size (default size is 64K). + "size" must be expressed as the logarithm (base2) of the + desired I/O size. + Valid values for this option are 14 through 16, inclusive + (i.e. 16K, 32K, and 64K bytes). On machines with a 4K + pagesize, 13 (8K bytes) is also a valid size. + The preferred buffered I/O size can also be altered on an + individual file basis using the ioctl(2) system call. + + dmapi/xdsm + Enable the DMAPI (Data Management API) event callouts. + + logbufs=value + Set the number of in-memory log buffers. Valid numbers range + from 2-8 inclusive. + The default value is 8 buffers for filesystems with a + blocksize of 64K, 4 buffers for filesystems with a blocksize + of 32K, 3 buffers for filesystems with a blocksize of 16K + and 2 buffers for all other configurations. Increasing the + number of buffers may increase performance on some workloads + at the cost of the memory used for the additional log buffers + and their associated control structures. + + logbsize=value + Set the size of each in-memory log buffer. + Valid sizes are 16384 (16K) and 32768 (32K). + The default value for machines with more than 32MB of memory + is 32768, machines with less memory use 16384 by default. + + logdev=device and rtdev=device + Use an external log (metadata journal) and/or real-time device. + An XFS filesystem has up to three parts: a data section, a log + section, and a real-time section. The real-time section is + optional, and the log section can be separate from the data + section or contained within it. + + noalign + Data allocations will not be aligned at stripe unit boundaries. + + noatime + Access timestamps are not updated when a file is read. + + norecovery + The filesystem will be mounted without running log recovery. + If the filesystem was not cleanly unmounted, it is likely to + be inconsistent when mounted in "norecovery" mode. + Some files or directories may not be accessible because of this. + Filesystems mounted "norecovery" must be mounted read-only or + the mount will fail. + + osyncisdsync + Make writes to files opened with the O_SYNC flag set behave + as if the O_DSYNC flag had been used instead. + This can result in better performance without compromising + data safety. + However if this option is in effect, timestamp updates from + O_SYNC writes can be lost if the system crashes. + + quota/usrquota/uqnoenforce + User disk quota accounting enabled, and limits (optionally) + enforced. + + grpquota/gqnoenforce + Group disk quota accounting enabled and limits (optionally) + enforced. + + sunit=value and swidth=value + Used to specify the stripe unit and width for a RAID device or + a stripe volume. "value" must be specified in 512-byte block + units. + If this option is not specified and the filesystem was made on + a stripe volume or the stripe width or unit were specified for + the RAID device at mkfs time, then the mount system call will + restore the value from the superblock. For filesystems that + are made directly on RAID devices, these options can be used + to override the information in the superblock if the underlying + disk layout changes after the filesystem has been created. + The "swidth" option is required if the "sunit" option has been + specified, and must be a multiple of the "sunit" value. + + kio + Issue I/O requests down to the disk drivers using kiobufs + instead of buffer heads. This is implemented for ide and scsi + devices, it is not available for lvm or md at the moment. + + nouuid + Don't check for double mounted file systems using the file system uuid. + This is useful to mount LVM snapshot volumes. + diff -rNu linux-2.4.7/linux/Documentation/i2c/CVS/Entries linux-2.4-xfs/linux/Documentation/i2c/CVS/Entries --- linux-2.4.7/linux/Documentation/i2c/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/i2c/CVS/Entries Thu Jul 5 11:46:42 2001 @@ -0,0 +1,9 @@ +/dev-interface/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/functionality/1.1/Wed Jan 3 01:43:05 2001/-ko/ +/i2c-protocol/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/proc-interface/1.1/Tue Dec 21 19:02:48 1999/-ko/ +/smbus-protocol/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/summary/1.1/Tue Dec 21 19:02:48 1999/-ko/ +/ten-bit-addresses/1.1/Tue Dec 21 19:02:48 1999/-ko/ +/writing-clients/1.4/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/i2c/CVS/Repository linux-2.4-xfs/linux/Documentation/i2c/CVS/Repository --- linux-2.4.7/linux/Documentation/i2c/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/i2c/CVS/Repository Thu Jul 5 11:46:42 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/i2c diff -rNu linux-2.4.7/linux/Documentation/i2c/CVS/Root linux-2.4-xfs/linux/Documentation/i2c/CVS/Root --- linux-2.4.7/linux/Documentation/i2c/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/i2c/CVS/Root Thu Jul 5 11:46:42 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/i386/CVS/Entries linux-2.4-xfs/linux/Documentation/i386/CVS/Entries --- linux-2.4.7/linux/Documentation/i386/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/i386/CVS/Entries Thu Jul 5 11:46:42 2001 @@ -0,0 +1,4 @@ +/IO-APIC.txt/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/boot.txt/1.2/Wed May 2 06:22:13 2001/-ko/ +/zero-page.txt/1.3/Mon Sep 6 21:00:05 1999/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/i386/CVS/Repository linux-2.4-xfs/linux/Documentation/i386/CVS/Repository --- linux-2.4.7/linux/Documentation/i386/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/i386/CVS/Repository Thu Jul 5 11:46:42 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/i386 diff -rNu linux-2.4.7/linux/Documentation/i386/CVS/Root linux-2.4-xfs/linux/Documentation/i386/CVS/Root --- linux-2.4.7/linux/Documentation/i386/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/i386/CVS/Root Thu Jul 5 11:46:42 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/ia64/CVS/Entries linux-2.4-xfs/linux/Documentation/ia64/CVS/Entries --- linux-2.4.7/linux/Documentation/ia64/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/ia64/CVS/Entries Thu Jul 5 11:46:42 2001 @@ -0,0 +1,3 @@ +/README/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/efirtc.txt/1.3/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/ia64/CVS/Repository linux-2.4-xfs/linux/Documentation/ia64/CVS/Repository --- linux-2.4.7/linux/Documentation/ia64/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/ia64/CVS/Repository Thu Jul 5 11:46:42 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/ia64 diff -rNu linux-2.4.7/linux/Documentation/ia64/CVS/Root linux-2.4-xfs/linux/Documentation/ia64/CVS/Root --- linux-2.4.7/linux/Documentation/ia64/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/ia64/CVS/Root Thu Jul 5 11:46:42 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/isdn/CVS/Entries linux-2.4-xfs/linux/Documentation/isdn/CVS/Entries --- linux-2.4.7/linux/Documentation/isdn/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/isdn/CVS/Entries Thu Jul 5 11:46:44 2001 @@ -0,0 +1,24 @@ +/00-INDEX/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/CREDITS/1.5/Thu Feb 17 20:30:57 2000/-ko/ +/HiSax.cert/1.3/Thu Feb 17 20:30:57 2000/-ko/ +/INTERFACE/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/INTERFACE.fax/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/README/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/README.FAQ/1.1/Fri Nov 12 18:38:14 1999/-ko/ +/README.HiSax/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/README.act2000/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/README.audio/1.3/Sun Aug 29 03:33:57 1999/-ko/ +/README.avmb1/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/README.concap/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/README.diversion/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/README.eicon/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/README.fax/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/README.hfc-pci/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/README.hysdn/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/README.icn/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/README.pcbit/1.3/Fri Nov 12 18:38:14 1999/-ko/ +/README.sc/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/README.syncppp/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README.x25/1.3/Thu Feb 17 20:30:57 2000/-ko/ +/syncPPP.FAQ/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/isdn/CVS/Repository linux-2.4-xfs/linux/Documentation/isdn/CVS/Repository --- linux-2.4.7/linux/Documentation/isdn/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/isdn/CVS/Repository Thu Jul 5 11:46:42 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/isdn diff -rNu linux-2.4.7/linux/Documentation/isdn/CVS/Root linux-2.4-xfs/linux/Documentation/isdn/CVS/Root --- linux-2.4.7/linux/Documentation/isdn/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/isdn/CVS/Root Thu Jul 5 11:46:42 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/kbuild/CVS/Entries linux-2.4-xfs/linux/Documentation/kbuild/CVS/Entries --- linux-2.4.7/linux/Documentation/kbuild/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/kbuild/CVS/Entries Thu Jul 5 11:46:44 2001 @@ -0,0 +1,6 @@ +/00-INDEX/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/bug-list.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/commands.txt/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/config-language.txt/1.8/Thu Sep 28 22:42:39 2000/-ko/ +/makefiles.txt/1.5/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/kbuild/CVS/Repository linux-2.4-xfs/linux/Documentation/kbuild/CVS/Repository --- linux-2.4.7/linux/Documentation/kbuild/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/kbuild/CVS/Repository Thu Jul 5 11:46:44 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/kbuild diff -rNu linux-2.4.7/linux/Documentation/kbuild/CVS/Root linux-2.4-xfs/linux/Documentation/kbuild/CVS/Root --- linux-2.4.7/linux/Documentation/kbuild/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/kbuild/CVS/Root Thu Jul 5 11:46:44 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/kdb/CVS/Entries linux-2.4-xfs/linux/Documentation/kdb/CVS/Entries --- linux-2.4.7/linux/Documentation/kdb/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/kdb/CVS/Entries Thu Jul 5 11:46:44 2001 @@ -0,0 +1,9 @@ +/kdb.mm/1.11/Tue Feb 27 05:07:04 2001/-ko/ +/kdb_bp.man/1.5/Wed Oct 4 11:42:46 2000/-ko/ +/kdb_bt.man/1.6/Wed Oct 4 11:42:46 2000/-ko/ +/kdb_env.man/1.4/Wed Oct 4 11:42:46 2000/-ko/ +/kdb_ll.man/1.4/Wed Oct 4 11:42:46 2000/-ko/ +/kdb_md.man/1.5/Wed Oct 4 11:42:46 2000/-ko/ +/kdb_rd.man/1.5/Wed Oct 4 11:42:46 2000/-ko/ +/kdb_ss.man/1.4/Wed Oct 4 11:42:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/kdb/CVS/Repository linux-2.4-xfs/linux/Documentation/kdb/CVS/Repository --- linux-2.4.7/linux/Documentation/kdb/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/kdb/CVS/Repository Thu Jul 5 11:46:44 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/kdb diff -rNu linux-2.4.7/linux/Documentation/kdb/CVS/Root linux-2.4-xfs/linux/Documentation/kdb/CVS/Root --- linux-2.4.7/linux/Documentation/kdb/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/kdb/CVS/Root Thu Jul 5 11:46:44 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/kdb/kdb.mm linux-2.4-xfs/linux/Documentation/kdb/kdb.mm --- linux-2.4.7/linux/Documentation/kdb/kdb.mm Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/kdb/kdb.mm Mon Feb 26 23:07:04 2001 @@ -0,0 +1,284 @@ +.TH KDB 8 "27 February 2001" +.hy 0 +.SH NAME +Built-in Kernel Debugger for Linux - v1.8 +.SH "Overview" +This document describes the built-in kernel debugger available +for linux. This debugger allows the programmer to interactively +examine kernel memory, disassemble kernel functions, set breakpoints +in the kernel code and display and modify register contents. +.P +A symbol table is included in the kernel image and in modules which +enables all non-stack symbols (including static symbols) to be used as +arguments to the kernel debugger commands. +.SH "Getting Started" +To include the kernel debugger in a linux kernel, use a +configuration mechanism (e.g. xconfig, menuconfig, et. al.) +to enable the \fBCONFIG_KDB\fP option. Additionally, for accurate +stack tracebacks, it is recommended that the \fBCONFIG_FRAME_POINTER\fP +option be enabled. \fBCONFIG_FRAME_POINTER\fP changes the compiler +flags so that the frame pointer register will be used as a frame +pointer rather than a general purpose register. +.P +After linux has been configured to include the kernel debugger, +make a new kernel with the new configuration file (a make clean +is recommended before making the kernel), and install the kernel +as normal. +.P +You can compile a kernel with kdb support but have kdb off by default, +select \fBCONFIG_KDB_OFF\fR. Then the user has to explicitly activate +kdb by booting with the 'kdb=on' flag or, after /proc is mounted, by +.nf + echo "1" > /proc/sys/kernel/kdb +.fi +You can also do the reverse, compile a kernel with kdb on and +deactivate kdb with the boot flag 'kdb=off' or, after /proc is mounted, +by +.nf + echo "0" > /proc/sys/kernel/kdb +.fi +.P +When booting the new kernel using \fIlilo\fP(1), the 'kdb=early' flag +may be added after the image name on the \fBLILO\fP boot line to +force the kernel to stop in the kernel debugger early in the +kernel initialization process. 'kdb=early' implies 'kdb=on'. +If the 'kdb=early' flag isn't provided, then kdb will automatically be +invoked upon system panic or when the \fBPAUSE\fP key is used from the +keyboard, assuming that kdb is on. Older versions of kdb used just a +boot flag of 'kdb' to activate kdb early, this is still supported but +is deprecated. +.P +Kdb can also be used via the serial port. Set up the system to +have a serial console (see \fIDocumentation/serial-console.txt\fP). +The \fBControl-A\fP key sequence on the serial port will cause the +kernel debugger to be entered, assuming that kdb is on. +.P +If you have both a keyboard+video and a serial console, you can use +either for kdb. +Define both video and serial consoles with boot parameters +.P +.nf + console=tty0 console=/dev/ttyS0,38400 +.fi +.P +Any kdb data entered on the keyboard or the serial console will be echoed +to both. +.P +While kdb is active, the keyboard (not serial console) indicators will strobe. +The caps lock and scroll lock lights will turn on and off, num lock is not used +because it can confuse laptop keyboards where the numeric keypad is mapped over +the normal keys. +On exit from kdb the keyboard indicators will probably be wrong, they will not match the kernel state. +Pressing caps lock twice should get the indicators back in sync with +the kernel. +.SH "Basic Commands" +There are several categories of commands available to the +kernel debugger user including commands providing memory +display and modification, register display and modification, +instruction disassemble, breakpoints and stack tracebacks. +.P +The following table shows the currently implemented commands: +.DS +.TS +box, center; +l | l +l | l. +Command Description +_ +bc Clear Breakpoint +bd Disable Breakpoint +be Enable Breakpoint +bl Display breakpoints +bp Set or Display breakpoint +bph Set or Display hardware breakpoint +bpa Set or Display breakpoint globally +bpha Set or Display hardware breakpoint globally +bt Stack backtrace for current process +btp Stack backtrace for specific process +bta Stack backtrace for all processes +cpu Display or switch cpus +ef Print exception frame +env Show environment +go Restart execution +help Display help message +id Disassemble Instructions +ll Follow Linked Lists +lsmod List loaded modules +md Display memory contents +mdr Display raw memory contents +mds Display memory contents symbolically +mm Modify memory contents +reboot Reboot the machine +rd Display register contents +rm Modify register contents +rmmod Remove a module +sections List information on all known sections +set Add/change environment variable +sr Invoke SysReq commands +ss Single step a cpu +ssb Single step a cpu until a branch instruction +.TE +.DE +.P +Some commands can be abbreviated, such commands are indicated by a +non-zero \fIminlen\fP parameter to \fBkdb_register\fP; the value of +\fIminlen\fP being the minimum length to which the command can be +abbreviated (for example, the \fBgo\fP command can be abbreviated +legally to \fBg\fP). +.P +If an input string does not match a command in the command table, +it is treated as an address expression and the corresponding address +value and nearest symbol are shown. +.P +Some of the commands are described here. +Information on the more complicated commands can be found in the +appropriate manual pages. +.TP 8 +cpu +With no parameters, it lists the available cpus, '*' after a cpu number +indicates a cpu that did not respond to the kdb stop signal. +.I cpu +followed by a number will switch to that cpu, you cannot switch to +a cpu marked '*'. +This command is only available if the kernel was configured for SMP. +.TP 8 +go +Continue normal execution. +Active breakpoints are reestablished and the processor(s) allowed to +run normally. +To continue at a specific address, use +.I rm +to change the instruction pointer then go. +.TP 8 +id +Disassemble instructions starting at an address. +Environment variable IDCOUNT controls how many lines of disassembly +output the command produces. +.TP 8 +lsmod +Internal command to list modules. +This does not use any kernel nor user space services so can be used at any time. +.TP 8 +reboot +Reboot the system, with no attempt to do a clean close down. +.TP 8 +rmmod +Internal command to remove a module. +This does not use any user space services, however it calls the module +cleanup routine and that routine may try to use kernel services. +Because kdb runs disabled there is no guarantee that the module cleanup +routine will succeed, there is a real risk of the routine hanging and +taking kdb with it. +Use the +.I rmmod +command with extreme care. +.TP 8 +sections +List information for all known sections. The output is one line per +module plus the kernel, starting with the module name. This is +followed by one or more repeats of section name, section start, +section end and section flags. This data is not designed for human +readability, it is intended to tell external debuggers where each +section has been loaded. +.TP 8 +sr +Invoke the SysReq code. +This command takes a single character which is passed to SysReq +processing, as if you had entered the SysReq key sequence followed by +that character. +.SH INITIAL KDB COMMANDS +kdb/kdb_cmds is a plain text file where you can define kdb commands +which are to be issued during kdb_init(). One command per line, blank +lines are ignored, lines starting with '#' are ignored. kdb_cmds is +intended for per user customization of kdb, you can use it to set +environment variables to suit your hardware or to set standard +breakpoints for the problem you are debugging. This file is converted +to a small C object, compiled and linked into the kernel. You must +rebuild and reinstall the kernel after changing kdb_cmds. This file +will never be shipped with any useful data so you can always override +it with your local copy. Sample kdb_cmds: +.P +.nf +# Initial commands for kdb, alter to suit your needs. +# These commands are executed in kdb_init() context, no SMP, no +# processes. Commands that require process data (including stack or +# registers) are not reliable this early. set and bp commands should +# be safe. Global breakpoint commands affect each cpu as it is booted. + +set LINES=50 +set MDCOUNT=25 +set RECURSE=1 +bp sys_init_module +.fi +.SH INTERRUPTS AND KDB +When a kdb event occurs, one cpu (the initial cpu) enters kdb state. +It uses a cross system non maskable interrupt (NMI) to interrupt the +other cpus and bring them all into kdb state. All cpus run with +interrupts disabled while they are inside kdb, this prevents most +external events from disturbing the kernel while kdb is running. +.B Note: +Disabled interrupts means that any I/O that relies on interrupts cannot +proceed while kdb is in control, devices can time out. The clock tick +is also disabled, machines will lose track of time while they are +inside kdb. +.P +Even with interrupts disabled, some NMI events will still occur, these +can disturb the kernel while you are debugging it. The initial cpu +will still accept NMI events, assuming that kdb was not entered for an +NMI event. Any cpu where you use the SS or SSB commands will accept +NMI events, even after the instruction has finished and the cpu is back +in kdb. This is an unavoidable side effect of the fact that doing +SS[B] requires the cpu to drop all the way out of kdb, including +exiting from the NMI event that brought the cpu into kdb. Under normal +circumstances the only NMI event is for the NMI oopser and that is kdb +aware so it does not disturb the kernel while kdb is running. +.P +Sometimes doing SS or SSB on ix86 will allow one interrupt to proceed, +even though the cpu is disabled for interrupts. I have not been able +to track this one down but I suspect that the interrupt was pending +when kdb was entered and it runs when kdb exits through IRET even +though the popped flags are marked as cli(). If any ix86 hardware +expert can shed some light on this problem, please notify the kdb +maintainer. +.SH RECOVERING FROM KDB ERRORS +If a kdb command breaks and kdb has enough of a recovery environment +then kdb will abort the command and drop back into mainline kdb code. +This means that user written kdb commands can follow bad pointers +without killing kdb. Ideally all code should verify that data areas +are valid (using kdba_getword) before accessing it but lots of calls +to kdba_getword can be clumsy. +.SH DEBUGGING THE DEBUGGER +kdb has limited support for debugging problems within kdb. If you +suspect that kdb is failing, you can set environment variable KDBDEBUG +to a bit pattern which will activate kdb_printf statements within kdb. +See include/linux/kdb.h, KDB_DEBUG_FLAG_xxx defines. For example +.nf + set KDBDEBUG=0x60 +.fi +activates the event callbacks into kdb plus state tracing in sections +of kdb. +.nf + set KDBDEBUG=0x18 +.fi +gives lots of tracing as kdb tries to decode the process stack. +.P +You can also perform one level of recursion in kdb. If environment +variable RECURSE is not set or is 0 then kdb will either recover from +an error (if the recovery environment is satisfactory) or kdb will +allow the error to percolate, usually resulting in a dead system. When +RECURSE is 1 then kdb will recover from an error or, if there is no +satisfactory recovery environment, it will drop into kdb state to let +you diagnose the problem. When RECURSE is 2 then all errors drop into +kdb state, kdb does not attempt recovery first. Errors while in +recursive state all drop through, kdb does not even attempt to recover +from recursive errors. +.SH WRITING NEW COMMANDS +TBD +.SH AUTHORS +Scott Lurndal, Richard Bass, Scott Foehner, Srinivasa Thirumalachar, +Masahiro Adegawa, Marc Esipovich, Ted Kline, Steve Lord, Andi Kleen. +.br +Keith Owens - kdb maintainer. +.SH SEE ALSO +.P +linux/Documentation/kdb/kdb_{bp,bt,env,ll,md,rd,ss}.man diff -rNu linux-2.4.7/linux/Documentation/kdb/kdb_bp.man linux-2.4-xfs/linux/Documentation/kdb/kdb_bp.man --- linux-2.4.7/linux/Documentation/kdb/kdb_bp.man Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/kdb/kdb_bp.man Wed Oct 4 06:42:46 2000 @@ -0,0 +1,172 @@ +.TH BD 1 "19 May 2000" +.SH NAME +bp, bpa, bph, bpha, bd, bc, be, bl \- breakpoint commands +.SH SYNOPSIS +bp \fIaddress-expression\fP +.LP +bpa \fIaddress-expression\fP +.LP +bph \fIaddress-expression\fP [\f(CWDATAR|DATAW|IO\fP [\fIlength\fP]] +.LP +bpha \fIaddress-expression\fP [\f(CWDATAR|DATAW|IO\fP [\fIlength\fP]] +.LP +bd \fIbreakpoint-number\fP +.LP +bc \fIbreakpoint-number\fP +.LP +be \fIbreakpoint-number\fP +.LP +bl +.SH DESCRIPTION +.hy 0 +The +.B bp +family of commands are used to establish a breakpoint. +The \fIaddress-expression\fP may be a numeric value (decimal or +hexidecimal), a symbol name, a register name preceeded by a +percent symbol '%', or a simple expression consisting of a +symbol name, an addition or subtraction character and a numeric +value (decimal or hexidecimal). +.P +\fBbph\fP and \fBbpha\fP will force the use of a hardware register, provided +the processor architecture supports them. +.P +The \fIaddress-expression\fP may also consist of a single +asterisk '*' symbol which indicates that the command should +operate on all existing breakpoints (valid only for \fBbc\fP, +\fBbd\fP and \fBbe\fP). +.P +Four different types of +breakpoints may be set: + +.TP 8 +Instruction +Causes the kernel debugger to be invoked from the debug exception +path when an instruction is fetched from the specified address. This +is the default if no other type of breakpoint is requested or when +the \fBbp\fP command is used. + +.TP 8 +DATAR +Causes the kernel debugger to be entered when data of length +\fIlength\fP is read from or written to the specified address. +This type of breakpoint must use a processor debug register which +places an architecture dependent limit on the number of data and I/O +breakpoints that may be established. +The \fBbph\fP or \fBbpha\fP commands must be used. + +.TP 8 +DATAW +Enters the kernel debugger when data of length \fIlength\fP +is written to the specified address. \fIlength\fP defaults +to four bytes if it is not explicitly specified. +Note that the processor may have already overwritten the prior data at +the breakpoint location before the kernel debugger is invoked. +The prior data should be saved before establishing the breakpoint, if +required. +The \fBbph\fP or \fBbpha\fP commands must be used. + +.TP 8 +IO +Enters the kernel debugger when an \fBin\fP or \fBout\fP instruction +targets the specified I/O address. The \fBbph\fP or \fBbpha\fP +commands must be used. + +.P +The +.B bpha +command will establish a breakpoint on all processors in an +SMP system. This command is not available in an uniprocessor +kernel. +.P +The +.B bd +command will disable a breakpoint without removing it from the kernel +debugger's breakpoint table. +This can be used to keep breakpoints in the table without exceeding the +architecture limit on breakpoint registers. +.P +The +.B be +command will re-enable a disabled breakpoint. +.P +The +.B bc +command will clear a breakpoint from the breakpoint table. +.P +The +.B bl +command will list the existing set of breakpoints. +.SH LIMITATIONS +There is a compile time limit of sixteen entries in the +breakpoint table at any one time. +.P +There are architecture dependent limits on the number of hardware +breakpoints that can be set. +.IP ix86 8 +Four. +.PD 0 +.IP ia64 8 +? +.PD 1 +.SH ENVIRONMENT +The breakpoint subsystem does not currently use any environment +variables. +.SH SMP CONSIDERATIONS +Using +.B bc +is risky on SMP systems. +If you clear a breakpoint when another cpu has hit that breakpoint but +has not been processed then it may not be recognised as a kdb +breakpoint, usually resulting in incorrect program counters and kernel +panics. +It is safer to disable the breakpoint with +.BR bd , +then +.B go +to let any other processors that are waiting on the breakpoint to +clear. +After all processors are clear of the disabled breakpoint then it is +safe to clear it using +.BR bc . +.P +Breakpoints which use the processor breakpoint registers +are only established on the processor which is +currently active. If you wish breakpoints to be universal +use the +.B bpa +or +.B bpha +commands. +.SH EXAMPLES +.TP 8 +bp schedule +Sets an instruction breakpoint at the begining of the +function \fBschedule\fP. + +.TP 8 +bp schedule+0x12e +Sets an instruction breakpoint at the instruction located +at \fBschedule\fP+\fI0x12e\fP. + +.TP 8 +bph ttybuffer+0x24 dataw +Sets a data write breakpoint at the location referenced by +\fBttybuffer\fP+\fI0x24\fP for a length of four bytes. + +.TP 8 +bph 0xc0254010 datar 1 +Establishes a data reference breakpoint at address \fB0xc0254010\fP +for a length of one byte. + +.TP 8 +bp +List current breakpoint table. + +.TP 8 +bd 0 +Disable breakpoint #0. + +.TP 8 +bc * +Clear all breakpoints diff -rNu linux-2.4.7/linux/Documentation/kdb/kdb_bt.man linux-2.4-xfs/linux/Documentation/kdb/kdb_bt.man --- linux-2.4.7/linux/Documentation/kdb/kdb_bt.man Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/kdb/kdb_bt.man Wed Oct 4 06:42:46 2000 @@ -0,0 +1,172 @@ +.TH BT 1 "16 September 2000" +.SH NAME +bt \- Stack Traceback command +.SH SYNOPSIS +bt [ ] +.LP +btp +.LP +bta +.SH DESCRIPTION +.hy 0 +The +.B bt +command is used to print a stack traceback. It uses the +current registers (see \fBrd\fP command) to determine +the starting context and attempts to provide a complete +stack traceback for the active thread. If \fIstack-frame-address\fP +is supplied, it is assumed to point to the start of a valid +stack frame and the stack will be traced back from that +point (e.g. on i386 architecture, \fIstack-frame-address\fP +should be the stack address of a saved \fB%eip\fP value from a \fBcall\fP +instruction). +.P +A kernel configuration option \fBCONFIG_FRAME_POINTER\fP should +be enabled so that the compiler will utilize the frame pointer +register properly to maintain a stack which can be correctly +analyzed. +.P +The \fBbt\fP command will attempt to analyze the stack without +frame pointers if the \fBCONFIG_FRAME_POINTER\fP option is not +enabled, but the analysis is difficult and may not produce +accurate nor complete results. +.P +The \fBbtp\fP command will analyze the stack for the given +process identification (see the \fBps\fP command). +.P +The \fBbta\fP command lists the stack for all processes. +.P +For each function, the stack trace prints at least two lines. +The first line contains four or five fields\ :- +.IP * 3 +The pointer to the previous stack frame, blank if there is no valid +frame pointer. +.PD 0 +.IP * 3 +The current address within this frame. +.IP * 3 +The address converted to a function name (actually the first non-local +label which is <= the address). +.IP * 3 +The offset of the address within the function. +.IP * 3 +Any parameters to the function. +.PD 1 +.PP +On the next line there are five fields which are designed to make it +easier to match the trace against the kernel code\ :- +.IP * 3 +The module name that contains the address, "kernel" if it is in the +base kernel. +.PD 0 +.IP * 3 +The section name that contains the address. +.IP * 3 +The start address of the section. +.IP * 3 +The start address of the function. +.IP * 3 +The end address of the function (the first non-local label which is > +the address). +.PD 1 +.PP +If arguments are being converted to symbols, any argument which +converts to a kernel or module address is printed as\ :- +.IP * 3 +Argument address. +.PD 0 +.IP * 3 +The module name that contains the address, "kernel" if it is in the +base kernel. +.IP * 3 +The symbol name the argument maps to. +.IP * 3 +The offset of the argument from the symbol, suppressed if 0. +.PD 1 +.SH MATCHING TRACE TO KERNEL CODE +The command "objdump\ -S" will disassemble an object and, if the code +was compiled with debugging (gcc flag -g), objdump will interleave the +C source lines with the generated object. +.PP +A complete objdump of the kernel or a module is too big, normally you +only want specific functions. +By default objdump will only print the .text section but Linux uses +other section names for executable code. +When objdump prints relocatable objects (modules) it uses an offset of +0 which is awkward to relate to the stack trace. +The five fields which are printed for each function are designed to +make it easier to match the stack trace against the kernel code using +"objdump\ -S". +.PP +If the function is in the kernel then you need the section name, the +start and end address of the function. The command is +.PP +.nf + objdump -S -j \\ + --start-address= \\ + --stop-address= \\ + /usr/src/linux/vmlinux +.fi +.PP +If the function is in a module then you need the section name, the +start address of the section, the start and end address of the +function, the module name. The command is +.PP +.nf + objdump -S -j \\ + --adjust-vma= \\ + --start-address= \\ + --stop-address= \\ + /path/to/module/.o +.fi +.PP +All addresses to objdump must be preceded by '0x' if they are in hex, +objdump does not assume hex. +The stack trace values are printed with leading '0x' to make it easy to +run objdump. +.SH LIMITATIONS +If the kernel is compiled without frame pointers, stack tracebacks +may be incomplete. The \fBmds %esp\fP command may be useful in +attemping to determine the actual stack traceback manually. +.P +A stack trace can be misleading if any code in a function exit has been +executed, the stack is partially unwound at that stage. +.P +The \fBbt\fP command may print more arguments for a function +than that function accepts; this happens when the C compiler +doesn't immediately pop the arguments off the stack upon return +from a called function. When this is this case, these extra +stack words will be considered additional arguments by the \fBbt\fP +command. +.SH ENVIRONMENT +The \fBBTARGS\fP environment variable governs the maximum number +of arguments that are printed for any single function. +.PP +If the \fBBTSYMARG\fP environment variable is non-zero then any +arguments that fall within the kernel are converted to symbols. +.PP +If the \fBNOSECT\fP environment variable is non-zero then the +section information is suppressed. +.PP +The \fBBTAPROMPT\fP environment variable controls the prompt after each +process is listed by the \fBbta\fP command. If \fBBTAPROMPT\fP is not +set or is non-zero then \fBbta\fP issues a prompt after each process is +listed. If \fBBTAPROMPT\fP is set to zero then no prompt is issued and +all processes are listed without human intervention. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.nf +.na +.ft CW +Entering kdb (0xc3cb4000) due to Breakpoint @ 0xc011725d +Instruction(i) breakpoint #0 at 0xc011725c +qm_modules+0xd1: movl %ebp,%esp +kdb> bt + EBP EIP Function(args) +0xc3cb5f98 0xc011725d qm_modules+0xd1 (0x80721c0, 0x100, 0xbfff5000) + kernel .text 0xc0100000 0xc011718c 0xc0117264 +0xc3cb5fbc 0xc0117875 sys_query_module+0x1b1 (0x0, 0x1, 0x80721c0, 0x100, 0xbfff5000) + kernel .text 0xc0100000 0xc01176c4 0xc01178e8 + 0xc01095f8 system_call+0x34 + kernel .text 0xc0100000 0xc01095c4 0xc01095fc diff -rNu linux-2.4.7/linux/Documentation/kdb/kdb_env.man linux-2.4-xfs/linux/Documentation/kdb/kdb_env.man --- linux-2.4.7/linux/Documentation/kdb/kdb_env.man Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/kdb/kdb_env.man Wed Oct 4 06:42:46 2000 @@ -0,0 +1,46 @@ +.TH ENV 1 "24 September 2000" +.SH NAME +env, set \- Environment manipulation commands +.SH SYNOPSIS +env +.LP +set \fIenvironment-variable\fP=\fIvalue\fP +.SH DESCRIPTION +The kernel debugger contains an environment which contains a series +of name-value pairs. Some environment variables are known to the +various kernel debugger commands and have specific meaning to the +command; such are enumerated on the respective reference material. +.P +Arbitrary environment variables may be created and used with +many commands (those which require an \fIaddress-expression\fP). +.P +The +.B env +command is used to display the current environment. +.P +The +.B set +command is used to alter an existing environment variable or +establish a new environment variable. +.SH LIMITATIONS +There is a compile-time limit of 33 environment variables. +.P +There is a compile-time limit of 512 bytes (\fBKDB_ENVBUFSIZE\fP) +of heap space available for new environment variables and for +environment variables changed from their compile-time values. +.SH ENVIRONMENT +These commands explicitly manipulate the environment. +.SH SMP CONSIDERATIONS +None. +.SH USER SETTINGS +You can include "set" commands in kdb/kdb_cmds (see kdb.mm) to define +your environment variables at kernel startup. +.SH EXAMPLES +.TP 8 +env +Display current environment settings. + +.TP 8 +set IDCOUNT=100 +Set the number of lines to display for the \fBid\fP command +to the value \fI100\fP. diff -rNu linux-2.4.7/linux/Documentation/kdb/kdb_ll.man linux-2.4-xfs/linux/Documentation/kdb/kdb_ll.man --- linux-2.4.7/linux/Documentation/kdb/kdb_ll.man Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/kdb/kdb_ll.man Wed Oct 4 06:42:46 2000 @@ -0,0 +1,134 @@ +.TH LL 1 "19 April 1999" +.SH NAME +ll \- Linked List examination +.SH SYNOPSIS +ll +.SH DESCRIPTION +The +.B ll +command is used to execute a single command repetitively for +each element of a linked list. +.P +The command specified by will be executed with a single +argument, the address of the current element. +.SH LIMITATIONS +Be careful if using this command recursively. +.SH ENVIRONMENT +None. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.nf +.na +.ft CW +# cd modules +# insmod kdbm_vm.o +# Entering kdb on processor 0 due to PAUSE +kdb> ps +Task Addr Pid Parent cpu lcpu Tss Command +0xc03de000 0000000001 0000000000 0000 0000 0xc03de2d4 init +0xc0090000 0000000002 0000000001 0000 0000 0xc00902d4 kflushd +0xc000e000 0000000003 0000000001 0000 0000 0xc000e2d4 kpiod +0xc000c000 0000000004 0000000001 0000 0000 0xc000c2d4 kswapd +0xc7de2000 0000000056 0000000001 0000 0000 0xc7de22d4 kerneld +0xc7d3a000 0000000179 0000000001 0000 0000 0xc7d3a2d4 syslogd +0xc7a7e000 0000000188 0000000001 0000 0000 0xc7a7e2d4 klogd +0xc7a04000 0000000199 0000000001 0000 0000 0xc7a042d4 atd +0xc7b84000 0000000210 0000000001 0000 0000 0xc7b842d4 crond +0xc79d6000 0000000221 0000000001 0000 0000 0xc79d62d4 portmap +0xc798e000 0000000232 0000000001 0000 0000 0xc798e2d4 snmpd +0xc7904000 0000000244 0000000001 0000 0000 0xc79042d4 inetd +0xc78fc000 0000000255 0000000001 0000 0000 0xc78fc2d4 lpd +0xc77ec000 0000000270 0000000001 0000 0000 0xc77ec2d4 sendmail +0xc77b8000 0000000282 0000000001 0000 0000 0xc77b82d4 gpm +0xc7716000 0000000300 0000000001 0000 0000 0xc77162d4 smbd +0xc7ee2000 0000000322 0000000001 0000 0000 0xc7ee22d4 mingetty +0xc7d6e000 0000000323 0000000001 0000 0000 0xc7d6e2d4 login +0xc778c000 0000000324 0000000001 0000 0000 0xc778c2d4 mingetty +0xc78b6000 0000000325 0000000001 0000 0000 0xc78b62d4 mingetty +0xc77e8000 0000000326 0000000001 0000 0000 0xc77e82d4 mingetty +0xc7708000 0000000327 0000000001 0000 0000 0xc77082d4 mingetty +0xc770e000 0000000328 0000000001 0000 0000 0xc770e2d4 mingetty +0xc76b0000 0000000330 0000000001 0000 0000 0xc76b02d4 update +0xc7592000 0000000331 0000000323 0000 0000 0xc75922d4 ksh +0xc7546000 0000000338 0000000331 0000 0000 0xc75462d4 su +0xc74dc000 0000000339 0000000338 0000 0000 0xc74dc2d4 ksh +kdb> md 0xc74dc2d4 +c74dc2d4: 00000000 c74de000 00000018 00000000 .....`MG........ +c74dc2e4: 00000000 00000000 00000000 074de000 .............`M. +c74dc2f4: c01123ff 00000000 00000000 00000000 #.@............ +c74dc304: 00000000 00000000 c74dded0 00000000 ........P^MG.... +[omitted] +c74dc474: 00000000 00000000 00000000 00000000 ................ +c74dc484: 00000000 c7c15d00 c77b0900 c026fbe0 .....]AG..{G`{&@ +c74dc494: 00000000 c76c2000 00000000 00000000 ..... lG........ +c74dc4a4: 00000000 00000000 00000000 c74dc4ac ............,DMG +kdb> md 0xc026fbe0 +c026fbe0: c0262b60 00000000 c7594940 c74de000 @HYG....@IYG.`MG +[omitted] +kdb> md 0xc0262b60 +c0262b60: c0266660 08048000 0804c000 c7bec360 `f&@.....@..`C>G +kdb> ll c0262b60 12 md +c0262b60: c0266660 08048000 0804c000 c7bec360 `f&@.....@..`C>G +c7bec360: c0266660 0804c000 0804d000 c7becb20 `f&@.@...P.. K>G +c7becb20: c0266660 0804d000 08050000 c7bec3a0 `f&@.P...... C>G +c7bec3a0: c0266660 40000000 40009000 c7bec420 `f&@...@...@ D>G +c7bec420: c0266660 40009000 4000b000 c7bec4a0 `f&@...@.0.@ D>G +c7bec4a0: c0266660 4000b000 40010000 c7bec8e0 `f&@.0.@...@`H>G +c7bec8e0: c0266660 40010000 400a1000 c7becbe0 `f&@...@...@`K>G +c7becbe0: c0266660 400a1000 400a8000 c7becc60 `f&@...@...@`L>G +c7becc60: c0266660 400a8000 400b4000 c7952300 `f&@...@.@.@.#.G +c7952300: c0266660 400b5000 400bc000 c79521c0 `f&@.P.@.@.@@!.G +c79521c0: c0266660 400bc000 400bd000 c7bec6e0 `f&@.@.@.P.@`F>G +c7bec6e0: c0266660 bffff000 c0000000 00000000 `f&@.p?...@.... +kdb> +kdb> ll c0262b60 12 vm +struct vm_area_struct at 0xc0262b60 for 56 bytes +vm_start = 0x8048000 vm_end = 0x804c000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +struct vm_area_struct at 0xc7bec360 for 56 bytes +vm_start = 0x804c000 vm_end = 0x804d000 +page_prot = 0x25 avl_height = -31808 vm_offset = 0x3000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE EXECUTABLE +struct vm_area_struct at 0xc7becb20 for 56 bytes +vm_start = 0x804d000 vm_end = 0x8050000 +page_prot = 0x25 avl_height = -28664 vm_offset = 0x0 +flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7bec3a0 for 56 bytes +vm_start = 0x40000000 vm_end = 0x40009000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC DENYWRITE +struct vm_area_struct at 0xc7bec420 for 56 bytes +vm_start = 0x40009000 vm_end = 0x4000b000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x8000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC DENYWRITE +struct vm_area_struct at 0xc7bec4a0 for 56 bytes +vm_start = 0x4000b000 vm_end = 0x40010000 +page_prot = 0x25 avl_height = 26853 vm_offset = 0x0 +flags: READ MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7bec8e0 for 56 bytes +vm_start = 0x40010000 vm_end = 0x400a1000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7becbe0 for 56 bytes +vm_start = 0x400a1000 vm_end = 0x400a8000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x90000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7becc60 for 56 bytes +vm_start = 0x400a8000 vm_end = 0x400b4000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7952300 for 56 bytes +vm_start = 0x400b5000 vm_end = 0x400bc000 +page_prot = 0x25 avl_height = 30126 vm_offset = 0x0 +flags: READ EXEC MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc79521c0 for 56 bytes +vm_start = 0x400bc000 vm_end = 0x400bd000 +page_prot = 0x25 avl_height = -16344 vm_offset = 0x6000 +flags: READ WRITE MAYREAD MAYWRITE MAYEXEC +struct vm_area_struct at 0xc7bec6e0 for 56 bytes +vm_start = 0xbffff000 vm_end = 0xc0000000 +page_prot = 0x25 avl_height = 2244 vm_offset = 0x0 +flags: READ WRITE EXEC MAYREAD MAYWRITE MAYEXEC GROWSDOWN +kdb> diff -rNu linux-2.4.7/linux/Documentation/kdb/kdb_md.man linux-2.4-xfs/linux/Documentation/kdb/kdb_md.man --- linux-2.4.7/linux/Documentation/kdb/kdb_md.man Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/kdb/kdb_md.man Wed Oct 4 06:42:46 2000 @@ -0,0 +1,103 @@ +.TH MD 1 "09 March 1999" +.SH NAME +md, mdr, mds, mm\- Memory manipulation commands +.SH SYNOPSIS +md [ \fIaddress-expression\fP [ \fIline-count\fP [\fIoutput-radix\fP ] ] ] +.LP +mdr \fIaddress-expression\fP,\fIbytes\fP +.LP +mds [ \fIaddress-expression\fP [ \fIline-count\fP [\fIoutput-radix\fP ] ] ] +.LP +mm \fIaddress-expression\fP \fInew-contents\fP +.SH DESCRIPTION +The +.B md +command is used to display the contents of memory. +The \fIaddress-expression\fP may be a numeric value (decimal or +hexidecimal), a symbol name, a register name preceeded by one or more +percent symbols '%', an environment variable name preceeded by +a currency symbol '$', or a simple expression consisting of a +symbol name, an addition or subtraction character and a numeric +value (decimal or hexidecimal). +.P +If the \fIline-count\fP or \fIradix\fP arguments are omitted, +they default to the values of the \fBMDCOUNT\fP and \fBRADIX\fP +environment variables respectively. If the \fBMDCOUNT\fP or +\fBRADIX\fP environment variables are unset, the appropriate +defaults will be used [see \fBENVIRONMENT\fP below]. +.P +The +.B mdr +command displays the raw contents of memory, starting at the specified +address for the specified number of bytes. +The data is printed in one line without a leading address and no +trailing character conversion. +.B mdr +is intended for interfacing with external debuggers, it is of little +use to humans. +.P +The +.B mds +command displays the contents of memory one word per line and +attempts to correlate the contents of each word with a symbol +in the symbol table. If no symbol is found, the ascii representation +of the word is printed, otherwise the symbol name and offset from +symbol value are printed. +By default the section data is printed for kernel symbols. +.P +The +.B mm +command allows modification of memory. The word at the address +represented by \fIaddress-expression\fP is changed to +\fInew-contents\fP. \fInew-contents\fP is allowed to be an +\fIaddress-expression\fP. +.SH LIMITATIONS +None. +.SH ENVIRONMENT +.TP 8 +MDCOUNT +This environment variable (default=8) defines the number of lines +that will be displayed by each invocation of the \fBmd\fP command. + +.TP 8 +RADIX +This environment variable (default=16) defines the radix used to +print the memory contents. + +.TP 8 +BYTESPERWORD +This environment variable (default=4) selects the width of output +data when printing memory contents. Select the value two to get +16-bit word output, select the value one to get byte output. + +.TP 8 +LINES +This environment variable governs the number of lines of output +that will be presented before the kernel debugger built-in pager +pauses the output. This variable only affects the functioning +of the \fBmd\fP and \fBmds\fP if the \fBMDCOUNT\fP variable +is set to a value greater than the \fBLINES\fP variable. + +.TP 8 +If the \fBNOSECT\fP environment variable is non-zero then the +section information is suppressed. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.TP 8 +md %edx +Display memory starting at the address contained in register \fB%edx\fP. + +.TP 8 +mds %esp +Display stack contents symbolically. This command is quite useful +in manual stack traceback. + +.TP 8 +mm 0xc0252110 0x25 +Change the memory location at 0xc0252110 to the value 0x25. + +.TP 8 +md chrdev_table 15 +Display 15 lines (at 16 bytes per line) starting at address +represented by the symbol \fIchrdev_table\fP. diff -rNu linux-2.4.7/linux/Documentation/kdb/kdb_rd.man linux-2.4-xfs/linux/Documentation/kdb/kdb_rd.man --- linux-2.4.7/linux/Documentation/kdb/kdb_rd.man Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/kdb/kdb_rd.man Wed Oct 4 06:42:46 2000 @@ -0,0 +1,68 @@ +.TH RD 1 "09 March 1999" +.SH NAME +rd, rm\- Register manipulation commands +.SH SYNOPSIS +rd [c|d|u] +.LP +rm \fIregister-name\fP \fInew-contents\fP +.LP +ef
+.SH DESCRIPTION +The +.B rd +command is used to display the contents of processor registers. +Without any arguments, the rd command displays the contents of +the general register set at the point at which the kernel debugger +was entered. With the 'c' argument, the processor control registers +%cr0, %cr1, %cr2 and %cr4 are displayed, while with the 'd' argument +the processor debug registers are displayed. If the 'u' argument +is supplied, the registers for the current task as of the last +time the current task entered the kernel are displayed. +.P +The +.B rm +command allows modification of a register. The following +register names are valid: \fB%eax\fP, \fB%ebx\fP, \fB%ecx\fP, +\fB%edx\fP, \fB%esi\fP, \fB%edi\fP, \fB%esp\fP, \fB%eip\fP, +and \fB%ebp\fP. Note that if two '%' symbols are used +consecutively, the register set displayed by the 'u' argument +to the \fBrd\fP command is modified. +.P +The debug registers, \fBdr0\fP through \fBdr3\fP and both +\fBdr6\fP and \fBdr7\fP can also be modified with the \fBrm\fP +command. +.P +The +.B ef +command displays an exception frame at the specified address. +.SH LIMITATIONS +Currently the \fBrm\fP command will not allow modification of the +control registers. +.P +Currently neither the \fBrd\fP command nor the \fBrm\fP command will +display or modify the model specific registers on the Pentium +and Pentium Pro families. +.SH ENVIRONMENT +None. +.SH SMP CONSIDERATIONS +None. +.SH EXAMPLES +.TP 8 +rd +Display general register set. + +.TP 8 +rm %eax 0 +Set the contents of \fB%eax\fP to zero. This will be the +value of %eax when kdb returns from the condition which +invoked it. + +.TP 8 +rm %%eax 0 +Set the value of the \fB%eax\fP register to zero. This will +be the value the user-mode application will see upon returning +from the kernel. + +.TP 8 +rm dr0 0xc1287220 +Set the value of the \fBdr0\fB register to \f(CW0xc1287220\fP. diff -rNu linux-2.4.7/linux/Documentation/kdb/kdb_ss.man linux-2.4-xfs/linux/Documentation/kdb/kdb_ss.man --- linux-2.4.7/linux/Documentation/kdb/kdb_ss.man Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/kdb/kdb_ss.man Wed Oct 4 06:42:46 2000 @@ -0,0 +1,101 @@ +.TH SS 1 "24 September 2000" +.SH NAME +ss, ssb \- Single Step +.SH SYNOPSIS +ss [] +.LP +ssb +.SH DESCRIPTION +The +.B ss +command is used to execute a single instruction and return +to the kernel debugger. +.P +Both the instruction that was single-stepped and the next +instruction to execute are printed. +.P +The \fBssb\fP command will execute instructions from the +current value of the instruction pointer. Each instruction +will be printed as it is executed; execution will stop at +any instruction which would cause the flow of control to +change (e.g. branch, call, interrupt instruction, return, etc.) +.SH LIMITATIONS +None. +.SH ENVIRONMENT +None. +.SH SMP CONSIDERATIONS +Other processors are held in the kernel debugger when the instruction +is traced. Single stepping though code that requires a lock which is +in use by another processor is an exercise in futility, it will never +succeed. +.SH INTERRUPT CONSIDERATIONS +When a kdb event occurs, one cpu (the initial cpu) enters kdb state. +It uses a cross system non maskable interrupt (NMI) to interrupt the +other cpus and bring them all into kdb state. All cpus run with +interrupts disabled while they are inside kdb, this prevents most +external events from disturbing the kernel while kdb is running. +.B Note: +Disabled interrupts means that any I/O that relies on interrupts cannot +proceed while kdb is in control, devices can time out. The clock tick +is also disabled, machines will lose track of time while they are +inside kdb. +.P +Even with interrupts disabled, some NMI events will still occur, these +can disturb the kernel while you are debugging it. The initial cpu +will still accept NMI events, assuming that kdb was not entered for an +NMI event. Any cpu where you use the SS or SSB commands will accept +NMI events, even after the instruction has finished and the cpu is back +in kdb. This is an unavoidable side effect of the fact that doing +SS[B] requires the cpu to drop all the way out of kdb, including +exiting from the NMI event that brought the cpu into kdb. Under normal +circumstances the only NMI event is for the NMI oopser and that is kdb +aware so it does not disturb the kernel while kdb is running. +.P +Sometimes doing SS or SSB on ix86 will allow one interrupt to proceed, +even though the cpu is disabled for interrupts. I have not been able +to track this one down but I suspect that the interrupt was pending +when kdb was entered and it runs when kdb exits through IRET even +though the popped flags are marked as cli(). If any ix86 hardware +expert can shed some light on this problem, please notify the kdb +maintainer. +.SH EXAMPLES +.nf +.na +.ft CW +kdb> bp gendisk_head datar 4 +Data Access Breakpoint #0 at 0xc024ddf4 (gendisk_head) in dr0 is enabled on cpu 0 +for 4 bytes +kdb> go +... +[root@host /root]# cat /proc/partitions +Entering kdb on processor 0 due to Debug Exception @ 0xc01845e3 +Read/Write breakpoint #0 at 0xc024ddf4 +[0]kdb> ssb +sd_finish+0x7b: movzbl 0xc02565d4,%edx +sd_finish+0x82: leal 0xf(%edx),%eax +sd_finish+0x85: sarl $0x4,%eax +sd_finish+0x88: movl 0xc0256654,%ecx +sd_finish+0x8e: leal (%eax,%eax,4),%edx +sd_finish+0x91: leal (%eax,%edx,2),%edx +sd_finish+0x94: movl 0xc0251108,%eax +sd_finish+0x99: movl %eax,0xffffffc(%ecx,%edx,4) +sd_finish+0x9d: movl %ecx,0xc0251108 +sd_finish+0xa3: xorl %ebx,%ebx +sd_finish+0xa5: cmpb $0x0,0xc02565d4 +[0]kdb> go +[root@host /root]# + +[0]kdb> ss +sys_read: pushl %ebp +SS trap at 0xc01274c1 +sys_read+0x1: movl %esp,%ebp +[0]kdb> ss +sys_read+0x1: movl %esp,%ebp +SS trap at 0xc01274c3 +sys_read+0x3: subl $0xc,%esp +[0]kdb> ss +sys_read+0x3: subl $0xc,%esp +SS trap at 0xc01274c6 +sys_read+0x6: pushl %edi +[0]kdb> + diff -rNu linux-2.4.7/linux/Documentation/m68k/CVS/Entries linux-2.4-xfs/linux/Documentation/m68k/CVS/Entries --- linux-2.4.7/linux/Documentation/m68k/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/m68k/CVS/Entries Thu Jul 5 11:46:45 2001 @@ -0,0 +1,4 @@ +/00-INDEX/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README.buddha/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/kernel-options.txt/1.3/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/m68k/CVS/Repository linux-2.4-xfs/linux/Documentation/m68k/CVS/Repository --- linux-2.4.7/linux/Documentation/m68k/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/m68k/CVS/Repository Thu Jul 5 11:46:44 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/m68k diff -rNu linux-2.4.7/linux/Documentation/m68k/CVS/Root linux-2.4-xfs/linux/Documentation/m68k/CVS/Root --- linux-2.4.7/linux/Documentation/m68k/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/m68k/CVS/Root Thu Jul 5 11:46:44 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/mips/CVS/Entries linux-2.4-xfs/linux/Documentation/mips/CVS/Entries --- linux-2.4.7/linux/Documentation/mips/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/mips/CVS/Entries Thu Jul 5 11:46:46 2001 @@ -0,0 +1,3 @@ +/GT64120.README/1.1/Wed May 2 06:22:13 2001/-ko/ +/time.README/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/mips/CVS/Repository linux-2.4-xfs/linux/Documentation/mips/CVS/Repository --- linux-2.4.7/linux/Documentation/mips/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/mips/CVS/Repository Thu Jul 5 11:46:45 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/mips diff -rNu linux-2.4.7/linux/Documentation/mips/CVS/Root linux-2.4-xfs/linux/Documentation/mips/CVS/Root --- linux-2.4.7/linux/Documentation/mips/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/mips/CVS/Root Thu Jul 5 11:46:45 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/networking/CVS/Entries linux-2.4-xfs/linux/Documentation/networking/CVS/Entries --- linux-2.4.7/linux/Documentation/networking/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/networking/CVS/Entries Thu Jul 5 11:46:52 2001 @@ -0,0 +1,66 @@ +/00-INDEX/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/3c505.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/6pack.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/8139too.txt/1.10/Tue May 29 19:53:13 2001/-ko/ +/Configurable/1.3/Sun Aug 29 02:07:15 1999/-ko/ +/DLINK.txt/1.3/Sun Aug 29 02:07:15 1999/-ko/ +/PLIP.txt/1.3/Wed Sep 15 20:42:56 1999/-ko/ +/README.sb1000/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/TODO/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/alias.txt/1.3/Mon Jul 2 15:59:04 2001/-ko/ +/arcnet-hardware.txt/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/arcnet.txt/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/atm.txt/1.1/Fri Feb 11 00:16:16 2000/-ko/ +/ax25.txt/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/baycom.txt/1.4/Mon Nov 8 22:55:41 1999/-ko/ +/bridge.txt/1.2/Sat Nov 25 08:05:45 2000/-ko/ +/comx.txt/1.3/Wed May 2 06:22:13 2001/-ko/ +/cops.txt/1.4/Tue May 29 19:53:13 2001/-ko/ +/cs89x0.txt/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/de4x5.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/decnet.txt/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/depca.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dgrs.txt/1.3/Sun Aug 29 02:07:15 1999/-ko/ +/dmfe.txt/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/eql.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ethertap.txt/1.5/Tue May 29 19:53:13 2001/-ko/ +/ewrk3.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/filter.txt/1.4/Tue May 29 19:53:13 2001/-ko/ +/fore200e.txt/1.2/Tue May 2 21:09:12 2000/-ko/ +/framerelay.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ip-sysctl.txt/1.9/Tue May 29 19:53:13 2001/-ko/ +/ip_dynaddr.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ipddp.txt/1.5/Tue May 29 19:53:13 2001/-ko/ +/iphase.txt/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/irda.txt/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/lapb-module.txt/1.3/Sat Nov 25 08:05:45 2000/-ko/ +/ltpc.txt/1.3/Mon Nov 8 22:55:41 1999/-ko/ +/multicast.txt/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/ncsa-telnet/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/net-modules.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/netdevices.txt/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/olympic.txt/1.3/Wed May 2 06:22:13 2001/-ko/ +/policy-routing.txt/1.3/Fri Jul 9 06:35:44 1999/-ko/ +/pt.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ray_cs.txt/1.1/Tue Oct 12 18:49:29 1999/-ko/ +/routing.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/shaper.txt/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/sis900.txt/1.5/Wed Jan 3 01:43:05 2001/-ko/ +/sk98lin.txt/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/skfp.txt/1.2/Fri May 26 01:26:22 2000/-ko/ +/smc9.txt/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/smctr.txt/1.4/Tue May 29 19:53:13 2001/-ko/ +/soundmodem.txt/1.4/Mon Nov 8 22:55:41 1999/-ko/ +/tcp.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/tlan.txt/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/tms380tr.txt/1.3/Tue May 29 19:53:13 2001/-ko/ +/tulip.txt/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/tuntap.txt/1.3/Wed May 2 06:22:13 2001/-ko/ +/vortex.txt/1.9/Thu Jun 21 15:45:04 2001/-ko/ +/wan-router.txt/1.5/Wed May 2 06:22:13 2001/-ko/ +/wanpipe.txt/1.5/Wed May 2 06:22:13 2001/-ko/ +/wavelan.txt/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/x25-iface.txt/1.3/Sat Nov 25 08:05:45 2000/-ko/ +/x25.txt/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/z8530drv.txt/1.4/Wed Nov 1 21:35:42 2000/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/networking/CVS/Repository linux-2.4-xfs/linux/Documentation/networking/CVS/Repository --- linux-2.4.7/linux/Documentation/networking/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/networking/CVS/Repository Thu Jul 5 11:46:46 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/networking diff -rNu linux-2.4.7/linux/Documentation/networking/CVS/Root linux-2.4-xfs/linux/Documentation/networking/CVS/Root --- linux-2.4.7/linux/Documentation/networking/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/networking/CVS/Root Thu Jul 5 11:46:46 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/nmi_watchdog.txt linux-2.4-xfs/linux/Documentation/nmi_watchdog.txt --- linux-2.4.7/linux/Documentation/nmi_watchdog.txt Mon Aug 21 10:57:35 2000 +++ linux-2.4-xfs/linux/Documentation/nmi_watchdog.txt Wed Oct 4 06:42:46 2000 @@ -1,19 +1,30 @@ -Is your SMP system locking up unpredictably? No keyboard activity, just -a frustrating complete hard lockup? Do you want to help us debugging -such lockups? If all yes then this document is definitely for you. - -on Intel SMP hardware there is a feature that enables us to generate -'watchdog NMI interrupts'. (NMI: Non Maskable Interrupt - these get -executed even if the system is otherwise locked up hard) This can be -used to debug hard kernel lockups. By executing periodic NMI interrupts, -the kernel can monitor whether any CPU has locked up, and print out -debugging messages if so. You can enable/disable the NMI watchdog at boot -time with the 'nmi_watchdog=1' boot parameter. Eg. the relevant -lilo.conf entry: +Is your system locking up unpredictably? No keyboard activity, just a +frustrating complete hard lockup? Do you want to help us debugging +such lockups? If all yes then this document is definitely for you. + +On Intel SMP hardware there is a feature that enables us to generate +'watchdog NMI interrupts' (NMI: Non Maskable Interrupt - these get +executed even if the system is otherwise locked up hard). + +On Intel UP hardware which has a local APIC (Advanced Programmable +Interrupt Controller) with the ability to interrupt on performance +counter overflow (typically any P6 and above) can also generate +watchdog NMI events. + +This can be used to debug hard kernel lockups. By executing periodic +NMI interrupts, the kernel can monitor whether any CPU has locked up, +and print out debugging messages if so. You can enable/disable the NMI +watchdog at boot time with the 'nmi_watchdog=1' boot parameter. Eg. +the relevant lilo.conf entry: append="nmi_watchdog=1" +You can also activate or deactivate the NMI watchdog on the fly + + echo "0" > /proc/sys/kernel/nmi_watchdog - deactivate + echo "1" > /proc/sys/kernel/nmi_watchdog - activate + A 'lockup' is the following scenario: if any CPU in the system does not execute the period local timer interrupt for more than 5 seconds, then the NMI handler generates an oops and kills the process. This @@ -27,7 +38,36 @@ NOTE: currently the NMI-oopser is enabled unconditionally on x86 SMP boxes. +On uniprocessors, the NMI watchdog requires the dedicated use of MSR +performance counter 1 (PerfCtr1). If you are using PerfCtr1 for tuning +work, the UP NMI watchdog will conflict with your tuning. Therefore on +UP the watchdog is conditionally activated via CONFIG_UP_NMI_WATCHDOG. +Note that CONFIG_UP_NMI_WATCHDOG only controls the default setting for +UP, you can always override that setting by booting with +nmi_watchdog=0/1 or by + + echo "0/1" > /proc/sys/kernel/nmi_watchdog + +Activating or deactivating the NMI watchdog on UP will reset both +performance counters. PerfCtr0 will be turned off, PerfCtr1 will be +used to generate NMI events or will be turned off. After activating +the UP NMI watchdog, you can use PerfCtr0 but not PerfCtr1. After +deactivating, you can use both performance counters. Activating or +deactivating the NMI watchdog on SMP does not affect the performance +counters. + +The SMP and UP watchdogs run at different rates. On SMP each cpu gets +one NMI every timer tick. On UP, when the cpu gets an NMI depends on +how busy the cpu is. If the cpu is running at 100% busy then it gets +an NMI every timer tick, if it is running at 1% busy it gets NMI every +100 timer ticks, approximately. A hung machine is almost always in a +tight loop so the UP NMI watchdog will trigger after a short period. + +Changes for UP NMI watchdog and /proc/sys/kernel/nmi_watchdog by +Keith Owens September 26, 2000. Complain to + first for any problems. + +Original author: [ feel free to send bug reports, suggestions and patches to Ingo Molnar or the Linux SMP mailing list at ] - diff -rNu linux-2.4.7/linux/Documentation/parisc/CVS/Entries linux-2.4-xfs/linux/Documentation/parisc/CVS/Entries --- linux-2.4.7/linux/Documentation/parisc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/parisc/CVS/Entries Thu Jul 5 11:46:52 2001 @@ -0,0 +1,6 @@ +/00-INDEX/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/IODC.txt/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/debugging/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/mm/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/registers/1.1/Sun Dec 17 19:15:00 2000/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/parisc/CVS/Repository linux-2.4-xfs/linux/Documentation/parisc/CVS/Repository --- linux-2.4.7/linux/Documentation/parisc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/parisc/CVS/Repository Thu Jul 5 11:46:52 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/parisc diff -rNu linux-2.4.7/linux/Documentation/parisc/CVS/Root linux-2.4-xfs/linux/Documentation/parisc/CVS/Root --- linux-2.4.7/linux/Documentation/parisc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/parisc/CVS/Root Thu Jul 5 11:46:52 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/power/CVS/Entries linux-2.4-xfs/linux/Documentation/power/CVS/Entries --- linux-2.4.7/linux/Documentation/power/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/power/CVS/Entries Thu Jul 5 11:46:52 2001 @@ -0,0 +1,2 @@ +/pci.txt/1.1/Fri Jun 29 22:21:45 2001/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/power/CVS/Repository linux-2.4-xfs/linux/Documentation/power/CVS/Repository --- linux-2.4.7/linux/Documentation/power/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/power/CVS/Repository Thu Jul 5 11:46:52 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/power diff -rNu linux-2.4.7/linux/Documentation/power/CVS/Root linux-2.4-xfs/linux/Documentation/power/CVS/Root --- linux-2.4.7/linux/Documentation/power/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/power/CVS/Root Thu Jul 5 11:46:52 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/powerpc/CVS/Entries linux-2.4-xfs/linux/Documentation/powerpc/CVS/Entries --- linux-2.4.7/linux/Documentation/powerpc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/powerpc/CVS/Entries Thu Jul 5 11:46:53 2001 @@ -0,0 +1,7 @@ +/00-INDEX/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/SBC8260_memory_mapping.txt/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/ppc_htab.txt/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/smp.txt/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/sound.txt/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/zImage_layout.txt/1.3/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/powerpc/CVS/Repository linux-2.4-xfs/linux/Documentation/powerpc/CVS/Repository --- linux-2.4.7/linux/Documentation/powerpc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/powerpc/CVS/Repository Thu Jul 5 11:46:52 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/powerpc diff -rNu linux-2.4.7/linux/Documentation/powerpc/CVS/Root linux-2.4-xfs/linux/Documentation/powerpc/CVS/Root --- linux-2.4.7/linux/Documentation/powerpc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/powerpc/CVS/Root Thu Jul 5 11:46:52 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/s390/CVS/Entries linux-2.4-xfs/linux/Documentation/s390/CVS/Entries --- linux-2.4.7/linux/Documentation/s390/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/s390/CVS/Entries Thu Jul 5 11:46:55 2001 @@ -0,0 +1,10 @@ +/3270.ChangeLog/1.1/Wed May 2 06:22:13 2001/-ko/ +/3270.txt/1.2/Tue May 29 19:53:13 2001/-ko/ +/DASD/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/Debugging390.txt/1.1/Wed May 2 06:22:13 2001/-ko/ +/TAPE/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/cds.txt/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/chandev.8/1.2/Wed May 2 06:22:13 2001/-ko/ +/config3270.sh/1.1/Wed May 2 06:22:13 2001/-ko/ +/s390dbf.txt/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/s390/CVS/Repository linux-2.4-xfs/linux/Documentation/s390/CVS/Repository --- linux-2.4.7/linux/Documentation/s390/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/s390/CVS/Repository Thu Jul 5 11:46:53 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/s390 diff -rNu linux-2.4.7/linux/Documentation/s390/CVS/Root linux-2.4-xfs/linux/Documentation/s390/CVS/Root --- linux-2.4.7/linux/Documentation/s390/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/s390/CVS/Root Thu Jul 5 11:46:53 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/sound/CVS/Entries linux-2.4-xfs/linux/Documentation/sound/CVS/Entries --- linux-2.4.7/linux/Documentation/sound/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/sound/CVS/Entries Thu Jul 5 11:46:57 2001 @@ -0,0 +1,45 @@ +/AD1816/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/ALS/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/AWE32/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/AudioExcelDSP16/1.3/Mon Nov 8 22:55:41 1999/-ko/ +/CMI8330/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/CMI8338/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/CS4232/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ChangeLog.awe/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ChangeLog.multisound/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ESS/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/ESS1868/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/INSTALL.awe/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/Introduction/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/MAD16/1.4/Tue May 29 19:53:13 2001/-ko/ +/Maestro/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/Maestro3/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/MultiSound/1.3/Fri Jan 21 19:18:03 2000/-ko/ +/NEWS/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/NM256/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/OPL3/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/OPL3-SA/1.3/Sat Mar 11 02:39:30 2000/-ko/ +/OPL3-SA2/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/Opti/1.5/Tue May 29 19:53:13 2001/-ko/ +/PAS16/1.2/Wed May 2 06:22:13 2001/-ko/ +/PSS/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/PSS-updates/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/README.OSS/1.6/Wed Jun 13 03:24:09 2001/-ko/ +/README.awe/1.3/Tue May 2 21:09:12 2000/-ko/ +/README.modules/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/README.ymfsb/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/SoundPro/1.2/Fri Apr 21 16:00:46 2000/-ko/ +/Soundblaster/1.5/Wed Jan 3 01:43:05 2001/-ko/ +/Tropez+/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/VIA-chipset/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/VIBRA16/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Wavefront/1.4/Sat Mar 11 02:39:30 2000/-ko/ +/cs46xx/1.1/Tue May 29 19:53:13 2001/-ko/ +/es1370/1.3/Wed May 2 06:22:13 2001/-ko/ +/es1371/1.3/Wed May 2 06:22:13 2001/-ko/ +/mwave/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/solo1/1.2/Wed May 2 06:22:13 2001/-ko/ +/sonicvibes/1.3/Wed May 2 06:22:13 2001/-ko/ +/ultrasound/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/vwsnd/1.1/Mon Aug 30 00:17:07 1999/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/sound/CVS/Repository linux-2.4-xfs/linux/Documentation/sound/CVS/Repository --- linux-2.4.7/linux/Documentation/sound/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/sound/CVS/Repository Thu Jul 5 11:46:55 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/sound diff -rNu linux-2.4.7/linux/Documentation/sound/CVS/Root linux-2.4-xfs/linux/Documentation/sound/CVS/Root --- linux-2.4.7/linux/Documentation/sound/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/sound/CVS/Root Thu Jul 5 11:46:55 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/sparc/CVS/Entries linux-2.4-xfs/linux/Documentation/sparc/CVS/Entries --- linux-2.4.7/linux/Documentation/sparc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/sparc/CVS/Entries Thu Jul 5 11:46:57 2001 @@ -0,0 +1,2 @@ +/sbus_drivers.txt/1.1/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/sparc/CVS/Repository linux-2.4-xfs/linux/Documentation/sparc/CVS/Repository --- linux-2.4.7/linux/Documentation/sparc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/sparc/CVS/Repository Thu Jul 5 11:46:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/sparc diff -rNu linux-2.4.7/linux/Documentation/sparc/CVS/Root linux-2.4-xfs/linux/Documentation/sparc/CVS/Root --- linux-2.4.7/linux/Documentation/sparc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/sparc/CVS/Root Thu Jul 5 11:46:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/sysctl/CVS/Entries linux-2.4-xfs/linux/Documentation/sysctl/CVS/Entries --- linux-2.4.7/linux/Documentation/sysctl/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/sysctl/CVS/Entries Thu Jul 5 11:46:58 2001 @@ -0,0 +1,6 @@ +/README/1.3/Fri Jul 9 06:35:44 1999/-ko/ +/fs.txt/1.4/Tue Jan 11 18:48:48 2000/-ko/ +/kernel.txt/1.4/Tue Jan 11 18:48:48 2000/-ko/ +/sunrpc.txt/1.3/Fri Jul 9 06:35:44 1999/-ko/ +/vm.txt/1.5/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/sysctl/CVS/Repository linux-2.4-xfs/linux/Documentation/sysctl/CVS/Repository --- linux-2.4.7/linux/Documentation/sysctl/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/sysctl/CVS/Repository Thu Jul 5 11:46:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/sysctl diff -rNu linux-2.4.7/linux/Documentation/sysctl/CVS/Root linux-2.4-xfs/linux/Documentation/sysctl/CVS/Root --- linux-2.4.7/linux/Documentation/sysctl/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/sysctl/CVS/Root Thu Jul 5 11:46:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/telephony/CVS/Entries linux-2.4-xfs/linux/Documentation/telephony/CVS/Entries --- linux-2.4.7/linux/Documentation/telephony/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/telephony/CVS/Entries Thu Jul 5 11:46:58 2001 @@ -0,0 +1,2 @@ +/ixj.txt/1.1/Thu Jan 6 19:50:16 2000/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/telephony/CVS/Repository linux-2.4-xfs/linux/Documentation/telephony/CVS/Repository --- linux-2.4.7/linux/Documentation/telephony/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/telephony/CVS/Repository Thu Jul 5 11:46:58 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/telephony diff -rNu linux-2.4.7/linux/Documentation/telephony/CVS/Root linux-2.4-xfs/linux/Documentation/telephony/CVS/Root --- linux-2.4.7/linux/Documentation/telephony/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/telephony/CVS/Root Thu Jul 5 11:46:58 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/usb/CVS/Entries linux-2.4-xfs/linux/Documentation/usb/CVS/Entries --- linux-2.4.7/linux/Documentation/usb/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/usb/CVS/Entries Thu Jul 5 11:46:59 2001 @@ -0,0 +1,21 @@ +/CREDITS/1.7/Mon Oct 23 18:56:35 2000/-ko/ +/URB.txt/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/acm.txt/1.2/Fri Apr 21 16:00:46 2000/-ko/ +/bluetooth.txt/1.1/Wed Nov 1 21:35:42 2000/-ko/ +/dc2xx.txt/1.3/Tue May 2 21:09:12 2000/-ko/ +/error-codes.txt/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/hotplug.txt/1.3/Tue May 29 19:53:13 2001/-ko/ +/ibmcam.txt/1.4/Fri Apr 21 16:00:46 2000/-ko/ +/input.txt/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/ohci.txt/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/ov511.txt/1.14/Sat Nov 25 08:05:45 2000/-ko/ +/philips.txt/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/proc_usb_info.txt/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/rio.txt/1.1/Fri Mar 3 01:30:48 2000/-ko/ +/scanner-hp-sane.txt/1.4/Fri May 26 01:14:50 2000/-ko/ +/scanner.txt/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/se401.txt/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/uhci.txt/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/usb-help.txt/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/usb-serial.txt/1.16/Thu Jun 28 05:21:16 2001/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/usb/CVS/Repository linux-2.4-xfs/linux/Documentation/usb/CVS/Repository --- linux-2.4.7/linux/Documentation/usb/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/usb/CVS/Repository Thu Jul 5 11:46:58 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/usb diff -rNu linux-2.4.7/linux/Documentation/usb/CVS/Root linux-2.4-xfs/linux/Documentation/usb/CVS/Root --- linux-2.4.7/linux/Documentation/usb/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/usb/CVS/Root Thu Jul 5 11:46:58 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/video4linux/CVS/Entries linux-2.4-xfs/linux/Documentation/video4linux/CVS/Entries --- linux-2.4.7/linux/Documentation/video4linux/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/video4linux/CVS/Entries Thu Jul 5 11:46:59 2001 @@ -0,0 +1,10 @@ +/API.html/1.4/Sun Jan 9 23:56:19 2000/-ko/ +/CQcam.txt/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/README.buz/1.2/Sun Jan 9 23:56:19 2000/-ko/ +/README.cpia/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/Zoran/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/meye.txt/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/radiotrack.txt/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/w9966.txt/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/zr36120.txt/1.3/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/video4linux/CVS/Entries.Log linux-2.4-xfs/linux/Documentation/video4linux/CVS/Entries.Log --- linux-2.4.7/linux/Documentation/video4linux/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/video4linux/CVS/Entries.Log Thu Jul 5 11:46:59 2001 @@ -0,0 +1 @@ +A D/bttv//// diff -rNu linux-2.4.7/linux/Documentation/video4linux/CVS/Repository linux-2.4-xfs/linux/Documentation/video4linux/CVS/Repository --- linux-2.4.7/linux/Documentation/video4linux/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/video4linux/CVS/Repository Thu Jul 5 11:46:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/video4linux diff -rNu linux-2.4.7/linux/Documentation/video4linux/CVS/Root linux-2.4-xfs/linux/Documentation/video4linux/CVS/Root --- linux-2.4.7/linux/Documentation/video4linux/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/video4linux/CVS/Root Thu Jul 5 11:46:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/video4linux/bttv/CVS/Entries linux-2.4-xfs/linux/Documentation/video4linux/bttv/CVS/Entries --- linux-2.4.7/linux/Documentation/video4linux/bttv/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/video4linux/bttv/CVS/Entries Thu Jul 5 11:46:59 2001 @@ -0,0 +1,13 @@ +/CARDLIST/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/CONTRIBUTORS/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/ICs/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Insmod-options/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/MAKEDEV/1.1/Tue Dec 21 19:02:48 1999/-ko/ +/Modules.conf/1.2/Wed Jan 3 01:43:05 2001/-ko/ +/PROBLEMS/1.4/Sun Jan 9 23:56:19 2000/-ko/ +/README/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/README.WINVIEW/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/Sound-FAQ/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/Specs/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/THANKS/1.3/Fri Jul 9 06:35:44 1999/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/video4linux/bttv/CVS/Repository linux-2.4-xfs/linux/Documentation/video4linux/bttv/CVS/Repository --- linux-2.4.7/linux/Documentation/video4linux/bttv/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/video4linux/bttv/CVS/Repository Thu Jul 5 11:46:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/video4linux/bttv diff -rNu linux-2.4.7/linux/Documentation/video4linux/bttv/CVS/Root linux-2.4-xfs/linux/Documentation/video4linux/bttv/CVS/Root --- linux-2.4.7/linux/Documentation/video4linux/bttv/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/video4linux/bttv/CVS/Root Thu Jul 5 11:46:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/Documentation/vm/CVS/Entries linux-2.4-xfs/linux/Documentation/vm/CVS/Entries --- linux-2.4.7/linux/Documentation/vm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/vm/CVS/Entries Thu Jul 5 11:46:59 2001 @@ -0,0 +1,4 @@ +/balance/1.2/Sun Feb 27 22:13:56 2000/-ko/ +/locking/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/numa/1.1/Tue Dec 7 03:15:49 1999/-ko/ +D diff -rNu linux-2.4.7/linux/Documentation/vm/CVS/Repository linux-2.4-xfs/linux/Documentation/vm/CVS/Repository --- linux-2.4.7/linux/Documentation/vm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/vm/CVS/Repository Thu Jul 5 11:46:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/Documentation/vm diff -rNu linux-2.4.7/linux/Documentation/vm/CVS/Root linux-2.4-xfs/linux/Documentation/vm/CVS/Root --- linux-2.4.7/linux/Documentation/vm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/Documentation/vm/CVS/Root Thu Jul 5 11:46:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/MAINTAINERS linux-2.4-xfs/linux/MAINTAINERS --- linux-2.4.7/linux/MAINTAINERS Wed Jun 27 15:59:32 2001 +++ linux-2.4-xfs/linux/MAINTAINERS Thu Jun 28 00:21:16 2001 @@ -1542,6 +1542,14 @@ L: linux-x25@vger.kernel.org S: Maintained +XFS FILESYSTEM +P: Silicon Graphics Inc +M: owner-xfs@oss.sgi.com +M: lord@sgi.com +L: linux-xfs@oss.sgi.com +W: http://oss.sgi.com/projects/xfs +S: Supported + X86 3-LEVEL PAGING (PAE) SUPPORT P: Ingo Molnar M: mingo@redhat.com diff -rNu linux-2.4.7/linux/Makefile linux-2.4-xfs/linux/Makefile --- linux-2.4.7/linux/Makefile Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/Makefile Thu Jul 5 01:13:42 2001 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 7 -EXTRAVERSION =-pre2 +EXTRAVERSION =-pre2-xfs KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -27,6 +27,20 @@ AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld CC = $(CROSS_COMPILE)gcc +#===== NOTE ===== +# egcs-2.91.66 is the recommended compiler version for building XFS. +# Most of the XFS developers are using that particular version for +# development, testing, and performance analysis work, and it will +# generate a functional XFS kernel (some versions of gcc will not) - +# uncomment the following line to force that gcc version to be used: +#CC = $(CROSS_COMPILE)gcc -V egcs-2.91.66 +# On early versions of RedHat 7.x, kgcc is the recommended compiler +# for building the kernel (kgcc is the same as egcs-2.91.66) - if +# you use such a distribution and wish to use kgcc, uncomment this: +#CC = $(CROSS_COMPILE)kgcc +# The default gcc with RedHat 7.1 (gcc-2.96-81) also appears to +# generate good code, earlier versions of 2.96 are however an +# unknown quantity and not recommended. CPP = $(CC) -E AR = $(CROSS_COMPILE)ar NM = $(CROSS_COMPILE)nm @@ -36,13 +50,16 @@ MAKEFILES = $(TOPDIR)/.config GENKSYMS = /sbin/genksyms DEPMOD = /sbin/depmod +KALLSYMS = /sbin/kallsyms MODFLAGS = -DMODULE CFLAGS_KERNEL = PERL = perl +AWK = awk +TMPPREFIX = export VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \ CONFIG_SHELL TOPDIR HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \ - CPP AR NM STRIP OBJCOPY OBJDUMP MAKE MAKEFILES GENKSYMS MODFLAGS PERL + CPP AR NM STRIP OBJCOPY OBJDUMP MAKE MAKEFILES GENKSYMS MODFLAGS PERL AWK all: do-it-all @@ -86,9 +103,13 @@ # CPPFLAGS := -D__KERNEL__ -I$(HPATH) +CPPFLAGS += $(patsubst %,-I%,$(CROSS_COMPILE_INC)) CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \ - -fomit-frame-pointer -fno-strict-aliasing + -fno-strict-aliasing +ifndef CONFIG_FRAME_POINTER +CFLAGS += -fomit-frame-pointer +endif AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS) # @@ -123,6 +144,11 @@ LIBS =$(TOPDIR)/lib/lib.a SUBDIRS =kernel drivers mm fs net ipc lib +ifeq ($(CONFIG_KDB),y) +CORE_FILES += kdb/kdb.o +SUBDIRS += kdb +endif + DRIVERS-n := DRIVERS-y := DRIVERS-m := @@ -188,7 +214,7 @@ CLEAN_FILES = \ kernel/ksyms.lst include/linux/compile.h \ vmlinux System.map \ - .tmp* \ + $(TMPPREFIX).tmp* \ drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c \ drivers/char/conmakehash \ drivers/char/drm/*-mod.c \ @@ -221,6 +247,7 @@ scripts/lxdialog/*.o scripts/lxdialog/lxdialog \ .menuconfig.log \ include/asm \ + kdb/gen-kdb_cmds.c \ .hdepend scripts/mkdep scripts/split-include scripts/docproc \ $(TOPDIR)/include/linux/modversions.h # directories removed with 'make mrproper' @@ -231,14 +258,14 @@ include arch/$(ARCH)/Makefile -export CPPFLAGS CFLAGS AFLAGS +export CPPFLAGS CFLAGS CFLAGS_KERNEL AFLAGS AFLAGS_KERNEL export NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS .S.s: - $(CPP) $(AFLAGS) -traditional -o $*.s $< + $(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -o $*.s $< .S.o: - $(CC) $(AFLAGS) -traditional -c -o $*.o $< + $(CC) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -c -o $*.o $< Version: dummy @rm -f include/linux/compile.h @@ -246,16 +273,39 @@ boot: vmlinux @$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C arch/$(ARCH)/boot +LD_VMLINUX := $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \ + --start-group \ + $(CORE_FILES) \ + $(DRIVERS) \ + $(NETWORKS) \ + $(LIBS) \ + --end-group +ifeq ($(CONFIG_KALLSYMS),y) +LD_VMLINUX_KALLSYMS := $(TMPPREFIX).tmp_kallsyms3.o +else +LD_VMLINUX_KALLSYMS := +endif + vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs - $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \ - --start-group \ - $(CORE_FILES) \ - $(DRIVERS) \ - $(NETWORKS) \ - $(LIBS) \ - --end-group \ - -o vmlinux + @$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" kallsyms + +.PHONY: kallsyms + +kallsyms: +ifeq ($(CONFIG_KALLSYMS),y) + @echo kallsyms pass 1 + $(LD_VMLINUX) -o $(TMPPREFIX).tmp_vmlinux1 + @$(KALLSYMS) $(TMPPREFIX).tmp_vmlinux1 > $(TMPPREFIX).tmp_kallsyms1.o + @echo kallsyms pass 2 + @$(LD_VMLINUX) $(TMPPREFIX).tmp_kallsyms1.o -o $(TMPPREFIX).tmp_vmlinux2 + @$(KALLSYMS) $(TMPPREFIX).tmp_vmlinux2 > $(TMPPREFIX).tmp_kallsyms2.o + @echo kallsyms pass 3 + @$(LD_VMLINUX) $(TMPPREFIX).tmp_kallsyms2.o -o $(TMPPREFIX).tmp_vmlinux3 + @$(KALLSYMS) $(TMPPREFIX).tmp_vmlinux3 > $(TMPPREFIX).tmp_kallsyms3.o +endif + $(LD_VMLINUX) $(LD_VMLINUX_KALLSYMS) -o vmlinux $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map + @rm -f $(TMPPREFIX).tmp_vmlinux* $(TMPPREFIX).tmp_kallsyms* symlinks: rm -f include/asm diff -rNu linux-2.4.7/linux/arch/CVS/Entries linux-2.4-xfs/linux/arch/CVS/Entries --- linux-2.4.7/linux/arch/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/CVS/Entries Thu Jul 5 11:46:59 2001 @@ -0,0 +1 @@ +D diff -rNu linux-2.4.7/linux/arch/CVS/Entries.Log linux-2.4-xfs/linux/arch/CVS/Entries.Log --- linux-2.4.7/linux/arch/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/CVS/Entries.Log Thu Jul 5 11:50:40 2001 @@ -0,0 +1,15 @@ +A D/alpha//// +A D/arm//// +A D/cris//// +A D/i386//// +A D/ia64//// +A D/m68k//// +A D/mips//// +A D/mips64//// +A D/parisc//// +A D/ppc//// +A D/s390//// +A D/s390x//// +A D/sh//// +A D/sparc//// +A D/sparc64//// diff -rNu linux-2.4.7/linux/arch/CVS/Repository linux-2.4-xfs/linux/arch/CVS/Repository --- linux-2.4.7/linux/arch/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/CVS/Repository Thu Jul 5 11:46:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch diff -rNu linux-2.4.7/linux/arch/CVS/Root linux-2.4-xfs/linux/arch/CVS/Root --- linux-2.4.7/linux/arch/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/CVS/Root Thu Jul 5 11:46:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/alpha/CVS/Entries linux-2.4-xfs/linux/arch/alpha/CVS/Entries --- linux-2.4.7/linux/arch/alpha/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/CVS/Entries Thu Jul 5 11:46:59 2001 @@ -0,0 +1,5 @@ +/Makefile/1.10/Sun Dec 17 19:15:00 2000/-ko/ +/config.in/1.31/Sat Jun 9 02:44:24 2001/-ko/ +/defconfig/1.17/Tue Jun 12 04:51:00 2001/-ko/ +/vmlinux.lds.in/1.4/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/alpha/CVS/Entries.Log linux-2.4-xfs/linux/arch/alpha/CVS/Entries.Log --- linux-2.4.7/linux/arch/alpha/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/CVS/Entries.Log Thu Jul 5 11:47:11 2001 @@ -0,0 +1,5 @@ +A D/boot//// +A D/kernel//// +A D/lib//// +A D/math-emu//// +A D/mm//// diff -rNu linux-2.4.7/linux/arch/alpha/CVS/Repository linux-2.4-xfs/linux/arch/alpha/CVS/Repository --- linux-2.4.7/linux/arch/alpha/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/CVS/Repository Thu Jul 5 11:46:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/alpha diff -rNu linux-2.4.7/linux/arch/alpha/CVS/Root linux-2.4-xfs/linux/arch/alpha/CVS/Root --- linux-2.4.7/linux/arch/alpha/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/CVS/Root Thu Jul 5 11:46:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/alpha/boot/CVS/Entries linux-2.4-xfs/linux/arch/alpha/boot/CVS/Entries --- linux-2.4.7/linux/arch/alpha/boot/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/boot/CVS/Entries Thu Jul 5 11:47:00 2001 @@ -0,0 +1,6 @@ +/Makefile/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/bootloader.lds/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/bootp.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/head.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/main.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/alpha/boot/CVS/Entries.Log linux-2.4-xfs/linux/arch/alpha/boot/CVS/Entries.Log --- linux-2.4.7/linux/arch/alpha/boot/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/boot/CVS/Entries.Log Thu Jul 5 11:47:00 2001 @@ -0,0 +1 @@ +A D/tools//// diff -rNu linux-2.4.7/linux/arch/alpha/boot/CVS/Repository linux-2.4-xfs/linux/arch/alpha/boot/CVS/Repository --- linux-2.4.7/linux/arch/alpha/boot/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/boot/CVS/Repository Thu Jul 5 11:46:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/alpha/boot diff -rNu linux-2.4.7/linux/arch/alpha/boot/CVS/Root linux-2.4-xfs/linux/arch/alpha/boot/CVS/Root --- linux-2.4.7/linux/arch/alpha/boot/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/boot/CVS/Root Thu Jul 5 11:46:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/alpha/boot/tools/CVS/Entries linux-2.4-xfs/linux/arch/alpha/boot/tools/CVS/Entries --- linux-2.4.7/linux/arch/alpha/boot/tools/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/boot/tools/CVS/Entries Thu Jul 5 11:47:00 2001 @@ -0,0 +1,3 @@ +/mkbb.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/objstrip.c/1.4/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/alpha/boot/tools/CVS/Repository linux-2.4-xfs/linux/arch/alpha/boot/tools/CVS/Repository --- linux-2.4.7/linux/arch/alpha/boot/tools/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/boot/tools/CVS/Repository Thu Jul 5 11:47:00 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/alpha/boot/tools diff -rNu linux-2.4.7/linux/arch/alpha/boot/tools/CVS/Root linux-2.4-xfs/linux/arch/alpha/boot/tools/CVS/Root --- linux-2.4.7/linux/arch/alpha/boot/tools/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/boot/tools/CVS/Root Thu Jul 5 11:47:00 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/alpha/defconfig linux-2.4-xfs/linux/arch/alpha/defconfig --- linux-2.4.7/linux/arch/alpha/defconfig Fri May 4 17:16:28 2001 +++ linux-2.4-xfs/linux/arch/alpha/defconfig Mon Jun 11 23:51:00 2001 @@ -635,3 +635,11 @@ CONFIG_MATHEMU=y CONFIG_MAGIC_SYSRQ=y CONFIG_ALPHA_LEGACY_START_ADDRESS=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/alpha/kernel/CVS/Entries linux-2.4-xfs/linux/arch/alpha/kernel/CVS/Entries --- linux-2.4.7/linux/arch/alpha/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/kernel/CVS/Entries Thu Jul 5 11:47:08 2001 @@ -0,0 +1,62 @@ +/Makefile/1.17/Thu Feb 22 21:09:04 2001/-ko/ +/alpha_ksyms.c/1.22/Thu Jun 21 15:45:04 2001/-ko/ +/check_asm.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/console.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/core_apecs.c/1.11/Mon Apr 2 17:13:32 2001/-ko/ +/core_cia.c/1.18/Tue May 29 19:53:13 2001/-ko/ +/core_irongate.c/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/core_lca.c/1.11/Mon Apr 2 17:13:32 2001/-ko/ +/core_mcpcia.c/1.16/Mon Apr 2 17:13:32 2001/-ko/ +/core_polaris.c/1.11/Mon Apr 2 17:13:32 2001/-ko/ +/core_t2.c/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/core_titan.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/core_tsunami.c/1.18/Wed Jun 6 03:10:14 2001/-ko/ +/core_wildfire.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/entry.S/1.19/Sat Jun 9 02:44:24 2001/-ko/ +/es1888.c/1.3/Tue Jul 27 20:02:32 1999/-ko/ +/head.S/1.5/Tue May 2 21:09:12 2000/-ko/ +/irq.c/1.18/Thu Jun 21 15:45:04 2001/-ko/ +/irq_alpha.c/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/irq_i8259.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/irq_impl.h/1.4/Fri Mar 3 01:30:48 2000/-ko/ +/irq_pyxis.c/1.1/Mon Mar 20 17:58:41 2000/-ko/ +/irq_smp.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/irq_srm.c/1.2/Mon Mar 20 17:58:41 2000/-ko/ +/machvec_impl.h/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/ns87312.c/1.1/Mon Sep 6 21:00:05 1999/-ko/ +/osf_sys.c/1.24/Wed Jun 13 03:24:09 2001/-ko/ +/pci-noop.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/pci.c/1.15/Tue May 29 19:53:13 2001/-ko/ +/pci_impl.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/pci_iommu.c/1.12/Tue May 29 19:53:13 2001/-ko/ +/process.c/1.17/Thu Jun 21 15:45:04 2001/-ko/ +/proto.h/1.16/Mon Apr 2 17:13:32 2001/-ko/ +/ptrace.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/semaphore.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.20/Tue May 29 19:53:13 2001/-ko/ +/signal.c/1.10/Thu Feb 1 17:10:24 2001/-ko/ +/smc37c669.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/smc37c93x.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/smp.c/1.23/Sat Jun 9 02:44:24 2001/-ko/ +/sys_alcor.c/1.9/Thu Jun 28 05:21:16 2001/-ko/ +/sys_cabriolet.c/1.11/Thu Feb 1 17:10:24 2001/-ko/ +/sys_dp264.c/1.15/Wed Jun 6 03:10:14 2001/-ko/ +/sys_eb64p.c/1.8/Wed Nov 1 21:35:42 2000/-ko/ +/sys_eiger.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/sys_jensen.c/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/sys_miata.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/sys_mikasa.c/1.10/Wed Nov 1 21:35:42 2000/-ko/ +/sys_nautilus.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/sys_noritake.c/1.9/Wed Nov 1 21:35:42 2000/-ko/ +/sys_rawhide.c/1.11/Wed Jun 6 03:10:14 2001/-ko/ +/sys_ruffian.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/sys_rx164.c/1.8/Wed Nov 1 21:35:42 2000/-ko/ +/sys_sable.c/1.8/Wed Jun 13 03:24:09 2001/-ko/ +/sys_sio.c/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/sys_sx164.c/1.9/Wed Nov 1 21:35:42 2000/-ko/ +/sys_takara.c/1.8/Wed Nov 1 21:35:42 2000/-ko/ +/sys_titan.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/sys_wildfire.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/time.c/1.16/Thu Jul 5 05:29:17 2001/-ko/ +/traps.c/1.12/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/alpha/kernel/CVS/Repository linux-2.4-xfs/linux/arch/alpha/kernel/CVS/Repository --- linux-2.4.7/linux/arch/alpha/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/kernel/CVS/Repository Thu Jul 5 11:47:00 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/alpha/kernel diff -rNu linux-2.4.7/linux/arch/alpha/kernel/CVS/Root linux-2.4-xfs/linux/arch/alpha/kernel/CVS/Root --- linux-2.4.7/linux/arch/alpha/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/kernel/CVS/Root Thu Jul 5 11:47:00 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/alpha/lib/CVS/Entries linux-2.4-xfs/linux/arch/alpha/lib/CVS/Entries --- linux-2.4.7/linux/arch/alpha/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/lib/CVS/Entries Thu Jul 5 11:47:11 2001 @@ -0,0 +1,53 @@ +/Makefile/1.12/Thu Jun 21 15:45:04 2001/-ko/ +/callback_srm.S/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/checksum.c/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/clear_page.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/clear_user.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/copy_page.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/copy_user.S/1.3/Fri May 26 01:14:50 2000/-ko/ +/csum_ipv6_magic.S/1.4/Wed Feb 23 18:35:06 2000/-ko/ +/csum_partial_copy.c/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/divide.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ev6-clear_page.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ev6-clear_user.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ev6-copy_page.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ev6-copy_user.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ev6-csum_ipv6_magic.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ev6-divide.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ev6-memchr.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ev6-memcpy.S/1.2/Wed Jan 3 01:43:05 2001/-ko/ +/ev6-memset.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ev6-strncpy_from_user.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ev6-stxcpy.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ev6-stxncpy.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ev67-strcat.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ev67-strchr.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ev67-strlen.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ev67-strlen_user.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ev67-strncat.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ev67-strrchr.S/1.1/Wed Jan 3 01:43:05 2001/-ko/ +/fpreg.c/1.1/Tue Dec 7 03:15:49 1999/-ko/ +/io.c/1.5/Tue Dec 7 03:15:49 1999/-ko/ +/memchr.S/1.1/Sun Aug 29 02:07:15 1999/-ko/ +/memcpy.c/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/memmove.S/1.2/Wed Jan 3 01:43:05 2001/-ko/ +/memset.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/srm_printk.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/srm_puts.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/stackcheck.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/stackkill.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/stacktrace.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/strcasecmp.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/strcat.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/strchr.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/strcpy.S/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/strlen.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/strlen_user.S/1.3/Tue Oct 12 18:49:29 1999/-ko/ +/strncat.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/strncpy.S/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/strncpy_from_user.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/strrchr.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/stxcpy.S/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/stxncpy.S/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/udelay.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/alpha/lib/CVS/Repository linux-2.4-xfs/linux/arch/alpha/lib/CVS/Repository --- linux-2.4.7/linux/arch/alpha/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/lib/CVS/Repository Thu Jul 5 11:47:08 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/alpha/lib diff -rNu linux-2.4.7/linux/arch/alpha/lib/CVS/Root linux-2.4-xfs/linux/arch/alpha/lib/CVS/Root --- linux-2.4.7/linux/arch/alpha/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/lib/CVS/Root Thu Jul 5 11:47:08 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/alpha/math-emu/CVS/Entries linux-2.4-xfs/linux/arch/alpha/math-emu/CVS/Entries --- linux-2.4.7/linux/arch/alpha/math-emu/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/math-emu/CVS/Entries Thu Jul 5 11:47:11 2001 @@ -0,0 +1,5 @@ +/Makefile/1.5/Wed Jan 3 01:43:05 2001/-ko/ +/math.c/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/qrnnd.S/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/sfp-util.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/alpha/math-emu/CVS/Repository linux-2.4-xfs/linux/arch/alpha/math-emu/CVS/Repository --- linux-2.4.7/linux/arch/alpha/math-emu/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/math-emu/CVS/Repository Thu Jul 5 11:47:11 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/alpha/math-emu diff -rNu linux-2.4.7/linux/arch/alpha/math-emu/CVS/Root linux-2.4-xfs/linux/arch/alpha/math-emu/CVS/Root --- linux-2.4.7/linux/arch/alpha/math-emu/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/math-emu/CVS/Root Thu Jul 5 11:47:11 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/alpha/mm/CVS/Entries linux-2.4-xfs/linux/arch/alpha/mm/CVS/Entries --- linux-2.4.7/linux/arch/alpha/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/mm/CVS/Entries Thu Jul 5 11:47:11 2001 @@ -0,0 +1,6 @@ +/Makefile/1.3/Tue May 29 19:53:13 2001/-ko/ +/extable.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/fault.c/1.13/Mon Apr 2 17:13:32 2001/-ko/ +/init.c/1.18/Tue May 29 19:53:13 2001/-ko/ +/numa.c/1.1/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/alpha/mm/CVS/Repository linux-2.4-xfs/linux/arch/alpha/mm/CVS/Repository --- linux-2.4.7/linux/arch/alpha/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/mm/CVS/Repository Thu Jul 5 11:47:11 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/alpha/mm diff -rNu linux-2.4.7/linux/arch/alpha/mm/CVS/Root linux-2.4-xfs/linux/arch/alpha/mm/CVS/Root --- linux-2.4.7/linux/arch/alpha/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/alpha/mm/CVS/Root Thu Jul 5 11:47:11 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/alpha/vmlinux.lds.in linux-2.4-xfs/linux/arch/alpha/vmlinux.lds.in --- linux-2.4.7/linux/arch/alpha/vmlinux.lds.in Mon Jul 2 16:40:14 2001 +++ linux-2.4-xfs/linux/arch/alpha/vmlinux.lds.in Mon Jul 2 21:33:57 2001 @@ -28,6 +28,10 @@ __stop___ksymtab = .; .kstrtab : { *(.kstrtab) } + __start___kallsyms = .; /* All kernel symbols */ + __kallsyms : { *(__kallsyms) } + __stop___kallsyms = .; + /* Startup code */ . = ALIGN(8192); __init_begin = .; diff -rNu linux-2.4.7/linux/arch/arm/CVS/Entries linux-2.4-xfs/linux/arch/arm/CVS/Entries --- linux-2.4.7/linux/arch/arm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/CVS/Entries Thu Jul 5 11:47:11 2001 @@ -0,0 +1,6 @@ +/Makefile/1.21/Thu Jun 28 05:21:16 2001/-ko/ +/config.in/1.25/Sat Jun 9 02:44:24 2001/-ko/ +/defconfig/1.17/Tue Jun 12 04:51:00 2001/-ko/ +/vmlinux-armo.lds.in/1.13/Tue Jul 3 02:33:57 2001/-ko/ +/vmlinux-armv.lds.in/1.15/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/arm/CVS/Entries.Log linux-2.4-xfs/linux/arch/arm/CVS/Entries.Log --- linux-2.4.7/linux/arch/arm/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/CVS/Entries.Log Thu Jul 5 11:47:31 2001 @@ -0,0 +1,12 @@ +A D/boot//// +A D/def-configs//// +A D/kernel//// +A D/lib//// +A D/mach-ebsa110//// +A D/mach-footbridge//// +A D/mach-integrator//// +A D/mach-sa1100//// +A D/mach-shark//// +A D/mm//// +A D/nwfpe//// +A D/tools//// diff -rNu linux-2.4.7/linux/arch/arm/CVS/Repository linux-2.4-xfs/linux/arch/arm/CVS/Repository --- linux-2.4.7/linux/arch/arm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/CVS/Repository Thu Jul 5 11:47:11 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/arm diff -rNu linux-2.4.7/linux/arch/arm/CVS/Root linux-2.4-xfs/linux/arch/arm/CVS/Root --- linux-2.4.7/linux/arch/arm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/CVS/Root Thu Jul 5 11:47:11 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/arm/boot/CVS/Entries linux-2.4-xfs/linux/arch/arm/boot/CVS/Entries --- linux-2.4.7/linux/arch/arm/boot/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/boot/CVS/Entries Thu Jul 5 11:47:11 2001 @@ -0,0 +1,3 @@ +/Makefile/1.8/Thu Jun 28 05:21:16 2001/-ko/ +/install.sh/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/arch/arm/boot/CVS/Entries.Log linux-2.4-xfs/linux/arch/arm/boot/CVS/Entries.Log --- linux-2.4.7/linux/arch/arm/boot/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/boot/CVS/Entries.Log Thu Jul 5 11:47:11 2001 @@ -0,0 +1,2 @@ +A D/bootp//// +A D/compressed//// diff -rNu linux-2.4.7/linux/arch/arm/boot/CVS/Repository linux-2.4-xfs/linux/arch/arm/boot/CVS/Repository --- linux-2.4.7/linux/arch/arm/boot/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/boot/CVS/Repository Thu Jul 5 11:47:11 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/arm/boot diff -rNu linux-2.4.7/linux/arch/arm/boot/CVS/Root linux-2.4-xfs/linux/arch/arm/boot/CVS/Root --- linux-2.4.7/linux/arch/arm/boot/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/boot/CVS/Root Thu Jul 5 11:47:11 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/arm/boot/bootp/CVS/Entries linux-2.4-xfs/linux/arch/arm/boot/bootp/CVS/Entries --- linux-2.4.7/linux/arch/arm/boot/bootp/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/boot/bootp/CVS/Entries Thu Jul 5 11:47:11 2001 @@ -0,0 +1,4 @@ +/Makefile/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/bootp.lds/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/init.S/1.3/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/arm/boot/bootp/CVS/Repository linux-2.4-xfs/linux/arch/arm/boot/bootp/CVS/Repository --- linux-2.4.7/linux/arch/arm/boot/bootp/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/boot/bootp/CVS/Repository Thu Jul 5 11:47:11 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/arm/boot/bootp diff -rNu linux-2.4.7/linux/arch/arm/boot/bootp/CVS/Root linux-2.4-xfs/linux/arch/arm/boot/bootp/CVS/Root --- linux-2.4.7/linux/arch/arm/boot/bootp/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/boot/bootp/CVS/Root Thu Jul 5 11:47:11 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/arm/boot/compressed/CVS/Entries linux-2.4-xfs/linux/arch/arm/boot/compressed/CVS/Entries --- linux-2.4.7/linux/arch/arm/boot/compressed/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/boot/compressed/CVS/Entries Thu Jul 5 11:47:12 2001 @@ -0,0 +1,17 @@ +/Makefile/1.18/Thu Jun 28 05:21:16 2001/-ko/ +/Makefile.debug/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/head-clps7500.S/1.1/Wed May 2 06:22:13 2001/-ko/ +/head-ftvpci.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/head-integrator.S/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/head-l7200.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/head-netwinder.S/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/head-sa1100.S/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/head-shark.S/1.2/Wed May 2 06:22:13 2001/-ko/ +/head.S/1.13/Thu Jun 28 05:21:16 2001/-ko/ +/hw-bse.c/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/ll_char_wr.S/1.3/Wed May 2 06:22:13 2001/-ko/ +/misc.c/1.3/Sat Oct 23 02:00:20 1999/-ko/ +/ofw-shark.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/setup-sa1100.S/1.6/Thu Jun 28 05:21:16 2001/-ko/ +/vmlinux.lds.in/1.4/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/arm/boot/compressed/CVS/Repository linux-2.4-xfs/linux/arch/arm/boot/compressed/CVS/Repository --- linux-2.4.7/linux/arch/arm/boot/compressed/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/boot/compressed/CVS/Repository Thu Jul 5 11:47:11 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/arm/boot/compressed diff -rNu linux-2.4.7/linux/arch/arm/boot/compressed/CVS/Root linux-2.4-xfs/linux/arch/arm/boot/compressed/CVS/Root --- linux-2.4.7/linux/arch/arm/boot/compressed/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/boot/compressed/CVS/Root Thu Jul 5 11:47:11 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/arm/def-configs/CVS/Entries linux-2.4-xfs/linux/arch/arm/def-configs/CVS/Entries --- linux-2.4.7/linux/arch/arm/def-configs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/def-configs/CVS/Entries Thu Jul 5 11:47:14 2001 @@ -0,0 +1,19 @@ +/a5k/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/assabet/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/brutus/1.8/Sun Dec 17 19:15:00 2000/-ko/ +/cerf/1.2/Sun Dec 17 19:15:00 2000/-ko/ +/clps7500/1.2/Tue May 29 19:53:13 2001/-ko/ +/ebsa110/1.7/Tue May 29 19:53:13 2001/-ko/ +/empeg/1.1/Sat Oct 23 02:00:20 1999/-ko/ +/footbridge/1.10/Sun Dec 17 19:15:00 2000/-ko/ +/graphicsclient/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/integrator/1.2/Tue May 29 19:53:13 2001/-ko/ +/lart/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/lusl7200/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/neponset/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/pangolin/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/rpc/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/shark/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/sherman/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/victor/1.2/Mon Jul 31 16:16:28 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/arm/def-configs/CVS/Repository linux-2.4-xfs/linux/arch/arm/def-configs/CVS/Repository --- linux-2.4.7/linux/arch/arm/def-configs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/def-configs/CVS/Repository Thu Jul 5 11:47:12 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/arm/def-configs diff -rNu linux-2.4.7/linux/arch/arm/def-configs/CVS/Root linux-2.4-xfs/linux/arch/arm/def-configs/CVS/Root --- linux-2.4.7/linux/arch/arm/def-configs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/def-configs/CVS/Root Thu Jul 5 11:47:12 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/arm/defconfig linux-2.4-xfs/linux/arch/arm/defconfig --- linux-2.4.7/linux/arch/arm/defconfig Sat May 19 19:43:05 2001 +++ linux-2.4-xfs/linux/arch/arm/defconfig Mon Jun 11 23:51:00 2001 @@ -509,3 +509,11 @@ # CONFIG_DEBUG_INFO is not set CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_LL=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/arm/kernel/CVS/Entries linux-2.4-xfs/linux/arch/arm/kernel/CVS/Entries --- linux-2.4.7/linux/arch/arm/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/kernel/CVS/Entries Thu Jul 5 11:47:20 2001 @@ -0,0 +1,42 @@ +/Makefile/1.16/Wed May 2 06:22:13 2001/-ko/ +/arch.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/armksyms.c/1.18/Wed May 2 06:22:13 2001/-ko/ +/arthur.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/bios32.c/1.22/Thu Jul 5 06:13:42 2001/-ko/ +/calls.S/1.15/Thu Jun 28 05:21:16 2001/-ko/ +/debug-armo.S/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/debug-armv.S/1.8/Wed May 2 06:22:13 2001/-ko/ +/dec21285.c/1.15/Thu Jul 5 06:13:42 2001/-ko/ +/dma-arc.c/1.10/Thu Jul 5 06:13:42 2001/-ko/ +/dma-footbridge.c/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/dma-isa.c/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/dma-rpc.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/dma.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/ecard.c/1.13/Thu Jun 28 05:21:16 2001/-ko/ +/entry-armo.S/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/entry-armv.S/1.19/Thu Jun 28 05:21:16 2001/-ko/ +/entry-common.S/1.14/Wed May 2 06:22:13 2001/-ko/ +/fiq.c/1.10/Thu Jun 28 05:21:16 2001/-ko/ +/ftv-pci.c/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/head-armo.S/1.7/Wed May 2 06:22:13 2001/-ko/ +/head-armv.S/1.15/Thu Jul 5 06:13:42 2001/-ko/ +/init_task.c/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/io.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/irq-arch.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/irq.c/1.13/Thu Jul 5 06:13:42 2001/-ko/ +/isa.c/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/leds-ftvpci.c/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/oldlatches.c/1.8/Thu Jul 5 06:13:42 2001/-ko/ +/plx90x0.c/1.2/Thu Jul 5 06:13:42 2001/-ko/ +/process.c/1.17/Thu Feb 22 21:09:04 2001/-ko/ +/ptrace.c/1.10/Mon Oct 23 18:56:35 2000/-ko/ +/ptrace.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/semaphore.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.20/Tue May 29 19:53:13 2001/-ko/ +/signal.c/1.14/Thu Feb 1 17:10:24 2001/-ko/ +/sys_arm.c/1.18/Thu Jul 5 06:13:42 2001/-ko/ +/time-acorn.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/time.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/traps.c/1.19/Thu Jun 28 05:21:16 2001/-ko/ +/via82c505.c/1.3/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/arm/kernel/CVS/Repository linux-2.4-xfs/linux/arch/arm/kernel/CVS/Repository --- linux-2.4.7/linux/arch/arm/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/kernel/CVS/Repository Thu Jul 5 11:47:14 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/arm/kernel diff -rNu linux-2.4.7/linux/arch/arm/kernel/CVS/Root linux-2.4-xfs/linux/arch/arm/kernel/CVS/Root --- linux-2.4.7/linux/arch/arm/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/kernel/CVS/Root Thu Jul 5 11:47:14 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/arm/lib/CVS/Entries linux-2.4-xfs/linux/arch/arm/lib/CVS/Entries --- linux-2.4.7/linux/arch/arm/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/lib/CVS/Entries Thu Jul 5 11:47:22 2001 @@ -0,0 +1,41 @@ +/Makefile/1.17/Tue May 29 19:53:13 2001/-ko/ +/backtrace.S/1.6/Wed May 2 06:22:13 2001/-ko/ +/changebit.S/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/clearbit.S/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/copy_page.S/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/csumipv6.S/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/csumpartial.S/1.3/Tue May 29 19:53:13 2001/-ko/ +/csumpartialcopy.S/1.4/Tue May 29 19:53:13 2001/-ko/ +/csumpartialcopygeneric.S/1.1/Tue May 29 19:53:13 2001/-ko/ +/csumpartialcopyuser.S/1.5/Tue May 29 19:53:13 2001/-ko/ +/delay.S/1.5/Wed May 2 06:22:13 2001/-ko/ +/ecard.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/findbit.S/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/floppydma.S/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/io-acorn.S/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/io-pcio.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/io-readsb.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/io-readsl-armv3.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/io-readsl-armv4.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/io-readsw-armv3.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/io-readsw-armv4.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/io-shark.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/io-writesb.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/io-writesl.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/io-writesw-armv3.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/io-writesw-armv4.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/memchr.S/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/memcpy.S/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/memset.S/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/memzero.S/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/setbit.S/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/strchr.S/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/strncpy_from_user.S/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/strnlen_user.S/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/strrchr.S/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/testchangebit.S/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/testclearbit.S/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/testsetbit.S/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/uaccess-armo.S/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/uaccess.S/1.7/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/arm/lib/CVS/Repository linux-2.4-xfs/linux/arch/arm/lib/CVS/Repository --- linux-2.4.7/linux/arch/arm/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/lib/CVS/Repository Thu Jul 5 11:47:20 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/arm/lib diff -rNu linux-2.4.7/linux/arch/arm/lib/CVS/Root linux-2.4-xfs/linux/arch/arm/lib/CVS/Root --- linux-2.4.7/linux/arch/arm/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/lib/CVS/Root Thu Jul 5 11:47:20 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/arm/mach-ebsa110/CVS/Entries linux-2.4-xfs/linux/arch/arm/mach-ebsa110/CVS/Entries --- linux-2.4.7/linux/arch/arm/mach-ebsa110/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mach-ebsa110/CVS/Entries Thu Jul 5 11:47:22 2001 @@ -0,0 +1,9 @@ +/Makefile/1.1/Wed May 2 06:22:13 2001/-ko/ +/arch.c/1.2/Thu Jun 28 05:21:16 2001/-ko/ +/hardware.h/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/io.c/1.3/Thu Jun 28 05:21:16 2001/-ko/ +/irq.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/leds.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/mm.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/time.c/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/arm/mach-ebsa110/CVS/Repository linux-2.4-xfs/linux/arch/arm/mach-ebsa110/CVS/Repository --- linux-2.4.7/linux/arch/arm/mach-ebsa110/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mach-ebsa110/CVS/Repository Thu Jul 5 11:47:22 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/arm/mach-ebsa110 diff -rNu linux-2.4.7/linux/arch/arm/mach-ebsa110/CVS/Root linux-2.4-xfs/linux/arch/arm/mach-ebsa110/CVS/Root --- linux-2.4.7/linux/arch/arm/mach-ebsa110/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mach-ebsa110/CVS/Root Thu Jul 5 11:47:22 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/arm/mach-footbridge/CVS/Entries linux-2.4-xfs/linux/arch/arm/mach-footbridge/CVS/Entries --- linux-2.4.7/linux/arch/arm/mach-footbridge/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mach-footbridge/CVS/Entries Thu Jul 5 11:47:22 2001 @@ -0,0 +1,13 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/arch.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/cats-hw.c/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/cats-pci.c/1.2/Thu Jul 5 06:13:42 2001/-ko/ +/ebsa285-leds.c/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/ebsa285-pci.c/1.2/Thu Jul 5 06:13:42 2001/-ko/ +/irq.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/mm.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/netwinder-hw.c/1.2/Sun Dec 17 19:15:00 2000/-ko/ +/netwinder-leds.c/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/netwinder-pci.c/1.2/Thu Jul 5 06:13:42 2001/-ko/ +/personal-pci.c/1.2/Thu Jul 5 06:13:42 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/arm/mach-footbridge/CVS/Repository linux-2.4-xfs/linux/arch/arm/mach-footbridge/CVS/Repository --- linux-2.4.7/linux/arch/arm/mach-footbridge/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mach-footbridge/CVS/Repository Thu Jul 5 11:47:22 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/arm/mach-footbridge diff -rNu linux-2.4.7/linux/arch/arm/mach-footbridge/CVS/Root linux-2.4-xfs/linux/arch/arm/mach-footbridge/CVS/Root --- linux-2.4.7/linux/arch/arm/mach-footbridge/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mach-footbridge/CVS/Root Thu Jul 5 11:47:22 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/arm/mach-integrator/CVS/Entries linux-2.4-xfs/linux/arch/arm/mach-integrator/CVS/Entries --- linux-2.4.7/linux/arch/arm/mach-integrator/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mach-integrator/CVS/Entries Thu Jul 5 11:47:22 2001 @@ -0,0 +1,10 @@ +/Makefile/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/arch.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/dma.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/irq.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/leds.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/mm.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/pci.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/pci_v3.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/time.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/arm/mach-integrator/CVS/Repository linux-2.4-xfs/linux/arch/arm/mach-integrator/CVS/Repository --- linux-2.4.7/linux/arch/arm/mach-integrator/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mach-integrator/CVS/Repository Thu Jul 5 11:47:22 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/arm/mach-integrator diff -rNu linux-2.4.7/linux/arch/arm/mach-integrator/CVS/Root linux-2.4-xfs/linux/arch/arm/mach-integrator/CVS/Root --- linux-2.4.7/linux/arch/arm/mach-integrator/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mach-integrator/CVS/Root Thu Jul 5 11:47:22 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/arm/mach-sa1100/CVS/Entries linux-2.4-xfs/linux/arch/arm/mach-sa1100/CVS/Entries --- linux-2.4.7/linux/arch/arm/mach-sa1100/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mach-sa1100/CVS/Entries Thu Jul 5 11:47:23 2001 @@ -0,0 +1,8 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/arch.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/dma-sa1100.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dma-sa1111.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dma.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/hw.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/leds.c/1.1/Mon Oct 23 19:17:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/arm/mach-sa1100/CVS/Repository linux-2.4-xfs/linux/arch/arm/mach-sa1100/CVS/Repository --- linux-2.4.7/linux/arch/arm/mach-sa1100/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mach-sa1100/CVS/Repository Thu Jul 5 11:47:22 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/arm/mach-sa1100 diff -rNu linux-2.4.7/linux/arch/arm/mach-sa1100/CVS/Root linux-2.4-xfs/linux/arch/arm/mach-sa1100/CVS/Root --- linux-2.4.7/linux/arch/arm/mach-sa1100/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mach-sa1100/CVS/Root Thu Jul 5 11:47:22 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/arm/mach-shark/CVS/Entries linux-2.4-xfs/linux/arch/arm/mach-shark/CVS/Entries --- linux-2.4.7/linux/arch/arm/mach-shark/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mach-shark/CVS/Entries Thu Jul 5 11:47:23 2001 @@ -0,0 +1,7 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/arch.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/dma.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/leds.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/mm.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/pci.c/1.1/Mon Oct 23 19:17:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/arm/mach-shark/CVS/Repository linux-2.4-xfs/linux/arch/arm/mach-shark/CVS/Repository --- linux-2.4.7/linux/arch/arm/mach-shark/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mach-shark/CVS/Repository Thu Jul 5 11:47:23 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/arm/mach-shark diff -rNu linux-2.4.7/linux/arch/arm/mach-shark/CVS/Root linux-2.4-xfs/linux/arch/arm/mach-shark/CVS/Root --- linux-2.4.7/linux/arch/arm/mach-shark/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mach-shark/CVS/Root Thu Jul 5 11:47:23 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/arm/mm/CVS/Entries linux-2.4-xfs/linux/arch/arm/mm/CVS/Entries --- linux-2.4.7/linux/arch/arm/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mm/CVS/Entries Thu Jul 5 11:47:25 2001 @@ -0,0 +1,24 @@ +/Makefile/1.11/Wed May 2 06:22:13 2001/-ko/ +/consistent.c/1.9/Thu Jun 28 05:21:16 2001/-ko/ +/extable.c/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/fault-armo.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/fault-armv.c/1.15/Thu Jun 28 05:21:16 2001/-ko/ +/fault-common.c/1.15/Wed May 2 06:22:13 2001/-ko/ +/init.c/1.22/Wed May 2 06:22:13 2001/-ko/ +/ioremap.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/mm-armo.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/mm-armv.c/1.22/Thu Jun 28 05:21:16 2001/-ko/ +/mm-clps7500.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/mm-l7200.c/1.5/Thu Jun 28 05:21:16 2001/-ko/ +/mm-nexuspci.c/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/mm-rpc.c/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/mm-sa1100.c/1.10/Wed May 2 06:22:13 2001/-ko/ +/mm-tbox.c/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/proc-arm2,3.S/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/proc-arm6,7.S/1.17/Mon Apr 2 17:13:32 2001/-ko/ +/proc-arm720.S/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/proc-arm920.S/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/proc-sa110.S/1.20/Wed May 2 06:22:13 2001/-ko/ +/proc-syms.c/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/small_page.c/1.9/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/arm/mm/CVS/Repository linux-2.4-xfs/linux/arch/arm/mm/CVS/Repository --- linux-2.4.7/linux/arch/arm/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mm/CVS/Repository Thu Jul 5 11:47:23 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/arm/mm diff -rNu linux-2.4.7/linux/arch/arm/mm/CVS/Root linux-2.4-xfs/linux/arch/arm/mm/CVS/Root --- linux-2.4.7/linux/arch/arm/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/mm/CVS/Root Thu Jul 5 11:47:23 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/arm/nwfpe/CVS/Entries linux-2.4-xfs/linux/arch/arm/nwfpe/CVS/Entries --- linux-2.4.7/linux/arch/arm/nwfpe/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/nwfpe/CVS/Entries Thu Jul 5 11:47:31 2001 @@ -0,0 +1,26 @@ +/ARM-gcc.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/ChangeLog/1.2/Sat Oct 23 02:00:20 1999/-ko/ +/Makefile/1.5/Wed May 2 06:22:13 2001/-ko/ +/double_cpdo.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/entry.S/1.3/Wed May 2 06:22:13 2001/-ko/ +/entry26.S/1.4/Wed May 2 06:22:13 2001/-ko/ +/extended_cpdo.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/fpa11.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/fpa11.h/1.3/Sat Oct 23 02:00:20 1999/-ko/ +/fpa11.inl/1.3/Wed May 2 06:22:13 2001/-ko/ +/fpa11_cpdo.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/fpa11_cpdt.c/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/fpa11_cprt.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/fpmodule.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/fpmodule.h/1.2/Mon Sep 6 21:00:05 1999/-ko/ +/fpmodule.inl/1.3/Wed May 2 06:22:13 2001/-ko/ +/fpopcode.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/fpopcode.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/fpsr.h/1.3/Mon Feb 14 19:32:36 2000/-ko/ +/milieu.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/single_cpdo.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/softfloat-macros/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/softfloat-specialize/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/softfloat.c/1.2/Sun Dec 17 19:15:00 2000/-ko/ +/softfloat.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/arch/arm/nwfpe/CVS/Repository linux-2.4-xfs/linux/arch/arm/nwfpe/CVS/Repository --- linux-2.4.7/linux/arch/arm/nwfpe/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/nwfpe/CVS/Repository Thu Jul 5 11:47:25 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/arm/nwfpe diff -rNu linux-2.4.7/linux/arch/arm/nwfpe/CVS/Root linux-2.4-xfs/linux/arch/arm/nwfpe/CVS/Root --- linux-2.4.7/linux/arch/arm/nwfpe/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/nwfpe/CVS/Root Thu Jul 5 11:47:25 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/arm/tools/CVS/Entries linux-2.4-xfs/linux/arch/arm/tools/CVS/Entries --- linux-2.4.7/linux/arch/arm/tools/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/tools/CVS/Entries Thu Jul 5 11:47:31 2001 @@ -0,0 +1,6 @@ +/Makefile/1.2/Thu Jun 28 05:21:16 2001/-ko/ +/constants-hdr/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/gen-mach-types/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/getconstants.c/1.3/Thu Jun 28 05:21:16 2001/-ko/ +/mach-types/1.6/Thu Jul 5 06:13:42 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/arm/tools/CVS/Repository linux-2.4-xfs/linux/arch/arm/tools/CVS/Repository --- linux-2.4.7/linux/arch/arm/tools/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/tools/CVS/Repository Thu Jul 5 11:47:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/arm/tools diff -rNu linux-2.4.7/linux/arch/arm/tools/CVS/Root linux-2.4-xfs/linux/arch/arm/tools/CVS/Root --- linux-2.4.7/linux/arch/arm/tools/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/arm/tools/CVS/Root Thu Jul 5 11:47:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/arm/vmlinux-armo.lds.in linux-2.4-xfs/linux/arch/arm/vmlinux-armo.lds.in --- linux-2.4.7/linux/arch/arm/vmlinux-armo.lds.in Mon Jul 2 16:40:14 2001 +++ linux-2.4-xfs/linux/arch/arm/vmlinux-armo.lds.in Mon Jul 2 21:33:57 2001 @@ -60,6 +60,10 @@ *(__ksymtab) __stop___ksymtab = .; + __start___kallsyms = .; /* All kernel symbols */ + *(__kallsyms) + __stop___kallsyms = .; + *(.got) /* Global offset table */ _etext = .; /* End of text section */ diff -rNu linux-2.4.7/linux/arch/arm/vmlinux-armv.lds.in linux-2.4-xfs/linux/arch/arm/vmlinux-armv.lds.in --- linux-2.4.7/linux/arch/arm/vmlinux-armv.lds.in Mon Jul 2 16:40:14 2001 +++ linux-2.4-xfs/linux/arch/arm/vmlinux-armv.lds.in Mon Jul 2 21:33:57 2001 @@ -65,6 +65,12 @@ __stop___ksymtab = .; } + __kallsyms : { /* Kernel debugging table */ + __start___kallsyms = .; /* All kernel symbols */ + *(__kallsyms) + __stop___kallsyms = .; + } + . = ALIGN(8192); .data : { diff -rNu linux-2.4.7/linux/arch/cris/CVS/Entries linux-2.4-xfs/linux/arch/cris/CVS/Entries --- linux-2.4.7/linux/arch/cris/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/CVS/Entries Thu Jul 5 11:47:32 2001 @@ -0,0 +1,6 @@ +/Makefile/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/README.mm/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/config.in/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/cris.ld/1.4/Tue Jul 3 02:33:57 2001/-ko/ +/defconfig/1.5/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/cris/CVS/Entries.Log linux-2.4-xfs/linux/arch/cris/CVS/Entries.Log --- linux-2.4.7/linux/arch/cris/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/CVS/Entries.Log Thu Jul 5 11:47:44 2001 @@ -0,0 +1,5 @@ +A D/boot//// +A D/drivers//// +A D/kernel//// +A D/lib//// +A D/mm//// diff -rNu linux-2.4.7/linux/arch/cris/CVS/Repository linux-2.4-xfs/linux/arch/cris/CVS/Repository --- linux-2.4.7/linux/arch/cris/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/CVS/Repository Thu Jul 5 11:47:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/cris diff -rNu linux-2.4.7/linux/arch/cris/CVS/Root linux-2.4-xfs/linux/arch/cris/CVS/Root --- linux-2.4.7/linux/arch/cris/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/CVS/Root Thu Jul 5 11:47:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/cris/Makefile linux-2.4-xfs/linux/arch/cris/Makefile --- linux-2.4.7/linux/arch/cris/Makefile Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/Makefile Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.19 2001/06/11 12:06:40 bjornw Exp $ +# $Id: Makefile,v 1.18 2001/04/17 13:58:38 orjanf Exp $ # cris/Makefile # # This file is included by the global makefile so that you can add your own diff -rNu linux-2.4.7/linux/arch/cris/boot/CVS/Entries linux-2.4-xfs/linux/arch/cris/boot/CVS/Entries --- linux-2.4.7/linux/arch/cris/boot/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/boot/CVS/Entries Thu Jul 5 11:47:32 2001 @@ -0,0 +1,2 @@ +/Makefile/1.1/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/cris/boot/CVS/Entries.Log linux-2.4-xfs/linux/arch/cris/boot/CVS/Entries.Log --- linux-2.4.7/linux/arch/cris/boot/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/boot/CVS/Entries.Log Thu Jul 5 11:47:32 2001 @@ -0,0 +1,3 @@ +A D/compressed//// +A D/rescue//// +A D/tools//// diff -rNu linux-2.4.7/linux/arch/cris/boot/CVS/Repository linux-2.4-xfs/linux/arch/cris/boot/CVS/Repository --- linux-2.4.7/linux/arch/cris/boot/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/boot/CVS/Repository Thu Jul 5 11:47:32 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/cris/boot diff -rNu linux-2.4.7/linux/arch/cris/boot/CVS/Root linux-2.4-xfs/linux/arch/cris/boot/CVS/Root --- linux-2.4.7/linux/arch/cris/boot/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/boot/CVS/Root Thu Jul 5 11:47:32 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/cris/boot/compressed/CVS/Entries linux-2.4-xfs/linux/arch/cris/boot/compressed/CVS/Entries --- linux-2.4.7/linux/arch/cris/boot/compressed/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/boot/compressed/CVS/Entries Thu Jul 5 11:47:32 2001 @@ -0,0 +1,6 @@ +/Makefile/1.3/Tue May 29 19:53:13 2001/-ko/ +/README/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/decompress.ld/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/head.S/1.3/Tue May 29 19:53:13 2001/-ko/ +/misc.c/1.3/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/cris/boot/compressed/CVS/Repository linux-2.4-xfs/linux/arch/cris/boot/compressed/CVS/Repository --- linux-2.4.7/linux/arch/cris/boot/compressed/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/boot/compressed/CVS/Repository Thu Jul 5 11:47:32 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/cris/boot/compressed diff -rNu linux-2.4.7/linux/arch/cris/boot/compressed/CVS/Root linux-2.4-xfs/linux/arch/cris/boot/compressed/CVS/Root --- linux-2.4.7/linux/arch/cris/boot/compressed/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/boot/compressed/CVS/Root Thu Jul 5 11:47:32 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/cris/boot/rescue/CVS/Entries linux-2.4-xfs/linux/arch/cris/boot/rescue/CVS/Entries --- linux-2.4.7/linux/arch/cris/boot/rescue/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/boot/rescue/CVS/Entries Thu Jul 5 11:47:32 2001 @@ -0,0 +1,6 @@ +/Makefile/1.1/Wed May 2 06:22:13 2001/-ko/ +/head.S/1.2/Tue May 29 19:53:13 2001/-ko/ +/kimagerescue.S/1.2/Tue May 29 19:53:13 2001/-ko/ +/rescue.ld/1.1/Wed May 2 06:22:13 2001/-ko/ +/testrescue.S/1.2/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/cris/boot/rescue/CVS/Repository linux-2.4-xfs/linux/arch/cris/boot/rescue/CVS/Repository --- linux-2.4.7/linux/arch/cris/boot/rescue/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/boot/rescue/CVS/Repository Thu Jul 5 11:47:32 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/cris/boot/rescue diff -rNu linux-2.4.7/linux/arch/cris/boot/rescue/CVS/Root linux-2.4-xfs/linux/arch/cris/boot/rescue/CVS/Root --- linux-2.4.7/linux/arch/cris/boot/rescue/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/boot/rescue/CVS/Root Thu Jul 5 11:47:32 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/cris/boot/tools/CVS/Entries linux-2.4-xfs/linux/arch/cris/boot/tools/CVS/Entries --- linux-2.4.7/linux/arch/cris/boot/tools/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/boot/tools/CVS/Entries Thu Jul 5 11:47:33 2001 @@ -0,0 +1,2 @@ +/build.c/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/cris/boot/tools/CVS/Repository linux-2.4-xfs/linux/arch/cris/boot/tools/CVS/Repository --- linux-2.4.7/linux/arch/cris/boot/tools/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/boot/tools/CVS/Repository Thu Jul 5 11:47:32 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/cris/boot/tools diff -rNu linux-2.4.7/linux/arch/cris/boot/tools/CVS/Root linux-2.4-xfs/linux/arch/cris/boot/tools/CVS/Root --- linux-2.4.7/linux/arch/cris/boot/tools/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/boot/tools/CVS/Root Thu Jul 5 11:47:32 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/cris/defconfig linux-2.4-xfs/linux/arch/cris/defconfig --- linux-2.4.7/linux/arch/cris/defconfig Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/defconfig Thu Jul 5 00:29:17 2001 @@ -511,3 +511,11 @@ # Kernel hacking # # CONFIG_PROFILE is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/cris/drivers/CVS/Entries linux-2.4-xfs/linux/arch/cris/drivers/CVS/Entries --- linux-2.4.7/linux/arch/cris/drivers/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/drivers/CVS/Entries Thu Jul 5 11:47:39 2001 @@ -0,0 +1,17 @@ +/Config.in/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/Makefile/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/axisflashmap.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/ds1302.c/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/eeprom.c/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/ethernet.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/gpio.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/i2c.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/i2c.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/ide.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/parport.c/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/serial.c/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/serial.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/sync_serial.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/usb-host.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/usb-host.h/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/cris/drivers/CVS/Entries.Log linux-2.4-xfs/linux/arch/cris/drivers/CVS/Entries.Log --- linux-2.4.7/linux/arch/cris/drivers/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/drivers/CVS/Entries.Log Thu Jul 5 11:47:39 2001 @@ -0,0 +1,2 @@ +A D/examples//// +A D/lpslave//// diff -rNu linux-2.4.7/linux/arch/cris/drivers/CVS/Repository linux-2.4-xfs/linux/arch/cris/drivers/CVS/Repository --- linux-2.4.7/linux/arch/cris/drivers/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/drivers/CVS/Repository Thu Jul 5 11:47:33 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/cris/drivers diff -rNu linux-2.4.7/linux/arch/cris/drivers/CVS/Root linux-2.4-xfs/linux/arch/cris/drivers/CVS/Root --- linux-2.4.7/linux/arch/cris/drivers/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/drivers/CVS/Root Thu Jul 5 11:47:33 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/cris/drivers/ds1302.c linux-2.4-xfs/linux/arch/cris/drivers/ds1302.c --- linux-2.4.7/linux/arch/cris/drivers/ds1302.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/drivers/ds1302.c Thu Jul 5 00:29:17 2001 @@ -82,7 +82,7 @@ *! *! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN *! -*! $Id: ds1302.c,v 1.11 2001/06/14 12:35:52 jonashg Exp $ +*! $Id: ds1302.c,v 1.3 2001/03/26 16:03:06 bjornw Exp $ *! *!***************************************************************************/ diff -rNu linux-2.4.7/linux/arch/cris/drivers/ethernet.c linux-2.4-xfs/linux/arch/cris/drivers/ethernet.c --- linux-2.4.7/linux/arch/cris/drivers/ethernet.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/drivers/ethernet.c Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: ethernet.c,v 1.17 2001/06/11 12:43:46 olof Exp $ +/* $Id: ethernet.c,v 1.12 2001/04/05 11:43:11 tobiasa Exp $ * * e100net.c: A network driver for the ETRAX 100LX network controller. * diff -rNu linux-2.4.7/linux/arch/cris/drivers/examples/CVS/Entries linux-2.4-xfs/linux/arch/cris/drivers/examples/CVS/Entries --- linux-2.4.7/linux/arch/cris/drivers/examples/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/drivers/examples/CVS/Entries Thu Jul 5 11:47:39 2001 @@ -0,0 +1,2 @@ +/kiobuftest.c/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/cris/drivers/examples/CVS/Repository linux-2.4-xfs/linux/arch/cris/drivers/examples/CVS/Repository --- linux-2.4.7/linux/arch/cris/drivers/examples/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/drivers/examples/CVS/Repository Thu Jul 5 11:47:39 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/cris/drivers/examples diff -rNu linux-2.4.7/linux/arch/cris/drivers/examples/CVS/Root linux-2.4-xfs/linux/arch/cris/drivers/examples/CVS/Root --- linux-2.4.7/linux/arch/cris/drivers/examples/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/drivers/examples/CVS/Root Thu Jul 5 11:47:39 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/cris/drivers/gpio.c linux-2.4-xfs/linux/arch/cris/drivers/gpio.c --- linux-2.4.7/linux/arch/cris/drivers/gpio.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/drivers/gpio.c Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: gpio.c,v 1.9 2001/05/04 14:16:07 matsfg Exp $ +/* $Id: gpio.c,v 1.7 2001/04/04 13:30:08 matsfg Exp $ * * Etrax general port I/O device * diff -rNu linux-2.4.7/linux/arch/cris/drivers/ide.c linux-2.4-xfs/linux/arch/cris/drivers/ide.c --- linux-2.4.7/linux/arch/cris/drivers/ide.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/drivers/ide.c Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: ide.c,v 1.19 2001/05/09 12:53:16 johana Exp $ +/* $Id: ide.c,v 1.16 2001/04/05 08:30:07 matsfg Exp $ * * Etrax specific IDE functions, like init and PIO-mode setting etc. * Almost the entire ide.c is used for the rest of the Etrax ATA driver. diff -rNu linux-2.4.7/linux/arch/cris/drivers/lpslave/CVS/Entries linux-2.4-xfs/linux/arch/cris/drivers/lpslave/CVS/Entries --- linux-2.4.7/linux/arch/cris/drivers/lpslave/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/drivers/lpslave/CVS/Entries Thu Jul 5 11:47:39 2001 @@ -0,0 +1,8 @@ +/Makefile/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/bintocarr.pl/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/e100lpslave.README/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/e100lpslave.S/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/e100lpslave.h/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/e100lpslaveld/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/e100lpslavenet.c/1.1/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/cris/drivers/lpslave/CVS/Repository linux-2.4-xfs/linux/arch/cris/drivers/lpslave/CVS/Repository --- linux-2.4.7/linux/arch/cris/drivers/lpslave/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/drivers/lpslave/CVS/Repository Thu Jul 5 11:47:39 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/cris/drivers/lpslave diff -rNu linux-2.4.7/linux/arch/cris/drivers/lpslave/CVS/Root linux-2.4-xfs/linux/arch/cris/drivers/lpslave/CVS/Root --- linux-2.4.7/linux/arch/cris/drivers/lpslave/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/drivers/lpslave/CVS/Root Thu Jul 5 11:47:39 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/cris/drivers/lpslave/bintocarr.pl linux-2.4-xfs/linux/arch/cris/drivers/lpslave/bintocarr.pl --- linux-2.4.7/linux/arch/cris/drivers/lpslave/bintocarr.pl Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/drivers/lpslave/bintocarr.pl Thu Jul 5 00:29:17 2001 @@ -1,5 +1,5 @@ #!/usr/bin/perl -w -# $Id: bintocarr.pl,v 1.3 2001/06/08 08:46:50 olof Exp $ +# $Id$ # Copy of mkjulbin.pl made by Olof # convert a binary stdin to a C-file containing a char array of the input # first argument is the symbol name diff -rNu linux-2.4.7/linux/arch/cris/drivers/lpslave/e100lpslave.S linux-2.4-xfs/linux/arch/cris/drivers/lpslave/e100lpslave.S --- linux-2.4.7/linux/arch/cris/drivers/lpslave/e100lpslave.S Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/drivers/lpslave/e100lpslave.S Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ - ;; $Id: e100lpslave.S,v 1.2 2001/06/11 12:50:01 olof Exp $ + ;; $Id$ ;; ;; Etrax100 slave network<->parport forwarder ;; diff -rNu linux-2.4.7/linux/arch/cris/drivers/lpslave/e100lpslavenet.c linux-2.4-xfs/linux/arch/cris/drivers/lpslave/e100lpslavenet.c --- linux-2.4.7/linux/arch/cris/drivers/lpslave/e100lpslavenet.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/drivers/lpslave/e100lpslavenet.c Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: e100lpslavenet.c,v 1.2 2001/06/11 15:39:52 olof Exp $ +/* $Id$ * * e100lpslavenet.c: A network driver for the ETRAX 100LX slave controller. * diff -rNu linux-2.4.7/linux/arch/cris/drivers/parport.c linux-2.4-xfs/linux/arch/cris/drivers/parport.c --- linux-2.4.7/linux/arch/cris/drivers/parport.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/drivers/parport.c Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: parport.c,v 1.5 2001/05/09 12:38:42 johana Exp $ +/* $Id: parport.c,v 1.4 2001/04/06 13:04:02 hugo Exp $ * * Elinux parallel port driver * NOTE! diff -rNu linux-2.4.7/linux/arch/cris/drivers/serial.c linux-2.4-xfs/linux/arch/cris/drivers/serial.c --- linux-2.4.7/linux/arch/cris/drivers/serial.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/drivers/serial.c Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: serial.c,v 1.13 2001/05/09 12:40:31 johana Exp $ +/* $Id: serial.c,v 1.12 2001/04/19 12:23:07 bjornw Exp $ * * Serial port driver for the ETRAX 100LX chip * @@ -202,7 +202,7 @@ * */ -static char *serial_version = "$Revision: 1.13 $"; +static char *serial_version = "$Revision: 1.12 $"; #include #include diff -rNu linux-2.4.7/linux/arch/cris/drivers/usb-host.c linux-2.4-xfs/linux/arch/cris/drivers/usb-host.c --- linux-2.4.7/linux/arch/cris/drivers/usb-host.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/drivers/usb-host.c Thu Jul 5 00:29:17 2001 @@ -3,7 +3,7 @@ * * Copyright (c) 2001 Axis Communications AB. * - * $Id: usb-host.c,v 1.9 2001/05/09 12:54:12 johana Exp $ + * $Id: usb-host.c,v 1.8 2001/02/27 13:52:48 bjornw Exp $ * */ @@ -34,7 +34,7 @@ #define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR #define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBR -static const char *usb_hcd_version = "$Revision: 1.9 $"; +static const char *usb_hcd_version = "$Revision: 1.8 $"; #undef KERN_DEBUG #define KERN_DEBUG "" diff -rNu linux-2.4.7/linux/arch/cris/kernel/CVS/Entries linux-2.4-xfs/linux/arch/cris/kernel/CVS/Entries --- linux-2.4.7/linux/arch/cris/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/kernel/CVS/Entries Thu Jul 5 11:47:43 2001 @@ -0,0 +1,19 @@ +/Makefile/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/debugport.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/entry.S/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/entryoffsets.c/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/head.S/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/hexify.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/irq.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/kgdb.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/ksyms.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/process.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/ptrace.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/semaphore.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/shadows.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/signal.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/sys_cris.c/1.4/Tue May 29 19:53:13 2001/-ko/ +/time.c/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/traps.c/1.3/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/cris/kernel/CVS/Repository linux-2.4-xfs/linux/arch/cris/kernel/CVS/Repository --- linux-2.4.7/linux/arch/cris/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/kernel/CVS/Repository Thu Jul 5 11:47:39 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/cris/kernel diff -rNu linux-2.4.7/linux/arch/cris/kernel/CVS/Root linux-2.4-xfs/linux/arch/cris/kernel/CVS/Root --- linux-2.4.7/linux/arch/cris/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/kernel/CVS/Root Thu Jul 5 11:47:39 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/cris/kernel/Makefile linux-2.4-xfs/linux/arch/cris/kernel/Makefile --- linux-2.4.7/linux/arch/cris/kernel/Makefile Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/kernel/Makefile Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.5 2001/05/15 05:10:00 hp Exp $ +# $Id: Makefile,v 1.4 2001/04/17 13:58:39 orjanf Exp $ # # Makefile for the linux kernel. # diff -rNu linux-2.4.7/linux/arch/cris/kernel/entry.S linux-2.4-xfs/linux/arch/cris/kernel/entry.S --- linux-2.4.7/linux/arch/cris/kernel/entry.S Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/kernel/entry.S Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.27 2001/05/29 11:25:27 markusl Exp $ +/* $Id: entry.S,v 1.22 2001/04/17 13:58:39 orjanf Exp $ * * linux/arch/cris/entry.S * diff -rNu linux-2.4.7/linux/arch/cris/kernel/head.S linux-2.4-xfs/linux/arch/cris/kernel/head.S --- linux-2.4.7/linux/arch/cris/kernel/head.S Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/kernel/head.S Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.34 2001/05/15 07:08:14 hp Exp $ +/* $Id: head.S,v 1.29 2001/04/18 12:51:59 orjanf Exp $ * * Head of the kernel - alter with care * diff -rNu linux-2.4.7/linux/arch/cris/kernel/irq.c linux-2.4-xfs/linux/arch/cris/kernel/irq.c --- linux-2.4.7/linux/arch/cris/kernel/irq.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/kernel/irq.c Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.15 2001/06/10 11:18:46 bjornw Exp $ +/* $Id: irq.c,v 1.14 2001/04/17 13:58:39 orjanf Exp $ * * linux/arch/cris/kernel/irq.c * diff -rNu linux-2.4.7/linux/arch/cris/kernel/process.c linux-2.4-xfs/linux/arch/cris/kernel/process.c --- linux-2.4.7/linux/arch/cris/kernel/process.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/kernel/process.c Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.14 2001/05/29 11:27:59 markusl Exp $ +/* $Id: process.c,v 1.13 2001/03/20 19:44:06 bjornw Exp $ * * linux/arch/cris/kernel/process.c * diff -rNu linux-2.4.7/linux/arch/cris/kernel/setup.c linux-2.4-xfs/linux/arch/cris/kernel/setup.c --- linux-2.4.7/linux/arch/cris/kernel/setup.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/kernel/setup.c Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.16 2001/05/15 01:23:13 hp Exp $ +/* $Id: setup.c,v 1.14 2001/04/03 12:54:12 starvik Exp $ * * linux/arch/cris/kernel/setup.c * diff -rNu linux-2.4.7/linux/arch/cris/kernel/sys_cris.c linux-2.4-xfs/linux/arch/cris/kernel/sys_cris.c --- linux-2.4.7/linux/arch/cris/kernel/sys_cris.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/kernel/sys_cris.c Tue May 29 14:53:13 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_cris.c,v 1.9 2001/05/30 06:20:26 markusl Exp $ +/* $Id: sys_cris.c,v 1.7 2001/04/17 11:52:15 orjanf Exp $ * * linux/arch/cris/kernel/sys_cris.c * diff -rNu linux-2.4.7/linux/arch/cris/kernel/time.c linux-2.4-xfs/linux/arch/cris/kernel/time.c --- linux-2.4.7/linux/arch/cris/kernel/time.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/kernel/time.c Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.6 2001/05/29 11:29:42 markusl Exp $ +/* $Id: time.c,v 1.4 2000/10/17 14:44:58 bjornw Exp $ * * linux/arch/cris/kernel/time.c * diff -rNu linux-2.4.7/linux/arch/cris/kernel/traps.c linux-2.4-xfs/linux/arch/cris/kernel/traps.c --- linux-2.4.7/linux/arch/cris/kernel/traps.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/kernel/traps.c Tue May 29 14:53:13 2001 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.12 2001/05/15 15:46:40 bjornw Exp $ +/* $Id: traps.c,v 1.11 2001/04/04 09:43:31 orjanf Exp $ * * linux/arch/cris/traps.c * diff -rNu linux-2.4.7/linux/arch/cris/lib/CVS/Entries linux-2.4-xfs/linux/arch/cris/lib/CVS/Entries --- linux-2.4.7/linux/arch/cris/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/lib/CVS/Entries Thu Jul 5 11:47:44 2001 @@ -0,0 +1,11 @@ +/Makefile/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/checksum.S/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/checksumcopy.S/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/dmacopy.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/dram_init.S/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/hw_settings.S/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/memset.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/old_checksum.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/string.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/usercopy.c/1.2/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/cris/lib/CVS/Repository linux-2.4-xfs/linux/arch/cris/lib/CVS/Repository --- linux-2.4.7/linux/arch/cris/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/lib/CVS/Repository Thu Jul 5 11:47:43 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/cris/lib diff -rNu linux-2.4.7/linux/arch/cris/lib/CVS/Root linux-2.4-xfs/linux/arch/cris/lib/CVS/Root --- linux-2.4.7/linux/arch/cris/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/lib/CVS/Root Thu Jul 5 11:47:43 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/cris/lib/checksum.S linux-2.4-xfs/linux/arch/cris/lib/checksum.S --- linux-2.4.7/linux/arch/cris/lib/checksum.S Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/lib/checksum.S Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: checksum.S,v 1.5 2001/05/29 11:40:14 markusl Exp $ +/* $Id: checksum.S,v 1.4 2001/02/19 11:11:33 bjornw Exp $ * A fast checksum routine using movem * Copyright (c) 1998-2001 Axis Communications AB * diff -rNu linux-2.4.7/linux/arch/cris/lib/checksumcopy.S linux-2.4-xfs/linux/arch/cris/lib/checksumcopy.S --- linux-2.4.7/linux/arch/cris/lib/checksumcopy.S Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/lib/checksumcopy.S Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: checksumcopy.S,v 1.5 2001/05/29 11:40:14 markusl Exp $ +/* $Id: checksumcopy.S,v 1.4 2001/02/19 11:11:34 bjornw Exp $ * A fast checksum+copy routine using movem * Copyright (c) 1998, 2001 Axis Communications AB * diff -rNu linux-2.4.7/linux/arch/cris/lib/dram_init.S linux-2.4-xfs/linux/arch/cris/lib/dram_init.S --- linux-2.4.7/linux/arch/cris/lib/dram_init.S Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/cris/lib/dram_init.S Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: dram_init.S,v 1.8 2001/05/15 07:12:45 hp Exp $ +/* $Id: dram_init.S,v 1.7 2001/04/18 12:05:39 bjornw Exp $ * * DRAM/SDRAM initialization - alter with care * This file is intended to be included from other assembler files diff -rNu linux-2.4.7/linux/arch/cris/mm/CVS/Entries linux-2.4-xfs/linux/arch/cris/mm/CVS/Entries --- linux-2.4.7/linux/arch/cris/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/mm/CVS/Entries Thu Jul 5 11:47:46 2001 @@ -0,0 +1,7 @@ +/Makefile/1.2/Wed May 2 06:22:13 2001/-ko/ +/extable.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fault.c/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/init.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/ioremap.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/tlb.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/cris/mm/CVS/Repository linux-2.4-xfs/linux/arch/cris/mm/CVS/Repository --- linux-2.4.7/linux/arch/cris/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/mm/CVS/Repository Thu Jul 5 11:47:44 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/cris/mm diff -rNu linux-2.4.7/linux/arch/cris/mm/CVS/Root linux-2.4-xfs/linux/arch/cris/mm/CVS/Root --- linux-2.4.7/linux/arch/cris/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/cris/mm/CVS/Root Thu Jul 5 11:47:44 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/i386/CVS/Entries linux-2.4-xfs/linux/arch/i386/CVS/Entries --- linux-2.4.7/linux/arch/i386/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/CVS/Entries Thu Jul 5 11:47:46 2001 @@ -0,0 +1,5 @@ +/Makefile/1.22/Wed May 2 06:22:13 2001/-ko/ +/config.in/1.58/Thu Jun 21 15:45:04 2001/-ko/ +/defconfig/1.60/Tue Jul 3 02:33:57 2001/-ko/ +/vmlinux.lds/1.13/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/i386/CVS/Entries.Log linux-2.4-xfs/linux/arch/i386/CVS/Entries.Log --- linux-2.4.7/linux/arch/i386/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/CVS/Entries.Log Thu Jul 5 11:48:09 2001 @@ -0,0 +1,6 @@ +A D/boot//// +A D/kdb//// +A D/kernel//// +A D/lib//// +A D/math-emu//// +A D/mm//// diff -rNu linux-2.4.7/linux/arch/i386/CVS/Repository linux-2.4-xfs/linux/arch/i386/CVS/Repository --- linux-2.4.7/linux/arch/i386/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/CVS/Repository Thu Jul 5 11:47:46 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/i386 diff -rNu linux-2.4.7/linux/arch/i386/CVS/Root linux-2.4-xfs/linux/arch/i386/CVS/Root --- linux-2.4.7/linux/arch/i386/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/CVS/Root Thu Jul 5 11:47:46 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/i386/Makefile linux-2.4-xfs/linux/arch/i386/Makefile --- linux-2.4.7/linux/arch/i386/Makefile Thu Apr 12 14:20:31 2001 +++ linux-2.4-xfs/linux/arch/i386/Makefile Wed May 2 01:22:13 2001 @@ -93,6 +93,11 @@ CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES) LIBS := $(TOPDIR)/arch/i386/lib/lib.a $(LIBS) $(TOPDIR)/arch/i386/lib/lib.a +ifdef CONFIG_KDB +LIBS := $(LIBS) $(TOPDIR)/arch/i386/kdb/kdba.o +SUBDIRS := $(SUBDIRS) arch/i386/kdb +endif + ifdef CONFIG_MATH_EMULATION SUBDIRS += arch/i386/math-emu DRIVERS += arch/i386/math-emu/math.o @@ -103,6 +108,11 @@ arch/i386/mm: dummy $(MAKE) linuxsubdirs SUBDIRS=arch/i386/mm + +ifdef CONFIG_KDB +arch/i386/kdb: dummy + $(MAKE) linuxsubdirs SUBDIRS=arch/i386/kdb +endif MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot diff -rNu linux-2.4.7/linux/arch/i386/boot/CVS/Entries linux-2.4-xfs/linux/arch/i386/boot/CVS/Entries --- linux-2.4.7/linux/arch/i386/boot/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/boot/CVS/Entries Thu Jul 5 11:47:48 2001 @@ -0,0 +1,6 @@ +/Makefile/1.9/Tue Mar 27 00:28:12 2001/-ko/ +/bootsect.S/1.12/Thu Feb 1 17:10:24 2001/-ko/ +/install.sh/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/setup.S/1.20/Tue May 29 19:53:13 2001/-ko/ +/video.S/1.6/Wed Nov 24 20:20:05 1999/-ko/ +D diff -rNu linux-2.4.7/linux/arch/i386/boot/CVS/Entries.Log linux-2.4-xfs/linux/arch/i386/boot/CVS/Entries.Log --- linux-2.4.7/linux/arch/i386/boot/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/boot/CVS/Entries.Log Thu Jul 5 11:47:48 2001 @@ -0,0 +1,2 @@ +A D/compressed//// +A D/tools//// diff -rNu linux-2.4.7/linux/arch/i386/boot/CVS/Repository linux-2.4-xfs/linux/arch/i386/boot/CVS/Repository --- linux-2.4.7/linux/arch/i386/boot/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/boot/CVS/Repository Thu Jul 5 11:47:46 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/i386/boot diff -rNu linux-2.4.7/linux/arch/i386/boot/CVS/Root linux-2.4-xfs/linux/arch/i386/boot/CVS/Root --- linux-2.4.7/linux/arch/i386/boot/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/boot/CVS/Root Thu Jul 5 11:47:46 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/i386/boot/compressed/CVS/Entries linux-2.4-xfs/linux/arch/i386/boot/compressed/CVS/Entries --- linux-2.4.7/linux/arch/i386/boot/compressed/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/boot/compressed/CVS/Entries Thu Jul 5 11:47:48 2001 @@ -0,0 +1,4 @@ +/Makefile/1.6/Wed Mar 8 01:44:14 2000/-ko/ +/head.S/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/misc.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/i386/boot/compressed/CVS/Repository linux-2.4-xfs/linux/arch/i386/boot/compressed/CVS/Repository --- linux-2.4.7/linux/arch/i386/boot/compressed/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/boot/compressed/CVS/Repository Thu Jul 5 11:47:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/i386/boot/compressed diff -rNu linux-2.4.7/linux/arch/i386/boot/compressed/CVS/Root linux-2.4-xfs/linux/arch/i386/boot/compressed/CVS/Root --- linux-2.4.7/linux/arch/i386/boot/compressed/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/boot/compressed/CVS/Root Thu Jul 5 11:47:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/i386/boot/tools/CVS/Entries linux-2.4-xfs/linux/arch/i386/boot/tools/CVS/Entries --- linux-2.4.7/linux/arch/i386/boot/tools/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/boot/tools/CVS/Entries Thu Jul 5 11:47:48 2001 @@ -0,0 +1,2 @@ +/build.c/1.5/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/i386/boot/tools/CVS/Repository linux-2.4-xfs/linux/arch/i386/boot/tools/CVS/Repository --- linux-2.4.7/linux/arch/i386/boot/tools/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/boot/tools/CVS/Repository Thu Jul 5 11:47:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/i386/boot/tools diff -rNu linux-2.4.7/linux/arch/i386/boot/tools/CVS/Root linux-2.4-xfs/linux/arch/i386/boot/tools/CVS/Root --- linux-2.4.7/linux/arch/i386/boot/tools/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/boot/tools/CVS/Root Thu Jul 5 11:47:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/i386/config.in linux-2.4-xfs/linux/arch/i386/config.in --- linux-2.4.7/linux/arch/i386/config.in Wed Jun 20 19:47:39 2001 +++ linux-2.4-xfs/linux/arch/i386/config.in Thu Jun 21 10:45:04 2001 @@ -174,6 +174,7 @@ if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then define_bool CONFIG_X86_IO_APIC y define_bool CONFIG_X86_LOCAL_APIC y + bool ' NMI watchdog active for uniprocessors' CONFIG_UP_NMI_WATCHDOG fi fi @@ -388,4 +389,13 @@ #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +bool 'Built-in Kernel Debugger support' CONFIG_KDB +if [ "$CONFIG_KDB" = "y" ]; then + bool ' KDB off by default' CONFIG_KDB_OFF + comment 'Load all symbols for debugging is required for KDB' + define_bool CONFIG_KALLSYMS y +else + bool 'Load all symbols for debugging' CONFIG_KALLSYMS +fi +bool 'Compile the kernel with frame pointers' CONFIG_FRAME_POINTER endmenu diff -rNu linux-2.4.7/linux/arch/i386/defconfig linux-2.4-xfs/linux/arch/i386/defconfig --- linux-2.4.7/linux/arch/i386/defconfig Mon Jul 2 18:08:28 2001 +++ linux-2.4-xfs/linux/arch/i386/defconfig Mon Jul 2 21:33:57 2001 @@ -747,3 +747,15 @@ # Kernel hacking # # CONFIG_MAGIC_SYSRQ is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y + +CONFIG_KDB=y +CONFIG_KDB_OFF=n +CONFIG_FRAME_POINTER=n diff -rNu linux-2.4.7/linux/arch/i386/kdb/CVS/Entries linux-2.4-xfs/linux/arch/i386/kdb/CVS/Entries --- linux-2.4.7/linux/arch/i386/kdb/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/kdb/CVS/Entries Thu Jul 5 11:47:51 2001 @@ -0,0 +1,8 @@ +/Makefile/1.8/Thu Dec 21 05:48:12 2000/-ko/ +/i386-dis.c/1.7/Sat Nov 25 17:31:48 2000/-ko/ +/kdba_bp.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/kdba_bt.c/1.10/Sat Nov 25 17:31:48 2000/-ko/ +/kdba_id.c/1.8/Tue Dec 12 04:44:55 2000/-ko/ +/kdba_io.c/1.12/Mon Apr 2 17:13:32 2001/-ko/ +/kdbasupport.c/1.15/Sun May 27 04:02:58 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/i386/kdb/CVS/Repository linux-2.4-xfs/linux/arch/i386/kdb/CVS/Repository --- linux-2.4.7/linux/arch/i386/kdb/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/kdb/CVS/Repository Thu Jul 5 11:47:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/i386/kdb diff -rNu linux-2.4.7/linux/arch/i386/kdb/CVS/Root linux-2.4-xfs/linux/arch/i386/kdb/CVS/Root --- linux-2.4.7/linux/arch/i386/kdb/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/kdb/CVS/Root Thu Jul 5 11:47:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/i386/kdb/Makefile linux-2.4-xfs/linux/arch/i386/kdb/Makefile --- linux-2.4.7/linux/arch/i386/kdb/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/kdb/Makefile Wed Dec 20 23:48:12 2000 @@ -0,0 +1,6 @@ +O_TARGET := kdba.o +obj-y := kdba_bt.o kdba_bp.o kdba_id.o kdba_io.o kdbasupport.o i386-dis.o + +override CFLAGS := $(CFLAGS:%-pg=% ) + +include $(TOPDIR)/Rules.make diff -rNu linux-2.4.7/linux/arch/i386/kdb/i386-dis.c linux-2.4-xfs/linux/arch/i386/kdb/i386-dis.c --- linux-2.4.7/linux/arch/i386/kdb/i386-dis.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/kdb/i386-dis.c Sat Nov 25 11:31:48 2000 @@ -0,0 +1,3781 @@ +/* Print i386 instructions for GDB, the GNU debugger. + Copyright (C) 1988, 89, 91, 93, 94, 95, 96, 97, 98, 1999 + Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) + * July 1988 + * modified by John Hassey (hassey@dg-rtp.dg.com) + */ + +/* Extracted from cygnus CVS and modified for kdb use. + * Keith Owens 30 Oct 2000 + */ + +/* + * The main tables describing the instructions is essentially a copy + * of the "Opcode Map" chapter (Appendix A) of the Intel 80386 + * Programmers Manual. Usually, there is a capital letter, followed + * by a small letter. The capital letter tell the addressing mode, + * and the small letter tells about the operand size. Refer to + * the Intel manual for details. + */ + +#ifdef __KERNEL__ +#include +#include +#include +#include +#else +#include "dis-asm.h" +#include "sysdep.h" +#include "opintl.h" +#endif + +#define MAXLEN 20 + +#ifndef __KERNEL__ +#include +#endif + +#ifndef UNIXWARE_COMPAT +/* Set non-zero for broken, compatible instructions. Set to zero for + non-broken opcodes. */ +#define UNIXWARE_COMPAT 1 +#endif + +static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *)); + +struct dis_private +{ + /* Points to first byte not fetched. */ + bfd_byte *max_fetched; + bfd_byte the_buffer[MAXLEN]; + bfd_vma insn_start; +#ifndef __KERNEL__ + jmp_buf bailout; +#endif +}; + +/* The opcode for the fwait instruction, which we treat as a prefix + when we can. */ +#define FWAIT_OPCODE (0x9b) + +/* Flags for the prefixes for the current instruction. See below. */ +static int prefixes; + +/* Flags for prefixes which we somehow handled when printing the + current instruction. */ +static int used_prefixes; + +/* Flags stored in PREFIXES. */ +#define PREFIX_REPZ 1 +#define PREFIX_REPNZ 2 +#define PREFIX_LOCK 4 +#define PREFIX_CS 8 +#define PREFIX_SS 0x10 +#define PREFIX_DS 0x20 +#define PREFIX_ES 0x40 +#define PREFIX_FS 0x80 +#define PREFIX_GS 0x100 +#define PREFIX_DATA 0x200 +#define PREFIX_ADDR 0x400 +#define PREFIX_FWAIT 0x800 + +/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) + to ADDR (exclusive) are valid. Returns 1 for success, longjmps + on error. */ +#define FETCH_DATA(info, addr) \ + ((addr) <= ((struct dis_private *)(info->private_data))->max_fetched \ + ? 1 : fetch_data ((info), (addr))) + +static int +fetch_data (info, addr) + struct disassemble_info *info; + bfd_byte *addr; +{ + int status; + struct dis_private *priv = (struct dis_private *)info->private_data; + bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); + + status = (*info->read_memory_func) (start, + priv->max_fetched, + addr - priv->max_fetched, + info); + if (status != 0) + { + /* If we did manage to read at least one byte, then + print_insn_i386 will do something sensible. Otherwise, print + an error. We do that here because this is where we know + STATUS. */ + if (priv->max_fetched == priv->the_buffer) + (*info->memory_error_func) (status, start, info); +#ifndef __KERNEL__ + longjmp (priv->bailout, 1); +#else + /* XXX - what to do? */ + kdb_printf("Hmm. longjmp.\n"); +#endif + } + else + priv->max_fetched = addr; + return 1; +} + +#define XX NULL, 0 + +#define Eb OP_E, b_mode +#define indirEb OP_indirE, b_mode +#define Gb OP_G, b_mode +#define Ev OP_E, v_mode +#define Ed OP_E, d_mode +#define indirEv OP_indirE, v_mode +#define Ew OP_E, w_mode +#define Ma OP_E, v_mode +#define M OP_E, 0 /* lea */ +#define Mp OP_E, 0 /* 32 or 48 bit memory operand for LDS, LES etc */ +#define Gv OP_G, v_mode +#define Gw OP_G, w_mode +#define Rd OP_Rd, d_mode +#define Ib OP_I, b_mode +#define sIb OP_sI, b_mode /* sign extened byte */ +#define Iv OP_I, v_mode +#define Iw OP_I, w_mode +#define Jb OP_J, b_mode +#define Jv OP_J, v_mode +#define Cd OP_C, d_mode +#define Dd OP_D, d_mode +#define Td OP_T, d_mode + +#define eAX OP_REG, eAX_reg +#define eBX OP_REG, eBX_reg +#define eCX OP_REG, eCX_reg +#define eDX OP_REG, eDX_reg +#define eSP OP_REG, eSP_reg +#define eBP OP_REG, eBP_reg +#define eSI OP_REG, eSI_reg +#define eDI OP_REG, eDI_reg +#define AL OP_REG, al_reg +#define CL OP_REG, cl_reg +#define DL OP_REG, dl_reg +#define BL OP_REG, bl_reg +#define AH OP_REG, ah_reg +#define CH OP_REG, ch_reg +#define DH OP_REG, dh_reg +#define BH OP_REG, bh_reg +#define AX OP_REG, ax_reg +#define DX OP_REG, dx_reg +#define indirDX OP_REG, indir_dx_reg + +#define Sw OP_SEG, w_mode +#define Ap OP_DIR, 0 +#define Ob OP_OFF, b_mode +#define Ov OP_OFF, v_mode +#define Xb OP_DSreg, eSI_reg +#define Xv OP_DSreg, eSI_reg +#define Yb OP_ESreg, eDI_reg +#define Yv OP_ESreg, eDI_reg +#define DSBX OP_DSreg, eBX_reg + +#define es OP_REG, es_reg +#define ss OP_REG, ss_reg +#define cs OP_REG, cs_reg +#define ds OP_REG, ds_reg +#define fs OP_REG, fs_reg +#define gs OP_REG, gs_reg + +#define MX OP_MMX, 0 +#define XM OP_XMM, 0 +#define EM OP_EM, v_mode +#define EX OP_EX, v_mode +#define MS OP_MS, v_mode +#define None OP_E, 0 +#define OPSUF OP_3DNowSuffix, 0 +#define OPSIMD OP_SIMD_Suffix, 0 + +/* bits in sizeflag */ +#if 0 /* leave undefined until someone adds the extra flag to objdump */ +#define SUFFIX_ALWAYS 4 +#endif +#define AFLAG 2 +#define DFLAG 1 + +typedef void (*op_rtn) PARAMS ((int bytemode, int sizeflag)); + +static void OP_E PARAMS ((int, int)); +static void OP_G PARAMS ((int, int)); +static void OP_I PARAMS ((int, int)); +static void OP_indirE PARAMS ((int, int)); +static void OP_sI PARAMS ((int, int)); +static void OP_REG PARAMS ((int, int)); +static void OP_J PARAMS ((int, int)); +static void OP_DIR PARAMS ((int, int)); +static void OP_OFF PARAMS ((int, int)); +static void OP_ESreg PARAMS ((int, int)); +static void OP_DSreg PARAMS ((int, int)); +static void OP_SEG PARAMS ((int, int)); +static void OP_C PARAMS ((int, int)); +static void OP_D PARAMS ((int, int)); +static void OP_T PARAMS ((int, int)); +static void OP_Rd PARAMS ((int, int)); +static void OP_ST PARAMS ((int, int)); +static void OP_STi PARAMS ((int, int)); +static void OP_MMX PARAMS ((int, int)); +static void OP_XMM PARAMS ((int, int)); +static void OP_EM PARAMS ((int, int)); +static void OP_EX PARAMS ((int, int)); +static void OP_MS PARAMS ((int, int)); +static void OP_3DNowSuffix PARAMS ((int, int)); +static void OP_SIMD_Suffix PARAMS ((int, int)); +static void SIMD_Fixup PARAMS ((int, int)); + +static void append_seg PARAMS ((void)); +static void set_op PARAMS ((unsigned int op)); +static void putop PARAMS ((const char *template, int sizeflag)); +static void dofloat PARAMS ((int sizeflag)); +static int get16 PARAMS ((void)); +static int get32 PARAMS ((void)); +static void ckprefix PARAMS ((void)); +static const char *prefix_name PARAMS ((int, int)); +static void ptr_reg PARAMS ((int, int)); +static void BadOp PARAMS ((void)); + +#define b_mode 1 +#define v_mode 2 +#define w_mode 3 +#define d_mode 4 +#define x_mode 5 + +#define es_reg 100 +#define cs_reg 101 +#define ss_reg 102 +#define ds_reg 103 +#define fs_reg 104 +#define gs_reg 105 + +#define eAX_reg 108 +#define eCX_reg 109 +#define eDX_reg 110 +#define eBX_reg 111 +#define eSP_reg 112 +#define eBP_reg 113 +#define eSI_reg 114 +#define eDI_reg 115 + +#define al_reg 116 +#define cl_reg 117 +#define dl_reg 118 +#define bl_reg 119 +#define ah_reg 120 +#define ch_reg 121 +#define dh_reg 122 +#define bh_reg 123 + +#define ax_reg 124 +#define cx_reg 125 +#define dx_reg 126 +#define bx_reg 127 +#define sp_reg 128 +#define bp_reg 129 +#define si_reg 130 +#define di_reg 131 + +#define indir_dx_reg 150 + +#define USE_GROUPS 1 +#define USE_PREFIX_USER_TABLE 2 + +#define GRP1b NULL, NULL, 0, NULL, USE_GROUPS, NULL, 0 +#define GRP1S NULL, NULL, 1, NULL, USE_GROUPS, NULL, 0 +#define GRP1Ss NULL, NULL, 2, NULL, USE_GROUPS, NULL, 0 +#define GRP2b NULL, NULL, 3, NULL, USE_GROUPS, NULL, 0 +#define GRP2S NULL, NULL, 4, NULL, USE_GROUPS, NULL, 0 +#define GRP2b_one NULL, NULL, 5, NULL, USE_GROUPS, NULL, 0 +#define GRP2S_one NULL, NULL, 6, NULL, USE_GROUPS, NULL, 0 +#define GRP2b_cl NULL, NULL, 7, NULL, USE_GROUPS, NULL, 0 +#define GRP2S_cl NULL, NULL, 8, NULL, USE_GROUPS, NULL, 0 +#define GRP3b NULL, NULL, 9, NULL, USE_GROUPS, NULL, 0 +#define GRP3S NULL, NULL, 10, NULL, USE_GROUPS, NULL, 0 +#define GRP4 NULL, NULL, 11, NULL, USE_GROUPS, NULL, 0 +#define GRP5 NULL, NULL, 12, NULL, USE_GROUPS, NULL, 0 +#define GRP6 NULL, NULL, 13, NULL, USE_GROUPS, NULL, 0 +#define GRP7 NULL, NULL, 14, NULL, USE_GROUPS, NULL, 0 +#define GRP8 NULL, NULL, 15, NULL, USE_GROUPS, NULL, 0 +#define GRP9 NULL, NULL, 16, NULL, USE_GROUPS, NULL, 0 +#define GRP10 NULL, NULL, 17, NULL, USE_GROUPS, NULL, 0 +#define GRP11 NULL, NULL, 18, NULL, USE_GROUPS, NULL, 0 +#define GRP12 NULL, NULL, 19, NULL, USE_GROUPS, NULL, 0 +#define GRP13 NULL, NULL, 20, NULL, USE_GROUPS, NULL, 0 +#define GRP14 NULL, NULL, 21, NULL, USE_GROUPS, NULL, 0 +#define GRPAMD NULL, NULL, 22, NULL, USE_GROUPS, NULL, 0 + +#define PREGRP0 NULL, NULL, 0, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP1 NULL, NULL, 1, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP2 NULL, NULL, 2, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP3 NULL, NULL, 3, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP4 NULL, NULL, 4, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP5 NULL, NULL, 5, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP6 NULL, NULL, 6, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP7 NULL, NULL, 7, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP8 NULL, NULL, 8, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP9 NULL, NULL, 9, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP10 NULL, NULL, 10, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP11 NULL, NULL, 11, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP12 NULL, NULL, 12, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP13 NULL, NULL, 13, NULL, USE_PREFIX_USER_TABLE, NULL, 0 +#define PREGRP14 NULL, NULL, 14, NULL, USE_PREFIX_USER_TABLE, NULL, 0 + +#define FLOATCODE 50 +#define FLOAT NULL, NULL, FLOATCODE, NULL, 0, NULL, 0 + +struct dis386 { + const char *name; + op_rtn op1; + int bytemode1; + op_rtn op2; + int bytemode2; + op_rtn op3; + int bytemode3; +}; + +/* Upper case letters in the instruction names here are macros. + 'A' => print 'b' if no register operands or suffix_always is true + 'B' => print 'b' if suffix_always is true + 'E' => print 'e' if 32-bit form of jcxz + 'L' => print 'l' if suffix_always is true + 'N' => print 'n' if instruction has no wait "prefix" + 'P' => print 'w' or 'l' if instruction has an operand size prefix, + or suffix_always is true + 'Q' => print 'w' or 'l' if no register operands or suffix_always is true + 'R' => print 'w' or 'l' ("wd" or "dq" in intel mode) + 'S' => print 'w' or 'l' if suffix_always is true + 'W' => print 'b' or 'w' ("w" or "de" in intel mode) +*/ + +static const struct dis386 dis386_att[] = { + /* 00 */ + { "addB", Eb, Gb, XX }, + { "addS", Ev, Gv, XX }, + { "addB", Gb, Eb, XX }, + { "addS", Gv, Ev, XX }, + { "addB", AL, Ib, XX }, + { "addS", eAX, Iv, XX }, + { "pushP", es, XX, XX }, + { "popP", es, XX, XX }, + /* 08 */ + { "orB", Eb, Gb, XX }, + { "orS", Ev, Gv, XX }, + { "orB", Gb, Eb, XX }, + { "orS", Gv, Ev, XX }, + { "orB", AL, Ib, XX }, + { "orS", eAX, Iv, XX }, + { "pushP", cs, XX, XX }, + { "(bad)", XX, XX, XX }, /* 0x0f extended opcode escape */ + /* 10 */ + { "adcB", Eb, Gb, XX }, + { "adcS", Ev, Gv, XX }, + { "adcB", Gb, Eb, XX }, + { "adcS", Gv, Ev, XX }, + { "adcB", AL, Ib, XX }, + { "adcS", eAX, Iv, XX }, + { "pushP", ss, XX, XX }, + { "popP", ss, XX, XX }, + /* 18 */ + { "sbbB", Eb, Gb, XX }, + { "sbbS", Ev, Gv, XX }, + { "sbbB", Gb, Eb, XX }, + { "sbbS", Gv, Ev, XX }, + { "sbbB", AL, Ib, XX }, + { "sbbS", eAX, Iv, XX }, + { "pushP", ds, XX, XX }, + { "popP", ds, XX, XX }, + /* 20 */ + { "andB", Eb, Gb, XX }, + { "andS", Ev, Gv, XX }, + { "andB", Gb, Eb, XX }, + { "andS", Gv, Ev, XX }, + { "andB", AL, Ib, XX }, + { "andS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG ES prefix */ + { "daa", XX, XX, XX }, + /* 28 */ + { "subB", Eb, Gb, XX }, + { "subS", Ev, Gv, XX }, + { "subB", Gb, Eb, XX }, + { "subS", Gv, Ev, XX }, + { "subB", AL, Ib, XX }, + { "subS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG CS prefix */ + { "das", XX, XX, XX }, + /* 30 */ + { "xorB", Eb, Gb, XX }, + { "xorS", Ev, Gv, XX }, + { "xorB", Gb, Eb, XX }, + { "xorS", Gv, Ev, XX }, + { "xorB", AL, Ib, XX }, + { "xorS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG SS prefix */ + { "aaa", XX, XX, XX }, + /* 38 */ + { "cmpB", Eb, Gb, XX }, + { "cmpS", Ev, Gv, XX }, + { "cmpB", Gb, Eb, XX }, + { "cmpS", Gv, Ev, XX }, + { "cmpB", AL, Ib, XX }, + { "cmpS", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG DS prefix */ + { "aas", XX, XX, XX }, + /* 40 */ + { "incS", eAX, XX, XX }, + { "incS", eCX, XX, XX }, + { "incS", eDX, XX, XX }, + { "incS", eBX, XX, XX }, + { "incS", eSP, XX, XX }, + { "incS", eBP, XX, XX }, + { "incS", eSI, XX, XX }, + { "incS", eDI, XX, XX }, + /* 48 */ + { "decS", eAX, XX, XX }, + { "decS", eCX, XX, XX }, + { "decS", eDX, XX, XX }, + { "decS", eBX, XX, XX }, + { "decS", eSP, XX, XX }, + { "decS", eBP, XX, XX }, + { "decS", eSI, XX, XX }, + { "decS", eDI, XX, XX }, + /* 50 */ + { "pushS", eAX, XX, XX }, + { "pushS", eCX, XX, XX }, + { "pushS", eDX, XX, XX }, + { "pushS", eBX, XX, XX }, + { "pushS", eSP, XX, XX }, + { "pushS", eBP, XX, XX }, + { "pushS", eSI, XX, XX }, + { "pushS", eDI, XX, XX }, + /* 58 */ + { "popS", eAX, XX, XX }, + { "popS", eCX, XX, XX }, + { "popS", eDX, XX, XX }, + { "popS", eBX, XX, XX }, + { "popS", eSP, XX, XX }, + { "popS", eBP, XX, XX }, + { "popS", eSI, XX, XX }, + { "popS", eDI, XX, XX }, + /* 60 */ + { "pushaP", XX, XX, XX }, + { "popaP", XX, XX, XX }, + { "boundS", Gv, Ma, XX }, + { "arpl", Ew, Gw, XX }, + { "(bad)", XX, XX, XX }, /* seg fs */ + { "(bad)", XX, XX, XX }, /* seg gs */ + { "(bad)", XX, XX, XX }, /* op size prefix */ + { "(bad)", XX, XX, XX }, /* adr size prefix */ + /* 68 */ + { "pushP", Iv, XX, XX }, /* 386 book wrong */ + { "imulS", Gv, Ev, Iv }, + { "pushP", sIb, XX, XX }, /* push of byte really pushes 2 or 4 bytes */ + { "imulS", Gv, Ev, sIb }, + { "insb", Yb, indirDX, XX }, + { "insR", Yv, indirDX, XX }, + { "outsb", indirDX, Xb, XX }, + { "outsR", indirDX, Xv, XX }, + /* 70 */ + { "jo", Jb, XX, XX }, + { "jno", Jb, XX, XX }, + { "jb", Jb, XX, XX }, + { "jae", Jb, XX, XX }, + { "je", Jb, XX, XX }, + { "jne", Jb, XX, XX }, + { "jbe", Jb, XX, XX }, + { "ja", Jb, XX, XX }, + /* 78 */ + { "js", Jb, XX, XX }, + { "jns", Jb, XX, XX }, + { "jp", Jb, XX, XX }, + { "jnp", Jb, XX, XX }, + { "jl", Jb, XX, XX }, + { "jge", Jb, XX, XX }, + { "jle", Jb, XX, XX }, + { "jg", Jb, XX, XX }, + /* 80 */ + { GRP1b }, + { GRP1S }, + { "(bad)", XX, XX, XX }, + { GRP1Ss }, + { "testB", Eb, Gb, XX }, + { "testS", Ev, Gv, XX }, + { "xchgB", Eb, Gb, XX }, + { "xchgS", Ev, Gv, XX }, + /* 88 */ + { "movB", Eb, Gb, XX }, + { "movS", Ev, Gv, XX }, + { "movB", Gb, Eb, XX }, + { "movS", Gv, Ev, XX }, + { "movQ", Ev, Sw, XX }, + { "leaS", Gv, M, XX }, + { "movQ", Sw, Ev, XX }, + { "popQ", Ev, XX, XX }, + /* 90 */ + { "nop", XX, XX, XX }, + { "xchgS", eCX, eAX, XX }, + { "xchgS", eDX, eAX, XX }, + { "xchgS", eBX, eAX, XX }, + { "xchgS", eSP, eAX, XX }, + { "xchgS", eBP, eAX, XX }, + { "xchgS", eSI, eAX, XX }, + { "xchgS", eDI, eAX, XX }, + /* 98 */ + { "cWtR", XX, XX, XX }, + { "cRtd", XX, XX, XX }, + { "lcallP", Ap, XX, XX }, + { "(bad)", XX, XX, XX }, /* fwait */ + { "pushfP", XX, XX, XX }, + { "popfP", XX, XX, XX }, + { "sahf", XX, XX, XX }, + { "lahf", XX, XX, XX }, + /* a0 */ + { "movB", AL, Ob, XX }, + { "movS", eAX, Ov, XX }, + { "movB", Ob, AL, XX }, + { "movS", Ov, eAX, XX }, + { "movsb", Yb, Xb, XX }, + { "movsR", Yv, Xv, XX }, + { "cmpsb", Xb, Yb, XX }, + { "cmpsR", Xv, Yv, XX }, + /* a8 */ + { "testB", AL, Ib, XX }, + { "testS", eAX, Iv, XX }, + { "stosB", Yb, AL, XX }, + { "stosS", Yv, eAX, XX }, + { "lodsB", AL, Xb, XX }, + { "lodsS", eAX, Xv, XX }, + { "scasB", AL, Yb, XX }, + { "scasS", eAX, Yv, XX }, + /* b0 */ + { "movB", AL, Ib, XX }, + { "movB", CL, Ib, XX }, + { "movB", DL, Ib, XX }, + { "movB", BL, Ib, XX }, + { "movB", AH, Ib, XX }, + { "movB", CH, Ib, XX }, + { "movB", DH, Ib, XX }, + { "movB", BH, Ib, XX }, + /* b8 */ + { "movS", eAX, Iv, XX }, + { "movS", eCX, Iv, XX }, + { "movS", eDX, Iv, XX }, + { "movS", eBX, Iv, XX }, + { "movS", eSP, Iv, XX }, + { "movS", eBP, Iv, XX }, + { "movS", eSI, Iv, XX }, + { "movS", eDI, Iv, XX }, + /* c0 */ + { GRP2b }, + { GRP2S }, + { "retP", Iw, XX, XX }, + { "retP", XX, XX, XX }, + { "lesS", Gv, Mp, XX }, + { "ldsS", Gv, Mp, XX }, + { "movA", Eb, Ib, XX }, + { "movQ", Ev, Iv, XX }, + /* c8 */ + { "enterP", Iw, Ib, XX }, + { "leaveP", XX, XX, XX }, + { "lretP", Iw, XX, XX }, + { "lretP", XX, XX, XX }, + { "int3", XX, XX, XX }, + { "int", Ib, XX, XX }, + { "into", XX, XX, XX}, + { "iretP", XX, XX, XX }, + /* d0 */ + { GRP2b_one }, + { GRP2S_one }, + { GRP2b_cl }, + { GRP2S_cl }, + { "aam", sIb, XX, XX }, + { "aad", sIb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "xlat", DSBX, XX, XX }, + /* d8 */ + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + /* e0 */ + { "loopne", Jb, XX, XX }, + { "loope", Jb, XX, XX }, + { "loop", Jb, XX, XX }, + { "jEcxz", Jb, XX, XX }, + { "inB", AL, Ib, XX }, + { "inS", eAX, Ib, XX }, + { "outB", Ib, AL, XX }, + { "outS", Ib, eAX, XX }, + /* e8 */ + { "callP", Jv, XX, XX }, + { "jmpP", Jv, XX, XX }, + { "ljmpP", Ap, XX, XX }, + { "jmp", Jb, XX, XX }, + { "inB", AL, indirDX, XX }, + { "inS", eAX, indirDX, XX }, + { "outB", indirDX, AL, XX }, + { "outS", indirDX, eAX, XX }, + /* f0 */ + { "(bad)", XX, XX, XX }, /* lock prefix */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, /* repne */ + { "(bad)", XX, XX, XX }, /* repz */ + { "hlt", XX, XX, XX }, + { "cmc", XX, XX, XX }, + { GRP3b }, + { GRP3S }, + /* f8 */ + { "clc", XX, XX, XX }, + { "stc", XX, XX, XX }, + { "cli", XX, XX, XX }, + { "sti", XX, XX, XX }, + { "cld", XX, XX, XX }, + { "std", XX, XX, XX }, + { GRP4 }, + { GRP5 }, +}; + +static const struct dis386 dis386_intel[] = { + /* 00 */ + { "add", Eb, Gb, XX }, + { "add", Ev, Gv, XX }, + { "add", Gb, Eb, XX }, + { "add", Gv, Ev, XX }, + { "add", AL, Ib, XX }, + { "add", eAX, Iv, XX }, + { "push", es, XX, XX }, + { "pop", es, XX, XX }, + /* 08 */ + { "or", Eb, Gb, XX }, + { "or", Ev, Gv, XX }, + { "or", Gb, Eb, XX }, + { "or", Gv, Ev, XX }, + { "or", AL, Ib, XX }, + { "or", eAX, Iv, XX }, + { "push", cs, XX, XX }, + { "(bad)", XX, XX, XX }, /* 0x0f extended opcode escape */ + /* 10 */ + { "adc", Eb, Gb, XX }, + { "adc", Ev, Gv, XX }, + { "adc", Gb, Eb, XX }, + { "adc", Gv, Ev, XX }, + { "adc", AL, Ib, XX }, + { "adc", eAX, Iv, XX }, + { "push", ss, XX, XX }, + { "pop", ss, XX, XX }, + /* 18 */ + { "sbb", Eb, Gb, XX }, + { "sbb", Ev, Gv, XX }, + { "sbb", Gb, Eb, XX }, + { "sbb", Gv, Ev, XX }, + { "sbb", AL, Ib, XX }, + { "sbb", eAX, Iv, XX }, + { "push", ds, XX, XX }, + { "pop", ds, XX, XX }, + /* 20 */ + { "and", Eb, Gb, XX }, + { "and", Ev, Gv, XX }, + { "and", Gb, Eb, XX }, + { "and", Gv, Ev, XX }, + { "and", AL, Ib, XX }, + { "and", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG ES prefix */ + { "daa", XX, XX, XX }, + /* 28 */ + { "sub", Eb, Gb, XX }, + { "sub", Ev, Gv, XX }, + { "sub", Gb, Eb, XX }, + { "sub", Gv, Ev, XX }, + { "sub", AL, Ib, XX }, + { "sub", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG CS prefix */ + { "das", XX, XX, XX }, + /* 30 */ + { "xor", Eb, Gb, XX }, + { "xor", Ev, Gv, XX }, + { "xor", Gb, Eb, XX }, + { "xor", Gv, Ev, XX }, + { "xor", AL, Ib, XX }, + { "xor", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG SS prefix */ + { "aaa", XX, XX, XX }, + /* 38 */ + { "cmp", Eb, Gb, XX }, + { "cmp", Ev, Gv, XX }, + { "cmp", Gb, Eb, XX }, + { "cmp", Gv, Ev, XX }, + { "cmp", AL, Ib, XX }, + { "cmp", eAX, Iv, XX }, + { "(bad)", XX, XX, XX }, /* SEG DS prefix */ + { "aas", XX, XX, XX }, + /* 40 */ + { "inc", eAX, XX, XX }, + { "inc", eCX, XX, XX }, + { "inc", eDX, XX, XX }, + { "inc", eBX, XX, XX }, + { "inc", eSP, XX, XX }, + { "inc", eBP, XX, XX }, + { "inc", eSI, XX, XX }, + { "inc", eDI, XX, XX }, + /* 48 */ + { "dec", eAX, XX, XX }, + { "dec", eCX, XX, XX }, + { "dec", eDX, XX, XX }, + { "dec", eBX, XX, XX }, + { "dec", eSP, XX, XX }, + { "dec", eBP, XX, XX }, + { "dec", eSI, XX, XX }, + { "dec", eDI, XX, XX }, + /* 50 */ + { "push", eAX, XX, XX }, + { "push", eCX, XX, XX }, + { "push", eDX, XX, XX }, + { "push", eBX, XX, XX }, + { "push", eSP, XX, XX }, + { "push", eBP, XX, XX }, + { "push", eSI, XX, XX }, + { "push", eDI, XX, XX }, + /* 58 */ + { "pop", eAX, XX, XX }, + { "pop", eCX, XX, XX }, + { "pop", eDX, XX, XX }, + { "pop", eBX, XX, XX }, + { "pop", eSP, XX, XX }, + { "pop", eBP, XX, XX }, + { "pop", eSI, XX, XX }, + { "pop", eDI, XX, XX }, + /* 60 */ + { "pusha", XX, XX, XX }, + { "popa", XX, XX, XX }, + { "bound", Gv, Ma, XX }, + { "arpl", Ew, Gw, XX }, + { "(bad)", XX, XX, XX }, /* seg fs */ + { "(bad)", XX, XX, XX }, /* seg gs */ + { "(bad)", XX, XX, XX }, /* op size prefix */ + { "(bad)", XX, XX, XX }, /* adr size prefix */ + /* 68 */ + { "push", Iv, XX, XX }, /* 386 book wrong */ + { "imul", Gv, Ev, Iv }, + { "push", sIb, XX, XX }, /* push of byte really pushes 2 or 4 bytes */ + { "imul", Gv, Ev, sIb }, + { "ins", Yb, indirDX, XX }, + { "ins", Yv, indirDX, XX }, + { "outs", indirDX, Xb, XX }, + { "outs", indirDX, Xv, XX }, + /* 70 */ + { "jo", Jb, XX, XX }, + { "jno", Jb, XX, XX }, + { "jb", Jb, XX, XX }, + { "jae", Jb, XX, XX }, + { "je", Jb, XX, XX }, + { "jne", Jb, XX, XX }, + { "jbe", Jb, XX, XX }, + { "ja", Jb, XX, XX }, + /* 78 */ + { "js", Jb, XX, XX }, + { "jns", Jb, XX, XX }, + { "jp", Jb, XX, XX }, + { "jnp", Jb, XX, XX }, + { "jl", Jb, XX, XX }, + { "jge", Jb, XX, XX }, + { "jle", Jb, XX, XX }, + { "jg", Jb, XX, XX }, + /* 80 */ + { GRP1b }, + { GRP1S }, + { "(bad)", XX, XX, XX }, + { GRP1Ss }, + { "test", Eb, Gb, XX }, + { "test", Ev, Gv, XX }, + { "xchg", Eb, Gb, XX }, + { "xchg", Ev, Gv, XX }, + /* 88 */ + { "mov", Eb, Gb, XX }, + { "mov", Ev, Gv, XX }, + { "mov", Gb, Eb, XX }, + { "mov", Gv, Ev, XX }, + { "mov", Ev, Sw, XX }, + { "lea", Gv, M, XX }, + { "mov", Sw, Ev, XX }, + { "pop", Ev, XX, XX }, + /* 90 */ + { "nop", XX, XX, XX }, + { "xchg", eCX, eAX, XX }, + { "xchg", eDX, eAX, XX }, + { "xchg", eBX, eAX, XX }, + { "xchg", eSP, eAX, XX }, + { "xchg", eBP, eAX, XX }, + { "xchg", eSI, eAX, XX }, + { "xchg", eDI, eAX, XX }, + /* 98 */ + { "cW", XX, XX, XX }, /* cwde and cbw */ + { "cR", XX, XX, XX }, /* cdq and cwd */ + { "lcall", Ap, XX, XX }, + { "(bad)", XX, XX, XX }, /* fwait */ + { "pushf", XX, XX, XX }, + { "popf", XX, XX, XX }, + { "sahf", XX, XX, XX }, + { "lahf", XX, XX, XX }, + /* a0 */ + { "mov", AL, Ob, XX }, + { "mov", eAX, Ov, XX }, + { "mov", Ob, AL, XX }, + { "mov", Ov, eAX, XX }, + { "movs", Yb, Xb, XX }, + { "movs", Yv, Xv, XX }, + { "cmps", Xb, Yb, XX }, + { "cmps", Xv, Yv, XX }, + /* a8 */ + { "test", AL, Ib, XX }, + { "test", eAX, Iv, XX }, + { "stos", Yb, AL, XX }, + { "stos", Yv, eAX, XX }, + { "lods", AL, Xb, XX }, + { "lods", eAX, Xv, XX }, + { "scas", AL, Yb, XX }, + { "scas", eAX, Yv, XX }, + /* b0 */ + { "mov", AL, Ib, XX }, + { "mov", CL, Ib, XX }, + { "mov", DL, Ib, XX }, + { "mov", BL, Ib, XX }, + { "mov", AH, Ib, XX }, + { "mov", CH, Ib, XX }, + { "mov", DH, Ib, XX }, + { "mov", BH, Ib, XX }, + /* b8 */ + { "mov", eAX, Iv, XX }, + { "mov", eCX, Iv, XX }, + { "mov", eDX, Iv, XX }, + { "mov", eBX, Iv, XX }, + { "mov", eSP, Iv, XX }, + { "mov", eBP, Iv, XX }, + { "mov", eSI, Iv, XX }, + { "mov", eDI, Iv, XX }, + /* c0 */ + { GRP2b }, + { GRP2S }, + { "ret", Iw, XX, XX }, + { "ret", XX, XX, XX }, + { "les", Gv, Mp, XX }, + { "lds", Gv, Mp, XX }, + { "mov", Eb, Ib, XX }, + { "mov", Ev, Iv, XX }, + /* c8 */ + { "enter", Iw, Ib, XX }, + { "leave", XX, XX, XX }, + { "lret", Iw, XX, XX }, + { "lret", XX, XX, XX }, + { "int3", XX, XX, XX }, + { "int", Ib, XX, XX }, + { "into", XX, XX, XX }, + { "iret", XX, XX, XX }, + /* d0 */ + { GRP2b_one }, + { GRP2S_one }, + { GRP2b_cl }, + { GRP2S_cl }, + { "aam", sIb, XX, XX }, + { "aad", sIb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "xlat", DSBX, XX, XX }, + /* d8 */ + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + { FLOAT }, + /* e0 */ + { "loopne", Jb, XX, XX }, + { "loope", Jb, XX, XX }, + { "loop", Jb, XX, XX }, + { "jEcxz", Jb, XX, XX }, + { "in", AL, Ib, XX }, + { "in", eAX, Ib, XX }, + { "out", Ib, AL, XX }, + { "out", Ib, eAX, XX }, + /* e8 */ + { "call", Jv, XX, XX }, + { "jmp", Jv, XX, XX }, + { "ljmp", Ap, XX, XX }, + { "jmp", Jb, XX, XX }, + { "in", AL, indirDX, XX }, + { "in", eAX, indirDX, XX }, + { "out", indirDX, AL, XX }, + { "out", indirDX, eAX, XX }, + /* f0 */ + { "(bad)", XX, XX, XX }, /* lock prefix */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, /* repne */ + { "(bad)", XX, XX, XX }, /* repz */ + { "hlt", XX, XX, XX }, + { "cmc", XX, XX, XX }, + { GRP3b }, + { GRP3S }, + /* f8 */ + { "clc", XX, XX, XX }, + { "stc", XX, XX, XX }, + { "cli", XX, XX, XX }, + { "sti", XX, XX, XX }, + { "cld", XX, XX, XX }, + { "std", XX, XX, XX }, + { GRP4 }, + { GRP5 }, +}; + +static const struct dis386 dis386_twobyte_att[] = { + /* 00 */ + { GRP6 }, + { GRP7 }, + { "larS", Gv, Ew, XX }, + { "lslS", Gv, Ew, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "clts", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 08 */ + { "invd", XX, XX, XX }, + { "wbinvd", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "ud2a", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { GRPAMD }, + { "femms", XX, XX, XX }, + { "", MX, EM, OPSUF }, /* See OP_3DNowSuffix */ + /* 10 */ + { PREGRP8 }, + { PREGRP9 }, + { "movlps", XM, EX, SIMD_Fixup, 'h' }, /* really only 2 operands */ + { "movlps", EX, XM, SIMD_Fixup, 'h' }, + { "unpcklps", XM, EX, XX }, + { "unpckhps", XM, EX, XX }, + { "movhps", XM, EX, SIMD_Fixup, 'l' }, + { "movhps", EX, XM, SIMD_Fixup, 'l' }, + /* 18 */ + { GRP14 }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 20 */ + /* these are all backward in appendix A of the intel book */ + { "movL", Rd, Cd, XX }, + { "movL", Rd, Dd, XX }, + { "movL", Cd, Rd, XX }, + { "movL", Dd, Rd, XX }, + { "movL", Rd, Td, XX }, + { "(bad)", XX, XX, XX }, + { "movL", Td, Rd, XX }, + { "(bad)", XX, XX, XX }, + /* 28 */ + { "movaps", XM, EX, XX }, + { "movaps", EX, XM, XX }, + { PREGRP2 }, + { "movntps", Ev, XM, XX }, + { PREGRP4 }, + { PREGRP3 }, + { "ucomiss", XM, EX, XX }, + { "comiss", XM, EX, XX }, + /* 30 */ + { "wrmsr", XX, XX, XX }, + { "rdtsc", XX, XX, XX }, + { "rdmsr", XX, XX, XX }, + { "rdpmc", XX, XX, XX }, + { "sysenter", XX, XX, XX }, + { "sysexit", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 38 */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 40 */ + { "cmovo", Gv, Ev, XX }, + { "cmovno", Gv, Ev, XX }, + { "cmovb", Gv, Ev, XX }, + { "cmovae", Gv, Ev, XX }, + { "cmove", Gv, Ev, XX }, + { "cmovne", Gv, Ev, XX }, + { "cmovbe", Gv, Ev, XX }, + { "cmova", Gv, Ev, XX }, + /* 48 */ + { "cmovs", Gv, Ev, XX }, + { "cmovns", Gv, Ev, XX }, + { "cmovp", Gv, Ev, XX }, + { "cmovnp", Gv, Ev, XX }, + { "cmovl", Gv, Ev, XX }, + { "cmovge", Gv, Ev, XX }, + { "cmovle", Gv, Ev, XX }, + { "cmovg", Gv, Ev, XX }, + /* 50 */ + { "movmskps", Gv, EX, XX }, + { PREGRP13 }, + { PREGRP12 }, + { PREGRP11 }, + { "andps", XM, EX, XX }, + { "andnps", XM, EX, XX }, + { "orps", XM, EX, XX }, + { "xorps", XM, EX, XX }, + /* 58 */ + { PREGRP0 }, + { PREGRP10 }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { PREGRP14 }, + { PREGRP7 }, + { PREGRP5 }, + { PREGRP6 }, + /* 60 */ + { "punpcklbw", MX, EM, XX }, + { "punpcklwd", MX, EM, XX }, + { "punpckldq", MX, EM, XX }, + { "packsswb", MX, EM, XX }, + { "pcmpgtb", MX, EM, XX }, + { "pcmpgtw", MX, EM, XX }, + { "pcmpgtd", MX, EM, XX }, + { "packuswb", MX, EM, XX }, + /* 68 */ + { "punpckhbw", MX, EM, XX }, + { "punpckhwd", MX, EM, XX }, + { "punpckhdq", MX, EM, XX }, + { "packssdw", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "movd", MX, Ed, XX }, + { "movq", MX, EM, XX }, + /* 70 */ + { "pshufw", MX, EM, Ib }, + { GRP10 }, + { GRP11 }, + { GRP12 }, + { "pcmpeqb", MX, EM, XX }, + { "pcmpeqw", MX, EM, XX }, + { "pcmpeqd", MX, EM, XX }, + { "emms", XX, XX, XX }, + /* 78 */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "movd", Ed, MX, XX }, + { "movq", EM, MX, XX }, + /* 80 */ + { "jo", Jv, XX, XX }, + { "jno", Jv, XX, XX }, + { "jb", Jv, XX, XX }, + { "jae", Jv, XX, XX }, + { "je", Jv, XX, XX }, + { "jne", Jv, XX, XX }, + { "jbe", Jv, XX, XX }, + { "ja", Jv, XX, XX }, + /* 88 */ + { "js", Jv, XX, XX }, + { "jns", Jv, XX, XX }, + { "jp", Jv, XX, XX }, + { "jnp", Jv, XX, XX }, + { "jl", Jv, XX, XX }, + { "jge", Jv, XX, XX }, + { "jle", Jv, XX, XX }, + { "jg", Jv, XX, XX }, + /* 90 */ + { "seto", Eb, XX, XX }, + { "setno", Eb, XX, XX }, + { "setb", Eb, XX, XX }, + { "setae", Eb, XX, XX }, + { "sete", Eb, XX, XX }, + { "setne", Eb, XX, XX }, + { "setbe", Eb, XX, XX }, + { "seta", Eb, XX, XX }, + /* 98 */ + { "sets", Eb, XX, XX }, + { "setns", Eb, XX, XX }, + { "setp", Eb, XX, XX }, + { "setnp", Eb, XX, XX }, + { "setl", Eb, XX, XX }, + { "setge", Eb, XX, XX }, + { "setle", Eb, XX, XX }, + { "setg", Eb, XX, XX }, + /* a0 */ + { "pushP", fs, XX, XX }, + { "popP", fs, XX, XX }, + { "cpuid", XX, XX, XX }, + { "btS", Ev, Gv, XX }, + { "shldS", Ev, Gv, Ib }, + { "shldS", Ev, Gv, CL }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* a8 */ + { "pushP", gs, XX, XX }, + { "popP", gs, XX, XX }, + { "rsm", XX, XX, XX }, + { "btsS", Ev, Gv, XX }, + { "shrdS", Ev, Gv, Ib }, + { "shrdS", Ev, Gv, CL }, + { GRP13 }, + { "imulS", Gv, Ev, XX }, + /* b0 */ + { "cmpxchgB", Eb, Gb, XX }, + { "cmpxchgS", Ev, Gv, XX }, + { "lssS", Gv, Mp, XX }, + { "btrS", Ev, Gv, XX }, + { "lfsS", Gv, Mp, XX }, + { "lgsS", Gv, Mp, XX }, + { "movzbR", Gv, Eb, XX }, + { "movzwR", Gv, Ew, XX }, /* yes, there really is movzww ! */ + /* b8 */ + { "(bad)", XX, XX, XX }, + { "ud2b", XX, XX, XX }, + { GRP8 }, + { "btcS", Ev, Gv, XX }, + { "bsfS", Gv, Ev, XX }, + { "bsrS", Gv, Ev, XX }, + { "movsbR", Gv, Eb, XX }, + { "movswR", Gv, Ew, XX }, /* yes, there really is movsww ! */ + /* c0 */ + { "xaddB", Eb, Gb, XX }, + { "xaddS", Ev, Gv, XX }, + { PREGRP1 }, + { "(bad)", XX, XX, XX }, + { "pinsrw", MX, Ev, Ib }, + { "pextrw", Ev, MX, Ib }, + { "shufps", XM, EX, Ib }, + { GRP9 }, + /* c8 */ + { "bswap", eAX, XX, XX }, /* bswap doesn't support 16 bit regs */ + { "bswap", eCX, XX, XX }, + { "bswap", eDX, XX, XX }, + { "bswap", eBX, XX, XX }, + { "bswap", eSP, XX, XX }, + { "bswap", eBP, XX, XX }, + { "bswap", eSI, XX, XX }, + { "bswap", eDI, XX, XX }, + /* d0 */ + { "(bad)", XX, XX, XX }, + { "psrlw", MX, EM, XX }, + { "psrld", MX, EM, XX }, + { "psrlq", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "pmullw", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "pmovmskb", Ev, MX, XX }, + /* d8 */ + { "psubusb", MX, EM, XX }, + { "psubusw", MX, EM, XX }, + { "pminub", MX, EM, XX }, + { "pand", MX, EM, XX }, + { "paddusb", MX, EM, XX }, + { "paddusw", MX, EM, XX }, + { "pmaxub", MX, EM, XX }, + { "pandn", MX, EM, XX }, + /* e0 */ + { "pavgb", MX, EM, XX }, + { "psraw", MX, EM, XX }, + { "psrad", MX, EM, XX }, + { "pavgw", MX, EM, XX }, + { "pmulhuw", MX, EM, XX }, + { "pmulhw", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "movntq", Ev, MX, XX }, + /* e8 */ + { "psubsb", MX, EM, XX }, + { "psubsw", MX, EM, XX }, + { "pminsw", MX, EM, XX }, + { "por", MX, EM, XX }, + { "paddsb", MX, EM, XX }, + { "paddsw", MX, EM, XX }, + { "pmaxsw", MX, EM, XX }, + { "pxor", MX, EM, XX }, + /* f0 */ + { "(bad)", XX, XX, XX }, + { "psllw", MX, EM, XX }, + { "pslld", MX, EM, XX }, + { "psllq", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "pmaddwd", MX, EM, XX }, + { "psadbw", MX, EM, XX }, + { "maskmovq", MX, EM, XX }, + /* f8 */ + { "psubb", MX, EM, XX }, + { "psubw", MX, EM, XX }, + { "psubd", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "paddb", MX, EM, XX }, + { "paddw", MX, EM, XX }, + { "paddd", MX, EM, XX }, + { "(bad)", XX, XX, XX } +}; + +static const struct dis386 dis386_twobyte_intel[] = { + /* 00 */ + { GRP6 }, + { GRP7 }, + { "lar", Gv, Ew, XX }, + { "lsl", Gv, Ew, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "clts", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 08 */ + { "invd", XX, XX, XX }, + { "wbinvd", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "ud2a", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { GRPAMD }, + { "femms" , XX, XX, XX}, + { "", MX, EM, OPSUF }, /* See OP_3DNowSuffix */ + /* 10 */ + { PREGRP8 }, + { PREGRP9 }, + { "movlps", XM, EX, SIMD_Fixup, 'h' }, /* really only 2 operands */ + { "movlps", EX, XM, SIMD_Fixup, 'h' }, + { "unpcklps", XM, EX, XX }, + { "unpckhps", XM, EX, XX }, + { "movhps", XM, EX, SIMD_Fixup, 'l' }, + { "movhps", EX, XM, SIMD_Fixup, 'l' }, + /* 18 */ + { GRP14 }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 20 */ + /* these are all backward in appendix A of the intel book */ + { "mov", Rd, Cd, XX }, + { "mov", Rd, Dd, XX }, + { "mov", Cd, Rd, XX }, + { "mov", Dd, Rd, XX }, + { "mov", Rd, Td, XX }, + { "(bad)", XX, XX, XX }, + { "mov", Td, Rd, XX }, + { "(bad)", XX, XX, XX }, + /* 28 */ + { "movaps", XM, EX, XX }, + { "movaps", EX, XM, XX }, + { PREGRP2 }, + { "movntps", Ev, XM, XX }, + { PREGRP4 }, + { PREGRP3 }, + { "ucomiss", XM, EX, XX }, + { "comiss", XM, EX, XX }, + /* 30 */ + { "wrmsr", XX, XX, XX }, + { "rdtsc", XX, XX, XX }, + { "rdmsr", XX, XX, XX }, + { "rdpmc", XX, XX, XX }, + { "sysenter", XX, XX, XX }, + { "sysexit", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 38 */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* 40 */ + { "cmovo", Gv, Ev, XX }, + { "cmovno", Gv, Ev, XX }, + { "cmovb", Gv, Ev, XX }, + { "cmovae", Gv, Ev, XX }, + { "cmove", Gv, Ev, XX }, + { "cmovne", Gv, Ev, XX }, + { "cmovbe", Gv, Ev, XX }, + { "cmova", Gv, Ev, XX }, + /* 48 */ + { "cmovs", Gv, Ev, XX }, + { "cmovns", Gv, Ev, XX }, + { "cmovp", Gv, Ev, XX }, + { "cmovnp", Gv, Ev, XX }, + { "cmovl", Gv, Ev, XX }, + { "cmovge", Gv, Ev, XX }, + { "cmovle", Gv, Ev, XX }, + { "cmovg", Gv, Ev, XX }, + /* 50 */ + { "movmskps", Gv, EX, XX }, + { PREGRP13 }, + { PREGRP12 }, + { PREGRP11 }, + { "andps", XM, EX, XX }, + { "andnps", XM, EX, XX }, + { "orps", XM, EX, XX }, + { "xorps", XM, EX, XX }, + /* 58 */ + { PREGRP0 }, + { PREGRP10 }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { PREGRP14 }, + { PREGRP7 }, + { PREGRP5 }, + { PREGRP6 }, + /* 60 */ + { "punpcklbw", MX, EM, XX }, + { "punpcklwd", MX, EM, XX }, + { "punpckldq", MX, EM, XX }, + { "packsswb", MX, EM, XX }, + { "pcmpgtb", MX, EM, XX }, + { "pcmpgtw", MX, EM, XX }, + { "pcmpgtd", MX, EM, XX }, + { "packuswb", MX, EM, XX }, + /* 68 */ + { "punpckhbw", MX, EM, XX }, + { "punpckhwd", MX, EM, XX }, + { "punpckhdq", MX, EM, XX }, + { "packssdw", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "movd", MX, Ed, XX }, + { "movq", MX, EM, XX }, + /* 70 */ + { "pshufw", MX, EM, Ib }, + { GRP10 }, + { GRP11 }, + { GRP12 }, + { "pcmpeqb", MX, EM, XX }, + { "pcmpeqw", MX, EM, XX }, + { "pcmpeqd", MX, EM, XX }, + { "emms", XX, XX, XX }, + /* 78 */ + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "movd", Ed, MX, XX }, + { "movq", EM, MX, XX }, + /* 80 */ + { "jo", Jv, XX, XX }, + { "jno", Jv, XX, XX }, + { "jb", Jv, XX, XX }, + { "jae", Jv, XX, XX }, + { "je", Jv, XX, XX }, + { "jne", Jv, XX, XX }, + { "jbe", Jv, XX, XX }, + { "ja", Jv, XX, XX }, + /* 88 */ + { "js", Jv, XX, XX }, + { "jns", Jv, XX, XX }, + { "jp", Jv, XX, XX }, + { "jnp", Jv, XX, XX }, + { "jl", Jv, XX, XX }, + { "jge", Jv, XX, XX }, + { "jle", Jv, XX, XX }, + { "jg", Jv, XX, XX }, + /* 90 */ + { "seto", Eb, XX, XX }, + { "setno", Eb, XX, XX }, + { "setb", Eb, XX, XX }, + { "setae", Eb, XX, XX }, + { "sete", Eb, XX, XX }, + { "setne", Eb, XX, XX }, + { "setbe", Eb, XX, XX }, + { "seta", Eb, XX, XX }, + /* 98 */ + { "sets", Eb, XX, XX }, + { "setns", Eb, XX, XX }, + { "setp", Eb, XX, XX }, + { "setnp", Eb, XX, XX }, + { "setl", Eb, XX, XX }, + { "setge", Eb, XX, XX }, + { "setle", Eb, XX, XX }, + { "setg", Eb, XX, XX }, + /* a0 */ + { "push", fs, XX, XX }, + { "pop", fs, XX, XX }, + { "cpuid", XX, XX, XX }, + { "bt", Ev, Gv, XX }, + { "shld", Ev, Gv, Ib }, + { "shld", Ev, Gv, CL }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + /* a8 */ + { "push", gs, XX, XX }, + { "pop", gs, XX, XX }, + { "rsm" , XX, XX, XX}, + { "bts", Ev, Gv, XX }, + { "shrd", Ev, Gv, Ib }, + { "shrd", Ev, Gv, CL }, + { GRP13 }, + { "imul", Gv, Ev, XX }, + /* b0 */ + { "cmpxchg", Eb, Gb, XX }, + { "cmpxchg", Ev, Gv, XX }, + { "lss", Gv, Mp, XX }, + { "btr", Ev, Gv, XX }, + { "lfs", Gv, Mp, XX }, + { "lgs", Gv, Mp, XX }, + { "movzx", Gv, Eb, XX }, + { "movzx", Gv, Ew, XX }, + /* b8 */ + { "(bad)", XX, XX, XX }, + { "ud2b", XX, XX, XX }, + { GRP8 }, + { "btc", Ev, Gv, XX }, + { "bsf", Gv, Ev, XX }, + { "bsr", Gv, Ev, XX }, + { "movsx", Gv, Eb, XX }, + { "movsx", Gv, Ew, XX }, + /* c0 */ + { "xadd", Eb, Gb, XX }, + { "xadd", Ev, Gv, XX }, + { PREGRP1 }, + { "(bad)", XX, XX, XX }, + { "pinsrw", MX, Ev, Ib }, + { "pextrw", Ev, MX, Ib }, + { "shufps", XM, EX, Ib }, + { GRP9 }, + /* c8 */ + { "bswap", eAX, XX, XX }, /* bswap doesn't support 16 bit regs */ + { "bswap", eCX, XX, XX }, + { "bswap", eDX, XX, XX }, + { "bswap", eBX, XX, XX }, + { "bswap", eSP, XX, XX }, + { "bswap", eBP, XX, XX }, + { "bswap", eSI, XX, XX }, + { "bswap", eDI, XX, XX }, + /* d0 */ + { "(bad)", XX, XX, XX }, + { "psrlw", MX, EM, XX }, + { "psrld", MX, EM, XX }, + { "psrlq", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "pmullw", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "pmovmskb", Ev, MX, XX }, + /* d8 */ + { "psubusb", MX, EM, XX }, + { "psubusw", MX, EM, XX }, + { "pminub", MX, EM, XX }, + { "pand", MX, EM, XX }, + { "paddusb", MX, EM, XX }, + { "paddusw", MX, EM, XX }, + { "pmaxub", MX, EM, XX }, + { "pandn", MX, EM, XX }, + /* e0 */ + { "pavgb", MX, EM, XX }, + { "psraw", MX, EM, XX }, + { "psrad", MX, EM, XX }, + { "pavgw", MX, EM, XX }, + { "pmulhuw", MX, EM, XX }, + { "pmulhw", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "movntq", Ev, MX, XX }, + /* e8 */ + { "psubsb", MX, EM, XX }, + { "psubsw", MX, EM, XX }, + { "pminsw", MX, EM, XX }, + { "por", MX, EM, XX }, + { "paddsb", MX, EM, XX }, + { "paddsw", MX, EM, XX }, + { "pmaxsw", MX, EM, XX }, + { "pxor", MX, EM, XX }, + /* f0 */ + { "(bad)", XX, XX, XX }, + { "psllw", MX, EM, XX }, + { "pslld", MX, EM, XX }, + { "psllq", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "pmaddwd", MX, EM, XX }, + { "psadbw", MX, EM, XX }, + { "maskmovq", MX, EM, XX }, + /* f8 */ + { "psubb", MX, EM, XX }, + { "psubw", MX, EM, XX }, + { "psubd", MX, EM, XX }, + { "(bad)", XX, XX, XX }, + { "paddb", MX, EM, XX }, + { "paddw", MX, EM, XX }, + { "paddd", MX, EM, XX }, + { "(bad)", XX, XX, XX } +}; + +static const unsigned char onebyte_has_modrm[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 00 */ + /* 10 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 10 */ + /* 20 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 20 */ + /* 30 */ 1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0, /* 30 */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */ + /* 50 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */ + /* 60 */ 0,0,1,1,0,0,0,0,0,1,0,1,0,0,0,0, /* 60 */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */ + /* 80 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 80 */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* a0 */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* b0 */ + /* c0 */ 1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* c0 */ + /* d0 */ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1, /* d0 */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* e0 */ + /* f0 */ 0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1 /* f0 */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_has_modrm[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,1, /* 0f */ + /* 10 */ 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4f */ + /* 50 */ 1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1, /* 5f */ + /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1, /* 6f */ + /* 70 */ 1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9f */ + /* a0 */ 0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1, /* af */ + /* b0 */ 1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1, /* bf */ + /* c0 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1, /* df */ + /* e0 */ 1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, /* ef */ + /* f0 */ 0,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static const unsigned char twobyte_uses_f3_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 0,1,1,1,0,0,0,0,1,1,0,0,1,1,1,1, /* 5f */ + /* 60 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 6f */ + /* 70 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* df */ + /* e0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ef */ + /* f0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + +static char obuf[100]; +static char *obufp; +static char scratchbuf[100]; +static unsigned char *start_codep; +static unsigned char *insn_codep; +static unsigned char *codep; +static disassemble_info *the_info; +static int mod; +static int rm; +static int reg; +static void oappend PARAMS ((const char *s)); + +static const char *names32[]={ + "%eax","%ecx","%edx","%ebx", "%esp","%ebp","%esi","%edi", +}; +static const char *names16[] = { + "%ax","%cx","%dx","%bx","%sp","%bp","%si","%di", +}; +static const char *names8[] = { + "%al","%cl","%dl","%bl","%ah","%ch","%dh","%bh", +}; +static const char *names_seg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", +}; +static const char *index16[] = { + "%bx,%si","%bx,%di","%bp,%si","%bp,%di","%si","%di","%bp","%bx" +}; + +static const struct dis386 grps[][8] = { + /* GRP1b */ + { + { "addA", Eb, Ib, XX }, + { "orA", Eb, Ib, XX }, + { "adcA", Eb, Ib, XX }, + { "sbbA", Eb, Ib, XX }, + { "andA", Eb, Ib, XX }, + { "subA", Eb, Ib, XX }, + { "xorA", Eb, Ib, XX }, + { "cmpA", Eb, Ib, XX } + }, + /* GRP1S */ + { + { "addQ", Ev, Iv, XX }, + { "orQ", Ev, Iv, XX }, + { "adcQ", Ev, Iv, XX }, + { "sbbQ", Ev, Iv, XX }, + { "andQ", Ev, Iv, XX }, + { "subQ", Ev, Iv, XX }, + { "xorQ", Ev, Iv, XX }, + { "cmpQ", Ev, Iv, XX } + }, + /* GRP1Ss */ + { + { "addQ", Ev, sIb, XX }, + { "orQ", Ev, sIb, XX }, + { "adcQ", Ev, sIb, XX }, + { "sbbQ", Ev, sIb, XX }, + { "andQ", Ev, sIb, XX }, + { "subQ", Ev, sIb, XX }, + { "xorQ", Ev, sIb, XX }, + { "cmpQ", Ev, sIb, XX } + }, + /* GRP2b */ + { + { "rolA", Eb, Ib, XX }, + { "rorA", Eb, Ib, XX }, + { "rclA", Eb, Ib, XX }, + { "rcrA", Eb, Ib, XX }, + { "shlA", Eb, Ib, XX }, + { "shrA", Eb, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "sarA", Eb, Ib, XX }, + }, + /* GRP2S */ + { + { "rolQ", Ev, Ib, XX }, + { "rorQ", Ev, Ib, XX }, + { "rclQ", Ev, Ib, XX }, + { "rcrQ", Ev, Ib, XX }, + { "shlQ", Ev, Ib, XX }, + { "shrQ", Ev, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "sarQ", Ev, Ib, XX }, + }, + /* GRP2b_one */ + { + { "rolA", Eb, XX, XX }, + { "rorA", Eb, XX, XX }, + { "rclA", Eb, XX, XX }, + { "rcrA", Eb, XX, XX }, + { "shlA", Eb, XX, XX }, + { "shrA", Eb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "sarA", Eb, XX, XX }, + }, + /* GRP2S_one */ + { + { "rolQ", Ev, XX, XX }, + { "rorQ", Ev, XX, XX }, + { "rclQ", Ev, XX, XX }, + { "rcrQ", Ev, XX, XX }, + { "shlQ", Ev, XX, XX }, + { "shrQ", Ev, XX, XX }, + { "(bad)", XX, XX, XX}, + { "sarQ", Ev, XX, XX }, + }, + /* GRP2b_cl */ + { + { "rolA", Eb, CL, XX }, + { "rorA", Eb, CL, XX }, + { "rclA", Eb, CL, XX }, + { "rcrA", Eb, CL, XX }, + { "shlA", Eb, CL, XX }, + { "shrA", Eb, CL, XX }, + { "(bad)", XX, XX, XX }, + { "sarA", Eb, CL, XX }, + }, + /* GRP2S_cl */ + { + { "rolQ", Ev, CL, XX }, + { "rorQ", Ev, CL, XX }, + { "rclQ", Ev, CL, XX }, + { "rcrQ", Ev, CL, XX }, + { "shlQ", Ev, CL, XX }, + { "shrQ", Ev, CL, XX }, + { "(bad)", XX, XX, XX }, + { "sarQ", Ev, CL, XX } + }, + /* GRP3b */ + { + { "testA", Eb, Ib, XX }, + { "(bad)", Eb, XX, XX }, + { "notA", Eb, XX, XX }, + { "negA", Eb, XX, XX }, + { "mulB", AL, Eb, XX }, + { "imulB", AL, Eb, XX }, + { "divB", AL, Eb, XX }, + { "idivB", AL, Eb, XX } + }, + /* GRP3S */ + { + { "testQ", Ev, Iv, XX }, + { "(bad)", XX, XX, XX }, + { "notQ", Ev, XX, XX }, + { "negQ", Ev, XX, XX }, + { "mulS", eAX, Ev, XX }, + { "imulS", eAX, Ev, XX }, + { "divS", eAX, Ev, XX }, + { "idivS", eAX, Ev, XX }, + }, + /* GRP4 */ + { + { "incA", Eb, XX, XX }, + { "decA", Eb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP5 */ + { + { "incQ", Ev, XX, XX }, + { "decQ", Ev, XX, XX }, + { "callP", indirEv, XX, XX }, + { "lcallP", indirEv, XX, XX }, + { "jmpP", indirEv, XX, XX }, + { "ljmpP", indirEv, XX, XX }, + { "pushQ", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP6 */ + { + { "sldt", Ew, XX, XX }, + { "str", Ew, XX, XX }, + { "lldt", Ew, XX, XX }, + { "ltr", Ew, XX, XX }, + { "verr", Ew, XX, XX }, + { "verw", Ew, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX } + }, + /* GRP7 */ + { + { "sgdt", Ew, XX, XX }, + { "sidt", Ew, XX, XX }, + { "lgdt", Ew, XX, XX }, + { "lidt", Ew, XX, XX }, + { "smsw", Ew, XX, XX }, + { "(bad)", XX, XX, XX }, + { "lmsw", Ew, XX, XX }, + { "invlpg", Ew, XX, XX }, + }, + /* GRP8 */ + { + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "btQ", Ev, Ib, XX }, + { "btsQ", Ev, Ib, XX }, + { "btrQ", Ev, Ib, XX }, + { "btcQ", Ev, Ib, XX }, + }, + /* GRP9 */ + { + { "(bad)", XX, XX, XX }, + { "cmpxchg8b", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP10 */ + { + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psrlw", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "psraw", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "psllw", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP11 */ + { + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psrld", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "psrad", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "pslld", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP12 */ + { + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psrlq", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "psllq", MS, Ib, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRP13 */ + { + { "fxsave", Ev, XX, XX }, + { "fxrstor", Ev, XX, XX }, + { "ldmxcsr", Ev, XX, XX }, + { "stmxcsr", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "sfence", None, XX, XX }, + }, + /* GRP14 */ + { + { "prefetchnta", Ev, XX, XX }, + { "prefetcht0", Ev, XX, XX }, + { "prefetcht1", Ev, XX, XX }, + { "prefetcht2", Ev, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* GRPAMD */ + { + { "prefetch", Eb, XX, XX }, + { "prefetchw", Eb, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + } + +}; + +static const struct dis386 prefix_user_table[][2] = { + /* PREGRP0 */ + { + { "addps", XM, EX, XX }, + { "addss", XM, EX, XX }, + }, + /* PREGRP1 */ + { + { "", XM, EX, OPSIMD }, /* See OP_SIMD_SUFFIX */ + { "", XM, EX, OPSIMD }, + }, + /* PREGRP2 */ + { + { "cvtpi2ps", XM, EM, XX }, + { "cvtsi2ss", XM, Ev, XX }, + }, + /* PREGRP3 */ + { + { "cvtps2pi", MX, EX, XX }, + { "cvtss2si", Gv, EX, XX }, + }, + /* PREGRP4 */ + { + { "cvttps2pi", MX, EX, XX }, + { "cvttss2si", Gv, EX, XX }, + }, + /* PREGRP5 */ + { + { "divps", XM, EX, XX }, + { "divss", XM, EX, XX }, + }, + /* PREGRP6 */ + { + { "maxps", XM, EX, XX }, + { "maxss", XM, EX, XX }, + }, + /* PREGRP7 */ + { + { "minps", XM, EX, XX }, + { "minss", XM, EX, XX }, + }, + /* PREGRP8 */ + { + { "movups", XM, EX, XX }, + { "movss", XM, EX, XX }, + }, + /* PREGRP9 */ + { + { "movups", EX, XM, XX }, + { "movss", EX, XM, XX }, + }, + /* PREGRP10 */ + { + { "mulps", XM, EX, XX }, + { "mulss", XM, EX, XX }, + }, + /* PREGRP11 */ + { + { "rcpps", XM, EX, XX }, + { "rcpss", XM, EX, XX }, + }, + /* PREGRP12 */ + { + { "rsqrtps", XM, EX, XX }, + { "rsqrtss", XM, EX, XX }, + }, + /* PREGRP13 */ + { + { "sqrtps", XM, EX, XX }, + { "sqrtss", XM, EX, XX }, + }, + /* PREGRP14 */ + { + { "subps", XM, EX, XX }, + { "subss", XM, EX, XX }, + } +}; + +#define INTERNAL_DISASSEMBLER_ERROR "" + +static void +ckprefix () +{ + prefixes = 0; + used_prefixes = 0; + while (1) + { + FETCH_DATA (the_info, codep + 1); + switch (*codep) + { + case 0xf3: + prefixes |= PREFIX_REPZ; + break; + case 0xf2: + prefixes |= PREFIX_REPNZ; + break; + case 0xf0: + prefixes |= PREFIX_LOCK; + break; + case 0x2e: + prefixes |= PREFIX_CS; + break; + case 0x36: + prefixes |= PREFIX_SS; + break; + case 0x3e: + prefixes |= PREFIX_DS; + break; + case 0x26: + prefixes |= PREFIX_ES; + break; + case 0x64: + prefixes |= PREFIX_FS; + break; + case 0x65: + prefixes |= PREFIX_GS; + break; + case 0x66: + prefixes |= PREFIX_DATA; + break; + case 0x67: + prefixes |= PREFIX_ADDR; + break; + case FWAIT_OPCODE: + /* fwait is really an instruction. If there are prefixes + before the fwait, they belong to the fwait, *not* to the + following instruction. */ + if (prefixes) + { + prefixes |= PREFIX_FWAIT; + codep++; + return; + } + prefixes = PREFIX_FWAIT; + break; + default: + return; + } + codep++; + } +} + +/* Return the name of the prefix byte PREF, or NULL if PREF is not a + prefix byte. */ + +static const char * +prefix_name (pref, sizeflag) + int pref; + int sizeflag; +{ + switch (pref) + { + case 0xf3: + return "repz"; + case 0xf2: + return "repnz"; + case 0xf0: + return "lock"; + case 0x2e: + return "cs"; + case 0x36: + return "ss"; + case 0x3e: + return "ds"; + case 0x26: + return "es"; + case 0x64: + return "fs"; + case 0x65: + return "gs"; + case 0x66: + return (sizeflag & DFLAG) ? "data16" : "data32"; + case 0x67: + return (sizeflag & AFLAG) ? "addr16" : "addr32"; + case FWAIT_OPCODE: + return "fwait"; + default: + return NULL; + } +} + +static char op1out[100], op2out[100], op3out[100]; +static int op_ad, op_index[3]; +static unsigned int op_address[3]; +static unsigned int start_pc; + + +/* + * On the 386's of 1988, the maximum length of an instruction is 15 bytes. + * (see topic "Redundant prefixes" in the "Differences from 8086" + * section of the "Virtual 8086 Mode" chapter.) + * 'pc' should be the address of this instruction, it will + * be used to print the target address if this is a relative jump or call + * The function returns the length of this instruction in bytes. + */ + +static int print_insn_i386 + PARAMS ((bfd_vma pc, disassemble_info *info)); + +static char intel_syntax; +static char open_char; +static char close_char; +static char separator_char; +static char scale_char; + +int +print_insn_i386_att (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + intel_syntax = 0; + open_char = '('; + close_char = ')'; + separator_char = ','; + scale_char = ','; + + return print_insn_i386 (pc, info); +} + +int +print_insn_i386_intel (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + intel_syntax = 1; + open_char = '['; + close_char = ']'; + separator_char = '+'; + scale_char = '*'; + + return print_insn_i386 (pc, info); +} + +static int +print_insn_i386 (pc, info) + bfd_vma pc; + disassemble_info *info; +{ + const struct dis386 *dp; + int i; + int two_source_ops; + char *first, *second, *third; + int needcomma; + unsigned char need_modrm; + unsigned char uses_f3_prefix; + VOLATILE int sizeflag; + VOLATILE int orig_sizeflag; + + struct dis_private priv; + bfd_byte *inbuf = priv.the_buffer; + + if (info->mach == bfd_mach_i386_i386 + || info->mach == bfd_mach_i386_i386_intel_syntax) + sizeflag = AFLAG|DFLAG; + else if (info->mach == bfd_mach_i386_i8086) + sizeflag = 0; + else + abort (); + orig_sizeflag = sizeflag; + + /* The output looks better if we put 7 bytes on a line, since that + puts most long word instructions on a single line. */ + info->bytes_per_line = 7; + + info->private_data = (PTR) &priv; + priv.max_fetched = priv.the_buffer; + priv.insn_start = pc; + + obuf[0] = 0; + op1out[0] = 0; + op2out[0] = 0; + op3out[0] = 0; + + op_index[0] = op_index[1] = op_index[2] = -1; + + the_info = info; + start_pc = pc; + start_codep = inbuf; + codep = inbuf; + +#ifndef __KERNEL__ + if (setjmp (priv.bailout) != 0) + { + const char *name; + + /* Getting here means we tried for data but didn't get it. That + means we have an incomplete instruction of some sort. Just + print the first byte as a prefix or a .byte pseudo-op. */ + if (codep > inbuf) + { + name = prefix_name (inbuf[0], orig_sizeflag); + if (name != NULL) + (*info->fprintf_func) (info->stream, "%s", name); + else + { + /* Just print the first byte as a .byte instruction. */ + (*info->fprintf_func) (info->stream, ".byte 0x%x", + (unsigned int) inbuf[0]); + } + + return 1; + } + + return -1; + } +#endif + + ckprefix (); + + insn_codep = codep; + + FETCH_DATA (info, codep + 1); + two_source_ops = (*codep == 0x62) || (*codep == 0xc8); + + obufp = obuf; + + if ((prefixes & PREFIX_FWAIT) + && ((*codep < 0xd8) || (*codep > 0xdf))) + { + const char *name; + + /* fwait not followed by floating point instruction. Print the + first prefix, which is probably fwait itself. */ + name = prefix_name (inbuf[0], orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s", name); + return 1; + } + + if (*codep == 0x0f) + { + FETCH_DATA (info, codep + 2); + if (intel_syntax) + dp = &dis386_twobyte_intel[*++codep]; + else + dp = &dis386_twobyte_att[*++codep]; + need_modrm = twobyte_has_modrm[*codep]; + uses_f3_prefix = twobyte_uses_f3_prefix[*codep]; + } + else + { + if (intel_syntax) + dp = &dis386_intel[*codep]; + else + dp = &dis386_att[*codep]; + need_modrm = onebyte_has_modrm[*codep]; + uses_f3_prefix = 0; + } + codep++; + + if (!uses_f3_prefix && (prefixes & PREFIX_REPZ)) + { + oappend ("repz "); + used_prefixes |= PREFIX_REPZ; + } + if (prefixes & PREFIX_REPNZ) + { + oappend ("repnz "); + used_prefixes |= PREFIX_REPNZ; + } + if (prefixes & PREFIX_LOCK) + { + oappend ("lock "); + used_prefixes |= PREFIX_LOCK; + } + + if (prefixes & PREFIX_DATA) + sizeflag ^= DFLAG; + + if (prefixes & PREFIX_ADDR) + { + sizeflag ^= AFLAG; + if (sizeflag & AFLAG) + oappend ("addr32 "); + else + oappend ("addr16 "); + used_prefixes |= PREFIX_ADDR; + } + + if (need_modrm) + { + FETCH_DATA (info, codep + 1); + mod = (*codep >> 6) & 3; + reg = (*codep >> 3) & 7; + rm = *codep & 7; + } + + if (dp->name == NULL && dp->bytemode1 == FLOATCODE) + { + dofloat (sizeflag); + } + else + { + if (dp->name == NULL) + { + switch(dp->bytemode2) + { + case USE_GROUPS: + dp = &grps[dp->bytemode1][reg]; + break; + case USE_PREFIX_USER_TABLE: + dp = &prefix_user_table[dp->bytemode1][prefixes & PREFIX_REPZ ? 1 : 0]; + used_prefixes |= (prefixes & PREFIX_REPZ); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } + } + + putop (dp->name, sizeflag); + + obufp = op1out; + op_ad = 2; + if (dp->op1) + (*dp->op1)(dp->bytemode1, sizeflag); + + obufp = op2out; + op_ad = 1; + if (dp->op2) + (*dp->op2)(dp->bytemode2, sizeflag); + + obufp = op3out; + op_ad = 0; + if (dp->op3) + (*dp->op3)(dp->bytemode3, sizeflag); + } + + /* See if any prefixes were not used. If so, print the first one + separately. If we don't do this, we'll wind up printing an + instruction stream which does not precisely correspond to the + bytes we are disassembling. */ + if ((prefixes & ~used_prefixes) != 0) + { + const char *name; + + name = prefix_name (inbuf[0], orig_sizeflag); + if (name == NULL) + name = INTERNAL_DISASSEMBLER_ERROR; + (*info->fprintf_func) (info->stream, "%s", name); + return 1; + } + + obufp = obuf + strlen (obuf); + for (i = strlen (obuf); i < 6; i++) + oappend (" "); + oappend (" "); + (*info->fprintf_func) (info->stream, "%s", obuf); + + /* The enter and bound instructions are printed with operands in the same + order as the intel book; everything else is printed in reverse order. */ + if (intel_syntax || two_source_ops) + { + first = op1out; + second = op2out; + third = op3out; + op_ad = op_index[0]; + op_index[0] = op_index[2]; + op_index[2] = op_ad; + } + else + { + first = op3out; + second = op2out; + third = op1out; + } + needcomma = 0; + if (*first) + { + if (op_index[0] != -1) + (*info->print_address_func) ((bfd_vma) op_address[op_index[0]], info); + else + (*info->fprintf_func) (info->stream, "%s", first); + needcomma = 1; + } + if (*second) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[1] != -1) + (*info->print_address_func) ((bfd_vma) op_address[op_index[1]], info); + else + (*info->fprintf_func) (info->stream, "%s", second); + needcomma = 1; + } + if (*third) + { + if (needcomma) + (*info->fprintf_func) (info->stream, ","); + if (op_index[2] != -1) + (*info->print_address_func) ((bfd_vma) op_address[op_index[2]], info); + else + (*info->fprintf_func) (info->stream, "%s", third); + } + return codep - inbuf; +} + +static const char *float_mem_att[] = { + /* d8 */ + "fadds", + "fmuls", + "fcoms", + "fcomps", + "fsubs", + "fsubrs", + "fdivs", + "fdivrs", + /* d9 */ + "flds", + "(bad)", + "fsts", + "fstps", + "fldenv", + "fldcw", + "fNstenv", + "fNstcw", + /* da */ + "fiaddl", + "fimull", + "ficoml", + "ficompl", + "fisubl", + "fisubrl", + "fidivl", + "fidivrl", + /* db */ + "fildl", + "(bad)", + "fistl", + "fistpl", + "(bad)", + "fldt", + "(bad)", + "fstpt", + /* dc */ + "faddl", + "fmull", + "fcoml", + "fcompl", + "fsubl", + "fsubrl", + "fdivl", + "fdivrl", + /* dd */ + "fldl", + "(bad)", + "fstl", + "fstpl", + "frstor", + "(bad)", + "fNsave", + "fNstsw", + /* de */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* df */ + "fild", + "(bad)", + "fist", + "fistp", + "fbld", + "fildll", + "fbstp", + "fistpll", +}; + +static const char *float_mem_intel[] = { + /* d8 */ + "fadd", + "fmul", + "fcom", + "fcomp", + "fsub", + "fsubr", + "fdiv", + "fdivr", + /* d9 */ + "fld", + "(bad)", + "fst", + "fstp", + "fldenv", + "fldcw", + "fNstenv", + "fNstcw", + /* da */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* db */ + "fild", + "(bad)", + "fist", + "fistp", + "(bad)", + "fld", + "(bad)", + "fstp", + /* dc */ + "fadd", + "fmul", + "fcom", + "fcomp", + "fsub", + "fsubr", + "fdiv", + "fdivr", + /* dd */ + "fld", + "(bad)", + "fst", + "fstp", + "frstor", + "(bad)", + "fNsave", + "fNstsw", + /* de */ + "fiadd", + "fimul", + "ficom", + "ficomp", + "fisub", + "fisubr", + "fidiv", + "fidivr", + /* df */ + "fild", + "(bad)", + "fist", + "fistp", + "fbld", + "fild", + "fbstp", + "fistpll", +}; + +#define ST OP_ST, 0 +#define STi OP_STi, 0 + +#define FGRPd9_2 NULL, NULL, 0, NULL, 0, NULL, 0 +#define FGRPd9_4 NULL, NULL, 1, NULL, 0, NULL, 0 +#define FGRPd9_5 NULL, NULL, 2, NULL, 0, NULL, 0 +#define FGRPd9_6 NULL, NULL, 3, NULL, 0, NULL, 0 +#define FGRPd9_7 NULL, NULL, 4, NULL, 0, NULL, 0 +#define FGRPda_5 NULL, NULL, 5, NULL, 0, NULL, 0 +#define FGRPdb_4 NULL, NULL, 6, NULL, 0, NULL, 0 +#define FGRPde_3 NULL, NULL, 7, NULL, 0, NULL, 0 +#define FGRPdf_4 NULL, NULL, 8, NULL, 0, NULL, 0 + +static const struct dis386 float_reg[][8] = { + /* d8 */ + { + { "fadd", ST, STi, XX }, + { "fmul", ST, STi, XX }, + { "fcom", STi, XX, XX }, + { "fcomp", STi, XX, XX }, + { "fsub", ST, STi, XX }, + { "fsubr", ST, STi, XX }, + { "fdiv", ST, STi, XX }, + { "fdivr", ST, STi, XX }, + }, + /* d9 */ + { + { "fld", STi, XX, XX }, + { "fxch", STi, XX, XX }, + { FGRPd9_2 }, + { "(bad)", XX, XX, XX }, + { FGRPd9_4 }, + { FGRPd9_5 }, + { FGRPd9_6 }, + { FGRPd9_7 }, + }, + /* da */ + { + { "fcmovb", ST, STi, XX }, + { "fcmove", ST, STi, XX }, + { "fcmovbe",ST, STi, XX }, + { "fcmovu", ST, STi, XX }, + { "(bad)", XX, XX, XX }, + { FGRPda_5 }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* db */ + { + { "fcmovnb",ST, STi, XX }, + { "fcmovne",ST, STi, XX }, + { "fcmovnbe",ST, STi, XX }, + { "fcmovnu",ST, STi, XX }, + { FGRPdb_4 }, + { "fucomi", ST, STi, XX }, + { "fcomi", ST, STi, XX }, + { "(bad)", XX, XX, XX }, + }, + /* dc */ + { + { "fadd", STi, ST, XX }, + { "fmul", STi, ST, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, +#if UNIXWARE_COMPAT + { "fsub", STi, ST, XX }, + { "fsubr", STi, ST, XX }, + { "fdiv", STi, ST, XX }, + { "fdivr", STi, ST, XX }, +#else + { "fsubr", STi, ST, XX }, + { "fsub", STi, ST, XX }, + { "fdivr", STi, ST, XX }, + { "fdiv", STi, ST, XX }, +#endif + }, + /* dd */ + { + { "ffree", STi, XX, XX }, + { "(bad)", XX, XX, XX }, + { "fst", STi, XX, XX }, + { "fstp", STi, XX, XX }, + { "fucom", STi, XX, XX }, + { "fucomp", STi, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + }, + /* de */ + { + { "faddp", STi, ST, XX }, + { "fmulp", STi, ST, XX }, + { "(bad)", XX, XX, XX }, + { FGRPde_3 }, +#if UNIXWARE_COMPAT + { "fsubp", STi, ST, XX }, + { "fsubrp", STi, ST, XX }, + { "fdivp", STi, ST, XX }, + { "fdivrp", STi, ST, XX }, +#else + { "fsubrp", STi, ST, XX }, + { "fsubp", STi, ST, XX }, + { "fdivrp", STi, ST, XX }, + { "fdivp", STi, ST, XX }, +#endif + }, + /* df */ + { + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { "(bad)", XX, XX, XX }, + { FGRPdf_4 }, + { "fucomip",ST, STi, XX }, + { "fcomip", ST, STi, XX }, + { "(bad)", XX, XX, XX }, + }, +}; + + +static char *fgrps[][8] = { + /* d9_2 0 */ + { + "fnop","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* d9_4 1 */ + { + "fchs","fabs","(bad)","(bad)","ftst","fxam","(bad)","(bad)", + }, + + /* d9_5 2 */ + { + "fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz","(bad)", + }, + + /* d9_6 3 */ + { + "f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp", + }, + + /* d9_7 4 */ + { + "fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos", + }, + + /* da_5 5 */ + { + "(bad)","fucompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* db_4 6 */ + { + "feni(287 only)","fdisi(287 only)","fNclex","fNinit", + "fNsetpm(287 only)","(bad)","(bad)","(bad)", + }, + + /* de_3 7 */ + { + "(bad)","fcompp","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, + + /* df_4 8 */ + { + "fNstsw","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)","(bad)", + }, +}; + +static void +dofloat (sizeflag) + int sizeflag; +{ + const struct dis386 *dp; + unsigned char floatop; + + floatop = codep[-1]; + + if (mod != 3) + { + if (intel_syntax) + putop (float_mem_intel[(floatop - 0xd8 ) * 8 + reg], sizeflag); + else + putop (float_mem_att[(floatop - 0xd8 ) * 8 + reg], sizeflag); + obufp = op1out; + if (floatop == 0xdb) + OP_E (x_mode, sizeflag); + else if (floatop == 0xdd) + OP_E (d_mode, sizeflag); + else + OP_E (v_mode, sizeflag); + return; + } + codep++; + + dp = &float_reg[floatop - 0xd8][reg]; + if (dp->name == NULL) + { + putop (fgrps[dp->bytemode1][rm], sizeflag); + + /* instruction fnstsw is only one with strange arg */ + if (floatop == 0xdf && codep[-1] == 0xe0) + strcpy (op1out, names16[0]); + } + else + { + putop (dp->name, sizeflag); + + obufp = op1out; + if (dp->op1) + (*dp->op1)(dp->bytemode1, sizeflag); + obufp = op2out; + if (dp->op2) + (*dp->op2)(dp->bytemode2, sizeflag); + } +} + +/* ARGSUSED */ +static void +OP_ST (ignore, sizeflag) + int ignore ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + oappend ("%st"); +} + +/* ARGSUSED */ +static void +OP_STi (ignore, sizeflag) + int ignore ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + sprintf (scratchbuf, "%%st(%d)", rm); + oappend (scratchbuf); +} + + +/* capital letters in template are macros */ +static void +putop (template, sizeflag) + const char *template; + int sizeflag; +{ + const char *p; + + for (p = template; *p; p++) + { + switch (*p) + { + default: + *obufp++ = *p; + break; + case 'A': + if (intel_syntax) + break; + if (mod != 3 +#ifdef SUFFIX_ALWAYS + || (sizeflag & SUFFIX_ALWAYS) +#endif + ) + *obufp++ = 'b'; + break; + case 'B': + if (intel_syntax) + break; +#ifdef SUFFIX_ALWAYS + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'b'; +#endif + break; + case 'E': /* For jcxz/jecxz */ + if (sizeflag & AFLAG) + *obufp++ = 'e'; + break; + case 'L': + if (intel_syntax) + break; +#ifdef SUFFIX_ALWAYS + if (sizeflag & SUFFIX_ALWAYS) + *obufp++ = 'l'; +#endif + break; + case 'N': + if ((prefixes & PREFIX_FWAIT) == 0) + *obufp++ = 'n'; + else + used_prefixes |= PREFIX_FWAIT; + break; + case 'P': + if (intel_syntax) + break; + if ((prefixes & PREFIX_DATA) +#ifdef SUFFIX_ALWAYS + || (sizeflag & SUFFIX_ALWAYS) +#endif + ) + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + break; + case 'Q': + if (intel_syntax) + break; + if (mod != 3 +#ifdef SUFFIX_ALWAYS + || (sizeflag & SUFFIX_ALWAYS) +#endif + ) + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + break; + case 'R': + if (intel_syntax) + { + if (sizeflag & DFLAG) + { + *obufp++ = 'd'; + *obufp++ = 'q'; + } + else + { + *obufp++ = 'w'; + *obufp++ = 'd'; + } + } + else + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 'S': + if (intel_syntax) + break; +#ifdef SUFFIX_ALWAYS + if (sizeflag & SUFFIX_ALWAYS) + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } +#endif + break; + case 'W': + /* operand size flag for cwtl, cbtw */ + if (sizeflag & DFLAG) + *obufp++ = 'w'; + else + *obufp++ = 'b'; + if (intel_syntax) + { + if (sizeflag & DFLAG) + { + *obufp++ = 'd'; + *obufp++ = 'e'; + } + else + { + *obufp++ = 'w'; + } + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + } + } + *obufp = 0; +} + +static void +oappend (s) + const char *s; +{ + strcpy (obufp, s); + obufp += strlen (s); +} + +static void +append_seg () +{ + if (prefixes & PREFIX_CS) + { + oappend ("%cs:"); + used_prefixes |= PREFIX_CS; + } + if (prefixes & PREFIX_DS) + { + oappend ("%ds:"); + used_prefixes |= PREFIX_DS; + } + if (prefixes & PREFIX_SS) + { + oappend ("%ss:"); + used_prefixes |= PREFIX_SS; + } + if (prefixes & PREFIX_ES) + { + oappend ("%es:"); + used_prefixes |= PREFIX_ES; + } + if (prefixes & PREFIX_FS) + { + oappend ("%fs:"); + used_prefixes |= PREFIX_FS; + } + if (prefixes & PREFIX_GS) + { + oappend ("%gs:"); + used_prefixes |= PREFIX_GS; + } +} + +static void +OP_indirE (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (!intel_syntax) + oappend ("*"); + OP_E (bytemode, sizeflag); +} + +static void +OP_E (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + int disp; + + /* skip mod/rm byte */ + codep++; + + if (mod == 3) + { + switch (bytemode) + { + case b_mode: + oappend (names8[rm]); + break; + case w_mode: + oappend (names16[rm]); + break; + case d_mode: + oappend (names32[rm]); + break; + case v_mode: + if (sizeflag & DFLAG) + oappend (names32[rm]); + else + oappend (names16[rm]); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case 0: + if ( !(codep[-2] == 0xAE && codep[-1] == 0xF8 /* sfence */)) + BadOp(); /* bad sfence,lea,lds,les,lfs,lgs,lss modrm */ + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } + return; + } + + disp = 0; + append_seg (); + + if (sizeflag & AFLAG) /* 32 bit address mode */ + { + int havesib; + int havebase; + int base; + int index = 0; + int scale = 0; + + havesib = 0; + havebase = 1; + base = rm; + + if (base == 4) + { + havesib = 1; + FETCH_DATA (the_info, codep + 1); + scale = (*codep >> 6) & 3; + index = (*codep >> 3) & 7; + base = *codep & 7; + codep++; + } + + switch (mod) + { + case 0: + if (base == 5) + { + havebase = 0; + disp = get32 (); + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case 2: + disp = get32 (); + break; + } + + if (!intel_syntax) + if (mod != 0 || base == 5) + { + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + } + + if (havebase || (havesib && (index != 4 || scale != 0))) + { + if (intel_syntax) + { + switch (bytemode) + { + case b_mode: + oappend("BYTE PTR "); + break; + case w_mode: + oappend("WORD PTR "); + break; + case v_mode: + oappend("DWORD PTR "); + break; + case d_mode: + oappend("QWORD PTR "); + break; + case x_mode: + oappend("XWORD PTR "); + break; + default: + break; + } + } + *obufp++ = open_char; + *obufp = '\0'; + if (havebase) + oappend (names32[base]); + if (havesib) + { + if (index != 4) + { + if (intel_syntax) + { + if (havebase) + { + *obufp++ = separator_char; + *obufp = '\0'; + } + sprintf (scratchbuf, "%s", names32[index]); + } + else + sprintf (scratchbuf, ",%s", names32[index]); + oappend (scratchbuf); + } + if (!intel_syntax + || (intel_syntax + && bytemode != b_mode + && bytemode != w_mode + && bytemode != v_mode)) + { + *obufp++ = scale_char; + *obufp = '\0'; + sprintf (scratchbuf, "%d", 1 << scale); + oappend (scratchbuf); + } + } + if (intel_syntax) + if (mod != 0 || base == 5) + { + /* Don't print zero displacements */ + if (disp > 0) + { + sprintf (scratchbuf, "+%d", disp); + oappend (scratchbuf); + } + else if (disp < 0) + { + sprintf (scratchbuf, "%d", disp); + oappend (scratchbuf); + } + } + + *obufp++ = close_char; + *obufp = '\0'; + } + else if (intel_syntax) + { + if (mod != 0 || base == 5) + { + if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS)) + ; + else + { + oappend (names_seg[3]); + oappend (":"); + } + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); + } + } + } + else + { /* 16 bit address mode */ + switch (mod) + { + case 0: + if (rm == 6) + { + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + } + break; + case 1: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case 2: + disp = get16 (); + if ((disp & 0x8000) != 0) + disp -= 0x10000; + break; + } + + if (!intel_syntax) + if (mod != 0 || rm == 6) + { + sprintf (scratchbuf, "%d", disp); + oappend (scratchbuf); + } + + if (mod != 0 || rm != 6) + { + *obufp++ = open_char; + *obufp = '\0'; + oappend (index16[rm]); + *obufp++ = close_char; + *obufp = '\0'; + } + } +} + +static void +OP_G (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + switch (bytemode) + { + case b_mode: + oappend (names8[reg]); + break; + case w_mode: + oappend (names16[reg]); + break; + case d_mode: + oappend (names32[reg]); + break; + case v_mode: + if (sizeflag & DFLAG) + oappend (names32[reg]); + else + oappend (names16[reg]); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + break; + } +} + +static int +get32 () +{ + int x = 0; + + FETCH_DATA (the_info, codep + 4); + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + x |= (*codep++ & 0xff) << 16; + x |= (*codep++ & 0xff) << 24; + return x; +} + +static int +get16 () +{ + int x = 0; + + FETCH_DATA (the_info, codep + 2); + x = *codep++ & 0xff; + x |= (*codep++ & 0xff) << 8; + return x; +} + +static void +set_op (op) + unsigned int op; +{ + op_index[op_ad] = op_ad; + op_address[op_ad] = op; +} + +static void +OP_REG (code, sizeflag) + int code; + int sizeflag; +{ + const char *s; + + switch (code) + { + case indir_dx_reg: + s = "(%dx)"; + break; + case ax_reg: case cx_reg: case dx_reg: case bx_reg: + case sp_reg: case bp_reg: case si_reg: case di_reg: + s = names16[code - ax_reg]; + break; + case es_reg: case ss_reg: case cs_reg: + case ds_reg: case fs_reg: case gs_reg: + s = names_seg[code - es_reg]; + break; + case al_reg: case ah_reg: case cl_reg: case ch_reg: + case dl_reg: case dh_reg: case bl_reg: case bh_reg: + s = names8[code - al_reg]; + break; + case eAX_reg: case eCX_reg: case eDX_reg: case eBX_reg: + case eSP_reg: case eBP_reg: case eSI_reg: case eDI_reg: + if (sizeflag & DFLAG) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + s = INTERNAL_DISASSEMBLER_ERROR; + break; + } + oappend (s); +} + +static void +OP_I (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + int op; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++ & 0xff; + break; + case v_mode: + if (sizeflag & DFLAG) + op = get32 (); + else + op = get16 (); + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case w_mode: + op = get16 (); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + + if (intel_syntax) + sprintf (scratchbuf, "0x%x", op); + else + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); + scratchbuf[0] = '\0'; +} + +static void +OP_sI (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + int op; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + op = *codep++; + if ((op & 0x80) != 0) + op -= 0x100; + break; + case v_mode: + if (sizeflag & DFLAG) + op = get32 (); + else + { + op = get16(); + if ((op & 0x8000) != 0) + op -= 0x10000; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + case w_mode: + op = get16 (); + if ((op & 0x8000) != 0) + op -= 0x10000; + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + if (intel_syntax) + sprintf (scratchbuf, "%d", op); + else + sprintf (scratchbuf, "$0x%x", op); + oappend (scratchbuf); +} + +static void +OP_J (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + int disp; + int mask = -1; + + switch (bytemode) + { + case b_mode: + FETCH_DATA (the_info, codep + 1); + disp = *codep++; + if ((disp & 0x80) != 0) + disp -= 0x100; + break; + case v_mode: + if (sizeflag & DFLAG) + disp = get32 (); + else + { + disp = get16 (); + /* for some reason, a data16 prefix on a jump instruction + means that the pc is masked to 16 bits after the + displacement is added! */ + mask = 0xffff; + } + used_prefixes |= (prefixes & PREFIX_DATA); + break; + default: + oappend (INTERNAL_DISASSEMBLER_ERROR); + return; + } + disp = (start_pc + codep - start_codep + disp) & mask; + set_op (disp); + sprintf (scratchbuf, "0x%x", disp); + oappend (scratchbuf); +} + +/* ARGSUSED */ +static void +OP_SEG (dummy, sizeflag) + int dummy ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + static char *sreg[] = { + "%es","%cs","%ss","%ds","%fs","%gs","%?","%?", + }; + + oappend (sreg[reg]); +} + +/* ARGSUSED */ +static void +OP_DIR (dummy, sizeflag) + int dummy ATTRIBUTE_UNUSED; + int sizeflag; +{ + int seg, offset; + + if (sizeflag & DFLAG) + { + offset = get32 (); + seg = get16 (); + } + else + { + offset = get16 (); + seg = get16 (); + } + used_prefixes |= (prefixes & PREFIX_DATA); + sprintf (scratchbuf, "$0x%x,$0x%x", seg, offset); + oappend (scratchbuf); +} + +/* ARGSUSED */ +static void +OP_OFF (ignore, sizeflag) + int ignore ATTRIBUTE_UNUSED; + int sizeflag; +{ + int off; + + append_seg (); + + if (sizeflag & AFLAG) + off = get32 (); + else + off = get16 (); + + if (intel_syntax) + { + if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS + | PREFIX_ES | PREFIX_FS | PREFIX_GS))) + { + oappend (names_seg[3]); + oappend (":"); + } + } + sprintf (scratchbuf, "0x%x", off); + oappend (scratchbuf); +} + +static void +ptr_reg (code, sizeflag) + int code; + int sizeflag; +{ + const char *s; + oappend ("("); + if (sizeflag & AFLAG) + s = names32[code - eAX_reg]; + else + s = names16[code - eAX_reg]; + oappend (s); + oappend (")"); +} + +static void +OP_ESreg (code, sizeflag) + int code; + int sizeflag; +{ + oappend ("%es:"); + ptr_reg (code, sizeflag); +} + +static void +OP_DSreg (code, sizeflag) + int code; + int sizeflag; +{ + if ((prefixes + & (PREFIX_CS + | PREFIX_DS + | PREFIX_SS + | PREFIX_ES + | PREFIX_FS + | PREFIX_GS)) == 0) + prefixes |= PREFIX_DS; + append_seg(); + ptr_reg (code, sizeflag); +} + +/* ARGSUSED */ +static void +OP_C (dummy, sizeflag) + int dummy ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + sprintf (scratchbuf, "%%cr%d", reg); + oappend (scratchbuf); +} + +/* ARGSUSED */ +static void +OP_D (dummy, sizeflag) + int dummy ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + sprintf (scratchbuf, "%%db%d", reg); + oappend (scratchbuf); +} + +/* ARGSUSED */ +static void +OP_T (dummy, sizeflag) + int dummy ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + sprintf (scratchbuf, "%%tr%d", reg); + oappend (scratchbuf); +} + +static void +OP_Rd (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (mod == 3) + OP_E (bytemode, sizeflag); + else + BadOp(); +} + +static void +OP_MMX (ignore, sizeflag) + int ignore ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + sprintf (scratchbuf, "%%mm%d", reg); + oappend (scratchbuf); +} + +static void +OP_XMM (bytemode, sizeflag) + int bytemode ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + sprintf (scratchbuf, "%%xmm%d", reg); + oappend (scratchbuf); +} + +static void +OP_EM (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (mod != 3) + { + OP_E (bytemode, sizeflag); + return; + } + + codep++; + sprintf (scratchbuf, "%%mm%d", rm); + oappend (scratchbuf); +} + +static void +OP_EX (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (mod != 3) + { + OP_E (bytemode, sizeflag); + return; + } + + codep++; + sprintf (scratchbuf, "%%xmm%d", rm); + oappend (scratchbuf); +} + +static void +OP_MS (bytemode, sizeflag) + int bytemode; + int sizeflag; +{ + if (mod == 3) + OP_EM (bytemode, sizeflag); + else + BadOp(); +} + +static const char *Suffix3DNow[] = { +/* 00 */ NULL, NULL, NULL, NULL, +/* 04 */ NULL, NULL, NULL, NULL, +/* 08 */ NULL, NULL, NULL, NULL, +/* 0C */ "pi2fw", "pi2fd", NULL, NULL, +/* 10 */ NULL, NULL, NULL, NULL, +/* 14 */ NULL, NULL, NULL, NULL, +/* 18 */ NULL, NULL, NULL, NULL, +/* 1C */ "pf2iw", "pf2id", NULL, NULL, +/* 20 */ NULL, NULL, NULL, NULL, +/* 24 */ NULL, NULL, NULL, NULL, +/* 28 */ NULL, NULL, NULL, NULL, +/* 2C */ NULL, NULL, NULL, NULL, +/* 30 */ NULL, NULL, NULL, NULL, +/* 34 */ NULL, NULL, NULL, NULL, +/* 38 */ NULL, NULL, NULL, NULL, +/* 3C */ NULL, NULL, NULL, NULL, +/* 40 */ NULL, NULL, NULL, NULL, +/* 44 */ NULL, NULL, NULL, NULL, +/* 48 */ NULL, NULL, NULL, NULL, +/* 4C */ NULL, NULL, NULL, NULL, +/* 50 */ NULL, NULL, NULL, NULL, +/* 54 */ NULL, NULL, NULL, NULL, +/* 58 */ NULL, NULL, NULL, NULL, +/* 5C */ NULL, NULL, NULL, NULL, +/* 60 */ NULL, NULL, NULL, NULL, +/* 64 */ NULL, NULL, NULL, NULL, +/* 68 */ NULL, NULL, NULL, NULL, +/* 6C */ NULL, NULL, NULL, NULL, +/* 70 */ NULL, NULL, NULL, NULL, +/* 74 */ NULL, NULL, NULL, NULL, +/* 78 */ NULL, NULL, NULL, NULL, +/* 7C */ NULL, NULL, NULL, NULL, +/* 80 */ NULL, NULL, NULL, NULL, +/* 84 */ NULL, NULL, NULL, NULL, +/* 88 */ NULL, NULL, "pfnacc", NULL, +/* 8C */ NULL, NULL, "pfpnacc", NULL, +/* 90 */ "pfcmpge", NULL, NULL, NULL, +/* 94 */ "pfmin", NULL, "pfrcp", "pfrsqrt", +/* 98 */ NULL, NULL, "pfsub", NULL, +/* 9C */ NULL, NULL, "pfadd", NULL, +/* A0 */ "pfcmpgt", NULL, NULL, NULL, +/* A4 */ "pfmax", NULL, "pfrcpit1", "pfrsqit1", +/* A8 */ NULL, NULL, "pfsubr", NULL, +/* AC */ NULL, NULL, "pfacc", NULL, +/* B0 */ "pfcmpeq", NULL, NULL, NULL, +/* B4 */ "pfmul", NULL, "pfrcpit2", "pfmulhrw", +/* B8 */ NULL, NULL, NULL, "pswapd", +/* BC */ NULL, NULL, NULL, "pavgusb", +/* C0 */ NULL, NULL, NULL, NULL, +/* C4 */ NULL, NULL, NULL, NULL, +/* C8 */ NULL, NULL, NULL, NULL, +/* CC */ NULL, NULL, NULL, NULL, +/* D0 */ NULL, NULL, NULL, NULL, +/* D4 */ NULL, NULL, NULL, NULL, +/* D8 */ NULL, NULL, NULL, NULL, +/* DC */ NULL, NULL, NULL, NULL, +/* E0 */ NULL, NULL, NULL, NULL, +/* E4 */ NULL, NULL, NULL, NULL, +/* E8 */ NULL, NULL, NULL, NULL, +/* EC */ NULL, NULL, NULL, NULL, +/* F0 */ NULL, NULL, NULL, NULL, +/* F4 */ NULL, NULL, NULL, NULL, +/* F8 */ NULL, NULL, NULL, NULL, +/* FC */ NULL, NULL, NULL, NULL, +}; + +static void +OP_3DNowSuffix (bytemode, sizeflag) + int bytemode ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + const char *mnemonic; + + FETCH_DATA (the_info, codep + 1); + /* AMD 3DNow! instructions are specified by an opcode suffix in the + place where an 8-bit immediate would normally go. ie. the last + byte of the instruction. */ + obufp = obuf + strlen(obuf); + mnemonic = Suffix3DNow[*codep++ & 0xff]; + if (mnemonic) + oappend (mnemonic); + else + { + /* Since a variable sized modrm/sib chunk is between the start + of the opcode (0x0f0f) and the opcode suffix, we need to do + all the modrm processing first, and don't know until now that + we have a bad opcode. This necessitates some cleaning up. */ + op1out[0] = '\0'; + op2out[0] = '\0'; + BadOp(); + } +} + + +static const char *simd_cmp_op [] = { + "eq", + "lt", + "le", + "unord", + "neq", + "nlt", + "nle", + "ord" +}; + +static void +OP_SIMD_Suffix (bytemode, sizeflag) + int bytemode ATTRIBUTE_UNUSED; + int sizeflag ATTRIBUTE_UNUSED; +{ + unsigned int cmp_type; + + FETCH_DATA (the_info, codep + 1); + obufp = obuf + strlen(obuf); + cmp_type = *codep++ & 0xff; + if (cmp_type < 8) + { + sprintf (scratchbuf, "cmp%s%cs", + simd_cmp_op[cmp_type], + prefixes & PREFIX_REPZ ? 's' : 'p'); + used_prefixes |= (prefixes & PREFIX_REPZ); + oappend (scratchbuf); + } + else + { + /* We have a bad extension byte. Clean up. */ + op1out[0] = '\0'; + op2out[0] = '\0'; + BadOp(); + } +} + +static void +SIMD_Fixup (extrachar, sizeflag) + int extrachar; + int sizeflag ATTRIBUTE_UNUSED; +{ + /* Change movlps/movhps to movhlps/movlhps for 2 register operand + forms of these instructions. */ + if (mod == 3) + { + char *p = obuf + strlen(obuf); + *(p+1) = '\0'; + *p = *(p-1); + *(p-1) = *(p-2); + *(p-2) = *(p-3); + *(p-3) = extrachar; + } +} + +static void BadOp (void) +{ + codep = insn_codep + 1; /* throw away prefixes and 1st. opcode byte */ + oappend ("(bad)"); +} diff -rNu linux-2.4.7/linux/arch/i386/kdb/kdba_bp.c linux-2.4-xfs/linux/arch/i386/kdb/kdba_bp.c --- linux-2.4.7/linux/arch/i386/kdb/kdba_bp.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/kdb/kdba_bp.c Thu Feb 22 15:09:04 2001 @@ -0,0 +1,777 @@ +/* + * Kernel Debugger Architecture Dependent Breakpoint Handling + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * + * See the file LIA-COPYRIGHT for additional information. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Richard Bass 1999/07/20 + * Many bug fixes and enhancements. + * Scott Foehner + * Port to ia64 + * Scott Lurndal 1999/12/12 + * v1.0 restructuring. + * Keith Owens 2000/05/23 + * KDB v1.2 + */ + +#include +#include +#include +#include +#include +#include +#include + + +static char *kdba_rwtypes[] = { "Instruction(Register)", "Data Write", + "I/O", "Data Access"}; + +/* + * Table describing processor architecture hardware + * breakpoint registers. + */ + +kdbhard_bp_t kdb_hardbreaks[KDB_MAXHARDBPT]; + +/* + * kdba_db_trap + * + * Perform breakpoint processing upon entry to the + * processor debugger fault. Determine and print + * the active breakpoint. + * + * Parameters: + * ef Exception frame containing machine register state + * error Error number passed to kdb. + * Outputs: + * None. + * Returns: + * KDB_DB_BPT Standard instruction or data breakpoint encountered + * KDB_DB_SS Single Step fault ('ss' command or end of 'ssb' command) + * KDB_DB_SSB Single Step fault, caller should continue ('ssb' command) + * KDB_DB_SSBPT Single step over breakpoint + * KDB_DB_NOBPT No existing kdb breakpoint matches this debug exception + * Locking: + * None. + * Remarks: + * Yup, there be goto's here. + * + * If multiple processors receive debug exceptions simultaneously, + * one may be waiting at the kdb fence in kdb() while the user + * issues a 'bc' command to clear the breakpoint the processor + * which is waiting has already encountered. If this is the case, + * the debug registers will no longer match any entry in the + * breakpoint table, and we'll return the value KDB_DB_NOBPT. + * This can cause a panic in die_if_kernel(). It is safer to + * disable the breakpoint (bd), go until all processors are past + * the breakpoint then clear the breakpoint (bc). This code + * recognises a breakpoint even when disabled but not when it has + * been cleared. + * + * WARNING: This routine clears the debug state. It should be called + * once per debug and the result cached. + */ + +kdb_dbtrap_t +kdba_db_trap(kdb_eframe_t ef, int error_unused) +{ + kdb_machreg_t dr6; + kdb_machreg_t dr7; + int rw, reg; + int i; + kdb_dbtrap_t rv = KDB_DB_BPT; + kdb_bp_t *bp; + + dr6 = kdba_getdr6(); + dr7 = kdba_getdr7(); + + if (KDB_DEBUG(BP)) + kdb_printf("kdb: dr6 0x%lx dr7 0x%lx\n", dr6, dr7); + if (dr6 & DR6_BS) { + if (KDB_STATE(SSBPT)) { + if (KDB_DEBUG(BP)) + kdb_printf("ssbpt\n"); + KDB_STATE_CLEAR(SSBPT); + for(i=0,bp=kdb_breakpoints; + i < KDB_MAXBPT; + i++, bp++) { + if (KDB_DEBUG(BP)) + kdb_printf("bp 0x%p enabled %d delayed %d global %d cpu %d\n", + bp, bp->bp_enabled, bp->bp_delayed, bp->bp_global, bp->bp_cpu); + if (!bp->bp_enabled) + continue; + if (!bp->bp_global && bp->bp_cpu != smp_processor_id()) + continue; + if (KDB_DEBUG(BP)) + kdb_printf("bp for this cpu\n"); + if (bp->bp_delayed) { + bp->bp_delayed = 0; + if (KDB_DEBUG(BP)) + kdb_printf("kdba_installbp\n"); + kdba_installbp(ef, bp); + if (!KDB_STATE(DOING_SS)) { + ef->eflags &= ~EF_TF; + return(KDB_DB_SSBPT); + } + break; + } + } + if (i == KDB_MAXBPT) { + kdb_printf("kdb: Unable to find delayed breakpoint\n"); + } + if (!KDB_STATE(DOING_SS)) { + ef->eflags &= ~EF_TF; + return(KDB_DB_NOBPT); + } + /* FALLTHROUGH */ + } + + /* + * KDB_STATE_DOING_SS is set when the kernel debugger is using + * the processor trap flag to single-step a processor. If a + * single step trap occurs and this flag is clear, the SS trap + * will be ignored by KDB and the kernel will be allowed to deal + * with it as necessary (e.g. for ptrace). + */ + if (!KDB_STATE(DOING_SS)) + goto unknown; + + /* single step */ + rv = KDB_DB_SS; /* Indicate single step */ + if (KDB_STATE(DOING_SSB)) { + unsigned char op1, op2 = 0; + + kdb_id1(ef->eip); + op1 = (unsigned char)kdba_getword(ef->eip, sizeof(op1)); + if (op1 == 0x0f) { + op2 = (unsigned char)kdba_getword(ef->eip+1, sizeof(op2)); + } + if (((op1&0xf0) == 0xe0) /* short disp jumps */ + || ((op1&0xf0) == 0x70) /* Misc. jumps */ + || (op1 == 0xc2) /* ret */ + || (op1 == 0x9a) /* call */ + || ((op1&0xf8) == 0xc8) /* enter, leave, iret, int, */ + || ((op1 == 0x0f) + && ((op2&0xf0)== 0x80))) { + /* + * End the ssb command here. + */ + KDB_STATE_CLEAR(DOING_SSB); + KDB_STATE_CLEAR(DOING_SS); + } else { + rv = KDB_DB_SSB; /* Indicate ssb - dismiss immediately */ + } + } else { + /* + * Print current insn + */ + kdb_printf("SS trap at "); + kdb_symbol_print(ef->eip, NULL, KDB_SP_DEFAULT|KDB_SP_NEWLINE); + kdb_id1(ef->eip); + KDB_STATE_CLEAR(DOING_SS); + } + + if (rv != KDB_DB_SSB) + ef->eflags &= ~EF_TF; + } + + if (dr6 & DR6_B0) { + rw = DR7_RW0(dr7); + reg = 0; + goto handle; + } + + if (dr6 & DR6_B1) { + rw = DR7_RW1(dr7); + reg = 1; + goto handle; + } + + if (dr6 & DR6_B2) { + rw = DR7_RW2(dr7); + reg = 2; + goto handle; + } + + if (dr6 & DR6_B3) { + rw = DR7_RW3(dr7); + reg = 3; + goto handle; + } + + if (rv > 0) + goto handled; + + goto unknown; /* dismiss */ + +handle: + /* + * Set Resume Flag + */ + ef->eflags |= EF_RF; + + /* + * Determine which breakpoint was encountered. + */ + for(i=0, bp=kdb_breakpoints; ibp_free) + && (bp->bp_global || bp->bp_cpu == smp_processor_id()) + && (bp->bp_hard) + && (bp->bp_hard->bph_reg == reg)) { + /* + * Hit this breakpoint. + */ + kdb_printf("%s breakpoint #%d at " kdb_bfd_vma_fmt "\n", + kdba_rwtypes[rw], + i, bp->bp_addr); + + /* + * For an instruction breakpoint, disassemble + * the current instruction. + */ + if (rw == 0) { + kdb_id1(ef->eip); + } + + goto handled; + } + } + +unknown: + ef->eflags |= EF_RF; /* Supress further faults */ + rv = KDB_DB_NOBPT; /* Cause kdb() to return */ + +handled: + + /* + * Clear the pending exceptions. + */ + kdba_putdr6(0); + + return rv; +} + +/* + * kdba_bp_trap + * + * Perform breakpoint processing upon entry to the + * processor breakpoint instruction fault. Determine and print + * the active breakpoint. + * + * Parameters: + * ef Exception frame containing machine register state + * error Error number passed to kdb. + * Outputs: + * None. + * Returns: + * 0 Standard instruction or data breakpoint encountered + * 1 Single Step fault ('ss' command) + * 2 Single Step fault, caller should continue ('ssb' command) + * 3 No existing kdb breakpoint matches this debug exception + * Locking: + * None. + * Remarks: + * + * If multiple processors receive debug exceptions simultaneously, + * one may be waiting at the kdb fence in kdb() while the user + * issues a 'bc' command to clear the breakpoint the processor which + * is waiting has already encountered. If this is the case, the + * debug registers will no longer match any entry in the breakpoint + * table, and we'll return the value '3'. This can cause a panic + * in die_if_kernel(). It is safer to disable the breakpoint (bd), + * 'go' until all processors are past the breakpoint then clear the + * breakpoint (bc). This code recognises a breakpoint even when + * disabled but not when it has been cleared. + * + * WARNING: This routine resets the eip. It should be called + * once per breakpoint and the result cached. + */ + +kdb_dbtrap_t +kdba_bp_trap(kdb_eframe_t ef, int error_unused) +{ + int i; + kdb_dbtrap_t rv; + kdb_bp_t *bp; + + /* + * Determine which breakpoint was encountered. + */ + if (KDB_DEBUG(BP)) + kdb_printf("kdba_bp_trap: eip=0x%lx (not adjusted) " + "eflags=0x%lx ef=0x%p esp=0x%lx\n", + ef->eip, ef->eflags, ef, ef->esp); + + rv = KDB_DB_NOBPT; /* Cause kdb() to return */ + + for(i=0, bp=kdb_breakpoints; ibp_free) + continue; + if (!bp->bp_global && bp->bp_cpu != smp_processor_id()) + continue; + if (bp->bp_addr == (ef->eip - bp->bp_adjust)) { + /* Hit this breakpoint. */ + ef->eip -= bp->bp_adjust; + kdb_printf("Instruction(i) breakpoint #%d at 0x%lx (adjusted)\n", + i, ef->eip); + kdb_id1(ef->eip); + rv = KDB_DB_BPT; + bp->bp_delay = 1; + break; + } + } + + return rv; +} + +/* + * kdba_handle_bp + * + * Handle an instruction-breakpoint trap. Called when re-installing + * an enabled breakpoint which has has the bp_delay bit set. + * + * Parameters: + * Returns: + * Locking: + * Remarks: + * + * Ok, we really need to: + * 1) Restore the original instruction byte + * 2) Single Step + * 3) Restore breakpoint instruction + * 4) Continue. + * + * + */ + +static void +kdba_handle_bp(kdb_eframe_t ef, kdb_bp_t *bp) +{ + if (!ef) { + kdb_printf("kdba_handle_bp: ef == NULL\n"); + return; + } + + if (KDB_DEBUG(BP)) + kdb_printf("ef->eip = 0x%lx\n", ef->eip); + + /* + * Setup single step + */ + kdba_setsinglestep(ef); + + /* KDB_STATE_SSBPT is set when the kernel debugger must single step + * a task in order to re-establish an instruction breakpoint which + * uses the instruction replacement mechanism. + */ + KDB_STATE_SET(SSBPT); + + /* + * Reset delay attribute + */ + bp->bp_delay = 0; + bp->bp_delayed = 1; +} + + +/* + * kdba_bptype + * + * Return a string describing type of breakpoint. + * + * Parameters: + * bph Pointer to hardware breakpoint description + * Outputs: + * None. + * Returns: + * Character string. + * Locking: + * None. + * Remarks: + */ + +char * +kdba_bptype(kdbhard_bp_t *bph) +{ + char *mode; + + mode = kdba_rwtypes[bph->bph_mode]; + + return mode; +} + +/* + * kdba_printbpreg + * + * Print register name assigned to breakpoint + * + * Parameters: + * bph Pointer hardware breakpoint structure + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void +kdba_printbpreg(kdbhard_bp_t *bph) +{ + kdb_printf(" in dr%ld", bph->bph_reg); +} + +/* + * kdba_printbp + * + * Print string describing hardware breakpoint. + * + * Parameters: + * bph Pointer to hardware breakpoint description + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void +kdba_printbp(kdb_bp_t *bp) +{ + kdb_printf("\n is enabled"); + if (bp->bp_hardtype) { + kdba_printbpreg(bp->bp_hard); + if (bp->bp_hard->bph_mode != 0) { + kdb_printf(" for %d bytes", + bp->bp_hard->bph_length+1); + } + } +} + +/* + * kdba_parsebp + * + * Parse architecture dependent portion of the + * breakpoint command. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic for failure + * Locking: + * None. + * Remarks: + * for Ia32 architure, data access, data write and + * I/O breakpoints are supported in addition to instruction + * breakpoints. + * + * {datar|dataw|io|inst} [length] + */ + +int +kdba_parsebp(int argc, const char **argv, int *nextargp, kdb_bp_t *bp) +{ + int nextarg = *nextargp; + int diag; + kdbhard_bp_t *bph = &bp->bp_template; + + bph->bph_mode = 0; /* Default to instruction breakpoint */ + bph->bph_length = 0; /* Length must be zero for insn bp */ + if ((argc + 1) != nextarg) { + if (strnicmp(argv[nextarg], "datar", sizeof("datar")) == 0) { + bph->bph_mode = 3; + } else if (strnicmp(argv[nextarg], "dataw", sizeof("dataw")) == 0) { + bph->bph_mode = 1; + } else if (strnicmp(argv[nextarg], "io", sizeof("io")) == 0) { + bph->bph_mode = 2; + } else if (strnicmp(argv[nextarg], "inst", sizeof("inst")) == 0) { + bph->bph_mode = 0; + } else { + return KDB_ARGCOUNT; + } + + bph->bph_length = 3; /* Default to 4 byte */ + + nextarg++; + + if ((argc + 1) != nextarg) { + unsigned long len; + + diag = kdbgetularg((char *)argv[nextarg], + &len); + if (diag) + return diag; + + + if ((len > 4) || (len == 3)) + return KDB_BADLENGTH; + + bph->bph_length = len; + bph->bph_length--; /* Normalize for debug register */ + nextarg++; + } + + if ((argc + 1) != nextarg) + return KDB_ARGCOUNT; + + /* + * Indicate to architecture independent level that + * a hardware register assignment is required to enable + * this breakpoint. + */ + + bph->bph_free = 0; + } else { + if (KDB_DEBUG(BP)) + kdb_printf("kdba_bp: no args, forcehw is %d\n", bp->bp_forcehw); + if (bp->bp_forcehw) { + /* + * We are forced to use a hardware register for this + * breakpoint because either the bph or bpha + * commands were used to establish this breakpoint. + */ + bph->bph_free = 0; + } else { + /* + * Indicate to architecture dependent level that + * the instruction replacement breakpoint technique + * should be used for this breakpoint. + */ + bph->bph_free = 1; + bp->bp_adjust = 1; /* software, int 3 is one byte */ + } + } + + *nextargp = nextarg; + return 0; +} + +/* + * kdba_allocbp + * + * Associate a hardware register with a breakpoint. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * A pointer to the allocated register kdbhard_bp_t structure for + * success, Null and a non-zero diagnostic for failure. + * Locking: + * None. + * Remarks: + */ + +kdbhard_bp_t * +kdba_allocbp(kdbhard_bp_t *bph, int *diagp) +{ + int i; + kdbhard_bp_t *newbph; + + for(i=0,newbph=kdb_hardbreaks; i < KDB_MAXHARDBPT; i++, newbph++) { + if (newbph->bph_free) { + break; + } + } + + if (i == KDB_MAXHARDBPT) { + *diagp = KDB_TOOMANYDBREGS; + return NULL; + } + + *diagp = 0; + + /* + * Copy data from template. Can't just copy the entire template + * here because the register number in kdb_hardbreaks must be + * preserved. + */ + newbph->bph_data = bph->bph_data; + newbph->bph_write = bph->bph_write; + newbph->bph_mode = bph->bph_mode; + newbph->bph_length = bph->bph_length; + + /* + * Mark entry allocated. + */ + newbph->bph_free = 0; + + return newbph; +} + +/* + * kdba_freebp + * + * Deallocate a hardware breakpoint + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic for failure + * Locking: + * None. + * Remarks: + */ + +void +kdba_freebp(kdbhard_bp_t *bph) +{ + bph->bph_free = 1; +} + +/* + * kdba_initbp + * + * Initialize the breakpoint table for the hardware breakpoint + * register. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic for failure + * Locking: + * None. + * Remarks: + * + * There is one entry per register. On the ia32 architecture + * all the registers are interchangeable, so no special allocation + * criteria are required. + */ + +void +kdba_initbp(void) +{ + int i; + kdbhard_bp_t *bph; + + /* + * Clear the hardware breakpoint table + */ + + memset(kdb_hardbreaks, '\0', sizeof(kdb_hardbreaks)); + + for(i=0,bph=kdb_hardbreaks; ibph_reg = i; + bph->bph_free = 1; + } +} + +/* + * kdba_installbp + * + * Install a breakpoint + * + * Parameters: + * ef Exception frame + * bp Breakpoint structure for the breakpoint to be installed + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * For hardware breakpoints, a debug register is allocated + * and assigned to the breakpoint. If no debug register is + * available, a warning message is printed and the breakpoint + * is disabled. + * + * For instruction replacement breakpoints, we must single-step + * over the replaced instruction at this point so we can re-install + * the breakpoint instruction after the single-step. + */ + +void +kdba_installbp(kdb_eframe_t ef, kdb_bp_t *bp) +{ + /* + * Install the breakpoint, if it is not already installed. + */ + + if (KDB_DEBUG(BP)) { + kdb_printf("kdba_installbp bp_installed %d\n", bp->bp_installed); + } + if (!bp->bp_installed) { + if (bp->bp_hardtype) { + kdba_installdbreg(bp); + bp->bp_installed = 1; + if (KDB_DEBUG(BP)) { + kdb_printf("kdba_installbp hardware reg %ld at " kdb_bfd_vma_fmt "\n", + bp->bp_hard->bph_reg, bp->bp_addr); + } + } else if (bp->bp_delay) { + if (KDB_DEBUG(BP)) + kdb_printf("kdba_installbp delayed bp\n"); + kdba_handle_bp(ef, bp); + } else { + bp->bp_inst = kdba_getword(bp->bp_addr, 1); + kdba_putword(bp->bp_addr, 1, IA32_BREAKPOINT_INSTRUCTION); + bp->bp_instvalid = 1; + if (KDB_DEBUG(BP)) + kdb_printf("kdba_installbp instruction 0x%x at " kdb_bfd_vma_fmt "\n", + IA32_BREAKPOINT_INSTRUCTION, bp->bp_addr); + bp->bp_installed = 1; + } + } +} + +/* + * kdba_removebp + * + * Make a breakpoint ineffective. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void +kdba_removebp(kdb_bp_t *bp) +{ + /* + * For hardware breakpoints, remove it from the active register, + * for software breakpoints, restore the instruction stream. + */ + if (KDB_DEBUG(BP)) { + kdb_printf("kdba_removebp bp_installed %d\n", bp->bp_installed); + } + if (bp->bp_installed) { + if (bp->bp_hardtype) { + if (KDB_DEBUG(BP)) { + kdb_printf("kdb: removing hardware reg %ld at " kdb_bfd_vma_fmt "\n", + bp->bp_hard->bph_reg, bp->bp_addr); + } + kdba_removedbreg(bp); + } else if (bp->bp_instvalid) { + if (KDB_DEBUG(BP)) + kdb_printf("kdb: restoring instruction 0x%x at " kdb_bfd_vma_fmt "\n", + bp->bp_inst, bp->bp_addr); + kdba_putword(bp->bp_addr, 1, bp->bp_inst); + bp->bp_instvalid = 0; + } + bp->bp_installed = 0; + } +} diff -rNu linux-2.4.7/linux/arch/i386/kdb/kdba_bt.c linux-2.4-xfs/linux/arch/i386/kdb/kdba_bt.c --- linux-2.4.7/linux/arch/i386/kdb/kdba_bt.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/kdb/kdba_bt.c Sat Nov 25 11:31:48 2000 @@ -0,0 +1,348 @@ +/* + * Minimalist Kernel Debugger - Architecture Dependent Stack Traceback + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * + * See the file LIA-COPYRIGHT for additional information. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Richard Bass 1999/07/20 + * Many bug fixes and enhancements. + * Scott Foehner + * Port to ia64 + * Srinivasa Thirumalachar + * RSE support for ia64 + * Masahiro Adegawa 1999/12/01 + * 'sr' command, active flag in 'ps' + * Scott Lurndal 1999/12/12 + * Significantly restructure for linux2.3 + * Keith Owens 2000/05/23 + * KDB v1.2 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * bt_print_one + * + * Print one back trace entry. + * + * Inputs: + * ebp Previous frame pointer, 0 if not valid. + * eip Current program counter. + * symtab Information about symbol that eip falls within. + * ar Activation record for this frame. + * argcount Maximum number of arguments to print. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * None. + */ + +static void +bt_print_one(kdb_machreg_t eip, kdb_machreg_t ebp, const kdb_ar_t *ar, + const kdb_symtab_t *symtab, int argcount) +{ + int btsymarg = 0; + int nosect = 0; + + kdbgetintenv("BTSYMARG", &btsymarg); + kdbgetintenv("NOSECT", &nosect); + + if (ebp) + kdb_printf("0x%08lx", ebp); + else + kdb_printf(" "); + kdb_symbol_print(eip, symtab, KDB_SP_SPACEB|KDB_SP_VALUE); + if (argcount && ar->args) { + int i, argc = ar->args / 4; + + kdb_printf(" ("); + if (argc > argcount) + argc = argcount; + + for(i=1; i<=argc; i++){ + kdb_machreg_t argp = ar->arg0 - ar->args + 4*i; + + if (i != 1) + kdb_printf(", "); + kdb_printf("0x%lx", + kdba_getword(argp, sizeof(kdb_machreg_t))); + } + kdb_printf(")"); + } + if (symtab->sym_name) { + if (!nosect) { + kdb_printf("\n"); + kdb_printf(" %s %s 0x%lx 0x%lx 0x%lx", + symtab->mod_name, + symtab->sec_name, + symtab->sec_start, + symtab->sym_start, + symtab->sym_end); + } + } + kdb_printf("\n"); + if (argcount && ar->args && btsymarg) { + int i, argc = ar->args / 4; + kdb_symtab_t arg_symtab; + kdb_machreg_t arg; + for(i=1; i<=argc; i++){ + kdb_machreg_t argp = ar->arg0 - ar->args + 4*i; + arg = kdba_getword(argp, sizeof(kdb_machreg_t)); + if (kdbnearsym(arg, &arg_symtab)) { + kdb_printf(" "); + kdb_symbol_print(arg, &arg_symtab, KDB_SP_DEFAULT|KDB_SP_NEWLINE); + } + } + } +} + +/* + * kdba_bt_stack_i386 + * + * kdba_bt_stack with i386 specific parameters. + * Specification as kdba_bt_stack plus :- + * + * Inputs: + * As kba_bt_stack plus + * regs_esp If 1 get esp from the registers (exception frame), if 0 + * get esp from kdba_getregcontents. + */ + +static int +kdba_bt_stack_i386(struct pt_regs *regs, kdb_machreg_t *addr, int argcount, + struct task_struct *p, int regs_esp) +{ + kdb_ar_t ar; + kdb_machreg_t eip, esp, ebp, ss, cs; + kdb_symtab_t symtab; + + /* + * The caller may have supplied an address at which the + * stack traceback operation should begin. This address + * is assumed by this code to point to a return-address + * on the stack to be traced back. + * + * The end result of this will make it appear as if a function + * entitled '' was called from the function which + * contains return-address. + */ + if (addr) { + eip = 0; + ebp = 0; + esp = *addr; + cs = __KERNEL_CS; /* have to assume kernel space */ + } else { + eip = regs->eip; + ebp = regs->ebp; + if (regs_esp) + esp = regs->esp; + else + kdba_getregcontents("esp", regs, &esp); + kdba_getregcontents("xcs", regs, &cs); + } + ss = esp & -8192; + + if ((cs & 0xffff) != __KERNEL_CS) { + kdb_printf("Stack is not in kernel space, backtrace not available\n"); + return 0; + } + + kdb_printf(" EBP EIP Function(args)\n"); + + /* + * Run through the activation records and print them. + */ + + while (1) { + kdbnearsym(eip, &symtab); + if (!kdb_get_next_ar(esp, symtab.sym_start, eip, ebp, ss, + &ar, &symtab)) { + break; + } + + if (strcmp(".text.lock", symtab.sec_name) == 0) { + /* + * Instructions in the .text.lock area are generated by + * the out of line code in lock handling, see + * include/asm-i386 semaphore.h and rwlock.h. There can + * be multiple instructions which eventually end with a + * jump back to the mainline code. Use the disassmebler + * to silently step through the code until we find the + * jump, resolve its destination and translate it to a + * symbol. Replace '.text.lock' with the symbol. + */ + unsigned char inst; + kdb_machreg_t offset = 0, realeip = eip; + int length, offsize = 0; + kdb_symtab_t lock_symtab; + /* Dummy out the disassembler print function */ + fprintf_ftype save_fprintf_func = kdb_di.fprintf_func; + + kdb_di.fprintf_func = &kdb_dis_fprintf_dummy; + while((length = kdba_id_printinsn(realeip, &kdb_di)) > 0) { + inst = kdba_getword(realeip, 1); + offsize = 0; + switch (inst) { + case 0xeb: /* jmp with 1 byte offset */ + offsize = 1; + offset = kdba_getword(realeip+1, offsize); + break; + case 0xe9: /* jmp with 4 byte offset */ + offsize = 4; + offset = kdba_getword(realeip+1, offsize); + break; + default: + realeip += length; /* next instruction */ + break; + } + if (offsize) + break; + } + kdb_di.fprintf_func = save_fprintf_func; + + if (offsize) { + realeip += 1 + offsize + offset; + if (kdbnearsym(realeip, &lock_symtab)) { + /* Print the stext entry without args */ + bt_print_one(eip, 0, &ar, &symtab, 0); + /* Point to mainline code */ + eip = realeip; + continue; + } + } + } + + if (strcmp("ret_from_intr", symtab.sym_name) == 0) { + /* + * Non-standard frame. ret_from_intr is preceded by + * 9 registers (ebx, ecx, edx, esi, edi, ebp, eax, ds, + * cs), original eax and the return address for a total + * of 11 words. + */ + ar.start = ar.end + 11*4; + /* Print the ret_from_intr entry without args */ + bt_print_one(eip, 0, &ar, &symtab, 0); + kdb_printf("Interrupt registers:\n"); + kdba_dumpregs((struct pt_regs *)(ar.end), NULL, NULL); + /* Step the frame to the interrupted code */ + eip = kdba_getword(ar.start-4, 4); + ebp = 0; + esp = ar.start; + continue; + } + + if (strcmp("error_code", symtab.sym_name) == 0) { + /* + * Non-standard frame. error_code is preceded + * by two parameters (-> registers, error code), + * 9 registers (ebx, ecx, edx, esi, edi, ebp, eax, ds, + * cs), original eax and the return address for a total + * of 13 words. + */ + ar.start = ar.end + 13*4; + /* Print the error_code entry without args */ + bt_print_one(eip, 0, &ar, &symtab, 0); + kdb_printf("Interrupt registers:\n"); + kdba_dumpregs((struct pt_regs *)(ar.end+8), NULL, NULL); + /* Step the frame to the interrupted code */ + eip = kdba_getword(ar.start-4, 4); + ebp = 0; + esp = ar.start; + continue; + } + + bt_print_one(eip, ebp, &ar, &symtab, argcount); + + if (ar.ret == 0) + break; /* End of frames */ + eip = ar.ret; + ebp = ar.oldfp; + esp = ar.start; + } + + return 0; +} + +/* + * kdba_bt_stack + * + * This function implements the 'bt' command. Print a stack + * traceback. + * + * bt [] (addr-exp is for alternate stacks) + * btp (Kernel stack for ) + * + * address expression refers to a return address on the stack. It + * may be preceeded by a frame pointer. + * + * Inputs: + * regs registers at time kdb was entered. + * addr Pointer to Address provided to 'bt' command, if any. + * argcount + * p Pointer to task for 'btp' command. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * mds comes in handy when examining the stack to do a manual + * traceback. + */ + +int +kdba_bt_stack(struct pt_regs *regs, kdb_machreg_t *addr, int argcount, + struct task_struct *p) +{ + return(kdba_bt_stack_i386(regs, addr, argcount, p, 0)); +} + +int +kdba_bt_process(struct task_struct *p, int argcount) +{ + struct pt_regs taskregs; + + memset(&taskregs, 0, sizeof(taskregs)); + taskregs.eip = p->thread.eip; + taskregs.esp = p->thread.esp; + + /* + * Since we don't really use the TSS + * to store register between task switches, + * attempt to locate real ebp (should be + * top of stack if task is in schedule) + */ + taskregs.ebp = *(kdb_machreg_t *)(taskregs.esp); + + taskregs.xcs = __KERNEL_CS; /* have to assume kernel space */ + + if (taskregs.esp < (unsigned long)p || + taskregs.esp >= (unsigned long)p + 8192) { + kdb_printf("Stack is not in task_struct, backtrace not available\n"); + return(0); + } + + return kdba_bt_stack_i386(&taskregs, NULL, argcount, p, 1); + +} diff -rNu linux-2.4.7/linux/arch/i386/kdb/kdba_id.c linux-2.4-xfs/linux/arch/i386/kdb/kdba_id.c --- linux-2.4.7/linux/arch/i386/kdb/kdba_id.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/kdb/kdba_id.c Mon Dec 11 22:44:55 2000 @@ -0,0 +1,270 @@ +/* + * Minimalist Kernel Debugger - Architecture Dependent Instruction Disassembly + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * + * See the file LIA-COPYRIGHT for additional information. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Richard Bass 1999/07/20 + * Many bug fixes and enhancements. + * Scott Foehner + * Port to ia64 + * Srinivasa Thirumalachar + * RSE support for ia64 + * Masahiro Adegawa 1999/12/01 + * 'sr' command, active flag in 'ps' + * Scott Lurndal 1999/12/12 + * Significantly restructure for linux2.3 + * Keith Owens 2000/05/23 + * KDB v1.2 + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * kdba_dis_getsym + * + * Get a symbol for the disassembler. + * + * Parameters: + * addr Address for which to get symbol + * dip Pointer to disassemble_info + * Returns: + * 0 + * Locking: + * Remarks: + * Not used for kdb. + */ + +/* ARGSUSED */ +static int +kdba_dis_getsym(bfd_vma addr, disassemble_info *dip) +{ + + return 0; +} + +/* + * kdba_printaddress + * + * Print (symbolically) an address. + * + * Parameters: + * addr Address for which to get symbol + * dip Pointer to disassemble_info + * flag True if a ":" sequence should follow the address + * Returns: + * 0 + * Locking: + * Remarks: + * + */ + +/* ARGSUSED */ +void +kdba_printaddress(kdb_machreg_t addr, disassemble_info *dip, int flag) +{ + kdb_symtab_t symtab; + + /* + * Print a symbol name or address as necessary. + */ + kdbnearsym(addr, &symtab); + if (symtab.sym_name) { + /* Do not use kdb_symbol_print here, it always does + * kdb_printf but we want dip->fprintf_func. + */ + dip->fprintf_func(dip->stream, + "0x%0*lx %s", + 2*sizeof(addr), addr, symtab.sym_name); + if (addr != symtab.sym_start) + dip->fprintf_func(dip->stream, "+0x%x", addr - symtab.sym_start); + + } else { + dip->fprintf_func(dip->stream, "0x%x", addr); + } + + if (flag) + dip->fprintf_func(dip->stream, ": "); +} + +/* + * kdba_dis_printaddr + * + * Print (symbolically) an address. Called by GNU disassembly + * code via disassemble_info structure. + * + * Parameters: + * addr Address for which to get symbol + * dip Pointer to disassemble_info + * Returns: + * 0 + * Locking: + * Remarks: + * This function will never append ":" to the printed + * symbolic address. + */ + +static void +kdba_dis_printaddr(bfd_vma addr, disassemble_info *dip) +{ + kdba_printaddress(addr, dip, 0); +} + +/* + * kdba_dis_getmem + * + * Fetch 'length' bytes from 'addr' into 'buf'. + * + * Parameters: + * addr Address for which to get symbol + * buf Address of buffer to fill with bytes from 'addr' + * length Number of bytes to fetch + * dip Pointer to disassemble_info + * Returns: + * 0 + * Locking: + * Remarks: + * + */ + +/* ARGSUSED */ +static int +kdba_dis_getmem(bfd_vma addr, bfd_byte *buf, unsigned int length, disassemble_info *dip) +{ + bfd_byte *bp = buf; + int i; + + /* + * Fill the provided buffer with bytes from + * memory, starting at address 'addr' for 'length bytes. + * + */ + + for(i=0; imach = bfd_mach_i386_i386; + } else if (strcmp(mode, "8086") == 0) { + dip->mach = bfd_mach_i386_i8086; + } else { + return KDB_BADMODE; + } + } + + return 0; +} + +/* + * kdba_check_pc + * + * Check that the pc is satisfactory. + * + * Parameters: + * pc Program Counter Value. + * Returns: + * None + * Locking: + * None. + * Remarks: + * Can change pc. + */ + +void +kdba_check_pc(kdb_machreg_t *pc) +{ + /* No action */ +} + +/* + * kdba_id_printinsn + * + * Format and print a single instruction at 'pc'. Return the + * length of the instruction. + * + * Parameters: + * pc Program Counter Value. + * dip Disassemble_info structure pointer + * Returns: + * Length of instruction, -1 for error. + * Locking: + * None. + * Remarks: + * Depends on 'IDMODE' environment variable. + */ + +int +kdba_id_printinsn(kdb_machreg_t pc, disassemble_info *dip) +{ + kdba_dis_printaddr(pc, dip); + return print_insn_i386_att(pc, dip); +} + +/* + * kdba_id_init + * + * Initialize the architecture dependent elements of + * the disassembly information structure + * for the GNU disassembler. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void __init +kdba_id_init(disassemble_info *dip) +{ + dip->read_memory_func = kdba_dis_getmem; + dip->print_address_func = kdba_dis_printaddr; + dip->symbol_at_address_func = kdba_dis_getsym; + + dip->flavour = bfd_target_elf_flavour; + dip->arch = bfd_arch_i386; + dip->mach = bfd_mach_i386_i386; + dip->endian = BFD_ENDIAN_LITTLE; + + dip->display_endian = BFD_ENDIAN_LITTLE; +} diff -rNu linux-2.4.7/linux/arch/i386/kdb/kdba_io.c linux-2.4-xfs/linux/arch/i386/kdb/kdba_io.c --- linux-2.4.7/linux/arch/i386/kdb/kdba_io.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/kdb/kdba_io.c Mon Apr 2 12:13:32 2001 @@ -0,0 +1,374 @@ +/* + * Kernel Debugger Console I/O handler + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * + * See the file LIA-COPYRIGHT for additional information. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Chuck Fleckenstein 1999/07/20 + * Move kdb_info struct declaration to this file + * for cases where serial support is not compiled into + * the kernel. + * + * Masahiro Adegawa 1999/07/20 + * Handle some peculiarities of japanese 86/106 + * keyboards. + * + * marc@mucom.co.il 1999/07/20 + * Catch buffer overflow for serial input. + * + * Scott Foehner + * Port to ia64 + * + * Scott Lurndal 2000/01/03 + * Restructure for v1.0 + * + * Keith Owens 2000/05/23 + * KDB v1.2 + * + * Andi Kleen 2000/03/19 + * Support simultaneous input from serial line and keyboard. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define KDB_BLINK_LED 1 + +int kdb_port; + +/* + * This module contains code to read characters from the keyboard or a serial + * port. + * + * It is used by the kernel debugger, and is polled, not interrupt driven. + * + */ + +#ifdef KDB_BLINK_LED +/* + * send: Send a byte to the keyboard controller. Used primarily to + * alter LED settings. + */ + +static void +kdb_kbdsend(unsigned char byte) +{ + while (inb(KBD_STATUS_REG) & KBD_STAT_IBF) + ; + outb(byte, KBD_DATA_REG); +} + +static void +kdb_toggleled(int led) +{ + static int leds; + + leds ^= led; + + kdb_kbdsend(KBD_CMD_SET_LEDS); + kdb_kbdsend((unsigned char)leds); +} +#endif /* KDB_BLINK_LED */ + +void +kdb_resetkeyboard(void) +{ +#if 0 + kdb_kbdsend(KBD_CMD_ENABLE); +#endif +} + +#if defined(CONFIG_SERIAL_CONSOLE) +/* Check if there is a byte ready at the serial port */ +static int get_serial_char(void) +{ + unsigned char ch; + int status; +#define serial_inp(info, offset) inb((info) + (offset)) + + if (kdb_port == 0) + return -1; + + if ((status = serial_inp(kdb_port, UART_LSR)) & UART_LSR_DR) { + ch = serial_inp(kdb_port, UART_RX); + if (ch == 0x7f) + ch = 8; + if (ch == '\t') + ch = ' '; + if (ch == 8) { /* BS */ + ; + } else if (ch == 13) { /* Enter */ + kdb_printf("\n"); + } else { + if (!isprint(ch)) + return(-1); + kdb_printf("%c", ch); + } + return ch; + } + return -1; +} +#endif /* CONFIG_SERIAL_CONSOLE */ + +#if defined(CONFIG_VT) +/* + * Check if the keyboard controller has a keypress for us. + * Some parts (Enter Release, LED change) are still blocking polled here, + * but hopefully they are all short. + */ +static int get_kbd_char(void) +{ + int scancode, scanstatus; + static int shift_lock; /* CAPS LOCK state (0-off, 1-on) */ + static int shift_key; /* Shift next keypress */ + static int ctrl_key; + u_short keychar; + extern u_short plain_map[], shift_map[], ctrl_map[]; + + if ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) + return -1; + + /* + * Fetch the scancode + */ + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + + /* + * Ignore mouse events. + */ + if (scanstatus & KBD_STAT_MOUSE_OBF) + return -1; + + /* + * Ignore release, trigger on make + * (except for shift keys, where we want to + * keep the shift state so long as the key is + * held down). + */ + + if (((scancode&0x7f) == 0x2a) || ((scancode&0x7f) == 0x36)) { + /* + * Next key may use shift table + */ + if ((scancode & 0x80) == 0) { + shift_key=1; + } else { + shift_key=0; + } + return -1; + } + + if ((scancode&0x7f) == 0x1d) { + /* + * Left ctrl key + */ + if ((scancode & 0x80) == 0) { + ctrl_key = 1; + } else { + ctrl_key = 0; + } + return -1; + } + + if ((scancode & 0x80) != 0) + return -1; + + scancode &= 0x7f; + + /* + * Translate scancode + */ + + if (scancode == 0x3a) { + /* + * Toggle caps lock + */ + shift_lock ^= 1; + + kdb_toggleled(0x4); + return -1; + } + + if (scancode == 0x0e) { + /* + * Backspace + */ + return 8; + } + + if (scancode == 0xe0) { + return -1; + } + + /* + * For Japanese 86/106 keyboards + * See comment in drivers/char/pc_keyb.c. + * - Masahiro Adegawa + */ + if (scancode == 0x73) { + scancode = 0x59; + } else if (scancode == 0x7d) { + scancode = 0x7c; + } + + if (!shift_lock && !shift_key && !ctrl_key) { + keychar = plain_map[scancode]; + } else if (shift_lock || shift_key) { + keychar = shift_map[scancode]; + } else if (ctrl_key) { + keychar = ctrl_map[scancode]; + } else { + keychar = 0x0020; + kdb_printf("Unknown state/scancode (%d)\n", scancode); + } + keychar &= 0x0fff; + if (keychar == '\t') + keychar = ' '; + switch (KTYP(keychar)) { + case KT_LETTER: + case KT_LATIN: + if (isprint(keychar)) + break; /* printable characters */ + /* drop through */ + case KT_SPEC: + if (keychar == K_ENTER) + break; + /* drop through */ + default: + return(-1); /* ignore unprintables */ + } + + if ((scancode & 0x7f) == 0x1c) { + /* + * enter key. All done. Absorb the release scancode. + */ + while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0) + ; + + /* + * Fetch the scancode + */ + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + + while (scanstatus & KBD_STAT_MOUSE_OBF) { + scancode = inb(KBD_DATA_REG); + scanstatus = inb(KBD_STATUS_REG); + } + + if (scancode != 0x9c) { + /* + * Wasn't an enter-release, why not? + */ + kdb_printf("kdb: expected enter got 0x%x status 0x%x\n", + scancode, scanstatus); + } + + kdb_printf("\n"); + return 13; + } + + /* + * echo the character. + */ + kdb_printf("%c", keychar&0xff); + + return keychar & 0xff; +} +#endif /* CONFIG_VT */ + +#ifdef KDB_BLINK_LED + +/* Leave numlock alone, setting it messes up laptop keyboards with the keypad + * mapped over normal keys. + */ +int kdba_blink_mask = 0x1 | 0x4; + +#define BOGOMIPS (boot_cpu_data.loops_per_jiffy/(500000/HZ)) +static int blink_led(void) +{ + static long delay; + if (--delay < 0) { + if (BOGOMIPS == 0) /* early kdb */ + delay = 150000000/1000; /* arbitrary bogomips */ + else + delay = 150000000/BOGOMIPS; /* Roughly 1 second when polling */ + kdb_toggleled(kdba_blink_mask); + } + return -1; +} +#endif + +typedef int (*get_char_func)(void); + +static get_char_func poll_funcs[] = { +#if defined(CONFIG_VT) + get_kbd_char, +#endif +#if defined(CONFIG_SERIAL_CONSOLE) + get_serial_char, +#endif +#ifdef KDB_BLINK_LED + blink_led, +#endif + NULL +}; + +char * +kdba_read(char *buffer, size_t bufsize) +{ + char *cp = buffer; + char *bufend = buffer+bufsize-2; /* Reserve space for newline and null byte */ + + for (;;) { + int key; + get_char_func *f; + for (f = &poll_funcs[0]; ; ++f) { + if (*f == NULL) { + /* Reset NMI watchdog once per poll loop */ + /* only in -ac. touch_nmi_watchdog(); */ + f = &poll_funcs[0]; + } + key = (*f)(); + if (key != -1) + break; + } + + /* Echo is done in the low level functions */ + switch (key) { + case 8: /* backspace */ + if (cp > buffer) { + kdb_printf("\b \b"); + --cp; + } + break; + case 13: /* enter */ + *cp++ = '\n'; + *cp++ = '\0'; + return buffer; + default: + if (cp < bufend) + *cp++ = key; + break; + } + } +} diff -rNu linux-2.4.7/linux/arch/i386/kdb/kdbasupport.c linux-2.4-xfs/linux/arch/i386/kdb/kdbasupport.c --- linux-2.4.7/linux/arch/i386/kdb/kdbasupport.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/kdb/kdbasupport.c Sat May 26 23:02:58 2001 @@ -0,0 +1,1619 @@ +/* + * Kernel Debugger Architecture Independent Support Functions + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * + * See the file LIA-COPYRIGHT for additional information. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Richard Bass 1999/07/20 + * Many bug fixes and enhancements. + * Scott Foehner + * Port to ia64 + * Scott Lurndal 1999/12/12 + * v1.0 restructuring. + * Keith Owens 2000/05/23 + * KDB v1.2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +char *kdb_diemsg; + + +/* + * kdba_find_return + * + * Given a starting point on the stack and symtab data for the + * current function, scan up the stack looking for a return + * address for this function. + * Inputs: + * sp Starting stack pointer for scan + * ss Start of stack for current process + * symtab kallsyms symbol data for the function + * Outputs: + * None. + * Returns: + * Position on stack of return address, 0 if not found. + * Locking: + * None. + * Remarks: + * This is sensitive to the calling sequence generated by gcc. + */ + +static kdb_machreg_t +kdba_find_return(kdb_machreg_t sp, kdb_machreg_t ss, const kdb_symtab_t *symtab) +{ + kdb_machreg_t ret; + kdb_symtab_t caller_symtab; + + if (KDB_DEBUG(ARA)) { + kdb_printf(" kdba_find_return: start\n"); + } + + if ((sp & -8192) != ss) { + kdb_printf(" sp is in wrong stack 0x%lx 0x%lx 0x%lx\n", sp, ss, sp & -8192); + return(0); + } + + if ((sp & (8192 - 1)) < sizeof(struct task_struct)) { + kdb_printf(" sp is inside task_struct\n"); + return(0); + } + + for (;ret = 0, sp & (8192-1);sp += 4) { + if (KDB_DEBUG(ARA)) { + kdb_printf(" sp=0x%lx", sp); + } + ret = kdba_getword(sp, 4); + kdbnearsym(ret, &caller_symtab); + if (KDB_DEBUG(ARA)) { + kdb_printf(" ret="); + kdb_symbol_print(ret, &caller_symtab, KDB_SP_DEFAULT|KDB_SP_SYMSIZE); + } + if (!caller_symtab.sym_name) { + if (KDB_DEBUG(ARA)) { + kdb_printf("\n"); + } + continue; /* not a valid kernel address */ + } + if (kdba_getword(ret-5, 1) == 0xe8) { + /* call disp32 */ + if (KDB_DEBUG(ARA)) { + kdb_printf(" call disp32"); + } + if (ret + kdba_getword(ret-4, 4) == symtab->sym_start) { + if (KDB_DEBUG(ARA)) { + kdb_printf(" matched\n"); + } + break; /* call to this function */ + } + if (KDB_DEBUG(ARA)) { + kdb_printf(" failed"); + } + } else if (kdba_getword(ret-7, 1) == 0xff && + kdba_getword(ret-6, 1) == 0x14 && + kdba_getword(ret-5, 1) == 0x85) { + /* call *0xnnnn(,%eax,4), used by syscall. + * Cannot calculate address, assume it is valid + * if the current function name starts with + * 'sys_' or 'old_'. + */ + if (KDB_DEBUG(ARA)) { + kdb_printf(" call *0xnnnn(,%%eax,4)"); + } + if (strncmp(symtab->sym_name, "sys_", 4) == 0 || + strncmp(symtab->sym_name, "old_", 4) == 0) { + if (KDB_DEBUG(ARA)) { + kdb_printf(" matched\n"); + } + break; /* probably call to this function */ + } + if (KDB_DEBUG(ARA)) { + kdb_printf(" failed"); + } + } else if (kdba_getword(ret-2, 1) == 0xff && + (kdba_getword(ret-1, 1) & 0xf8) == 0xd0) { + /* call *%reg. Cannot validate, have to assume + * it is valid. + */ + if (KDB_DEBUG(ARA)) { + kdb_printf(" call *%%reg, assume valid\n"); + } + break; /* hope it is a call to this function */ + } else if (kdba_getword(ret-3, 1) == 0xff && + (kdba_getword(ret-2, 1) & 0xf8) == 0x50) { + /* call *disp8(%reg). Cannot validate, have to assume + * it is valid. + */ + if (KDB_DEBUG(ARA)) { + kdb_printf(" call *disp8(%%reg), assume valid\n"); + } + break; /* hope it is a call to this function */ + } else if (kdba_getword(ret-5, 1) == 0xe9) { + /* jmp disp32. I have been told that gcc may + * do function tail optimization and replace + * call with jmp. + */ + if (KDB_DEBUG(ARA)) { + kdb_printf(" jmp disp32\n"); + } + if (ret + kdba_getword(ret-4, 4) == symtab->sym_start) { + if (KDB_DEBUG(ARA)) { + kdb_printf(" matched\n"); + } + break; /* jmp to this function */ + } + if (KDB_DEBUG(ARA)) { + kdb_printf(" failed"); + } + } else if (kdba_getword(ret-2, 1) == 0xeb) { + /* jmp disp8 */ + if (KDB_DEBUG(ARA)) { + kdb_printf(" jmp disp8\n"); + } + if (ret + kdba_getword(ret-1, 1) == symtab->sym_start) { + if (KDB_DEBUG(ARA)) { + kdb_printf(" matched\n"); + } + break; /* jmp to this function */ + } + if (KDB_DEBUG(ARA)) { + kdb_printf(" failed"); + } + } else if (strcmp(caller_symtab.sym_name, "ret_from_intr") == 0 + && ret == caller_symtab.sym_start) { + /* ret_from_intr is pushed on stack for interrupts */ + if (KDB_DEBUG(ARA)) { + kdb_printf(" ret_from_intr matched\n"); + } + break; /* special case, hand crafted frame */ + } + if (KDB_DEBUG(ARA)) { + kdb_printf("\n"); + } + } + if (KDB_DEBUG(ARA)) { + kdb_printf(" end ret=0x%lx sp=0x%lx\n", ret, sp); + } + if (ret) + return(sp); + return(0); +} + +/* + * kdba_prologue + * + * This function analyzes a gcc-generated function prototype + * with or without frame pointers to determine the amount of + * automatic storage and register save storage is used on the + * stack of the target function. It only counts instructions + * that have been executed up to but excluding the current eip. + * Inputs: + * code Start address of function code to analyze + * pc Current program counter within function + * sp Current stack pointer for function + * fp Current frame pointer for function, may not be valid + * ss Start of stack for current process. + * caller 1 if looking for data on the caller frame, 0 for callee. + * Outputs: + * ar Activation record, all fields may be set. fp and oldfp + * are 0 if they cannot be extracted. return is 0 if the + * code cannot find a valid return address. args and arg0 + * are 0 if the number of arguments cannot be safely + * calculated. + * Returns: + * 1 if prologue is valid, 0 otherwise. If pc is 0 treat it as a + * valid prologue to allow bt on wild branches. + * Locking: + * None. + * Remarks: + * + * A prologue for ia32 generally looks like: + * + * pushl %ebp [All functions, but only if + * movl %esp, %ebp compiled with frame pointers] + * subl $auto, %esp [some functions] + * pushl %reg [some functions] + * pushl %reg [some functions] + * + * FIXME: Mike Galbraith says that gcc 2.95 can generate a slightly + * different prologue. No support for gcc 2.95 yet. + */ + +int +kdba_prologue(const kdb_symtab_t *symtab, kdb_machreg_t pc, kdb_machreg_t sp, + kdb_machreg_t fp, kdb_machreg_t ss, int caller, kdb_ar_t *ar) +{ + kdb_machreg_t ret_p, code = symtab->sym_start; + int oldfp_present = 0, unwound = 0; + + if (KDB_DEBUG(ARA)) { + kdb_printf("kdba_prologue: code=0x%lx %s pc=0x%lx sp=0x%lx fp=0x%lx\n", + code, symtab->sym_name, pc, sp, fp); + } + + /* Special case for wild branches. Assumes top of stack is return address */ + if (pc == 0) { + memset(ar, 0, sizeof(*ar)); + ar->setup = 4; + ar->end = sp; + ar->start = ar->end + 4; + ar->ret = kdba_getword(sp, 4); + if (KDB_DEBUG(ARA)) { + kdb_printf(" pc==0: ret=0x%lx\n", ar->ret); + } + return(1); + } + + if (code == 0 || sp & 3 || ss != (sp & -8192)) + return(0); + + ar->end = sp; /* End of activation record +1 */ + + /* Special cases galore when the caller pc is within entry.S. + * The return address for these routines is outside the kernel, + * so the normal algorithm to find the frame does not work. + * Hand craft the frame to no setup, regs, locals etc, assume 6 + * parameters. + * This list was extracted from entry.S by looking for all call + * instructions that were eventually followed by RESTORE_ALL, + * take the label before each such instruction. + */ + if (caller && + (strcmp(symtab->sym_name, "lcall7") == 0 || + strcmp(symtab->sym_name, "lcall27") == 0 || + strcmp(symtab->sym_name, "kdb_call") == 0 || + strcmp(symtab->sym_name, "system_call") == 0 || + strcmp(symtab->sym_name, "tracesys") == 0 || + strcmp(symtab->sym_name, "signal_return") == 0 || + strcmp(symtab->sym_name, "v86_signal_return") == 0 || + strcmp(symtab->sym_name, "tracesys") == 0 || + strcmp(symtab->sym_name, "tracesys_exit") == 0 || + strcmp(symtab->sym_name, "handle_softirq") == 0 || + strcmp(symtab->sym_name, "reschedule") == 0 || + strcmp(symtab->sym_name, "error_code") == 0 || + strcmp(symtab->sym_name, "device_not_available") == 0 || + strcmp(symtab->sym_name, "nmi") == 0)) { + ar->start = ar->end + 6*4; /* 6 parameters */ + if ((ar->start & -8192) != ss) + ar->start = 0; + return(1); + } + + ar->setup = 4; /* Return address is always on stack */ + + /* Kludge. If we are sitting on 'ret' then the stack has been unwound, + * ignore all the startup code. + */ + if (kdba_getword(pc, 1) == 0xc3) { + /* ret */ + unwound = 1; + } + + if (!unwound + && code < pc + && kdba_getword(code, 1) == 0x55) { + /* pushl %ebp */ + ar->setup += 4; /* Frame pointer is on stack */ + oldfp_present = 1; + ++code; + if (KDB_DEBUG(ARA)) { + kdb_printf(" pushl %%ebp\n"); + } + if (code < pc && + kdba_getword(code, 1) == 0x89 && + kdba_getword(code+1, 1) == 0xe5) { + /* movl %esp,%ebp */ + if (fp >= sp && (fp & -8192) == ss) + ar->fp = fp; /* %ebp has been set */ + code += 2; + if (KDB_DEBUG(ARA)) { + kdb_printf(" movl %%esp,%%ebp, fp=0x%lx\n", ar->fp); + } + } + } + + if (!unwound && code < pc) { + if (kdba_getword(code, 1) == 0x83 && + kdba_getword(code+1, 1) == 0xec) { + /* subl $xx,%esp */ + code += 2; + ar->locals = kdba_getword(code, 1); + ++code; + if (KDB_DEBUG(ARA)) { + kdb_printf(" subl $xx,%%esp, locals=%d\n", ar->locals); + } + } else if (kdba_getword(code, 1) == 0x81 && + kdba_getword(code+1, 1) == 0xec) { + /* subl $xxxxxxxx,%esp */ + code += 2; + ar->locals = kdba_getword(code, 4); + code += 4; + if (KDB_DEBUG(ARA)) { + kdb_printf(" subl $xxxxxxxx,%%esp, locals=%d\n", ar->locals); + } + } + } + + while (!unwound && code < pc && (kdba_getword(code, 1)&0xf8) == 0x50) { + /* pushl %reg */ + ar->regs += 4; + ++code; + if (KDB_DEBUG(ARA)) { + kdb_printf(" pushl %%reg, regs=%d\n", ar->regs); + } + } + + /* Check the return address. It must point within the kernel + * and the code at that location must be a valid entry sequence. + */ + if (ar->fp) { + ret_p = ar->fp + ar->setup; + } + else { + ret_p = ar->end + ar->regs + ar->locals + ar->setup; + } + ret_p -= 4; + if (KDB_DEBUG(ARA)) { + kdb_printf(" ret_p(0)=0x%lx\n", ret_p); + } + if ((ret_p & -8192) == ss && + (ret_p = kdba_find_return(ret_p, ss, symtab))) { + ar->ret = kdba_getword(ret_p, 4); + } + if (KDB_DEBUG(ARA)) { + kdb_printf(" ret_p(1)=0x%lx ret=0x%lx\n", ret_p, ar->ret); + } + if (ar->ret) { + ar->fp = ret_p - ar->setup + 4; /* "accurate" fp */ + ar->start = ret_p + 4; + if (KDB_DEBUG(ARA)) { + kdb_printf(" fp=0x%lx start=0x%lx\n", ar->fp, ar->start); + } + } + if (oldfp_present) { + if (ar->fp) + ar->oldfp = kdba_getword(ar->fp, 4); + if (KDB_DEBUG(ARA)) { + kdb_printf(" oldfp=0x%lx", ar->oldfp); + } + if (ar->oldfp <= ar->fp || (ar->oldfp & -8192) != ss) { + ar->oldfp = 0; + if (KDB_DEBUG(ARA)) { + kdb_printf(" (out of range)"); + } + } + if (KDB_DEBUG(ARA)) { + kdb_printf("\n"); + } + } + return(1); +} + +kdb_machreg_t +kdba_getdr6(void) +{ + return kdba_getdr(6); +} + +kdb_machreg_t +kdba_getdr7(void) +{ + return kdba_getdr(7); +} + +void +kdba_putdr6(kdb_machreg_t contents) +{ + kdba_putdr(6, contents); +} + +static void +kdba_putdr7(kdb_machreg_t contents) +{ + kdba_putdr(7, contents); +} + +void +kdba_installdbreg(kdb_bp_t *bp) +{ + kdb_machreg_t dr7; + + dr7 = kdba_getdr7(); + + kdba_putdr(bp->bp_hard->bph_reg, bp->bp_addr); + + dr7 |= DR7_GE; + + switch (bp->bp_hard->bph_reg){ + case 0: + DR7_RW0SET(dr7,bp->bp_hard->bph_mode); + DR7_LEN0SET(dr7,bp->bp_hard->bph_length); + DR7_G0SET(dr7); + break; + case 1: + DR7_RW1SET(dr7,bp->bp_hard->bph_mode); + DR7_LEN1SET(dr7,bp->bp_hard->bph_length); + DR7_G1SET(dr7); + break; + case 2: + DR7_RW2SET(dr7,bp->bp_hard->bph_mode); + DR7_LEN2SET(dr7,bp->bp_hard->bph_length); + DR7_G2SET(dr7); + break; + case 3: + DR7_RW3SET(dr7,bp->bp_hard->bph_mode); + DR7_LEN3SET(dr7,bp->bp_hard->bph_length); + DR7_G3SET(dr7); + break; + default: + kdb_printf("kdb: Bad debug register!! %ld\n", + bp->bp_hard->bph_reg); + break; + } + + kdba_putdr7(dr7); + return; +} + +void +kdba_removedbreg(kdb_bp_t *bp) +{ + int regnum; + kdb_machreg_t dr7; + + if (!bp->bp_hard) + return; + + regnum = bp->bp_hard->bph_reg; + + dr7 = kdba_getdr7(); + + kdba_putdr(regnum, 0); + + switch (regnum) { + case 0: + DR7_G0CLR(dr7); + DR7_L0CLR(dr7); + break; + case 1: + DR7_G1CLR(dr7); + DR7_L1CLR(dr7); + break; + case 2: + DR7_G2CLR(dr7); + DR7_L2CLR(dr7); + break; + case 3: + DR7_G3CLR(dr7); + DR7_L3CLR(dr7); + break; + default: + kdb_printf("kdb: Bad debug register!! %d\n", regnum); + break; + } + + kdba_putdr7(dr7); +} + +kdb_machreg_t +kdba_getdr(int regnum) +{ + kdb_machreg_t contents = 0; + switch(regnum) { + case 0: + __asm__ ("movl %%db0,%0\n\t":"=r"(contents)); + break; + case 1: + __asm__ ("movl %%db1,%0\n\t":"=r"(contents)); + break; + case 2: + __asm__ ("movl %%db2,%0\n\t":"=r"(contents)); + break; + case 3: + __asm__ ("movl %%db3,%0\n\t":"=r"(contents)); + break; + case 4: + case 5: + break; + case 6: + __asm__ ("movl %%db6,%0\n\t":"=r"(contents)); + break; + case 7: + __asm__ ("movl %%db7,%0\n\t":"=r"(contents)); + break; + default: + break; + } + + return contents; +} + + +kdb_machreg_t +kdb_getcr(int regnum) +{ + kdb_machreg_t contents = 0; + switch(regnum) { + case 0: + __asm__ ("movl %%cr0,%0\n\t":"=r"(contents)); + break; + case 1: + break; + case 2: + __asm__ ("movl %%cr2,%0\n\t":"=r"(contents)); + break; + case 3: + __asm__ ("movl %%cr3,%0\n\t":"=r"(contents)); + break; + case 4: + __asm__ ("movl %%cr4,%0\n\t":"=r"(contents)); + break; + default: + break; + } + + return contents; +} + +void +kdba_putdr(int regnum, kdb_machreg_t contents) +{ + switch(regnum) { + case 0: + __asm__ ("movl %0,%%db0\n\t"::"r"(contents)); + break; + case 1: + __asm__ ("movl %0,%%db1\n\t"::"r"(contents)); + break; + case 2: + __asm__ ("movl %0,%%db2\n\t"::"r"(contents)); + break; + case 3: + __asm__ ("movl %0,%%db3\n\t"::"r"(contents)); + break; + case 4: + case 5: + break; + case 6: + __asm__ ("movl %0,%%db6\n\t"::"r"(contents)); + break; + case 7: + __asm__ ("movl %0,%%db7\n\t"::"r"(contents)); + break; + default: + break; + } +} + +/* + * kdba_getregcontents + * + * Return the contents of the register specified by the + * input string argument. Return an error if the string + * does not match a machine register. + * + * The following pseudo register names are supported: + * ®s - Prints address of exception frame + * kesp - Prints kernel stack pointer at time of fault + * cesp - Prints current kernel stack pointer, inside kdb + * ceflags - Prints current flags, inside kdb + * % - Uses the value of the registers at the + * last time the user process entered kernel + * mode, instead of the registers at the time + * kdb was entered. + * + * Parameters: + * regname Pointer to string naming register + * regs Pointer to structure containing registers. + * Outputs: + * *contents Pointer to unsigned long to recieve register contents + * Returns: + * 0 Success + * KDB_BADREG Invalid register name + * Locking: + * None. + * Remarks: + * If kdb was entered via an interrupt from the kernel itself then + * ss and esp are *not* on the stack. + */ + +static struct kdbregs { + char *reg_name; + size_t reg_offset; +} kdbreglist[] = { + { "eax", offsetof(struct pt_regs, eax) }, + { "ebx", offsetof(struct pt_regs, ebx) }, + { "ecx", offsetof(struct pt_regs, ecx) }, + { "edx", offsetof(struct pt_regs, edx) }, + + { "esi", offsetof(struct pt_regs, esi) }, + { "edi", offsetof(struct pt_regs, edi) }, + { "esp", offsetof(struct pt_regs, esp) }, + { "eip", offsetof(struct pt_regs, eip) }, + + { "ebp", offsetof(struct pt_regs, ebp) }, + { "xss", offsetof(struct pt_regs, xss) }, + { "xcs", offsetof(struct pt_regs, xcs) }, + { "eflags", offsetof(struct pt_regs, eflags) }, + + { "xds", offsetof(struct pt_regs, xds) }, + { "xes", offsetof(struct pt_regs, xes) }, + { "origeax", offsetof(struct pt_regs, orig_eax) }, + +}; + +static const int nkdbreglist = sizeof(kdbreglist) / sizeof(struct kdbregs); + +static struct kdbregs dbreglist[] = { + { "dr0", 0 }, + { "dr1", 1 }, + { "dr2", 2 }, + { "dr3", 3 }, + { "dr6", 6 }, + { "dr7", 7 }, +}; + +static const int ndbreglist = sizeof(dbreglist) / sizeof(struct kdbregs); + +int +kdba_getregcontents(const char *regname, + struct pt_regs *regs, + kdb_machreg_t *contents) +{ + int i; + + if (strcmp(regname, "®s") == 0) { + *contents = (unsigned long)regs; + return 0; + } + + if (strcmp(regname, "kesp") == 0) { + *contents = (unsigned long)regs + sizeof(struct pt_regs); + if ((regs->xcs & 0xffff) == __KERNEL_CS) { + /* esp and ss are not on stack */ + *contents -= 2*4; + } + return 0; + } + + if (strcmp(regname, "cesp") == 0) { + asm volatile("movl %%esp,%0":"=m" (*contents)); + return 0; + } + + if (strcmp(regname, "ceflags") == 0) { + int flags; + __save_flags(flags); + *contents = flags; + return 0; + } + + if (regname[0] == '%') { + /* User registers: %%e[a-c]x, etc */ + regname++; + regs = (struct pt_regs *) + (current->thread.esp0 - sizeof(struct pt_regs)); + } + + for (i=0; ixcs & 0xffff) == __KERNEL_CS) { + /* No cpl switch, esp and ss are not on stack */ + if (strcmp(kdbreglist[i].reg_name, "esp") == 0) { + *contents = (kdb_machreg_t)regs + + sizeof(struct pt_regs) - 2*4; + return(0); + } + if (strcmp(kdbreglist[i].reg_name, "xss") == 0) { + asm volatile( + "pushl %%ss\n" + "popl %0\n" + :"=m" (*contents)); + return(0); + } + } + *contents = *(unsigned long *)((unsigned long)regs + + kdbreglist[i].reg_offset); + return(0); + } + + for (i=0; i + * + * Parameters: + * regname Pointer to string naming register + * regs Pointer to structure containing registers. + * contents Unsigned long containing new register contents + * Outputs: + * Returns: + * 0 Success + * KDB_BADREG Invalid register name + * Locking: + * None. + * Remarks: + */ + +int +kdba_setregcontents(const char *regname, + struct pt_regs *regs, + unsigned long contents) +{ + int i; + + if (regname[0] == '%') { + regname++; + regs = (struct pt_regs *) + (current->thread.esp0 - sizeof(struct pt_regs)); + } + + for (i=0; ithread.esp0 - sizeof(struct pt_regs)); + } + + if (type == NULL) { + struct kdbregs *rlp; + kdb_machreg_t contents; + + for (i=0, rlp=kdbreglist; ieip; +} + +int +kdba_setpc(kdb_eframe_t ef, kdb_machreg_t newpc) +{ + ef->eip = newpc; + KDB_STATE_SET(IP_ADJUSTED); + return 0; +} + +/* + * kdba_main_loop + * + * Do any architecture specific set up before entering the main kdb loop. + * The primary function of this routine is to make all processes look the + * same to kdb, kdb must be able to list a process without worrying if the + * process is running or blocked, so make all process look as though they + * are blocked. + * + * Inputs: + * reason The reason KDB was invoked + * error The hardware-defined error code + * error2 kdb's current reason code. Initially error but can change + * acording to kdb state. + * db_result Result from break or debug point. + * ef The exception frame at time of fault/breakpoint. If reason + * is KDB_REASON_SILENT then ef is NULL, otherwise it should + * always be valid. + * Returns: + * 0 KDB was invoked for an event which it wasn't responsible + * 1 KDB handled the event for which it was invoked. + * Outputs: + * Sets eip and esp in current->thread. + * Locking: + * None. + * Remarks: + * none. + */ + +int +kdba_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error, + kdb_dbtrap_t db_result, kdb_eframe_t ef) +{ + if (ef) { + kdba_getregcontents("eip", ef, &(current->thread.eip)); + kdba_getregcontents("esp", ef, &(current->thread.esp)); + } + return(kdb_main_loop(reason, reason2, error, db_result, ef)); +} + +void +kdba_disableint(kdb_intstate_t *state) +{ + int *fp = (int *)state; + int flags; + + __save_flags(flags); + __cli(); + + *fp = flags; +} + +void +kdba_restoreint(kdb_intstate_t *state) +{ + int flags = *(int *)state; + __restore_flags(flags); +} + +void +kdba_setsinglestep(struct pt_regs *regs) +{ + if (regs->eflags & EF_IE) + KDB_STATE_SET(A_IF); + else + KDB_STATE_CLEAR(A_IF); + regs->eflags = (regs->eflags | EF_TF) & ~EF_IE; +} + +void +kdba_clearsinglestep(struct pt_regs *regs) +{ + if (KDB_STATE(A_IF)) + regs->eflags |= EF_IE; + else + regs->eflags &= ~EF_IE; +} + +int +kdb_getcurrentframe(struct pt_regs *regs) +{ + regs->xcs = 0; +#if defined(CONFIG_FRAME_POINTER) + asm volatile("movl %%ebp,%0":"=m" (*(int *)®s->ebp)); +#endif + asm volatile("movl %%esp,%0":"=m" (*(int *)®s->esp)); + + return 0; +} + +#ifdef KDB_HAVE_LONGJMP +int +kdb_setjmp(kdb_jmp_buf *jb) +{ +#if defined(CONFIG_FRAME_POINTER) + __asm__ ("movl 8(%esp), %eax\n\t" + "movl %ebx, 0(%eax)\n\t" + "movl %esi, 4(%eax)\n\t" + "movl %edi, 8(%eax)\n\t" + "movl (%esp), %ecx\n\t" + "movl %ecx, 12(%eax)\n\t" + "leal 8(%esp), %ecx\n\t" + "movl %ecx, 16(%eax)\n\t" + "movl 4(%esp), %ecx\n\t" + "movl %ecx, 20(%eax)\n\t"); +#else /* CONFIG_FRAME_POINTER */ + __asm__ ("movl 4(%esp), %eax\n\t" + "movl %ebx, 0(%eax)\n\t" + "movl %esi, 4(%eax)\n\t" + "movl %edi, 8(%eax)\n\t" + "movl %ebp, 12(%eax)\n\t" + "leal 4(%esp), %ecx\n\t" + "movl %ecx, 16(%eax)\n\t" + "movl 0(%esp), %ecx\n\t" + "movl %ecx, 20(%eax)\n\t"); +#endif /* CONFIG_FRAME_POINTER */ + KDB_STATE_SET(LONGJMP); + return 0; +} + +void +kdb_longjmp(kdb_jmp_buf *jb, int reason) +{ +#if defined(CONFIG_FRAME_POINTER) + __asm__("movl 8(%esp), %ecx\n\t" + "movl 12(%esp), %eax\n\t" + "movl 20(%ecx), %edx\n\t" + "movl 0(%ecx), %ebx\n\t" + "movl 4(%ecx), %esi\n\t" + "movl 8(%ecx), %edi\n\t" + "movl 12(%ecx), %ebp\n\t" + "movl 16(%ecx), %esp\n\t" + "jmp *%edx\n"); +#else /* CONFIG_FRAME_POINTER */ + __asm__("movl 4(%esp), %ecx\n\t" + "movl 8(%esp), %eax\n\t" + "movl 20(%ecx), %edx\n\t" + "movl 0(%ecx), %ebx\n\t" + "movl 4(%ecx), %esi\n\t" + "movl 8(%ecx), %edi\n\t" + "movl 12(%ecx), %ebp\n\t" + "movl 16(%ecx), %esp\n\t" + "jmp *%edx\n"); +#endif /* CONFIG_FRAME_POINTER */ +} +#endif /* KDB_HAVE_LONGJMP */ + + +/* + * kdba_enable_mce + * + * This function is called once on each CPU to enable machine + * check exception handling. + * + * Inputs: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * + */ + +void +kdba_enable_mce(void) +{ + /* + * Enable Machine Check Exceptions + */ + if (test_bit(X86_FEATURE_MCE, &boot_cpu_data.x86_capability) && + test_bit(X86_FEATURE_MCA, &boot_cpu_data.x86_capability)) { + u32 i, lv, hv, count; + rdmsr(MCG_CAP, lv, hv); + count = lv&0xff; + if (lv & 0x100) { + hv = lv = 0xffffffff; + wrmsr(MCG_CTL, lv, hv); + } + for(i=1; i (unsigned long)high_memory) { + if (!kdb_vmlist_check(addr, addr+width)) { + /* + * Would appear to be an illegal kernel address; + * Print a message once, and don't print again until + * a legal address is used. + */ + if (!KDB_STATE(SUPPRESS)) { + kdb_printf("kdb: Bad kernel address 0x%lx\n", addr); + KDB_STATE_SET(SUPPRESS); + } + return 0L; + } + } + + /* + * A good address. Reset error flag. + */ + KDB_STATE_CLEAR(SUPPRESS); + + switch (width) { + case 4: + { unsigned long *lp; + + lp = (unsigned long *)(addr); + return *lp; + } + case 2: + { unsigned short *sp; + + sp = (unsigned short *)(addr); + return *sp; + } + case 1: + { unsigned char *cp; + + cp = (unsigned char *)(addr); + return *cp; + } + } + + kdb_printf("kdbgetword: Bad width\n"); + return 0L; +} + +/* + * kdba_putword + * + * Architecture specific function to access kernel virtual + * address space. + * + * Parameters: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * None. + */ + +unsigned long +kdba_putword(unsigned long addr, size_t size, unsigned long contents) +{ + /* + * This function checks the address for validity. Any address + * in the range PAGE_OFFSET to high_memory is legal, any address + * which maps to a vmalloc region is legal, and any address which + * is a user address, we use get_user() to verify validity. + */ + + if (addr < PAGE_OFFSET) { + /* + * Usermode address. + */ + unsigned long diag; + + switch (size) { + case 4: + { unsigned long *lp; + + lp = (unsigned long *) addr; + diag = put_user(contents, lp); + break; + } + case 2: + { unsigned short *sp; + + sp = (unsigned short *) addr; + diag = put_user(contents, sp); + break; + } + case 1: + { unsigned char *cp; + + cp = (unsigned char *) addr; + diag = put_user(contents, cp); + break; + } + default: + kdb_printf("kdba_putword: Bad width\n"); + return 0; + } + + if (diag) { + if (!KDB_STATE(SUPPRESS)) { + kdb_printf("kdb: Bad user address 0x%lx\n", addr); + KDB_STATE_SET(SUPPRESS); + } + return 0; + } + KDB_STATE_CLEAR(SUPPRESS); + return 0; + } + + if (addr > (unsigned long)high_memory) { + if (!kdb_vmlist_check(addr, addr+size)) { + /* + * Would appear to be an illegal kernel address; + * Print a message once, and don't print again until + * a legal address is used. + */ + if (!KDB_STATE(SUPPRESS)) { + kdb_printf("kdb: Bad kernel address 0x%lx\n", addr); + KDB_STATE_SET(SUPPRESS); + } + return 0L; + } + } + + /* + * A good address. Reset error flag. + */ + KDB_STATE_CLEAR(SUPPRESS); + + switch (size) { + case 4: + { unsigned long *lp; + + lp = (unsigned long *)(addr); + *lp = contents; + return 0; + } + case 2: + { unsigned short *sp; + + sp = (unsigned short *)(addr); + *sp = (unsigned short) contents; + return 0; + } + case 1: + { unsigned char *cp; + + cp = (unsigned char *)(addr); + *cp = (unsigned char) contents; + return 0; + } + } + + kdb_printf("kdba_putword: Bad width\n"); + return 0; +} + +/* + * kdba_callback_die + * + * Callback function for kernel 'die' function. + * + * Parameters: + * regs Register contents at time of trap + * error_code Trap-specific error code value + * trapno Trap number + * vp Pointer to die message + * Returns: + * Returns 1 if fault handled by kdb. + * Locking: + * None. + * Remarks: + * + */ +int +kdba_callback_die(struct pt_regs *regs, int error_code, long trapno, void *vp) +{ + /* + * Save a pointer to the message provided to 'die()'. + */ + kdb_diemsg = (char *)vp; + + return kdb(KDB_REASON_OOPS, error_code, (kdb_eframe_t) regs); +} + +/* + * kdba_callback_bp + * + * Callback function for kernel breakpoint trap. + * + * Parameters: + * regs Register contents at time of trap + * error_code Trap-specific error code value + * trapno Trap number + * vp Not Used. + * Returns: + * Returns 1 if fault handled by kdb. + * Locking: + * None. + * Remarks: + * + */ + +int +kdba_callback_bp(struct pt_regs *regs, int error_code, long trapno, void *vp) +{ + int diag; + + if (KDB_DEBUG(BP)) + kdb_printf("cb_bp: e_c = %d tn = %ld regs = 0x%p\n", error_code, + trapno, regs); + + diag = kdb(KDB_REASON_BREAK, error_code, (kdb_eframe_t) regs); + + if (KDB_DEBUG(BP)) + kdb_printf("cb_bp: e_c = %d tn = %ld regs = 0x%p diag = %d\n", error_code, + trapno, regs, diag); + return diag; +} + +/* + * kdba_callback_debug + * + * Callback function for kernel debug register trap. + * + * Parameters: + * regs Register contents at time of trap + * error_code Trap-specific error code value + * trapno Trap number + * vp Not used. + * Returns: + * Returns 1 if fault handled by kdb. + * Locking: + * None. + * Remarks: + * + */ + +int +kdba_callback_debug(struct pt_regs *regs, int error_code, long trapno, void *vp) +{ + return kdb(KDB_REASON_DEBUG, error_code, (kdb_eframe_t) regs); +} + +/* + * kdba_init + * + * Architecture specific initialization. + * + * Parameters: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * None. + */ + +void __init +kdba_init(void) +{ + kdba_enable_lbr(); + + return; +} + +/* + * kdba_adjust_ip + * + * Architecture specific adjustment of instruction pointer before leaving + * kdb. + * + * Parameters: + * reason The reason KDB was invoked + * error The hardware-defined error code + * ef The exception frame at time of fault/breakpoint. If reason + * is KDB_REASON_SILENT then ef is NULL, otherwise it should + * always be valid. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * noop on ix86. + */ + +void +kdba_adjust_ip(kdb_reason_t reason, int error, kdb_eframe_t ef) +{ + return; +} diff -rNu linux-2.4.7/linux/arch/i386/kernel/CVS/Entries linux-2.4-xfs/linux/arch/i386/kernel/CVS/Entries --- linux-2.4.7/linux/arch/i386/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/kernel/CVS/Entries Thu Jul 5 11:48:04 2001 @@ -0,0 +1,41 @@ +/Makefile/1.21/Wed Jan 3 01:43:05 2001/-ko/ +/apic.c/1.17/Thu Jun 21 15:45:04 2001/-ko/ +/apm.c/1.31/Wed May 2 06:22:13 2001/-ko/ +/bluesmoke.c/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/cpuid.c/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/dmi_scan.c/1.4/Thu Jul 5 06:13:42 2001/-ko/ +/entry.S/1.34/Wed Jun 13 03:24:09 2001/-ko/ +/head.S/1.19/Thu Jun 21 15:45:04 2001/-ko/ +/i386_ksyms.c/1.38/Tue Jul 3 02:33:57 2001/-ko/ +/i387.c/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/i8259.c/1.22/Thu Jun 21 15:45:04 2001/-ko/ +/init_task.c/1.5/Sun Aug 29 02:07:15 1999/-ko/ +/io_apic.c/1.28/Thu Jun 21 15:45:04 2001/-ko/ +/ioport.c/1.3/Tue Jul 27 20:02:32 1999/-ko/ +/irq.c/1.35/Thu Jun 21 15:45:04 2001/-ko/ +/ldt.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/mca.c/1.11/Thu Sep 28 22:42:39 2000/-ko/ +/microcode.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/mpparse.c/1.9/Wed Jun 6 03:10:14 2001/-ko/ +/msr.c/1.7/Tue Feb 27 05:07:04 2001/-ko/ +/mtrr.c/1.26/Tue May 29 19:53:13 2001/-ko/ +/pci-dma.c/1.2/Thu Feb 17 20:30:57 2000/-ko/ +/pci-i386.c/1.16/Tue May 29 19:53:13 2001/-ko/ +/pci-i386.h/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/pci-irq.c/1.16/Thu Jul 5 06:13:42 2001/-ko/ +/pci-pc.c/1.23/Thu Jun 21 15:45:04 2001/-ko/ +/pci-visws.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/process.c/1.32/Thu Jul 5 06:13:42 2001/-ko/ +/ptrace.c/1.13/Mon Apr 2 17:13:32 2001/-ko/ +/semaphore.c/1.15/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.47/Thu Jul 5 06:13:42 2001/-ko/ +/signal.c/1.17/Thu Jul 5 06:13:42 2001/-ko/ +/smp.c/1.32/Wed May 2 06:22:13 2001/-ko/ +/smpboot.c/1.21/Thu Feb 22 21:09:04 2001/-ko/ +/sys_i386.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/time.c/1.15/Wed Jan 3 01:43:05 2001/-ko/ +/trampoline.S/1.3/Fri Feb 11 00:16:16 2000/-ko/ +/traps.c/1.37/Thu Jun 21 15:45:04 2001/-ko/ +/visws_apic.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/vm86.c/1.8/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/i386/kernel/CVS/Repository linux-2.4-xfs/linux/arch/i386/kernel/CVS/Repository --- linux-2.4.7/linux/arch/i386/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/kernel/CVS/Repository Thu Jul 5 11:47:51 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/i386/kernel diff -rNu linux-2.4.7/linux/arch/i386/kernel/CVS/Root linux-2.4-xfs/linux/arch/i386/kernel/CVS/Root --- linux-2.4.7/linux/arch/i386/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/kernel/CVS/Root Thu Jul 5 11:47:51 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/i386/kernel/apic.c linux-2.4-xfs/linux/arch/i386/kernel/apic.c --- linux-2.4.7/linux/arch/i386/kernel/apic.c Wed Jun 20 13:06:38 2001 +++ linux-2.4-xfs/linux/arch/i386/kernel/apic.c Thu Jun 21 10:45:04 2001 @@ -28,6 +28,8 @@ #include #include #include +#include +#include int prof_multiplier[NR_CPUS] = { 1, }; int prof_old_multiplier[NR_CPUS] = { 1, }; @@ -202,6 +204,62 @@ | APIC_DM_INIT); } +/* + * Set the counter value for the local APIC NMI watchdog. + */ + +int set_nmi_counter_local(void) +{ + extern unsigned long cpu_khz; + + if (!test_bit(X86_FEATURE_APIC, &boot_cpu_data.x86_capability)) + return(-EIO); + if (nmi_watchdog_source && nmi_watchdog_source != 1) + return(0); /* Not using local APIC */ + return wrmsr_eio(PERFCTR1, -(cpu_khz/HZ*1000), 0); +} + +/* + * Activate or deactivate NMI watchdog via a local APIC. + */ + +int setup_apic_nmi_watchdog(int value) +{ + int ret, eax; + + if (!test_bit(X86_FEATURE_APIC, &boot_cpu_data.x86_capability)) + return(-EIO); + if (nmi_watchdog_source && nmi_watchdog_source != 1) + return(0); /* Not using local APIC */ + /* Disable performance counters 0, 1 for all NMI changes */ + nmi_watchdog = proc_nmi_watchdog = nmi_watchdog_source = 0; + if ((ret = wrmsr_eio(EVNTSEL0, 0, 0)) || + (ret = wrmsr_eio(EVNTSEL1, 0, 0)) || + (ret = wrmsr_eio(PERFCTR0, 0, 0)) || + (ret = wrmsr_eio(PERFCTR1, 0, 0))) + goto exit; + if (!value) + return(0); + /* Must set before activation to catch first NMI */ + nmi_watchdog = proc_nmi_watchdog = nmi_watchdog_source = 1; + eax = 1 << 20 /* Interrupt on overflow */ + | 1 << 17 /* OS mode */ + | 1 << 16 /* User mode */ + | 0x79; /* Event, cpu clocks not halted */ + if ((ret = wrmsr_eio(EVNTSEL1, eax, 0)) + || (ret = set_nmi_counter_local())) + goto exit; + apic_write_around(APIC_LVTPC, APIC_DM_NMI); + eax = 1 << 22; /* Enable performance counters, only using ctr1 */ + ret = wrmsr_eio(EVNTSEL0, eax, 0); +exit: + if (ret) + nmi_watchdog = proc_nmi_watchdog = nmi_watchdog_source = 0; + else + printk(KERN_INFO "Activated NMI via local APIC\n"); + return(ret); +} + extern void __error_in_apic_c (void); void __init setup_local_APIC (void) @@ -345,18 +403,16 @@ { unsigned long apic_phys; - if (smp_found_config) { - apic_phys = mp_lapic_addr; - } else { - /* - * set up a fake all zeroes page to simulate the - * local APIC and another one for the IO-APIC. We - * could use the real zero-page, but it's safer - * this way if some buggy code writes to this page ... - */ - apic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); - apic_phys = __pa(apic_phys); - } + /* + * Now that we make more of an effort to enable the local APIC even + * when we could find no SMP config information, we always map the + * APIC registers correctly (ie. the zero-page trick has been + * removed). See `IO_APIC_init_uniprocessor' in io_apic.c for more + * info. + */ + if ( !smp_found_config ) mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; + apic_phys = mp_lapic_addr; + set_fixmap_nocache(FIX_APIC_BASE, apic_phys); Dprintk("mapped APIC to %08lx (%08lx)\n", APIC_BASE, apic_phys); diff -rNu linux-2.4.7/linux/arch/i386/kernel/bluesmoke.c linux-2.4-xfs/linux/arch/i386/kernel/bluesmoke.c --- linux-2.4.7/linux/arch/i386/kernel/bluesmoke.c Sun Jul 1 21:52:45 2001 +++ linux-2.4-xfs/linux/arch/i386/kernel/bluesmoke.c Mon Jul 2 21:33:57 2001 @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -105,6 +106,7 @@ void do_machine_check(struct pt_regs * regs, long error_code) { machine_check_vector(regs, error_code); + (void)kdb(KDB_REASON_NMI, error_code, regs); } /* diff -rNu linux-2.4.7/linux/arch/i386/kernel/entry.S linux-2.4-xfs/linux/arch/i386/kernel/entry.S --- linux-2.4.7/linux/arch/i386/kernel/entry.S Tue Jun 12 13:47:28 2001 +++ linux-2.4-xfs/linux/arch/i386/kernel/entry.S Tue Jun 12 22:24:09 2001 @@ -185,6 +185,18 @@ jne tracesys_exit jmp ret_from_sys_call +#if defined(CONFIG_KDB) +ENTRY(kdb_call) + pushl %eax # save orig EAX + SAVE_ALL + pushl %esp # struct pt_regs + pushl $0 # error_code + pushl $7 # KDB_REASON_ENTRY + call SYMBOL_NAME(kdb) + addl $12,%esp # remove args + RESTORE_ALL +#endif + /* * Return to user mode is not as complex as all this looks, * but we want the default path for a system call return to @@ -381,6 +393,22 @@ pushl $ SYMBOL_NAME(do_alignment_check) jmp error_code +#if defined(CONFIG_KDB) +ENTRY(page_fault_mca) + pushl %ecx + pushl %edx + pushl %eax + movl $473,%ecx + rdmsr + andl $0xfffffffe,%eax /* Disable last branch recording */ + wrmsr + popl %eax + popl %edx + popl %ecx + pushl $ SYMBOL_NAME(do_page_fault) + jmp error_code +#endif + ENTRY(page_fault) pushl $ SYMBOL_NAME(do_page_fault) jmp error_code @@ -619,7 +647,37 @@ .long SYMBOL_NAME(sys_madvise) .long SYMBOL_NAME(sys_getdents64) /* 220 */ .long SYMBOL_NAME(sys_fcntl64) - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */ + .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */ + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) /* 225 */ + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) /* 230 */ + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) /* 235 */ + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) /* 240 */ + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) /* 245 */ + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_ni_syscall) + .long SYMBOL_NAME(sys_attrctl) /* 250 */ + .long SYMBOL_NAME(sys_acl_get) + .long SYMBOL_NAME(sys_acl_set) /* * NOTE!! This doesn't have to be exact - we just have @@ -627,6 +685,6 @@ * entries. Don't panic if you notice that this hasn't * been shrunk every time we add a new system call. */ - .rept NR_syscalls-221 + .rept NR_syscalls-252 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -rNu linux-2.4.7/linux/arch/i386/kernel/i8259.c linux-2.4-xfs/linux/arch/i386/kernel/i8259.c --- linux-2.4.7/linux/arch/i386/kernel/i8259.c Wed Jun 20 13:06:38 2001 +++ linux-2.4-xfs/linux/arch/i386/kernel/i8259.c Thu Jun 21 10:45:04 2001 @@ -452,7 +452,11 @@ */ for (i = 0; i < NR_IRQS; i++) { int vector = FIRST_EXTERNAL_VECTOR + i; - if (vector != SYSCALL_VECTOR) + if ((vector != SYSCALL_VECTOR) +#if defined(CONFIG_KDB) + && (vector != KDBENTER_VECTOR) +#endif + ) set_intr_gate(vector, interrupt[i]); } diff -rNu linux-2.4.7/linux/arch/i386/kernel/io_apic.c linux-2.4-xfs/linux/arch/i386/kernel/io_apic.c --- linux-2.4.7/linux/arch/i386/kernel/io_apic.c Wed Jun 20 13:06:38 2001 +++ linux-2.4-xfs/linux/arch/i386/kernel/io_apic.c Thu Jun 21 10:45:04 2001 @@ -1385,7 +1385,7 @@ apic_write_around(APIC_LVT0, v); } -static void setup_nmi (void) +static void setup_nmi_io (void) { /* * Dirty trick to enable the NMI watchdog ... @@ -1402,6 +1402,8 @@ enable_NMI_through_LVT0(NULL); printk(" done.\n"); + proc_nmi_watchdog = nmi_watchdog = 1; + nmi_watchdog_source = 2; } /* @@ -1503,7 +1505,7 @@ if (timer_irq_works()) { if (nmi_watchdog) { disable_8259A_irq(0); - setup_nmi(); + setup_nmi_io(); enable_8259A_irq(0); nmi_irq_works(); } @@ -1523,7 +1525,7 @@ if (timer_irq_works()) { printk("works.\n"); if (nmi_watchdog) { - setup_nmi(); + setup_nmi_io(); nmi_irq_works(); } return; @@ -1613,11 +1615,91 @@ */ void IO_APIC_init_uniprocessor (void) { + /* + * For real non-SMP machines, we now make more of an effort to + * actually enable the local APIC. We do this without enabling any IO + * APICs (without smp_config info we don't know if there are any!). + */ if (!smp_found_config) - return; + { + u32 h, l, dummy, features; + + if ( boot_cpu_data.x86 < 5 ) + { + printk("No local APIC on pre-Pentium Intel processors\n"); + return; + } + + if ( boot_cpu_data.x86 == 6 ) + { + /* + * Some BIOSes disable the local APIC in the APIC_BASE MSR. + * This can only be done in software for PPro and above. + */ + rdmsr(0x1b, l, h); + if ( !(l & 0x800) ) + { + printk("Local APIC disabled by BIOS -- reenabling...\n"); + l |= 0x800; + wrmsr(0x1b, l, h); + + /* The APIC feature bit should now be enabled in `cpuid' */ + cpuid(1, &dummy, &dummy, &dummy, &features); + if ( !(features & X86_FEATURE_APIC) ) + { + printk("Could not enable APIC -- support disabled\n"); + return; + } + } + } + + /* + * Make sure that we are processor 0, and that we are indicated + * as present. This stuff doesn't normally get done on a + * uniprocessor machine. + */ + phys_cpu_present_map = 1; + apic_read_around(APIC_ID); /* buggy P5 paranoia */ + apic_write_around(APIC_ID, 0); + + /* + * A final sanity check. Early P5 processors don't have a local + * APIC. Also, a P5 local APIC can be disabled in hardware! + */ + if ( apic_read(APIC_ID) != 0 ) + { + printk("Can't find local APIC: non-existent or disabled" + "in hardware\n"); + return; + } + + /* Now we know the APIC is enabled, update CPU features flags */ + set_bit(X86_FEATURE_APIC, &boot_cpu_data.x86_capability); + + /* + * Not sure about this, but it stops external INTs being masked! + * This is necessary because we don't initialise any IO APICs: + * (a) they weren't memory-mapped by `init_apic_mappings' because + * it didn't find any smp configuration info. + * (b) in a uniprocessor system, an IO APIC is redundant because + * all external INTs must go to the only processor. + */ + pic_mode = 1; + nr_ioapics = 0; + } + connect_bsp_APIC(); setup_local_APIC(); - setup_IO_APIC(); - setup_APIC_clocks(); + + /* + * We only set up IO APICs for a real SMP machine. Otherwise external + * INTs get masked locally, without them being routed to an IO APIC. + */ + if ( smp_found_config ) + { + setup_IO_APIC(); + } + + setup_APIC_clocks(); } #endif diff -rNu linux-2.4.7/linux/arch/i386/kernel/irq.c linux-2.4-xfs/linux/arch/i386/kernel/irq.c --- linux-2.4.7/linux/arch/i386/kernel/irq.c Wed Jun 20 13:06:38 2001 +++ linux-2.4-xfs/linux/arch/i386/kernel/irq.c Thu Jun 21 10:45:04 2001 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -316,6 +317,11 @@ static inline void get_irqlock(int cpu) { +#ifdef CONFIG_KDB + static int kdb_rate; + if (KDB_IS_RUNNING() && kdb_rate++ < 10) + kdb_printf("Warning: get_irqlock on cpu %d while kdb is running, may hang\n", smp_processor_id()); +#endif /* CONFIG_KDB */ if (test_and_set_bit(0,&global_irq_lock)) { /* do we already hold the lock? */ if ((unsigned char) cpu == global_irq_holder) diff -rNu linux-2.4.7/linux/arch/i386/kernel/msr.c linux-2.4-xfs/linux/arch/i386/kernel/msr.c --- linux-2.4.7/linux/arch/i386/kernel/msr.c Sun Dec 31 11:24:08 2000 +++ linux-2.4-xfs/linux/arch/i386/kernel/msr.c Mon Feb 26 23:07:04 2001 @@ -1,4 +1,4 @@ -#ident "$Id$" +#ident "$Id: msr.c 1.2 Fri, 05 Jan 2001 15:09:28 +1100 kaos $" /* ----------------------------------------------------------------------- * * * Copyright 2000 H. Peter Anvin - All Rights Reserved @@ -39,51 +39,7 @@ #include #include #include - -/* Note: "err" is handled in a funny way below. Otherwise one version - of gcc or another breaks. */ - -extern inline int wrmsr_eio(u32 reg, u32 eax, u32 edx) -{ - int err; - - asm volatile( - "1: wrmsr\n" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: movl %4,%0\n" - " jmp 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b,3b\n" - ".previous" - : "=&bDS" (err) - : "a" (eax), "d" (edx), "c" (reg), "i" (-EIO), "0" (0)); - - return err; -} - -extern inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx) -{ - int err; - - asm volatile( - "1: rdmsr\n" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: movl %4,%0\n" - " jmp 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b,3b\n" - ".previous" - : "=&bDS" (err), "=a" (*eax), "=d" (*edx) - : "c" (reg), "i" (-EIO), "0" (0)); - - return err; -} +#include #ifdef CONFIG_SMP diff -rNu linux-2.4.7/linux/arch/i386/kernel/process.c linux-2.4-xfs/linux/arch/i386/kernel/process.c --- linux-2.4.7/linux/arch/i386/kernel/process.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/i386/kernel/process.c Thu Jul 5 01:13:42 2001 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -350,7 +351,16 @@ * Stop all CPUs and turn off local APICs and the IO-APIC, so * other OSs see a clean IRQ state. */ +#if defined(CONFIG_KDB) + /* + * If this restart is occuring while kdb is running (e.g. reboot + * command), the other CPU's are already stopped. Don't try to + * stop them yet again. + */ + if (!KDB_IS_RUNNING()) +#endif smp_send_stop(); + disable_IO_APIC(); #endif diff -rNu linux-2.4.7/linux/arch/i386/kernel/semaphore.c linux-2.4-xfs/linux/arch/i386/kernel/semaphore.c --- linux-2.4.7/linux/arch/i386/kernel/semaphore.c Thu Apr 12 14:22:53 2001 +++ linux-2.4-xfs/linux/arch/i386/kernel/semaphore.c Wed May 2 01:22:13 2001 @@ -182,6 +182,10 @@ ".align 4\n" ".globl __down_failed\n" "__down_failed:\n\t" +#if defined(CONFIG_FRAME_POINTER) + "pushl %ebp\n\t" + "movl %esp,%ebp\n\t" +#endif "pushl %eax\n\t" "pushl %edx\n\t" "pushl %ecx\n\t" @@ -189,6 +193,10 @@ "popl %ecx\n\t" "popl %edx\n\t" "popl %eax\n\t" +#if defined(CONFIG_FRAME_POINTER) + "movl %ebp,%esp\n\t" + "popl %ebp\n\t" +#endif "ret" ); @@ -197,11 +205,19 @@ ".align 4\n" ".globl __down_failed_interruptible\n" "__down_failed_interruptible:\n\t" +#if defined(CONFIG_FRAME_POINTER) + "pushl %ebp\n\t" + "movl %esp,%ebp\n\t" +#endif "pushl %edx\n\t" "pushl %ecx\n\t" "call __down_interruptible\n\t" "popl %ecx\n\t" "popl %edx\n\t" +#if defined(CONFIG_FRAME_POINTER) + "movl %ebp,%esp\n\t" + "popl %ebp\n\t" +#endif "ret" ); @@ -210,11 +226,19 @@ ".align 4\n" ".globl __down_failed_trylock\n" "__down_failed_trylock:\n\t" +#if defined(CONFIG_FRAME_POINTER) + "pushl %ebp\n\t" + "movl %esp,%ebp\n\t" +#endif "pushl %edx\n\t" "pushl %ecx\n\t" "call __down_trylock\n\t" "popl %ecx\n\t" "popl %edx\n\t" +#if defined(CONFIG_FRAME_POINTER) + "movl %ebp,%esp\n\t" + "popl %ebp\n\t" +#endif "ret" ); diff -rNu linux-2.4.7/linux/arch/i386/kernel/smp.c linux-2.4-xfs/linux/arch/i386/kernel/smp.c --- linux-2.4.7/linux/arch/i386/kernel/smp.c Tue Feb 13 16:13:43 2001 +++ linux-2.4-xfs/linux/arch/i386/kernel/smp.c Wed May 2 01:22:13 2001 @@ -21,6 +21,9 @@ #include #include +#include +#include + /* * Some notes on x86 processor bugs affecting SMP operation: * @@ -142,6 +145,15 @@ */ cfg = __prepare_ICR(shortcut, vector); +#if defined(CONFIG_KDB) + if (vector == KDB_VECTOR) { + /* + * Setup KDB IPI to be delivered as an NMI + */ + cfg = (cfg&~APIC_VECTOR_MASK)|APIC_DM_NMI; + } +#endif /* CONFIG_KDB */ + /* * Send the IPI. The write to APIC_ICR fires this off. */ @@ -405,6 +417,14 @@ do_flush_tlb_all_local(); } + +#if defined(CONFIG_KDB) +void +smp_kdb_stop(void) +{ + send_IPI_allbutself(KDB_VECTOR); +} +#endif /* CONFIG_KDB */ /* * this function sends a 'reschedule' IPI to another CPU. diff -rNu linux-2.4.7/linux/arch/i386/kernel/smpboot.c linux-2.4-xfs/linux/arch/i386/kernel/smpboot.c --- linux-2.4.7/linux/arch/i386/kernel/smpboot.c Tue Feb 13 16:13:43 2001 +++ linux-2.4-xfs/linux/arch/i386/kernel/smpboot.c Thu Feb 22 15:09:04 2001 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -427,6 +428,11 @@ */ smp_store_cpu_info(cpuid); +#ifdef CONFIG_KDB + /* Activate any preset global breakpoints on this cpu */ + kdb(KDB_REASON_SILENT, 0, 0); +#endif /* CONFIG_KDB */ + /* * Allow the master to continue. */ @@ -545,6 +551,8 @@ unsigned long send_status, accept_status, boot_status, maxlvt; int timeout, num_starts, j, cpu; unsigned long start_eip; + + nmi_watchdog_source = 2; /* Must assume that we have a working IO-APIC */ cpu = ++cpucount; /* diff -rNu linux-2.4.7/linux/arch/i386/kernel/traps.c linux-2.4-xfs/linux/arch/i386/kernel/traps.c --- linux-2.4.7/linux/arch/i386/kernel/traps.c Wed Jun 20 15:59:44 2001 +++ linux-2.4-xfs/linux/arch/i386/kernel/traps.c Thu Jun 21 10:45:04 2001 @@ -30,6 +30,9 @@ #include #endif +#include +#include + #include #include #include @@ -50,6 +53,9 @@ #include asmlinkage int system_call(void); +#if defined(CONFIG_KDB) +asmlinkage int kdb_call(void); +#endif asmlinkage void lcall7(void); asmlinkage void lcall27(void); @@ -80,6 +86,9 @@ asmlinkage void stack_segment(void); asmlinkage void general_protection(void); asmlinkage void page_fault(void); +#if defined(CONFIG_KDB) +asmlinkage void page_fault_mca(void); +#endif asmlinkage void coprocessor_error(void); asmlinkage void simd_coprocessor_error(void); asmlinkage void alignment_check(void); @@ -212,16 +221,173 @@ printk("\n"); } +#if defined(CONFIG_KDB) +spinlock_t dblist_lock = SPIN_LOCK_UNLOCKED; + +#define MAXDBLIST 8 + +typedef int (*dbfunc_t)(struct pt_regs * regs, int error_code, + long trap, void *value); + +typedef struct __db_list_s { + struct __db_list_s *db_next; + dbfunc_t db_func; +} dblist_t; + +typedef struct __db_listhead_s { + dblist_t dblh_list[MAXDBLIST]; + dblist_t *dblh_head; + char *dblh_name; +} dblisthead_t; + + /* + * Hook-up list to 'die' function + */ +static dblisthead_t dblist_die = + { {{ NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }}, + NULL, + "die" + }; + + /* + * Hook-up list to int3 + */ +static dblisthead_t dblist_int3 = + { {{ NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }}, + NULL, + "int3" + }; + + /* + * Hook-up list to debug trap + */ +static dblisthead_t dblist_debug = + { {{ NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }, + { NULL, NULL }}, + NULL, + "debug" + }; + +static void register_dbfunc(dblisthead_t *lhp, dbfunc_t dfp) +{ + int i; + + spin_lock(&dblist_lock); + + if (KDB_DEBUG(CALLBACK)) + kdb_printf("listhead 0x%p func 0x%p\n", lhp, dfp); + + for(i=0; idblh_list[i].db_func == NULL) { + break; + } + } + if (i == MAXDBLIST) { + if (KDB_DEBUG(CALLBACK)) + kdb_printf("register_dbfunc: 0x%p not registered for %s\n", + dfp, lhp->dblh_name); + spin_unlock(&dblist_lock); + return; + } + + lhp->dblh_list[i].db_func = dfp; + lhp->dblh_list[i].db_next = lhp->dblh_head; + lhp->dblh_head = &lhp->dblh_list[i]; + + spin_unlock(&dblist_lock); +} + +void register_die(dbfunc_t dfp) +{ + register_dbfunc(&dblist_die, dfp); +} + +void register_int3(dbfunc_t dfp) +{ + register_dbfunc(&dblist_int3, dfp); +} + +void register_debug(dbfunc_t dfp) +{ + register_dbfunc(&dblist_debug, dfp); +} + +static inline int +callout_dbfunc(dblisthead_t *lhp, struct pt_regs *regs, int error_code, + long trap_number, void *parameter) +{ + dblist_t *dlp = lhp->dblh_head; + int diag = 0; + + if (KDB_DEBUG(CALLBACK)) + kdb_printf("callout dbfunc: cpu %d lhp 0x%p\n", smp_processor_id(), lhp); + /* If we oops inside kdb, we already have the dblist_lock */ + if (!KDB_IS_RUNNING()) + spin_lock(&dblist_lock); + while (dlp) { + int rv; + + /* + * The first callout function to handle this callout + * condition will return '1'. No other callout handlers + * will be invoked. Errors inside kdb will longjmp + * instead of returning. + */ + if (KDB_DEBUG(CALLBACK)) + kdb_printf("callout dbfunc: cpu %d func 0x%p\n", smp_processor_id(), dlp->db_func); + rv = dlp->db_func(regs, error_code, trap_number, parameter); + if (KDB_DEBUG(CALLBACK)) + kdb_printf("callout cpu %d diag %d\n", smp_processor_id(), rv); + if (rv) { + diag ++; + break; + } + + dlp = dlp->db_next; + } + if (!KDB_IS_RUNNING()) + spin_unlock(&dblist_lock); + if (KDB_DEBUG(CALLBACK)) + kdb_printf("callout dbfunc: cpu %d end\n", smp_processor_id()); + + return diag; +} +#endif + spinlock_t die_lock = SPIN_LOCK_UNLOCKED; void die(const char * str, struct pt_regs * regs, long err) { + unsigned long flags; console_verbose(); - spin_lock_irq(&die_lock); +#if defined(CONFIG_KDB) + (void) callout_dbfunc(&dblist_die, regs, err, -1, (void *)str); +#endif + spin_lock_irqsave(&die_lock, flags); printk("%s: %04lx\n", str, err & 0xffff); show_registers(regs); - spin_unlock_irq(&die_lock); + spin_unlock_irqrestore(&die_lock, flags); do_exit(SIGSEGV); } @@ -310,7 +476,9 @@ } DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) +#if !defined(CONFIG_KDB) DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) +#endif DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip) @@ -387,6 +555,7 @@ return; } #endif + (void)kdb(KDB_REASON_NMI, reason, regs); printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); printk("Dazed and confused, but trying to continue\n"); printk("Do you have a strange power saving mode enabled?\n"); @@ -394,22 +563,53 @@ #if CONFIG_X86_IO_APIC -int nmi_watchdog = 0; +#if defined(CONFIG_SMP) || defined(CONFIG_UP_NMI_WATCHDOG) +int nmi_watchdog = 1; +#else +int nmi_watchdog; +#endif +int proc_nmi_watchdog; /* Visible/changeable via /proc */ +int nmi_watchdog_source; /* 1 local APIC, 2 IO-APIC */ + +int set_nmi_watchdog(int value) +{ + int ret = -ENOSYS; + if (value != nmi_watchdog && nmi_watchdog_source == 2) { + /* FIXME: No code to disable/enable IO-APIC NMI watchdog yet */ + printk(KERN_WARNING "NMI watchdog using IO-APIC, cannot change after boot\n"); + proc_nmi_watchdog = nmi_watchdog; + } + else if ((ret = setup_apic_nmi_watchdog(value))) { + printk(KERN_WARNING "set_nmi_watchdog failed %d, value not changed\n", ret); + proc_nmi_watchdog = nmi_watchdog; + } + return ret; +} static int __init setup_nmi_watchdog(char *str) { - get_option(&str, &nmi_watchdog); - return 1; + get_option(&str, &nmi_watchdog); + if (nmi_watchdog) + nmi_watchdog = 1; + return 1; } __setup("nmi_watchdog=", setup_nmi_watchdog); static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED; +#if defined(CONFIG_SMP) && defined(CONFIG_KDB) +static void +do_ack_apic_irq(void) +{ + ack_APIC_irq(); +} +#endif + inline void nmi_watchdog_tick(struct pt_regs * regs) { /* - * the best way to detect wether a CPU has a 'hard lockup' problem + * the best way to detect whether a CPU has a 'hard lockup' problem * is to check it's local APIC timer IRQ counts. If they are not * changing then that CPU has some problem. * @@ -431,6 +631,12 @@ * the stack NMI-atomically, it's safe to use smp_processor_id(). */ int sum, cpu = smp_processor_id(); + set_nmi_counter_local(); /* May be using local APIC */ +#if defined(CONFIG_KDB) + /* Ignore watchdog if kdb says so */ + if (KDB_STATE(NO_WATCHDOG)) + return; +#endif /* defined(CONFIG_KDB) */ sum = apic_timer_irqs[cpu]; @@ -449,6 +655,14 @@ bust_spinlocks(); printk("NMI Watchdog detected LOCKUP on CPU%d, registers:\n", cpu); show_registers(regs); +#if defined(CONFIG_KDB) + if (kdb_on) { + /* Invoke kdb and try to continue in the same state afterwards */ + spin_unlock(&nmi_print_lock); + kdb(KDB_REASON_WATCHDOG, 0, regs); + spin_lock(&nmi_print_lock); + } +#endif /* CONFIG_KDB */ printk("console shuts up ...\n"); console_silent(); spin_unlock(&nmi_print_lock); @@ -459,14 +673,23 @@ alert_counter[cpu] = 0; } } -#endif +#endif /* CONFIG_X86_IO_APIC */ asmlinkage void do_nmi(struct pt_regs * regs, long error_code) { unsigned char reason = inb(0x61); - ++nmi_count(smp_processor_id()); + +#if defined(CONFIG_SMP) && defined(CONFIG_KDB) + /* + * Call the kernel debugger to see if this NMI is due + * to an KDB requested IPI. If so, kdb will handle it. + */ + if (kdb_ipi((kdb_eframe_t)regs, do_ack_apic_irq)) { + return; + } +#endif if (!(reason & 0xc0)) { #if CONFIG_X86_IO_APIC /* @@ -478,9 +701,9 @@ return; } else unknown_nmi_error(reason, regs); -#else +#else /* ! CONFIG_X86_IO_APIC */ unknown_nmi_error(reason, regs); -#endif +#endif /* ! CONFIG_X86_IO_APIC */ return; } if (reason & 0x80) @@ -527,6 +750,15 @@ __asm__ __volatile__("movl %%db6,%0" : "=r" (condition)); +#if defined(CONFIG_KDB) + /* + * The callout functions will return 'true' if they've handled + * the callout condition. + */ + if (callout_dbfunc(&dblist_debug, regs, error_code, SIGTRAP, NULL)) + return; +#endif + /* Mask out spurious debug traps due to lazy DR7 setting */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { if (!tsk->thread.debugreg[7]) @@ -586,6 +818,16 @@ return; } +#if defined(CONFIG_KDB) +asmlinkage void do_int3(struct pt_regs * regs, long error_code) +{ + if (callout_dbfunc(&dblist_int3, regs, error_code, SIGTRAP, NULL)) + return; + + do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); +} +#endif + /* * Note that we play around with the 'TS' bit in an attempt to get * the correct behaviour even in the presence of the asynchronous @@ -979,7 +1221,17 @@ set_trap_gate(11,&segment_not_present); set_trap_gate(12,&stack_segment); set_trap_gate(13,&general_protection); +#if defined(CONFIG_KDB) + if (test_bit(X86_FEATURE_MCE, &boot_cpu_data.x86_capability) && + test_bit(X86_FEATURE_MCA, &boot_cpu_data.x86_capability)) { + set_intr_gate(14,&page_fault_mca); + } + else { + set_intr_gate(14,&page_fault); + } +#else set_intr_gate(14,&page_fault); +#endif set_trap_gate(15,&spurious_interrupt_bug); set_trap_gate(16,&coprocessor_error); set_trap_gate(17,&alignment_check); @@ -987,6 +1239,17 @@ set_trap_gate(19,&simd_coprocessor_error); set_system_gate(SYSCALL_VECTOR,&system_call); +#if defined(CONFIG_KDB) + { + set_trap_gate(18, &machine_check); + } + kdb_enablehwfault(); + /* + * A trap gate, used by the kernel to enter the + * debugger, preserving all registers. + */ + set_trap_gate(KDBENTER_VECTOR, &kdb_call); +#endif /* CONFIG_KDB */ /* * default LDT is a single-entry callgate to lcall7 for iBCS @@ -1004,5 +1267,11 @@ superio_init(); lithium_init(); cobalt_init(); +#endif + +#if defined(CONFIG_KDB) + register_die(kdba_callback_die); + register_int3(kdba_callback_bp); + register_debug(kdba_callback_debug); #endif } diff -rNu linux-2.4.7/linux/arch/i386/lib/CVS/Entries linux-2.4-xfs/linux/arch/i386/lib/CVS/Entries --- linux-2.4.7/linux/arch/i386/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/lib/CVS/Entries Thu Jul 5 11:48:04 2001 @@ -0,0 +1,12 @@ +/Makefile/1.15/Tue Jul 3 02:33:57 2001/-ko/ +/checksum.S/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/dec_and_lock.c/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/delay.c/1.5/Wed Jan 3 01:43:05 2001/-ko/ +/getuser.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/iodebug.c/1.1/Sat Oct 23 02:00:20 1999/-ko/ +/memcpy.c/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/mmx.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/old-checksum.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/strstr.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/usercopy.c/1.5/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/i386/lib/CVS/Repository linux-2.4-xfs/linux/arch/i386/lib/CVS/Repository --- linux-2.4.7/linux/arch/i386/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/lib/CVS/Repository Thu Jul 5 11:48:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/i386/lib diff -rNu linux-2.4.7/linux/arch/i386/lib/CVS/Root linux-2.4-xfs/linux/arch/i386/lib/CVS/Root --- linux-2.4.7/linux/arch/i386/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/lib/CVS/Root Thu Jul 5 11:48:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/i386/math-emu/CVS/Entries linux-2.4-xfs/linux/arch/i386/math-emu/CVS/Entries --- linux-2.4.7/linux/arch/i386/math-emu/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/math-emu/CVS/Entries Thu Jul 5 11:48:09 2001 @@ -0,0 +1,48 @@ +/Makefile/1.5/Thu Dec 21 05:48:12 2000/-ko/ +/README/1.3/Mon Nov 8 22:55:41 1999/-ko/ +/control_w.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/div_Xsig.S/1.4/Wed May 2 06:22:13 2001/-ko/ +/div_small.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/errors.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/exception.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/fpu_arith.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fpu_asm.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/fpu_aux.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fpu_emu.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/fpu_entry.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/fpu_etc.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/fpu_proto.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fpu_system.h/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/fpu_tags.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fpu_trig.c/1.5/Wed Jun 13 03:24:09 2001/-ko/ +/get_address.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/load_store.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/mul_Xsig.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/poly.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/poly_2xm1.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/poly_atan.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/poly_l2.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/poly_sin.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/poly_tan.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/polynom_Xsig.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/reg_add_sub.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/reg_compare.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/reg_constant.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/reg_constant.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/reg_convert.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/reg_divide.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/reg_ld_str.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/reg_mul.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/reg_norm.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/reg_round.S/1.5/Wed May 2 06:22:13 2001/-ko/ +/reg_u_add.S/1.3/Wed May 2 06:22:13 2001/-ko/ +/reg_u_div.S/1.5/Thu Jul 5 06:13:42 2001/-ko/ +/reg_u_mul.S/1.3/Wed May 2 06:22:13 2001/-ko/ +/reg_u_sub.S/1.3/Wed May 2 06:22:13 2001/-ko/ +/round_Xsig.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/shr_Xsig.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/status_w.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/version.h/1.3/Mon Nov 8 22:55:41 1999/-ko/ +/wm_shrx.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/wm_sqrt.S/1.3/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/i386/math-emu/CVS/Repository linux-2.4-xfs/linux/arch/i386/math-emu/CVS/Repository --- linux-2.4.7/linux/arch/i386/math-emu/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/math-emu/CVS/Repository Thu Jul 5 11:48:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/i386/math-emu diff -rNu linux-2.4.7/linux/arch/i386/math-emu/CVS/Root linux-2.4-xfs/linux/arch/i386/math-emu/CVS/Root --- linux-2.4.7/linux/arch/i386/math-emu/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/math-emu/CVS/Root Thu Jul 5 11:48:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/i386/mm/CVS/Entries linux-2.4-xfs/linux/arch/i386/mm/CVS/Entries --- linux-2.4.7/linux/arch/i386/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/mm/CVS/Entries Thu Jul 5 11:48:10 2001 @@ -0,0 +1,6 @@ +/Makefile/1.5/Thu Dec 21 05:48:12 2000/-ko/ +/extable.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/fault.c/1.17/Tue May 29 19:53:13 2001/-ko/ +/init.c/1.29/Wed May 2 06:22:13 2001/-ko/ +/ioremap.c/1.9/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/i386/mm/CVS/Repository linux-2.4-xfs/linux/arch/i386/mm/CVS/Repository --- linux-2.4.7/linux/arch/i386/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/mm/CVS/Repository Thu Jul 5 11:48:09 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/i386/mm diff -rNu linux-2.4.7/linux/arch/i386/mm/CVS/Root linux-2.4-xfs/linux/arch/i386/mm/CVS/Root --- linux-2.4.7/linux/arch/i386/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/i386/mm/CVS/Root Thu Jul 5 11:48:09 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/i386/vmlinux.lds linux-2.4-xfs/linux/arch/i386/vmlinux.lds --- linux-2.4.7/linux/arch/i386/vmlinux.lds Mon Jul 2 16:40:14 2001 +++ linux-2.4-xfs/linux/arch/i386/vmlinux.lds Mon Jul 2 21:33:57 2001 @@ -29,6 +29,10 @@ __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; + __start___kallsyms = .; /* All kernel symbols */ + __kallsyms : { *(__kallsyms) } + __stop___kallsyms = .; + .data : { /* Data */ *(.data) CONSTRUCTORS diff -rNu linux-2.4.7/linux/arch/ia64/CVS/Entries linux-2.4-xfs/linux/arch/ia64/CVS/Entries --- linux-2.4.7/linux/arch/ia64/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/CVS/Entries Thu Jul 5 11:48:10 2001 @@ -0,0 +1,5 @@ +/Makefile/1.8/Wed May 2 06:22:13 2001/-ko/ +/config.in/1.17/Wed May 2 06:22:13 2001/-ko/ +/defconfig/1.8/Tue Jun 12 04:51:00 2001/-ko/ +/vmlinux.lds.S/1.6/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ia64/CVS/Entries.Log linux-2.4-xfs/linux/arch/ia64/CVS/Entries.Log --- linux-2.4.7/linux/arch/ia64/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/CVS/Entries.Log Thu Jul 5 11:48:38 2001 @@ -0,0 +1,9 @@ +A D/boot//// +A D/dig//// +A D/hp//// +A D/ia32//// +A D/kernel//// +A D/lib//// +A D/mm//// +A D/sn//// +A D/tools//// diff -rNu linux-2.4.7/linux/arch/ia64/CVS/Repository linux-2.4-xfs/linux/arch/ia64/CVS/Repository --- linux-2.4.7/linux/arch/ia64/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/CVS/Repository Thu Jul 5 11:48:10 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ia64 diff -rNu linux-2.4.7/linux/arch/ia64/CVS/Root linux-2.4-xfs/linux/arch/ia64/CVS/Root --- linux-2.4.7/linux/arch/ia64/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/CVS/Root Thu Jul 5 11:48:10 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ia64/boot/CVS/Entries linux-2.4-xfs/linux/arch/ia64/boot/CVS/Entries --- linux-2.4.7/linux/arch/ia64/boot/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/boot/CVS/Entries Thu Jul 5 11:48:10 2001 @@ -0,0 +1,4 @@ +/Makefile/1.4/Fri Jan 5 18:42:30 2001/-ko/ +/bootloader.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/bootloader.lds/1.2/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ia64/boot/CVS/Repository linux-2.4-xfs/linux/arch/ia64/boot/CVS/Repository --- linux-2.4.7/linux/arch/ia64/boot/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/boot/CVS/Repository Thu Jul 5 11:48:10 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ia64/boot diff -rNu linux-2.4.7/linux/arch/ia64/boot/CVS/Root linux-2.4-xfs/linux/arch/ia64/boot/CVS/Root --- linux-2.4.7/linux/arch/ia64/boot/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/boot/CVS/Root Thu Jul 5 11:48:10 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ia64/defconfig linux-2.4-xfs/linux/arch/ia64/defconfig --- linux-2.4.7/linux/arch/ia64/defconfig Thu Jun 22 09:09:44 2000 +++ linux-2.4-xfs/linux/arch/ia64/defconfig Mon Jun 11 23:51:00 2001 @@ -276,3 +276,15 @@ # CONFIG_IA64_DEBUG_IRQ is not set # CONFIG_IA64_PRINT_HAZARDS is not set # CONFIG_KDB is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y + +CONFIG_KDB=y +CONFIG_KDB_OFF=n +CONFIG_FRAME_POINTER=n diff -rNu linux-2.4.7/linux/arch/ia64/dig/CVS/Entries linux-2.4-xfs/linux/arch/ia64/dig/CVS/Entries --- linux-2.4.7/linux/arch/ia64/dig/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/dig/CVS/Entries Thu Jul 5 11:48:10 2001 @@ -0,0 +1,4 @@ +/Makefile/1.4/Fri Jan 5 18:42:30 2001/-ko/ +/machvec.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/setup.c/1.6/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ia64/dig/CVS/Repository linux-2.4-xfs/linux/arch/ia64/dig/CVS/Repository --- linux-2.4.7/linux/arch/ia64/dig/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/dig/CVS/Repository Thu Jul 5 11:48:10 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ia64/dig diff -rNu linux-2.4.7/linux/arch/ia64/dig/CVS/Root linux-2.4-xfs/linux/arch/ia64/dig/CVS/Root --- linux-2.4.7/linux/arch/ia64/dig/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/dig/CVS/Root Thu Jul 5 11:48:10 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ia64/hp/CVS/Entries linux-2.4-xfs/linux/arch/ia64/hp/CVS/Entries --- linux-2.4.7/linux/arch/ia64/hp/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/hp/CVS/Entries Thu Jul 5 11:48:10 2001 @@ -0,0 +1,7 @@ +/Makefile/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/hpsim_console.c/1.2/Wed Nov 1 21:35:42 2000/-ko/ +/hpsim_irq.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/hpsim_machvec.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/hpsim_setup.c/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/hpsim_ssc.h/1.1/Fri Feb 11 00:16:16 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ia64/hp/CVS/Repository linux-2.4-xfs/linux/arch/ia64/hp/CVS/Repository --- linux-2.4.7/linux/arch/ia64/hp/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/hp/CVS/Repository Thu Jul 5 11:48:10 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ia64/hp diff -rNu linux-2.4.7/linux/arch/ia64/hp/CVS/Root linux-2.4-xfs/linux/arch/ia64/hp/CVS/Root --- linux-2.4.7/linux/arch/ia64/hp/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/hp/CVS/Root Thu Jul 5 11:48:10 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ia64/ia32/CVS/Entries linux-2.4-xfs/linux/arch/ia64/ia32/CVS/Entries --- linux-2.4.7/linux/arch/ia64/ia32/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/ia32/CVS/Entries Thu Jul 5 11:48:12 2001 @@ -0,0 +1,9 @@ +/Makefile/1.6/Fri Jan 5 18:42:30 2001/-ko/ +/binfmt_elf32.c/1.10/Wed May 2 06:22:13 2001/-ko/ +/ia32_entry.S/1.11/Wed May 2 06:22:13 2001/-ko/ +/ia32_ioctl.c/1.2/Fri Jan 5 18:42:30 2001/-ko/ +/ia32_signal.c/1.6/Wed Nov 1 21:35:42 2000/-ko/ +/ia32_support.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/ia32_traps.c/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/sys_ia32.c/1.15/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ia64/ia32/CVS/Repository linux-2.4-xfs/linux/arch/ia64/ia32/CVS/Repository --- linux-2.4.7/linux/arch/ia64/ia32/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/ia32/CVS/Repository Thu Jul 5 11:48:10 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ia64/ia32 diff -rNu linux-2.4.7/linux/arch/ia64/ia32/CVS/Root linux-2.4-xfs/linux/arch/ia64/ia32/CVS/Root --- linux-2.4.7/linux/arch/ia64/ia32/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/ia32/CVS/Root Thu Jul 5 11:48:10 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ia64/ia32/ia32_entry.S linux-2.4-xfs/linux/arch/ia64/ia32/ia32_entry.S --- linux-2.4.7/linux/arch/ia64/ia32/ia32_entry.S Thu Apr 5 14:51:47 2001 +++ linux-2.4-xfs/linux/arch/ia64/ia32/ia32_entry.S Wed May 2 01:22:13 2001 @@ -341,9 +341,39 @@ data8 sys_ni_syscall data8 sys_ni_syscall data8 sys_ni_syscall - data8 sys_ni_syscall /* 220 */ + data8 sys_ni_syscall /* 220 */ data8 sys_ni_syscall data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /* 230 */ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall /* 240 */ + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_ni_syscall + data8 sys_attrctl /* 250 */ + data8 sys_acl_get + data8 sys_acl_set /* * CAUTION: If any system calls are added beyond this point * then the check in `arch/ia64/kernel/ivt.S' will have diff -rNu linux-2.4.7/linux/arch/ia64/kernel/CVS/Entries linux-2.4-xfs/linux/arch/ia64/kernel/CVS/Entries --- linux-2.4.7/linux/arch/ia64/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/kernel/CVS/Entries Thu Jul 5 11:48:20 2001 @@ -0,0 +1,42 @@ +/Makefile/1.9/Wed May 2 06:22:13 2001/-ko/ +/acpi.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/brl_emu.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/efi.c/1.10/Wed May 2 06:22:13 2001/-ko/ +/efi_stub.S/1.3/Wed May 2 06:22:13 2001/-ko/ +/efivars.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/entry.S/1.13/Mon Jul 2 03:31:14 2001/-ko/ +/entry.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/fw-emu.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/gate.S/1.6/Wed May 2 06:22:13 2001/-ko/ +/head.S/1.7/Wed May 2 06:22:13 2001/-ko/ +/ia64_ksyms.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/init_task.c/1.1/Fri Feb 11 00:16:16 2000/-ko/ +/iosapic.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/irq.c/1.12/Wed May 2 06:22:13 2001/-ko/ +/irq_ia64.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/irq_sapic.c/1.1/Tue May 2 21:09:12 2000/-ko/ +/ivt.S/1.10/Wed May 2 06:22:13 2001/-ko/ +/machvec.c/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/mca.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/mca_asm.S/1.6/Wed May 2 06:22:13 2001/-ko/ +/minstate.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/pal.S/1.6/Wed May 2 06:22:13 2001/-ko/ +/palinfo.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/pci.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/perfmon.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/process.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/ptrace.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/sal.c/1.5/Fri Jan 5 18:42:30 2001/-ko/ +/semaphore.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/signal.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/smp.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/smpboot.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/sys_ia64.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/time.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/traps.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/unaligned.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/unwind.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/unwind_decoder.c/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/unwind_i.h/1.2/Wed Nov 1 21:35:42 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ia64/kernel/CVS/Repository linux-2.4-xfs/linux/arch/ia64/kernel/CVS/Repository --- linux-2.4.7/linux/arch/ia64/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/kernel/CVS/Repository Thu Jul 5 11:48:12 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ia64/kernel diff -rNu linux-2.4.7/linux/arch/ia64/kernel/CVS/Root linux-2.4-xfs/linux/arch/ia64/kernel/CVS/Root --- linux-2.4.7/linux/arch/ia64/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/kernel/CVS/Root Thu Jul 5 11:48:12 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ia64/kernel/entry.S linux-2.4-xfs/linux/arch/ia64/kernel/entry.S --- linux-2.4.7/linux/arch/ia64/kernel/entry.S Thu Apr 5 14:51:47 2001 +++ linux-2.4-xfs/linux/arch/ia64/kernel/entry.S Sun Jul 1 22:31:14 2001 @@ -1232,9 +1232,9 @@ data8 ia64_ni_syscall data8 ia64_ni_syscall data8 ia64_ni_syscall - data8 ia64_ni_syscall // 1260 - data8 ia64_ni_syscall - data8 ia64_ni_syscall + data8 sys_attrctl // 1260 + data8 sys_acl_get + data8 sys_acl_set data8 ia64_ni_syscall data8 ia64_ni_syscall data8 ia64_ni_syscall // 1265 diff -rNu linux-2.4.7/linux/arch/ia64/kernel/ivt.S linux-2.4-xfs/linux/arch/ia64/kernel/ivt.S --- linux-2.4.7/linux/arch/ia64/kernel/ivt.S Thu Apr 5 14:51:47 2001 +++ linux-2.4-xfs/linux/arch/ia64/kernel/ivt.S Wed May 2 01:22:13 2001 @@ -861,7 +861,7 @@ alloc r15=ar.pfs,0,0,6,0 // must first in an insn group ;; ld4 r8=[r14],8 // r8 == EAX (syscall number) - mov r15=222 // sys_vfork - last implemented system call + mov r15=252 // sys_acl_set - last implemented system call ;; cmp.leu.unc p6,p7=r8,r15 ld4 out1=[r14],8 // r9 == ecx diff -rNu linux-2.4.7/linux/arch/ia64/lib/CVS/Entries linux-2.4-xfs/linux/arch/ia64/lib/CVS/Entries --- linux-2.4.7/linux/arch/ia64/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/lib/CVS/Entries Thu Jul 5 11:48:22 2001 @@ -0,0 +1,20 @@ +/Makefile/1.7/Wed May 2 06:22:13 2001/-ko/ +/checksum.c/1.1/Fri Feb 11 00:16:16 2000/-ko/ +/clear_page.S/1.3/Wed May 2 06:22:13 2001/-ko/ +/clear_user.S/1.4/Wed May 2 06:22:13 2001/-ko/ +/copy_page.S/1.4/Wed May 2 06:22:13 2001/-ko/ +/copy_user.S/1.8/Wed May 2 06:22:13 2001/-ko/ +/csum_partial_copy.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/do_csum.S/1.3/Wed May 2 06:22:13 2001/-ko/ +/flush.S/1.4/Wed May 2 06:22:13 2001/-ko/ +/idiv32.S/1.1/Wed Nov 1 21:35:42 2000/-ko/ +/idiv64.S/1.2/Wed May 2 06:22:13 2001/-ko/ +/io.c/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/memcpy.S/1.4/Wed May 2 06:22:13 2001/-ko/ +/memset.S/1.3/Wed May 2 06:22:13 2001/-ko/ +/strlen.S/1.5/Wed May 2 06:22:13 2001/-ko/ +/strlen_user.S/1.4/Wed May 2 06:22:13 2001/-ko/ +/strncpy_from_user.S/1.4/Wed May 2 06:22:13 2001/-ko/ +/strnlen_user.S/1.3/Wed May 2 06:22:13 2001/-ko/ +/swiotlb.c/1.2/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ia64/lib/CVS/Repository linux-2.4-xfs/linux/arch/ia64/lib/CVS/Repository --- linux-2.4.7/linux/arch/ia64/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/lib/CVS/Repository Thu Jul 5 11:48:20 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ia64/lib diff -rNu linux-2.4.7/linux/arch/ia64/lib/CVS/Root linux-2.4-xfs/linux/arch/ia64/lib/CVS/Root --- linux-2.4.7/linux/arch/ia64/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/lib/CVS/Root Thu Jul 5 11:48:20 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ia64/mm/CVS/Entries linux-2.4-xfs/linux/arch/ia64/mm/CVS/Entries --- linux-2.4.7/linux/arch/ia64/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/mm/CVS/Entries Thu Jul 5 11:48:22 2001 @@ -0,0 +1,6 @@ +/Makefile/1.2/Fri Jan 5 18:42:30 2001/-ko/ +/extable.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/fault.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/init.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/tlb.c/1.7/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ia64/mm/CVS/Repository linux-2.4-xfs/linux/arch/ia64/mm/CVS/Repository --- linux-2.4.7/linux/arch/ia64/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/mm/CVS/Repository Thu Jul 5 11:48:22 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ia64/mm diff -rNu linux-2.4.7/linux/arch/ia64/mm/CVS/Root linux-2.4-xfs/linux/arch/ia64/mm/CVS/Root --- linux-2.4.7/linux/arch/ia64/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/mm/CVS/Root Thu Jul 5 11:48:22 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ia64/sn/CVS/Entries linux-2.4-xfs/linux/arch/ia64/sn/CVS/Entries --- linux-2.4.7/linux/arch/ia64/sn/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/CVS/Entries Thu Jul 5 11:48:22 2001 @@ -0,0 +1,2 @@ +/Makefile/1.4/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ia64/sn/CVS/Entries.Log linux-2.4-xfs/linux/arch/ia64/sn/CVS/Entries.Log --- linux-2.4.7/linux/arch/ia64/sn/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/CVS/Entries.Log Thu Jul 5 11:48:38 2001 @@ -0,0 +1,4 @@ +A D/fprom//// +A D/io//// +A D/sn1//// +A D/tools//// diff -rNu linux-2.4.7/linux/arch/ia64/sn/CVS/Repository linux-2.4-xfs/linux/arch/ia64/sn/CVS/Repository --- linux-2.4.7/linux/arch/ia64/sn/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/CVS/Repository Thu Jul 5 11:48:22 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ia64/sn diff -rNu linux-2.4.7/linux/arch/ia64/sn/CVS/Root linux-2.4-xfs/linux/arch/ia64/sn/CVS/Root --- linux-2.4.7/linux/arch/ia64/sn/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/CVS/Root Thu Jul 5 11:48:22 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ia64/sn/fprom/CVS/Entries linux-2.4-xfs/linux/arch/ia64/sn/fprom/CVS/Entries --- linux-2.4.7/linux/arch/ia64/sn/fprom/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/fprom/CVS/Entries Thu Jul 5 11:48:23 2001 @@ -0,0 +1,10 @@ +/Makefile/1.2/Wed May 2 06:22:13 2001/-ko/ +/README/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/fpmem.c/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/fpmem.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/fprom.lds/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/fpromasm.S/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/fw-emu.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/main.c/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/runsim/1.1/Fri Jan 5 18:42:30 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ia64/sn/fprom/CVS/Repository linux-2.4-xfs/linux/arch/ia64/sn/fprom/CVS/Repository --- linux-2.4.7/linux/arch/ia64/sn/fprom/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/fprom/CVS/Repository Thu Jul 5 11:48:22 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ia64/sn/fprom diff -rNu linux-2.4.7/linux/arch/ia64/sn/fprom/CVS/Root linux-2.4-xfs/linux/arch/ia64/sn/fprom/CVS/Root --- linux-2.4.7/linux/arch/ia64/sn/fprom/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/fprom/CVS/Root Thu Jul 5 11:48:22 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ia64/sn/io/CVS/Entries linux-2.4-xfs/linux/arch/ia64/sn/io/CVS/Entries --- linux-2.4.7/linux/arch/ia64/sn/io/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/io/CVS/Entries Thu Jul 5 11:48:37 2001 @@ -0,0 +1,38 @@ +/Makefile/1.2/Wed May 2 06:22:13 2001/-ko/ +/alenlist.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/cdl.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/devsupport.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/eeprom.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/hcl.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/hcl_util.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/hubdev.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/huberror.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/hubspc.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/invent.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/io.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/ip37.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/klconflib.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/klgraph.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/klgraph_hack.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/l1.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/l1_command.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/labelcl.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/mem_refcnt.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/ml_SN_init.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/ml_SN_intr.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/ml_iograph.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/module.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/pci.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/pci_bus_cvlink.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/pci_dma.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/pciba.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/pcibr.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/pciio.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/sgi_if.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/sgi_io_init.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/sgi_io_sim.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/stubs.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/xbow.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/xswitch.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/xtalk.c/1.3/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ia64/sn/io/CVS/Repository linux-2.4-xfs/linux/arch/ia64/sn/io/CVS/Repository --- linux-2.4.7/linux/arch/ia64/sn/io/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/io/CVS/Repository Thu Jul 5 11:48:23 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ia64/sn/io diff -rNu linux-2.4.7/linux/arch/ia64/sn/io/CVS/Root linux-2.4-xfs/linux/arch/ia64/sn/io/CVS/Root --- linux-2.4.7/linux/arch/ia64/sn/io/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/io/CVS/Root Thu Jul 5 11:48:23 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ia64/sn/sn1/CVS/Entries linux-2.4-xfs/linux/arch/ia64/sn/sn1/CVS/Entries --- linux-2.4.7/linux/arch/ia64/sn/sn1/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/sn1/CVS/Entries Thu Jul 5 11:48:38 2001 @@ -0,0 +1,17 @@ +/Makefile/1.4/Wed May 2 06:22:13 2001/-ko/ +/discontig.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/error.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/iomv.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/irq.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/llsc4.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/llsc4.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/machvec.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/mm.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/probe.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/smp.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/sn1_asm.S/1.2/Wed May 2 06:22:13 2001/-ko/ +/sn1_ksyms.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sv.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/synergy.c/1.2/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ia64/sn/sn1/CVS/Repository linux-2.4-xfs/linux/arch/ia64/sn/sn1/CVS/Repository --- linux-2.4.7/linux/arch/ia64/sn/sn1/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/sn1/CVS/Repository Thu Jul 5 11:48:37 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ia64/sn/sn1 diff -rNu linux-2.4.7/linux/arch/ia64/sn/sn1/CVS/Root linux-2.4-xfs/linux/arch/ia64/sn/sn1/CVS/Root --- linux-2.4.7/linux/arch/ia64/sn/sn1/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/sn1/CVS/Root Thu Jul 5 11:48:37 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ia64/sn/tools/CVS/Entries linux-2.4-xfs/linux/arch/ia64/sn/tools/CVS/Entries --- linux-2.4.7/linux/arch/ia64/sn/tools/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/tools/CVS/Entries Thu Jul 5 11:48:38 2001 @@ -0,0 +1,2 @@ +/make_textsym/1.1/Fri Jan 5 18:42:30 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ia64/sn/tools/CVS/Repository linux-2.4-xfs/linux/arch/ia64/sn/tools/CVS/Repository --- linux-2.4.7/linux/arch/ia64/sn/tools/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/tools/CVS/Repository Thu Jul 5 11:48:38 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ia64/sn/tools diff -rNu linux-2.4.7/linux/arch/ia64/sn/tools/CVS/Root linux-2.4-xfs/linux/arch/ia64/sn/tools/CVS/Root --- linux-2.4.7/linux/arch/ia64/sn/tools/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/sn/tools/CVS/Root Thu Jul 5 11:48:38 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ia64/tools/CVS/Entries linux-2.4-xfs/linux/arch/ia64/tools/CVS/Entries --- linux-2.4.7/linux/arch/ia64/tools/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/tools/CVS/Entries Thu Jul 5 11:48:38 2001 @@ -0,0 +1,4 @@ +/Makefile/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/print_offsets.awk/1.3/Wed May 2 06:22:13 2001/-ko/ +/print_offsets.c/1.6/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ia64/tools/CVS/Repository linux-2.4-xfs/linux/arch/ia64/tools/CVS/Repository --- linux-2.4.7/linux/arch/ia64/tools/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/tools/CVS/Repository Thu Jul 5 11:48:38 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ia64/tools diff -rNu linux-2.4.7/linux/arch/ia64/tools/CVS/Root linux-2.4-xfs/linux/arch/ia64/tools/CVS/Root --- linux-2.4.7/linux/arch/ia64/tools/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ia64/tools/CVS/Root Thu Jul 5 11:48:38 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/CVS/Entries linux-2.4-xfs/linux/arch/m68k/CVS/Entries --- linux-2.4.7/linux/arch/m68k/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/CVS/Entries Thu Jul 5 11:48:39 2001 @@ -0,0 +1,6 @@ +/Makefile/1.7/Sat Jun 9 02:44:24 2001/-ko/ +/config.in/1.23/Sat Jun 9 02:44:24 2001/-ko/ +/defconfig/1.10/Tue Jun 12 04:51:00 2001/-ko/ +/vmlinux-sun3.lds/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/vmlinux.lds/1.9/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/CVS/Entries.Log linux-2.4-xfs/linux/arch/m68k/CVS/Entries.Log --- linux-2.4.7/linux/arch/m68k/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/CVS/Entries.Log Thu Jul 5 11:49:15 2001 @@ -0,0 +1,18 @@ +A D/amiga//// +A D/apollo//// +A D/atari//// +A D/bvme6000//// +A D/fpsp040//// +A D/hp300//// +A D/ifpsp060//// +A D/kernel//// +A D/lib//// +A D/mac//// +A D/math-emu//// +A D/mm//// +A D/mvme147//// +A D/mvme16x//// +A D/q40//// +A D/sun3//// +A D/sun3x//// +A D/tools//// diff -rNu linux-2.4.7/linux/arch/m68k/CVS/Repository linux-2.4-xfs/linux/arch/m68k/CVS/Repository --- linux-2.4.7/linux/arch/m68k/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/CVS/Repository Thu Jul 5 11:48:38 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k diff -rNu linux-2.4.7/linux/arch/m68k/CVS/Root linux-2.4-xfs/linux/arch/m68k/CVS/Root --- linux-2.4.7/linux/arch/m68k/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/CVS/Root Thu Jul 5 11:48:38 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/amiga/CVS/Entries linux-2.4-xfs/linux/arch/m68k/amiga/CVS/Entries --- linux-2.4.7/linux/arch/m68k/amiga/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/amiga/CVS/Entries Thu Jul 5 11:48:39 2001 @@ -0,0 +1,9 @@ +/Makefile/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/amiga_ksyms.c/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/amiints.c/1.7/Sun Dec 17 19:15:00 2000/-ko/ +/amisound.c/1.8/Sat Jun 9 02:44:24 2001/-ko/ +/chipram.c/1.8/Sun Dec 17 19:15:00 2000/-ko/ +/cia.c/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/config.c/1.9/Sat Jun 9 02:44:24 2001/-ko/ +/pcmcia.c/1.3/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/amiga/CVS/Repository linux-2.4-xfs/linux/arch/m68k/amiga/CVS/Repository --- linux-2.4.7/linux/arch/m68k/amiga/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/amiga/CVS/Repository Thu Jul 5 11:48:39 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/amiga diff -rNu linux-2.4.7/linux/arch/m68k/amiga/CVS/Root linux-2.4-xfs/linux/arch/m68k/amiga/CVS/Root --- linux-2.4.7/linux/arch/m68k/amiga/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/amiga/CVS/Root Thu Jul 5 11:48:39 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/apollo/CVS/Entries linux-2.4-xfs/linux/arch/m68k/apollo/CVS/Entries --- linux-2.4.7/linux/arch/m68k/apollo/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/apollo/CVS/Entries Thu Jul 5 11:48:39 2001 @@ -0,0 +1,6 @@ +/Makefile/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/config.c/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/dma.c/1.1/Sat Jan 29 23:00:52 2000/-ko/ +/dn_debug.c/1.3/Sun Aug 29 02:07:15 1999/-ko/ +/dn_ints.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/apollo/CVS/Repository linux-2.4-xfs/linux/arch/m68k/apollo/CVS/Repository --- linux-2.4.7/linux/arch/m68k/apollo/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/apollo/CVS/Repository Thu Jul 5 11:48:39 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/apollo diff -rNu linux-2.4.7/linux/arch/m68k/apollo/CVS/Root linux-2.4-xfs/linux/arch/m68k/apollo/CVS/Root --- linux-2.4.7/linux/arch/m68k/apollo/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/apollo/CVS/Root Thu Jul 5 11:48:39 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/atari/CVS/Entries linux-2.4-xfs/linux/arch/m68k/atari/CVS/Entries --- linux-2.4.7/linux/arch/m68k/atari/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/atari/CVS/Entries Thu Jul 5 11:48:41 2001 @@ -0,0 +1,14 @@ +/Makefile/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/ataints.c/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/atakeyb.c/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/atari_ksyms.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/atasound.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/atasound.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/config.c/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/debug.c/1.6/Fri Jan 5 18:42:30 2001/-ko/ +/hades-pci.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/joystick.c/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/stdma.c/1.4/Wed Sep 15 20:42:56 1999/-ko/ +/stram.c/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/time.c/1.4/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/atari/CVS/Repository linux-2.4-xfs/linux/arch/m68k/atari/CVS/Repository --- linux-2.4.7/linux/arch/m68k/atari/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/atari/CVS/Repository Thu Jul 5 11:48:39 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/atari diff -rNu linux-2.4.7/linux/arch/m68k/atari/CVS/Root linux-2.4-xfs/linux/arch/m68k/atari/CVS/Root --- linux-2.4.7/linux/arch/m68k/atari/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/atari/CVS/Root Thu Jul 5 11:48:39 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/bvme6000/CVS/Entries linux-2.4-xfs/linux/arch/m68k/bvme6000/CVS/Entries --- linux-2.4.7/linux/arch/m68k/bvme6000/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/bvme6000/CVS/Entries Thu Jul 5 11:48:41 2001 @@ -0,0 +1,5 @@ +/Makefile/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/bvmeints.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/config.c/1.7/Sat Jun 9 02:44:24 2001/-ko/ +/rtc.c/1.8/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/bvme6000/CVS/Repository linux-2.4-xfs/linux/arch/m68k/bvme6000/CVS/Repository --- linux-2.4.7/linux/arch/m68k/bvme6000/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/bvme6000/CVS/Repository Thu Jul 5 11:48:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/bvme6000 diff -rNu linux-2.4.7/linux/arch/m68k/bvme6000/CVS/Root linux-2.4-xfs/linux/arch/m68k/bvme6000/CVS/Root --- linux-2.4.7/linux/arch/m68k/bvme6000/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/bvme6000/CVS/Root Thu Jul 5 11:48:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/defconfig linux-2.4-xfs/linux/arch/m68k/defconfig --- linux-2.4.7/linux/arch/m68k/defconfig Mon Jun 19 14:56:08 2000 +++ linux-2.4-xfs/linux/arch/m68k/defconfig Mon Jun 11 23:51:00 2001 @@ -327,3 +327,11 @@ # Kernel hacking # # CONFIG_MAGIC_SYSRQ is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/m68k/fpsp040/CVS/Entries linux-2.4-xfs/linux/arch/m68k/fpsp040/CVS/Entries --- linux-2.4.7/linux/arch/m68k/fpsp040/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/fpsp040/CVS/Entries Thu Jul 5 11:48:45 2001 @@ -0,0 +1,45 @@ +/Makefile/1.4/Fri Apr 21 16:00:46 2000/-ko/ +/README/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/bindec.S/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/binstr.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/bugfix.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/decbin.S/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/do_func.S/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/fpsp.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/gen_except.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/get_op.S/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/kernel_ex.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/res_func.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/round.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sacos.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sasin.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/satan.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/satanh.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/scale.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/scosh.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/setox.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sgetem.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sint.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/skeleton.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/slog2.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/slogn.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/smovecr.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/srem_mod.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ssin.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ssinh.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/stan.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/stanh.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sto_res.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/stwotox.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/tbldo.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/util.S/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/x_bsun.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/x_fline.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/x_operr.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/x_ovfl.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/x_snan.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/x_store.S/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/x_unfl.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/x_unimp.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/x_unsupp.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/fpsp040/CVS/Repository linux-2.4-xfs/linux/arch/m68k/fpsp040/CVS/Repository --- linux-2.4.7/linux/arch/m68k/fpsp040/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/fpsp040/CVS/Repository Thu Jul 5 11:48:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/fpsp040 diff -rNu linux-2.4.7/linux/arch/m68k/fpsp040/CVS/Root linux-2.4-xfs/linux/arch/m68k/fpsp040/CVS/Root --- linux-2.4.7/linux/arch/m68k/fpsp040/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/fpsp040/CVS/Root Thu Jul 5 11:48:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/hp300/CVS/Entries linux-2.4-xfs/linux/arch/m68k/hp300/CVS/Entries --- linux-2.4.7/linux/arch/m68k/hp300/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/hp300/CVS/Entries Thu Jul 5 11:48:45 2001 @@ -0,0 +1,12 @@ +/Makefile/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/README.hp300/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/config.c/1.3/Mon Sep 6 21:00:05 1999/-ko/ +/hil.c/1.3/Mon Sep 6 21:00:05 1999/-ko/ +/hp300map.map/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ints.c/1.4/Wed Sep 15 22:45:13 1999/-ko/ +/ints.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ksyms.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/reboot.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/time.c/1.3/Mon Sep 6 21:00:05 1999/-ko/ +/time.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/hp300/CVS/Repository linux-2.4-xfs/linux/arch/m68k/hp300/CVS/Repository --- linux-2.4.7/linux/arch/m68k/hp300/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/hp300/CVS/Repository Thu Jul 5 11:48:45 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/hp300 diff -rNu linux-2.4.7/linux/arch/m68k/hp300/CVS/Root linux-2.4-xfs/linux/arch/m68k/hp300/CVS/Root --- linux-2.4.7/linux/arch/m68k/hp300/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/hp300/CVS/Root Thu Jul 5 11:48:45 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/ifpsp060/CVS/Entries linux-2.4-xfs/linux/arch/m68k/ifpsp060/CVS/Entries --- linux-2.4.7/linux/arch/m68k/ifpsp060/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/ifpsp060/CVS/Entries Thu Jul 5 11:48:51 2001 @@ -0,0 +1,20 @@ +/CHANGES/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/MISC/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Makefile/1.4/Fri Apr 21 16:00:46 2000/-ko/ +/README/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/TEST.DOC/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fplsp.doc/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fplsp.sa/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fpsp.doc/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fpsp.sa/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fskeleton.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ftest.sa/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ilsp.doc/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ilsp.sa/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/iskeleton.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/isp.doc/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/isp.sa/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/itest.sa/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/os.S/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/pfpsp.sa/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/ifpsp060/CVS/Entries.Log linux-2.4-xfs/linux/arch/m68k/ifpsp060/CVS/Entries.Log --- linux-2.4.7/linux/arch/m68k/ifpsp060/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/ifpsp060/CVS/Entries.Log Thu Jul 5 11:48:51 2001 @@ -0,0 +1 @@ +A D/src//// diff -rNu linux-2.4.7/linux/arch/m68k/ifpsp060/CVS/Repository linux-2.4-xfs/linux/arch/m68k/ifpsp060/CVS/Repository --- linux-2.4.7/linux/arch/m68k/ifpsp060/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/ifpsp060/CVS/Repository Thu Jul 5 11:48:45 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/ifpsp060 diff -rNu linux-2.4.7/linux/arch/m68k/ifpsp060/CVS/Root linux-2.4-xfs/linux/arch/m68k/ifpsp060/CVS/Root --- linux-2.4.7/linux/arch/m68k/ifpsp060/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/ifpsp060/CVS/Root Thu Jul 5 11:48:45 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/ifpsp060/src/CVS/Entries linux-2.4-xfs/linux/arch/m68k/ifpsp060/src/CVS/Entries --- linux-2.4.7/linux/arch/m68k/ifpsp060/src/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/ifpsp060/src/CVS/Entries Thu Jul 5 11:49:09 2001 @@ -0,0 +1,9 @@ +/README-SRC/1.1/Wed Jan 3 01:43:05 2001/-ko/ +/fplsp.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/fpsp.S/1.4/Wed May 2 06:22:13 2001/-ko/ +/ftest.S/1.1/Wed Jan 3 01:43:05 2001/-ko/ +/ilsp.S/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/isp.S/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/itest.S/1.1/Wed Jan 3 01:43:05 2001/-ko/ +/pfpsp.S/1.4/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/ifpsp060/src/CVS/Repository linux-2.4-xfs/linux/arch/m68k/ifpsp060/src/CVS/Repository --- linux-2.4.7/linux/arch/m68k/ifpsp060/src/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/ifpsp060/src/CVS/Repository Thu Jul 5 11:48:51 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/ifpsp060/src diff -rNu linux-2.4.7/linux/arch/m68k/ifpsp060/src/CVS/Root linux-2.4-xfs/linux/arch/m68k/ifpsp060/src/CVS/Root --- linux-2.4.7/linux/arch/m68k/ifpsp060/src/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/ifpsp060/src/CVS/Root Thu Jul 5 11:48:51 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/kernel/CVS/Entries linux-2.4-xfs/linux/arch/m68k/kernel/CVS/Entries --- linux-2.4.7/linux/arch/m68k/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/kernel/CVS/Entries Thu Jul 5 11:49:11 2001 @@ -0,0 +1,18 @@ +/Makefile/1.8/Wed Jan 3 01:43:05 2001/-ko/ +/bios32.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/entry.S/1.14/Thu Feb 22 21:09:04 2001/-ko/ +/head.S/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/ints.c/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/m68k_defs.c/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/m68k_defs.head/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/m68k_ksyms.c/1.10/Fri Jan 5 18:42:30 2001/-ko/ +/process.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/ptrace.c/1.7/Sat Jun 9 02:44:24 2001/-ko/ +/semaphore.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.13/Sat Jun 9 02:44:24 2001/-ko/ +/signal.c/1.13/Thu Feb 1 17:10:24 2001/-ko/ +/sun3-head.S/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/sys_m68k.c/1.8/Sat Jun 9 02:44:24 2001/-ko/ +/time.c/1.4/Fri Jan 5 18:42:30 2001/-ko/ +/traps.c/1.10/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/kernel/CVS/Repository linux-2.4-xfs/linux/arch/m68k/kernel/CVS/Repository --- linux-2.4.7/linux/arch/m68k/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/kernel/CVS/Repository Thu Jul 5 11:49:09 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/kernel diff -rNu linux-2.4.7/linux/arch/m68k/kernel/CVS/Root linux-2.4-xfs/linux/arch/m68k/kernel/CVS/Root --- linux-2.4.7/linux/arch/m68k/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/kernel/CVS/Root Thu Jul 5 11:49:09 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/lib/CVS/Entries linux-2.4-xfs/linux/arch/m68k/lib/CVS/Entries --- linux-2.4.7/linux/arch/m68k/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/lib/CVS/Entries Thu Jul 5 11:49:11 2001 @@ -0,0 +1,11 @@ +/Makefile/1.8/Fri Jan 5 18:42:30 2001/-ko/ +/ashldi3.c/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/ashrdi3.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/checksum.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/lshrdi3.c/1.1/Sat Jan 29 23:00:52 2000/-ko/ +/memcmp.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/memcpy.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/memset.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/muldi3.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/semaphore.S/1.4/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/lib/CVS/Repository linux-2.4-xfs/linux/arch/m68k/lib/CVS/Repository --- linux-2.4.7/linux/arch/m68k/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/lib/CVS/Repository Thu Jul 5 11:49:11 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/lib diff -rNu linux-2.4.7/linux/arch/m68k/lib/CVS/Root linux-2.4-xfs/linux/arch/m68k/lib/CVS/Root --- linux-2.4.7/linux/arch/m68k/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/lib/CVS/Root Thu Jul 5 11:49:11 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/mac/CVS/Entries linux-2.4-xfs/linux/arch/m68k/mac/CVS/Entries --- linux-2.4.7/linux/arch/m68k/mac/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/mac/CVS/Entries Thu Jul 5 11:49:12 2001 @@ -0,0 +1,15 @@ +/Makefile/1.5/Wed Jan 3 01:43:05 2001/-ko/ +/baboon.c/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/bootparse.c/1.3/Wed Sep 15 20:42:56 1999/-ko/ +/config.c/1.8/Sat Jun 9 02:44:24 2001/-ko/ +/debug.c/1.7/Sat Jun 9 02:44:24 2001/-ko/ +/iop.c/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/mac_ksyms.c/1.3/Wed Sep 15 20:42:56 1999/-ko/ +/mac_penguin.S/1.1/Wed Sep 15 20:42:56 1999/-ko/ +/macboing.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/macints.c/1.7/Sat Jun 9 02:44:24 2001/-ko/ +/misc.c/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/oss.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/psc.c/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/via.c/1.4/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/mac/CVS/Repository linux-2.4-xfs/linux/arch/m68k/mac/CVS/Repository --- linux-2.4.7/linux/arch/m68k/mac/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/mac/CVS/Repository Thu Jul 5 11:49:11 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/mac diff -rNu linux-2.4.7/linux/arch/m68k/mac/CVS/Root linux-2.4-xfs/linux/arch/m68k/mac/CVS/Root --- linux-2.4.7/linux/arch/m68k/mac/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/mac/CVS/Root Thu Jul 5 11:49:11 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/math-emu/CVS/Entries linux-2.4-xfs/linux/arch/m68k/math-emu/CVS/Entries --- linux-2.4.7/linux/arch/m68k/math-emu/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/math-emu/CVS/Entries Thu Jul 5 11:49:14 2001 @@ -0,0 +1,16 @@ +/Makefile/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/fp_arith.c/1.1/Sun Aug 29 03:33:57 1999/-ko/ +/fp_arith.h/1.1/Sun Aug 29 03:33:57 1999/-ko/ +/fp_cond.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/fp_decode.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/fp_emu.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/fp_entry.S/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/fp_log.c/1.1/Sun Aug 29 03:33:57 1999/-ko/ +/fp_move.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/fp_movem.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/fp_scan.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/fp_trig.c/1.1/Sun Aug 29 03:33:57 1999/-ko/ +/fp_trig.h/1.1/Sun Aug 29 03:33:57 1999/-ko/ +/fp_util.S/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/multi_arith.h/1.2/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/math-emu/CVS/Repository linux-2.4-xfs/linux/arch/m68k/math-emu/CVS/Repository --- linux-2.4.7/linux/arch/m68k/math-emu/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/math-emu/CVS/Repository Thu Jul 5 11:49:12 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/math-emu diff -rNu linux-2.4.7/linux/arch/m68k/math-emu/CVS/Root linux-2.4-xfs/linux/arch/m68k/math-emu/CVS/Root --- linux-2.4.7/linux/arch/m68k/math-emu/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/math-emu/CVS/Root Thu Jul 5 11:49:12 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/mm/CVS/Entries linux-2.4-xfs/linux/arch/m68k/mm/CVS/Entries --- linux-2.4.7/linux/arch/m68k/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/mm/CVS/Entries Thu Jul 5 11:49:14 2001 @@ -0,0 +1,10 @@ +/Makefile/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/extable.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fault.c/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/hwtest.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/init.c/1.12/Sat Jun 9 02:44:24 2001/-ko/ +/kmap.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/memory.c/1.10/Sat Jun 9 02:44:24 2001/-ko/ +/motorola.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/sun3mmu.c/1.4/Wed Jan 3 01:43:05 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/mm/CVS/Repository linux-2.4-xfs/linux/arch/m68k/mm/CVS/Repository --- linux-2.4.7/linux/arch/m68k/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/mm/CVS/Repository Thu Jul 5 11:49:14 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/mm diff -rNu linux-2.4.7/linux/arch/m68k/mm/CVS/Root linux-2.4-xfs/linux/arch/m68k/mm/CVS/Root --- linux-2.4.7/linux/arch/m68k/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/mm/CVS/Root Thu Jul 5 11:49:14 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/mvme147/CVS/Entries linux-2.4-xfs/linux/arch/m68k/mvme147/CVS/Entries --- linux-2.4.7/linux/arch/m68k/mvme147/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/mvme147/CVS/Entries Thu Jul 5 11:49:14 2001 @@ -0,0 +1,4 @@ +/147ints.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Makefile/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/config.c/1.8/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/mvme147/CVS/Repository linux-2.4-xfs/linux/arch/m68k/mvme147/CVS/Repository --- linux-2.4.7/linux/arch/m68k/mvme147/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/mvme147/CVS/Repository Thu Jul 5 11:49:14 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/mvme147 diff -rNu linux-2.4.7/linux/arch/m68k/mvme147/CVS/Root linux-2.4-xfs/linux/arch/m68k/mvme147/CVS/Root --- linux-2.4.7/linux/arch/m68k/mvme147/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/mvme147/CVS/Root Thu Jul 5 11:49:14 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/mvme16x/CVS/Entries linux-2.4-xfs/linux/arch/m68k/mvme16x/CVS/Entries --- linux-2.4.7/linux/arch/m68k/mvme16x/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/mvme16x/CVS/Entries Thu Jul 5 11:49:14 2001 @@ -0,0 +1,6 @@ +/16xints.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Makefile/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/config.c/1.7/Sat Jun 9 02:44:24 2001/-ko/ +/mvme16x_ksyms.c/1.1/Sat Jan 29 23:00:52 2000/-ko/ +/rtc.c/1.8/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/mvme16x/CVS/Repository linux-2.4-xfs/linux/arch/m68k/mvme16x/CVS/Repository --- linux-2.4.7/linux/arch/m68k/mvme16x/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/mvme16x/CVS/Repository Thu Jul 5 11:49:14 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/mvme16x diff -rNu linux-2.4.7/linux/arch/m68k/mvme16x/CVS/Root linux-2.4-xfs/linux/arch/m68k/mvme16x/CVS/Root --- linux-2.4.7/linux/arch/m68k/mvme16x/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/mvme16x/CVS/Root Thu Jul 5 11:49:14 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/q40/CVS/Entries linux-2.4-xfs/linux/arch/m68k/q40/CVS/Entries --- linux-2.4.7/linux/arch/m68k/q40/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/q40/CVS/Entries Thu Jul 5 11:49:15 2001 @@ -0,0 +1,5 @@ +/Makefile/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/README/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/config.c/1.10/Sat Jun 9 02:44:24 2001/-ko/ +/q40ints.c/1.5/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/q40/CVS/Repository linux-2.4-xfs/linux/arch/m68k/q40/CVS/Repository --- linux-2.4.7/linux/arch/m68k/q40/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/q40/CVS/Repository Thu Jul 5 11:49:14 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/q40 diff -rNu linux-2.4.7/linux/arch/m68k/q40/CVS/Root linux-2.4-xfs/linux/arch/m68k/q40/CVS/Root --- linux-2.4.7/linux/arch/m68k/q40/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/q40/CVS/Root Thu Jul 5 11:49:14 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/sun3/CVS/Entries linux-2.4-xfs/linux/arch/m68k/sun3/CVS/Entries --- linux-2.4.7/linux/arch/m68k/sun3/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/sun3/CVS/Entries Thu Jul 5 11:49:15 2001 @@ -0,0 +1,12 @@ +/Makefile/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/config.c/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/dvma.c/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/idprom.c/1.2/Wed Sep 15 22:45:13 1999/-ko/ +/intersil.c/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/leds.c/1.1/Wed Sep 15 20:42:56 1999/-ko/ +/mmu_emu.c/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/sbus.c/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/sun3_ksyms.c/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/sun3dvma.c/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/sun3ints.c/1.4/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/sun3/CVS/Entries.Log linux-2.4-xfs/linux/arch/m68k/sun3/CVS/Entries.Log --- linux-2.4.7/linux/arch/m68k/sun3/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/sun3/CVS/Entries.Log Thu Jul 5 11:49:15 2001 @@ -0,0 +1 @@ +A D/prom//// diff -rNu linux-2.4.7/linux/arch/m68k/sun3/CVS/Repository linux-2.4-xfs/linux/arch/m68k/sun3/CVS/Repository --- linux-2.4.7/linux/arch/m68k/sun3/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/sun3/CVS/Repository Thu Jul 5 11:49:15 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/sun3 diff -rNu linux-2.4.7/linux/arch/m68k/sun3/CVS/Root linux-2.4-xfs/linux/arch/m68k/sun3/CVS/Root --- linux-2.4.7/linux/arch/m68k/sun3/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/sun3/CVS/Root Thu Jul 5 11:49:15 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/sun3/prom/CVS/Entries linux-2.4-xfs/linux/arch/m68k/sun3/prom/CVS/Entries --- linux-2.4.7/linux/arch/m68k/sun3/prom/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/sun3/prom/CVS/Entries Thu Jul 5 11:49:15 2001 @@ -0,0 +1,6 @@ +/Makefile/1.2/Tue Dec 21 19:02:48 1999/-ko/ +/console.c/1.2/Mon Nov 15 18:18:49 1999/-ko/ +/init.c/1.2/Wed Sep 15 22:45:13 1999/-ko/ +/misc.c/1.2/Mon Nov 15 18:18:49 1999/-ko/ +/printf.c/1.1/Wed Sep 15 20:42:56 1999/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/sun3/prom/CVS/Repository linux-2.4-xfs/linux/arch/m68k/sun3/prom/CVS/Repository --- linux-2.4.7/linux/arch/m68k/sun3/prom/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/sun3/prom/CVS/Repository Thu Jul 5 11:49:15 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/sun3/prom diff -rNu linux-2.4.7/linux/arch/m68k/sun3/prom/CVS/Root linux-2.4-xfs/linux/arch/m68k/sun3/prom/CVS/Root --- linux-2.4.7/linux/arch/m68k/sun3/prom/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/sun3/prom/CVS/Root Thu Jul 5 11:49:15 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/sun3x/CVS/Entries linux-2.4-xfs/linux/arch/m68k/sun3x/CVS/Entries --- linux-2.4.7/linux/arch/m68k/sun3x/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/sun3x/CVS/Entries Thu Jul 5 11:49:15 2001 @@ -0,0 +1,8 @@ +/Makefile/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/config.c/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/dvma.c/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/prom.c/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/sun3x_ksyms.c/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/time.c/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/time.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/sun3x/CVS/Repository linux-2.4-xfs/linux/arch/m68k/sun3x/CVS/Repository --- linux-2.4.7/linux/arch/m68k/sun3x/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/sun3x/CVS/Repository Thu Jul 5 11:49:15 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/sun3x diff -rNu linux-2.4.7/linux/arch/m68k/sun3x/CVS/Root linux-2.4-xfs/linux/arch/m68k/sun3x/CVS/Root --- linux-2.4.7/linux/arch/m68k/sun3x/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/sun3x/CVS/Root Thu Jul 5 11:49:15 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/tools/CVS/Entries linux-2.4-xfs/linux/arch/m68k/tools/CVS/Entries --- linux-2.4.7/linux/arch/m68k/tools/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/tools/CVS/Entries Thu Jul 5 11:49:15 2001 @@ -0,0 +1 @@ +D diff -rNu linux-2.4.7/linux/arch/m68k/tools/CVS/Entries.Log linux-2.4-xfs/linux/arch/m68k/tools/CVS/Entries.Log --- linux-2.4.7/linux/arch/m68k/tools/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/tools/CVS/Entries.Log Thu Jul 5 11:49:15 2001 @@ -0,0 +1 @@ +A D/amiga//// diff -rNu linux-2.4.7/linux/arch/m68k/tools/CVS/Repository linux-2.4-xfs/linux/arch/m68k/tools/CVS/Repository --- linux-2.4.7/linux/arch/m68k/tools/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/tools/CVS/Repository Thu Jul 5 11:49:15 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/tools diff -rNu linux-2.4.7/linux/arch/m68k/tools/CVS/Root linux-2.4-xfs/linux/arch/m68k/tools/CVS/Root --- linux-2.4.7/linux/arch/m68k/tools/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/tools/CVS/Root Thu Jul 5 11:49:15 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/tools/amiga/CVS/Entries linux-2.4-xfs/linux/arch/m68k/tools/amiga/CVS/Entries --- linux-2.4.7/linux/arch/m68k/tools/amiga/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/tools/amiga/CVS/Entries Thu Jul 5 11:49:15 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dmesg.c/1.3/Mon Aug 30 00:17:07 1999/-ko/ +D diff -rNu linux-2.4.7/linux/arch/m68k/tools/amiga/CVS/Repository linux-2.4-xfs/linux/arch/m68k/tools/amiga/CVS/Repository --- linux-2.4.7/linux/arch/m68k/tools/amiga/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/tools/amiga/CVS/Repository Thu Jul 5 11:49:15 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/m68k/tools/amiga diff -rNu linux-2.4.7/linux/arch/m68k/tools/amiga/CVS/Root linux-2.4-xfs/linux/arch/m68k/tools/amiga/CVS/Root --- linux-2.4.7/linux/arch/m68k/tools/amiga/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/m68k/tools/amiga/CVS/Root Thu Jul 5 11:49:15 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/m68k/vmlinux-sun3.lds linux-2.4-xfs/linux/arch/m68k/vmlinux-sun3.lds --- linux-2.4.7/linux/arch/m68k/vmlinux-sun3.lds Mon Jul 2 16:40:14 2001 +++ linux-2.4-xfs/linux/arch/m68k/vmlinux-sun3.lds Mon Jul 2 21:33:57 2001 @@ -30,6 +30,9 @@ __start___ksymtab = .; /* Kernel symbol table */ *(__ksymtab) __stop___ksymtab = .; + __start___kallsyms = .; /* All kernel symbols */ + *(__kallsyms) + __stop___kallsyms = .; } /* End of data goes *here* so that freeing init code works properly. */ _edata = .; diff -rNu linux-2.4.7/linux/arch/m68k/vmlinux.lds linux-2.4-xfs/linux/arch/m68k/vmlinux.lds --- linux-2.4.7/linux/arch/m68k/vmlinux.lds Mon Jul 2 16:40:14 2001 +++ linux-2.4-xfs/linux/arch/m68k/vmlinux.lds Mon Jul 2 21:33:57 2001 @@ -24,6 +24,10 @@ __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; + __start___kallsyms = .; /* All kernel symbols */ + __kallsyms : { *(__kallsyms) } + __stop___kallsyms = .; + _etext = .; /* End of text section */ .data : { /* Data */ diff -rNu linux-2.4.7/linux/arch/mips/CVS/Entries linux-2.4-xfs/linux/arch/mips/CVS/Entries --- linux-2.4.7/linux/arch/mips/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/CVS/Entries Thu Jul 5 11:49:16 2001 @@ -0,0 +1,13 @@ +/.gdbinit/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Makefile/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/config.in/1.22/Tue Jul 3 02:33:57 2001/-ko/ +/defconfig/1.18/Tue Jun 12 04:51:00 2001/-ko/ +/defconfig-cobalt/1.3/Wed May 2 06:22:13 2001/-ko/ +/defconfig-ddb5476/1.1/Wed May 2 06:22:13 2001/-ko/ +/defconfig-decstation/1.6/Wed May 2 06:22:13 2001/-ko/ +/defconfig-ip22/1.7/Wed May 2 06:22:13 2001/-ko/ +/defconfig-it8172/1.1/Wed May 2 06:22:13 2001/-ko/ +/defconfig-orion/1.3/Wed May 2 06:22:13 2001/-ko/ +/defconfig-rm200/1.3/Wed May 2 06:22:13 2001/-ko/ +/ld.script.in/1.1/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/CVS/Entries.Log linux-2.4-xfs/linux/arch/mips/CVS/Entries.Log --- linux-2.4.7/linux/arch/mips/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/CVS/Entries.Log Thu Jul 5 11:49:30 2001 @@ -0,0 +1,17 @@ +A D/algor//// +A D/arc//// +A D/baget//// +A D/boot//// +A D/ddb5074//// +A D/ddb5476//// +A D/dec//// +A D/ite-boards//// +A D/jazz//// +A D/kernel//// +A D/lib//// +A D/math-emu//// +A D/mips-boards//// +A D/mm//// +A D/sgi//// +A D/sni//// +A D/tools//// diff -rNu linux-2.4.7/linux/arch/mips/CVS/Repository linux-2.4-xfs/linux/arch/mips/CVS/Repository --- linux-2.4.7/linux/arch/mips/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/CVS/Repository Thu Jul 5 11:49:15 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips diff -rNu linux-2.4.7/linux/arch/mips/CVS/Root linux-2.4-xfs/linux/arch/mips/CVS/Root --- linux-2.4.7/linux/arch/mips/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/CVS/Root Thu Jul 5 11:49:15 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/algor/CVS/Entries linux-2.4-xfs/linux/arch/mips/algor/CVS/Entries --- linux-2.4.7/linux/arch/mips/algor/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/algor/CVS/Entries Thu Jul 5 11:49:16 2001 @@ -0,0 +1,2 @@ +/README/1.1/Fri Jul 2 09:56:47 1999/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/algor/CVS/Repository linux-2.4-xfs/linux/arch/mips/algor/CVS/Repository --- linux-2.4.7/linux/arch/mips/algor/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/algor/CVS/Repository Thu Jul 5 11:49:16 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/algor diff -rNu linux-2.4.7/linux/arch/mips/algor/CVS/Root linux-2.4-xfs/linux/arch/mips/algor/CVS/Root --- linux-2.4.7/linux/arch/mips/algor/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/algor/CVS/Root Thu Jul 5 11:49:16 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/arc/CVS/Entries linux-2.4-xfs/linux/arch/mips/arc/CVS/Entries --- linux-2.4.7/linux/arch/mips/arc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/arc/CVS/Entries Thu Jul 5 11:49:16 2001 @@ -0,0 +1,14 @@ +/Makefile/1.5/Wed May 2 06:22:13 2001/-ko/ +/arc_con.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/cmdline.c/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/console.c/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/env.c/1.4/Fri May 26 01:52:46 2000/-ko/ +/file.c/1.4/Fri May 26 01:52:46 2000/-ko/ +/identify.c/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/init.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/memory.c/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/misc.c/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/salone.c/1.4/Fri May 26 01:52:46 2000/-ko/ +/time.c/1.4/Fri May 26 01:52:46 2000/-ko/ +/tree.c/1.4/Fri May 26 01:52:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/arc/CVS/Repository linux-2.4-xfs/linux/arch/mips/arc/CVS/Repository --- linux-2.4.7/linux/arch/mips/arc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/arc/CVS/Repository Thu Jul 5 11:49:16 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/arc diff -rNu linux-2.4.7/linux/arch/mips/arc/CVS/Root linux-2.4-xfs/linux/arch/mips/arc/CVS/Root --- linux-2.4.7/linux/arch/mips/arc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/arc/CVS/Root Thu Jul 5 11:49:16 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/baget/CVS/Entries linux-2.4-xfs/linux/arch/mips/baget/CVS/Entries --- linux-2.4.7/linux/arch/mips/baget/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/baget/CVS/Entries Thu Jul 5 11:49:19 2001 @@ -0,0 +1,14 @@ +/Makefile/1.4/Wed May 2 06:22:13 2001/-ko/ +/baget.c/1.3/Fri May 26 01:52:46 2000/-ko/ +/bagetIRQ.S/1.3/Fri May 26 01:52:46 2000/-ko/ +/balo.c/1.3/Fri May 26 01:52:46 2000/-ko/ +/balo_supp.S/1.3/Fri Mar 3 01:30:48 2000/-ko/ +/irq.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/ld.script.balo/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/print.c/1.4/Fri May 26 01:52:46 2000/-ko/ +/reset.c/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/setup.c/1.4/Fri Mar 3 01:30:48 2000/-ko/ +/time.c/1.4/Fri May 26 01:52:46 2000/-ko/ +/vacserial.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/wbflush.c/1.3/Sun Feb 27 22:13:56 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/baget/CVS/Entries.Log linux-2.4-xfs/linux/arch/mips/baget/CVS/Entries.Log --- linux-2.4.7/linux/arch/mips/baget/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/baget/CVS/Entries.Log Thu Jul 5 11:49:19 2001 @@ -0,0 +1 @@ +A D/prom//// diff -rNu linux-2.4.7/linux/arch/mips/baget/CVS/Repository linux-2.4-xfs/linux/arch/mips/baget/CVS/Repository --- linux-2.4.7/linux/arch/mips/baget/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/baget/CVS/Repository Thu Jul 5 11:49:16 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/baget diff -rNu linux-2.4.7/linux/arch/mips/baget/CVS/Root linux-2.4-xfs/linux/arch/mips/baget/CVS/Root --- linux-2.4.7/linux/arch/mips/baget/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/baget/CVS/Root Thu Jul 5 11:49:16 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/baget/prom/CVS/Entries linux-2.4-xfs/linux/arch/mips/baget/prom/CVS/Entries --- linux-2.4.7/linux/arch/mips/baget/prom/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/baget/prom/CVS/Entries Thu Jul 5 11:49:19 2001 @@ -0,0 +1,3 @@ +/Makefile/1.4/Wed May 2 06:22:13 2001/-ko/ +/init.c/1.4/Fri Mar 3 01:30:48 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/baget/prom/CVS/Repository linux-2.4-xfs/linux/arch/mips/baget/prom/CVS/Repository --- linux-2.4.7/linux/arch/mips/baget/prom/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/baget/prom/CVS/Repository Thu Jul 5 11:49:19 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/baget/prom diff -rNu linux-2.4.7/linux/arch/mips/baget/prom/CVS/Root linux-2.4-xfs/linux/arch/mips/baget/prom/CVS/Root --- linux-2.4.7/linux/arch/mips/baget/prom/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/baget/prom/CVS/Root Thu Jul 5 11:49:19 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/boot/CVS/Entries linux-2.4-xfs/linux/arch/mips/boot/CVS/Entries --- linux-2.4.7/linux/arch/mips/boot/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/boot/CVS/Entries Thu Jul 5 11:49:19 2001 @@ -0,0 +1,6 @@ +/Makefile/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/addinitrd.c/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/ecoff.h/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/elf2ecoff.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/mkboot.c/1.3/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/boot/CVS/Repository linux-2.4-xfs/linux/arch/mips/boot/CVS/Repository --- linux-2.4.7/linux/arch/mips/boot/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/boot/CVS/Repository Thu Jul 5 11:49:19 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/boot diff -rNu linux-2.4.7/linux/arch/mips/boot/CVS/Root linux-2.4-xfs/linux/arch/mips/boot/CVS/Root --- linux-2.4.7/linux/arch/mips/boot/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/boot/CVS/Root Thu Jul 5 11:49:19 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/ddb5074/CVS/Entries linux-2.4-xfs/linux/arch/mips/ddb5074/CVS/Entries --- linux-2.4.7/linux/arch/mips/ddb5074/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ddb5074/CVS/Entries Thu Jul 5 11:49:20 2001 @@ -0,0 +1,9 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/int-handler.S/1.3/Wed May 2 06:22:13 2001/-ko/ +/irq.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/nile4.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/pci.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/prom.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/time.c/1.3/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/ddb5074/CVS/Repository linux-2.4-xfs/linux/arch/mips/ddb5074/CVS/Repository --- linux-2.4.7/linux/arch/mips/ddb5074/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ddb5074/CVS/Repository Thu Jul 5 11:49:19 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/ddb5074 diff -rNu linux-2.4.7/linux/arch/mips/ddb5074/CVS/Root linux-2.4-xfs/linux/arch/mips/ddb5074/CVS/Root --- linux-2.4.7/linux/arch/mips/ddb5074/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ddb5074/CVS/Root Thu Jul 5 11:49:19 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/ddb5476/CVS/Entries linux-2.4-xfs/linux/arch/mips/ddb5476/CVS/Entries --- linux-2.4.7/linux/arch/mips/ddb5476/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ddb5476/CVS/Entries Thu Jul 5 11:49:20 2001 @@ -0,0 +1,10 @@ +/Makefile/1.1/Wed May 2 06:22:13 2001/-ko/ +/dbg_io.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/int-handler.S/1.1/Wed May 2 06:22:13 2001/-ko/ +/irq.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/nile4.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/pci.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/prom.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/time.c/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/ddb5476/CVS/Repository linux-2.4-xfs/linux/arch/mips/ddb5476/CVS/Repository --- linux-2.4.7/linux/arch/mips/ddb5476/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ddb5476/CVS/Repository Thu Jul 5 11:49:20 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/ddb5476 diff -rNu linux-2.4.7/linux/arch/mips/ddb5476/CVS/Root linux-2.4-xfs/linux/arch/mips/ddb5476/CVS/Root --- linux-2.4.7/linux/arch/mips/ddb5476/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ddb5476/CVS/Root Thu Jul 5 11:49:20 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/dec/CVS/Entries linux-2.4-xfs/linux/arch/mips/dec/CVS/Entries --- linux-2.4.7/linux/arch/mips/dec/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/dec/CVS/Entries Thu Jul 5 11:49:21 2001 @@ -0,0 +1,11 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/int-handler.S/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/irq.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/promcon.c/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/reset.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/rtc-dec.c/1.3/Fri May 26 01:52:46 2000/-ko/ +/serial.c/1.4/Fri May 26 01:52:46 2000/-ko/ +/setup.c/1.3/Mon Sep 6 21:00:05 1999/-ko/ +/time.c/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/wbflush.c/1.4/Sun Feb 27 22:13:56 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/dec/CVS/Entries.Log linux-2.4-xfs/linux/arch/mips/dec/CVS/Entries.Log --- linux-2.4.7/linux/arch/mips/dec/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/dec/CVS/Entries.Log Thu Jul 5 11:49:21 2001 @@ -0,0 +1,2 @@ +A D/boot//// +A D/prom//// diff -rNu linux-2.4.7/linux/arch/mips/dec/CVS/Repository linux-2.4-xfs/linux/arch/mips/dec/CVS/Repository --- linux-2.4.7/linux/arch/mips/dec/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/dec/CVS/Repository Thu Jul 5 11:49:20 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/dec diff -rNu linux-2.4.7/linux/arch/mips/dec/CVS/Root linux-2.4-xfs/linux/arch/mips/dec/CVS/Root --- linux-2.4.7/linux/arch/mips/dec/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/dec/CVS/Root Thu Jul 5 11:49:20 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/dec/boot/CVS/Entries linux-2.4-xfs/linux/arch/mips/dec/boot/CVS/Entries --- linux-2.4.7/linux/arch/mips/dec/boot/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/dec/boot/CVS/Entries Thu Jul 5 11:49:21 2001 @@ -0,0 +1,4 @@ +/Makefile/1.2/Wed May 2 06:22:13 2001/-ko/ +/decstation.c/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/ld.ecoff/1.2/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/dec/boot/CVS/Repository linux-2.4-xfs/linux/arch/mips/dec/boot/CVS/Repository --- linux-2.4.7/linux/arch/mips/dec/boot/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/dec/boot/CVS/Repository Thu Jul 5 11:49:21 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/dec/boot diff -rNu linux-2.4.7/linux/arch/mips/dec/boot/CVS/Root linux-2.4-xfs/linux/arch/mips/dec/boot/CVS/Root --- linux-2.4.7/linux/arch/mips/dec/boot/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/dec/boot/CVS/Root Thu Jul 5 11:49:21 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/dec/prom/CVS/Entries linux-2.4-xfs/linux/arch/mips/dec/prom/CVS/Entries --- linux-2.4.7/linux/arch/mips/dec/prom/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/dec/prom/CVS/Entries Thu Jul 5 11:49:21 2001 @@ -0,0 +1,9 @@ +/Makefile/1.4/Fri May 26 01:52:46 2000/-ko/ +/cmdline.c/1.4/Fri Mar 3 01:30:48 2000/-ko/ +/dectypes.h/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/identify.c/1.4/Fri Mar 3 01:30:48 2000/-ko/ +/init.c/1.4/Fri May 26 01:52:46 2000/-ko/ +/locore.S/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/memory.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/prom.h/1.1/Fri Jul 2 09:56:47 1999/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/dec/prom/CVS/Repository linux-2.4-xfs/linux/arch/mips/dec/prom/CVS/Repository --- linux-2.4.7/linux/arch/mips/dec/prom/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/dec/prom/CVS/Repository Thu Jul 5 11:49:21 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/dec/prom diff -rNu linux-2.4.7/linux/arch/mips/dec/prom/CVS/Root linux-2.4-xfs/linux/arch/mips/dec/prom/CVS/Root --- linux-2.4.7/linux/arch/mips/dec/prom/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/dec/prom/CVS/Root Thu Jul 5 11:49:21 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/defconfig linux-2.4-xfs/linux/arch/mips/defconfig --- linux-2.4.7/linux/arch/mips/defconfig Fri Apr 13 22:26:07 2001 +++ linux-2.4-xfs/linux/arch/mips/defconfig Mon Jun 11 23:51:00 2001 @@ -355,3 +355,11 @@ CONFIG_CROSSCOMPILE=y # CONFIG_MIPS_FPE_MODULE is not set # CONFIG_MAGIC_SYSRQ is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/mips/ite-boards/CVS/Entries linux-2.4-xfs/linux/arch/mips/ite-boards/CVS/Entries --- linux-2.4.7/linux/arch/mips/ite-boards/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ite-boards/CVS/Entries Thu Jul 5 11:49:21 2001 @@ -0,0 +1 @@ +D diff -rNu linux-2.4.7/linux/arch/mips/ite-boards/CVS/Entries.Log linux-2.4-xfs/linux/arch/mips/ite-boards/CVS/Entries.Log --- linux-2.4.7/linux/arch/mips/ite-boards/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ite-boards/CVS/Entries.Log Thu Jul 5 11:49:22 2001 @@ -0,0 +1,2 @@ +A D/generic//// +A D/qed-4n-s01b//// diff -rNu linux-2.4.7/linux/arch/mips/ite-boards/CVS/Repository linux-2.4-xfs/linux/arch/mips/ite-boards/CVS/Repository --- linux-2.4.7/linux/arch/mips/ite-boards/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ite-boards/CVS/Repository Thu Jul 5 11:49:21 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/ite-boards diff -rNu linux-2.4.7/linux/arch/mips/ite-boards/CVS/Root linux-2.4-xfs/linux/arch/mips/ite-boards/CVS/Root --- linux-2.4.7/linux/arch/mips/ite-boards/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ite-boards/CVS/Root Thu Jul 5 11:49:21 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/ite-boards/generic/CVS/Entries linux-2.4-xfs/linux/arch/mips/ite-boards/generic/CVS/Entries --- linux-2.4.7/linux/arch/mips/ite-boards/generic/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ite-boards/generic/CVS/Entries Thu Jul 5 11:49:22 2001 @@ -0,0 +1,14 @@ +/Makefile/1.1/Wed May 2 06:22:13 2001/-ko/ +/dbg_io.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/int-handler.S/1.1/Wed May 2 06:22:13 2001/-ko/ +/irq.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/it8172_cir.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/it8172_pci.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/it8172_rtc.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/it8172_setup.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/lpc.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/pmon_prom.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/puts.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/reset.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/time.c/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/ite-boards/generic/CVS/Repository linux-2.4-xfs/linux/arch/mips/ite-boards/generic/CVS/Repository --- linux-2.4.7/linux/arch/mips/ite-boards/generic/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ite-boards/generic/CVS/Repository Thu Jul 5 11:49:21 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/ite-boards/generic diff -rNu linux-2.4.7/linux/arch/mips/ite-boards/generic/CVS/Root linux-2.4-xfs/linux/arch/mips/ite-boards/generic/CVS/Root --- linux-2.4.7/linux/arch/mips/ite-boards/generic/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ite-boards/generic/CVS/Root Thu Jul 5 11:49:21 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/ite-boards/qed-4n-s01b/CVS/Entries linux-2.4-xfs/linux/arch/mips/ite-boards/qed-4n-s01b/CVS/Entries --- linux-2.4.7/linux/arch/mips/ite-boards/qed-4n-s01b/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ite-boards/qed-4n-s01b/CVS/Entries Thu Jul 5 11:49:22 2001 @@ -0,0 +1,5 @@ +/Makefile/1.1/Wed May 2 06:22:13 2001/-ko/ +/README/1.1/Wed May 2 06:22:13 2001/-ko/ +/init.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/pci_fixup.c/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/ite-boards/qed-4n-s01b/CVS/Repository linux-2.4-xfs/linux/arch/mips/ite-boards/qed-4n-s01b/CVS/Repository --- linux-2.4.7/linux/arch/mips/ite-boards/qed-4n-s01b/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ite-boards/qed-4n-s01b/CVS/Repository Thu Jul 5 11:49:22 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/ite-boards/qed-4n-s01b diff -rNu linux-2.4.7/linux/arch/mips/ite-boards/qed-4n-s01b/CVS/Root linux-2.4-xfs/linux/arch/mips/ite-boards/qed-4n-s01b/CVS/Root --- linux-2.4.7/linux/arch/mips/ite-boards/qed-4n-s01b/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/ite-boards/qed-4n-s01b/CVS/Root Thu Jul 5 11:49:22 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/jazz/CVS/Entries linux-2.4-xfs/linux/arch/mips/jazz/CVS/Entries --- linux-2.4.7/linux/arch/mips/jazz/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/jazz/CVS/Entries Thu Jul 5 11:49:22 2001 @@ -0,0 +1,10 @@ +/Makefile/1.5/Wed May 2 06:22:13 2001/-ko/ +/floppy-jazz.c/1.6/Fri May 26 01:52:46 2000/-ko/ +/int-handler.S/1.5/Fri May 26 01:52:46 2000/-ko/ +/io.c/1.4/Sun Feb 27 22:13:56 2000/-ko/ +/jazzdma.c/1.4/Sun Feb 27 22:13:56 2000/-ko/ +/kbd-jazz.c/1.3/Fri May 26 01:52:46 2000/-ko/ +/reset.c/1.4/Fri May 26 01:52:46 2000/-ko/ +/rtc-jazz.c/1.5/Fri May 26 01:52:46 2000/-ko/ +/setup.c/1.6/Fri May 26 01:52:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/jazz/CVS/Repository linux-2.4-xfs/linux/arch/mips/jazz/CVS/Repository --- linux-2.4.7/linux/arch/mips/jazz/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/jazz/CVS/Repository Thu Jul 5 11:49:22 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/jazz diff -rNu linux-2.4.7/linux/arch/mips/jazz/CVS/Root linux-2.4-xfs/linux/arch/mips/jazz/CVS/Root --- linux-2.4.7/linux/arch/mips/jazz/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/jazz/CVS/Root Thu Jul 5 11:49:22 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/kernel/CVS/Entries linux-2.4-xfs/linux/arch/mips/kernel/CVS/Entries --- linux-2.4.7/linux/arch/mips/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/kernel/CVS/Entries Thu Jul 5 11:49:26 2001 @@ -0,0 +1,47 @@ +/Makefile/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/branch.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/entry.S/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/fpe.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/gdb-low.S/1.5/Fri May 26 01:52:46 2000/-ko/ +/gdb-stub.c/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/head.S/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/i8259.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/init_task.c/1.4/Fri Aug 27 23:14:48 1999/-ko/ +/ioport.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ipc.c/1.3/Sun Feb 27 22:13:56 2000/-ko/ +/irix5sys.h/1.6/Thu Feb 1 04:38:20 2001/-ko/ +/irixelf.c/1.15/Mon Apr 2 17:13:32 2001/-ko/ +/irixinv.c/1.6/Fri May 26 01:52:46 2000/-ko/ +/irixioctl.c/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/irixsig.c/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/irq.c/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/mips_ksyms.c/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/old-irq.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/old-time.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/pci-dma.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/proc.c/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/process.c/1.11/Tue Jul 3 02:33:57 2001/-ko/ +/ptrace.c/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/r2300_fpu.S/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/r2300_misc.S/1.5/Fri Mar 3 01:30:48 2000/-ko/ +/r2300_switch.S/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/r4k_fpu.S/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/r4k_misc.S/1.8/Tue Jul 3 02:33:57 2001/-ko/ +/r4k_switch.S/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/r6000_fpu.S/1.6/Wed May 2 06:22:13 2001/-ko/ +/reset.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/scall_o32.S/1.8/Tue Jul 3 02:33:57 2001/-ko/ +/semaphore.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.11/Tue Jul 3 02:33:57 2001/-ko/ +/signal.c/1.12/Wed May 2 06:22:13 2001/-ko/ +/smp.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/softfp.S/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/syscall.c/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/syscalls.h/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/sysirix.c/1.15/Tue Jul 3 02:33:57 2001/-ko/ +/sysmips.c/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/time.c/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/traps.c/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/unaligned.c/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/vm86.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/kernel/CVS/Repository linux-2.4-xfs/linux/arch/mips/kernel/CVS/Repository --- linux-2.4.7/linux/arch/mips/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/kernel/CVS/Repository Thu Jul 5 11:49:22 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/kernel diff -rNu linux-2.4.7/linux/arch/mips/kernel/CVS/Root linux-2.4-xfs/linux/arch/mips/kernel/CVS/Root --- linux-2.4.7/linux/arch/mips/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/kernel/CVS/Root Thu Jul 5 11:49:22 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/lib/CVS/Entries linux-2.4-xfs/linux/arch/mips/lib/CVS/Entries --- linux-2.4.7/linux/arch/mips/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/lib/CVS/Entries Thu Jul 5 11:49:26 2001 @@ -0,0 +1,21 @@ +/Makefile/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/csum_partial.S/1.4/Fri May 26 01:52:46 2000/-ko/ +/csum_partial_copy.c/1.5/Fri May 26 01:52:46 2000/-ko/ +/dump_tlb.c/1.3/Sun Feb 27 22:13:56 2000/-ko/ +/floppy-no.c/1.4/Fri May 26 01:52:46 2000/-ko/ +/floppy-std.c/1.6/Fri May 26 01:52:46 2000/-ko/ +/ide-no.c/1.4/Fri May 26 01:52:46 2000/-ko/ +/ide-std.c/1.4/Fri May 26 01:52:46 2000/-ko/ +/kbd-no.c/1.3/Fri May 26 01:52:46 2000/-ko/ +/kbd-std.c/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/memcpy.S/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/memset.S/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/r3k_dump_tlb.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/rtc-no.c/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/rtc-std.c/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/strlen_user.S/1.5/Fri May 26 01:52:46 2000/-ko/ +/strncpy_user.S/1.5/Fri May 26 01:52:46 2000/-ko/ +/strnlen_user.S/1.2/Fri May 26 01:52:46 2000/-ko/ +/tinycon.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/watch.S/1.5/Fri May 26 01:52:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/lib/CVS/Repository linux-2.4-xfs/linux/arch/mips/lib/CVS/Repository --- linux-2.4.7/linux/arch/mips/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/lib/CVS/Repository Thu Jul 5 11:49:26 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/lib diff -rNu linux-2.4.7/linux/arch/mips/lib/CVS/Root linux-2.4-xfs/linux/arch/mips/lib/CVS/Root --- linux-2.4.7/linux/arch/mips/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/lib/CVS/Root Thu Jul 5 11:49:26 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/math-emu/CVS/Entries linux-2.4-xfs/linux/arch/mips/math-emu/CVS/Entries --- linux-2.4.7/linux/arch/mips/math-emu/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/math-emu/CVS/Entries Thu Jul 5 11:49:27 2001 @@ -0,0 +1,46 @@ +/Makefile/1.1/Wed May 2 06:22:13 2001/-ko/ +/cp1emu.c/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/dp_add.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dp_cmp.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dp_div.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dp_fint.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dp_flong.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dp_frexp.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dp_fsp.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dp_logb.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dp_modf.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dp_mul.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dp_scalb.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dp_simple.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dp_sqrt.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dp_sub.c/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/dp_tint.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dp_tlong.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/ieee754.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/ieee754.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/ieee754d.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/ieee754dp.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/ieee754dp.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/ieee754int.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/ieee754m.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/ieee754sp.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/ieee754sp.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/ieee754xcpt.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/kernel_linkage.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_add.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_cmp.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_div.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_fdp.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_fint.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_flong.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_frexp.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_logb.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_modf.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_mul.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_scalb.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_simple.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_sqrt.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_sub.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_tint.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sp_tlong.c/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/math-emu/CVS/Repository linux-2.4-xfs/linux/arch/mips/math-emu/CVS/Repository --- linux-2.4.7/linux/arch/mips/math-emu/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/math-emu/CVS/Repository Thu Jul 5 11:49:26 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/math-emu diff -rNu linux-2.4.7/linux/arch/mips/math-emu/CVS/Root linux-2.4-xfs/linux/arch/mips/math-emu/CVS/Root --- linux-2.4.7/linux/arch/mips/math-emu/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/math-emu/CVS/Root Thu Jul 5 11:49:26 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/mips-boards/CVS/Entries linux-2.4-xfs/linux/arch/mips/mips-boards/CVS/Entries --- linux-2.4.7/linux/arch/mips/mips-boards/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mips-boards/CVS/Entries Thu Jul 5 11:49:27 2001 @@ -0,0 +1 @@ +D diff -rNu linux-2.4.7/linux/arch/mips/mips-boards/CVS/Entries.Log linux-2.4-xfs/linux/arch/mips/mips-boards/CVS/Entries.Log --- linux-2.4.7/linux/arch/mips/mips-boards/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mips-boards/CVS/Entries.Log Thu Jul 5 11:49:27 2001 @@ -0,0 +1,3 @@ +A D/atlas//// +A D/generic//// +A D/malta//// diff -rNu linux-2.4.7/linux/arch/mips/mips-boards/CVS/Repository linux-2.4-xfs/linux/arch/mips/mips-boards/CVS/Repository --- linux-2.4.7/linux/arch/mips/mips-boards/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mips-boards/CVS/Repository Thu Jul 5 11:49:27 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/mips-boards diff -rNu linux-2.4.7/linux/arch/mips/mips-boards/CVS/Root linux-2.4-xfs/linux/arch/mips/mips-boards/CVS/Root --- linux-2.4.7/linux/arch/mips/mips-boards/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mips-boards/CVS/Root Thu Jul 5 11:49:27 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/mips-boards/atlas/CVS/Entries linux-2.4-xfs/linux/arch/mips/mips-boards/atlas/CVS/Entries --- linux-2.4.7/linux/arch/mips/mips-boards/atlas/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mips-boards/atlas/CVS/Entries Thu Jul 5 11:49:27 2001 @@ -0,0 +1,5 @@ +/Makefile/1.1/Wed May 2 06:22:13 2001/-ko/ +/atlas_int.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/atlas_rtc.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/atlas_setup.c/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/mips-boards/atlas/CVS/Repository linux-2.4-xfs/linux/arch/mips/mips-boards/atlas/CVS/Repository --- linux-2.4.7/linux/arch/mips/mips-boards/atlas/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mips-boards/atlas/CVS/Repository Thu Jul 5 11:49:27 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/mips-boards/atlas diff -rNu linux-2.4.7/linux/arch/mips/mips-boards/atlas/CVS/Root linux-2.4-xfs/linux/arch/mips/mips-boards/atlas/CVS/Root --- linux-2.4.7/linux/arch/mips/mips-boards/atlas/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mips-boards/atlas/CVS/Root Thu Jul 5 11:49:27 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/mips-boards/generic/CVS/Entries linux-2.4-xfs/linux/arch/mips/mips-boards/generic/CVS/Entries --- linux-2.4.7/linux/arch/mips/mips-boards/generic/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mips-boards/generic/CVS/Entries Thu Jul 5 11:49:27 2001 @@ -0,0 +1,12 @@ +/Makefile/1.1/Wed May 2 06:22:13 2001/-ko/ +/cmdline.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/display.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/gdb_hook.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/init.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/memory.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/mipsIRQ.S/1.1/Wed May 2 06:22:13 2001/-ko/ +/pci.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/printf.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/reset.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/time.c/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/mips-boards/generic/CVS/Repository linux-2.4-xfs/linux/arch/mips/mips-boards/generic/CVS/Repository --- linux-2.4.7/linux/arch/mips/mips-boards/generic/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mips-boards/generic/CVS/Repository Thu Jul 5 11:49:27 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/mips-boards/generic diff -rNu linux-2.4.7/linux/arch/mips/mips-boards/generic/CVS/Root linux-2.4-xfs/linux/arch/mips/mips-boards/generic/CVS/Root --- linux-2.4.7/linux/arch/mips/mips-boards/generic/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mips-boards/generic/CVS/Root Thu Jul 5 11:49:27 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/mips-boards/malta/CVS/Entries linux-2.4-xfs/linux/arch/mips/mips-boards/malta/CVS/Entries --- linux-2.4.7/linux/arch/mips/mips-boards/malta/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mips-boards/malta/CVS/Entries Thu Jul 5 11:49:27 2001 @@ -0,0 +1,5 @@ +/Makefile/1.1/Wed May 2 06:22:13 2001/-ko/ +/malta_int.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/malta_rtc.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/malta_setup.c/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/mips-boards/malta/CVS/Repository linux-2.4-xfs/linux/arch/mips/mips-boards/malta/CVS/Repository --- linux-2.4.7/linux/arch/mips/mips-boards/malta/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mips-boards/malta/CVS/Repository Thu Jul 5 11:49:27 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/mips-boards/malta diff -rNu linux-2.4.7/linux/arch/mips/mips-boards/malta/CVS/Root linux-2.4-xfs/linux/arch/mips/mips-boards/malta/CVS/Root --- linux-2.4.7/linux/arch/mips/mips-boards/malta/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mips-boards/malta/CVS/Root Thu Jul 5 11:49:27 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/mm/CVS/Entries linux-2.4-xfs/linux/arch/mips/mm/CVS/Entries --- linux-2.4.7/linux/arch/mips/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mm/CVS/Entries Thu Jul 5 11:49:29 2001 @@ -0,0 +1,15 @@ +/Makefile/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/andes.c/1.8/Thu Jul 5 05:29:17 2001/-ko/ +/extable.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/fault.c/1.11/Thu Jul 5 05:29:17 2001/-ko/ +/init.c/1.12/Thu Jul 5 05:29:17 2001/-ko/ +/ioremap.c/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/loadmmu.c/1.8/Thu Jul 5 05:29:17 2001/-ko/ +/mips32.c/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/r2300.c/1.9/Thu Jul 5 05:29:17 2001/-ko/ +/r4xx0.c/1.8/Thu Jul 5 05:29:17 2001/-ko/ +/r5432.c/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/rm7k.c/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/sb1.c/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/umap.c/1.7/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/mm/CVS/Repository linux-2.4-xfs/linux/arch/mips/mm/CVS/Repository --- linux-2.4.7/linux/arch/mips/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mm/CVS/Repository Thu Jul 5 11:49:27 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/mm diff -rNu linux-2.4.7/linux/arch/mips/mm/CVS/Root linux-2.4-xfs/linux/arch/mips/mm/CVS/Root --- linux-2.4.7/linux/arch/mips/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/mm/CVS/Root Thu Jul 5 11:49:27 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/sgi/CVS/Entries linux-2.4-xfs/linux/arch/mips/sgi/CVS/Entries --- linux-2.4.7/linux/arch/mips/sgi/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/sgi/CVS/Entries Thu Jul 5 11:49:29 2001 @@ -0,0 +1 @@ +D diff -rNu linux-2.4.7/linux/arch/mips/sgi/CVS/Entries.Log linux-2.4-xfs/linux/arch/mips/sgi/CVS/Entries.Log --- linux-2.4.7/linux/arch/mips/sgi/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/sgi/CVS/Entries.Log Thu Jul 5 11:49:29 2001 @@ -0,0 +1 @@ +A D/kernel//// diff -rNu linux-2.4.7/linux/arch/mips/sgi/CVS/Repository linux-2.4-xfs/linux/arch/mips/sgi/CVS/Repository --- linux-2.4.7/linux/arch/mips/sgi/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/sgi/CVS/Repository Thu Jul 5 11:49:29 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/sgi diff -rNu linux-2.4.7/linux/arch/mips/sgi/CVS/Root linux-2.4-xfs/linux/arch/mips/sgi/CVS/Root --- linux-2.4.7/linux/arch/mips/sgi/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/sgi/CVS/Root Thu Jul 5 11:49:29 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/sgi/kernel/CVS/Entries linux-2.4-xfs/linux/arch/mips/sgi/kernel/CVS/Entries --- linux-2.4.7/linux/arch/mips/sgi/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/sgi/kernel/CVS/Entries Thu Jul 5 11:49:30 2001 @@ -0,0 +1,14 @@ +/Makefile/1.8/Wed May 2 06:22:13 2001/-ko/ +/indyIRQ.S/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/indy_hpc.c/1.6/Fri May 26 01:52:46 2000/-ko/ +/indy_int.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/indy_mc.c/1.6/Fri May 26 01:52:46 2000/-ko/ +/indy_rtc.c/1.4/Fri May 26 01:52:46 2000/-ko/ +/indy_sc.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/indy_timer.c/1.8/Wed Nov 1 21:35:42 2000/-ko/ +/promcon.c/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/reset.c/1.6/Fri May 26 01:52:46 2000/-ko/ +/setup.c/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/system.c/1.6/Fri May 26 01:52:46 2000/-ko/ +/time.c/1.7/Mon Jul 31 16:16:28 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/sgi/kernel/CVS/Repository linux-2.4-xfs/linux/arch/mips/sgi/kernel/CVS/Repository --- linux-2.4.7/linux/arch/mips/sgi/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/sgi/kernel/CVS/Repository Thu Jul 5 11:49:29 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/sgi/kernel diff -rNu linux-2.4.7/linux/arch/mips/sgi/kernel/CVS/Root linux-2.4-xfs/linux/arch/mips/sgi/kernel/CVS/Root --- linux-2.4.7/linux/arch/mips/sgi/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/sgi/kernel/CVS/Root Thu Jul 5 11:49:29 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/sni/CVS/Entries linux-2.4-xfs/linux/arch/mips/sni/CVS/Entries --- linux-2.4.7/linux/arch/mips/sni/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/sni/CVS/Entries Thu Jul 5 11:49:30 2001 @@ -0,0 +1,9 @@ +/Makefile/1.6/Wed May 2 06:22:13 2001/-ko/ +/dma.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/int-handler.S/1.5/Fri May 26 01:52:46 2000/-ko/ +/io.c/1.6/Fri May 26 01:52:46 2000/-ko/ +/pci.c/1.8/Mon Jul 31 16:16:28 2000/-ko/ +/pcimt_scache.c/1.6/Fri May 26 01:52:46 2000/-ko/ +/reset.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/setup.c/1.8/Mon Jul 31 16:16:28 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/sni/CVS/Repository linux-2.4-xfs/linux/arch/mips/sni/CVS/Repository --- linux-2.4.7/linux/arch/mips/sni/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/sni/CVS/Repository Thu Jul 5 11:49:30 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/sni diff -rNu linux-2.4.7/linux/arch/mips/sni/CVS/Root linux-2.4-xfs/linux/arch/mips/sni/CVS/Root --- linux-2.4.7/linux/arch/mips/sni/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/sni/CVS/Root Thu Jul 5 11:49:30 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips/tools/CVS/Entries linux-2.4-xfs/linux/arch/mips/tools/CVS/Entries --- linux-2.4.7/linux/arch/mips/tools/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/tools/CVS/Entries Thu Jul 5 11:49:30 2001 @@ -0,0 +1,3 @@ +/Makefile/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/offset.c/1.7/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips/tools/CVS/Repository linux-2.4-xfs/linux/arch/mips/tools/CVS/Repository --- linux-2.4.7/linux/arch/mips/tools/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/tools/CVS/Repository Thu Jul 5 11:49:30 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips/tools diff -rNu linux-2.4.7/linux/arch/mips/tools/CVS/Root linux-2.4-xfs/linux/arch/mips/tools/CVS/Root --- linux-2.4.7/linux/arch/mips/tools/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips/tools/CVS/Root Thu Jul 5 11:49:30 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips64/CVS/Entries linux-2.4-xfs/linux/arch/mips64/CVS/Entries --- linux-2.4.7/linux/arch/mips64/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/CVS/Entries Thu Jul 5 11:49:31 2001 @@ -0,0 +1,8 @@ +/Makefile/1.7/Thu Jul 5 05:29:17 2001/-ko/ +/config.in/1.14/Thu Jul 5 05:29:17 2001/-ko/ +/defconfig/1.14/Thu Jul 5 05:29:17 2001/-ko/ +/defconfig-ip22/1.9/Thu Jul 5 05:29:17 2001/-ko/ +/defconfig-ip27/1.8/Thu Jul 5 05:29:17 2001/-ko/ +/ld.script.elf32.S/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/ld.script.elf64/1.4/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips64/CVS/Entries.Log linux-2.4-xfs/linux/arch/mips64/CVS/Entries.Log --- linux-2.4.7/linux/arch/mips64/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/CVS/Entries.Log Thu Jul 5 11:49:43 2001 @@ -0,0 +1,9 @@ +A D/arc//// +A D/boot//// +A D/kernel//// +A D/lib//// +A D/math-emu//// +A D/mm//// +A D/sgi-ip22//// +A D/sgi-ip27//// +A D/tools//// diff -rNu linux-2.4.7/linux/arch/mips64/CVS/Repository linux-2.4-xfs/linux/arch/mips64/CVS/Repository --- linux-2.4.7/linux/arch/mips64/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/CVS/Repository Thu Jul 5 11:49:30 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips64 diff -rNu linux-2.4.7/linux/arch/mips64/CVS/Root linux-2.4-xfs/linux/arch/mips64/CVS/Root --- linux-2.4.7/linux/arch/mips64/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/CVS/Root Thu Jul 5 11:49:30 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips64/arc/CVS/Entries linux-2.4-xfs/linux/arch/mips64/arc/CVS/Entries --- linux-2.4.7/linux/arch/mips64/arc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/arc/CVS/Entries Thu Jul 5 11:49:31 2001 @@ -0,0 +1,14 @@ +/Makefile/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/arc_con.c/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/cmdline.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/console.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/env.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/file.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/identify.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/init.c/1.2/Fri Mar 3 01:30:48 2000/-ko/ +/memory.c/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/misc.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/salone.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/time.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/tree.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips64/arc/CVS/Repository linux-2.4-xfs/linux/arch/mips64/arc/CVS/Repository --- linux-2.4.7/linux/arch/mips64/arc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/arc/CVS/Repository Thu Jul 5 11:49:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips64/arc diff -rNu linux-2.4.7/linux/arch/mips64/arc/CVS/Root linux-2.4-xfs/linux/arch/mips64/arc/CVS/Root --- linux-2.4.7/linux/arch/mips64/arc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/arc/CVS/Root Thu Jul 5 11:49:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips64/boot/CVS/Entries linux-2.4-xfs/linux/arch/mips64/boot/CVS/Entries --- linux-2.4.7/linux/arch/mips64/boot/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/boot/CVS/Entries Thu Jul 5 11:49:31 2001 @@ -0,0 +1,2 @@ +/Makefile/1.4/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips64/boot/CVS/Repository linux-2.4-xfs/linux/arch/mips64/boot/CVS/Repository --- linux-2.4.7/linux/arch/mips64/boot/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/boot/CVS/Repository Thu Jul 5 11:49:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips64/boot diff -rNu linux-2.4.7/linux/arch/mips64/boot/CVS/Root linux-2.4-xfs/linux/arch/mips64/boot/CVS/Root --- linux-2.4.7/linux/arch/mips64/boot/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/boot/CVS/Root Thu Jul 5 11:49:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips64/defconfig linux-2.4-xfs/linux/arch/mips64/defconfig --- linux-2.4.7/linux/arch/mips64/defconfig Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/mips64/defconfig Thu Jul 5 00:29:17 2001 @@ -470,3 +470,11 @@ # CONFIG_REMOTE_DEBUG is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_MIPS_UNCACHED is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/mips64/kernel/CVS/Entries linux-2.4-xfs/linux/arch/mips64/kernel/CVS/Entries --- linux-2.4.7/linux/arch/mips64/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/kernel/CVS/Entries Thu Jul 5 11:49:34 2001 @@ -0,0 +1,31 @@ +/Makefile/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/binfmt_elf32.c/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/branch.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/entry.S/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/head.S/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/init_task.c/1.1/Sun Feb 27 23:15:45 2000/-ko/ +/ioctl32.c/1.6/Thu Jul 5 05:29:17 2001/-ko/ +/linux32.c/1.9/Thu Jul 5 05:29:17 2001/-ko/ +/mips64_ksyms.c/1.6/Thu Jul 5 05:29:17 2001/-ko/ +/proc.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/process.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/ptrace.c/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/r4k_cache.S/1.2/Fri May 26 01:52:46 2000/-ko/ +/r4k_fpu.S/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/r4k_genex.S/1.2/Fri May 26 01:52:46 2000/-ko/ +/r4k_switch.S/1.2/Fri May 26 01:52:46 2000/-ko/ +/r4k_tlb.S/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/r4k_tlb_debug.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/r4k_tlb_glue.S/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/scall_64.S/1.8/Thu Jul 5 05:29:17 2001/-ko/ +/scall_o32.S/1.6/Thu Jul 5 05:29:17 2001/-ko/ +/semaphore.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.6/Thu Jul 5 05:29:17 2001/-ko/ +/signal.c/1.6/Thu Feb 1 17:10:24 2001/-ko/ +/signal32.c/1.7/Thu Feb 1 17:10:24 2001/-ko/ +/smp.c/1.7/Thu Jul 5 05:29:17 2001/-ko/ +/softfp.S/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/syscall.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/traps.c/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/unaligned.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips64/kernel/CVS/Repository linux-2.4-xfs/linux/arch/mips64/kernel/CVS/Repository --- linux-2.4.7/linux/arch/mips64/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/kernel/CVS/Repository Thu Jul 5 11:49:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips64/kernel diff -rNu linux-2.4.7/linux/arch/mips64/kernel/CVS/Root linux-2.4-xfs/linux/arch/mips64/kernel/CVS/Root --- linux-2.4.7/linux/arch/mips64/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/kernel/CVS/Root Thu Jul 5 11:49:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips64/kernel/ioctl32.c linux-2.4-xfs/linux/arch/mips64/kernel/ioctl32.c --- linux-2.4.7/linux/arch/mips64/kernel/ioctl32.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/arch/mips64/kernel/ioctl32.c Thu Jul 5 00:29:17 2001 @@ -799,6 +799,9 @@ IOCTL32_DEFAULT(RESTART_ARRAY_RW), #endif /* CONFIG_MD */ + IOCTL32_DEFAULT(BLKBSZGET), + IOCTL32_DEFAULT(BLKBSZSET), + IOCTL32_DEFAULT(MTIOCTOP), /* mtio.h ioctls */ IOCTL32_HANDLER(MTIOCGET32, mt_ioctl_trans), IOCTL32_HANDLER(MTIOCPOS32, mt_ioctl_trans), diff -rNu linux-2.4.7/linux/arch/mips64/lib/CVS/Entries linux-2.4-xfs/linux/arch/mips64/lib/CVS/Entries --- linux-2.4.7/linux/arch/mips64/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/lib/CVS/Entries Thu Jul 5 11:49:35 2001 @@ -0,0 +1,19 @@ +/Makefile/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/csum_partial.S/1.2/Fri May 26 01:52:46 2000/-ko/ +/csum_partial_copy.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/dump_tlb.c/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/floppy-no.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/floppy-std.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/ide-no.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/ide-std.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/kbd-no.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/kbd-std.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/memcpy.S/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/memset.S/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/rtc-no.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/rtc-std.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/strlen_user.S/1.2/Fri May 26 01:52:46 2000/-ko/ +/strncpy_user.S/1.2/Fri May 26 01:52:46 2000/-ko/ +/strnlen_user.S/1.2/Fri May 26 01:52:46 2000/-ko/ +/watch.S/1.3/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips64/lib/CVS/Repository linux-2.4-xfs/linux/arch/mips64/lib/CVS/Repository --- linux-2.4.7/linux/arch/mips64/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/lib/CVS/Repository Thu Jul 5 11:49:34 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips64/lib diff -rNu linux-2.4.7/linux/arch/mips64/lib/CVS/Root linux-2.4-xfs/linux/arch/mips64/lib/CVS/Root --- linux-2.4.7/linux/arch/mips64/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/lib/CVS/Root Thu Jul 5 11:49:34 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips64/math-emu/CVS/Entries linux-2.4-xfs/linux/arch/mips64/math-emu/CVS/Entries --- linux-2.4.7/linux/arch/mips64/math-emu/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/math-emu/CVS/Entries Thu Jul 5 11:49:38 2001 @@ -0,0 +1,46 @@ +/Makefile/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/cp1emu.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_add.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_cmp.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_div.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_fint.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_flong.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_frexp.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_fsp.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_logb.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_modf.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_mul.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_scalb.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_simple.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_sqrt.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_sub.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_tint.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/dp_tlong.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/ieee754.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/ieee754.h/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/ieee754d.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/ieee754dp.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/ieee754dp.h/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/ieee754int.h/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/ieee754m.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/ieee754sp.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/ieee754sp.h/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/ieee754xcpt.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/kernel_linkage.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_add.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_cmp.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_div.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_fdp.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_fint.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_flong.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_frexp.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_logb.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_modf.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_mul.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_scalb.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_simple.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_sqrt.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_sub.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_tint.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/sp_tlong.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips64/math-emu/CVS/Repository linux-2.4-xfs/linux/arch/mips64/math-emu/CVS/Repository --- linux-2.4.7/linux/arch/mips64/math-emu/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/math-emu/CVS/Repository Thu Jul 5 11:49:35 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips64/math-emu diff -rNu linux-2.4.7/linux/arch/mips64/math-emu/CVS/Root linux-2.4-xfs/linux/arch/mips64/math-emu/CVS/Root --- linux-2.4.7/linux/arch/mips64/math-emu/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/math-emu/CVS/Root Thu Jul 5 11:49:35 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips64/mm/CVS/Entries linux-2.4-xfs/linux/arch/mips64/mm/CVS/Entries --- linux-2.4.7/linux/arch/mips64/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/mm/CVS/Entries Thu Jul 5 11:49:40 2001 @@ -0,0 +1,9 @@ +/Makefile/1.4/Wed May 2 06:22:13 2001/-ko/ +/andes.c/1.6/Thu Jul 5 05:29:17 2001/-ko/ +/extable.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/fault.c/1.7/Thu Jul 5 05:29:17 2001/-ko/ +/init.c/1.6/Thu Jul 5 05:29:17 2001/-ko/ +/loadmmu.c/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/r4xx0.c/1.7/Thu Jul 5 05:29:17 2001/-ko/ +/umap.c/1.5/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips64/mm/CVS/Repository linux-2.4-xfs/linux/arch/mips64/mm/CVS/Repository --- linux-2.4.7/linux/arch/mips64/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/mm/CVS/Repository Thu Jul 5 11:49:38 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips64/mm diff -rNu linux-2.4.7/linux/arch/mips64/mm/CVS/Root linux-2.4-xfs/linux/arch/mips64/mm/CVS/Root --- linux-2.4.7/linux/arch/mips64/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/mm/CVS/Root Thu Jul 5 11:49:38 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips64/sgi-ip22/CVS/Entries linux-2.4-xfs/linux/arch/mips64/sgi-ip22/CVS/Entries --- linux-2.4.7/linux/arch/mips64/sgi-ip22/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/sgi-ip22/CVS/Entries Thu Jul 5 11:49:41 2001 @@ -0,0 +1,14 @@ +/Makefile/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/ip22-berr.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/ip22-hpc.c/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/ip22-int.c/1.5/Wed Feb 28 17:34:44 2001/-ko/ +/ip22-irq.S/1.2/Fri May 26 01:52:46 2000/-ko/ +/ip22-mc.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/ip22-reset.c/1.3/Fri May 26 01:52:46 2000/-ko/ +/ip22-rtc.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/ip22-sc.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/ip22-setup.c/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/ip22-timer.c/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/system.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/time.c/1.2/Fri May 26 01:52:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips64/sgi-ip22/CVS/Repository linux-2.4-xfs/linux/arch/mips64/sgi-ip22/CVS/Repository --- linux-2.4.7/linux/arch/mips64/sgi-ip22/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/sgi-ip22/CVS/Repository Thu Jul 5 11:49:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips64/sgi-ip22 diff -rNu linux-2.4.7/linux/arch/mips64/sgi-ip22/CVS/Root linux-2.4-xfs/linux/arch/mips64/sgi-ip22/CVS/Root --- linux-2.4.7/linux/arch/mips64/sgi-ip22/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/sgi-ip22/CVS/Root Thu Jul 5 11:49:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips64/sgi-ip27/CVS/Entries linux-2.4-xfs/linux/arch/mips64/sgi-ip27/CVS/Entries --- linux-2.4.7/linux/arch/mips64/sgi-ip27/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/sgi-ip27/CVS/Entries Thu Jul 5 11:49:43 2001 @@ -0,0 +1,18 @@ +/Makefile/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/TODO/1.2/Fri May 26 01:52:46 2000/-ko/ +/ip27-berr.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/ip27-console.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ip27-init.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/ip27-irq-glue.S/1.2/Fri May 26 01:52:46 2000/-ko/ +/ip27-irq.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/ip27-klconfig.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/ip27-klnuma.c/1.2/Sun Dec 17 19:15:00 2000/-ko/ +/ip27-memory.c/1.7/Sun Dec 17 19:15:00 2000/-ko/ +/ip27-nmi.c/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/ip27-pci-dma.c/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/ip27-pci.c/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/ip27-reset.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/ip27-rtc.c/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/ip27-setup.c/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/ip27-timer.c/1.7/Sun Dec 17 19:15:00 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips64/sgi-ip27/CVS/Repository linux-2.4-xfs/linux/arch/mips64/sgi-ip27/CVS/Repository --- linux-2.4.7/linux/arch/mips64/sgi-ip27/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/sgi-ip27/CVS/Repository Thu Jul 5 11:49:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips64/sgi-ip27 diff -rNu linux-2.4.7/linux/arch/mips64/sgi-ip27/CVS/Root linux-2.4-xfs/linux/arch/mips64/sgi-ip27/CVS/Root --- linux-2.4.7/linux/arch/mips64/sgi-ip27/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/sgi-ip27/CVS/Root Thu Jul 5 11:49:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/mips64/tools/CVS/Entries linux-2.4-xfs/linux/arch/mips64/tools/CVS/Entries --- linux-2.4.7/linux/arch/mips64/tools/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/tools/CVS/Entries Thu Jul 5 11:49:43 2001 @@ -0,0 +1,3 @@ +/Makefile/1.4/Wed May 2 06:22:13 2001/-ko/ +/offset.c/1.4/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/mips64/tools/CVS/Repository linux-2.4-xfs/linux/arch/mips64/tools/CVS/Repository --- linux-2.4.7/linux/arch/mips64/tools/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/tools/CVS/Repository Thu Jul 5 11:49:43 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/mips64/tools diff -rNu linux-2.4.7/linux/arch/mips64/tools/CVS/Root linux-2.4-xfs/linux/arch/mips64/tools/CVS/Root --- linux-2.4.7/linux/arch/mips64/tools/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/mips64/tools/CVS/Root Thu Jul 5 11:49:43 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/parisc/CVS/Entries linux-2.4-xfs/linux/arch/parisc/CVS/Entries --- linux-2.4.7/linux/arch/parisc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/CVS/Entries Thu Jul 5 11:49:43 2001 @@ -0,0 +1,5 @@ +/Makefile/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/config.in/1.2/Wed May 2 06:22:13 2001/-ko/ +/defconfig/1.2/Tue Jun 12 04:51:00 2001/-ko/ +/vmlinux.lds/1.2/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/parisc/CVS/Entries.Log linux-2.4-xfs/linux/arch/parisc/CVS/Entries.Log --- linux-2.4.7/linux/arch/parisc/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/CVS/Entries.Log Thu Jul 5 11:49:51 2001 @@ -0,0 +1,5 @@ +A D/hpux//// +A D/kernel//// +A D/lib//// +A D/mm//// +A D/tools//// diff -rNu linux-2.4.7/linux/arch/parisc/CVS/Repository linux-2.4-xfs/linux/arch/parisc/CVS/Repository --- linux-2.4.7/linux/arch/parisc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/CVS/Repository Thu Jul 5 11:49:43 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/parisc diff -rNu linux-2.4.7/linux/arch/parisc/CVS/Root linux-2.4-xfs/linux/arch/parisc/CVS/Root --- linux-2.4.7/linux/arch/parisc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/CVS/Root Thu Jul 5 11:49:43 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/parisc/defconfig linux-2.4-xfs/linux/arch/parisc/defconfig --- linux-2.4.7/linux/arch/parisc/defconfig Tue Dec 5 14:29:39 2000 +++ linux-2.4-xfs/linux/arch/parisc/defconfig Mon Jun 11 23:51:00 2001 @@ -361,3 +361,11 @@ # Kernel hacking # CONFIG_MAGIC_SYSRQ=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/parisc/hpux/CVS/Entries linux-2.4-xfs/linux/arch/parisc/hpux/CVS/Entries --- linux-2.4.7/linux/arch/parisc/hpux/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/hpux/CVS/Entries Thu Jul 5 11:49:44 2001 @@ -0,0 +1,8 @@ +/Makefile/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/entry_hpux.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/fs.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/gate.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ioctl.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/sys_hpux.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/wrappers.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/parisc/hpux/CVS/Repository linux-2.4-xfs/linux/arch/parisc/hpux/CVS/Repository --- linux-2.4.7/linux/arch/parisc/hpux/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/hpux/CVS/Repository Thu Jul 5 11:49:43 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/parisc/hpux diff -rNu linux-2.4.7/linux/arch/parisc/hpux/CVS/Root linux-2.4-xfs/linux/arch/parisc/hpux/CVS/Root --- linux-2.4.7/linux/arch/parisc/hpux/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/hpux/CVS/Root Thu Jul 5 11:49:43 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/parisc/kernel/CVS/Entries linux-2.4-xfs/linux/arch/parisc/kernel/CVS/Entries --- linux-2.4.7/linux/arch/parisc/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/kernel/CVS/Entries Thu Jul 5 11:49:49 2001 @@ -0,0 +1,37 @@ +/Makefile/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/cache.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ccio-dma.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/ccio-rm-dma.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/drivers.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/entry.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/hardware.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/head.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/hpmc.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/init_task.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/inventory.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/iosapic.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/iosapic_private.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/irq.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/keyboard.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/lasimap.map/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/lba_pci.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/led.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/pa7300lc.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/parisc_ksyms.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/pci-dma.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/pci.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/pdc.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/pdc_cons.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/process.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/ptrace.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/real1.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/real2.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/sba_iommu.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/semaphore.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/signal.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/sys_parisc.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/syscall.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/time.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/traps.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/parisc/kernel/CVS/Repository linux-2.4-xfs/linux/arch/parisc/kernel/CVS/Repository --- linux-2.4.7/linux/arch/parisc/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/kernel/CVS/Repository Thu Jul 5 11:49:44 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/parisc/kernel diff -rNu linux-2.4.7/linux/arch/parisc/kernel/CVS/Root linux-2.4-xfs/linux/arch/parisc/kernel/CVS/Root --- linux-2.4.7/linux/arch/parisc/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/kernel/CVS/Root Thu Jul 5 11:49:44 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/parisc/lib/CVS/Entries linux-2.4-xfs/linux/arch/parisc/lib/CVS/Entries --- linux-2.4.7/linux/arch/parisc/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/lib/CVS/Entries Thu Jul 5 11:49:50 2001 @@ -0,0 +1,5 @@ +/Makefile/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/bitops.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/checksum.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/lusercopy.S/1.1/Sun Dec 17 19:15:00 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/parisc/lib/CVS/Repository linux-2.4-xfs/linux/arch/parisc/lib/CVS/Repository --- linux-2.4.7/linux/arch/parisc/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/lib/CVS/Repository Thu Jul 5 11:49:49 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/parisc/lib diff -rNu linux-2.4.7/linux/arch/parisc/lib/CVS/Root linux-2.4-xfs/linux/arch/parisc/lib/CVS/Root --- linux-2.4.7/linux/arch/parisc/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/lib/CVS/Root Thu Jul 5 11:49:49 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/parisc/mm/CVS/Entries linux-2.4-xfs/linux/arch/parisc/mm/CVS/Entries --- linux-2.4.7/linux/arch/parisc/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/mm/CVS/Entries Thu Jul 5 11:49:51 2001 @@ -0,0 +1,8 @@ +/Makefile/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/extable.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/fault.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/init.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/kmap.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/pa11.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/pa20.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/parisc/mm/CVS/Repository linux-2.4-xfs/linux/arch/parisc/mm/CVS/Repository --- linux-2.4.7/linux/arch/parisc/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/mm/CVS/Repository Thu Jul 5 11:49:50 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/parisc/mm diff -rNu linux-2.4.7/linux/arch/parisc/mm/CVS/Root linux-2.4-xfs/linux/arch/parisc/mm/CVS/Root --- linux-2.4.7/linux/arch/parisc/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/mm/CVS/Root Thu Jul 5 11:49:50 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/parisc/tools/CVS/Entries linux-2.4-xfs/linux/arch/parisc/tools/CVS/Entries --- linux-2.4.7/linux/arch/parisc/tools/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/tools/CVS/Entries Thu Jul 5 11:49:51 2001 @@ -0,0 +1,3 @@ +/Makefile/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/offset.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/parisc/tools/CVS/Repository linux-2.4-xfs/linux/arch/parisc/tools/CVS/Repository --- linux-2.4.7/linux/arch/parisc/tools/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/tools/CVS/Repository Thu Jul 5 11:49:51 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/parisc/tools diff -rNu linux-2.4.7/linux/arch/parisc/tools/CVS/Root linux-2.4-xfs/linux/arch/parisc/tools/CVS/Root --- linux-2.4.7/linux/arch/parisc/tools/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/parisc/tools/CVS/Root Thu Jul 5 11:49:51 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/8260_io/CVS/Entries linux-2.4-xfs/linux/arch/ppc/8260_io/CVS/Entries --- linux-2.4.7/linux/arch/ppc/8260_io/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/8260_io/CVS/Entries Thu Jul 5 11:49:53 2001 @@ -0,0 +1,7 @@ +/Config.in/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/Makefile/1.4/Tue May 29 19:53:13 2001/-ko/ +/commproc.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/enet.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/fcc_enet.c/1.4/Tue May 29 19:53:13 2001/-ko/ +/uart.c/1.8/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/8260_io/CVS/Repository linux-2.4-xfs/linux/arch/ppc/8260_io/CVS/Repository --- linux-2.4.7/linux/arch/ppc/8260_io/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/8260_io/CVS/Repository Thu Jul 5 11:49:51 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/8260_io diff -rNu linux-2.4.7/linux/arch/ppc/8260_io/CVS/Root linux-2.4-xfs/linux/arch/ppc/8260_io/CVS/Root --- linux-2.4.7/linux/arch/ppc/8260_io/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/8260_io/CVS/Root Thu Jul 5 11:49:51 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/8xx_io/CVS/Entries linux-2.4-xfs/linux/arch/ppc/8xx_io/CVS/Entries --- linux-2.4.7/linux/arch/ppc/8xx_io/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/8xx_io/CVS/Entries Thu Jul 5 11:49:54 2001 @@ -0,0 +1,8 @@ +/Config.in/1.4/Tue May 29 19:53:13 2001/-ko/ +/Makefile/1.5/Tue May 29 19:53:13 2001/-ko/ +/commproc.c/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/commproc.h/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/enet.c/1.13/Tue May 29 19:53:13 2001/-ko/ +/fec.c/1.13/Tue May 29 19:53:13 2001/-ko/ +/uart.c/1.14/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/8xx_io/CVS/Repository linux-2.4-xfs/linux/arch/ppc/8xx_io/CVS/Repository --- linux-2.4.7/linux/arch/ppc/8xx_io/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/8xx_io/CVS/Repository Thu Jul 5 11:49:53 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/8xx_io diff -rNu linux-2.4.7/linux/arch/ppc/8xx_io/CVS/Root linux-2.4-xfs/linux/arch/ppc/8xx_io/CVS/Root --- linux-2.4.7/linux/arch/ppc/8xx_io/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/8xx_io/CVS/Root Thu Jul 5 11:49:53 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/CVS/Entries linux-2.4-xfs/linux/arch/ppc/CVS/Entries --- linux-2.4.7/linux/arch/ppc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/CVS/Entries Thu Jul 5 11:49:51 2001 @@ -0,0 +1,5 @@ +/Makefile/1.18/Tue May 29 19:53:13 2001/-ko/ +/config.in/1.37/Tue Jul 3 02:33:57 2001/-ko/ +/defconfig/1.30/Tue Jun 12 04:51:00 2001/-ko/ +/vmlinux.lds/1.8/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/CVS/Entries.Log linux-2.4-xfs/linux/arch/ppc/CVS/Entries.Log --- linux-2.4.7/linux/arch/ppc/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/CVS/Entries.Log Thu Jul 5 11:50:13 2001 @@ -0,0 +1,10 @@ +A D/8260_io//// +A D/8xx_io//// +A D/amiga//// +A D/boot//// +A D/configs//// +A D/kernel//// +A D/lib//// +A D/math-emu//// +A D/mm//// +A D/xmon//// diff -rNu linux-2.4.7/linux/arch/ppc/CVS/Repository linux-2.4-xfs/linux/arch/ppc/CVS/Repository --- linux-2.4.7/linux/arch/ppc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/CVS/Repository Thu Jul 5 11:49:51 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc diff -rNu linux-2.4.7/linux/arch/ppc/CVS/Root linux-2.4-xfs/linux/arch/ppc/CVS/Root --- linux-2.4.7/linux/arch/ppc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/CVS/Root Thu Jul 5 11:49:51 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/amiga/CVS/Entries linux-2.4-xfs/linux/arch/ppc/amiga/CVS/Entries --- linux-2.4.7/linux/arch/ppc/amiga/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/amiga/CVS/Entries Thu Jul 5 11:49:55 2001 @@ -0,0 +1,12 @@ +/Makefile/1.7/Tue May 29 19:53:13 2001/-ko/ +/amiga_ksyms.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/amiints.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/amisound.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/bootinfo.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/chipram.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/cia.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/config.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/ints.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/pcmcia.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/time.c/1.5/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/amiga/CVS/Repository linux-2.4-xfs/linux/arch/ppc/amiga/CVS/Repository --- linux-2.4.7/linux/arch/ppc/amiga/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/amiga/CVS/Repository Thu Jul 5 11:49:54 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/amiga diff -rNu linux-2.4.7/linux/arch/ppc/amiga/CVS/Root linux-2.4-xfs/linux/arch/ppc/amiga/CVS/Root --- linux-2.4.7/linux/arch/ppc/amiga/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/amiga/CVS/Root Thu Jul 5 11:49:54 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/boot/CVS/Entries linux-2.4-xfs/linux/arch/ppc/boot/CVS/Entries --- linux-2.4.7/linux/arch/ppc/boot/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/CVS/Entries Thu Jul 5 11:49:55 2001 @@ -0,0 +1,2 @@ +/Makefile/1.14/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/boot/CVS/Entries.Log linux-2.4-xfs/linux/arch/ppc/boot/CVS/Entries.Log --- linux-2.4.7/linux/arch/ppc/boot/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/CVS/Entries.Log Thu Jul 5 11:49:58 2001 @@ -0,0 +1,10 @@ +A D/chrp//// +A D/common//// +A D/images//// +A D/include//// +A D/lib//// +A D/mbx//// +A D/pmac//// +A D/prep//// +A D/tree//// +A D/utils//// diff -rNu linux-2.4.7/linux/arch/ppc/boot/CVS/Repository linux-2.4-xfs/linux/arch/ppc/boot/CVS/Repository --- linux-2.4.7/linux/arch/ppc/boot/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/CVS/Repository Thu Jul 5 11:49:55 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/boot diff -rNu linux-2.4.7/linux/arch/ppc/boot/CVS/Root linux-2.4-xfs/linux/arch/ppc/boot/CVS/Root --- linux-2.4.7/linux/arch/ppc/boot/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/CVS/Root Thu Jul 5 11:49:55 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/boot/chrp/CVS/Entries linux-2.4-xfs/linux/arch/ppc/boot/chrp/CVS/Entries --- linux-2.4.7/linux/arch/ppc/boot/chrp/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/chrp/CVS/Entries Thu Jul 5 11:49:55 2001 @@ -0,0 +1,5 @@ +/Makefile/1.1/Tue May 29 19:53:13 2001/-ko/ +/main.c/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/misc.S/1.1/Tue May 29 19:53:13 2001/-ko/ +/start.c/1.1/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/boot/chrp/CVS/Repository linux-2.4-xfs/linux/arch/ppc/boot/chrp/CVS/Repository --- linux-2.4.7/linux/arch/ppc/boot/chrp/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/chrp/CVS/Repository Thu Jul 5 11:49:55 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/boot/chrp diff -rNu linux-2.4.7/linux/arch/ppc/boot/chrp/CVS/Root linux-2.4-xfs/linux/arch/ppc/boot/chrp/CVS/Root --- linux-2.4.7/linux/arch/ppc/boot/chrp/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/chrp/CVS/Root Thu Jul 5 11:49:55 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/boot/common/CVS/Entries linux-2.4-xfs/linux/arch/ppc/boot/common/CVS/Entries --- linux-2.4.7/linux/arch/ppc/boot/common/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/common/CVS/Entries Thu Jul 5 11:49:56 2001 @@ -0,0 +1,8 @@ +/Makefile/1.1/Tue May 29 19:53:13 2001/-ko/ +/crt0.S/1.1/Tue May 29 19:53:13 2001/-ko/ +/misc-common.c/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/misc-simple.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/no_initrd.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/ns16550.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/string.S/1.1/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/boot/common/CVS/Repository linux-2.4-xfs/linux/arch/ppc/boot/common/CVS/Repository --- linux-2.4.7/linux/arch/ppc/boot/common/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/common/CVS/Repository Thu Jul 5 11:49:56 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/boot/common diff -rNu linux-2.4.7/linux/arch/ppc/boot/common/CVS/Root linux-2.4-xfs/linux/arch/ppc/boot/common/CVS/Root --- linux-2.4.7/linux/arch/ppc/boot/common/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/common/CVS/Root Thu Jul 5 11:49:56 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/boot/images/CVS/Entries linux-2.4-xfs/linux/arch/ppc/boot/images/CVS/Entries --- linux-2.4.7/linux/arch/ppc/boot/images/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/images/CVS/Entries Thu Jul 5 11:49:56 2001 @@ -0,0 +1,2 @@ +/Makefile/1.1/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/boot/images/CVS/Repository linux-2.4-xfs/linux/arch/ppc/boot/images/CVS/Repository --- linux-2.4.7/linux/arch/ppc/boot/images/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/images/CVS/Repository Thu Jul 5 11:49:56 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/boot/images diff -rNu linux-2.4.7/linux/arch/ppc/boot/images/CVS/Root linux-2.4-xfs/linux/arch/ppc/boot/images/CVS/Root --- linux-2.4.7/linux/arch/ppc/boot/images/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/images/CVS/Root Thu Jul 5 11:49:56 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/boot/include/CVS/Entries linux-2.4-xfs/linux/arch/ppc/boot/include/CVS/Entries --- linux-2.4.7/linux/arch/ppc/boot/include/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/include/CVS/Entries Thu Jul 5 11:49:56 2001 @@ -0,0 +1,4 @@ +/nonstdio.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/rs6000.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/zlib.h/1.1/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/boot/include/CVS/Repository linux-2.4-xfs/linux/arch/ppc/boot/include/CVS/Repository --- linux-2.4.7/linux/arch/ppc/boot/include/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/include/CVS/Repository Thu Jul 5 11:49:56 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/boot/include diff -rNu linux-2.4.7/linux/arch/ppc/boot/include/CVS/Root linux-2.4-xfs/linux/arch/ppc/boot/include/CVS/Root --- linux-2.4.7/linux/arch/ppc/boot/include/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/include/CVS/Root Thu Jul 5 11:49:56 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/boot/lib/CVS/Entries linux-2.4-xfs/linux/arch/ppc/boot/lib/CVS/Entries --- linux-2.4.7/linux/arch/ppc/boot/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/lib/CVS/Entries Thu Jul 5 11:49:57 2001 @@ -0,0 +1,3 @@ +/Makefile/1.1/Tue May 29 19:53:13 2001/-ko/ +/zlib.c/1.1/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/boot/lib/CVS/Repository linux-2.4-xfs/linux/arch/ppc/boot/lib/CVS/Repository --- linux-2.4.7/linux/arch/ppc/boot/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/lib/CVS/Repository Thu Jul 5 11:49:56 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/boot/lib diff -rNu linux-2.4.7/linux/arch/ppc/boot/lib/CVS/Root linux-2.4-xfs/linux/arch/ppc/boot/lib/CVS/Root --- linux-2.4.7/linux/arch/ppc/boot/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/lib/CVS/Root Thu Jul 5 11:49:56 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/boot/mbx/CVS/Entries linux-2.4-xfs/linux/arch/ppc/boot/mbx/CVS/Entries --- linux-2.4.7/linux/arch/ppc/boot/mbx/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/mbx/CVS/Entries Thu Jul 5 11:49:57 2001 @@ -0,0 +1,13 @@ +/Makefile/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/embed_config.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/gzimage.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/head.S/1.1/Tue May 29 19:53:13 2001/-ko/ +/head_8260.S/1.1/Tue May 29 19:53:13 2001/-ko/ +/iic.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/m8260_tty.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/m8xx_tty.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/misc.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/pci.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/qspan_pci.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/rdimage.c/1.1/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/boot/mbx/CVS/Repository linux-2.4-xfs/linux/arch/ppc/boot/mbx/CVS/Repository --- linux-2.4.7/linux/arch/ppc/boot/mbx/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/mbx/CVS/Repository Thu Jul 5 11:49:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/boot/mbx diff -rNu linux-2.4.7/linux/arch/ppc/boot/mbx/CVS/Root linux-2.4-xfs/linux/arch/ppc/boot/mbx/CVS/Root --- linux-2.4.7/linux/arch/ppc/boot/mbx/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/mbx/CVS/Root Thu Jul 5 11:49:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/boot/pmac/CVS/Entries linux-2.4-xfs/linux/arch/ppc/boot/pmac/CVS/Entries --- linux-2.4.7/linux/arch/ppc/boot/pmac/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/pmac/CVS/Entries Thu Jul 5 11:49:58 2001 @@ -0,0 +1,8 @@ +/Makefile/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/chrpmain.c/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/coffmain.c/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/dummy.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/ld.script/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/misc.S/1.1/Tue May 29 19:53:13 2001/-ko/ +/start.c/1.1/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/boot/pmac/CVS/Repository linux-2.4-xfs/linux/arch/ppc/boot/pmac/CVS/Repository --- linux-2.4.7/linux/arch/ppc/boot/pmac/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/pmac/CVS/Repository Thu Jul 5 11:49:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/boot/pmac diff -rNu linux-2.4.7/linux/arch/ppc/boot/pmac/CVS/Root linux-2.4-xfs/linux/arch/ppc/boot/pmac/CVS/Root --- linux-2.4.7/linux/arch/ppc/boot/pmac/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/pmac/CVS/Root Thu Jul 5 11:49:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/boot/prep/CVS/Entries linux-2.4-xfs/linux/arch/ppc/boot/prep/CVS/Entries --- linux-2.4.7/linux/arch/ppc/boot/prep/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/prep/CVS/Entries Thu Jul 5 11:49:58 2001 @@ -0,0 +1,9 @@ +/Makefile/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/head.S/1.1/Tue May 29 19:53:13 2001/-ko/ +/iso_font.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/kbd.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/misc.c/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/of1275.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/of1275.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/vreset.c/1.1/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/boot/prep/CVS/Repository linux-2.4-xfs/linux/arch/ppc/boot/prep/CVS/Repository --- linux-2.4.7/linux/arch/ppc/boot/prep/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/prep/CVS/Repository Thu Jul 5 11:49:58 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/boot/prep diff -rNu linux-2.4.7/linux/arch/ppc/boot/prep/CVS/Root linux-2.4-xfs/linux/arch/ppc/boot/prep/CVS/Root --- linux-2.4.7/linux/arch/ppc/boot/prep/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/prep/CVS/Root Thu Jul 5 11:49:58 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/boot/tree/CVS/Entries linux-2.4-xfs/linux/arch/ppc/boot/tree/CVS/Entries --- linux-2.4.7/linux/arch/ppc/boot/tree/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/tree/CVS/Entries Thu Jul 5 11:49:58 2001 @@ -0,0 +1,7 @@ +/Makefile/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/irSect.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/irSect.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/ld.script/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/main.c/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/misc.S/1.1/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/boot/tree/CVS/Repository linux-2.4-xfs/linux/arch/ppc/boot/tree/CVS/Repository --- linux-2.4.7/linux/arch/ppc/boot/tree/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/tree/CVS/Repository Thu Jul 5 11:49:58 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/boot/tree diff -rNu linux-2.4.7/linux/arch/ppc/boot/tree/CVS/Root linux-2.4-xfs/linux/arch/ppc/boot/tree/CVS/Root --- linux-2.4.7/linux/arch/ppc/boot/tree/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/tree/CVS/Root Thu Jul 5 11:49:58 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/boot/utils/CVS/Entries linux-2.4-xfs/linux/arch/ppc/boot/utils/CVS/Entries --- linux-2.4.7/linux/arch/ppc/boot/utils/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/utils/CVS/Entries Thu Jul 5 11:49:59 2001 @@ -0,0 +1,15 @@ +/Makefile/1.1/Tue May 29 19:53:13 2001/-ko/ +/addnote.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/elf.pl/1.1/Tue May 29 19:53:13 2001/-ko/ +/hack-coff.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/mkevimg/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/mkirimg/1.1/Tue May 29 19:53:13 2001/-ko/ +/mknote.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/mkprep.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/mksimage.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/offset/1.1/Tue May 29 19:53:13 2001/-ko/ +/piggyback.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/sioffset/1.1/Tue May 29 19:53:13 2001/-ko/ +/sisize/1.1/Tue May 29 19:53:13 2001/-ko/ +/size/1.1/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/boot/utils/CVS/Repository linux-2.4-xfs/linux/arch/ppc/boot/utils/CVS/Repository --- linux-2.4.7/linux/arch/ppc/boot/utils/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/utils/CVS/Repository Thu Jul 5 11:49:58 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/boot/utils diff -rNu linux-2.4.7/linux/arch/ppc/boot/utils/CVS/Root linux-2.4-xfs/linux/arch/ppc/boot/utils/CVS/Root --- linux-2.4.7/linux/arch/ppc/boot/utils/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/boot/utils/CVS/Root Thu Jul 5 11:49:58 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/configs/CVS/Entries linux-2.4-xfs/linux/arch/ppc/configs/CVS/Entries --- linux-2.4.7/linux/arch/ppc/configs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/configs/CVS/Entries Thu Jul 5 11:50:00 2001 @@ -0,0 +1,19 @@ +/IVMS8_defconfig/1.3/Tue Jun 12 04:51:00 2001/-ko/ +/SM850_defconfig/1.3/Tue Jun 12 04:51:00 2001/-ko/ +/SPD823TS_defconfig/1.3/Tue Jun 12 04:51:00 2001/-ko/ +/TQM823L_defconfig/1.3/Tue Jun 12 04:51:00 2001/-ko/ +/TQM850L_defconfig/1.3/Tue Jun 12 04:51:00 2001/-ko/ +/TQM860L_defconfig/1.3/Tue Jun 12 04:51:00 2001/-ko/ +/apus_defconfig/1.6/Tue Jun 12 04:51:00 2001/-ko/ +/bseip_defconfig/1.5/Tue Jun 12 04:51:00 2001/-ko/ +/common_defconfig/1.18/Tue Jun 12 04:51:00 2001/-ko/ +/est8260_defconfig/1.6/Tue Jun 12 04:51:00 2001/-ko/ +/gemini_defconfig/1.12/Tue Jun 12 04:51:00 2001/-ko/ +/ibmchrp_defconfig/1.3/Tue Jun 12 04:51:00 2001/-ko/ +/mbx_defconfig/1.5/Tue Jun 12 04:51:00 2001/-ko/ +/oak_defconfig/1.10/Tue Jun 12 04:51:00 2001/-ko/ +/power3_defconfig/1.3/Tue Jun 12 04:51:00 2001/-ko/ +/rpxcllf_defconfig/1.6/Tue Jun 12 04:51:00 2001/-ko/ +/rpxlite_defconfig/1.5/Tue Jun 12 04:51:00 2001/-ko/ +/walnut_defconfig/1.10/Tue Jun 12 04:51:00 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/configs/CVS/Repository linux-2.4-xfs/linux/arch/ppc/configs/CVS/Repository --- linux-2.4.7/linux/arch/ppc/configs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/configs/CVS/Repository Thu Jul 5 11:49:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/configs diff -rNu linux-2.4.7/linux/arch/ppc/configs/CVS/Root linux-2.4-xfs/linux/arch/ppc/configs/CVS/Root --- linux-2.4.7/linux/arch/ppc/configs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/configs/CVS/Root Thu Jul 5 11:49:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/configs/IVMS8_defconfig linux-2.4-xfs/linux/arch/ppc/configs/IVMS8_defconfig --- linux-2.4.7/linux/arch/ppc/configs/IVMS8_defconfig Mon May 21 19:04:46 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/IVMS8_defconfig Mon Jun 11 23:51:00 2001 @@ -476,3 +476,11 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/SM850_defconfig linux-2.4-xfs/linux/arch/ppc/configs/SM850_defconfig --- linux-2.4.7/linux/arch/ppc/configs/SM850_defconfig Mon May 21 19:04:46 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/SM850_defconfig Mon Jun 11 23:51:00 2001 @@ -444,3 +444,11 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/SPD823TS_defconfig linux-2.4-xfs/linux/arch/ppc/configs/SPD823TS_defconfig --- linux-2.4.7/linux/arch/ppc/configs/SPD823TS_defconfig Mon May 21 19:04:46 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/SPD823TS_defconfig Mon Jun 11 23:51:00 2001 @@ -443,3 +443,11 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/TQM823L_defconfig linux-2.4-xfs/linux/arch/ppc/configs/TQM823L_defconfig --- linux-2.4.7/linux/arch/ppc/configs/TQM823L_defconfig Mon May 21 19:04:46 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/TQM823L_defconfig Mon Jun 11 23:51:00 2001 @@ -444,3 +444,11 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/TQM850L_defconfig linux-2.4-xfs/linux/arch/ppc/configs/TQM850L_defconfig --- linux-2.4.7/linux/arch/ppc/configs/TQM850L_defconfig Mon May 21 19:04:46 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/TQM850L_defconfig Mon Jun 11 23:51:00 2001 @@ -444,3 +444,11 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/TQM860L_defconfig linux-2.4-xfs/linux/arch/ppc/configs/TQM860L_defconfig --- linux-2.4.7/linux/arch/ppc/configs/TQM860L_defconfig Mon May 21 19:04:46 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/TQM860L_defconfig Mon Jun 11 23:51:00 2001 @@ -444,3 +444,11 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/apus_defconfig linux-2.4-xfs/linux/arch/ppc/configs/apus_defconfig --- linux-2.4.7/linux/arch/ppc/configs/apus_defconfig Mon May 21 19:04:46 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/apus_defconfig Mon Jun 11 23:51:00 2001 @@ -790,3 +790,11 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/bseip_defconfig linux-2.4-xfs/linux/arch/ppc/configs/bseip_defconfig --- linux-2.4.7/linux/arch/ppc/configs/bseip_defconfig Mon May 21 19:04:46 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/bseip_defconfig Mon Jun 11 23:51:00 2001 @@ -441,3 +441,11 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/common_defconfig linux-2.4-xfs/linux/arch/ppc/configs/common_defconfig --- linux-2.4.7/linux/arch/ppc/configs/common_defconfig Wed May 16 11:57:20 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/common_defconfig Mon Jun 11 23:51:00 2001 @@ -860,3 +860,11 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set CONFIG_XMON=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/est8260_defconfig linux-2.4-xfs/linux/arch/ppc/configs/est8260_defconfig --- linux-2.4.7/linux/arch/ppc/configs/est8260_defconfig Mon May 21 19:04:46 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/est8260_defconfig Mon Jun 11 23:51:00 2001 @@ -416,3 +416,11 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/gemini_defconfig linux-2.4-xfs/linux/arch/ppc/configs/gemini_defconfig --- linux-2.4.7/linux/arch/ppc/configs/gemini_defconfig Mon May 21 19:04:46 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/gemini_defconfig Mon Jun 11 23:51:00 2001 @@ -507,3 +507,11 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set CONFIG_XMON=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/ibmchrp_defconfig linux-2.4-xfs/linux/arch/ppc/configs/ibmchrp_defconfig --- linux-2.4.7/linux/arch/ppc/configs/ibmchrp_defconfig Wed May 16 11:57:20 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/ibmchrp_defconfig Mon Jun 11 23:51:00 2001 @@ -663,3 +663,11 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set CONFIG_XMON=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/mbx_defconfig linux-2.4-xfs/linux/arch/ppc/configs/mbx_defconfig --- linux-2.4.7/linux/arch/ppc/configs/mbx_defconfig Mon May 21 19:04:46 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/mbx_defconfig Mon Jun 11 23:51:00 2001 @@ -434,3 +434,11 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/oak_defconfig linux-2.4-xfs/linux/arch/ppc/configs/oak_defconfig --- linux-2.4.7/linux/arch/ppc/configs/oak_defconfig Mon May 21 19:04:46 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/oak_defconfig Mon Jun 11 23:51:00 2001 @@ -396,3 +396,11 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/power3_defconfig linux-2.4-xfs/linux/arch/ppc/configs/power3_defconfig --- linux-2.4.7/linux/arch/ppc/configs/power3_defconfig Wed May 16 11:57:20 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/power3_defconfig Mon Jun 11 23:51:00 2001 @@ -684,3 +684,11 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set CONFIG_XMON=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/rpxcllf_defconfig linux-2.4-xfs/linux/arch/ppc/configs/rpxcllf_defconfig --- linux-2.4.7/linux/arch/ppc/configs/rpxcllf_defconfig Mon May 21 19:04:46 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/rpxcllf_defconfig Mon Jun 11 23:51:00 2001 @@ -442,3 +442,11 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/rpxlite_defconfig linux-2.4-xfs/linux/arch/ppc/configs/rpxlite_defconfig --- linux-2.4.7/linux/arch/ppc/configs/rpxlite_defconfig Mon May 21 19:04:46 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/rpxlite_defconfig Mon Jun 11 23:51:00 2001 @@ -439,3 +439,11 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/configs/walnut_defconfig linux-2.4-xfs/linux/arch/ppc/configs/walnut_defconfig --- linux-2.4.7/linux/arch/ppc/configs/walnut_defconfig Mon May 21 19:04:46 2001 +++ linux-2.4-xfs/linux/arch/ppc/configs/walnut_defconfig Mon Jun 11 23:51:00 2001 @@ -399,3 +399,11 @@ # CONFIG_MAGIC_SYSRQ is not set # CONFIG_KGDB is not set # CONFIG_XMON is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/defconfig linux-2.4-xfs/linux/arch/ppc/defconfig --- linux-2.4.7/linux/arch/ppc/defconfig Wed May 16 11:57:20 2001 +++ linux-2.4-xfs/linux/arch/ppc/defconfig Mon Jun 11 23:51:00 2001 @@ -857,3 +857,11 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set CONFIG_XMON=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/ppc/kernel/CVS/Entries linux-2.4-xfs/linux/arch/ppc/kernel/CVS/Entries --- linux-2.4.7/linux/arch/ppc/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/kernel/CVS/Entries Thu Jul 5 11:50:10 2001 @@ -0,0 +1,83 @@ +/Makefile/1.22/Tue Jul 3 02:33:57 2001/-ko/ +/align.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/apus_pci.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/apus_pci.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/apus_setup.c/1.15/Tue May 29 19:53:13 2001/-ko/ +/bitops.c/1.4/Tue May 29 19:53:13 2001/-ko/ +/checks.c/1.4/Tue May 29 19:53:13 2001/-ko/ +/chrp_pci.c/1.17/Tue Jul 3 02:33:57 2001/-ko/ +/chrp_setup.c/1.22/Sat Jun 9 02:44:24 2001/-ko/ +/chrp_time.c/1.9/Tue May 29 19:53:13 2001/-ko/ +/entry.S/1.20/Tue Jul 3 02:33:57 2001/-ko/ +/error_log.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/error_log.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/feature.c/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/find_name.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/galaxy_pci.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/gemini_pci.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/gemini_prom.S/1.6/Tue May 29 19:53:13 2001/-ko/ +/gemini_setup.c/1.17/Tue May 29 19:53:13 2001/-ko/ +/head.S/1.26/Tue Jul 3 02:33:57 2001/-ko/ +/head_4xx.S/1.5/Tue May 29 19:53:13 2001/-ko/ +/head_8xx.S/1.11/Tue Jul 3 02:33:57 2001/-ko/ +/i8259.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/i8259.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/idle.c/1.16/Tue May 29 19:53:13 2001/-ko/ +/indirect_pci.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/irq.c/1.29/Tue Jul 3 02:33:57 2001/-ko/ +/local_irq.h/1.9/Tue May 29 19:53:13 2001/-ko/ +/m8260_setup.c/1.8/Tue May 29 19:53:13 2001/-ko/ +/m8xx_setup.c/1.13/Tue Jul 3 02:33:57 2001/-ko/ +/misc.S/1.28/Tue Jul 3 02:33:57 2001/-ko/ +/mk_defs.c/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/oak_setup.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/oak_setup.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/open_pic.c/1.18/Tue May 29 19:53:13 2001/-ko/ +/open_pic.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/open_pic_defs.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/pci-dma.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/pci.c/1.20/Tue Jul 3 02:33:57 2001/-ko/ +/pci.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/pmac_backlight.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/pmac_nvram.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/pmac_pci.c/1.15/Thu Jul 5 05:29:17 2001/-ko/ +/pmac_pic.c/1.18/Tue May 29 19:53:13 2001/-ko/ +/pmac_pic.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/pmac_setup.c/1.21/Tue May 29 19:53:13 2001/-ko/ +/pmac_time.c/1.11/Tue May 29 19:53:13 2001/-ko/ +/ppc-stub.c/1.8/Tue May 29 19:53:13 2001/-ko/ +/ppc4xx_pic.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/ppc4xx_pic.h/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/ppc8260_pic.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/ppc8260_pic.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/ppc8xx_pic.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/ppc8xx_pic.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/ppc_asm.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/ppc_asm.tmpl/1.4/Mon Feb 14 19:32:36 2000/-ko/ +/ppc_defs.head/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ppc_htab.c/1.13/Tue Jul 3 02:33:57 2001/-ko/ +/ppc_ksyms.c/1.32/Tue Jul 3 02:33:57 2001/-ko/ +/prep_nvram.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/prep_pci.c/1.10/Thu Jun 21 15:45:04 2001/-ko/ +/prep_setup.c/1.19/Tue May 29 19:53:13 2001/-ko/ +/prep_time.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/proc_rtas.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/process.c/1.28/Tue Jul 3 02:33:57 2001/-ko/ +/prom.c/1.22/Tue Jul 3 02:33:57 2001/-ko/ +/ptrace.c/1.8/Tue May 29 19:53:13 2001/-ko/ +/qspan_pci.c/1.4/Tue May 29 19:53:13 2001/-ko/ +/residual.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/semaphore.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/setup.c/1.32/Tue Jul 3 02:33:57 2001/-ko/ +/signal.c/1.12/Tue May 29 19:53:13 2001/-ko/ +/sleep.S/1.4/Tue Jul 3 02:33:57 2001/-ko/ +/smp.c/1.25/Sat Jun 9 02:44:24 2001/-ko/ +/softemu8xx.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/syscalls.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/time.c/1.14/Sat Jun 9 02:44:24 2001/-ko/ +/traps.c/1.19/Tue Jul 3 02:33:57 2001/-ko/ +/walnut_setup.c/1.4/Tue May 29 19:53:13 2001/-ko/ +/walnut_setup.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/xics.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/xics.h/1.2/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/kernel/CVS/Repository linux-2.4-xfs/linux/arch/ppc/kernel/CVS/Repository --- linux-2.4.7/linux/arch/ppc/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/kernel/CVS/Repository Thu Jul 5 11:50:00 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/kernel diff -rNu linux-2.4.7/linux/arch/ppc/kernel/CVS/Root linux-2.4-xfs/linux/arch/ppc/kernel/CVS/Root --- linux-2.4.7/linux/arch/ppc/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/kernel/CVS/Root Thu Jul 5 11:50:00 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/lib/CVS/Entries linux-2.4-xfs/linux/arch/ppc/lib/CVS/Entries --- linux-2.4.7/linux/arch/ppc/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/lib/CVS/Entries Thu Jul 5 11:50:10 2001 @@ -0,0 +1,6 @@ +/Makefile/1.7/Tue May 29 19:53:13 2001/-ko/ +/checksum.S/1.5/Tue May 29 19:53:13 2001/-ko/ +/locks.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/strcase.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/string.S/1.6/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/lib/CVS/Repository linux-2.4-xfs/linux/arch/ppc/lib/CVS/Repository --- linux-2.4.7/linux/arch/ppc/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/lib/CVS/Repository Thu Jul 5 11:50:10 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/lib diff -rNu linux-2.4.7/linux/arch/ppc/lib/CVS/Root linux-2.4-xfs/linux/arch/ppc/lib/CVS/Root --- linux-2.4.7/linux/arch/ppc/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/lib/CVS/Root Thu Jul 5 11:50:10 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/math-emu/CVS/Entries linux-2.4-xfs/linux/arch/ppc/math-emu/CVS/Entries --- linux-2.4.7/linux/arch/ppc/math-emu/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/math-emu/CVS/Entries Thu Jul 5 11:50:12 2001 @@ -0,0 +1,54 @@ +/Makefile/1.3/Tue May 29 19:53:13 2001/-ko/ +/double.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/fabs.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fadd.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fadds.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fcmpo.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fcmpu.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fctiw.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fctiwz.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fdiv.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fdivs.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fmadd.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fmadds.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fmr.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fmsub.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fmsubs.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fmul.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fmuls.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fnabs.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fneg.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fnmadd.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fnmadds.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fnmsub.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fnmsubs.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fres.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/frsp.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/frsqrte.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fsel.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fsqrt.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fsqrts.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fsub.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fsubs.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/lfd.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/lfs.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/math.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/mcrfs.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/mffs.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/mtfsb0.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/mtfsb1.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/mtfsf.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/mtfsfi.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/op-1.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/op-2.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/op-4.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/op-common.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/sfp-machine.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/single.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/soft-fp.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/stfd.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/stfiwx.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/stfs.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/types.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/udivmodti4.c/1.2/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/math-emu/CVS/Repository linux-2.4-xfs/linux/arch/ppc/math-emu/CVS/Repository --- linux-2.4.7/linux/arch/ppc/math-emu/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/math-emu/CVS/Repository Thu Jul 5 11:50:10 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/math-emu diff -rNu linux-2.4.7/linux/arch/ppc/math-emu/CVS/Root linux-2.4-xfs/linux/arch/ppc/math-emu/CVS/Root --- linux-2.4.7/linux/arch/ppc/math-emu/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/math-emu/CVS/Root Thu Jul 5 11:50:10 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/mm/CVS/Entries linux-2.4-xfs/linux/arch/ppc/mm/CVS/Entries --- linux-2.4.7/linux/arch/ppc/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/mm/CVS/Entries Thu Jul 5 11:50:13 2001 @@ -0,0 +1,10 @@ +/4xx_tlb.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/4xx_tlb.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/Makefile/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/extable.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/fault.c/1.16/Tue Jul 3 02:33:57 2001/-ko/ +/hashtable.S/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/init.c/1.34/Tue Jul 3 02:33:57 2001/-ko/ +/mem_pieces.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/mem_pieces.h/1.3/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/mm/CVS/Repository linux-2.4-xfs/linux/arch/ppc/mm/CVS/Repository --- linux-2.4.7/linux/arch/ppc/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/mm/CVS/Repository Thu Jul 5 11:50:12 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/mm diff -rNu linux-2.4.7/linux/arch/ppc/mm/CVS/Root linux-2.4-xfs/linux/arch/ppc/mm/CVS/Root --- linux-2.4.7/linux/arch/ppc/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/mm/CVS/Root Thu Jul 5 11:50:12 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/ppc/vmlinux.lds linux-2.4-xfs/linux/arch/ppc/vmlinux.lds --- linux-2.4.7/linux/arch/ppc/vmlinux.lds Mon Jul 2 16:40:58 2001 +++ linux-2.4-xfs/linux/arch/ppc/vmlinux.lds Mon Jul 2 21:33:57 2001 @@ -70,6 +70,10 @@ __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; + __start___kallsyms = .; /* All kernel symbols */ + __kallsyms : { *(__kallsyms) } + __stop___kallsyms = .; + . = ALIGN(32); .data.cacheline_aligned : { *(.data.cacheline_aligned) } diff -rNu linux-2.4.7/linux/arch/ppc/xmon/CVS/Entries linux-2.4-xfs/linux/arch/ppc/xmon/CVS/Entries --- linux-2.4.7/linux/arch/ppc/xmon/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/xmon/CVS/Entries Thu Jul 5 11:50:15 2001 @@ -0,0 +1,14 @@ +/Makefile/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/adb.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/ansidecl.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/nonstdio.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/ppc-dis.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/ppc-opc.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/ppc.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/privinst.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/setjmp.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/start.c/1.15/Tue May 29 19:53:13 2001/-ko/ +/start_8xx.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/subr_prf.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/xmon.c/1.16/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/ppc/xmon/CVS/Repository linux-2.4-xfs/linux/arch/ppc/xmon/CVS/Repository --- linux-2.4.7/linux/arch/ppc/xmon/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/xmon/CVS/Repository Thu Jul 5 11:50:13 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/ppc/xmon diff -rNu linux-2.4.7/linux/arch/ppc/xmon/CVS/Root linux-2.4-xfs/linux/arch/ppc/xmon/CVS/Root --- linux-2.4.7/linux/arch/ppc/xmon/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/ppc/xmon/CVS/Root Thu Jul 5 11:50:13 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390/CVS/Entries linux-2.4-xfs/linux/arch/s390/CVS/Entries --- linux-2.4.7/linux/arch/s390/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/CVS/Entries Thu Jul 5 11:50:16 2001 @@ -0,0 +1,5 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/config.in/1.7/Wed May 2 06:22:13 2001/-ko/ +/defconfig/1.5/Tue Jun 12 04:51:00 2001/-ko/ +/vmlinux.lds/1.3/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/s390/CVS/Entries.Log linux-2.4-xfs/linux/arch/s390/CVS/Entries.Log --- linux-2.4.7/linux/arch/s390/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/CVS/Entries.Log Thu Jul 5 11:50:20 2001 @@ -0,0 +1,6 @@ +A D/boot//// +A D/kernel//// +A D/lib//// +A D/math-emu//// +A D/mm//// +A D/tools//// diff -rNu linux-2.4.7/linux/arch/s390/CVS/Repository linux-2.4-xfs/linux/arch/s390/CVS/Repository --- linux-2.4.7/linux/arch/s390/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/CVS/Repository Thu Jul 5 11:50:15 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390 diff -rNu linux-2.4.7/linux/arch/s390/CVS/Root linux-2.4-xfs/linux/arch/s390/CVS/Root --- linux-2.4.7/linux/arch/s390/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/CVS/Root Thu Jul 5 11:50:15 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390/boot/CVS/Entries linux-2.4-xfs/linux/arch/s390/boot/CVS/Entries --- linux-2.4.7/linux/arch/s390/boot/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/boot/CVS/Entries Thu Jul 5 11:50:16 2001 @@ -0,0 +1,5 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/ipldump.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/ipleckd.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/iplfba.S/1.1/Fri May 26 01:26:22 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/s390/boot/CVS/Repository linux-2.4-xfs/linux/arch/s390/boot/CVS/Repository --- linux-2.4.7/linux/arch/s390/boot/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/boot/CVS/Repository Thu Jul 5 11:50:16 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390/boot diff -rNu linux-2.4.7/linux/arch/s390/boot/CVS/Root linux-2.4-xfs/linux/arch/s390/boot/CVS/Root --- linux-2.4.7/linux/arch/s390/boot/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/boot/CVS/Root Thu Jul 5 11:50:16 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390/defconfig linux-2.4-xfs/linux/arch/s390/defconfig --- linux-2.4.7/linux/arch/s390/defconfig Wed Apr 11 21:02:27 2001 +++ linux-2.4-xfs/linux/arch/s390/defconfig Mon Jun 11 23:51:00 2001 @@ -244,3 +244,11 @@ # Kernel hacking # # CONFIG_MAGIC_SYSRQ is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/s390/kernel/CVS/Entries linux-2.4-xfs/linux/arch/s390/kernel/CVS/Entries --- linux-2.4.7/linux/arch/s390/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/kernel/CVS/Entries Thu Jul 5 11:50:19 2001 @@ -0,0 +1,26 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/bitmap.S/1.1/Fri May 26 01:26:22 2000/-ko/ +/cpcmd.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/debug.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/ebcdic.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/entry.S/1.9/Thu Jul 5 05:29:17 2001/-ko/ +/gdb-stub.c/1.1/Fri May 26 01:26:22 2000/-ko/ +/head.S/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/ieee.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/init_task.c/1.1/Fri May 26 01:26:22 2000/-ko/ +/irq.c/1.6/Thu Jul 5 05:29:17 2001/-ko/ +/lowcore.S/1.1/Fri May 26 01:26:22 2000/-ko/ +/process.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/ptrace.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/reipl.S/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/s390_ext.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/s390_ksyms.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/s390fpu.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/semaphore.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/signal.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/smp.c/1.6/Thu Jul 5 05:29:17 2001/-ko/ +/sys_s390.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/time.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/traps.c/1.5/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/s390/kernel/CVS/Repository linux-2.4-xfs/linux/arch/s390/kernel/CVS/Repository --- linux-2.4.7/linux/arch/s390/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/kernel/CVS/Repository Thu Jul 5 11:50:16 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390/kernel diff -rNu linux-2.4.7/linux/arch/s390/kernel/CVS/Root linux-2.4-xfs/linux/arch/s390/kernel/CVS/Root --- linux-2.4.7/linux/arch/s390/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/kernel/CVS/Root Thu Jul 5 11:50:16 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390/lib/CVS/Entries linux-2.4-xfs/linux/arch/s390/lib/CVS/Entries --- linux-2.4.7/linux/arch/s390/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/lib/CVS/Entries Thu Jul 5 11:50:19 2001 @@ -0,0 +1,9 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/checksum.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/delay.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/memset.S/1.1/Fri May 26 01:26:22 2000/-ko/ +/misaligned.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/strcmp.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/strncpy.S/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/uaccess.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/s390/lib/CVS/Repository linux-2.4-xfs/linux/arch/s390/lib/CVS/Repository --- linux-2.4.7/linux/arch/s390/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/lib/CVS/Repository Thu Jul 5 11:50:19 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390/lib diff -rNu linux-2.4.7/linux/arch/s390/lib/CVS/Root linux-2.4-xfs/linux/arch/s390/lib/CVS/Root --- linux-2.4.7/linux/arch/s390/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/lib/CVS/Root Thu Jul 5 11:50:19 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390/math-emu/CVS/Entries linux-2.4-xfs/linux/arch/s390/math-emu/CVS/Entries --- linux-2.4.7/linux/arch/s390/math-emu/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/math-emu/CVS/Entries Thu Jul 5 11:50:20 2001 @@ -0,0 +1,5 @@ +/Makefile/1.1/Wed May 2 06:22:13 2001/-ko/ +/math.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/qrnnd.S/1.1/Wed May 2 06:22:13 2001/-ko/ +/sfp-util.h/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/s390/math-emu/CVS/Repository linux-2.4-xfs/linux/arch/s390/math-emu/CVS/Repository --- linux-2.4.7/linux/arch/s390/math-emu/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/math-emu/CVS/Repository Thu Jul 5 11:50:19 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390/math-emu diff -rNu linux-2.4.7/linux/arch/s390/math-emu/CVS/Root linux-2.4-xfs/linux/arch/s390/math-emu/CVS/Root --- linux-2.4.7/linux/arch/s390/math-emu/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/math-emu/CVS/Root Thu Jul 5 11:50:19 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390/mm/CVS/Entries linux-2.4-xfs/linux/arch/s390/mm/CVS/Entries --- linux-2.4.7/linux/arch/s390/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/mm/CVS/Entries Thu Jul 5 11:50:20 2001 @@ -0,0 +1,6 @@ +/Makefile/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/extable.c/1.1/Fri May 26 01:26:22 2000/-ko/ +/fault.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/init.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/ioremap.c/1.3/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/s390/mm/CVS/Repository linux-2.4-xfs/linux/arch/s390/mm/CVS/Repository --- linux-2.4.7/linux/arch/s390/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/mm/CVS/Repository Thu Jul 5 11:50:20 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390/mm diff -rNu linux-2.4.7/linux/arch/s390/mm/CVS/Root linux-2.4-xfs/linux/arch/s390/mm/CVS/Root --- linux-2.4.7/linux/arch/s390/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/mm/CVS/Root Thu Jul 5 11:50:20 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390/tools/CVS/Entries linux-2.4-xfs/linux/arch/s390/tools/CVS/Entries --- linux-2.4.7/linux/arch/s390/tools/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/tools/CVS/Entries Thu Jul 5 11:50:20 2001 @@ -0,0 +1 @@ +D diff -rNu linux-2.4.7/linux/arch/s390/tools/CVS/Entries.Log linux-2.4-xfs/linux/arch/s390/tools/CVS/Entries.Log --- linux-2.4.7/linux/arch/s390/tools/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/tools/CVS/Entries.Log Thu Jul 5 11:50:20 2001 @@ -0,0 +1,2 @@ +A D/dasdfmt//// +A D/silo//// diff -rNu linux-2.4.7/linux/arch/s390/tools/CVS/Repository linux-2.4-xfs/linux/arch/s390/tools/CVS/Repository --- linux-2.4.7/linux/arch/s390/tools/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/tools/CVS/Repository Thu Jul 5 11:50:20 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390/tools diff -rNu linux-2.4.7/linux/arch/s390/tools/CVS/Root linux-2.4-xfs/linux/arch/s390/tools/CVS/Root --- linux-2.4.7/linux/arch/s390/tools/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/tools/CVS/Root Thu Jul 5 11:50:20 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390/tools/dasdfmt/CVS/Entries linux-2.4-xfs/linux/arch/s390/tools/dasdfmt/CVS/Entries --- linux-2.4.7/linux/arch/s390/tools/dasdfmt/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/tools/dasdfmt/CVS/Entries Thu Jul 5 11:50:20 2001 @@ -0,0 +1,4 @@ +/Makefile/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/dasdfmt.8/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/dasdfmt.c/1.4/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/s390/tools/dasdfmt/CVS/Repository linux-2.4-xfs/linux/arch/s390/tools/dasdfmt/CVS/Repository --- linux-2.4.7/linux/arch/s390/tools/dasdfmt/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/tools/dasdfmt/CVS/Repository Thu Jul 5 11:50:20 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390/tools/dasdfmt diff -rNu linux-2.4.7/linux/arch/s390/tools/dasdfmt/CVS/Root linux-2.4-xfs/linux/arch/s390/tools/dasdfmt/CVS/Root --- linux-2.4.7/linux/arch/s390/tools/dasdfmt/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/tools/dasdfmt/CVS/Root Thu Jul 5 11:50:20 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390/tools/silo/CVS/Entries linux-2.4-xfs/linux/arch/s390/tools/silo/CVS/Entries --- linux-2.4.7/linux/arch/s390/tools/silo/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/tools/silo/CVS/Entries Thu Jul 5 11:50:20 2001 @@ -0,0 +1,6 @@ +/Makefile/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/cfg.c/1.1/Fri May 26 01:26:22 2000/-ko/ +/cfg.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/silo.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/silo.conf/1.1/Fri May 26 01:26:22 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/s390/tools/silo/CVS/Repository linux-2.4-xfs/linux/arch/s390/tools/silo/CVS/Repository --- linux-2.4.7/linux/arch/s390/tools/silo/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/tools/silo/CVS/Repository Thu Jul 5 11:50:20 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390/tools/silo diff -rNu linux-2.4.7/linux/arch/s390/tools/silo/CVS/Root linux-2.4-xfs/linux/arch/s390/tools/silo/CVS/Root --- linux-2.4.7/linux/arch/s390/tools/silo/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390/tools/silo/CVS/Root Thu Jul 5 11:50:20 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390x/CVS/Entries linux-2.4-xfs/linux/arch/s390x/CVS/Entries --- linux-2.4.7/linux/arch/s390x/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/CVS/Entries Thu Jul 5 11:50:20 2001 @@ -0,0 +1,5 @@ +/Makefile/1.2/Wed Feb 28 15:36:10 2001/-ko/ +/config.in/1.2/Wed May 2 06:22:13 2001/-ko/ +/defconfig/1.3/Tue Jun 12 04:51:00 2001/-ko/ +/vmlinux.lds/1.3/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/s390x/CVS/Entries.Log linux-2.4-xfs/linux/arch/s390x/CVS/Entries.Log --- linux-2.4.7/linux/arch/s390x/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/CVS/Entries.Log Thu Jul 5 11:50:24 2001 @@ -0,0 +1,5 @@ +A D/boot//// +A D/kernel//// +A D/lib//// +A D/mm//// +A D/tools//// diff -rNu linux-2.4.7/linux/arch/s390x/CVS/Repository linux-2.4-xfs/linux/arch/s390x/CVS/Repository --- linux-2.4.7/linux/arch/s390x/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/CVS/Repository Thu Jul 5 11:50:20 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390x diff -rNu linux-2.4.7/linux/arch/s390x/CVS/Root linux-2.4-xfs/linux/arch/s390x/CVS/Root --- linux-2.4.7/linux/arch/s390x/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/CVS/Root Thu Jul 5 11:50:20 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390x/boot/CVS/Entries linux-2.4-xfs/linux/arch/s390x/boot/CVS/Entries --- linux-2.4.7/linux/arch/s390x/boot/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/boot/CVS/Entries Thu Jul 5 11:50:20 2001 @@ -0,0 +1,5 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/ipldump.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ipleckd.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/iplfba.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/s390x/boot/CVS/Repository linux-2.4-xfs/linux/arch/s390x/boot/CVS/Repository --- linux-2.4.7/linux/arch/s390x/boot/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/boot/CVS/Repository Thu Jul 5 11:50:20 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390x/boot diff -rNu linux-2.4.7/linux/arch/s390x/boot/CVS/Root linux-2.4-xfs/linux/arch/s390x/boot/CVS/Root --- linux-2.4.7/linux/arch/s390x/boot/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/boot/CVS/Root Thu Jul 5 11:50:20 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390x/defconfig linux-2.4-xfs/linux/arch/s390x/defconfig --- linux-2.4.7/linux/arch/s390x/defconfig Wed Apr 11 21:02:29 2001 +++ linux-2.4-xfs/linux/arch/s390x/defconfig Mon Jun 11 23:51:00 2001 @@ -245,3 +245,11 @@ # Kernel hacking # # CONFIG_MAGIC_SYSRQ is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/s390x/kernel/CVS/Entries linux-2.4-xfs/linux/arch/s390x/kernel/CVS/Entries --- linux-2.4.7/linux/arch/s390x/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/kernel/CVS/Entries Thu Jul 5 11:50:24 2001 @@ -0,0 +1,34 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/binfmt_elf32.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/bitmap.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/cpcmd.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/debug.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/ebcdic.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/entry.S/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/exec32.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/gdb-stub.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/head.S/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/ieee.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/init_task.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ioctl32.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/irq.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/linux32.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/linux32.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/lowcore.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/mathemu.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/process.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/ptrace.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/reipl.S/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/s390_ext.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/s390_ksyms.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/s390fpu.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/semaphore.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/signal.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/signal32.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/smp.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/sys_s390.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/time.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/traps.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/wrapper32.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/s390x/kernel/CVS/Repository linux-2.4-xfs/linux/arch/s390x/kernel/CVS/Repository --- linux-2.4.7/linux/arch/s390x/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/kernel/CVS/Repository Thu Jul 5 11:50:20 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390x/kernel diff -rNu linux-2.4.7/linux/arch/s390x/kernel/CVS/Root linux-2.4-xfs/linux/arch/s390x/kernel/CVS/Root --- linux-2.4.7/linux/arch/s390x/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/kernel/CVS/Root Thu Jul 5 11:50:20 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390x/lib/CVS/Entries linux-2.4-xfs/linux/arch/s390x/lib/CVS/Entries --- linux-2.4.7/linux/arch/s390x/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/lib/CVS/Entries Thu Jul 5 11:50:24 2001 @@ -0,0 +1,9 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/checksum.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/delay.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/memset.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/misaligned.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/strcmp.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/strncpy.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/uaccess.S/1.1/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/s390x/lib/CVS/Repository linux-2.4-xfs/linux/arch/s390x/lib/CVS/Repository --- linux-2.4.7/linux/arch/s390x/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/lib/CVS/Repository Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390x/lib diff -rNu linux-2.4.7/linux/arch/s390x/lib/CVS/Root linux-2.4-xfs/linux/arch/s390x/lib/CVS/Root --- linux-2.4.7/linux/arch/s390x/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/lib/CVS/Root Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390x/mm/CVS/Entries linux-2.4-xfs/linux/arch/s390x/mm/CVS/Entries --- linux-2.4.7/linux/arch/s390x/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/mm/CVS/Entries Thu Jul 5 11:50:24 2001 @@ -0,0 +1,6 @@ +/Makefile/1.2/Wed Feb 28 15:36:10 2001/-ko/ +/extable.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/fault.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/init.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/ioremap.c/1.2/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/s390x/mm/CVS/Repository linux-2.4-xfs/linux/arch/s390x/mm/CVS/Repository --- linux-2.4.7/linux/arch/s390x/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/mm/CVS/Repository Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390x/mm diff -rNu linux-2.4.7/linux/arch/s390x/mm/CVS/Root linux-2.4-xfs/linux/arch/s390x/mm/CVS/Root --- linux-2.4.7/linux/arch/s390x/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/mm/CVS/Root Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390x/tools/CVS/Entries linux-2.4-xfs/linux/arch/s390x/tools/CVS/Entries --- linux-2.4.7/linux/arch/s390x/tools/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/tools/CVS/Entries Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +D diff -rNu linux-2.4.7/linux/arch/s390x/tools/CVS/Entries.Log linux-2.4-xfs/linux/arch/s390x/tools/CVS/Entries.Log --- linux-2.4.7/linux/arch/s390x/tools/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/tools/CVS/Entries.Log Thu Jul 5 11:50:24 2001 @@ -0,0 +1,2 @@ +A D/dasdfmt//// +A D/silo//// diff -rNu linux-2.4.7/linux/arch/s390x/tools/CVS/Repository linux-2.4-xfs/linux/arch/s390x/tools/CVS/Repository --- linux-2.4.7/linux/arch/s390x/tools/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/tools/CVS/Repository Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390x/tools diff -rNu linux-2.4.7/linux/arch/s390x/tools/CVS/Root linux-2.4-xfs/linux/arch/s390x/tools/CVS/Root --- linux-2.4.7/linux/arch/s390x/tools/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/tools/CVS/Root Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390x/tools/dasdfmt/CVS/Entries linux-2.4-xfs/linux/arch/s390x/tools/dasdfmt/CVS/Entries --- linux-2.4.7/linux/arch/s390x/tools/dasdfmt/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/tools/dasdfmt/CVS/Entries Thu Jul 5 11:50:24 2001 @@ -0,0 +1,4 @@ +/Makefile/1.2/Wed Feb 28 15:36:10 2001/-ko/ +/dasdfmt.8/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/dasdfmt.c/1.3/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/s390x/tools/dasdfmt/CVS/Repository linux-2.4-xfs/linux/arch/s390x/tools/dasdfmt/CVS/Repository --- linux-2.4.7/linux/arch/s390x/tools/dasdfmt/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/tools/dasdfmt/CVS/Repository Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390x/tools/dasdfmt diff -rNu linux-2.4.7/linux/arch/s390x/tools/dasdfmt/CVS/Root linux-2.4-xfs/linux/arch/s390x/tools/dasdfmt/CVS/Root --- linux-2.4.7/linux/arch/s390x/tools/dasdfmt/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/tools/dasdfmt/CVS/Root Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/s390x/tools/silo/CVS/Entries linux-2.4-xfs/linux/arch/s390x/tools/silo/CVS/Entries --- linux-2.4.7/linux/arch/s390x/tools/silo/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/tools/silo/CVS/Entries Thu Jul 5 11:50:24 2001 @@ -0,0 +1,6 @@ +/Makefile/1.2/Wed Feb 28 15:36:10 2001/-ko/ +/cfg.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/cfg.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/silo.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/silo.conf/1.1/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/s390x/tools/silo/CVS/Repository linux-2.4-xfs/linux/arch/s390x/tools/silo/CVS/Repository --- linux-2.4.7/linux/arch/s390x/tools/silo/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/tools/silo/CVS/Repository Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/s390x/tools/silo diff -rNu linux-2.4.7/linux/arch/s390x/tools/silo/CVS/Root linux-2.4-xfs/linux/arch/s390x/tools/silo/CVS/Root --- linux-2.4.7/linux/arch/s390x/tools/silo/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/s390x/tools/silo/CVS/Root Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sh/CVS/Entries linux-2.4-xfs/linux/arch/sh/CVS/Entries --- linux-2.4.7/linux/arch/sh/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/CVS/Entries Thu Jul 5 11:50:24 2001 @@ -0,0 +1,5 @@ +/Makefile/1.6/Wed Jan 3 01:43:05 2001/-ko/ +/config.in/1.17/Thu Jun 28 05:21:16 2001/-ko/ +/defconfig/1.15/Tue Jun 12 04:51:00 2001/-ko/ +/vmlinux.lds.S/1.11/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sh/CVS/Entries.Log linux-2.4-xfs/linux/arch/sh/CVS/Entries.Log --- linux-2.4.7/linux/arch/sh/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/CVS/Entries.Log Thu Jul 5 11:50:26 2001 @@ -0,0 +1,5 @@ +A D/boot//// +A D/kernel//// +A D/lib//// +A D/mm//// +A D/stboards//// diff -rNu linux-2.4.7/linux/arch/sh/CVS/Repository linux-2.4-xfs/linux/arch/sh/CVS/Repository --- linux-2.4.7/linux/arch/sh/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/CVS/Repository Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sh diff -rNu linux-2.4.7/linux/arch/sh/CVS/Root linux-2.4-xfs/linux/arch/sh/CVS/Root --- linux-2.4.7/linux/arch/sh/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/CVS/Root Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sh/boot/CVS/Entries linux-2.4-xfs/linux/arch/sh/boot/CVS/Entries --- linux-2.4.7/linux/arch/sh/boot/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/boot/CVS/Entries Thu Jul 5 11:50:24 2001 @@ -0,0 +1,2 @@ +/Makefile/1.3/Mon Jul 31 16:16:28 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sh/boot/CVS/Entries.Log linux-2.4-xfs/linux/arch/sh/boot/CVS/Entries.Log --- linux-2.4.7/linux/arch/sh/boot/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/boot/CVS/Entries.Log Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +A D/compressed//// diff -rNu linux-2.4.7/linux/arch/sh/boot/CVS/Repository linux-2.4-xfs/linux/arch/sh/boot/CVS/Repository --- linux-2.4.7/linux/arch/sh/boot/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/boot/CVS/Repository Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sh/boot diff -rNu linux-2.4.7/linux/arch/sh/boot/CVS/Root linux-2.4-xfs/linux/arch/sh/boot/CVS/Root --- linux-2.4.7/linux/arch/sh/boot/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/boot/CVS/Root Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sh/boot/compressed/CVS/Entries linux-2.4-xfs/linux/arch/sh/boot/compressed/CVS/Entries --- linux-2.4.7/linux/arch/sh/boot/compressed/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/boot/compressed/CVS/Entries Thu Jul 5 11:50:24 2001 @@ -0,0 +1,5 @@ +/Makefile/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/head.S/1.4/Thu Feb 1 17:10:24 2001/-ko/ +/install.sh/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/misc.c/1.1/Mon Jul 31 16:16:28 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sh/boot/compressed/CVS/Repository linux-2.4-xfs/linux/arch/sh/boot/compressed/CVS/Repository --- linux-2.4.7/linux/arch/sh/boot/compressed/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/boot/compressed/CVS/Repository Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sh/boot/compressed diff -rNu linux-2.4.7/linux/arch/sh/boot/compressed/CVS/Root linux-2.4-xfs/linux/arch/sh/boot/compressed/CVS/Root --- linux-2.4.7/linux/arch/sh/boot/compressed/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/boot/compressed/CVS/Root Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sh/defconfig linux-2.4-xfs/linux/arch/sh/defconfig --- linux-2.4.7/linux/arch/sh/defconfig Wed Aug 9 15:59:04 2000 +++ linux-2.4-xfs/linux/arch/sh/defconfig Mon Jun 11 23:51:00 2001 @@ -204,3 +204,11 @@ CONFIG_DEBUG_KERNEL_WITH_GDB_STUB=y CONFIG_GDB_STUB_VBR=a0000000 CONFIG_SH_EARLY_PRINTK=y + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/sh/kernel/CVS/Entries linux-2.4-xfs/linux/arch/sh/kernel/CVS/Entries --- linux-2.4.7/linux/arch/sh/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/kernel/CVS/Entries Thu Jul 5 11:50:26 2001 @@ -0,0 +1,59 @@ +/Makefile/1.12/Thu Jun 28 05:21:16 2001/-ko/ +/cf-enabler.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/entry.S/1.18/Thu Jun 28 05:21:16 2001/-ko/ +/fpu.c/1.4/Thu Feb 1 17:10:24 2001/-ko/ +/hd64465_gpio.c/1.3/Thu Jun 28 05:21:16 2001/-ko/ +/head.S/1.8/Thu Feb 1 17:10:24 2001/-ko/ +/init_task.c/1.1/Mon Sep 6 21:12:40 1999/-ko/ +/io.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/io_bigsur.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/io_cat68701.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/io_dc.c/1.3/Thu Jun 28 05:21:16 2001/-ko/ +/io_ec3104.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/io_generic.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/io_hd64461.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/io_hd64465.c/1.2/Thu Jun 28 05:21:16 2001/-ko/ +/io_se.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/io_sh2000.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/io_unknown.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/irq.c/1.11/Thu Jun 28 05:21:16 2001/-ko/ +/irq_imask.c/1.6/Thu Feb 1 17:10:24 2001/-ko/ +/irq_intc2.c/1.3/Thu Jun 28 05:21:16 2001/-ko/ +/irq_ipr.c/1.5/Thu Jun 28 05:21:16 2001/-ko/ +/led_bigsur.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/led_se.c/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/mach_bigsur.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/mach_cat68701.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/mach_dc.c/1.3/Thu Jun 28 05:21:16 2001/-ko/ +/mach_dmida.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/mach_ec3104.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/mach_hp600.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/mach_se.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/mach_unknown.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/pci-7751se.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/pci-bigsur.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/pci-dc.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/pci-dma.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/pci-sh7751.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/pci_st40.c/1.2/Thu Jun 28 05:21:16 2001/-ko/ +/pci_st40.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/process.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/ptrace.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/rtc.c/1.4/Thu Jun 28 05:21:16 2001/-ko/ +/semaphore.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.15/Thu Jun 28 05:21:16 2001/-ko/ +/setup_bigsur.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/setup_cqreek.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/setup_dc.c/1.3/Thu Jun 28 05:21:16 2001/-ko/ +/setup_ec3104.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/setup_hd64461.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/setup_hd64465.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/setup_se.c/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/setup_sh2000.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/sh_bios.c/1.4/Thu Feb 1 17:10:24 2001/-ko/ +/sh_ksyms.c/1.9/Thu Jun 28 05:21:16 2001/-ko/ +/signal.c/1.11/Thu Feb 1 17:10:24 2001/-ko/ +/sys_sh.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/time.c/1.15/Thu Jun 28 05:21:16 2001/-ko/ +/traps.c/1.9/Thu Feb 1 17:10:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sh/kernel/CVS/Repository linux-2.4-xfs/linux/arch/sh/kernel/CVS/Repository --- linux-2.4.7/linux/arch/sh/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/kernel/CVS/Repository Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sh/kernel diff -rNu linux-2.4.7/linux/arch/sh/kernel/CVS/Root linux-2.4-xfs/linux/arch/sh/kernel/CVS/Root --- linux-2.4.7/linux/arch/sh/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/kernel/CVS/Root Thu Jul 5 11:50:24 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sh/lib/CVS/Entries linux-2.4-xfs/linux/arch/sh/lib/CVS/Entries --- linux-2.4.7/linux/arch/sh/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/lib/CVS/Entries Thu Jul 5 11:50:26 2001 @@ -0,0 +1,10 @@ +/Makefile/1.6/Wed Jan 3 01:43:05 2001/-ko/ +/checksum.S/1.6/Thu Feb 1 17:10:24 2001/-ko/ +/delay.c/1.3/Thu Feb 1 17:10:24 2001/-ko/ +/memchr.S/1.1/Fri Oct 29 00:22:42 1999/-ko/ +/memcpy.S/1.2/Sat Oct 23 02:00:20 1999/-ko/ +/memmove.S/1.2/Sat Oct 23 02:00:20 1999/-ko/ +/memset.S/1.2/Sat Oct 23 02:00:20 1999/-ko/ +/old-checksum.c/1.2/Sat Oct 23 02:00:20 1999/-ko/ +/strcasecmp.c/1.1/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sh/lib/CVS/Repository linux-2.4-xfs/linux/arch/sh/lib/CVS/Repository --- linux-2.4.7/linux/arch/sh/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/lib/CVS/Repository Thu Jul 5 11:50:26 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sh/lib diff -rNu linux-2.4.7/linux/arch/sh/lib/CVS/Root linux-2.4-xfs/linux/arch/sh/lib/CVS/Root --- linux-2.4.7/linux/arch/sh/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/lib/CVS/Root Thu Jul 5 11:50:26 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sh/mm/CVS/Entries linux-2.4-xfs/linux/arch/sh/mm/CVS/Entries --- linux-2.4.7/linux/arch/sh/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/mm/CVS/Entries Thu Jul 5 11:50:26 2001 @@ -0,0 +1,7 @@ +/Makefile/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/cache.c/1.12/Thu Jun 28 05:21:16 2001/-ko/ +/extable.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/fault.c/1.15/Thu Jun 28 05:21:16 2001/-ko/ +/init.c/1.14/Thu Jun 28 05:21:16 2001/-ko/ +/ioremap.c/1.6/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sh/mm/CVS/Repository linux-2.4-xfs/linux/arch/sh/mm/CVS/Repository --- linux-2.4.7/linux/arch/sh/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/mm/CVS/Repository Thu Jul 5 11:50:26 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sh/mm diff -rNu linux-2.4.7/linux/arch/sh/mm/CVS/Root linux-2.4-xfs/linux/arch/sh/mm/CVS/Root --- linux-2.4.7/linux/arch/sh/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/mm/CVS/Root Thu Jul 5 11:50:26 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sh/stboards/CVS/Entries linux-2.4-xfs/linux/arch/sh/stboards/CVS/Entries --- linux-2.4.7/linux/arch/sh/stboards/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/stboards/CVS/Entries Thu Jul 5 11:50:26 2001 @@ -0,0 +1,8 @@ +/Makefile/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/harp.h/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/irq.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/led.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/mach.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/pcidma.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/setup.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sh/stboards/CVS/Repository linux-2.4-xfs/linux/arch/sh/stboards/CVS/Repository --- linux-2.4.7/linux/arch/sh/stboards/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/stboards/CVS/Repository Thu Jul 5 11:50:26 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sh/stboards diff -rNu linux-2.4.7/linux/arch/sh/stboards/CVS/Root linux-2.4-xfs/linux/arch/sh/stboards/CVS/Root --- linux-2.4.7/linux/arch/sh/stboards/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sh/stboards/CVS/Root Thu Jul 5 11:50:26 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sparc/CVS/Entries linux-2.4-xfs/linux/arch/sparc/CVS/Entries --- linux-2.4.7/linux/arch/sparc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/CVS/Entries Thu Jul 5 11:50:27 2001 @@ -0,0 +1,5 @@ +/Makefile/1.8/Thu Dec 21 05:48:12 2000/-ko/ +/config.in/1.30/Sat Jun 9 02:44:24 2001/-ko/ +/defconfig/1.23/Tue Jun 12 04:51:00 2001/-ko/ +/vmlinux.lds/1.9/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sparc/CVS/Entries.Log linux-2.4-xfs/linux/arch/sparc/CVS/Entries.Log --- linux-2.4.7/linux/arch/sparc/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/CVS/Entries.Log Thu Jul 5 11:50:40 2001 @@ -0,0 +1,6 @@ +A D/boot//// +A D/kernel//// +A D/lib//// +A D/math-emu//// +A D/mm//// +A D/prom//// diff -rNu linux-2.4.7/linux/arch/sparc/CVS/Repository linux-2.4-xfs/linux/arch/sparc/CVS/Repository --- linux-2.4.7/linux/arch/sparc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/CVS/Repository Thu Jul 5 11:50:26 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sparc diff -rNu linux-2.4.7/linux/arch/sparc/CVS/Root linux-2.4-xfs/linux/arch/sparc/CVS/Root --- linux-2.4.7/linux/arch/sparc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/CVS/Root Thu Jul 5 11:50:26 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sparc/boot/CVS/Entries linux-2.4-xfs/linux/arch/sparc/boot/CVS/Entries --- linux-2.4.7/linux/arch/sparc/boot/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/boot/CVS/Entries Thu Jul 5 11:50:27 2001 @@ -0,0 +1,4 @@ +/Makefile/1.3/Sun Feb 27 23:15:45 2000/-ko/ +/btfixupprep.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/piggyback.c/1.4/Sun Dec 17 19:15:00 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sparc/boot/CVS/Repository linux-2.4-xfs/linux/arch/sparc/boot/CVS/Repository --- linux-2.4.7/linux/arch/sparc/boot/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/boot/CVS/Repository Thu Jul 5 11:50:27 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sparc/boot diff -rNu linux-2.4.7/linux/arch/sparc/boot/CVS/Root linux-2.4-xfs/linux/arch/sparc/boot/CVS/Root --- linux-2.4.7/linux/arch/sparc/boot/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/boot/CVS/Root Thu Jul 5 11:50:27 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sparc/defconfig linux-2.4-xfs/linux/arch/sparc/defconfig --- linux-2.4.7/linux/arch/sparc/defconfig Wed May 16 12:31:27 2001 +++ linux-2.4-xfs/linux/arch/sparc/defconfig Mon Jun 11 23:51:00 2001 @@ -380,3 +380,11 @@ # Kernel hacking # # CONFIG_MAGIC_SYSRQ is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/sparc/kernel/CVS/Entries linux-2.4-xfs/linux/arch/sparc/kernel/CVS/Entries --- linux-2.4.7/linux/arch/sparc/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/kernel/CVS/Entries Thu Jul 5 11:50:33 2001 @@ -0,0 +1,48 @@ +/Makefile/1.13/Thu Dec 21 05:48:12 2000/-ko/ +/auxio.c/1.4/Wed Dec 29 19:04:31 1999/-ko/ +/check_asm.sh/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/cpu.c/1.4/Tue May 2 21:09:12 2000/-ko/ +/devices.c/1.3/Mon Sep 6 21:12:40 1999/-ko/ +/ebus.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/entry.S/1.10/Thu Feb 1 17:10:24 2001/-ko/ +/errtbls.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/etrap.S/1.4/Tue Jan 11 18:48:48 2000/-ko/ +/head.S/1.9/Tue May 29 19:53:13 2001/-ko/ +/idprom.c/1.3/Mon Sep 6 21:12:40 1999/-ko/ +/init_task.c/1.3/Fri Aug 27 23:14:48 1999/-ko/ +/ioport.c/1.18/Thu Feb 22 21:09:04 2001/-ko/ +/irq.c/1.16/Tue May 29 19:53:13 2001/-ko/ +/muldiv.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/pcic.c/1.16/Thu Feb 22 21:09:04 2001/-ko/ +/process.c/1.18/Thu Feb 22 21:09:04 2001/-ko/ +/ptrace.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/rtrap.S/1.7/Wed Jun 13 03:24:09 2001/-ko/ +/sclow.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/semaphore.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/setup.c/1.18/Wed May 2 06:22:13 2001/-ko/ +/signal.c/1.18/Thu Feb 1 17:10:24 2001/-ko/ +/smp.c/1.13/Fri Jan 5 18:42:30 2001/-ko/ +/sparc-stub.c/1.7/Wed Nov 1 21:35:42 2000/-ko/ +/sparc_ksyms.c/1.24/Thu Feb 1 17:10:24 2001/-ko/ +/sun4c_irq.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/sun4d_irq.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/sun4d_smp.c/1.16/Thu Feb 22 21:09:04 2001/-ko/ +/sun4m_irq.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/sun4m_smp.c/1.16/Thu Feb 22 21:09:04 2001/-ko/ +/sun4setup.c/1.3/Mon Sep 6 21:12:40 1999/-ko/ +/sunos_asm.S/1.3/Fri Jan 21 19:18:03 2000/-ko/ +/sunos_ioctl.c/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/sys_solaris.c/1.7/Thu Sep 28 22:42:39 2000/-ko/ +/sys_sparc.c/1.14/Wed May 2 06:22:13 2001/-ko/ +/sys_sunos.c/1.29/Tue May 29 19:53:13 2001/-ko/ +/systbls.S/1.16/Thu Feb 1 04:38:20 2001/-ko/ +/tadpole.c/1.3/Mon Sep 6 21:12:40 1999/-ko/ +/tick14.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/time.c/1.13/Thu Feb 1 17:10:24 2001/-ko/ +/trampoline.S/1.3/Sun Aug 29 02:07:15 1999/-ko/ +/traps.c/1.8/Thu Sep 28 22:42:39 2000/-ko/ +/unaligned.c/1.6/Fri May 26 01:14:50 2000/-ko/ +/windows.c/1.3/Mon Sep 6 21:12:40 1999/-ko/ +/wof.S/1.4/Tue Jan 11 18:48:48 2000/-ko/ +/wuf.S/1.4/Tue Jan 11 18:48:48 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sparc/kernel/CVS/Repository linux-2.4-xfs/linux/arch/sparc/kernel/CVS/Repository --- linux-2.4.7/linux/arch/sparc/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/kernel/CVS/Repository Thu Jul 5 11:50:27 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sparc/kernel diff -rNu linux-2.4.7/linux/arch/sparc/kernel/CVS/Root linux-2.4-xfs/linux/arch/sparc/kernel/CVS/Root --- linux-2.4.7/linux/arch/sparc/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/kernel/CVS/Root Thu Jul 5 11:50:27 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sparc/lib/CVS/Entries linux-2.4-xfs/linux/arch/sparc/lib/CVS/Entries --- linux-2.4.7/linux/arch/sparc/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/lib/CVS/Entries Thu Jul 5 11:50:36 2001 @@ -0,0 +1,31 @@ +/COPYING.LIB/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Makefile/1.10/Thu Dec 21 05:48:12 2000/-ko/ +/ashldi3.S/1.1/Wed Dec 29 19:04:31 1999/-ko/ +/ashrdi3.S/1.3/Wed Dec 29 19:04:31 1999/-ko/ +/atomic.S/1.4/Fri May 26 01:14:50 2000/-ko/ +/bitops.S/1.4/Fri May 26 01:14:50 2000/-ko/ +/blockops.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/checksum.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/copy_user.S/1.4/Tue May 2 21:09:12 2000/-ko/ +/debuglocks.c/1.5/Wed Sep 15 22:45:13 1999/-ko/ +/divdi3.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/locks.S/1.3/Sun Feb 27 23:15:45 2000/-ko/ +/lshrdi3.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/memcmp.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/memcpy.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/memscan.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/memset.S/1.4/Wed May 2 06:22:13 2001/-ko/ +/mul.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/muldi3.S/1.1/Mon Mar 20 17:58:41 2000/-ko/ +/rem.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/rwsem.S/1.5/Fri May 26 01:52:46 2000/-ko/ +/sdiv.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/strlen.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/strlen_user.S/1.3/Wed Dec 29 19:04:31 1999/-ko/ +/strncmp.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/strncpy_from_user.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/udiv.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/udivdi3.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/umul.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/urem.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sparc/lib/CVS/Repository linux-2.4-xfs/linux/arch/sparc/lib/CVS/Repository --- linux-2.4.7/linux/arch/sparc/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/lib/CVS/Repository Thu Jul 5 11:50:33 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sparc/lib diff -rNu linux-2.4.7/linux/arch/sparc/lib/CVS/Root linux-2.4-xfs/linux/arch/sparc/lib/CVS/Root --- linux-2.4.7/linux/arch/sparc/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/lib/CVS/Root Thu Jul 5 11:50:33 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sparc/math-emu/CVS/Entries linux-2.4-xfs/linux/arch/sparc/math-emu/CVS/Entries --- linux-2.4.7/linux/arch/sparc/math-emu/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/math-emu/CVS/Entries Thu Jul 5 11:50:36 2001 @@ -0,0 +1,5 @@ +/Makefile/1.7/Thu Dec 21 05:48:12 2000/-ko/ +/ashldi3.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/math.c/1.4/Tue Dec 7 03:15:49 1999/-ko/ +/sfp-util.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sparc/math-emu/CVS/Repository linux-2.4-xfs/linux/arch/sparc/math-emu/CVS/Repository --- linux-2.4.7/linux/arch/sparc/math-emu/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/math-emu/CVS/Repository Thu Jul 5 11:50:36 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sparc/math-emu diff -rNu linux-2.4.7/linux/arch/sparc/math-emu/CVS/Root linux-2.4-xfs/linux/arch/sparc/math-emu/CVS/Root --- linux-2.4.7/linux/arch/sparc/math-emu/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/math-emu/CVS/Root Thu Jul 5 11:50:36 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sparc/mm/CVS/Entries linux-2.4-xfs/linux/arch/sparc/mm/CVS/Entries --- linux-2.4.7/linux/arch/sparc/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/mm/CVS/Entries Thu Jul 5 11:50:40 2001 @@ -0,0 +1,18 @@ +/Makefile/1.8/Thu Dec 21 05:48:12 2000/-ko/ +/btfixup.c/1.6/Fri May 26 01:52:46 2000/-ko/ +/extable.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fault.c/1.14/Mon Apr 2 17:13:32 2001/-ko/ +/generic.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/hypersparc.S/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/init.c/1.24/Wed May 2 06:22:13 2001/-ko/ +/io-unit.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/iommu.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/loadmmu.c/1.7/Fri Feb 11 00:16:16 2000/-ko/ +/nosrmmu.c/1.4/Wed Dec 29 19:04:31 1999/-ko/ +/nosun4c.c/1.4/Wed Feb 23 18:35:06 2000/-ko/ +/srmmu.c/1.24/Wed May 2 06:22:13 2001/-ko/ +/sun4c.c/1.26/Wed May 2 06:22:13 2001/-ko/ +/swift.S/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/tsunami.S/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/viking.S/1.7/Mon Jul 31 16:16:28 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sparc/mm/CVS/Repository linux-2.4-xfs/linux/arch/sparc/mm/CVS/Repository --- linux-2.4.7/linux/arch/sparc/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/mm/CVS/Repository Thu Jul 5 11:50:36 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sparc/mm diff -rNu linux-2.4.7/linux/arch/sparc/mm/CVS/Root linux-2.4-xfs/linux/arch/sparc/mm/CVS/Root --- linux-2.4.7/linux/arch/sparc/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/mm/CVS/Root Thu Jul 5 11:50:36 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sparc/prom/CVS/Entries linux-2.4-xfs/linux/arch/sparc/prom/CVS/Entries --- linux-2.4.7/linux/arch/sparc/prom/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/prom/CVS/Entries Thu Jul 5 11:50:40 2001 @@ -0,0 +1,16 @@ +/Makefile/1.5/Thu Dec 21 05:48:12 2000/-ko/ +/bootstr.c/1.5/Fri Feb 11 00:16:16 2000/-ko/ +/console.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/devmap.c/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/devops.c/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/init.c/1.4/Tue Feb 1 23:02:54 2000/-ko/ +/memory.c/1.4/Tue Feb 1 23:02:54 2000/-ko/ +/misc.c/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/mp.c/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/palloc.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/printf.c/1.4/Fri Feb 11 00:16:16 2000/-ko/ +/ranges.c/1.4/Wed Dec 29 19:04:31 1999/-ko/ +/segment.c/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/sun4prom.c/1.3/Mon Sep 6 21:12:40 1999/-ko/ +/tree.c/1.3/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sparc/prom/CVS/Repository linux-2.4-xfs/linux/arch/sparc/prom/CVS/Repository --- linux-2.4.7/linux/arch/sparc/prom/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/prom/CVS/Repository Thu Jul 5 11:50:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sparc/prom diff -rNu linux-2.4.7/linux/arch/sparc/prom/CVS/Root linux-2.4-xfs/linux/arch/sparc/prom/CVS/Root --- linux-2.4.7/linux/arch/sparc/prom/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc/prom/CVS/Root Thu Jul 5 11:50:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sparc64/CVS/Entries linux-2.4-xfs/linux/arch/sparc64/CVS/Entries --- linux-2.4.7/linux/arch/sparc64/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/CVS/Entries Thu Jul 5 11:50:41 2001 @@ -0,0 +1,5 @@ +/Makefile/1.10/Thu Dec 21 05:48:12 2000/-ko/ +/config.in/1.40/Thu Jun 28 05:21:16 2001/-ko/ +/defconfig/1.39/Mon Jul 2 15:59:04 2001/-ko/ +/vmlinux.lds/1.9/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sparc64/CVS/Entries.Log linux-2.4-xfs/linux/arch/sparc64/CVS/Entries.Log --- linux-2.4.7/linux/arch/sparc64/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/CVS/Entries.Log Thu Jul 5 11:50:56 2001 @@ -0,0 +1,7 @@ +A D/boot//// +A D/kernel//// +A D/lib//// +A D/math-emu//// +A D/mm//// +A D/prom//// +A D/solaris//// diff -rNu linux-2.4.7/linux/arch/sparc64/CVS/Repository linux-2.4-xfs/linux/arch/sparc64/CVS/Repository --- linux-2.4.7/linux/arch/sparc64/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/CVS/Repository Thu Jul 5 11:50:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sparc64 diff -rNu linux-2.4.7/linux/arch/sparc64/CVS/Root linux-2.4-xfs/linux/arch/sparc64/CVS/Root --- linux-2.4.7/linux/arch/sparc64/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/CVS/Root Thu Jul 5 11:50:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sparc64/boot/CVS/Entries linux-2.4-xfs/linux/arch/sparc64/boot/CVS/Entries --- linux-2.4.7/linux/arch/sparc64/boot/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/boot/CVS/Entries Thu Jul 5 11:50:41 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/piggyback.c/1.3/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sparc64/boot/CVS/Repository linux-2.4-xfs/linux/arch/sparc64/boot/CVS/Repository --- linux-2.4.7/linux/arch/sparc64/boot/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/boot/CVS/Repository Thu Jul 5 11:50:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sparc64/boot diff -rNu linux-2.4.7/linux/arch/sparc64/boot/CVS/Root linux-2.4-xfs/linux/arch/sparc64/boot/CVS/Root --- linux-2.4.7/linux/arch/sparc64/boot/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/boot/CVS/Root Thu Jul 5 11:50:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sparc64/defconfig linux-2.4-xfs/linux/arch/sparc64/defconfig --- linux-2.4.7/linux/arch/sparc64/defconfig Fri Jun 29 21:38:26 2001 +++ linux-2.4-xfs/linux/arch/sparc64/defconfig Mon Jul 2 10:59:04 2001 @@ -765,3 +765,11 @@ # Kernel hacking # # CONFIG_MAGIC_SYSRQ is not set + +# +# XFS addons +# +CONFIG_FS_POSIX_ACL=y +CONFIG_PAGE_BUF=y +CONFIG_XFS_FS=y +CONFIG_XFS_DMAPI=y diff -rNu linux-2.4.7/linux/arch/sparc64/kernel/CVS/Entries linux-2.4-xfs/linux/arch/sparc64/kernel/CVS/Entries --- linux-2.4.7/linux/arch/sparc64/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/kernel/CVS/Entries Thu Jul 5 11:50:50 2001 @@ -0,0 +1,56 @@ +/Makefile/1.19/Tue May 29 19:53:13 2001/-ko/ +/auxio.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/binfmt_aout32.c/1.15/Mon Apr 2 17:13:32 2001/-ko/ +/binfmt_elf32.c/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/central.c/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/check_asm.sh/1.5/Wed May 2 06:22:13 2001/-ko/ +/chmc.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/cpu.c/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/devices.c/1.10/Wed Jun 13 03:24:09 2001/-ko/ +/dtlb_backend.S/1.4/Tue Feb 1 23:02:54 2000/-ko/ +/dtlb_base.S/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/dtlb_prot.S/1.6/Wed May 2 06:22:13 2001/-ko/ +/ebus.c/1.13/Wed Jun 13 03:24:09 2001/-ko/ +/entry.S/1.13/Wed May 2 06:22:13 2001/-ko/ +/etrap.S/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/head.S/1.8/Wed May 2 06:22:13 2001/-ko/ +/idprom.c/1.3/Mon Sep 6 21:12:40 1999/-ko/ +/init_task.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/ioctl32.c/1.35/Sat Jun 9 02:44:24 2001/-ko/ +/iommu_common.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/iommu_common.h/1.1/Wed Dec 29 19:04:31 1999/-ko/ +/irq.c/1.19/Sat Jun 9 02:44:24 2001/-ko/ +/isa.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/itlb_base.S/1.5/Sat Nov 25 08:05:45 2000/-ko/ +/pci.c/1.21/Thu Jun 21 15:45:04 2001/-ko/ +/pci_common.c/1.13/Mon Jul 2 15:59:04 2001/-ko/ +/pci_impl.h/1.8/Thu Jun 21 15:45:04 2001/-ko/ +/pci_iommu.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/pci_psycho.c/1.19/Thu Jun 21 15:45:04 2001/-ko/ +/pci_sabre.c/1.22/Thu Jun 21 15:45:04 2001/-ko/ +/pci_schizo.c/1.7/Thu Jun 21 15:45:04 2001/-ko/ +/power.c/1.6/Wed Jun 13 03:24:09 2001/-ko/ +/process.c/1.20/Sat Jun 9 02:44:24 2001/-ko/ +/ptrace.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/rtrap.S/1.8/Wed Jun 13 03:24:09 2001/-ko/ +/sbus.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/semaphore.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/setup.c/1.19/Sat Jun 9 02:44:24 2001/-ko/ +/signal.c/1.15/Mon Apr 2 17:13:32 2001/-ko/ +/signal32.c/1.17/Wed May 2 06:22:13 2001/-ko/ +/smp.c/1.23/Wed May 2 06:22:13 2001/-ko/ +/sparc64_ksyms.c/1.29/Sat Jun 9 02:44:24 2001/-ko/ +/starfire.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/sunos_ioctl32.c/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/sys32.S/1.5/Fri Apr 21 16:00:46 2000/-ko/ +/sys_sparc.c/1.20/Wed May 2 06:22:13 2001/-ko/ +/sys_sparc32.c/1.36/Thu Jun 21 15:45:04 2001/-ko/ +/sys_sunos32.c/1.30/Tue May 29 19:53:13 2001/-ko/ +/systbls.S/1.19/Thu Feb 1 04:38:20 2001/-ko/ +/time.c/1.14/Wed Jun 13 03:24:09 2001/-ko/ +/trampoline.S/1.7/Wed May 2 06:22:13 2001/-ko/ +/traps.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/ttable.S/1.8/Wed May 2 06:22:13 2001/-ko/ +/unaligned.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/winfixup.S/1.4/Fri Apr 21 16:00:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sparc64/kernel/CVS/Repository linux-2.4-xfs/linux/arch/sparc64/kernel/CVS/Repository --- linux-2.4.7/linux/arch/sparc64/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/kernel/CVS/Repository Thu Jul 5 11:50:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sparc64/kernel diff -rNu linux-2.4.7/linux/arch/sparc64/kernel/CVS/Root linux-2.4-xfs/linux/arch/sparc64/kernel/CVS/Root --- linux-2.4.7/linux/arch/sparc64/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/kernel/CVS/Root Thu Jul 5 11:50:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sparc64/kernel/ioctl32.c linux-2.4-xfs/linux/arch/sparc64/kernel/ioctl32.c --- linux-2.4.7/linux/arch/sparc64/kernel/ioctl32.c Mon Jun 11 21:15:27 2001 +++ linux-2.4-xfs/linux/arch/sparc64/kernel/ioctl32.c Fri Jun 8 21:44:24 2001 @@ -3204,6 +3204,8 @@ COMPATIBLE_IOCTL(BLKFRASET) COMPATIBLE_IOCTL(BLKSECTSET) COMPATIBLE_IOCTL(BLKSSZGET) +COMPATIBLE_IOCTL(BLKBSZGET) +COMPATIBLE_IOCTL(BLKBSZSET) /* RAID */ COMPATIBLE_IOCTL(RAID_VERSION) diff -rNu linux-2.4.7/linux/arch/sparc64/lib/CVS/Entries linux-2.4-xfs/linux/arch/sparc64/lib/CVS/Entries --- linux-2.4.7/linux/arch/sparc64/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/lib/CVS/Entries Thu Jul 5 11:50:54 2001 @@ -0,0 +1,28 @@ +/Makefile/1.9/Thu Dec 21 05:48:12 2000/-ko/ +/PeeCeeI.c/1.3/Wed Sep 15 22:45:13 1999/-ko/ +/U3copy_from_user.S/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/U3copy_in_user.S/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/U3copy_to_user.S/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/U3memcpy.S/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/VIS.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/VISbzero.S/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/VIScopy.S/1.6/Sat Nov 25 08:05:45 2000/-ko/ +/VIScsum.S/1.4/Sun Feb 27 23:15:45 2000/-ko/ +/VIScsumcopy.S/1.4/Sun Feb 27 23:15:45 2000/-ko/ +/VIScsumcopyusr.S/1.2/Sun Feb 27 23:15:45 2000/-ko/ +/VISmemset.S/1.3/Thu Jan 6 19:50:16 2000/-ko/ +/VISsave.S/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/atomic.S/1.3/Mon Mar 20 17:58:41 2000/-ko/ +/bitops.S/1.2/Wed May 2 06:22:13 2001/-ko/ +/blockops.S/1.11/Wed May 2 06:22:13 2001/-ko/ +/checksum.S/1.4/Sat Jan 29 23:00:52 2000/-ko/ +/debuglocks.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/dec_and_lock.S/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/memcmp.S/1.3/Fri Mar 24 21:14:53 2000/-ko/ +/memscan.S/1.3/Tue Feb 1 23:02:54 2000/-ko/ +/rwlock.S/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/strlen.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/strlen_user.S/1.3/Wed Dec 29 19:04:31 1999/-ko/ +/strncmp.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/strncpy_from_user.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sparc64/lib/CVS/Repository linux-2.4-xfs/linux/arch/sparc64/lib/CVS/Repository --- linux-2.4.7/linux/arch/sparc64/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/lib/CVS/Repository Thu Jul 5 11:50:50 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sparc64/lib diff -rNu linux-2.4.7/linux/arch/sparc64/lib/CVS/Root linux-2.4-xfs/linux/arch/sparc64/lib/CVS/Root --- linux-2.4.7/linux/arch/sparc64/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/lib/CVS/Root Thu Jul 5 11:50:50 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sparc64/math-emu/CVS/Entries linux-2.4-xfs/linux/arch/sparc64/math-emu/CVS/Entries --- linux-2.4.7/linux/arch/sparc64/math-emu/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/math-emu/CVS/Entries Thu Jul 5 11:50:54 2001 @@ -0,0 +1,4 @@ +/Makefile/1.5/Thu Dec 21 05:48:12 2000/-ko/ +/math.c/1.6/Wed Dec 29 19:04:31 1999/-ko/ +/sfp-util.h/1.3/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sparc64/math-emu/CVS/Repository linux-2.4-xfs/linux/arch/sparc64/math-emu/CVS/Repository --- linux-2.4.7/linux/arch/sparc64/math-emu/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/math-emu/CVS/Repository Thu Jul 5 11:50:54 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sparc64/math-emu diff -rNu linux-2.4.7/linux/arch/sparc64/math-emu/CVS/Root linux-2.4-xfs/linux/arch/sparc64/math-emu/CVS/Root --- linux-2.4.7/linux/arch/sparc64/math-emu/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/math-emu/CVS/Root Thu Jul 5 11:50:54 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sparc64/mm/CVS/Entries linux-2.4-xfs/linux/arch/sparc64/mm/CVS/Entries --- linux-2.4.7/linux/arch/sparc64/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/mm/CVS/Entries Thu Jul 5 11:50:55 2001 @@ -0,0 +1,8 @@ +/Makefile/1.6/Thu Dec 21 05:48:12 2000/-ko/ +/extable.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fault.c/1.15/Mon Apr 2 17:13:32 2001/-ko/ +/generic.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/init.c/1.25/Tue May 29 19:53:13 2001/-ko/ +/modutil.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/ultra.S/1.15/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sparc64/mm/CVS/Repository linux-2.4-xfs/linux/arch/sparc64/mm/CVS/Repository --- linux-2.4.7/linux/arch/sparc64/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/mm/CVS/Repository Thu Jul 5 11:50:54 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sparc64/mm diff -rNu linux-2.4.7/linux/arch/sparc64/mm/CVS/Root linux-2.4-xfs/linux/arch/sparc64/mm/CVS/Root --- linux-2.4.7/linux/arch/sparc64/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/mm/CVS/Root Thu Jul 5 11:50:54 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sparc64/prom/CVS/Entries linux-2.4-xfs/linux/arch/sparc64/prom/CVS/Entries --- linux-2.4.7/linux/arch/sparc64/prom/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/prom/CVS/Entries Thu Jul 5 11:50:56 2001 @@ -0,0 +1,12 @@ +/Makefile/1.7/Thu Dec 21 05:48:12 2000/-ko/ +/bootstr.c/1.3/Mon Sep 6 21:12:40 1999/-ko/ +/console.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/devops.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/init.c/1.4/Wed Dec 29 19:04:31 1999/-ko/ +/map.S/1.1/Wed Dec 29 19:04:31 1999/-ko/ +/memory.c/1.3/Mon Sep 6 21:12:40 1999/-ko/ +/misc.c/1.8/Mon Jul 31 16:16:28 2000/-ko/ +/p1275.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/printf.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/tree.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sparc64/prom/CVS/Repository linux-2.4-xfs/linux/arch/sparc64/prom/CVS/Repository --- linux-2.4.7/linux/arch/sparc64/prom/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/prom/CVS/Repository Thu Jul 5 11:50:55 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sparc64/prom diff -rNu linux-2.4.7/linux/arch/sparc64/prom/CVS/Root linux-2.4-xfs/linux/arch/sparc64/prom/CVS/Root --- linux-2.4.7/linux/arch/sparc64/prom/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/prom/CVS/Root Thu Jul 5 11:50:55 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/arch/sparc64/solaris/CVS/Entries linux-2.4-xfs/linux/arch/sparc64/solaris/CVS/Entries --- linux-2.4.7/linux/arch/sparc64/solaris/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/solaris/CVS/Entries Thu Jul 5 11:50:57 2001 @@ -0,0 +1,15 @@ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/conv.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/entry64.S/1.3/Fri Jan 21 19:18:03 2000/-ko/ +/fs.c/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/ioctl.c/1.10/Sun Dec 17 19:15:00 2000/-ko/ +/ipc.c/1.3/Wed Dec 29 19:04:31 1999/-ko/ +/misc.c/1.18/Mon Apr 2 17:13:32 2001/-ko/ +/signal.c/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/signal.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/socket.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/socksys.c/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/socksys.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/systbl.S/1.4/Wed Mar 15 18:02:00 2000/-ko/ +/timod.c/1.12/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/arch/sparc64/solaris/CVS/Repository linux-2.4-xfs/linux/arch/sparc64/solaris/CVS/Repository --- linux-2.4.7/linux/arch/sparc64/solaris/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/solaris/CVS/Repository Thu Jul 5 11:50:56 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/arch/sparc64/solaris diff -rNu linux-2.4.7/linux/arch/sparc64/solaris/CVS/Root linux-2.4-xfs/linux/arch/sparc64/solaris/CVS/Root --- linux-2.4.7/linux/arch/sparc64/solaris/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/arch/sparc64/solaris/CVS/Root Thu Jul 5 11:50:56 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/CVS/Entries linux-2.4-xfs/linux/drivers/CVS/Entries --- linux-2.4.7/linux/drivers/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/CVS/Entries Thu Jul 5 11:50:57 2001 @@ -0,0 +1,2 @@ +/Makefile/1.22/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/CVS/Entries.Log linux-2.4-xfs/linux/drivers/CVS/Entries.Log --- linux-2.4.7/linux/drivers/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/CVS/Entries.Log Thu Jul 5 12:02:20 2001 @@ -0,0 +1,36 @@ +A D/acorn//// +A D/acpi//// +A D/atm//// +A D/block//// +A D/bluetooth//// +A D/cdrom//// +A D/char//// +A D/dio//// +A D/fc4//// +A D/i2c//// +A D/i2o//// +A D/ide//// +A D/ieee1394//// +A D/input//// +A D/isdn//// +A D/macintosh//// +A D/md//// +A D/media//// +A D/misc//// +A D/mtd//// +A D/net//// +A D/nubus//// +A D/parport//// +A D/pci//// +A D/pcmcia//// +A D/pnp//// +A D/s390//// +A D/sbus//// +A D/scsi//// +A D/sgi//// +A D/sound//// +A D/tc//// +A D/telephony//// +A D/usb//// +A D/video//// +A D/zorro//// diff -rNu linux-2.4.7/linux/drivers/CVS/Repository linux-2.4-xfs/linux/drivers/CVS/Repository --- linux-2.4.7/linux/drivers/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/CVS/Repository Thu Jul 5 11:50:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers diff -rNu linux-2.4.7/linux/drivers/CVS/Root linux-2.4-xfs/linux/drivers/CVS/Root --- linux-2.4.7/linux/drivers/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/CVS/Root Thu Jul 5 11:50:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acorn/CVS/Entries linux-2.4-xfs/linux/drivers/acorn/CVS/Entries --- linux-2.4.7/linux/drivers/acorn/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/CVS/Entries Thu Jul 5 11:50:57 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/README/1.3/Sat Oct 23 02:00:20 1999/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acorn/CVS/Entries.Log linux-2.4-xfs/linux/drivers/acorn/CVS/Entries.Log --- linux-2.4.7/linux/drivers/acorn/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/CVS/Entries.Log Thu Jul 5 11:51:00 2001 @@ -0,0 +1,4 @@ +A D/block//// +A D/char//// +A D/net//// +A D/scsi//// diff -rNu linux-2.4.7/linux/drivers/acorn/CVS/Repository linux-2.4-xfs/linux/drivers/acorn/CVS/Repository --- linux-2.4.7/linux/drivers/acorn/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/CVS/Repository Thu Jul 5 11:50:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acorn diff -rNu linux-2.4.7/linux/drivers/acorn/CVS/Root linux-2.4-xfs/linux/drivers/acorn/CVS/Root --- linux-2.4.7/linux/drivers/acorn/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/CVS/Root Thu Jul 5 11:50:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acorn/block/CVS/Entries linux-2.4-xfs/linux/drivers/acorn/block/CVS/Entries --- linux-2.4.7/linux/drivers/acorn/block/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/block/CVS/Entries Thu Jul 5 11:50:59 2001 @@ -0,0 +1,7 @@ +/Config.in/1.3/Tue Oct 12 18:49:29 1999/-ko/ +/Makefile/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/fd1772.c/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/fd1772dma.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mfm.S/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mfmhd.c/1.9/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acorn/block/CVS/Repository linux-2.4-xfs/linux/drivers/acorn/block/CVS/Repository --- linux-2.4.7/linux/drivers/acorn/block/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/block/CVS/Repository Thu Jul 5 11:50:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acorn/block diff -rNu linux-2.4.7/linux/drivers/acorn/block/CVS/Root linux-2.4-xfs/linux/drivers/acorn/block/CVS/Root --- linux-2.4.7/linux/drivers/acorn/block/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/block/CVS/Root Thu Jul 5 11:50:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acorn/char/CVS/Entries linux-2.4-xfs/linux/drivers/acorn/char/CVS/Entries --- linux-2.4.7/linux/drivers/acorn/char/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/char/CVS/Entries Thu Jul 5 11:51:00 2001 @@ -0,0 +1,13 @@ +/Makefile/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/defkeymap-acorn.c/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/i2c.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/keyb_arc.c/1.9/Thu Jun 28 05:21:16 2001/-ko/ +/keyb_ps2.c/1.9/Thu Jun 28 05:21:16 2001/-ko/ +/mouse_ps2.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/mouse_rpc.c/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/pcf8583.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/pcf8583.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/serial-atomwide.c/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/serial-card.c/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/serial-dualsp.c/1.4/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acorn/char/CVS/Repository linux-2.4-xfs/linux/drivers/acorn/char/CVS/Repository --- linux-2.4.7/linux/drivers/acorn/char/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/char/CVS/Repository Thu Jul 5 11:50:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acorn/char diff -rNu linux-2.4.7/linux/drivers/acorn/char/CVS/Root linux-2.4-xfs/linux/drivers/acorn/char/CVS/Root --- linux-2.4.7/linux/drivers/acorn/char/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/char/CVS/Root Thu Jul 5 11:50:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acorn/net/CVS/Entries linux-2.4-xfs/linux/drivers/acorn/net/CVS/Entries --- linux-2.4.7/linux/drivers/acorn/net/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/net/CVS/Entries Thu Jul 5 11:51:00 2001 @@ -0,0 +1,8 @@ +/Config.in/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/Makefile/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/ether1.c/1.12/Thu Jun 28 05:21:16 2001/-ko/ +/ether1.h/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/ether3.c/1.11/Thu Jun 28 05:21:16 2001/-ko/ +/ether3.h/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/etherh.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acorn/net/CVS/Repository linux-2.4-xfs/linux/drivers/acorn/net/CVS/Repository --- linux-2.4.7/linux/drivers/acorn/net/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/net/CVS/Repository Thu Jul 5 11:51:00 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acorn/net diff -rNu linux-2.4.7/linux/drivers/acorn/net/CVS/Root linux-2.4-xfs/linux/drivers/acorn/net/CVS/Root --- linux-2.4.7/linux/drivers/acorn/net/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/net/CVS/Root Thu Jul 5 11:51:00 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acorn/scsi/CVS/Entries linux-2.4-xfs/linux/drivers/acorn/scsi/CVS/Entries --- linux-2.4.7/linux/drivers/acorn/scsi/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/scsi/CVS/Entries Thu Jul 5 11:51:04 2001 @@ -0,0 +1,20 @@ +/Config.in/1.4/Fri Jan 21 19:18:03 2000/-ko/ +/Makefile/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/acornscsi-io.S/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/acornscsi.c/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/acornscsi.h/1.6/Thu Jun 28 05:21:16 2001/-ko/ +/arxescsi.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/arxescsi.h/1.3/Fri May 26 01:26:22 2000/-ko/ +/cumana_1.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/cumana_2.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/ecoscsi.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/eesox.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/fas216.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/fas216.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/msgqueue.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/msgqueue.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/oak.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/powertec.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/queue.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/queue.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acorn/scsi/CVS/Repository linux-2.4-xfs/linux/drivers/acorn/scsi/CVS/Repository --- linux-2.4.7/linux/drivers/acorn/scsi/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/scsi/CVS/Repository Thu Jul 5 11:51:00 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acorn/scsi diff -rNu linux-2.4.7/linux/drivers/acorn/scsi/CVS/Root linux-2.4-xfs/linux/drivers/acorn/scsi/CVS/Root --- linux-2.4.7/linux/drivers/acorn/scsi/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acorn/scsi/CVS/Root Thu Jul 5 11:51:00 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/CVS/Entries Thu Jul 5 11:51:04 2001 @@ -0,0 +1,7 @@ +/Config.in/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/Makefile/1.7/Thu Jun 21 15:45:04 2001/-ko/ +/acpi_ksyms.c/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/driver.c/1.10/Thu Jun 21 15:45:04 2001/-ko/ +/driver.h/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/os.c/1.6/Thu Jun 28 05:21:16 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/CVS/Entries.Log linux-2.4-xfs/linux/drivers/acpi/CVS/Entries.Log --- linux-2.4.7/linux/drivers/acpi/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/CVS/Entries.Log Thu Jul 5 11:51:17 2001 @@ -0,0 +1,12 @@ +A D/debugger//// +A D/dispatcher//// +A D/events//// +A D/executer//// +A D/hardware//// +A D/include//// +A D/namespace//// +A D/ospm//// +A D/parser//// +A D/resources//// +A D/tables//// +A D/utilities//// diff -rNu linux-2.4.7/linux/drivers/acpi/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/CVS/Repository Thu Jul 5 11:51:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi diff -rNu linux-2.4.7/linux/drivers/acpi/CVS/Root linux-2.4-xfs/linux/drivers/acpi/CVS/Root --- linux-2.4.7/linux/drivers/acpi/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/CVS/Root Thu Jul 5 11:51:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/debugger/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/debugger/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/debugger/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/debugger/CVS/Entries Thu Jul 5 11:51:05 2001 @@ -0,0 +1,11 @@ +/dbcmds.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/dbdisasm.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/dbdisply.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/dbexec.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/dbfileio.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/dbhistry.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/dbinput.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/dbstats.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/dbutils.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/dbxface.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/debugger/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/debugger/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/debugger/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/debugger/CVS/Repository Thu Jul 5 11:51:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/debugger diff -rNu linux-2.4.7/linux/drivers/acpi/debugger/CVS/Root linux-2.4-xfs/linux/drivers/acpi/debugger/CVS/Root --- linux-2.4.7/linux/drivers/acpi/debugger/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/debugger/CVS/Root Thu Jul 5 11:51:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/dispatcher/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/dispatcher/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/dispatcher/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/dispatcher/CVS/Entries Thu Jul 5 11:51:07 2001 @@ -0,0 +1,12 @@ +/Makefile/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/dsfield.c/1.4/Thu Jun 21 15:45:04 2001/-ko/ +/dsmethod.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/dsmthdat.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/dsobject.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/dsopcode.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/dsutils.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/dswexec.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/dswload.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/dswscope.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/dswstate.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/dispatcher/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/dispatcher/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/dispatcher/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/dispatcher/CVS/Repository Thu Jul 5 11:51:05 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/dispatcher diff -rNu linux-2.4.7/linux/drivers/acpi/dispatcher/CVS/Root linux-2.4-xfs/linux/drivers/acpi/dispatcher/CVS/Root --- linux-2.4.7/linux/drivers/acpi/dispatcher/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/dispatcher/CVS/Root Thu Jul 5 11:51:05 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/events/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/events/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/events/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/events/CVS/Entries Thu Jul 5 11:51:08 2001 @@ -0,0 +1,10 @@ +/Makefile/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/evevent.c/1.7/Thu Jun 21 15:45:04 2001/-ko/ +/evmisc.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/evregion.c/1.7/Thu Jun 21 15:45:04 2001/-ko/ +/evrgnini.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/evsci.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/evxface.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/evxfevnt.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/evxfregn.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/events/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/events/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/events/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/events/CVS/Repository Thu Jul 5 11:51:07 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/events diff -rNu linux-2.4.7/linux/drivers/acpi/events/CVS/Root linux-2.4-xfs/linux/drivers/acpi/events/CVS/Root --- linux-2.4.7/linux/drivers/acpi/events/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/events/CVS/Root Thu Jul 5 11:51:07 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/executer/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/executer/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/executer/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/executer/CVS/Entries Thu Jul 5 11:51:09 2001 @@ -0,0 +1,24 @@ +/Makefile/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exconfig.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exconvrt.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/excreate.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exdump.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exdyadic.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exfield.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exfldio.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exmisc.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exmonad.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exmutex.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exnames.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exprep.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exregion.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exresnte.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exresolv.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exresop.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exstore.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exstoren.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exstorob.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exsystem.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exutils.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/exxface.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/executer/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/executer/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/executer/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/executer/CVS/Repository Thu Jul 5 11:51:08 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/executer diff -rNu linux-2.4.7/linux/drivers/acpi/executer/CVS/Root linux-2.4-xfs/linux/drivers/acpi/executer/CVS/Root --- linux-2.4.7/linux/drivers/acpi/executer/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/executer/CVS/Root Thu Jul 5 11:51:08 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/hardware/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/hardware/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/hardware/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/hardware/CVS/Entries Thu Jul 5 11:51:09 2001 @@ -0,0 +1,7 @@ +/Makefile/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/hwacpi.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/hwgpe.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/hwregs.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/hwsleep.c/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/hwtimer.c/1.3/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/hardware/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/hardware/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/hardware/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/hardware/CVS/Repository Thu Jul 5 11:51:09 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/hardware diff -rNu linux-2.4.7/linux/drivers/acpi/hardware/CVS/Root linux-2.4-xfs/linux/drivers/acpi/hardware/CVS/Root --- linux-2.4.7/linux/drivers/acpi/hardware/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/hardware/CVS/Root Thu Jul 5 11:51:09 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/include/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/include/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/include/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/include/CVS/Entries Thu Jul 5 11:51:11 2001 @@ -0,0 +1,28 @@ +/acconfig.h/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/acdebug.h/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/acdispat.h/1.4/Thu Jun 21 15:45:04 2001/-ko/ +/acevents.h/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/acexcep.h/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/acglobal.h/1.4/Thu Jun 21 15:45:04 2001/-ko/ +/achware.h/1.4/Thu Jun 21 15:45:04 2001/-ko/ +/acinterp.h/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/aclocal.h/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/acmacros.h/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/acnamesp.h/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/acobject.h/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/acoutput.h/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/acparser.h/1.3/Thu Feb 1 17:10:24 2001/-ko/ +/acpi.h/1.4/Thu Jun 21 15:45:04 2001/-ko/ +/acpiosxf.h/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/acpixf.h/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/acresrc.h/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/acstruct.h/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/actables.h/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/actbl.h/1.4/Thu Jun 21 15:45:04 2001/-ko/ +/actbl1.h/1.2/Thu Feb 1 17:10:24 2001/-ko/ +/actbl2.h/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/actbl71.h/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/actypes.h/1.7/Thu Jun 21 15:45:04 2001/-ko/ +/acutils.h/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/amlcode.h/1.5/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/include/CVS/Entries.Log linux-2.4-xfs/linux/drivers/acpi/include/CVS/Entries.Log --- linux-2.4.7/linux/drivers/acpi/include/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/include/CVS/Entries.Log Thu Jul 5 11:51:11 2001 @@ -0,0 +1 @@ +A D/platform//// diff -rNu linux-2.4.7/linux/drivers/acpi/include/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/include/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/include/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/include/CVS/Repository Thu Jul 5 11:51:09 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/include diff -rNu linux-2.4.7/linux/drivers/acpi/include/CVS/Root linux-2.4-xfs/linux/drivers/acpi/include/CVS/Root --- linux-2.4.7/linux/drivers/acpi/include/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/include/CVS/Root Thu Jul 5 11:51:09 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/include/platform/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/include/platform/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/include/platform/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/include/platform/CVS/Entries Thu Jul 5 11:51:11 2001 @@ -0,0 +1,4 @@ +/acenv.h/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/acgcc.h/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/aclinux.h/1.1/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/include/platform/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/include/platform/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/include/platform/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/include/platform/CVS/Repository Thu Jul 5 11:51:11 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/include/platform diff -rNu linux-2.4.7/linux/drivers/acpi/include/platform/CVS/Root linux-2.4-xfs/linux/drivers/acpi/include/platform/CVS/Root --- linux-2.4.7/linux/drivers/acpi/include/platform/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/include/platform/CVS/Root Thu Jul 5 11:51:11 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/namespace/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/namespace/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/namespace/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/namespace/CVS/Entries Thu Jul 5 11:51:12 2001 @@ -0,0 +1,14 @@ +/Makefile/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/nsaccess.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/nsalloc.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/nseval.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/nsinit.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/nsload.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/nsnames.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/nsobject.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/nssearch.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/nsutils.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/nswalk.c/1.4/Thu Jun 21 15:45:04 2001/-ko/ +/nsxfname.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/nsxfobj.c/1.8/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/namespace/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/namespace/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/namespace/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/namespace/CVS/Repository Thu Jul 5 11:51:11 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/namespace diff -rNu linux-2.4.7/linux/drivers/acpi/namespace/CVS/Root linux-2.4-xfs/linux/drivers/acpi/namespace/CVS/Root --- linux-2.4.7/linux/drivers/acpi/namespace/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/namespace/CVS/Root Thu Jul 5 11:51:11 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/ospm/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/ospm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/CVS/Entries Thu Jul 5 11:51:12 2001 @@ -0,0 +1,2 @@ +/Makefile/1.1/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/CVS/Entries.Log linux-2.4-xfs/linux/drivers/acpi/ospm/CVS/Entries.Log --- linux-2.4.7/linux/drivers/acpi/ospm/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/CVS/Entries.Log Thu Jul 5 11:51:14 2001 @@ -0,0 +1,9 @@ +A D/ac_adapter//// +A D/battery//// +A D/busmgr//// +A D/button//// +A D/ec//// +A D/include//// +A D/processor//// +A D/system//// +A D/thermal//// diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/ospm/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/ospm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/CVS/Repository Thu Jul 5 11:51:12 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/ospm diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/CVS/Root linux-2.4-xfs/linux/drivers/acpi/ospm/CVS/Root --- linux-2.4.7/linux/drivers/acpi/ospm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/CVS/Root Thu Jul 5 11:51:12 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/ac_adapter/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/ospm/ac_adapter/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/ospm/ac_adapter/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/ac_adapter/CVS/Entries Thu Jul 5 11:51:12 2001 @@ -0,0 +1,4 @@ +/Makefile/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/ac.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/ac_osl.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/ac_adapter/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/ospm/ac_adapter/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/ospm/ac_adapter/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/ac_adapter/CVS/Repository Thu Jul 5 11:51:12 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/ospm/ac_adapter diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/ac_adapter/CVS/Root linux-2.4-xfs/linux/drivers/acpi/ospm/ac_adapter/CVS/Root --- linux-2.4.7/linux/drivers/acpi/ospm/ac_adapter/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/ac_adapter/CVS/Root Thu Jul 5 11:51:12 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/battery/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/ospm/battery/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/ospm/battery/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/battery/CVS/Entries Thu Jul 5 11:51:12 2001 @@ -0,0 +1,4 @@ +/Makefile/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bt.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bt_osl.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/battery/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/ospm/battery/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/ospm/battery/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/battery/CVS/Repository Thu Jul 5 11:51:12 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/ospm/battery diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/battery/CVS/Root linux-2.4-xfs/linux/drivers/acpi/ospm/battery/CVS/Root --- linux-2.4.7/linux/drivers/acpi/ospm/battery/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/battery/CVS/Root Thu Jul 5 11:51:12 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/busmgr/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/ospm/busmgr/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/ospm/busmgr/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/busmgr/CVS/Entries Thu Jul 5 11:51:13 2001 @@ -0,0 +1,11 @@ +/Makefile/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bm.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bm_osl.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bmdriver.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bmnotify.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bmpm.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bmpower.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bmrequest.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bmsearch.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bmutils.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/busmgr/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/ospm/busmgr/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/ospm/busmgr/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/busmgr/CVS/Repository Thu Jul 5 11:51:12 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/ospm/busmgr diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/busmgr/CVS/Root linux-2.4-xfs/linux/drivers/acpi/ospm/busmgr/CVS/Root --- linux-2.4.7/linux/drivers/acpi/ospm/busmgr/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/busmgr/CVS/Root Thu Jul 5 11:51:12 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/button/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/ospm/button/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/ospm/button/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/button/CVS/Entries Thu Jul 5 11:51:13 2001 @@ -0,0 +1,4 @@ +/Makefile/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bn.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bn_osl.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/button/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/ospm/button/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/ospm/button/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/button/CVS/Repository Thu Jul 5 11:51:13 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/ospm/button diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/button/CVS/Root linux-2.4-xfs/linux/drivers/acpi/ospm/button/CVS/Root --- linux-2.4.7/linux/drivers/acpi/ospm/button/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/button/CVS/Root Thu Jul 5 11:51:13 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/ec/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/ospm/ec/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/ospm/ec/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/ec/CVS/Entries Thu Jul 5 11:51:13 2001 @@ -0,0 +1,7 @@ +/Makefile/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/ec_osl.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/ecgpe.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/ecmain.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/ecspace.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/ectransx.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/ec/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/ospm/ec/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/ospm/ec/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/ec/CVS/Repository Thu Jul 5 11:51:13 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/ospm/ec diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/ec/CVS/Root linux-2.4-xfs/linux/drivers/acpi/ospm/ec/CVS/Root --- linux-2.4.7/linux/drivers/acpi/ospm/ec/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/ec/CVS/Root Thu Jul 5 11:51:13 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/include/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/ospm/include/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/ospm/include/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/include/CVS/Entries Thu Jul 5 11:51:14 2001 @@ -0,0 +1,10 @@ +/ac.h/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bm.h/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bmpower.h/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bn.h/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/bt.h/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/ec.h/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/pr.h/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/sm.h/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/tz.h/1.1/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/include/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/ospm/include/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/ospm/include/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/include/CVS/Repository Thu Jul 5 11:51:13 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/ospm/include diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/include/CVS/Root linux-2.4-xfs/linux/drivers/acpi/ospm/include/CVS/Root --- linux-2.4.7/linux/drivers/acpi/ospm/include/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/include/CVS/Root Thu Jul 5 11:51:13 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/processor/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/ospm/processor/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/ospm/processor/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/processor/CVS/Entries Thu Jul 5 11:51:14 2001 @@ -0,0 +1,6 @@ +/Makefile/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/pr.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/pr_osl.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/prperf.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/prpower.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/processor/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/ospm/processor/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/ospm/processor/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/processor/CVS/Repository Thu Jul 5 11:51:14 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/ospm/processor diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/processor/CVS/Root linux-2.4-xfs/linux/drivers/acpi/ospm/processor/CVS/Root --- linux-2.4.7/linux/drivers/acpi/ospm/processor/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/processor/CVS/Root Thu Jul 5 11:51:14 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/system/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/ospm/system/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/ospm/system/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/system/CVS/Entries Thu Jul 5 11:51:14 2001 @@ -0,0 +1,4 @@ +/Makefile/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/sm.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/sm_osl.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/system/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/ospm/system/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/ospm/system/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/system/CVS/Repository Thu Jul 5 11:51:14 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/ospm/system diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/system/CVS/Root linux-2.4-xfs/linux/drivers/acpi/ospm/system/CVS/Root --- linux-2.4.7/linux/drivers/acpi/ospm/system/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/system/CVS/Root Thu Jul 5 11:51:14 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/thermal/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/ospm/thermal/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/ospm/thermal/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/thermal/CVS/Entries Thu Jul 5 11:51:14 2001 @@ -0,0 +1,5 @@ +/Makefile/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/tz.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/tz_osl.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/tzpolicy.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/thermal/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/ospm/thermal/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/ospm/thermal/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/thermal/CVS/Repository Thu Jul 5 11:51:14 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/ospm/thermal diff -rNu linux-2.4.7/linux/drivers/acpi/ospm/thermal/CVS/Root linux-2.4-xfs/linux/drivers/acpi/ospm/thermal/CVS/Root --- linux-2.4.7/linux/drivers/acpi/ospm/thermal/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/ospm/thermal/CVS/Root Thu Jul 5 11:51:14 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/parser/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/parser/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/parser/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/parser/CVS/Entries Thu Jul 5 11:51:16 2001 @@ -0,0 +1,11 @@ +/Makefile/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/psargs.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/psfind.c/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/psopcode.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/psparse.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/psscope.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/pstree.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/psutils.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/pswalk.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/psxface.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/parser/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/parser/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/parser/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/parser/CVS/Repository Thu Jul 5 11:51:14 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/parser diff -rNu linux-2.4.7/linux/drivers/acpi/parser/CVS/Root linux-2.4-xfs/linux/drivers/acpi/parser/CVS/Root --- linux-2.4.7/linux/drivers/acpi/parser/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/parser/CVS/Root Thu Jul 5 11:51:14 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/resources/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/resources/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/resources/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/resources/CVS/Entries Thu Jul 5 11:51:17 2001 @@ -0,0 +1,13 @@ +/Makefile/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/rsaddr.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/rscalc.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/rscreate.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/rsdump.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/rsio.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/rsirq.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/rslist.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/rsmemory.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/rsmisc.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/rsutils.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/rsxface.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/resources/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/resources/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/resources/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/resources/CVS/Repository Thu Jul 5 11:51:16 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/resources diff -rNu linux-2.4.7/linux/drivers/acpi/resources/CVS/Root linux-2.4-xfs/linux/drivers/acpi/resources/CVS/Root --- linux-2.4.7/linux/drivers/acpi/resources/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/resources/CVS/Root Thu Jul 5 11:51:16 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/tables/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/tables/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/tables/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/tables/CVS/Entries Thu Jul 5 11:51:17 2001 @@ -0,0 +1,8 @@ +/Makefile/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/tbconvrt.c/1.4/Thu Jun 21 15:45:04 2001/-ko/ +/tbget.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/tbinstal.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/tbutils.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/tbxface.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/tbxfroot.c/1.3/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/tables/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/tables/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/tables/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/tables/CVS/Repository Thu Jul 5 11:51:17 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/tables diff -rNu linux-2.4.7/linux/drivers/acpi/tables/CVS/Root linux-2.4-xfs/linux/drivers/acpi/tables/CVS/Root --- linux-2.4.7/linux/drivers/acpi/tables/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/tables/CVS/Root Thu Jul 5 11:51:17 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/acpi/utilities/CVS/Entries linux-2.4-xfs/linux/drivers/acpi/utilities/CVS/Entries --- linux-2.4.7/linux/drivers/acpi/utilities/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/utilities/CVS/Entries Thu Jul 5 11:51:19 2001 @@ -0,0 +1,12 @@ +/Makefile/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/utalloc.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/utcopy.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/utdebug.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/utdelete.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/uteval.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/utglobal.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/utinit.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/utmisc.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/utobject.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/utxface.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/acpi/utilities/CVS/Repository linux-2.4-xfs/linux/drivers/acpi/utilities/CVS/Repository --- linux-2.4.7/linux/drivers/acpi/utilities/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/utilities/CVS/Repository Thu Jul 5 11:51:17 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/acpi/utilities diff -rNu linux-2.4.7/linux/drivers/acpi/utilities/CVS/Root linux-2.4-xfs/linux/drivers/acpi/utilities/CVS/Root --- linux-2.4.7/linux/drivers/acpi/utilities/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/acpi/utilities/CVS/Root Thu Jul 5 11:51:17 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/atm/CVS/Entries linux-2.4-xfs/linux/drivers/atm/CVS/Entries --- linux-2.4.7/linux/drivers/atm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/atm/CVS/Entries Thu Jul 5 11:51:35 2001 @@ -0,0 +1,42 @@ +/Config.in/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/Makefile/1.12/Mon Apr 2 17:13:32 2001/-ko/ +/ambassador.c/1.12/Thu Jun 28 05:21:16 2001/-ko/ +/ambassador.h/1.4/Tue May 2 21:09:12 2000/-ko/ +/atmdev_init.c/1.7/Wed Jan 3 01:43:05 2001/-ko/ +/atmsar11.data/1.2/Fri Feb 11 00:16:16 2000/-ko/ +/atmsar11.regions/1.2/Fri Feb 11 00:16:16 2000/-ko/ +/atmsar11.start/1.2/Fri Feb 11 00:16:16 2000/-ko/ +/atmtcp.c/1.7/Wed Jan 3 01:43:05 2001/-ko/ +/eni.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/eni.h/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/firestream.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/firestream.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/fore200e.c/1.11/Thu Jun 28 05:21:16 2001/-ko/ +/fore200e.h/1.3/Tue May 2 21:09:12 2000/-ko/ +/fore200e_firmware_copyright/1.1/Sun Feb 27 23:15:45 2000/-ko/ +/fore200e_mkfirm.c/1.2/Thu Jun 21 15:45:04 2001/-ko/ +/horizon.c/1.9/Wed Jan 3 01:43:05 2001/-ko/ +/horizon.h/1.3/Fri Mar 24 21:14:53 2000/-ko/ +/idt77105.c/1.4/Thu Jun 28 05:21:16 2001/-ko/ +/idt77105.h/1.1/Fri Feb 11 00:16:16 2000/-ko/ +/iphase.c/1.10/Fri Jun 29 22:21:45 2001/-ko/ +/iphase.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/midway.h/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/nicstar.c/1.14/Thu Jun 28 05:21:16 2001/-ko/ +/nicstar.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/nicstarmac.c/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/nicstarmac.copyright/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/nicstarmac.h/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/pca200e.data/1.1/Sun Feb 27 23:15:45 2000/-ko/ +/pca200e_ecd.data/1.1/Sun Feb 27 23:15:45 2000/-ko/ +/sba200e_ecd.data/1.1/Sun Feb 27 23:15:45 2000/-ko/ +/suni.c/1.6/Fri May 26 01:14:50 2000/-ko/ +/suni.h/1.2/Fri Mar 24 21:14:53 2000/-ko/ +/tonga.h/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/uPD98401.h/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/uPD98402.c/1.6/Thu Jun 28 05:21:16 2001/-ko/ +/uPD98402.h/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/zatm.c/1.10/Thu Jun 28 05:21:16 2001/-ko/ +/zatm.h/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/zeprom.h/1.1/Mon Aug 30 00:17:07 1999/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/atm/CVS/Repository linux-2.4-xfs/linux/drivers/atm/CVS/Repository --- linux-2.4.7/linux/drivers/atm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/atm/CVS/Repository Thu Jul 5 11:51:19 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/atm diff -rNu linux-2.4.7/linux/drivers/atm/CVS/Root linux-2.4-xfs/linux/drivers/atm/CVS/Root --- linux-2.4.7/linux/drivers/atm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/atm/CVS/Root Thu Jul 5 11:51:19 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/block/CVS/Entries linux-2.4-xfs/linux/drivers/block/CVS/Entries --- linux-2.4.7/linux/drivers/block/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/block/CVS/Entries Thu Jul 5 11:51:49 2001 @@ -0,0 +1,31 @@ +/Config.in/1.33/Thu Feb 22 21:09:04 2001/-ko/ +/DAC960.c/1.27/Fri Jun 15 12:12:13 2001/-ko/ +/DAC960.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/Makefile/1.21/Thu Dec 21 05:48:12 2000/-ko/ +/acsi.c/1.12/Tue May 29 19:53:13 2001/-ko/ +/acsi_slm.c/1.9/Tue May 29 19:53:13 2001/-ko/ +/amiflop.c/1.14/Tue May 29 19:53:13 2001/-ko/ +/ataflop.c/1.13/Thu Feb 22 21:09:04 2001/-ko/ +/blkpg.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/cciss.c/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/cciss.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/cciss_cmd.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/cpqarray.c/1.22/Tue May 29 19:53:13 2001/-ko/ +/cpqarray.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/elevator.c/1.8/Tue Apr 3 23:07:43 2001/-ko/ +/floppy.c/1.23/Thu Feb 22 21:09:04 2001/-ko/ +/genhd.c/1.14/Tue May 29 19:53:13 2001/-ko/ +/ida_cmd.h/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/ida_ioctl.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/ll_rw_blk.c/1.70/Thu Jul 5 06:13:42 2001/-ko/ +/loop.c/1.33/Mon Jul 2 15:59:04 2001/-ko/ +/nbd.c/1.20/Mon Jul 2 15:59:04 2001/-ko/ +/ps2esdi.c/1.15/Thu Jun 28 05:21:16 2001/-ko/ +/rd.c/1.29/Thu Jul 5 06:13:42 2001/-ko/ +/smart1,2.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/swim3.c/1.12/Thu Jun 28 05:21:16 2001/-ko/ +/swim_iop.c/1.8/Tue May 29 19:53:13 2001/-ko/ +/xd.c/1.19/Tue May 29 19:53:13 2001/-ko/ +/xd.h/1.8/Thu Sep 28 22:42:39 2000/-ko/ +/z2ram.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/block/CVS/Entries.Log linux-2.4-xfs/linux/drivers/block/CVS/Entries.Log --- linux-2.4.7/linux/drivers/block/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/block/CVS/Entries.Log Thu Jul 5 11:51:49 2001 @@ -0,0 +1 @@ +A D/paride//// diff -rNu linux-2.4.7/linux/drivers/block/CVS/Repository linux-2.4-xfs/linux/drivers/block/CVS/Repository --- linux-2.4.7/linux/drivers/block/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/block/CVS/Repository Thu Jul 5 11:51:35 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/block diff -rNu linux-2.4.7/linux/drivers/block/CVS/Root linux-2.4-xfs/linux/drivers/block/CVS/Root --- linux-2.4.7/linux/drivers/block/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/block/CVS/Root Thu Jul 5 11:51:35 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/block/DAC960.c linux-2.4-xfs/linux/drivers/block/DAC960.c --- linux-2.4.7/linux/drivers/block/DAC960.c Sat Apr 28 13:27:53 2001 +++ linux-2.4-xfs/linux/drivers/block/DAC960.c Fri Jun 15 07:12:13 2001 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -5104,6 +5105,9 @@ return put_user(Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)] .nr_sects, (long *) Argument); + case BLKBSZSET: + /* Set block size. */ + return blk_ioctl (Inode->i_rdev, Request, Argument); case BLKRAGET: /* Get Read-Ahead. */ if ((long *) Argument == NULL) return -EINVAL; diff -rNu linux-2.4.7/linux/drivers/block/blkpg.c linux-2.4-xfs/linux/drivers/block/blkpg.c --- linux-2.4.7/linux/drivers/block/blkpg.c Sun May 20 13:34:05 2001 +++ linux-2.4-xfs/linux/drivers/block/blkpg.c Tue May 29 14:53:13 2001 @@ -273,6 +273,34 @@ case BLKELVSET: return blkelvset_ioctl(&blk_get_queue(dev)->elevator, (blkelv_ioctl_arg_t *) arg); + + case BLKBSZGET: + /* get the logical block size */ + intval = BLOCK_SIZE; + if (blksize_size[MAJOR(dev)]) + intval = blksize_size[MAJOR(dev)][MINOR(dev)]; + return put_user (intval, (int *) arg); + + case BLKBSZSET: + /* set the logical block size */ + if (!capable (CAP_SYS_ADMIN)) + return -EACCES; + + if (!dev || !arg) + return -EINVAL; + + if (get_user (intval, (int *) arg)) + return -EFAULT; + + if (intval > PAGE_SIZE || intval < 512 || + (intval & (intval - 1))) + return -EINVAL; + + if (get_super (dev) || is_swap_partition (dev)) + return -EBUSY; + + set_blocksize (dev, intval); + return 0; default: return -EINVAL; diff -rNu linux-2.4.7/linux/drivers/block/cciss.c linux-2.4-xfs/linux/drivers/block/cciss.c --- linux-2.4.7/linux/drivers/block/cciss.c Mon Jul 2 15:56:40 2001 +++ linux-2.4-xfs/linux/drivers/block/cciss.c Mon Jul 2 21:33:57 2001 @@ -411,6 +411,8 @@ case BLKRASET: case BLKRAGET: case BLKPG: + case BLKBSZSET: + case BLKBSZGET: return( blk_ioctl(inode->i_rdev, cmd, arg)); case CCISS_GETPCIINFO: { diff -rNu linux-2.4.7/linux/drivers/block/cpqarray.c linux-2.4-xfs/linux/drivers/block/cpqarray.c --- linux-2.4.7/linux/drivers/block/cpqarray.c Tue May 22 12:23:16 2001 +++ linux-2.4-xfs/linux/drivers/block/cpqarray.c Tue May 29 14:53:13 2001 @@ -1217,6 +1217,9 @@ if (!arg) return -EINVAL; put_user(ida[(ctlr<i_rdev)].nr_sects, (long*)arg); return 0; + case BLKBSZSET: + case BLKBSZGET: + return blk_ioctl(inode->i_rdev, cmd, arg); case BLKRRPART: return revalidate_logvol(inode->i_rdev, 1); case IDAPASSTHRU: diff -rNu linux-2.4.7/linux/drivers/block/ll_rw_blk.c linux-2.4-xfs/linux/drivers/block/ll_rw_blk.c --- linux-2.4.7/linux/drivers/block/ll_rw_blk.c Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/drivers/block/ll_rw_blk.c Thu Jul 5 01:13:42 2001 @@ -1029,6 +1029,8 @@ correct_size, bh->b_size); goto sorry; } + if (buffer_delay(bh) || !buffer_mapped(bh)) + BUG(); } if ((rw & WRITE) && is_read_only(bhs[0]->b_dev)) { diff -rNu linux-2.4.7/linux/drivers/block/paride/CVS/Entries linux-2.4-xfs/linux/drivers/block/paride/CVS/Entries --- linux-2.4.7/linux/drivers/block/paride/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/block/paride/CVS/Entries Thu Jul 5 11:51:52 2001 @@ -0,0 +1,30 @@ +/Config.in/1.4/Wed May 2 06:22:13 2001/-ko/ +/Makefile/1.6/Wed May 2 06:22:13 2001/-ko/ +/aten.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/bpck.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/bpck6.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/comm.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/dstr.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/epat.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/epia.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/fit2.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/fit3.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/friq.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/frpw.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/jumbo/1.3/Fri May 26 01:14:50 2000/-ko/ +/kbic.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/ktti.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/mkd/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/on20.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/on26.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/paride.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/paride.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/pcd.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/pd.c/1.14/Tue May 29 19:53:13 2001/-ko/ +/pf.c/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/pg.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/ppc6lnx.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/pseudo.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/pt.c/1.11/Thu Jun 28 05:21:16 2001/-ko/ +/setup.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/block/paride/CVS/Repository linux-2.4-xfs/linux/drivers/block/paride/CVS/Repository --- linux-2.4.7/linux/drivers/block/paride/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/block/paride/CVS/Repository Thu Jul 5 11:51:49 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/block/paride diff -rNu linux-2.4.7/linux/drivers/block/paride/CVS/Root linux-2.4-xfs/linux/drivers/block/paride/CVS/Root --- linux-2.4.7/linux/drivers/block/paride/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/block/paride/CVS/Root Thu Jul 5 11:51:49 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/block/ps2esdi.c linux-2.4-xfs/linux/drivers/block/ps2esdi.c --- linux-2.4.7/linux/drivers/block/ps2esdi.c Wed Jun 27 19:10:55 2001 +++ linux-2.4-xfs/linux/drivers/block/ps2esdi.c Thu Jun 28 00:21:16 2001 @@ -1124,6 +1124,8 @@ case BLKRAGET: case BLKFLSBUF: case BLKPG: + case BLKBSZGET: + case BLKBSZSET: return blk_ioctl(inode->i_rdev, cmd, arg); } return (-EINVAL); diff -rNu linux-2.4.7/linux/drivers/bluetooth/CVS/Entries linux-2.4-xfs/linux/drivers/bluetooth/CVS/Entries --- linux-2.4.7/linux/drivers/bluetooth/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/bluetooth/CVS/Entries Thu Jul 5 11:51:52 2001 @@ -0,0 +1,6 @@ +/Config.in/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/Makefile/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/hci_emu.c/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/hci_uart.c/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/hci_usb.c/1.1/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/bluetooth/CVS/Repository linux-2.4-xfs/linux/drivers/bluetooth/CVS/Repository --- linux-2.4.7/linux/drivers/bluetooth/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/bluetooth/CVS/Repository Thu Jul 5 11:51:52 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/bluetooth diff -rNu linux-2.4.7/linux/drivers/bluetooth/CVS/Root linux-2.4-xfs/linux/drivers/bluetooth/CVS/Root --- linux-2.4.7/linux/drivers/bluetooth/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/bluetooth/CVS/Root Thu Jul 5 11:51:52 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/cdrom/CVS/Entries linux-2.4-xfs/linux/drivers/cdrom/CVS/Entries --- linux-2.4.7/linux/drivers/cdrom/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/cdrom/CVS/Entries Thu Jul 5 11:52:04 2001 @@ -0,0 +1,29 @@ +/Config.in/1.4/Sat Jan 29 23:00:52 2000/-ko/ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/aztcd.c/1.11/Mon Jul 31 16:16:28 2000/-ko/ +/aztcd.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cdrom.c/1.31/Tue May 29 19:53:13 2001/-ko/ +/cdu31a.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/cdu31a.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cm206.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/cm206.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/gscd.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/gscd.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/isp16.c/1.4/Wed Dec 15 00:05:45 1999/-ko/ +/isp16.h/1.3/Wed Dec 15 00:05:45 1999/-ko/ +/mcd.c/1.10/Thu Jul 5 05:29:17 2001/-ko/ +/mcd.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/mcdx.c/1.8/Thu Jun 28 05:21:16 2001/-ko/ +/mcdx.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/optcd.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/optcd.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/sbpcd.c/1.12/Tue May 29 19:53:13 2001/-ko/ +/sbpcd.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/sbpcd2.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sbpcd3.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sbpcd4.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sjcd.c/1.10/Mon Jul 31 16:16:28 2000/-ko/ +/sjcd.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sonycd535.c/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/sonycd535.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/cdrom/CVS/Repository linux-2.4-xfs/linux/drivers/cdrom/CVS/Repository --- linux-2.4.7/linux/drivers/cdrom/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/cdrom/CVS/Repository Thu Jul 5 11:51:52 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/cdrom diff -rNu linux-2.4.7/linux/drivers/cdrom/CVS/Root linux-2.4-xfs/linux/drivers/cdrom/CVS/Root --- linux-2.4.7/linux/drivers/cdrom/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/cdrom/CVS/Root Thu Jul 5 11:51:52 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/char/CVS/Entries linux-2.4-xfs/linux/drivers/char/CVS/Entries --- linux-2.4.7/linux/drivers/char/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/CVS/Entries Thu Jul 5 11:52:44 2001 @@ -0,0 +1,139 @@ +/ChangeLog/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Config.in/1.45/Thu Jul 5 06:13:42 2001/-ko/ +/Makefile/1.45/Thu Jul 5 06:13:42 2001/-ko/ +/README.computone/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/README.cycladesZ/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README.cyclomY/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README.epca/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/README.scc/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/acquirewdt.c/1.11/Tue May 29 19:53:13 2001/-ko/ +/adbmouse.c/1.13/Sun Dec 17 19:15:00 2000/-ko/ +/advantechwdt.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/amigamouse.c/1.9/Sun Dec 17 19:15:00 2000/-ko/ +/amikeyb.c/1.7/Sun Dec 17 19:15:00 2000/-ko/ +/amiserial.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/applicom.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/applicom.h/1.1/Mon Sep 6 21:36:14 1999/-ko/ +/atarimouse.c/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/atixlmouse.c/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/busmouse.c/1.16/Thu Feb 22 21:09:04 2001/-ko/ +/busmouse.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/cd1865.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/conmakehash.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/console.c/1.22/Wed Jun 13 03:24:09 2001/-ko/ +/console_macros.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/consolemap.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/cp437.uni/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cyclades.c/1.17/Thu Jun 28 05:21:16 2001/-ko/ +/defkeymap.c/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/defkeymap.map/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/digi.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/digi1.h/1.1/Fri Mar 3 01:30:48 2000/-ko/ +/digiFep1.h/1.1/Fri Mar 3 01:30:48 2000/-ko/ +/digiPCI.h/1.1/Fri Mar 3 01:30:48 2000/-ko/ +/digi_bios.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/digi_fep.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dn_keyb.c/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/ds1620.c/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/dsp56k.c/1.13/Mon Apr 2 17:13:32 2001/-ko/ +/dtlk.c/1.13/Thu Jul 5 06:13:42 2001/-ko/ +/dz.c/1.11/Thu Jul 5 06:13:42 2001/-ko/ +/dz.h/1.2/Sun Feb 27 22:37:25 2000/-ko/ +/ec3104_keyb.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/efirtc.c/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/epca.c/1.16/Thu Jun 28 05:21:16 2001/-ko/ +/epca.h/1.1/Fri Mar 3 01:30:48 2000/-ko/ +/epcaconfig.h/1.1/Fri Mar 3 01:30:48 2000/-ko/ +/esp.c/1.10/Thu Jun 28 05:21:16 2001/-ko/ +/fep.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/generic_serial.c/1.11/Thu Jul 5 06:13:42 2001/-ko/ +/h8.c/1.10/Thu Jul 5 06:13:42 2001/-ko/ +/h8.h/1.3/Sun Feb 27 22:37:25 2000/-ko/ +/hp600_keyb.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/i810-tco.c/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/i810-tco.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/i810_rng.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/ip2.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/ip2main.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/isicom.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/istallion.c/1.15/Mon Apr 2 17:13:32 2001/-ko/ +/keyboard.c/1.20/Wed Nov 1 21:35:42 2000/-ko/ +/logibusmouse.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/lp.c/1.19/Mon Apr 2 17:13:32 2001/-ko/ +/machzwd.c/1.4/Thu Jul 5 06:13:42 2001/-ko/ +/mem.c/1.35/Tue May 29 19:53:13 2001/-ko/ +/misc.c/1.25/Tue May 29 19:53:13 2001/-ko/ +/mixcomwd.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/moxa.c/1.6/Thu Jul 5 06:13:42 2001/-ko/ +/msbusmouse.c/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/mxser.c/1.8/Tue May 29 19:53:13 2001/-ko/ +/n_hdlc.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/n_r3964.c/1.9/Thu Jun 28 05:21:16 2001/-ko/ +/n_tty.c/1.12/Wed May 2 06:22:13 2001/-ko/ +/nvram.c/1.13/Thu Jun 28 05:21:16 2001/-ko/ +/nwbutton.c/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/nwbutton.h/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/nwflash.c/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/pc110pad.c/1.11/Tue May 29 19:53:13 2001/-ko/ +/pc110pad.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/pc_keyb.c/1.22/Wed May 2 06:22:13 2001/-ko/ +/pcwd.c/1.14/Tue May 29 19:53:13 2001/-ko/ +/pcxx.c/1.13/Tue May 29 19:53:13 2001/-ko/ +/pcxx.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/ppdev.c/1.21/Tue May 29 19:53:13 2001/-ko/ +/pty.c/1.10/Mon Jul 31 16:16:28 2000/-ko/ +/q40_keyb.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/qpmouse.c/1.10/Wed May 2 06:22:13 2001/-ko/ +/qtronix.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/qtronixmap.map/1.1/Wed May 2 06:22:13 2001/-ko/ +/random.c/1.16/Tue Jul 3 02:33:57 2001/-ko/ +/raw.c/1.17/Thu Jun 28 05:21:16 2001/-ko/ +/riscom8.c/1.9/Tue May 29 19:53:13 2001/-ko/ +/riscom8.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/riscom8_reg.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/rocket.c/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/rocket_int.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/rsf16fmi.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/rtc.c/1.20/Wed Jun 13 03:24:09 2001/-ko/ +/sbc60xxwdt.c/1.6/Thu Jun 28 05:21:16 2001/-ko/ +/scan_keyb.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/scan_keyb.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/scc.h/1.1/Tue Feb 1 23:02:54 2000/-ko/ +/selection.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/ser_a2232.c/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/ser_a2232.h/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/ser_a2232fw.ax/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/ser_a2232fw.h/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/serial.c/1.40/Tue May 29 19:53:13 2001/-ko/ +/serial167.c/1.8/Tue May 29 19:53:13 2001/-ko/ +/serial_21285.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/serial_amba.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/sh-sci.c/1.12/Thu Jun 28 05:21:16 2001/-ko/ +/sh-sci.h/1.8/Thu Jun 28 05:21:16 2001/-ko/ +/softdog.c/1.11/Tue May 29 19:53:13 2001/-ko/ +/sonypi.c/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/sonypi.h/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/specialix.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/specialix_io8.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/stallion.c/1.15/Mon Apr 2 17:13:32 2001/-ko/ +/sx.c/1.19/Thu Jul 5 06:13:42 2001/-ko/ +/sx.h/1.4/Thu Jun 28 05:21:16 2001/-ko/ +/sxboards.h/1.2/Wed Mar 15 18:02:00 2000/-ko/ +/sxwindow.h/1.1/Sun Aug 29 02:07:15 1999/-ko/ +/synclink.c/1.15/Tue May 29 19:53:13 2001/-ko/ +/sysrq.c/1.13/Thu Feb 22 21:09:04 2001/-ko/ +/toshiba.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/tpqic02.c/1.12/Mon Apr 2 17:13:32 2001/-ko/ +/tty_io.c/1.31/Tue Jul 3 02:33:57 2001/-ko/ +/tty_ioctl.c/1.3/Mon Sep 6 21:36:14 1999/-ko/ +/vc_screen.c/1.10/Wed Nov 1 21:35:42 2000/-ko/ +/vino.h/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/vme_scc.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/vt.c/1.18/Thu Feb 22 21:09:04 2001/-ko/ +/w83877f_wdt.c/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/wd501p.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/wdt.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/wdt285.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/wdt977.c/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/wdt_pci.c/1.5/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/char/CVS/Entries.Log linux-2.4-xfs/linux/drivers/char/CVS/Entries.Log --- linux-2.4.7/linux/drivers/char/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/CVS/Entries.Log Thu Jul 5 11:53:04 2001 @@ -0,0 +1,7 @@ +A D/agp//// +A D/drm//// +A D/ftape//// +A D/ip2//// +A D/joystick//// +A D/pcmcia//// +A D/rio//// diff -rNu linux-2.4.7/linux/drivers/char/CVS/Repository linux-2.4-xfs/linux/drivers/char/CVS/Repository --- linux-2.4.7/linux/drivers/char/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/CVS/Repository Thu Jul 5 11:52:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/char diff -rNu linux-2.4.7/linux/drivers/char/CVS/Root linux-2.4-xfs/linux/drivers/char/CVS/Root --- linux-2.4.7/linux/drivers/char/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/CVS/Root Thu Jul 5 11:52:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/char/Makefile linux-2.4-xfs/linux/drivers/char/Makefile --- linux-2.4.7/linux/drivers/char/Makefile Thu Jul 5 10:49:35 2001 +++ linux-2.4-xfs/linux/drivers/char/Makefile Thu Jul 5 01:13:42 2001 @@ -241,5 +241,9 @@ consolemap_deftbl.o: consolemap_deftbl.c $(TOPDIR)/include/linux/types.h +# Simple pipe does not work, it ignores return codes from loadkeys defkeymap.c: defkeymap.map - loadkeys --mktable defkeymap.map > defkeymap.c + loadkeys --mktable defkeymap.map > .tmp_a_$@ + sed -e 's/^static *//' .tmp_a_$@ > .tmp_b_$@ + rm .tmp_a_$@ + mv .tmp_b_$@ $@ diff -rNu linux-2.4.7/linux/drivers/char/agp/CVS/Entries linux-2.4-xfs/linux/drivers/char/agp/CVS/Entries --- linux-2.4.7/linux/drivers/char/agp/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/agp/CVS/Entries Thu Jul 5 11:52:45 2001 @@ -0,0 +1,5 @@ +/Makefile/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/agp.h/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/agpgart_be.c/1.17/Tue Jul 3 02:33:57 2001/-ko/ +/agpgart_fe.c/1.11/Thu Jun 28 05:21:16 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/char/agp/CVS/Repository linux-2.4-xfs/linux/drivers/char/agp/CVS/Repository --- linux-2.4.7/linux/drivers/char/agp/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/agp/CVS/Repository Thu Jul 5 11:52:44 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/char/agp diff -rNu linux-2.4.7/linux/drivers/char/agp/CVS/Root linux-2.4-xfs/linux/drivers/char/agp/CVS/Root --- linux-2.4.7/linux/drivers/char/agp/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/agp/CVS/Root Thu Jul 5 11:52:44 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/char/drm/CVS/Entries linux-2.4-xfs/linux/drivers/char/drm/CVS/Entries --- linux-2.4.7/linux/drivers/char/drm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/drm/CVS/Entries Thu Jul 5 11:52:52 2001 @@ -0,0 +1,57 @@ +/Config.in/1.3/Thu Feb 1 17:10:24 2001/-ko/ +/Makefile/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/README.drm/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/agpsupport.c/1.4/Tue Jul 3 02:33:57 2001/-ko/ +/auth.c/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/bufs.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/context.c/1.6/Thu Jun 28 05:21:16 2001/-ko/ +/ctxbitmap.c/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/dma.c/1.8/Thu Jun 28 05:21:16 2001/-ko/ +/drawable.c/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/drm.h/1.7/Thu Feb 1 17:10:24 2001/-ko/ +/drmP.h/1.11/Mon Apr 2 17:13:32 2001/-ko/ +/ffb_context.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/ffb_drv.c/1.7/Sat Jun 9 02:44:24 2001/-ko/ +/ffb_drv.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/fops.c/1.9/Tue May 29 19:53:13 2001/-ko/ +/gamma_dma.c/1.7/Sun Dec 17 19:15:00 2000/-ko/ +/gamma_drv.c/1.10/Sat Nov 25 08:05:45 2000/-ko/ +/gamma_drv.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/i810_bufs.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/i810_context.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/i810_dma.c/1.6/Thu Jun 28 05:21:16 2001/-ko/ +/i810_drm.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/i810_drv.c/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/i810_drv.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/init.c/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/ioctl.c/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/lists.c/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/lock.c/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/memory.c/1.6/Sat Nov 25 08:05:45 2000/-ko/ +/mga_bufs.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/mga_context.c/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/mga_dma.c/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/mga_drm.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/mga_drv.c/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/mga_drv.h/1.5/Fri Jan 5 18:42:30 2001/-ko/ +/mga_state.c/1.5/Thu Jun 28 05:21:16 2001/-ko/ +/proc.c/1.8/Thu Jun 28 05:21:16 2001/-ko/ +/r128_bufs.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/r128_cce.c/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/r128_context.c/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/r128_drm.h/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/r128_drv.c/1.5/Fri Jan 5 18:42:30 2001/-ko/ +/r128_drv.h/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/r128_state.c/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/radeon_bufs.c/1.3/Thu Jun 28 05:21:16 2001/-ko/ +/radeon_context.c/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/radeon_cp.c/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/radeon_drm.h/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/radeon_drv.c/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/radeon_drv.h/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/radeon_state.c/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/tdfx_context.c/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/tdfx_drv.c/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/tdfx_drv.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/vm.c/1.7/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/char/drm/CVS/Repository linux-2.4-xfs/linux/drivers/char/drm/CVS/Repository --- linux-2.4.7/linux/drivers/char/drm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/drm/CVS/Repository Thu Jul 5 11:52:45 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/char/drm diff -rNu linux-2.4.7/linux/drivers/char/drm/CVS/Root linux-2.4-xfs/linux/drivers/char/drm/CVS/Root --- linux-2.4.7/linux/drivers/char/drm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/drm/CVS/Root Thu Jul 5 11:52:45 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/char/ftape/CVS/Entries linux-2.4-xfs/linux/drivers/char/ftape/CVS/Entries --- linux-2.4.7/linux/drivers/char/ftape/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ftape/CVS/Entries Thu Jul 5 11:52:52 2001 @@ -0,0 +1,5 @@ +/Config.in/1.5/Sat Jan 29 23:00:52 2000/-ko/ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/README.PCI/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/RELEASE-NOTES/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/char/ftape/CVS/Entries.Log linux-2.4-xfs/linux/drivers/char/ftape/CVS/Entries.Log --- linux-2.4.7/linux/drivers/char/ftape/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ftape/CVS/Entries.Log Thu Jul 5 11:52:57 2001 @@ -0,0 +1,3 @@ +A D/compressor//// +A D/lowlevel//// +A D/zftape//// diff -rNu linux-2.4.7/linux/drivers/char/ftape/CVS/Repository linux-2.4-xfs/linux/drivers/char/ftape/CVS/Repository --- linux-2.4.7/linux/drivers/char/ftape/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ftape/CVS/Repository Thu Jul 5 11:52:52 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/char/ftape diff -rNu linux-2.4.7/linux/drivers/char/ftape/CVS/Root linux-2.4-xfs/linux/drivers/char/ftape/CVS/Root --- linux-2.4.7/linux/drivers/char/ftape/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ftape/CVS/Root Thu Jul 5 11:52:52 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/char/ftape/compressor/CVS/Entries linux-2.4-xfs/linux/drivers/char/ftape/compressor/CVS/Entries --- linux-2.4.7/linux/drivers/char/ftape/compressor/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ftape/compressor/CVS/Entries Thu Jul 5 11:52:53 2001 @@ -0,0 +1,6 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/lzrw3.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/lzrw3.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/zftape-compress.c/1.3/Wed Nov 24 20:20:05 1999/-ko/ +/zftape-compress.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/char/ftape/compressor/CVS/Repository linux-2.4-xfs/linux/drivers/char/ftape/compressor/CVS/Repository --- linux-2.4.7/linux/drivers/char/ftape/compressor/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ftape/compressor/CVS/Repository Thu Jul 5 11:52:52 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/char/ftape/compressor diff -rNu linux-2.4.7/linux/drivers/char/ftape/compressor/CVS/Root linux-2.4-xfs/linux/drivers/char/ftape/compressor/CVS/Root --- linux-2.4.7/linux/drivers/char/ftape/compressor/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ftape/compressor/CVS/Root Thu Jul 5 11:52:52 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/char/ftape/lowlevel/CVS/Entries linux-2.4-xfs/linux/drivers/char/ftape/lowlevel/CVS/Entries --- linux-2.4.7/linux/drivers/char/ftape/lowlevel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ftape/lowlevel/CVS/Entries Thu Jul 5 11:52:57 2001 @@ -0,0 +1,37 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/fc-10.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fc-10.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fdc-io.c/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/fdc-io.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fdc-isr.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/fdc-isr.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ftape-bsm.c/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/ftape-bsm.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ftape-buffer.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/ftape-buffer.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ftape-calibr.c/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/ftape-calibr.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ftape-ctl.c/1.5/Sat Nov 25 08:05:45 2000/-ko/ +/ftape-ctl.h/1.3/Wed Nov 24 20:20:05 1999/-ko/ +/ftape-ecc.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ftape-ecc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ftape-format.c/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/ftape-format.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ftape-init.c/1.4/Wed Nov 24 20:20:05 1999/-ko/ +/ftape-init.h/1.3/Wed Nov 24 20:20:05 1999/-ko/ +/ftape-io.c/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/ftape-io.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ftape-proc.c/1.5/Fri Nov 12 18:38:14 1999/-ko/ +/ftape-proc.h/1.3/Wed Nov 24 20:20:05 1999/-ko/ +/ftape-read.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ftape-read.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ftape-rw.c/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/ftape-rw.h/1.3/Wed Nov 24 20:20:05 1999/-ko/ +/ftape-setup.c/1.4/Sun Aug 29 03:33:57 1999/-ko/ +/ftape-tracing.c/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/ftape-tracing.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/ftape-write.c/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/ftape-write.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ftape_syms.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/ftape_syms.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/char/ftape/lowlevel/CVS/Repository linux-2.4-xfs/linux/drivers/char/ftape/lowlevel/CVS/Repository --- linux-2.4.7/linux/drivers/char/ftape/lowlevel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ftape/lowlevel/CVS/Repository Thu Jul 5 11:52:53 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/char/ftape/lowlevel diff -rNu linux-2.4.7/linux/drivers/char/ftape/lowlevel/CVS/Root linux-2.4-xfs/linux/drivers/char/ftape/lowlevel/CVS/Root --- linux-2.4.7/linux/drivers/char/ftape/lowlevel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ftape/lowlevel/CVS/Root Thu Jul 5 11:52:53 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/char/ftape/zftape/CVS/Entries linux-2.4-xfs/linux/drivers/char/ftape/zftape/CVS/Entries --- linux-2.4.7/linux/drivers/char/ftape/zftape/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ftape/zftape/CVS/Entries Thu Jul 5 11:52:58 2001 @@ -0,0 +1,20 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/zftape-buffers.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/zftape-buffers.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/zftape-ctl.c/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/zftape-ctl.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/zftape-eof.c/1.3/Wed Nov 24 20:20:05 1999/-ko/ +/zftape-eof.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/zftape-init.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/zftape-init.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/zftape-read.c/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/zftape-read.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/zftape-rw.c/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/zftape-rw.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/zftape-vtbl.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/zftape-vtbl.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/zftape-write.c/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/zftape-write.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/zftape_syms.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/zftape_syms.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/char/ftape/zftape/CVS/Repository linux-2.4-xfs/linux/drivers/char/ftape/zftape/CVS/Repository --- linux-2.4.7/linux/drivers/char/ftape/zftape/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ftape/zftape/CVS/Repository Thu Jul 5 11:52:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/char/ftape/zftape diff -rNu linux-2.4.7/linux/drivers/char/ftape/zftape/CVS/Root linux-2.4-xfs/linux/drivers/char/ftape/zftape/CVS/Root --- linux-2.4.7/linux/drivers/char/ftape/zftape/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ftape/zftape/CVS/Root Thu Jul 5 11:52:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/char/ip2/CVS/Entries linux-2.4-xfs/linux/drivers/char/ip2/CVS/Entries --- linux-2.4.7/linux/drivers/char/ip2/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ip2/CVS/Entries Thu Jul 5 11:53:02 2001 @@ -0,0 +1,19 @@ +/Makefile/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/fip_firm.h/1.2/Tue May 2 21:09:12 2000/-ko/ +/i2cmd.c/1.3/Thu Jul 5 06:13:42 2001/-ko/ +/i2cmd.h/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/i2ellis.c/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/i2ellis.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/i2hw.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/i2lib.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/i2lib.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/i2os.h/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/i2pack.h/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/ip2.h/1.2/Mon Nov 8 22:55:41 1999/-ko/ +/ip2ioctl.h/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/ip2mkdev.c/1.1/Tue May 2 21:09:12 2000/-ko/ +/ip2stat.c/1.1/Tue May 2 21:09:12 2000/-ko/ +/ip2trace.c/1.1/Tue May 2 21:09:12 2000/-ko/ +/ip2trace.h/1.2/Tue May 2 21:09:12 2000/-ko/ +/ip2types.h/1.1/Mon Aug 30 00:17:07 1999/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/char/ip2/CVS/Repository linux-2.4-xfs/linux/drivers/char/ip2/CVS/Repository --- linux-2.4.7/linux/drivers/char/ip2/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ip2/CVS/Repository Thu Jul 5 11:52:58 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/char/ip2 diff -rNu linux-2.4.7/linux/drivers/char/ip2/CVS/Root linux-2.4-xfs/linux/drivers/char/ip2/CVS/Root --- linux-2.4.7/linux/drivers/char/ip2/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/ip2/CVS/Root Thu Jul 5 11:52:58 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/char/joystick/CVS/Entries linux-2.4-xfs/linux/drivers/char/joystick/CVS/Entries --- linux-2.4.7/linux/drivers/char/joystick/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/joystick/CVS/Entries Thu Jul 5 11:53:04 2001 @@ -0,0 +1,29 @@ +/Config.in/1.7/Wed May 2 06:22:13 2001/-ko/ +/Makefile/1.7/Wed May 2 06:22:13 2001/-ko/ +/a3d.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/adi.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/amijoy.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/analog.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/cobra.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/cs461x.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/db9.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/gamecon.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/gameport.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/gf2k.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/grip.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/iforce.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/interact.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/lightning.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/magellan.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/ns558.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/pcigame.c/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/serio.c/1.2/Wed Nov 1 21:35:42 2000/-ko/ +/serport.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/sidewinder.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/spaceball.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/spaceorb.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/stinger.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/tmdc.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/turbografx.c/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/warrior.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/char/joystick/CVS/Repository linux-2.4-xfs/linux/drivers/char/joystick/CVS/Repository --- linux-2.4.7/linux/drivers/char/joystick/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/joystick/CVS/Repository Thu Jul 5 11:53:02 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/char/joystick diff -rNu linux-2.4.7/linux/drivers/char/joystick/CVS/Root linux-2.4-xfs/linux/drivers/char/joystick/CVS/Root --- linux-2.4.7/linux/drivers/char/joystick/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/joystick/CVS/Root Thu Jul 5 11:53:02 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/char/keyboard.c linux-2.4-xfs/linux/drivers/char/keyboard.c --- linux-2.4.7/linux/drivers/char/keyboard.c Mon Oct 16 14:58:51 2000 +++ linux-2.4-xfs/linux/drivers/char/keyboard.c Wed Nov 1 15:35:42 2000 @@ -42,6 +42,9 @@ #include #include #include +#if defined(CONFIG_KDB) +#include +#endif #define SIZE(x) (sizeof(x)/sizeof((x)[0])) @@ -248,6 +251,13 @@ up_flag = kbd_unexpected_up(keycode); } else rep = test_and_set_bit(keycode, key_down); + +#if defined(CONFIG_KDB) + if (!up_flag && (keycode == E1_PAUSE) && kdb_on) { + kdb(KDB_REASON_KEYBOARD, 0, kbd_pt_regs); + return; + } +#endif /* CONFIG_KDB */ #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == SYSRQ_KEY) { diff -rNu linux-2.4.7/linux/drivers/char/pcmcia/CVS/Entries linux-2.4-xfs/linux/drivers/char/pcmcia/CVS/Entries --- linux-2.4.7/linux/drivers/char/pcmcia/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/pcmcia/CVS/Entries Thu Jul 5 11:53:04 2001 @@ -0,0 +1,4 @@ +/Config.in/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/Makefile/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/serial_cs.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/char/pcmcia/CVS/Repository linux-2.4-xfs/linux/drivers/char/pcmcia/CVS/Repository --- linux-2.4.7/linux/drivers/char/pcmcia/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/pcmcia/CVS/Repository Thu Jul 5 11:53:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/char/pcmcia diff -rNu linux-2.4.7/linux/drivers/char/pcmcia/CVS/Root linux-2.4-xfs/linux/drivers/char/pcmcia/CVS/Root --- linux-2.4.7/linux/drivers/char/pcmcia/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/pcmcia/CVS/Root Thu Jul 5 11:53:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/char/rio/CVS/Entries linux-2.4-xfs/linux/drivers/char/rio/CVS/Entries --- linux-2.4.7/linux/drivers/char/rio/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/rio/CVS/Entries Thu Jul 5 11:53:08 2001 @@ -0,0 +1,79 @@ +/Makefile/1.2/Thu Dec 21 05:48:12 2000/-ko/ +/board.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/bootpkt.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/brates.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/cdproto.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/chan.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/cirrus.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/cmd.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/cmdblk.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/cmdpkt.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/control.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/daemon.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/data.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/debug.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/defaults.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/eisa.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/enable.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/error.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/errors.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/formpkt.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/func.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/host.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/hosthw.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/link.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/linux_compat.h/1.4/Thu Jul 5 06:13:42 2001/-ko/ +/list.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/lrt.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/ltt.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/lttwake.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/map.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/mca.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/mesg.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/param.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/parmmap.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/pci.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/phb.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/pkt.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/poll.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/port.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/proto.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/protsts.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/qbuf.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/rio.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/rio_linux.c/1.9/Thu Jul 5 06:13:42 2001/-ko/ +/rio_linux.h/1.4/Thu Jul 5 06:13:42 2001/-ko/ +/rioboard.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/rioboot.c/1.5/Thu Jul 5 06:13:42 2001/-ko/ +/riocmd.c/1.5/Thu Jul 5 06:13:42 2001/-ko/ +/rioctrl.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/riodrvr.h/1.2/Thu Jul 5 06:13:42 2001/-ko/ +/rioinfo.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/rioinit.c/1.5/Thu Jul 5 06:13:42 2001/-ko/ +/riointr.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/rioioctl.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/riolocks.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/rioparam.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/riopcicopy.c/1.1/Fri May 26 01:14:50 2000/-ko/ +/rioroute.c/1.4/Wed Jun 6 03:10:14 2001/-ko/ +/riospace.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/riotable.c/1.4/Thu Jul 5 06:13:42 2001/-ko/ +/riotime.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/riotty.c/1.5/Thu Jul 5 06:13:42 2001/-ko/ +/riotypes.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/riowinif.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/riscos.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/rom.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/route.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/rtahw.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/rup.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/rupstat.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/sam.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/selftest.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/space.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/sysmap.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/timeouts.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/top.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/typdef.h/1.1/Fri May 26 01:14:50 2000/-ko/ +/unixrup.h/1.2/Fri May 26 01:52:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/char/rio/CVS/Repository linux-2.4-xfs/linux/drivers/char/rio/CVS/Repository --- linux-2.4.7/linux/drivers/char/rio/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/rio/CVS/Repository Thu Jul 5 11:53:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/char/rio diff -rNu linux-2.4.7/linux/drivers/char/rio/CVS/Root linux-2.4-xfs/linux/drivers/char/rio/CVS/Root --- linux-2.4.7/linux/drivers/char/rio/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/char/rio/CVS/Root Thu Jul 5 11:53:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/char/ser_a2232.c linux-2.4-xfs/linux/drivers/char/ser_a2232.c --- linux-2.4.7/linux/drivers/char/ser_a2232.c Thu Jul 5 10:49:36 2001 +++ linux-2.4-xfs/linux/drivers/char/ser_a2232.c Thu Jul 5 01:13:42 2001 @@ -1,6 +1,6 @@ /* drivers/char/ser_a2232.c */ -/* $Id: ser_a2232.c,v 0.4 2000/01/25 12:00:00 ehaase Exp $ */ +/* $Id$ */ /* Linux serial driver for the Amiga A2232 board */ diff -rNu linux-2.4.7/linux/drivers/char/ser_a2232.h linux-2.4-xfs/linux/drivers/char/ser_a2232.h --- linux-2.4.7/linux/drivers/char/ser_a2232.h Thu Jul 5 10:49:36 2001 +++ linux-2.4-xfs/linux/drivers/char/ser_a2232.h Thu Jul 5 01:13:42 2001 @@ -1,6 +1,6 @@ /* drivers/char/ser_a2232.h */ -/* $Id: ser_a2232.h,v 0.4 2000/01/25 12:00:00 ehaase Exp $ */ +/* $Id$ */ /* Linux serial driver for the Amiga A2232 board */ diff -rNu linux-2.4.7/linux/drivers/char/ser_a2232fw.h linux-2.4-xfs/linux/drivers/char/ser_a2232fw.h --- linux-2.4.7/linux/drivers/char/ser_a2232fw.h Thu Jul 5 10:49:36 2001 +++ linux-2.4-xfs/linux/drivers/char/ser_a2232fw.h Thu Jul 5 01:13:42 2001 @@ -1,6 +1,6 @@ /* drivers/char/ser_a2232fw.h */ -/* $Id: ser_a2232fw.h,v 0.4 2000/01/25 12:00:00 ehaase Exp $ */ +/* $Id$ */ /* * Copyright (c) 1995 Jukka Marin . diff -rNu linux-2.4.7/linux/drivers/char/serial.c linux-2.4-xfs/linux/drivers/char/serial.c --- linux-2.4.7/linux/drivers/char/serial.c Sun May 20 14:11:38 2001 +++ linux-2.4-xfs/linux/drivers/char/serial.c Tue May 29 14:53:13 2001 @@ -209,6 +209,29 @@ #include #endif +#if defined(CONFIG_KDB) +#include +/* + * kdb_serial_line records the serial line number of the first serial console. + * NOTE: The kernel ignores characters on the serial line unless a user space + * program has opened the line first. To enter kdb before user space has opened + * the serial line, you can use the 'kdb=early' flag to lilo and set the + * appropriate breakpoints. + * + * kdb_serial_str[] is the sequence that the user must enter on the serial + * console to invoke kdb. It can be a single character such as "\001" + * (control-A) or multiple characters such as "\eKdB". NOTE: All except the + * last character are passed through to the application reading from the serial + * console. + * + * I tried to make the sequence a CONFIG_ option but most of CML1 cannot cope + * with '\' in strings, CML2 should be able to do it. KAO. + */ + +static int kdb_serial_line = -1; +static char kdb_serial_str[] = "\001"; +static char *kdb_serial_ptr = kdb_serial_str; +#endif /* CONFIG_KDB */ /* * All of the compatibilty code so we can compile serial.c against * older kernels is hidden in serial_compat.h @@ -571,6 +594,18 @@ return; // if TTY_DONT_FLIP is set } ch = serial_inp(info, UART_RX); +#if defined(CONFIG_KDB) + if ((info->line == kdb_serial_line) && kdb_on) { + if (ch == *kdb_serial_ptr) { + if (!(*++kdb_serial_ptr)) { + kdb(KDB_REASON_KEYBOARD, 0, (kdb_eframe_t)regs); + kdb_serial_ptr = kdb_serial_str; + break; + } + } else + kdb_serial_ptr = kdb_serial_str; + } +#endif /* CONFIG_KDB */ *tty->flip.char_buf_ptr = ch; icount->rx++; @@ -5801,6 +5836,17 @@ */ if (serial_in(info, UART_LSR) == 0xff) return -1; + +#if defined(CONFIG_KDB) + /* + * Remember the line number of the first serial + * console. We'll make this the kdb serial console too. + */ + if (kdb_serial_line == -1) { + kdb_serial_line = co->index; + kdb_port = state->port; + } +#endif /* CONFIG_KDB */ return 0; } diff -rNu linux-2.4.7/linux/drivers/dio/CVS/Entries linux-2.4-xfs/linux/drivers/dio/CVS/Entries --- linux-2.4.7/linux/drivers/dio/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/dio/CVS/Entries Thu Jul 5 11:53:08 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dio.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/dio/CVS/Repository linux-2.4-xfs/linux/drivers/dio/CVS/Repository --- linux-2.4.7/linux/drivers/dio/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/dio/CVS/Repository Thu Jul 5 11:53:08 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/dio diff -rNu linux-2.4.7/linux/drivers/dio/CVS/Root linux-2.4-xfs/linux/drivers/dio/CVS/Root --- linux-2.4.7/linux/drivers/dio/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/dio/CVS/Root Thu Jul 5 11:53:08 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/fc4/CVS/Entries linux-2.4-xfs/linux/drivers/fc4/CVS/Entries --- linux-2.4.7/linux/drivers/fc4/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/fc4/CVS/Entries Thu Jul 5 11:53:08 2001 @@ -0,0 +1,13 @@ +/Config.in/1.4/Mon Nov 8 22:55:41 1999/-ko/ +/Makefile/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/fc-al.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fc.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/fc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fc_syms.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fcp.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fcp_impl.h/1.4/Sat Jan 29 23:00:52 2000/-ko/ +/soc.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/soc.h/1.4/Thu Jan 6 19:50:16 2000/-ko/ +/socal.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/socal.h/1.3/Wed Dec 29 19:04:31 1999/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/fc4/CVS/Repository linux-2.4-xfs/linux/drivers/fc4/CVS/Repository --- linux-2.4.7/linux/drivers/fc4/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/fc4/CVS/Repository Thu Jul 5 11:53:08 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/fc4 diff -rNu linux-2.4.7/linux/drivers/fc4/CVS/Root linux-2.4-xfs/linux/drivers/fc4/CVS/Root --- linux-2.4.7/linux/drivers/fc4/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/fc4/CVS/Root Thu Jul 5 11:53:08 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/i2c/CVS/Entries linux-2.4-xfs/linux/drivers/i2c/CVS/Entries --- linux-2.4.7/linux/drivers/i2c/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/i2c/CVS/Entries Thu Jul 5 11:53:09 2001 @@ -0,0 +1,12 @@ +/Config.in/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/i2c-algo-bit.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/i2c-algo-pcf.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/i2c-core.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/i2c-dev.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/i2c-elektor.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/i2c-elv.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/i2c-pcf8584.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/i2c-philips-par.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/i2c-velleman.c/1.3/Fri Feb 11 00:45:14 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/i2c/CVS/Repository linux-2.4-xfs/linux/drivers/i2c/CVS/Repository --- linux-2.4.7/linux/drivers/i2c/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/i2c/CVS/Repository Thu Jul 5 11:53:08 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/i2c diff -rNu linux-2.4.7/linux/drivers/i2c/CVS/Root linux-2.4-xfs/linux/drivers/i2c/CVS/Root --- linux-2.4.7/linux/drivers/i2c/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/i2c/CVS/Root Thu Jul 5 11:53:08 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/i2o/CVS/Entries linux-2.4-xfs/linux/drivers/i2o/CVS/Entries --- linux-2.4.7/linux/drivers/i2o/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/i2o/CVS/Entries Thu Jul 5 11:53:10 2001 @@ -0,0 +1,14 @@ +/Config.in/1.4/Tue May 2 21:09:12 2000/-ko/ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/README/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/README.ioctl/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/i2o_block.c/1.22/Tue May 29 19:53:13 2001/-ko/ +/i2o_config.c/1.15/Tue May 29 19:53:13 2001/-ko/ +/i2o_core.c/1.25/Tue May 29 19:53:13 2001/-ko/ +/i2o_lan.c/1.19/Wed Jun 6 03:10:14 2001/-ko/ +/i2o_lan.h/1.9/Mon Jul 31 16:16:28 2000/-ko/ +/i2o_pci.c/1.16/Tue May 29 19:53:13 2001/-ko/ +/i2o_proc.c/1.14/Tue May 29 19:53:13 2001/-ko/ +/i2o_scsi.c/1.11/Tue May 29 19:53:13 2001/-ko/ +/i2o_scsi.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/i2o/CVS/Repository linux-2.4-xfs/linux/drivers/i2o/CVS/Repository --- linux-2.4.7/linux/drivers/i2o/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/i2o/CVS/Repository Thu Jul 5 11:53:09 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/i2o diff -rNu linux-2.4.7/linux/drivers/i2o/CVS/Root linux-2.4-xfs/linux/drivers/i2o/CVS/Root --- linux-2.4.7/linux/drivers/i2o/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/i2o/CVS/Root Thu Jul 5 11:53:09 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/ide/CVS/Entries linux-2.4-xfs/linux/drivers/ide/CVS/Entries --- linux-2.4.7/linux/drivers/ide/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/ide/CVS/Entries Thu Jul 5 11:53:19 2001 @@ -0,0 +1,55 @@ +/Config.in/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/Makefile/1.8/Thu Dec 21 05:48:12 2000/-ko/ +/aec62xx.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/ali14xx.c/1.3/Tue May 2 21:09:12 2000/-ko/ +/alim15x3.c/1.9/Tue May 29 19:53:13 2001/-ko/ +/amd7409.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/buddha.c/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/cmd640.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/cmd64x.c/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/cs5530.c/1.4/Fri Jan 5 18:42:30 2001/-ko/ +/cy82c693.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/dtc2278.c/1.3/Tue May 2 21:36:51 2000/-ko/ +/falconide.c/1.3/Tue May 2 21:36:51 2000/-ko/ +/gayle.c/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/hd.c/1.9/Tue May 29 19:53:13 2001/-ko/ +/hpt34x.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/hpt366.c/1.9/Thu Jun 28 05:21:16 2001/-ko/ +/ht6560b.c/1.3/Tue May 2 21:36:51 2000/-ko/ +/icside.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/ide-cd.c/1.13/Tue May 29 19:53:13 2001/-ko/ +/ide-cd.h/1.6/Fri Jan 5 18:42:30 2001/-ko/ +/ide-cs.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/ide-disk.c/1.13/Tue Apr 3 23:07:43 2001/-ko/ +/ide-dma.c/1.10/Tue Apr 3 23:07:43 2001/-ko/ +/ide-features.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/ide-floppy.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/ide-geometry.c/1.7/Fri Jan 5 18:42:30 2001/-ko/ +/ide-pci.c/1.14/Thu Jun 28 05:21:16 2001/-ko/ +/ide-pmac.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/ide-pnp.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/ide-probe.c/1.14/Mon Apr 2 17:13:32 2001/-ko/ +/ide-proc.c/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/ide-tape.c/1.12/Thu Jul 5 06:13:42 2001/-ko/ +/ide-timing.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ide.c/1.22/Tue May 29 19:53:13 2001/-ko/ +/ide_modes.h/1.3/Tue May 2 21:36:51 2000/-ko/ +/macide.c/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/ns87415.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/opti621.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/osb4.c/1.4/Tue May 29 19:53:13 2001/-ko/ +/pdc202xx.c/1.8/Tue May 29 19:53:13 2001/-ko/ +/pdc4030.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/pdc4030.h/1.1/Wed Mar 15 18:02:00 2000/-ko/ +/piix.c/1.10/Thu Jun 21 15:45:04 2001/-ko/ +/q40ide.c/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/qd6580.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/rapide.c/1.5/Thu Jun 28 05:21:16 2001/-ko/ +/rz1000.c/1.4/Tue May 29 19:53:13 2001/-ko/ +/sis5513.c/1.9/Tue May 29 19:53:13 2001/-ko/ +/sl82c105.c/1.4/Thu Jun 28 05:21:16 2001/-ko/ +/slc90e66.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/trm290.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/umc8672.c/1.3/Tue May 2 21:36:51 2000/-ko/ +/via82cxxx.c/1.13/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/ide/CVS/Repository linux-2.4-xfs/linux/drivers/ide/CVS/Repository --- linux-2.4.7/linux/drivers/ide/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/ide/CVS/Repository Thu Jul 5 11:53:10 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/ide diff -rNu linux-2.4.7/linux/drivers/ide/CVS/Root linux-2.4-xfs/linux/drivers/ide/CVS/Root --- linux-2.4.7/linux/drivers/ide/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/ide/CVS/Root Thu Jul 5 11:53:10 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/ide/ide.c linux-2.4-xfs/linux/drivers/ide/ide.c --- linux-2.4.7/linux/drivers/ide/ide.c Tue May 1 18:05:00 2001 +++ linux-2.4-xfs/linux/drivers/ide/ide.c Tue May 29 14:53:13 2001 @@ -2668,6 +2668,8 @@ case BLKPG: case BLKELVGET: case BLKELVSET: + case BLKBSZGET: + case BLKBSZSET: return blk_ioctl(inode->i_rdev, cmd, arg); default: diff -rNu linux-2.4.7/linux/drivers/ieee1394/CVS/Entries linux-2.4-xfs/linux/drivers/ieee1394/CVS/Entries --- linux-2.4.7/linux/drivers/ieee1394/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/ieee1394/CVS/Entries Thu Jul 5 11:53:26 2001 @@ -0,0 +1,28 @@ +/Config.in/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/Makefile/1.5/Fri Jan 5 18:42:30 2001/-ko/ +/aic5800.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/aic5800.h/1.1/Fri Jan 21 19:18:03 2000/-ko/ +/csr.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/csr.h/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/guid.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/guid.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/highlevel.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/highlevel.h/1.2/Fri Mar 24 21:14:53 2000/-ko/ +/hosts.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/hosts.h/1.4/Fri Jan 5 18:42:30 2001/-ko/ +/ieee1394.h/1.2/Fri Mar 24 21:14:53 2000/-ko/ +/ieee1394_core.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/ieee1394_core.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/ieee1394_syms.c/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/ieee1394_transactions.c/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/ieee1394_transactions.h/1.2/Tue Feb 1 23:02:54 2000/-ko/ +/ieee1394_types.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/ohci1394.c/1.11/Mon Apr 2 17:13:32 2001/-ko/ +/ohci1394.h/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/pcilynx.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/pcilynx.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/raw1394.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/raw1394.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/video1394.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/video1394.h/1.3/Fri Jan 5 18:42:30 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/ieee1394/CVS/Repository linux-2.4-xfs/linux/drivers/ieee1394/CVS/Repository --- linux-2.4.7/linux/drivers/ieee1394/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/ieee1394/CVS/Repository Thu Jul 5 11:53:19 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/ieee1394 diff -rNu linux-2.4.7/linux/drivers/ieee1394/CVS/Root linux-2.4-xfs/linux/drivers/ieee1394/CVS/Root --- linux-2.4.7/linux/drivers/ieee1394/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/ieee1394/CVS/Root Thu Jul 5 11:53:19 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/input/CVS/Entries linux-2.4-xfs/linux/drivers/input/CVS/Entries --- linux-2.4.7/linux/drivers/input/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/input/CVS/Entries Thu Jul 5 11:53:27 2001 @@ -0,0 +1,8 @@ +/Config.in/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/Makefile/1.2/Thu Dec 21 05:48:12 2000/-ko/ +/evdev.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/input.c/1.3/Sat Nov 25 08:05:45 2000/-ko/ +/joydev.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/keybdev.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/mousedev.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/input/CVS/Repository linux-2.4-xfs/linux/drivers/input/CVS/Repository --- linux-2.4.7/linux/drivers/input/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/input/CVS/Repository Thu Jul 5 11:53:26 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/input diff -rNu linux-2.4.7/linux/drivers/input/CVS/Root linux-2.4-xfs/linux/drivers/input/CVS/Root --- linux-2.4.7/linux/drivers/input/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/input/CVS/Root Thu Jul 5 11:53:26 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/isdn/CVS/Entries linux-2.4-xfs/linux/drivers/isdn/CVS/Entries --- linux-2.4.7/linux/drivers/isdn/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/CVS/Entries Thu Jul 5 11:53:34 2001 @@ -0,0 +1,22 @@ +/Config.in/1.17/Tue Jul 3 02:33:57 2001/-ko/ +/Makefile/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/isdn_audio.c/1.7/Thu Sep 28 22:42:39 2000/-ko/ +/isdn_audio.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/isdn_bsdcomp.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/isdn_common.c/1.25/Tue Jul 3 02:33:57 2001/-ko/ +/isdn_common.h/1.7/Sun Dec 17 19:15:00 2000/-ko/ +/isdn_concap.c/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/isdn_concap.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/isdn_net.c/1.20/Tue Jul 3 02:33:57 2001/-ko/ +/isdn_net.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/isdn_ppp.c/1.15/Wed Jun 13 03:24:09 2001/-ko/ +/isdn_ppp.h/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/isdn_tty.c/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/isdn_tty.h/1.8/Thu Sep 28 22:42:39 2000/-ko/ +/isdn_ttyfax.c/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/isdn_ttyfax.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/isdn_v110.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/isdn_v110.h/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/isdn_x25iface.c/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/isdn_x25iface.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/isdn/CVS/Entries.Log linux-2.4-xfs/linux/drivers/isdn/CVS/Entries.Log --- linux-2.4.7/linux/drivers/isdn/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/CVS/Entries.Log Thu Jul 5 11:53:56 2001 @@ -0,0 +1,11 @@ +A D/act2000//// +A D/avmb1//// +A D/divert//// +A D/eicon//// +A D/hisax//// +A D/hysdn//// +A D/icn//// +A D/isdnloop//// +A D/pcbit//// +A D/sc//// +A D/tpam//// diff -rNu linux-2.4.7/linux/drivers/isdn/CVS/Repository linux-2.4-xfs/linux/drivers/isdn/CVS/Repository --- linux-2.4.7/linux/drivers/isdn/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/CVS/Repository Thu Jul 5 11:53:27 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/isdn diff -rNu linux-2.4.7/linux/drivers/isdn/CVS/Root linux-2.4-xfs/linux/drivers/isdn/CVS/Root --- linux-2.4.7/linux/drivers/isdn/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/CVS/Root Thu Jul 5 11:53:27 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/isdn/act2000/CVS/Entries linux-2.4-xfs/linux/drivers/isdn/act2000/CVS/Entries --- linux-2.4.7/linux/drivers/isdn/act2000/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/act2000/CVS/Entries Thu Jul 5 11:53:35 2001 @@ -0,0 +1,8 @@ +/Makefile/1.5/Wed Jan 3 01:43:05 2001/-ko/ +/act2000.h/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/act2000_isa.c/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/act2000_isa.h/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/capi.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/capi.h/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/module.c/1.6/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/isdn/act2000/CVS/Repository linux-2.4-xfs/linux/drivers/isdn/act2000/CVS/Repository --- linux-2.4.7/linux/drivers/isdn/act2000/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/act2000/CVS/Repository Thu Jul 5 11:53:34 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/isdn/act2000 diff -rNu linux-2.4.7/linux/drivers/isdn/act2000/CVS/Root linux-2.4-xfs/linux/drivers/isdn/act2000/CVS/Root --- linux-2.4.7/linux/drivers/isdn/act2000/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/act2000/CVS/Root Thu Jul 5 11:53:34 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/isdn/avmb1/CVS/Entries linux-2.4-xfs/linux/drivers/isdn/avmb1/CVS/Entries --- linux-2.4.7/linux/drivers/isdn/avmb1/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/avmb1/CVS/Entries Thu Jul 5 11:53:37 2001 @@ -0,0 +1,23 @@ +/Makefile/1.11/Wed Jan 3 01:43:05 2001/-ko/ +/avm_cs.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/avmcard.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/b1.c/1.13/Wed Jun 13 03:24:09 2001/-ko/ +/b1dma.c/1.14/Wed Jun 13 03:24:09 2001/-ko/ +/b1isa.c/1.10/Wed Jun 13 03:24:09 2001/-ko/ +/b1pci.c/1.14/Wed Jun 13 03:24:09 2001/-ko/ +/b1pcmcia.c/1.12/Wed Jun 13 03:24:09 2001/-ko/ +/c4.c/1.14/Thu Jun 28 05:21:16 2001/-ko/ +/capi.c/1.22/Thu Jun 28 05:21:16 2001/-ko/ +/capicmd.h/1.4/Wed Jun 13 03:24:09 2001/-ko/ +/capidev.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/capidrv.c/1.17/Tue May 29 19:53:13 2001/-ko/ +/capidrv.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/capifs.c/1.11/Wed Jun 13 03:24:09 2001/-ko/ +/capifs.h/1.2/Wed Jun 13 03:24:09 2001/-ko/ +/capilli.h/1.1/Sun Aug 29 03:33:57 1999/-ko/ +/capiutil.c/1.8/Tue May 29 19:53:13 2001/-ko/ +/capiutil.h/1.5/Wed Jun 13 03:24:09 2001/-ko/ +/kcapi.c/1.14/Thu Jun 28 05:21:16 2001/-ko/ +/t1isa.c/1.12/Wed Jun 13 03:24:09 2001/-ko/ +/t1pci.c/1.13/Wed Jun 13 03:24:09 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/isdn/avmb1/CVS/Repository linux-2.4-xfs/linux/drivers/isdn/avmb1/CVS/Repository --- linux-2.4.7/linux/drivers/isdn/avmb1/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/avmb1/CVS/Repository Thu Jul 5 11:53:35 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/isdn/avmb1 diff -rNu linux-2.4.7/linux/drivers/isdn/avmb1/CVS/Root linux-2.4-xfs/linux/drivers/isdn/avmb1/CVS/Root --- linux-2.4.7/linux/drivers/isdn/avmb1/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/avmb1/CVS/Root Thu Jul 5 11:53:35 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/isdn/divert/CVS/Entries linux-2.4-xfs/linux/drivers/isdn/divert/CVS/Entries --- linux-2.4.7/linux/drivers/isdn/divert/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/divert/CVS/Entries Thu Jul 5 11:53:37 2001 @@ -0,0 +1,6 @@ +/Makefile/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/divert_init.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/divert_procfs.c/1.12/Sun Dec 17 19:15:00 2000/-ko/ +/isdn_divert.c/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/isdn_divert.h/1.4/Sat Nov 25 08:05:45 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/isdn/divert/CVS/Repository linux-2.4-xfs/linux/drivers/isdn/divert/CVS/Repository --- linux-2.4.7/linux/drivers/isdn/divert/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/divert/CVS/Repository Thu Jul 5 11:53:37 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/isdn/divert diff -rNu linux-2.4.7/linux/drivers/isdn/divert/CVS/Root linux-2.4-xfs/linux/drivers/isdn/divert/CVS/Root --- linux-2.4.7/linux/drivers/isdn/divert/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/divert/CVS/Root Thu Jul 5 11:53:37 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/isdn/eicon/CVS/Entries linux-2.4-xfs/linux/drivers/isdn/eicon/CVS/Entries --- linux-2.4.7/linux/drivers/isdn/eicon/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/eicon/CVS/Entries Thu Jul 5 11:53:40 2001 @@ -0,0 +1,38 @@ +/Divas_mod.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/Makefile/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/adapter.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/bri.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/common.c/1.5/Thu Jun 28 05:21:16 2001/-ko/ +/constant.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/divalog.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/divas.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/dsp_defs.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/dspdids.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/eicon.h/1.10/Tue May 29 19:53:13 2001/-ko/ +/eicon_dsp.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/eicon_idi.c/1.11/Wed May 2 06:22:13 2001/-ko/ +/eicon_idi.h/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/eicon_io.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/eicon_isa.c/1.7/Thu Sep 28 22:42:39 2000/-ko/ +/eicon_isa.h/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/eicon_mod.c/1.12/Mon Apr 2 17:13:32 2001/-ko/ +/eicon_pci.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/eicon_pci.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/fourbri.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/fpga.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/idi.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/idi.h/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/kprintf.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/lincfg.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/linchr.c/1.4/Thu Jun 28 05:21:16 2001/-ko/ +/linio.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/linsys.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/log.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/pc.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/pc_maint.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/pr_pc.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/pri.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/sys.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/uxio.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/xlog.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/isdn/eicon/CVS/Repository linux-2.4-xfs/linux/drivers/isdn/eicon/CVS/Repository --- linux-2.4.7/linux/drivers/isdn/eicon/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/eicon/CVS/Repository Thu Jul 5 11:53:37 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/isdn/eicon diff -rNu linux-2.4.7/linux/drivers/isdn/eicon/CVS/Root linux-2.4-xfs/linux/drivers/isdn/eicon/CVS/Root --- linux-2.4.7/linux/drivers/isdn/eicon/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/eicon/CVS/Root Thu Jul 5 11:53:37 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/isdn/hisax/CVS/Entries linux-2.4-xfs/linux/drivers/isdn/hisax/CVS/Entries --- linux-2.4.7/linux/drivers/isdn/hisax/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/hisax/CVS/Entries Thu Jul 5 11:53:52 2001 @@ -0,0 +1,82 @@ +/Makefile/1.11/Wed May 2 06:22:13 2001/-ko/ +/amd7930.c/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/arcofi.c/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/arcofi.h/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/asuscom.c/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/avm_a1.c/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/avm_a1p.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/avm_pci.c/1.11/Tue Jul 3 02:33:57 2001/-ko/ +/bkm_a4t.c/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/bkm_a8.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/bkm_ax.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/callc.c/1.13/Tue Jul 3 02:33:57 2001/-ko/ +/cert.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/config.c/1.19/Tue Jul 3 02:33:57 2001/-ko/ +/diva.c/1.13/Mon Apr 2 17:13:32 2001/-ko/ +/elsa.c/1.11/Mon Apr 2 17:13:32 2001/-ko/ +/elsa_cs.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/elsa_ser.c/1.8/Tue Jul 3 02:33:57 2001/-ko/ +/fsm.c/1.8/Wed Jun 13 03:24:09 2001/-ko/ +/gazel.c/1.9/Wed Jun 13 03:24:09 2001/-ko/ +/hfc_2bds0.c/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/hfc_2bds0.h/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/hfc_2bs0.c/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/hfc_2bs0.h/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/hfc_pci.c/1.16/Tue Jul 3 02:33:57 2001/-ko/ +/hfc_pci.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/hfc_sx.c/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/hfc_sx.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/hfcscard.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/hisax.h/1.18/Tue Jul 3 02:33:57 2001/-ko/ +/hscx.c/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/hscx.h/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/hscx_irq.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/icc.c/1.4/Tue Jul 3 02:33:57 2001/-ko/ +/icc.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/ipac.h/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/isac.c/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/isac.h/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/isar.c/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/isar.h/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/isdnl1.c/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/isdnl1.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/isdnl2.c/1.11/Tue Jul 3 02:33:57 2001/-ko/ +/isdnl2.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/isdnl3.c/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/isdnl3.h/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/isurf.c/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/ix1_micro.c/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/jade.c/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/jade.h/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/jade_irq.c/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/l3_1tr6.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/l3_1tr6.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/l3dss1.c/1.11/Mon Apr 2 17:13:32 2001/-ko/ +/l3dss1.h/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/l3ni1.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/l3ni1.h/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/lmgr.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/md/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/md5sums.asc/1.13/Tue Jul 3 02:33:57 2001/-ko/ +/mic.c/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/netjet.c/1.16/Tue Jul 3 02:33:57 2001/-ko/ +/netjet.h/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/niccy.c/1.12/Mon Apr 2 17:13:32 2001/-ko/ +/nj_s.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/nj_u.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/q931.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/rawhdlc.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/rawhdlc.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/s0box.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/saphir.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/sedlbauer.c/1.14/Mon Apr 2 17:13:32 2001/-ko/ +/sedlbauer_cs.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/sportster.c/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/tei.c/1.8/Wed Jun 13 03:24:09 2001/-ko/ +/teleint.c/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/teles0.c/1.11/Mon Apr 2 17:13:32 2001/-ko/ +/teles3.c/1.11/Mon Apr 2 17:13:32 2001/-ko/ +/telespci.c/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/w6692.c/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/w6692.h/1.3/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/isdn/hisax/CVS/Repository linux-2.4-xfs/linux/drivers/isdn/hisax/CVS/Repository --- linux-2.4.7/linux/drivers/isdn/hisax/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/hisax/CVS/Repository Thu Jul 5 11:53:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/isdn/hisax diff -rNu linux-2.4.7/linux/drivers/isdn/hisax/CVS/Root linux-2.4-xfs/linux/drivers/isdn/hisax/CVS/Root --- linux-2.4.7/linux/drivers/isdn/hisax/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/hisax/CVS/Root Thu Jul 5 11:53:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/isdn/hysdn/CVS/Entries linux-2.4-xfs/linux/drivers/isdn/hysdn/CVS/Entries --- linux-2.4.7/linux/drivers/isdn/hysdn/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/hysdn/CVS/Entries Thu Jul 5 11:53:53 2001 @@ -0,0 +1,15 @@ +/Makefile/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/boardergo.c/1.9/Tue May 29 19:53:13 2001/-ko/ +/boardergo.h/1.2/Sat Nov 25 08:05:45 2000/-ko/ +/hycapi.c/1.7/Wed Jun 13 03:24:09 2001/-ko/ +/hysdn_boot.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/hysdn_defs.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/hysdn_init.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/hysdn_net.c/1.8/Wed Jun 13 03:24:09 2001/-ko/ +/hysdn_pof.h/1.2/Sat Nov 25 08:05:45 2000/-ko/ +/hysdn_procconf.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/hysdn_procfs.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/hysdn_proclog.c/1.9/Wed Jun 13 03:24:09 2001/-ko/ +/hysdn_sched.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/ince1pc.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/isdn/hysdn/CVS/Repository linux-2.4-xfs/linux/drivers/isdn/hysdn/CVS/Repository --- linux-2.4.7/linux/drivers/isdn/hysdn/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/hysdn/CVS/Repository Thu Jul 5 11:53:52 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/isdn/hysdn diff -rNu linux-2.4.7/linux/drivers/isdn/hysdn/CVS/Root linux-2.4-xfs/linux/drivers/isdn/hysdn/CVS/Root --- linux-2.4.7/linux/drivers/isdn/hysdn/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/hysdn/CVS/Root Thu Jul 5 11:53:52 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/isdn/icn/CVS/Entries linux-2.4-xfs/linux/drivers/isdn/icn/CVS/Entries --- linux-2.4.7/linux/drivers/isdn/icn/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/icn/CVS/Entries Thu Jul 5 11:53:54 2001 @@ -0,0 +1,4 @@ +/Makefile/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/icn.c/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/icn.h/1.7/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/isdn/icn/CVS/Repository linux-2.4-xfs/linux/drivers/isdn/icn/CVS/Repository --- linux-2.4.7/linux/drivers/isdn/icn/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/icn/CVS/Repository Thu Jul 5 11:53:53 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/isdn/icn diff -rNu linux-2.4.7/linux/drivers/isdn/icn/CVS/Root linux-2.4-xfs/linux/drivers/isdn/icn/CVS/Root --- linux-2.4.7/linux/drivers/isdn/icn/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/icn/CVS/Root Thu Jul 5 11:53:53 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/isdn/isdnloop/CVS/Entries linux-2.4-xfs/linux/drivers/isdn/isdnloop/CVS/Entries --- linux-2.4.7/linux/drivers/isdn/isdnloop/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/isdnloop/CVS/Entries Thu Jul 5 11:53:54 2001 @@ -0,0 +1,4 @@ +/Makefile/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/isdnloop.c/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/isdnloop.h/1.6/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/isdn/isdnloop/CVS/Repository linux-2.4-xfs/linux/drivers/isdn/isdnloop/CVS/Repository --- linux-2.4.7/linux/drivers/isdn/isdnloop/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/isdnloop/CVS/Repository Thu Jul 5 11:53:54 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/isdn/isdnloop diff -rNu linux-2.4.7/linux/drivers/isdn/isdnloop/CVS/Root linux-2.4-xfs/linux/drivers/isdn/isdnloop/CVS/Root --- linux-2.4.7/linux/drivers/isdn/isdnloop/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/isdnloop/CVS/Root Thu Jul 5 11:53:54 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/isdn/pcbit/CVS/Entries linux-2.4-xfs/linux/drivers/isdn/pcbit/CVS/Entries --- linux-2.4.7/linux/drivers/isdn/pcbit/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/pcbit/CVS/Entries Thu Jul 5 11:53:55 2001 @@ -0,0 +1,13 @@ +/Makefile/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/callbacks.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/callbacks.h/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/capi.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/capi.h/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/drv.c/1.12/Wed May 2 06:22:13 2001/-ko/ +/edss1.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/edss1.h/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/layer2.c/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/layer2.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/module.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/pcbit.h/1.6/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/isdn/pcbit/CVS/Repository linux-2.4-xfs/linux/drivers/isdn/pcbit/CVS/Repository --- linux-2.4.7/linux/drivers/isdn/pcbit/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/pcbit/CVS/Repository Thu Jul 5 11:53:54 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/isdn/pcbit diff -rNu linux-2.4.7/linux/drivers/isdn/pcbit/CVS/Root linux-2.4-xfs/linux/drivers/isdn/pcbit/CVS/Root --- linux-2.4.7/linux/drivers/isdn/pcbit/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/pcbit/CVS/Root Thu Jul 5 11:53:54 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/isdn/sc/CVS/Entries linux-2.4-xfs/linux/drivers/isdn/sc/CVS/Entries --- linux-2.4.7/linux/drivers/isdn/sc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/sc/CVS/Entries Thu Jul 5 11:53:56 2001 @@ -0,0 +1,18 @@ +/Makefile/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/card.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/command.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/debug.c/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/debug.h/1.4/Sun Feb 27 22:37:25 2000/-ko/ +/event.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/hardware.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/includes.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/init.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/interrupt.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/ioctl.c/1.3/Fri Nov 12 18:38:14 1999/-ko/ +/message.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/message.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/packet.c/1.3/Fri Nov 12 18:38:14 1999/-ko/ +/scioc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/shmem.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/timer.c/1.4/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/isdn/sc/CVS/Repository linux-2.4-xfs/linux/drivers/isdn/sc/CVS/Repository --- linux-2.4.7/linux/drivers/isdn/sc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/sc/CVS/Repository Thu Jul 5 11:53:55 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/isdn/sc diff -rNu linux-2.4.7/linux/drivers/isdn/sc/CVS/Root linux-2.4-xfs/linux/drivers/isdn/sc/CVS/Root --- linux-2.4.7/linux/drivers/isdn/sc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/sc/CVS/Root Thu Jul 5 11:53:55 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/isdn/tpam/CVS/Entries linux-2.4-xfs/linux/drivers/isdn/tpam/CVS/Entries --- linux-2.4.7/linux/drivers/isdn/tpam/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/tpam/CVS/Entries Thu Jul 5 11:53:57 2001 @@ -0,0 +1,10 @@ +/Makefile/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/tpam.h/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/tpam_commands.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/tpam_crcpc.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/tpam_hdlc.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/tpam_main.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/tpam_memory.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/tpam_nco.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/tpam_queues.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/isdn/tpam/CVS/Repository linux-2.4-xfs/linux/drivers/isdn/tpam/CVS/Repository --- linux-2.4.7/linux/drivers/isdn/tpam/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/tpam/CVS/Repository Thu Jul 5 11:53:56 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/isdn/tpam diff -rNu linux-2.4.7/linux/drivers/isdn/tpam/CVS/Root linux-2.4-xfs/linux/drivers/isdn/tpam/CVS/Root --- linux-2.4.7/linux/drivers/isdn/tpam/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/isdn/tpam/CVS/Root Thu Jul 5 11:53:56 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/macintosh/CVS/Entries linux-2.4-xfs/linux/drivers/macintosh/CVS/Entries --- linux-2.4.7/linux/drivers/macintosh/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/macintosh/CVS/Entries Thu Jul 5 11:54:01 2001 @@ -0,0 +1,19 @@ +/Makefile/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/adb-iop.c/1.2/Thu Feb 17 20:46:04 2000/-ko/ +/adb.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/adbhid.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/mac_hid.c/1.2/Thu Jun 28 05:21:16 2001/-ko/ +/mac_keyb.c/1.14/Thu Jun 28 05:21:16 2001/-ko/ +/macio-adb.c/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/mackeymap.map/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/macserial.c/1.17/Thu Jun 28 05:21:16 2001/-ko/ +/macserial.h/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/mediabay.c/1.11/Mon Oct 23 18:56:35 2000/-ko/ +/nvram.c/1.8/Mon Oct 23 18:56:35 2000/-ko/ +/rtc.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/via-cuda.c/1.8/Tue May 29 19:53:13 2001/-ko/ +/via-macii.c/1.2/Sun Dec 17 19:15:00 2000/-ko/ +/via-maciisi.c/1.1/Mon Feb 14 19:32:36 2000/-ko/ +/via-pmu.c/1.14/Tue Jul 3 02:33:57 2001/-ko/ +/via-pmu68k.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/macintosh/CVS/Repository linux-2.4-xfs/linux/drivers/macintosh/CVS/Repository --- linux-2.4.7/linux/drivers/macintosh/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/macintosh/CVS/Repository Thu Jul 5 11:53:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/macintosh diff -rNu linux-2.4.7/linux/drivers/macintosh/CVS/Root linux-2.4-xfs/linux/drivers/macintosh/CVS/Root --- linux-2.4.7/linux/drivers/macintosh/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/macintosh/CVS/Root Thu Jul 5 11:53:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/md/CVS/Entries linux-2.4-xfs/linux/drivers/md/CVS/Entries --- linux-2.4.7/linux/drivers/md/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/md/CVS/Entries Thu Jul 5 11:54:04 2001 @@ -0,0 +1,14 @@ +/Config.in/1.2/Thu Feb 1 17:10:24 2001/-ko/ +/Makefile/1.4/Tue Mar 20 20:10:08 2001/-ko/ +/linear.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/lvm-fs.c/1.1/Tue Mar 20 20:10:08 2001/-ko/ +/lvm-internal.h/1.1/Tue Mar 20 20:10:08 2001/-ko/ +/lvm-snap.c/1.4/Tue Mar 20 20:10:08 2001/-ko/ +/lvm-snap.h/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/lvm.c/1.12/Wed May 2 07:48:52 2001/-ko/ +/md.c/1.16/Tue Jul 3 02:33:57 2001/-ko/ +/raid0.c/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/raid1.c/1.10/Mon Jul 2 15:59:04 2001/-ko/ +/raid5.c/1.16/Thu Jun 21 15:45:04 2001/-ko/ +/xor.c/1.4/Thu Feb 1 17:10:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/md/CVS/Repository linux-2.4-xfs/linux/drivers/md/CVS/Repository --- linux-2.4.7/linux/drivers/md/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/md/CVS/Repository Thu Jul 5 11:54:01 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/md diff -rNu linux-2.4.7/linux/drivers/md/CVS/Root linux-2.4-xfs/linux/drivers/md/CVS/Root --- linux-2.4.7/linux/drivers/md/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/md/CVS/Root Thu Jul 5 11:54:01 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/md/Makefile linux-2.4-xfs/linux/drivers/md/Makefile --- linux-2.4.7/linux/drivers/md/Makefile Fri Dec 29 16:07:22 2000 +++ linux-2.4-xfs/linux/drivers/md/Makefile Tue Mar 20 14:10:08 2001 @@ -6,7 +6,7 @@ export-objs := md.o xor.o list-multi := lvm-mod.o -lvm-mod-objs := lvm.o lvm-snap.o +lvm-mod-objs := lvm.o lvm-snap.o lvm-fs.o # Note: link order is important. All raid personalities # and xor.o must come before md.o, as they each initialise diff -rNu linux-2.4.7/linux/drivers/md/lvm-fs.c linux-2.4-xfs/linux/drivers/md/lvm-fs.c --- linux-2.4.7/linux/drivers/md/lvm-fs.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/md/lvm-fs.c Tue Mar 20 14:10:08 2001 @@ -0,0 +1,596 @@ +/* + * kernel/lvm-fs.c + * + * Copyright (C) 2001 Sistina Software + * + * January,February 2001 + * + * LVM driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * LVM driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/* + * Changelog + * + * 11/01/2001 - First version (Joe Thornber) + * + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "lvm-internal.h" + + +static int _proc_read_vg(char *page, char **start, off_t off, + int count, int *eof, void *data); +static int _proc_read_lv(char *page, char **start, off_t off, + int count, int *eof, void *data); +static int _proc_read_pv(char *page, char **start, off_t off, + int count, int *eof, void *data); +static int _proc_read_global(char *page, char **start, off_t off, + int count, int *eof, void *data); + +static int _vg_info(vg_t *vg_ptr, char *buf); +static int _lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf); +static int _pv_info(pv_t *pv_ptr, char *buf); + +static void _show_uuid(const char *src, char *b, char *e); + +static devfs_handle_t lvm_devfs_handle; +static devfs_handle_t vg_devfs_handle[MAX_VG]; +static devfs_handle_t ch_devfs_handle[MAX_VG]; +static devfs_handle_t lv_devfs_handle[MAX_LV]; + +static struct proc_dir_entry *lvm_proc_dir = NULL; +static struct proc_dir_entry *lvm_proc_vg_subdir = NULL; + +/* inline functions */ + +/* public interface */ +void lvm_init_fs() { + struct proc_dir_entry *pde; + + lvm_devfs_handle = devfs_register( + 0 , "lvm", 0, 0, LVM_CHAR_MAJOR, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + &lvm_chr_fops, NULL); + + lvm_proc_dir = create_proc_entry(LVM_DIR, S_IFDIR, &proc_root); + if (lvm_proc_dir) { + lvm_proc_vg_subdir = create_proc_entry(LVM_VG_SUBDIR, S_IFDIR, + lvm_proc_dir); + pde = create_proc_entry(LVM_GLOBAL, S_IFREG, lvm_proc_dir); + if ( pde != NULL) pde->read_proc = _proc_read_global; + } +} + +void lvm_fin_fs() { + devfs_unregister (lvm_devfs_handle); + + remove_proc_entry(LVM_GLOBAL, lvm_proc_dir); + remove_proc_entry(LVM_VG_SUBDIR, lvm_proc_dir); + remove_proc_entry(LVM_DIR, &proc_root); +} + +void lvm_fs_create_vg(vg_t *vg_ptr) { + struct proc_dir_entry *pde; + + vg_devfs_handle[vg_ptr->vg_number] = + devfs_mk_dir(0, vg_ptr->vg_name, NULL); + + ch_devfs_handle[vg_ptr->vg_number] = devfs_register( + vg_devfs_handle[vg_ptr->vg_number] , "group", + DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR, vg_ptr->vg_number, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + &lvm_chr_fops, NULL); + + vg_ptr->vg_dir_pde = create_proc_entry(vg_ptr->vg_name, S_IFDIR, + lvm_proc_vg_subdir); + + if((pde = create_proc_entry("group", S_IFREG, vg_ptr->vg_dir_pde))) { + pde->read_proc = _proc_read_vg; + pde->data = vg_ptr; + } + + vg_ptr->lv_subdir_pde = + create_proc_entry(LVM_LV_SUBDIR, S_IFDIR, vg_ptr->vg_dir_pde); + + vg_ptr->pv_subdir_pde = + create_proc_entry(LVM_PV_SUBDIR, S_IFDIR, vg_ptr->vg_dir_pde); +} + +void lvm_fs_remove_vg(vg_t *vg_ptr) { + int i; + + devfs_unregister(ch_devfs_handle[vg_ptr->vg_number]); + devfs_unregister(vg_devfs_handle[vg_ptr->vg_number]); + + /* remove lv's */ + for(i = 0; i < vg_ptr->lv_max; i++) + if(vg_ptr->lv[i]) lvm_fs_remove_lv(vg_ptr, vg_ptr->lv[i]); + + /* remove pv's */ + for(i = 0; i < vg_ptr->pv_max; i++) + if(vg_ptr->pv[i]) lvm_fs_remove_pv(vg_ptr, vg_ptr->pv[i]); + + if(vg_ptr->vg_dir_pde) { + remove_proc_entry(LVM_LV_SUBDIR, vg_ptr->vg_dir_pde); + remove_proc_entry(LVM_PV_SUBDIR, vg_ptr->vg_dir_pde); + remove_proc_entry("group", vg_ptr->vg_dir_pde); + remove_proc_entry(vg_ptr->vg_name, lvm_proc_vg_subdir); + } +} + + +static inline const char *_basename(const char *str) { + const char *name = strrchr(str, '/'); + name = name ? name + 1 : str; + return name; +} + +void lvm_fs_create_lv(vg_t *vg_ptr, lv_t *lv) { + struct proc_dir_entry *pde; + const char *name = _basename(lv->lv_name); + + lv_devfs_handle[MINOR(lv->lv_dev)] = devfs_register( + vg_devfs_handle[vg_ptr->vg_number], name, + DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, MINOR(lv->lv_dev), + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + &lvm_blk_dops, NULL); + + if(vg_ptr->lv_subdir_pde && + (pde = create_proc_entry(name, S_IFREG, vg_ptr->lv_subdir_pde))) { + pde->read_proc = _proc_read_lv; + pde->data = lv; + } +} + +void lvm_fs_remove_lv(vg_t *vg_ptr, lv_t *lv) { + devfs_unregister(lv_devfs_handle[MINOR(lv->lv_dev)]); + + if(vg_ptr->lv_subdir_pde) { + const char *name = _basename(lv->lv_name); + remove_proc_entry(name, vg_ptr->lv_subdir_pde); + } +} + + +static inline void _make_pv_name(const char *src, char *b, char *e) { + int offset = strlen(LVM_DIR_PREFIX); + if(strncmp(src, LVM_DIR_PREFIX, offset)) + offset = 0; + + e--; + src += offset; + while(*src && (b != e)) { + *b++ = (*src == '/') ? '_' : *src; + src++; + } + *b = '\0'; +} + +void lvm_fs_create_pv(vg_t *vg_ptr, pv_t *pv) { + struct proc_dir_entry *pde; + char name[NAME_LEN]; + + if(!vg_ptr->pv_subdir_pde) + return; + + _make_pv_name(pv->pv_name, name, name + sizeof(name)); + if((pde = create_proc_entry(name, S_IFREG, vg_ptr->pv_subdir_pde))) { + pde->read_proc = _proc_read_pv; + pde->data = pv; + } +} + +void lvm_fs_remove_pv(vg_t *vg_ptr, pv_t *pv) { + char name[NAME_LEN]; + + if(!vg_ptr->pv_subdir_pde) + return; + + _make_pv_name(pv->pv_name, name, name + sizeof(name)); + remove_proc_entry(name, vg_ptr->pv_subdir_pde); +} + + +static int _proc_read_vg(char *page, char **start, off_t off, + int count, int *eof, void *data) { + int sz = 0; + vg_t *vg_ptr = data; + char uuid[NAME_LEN]; + + sz += sprintf(page + sz, "name: %s\n", vg_ptr->vg_name); + sz += sprintf(page + sz, "size: %u\n", + vg_ptr->pe_total * vg_ptr->pe_size / 2); + sz += sprintf(page + sz, "access: %u\n", vg_ptr->vg_access); + sz += sprintf(page + sz, "status: %u\n", vg_ptr->vg_status); + sz += sprintf(page + sz, "number: %u\n", vg_ptr->vg_number); + sz += sprintf(page + sz, "LV max: %u\n", vg_ptr->lv_max); + sz += sprintf(page + sz, "LV current: %u\n", vg_ptr->lv_cur); + sz += sprintf(page + sz, "LV open: %u\n", vg_ptr->lv_open); + sz += sprintf(page + sz, "PV max: %u\n", vg_ptr->pv_max); + sz += sprintf(page + sz, "PV current: %u\n", vg_ptr->pv_cur); + sz += sprintf(page + sz, "PV active: %u\n", vg_ptr->pv_act); + sz += sprintf(page + sz, "PE size: %u\n", vg_ptr->pe_size / 2); + sz += sprintf(page + sz, "PE total: %u\n", vg_ptr->pe_total); + sz += sprintf(page + sz, "PE allocated: %u\n", vg_ptr->pe_allocated); + + _show_uuid(vg_ptr->vg_uuid, uuid, uuid + sizeof(uuid)); + sz += sprintf(page + sz, "uuid: %s\n", uuid); + + return sz; +} + +static int _proc_read_lv(char *page, char **start, off_t off, + int count, int *eof, void *data) { + int sz = 0; + lv_t *lv = data; + + sz += sprintf(page + sz, "name: %s\n", lv->lv_name); + sz += sprintf(page + sz, "size: %u\n", lv->lv_size); + sz += sprintf(page + sz, "access: %u\n", lv->lv_access); + sz += sprintf(page + sz, "status: %u\n", lv->lv_status); + sz += sprintf(page + sz, "number: %u\n", lv->lv_number); + sz += sprintf(page + sz, "open: %u\n", lv->lv_open); + sz += sprintf(page + sz, "allocation: %u\n", lv->lv_allocation); + sz += sprintf(page + sz, "device: %02u:%02u\n", + MAJOR(lv->lv_dev), MINOR(lv->lv_dev)); + + return sz; +} + +static int _proc_read_pv(char *page, char **start, off_t off, + int count, int *eof, void *data) { + int sz = 0; + pv_t *pv = data; + char uuid[NAME_LEN]; + + sz += sprintf(page + sz, "name: %s\n", pv->pv_name); + sz += sprintf(page + sz, "size: %u\n", pv->pv_size); + sz += sprintf(page + sz, "status: %u\n", pv->pv_status); + sz += sprintf(page + sz, "number: %u\n", pv->pv_number); + sz += sprintf(page + sz, "allocatable: %u\n", pv->pv_allocatable); + sz += sprintf(page + sz, "LV current: %u\n", pv->lv_cur); + sz += sprintf(page + sz, "PE size: %u\n", pv->pe_size / 2); + sz += sprintf(page + sz, "PE total: %u\n", pv->pe_total); + sz += sprintf(page + sz, "PE allocated: %u\n", pv->pe_allocated); + sz += sprintf(page + sz, "device: %02u:%02u\n", + MAJOR(pv->pv_dev), MINOR(pv->pv_dev)); + + _show_uuid(pv->pv_uuid, uuid, uuid + sizeof(uuid)); + sz += sprintf(page + sz, "uuid: %s\n", uuid); + + return sz; +} + +static int _proc_read_global(char *page, char **start, off_t pos, int count, + int *eof, void *data) { + +#define LVM_PROC_BUF ( i == 0 ? dummy_buf : &buf[sz]) + + int c, i, l, p, v, vg_counter, pv_counter, lv_counter, lv_open_counter, + lv_open_total, pe_t_bytes, hash_table_bytes, lv_block_exception_t_bytes, seconds; + static off_t sz; + off_t sz_last; + static char *buf = NULL; + static char dummy_buf[160]; /* sized for 2 lines */ + vg_t *vg_ptr; + lv_t *lv_ptr; + pv_t *pv_ptr; + + +#ifdef DEBUG_LVM_PROC_GET_INFO + printk(KERN_DEBUG + "%s - lvm_proc_get_global_info CALLED pos: %lu count: %d whence: %d\n", + lvm_name, pos, count, whence); +#endif + + if(pos != 0 && buf != NULL) + goto out; + + sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter = \ + lv_open_total = pe_t_bytes = hash_table_bytes = \ + lv_block_exception_t_bytes = 0; + + /* get some statistics */ + for (v = 0; v < ABS_MAX_VG; v++) { + if ((vg_ptr = vg[v]) != NULL) { + vg_counter++; + pv_counter += vg_ptr->pv_cur; + lv_counter += vg_ptr->lv_cur; + if (vg_ptr->lv_cur > 0) { + for (l = 0; l < vg[v]->lv_max; l++) { + if ((lv_ptr = vg_ptr->lv[l]) != NULL) { + pe_t_bytes += lv_ptr->lv_allocated_le; + hash_table_bytes += lv_ptr->lv_snapshot_hash_table_size; + if (lv_ptr->lv_block_exception != NULL) + lv_block_exception_t_bytes += lv_ptr->lv_remap_end; + if (lv_ptr->lv_open > 0) { + lv_open_counter++; + lv_open_total += lv_ptr->lv_open; + } + } + } + } + } + } + + pe_t_bytes *= sizeof(pe_t); + lv_block_exception_t_bytes *= sizeof(lv_block_exception_t); + + if (buf != NULL) { + P_KFREE("%s -- vfree %d\n", lvm_name, __LINE__); + lock_kernel(); + vfree(buf); + unlock_kernel(); + buf = NULL; + } + /* 2 times: first to get size to allocate buffer, + 2nd to fill the malloced buffer */ + for (i = 0; i < 2; i++) { + sz = 0; + sz += sprintf(LVM_PROC_BUF, + "LVM " +#ifdef MODULE + "module" +#else + "driver" +#endif + " %s\n\n" + "Total: %d VG%s %d PV%s %d LV%s ", + lvm_short_version, + vg_counter, vg_counter == 1 ? "" : "s", + pv_counter, pv_counter == 1 ? "" : "s", + lv_counter, lv_counter == 1 ? "" : "s"); + sz += sprintf(LVM_PROC_BUF, + "(%d LV%s open", + lv_open_counter, + lv_open_counter == 1 ? "" : "s"); + if (lv_open_total > 0) + sz += sprintf(LVM_PROC_BUF, + " %d times)\n", + lv_open_total); + else + sz += sprintf(LVM_PROC_BUF, ")"); + sz += sprintf(LVM_PROC_BUF, + "\nGlobal: %lu bytes malloced IOP version: %d ", + vg_counter * sizeof(vg_t) + + pv_counter * sizeof(pv_t) + + lv_counter * sizeof(lv_t) + + pe_t_bytes + hash_table_bytes + lv_block_exception_t_bytes + sz_last, + lvm_iop_version); + + seconds = CURRENT_TIME - loadtime; + if (seconds < 0) + loadtime = CURRENT_TIME + seconds; + if (seconds / 86400 > 0) { + sz += sprintf(LVM_PROC_BUF, "%d day%s ", + seconds / 86400, + seconds / 86400 == 0 || + seconds / 86400 > 1 ? "s" : ""); + } + sz += sprintf(LVM_PROC_BUF, "%d:%02d:%02d active\n", + (seconds % 86400) / 3600, + (seconds % 3600) / 60, + seconds % 60); + + if (vg_counter > 0) { + for (v = 0; v < ABS_MAX_VG; v++) { + /* volume group */ + if ((vg_ptr = vg[v]) != NULL) { + sz += _vg_info(vg_ptr, LVM_PROC_BUF); + + /* physical volumes */ + sz += sprintf(LVM_PROC_BUF, + "\n PV%s ", + vg_ptr->pv_cur == 1 ? ": " : "s:"); + c = 0; + for (p = 0; p < vg_ptr->pv_max; p++) { + if ((pv_ptr = vg_ptr->pv[p]) != NULL) { + sz += _pv_info(pv_ptr, LVM_PROC_BUF); + + c++; + if (c < vg_ptr->pv_cur) + sz += sprintf(LVM_PROC_BUF, + "\n "); + } + } + + /* logical volumes */ + sz += sprintf(LVM_PROC_BUF, + "\n LV%s ", + vg_ptr->lv_cur == 1 ? ": " : "s:"); + c = 0; + for (l = 0; l < vg_ptr->lv_max; l++) { + if ((lv_ptr = vg_ptr->lv[l]) != NULL) { + sz += _lv_info(vg_ptr, lv_ptr, LVM_PROC_BUF); + c++; + if (c < vg_ptr->lv_cur) + sz += sprintf(LVM_PROC_BUF, + "\n "); + } + } + if (vg_ptr->lv_cur == 0) sz += sprintf(LVM_PROC_BUF, "none"); + sz += sprintf(LVM_PROC_BUF, "\n"); + } + } + } + if (buf == NULL) { + lock_kernel(); + buf = vmalloc(sz); + unlock_kernel(); + if (buf == NULL) { + sz = 0; + return sprintf(page, "%s - vmalloc error at line %d\n", + lvm_name, __LINE__); + } + } + sz_last = sz; + } + + out: + if (pos > sz - 1) { + lock_kernel(); + vfree(buf); + unlock_kernel(); + buf = NULL; + return 0; + } + *start = &buf[pos]; + if (sz - pos < count) + return sz - pos; + else + return count; + +#undef LVM_PROC_BUF +} + +/* + * provide VG info for proc filesystem use (global) + */ +static int _vg_info(vg_t *vg_ptr, char *buf) { + int sz = 0; + char inactive_flag = ' '; + + if (!(vg_ptr->vg_status & VG_ACTIVE)) inactive_flag = 'I'; + sz = sprintf(buf, + "\nVG: %c%s [%d PV, %d LV/%d open] " + " PE Size: %d KB\n" + " Usage [KB/PE]: %d /%d total " + "%d /%d used %d /%d free", + inactive_flag, + vg_ptr->vg_name, + vg_ptr->pv_cur, + vg_ptr->lv_cur, + vg_ptr->lv_open, + vg_ptr->pe_size >> 1, + vg_ptr->pe_size * vg_ptr->pe_total >> 1, + vg_ptr->pe_total, + vg_ptr->pe_allocated * vg_ptr->pe_size >> 1, + vg_ptr->pe_allocated, + (vg_ptr->pe_total - vg_ptr->pe_allocated) * + vg_ptr->pe_size >> 1, + vg_ptr->pe_total - vg_ptr->pe_allocated); + return sz; +} + + +/* + * provide LV info for proc filesystem use (global) + */ +static int _lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf) { + int sz = 0; + char inactive_flag = 'A', allocation_flag = ' ', + stripes_flag = ' ', rw_flag = ' ', *basename; + + if (!(lv_ptr->lv_status & LV_ACTIVE)) + inactive_flag = 'I'; + rw_flag = 'R'; + if (lv_ptr->lv_access & LV_WRITE) + rw_flag = 'W'; + allocation_flag = 'D'; + if (lv_ptr->lv_allocation & LV_CONTIGUOUS) + allocation_flag = 'C'; + stripes_flag = 'L'; + if (lv_ptr->lv_stripes > 1) + stripes_flag = 'S'; + sz += sprintf(buf+sz, + "[%c%c%c%c", + inactive_flag, + rw_flag, + allocation_flag, + stripes_flag); + if (lv_ptr->lv_stripes > 1) + sz += sprintf(buf+sz, "%-2d", + lv_ptr->lv_stripes); + else + sz += sprintf(buf+sz, " "); + + /* FIXME: use _basename */ + basename = strrchr(lv_ptr->lv_name, '/'); + if ( basename == 0) basename = lv_ptr->lv_name; + else basename++; + sz += sprintf(buf+sz, "] %-25s", basename); + if (strlen(basename) > 25) + sz += sprintf(buf+sz, + "\n "); + sz += sprintf(buf+sz, "%9d /%-6d ", + lv_ptr->lv_size >> 1, + lv_ptr->lv_size / vg_ptr->pe_size); + + if (lv_ptr->lv_open == 0) + sz += sprintf(buf+sz, "close"); + else + sz += sprintf(buf+sz, "%dx open", + lv_ptr->lv_open); + + return sz; +} + + +/* + * provide PV info for proc filesystem use (global) + */ +static int _pv_info(pv_t *pv, char *buf) { + int sz = 0; + char inactive_flag = 'A', allocation_flag = ' '; + char *pv_name = NULL; + + if (!(pv->pv_status & PV_ACTIVE)) + inactive_flag = 'I'; + allocation_flag = 'A'; + if (!(pv->pv_allocatable & PV_ALLOCATABLE)) + allocation_flag = 'N'; + pv_name = strrchr(pv->pv_name+1,'/'); + if ( pv_name == 0) pv_name = pv->pv_name; + else pv_name++; + sz = sprintf(buf, + "[%c%c] %-21s %8d /%-6d " + "%8d /%-6d %8d /%-6d", + inactive_flag, + allocation_flag, + pv_name, + pv->pe_total * pv->pe_size >> 1, + pv->pe_total, + pv->pe_allocated * pv->pe_size >> 1, + pv->pe_allocated, + (pv->pe_total - pv->pe_allocated) * + pv->pe_size >> 1, + pv->pe_total - pv->pe_allocated); + return sz; +} + +static void _show_uuid(const char *src, char *b, char *e) { + int i; + + e--; + for(i = 0; *src && (b != e); i++) { + if(i && !(i & 0x3)) + *b++ = '-'; + *b++ = *src++; + } + *b = '\0'; +} diff -rNu linux-2.4.7/linux/drivers/md/lvm-internal.h linux-2.4-xfs/linux/drivers/md/lvm-internal.h --- linux-2.4.7/linux/drivers/md/lvm-internal.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/md/lvm-internal.h Tue Mar 20 14:10:08 2001 @@ -0,0 +1,104 @@ +/* + * kernel/lvm_internal.h + * + * Copyright (C) 2001 Sistina Software + * + * + * LVM driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * LVM driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/* + * Changelog + * + * 05/01/2001 - Factored this file out of lvm.c (Joe Thornber) + * 11/01/2001 - Renamed lvm_internal and added declarations + * for lvm_fs.c stuff + * + */ + +#ifndef LVM_INTERNAL_H +#define LVM_INTERNAL_H + +#include + +#define _LVM_INTERNAL_H_VERSION "LVM "LVM_RELEASE_NAME" ("LVM_RELEASE_DATE")" + +/* global variables, defined in lvm.c */ +extern char *lvm_version; +extern char *lvm_short_version; +extern ushort lvm_iop_version; +extern int loadtime; +extern const char *const lvm_name; + + +extern vg_t *vg[]; +extern struct file_operations lvm_chr_fops; + +extern struct block_device_operations lvm_blk_dops; + + +/* debug macros */ +#ifdef DEBUG_IOCTL +#define P_IOCTL(fmt, args...) printk(KERN_DEBUG "lvm ioctl: " fmt, ## args) +#else +#define P_IOCTL(fmt, args...) +#endif + +#ifdef DEBUG_MAP +#define P_MAP(fmt, args...) printk(KERN_DEBUG "lvm map: " fmt, ## args) +#else +#define P_MAP(fmt, args...) +#endif + +#ifdef DEBUG_KFREE +#define P_KFREE(fmt, args...) printk(KERN_DEBUG "lvm kfree: " fmt, ## args) +#else +#define P_KFREE(fmt, args...) +#endif + +#ifdef DEBUG_DEVICE +#define P_DEV(fmt, args...) printk(KERN_DEBUG "lvm device: " fmt, ## args) +#else +#define P_DEV(fmt, args...) +#endif + + +/* lvm-snap.c */ +int lvm_get_blksize(kdev_t); +int lvm_snapshot_alloc(lv_t *); +int lvm_snapshot_fill_COW_page(vg_t *, lv_t *); +int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, vg_t *vg, lv_t *); +int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, lv_t *); +void lvm_snapshot_release(lv_t *); +int lvm_write_COW_table_block(vg_t *, lv_t *); +void lvm_hash_link(lv_block_exception_t *, kdev_t, ulong, lv_t *); +int lvm_snapshot_alloc_hash_table(lv_t *); +void lvm_drop_snapshot(vg_t *vg, lv_t *, const char *); + + +/* lvm_fs.c */ +void lvm_init_fs(void); +void lvm_fin_fs(void); + +void lvm_fs_create_vg(vg_t *vg_ptr); +void lvm_fs_remove_vg(vg_t *vg_ptr); +void lvm_fs_create_lv(vg_t *vg_ptr, lv_t *lv); +void lvm_fs_remove_lv(vg_t *vg_ptr, lv_t *lv); +void lvm_fs_create_pv(vg_t *vg_ptr, pv_t *pv); +void lvm_fs_remove_pv(vg_t *vg_ptr, pv_t *pv); + +#endif diff -rNu linux-2.4.7/linux/drivers/md/lvm-snap.c linux-2.4-xfs/linux/drivers/md/lvm-snap.c --- linux-2.4.7/linux/drivers/md/lvm-snap.c Fri Apr 27 16:23:25 2001 +++ linux-2.4-xfs/linux/drivers/md/lvm-snap.c Tue Mar 20 14:10:08 2001 @@ -2,22 +2,22 @@ * kernel/lvm-snap.c * * Copyright (C) 2000 Andrea Arcangeli SuSE - * Heinz Mauelshagen, Sistina Software (persistent snapshots) + * 2000 - 2001 Heinz Mauelshagen, Sistina Software * * LVM snapshot driver is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. - * + * * LVM snapshot driver is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Boston, MA 02111-1307, USA. * */ @@ -26,6 +26,19 @@ * * 05/07/2000 - implemented persistent snapshot support * 23/11/2000 - used cpu_to_le64 rather than my own macro + * 25/01/2001 - Put LockPage back in + * 01/02/2001 - A dropped snapshot is now set as inactive + * 14/02/2001 - tidied debug statements + * 19/02/2001 - changed rawio calls to pass in preallocated buffer_heads + * 26/02/2001 - introduced __brw_kiovec to remove a lot of conditional + * compiles. + * 07/03/2001 - fixed COW exception table not persistent on 2.2 (HM) + * 12/03/2001 - lvm_pv_get_number changes: + * o made it static + * o renamed it to _pv_get_number + * o pv number is returned in new uint * arg + * o -1 returned on error + * lvm_snapshot_fill_COW_table has a return value too. * */ @@ -38,26 +51,48 @@ #include -#include "lvm-snap.h" +#include "lvm-internal.h" + +static char *lvm_snap_version __attribute__ ((unused)) = "LVM "LVM_RELEASE_NAME" snapshot code ("LVM_RELEASE_DATE")\n"; -static char *lvm_snap_version __attribute__ ((unused)) = "LVM 0.9.1_beta2 snapshot code (18/01/2001)\n"; extern const char *const lvm_name; extern int lvm_blocksizes[]; void lvm_snapshot_release(lv_t *); -uint lvm_pv_get_number(vg_t * vg, kdev_t rdev) -{ +static int _write_COW_table_block(vg_t *vg, lv_t *lv, int idx, + const char **reason); +static void _disable_snapshot(vg_t *vg, lv_t *lv); + + +static inline int __brw_kiovec(int rw, int nr, struct kiobuf *iovec[], + kdev_t dev, unsigned long b[], int size, + lv_t *lv) { + return brw_kiovec(rw, nr, iovec, dev, b, size); +} + + +static int _pv_get_number(vg_t * vg, kdev_t rdev, uint *pvn) { uint p; + for(p = 0; p < vg->pv_max; p++) { + if(vg->pv[p] == NULL) + continue; - for ( p = 0; p < vg->pv_max; p++) - { - if ( vg->pv[p] == NULL) continue; - if ( vg->pv[p]->pv_dev == rdev) break; + if(vg->pv[p]->pv_dev == rdev) + break; + } + + if(p >= vg->pv_max) { + /* bad news, the snapshot COW table is probably corrupt */ + printk(KERN_ERR + "%s -- _pv_get_number failed for rdev = %u\n", + lvm_name, rdev); + return -1; } - return vg->pv[p]->pv_number; + *pvn = vg->pv[p]->pv_number; + return 0; } @@ -133,7 +168,7 @@ return ret; } -void lvm_drop_snapshot(lv_t * lv_snap, const char * reason) +void lvm_drop_snapshot(vg_t *vg, lv_t *lv_snap, const char *reason) { kdev_t last_dev; int i; @@ -142,6 +177,9 @@ or error on this snapshot --> release it */ invalidate_buffers(lv_snap->lv_dev); + /* wipe the snapshot since it's inconsistent now */ + _disable_snapshot(vg, lv_snap); + for (i = last_dev = 0; i < lv_snap->lv_remap_ptr; i++) { if ( lv_snap->lv_block_exception[i].rdev_new != last_dev) { last_dev = lv_snap->lv_block_exception[i].rdev_new; @@ -150,9 +188,10 @@ } lvm_snapshot_release(lv_snap); + lv_snap->lv_status &= ~LV_ACTIVE; printk(KERN_INFO - "%s -- giving up to snapshot %s on %s due %s\n", + "%s -- giving up to snapshot %s on %s: %s\n", lvm_name, lv_snap->lv_snapshot_org->lv_name, lv_snap->lv_name, reason); } @@ -209,128 +248,58 @@ #endif -void lvm_snapshot_fill_COW_page(vg_t * vg, lv_t * lv_snap) +int lvm_snapshot_fill_COW_page(vg_t * vg, lv_t * lv_snap) { - int id = 0, is = lv_snap->lv_remap_ptr; - ulong blksize_snap; - lv_COW_table_disk_t * lv_COW_table = - ( lv_COW_table_disk_t *) page_address(lv_snap->lv_COW_table_page); + uint pvn; + int id = 0, is = lv_snap->lv_remap_ptr; + ulong blksize_snap; + lv_COW_table_disk_t * lv_COW_table = (lv_COW_table_disk_t *) + page_address(lv_snap->lv_COW_table_iobuf->maplist[0]); + + if (is == 0) + return 0; - if (is == 0) return; is--; - blksize_snap = lvm_get_blksize(lv_snap->lv_block_exception[is].rdev_new); + blksize_snap = + lvm_get_blksize(lv_snap->lv_block_exception[is].rdev_new); is -= is % (blksize_snap / sizeof(lv_COW_table_disk_t)); memset(lv_COW_table, 0, blksize_snap); for ( ; is < lv_snap->lv_remap_ptr; is++, id++) { /* store new COW_table entry */ - lv_COW_table[id].pv_org_number = cpu_to_le64(lvm_pv_get_number(vg, lv_snap->lv_block_exception[is].rdev_org)); - lv_COW_table[id].pv_org_rsector = cpu_to_le64(lv_snap->lv_block_exception[is].rsector_org); - lv_COW_table[id].pv_snap_number = cpu_to_le64(lvm_pv_get_number(vg, lv_snap->lv_block_exception[is].rdev_new)); - lv_COW_table[id].pv_snap_rsector = cpu_to_le64(lv_snap->lv_block_exception[is].rsector_new); + lv_block_exception_t *be = lv_snap->lv_block_exception + is; + if(_pv_get_number(vg, be->rdev_org, &pvn)) + goto bad; + + lv_COW_table[id].pv_org_number = cpu_to_le64(pvn); + lv_COW_table[id].pv_org_rsector = cpu_to_le64(be->rsector_org); + if(_pv_get_number(vg, be->rdev_new, &pvn)) + goto bad; + + lv_COW_table[id].pv_snap_number = cpu_to_le64(pvn); + lv_COW_table[id].pv_snap_rsector = + cpu_to_le64(be->rsector_new); } + + return 0; + + bad: + printk(KERN_ERR "%s -- lvm_snapshot_fill_COW_page failed", lvm_name); + return -1; } /* * writes a COW exception table sector to disk (HM) - * */ - -int lvm_write_COW_table_block(vg_t * vg, lv_t * lv_snap) +int lvm_write_COW_table_block(vg_t * vg, lv_t *lv_snap) { - int blksize_snap; - int end_of_table; - int idx = lv_snap->lv_remap_ptr, idx_COW_table; - int nr_pages_tmp; - int length_tmp; - ulong snap_pe_start, COW_table_sector_offset, - COW_entries_per_pe, COW_chunks_per_pe, COW_entries_per_block; - const char * reason; - kdev_t snap_phys_dev; - struct kiobuf * iobuf = lv_snap->lv_iobuf; - struct page * page_tmp; - lv_COW_table_disk_t * lv_COW_table = - ( lv_COW_table_disk_t *) page_address(lv_snap->lv_COW_table_page); - - idx--; - - COW_chunks_per_pe = LVM_GET_COW_TABLE_CHUNKS_PER_PE(vg, lv_snap); - COW_entries_per_pe = LVM_GET_COW_TABLE_ENTRIES_PER_PE(vg, lv_snap); - - /* get physical addresse of destination chunk */ - snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new; - snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size; - - blksize_snap = lvm_get_blksize(snap_phys_dev); - - COW_entries_per_block = blksize_snap / sizeof(lv_COW_table_disk_t); - idx_COW_table = idx % COW_entries_per_pe % COW_entries_per_block; - - if ( idx_COW_table == 0) memset(lv_COW_table, 0, blksize_snap); - - /* sector offset into the on disk COW table */ - COW_table_sector_offset = (idx % COW_entries_per_pe) / (SECTOR_SIZE / sizeof(lv_COW_table_disk_t)); - - /* COW table block to write next */ - iobuf->blocks[0] = (snap_pe_start + COW_table_sector_offset) >> (blksize_snap >> 10); - - /* store new COW_table entry */ - lv_COW_table[idx_COW_table].pv_org_number = cpu_to_le64(lvm_pv_get_number(vg, lv_snap->lv_block_exception[idx].rdev_org)); - lv_COW_table[idx_COW_table].pv_org_rsector = cpu_to_le64(lv_snap->lv_block_exception[idx].rsector_org); - lv_COW_table[idx_COW_table].pv_snap_number = cpu_to_le64(lvm_pv_get_number(vg, snap_phys_dev)); - lv_COW_table[idx_COW_table].pv_snap_rsector = cpu_to_le64(lv_snap->lv_block_exception[idx].rsector_new); - - length_tmp = iobuf->length; - iobuf->length = blksize_snap; - page_tmp = iobuf->maplist[0]; - iobuf->maplist[0] = lv_snap->lv_COW_table_page; - nr_pages_tmp = iobuf->nr_pages; - iobuf->nr_pages = 1; - - if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev, - iobuf->blocks, blksize_snap) != blksize_snap) - goto fail_raw_write; - - - /* initialization of next COW exception table block with zeroes */ - end_of_table = idx % COW_entries_per_pe == COW_entries_per_pe - 1; - if (idx_COW_table % COW_entries_per_block == COW_entries_per_block - 1 || end_of_table) - { - /* don't go beyond the end */ - if (idx + 1 >= lv_snap->lv_remap_end) goto good_out; - - memset(lv_COW_table, 0, blksize_snap); - - if (end_of_table) - { - idx++; - snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new; - snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size; - blksize_snap = lvm_get_blksize(snap_phys_dev); - iobuf->blocks[0] = snap_pe_start >> (blksize_snap >> 10); - } else iobuf->blocks[0]++; - - if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev, - iobuf->blocks, blksize_snap) != blksize_snap) - goto fail_raw_write; - } - - - good_out: - iobuf->length = length_tmp; - iobuf->maplist[0] = page_tmp; - iobuf->nr_pages = nr_pages_tmp; - return 0; - - /* slow path */ - out: - lvm_drop_snapshot(lv_snap, reason); - return 1; - - fail_raw_write: - reason = "write error"; - goto out; + int r; + const char *err; + if((r = _write_COW_table_block(vg, lv_snap, + lv_snap->lv_remap_ptr - 1, &err))) + lvm_drop_snapshot(vg, lv_snap, err); + return r; } /* @@ -345,12 +314,13 @@ unsigned long org_phys_sector, unsigned long org_pe_start, unsigned long org_virt_sector, - lv_t * lv_snap) + vg_t *vg, lv_t* lv_snap) { const char * reason; unsigned long org_start, snap_start, snap_phys_dev, virt_start, pe_off; int idx = lv_snap->lv_remap_ptr, chunk_size = lv_snap->lv_chunk_size; struct kiobuf * iobuf; + unsigned long blocks[KIO_MAX_SECTORS]; int blksize_snap, blksize_org, min_blksize, max_blksize; int max_sectors, nr_sectors; @@ -370,13 +340,11 @@ #ifdef DEBUG_SNAPSHOT printk(KERN_INFO "%s -- COW: " - "org %02d:%02d faulting %lu start %lu, " - "snap %02d:%02d start %lu, " + "org %s faulting %lu start %lu, snap %s start %lu, " "size %d, pe_start %lu pe_off %lu, virt_sec %lu\n", lvm_name, - MAJOR(org_phys_dev), MINOR(org_phys_dev), org_phys_sector, - org_start, - MAJOR(snap_phys_dev), MINOR(snap_phys_dev), snap_start, + kdevname(org_phys_dev), org_phys_sector, org_start, + kdevname(snap_phys_dev), snap_start, chunk_size, org_pe_start, pe_off, org_virt_sector); @@ -400,16 +368,16 @@ iobuf->length = nr_sectors << 9; - lvm_snapshot_prepare_blocks(iobuf->blocks, org_start, + lvm_snapshot_prepare_blocks(blocks, org_start, nr_sectors, blksize_org); - if (brw_kiovec(READ, 1, &iobuf, org_phys_dev, - iobuf->blocks, blksize_org) != (nr_sectors<<9)) + if (__brw_kiovec(READ, 1, &iobuf, org_phys_dev, blocks, + blksize_org, lv_snap) != (nr_sectors<<9)) goto fail_raw_read; - lvm_snapshot_prepare_blocks(iobuf->blocks, snap_start, + lvm_snapshot_prepare_blocks(blocks, snap_start, nr_sectors, blksize_snap); - if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev, - iobuf->blocks, blksize_snap) != (nr_sectors<<9)) + if (__brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev, blocks, + blksize_snap, lv_snap) != (nr_sectors<<9)) goto fail_raw_write; } @@ -434,20 +402,20 @@ return 0; /* slow path */ - out: - lvm_drop_snapshot(lv_snap, reason); +out: + lvm_drop_snapshot(vg, lv_snap, reason); return 1; - fail_out_of_space: +fail_out_of_space: reason = "out of space"; goto out; - fail_raw_read: +fail_raw_read: reason = "read error"; goto out; - fail_raw_write: +fail_raw_write: reason = "write error"; goto out; - fail_blksize: +fail_blksize: reason = "blocksize error"; goto out; } @@ -456,30 +424,30 @@ { int bytes, nr_pages, err, i; - bytes = sectors << 9; + bytes = sectors * SECTOR_SIZE; nr_pages = (bytes + ~PAGE_MASK) >> PAGE_SHIFT; err = expand_kiobuf(iobuf, nr_pages); - if (err) - goto out; + if (err) goto out; err = -ENOMEM; - iobuf->locked = 0; + iobuf->locked = 1; iobuf->nr_pages = 0; for (i = 0; i < nr_pages; i++) { struct page * page; page = alloc_page(GFP_KERNEL); - if (!page) - goto out; + if (!page) goto out; iobuf->maplist[i] = page; + LockPage(page); iobuf->nr_pages++; } iobuf->offset = 0; err = 0; - out: + +out: return err; } @@ -521,41 +489,49 @@ while (buckets--) INIT_LIST_HEAD(hash+buckets); err = 0; - out: +out: return err; } int lvm_snapshot_alloc(lv_t * lv_snap) { - int err, blocksize, max_sectors; + int ret, max_sectors; - err = alloc_kiovec(1, &lv_snap->lv_iobuf); - if (err) - goto out; + /* allocate kiovec to do chunk io */ + ret = alloc_kiovec(1, &lv_snap->lv_iobuf); + if (ret) goto out; - blocksize = lvm_blocksizes[MINOR(lv_snap->lv_dev)]; max_sectors = KIO_MAX_SECTORS << (PAGE_SHIFT-9); - err = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_iobuf, max_sectors); - if (err) - goto out_free_kiovec; + ret = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_iobuf, max_sectors); + if (ret) goto out_free_kiovec; - err = lvm_snapshot_alloc_hash_table(lv_snap); - if (err) - goto out_free_kiovec; + /* allocate kiovec to do exception table io */ + ret = alloc_kiovec(1, &lv_snap->lv_COW_table_iobuf); + if (ret) goto out_free_kiovec; + ret = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_COW_table_iobuf, + PAGE_SIZE/SECTOR_SIZE); + if (ret) goto out_free_both_kiovecs; - lv_snap->lv_COW_table_page = alloc_page(GFP_KERNEL); - if (!lv_snap->lv_COW_table_page) - goto out_free_kiovec; + ret = lvm_snapshot_alloc_hash_table(lv_snap); + if (ret) goto out_free_both_kiovecs; - out: - return err; - out_free_kiovec: +out: + return ret; + +out_free_both_kiovecs: + unmap_kiobuf(lv_snap->lv_COW_table_iobuf); + free_kiovec(1, &lv_snap->lv_COW_table_iobuf); + lv_snap->lv_COW_table_iobuf = NULL; + +out_free_kiovec: unmap_kiobuf(lv_snap->lv_iobuf); free_kiovec(1, &lv_snap->lv_iobuf); - vfree(lv_snap->lv_snapshot_hash_table); + lv_snap->lv_iobuf = NULL; + if (lv_snap->lv_snapshot_hash_table != NULL) + vfree(lv_snap->lv_snapshot_hash_table); lv_snap->lv_snapshot_hash_table = NULL; goto out; } @@ -580,9 +556,125 @@ free_kiovec(1, &lv->lv_iobuf); lv->lv_iobuf = NULL; } - if (lv->lv_COW_table_page) + if (lv->lv_COW_table_iobuf) { - free_page((ulong)lv->lv_COW_table_page); - lv->lv_COW_table_page = NULL; + kiobuf_wait_for_io(lv->lv_COW_table_iobuf); + unmap_kiobuf(lv->lv_COW_table_iobuf); + free_kiovec(1, &lv->lv_COW_table_iobuf); + lv->lv_COW_table_iobuf = NULL; + } +} + + +static int _write_COW_table_block(vg_t *vg, lv_t *lv_snap, + int idx, const char **reason) { + int blksize_snap; + int end_of_table; + int idx_COW_table; + uint pvn; + ulong snap_pe_start, COW_table_sector_offset, + COW_entries_per_pe, COW_chunks_per_pe, COW_entries_per_block; + ulong blocks[1]; + kdev_t snap_phys_dev; + lv_block_exception_t *be; + struct kiobuf *COW_table_iobuf = lv_snap->lv_COW_table_iobuf; + lv_COW_table_disk_t * lv_COW_table = + ( lv_COW_table_disk_t *) page_address(lv_snap->lv_COW_table_iobuf->maplist[0]); + + COW_chunks_per_pe = LVM_GET_COW_TABLE_CHUNKS_PER_PE(vg, lv_snap); + COW_entries_per_pe = LVM_GET_COW_TABLE_ENTRIES_PER_PE(vg, lv_snap); + + /* get physical addresse of destination chunk */ + snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new; + snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size; + + blksize_snap = lvm_get_blksize(snap_phys_dev); + + COW_entries_per_block = blksize_snap / sizeof(lv_COW_table_disk_t); + idx_COW_table = idx % COW_entries_per_pe % COW_entries_per_block; + + if ( idx_COW_table == 0) memset(lv_COW_table, 0, blksize_snap); + + /* sector offset into the on disk COW table */ + COW_table_sector_offset = (idx % COW_entries_per_pe) / (SECTOR_SIZE / sizeof(lv_COW_table_disk_t)); + + /* COW table block to write next */ + blocks[0] = (snap_pe_start + COW_table_sector_offset) >> (blksize_snap >> 10); + + /* store new COW_table entry */ + be = lv_snap->lv_block_exception + idx; + if(_pv_get_number(vg, be->rdev_org, &pvn)) + goto fail_pv_get_number; + + lv_COW_table[idx_COW_table].pv_org_number = cpu_to_le64(pvn); + lv_COW_table[idx_COW_table].pv_org_rsector = + cpu_to_le64(be->rsector_org); + if(_pv_get_number(vg, snap_phys_dev, &pvn)) + goto fail_pv_get_number; + + lv_COW_table[idx_COW_table].pv_snap_number = cpu_to_le64(pvn); + lv_COW_table[idx_COW_table].pv_snap_rsector = + cpu_to_le64(be->rsector_new); + + COW_table_iobuf->length = blksize_snap; + /* COW_table_iobuf->nr_pages = 1; */ + + if (__brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev, + blocks, blksize_snap, lv_snap) != blksize_snap) + goto fail_raw_write; + + /* initialization of next COW exception table block with zeroes */ + end_of_table = idx % COW_entries_per_pe == COW_entries_per_pe - 1; + if (idx_COW_table % COW_entries_per_block == COW_entries_per_block - 1 || end_of_table) + { + /* don't go beyond the end */ + if (idx + 1 >= lv_snap->lv_remap_end) goto out; + + memset(lv_COW_table, 0, blksize_snap); + + if (end_of_table) + { + idx++; + snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new; + snap_pe_start = lv_snap->lv_block_exception[idx - (idx % COW_entries_per_pe)].rsector_new - lv_snap->lv_chunk_size; + blksize_snap = lvm_get_blksize(snap_phys_dev); + blocks[0] = snap_pe_start >> (blksize_snap >> 10); + } else blocks[0]++; + + if (__brw_kiovec(WRITE, 1, &COW_table_iobuf, snap_phys_dev, + blocks, blksize_snap, lv_snap) != + blksize_snap) + goto fail_raw_write; + } + +out: + return 0; + +fail_raw_write: + *reason = "write error"; + return 1; + +fail_pv_get_number: + *reason = "_pv_get_number failed"; + return 1; +} + +/* + * FIXME_1.2 + * This function is a bit of a hack; we need to ensure that the + * snapshot is never made active again, because it will surely be + * corrupt. At the moment we do not have access to the LVM metadata + * from within the kernel. So we set the first exception to point to + * sector 1 (which will always be within the metadata, and as such + * invalid). User land tools will check for this when they are asked + * to activate the snapshot and prevent this from happening. + */ + +static void _disable_snapshot(vg_t *vg, lv_t *lv) { + const char *err; + lv->lv_block_exception[0].rsector_org = LVM_SNAPSHOT_DROPPED_SECTOR; + if(_write_COW_table_block(vg, lv, 0, &err) < 0) { + printk(KERN_ERR "%s -- couldn't disable snapshot: %s\n", + lvm_name, err); } } diff -rNu linux-2.4.7/linux/drivers/md/lvm.c linux-2.4-xfs/linux/drivers/md/lvm.c --- linux-2.4.7/linux/drivers/md/lvm.c Sat Apr 21 12:37:16 2001 +++ linux-2.4-xfs/linux/drivers/md/lvm.c Wed May 2 02:48:52 2001 @@ -1,13 +1,13 @@ /* * kernel/lvm.c * - * Copyright (C) 1997 - 2000 Heinz Mauelshagen, Sistina Software + * Copyright (C) 1997 - 2001 Heinz Mauelshagen, Sistina Software * * February-November 1997 * April-May,July-August,November 1998 * January-March,May,July,September,October 1999 * January,February,July,September-November 2000 - * January 2001 + * January,February,March 2001 * * * LVM driver is free software; you can redistribute it and/or modify @@ -43,7 +43,8 @@ * support for free (eg. longer) logical volume names * 12/05/1998 - added spin_locks (thanks to Pascal van Dam * ) - * 25/05/1998 - fixed handling of locked PEs in lvm_map() and lvm_chr_ioctl() + * 25/05/1998 - fixed handling of locked PEs in lvm_map() and + * lvm_chr_ioctl() * 26/05/1998 - reactivated verify_area by access_ok * 07/06/1998 - used vmalloc/vfree instead of kmalloc/kfree to go * beyond 128/256 KB max allocation limit per call @@ -72,7 +73,7 @@ * only other update ioctls are blocked now * - fixed pv->pe to NULL for pv_status * - using lv_req structure in lvm_chr_ioctl() now - * - fixed NULL ptr reference bug in lvm_do_lv_extend_reduce() + * - fixed NULL ptr reference bug in lvm_do_lv_extendreduce() * caused by uncontiguous PV array in lvm_chr_ioctl(VG_REDUCE) * 09/02/1999 - changed BLKRASET and BLKRAGET in lvm_chr_ioctl() to * handle lgoical volume private read ahead sector @@ -125,7 +126,8 @@ * 14/02/2000 - support for 2.3.43 * - integrated Andrea Arcagneli's snapshot code * 25/06/2000 - james (chip) , IKKHAYD! roffl - * 26/06/2000 - enhanced lv_extend_reduce for snapshot logical volume support + * 26/06/2000 - enhanced lv_extend_reduce for snapshot logical volume + * support * 06/09/2000 - added devfs support * 07/09/2000 - changed IOP version to 9 * - started to add new char ioctl LV_STATUS_BYDEV_T to support @@ -148,28 +150,72 @@ * procfs is always supported now. (JT) * 12/01/2001 - avoided flushing logical volume in case of shrinking * because of unecessary overhead in case of heavy updates + * 25/01/2001 - Allow RO open of an inactive LV so it can be reactivated. + * 31/01/2001 - removed blk_init_queue/blk_cleanup_queue queueing will be + * handled by the proper devices. + * - If you try and BMAP a snapshot you now get an -EPERM + * 01/01/2001 - lvm_map() now calls buffer_IO_error on error for 2.4 + * - factored __remap_snapshot out of lvm_map + * 12/02/2001 - move devfs code to create VG before LVs + * 13/02/2001 - allow VG_CREATE on /dev/lvm + * 14/02/2001 - removed modversions.h + * - tidied device defines for blk.h + * - tidied debug statements + * - bug: vg[] member not set back to NULL if activation fails + * - more lvm_map tidying + * 15/02/2001 - register /dev/lvm with devfs correctly (major/minor + * were swapped) + * 19/02/2001 - preallocated buffer_heads for rawio when using + * snapshots [JT] + * 28/02/2001 - introduced the P_DEV macro and changed some internel + * functions to be static [AD] + * 28/02/2001 - factored lvm_get_snapshot_use_rate out of blk_ioctl [AD] + * - fixed user address accessing bug in lvm_do_lv_create() + * where the check for an existing LV takes place right at + * the beginning + * 01/03/2001 - Add VG_CREATE_OLD for IOP 10 compatibility + * 02/03/2001 - Don't destroy usermode pointers in lv_t structures duing + * LV_STATUS_BYxxx + * and remove redundant lv_t variables from same. + * - avoid compilation of lvm_dummy_device_request in case of + * Linux >= 2.3.0 to avoid a warning + * - added lvm_name argument to printk in buffer allocation + * in order to avoid a warning + * 04/03/2001 - moved linux/version.h above first use of KERNEL_VERSION + * macros + * 05/03/2001 - restore copying pe_t array in lvm_do_lv_status_byname. For + * lvdisplay -v (PC) + * - restore copying pe_t array in lvm_do_lv_status_byindex (HM) + * - added copying pe_t array in lvm_do_lv_status_bydev (HM) + * - enhanced lvm_do_lv_status_by{name,index,dev} to be capable + * to copy the lv_block_exception_t array to userspace (HM) + * 08/03/2001 - initialize new lv_ptr->lv_COW_table_iobuf for snapshots; + * removed obsolete lv_ptr->lv_COW_table_page initialization + * - factored lvm_do_pv_flush out of lvm_chr_ioctl (HM) + * 09/03/2001 - Added _lock_open_count to ensure we only drop the lock + * when the locking process closes. * 05/04/2001 - lvm_map bugs: don't use b_blocknr/b_dev in lvm_map, it - * destroys stacking devices. call b_end_io on failed maps. - * (Jens Axboe) + * destroys stacking devices. call b_end_io on failed maps. + * (Jens Axboe) + * 30/04/2001 - replace get_hardblock_size() with get_hardsect_size() for + * 2.4.4 kernel. * */ +#include -static char *lvm_version = "LVM version 0.9.1_beta2 by Heinz Mauelshagen (18/01/2001)\n"; -static char *lvm_short_version = "version 0.9.1_beta2 (18/01/2001)"; - -#define MAJOR_NR LVM_BLK_MAJOR -#define DEVICE_OFF(device) +#define MAJOR_NR LVM_BLK_MAJOR +#define DEVICE_OFF(device) +#define LOCAL_END_REQUEST /* lvm_do_lv_create calls fsync_dev_lockfs()/unlockfs() */ /* #define LVM_VFS_ENHANCEMENT */ #include -#include #include - #include #include + #include #include @@ -180,6 +226,8 @@ #include #include #include + + #include #include #include @@ -195,7 +243,7 @@ #include #include -#include "lvm-snap.h" +#include "lvm-internal.h" #define LVM_CORRECT_READ_AHEAD( a) \ if ( a < LVM_MIN_READ_AHEAD || \ @@ -205,24 +253,6 @@ # define WRITEA WRITE #endif -/* debug macros */ -#ifdef DEBUG_IOCTL -#define P_IOCTL(fmt, args...) printk(KERN_DEBUG "lvm ioctl: " fmt, ## args) -#else -#define P_IOCTL(fmt, args...) -#endif - -#ifdef DEBUG_MAP -#define P_MAP(fmt, args...) printk(KERN_DEBUG "lvm map: " fmt, ## args) -#else -#define P_MAP(fmt, args...) -#endif - -#ifdef DEBUG_KFREE -#define P_KFREE(fmt, args...) printk(KERN_DEBUG "lvm kfree: " fmt, ## args) -#else -#define P_KFREE(fmt, args...) -#endif /* * External function prototypes @@ -232,27 +262,14 @@ static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong); static int lvm_blk_open(struct inode *, struct file *); -static int lvm_chr_open(struct inode *, struct file *); - -static int lvm_chr_close(struct inode *, struct file *); static int lvm_blk_close(struct inode *, struct file *); +static int lvm_get_snapshot_use_rate(lv_t *lv_ptr, void *arg); static int lvm_user_bmap(struct inode *, struct lv_bmap *); +static int lvm_chr_open(struct inode *, struct file *); +static int lvm_chr_close(struct inode *, struct file *); static int lvm_chr_ioctl(struct inode *, struct file *, uint, ulong); -int lvm_proc_read_vg_info(char *, char **, off_t, int, int *, void *); -int lvm_proc_read_lv_info(char *, char **, off_t, int, int *, void *); -int lvm_proc_read_pv_info(char *, char **, off_t, int, int *, void *); -static int lvm_proc_get_global_info(char *, char **, off_t, int, int *, void *); - -void lvm_do_create_devfs_entry_of_vg ( vg_t *); - -void lvm_do_create_proc_entry_of_vg ( vg_t *); -void lvm_do_remove_proc_entry_of_vg ( vg_t *); -void lvm_do_create_proc_entry_of_lv ( vg_t *, lv_t *); -void lvm_do_remove_proc_entry_of_lv ( vg_t *, lv_t *); -void lvm_do_create_proc_entry_of_pv ( vg_t *, pv_t *); -void lvm_do_remove_proc_entry_of_pv ( vg_t *, pv_t *); /* End external function prototypes */ @@ -284,33 +301,38 @@ static int lvm_do_pv_change(vg_t*, void*); static int lvm_do_pv_status(vg_t *, void *); +static int lvm_do_pv_flush(void *); -static int lvm_do_vg_create(int, void *); +static int lvm_do_vg_create(void *, int minor); static int lvm_do_vg_extend(vg_t *, void *); static int lvm_do_vg_reduce(vg_t *, void *); static int lvm_do_vg_rename(vg_t *, void *); static int lvm_do_vg_remove(int); static void lvm_geninit(struct gendisk *); -static char *lvm_show_uuid ( char *); +static void __update_hardsectsize(lv_t *lv); + + #ifdef LVM_HD_NAME void lvm_hd_name(char *, int); #endif /* END Internal function prototypes */ -/* volume group descriptor area pointers */ -static vg_t *vg[ABS_MAX_VG]; +/* variables */ +char *lvm_version = "LVM version "LVM_RELEASE_NAME" by Heinz Mauelshagen " + "("LVM_RELEASE_DATE")\n"; +char *lvm_short_version = "version "LVM_RELEASE_NAME" ("LVM_RELEASE_DATE")"; +ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION; +int loadtime = 0; +const char *const lvm_name = LVM_NAME; -static devfs_handle_t lvm_devfs_handle; -static devfs_handle_t vg_devfs_handle[MAX_VG]; -static devfs_handle_t ch_devfs_handle[MAX_VG]; -static devfs_handle_t lv_devfs_handle[MAX_LV]; + +/* volume group descriptor area pointers */ +vg_t *vg[ABS_MAX_VG]; static pv_t *pvp = NULL; static lv_t *lvp = NULL; static pe_t *pep = NULL; -static pe_t *pep1 = NULL; -static char *basename = NULL; /* map from block minor number to VG and LV numbers */ @@ -323,7 +345,6 @@ /* Request structures (lvm_chr_ioctl()) */ static pv_change_req_t pv_change_req; -static pv_flush_req_t pv_flush_req; static pv_status_req_t pv_status_req; static pe_lock_req_t pe_lock_req; static le_remap_req_t le_remap_req; @@ -335,32 +356,24 @@ static char pv_name[NAME_LEN]; /* static char rootvg[NAME_LEN] = { 0, }; */ -const char *const lvm_name = LVM_NAME; static int lock = 0; -static int loadtime = 0; +static int _lock_open_count = 0; static uint vg_count = 0; static long lvm_chr_open_count = 0; -static ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION; static DECLARE_WAIT_QUEUE_HEAD(lvm_wait); static DECLARE_WAIT_QUEUE_HEAD(lvm_map_wait); static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED; static spinlock_t lvm_snapshot_lock = SPIN_LOCK_UNLOCKED; -static struct proc_dir_entry *lvm_proc_dir = NULL; -static struct proc_dir_entry *lvm_proc_vg_subdir = NULL; -struct proc_dir_entry *pde = NULL; - -static struct file_operations lvm_chr_fops = -{ +struct file_operations lvm_chr_fops = { open: lvm_chr_open, release: lvm_chr_close, ioctl: lvm_chr_ioctl, }; - /* block device operations structure needed for 2.3.38? and above */ -static struct block_device_operations lvm_blk_dops = +struct block_device_operations lvm_blk_dops = { open: lvm_blk_open, release: lvm_blk_close, @@ -370,10 +383,10 @@ /* gendisk structures */ static struct hd_struct lvm_hd_struct[MAX_LV]; -static int lvm_blocksizes[MAX_LV] = -{0,}; -static int lvm_size[MAX_LV] = -{0,}; +static int lvm_blocksizes[MAX_LV]; +static int lvm_hardsectsizes[MAX_LV]; +static int lvm_size[MAX_LV]; + static struct gendisk lvm_gendisk = { MAJOR_NR, /* major # */ @@ -408,18 +421,7 @@ return -EIO; } - lvm_devfs_handle = devfs_register( - 0 , "lvm", 0, 0, LVM_CHAR_MAJOR, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, - &lvm_chr_fops, NULL); - - lvm_proc_dir = create_proc_entry (LVM_DIR, S_IFDIR, &proc_root); - if (lvm_proc_dir != NULL) { - lvm_proc_vg_subdir = create_proc_entry (LVM_VG_SUBDIR, S_IFDIR, lvm_proc_dir); - pde = create_proc_entry(LVM_GLOBAL, S_IFREG, lvm_proc_dir); - if ( pde != NULL) pde->read_proc = &lvm_proc_get_global_info; - } - + lvm_init_fs(); lvm_init_vars(); lvm_geninit(&lvm_gendisk); @@ -463,16 +465,14 @@ return 0; } /* lvm_init() */ - /* * cleanup... */ + static void lvm_cleanup(void) { struct gendisk *gendisk_ptr = NULL, *gendisk_ptr_prev = NULL; - devfs_unregister (lvm_devfs_handle); - if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) { printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name); } @@ -481,6 +481,7 @@ } + gendisk_ptr = gendisk_ptr_prev = gendisk_head; while (gendisk_ptr != NULL) { if (gendisk_ptr == &lvm_gendisk) @@ -496,25 +497,23 @@ blksize_size[MAJOR_NR] = NULL; hardsect_size[MAJOR_NR] = NULL; - remove_proc_entry(LVM_GLOBAL, lvm_proc_dir); - remove_proc_entry(LVM_VG_SUBDIR, lvm_proc_dir); - remove_proc_entry(LVM_DIR, &proc_root); - #ifdef LVM_HD_NAME /* reference from linux/drivers/block/genhd.c */ lvm_hd_name_ptr = NULL; #endif + /* unregister with procfs and devfs */ + lvm_fin_fs(); + printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name); return; } /* lvm_cleanup() */ - /* * support function to initialize lvm variables */ -void __init lvm_init_vars(void) +static void __init lvm_init_vars(void) { int v; @@ -550,16 +549,12 @@ /* * character device open routine */ -static int lvm_chr_open(struct inode *inode, - struct file *file) +static int lvm_chr_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); -#ifdef DEBUG - printk(KERN_DEBUG - "%s -- lvm_chr_open MINOR: %d VG#: %d mode: 0x%X lock: %d\n", - lvm_name, minor, VG_CHR(minor), file->f_mode, lock); -#endif + P_DEV("%s -- lvm_chr_open MINOR: %d VG#: %d mode: 0x%X lock: %d\n", + lvm_name, minor, VG_CHR(minor), file->f_mode, lock); /* super user validation */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -567,6 +562,11 @@ /* Group special file open */ if (VG_CHR(minor) > MAX_VG) return -ENXIO; + spin_lock(&lvm_lock); + if(lock == current->pid) + _lock_open_count++; + spin_unlock(&lvm_lock); + lvm_chr_open_count++; MOD_INC_USE_COUNT; @@ -583,7 +583,7 @@ * */ static int lvm_chr_ioctl(struct inode *inode, struct file *file, - uint command, ulong a) + uint command, ulong a) { int minor = MINOR(inode->i_rdev); uint extendable, l, v; @@ -644,9 +644,13 @@ physical volume (move's done in user space's pvmove) */ return lvm_do_pe_lock_unlock(vg_ptr,arg); - case VG_CREATE: + case VG_CREATE_OLD: /* create a VGDA */ - return lvm_do_vg_create(minor, arg); + return lvm_do_vg_create(arg, minor); + + case VG_CREATE: + /* create a VGDA, assume VG number is filled in */ + return lvm_do_vg_create(arg, -1); case VG_EXTEND: /* extend a volume group */ @@ -697,7 +701,7 @@ case VG_STATUS_GET_NAMELIST: - /* get volume group count */ + /* get volume group names */ for (l = v = 0; v < ABS_MAX_VG; v++) { if (vg[v] != NULL) { if (copy_to_user(arg + l * NAME_LEN, @@ -752,6 +756,7 @@ case LV_STATUS_BYDEV: + /* get status of a logical volume by device */ return lvm_do_lv_status_bydev(vg_ptr, arg); @@ -767,18 +772,12 @@ case PV_FLUSH: /* physical volume buffer flush/invalidate */ - if (copy_from_user(&pv_flush_req, arg, - sizeof(pv_flush_req)) != 0) - return -EFAULT; - - fsync_dev(pv_flush_req.pv_dev); - invalidate_buffers(pv_flush_req.pv_dev); - return 0; + return lvm_do_pv_flush(arg); default: printk(KERN_WARNING - "%s -- lvm_chr_ioctl: unknown command %x\n", + "%s -- lvm_chr_ioctl: unknown command 0x%x\n", lvm_name, command); return -EINVAL; } @@ -790,7 +789,7 @@ /* * character device close routine */ -static int lvm_chr_close(struct inode *inode, struct file *file) +int lvm_chr_close(struct inode *inode, struct file *file) { #ifdef DEBUG int minor = MINOR(inode->i_rdev); @@ -806,10 +805,16 @@ #endif if (lvm_chr_open_count > 0) lvm_chr_open_count--; - if (lock == current->pid) { - lock = 0; /* release lock */ - wake_up_interruptible(&lvm_wait); + + spin_lock(&lvm_lock); + if(lock == current->pid) { + if(!_lock_open_count) { + lock = 0; + wake_up_interruptible(&lvm_wait); + } else + _lock_open_count--; } + spin_unlock(&lvm_lock); MOD_DEC_USE_COUNT; @@ -833,11 +838,8 @@ lv_t *lv_ptr; vg_t *vg_ptr = vg[VG_BLK(minor)]; -#ifdef DEBUG_LVM_BLK_OPEN - printk(KERN_DEBUG - "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d mode: 0x%X\n", - lvm_name, minor, VG_BLK(minor), LV_BLK(minor), file->f_mode); -#endif + P_DEV("%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d mode: 0x%X\n", + lvm_name, minor, VG_BLK(minor), LV_BLK(minor), file->f_mode); #ifdef LVM_TOTAL_RESET if (lvm_reset_spindown > 0) @@ -850,12 +852,16 @@ LV_BLK(minor) >= 0 && LV_BLK(minor) < vg_ptr->lv_max) { - /* Check parallel LV spindown (LV remove) */ + /* Check parallel LV spindown (LV remove) */ if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM; /* Check inactive LV and open for read/write */ - if (!(lv_ptr->lv_status & LV_ACTIVE)) - return -EPERM; + /* We need to be able to "read" an inactive LV + to re-activate it again */ + if ((file->f_mode & FMODE_WRITE) && + (!(lv_ptr->lv_status & LV_ACTIVE))) + return -EPERM; + if (!(lv_ptr->lv_access & LV_WRITE) && (file->f_mode & FMODE_WRITE)) return -EACCES; @@ -867,12 +873,7 @@ MOD_INC_USE_COUNT; -#ifdef DEBUG_LVM_BLK_OPEN - printk(KERN_DEBUG - "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d size: %d\n", - lvm_name, minor, VG_BLK(minor), LV_BLK(minor), - lv_ptr->lv_size); -#endif + P_DEV("%s -- OPEN OK, LV size %d\n", lvm_name, lv_ptr->lv_size); return 0; } @@ -892,7 +893,7 @@ void *arg = (void *) a; struct hd_geometry *hd = (struct hd_geometry *) a; - P_IOCTL("%s -- lvm_blk_ioctl MINOR: %d command: 0x%X arg: %X " + P_IOCTL("%s -- lvm_blk_ioctl MINOR: %d command: 0x%X arg: %lX " "VG#: %dl LV#: %d\n", lvm_name, minor, command, (ulong) arg, VG_BLK(minor), LV_BLK(minor)); @@ -922,8 +923,8 @@ /* set read ahead for block device */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; - P_IOCTL("%s -- lvm_blk_ioctl -- BLKRASET: %d sectors for %02X:%02X\n", - lvm_name, (long) arg, MAJOR(inode->i_rdev), minor); + P_IOCTL("%s -- lvm_blk_ioctl -- BLKRASET: %ld sectors for %s\n", + lvm_name, (long) arg, kdevname(inode->i_rdev)); if ((long) arg < LVM_MIN_READ_AHEAD || (long) arg > LVM_MAX_READ_AHEAD) @@ -939,6 +940,9 @@ return -EFAULT; break; + case BLKBSZGET: + case BLKBSZSET: + return blk_ioctl (inode->i_rdev, command, a); case HDIO_GETGEO: /* get disk geometry */ @@ -960,10 +964,10 @@ copy_to_user((long *) &hd->start, &start, sizeof(start)) != 0) return -EFAULT; - } - P_IOCTL("%s -- lvm_blk_ioctl -- cylinders: %d\n", - lvm_name, lv_ptr->lv_size / heads / sectors); + P_IOCTL("%s -- lvm_blk_ioctl -- cylinders: %d\n", + lvm_name, cylinders); + } break; @@ -987,6 +991,11 @@ break; case LV_BMAP: + /* turn logical block into (dev_t, block). non privileged. */ + /* don't bmap a snapshot, since the mapping can change */ + if(lv_ptr->lv_access & LV_SNAPSHOT) + return -EPERM; + /* turn logical block into (dev_t, block). non privileged. */ return lvm_user_bmap(inode, (struct lv_bmap *) arg); break; @@ -998,40 +1007,11 @@ break; case LV_SNAPSHOT_USE_RATE: - if (!(lv_ptr->lv_access & LV_SNAPSHOT)) return -EPERM; - { - lv_snapshot_use_rate_req_t lv_snapshot_use_rate_req; - - if (copy_from_user(&lv_snapshot_use_rate_req, arg, - sizeof(lv_snapshot_use_rate_req_t))) - return -EFAULT; - if (lv_snapshot_use_rate_req.rate < 0 || - lv_snapshot_use_rate_req.rate > 100) return -EFAULT; - - switch (lv_snapshot_use_rate_req.block) - { - case 0: - lv_ptr->lv_snapshot_use_rate = lv_snapshot_use_rate_req.rate; - if (lv_ptr->lv_remap_ptr * 100 / lv_ptr->lv_remap_end < lv_ptr->lv_snapshot_use_rate) - interruptible_sleep_on (&lv_ptr->lv_snapshot_wait); - break; - - case O_NONBLOCK: - break; - - default: - return -EFAULT; - } - lv_snapshot_use_rate_req.rate = lv_ptr->lv_remap_ptr * 100 / lv_ptr->lv_remap_end; - if (copy_to_user(arg, &lv_snapshot_use_rate_req, - sizeof(lv_snapshot_use_rate_req_t))) - return -EFAULT; - } - break; + return lvm_get_snapshot_use_rate(lv_ptr, arg); default: printk(KERN_WARNING - "%s -- lvm_blk_ioctl: unknown command %d\n", + "%s -- lvm_blk_ioctl: unknown command 0x%x\n", lvm_name, command); return -EINVAL; } @@ -1064,6 +1044,38 @@ return 0; } /* lvm_blk_close() */ +static int lvm_get_snapshot_use_rate(lv_t *lv, void *arg) +{ + lv_snapshot_use_rate_req_t lv_rate_req; + + if (!(lv->lv_access & LV_SNAPSHOT)) + return -EPERM; + + if (copy_from_user(&lv_rate_req, arg, sizeof(lv_rate_req))) + return -EFAULT; + + if (lv_rate_req.rate < 0 || lv_rate_req.rate > 100) + return -EINVAL; + + switch (lv_rate_req.block) { + case 0: + lv->lv_snapshot_use_rate = lv_rate_req.rate; + if (lv->lv_remap_ptr * 100 / lv->lv_remap_end < + lv->lv_snapshot_use_rate) + interruptible_sleep_on(&lv->lv_snapshot_wait); + break; + + case O_NONBLOCK: + break; + + default: + return -EINVAL; + } + lv_rate_req.rate = lv->lv_remap_ptr * 100 / lv->lv_remap_end; + + return copy_to_user(arg, &lv_rate_req, + sizeof(lv_rate_req)) ? -EFAULT : 0; +} static int lvm_user_bmap(struct inode *inode, struct lv_bmap *user_result) { @@ -1075,398 +1087,16 @@ return -EFAULT; memset(&bh,0,sizeof bh); - bh.b_rsector = block; - bh.b_dev = bh.b_rdev = inode->i_dev; + bh.b_blocknr = block; + bh.b_dev = bh.b_rdev = inode->i_rdev; bh.b_size = lvm_get_blksize(bh.b_dev); if ((err=lvm_map(&bh, READ)) < 0) { printk("lvm map failed: %d\n", err); return -EINVAL; } - return put_user(kdev_t_to_nr(bh.b_rdev), &user_result->lv_dev) || - put_user(bh.b_rsector, &user_result->lv_block) ? -EFAULT : 0; -} - - -/* - * provide VG info for proc filesystem use (global) - */ -int lvm_vg_info(vg_t *vg_ptr, char *buf) { - int sz = 0; - char inactive_flag = ' '; - - if (!(vg_ptr->vg_status & VG_ACTIVE)) inactive_flag = 'I'; - sz = sprintf(buf, - "\nVG: %c%s [%d PV, %d LV/%d open] " - " PE Size: %d KB\n" - " Usage [KB/PE]: %d /%d total " - "%d /%d used %d /%d free", - inactive_flag, - vg_ptr->vg_name, - vg_ptr->pv_cur, - vg_ptr->lv_cur, - vg_ptr->lv_open, - vg_ptr->pe_size >> 1, - vg_ptr->pe_size * vg_ptr->pe_total >> 1, - vg_ptr->pe_total, - vg_ptr->pe_allocated * vg_ptr->pe_size >> 1, - vg_ptr->pe_allocated, - (vg_ptr->pe_total - vg_ptr->pe_allocated) * - vg_ptr->pe_size >> 1, - vg_ptr->pe_total - vg_ptr->pe_allocated); - return sz; -} - - -/* - * provide LV info for proc filesystem use (global) - */ -int lvm_lv_info(vg_t *vg_ptr, lv_t *lv_ptr, char *buf) { - int sz = 0; - char inactive_flag = 'A', allocation_flag = ' ', - stripes_flag = ' ', rw_flag = ' '; - - if (!(lv_ptr->lv_status & LV_ACTIVE)) - inactive_flag = 'I'; - rw_flag = 'R'; - if (lv_ptr->lv_access & LV_WRITE) - rw_flag = 'W'; - allocation_flag = 'D'; - if (lv_ptr->lv_allocation & LV_CONTIGUOUS) - allocation_flag = 'C'; - stripes_flag = 'L'; - if (lv_ptr->lv_stripes > 1) - stripes_flag = 'S'; - sz += sprintf(buf+sz, - "[%c%c%c%c", - inactive_flag, - rw_flag, - allocation_flag, - stripes_flag); - if (lv_ptr->lv_stripes > 1) - sz += sprintf(buf+sz, "%-2d", - lv_ptr->lv_stripes); - else - sz += sprintf(buf+sz, " "); - basename = strrchr(lv_ptr->lv_name, '/'); - if ( basename == 0) basename = lv_ptr->lv_name; - else basename++; - sz += sprintf(buf+sz, "] %-25s", basename); - if (strlen(basename) > 25) - sz += sprintf(buf+sz, - "\n "); - sz += sprintf(buf+sz, "%9d /%-6d ", - lv_ptr->lv_size >> 1, - lv_ptr->lv_size / vg_ptr->pe_size); - - if (lv_ptr->lv_open == 0) - sz += sprintf(buf+sz, "close"); - else - sz += sprintf(buf+sz, "%dx open", - lv_ptr->lv_open); - - return sz; -} - - -/* - * provide PV info for proc filesystem use (global) - */ -int lvm_pv_info(pv_t *pv_ptr, char *buf) { - int sz = 0; - char inactive_flag = 'A', allocation_flag = ' '; - char *pv_name = NULL; - - if (!(pv_ptr->pv_status & PV_ACTIVE)) - inactive_flag = 'I'; - allocation_flag = 'A'; - if (!(pv_ptr->pv_allocatable & PV_ALLOCATABLE)) - allocation_flag = 'N'; - pv_name = strrchr(pv_ptr->pv_name+1,'/'); - if ( pv_name == 0) pv_name = pv_ptr->pv_name; - else pv_name++; - sz = sprintf(buf, - "[%c%c] %-21s %8d /%-6d " - "%8d /%-6d %8d /%-6d", - inactive_flag, - allocation_flag, - pv_name, - pv_ptr->pe_total * - pv_ptr->pe_size >> 1, - pv_ptr->pe_total, - pv_ptr->pe_allocated * - pv_ptr->pe_size >> 1, - pv_ptr->pe_allocated, - (pv_ptr->pe_total - - pv_ptr->pe_allocated) * - pv_ptr->pe_size >> 1, - pv_ptr->pe_total - - pv_ptr->pe_allocated); - return sz; -} - - -/* - * Support functions /proc-Filesystem - */ - -#define LVM_PROC_BUF ( i == 0 ? dummy_buf : &buf[sz]) - -/* - * provide global LVM information - */ -static int lvm_proc_get_global_info(char *page, char **start, off_t pos, int count, int *eof, void *data) -{ - int c, i, l, p, v, vg_counter, pv_counter, lv_counter, lv_open_counter, - lv_open_total, pe_t_bytes, hash_table_bytes, lv_block_exception_t_bytes, seconds; - static off_t sz; - off_t sz_last; - static char *buf = NULL; - static char dummy_buf[160]; /* sized for 2 lines */ - vg_t *vg_ptr; - lv_t *lv_ptr; - pv_t *pv_ptr; - - -#ifdef DEBUG_LVM_PROC_GET_INFO - printk(KERN_DEBUG - "%s - lvm_proc_get_global_info CALLED pos: %lu count: %d whence: %d\n", - lvm_name, pos, count, whence); -#endif - - MOD_INC_USE_COUNT; - - if (pos == 0 || buf == NULL) { - sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter = \ - lv_open_total = pe_t_bytes = hash_table_bytes = \ - lv_block_exception_t_bytes = 0; - - /* search for activity */ - for (v = 0; v < ABS_MAX_VG; v++) { - if ((vg_ptr = vg[v]) != NULL) { - vg_counter++; - pv_counter += vg_ptr->pv_cur; - lv_counter += vg_ptr->lv_cur; - if (vg_ptr->lv_cur > 0) { - for (l = 0; l < vg[v]->lv_max; l++) { - if ((lv_ptr = vg_ptr->lv[l]) != NULL) { - pe_t_bytes += lv_ptr->lv_allocated_le; - hash_table_bytes += lv_ptr->lv_snapshot_hash_table_size; - if (lv_ptr->lv_block_exception != NULL) - lv_block_exception_t_bytes += lv_ptr->lv_remap_end; - if (lv_ptr->lv_open > 0) { - lv_open_counter++; - lv_open_total += lv_ptr->lv_open; - } - } - } - } - } - } - pe_t_bytes *= sizeof(pe_t); - lv_block_exception_t_bytes *= sizeof(lv_block_exception_t); - - if (buf != NULL) { - P_KFREE("%s -- vfree %d\n", lvm_name, __LINE__); - lock_kernel(); - vfree(buf); - unlock_kernel(); - buf = NULL; - } - /* 2 times: first to get size to allocate buffer, - 2nd to fill the malloced buffer */ - for (i = 0; i < 2; i++) { - sz = 0; - sz += sprintf(LVM_PROC_BUF, - "LVM " -#ifdef MODULE - "module" -#else - "driver" -#endif - " %s\n\n" - "Total: %d VG%s %d PV%s %d LV%s ", - lvm_short_version, - vg_counter, vg_counter == 1 ? "" : "s", - pv_counter, pv_counter == 1 ? "" : "s", - lv_counter, lv_counter == 1 ? "" : "s"); - sz += sprintf(LVM_PROC_BUF, - "(%d LV%s open", - lv_open_counter, - lv_open_counter == 1 ? "" : "s"); - if (lv_open_total > 0) - sz += sprintf(LVM_PROC_BUF, - " %d times)\n", - lv_open_total); - else - sz += sprintf(LVM_PROC_BUF, ")"); - sz += sprintf(LVM_PROC_BUF, - "\nGlobal: %lu bytes malloced IOP version: %d ", - vg_counter * sizeof(vg_t) + - pv_counter * sizeof(pv_t) + - lv_counter * sizeof(lv_t) + - pe_t_bytes + hash_table_bytes + lv_block_exception_t_bytes + sz_last, - lvm_iop_version); - - seconds = CURRENT_TIME - loadtime; - if (seconds < 0) - loadtime = CURRENT_TIME + seconds; - if (seconds / 86400 > 0) { - sz += sprintf(LVM_PROC_BUF, "%d day%s ", - seconds / 86400, - seconds / 86400 == 0 || - seconds / 86400 > 1 ? "s" : ""); - } - sz += sprintf(LVM_PROC_BUF, "%d:%02d:%02d active\n", - (seconds % 86400) / 3600, - (seconds % 3600) / 60, - seconds % 60); - - if (vg_counter > 0) { - for (v = 0; v < ABS_MAX_VG; v++) { - /* volume group */ - if ((vg_ptr = vg[v]) != NULL) { - sz += lvm_vg_info(vg_ptr, LVM_PROC_BUF); - - /* physical volumes */ - sz += sprintf(LVM_PROC_BUF, - "\n PV%s ", - vg_ptr->pv_cur == 1 ? ": " : "s:"); - c = 0; - for (p = 0; p < vg_ptr->pv_max; p++) { - if ((pv_ptr = vg_ptr->pv[p]) != NULL) { - sz += lvm_pv_info(pv_ptr, LVM_PROC_BUF); - - c++; - if (c < vg_ptr->pv_cur) - sz += sprintf(LVM_PROC_BUF, - "\n "); - } - } - - /* logical volumes */ - sz += sprintf(LVM_PROC_BUF, - "\n LV%s ", - vg_ptr->lv_cur == 1 ? ": " : "s:"); - c = 0; - for (l = 0; l < vg_ptr->lv_max; l++) { - if ((lv_ptr = vg_ptr->lv[l]) != NULL) { - sz += lvm_lv_info(vg_ptr, lv_ptr, LVM_PROC_BUF); - c++; - if (c < vg_ptr->lv_cur) - sz += sprintf(LVM_PROC_BUF, - "\n "); - } - } - if (vg_ptr->lv_cur == 0) sz += sprintf(LVM_PROC_BUF, "none"); - sz += sprintf(LVM_PROC_BUF, "\n"); - } - } - } - if (buf == NULL) { - lock_kernel(); - buf = vmalloc(sz); - unlock_kernel(); - if (buf == NULL) { - sz = 0; - MOD_DEC_USE_COUNT; - return sprintf(page, "%s - vmalloc error at line %d\n", - lvm_name, __LINE__); - } - } - sz_last = sz; - } - } - MOD_DEC_USE_COUNT; - if (pos > sz - 1) { - lock_kernel(); - vfree(buf); - unlock_kernel(); - buf = NULL; - return 0; - } - *start = &buf[pos]; - if (sz - pos < count) - return sz - pos; - else - return count; -} /* lvm_proc_get_global_info() */ - - -/* - * provide VG information - */ -int lvm_proc_read_vg_info(char *page, char **start, off_t off, - int count, int *eof, void *data) { - int sz = 0; - vg_t *vg = data; - - sz += sprintf ( page+sz, "name: %s\n", vg->vg_name); - sz += sprintf ( page+sz, "size: %u\n", - vg->pe_total * vg->pe_size / 2); - sz += sprintf ( page+sz, "access: %u\n", vg->vg_access); - sz += sprintf ( page+sz, "status: %u\n", vg->vg_status); - sz += sprintf ( page+sz, "number: %u\n", vg->vg_number); - sz += sprintf ( page+sz, "LV max: %u\n", vg->lv_max); - sz += sprintf ( page+sz, "LV current: %u\n", vg->lv_cur); - sz += sprintf ( page+sz, "LV open: %u\n", vg->lv_open); - sz += sprintf ( page+sz, "PV max: %u\n", vg->pv_max); - sz += sprintf ( page+sz, "PV current: %u\n", vg->pv_cur); - sz += sprintf ( page+sz, "PV active: %u\n", vg->pv_act); - sz += sprintf ( page+sz, "PE size: %u\n", vg->pe_size / 2); - sz += sprintf ( page+sz, "PE total: %u\n", vg->pe_total); - sz += sprintf ( page+sz, "PE allocated: %u\n", vg->pe_allocated); - sz += sprintf ( page+sz, "uuid: %s\n", lvm_show_uuid(vg->vg_uuid)); - - return sz; -} - - -/* - * provide LV information - */ -int lvm_proc_read_lv_info(char *page, char **start, off_t off, - int count, int *eof, void *data) { - int sz = 0; - lv_t *lv = data; - - sz += sprintf ( page+sz, "name: %s\n", lv->lv_name); - sz += sprintf ( page+sz, "size: %u\n", lv->lv_size); - sz += sprintf ( page+sz, "access: %u\n", lv->lv_access); - sz += sprintf ( page+sz, "status: %u\n", lv->lv_status); - sz += sprintf ( page+sz, "number: %u\n", lv->lv_number); - sz += sprintf ( page+sz, "open: %u\n", lv->lv_open); - sz += sprintf ( page+sz, "allocation: %u\n", lv->lv_allocation); - sz += sprintf ( page+sz, "device: %02u:%02u\n", - MAJOR(lv->lv_dev), MINOR(lv->lv_dev)); - - return sz; -} - - -/* - * provide PV information - */ -int lvm_proc_read_pv_info(char *page, char **start, off_t off, - int count, int *eof, void *data) { - int sz = 0; - pv_t *pv = data; - - sz += sprintf ( page+sz, "name: %s\n", pv->pv_name); - sz += sprintf ( page+sz, "size: %u\n", pv->pv_size); - sz += sprintf ( page+sz, "status: %u\n", pv->pv_status); - sz += sprintf ( page+sz, "number: %u\n", pv->pv_number); - sz += sprintf ( page+sz, "allocatable: %u\n", pv->pv_allocatable); - sz += sprintf ( page+sz, "LV current: %u\n", pv->lv_cur); - sz += sprintf ( page+sz, "PE size: %u\n", pv->pe_size / 2); - sz += sprintf ( page+sz, "PE total: %u\n", pv->pe_total); - sz += sprintf ( page+sz, "PE allocated: %u\n", pv->pe_allocated); - sz += sprintf ( page+sz, "device: %02u:%02u\n", - MAJOR(pv->pv_dev), MINOR(pv->pv_dev)); - sz += sprintf ( page+sz, "uuid: %s\n", lvm_show_uuid(pv->pv_uuid)); - - - return sz; + return (put_user(kdev_t_to_nr(bh.b_rdev), &user_result->lv_dev) || + put_user(bh.b_rsector/(bh.b_size>>9), &user_result->lv_block)); } @@ -1474,172 +1104,151 @@ * block device support function for /usr/src/linux/drivers/block/ll_rw_blk.c * (see init_module/lvm_init) */ +static inline void __remap_snapshot(kdev_t rdev, ulong rsector, + ulong pe_start, lv_t *lv, vg_t *vg) { + if (!lvm_snapshot_remap_block(&rdev, &rsector, pe_start, lv) && + !lvm_snapshot_COW(rdev, rsector, pe_start, rsector, vg, lv)) + lvm_write_COW_table_block(vg, lv); +} + static int lvm_map(struct buffer_head *bh, int rw) { - int minor = MINOR(bh->b_rdev); - int ret = 0; + int minor = MINOR(bh->b_dev); ulong index; ulong pe_start; ulong size = bh->b_size >> 9; - ulong rsector_tmp = bh->b_rsector; - ulong rsector_sav; - kdev_t rdev_tmp = bh->b_rdev; - kdev_t rdev_sav; + ulong rsector_org = bh->b_rsector; + ulong rsector_map; + kdev_t rdev_map; vg_t *vg_this = vg[VG_BLK(minor)]; lv_t *lv = vg_this->lv[LV_BLK(minor)]; + down(&lv->lv_snapshot_sem); if (!(lv->lv_status & LV_ACTIVE)) { printk(KERN_ALERT "%s - lvm_map: ll_rw_blk for inactive LV %s\n", lvm_name, lv->lv_name); - return -1; + goto bad; } if ((rw == WRITE || rw == WRITEA) && !(lv->lv_access & LV_WRITE)) { printk(KERN_CRIT - "%s - lvm_map: ll_rw_blk write for readonly LV %s\n", + "%s - lvm_map: ll_rw_blk write for readonly LV %s\n", lvm_name, lv->lv_name); - return -1; + goto bad; } - P_MAP("%s - lvm_map minor:%d *rdev: %02d:%02d *rsector: %lu " - "size:%lu\n", + P_MAP("%s - lvm_map minor: %d *rdev: %s *rsector: %lu size:%lu\n", lvm_name, minor, - MAJOR(rdev_tmp), - MINOR(rdev_tmp), - rsector_tmp, size); + kdevname(bh->b_dev), + rsector_org, size); - if (rsector_tmp + size > lv->lv_size) { + if (rsector_org + size > lv->lv_size) { printk(KERN_ALERT "%s - lvm_map access beyond end of device; *rsector: " "%lu or size: %lu wrong for minor: %2d\n", - lvm_name, rsector_tmp, size, minor); - return -1; + lvm_name, rsector_org, size, minor); + goto bad; } - rsector_sav = rsector_tmp; - rdev_sav = rdev_tmp; -lvm_second_remap: - /* linear mapping */ - if (lv->lv_stripes < 2) { +remap: + if (lv->lv_stripes < 2) { /* linear mapping */ /* get the index */ - index = rsector_tmp / vg_this->pe_size; + index = rsector_org / vg_this->pe_size; pe_start = lv->lv_current_pe[index].pe; - rsector_tmp = lv->lv_current_pe[index].pe + - (rsector_tmp % vg_this->pe_size); - rdev_tmp = lv->lv_current_pe[index].dev; - - P_MAP("lv_current_pe[%ld].pe: %ld rdev: %02d:%02d " - "rsector:%ld\n", - index, - lv->lv_current_pe[index].pe, - MAJOR(rdev_tmp), - MINOR(rdev_tmp), - rsector_tmp); + rsector_map = lv->lv_current_pe[index].pe + + (rsector_org % vg_this->pe_size); + rdev_map = lv->lv_current_pe[index].dev; + + P_MAP("lv_current_pe[%ld].pe: %d rdev: %s rsector:%ld\n", + index, lv->lv_current_pe[index].pe, + kdevname(rdev_map), rsector_map); - /* striped mapping */ - } else { + } else { /* striped mapping */ ulong stripe_index; ulong stripe_length; stripe_length = vg_this->pe_size * lv->lv_stripes; - stripe_index = (rsector_tmp % stripe_length) / lv->lv_stripesize; - index = rsector_tmp / stripe_length + - (stripe_index % lv->lv_stripes) * - (lv->lv_allocated_le / lv->lv_stripes); + stripe_index = (rsector_org % stripe_length) / + lv->lv_stripesize; + index = rsector_org / stripe_length + + (stripe_index % lv->lv_stripes) * + (lv->lv_allocated_le / lv->lv_stripes); pe_start = lv->lv_current_pe[index].pe; - rsector_tmp = lv->lv_current_pe[index].pe + - (rsector_tmp % stripe_length) - - (stripe_index % lv->lv_stripes) * lv->lv_stripesize - - stripe_index / lv->lv_stripes * - (lv->lv_stripes - 1) * lv->lv_stripesize; - rdev_tmp = lv->lv_current_pe[index].dev; - } - - P_MAP("lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n" - "stripe_length: %ld stripe_index: %ld\n", - index, - lv->lv_current_pe[index].pe, - MAJOR(rdev_tmp), - MINOR(rdev_tmp), - rsector_tmp, - stripe_length, - stripe_index); + rsector_map = lv->lv_current_pe[index].pe + + (rsector_org % stripe_length) - + (stripe_index % lv->lv_stripes) * lv->lv_stripesize - + stripe_index / lv->lv_stripes * + (lv->lv_stripes - 1) * lv->lv_stripesize; + rdev_map = lv->lv_current_pe[index].dev; + + P_MAP("lv_current_pe[%ld].pe: %d rdev: %s rsector:%ld\n" + "stripe_length: %ld stripe_index: %ld\n", + index, lv->lv_current_pe[index].pe, kdevname(rdev_map), + rsector_map, stripe_length, stripe_index); + } /* handle physical extents on the move */ if (pe_lock_req.lock == LOCK_PE) { - if (rdev_tmp == pe_lock_req.data.pv_dev && - rsector_tmp >= pe_lock_req.data.pv_offset && - rsector_tmp < (pe_lock_req.data.pv_offset + + if (rdev_map == pe_lock_req.data.pv_dev && + rsector_map >= pe_lock_req.data.pv_offset && + rsector_map < (pe_lock_req.data.pv_offset + vg_this->pe_size)) { sleep_on(&lvm_map_wait); - rsector_tmp = rsector_sav; - rdev_tmp = rdev_sav; - goto lvm_second_remap; + goto remap; } } + /* statistic */ if (rw == WRITE || rw == WRITEA) lv->lv_current_pe[index].writes++; else lv->lv_current_pe[index].reads++; - /* snapshot volume exception handling on physical device address base */ - if (lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG)) { - /* original logical volume */ - if (lv->lv_access & LV_SNAPSHOT_ORG) { - /* Serializes the access to the lv_snapshot_next list */ - down(&lv->lv_snapshot_sem); - if (rw == WRITE || rw == WRITEA) - { - lv_t *lv_ptr; - - /* start with first snapshot and loop thrugh all of them */ - for (lv_ptr = lv->lv_snapshot_next; - lv_ptr != NULL; - lv_ptr = lv_ptr->lv_snapshot_next) { - /* Check for inactive snapshot */ - if (!(lv_ptr->lv_status & LV_ACTIVE)) continue; - /* Serializes the COW with the accesses to the snapshot device */ - down(&lv_ptr->lv_snapshot_sem); - /* do we still have exception storage for this snapshot free? */ - if (lv_ptr->lv_block_exception != NULL) { - rdev_sav = rdev_tmp; - rsector_sav = rsector_tmp; - if (!lvm_snapshot_remap_block(&rdev_tmp, - &rsector_tmp, - pe_start, - lv_ptr)) { - /* create a new mapping */ - if (!(ret = lvm_snapshot_COW(rdev_tmp, - rsector_tmp, - pe_start, - rsector_sav, - lv_ptr))) - ret = lvm_write_COW_table_block(vg_this, - lv_ptr); - } - rdev_tmp = rdev_sav; - rsector_tmp = rsector_sav; - } - up(&lv_ptr->lv_snapshot_sem); - } - } - up(&lv->lv_snapshot_sem); - } else { - /* remap snapshot logical volume */ - down(&lv->lv_snapshot_sem); - if (lv->lv_block_exception != NULL) - lvm_snapshot_remap_block(&rdev_tmp, &rsector_tmp, pe_start, lv); - up(&lv->lv_snapshot_sem); + /* snapshot volume exception handling on physical device + address base */ + if (!(lv->lv_access & (LV_SNAPSHOT|LV_SNAPSHOT_ORG))) + goto out; + + if (lv->lv_access & LV_SNAPSHOT) { /* remap snapshot */ + if (lv->lv_block_exception) + lvm_snapshot_remap_block(&rdev_map, &rsector_map, + pe_start, lv); + else + goto bad; + + } else if(rw == WRITE || rw == WRITEA) { /* snapshot origin */ + lv_t *snap; + + /* start with first snapshot and loop through all of + them */ + for (snap = lv->lv_snapshot_next; snap; + snap = snap->lv_snapshot_next) { + /* Check for inactive snapshot */ + if (!(snap->lv_status & LV_ACTIVE)) + continue; + + /* Serializes the COW with the accesses to the + snapshot device */ + down(&snap->lv_snapshot_sem); + __remap_snapshot(rdev_map, rsector_map, + pe_start, snap, vg_this); + up(&snap->lv_snapshot_sem); } } - bh->b_rdev = rdev_tmp; - bh->b_rsector = rsector_tmp; - return ret; + out: + bh->b_rdev = rdev_map; + bh->b_rsector = rsector_map; + up(&lv->lv_snapshot_sem); + return 1; + + bad: + buffer_IO_error(bh); + up(&lv->lv_snapshot_sem); + return -1; } /* lvm_map() */ @@ -1667,12 +1276,14 @@ #endif + + /* * make request function */ -static int lvm_make_request_fn(request_queue_t *q, - int rw, - struct buffer_head *bh) +static int lvm_make_request_fn(request_queue_t *q, + int rw, + struct buffer_head *bh) { if (lvm_map(bh, rw) >= 0) return 1; @@ -1781,6 +1392,8 @@ le_remap_req.new_dev; lv_ptr->lv_current_pe[le].pe = le_remap_req.new_pe; + + __update_hardsectsize(lv_ptr); return 0; } } @@ -1794,7 +1407,7 @@ /* * character device support function VGDA create */ -int lvm_do_vg_create(int minor, void *arg) +static int lvm_do_vg_create(void *arg, int minor) { int ret = 0; ulong l, ls = 0, p, size; @@ -1802,8 +1415,6 @@ vg_t *vg_ptr; lv_t **snap_lv_ptr; - if (vg[VG_CHR(minor)] != NULL) return -EPERM; - if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) { printk(KERN_CRIT "%s -- VG_CREATE: kmalloc error VG at line %d\n", @@ -1816,28 +1427,40 @@ return -EFAULT; } + /* VG_CREATE now uses minor number in VG structure */ + if (minor == -1) minor = vg_ptr->vg_number; + + /* Validate it */ + if (vg[VG_CHR(minor)] != NULL) { + kfree(vg_ptr); + return -EPERM; + } + /* we are not that active so far... */ vg_ptr->vg_status &= ~VG_ACTIVE; - vg[VG_CHR(minor)] = vg_ptr; - vg[VG_CHR(minor)]->pe_allocated = 0; + vg_ptr->pe_allocated = 0; if (vg_ptr->pv_max > ABS_MAX_PV) { printk(KERN_WARNING "%s -- Can't activate VG: ABS_MAX_PV too small\n", lvm_name); kfree(vg_ptr); - vg[VG_CHR(minor)] = NULL; return -EPERM; } + if (vg_ptr->lv_max > ABS_MAX_LV) { printk(KERN_WARNING "%s -- Can't activate VG: ABS_MAX_LV too small for %u\n", lvm_name, vg_ptr->lv_max); kfree(vg_ptr); - vg_ptr = NULL; return -EPERM; } + /* create devfs and procfs entries */ + lvm_fs_create_vg(vg_ptr); + + vg[VG_CHR(minor)] = vg_ptr; + /* get the physical volume structures */ vg_ptr->pv_act = vg_ptr->pv_cur = 0; for (p = 0; p < vg_ptr->pv_max; p++) { @@ -1885,8 +1508,6 @@ } } - lvm_do_create_devfs_entry_of_vg ( vg_ptr); - /* Second path to correct snapshot logical volumes which are not in place during first path above */ for (l = 0; l < ls; l++) { @@ -1901,8 +1522,6 @@ } } - lvm_do_create_proc_entry_of_vg ( vg_ptr); - vfree(snap_lv_ptr); vg_count++; @@ -1934,7 +1553,6 @@ if ( ret != 0) return ret; pv_ptr = vg_ptr->pv[p]; vg_ptr->pe_total += pv_ptr->pe_total; - lvm_do_create_proc_entry_of_pv(vg_ptr, pv_ptr); return 0; } } @@ -1984,10 +1602,13 @@ lv_t *lv_ptr = NULL; pv_t *pv_ptr = NULL; + /* If the VG doesn't exist in the kernel then just exit */ + if (!vg_ptr) return 0; + if (copy_from_user(vg_name, arg, sizeof(vg_name)) != 0) return -EFAULT; - lvm_do_remove_proc_entry_of_vg ( vg_ptr); + lvm_fs_remove_vg(vg_ptr); strncpy ( vg_ptr->vg_name, vg_name, sizeof ( vg_name)-1); for ( l = 0; l < vg_ptr->lv_max; l++) @@ -2009,7 +1630,7 @@ strncpy(pv_ptr->vg_name, vg_name, NAME_LEN); } - lvm_do_create_proc_entry_of_vg ( vg_ptr); + lvm_fs_create_vg(vg_ptr); return 0; } /* lvm_do_vg_rename */ @@ -2036,6 +1657,9 @@ /* let's go inactive */ vg_ptr->vg_status &= ~VG_ACTIVE; + /* remove from procfs and devfs */ + lvm_fs_remove_vg(vg_ptr); + /* free LVs */ /* first free snapshot logical volumes */ for (i = 0; i < vg_ptr->lv_max; i++) { @@ -2063,11 +1687,6 @@ } } - devfs_unregister (ch_devfs_handle[vg_ptr->vg_number]); - devfs_unregister (vg_devfs_handle[vg_ptr->vg_number]); - - lvm_do_remove_proc_entry_of_vg ( vg_ptr); - P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__); kfree(vg_ptr); vg[VG_CHR(minor)] = NULL; @@ -2089,7 +1708,7 @@ pv_ptr = vg_ptr->pv[p] = kmalloc(sizeof(pv_t),GFP_KERNEL); if (pv_ptr == NULL) { printk(KERN_CRIT - "%s -- VG_CREATE: kmalloc error PV at line %d\n", + "%s -- PV_CREATE: kmalloc error PV at line %d\n", lvm_name, __LINE__); return -ENOMEM; } @@ -2103,18 +1722,20 @@ pv_ptr->pv_status = PV_ACTIVE; vg_ptr->pv_act++; vg_ptr->pv_cur++; + lvm_fs_create_pv(vg_ptr, pv_ptr); return 0; } /* lvm_do_pv_create() */ /* - * character device support function physical volume create + * character device support function physical volume remove */ static int lvm_do_pv_remove(vg_t *vg_ptr, ulong p) { pv_t *pv_ptr = vg_ptr->pv[p]; - lvm_do_remove_proc_entry_of_pv ( vg_ptr, pv_ptr); + lvm_fs_remove_pv(vg_ptr, pv_ptr); + vg_ptr->pe_total -= pv_ptr->pe_total; vg_ptr->pv_cur--; vg_ptr->pv_act--; @@ -2128,12 +1749,39 @@ } +static void __update_hardsectsize(lv_t *lv) { + int le, e; + int max_hardsectsize = 0, hardsectsize; + + for (le = 0; le < lv->lv_allocated_le; le++) { + hardsectsize = get_hardsect_size(lv->lv_current_pe[le].dev); + if (hardsectsize == 0) + hardsectsize = 512; + if (hardsectsize > max_hardsectsize) + max_hardsectsize = hardsectsize; + } + + if (lv->lv_access & LV_SNAPSHOT) { + for (e = 0; e < lv->lv_remap_end; e++) { + hardsectsize = + get_hardsect_size( + lv->lv_block_exception[e].rdev_new); + if (hardsectsize == 0) + hardsectsize = 512; + if (hardsectsize > max_hardsectsize) + max_hardsectsize = hardsectsize; + } + } + + lvm_hardsectsizes[MINOR(lv->lv_dev)] = max_hardsectsize; +} + /* * character device support function logical volume create */ static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv) { - int e, ret, l, le, l_new, p, size; + int e, ret, l, le, l_new, p, size, activate = 1; ulong lv_status_save; lv_block_exception_t *lvbe = lv->lv_block_exception; vg_t *vg_ptr = vg[VG_CHR(minor)]; @@ -2143,7 +1791,7 @@ if (lv->lv_chunk_size > LVM_SNAPSHOT_MAX_CHUNK) return -EINVAL; - for (l = 0; l < vg_ptr->lv_max; l++) { + for (l = 0; l < vg_ptr->lv_cur; l++) { if (vg_ptr->lv[l] != NULL && strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) return -EEXIST; @@ -2177,16 +1825,17 @@ lv_ptr->lv_snapshot_next = NULL; lv_ptr->lv_block_exception = NULL; lv_ptr->lv_iobuf = NULL; + lv_ptr->lv_COW_table_iobuf = NULL; lv_ptr->lv_snapshot_hash_table = NULL; lv_ptr->lv_snapshot_hash_table_size = 0; lv_ptr->lv_snapshot_hash_mask = 0; - lv_ptr->lv_COW_table_page = NULL; init_MUTEX(&lv_ptr->lv_snapshot_sem); lv_ptr->lv_snapshot_use_rate = 0; + vg_ptr->lv[l] = lv_ptr; /* get the PE structures from user space if this - is no snapshot logical volume */ + is not a snapshot logical volume */ if (!(lv_ptr->lv_access & LV_SNAPSHOT)) { size = lv_ptr->lv_allocated_le * sizeof(pe_t); if ((lv_ptr->lv_current_pe = vmalloc(size)) == NULL) { @@ -2238,6 +1887,16 @@ vg_ptr->lv[l] = NULL; return -EFAULT; } + + if(lv_ptr->lv_block_exception[0].rsector_org == + LVM_SNAPSHOT_DROPPED_SECTOR) + { + printk(KERN_WARNING + "%s -- lvm_do_lv_create: snapshot has been dropped and will not be activated\n", + lvm_name); + activate = 0; + } + /* point to the original logical volume */ lv_ptr = lv_ptr->lv_snapshot_org; @@ -2271,10 +1930,13 @@ lv_ptr->lv_block_exception[e].rsector_org, lv_ptr); /* need to fill the COW exception table data into the page for disk i/o */ - lvm_snapshot_fill_COW_page(vg_ptr, lv_ptr); + if(lvm_snapshot_fill_COW_page(vg_ptr, lv_ptr)) { + kfree(lv_ptr); + vg_ptr->lv[l] = NULL; + return -EINVAL; + } init_waitqueue_head(&lv_ptr->lv_snapshot_wait); } else { - vfree(lv_ptr->lv_block_exception); kfree(lv_ptr); vg_ptr->lv[l] = NULL; return -EFAULT; @@ -2296,21 +1958,7 @@ vg_ptr->lv_cur++; lv_ptr->lv_status = lv_status_save; - { - char *lv_tmp, *lv_buf = lv->lv_name; - - strtok(lv->lv_name, "/"); /* /dev */ - while((lv_tmp = strtok(NULL, "/")) != NULL) - lv_buf = lv_tmp; - - lv_devfs_handle[lv->lv_number] = devfs_register( - vg_devfs_handle[vg_ptr->vg_number], lv_buf, - DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, lv->lv_number, - S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, - &lvm_blk_dops, NULL); - } - - lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr); + __update_hardsectsize(lv_ptr); /* optionally add our new snapshot LV */ if (lv_ptr->lv_access & LV_SNAPSHOT) { @@ -2327,6 +1975,7 @@ org->lv_access |= LV_SNAPSHOT_ORG; lv_ptr->lv_access &= ~LV_SNAPSHOT_ORG; /* this can only hide an userspace bug */ + /* Link in the list of snapshot volumes */ for (last = org; last->lv_snapshot_next; last = last->lv_snapshot_next); lv_ptr->lv_snapshot_prev = last; @@ -2335,7 +1984,11 @@ } /* activate the logical volume */ - lv_ptr->lv_status |= LV_ACTIVE; + if(activate) + lv_ptr->lv_status |= LV_ACTIVE; + else + lv_ptr->lv_status &= ~LV_ACTIVE; + if ( lv_ptr->lv_access & LV_WRITE) set_device_ro(lv_ptr->lv_dev, 0); else @@ -2350,6 +2003,7 @@ lv_ptr->vg = vg_ptr; + lvm_fs_create_lv(vg_ptr, lv_ptr); return 0; } /* lvm_do_lv_create() */ @@ -2387,6 +2041,8 @@ lv_ptr->lv_snapshot_next != NULL) return -EPERM; + lvm_fs_remove_lv(vg_ptr, lv_ptr); + if (lv_ptr->lv_access & LV_SNAPSHOT) { /* * Atomically make the the snapshot invisible @@ -2401,11 +2057,13 @@ lv_ptr->lv_snapshot_next->lv_snapshot_prev = lv_ptr->lv_snapshot_prev; } - up(&org->lv_snapshot_sem); /* no more snapshots? */ - if (!org->lv_snapshot_next) + if (!org->lv_snapshot_next) { org->lv_access &= ~LV_SNAPSHOT_ORG; + } + up(&org->lv_snapshot_sem); + lvm_snapshot_release(lv_ptr); /* Update the VG PE(s) used by snapshot reserve space. */ @@ -2448,10 +2106,6 @@ vfree(lv_ptr->lv_current_pe); } - devfs_unregister(lv_devfs_handle[lv_ptr->lv_number]); - - lvm_do_remove_proc_entry_of_lv ( vg_ptr, lv_ptr); - P_KFREE("%s -- kfree %d\n", lvm_name, __LINE__); kfree(lv_ptr); vg_ptr->lv[l] = NULL; @@ -2461,204 +2115,212 @@ /* - * character device support function logical volume extend / reduce + * logical volume extend / reduce */ -static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *lv) -{ - ulong end, l, le, p, size, old_allocated_le; - vg_t *vg_ptr = vg[VG_CHR(minor)]; - lv_t *lv_ptr; - pe_t *pe; +static int __extend_reduce_snapshot(vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) { + ulong size; + lv_block_exception_t *lvbe; - if ((pep = lv->lv_current_pe) == NULL) return -EINVAL; + if (!new_lv->lv_block_exception) + return -ENXIO; - for (l = 0; l < vg_ptr->lv_max; l++) { - if (vg_ptr->lv[l] != NULL && - strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) - break; + size = new_lv->lv_remap_end * sizeof(lv_block_exception_t); + if ((lvbe = vmalloc(size)) == NULL) { + printk(KERN_CRIT + "%s -- lvm_do_lv_extend_reduce: vmalloc " + "error LV_BLOCK_EXCEPTION of %lu Byte at line %d\n", + lvm_name, size, __LINE__); + return -ENOMEM; } - if (l == vg_ptr->lv_max) return -ENXIO; - lv_ptr = vg_ptr->lv[l]; - /* check for active snapshot */ - if (lv->lv_access & LV_SNAPSHOT) - { - ulong e; - lv_block_exception_t *lvbe, *lvbe_old; - struct list_head * lvs_hash_table_old; - - if (lv->lv_block_exception == NULL) return -ENXIO; - size = lv->lv_remap_end * sizeof ( lv_block_exception_t); - if ((lvbe = vmalloc(size)) == NULL) - { - printk(KERN_CRIT - "%s -- lvm_do_lv_extend_reduce: vmalloc error LV_BLOCK_EXCEPTION " - "of %lu Byte at line %d\n", - lvm_name, size, __LINE__); - return -ENOMEM; - } - if (lv->lv_remap_end > lv_ptr->lv_remap_end) - { - if (copy_from_user(lvbe, lv->lv_block_exception, size)) - { - vfree(lvbe); - return -EFAULT; - } - } - - lvbe_old = lv_ptr->lv_block_exception; - lvs_hash_table_old = lv_ptr->lv_snapshot_hash_table; - - /* we need to play on the safe side here... */ - down(&lv_ptr->lv_snapshot_org->lv_snapshot_sem); - if (lv_ptr->lv_block_exception == NULL || - lv_ptr->lv_remap_ptr > lv_ptr->lv_remap_end) - { - up(&lv_ptr->lv_snapshot_org->lv_snapshot_sem); - vfree(lvbe); - return -EPERM; - } - memcpy(lvbe, - lv_ptr->lv_block_exception, - (lv->lv_remap_end > lv_ptr->lv_remap_end ? - lv_ptr->lv_remap_ptr : lv->lv_remap_end) * sizeof(lv_block_exception_t)); - - lv_ptr->lv_block_exception = lvbe; - lv_ptr->lv_remap_end = lv->lv_remap_end; - if (lvm_snapshot_alloc_hash_table(lv_ptr) != 0) - { - lvm_drop_snapshot(lv_ptr, "no memory for hash table"); - up(&lv_ptr->lv_snapshot_org->lv_snapshot_sem); - vfree(lvbe_old); - vfree(lvs_hash_table_old); - return -ENOMEM; - } - - for (e = 0; e < lv_ptr->lv_remap_ptr; e++) - lvm_hash_link (lv_ptr->lv_block_exception + e, - lv_ptr->lv_block_exception[e].rdev_org, - lv_ptr->lv_block_exception[e].rsector_org, lv_ptr); - - up(&lv_ptr->lv_snapshot_org->lv_snapshot_sem); - - vfree(lvbe_old); - vfree(lvs_hash_table_old); + if ((new_lv->lv_remap_end > old_lv->lv_remap_end) && + (copy_from_user(lvbe, new_lv->lv_block_exception, size))) { + vfree(lvbe); + return -EFAULT; + } + new_lv->lv_block_exception = lvbe; - return 0; + if (lvm_snapshot_alloc_hash_table(new_lv)) { + vfree(new_lv->lv_block_exception); + return -ENOMEM; } + return 0; +} - /* we drop in here in case it is an original logical volume */ - if ((pe = vmalloc(size = lv->lv_current_le * sizeof(pe_t))) == NULL) { +static int __extend_reduce(vg_t *vg_ptr, lv_t *old_lv, lv_t *new_lv) { + ulong size, l, p, end; + pe_t *pe; + + /* allocate space for new pe structures */ + size = new_lv->lv_current_le * sizeof(pe_t); + if ((pe = vmalloc(size)) == NULL) { printk(KERN_CRIT - "%s -- lvm_do_lv_extend_reduce: vmalloc error LV_CURRENT_PE " - "of %lu Byte at line %d\n", + "%s -- lvm_do_lv_extend_reduce: " + "vmalloc error LV_CURRENT_PE of %lu Byte at line %d\n", lvm_name, size, __LINE__); return -ENOMEM; } + /* get the PE structures from user space */ - if (copy_from_user(pe, pep, size)) { + if (copy_from_user(pe, new_lv->lv_current_pe, size)) { + if(old_lv->lv_access & LV_SNAPSHOT) + vfree(new_lv->lv_snapshot_hash_table); vfree(pe); return -EFAULT; } + new_lv->lv_current_pe = pe; + /* reduce allocation counters on PV(s) */ - for (le = 0; le < lv_ptr->lv_allocated_le; le++) { + for (l = 0; l < old_lv->lv_allocated_le; l++) { vg_ptr->pe_allocated--; for (p = 0; p < vg_ptr->pv_cur; p++) { if (vg_ptr->pv[p]->pv_dev == - lv_ptr->lv_current_pe[le].dev) { + old_lv->lv_current_pe[l].dev) { vg_ptr->pv[p]->pe_allocated--; break; } } } - - /* save pointer to "old" lv/pe pointer array */ - pep1 = lv_ptr->lv_current_pe; - end = lv_ptr->lv_current_le; - - /* save open counter... */ - lv->lv_open = lv_ptr->lv_open; - lv->lv_snapshot_prev = lv_ptr->lv_snapshot_prev; - lv->lv_snapshot_next = lv_ptr->lv_snapshot_next; - lv->lv_snapshot_org = lv_ptr->lv_snapshot_org; - - lv->lv_current_pe = pe; - - /* save # of old allocated logical extents */ - old_allocated_le = lv_ptr->lv_allocated_le; - - /* copy preloaded LV */ - memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t)); - - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0; - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size; - lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1; - /* vg_lv_map array doesn't have to be changed here */ - - LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); + /* extend the PE count in PVs */ + for (l = 0; l < new_lv->lv_allocated_le; l++) { + vg_ptr->pe_allocated++; + for (p = 0; p < vg_ptr->pv_cur; p++) { + if (vg_ptr->pv[p]->pv_dev == + new_lv->lv_current_pe[l].dev) { + vg_ptr->pv[p]->pe_allocated++; + break; + } + } + } /* save availiable i/o statistic data */ - /* linear logical volume */ - if (lv_ptr->lv_stripes < 2) { - /* Check what last LE shall be used */ - if (end > lv_ptr->lv_current_le) end = lv_ptr->lv_current_le; - for (le = 0; le < end; le++) { - lv_ptr->lv_current_pe[le].reads += pep1[le].reads; - lv_ptr->lv_current_pe[le].writes += pep1[le].writes; + if (old_lv->lv_stripes < 2) { /* linear logical volume */ + end = min(old_lv->lv_current_le, new_lv->lv_current_le); + for (l = 0; l < end; l++) { + new_lv->lv_current_pe[l].reads += + old_lv->lv_current_pe[l].reads; + + new_lv->lv_current_pe[l].writes += + old_lv->lv_current_pe[l].writes; } - /* striped logical volume */ - } else { + + } else { /* striped logical volume */ uint i, j, source, dest, end, old_stripe_size, new_stripe_size; - old_stripe_size = old_allocated_le / lv_ptr->lv_stripes; - new_stripe_size = lv_ptr->lv_allocated_le / lv_ptr->lv_stripes; - end = old_stripe_size; - if (end > new_stripe_size) end = new_stripe_size; + old_stripe_size = old_lv->lv_allocated_le / old_lv->lv_stripes; + new_stripe_size = new_lv->lv_allocated_le / new_lv->lv_stripes; + end = min(old_stripe_size, new_stripe_size); + for (i = source = dest = 0; - i < lv_ptr->lv_stripes; i++) { + i < new_lv->lv_stripes; i++) { for (j = 0; j < end; j++) { - lv_ptr->lv_current_pe[dest + j].reads += - pep1[source + j].reads; - lv_ptr->lv_current_pe[dest + j].writes += - pep1[source + j].writes; + new_lv->lv_current_pe[dest + j].reads += + old_lv->lv_current_pe[source + j].reads; + new_lv->lv_current_pe[dest + j].writes += + old_lv->lv_current_pe[source + j].writes; } source += old_stripe_size; dest += new_stripe_size; } } - /* extend the PE count in PVs */ - for (le = 0; le < lv_ptr->lv_allocated_le; le++) { - vg_ptr->pe_allocated++; - for (p = 0; p < vg_ptr->pv_cur; p++) { - if (vg_ptr->pv[p]->pv_dev == - lv_ptr->lv_current_pe[le].dev) { - vg_ptr->pv[p]->pe_allocated++; - break; - } - } - } + return 0; +} + +static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *new_lv) +{ + int r; + ulong l, e, size; + vg_t *vg_ptr = vg[VG_CHR(minor)]; + lv_t *old_lv; + pe_t *pe; - vfree ( pep1); - pep1 = NULL; + if ((pe = new_lv->lv_current_pe) == NULL) + return -EINVAL; - if (lv->lv_access & LV_SNAPSHOT_ORG) - { - /* Correct the snapshot size information */ - while ((lv_ptr = lv_ptr->lv_snapshot_next) != NULL) - { - lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe; - lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le; - lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le; - lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size; - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size; - lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1; + for (l = 0; l < vg_ptr->lv_max; l++) + if (vg_ptr->lv[l] && !strcmp(vg_ptr->lv[l]->lv_name, lv_name)) + break; + + if (l == vg_ptr->lv_max) + return -ENXIO; + + old_lv = vg_ptr->lv[l]; + + if (old_lv->lv_access & LV_SNAPSHOT) + r = __extend_reduce_snapshot(vg_ptr, old_lv, new_lv); + else + r = __extend_reduce(vg_ptr, old_lv, new_lv); + + if(r) + return r; + + /* copy relevent fields */ + down(&old_lv->lv_snapshot_sem); + + if(new_lv->lv_access & LV_SNAPSHOT) { + + size = (new_lv->lv_remap_end > old_lv->lv_remap_end) ? + old_lv->lv_remap_ptr : new_lv->lv_remap_end; + size *= sizeof(lv_block_exception_t); + memcpy(new_lv->lv_block_exception, + old_lv->lv_block_exception, size); + + old_lv->lv_remap_end = new_lv->lv_remap_end; + old_lv->lv_block_exception = new_lv->lv_block_exception; + old_lv->lv_snapshot_hash_table = + new_lv->lv_snapshot_hash_table; + old_lv->lv_snapshot_hash_table_size = + new_lv->lv_snapshot_hash_table_size; + old_lv->lv_snapshot_hash_mask = + new_lv->lv_snapshot_hash_mask; + + for (e = 0; e < new_lv->lv_remap_ptr; e++) + lvm_hash_link(new_lv->lv_block_exception + e, + new_lv->lv_block_exception[e].rdev_org, + new_lv->lv_block_exception[e].rsector_org, + new_lv); + + } else { + + vfree(old_lv->lv_current_pe); + vfree(old_lv->lv_snapshot_hash_table); + + old_lv->lv_size = new_lv->lv_size; + old_lv->lv_allocated_le = new_lv->lv_allocated_le; + old_lv->lv_current_le = new_lv->lv_current_le; + old_lv->lv_current_pe = new_lv->lv_current_pe; + lvm_gendisk.part[MINOR(old_lv->lv_dev)].nr_sects = + old_lv->lv_size; + lvm_size[MINOR(old_lv->lv_dev)] = old_lv->lv_size >> 1; + + if (old_lv->lv_access & LV_SNAPSHOT_ORG) { + lv_t *snap; + for(snap = old_lv->lv_snapshot_next; snap; + snap = snap->lv_snapshot_next) { + down(&snap->lv_snapshot_sem); + snap->lv_current_pe = old_lv->lv_current_pe; + snap->lv_allocated_le = + old_lv->lv_allocated_le; + snap->lv_current_le = old_lv->lv_current_le; + snap->lv_size = old_lv->lv_size; + + lvm_gendisk.part[MINOR(snap->lv_dev)].nr_sects + = old_lv->lv_size; + lvm_size[MINOR(snap->lv_dev)] = + old_lv->lv_size >> 1; + __update_hardsectsize(snap); + up(&snap->lv_snapshot_sem); + } } } + __update_hardsectsize(old_lv); + up(&old_lv->lv_snapshot_sem); + return 0; } /* lvm_do_lv_extend_reduce() */ @@ -2669,10 +2331,10 @@ static int lvm_do_lv_status_byname(vg_t *vg_ptr, void *arg) { uint l; - ulong size; - lv_t lv; - lv_t *lv_ptr; lv_status_byname_req_t lv_status_byname_req; + void *saved_ptr1; + void *saved_ptr2; + lv_t *lv_ptr; if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&lv_status_byname_req, arg, @@ -2680,28 +2342,27 @@ return -EFAULT; if (lv_status_byname_req.lv == NULL) return -EINVAL; - if (copy_from_user(&lv, lv_status_byname_req.lv, - sizeof(lv_t)) != 0) - return -EFAULT; for (l = 0; l < vg_ptr->lv_max; l++) { - lv_ptr = vg_ptr->lv[l]; - if (lv_ptr != NULL && + if ((lv_ptr = vg_ptr->lv[l]) != NULL && strcmp(lv_ptr->lv_name, - lv_status_byname_req.lv_name) == 0) { - if (copy_to_user(lv_status_byname_req.lv, + lv_status_byname_req.lv_name) == 0) { + /* Save usermode pointers */ + saved_ptr1 = lv_status_byname_req.lv->lv_current_pe; + saved_ptr2 = lv_status_byname_req.lv->lv_block_exception; + if (copy_to_user(lv_status_byname_req.lv, lv_ptr, sizeof(lv_t)) != 0) return -EFAULT; - - if (lv.lv_current_pe != NULL) { - size = lv_ptr->lv_allocated_le * - sizeof(pe_t); - if (copy_to_user(lv.lv_current_pe, + if (saved_ptr1 != NULL) { + if (copy_to_user(saved_ptr1, lv_ptr->lv_current_pe, - size) != 0) + lv_ptr->lv_allocated_le * + sizeof(pe_t)) != 0) return -EFAULT; } + /* Restore usermode pointers */ + lv_status_byname_req.lv->lv_current_pe = saved_ptr1; return 0; } } @@ -2714,34 +2375,37 @@ */ static int lvm_do_lv_status_byindex(vg_t *vg_ptr,void *arg) { - ulong size; - lv_t lv; - lv_t *lv_ptr; lv_status_byindex_req_t lv_status_byindex_req; + void *saved_ptr1; + void *saved_ptr2; + lv_t *lv_ptr; if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&lv_status_byindex_req, arg, sizeof(lv_status_byindex_req)) != 0) return -EFAULT; - if ((lvp = lv_status_byindex_req.lv) == NULL) + if (lv_status_byindex_req.lv == NULL) return -EINVAL; if ( ( lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL) return -ENXIO; - if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) - return -EFAULT; - - if (copy_to_user(lvp, lv_ptr, sizeof(lv_t)) != 0) + /* Save usermode pointers */ + saved_ptr1 = lv_status_byindex_req.lv->lv_current_pe; + saved_ptr2 = lv_status_byindex_req.lv->lv_block_exception; + if (copy_to_user(lv_status_byindex_req.lv, lv_ptr, sizeof(lv_t)) != 0) return -EFAULT; - - if (lv.lv_current_pe != NULL) { - size = lv_ptr->lv_allocated_le * sizeof(pe_t); - if (copy_to_user(lv.lv_current_pe, - lv_ptr->lv_current_pe, - size) != 0) + if (saved_ptr1 != NULL) { + if (copy_to_user(saved_ptr1, + lv_ptr->lv_current_pe, + lv_ptr->lv_allocated_le * + sizeof(pe_t)) != 0) return -EFAULT; } + + /* Restore usermode pointers */ + lv_status_byindex_req.lv->lv_current_pe = saved_ptr1; + return 0; } /* lvm_do_lv_status_byindex() */ @@ -2752,6 +2416,9 @@ static int lvm_do_lv_status_bydev(vg_t * vg_ptr, void * arg) { int l; lv_status_bydev_req_t lv_status_bydev_req; + void *saved_ptr1; + void *saved_ptr2; + lv_t *lv_ptr; if (vg_ptr == NULL) return -ENXIO; if (copy_from_user(&lv_status_bydev_req, arg, @@ -2764,10 +2431,23 @@ } if ( l == vg_ptr->lv_max) return -ENXIO; + lv_ptr = vg_ptr->lv[l]; + + /* Save usermode pointers */ + saved_ptr1 = lv_status_bydev_req.lv->lv_current_pe; + saved_ptr2 = lv_status_bydev_req.lv->lv_block_exception; - if (copy_to_user(lv_status_bydev_req.lv, - vg_ptr->lv[l], sizeof(lv_t)) != 0) + if (copy_to_user(lv_status_bydev_req.lv, lv_ptr, sizeof(lv_t)) != 0) return -EFAULT; + if (saved_ptr1 != NULL) { + if (copy_to_user(saved_ptr1, + lv_ptr->lv_current_pe, + lv_ptr->lv_allocated_le * + sizeof(pe_t)) != 0) + return -EFAULT; + } + /* Restore usermode pointers */ + lv_status_bydev_req.lv->lv_current_pe = saved_ptr1; return 0; } /* lvm_do_lv_status_bydev() */ @@ -2787,11 +2467,11 @@ if ( (lv_ptr = vg_ptr->lv[l]) == NULL) continue; if (lv_ptr->lv_dev == lv->lv_dev) { - lvm_do_remove_proc_entry_of_lv ( vg_ptr, lv_ptr); + lvm_fs_remove_lv(vg_ptr, lv_ptr); strncpy(lv_ptr->lv_name, lv_req->lv_name, NAME_LEN); - lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr); + lvm_fs_create_lv(vg_ptr, lv_ptr); break; } } @@ -2871,160 +2551,28 @@ } /* lvm_do_pv_status() */ - /* - * create a devfs entry for a volume group + * character device support function flush and invalidate all buffers of a PV */ -void lvm_do_create_devfs_entry_of_vg ( vg_t *vg_ptr) { - vg_devfs_handle[vg_ptr->vg_number] = devfs_mk_dir(0, vg_ptr->vg_name, NULL); - ch_devfs_handle[vg_ptr->vg_number] = devfs_register( - vg_devfs_handle[vg_ptr->vg_number] , "group", - DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR, vg_ptr->vg_number, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, - &lvm_chr_fops, NULL); -} - - -/* - * create a /proc entry for a logical volume - */ -void lvm_do_create_proc_entry_of_lv ( vg_t *vg_ptr, lv_t *lv_ptr) { - char *basename; - - if ( vg_ptr->lv_subdir_pde != NULL) { - basename = strrchr(lv_ptr->lv_name, '/'); - if (basename == NULL) basename = lv_ptr->lv_name; - else basename++; - pde = create_proc_entry(basename, S_IFREG, - vg_ptr->lv_subdir_pde); - if ( pde != NULL) { - pde->read_proc = lvm_proc_read_lv_info; - pde->data = lv_ptr; - } - } -} - - -/* - * remove a /proc entry for a logical volume - */ -void lvm_do_remove_proc_entry_of_lv ( vg_t *vg_ptr, lv_t *lv_ptr) { - char *basename; - - if ( vg_ptr->lv_subdir_pde != NULL) { - basename = strrchr(lv_ptr->lv_name, '/'); - if (basename == NULL) basename = lv_ptr->lv_name; - else basename++; - remove_proc_entry(basename, vg_ptr->lv_subdir_pde); - } -} - - -/* - * create a /proc entry for a physical volume - */ -void lvm_do_create_proc_entry_of_pv ( vg_t *vg_ptr, pv_t *pv_ptr) { - int offset = 0; - char *basename; - char buffer[NAME_LEN]; - - basename = pv_ptr->pv_name; - if (strncmp(basename, "/dev/", 5) == 0) offset = 5; - strncpy(buffer, basename + offset, sizeof(buffer)); - basename = buffer; - while ( ( basename = strchr ( basename, '/')) != NULL) *basename = '_'; - pde = create_proc_entry(buffer, S_IFREG, vg_ptr->pv_subdir_pde); - if ( pde != NULL) { - pde->read_proc = lvm_proc_read_pv_info; - pde->data = pv_ptr; - } -} - - -/* - * remove a /proc entry for a physical volume - */ -void lvm_do_remove_proc_entry_of_pv ( vg_t *vg_ptr, pv_t *pv_ptr) { - char *basename; - - basename = strrchr(pv_ptr->pv_name, '/'); - if ( vg_ptr->pv_subdir_pde != NULL) { - basename = strrchr(pv_ptr->pv_name, '/'); - if (basename == NULL) basename = pv_ptr->pv_name; - else basename++; - remove_proc_entry(basename, vg_ptr->pv_subdir_pde); - } -} - - -/* - * create a /proc entry for a volume group - */ -void lvm_do_create_proc_entry_of_vg ( vg_t *vg_ptr) { - int l, p; - pv_t *pv_ptr; - lv_t *lv_ptr; +static int lvm_do_pv_flush(void *arg) +{ + pv_flush_req_t pv_flush_req; - pde = create_proc_entry(vg_ptr->vg_name, S_IFDIR, - lvm_proc_vg_subdir); - if ( pde != NULL) { - vg_ptr->vg_dir_pde = pde; - pde = create_proc_entry("group", S_IFREG, - vg_ptr->vg_dir_pde); - if ( pde != NULL) { - pde->read_proc = lvm_proc_read_vg_info; - pde->data = vg_ptr; - } - pde = create_proc_entry(LVM_LV_SUBDIR, S_IFDIR, - vg_ptr->vg_dir_pde); - if ( pde != NULL) { - vg_ptr->lv_subdir_pde = pde; - for ( l = 0; l < vg_ptr->lv_max; l++) { - if ( ( lv_ptr = vg_ptr->lv[l]) == NULL) continue; - lvm_do_create_proc_entry_of_lv ( vg_ptr, lv_ptr); - } - } - pde = create_proc_entry(LVM_PV_SUBDIR, S_IFDIR, - vg_ptr->vg_dir_pde); - if ( pde != NULL) { - vg_ptr->pv_subdir_pde = pde; - for ( p = 0; p < vg_ptr->pv_max; p++) { - if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) continue; - lvm_do_create_proc_entry_of_pv ( vg_ptr, pv_ptr); - } - } - } -} + if (copy_from_user(&pv_flush_req, arg, + sizeof(pv_flush_req)) != 0) + return -EFAULT; -/* - * remove a /proc entry for a volume group - */ -void lvm_do_remove_proc_entry_of_vg ( vg_t *vg_ptr) { - int l, p; - lv_t *lv_ptr; - pv_t *pv_ptr; + fsync_dev(pv_flush_req.pv_dev); + invalidate_buffers(pv_flush_req.pv_dev); - for ( l = 0; l < vg_ptr->lv_max; l++) { - if ( ( lv_ptr = vg_ptr->lv[l]) == NULL) continue; - lvm_do_remove_proc_entry_of_lv ( vg_ptr, vg_ptr->lv[l]); - } - for ( p = 0; p < vg_ptr->pv_max; p++) { - if ( ( pv_ptr = vg_ptr->pv[p]) == NULL) continue; - lvm_do_remove_proc_entry_of_pv ( vg_ptr, vg_ptr->pv[p]); - } - if ( vg_ptr->vg_dir_pde != NULL) { - remove_proc_entry(LVM_LV_SUBDIR, vg_ptr->vg_dir_pde); - remove_proc_entry(LVM_PV_SUBDIR, vg_ptr->vg_dir_pde); - remove_proc_entry("group", vg_ptr->vg_dir_pde); - remove_proc_entry(vg_ptr->vg_name, lvm_proc_vg_subdir); - } + return 0; } /* * support function initialize gendisk variables */ -void __init lvm_geninit(struct gendisk *lvm_gdisk) +static void __init lvm_geninit(struct gendisk *lvm_gdisk) { int i = 0; @@ -3040,36 +2588,11 @@ blk_size[MAJOR_NR] = lvm_size; blksize_size[MAJOR_NR] = lvm_blocksizes; - hardsect_size[MAJOR_NR] = lvm_blocksizes; + hardsect_size[MAJOR_NR] = lvm_hardsectsizes; return; } /* lvm_gen_init() */ - -/* - * return a pointer to a '-' padded uuid - */ -static char *lvm_show_uuid ( char *uuidstr) { - int i, j; - static char uuid[NAME_LEN] = { 0, }; - - memset ( uuid, 0, NAME_LEN); - - i = 6; - memcpy ( uuid, uuidstr, i); - uuidstr += i; - - for ( j = 0; j < 6; j++) { - uuid[i++] = '-'; - memcpy ( &uuid[i], uuidstr, 4); - uuidstr += 4; - i += 4; - } - - memcpy ( &uuid[i], uuidstr, 2 ); - - return uuid; -} module_init(lvm_init); module_exit(lvm_cleanup); diff -rNu linux-2.4.7/linux/drivers/md/md.c linux-2.4-xfs/linux/drivers/md/md.c --- linux-2.4.7/linux/drivers/md/md.c Mon Jul 2 16:16:24 2001 +++ linux-2.4-xfs/linux/drivers/md/md.c Mon Jul 2 21:33:57 2001 @@ -2522,6 +2522,12 @@ err = md_put_user (read_ahead[ MAJOR(dev)], (long *) arg); goto done; + + case BLKBSZGET: + case BLKBSZSET: + err = blk_ioctl (dev, cmd, arg); + goto done_unlock; + default:; } diff -rNu linux-2.4.7/linux/drivers/md/raid5.c linux-2.4-xfs/linux/drivers/md/raid5.c --- linux-2.4.7/linux/drivers/md/raid5.c Wed Jun 20 22:55:08 2001 +++ linux-2.4-xfs/linux/drivers/md/raid5.c Thu Jun 21 10:45:04 2001 @@ -281,7 +281,8 @@ } if (conf->buffer_size != size) { - printk("raid5: switching cache buffer size, %d --> %d\n", oldsize, size); + PRINTK("raid5: switching cache buffer size, %d --> %d\n", oldsize, size); + PRINTK("raid5: conf->buffer_size = %d\n", conf->buffer_size); shrink_stripe_cache(conf); if (size==0) BUG(); conf->buffer_size = size; @@ -531,7 +532,7 @@ return 0; } } - MD_BUG(); +/* MD_BUG(); */ return -EIO; } diff -rNu linux-2.4.7/linux/drivers/media/CVS/Entries linux-2.4-xfs/linux/drivers/media/CVS/Entries --- linux-2.4.7/linux/drivers/media/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/media/CVS/Entries Thu Jul 5 11:54:04 2001 @@ -0,0 +1,3 @@ +/Config.in/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/Makefile/1.3/Wed Jan 3 01:43:05 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/media/CVS/Entries.Log linux-2.4-xfs/linux/drivers/media/CVS/Entries.Log --- linux-2.4.7/linux/drivers/media/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/media/CVS/Entries.Log Thu Jul 5 11:54:05 2001 @@ -0,0 +1,2 @@ +A D/radio//// +A D/video//// diff -rNu linux-2.4.7/linux/drivers/media/CVS/Repository linux-2.4-xfs/linux/drivers/media/CVS/Repository --- linux-2.4.7/linux/drivers/media/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/media/CVS/Repository Thu Jul 5 11:54:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/media diff -rNu linux-2.4.7/linux/drivers/media/CVS/Root linux-2.4-xfs/linux/drivers/media/CVS/Root --- linux-2.4.7/linux/drivers/media/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/media/CVS/Root Thu Jul 5 11:54:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/media/radio/CVS/Entries linux-2.4-xfs/linux/drivers/media/radio/CVS/Entries --- linux-2.4.7/linux/drivers/media/radio/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/media/radio/CVS/Entries Thu Jul 5 11:54:05 2001 @@ -0,0 +1,19 @@ +/Config.in/1.5/Wed Jun 13 03:24:09 2001/-ko/ +/Makefile/1.6/Wed Jun 13 03:24:09 2001/-ko/ +/miropcm20-radio.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/miropcm20-rds-core.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/miropcm20-rds-core.h/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/miropcm20-rds.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/radio-aimslab.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/radio-aztech.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/radio-cadet.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/radio-gemtek.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/radio-maestro.c/1.4/Tue May 29 19:53:13 2001/-ko/ +/radio-maxiradio.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/radio-rtrack2.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/radio-sf16fmi.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/radio-terratec.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/radio-trust.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/radio-typhoon.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/radio-zoltrix.c/1.6/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/media/radio/CVS/Repository linux-2.4-xfs/linux/drivers/media/radio/CVS/Repository --- linux-2.4.7/linux/drivers/media/radio/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/media/radio/CVS/Repository Thu Jul 5 11:54:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/media/radio diff -rNu linux-2.4.7/linux/drivers/media/radio/CVS/Root linux-2.4-xfs/linux/drivers/media/radio/CVS/Root --- linux-2.4.7/linux/drivers/media/radio/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/media/radio/CVS/Root Thu Jul 5 11:54:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/media/video/CVS/Entries linux-2.4-xfs/linux/drivers/media/video/CVS/Entries --- linux-2.4.7/linux/drivers/media/video/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/media/video/CVS/Entries Thu Jul 5 11:54:15 2001 @@ -0,0 +1,61 @@ +/Config.in/1.3/Thu Jul 5 06:13:42 2001/-ko/ +/Makefile/1.4/Thu Jul 5 06:13:42 2001/-ko/ +/adv7175.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/audiochip.h/1.2/Sat Nov 25 08:05:45 2000/-ko/ +/bt819.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/bt848.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/bt856.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/bttv-cards.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/bttv-driver.c/1.9/Thu Jun 21 15:45:04 2001/-ko/ +/bttv-if.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/bttv.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/bttvp.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/bw-qcam.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/bw-qcam.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/c-qcam.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/cpia.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/cpia.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/cpia_pp.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/cpia_usb.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/cs8420.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/i2c-old.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/i2c-parport.c/1.2/Thu Jun 28 05:21:16 2001/-ko/ +/ibmmpeg2.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/id.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/meye.c/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/meye.h/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/msp3400.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/planb.c/1.6/Thu Jun 28 05:21:16 2001/-ko/ +/planb.h/1.2/Thu Jun 28 05:21:16 2001/-ko/ +/pms.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/saa5249.c/1.4/Thu Jul 5 06:13:42 2001/-ko/ +/saa7110.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/saa7111.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/saa7121.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/saa7146.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/saa7146reg.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/saa7185.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/saa7196.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/stradis.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/tda7432.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/tda9875.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/tuner-3036.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/tuner.c/1.4/Wed Jun 13 03:24:09 2001/-ko/ +/tuner.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/tvaudio.c/1.4/Tue May 29 19:53:13 2001/-ko/ +/tvaudio.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/tvmixer.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/videodev.c/1.5/Thu Jun 28 05:21:16 2001/-ko/ +/vino.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/w9966.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/zoran.h/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/zoran_procfs.c/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/zr36057.h/1.2/Thu Jul 5 06:13:42 2001/-ko/ +/zr36060.h/1.2/Thu Jul 5 06:13:42 2001/-ko/ +/zr36067.c/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/zr36120.c/1.6/Thu Jun 28 05:21:16 2001/-ko/ +/zr36120.h/1.2/Sun Dec 17 19:15:00 2000/-ko/ +/zr36120_i2c.c/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/zr36120_mem.c/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/zr36120_mem.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/media/video/CVS/Repository linux-2.4-xfs/linux/drivers/media/video/CVS/Repository --- linux-2.4.7/linux/drivers/media/video/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/media/video/CVS/Repository Thu Jul 5 11:54:05 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/media/video diff -rNu linux-2.4.7/linux/drivers/media/video/CVS/Root linux-2.4-xfs/linux/drivers/media/video/CVS/Root --- linux-2.4.7/linux/drivers/media/video/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/media/video/CVS/Root Thu Jul 5 11:54:05 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/misc/CVS/Entries linux-2.4-xfs/linux/drivers/misc/CVS/Entries --- linux-2.4.7/linux/drivers/misc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/misc/CVS/Entries Thu Jul 5 11:54:15 2001 @@ -0,0 +1,3 @@ +/Config.in/1.7/Wed Dec 29 19:04:31 1999/-ko/ +/Makefile/1.10/Thu Dec 21 05:48:12 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/misc/CVS/Repository linux-2.4-xfs/linux/drivers/misc/CVS/Repository --- linux-2.4.7/linux/drivers/misc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/misc/CVS/Repository Thu Jul 5 11:54:15 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/misc diff -rNu linux-2.4.7/linux/drivers/misc/CVS/Root linux-2.4-xfs/linux/drivers/misc/CVS/Root --- linux-2.4.7/linux/drivers/misc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/misc/CVS/Root Thu Jul 5 11:54:15 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/mtd/CVS/Entries linux-2.4-xfs/linux/drivers/mtd/CVS/Entries --- linux-2.4.7/linux/drivers/mtd/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/CVS/Entries Thu Jul 5 11:54:18 2001 @@ -0,0 +1,13 @@ +/Config.in/1.5/Thu Jun 28 05:21:16 2001/-ko/ +/Makefile/1.6/Wed Jun 13 03:24:09 2001/-ko/ +/bootldr.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/ftl.c/1.5/Wed Jun 13 03:24:09 2001/-ko/ +/mtdblock.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/mtdblock_ro.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/mtdchar.c/1.6/Wed Jun 13 03:24:09 2001/-ko/ +/mtdcore.c/1.4/Wed Jun 13 03:24:09 2001/-ko/ +/mtdpart.c/1.3/Wed Jun 13 03:24:09 2001/-ko/ +/nftlcore.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/nftlmount.c/1.4/Wed Jun 13 03:24:09 2001/-ko/ +/redboot.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/mtd/CVS/Entries.Log linux-2.4-xfs/linux/drivers/mtd/CVS/Entries.Log --- linux-2.4.7/linux/drivers/mtd/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/CVS/Entries.Log Thu Jul 5 11:54:22 2001 @@ -0,0 +1,4 @@ +A D/chips//// +A D/devices//// +A D/maps//// +A D/nand//// diff -rNu linux-2.4.7/linux/drivers/mtd/CVS/Repository linux-2.4-xfs/linux/drivers/mtd/CVS/Repository --- linux-2.4.7/linux/drivers/mtd/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/CVS/Repository Thu Jul 5 11:54:15 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/mtd diff -rNu linux-2.4.7/linux/drivers/mtd/CVS/Root linux-2.4-xfs/linux/drivers/mtd/CVS/Root --- linux-2.4.7/linux/drivers/mtd/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/CVS/Root Thu Jul 5 11:54:15 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/mtd/chips/CVS/Entries linux-2.4-xfs/linux/drivers/mtd/chips/CVS/Entries --- linux-2.4.7/linux/drivers/mtd/chips/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/chips/CVS/Entries Thu Jul 5 11:54:20 2001 @@ -0,0 +1,13 @@ +/Config.in/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/Makefile/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/amd_flash.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/cfi_cmdset_0001.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/cfi_cmdset_0002.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/cfi_jedec.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/cfi_probe.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/chipreg.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/jedec.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/map_ram.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/map_rom.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/sharp.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/mtd/chips/CVS/Repository linux-2.4-xfs/linux/drivers/mtd/chips/CVS/Repository --- linux-2.4.7/linux/drivers/mtd/chips/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/chips/CVS/Repository Thu Jul 5 11:54:18 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/mtd/chips diff -rNu linux-2.4.7/linux/drivers/mtd/chips/CVS/Root linux-2.4-xfs/linux/drivers/mtd/chips/CVS/Root --- linux-2.4.7/linux/drivers/mtd/chips/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/chips/CVS/Root Thu Jul 5 11:54:18 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/mtd/devices/CVS/Entries linux-2.4-xfs/linux/drivers/mtd/devices/CVS/Entries --- linux-2.4.7/linux/drivers/mtd/devices/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/devices/CVS/Entries Thu Jul 5 11:54:21 2001 @@ -0,0 +1,11 @@ +/Config.in/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/Makefile/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/doc1000.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/doc2000.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/doc2001.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/docecc.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/docprobe.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/mtdram.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/pmc551.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/slram.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/mtd/devices/CVS/Repository linux-2.4-xfs/linux/drivers/mtd/devices/CVS/Repository --- linux-2.4.7/linux/drivers/mtd/devices/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/devices/CVS/Repository Thu Jul 5 11:54:20 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/mtd/devices diff -rNu linux-2.4.7/linux/drivers/mtd/devices/CVS/Root linux-2.4-xfs/linux/drivers/mtd/devices/CVS/Root --- linux-2.4.7/linux/drivers/mtd/devices/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/devices/CVS/Root Thu Jul 5 11:54:20 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/mtd/maps/CVS/Entries linux-2.4-xfs/linux/drivers/mtd/maps/CVS/Entries --- linux-2.4.7/linux/drivers/mtd/maps/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/maps/CVS/Entries Thu Jul 5 11:54:22 2001 @@ -0,0 +1,21 @@ +/Config.in/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/Makefile/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/cfi_flagadm.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/cstm_mips_ixx.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/dbox2-flash.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/dc21285.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/elan-104nc.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/iq80310.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/netsc520.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/nora.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/ocelot.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/octagon-5066.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/physmap.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/pnc2000.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/rpxlite.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/sa1100-flash.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/sbc_gxx.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/sc520cdp.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/sun_uflash.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/vmax301.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/mtd/maps/CVS/Repository linux-2.4-xfs/linux/drivers/mtd/maps/CVS/Repository --- linux-2.4.7/linux/drivers/mtd/maps/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/maps/CVS/Repository Thu Jul 5 11:54:21 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/mtd/maps diff -rNu linux-2.4.7/linux/drivers/mtd/maps/CVS/Root linux-2.4-xfs/linux/drivers/mtd/maps/CVS/Root --- linux-2.4.7/linux/drivers/mtd/maps/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/maps/CVS/Root Thu Jul 5 11:54:21 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/mtd/nand/CVS/Entries linux-2.4-xfs/linux/drivers/mtd/nand/CVS/Entries --- linux-2.4.7/linux/drivers/mtd/nand/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/nand/CVS/Entries Thu Jul 5 11:54:23 2001 @@ -0,0 +1,6 @@ +/Config.in/1.2/Thu Jul 5 03:57:00 2001/-ko/ +/Makefile/1.2/Fri Jun 29 22:21:45 2001/-ko/ +/nand.c/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/nand_ecc.c/1.2/Fri Jun 29 22:21:45 2001/-ko/ +/spia.c/1.2/Thu Jul 5 03:57:00 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/mtd/nand/CVS/Repository linux-2.4-xfs/linux/drivers/mtd/nand/CVS/Repository --- linux-2.4.7/linux/drivers/mtd/nand/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/nand/CVS/Repository Thu Jul 5 11:54:22 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/mtd/nand diff -rNu linux-2.4.7/linux/drivers/mtd/nand/CVS/Root linux-2.4-xfs/linux/drivers/mtd/nand/CVS/Root --- linux-2.4.7/linux/drivers/mtd/nand/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/mtd/nand/CVS/Root Thu Jul 5 11:54:22 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/mtd/nand/Config.in linux-2.4-xfs/linux/drivers/mtd/nand/Config.in --- linux-2.4.7/linux/drivers/mtd/nand/Config.in Tue Jul 3 14:15:40 2001 +++ linux-2.4-xfs/linux/drivers/mtd/nand/Config.in Wed Jul 4 22:57:00 2001 @@ -1,6 +1,6 @@ # drivers/mtd/nand/Config.in -# $Id: Config.in,v 1.3 2001/07/03 17:50:56 sjhill Exp $ +# $Id: Config.in,v 1.1 2001/04/20 15:27:38 dwmw2 Exp $ mainmenu_option next_comment diff -rNu linux-2.4.7/linux/drivers/mtd/nand/spia.c linux-2.4-xfs/linux/drivers/mtd/nand/spia.c --- linux-2.4.7/linux/drivers/mtd/nand/spia.c Tue Jul 3 14:15:40 2001 +++ linux-2.4-xfs/linux/drivers/mtd/nand/spia.c Wed Jul 4 22:57:00 2001 @@ -3,7 +3,7 @@ * * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) * - * $Id: spia.c,v 1.11 2001/07/03 17:50:56 sjhill Exp $ + * $Id: spia.c,v 1.9 2001/06/02 14:47:16 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff -rNu linux-2.4.7/linux/drivers/net/CVS/Entries linux-2.4-xfs/linux/drivers/net/CVS/Entries --- linux-2.4.7/linux/drivers/net/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/CVS/Entries Thu Jul 5 11:55:47 2001 @@ -0,0 +1,216 @@ +/3c501.c/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/3c503.c/1.17/Thu Jun 21 15:45:04 2001/-ko/ +/3c503.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/3c505.c/1.19/Thu Jun 21 15:45:04 2001/-ko/ +/3c505.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/3c507.c/1.18/Thu Jun 21 15:45:04 2001/-ko/ +/3c509.c/1.22/Thu Jun 28 05:21:16 2001/-ko/ +/3c515.c/1.18/Thu Jun 21 15:45:04 2001/-ko/ +/3c523.c/1.15/Thu Jun 21 15:45:04 2001/-ko/ +/3c523.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/3c527.c/1.17/Wed May 2 06:22:13 2001/-ko/ +/3c527.h/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/3c59x.c/1.27/Tue Jul 3 02:33:57 2001/-ko/ +/7990.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/7990.h/1.4/Fri Jan 5 18:42:30 2001/-ko/ +/8139too.c/1.21/Tue Jul 3 02:33:57 2001/-ko/ +/82596.c/1.17/Thu Jun 21 15:45:04 2001/-ko/ +/8390.c/1.21/Tue May 29 19:53:13 2001/-ko/ +/8390.h/1.9/Wed May 2 06:22:13 2001/-ko/ +/Config.in/1.42/Tue Jul 3 02:33:57 2001/-ko/ +/LICENSE.SRC/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/Makefile/1.43/Thu Jun 21 15:45:04 2001/-ko/ +/Space.c/1.30/Wed May 2 06:22:13 2001/-ko/ +/a2065.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/a2065.h/1.4/Sat Jan 29 23:00:52 2000/-ko/ +/ac3200.c/1.14/Thu Jun 21 15:45:04 2001/-ko/ +/acenic.c/1.28/Thu Jul 5 06:13:42 2001/-ko/ +/acenic.h/1.14/Fri Jun 29 22:21:45 2001/-ko/ +/acenic_firmware.h/1.12/Tue May 29 19:53:13 2001/-ko/ +/aironet4500.h/1.7/Sun Dec 17 19:15:00 2000/-ko/ +/aironet4500_card.c/1.12/Thu Jun 21 15:45:04 2001/-ko/ +/aironet4500_core.c/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/aironet4500_proc.c/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/aironet4500_rid.c/1.3/Sat Mar 11 02:39:30 2000/-ko/ +/am79c961a.c/1.12/Thu Jun 28 05:21:16 2001/-ko/ +/am79c961a.h/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/apne.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/ariadne.c/1.12/Wed May 2 06:22:13 2001/-ko/ +/ariadne.h/1.4/Sat Jan 29 23:00:52 2000/-ko/ +/ariadne2.c/1.11/Wed May 2 06:22:13 2001/-ko/ +/arlan-proc.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/arlan.c/1.17/Thu Jul 5 06:13:42 2001/-ko/ +/arlan.h/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/at1700.c/1.11/Thu Jun 21 15:45:04 2001/-ko/ +/atari_bionet.c/1.10/Thu Jun 21 15:45:04 2001/-ko/ +/atari_pamsnet.c/1.10/Thu Jun 21 15:45:04 2001/-ko/ +/atarilance.c/1.9/Thu Jun 21 15:45:04 2001/-ko/ +/atp.c/1.15/Thu Jun 21 15:45:04 2001/-ko/ +/atp.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/au1000_eth.c/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/au1000_eth.h/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/auto_irq.c/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/bagetlance.c/1.10/Thu Jun 21 15:45:04 2001/-ko/ +/bmac.c/1.14/Tue May 29 19:53:13 2001/-ko/ +/bmac.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/bonding.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/bsd_comp.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/cs89x0.c/1.18/Thu Jun 21 15:45:04 2001/-ko/ +/cs89x0.h/1.5/Wed Mar 8 01:44:14 2000/-ko/ +/daynaport.c/1.10/Wed May 2 06:22:13 2001/-ko/ +/de4x5.c/1.21/Thu Jun 21 15:45:04 2001/-ko/ +/de4x5.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/de600.c/1.12/Thu Jun 21 15:45:04 2001/-ko/ +/de620.c/1.11/Thu Jun 21 15:45:04 2001/-ko/ +/de620.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/declance.c/1.11/Tue Jul 3 02:33:57 2001/-ko/ +/defxx.c/1.17/Tue Jul 3 02:33:57 2001/-ko/ +/defxx.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/depca.c/1.15/Thu Jun 21 15:45:04 2001/-ko/ +/depca.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/dgrs.c/1.16/Thu Jun 21 15:45:04 2001/-ko/ +/dgrs.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dgrs_asstruct.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dgrs_bcomm.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dgrs_es4h.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dgrs_ether.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dgrs_firmware.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/dgrs_i82596.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dgrs_plx9060.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dmfe.c/1.18/Thu Jul 5 06:13:42 2001/-ko/ +/dummy.c/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/e2100.c/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/eepro.c/1.19/Thu Jun 21 15:45:04 2001/-ko/ +/eepro100.c/1.31/Tue Jul 3 02:33:57 2001/-ko/ +/eexpress.c/1.16/Thu Jun 21 15:45:04 2001/-ko/ +/eexpress.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/epic100.c/1.22/Tue Jul 3 02:33:57 2001/-ko/ +/eql.c/1.13/Thu Jul 5 06:13:42 2001/-ko/ +/es3210.c/1.14/Thu Jun 21 15:45:04 2001/-ko/ +/eth16i.c/1.18/Thu Jul 5 06:13:42 2001/-ko/ +/ethertap.c/1.10/Thu Jun 21 15:45:04 2001/-ko/ +/ewrk3.c/1.17/Thu Jun 28 05:21:16 2001/-ko/ +/ewrk3.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/fealnx.c/1.4/Tue Jul 3 02:33:57 2001/-ko/ +/fmv18x.c/1.14/Thu Jun 21 15:45:04 2001/-ko/ +/gmac.c/1.9/Tue May 29 19:53:13 2001/-ko/ +/gmac.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/gt96100eth.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/gt96100eth.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/hamachi.c/1.8/Tue Jul 3 02:33:57 2001/-ko/ +/hp-plus.c/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/hp.c/1.12/Thu Jun 21 15:45:04 2001/-ko/ +/hp100.c/1.17/Mon Apr 2 17:13:32 2001/-ko/ +/hp100.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/hplance.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/hplance.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/hydra.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/hydra.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/i82586.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/ibmlana.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/ibmlana.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/ioc3-eth.c/1.12/Thu Jul 5 06:13:42 2001/-ko/ +/isa-skeleton.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/jazzsonic.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/lance.c/1.19/Thu Jun 21 15:45:04 2001/-ko/ +/lasi_82596.c/1.4/Tue Jul 3 02:33:57 2001/-ko/ +/lne390.c/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/loopback.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/lp486e.c/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/mac89x0.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/mace.c/1.14/Thu Jun 21 15:45:04 2001/-ko/ +/mace.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/macmace.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/macsonic.c/1.7/Thu Jun 21 15:45:04 2001/-ko/ +/mvme147.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/myri_code.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/myri_sbus.c/1.12/Wed May 2 06:22:13 2001/-ko/ +/myri_sbus.h/1.4/Wed Dec 29 19:04:31 1999/-ko/ +/natsemi.c/1.9/Thu Jun 28 05:21:16 2001/-ko/ +/ncr885_debug.h/1.1/Tue Oct 12 18:49:29 1999/-ko/ +/ncr885e.c/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/ncr885e.h/1.2/Wed Jan 3 01:43:05 2001/-ko/ +/ne.c/1.17/Thu Jun 21 15:45:04 2001/-ko/ +/ne2.c/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/ne2k-pci.c/1.21/Thu Jun 21 15:45:04 2001/-ko/ +/ne3210.c/1.12/Thu Jun 21 15:45:04 2001/-ko/ +/net_init.c/1.19/Tue May 29 19:53:13 2001/-ko/ +/ni5010.c/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/ni5010.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/ni52.c/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/ni52.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/ni65.c/1.10/Thu Jun 21 15:45:04 2001/-ko/ +/ni65.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/oaknet.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/pci-skeleton.c/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/pcnet32.c/1.24/Tue Jul 3 02:33:57 2001/-ko/ +/plip.c/1.19/Thu Jun 21 15:45:04 2001/-ko/ +/ppp_async.c/1.13/Thu Jul 5 05:29:17 2001/-ko/ +/ppp_deflate.c/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/ppp_generic.c/1.21/Thu Jul 5 05:29:17 2001/-ko/ +/ppp_synctty.c/1.9/Thu Jul 5 05:29:17 2001/-ko/ +/pppoe.c/1.13/Thu Jul 5 05:29:17 2001/-ko/ +/pppox.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/ptifddi.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/ptifddi.h/1.4/Mon Sep 6 21:36:14 1999/-ko/ +/ptifddi_asm.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/rcif.h/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/rclanmtl.c/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/rclanmtl.h/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/rcpci45.c/1.19/Tue Jul 3 02:33:57 2001/-ko/ +/rrunner.c/1.16/Thu Jul 5 05:29:17 2001/-ko/ +/rrunner.h/1.3/Sun Aug 29 03:33:57 1999/-ko/ +/saa9730.c/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/saa9730.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/sb1000.c/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/seeq8005.c/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/seeq8005.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/setup.c/1.19/Thu Jul 5 06:13:42 2001/-ko/ +/sgiseeq.c/1.11/Wed May 2 06:22:13 2001/-ko/ +/sgiseeq.h/1.5/Fri May 26 01:52:46 2000/-ko/ +/shaper.c/1.18/Thu Jun 28 05:21:16 2001/-ko/ +/sis900.c/1.24/Tue Jul 3 02:33:57 2001/-ko/ +/sis900.h/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/sk_g16.c/1.13/Thu Jul 5 05:29:17 2001/-ko/ +/sk_g16.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/sk_mca.c/1.12/Thu Jul 5 05:29:17 2001/-ko/ +/sk_mca.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/slhc.c/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/slip.c/1.16/Thu Jun 21 15:45:04 2001/-ko/ +/slip.h/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/smc-mca.c/1.12/Thu Jun 21 15:45:04 2001/-ko/ +/smc-mca.h/1.3/Wed Oct 6 23:00:36 1999/-ko/ +/smc-ultra.c/1.16/Thu Jun 21 15:45:04 2001/-ko/ +/smc-ultra32.c/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/smc9194.c/1.14/Thu Jun 21 15:45:04 2001/-ko/ +/smc9194.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/sonic.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/sonic.h/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/starfire.c/1.15/Tue Jul 3 02:33:57 2001/-ko/ +/stnic.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/strip.c/1.13/Thu Feb 22 21:09:04 2001/-ko/ +/sun3lance.c/1.9/Thu Jul 5 05:29:17 2001/-ko/ +/sunbmac.c/1.18/Wed May 2 06:22:13 2001/-ko/ +/sunbmac.h/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/sundance.c/1.8/Tue Jul 3 02:33:57 2001/-ko/ +/sungem.c/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/sungem.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/sunhme.c/1.27/Mon Jul 2 15:59:04 2001/-ko/ +/sunhme.h/1.9/Wed May 2 06:22:13 2001/-ko/ +/sunlance.c/1.22/Wed May 2 06:22:13 2001/-ko/ +/sunqe.c/1.17/Wed May 2 06:22:13 2001/-ko/ +/sunqe.h/1.6/Fri Feb 11 00:45:14 2000/-ko/ +/tlan.c/1.21/Tue Jul 3 02:33:57 2001/-ko/ +/tlan.h/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/tun.c/1.7/Sat Jun 9 02:44:24 2001/-ko/ +/via-rhine.c/1.25/Tue Jul 3 02:33:57 2001/-ko/ +/wavelan.c/1.20/Wed May 2 06:22:13 2001/-ko/ +/wavelan.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/wavelan.p.h/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/wd.c/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/winbond-840.c/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/yellowfin.c/1.23/Tue Jul 3 02:33:57 2001/-ko/ +/zlib.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/zlib.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/znet.c/1.8/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/CVS/Entries.Log linux-2.4-xfs/linux/drivers/net/CVS/Entries.Log --- linux-2.4.7/linux/drivers/net/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/CVS/Entries.Log Thu Jul 5 11:57:03 2001 @@ -0,0 +1,12 @@ +A D/appletalk//// +A D/arcnet//// +A D/fc//// +A D/hamradio//// +A D/irda//// +A D/pcmcia//// +A D/sk98lin//// +A D/skfp//// +A D/tokenring//// +A D/tulip//// +A D/wan//// +A D/wireless//// diff -rNu linux-2.4.7/linux/drivers/net/CVS/Repository linux-2.4-xfs/linux/drivers/net/CVS/Repository --- linux-2.4.7/linux/drivers/net/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/CVS/Repository Thu Jul 5 11:54:23 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net diff -rNu linux-2.4.7/linux/drivers/net/CVS/Root linux-2.4-xfs/linux/drivers/net/CVS/Root --- linux-2.4.7/linux/drivers/net/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/CVS/Root Thu Jul 5 11:54:23 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/appletalk/CVS/Entries linux-2.4-xfs/linux/drivers/net/appletalk/CVS/Entries --- linux-2.4.7/linux/drivers/net/appletalk/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/appletalk/CVS/Entries Thu Jul 5 11:55:48 2001 @@ -0,0 +1,11 @@ +/Config.in/1.2/Wed Mar 15 18:02:00 2000/-ko/ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/cops.c/1.11/Tue May 29 19:53:13 2001/-ko/ +/cops.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/cops_ffdrv.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/cops_ltdrv.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/ipddp.c/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/ipddp.h/1.1/Wed Mar 8 01:44:14 2000/-ko/ +/ltpc.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/ltpc.h/1.1/Wed Mar 8 01:44:14 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/appletalk/CVS/Repository linux-2.4-xfs/linux/drivers/net/appletalk/CVS/Repository --- linux-2.4.7/linux/drivers/net/appletalk/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/appletalk/CVS/Repository Thu Jul 5 11:55:47 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/appletalk diff -rNu linux-2.4.7/linux/drivers/net/appletalk/CVS/Root linux-2.4-xfs/linux/drivers/net/appletalk/CVS/Root --- linux-2.4.7/linux/drivers/net/appletalk/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/appletalk/CVS/Root Thu Jul 5 11:55:47 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/arcnet/CVS/Entries linux-2.4-xfs/linux/drivers/net/arcnet/CVS/Entries --- linux-2.4.7/linux/drivers/net/arcnet/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/arcnet/CVS/Entries Thu Jul 5 11:55:50 2001 @@ -0,0 +1,13 @@ +/Config.in/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/Makefile/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/arc-rawmode.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/arc-rimi.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/arcnet.c/1.10/Wed May 2 06:22:13 2001/-ko/ +/com20020-isa.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/com20020-pci.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/com20020.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/com90io.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/com90xx.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/rfc1051.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/rfc1201.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/arcnet/CVS/Repository linux-2.4-xfs/linux/drivers/net/arcnet/CVS/Repository --- linux-2.4.7/linux/drivers/net/arcnet/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/arcnet/CVS/Repository Thu Jul 5 11:55:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/arcnet diff -rNu linux-2.4.7/linux/drivers/net/arcnet/CVS/Root linux-2.4-xfs/linux/drivers/net/arcnet/CVS/Root --- linux-2.4.7/linux/drivers/net/arcnet/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/arcnet/CVS/Root Thu Jul 5 11:55:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/fc/CVS/Entries linux-2.4-xfs/linux/drivers/net/fc/CVS/Entries --- linux-2.4.7/linux/drivers/net/fc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/fc/CVS/Entries Thu Jul 5 11:55:51 2001 @@ -0,0 +1,8 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/iph5526.c/1.14/Thu Jun 21 15:45:04 2001/-ko/ +/iph5526_ip.h/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/iph5526_novram.c/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/iph5526_scsi.h/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/tach.h/1.1/Mon Aug 30 00:17:07 1999/-ko/ +/tach_structs.h/1.2/Wed Jan 3 01:43:05 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/fc/CVS/Repository linux-2.4-xfs/linux/drivers/net/fc/CVS/Repository --- linux-2.4.7/linux/drivers/net/fc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/fc/CVS/Repository Thu Jul 5 11:55:50 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/fc diff -rNu linux-2.4.7/linux/drivers/net/fc/CVS/Root linux-2.4-xfs/linux/drivers/net/fc/CVS/Root --- linux-2.4.7/linux/drivers/net/fc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/fc/CVS/Root Thu Jul 5 11:55:50 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/hamradio/CVS/Entries linux-2.4-xfs/linux/drivers/net/hamradio/CVS/Entries --- linux-2.4.7/linux/drivers/net/hamradio/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/hamradio/CVS/Entries Thu Jul 5 11:55:56 2001 @@ -0,0 +1,18 @@ +/6pack.c/1.11/Wed May 2 06:22:13 2001/-ko/ +/Config.in/1.6/Wed Oct 6 23:00:36 1999/-ko/ +/Makefile/1.8/Fri Jan 5 18:42:30 2001/-ko/ +/baycom_epp.c/1.15/Wed May 2 06:22:13 2001/-ko/ +/baycom_par.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/baycom_ser_fdx.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/baycom_ser_hdx.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/bpqether.c/1.16/Thu Jun 28 05:21:16 2001/-ko/ +/dmascc.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/hdlcdrv.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/mkiss.c/1.11/Wed May 2 06:22:13 2001/-ko/ +/mkiss.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/scc.c/1.18/Thu Jun 28 05:21:16 2001/-ko/ +/yam.c/1.14/Wed May 2 06:22:13 2001/-ko/ +/yam1200.h/1.1/Sun Aug 29 02:07:15 1999/-ko/ +/yam9600.h/1.1/Sun Aug 29 02:07:15 1999/-ko/ +/z8530.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/hamradio/CVS/Entries.Log linux-2.4-xfs/linux/drivers/net/hamradio/CVS/Entries.Log --- linux-2.4.7/linux/drivers/net/hamradio/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/hamradio/CVS/Entries.Log Thu Jul 5 11:55:56 2001 @@ -0,0 +1 @@ +A D/soundmodem//// diff -rNu linux-2.4.7/linux/drivers/net/hamradio/CVS/Repository linux-2.4-xfs/linux/drivers/net/hamradio/CVS/Repository --- linux-2.4.7/linux/drivers/net/hamradio/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/hamradio/CVS/Repository Thu Jul 5 11:55:51 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/hamradio diff -rNu linux-2.4.7/linux/drivers/net/hamradio/CVS/Root linux-2.4-xfs/linux/drivers/net/hamradio/CVS/Root --- linux-2.4.7/linux/drivers/net/hamradio/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/hamradio/CVS/Root Thu Jul 5 11:55:51 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/hamradio/soundmodem/CVS/Entries linux-2.4-xfs/linux/drivers/net/hamradio/soundmodem/CVS/Entries --- linux-2.4.7/linux/drivers/net/hamradio/soundmodem/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/hamradio/soundmodem/CVS/Entries Thu Jul 5 11:56:00 2001 @@ -0,0 +1,15 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/gentbl.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/sm.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/sm.h/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/sm_afsk1200.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sm_afsk2400_7.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sm_afsk2400_8.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sm_afsk2666.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sm_fsk9600.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sm_hapn4800.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sm_psk4800.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sm_sbc.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/sm_wss.c/1.6/Thu Jun 28 05:21:16 2001/-ko/ +/smdma.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/hamradio/soundmodem/CVS/Repository linux-2.4-xfs/linux/drivers/net/hamradio/soundmodem/CVS/Repository --- linux-2.4.7/linux/drivers/net/hamradio/soundmodem/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/hamradio/soundmodem/CVS/Repository Thu Jul 5 11:55:56 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/hamradio/soundmodem diff -rNu linux-2.4.7/linux/drivers/net/hamradio/soundmodem/CVS/Root linux-2.4-xfs/linux/drivers/net/hamradio/soundmodem/CVS/Root --- linux-2.4.7/linux/drivers/net/hamradio/soundmodem/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/hamradio/soundmodem/CVS/Root Thu Jul 5 11:55:56 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/irda/CVS/Entries linux-2.4-xfs/linux/drivers/net/irda/CVS/Entries --- linux-2.4.7/linux/drivers/net/irda/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/irda/CVS/Entries Thu Jul 5 11:56:04 2001 @@ -0,0 +1,17 @@ +/Config.in/1.10/Thu Jul 5 05:29:17 2001/-ko/ +/Makefile/1.13/Thu Jul 5 05:29:17 2001/-ko/ +/actisys.c/1.8/Sun Jan 9 23:56:19 2000/-ko/ +/ali-ircc.c/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/esi.c/1.7/Sun Jan 9 23:56:19 2000/-ko/ +/girbil.c/1.9/Mon Jul 31 16:16:28 2000/-ko/ +/irda-usb.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/irport.c/1.20/Thu Jul 5 05:29:17 2001/-ko/ +/irtty.c/1.21/Thu Jul 5 05:29:17 2001/-ko/ +/litelink.c/1.7/Sun Jan 9 23:56:19 2000/-ko/ +/nsc-ircc.c/1.14/Thu Jul 5 05:29:17 2001/-ko/ +/old_belkin.c/1.2/Sun Jan 9 23:56:19 2000/-ko/ +/smc-ircc.c/1.19/Thu Jul 5 05:29:17 2001/-ko/ +/tekram.c/1.7/Sun Jan 9 23:56:19 2000/-ko/ +/toshoboe.c/1.23/Thu Jul 5 05:29:17 2001/-ko/ +/w83977af_ir.c/1.18/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/irda/CVS/Repository linux-2.4-xfs/linux/drivers/net/irda/CVS/Repository --- linux-2.4.7/linux/drivers/net/irda/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/irda/CVS/Repository Thu Jul 5 11:56:00 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/irda diff -rNu linux-2.4.7/linux/drivers/net/irda/CVS/Root linux-2.4-xfs/linux/drivers/net/irda/CVS/Root --- linux-2.4.7/linux/drivers/net/irda/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/irda/CVS/Root Thu Jul 5 11:56:00 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/pcmcia/CVS/Entries linux-2.4-xfs/linux/drivers/net/pcmcia/CVS/Entries --- linux-2.4.7/linux/drivers/net/pcmcia/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/pcmcia/CVS/Entries Thu Jul 5 11:56:17 2001 @@ -0,0 +1,23 @@ +/3c574_cs.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/3c589_cs.c/1.15/Wed May 2 06:22:13 2001/-ko/ +/Config.in/1.23/Thu Jun 21 15:45:04 2001/-ko/ +/Makefile/1.17/Thu Jun 21 15:45:04 2001/-ko/ +/aironet4500_cs.c/1.11/Wed May 2 06:22:13 2001/-ko/ +/com20020_cs.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/fmvj18x_cs.c/1.10/Wed May 2 06:22:13 2001/-ko/ +/i82593.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/ibmtr_cs.c/1.6/Thu Jul 5 05:29:17 2001/-ko/ +/netwave_cs.c/1.14/Wed May 2 06:22:13 2001/-ko/ +/nmclan_cs.c/1.11/Wed May 2 06:22:13 2001/-ko/ +/ositech.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/pcnet_cs.c/1.14/Wed May 2 06:22:13 2001/-ko/ +/ray_cs.c/1.20/Wed May 2 06:22:13 2001/-ko/ +/ray_cs.h/1.5/Wed Jan 3 01:43:05 2001/-ko/ +/rayctl.h/1.2/Tue Oct 12 18:49:29 1999/-ko/ +/smc91c92_cs.c/1.11/Wed May 2 06:22:13 2001/-ko/ +/wavelan.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/wavelan_cs.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/wavelan_cs.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/xirc2ps_cs.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/xircom_tulip_cb.c/1.11/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/pcmcia/CVS/Repository linux-2.4-xfs/linux/drivers/net/pcmcia/CVS/Repository --- linux-2.4.7/linux/drivers/net/pcmcia/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/pcmcia/CVS/Repository Thu Jul 5 11:56:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/pcmcia diff -rNu linux-2.4.7/linux/drivers/net/pcmcia/CVS/Root linux-2.4-xfs/linux/drivers/net/pcmcia/CVS/Root --- linux-2.4.7/linux/drivers/net/pcmcia/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/pcmcia/CVS/Root Thu Jul 5 11:56:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/CVS/Entries linux-2.4-xfs/linux/drivers/net/sk98lin/CVS/Entries --- linux-2.4.7/linux/drivers/net/sk98lin/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/CVS/Entries Thu Jul 5 11:56:24 2001 @@ -0,0 +1,17 @@ +/Makefile/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/skaddr.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/skcsum.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/skge.c/1.11/Thu Jul 5 05:29:17 2001/-ko/ +/skgehwt.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/skgeinit.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/skgepnmi.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/skgesirq.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/ski2c.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/sklm80.c/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/skproc.c/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/skqueue.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/skrlmt.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/sktimer.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/skvpd.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/skxmac2.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/CVS/Entries.Log linux-2.4-xfs/linux/drivers/net/sk98lin/CVS/Entries.Log --- linux-2.4.7/linux/drivers/net/sk98lin/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/CVS/Entries.Log Thu Jul 5 11:56:24 2001 @@ -0,0 +1 @@ +A D/h//// diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/CVS/Repository linux-2.4-xfs/linux/drivers/net/sk98lin/CVS/Repository --- linux-2.4.7/linux/drivers/net/sk98lin/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/CVS/Repository Thu Jul 5 11:56:17 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/sk98lin diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/CVS/Root linux-2.4-xfs/linux/drivers/net/sk98lin/CVS/Root --- linux-2.4.7/linux/drivers/net/sk98lin/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/CVS/Root Thu Jul 5 11:56:17 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/CVS/Entries linux-2.4-xfs/linux/drivers/net/sk98lin/h/CVS/Entries --- linux-2.4.7/linux/drivers/net/sk98lin/h/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/CVS/Entries Thu Jul 5 11:56:27 2001 @@ -0,0 +1,24 @@ +/lm80.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/skaddr.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/skcsum.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/skdebug.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/skdrv1st.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/skdrv2nd.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/skerror.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/skgedrv.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/skgehw.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/skgehwt.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/skgei2c.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/skgeinit.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/skgepnm2.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/skgepnmi.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/skgesirq.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/ski2c.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/skqueue.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/skrlmt.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/sktimer.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/sktypes.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/skversion.h/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/skvpd.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/xmac_ii.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/CVS/Repository linux-2.4-xfs/linux/drivers/net/sk98lin/h/CVS/Repository --- linux-2.4.7/linux/drivers/net/sk98lin/h/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/CVS/Repository Thu Jul 5 11:56:24 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/sk98lin/h diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/CVS/Root linux-2.4-xfs/linux/drivers/net/sk98lin/h/CVS/Root --- linux-2.4.7/linux/drivers/net/sk98lin/h/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/CVS/Root Thu Jul 5 11:56:24 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/skaddr.h linux-2.4-xfs/linux/drivers/net/sk98lin/h/skaddr.h --- linux-2.4.7/linux/drivers/net/sk98lin/h/skaddr.h Thu Jul 5 10:49:36 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/skaddr.h Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skaddr.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.24 $ - * Date: $Date: 2001/01/22 13:41:34 $ + * Version: $Revision: 1.23 $ + * Date: $Date: 2000/08/10 11:27:50 $ * Purpose: Header file for Address Management (MC, UC, Prom). * ******************************************************************************/ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/skcsum.h linux-2.4-xfs/linux/drivers/net/sk98lin/h/skcsum.h --- linux-2.4.7/linux/drivers/net/sk98lin/h/skcsum.h Thu Jul 5 10:49:36 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/skcsum.h Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skcsum.h * Project: GEnesis - SysKonnect SK-NET Gigabit Ethernet (SK-98xx) - * Version: $Revision: 1.9 $ - * Date: $Date: 2001/02/06 11:21:39 $ + * Version: $Revision: 1.7 $ + * Date: $Date: 2000/06/29 13:17:05 $ * Purpose: Store/verify Internet checksum in send/receive packets. * ******************************************************************************/ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/skdrv1st.h linux-2.4-xfs/linux/drivers/net/sk98lin/h/skdrv1st.h --- linux-2.4.7/linux/drivers/net/sk98lin/h/skdrv1st.h Thu Jul 5 10:49:36 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/skdrv1st.h Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skdrv1st.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.9.2.1 $ - * Date: $Date: 2001/03/12 16:50:59 $ + * Version: $Revision: 1.8 $ + * Date: $Date: 2000/02/21 12:19:18 $ * Purpose: First header file for driver and all other modules * ******************************************************************************/ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/skdrv2nd.h linux-2.4-xfs/linux/drivers/net/sk98lin/h/skdrv2nd.h --- linux-2.4.7/linux/drivers/net/sk98lin/h/skdrv2nd.h Thu Jul 5 10:49:36 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/skdrv2nd.h Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skdrv2nd.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.12.2.1 $ - * Date: $Date: 2001/03/12 16:50:59 $ + * Version: $Revision: 1.7 $ + * Date: $Date: 1999/09/28 12:38:21 $ * Purpose: Second header file for driver and all other modules * ******************************************************************************/ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/skgehw.h linux-2.4-xfs/linux/drivers/net/sk98lin/h/skgehw.h --- linux-2.4.7/linux/drivers/net/sk98lin/h/skgehw.h Thu Jul 5 10:49:36 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/skgehw.h Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skgehw.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.36 $ - * Date: $Date: 2000/11/09 12:32:49 $ + * Version: $Revision: 1.35 $ + * Date: $Date: 2000/05/19 10:17:13 $ * Purpose: Defines and Macros for the Gigabit Ethernet Adapter Product * Family * diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/skgeinit.h linux-2.4-xfs/linux/drivers/net/sk98lin/h/skgeinit.h --- linux-2.4.7/linux/drivers/net/sk98lin/h/skgeinit.h Thu Jul 5 10:49:36 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/skgeinit.h Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skgeinit.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.51 $ - * Date: $Date: 2001/02/09 12:26:38 $ + * Version: $Revision: 1.46 $ + * Date: $Date: 2000/08/10 11:28:00 $ * Purpose: Structures and prototypes for the GE Init Module * ******************************************************************************/ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/skgepnm2.h linux-2.4-xfs/linux/drivers/net/sk98lin/h/skgepnm2.h --- linux-2.4.7/linux/drivers/net/sk98lin/h/skgepnm2.h Thu Jul 5 10:49:36 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/skgepnm2.h Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skgepnm2.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.30 $ - * Date: $Date: 2001/02/06 10:03:41 $ + * Version: $Revision: 1.28 $ + * Date: $Date: 2000/08/03 15:12:48 $ * Purpose: Defines for Private Network Management Interface * ****************************************************************************/ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/skgepnmi.h linux-2.4-xfs/linux/drivers/net/sk98lin/h/skgepnmi.h --- linux-2.4.7/linux/drivers/net/sk98lin/h/skgepnmi.h Thu Jul 5 10:49:36 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/skgepnmi.h Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skgepnmi.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.48 $ - * Date: $Date: 2001/02/23 14:34:24 $ + * Version: $Revision: 1.44 $ + * Date: $Date: 2000/09/07 07:35:27 $ * Purpose: Defines for Private Network Management Interface * ****************************************************************************/ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/skgesirq.h linux-2.4-xfs/linux/drivers/net/sk98lin/h/skgesirq.h --- linux-2.4.7/linux/drivers/net/sk98lin/h/skgesirq.h Thu Jul 5 10:49:37 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/skgesirq.h Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skgesirq.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.22 $ - * Date: $Date: 2000/11/09 11:30:10 $ + * Version: $Revision: 1.20 $ + * Date: $Date: 1999/12/06 10:00:44 $ * Purpose: SK specific Gigabit Ethernet special IRQ functions * ******************************************************************************/ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/ski2c.h linux-2.4-xfs/linux/drivers/net/sk98lin/h/ski2c.h --- linux-2.4.7/linux/drivers/net/sk98lin/h/ski2c.h Thu Jul 5 10:49:37 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/ski2c.h Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: ski2c.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.30 $ - * Date: $Date: 2001/04/05 11:38:09 $ + * Version: $Revision: 1.29 $ + * Date: $Date: 2000/08/03 14:28:17 $ * Purpose: Defines to access Voltage and Temperature Sensor * (taken from Monalisa (taken from Concentrator)) * diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/skrlmt.h linux-2.4-xfs/linux/drivers/net/sk98lin/h/skrlmt.h --- linux-2.4.7/linux/drivers/net/sk98lin/h/skrlmt.h Thu Jul 5 10:49:37 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/skrlmt.h Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skrlmt.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.32 $ - * Date: $Date: 2001/02/14 14:06:31 $ + * Version: $Revision: 1.27 $ + * Date: $Date: 1999/11/22 13:59:56 $ * Purpose: Header file for Redundant Link ManagemenT. * ******************************************************************************/ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/skversion.h linux-2.4-xfs/linux/drivers/net/sk98lin/h/skversion.h --- linux-2.4.7/linux/drivers/net/sk98lin/h/skversion.h Thu Jul 5 10:49:37 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/skversion.h Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: version.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.1 $ - * Date: $Date: 2001/03/06 09:25:00 $ + * Version: $Revision$ + * Date: $Date$ * Purpose: SK specific Error log support * ******************************************************************************/ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/skvpd.h linux-2.4-xfs/linux/drivers/net/sk98lin/h/skvpd.h --- linux-2.4.7/linux/drivers/net/sk98lin/h/skvpd.h Thu Jul 5 10:49:37 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/skvpd.h Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skvpd.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.9 $ - * Date: $Date: 1999/11/22 14:02:27 $ + * Version: $Revision: 1.10 $ + * Date: $Date: 2000/08/10 11:29:07 $ * Purpose: Defines and Macros for VPD handling * ******************************************************************************/ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/h/xmac_ii.h linux-2.4-xfs/linux/drivers/net/sk98lin/h/xmac_ii.h --- linux-2.4.7/linux/drivers/net/sk98lin/h/xmac_ii.h Thu Jul 5 10:49:37 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/h/xmac_ii.h Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: xmac_ii.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.28 $ - * Date: $Date: 2000/11/09 12:32:49 $ + * Version: $Revision: 1.27 $ + * Date: $Date: 2000/05/17 11:00:46 $ * Purpose: Defines and Macros for XaQti's Gigabit Ethernet Controller * ******************************************************************************/ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/skaddr.c linux-2.4-xfs/linux/drivers/net/sk98lin/skaddr.c --- linux-2.4.7/linux/drivers/net/sk98lin/skaddr.c Thu Jul 5 10:49:37 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/skaddr.c Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skaddr.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.40 $ - * Date: $Date: 2001/02/14 14:04:59 $ + * Version: $Revision: 1.36 $ + * Date: $Date: 2000/08/07 11:10:39 $ * Purpose: Manage Addresses (Multicast and Unicast) and Promiscuous Mode. * ******************************************************************************/ @@ -183,7 +183,7 @@ #ifndef lint static const char SysKonnectFileId[] = - "@(#) $Id: skaddr.c,v 1.40 2001/02/14 14:04:59 rassmann Exp $ (C) SysKonnect."; + "@(#) $Id: skaddr.c,v 1.36 2000/08/07 11:10:39 rassmann Exp $ (C) SysKonnect."; #endif /* !defined(lint) */ #define __SKADDR_C diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/skcsum.c linux-2.4-xfs/linux/drivers/net/sk98lin/skcsum.c --- linux-2.4.7/linux/drivers/net/sk98lin/skcsum.c Thu Jul 5 10:49:37 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/skcsum.c Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skcsum.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.8 $ - * Date: $Date: 2001/02/06 11:15:36 $ + * Version: $Revision: 1.7 $ + * Date: $Date: 2000/06/29 13:17:05 $ * Purpose: Store/verify Internet checksum in send/receive packets. * ******************************************************************************/ @@ -65,7 +65,7 @@ #ifndef lint static const char SysKonnectFileId[] = "@(#)" - "$Id: skcsum.c,v 1.8 2001/02/06 11:15:36 rassmann Exp $" + "$Id: skcsum.c,v 1.7 2000/06/29 13:17:05 rassmann Exp $" " (C) SysKonnect."; #endif /* !lint */ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/skge.c linux-2.4-xfs/linux/drivers/net/sk98lin/skge.c --- linux-2.4.7/linux/drivers/net/sk98lin/skge.c Thu Jul 5 10:49:37 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/skge.c Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skge.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.29.2.6 $ - * Date: $Date: 2001/05/21 07:59:29 $ + * Version: $Revision: 1.29 $ + * Date: $Date: 2000/02/21 13:31:56 $ * Purpose: The main driver source module * ******************************************************************************/ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/skgeinit.c linux-2.4-xfs/linux/drivers/net/sk98lin/skgeinit.c --- linux-2.4.7/linux/drivers/net/sk98lin/skgeinit.c Thu Jul 5 10:49:37 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/skgeinit.c Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skgeinit.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.63 $ - * Date: $Date: 2001/04/05 11:02:09 $ + * Version: $Revision: 1.57 $ + * Date: $Date: 2000/08/03 14:55:28 $ * Purpose: Contains functions to initialize the GE HW * ******************************************************************************/ @@ -300,7 +300,7 @@ /* local variables ************************************************************/ static const char SysKonnectFileId[] = - "@(#)$Id: skgeinit.c,v 1.63 2001/04/05 11:02:09 rassmann Exp $ (C) SK "; + "@(#)$Id: skgeinit.c,v 1.57 2000/08/03 14:55:28 rassmann Exp $ (C) SK "; struct s_QOffTab { int RxQOff; /* Receive Queue Address Offset */ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/skgepnmi.c linux-2.4-xfs/linux/drivers/net/sk98lin/skgepnmi.c --- linux-2.4.7/linux/drivers/net/sk98lin/skgepnmi.c Thu Jul 5 10:49:37 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/skgepnmi.c Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skgepnmi.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.87 $ - * Date: $Date: 2001/04/06 13:35:09 $ + * Version: $Revision: 1.78 $ + * Date: $Date: 2000/09/12 10:44:58 $ * Purpose: Private Network Management Interface * ****************************************************************************/ @@ -362,7 +362,7 @@ static const char SysKonnectFileId[] = - "@(#) $Id: skgepnmi.c,v 1.87 2001/04/06 13:35:09 mkunz Exp $" + "@(#) $Id: skgepnmi.c,v 1.78 2000/09/12 10:44:58 cgoos Exp $" " (C) SysKonnect."; #include "h/skdrv1st.h" diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/skgesirq.c linux-2.4-xfs/linux/drivers/net/sk98lin/skgesirq.c --- linux-2.4.7/linux/drivers/net/sk98lin/skgesirq.c Thu Jul 5 10:49:37 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/skgesirq.c Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skgesirq.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.65 $ - * Date: $Date: 2001/02/23 13:41:51 $ + * Version: $Revision: 1.55 $ + * Date: $Date: 2000/06/19 08:36:25 $ * Purpose: Special IRQ module * ******************************************************************************/ @@ -271,7 +271,7 @@ */ static const char SysKonnectFileId[] = - "$Id: skgesirq.c,v 1.65 2001/02/23 13:41:51 gklug Exp $" ; + "$Id: skgesirq.c,v 1.55 2000/06/19 08:36:25 cgoos Exp $" ; #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/skgepnmi.h" /* PNMI Definitions */ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/skproc.c linux-2.4-xfs/linux/drivers/net/sk98lin/skproc.c --- linux-2.4.7/linux/drivers/net/sk98lin/skproc.c Thu Jul 5 10:49:37 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/skproc.c Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skproc.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.2.2.2 $ - * Date: $Date: 2001/03/15 12:50:13 $ + * Version: $Revision$ + * Date: $Date$ * Purpose: Funktions to display statictic data * ******************************************************************************/ diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/skrlmt.c linux-2.4-xfs/linux/drivers/net/sk98lin/skrlmt.c --- linux-2.4.7/linux/drivers/net/sk98lin/skrlmt.c Thu Jul 5 10:49:37 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/skrlmt.c Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skrlmt.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.61 $ - * Date: $Date: 2001/03/14 12:52:08 $ + * Version: $Revision: 1.49 $ + * Date: $Date: 1999/11/22 13:38:02 $ * Purpose: Manage links on SK-NET Adapters, esp. redundant ones. * ******************************************************************************/ @@ -255,7 +255,7 @@ #ifndef lint static const char SysKonnectFileId[] = - "@(#) $Id: skrlmt.c,v 1.61 2001/03/14 12:52:08 rassmann Exp $ (C) SysKonnect."; + "@(#) $Id: skrlmt.c,v 1.49 1999/11/22 13:38:02 cgoos Exp $ (C) SysKonnect."; #endif /* !defined(lint) */ #define __SKRLMT_C diff -rNu linux-2.4.7/linux/drivers/net/sk98lin/skxmac2.c linux-2.4-xfs/linux/drivers/net/sk98lin/skxmac2.c --- linux-2.4.7/linux/drivers/net/sk98lin/skxmac2.c Thu Jul 5 10:49:37 2001 +++ linux-2.4-xfs/linux/drivers/net/sk98lin/skxmac2.c Thu Jul 5 00:29:17 2001 @@ -2,8 +2,8 @@ * * Name: skxmac2.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.61 $ - * Date: $Date: 2001/02/09 15:40:59 $ + * Version: $Revision: 1.53 $ + * Date: $Date: 2000/07/27 12:22:11 $ * Purpose: Contains functions to initialize the XMAC II * ******************************************************************************/ @@ -256,7 +256,7 @@ /* local variables ************************************************************/ static const char SysKonnectFileId[] = - "@(#)$Id: skxmac2.c,v 1.61 2001/02/09 15:40:59 rassmann Exp $ (C) SK "; + "@(#)$Id: skxmac2.c,v 1.53 2000/07/27 12:22:11 gklug Exp $ (C) SK "; /* BCOM PHY magic pattern list */ typedef struct s_PhyHack { diff -rNu linux-2.4.7/linux/drivers/net/skfp/CVS/Entries linux-2.4-xfs/linux/drivers/net/skfp/CVS/Entries --- linux-2.4.7/linux/drivers/net/skfp/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/skfp/CVS/Entries Thu Jul 5 11:56:31 2001 @@ -0,0 +1,22 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/can.c/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/cfm.c/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/drvfbi.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/ecm.c/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/ess.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/fplustm.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/hwmtm.c/1.2/Fri May 26 01:26:22 2000/-ko/ +/hwt.c/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/lnkstat.c/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/pcmplc.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/pmf.c/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/queue.c/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/rmt.c/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/skfddi.c/1.10/Wed May 2 06:22:13 2001/-ko/ +/smt.c/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/smtdef.c/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/smtinit.c/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/smtparse.c/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/smttimer.c/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/srf.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/skfp/CVS/Entries.Log linux-2.4-xfs/linux/drivers/net/skfp/CVS/Entries.Log --- linux-2.4.7/linux/drivers/net/skfp/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/skfp/CVS/Entries.Log Thu Jul 5 11:56:31 2001 @@ -0,0 +1 @@ +A D/h//// diff -rNu linux-2.4.7/linux/drivers/net/skfp/CVS/Repository linux-2.4-xfs/linux/drivers/net/skfp/CVS/Repository --- linux-2.4.7/linux/drivers/net/skfp/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/skfp/CVS/Repository Thu Jul 5 11:56:27 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/skfp diff -rNu linux-2.4.7/linux/drivers/net/skfp/CVS/Root linux-2.4-xfs/linux/drivers/net/skfp/CVS/Root --- linux-2.4.7/linux/drivers/net/skfp/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/skfp/CVS/Root Thu Jul 5 11:56:27 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/skfp/h/CVS/Entries linux-2.4-xfs/linux/drivers/net/skfp/h/CVS/Entries --- linux-2.4.7/linux/drivers/net/skfp/h/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/skfp/h/CVS/Entries Thu Jul 5 11:56:33 2001 @@ -0,0 +1,21 @@ +/cmtdef.h/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/fddi.h/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/fddimib.h/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/fplustm.h/1.2/Fri May 26 01:26:22 2000/-ko/ +/hwmtm.h/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/lnkstat.h/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/mbuf.h/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/osdef1st.h/1.2/Fri May 26 01:26:22 2000/-ko/ +/sba.h/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/sba_def.h/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/skfbi.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/skfbiinc.h/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/smc.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/smt.h/1.2/Fri May 26 01:26:22 2000/-ko/ +/smt_p.h/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/smtstate.h/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/supern_2.h/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/targethw.h/1.1/Wed Feb 23 18:35:06 2000/-ko/ +/targetos.h/1.2/Fri May 26 01:26:22 2000/-ko/ +/types.h/1.1/Wed Feb 23 18:35:06 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/skfp/h/CVS/Repository linux-2.4-xfs/linux/drivers/net/skfp/h/CVS/Repository --- linux-2.4.7/linux/drivers/net/skfp/h/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/skfp/h/CVS/Repository Thu Jul 5 11:56:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/skfp/h diff -rNu linux-2.4.7/linux/drivers/net/skfp/h/CVS/Root linux-2.4-xfs/linux/drivers/net/skfp/h/CVS/Root --- linux-2.4.7/linux/drivers/net/skfp/h/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/skfp/h/CVS/Root Thu Jul 5 11:56:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/tokenring/CVS/Entries linux-2.4-xfs/linux/drivers/net/tokenring/CVS/Entries --- linux-2.4.7/linux/drivers/net/tokenring/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/tokenring/CVS/Entries Thu Jul 5 11:56:41 2001 @@ -0,0 +1,20 @@ +/Config.in/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/Makefile/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/abyss.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/abyss.h/1.1/Sat Jan 29 23:00:52 2000/-ko/ +/ibmtr.c/1.14/Thu Jul 5 05:29:17 2001/-ko/ +/lanstreamer.c/1.7/Thu Jun 21 15:45:04 2001/-ko/ +/lanstreamer.h/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/madgemc.c/1.4/Tue May 29 19:53:13 2001/-ko/ +/madgemc.h/1.1/Sat Jan 29 23:00:52 2000/-ko/ +/olympic.c/1.14/Thu Jun 21 15:45:04 2001/-ko/ +/olympic.h/1.8/Thu Jun 21 15:45:04 2001/-ko/ +/smctr.c/1.13/Thu Jun 28 05:21:16 2001/-ko/ +/smctr.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/smctr_firmware.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/tms380tr.c/1.16/Tue May 29 19:53:13 2001/-ko/ +/tms380tr.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/tms380tr_microcode.h/1.2/Sun Dec 17 19:15:00 2000/-ko/ +/tmsisa.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/tmspci.c/1.5/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/tokenring/CVS/Repository linux-2.4-xfs/linux/drivers/net/tokenring/CVS/Repository --- linux-2.4.7/linux/drivers/net/tokenring/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/tokenring/CVS/Repository Thu Jul 5 11:56:33 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/tokenring diff -rNu linux-2.4.7/linux/drivers/net/tokenring/CVS/Root linux-2.4-xfs/linux/drivers/net/tokenring/CVS/Root --- linux-2.4.7/linux/drivers/net/tokenring/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/tokenring/CVS/Root Thu Jul 5 11:56:33 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/tulip/CVS/Entries linux-2.4-xfs/linux/drivers/net/tulip/CVS/Entries --- linux-2.4.7/linux/drivers/net/tulip/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/tulip/CVS/Entries Thu Jul 5 11:56:44 2001 @@ -0,0 +1,11 @@ +/21142.c/1.9/Thu Jun 21 15:45:04 2001/-ko/ +/ChangeLog/1.7/Thu Jun 21 15:45:04 2001/-ko/ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/eeprom.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/interrupt.c/1.11/Thu Jun 21 15:45:04 2001/-ko/ +/media.c/1.10/Thu Jun 21 15:45:04 2001/-ko/ +/pnic.c/1.8/Thu Jun 21 15:45:04 2001/-ko/ +/timer.c/1.9/Thu Jun 21 15:45:04 2001/-ko/ +/tulip.h/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/tulip_core.c/1.23/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/tulip/CVS/Repository linux-2.4-xfs/linux/drivers/net/tulip/CVS/Repository --- linux-2.4.7/linux/drivers/net/tulip/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/tulip/CVS/Repository Thu Jul 5 11:56:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/tulip diff -rNu linux-2.4.7/linux/drivers/net/tulip/CVS/Root linux-2.4-xfs/linux/drivers/net/tulip/CVS/Root --- linux-2.4.7/linux/drivers/net/tulip/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/tulip/CVS/Root Thu Jul 5 11:56:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/wan/CVS/Entries linux-2.4-xfs/linux/drivers/net/wan/CVS/Entries --- linux-2.4.7/linux/drivers/net/wan/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/wan/CVS/Entries Thu Jul 5 11:57:02 2001 @@ -0,0 +1,45 @@ +/Config.in/1.11/Thu Jul 5 05:29:17 2001/-ko/ +/Makefile/1.11/Wed May 2 06:22:13 2001/-ko/ +/c101.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/comx-hw-comx.c/1.4/Tue May 29 19:53:13 2001/-ko/ +/comx-hw-locomx.c/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/comx-hw-mixcom.c/1.5/Thu Jun 28 05:21:16 2001/-ko/ +/comx-proto-fr.c/1.5/Thu Jun 28 05:21:16 2001/-ko/ +/comx-proto-lapb.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/comx-proto-ppp.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/comx.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/comx.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/comxhw.h/1.1/Wed Mar 15 18:20:34 2000/-ko/ +/cosa.c/1.19/Thu Jun 28 05:21:16 2001/-ko/ +/cosa.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/cycx_drv.c/1.5/Fri Apr 21 16:00:46 2000/-ko/ +/cycx_main.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/cycx_x25.c/1.12/Wed May 2 06:22:13 2001/-ko/ +/dlci.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/dscc4.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/hd64570.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/hd6457x.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/hdlc.c/1.3/Wed Jun 13 03:24:09 2001/-ko/ +/hostess_sv11.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/hscx.h/1.1/Wed Mar 15 18:20:34 2000/-ko/ +/lapbether.c/1.8/Thu Jun 28 05:21:16 2001/-ko/ +/mixcom.h/1.1/Wed Mar 15 18:20:34 2000/-ko/ +/n2.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/sbni.c/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/sbni.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/sdla.c/1.11/Wed May 2 06:22:13 2001/-ko/ +/sdla_chdlc.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/sdla_fr.c/1.11/Wed Jun 13 03:24:09 2001/-ko/ +/sdla_ft1.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/sdla_ppp.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/sdla_x25.c/1.7/Wed Jun 13 03:24:09 2001/-ko/ +/sdladrv.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/sdlamain.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/sealevel.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/syncppp.c/1.11/Thu Jun 28 05:21:16 2001/-ko/ +/wanpipe_multppp.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/x25_asy.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/x25_asy.h/1.2/Sun Dec 17 19:15:00 2000/-ko/ +/z85230.c/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/z85230.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/wan/CVS/Entries.Log linux-2.4-xfs/linux/drivers/net/wan/CVS/Entries.Log --- linux-2.4.7/linux/drivers/net/wan/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/wan/CVS/Entries.Log Thu Jul 5 11:57:02 2001 @@ -0,0 +1 @@ +A D/lmc//// diff -rNu linux-2.4.7/linux/drivers/net/wan/CVS/Repository linux-2.4-xfs/linux/drivers/net/wan/CVS/Repository --- linux-2.4.7/linux/drivers/net/wan/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/wan/CVS/Repository Thu Jul 5 11:56:44 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/wan diff -rNu linux-2.4.7/linux/drivers/net/wan/CVS/Root linux-2.4-xfs/linux/drivers/net/wan/CVS/Root --- linux-2.4.7/linux/drivers/net/wan/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/wan/CVS/Root Thu Jul 5 11:56:44 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/wan/lmc/CVS/Entries linux-2.4-xfs/linux/drivers/net/wan/lmc/CVS/Entries --- linux-2.4.7/linux/drivers/net/wan/lmc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/wan/lmc/CVS/Entries Thu Jul 5 11:57:03 2001 @@ -0,0 +1,15 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/lmc.h/1.2/Thu Feb 1 17:10:24 2001/-ko/ +/lmc_debug.c/1.1/Tue May 2 21:36:51 2000/-ko/ +/lmc_debug.h/1.1/Tue May 2 21:36:51 2000/-ko/ +/lmc_ioctl.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/lmc_main.c/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/lmc_media.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/lmc_media.h/1.2/Thu Feb 1 17:10:24 2001/-ko/ +/lmc_prot.h/1.2/Thu Feb 1 17:10:24 2001/-ko/ +/lmc_proto.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/lmc_proto.h/1.2/Thu Feb 1 17:10:24 2001/-ko/ +/lmc_proto_raw.h/1.1/Tue May 2 21:36:51 2000/-ko/ +/lmc_var.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/lmc_ver.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/wan/lmc/CVS/Repository linux-2.4-xfs/linux/drivers/net/wan/lmc/CVS/Repository --- linux-2.4.7/linux/drivers/net/wan/lmc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/wan/lmc/CVS/Repository Thu Jul 5 11:57:02 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/wan/lmc diff -rNu linux-2.4.7/linux/drivers/net/wan/lmc/CVS/Root linux-2.4-xfs/linux/drivers/net/wan/lmc/CVS/Root --- linux-2.4.7/linux/drivers/net/wan/lmc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/wan/lmc/CVS/Root Thu Jul 5 11:57:02 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/net/wireless/CVS/Entries linux-2.4-xfs/linux/drivers/net/wireless/CVS/Entries --- linux-2.4.7/linux/drivers/net/wireless/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/wireless/CVS/Entries Thu Jul 5 11:57:06 2001 @@ -0,0 +1,13 @@ +/Config.in/1.2/Thu Jun 21 15:45:04 2001/-ko/ +/Makefile/1.2/Thu Jun 21 15:45:04 2001/-ko/ +/README/1.1/Tue May 29 19:53:13 2001/-ko/ +/airo.c/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/airo_cs.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/airport.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/hermes.c/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/hermes.h/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/orinoco.c/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/orinoco.h/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/orinoco_cs.c/1.4/Tue Jul 3 02:33:57 2001/-ko/ +/todo.txt/1.1/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/net/wireless/CVS/Repository linux-2.4-xfs/linux/drivers/net/wireless/CVS/Repository --- linux-2.4.7/linux/drivers/net/wireless/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/wireless/CVS/Repository Thu Jul 5 11:57:03 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/net/wireless diff -rNu linux-2.4.7/linux/drivers/net/wireless/CVS/Root linux-2.4-xfs/linux/drivers/net/wireless/CVS/Root --- linux-2.4.7/linux/drivers/net/wireless/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/net/wireless/CVS/Root Thu Jul 5 11:57:03 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/nubus/CVS/Entries linux-2.4-xfs/linux/drivers/nubus/CVS/Entries --- linux-2.4.7/linux/drivers/nubus/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/nubus/CVS/Entries Thu Jul 5 11:57:07 2001 @@ -0,0 +1,5 @@ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/nubus.c/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/nubus_syms.c/1.1/Wed Sep 15 20:42:56 1999/-ko/ +/proc.c/1.6/Sat Nov 25 08:05:45 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/nubus/CVS/Repository linux-2.4-xfs/linux/drivers/nubus/CVS/Repository --- linux-2.4.7/linux/drivers/nubus/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/nubus/CVS/Repository Thu Jul 5 11:57:06 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/nubus diff -rNu linux-2.4.7/linux/drivers/nubus/CVS/Root linux-2.4-xfs/linux/drivers/nubus/CVS/Root --- linux-2.4.7/linux/drivers/nubus/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/nubus/CVS/Root Thu Jul 5 11:57:06 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/parport/CVS/Entries linux-2.4-xfs/linux/drivers/parport/CVS/Entries --- linux-2.4.7/linux/drivers/parport/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/parport/CVS/Entries Thu Jul 5 11:57:10 2001 @@ -0,0 +1,21 @@ +/BUGS-parport/1.3/Tue May 29 19:53:13 2001/-ko/ +/ChangeLog/1.15/Sat Jun 9 02:44:24 2001/-ko/ +/Config.in/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/Makefile/1.6/Thu Dec 21 05:48:12 2000/-ko/ +/TODO-parport/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/daisy.c/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/ieee1284.c/1.11/Tue May 29 19:53:13 2001/-ko/ +/ieee1284_ops.c/1.11/Tue May 29 19:53:13 2001/-ko/ +/init.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/multiface.h/1.1/Fri Aug 27 23:14:48 1999/-ko/ +/parport_amiga.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/parport_arc.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/parport_atari.c/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/parport_gsc.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/parport_mfc3.c/1.8/Tue May 29 19:53:13 2001/-ko/ +/parport_pc.c/1.34/Sat Jun 9 02:44:24 2001/-ko/ +/parport_sunbpp.c/1.7/Sat Jun 9 02:44:24 2001/-ko/ +/probe.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/procfs.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/share.c/1.15/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/parport/CVS/Repository linux-2.4-xfs/linux/drivers/parport/CVS/Repository --- linux-2.4.7/linux/drivers/parport/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/parport/CVS/Repository Thu Jul 5 11:57:07 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/parport diff -rNu linux-2.4.7/linux/drivers/parport/CVS/Root linux-2.4-xfs/linux/drivers/parport/CVS/Root --- linux-2.4.7/linux/drivers/parport/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/parport/CVS/Root Thu Jul 5 11:57:07 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/pci/CVS/Entries linux-2.4-xfs/linux/drivers/pci/CVS/Entries --- linux-2.4.7/linux/drivers/pci/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/pci/CVS/Entries Thu Jul 5 11:57:12 2001 @@ -0,0 +1,14 @@ +/Config.in/1.1/Thu Dec 9 03:05:16 1999/-ko/ +/Makefile/1.16/Wed Jun 13 03:24:09 2001/-ko/ +/compat.c/1.7/Sat Jan 29 23:00:52 2000/-ko/ +/gen-devlist.c/1.6/Wed Nov 1 21:35:42 2000/-ko/ +/names.c/1.8/Mon Oct 23 18:56:35 2000/-ko/ +/pci.c/1.40/Thu Jul 5 05:29:17 2001/-ko/ +/pci.ids/1.30/Tue Jul 3 02:33:57 2001/-ko/ +/proc.c/1.19/Tue May 29 19:53:13 2001/-ko/ +/quirks.c/1.21/Thu Jun 21 15:45:04 2001/-ko/ +/setup-bus.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/setup-irq.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/setup-res.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/syscall.c/1.3/Fri Jan 21 19:20:14 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/pci/CVS/Repository linux-2.4-xfs/linux/drivers/pci/CVS/Repository --- linux-2.4.7/linux/drivers/pci/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/pci/CVS/Repository Thu Jul 5 11:57:10 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/pci diff -rNu linux-2.4.7/linux/drivers/pci/CVS/Root linux-2.4-xfs/linux/drivers/pci/CVS/Root --- linux-2.4.7/linux/drivers/pci/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/pci/CVS/Root Thu Jul 5 11:57:10 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/pcmcia/CVS/Entries linux-2.4-xfs/linux/drivers/pcmcia/CVS/Entries --- linux-2.4.7/linux/drivers/pcmcia/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/pcmcia/CVS/Entries Thu Jul 5 11:57:16 2001 @@ -0,0 +1,29 @@ +/Config.in/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/Makefile/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/bulkmem.c/1.13/Mon Apr 2 17:13:32 2001/-ko/ +/cardbus.c/1.17/Mon Apr 2 17:13:32 2001/-ko/ +/cb_enabler.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/cirrus.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/cistpl.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/cs.c/1.27/Thu Jun 21 15:45:04 2001/-ko/ +/cs_internal.h/1.10/Wed Nov 1 21:35:42 2000/-ko/ +/ds.c/1.14/Thu Feb 22 21:09:04 2001/-ko/ +/hd64465_ss.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/i82365.c/1.18/Tue May 29 19:53:13 2001/-ko/ +/i82365.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/o2micro.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/old-yenta.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/pci_socket.c/1.8/Wed Jun 13 03:24:09 2001/-ko/ +/pci_socket.h/1.6/Sat Nov 25 08:05:45 2000/-ko/ +/ricoh.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/rsrc_mgr.c/1.12/Mon Apr 2 17:13:32 2001/-ko/ +/rsrc_mgr.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/smc34c90.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/tcic.c/1.12/Mon Apr 2 17:13:32 2001/-ko/ +/tcic.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/ti113x.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/topic.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/vg468.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/yenta.c/1.25/Thu Jul 5 06:13:42 2001/-ko/ +/yenta.h/1.4/Thu Jan 6 19:50:16 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/pcmcia/CVS/Repository linux-2.4-xfs/linux/drivers/pcmcia/CVS/Repository --- linux-2.4.7/linux/drivers/pcmcia/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/pcmcia/CVS/Repository Thu Jul 5 11:57:12 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/pcmcia diff -rNu linux-2.4.7/linux/drivers/pcmcia/CVS/Root linux-2.4-xfs/linux/drivers/pcmcia/CVS/Root --- linux-2.4.7/linux/drivers/pcmcia/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/pcmcia/CVS/Root Thu Jul 5 11:57:12 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/pnp/CVS/Entries linux-2.4-xfs/linux/drivers/pnp/CVS/Entries --- linux-2.4.7/linux/drivers/pnp/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/pnp/CVS/Entries Thu Jul 5 11:57:16 2001 @@ -0,0 +1,6 @@ +/Config.in/1.5/Tue Oct 12 19:12:19 1999/-ko/ +/Makefile/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/isapnp.c/1.21/Thu Jul 5 06:13:42 2001/-ko/ +/isapnp_proc.c/1.13/Thu Feb 1 17:10:24 2001/-ko/ +/quirks.c/1.6/Thu Dec 21 05:48:12 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/pnp/CVS/Repository linux-2.4-xfs/linux/drivers/pnp/CVS/Repository --- linux-2.4.7/linux/drivers/pnp/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/pnp/CVS/Repository Thu Jul 5 11:57:16 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/pnp diff -rNu linux-2.4.7/linux/drivers/pnp/CVS/Root linux-2.4-xfs/linux/drivers/pnp/CVS/Root --- linux-2.4.7/linux/drivers/pnp/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/pnp/CVS/Root Thu Jul 5 11:57:16 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/s390/CVS/Entries linux-2.4-xfs/linux/drivers/s390/CVS/Entries --- linux-2.4.7/linux/drivers/s390/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/CVS/Entries Thu Jul 5 11:57:18 2001 @@ -0,0 +1,9 @@ +/Config.in/1.5/Wed May 2 06:22:13 2001/-ko/ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/ccwcache.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/ebcdic.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/idals.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/s390dyn.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/s390io.c/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/s390mach.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/s390/CVS/Entries.Log linux-2.4-xfs/linux/drivers/s390/CVS/Entries.Log --- linux-2.4.7/linux/drivers/s390/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/CVS/Entries.Log Thu Jul 5 11:57:30 2001 @@ -0,0 +1,4 @@ +A D/block//// +A D/char//// +A D/misc//// +A D/net//// diff -rNu linux-2.4.7/linux/drivers/s390/CVS/Repository linux-2.4-xfs/linux/drivers/s390/CVS/Repository --- linux-2.4.7/linux/drivers/s390/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/CVS/Repository Thu Jul 5 11:57:16 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/s390 diff -rNu linux-2.4.7/linux/drivers/s390/CVS/Root linux-2.4-xfs/linux/drivers/s390/CVS/Root --- linux-2.4.7/linux/drivers/s390/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/CVS/Root Thu Jul 5 11:57:16 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/s390/block/CVS/Entries linux-2.4-xfs/linux/drivers/s390/block/CVS/Entries --- linux-2.4.7/linux/drivers/s390/block/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/block/CVS/Entries Thu Jul 5 11:57:22 2001 @@ -0,0 +1,17 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/dasd.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/dasd_3370_erp.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/dasd_3990_erp.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/dasd_3990_erp.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/dasd_9336_erp.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/dasd_9343_erp.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/dasd_9343_erp.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/dasd_diag.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/dasd_diag.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/dasd_eckd.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/dasd_eckd.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/dasd_fba.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/dasd_fba.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/xpram.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/xpram.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/s390/block/CVS/Repository linux-2.4-xfs/linux/drivers/s390/block/CVS/Repository --- linux-2.4.7/linux/drivers/s390/block/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/block/CVS/Repository Thu Jul 5 11:57:18 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/s390/block diff -rNu linux-2.4.7/linux/drivers/s390/block/CVS/Root linux-2.4-xfs/linux/drivers/s390/block/CVS/Root --- linux-2.4.7/linux/drivers/s390/block/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/block/CVS/Root Thu Jul 5 11:57:18 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/s390/char/CVS/Entries linux-2.4-xfs/linux/drivers/s390/char/CVS/Entries --- linux-2.4.7/linux/drivers/s390/char/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/char/CVS/Entries Thu Jul 5 11:57:29 2001 @@ -0,0 +1,32 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/con3215.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/ctrlchar.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/ctrlchar.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/hwc.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/hwc_con.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/hwc_rw.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/hwc_rw.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/hwc_tty.c/1.4/Tue May 29 19:53:13 2001/-ko/ +/tape.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/tape.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/tape3480.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/tape3480.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/tape3490.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/tape3490.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/tape34xx.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/tape34xx.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/tapeblock.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/tapeblock.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/tapechar.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/tapechar.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/tapedefs.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/tuball.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/tubfs.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/tubio.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/tubtty.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/tubttyaid.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/tubttybld.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/tubttyrcl.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/tubttyscl.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/tubttysiz.c/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/s390/char/CVS/Repository linux-2.4-xfs/linux/drivers/s390/char/CVS/Repository --- linux-2.4.7/linux/drivers/s390/char/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/char/CVS/Repository Thu Jul 5 11:57:22 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/s390/char diff -rNu linux-2.4.7/linux/drivers/s390/char/CVS/Root linux-2.4-xfs/linux/drivers/s390/char/CVS/Root --- linux-2.4.7/linux/drivers/s390/char/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/char/CVS/Root Thu Jul 5 11:57:22 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/s390/misc/CVS/Entries linux-2.4-xfs/linux/drivers/s390/misc/CVS/Entries --- linux-2.4.7/linux/drivers/s390/misc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/misc/CVS/Entries Thu Jul 5 11:57:30 2001 @@ -0,0 +1,3 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/chandev.c/1.4/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/s390/misc/CVS/Repository linux-2.4-xfs/linux/drivers/s390/misc/CVS/Repository --- linux-2.4.7/linux/drivers/s390/misc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/misc/CVS/Repository Thu Jul 5 11:57:29 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/s390/misc diff -rNu linux-2.4.7/linux/drivers/s390/misc/CVS/Root linux-2.4-xfs/linux/drivers/s390/misc/CVS/Root --- linux-2.4.7/linux/drivers/s390/misc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/misc/CVS/Root Thu Jul 5 11:57:29 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/s390/net/CVS/Entries linux-2.4-xfs/linux/drivers/s390/net/CVS/Entries --- linux-2.4.7/linux/drivers/s390/net/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/net/CVS/Entries Thu Jul 5 11:57:32 2001 @@ -0,0 +1,10 @@ +/Makefile/1.3/Wed May 2 06:22:13 2001/-ko/ +/ctcmain.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/ctctty.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/ctctty.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/fsm.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/fsm.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/iucv.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/iucv.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/netiucv.c/1.3/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/s390/net/CVS/Repository linux-2.4-xfs/linux/drivers/s390/net/CVS/Repository --- linux-2.4.7/linux/drivers/s390/net/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/net/CVS/Repository Thu Jul 5 11:57:30 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/s390/net diff -rNu linux-2.4.7/linux/drivers/s390/net/CVS/Root linux-2.4-xfs/linux/drivers/s390/net/CVS/Root --- linux-2.4.7/linux/drivers/s390/net/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/s390/net/CVS/Root Thu Jul 5 11:57:30 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/sbus/CVS/Entries linux-2.4-xfs/linux/drivers/sbus/CVS/Entries --- linux-2.4.7/linux/drivers/sbus/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sbus/CVS/Entries Thu Jul 5 11:57:32 2001 @@ -0,0 +1,4 @@ +/Makefile/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/dvma.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/sbus.c/1.12/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/sbus/CVS/Entries.Log linux-2.4-xfs/linux/drivers/sbus/CVS/Entries.Log --- linux-2.4.7/linux/drivers/sbus/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sbus/CVS/Entries.Log Thu Jul 5 11:57:36 2001 @@ -0,0 +1,2 @@ +A D/audio//// +A D/char//// diff -rNu linux-2.4.7/linux/drivers/sbus/CVS/Repository linux-2.4-xfs/linux/drivers/sbus/CVS/Repository --- linux-2.4.7/linux/drivers/sbus/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sbus/CVS/Repository Thu Jul 5 11:57:32 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/sbus diff -rNu linux-2.4.7/linux/drivers/sbus/CVS/Root linux-2.4-xfs/linux/drivers/sbus/CVS/Root --- linux-2.4.7/linux/drivers/sbus/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sbus/CVS/Root Thu Jul 5 11:57:32 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/sbus/audio/CVS/Entries linux-2.4-xfs/linux/drivers/sbus/audio/CVS/Entries --- linux-2.4.7/linux/drivers/sbus/audio/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sbus/audio/CVS/Entries Thu Jul 5 11:57:36 2001 @@ -0,0 +1,13 @@ +/Config.in/1.5/Thu Feb 1 17:10:24 2001/-ko/ +/Makefile/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/amd7930.c/1.8/Sat Jun 9 02:44:24 2001/-ko/ +/amd7930.h/1.3/Wed Dec 29 19:04:31 1999/-ko/ +/audio.c/1.13/Sat Jun 9 02:44:24 2001/-ko/ +/cs4215.h/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/cs4231.c/1.11/Sat Jun 9 02:44:24 2001/-ko/ +/cs4231.h/1.4/Wed Dec 29 19:04:31 1999/-ko/ +/dbri.c/1.12/Sat Jun 9 02:44:24 2001/-ko/ +/dbri.h/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/dmy.c/1.8/Sat Jun 9 02:44:24 2001/-ko/ +/dummy.h/1.3/Wed Dec 29 19:04:31 1999/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/sbus/audio/CVS/Repository linux-2.4-xfs/linux/drivers/sbus/audio/CVS/Repository --- linux-2.4.7/linux/drivers/sbus/audio/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sbus/audio/CVS/Repository Thu Jul 5 11:57:32 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/sbus/audio diff -rNu linux-2.4.7/linux/drivers/sbus/audio/CVS/Root linux-2.4-xfs/linux/drivers/sbus/audio/CVS/Root --- linux-2.4.7/linux/drivers/sbus/audio/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sbus/audio/CVS/Root Thu Jul 5 11:57:32 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/sbus/char/CVS/Entries linux-2.4-xfs/linux/drivers/sbus/char/CVS/Entries --- linux-2.4.7/linux/drivers/sbus/char/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sbus/char/CVS/Entries Thu Jul 5 11:57:46 2001 @@ -0,0 +1,39 @@ +/Config.in/1.7/Fri Feb 11 00:45:14 2000/-ko/ +/Makefile/1.10/Wed May 2 06:22:13 2001/-ko/ +/aurora.c/1.8/Tue May 29 19:53:13 2001/-ko/ +/aurora.h/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/bbc_envctrl.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/bbc_i2c.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/bbc_i2c.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/bpp.c/1.15/Thu Feb 1 17:10:24 2001/-ko/ +/cd180.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/cpwatchdog.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/display7seg.c/1.2/Sat Nov 25 08:05:45 2000/-ko/ +/envctrl.c/1.12/Mon Apr 2 17:13:32 2001/-ko/ +/flash.c/1.12/Mon Apr 2 17:13:32 2001/-ko/ +/jsflash.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/max1617.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/openprom.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/pcikbd.c/1.19/Thu Jun 21 15:45:04 2001/-ko/ +/pcikbd.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/riowatchdog.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/rtc.c/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/sab82532.c/1.20/Mon Jul 2 15:59:04 2001/-ko/ +/su.c/1.17/Mon Jul 2 15:59:04 2001/-ko/ +/sunkbd.c/1.15/Thu Feb 1 17:10:24 2001/-ko/ +/sunkbd.h/1.3/Fri Feb 11 00:45:14 2000/-ko/ +/sunkbdmap.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sunkeymap.c/1.3/Wed Dec 29 19:04:31 1999/-ko/ +/sunkeymap.map/1.3/Wed Dec 29 19:04:31 1999/-ko/ +/sunmouse.c/1.13/Thu Feb 1 17:10:24 2001/-ko/ +/sunmouse.h/1.3/Wed Dec 29 19:04:31 1999/-ko/ +/sunserial.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/sunserial.h/1.3/Wed Dec 29 19:04:31 1999/-ko/ +/uctrl.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/vfc.h/1.3/Thu Feb 17 20:46:04 2000/-ko/ +/vfc_dev.c/1.12/Mon Apr 2 17:13:32 2001/-ko/ +/vfc_i2c.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/vfc_i2c.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/zs.c/1.17/Mon Jul 2 15:59:04 2001/-ko/ +/zs.h/1.3/Wed Dec 29 19:04:31 1999/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/sbus/char/CVS/Repository linux-2.4-xfs/linux/drivers/sbus/char/CVS/Repository --- linux-2.4.7/linux/drivers/sbus/char/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sbus/char/CVS/Repository Thu Jul 5 11:57:36 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/sbus/char diff -rNu linux-2.4.7/linux/drivers/sbus/char/CVS/Root linux-2.4-xfs/linux/drivers/sbus/char/CVS/Root --- linux-2.4.7/linux/drivers/sbus/char/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sbus/char/CVS/Root Thu Jul 5 11:57:36 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/scsi/CVS/Entries linux-2.4-xfs/linux/drivers/scsi/CVS/Entries --- linux-2.4.7/linux/drivers/scsi/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/CVS/Entries Thu Jul 5 11:59:50 2001 @@ -0,0 +1,266 @@ +/3w-xxxx.c/1.10/Thu Jun 28 05:21:16 2001/-ko/ +/3w-xxxx.h/1.5/Thu Jun 28 05:21:16 2001/-ko/ +/53c7,8xx.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/53c7,8xx.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/53c7,8xx.scr/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/53c7xx.c/1.12/Wed May 2 06:22:13 2001/-ko/ +/53c7xx.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/53c7xx.scr/1.3/Wed May 2 06:22:13 2001/-ko/ +/53c8xx_d.h/1.4/Wed Dec 15 00:05:45 1999/-ko/ +/53c8xx_u.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/AM53C974.c/1.11/Wed May 2 06:22:13 2001/-ko/ +/AM53C974.h/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/BusLogic.c/1.11/Sat Nov 25 08:05:45 2000/-ko/ +/BusLogic.h/1.5/Wed Dec 29 19:04:31 1999/-ko/ +/ChangeLog/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ChangeLog.ips/1.4/Tue May 29 19:53:13 2001/-ko/ +/ChangeLog.ncr53c8xx/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/ChangeLog.serverraid/1.1/Mon Sep 6 21:36:14 1999/-ko/ +/ChangeLog.sym53c8xx/1.12/Mon Apr 2 17:13:32 2001/-ko/ +/Config.in/1.21/Thu Jul 5 06:13:42 2001/-ko/ +/FlashPoint.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/LICENSE.FlashPoint/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Makefile/1.26/Tue May 29 19:53:13 2001/-ko/ +/NCR5380.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/NCR5380.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/NCR53C9x.c/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/NCR53C9x.h/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/NCR53c406a.c/1.10/Thu Jun 28 05:21:16 2001/-ko/ +/NCR53c406a.h/1.3/Fri Nov 12 18:56:11 1999/-ko/ +/README.AM53C974/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README.BusLogic/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README.FlashPoint/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README.Mylex/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README.aha152x/1.1/Thu Jan 6 19:50:16 2000/-ko/ +/README.dtc3x80/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README.g_NCR5380/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README.ibmmca/1.6/Tue May 29 19:53:13 2001/-ko/ +/README.in2000/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README.ncr53c7xx/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README.ncr53c8xx/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/README.osst/1.1/Wed Jan 3 01:43:05 2001/-ko/ +/README.ppa/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README.qlogicfas/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README.qlogicisp/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/README.st/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/README.tmscsim/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/a2091.c/1.11/Sun Dec 17 19:15:00 2000/-ko/ +/a2091.h/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/a3000.c/1.9/Sun Dec 17 19:15:00 2000/-ko/ +/a3000.h/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/advansys.c/1.17/Wed May 2 06:22:13 2001/-ko/ +/advansys.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/aha152x.c/1.19/Thu Jun 28 05:21:16 2001/-ko/ +/aha152x.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/aha1542.c/1.16/Tue May 29 19:53:13 2001/-ko/ +/aha1542.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/aha1740.c/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/aha1740.h/1.3/Fri Nov 12 18:56:11 1999/-ko/ +/aic7xxx_old.c/1.3/Wed Jun 13 03:24:09 2001/-ko/ +/amiga7xx.c/1.7/Wed Jan 3 01:43:05 2001/-ko/ +/amiga7xx.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/atari_NCR5380.c/1.4/Mon Sep 6 21:36:14 1999/-ko/ +/atari_dma_emul.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/atari_scsi.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/atari_scsi.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/atp870u.c/1.12/Wed May 2 06:22:13 2001/-ko/ +/atp870u.h/1.5/Wed Dec 15 00:05:45 1999/-ko/ +/blz1230.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/blz1230.h/1.4/Fri Nov 12 18:56:11 1999/-ko/ +/blz2060.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/blz2060.h/1.4/Fri Nov 12 18:56:11 1999/-ko/ +/bvme6000.c/1.3/Fri Nov 12 18:56:11 1999/-ko/ +/bvme6000.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/constants.c/1.7/Wed Jun 13 03:24:09 2001/-ko/ +/constants.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cpqfc.Readme/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/cpqfcTS.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/cpqfcTSchip.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/cpqfcTScontrol.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/cpqfcTSi2c.c/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/cpqfcTSinit.c/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/cpqfcTSioctl.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/cpqfcTSstructs.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/cpqfcTStrigger.c/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/cpqfcTSworker.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/cpqioctl.c/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/cyberstorm.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/cyberstorm.h/1.4/Fri Nov 12 18:56:11 1999/-ko/ +/cyberstormII.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/cyberstormII.h/1.4/Fri Nov 12 18:56:11 1999/-ko/ +/dc390.h/1.5/Wed Jan 3 01:43:05 2001/-ko/ +/dec_esp.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/dec_esp.h/1.3/Sun Feb 27 22:37:25 2000/-ko/ +/dmx3191d.c/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/dmx3191d.h/1.3/Thu Jun 28 05:21:16 2001/-ko/ +/dtc.c/1.7/Sat Nov 25 08:05:45 2000/-ko/ +/dtc.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/eata.c/1.16/Tue May 29 19:53:13 2001/-ko/ +/eata.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/eata_dma.c/1.16/Thu Jun 28 05:21:16 2001/-ko/ +/eata_dma.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/eata_dma_proc.c/1.7/Sat Nov 25 08:05:45 2000/-ko/ +/eata_dma_proc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/eata_generic.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/eata_pio.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/eata_pio.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/eata_pio_proc.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/esp.c/1.16/Thu Feb 22 21:09:04 2001/-ko/ +/esp.h/1.5/Fri Apr 21 16:00:46 2000/-ko/ +/fastlane.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/fastlane.h/1.4/Fri Nov 12 18:56:11 1999/-ko/ +/fcal.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/fcal.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fd_mcs.c/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/fd_mcs.h/1.3/Fri Nov 12 18:56:11 1999/-ko/ +/fdomain.c/1.14/Tue May 29 19:53:13 2001/-ko/ +/fdomain.h/1.3/Fri Nov 12 18:56:11 1999/-ko/ +/g_NCR5380.c/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/g_NCR5380.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/gdth.c/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/gdth.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/gdth_ioctl.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/gdth_proc.c/1.8/Tue May 29 19:53:13 2001/-ko/ +/gdth_proc.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/gvp11.c/1.10/Sun Dec 17 19:15:00 2000/-ko/ +/gvp11.h/1.3/Fri Nov 12 18:56:11 1999/-ko/ +/hosts.c/1.24/Thu Jul 5 05:29:17 2001/-ko/ +/hosts.h/1.16/Wed May 2 06:22:13 2001/-ko/ +/i60uscsi.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/i60uscsi.h/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/i91uscsi.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/i91uscsi.h/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/ibmmca.c/1.14/Tue May 29 19:53:13 2001/-ko/ +/ibmmca.h/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/ide-scsi.c/1.16/Thu Feb 22 21:09:04 2001/-ko/ +/ide-scsi.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/imm.c/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/imm.h/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/in2000.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/in2000.h/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/ini9100u.c/1.14/Mon Apr 2 17:13:32 2001/-ko/ +/ini9100u.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/inia100.c/1.15/Mon Apr 2 17:13:32 2001/-ko/ +/inia100.h/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/ips.c/1.16/Tue May 29 19:53:13 2001/-ko/ +/ips.h/1.9/Tue May 29 19:53:13 2001/-ko/ +/jazz_esp.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/jazz_esp.h/1.4/Sun Feb 27 22:37:25 2000/-ko/ +/mac53c94.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/mac53c94.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/mac_NCR5380.c/1.4/Fri Jan 5 18:42:30 2001/-ko/ +/mac_esp.c/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/mac_esp.h/1.3/Fri Nov 12 18:56:11 1999/-ko/ +/mac_scsi.c/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/mac_scsi.h/1.3/Fri Nov 12 18:56:11 1999/-ko/ +/mca_53c9x.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/mca_53c9x.h/1.3/Fri Nov 12 18:56:11 1999/-ko/ +/megaraid.c/1.23/Thu Jul 5 05:29:17 2001/-ko/ +/megaraid.h/1.10/Thu Jul 5 05:29:17 2001/-ko/ +/mesh.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/mesh.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/mvme147.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/mvme147.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/mvme16x.c/1.5/Mon Feb 14 19:32:36 2000/-ko/ +/mvme16x.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/ncr53c8xx.c/1.20/Wed May 2 06:22:13 2001/-ko/ +/ncr53c8xx.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/oktagon_esp.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/oktagon_esp.h/1.2/Fri Nov 12 18:56:11 1999/-ko/ +/oktagon_io.S/1.1/Sun Aug 29 03:09:59 1999/-ko/ +/osst.c/1.5/Thu Jul 5 06:13:42 2001/-ko/ +/osst.h/1.3/Thu Jul 5 06:13:42 2001/-ko/ +/osst_detect.h/1.1/Wed Jan 3 01:43:05 2001/-ko/ +/osst_options.h/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/pas16.c/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/pas16.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/pci2000.c/1.15/Wed May 2 06:22:13 2001/-ko/ +/pci2000.h/1.5/Sun Feb 27 22:37:25 2000/-ko/ +/pci2220i.c/1.18/Tue May 29 19:53:13 2001/-ko/ +/pci2220i.h/1.6/Sun Feb 27 22:37:25 2000/-ko/ +/pluto.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/pluto.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ppa.c/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/ppa.h/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/psi240i.c/1.6/Sat Nov 25 08:05:45 2000/-ko/ +/psi240i.h/1.4/Fri Jan 21 19:20:14 2000/-ko/ +/psi_chip.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/psi_dale.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/psi_roy.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ql12160_fw.h/1.1/Fri Feb 11 00:45:14 2000/-ko/ +/ql1280_fw.h/1.1/Fri Feb 11 00:45:14 2000/-ko/ +/qla1280.c/1.10/Thu Jun 28 05:21:16 2001/-ko/ +/qla1280.h/1.1/Fri Feb 11 00:45:14 2000/-ko/ +/qlogicfas.c/1.8/Tue May 29 19:53:13 2001/-ko/ +/qlogicfas.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/qlogicfc.c/1.17/Wed May 2 06:22:13 2001/-ko/ +/qlogicfc.h/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/qlogicfc_asm.c/1.5/Sat Jan 29 23:00:52 2000/-ko/ +/qlogicisp.c/1.21/Thu Jun 21 15:45:04 2001/-ko/ +/qlogicisp.h/1.3/Mon Nov 15 18:18:49 1999/-ko/ +/qlogicisp_asm.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/qlogicpti.c/1.13/Sat Jun 9 02:44:24 2001/-ko/ +/qlogicpti.h/1.4/Wed Dec 29 19:04:31 1999/-ko/ +/qlogicpti_asm.c/1.3/Wed Dec 29 19:04:31 1999/-ko/ +/script_asm.pl/1.4/Wed Nov 24 20:20:05 1999/-ko/ +/scsi.c/1.36/Wed Jun 13 03:24:09 2001/-ko/ +/scsi.h/1.18/Wed Jan 3 01:43:05 2001/-ko/ +/scsi_debug.c/1.13/Sat Nov 25 08:05:45 2000/-ko/ +/scsi_debug.h/1.4/Wed Dec 15 00:05:45 1999/-ko/ +/scsi_dma.c/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/scsi_error.c/1.18/Mon Apr 2 17:13:32 2001/-ko/ +/scsi_ioctl.c/1.18/Wed Jun 6 03:10:14 2001/-ko/ +/scsi_lib.c/1.30/Tue May 29 19:53:13 2001/-ko/ +/scsi_merge.c/1.27/Tue Apr 3 23:07:43 2001/-ko/ +/scsi_module.c/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/scsi_obsolete.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/scsi_obsolete.h/1.3/Wed Sep 15 20:42:56 1999/-ko/ +/scsi_proc.c/1.10/Thu Jun 28 05:21:16 2001/-ko/ +/scsi_queue.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/scsi_scan.c/1.15/Wed Jun 13 03:24:09 2001/-ko/ +/scsi_syms.c/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/scsicam.c/1.5/Wed Nov 24 20:36:16 1999/-ko/ +/scsiiom.c/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/sd.c/1.36/Wed Jun 13 03:24:09 2001/-ko/ +/sd.h/1.5/Sun Jan 9 23:56:19 2000/-ko/ +/seagate.c/1.11/Sat Nov 25 08:05:45 2000/-ko/ +/seagate.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/sg.c/1.19/Thu Jul 5 06:13:42 2001/-ko/ +/sgiwd93.c/1.10/Sat Nov 25 08:05:45 2000/-ko/ +/sgiwd93.h/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/sim710.c/1.7/Wed Jan 3 01:43:05 2001/-ko/ +/sim710.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/sim710.scr/1.1/Tue Oct 12 19:12:19 1999/-ko/ +/sim710_d.h/1.3/Wed Dec 15 00:05:45 1999/-ko/ +/sim710_u.h/1.1/Tue Oct 12 19:12:19 1999/-ko/ +/sr.c/1.25/Tue May 29 19:53:13 2001/-ko/ +/sr.h/1.6/Thu Dec 21 05:48:12 2000/-ko/ +/sr_ioctl.c/1.15/Thu Jul 5 05:29:17 2001/-ko/ +/sr_vendor.c/1.8/Thu Dec 21 05:48:12 2000/-ko/ +/st.c/1.28/Wed Jan 3 01:43:05 2001/-ko/ +/st.h/1.9/Tue May 2 21:36:51 2000/-ko/ +/st_options.h/1.6/Tue May 2 21:36:51 2000/-ko/ +/sun3_NCR5380.c/1.2/Wed Jan 3 01:43:05 2001/-ko/ +/sun3_scsi.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/sun3_scsi.h/1.2/Mon Feb 14 19:32:36 2000/-ko/ +/sun3x_esp.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/sun3x_esp.h/1.2/Fri Nov 12 18:56:11 1999/-ko/ +/sym53c416.c/1.9/Thu Jun 28 05:21:16 2001/-ko/ +/sym53c416.h/1.5/Thu Jun 28 05:21:16 2001/-ko/ +/sym53c8xx.c/1.24/Wed Jun 13 03:24:09 2001/-ko/ +/sym53c8xx.h/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/sym53c8xx_comm.h/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/sym53c8xx_defs.h/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/t128.c/1.7/Sat Nov 25 08:05:45 2000/-ko/ +/t128.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/tmscsim.c/1.12/Wed May 2 06:22:13 2001/-ko/ +/tmscsim.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/u14-34f.c/1.15/Tue May 29 19:53:13 2001/-ko/ +/u14-34f.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/ultrastor.c/1.8/Thu Jul 5 05:29:17 2001/-ko/ +/ultrastor.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/wd33c93.c/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/wd33c93.h/1.8/Sun Dec 17 19:15:00 2000/-ko/ +/wd7000.c/1.11/Wed May 2 06:22:13 2001/-ko/ +/wd7000.h/1.3/Fri Nov 12 18:56:11 1999/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/scsi/CVS/Entries.Log linux-2.4-xfs/linux/drivers/scsi/CVS/Entries.Log --- linux-2.4.7/linux/drivers/scsi/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/CVS/Entries.Log Thu Jul 5 12:00:06 2001 @@ -0,0 +1,3 @@ +A D/aic7xxx//// +A D/aic7xxx_old//// +A D/pcmcia//// diff -rNu linux-2.4.7/linux/drivers/scsi/CVS/Repository linux-2.4-xfs/linux/drivers/scsi/CVS/Repository --- linux-2.4.7/linux/drivers/scsi/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/CVS/Repository Thu Jul 5 11:57:46 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/scsi diff -rNu linux-2.4.7/linux/drivers/scsi/CVS/Root linux-2.4-xfs/linux/drivers/scsi/CVS/Root --- linux-2.4.7/linux/drivers/scsi/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/CVS/Root Thu Jul 5 11:57:46 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/scsi/aic7xxx/CVS/Entries linux-2.4-xfs/linux/drivers/scsi/aic7xxx/CVS/Entries --- linux-2.4.7/linux/drivers/scsi/aic7xxx/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/aic7xxx/CVS/Entries Thu Jul 5 12:00:02 2001 @@ -0,0 +1,23 @@ +/Config.in/1.2/Tue May 29 19:53:13 2001/-ko/ +/Makefile/1.2/Tue May 29 19:53:13 2001/-ko/ +/aic7770.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/aic7770_linux.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/aic7xxx.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/aic7xxx.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/aic7xxx.reg/1.6/Tue May 29 19:53:13 2001/-ko/ +/aic7xxx.seq/1.8/Tue May 29 19:53:13 2001/-ko/ +/aic7xxx_93cx6.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/aic7xxx_93cx6.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/aic7xxx_inline.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/aic7xxx_linux.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/aic7xxx_linux_host.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/aic7xxx_linux_pci.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/aic7xxx_osm.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/aic7xxx_pci.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/aic7xxx_proc.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/aic7xxx_reg.h/1.3/Wed Jun 27 21:25:49 2001/-ko/ +/aic7xxx_seq.h/1.3/Wed Jun 27 21:25:49 2001/-ko/ +/cam.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/queue.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/scsi_message.h/1.3/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/scsi/aic7xxx/CVS/Entries.Log linux-2.4-xfs/linux/drivers/scsi/aic7xxx/CVS/Entries.Log --- linux-2.4.7/linux/drivers/scsi/aic7xxx/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/aic7xxx/CVS/Entries.Log Thu Jul 5 12:00:02 2001 @@ -0,0 +1 @@ +A D/aicasm//// diff -rNu linux-2.4.7/linux/drivers/scsi/aic7xxx/CVS/Repository linux-2.4-xfs/linux/drivers/scsi/aic7xxx/CVS/Repository --- linux-2.4.7/linux/drivers/scsi/aic7xxx/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/aic7xxx/CVS/Repository Thu Jul 5 11:59:50 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/scsi/aic7xxx diff -rNu linux-2.4.7/linux/drivers/scsi/aic7xxx/CVS/Root linux-2.4-xfs/linux/drivers/scsi/aic7xxx/CVS/Root --- linux-2.4.7/linux/drivers/scsi/aic7xxx/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/aic7xxx/CVS/Root Thu Jul 5 11:59:50 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/scsi/aic7xxx/aicasm/CVS/Entries linux-2.4-xfs/linux/drivers/scsi/aic7xxx/aicasm/CVS/Entries --- linux-2.4.7/linux/drivers/scsi/aic7xxx/aicasm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/aic7xxx/aicasm/CVS/Entries Thu Jul 5 12:00:04 2001 @@ -0,0 +1,9 @@ +/Makefile/1.2/Tue May 29 19:53:13 2001/-ko/ +/aicasm.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/aicasm.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/aicasm_gram.y/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/aicasm_insformat.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/aicasm_scan.l/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/aicasm_symbol.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/aicasm_symbol.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/scsi/aic7xxx/aicasm/CVS/Repository linux-2.4-xfs/linux/drivers/scsi/aic7xxx/aicasm/CVS/Repository --- linux-2.4.7/linux/drivers/scsi/aic7xxx/aicasm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/aic7xxx/aicasm/CVS/Repository Thu Jul 5 12:00:02 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/scsi/aic7xxx/aicasm diff -rNu linux-2.4.7/linux/drivers/scsi/aic7xxx/aicasm/CVS/Root linux-2.4-xfs/linux/drivers/scsi/aic7xxx/aicasm/CVS/Root --- linux-2.4.7/linux/drivers/scsi/aic7xxx/aicasm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/aic7xxx/aicasm/CVS/Root Thu Jul 5 12:00:02 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/scsi/aic7xxx_old/CVS/Entries linux-2.4-xfs/linux/drivers/scsi/aic7xxx_old/CVS/Entries --- linux-2.4.7/linux/drivers/scsi/aic7xxx_old/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/aic7xxx_old/CVS/Entries Thu Jul 5 12:00:06 2001 @@ -0,0 +1,10 @@ +/README.aic7xxx/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/aic7xxx.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/aic7xxx.reg/1.2/Wed May 2 06:22:13 2001/-ko/ +/aic7xxx.seq/1.2/Wed May 2 06:22:13 2001/-ko/ +/aic7xxx_proc.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/aic7xxx_reg.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/aic7xxx_seq.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/scsi_message.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/sequencer.h/1.2/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/scsi/aic7xxx_old/CVS/Repository linux-2.4-xfs/linux/drivers/scsi/aic7xxx_old/CVS/Repository --- linux-2.4.7/linux/drivers/scsi/aic7xxx_old/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/aic7xxx_old/CVS/Repository Thu Jul 5 12:00:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/scsi/aic7xxx_old diff -rNu linux-2.4.7/linux/drivers/scsi/aic7xxx_old/CVS/Root linux-2.4-xfs/linux/drivers/scsi/aic7xxx_old/CVS/Root --- linux-2.4.7/linux/drivers/scsi/aic7xxx_old/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/aic7xxx_old/CVS/Root Thu Jul 5 12:00:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/scsi/pcmcia/CVS/Entries linux-2.4-xfs/linux/drivers/scsi/pcmcia/CVS/Entries --- linux-2.4.7/linux/drivers/scsi/pcmcia/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/pcmcia/CVS/Entries Thu Jul 5 12:00:08 2001 @@ -0,0 +1,10 @@ +/Config.in/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/Makefile/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/aha152x_stub.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/fdomain_stub.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/nsp_cs.c/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/nsp_cs.h/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/nsp_debug.c/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/nsp_io.h/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/qlogic_stub.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/scsi/pcmcia/CVS/Repository linux-2.4-xfs/linux/drivers/scsi/pcmcia/CVS/Repository --- linux-2.4.7/linux/drivers/scsi/pcmcia/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/pcmcia/CVS/Repository Thu Jul 5 12:00:06 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/scsi/pcmcia diff -rNu linux-2.4.7/linux/drivers/scsi/pcmcia/CVS/Root linux-2.4-xfs/linux/drivers/scsi/pcmcia/CVS/Root --- linux-2.4.7/linux/drivers/scsi/pcmcia/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/scsi/pcmcia/CVS/Root Thu Jul 5 12:00:06 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/scsi/pcmcia/nsp_cs.c linux-2.4-xfs/linux/drivers/scsi/pcmcia/nsp_cs.c --- linux-2.4.7/linux/drivers/scsi/pcmcia/nsp_cs.c Thu Jul 5 10:49:38 2001 +++ linux-2.4-xfs/linux/drivers/scsi/pcmcia/nsp_cs.c Thu Jul 5 00:29:17 2001 @@ -23,7 +23,7 @@ ***********************************************************************/ -/* $Id: nsp_cs.c,v 1.28 2001/02/15 02:56:32 elca Exp $ */ +/* $Id$ */ #ifdef NSP_KERNEL_2_2 #include @@ -71,7 +71,7 @@ static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); MODULE_PARM_DESC(pc_debug, "set debug level"); -static char *version = "$Id: nsp_cs.c,v 1.28 2001/02/15 02:56:32 elca Exp $"; +static char *version = "$Id$"; #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) #else #define DEBUG(n, args...) /* */ diff -rNu linux-2.4.7/linux/drivers/scsi/pcmcia/nsp_cs.h linux-2.4-xfs/linux/drivers/scsi/pcmcia/nsp_cs.h --- linux-2.4.7/linux/drivers/scsi/pcmcia/nsp_cs.h Thu Jul 5 10:49:38 2001 +++ linux-2.4-xfs/linux/drivers/scsi/pcmcia/nsp_cs.h Thu Jul 5 00:29:17 2001 @@ -10,7 +10,7 @@ =========================================================*/ -/* $Id: nsp_cs.h,v 1.18 2001/02/09 04:42:19 elca Exp $ */ +/* $Id$ */ #ifndef __nsp_cs__ #define __nsp_cs__ diff -rNu linux-2.4.7/linux/drivers/scsi/pcmcia/nsp_debug.c linux-2.4-xfs/linux/drivers/scsi/pcmcia/nsp_debug.c --- linux-2.4.7/linux/drivers/scsi/pcmcia/nsp_debug.c Thu Jul 5 10:49:38 2001 +++ linux-2.4-xfs/linux/drivers/scsi/pcmcia/nsp_debug.c Thu Jul 5 00:29:17 2001 @@ -6,7 +6,7 @@ the GNU General Public License. =========================================================================*/ -/* $Id: nsp_debug.c,v 1.5 2001/02/08 08:08:58 elca Exp $ */ +/* $Id$ */ /* * Show the command data of a command diff -rNu linux-2.4.7/linux/drivers/scsi/pcmcia/nsp_io.h linux-2.4-xfs/linux/drivers/scsi/pcmcia/nsp_io.h --- linux-2.4.7/linux/drivers/scsi/pcmcia/nsp_io.h Thu Jul 5 10:49:38 2001 +++ linux-2.4-xfs/linux/drivers/scsi/pcmcia/nsp_io.h Thu Jul 5 00:29:17 2001 @@ -7,7 +7,7 @@ */ -/* $Id: nsp_io.h,v 1.8 2001/01/30 05:16:02 elca Exp $ */ +/* $Id$ */ #ifndef __NSP_IO_H__ #define __NSP_IO_H__ diff -rNu linux-2.4.7/linux/drivers/scsi/sd.c linux-2.4-xfs/linux/drivers/scsi/sd.c --- linux-2.4.7/linux/drivers/scsi/sd.c Tue Jun 12 13:17:17 2001 +++ linux-2.4-xfs/linux/drivers/scsi/sd.c Tue Jun 12 22:24:09 2001 @@ -234,6 +234,8 @@ case BLKPG: case BLKELVGET: case BLKELVSET: + case BLKBSZGET: + case BLKBSZSET: return blk_ioctl(inode->i_rdev, cmd, arg); case BLKRRPART: /* Re-read partition tables */ diff -rNu linux-2.4.7/linux/drivers/sgi/CVS/Entries linux-2.4-xfs/linux/drivers/sgi/CVS/Entries --- linux-2.4.7/linux/drivers/sgi/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sgi/CVS/Entries Thu Jul 5 12:00:08 2001 @@ -0,0 +1,3 @@ +/Config.in/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/Makefile/1.5/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/sgi/CVS/Entries.Log linux-2.4-xfs/linux/drivers/sgi/CVS/Entries.Log --- linux-2.4.7/linux/drivers/sgi/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sgi/CVS/Entries.Log Thu Jul 5 12:00:08 2001 @@ -0,0 +1 @@ +A D/char//// diff -rNu linux-2.4.7/linux/drivers/sgi/CVS/Repository linux-2.4-xfs/linux/drivers/sgi/CVS/Repository --- linux-2.4.7/linux/drivers/sgi/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sgi/CVS/Repository Thu Jul 5 12:00:08 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/sgi diff -rNu linux-2.4.7/linux/drivers/sgi/CVS/Root linux-2.4-xfs/linux/drivers/sgi/CVS/Root --- linux-2.4.7/linux/drivers/sgi/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sgi/CVS/Root Thu Jul 5 12:00:08 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/sgi/char/CVS/Entries linux-2.4-xfs/linux/drivers/sgi/char/CVS/Entries --- linux-2.4.7/linux/drivers/sgi/char/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sgi/char/CVS/Entries Thu Jul 5 12:00:10 2001 @@ -0,0 +1,16 @@ +/Makefile/1.4/Wed May 2 06:22:13 2001/-ko/ +/ds1286.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/gconsole.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/graphics.c/1.14/Mon Apr 2 17:13:32 2001/-ko/ +/graphics.h/1.3/Fri Jul 2 09:43:42 1999/-ko/ +/graphics_syms.c/1.3/Fri Mar 3 01:30:48 2000/-ko/ +/newport.c/1.5/Fri Mar 3 01:30:48 2000/-ko/ +/rrm.c/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/sgicons.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/sgiserial.c/1.8/Wed Nov 1 21:35:42 2000/-ko/ +/sgiserial.h/1.3/Fri Jul 2 09:43:42 1999/-ko/ +/shmiq.c/1.15/Mon Apr 2 17:13:32 2001/-ko/ +/streamable.c/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/usema.c/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/usema.h/1.1/Fri Jul 2 09:56:47 1999/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/sgi/char/CVS/Repository linux-2.4-xfs/linux/drivers/sgi/char/CVS/Repository --- linux-2.4.7/linux/drivers/sgi/char/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sgi/char/CVS/Repository Thu Jul 5 12:00:08 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/sgi/char diff -rNu linux-2.4.7/linux/drivers/sgi/char/CVS/Root linux-2.4-xfs/linux/drivers/sgi/char/CVS/Root --- linux-2.4.7/linux/drivers/sgi/char/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sgi/char/CVS/Root Thu Jul 5 12:00:08 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/sound/CVS/Entries linux-2.4-xfs/linux/drivers/sound/CVS/Entries --- linux-2.4.7/linux/drivers/sound/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sound/CVS/Entries Thu Jul 5 12:00:51 2001 @@ -0,0 +1,138 @@ +/.indent.pro/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/.version/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/724hwmcode.h/1.2/Sat Nov 25 08:05:45 2000/-ko/ +/CHANGELOG/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/COPYING/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Config.in/1.25/Thu Jul 5 05:29:17 2001/-ko/ +/Hwmcode.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/Makefile/1.29/Tue Jul 3 02:33:57 2001/-ko/ +/README.FIRST/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ac97.c/1.3/Sun Jan 9 23:56:19 2000/-ko/ +/ac97.h/1.4/Fri Oct 29 00:22:42 1999/-ko/ +/ac97_codec.c/1.16/Wed May 2 06:22:13 2001/-ko/ +/aci.c/1.6/Wed Jun 13 03:24:09 2001/-ko/ +/aci.h/1.2/Wed Jun 13 03:24:09 2001/-ko/ +/ad1816.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/ad1848.c/1.11/Thu Jul 5 05:29:17 2001/-ko/ +/ad1848.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/ad1848_mixer.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/adlib_card.c/1.8/Mon Oct 23 18:56:35 2000/-ko/ +/aedsp16.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/audio.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/audio_syms.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/awe_hw.h/1.2/Fri Mar 24 21:32:44 2000/-ko/ +/awe_wave.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/awe_wave.h/1.2/Fri Mar 24 21:32:44 2000/-ko/ +/bin2hex.c/1.3/Mon Mar 20 17:58:41 2000/-ko/ +/cmpci.c/1.23/Thu Jun 28 05:21:16 2001/-ko/ +/coproc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cs4232.c/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/cs4232.h/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/cs461x.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/cs461x_image.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/cs46xx.c/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/cs46xx_wrapper-24.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/cs46xxpm-24.h/1.2/Thu Jun 28 05:21:16 2001/-ko/ +/cs46xxpm.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/dev_table.c/1.10/Mon Oct 23 18:56:35 2000/-ko/ +/dev_table.h/1.14/Thu Jul 5 05:29:17 2001/-ko/ +/dm.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dmabuf.c/1.8/Thu Sep 28 22:42:39 2000/-ko/ +/es1370.c/1.31/Tue May 29 19:53:13 2001/-ko/ +/es1371.c/1.32/Tue May 29 19:53:13 2001/-ko/ +/esssolo1.c/1.28/Tue May 29 19:53:13 2001/-ko/ +/gus.h/1.1/Wed Mar 8 01:44:14 2000/-ko/ +/gus_card.c/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/gus_hw.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/gus_linearvol.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/gus_midi.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/gus_vol.c/1.5/Wed Mar 8 01:44:14 2000/-ko/ +/gus_wave.c/1.7/Wed Jun 13 03:24:09 2001/-ko/ +/hex2hex.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/i810_audio.c/1.12/Thu Jul 5 03:57:00 2001/-ko/ +/ics2101.c/1.7/Sat Nov 25 08:05:45 2000/-ko/ +/iwmem.h/1.3/Sat Nov 25 08:05:45 2000/-ko/ +/mad16.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/maestro.c/1.22/Thu Jul 5 05:29:17 2001/-ko/ +/maestro.h/1.1/Mon Sep 6 21:36:14 1999/-ko/ +/maestro3.c/1.4/Thu Jun 28 05:21:16 2001/-ko/ +/maestro3.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/maestro_tables.h/1.1/Mon Sep 6 21:36:14 1999/-ko/ +/maui.c/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/midi_ctrl.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/midi_syms.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/midi_synth.c/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/midi_synth.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/midibuf.c/1.7/Thu Sep 28 22:42:39 2000/-ko/ +/mpu401.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/mpu401.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/msnd.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/msnd.h/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/msnd_classic.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/msnd_classic.h/1.3/Fri Jan 21 19:20:14 2000/-ko/ +/msnd_pinnacle.c/1.15/Mon Apr 2 17:13:32 2001/-ko/ +/msnd_pinnacle.h/1.3/Fri Jan 21 19:20:14 2000/-ko/ +/nm256.h/1.2/Fri Oct 29 00:22:42 1999/-ko/ +/nm256_audio.c/1.12/Thu Jul 5 05:29:17 2001/-ko/ +/nm256_coeff.h/1.2/Fri Oct 29 00:22:42 1999/-ko/ +/opl3.c/1.8/Mon Oct 23 18:56:35 2000/-ko/ +/opl3.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/opl3_hw.h/1.1/Wed Mar 8 01:44:14 2000/-ko/ +/opl3sa.c/1.8/Mon Oct 23 18:56:35 2000/-ko/ +/opl3sa2.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/os.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/pas2.h/1.1/Wed Mar 8 01:44:14 2000/-ko/ +/pas2_card.c/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/pas2_midi.c/1.7/Sat Nov 25 08:05:45 2000/-ko/ +/pas2_mixer.c/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/pas2_pcm.c/1.7/Sat Nov 25 08:05:45 2000/-ko/ +/pss.c/1.9/Wed Jun 13 03:24:09 2001/-ko/ +/sb.h/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/sb_audio.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/sb_card.c/1.25/Thu Jun 28 05:21:16 2001/-ko/ +/sb_common.c/1.18/Thu Jul 5 05:29:17 2001/-ko/ +/sb_ess.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/sb_ess.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sb_midi.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/sb_mixer.c/1.8/Thu Sep 28 22:42:39 2000/-ko/ +/sb_mixer.h/1.5/Fri Mar 3 01:42:02 2000/-ko/ +/sequencer.c/1.8/Fri Jan 5 18:42:30 2001/-ko/ +/sequencer_syms.c/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/sgalaxy.c/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/skeleton.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/sonicvibes.c/1.31/Wed May 2 06:22:13 2001/-ko/ +/sound_calls.h/1.6/Fri Apr 21 16:00:46 2000/-ko/ +/sound_config.h/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/sound_core.c/1.17/Wed May 2 06:22:13 2001/-ko/ +/sound_firmware.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/sound_firmware.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sound_syms.c/1.7/Mon Oct 23 18:56:35 2000/-ko/ +/sound_timer.c/1.7/Fri Jan 5 18:42:30 2001/-ko/ +/soundcard.c/1.18/Thu Feb 22 21:09:04 2001/-ko/ +/soundvers.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sscape.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/sys_timer.c/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/trident.c/1.22/Tue May 29 19:53:13 2001/-ko/ +/trident.h/1.9/Wed Nov 1 21:35:42 2000/-ko/ +/trix.c/1.10/Thu Feb 1 17:10:24 2001/-ko/ +/tuning.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/uart401.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/uart6850.c/1.8/Mon Oct 23 18:56:35 2000/-ko/ +/ulaw.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/v_midi.c/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/v_midi.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/via82cxxx_audio.c/1.16/Tue Jul 3 02:33:57 2001/-ko/ +/vidc.c/1.10/Wed May 2 06:22:13 2001/-ko/ +/vidc.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/vidc_fill.S/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/vwsnd.c/1.11/Sun Dec 17 19:15:00 2000/-ko/ +/waveartist.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/waveartist.h/1.3/Sat Oct 23 02:22:05 1999/-ko/ +/wavfront.c/1.16/Thu Jun 28 05:21:16 2001/-ko/ +/wf_midi.c/1.9/Thu Jun 28 05:21:16 2001/-ko/ +/ymfpci.c/1.8/Thu Jul 5 05:29:17 2001/-ko/ +/ymfpci.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/ymfpci_image.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/yss225.c/1.3/Sat Nov 25 08:05:45 2000/-ko/ +/yss225.h/1.3/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/sound/CVS/Entries.Log linux-2.4-xfs/linux/drivers/sound/CVS/Entries.Log --- linux-2.4.7/linux/drivers/sound/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sound/CVS/Entries.Log Thu Jul 5 12:00:55 2001 @@ -0,0 +1,3 @@ +A D/cs4281//// +A D/dmasound//// +A D/emu10k1//// diff -rNu linux-2.4.7/linux/drivers/sound/CVS/Repository linux-2.4-xfs/linux/drivers/sound/CVS/Repository --- linux-2.4.7/linux/drivers/sound/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sound/CVS/Repository Thu Jul 5 12:00:10 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/sound diff -rNu linux-2.4.7/linux/drivers/sound/CVS/Root linux-2.4-xfs/linux/drivers/sound/CVS/Root --- linux-2.4.7/linux/drivers/sound/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sound/CVS/Root Thu Jul 5 12:00:10 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/sound/cs4281/CVS/Entries linux-2.4-xfs/linux/drivers/sound/cs4281/CVS/Entries --- linux-2.4.7/linux/drivers/sound/cs4281/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sound/cs4281/CVS/Entries Thu Jul 5 12:00:54 2001 @@ -0,0 +1,7 @@ +/Makefile/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/cs4281_hwdefs.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/cs4281_wrapper-24.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/cs4281m.c/1.5/Thu Jun 28 05:21:16 2001/-ko/ +/cs4281pm-24.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/cs4281pm.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/sound/cs4281/CVS/Repository linux-2.4-xfs/linux/drivers/sound/cs4281/CVS/Repository --- linux-2.4.7/linux/drivers/sound/cs4281/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sound/cs4281/CVS/Repository Thu Jul 5 12:00:51 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/sound/cs4281 diff -rNu linux-2.4.7/linux/drivers/sound/cs4281/CVS/Root linux-2.4-xfs/linux/drivers/sound/cs4281/CVS/Root --- linux-2.4.7/linux/drivers/sound/cs4281/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sound/cs4281/CVS/Root Thu Jul 5 12:00:51 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/sound/dmasound/CVS/Entries linux-2.4-xfs/linux/drivers/sound/dmasound/CVS/Entries --- linux-2.4.7/linux/drivers/sound/dmasound/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sound/dmasound/CVS/Entries Thu Jul 5 12:00:55 2001 @@ -0,0 +1,10 @@ +/Config.in/1.1/Fri Apr 21 16:00:46 2000/-ko/ +/Makefile/1.2/Thu Dec 21 05:48:12 2000/-ko/ +/awacs_defs.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/dmasound.h/1.3/Sat Nov 25 08:05:45 2000/-ko/ +/dmasound_atari.c/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/dmasound_awacs.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/dmasound_core.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/dmasound_paula.c/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/dmasound_q40.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/sound/dmasound/CVS/Repository linux-2.4-xfs/linux/drivers/sound/dmasound/CVS/Repository --- linux-2.4.7/linux/drivers/sound/dmasound/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sound/dmasound/CVS/Repository Thu Jul 5 12:00:54 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/sound/dmasound diff -rNu linux-2.4.7/linux/drivers/sound/dmasound/CVS/Root linux-2.4-xfs/linux/drivers/sound/dmasound/CVS/Root --- linux-2.4.7/linux/drivers/sound/dmasound/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sound/dmasound/CVS/Root Thu Jul 5 12:00:54 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/sound/emu10k1/CVS/Entries linux-2.4-xfs/linux/drivers/sound/emu10k1/CVS/Entries --- linux-2.4.7/linux/drivers/sound/emu10k1/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sound/emu10k1/CVS/Entries Thu Jul 5 12:00:59 2001 @@ -0,0 +1,34 @@ +/8010.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/audio.c/1.8/Tue Jul 3 02:33:57 2001/-ko/ +/audio.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/cardmi.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/cardmi.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/cardmo.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/cardmo.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/cardwi.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/cardwi.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/cardwo.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/cardwo.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/ecard.c/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/ecard.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/efxmgr.h/1.1/Tue May 2 21:36:51 2000/-ko/ +/emu_wrapper.h/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/emuadxmg.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/hwaccess.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/hwaccess.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/icardmid.h/1.1/Tue May 2 21:36:51 2000/-ko/ +/icardwav.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/irqmgr.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/irqmgr.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/main.c/1.9/Tue May 29 19:53:13 2001/-ko/ +/midi.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/midi.h/1.1/Tue May 2 21:36:51 2000/-ko/ +/mixer.c/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/recmgr.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/recmgr.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/timer.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/timer.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/voicemgr.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/voicemgr.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/sound/emu10k1/CVS/Repository linux-2.4-xfs/linux/drivers/sound/emu10k1/CVS/Repository --- linux-2.4.7/linux/drivers/sound/emu10k1/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sound/emu10k1/CVS/Repository Thu Jul 5 12:00:55 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/sound/emu10k1 diff -rNu linux-2.4.7/linux/drivers/sound/emu10k1/CVS/Root linux-2.4-xfs/linux/drivers/sound/emu10k1/CVS/Root --- linux-2.4.7/linux/drivers/sound/emu10k1/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/sound/emu10k1/CVS/Root Thu Jul 5 12:00:55 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/tc/CVS/Entries linux-2.4-xfs/linux/drivers/tc/CVS/Entries --- linux-2.4.7/linux/drivers/tc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/tc/CVS/Entries Thu Jul 5 12:01:00 2001 @@ -0,0 +1,6 @@ +/Makefile/1.2/Wed May 2 06:22:13 2001/-ko/ +/tc.c/1.4/Fri May 26 01:52:46 2000/-ko/ +/tcsyms.c/1.2/Fri May 26 01:52:46 2000/-ko/ +/zs.c/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/zs.h/1.2/Fri May 26 01:52:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/tc/CVS/Repository linux-2.4-xfs/linux/drivers/tc/CVS/Repository --- linux-2.4.7/linux/drivers/tc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/tc/CVS/Repository Thu Jul 5 12:00:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/tc diff -rNu linux-2.4.7/linux/drivers/tc/CVS/Root linux-2.4-xfs/linux/drivers/tc/CVS/Root --- linux-2.4.7/linux/drivers/tc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/tc/CVS/Root Thu Jul 5 12:00:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/telephony/CVS/Entries linux-2.4-xfs/linux/drivers/telephony/CVS/Entries --- linux-2.4.7/linux/drivers/telephony/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/telephony/CVS/Entries Thu Jul 5 12:01:03 2001 @@ -0,0 +1,6 @@ +/Config.in/1.1/Thu Jan 6 19:50:16 2000/-ko/ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/ixj.c/1.15/Thu Jun 28 05:21:16 2001/-ko/ +/ixj.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/phonedev.c/1.6/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/telephony/CVS/Repository linux-2.4-xfs/linux/drivers/telephony/CVS/Repository --- linux-2.4.7/linux/drivers/telephony/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/telephony/CVS/Repository Thu Jul 5 12:01:00 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/telephony diff -rNu linux-2.4.7/linux/drivers/telephony/CVS/Root linux-2.4-xfs/linux/drivers/telephony/CVS/Root --- linux-2.4.7/linux/drivers/telephony/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/telephony/CVS/Root Thu Jul 5 12:01:00 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/usb/CVS/Entries linux-2.4-xfs/linux/drivers/usb/CVS/Entries --- linux-2.4.7/linux/drivers/usb/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/usb/CVS/Entries Thu Jul 5 12:01:19 2001 @@ -0,0 +1,65 @@ +/Config.in/1.42/Thu Jun 28 05:21:16 2001/-ko/ +/Makefile/1.38/Thu Jun 28 05:21:16 2001/-ko/ +/acm.c/1.39/Thu Jul 5 06:13:42 2001/-ko/ +/audio.c/1.31/Wed Jun 13 03:24:09 2001/-ko/ +/audio.h/1.2/Fri Apr 21 16:00:46 2000/-ko/ +/bluetooth.c/1.12/Thu Jun 21 15:45:04 2001/-ko/ +/catc.c/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/dabfirmware.h/1.1/Sat Jan 29 23:00:52 2000/-ko/ +/dabusb.c/1.11/Wed Jun 13 03:24:09 2001/-ko/ +/dabusb.h/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/dc2xx.c/1.19/Wed Jun 13 03:24:09 2001/-ko/ +/devices.c/1.11/Thu Jul 5 06:13:42 2001/-ko/ +/devio.c/1.14/Wed May 2 06:22:13 2001/-ko/ +/drivers.c/1.7/Tue May 2 21:36:51 2000/-ko/ +/dsbr100.c/1.10/Wed Jun 13 03:24:09 2001/-ko/ +/hid-debug.h/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/hid.c/1.25/Wed Jun 13 03:24:09 2001/-ko/ +/hid.h/1.11/Wed May 2 06:22:13 2001/-ko/ +/hub.c/1.35/Wed May 2 06:22:13 2001/-ko/ +/hub.h/1.14/Wed May 2 06:22:13 2001/-ko/ +/ibmcam.c/1.13/Wed Jun 13 03:24:09 2001/-ko/ +/ibmcam.h/1.3/Fri Mar 3 01:42:02 2000/-ko/ +/inode.c/1.14/Thu Jul 5 06:13:42 2001/-ko/ +/mdc800.c/1.11/Thu Jul 5 06:13:42 2001/-ko/ +/microtek.c/1.9/Wed Jun 13 03:24:09 2001/-ko/ +/microtek.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/net1080.c/1.6/Wed Jun 13 03:24:09 2001/-ko/ +/ov511.c/1.23/Wed Jun 13 03:24:09 2001/-ko/ +/ov511.h/1.11/Mon Oct 23 18:56:35 2000/-ko/ +/pegasus.c/1.19/Thu Jun 28 05:21:16 2001/-ko/ +/pegasus.h/1.3/Thu Jun 28 05:21:16 2001/-ko/ +/plusb.c/1.12/Wed Jun 13 03:24:09 2001/-ko/ +/printer.c/1.36/Wed Jun 13 03:24:09 2001/-ko/ +/pwc-ctrl.c/1.2/Thu Jun 21 15:45:04 2001/-ko/ +/pwc-if.c/1.2/Thu Jun 21 15:45:04 2001/-ko/ +/pwc-ioctl.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/pwc-misc.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/pwc-uncompress.c/1.2/Thu Jun 21 15:45:04 2001/-ko/ +/pwc-uncompress.h/1.2/Thu Jun 21 15:45:04 2001/-ko/ +/pwc.h/1.2/Thu Jun 21 15:45:04 2001/-ko/ +/pwc_kiara.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/pwc_nala.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/pwc_timon.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/rio500.c/1.11/Wed Jun 13 03:24:09 2001/-ko/ +/rio500_usb.h/1.1/Fri Mar 3 01:42:02 2000/-ko/ +/scanner.c/1.20/Wed May 2 06:22:13 2001/-ko/ +/scanner.h/1.13/Tue May 29 19:53:13 2001/-ko/ +/se401.c/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/se401.h/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/uhci-debug.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/uhci.c/1.45/Thu Jul 5 06:13:42 2001/-ko/ +/uhci.h/1.23/Wed May 2 06:22:13 2001/-ko/ +/usb-debug.c/1.14/Thu Feb 22 21:09:04 2001/-ko/ +/usb-ohci.c/1.22/Thu Jun 28 05:21:16 2001/-ko/ +/usb-ohci.h/1.11/Wed Jun 13 03:24:09 2001/-ko/ +/usb-skeleton.c/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/usb-uhci-debug.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/usb-uhci.c/1.22/Thu Jun 28 05:21:16 2001/-ko/ +/usb-uhci.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/usb.c/1.51/Thu Jul 5 06:13:42 2001/-ko/ +/usbkbd.c/1.15/Wed Jun 13 03:24:09 2001/-ko/ +/usbmouse.c/1.12/Wed Jun 13 03:24:09 2001/-ko/ +/uss720.c/1.19/Wed Jun 13 03:24:09 2001/-ko/ +/wacom.c/1.13/Wed Jun 13 03:24:09 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/usb/CVS/Entries.Log linux-2.4-xfs/linux/drivers/usb/CVS/Entries.Log --- linux-2.4.7/linux/drivers/usb/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/usb/CVS/Entries.Log Thu Jul 5 12:01:33 2001 @@ -0,0 +1,2 @@ +A D/serial//// +A D/storage//// diff -rNu linux-2.4.7/linux/drivers/usb/CVS/Repository linux-2.4-xfs/linux/drivers/usb/CVS/Repository --- linux-2.4.7/linux/drivers/usb/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/usb/CVS/Repository Thu Jul 5 12:01:03 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/usb diff -rNu linux-2.4.7/linux/drivers/usb/CVS/Root linux-2.4-xfs/linux/drivers/usb/CVS/Root --- linux-2.4.7/linux/drivers/usb/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/usb/CVS/Root Thu Jul 5 12:01:03 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/usb/serial/CVS/Entries linux-2.4-xfs/linux/drivers/usb/serial/CVS/Entries --- linux-2.4.7/linux/drivers/usb/serial/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/usb/serial/CVS/Entries Thu Jul 5 12:01:33 2001 @@ -0,0 +1,48 @@ +/Config.in/1.5/Thu Jun 28 05:21:16 2001/-ko/ +/Makefile/1.14/Thu Jun 28 05:21:16 2001/-ko/ +/Makefile-keyspan_pda_fw/1.2/Fri Mar 24 21:32:44 2000/-ko/ +/belkin_sa.c/1.8/Thu Jun 21 15:45:04 2001/-ko/ +/belkin_sa.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/cyberjack.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/digi_acceleport.c/1.13/Wed Jun 13 03:24:09 2001/-ko/ +/empeg.c/1.7/Thu Jun 21 15:45:04 2001/-ko/ +/ezusb_convert.pl/1.3/Fri May 26 01:14:50 2000/-ko/ +/ftdi_sio.c/1.18/Thu Jun 21 15:45:04 2001/-ko/ +/ftdi_sio.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/io_16654.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/io_edgeport.c/1.5/Wed Jun 13 03:24:09 2001/-ko/ +/io_edgeport.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/io_fw_boot.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/io_fw_boot2.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/io_fw_down.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/io_fw_down2.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/io_ionsp.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/io_tables.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/io_usbvend.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/keyspan.c/1.11/Thu Jun 21 15:45:04 2001/-ko/ +/keyspan.h/1.4/Fri Jan 5 18:42:30 2001/-ko/ +/keyspan_pda.S/1.1/Fri Mar 24 21:32:44 2000/-ko/ +/keyspan_pda.c/1.15/Thu Jun 21 15:45:04 2001/-ko/ +/keyspan_pda_fw.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/keyspan_usa18x_fw.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/keyspan_usa19_fw.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/keyspan_usa19w_fw.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/keyspan_usa26msg.h/1.2/Sun Dec 17 19:15:00 2000/-ko/ +/keyspan_usa28_fw.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/keyspan_usa28msg.h/1.2/Sun Dec 17 19:15:00 2000/-ko/ +/keyspan_usa28x_fw.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/keyspan_usa49msg.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/keyspan_usa49w_fw.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/mct_u232.c/1.7/Thu Jun 21 15:45:04 2001/-ko/ +/mct_u232.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/omninet.c/1.14/Thu Jun 21 15:45:04 2001/-ko/ +/pl2303.c/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/pl2303.h/1.1/Thu Jun 21 15:45:04 2001/-ko/ +/usb-serial.h/1.13/Thu Jun 21 15:45:04 2001/-ko/ +/usbserial.c/1.17/Thu Jun 21 15:45:04 2001/-ko/ +/visor.c/1.18/Thu Jun 21 15:45:04 2001/-ko/ +/visor.h/1.4/Wed Jun 6 03:10:14 2001/-ko/ +/whiteheat.c/1.15/Thu Jun 21 15:45:04 2001/-ko/ +/whiteheat.h/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/whiteheat_fw.h/1.2/Wed Nov 1 21:35:42 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/usb/serial/CVS/Repository linux-2.4-xfs/linux/drivers/usb/serial/CVS/Repository --- linux-2.4.7/linux/drivers/usb/serial/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/usb/serial/CVS/Repository Thu Jul 5 12:01:19 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/usb/serial diff -rNu linux-2.4.7/linux/drivers/usb/serial/CVS/Root linux-2.4-xfs/linux/drivers/usb/serial/CVS/Root --- linux-2.4.7/linux/drivers/usb/serial/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/usb/serial/CVS/Root Thu Jul 5 12:01:19 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/usb/storage/CVS/Entries linux-2.4-xfs/linux/drivers/usb/storage/CVS/Entries --- linux-2.4.7/linux/drivers/usb/storage/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/usb/storage/CVS/Entries Thu Jul 5 12:01:36 2001 @@ -0,0 +1,23 @@ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/debug.c/1.4/Wed Jun 13 03:24:09 2001/-ko/ +/debug.h/1.5/Thu Feb 1 17:10:24 2001/-ko/ +/dpcm.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/dpcm.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/freecom.c/1.5/Thu Jul 5 06:13:42 2001/-ko/ +/freecom.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/initializers.c/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/initializers.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/protocol.c/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/protocol.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/scsiglue.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/scsiglue.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/sddr09.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/sddr09.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/shuttle_usbat.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/shuttle_usbat.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/transport.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/transport.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/unusual_devs.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/usb.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/usb.h/1.7/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/usb/storage/CVS/Repository linux-2.4-xfs/linux/drivers/usb/storage/CVS/Repository --- linux-2.4.7/linux/drivers/usb/storage/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/usb/storage/CVS/Repository Thu Jul 5 12:01:33 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/usb/storage diff -rNu linux-2.4.7/linux/drivers/usb/storage/CVS/Root linux-2.4-xfs/linux/drivers/usb/storage/CVS/Root --- linux-2.4.7/linux/drivers/usb/storage/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/usb/storage/CVS/Root Thu Jul 5 12:01:33 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/video/CVS/Entries linux-2.4-xfs/linux/drivers/video/CVS/Entries --- linux-2.4.7/linux/drivers/video/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/video/CVS/Entries Thu Jul 5 12:02:08 2001 @@ -0,0 +1,120 @@ +/Config.in/1.25/Wed May 2 06:22:13 2001/-ko/ +/Makefile/1.30/Wed May 2 06:22:13 2001/-ko/ +/S3triofb.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/acornfb.c/1.16/Wed May 2 06:22:13 2001/-ko/ +/acornfb.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/amifb.c/1.16/Wed May 2 06:22:13 2001/-ko/ +/atafb.c/1.11/Wed May 2 06:22:13 2001/-ko/ +/aty.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/aty128.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/aty128fb.c/1.21/Tue Jul 3 02:33:57 2001/-ko/ +/atyfb.c/1.30/Sat Jun 9 02:44:24 2001/-ko/ +/bwtwofb.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/cgfourteenfb.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/cgsixfb.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/cgthreefb.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/chipsfb.c/1.14/Tue May 29 19:53:13 2001/-ko/ +/clgenfb.c/1.18/Mon Apr 2 17:13:32 2001/-ko/ +/clgenfb.h/1.4/Thu Jan 6 21:20:23 2000/-ko/ +/controlfb.c/1.13/Thu Feb 22 21:09:04 2001/-ko/ +/controlfb.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/creatorfb.c/1.9/Wed Jun 13 03:24:09 2001/-ko/ +/cvisionppc.h/1.3/Sat Jan 29 23:15:44 2000/-ko/ +/cyber2000fb.c/1.22/Thu Jul 5 05:29:17 2001/-ko/ +/cyber2000fb.h/1.11/Mon Oct 23 18:56:35 2000/-ko/ +/cyberfb.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/cyberfb.h/1.3/Sun Aug 29 02:28:51 1999/-ko/ +/dcfb.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/dn_accel.h/1.1/Tue Feb 1 23:02:54 2000/-ko/ +/dn_cfb4.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/dn_cfb8.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/dnfb.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/dummycon.c/1.8/Sun Dec 17 19:15:00 2000/-ko/ +/epson1355fb.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/fbcmap.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/fbcon-afb.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon-cfb16.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon-cfb2.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon-cfb24.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon-cfb32.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon-cfb4.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon-cfb8.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon-hga.c/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon-ilbm.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon-iplan2p2.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon-iplan2p4.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon-iplan2p8.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon-mac.c/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon-mfb.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon-sti.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/fbcon-vga-planes.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon-vga.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/fbcon.c/1.19/Thu Jul 5 05:29:17 2001/-ko/ +/fbgen.c/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/fbmem.c/1.36/Wed May 2 06:22:13 2001/-ko/ +/fbmon.c/1.2/Sat Mar 11 02:39:30 2000/-ko/ +/fm2fb.c/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/font_6x11.c/1.3/Sun Aug 29 03:09:59 1999/-ko/ +/font_8x16.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/font_8x8.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/font_acorn_8x8.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/font_pearl_8x8.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/font_sun12x22.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/font_sun8x16.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fonts.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/g364fb.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/hgafb.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/hitfb.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/hpfb.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/iga.h/1.3/Wed Dec 29 19:17:52 1999/-ko/ +/igafb.c/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/imsttfb.c/1.14/Thu Jul 5 05:29:17 2001/-ko/ +/leofb.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/macfb.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/macmodes.c/1.9/Thu Jun 28 05:21:16 2001/-ko/ +/maxinefb.c/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/maxinefb.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/mdacon.c/1.9/Thu Jun 28 05:21:16 2001/-ko/ +/modedb.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/newport_con.c/1.7/Wed Nov 1 21:35:42 2000/-ko/ +/offb.c/1.16/Thu Feb 22 21:09:04 2001/-ko/ +/p9100.h/1.2/Wed Dec 29 19:17:52 1999/-ko/ +/p9100fb.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/platinumfb.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/platinumfb.h/1.3/Sat Jan 29 23:15:44 2000/-ko/ +/pm2fb.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/pm2fb.h/1.4/Sat Jan 29 23:15:44 2000/-ko/ +/pmag-ba-fb.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/pmag-ba-fb.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/pmagb-b-fb.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/pmagb-b-fb.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/prom.uni/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/promcon.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/q40fb.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/retz3fb.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/retz3fb.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sa1100fb.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/sbusfb.c/1.17/Wed May 2 06:22:13 2001/-ko/ +/sgivwfb.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/sgivwfb.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/skeletonfb.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/sti-bmode.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/sti.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/sticon-bmode.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/sticon.c/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/sticore.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/stifb.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/sun3fb.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/tcxfb.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/tdfxfb.c/1.10/Thu Jul 5 05:29:17 2001/-ko/ +/tgafb.c/1.14/Thu Jul 5 06:13:42 2001/-ko/ +/tgafb.h/1.3/Tue May 2 21:36:51 2000/-ko/ +/valkyriefb.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/valkyriefb.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/vesafb.c/1.14/Wed May 2 06:22:13 2001/-ko/ +/vfb.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/vga.h/1.4/Fri May 26 01:14:50 2000/-ko/ +/vga16fb.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/vgacon.c/1.15/Thu Feb 22 21:09:04 2001/-ko/ +/virgefb.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/video/CVS/Entries.Log linux-2.4-xfs/linux/drivers/video/CVS/Entries.Log --- linux-2.4.7/linux/drivers/video/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/video/CVS/Entries.Log Thu Jul 5 12:02:18 2001 @@ -0,0 +1,3 @@ +A D/matrox//// +A D/riva//// +A D/sis//// diff -rNu linux-2.4.7/linux/drivers/video/CVS/Repository linux-2.4-xfs/linux/drivers/video/CVS/Repository --- linux-2.4.7/linux/drivers/video/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/video/CVS/Repository Thu Jul 5 12:01:36 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/video diff -rNu linux-2.4.7/linux/drivers/video/CVS/Root linux-2.4-xfs/linux/drivers/video/CVS/Root --- linux-2.4.7/linux/drivers/video/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/video/CVS/Root Thu Jul 5 12:01:36 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/video/matrox/CVS/Entries linux-2.4-xfs/linux/drivers/video/matrox/CVS/Entries --- linux-2.4.7/linux/drivers/video/matrox/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/video/matrox/CVS/Entries Thu Jul 5 12:02:13 2001 @@ -0,0 +1,19 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/i2c-matroxfb.c/1.2/Sat Mar 11 02:39:30 2000/-ko/ +/matroxfb_DAC1064.c/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/matroxfb_DAC1064.h/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/matroxfb_Ti3026.c/1.4/Thu Jun 28 05:21:16 2001/-ko/ +/matroxfb_Ti3026.h/1.1/Sun Feb 27 22:37:25 2000/-ko/ +/matroxfb_accel.c/1.4/Thu Jun 28 05:21:16 2001/-ko/ +/matroxfb_accel.h/1.1/Sun Feb 27 22:37:25 2000/-ko/ +/matroxfb_base.c/1.10/Thu Jun 28 05:21:16 2001/-ko/ +/matroxfb_base.h/1.6/Thu Jun 28 05:21:16 2001/-ko/ +/matroxfb_crtc2.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/matroxfb_crtc2.h/1.1/Sun Feb 27 22:37:25 2000/-ko/ +/matroxfb_g450.c/1.2/Thu Jun 28 05:21:16 2001/-ko/ +/matroxfb_g450.h/1.1/Thu Dec 21 05:48:12 2000/-ko/ +/matroxfb_maven.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/matroxfb_maven.h/1.2/Sat Mar 11 02:39:30 2000/-ko/ +/matroxfb_misc.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/matroxfb_misc.h/1.1/Sun Feb 27 22:37:25 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/video/matrox/CVS/Repository linux-2.4-xfs/linux/drivers/video/matrox/CVS/Repository --- linux-2.4.7/linux/drivers/video/matrox/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/video/matrox/CVS/Repository Thu Jul 5 12:02:08 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/video/matrox diff -rNu linux-2.4.7/linux/drivers/video/matrox/CVS/Root linux-2.4-xfs/linux/drivers/video/matrox/CVS/Root --- linux-2.4.7/linux/drivers/video/matrox/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/video/matrox/CVS/Root Thu Jul 5 12:02:08 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/video/riva/CVS/Entries linux-2.4-xfs/linux/drivers/video/riva/CVS/Entries --- linux-2.4.7/linux/drivers/video/riva/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/video/riva/CVS/Entries Thu Jul 5 12:02:18 2001 @@ -0,0 +1,10 @@ +/Makefile/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/accel.c/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/fbdev.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/nv4ref.h/1.1/Fri Mar 3 01:42:02 2000/-ko/ +/nvreg.h/1.1/Fri Mar 3 01:42:02 2000/-ko/ +/riva_hw.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/riva_hw.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/riva_tbl.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/rivafb.h/1.2/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/video/riva/CVS/Repository linux-2.4-xfs/linux/drivers/video/riva/CVS/Repository --- linux-2.4.7/linux/drivers/video/riva/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/video/riva/CVS/Repository Thu Jul 5 12:02:13 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/video/riva diff -rNu linux-2.4.7/linux/drivers/video/riva/CVS/Root linux-2.4-xfs/linux/drivers/video/riva/CVS/Root --- linux-2.4.7/linux/drivers/video/riva/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/video/riva/CVS/Root Thu Jul 5 12:02:13 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/video/sis/CVS/Entries linux-2.4-xfs/linux/drivers/video/sis/CVS/Entries --- linux-2.4.7/linux/drivers/video/sis/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/video/sis/CVS/Entries Thu Jul 5 12:02:20 2001 @@ -0,0 +1,9 @@ +/Makefile/1.2/Thu Dec 21 05:48:12 2000/-ko/ +/initdef.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/sis.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/sis_300.c/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/sis_300.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/sis_301.c/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/sis_301.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/sis_main.c/1.3/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/video/sis/CVS/Repository linux-2.4-xfs/linux/drivers/video/sis/CVS/Repository --- linux-2.4.7/linux/drivers/video/sis/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/video/sis/CVS/Repository Thu Jul 5 12:02:18 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/video/sis diff -rNu linux-2.4.7/linux/drivers/video/sis/CVS/Root linux-2.4-xfs/linux/drivers/video/sis/CVS/Root --- linux-2.4.7/linux/drivers/video/sis/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/video/sis/CVS/Root Thu Jul 5 12:02:18 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/drivers/zorro/CVS/Entries linux-2.4-xfs/linux/drivers/zorro/CVS/Entries --- linux-2.4.7/linux/drivers/zorro/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/zorro/CVS/Entries Thu Jul 5 12:02:20 2001 @@ -0,0 +1,8 @@ +/Config.in/1.1/Wed Nov 1 21:35:42 2000/-ko/ +/Makefile/1.6/Wed Jan 3 01:43:05 2001/-ko/ +/gen-devlist.c/1.1/Wed Nov 1 21:35:42 2000/-ko/ +/names.c/1.2/Wed Nov 1 21:35:42 2000/-ko/ +/proc.c/1.11/Wed Mar 8 01:44:14 2000/-ko/ +/zorro.c/1.7/Wed Nov 1 21:35:42 2000/-ko/ +/zorro.ids/1.1/Wed Nov 1 21:35:42 2000/-ko/ +D diff -rNu linux-2.4.7/linux/drivers/zorro/CVS/Repository linux-2.4-xfs/linux/drivers/zorro/CVS/Repository --- linux-2.4.7/linux/drivers/zorro/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/zorro/CVS/Repository Thu Jul 5 12:02:20 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/drivers/zorro diff -rNu linux-2.4.7/linux/drivers/zorro/CVS/Root linux-2.4-xfs/linux/drivers/zorro/CVS/Root --- linux-2.4.7/linux/drivers/zorro/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/drivers/zorro/CVS/Root Thu Jul 5 12:02:20 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/CVS/Entries linux-2.4-xfs/linux/fs/CVS/Entries --- linux-2.4.7/linux/fs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/CVS/Entries Thu Jul 5 12:02:27 2001 @@ -0,0 +1,40 @@ +/ChangeLog/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Config.in/1.64/Tue Jul 3 02:33:57 2001/-ko/ +/Makefile/1.32/Thu May 31 07:08:46 2001/-ko/ +/attr.c/1.9/Wed Nov 1 21:35:42 2000/-ko/ +/bad_inode.c/1.9/Tue May 2 21:36:51 2000/-ko/ +/binfmt_aout.c/1.20/Mon Apr 2 17:13:32 2001/-ko/ +/binfmt_elf.c/1.28/Tue Jul 3 02:33:57 2001/-ko/ +/binfmt_em86.c/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/binfmt_misc.c/1.15/Thu Feb 22 21:09:04 2001/-ko/ +/binfmt_script.c/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/block_dev.c/1.22/Sat Jun 9 02:44:24 2001/-ko/ +/buffer.c/1.70/Tue Jul 3 02:33:57 2001/-ko/ +/char_dev.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/dcache.c/1.25/Sat Jun 9 02:44:24 2001/-ko/ +/devices.c/1.14/Tue May 29 19:53:13 2001/-ko/ +/dnotify.c/1.2/Sat Nov 25 08:05:45 2000/-ko/ +/dquot.c/1.27/Wed Jun 13 03:24:09 2001/-ko/ +/exec.c/1.41/Wed May 2 06:22:13 2001/-ko/ +/ext_attr.c/1.4/Fri May 4 06:06:47 2001/-ko/ +/fcntl.c/1.15/Tue May 29 19:53:13 2001/-ko/ +/fifo.c/1.14/Thu Feb 22 21:09:04 2001/-ko/ +/file.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/file_table.c/1.14/Wed May 2 06:22:13 2001/-ko/ +/filesystems.c/1.18/Wed May 2 06:22:13 2001/-ko/ +/inode.c/1.44/Tue Jun 19 01:55:19 2001/-ko/ +/iobuf.c/1.20/Wed May 9 20:54:27 2001/-ko/ +/ioctl.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/locks.c/1.17/Thu Jul 5 06:13:42 2001/-ko/ +/namei.c/1.32/Thu Jul 5 03:57:00 2001/-ko/ +/noposix_acl.c/1.1/Tue Jan 23 07:11:51 2001/-ko/ +/noquot.c/1.6/Fri Nov 3 03:19:17 2000/-ko/ +/open.c/1.28/Thu Feb 22 21:09:04 2001/-ko/ +/pipe.c/1.21/Thu Feb 22 21:09:04 2001/-ko/ +/posix_acl.c/1.5/Fri May 4 05:27:54 2001/-ko/ +/read_write.c/1.13/Thu Feb 22 21:09:04 2001/-ko/ +/readdir.c/1.9/Sun Dec 17 19:15:00 2000/-ko/ +/select.c/1.16/Thu Jun 28 05:21:16 2001/-ko/ +/stat.c/1.20/Wed May 2 06:22:13 2001/-ko/ +/super.c/1.49/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/CVS/Entries.Log linux-2.4-xfs/linux/fs/CVS/Entries.Log --- linux-2.4.7/linux/fs/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/CVS/Entries.Log Thu Jul 5 12:04:30 2001 @@ -0,0 +1,41 @@ +A D/adfs//// +A D/affs//// +A D/autofs//// +A D/autofs4//// +A D/bfs//// +A D/coda//// +A D/cramfs//// +A D/devfs//// +A D/devpts//// +A D/efs//// +A D/ext2//// +A D/fat//// +A D/freevxfs//// +A D/hfs//// +A D/hpfs//// +A D/isofs//// +A D/jffs//// +A D/lockd//// +A D/minix//// +A D/msdos//// +A D/ncpfs//// +A D/nfs//// +A D/nfsd//// +A D/nls//// +A D/ntfs//// +A D/openpromfs//// +A D/pagebuf//// +A D/partitions//// +A D/proc//// +A D/qnx4//// +A D/ramfs//// +A D/reiserfs//// +A D/romfs//// +A D/smbfs//// +A D/sysv//// +A D/udf//// +A D/ufs//// +A D/umsdos//// +A D/vfat//// +A D/xfs//// +A D/xfs_support//// diff -rNu linux-2.4.7/linux/fs/CVS/Repository linux-2.4-xfs/linux/fs/CVS/Repository --- linux-2.4.7/linux/fs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/CVS/Repository Thu Jul 5 12:02:20 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs diff -rNu linux-2.4.7/linux/fs/CVS/Root linux-2.4-xfs/linux/fs/CVS/Root --- linux-2.4.7/linux/fs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/CVS/Root Thu Jul 5 12:02:20 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/Config.in linux-2.4-xfs/linux/fs/Config.in --- linux-2.4.7/linux/fs/Config.in Mon Jul 2 16:03:04 2001 +++ linux-2.4-xfs/linux/fs/Config.in Mon Jul 2 21:33:57 2001 @@ -5,6 +5,7 @@ comment 'File systems' bool 'Quota support' CONFIG_QUOTA +bool 'POSIX Access Control List support' CONFIG_FS_POSIX_ACL tristate 'Kernel automounter support' CONFIG_AUTOFS_FS tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS @@ -71,6 +72,20 @@ tristate 'UFS file system support (read only)' CONFIG_UFS_FS dep_mbool ' UFS file system write support (DANGEROUS)' CONFIG_UFS_FS_WRITE $CONFIG_UFS_FS $CONFIG_EXPERIMENTAL + +tristate 'Page Buffer support' CONFIG_PAGE_BUF + +if [ "$CONFIG_PAGE_BUF" = "n" ]; then + comment ' Page Buffer support needed for XFS filesystem' +else + dep_tristate 'SGI XFS filesystem support' CONFIG_XFS_FS $CONFIG_PAGE_BUF + dep_mbool ' Enable XFS Realtime support' CONFIG_XFS_RT $CONFIG_XFS_FS + if [ "$CONFIG_XFS_FS" != "n" ]; then + define_bool CONFIG_HAVE_ATTRCTL y + dep_mbool ' Enable XFS DMAPI' CONFIG_XFS_DMAPI $CONFIG_XFS_FS + dep_mbool ' Enable XFS Quota' CONFIG_XFS_QUOTA $CONFIG_XFS_FS $CONFIG_QUOTA + fi +fi if [ "$CONFIG_NET" = "y" ]; then diff -rNu linux-2.4.7/linux/fs/Makefile linux-2.4-xfs/linux/fs/Makefile --- linux-2.4.7/linux/fs/Makefile Tue May 22 11:35:42 2001 +++ linux-2.4-xfs/linux/fs/Makefile Thu May 31 02:08:46 2001 @@ -63,6 +63,32 @@ subdir-$(CONFIG_DEVPTS_FS) += devpts subdir-$(CONFIG_SUN_OPENPROMFS) += openpromfs +subdir-$(CONFIG_PAGE_BUF) += pagebuf +subdir-$(CONFIG_XFS_FS) += xfs +mod-subdirs += xfs +# xfs_support is used by xfs and a couple of other SGI components. Because CML1 +# does not correctly handle inter-menu dependencies, set CONFIG_XFS_SUPPORT +# here. CML2 is not a problem, thank goodness. The support code can be linked +# into vmlinux even if xfs is not selected or is a module so xfs_support needs +# to be exposed at this level. Keith Owens. +ifneq ($(findstring y,$(CONFIG_XFS_FS) $(CONFIG_XSCSI) $(CONFIG_XVM)),) + CONFIG_XFS_SUPPORT := y +else + ifneq ($(findstring m,$(CONFIG_XFS_FS) $(CONFIG_XSCSI) $(CONFIG_XVM)),) + CONFIG_XFS_SUPPORT := m + else + CONFIG_XFS_SUPPORT := + endif +endif +subdir-$(CONFIG_XFS_SUPPORT) += xfs_support +CFLAGS_ext_attr.o += -I xfs +obj-y += ext_attr.o +ifeq ($(CONFIG_FS_POSIX_ACL),y) + obj-y += posix_acl.o +else + CFLAGS_noposix_acl.o += -I xfs + obj-y += noposix_acl.o +endif obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o obj-$(CONFIG_BINFMT_EM86) += binfmt_em86.o diff -rNu linux-2.4.7/linux/fs/adfs/CVS/Entries linux-2.4-xfs/linux/fs/adfs/CVS/Entries --- linux-2.4.7/linux/fs/adfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/adfs/CVS/Entries Thu Jul 5 12:02:28 2001 @@ -0,0 +1,12 @@ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/adfs.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/dir.c/1.13/Mon Oct 23 18:56:35 2000/-ko/ +/dir_f.c/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/dir_f.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/dir_fplus.c/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/dir_fplus.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/file.c/1.10/Mon Oct 23 18:56:35 2000/-ko/ +/inode.c/1.15/Wed Jan 3 01:43:05 2001/-ko/ +/map.c/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/super.c/1.11/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/adfs/CVS/Repository linux-2.4-xfs/linux/fs/adfs/CVS/Repository --- linux-2.4.7/linux/fs/adfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/adfs/CVS/Repository Thu Jul 5 12:02:27 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/adfs diff -rNu linux-2.4.7/linux/fs/adfs/CVS/Root linux-2.4-xfs/linux/fs/adfs/CVS/Root --- linux-2.4.7/linux/fs/adfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/adfs/CVS/Root Thu Jul 5 12:02:27 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/affs/CVS/Entries linux-2.4-xfs/linux/fs/affs/CVS/Entries --- linux-2.4.7/linux/fs/affs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/affs/CVS/Entries Thu Jul 5 12:02:29 2001 @@ -0,0 +1,11 @@ +/Changes/1.4/Wed May 2 06:22:13 2001/-ko/ +/Makefile/1.4/Wed May 2 06:22:13 2001/-ko/ +/amigaffs.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/bitmap.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/dir.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/file.c/1.16/Mon Jul 2 15:59:04 2001/-ko/ +/inode.c/1.12/Wed May 2 06:22:13 2001/-ko/ +/namei.c/1.11/Wed May 2 06:22:13 2001/-ko/ +/super.c/1.10/Wed May 2 06:22:13 2001/-ko/ +/symlink.c/1.12/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/affs/CVS/Repository linux-2.4-xfs/linux/fs/affs/CVS/Repository --- linux-2.4.7/linux/fs/affs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/affs/CVS/Repository Thu Jul 5 12:02:28 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/affs diff -rNu linux-2.4.7/linux/fs/affs/CVS/Root linux-2.4-xfs/linux/fs/affs/CVS/Root --- linux-2.4.7/linux/fs/affs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/affs/CVS/Root Thu Jul 5 12:02:28 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/autofs/CVS/Entries linux-2.4-xfs/linux/fs/autofs/CVS/Entries --- linux-2.4.7/linux/fs/autofs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/autofs/CVS/Entries Thu Jul 5 12:02:30 2001 @@ -0,0 +1,10 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/autofs_i.h/1.7/Thu Jun 21 15:45:04 2001/-ko/ +/dir.c/1.8/Fri May 26 01:52:46 2000/-ko/ +/dirhash.c/1.6/Fri May 26 01:52:46 2000/-ko/ +/init.c/1.6/Sat Mar 11 02:39:30 2000/-ko/ +/inode.c/1.9/Thu Jun 21 15:45:04 2001/-ko/ +/root.c/1.14/Thu Sep 28 22:42:39 2000/-ko/ +/symlink.c/1.6/Fri Apr 21 16:16:46 2000/-ko/ +/waitq.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/autofs/CVS/Repository linux-2.4-xfs/linux/fs/autofs/CVS/Repository --- linux-2.4.7/linux/fs/autofs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/autofs/CVS/Repository Thu Jul 5 12:02:29 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/autofs diff -rNu linux-2.4.7/linux/fs/autofs/CVS/Root linux-2.4-xfs/linux/fs/autofs/CVS/Root --- linux-2.4.7/linux/fs/autofs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/autofs/CVS/Root Thu Jul 5 12:02:29 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/autofs4/CVS/Entries linux-2.4-xfs/linux/fs/autofs4/CVS/Entries --- linux-2.4.7/linux/fs/autofs4/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/autofs4/CVS/Entries Thu Jul 5 12:02:31 2001 @@ -0,0 +1,9 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/autofs_i.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/expire.c/1.9/Sat Jun 9 02:44:24 2001/-ko/ +/init.c/1.3/Tue May 2 21:36:51 2000/-ko/ +/inode.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/root.c/1.10/Wed Nov 1 21:35:42 2000/-ko/ +/symlink.c/1.3/Tue May 2 21:36:51 2000/-ko/ +/waitq.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/autofs4/CVS/Repository linux-2.4-xfs/linux/fs/autofs4/CVS/Repository --- linux-2.4.7/linux/fs/autofs4/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/autofs4/CVS/Repository Thu Jul 5 12:02:30 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/autofs4 diff -rNu linux-2.4.7/linux/fs/autofs4/CVS/Root linux-2.4-xfs/linux/fs/autofs4/CVS/Root --- linux-2.4.7/linux/fs/autofs4/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/autofs4/CVS/Root Thu Jul 5 12:02:30 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/bfs/CVS/Entries linux-2.4-xfs/linux/fs/bfs/CVS/Entries --- linux-2.4.7/linux/fs/bfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/bfs/CVS/Entries Thu Jul 5 12:02:31 2001 @@ -0,0 +1,6 @@ +/Makefile/1.2/Thu Dec 21 05:48:12 2000/-ko/ +/bfs_defs.h/1.3/Fri Feb 11 00:45:14 2000/-ko/ +/dir.c/1.12/Sat Nov 25 08:05:45 2000/-ko/ +/file.c/1.14/Sun Dec 17 19:15:00 2000/-ko/ +/inode.c/1.14/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/bfs/CVS/Repository linux-2.4-xfs/linux/fs/bfs/CVS/Repository --- linux-2.4.7/linux/fs/bfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/bfs/CVS/Repository Thu Jul 5 12:02:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/bfs diff -rNu linux-2.4.7/linux/fs/bfs/CVS/Root linux-2.4-xfs/linux/fs/bfs/CVS/Root --- linux-2.4.7/linux/fs/bfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/bfs/CVS/Root Thu Jul 5 12:02:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/buffer.c linux-2.4-xfs/linux/fs/buffer.c --- linux-2.4.7/linux/fs/buffer.c Sat Jun 30 12:44:32 2001 +++ linux-2.4-xfs/linux/fs/buffer.c Mon Jul 2 21:33:57 2001 @@ -133,6 +133,45 @@ int bdflush_min[N_PARAM] = { 0, 10, 5, 25, 0, 1*HZ, 0, 0, 0}; int bdflush_max[N_PARAM] = {100,50000, 20000, 20000,600*HZ, 6000*HZ, 100, 0, 0}; + +#define buffer_delay_busy(bh) \ + (buffer_delay(bh) && bh->b_page && PageLocked(bh->b_page)) + +int +_write_buffer(struct buffer_head *bh, int wait) +{ + struct page *page = bh->b_page; + int ret = 0; + + if (!page) + BUG(); + if (wait) { + lock_page(page); + } else if (TryLockPage(page)) { + if (current->need_resched) + schedule(); + return 0; + } + + if (buffer_delay(bh)) { + ret = page->mapping->a_ops->writepage(page); + } else { + UnlockPage(page); + } + return ret; +} + +static inline int +write_buffer(struct buffer_head *bh, int wait) +{ + if (!buffer_delay(bh)) { + ll_rw_block(WRITE, 1, &bh); + return 1; + } else + return _write_buffer(bh, wait); +} + + /* * Rewrote the wait-routines to use the "new" wait-queue functionality, * and getting rid of the cli-sti pairs. The wait-queue routines still @@ -208,6 +247,14 @@ if (dev && bh->b_dev != dev) continue; + if (test_bit(BH_Delay, &bh->b_state)) { + spin_unlock(&lru_list_lock); + if (count) + write_locked_buffers(array, count); + _write_buffer(bh, 0); + goto repeat; + } + if (test_and_set_bit(BH_Lock, &bh->b_state)) continue; if (atomic_set_buffer_clean(bh)) { @@ -520,6 +567,8 @@ struct bh_free_head *head = &free_list[BUFSIZE_INDEX(bh->b_size)]; struct buffer_head **bhp = &head->list; + if (buffer_delay(bh)) + BUG(); bh->b_state = 0; spin_lock(&head->lock); @@ -881,7 +930,7 @@ if (buffer_dirty(bh)) { atomic_inc(&bh->b_count); spin_unlock(&lru_list_lock); - ll_rw_block(WRITE, 1, &bh); + write_buffer(bh, 1); brelse(bh); spin_lock(&lru_list_lock); } @@ -1362,6 +1411,7 @@ clear_bit(BH_Mapped, &bh->b_state); clear_bit(BH_Req, &bh->b_state); clear_bit(BH_New, &bh->b_state); + clear_bit(BH_Delay, &bh->b_state); unlock_buffer(bh); } } @@ -1418,7 +1468,7 @@ return 1; } -static void create_empty_buffers(struct page *page, kdev_t dev, unsigned long blocksize) +void create_empty_buffers(struct page *page, kdev_t dev, unsigned long blocksize) { struct buffer_head *bh, *head, *tail; @@ -2538,7 +2588,7 @@ __refile_buffer(bh); continue; } - if (buffer_locked(bh)) + if (buffer_locked(bh) || buffer_delay_busy(bh)) continue; if (check_flushtime) { @@ -2549,14 +2599,14 @@ if (time_before(jiffies, bh->b_flushtime)) goto out_unlock; } else { - if (++flushed > bdf_prm.b_un.ndirty) + if (flushed > bdf_prm.b_un.ndirty) goto out_unlock; } /* OK, now we are committed to write it out. */ atomic_inc(&bh->b_count); spin_unlock(&lru_list_lock); - ll_rw_block(WRITE, 1, &bh); + flushed += write_buffer(bh, 0); atomic_dec(&bh->b_count); if (current->need_resched) diff -rNu linux-2.4.7/linux/fs/coda/CVS/Entries linux-2.4-xfs/linux/fs/coda/CVS/Entries --- linux-2.4.7/linux/fs/coda/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/coda/CVS/Entries Thu Jul 5 12:02:32 2001 @@ -0,0 +1,13 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/cache.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/cnode.c/1.11/Wed May 2 06:22:13 2001/-ko/ +/coda_linux.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/dir.c/1.19/Wed May 2 06:22:13 2001/-ko/ +/file.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/inode.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/pioctl.c/1.9/Mon Oct 23 18:56:35 2000/-ko/ +/psdev.c/1.15/Wed May 2 06:22:13 2001/-ko/ +/symlink.c/1.12/Wed May 2 06:22:13 2001/-ko/ +/sysctl.c/1.12/Wed May 2 06:22:13 2001/-ko/ +/upcall.c/1.11/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/coda/CVS/Repository linux-2.4-xfs/linux/fs/coda/CVS/Repository --- linux-2.4.7/linux/fs/coda/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/coda/CVS/Repository Thu Jul 5 12:02:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/coda diff -rNu linux-2.4.7/linux/fs/coda/CVS/Root linux-2.4-xfs/linux/fs/coda/CVS/Root --- linux-2.4.7/linux/fs/coda/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/coda/CVS/Root Thu Jul 5 12:02:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/cramfs/CVS/Entries linux-2.4-xfs/linux/fs/cramfs/CVS/Entries --- linux-2.4.7/linux/fs/cramfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/cramfs/CVS/Entries Thu Jul 5 12:02:32 2001 @@ -0,0 +1,6 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/README/1.1/Fri Jan 21 19:20:14 2000/-ko/ +/cramfs.h/1.2/Fri Jan 21 19:20:14 2000/-ko/ +/inode.c/1.15/Wed May 2 06:22:13 2001/-ko/ +/uncompress.c/1.4/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/fs/cramfs/CVS/Entries.Log linux-2.4-xfs/linux/fs/cramfs/CVS/Entries.Log --- linux-2.4.7/linux/fs/cramfs/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/cramfs/CVS/Entries.Log Thu Jul 5 12:02:32 2001 @@ -0,0 +1 @@ +A D/inflate//// diff -rNu linux-2.4.7/linux/fs/cramfs/CVS/Repository linux-2.4-xfs/linux/fs/cramfs/CVS/Repository --- linux-2.4.7/linux/fs/cramfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/cramfs/CVS/Repository Thu Jul 5 12:02:32 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/cramfs diff -rNu linux-2.4.7/linux/fs/cramfs/CVS/Root linux-2.4-xfs/linux/fs/cramfs/CVS/Root --- linux-2.4.7/linux/fs/cramfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/cramfs/CVS/Root Thu Jul 5 12:02:32 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/cramfs/inflate/CVS/Entries linux-2.4-xfs/linux/fs/cramfs/inflate/CVS/Entries --- linux-2.4.7/linux/fs/cramfs/inflate/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/cramfs/inflate/CVS/Entries Thu Jul 5 12:02:33 2001 @@ -0,0 +1,19 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/adler32.c/1.2/Tue May 2 21:36:51 2000/-ko/ +/infblock.c/1.3/Tue May 2 21:36:51 2000/-ko/ +/infblock.h/1.2/Tue May 2 21:36:51 2000/-ko/ +/infcodes.c/1.3/Tue May 2 21:36:51 2000/-ko/ +/infcodes.h/1.2/Tue May 2 21:36:51 2000/-ko/ +/inffast.c/1.3/Tue May 2 21:36:51 2000/-ko/ +/inffast.h/1.2/Tue May 2 21:36:51 2000/-ko/ +/inffixed.h/1.1/Wed Dec 29 19:17:52 1999/-ko/ +/inflate.c/1.3/Tue May 2 21:36:51 2000/-ko/ +/inftrees.c/1.2/Tue May 2 21:36:51 2000/-ko/ +/inftrees.h/1.2/Tue May 2 21:36:51 2000/-ko/ +/infutil.c/1.2/Tue May 2 21:36:51 2000/-ko/ +/infutil.h/1.2/Tue May 2 21:36:51 2000/-ko/ +/uncompr.c/1.2/Tue May 2 21:36:51 2000/-ko/ +/zconf.h/1.2/Fri Feb 11 00:45:14 2000/-ko/ +/zlib.h/1.2/Tue May 2 21:36:51 2000/-ko/ +/zutil.h/1.2/Thu Jan 6 19:50:16 2000/-ko/ +D diff -rNu linux-2.4.7/linux/fs/cramfs/inflate/CVS/Repository linux-2.4-xfs/linux/fs/cramfs/inflate/CVS/Repository --- linux-2.4.7/linux/fs/cramfs/inflate/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/cramfs/inflate/CVS/Repository Thu Jul 5 12:02:32 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/cramfs/inflate diff -rNu linux-2.4.7/linux/fs/cramfs/inflate/CVS/Root linux-2.4-xfs/linux/fs/cramfs/inflate/CVS/Root --- linux-2.4.7/linux/fs/cramfs/inflate/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/cramfs/inflate/CVS/Root Thu Jul 5 12:02:32 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/devfs/CVS/Entries linux-2.4-xfs/linux/fs/devfs/CVS/Entries --- linux-2.4.7/linux/fs/devfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/devfs/CVS/Entries Thu Jul 5 12:02:34 2001 @@ -0,0 +1,4 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/base.c/1.17/Thu Jun 21 15:45:04 2001/-ko/ +/util.c/1.5/Wed Jun 13 03:24:09 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/devfs/CVS/Repository linux-2.4-xfs/linux/fs/devfs/CVS/Repository --- linux-2.4.7/linux/fs/devfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/devfs/CVS/Repository Thu Jul 5 12:02:33 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/devfs diff -rNu linux-2.4.7/linux/fs/devfs/CVS/Root linux-2.4-xfs/linux/fs/devfs/CVS/Root --- linux-2.4.7/linux/fs/devfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/devfs/CVS/Root Thu Jul 5 12:02:33 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/devpts/CVS/Entries linux-2.4-xfs/linux/fs/devpts/CVS/Entries --- linux-2.4.7/linux/fs/devpts/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/devpts/CVS/Entries Thu Jul 5 12:02:34 2001 @@ -0,0 +1,5 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/devpts_i.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/inode.c/1.10/Wed May 2 06:22:13 2001/-ko/ +/root.c/1.12/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/fs/devpts/CVS/Repository linux-2.4-xfs/linux/fs/devpts/CVS/Repository --- linux-2.4.7/linux/fs/devpts/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/devpts/CVS/Repository Thu Jul 5 12:02:34 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/devpts diff -rNu linux-2.4.7/linux/fs/devpts/CVS/Root linux-2.4-xfs/linux/fs/devpts/CVS/Root --- linux-2.4.7/linux/fs/devpts/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/devpts/CVS/Root Thu Jul 5 12:02:34 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/dquot.c linux-2.4-xfs/linux/fs/dquot.c --- linux-2.4.7/linux/fs/dquot.c Tue Jun 12 18:03:27 2001 +++ linux-2.4-xfs/linux/fs/dquot.c Tue Jun 12 22:24:09 2001 @@ -52,6 +52,7 @@ #include #include #include +#include #include @@ -1519,15 +1520,15 @@ if ((u_int) type >= MAXQUOTAS) goto out; - if (id & ~0xFFFF) - goto out; ret = -EPERM; switch (cmds) { case Q_SYNC: case Q_GETSTATS: + case Q_XGETQSTAT: break; case Q_GETQUOTA: + case Q_XGETQUOTA: if (((type == USRQUOTA && current->euid != id) || (type == GRPQUOTA && !in_egroup_p(id))) && !capable(CAP_SYS_RESOURCE)) @@ -1557,6 +1558,14 @@ goto out; sb = get_super(dev); } + + if (sb && sb->s_op && sb->s_op->quotactl) { + unlock_kernel(); + return sb->s_op->quotactl(sb, cmds, type, id, addr); + } + + if (id & ~0xFFFF) + goto out; ret = -EINVAL; switch (cmds) { diff -rNu linux-2.4.7/linux/fs/efs/CVS/Entries linux-2.4-xfs/linux/fs/efs/CVS/Entries --- linux-2.4.7/linux/fs/efs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/efs/CVS/Entries Thu Jul 5 12:02:34 2001 @@ -0,0 +1,8 @@ +/Makefile/1.2/Thu Dec 21 05:48:12 2000/-ko/ +/dir.c/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/file.c/1.6/Sun Feb 27 22:37:25 2000/-ko/ +/inode.c/1.7/Fri May 26 01:14:50 2000/-ko/ +/namei.c/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/super.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/symlink.c/1.9/Wed Jan 3 01:43:05 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/efs/CVS/Repository linux-2.4-xfs/linux/fs/efs/CVS/Repository --- linux-2.4.7/linux/fs/efs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/efs/CVS/Repository Thu Jul 5 12:02:34 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/efs diff -rNu linux-2.4.7/linux/fs/efs/CVS/Root linux-2.4-xfs/linux/fs/efs/CVS/Root --- linux-2.4.7/linux/fs/efs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/efs/CVS/Root Thu Jul 5 12:02:34 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/ext2/CVS/Entries linux-2.4-xfs/linux/fs/ext2/CVS/Entries --- linux-2.4.7/linux/fs/ext2/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ext2/CVS/Entries Thu Jul 5 12:02:35 2001 @@ -0,0 +1,15 @@ +/CHANGES/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/acl.c/1.5/Wed Dec 15 00:16:10 1999/-ko/ +/balloc.c/1.12/Wed Jan 3 01:43:05 2001/-ko/ +/bitmap.c/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/dir.c/1.15/Thu Jun 21 15:45:04 2001/-ko/ +/file.c/1.15/Mon Oct 23 18:56:35 2000/-ko/ +/fsync.c/1.10/Sun Dec 17 19:15:00 2000/-ko/ +/ialloc.c/1.16/Thu Jul 5 03:57:00 2001/-ko/ +/inode.c/1.27/Wed Jun 6 03:10:14 2001/-ko/ +/ioctl.c/1.8/Mon Oct 23 18:56:35 2000/-ko/ +/namei.c/1.20/Wed Jun 6 03:10:14 2001/-ko/ +/super.c/1.17/Tue May 29 19:53:13 2001/-ko/ +/symlink.c/1.9/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/fs/ext2/CVS/Repository linux-2.4-xfs/linux/fs/ext2/CVS/Repository --- linux-2.4.7/linux/fs/ext2/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ext2/CVS/Repository Thu Jul 5 12:02:34 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/ext2 diff -rNu linux-2.4.7/linux/fs/ext2/CVS/Root linux-2.4-xfs/linux/fs/ext2/CVS/Root --- linux-2.4.7/linux/fs/ext2/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ext2/CVS/Root Thu Jul 5 12:02:34 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/ext_attr.c linux-2.4-xfs/linux/fs/ext_attr.c --- linux-2.4.7/linux/fs/ext_attr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ext_attr.c Fri May 4 01:06:47 2001 @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Revalidate the inode. This is required for proper NFS attribute caching. + * Blatently copied wholesale from fs/stat.c + */ +static __inline__ int +do_revalidate(struct dentry *dentry) +{ + struct inode * inode = dentry->d_inode; + if (inode->i_op && inode->i_op->revalidate) + return inode->i_op->revalidate(dentry); + return 0; +} + + +asmlinkage long sys_attrctl(attr_obj_t obj, int type, attr_op_t *ops, int count) +{ + int error = 0; + struct inode *inode; + struct dentry *dentry; + struct file *f = NULL; + struct nameidata nd; + + if (count <= 0) + return -EINVAL; + + lock_kernel(); + + switch (type) { + case ATTR_TYPE_FD: + if (! (f = fget(obj.fd))) { + error = -ENOENT; + goto unlock; + } + dentry = f->f_dentry; + break; + + case ATTR_TYPE_PATH: + /* follow symlinks */ + error = user_path_walk(obj.path, &nd); + if (error) + goto unlock; + dentry = nd.dentry; + break; + + case ATTR_TYPE_LPATH: + error = user_path_walk_link(obj.path, &nd); + if (error) + goto unlock; + dentry = nd.dentry; + break; + + case ATTR_TYPE_PID: + error = -ENOSYS; + goto unlock; + + default: + error = -EINVAL; + goto unlock; + } + + inode = dentry->d_inode; + error = -EOPNOTSUPP; + + if ( inode->i_op + && inode->i_op->attrctl + && ! (error = do_revalidate(dentry))) + { + attr_op_t kop, *kops; + + if (count == 1) { + kops = &kop; + } + else { + kops = (attr_op_t *) kmalloc(count * sizeof(attr_op_t), + GFP_KERNEL); + if (! kops) { + error = -ENOMEM; + goto release; + } + } + + if (copy_from_user(kops, ops, count * sizeof(attr_op_t)) != 0) { + error = -EFAULT; + goto free_mem; + } + + error = inode->i_op->attrctl(inode, kops, count); + + if (copy_to_user(ops, kops, count * sizeof(attr_op_t)) != 0) { + error = -EFAULT; + goto free_mem; + } + + free_mem: + if (count > 1) + kfree(kops); + + } + + release: + (type == ATTR_TYPE_FD) ? fput(f) : path_release(&nd); + unlock: + unlock_kernel(); + return error; +} diff -rNu linux-2.4.7/linux/fs/fat/CVS/Entries linux-2.4-xfs/linux/fs/fat/CVS/Entries --- linux-2.4.7/linux/fs/fat/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/fat/CVS/Entries Thu Jul 5 12:02:36 2001 @@ -0,0 +1,13 @@ +/Makefile/1.5/Wed May 2 06:22:13 2001/-ko/ +/buffer.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/cache.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/cvf.c/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/dir.c/1.11/Wed May 2 06:22:13 2001/-ko/ +/fatfs_syms.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/file.c/1.13/Tue May 29 19:53:13 2001/-ko/ +/inode.c/1.23/Sat Jun 9 02:44:24 2001/-ko/ +/misc.c/1.8/Tue May 29 19:53:13 2001/-ko/ +/msbuffer.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/tables.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/tables.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/fs/fat/CVS/Repository linux-2.4-xfs/linux/fs/fat/CVS/Repository --- linux-2.4.7/linux/fs/fat/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/fat/CVS/Repository Thu Jul 5 12:02:35 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/fat diff -rNu linux-2.4.7/linux/fs/fat/CVS/Root linux-2.4-xfs/linux/fs/fat/CVS/Root --- linux-2.4.7/linux/fs/fat/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/fat/CVS/Root Thu Jul 5 12:02:35 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/freevxfs/CVS/Entries linux-2.4-xfs/linux/fs/freevxfs/CVS/Entries --- linux-2.4.7/linux/fs/freevxfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/freevxfs/CVS/Entries Thu Jul 5 12:02:37 2001 @@ -0,0 +1,16 @@ +/Makefile/1.1/Tue May 29 19:53:13 2001/-ko/ +/vxfs.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/vxfs_bmap.c/1.2/Thu Jun 28 05:21:16 2001/-ko/ +/vxfs_dir.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/vxfs_extern.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/vxfs_fshead.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/vxfs_fshead.h/1.2/Thu Jun 28 05:21:16 2001/-ko/ +/vxfs_immed.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/vxfs_inode.c/1.3/Fri Jun 29 22:21:45 2001/-ko/ +/vxfs_inode.h/1.2/Thu Jun 28 05:21:16 2001/-ko/ +/vxfs_lookup.c/1.2/Thu Jun 28 05:21:16 2001/-ko/ +/vxfs_olt.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/vxfs_olt.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/vxfs_subr.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/vxfs_super.c/1.2/Thu Jun 28 05:21:16 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/freevxfs/CVS/Repository linux-2.4-xfs/linux/fs/freevxfs/CVS/Repository --- linux-2.4.7/linux/fs/freevxfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/freevxfs/CVS/Repository Thu Jul 5 12:02:36 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/freevxfs diff -rNu linux-2.4.7/linux/fs/freevxfs/CVS/Root linux-2.4-xfs/linux/fs/freevxfs/CVS/Root --- linux-2.4.7/linux/fs/freevxfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/freevxfs/CVS/Root Thu Jul 5 12:02:36 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/hfs/CVS/Entries linux-2.4-xfs/linux/fs/hfs/CVS/Entries --- linux-2.4.7/linux/fs/hfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/hfs/CVS/Entries Thu Jul 5 12:02:41 2001 @@ -0,0 +1,37 @@ +/COPYING/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ChangeLog/1.3/Fri Jan 21 19:20:14 2000/-ko/ +/FAQ.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/HFS.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/INSTALL.txt/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/TODO/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/balloc.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/bdelete.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/bfind.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/bins_del.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/binsert.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/bitmap.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/bitops.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/bnode.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/brec.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/btree.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/catalog.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/dir.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/dir_cap.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/dir_dbl.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/dir_nat.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/extent.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/file.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/file_cap.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/file_hdr.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/hfs.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/hfs_btree.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/inode.c/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/mdb.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/part_tbl.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/string.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/super.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/sysdep.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/trans.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/version.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/hfs/CVS/Repository linux-2.4-xfs/linux/fs/hfs/CVS/Repository --- linux-2.4.7/linux/fs/hfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/hfs/CVS/Repository Thu Jul 5 12:02:37 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/hfs diff -rNu linux-2.4.7/linux/fs/hfs/CVS/Root linux-2.4-xfs/linux/fs/hfs/CVS/Root --- linux-2.4.7/linux/fs/hfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/hfs/CVS/Root Thu Jul 5 12:02:37 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/hpfs/CVS/Entries linux-2.4-xfs/linux/fs/hpfs/CVS/Entries --- linux-2.4.7/linux/fs/hpfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/hpfs/CVS/Entries Thu Jul 5 12:02:43 2001 @@ -0,0 +1,17 @@ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/alloc.c/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/anode.c/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/buffer.c/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/dentry.c/1.2/Wed Mar 8 01:44:14 2000/-ko/ +/dir.c/1.8/Sat Jun 9 02:44:24 2001/-ko/ +/dnode.c/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/ea.c/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/file.c/1.13/Wed Jan 3 01:43:05 2001/-ko/ +/hpfs.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/hpfs_fn.h/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/inode.c/1.12/Thu Feb 1 17:10:24 2001/-ko/ +/map.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/name.c/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/namei.c/1.12/Wed Jan 3 01:43:05 2001/-ko/ +/super.c/1.9/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/hpfs/CVS/Repository linux-2.4-xfs/linux/fs/hpfs/CVS/Repository --- linux-2.4.7/linux/fs/hpfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/hpfs/CVS/Repository Thu Jul 5 12:02:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/hpfs diff -rNu linux-2.4.7/linux/fs/hpfs/CVS/Root linux-2.4-xfs/linux/fs/hpfs/CVS/Root --- linux-2.4.7/linux/fs/hpfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/hpfs/CVS/Root Thu Jul 5 12:02:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/inode.c linux-2.4-xfs/linux/fs/inode.c --- linux-2.4.7/linux/fs/inode.c Tue Jun 12 13:02:44 2001 +++ linux-2.4-xfs/linux/fs/inode.c Mon Jun 18 20:55:19 2001 @@ -797,6 +797,46 @@ return inode; } +static inline void _unlock_new_inode(struct inode *inode) +{ + /* + * This is special! We do not need the spinlock + * when clearing I_LOCK, because we're guaranteed + * that nobody else tries to do anything about the + * state of the inode when it is locked, as we + * just created it (so there can be no old holders + * that haven't tested I_LOCK). + */ + inode->i_state &= ~(I_LOCK|I_NEW); + wake_up(&inode->i_wait); +} + + +/* + * Broken out of create_new_inode for clarity, Calls the read_inode + * function, unlocks the populated inode, and wakes up anyone + * waiting for it to be available. + */ + +static inline void populate_inode( + struct super_block *sb, + struct inode * inode, + void *opaque) +{ + /* reiserfs specific hack right here. We don't + ** want this to last, and are looking for VFS changes + ** that will allow us to get rid of it. + ** -- mason@suse.com + */ + if (sb->s_op->read_inode2) { + sb->s_op->read_inode2(inode, opaque) ; + } else { + sb->s_op->read_inode(inode); + } + + _unlock_new_inode(inode); +} + /* * This is called without the inode lock held.. Be careful. * @@ -823,33 +863,14 @@ inode->i_ino = ino; inode->i_flags = 0; atomic_set(&inode->i_count, 1); - inode->i_state = I_LOCK; + inode->i_state = I_LOCK|I_NEW; spin_unlock(&inode_lock); clean_inode(inode); - /* reiserfs specific hack right here. We don't - ** want this to last, and are looking for VFS changes - ** that will allow us to get rid of it. - ** -- mason@suse.com - */ - if (sb->s_op->read_inode2) { - sb->s_op->read_inode2(inode, opaque) ; - } else { - sb->s_op->read_inode(inode); - } - - /* - * This is special! We do not need the spinlock - * when clearing I_LOCK, because we're guaranteed - * that nobody else tries to do anything about the - * state of the inode when it is locked, as we - * just created it (so there can be no old holders - * that haven't tested I_LOCK). + /* Return the locked inode with I_NEW set, the + * caller is responsible for filling in the contents */ - inode->i_state &= ~I_LOCK; - wake_up(&inode->i_wait); - return inode; } @@ -931,6 +952,34 @@ return inode; } +/* + * This is iget4 without the read_inode portion of get_new_inode + * the filesystem gets back a new locked and hashed inode and gets + * to fill it in before unlocking it via unlock_new_inode(). + */ +struct inode *icreate4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque) +{ + struct list_head * head = inode_hashtable + hash(sb,ino); + struct inode * inode; + + spin_lock(&inode_lock); + inode = find_inode(sb, ino, head, find_actor, opaque); + if (inode) { + __iget(inode); + spin_unlock(&inode_lock); + wait_on_inode(inode); + return inode; + } + spin_unlock(&inode_lock); + + return get_new_inode(sb, ino, head, find_actor, opaque); +} + +void unlock_new_inode(struct inode *inode) +{ + _unlock_new_inode(inode); +} + struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque) { @@ -951,7 +1000,11 @@ * get_new_inode() will do the right thing, re-trying the search * in case it had to block at any point. */ - return get_new_inode(sb, ino, head, find_actor, opaque); + inode = get_new_inode(sb, ino, head, find_actor, opaque); + if (inode && (inode->i_state & I_NEW)) + populate_inode(sb, inode, opaque); + + return inode; } /** diff -rNu linux-2.4.7/linux/fs/isofs/CVS/Entries linux-2.4-xfs/linux/fs/isofs/CVS/Entries --- linux-2.4.7/linux/fs/isofs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/isofs/CVS/Entries Thu Jul 5 12:02:44 2001 @@ -0,0 +1,9 @@ +/Makefile/1.5/Thu Dec 21 05:48:12 2000/-ko/ +/dir.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/inode.c/1.23/Wed May 2 06:22:13 2001/-ko/ +/joliet.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/namei.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/rock.c/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/rock.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/util.c/1.5/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/isofs/CVS/Repository linux-2.4-xfs/linux/fs/isofs/CVS/Repository --- linux-2.4.7/linux/fs/isofs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/isofs/CVS/Repository Thu Jul 5 12:02:43 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/isofs diff -rNu linux-2.4.7/linux/fs/isofs/CVS/Root linux-2.4-xfs/linux/fs/isofs/CVS/Root --- linux-2.4.7/linux/fs/isofs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/isofs/CVS/Root Thu Jul 5 12:02:43 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/jffs/CVS/Entries linux-2.4-xfs/linux/fs/jffs/CVS/Entries --- linux-2.4.7/linux/fs/jffs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/jffs/CVS/Entries Thu Jul 5 12:02:47 2001 @@ -0,0 +1,7 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/inode-v23.c/1.8/Thu Jun 28 05:21:16 2001/-ko/ +/intrep.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/intrep.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/jffs_fm.c/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/jffs_fm.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/fs/jffs/CVS/Repository linux-2.4-xfs/linux/fs/jffs/CVS/Repository --- linux-2.4.7/linux/fs/jffs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/jffs/CVS/Repository Thu Jul 5 12:02:44 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/jffs diff -rNu linux-2.4.7/linux/fs/jffs/CVS/Root linux-2.4-xfs/linux/fs/jffs/CVS/Root --- linux-2.4.7/linux/fs/jffs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/jffs/CVS/Root Thu Jul 5 12:02:44 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/lockd/CVS/Entries linux-2.4-xfs/linux/fs/lockd/CVS/Entries --- linux-2.4.7/linux/fs/lockd/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/lockd/CVS/Entries Thu Jul 5 12:02:49 2001 @@ -0,0 +1,15 @@ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/clntlock.c/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/clntproc.c/1.12/Sun Dec 17 19:15:00 2000/-ko/ +/host.c/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/lockd_syms.c/1.4/Sat Mar 11 02:39:30 2000/-ko/ +/mon.c/1.8/Wed Jun 6 03:10:14 2001/-ko/ +/svc.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/svc4proc.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/svclock.c/1.11/Thu Dec 7 02:20:20 2000/-ko/ +/svcproc.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/svcshare.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/svcsubs.c/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/xdr.c/1.9/Mon Oct 23 18:56:35 2000/-ko/ +/xdr4.c/1.5/Wed Jan 3 01:43:05 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/lockd/CVS/Repository linux-2.4-xfs/linux/fs/lockd/CVS/Repository --- linux-2.4.7/linux/fs/lockd/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/lockd/CVS/Repository Thu Jul 5 12:02:47 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/lockd diff -rNu linux-2.4.7/linux/fs/lockd/CVS/Root linux-2.4-xfs/linux/fs/lockd/CVS/Root --- linux-2.4.7/linux/fs/lockd/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/lockd/CVS/Root Thu Jul 5 12:02:47 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/minix/CVS/Entries linux-2.4-xfs/linux/fs/minix/CVS/Entries --- linux-2.4.7/linux/fs/minix/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/minix/CVS/Entries Thu Jul 5 12:02:49 2001 @@ -0,0 +1,10 @@ +/Makefile/1.5/Thu Dec 21 05:48:12 2000/-ko/ +/bitmap.c/1.10/Sat Nov 25 08:05:45 2000/-ko/ +/dir.c/1.7/Thu Sep 28 22:42:39 2000/-ko/ +/file.c/1.10/Mon Oct 23 18:56:35 2000/-ko/ +/inode.c/1.21/Wed May 2 06:22:13 2001/-ko/ +/itree_common.c/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/itree_v1.c/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/itree_v2.c/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/namei.c/1.14/Wed Nov 1 21:35:42 2000/-ko/ +D diff -rNu linux-2.4.7/linux/fs/minix/CVS/Repository linux-2.4-xfs/linux/fs/minix/CVS/Repository --- linux-2.4.7/linux/fs/minix/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/minix/CVS/Repository Thu Jul 5 12:02:49 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/minix diff -rNu linux-2.4.7/linux/fs/minix/CVS/Root linux-2.4-xfs/linux/fs/minix/CVS/Root --- linux-2.4.7/linux/fs/minix/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/minix/CVS/Root Thu Jul 5 12:02:49 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/msdos/CVS/Entries linux-2.4-xfs/linux/fs/msdos/CVS/Entries --- linux-2.4.7/linux/fs/msdos/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/msdos/CVS/Entries Thu Jul 5 12:02:49 2001 @@ -0,0 +1,4 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/msdosfs_syms.c/1.5/Wed Mar 15 18:20:34 2000/-ko/ +/namei.c/1.17/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/msdos/CVS/Repository linux-2.4-xfs/linux/fs/msdos/CVS/Repository --- linux-2.4.7/linux/fs/msdos/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/msdos/CVS/Repository Thu Jul 5 12:02:49 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/msdos diff -rNu linux-2.4.7/linux/fs/msdos/CVS/Root linux-2.4-xfs/linux/fs/msdos/CVS/Root --- linux-2.4.7/linux/fs/msdos/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/msdos/CVS/Root Thu Jul 5 12:02:49 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/namei.c linux-2.4-xfs/linux/fs/namei.c --- linux-2.4.7/linux/fs/namei.c Tue Jul 3 10:05:42 2001 +++ linux-2.4-xfs/linux/fs/namei.c Wed Jul 4 22:57:00 2001 @@ -886,7 +886,9 @@ { int error; - mode &= S_IALLUGO & ~current->fs->umask; + mode &= S_IALLUGO; + if (!IS_POSIX_ACL(dir)) + mode &= ~current->fs->umask; mode |= S_IFREG; down(&dir->i_zombie); @@ -1164,7 +1166,8 @@ { int error = -EPERM; - mode &= ~current->fs->umask; + if (!IS_POSIX_ACL(dir)) + mode &= ~current->fs->umask; down(&dir->i_zombie); if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) @@ -1246,7 +1249,9 @@ goto exit_lock; DQUOT_INIT(dir); - mode &= (S_IRWXUGO|S_ISVTX) & ~current->fs->umask; + mode &= (S_IRWXUGO|S_ISVTX); + if (!IS_POSIX_ACL(dir)) + mode &= ~current->fs->umask; lock_kernel(); error = dir->i_op->mkdir(dir, dentry, mode); unlock_kernel(); diff -rNu linux-2.4.7/linux/fs/ncpfs/CVS/Entries linux-2.4-xfs/linux/fs/ncpfs/CVS/Entries --- linux-2.4.7/linux/fs/ncpfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ncpfs/CVS/Entries Thu Jul 5 12:02:50 2001 @@ -0,0 +1,14 @@ +/Config.in/1.7/Sun Dec 17 19:15:00 2000/-ko/ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/dir.c/1.25/Mon Apr 2 17:13:32 2001/-ko/ +/file.c/1.14/Thu Feb 22 21:09:04 2001/-ko/ +/inode.c/1.20/Wed May 2 06:22:13 2001/-ko/ +/ioctl.c/1.14/Sun Dec 17 19:15:00 2000/-ko/ +/mmap.c/1.13/Mon Apr 2 17:13:32 2001/-ko/ +/ncplib_kernel.c/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/ncplib_kernel.h/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/ncpsign_kernel.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ncpsign_kernel.h/1.3/Tue Oct 12 19:12:19 1999/-ko/ +/sock.c/1.9/Thu Feb 1 17:10:24 2001/-ko/ +/symlink.c/1.12/Wed Jan 3 01:43:05 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/ncpfs/CVS/Repository linux-2.4-xfs/linux/fs/ncpfs/CVS/Repository --- linux-2.4.7/linux/fs/ncpfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ncpfs/CVS/Repository Thu Jul 5 12:02:49 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/ncpfs diff -rNu linux-2.4.7/linux/fs/ncpfs/CVS/Root linux-2.4-xfs/linux/fs/ncpfs/CVS/Root --- linux-2.4.7/linux/fs/ncpfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ncpfs/CVS/Root Thu Jul 5 12:02:49 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/nfs/CVS/Entries linux-2.4-xfs/linux/fs/nfs/CVS/Entries --- linux-2.4.7/linux/fs/nfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/nfs/CVS/Entries Thu Jul 5 12:02:52 2001 @@ -0,0 +1,16 @@ +/Makefile/1.6/Thu Dec 21 05:48:12 2000/-ko/ +/dir.c/1.29/Wed Jun 13 03:24:09 2001/-ko/ +/file.c/1.20/Tue May 29 19:53:13 2001/-ko/ +/flushd.c/1.9/Tue May 29 19:53:13 2001/-ko/ +/inode.c/1.26/Wed Jun 13 03:24:09 2001/-ko/ +/mount_clnt.c/1.5/Tue May 2 21:36:51 2000/-ko/ +/nfs2xdr.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/nfs3proc.c/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/nfs3xdr.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/nfsroot.c/1.8/Mon Oct 23 18:56:35 2000/-ko/ +/proc.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/read.c/1.22/Wed May 2 06:22:13 2001/-ko/ +/symlink.c/1.14/Thu Feb 22 21:09:04 2001/-ko/ +/unlink.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/write.c/1.26/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/nfs/CVS/Repository linux-2.4-xfs/linux/fs/nfs/CVS/Repository --- linux-2.4.7/linux/fs/nfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/nfs/CVS/Repository Thu Jul 5 12:02:50 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/nfs diff -rNu linux-2.4.7/linux/fs/nfs/CVS/Root linux-2.4-xfs/linux/fs/nfs/CVS/Root --- linux-2.4.7/linux/fs/nfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/nfs/CVS/Root Thu Jul 5 12:02:50 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/nfsd/CVS/Entries linux-2.4-xfs/linux/fs/nfsd/CVS/Entries --- linux-2.4.7/linux/fs/nfsd/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/nfsd/CVS/Entries Thu Jul 5 12:02:54 2001 @@ -0,0 +1,15 @@ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/auth.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/export.c/1.19/Tue Jul 3 02:33:57 2001/-ko/ +/lockd.c/1.6/Fri Apr 21 16:16:46 2000/-ko/ +/nfs3proc.c/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/nfs3xdr.c/1.18/Tue Jul 3 02:33:57 2001/-ko/ +/nfscache.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/nfsctl.c/1.20/Tue May 29 19:53:13 2001/-ko/ +/nfsfh.c/1.27/Tue Jul 3 02:33:57 2001/-ko/ +/nfsproc.c/1.16/Tue Jul 3 02:33:57 2001/-ko/ +/nfssvc.c/1.13/Tue May 29 19:53:13 2001/-ko/ +/nfsxdr.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/stats.c/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/vfs.c/1.35/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/nfsd/CVS/Repository linux-2.4-xfs/linux/fs/nfsd/CVS/Repository --- linux-2.4.7/linux/fs/nfsd/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/nfsd/CVS/Repository Thu Jul 5 12:02:52 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/nfsd diff -rNu linux-2.4.7/linux/fs/nfsd/CVS/Root linux-2.4-xfs/linux/fs/nfsd/CVS/Root --- linux-2.4.7/linux/fs/nfsd/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/nfsd/CVS/Root Thu Jul 5 12:02:52 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/nls/CVS/Entries linux-2.4-xfs/linux/fs/nls/CVS/Entries --- linux-2.4.7/linux/fs/nls/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/nls/CVS/Entries Thu Jul 5 12:03:27 2001 @@ -0,0 +1,48 @@ +/Config.in/1.9/Thu Jun 28 05:21:16 2001/-ko/ +/Makefile/1.8/Tue May 29 19:53:13 2001/-ko/ +/nls_base.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/nls_big5.c/1.2/Wed Nov 1 21:35:42 2000/-ko/ +/nls_cp1251.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/nls_cp1255.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/nls_cp437.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp737.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp775.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp850.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp852.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp855.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp857.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp860.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp861.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp862.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp863.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp864.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp865.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp866.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp869.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp874.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp932.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/nls_cp936.c/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp949.c/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/nls_cp950.c/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/nls_euc-jp.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/nls_euc-kr.c/1.2/Wed Nov 1 21:35:42 2000/-ko/ +/nls_gb2312.c/1.2/Wed Nov 1 21:35:42 2000/-ko/ +/nls_iso8859-1.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_iso8859-13.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/nls_iso8859-14.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/nls_iso8859-15.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_iso8859-2.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_iso8859-3.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_iso8859-4.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_iso8859-5.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_iso8859-6.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_iso8859-7.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_iso8859-8.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/nls_iso8859-9.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_koi8-r.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/nls_koi8-ru.c/1.1/Tue May 29 19:53:13 2001/-ko/ +/nls_koi8-u.c/1.2/Tue May 29 19:53:13 2001/-ko/ +/nls_sjis.c/1.2/Wed Nov 1 21:35:42 2000/-ko/ +/nls_tis-620.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/nls_utf8.c/1.1/Mon Jul 31 16:16:28 2000/-ko/ +D diff -rNu linux-2.4.7/linux/fs/nls/CVS/Repository linux-2.4-xfs/linux/fs/nls/CVS/Repository --- linux-2.4.7/linux/fs/nls/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/nls/CVS/Repository Thu Jul 5 12:02:54 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/nls diff -rNu linux-2.4.7/linux/fs/nls/CVS/Root linux-2.4-xfs/linux/fs/nls/CVS/Root --- linux-2.4.7/linux/fs/nls/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/nls/CVS/Root Thu Jul 5 12:02:54 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/noposix_acl.c linux-2.4-xfs/linux/fs/noposix_acl.c --- linux-2.4.7/linux/fs/noposix_acl.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/noposix_acl.c Tue Jan 23 01:11:51 2001 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* ACL system call stubs necessary for when posix ACLs are not + * compiled into the kernel. + */ + +#include +#include +#include +#include + +asmlinkage long sys_acl_get( + const char *path, + int fdes, + struct acl *acl, + struct acl *dacl) +{ + return -ENOSYS; +} + + +asmlinkage long sys_acl_set( + const char *path, + int fdes, + struct acl *acl, + struct acl *dacl) +{ + return -ENOSYS; +} diff -rNu linux-2.4.7/linux/fs/ntfs/CVS/Entries linux-2.4-xfs/linux/fs/ntfs/CVS/Entries --- linux-2.4.7/linux/fs/ntfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ntfs/CVS/Entries Thu Jul 5 12:03:30 2001 @@ -0,0 +1,21 @@ +/Makefile/1.7/Wed May 2 06:22:13 2001/-ko/ +/attr.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/attr.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/dir.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/dir.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/fs.c/1.25/Wed May 2 06:22:13 2001/-ko/ +/inode.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/inode.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/macros.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/ntfsendian.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/ntfstypes.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/struct.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/super.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/super.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/support.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/support.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/sysctl.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sysctl.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/util.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/util.h/1.3/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/ntfs/CVS/Repository linux-2.4-xfs/linux/fs/ntfs/CVS/Repository --- linux-2.4.7/linux/fs/ntfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ntfs/CVS/Repository Thu Jul 5 12:03:27 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/ntfs diff -rNu linux-2.4.7/linux/fs/ntfs/CVS/Root linux-2.4-xfs/linux/fs/ntfs/CVS/Root --- linux-2.4.7/linux/fs/ntfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ntfs/CVS/Root Thu Jul 5 12:03:27 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/openpromfs/CVS/Entries linux-2.4-xfs/linux/fs/openpromfs/CVS/Entries --- linux-2.4.7/linux/fs/openpromfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/openpromfs/CVS/Entries Thu Jul 5 12:03:30 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Thu Dec 21 05:48:12 2000/-ko/ +/inode.c/1.13/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/openpromfs/CVS/Repository linux-2.4-xfs/linux/fs/openpromfs/CVS/Repository --- linux-2.4.7/linux/fs/openpromfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/openpromfs/CVS/Repository Thu Jul 5 12:03:30 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/openpromfs diff -rNu linux-2.4.7/linux/fs/openpromfs/CVS/Root linux-2.4-xfs/linux/fs/openpromfs/CVS/Root --- linux-2.4.7/linux/fs/openpromfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/openpromfs/CVS/Root Thu Jul 5 12:03:30 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/pagebuf/CVS/Entries linux-2.4-xfs/linux/fs/pagebuf/CVS/Entries --- linux-2.4.7/linux/fs/pagebuf/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/pagebuf/CVS/Entries Thu Jul 5 12:03:32 2001 @@ -0,0 +1,6 @@ +/Makefile/1.4/Tue Jan 9 02:55:07 2001/-ko/ +/avl.c/1.4/Fri May 25 22:32:42 2001/-ko/ +/page_buf.c/1.91/Tue Jul 3 02:29:39 2001/-ko/ +/page_buf_io.c/1.87/Mon Jul 2 15:59:04 2001/-ko/ +/page_buf_locking.c/1.13/Wed Jun 20 19:56:33 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/pagebuf/CVS/Repository linux-2.4-xfs/linux/fs/pagebuf/CVS/Repository --- linux-2.4.7/linux/fs/pagebuf/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/pagebuf/CVS/Repository Thu Jul 5 12:03:30 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/pagebuf diff -rNu linux-2.4.7/linux/fs/pagebuf/CVS/Root linux-2.4-xfs/linux/fs/pagebuf/CVS/Root --- linux-2.4.7/linux/fs/pagebuf/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/pagebuf/CVS/Root Thu Jul 5 12:03:30 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/pagebuf/Makefile linux-2.4-xfs/linux/fs/pagebuf/Makefile --- linux-2.4.7/linux/fs/pagebuf/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/pagebuf/Makefile Mon Jan 8 20:55:07 2001 @@ -0,0 +1,21 @@ +# +# Makefile for the linux pagebuf routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +EXTRA_CFLAGS += + +O_TARGET := pagebuf.o +obj-m := $(O_TARGET) + +export-objs += page_buf.o page_buf_io.o page_buf_locking.o +obj-y += avl.o \ + page_buf.o \ + page_buf_io.o \ + page_buf_locking.o + +include $(TOPDIR)/Rules.make diff -rNu linux-2.4.7/linux/fs/pagebuf/avl.c linux-2.4-xfs/linux/fs/pagebuf/avl.c --- linux-2.4.7/linux/fs/pagebuf/avl.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/pagebuf/avl.c Fri May 25 17:32:42 2001 @@ -0,0 +1,813 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Id: $" + +/* + * Generic AVL module: avl + * + * This module supports storing key-value pairs in an opaque + * AVL tree. Both the key and the value are pointer-sized integers. + * The caller may provide an optional comparison function. The + * tree is kept separate from the objects to avoid locking problems + * and cache thrashing with respect to the referenced objects on + * larger SMP systems. + * + * Derived from mmap_avl.c, which was + * written by Bruno Haible . + * + * + * Written by William J. Earl at SGI + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define assert(x) do { } while (0) +#define bzero(loc,size) memset(loc,0,size) + +typedef struct avl_entry_struct { + struct avl_entry_struct *avl_left; + struct avl_entry_struct *avl_right; + int avl_height; + avl_key_t avl_key; + avl_value_t avl_value; +} avl_entry_t; + +typedef struct avl_object_struct { + avl_opt_t avlo_options; + avl_entry_t *avlo_tree; + avl_entry_t *avlo_cache; + spinlock_t avlo_lock; + avl_comparison_t avlo_compare; + avl_increment_t avlo_increment; +} avl_object_t; + +#define avl_empty ((avl_entry_t *) NULL) + +#define avl_maxheight 100 +#define heightof(tree) (((tree) == avl_empty) ? 0 : (tree)->avl_height) + +static kmem_cache_t *avl_entry_cache = NULL; +static kmem_cache_t *avl_object_cache = NULL; + +/* + * Consistency and balancing rules: + * 1. tree->avl_height == 1+max(heightof(tree->avl_left),heightof(tree->avl_right)) + * 2. abs( heightof(tree->avl_left) - heightof(tree->avl_right) ) <= 1 + * 3. foreach node in tree->avl_left: node->avl_key <= tree->avl_key, + * foreach node in tree->avl_right: node->avl_key >= tree->avl_key. + */ + +/* + * avl_compare + * + * This is the default key comparison function. + */ + +static int +avl_compare(avl_key_t a, + avl_key_t b) +{ + if (a == b) + return(0); + else if (a < b) + return(-1); + else + return(1); +} + + +#ifdef CONFIG_AVL_DEBUG + +#ifdef notyet +/* Look up the nodes at the left and at the right of a given node. */ +static void +avl_neighbours (avl_entry_t * node, + avl_entry_t * tree, + avl_entry_t ** to_the_left, + avl_entry_t ** to_the_right) +{ + avl_key_t key = node->avl_key; + + *to_the_left = *to_the_right = NULL; + for (;;) { + if (tree == avl_empty) { + printk("avl_neighbours: node not found in the tree\n"); + return; + } + if (key == tree->avl_key) + break; + if (key < tree->avl_key) { + *to_the_right = tree; + tree = tree->avl_left; + } else { + *to_the_left = tree; + tree = tree->avl_right; + } + } + if (tree != node) { + printk("avl_neighbours: node not exactly found in the tree\n"); + return; + } + if (tree->avl_left != avl_empty) { + avl_entry_t * node; + for (node = tree->avl_left; + node->avl_right != avl_empty; + node = node->avl_right) + continue; + *to_the_left = node; + } + if (tree->avl_right != avl_empty) { + avl_entry_t * node; + for (node = tree->avl_right; + node->avl_left != avl_empty; + node = node->avl_left) + continue; + *to_the_right = node; + } +} +#endif /* notyet */ + +#endif /* CONFIG_AVL_DEBUG */ + +/* + * Rebalance a tree. + * After inserting or deleting a node of a tree we have a sequence of subtrees + * nodes[0]..nodes[k-1] such that + * nodes[0] is the root and nodes[i+1] = nodes[i]->{avl_left|avl_right}. + */ +static void +avl_rebalance (avl_entry_t *** nodeplaces_ptr, + int count) +{ + for ( ; count > 0 ; count--) { + avl_entry_t ** nodeplace = *--nodeplaces_ptr; + avl_entry_t * node = *nodeplace; + avl_entry_t * nodeleft = node->avl_left; + avl_entry_t * noderight = node->avl_right; + int heightleft = heightof(nodeleft); + int heightright = heightof(noderight); + if (heightright + 1 < heightleft) { + /* */ + /* * */ + /* / \ */ + /* n+2 n */ + /* */ + avl_entry_t * nodeleftleft = nodeleft->avl_left; + avl_entry_t * nodeleftright = nodeleft->avl_right; + int heightleftright = heightof(nodeleftright); + if (heightof(nodeleftleft) >= heightleftright) { + /* */ + /* * n+2|n+3 */ + /* / \ / \ */ + /* n+2 n --> / n+1|n+2 */ + /* / \ | / \ */ + /* n+1 n|n+1 n+1 n|n+1 n */ + /* */ + node->avl_left = nodeleftright; + nodeleft->avl_right = node; + nodeleft->avl_height = 1 + (node->avl_height = + (1 + heightleftright)); + *nodeplace = nodeleft; + } else { + /* */ + /* * n+2 */ + /* / \ / \ */ + /* n+2 n --> n+1 n+1 */ + /* / \ / \ / \ */ + /* n n+1 n L R n */ + /* / \ */ + /* L R */ + /* */ + nodeleft->avl_right = nodeleftright->avl_left; + node->avl_left = nodeleftright->avl_right; + nodeleftright->avl_left = nodeleft; + nodeleftright->avl_right = node; + nodeleft->avl_height = + (node->avl_height = heightleftright); + nodeleftright->avl_height = heightleft; + *nodeplace = nodeleftright; + } + } + else if (heightleft + 1 < heightright) { + /* similar to the above, just interchange 'left' <--> 'right' */ + avl_entry_t * noderightright = noderight->avl_right; + avl_entry_t * noderightleft = noderight->avl_left; + int heightrightleft = heightof(noderightleft); + if (heightof(noderightright) >= heightrightleft) { + node->avl_right = noderightleft; + noderight->avl_left = node; + noderight->avl_height = 1 + (node->avl_height = + (1 + heightrightleft)); + *nodeplace = noderight; + } else { + noderight->avl_left = noderightleft->avl_right; + node->avl_right = noderightleft->avl_left; + noderightleft->avl_right = noderight; + noderightleft->avl_left = node; + noderight->avl_height = + (node->avl_height = heightrightleft); + noderightleft->avl_height = heightright; + *nodeplace = noderightleft; + } + } + else { + int height = (heightleftavl_height) + break; + node->avl_height = height; + } + } +} + +/* Insert a node into a tree. */ +static inline void +avl_insert_entry (avl_entry_t * new_node, + avl_object_t * avl) +{ + avl_key_t key = new_node->avl_key; + avl_entry_t ** nodeplace = &avl->avlo_tree; + avl_entry_t ** stack[avl_maxheight]; + int stack_count = 0; + int cval; + avl_entry_t *** stack_ptr = &stack[0]; /* = &stack[stackcount] */ + + for (;;) { + avl_entry_t * node = *nodeplace; + if (node == avl_empty) + break; + *stack_ptr++ = nodeplace; stack_count++; + cval = avl->avlo_compare(node->avl_key, key); + if (cval > 0) + nodeplace = &node->avl_left; + else + nodeplace = &node->avl_right; + } + new_node->avl_left = avl_empty; + new_node->avl_right = avl_empty; + new_node->avl_height = 1; + *nodeplace = new_node; + avl_rebalance(stack_ptr,stack_count); +} + + +#if NOTDEF +/* Insert a node into a tree, and + * return the node to the left of it and the node to the right of it. + */ +static inline void +avl_insert_neighbours (avl_entry_t * new_node, + avl_entry_t ** ptree, + avl_entry_t ** to_the_left, + avl_entry_t ** to_the_right) +{ + avl_key_t key = new_node->avl_key; + avl_entry_t ** nodeplace = ptree; + avl_entry_t ** stack[avl_maxheight]; + int stack_count = 0; + avl_entry_t *** stack_ptr = &stack[0]; /* = &stack[stackcount] */ + *to_the_left = *to_the_right = NULL; + + for (;;) { + avl_entry_t * node = *nodeplace; + if (node == avl_empty) + break; + *stack_ptr++ = nodeplace; stack_count++; + if (key < node->avl_key) { + *to_the_right = node; + nodeplace = &node->avl_left; + } else { + *to_the_left = node; + nodeplace = &node->avl_right; + } + } + new_node->avl_left = avl_empty; + new_node->avl_right = avl_empty; + new_node->avl_height = 1; + *nodeplace = new_node; + avl_rebalance(stack_ptr,stack_count); +} +#endif + +/* Removes a node out of a tree. */ +static void +avl_remove (avl_entry_t * node_to_delete, + avl_object_t * avl) +{ + avl_key_t key = node_to_delete->avl_key; + avl_entry_t ** nodeplace = &avl->avlo_tree; + avl_entry_t ** stack[avl_maxheight]; + int stack_count = 0; + int cval; + avl_entry_t *** stack_ptr = &stack[0]; /* = &stack[stackcount] */ + avl_entry_t ** nodeplace_to_delete; + + for (;;) { + avl_entry_t * node = *nodeplace; +#ifdef CONFIG_AVL_DEBUG + if (node == avl_empty) { + /* what? node_to_delete not found in tree? */ + printk("avl_remove: node to delete not found in tree\n"); + return; + } +#endif /* CONFIG_AVL_DEBUG */ + *stack_ptr++ = nodeplace; stack_count++; + cval = avl->avlo_compare(node->avl_key, key); + if (cval == 0) + break; + if (cval > 0) + nodeplace = &node->avl_left; + else + nodeplace = &node->avl_right; + } + nodeplace_to_delete = nodeplace; + /* Have to remove node_to_delete = *nodeplace_to_delete. */ + if (node_to_delete->avl_left == avl_empty) { + *nodeplace_to_delete = node_to_delete->avl_right; + stack_ptr--; stack_count--; + } else { + avl_entry_t *** stack_ptr_to_delete = stack_ptr; + avl_entry_t ** nodeplace = &node_to_delete->avl_left; + avl_entry_t * node; + for (;;) { + node = *nodeplace; + if (node->avl_right == avl_empty) + break; + *stack_ptr++ = nodeplace; stack_count++; + nodeplace = &node->avl_right; + } + *nodeplace = node->avl_left; + /* node replaces node_to_delete */ + node->avl_left = node_to_delete->avl_left; + node->avl_right = node_to_delete->avl_right; + node->avl_height = node_to_delete->avl_height; + *nodeplace_to_delete = node; /* replace node_to_delete */ + /* replace &node_to_delete->avl_left */ + *stack_ptr_to_delete = &node->avl_left; + } + avl_rebalance(stack_ptr,stack_count); +} + +#ifdef CONFIG_AVL_DEBUG + +/* print a tree */ +static void +avl_printk_avl (avl_entry_t * entry) +{ + if (entry != avl_empty) { + printk("("); + if (entry->avl_left != avl_empty) { + avl_printk_avl(entry->avl_left); + printk("<"); + } + printk("0x%08lX=0x%08lX", + (long) entry->avl_key, + (long) entry->avl_value); + if (entry->avl_right != avl_empty) { + printk(">"); + avl_printk_avl(entry->avl_right); + } + printk(")"); + } +} + +/* check a tree's consistency and balancing */ +static void +avl_checkheights (avl_object_t *avl, + char *avl_check_point, + avl_entry_t * tree) +{ + int h, hl, hr; + + if (tree == avl_empty) + return; + avl_checkheights(avl,avl_check_point,tree->avl_left); + avl_checkheights(avl,avl_check_point,tree->avl_right); + h = tree->avl_height; + hl = heightof(tree->avl_left); + hr = heightof(tree->avl_right); + if ((h == hl+1) && (hr <= hl) && (hl <= hr+1)) + return; + if ((h == hr+1) && (hl <= hr) && (hr <= hl+1)) + return; + printk("%s: avl_checkheights: heights inconsistent\n",avl_check_point); +} + +/* check that all values stored in a tree are < key */ +static void +avl_checkleft (avl_object_t *avl, + char *avl_check_point, + avl_entry_t * tree, + avl_key_t key) +{ + if (tree == avl_empty) + return; + avl_checkleft(avl,avl_check_point,tree->avl_left,key); + avl_checkleft(avl,avl_check_point,tree->avl_right,key); + if (avl->avlo_compare(tree->avl_key,key) < 0) + return; + printk("%s: avl_checkleft: left key 0x%08lX >= top key 0x%08lX\n", + avl_check_point, + (long) tree->avl_key, + (long) key); +} + +/* check that all values stored in a tree are > key */ +static void +avl_checkright (avl_object_t *avl, + char *avl_check_point, + avl_entry_t * tree, + avl_key_t key) +{ + if (tree == avl_empty) + return; + avl_checkright(avl,avl_check_point,tree->avl_left,key); + avl_checkright(avl,avl_check_point,tree->avl_right,key); + if (avl->avlo_compare(tree->avl_key,key) > 0) + return; + printk("%s: avl_checkright: right key 0x%08lX <= top key 0x%08lX\n", + avl_check_point, + (long) tree->avl_key, + (long) key); +} + +/* check that all values are properly increasing */ +static void +avl_checkorder (avl_object_t *avl, + char *avl_check_point, + avl_entry_t * tree) +{ + if (tree == avl_empty) + return; + avl_checkorder(avl,avl_check_point,tree->avl_left); + avl_checkorder(avl,avl_check_point,tree->avl_right); + avl_checkleft(avl,avl_check_point,tree->avl_left,tree->avl_key); + avl_checkright(avl,avl_check_point,tree->avl_right,tree->avl_key); +} + +/* all checks */ +void +avl_check (avl_handle_t handle, + char *avl_check_point) +{ + avl_object_t *avl = (avl_object_t *) handle; + + if (! debug) + return; +#ifdef nolonger + printk("avl 0x%08lX, %s tree:\n",(long) handle,avl_check_point); + avl_printk_avl(avl->avlo_tree); + printk("\n"); +#endif /* nolonger */ + avl_checkheights(avl,avl_check_point,avl->avlo_tree); + avl_checkorder(avl,avl_check_point,avl->avlo_tree); +} + +#endif /* CONFIG_AVL_DEBUG */ + +/* + * avl_init + * + * Initialize avl module. + */ + +int __init avl_init(void) +{ + if (avl_entry_cache == NULL) { + avl_entry_cache = kmem_cache_create("avl_entry_t", + sizeof(avl_entry_t), + 0, + SLAB_HWCACHE_ALIGN, + NULL, + NULL); + if (avl_entry_cache == NULL) + return(-ENOMEM); + } + if (avl_object_cache == NULL) { + avl_object_cache = kmem_cache_create("avl_object_t", + sizeof(avl_object_t), + 0, + SLAB_HWCACHE_ALIGN, + NULL, + NULL); + if (avl_object_cache == NULL) { + kmem_cache_shrink(avl_entry_cache); + return(-ENOMEM); + } + } + return(0); +} + +/* + * avl_terminate + */ + +void __exit avl_terminate(void) +{ + if (avl_object_cache != NULL) + kmem_cache_destroy(avl_object_cache); + if (avl_entry_cache != NULL) + kmem_cache_destroy(avl_entry_cache); +} + +/* + * avl_create + * + * Allocate an AVL tree object, to be returned in the + * avl_handle_t variable passed by reference. + * The avl_comparison_t value may be NULL, in which case a + * default (integer) comparison is used. + */ + +int +avl_create(avl_handle_t *handle_p, + avl_opt_t options, + avl_comparison_t cmpfn, + avl_increment_t incfn) +{ + avl_object_t *avl; + + if (cmpfn == NULL) + cmpfn = avl_compare; + + avl = kmem_cache_alloc(avl_object_cache,SLAB_KERNEL); + if (avl == NULL) + return(-ENOMEM); + bzero(avl,sizeof(avl_object_t)); + avl->avlo_options = options; + spin_lock_init(&avl->avlo_lock); + avl->avlo_compare = cmpfn; + avl->avlo_increment = incfn; + *handle_p = (avl_handle_t) avl; + return(0); +} + +/* + * avl_destroy + * + * Destroy (deallocate) an AVL tree object. + */ + +void +avl_destroy(avl_handle_t handle) +{ + avl_object_t *avl = (avl_object_t *) handle; + + while (avl->avlo_tree != NULL) { + (void) avl_delete(handle, + avl->avlo_tree->avl_key, + avl->avlo_tree->avl_value); + } + kmem_cache_free(avl_object_cache,avl); +} + +/* + * avl_insert + * + * Insert the key-value pair into the give AVL tree. + * + * Returns -EEXIST if there is already an entry for the key. + */ + +int +avl_insert(avl_handle_t handle, + avl_key_t key, + avl_value_t value) +{ + avl_object_t *avl = (avl_object_t *) handle; + avl_entry_t *entry; + avl_value_t old_value; + + if (! avl_lookup(handle,key,&old_value)) + return(-EEXIST); + + /* We have a spinlock - do not sleep */ + entry = kmem_cache_alloc(avl_entry_cache,SLAB_ATOMIC); + if (entry == NULL) + return(-ENOMEM); + entry->avl_key = key; + entry->avl_value = value; + avl_insert_entry(entry, avl); + avl->avlo_cache = entry; + return(0); +} + +/* + * avl_replace + * + * Replace (or insert) the key-value pair into the give AVL tree. + */ + +int +avl_replace(avl_handle_t handle, + avl_key_t key, + avl_value_t value) +{ + avl_object_t *avl = (avl_object_t *) handle; + avl_entry_t *entry; + int cval; + + entry = avl->avlo_cache; + if (entry == NULL || + entry->avl_key != key) { + entry = avl->avlo_tree; + for (;;) { + if (entry == avl_empty) + return(avl_insert(handle,key,value)); + cval = avl->avlo_compare(entry->avl_key,key); + if (cval == 0) + break; + if (cval > 0) + entry = entry->avl_left; + else + entry = entry->avl_right; + } + avl->avlo_cache = entry; + } + entry->avl_value = value; + return(0); +} + +/* + * avl_delete + * + * Delete the key-value pair from the give AVL tree. + * + * Returns -ENOENT if the key is not present in the tree. + * Returns -EINVAL if the value supplied does not match the + * value stored in the tree. + */ + +int +avl_delete(avl_handle_t handle, + avl_key_t key, + avl_value_t value) +{ + avl_object_t *avl = (avl_object_t *) handle; + avl_entry_t *entry; + int cval; + + entry = avl->avlo_cache; + if (entry == NULL || + entry->avl_key != key) { + entry = avl->avlo_tree; + for (;;) { + if (entry == avl_empty) + return(-ENOENT); + cval = avl->avlo_compare(entry->avl_key,key); + if (cval == 0) + break; + if (cval > 0) + entry = entry->avl_left; + else + entry = entry->avl_right; + } + avl->avlo_cache = entry; + } + if (value != entry->avl_value) + return(-EINVAL); + avl->avlo_cache = NULL; + avl_remove(entry, avl); + kmem_cache_free(avl_entry_cache,entry); + return(0); + +} + +/* + * avl_lookup + * + * Lookup the key in the give AVL tree, and return the + * associated value in the avl_value_t variable passed by + * reference. + * + * Returns -ENOENT if the key is not present in the tree. + */ + +int +avl_lookup(avl_handle_t handle, + avl_key_t key, + avl_value_t *value) +{ + avl_object_t *avl = (avl_object_t *) handle; + avl_entry_t *entry; + int cval; + + entry = avl->avlo_cache; + if (entry == NULL || + entry->avl_key != key) { + entry = avl->avlo_tree; + for (;;) { + if (entry == avl_empty) { + *value = (avl_value_t)0; + return(-ENOENT); + } + cval = avl->avlo_compare(entry->avl_key,key); + if (cval == 0) + break; + if (cval > 0) + entry = entry->avl_left; + else + entry = entry->avl_right; + } + avl->avlo_cache = entry; + } + *value = entry->avl_value; + return(0); +} + +/* + * avl_lookup_next + * + * Lookup the first key equal to or greater than the key + * in the first avl_key_t variable passed by reference, returning + * the associated key and value in the remaining variables passed + * by reference, and update the first variable to be the next key value + * greater than the key of the entry found. + * + * If the starting key is set to the lowest possible key value, + * this may be used to search for all entries in the tree in a loop. + * + * Returns -ENOENT if no matching key is present in the tree. + */ + +int +avl_lookup_next(avl_handle_t handle, + avl_key_t *next_key, + avl_key_t *key, + avl_value_t *value) +{ + avl_object_t *avl = (avl_object_t *) handle; + avl_entry_t *entry; + int cval; + + entry = avl->avlo_cache; + if (entry == NULL || + entry->avl_key != *next_key) { + entry = avl->avlo_tree; + for (;;) { + if (entry == avl_empty) + return(-ENOENT); + cval = avl->avlo_compare(entry->avl_key,*next_key); + if (cval == 0) + break; + if (cval > 0) { + if (entry->avl_left == NULL) + break; + entry = entry->avl_left; + } else + entry = entry->avl_right; + } + avl->avlo_cache = entry; + } + *key = entry->avl_key; + *value = entry->avl_value; + if (avl->avlo_increment != NULL) + avl->avlo_increment(next_key,entry->avl_key); + else + *next_key = (*key) + 1; + + return(0); +} + diff -rNu linux-2.4.7/linux/fs/pagebuf/page_buf.c linux-2.4-xfs/linux/fs/pagebuf/page_buf.c --- linux-2.4.7/linux/fs/pagebuf/page_buf.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/pagebuf/page_buf.c Mon Jul 2 21:29:39 2001 @@ -0,0 +1,2277 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Id: $" + +/* + * page_buf.c + * + * The page_buf module provides an abstract buffer cache model on top of + * the Linux page cache. Cached blocks for a file are hashed to the + * inode for that file, and can be held dirty in delayed write mode in + * the page cache. Cached metadata blocks for a file system are hashed + * to the inode for the mounted device. The page_buf module assembles + * buffer (page_buf_t) objects on demand to aggregate such cached pages + * for I/O. + * + * + * Written by Steve Lord, Jim Mostek, Russell Cattelan + * and Rajagopal Ananthanarayanan ("ananth") at SGI. + * + */ + +#define _PAGE_BUF_INTERNAL_ 1 + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6) +#define SLAB_NOFS SLAB_BUFFER +#define GFP_NOFS GFP_BUFFER +#endif + +/* + * Debug code + */ + +#define PB_DEFINE_TRACES +#include + +MODULE_DESCRIPTION("page_buf file system buffer module"); +#ifdef PAGEBUF_TRACE +#define STATIC +static spinlock_t pb_trace_lock = SPIN_LOCK_UNLOCKED; +struct pagebuf_trace_buf pb_trace; +EXPORT_SYMBOL(pb_trace); +EXPORT_SYMBOL(pb_trace_func); +#define CIRC_INC(i) (((i) + 1) & (PB_TRACE_BUFSIZE - 1)) + +void pb_trace_func(page_buf_t *pb, int event, void *misc, void *ra) +{ + int j; + unsigned long flags; + + if (!pb_params.p_un.debug) return; + + if (ra == NULL) ra = (void *)__builtin_return_address(0); + + spin_lock_irqsave(&pb_trace_lock, flags); + j = pb_trace.start; + pb_trace.start = CIRC_INC(j); + spin_unlock_irqrestore(&pb_trace_lock, flags); + + pb_trace.buf[j].pb = (unsigned long) pb; + pb_trace.buf[j].event = event; + pb_trace.buf[j].flags = pb->pb_flags; + pb_trace.buf[j].hold = pb->pb_hold; + pb_trace.buf[j].lock_value = PBP(pb)->pb_sema.count.counter; + pb_trace.buf[j].task = (void *)current; + pb_trace.buf[j].misc = misc; + pb_trace.buf[j].ra = ra; + pb_trace.buf[j].offset = pb->pb_file_offset; + pb_trace.buf[j].size = pb->pb_buffer_length; +} +#define ENTER(x) printk("Entering " #x "\n"); +#define EXIT(x) printk("Exiting " #x "\n"); +#else +#define STATIC static +#define ENTER(x) +#define EXIT(x) +#endif + +#ifdef PB_TRACKING +#define MAX_PB 10000 +page_buf_t *pb_array[MAX_PB]; + +EXPORT_SYMBOL(pb_array); +#endif + +/* + * External locking functions + */ + +extern int _pagebuf_get_lockable_buffer( + pb_target_t *, loff_t, size_t, page_buf_flags_t, + page_buf_t **); +extern int _pagebuf_find_lockable_buffer( + pb_target_t *, loff_t, size_t, page_buf_flags_t, + page_buf_t **); +extern int _pagebuf_free_lockable_buffer( + page_buf_t *, unsigned long); + + +/* + * File wide globals + */ + +STATIC kmem_cache_t *pagebuf_cache = NULL; +STATIC pagebuf_daemon_t *pb_daemon = NULL; + +/* + * Pagebuf module configuration parameters, exported via + * /proc/sys/vm/pagebuf + */ + +unsigned long pagebuf_min[P_PARAM] = { HZ/2, 1*HZ, 1, 0 }; +unsigned long pagebuf_max[P_PARAM] = { HZ*30, HZ*300, 4096, 1 }; + +pagebuf_param_t pb_params = {{ HZ, 15 * HZ, 256, 0 }}; + +/* + * Pagebuf statistics variables + */ + +struct pbstats pbstats; + +#define REMAPPING_SUPPORT + +#ifdef REMAPPING_SUPPORT +STATIC void *pagebuf_mapout_locked(page_buf_t *); + +STATIC spinlock_t as_lock = SPIN_LOCK_UNLOCKED; +typedef struct a_list { + void *vm_addr; + struct a_list *next; +} a_list_t; +STATIC a_list_t *as_free_head; +STATIC int as_list_len; + +STATIC void +free_address(void *addr) +{ + unsigned long flags; + a_list_t *aentry; + + spin_lock_irqsave(&as_lock, flags); + aentry = kmalloc(sizeof(a_list_t), GFP_ATOMIC); + aentry->next = as_free_head; + aentry->vm_addr = addr; + as_free_head = aentry; + as_list_len++; + spin_unlock_irqrestore(&as_lock, flags); +} + +STATIC void +purge_addresses(void) +{ + unsigned long flags; + a_list_t *aentry, *old; + + if (as_free_head == NULL) return; + + spin_lock_irqsave(&as_lock, flags); + aentry = as_free_head; + as_free_head = NULL; + as_list_len = 0; + spin_unlock_irqrestore(&as_lock, flags); + + while ((old = aentry) != NULL) { + vfree(aentry->vm_addr); + aentry = aentry->next; + kfree(old); + } +} +#endif + +/* + * Locking model: + * + * Buffers associated with inodes for which buffer locking + * is not enabled are not protected by semaphores, and are + * assumed to be exclusively owned by the caller. There is + * spinlock in the buffer, for use by the caller when concurrent + * access is possible. + */ + +/* + * Internal pagebuf object manipulation + */ + +/* + * _pagebuf_get_object + * + * This routine allocates a page_buf_t object and initializes it, + * with no other operations implied. + */ + +int +_pagebuf_get_object( + pb_target_t *target, + loff_t range_base, + size_t range_length, + page_buf_flags_t flags, + page_buf_t ** pb_p) +{ + page_buf_t *pb; + + pb = kmem_cache_alloc(pagebuf_cache, + (flags & PBF_DONT_BLOCK) ? SLAB_NOFS : SLAB_KERNEL); + if (pb == NULL) + return (-ENOMEM); + +#ifdef PB_TRACKING + { + int i; + + for (i = 0; (pb_array[i] != 0) && (i < MAX_PB); i++); + if (i == MAX_PB) + printk("pb 0x%p not recorded in pb_array\n", pb); + else + pb_array[i] = pb; + } +#endif + + bzero(pb, sizeof(page_buf_private_t)); + pb->pb_hold = 1; + spin_lock_init(&PBP(pb)->pb_lock); + init_MUTEX_LOCKED(&PBP(pb)->pb_iodonesema); + INIT_LIST_HEAD(&pb->pb_list); + if (flags && _PBF_LOCKABLE) + init_MUTEX_LOCKED(&PBP(pb)->pb_sema); /* held, no waiters */ + PB_SET_OWNER(pb); + pb->pb_target = target; + if (target) { + pb->pb_sector_bits = target->pbr_sector_bits; + pb->pb_dev = target->pbr_device; + } + pb->pb_file_offset = range_base; + pb->pb_buffer_length = pb->pb_count_desired = range_length; + /* set buffer_length and count_desired to the same value initially + * io routines should use count_desired, which will the same in + * most cases but may be reset (e.g. XFS recovery) + */ + pb->pb_flags = (flags & ~(PBF_ENTER_PAGES|PBF_MAPPED|PBF_DONT_BLOCK)) | + PBF_NONE; + pb->pb_bn = PAGE_BUF_DADDR_NULL; + atomic_set(&PBP(pb)->pb_pin_count, 0); + init_waitqueue_head(&PBP(pb)->pb_waiters); + + *pb_p = pb; + + PB_STATS_INC(pbstats.pb_create); + PB_TRACE(pb, PB_TRACE_REC(get), target); + return (0); +} + +/* + * Allocate a page array capable of holding a specified number + * of pages, and point the page buf at it. + */ +STATIC int +_pagebuf_get_pages(page_buf_t * pb, int page_count, int flags) +{ + + int gpf_mask = (flags & PBF_DONT_BLOCK) ? + SLAB_NOFS : SLAB_KERNEL; + + /* assure that we have a page list */ + if (pb->pb_pages == NULL) { + pb->pb_offset = page_buf_poff(pb->pb_file_offset); + pb->pb_page_count = page_count; + if (page_count <= PB_PAGES) { + pb->pb_pages = pb->pb_page_array; + } else { + pb->pb_pages = kmalloc(sizeof(struct page *) * + page_count, gpf_mask); + if (pb->pb_pages == NULL) + return (-ENOMEM); + } + memset(pb->pb_pages, 0, sizeof(struct page *) * page_count); + } + return (0); +} + +/* + * Walk a pagebuf releasing all the pages contained + * within it. + */ +STATIC inline void _pagebuf_freepages(page_buf_t *pb) +{ + int buf_index; + struct page *page; + + for (buf_index = 0; buf_index < pb->pb_page_count; buf_index++) { + page = pb->pb_pages[buf_index]; + if (page != NULL) { + pb->pb_pages[buf_index] = NULL; + page_cache_release(page); + } + } + + if (pb->pb_pages != pb->pb_page_array) + kfree(pb->pb_pages); +} + + +/* + * _pagebuf_free_object + * + * _pagebuf_free_object releases the contents specified buffer. + * The modification state of any associated pages is left unchanged. + * Caller must call with pb_lock held. If pb_hold is non-zero after this + * routine decrements it, the page_buf_t is not freed, although it + * is marked as having been freed. + */ + +void _pagebuf_free_object( + page_buf_t * pb, /* buffer to deallocate */ + unsigned long flags) /* interrupt state to restore */ +{ +#ifdef REMAPPING_SUPPORT + void *vaddr = NULL; +#endif + + PB_TRACE(pb, PB_TRACE_REC(free_obj), 0); + if (!(pb->pb_flags & PBF_FREED)) { +#ifdef REMAPPING_SUPPORT + /* release any virtual mapping */ ; + if (pb->pb_flags & _PBF_ADDR_ALLOCATED) + vaddr = pagebuf_mapout_locked(pb); +#endif + + if (pb->pb_flags & _PBF_MEM_ALLOCATED) { + if (pb->pb_pages) { + /* release the pages in the address list */ + if (pb->pb_pages[0] && + PageSlab(pb->pb_pages[0])) { + /* + * This came from the slab + * allocator free it as such + */ + kfree(pb->pb_addr); + } else { + _pagebuf_freepages(pb); + } + + pb->pb_pages = NULL; + } + pb->pb_flags &= ~_PBF_MEM_ALLOCATED; + } + + pb->pb_flags |= PBF_FREED; + } + pb->pb_hold--; + if (pb->pb_hold == 0) { + /* Drop the spinlock before calling free lockable, + * as it needs to get the pbr_lock. We have set + * PBF_FREED, so anyone doing a lookup should + * skip this pagebuf. + */ + spin_unlock(&PBP(pb)->pb_lock); + if (pb->pb_flags & _PBF_LOCKABLE) + _pagebuf_free_lockable_buffer(pb, flags); + kmem_cache_free(pagebuf_cache, pb); +#ifdef PB_TRACKING + { + int i; + + for (i = 0; (pb_array[i] != pb) && (i < MAX_PB); i++); + if (i < MAX_PB) + pb_array[i] = NULL; + else + printk("Freed unmonitored pagebuf 0x%p\n", pb); + } +#endif + } else { + spin_unlock_irqrestore(&PBP(pb)->pb_lock, flags); + } + +#ifdef REMAPPING_SUPPORT + if (vaddr) { + free_address(vaddr); + } +#endif +} + + +/* + * _pagebuf_lookup_pages + * + * _pagebuf_lookup_pages finds all pages which match the buffer + * in question and the range of file offsets supplied, + * and builds the page list for the buffer, if the + * page list is not already formed or if not all of the pages are + * already in the list. Invalid pages (pages which have not yet been + * read in from disk) are assigned for any pages which are not found. + */ + +int +_pagebuf_lookup_pages( + page_buf_t * pb, + struct address_space *aspace, + page_buf_flags_t flags) +{ + loff_t next_buffer_offset; + unsigned long page_count; + int rval = 0; + unsigned long pi; + unsigned long index; + int all_mapped, good_pages; + struct page *cp, **hash, *cached_page; + int gfp_mask; + + /* For pagebufs where we want to map an address, do not use + * highmem pages - so that we do not need to use kmap resources + * to access the data. + * + * For pages were the caller has indicated there may be resource + * contention (e.g. called from a transaction) do not flush + * delalloc pages to obtain memory. + */ + + if (flags & PBF_DONT_BLOCK) { + gfp_mask = GFP_NOFS; + } else if (flags & PBF_MAPPABLE) { + gfp_mask = GFP_KERNEL; + } else { + gfp_mask = GFP_HIGHUSER; + } + + next_buffer_offset = pb->pb_file_offset + pb->pb_buffer_length; + + good_pages = page_count = (page_buf_btoc(next_buffer_offset) - + page_buf_btoct(pb->pb_file_offset)); + + if (pb->pb_flags & _PBF_ALL_PAGES_MAPPED) { + if ((flags & PBF_MAPPED) && !(pb->pb_flags & PBF_MAPPED)) { + all_mapped = 1; + goto mapit; + } + return (0); + } + + /* assure that we have a page list */ + rval = _pagebuf_get_pages(pb, page_count, flags); + if (rval != 0) + return (rval); + + rval = pi = 0; + cached_page = NULL; + /* enter the pages in the page list */ + index = (pb->pb_file_offset - pb->pb_offset) >> PAGE_CACHE_SHIFT; + for (all_mapped = 1; pi < page_count; pi++, index++) { + if (pb->pb_pages[pi] == 0) { + hash = page_hash(aspace, index); + retry: + cp = __find_lock_page(aspace, index, hash); + if (!cp) { + PB_STATS_INC(pbstats.pb_page_alloc); + if (!cached_page) { + int retry_count = 0; + /* allocate a new page */ + cached_page = alloc_pages(gfp_mask, 0); + + if (!cached_page) { + pagebuf_daemon_wakeup(1); + if (++retry_count < 8) { + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(10); + } + + rval = -ENOMEM; + all_mapped = 0; + continue; + } + } + cp = cached_page; + if (add_to_page_cache_unique(cp, + aspace, index, hash)) + goto retry; + cached_page = NULL; + } else { + PB_STATS_INC(pbstats.pb_page_found); + } + + pb->pb_pages[pi] = cp; + } else { + cp = pb->pb_pages[pi]; + while (TryLockPage(cp)) { + ___wait_on_page(cp); + } + } + + /* Test for the page being valid. There is a special case + * in here for the case where we are reading a pagebuf + * smaller than a page. We want to populate the whole page + * here rather than just the part the caller wanted. That + * way we do not need to deal with partially valid pages. + * We keep the page locked, and in the read path fake out + * the lower layers to issue an I/O for the whole page. + */ + if (!Page_Uptodate(cp)) { + good_pages--; + if ((pb->pb_buffer_length < PAGE_CACHE_SIZE) && + (flags & PBF_READ) && !PageSlab(cp)) { + pb->pb_locked = 1; + } + } + if (!pb->pb_locked) + UnlockPage(cp); + } + if (cached_page) + page_cache_free(cached_page); + +mapit: + pb->pb_flags |= _PBF_MEM_ALLOCATED; + if (all_mapped) { + pb->pb_flags |= _PBF_ALL_PAGES_MAPPED; + /* A single page buffer is always mappable */ + if (page_count == 1) { + pb->pb_addr = + (caddr_t) page_address(pb->pb_pages[0]) + + pb->pb_offset; + pb->pb_flags |= PBF_MAPPED; +#ifdef REMAPPING_SUPPORT + } else if ((flags & PBF_MAPPED) && (pb->pb_offset == 0)) { + if (as_list_len > 64) + purge_addresses(); + pb->pb_addr = (caddr_t) remap_page_array(pb->pb_pages, + page_count, gfp_mask); + if (pb->pb_addr) { + pb->pb_flags |= PBF_MAPPED | + _PBF_ADDR_ALLOCATED; + } + } +#else + } else if (flags & PBF_MAPPED) { + printk("request for a mapped pagebuf > page size\n"); + BUG(); + } +#endif + } + /* If some pages were found with data in them + * we are not in PBF_NONE state. + */ + if (good_pages != 0) { + pb->pb_flags &= ~(PBF_NONE); + if (good_pages != page_count) { + pb->pb_flags |= PBF_PARTIAL; + } + } + + PB_TRACE(pb, PB_TRACE_REC(look_pg), good_pages); + + return (rval); +} + + +/* + * Finding and Reading Buffers + */ + +/* + * pagebuf_find + * + * pagebuf_find returns a buffer matching the specified range of + * data for the specified target, if any of the relevant blocks + * are in memory. The buffer may have unallocated holes, if + * some, but not all, of the blocks are in memory. Even where + * pages are present in the buffer, not all of every page may be + * valid. The file system may use pagebuf_segment to visit the + * various segments of the buffer. pagebuf_find will return an + * empty buffer (with no storage allocated) if the fifth argument + * is TRUE. + */ + +page_buf_t *pagebuf_find( /* find buffer for block if */ + /* the block is in memory */ + pb_target_t *target, /* target for block */ + loff_t ioff, /* starting offset of range */ + size_t isize, /* length of range */ + page_buf_flags_t flags) /* PBF_LOCK, PBF_ALWAYS_ALLOC */ +{ + page_buf_t *pb = NULL; + + spin_lock_irq(&target->pbr_lock); + _pagebuf_find_lockable_buffer(target, ioff, isize, flags, &pb); + + return (pb); +} + + +/* + * pagebuf_get + * + * pagebuf_get assembles a buffer covering the specified range. + * Some or all of the blocks in the range may be valid. The file + * system may use pagebuf_segment to visit the various segments + * of the buffer. Storage in memory for all portions of the + * buffer will be allocated, although backing storage may not be. + * If PBF_READ is set in flags, pagebuf_read + */ + +page_buf_t *pagebuf_get( /* allocate a buffer */ + pb_target_t *target, /* target for buffer (or NULL) */ + loff_t ioff, /* starting offset of range */ + size_t isize, /* length of range */ + page_buf_flags_t flags) /* PBF_LOCK, PBF_TRYLOCK, PBF_READ, */ + /* PBF_LONG_TERM, PBF_SEQUENTIAL, */ + /* PBF_MAPPED */ +{ + int rval; + page_buf_t *pb; + + /* Enforce alignment of pagebufs on sector boundaries */ + if ((ioff & (target->pbr_sector - 1)) || + (isize & (target->pbr_sector - 1))) { + printk("Bad alignment of pagebuf offset %Ld size %d\n", + ioff, isize); + + BUG(); + } + + rval = _pagebuf_get_lockable_buffer(target, ioff, isize, flags, &pb); + + if (rval != 0) + return (NULL); + + PB_STATS_INC(pbstats.pb_get); + + /* fill in any missing pages */ + rval = _pagebuf_lookup_pages(pb, PB_ADDR_SPACE(pb), flags); + if (rval != 0) { + pagebuf_free(pb); + return (NULL); + } + + /* Always fill in the block number now, the mapped cases can do + * their own overlay of this later. + */ + + pb->pb_bn = pb->pb_file_offset >> PB_SECTOR_BITS(pb); + pb->pb_count_desired = pb->pb_buffer_length; + + if (flags & PBF_READ) { + if (PBF_NOT_DONE(pb)) { + PB_TRACE(pb, PB_TRACE_REC(get_read), flags); + pagebuf_iostart(pb, flags); + } else if (flags & PBF_ASYNC) { + /* Read ahead call which is already satisfied, + * drop the buffer + */ + if (flags & (PBF_LOCK | PBF_TRYLOCK)) + pagebuf_unlock(pb); + pagebuf_rele(pb); + return NULL; + } else { + /* We do not want read in the flags */ + pb->pb_flags &= ~PBF_READ; + } + } + + PB_TRACE(pb, PB_TRACE_REC(get_obj), flags); + + return (pb); +} + +/* + * Create a pagebuf and populate it with pages from the address + * space of the passed in inode. + */ + +page_buf_t *pagebuf_lookup( + struct inode *inode, + loff_t ioff, + size_t isize, + int flags) +{ + page_buf_t *pb = NULL; + int status; + + _pagebuf_get_object(NULL, ioff, isize, flags, &pb); + if (pb) { + pb->pb_sector_bits = inode->i_sb->s_blocksize_bits; + pb->pb_dev = inode->i_sb->s_dev; + if (flags & PBF_ENTER_PAGES) { + status = _pagebuf_lookup_pages(pb, &inode->i_data, 0); + if (status != 0) { + pagebuf_free(pb); + return (NULL); + } + } + } + return (pb); +} + +/* + * If we are not low on memory then do the readahead in a deadlock + * safe manner. + */ +void +pagebuf_readahead( + pb_target_t * target, /* target for buffer (or NULL) */ + loff_t ioff, /* starting offset of range */ + size_t isize, /* length of range */ + int flags) /* extra flags for the read */ +{ + if (!free_shortage()) { + (void)pagebuf_get(target, ioff, isize, + flags | PBF_TRYLOCK | PBF_READ | + PBF_ASYNC | PBF_MAPPABLE); + } +} + +page_buf_t * +pagebuf_get_empty(pb_target_t *target) +{ + int rval; + int flags = _PBF_LOCKABLE; + page_buf_t *pb; + + rval = _pagebuf_get_object(target, 0, 0, flags, &pb); + return ((rval != 0) ? NULL : pb); +} + +int +pagebuf_associate_memory( + page_buf_t *pb, + void *mem, + size_t len) +{ + int rval; + int i = 0; + size_t ptr; + size_t end, end_cur; + off_t offset; + int page_count = PAGE_CACHE_ALIGN(len) >> PAGE_CACHE_SHIFT; + + offset = (off_t) mem - ((off_t)mem & PAGE_CACHE_MASK); + if (offset && (len > PAGE_CACHE_SIZE)) + page_count++; + + /* Free any previous set of page pointers */ + if (pb->pb_pages && (pb->pb_pages != pb->pb_page_array)) { + kfree(pb->pb_pages); + } + pb->pb_pages = NULL; + pb->pb_addr = mem; + + rval = _pagebuf_get_pages(pb, page_count, 0); + if (0 != rval) { + return (rval); + } + pb->pb_offset = offset; + ptr = (size_t) mem & PAGE_CACHE_MASK; + end = PAGE_CACHE_ALIGN((size_t) mem + len); + end_cur = end; + /* set up first page */ + pb->pb_pages[0] = virt_to_page(mem); + + ptr += PAGE_CACHE_SIZE; + pb->pb_page_count = ++i; + while (ptr < end) { + pb->pb_pages[i] = virt_to_page(ptr); + pb->pb_page_count = ++i; + ptr += PAGE_CACHE_SIZE; + } + pb->pb_locked = 0; + + pb->pb_count_desired = pb->pb_buffer_length = len; + pb->pb_flags |= PBF_MAPPED; + + return 0; +} + +page_buf_t * +pagebuf_get_no_daddr(size_t len, pb_target_t *target) +{ + int rval; + void *rmem = NULL; + int flags = _PBF_LOCKABLE | PBF_FORCEIO; + page_buf_t *pb; + size_t tlen = 0; + + if (len > 0x20000) + return(NULL); + + rval = _pagebuf_get_object(target, 0, len, flags, &pb); + + if (0 != rval) + return (NULL); + + do { + if (tlen == 0){ + tlen = len; /* first time */ + } else { + kfree(rmem); /* free the mem from the previous try */ + tlen <<= 1; /* double the size and try again */ + /* + printk( "pb_get_no_daddr NOT block 0x%p mask 0x%p len %d\n", + rmem, + ((size_t)rmem & (size_t)~BBMASK), + len); + */ + } + if ((rmem = kmalloc(tlen, GFP_KERNEL)) == 0) { + pagebuf_free(pb); + return (NULL); + } + } while ((size_t)rmem != ((size_t)rmem & (size_t)~BBMASK)); + + if ((rval = pagebuf_associate_memory(pb, rmem, len)) != 0) { + kfree(rmem); + pagebuf_free(pb); + return (NULL); + } + /* otherwise pagebuf_free just ignores it */ + pb->pb_flags |= _PBF_MEM_ALLOCATED; + + PB_TRACE(pb, PB_TRACE_REC(no_daddr), rmem); + + return (pb); +} + + +/* + * pagebuf_hold + * + * Increment reference count on buffer, to hold the buffer concurrently + * with another thread which may release (free) the buffer asynchronously. + * + * Must hold the buffer already to call this function. + */ + +void pagebuf_hold(page_buf_t * pb) +{ + unsigned long flags; + + if (pb != NULL) { + spin_lock_irqsave(&PBP(pb)->pb_lock, flags); + assert(pb->pb_hold > 0); + pb->pb_hold++; + spin_unlock_irqrestore(&PBP(pb)->pb_lock, flags); + + PB_TRACE(pb, PB_TRACE_REC(hold), 0); + } +} + + +/* + * pagebuf_free + * + * pagebuf_free releases the specified buffer. The modification + * state of any associated pages is left unchanged. + */ + +void pagebuf_free( /* deallocate a buffer */ + page_buf_t * pb) /* buffer to deallocate */ +{ + unsigned long flags; + + spin_lock_irqsave(&PBP(pb)->pb_lock, flags); + _pagebuf_free_object(pb, flags); +} + + +/* + * pagebuf_rele + * + * pagebuf_rele releases a hold on the specified buffer. If the + * the hold count is 1, pagebuf_rele calls pagebuf_free. + */ + +void pagebuf_rele(page_buf_t * pb) +{ + int do_free; + unsigned long flags; + + PB_TRACE(pb, PB_TRACE_REC(rele), pb->pb_relse); + spin_lock_irqsave(&PBP(pb)->pb_lock, flags); + + if (pb->pb_hold == 1) { + do_free = 1; + if (pb->pb_relse) { + spin_unlock_irqrestore(&PBP(pb)->pb_lock, flags); + (*(pb->pb_relse)) (pb); + do_free = 0; + } + if (pb->pb_flags & PBF_DELWRI) { + pb->pb_flags |= PBF_ASYNC; + if (do_free) + spin_unlock_irqrestore(&PBP(pb)->pb_lock,flags); + pagebuf_delwri_queue(pb, 0); + do_free = 0; + } + + if (do_free) { + _pagebuf_free_object(pb, flags); + } + } else { + pb->pb_hold--; + spin_unlock_irqrestore(&PBP(pb)->pb_lock, flags); + } +} + + +/* + * Pinning Buffer Storage in Memory + */ + +/* + * pagebuf_pin + * + * pagebuf_pin locks all of the memory represented by a buffer in + * memory. Multiple calls to pagebuf_pin and pagebuf_unpin, for + * the same or different buffers affecting a given page, will + * properly count the number of outstanding "pin" requests. The + * buffer may be released after the pagebuf_pin and a different + * buffer used when calling pagebuf_unpin, if desired. + * pagebuf_pin should be used by the file system when it wants be + * assured that no attempt will be made to force the affected + * memory to disk. It does not assure that a given logical page + * will not be moved to a different physical page. Only the + * raw_count field of mem_map_t can in general assure that a + * logical page will not be moved to a different physical page. + */ + +void pagebuf_pin( /* pin buffer in memory */ + page_buf_t * pb) /* buffer to pin */ +{ + atomic_inc(&PBP(pb)->pb_pin_count); + PB_TRACE(pb, PB_TRACE_REC(pin), PBP(pb)->pb_pin_count.counter); +} + + +/* + * pagebuf_unpin + * + * pagebuf_unpin reverses the locking of memory performed by + * pagebuf_pin. Note that both functions affected the logical + * pages associated with the buffer, not the buffer itself. + */ + +void pagebuf_unpin( /* unpin buffered data */ + page_buf_t * pb) /* buffer to unpin */ +{ + if (atomic_dec_and_test(&PBP(pb)->pb_pin_count)) { + wake_up(&PBP(pb)->pb_waiters); + } + PB_TRACE(pb, PB_TRACE_REC(unpin), PBP(pb)->pb_pin_count.counter); +} + +int +pagebuf_ispin(page_buf_t *pb) { + return atomic_read(&PBP(pb)->pb_pin_count); +} +/* + * pagebuf_wait_unpin + * + * pagebuf_wait_unpin waits until all of the memory associated + * with the buffer is not longer locked in memory. It returns + * immediately if none of the affected pages are locked. + */ + +static inline void _pagebuf_wait_unpin(page_buf_t * pb) +{ + DECLARE_WAITQUEUE(wait, current); + + if (atomic_read(&PBP(pb)->pb_pin_count) == 0) { + return; + } + + add_wait_queue(&PBP(pb)->pb_waiters, &wait); + for (;;) { + current->state = TASK_UNINTERRUPTIBLE; + if (atomic_read(&PBP(pb)->pb_pin_count) == 0) { + break; + } + run_task_queue(&tq_disk); + schedule(); + } + remove_wait_queue(&PBP(pb)->pb_waiters, &wait); + current->state = TASK_RUNNING; +} + +void pagebuf_wait_unpin( /* wait for buffer to be unpinned */ + page_buf_t * pb) /* buffer for which to wait */ +{ + _pagebuf_wait_unpin(pb); +} + +/* + * Buffer Utility Routines + */ + +/* + * pagebuf_geterror + * + * pagebuf_geterror returns the error stored in the buffer, or 0 if + * there is no error. + */ + +int pagebuf_geterror( /* return buffer error */ + page_buf_t * pb) /* buffer */ +{ + return (pb->pb_error); +} + + +/* + * pagebuf_iodone + * + * pagebuf_iodone marks a buffer for which I/O is in progress + * done with respect to that I/O. The pb_done routine, if + * present, will be called as a side-effect. + */ + +void pagebuf_iodone( /* mark buffer I/O complete */ + page_buf_t * pb) /* buffer to mark */ +{ + pb->pb_flags &= ~(PBF_READ | PBF_WRITE); + if (pb->pb_error == 0) { + pb->pb_flags &= + ~(PBF_PARTIAL | PBF_NONE); + } + + PB_TRACE(pb, PB_TRACE_REC(done), pb->pb_iodone); + + /* If we were on the delwri list, dequeue if there is no one waiting */ + if ((pb->pb_flags & PBF_ASYNC) && + (pb->pb_list.next != &pb->pb_list)) + pagebuf_delwri_dequeue(pb); + + if (pb->pb_iodone) { + (*(pb->pb_iodone)) (pb); + return; + } + + if (pb->pb_flags & PBF_ASYNC) { + if ((pb->pb_flags & _PBF_LOCKABLE) && !pb->pb_relse) + pagebuf_unlock(pb); + pagebuf_rele(pb); + } else { + up(&PBP(pb)->pb_iodonesema); + } +} + +/* + * pagebuf_ioerror + * + * pagebuf_ioerror sets the error code for a buffer. + */ + +void pagebuf_ioerror( /* mark buffer in error (or not) */ + page_buf_t * pb, /* buffer to mark */ + int serror) /* error to store (0 if none) */ +{ + pb->pb_error = serror; + PB_TRACE(pb, PB_TRACE_REC(ioerror), serror); +} + +/* + * pagebuf_iostart + * + * pagebuf_iostart initiates I/O on a buffer, based on the flags supplied. + * If necessary, it will arrange for any disk space allocation required, + * and it will break up the request if the block mappings require it. + * An pb_iodone routine in the buffer supplied will only be called + * when all of the subsidiary I/O requests, if any, have been completed. + * pagebuf_iostart calls the pagebuf_ioinitiate routine or + * pagebuf_iorequest, if the former routine is not defined, to start + * the I/O on a given low-level request. + */ + +int pagebuf_iostart( /* start I/O on a buffer */ + page_buf_t * pb, /* buffer to start */ + page_buf_flags_t flags) /* PBF_LOCK, PBF_ASYNC, PBF_READ, */ + /* PBF_WRITE, PBF_ALLOCATE, */ + /* PBF_DELWRI, PBF_SEQUENTIAL, */ + /* PBF_SYNC, PBF_DONT_BLOCK */ + /* PBF_RELEASE */ +{ + int status = 0; + + PB_TRACE(pb, PB_TRACE_REC(iostart), flags); + + if (flags & PBF_DELWRI) { + pb->pb_flags &= ~(PBF_READ | PBF_WRITE | PBF_ASYNC); + pb->pb_flags |= flags & + (PBF_DELWRI | PBF_ASYNC | PBF_SYNC); + pagebuf_delwri_queue(pb, 1); + return status; + } + + pb->pb_flags &= ~(PBF_READ | PBF_WRITE | PBF_ASYNC | PBF_DELWRI); + pb->pb_flags |= flags & (PBF_READ | PBF_WRITE | PBF_ASYNC | PBF_SYNC); + + if (pb->pb_bn == PAGE_BUF_DADDR_NULL) { + BUG(); + } + /* For writes call internal function which checks for + * filesystem specific callout function and execute it. + */ + if (flags & PBF_WRITE) { + status = __pagebuf_iorequest(pb); + } else { + status = pagebuf_iorequest(pb); + } + + /* Wait for I/O if we are not an async request */ + if ((status == 0) && (flags & PBF_ASYNC) == 0) { + status = pagebuf_iowait(pb); + if (flags & (PBF_WRITE| PBF_DELWRI)) + pagebuf_rele(pb); + } + + return status; +} + +/* Helper routines for pagebuf_iorequest */ + +typedef struct { + page_buf_t *pb; /* pointer to pagebuf page is within */ + int locking; /* are pages locked */ + atomic_t remain; /* count of remaining I/O requests */ +} pagesync_t; + +static inline void _pb_io_done(page_buf_t *pb) +{ + if (atomic_dec_and_test(&PBP(pb)->pb_io_remaining) == 1) { + pb->pb_locked = 0; + pagebuf_iodone(pb); + } +} + + +/* I/O completion routine for pagebuf I/O on a page, can be used for a + * page without a pagebuf - the pb field in pagesync_t is not set. + */ +STATIC void _end_pagebuf_page_io(struct buffer_head *bh, int uptodate) +{ + struct page *page; + page_buf_t *pb = (page_buf_t *) bh->b_private; + + mark_buffer_uptodate(bh, uptodate); + atomic_dec(&bh->b_count); + + page = bh->b_page; + if (!test_bit(BH_Uptodate, &bh->b_state)) { + set_bit(PG_error, &page->flags); + pb->pb_error = -EIO; + } + + unlock_buffer(bh); + kmem_cache_free(bh_cachep, bh); + + SetPageUptodate(page); + _pb_io_done(pb); +} + +STATIC void _end_pagebuf_page_io_locked(struct buffer_head *bh, int uptodate) +{ + struct page *page; + page_buf_t *pb = (page_buf_t *) bh->b_private; + + mark_buffer_uptodate(bh, uptodate); + atomic_dec(&bh->b_count); + + page = bh->b_page; + if (!test_bit(BH_Uptodate, &bh->b_state)) { + set_bit(PG_error, &page->flags); + pb->pb_error = -EIO; + } + + unlock_buffer(bh); + kmem_cache_free(bh_cachep, bh); + + SetPageUptodate(page); + UnlockPage(page); + _pb_io_done(pb); +} + +STATIC void _end_pagebuf_page_io_multi(struct buffer_head *bh, int uptodate) +{ + pagesync_t *psync = (pagesync_t *) bh->b_private; + page_buf_t *pb = psync->pb; + struct page *page; + + mark_buffer_uptodate(bh, uptodate); + atomic_dec(&bh->b_count); + + page = bh->b_page; + if (!test_bit(BH_Uptodate, &bh->b_state)) { + set_bit(PG_error, &page->flags); + pb->pb_error = -EIO; + } + + unlock_buffer(bh); + kmem_cache_free(bh_cachep, bh); + + if (atomic_dec_and_test(&psync->remain) == 1) { + SetPageUptodate(page); + if (psync->locking) + UnlockPage(page); + kfree(psync); + _pb_io_done(pb); + } +} + +/* + * Initiate I/O on part of a page we are interested in + * + * This will attempt to make a request bigger than the sector + * size if we are not running on the MD device - LVM need to be + * added to this logic as well. + * + * If you think this change is causing problems initializing the + * concat_ok variable will turn it off again. + */ +STATIC int +_pagebuf_page_io( + struct page *page, /* Page structure we are dealing with */ + page_buf_t * pb, /* pagebuf holding it, can be NULL */ + page_buf_daddr_t bn, /* starting block number */ + kdev_t dev, /* device for I/O */ + size_t sector, /* device block size */ + int sshift, /* device block shift */ + off_t pg_offset, /* starting offset in page */ + size_t pg_length, /* count of data to process */ + int locking, /* page locking in use */ + int rw) /* read/write operation */ +{ + int cnt,itr; + pagesync_t *psync = NULL; + struct buffer_head *bh, *bufferlist[8]; + size_t blk_length; + int err=0; + int concat_ok; + + if ((MAJOR(dev) != LVM_BLK_MAJOR) && (MAJOR(dev) != MD_MAJOR)) { + concat_ok = 1; + } else if ((MAJOR(dev) == MD_MAJOR) && (pg_offset == 0) && + ((bn & (PAGE_CACHE_MASK >> 9)) == bn)) { + concat_ok = 1; + } else { + concat_ok = 0; + } + + /* Calculate the block offsets and length we will be using */ + if (pg_offset) { + size_t block_offset; + + block_offset = pg_offset >> sshift; + block_offset = pg_offset - (block_offset << sshift); + blk_length = (pg_length + block_offset + sector - 1) >> sshift; + } else { + blk_length = (pg_length + sector - 1) >> sshift; + } + + if (concat_ok) { + /* This should just create one buffer head */ + sector *= blk_length; + blk_length = 1; + } + + /* Allocate pagesync_t and buffer heads for portions of the + * page which need I/O. + * Call generic_make_request + */ + + if (blk_length != 1) { + psync = (pagesync_t *) kmalloc(sizeof(pagesync_t), GFP_NOFS); + + /* Ugh - out of memory condition here */ + if (psync == NULL) + BUG(); + + psync->pb = pb; + psync->locking = locking; + atomic_set(&psync->remain, 0); + } + + for (cnt = 0; blk_length > 0; + blk_length--, pg_offset += sector) { + bh = kmem_cache_alloc(bh_cachep, SLAB_NOFS); + if (bh == NULL){ + err = -ENOMEM; + goto error; + } + memset(bh, 0, sizeof(*bh)); + init_waitqueue_head(&bh->b_wait); + + if (psync) { + init_buffer(bh, _end_pagebuf_page_io_multi, psync); + atomic_inc(&psync->remain); + } else if (locking) { + init_buffer(bh, _end_pagebuf_page_io_locked, pb); + } else { + init_buffer(bh, _end_pagebuf_page_io, pb); + } + + bh->b_size = sector; + set_bh_page(bh, page, pg_offset); + atomic_set(&bh->b_count, 1); + bh->b_dev = dev; + bh->b_blocknr = bn++; + + bh->b_rdev = bh->b_dev; + bh->b_rsector = bh->b_blocknr; + set_bit(BH_Lock, &bh->b_state); + set_bit(BH_Mapped, &bh->b_state); + + if (rw == WRITE ) { + set_bit(BH_Uptodate, &bh->b_state); + set_bit(BH_Dirty, &bh->b_state); + } + bufferlist[cnt++] = bh; + } + + if (cnt) { + /* Indicate that there is another page in progress */ + atomic_inc(&PBP(pb)->pb_io_remaining); + + for (itr=0; itr < cnt; itr++){ + generic_make_request(rw, bufferlist[itr]); + } + } else { + if (psync) + kfree(psync); + if (locking) + UnlockPage(page); + } + + return err; +error: + /* If we ever do get here then clean up what we already did */ + for (itr=0; itr < cnt; itr++) { + atomic_set_buffer_clean (bufferlist[itr]); + bufferlist[itr]->b_end_io(bufferlist[itr], 0); + } + return err; +} + +/* Apply function for pagebuf_segment_apply */ +STATIC int _page_buf_page_apply( + page_buf_t * pb, + loff_t offset, + struct page *page, + size_t pg_offset, + size_t pg_length) +{ + page_buf_daddr_t bn = pb->pb_bn; + kdev_t dev = pb->pb_dev; + int sshift = PB_SECTOR_BITS(pb); + size_t sector = 1 << sshift; + loff_t pb_offset; + size_t ret_len = pg_length; + assert(page); + + if ((pb->pb_buffer_length < PAGE_CACHE_SIZE) && + (pb->pb_flags & PBF_READ) && pb->pb_locked) { + bn -= (pb->pb_offset >> sshift); + pg_offset = 0; + pg_length = PAGE_CACHE_SIZE; + } else { + pb_offset = offset - pb->pb_file_offset; + if (pb_offset) { + bn += (pb_offset + sector - 1) >> sshift; + } + } + + if (pb->pb_flags & PBF_READ) { + /* We only need to do I/O on pages which are not upto date */ + while (!Page_Uptodate(page) || (pb->pb_flags & PBF_FORCEIO)) { + /* Attempt to lock page */ + if (pb->pb_locked || !TryLockPage(page)) { + _pagebuf_page_io(page, pb, bn, dev, + sector, sshift, + (off_t) pg_offset, pg_length, 1, READ); + + /* When doing the I/O we need to setup a + * completion routine which gets called for + * each buffer_head completion. On completion + * we will need to decrement a count and + * mark the section of the page we deal + * with upto date. Once the count reaches + * zero we can update the PG_uptodate + * and PG_partial fields, unlock the page + * and wake up page waiters. + * + * We also need to locate the pagebuf and + * decrement the a count of pending I/O, + * should this count reach zero we need + * to call the pagebuf_iodone() function. + */ + + break; + } else { + /* we could not lock the page, this means + * someone else is doing I/O in this page, + * the possibilities are that either their + * I/O will satisfy our I/O, or that we will + * still need to do I/O when they are done. + * There is no way to tell this until we can + * lock the page - ugh! + */ + ___wait_on_page(page); + } + } + } else if (pb->pb_flags & PBF_WRITE) { + int locking = (pb->pb_flags & _PBF_LOCKABLE) == 0; + + /* Check we need to lock pages */ + if (locking && (pb->pb_locked == 0)) + lock_page(page); + _pagebuf_page_io(page, pb, bn, dev, sector, sshift, + (off_t) pg_offset, pg_length, locking, WRITE); + } + + return (ret_len); +} + +/* + * pagebuf_iorequest + * + * pagebuf_iorequest is the core I/O request routine. + * It assumes that the buffer is well-formed and + * mapped and ready for physical I/O, unlike + * pagebuf_iostart() and pagebuf_iophysio(). Those + * routines call the pagebuf_ioinitiate routine to start I/O, + * if it is present, or else call pagebuf_iorequest() + * directly if the pagebuf_ioinitiate routine is not present. + * + * This function will be responsible for ensuring access to the + * pages is restricted whilst I/O is in progress - for locking + * pagebufs the pagebuf lock is the mediator, for non-locking + * pagebufs the pages will be locked. In the locking case we + * need to use the pagebuf lock as multiple meta-data buffers + * will reference the same page. + */ + +int pagebuf_iorequest( /* start real I/O */ + page_buf_t * pb) /* buffer to convey to device */ +{ + int status = 0; + + assert(pb->pb_flags & _PBF_ALL_PAGES_MAPPED); + + PB_TRACE(pb, PB_TRACE_REC(ioreq), 0); + + if (pb->pb_flags & PBF_DELWRI) { + pagebuf_delwri_queue(pb, 1); + return status; + } + + if (pb->pb_flags & PBF_WRITE) { + _pagebuf_wait_unpin(pb); + } + + /* Set the count to 1 initially, this will stop an I/O + * completion callout which happens before we have started + * all the I/O from calling iodone too early + */ + atomic_set(&PBP(pb)->pb_io_remaining, 1); + status = pagebuf_segment_apply(_page_buf_page_apply, pb); + + /* Drop our count and if everything worked we are done */ + if (atomic_dec_and_test(&PBP(pb)->pb_io_remaining) == 1) { + pagebuf_iodone(pb); + } else if ((pb->pb_flags & (PBF_SYNC|PBF_ASYNC)) == PBF_SYNC) { + run_task_queue(&tq_disk); + } + + return status < 0 ? status : 0; +} + +/* + * pagebuf_iowait + * + * pagebuf_iowait waits for I/O to complete on the buffer supplied. + * It returns immediately if no I/O is pending. In any case, it returns + * the error code, if any, or 0 if there is no error. + */ + +int pagebuf_iowait(page_buf_t * pb) /* buffer to wait on */ +{ + PB_TRACE(pb, PB_TRACE_REC(iowait), 0); + run_task_queue(&tq_disk); + down(&PBP(pb)->pb_iodonesema); + PB_TRACE(pb, PB_TRACE_REC(iowaited), pb->pb_error); + return (pb->pb_error); +} + + +/* reverse pagebuf_mapin() */ +STATIC void +*pagebuf_mapout_locked( + page_buf_t * pb) /* buffer to unmap */ +{ + void *old_addr = NULL; + + if (pb->pb_flags & PBF_MAPPED) { + if (pb->pb_flags & _PBF_ADDR_ALLOCATED) + old_addr = pb->pb_addr; + pb->pb_addr = NULL; + pb->pb_flags &= ~(PBF_MAPPED | _PBF_ADDR_ALLOCATED); + } + + return (old_addr); /* Caller must free the address space, + * we are under a spin lock, probably + * not safe to do vfree here + */ +} + +caddr_t +pagebuf_offset(page_buf_t *pb, off_t offset) +{ + struct page *page; + + offset += pb->pb_offset; + + page = pb->pb_pages[offset >> PAGE_CACHE_SHIFT]; + return (caddr_t) page_address(page) + (offset & (PAGE_CACHE_SIZE - 1)); +} + +/* + * pagebuf_segment + * + * pagebuf_segment is used to retrieve the various contiguous + * segments of a buffer. The variable addressed by the + * loff_t * should be initialized to 0, and successive + * calls will update to point to the segment following the one + * returned. pagebuf_segment returns 0 on a successful + * retrieval, and a negative error code on any error (including + * -ENOENT when the loff_t is out of range). + * + * The mem_map_t * return value may be set to NULL if the + * page is outside of main memory (as in the case of memory on a controller + * card). The page_buf_pgno_t may be set to PAGE_BUF_PGNO_NULL + * as well, if the page is not actually allocated, unless the + * PBF_ALWAYS_ALLOC flag is set in the page_buf_flags_t, + * in which allocation of storage will be forced. + */ + +int pagebuf_segment( /* return next segment of buffer */ + page_buf_t * pb, /* buffer to examine */ + loff_t * boff_p, /* offset in buffer of next */ + /* segment (updated) */ + mem_map_t ** spage_p, /* page (updated) */ + /* (NULL if not in mem_map[]) */ + size_t * soff_p, /* offset in page (updated) */ + size_t * ssize_p, /* length of segment (updated) */ + page_buf_flags_t flags) /* PBF_ALWAYS_ALLOC */ +{ + loff_t kpboff; /* offset in pagebuf */ + int kpi; /* page index in pagebuf */ + size_t slen; /* segment length */ + + kpboff = *boff_p; + + kpi = page_buf_btoct(kpboff + pb->pb_offset); + + *spage_p = pb->pb_pages[kpi]; + + *soff_p = page_buf_poff(kpboff + pb->pb_offset); + slen = PAGE_CACHE_SIZE - *soff_p; + if (slen > (pb->pb_count_desired - kpboff)) + slen = (pb->pb_count_desired - kpboff); + *ssize_p = slen; + + *boff_p = *boff_p + slen; + + return (0); +} + + +int pagebuf_iomove( /* move data in/out of buffer */ + page_buf_t *pb, /* buffer to process */ + off_t boff, /* starting buffer offset */ + size_t bsize, /* length to copy */ + caddr_t data, /* data address */ + page_buf_rw_t mode) /* read/write flag */ +{ + loff_t cboff; + size_t cpoff; + size_t csize; + struct page *page; + + cboff = boff; + boff += bsize; /* last */ + + while (cboff < boff) { + if (pagebuf_segment(pb, &cboff, &page, &cpoff, &csize, 0)) { + /* XXX allocate missing page */ + return (-ENOMEM); + } + assert(((csize + cpoff) <= PAGE_CACHE_SIZE)); + switch (mode) { + case PBRW_ZERO: + memset(page_address(page) + cpoff, 0, csize); + break; + case PBRW_READ: + memcpy(data, page_address(page) + cpoff, csize); + break; + case PBRW_WRITE: + memcpy(page_address(page) + cpoff, data, csize); + } + + data += csize; + } + return 0; +} + +/* + * pagebuf_segment_apply + * + * pagebuf_segment_apply applies the page_buf_apply_t function + * to each segment of the page_buf_t. It may be used to walk + * the segments of a buffer, as when building + * a driver scatter-gather list. + */ + +int pagebuf_segment_apply( /* apply function to segments */ + page_buf_apply_t func, /* function to call */ + page_buf_t * pb) /* buffer to examine */ +{ + int buf_index; + int status = 0; + int sval; + loff_t buffer_offset = pb->pb_file_offset; + size_t buffer_len = pb->pb_count_desired; + size_t page_offset; + size_t len; + size_t total = 0; + size_t cur_offset; + size_t cur_len; + + pagebuf_hold(pb); + + cur_offset = pb->pb_offset; + cur_len = buffer_len; + + for (buf_index = 0; buf_index < pb->pb_page_count; buf_index++) { + if (cur_len == 0) + break; + if (cur_offset >= PAGE_CACHE_SIZE) { + cur_offset -= PAGE_CACHE_SIZE; + continue; + } + + page_offset = cur_offset; + cur_offset = 0; + + len = PAGE_CACHE_SIZE - page_offset; + if (len > cur_len) + len = cur_len; + cur_len -= len; + /* func probably = _page_buf_page_apply */ + sval = func(pb, buffer_offset, + pb->pb_pages[buf_index], page_offset, len); + + if (sval <= 0) { + status = sval; + goto out; + } else { + len = sval; + total += len; + } + + buffer_offset += len; + buffer_len -= len; + } + +out: + pagebuf_rele(pb); + + if (!status) + status = total; + + return (status); +} + +/* + * Pagebuf delayed write buffer handling + */ + + +void +pagebuf_delwri_queue(page_buf_t *pb, int unlock) +{ + unsigned long flags; + + PB_TRACE(pb, PB_TRACE_REC(delwri_q), unlock); + spin_lock_irqsave(&pb_daemon->pb_delwrite_lock, flags); + /* If already in the queue, dequeue and place at tail */ + if (pb->pb_list.next != &pb->pb_list) { + if (unlock) { + spin_lock(&PBP(pb)->pb_lock); + if (pb->pb_hold > 1) pb->pb_hold--; + spin_unlock(&PBP(pb)->pb_lock); + } + list_del(&pb->pb_list); + } else { + pb_daemon->pb_delwri_cnt++; + } + list_add_tail(&pb->pb_list, &pb_daemon->pb_delwrite_l); + PBP(pb)->pb_flushtime = jiffies + pb_params.p_un.age_buffer; + spin_unlock_irqrestore(&pb_daemon->pb_delwrite_lock, flags); + + if (unlock && (pb->pb_flags & _PBF_LOCKABLE)) { + pagebuf_unlock(pb); + } +} + +void +pagebuf_delwri_dequeue(page_buf_t *pb) +{ + unsigned long flags; + + PB_TRACE(pb, PB_TRACE_REC(delwri_uq), 0); + spin_lock_irqsave(&pb_daemon->pb_delwrite_lock, flags); + list_del(&pb->pb_list); + INIT_LIST_HEAD(&pb->pb_list); + pb->pb_flags &= ~PBF_DELWRI; + pb_daemon->pb_delwri_cnt--; + spin_unlock_irqrestore(&pb_daemon->pb_delwrite_lock, flags); +} + +/* Defines for page buf daemon */ +DECLARE_WAIT_QUEUE_HEAD(pbd_waitq); + +STATIC int force_flush; +void +pagebuf_daemon_wakeup(int flag) +{ + force_flush = flag; + if (waitqueue_active(&pbd_waitq)) { + wake_up_interruptible(&pbd_waitq); + } +} + +typedef void (*timeout_fn)(unsigned long); + + +STATIC int +pagebuf_daemon(void *data) +{ + u_long flags; + int count; + page_buf_t *pb = NULL; + struct list_head *head, *curr; + pagebuf_marker_t *pb_marker_ptr; + struct timer_list pb_daemon_timer = + { {NULL, NULL}, 0, 0, (timeout_fn)pagebuf_daemon_wakeup }; + + + pb_marker_ptr = kmalloc(sizeof(pagebuf_marker_t), GFP_KERNEL); + + pb_marker_ptr->pb_flags = 0; + + /* Set up the thread */ + exit_files(current); + daemonize(); + + spin_lock_irqsave(¤t->sigmask_lock, flags); + flush_signals(current); + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + + strcpy(current->comm, "pagebuf_daemon"); + current->flags |= PF_MEMALLOC; + + do { + if (pb_daemon->active == 1) { + del_timer(&pb_daemon_timer); + pb_daemon_timer.expires = jiffies + pb_params.p_un.flush_interval; + add_timer(&pb_daemon_timer); + interruptible_sleep_on(&pbd_waitq); + } + + if (pb_daemon->active == 0) { + del_timer(&pb_daemon_timer); + } + + spin_lock_irqsave(&pb_daemon->pb_delwrite_lock, flags); + + head = curr = &pb_daemon->pb_delwrite_l; + curr = curr->next; /* need to walk off the list head, + * since it just a global place holder */ + + count = 0; + while (curr != head) { + pb = list_entry(curr, page_buf_t, pb_list); + + /* + * Skip other markers. + */ + if (pb->pb_flags == 0 ) { + curr = curr->next; + continue; + } + + PB_TRACE(pb, PB_TRACE_REC(walkq1), pagebuf_ispin(pb)); + + if ((pb->pb_flags & PBF_DELWRI) && !pagebuf_ispin(pb) && + (((pb->pb_flags & _PBF_LOCKABLE) == 0) || + !pagebuf_cond_lock(pb))) { + + if (!force_flush && time_before(jiffies, + PBP(pb)->pb_flushtime)) { + pagebuf_unlock(pb); + break; + } + + pb->pb_flags &= ~PBF_DELWRI; + pb->pb_flags |= PBF_WRITE; + + /* insert a place holder */ + list_add(&pb_marker_ptr->pb_list, curr); + + spin_unlock_irqrestore( + &pb_daemon->pb_delwrite_lock, + flags); + + __pagebuf_iorequest(pb); + count++; + + spin_lock_irqsave( + &pb_daemon->pb_delwrite_lock, + flags); + /* + * ok got the lock back; pick up the place + * holder and continue on + */ + curr = pb_marker_ptr->pb_list.next; + list_del(&pb_marker_ptr->pb_list); + + } else { + /* not doing anything with current... + * move on to the next one */ + curr = curr->next; + } + } + + spin_unlock_irqrestore(&pb_daemon->pb_delwrite_lock, flags); + +#ifdef REMAPPING_SUPPORT + if (as_list_len > 0) + purge_addresses(); +#endif + + if (count) + run_task_queue(&tq_disk); + force_flush = 0; + } while (pb_daemon->active == 1); + + pb_daemon->active = -1; + wake_up_interruptible(&pbd_waitq); + kfree(pb_marker_ptr); + + return(0); +} + + +void +pagebuf_delwri_flush(pb_target_t *target, u_long flags, int *pinptr) +{ + page_buf_t *pb = NULL; + struct list_head *head, *curr; + unsigned long save; + int locked; + int pincount = 0; + pagebuf_marker_t *pb_marker_ptr; + + + pb_marker_ptr = kmalloc(sizeof(pagebuf_marker_t), GFP_KERNEL); + + pb_marker_ptr->pb_flags = 0; + + spin_lock_irqsave(&pb_daemon->pb_delwrite_lock, save); + locked = 1; + + head = curr = &pb_daemon->pb_delwrite_l; + curr = curr->next; /* need to walk off the list head, + * since it just a global place holder */ + + while (curr != head) { + pb = list_entry(curr, page_buf_t, pb_list); + + /* + * Skip other targets, markers and in progress buffers + */ + + if ((pb->pb_flags == 0) || (pb->pb_target != target) || + !(pb->pb_flags & PBF_DELWRI)) { + curr = curr->next; + continue; + } + + PB_TRACE(pb, PB_TRACE_REC(walkq2), pagebuf_ispin(pb)); + + if (flags & PBDF_TRYLOCK) { + if (!pagebuf_cond_lock(pb)) { + pincount++; + curr = curr->next; + continue; + } + } else { + list_add(&pb_marker_ptr->pb_list, curr); + spin_unlock_irqrestore(&pb_daemon->pb_delwrite_lock, + save); + locked = 0; + pagebuf_lock(pb); + } + + if (pagebuf_ispin(pb)) { + pincount++; + pagebuf_unlock(pb); + if (!locked) + goto relock; + curr = curr->next; + continue; + } + + pb->pb_flags &= ~PBF_DELWRI; + pb->pb_flags |= PBF_WRITE; + if (flags & PBDF_WAIT) + pb->pb_flags &= ~PBF_ASYNC; + + if (locked) { + list_add(&pb_marker_ptr->pb_list, curr); + spin_unlock_irqrestore(&pb_daemon->pb_delwrite_lock, + save); + } + + __pagebuf_iorequest(pb); + +relock: + spin_lock_irqsave( &pb_daemon->pb_delwrite_lock, + save); + /* + * ok got the lock back; pick up the place + * holder and continue on + */ + curr = pb_marker_ptr->pb_list.next; + list_del(&pb_marker_ptr->pb_list); + locked = 1; + } + + spin_unlock_irqrestore(&pb_daemon->pb_delwrite_lock, save); + + run_task_queue(&tq_disk); + + if (pinptr) + *pinptr = pincount; + + if ((flags & PBDF_WAIT) == 0 ){ + kfree(pb_marker_ptr); + return; + } + + /* + * The problem to solve here: if you find a buffer on the + * delwri queue, under protection of "pb_delwrite_lock", + * and it's had I/O initiated via the above loop, as soon + * as you drop "pb_delwrite_lock" it can turn into somebody + * else's buffer before you can try to lock/unlock it in + * order to synchronize with it. + */ + + + /* Now do that again, just waiting for the lock */ + spin_lock_irqsave(&pb_daemon->pb_delwrite_lock, flags); + + head = curr = &pb_daemon->pb_delwrite_l; + curr = curr->next; + + + while (curr != head) { + + pb = list_entry(curr, page_buf_t, pb_list); + + /* + * Skip stuff we do not care about + */ + if ((pb->pb_flags == 0) || (pb->pb_flags & PBF_DELWRI) || + (pb->pb_target != target)) { + curr = curr->next; + continue; + } + + PB_TRACE(pb, PB_TRACE_REC(walkq3), pagebuf_ispin(pb)); + + if (pb->pb_flags & PBF_ASYNC) { + curr = curr->next; + continue; + } + + list_add(&pb_marker_ptr->pb_list, curr); + + spin_unlock_irqrestore( &pb_daemon->pb_delwrite_lock, flags); + pagebuf_iowait(pb); + pagebuf_delwri_dequeue(pb); + if (!pb->pb_relse) + pagebuf_unlock(pb); + pagebuf_rele(pb); + + spin_lock_irqsave(&pb_daemon->pb_delwrite_lock, flags); + + curr = pb_marker_ptr->pb_list.next; + list_del(&pb_marker_ptr->pb_list); + } + + spin_unlock_irqrestore(&pb_daemon->pb_delwrite_lock, flags); + + kfree(pb_marker_ptr); +} + +static int pagebuf_daemon_start(void) +{ + + if (!pb_daemon){ + pb_daemon = (pagebuf_daemon_t *) + kmalloc(sizeof(pagebuf_daemon_t), GFP_KERNEL); + if (!pb_daemon){ + return -1; /* error */ + } + + pb_daemon->active = 1; + pb_daemon->pb_delwri_cnt = 0; + pb_daemon->pb_delwrite_lock = SPIN_LOCK_UNLOCKED; + + INIT_LIST_HEAD(&pb_daemon->pb_delwrite_l); + + if (0 > kernel_thread(pagebuf_daemon, (void *)pb_daemon, + CLONE_FS|CLONE_FILES|CLONE_SIGHAND)) { + printk("Can't start pagebuf daemon\n"); + kfree(pb_daemon); + return -1; /* error */ + } + } + return 0; +} + +static int __exit pagebuf_daemon_stop(void) +{ + if (pb_daemon) { + pb_daemon->active = 0; + + wake_up_interruptible(&pbd_waitq); + + while (pb_daemon->active == 0) { + interruptible_sleep_on(&pbd_waitq); + } + + kfree(pb_daemon); + pb_daemon = NULL; + } + + return 0; +} + +/* + * Pagebuf sysctl interface + */ + +static struct ctl_table_header *pagebuf_table_header; + + +static ctl_table pagebuf_table[] = { + {PB_FLUSH_INT, "flush_int", &pb_params.data[0], + sizeof(int), 0644, NULL, &proc_doulongvec_ms_jiffies_minmax, + &sysctl_intvec, NULL, &pagebuf_min[0], &pagebuf_max[0]}, + {PB_FLUSH_AGE, "flush_age", &pb_params.data[1], + sizeof(int), 0644, NULL, &proc_doulongvec_ms_jiffies_minmax, + &sysctl_intvec, NULL, &pagebuf_min[1], &pagebuf_max[1]}, + {PB_DIO_MAX, "max_dio_pages", &pb_params.data[2], + sizeof(int), 0644, NULL, &proc_doulongvec_minmax, &sysctl_intvec, NULL, + &pagebuf_min[2], &pagebuf_max[2]}, +#ifdef PAGEBUF_TRACE + {PB_DEBUG, "debug", &pb_params.data[3], + sizeof(int), 0644, NULL, &proc_doulongvec_minmax, &sysctl_intvec, NULL, + &pagebuf_min[3], &pagebuf_max[3]}, +#endif + {0} +}; + +static ctl_table pagebuf_dir_table[] = { + {VM_PAGEBUF, "pagebuf", NULL, 0, 0555, pagebuf_table}, + {0} +}; + +static ctl_table pagebuf_root_table[] = { + {CTL_VM, "vm", NULL, 0, 0555, pagebuf_dir_table}, + {0} +}; + +#ifdef CONFIG_PROC_FS +static int +pagebuf_readstats(char *buffer, char **start, off_t offset, + int count, int *eof, void *data) +{ + int i, len; + + len = 0; + len += sprintf(buffer + len, "pagebuf"); + for (i = 0; i < sizeof(pbstats) / sizeof(u_int32_t); i++) { + len += sprintf(buffer + len, " %u", + *(((u_int32_t*)&pbstats) + i)); + } + buffer[len++] = '\n'; + + if (offset >= len) { + *start = buffer; + *eof = 1; + return 0; + } + *start = buffer + offset; + if ((len -= offset) > count) + return count; + *eof = 1; + + return len; +} +#endif /* CONFIG_PROC_FS */ + + +/* + * Initialization and Termination + */ + +/* + * pagebuf_init + */ + +static int __init pagebuf_init(void) +{ + pagebuf_table_header = register_sysctl_table(pagebuf_root_table, 1); + +#ifdef CONFIG_PROC_FS + if (proc_mkdir("fs/pagebuf", 0)) + create_proc_read_entry("fs/pagebuf/stat", 0, 0, pagebuf_readstats, NULL); +#endif + + avl_init(); + pagebuf_locking_init(); + if (pagebuf_cache == NULL) { + pagebuf_cache = kmem_cache_create("page_buf_t", + sizeof(page_buf_private_t), + 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + if (pagebuf_cache == NULL) + return (-ENOMEM); + } + +#ifdef PAGEBUF_TRACE + pb_trace.buf = (pagebuf_trace_t *)kmalloc(PB_TRACE_BUFSIZE * + sizeof(pagebuf_trace_t), GFP_KERNEL); +/* For really really long trace bufs */ +/* pb_trace.buf = (pagebuf_trace_t *)vmalloc(PB_TRACE_BUFSIZE * sizeof(pagebuf_trace_t)); */ + memset(pb_trace.buf, 0, PB_TRACE_BUFSIZE * sizeof(pagebuf_trace_t)); + pb_trace.start = 0; + pb_trace.end = PB_TRACE_BUFSIZE - 1; +#endif + + pagebuf_daemon_start(); + + return (0); +} + + +/* + * Module management + */ + +EXPORT_SYMBOL(pagebuf_delwri_flush); +EXPORT_SYMBOL(pagebuf_delwri_queue); +EXPORT_SYMBOL(pagebuf_delwri_dequeue); + +EXPORT_SYMBOL(pagebuf_find); +EXPORT_SYMBOL(pagebuf_get); +EXPORT_SYMBOL(pagebuf_associate_memory); +EXPORT_SYMBOL(pagebuf_get_no_daddr); +EXPORT_SYMBOL(pagebuf_get_empty); +EXPORT_SYMBOL(pagebuf_hold); +EXPORT_SYMBOL(pagebuf_free); +EXPORT_SYMBOL(pagebuf_rele); +EXPORT_SYMBOL(pagebuf_geterror); +EXPORT_SYMBOL(pagebuf_iodone); +EXPORT_SYMBOL(pagebuf_ioerror); +EXPORT_SYMBOL(pagebuf_iostart); +EXPORT_SYMBOL(pagebuf_iorequest); +EXPORT_SYMBOL(pagebuf_iowait); +EXPORT_SYMBOL(pagebuf_offset); +EXPORT_SYMBOL(pagebuf_segment); +EXPORT_SYMBOL(pagebuf_iomove); +EXPORT_SYMBOL(pagebuf_pin); +EXPORT_SYMBOL(pagebuf_ispin); +EXPORT_SYMBOL(pagebuf_unpin); +EXPORT_SYMBOL(pagebuf_wait_unpin); +EXPORT_SYMBOL(pagebuf_readahead); +EXPORT_SYMBOL(pagebuf_lookup); +EXPORT_SYMBOL(pagebuf_daemon_wakeup); + + +/* + * pagebuf_terminate + */ + +void __exit pagebuf_terminate(void) +{ + if (pagebuf_cache != NULL) + kmem_cache_destroy(pagebuf_cache); + pagebuf_daemon_stop(); + pagebuf_locking_terminate(); + avl_terminate(); + unregister_sysctl_table(pagebuf_table_header); +#ifdef CONFIG_PROC_FS + remove_proc_entry("fs/pagebuf/stat", NULL); + remove_proc_entry("fs/pagebuf", NULL); +#endif +} + + +module_init(pagebuf_init); +module_exit(pagebuf_terminate); diff -rNu linux-2.4.7/linux/fs/pagebuf/page_buf_io.c linux-2.4-xfs/linux/fs/pagebuf/page_buf_io.c --- linux-2.4.7/linux/fs/pagebuf/page_buf_io.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/pagebuf/page_buf_io.c Mon Jul 2 10:59:04 2001 @@ -0,0 +1,1455 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Id: $" + +/* + * page_buf_io.c + * + * See generic comments about page_bufs in page_buf.c. This file deals with + * file I/O (reads & writes) including delayed allocation & direct IO. + * + * Written by Steve Lord, Jim Mostek, Russell Cattelan + * and Rajagopal Ananthanarayanan ("ananth") at SGI. + * + */ + +#define _PAGE_BUF_INTERNAL_ 1 + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PAGE_CACHE_MASK_LL (~((long long)(PAGE_CACHE_SIZE-1))) +#define PAGE_CACHE_ALIGN_LL(addr) \ + (((addr)+PAGE_CACHE_SIZE-1)&PAGE_CACHE_MASK_LL) +#define MAX_BUF_PER_PAGE 1 /* (PAGE_CACHE_SIZE / 512) */ +#define PBF_IO_CHUNKSIZE 65536 +#define PBF_MAX_MAPS 1 + +#ifndef STATIC +#define STATIC static +#endif + +/* + * Forward declarations. + */ +STATIC void __pb_block_commit_write_async(struct inode *, + struct page *, int); +STATIC int __pb_block_prepare_write_async(struct inode *, struct page *, + unsigned, unsigned, int, pagebuf_bmap_fn_t, + page_buf_bmap_t *, int); +STATIC int pagebuf_delalloc_convert(struct inode *, struct page *, + unsigned long, pagebuf_bmap_fn_t); +STATIC void hook_buffers_to_page(struct inode *, struct page *, + page_buf_bmap_t *); + +/* + * The following structure is used to communicate between various levels + * of pagebuf code. It is used by iomove, through segment_apply, into + * the actual copyfrom or copyto routines. + */ + +/* The start of this deliberately looks like a read_descriptor_t in layout */ +typedef struct { + read_descriptor_t io_rdesc; + + /* 0x10 */ + loff_t io_offset; /* Starting offset of I/O */ + int io_iovec_nr; /* Number of entries in iovec */ + + /* 0x20 */ + struct iovec **io_iovec; /* iovec list indexed by iovec_index */ + loff_t io_iovec_offset; /* offset into current iovec. */ + int io_iovec_index; /* current iovec being processed */ + loff_t io_i_size; /* size of the file */ +} pb_io_desc_t; + + +#define io_written io_rdesc.written +#define io_total_count io_rdesc.count +#define io_error io_rdesc.error + +static void +_unmark_delalloc(struct page *page) +{ + struct buffer_head *bh = page->buffers; + + if (!PageLocked(page)) + PAGE_BUG(page); + if (!bh || !buffer_delay(bh)) + BUG(); + clear_bit(BH_Delay, &bh->b_state); +} + +/* + * pagebuf_flush: write back cached pages to disk. + * + */ +void pagebuf_flush( + struct inode *ip, /* inode for range */ + loff_t ioff, /* first location in range */ + page_buf_flags_t bflags) /* buffer flags, usually */ + /* PBF_ASYNC */ + +{ + filemap_fdatasync(ip->i_mapping); + fsync_inode_buffers(ip); + filemap_fdatawait(ip->i_mapping); +} + + +/* + * pagebuf_inval: invalidate from page-cache (no implied write back). + */ +void pagebuf_inval( /* invalidate buffered data for */ + struct inode *ip, /* inode for range */ + loff_t ioff, /* first location in range */ + page_buf_flags_t bflags) /* buffer flags, usually PBF_ASYNC */ +{ + truncate_inode_pages(ip->i_mapping, ioff); +} + +/* + * pagebuf_flushinval + */ +void pagebuf_flushinval( /* write & invalidate buffered storage */ + struct inode *ip, /* inode for range */ + loff_t ioff, /* first location in range */ + page_buf_flags_t bflags) /* buffer flags, usually PBF_ASYNC */ +{ + pagebuf_flush(ip, ioff, bflags); + truncate_inode_pages(ip->i_mapping, ioff); +} + +/* + * _pagebuf_handle_iovecs + * + * _pagebuf_handle_iovecs uses an I/O descriptor structure containing + * iovec(s) and copies in/out or zeros the memory associated with it. + * This routine is passed (for copies in/out) a kern address with contiguous + * memory which is to be copied to/from the iovec(s). This routine updates + * the I/O descriptor to show what happened including setting io_error if + * something goes awry. + */ + +int _pagebuf_handle_iovecs( + pb_io_desc_t * iodp, /* I/O descriptor */ + unsigned long offset, /* start offset into page data */ + loff_t pb_off, size_t len, /* Total length to copy in this call */ + page_buf_rw_t op) /* read/write/zero */ +{ + int start_off; /* offset past kern_addr to start */ + struct iovec *iovecp; + void *user_addr; /* user addr computed from iovec(s) */ + size_t copy_len, /* Amount per copy to user */ + left, /* not copied by __copy_to_user */ + iov_left_len, /* amount to do in one iovec entry */ + copied; /* amount successfully copied */ + + /* + * If the offsets don't match, move kern_addr up + * and length down. + */ + if (pb_off != iodp->io_offset) { + start_off = iodp->io_offset - pb_off; + offset += start_off; + len -= start_off; + } else { + start_off = 0; + } + + copied = start_off; /* Tell caller we used this + what we copy + use below. */ + + while (len && iodp->io_error == 0 && + iodp->io_iovec_index < iodp->io_iovec_nr && + (iodp->io_offset < iodp->io_i_size)) { + iovecp = iodp->io_iovec[iodp->io_iovec_index]; + user_addr = iovecp->iov_base + iodp->io_iovec_offset; + iov_left_len = iovecp->iov_len - iodp->io_iovec_offset; + copy_len = min(iov_left_len, len); + + /* + * Restrict read/zero size to what is left + * in the file. + */ + copy_len = min(copy_len, + iodp->io_i_size - iodp->io_offset); + + /* Use __clear_user since we don't need + * to check VERIFY_WRITE, again. + */ + left = __clear_user(user_addr, copy_len); + + if (left) { + copy_len -= left; + iodp->io_error = -EFAULT; + } + + /* Move to the next iov or update the offset in the current */ + if (copy_len == iov_left_len) { + iodp->io_iovec_index++; + iodp->io_iovec_offset = 0; + } else { + iodp->io_iovec_offset += copy_len; + } + + /* Move along the total offset, length, writen, ... */ + iodp->io_written += copy_len; + iodp->io_total_count -= copy_len; + iodp->io_offset += copy_len; + len = len - copy_len; + copied += copy_len; + offset += copy_len; + } + + if (iodp->io_error) + return iodp->io_error; + else + return copied; +} + +/* + * pagebuf_iozero + * + * pagebuf_iozero clears the specified range of buffer supplied, + * and marks all the affected blocks as valid and modified. If + * an affected block is not allocated, it will be allocated. If + * an affected block is not completely overwritten, and is not + * valid before the operation, it will be read from disk before + * being partially zeroed. + */ + +int pagebuf_iozero( /* zero contents of buffer */ + struct inode *ip, /* inode owning buffer */ + page_buf_t * pb, /* buffer to zero */ + off_t boff, /* offset in buffer */ + size_t bsize) /* size of data to zero */ +{ + loff_t cboff; + size_t cpoff; + size_t csize; + struct page *page; + + cboff = boff; + boff += bsize; /* last */ + + /* check range */ + if (boff > pb->pb_buffer_length) + return (-ENOENT); + + while (cboff < boff) { + if (pagebuf_segment(pb, &cboff, &page, &cpoff, &csize, 0)) { + return (-ENOMEM); + } + assert(((csize + cpoff) <= PAGE_CACHE_SIZE)); + lock_page(page); + memset((void *) (kmap(page) + cpoff), 0, csize); + pagebuf_commit_write(NULL, page, cpoff, cpoff + csize); + UnlockPage(page); + } + + pb->pb_flags &= ~(PBF_READ | PBF_WRITE); + pb->pb_flags &= ~(PBF_PARTIAL | PBF_NONE); + + return (0); +} + + +/* + * Reading and writing files + */ + + +size_t +_pb_direct_io( + struct inode *inode, + loff_t rounded_offset, + size_t pb_size, + page_buf_bmap_t *mp, + void *user_addr, + pb_io_desc_t *rdp, + int rdwr) +{ + page_buf_t *pb; + struct kiobuf *kp; + int rval; + struct iovec *iovecp; + int pb_flags; + off_t offset; + ulong max_io = pb_params.p_un.max_dio << PAGE_SHIFT; + + pb_size = min(pb_size, max_io); + + pb_flags = (rdwr ? PBF_WRITE : PBF_READ) | PBF_FORCEIO; + + pb = pagebuf_lookup(inode, rounded_offset, pb_size, pb_flags); + if (!pb) { + rdp->io_error = -ENOMEM; + return 0; + } + + offset = mp->pbm_delta >> inode->i_sb->s_blocksize_bits; + pb->pb_dev = mp->pbm_dev; + pb->pb_bn = mp->pbm_bn + offset; + + /* Do our own allocation to avoid the buffer_head overhead */ + kp = kmalloc(sizeof(struct kiobuf), SLAB_KERNEL); + if (!kp) { + pagebuf_rele(pb); + rdp->io_error = -ENOMEM; + return 0; + } + memset(kp, 0, sizeof(struct kiobuf)); + kp->array_len = KIO_STATIC_PAGES; + kp->maplist = kp->map_array; + if (rdp) { + iovecp = rdp->io_iovec[rdp->io_iovec_index]; + user_addr = iovecp->iov_base + rdp->io_iovec_offset; + } + rval = map_user_kiobuf(rdwr ? WRITE : READ, + kp, (unsigned long) user_addr, pb_size); + if (rval == 0) { + pb->pb_pages = kp->maplist; + pb->pb_page_count = kp->nr_pages; + pb->pb_offset = kp->offset; + rval = pagebuf_iostart(pb, pb_flags); + unmap_kiobuf(kp); + } + kfree(kp); + + if (rdp) { + if (rval == 0) { + rdp->io_written += pb_size; + rdp->io_total_count -= pb_size; + rdp->io_offset += pb_size; + rdp->io_iovec_offset += pb_size; + } else { + rdp->io_error = rval; + } + } + + pagebuf_rele(pb); + + return rval ? 0 : pb_size; +} + +/* + * Return size in bytes of maximum direct I/O done in one call + */ +size_t pagebuf_max_direct() +{ + return pb_params.p_un.max_dio << PAGE_SHIFT; +} + +/* + * pagebuf_direct_file_read + * + * pagebuf_file_read reads data from the specified file + * at the loff_t referenced, updating the loff_t to point after the + * data read and updating "rdp" to contain any errors and the bytes + * read. + */ + +ssize_t +pagebuf_direct_file_read( + struct file * filp, /* file to read */ + char *buf, /* buffer address */ + size_t len, /* size of buffer */ + loff_t * lp, /* file offset to use and update */ + pagebuf_bmap_fn_t bmap) /* bmap function */ +{ + pb_io_desc_t iodp, *rdp=&iodp; + struct iovec iovec, *iovp = &iovec; + struct inode *inode = filp->f_dentry->d_inode; + page_buf_bmap_t maps[PBF_MAX_MAPS], *mp; + int maps_returned, map_entry; + unsigned long chunksize, map_size, size; + unsigned long rounding; + loff_t mask, rounded_isize; + + if (!access_ok(VERIFY_WRITE, buf, len)) { + return -EFAULT; + } + + rdp->io_offset = *lp; + rdp->io_written = 0; + rdp->io_total_count = len; + rdp->io_iovec_nr = 1; + rdp->io_iovec = &iovp; + iovp->iov_base = buf; + iovp->iov_len = len; + rdp->io_iovec_offset = 0; + rdp->io_iovec_index = 0; + rdp->io_error = 0; + rdp->io_i_size = inode->i_size; + + + rounding = inode->i_sb->s_blocksize; + mask = ~(loff_t)(rounding - 1); + + /* + * while we have data to do, get a bunch of mapping for this + * file to blocks on disk (or in delalloc or holes or ...). + * For each map entry, + * get a pagebuf. Note that pagebuf's are limited in size + * so we need to loop again for each chunksize + * within the mapping the file system returned. + */ + + rounded_isize = (inode->i_size + rounding - 1) & mask; + + while (rdp->io_total_count && !rdp->io_error && + rdp->io_offset < inode->i_size) { + loff_t rounded_offset; + size_t rounded_size; + + /* + * Let's start by calling bmap. + * Back up the offset to start at a page and increase to size + * to make it cover an entire page (plus any backing up done). + * This will return the on disk representation + * (or dealalloc/holes). + * There isn't a page for the first part of the I/O + * (at least there wasn't before we were called). + * + * Once we know the on disk and/or in memory representation, + * we can better do the I/Os or zero out or ... + */ + + /* + * Make the I/O which will fill pages, + * page aligned and complete pages. + */ + + rounded_offset = rdp->io_offset & mask; + rounded_size = rdp->io_total_count + + (rdp->io_offset - rounded_offset); + rounded_size = + (rounded_size + rounding - 1) & mask; + + /* + * Truncate the read at the page/block where EOF resides. + */ + if (rounded_offset + rounded_size > rounded_isize) + rounded_size = rounded_isize - rounded_offset; + + rdp->io_error = bmap(inode, rounded_offset, rounded_size, + &maps[0], PBF_MAX_MAPS, + &maps_returned, PBF_READ); + + map_entry = 0; + + while (rdp->io_total_count && map_entry < maps_returned && + !rdp->io_error && rdp->io_offset < inode->i_size) { + + /* + * Let's look at each maps entry and decide how + * to handle things. + */ + + mp = &maps[map_entry]; + + /* + * First, get the size from this map entry that + * applies to this user's I/O. The offset of + * the mapping indicates how far from pbm_bn + * we need to go (in bytes) to find the block + * containing the offset we requested. + * + * Get the size of this mapping from the offset we + * care about to the end of the mapping. Then, + * reduce the size to lesser of the user's or the + * piece in the map. + */ + + map_size = mp->pbm_bsize - mp->pbm_delta; + size = min(map_size, rounded_size); + + if (mp->pbm_flags & (PBMF_HOLE|PBMF_UNWRITTEN)) { + + /* + * Zero the user's area for the size of + * this mapping. + */ + + _pagebuf_handle_iovecs(rdp, 0, + rounded_offset, size, PBRW_ZERO); + rounded_offset += size; + } else { + size_t pb_size, pb_done; + + pb_size = chunksize = size; + pb_done = 0; + + while (pb_done < size) { + pb_size = _pb_direct_io(inode, + rounded_offset, + pb_size, mp, + NULL, rdp, 0); + if (rdp->io_error) + break; + pb_done += pb_size; + rounded_offset += pb_size; + mp->pbm_delta += pb_size; + + /* + * Next size is either chunksize or what + * is left between pb_done and pb_size. + */ + + pb_size = + min(chunksize, size - pb_done); + } /* End of for chunksizes to get/read/copy pbs */ + } /* End of else we need to do I/O */ + map_entry++; + } /* end for all the bmaps */ + } /* end while we have data to do, bmap */ + + if (rdp->io_offset > inode->i_size) { + rdp->io_written -= rdp->io_offset - inode->i_size; + rdp->io_offset = inode->i_size; + } + + *lp = rdp->io_offset; + + if (!rdp->io_error) { + return (rdp->io_written); + } + return (rdp->io_error); +} + +STATIC void end_pb_buffer_io_sync(struct buffer_head *bh, int uptodate) +{ + struct page *page = bh->b_page; + + mark_buffer_uptodate(bh, uptodate); + SetPageUptodate(page); + unlock_buffer(bh); +} + + +/* + * Generic "read page" function for block devices that have the normal + * get_block functionality. This is most of the block device filesystems. + * Reads the page asynchronously --- the unlock_buffer() and + * mark_buffer_uptodate() functions propagate buffer state into the + * page struct once IO has completed. + * + * pagebuf_read_full_page + */ + +int pagebuf_read_full_page( + struct file *filp, + struct page *page, + pagebuf_bmap_fn_t bmap) +{ + struct inode *inode = (struct inode*)page->mapping->host; + /* arr is sized for worst case */ + struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE]; + int blocksize, bbits = inode->i_sb->s_blocksize_bits; + long nr, i, status = 0; + + if (!PageLocked(page)) + PAGE_BUG(page); + + if (DelallocPage(page)) { + UnlockPage(page); + return status; + } + + bh = head = page->buffers; + if (!bh || !buffer_mapped(bh)) { + page_buf_bmap_t map; + int nmaps; + + status = bmap(inode, ((loff_t)page->index << PAGE_CACHE_SHIFT), + PAGE_CACHE_SIZE, &map, 1, &nmaps, PBF_READ); + + if (map.pbm_bn >= 0) { + hook_buffers_to_page(inode, page, &map); + bh = head = page->buffers; + } else if (map.pbm_flags & (PBMF_HOLE|PBMF_DELAY)) { + memset(kmap(page), 0, PAGE_CACHE_SIZE); + flush_dcache_page(page); + kunmap(page); + goto page_done; + } else { + printk("pagebuf_read_full_page: page 0x%p map 0x%p\n", + page, &map); + BUG(); + } + } + + nr = 0; + i = 0; + + do { + blocksize = bh->b_size; + + if (buffer_uptodate(bh)) + continue; + + arr[nr] = bh; + nr++; + } while (i += blocksize >> bbits, (bh = bh->b_this_page) != head); + + if (!nr) { +page_done: + /* + * all buffers are uptodate - we can set the page + * uptodate as well. + */ + SetPageUptodate(page); + UnlockPage(page); + return 0; + } + + /* Stage two: lock the buffers */ + for (i = 0; i < nr; i++) { + struct buffer_head * bh = arr[i]; + lock_buffer(bh); + set_buffer_async_io(bh); + atomic_inc(&bh->b_count); + } + + /* Stage 3: start the IO */ + for(i=0; i < nr; i++){ + submit_bh(READ, arr[i]); + } + return 0; +} + + +/* + * pagebuf_write_full_page + */ + +int pagebuf_write_full_page(struct page *page, pagebuf_bmap_fn_t bmap) +{ + struct inode *inode = (struct inode*)page->mapping->host; + unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT, pb_flags; + loff_t offset; + int ret; + + if (DelallocPage(page)) + pb_flags = PBF_WRITE|PBF_FILE_ALLOCATE; + else + pb_flags = PBF_WRITE|PBF_DIRECT; + /* easy case */ + if (page->index < end_index) { + ret = pagebuf_delalloc_convert(inode, page, pb_flags, bmap); + goto out; + } + + /* things got complicated... */ + offset = inode->i_size & (PAGE_CACHE_SIZE-1); + /* OK, are we completely out? */ + if ((page->index >= end_index+1) || !offset) { + printk("Bad write on page 0x%p\n", page); + ret = -EIO; + goto out; + } + ret = __pb_block_prepare_write_async(inode, page, + 0, PAGE_CACHE_SIZE, 1, bmap, NULL, pb_flags); + if (ret) { + if (ret == -EAGAIN) { + kunmap(page); + return ret; + } + + ClearPageUptodate(page); + } else { + struct buffer_head *bh, *head; + + __pb_block_commit_write_async(inode, page, 0); + + /* + * Pages over holes may have just been allocated + * buffers, so bh needs to be looked up now. + */ + bh = page->buffers; + + /* + * Kick-start that last write... + */ + head = bh; + + do { + lock_buffer(bh); + set_buffer_async_io(bh); + atomic_inc(&bh->b_count); + set_bit(BH_Uptodate, &bh->b_state); + clear_bit(BH_Dirty, &bh->b_state); + bh = bh->b_this_page; + } while (bh != head); + + do { + submit_bh(WRITE, bh); + bh = bh->b_this_page; + } while (bh != head); + } + + kunmap(page); +out: + if (ret < 0) { + if (DelallocPage(page)) + block_flushpage(page, 0); + UnlockPage(page); + } + + return ret; +} + +STATIC void +hook_buffers_to_page_delay(struct inode *inode, struct page *page) +{ + struct buffer_head *bh; + + if (page->buffers) + BUG(); + create_empty_buffers(page, inode->i_dev, PAGE_CACHE_SIZE); + bh = page->buffers; + bh->b_state = (1 << BH_Delay) | (1 << BH_Mapped); + __mark_buffer_dirty(bh); + buffer_insert_inode_queue(bh, inode); + balance_dirty(bh->b_dev); +} + +STATIC void +hook_buffers_to_page(struct inode *inode, + struct page *page, page_buf_bmap_t *mp) +{ + struct buffer_head *bh; + page_buf_daddr_t bn; + loff_t delta; + + if (!page->buffers) + create_empty_buffers(page, mp->pbm_dev, PAGE_CACHE_SIZE); + bh = page->buffers; + /* + * pbm_offset:pbm_bn :: (page's offset):??? + * + * delta = offset of _this_ page in extent. + * pbm_offset = offset in file corresponding to pbm_bn. + */ + delta = page->index; /* do computations in 64 bit ... */ + delta <<= PAGE_CACHE_SHIFT; /* delta now offset from 0 of page */ + delta -= mp->pbm_offset; /* delta now offset in extent of page */ + + bn = mp->pbm_bn >> + (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); + bn += (delta >> PAGE_CACHE_SHIFT); + bh->b_blocknr = bn; + bh->b_dev = mp->pbm_dev; + if (buffer_locked(bh)) + BUG(); + set_bit(BH_Mapped, &bh->b_state); +} + +void +set_buffer_dirty_uptodate( + struct inode *inode, + struct buffer_head *bh, + int partial) +{ + int need_balance_dirty = 0; + + if (bh->b_blocknr <= 0) { + printk("Warning: buffer 0x%p with weird blockno (%ld)\n", + bh, bh->b_blocknr); + } + set_bit(BH_Uptodate, &bh->b_state); + if (!buffer_dirty(bh)) { + need_balance_dirty = 1; + } + __mark_buffer_dirty(bh); + + if (need_balance_dirty) { + buffer_insert_inode_queue(bh, inode); + if (!partial) + balance_dirty(bh->b_dev); + } +} + +STATIC int +__pb_block_prepare_write_async(struct inode *inode, struct page *page, + unsigned from, unsigned to, int at_eof, + pagebuf_bmap_fn_t bmap, page_buf_bmap_t *mp, int flags) +{ + struct buffer_head *bh; + int err = 0; + int nmaps, dp = DelallocPage(page); + char *kaddr = kmap(page); + page_buf_bmap_t map; + + + /* + * Create & map buffer. + * + * If we are not already mapped via buffers to a disk address, + * or the page is not already marked delalloc, then we need to + * go get some space. + */ + bh = page->buffers; + if ((!bh || buffer_delay(bh)) && (!dp || (flags & PBF_FILE_ALLOCATE))) + { + if (!mp) { + mp = ↦ + err = bmap(inode, ((loff_t)page->index << PAGE_CACHE_SHIFT), + PAGE_CACHE_SIZE, mp, 1, &nmaps, flags); + if (err < 0) { + goto out; + } + } + if (mp->pbm_bn > 0) { + hook_buffers_to_page(inode, page, mp); + if (dp) + _unmark_delalloc(page); + bh = page->buffers; + } + } + + /* Is the write over the entire page? */ + if (from == 0 && to == PAGE_CACHE_SIZE) + goto out; + + /* Partial write. Is the page valid anyway? */ + if (Page_Uptodate(page) || dp) + goto out; + + /* + * If writing at eof and the i_size at beginning of page + * then we can zero the page (or parts of it). + */ + if ((at_eof && (!bh || buffer_delay(bh) || + (inode->i_size & ~PAGE_CACHE_MASK_LL) == 0)) || + (mp && (mp->pbm_flags & (PBMF_DELAY|PBMF_UNWRITTEN)))) { + + /* + * Zero the parts of page not coverd by this I/O + */ + if (PAGE_CACHE_SIZE > to) { + memset(kaddr+to, 0, PAGE_CACHE_SIZE-to); + } + if (0 < from) { + memset(kaddr, 0, from); + } + if ((0 < from) || (PAGE_CACHE_SIZE > to)) + flush_dcache_page(page); + goto out; + } + /* + * Ensure only one block allocated. + */ + if (bh != bh->b_this_page) { + printk("bh 0x%p != bh->b_this_page 0x%p\n",bh,bh->b_this_page); + err = -EIO; + goto out; + } + lock_buffer(bh); + bh->b_end_io = end_pb_buffer_io_sync; + + submit_bh(READ,bh); + wait_on_buffer(bh); + if (!buffer_uptodate(bh)) + err = -EIO; +out: + return err; +} + +int +pagebuf_prepare_write( + struct file *file, + struct page *page, + unsigned from, + unsigned to, + pagebuf_bmap_fn_t bmap) +{ + struct inode *inode = (struct inode*)page->mapping->host; + int at_eof = page->index >= (inode->i_size >> PAGE_CACHE_SHIFT); + int err; + + err = __pb_block_prepare_write_async(inode, page, from, to, + at_eof, bmap, NULL, PBF_WRITE); + if (err) { + ClearPageUptodate(page); + kunmap(page); + } + + return err; +} + +int +pagebuf_commit_write( + struct file *file, + struct page *page, + unsigned from, + unsigned to) +{ + struct inode *inode = (struct inode*)page->mapping->host; + loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + int partial = (from - to) != PAGE_CACHE_SIZE; + + __pb_block_commit_write_async(inode, page, partial); + + kunmap(page); + if (pos > inode->i_size) { + inode->i_size = pos; + } + + return 0; +} + +STATIC void +__pb_block_commit_write_async(struct inode *inode, + struct page *page, + int partial) +{ + struct buffer_head *bh; + + /* + * Prepare write took care of reading/zero-out + * parts of page not covered by from/to. Page is now fully valid. + */ + SetPageUptodate(page); + if ((bh = page->buffers) && !buffer_delay(bh)) { + set_buffer_dirty_uptodate(inode, page->buffers, partial); + } else if (!DelallocPage(page)) { + hook_buffers_to_page_delay(inode, page); + } +} + +int +__pagebuf_do_delwri( + struct inode *inode, /* target */ + loff_t rounded_offset, /* offset in file, page aligned */ + unsigned long size, /* size to write, constrained by wdp */ + char *user_addr, + size_t len, + loff_t *lp, + page_buf_bmap_t *mp) /* bmap for page */ +{ + struct page *page; + unsigned long done; + int err = 0, written = 0; + loff_t foff = *lp; + char *kaddr; + + for (done = 0; (done < size) && len; + done += PAGE_CACHE_SIZE, rounded_offset += PAGE_CACHE_SIZE) + { + int bytes_in_page; + int at_eof; + int deactivate = 1; + unsigned long offset_in_page; + + page = grab_cache_page(inode->i_mapping, + rounded_offset >> PAGE_CACHE_SHIFT); + + if (!page) { + err = -ENOMEM; + break; + } + + + offset_in_page = foff & (PAGE_CACHE_SIZE - 1); + bytes_in_page = PAGE_CACHE_SIZE - offset_in_page; + if (bytes_in_page > len) { + bytes_in_page = len; + deactivate = 0; + } + bytes_in_page = min(bytes_in_page, size); + at_eof = foff == inode->i_size; + + err = __pb_block_prepare_write_async(inode, page, + offset_in_page, offset_in_page + bytes_in_page, + at_eof, NULL, mp, PBF_WRITE); + + if (err) + goto unlock; + kaddr = page_address(page); + + err = copy_from_user(kaddr + offset_in_page, user_addr, + bytes_in_page); + if (err) { + ClearPageUptodate(page); + goto unlock; + } + + __pb_block_commit_write_async(inode, page, + bytes_in_page != PAGE_CACHE_SIZE); + + foff += bytes_in_page; + len -= bytes_in_page; + written += bytes_in_page; + user_addr += bytes_in_page; + + if (foff > inode->i_size) + inode->i_size = foff; + +unlock: + kunmap(page); + UnlockPage(page); + if (deactivate) + deactivate_page(page); + page_cache_release(page); + if (err < 0) + break; + } + *lp = foff; + return err ? err : written; +} + +int +_pagebuf_file_write( + struct file * filp, /* file to write */ + char *buf, /* buffer address */ + size_t len, /* size of buffer */ + loff_t * lp, /* file offset to use and update */ + pagebuf_bmap_fn_t bmap, /* bmap function */ + int pb_flags) /* flags to pass to bmap calls */ +{ + struct inode *inode = filp->f_dentry->d_inode; + page_buf_bmap_t map; + int maps_returned; + unsigned long map_size, size; + int status = 0, written = 0; + loff_t foff = *lp; + int sync; + + sync = filp->f_flags & (O_SYNC|O_DIRECT); + + /* + * while we have data to do, get a bunch of mapping for this + * file to blocks on disk (or in delalloc or holes or ...). + * For each map entry, + * get a pagebuf. Note that pagebuf's are limited in size + * so we need to loop again for each chunksize + * within the mapping the file system returned. + */ + + while (len) { + + loff_t rounded_offset; + size_t rounded_size; + + /* + * Let's start by calling bmap for the offset/len we have. + * This will return the on disk representation + * (or dealalloc/holes). + * + * Once we know the on disk and/or in memory representation, + * we can better do the I/Os in chunks or ... + */ + + /* + * Make the I/O which will fill pages, + * page aligned and complete pages. + */ + + if (!(filp->f_flags & O_DIRECT)) { + rounded_offset = foff & PAGE_CACHE_MASK_LL; + } else { + rounded_offset = foff; + } + rounded_size = len + (foff - rounded_offset); + rounded_size = + (rounded_size + PAGE_CACHE_SIZE - 1) & + PAGE_CACHE_MASK; + size = rounded_size; + + /* + * round the size up to some minimum value + * since this is allocation. 64K for now. + * + * Don't round up if we are writing within the file + * since this probably means seek/write/... and + * it isn't sequential. Leave holes. + */ + + if ((rounded_offset >= inode->i_size) && !sync) + size = PBF_IO_CHUNKSIZE; + + status = bmap(inode, rounded_offset, size, + &map, 1, &maps_returned, pb_flags); + + if (status) { + break; + } + + /* + * Get the size of this mapping from the offset we + * care about to the end of the mapping. Then, + * reduce the size to lesser of the user's or the + * piece in the map. + */ + + map_size = map.pbm_bsize - map.pbm_delta; + size = min(map_size, size); + + /* + * Holes mean we came to the end of the space returned + * from the file system. We need to go back and ask for + * more space. + */ + if (map.pbm_flags & PBMF_HOLE) { + printk("pbfwa: HOLE ro 0x%Lx size 0x%lx mp 0x%p\n", + rounded_offset, size, &map); + break; + } + /* + * Handle delwri or direct I/O + */ + if ((filp->f_flags & O_DIRECT) == 0) { + status = __pagebuf_do_delwri(inode, + rounded_offset, size, buf, + len, &foff, &map); + } else { + int io_size = min(size, len); + + status = _pb_direct_io(inode, rounded_offset, + io_size, &map, buf, NULL, 1); + if (status > 0) + foff += status; + if (foff > inode->i_size) + inode->i_size = foff; + } + if (status <= 0) + break; + written += status; + buf += status; + len -= status; + } + *lp = foff; + return written ? written : status; +} + +ssize_t +pagebuf_generic_file_write( + struct file * filp, /* file to write */ + char *buf, /* buffer address */ + size_t len, /* size of buffer */ + loff_t * lp, /* file offset to use and update */ + pagebuf_bmap_fn_t bmap) /* bmap function */ +{ + struct inode *inode = filp->f_dentry->d_inode; + unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur; + unsigned long index; + int status = 0, written = 0; + char *kaddr; + loff_t foff; + struct page *page; + int pb_flags; + int direct = filp->f_flags & O_DIRECT; + + pb_flags = PBF_WRITE; + if (filp->f_flags & O_SYNC) + pb_flags |= PBF_SYNC; + if (direct) + pb_flags |= PBF_DIRECT; + + if ((foff = *lp) < 0) + goto out; + + if ((status = filp->f_error) != 0) { + filp->f_error = 0; + goto out; + } + + /* + * Check if we've reached the file size limit. + * note that file limits do not appear to cope with + * files bigger than 32 bits. + */ + if (limit != RLIM_INFINITY) { + if (foff >= limit) { + send_sig(SIGXFSZ, current, 0); + status = -EFBIG; + goto out; + } + if (len > limit - foff) { + send_sig(SIGXFSZ, current, 0); + len = limit - foff; + } + } + + while (len) { + unsigned long bytes, offset; + int at_eof; + int deactivate = 1; + /* + * Try to find the page in the cache. If it isn't there, + * allocate a free page. If the write is sufficiently big, + * use pagebufs with possible delayed allocation. + */ + offset = (foff & ~PAGE_CACHE_MASK_LL); + index = foff >> PAGE_CACHE_SHIFT; + bytes = PAGE_CACHE_SIZE - offset; + if (bytes > len) { + bytes = len; + deactivate = 0; + } + + if (&inode->i_data != inode->i_mapping) + BUG(); + + if (!direct) { + page = find_lock_page(&inode->i_data, index); + } else { + page = NULL; + } + + if (!page) { + status = _pagebuf_file_write(filp, + buf, len, &foff, bmap, pb_flags); + if (status > 0) + written += status; + break; + } + + if (!PageLocked(page)) { + PAGE_BUG(page); + } + + at_eof = foff == inode->i_size; + + status = __pb_block_prepare_write_async(inode, page, + offset, offset + bytes, at_eof, bmap, + NULL, pb_flags); + + if (status) + goto unlock; + + kaddr = page_address(page); + status = copy_from_user(kaddr+offset, buf, bytes); + + if (status) { + status = -EFAULT; + ClearPageUptodate(page); + goto unlock; + } + + __pb_block_commit_write_async(inode, page, + bytes != PAGE_CACHE_SIZE); + + len -= bytes; + buf += bytes; + foff += bytes; + written += bytes; + + if (foff > inode->i_size) + inode->i_size = foff; + + SetPageUptodate(page); +unlock: + kunmap(page); + UnlockPage(page); + if (deactivate) + deactivate_page(page); + page_cache_release(page); + + if (status < 0) + break; + } + *lp = foff; + +out: + return written ? written : status; +} + +/* + * Probe for a given page (index) in the inode & test if it is delayed. + * Returns page locked and with an extra reference count. + */ +STATIC struct page * +probe_page(struct inode *inode, unsigned long index) +{ + struct page *page; + + page = find_get_page_simple(inode->i_mapping, index); + if (!page) + return NULL; + if (TryLockPage(page)) { + page_cache_release(page); + return NULL; + } + if (!page->mapping || !DelallocPage(page)) { + UnlockPage(page); + page_cache_release(page); + return NULL; + } + return page; +} + + +/* + * Allocate & map buffers for page given the extent map. Write it out. + */ +STATIC void +convert_page(struct inode *inode, struct page *page, page_buf_bmap_t *mp) +{ + struct buffer_head *head, *bh = page->buffers; + + if (!bh || DelallocPage(page)) { + hook_buffers_to_page(inode, page, mp); + bh = page->buffers; + } + + head = bh; + do { + lock_buffer(bh); + set_buffer_async_io(bh); + atomic_inc(&bh->b_count); + set_bit(BH_Uptodate, &bh->b_state); + clear_bit(BH_Dirty, &bh->b_state); + clear_bit(BH_Delay, &bh->b_state); + bh = bh->b_this_page; + } while (bh != head); + + do { + submit_bh(WRITE, bh); + bh = bh->b_this_page; + } while (bh != head); + + SetPageUptodate(page); + page_cache_release(page); +} + +/* + * Convert & write out a cluster of pages in the same extent as defined + * by mp and surrounding the start page. + */ +STATIC int +cluster_write(struct inode *inode, + struct page *startpage, + page_buf_bmap_t *mp) +{ + unsigned long tindex, tlast; + struct page *page; + int count = 0; + + if (startpage->index != 0) { + tlast = mp->pbm_offset >> PAGE_CACHE_SHIFT; + for (tindex = startpage->index-1; tindex >= tlast; tindex--) { + if (!(page = probe_page(inode, tindex))) + break; + convert_page(inode, page, mp); + count++; + } + } + convert_page(inode, startpage, mp); + count++; + tlast = PAGE_CACHE_ALIGN_LL(mp->pbm_offset + mp->pbm_bsize) >> + PAGE_CACHE_SHIFT; + for (tindex = startpage->index + 1; tindex < tlast; tindex++) { + if (!(page = probe_page(inode, tindex))) + break; + convert_page(inode, page, mp); + count++; + } + return count; +} + +STATIC int +pagebuf_delalloc_convert( + struct inode *inode, + struct page *page, /* delalloc page to convert - locked */ + unsigned long flags, /* allocation mode to use */ + pagebuf_bmap_fn_t bmap) /* bmap function */ +{ + page_buf_bmap_t maps[PBF_MAX_MAPS]; + int maps_returned, error; + loff_t rounded_offset; + + rounded_offset = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT; +allocate: + error = bmap(inode, rounded_offset, PAGE_CACHE_SIZE, + &maps[0], PBF_MAX_MAPS, &maps_returned, flags); + if (error) + return error; + + if ((error == 0) && (maps[0].pbm_flags & PBMF_HOLE)) { + printk("delalloc page 0x%p with no extent index 0x%lx\n", + page, page->index); + BUG(); + } + + if (maps[0].pbm_delta % PAGE_CACHE_SIZE) { + printk("PCD: pbm_delta not page aligned mp 0x%p\n", &maps[0]); + return -EIO; + } + if ((maps[0].pbm_flags & PBMF_DELAY) && (flags == PBF_DIRECT)) { + flags = PBF_WRITE | PBF_FILE_ALLOCATE; + printk("Redoing allocate for delalloc on page 0x%p\n", + page); + goto allocate; + } + /* + * page needs to be setup as though find_page(...) returned it, + * which is a locked page with an extra reference. + */ + page_cache_get(page); + return cluster_write(inode, page, &maps[0]); +} + +/* + * Module management + */ + +EXPORT_SYMBOL(pagebuf_flush); +EXPORT_SYMBOL(pagebuf_inval); +EXPORT_SYMBOL(pagebuf_flushinval); +EXPORT_SYMBOL(pagebuf_iozero); +EXPORT_SYMBOL(pagebuf_direct_file_read); +EXPORT_SYMBOL(pagebuf_generic_file_write); +EXPORT_SYMBOL(pagebuf_read_full_page); +EXPORT_SYMBOL(pagebuf_write_full_page); +EXPORT_SYMBOL(pagebuf_prepare_write); +EXPORT_SYMBOL(pagebuf_commit_write); +EXPORT_SYMBOL(pagebuf_max_direct); diff -rNu linux-2.4.7/linux/fs/pagebuf/page_buf_locking.c linux-2.4-xfs/linux/fs/pagebuf/page_buf_locking.c --- linux-2.4.7/linux/fs/pagebuf/page_buf_locking.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/pagebuf/page_buf_locking.c Wed Jun 20 14:56:33 2001 @@ -0,0 +1,644 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ident "$Id: $" + +/* + * page_buf_locking.c + * + * The page_buf module provides an abstract buffer cache model on top of + * the Linux page cache. Cached blocks for a file are hashed to the + * inode for that file, and can be held dirty in delayed write mode in + * the page cache. Cached metadata blocks for a file system are hashed + * to the inode for the mounted device. The page_buf module assembles + * buffer (page_buf_t) objects on demand to aggregate such cached pages + * for I/O. The page_buf_locking module adds support for locking such + * page buffers. + * + * Written by William J. Earl and Steve Lord at SGI + * + * + */ + +#define _PAGE_BUF_INTERNAL_ 1 + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PB_DEFINE_TRACES +#include + +/* + * Locking model: + * + * Buffers associated with inodes for which buffer locking + * is not enabled are not protected by semaphores, and are + * assumed to be exclusively owned by the caller. There is + * spinlock in the buffer, for use by the caller when concurrent + * access is possible. + * + * Buffers asociated with inodes for which buffer locking is + * enabled are protected by semaphores in the page_buf_lockable_t + * structure, but only between different callers. For a given + * caller, the buffer is exclusively owned by the caller, but + * the caller must still use the spinlock when concurrent access + * is possible. + * + * Internally, when implementing buffer locking, page_buf uses + * a rwlock_t to protect the pagebuf_registered_inodes tree, + * a spinlock_t to protect the buffer tree associated with an inode, + * as well as to protect the hold count in the page_buf_lockable_t. + * The locking order is the pagebuf_registered_inodes tree lock + * first, then the page_buf_registration_t lock. The semaphore + * in the page_buf_lockable_t should be acquired only after acquiring + * a hold on the page_buf_lockable_t (and of course releasing the + * page_buf_registration_t spinlock_t). + */ + +static kmem_cache_t *pagebuf_registration_cache = NULL; + + +/* + * Initialization and Termination + */ + +/* + * pagebuf_locking_init + */ + +int __init pagebuf_locking_init(void) +{ + if (pagebuf_registration_cache == NULL) { + pagebuf_registration_cache = kmem_cache_create("page_buf_reg_t", + sizeof(pb_target_t), + 0, + SLAB_HWCACHE_ALIGN, + NULL, + NULL); + if (pagebuf_registration_cache == NULL) + return(-ENOMEM); + } + + return(0); +} + + +/* + * Buffer Locking Control + */ + +/* + * _pagebuf_registration_free + * + * Free a page_buf_registration_t object. The caller must hold + * the pagebuf_registered_inodes_lock. + */ + +static void +_pagebuf_registration_free(pb_target_t *target) +{ + if (target != NULL) { + if (target->pbr_buffers != NULL) + avl_destroy(target->pbr_buffers); + kmem_cache_free(pagebuf_registration_cache, target); + } +} + + +int +_pagebuf_free_lockable_buffer(page_buf_t *pb, unsigned long flags) +{ + pb_target_t *target = pb->pb_target; + int status; + + PB_TRACE(pb, PB_TRACE_REC(free_lk), 0); + + spin_lock(&target->pbr_lock); + spin_lock(&PBP(pb)->pb_lock); + status = (avl_delete(target->pbr_buffers, + (avl_key_t) pb, (avl_value_t) pb)); + + spin_unlock_irqrestore(&target->pbr_lock, flags); + + PB_TRACE(pb, PB_TRACE_REC(freed_l), status); + + return status; +} + + + +/* + * _pagebuf_lockable_compare + */ + +static int +_pagebuf_lockable_compare_key(avl_key_t key_a, + avl_key_t key_b) +{ + page_buf_t *pb_a = (page_buf_t *) key_a; + page_buf_t *pb_b = (page_buf_t *) key_b; + int ret; + + if (pb_b == NULL) { + if (pb_a == NULL) + return(0); + else + return(-1); + } + + assert(pb_a->pb_target == pb_b->pb_target); + if (pb_a->pb_file_offset == pb_b->pb_file_offset) + ret = 0; + else if (pb_a->pb_file_offset < pb_b->pb_file_offset) + ret = -1; + else + ret = 1; + + return ret; +} + +/* + * _pagebuf_lockable_increment_key + */ + +static void +_pagebuf_lockable_increment_key(avl_key_t *next_key,avl_key_t key) +{ + page_buf_t *next_pb = (page_buf_t *) (*next_key); + page_buf_t *pb = (page_buf_t *) key; + + assert((next_pb != NULL) && \ + (next_pb->pb_flags & _PBF_NEXT_KEY) && \ + (pb != NULL)); + + next_pb->pb_file_offset = pb->pb_file_offset + pb->pb_buffer_length; +} + + +/* + * _pagebuf_get_lockable_buffer + * + * Looks up, and creates if absent, a lockable buffer for + * a given range of an inode. The buffer is returned + * locked. If other overlapping buffers exist, they are + * released before the new buffer is created and locked, + * which may imply that this call will block until those buffers + * are unlocked. No I/O is implied by this call. + * + * The caller must have previously called _pagebuf_check_lockable() + * successfully, and must pass in the page_buf_registration_t pointer + * obtained via that call, with the pbr_lock spinlock held and interrupts + * disabled. + */ + +void +_pagebuf_grab_lock(page_buf_t *pb) +{ + down(&PBP(pb)->pb_sema); +} + + +int +_pagebuf_find_lockable_buffer(pb_target_t *target, + loff_t range_base, + size_t range_length, + page_buf_flags_t flags, + page_buf_t **pb_p) +{ + page_buf_t next_key_buf; + page_buf_t *pb; + avl_key_t next_key; + avl_key_t key; + avl_value_t value; + int not_locked; + + next_key_buf.pb_flags = _PBF_NEXT_KEY; + next_key_buf.pb_file_offset = range_base; + next_key_buf.pb_buffer_length = range_length; + next_key = (avl_key_t) &next_key_buf; + while (avl_lookup_next(target->pbr_buffers, + &next_key, + &key, + &value) == 0) { + pb = (page_buf_t *)value; + assert(pb != NULL); + + if (pb->pb_file_offset >= (range_base + range_length)) + break; /* no overlap found - allocate buffer */ + + if (pb->pb_flags & PBF_FREED) + continue; + + spin_lock(&PBP(pb)->pb_lock); + if (pb->pb_flags & PBF_FREED) { + spin_unlock(&PBP(pb)->pb_lock); + continue; + } + pb->pb_hold++; + + PB_TRACE(pb, PB_TRACE_REC(avl_ret), 0); + + /* Attempt to get the semaphore without sleeping, + * if this does not work then we need to drop the + * spinlocks and do a hard attempt on the semaphore. + */ + not_locked = down_trylock(&PBP(pb)->pb_sema); + if (not_locked) { + spin_unlock(&PBP(pb)->pb_lock); + spin_unlock_irq(&(target->pbr_lock)); + + if (!(flags & PBF_TRYLOCK)) { + /* wait for buffer ownership */ + PB_TRACE(pb, PB_TRACE_REC(get_lk), 0); + + /* If this buffer has I/O outstanding, push */ + if (atomic_read(&PBP(pb)->pb_io_remaining)) + run_task_queue(&tq_disk); + _pagebuf_grab_lock(pb); + /** down(&PBP(pb)->pb_sema); **/ + PB_SET_OWNER(pb); + PB_STATS_INC(pbstats.pb_get_locked_waited); + } else { + /* We asked for a trylock and failed, no need + * to look at file offset and length here, we + * know that this pagebuf at least overlaps our + * pagebuf and is locked, therefore our buffer + * either does not exist, or is this buffer + */ + + pagebuf_rele(pb); + + PB_STATS_INC(pbstats.pb_busy_locked); + return -EBUSY; + } + } else { + /* trylock worked */ + PB_SET_OWNER(pb); + spin_unlock(&target->pbr_lock); + } + + + if (pb->pb_file_offset == range_base && + pb->pb_buffer_length == range_length) { + if (not_locked) + spin_lock_irq(&PBP(pb)->pb_lock); + if (!(pb->pb_flags & PBF_FREED)) { + spin_unlock_irq(&PBP(pb)->pb_lock); + PB_TRACE(pb, PB_TRACE_REC(got_lk), 0); + *pb_p = pb; + PB_STATS_INC(pbstats.pb_get_locked); + return(0); + } + spin_unlock_irq(&PBP(pb)->pb_lock); + } else if (!not_locked) { + spin_unlock_irq(&PBP(pb)->pb_lock); + } + + /* Let go of the buffer - if the count goes to zero + * this will remove it from the tree. The problem here + * is that if there is a hold on the pagebuf without a + * lock then we just threw away the contents.... + * Which means that if someone else comes along and + * locks the pagebuf which they have a hold on they + * can discover that the memory has gone away on them. + */ + PB_CLEAR_OWNER(pb); + PB_TRACE(pb, PB_TRACE_REC(skip), 0); + up(&PBP(pb)->pb_sema); + pagebuf_rele(pb); + + return -EBUSY; + } + + spin_unlock_irq(&target->pbr_lock); + + /* No match found */ + PB_STATS_INC(pbstats.pb_miss_locked); + *pb_p = NULL; + return 0; +} + +int +_pagebuf_get_lockable_buffer(pb_target_t *target, + loff_t range_base, + size_t range_length, + page_buf_flags_t flags, + page_buf_t **pb_p) +{ + int status; + page_buf_t *pb; + +retry_scan: + spin_lock_irq(&target->pbr_lock); + status = _pagebuf_find_lockable_buffer(target, range_base, + range_length, flags, pb_p); + + if (status) + return status; + + if (*pb_p) + return 0; + + + status = _pagebuf_get_object(target, range_base, range_length, + flags | _PBF_LOCKABLE, &pb); + if (status != 0) { + return(status); + } + + + /* Tree manipulation requires the registration spinlock */ + spin_lock_irq(&target->pbr_lock); + status = avl_insert(target->pbr_buffers, + (avl_key_t) pb, + (avl_value_t) pb); + spin_unlock_irq(&target->pbr_lock); + PB_TRACE(pb, PB_TRACE_REC(avl_ins), status); + if (status != 0) { + unsigned long flags; + + spin_lock_irqsave(&PBP(pb)->pb_lock, flags); + pb->pb_flags &= ~_PBF_LOCKABLE; /* we are not in the avl */ + _pagebuf_free_object(pb, flags); + if (status == -EEXIST) { + /* Race condition with another thread - try again, + * set up locking state first. + */ + goto retry_scan; + } + return(status); + } + + *pb_p = pb; + return(0); +} + +/* + * Locking and Unlocking Buffers + */ + +/* + * pagebuf_cond_lock + * + * pagebuf_cond_lock locks a buffer object, if it is not already locked. + * Note that this in no way + * locks the underlying pages, so it is only useful for synchronizing + * concurrent use of page buffer objects, not for synchronizing independent + * access to the underlying pages. + */ + +int +pagebuf_cond_lock( /* lock buffer, if not locked */ + /* returns -EBUSY if locked) */ + page_buf_t *pb) /* buffer to lock */ +{ + int locked; + + assert(pb->pb_flags & _PBF_LOCKABLE); + + locked = down_trylock(&PBP(pb)->pb_sema) == 0; + if (locked) { + PB_SET_OWNER(pb); + } + + PB_TRACE(pb, PB_TRACE_REC(condlck), locked); + + return(locked ? 0 : -EBUSY); +} + + +/* + * pagebuf_is_locked + * + * pagebuf_is_locked tests if the buffer is locked, return 1 if locked + * and 0 if not. This routine is useful only for assertions that + * the buffer is locked, since the state could change at any time + * if the buffer is not locked. + */ + +int +pagebuf_is_locked( /* test if buffer is locked */ + page_buf_t *pb) /* buffer to test */ +{ + assert(pb->pb_flags & _PBF_LOCKABLE); + + return(atomic_read(&PBP(pb)->pb_sema.count) <= 0 ); +} + +/* + * pagebuf_lock_value + * + * Return lock value for a pagebuf + */ + +int +pagebuf_lock_value(page_buf_t *pb) +{ + assert(pb->pb_flags & _PBF_LOCKABLE); + + return(atomic_read(&PBP(pb)->pb_sema.count)); +} + + + +/* + * pagebuf_lock + * + * pagebuf_lock locks a buffer object. Note that this in no way + * locks the underlying pages, so it is only useful for synchronizing + * concurrent use of page buffer objects, not for synchronizing independent + * access to the underlying pages. + */ + +int +pagebuf_lock( /* lock buffer */ + /* (returns -EDEADLK if would */ + /* deadlock) */ + page_buf_t *pb) /* buffer to lock */ +{ + assert(pb->pb_flags & _PBF_LOCKABLE); + + PB_TRACE(pb, PB_TRACE_REC(lock), 0); + if (atomic_read(&PBP(pb)->pb_io_remaining)) + run_task_queue(&tq_disk); + down(&PBP(pb)->pb_sema); + PB_SET_OWNER(pb); + PB_TRACE(pb, PB_TRACE_REC(locked), 0); + return(0); +} + + +/* + * pagebuf_lock_disable + * + * pagebuf_lock_disable disables buffer object locking for an inode. + * This call fails with -EBUSY if buffers are still in use and locked for + * this inode. + */ + +int +pagebuf_lock_disable( /* disable buffer locking */ + pb_target_t *target) /* inode for buffers */ +{ + avl_key_t next_key; + avl_key_t key; + avl_value_t value; + + spin_lock_irq(&target->pbr_lock); + if (target->pbr_buffers != NULL) { + next_key = 0; + if (avl_lookup_next(target->pbr_buffers, + &next_key, + &key, + &value) == 0) { + spin_unlock_irq(&target->pbr_lock); + return(-EBUSY); + } + } + truncate_inode_pages(&target->pbr_addrspace, 0LL); + _pagebuf_registration_free(target); + local_irq_enable(); + MOD_DEC_USE_COUNT; + + return(0); +} + +static struct address_space_operations pagebuf_aops = { + sync_page: block_sync_page, +}; + +/* + * pagebuf_lock_enable + * + * pagebuf_lock_enable enables buffer object locking for an inode. + * This call fails with -EBUSY if buffers are in use for this inode. + */ + +pb_target_t *pagebuf_lock_enable( + kdev_t kdev, + struct super_block *sb) +{ + int status = 0; + pb_target_t *target; + + target = kmem_cache_zalloc(pagebuf_registration_cache, + SLAB_KERNEL); + if (target == NULL) { + return(NULL); + } + spin_lock_init(&target->pbr_lock); + target->pbr_device = kdev; + target->pbr_sector = sb->s_blocksize; + target->pbr_sector_bits = sb->s_blocksize_bits; + status = avl_create(&target->pbr_buffers, + avl_opt_nolock, + _pagebuf_lockable_compare_key, + _pagebuf_lockable_increment_key); + INIT_LIST_HEAD(&target->pbr_addrspace.clean_pages); + INIT_LIST_HEAD(&target->pbr_addrspace.dirty_pages); + INIT_LIST_HEAD(&target->pbr_addrspace.locked_pages); + spin_lock_init(&target->pbr_addrspace.i_shared_lock); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) + spin_lock_init(&target->pbr_addrspace.page_lock); +#endif + target->pbr_addrspace.a_ops = &pagebuf_aops; + if (status) { + _pagebuf_registration_free(target); + return(NULL); + } + MOD_INC_USE_COUNT; + + return(target); +} + +int pagebuf_target_clear(pb_target_t *target) +{ + truncate_inode_pages(&target->pbr_addrspace, 0LL); + return 0; +} + + +/* + * pagebuf_unlock + * + * pagebuf_unlock releases the lock on the buffer object created by + * pagebuf_lock or pagebuf_cond_lock (not any + * pinning of underlying pages created by pagebuf_pin). + */ + +void +pagebuf_unlock( /* unlock buffer */ + page_buf_t *pb) /* buffer to unlock */ +{ + assert(pb->pb_flags & _PBF_LOCKABLE); + + PB_CLEAR_OWNER(pb); + up(&PBP(pb)->pb_sema); + PB_TRACE(pb, PB_TRACE_REC(unlock), 0); +} + + +/* + * Module management + */ + +EXPORT_SYMBOL(pagebuf_cond_lock); +EXPORT_SYMBOL(pagebuf_lock); +EXPORT_SYMBOL(pagebuf_is_locked); +EXPORT_SYMBOL(pagebuf_lock_value); +EXPORT_SYMBOL(pagebuf_lock_disable); +EXPORT_SYMBOL(pagebuf_lock_enable); +EXPORT_SYMBOL(pagebuf_unlock); +EXPORT_SYMBOL(pagebuf_target_clear); + +/* + * pagebuf_terminate + */ + +void __exit pagebuf_locking_terminate(void) +{ + if (pagebuf_registration_cache != NULL) + kmem_cache_destroy(pagebuf_registration_cache); +} + diff -rNu linux-2.4.7/linux/fs/partitions/CVS/Entries linux-2.4-xfs/linux/fs/partitions/CVS/Entries --- linux-2.4.7/linux/fs/partitions/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/partitions/CVS/Entries Thu Jul 5 12:03:33 2001 @@ -0,0 +1,25 @@ +/Config.in/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/Makefile/1.5/Wed May 2 06:22:13 2001/-ko/ +/acorn.c/1.10/Mon Oct 23 18:56:35 2000/-ko/ +/acorn.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/amiga.c/1.2/Thu Feb 17 20:46:04 2000/-ko/ +/amiga.h/1.1/Sun Aug 29 03:09:59 1999/-ko/ +/atari.c/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/atari.h/1.2/Wed Sep 15 20:42:56 1999/-ko/ +/check.c/1.24/Wed Jun 13 03:24:09 2001/-ko/ +/check.h/1.2/Thu Feb 17 20:46:04 2000/-ko/ +/ibm.c/1.4/Tue May 29 19:53:13 2001/-ko/ +/ibm.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/mac.c/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/mac.h/1.1/Sun Aug 29 03:09:59 1999/-ko/ +/msdos.c/1.13/Thu Feb 22 21:09:04 2001/-ko/ +/msdos.h/1.1/Sun Aug 29 03:09:59 1999/-ko/ +/osf.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/osf.h/1.1/Sun Aug 29 03:09:59 1999/-ko/ +/sgi.c/1.4/Wed Mar 15 18:20:34 2000/-ko/ +/sgi.h/1.1/Sun Aug 29 03:09:59 1999/-ko/ +/sun.c/1.3/Thu Feb 17 20:46:04 2000/-ko/ +/sun.h/1.1/Sun Aug 29 03:09:59 1999/-ko/ +/ultrix.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/ultrix.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +D diff -rNu linux-2.4.7/linux/fs/partitions/CVS/Repository linux-2.4-xfs/linux/fs/partitions/CVS/Repository --- linux-2.4.7/linux/fs/partitions/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/partitions/CVS/Repository Thu Jul 5 12:03:32 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/partitions diff -rNu linux-2.4.7/linux/fs/partitions/CVS/Root linux-2.4-xfs/linux/fs/partitions/CVS/Root --- linux-2.4.7/linux/fs/partitions/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/partitions/CVS/Root Thu Jul 5 12:03:32 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/posix_acl.c linux-2.4-xfs/linux/fs/posix_acl.c --- linux-2.4.7/linux/fs/posix_acl.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/posix_acl.c Fri May 4 00:27:54 2001 @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include + +/* + * Revalidate the inode. This is required for proper NFS attribute caching. + * Blatently copied wholesale from fs/stat.c + */ +static __inline__ int +do_revalidate(struct dentry *dentry) +{ + struct inode * inode = dentry->d_inode; + if (inode->i_op && inode->i_op->revalidate) + return inode->i_op->revalidate(dentry); + return 0; +} + +/* + * syscall to get an ACL on a file descriptor or path + * + * if no i_op set then return -EOPNOTSUPP (ENOTSUP equivalent for Linux) + */ + +asmlinkage long sys_acl_get( + const char *path, + int fdes, + struct acl *acl, + struct acl *dacl) +{ + int error; + struct nameidata nd; + struct dentry *dentry = NULL; + struct file *f = NULL; + + if (path == NULL && fdes == -1) + return -EINVAL; + + if (path != NULL && fdes != -1) + return -EINVAL; + + lock_kernel(); + + error = -EINVAL; + + if (path) { + error = user_path_walk_link(path, &nd); + + if (!error) + dentry = nd.dentry; + } + else { + f = fget (fdes); + + if (f) + dentry = f->f_dentry; + } + + if (dentry) { + error = -EOPNOTSUPP; + + if (dentry->d_inode->i_op && + dentry->d_inode->i_op->acl_get && + !(error = do_revalidate(dentry))) { + + error = dentry->d_inode->i_op->acl_get(dentry, + acl, + dacl); + } + + if (path) + path_release(&nd); + else + fput(f); + } + + unlock_kernel(); + + return error; +} + +/* + * syscall to set an ACL on a file descriptor or path + * + * if no i_op set then return -EOPNOTSUPP (ENOTSUP equivalent for Linux) + */ + +asmlinkage long sys_acl_set( + const char *path, + int fdes, + struct acl *acl, + struct acl *dacl) +{ + int error; + struct nameidata nd; + struct dentry *dentry = NULL; + struct file *f = NULL; + + if (path == NULL && fdes == -1) + return -EINVAL; + + if (path != NULL && fdes != -1) + return -EINVAL; + + lock_kernel(); + + error = -EINVAL; + + if (path) { + error = user_path_walk_link(path, &nd); + + if (!error) + dentry = nd.dentry; + } + else { + f = fget (fdes); + + if (f) + dentry = f->f_dentry; + } + + if (dentry) { + error = -EOPNOTSUPP; + + if (dentry->d_inode->i_op && + dentry->d_inode->i_op->acl_set && + !(error = do_revalidate(dentry))) { + + error = dentry->d_inode->i_op->acl_set(dentry, + acl, + dacl); + if (!error) { + error = do_revalidate(dentry); + } + } + + if (path) + path_release(&nd); + else + fput(f); + } + + unlock_kernel(); + + return error; +} diff -rNu linux-2.4.7/linux/fs/proc/CVS/Entries linux-2.4-xfs/linux/fs/proc/CVS/Entries --- linux-2.4.7/linux/fs/proc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/proc/CVS/Entries Thu Jul 5 12:03:35 2001 @@ -0,0 +1,13 @@ +/Makefile/1.10/Tue May 29 19:53:13 2001/-ko/ +/array.c/1.29/Wed Jun 13 03:24:09 2001/-ko/ +/base.c/1.27/Thu Jul 5 03:57:00 2001/-ko/ +/generic.c/1.22/Tue Jul 3 02:33:57 2001/-ko/ +/inode-alloc.txt/1.4/Wed Nov 24 20:36:16 1999/-ko/ +/inode.c/1.14/Wed May 2 06:22:13 2001/-ko/ +/kcore.c/1.10/Thu Feb 1 17:10:24 2001/-ko/ +/kmsg.c/1.6/Sun Feb 27 22:37:25 2000/-ko/ +/proc_devtree.c/1.7/Fri May 26 01:52:46 2000/-ko/ +/proc_misc.c/1.18/Wed May 2 06:22:13 2001/-ko/ +/proc_tty.c/1.6/Tue May 2 22:18:18 2000/-ko/ +/root.c/1.23/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/proc/CVS/Repository linux-2.4-xfs/linux/fs/proc/CVS/Repository --- linux-2.4.7/linux/fs/proc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/proc/CVS/Repository Thu Jul 5 12:03:33 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/proc diff -rNu linux-2.4.7/linux/fs/proc/CVS/Root linux-2.4-xfs/linux/fs/proc/CVS/Root --- linux-2.4.7/linux/fs/proc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/proc/CVS/Root Thu Jul 5 12:03:33 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/qnx4/CVS/Entries linux-2.4-xfs/linux/fs/qnx4/CVS/Entries --- linux-2.4.7/linux/fs/qnx4/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/qnx4/CVS/Entries Thu Jul 5 12:03:35 2001 @@ -0,0 +1,12 @@ +/BUGS/1.3/Wed Dec 29 19:17:52 1999/-ko/ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/README/1.4/Tue Jan 11 18:48:48 2000/-ko/ +/TODO/1.3/Wed Dec 29 19:17:52 1999/-ko/ +/bitmap.c/1.8/Thu Sep 28 22:42:39 2000/-ko/ +/dir.c/1.10/Thu Sep 28 22:42:39 2000/-ko/ +/file.c/1.8/Sun Feb 27 22:37:25 2000/-ko/ +/fsync.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/inode.c/1.23/Wed May 2 06:22:13 2001/-ko/ +/namei.c/1.9/Thu Sep 28 22:42:39 2000/-ko/ +/truncate.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/qnx4/CVS/Repository linux-2.4-xfs/linux/fs/qnx4/CVS/Repository --- linux-2.4.7/linux/fs/qnx4/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/qnx4/CVS/Repository Thu Jul 5 12:03:35 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/qnx4 diff -rNu linux-2.4.7/linux/fs/qnx4/CVS/Root linux-2.4-xfs/linux/fs/qnx4/CVS/Root --- linux-2.4.7/linux/fs/qnx4/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/qnx4/CVS/Root Thu Jul 5 12:03:35 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/ramfs/CVS/Entries linux-2.4-xfs/linux/fs/ramfs/CVS/Entries --- linux-2.4.7/linux/fs/ramfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ramfs/CVS/Entries Thu Jul 5 12:03:36 2001 @@ -0,0 +1,3 @@ +/Makefile/1.2/Thu Dec 21 05:48:12 2000/-ko/ +/inode.c/1.12/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/ramfs/CVS/Repository linux-2.4-xfs/linux/fs/ramfs/CVS/Repository --- linux-2.4.7/linux/fs/ramfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ramfs/CVS/Repository Thu Jul 5 12:03:35 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/ramfs diff -rNu linux-2.4.7/linux/fs/ramfs/CVS/Root linux-2.4-xfs/linux/fs/ramfs/CVS/Root --- linux-2.4.7/linux/fs/ramfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ramfs/CVS/Root Thu Jul 5 12:03:35 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/reiserfs/CVS/Entries linux-2.4-xfs/linux/fs/reiserfs/CVS/Entries --- linux-2.4.7/linux/fs/reiserfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/reiserfs/CVS/Entries Thu Jul 5 12:03:43 2001 @@ -0,0 +1,24 @@ +/Makefile/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/README/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/bitmap.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/buffer2.c/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/dir.c/1.3/Mon Jul 2 15:59:04 2001/-ko/ +/do_balan.c/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/file.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/fix_node.c/1.5/Mon Jul 2 15:59:04 2001/-ko/ +/hashes.c/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/ibalance.c/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/inode.c/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/ioctl.c/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/item_ops.c/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/journal.c/1.4/Mon Jul 2 15:59:04 2001/-ko/ +/lbalance.c/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/namei.c/1.4/Mon Jul 2 15:59:04 2001/-ko/ +/objectid.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/prints.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/resize.c/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/stree.c/1.4/Wed Jun 13 03:24:09 2001/-ko/ +/super.c/1.5/Mon Jul 2 15:59:04 2001/-ko/ +/tail_conversion.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/version.c/1.1/Thu Feb 1 17:10:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/reiserfs/CVS/Repository linux-2.4-xfs/linux/fs/reiserfs/CVS/Repository --- linux-2.4.7/linux/fs/reiserfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/reiserfs/CVS/Repository Thu Jul 5 12:03:36 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/reiserfs diff -rNu linux-2.4.7/linux/fs/reiserfs/CVS/Root linux-2.4-xfs/linux/fs/reiserfs/CVS/Root --- linux-2.4.7/linux/fs/reiserfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/reiserfs/CVS/Root Thu Jul 5 12:03:36 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/romfs/CVS/Entries linux-2.4-xfs/linux/fs/romfs/CVS/Entries --- linux-2.4.7/linux/fs/romfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/romfs/CVS/Entries Thu Jul 5 12:03:43 2001 @@ -0,0 +1,3 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/inode.c/1.22/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/romfs/CVS/Repository linux-2.4-xfs/linux/fs/romfs/CVS/Repository --- linux-2.4.7/linux/fs/romfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/romfs/CVS/Repository Thu Jul 5 12:03:43 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/romfs diff -rNu linux-2.4.7/linux/fs/romfs/CVS/Root linux-2.4-xfs/linux/fs/romfs/CVS/Root --- linux-2.4.7/linux/fs/romfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/romfs/CVS/Root Thu Jul 5 12:03:43 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/smbfs/CVS/Entries linux-2.4-xfs/linux/fs/smbfs/CVS/Entries --- linux-2.4.7/linux/fs/smbfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/smbfs/CVS/Entries Thu Jul 5 12:03:45 2001 @@ -0,0 +1,13 @@ +/ChangeLog/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/Makefile/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/cache.c/1.11/Mon Apr 2 17:13:32 2001/-ko/ +/dir.c/1.14/Tue May 29 19:53:13 2001/-ko/ +/file.c/1.20/Thu Jun 21 15:45:04 2001/-ko/ +/getopt.c/1.2/Wed May 2 06:22:13 2001/-ko/ +/getopt.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/inode.c/1.22/Thu Jun 21 15:45:04 2001/-ko/ +/ioctl.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/proc.c/1.11/Thu Jun 21 15:45:04 2001/-ko/ +/smb_debug.h/1.2/Fri Jan 5 18:42:30 2001/-ko/ +/sock.c/1.8/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/smbfs/CVS/Repository linux-2.4-xfs/linux/fs/smbfs/CVS/Repository --- linux-2.4.7/linux/fs/smbfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/smbfs/CVS/Repository Thu Jul 5 12:03:43 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/smbfs diff -rNu linux-2.4.7/linux/fs/smbfs/CVS/Root linux-2.4-xfs/linux/fs/smbfs/CVS/Root --- linux-2.4.7/linux/fs/smbfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/smbfs/CVS/Root Thu Jul 5 12:03:43 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/super.c linux-2.4-xfs/linux/fs/super.c --- linux-2.4.7/linux/fs/super.c Thu Jun 14 16:16:58 2001 +++ linux-2.4-xfs/linux/fs/super.c Thu Jun 21 10:45:04 2001 @@ -1305,8 +1305,16 @@ /* get superblock, locks mount_sem on success */ if (fstype->fs_flags & FS_NOMOUNT) sb = ERR_PTR(-EINVAL); - else if (fstype->fs_flags & FS_REQUIRES_DEV) + else if (fstype->fs_flags & FS_REQUIRES_DEV) { sb = get_sb_bdev(fstype, name, flags, data); + if (!IS_ERR(sb)) { + if (sb->s_op && sb->s_op->dmapi_mount_event) { + retval = sb->s_op->dmapi_mount_event(sb, name); + if (retval) + goto fail; + } + } + } else if (fstype->fs_flags & FS_SINGLE) sb = get_sb_single(fstype, flags, data); else @@ -1314,6 +1322,7 @@ retval = PTR_ERR(sb); if (IS_ERR(sb)) { +fail: if (mnt->mnt_devname) kfree(mnt->mnt_devname); kmem_cache_free(mnt_cache, mnt); diff -rNu linux-2.4.7/linux/fs/sysv/CVS/Entries linux-2.4-xfs/linux/fs/sysv/CVS/Entries --- linux-2.4.7/linux/fs/sysv/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/sysv/CVS/Entries Thu Jul 5 12:03:46 2001 @@ -0,0 +1,12 @@ +/CHANGES/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/INTRO/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Makefile/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/balloc.c/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/dir.c/1.8/Tue Jul 3 02:33:57 2001/-ko/ +/file.c/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/ialloc.c/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/inode.c/1.21/Tue Jul 3 02:33:57 2001/-ko/ +/itree.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/namei.c/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/super.c/1.1/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/sysv/CVS/Repository linux-2.4-xfs/linux/fs/sysv/CVS/Repository --- linux-2.4.7/linux/fs/sysv/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/sysv/CVS/Repository Thu Jul 5 12:03:45 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/sysv diff -rNu linux-2.4.7/linux/fs/sysv/CVS/Root linux-2.4-xfs/linux/fs/sysv/CVS/Root --- linux-2.4.7/linux/fs/sysv/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/sysv/CVS/Root Thu Jul 5 12:03:45 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/udf/CVS/Entries linux-2.4-xfs/linux/fs/udf/CVS/Entries --- linux-2.4.7/linux/fs/udf/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/udf/CVS/Entries Thu Jul 5 12:03:49 2001 @@ -0,0 +1,23 @@ +/Makefile/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/balloc.c/1.8/Sat Jun 9 02:44:24 2001/-ko/ +/crc.c/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/dir.c/1.14/Sat Jun 9 02:44:24 2001/-ko/ +/directory.c/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/file.c/1.23/Sat Jun 9 02:44:24 2001/-ko/ +/fsync.c/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/ialloc.c/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/inode.c/1.21/Tue Jul 3 02:33:57 2001/-ko/ +/lowlevel.c/1.8/Sat Jun 9 02:44:24 2001/-ko/ +/misc.c/1.8/Sat Jun 9 02:44:24 2001/-ko/ +/namei.c/1.16/Sat Jun 9 02:44:24 2001/-ko/ +/partition.c/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/super.c/1.19/Sat Jun 9 02:44:24 2001/-ko/ +/symlink.c/1.12/Sat Jun 9 02:44:24 2001/-ko/ +/truncate.c/1.8/Sat Jun 9 02:44:24 2001/-ko/ +/udf_i.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/udf_sb.h/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/udfdecl.h/1.13/Sat Jun 9 02:44:24 2001/-ko/ +/udfend.h/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/udftime.c/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/unicode.c/1.5/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/udf/CVS/Repository linux-2.4-xfs/linux/fs/udf/CVS/Repository --- linux-2.4.7/linux/fs/udf/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/udf/CVS/Repository Thu Jul 5 12:03:46 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/udf diff -rNu linux-2.4.7/linux/fs/udf/CVS/Root linux-2.4-xfs/linux/fs/udf/CVS/Root --- linux-2.4.7/linux/fs/udf/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/udf/CVS/Root Thu Jul 5 12:03:46 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/ufs/CVS/Entries linux-2.4-xfs/linux/fs/ufs/CVS/Entries --- linux-2.4.7/linux/fs/ufs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ufs/CVS/Entries Thu Jul 5 12:03:51 2001 @@ -0,0 +1,15 @@ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/balloc.c/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/cylinder.c/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/dir.c/1.11/Thu Sep 28 22:42:39 2000/-ko/ +/file.c/1.7/Sun Feb 27 22:49:22 2000/-ko/ +/ialloc.c/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/inode.c/1.14/Sun Dec 17 19:15:00 2000/-ko/ +/namei.c/1.10/Thu Sep 28 22:42:39 2000/-ko/ +/super.c/1.18/Tue May 29 19:53:13 2001/-ko/ +/swab.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/symlink.c/1.7/Fri Apr 21 16:16:46 2000/-ko/ +/truncate.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/util.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/util.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/fs/ufs/CVS/Repository linux-2.4-xfs/linux/fs/ufs/CVS/Repository --- linux-2.4.7/linux/fs/ufs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ufs/CVS/Repository Thu Jul 5 12:03:49 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/ufs diff -rNu linux-2.4.7/linux/fs/ufs/CVS/Root linux-2.4-xfs/linux/fs/ufs/CVS/Root --- linux-2.4.7/linux/fs/ufs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/ufs/CVS/Root Thu Jul 5 12:03:49 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/umsdos/CVS/Entries linux-2.4-xfs/linux/fs/umsdos/CVS/Entries --- linux-2.4.7/linux/fs/umsdos/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/umsdos/CVS/Entries Thu Jul 5 12:03:52 2001 @@ -0,0 +1,12 @@ +/Makefile/1.6/Thu Dec 21 05:48:12 2000/-ko/ +/README-WIP.txt/1.3/Wed Dec 15 00:05:45 1999/-ko/ +/dir.c/1.15/Thu Feb 22 21:09:04 2001/-ko/ +/emd.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/inode.c/1.16/Tue May 29 19:53:13 2001/-ko/ +/ioctl.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/mangle.c/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/namei.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/notes/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/rdir.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/specs/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/fs/umsdos/CVS/Repository linux-2.4-xfs/linux/fs/umsdos/CVS/Repository --- linux-2.4.7/linux/fs/umsdos/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/umsdos/CVS/Repository Thu Jul 5 12:03:51 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/umsdos diff -rNu linux-2.4.7/linux/fs/umsdos/CVS/Root linux-2.4-xfs/linux/fs/umsdos/CVS/Root --- linux-2.4.7/linux/fs/umsdos/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/umsdos/CVS/Root Thu Jul 5 12:03:51 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/vfat/CVS/Entries linux-2.4-xfs/linux/fs/vfat/CVS/Entries --- linux-2.4.7/linux/fs/vfat/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/vfat/CVS/Entries Thu Jul 5 12:03:53 2001 @@ -0,0 +1,4 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/namei.c/1.19/Wed May 2 06:22:13 2001/-ko/ +/vfatfs_syms.c/1.4/Wed Mar 15 18:20:34 2000/-ko/ +D diff -rNu linux-2.4.7/linux/fs/vfat/CVS/Repository linux-2.4-xfs/linux/fs/vfat/CVS/Repository --- linux-2.4.7/linux/fs/vfat/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/vfat/CVS/Repository Thu Jul 5 12:03:52 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/vfat diff -rNu linux-2.4.7/linux/fs/vfat/CVS/Root linux-2.4-xfs/linux/fs/vfat/CVS/Root --- linux-2.4.7/linux/fs/vfat/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/vfat/CVS/Root Thu Jul 5 12:03:52 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/xfs/CVS/Entries linux-2.4-xfs/linux/fs/xfs/CVS/Entries --- linux-2.4.7/linux/fs/xfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/CVS/Entries Thu Jul 5 12:04:24 2001 @@ -0,0 +1,125 @@ +/Makefile/1.121/Wed Apr 11 01:44:54 2001// +/mac_xfs.c/1.10/Mon Mar 12 19:10:09 2001// +/macstubs.c/1.7/Mon Jan 15 10:28:46 2001// +/xfs.h/1.18/Wed Apr 25 05:02:25 2001/-ko/ +/xfs_acl.c/1.4/Tue Apr 17 05:16:51 2001/-ko/ +/xfs_acl.h/1.4/Tue Apr 17 05:16:51 2001/-ko/ +/xfs_ag.h/1.38/Mon May 14 15:27:31 2001// +/xfs_alloc.c/1.140/Thu Apr 19 02:37:23 2001// +/xfs_alloc.h/1.47/Mon Sep 25 05:42:07 2000// +/xfs_alloc_btree.c/1.68/Thu Apr 19 02:37:23 2001// +/xfs_alloc_btree.h/1.20/Mon Sep 25 05:42:07 2000// +/xfs_arch.h/1.33/Thu Nov 16 02:50:50 2000/-ko/ +/xfs_attr.c/1.84/Thu Apr 19 02:37:23 2001// +/xfs_attr.h/1.15/Mon Sep 25 05:42:07 2000// +/xfs_attr_fetch.c/1.8/Mon Sep 25 05:42:07 2000// +/xfs_attr_leaf.c/1.53/Wed Apr 11 01:44:54 2001// +/xfs_attr_leaf.h/1.26/Mon Sep 25 05:42:07 2000// +/xfs_attr_sf.h/1.13/Mon Sep 25 05:42:07 2000// +/xfs_bit.c/1.13/Wed Apr 11 01:44:54 2001// +/xfs_bit.h/1.7/Mon Sep 25 05:42:07 2000// +/xfs_bmap.c/1.269/Thu Apr 19 02:37:23 2001// +/xfs_bmap.h/1.76/Fri Sep 29 19:03:03 2000// +/xfs_bmap_btree.c/1.121/Thu Apr 19 02:37:23 2001// +/xfs_bmap_btree.h/1.50/Mon Sep 25 05:42:07 2000// +/xfs_btree.c/1.91/Fri May 25 05:08:09 2001// +/xfs_btree.h/1.51/Tue Apr 3 17:32:55 2001// +/xfs_buf.h/1.74/Tue May 15 15:00:03 2001// +/xfs_buf_item.c/1.114/Wed Apr 11 16:27:03 2001// +/xfs_buf_item.h/1.33/Tue Apr 3 02:52:38 2001// +/xfs_clnt.h/1.23/Fri Jun 29 22:29:47 2001// +/xfs_cxfs.h/1.7/Mon Sep 25 05:42:07 2000// +/xfs_da_btree.c/1.119/Mon Jul 2 18:15:34 2001// +/xfs_da_btree.h/1.40/Mon Sep 25 05:42:07 2000// +/xfs_dfrag.c/1.27/Wed Apr 11 01:44:54 2001// +/xfs_dfrag.h/1.5/Mon Sep 25 05:42:07 2000// +/xfs_dinode.h/1.57/Tue Nov 14 23:40:34 2000// +/xfs_dir.c/1.133/Thu Apr 19 02:37:23 2001// +/xfs_dir.h/1.37/Mon Sep 25 05:42:07 2000// +/xfs_dir2.c/1.31/Mon Apr 23 19:52:01 2001// +/xfs_dir2.h/1.9/Wed Apr 11 01:44:54 2001// +/xfs_dir2_block.c/1.21/Mon Apr 23 19:52:01 2001// +/xfs_dir2_block.h/1.7/Wed Apr 11 01:44:54 2001// +/xfs_dir2_data.c/1.15/Thu Apr 12 23:35:02 2001// +/xfs_dir2_data.h/1.6/Mon Sep 25 05:42:07 2000// +/xfs_dir2_leaf.c/1.22/Mon Apr 23 19:52:01 2001// +/xfs_dir2_leaf.h/1.8/Wed Apr 11 01:44:54 2001// +/xfs_dir2_node.c/1.21/Mon Apr 23 19:52:01 2001// +/xfs_dir2_node.h/1.5/Mon Sep 25 05:42:07 2000// +/xfs_dir2_sf.c/1.23/Mon Apr 23 19:52:01 2001// +/xfs_dir2_sf.h/1.11/Wed Apr 11 01:44:54 2001// +/xfs_dir2_trace.c/1.8/Mon Sep 25 05:42:07 2000// +/xfs_dir2_trace.h/1.5/Mon Sep 25 05:42:07 2000// +/xfs_dir_leaf.c/1.96/Thu Apr 12 23:35:02 2001// +/xfs_dir_leaf.h/1.32/Wed Apr 11 01:44:54 2001// +/xfs_dir_sf.h/1.19/Mon Sep 25 05:42:07 2000// +/xfs_dmapi.c/1.36/Thu May 24 23:17:45 2001/-ko/ +/xfs_dmapi.h/1.15/Wed Jan 17 04:01:25 2001// +/xfs_dqblk.h/1.6/Tue Apr 3 02:52:38 2001// +/xfs_dquot.c/1.59/Thu Apr 19 02:37:23 2001// +/xfs_dquot.h/1.19/Wed May 23 05:32:22 2001// +/xfs_dquot_item.c/1.24/Wed Apr 11 16:27:03 2001// +/xfs_dquot_item.h/1.6/Tue Apr 3 02:52:38 2001// +/xfs_error.c/1.31/Wed Apr 11 01:44:54 2001// +/xfs_error.h/1.21/Mon Mar 12 19:36:49 2001// +/xfs_extfree_item.c/1.46/Wed Apr 11 16:27:03 2001// +/xfs_extfree_item.h/1.13/Mon Sep 25 05:42:07 2000// +/xfs_fsops.c/1.65/Wed Apr 11 01:44:54 2001// +/xfs_fsops.h/1.18/Mon Sep 25 05:42:07 2000// +/xfs_grio.c/1.87/Fri Jun 15 12:09:10 2001// +/xfs_grio.h/1.3/Wed Dec 6 04:48:11 2000/-ko/ +/xfs_ialloc.c/1.145/Mon May 14 15:39:44 2001// +/xfs_ialloc.h/1.39/Mon Sep 25 05:42:07 2000// +/xfs_ialloc_btree.c/1.65/Thu Apr 12 23:35:02 2001// +/xfs_ialloc_btree.h/1.20/Tue Sep 26 02:03:57 2000// +/xfs_iget.c/1.145/Tue Jun 19 01:57:21 2001// +/xfs_imap.h/1.7/Mon Sep 25 05:42:07 2000// +/xfs_inode.c/1.320/Fri Jun 8 20:55:16 2001// +/xfs_inode.h/1.150/Fri Jun 8 20:55:16 2001// +/xfs_inode_item.c/1.96/Tue Apr 10 01:57:29 2001// +/xfs_inode_item.h/1.38/Mon Sep 25 05:42:07 2000// +/xfs_inum.h/1.18/Mon Sep 25 05:42:07 2000// +/xfs_iocore.c/1.25/Mon Apr 16 22:49:09 2001// +/xfs_itable.c/1.98/Wed Apr 11 01:44:54 2001// +/xfs_itable.h/1.32/Mon Sep 25 05:42:07 2000// +/xfs_log.c/1.237/Thu May 17 02:58:46 2001// +/xfs_log.h/1.56/Wed Apr 18 16:19:03 2001// +/xfs_log_priv.h/1.77/Fri Feb 23 19:08:48 2001// +/xfs_log_recover.c/1.207/Fri Apr 13 16:34:37 2001// +/xfs_log_recover.h/1.15/Mon Sep 25 05:42:07 2000// +/xfs_macros.c/1.38/Mon May 14 15:27:31 2001// +/xfs_macros.h/1.17/Mon Sep 25 05:42:07 2000// +/xfs_mount.c/1.257/Fri Jun 29 22:29:47 2001// +/xfs_mount.h/1.129/Fri Jun 29 22:29:47 2001// +/xfs_qm.c/1.69/Thu May 24 03:34:41 2001// +/xfs_qm.h/1.18/Tue Apr 3 02:52:38 2001// +/xfs_qm_syscalls.c/1.52/Wed Apr 11 01:44:54 2001// +/xfs_quota.h/1.24/Tue Apr 17 01:11:30 2001// +/xfs_quota_priv.h/1.19/Wed May 23 05:32:22 2001// +/xfs_rename.c/1.31/Wed Apr 11 01:44:54 2001// +/xfs_rtalloc.c/1.67/Tue Jun 26 21:08:42 2001// +/xfs_rtalloc.h/1.20/Mon Sep 25 05:42:07 2000// +/xfs_rtbit.c/1.7/Mon Sep 25 05:42:07 2000// +/xfs_rw.c/1.339/Mon May 14 15:39:44 2001// +/xfs_rw.h/1.58/Tue Mar 6 19:44:15 2001// +/xfs_sb.h/1.50/Tue Apr 3 02:52:38 2001// +/xfs_trans.c/1.120/Thu May 17 02:58:46 2001// +/xfs_trans.h/1.107/Mon Sep 25 05:42:07 2000// +/xfs_trans_ail.c/1.59/Thu Apr 19 02:37:23 2001// +/xfs_trans_buf.c/1.94/Tue Jun 26 20:52:59 2001// +/xfs_trans_dquot.c/1.32/Wed Apr 11 16:27:03 2001// +/xfs_trans_extfree.c/1.19/Mon Sep 25 05:42:07 2000// +/xfs_trans_inode.c/1.37/Mon Sep 25 05:42:07 2000// +/xfs_trans_item.c/1.28/Wed Apr 11 01:44:54 2001// +/xfs_trans_priv.h/1.17/Mon Sep 25 05:42:07 2000// +/xfs_trans_space.h/1.9/Mon Sep 25 05:42:07 2000// +/xfs_types.h/1.51/Thu Apr 19 02:37:23 2001// +/xfs_utils.c/1.37/Wed Apr 11 01:44:54 2001// +/xfs_utils.h/1.14/Mon Jan 15 10:28:46 2001// +/xfs_vfsops.c/1.320/Mon Jul 2 22:36:00 2001// +/xfs_vnodeops.c/1.506/Tue Jun 26 22:07:29 2001// +/xfsdmapistubs.c/1.8/Tue Sep 26 06:26:39 2000// +/xfsidbg.c/1.162/Thu May 17 02:58:46 2001// +/xfsquotasstubs.c/1.14/Thu May 24 03:34:41 2001// +/xfsrtstubs.c/1.11/Wed Mar 7 20:19:24 2001// +D diff -rNu linux-2.4.7/linux/fs/xfs/CVS/Entries.Log linux-2.4-xfs/linux/fs/xfs/CVS/Entries.Log --- linux-2.4.7/linux/fs/xfs/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/CVS/Entries.Log Thu Jul 5 12:04:26 2001 @@ -0,0 +1,2 @@ +A D/dmapi//// +A D/linux//// diff -rNu linux-2.4.7/linux/fs/xfs/CVS/Repository linux-2.4-xfs/linux/fs/xfs/CVS/Repository --- linux-2.4.7/linux/fs/xfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/CVS/Repository Thu Jul 5 12:03:53 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/xfs diff -rNu linux-2.4.7/linux/fs/xfs/CVS/Root linux-2.4-xfs/linux/fs/xfs/CVS/Root --- linux-2.4.7/linux/fs/xfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/CVS/Root Thu Jul 5 12:03:53 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/xfs/Makefile linux-2.4-xfs/linux/fs/xfs/Makefile --- linux-2.4.7/linux/fs/xfs/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/Makefile Tue Apr 10 20:44:54 2001 @@ -0,0 +1,156 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# Makefile for XFS on Linux. +# + +#CFLAGS := $(filter-out -Wall,$(CFLAGS)) + +# This needs -I. because everything does #include instead of "xfs.h". +# The code is wrong, local files should be included using "xfs.h", not +# but I am not going to change every file at the moment. It also needs +# -I $TOPDIR/fs to pick up #include , the support files should +# really be in linux/include/xfs_support, not hidden under fs. Keith Owens. +EXTRA_CFLAGS += -I. -I$(TOPDIR)/fs -funsigned-char + +ifeq ($(CONFIG_XFS_DEBUG),y) + EXTRA_CFLAGS += -DDEBUG -DXFSDEBUG +endif + +subdir-$(CONFIG_XFS_FS) += linux +ifeq ($(CONFIG_XFS_DMAPI),y) + subdir-$(CONFIG_XFS_FS) += dmapi +endif + +# fs/Makefile enters fs/xfs twice if CONFIG_XFS_FS is y, once for kernel and +# once for modules. This is necessary because xfsidbg is built as a module even +# if xfs is in kernel. Alas the shorthand form +# O_TARGET := xfs.o +# obj-m := $(O_TARGET) +# fails when the makefile is run more than once, code gets compiled as both +# kernel and as module, which one gets linked depends on the phase of the moon. +# I just love these layer violations where a makefile behaves differently +# depending on changes to its parent. Work around by only setting obj-m when +# xfs is selected as a module. Keith Owens. + +O_TARGET := xfs.o +ifeq ($(CONFIG_XFS_FS),m) + obj-m := $(O_TARGET) +endif + +# xfsidbg is always a module, but only if kdb is available. +ifeq ($(CONFIG_KDB),y) + obj-m += xfsidbg.o +endif + +ifeq ($(CONFIG_XFS_RT),) + obj-y += xfsrtstubs.o +else + obj-y += xfs_rtalloc.o xfs_rtbit.o +endif + +ifneq ($(CONFIG_XFS_GRIO),) + obj-y += xfs_grio.o +endif + +ifeq ($(CONFIG_XFS_DMAPI),) + obj-y += xfsdmapistubs.o +else + obj-y += dmapi/dmapi.o xfs_dmapi.o +endif + +ifeq ($(CONFIG_XFS_QUOTA),) + obj-y += xfsquotasstubs.o +else + obj-y += xfs_dquot.o xfs_trans_dquot.o xfs_dquot_item.o xfs_qm_syscalls.o xfs_qm.o +endif + +ifneq ($(CONFIG_FS_POSIX_ACL),) + obj-y += xfs_acl.o +endif + +obj-y += xfs_alloc.o \ + xfs_alloc_btree.o \ + xfs_attr.o \ + xfs_attr_fetch.o \ + xfs_attr_leaf.o \ + xfs_bit.o \ + xfs_bmap.o \ + xfs_bmap_btree.o \ + xfs_btree.o \ + xfs_buf_item.o \ + xfs_da_btree.o \ + xfs_dir.o \ + xfs_dir2.o \ + xfs_dir2_block.o \ + xfs_dir2_data.o \ + xfs_dir2_leaf.o \ + xfs_dir2_node.o \ + xfs_dir2_sf.o \ + xfs_dir2_trace.o \ + xfs_dir_leaf.o \ + xfs_error.o \ + xfs_extfree_item.o \ + xfs_fsops.o \ + xfs_ialloc.o \ + xfs_ialloc_btree.o \ + xfs_iget.o \ + xfs_inode.o \ + xfs_inode_item.o \ + xfs_iocore.o \ + xfs_itable.o \ + xfs_dfrag.o \ + xfs_log.o \ + xfs_log_recover.o \ + xfs_macros.o \ + xfs_mount.o \ + xfs_rename.o \ + xfs_trans.o \ + xfs_trans_ail.o \ + xfs_trans_buf.o \ + xfs_trans_extfree.o \ + xfs_trans_inode.o \ + xfs_trans_item.o \ + xfs_utils.o \ + xfs_vfsops.o \ + xfs_vnodeops.o \ + xfs_rw.o \ + macstubs.o + +# Objects not built in this directory +obj-y += linux/linux_xfs.o + +include $(TOPDIR)/Rules.make + +# This is really nasty, but Rules.make was never designed for multi directory +# modules. Keith Owens. + +xfs.o: $(patsubst %,_modsubdir_%,$(subdir-m)) diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/CVS/Entries linux-2.4-xfs/linux/fs/xfs/dmapi/CVS/Entries --- linux-2.4.7/linux/fs/xfs/dmapi/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/CVS/Entries Thu Jul 5 12:04:26 2001 @@ -0,0 +1,18 @@ +/Makefile/1.10/Wed Mar 14 08:07:20 2001/-ko/ +/Status/1.3/Wed Oct 25 13:02:50 2000/-ko/ +/dmapi_attr.c/1.4/Mon Oct 2 15:19:34 2000/-ko/ +/dmapi_bulkattr.c/1.4/Mon Oct 2 15:19:34 2000/-ko/ +/dmapi_config.c/1.5/Wed Oct 11 15:45:35 2000/-ko/ +/dmapi_dmattr.c/1.4/Mon Oct 2 15:19:34 2000/-ko/ +/dmapi_event.c/1.5/Wed Oct 11 15:45:35 2000/-ko/ +/dmapi_handle.c/1.4/Mon Oct 2 15:19:34 2000/-ko/ +/dmapi_hole.c/1.4/Mon Oct 2 15:19:34 2000/-ko/ +/dmapi_io.c/1.4/Mon Oct 2 15:19:34 2000/-ko/ +/dmapi_mountinfo.c/1.7/Fri Oct 20 06:02:14 2000/-ko/ +/dmapi_private.h/1.5/Wed Oct 11 15:45:35 2000/-ko/ +/dmapi_region.c/1.4/Mon Oct 2 15:19:34 2000/-ko/ +/dmapi_register.c/1.10/Sat Apr 7 02:03:36 2001/-ko/ +/dmapi_right.c/1.7/Wed Oct 11 15:45:35 2000/-ko/ +/dmapi_session.c/1.8/Wed Jun 6 21:08:08 2001/-ko/ +/dmapi_sysent.c/1.9/Fri Jun 15 12:09:10 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/CVS/Repository linux-2.4-xfs/linux/fs/xfs/dmapi/CVS/Repository --- linux-2.4.7/linux/fs/xfs/dmapi/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/CVS/Repository Thu Jul 5 12:04:24 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/xfs/dmapi diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/CVS/Root linux-2.4-xfs/linux/fs/xfs/dmapi/CVS/Root --- linux-2.4.7/linux/fs/xfs/dmapi/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/CVS/Root Thu Jul 5 12:04:24 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/Makefile linux-2.4-xfs/linux/fs/xfs/dmapi/Makefile --- linux-2.4.7/linux/fs/xfs/dmapi/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/Makefile Wed Mar 14 02:07:20 2001 @@ -0,0 +1,76 @@ +# +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +#CFLAGS := $(filter-out -Wall,$(CFLAGS)) + +# This needs -I.. because everything does #include instead of "xfs.h". +# The code is wrong, local files should be included using "xfs.h", not +# but I am not going to change every file at the moment. It also needs +# -I $TOPDIR/fs to pick up #include , the support files should +# really be in linux/include/xfs_support, not hidden under fs. Keith Owens. +EXTRA_CFLAGS += -g3 -Wno-unused -Wno-parentheses \ + -Wno-uninitialized -I../linux -I.. -I $(TOPDIR)/fs \ + -funsigned-char + +EXTRA_CFLAGS += $(shell if $(CC) -Wno-unknown-pragmas -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-Wno-unknown-pragmas"; fi) + +ifeq ($(CONFIG_XFS_DEBUG),y) + EXTRA_CFLAGS += -DDEBUG -DXFSDEBUG +endif + +O_TARGET := dmapi.o +ifneq ($(MAKECMDGOALS),modules_install) + obj-m := $(O_TARGET) +endif + +obj-y += dmapi_sysent.o \ + dmapi_attr.o \ + dmapi_config.o \ + dmapi_bulkattr.o \ + dmapi_dmattr.o \ + dmapi_event.o \ + dmapi_handle.o \ + dmapi_hole.o \ + dmapi_io.o \ + dmapi_mountinfo.o \ + dmapi_region.o \ + dmapi_register.o \ + dmapi_right.o \ + dmapi_session.o + +include $(TOPDIR)/Rules.make diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/Status linux-2.4-xfs/linux/fs/xfs/dmapi/Status --- linux-2.4.7/linux/fs/xfs/dmapi/Status Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/Status Wed Oct 25 08:02:50 2000 @@ -0,0 +1,126 @@ +for linux: + + +68 external interfaces in libdm + + 56 of those interfaces go through to dmi(), the kernel side of DMAPI + + + +Functions known to work +---------------------------------------------- + +dm_create_session +dm_create_userevent +dm_destroy_session +dm_getall_sessions +dm_getall_tokens +dm_get_allocinfo +dm_get_bulkattr +dm_get_config_events +dm_get_dmattr +dm_get_eventlist +dm_get_events +dm_get_fileattr +dm_get_region +dm_handle_free +dm_init_attrloc +dm_init_service +dm_obj_ref_hold +dm_obj_ref_query +dm_obj_ref_rele +dm_path_to_fshandle +dm_path_to_handle +dm_punch_hole +dm_query_session +dm_read_invis +dm_remove_dmattr +dm_respond_event +dm_send_msg +dm_set_disp +dm_set_dmattr +dm_set_eventlist +dm_set_fileattr +dm_set_region +dm_sync_by_handle +dm_write_invis +34 + +Functions that seem to work (would like more rigorous test case) +------------------------------------------ + +dm_pending +dm_probe_hole - one test case of test_hole.c fails +dm_request_right +3 + +Functions untested but probably work +---------------------------------------------- + +dm_find_eventmsg +dm_handle_cmp +dm_handle_to_fshandle +dm_handle_to_ino +dm_release_right +5 + +Functions that do not work +----------------------------------------- + +dm_get_dioinfo - directio not implemented +1 + +Functions not supported in SGI DMAPI +------------------------------------------------------------- + +dm_clear_inherit +dm_create_by_handle +dm_getall_inherit +dm_get_bulkall +dm_mkdir_by_handle +dm_set_inherit +dm_symlink_by_handle + + + + +Functions that seem to work (would like more rigorous test case) +---------------------------------------------------------------- + +dm_get_config +dm_downgrade_right +dm_get_mountinfo +dm_set_return_on_destory +dm_upgrade_right + + + +Functions that do not work +----------------------------------------------------------------- + +dm_fd_to_handle - Irix getf not implemented on linux +dm_get_dirattrs - null pointer reference +dm_handle_to_path +dm_getall_dmattr - needs a copy_from_user in place of useracc + + +Functions that are untested, but probably work +----------------------------------------------------------------- + +dm_getall_disp +dm_handle_hash +dm_handle_is_valid +dm_handle_to_fsid +dm_handle_to_igen +dm_make_fshandle +dm_make_handle +dm_move_event +dm_query_right + + + +Other things not working +---------------------------------- + +- read/write events for memory-mapped I/O? + diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/dmapi_attr.c linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_attr.c --- linux-2.4.7/linux/fs/xfs/dmapi/dmapi_attr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_attr.c Mon Oct 2 10:19:34 2000 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +/* Retrieve attributes for a single file, directory or symlink. */ + +int +dm_get_fileattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_stat_t *statp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->get_fileattr(tdp->td_bdp, tdp->td_right, + mask, statp); + + dm_app_put_tdp(tdp); + return(error); +} + + +/* Set one or more file attributes of a file, directory, or symlink. */ + +int +dm_set_fileattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_fileattr_t *attrp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->set_fileattr(tdp->td_bdp, tdp->td_right, + mask, attrp); + + dm_app_put_tdp(tdp); + return(error); +} diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/dmapi_bulkattr.c linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_bulkattr.c --- linux-2.4.7/linux/fs/xfs/dmapi/dmapi_bulkattr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_bulkattr.c Mon Oct 2 10:19:34 2000 @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +int +dm_init_attrloc( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrloc_t *locp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS|DM_TDT_DIR, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->init_attrloc(tdp->td_bdp, tdp->td_right, locp); + + dm_app_put_tdp(tdp); + return(error); +} + + +/* + * Retrieves both standard and DM specific file attributes for the file + * system indicated by the handle. (The FS has to be mounted). + * Syscall returns 1 to indicate SUCCESS and more information is available. + * -1 is returned on error, and errno will be set appropriately. + * 0 is returned upon successful completion. + */ + +int +dm_get_bulkattr_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->get_bulkattr_rvp(tdp->td_bdp, tdp->td_right, + mask, locp, buflen, bufp, rlenp, rvp); + + dm_app_put_tdp(tdp); + return(error); +} + + +/* + * Retrieves attributes of directory entries given a handle to that + * directory. Iterative. + * Syscall returns 1 to indicate SUCCESS and more information is available. + * -1 is returned on error, and errno will be set appropriately. + * 0 is returned upon successful completion. + */ + +int +dm_get_dirattrs_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_DIR, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->get_dirattrs_rvp(tdp->td_bdp, tdp->td_right, + mask, locp, buflen, bufp, rlenp, rvp); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_get_bulkall_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrname_t *attrnamep, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->get_bulkall_rvp(tdp->td_bdp, tdp->td_right, + mask, attrnamep, locp, buflen, bufp, rlenp, rvp); + + dm_app_put_tdp(tdp); + return(error); +} diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/dmapi_config.c linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_config.c --- linux-2.4.7/linux/fs/xfs/dmapi/dmapi_config.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_config.c Wed Oct 11 10:45:35 2000 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + +int +dm_get_config( + void *hanp, + size_t hlen, + dm_config_t flagname, + dm_size_t *retvalp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + dm_size_t retval; + int system = 1; + int error; + + /* Trap and process configuration parameters which are system-wide. */ + + switch (flagname) { + case DM_CONFIG_LEGACY: + case DM_CONFIG_PENDING: + case DM_CONFIG_OBJ_REF: + retval = DM_TRUE; + break; + case DM_CONFIG_MAX_MESSAGE_DATA: + retval = DM_MAX_MSG_DATA; + break; + default: + system = 0; + break; + } + if (system) { +#ifdef __sgi + if (copyout(&retval, retvalp, sizeof(retval))) + return(EFAULT); +#else + if (copy_to_user(retvalp, &retval, sizeof(retval))) + return(EFAULT); +#endif + return(0); + } + + /* Must be filesystem-specific. Convert the handle into a vnode. */ + + if ((error = dm_get_config_tdp(hanp, hlen, &tdp)) != 0) + return(error); + + /* Now call the filesystem-specific routine to determine the + value of the configuration option for that filesystem. + */ + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->get_config(tdp->td_bdp, tdp->td_right, + flagname, retvalp); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_get_config_events( + void *hanp, + size_t hlen, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + /* Convert the handle into a vnode. */ + + if ((error = dm_get_config_tdp(hanp, hlen, &tdp)) != 0) + return(error); + + /* Now call the filesystem-specific routine to determine the + events supported by that filesystem. + */ + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->get_config_events(tdp->td_bdp, tdp->td_right, + nelem, eventsetp, nelemp); + + dm_app_put_tdp(tdp); + return(error); +} diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/dmapi_dmattr.c linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_dmattr.c --- linux-2.4.7/linux/fs/xfs/dmapi/dmapi_dmattr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_dmattr.c Mon Oct 2 10:19:34 2000 @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +int +dm_clear_inherit( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->clear_inherit(tdp->td_bdp, tdp->td_right, + attrnamep); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_get_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->get_dmattr(tdp->td_bdp, tdp->td_right, + attrnamep, buflen, bufp, rlenp); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_getall_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->getall_dmattr(tdp->td_bdp, tdp->td_right, + buflen, bufp, rlenp); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_getall_inherit( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_inherit_t *inheritbufp, + u_int *nelemp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->getall_inherit(tdp->td_bdp, tdp->td_right, + nelem, inheritbufp, nelemp); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_remove_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int setdtime, + dm_attrname_t *attrnamep) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->remove_dmattr(tdp->td_bdp, tdp->td_right, + setdtime, attrnamep); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_set_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + int setdtime, + size_t buflen, + void *bufp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->set_dmattr(tdp->td_bdp, tdp->td_right, + attrnamep, setdtime, buflen, bufp); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_set_inherit( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + mode_t mode) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->set_inherit(tdp->td_bdp, tdp->td_right, + attrnamep, mode); + + dm_app_put_tdp(tdp); + return(error); +} diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/dmapi_event.c linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_event.c --- linux-2.4.7/linux/fs/xfs/dmapi/dmapi_event.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_event.c Wed Oct 11 10:45:35 2000 @@ -0,0 +1,803 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + +/* The "rights" portion of the DMAPI spec is not currently implemented. A + framework for rights is provided in the code, but turns out to be a noop + in practice. The following comments are a brain dump to serve as input to + the poor soul that eventually has to get DMAPI rights working in IRIX. + + A DMAPI right is similar but not identical to the mrlock_t mechanism + already used within the kernel. The similarities are that it is a + sleeping lock, and that a multiple-reader, single-writer protocol is used. + How locks are obtained and dropped are different however. With a mrlock_t, + a thread grabs the lock, does some stuff, then drops the lock, and all other + threads block in the meantime (assuming a write lock). There is a one-to- + one relationship between the lock and the thread which obtained the lock. + Not so with DMAPI right locks. A DMAPI lock is associated with a particular + session/token/hanp/hlen quad; since there is a dm_tokdata_t structure for + each such quad, you can think of it as a one-to-one relationship between the + lock and a dm_tokdata_t. Any application thread which presents the correct + quad is entitled to grab or release the lock, or to use the rights + associated with that lock. The thread that grabs the lock does not have to + be the one to use the lock, nor does it have to be the thread which drops + the lock. The lock can be held for very long periods of time, even across + multiple systems calls by multiple application threads. The idea is that a + coordinated group of DMAPI application threads can grab the lock, issue a + series of inode accesses and/or updates, then drop the lock, and be assured + that no other thread in the system could be modifying the inode at the same + time. The kernel is expected to blindly trust that the application will + not forget to unlock inodes it has locked, and will not deadlock itself + against the kernel. + + There are two types of DMAPI rights, file object (inode) and filesystem + object (superblock?). An inode right is the equivalent of the combination + of both the XFS ilock and iolock; if held exclusively, no data or metadata + within the file can be changed by non-lock-holding threads. The filesystem + object lock is a little fuzzier; I think that if it is held, things like + unmounts can be blocked, plus there is an event mask associated with the + filesystem which can't be updated without the lock. (By the way, that + event mask is supposed to be persistent in the superblock; add that to + your worklist :-) + + All events generated by XFS currently arrive with no rights, i.e. + DM_RIGHT_NULL, and return to the filesystem with no rights. It would be + smart to leave it this way if possible, because it otherwise becomes more + likely that an application thread will deadlock against the kernel if the + one responsible for calling dm_get_events() happens to touch a file which + was locked at the time the event was queued. Since the thread is blocked, + it can't read the event in order to find and drop the lock. Catch-22. If + you do have events that arrive with non-null rights, then dm_enqueue() needs + to have code added for synchronous events which atomically switches the + right from being a thread-based right to a dm_tokdata_t-based right without + allowing the lock to drop in between. You will probably have to add a new + dm_fsys_vector entry point to do this. The lock can't be lost during the + switch, or other threads might change the inode or superblock in between. + Likewise, if you need to return to the filesystem holding a right, then + you need a DMAPI-to-thread atomic switch to occur, most likely in + dm_change_right(). Again, the lock must not be lost during the switch; the + DMAPI spec spends a couple of pages stressing this. Another dm_fsys_vector + entry point is probably the answer. + + There are several assumptions implied in the current layout of the code. + First of all, if an event returns to the filesystem with a return value of + zero, then the filesystem can assume that any locks (rights) held at the + start of the event are still in effect at the end of the event. (Note that + the application could have temporarily dropped and reaquired the right + while the event was outstanding, however). If the event returns to the + filesystem with an errno, then the filesystem must assume that it has lost + any and all rights associated with any of the objects in the event. This + was done for a couple of reasons. First of all, since an errno is being + returned, most likely the filesystem is going to immediately drop all the + locks anyway. If the DMAPI code was required to unconditionally reobtain + all locks before returning to the filesystem, then dm_pending() wouldn't + work for NFS server threads because the process would block indefinitely + trying to get its thread-based rights back, because the DMAPI-rights + associated with the dm_tokdata_t in the outstanding event would prevent + the rights from being obtained. That would be a bad thing. We wouldn't + be able to let users Cntl-C out of read/write/truncate events either. + + If a case should ever surface where the thread has lost its rights even + though it has a zero return status, or where the thread has rights even + though it is returning with an errno, then this logic will have to be + reworked. This could be done by changing the 'right' parameters on all + the event calls to (dm_right_t *), so that they could serve both as IN + and OUT parameters. + + Some events such as DM_EVENT_DESTROY arrive without holding a vnode + reference; if you don't have a vnode reference, you can't have a right + on the file. + + One more quirk. The DM_EVENT_UNMOUNT event is defined to be synchronous + when it's behavior is asynchronous. If an unmount event arrives with + rights, the event should return with the same rights and should NOT leave + any rights in the dm_tokdata_t where the application could use them. +*/ + + +#define GETNEXTOFF(vdat) ((vdat).vd_offset + (vdat).vd_length) +#ifdef __sgi +#define HANDLE_SIZE(tdp) \ + ((tdp)->td_type & DM_TDT_VFS ? FSHSIZE : HSIZE((tdp)->td_handle)) +#else +#define HANDLE_SIZE(tdp) \ + ((tdp)->td_type & DM_TDT_VFS ? FSHSIZE : XFS_HSIZE((tdp)->td_handle)) +#endif + + +/* Given a behavior descriptor pointer in a filesystem known to support DMAPI, + build a tdp structure for the corresponding vnode. +*/ + +static dm_tokdata_t * +dm_bhv_data( + bhv_desc_t *bdp, + dm_right_t right, + int referenced) /* != 0, caller holds vnode reference */ +{ + int error; + dm_tokdata_t *tdp; + vnode_t *vp = BHV_TO_VNODE(bdp); + + tdp = kmem_alloc(sizeof(*tdp), KM_SLEEP); + + tdp->td_next = NULL; + tdp->td_tevp = NULL; + tdp->td_app_ref = 0; + tdp->td_orig_right = right; + tdp->td_right = right; + tdp->td_flags = DM_TDF_ORIG; + if (referenced) { + tdp->td_flags |= DM_TDF_EVTREF; + } + + if (vp->v_type == VREG) { + tdp->td_type = DM_TDT_REG; + } else if (vp->v_type == VDIR) { + tdp->td_type = DM_TDT_DIR; + } else if (vp->v_type == VLNK) { + tdp->td_type = DM_TDT_LNK; + } else { + tdp->td_type = DM_TDT_OTH; + } + + if (referenced) { + tdp->td_bdp = bdp; + } else { + tdp->td_bdp = 0; + } + tdp->td_vcount = 0; + + if ((error = dm_vp_to_handle(vp, &tdp->td_handle)) != 0) { + panic("dm_bhv_data: dm_vp_to_handle failed for vp %p in " + "a DMAPI filesystem, errno %d\n", vp, error); + } + + return(tdp); +} + + +/* Given a vfs pointer to a filesystem known to support DMAPI, build a tdp + structure for that vfsp. +*/ +static dm_tokdata_t * +dm_vfs_data( + vfs_t *vfsp, + vnode_t *vp, /* will be NULL for DM_EVENT_UNMOUNT */ + dm_right_t right) +{ + dm_tokdata_t *tdp; + + tdp = kmem_alloc(sizeof(*tdp), KM_SLEEP); + + tdp->td_next = NULL; + tdp->td_tevp = NULL; + tdp->td_app_ref = 0; + tdp->td_orig_right = right; + tdp->td_right = right; + tdp->td_flags = DM_TDF_ORIG; + if (vp) { + tdp->td_flags |= DM_TDF_EVTREF; + } + tdp->td_type = DM_TDT_VFS; + if (vp) { + tdp->td_bdp = bhv_base_unlocked(VN_BHV_HEAD(vp)); + } else { + tdp->td_bdp = 0; + } + tdp->td_vcount = 0; + + bcopy(vfsp->vfs_altfsid, &tdp->td_handle.ha_fsid, sizeof(fsid_t)); + bzero((char *)&tdp->td_handle.ha_fsid + sizeof(fsid_t), + sizeof(tdp->td_handle) - sizeof(fsid_t)); + + return(tdp); +} + + +/* Link a tdp structure into the tevp. */ + +static void +dm_add_handle_to_event( + dm_tokevent_t *tevp, + dm_tokdata_t *tdp) +{ + tdp->td_next = tevp->te_tdp; + tevp->te_tdp = tdp; + tdp->td_tevp = tevp; +} + + +/* Generate the given data event for the vnode, and wait for a reply. The + caller must guarantee that the vnode's reference count is greater than zero + so that the filesystem can't disappear while the request is outstanding. +*/ + +int +dm_send_data_event( + dm_eventtype_t event, + bhv_desc_t *bdp, + dm_right_t vp_right, /* current right for vp */ + off_t offset, + size_t length, + int flags) /* 0 or DM_FLAGS_NDELAY */ +{ + dm_data_event_t *datap; + dm_tokevent_t *tevp; + dm_tokdata_t *tdp; + vnode_t *vp; + int error; + + vp = BHV_TO_VNODE(bdp); + tdp = dm_bhv_data(bdp, vp_right, /* reference held */ 1); + + /* Calculate the size of the event in bytes, create an event structure + for it, and insert the file's handle into the event. + */ + + tevp = dm_evt_create_tevp(event, HANDLE_SIZE(tdp), (void **)&datap); + dm_add_handle_to_event(tevp, tdp); + + /* Now fill in all the dm_data_event_t fields. */ + + datap->de_handle.vd_offset = sizeof(*datap); + datap->de_handle.vd_length = HANDLE_SIZE(tdp); + bcopy(&tdp->td_handle, (char *)datap + datap->de_handle.vd_offset, + datap->de_handle.vd_length); + datap->de_offset = offset; + datap->de_length = length; + + /* Queue the message and wait for the reply. */ + + error = dm_enqueue_normal_event(vp->v_vfsp, tevp, flags); + + /* If no errors occurred, we must leave with the same rights we had + upon entry. If errors occurred, we must leave with no rights. + */ + + dm_evt_rele_tevp(tevp, error); + + return(error); +} + + +/* Generate the destroy event for the vnode and wait until the request has been + queued. The caller does not hold a vnode reference or a right on the vnode, + but it must otherwise lock down the vnode such that the filesystem can't + disappear while the request is waiting to be queued. While waiting to be + queued, the vnode must not be referenceable either by path or by a call + to dm_handle_to_vp(). +*/ + +int +dm_send_destroy_event( + bhv_desc_t *bdp, + dm_right_t vp_right) /* always DM_RIGHT_NULL */ +{ + dm_fsys_vector_t *fsys_vector; + dm_tokevent_t *tevp; + dm_tokdata_t *tdp; + dm_destroy_event_t *destp; + dm_attrname_t attrname; + vnode_t *vp; + char *value; + int value_len; + int error; + + vp = BHV_TO_VNODE(bdp); + tdp = dm_bhv_data(bdp, vp_right, /* no reference held */ 0); + + if ((error = dm_waitfor_destroy_attrname(vp->v_vfsp, &attrname)) != 0) + return(error); + + /* If a return-on-destroy attribute name exists for this filesystem, + see if the object being deleted has this attribute. If the object + doesn't have the attribute or if we encounter an error, then send + the event without the attribute. + */ + + value_len = -1; /* because zero is a valid attribute length */ + if (attrname.an_chars[0] != '\0') { + fsys_vector = dm_fsys_vector(bdp); + (void)fsys_vector->get_destroy_dmattr(bdp, vp_right, &attrname, + &value, &value_len); + } + + /* Now that we know the size of the attribute value, if any, calculate + the size of the event in bytes, create an event structure for it, + and insert the handle into the event. + */ + + tevp = dm_evt_create_tevp(DM_EVENT_DESTROY, + HANDLE_SIZE(tdp) + (value_len >= 0 ? value_len : 0), + (void **)&destp); + dm_add_handle_to_event(tevp, tdp); + + /* Now fill in all the dm_destroy_event_t fields. */ + + destp->ds_handle.vd_offset = sizeof(*destp); + destp->ds_handle.vd_length = HANDLE_SIZE(tdp); + bcopy(&tdp->td_handle, (char *)destp + destp->ds_handle.vd_offset, + destp->ds_handle.vd_length); + if (value_len >= 0) { + destp->ds_attrname = attrname; + destp->ds_attrcopy.vd_length = value_len; + if (value_len == 0) { + destp->ds_attrcopy.vd_offset = 0; + } else { + destp->ds_attrcopy.vd_offset = GETNEXTOFF(destp->ds_handle); + bcopy(value, (char *)destp + destp->ds_attrcopy.vd_offset, + value_len); + kmem_free(value, value_len); + } + } + + /* Queue the message asynchronously. */ + + error = dm_enqueue_normal_event(vp->v_vfsp, tevp, 0); + + /* Since we had no rights upon entry, we have none to reobtain before + leaving. + */ + + dm_evt_rele_tevp(tevp, 1); + + return(error); +} + + +/* The dm_mount_event_t event is sent in turn to all sessions that have asked + for it until one either rejects it or accepts it. The filesystem is not + going anywhere because the mount is blocked until the event is answered. +*/ + +int +dm_send_mount_event( + vfs_t *vfsp, /* filesystem being mounted */ + dm_right_t vfsp_right, + bhv_desc_t *bdp, /* mounted on directory */ + dm_right_t vp_right, + bhv_desc_t *rootbdp, + dm_right_t rootvp_right, + char *name1, /* mount path */ + char *name2) /* filesystem device name */ +{ + int error; + dm_tokevent_t *tevp; + dm_tokdata_t *tdp1; /* filesystem handle for event */ + dm_tokdata_t *tdp2; /* file handle for mounted-on dir. */ + dm_tokdata_t *tdp3; /* file handle for root vnode */ + dm_mount_event_t *mp; + size_t nextoff; +#ifdef __sgi + vnode_t *vp = BHV_TO_VNODE(bdp); /* mounted on directory */ +#else + vnode_t *vp = NULL; /* mounted on directory */ +#endif + vnode_t *rootvp = BHV_TO_VNODE(rootbdp); + + /* Convert the vfsp to a filesystem handle, and vp and rootvp into + file handles. vp (the mounted-on directory) may not have a handle + if it is a different filesystem type such as EFS which does not + support DMAPI. + */ + + if(bdp) + vp = BHV_TO_VNODE(bdp); + + tdp1 = dm_vfs_data(vfsp, rootvp, vfsp_right); + + if ((vp == NULL) || dm_check_dmapi_vp(vp)) { + vp = NULL; /* assume we are mounting on non XFS */ + } else { + tdp2 = dm_bhv_data(bdp, vp_right, /* reference held */ 1); + } + + tdp3 = dm_bhv_data(rootbdp, rootvp_right, /* reference held */ 1); + + /* Calculate the size of the event in bytes, create an event structure + for it, and insert the handles into the event. + */ + + tevp = dm_evt_create_tevp(DM_EVENT_MOUNT, + HANDLE_SIZE(tdp1) + (vp ? HANDLE_SIZE(tdp2) : 0) + + HANDLE_SIZE(tdp3) + strlen(name1) + 1 + + strlen(name2) + 1, (void **)&mp); + + dm_add_handle_to_event(tevp, tdp1); + if (vp) + dm_add_handle_to_event(tevp, tdp2); + dm_add_handle_to_event(tevp, tdp3); + + /* Now fill in all the dm_mount_event_t fields. */ + + mp->me_handle1.vd_offset = sizeof(*mp); + mp->me_handle1.vd_length = HANDLE_SIZE(tdp1); + bcopy(&tdp1->td_handle, (char *) mp + mp->me_handle1.vd_offset, + mp->me_handle1.vd_length); + nextoff = GETNEXTOFF(mp->me_handle1); + + if (vp) { + mp->me_handle2.vd_offset = nextoff; + mp->me_handle2.vd_length = HANDLE_SIZE(tdp2); + bcopy(&tdp2->td_handle, (char *)mp + mp->me_handle2.vd_offset, + mp->me_handle2.vd_length); + nextoff = GETNEXTOFF(mp->me_handle2); + } + + mp->me_name1.vd_offset = nextoff; + mp->me_name1.vd_length = strlen(name1) + 1; + bcopy(name1, (char *)mp + mp->me_name1.vd_offset, mp->me_name1.vd_length); + nextoff = GETNEXTOFF(mp->me_name1); + + mp->me_name2.vd_offset = nextoff; + mp->me_name2.vd_length = strlen(name2) + 1; + bcopy(name2, (char *)mp + mp->me_name2.vd_offset, mp->me_name2.vd_length); + nextoff = GETNEXTOFF(mp->me_name2); + + mp->me_roothandle.vd_offset = nextoff; + mp->me_roothandle.vd_length = HANDLE_SIZE(tdp3); + bcopy(&tdp3->td_handle, (char *)mp + mp->me_roothandle.vd_offset, + mp->me_roothandle.vd_length); + + mp->me_mode = (vfsp->vfs_flag & VFS_RDONLY ? DM_MOUNT_RDONLY : 0); + + /* Queue the message and wait for the reply. */ + + error = dm_enqueue_mount_event(vfsp, tevp); + + /* If no errors occurred, we must leave with the same rights we had + upon entry. If errors occurred, we must leave with no rights. + */ + + dm_evt_rele_tevp(tevp, error); + + return(error); +} + + +/* Generate an DM_EVENT_UNMOUNT event and wait for a reply. The 'retcode' + field indicates whether this is a successful or unsuccessful unmount. + If successful, the filesystem is already unmounted, and any pending handle + reference to the filesystem will be failed. If the unmount was + unsuccessful, then the filesystem will be placed back into full service. + + The DM_EVENT_UNMOUNT event should really be asynchronous, because the + application has no control over whether or not the unmount succeeds. (The + DMAPI spec defined it that way because asynchronous events aren't always + guaranteed to be delivered.) + + Since the filesystem is already unmounted in the successful case, the + DM_EVENT_UNMOUNT event can't make available any vnode to be used in + subsequent sid/hanp/hlen/token calls by the application. The event will + hang around until the application does a DM_RESP_CONTINUE, but the handle + within the event is unusable by the application. +*/ + +void +dm_send_unmount_event( + vfs_t *vfsp, + vnode_t *vp, /* NULL if unmount successful */ + dm_right_t vfsp_right, + mode_t mode, + int retcode, /* errno, if unmount failed */ + int flags) +{ + dm_namesp_event_t *np; + dm_tokevent_t *tevp; + dm_tokdata_t *tdp1; + + tdp1 = dm_vfs_data(vfsp, vp, vfsp_right); + + /* If the unmount failed, put the filesystem back into full service, + allowing blocked handle references to finish. If it succeeded, put + the filesystem into the DM_STATE_UNMOUNTED state and fail all + blocked DM_NO_TOKEN handle accesses. + */ + + if (retcode != 0) { /* unmount was unsuccessful */ + dm_change_fsys_entry(vfsp, DM_STATE_MOUNTED); + } else { + dm_change_fsys_entry(vfsp, DM_STATE_UNMOUNTED); + } + + /* If the event wasn't in the filesystem dm_eventset_t, just remove + the filesystem from the list of DMAPI filesystems and return. + */ + + if (flags & DM_FLAGS_UNWANTED) { + if (retcode == 0) + dm_remove_fsys_entry(vfsp); + return; + } + + /* Calculate the size of the event in bytes and allocate zeroed memory + for it. + */ + + tevp = dm_evt_create_tevp(DM_EVENT_UNMOUNT, HANDLE_SIZE(tdp1), + (void **)&np); + + dm_add_handle_to_event(tevp, tdp1); + + /* Now copy in all the dm_namesp_event_t specific fields. */ + + np->ne_handle1.vd_offset = sizeof(*np); + np->ne_handle1.vd_length = HANDLE_SIZE(tdp1); + bcopy(&tdp1->td_handle, (char *) np + np->ne_handle1.vd_offset, + np->ne_handle1.vd_length); + np->ne_mode = mode; + np->ne_retcode = retcode; + + /* Since DM_EVENT_UNMOUNT is effectively asynchronous, queue the + message and ignore any error return for DM_EVENT_UNMOUNT. + */ + + (void)dm_enqueue_normal_event(vfsp, tevp, flags); + + if (retcode == 0) + dm_remove_fsys_entry(vfsp); + + dm_evt_rele_tevp(tevp, 0); +} + + +/* Generate the given namespace event and wait for a reply (if synchronous) or + until the event has been queued (asynchronous). The caller must guarantee + that at least one vnode within the filesystem has had its reference count + bumped so that the filesystem can't disappear while the event is + outstanding. +*/ + +int +dm_send_namesp_event( + dm_eventtype_t event, + bhv_desc_t *bdp1, + dm_right_t vp1_right, + bhv_desc_t *bdp2, + dm_right_t vp2_right, + char *name1, + char *name2, + mode_t mode, + int retcode, + int flags) +{ + dm_namesp_event_t *np; + dm_tokevent_t *tevp; + dm_tokdata_t *tdp1; /* primary handle for event */ + dm_tokdata_t *tdp2; /* additional handle for event */ + vfs_t *sidvfsp; /* vfs event must be registered on */ + size_t nextoff; + int error; + vnode_t *vp1; + + vp1 = BHV_TO_VNODE(bdp1); + sidvfsp = vp1->v_vfsp; + + switch (event) { + case DM_EVENT_PREUNMOUNT: + /* + * PREUNMOUNT - Send the file system handle in handle1, + * and the handle for the root dir in the second. Otherwise + * it's a normal sync message; i.e. succeeds or fails + * depending on the app's return code. + * bdp1 and bdp2 are both the root dir of mounted FS + * vp1_right is the filesystem right. + * vp2_right is the root inode right. + */ + + tdp1 = dm_vfs_data(sidvfsp, vp1, vp1_right); + tdp2 = dm_bhv_data(bdp2, vp2_right, /* reference held */ 1); + + if (flags & DM_FLAGS_UNWANTED) { + dm_change_fsys_entry(sidvfsp, DM_STATE_UNMOUNTING); + return(0); + } + break; + + case DM_EVENT_NOSPACE: + /* vp1_right is the filesystem right. */ + + tdp1 = dm_vfs_data(sidvfsp, vp1, vp1_right); + tdp2 = dm_bhv_data(bdp2, vp2_right, /* reference held */ 1); /* additional info - not in the spec */ + break; + + default: + /* All other events only pass in vnodes and don't require any + special cases. + */ + + tdp1 = dm_bhv_data(bdp1, vp1_right, /* reference held */ 1); + if (bdp2) + tdp2 = dm_bhv_data(bdp2, vp2_right, /* reference held */ 1); + } + + /* Calculate the size of the event in bytes and allocate zeroed memory + for it. + */ + + tevp = dm_evt_create_tevp(event, + HANDLE_SIZE(tdp1) + (bdp2 ? HANDLE_SIZE(tdp2) : 0) + + (name1 ? strlen(name1) + 1 : 0) + + (name2 ? strlen(name2) + 1 : 0), (void **)&np); + + dm_add_handle_to_event(tevp, tdp1); + if (bdp2) + dm_add_handle_to_event(tevp, tdp2); + + /* Now copy in all the dm_namesp_event_t specific fields. */ + + np->ne_handle1.vd_offset = sizeof(*np); + np->ne_handle1.vd_length = HANDLE_SIZE(tdp1); + bcopy(&tdp1->td_handle, (char *) np + np->ne_handle1.vd_offset, + np->ne_handle1.vd_length); + nextoff = GETNEXTOFF(np->ne_handle1); + if (bdp2) { + np->ne_handle2.vd_offset = nextoff; + np->ne_handle2.vd_length = HANDLE_SIZE(tdp2); + bcopy(&tdp2->td_handle, (char *)np + np->ne_handle2.vd_offset, + np->ne_handle2.vd_length); + nextoff = GETNEXTOFF(np->ne_handle2); + } + if (name1) { + np->ne_name1.vd_offset = nextoff; + np->ne_name1.vd_length = strlen(name1) + 1; + bcopy(name1, (char *)np + np->ne_name1.vd_offset, + np->ne_name1.vd_length); + nextoff = GETNEXTOFF(np->ne_name1); + } + if (name2) { + np->ne_name2.vd_offset = nextoff; + np->ne_name2.vd_length = strlen(name2) + 1; + bcopy(name2, (char *)np + np->ne_name2.vd_offset, + np->ne_name2.vd_length); + } + np->ne_mode = mode; + np->ne_retcode = retcode; + + /* Queue the message and wait for the reply. */ + + error = dm_enqueue_normal_event(sidvfsp, tevp, flags); + + /* If no errors occurred, we must leave with the same rights we had + upon entry. If errors occurred, we must leave with no rights. + */ + + dm_evt_rele_tevp(tevp, error); + + if (!error && event == DM_EVENT_PREUNMOUNT) { + dm_change_fsys_entry(sidvfsp, DM_STATE_UNMOUNTING); + } + + return(error); +} + + +/* + * Send a message of type "DM_EVENT_USER". Since no vnode is involved, we + * don't have to worry about rights here. + */ + +int +dm_send_msg( + dm_sessid_t targetsid, + dm_msgtype_t msgtype, /* SYNC or ASYNC */ + size_t buflen, + void *bufp) +{ + dm_tokevent_t *tevp; + int sync; + void *msgp; + int error; + + if (buflen > DM_MAX_MSG_DATA) + return(E2BIG); + if (msgtype == DM_MSGTYPE_ASYNC) { + sync = 0; + } else if (msgtype == DM_MSGTYPE_SYNC) { + sync = 1; + } else { + return(EINVAL); + } + + tevp = dm_evt_create_tevp(DM_EVENT_USER, buflen, (void **)&msgp); + +#ifdef __sgi + if (buflen && copyin(bufp, msgp, buflen)) { +#else + if (buflen && copy_from_user(msgp, bufp, buflen)) { +#endif + dm_evt_rele_tevp(tevp, 0); + return(EFAULT); + } + + /* Enqueue the request and wait for the reply. */ + + error = dm_enqueue_sendmsg_event(targetsid, tevp, sync); + + /* Destroy the tevp and return the reply. (dm_pending is not + supported here.) + */ + + dm_evt_rele_tevp(tevp, error); + + return(error); +} + + +/* + * Send a message of type "DM_EVENT_USER". Since no vnode is involved, we + * don't have to worry about rights here. + */ + +int +dm_create_userevent( + dm_sessid_t sid, + size_t msglen, + void *msgdatap, + dm_token_t *tokenp) /* return token created */ +{ + dm_tokevent_t *tevp; + dm_token_t token; + int error; + void *msgp; + + if (msglen > DM_MAX_MSG_DATA) + return(E2BIG); + + tevp = dm_evt_create_tevp(DM_EVENT_USER, msglen, (void **)&msgp); + +#ifdef __sgi + if (msglen && copyin(msgdatap, msgp, msglen)) { +#else + if (msglen && copy_from_user(msgp, msgdatap, msglen)) { +#endif + dm_evt_rele_tevp(tevp, 0); + return(EFAULT); + } + + /* Queue the message. If that didn't work, free the tevp structure. */ + + if ((error = dm_enqueue_user_event(sid, tevp, &token)) != 0) + dm_evt_rele_tevp(tevp, 0); + +#ifdef __sgi + if (!error && copyout(&token, tokenp, sizeof(token))) + error = EFAULT; +#else + if (!error && copy_to_user(tokenp, &token, sizeof(token))) + error = EFAULT; +#endif + + return(error); +} diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/dmapi_handle.c linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_handle.c --- linux-2.4.7/linux/fs/xfs/dmapi/dmapi_handle.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_handle.c Mon Oct 2 10:19:34 2000 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +int +dm_create_by_handle( + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, dirhanp, dirhlen, token, DM_TDT_DIR, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->create_by_handle(tdp->td_bdp, tdp->td_right, + hanp, hlen, cname); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_mkdir_by_handle( + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, dirhanp, dirhlen, token, DM_TDT_DIR, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->mkdir_by_handle(tdp->td_bdp, tdp->td_right, + hanp, hlen, cname); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_symlink_by_handle( + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname, + char *path) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, dirhanp, dirhlen, token, DM_TDT_DIR, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->symlink_by_handle(tdp->td_bdp, tdp->td_right, + hanp, hlen, cname, path); + + dm_app_put_tdp(tdp); + return(error); +} diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/dmapi_hole.c linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_hole.c --- linux-2.4.7/linux/fs/xfs/dmapi/dmapi_hole.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_hole.c Mon Oct 2 10:19:34 2000 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +int +dm_get_allocinfo_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t *offp, + u_int nelem, + dm_extent_t *extentp, + u_int *nelemp, + int *rvp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->get_allocinfo_rvp(tdp->td_bdp, tdp->td_right, + offp, nelem, extentp, nelemp, rvp); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_probe_hole( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + dm_off_t *roffp, + dm_size_t *rlenp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->probe_hole(tdp->td_bdp, tdp->td_right, + off, len, roffp, rlenp); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_punch_hole( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->punch_hole(tdp->td_bdp, tdp->td_right, off, len); + + dm_app_put_tdp(tdp); + return(error); +} diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/dmapi_io.c linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_io.c --- linux-2.4.7/linux/fs/xfs/dmapi/dmapi_io.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_io.c Mon Oct 2 10:19:34 2000 @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +int +dm_read_invis_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->read_invis_rvp(tdp->td_bdp, tdp->td_right, + off, len, bufp, rvp); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_write_invis_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int flags, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->write_invis_rvp(tdp->td_bdp, tdp->td_right, + flags, off, len, bufp, rvp); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_sync_by_handle ( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->sync_by_handle(tdp->td_bdp, tdp->td_right); + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_get_dioinfo ( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_dioinfo_t *diop) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->get_dioinfo(tdp->td_bdp, tdp->td_right, diop); + + dm_app_put_tdp(tdp); + return(error); +} diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/dmapi_mountinfo.c linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_mountinfo.c --- linux-2.4.7/linux/fs/xfs/dmapi/dmapi_mountinfo.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_mountinfo.c Fri Oct 20 01:02:14 2000 @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifdef __sgi +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "dmapi_private.h" + +#ifdef linux +#define vfsmax 1 +#endif + +typedef struct { + int support_type; + char name[16]; + dm_fsys_vector_t *vptr; +} dm_vector_map_t; + +/* Values for the support_type field. */ + +#define DM_SUPPORT_UNKNOWN 0 +#define DM_SUPPORT_AVAIL 1 + + +dm_vector_map_t *dm_fsys_map = NULL; + + +int +dm_code_level(void) +{ + return(DM_CLVL_XOPEN); /* initial X/Open compliant release */ +} + + +/* Dummy routine which is stored in each function vector slot for which the + filesystem provides no function of its own. If an application calls the + function, he will just get ENOSYS. +*/ + +static int +dm_enosys(void) +{ + return(ENOSYS); /* function not supported by filesystem */ +} + + +/* dm_query_fsys_for_vector() asks a filesystem for its list of supported + DMAPI functions, and builds a dm_vector_map_t structure based upon the + reply. We ignore functions supported by the filesystem which we do not + know about, and we substitute the subroutine 'dm_enosys' for each function + we know about but the filesystem does not support. +*/ + +static void +dm_query_fsys_for_vector( + bhv_desc_t *bdp) +{ + dm_vector_map_t *map; + fsys_function_vector_t *vecp; + dm_fsys_vector_t *vptr; + dm_fcntl_t dmfcntl; + vnode_t *vp = BHV_TO_VNODE(bdp); + struct vfs *vfsp = vp->v_vfsp; + int fstype; + int error; + int i; + + fstype = vfsp->vfs_fstype; + map = &dm_fsys_map[fstype]; + + /* Clear out any information left from a previous filesystem that was + in this slot and initialize it for the new filesystem. + */ + + if (map->vptr) { + kmem_free(map->vptr, sizeof(*map->vptr)); + map->vptr = NULL; + } +#ifdef __sgi + strcpy(map->name, vfssw[fstype].vsw_name); +#else + /* XXX */ + strcpy(map->name, XFS_NAME); +#endif + map->support_type = DM_SUPPORT_AVAIL; + + /* Next allocate a function vector and initialize all fields with a + dummy function that returns ENOSYS. + */ + + vptr = map->vptr = kmem_alloc(sizeof(*map->vptr), KM_SLEEP); + + strncpy(vptr->fsys_name, map->name, sizeof(vptr->fsys_name)); + vptr->code_level = 0; + vptr->clear_inherit = (dm_fsys_clear_inherit_t)dm_enosys; + vptr->create_by_handle = (dm_fsys_create_by_handle_t)dm_enosys; + vptr->downgrade_right = (dm_fsys_downgrade_right_t)dm_enosys; + vptr->get_allocinfo_rvp = (dm_fsys_get_allocinfo_rvp_t)dm_enosys; + vptr->get_bulkall_rvp = (dm_fsys_get_bulkall_rvp_t)dm_enosys; + vptr->get_bulkattr_rvp = (dm_fsys_get_bulkattr_rvp_t)dm_enosys; + vptr->get_config = (dm_fsys_get_config_t)dm_enosys; + vptr->get_config_events = (dm_fsys_get_config_events_t)dm_enosys; + vptr->get_destroy_dmattr = (dm_fsys_get_destroy_dmattr_t)dm_enosys; + vptr->get_dioinfo = (dm_fsys_get_dioinfo_t)dm_enosys; + vptr->get_dirattrs_rvp = (dm_fsys_get_dirattrs_rvp_t)dm_enosys; + vptr->get_dmattr = (dm_fsys_get_dmattr_t)dm_enosys; + vptr->get_eventlist = (dm_fsys_get_eventlist_t)dm_enosys; + vptr->get_fileattr = (dm_fsys_get_fileattr_t)dm_enosys; + vptr->get_region = (dm_fsys_get_region_t)dm_enosys; + vptr->getall_dmattr = (dm_fsys_getall_dmattr_t)dm_enosys; + vptr->getall_inherit = (dm_fsys_getall_inherit_t)dm_enosys; + vptr->init_attrloc = (dm_fsys_init_attrloc_t)dm_enosys; + vptr->mkdir_by_handle = (dm_fsys_mkdir_by_handle_t)dm_enosys; + vptr->probe_hole = (dm_fsys_probe_hole_t)dm_enosys; + vptr->punch_hole = (dm_fsys_punch_hole_t)dm_enosys; + vptr->read_invis_rvp = (dm_fsys_read_invis_rvp_t)dm_enosys; + vptr->release_right = (dm_fsys_release_right_t)dm_enosys; + vptr->request_right = (dm_fsys_request_right_t)dm_enosys; + vptr->remove_dmattr = (dm_fsys_remove_dmattr_t)dm_enosys; + vptr->set_dmattr = (dm_fsys_set_dmattr_t)dm_enosys; + vptr->set_eventlist = (dm_fsys_set_eventlist_t)dm_enosys; + vptr->set_fileattr = (dm_fsys_set_fileattr_t)dm_enosys; + vptr->set_inherit = (dm_fsys_set_inherit_t)dm_enosys; + vptr->set_region = (dm_fsys_set_region_t)dm_enosys; + vptr->symlink_by_handle = (dm_fsys_symlink_by_handle_t)dm_enosys; + vptr->sync_by_handle = (dm_fsys_sync_by_handle_t)dm_enosys; + vptr->upgrade_right = (dm_fsys_upgrade_right_t)dm_enosys; + vptr->write_invis_rvp = (dm_fsys_write_invis_rvp_t)dm_enosys; + + /* Issue a F_DMAPI fcntl() to the filesystem in order to obtain its + vector of filesystem-specific DMAPI routines. + */ + + dmfcntl.dmfc_subfunc = DM_FCNTL_FSYSVECTOR; + dmfcntl.u_fcntl.vecrq.count = 0; + dmfcntl.u_fcntl.vecrq.vecp = NULL; + +#ifdef __sgi + VOP_FCNTL(vp, F_DMAPI, &dmfcntl, 0, 0, DM_GET_CRED, NULL, error); +#else + error = xfs_dm_fcntl(bdp, &dmfcntl, 0, 0, DM_GET_CRED, NULL); +#endif + + /* If we still have an error at this point, then the filesystem simply + does not support DMAPI, so we give up with all functions set to + ENOSYS. + */ + + if (error || dmfcntl.u_fcntl.vecrq.count == 0) + return; + + /* The request succeeded and we were given a vector which we need to + map to our current level. Overlay the dummy function with every + filesystem function we understand. + */ + + vptr->code_level = dmfcntl.u_fcntl.vecrq.code_level; + vecp = dmfcntl.u_fcntl.vecrq.vecp; + for (i = 0; i < dmfcntl.u_fcntl.vecrq.count; i++) { + switch (vecp[i].func_no) { + case DM_FSYS_CLEAR_INHERIT: + vptr->clear_inherit = vecp[i].u_fc.clear_inherit; + break; + case DM_FSYS_CREATE_BY_HANDLE: + vptr->create_by_handle = vecp[i].u_fc.create_by_handle; + break; + case DM_FSYS_DOWNGRADE_RIGHT: + vptr->downgrade_right = vecp[i].u_fc.downgrade_right; + break; + case DM_FSYS_GET_ALLOCINFO_RVP: + vptr->get_allocinfo_rvp = vecp[i].u_fc.get_allocinfo_rvp; + break; + case DM_FSYS_GET_BULKALL_RVP: + vptr->get_bulkall_rvp = vecp[i].u_fc.get_bulkall_rvp; + break; + case DM_FSYS_GET_BULKATTR_RVP: + vptr->get_bulkattr_rvp = vecp[i].u_fc.get_bulkattr_rvp; + break; + case DM_FSYS_GET_CONFIG: + vptr->get_config = vecp[i].u_fc.get_config; + break; + case DM_FSYS_GET_CONFIG_EVENTS: + vptr->get_config_events = vecp[i].u_fc.get_config_events; + break; + case DM_FSYS_GET_DESTROY_DMATTR: + vptr->get_destroy_dmattr = vecp[i].u_fc.get_destroy_dmattr; + break; + case DM_FSYS_GET_DIOINFO: + vptr->get_dioinfo = vecp[i].u_fc.get_dioinfo; + break; + case DM_FSYS_GET_DIRATTRS_RVP: + vptr->get_dirattrs_rvp = vecp[i].u_fc.get_dirattrs_rvp; + break; + case DM_FSYS_GET_DMATTR: + vptr->get_dmattr = vecp[i].u_fc.get_dmattr; + break; + case DM_FSYS_GET_EVENTLIST: + vptr->get_eventlist = vecp[i].u_fc.get_eventlist; + break; + case DM_FSYS_GET_FILEATTR: + vptr->get_fileattr = vecp[i].u_fc.get_fileattr; + break; + case DM_FSYS_GET_REGION: + vptr->get_region = vecp[i].u_fc.get_region; + break; + case DM_FSYS_GETALL_DMATTR: + vptr->getall_dmattr = vecp[i].u_fc.getall_dmattr; + break; + case DM_FSYS_GETALL_INHERIT: + vptr->getall_inherit = vecp[i].u_fc.getall_inherit; + break; + case DM_FSYS_INIT_ATTRLOC: + vptr->init_attrloc = vecp[i].u_fc.init_attrloc; + break; + case DM_FSYS_MKDIR_BY_HANDLE: + vptr->mkdir_by_handle = vecp[i].u_fc.mkdir_by_handle; + break; + case DM_FSYS_PROBE_HOLE: + vptr->probe_hole = vecp[i].u_fc.probe_hole; + break; + case DM_FSYS_PUNCH_HOLE: + vptr->punch_hole = vecp[i].u_fc.punch_hole; + break; + case DM_FSYS_READ_INVIS_RVP: + vptr->read_invis_rvp = vecp[i].u_fc.read_invis_rvp; + break; + case DM_FSYS_RELEASE_RIGHT: + vptr->release_right = vecp[i].u_fc.release_right; + break; + case DM_FSYS_REMOVE_DMATTR: + vptr->remove_dmattr = vecp[i].u_fc.remove_dmattr; + break; + case DM_FSYS_REQUEST_RIGHT: + vptr->request_right = vecp[i].u_fc.request_right; + break; + case DM_FSYS_SET_DMATTR: + vptr->set_dmattr = vecp[i].u_fc.set_dmattr; + break; + case DM_FSYS_SET_EVENTLIST: + vptr->set_eventlist = vecp[i].u_fc.set_eventlist; + break; + case DM_FSYS_SET_FILEATTR: + vptr->set_fileattr = vecp[i].u_fc.set_fileattr; + break; + case DM_FSYS_SET_INHERIT: + vptr->set_inherit = vecp[i].u_fc.set_inherit; + break; + case DM_FSYS_SET_REGION: + vptr->set_region = vecp[i].u_fc.set_region; + break; + case DM_FSYS_SYMLINK_BY_HANDLE: + vptr->symlink_by_handle = vecp[i].u_fc.symlink_by_handle; + break; + case DM_FSYS_SYNC_BY_HANDLE: + vptr->sync_by_handle = vecp[i].u_fc.sync_by_handle; + break; + case DM_FSYS_UPGRADE_RIGHT: + vptr->upgrade_right = vecp[i].u_fc.upgrade_right; + break; + case DM_FSYS_WRITE_INVIS_RVP: + vptr->write_invis_rvp = vecp[i].u_fc.write_invis_rvp; + break; + default: /* ignore ones we don't understand */ + break; + } + } +} + + +/* Given a behavior pointer, dm_fsys_vector() returns a pointer to the DMAPI + function vector to be used for the corresponding vnode. There is one possible + function vector for each filesystem type, although currently XFS is the + only filesystem that actually supports DMAPI. +*/ + +dm_fsys_vector_t * +dm_fsys_vector( + bhv_desc_t *bdp) +{ + dm_vector_map_t *map; + struct vfs *vfsp = BHV_TO_VNODE(bdp)->v_vfsp; + int fstype = vfsp->vfs_fstype;; + + /* If this is the first call, initialize the filesystem function + vector map. + */ + + if (dm_fsys_map == NULL) { + int size = vfsmax * sizeof(*dm_fsys_map); + int i; + + dm_fsys_map = (dm_vector_map_t *)kmem_zalloc(size, KM_SLEEP); + for (i = 0; i < vfsmax; i++) { + dm_fsys_map[i].support_type = DM_SUPPORT_UNKNOWN; + } + } + map = &dm_fsys_map[fstype]; + + /* If a new filesystem has been dynamically loaded into a slot + previously held by another filesystem, then treat it as a + DM_SUPPORT_UNKNOWN. + */ + +#ifdef __sgi + if (strcmp(map->name, vfssw[fstype].vsw_name)) + map->support_type = DM_SUPPORT_UNKNOWN; +#else + /* XXX */ + if (strcmp(map->name, XFS_NAME)) + map->support_type = DM_SUPPORT_UNKNOWN; +#endif + + /* If we don't yet know what the filesystem supports, ask it. */ + + if (map->support_type == DM_SUPPORT_UNKNOWN) + dm_query_fsys_for_vector(bdp); + + /* Now return the function vector. */ + + return(map->vptr); +} diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/dmapi_private.h linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_private.h --- linux-2.4.7/linux/fs/xfs/dmapi/dmapi_private.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_private.h Wed Oct 11 10:45:35 2000 @@ -0,0 +1,606 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef _DMAPI_PRIVATE_H +#define _DMAPI_PRIVATE_H + +#ifdef __sgi + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* define fsid_t for handle_t */ +#include +#include /* define handle_t */ + +#include +#else + +#include + +#endif + +#if defined(DMAPI_ON_KUDZU) || defined(linux) + +#define DM_GET_CRED (get_current_cred()) +#define DM_GET_ABI (get_current_abi()) + +#else + +#define DM_GET_CRED (curprocp->p_cred) +#define DM_GET_ABI (curprocp->p_abi) + +#endif + + +typedef struct dm_tokdata { + struct dm_tokdata *td_next; + struct dm_tokevent *td_tevp; /* pointer to owning tevp */ + int td_app_ref; /* # app threads currently active */ + dm_right_t td_orig_right; /* original right held when created */ + dm_right_t td_right; /* current right held for this handle */ + short td_flags; + short td_type; /* object type */ + int td_vcount; /* # of current application VN_HOLDs */ + bhv_desc_t *td_bdp; /* behavior descriptor */ + xfs_handle_t td_handle; /* handle for vp or vfsp */ +} dm_tokdata_t; + +/* values for td_type */ + +#define DM_TDT_NONE 0x00 /* td_handle is empty */ +#define DM_TDT_VFS 0x01 /* td_handle points to a vfs */ +#define DM_TDT_REG 0x02 /* td_handle points to a file */ +#define DM_TDT_DIR 0x04 /* td_handle points to a directory */ +#define DM_TDT_LNK 0x08 /* td_handle points to a symlink */ +#define DM_TDT_OTH 0x10 /* some other object eg. pipe, socket */ + +#define DM_TDT_VNO (DM_TDT_REG|DM_TDT_DIR|DM_TDT_LNK|DM_TDT_OTH) +#define DM_TDT_ANY (DM_TDT_VFS|DM_TDT_REG|DM_TDT_DIR|DM_TDT_LNK|DM_TDT_OTH) + +/* values for td_flags */ + +#define DM_TDF_ORIG 0x0001 /* part of the original event */ +#define DM_TDF_EVTREF 0x0002 /* event thread holds vnode reference */ +#define DM_TDF_STHREAD 0x0004 /* only one app can use this handle */ +#define DM_TDF_RIGHT 0x0008 /* vcount bumped for dm_request_right */ +#define DM_TDF_HOLD 0x0010 /* vcount bumped for dm_obj_ref_hold */ + + +/* Because some events contain __u64 fields, we force te_msg and te_event + to always be 8-byte aligned. In order to send more than one message in + a single dm_get_events() call, we also ensure that each message is an + 8-byte multiple. +*/ + +typedef struct dm_tokevent { + struct dm_tokevent *te_next; + struct dm_tokevent *te_hashnext; /* hash chain */ + lock_t te_lock; /* lock for all fields but te_*next. + * te_next and te_hashnext are + * protected by the session lock. + */ + short te_flags; + short te_allocsize; /* alloc'ed size of this structure */ + sv_t te_evt_queue; /* queue waiting for dm_respond_event */ + sv_t te_app_queue; /* queue waiting for handle access */ + int te_evt_ref; /* number of event procs using token */ + int te_app_ref; /* number of app procs using token */ + int te_app_slp; /* number of app procs sleeping */ + int te_reply; /* return errno for sync messages */ + dm_tokdata_t *te_tdp; /* list of handle/right pairs */ + union { + __u64 align; /* force alignment of te_msg */ + dm_eventmsg_t te_msg; /* user visible part */ + } te_u; + __u64 te_event; /* start of dm_xxx_event_t message */ +} dm_tokevent_t; + +#define te_msg te_u.te_msg + +/* values for te_flags */ + +#define DM_TEF_LOCKED 0x0001 /* event "locked" by dm_get_events() */ +#define DM_TEF_INTERMED 0x0002 /* a dm_pending reply was received */ +#define DM_TEF_FINAL 0x0004 /* dm_respond_event has been received */ +#ifdef __sgi +#define DM_TEF_HASHED 0x0010 /* event is on hash chain */ +#endif + + +#ifdef __sgi +#ifdef DEBUG +#define DM_SHASH_DEBUG +#endif + +typedef struct dm_sesshash { + dm_tokevent_t *h_next; /* ptr to chain of tokevents */ +#ifdef DM_SHASH_DEBUG + int maxlength; + int curlength; + int num_adds; + int num_dels; + int dup_hits; +#endif +} dm_sesshash_t; +#endif + + +typedef struct dm_eventq { + dm_tokevent_t *eq_head; + dm_tokevent_t *eq_tail; + int eq_count; /* size of queue */ +} dm_eventq_t; + + +typedef struct dm_session { + struct dm_session *sn_next; /* sessions linkage */ + dm_sessid_t sn_sessid; /* user-visible session number */ + u_int sn_flags; + lock_t sn_qlock; /* lock for newq/delq related fields */ + sv_t sn_readerq; /* waiting for message on sn_newq */ + sv_t sn_writerq; /* waiting for room on sn_newq */ + u_int sn_readercnt; /* count of waiting readers */ + u_int sn_writercnt; /* count of waiting readers */ + dm_eventq_t sn_newq; /* undelivered event queue */ + dm_eventq_t sn_delq; /* delivered event queue */ +#ifdef __sgi + dm_sesshash_t *sn_sesshash; /* buckets for tokevent hash chains */ +#ifdef DM_SHASH_DEBUG + int sn_buckets_in_use; + int sn_max_buckets_in_use; +#endif +#endif + char sn_info[DM_SESSION_INFO_LEN]; /* user-supplied info */ +} dm_session_t; + +/* values for sn_flags */ + +#define DM_SN_WANTMOUNT 0x0001 /* session wants to get mount events */ + + +typedef enum { + DM_STATE_MOUNTING, + DM_STATE_MOUNTED, + DM_STATE_UNMOUNTING, + DM_STATE_UNMOUNTED +} dm_fsstate_t; + + +typedef struct dm_fsreg { + struct dm_fsreg *fr_next; + vfs_t *fr_vfsp; /* filesystem pointer */ + dm_tokevent_t *fr_tevp; + fsid_t fr_fsid; /* filesystem ID */ + void *fr_msg; /* dm_mount_event_t for filesystem */ + int fr_msgsize; /* size of dm_mount_event_t */ + dm_fsstate_t fr_state; + sv_t fr_dispq; + int fr_dispcnt; + sv_t fr_queue; /* queue for hdlcnt/vfscnt/unmount */ + lock_t fr_lock; + int fr_hdlcnt; /* threads blocked during unmount */ + int fr_vfscnt; /* threads in VFS_VGET or VFS_ROOT */ + int fr_unmount; /* if non-zero, umount is sleeping */ + dm_attrname_t fr_rattr; /* dm_set_return_on_destroy attribute */ + dm_session_t *fr_sessp [DM_EVENT_MAX]; +} dm_fsreg_t; + + + + +/* events valid in dm_set_disp() when called with a filesystem handle. */ + +#define DM_VALID_DISP_EVENTS ( \ + (1 << DM_EVENT_PREUNMOUNT) | \ + (1 << DM_EVENT_UNMOUNT) | \ + (1 << DM_EVENT_NOSPACE) | \ + (1 << DM_EVENT_DEBUT) | \ + (1 << DM_EVENT_CREATE) | \ + (1 << DM_EVENT_POSTCREATE) | \ + (1 << DM_EVENT_REMOVE) | \ + (1 << DM_EVENT_POSTREMOVE) | \ + (1 << DM_EVENT_RENAME) | \ + (1 << DM_EVENT_POSTRENAME) | \ + (1 << DM_EVENT_LINK) | \ + (1 << DM_EVENT_POSTLINK) | \ + (1 << DM_EVENT_SYMLINK) | \ + (1 << DM_EVENT_POSTSYMLINK) | \ + (1 << DM_EVENT_READ) | \ + (1 << DM_EVENT_WRITE) | \ + (1 << DM_EVENT_TRUNCATE) | \ + (1 << DM_EVENT_ATTRIBUTE) | \ + (1 << DM_EVENT_DESTROY) ) + + +/* isolate the read/write/trunc events of a dm_tokevent_t */ + +#define DM_EVENT_RDWRTRUNC(tevp) ( \ + ((tevp)->te_msg.ev_type == DM_EVENT_READ) || \ + ((tevp)->te_msg.ev_type == DM_EVENT_WRITE) || \ + ((tevp)->te_msg.ev_type == DM_EVENT_TRUNCATE) ) + + +/* + * Global handle hack isolation. + */ + +#define DM_GLOBALHAN(hanp, hlen) (((hanp) == DM_GLOBAL_HANP) && \ + ((hlen) == DM_GLOBAL_HLEN)) + + +#define DM_MAX_MSG_DATA 3960 + + + +/* Supported filesystem function vector functions. */ + + +typedef struct { + int code_level; + char fsys_name[16]; + dm_fsys_clear_inherit_t clear_inherit; + dm_fsys_create_by_handle_t create_by_handle; + dm_fsys_downgrade_right_t downgrade_right; + dm_fsys_get_allocinfo_rvp_t get_allocinfo_rvp; + dm_fsys_get_bulkall_rvp_t get_bulkall_rvp; + dm_fsys_get_bulkattr_rvp_t get_bulkattr_rvp; + dm_fsys_get_config_t get_config; + dm_fsys_get_config_events_t get_config_events; + dm_fsys_get_destroy_dmattr_t get_destroy_dmattr; + dm_fsys_get_dioinfo_t get_dioinfo; + dm_fsys_get_dirattrs_rvp_t get_dirattrs_rvp; + dm_fsys_get_dmattr_t get_dmattr; + dm_fsys_get_eventlist_t get_eventlist; + dm_fsys_get_fileattr_t get_fileattr; + dm_fsys_get_region_t get_region; + dm_fsys_getall_dmattr_t getall_dmattr; + dm_fsys_getall_inherit_t getall_inherit; + dm_fsys_init_attrloc_t init_attrloc; + dm_fsys_mkdir_by_handle_t mkdir_by_handle; + dm_fsys_probe_hole_t probe_hole; + dm_fsys_punch_hole_t punch_hole; + dm_fsys_read_invis_rvp_t read_invis_rvp; + dm_fsys_release_right_t release_right; + dm_fsys_remove_dmattr_t remove_dmattr; + dm_fsys_request_right_t request_right; + dm_fsys_set_dmattr_t set_dmattr; + dm_fsys_set_eventlist_t set_eventlist; + dm_fsys_set_fileattr_t set_fileattr; + dm_fsys_set_inherit_t set_inherit; + dm_fsys_set_region_t set_region; + dm_fsys_symlink_by_handle_t symlink_by_handle; + dm_fsys_sync_by_handle_t sync_by_handle; + dm_fsys_upgrade_right_t upgrade_right; + dm_fsys_write_invis_rvp_t write_invis_rvp; +} dm_fsys_vector_t; + + +extern dm_session_t *dm_sessions; /* head of session list */ +extern dm_fsreg_t *dm_registers; +extern lock_t dm_reg_lock; /* lock for registration list */ + +/* + * Kernel only prototypes. + */ + +int dm_find_session_and_lock( + dm_sessid_t sid, + dm_session_t **sessionpp, + int *lcp); + +int dm_find_msg_and_lock( + dm_sessid_t sid, + dm_token_t token, + dm_tokevent_t **tevpp, + int *lcp); + +dm_tokevent_t * dm_evt_create_tevp( + dm_eventtype_t event, + int variable_size, + void **msgpp); + +int dm_app_get_tdp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + short types, + dm_right_t right, + dm_tokdata_t **tdpp); + +int dm_get_config_tdp( + void *hanp, + size_t hlen, + dm_tokdata_t **tdpp); + +void dm_app_put_tdp( + dm_tokdata_t *tdp); + +void dm_put_tevp( + dm_tokevent_t *tevp, + dm_tokdata_t *tdp); + +void dm_evt_rele_tevp( + dm_tokevent_t *tevp, + int droprights); + +int dm_enqueue_normal_event( + vfs_t *vfsp, + dm_tokevent_t *tevp, + int flags); + +int dm_enqueue_mount_event( + vfs_t *vfsp, + dm_tokevent_t *tevp); + +int dm_enqueue_sendmsg_event( + dm_sessid_t targetsid, + dm_tokevent_t *tevp, + int synch); + +int dm_enqueue_user_event( + dm_sessid_t sid, + dm_tokevent_t *tevp, + dm_token_t *tokenp); + +int dm_obj_ref_query_rvp( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen, + int *rvp); + +int dm_read_invis_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp); + +int dm_write_invis_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int flags, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp); + +int dm_get_bulkattr_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvp); + +int dm_get_bulkall_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrname_t *attrnamep, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvp); + +int dm_get_dirattrs_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvp); + +int dm_get_allocinfo_rvp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t *offp, + u_int nelem, + dm_extent_t *extentp, + u_int *nelemp, + int *rvp); + +dm_session_t * dm_get_session( + vfs_t *vfsp, + dm_eventtype_t event); + +int dm_waitfor_destroy_attrname( + vfs_t *vfsp, + dm_attrname_t *attrnamep); + +void dm_clear_fsreg( + dm_session_t *s); + +int dm_add_fsys_entry( + vfs_t *vfsp, + dm_tokevent_t *tevp); + +void dm_change_fsys_entry( + vfs_t *vfsp, + dm_fsstate_t newstate); + +void dm_remove_fsys_entry( + vfs_t *vfsp); + +dm_fsys_vector_t *dm_fsys_vector( + bhv_desc_t *bdp); + +int dm_waitfor_disp_session( + vfs_t *vfsp, + dm_tokevent_t *tevp, + dm_session_t **sessionpp, + int *lcp); + +vnode_t * dm_handle_to_vp ( + xfs_handle_t *handlep, + short *typep); + +int dm_check_dmapi_vp( + vnode_t *vp); + +dm_tokevent_t * dm_find_mount_tevp_and_lock( + fsid_t *fsidp, + int *lcp); + +int dm_path_to_hdl( + char *path, + void *hanp, + size_t *hlenp); + +int dm_path_to_fshdl( + char *path, + void *hanp, + size_t *hlenp); + +int dm_fd_to_hdl( + int fd, + void *hanp, + size_t *hlenp); + +int dm_upgrade_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +int dm_downgrade_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +int dm_request_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int flags, + dm_right_t right); + +int dm_release_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +int dm_query_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_right_t *rightp); + + +int dm_set_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + u_int maxevent); + +int dm_obj_ref_hold( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +int dm_obj_ref_rele( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +int dm_get_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp); + + +int dm_set_disp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + u_int maxevent); + + +int dm_set_return_on_destroy( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + dm_boolean_t enable); + + +int dm_get_mountinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp); + +#endif /* _DMAPI_PRIVATE_H */ diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/dmapi_region.c linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_region.c --- linux-2.4.7/linux/fs/xfs/dmapi/dmapi_region.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_region.c Mon Oct 2 10:19:34 2000 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +int +dm_get_region( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_region_t *regbufp, + u_int *nelemp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->get_region(tdp->td_bdp, tdp->td_right, + nelem, regbufp, nelemp); + + dm_app_put_tdp(tdp); + return(error); +} + + + +int +dm_set_region( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_region_t *regbufp, + dm_boolean_t *exactflagp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_REG, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->set_region(tdp->td_bdp, tdp->td_right, + nelem, regbufp, exactflagp); + + dm_app_put_tdp(tdp); + return(error); +} diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/dmapi_register.c linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_register.c --- linux-2.4.7/linux/fs/xfs/dmapi/dmapi_register.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_register.c Fri Apr 6 21:03:36 2001 @@ -0,0 +1,1426 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" +#include + + +dm_fsreg_t *dm_registers; /* head of filesystem registration list */ +int dm_fsys_cnt; /* number of filesystems on dm_registers list */ +lock_t dm_reg_lock; /* lock for dm_registers */ + + + +/* Returns a pointer to the filesystem structure for the filesystem + referenced by vfsp. The caller is responsible for obtaining dm_reg_lock + before calling this routine. +*/ + +static dm_fsreg_t * +dm_find_fsreg( + fsid_t *fsidp) +{ + dm_fsreg_t *fsrp; + + for (fsrp = dm_registers; fsrp; fsrp = fsrp->fr_next) { + if (!bcmp(&fsrp->fr_fsid, fsidp, sizeof(*fsidp))) + break; + } + return(fsrp); +} + + +/* Given a fsid_t, dm_find_fsreg_and_lock() finds the dm_fsreg_t structure + for that filesytem if one exists, and returns a pointer to the structure + after obtaining its 'fr_lock' so that the caller can safely modify the + dm_fsreg_t. The caller is responsible for releasing 'fr_lock'. +*/ + +static dm_fsreg_t * +dm_find_fsreg_and_lock( + fsid_t *fsidp, + int *lcp) /* address of returned lock cookie */ +{ + dm_fsreg_t *fsrp; + + for (;;) { + *lcp = mutex_spinlock(&dm_reg_lock); + + if ((fsrp = dm_find_fsreg(fsidp)) == NULL) { + mutex_spinunlock(&dm_reg_lock, *lcp); + return(NULL); + } + if (nested_spintrylock(&fsrp->fr_lock)) { + nested_spinunlock(&dm_reg_lock); + return(fsrp); /* success */ + } + + /* If the second lock is not available, drop the first and + start over. This gives the CPU a chance to process any + interrupts, and also allows processes which want a fr_lock + for a different filesystem to proceed. + */ + + mutex_spinunlock(&dm_reg_lock, *lcp); + } +} + + +/* dm_add_fsys_entry() is called when a DM_EVENT_MOUNT event is about to be + sent. It creates a dm_fsreg_t structure for the filesystem and stores a + pointer to a copy of the mount event within that structure so that it is + available for subsequent dm_get_mountinfo() calls. +*/ + +int +dm_add_fsys_entry( + vfs_t *vfsp, + dm_tokevent_t *tevp) +{ + dm_fsreg_t *fsrp; + int msgsize; + void *msg; + int lc; /* lock cookie */ + + /* Allocate and initialize a dm_fsreg_t structure for the filesystem. */ + + msgsize = tevp->te_allocsize - offsetof(dm_tokevent_t, te_event); + msg = kmem_alloc(msgsize, KM_SLEEP); + bcopy(&tevp->te_event, msg, msgsize); + + fsrp = kmem_zalloc(sizeof(*fsrp), KM_SLEEP); + fsrp->fr_vfsp = vfsp; + fsrp->fr_tevp = tevp; + fsrp->fr_fsid = *vfsp->vfs_altfsid; + fsrp->fr_msg = msg; + fsrp->fr_msgsize = msgsize; + fsrp->fr_state = DM_STATE_MOUNTING; + sv_init(&fsrp->fr_dispq, SV_DEFAULT, "fr_dispq"); + sv_init(&fsrp->fr_queue, SV_DEFAULT, "fr_queue"); + spinlock_init(&fsrp->fr_lock, "fr_lock"); + + /* If no other mounted DMAPI filesystem already has this same + fsid_t, then add this filesystem to the list. + */ + + lc = mutex_spinlock(&dm_reg_lock); + + if (!dm_find_fsreg(vfsp->vfs_altfsid)) { + fsrp->fr_next = dm_registers; + dm_registers = fsrp; + dm_fsys_cnt++; + mutex_spinunlock(&dm_reg_lock, lc); + return(0); + } + + /* A fsid_t collision occurred, so prevent this new filesystem from + mounting. + */ + + mutex_spinunlock(&dm_reg_lock, lc); + + sv_destroy(&fsrp->fr_dispq); + sv_destroy(&fsrp->fr_queue); + spinlock_destroy(&fsrp->fr_lock); + kmem_free(fsrp->fr_msg, fsrp->fr_msgsize); + kmem_free(fsrp, sizeof(*fsrp)); + return(EBUSY); +} + + +/* dm_change_fsys_entry() is called whenever a filesystem's mount state is + about to change. The state is changed to DM_STATE_MOUNTED after a + successful DM_EVENT_MOUNT event or after a failed unmount. It is changed + to DM_STATE_UNMOUNTING after a successful DM_EVENT_PREUNMOUNT event. + Finally, the state is changed to DM_STATE_UNMOUNTED after a successful + unmount. It stays in this state until the DM_EVENT_UNMOUNT event is + queued, at which point the filesystem entry is removed. +*/ + +void +dm_change_fsys_entry( + vfs_t *vfsp, + dm_fsstate_t newstate) +{ + dm_fsreg_t *fsrp; + int seq_error; + int lc; /* lock cookie */ + + /* Find the filesystem referenced by the vfsp's fsid_t. This should + always succeed. + */ + + if ((fsrp = dm_find_fsreg_and_lock(vfsp->vfs_altfsid, &lc)) == NULL) { + panic("dm_change_fsys_entry: can't find DMAPI fsrp for " + "vfsp %p\n", vfsp); + } + + /* Make sure that the new state is acceptable given the current state + of the filesystem. Any error here is a major DMAPI/filesystem + screwup. + */ + + seq_error = 0; + switch (newstate) { + case DM_STATE_MOUNTED: + if (fsrp->fr_state != DM_STATE_MOUNTING && + fsrp->fr_state != DM_STATE_UNMOUNTING) { + seq_error++; + } + break; + case DM_STATE_UNMOUNTING: + if (fsrp->fr_state != DM_STATE_MOUNTED) + seq_error++; + break; + case DM_STATE_UNMOUNTED: + if (fsrp->fr_state != DM_STATE_UNMOUNTING) + seq_error++; + break; + default: + seq_error++; + break; + } + if (seq_error) { + panic("dm_change_fsys_entry: DMAPI sequence error: old state " + "%d, new state %d, fsrp %p\n", fsrp->fr_state, + newstate, fsrp); + } + + /* If the old state was DM_STATE_UNMOUNTING, then processes could be + sleeping in dm_handle_to_vp() waiting for their DM_NO_TOKEN handles + to be translated to vnodes. Wake them up so that they either + continue (new state is DM_STATE_MOUNTED) or fail (new state is + DM_STATE_UNMOUNTED). + */ + + if (fsrp->fr_state == DM_STATE_UNMOUNTING) { + if (fsrp->fr_hdlcnt) + sv_broadcast(&fsrp->fr_queue); + } + + /* Change the filesystem's mount state to its new value. */ + + fsrp->fr_state = newstate; + fsrp->fr_tevp = NULL; /* not valid after DM_STATE_MOUNTING */ + + /* If the new state is DM_STATE_UNMOUNTING, wait until any application + threads currently in the process of making VFS_VGET and VFS_ROOT + calls are done before we let this unmount thread continue the + unmount. (We want to make sure that the unmount will see these + vnode references during its scan.) + */ + + if (newstate == DM_STATE_UNMOUNTING) { + while (fsrp->fr_vfscnt) { + fsrp->fr_unmount++; +#ifdef __sgi + sv_wait(&fsrp->fr_queue, PZERO, &fsrp->fr_lock, lc); +#else + sv_wait(&fsrp->fr_queue, 1, &fsrp->fr_lock, lc); +#endif + lc = mutex_spinlock(&fsrp->fr_lock); + fsrp->fr_unmount--; + } + } + + mutex_spinunlock(&fsrp->fr_lock, lc); +} + + +/* dm_remove_fsys_entry() gets called after a failed mount or after an + DM_EVENT_UNMOUNT event has been queued. (The filesystem entry must stay + until the DM_EVENT_UNMOUNT reply is queued so that the event can use the + 'fr_sessp' list to see which session to send the event to.) +*/ + +void +dm_remove_fsys_entry( + vfs_t *vfsp) +{ + dm_fsreg_t **fsrpp; + dm_fsreg_t *fsrp; + int lc; /* lock cookie */ + + /* Find the filesystem referenced by the vfsp's fsid_t and dequeue + it after verifying that the fr_state shows a filesystem that is + either mounting or unmounted. + */ + + lc = mutex_spinlock(&dm_reg_lock); + + fsrpp = &dm_registers; + while ((fsrp = *fsrpp) != NULL) { + if (!bcmp(&fsrp->fr_fsid, vfsp->vfs_altfsid, sizeof(fsrp->fr_fsid))) + break; + fsrpp = &fsrp->fr_next; + } + if (fsrp == NULL) { + mutex_spinunlock(&dm_reg_lock, lc); + panic("dm_remove_fsys_entry: can't find DMAPI fsrp for " + "vfsp %p\n", vfsp); + } + + nested_spinlock(&fsrp->fr_lock); + + /* Verify that it makes sense to remove this entry. */ + + if (fsrp->fr_state != DM_STATE_MOUNTING && + fsrp->fr_state != DM_STATE_UNMOUNTED) { + nested_spinunlock(&fsrp->fr_lock); + mutex_spinunlock(&dm_reg_lock, lc); + panic("dm_remove_fsys_entry: DMAPI sequence error: old state " + "%d, fsrp %p\n", fsrp->fr_state, fsrp); + } + + *fsrpp = fsrp->fr_next; + dm_fsys_cnt--; + + nested_spinunlock(&dm_reg_lock); + + /* Since the filesystem is about to finish unmounting, we must be sure + that no vnodes are being referenced within the filesystem before we + let this event thread continue. If the filesystem is currently in + state DM_STATE_MOUNTING, then we know by definition that there can't + be any references. If the filesystem is DM_STATE_UNMOUNTED, then + any application threads referencing handles with DM_NO_TOKEN should + have already been awakened by dm_change_fsys_entry and should be + long gone by now. Just in case they haven't yet left, sleep here + until they are really gone. + */ + + while (fsrp->fr_hdlcnt) { + fsrp->fr_unmount++; +#ifdef __sgi + sv_wait(&fsrp->fr_queue, PZERO, &fsrp->fr_lock, lc); +#else + sv_wait(&fsrp->fr_queue, 1, &fsrp->fr_lock, lc); +#endif + lc = mutex_spinlock(&fsrp->fr_lock); + fsrp->fr_unmount--; + } + mutex_spinunlock(&fsrp->fr_lock, lc); + + /* Release all memory. */ + + sv_destroy(&fsrp->fr_dispq); + sv_destroy(&fsrp->fr_queue); + spinlock_destroy(&fsrp->fr_lock); + kmem_free(fsrp->fr_msg, fsrp->fr_msgsize); + kmem_free(fsrp, sizeof(*fsrp)); +} + + +/* Get a vnode for the object referenced by handlep. We cannot use + altgetvfs() because it fails if the VFS_OFFLINE bit is set, which means + that any call to dm_handle_to_vp() while a umount is in progress would + return an error, even if the umount can't possibly succeed because users + are in the filesystem. The requests would start to fail as soon as the + umount begins, even before the application receives the DM_EVENT_PREUNMOUNT + event. + + dm_handle_to_vp() emulates the behavior of lookup() while an unmount is + in progress. Any call to dm_handle_to_vp() while the filesystem is in the + DM_STATE_UNMOUNTING state will block. If the unmount eventually succeeds, + the requests will wake up and fail. If the unmount fails, the requests will + wake up and complete normally. + + While a filesystem is in state DM_STATE_MOUNTING, dm_handle_to_vp() will + fail all requests. Per the DMAPI spec, the only handles in the filesystem + which are valid during a mount event are the handles within the event + itself. +*/ + +vnode_t * +dm_handle_to_vp( + xfs_handle_t *handlep, + short *typep) +{ + dm_fsreg_t *fsrp; + vnode_t *vp; + short type; + int lc; /* lock cookie */ + int error; + fid_t *fidp; + + if ((fsrp = dm_find_fsreg_and_lock((fsid_t*)&handlep->ha_fsid, &lc)) == NULL) + return(NULL); + + if (fsrp->fr_state == DM_STATE_MOUNTING) { + mutex_spinunlock(&fsrp->fr_lock, lc); + return(NULL); + } + + for (;;) { + if (fsrp->fr_state == DM_STATE_MOUNTED) + break; + if (fsrp->fr_state == DM_STATE_UNMOUNTED) { + if (fsrp->fr_unmount && fsrp->fr_hdlcnt == 0) + sv_broadcast(&fsrp->fr_queue); + mutex_spinunlock(&fsrp->fr_lock, lc); + return(NULL); + } + + /* Must be DM_STATE_UNMOUNTING. */ + + fsrp->fr_hdlcnt++; +#ifdef __sgi + sv_wait(&fsrp->fr_queue, PZERO, &fsrp->fr_lock, lc); +#else + sv_wait(&fsrp->fr_queue, 1, &fsrp->fr_lock, lc); +#endif + lc = mutex_spinlock(&fsrp->fr_lock); + fsrp->fr_hdlcnt--; + } + + fsrp->fr_vfscnt++; + mutex_spinunlock(&fsrp->fr_lock, lc); + + /* Now that the mutex is released, wait until we have access to the + vnode. + */ + + fidp = (fid_t*)&handlep->ha_fid; + if (fidp->fid_len == 0) { /* filesystem handle */ + VFS_ROOT(fsrp->fr_vfsp, &vp, error); + } else { /* file object handle */ + VFS_VGET(fsrp->fr_vfsp, &vp, fidp, error); + } + + lc = mutex_spinlock(&fsrp->fr_lock); + + fsrp->fr_vfscnt--; + if (fsrp->fr_unmount && fsrp->fr_vfscnt == 0) + sv_broadcast(&fsrp->fr_queue); + + mutex_spinunlock(&fsrp->fr_lock, lc); + if (error || vp == NULL) + return(NULL); + + if (fidp->fid_len == 0) { + type = DM_TDT_VFS; + } else if (vp->v_type == VREG) { + type = DM_TDT_REG; + } else if (vp->v_type == VDIR) { + type = DM_TDT_DIR; + } else if (vp->v_type == VLNK) { + type = DM_TDT_LNK; + } else { + type = DM_TDT_OTH; + } + *typep = type; + return(vp); +} + + +int +dm_vp_to_handle( + vnode_t *vp, + xfs_handle_t *handlep) +{ + int error; + struct fid fid; + int hsize; + + if (vp->v_vfsp->vfs_altfsid == NULL) + return(EINVAL); + + VOP_FID2(vp, &fid, error); + if (error) + return(error); + + bcopy (vp->v_vfsp->vfs_altfsid, &handlep->ha_fsid, sizeof(fsid_t)); + bcopy(&fid, &handlep->ha_fid, fid.fid_len + sizeof fid.fid_len); + hsize = XFS_HSIZE(*handlep); + bzero ((char *)handlep + hsize, sizeof(*handlep) - hsize); + return(0); +} + + +/* Given a vnode, check if that vnode resides in filesystem that supports + DMAPI. Returns zero if the vnode is in a DMAPI filesystem, otherwise + returns an errno. +*/ + +int +dm_check_dmapi_vp( + vnode_t *vp) +{ + xfs_handle_t handle; + /* REFERENCED */ + dm_fsreg_t *fsrp; + int error; + int lc; /* lock cookie */ + + if ((error = dm_vp_to_handle(vp, &handle)) != 0) + return(error); + + if ((fsrp = dm_find_fsreg_and_lock((fsid_t*)&handle.ha_fsid, &lc)) == NULL) + return(EBADF); + mutex_spinunlock(&fsrp->fr_lock, lc); + return(0); +} + + +/* Return a pointer to the DM_EVENT_MOUNT event while a mount is still in + progress. This is only called by dm_get_config and dm_get_config_events + which need to access the filesystem during a mount but which don't have + a session and token to use. +*/ + +dm_tokevent_t * +dm_find_mount_tevp_and_lock( + fsid_t *fsidp, + int *lcp) /* address of returned lock cookie */ +{ + dm_fsreg_t *fsrp; + + if ((fsrp = dm_find_fsreg_and_lock(fsidp, lcp)) == NULL) + return(NULL); + + if (!fsrp->fr_tevp || fsrp->fr_state != DM_STATE_MOUNTING) { + mutex_spinunlock(&fsrp->fr_lock, *lcp); + return(NULL); + } + nested_spinlock(&fsrp->fr_tevp->te_lock); + nested_spinunlock(&fsrp->fr_lock); + return(fsrp->fr_tevp); +} + + +/* Wait interruptibly until a session registers disposition for 'event' in + filesystem 'vfsp'. Upon successful exit, both the filesystem's dm_fsreg_t + structure and the session's dm_session_t structure are locked. The caller + is responsible for unlocking both structures using the returned cookies. + + Warning: The locks can be dropped in any order, but the 'lc2p' cookie MUST + BE USED FOR THE FIRST UNLOCK, and the lc1p cookie must be used for the + second unlock. If this is not done, the CPU will be interruptible while + holding a mutex, which could deadlock the machine! +*/ + +static int +dm_waitfor_disp( + vfs_t *vfsp, + dm_eventtype_t event, + dm_fsreg_t **fsrpp, + int *lc1p, /* addr of first returned lock cookie */ + dm_session_t **sessionpp, + int *lc2p) /* addr of 2nd returned lock cookie */ +{ + dm_session_t *s; + dm_fsreg_t *fsrp; + + if ((fsrp = dm_find_fsreg_and_lock(vfsp->vfs_altfsid, lc1p)) == NULL) + return(ENOENT); + + /* If no session is registered for this event in the specified + filesystem, then sleep interruptibly until one does. + */ + + for (;;) { + int rc = 0; + + /* The dm_find_session_and_lock() call is needed because a + session that is in the process of being removed might still + be in the dm_fsreg_t structure but won't be in the + dm_sessions list. + */ + + if ((s = fsrp->fr_sessp[event]) != NULL && + dm_find_session_and_lock(s->sn_sessid, &s, lc2p) == 0) { + break; + } + + /* Noone is currently registered. DM_EVENT_UNMOUNT events + don't wait for anyone to register because the unmount is + already past the point of no return. + */ + + if (event == DM_EVENT_UNMOUNT) { + mutex_spinunlock(&fsrp->fr_lock, *lc1p); + return(ENOENT); + } + + /* Wait until a session registers for disposition of this + event. + */ + + fsrp->fr_dispcnt++; +#ifdef __sgi + rc = sv_wait_sig(&fsrp->fr_dispq, PUSER, &fsrp->fr_lock, *lc1p); +#else + mp_sv_wait_sig(&fsrp->fr_dispq, 1, &fsrp->fr_lock, *lc1p); + rc = current->sigpending; +#endif + *lc1p = mutex_spinlock(&fsrp->fr_lock); + fsrp->fr_dispcnt--; + if (rc) { /* if signal was received */ + mutex_spinunlock(&fsrp->fr_lock, *lc1p); + return(EINTR); + } + } + *sessionpp = s; + *fsrpp = fsrp; + return(0); +} + + +/* Returns the session pointer for the session registered for an event + in the given vfsp. If successful, the session is locked upon return. The + caller is responsible for releasing the lock. If no session is currently + registered for the event, dm_waitfor_disp_session() will sleep interruptibly + until a registration occurs. +*/ + +int +dm_waitfor_disp_session( + vfs_t *vfsp, + dm_tokevent_t *tevp, + dm_session_t **sessionpp, + int *lcp) +{ + dm_fsreg_t *fsrp; + int lc2; + int error; + + if (tevp->te_msg.ev_type < 0 || tevp->te_msg.ev_type > DM_EVENT_MAX) + return(EIO); + + error = dm_waitfor_disp(vfsp, tevp->te_msg.ev_type, &fsrp, lcp, + sessionpp, &lc2); + if (!error) + mutex_spinunlock(&fsrp->fr_lock, lc2); /* rev. cookie order*/ + return(error); +} + + +/* Find the session registered for the DM_EVENT_DESTROY event on the specified + filesystem, sleeping if necessary until registration occurs. Once found, + copy the session's return-on-destroy attribute name, if any, back to the + caller. +*/ + +int +dm_waitfor_destroy_attrname( + vfs_t *vfsp, + dm_attrname_t *attrnamep) +{ + dm_session_t *s; + dm_fsreg_t *fsrp; + int error; + int lc1; /* first lock cookie */ + int lc2; /* second lock cookie */ + + error = dm_waitfor_disp(vfsp, DM_EVENT_DESTROY, &fsrp, &lc1, &s, &lc2); + if (!error) { + *attrnamep = fsrp->fr_rattr; /* attribute or zeros */ + mutex_spinunlock(&s->sn_qlock, lc2); /* rev. cookie order */ + mutex_spinunlock(&fsrp->fr_lock, lc1); + } + return(error); +} + + +/* Unregisters the session for the disposition of all events on all + filesystems. This routine is not called until the session has been + dequeued from the session list and its session lock has been dropped, + but before the actual structure is freed, so it is safe to grab the + 'dm_reg_lock' here. If dm_waitfor_disp_session() happens to be called + by another thread, it won't find this session on the session list and + will wait until a new session registers. +*/ + +void +dm_clear_fsreg( + dm_session_t *s) +{ + dm_fsreg_t *fsrp; + int event; + int lc; /* lock cookie */ + + lc = mutex_spinlock(&dm_reg_lock); + + for (fsrp = dm_registers; fsrp != NULL; fsrp = fsrp->fr_next) { + nested_spinlock(&fsrp->fr_lock); + for (event = 0; event < DM_EVENT_MAX; event++) { + if (fsrp->fr_sessp[event] != s) + continue; + fsrp->fr_sessp[event] = NULL; + if (event == DM_EVENT_DESTROY) + bzero(&fsrp->fr_rattr, sizeof(fsrp->fr_rattr)); + } + nested_spinunlock(&fsrp->fr_lock); + } + + mutex_spinunlock(&dm_reg_lock, lc); +} + + +/* + * Return the handle for the object named by path. + */ + +int +dm_path_to_hdl( + char *path, /* any path name */ + void *hanp, /* user's data buffer */ + size_t *hlenp) /* set to size of data copied */ +{ + /* REFERENCED */ + dm_fsreg_t *fsrp; + xfs_handle_t handle; + vnode_t *vp; + size_t hlen; + int error; + int lc; /* lock cookie */ + struct nameidata nd; + struct inode *inode; + size_t len; + char *name; + +#ifdef __sgi + error = lookupname(path, UIO_USERSPACE, NO_FOLLOW, NULLVPP, &vp, NULL); + if (error) + return(error); +#else + /* XXX get things straightened out so getname() works here? */ + len = strnlen_user(path, 2000); + name = kmem_alloc(len, KM_SLEEP); + if (copy_from_user(name, path, len)) + return(EFAULT); + + error = 0; + if (path_init(name, LOOKUP_POSITIVE, &nd)) + error = path_walk(name, &nd); + if (error) + return error; + + kmem_free(name, len); + ASSERT(nd.dentry); + ASSERT(nd.dentry->d_inode); + inode = igrab(nd.dentry->d_inode); + path_release(&nd); + + /* we need the vnode */ + vp = LINVFS_GET_VP(inode); + if (!vp || !vp->v_vfsp->vfs_altfsid) { + /* we're not in XFS anymore, Toto */ + iput(inode); + return EINVAL; + } +#endif + + error = dm_vp_to_handle(vp, &handle); + VN_RELE(vp); + if (error) + return(error); + + if ((fsrp = dm_find_fsreg_and_lock((fsid_t*)&handle.ha_fsid, &lc)) == NULL) + return(EBADF); + mutex_spinunlock(&fsrp->fr_lock, lc); + + hlen = XFS_HSIZE(handle); +#ifdef __sgi + if (copyout(&handle, hanp, (int)hlen)) + return(EFAULT); +#else + if (copy_to_user(hanp, &handle, (int)hlen)) + return(EFAULT); +#endif +#ifdef __sgi + return(dm_cpoutsizet(hlenp, hlen)); +#else + return(put_user(hlen,hlenp)); +#endif +} + + +/* + * Return the handle for the file system containing the object named by path. + */ + +int +dm_path_to_fshdl( + char *path, /* any path name */ + void *hanp, /* user's data buffer */ + size_t *hlenp) /* set to size of data copied */ +{ + /* REFERENCED */ + dm_fsreg_t *fsrp; + xfs_handle_t handle; + vnode_t *vp; + size_t hlen; + int error; + int lc; /* lock cookie */ + char *tmp; + struct nameidata nd; + struct inode *inode; + size_t len; + char *name; + +#ifdef __sgi + error = lookupname(path, UIO_USERSPACE, NO_FOLLOW, NULLVPP, &vp, NULL); + if (error) + return(error); +#else + /* XXX get things straightened out so getname() works here? */ + len = strnlen_user(path, 2000); + name = kmem_alloc(len, KM_SLEEP); + if (copy_from_user(name, path, len)) + return(EFAULT); + + error = 0; + if (path_init(name, LOOKUP_POSITIVE|LOOKUP_FOLLOW, &nd)) + error = path_walk(name, &nd); + if (error) + return error; + kmem_free(name, len); + + ASSERT(nd.dentry); + ASSERT(nd.dentry->d_inode); + + inode = igrab(nd.dentry->d_inode); + path_release(&nd); + + /* we need the vnode */ + vp = LINVFS_GET_VP(inode); + if (!vp || !vp->v_vfsp->vfs_altfsid) { + /* we're not in XFS anymore, Toto */ + iput(inode); + return EINVAL; + } + + +#endif + error = dm_vp_to_handle(vp, &handle); + VN_RELE(vp); + if (error) + return(error); + + if ((fsrp = dm_find_fsreg_and_lock((fsid_t*)&handle.ha_fsid, &lc)) == NULL) + return(EBADF); + mutex_spinunlock(&fsrp->fr_lock, lc); + + hlen = FSHSIZE; +#ifdef __sgi + if (copyout(&handle, hanp, (int)hlen)) + return(EFAULT); +#else + if(copy_to_user(hanp, &handle, (int)hlen)) + return(EFAULT); +#endif +#ifdef __sgi + return(dm_cpoutsizet(hlenp, hlen)); +#else + return(put_user(hlen,hlenp)); +#endif +} + + +int +dm_fd_to_hdl( + int fd, /* any file descriptor */ + void *hanp, /* user's data buffer */ + size_t *hlenp) /* set to size of data copied */ +{ + /* REFERENCED */ + dm_fsreg_t *fsrp; + xfs_handle_t handle; + size_t hlen; + int error; + int lc; /* lock cookie */ + +#ifdef __sgi + vfile_t *vfilep; + + if ((error = getf(fd, &vfilep)) != 0) + return(error); + if (!VF_IS_VNODE(vfilep)) + return(EINVAL); + if ((error = dm_vp_to_handle(VF_TO_VNODE(vfilep), &handle)) != 0) + return(error); +#else + struct file *filep = fget(fd); + + if (!filep) + return(EBADF); + if ((error = dm_vp_to_handle(LINVFS_GET_VP(filep->f_dentry->d_inode), &handle)) != 0) + return(error); +#endif + + if ((fsrp = dm_find_fsreg_and_lock((fsid_t*)&handle.ha_fsid, &lc)) == NULL) + return(EBADF); + mutex_spinunlock(&fsrp->fr_lock, lc); + + hlen = XFS_HSIZE(handle); +#ifdef __sgi + if (copyout(&handle, hanp, (int)hlen)) + return(EFAULT); +#else + if (copy_to_user(hanp, &handle, (int)hlen)) + return(EFAULT); +#endif +#ifdef __sgi + return(dm_cpoutsizet(hlenp, hlen)); +#else + fput(filep); + return(put_user(hlen, hlenp)); +#endif +} + + +/* Enable events on an object. */ + +int +dm_set_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + u_int maxevent) +{ + dm_fsys_vector_t *fsys_vector; + dm_eventset_t eventset; + dm_tokdata_t *tdp; + int error; + +#ifdef __sgi + if (copyin(eventsetp, &eventset, sizeof(eventset))) + return(EFAULT); +#else + if (copy_from_user(&eventset, eventsetp, sizeof(eventset))) + return(EFAULT); +#endif + + /* Do some minor sanity checking. */ + + if (maxevent == 0 || maxevent > DM_EVENT_MAX) + return(EINVAL); + + /* Access the specified object. */ + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_ANY, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->set_eventlist(tdp->td_bdp, tdp->td_right, + (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0), + &eventset, maxevent); + + dm_app_put_tdp(tdp); + return(error); +} + + +/* Return the list of enabled events for an object. */ + +int +dm_get_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + dm_eventset_t eventset; + u_int elem; + int error; + + if (nelem == 0) + return(EINVAL); + + /* Access the specified object. */ + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_ANY, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + /* Get the object's event list. */ + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->get_eventlist(tdp->td_bdp, tdp->td_right, + (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0), + nelem, &eventset, &elem); + + dm_app_put_tdp(tdp); + + if (error) + return(error); + +#ifdef __sgi + if (copyout(&eventset, eventsetp, sizeof(eventset))) + return(EFAULT); +#else + if (copy_to_user(eventsetp, &eventset, sizeof(eventset))) + return(EFAULT); +#endif +#ifdef __sgi + if (suword(nelemp, nelem)) + return(EFAULT); +#else + if (put_user(nelem, nelemp)) + return(EFAULT); +#endif + return(0); +} + + +/* Register for disposition of events. The handle must either be the + global handle or must be the handle of a file system. The list of events + is pointed to by eventsetp. +*/ + +int +dm_set_disp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + u_int maxevent) +{ + dm_session_t *s; + dm_fsreg_t *fsrp; + dm_tokdata_t *tdp; + dm_eventset_t eventset; + int error; + int lc1; /* first lock cookie */ + int lc2; /* second lock cookie */ + u_int i; + + /* Copy in and validate the event mask. Only the lower maxevent bits + are meaningful, so clear any bits set above maxevent. + */ + + if (maxevent == 0 || maxevent > DM_EVENT_MAX) + return(EINVAL); +#ifdef __sgi + if (copyin(eventsetp, &eventset, sizeof(eventset))) + return(EFAULT); +#else + if (copy_from_user(&eventset, eventsetp, sizeof(eventset))) + return(EFAULT); +#endif + eventset &= (1 << maxevent) - 1; + + /* If the caller specified the global handle, then the only valid token + is DM_NO_TOKEN, and the only valid event in the event mask is + DM_EVENT_MOUNT. If it is set, add the session to the list of + sessions that want to receive mount events. If it is clear, remove + the session from the list. Since DM_EVENT_MOUNT events never block + waiting for a session to register, there is noone to wake up if we + do add the session to the list. + */ + + if (DM_GLOBALHAN(hanp, hlen)) { + if (token != DM_NO_TOKEN) + return(EINVAL); + if ((error = dm_find_session_and_lock(sid, &s, &lc1)) != 0) + return(error); + if (eventset == 0) { + s->sn_flags &= ~DM_SN_WANTMOUNT; + error = 0; + } else if (eventset == 1 << DM_EVENT_MOUNT) { + s->sn_flags |= DM_SN_WANTMOUNT; + error = 0; + } else { + error = EINVAL; + } + mutex_spinunlock(&s->sn_qlock, lc1); + return(error); + } + + /* Since it's not the global handle, it had better be a filesystem + handle. Verify that the first 'maxevent' events in the event list + are all valid for a filesystem handle. + */ + + if (eventset & ~DM_VALID_DISP_EVENTS) + return(EINVAL); + + /* Verify that the session is valid, that the handle is a filesystem + handle, and that the filesystem is capable of sending events. (If + a dm_fsreg_t structure exists, then the filesystem can issue events.) + */ + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsrp = dm_find_fsreg_and_lock((fsid_t*)&tdp->td_handle.ha_fsid, &lc1); + if (fsrp == NULL) { + dm_app_put_tdp(tdp); + return(EINVAL); + } + + /* Now that we own 'fsrp->fr_lock', get the lock on the session so that + it can't disappear while we add it to the filesystem's event mask. + */ + + if ((error = dm_find_session_and_lock(sid, &s, &lc2)) != 0) { + mutex_spinunlock(&fsrp->fr_lock, lc1); + dm_app_put_tdp(tdp); + return(error); + } + + /* Update the event disposition array for this filesystem, adding + and/or removing the session as appropriate. If this session is + dropping registration for DM_EVENT_DESTROY, or is overriding some + other session's registration for DM_EVENT_DESTROY, then clear any + any attr-on-destroy attribute name also. + */ + + for (i = 0; i < DM_EVENT_MAX; i++) { + if (DMEV_ISSET(i, eventset)) { + if (i == DM_EVENT_DESTROY && fsrp->fr_sessp[i] != s) + bzero(&fsrp->fr_rattr, sizeof(fsrp->fr_rattr)); + fsrp->fr_sessp[i] = s; + } else if (fsrp->fr_sessp[i] == s) { + if (i == DM_EVENT_DESTROY) + bzero(&fsrp->fr_rattr, sizeof(fsrp->fr_rattr)); + fsrp->fr_sessp[i] = NULL; + } + } + mutex_spinunlock(&s->sn_qlock, lc2); /* reverse cookie order */ + + /* Wake up all processes waiting for a disposition on this filesystem + in case any of them happen to be waiting for an event which we just + added. + */ + + if (fsrp->fr_dispcnt) + sv_broadcast(&fsrp->fr_dispq); + + mutex_spinunlock(&fsrp->fr_lock, lc1); + + dm_app_put_tdp(tdp); + return(0); +} + + +/* + * Register a specific attribute name with a filesystem. The value of + * the attribute is to be returned with an asynchronous destroy event. + */ + +int +dm_set_return_on_destroy( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + dm_boolean_t enable) +{ + dm_attrname_t attrname; + dm_tokdata_t *tdp; + dm_fsreg_t *fsrp; + dm_session_t *s; + int error; + int lc1; /* first lock cookie */ + int lc2; /* second lock cookie */ + + /* If a dm_attrname_t is provided, copy it in and validate it. */ + +#ifdef __sgi + if (enable && (error = copyin(attrnamep, &attrname, sizeof(attrname))) != 0)*/ + return(error); +#else + if (enable && (error = copy_from_user(&attrname, attrnamep, sizeof(attrname))) != 0) + return(error); +#endif + + /* Validate the filesystem handle and use it to get the filesystem's + disposition structure. + */ + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_EXCL, &tdp); + if (error != 0) + return(error); + + fsrp = dm_find_fsreg_and_lock((fsid_t*)&tdp->td_handle.ha_fsid, &lc1); + if (fsrp == NULL) { + dm_app_put_tdp(tdp); + return(EINVAL); + } + + /* Now that we own 'fsrp->fr_lock', get the lock on the session so that + it can't disappear while we add it to the filesystem's event mask. + */ + + if ((error = dm_find_session_and_lock(sid, &s, &lc2)) != 0) { + mutex_spinunlock(&fsrp->fr_lock, lc1); + dm_app_put_tdp(tdp); + return(error); + } + + /* A caller cannot disable return-on-destroy if he is not registered + for DM_EVENT_DESTROY. Enabling return-on-destroy is an implicit + dm_set_disp() for DM_EVENT_DESTROY; we wake up all processes + waiting for a disposition in case any was waiting for a + DM_EVENT_DESTROY event. + */ + + error = 0; + if (enable) { + fsrp->fr_sessp[DM_EVENT_DESTROY] = s; + fsrp->fr_rattr = attrname; + if (fsrp->fr_dispcnt) + sv_broadcast(&fsrp->fr_dispq); + } else if (fsrp->fr_sessp[DM_EVENT_DESTROY] != s) { + error = EINVAL; + } else { + bzero(&fsrp->fr_rattr, sizeof(fsrp->fr_rattr)); + } + mutex_spinunlock(&s->sn_qlock, lc2); /* reverse cookie order */ + mutex_spinunlock(&fsrp->fr_lock, lc1); + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_get_mountinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_fsreg_t *fsrp; + dm_tokdata_t *tdp; + int error; + int lc; /* lock cookie */ + + /* Make sure that the caller's buffer is 8-byte aligned. */ + + if (((__psint_t)bufp & (sizeof(__u64) - 1)) != 0) + return(EFAULT); + + /* Verify that the handle is a filesystem handle, and that the + filesystem is capable of sending events. If not, return an error. + */ + + error = dm_app_get_tdp(sid, hanp, hlen, token, DM_TDT_VFS, + DM_RIGHT_SHARED, &tdp); + if (error != 0) + return(error); + + /* Find the filesystem entry. This should always succeed as the + dm_app_get_tdp call created a filesystem reference. Once we find + the entry, drop the lock. The mountinfo message is never modified, + the filesystem entry can't disappear, and we don't want to hold a + spinlock while doing copyout calls. + */ + + fsrp = dm_find_fsreg_and_lock((fsid_t*)&tdp->td_handle.ha_fsid, &lc); + if (fsrp == NULL) { + dm_app_put_tdp(tdp); + return(EINVAL); + } + mutex_spinunlock(&fsrp->fr_lock, lc); + + /* Copy the message into the user's buffer and update his 'rlenp'. */ + +#ifdef __sgi + if (dm_cpoutsizet(rlenp, fsrp->fr_msgsize)) { +#else + if (put_user(fsrp->fr_msgsize, rlenp)) { +#endif + error = EFAULT; + } else if (fsrp->fr_msgsize > buflen) { /* user buffer not big enough */ + error = E2BIG; +#ifdef __sgi + } else if (copyout(fsrp->fr_msg, bufp, fsrp->fr_msgsize)) { +#else + } else if (copy_to_user(bufp, fsrp->fr_msg, fsrp->fr_msgsize)) { +#endif + error = EFAULT; + } else { + error = 0; + } + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_getall_disp( + dm_sessid_t sid, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_session_t *s; /* pointer to session given by sid */ + int lc1; /* first lock cookie */ + int lc2; /* second lock cookie */ + int totalsize; + int msgsize; + int fsyscnt; + dm_dispinfo_t *prevmsg; + dm_fsreg_t *fsrp; + int error; + char *kbuf; + + int tmp3; + int tmp4; + + /* Because the dm_getall_disp structure contains a __u64 field, + make sure that the buffer provided by the caller is aligned so + that he can read such fields successfully. + */ + + if (((__psint_t)bufp & (sizeof(__u64) - 1)) != 0) + return(EFAULT); + + /* Compute the size of a dm_dispinfo structure, rounding up to an + 8-byte boundary so that any subsequent structures will also be + aligned. + */ + +#ifdef __sgi + msgsize = (sizeof(dm_dispinfo_t) + FSHSIZE + sizeof(uint64_t) - 1) & + ~(sizeof(uint64_t) - 1); +#else +/* XXX */ +/* ug, what is going on here? */ + tmp3 = sizeof(dm_dispinfo_t) + FSHSIZE; + tmp3 += sizeof(__u64); + tmp3 -= 1; + tmp4 = ~(sizeof(__u64) - 1); + msgsize = tmp3 & tmp4; +#endif + + /* Loop until we can get the right amount of temp space, being careful + not to hold a mutex during the allocation. Usually only one trip. + */ + + for (;;) { + if ((fsyscnt = dm_fsys_cnt) == 0) { + /*if (dm_cpoutsizet(rlenp, 0))*/ + if (put_user(0,rlenp)) + return(EFAULT); + return(0); + } + kbuf = kmem_alloc(fsyscnt * msgsize, KM_SLEEP); + + lc1 = mutex_spinlock(&dm_reg_lock); + if (fsyscnt == dm_fsys_cnt) + break; + + mutex_spinunlock(&dm_reg_lock, lc1); + kmem_free(kbuf, fsyscnt * msgsize); + } + + /* Find the indicated session and lock it. */ + + if ((error = dm_find_session_and_lock(sid, &s, &lc2)) != 0) { + mutex_spinunlock(&dm_reg_lock, lc1); + kmem_free(kbuf, fsyscnt * msgsize); + return(error); + } + + /* Create a dm_dispinfo structure for each filesystem in which + this session has at least one event selected for disposition. + */ + + totalsize = 0; /* total bytes to transfer to the user */ + prevmsg = NULL; + + for (fsrp = dm_registers; fsrp; fsrp = fsrp->fr_next) { + dm_dispinfo_t *disp; + int event; + int found; + + disp = (dm_dispinfo_t *)(kbuf + totalsize); + + DMEV_ZERO(disp->di_eventset); + + for (event = 0, found = 0; event < DM_EVENT_MAX; event++) { + if (fsrp->fr_sessp[event] != s) + continue; + DMEV_SET(event, disp->di_eventset); + found++; + } + if (!found) + continue; + + disp->_link = 0; + disp->di_fshandle.vd_offset = sizeof(dm_dispinfo_t); + disp->di_fshandle.vd_length = FSHSIZE; + + bcopy(&fsrp->fr_fsid, + (char *)disp + disp->di_fshandle.vd_offset, + disp->di_fshandle.vd_length); + + if (prevmsg) + prevmsg->_link = msgsize; + + prevmsg = disp; + totalsize += msgsize; + } + mutex_spinunlock(&s->sn_qlock, lc2); /* reverse cookie order */ + mutex_spinunlock(&dm_reg_lock, lc1); + +#ifdef __sgi + if (dm_cpoutsizet(rlenp, totalsize)) { +#else + if (put_user(totalsize, rlenp)) { +#endif + error = EFAULT; + } else if (totalsize > buflen) { /* no more room */ + error = E2BIG; +#ifdef __sgi + } else if (totalsize && copyout(kbuf, bufp, totalsize)) { +#else + } else if (totalsize && copy_to_user(bufp, kbuf, totalsize)) { +#endif + error = EFAULT; + } else { + error = 0; + } + + kmem_free(kbuf, fsyscnt * msgsize); + return(error); +} diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/dmapi_right.c linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_right.c --- linux-2.4.7/linux/fs/xfs/dmapi/dmapi_right.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_right.c Wed Oct 11 10:45:35 2000 @@ -0,0 +1,1251 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include "dmapi_private.h" + + +#define DM_FG_STHREAD 0x001 /* keep other threads from using tdp */ +#define DM_FG_MUSTEXIST 0x002 /* handle must exist in the event */ +#define DM_FG_DONTADD 0x004 /* don't add handle if not in event */ + + + +/* Get a handle of the form (void *, size_t) from user space and convert it to + a handle_t. Do as much validation of the result as possible; any error + other than a bad address should return EBADF per the DMAPI spec. +*/ + +static int +dm_copyin_handle( + void *hanp, /* input, handle data */ + size_t hlen, /* input, size of handle data */ + xfs_handle_t *handlep) /* output, copy of data */ +{ + u_short len; + fid_t *fidp; + + fidp = (fid_t*)&handlep->ha_fid; + + if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep)) + return(EBADF); + +#ifdef __sgi + if (copyin(hanp, handlep, hlen)) + return(EFAULT); +#else + if (copy_from_user(handlep, hanp, hlen)) + return(EFAULT); +#endif + + if (hlen < sizeof(*handlep)) + bzero((char *)handlep + hlen, sizeof(*handlep) - hlen); + + if (hlen == sizeof(handlep->ha_fsid)) + return(0); /* FS handle, nothing more to check */ + + len = hlen - sizeof(handlep->ha_fsid) - sizeof(fidp->fid_len); + + if (fidp->fid_len != len || + *((short *) fidp->fid_data)) { + return(EBADF); + } + return(0); +} + +/* Allocate and initialize a tevp structure. Called from both application and + event threads. +*/ + +static dm_tokevent_t * +dm_init_tevp( + int ev_size, /* size of event structure */ + int var_size) /* size of variable-length data */ +{ + dm_tokevent_t *tevp; + int msgsize; + + /* Calculate the size of the event in bytes and allocate memory for it. + Zero all but the variable portion of the message, which will be + eventually overlaid by the caller with data. + */ + + msgsize = offsetof(dm_tokevent_t, te_event) + ev_size + var_size; + tevp = kmem_alloc(msgsize, KM_SLEEP); + bzero(tevp, msgsize - var_size); + + /* Now initialize all the non-zero fields. */ + + spinlock_init(&tevp->te_lock, "te_lock"); + sv_init(&tevp->te_evt_queue, SV_DEFAULT, "te_evt_queue"); + sv_init(&tevp->te_app_queue, SV_DEFAULT, "te_app_queue"); + tevp->te_allocsize = msgsize; + tevp->te_msg.ev_type = DM_EVENT_INVALID; + + return(tevp); +} + + +/* Given the event type and the number of bytes of variable length data that + will follow the event, dm_evt_create_tevp() creates a dm_tokevent_t + structure to hold the event and initializes all the common event fields. + + No locking is required for this routine because the caller is an event + thread, and is therefore the only thread that can see the event. +*/ + +dm_tokevent_t * +dm_evt_create_tevp( + dm_eventtype_t event, + int variable_size, + void **msgpp) +{ + dm_tokevent_t *tevp; + int evsize; + + switch (event) { + case DM_EVENT_READ: + case DM_EVENT_WRITE: + case DM_EVENT_TRUNCATE: + evsize = sizeof(dm_data_event_t); + break; + + case DM_EVENT_DESTROY: + evsize = sizeof(dm_destroy_event_t); + break; + + case DM_EVENT_MOUNT: + evsize = sizeof(dm_mount_event_t); + break; + + case DM_EVENT_PREUNMOUNT: + case DM_EVENT_UNMOUNT: + case DM_EVENT_NOSPACE: + case DM_EVENT_CREATE: + case DM_EVENT_REMOVE: + case DM_EVENT_RENAME: + case DM_EVENT_SYMLINK: + case DM_EVENT_LINK: + case DM_EVENT_POSTCREATE: + case DM_EVENT_POSTREMOVE: + case DM_EVENT_POSTRENAME: + case DM_EVENT_POSTSYMLINK: + case DM_EVENT_POSTLINK: + case DM_EVENT_ATTRIBUTE: + case DM_EVENT_DEBUT: /* currently not supported */ + case DM_EVENT_CLOSE: /* currently not supported */ + evsize = sizeof(dm_namesp_event_t); + break; + + case DM_EVENT_CANCEL: /* currently not supported */ + evsize = sizeof(dm_cancel_event_t); + break; + + case DM_EVENT_USER: + evsize = 0; + break; + + default: + panic("dm_create_tevp: called with unknown event type %d\n", + event); + } + + /* Allocate and initialize an event structure of the correct size. */ + + tevp = dm_init_tevp(evsize, variable_size); + tevp->te_evt_ref = 1; + + /* Fields ev_token, ev_sequence, and _link are all filled in when the + event is queued onto a session. Initialize all other fields here. + */ + + tevp->te_msg.ev_type = event; + tevp->te_msg.ev_data.vd_offset = offsetof(dm_tokevent_t, te_event) - + offsetof(dm_tokevent_t, te_msg); + tevp->te_msg.ev_data.vd_length = evsize + variable_size; + + /* Give the caller a pointer to the event-specific structure. */ + + *msgpp = ((char *)&tevp->te_msg + tevp->te_msg.ev_data.vd_offset); + return(tevp); +} + + +/* Given a pointer to an event (tevp) and a pointer to a handle_t, look for a + tdp structure within the event which contains the handle_t. Either verify + that the event contains the tdp, or optionally add the tdp to the + event. Called only from application threads. + + On entry, tevp->te_lock is held; it is dropped prior to return. +*/ + +static int +dm_app_lookup_tdp( + xfs_handle_t *handlep, /* the handle we are looking for */ + dm_tokevent_t *tevp, /* the event to search for the handle */ + int *lcp, /* address of active lock cookie */ + short types, /* acceptable object types */ + dm_right_t right, /* minimum right the object must have */ + u_int flags, + dm_tokdata_t **tdpp) /* if ! NULL, pointer to matching tdp */ +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + vnode_t *vp; + int error; + + /* Bump the tevp application reference counter so that the event + can't disappear in case we have to drop the lock for a while. + */ + + tevp->te_app_ref++; + *tdpp = NULL; /* assume failure */ + + for (;;) { + /* Look for a matching tdp in the tevp. */ + + for (tdp = tevp->te_tdp; tdp; tdp = tdp->td_next) { + if (XFS_HANDLE_CMP(&tdp->td_handle, handlep) == 0) + break; + } + + /* If the tdp exists, but either we need single-thread access + to the handle and can't get it, or some other thread already + has single-thread access, then sleep until we can try again. + */ + + if (tdp != NULL && tdp->td_app_ref && + ((flags & DM_FG_STHREAD) || + (tdp->td_flags & DM_TDF_STHREAD))) { + tevp->te_app_slp++; +#ifdef __sgi + sv_wait(&tevp->te_app_queue, PZERO, + &tevp->te_lock, *lcp); +#else + sv_wait(&tevp->te_app_queue, 1, + &tevp->te_lock, *lcp); +#endif + *lcp = mutex_spinlock(&tevp->te_lock); + tevp->te_app_slp--; + continue; + } + + if (tdp != NULL && + (tdp->td_vcount > 0 || tdp->td_flags & DM_TDF_EVTREF)) { + /* We have an existing tdp with a non-zero vnode + reference count. If it's the wrong type, return + an appropriate errno. + */ + + if (!(tdp->td_type & types)) { + mutex_spinunlock(&tevp->te_lock, *lcp); + dm_put_tevp(tevp, NULL); /* no destroy events */ + return(ENOTSUP); + } + + /* If the current access right isn't high enough, + complain. + */ + + if (tdp->td_right < right) { + mutex_spinunlock(&tevp->te_lock, *lcp); + dm_put_tevp(tevp, NULL); /* no destroy events */ + return(EACCES); + } + + /* The handle is acceptable. Increment the tdp + application and vnode references and mark the tdp + as single-threaded if necessary. + */ + + tdp->td_app_ref++; + if (flags & DM_FG_STHREAD) + tdp->td_flags |= DM_TDF_STHREAD; + VN_HOLD(BHV_TO_VNODE(tdp->td_bdp)); + tdp->td_vcount++; + + mutex_spinunlock(&tevp->te_lock, *lcp); + *tdpp = tdp; + return(0); + } + + /* If the tdp is not in the tevp or does not have a vnode + reference, check to make sure it is okay to add/update it. + */ + + if (flags & DM_FG_MUSTEXIST) { + mutex_spinunlock(&tevp->te_lock, *lcp); + dm_put_tevp(tevp, NULL); /* no destroy events */ + return(EACCES); /* i.e. an insufficient right */ + } + if (flags & DM_FG_DONTADD) { + tevp->te_app_ref--; + mutex_spinunlock(&tevp->te_lock, *lcp); + return(0); + } + + /* If a tdp structure doesn't yet exist, create one and link + it into the tevp. Drop the lock while we are doing this as + zallocs can go to sleep. Once we have the memory, make + sure that another thread didn't simultaneously add the same + handle to the same event. If so, toss ours and start over. + */ + + if (tdp == NULL) { + dm_tokdata_t *tmp; + + mutex_spinunlock(&tevp->te_lock, *lcp); + + tdp = kmem_zalloc(sizeof(*tdp), KM_SLEEP); + + *lcp = mutex_spinlock(&tevp->te_lock); + + for (tmp = tevp->te_tdp; tmp; tmp = tmp->td_next) { + if (XFS_HANDLE_CMP(&tmp->td_handle, handlep) == 0) + break; + } + if (tmp) { + kmem_free(tdp, sizeof(*tdp)); + continue; + } + + tdp->td_next = tevp->te_tdp; + tevp->te_tdp = tdp; + tdp->td_tevp = tevp; + tdp->td_handle = *handlep; + } + + /* Temporarily single-thread access to the tdp so that other + threads don't touch it while we are filling the rest of the + fields in. + */ + + tdp->td_app_ref = 1; + tdp->td_flags |= DM_TDF_STHREAD; + + /* Drop the spinlock while we access, validate, and obtain the + proper rights to the object. This can take a very long time + if the vnode is not in memory, if the filesystem is + unmounting, or if the request_right() call should block + because some other tdp or kernel thread is holding a right. + */ + + mutex_spinunlock(&tevp->te_lock, *lcp); + + if ((vp = dm_handle_to_vp(handlep, &tdp->td_type)) == NULL) { + error = EBADF; + } else { + tdp->td_vcount = 1; + tdp->td_bdp = bhv_base_unlocked(VN_BHV_HEAD(vp)); + + /* The handle is usable. Check that the type of the + object matches one of the types that the caller + will accept. + */ + + if (!(types & tdp->td_type)) { + error = ENOTSUP; + } else if (right > DM_RIGHT_NULL) { + /* Attempt to get the rights required by the + caller. If rights can't be obtained, return + an error. + */ + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->request_right(tdp->td_bdp, + DM_RIGHT_NULL, + (tdp->td_type == DM_TDT_VFS ? + DM_FSYS_OBJ : 0), + DM_RR_WAIT, right); + if (!error) { + tdp->td_right = right; + } + } else { + error = 0; + } + } + if (error != 0) { + dm_put_tevp(tevp, tdp); /* destroy event risk, although tiny */ + return(error); + } + + *lcp = mutex_spinlock(&tevp->te_lock); + + /* Wake up any threads which may have seen our tdp while we + were filling it in. + */ + + if (!(flags & DM_FG_STHREAD)) { + tdp->td_flags &= ~DM_TDF_STHREAD; + if (tevp->te_app_slp) + sv_broadcast(&tevp->te_app_queue); + } + + mutex_spinunlock(&tevp->te_lock, *lcp); + *tdpp = tdp; + return(0); + } +} + + +/* dm_app_get_tdp_by_token() is called whenever the application request + contains a session ID and contains a token other than DM_NO_TOKEN. + Most of the callers provide a right that is either DM_RIGHT_SHARED or + DM_RIGHT_EXCL, but a few of the callers such as dm_obj_ref_hold() may + specify a right of DM_RIGHT_NULL. +*/ + +static int +dm_app_get_tdp_by_token( + dm_sessid_t sid, /* an existing session ID */ + void *hanp, + size_t hlen, + dm_token_t token, /* an existing token */ + short types, /* acceptable object types */ + dm_right_t right, /* minimum right the object must have */ + u_int flags, + dm_tokdata_t **tdpp) +{ + dm_tokevent_t *tevp; + xfs_handle_t handle; + int error; + int lc; /* lock cookie */ + + if (right < DM_RIGHT_NULL || right > DM_RIGHT_EXCL) + return(EINVAL); + + if ((error = dm_copyin_handle(hanp, hlen, &handle)) != 0) + return(error); + + /* Find and lock the event which corresponds to the specified + session/token pair. + */ + + if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0) + return(error); + + return(dm_app_lookup_tdp(&handle, tevp, &lc, types, + right, flags, tdpp)); +} + + +/* Function dm_app_get_tdp() must ONLY be called from routines associated with + application calls, e.g. dm_read_invis, dm_set_disp, etc. It must not be + called by a thread responsible for generating an event such as + dm_send_data_event()! + + dm_app_get_tdp() is the interface used by all application calls other than + dm_get_events, dm_respond_event, dm_get_config, dm_get_config_events, and by + the dm_obj_ref_* and dm_*_right families of requests. + + dm_app_get_tdp() converts a sid/hanp/hlen/token quad into a tdp pointer, + increments the number of active application threads in the event, and + increments the number of active application threads using the tdp. The + 'right' parameter must be either DM_RIGHT_SHARED or DM_RIGHT_EXCL. The + token may either be DM_NO_TOKEN, or can be a token received in a synchronous + event. +*/ + +int +dm_app_get_tdp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + short types, + dm_right_t right, /* minimum right */ + dm_tokdata_t **tdpp) +{ + dm_session_t *s; + xfs_handle_t handle; + dm_tokevent_t *tevp; + int error; + int lc; /* lock cookie */ + + ASSERT(right >= DM_RIGHT_SHARED); + + /* If a token other than DM_NO_TOKEN is specified, find the event on + this session which owns the token and increment its reference count. + */ + + if (token != DM_NO_TOKEN) { /* look up existing tokevent struct */ + return(dm_app_get_tdp_by_token(sid, hanp, hlen, token, types, + right, DM_FG_MUSTEXIST, tdpp)); + } + + /* The token is DM_NO_TOKEN. In this case we only want to verify that + the session ID is valid, and do not need to continue holding the + session lock after we know that to be true. + */ + + if ((error = dm_copyin_handle(hanp, hlen, &handle)) != 0) + return(error); + + if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) + return(error); + mutex_spinunlock(&s->sn_qlock, lc); + + /* When DM_NO_TOKEN is used, we simply block until we can obtain the + right that we want (since the tevp contains no tdp structures). + The blocking when we eventually support it will occur within + fsys_vector->request_right(). + */ + + tevp = dm_init_tevp(0, 0); + lc = mutex_spinlock(&tevp->te_lock); + + return(dm_app_lookup_tdp(&handle, tevp, &lc, types, right, 0, tdpp)); +} + + +/* dm_get_config_tdp() is only called by dm_get_config() and + dm_get_config_events(), which neither have a session ID nor a token. + Both of these calls are supposed to work even if the filesystem is in the + process of being mounted, as long as the caller only uses handles within + the mount event. +*/ + +int +dm_get_config_tdp( + void *hanp, + size_t hlen, + dm_tokdata_t **tdpp) +{ + xfs_handle_t handle; + dm_tokevent_t *tevp; + int error; + int lc; /* lock cookie */ + + if ((error = dm_copyin_handle(hanp, hlen, &handle)) != 0) + return(error); + + tevp = dm_init_tevp(0, 0); + lc = mutex_spinlock(&tevp->te_lock); + + /* Try to use the handle provided by the caller and assume DM_NO_TOKEN. + This will fail if the filesystem is in the process of being mounted. + */ + + error = dm_app_lookup_tdp(&handle, tevp, &lc, DM_TDT_ANY, + DM_RIGHT_NULL, 0, tdpp); + + if (!error) { + return(0); + } + + /* Perhaps the filesystem is still mounting, in which case we need to + see if this is one of the handles in the DM_EVENT_MOUNT tevp. + */ + + if ((tevp = dm_find_mount_tevp_and_lock((fsid_t*)&handle.ha_fsid, &lc)) == NULL) + return(EBADF); + + return(dm_app_lookup_tdp(&handle, tevp, &lc, DM_TDT_ANY, + DM_RIGHT_NULL, DM_FG_MUSTEXIST, tdpp)); +} + + +/* dm_put_tdp() is called to release any right held on the vnode, and to + VN_RELE() all references held on the vnode. It is the caller's + responsibility to ensure that no other application threads are using the + tdp, and if necessary to unlink the tdp from the tevp before calling + this routine and to free the tdp afterwards. +*/ + +static void +dm_put_tdp( + dm_tokdata_t *tdp) +{ + ASSERT(tdp->td_app_ref <= 1); + + /* If the application thread is holding a right, or if the event + thread had a right but it has disappeared because of a dm_pending + or Cntl-C, then we need to release it here. + */ + + if (tdp->td_right != DM_RIGHT_NULL) { + dm_fsys_vector_t *fsys_vector; + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + (void)fsys_vector->release_right(tdp->td_bdp, tdp->td_right, + (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0)); + tdp->td_right = DM_RIGHT_NULL; + } + + /* Given that we wouldn't be here if there was still an event thread, + this VN_RELE loop has the potential of generating a DM_EVENT_DESTROY + event if some other thread has unlinked the file. + */ + + while (tdp->td_vcount > 0) { + VN_RELE(BHV_TO_VNODE(tdp->td_bdp)); + tdp->td_vcount--; + } + + tdp->td_flags &= ~(DM_TDF_HOLD|DM_TDF_RIGHT); + tdp->td_bdp = NULL; +} + + +/* Function dm_put_tevp() must ONLY be called from routines associated with + application threads, e.g. dm_read_invis, dm_get_events, etc. It must not be + called by a thread responsible for generating an event, such as + dm_send_data_event. + + PLEASE NOTE: It is possible for this routine to generate DM_EVENT_DESTROY + events, because its calls to dm_put_tdp drop vnode references, and another + thread may have already unlinked a file whose vnode we are de-referencing. + This sets the stage for various types of deadlock if the thread calling + dm_put_tevp is the same thread that calls dm_respond_event! In particular, + the dm_sent_destroy_event routine needs to obtain the dm_reg_lock, + dm_session_lock, and sn_qlock in order to queue the destroy event. No + caller of dm_put_tevp can hold any of these locks! + + Other possible deadlocks are that dm_send_destroy_event could block waiting + for a thread to register for the event using dm_set_disp() and/or + dm_set_return_on_destroy, or it could block because the session's sn_newq + is at the dm_max_queued_msgs event limit. The only safe solution + (unimplemented) is to have a separate kernel thread for each filesystem + whose only job is to do the vnode-dereferencing. That way dm_respond_event + will not block, so the application can keep calling dm_get_events to read + events even if the filesystem thread should block. (If the filesystem + thread blocks, so will all subsequent destroy events for the same + filesystem.) +*/ + +void +dm_put_tevp( + dm_tokevent_t *tevp, + dm_tokdata_t *tdp) +{ + int free_tdp = 0; + int lc; /* lock cookie */ + + lc = mutex_spinlock(&tevp->te_lock); + + if (tdp != NULL) { + if (tdp->td_vcount > 1 || (tdp->td_flags & DM_TDF_EVTREF)) { + ASSERT(tdp->td_app_ref > 0); + + VN_RELE(BHV_TO_VNODE(tdp->td_bdp)); + tdp->td_vcount--; + } else { + ASSERT(tdp->td_app_ref == 1); + + /* The vnode reference count is either already at + zero (e.g. a failed dm_handle_to_vp() call in + dm_app_lookup_tdp()) or is going to zero. We can't + hold the lock while we decrement the count because + we could potentially end up being busy for a long + time in VOP_INACTIVATE. Use single-threading to + lock others out while we clean house. + */ + + tdp->td_flags |= DM_TDF_STHREAD; + + /* WARNING - A destroy event is possible here if we are + giving up the last reference on a vnode which has + been previously unlinked by some other thread! + */ + + mutex_spinunlock(&tevp->te_lock, lc); + dm_put_tdp(tdp); + lc = mutex_spinlock(&tevp->te_lock); + + /* If this tdp is not one of the original tdps in the + event, then remove it from the tevp. + */ + + if (!(tdp->td_flags & DM_TDF_ORIG)) { + dm_tokdata_t **tdpp = &tevp->te_tdp; + + while (*tdpp && *tdpp != tdp) { + tdpp = &(*tdpp)->td_next; + } + if (*tdpp == NULL) { + panic("dm_remove_tdp_from_tevp: tdp " + "%p not in tevp %p\n", tdp, + tevp); + } + *tdpp = tdp->td_next; + free_tdp++; + } + } + + /* If this is the last app thread actively using the tdp, clear + any single-threading and wake up any other app threads who + might be waiting to use this tdp, single-threaded or + otherwise. + */ + + if (--tdp->td_app_ref == 0) { + if (tdp->td_flags & DM_TDF_STHREAD) { + tdp->td_flags &= ~DM_TDF_STHREAD; + if (tevp->te_app_slp) + sv_broadcast(&tevp->te_app_queue); + } + } + + if (free_tdp) { + kmem_free(tdp, sizeof(*tdp)); + } + } + + /* If other application threads are using this token/event, they will + do the cleanup. + */ + + if (--tevp->te_app_ref > 0) { + mutex_spinunlock(&tevp->te_lock, lc); + return; + } + + /* If event generation threads are waiting for this thread to go away, + wake them up and let them do the cleanup. + */ + + if (tevp->te_evt_ref > 0) { + sv_broadcast(&tevp->te_evt_queue); + mutex_spinunlock(&tevp->te_lock, lc); + return; + } + + /* This thread is the last active thread using the token/event. No + lock can be held while we disassemble the tevp because we could + potentially end up being busy for a long time in VOP_INACTIVATE. + */ + + mutex_spinunlock(&tevp->te_lock, lc); + + /* WARNING - One or more destroy events are possible here if we are + giving up references on vnodes which have been previously unlinked + by other kernel threads! + */ + + while ((tdp = tevp->te_tdp) != NULL) { + tevp->te_tdp = tdp->td_next; + dm_put_tdp(tdp); + kmem_free(tdp, sizeof(*tdp)); + } + spinlock_destroy(&tevp->te_lock); + sv_destroy(&tevp->te_evt_queue); + sv_destroy(&tevp->te_app_queue); + kmem_free(tevp, tevp->te_allocsize); +} + + +/* No caller of dm_app_put_tevp can hold either of the locks dm_reg_lock, + dm_session_lock, or any sn_qlock! (See dm_put_tevp for details.) +*/ + +void +dm_app_put_tdp( + dm_tokdata_t *tdp) +{ + dm_put_tevp(tdp->td_tevp, tdp); +} + + +/* dm_change_right is only called if the event thread is the one doing the + cleanup on a completed event. It looks at the current rights of a tdp + and compares that with the rights it had on the tdp when the event was + created. If different, it reaquires the original rights, then transfers + the rights back to being thread-based. +*/ + +static void +dm_change_right( + dm_tokdata_t *tdp) +{ + dm_fsys_vector_t *fsys_vector; + int error; + u_int type; + + /* If the event doesn't have a vnode reference, if the original right + was DM_RIGHT_NULL, or if the rights were never switched from being + thread-based to tdp-based, then there is nothing to do. + */ + + if (!(tdp->td_flags & DM_TDF_EVTREF)) + return; + + if (tdp->td_orig_right == DM_RIGHT_NULL) + return; + + /* DEBUG - Need a check here for event-based rights. */ + + /* If the current right is not the same as it was when the event was + created, first get back the original right. + */ + + if (tdp->td_right != tdp->td_orig_right) { + fsys_vector = dm_fsys_vector(tdp->td_bdp); + type = (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0); + + switch (tdp->td_orig_right) { + case DM_RIGHT_SHARED: + if (tdp->td_right == DM_RIGHT_EXCL) { + error = fsys_vector->downgrade_right( + tdp->td_bdp, tdp->td_right, type); + if (!error) + break; + (void)fsys_vector->release_right(tdp->td_bdp, + tdp->td_right, type); + } + (void)fsys_vector->request_right(tdp->td_bdp, + tdp->td_right, type, DM_RR_WAIT, + tdp->td_orig_right); + break; + + case DM_RIGHT_EXCL: + if (tdp->td_right == DM_RIGHT_SHARED) { + error = fsys_vector->upgrade_right(tdp->td_bdp, + tdp->td_right, type); + if (!error) + break; + (void)fsys_vector->release_right(tdp->td_bdp, + tdp->td_right, type); + } + (void)fsys_vector->request_right(tdp->td_bdp, + tdp->td_right, type, DM_RR_WAIT, + tdp->td_orig_right); + break; + case DM_RIGHT_NULL: + break; + } + } + + /* We now have back the same level of rights as we had when the event + was generated. Now transfer the rights from being tdp-based back + to thread-based. + */ + + /* DEBUG - Add a call here to transfer rights back to thread-based. */ + + /* Finally, update the tdp so that we don't mess with the rights when + we eventually call dm_put_tdp. + */ + + tdp->td_right = DM_RIGHT_NULL; +} + + +/* This routine is only called by event threads. The calls to dm_put_tdp + are not a deadlock risk here because this is an event thread, and it is + okay for such a thread to block on an induced destroy event. Okay, maybe + there is a slight risk; say that the event contains three vnodes all of + which have DM_RIGHT_EXCL, and say that we are at the dm_max_queued_msgs + limit, and that the first vnode is already unlinked. In that case the + destroy event will block waiting to be queued, and the application thread + could happen to reference one of the other locked vnodes. Deadlock. +*/ + +void +dm_evt_rele_tevp( + dm_tokevent_t *tevp, + int droprights) /* non-zero, evt thread loses rights */ +{ + dm_tokdata_t *tdp; + int lc; /* lock cookie */ + + lc = mutex_spinlock(&tevp->te_lock); + + /* If we are here without DM_TEF_FINAL set and with at least one + application reference still remaining, then one of several + possibilities is true: + 1. This is an asynchronous event which has been queued but has not + yet been delivered, or which is in the process of being delivered. + 2. This is an unmount event (pseudo-asynchronous) yet to be + delivered or in the process of being delivered. + 3. This event had DM_FLAGS_NDELAY specified, and the application + has sent a dm_pending() reply for the event. + 4. This is a DM_EVENT_READ, DM_EVENT_WRITE, or DM_EVENT_TRUNCATE + event and the user typed a Cntl-C. + In all of these cases, the correct behavior is to leave the + responsibility of releasing any rights to the application threads + when they are done. + */ + + if (tevp->te_app_ref > 0 && !(tevp->te_flags & DM_TEF_FINAL)) { + tevp->te_evt_ref--; + for (tdp = tevp->te_tdp; tdp; tdp = tdp->td_next) { + if (tdp->td_flags & DM_TDF_EVTREF) { + tdp->td_flags &= ~DM_TDF_EVTREF; + if (tdp->td_vcount == 0) + tdp->td_bdp = NULL; + } + } + mutex_spinunlock(&tevp->te_lock, lc); + return; /* not the last thread */ + } + + /* If the application reference count is non-zero here, that can only + mean that dm_respond_event() has been called, but the application + still has one or more threads in the kernel that haven't let go of + the tevp. In these cases, the event thread must wait until all + application threads have given up their references, and their + rights to handles within the event. + */ + + while (tevp->te_app_ref) { +#ifdef __sgi + sv_wait(&tevp->te_evt_queue, PZERO, &tevp->te_lock, lc); +#else + sv_wait(&tevp->te_evt_queue, 1, &tevp->te_lock, lc); +#endif + lc = mutex_spinlock(&tevp->te_lock); + } + + /* This thread is the last active thread using the token/event. Reset + the rights of any vnode that was part of the original event back + to their initial values before returning to the filesystem. The + exception is if the event failed (droprights is non-zero), in which + case we chose to return to the filesystem with all rights released. + Release the rights on any vnode that was not part of the original + event. Give up all remaining application vnode references + regardless of whether or not the vnode was part of the original + event. + */ + + mutex_spinunlock(&tevp->te_lock, lc); + + while ((tdp = tevp->te_tdp) != NULL) { + tevp->te_tdp = tdp->td_next; + if ((tdp->td_flags & DM_TDF_ORIG) && + (tdp->td_flags & DM_TDF_EVTREF) && + (!droprights)) { + dm_change_right(tdp); + } + dm_put_tdp(tdp); + kmem_free(tdp, sizeof(*tdp)); + } + spinlock_destroy(&tevp->te_lock); + sv_destroy(&tevp->te_evt_queue); + sv_destroy(&tevp->te_app_queue); + kmem_free(tevp, tevp->te_allocsize); +} + + +/* dm_obj_ref_hold() is just a fancy way to get a vnode reference on an object + to hold it in kernel memory. +*/ + +int +dm_obj_ref_hold( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen) +{ + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_NULL, DM_FG_STHREAD, &tdp); + + /* The tdp is single-threaded, so no mutex lock needed for update. */ + + if (error == 0) { + if (tdp->td_flags & DM_TDF_HOLD) { /* if already held */ + error = EBUSY; + } else { + tdp->td_flags |= DM_TDF_HOLD; + VN_HOLD(BHV_TO_VNODE(tdp->td_bdp)); + tdp->td_vcount++; + } + dm_app_put_tdp(tdp); + } + return(error); +} + + +int +dm_obj_ref_rele( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen) +{ + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_NULL, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp); + + /* The tdp is single-threaded, so no mutex lock needed for update. */ + + if (error == 0) { + if (!(tdp->td_flags & DM_TDF_HOLD)) { /* if not held */ + error = EACCES; /* use the DM_FG_MUSTEXIST errno */ + } else { + tdp->td_flags &= ~DM_TDF_HOLD; + VN_RELE(BHV_TO_VNODE(tdp->td_bdp)); + tdp->td_vcount--; + } + dm_app_put_tdp(tdp); + } + return(error); +} + + +int +dm_obj_ref_query_rvp( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen, + int *rvp) +{ + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_VNO, + DM_RIGHT_NULL, DM_FG_DONTADD|DM_FG_STHREAD, &tdp); + if (error != 0) + return(error); + + /* If the request is valid but the handle just isn't present in the + event or the hold flag isn't set, return zero, else return one. + */ + + if (tdp) { + if (tdp->td_flags & DM_TDF_HOLD) { /* if held */ + *rvp = 1; + } else { + *rvp = 0; + } + dm_app_put_tdp(tdp); + } else { + *rvp = 0; + } + return(0); +} + + +int +dm_downgrade_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY, + DM_RIGHT_EXCL, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp); + if (error != 0) + return(error); + + /* Attempt the downgrade. Filesystems which support rights but not + the downgrading of rights will return ENOSYS. + */ + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->downgrade_right(tdp->td_bdp, tdp->td_right, + (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0)); + + /* The tdp is single-threaded, so no mutex lock needed for update. */ + + if (error == 0) + tdp->td_right = DM_RIGHT_SHARED; + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_query_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_right_t *rightp) +{ + dm_tokdata_t *tdp; + dm_right_t right; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY, + DM_RIGHT_NULL, DM_FG_DONTADD|DM_FG_STHREAD, &tdp); + if (error != 0) + return(error); + + /* Get the current right and copy it to the caller. The tdp is + single-threaded, so no mutex lock is needed. If the tdp is not in + the event we are supposed to return DM_RIGHT_NULL in order to be + compatible with Veritas. + */ + + if (tdp) { + right = tdp->td_right; + dm_app_put_tdp(tdp); + } else { + right = DM_RIGHT_NULL; + } +#ifdef __sgi + if (copyout(&right, rightp, sizeof(right))) + return(EFAULT); +#else + if (copy_to_user(rightp, &right, sizeof(right))) + return(EFAULT); +#endif + return(0); +} + + +int +dm_release_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY, + DM_RIGHT_SHARED, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->release_right(tdp->td_bdp, tdp->td_right, + (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0)); + + /* The tdp is single-threaded, so no mutex lock needed for update. */ + + if (error == 0) { + tdp->td_right = DM_RIGHT_NULL; + if (tdp->td_flags & DM_TDF_RIGHT) { + tdp->td_flags &= ~DM_TDF_RIGHT; + VN_RELE(BHV_TO_VNODE(tdp->td_bdp)); + tdp->td_vcount--; + } + } + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_request_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + u_int flags, + dm_right_t right) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY, + DM_RIGHT_NULL, DM_FG_STHREAD, &tdp); + if (error != 0) + return(error); + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->request_right(tdp->td_bdp, tdp->td_right, + (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0), flags, right); + + /* The tdp is single-threaded, so no mutex lock is needed for update. + + If this is the first dm_request_right call for this vnode, then we + need to bump the vnode reference count for two reasons. First of + all, it is supposed to be impossible for the file to disappear or + for the filesystem to be unmounted while a right is held on a file; + bumping the file's vnode reference count ensures this. Second, if + rights are ever actually implemented, it will most likely be done + without changes to the on-disk inode, which means that we can't let + the vnode become unreferenced while a right on it is held. + */ + + if (error == 0) { + if (!(tdp->td_flags & DM_TDF_RIGHT)) { /* if first call */ + tdp->td_flags |= DM_TDF_RIGHT; + VN_HOLD(BHV_TO_VNODE(tdp->td_bdp)); + tdp->td_vcount++; + } + tdp->td_right = right; + } + + dm_app_put_tdp(tdp); + return(error); +} + + +int +dm_upgrade_right( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token) +{ + dm_fsys_vector_t *fsys_vector; + dm_tokdata_t *tdp; + int error; + + error = dm_app_get_tdp_by_token(sid, hanp, hlen, token, DM_TDT_ANY, + DM_RIGHT_SHARED, DM_FG_MUSTEXIST|DM_FG_STHREAD, &tdp); + if (error != 0) + return(error); + + /* If the object already has the DM_RIGHT_EXCL right, no need to + attempt an upgrade. + */ + + if (tdp->td_right == DM_RIGHT_EXCL) { + dm_app_put_tdp(tdp); + return(0); + } + + /* Attempt the upgrade. Filesystems which support rights but not + the upgrading of rights will return ENOSYS. + */ + + fsys_vector = dm_fsys_vector(tdp->td_bdp); + error = fsys_vector->upgrade_right(tdp->td_bdp, tdp->td_right, + (tdp->td_type == DM_TDT_VFS ? DM_FSYS_OBJ : 0)); + + /* The tdp is single-threaded, so no mutex lock needed for update. */ + + if (error == 0) + tdp->td_right = DM_RIGHT_EXCL; + + dm_app_put_tdp(tdp); + return(error); +} diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/dmapi_session.c linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_session.c --- linux-2.4.7/linux/fs/xfs/dmapi/dmapi_session.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_session.c Wed Jun 6 16:08:08 2001 @@ -0,0 +1,1582 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifdef __sgi + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#else + +#include + +#endif + +#include "dmapi_private.h" + +dm_session_t *dm_sessions = NULL; /* head of session list */ +u_int dm_sessions_active = 0; /* # sessions currently active */ +dm_sessid_t dm_next_sessid = 1; /* next session ID to use */ +lock_t dm_session_lock; /* lock for session list */ + +dm_token_t dm_next_token = 1; /* next token ID to use */ +dm_sequence_t dm_next_sequence = 1; /* next sequence number to use */ +lock_t dm_token_lock; /* dm_next_token/dm_next_sequence lock */ + +int dm_max_queued_msgs = 2048; /* max # undelivered msgs/session */ + +#ifdef __sgi +int dm_hash_buckets = 1009; /* prime -- number of buckets */ + +/* XXX floating point not allowed in Linux kernel. */ +#define DM_SHASH(sess,inodenum) ((sess)->sn_sesshash + \ + ((inodenum) % dm_hash_buckets)) +#endif + + +#ifdef linux +void +dm_init(void) +{ + spinlock_init(&dm_session_lock, "dm_session_lock"); + spinlock_init(&dm_token_lock, "dm_token_lock"); + spinlock_init(&dm_reg_lock, "dm_reg_lock"); +} + +/* Returns 0 if dmapi is not busy. */ +int +dm_uninit(void) +{ + extern int dm_fsys_cnt; + int busy = 0; + + if( spin_is_locked(&dm_session_lock) ){ + printk(KERN_ERR "dm_uninit: attempt to unload while dm_session_lock is held\n"); + busy=1; + } + if( spin_is_locked(&dm_token_lock) ){ + printk(KERN_ERR "dm_uninit: attempt to unload while dm_token_lock is held\n"); + busy=1; + } + if( spin_is_locked(&dm_reg_lock) ){ + printk(KERN_ERR "dm_uninit: attempt to unload while dm_reg_lock is held\n"); + busy=1; + } + if(dm_sessions_active){ + printk(KERN_ERR "dm_uninit: attempt to unload while there are active sessions\n"); + busy=1; + } + if(dm_fsys_cnt){ + printk(KERN_ERR "dm_uninit: attempt to unload while there are filesystems registered.\n"); + busy=1; + } + + if(!busy) { + spinlock_destroy(&dm_session_lock); + spinlock_destroy(&dm_token_lock); + spinlock_destroy(&dm_reg_lock); + } + + return(busy); +} +#endif + + +/* Link a session to the end of the session list. New sessions are always + added at the end of the list so that dm_enqueue_mount_event() doesn't + miss a session. The caller must have obtained dm_session_lock before + calling this routine. +*/ + +static void +link_session( + dm_session_t *s) +{ + dm_session_t *tmp; + + if ((tmp = dm_sessions) == NULL) { + dm_sessions = s; + } else { + while (tmp->sn_next != NULL) + tmp = tmp->sn_next; + tmp->sn_next = s; + } + s->sn_next = NULL; + dm_sessions_active++; +} + + +/* Remove a session from the session list. The caller must have obtained + dm_session_lock before calling this routine. unlink_session() should only + be used in situations where the session is known to be on the dm_sessions + list; otherwise it panics. +*/ + +static void +unlink_session( + dm_session_t *s) +{ + dm_session_t *tmp; + + if (dm_sessions == s) { + dm_sessions = dm_sessions->sn_next; + } else { + for (tmp = dm_sessions; tmp; tmp = tmp->sn_next) { + if (tmp->sn_next == s) + break; + } + if (tmp == NULL) { + panic("unlink_session: corrupt DMAPI session list, " + "dm_sessions %p, session %p\n", + dm_sessions, s); + } + tmp->sn_next = s->sn_next; + } + s->sn_next = NULL; + dm_sessions_active--; +} + + +/* Link an event to the end of an event queue. The caller must have obtained + the session's sn_qlock before calling this routine. +*/ + +static void +link_event( + dm_tokevent_t *tevp, + dm_eventq_t *queue) +{ + if (queue->eq_tail) { + queue->eq_tail->te_next = tevp; + queue->eq_tail = tevp; + } else { + queue->eq_head = queue->eq_tail = tevp; + } + tevp->te_next = NULL; + queue->eq_count++; +} + + +/* Remove an event from an event queue. The caller must have obtained the + session's sn_qlock before calling this routine. unlink_event() should + only be used in situations where the event is known to be on the queue; + otherwise it panics. +*/ + +static void +unlink_event( + dm_tokevent_t *tevp, + dm_eventq_t *queue) +{ + dm_tokevent_t *tmp; + + if (queue->eq_head == tevp) { + queue->eq_head = tevp->te_next; + if (queue->eq_head == NULL) + queue->eq_tail = NULL; + } else { + tmp = queue->eq_head; + while (tmp && tmp->te_next != tevp) + tmp = tmp->te_next; + if (tmp == NULL) { + panic("unlink_event: corrupt DMAPI queue %p, " + "tevp %p\n", queue, tevp); + } + tmp->te_next = tevp->te_next; + if (tmp->te_next == NULL) + queue->eq_tail = tmp; + } + tevp->te_next = NULL; + queue->eq_count--; +} + +/* Link a regular file event to a hash bucket. The caller must have obtained + the session's sn_qlock before calling this routine. + The tokevent must be for a regular file object--DM_TDT_REG. +*/ + +#ifdef __sgi +static void +hash_event( + dm_session_t *s, + dm_tokevent_t *tevp) +{ + dm_sesshash_t *sh; + xfs_ino_t ino; + + if (s->sn_sesshash == NULL) + s->sn_sesshash = kmem_zalloc(dm_hash_buckets * sizeof(dm_sesshash_t), KM_SLEEP); + + ino = ((xfs_fid2_t*)&tevp->te_tdp->td_handle.ha_fid)->fid_ino; + sh = DM_SHASH(s, ino); + +#ifdef DM_SHASH_DEBUG + if (sh->h_next == NULL) { + s->sn_buckets_in_use++; + if (s->sn_buckets_in_use > s->sn_max_buckets_in_use) + s->sn_max_buckets_in_use++; + } + sh->maxlength++; + sh->curlength++; + sh->num_adds++; +#endif + + tevp->te_flags |= DM_TEF_HASHED; + tevp->te_hashnext = sh->h_next; + sh->h_next = tevp; +} +#endif + + +/* Remove a regular file event from a hash bucket. The caller must have + obtained the session's sn_qlock before calling this routine. + The tokevent must be for a regular file object--DM_TDT_REG. +*/ + +#ifdef __sgi +static void +unhash_event( + dm_session_t *s, + dm_tokevent_t *tevp) +{ + dm_sesshash_t *sh; + dm_tokevent_t *tmp; + xfs_ino_t ino; + + if (s->sn_sesshash == NULL) + return; + + ino = ((xfs_fid2_t*)&tevp->te_tdp->td_handle.ha_fid)->fid_ino; + sh = DM_SHASH(s, ino); + + if (sh->h_next == tevp) { + sh->h_next = tevp->te_hashnext; /* leap frog */ + } else { + tmp = sh->h_next; + while (tmp->te_hashnext != tevp) { + tmp = tmp->te_hashnext; + } + tmp->te_hashnext = tevp->te_hashnext; /* leap frog */ + } + tevp->te_hashnext = NULL; + tevp->te_flags &= ~DM_TEF_HASHED; + +#ifdef DM_SHASH_DEBUG + if (sh->h_next == NULL) + s->sn_buckets_in_use--; + sh->curlength--; + sh->num_dels++; +#endif +} +#endif + + +/* Determine if this is a repeat event. The caller MUST be holding + the session lock. + The tokevent must be for a regular file object--DM_TDT_REG. + Returns: + 0 == match not found + 1 == match found +*/ + +#ifdef __sgi +static int +repeated_event( + dm_session_t *s, + dm_tokevent_t *tevp) +{ + dm_sesshash_t *sh; + dm_data_event_t *d_event1; + dm_data_event_t *d_event2; + dm_tokevent_t *tevph; + xfs_ino_t ino1; + xfs_ino_t ino2; + + if ((!s->sn_newq.eq_tail) && (!s->sn_delq.eq_tail)) { + return(0); + } + if (s->sn_sesshash == NULL) { + return(0); + } + + ino1 = ((xfs_fid2_t*)&tevp->te_tdp->td_handle.ha_fid)->fid_ino; + sh = DM_SHASH(s, ino1); + + if (sh->h_next == NULL) { + /* bucket is empty, no match here */ + return(0); + } + + d_event1 = (dm_data_event_t *)((char *)&tevp->te_msg + tevp->te_msg.ev_data.vd_offset); + tevph = sh->h_next; + while (tevph) { + /* find something with the same event type and handle type */ + if ((tevph->te_msg.ev_type == tevp->te_msg.ev_type) && + (tevph->te_tdp->td_type == tevp->te_tdp->td_type)) { + + ino2 = ((xfs_fid2_t*)&tevp->te_tdp->td_handle.ha_fid)->fid_ino; + d_event2 = (dm_data_event_t *)((char *)&tevph->te_msg + tevph->te_msg.ev_data.vd_offset); + + /* If the two events are operating on the same file, + and the same part of that file, then we have a + match. + */ + if ((ino1 == ino2) && + (d_event2->de_offset == d_event1->de_offset) && + (d_event2->de_length == d_event1->de_length)) { + /* found a match */ +#ifdef DM_SHASH_DEBUG + sh->dup_hits++; +#endif + return(1); + } + } + tevph = tevph->te_hashnext; + } + + /* No match found */ + return(0); +} +#endif + + +/* Return a pointer to a session given its session ID, or EINVAL if no session + has the session ID (per the DMAPI spec). The caller must have obtained + dm_session_lock before calling this routine. +*/ + +static int +dm_find_session( + dm_sessid_t sid, + dm_session_t **sessionpp) +{ + dm_session_t *s; + + for (s = dm_sessions; s; s = s->sn_next) { + if (s->sn_sessid == sid) { + *sessionpp = s; + return(0); + } + } + return(EINVAL); +} + + +/* Return a pointer to a locked session given its session ID. '*lcp' is + used to obtain the session's sn_qlock. Caller is responsible for eventually + unlocking it. +*/ + +int +dm_find_session_and_lock( + dm_sessid_t sid, + dm_session_t **sessionpp, + int *lcp) /* addr of returned lock cookie */ +{ + int error; + + for (;;) { + *lcp = mutex_spinlock(&dm_session_lock); + + if ((error = dm_find_session(sid, sessionpp)) != 0) { + mutex_spinunlock(&dm_session_lock, *lcp); + return(error); + } + if (nested_spintrylock(&(*sessionpp)->sn_qlock)) { + nested_spinunlock(&dm_session_lock); + return(0); /* success */ + } + + /* If the second lock is not available, drop the first and + start over. This gives the CPU a chance to process any + interrupts, and also allows processes which want a sn_qlock + for a different session to proceed. + */ + + mutex_spinunlock(&dm_session_lock, *lcp); + } +} + + +/* Return a pointer to the event on the specified session's sn_delq which + contains the given token. The caller must have obtained the session's + sn_qlock before calling this routine. +*/ + +static int +dm_find_msg( + dm_session_t *s, + dm_token_t token, + dm_tokevent_t **tevpp) +{ + dm_tokevent_t *tevp; + + if (token <= DM_INVALID_TOKEN) + return(EINVAL); + + for (tevp = s->sn_delq.eq_head; tevp; tevp = tevp->te_next) { + if (tevp->te_msg.ev_token == token) { + *tevpp = tevp; + return(0); + } + } + return(ESRCH); +} + + +/* Given a session ID and token, find the tevp on the specified session's + sn_delq which corresponds to that session ID/token pair. If a match is + found, lock the tevp's te_lock and return a pointer to the tevp. + '*lcp' is used to obtain the tevp's te_lock. The caller is responsible + for eventually unlocking it. +*/ + +int +dm_find_msg_and_lock( + dm_sessid_t sid, + dm_token_t token, + dm_tokevent_t **tevpp, + int *lcp) /* address of returned lock cookie */ +{ + dm_session_t *s; + int error; + + if ((error = dm_find_session_and_lock(sid, &s, lcp)) != 0) + return(error); + + if ((error = dm_find_msg(s, token, tevpp)) != 0) { + mutex_spinunlock(&s->sn_qlock, *lcp); + return(error); + } + nested_spinlock(&(*tevpp)->te_lock); + nested_spinunlock(&s->sn_qlock); + return(0); +} + + +/* Create a new session, or resume an old session if one is given. */ + +int +dm_create_session( + dm_sessid_t old, + char *info, + dm_sessid_t *new) +{ + dm_session_t *s; + dm_sessid_t sid; + char sessinfo[DM_SESSION_INFO_LEN]; + size_t len; + int error; + int lc; /* lock cookie */ + +#ifdef __sgi + if (copyinstr(info, sessinfo, DM_SESSION_INFO_LEN, &len)) + return(EFAULT); +#else + len = strnlen_user(info, DM_SESSION_INFO_LEN-1); + if (copy_from_user(sessinfo, info, len)) + return(EFAULT); +#endif + lc = mutex_spinlock(&dm_session_lock); + sid = dm_next_sessid++; + mutex_spinunlock(&dm_session_lock, lc); +#ifdef __sgi + if (copyout(&sid, new, sizeof(sid))) + return(EFAULT); +#else + if (copy_to_user(new, &sid, sizeof(sid))) + return(EFAULT); +#endif + + if (old == DM_NO_SESSION) { + s = kmem_zalloc(sizeof(*s), KM_SLEEP); + sv_init(&s->sn_readerq, SV_DEFAULT, "dmreadq"); + sv_init(&s->sn_writerq, SV_DEFAULT, "dmwritq"); + spinlock_init(&s->sn_qlock, "sn_qlock"); + lc = mutex_spinlock(&dm_session_lock); + } else { + lc = mutex_spinlock(&dm_session_lock); + if ((error = dm_find_session(old, &s)) != 0) { + mutex_spinunlock(&dm_session_lock, lc); + return(error); + } + unlink_session(s); + } + bcopy(sessinfo, s->sn_info, len); + s->sn_info[len-1] = 0; /* if not NULL, then now 'tis */ + s->sn_sessid = sid; + link_session(s); + mutex_spinunlock(&dm_session_lock, lc); + return(0); +} + + +int +dm_destroy_session( + dm_sessid_t sid) +{ + dm_session_t *s; + int error; + int lc; /* lock cookie */ + + /* The dm_session_lock must be held until the session is unlinked. */ + + lc = mutex_spinlock(&dm_session_lock); + + if ((error = dm_find_session(sid, &s)) != 0) { + mutex_spinunlock(&dm_session_lock, lc); + return(error); + } + nested_spinlock(&s->sn_qlock); + + /* The session exists. Check to see if it is still in use. If any + messages still exist on the sn_newq or sn_delq, or if any processes + are waiting for messages to arrive on the session, then the session + must not be destroyed. + */ + + if (s->sn_newq.eq_head || s->sn_readercnt || s->sn_delq.eq_head) { + nested_spinunlock(&s->sn_qlock); + mutex_spinunlock(&dm_session_lock, lc); + return(EBUSY); + } + + /* The session is not in use. Dequeue it from the session chain. */ + + unlink_session(s); + nested_spinunlock(&s->sn_qlock); + mutex_spinunlock(&dm_session_lock, lc); + + /* Now clear the sessions's disposition registration, and then destroy + the session structure. + */ + + dm_clear_fsreg(s); + + spinlock_destroy(&s->sn_qlock); + sv_destroy(&s->sn_readerq); + sv_destroy(&s->sn_writerq); +#ifdef __sgi + if (s->sn_sesshash) + kmem_free(s->sn_sesshash, dm_hash_buckets * sizeof(dm_sesshash_t)); +#endif + kmem_free(s, sizeof *s); + return(0); +} + + +/* + * Return a list of all active sessions. + */ + +int +dm_getall_sessions( + u_int nelem, + dm_sessid_t *sidp, + u_int *nelemp) +{ + dm_session_t *s; + u_int sesscnt; + dm_sessid_t *sesslist; + int lc; /* lock cookie */ + int error; + int i; + + /* Loop until we can get the right amount of temp space, being careful + not to hold a mutex during the allocation. Usually only one trip. + */ + + for (;;) { + if ((sesscnt = dm_sessions_active) == 0) { + /*if (suword(nelemp, 0))*/ + if (put_user(0, nelemp)) + return(EFAULT); + return(0); + } + sesslist = kmem_alloc(sesscnt * sizeof(*sidp), KM_SLEEP); + + lc = mutex_spinlock(&dm_session_lock); + if (sesscnt == dm_sessions_active) + break; + + mutex_spinunlock(&dm_session_lock, lc); + kmem_free(sesslist, sesscnt * sizeof(*sidp)); + } + + /* Make a temp copy of the data, then release the mutex. */ + + for (i = 0, s = dm_sessions; i < sesscnt; i++, s = s->sn_next) + sesslist[i] = s->sn_sessid; + + mutex_spinunlock(&dm_session_lock, lc); + + /* Now copy the data to the user. */ + + if(put_user(sesscnt, nelemp)) { + error = EFAULT; + } else if (sesscnt > nelem) { + error = E2BIG; + } else if (copy_to_user(sidp, sesslist, sesscnt * sizeof(*sidp))) { + error = EFAULT; + } else { + error = 0; + } + kmem_free(sesslist, sesscnt * sizeof(*sidp)); + return(error); +} + + +/* + * Return the descriptive string associated with a session. + */ + +int +dm_query_session( + dm_sessid_t sid, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_session_t *s; /* pointer to session given by sid */ + int len; /* length of session info string */ + int error; + char sessinfo[DM_SESSION_INFO_LEN]; + int lc; /* lock cookie */ + + if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) + return(error); + + len = strlen(s->sn_info) + 1; /* NULL terminated when created */ + bcopy(s->sn_info, sessinfo, len); + + mutex_spinunlock(&s->sn_qlock, lc); + + /* Now that the mutex is released, copy the sessinfo to the user. */ + + if (put_user(len, rlenp)) { + error = EFAULT; + } else if (len > buflen) { + error = E2BIG; +#ifdef __sgi + } else if (copyout(sessinfo, bufp, len)) { +#else + } else if (copy_to_user(bufp, sessinfo, len)) { +#endif + error = EFAULT; + } else { + error = 0; + } + return(error); +} + + +/* + * Return all of the previously delivered tokens (that is, their IDs) + * for the given session. + */ + +int +dm_getall_tokens( + dm_sessid_t sid, /* session obtaining tokens from */ + u_int nelem, /* size of tokenbufp */ + dm_token_t *tokenbufp, /* buffer to copy token IDs to */ + u_int *nelemp) /* return number copied to tokenbufp */ +{ + dm_session_t *s; /* pointer to session given by sid */ + dm_tokevent_t *tevp; /* event message queue traversal */ + int lc; /* lock cookie */ + int tokcnt; + dm_token_t *toklist; + int error; + int i; + + /* Loop until we can get the right amount of temp space, being careful + not to hold a mutex during the allocation. Usually only one trip. + */ + + for (;;) { + if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) + return(error); + tokcnt = s->sn_delq.eq_count; + mutex_spinunlock(&s->sn_qlock, lc); + + if (tokcnt == 0) { + /*if (suword(nelemp, 0))*/ + if (put_user(0, nelemp)) + return(EFAULT); + return(0); + } + toklist = kmem_alloc(tokcnt * sizeof(*tokenbufp), KM_SLEEP); + + if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) { + kmem_free(toklist, tokcnt * sizeof(*tokenbufp)); + return(error); + } + + if (tokcnt == s->sn_delq.eq_count) + break; + + mutex_spinunlock(&s->sn_qlock, lc); + kmem_free(toklist, tokcnt * sizeof(*tokenbufp)); + } + + /* Make a temp copy of the data, then release the mutex. */ + + tevp = s->sn_delq.eq_head; + for (i = 0; i < tokcnt; i++, tevp = tevp->te_next) + toklist[i] = tevp->te_msg.ev_token; + + mutex_spinunlock(&s->sn_qlock, lc); + + /* Now copy the data to the user. */ + +#ifdef __sgi + if (suword(nelemp, tokcnt)) { +#else + if (put_user(tokcnt, nelemp)) { +#endif + error = EFAULT; + } else if (tokcnt > nelem) { + error = E2BIG; +#ifdef __sgi + } else if (copyout(toklist, tokenbufp, tokcnt * sizeof(*tokenbufp))) { +#else + } else if (copy_to_user(tokenbufp,toklist,tokcnt*sizeof(*tokenbufp))) { +#endif + error = EFAULT; + } else { + error = 0; + } + kmem_free(toklist, tokcnt * sizeof(*tokenbufp)); + return(error); +} + + +/* + * Return the message identified by token. + */ + +int +dm_find_eventmsg( + dm_sessid_t sid, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_tokevent_t *tevp; /* message identified by token */ + int msgsize; /* size of message to copy out */ + void *msg; + int error; + int lc; /* lock cookie */ + + /* Because some of the events (dm_data_event_t in particular) contain + __u64 fields, we need to make sure that the buffer provided by the + caller is aligned such that he can read those fields successfully. + */ + + if (((__psint_t)bufp & (sizeof(__u64) - 1)) != 0) + return(EFAULT); + + /* Allocate the right amount of temp space, being careful not to hold + a mutex during the allocation. + */ + + if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0) + return(error); + msgsize = tevp->te_allocsize - offsetof(dm_tokevent_t, te_msg); + mutex_spinunlock(&tevp->te_lock, lc); + + msg = kmem_alloc(msgsize, KM_SLEEP); + + if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0) { + kmem_free(msg, msgsize); + return(error); + } + + /* Make a temp copy of the data, then release the mutex. */ + + bcopy(&tevp->te_msg, msg, msgsize); + mutex_spinunlock(&tevp->te_lock, lc); + + /* Now copy the data to the user. */ + +#ifdef __sgi + if (dm_cpoutsizet(rlenp, msgsize)) { +#else + if (put_user(msgsize,rlenp)) { +#endif + error = EFAULT; + } else if (msgsize > buflen) { /* user buffer not big enough */ + error = E2BIG; +#ifdef __sgi + } else if (copyout(msg, bufp, msgsize)) { +#else + } else if (copy_to_user( bufp, msg, msgsize )) { +#endif + error = EFAULT; + } else { + error = 0; + } + kmem_free(msg, msgsize); + return(error); +} + + +int +dm_move_event( + dm_sessid_t srcsid, + dm_token_t token, + dm_sessid_t targetsid, + dm_token_t *rtokenp) +{ + dm_session_t *s1; + dm_session_t *s2; + dm_tokevent_t *tevp; + int error; + int lc; /* lock cookie */ + int hash_it; + + lc = mutex_spinlock(&dm_session_lock); + + if ((error = dm_find_session(srcsid, &s1)) != 0 || + (error = dm_find_session(targetsid, &s2)) != 0 || + (error = dm_find_msg(s1, token, &tevp)) != 0) { + mutex_spinunlock(&dm_session_lock, lc); + return(error); + } + unlink_event(tevp, &s1->sn_delq); +#ifdef __sgi + if (tevp->te_flags & DM_TEF_HASHED) { + unhash_event(s1, tevp); + hash_it = 1; + } +#endif + link_event(tevp, &s2->sn_delq); +#ifdef __sgi + if (hash_it) + hash_event(s2, tevp); +#endif + mutex_spinunlock(&dm_session_lock, lc); + +#ifdef __sgi + if (copyout(&token, rtokenp, sizeof(token))) + return(EFAULT); +#else + if (copy_to_user(rtokenp, &token, sizeof(token))) + return(EFAULT); +#endif + return(0); +} + + +/* ARGSUSED */ +int +dm_pending( + dm_sessid_t sid, + dm_token_t token, + dm_timestruct_t *delay) /* unused */ +{ + dm_tokevent_t *tevp; + int error; + int lc; /* lock cookie */ + + if ((error = dm_find_msg_and_lock(sid, token, &tevp, &lc)) != 0) + return(error); + + tevp->te_flags |= DM_TEF_INTERMED; + if (tevp->te_evt_ref > 0) /* if event generation threads exist */ + sv_broadcast(&tevp->te_evt_queue); + + mutex_spinunlock(&tevp->te_lock, lc); + return(0); +} + + +int +dm_get_events( + dm_sessid_t sid, + u_int maxmsgs, + u_int flags, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_session_t *s; /* pointer to session given by sid */ + dm_tokevent_t *tevp; /* next event message on queue */ + int error; + int lc1; /* first lock cookie */ + int lc2; /* second lock cookie */ + int totalsize; + int msgsize; + dm_eventmsg_t *prevmsg; + int prev_msgsize; + u_int msgcnt; + + /* Because some of the events (dm_data_event_t in particular) contain + __u64 fields, we need to make sure that the buffer provided by the + caller is aligned such that he can read those fields successfully. + */ + + if (((__psint_t)bufp & (sizeof(__u64) - 1)) != 0) + return(EFAULT); + + /* Find the indicated session and lock it. */ + + if ((error = dm_find_session_and_lock(sid, &s, &lc1)) != 0) + return(error); + + /* Check for messages on sn_newq. If there aren't any that haven't + already been grabbed by another process, and if we are supposed to + to wait until one shows up, then go to sleep interruptibly on the + sn_readerq semaphore. The session can't disappear out from under + us as long as sn_readerq is non-zero. + */ + + for (;;) { + int rc; + + for (tevp = s->sn_newq.eq_head; tevp; tevp = tevp->te_next) { + lc2 = mutex_spinlock(&tevp->te_lock); + if (!(tevp->te_flags & DM_TEF_LOCKED)) + break; + mutex_spinunlock(&tevp->te_lock, lc2); + } + if (tevp) + break; /* got one! */ + + if (!(flags & DM_EV_WAIT)) { + mutex_spinunlock(&s->sn_qlock, lc1); + return(EAGAIN); + } + s->sn_readercnt++; +#ifdef __sgi + rc = sv_wait_sig(&s->sn_readerq, PUSER, &s->sn_qlock, lc1); +#else + mp_sv_wait_sig(&s->sn_readerq, 1, &s->sn_qlock, lc1); + rc = current->sigpending; +#endif + lc1 = mutex_spinlock(&s->sn_qlock); + s->sn_readercnt--; + if (rc) { /* if signal was received */ + mutex_spinunlock(&s->sn_qlock, lc1); + return(EINTR); + } + } + + /* At least one message is available for delivery, and we have both the + session lock and event lock. Mark the event so that it is not + grabbed by other daemons, then drop both locks prior copying the + data to the caller's buffer. Leaving the event on the queue in a + marked state prevents both the session and the event from + disappearing out from under us while we don't have the locks. + */ + + tevp->te_flags |= DM_TEF_LOCKED; + mutex_spinunlock(&tevp->te_lock, lc2); /* reverse cookie order */ + mutex_spinunlock(&s->sn_qlock, lc1); + + /* Continue to deliver messages until there are no more, the + user's buffer becomes full, or we hit his maxmsgs limit. + */ + + totalsize = 0; /* total bytes transferred to the user */ + prevmsg = NULL; + msgcnt = 0; + + while (tevp) { + /* Compute the number of bytes to be moved, rounding up to an + 8-byte boundary so that any subsequent messages will also be + aligned. + */ + + msgsize = tevp->te_allocsize - offsetof(dm_tokevent_t, te_msg); + msgsize = (msgsize + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1); + totalsize += msgsize; + + /* If it fits, copy the message into the user's buffer and + update his 'rlenp'. Update the _link pointer for any + previous message. + */ + + if (totalsize > buflen) { /* no more room */ + error = E2BIG; +#ifdef __sgi + } else if (dm_cpoutsizet(rlenp, totalsize)) { +#else + } else if (put_user(totalsize, rlenp)) { +#endif + error = EFAULT; +#ifdef __sgi + } else if (copyout(&tevp->te_msg, bufp, msgsize)) { +#else + } else if (copy_to_user(bufp, &tevp->te_msg, msgsize)) { +#endif + error = EFAULT; +#ifdef __sgi + } else if (prevmsg && suword(&prevmsg->_link, prev_msgsize)) { +#else + } else if (prevmsg && put_user(prev_msgsize, &prevmsg->_link)) { +#endif + error = EFAULT; + } else { + error = 0; + } + + /* If an error occurred, just unmark the event and leave it on + the queue for someone else. Note that other daemons may + have gone to sleep because this event was marked, so wake + them up. Also, if at least one message has already been + delivered, then an error here is not really an error. + */ + + lc1 = mutex_spinlock(&s->sn_qlock); + lc2 = mutex_spinlock(&tevp->te_lock); + tevp->te_flags &= ~DM_TEF_LOCKED; /* drop the mark */ + + if (error) { + if (s->sn_readercnt) + sv_signal(&s->sn_readerq); + + mutex_spinunlock(&tevp->te_lock, lc2); /* rev. order */ + mutex_spinunlock(&s->sn_qlock, lc1); + if (prevmsg) + return(0); +#ifdef __sgi + if (error == E2BIG && dm_cpoutsizet(rlenp, totalsize)) + error = EFAULT; +#else + if (error == E2BIG && put_user(totalsize,rlenp)) + error = EFAULT; +#endif + return(error); + } + + /* The message was successfully delivered. Unqueue it. */ + + unlink_event(tevp, &s->sn_newq); + + /* Wake up the first of any processes waiting for room on the + sn_newq. + */ + + if (s->sn_writercnt) + sv_signal(&s->sn_writerq); + + /* If the message is synchronous, add it to the sn_delq while + still holding the lock. If it is asynchronous, free it. + */ + + if (tevp->te_msg.ev_token != DM_INVALID_TOKEN) { /* synch */ + link_event(tevp, &s->sn_delq); + mutex_spinunlock(&tevp->te_lock, lc2); + } else { + tevp->te_flags |= DM_TEF_FINAL; +#ifdef __sgi + if (tevp->te_flags & DM_TEF_HASHED) + unhash_event(s, tevp); +#endif + mutex_spinunlock(&tevp->te_lock, lc2); + dm_put_tevp(tevp, NULL);/* can't cause destroy events */ + } + + /* Update our notion of where we are in the user's buffer. If + he doesn't want any more messages, then stop. + */ + + prevmsg = (dm_eventmsg_t *)bufp; + prev_msgsize = msgsize; + bufp = (char *)bufp + msgsize; + + msgcnt++; + if (maxmsgs && msgcnt >= maxmsgs) { + mutex_spinunlock(&s->sn_qlock, lc1); + break; + } + + /* While still holding the sn_qlock, see if any additional + messages are available for delivery. + */ + + for (tevp = s->sn_newq.eq_head; tevp; tevp = tevp->te_next) { + lc2 = mutex_spinlock(&tevp->te_lock); + if (!(tevp->te_flags & DM_TEF_LOCKED)) { + tevp->te_flags |= DM_TEF_LOCKED; + mutex_spinunlock(&tevp->te_lock, lc2); + break; + } + mutex_spinunlock(&tevp->te_lock, lc2); + } + mutex_spinunlock(&s->sn_qlock, lc1); + } + return(0); +} + + +/* + * Remove an event message from the delivered queue, set the returned + * error where the event generator wants it, and wake up the generator. + * Also currently have the user side release any locks it holds... + */ + +/* ARGSUSED */ +int +dm_respond_event( + dm_sessid_t sid, + dm_token_t token, + dm_response_t response, + int reterror, + size_t buflen, /* unused */ + void *respbufp) /* unused */ +{ + dm_session_t *s; /* pointer to session given by sid */ + dm_tokevent_t *tevp; /* event message queue traversal */ + int error; + int lc; /* lock cookie */ + + /* Sanity check the input parameters. */ + + switch (response) { + case DM_RESP_CONTINUE: /* continue must have reterror == 0 */ + if (reterror != 0) + return(EINVAL); + break; + case DM_RESP_ABORT: /* abort must have errno set */ + if (reterror <= 0) + return(EINVAL); + break; + case DM_RESP_DONTCARE: + if (reterror > 0) + return(EINVAL); + reterror = -1; /* to distinguish DM_RESP_DONTCARE */ + break; + default: + return(EINVAL); + } + + /* Hold session lock until the event is unqueued. */ + + if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) + return(error); + + if ((error = dm_find_msg(s, token, &tevp)) != 0) { + mutex_spinunlock(&s->sn_qlock, lc); + return(error); + } + nested_spinlock(&tevp->te_lock); + + if (reterror == -1 && tevp->te_msg.ev_type != DM_EVENT_MOUNT) { + error = EINVAL; + nested_spinunlock(&tevp->te_lock); + mutex_spinunlock(&s->sn_qlock, lc); + } else { + unlink_event(tevp, &s->sn_delq); +#ifdef __sgi + if (tevp->te_flags & DM_TEF_HASHED) + unhash_event(s, tevp); +#endif + tevp->te_reply = reterror; + tevp->te_flags |= DM_TEF_FINAL; + if (tevp->te_evt_ref) + sv_broadcast(&tevp->te_evt_queue); + nested_spinunlock(&tevp->te_lock); + mutex_spinunlock(&s->sn_qlock, lc); + error = 0; + + /* Absolutely no locks can be held when calling dm_put_tevp! */ + + dm_put_tevp(tevp, NULL); /* this can generate destroy events */ + } + return(error); +} + + +/* Queue the filled in event message pointed to by tevp on the session s, and + (if a synchronous event) wait for the reply from the DMAPI application. + The caller MUST be holding the session lock before calling this routine! + The session lock is always released upon exit. + Returns: + -1 == don't care + 0 == success (or async event) + > 0 == errno describing reason for failure +*/ + +static int +dm_enqueue( + dm_session_t *s, + int lc, /* input lock cookie */ + dm_tokevent_t *tevp, /* in/out parameter */ + int sync, + int flags, + int interruptable) +{ + int is_unmount = 0; + int is_hashable = 0; + int reply; + +#ifdef __sgi + /* If the caller isn't planning to stick around for the result + and this request is identical to one that is already on the + queues then just give the caller an EAGAIN. Release the + session lock before returning. + + We look only at NDELAY requests with an event type of READ, + WRITE, or TRUNCATE on objects that are regular files. + */ + + if ((flags & DM_FLAGS_NDELAY) && DM_EVENT_RDWRTRUNC(tevp) && + (tevp->te_tdp->td_type == DM_TDT_REG)) { + if (repeated_event(s, tevp)) { + mutex_spinunlock(&s->sn_qlock, lc); + return(EAGAIN); + } + is_hashable = 1; + } +#endif + + if (tevp->te_msg.ev_type == DM_EVENT_UNMOUNT) + is_unmount = 1; + + /* Check for room on sn_newq. If there is no room for new messages, + then go to sleep on the sn_writerq semaphore. The + session cannot disappear out from under us as long as sn_writercnt + is non-zero. + */ + + while (s->sn_newq.eq_count >= dm_max_queued_msgs) { /* no room */ + s->sn_writercnt++; +#ifdef __sgi + if (interruptable) { + if (sv_wait_sig(&s->sn_writerq, PUSER, &s->sn_qlock, lc)) { + s->sn_writercnt--; + return(EINTR); + } + } else { + sv_wait(&s->sn_writerq, PZERO, &s->sn_qlock, lc); + } +#else + if (interruptable) { + mp_sv_wait_sig(&s->sn_writerq, 1, &s->sn_qlock, lc); + if (current->sigpending) { + s->sn_writercnt--; + return(EINTR); + } + } else { + sv_wait(&s->sn_writerq, 1, &s->sn_qlock, lc); + } +#endif + lc = mutex_spinlock(&s->sn_qlock); + s->sn_writercnt--; + } + + /* Assign a sequence number and token to the event and bump the + application reference count by one. We don't need 'te_lock' here + because this thread is still the only thread that can see the event. + */ + + nested_spinlock(&dm_token_lock); + tevp->te_msg.ev_sequence = dm_next_sequence++; + if (sync) { + tevp->te_msg.ev_token = dm_next_token++; + } else { + tevp->te_msg.ev_token = DM_INVALID_TOKEN; + } + nested_spinunlock(&dm_token_lock); + + tevp->te_flags &= ~(DM_TEF_INTERMED|DM_TEF_FINAL); + tevp->te_app_ref++; + + /* Room exists on the sn_newq queue, so add this request. If the + queue was previously empty, wake up the first of any processes + that are waiting for an event. + */ + + link_event(tevp, &s->sn_newq); +#ifdef __sgi + if (is_hashable) + hash_event(s, tevp); +#endif + + if (s->sn_readercnt) + sv_signal(&s->sn_readerq); + + mutex_spinunlock(&s->sn_qlock, lc); + + /* Now that the message is queued, processes issuing asynchronous + events or DM_EVENT_UNMOUNT events are ready to continue. + */ + + if (!sync || is_unmount) + return(0); + + /* Synchronous requests wait until a final reply is received. If the + caller supplied the DM_FLAGS_NDELAY flag, the process will return + EAGAIN if dm_pending() sets DM_TEF_INTERMED. We also let users + Cntl-C out of a read, write, and truncate requests. + */ + + lc = mutex_spinlock(&tevp->te_lock); + + while (!(tevp->te_flags & DM_TEF_FINAL)) { + if ((tevp->te_flags & DM_TEF_INTERMED) && + (flags & DM_FLAGS_NDELAY)) { + mutex_spinunlock(&tevp->te_lock, lc); + return(EAGAIN); + } +#ifdef __sgi + if (tevp->te_msg.ev_type == DM_EVENT_READ || + tevp->te_msg.ev_type == DM_EVENT_WRITE || + tevp->te_msg.ev_type == DM_EVENT_TRUNCATE) { + if (sv_wait_sig(&tevp->te_evt_queue, PUSER, &tevp->te_lock, lc)) + return(EINTR); + } else { + sv_wait(&tevp->te_evt_queue, PZERO, &tevp->te_lock, lc); + } +#else + if (tevp->te_msg.ev_type == DM_EVENT_READ || + tevp->te_msg.ev_type == DM_EVENT_WRITE || + tevp->te_msg.ev_type == DM_EVENT_TRUNCATE) { + mp_sv_wait_sig(&tevp->te_evt_queue, 1, &tevp->te_lock, lc); + if (current->sigpending){ + return(EINTR); + } + } else { + sv_wait(&tevp->te_evt_queue, 1, &tevp->te_lock, lc); + } +#endif + lc = mutex_spinlock(&tevp->te_lock); + } + + /* Return both the tevp and the reply which was stored in the tevp by + dm_respond_event. The tevp structure has already been removed from + the reply queue by this point in dm_respond_event(). + */ + + reply = tevp->te_reply; + mutex_spinunlock(&tevp->te_lock, lc); + return(reply); +} + + +/* The filesystem is guaranteed to stay mounted while this event is + outstanding. +*/ + +int +dm_enqueue_normal_event( + vfs_t *vfsp, + dm_tokevent_t *tevp, + int flags) +{ + dm_session_t *s; + int error; + int sync; + int lc; /* lock cookie */ + + switch (tevp->te_msg.ev_type) { + case DM_EVENT_READ: + case DM_EVENT_WRITE: + case DM_EVENT_TRUNCATE: + case DM_EVENT_PREUNMOUNT: + case DM_EVENT_UNMOUNT: + case DM_EVENT_NOSPACE: + case DM_EVENT_CREATE: + case DM_EVENT_REMOVE: + case DM_EVENT_RENAME: + case DM_EVENT_SYMLINK: + case DM_EVENT_LINK: + case DM_EVENT_DEBUT: /* not currently supported */ + sync = 1; + break; + + case DM_EVENT_DESTROY: + case DM_EVENT_POSTCREATE: + case DM_EVENT_POSTREMOVE: + case DM_EVENT_POSTRENAME: + case DM_EVENT_POSTSYMLINK: + case DM_EVENT_POSTLINK: + case DM_EVENT_ATTRIBUTE: + case DM_EVENT_CLOSE: /* not currently supported */ + case DM_EVENT_CANCEL: /* not currently supported */ + sync = 0; + break; + + default: + return(EIO); /* garbage event number */ + } + + /* Wait until a session selects disposition for the event. The session + is locked upon return from dm_waitfor_disp_session(). + */ + + if ((error = dm_waitfor_disp_session(vfsp, tevp, &s, &lc)) != 0) + return(error); + + return(dm_enqueue(s, lc, tevp, sync, flags, 0)); +} + + +/* Traverse the session list checking for sessions with the WANTMOUNT flag + set. When one is found, send it the message. Possible responses to the + message are one of DONTCARE, CONTINUE, or ABORT. The action taken in each + case is: + DONTCARE (-1) - Send the event to the next session with WANTMOUNT set + CONTINUE ( 0) - Proceed with the mount, errno zero. + ABORT (>0) - Fail the mount, return the returned errno. + + The mount request is sent to sessions in ascending session ID order. + Since the session list can change dramatically while this process is + sleeping in dm_enqueue(), this routine must use session IDs rather than + session pointers when keeping track of where it is in the list. Since + new sessions are always added at the end of the queue, and have increasing + session ID values, we don't have to worry about missing any session. +*/ + +int +dm_enqueue_mount_event( + vfs_t *vfsp, + dm_tokevent_t *tevp) +{ + dm_session_t *s; + dm_sessid_t sid; + int error; + int lc; /* lock cookie */ + + /* Make the mounting filesystem visible to other DMAPI calls. */ + + if ((error = dm_add_fsys_entry(vfsp, tevp)) != 0){ + return(error); + } + + /* Walk through the session list presenting the mount event to each + session that is interested until a session accepts or rejects it, + or until all sessions ignore it. + */ + + for (sid = DM_NO_SESSION, error = -1; error < 0; sid = s->sn_sessid) { + + lc = mutex_spinlock(&dm_session_lock); + for (s = dm_sessions; s; s = s->sn_next) { + if (s->sn_sessid > sid && s->sn_flags & DM_SN_WANTMOUNT) { + nested_spinlock(&s->sn_qlock); + nested_spinunlock(&dm_session_lock); + break; + } + } + if (s == NULL) { + mutex_spinunlock(&dm_session_lock, lc); + break; /* noone wants it; proceed with mount */ + } + error = dm_enqueue(s, lc, tevp, 1, 0, 0); + } + + /* If the mount will be allowed to complete, then update the fsrp entry + accordingly. If the mount is to be aborted, remove the fsrp entry. + */ + + if (error <= 0) { + dm_change_fsys_entry(vfsp, DM_STATE_MOUNTED); + error = 0; + } else { + dm_remove_fsys_entry(vfsp); + } + return(error); +} + +int +dm_enqueue_sendmsg_event( + dm_sessid_t targetsid, + dm_tokevent_t *tevp, + int sync) +{ + dm_session_t *s; + int error; + int lc; /* lock cookie */ + + if ((error = dm_find_session_and_lock(targetsid, &s, &lc)) != 0) + return(error); + + return(dm_enqueue(s, lc, tevp, sync, 0, 1)); +} + + +dm_token_t +dm_enqueue_user_event( + dm_sessid_t sid, + dm_tokevent_t *tevp, + dm_token_t *tokenp) +{ + dm_session_t *s; + int error; + int lc; /* lock cookie */ + + /* Atomically find and lock the session whose session id is 'sid'. */ + + if ((error = dm_find_session_and_lock(sid, &s, &lc)) != 0) + return(error); + + /* Assign a sequence number and token to the event, bump the + application reference count by one, and decrement the event + count because the caller gives up all ownership of the event. + We don't need 'te_lock' here because this thread is still the + only thread that can see the event. + */ + + nested_spinlock(&dm_token_lock); + tevp->te_msg.ev_sequence = dm_next_sequence++; + *tokenp = tevp->te_msg.ev_token = dm_next_token++; + nested_spinunlock(&dm_token_lock); + + tevp->te_flags &= ~(DM_TEF_INTERMED|DM_TEF_FINAL); + tevp->te_app_ref++; + tevp->te_evt_ref--; + + /* Add the request to the tail of the sn_delq. Now it's visible. */ + + link_event(tevp, &s->sn_delq); + mutex_spinunlock(&s->sn_qlock, lc); + + return(0); +} diff -rNu linux-2.4.7/linux/fs/xfs/dmapi/dmapi_sysent.c linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_sysent.c --- linux-2.4.7/linux/fs/xfs/dmapi/dmapi_sysent.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/dmapi/dmapi_sysent.c Fri Jun 15 07:09:10 2001 @@ -0,0 +1,659 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* Data Migration API (DMAPI) + */ + + +/* We're using MISC_MAJOR / DMAPI_MINOR. */ +/* mknod /dev/dmapi c 10 140 */ + +#include +#include +#include + +#include + +#include "dmapi_private.h" + +void dm_init(void); +int dm_uninit(void); + +static int +dmapi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + sys_dmapi_args_t kargs; + sys_dmapi_args_t *uap = &kargs; + int error = 0; + int rvp = -ENOSYS; + int use_rvp = 0; + + if (!capable(CAP_MKNOD)) + return(-EPERM); + + if( copy_from_user( &kargs, (sys_dmapi_args_t*)arg, + sizeof(sys_dmapi_args_t) ) ) + return -EFAULT; + + switch (cmd) { + case DM_CLEAR_INHERIT: + error = dm_clear_inherit( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (dm_attrname_t *) uap->arg5); /* attrnamep */ + break; + case DM_CREATE_BY_HANDLE: + error = dm_create_by_handle( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* dirhanp */ + (size_t) uap->arg3, /* dirhlen */ + (dm_token_t) uap->arg4, /* token */ + (void *) uap->arg5, /* hanp */ + (size_t) uap->arg6, /* hlen */ + (char *) uap->arg7); /* cname */ + break; + case DM_CREATE_SESSION: + error = dm_create_session( + (dm_sessid_t) uap->arg1, /* oldsid */ + (char *) uap->arg2, /* sessinfop */ + (dm_sessid_t *) uap->arg3); /* newsidp */ + break; + case DM_CREATE_USEREVENT: + error = dm_create_userevent( + (dm_sessid_t) uap->arg1, /* sid */ + (size_t) uap->arg2, /* msglen */ + (void *) uap->arg3, /* msgdatap */ + (dm_token_t *) uap->arg4); /* tokenp */ + break; + case DM_DESTROY_SESSION: + error = dm_destroy_session( + (dm_sessid_t) uap->arg1); /* sid */ + break; + case DM_DOWNGRADE_RIGHT: + error = dm_downgrade_right( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4); /* token */ + break; + case DM_FD_TO_HANDLE: + error = dm_fd_to_hdl( + (int) uap->arg1, /* fd */ + (void *) uap->arg2, /* hanp */ + (size_t *) uap->arg3); /* hlenp */ + break; + case DM_FIND_EVENTMSG: + error = dm_find_eventmsg( + (dm_sessid_t) uap->arg1, /* sid */ + (dm_token_t) uap->arg2, /* token */ + (size_t) uap->arg3, /* buflen */ + (void *) uap->arg4, /* bufp */ + (size_t *) uap->arg5); /* rlenp */ + break; + case DM_GET_ALLOCINFO: + use_rvp = 1; + error = dm_get_allocinfo_rvp( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (dm_off_t *) uap->arg5, /* offp */ + (u_int) uap->arg6, /* nelem */ + (dm_extent_t *) uap->arg7, /* extentp */ + (u_int *) uap->arg8, /* nelemp */ + &rvp); + break; + case DM_GET_BULKALL: + use_rvp = 1; + error = dm_get_bulkall_rvp( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (u_int) uap->arg5, /* mask */ + (dm_attrname_t *) uap->arg6, /* attrnamep */ + (dm_attrloc_t *) uap->arg7, /* locp */ + (size_t) uap->arg8, /* buflen */ + (void *) uap->arg9, /* bufp */ + (size_t *) uap->arg10, /* rlenp */ + &rvp); + break; + case DM_GET_BULKATTR: + use_rvp = 1; + error = dm_get_bulkattr_rvp( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (u_int) uap->arg5, /* mask */ + (dm_attrloc_t *)uap->arg6, /* locp */ + (size_t) uap->arg7, /* buflen */ + (void *) uap->arg8, /* bufp */ + (size_t *) uap->arg9, /* rlenp */ + &rvp); + break; + case DM_GET_CONFIG: + error = dm_get_config( + (void *) uap->arg1, /* hanp */ + (size_t) uap->arg2, /* hlen */ + (dm_config_t) uap->arg3, /* flagname */ + (dm_size_t *) uap->arg4); /* retvalp */ + break; + case DM_GET_CONFIG_EVENTS: + error = dm_get_config_events( + (void *) uap->arg1, /* hanp */ + (size_t) uap->arg2, /* hlen */ + (u_int) uap->arg3, /* nelem */ + (dm_eventset_t *) uap->arg4, /* eventsetp */ + (u_int *) uap->arg5); /* nelemp */ + break; + case DM_GET_DIOINFO: + error = dm_get_dioinfo( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (dm_dioinfo_t *)uap->arg5); /* diop */ + break; + case DM_GET_DIRATTRS: + use_rvp = 1; + error = dm_get_dirattrs_rvp( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (u_int) uap->arg5, /* mask */ + (dm_attrloc_t *)uap->arg6, /* locp */ + (size_t) uap->arg7, /* buflen */ + (void *) uap->arg8, /* bufp */ + (size_t *) uap->arg9, /* rlenp */ + &rvp); + break; + case DM_GET_DMATTR: + error = dm_get_dmattr( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (dm_attrname_t *) uap->arg5, /* attrnamep */ + (size_t) uap->arg6, /* buflen */ + (void *) uap->arg7, /* bufp */ + (size_t *) uap->arg8); /* rlenp */ + + break; + case DM_GET_EVENTLIST: + error = dm_get_eventlist( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (u_int) uap->arg5, /* nelem */ + (dm_eventset_t *) uap->arg6, /* eventsetp */ + (u_int *) uap->arg7); /* nelemp */ + break; + case DM_GET_EVENTS: + error = dm_get_events( + (dm_sessid_t) uap->arg1, /* sid */ + (u_int) uap->arg2, /* maxmsgs */ + (u_int) uap->arg3, /* flags */ + (size_t) uap->arg4, /* buflen */ + (void *) uap->arg5, /* bufp */ + (size_t *) uap->arg6); /* rlenp */ + break; + case DM_GET_FILEATTR: + error = dm_get_fileattr( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (u_int) uap->arg5, /* mask */ + (dm_stat_t *) uap->arg6); /* statp */ + break; + case DM_GET_MOUNTINFO: + error = dm_get_mountinfo( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (size_t) uap->arg5, /* buflen */ + (void *) uap->arg6, /* bufp */ + (size_t *) uap->arg7); /* rlenp */ + break; + case DM_GET_REGION: + error = dm_get_region( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (u_int) uap->arg5, /* nelem */ + (dm_region_t *) uap->arg6, /* regbufp */ + (u_int *) uap->arg7); /* nelemp */ + break; + case DM_GETALL_DISP: + error = dm_getall_disp( + (dm_sessid_t) uap->arg1, /* sid */ + (size_t) uap->arg2, /* buflen */ + (void *) uap->arg3, /* bufp */ + (size_t *) uap->arg4); /* rlenp */ + break; + case DM_GETALL_DMATTR: + error = dm_getall_dmattr( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (size_t) uap->arg5, /* buflen */ + (void *) uap->arg6, /* bufp */ + (size_t *) uap->arg7); /* rlenp */ + break; + case DM_GETALL_INHERIT: + error = dm_getall_inherit( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (u_int) uap->arg5, /* nelem */ + (dm_inherit_t *)uap->arg6, /* inheritbufp*/ + (u_int *) uap->arg7); /* nelemp */ + break; + case DM_GETALL_SESSIONS: + error = dm_getall_sessions( + (u_int) uap->arg1, /* nelem */ + (dm_sessid_t *) uap->arg2, /* sidbufp */ + (u_int *) uap->arg3); /* nelemp */ + break; + case DM_GETALL_TOKENS: + error = dm_getall_tokens( + (dm_sessid_t) uap->arg1, /* sid */ + (u_int) uap->arg2, /* nelem */ + (dm_token_t *) uap->arg3, /* tokenbufp */ + (u_int *) uap->arg4); /* nelemp */ + break; + case DM_INIT_ATTRLOC: + error = dm_init_attrloc( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (dm_attrloc_t *) uap->arg5); /* locp */ + break; + case DM_MKDIR_BY_HANDLE: + error = dm_mkdir_by_handle( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* dirhanp */ + (size_t) uap->arg3, /* dirhlen */ + (dm_token_t) uap->arg4, /* token */ + (void *) uap->arg5, /* hanp */ + (size_t) uap->arg6, /* hlen */ + (char *) uap->arg7); /* cname */ + break; + case DM_MOVE_EVENT: + error = dm_move_event( + (dm_sessid_t) uap->arg1, /* srcsid */ + (dm_token_t) uap->arg2, /* token */ + (dm_sessid_t) uap->arg3, /* targetsid */ + (dm_token_t *) uap->arg4); /* rtokenp */ + break; + case DM_OBJ_REF_HOLD: + error = dm_obj_ref_hold( + (dm_sessid_t) uap->arg1, /* sid */ + (dm_token_t) uap->arg2, /* token */ + (void *) uap->arg3, /* hanp */ + (size_t) uap->arg4); /* hlen */ + break; + case DM_OBJ_REF_QUERY: + use_rvp = 1; + error = dm_obj_ref_query_rvp( + (dm_sessid_t) uap->arg1, /* sid */ + (dm_token_t) uap->arg2, /* token */ + (void *) uap->arg3, /* hanp */ + (size_t) uap->arg4, /* hlen */ + &rvp); + break; + case DM_OBJ_REF_RELE: + error = dm_obj_ref_rele( + (dm_sessid_t) uap->arg1, /* sid */ + (dm_token_t) uap->arg2, /* token */ + (void *) uap->arg3, /* hanp */ + (size_t) uap->arg4); /* hlen */ + break; + case DM_PATH_TO_FSHANDLE: + error = dm_path_to_fshdl( + (char *) uap->arg1, /* path */ + (void *) uap->arg2, /* hanp */ + (size_t *) uap->arg3); /* hlenp */ + break; + case DM_PATH_TO_HANDLE: + error = dm_path_to_hdl( + (char *) uap->arg1, /* path */ + (void *) uap->arg2, /* hanp */ + (size_t *) uap->arg3); /* hlenp */ + break; + case DM_PENDING: + error = dm_pending( + (dm_sessid_t) uap->arg1, /* sid */ + (dm_token_t) uap->arg2, /* token */ + (dm_timestruct_t *) uap->arg3); /* delay */ + break; + case DM_PROBE_HOLE: + error = dm_probe_hole( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (dm_off_t) uap->arg5, /* off */ + (dm_size_t) uap->arg6, /* len */ + (dm_off_t *) uap->arg7, /* roffp */ + (dm_size_t *) uap->arg8); /* rlenp */ + break; + case DM_PUNCH_HOLE: + error = dm_punch_hole( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (dm_off_t) uap->arg5, /* off */ + (dm_size_t) uap->arg6); /* len */ + break; + case DM_QUERY_RIGHT: + error = dm_query_right( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (dm_right_t *) uap->arg5); /* rightp */ + break; + case DM_QUERY_SESSION: + error = dm_query_session( + (dm_sessid_t) uap->arg1, /* sid */ + (size_t) uap->arg2, /* buflen */ + (void *) uap->arg3, /* bufp */ + (size_t *) uap->arg4); /* rlenp */ + break; + case DM_READ_INVIS: + use_rvp = 1; + error = dm_read_invis_rvp( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (dm_off_t) uap->arg5, /* off */ + (dm_size_t) uap->arg6, /* len */ + (void *) uap->arg7, /* bufp */ + &rvp); + break; + case DM_RELEASE_RIGHT: + error = dm_release_right( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4); /* token */ + break; + case DM_REMOVE_DMATTR: + error = dm_remove_dmattr( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (int) uap->arg5, /* setdtime */ + (dm_attrname_t *) uap->arg6); /* attrnamep */ + break; + case DM_REQUEST_RIGHT: + error = dm_request_right( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (u_int) uap->arg5, /* flags */ + (dm_right_t) uap->arg6); /* right */ + break; + case DM_RESPOND_EVENT: + error = dm_respond_event( + (dm_sessid_t) uap->arg1, /* sid */ + (dm_token_t) uap->arg2, /* token */ + (dm_response_t) uap->arg3, /* response */ + (int) uap->arg4, /* reterror */ + (size_t) uap->arg5, /* buflen */ + (void *) uap->arg6); /* respbufp */ + break; + case DM_SEND_MSG: + error = dm_send_msg( + (dm_sessid_t) uap->arg1, /* targetsid */ + (dm_msgtype_t) uap->arg2, /* msgtype */ + (size_t) uap->arg3, /* buflen */ + (void *) uap->arg4); /* bufp */ + break; + case DM_SET_DISP: + error = dm_set_disp( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (dm_eventset_t *) uap->arg5, /* eventsetp */ + (u_int) uap->arg6); /* maxevent */ + break; + case DM_SET_DMATTR: + error = dm_set_dmattr( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (dm_attrname_t *) uap->arg5, /* attrnamep */ + (int) uap->arg6, /* setdtime */ + (size_t) uap->arg7, /* buflen */ + (void *) uap->arg8); /* bufp */ + break; + case DM_SET_EVENTLIST: + error = dm_set_eventlist( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (dm_eventset_t *) uap->arg5, /* eventsetp */ + (u_int) uap->arg6); /* maxevent */ + break; + case DM_SET_FILEATTR: + error = dm_set_fileattr( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (u_int) uap->arg5, /* mask */ + (dm_fileattr_t *)uap->arg6); /* attrp */ + break; + case DM_SET_INHERIT: + error = dm_set_inherit( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (dm_attrname_t *)uap->arg5, /* attrnamep */ + (mode_t) uap->arg6); /* mode */ + break; + case DM_SET_REGION: + error = dm_set_region( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (u_int) uap->arg5, /* nelem */ + (dm_region_t *) uap->arg6, /* regbufp */ + (dm_boolean_t *) uap->arg7); /* exactflagp */ + break; + case DM_SET_RETURN_ON_DESTROY: + error = dm_set_return_on_destroy( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (dm_attrname_t *) uap->arg5, /* attrnamep */ + (dm_boolean_t) uap->arg6); /* enable */ + break; + case DM_SYMLINK_BY_HANDLE: + error = dm_symlink_by_handle( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* dirhanp */ + (size_t) uap->arg3, /* dirhlen */ + (dm_token_t) uap->arg4, /* token */ + (void *) uap->arg5, /* hanp */ + (size_t) uap->arg6, /* hlen */ + (char *) uap->arg7, /* cname */ + (char *) uap->arg8); /* path */ + break; + case DM_SYNC_BY_HANDLE: + error = dm_sync_by_handle( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4); /* token */ + break; + case DM_UPGRADE_RIGHT: + error = dm_upgrade_right( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4); /* token */ + break; + case DM_WRITE_INVIS: + use_rvp = 1; + error = dm_write_invis_rvp( + (dm_sessid_t) uap->arg1, /* sid */ + (void *) uap->arg2, /* hanp */ + (size_t) uap->arg3, /* hlen */ + (dm_token_t) uap->arg4, /* token */ + (int) uap->arg5, /* flags */ + (dm_off_t) uap->arg6, /* off */ + (dm_size_t) uap->arg7, /* len */ + (void *) uap->arg8, /* bufp */ + &rvp); + break; + default: + error = ENOSYS; + break; + } + /* If it was an *_rvp() function, then + if error==0, return |rvp| + */ + if( use_rvp && (error == 0) ) + return rvp; + else + return -error; +} + + +/* XXX a debugging tool */ +/* use 'cat /dev/dmapi' to get dump of info */ +static ssize_t +dmapi_dump(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + char tmp[1024]; + int l, len; + + extern u_int dm_sessions_active; + extern dm_sessid_t dm_next_sessid; + extern dm_token_t dm_next_token; + extern dm_sequence_t dm_next_sequence; + extern int dm_fsys_cnt; + + if( *ppos == 0 ){ + l = sprintf( tmp, "# " DM_VER_STR_CONTENTS "\n" + "dm_sessions_active=%u\n" + "dm_next_sessid=%d\n" + "dm_next_token=%d\n" + "dm_next_sequence=%u\n" + "dm_fsys_cnt=%d\n", + dm_sessions_active, + (int)dm_next_sessid, + (int)dm_next_token, + (u_int)dm_next_sequence, + dm_fsys_cnt ); + } + else { + return 0; + } +#define min(a,b) (((a)<(b))?(a):(b)) + len = min(l,count); +#undef min + + if( copy_to_user(buf, tmp, len) ) + return -EFAULT; + *ppos += 1; + return len; +} + + +static int +dmapi_open(struct inode *inode, struct file *file) +{ + return 0; +} + + +static int +dmapi_release(struct inode *inode, struct file *file) +{ + return 0; +} + + +static struct file_operations dmapi_fops = { + open: dmapi_open, + ioctl: dmapi_ioctl, + read: dmapi_dump, + release: dmapi_release +}; + +static struct miscdevice dmapi_dev = { + minor: DMAPI_MINOR, + name: "dmapi", + fops: &dmapi_fops +}; + +void dmapi_init(void) +{ + int ret; + + ret = misc_register(&dmapi_dev); + if( ret != 0 ) + printk(KERN_ERR "dmapi_init: misc_register returned %d\n", ret); + dm_init(); +} + +void dmapi_uninit(void) +{ + if( dm_uninit() == 0 ){ + misc_deregister(&dmapi_dev); + } +} diff -rNu linux-2.4.7/linux/fs/xfs/linux/CVS/Entries linux-2.4-xfs/linux/fs/xfs/linux/CVS/Entries --- linux-2.4.7/linux/fs/xfs/linux/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/CVS/Entries Thu Jul 5 12:04:30 2001 @@ -0,0 +1,29 @@ +/Makefile/1.41/Wed Apr 11 01:44:54 2001// +/acl.h/1.2/Wed Jun 6 04:55:01 2001/-ko/ +/attr_kern.h/1.1/Thu May 31 06:41:06 2001/-ko/ +/xfs_behavior.c/1.12/Mon Sep 25 05:42:07 2000// +/xfs_behavior.h/1.2/Wed Dec 20 03:23:53 2000/-ko/ +/xfs_cred.c/1.9/Mon Sep 25 05:42:07 2000/-ko/ +/xfs_cred.h/1.9/Mon Jan 15 10:28:46 2001/-ko/ +/xfs_dmistubs.c/1.13/Tue Jun 5 19:58:19 2001// +/xfs_file.c/1.47/Thu May 17 20:53:29 2001/-kv/ +/xfs_fs_subr.c/1.27/Mon Mar 5 16:47:52 2001// +/xfs_fs_subr.h/1.4/Wed Dec 13 06:02:07 2000/-ko/ +/xfs_globals.c/1.23/Tue Feb 27 02:43:46 2001// +/xfs_globals.h/1.5/Tue Feb 27 02:43:46 2001/-ko/ +/xfs_griostubs.c/1.11/Mon Sep 25 05:42:07 2000// +/xfs_ioctl.c/1.41/Fri Jun 22 20:35:18 2001/-ko/ +/xfs_iops.c/1.110/Mon Jun 25 20:12:14 2001// +/xfs_iops.h/1.10/Mon Apr 16 21:06:55 2001// +/xfs_linux.h/1.50/Fri May 18 00:20:50 2001/-kv/ +/xfs_lrw.c/1.101/Sat Jun 9 03:23:46 2001// +/xfs_lrw.h/1.16/Tue Feb 27 02:43:46 2001// +/xfs_stats.c/1.2/Thu Apr 19 02:37:23 2001/-ko/ +/xfs_stats.h/1.1/Tue Nov 14 02:57:58 2000/-ko/ +/xfs_super.c/1.129/Fri Jun 29 22:29:47 2001/-kv/ +/xfs_super.h/1.9/Thu May 10 14:44:32 2001/-kv/ +/xfs_vfs.c/1.23/Tue Apr 24 18:43:41 2001// +/xfs_vfs.h/1.5/Tue Apr 24 18:43:41 2001/-ko/ +/xfs_vnode.c/1.65/Tue Jun 5 21:06:24 2001// +/xfs_vnode.h/1.20/Fri May 25 20:33:07 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/xfs/linux/CVS/Repository linux-2.4-xfs/linux/fs/xfs/linux/CVS/Repository --- linux-2.4.7/linux/fs/xfs/linux/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/CVS/Repository Thu Jul 5 12:04:26 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/xfs/linux diff -rNu linux-2.4.7/linux/fs/xfs/linux/CVS/Root linux-2.4-xfs/linux/fs/xfs/linux/CVS/Root --- linux-2.4.7/linux/fs/xfs/linux/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/CVS/Root Thu Jul 5 12:04:26 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/xfs/linux/Makefile linux-2.4-xfs/linux/fs/xfs/linux/Makefile --- linux-2.4.7/linux/fs/xfs/linux/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/Makefile Tue Apr 10 20:44:54 2001 @@ -0,0 +1,77 @@ +# +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# Makefile for XFS on Linux. + +#CFLAGS := $(filter-out -Wall,$(CFLAGS)) + +# This needs -I.. because everything does #include instead of "xfs.h". +# The code is wrong, local files should be included using "xfs.h", not +# but I am not going to change every file at the moment. It also needs +# -I $TOPDIR/fs to pick up #include , the support files should +# really be in linux/include/xfs_support, not hidden under fs. Keith Owens. +EXTRA_CFLAGS += -I .. -I $(TOPDIR)/fs -funsigned-char + + +ifeq ($(CONFIG_XFS_DEBUG),y) + EXTRA_CFLAGS += -DDEBUG -DXFSDEBUG +endif + +O_TARGET := linux_xfs.o +ifneq ($(MAKECMDGOALS),modules_install) + obj-m := $(O_TARGET) +endif + +export-objs := xfs_fs_subr.o + +ifeq ($(CONFIG_XFS_GRIO),) + obj-y += xfs_griostubs.o +endif + +ifeq ($(CONFIG_XFS_DMAPI),) + obj-y += xfs_dmistubs.o +endif + +obj-y += xfs_behavior.o \ + xfs_cred.o \ + xfs_file.o \ + xfs_fs_subr.o \ + xfs_globals.o \ + xfs_ioctl.o \ + xfs_iops.o \ + xfs_lrw.o \ + xfs_stats.o \ + xfs_super.o \ + xfs_vfs.o \ + xfs_vnode.o + +include $(TOPDIR)/Rules.make diff -rNu linux-2.4.7/linux/fs/xfs/linux/acl.h linux-2.4-xfs/linux/fs/xfs/linux/acl.h --- linux-2.4.7/linux/fs/xfs/linux/acl.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/acl.h Tue Jun 5 23:55:01 2001 @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef __ACL_H__ +#define __ACL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Data types for Access Control Lists (ACLs) + */ +#define SGI_ACL_FILE "SGI_ACL_FILE" +#define SGI_ACL_DEFAULT "SGI_ACL_DEFAULT" + +#define SGI_ACL_FILE_SIZE 12 +#define SGI_ACL_DEFAULT_SIZE 15 + +/* + * An IRIX defined macro not in P1003.1e + * With ACL_COMPAT_IRIXGET set + * it used to signify an empty ACL. + * It is also used to delete an ACL. + */ +#define ACL_NOT_PRESENT -1 + +/* + * Number of "base" ACL entries + * (USER_OBJ, GROUP_OBJ, MASK, & OTHER_OBJ) + */ +#define NACLBASE 4 +#define ACL_MAX_ENTRIES 25 /* Arbitrarily chosen number */ + +/* + * Data types required by POSIX P1003.1eD15 + */ +typedef ushort acl_perm_t; +typedef int acl_type_t; +typedef int acl_tag_t; + +/* + * On-disk representation of an ACL. + */ +struct acl_entry { + acl_tag_t ae_tag; + uid_t ae_id; + acl_perm_t ae_perm; +}; +typedef struct acl_entry * acl_entry_t; + +struct acl { + int acl_cnt; /* Number of entries */ + struct acl_entry acl_entry[ACL_MAX_ENTRIES]; +}; + +/* + * Values for acl_get_entry + */ +#define ACL_FIRST_ENTRY 0x00 +#define ACL_NEXT_ENTRY 0x01 + +/* + * Values for acl_tag_t + */ +#define ACL_UNDEFINED_TAG 0x00 /* undefined tag */ +#define ACL_USER_OBJ 0x01 /* owner */ +#define ACL_USER 0x02 /* additional users */ +#define ACL_GROUP_OBJ 0x04 /* group */ +#define ACL_GROUP 0x08 /* additional groups */ +#define ACL_MASK 0x10 /* mask entry */ +#define ACL_OTHER_OBJ 0x20 /* other entry */ +#define ACL_OTHER 0x20 /* POSIX other entry */ +/* + * Values for acl_type_t + */ +#define ACL_TYPE_ACCESS 0 +#define ACL_TYPE_DEFAULT 1 +/* + * Values for acl_perm_t + */ +#define ACL_PERM_NONE 00 +#define ACL_READ 04 +#define ACL_WRITE 02 +#define ACL_EXECUTE 01 + +/* + * Values for qualifiers + */ +#define ACL_UNDEFINED_ID ((unsigned int)-1) + +/* + * Values for acl compatibility + */ +#define ACL_COMPAT_DEFAULT 0x00 +#define ACL_COMPAT_IRIXGET 0x01 + +typedef struct acl * acl_t; +typedef acl_perm_t * acl_permset_t; +typedef unsigned int acl_compat_t; + +/* + * User-space POSIX data types and functions. + */ +#ifndef __KERNEL__ + +extern void acl_set_compat(acl_compat_t); +extern int acl_add_perm(acl_permset_t, acl_perm_t); +extern int acl_clear_perms(acl_permset_t); +extern ssize_t acl_copy_ext(void *, acl_t, ssize_t); +extern acl_t acl_copy_int(const void *); +extern int acl_create_entry(acl_t *, acl_entry_t *); +extern int acl_delete_def_file(const char *); +extern int acl_delete_entry(acl_t, acl_entry_t); +extern int acl_delete_perm(acl_permset_t, acl_perm_t); +extern acl_t acl_dup(acl_t); +extern void acl_entry_sort(acl_t); +extern int acl_free(void *); +extern acl_t acl_from_text(const char *); +extern int acl_get_entry(acl_t, int, acl_entry_t *); +extern acl_t acl_get_fd(int); +extern acl_t acl_get_file(const char *, acl_type_t); +extern int acl_get_perm(acl_permset_t, acl_perm_t); +extern int acl_get_permset(acl_entry_t, acl_permset_t *); +extern void *acl_get_qualifier(acl_entry_t); +extern int acl_get_tag_type(acl_entry_t, acl_tag_t *); +extern acl_t acl_init(int); +extern int acl_set_fd(int, acl_t); +extern int acl_set_file(const char *, acl_type_t, acl_t); +extern int acl_set_permset(acl_entry_t, acl_permset_t); +extern int acl_set_qualifier(acl_entry_t,const void *); +extern int acl_set_tag_type(acl_entry_t, acl_tag_t); +extern ssize_t acl_size(acl_t); +extern char *acl_to_short_text(acl_t, ssize_t *); +extern char *acl_to_text(acl_t, ssize_t *); +extern int acl_valid(acl_t); + +/* system calls */ +extern int acl_get(const char *, int, struct acl *, struct acl *); +extern int acl_set(const char *, int, struct acl *, struct acl *); + +#endif /* __KERNEL__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ACL_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/linux/attr_kern.h linux-2.4-xfs/linux/fs/xfs/linux/attr_kern.h --- linux-2.4.7/linux/fs/xfs/linux/attr_kern.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/attr_kern.h Thu May 31 01:41:06 2001 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __ATTR_KERN_H__ +#define __ATTR_KERN_H__ + +/* + * The (experimental) Linux generic attribute syscall - attrctl(2) + */ + +typedef union attr_obj { + char *path; + int fd; + pid_t pid; +} attr_obj_t; + +/* + * attr_obj_t type identifiers + */ +#define ATTR_TYPE_FD 1 /* file descriptor */ +#define ATTR_TYPE_PATH 2 /* path - follow symlinks */ +#define ATTR_TYPE_LPATH 3 /* path - don't follow symlinks */ +#define ATTR_TYPE_PID 4 /* process id */ + +/* + * Kernel-internal version of the attrlist cursor. + */ +typedef struct attrlist_cursor_kern { + __u32 hashval; /* hash value of next entry to add */ + __u32 blkno; /* block containing entry (suggestion)*/ + __u32 offset; /* offset in list of equal-hashvals */ + __u16 pad1; /* padding to match user-level */ + __u8 pad2; /* padding to match user-level */ + __u8 initted; /* T/F: cursor has been initialized */ +} attrlist_cursor_kern_t; + +#endif /* __ATTR_KERN_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_behavior.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_behavior.c --- linux-2.4.7/linux/fs/xfs/linux/xfs_behavior.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_behavior.c Mon Sep 25 00:42:07 2000 @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + * + */ + +/* + * Source file used to associate/disassociate behaviors with virtualized + * objects. See behavior.h for more information about behaviors, etc. + * + * The implementation is split between functions in this file and macros + * in behavior.h. + */ +#include + +xfs_zone_t *bhv_global_zone; + +/* + * Global initialization function called out of main. + */ +void +bhv_global_init(void) +{ + /* + * Initialize a behavior zone used by subsystems using behaviors + * but without any private data. In the UNIKERNEL case, this zone + * is used only for behaviors that are not yet isolated to a single + * cell. The only such user is in pshm.c in which a dummy vnode is + * obtained in support of vce avoidance logic. + */ + bhv_global_zone = kmem_zone_init(sizeof(bhv_desc_t), "bhv_global_zone"); +} + +/* + * Insert a new behavior descriptor into a behavior chain. The act of + * modifying the chain is done atomically w.r.t. ops-in-progress + * (see comment at top of behavior.h for more info on synchronization). + * + * If BHV_SYNCH is defined, then must be called with the behavior chain + * write locked. This both synchronizes with ops-in-progress as well + * as multiple concurrent threads inserting. + * + * If BHV_SYNCH is not defined, then it's the callers' responsibility + * to synchronize appropriately. Imon, for instance, relies on the + * atomic nature of insertion to synchronize with ops-in-progress, and + * implements its own lock to synchronize multiple concurrent threads + * inserting. + * + * The behavior chain is ordered based on the 'position' number which + * lives in the first field of the ops vector (higher numbers first). + * + * Attemps to insert duplicate ops result in an EINVAL return code. + * Otherwise, return 0 to indicate success. + */ +int +bhv_insert(bhv_head_t *bhp, bhv_desc_t *bdp) +{ + bhv_desc_t *curdesc, *prev; + int position; + + ASSERT(bdp->bd_next == NULL); + ASSERT(BHV_IS_WRITE_LOCKED(bhp)); + + /* + * Validate the position value of the new behavior. + */ + position = BHV_POSITION(bdp); + ASSERT(position >= BHV_POSITION_BASE && position <= BHV_POSITION_TOP); + + /* + * Find location to insert behavior. Check for duplicates. + */ + prev = NULL; + for (curdesc = bhp->bh_first; + curdesc != NULL; + curdesc = curdesc->bd_next) { + + /* Check for duplication. */ + if (curdesc->bd_ops == bdp->bd_ops) + return EINVAL; + + /* Find correct position */ + if (position >= BHV_POSITION(curdesc)) { + ASSERT(position != BHV_POSITION(curdesc)); + break; /* found it */ + } + + prev = curdesc; + } + + if (prev == NULL) { + /* insert at front of chain */ + bdp->bd_next = bhp->bh_first; + bhp->bh_first = bdp; /* atomic wrt oip's */ + } else { + /* insert after prev */ + bdp->bd_next = prev->bd_next; + prev->bd_next = bdp; /* atomic wrt oip's */ + } + + return 0; +} + +/* + * Remove a behavior descriptor from a position in a behavior chain; + * the postition is guaranteed not to be the first position. + * Should only be called by the bhv_remove() macro. + * + * The act of modifying the chain is done atomically w.r.t. ops-in-progress + * (see comment at top of behavior.h for more info on synchronization). + */ +void +bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp) +{ + bhv_desc_t *curdesc, *prev; + + ASSERT(bhp->bh_first != NULL); + ASSERT(bhp->bh_first->bd_next != NULL); + + prev = bhp->bh_first; + for (curdesc = bhp->bh_first->bd_next; + curdesc != NULL; + curdesc = curdesc->bd_next) { + + if (curdesc == bdp) + break; /* found it */ + prev = curdesc; + } + + ASSERT(curdesc == bdp); + prev->bd_next = bdp->bd_next; /* remove from after prev */ + /* atomic wrt oip's */ +} + +/* + * Look for a specific ops vector on the specified behavior chain. + * Return the associated behavior descriptor. Or NULL, if not found. + */ +bhv_desc_t * +bhv_lookup(bhv_head_t *bhp, void *ops) +{ + bhv_desc_t *curdesc; + + for (curdesc = bhp->bh_first; + curdesc != NULL; + curdesc = curdesc->bd_next) { + + if (curdesc->bd_ops == ops) + return curdesc; + } + + return NULL; +} + +/* + * Look for a specific ops vector on the specified behavior chain. + * Return the associated behavior descriptor. Or NULL, if not found. + * + * The caller has not read locked the behavior chain, so acquire the + * lock before traversing the chain. + */ +bhv_desc_t * +bhv_lookup_unlocked(bhv_head_t *bhp, void *ops) +{ + bhv_desc_t *bdp; + + BHV_READ_LOCK(bhp); + bdp = bhv_lookup(bhp, ops); + BHV_READ_UNLOCK(bhp); + + return bdp; +} + +/* + * Return the base behavior in the chain, or NULL if the chain + * is empty. + * + * The caller has not read locked the behavior chain, so acquire the + * lock before traversing the chain. + */ +bhv_desc_t * +bhv_base_unlocked(bhv_head_t *bhp) +{ + bhv_desc_t *curdesc; + + BHV_READ_LOCK(bhp); + for (curdesc = bhp->bh_first; + curdesc != NULL; + curdesc = curdesc->bd_next) { + + if (curdesc->bd_next == NULL) { + BHV_READ_UNLOCK(bhp); + return curdesc; + } + } + + BHV_READ_UNLOCK(bhp); + return NULL; +} + +#define BHVMAGIC 0xf00d + +/* ARGSUSED */ +void +bhv_head_init( + bhv_head_t *bhp, + char *name) +{ + bhp->bh_first = NULL; +#if defined(CELL_ENABLED) + bhp->bh_lockp = BHVMAGIC; +#endif +} + + +/* ARGSUSED */ +void +bhv_head_reinit( + bhv_head_t *bhp) +{ + ASSERT(bhp->bh_first == NULL); +#if defined(CELL_ENABLED) + ASSERT(bhp->bh_lockp == BHVMAGIC); +#endif +} + + +void +bhv_insert_initial( + bhv_head_t *bhp, + bhv_desc_t *bdp) +{ + ASSERT(bhp->bh_first == NULL); +#if defined(CELL_ENABLED) + ASSERT(bhp->bh_lockp == BHVMAGIC); +#endif + (bhp)->bh_first = bdp; +} + +void +bhv_head_destroy( + bhv_head_t *bhp) +{ + ASSERT(bhp->bh_first == NULL); +#if defined(CELL_CAPABLE) + ASSERT(bhp->bh_lockp == BHVMAGIC); + bhp->bh_lockp = NULL; +#endif +} + diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_behavior.h linux-2.4-xfs/linux/fs/xfs/linux/xfs_behavior.h --- linux-2.4.7/linux/fs/xfs/linux/xfs_behavior.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_behavior.h Tue Dec 19 21:23:53 2000 @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BEHAVIOR_H__ +#define __XFS_BEHAVIOR_H__ + +/* + * Header file used to associate behaviors with virtualized objects. + * + * A virtualized object is an internal, virtualized representation of + * OS entities such as persistent files, processes, or sockets. Examples + * of virtualized objects include vnodes, vprocs, and vsockets. Often + * a virtualized object is referred to simply as an "object." + * + * A behavior is essentially an implementation layer associated with + * an object. Multiple behaviors for an object are chained together, + * the order of chaining determining the order of invocation. Each + * behavior of a given object implements the same set of interfaces + * (e.g., the VOP interfaces). + * + * Behaviors may be dynamically inserted into an object's behavior chain, + * such that the addition is transparent to consumers that already have + * references to the object. Typically, a given behavior will be inserted + * at a particular location in the behavior chain. Insertion of new + * behaviors is synchronized with operations-in-progress (oip's) so that + * the oip's always see a consistent view of the chain. + * + * The term "interpostion" is used to refer to the act of inserting + * a behavior such that it interposes on (i.e., is inserted in front + * of) a particular other behavior. A key example of this is when a + * system implementing distributed single system image wishes to + * interpose a distribution layer (providing distributed coherency) + * in front of an object that is otherwise only accessed locally. + * + * Note that the traditional vnode/inode combination is simply a virtualized + * object that has exactly one associated behavior. + * + * Behavior synchronization is logic which is necessary under certain + * circumstances that there is no conflict between ongoing operations + * traversing the behavior chain and those dunamically modifying the + * behavior chain. Because behavior synchronization adds extra overhead + * to virtual operation invocation, we want to restrict, as much as + * we can, the requirement for this extra code, to those situations + * in which it is truly necessary. + * + * Behavior synchronization is needed whenever there's at least one class + * of object in the system for which: + * 1) multiple behaviors for a given object are supported, + * -- AND -- + * 2a) insertion of a new behavior can happen dynamically at any time during + * the life of an active object, + * -- AND -- + * 3a) insertion of a new behavior needs to synchronize with existing + * ops-in-progress. + * -- OR -- + * 3b) multiple different behaviors can be dynamically inserted at + * any time during the life of an active object + * -- OR -- + * 3c) removal of a behavior can occur at any time during the life of + * an active object. + * -- OR -- + * 2b) removal of a behavior can occur at any time during the life of an + * active object + * + * For now, behavior synchornization, is controlled if CELL is + * defined. + * + * In order to allow binary compatibility with 6.5, platforms that might + * support Cellular or Cluster Irix have reserved space in 6.5 in several kernel + * structures (ex., kthread_t) which can be used to implement behavior + * synchronization functionality. Reservation of this space is controled + * by the CELL_PREPARE define. + * + * Note that currently, the CELL code, takes up more space than will be + * available in 6.5 systems. This needs to be addressed, at some point. + * + * The makefile (Makefile.kernio) that is used for compiling 3rd party + * drivers also defines CELL_PREPARE for the platforms that might + * support Cellular or Cluster Irix. In addition, this makefile also defines + * BHV_PREPARE. This causes calls to be generated to the appropriate + * BHV locking code. In 6.5, these function are stubs but they will be + * replaced with real locking code in CELL systems. + * + * Note that modifying the behavior chain due to insertion of a new behavior + * is done atomically w.r.t. ops-in-progress. This implies that even if + * CELL is off, a racing op-in-progress will always see a consistent + * view of the chain. However, correctness is not guaranteed if an + * op-in-progress is dependent on whether or not a new behavior is + * inserted while it is executing. The same applies to removal + * of an existing behavior. + * + */ + +#include + +/* + * Define stuff for behavior position masks + */ +#ifdef CELL_CAPABLE +typedef __uint64_t bhv_posmask_t; +#define BHV_POSMASK_NULL ((bhv_posmask_t) 0) +#define BHV_POSMASK_ONE(a) (((bhv_posmask_t) 1) << (a)) +#define BHV_POSMASK_RANGE(a, b) (((((bhv_posmask_t) 1) << ((b)-(a)))-1) << (a)) +#define BHV_POSMASK_TEST(a, b) ((a) & BHV_POSMASK(b)) +#define BHV_POMASK_TESTID(a, b) BHV_POS_MASK((b)->bi_position) +#endif + +/* + * Plumbing macros. + */ +#define BHV_HEAD_FIRST(bhp) (ASSERT((bhp)->bh_first), (bhp)->bh_first) +#ifdef CELL_CAPABLE +#define BHV_NEXT(bdp) (ASSERT((bdp)->bd_next), (bdp)->bd_next) +#define BHV_NEXTNULL(bdp) ((bdp)->bd_next) +#endif +#define BHV_VOBJ(bdp) (ASSERT((bdp)->bd_vobj), (bdp)->bd_vobj) +#define BHV_VOBJNULL(bdp) ((bdp)->bd_vobj) +#define BHV_PDATA(bdp) (bdp)->bd_pdata +#define BHV_OPS(bdp) (bdp)->bd_ops +#define BHV_IDENTITY(bdp) ((bhv_identity_t *)(bdp)->bd_ops) +#define BHV_POSITION(bdp) (BHV_IDENTITY(bdp)->bi_position) + +// /* +// * This is used to mark an op table entry for an operation that has +// * been deleted but the entry remains reserved so that alignment +// * is maintained for compatibility for all subsequent operations. +// */ +// #define BHV_OP_DELETED NULL + + + + +#ifdef CELL_CAPABLE + +/* + * Macros for manipulation of behavior locks. The following + * macros operate on the lock itself. Currently, BHV locks are + * simply mrlocks but this implementation could change in the + * future. These macros should insulate us from this change. + * These macros take a mrlock_t* as an argument. + */ + +#define BHV_MRACCESS(l) mraccess(l) +#define BHV_MRACCUNLOCK(l) mraccunlock(l) +#define BHV_MRTRYACCESS(l) mrtryaccess(l) +#define BHV_MRTRYPROMOTE(l) mrtrypromote(l) + +#define BHV_MRUPDATE(l) mrupdate(l) +#define BHV_MRTRYUPDATE(l) mrtryupdate(l) +#define BHV_MRUNLOCK(l) mrunlock(l) +#define BHV_MRDEMOTE(l) mrdemote(l) +#define BHV_MRDIVEST(l) mrdivest(l) + +#define BHV_MR_IS_READ_LOCKED(l) mrislocked_access(l) +#define BHV_MR_NOT_READ_LOCKED(l) (!mrislocked_access(l)) +#define BHV_MR_IS_WRITE_LOCKED(l) mrislocked_update(l) +#define BHV_MR_NOT_WRITE_LOCKED(l) (!mrislocked_update(l)) +#define BHV_MR_IS_EITHER_LOCKED(l) mrislocked_any(l) +#define BHV_MR_NOT_EITHER_LOCKED(l) (!mrislocked_any(l)) +#define BHV_MR_LOCK_MINE(l) mrlock_mine(l,curthreadp) + +/* + * Behavior chain lock macros - typically used by ops-in-progress to + * synchronize with behavior insertion and object migration. + * Theses macros take a behavior (bhv_head_t*) as an + * argument. + */ +#define BH_LOCK(bhp) (&(bhp)->bh_lockp->bhl_lock) + +#define BHV_READ_LOCK(bhp) CELL_ONLY(BHV_MRACCESS(BH_LOCK(bhp))) +#define BHV_READ_UNLOCK(bhp) CELL_ONLY(BHV_MRACCUNLOCK(BH_LOCK(bhp))) +#define BHV_TRYACCESS(bhp) CELL_MUST(BHV_MRTRYACCESS(BH_LOCK(bhp))) +#define BHV_TRYPROMOTE(bhp) CELL_MUST(BHV_MRTRYPROMOTE(BH_LOCK(bhp))) + +#define BHV_WRITE_LOCK(bhp) CELL_ONLY(BHV_MRUPDATE(BH_LOCK(bhp))) +#define BHV_WRITE_UNLOCK(bhp) CELL_ONLY(BHV_MRUNLOCK(BH_LOCK(bhp))) +#define BHV_TRYUPDATE(bhp) CELL_MUST(BHV_MRTRYUPDATE(BH_LOCK(bhp))) +#define BHV_WRITE_TO_READ(bhp) CELL_ONLY(BHV_MRDEMOTE(BH_LOCK(bhp))) +#define BHV_DEMOTE(bhp) CELL_MUST(BHV_MRDEMOTE(BH_LOCK(bhp))) + +#define BHV_IS_READ_LOCKED(bhp) CELL_IF(BHV_MR_IS_READ_LOCKED(BH_LOCK(bhp)), 1) +#define BHV_NOT_READ_LOCKED(bhp) CELL_IF(BHV_MR_NOT_READ_LOCKED(BH_LOCK(bhp)), 1) +#define BHV_IS_WRITE_LOCKED(bhp) CELL_IF(BHV_MR_IS_WRITE_LOCKED(BH_LOCK(bhp)), 1) +#define BHV_NOT_WRITE_LOCKED(bhp) CELL_IF(BHV_MR_NOT_WRITE_LOCKED(BH_LOCK(bhp)), 1) +#define BHV_IS_EITHER_LOCKED(bhp) CELL_IF(BHV_MR_IS_EITHER_LOCKED(BH_LOCK(bhp)), 1) +#define BHV_NOT_EITHER_LOCKED(bhp) CELL_IF(BHV_MR_NOT_EITHER_LOCKED(BH_LOCK(bhp)), 1) +#define BHV_LOCK_MINE(bhp) CELL_IF(BHV_MR_LOCK_MINE(BH_LOCK(bhp)), 1) +#define BHV_AM_WRITE_OWNER(bhp) \ + CELL_IF(BHV_MR_IS_WRITE_LOCKED(BH_LOCK(bhp)) && \ + BHV_MR_LOCK_MINE(BH_LOCK(bhp)), 1) + +/* + * Request a callout to be made ((*func)(bhp, arg1, arg2, arg3, argv, argvsz)) + * with the behavior chain update locked. + * + * Must have read lock before calling this routine. + * Note that the callouts will occur in the context of the last + * accessor unlocking the behavior. + */ +typedef void bhv_ucallout_t(bhv_head_t *bhp, void *, void *, caddr_t, size_t); + +#define BHV_WRITE_LOCK_CALLOUT(bhp, flags, func, arg1, arg2, argv, argvsz) \ + bhv_queue_ucallout(bhp, flags, func, arg1, arg2, argv, argvsz) + +#define bhv_lock_init(bhp,name) CELL_ONLY(mrbhinit(BH_LOCK(bhp), (name))) +#define bhv_lock_free(bhp) CELL_ONLY(mrfree(BH_LOCK(bhp))) + + +#else /* not CELL_CAPABLE ie non-cell kernel */ + +#define BHV_READ_LOCK(bhp) +#define BHV_READ_UNLOCK(bhp) +#define BHV_NOT_READ_LOCKED(bhp) 1 +#define BHV_IS_WRITE_LOCKED(bhp) 1 +#define BHV_NOT_WRITE_LOCKED(bhp) 1 + +#endif /* CELL_CAPABLE */ + +#ifdef CELL_CAPABLE +extern int bhv_try_deferred_ucalloutp(bhv_head_lock_t *bhl); + +static __inline int +bhv_try_deferred_ucallout(mrlock_t *mrp) +{ + bhv_head_lock_t *bhl; + + bhl = MR_TO_BHVL(mrp); + if (kcallout_isempty(&bhl->bhl_ucallout)) + return 0; + return bhv_try_deferred_ucalloutp(bhl); +} + +#endif + +extern void bhv_head_init(bhv_head_t *, char *); +extern void bhv_head_destroy(bhv_head_t *); +extern void bhv_head_reinit(bhv_head_t *); +extern void bhv_insert_initial(bhv_head_t *, bhv_desc_t *); + +/* + * Initialize a new behavior descriptor. + * Arguments: + * bdp - pointer to behavior descriptor + * pdata - pointer to behavior's private data + * vobj - pointer to associated virtual object + * ops - pointer to ops for this behavior + */ +#define bhv_desc_init(bdp, pdata, vobj, ops) \ + { \ + (bdp)->bd_pdata = pdata; \ + (bdp)->bd_vobj = vobj; \ + (bdp)->bd_ops = ops; \ + (bdp)->bd_next = NULL; \ + } + +/* + * Remove a behavior descriptor from a behavior chain. + */ +#define bhv_remove(bhp, bdp) \ + { \ + if ((bhp)->bh_first == (bdp)) { \ + /* \ + * Remove from front of chain. \ + * Atomic wrt oip's. \ + */ \ + (bhp)->bh_first = (bdp)->bd_next; \ + } else { \ + /* remove from non-front of chain */ \ + bhv_remove_not_first(bhp, bdp); \ + } \ + (bdp)->bd_vobj = NULL; \ + } + +/* + * Behavior module prototypes. + */ +#ifdef CELL_CAPABLE +extern int bhv_insert(bhv_head_t *bhp, bhv_desc_t *bdp); +extern int bhv_forced_insert(bhv_head_t *bhp, bhv_desc_t *bdp); +extern int bhv_append(bhv_head_t *bhp, bhv_desc_t *bdp); +extern int bhv_truncate(bhv_head_t *bhp, bhv_desc_t *bdp); +#endif +extern void bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp); +extern bhv_desc_t * bhv_lookup(bhv_head_t *bhp, void *ops); +extern bhv_desc_t * bhv_lookup_unlocked(bhv_head_t *bhp, void *ops); +#ifdef CELL_CAPABLE +extern bhv_desc_t * bhv_lookup_range(bhv_head_t *bhp, int lpos, int hpos); +#endif +extern bhv_desc_t * bhv_base_unlocked(bhv_head_t *bhp); + +#ifdef CELL_CAPABLE +extern void bhv_global_init(void); +extern struct zone * bhv_global_zone; +extern void bhv_queue_ucallout(bhv_head_t *bhp, + int flags, bhv_ucallout_t *func, + void *, void *, caddr_t, size_t); +extern void bhv_queue_ucallout_unlocked(bhv_head_t *bhp, + int flags, bhv_ucallout_t *func, + void *, void *, caddr_t, size_t); +#endif /* CELL_CAPABLE */ + +/* + * Prototypes for interruptible sleep requests + * Noop on non-cell kernels. + */ +#ifdef CELL_CAPABLE +#define BLA_ACCESS 0 +#define BLA_UPDATE 1 +#define BLA_RWMASK 1 +#define BLA_TRY 4 +#define BLA_INTERRUPT 8 +#ifdef BLALOG +#define bla_push(mr,rw,ra) CELL_ONLY(_bla_push(mr,rw,ra)) +extern void _bla_push(mrlock_t *mrp, int rw, void *ra); +#else +#define bla_push(mr,rw,ra) CELL_ONLY(_bla_push(mr,rw)) +extern void _bla_push(mrlock_t *mrp, int rw); +#endif +#define bla_pop(mrp) CELL_ONLY(_bla_pop(mrp)) +extern void _bla_pop(mrlock_t *mrp); + +#define bla_isleep() CELL_ONLY(_bla_isleep()) +extern void _bla_isleep(void); + +#define bla_iunsleep() CELL_ONLY(_bla_iunsleep()) +extern void _bla_iunsleep(void); + +#define bla_wait_for_mrlock(mrp) CELL_IF(_bla_wait_for_mrlock(mrp), 0) +extern uint_t _bla_wait_for_mrlock(mrlock_t *mrp); + +#define bla_got_mrlock(rv) CELL_ONLY(_bla_got_mrlock(rv)) +extern void _bla_got_mrlock(uint_t rv); + +#define bla_curlocksheld() \ + CELL_MUST((private.p_blaptr - (curthreadp)->k_blap->kb_lockp)) + +#define bla_klocksheld(kt) \ + CELL_MUST(((kt)->k_blap->kb_lockpp - (kt)->k_blap->kb_lockp)) +#endif + +#endif /* __XFS_BEHAVIOR_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_cred.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_cred.c --- linux-2.4.7/linux/fs/xfs/linux/xfs_cred.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_cred.c Mon Sep 25 00:42:07 2000 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * Global system credential structure. + */ +cred_t sys_cred_val, *sys_cred = &sys_cred_val; + + +/* + * Initialize the global system credential structure. + */ +void +cred_init(void) +{ + memset(sys_cred, 0, sizeof(cred_t)); + + sys_cred->cr_ref = 1; + + sys_cred->cr_cap.cap_effective = CAP_FULL_SET; + sys_cred->cr_cap.cap_inheritable = CAP_FULL_SET; + sys_cred->cr_cap.cap_permitted = CAP_FULL_SET; + + /*_MAC_INIT_CRED();*/ +} + +#if 0 +void +cred_fill_from_current(cred_t *credp) +{ + int i; + + memset(credp, 0, sizeof(cred_t)); + + credp->cr_ref = 1; + + credp->cr_uid = current->fsuid; + credp->cr_gid = current->fsgid; + + credp->cr_ruid = current->uid; + credp->cr_rgid = current->gid; + + credp->cr_suid = current->suid; + credp->cr_sgid = current->suid; + + credp->cr_ngroups = current->ngroups; + + for (i = 0; i < current->ngroups; i++) + credp->cr_groups[i] = current->groups[i]; + + credp->cr_cap.cap_effective = current->cap_effective; + credp->cr_cap.cap_inheritable = current->cap_inheritable; + credp->cr_cap.cap_permitted = current->cap_permitted; +} +#endif diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_cred.h linux-2.4-xfs/linux/fs/xfs/linux/xfs_cred.h --- linux-2.4.7/linux/fs/xfs/linux/xfs_cred.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_cred.h Mon Jan 15 04:28:46 2001 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef __XFS_CRED_H__ +#define __XFS_CRED_H__ + +#include /* For NGROUPS */ +#ifdef __KERNEL__ +#include +#include +#endif + +/* + * Capabilities + */ +typedef __uint64_t cap_value_t; + +typedef struct cap_set { + cap_value_t cap_effective; /* use in capability checks */ + cap_value_t cap_permitted; /* combined with file attrs */ + cap_value_t cap_inheritable;/* pass through exec */ +} cap_set_t; + + +/* + * Mandatory Access Control + * + * Layout of a composite MAC label: + * ml_list contains the list of categories (MSEN) followed by the list of + * divisions (MINT). This is actually a header for the data structure which + * will have an ml_list with more than one element. + * + * ------------------------------- + * | ml_msen_type | ml_mint_type | + * ------------------------------- + * | ml_level | ml_grade | + * ------------------------------- + * | ml_catcount | + * ------------------------------- + * | ml_divcount | + * ------------------------------- + * | category 1 | + * | . . . | + * | category N | (where N = ml_catcount) + * ------------------------------- + * | division 1 | + * | . . . | + * | division M | (where M = ml_divcount) + * ------------------------------- + */ +#define MAC_MAX_SETS 250 +typedef struct mac_label { + unsigned char ml_msen_type; /* MSEN label type */ + unsigned char ml_mint_type; /* MINT label type */ + unsigned char ml_level; /* Hierarchical level */ + unsigned char ml_grade; /* Hierarchical grade */ + unsigned short ml_catcount; /* Category count */ + unsigned short ml_divcount; /* Division count */ + /* Category set, then Division set */ + unsigned short ml_list[MAC_MAX_SETS]; +} mac_label; + +/* Data types required by POSIX P1003.1eD15 */ +typedef struct mac_label * mac_t; + + +/* + * Credentials + */ +typedef struct cred { + int cr_ref; /* reference count */ + ushort cr_ngroups; /* number of groups in cr_groups */ + uid_t cr_uid; /* effective user id */ + gid_t cr_gid; /* effective group id */ + uid_t cr_ruid; /* real user id */ + gid_t cr_rgid; /* real group id */ + uid_t cr_suid; /* "saved" user id (from exec) */ + gid_t cr_sgid; /* "saved" group id (from exec) */ + struct mac_label *cr_mac; /* MAC label for B1 and beyond */ + cap_set_t cr_cap; /* capability (privilege) sets */ + gid_t cr_groups[NGROUPS]; /* supplementary group list */ +} cred_t; + + +#ifdef __KERNEL__ +extern int mac_enabled; +extern mac_label *mac_high_low_lp; +static __inline void mac_never(void) {} +struct xfs_inode; +extern int mac_xfs_iaccess(struct xfs_inode *, mode_t, cred_t *); +#define _MAC_XFS_IACCESS(i,m,c) \ + (mac_enabled? (mac_never(), mac_xfs_iaccess(i,m,c)): 0) +extern int mac_xfs_vaccess(vnode_t *, cred_t *, mode_t); +#define _MAC_VACCESS(v,c,m) \ + (mac_enabled? (mac_never(), mac_xfs_vaccess(v,c,m)): 0) + +#define VREAD 01 +#define VWRITE 02 +#endif /* __KERNEL__ */ + +#define MACWRITE 00200 +#define SGI_MAC_FILE "/dev/null" +#define SGI_MAC_FILE_SIZE 10 +#define SGI_CAP_FILE "/dev/null" +#define SGI_CAP_FILE_SIZE 10 + +/* MSEN label type names. Choose an upper case ASCII character. */ +#define MSEN_ADMIN_LABEL 'A' /* Admin: low + +/* The following stubs are for routines needed for the X/Open + * version of DMAPI. + */ +int +xfs_dm_mount( + vfs_t *vfsp, + vnode_t *mvp, + char *dir_name, + char *fsname) +{ + return nopkg(); +} + +int +dm_send_destroy_event(bhv_desc_t *bdp, dm_right_t vp_right) +{ + return nopkg(); +} + + + +int +dm_send_namesp_event(dm_eventtype_t event, bhv_desc_t *bdp1, + dm_right_t vp1_right, bhv_desc_t *bdp2, dm_right_t vp2_right, + char *name1, char *name2, mode_t mode, int retcode, int flags) +{ + return nopkg(); +} + + +void +dm_send_unmount_event(vfs_t *vfsp, vnode_t *vp, dm_right_t vfsp_right, + mode_t mode, int retcode, int flags) +{ +} diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_file.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_file.c --- linux-2.4.7/linux/fs/xfs/linux/xfs_file.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_file.c Thu May 17 15:53:29 2001 @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include + + +STATIC long long linvfs_file_lseek( + struct file *file, + loff_t offset, + int origin) +{ + struct inode *inode = file->f_dentry->d_inode; + vnode_t *vp; + struct vattr vattr; + loff_t old_off = offset; + int error; + + vp = LINVFS_GET_VP(inode); + + ASSERT(vp); + + switch (origin) { + case 2: + vattr.va_mask = AT_SIZE; + VOP_GETATTR(vp, &vattr, 0, get_current_cred(), error); + if (error) + return -error; + + offset += vattr.va_size; + break; + case 1: + offset += file->f_pos; + } + + /* All for the sake of seeing if we are too big */ + VOP_SEEK(vp, old_off, &offset, error); + + if (error) + return -error; + + if (offset != file->f_pos) { + file->f_pos = offset; + file->f_version = ++event; + file->f_reada = 0; + } + + return offset; +} + +STATIC ssize_t linvfs_read( + struct file *filp, + char *buf, + size_t size, + loff_t *offset) +{ + struct inode *inode; + vnode_t *vp; + int err; + uio_t uio; + iovec_t iov; + + if (!filp || !filp->f_dentry || + !(inode = filp->f_dentry->d_inode)) { + printk("EXIT linvfs_read -EBADF\n"); + return -EBADF; + } + + inode = filp->f_dentry->d_inode; + + vp = LINVFS_GET_VP(inode); + + ASSERT(vp); + + uio.uio_iov = &iov; + uio.uio_offset = *offset; + uio.uio_fp = filp; + uio.uio_iovcnt = 1; + uio.uio_iov->iov_base = buf; + uio.uio_iov->iov_len = uio.uio_resid = size; + + XFS_STATS_INC(xfsstats.xs_read_calls); + XFS_STATS_ADD(xfsstats.xs_read_bytes, size); + + VOP_READ(vp, &uio, 0, NULL, NULL, err); + *offset = uio.uio_offset; + + /* + * If we got a return value, it was an error + * Flip to negative & return that + * Otherwise, return bytes actually read + */ + return(err ? -err : size-uio.uio_resid); +} + + +STATIC ssize_t linvfs_write( + struct file *filp, + const char *buf, + size_t size, + loff_t *offset) +{ + struct inode *inode; + loff_t pos; + vnode_t *vp; + int err; + int pb_flags = 0; /* Flags to pass bmap calls */ + + uio_t uio; + iovec_t iov; + + if (!filp || !filp->f_dentry || + !(inode = filp->f_dentry->d_inode)) { + printk("EXIT linvfs_write -EBADF\n"); + return -EBADF; + } + + inode = filp->f_dentry->d_inode; + + down(&inode->i_sem); + + err = -EINVAL; + + pos = *offset; + if (pos < 0) + goto out; + + err = filp->f_error; + if (err) { + filp->f_error = 0; + goto out; + } + + if (filp->f_flags & O_APPEND) + pos = inode->i_size; + + /* + * Handle O_SYNC writes + * The real work gets done in xfs_write() + */ + + if (filp->f_flags & O_SYNC) { + pb_flags |= PBF_SYNC; + } + + XFS_STATS_INC(xfsstats.xs_write_calls); + XFS_STATS_ADD(xfsstats.xs_write_bytes, size); + + vp = LINVFS_GET_VP(inode); + + ASSERT(vp); + + uio.uio_iov = &iov; + uio.uio_offset = pos; + uio.uio_fp = filp; + uio.uio_iovcnt = 1; + uio.uio_iov->iov_base = (void *)buf; + uio.uio_iov->iov_len = uio.uio_resid = size; + + VOP_WRITE(vp, &uio, pb_flags, NULL, NULL, err); + *offset = pos = uio.uio_offset; + +out: + up(&inode->i_sem); + + /* + * If we got a return value, it was an error + * Flip to negative & return that + * Otherwise, return bytes actually written + */ + + return(err ? -err : size-uio.uio_resid); +} + + +STATIC int linvfs_open( + struct inode *inode, + struct file *filp) +{ + vnode_t *vp = LINVFS_GET_VP(inode); + vnode_t *newvp; + int error; + + ASSERT(vp); + + VOP_OPEN(vp, &newvp, 0, get_current_cred(), error); + + return -error; +} + + +STATIC int linvfs_release( + struct inode *inode, + struct file *filp) +{ + vnode_t *vp = LINVFS_GET_VP(inode); + int error = 0; + + if (vp) { + VOP_RELEASE(vp, error); + } + + return -error; +} + + +STATIC int linvfs_fsync( + struct file *filp, + struct dentry *dentry, + int datasync) +{ + struct inode *inode = dentry->d_inode; + vnode_t *vp = LINVFS_GET_VP(inode); + int error; + int flags = FSYNC_WAIT; + + if (datasync) + flags |= FSYNC_DATA; + + ASSERT(vp); + + VOP_FSYNC(vp, flags, get_current_cred(), + (off_t)0, (off_t)-1, error); + + if (error) + return -error; + + return 0; +} + +/* + * linvfs_readdir maps to VOP_READDIR(). + * We need to build a uio, cred, ... + */ + +#define nextdp(dp) ((struct xfs_dirent *)((char *)(dp) + (dp)->d_reclen)) + +STATIC int linvfs_readdir( + struct file *filp, + void *dirent, + filldir_t filldir) +{ + int error = 0; + vnode_t *vp; + uio_t uio; + iovec_t iov; + int eof = 0; + cred_t cred; /* Temporary cred workaround */ + caddr_t read_buf; + int namelen, size = 0; + size_t rlen = PAGE_CACHE_SIZE << 2; + off_t start_offset; + xfs_dirent_t *dbp = NULL; + + vp = LINVFS_GET_VP(filp->f_dentry->d_inode); + + ASSERT(vp); + /* Try fairly hard to get memory */ + do { + if ((read_buf = (caddr_t)kmalloc(rlen, GFP_KERNEL))) + break; + rlen >>= 1; + } while (rlen >= 1024); + + if (read_buf == NULL) + return -ENOMEM; + + uio.uio_iov = &iov; + uio.uio_fmode = filp->f_mode; + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_offset = filp->f_pos; + + while (!eof) { + uio.uio_resid = iov.iov_len = rlen; + iov.iov_base = read_buf; + uio.uio_iovcnt = 1; + + start_offset = uio.uio_offset; + + VOP_READDIR(vp, &uio, &cred, &eof, error); + if ((uio.uio_offset == start_offset) || error) { + size = 0; + break; + } + + size = rlen - uio.uio_resid; + dbp = (xfs_dirent_t *)read_buf; + while (size > 0) { + namelen = strlen(dbp->d_name); + + if (filldir(dirent, dbp->d_name, namelen, + (off_t) dbp->d_off, + (linux_ino_t) dbp->d_ino, + DT_UNKNOWN)) { + goto done; + } + size -= dbp->d_reclen; + dbp = nextdp(dbp); + } + } +done: + if (!error) { + if (size == 0) + filp->f_pos = uio.uio_offset; + else if (dbp) + filp->f_pos = dbp->d_off; + } + + kfree(read_buf); + return -error; +} + + +int linvfs_generic_file_mmap(struct file *filp, struct vm_area_struct *vma) +{ + vnode_t *vp; + int ret; + + /* this will return a (-) error so flip */ + ret = -generic_file_mmap(filp, vma); + if (!ret) { + vattr_t va, *vap; + + vap = &va; + vap->va_mask = AT_UPDATIME; + + vp = LINVFS_GET_VP(filp->f_dentry->d_inode); + + ASSERT(vp); + + VOP_SETATTR(vp, vap, AT_UPDATIME, NULL, ret); + } + return(-ret); +} + + +STATIC int linvfs_ioctl( + struct inode *inode, + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + int error; + vnode_t *vp = LINVFS_GET_VP(inode); + + + ASSERT(vp); + + VOP_IOCTL(vp, inode, filp, cmd, arg, error); + VMODIFY(vp); + + /* NOTE: some of the ioctl's return positive #'s as a + * byte count indicating success, such as + * readlink_by_handle. So we don't "sign flip" + * like most other routines. This means true + * errors need to be returned as a negative value. + */ + return error; +} + + +struct file_operations linvfs_file_operations = +{ + llseek: linvfs_file_lseek, + read: linvfs_read, + write: linvfs_write, + ioctl: linvfs_ioctl, + mmap: linvfs_generic_file_mmap, + open: linvfs_open, + release: linvfs_release, + fsync: linvfs_fsync, +}; + +struct file_operations linvfs_dir_operations = { + read: generic_read_dir, + readdir: linvfs_readdir, + ioctl: linvfs_ioctl, + fsync: linvfs_fsync, +}; + + diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_fs_subr.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_fs_subr.c --- linux-2.4.7/linux/fs/xfs/linux/xfs_fs_subr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_fs_subr.c Mon Mar 5 10:47:52 2001 @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * Implementation for VFS_DOUNMOUNT. + */ +int +fs_dounmount( + bhv_desc_t *bdp, + int flags, + vnode_t *rootvp, + cred_t *cr) +{ + struct vfs *vfsp = bhvtovfs(bdp); + bhv_desc_t *fbdp = vfsp->vfs_fbhv; + int error; + + /* + * Wait for sync to finish and lock vfsp. This also sets the + * VFS_OFFLINE flag. Once we do this we can give up reference + * the root vnode which we hold to avoid the another unmount + * ripping the vfs out from under us before we get to lock it. + * The VFS_DOUNMOUNT calling convention is that the reference + * on the rot vnode is released whether the call succeeds or + * fails. + */ + error = vfs_lock_offline(vfsp); + if (rootvp) + VN_RELE(rootvp); + if (error) + return error; + + /* + * Now invoke SYNC and UNMOUNT ops, using the PVFS versions is + * OK since we already have a behavior lock as a result of + * being in VFS_DOUNMOUNT. It is necessary to do things this + * way since using the VFS versions would cause us to get the + * behavior lock twice which can cause deadlock as well as + * making the coding of vfs relocation unnecessarilty difficult + * by making relocations invoked by unmount occur in a different + * environment than those invoked by mount-update. + */ + PVFS_SYNC(fbdp, SYNC_ATTR|SYNC_DELWRI|SYNC_NOWAIT, cr, error); + if (error == 0) + PVFS_UNMOUNT(fbdp, flags, cr, error); + + if (error) { + vfs_unlock(vfsp); /* clears VFS_OFFLINE flag, too */ + } + return error; +} + +/* + * Stub for no-op vnode operations that return error status. + */ +int +fs_noerr() +{ + return 0; +} + +/* + * Operation unsupported under this file system. + */ +int +fs_nosys() +{ + return ENOSYS; +} + +/* + * Stub for inactive, strategy, and read/write lock/unlock. Does nothing. + */ +/* ARGSUSED */ +void +fs_noval() +{ +} + +/* + * Change state of vnode itself. + * + * This routine may or may not require that the caller(s) prohibit + * simultaneous changes to a given piece of state. This depends + * on the particular 'cmd' - and individual commands should assert + * appropriately if they so desire. + */ +void +fs_vnode_change( + bhv_desc_t *bdp, + vchange_t cmd, + __psint_t val) +{ +// printk("XFS: fs_vnode_change() NOT IMPLEMENTED\n"); +} + + +/* + * vnode pcache layer for vnode_tosspages. + * 'last' parameter unused but left in for IRIX compatibility + */ +void +fs_tosspages( + bhv_desc_t *bdp, + xfs_off_t first, + xfs_off_t last, + int fiopt) +{ + vnode_t *vp = BHV_TO_VNODE(bdp); + + if (vp->v_inode && VN_CACHED(vp)) + pagebuf_inval(vp->v_inode, first, 0); +} + + +/* + * vnode pcache layer for vnode_flushinval_pages. + * 'last' parameter unused but left in for IRIX compatibility + */ +void +fs_flushinval_pages( + bhv_desc_t *bdp, + xfs_off_t first, + xfs_off_t last, + int fiopt) +{ + vnode_t *vp = BHV_TO_VNODE(bdp); + + if (vp->v_inode && VN_CACHED(vp)) + pagebuf_flushinval(vp->v_inode, first, 0); +} + + + +/* + * vnode pcache layer for vnode_flush_pages. + * 'last' parameter unused but left in for IRIX compatibility + */ +int +fs_flush_pages( + bhv_desc_t *bdp, + xfs_off_t first, + xfs_off_t last, + uint64_t flags, + int fiopt) +{ + vnode_t *vp = BHV_TO_VNODE(bdp); + + if (vp->v_inode && VN_CACHED(vp)) + pagebuf_flush(vp->v_inode, first, 0); + return 0; +} + + +/* + * vnode pcache layer for vnode_pages_sethole. + */ +void +fs_pages_sethole( + bhv_desc_t *bdp, + void *pfd, + int cnt, + int doremap, + xfs_off_t remap_offset) +{ + printk("XFS: fs_pages_sethole() NOT IMPLEMENTED\n"); +} + +#ifdef CELL_CAPABLE +EXPORT_SYMBOL(fs_noerr); +EXPORT_SYMBOL(fs_nosys); +EXPORT_SYMBOL(fs_nodev); +EXPORT_SYMBOL(fs_noval); +EXPORT_SYMBOL(fs_vnode_change); +EXPORT_SYMBOL(fs_dounmount); +EXPORT_SYMBOL(fs_tosspages); +EXPORT_SYMBOL(fs_flushinval_pages); +EXPORT_SYMBOL(fs_flush_pages); +EXPORT_SYMBOL(fs_pages_sethole); +#endif diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_fs_subr.h linux-2.4-xfs/linux/fs/xfs/linux/xfs_fs_subr.h --- linux-2.4.7/linux/fs/xfs/linux/xfs_fs_subr.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_fs_subr.h Wed Dec 13 00:02:07 2000 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUBR_H__ +#define __XFS_SUBR_H__ + +/* + * Utilities shared among file system implementations. + */ + +extern int fs_noerr(void); +extern int fs_nosys(void); +extern int fs_nodev(void); +extern void fs_noval(void); +extern void fs_vnode_change(bhv_desc_t *, vchange_t, __psint_t); +extern int fs_dounmount(bhv_desc_t *, int, vnode_t *, cred_t *); +extern void fs_tosspages(bhv_desc_t *, xfs_off_t, xfs_off_t, int); +extern void fs_flushinval_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, int); +extern int fs_flush_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, uint64_t, int); +extern void fs_pages_sethole(bhv_desc_t *, void*, int, int, xfs_off_t); + +#endif /* __XFS_FS_SUBR_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_globals.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_globals.c --- linux-2.4.7/linux/fs/xfs/linux/xfs_globals.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_globals.c Mon Feb 26 20:43:46 2001 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * This file contains globals needed by XFS that were normally defined + * somewhere else in IRIX. + */ + +#include + +int mac_enabled = 0; +int xpg4_sticky_dir = 1; /* see xfs_stickytest */ +int xfs_fstype; +uint64_t xfs_panic_mask; /* set to cause more panics */ + +int restricted_chown = 0; +int scache_linemask = 0x1f; /* second level cache line size mask */ +prid_t dfltprid; +unsigned long physmem; +int ndquot; diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_globals.h linux-2.4-xfs/linux/fs/xfs/linux/xfs_globals.h --- linux-2.4.7/linux/fs/xfs/linux/xfs_globals.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_globals.h Mon Feb 26 20:43:46 2001 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_GLOBALS_H__ +#define __XFS_GLOBALS_H__ + +/* + * This file declares globals needed by XFS that were normally defined + * somewhere else in IRIX. + */ + +extern int mac_enabled; +extern int acl_enabled; +extern int xpg4_sticky_dir; /* see xfs_stickytest */ +extern int xfs_fstype; +extern uint64_t xfs_panic_mask; /* set to cause more panics */ + +extern int restricted_chown; +extern int scache_linemask; /* second level cache line size mask */ +extern prid_t dfltprid; +extern unsigned long physmem; +extern int ndquot; + +#endif /* __XFS_GLOBALS_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_griostubs.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_griostubs.c --- linux-2.4.7/linux/fs/xfs/linux/xfs_griostubs.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_griostubs.c Mon Sep 25 00:42:07 2000 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +/* + * Grio driver stubs. + */ + +#include + +void grio_iodone(xfs_buf_t *bp) +{ +} + +int grio_strategy(xfs_buf_t *bp) +{ + return pagebuf_iorequest(bp); +} + +int grio_config(sysarg_t a0, sysarg_t a1, sysarg_t a2, sysarg_t a3, sysarg_t a4) +{ + return(ENOSYS); +} + +int grio_monitor_io_start(stream_id_t *stream_id, __int64_t iosize) +{ + return(-1); +} + +int grio_monitor_io_end(stream_id_t *stream_id, int index) +{ + return(-1); +} + +int grio_remove_reservation_with_fp(void) +{ + return(-1); +} + +int grio_io_is_guaranteed(struct file *fp, stream_id_t *stream_id) +{ + return -1; +} diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_ioctl.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_ioctl.c --- linux-2.4.7/linux/fs/xfs/linux/xfs_ioctl.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_ioctl.c Fri Jun 22 15:35:18 2001 @@ -0,0 +1,1329 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include + + +/* + * The "open_by_handle() & readlink_by_handle() ioctl's + * require 'root', or 'SysAdmin' capabilies. + * To change to a simple 'permission' test, + * uncomment the following #define. + */ +/* #define PERMISSIONS_BY_USER */ + + +int +xfs_getattr( + bhv_desc_t *bdp, + vattr_t *vap, + int flags, + cred_t *credp); + +int +xfs_setattr( + bhv_desc_t *bdp, + vattr_t *vap, + int flags, + cred_t *credp); + +int +xfs_set_dmattrs ( + bhv_desc_t *bdp, + u_int evmask, + u_int16_t state, + cred_t *credp); + +int +xfs_get_uiosize( + xfs_mount_t *mp, + xfs_inode_t *ip, + struct biosize *bs, + cred_t *credp); + +int +xfs_set_uiosize( + xfs_mount_t *mp, + xfs_inode_t *ip, + uint flags, + int read_iosizelog, + int write_iosizelog, + cred_t *credp); + +int +xfs_change_file_space( + bhv_desc_t *bdp, + int cmd, + xfs_flock64_t *bf, + xfs_off_t offset, + cred_t *credp, + int attr_flags); + + +/* + * xfs_find_handle: map from userspace xfs_fsop_handlereq structure to + * a file or fs handle - used for XFS_IOC_PATH_TO_FSHANDLE, + * XFS_IOC_PATH_TO_HANDLE and XFS_IOC_FD_TO_HANDLE. + */ + +int +xfs_find_handle( + unsigned int cmd, + unsigned long arg) +{ + int hsize; + xfs_handle_t handle; + xfs_fsop_handlereq_t hreq; + struct inode *inode; + struct vnode *vp; + int only_fsid; + + /* read handle request from user */ + if (copy_from_user(&hreq, (struct xfs_fsop_handlereq *)arg, + sizeof(struct xfs_fsop_handlereq))) + return -XFS_ERROR(EFAULT); + + /* zero our handle */ + bzero((char *)&handle, sizeof(handle)); + + /* now we need the inode in question */ + only_fsid=0; + switch (cmd) { + case XFS_IOC_PATH_TO_FSHANDLE: + only_fsid=1; + /* fallthrough */ + case XFS_IOC_PATH_TO_HANDLE: { + struct nameidata nd; + char *path; + int error; + + /* we need the path */ + path = getname(hreq.path); + if (IS_ERR(path)) + return PTR_ERR(path); + + /* traverse the path */ + error = 0; + if (path_init(path, LOOKUP_POSITIVE, &nd)) + error = path_walk(path, &nd); + putname(path); + if (error) + return error; + + ASSERT(nd.dentry); + ASSERT(nd.dentry->d_inode); + inode = igrab(nd.dentry->d_inode); + path_release(&nd); + + break; + } + + case XFS_IOC_FD_TO_HANDLE: { + struct file * file; + + file = fget(hreq.fd); + if (!file) + return -EBADF; + + ASSERT(file->f_dentry); + ASSERT(file->f_dentry->d_inode); + inode = igrab(file->f_dentry->d_inode); + fput(file); + + break; + } + + default: + ASSERT(0); + return -XFS_ERROR(EINVAL); + } + + /* we need the vnode */ + vp = LINVFS_GET_VP(inode); + if (!vp || !vp->v_vfsp->vfs_altfsid) { + /* we're not in XFS anymore, Toto */ + iput(inode); + return -XFS_ERROR(EINVAL); + } + if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) { + iput(inode); + return -XFS_ERROR(EBADF); + } + + /* now we can grab the fsid */ + memcpy(&handle.ha_fsid, vp->v_vfsp->vfs_altfsid, sizeof(xfs_fsid_t)); + hsize = sizeof(xfs_fsid_t); + + if (!only_fsid) { + xfs_inode_t *ip; + bhv_desc_t *bhv; + int lock_mode; + + /* we need to get access to the xfs_inode to read the generation */ + + VN_BHV_READ_LOCK(&(vp)->v_bh); + bhv = VNODE_TO_FIRST_BHV(vp); + ASSERT(bhv); + ip = XFS_BHVTOI(bhv); + ASSERT(ip); + lock_mode = xfs_ilock_map_shared(ip); + + /* fill in fid section of handle from inode */ + + handle.ha_fid.xfs_fid_len = sizeof(xfs_fid_t) - + sizeof(handle.ha_fid.xfs_fid_len); + handle.ha_fid.xfs_fid_pad = 0; + handle.ha_fid.xfs_fid_gen = ip->i_d.di_gen; + handle.ha_fid.xfs_fid_ino = ip->i_ino; + + xfs_iunlock_map_shared(ip, lock_mode); + VN_BHV_READ_UNLOCK(&(vp)->v_bh); + + hsize = XFS_HSIZE(handle); + } + + /* now copy our handle into the user buffer & write out the size */ + if (copy_to_user((xfs_handle_t *)hreq.ohandle, &handle, hsize) || + copy_to_user(hreq.ohandlen, &hsize, sizeof(__s32))) { + iput(inode); + return -XFS_ERROR(EFAULT); + } + + iput(inode); + return 0; +} + + +int +xfs_open_by_handle( + unsigned int cmd, + unsigned long arg, + struct file *parfilp, + struct inode *parinode, + vfs_t *vfsp, + xfs_mount_t *mp) +{ + int error; + int new_fd; + int permflag; + __u32 igen; + struct dentry *dentry = NULL; + struct file *filp = NULL; + struct inode *inode = NULL; + struct list_head *lp; + void *hanp; + size_t hlen; + ino_t ino; + xfs_fid_t *xfid; + xfs_handle_t *handlep; + xfs_handle_t handle; + xfs_fsop_handlereq_t hreq; + xfs_inode_t *ip; + +#ifndef PERMISSIONS_BY_USER + /* + * Only allow Sys Admin capable users. + */ + if (! capable(CAP_SYS_ADMIN)) + return -EPERM; + +#endif /* ! PERMISSIONS_BY_USER */ + + /* + * Only allow handle opens under a directory. + */ + if ( !S_ISDIR(parinode->i_mode) ) + return -ENOTDIR; + + /* + * Copy the handle down from the user and validate + * that it looks to be in the correct format. + */ + if (copy_from_user(&hreq, (struct xfs_fsop_handlereq *)arg, + sizeof(struct xfs_fsop_handlereq))) + return -XFS_ERROR(EFAULT); + + hanp = hreq.ihandle; + hlen = hreq.ihandlen; + + handlep = &handle; + + /* + * gethandle(hanp, hlen, &handle) + */ + if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep)) + return -XFS_ERROR(EINVAL); + + if (copy_from_user(handlep, hanp, hlen)) + return -XFS_ERROR(EFAULT); + + if (hlen < sizeof(*handlep)) + bzero(((char *)handlep) + hlen, + sizeof(*handlep) - hlen); + + if (hlen > sizeof(handlep->ha_fsid)) { + + if ( handlep->ha_fid.xfs_fid_len != + (hlen - sizeof(handlep->ha_fsid) + - sizeof(handlep->ha_fid.xfs_fid_len)) + || handlep->ha_fid.xfs_fid_pad) { + + return -XFS_ERROR(EINVAL); + } + } + + + /* + * Crack the handle, obtain the inode # & generation # + */ + + xfid = (struct xfs_fid *)&handlep->ha_fid; + + if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) { + ino = xfid->xfs_fid_ino; + igen = xfid->xfs_fid_gen; + } else { + /* + * Invalid. Since handles can be created in user + * space and passed in, this is not cause for a panic. + */ + return -XFS_ERROR(EINVAL); + } + + /* + * Get the XFS inode, building a vnode to go with it. + */ + error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, 0); + + if (error) + return -error; + + if (ip == NULL) + return -XFS_ERROR(EIO); + + if (ip->i_d.di_mode == 0 || ip->i_d.di_gen != igen) { + + xfs_iput(ip, XFS_ILOCK_SHARED); + + return -XFS_ERROR(ENOENT); + } + + inode = XFS_ITOV(ip)->v_inode; + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + linvfs_set_inode_ops(inode); + error = linvfs_revalidate_core(inode, ATTR_COMM); + if (error) { + iput(inode); + return -XFS_ERROR(error); + } + + /* + * Restrict handle operations to directories & regular files. + */ + if (! (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)) ) { + iput(inode); + return -XFS_ERROR(EINVAL); + } + + /* + * Put open permission in namei format. + */ + permflag = hreq.oflags; + if ((permflag+1) & O_ACCMODE) + permflag++; + if (permflag & O_TRUNC) + permflag |= 2; + + /* + * Can't write directories. + */ + if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) { + iput(inode); + return -XFS_ERROR(EISDIR); + } + + /* + * Create new_fd + */ + if ((new_fd = get_unused_fd()) < 0) { + iput(inode); + return new_fd; + } + + /* now to find a dentry. + * If possible, get a well-connected one + */ + spin_lock(&dcache_lock); + for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) { + dentry = list_entry(lp,struct dentry, d_alias); + if (! (dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) { + dget_locked(dentry); + spin_unlock(&dcache_lock); + iput(inode); + goto found; + } + } + spin_unlock(&dcache_lock); + + /* + * ELSE didn't find dentry Create anonymous dcache entry. + */ + dentry = d_alloc_root(inode); + if (dentry == NULL) { + iput(inode); + put_unused_fd(new_fd); + return -XFS_ERROR(ENOMEM); + } + + /* + * Keep nfsd happy. + */ + dentry->d_flags |= DCACHE_NFSD_DISCONNECTED; + + /* + * Make sure dput can find this dcache entry. + */ + d_rehash(dentry); + + found: + /* + * Make sure umount returns an EBUSY on umounts while this file is open. + */ + mntget(parfilp->f_vfsmnt); + + /* + * Create file pointer. + */ + filp = dentry_open(dentry, parfilp->f_vfsmnt, hreq.oflags); + if (IS_ERR(filp)) { + dput(dentry); + put_unused_fd(new_fd); + return -XFS_ERROR(-PTR_ERR(filp)); + } + +#ifdef PERMISSIONS_BY_USER + /* + * Do permission/write checks + */ + permflag = 0; + + if (filp->f_mode & FMODE_READ) + permflag |= MAY_READ; + + if (filp->f_mode & FMODE_WRITE) + permflag |= MAY_WRITE; + + if (error = permission(inode, permflag)) { + put_unused_fd(new_fd); + fput(filp); + return -XFS_ERROR(-error); + + } +#endif /* PERMISSIONS_BY_USER */ + + fd_install(new_fd, filp); + + return new_fd; +} + + +int +xfs_readlink_by_handle( + unsigned int cmd, + unsigned long arg, + struct file *parfilp, + struct inode *parinode, + vfs_t *vfsp, + xfs_mount_t *mp) +{ + int error; + int rlsize; + __u32 igen; + struct iovec aiov; + struct uio auio; + void *hanp; + size_t hlen; + vnode_t *vp = NULL; + struct inode *inode = NULL; + xfs_fid_t *xfid; + xfs_handle_t *handlep; + xfs_handle_t handle; + xfs_ino_t ino; + xfs_inode_t *ip = NULL; + xfs_fsop_handlereq_t hreq; + __u32 olen; + +#ifndef PERMISSIONS_BY_USER + /* + * Only allow Sys Admin capable users. + */ + if (! capable(CAP_SYS_ADMIN)) + return -EPERM; + +#endif /* ! PERMISSIONS_BY_USER */ + + /* + * Only allow handle opens under a directory. + */ + if ( !S_ISDIR(parinode->i_mode) ) + return -ENOTDIR; + + /* + * Copy the handle down from the user and validate + * that it looks to be in the correct format. + */ + if (copy_from_user(&hreq, (struct xfs_fsop_handlereq *)arg, + sizeof(struct xfs_fsop_handlereq))) + return -XFS_ERROR(EFAULT); + + hanp = hreq.ihandle; + hlen = hreq.ihandlen; + + handlep = &handle; + + /* + * gethandle(hanp, hlen, &handle) + */ + if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep)) + return -XFS_ERROR(EINVAL); + + if (copy_from_user(handlep, hanp, hlen)) + return -XFS_ERROR(EFAULT); + + if (hlen < sizeof(*handlep)) + bzero(((char *)handlep) + hlen, + sizeof(*handlep) - hlen); + + if (hlen > sizeof(handlep->ha_fsid)) { + + if ( handlep->ha_fid.xfs_fid_len != + (hlen - sizeof(handlep->ha_fsid) + - sizeof(handlep->ha_fid.xfs_fid_len)) + || handlep->ha_fid.xfs_fid_pad) { + + return -XFS_ERROR(EINVAL); + } + } + + + /* + * Crack the handle, obtain the inode # & generation # + */ + + /* + * handle_to_vp(&handle) + * VFS_VGET (vfsp, &vp, &handlep->ha_fid, error) + * bdp, **vp, fidp; + */ + xfid = (struct xfs_fid *)&handlep->ha_fid; + + if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) { + ino = xfid->xfs_fid_ino; + igen = xfid->xfs_fid_gen; + } else { + /* + * Invalid. Since handles can be created in user + * space and passed in via gethandle(), this is not + * cause for a panic. + */ + return -XFS_ERROR(EINVAL); + } + + + /* + * Get the XFS inode, building a vnode to go with it. + */ + error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, 0); + + if (error) + return -error; + + if (ip == NULL) + return -XFS_ERROR(EIO); + + if (ip->i_d.di_mode == 0 || ip->i_d.di_gen != igen) { + + xfs_iput(ip, XFS_ILOCK_SHARED); + + return -XFS_ERROR(ENOENT); + } + + vp = XFS_ITOV(ip); + + inode = vp->v_inode; + xfs_iunlock(ip, XFS_ILOCK_SHARED); + linvfs_set_inode_ops(inode); + error = linvfs_revalidate_core(inode, ATTR_COMM); + + + /* + * Restrict handle operations to symlinks. + */ + if (vp->v_type != VLNK) { + VN_RELE(vp); + + return -XFS_ERROR(EINVAL); + } + + aiov.iov_base = hreq.ohandle; + + + if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) + return -XFS_ERROR(EFAULT); + aiov.iov_len = olen; + + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_fmode = FINVIS; + auio.uio_offset = 0; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_resid = olen; + + vp = XFS_ITOV(ip); + VOP_READLINK(vp, &auio, get_current_cred(), error); + + VN_RELE(vp); + + rlsize = olen - auio.uio_resid; + + return rlsize; +} + + +int +xfs_attrctl_by_handle( + unsigned int cmd, + unsigned long arg, + struct file *parfilp, + struct inode *parinode, + vfs_t *vfsp, + xfs_mount_t *mp) +{ +#ifdef CONFIG_HAVE_ATTRCTL + int error; + xfs_fsop_attr_handlereq_t attr_hreq; + xfs_fsop_handlereq_t hreq; + attr_op_t *ops; + void *hanp; + size_t hlen; + xfs_handle_t handle; + xfs_handle_t *handlep; + xfs_fid_t *xfid; + xfs_ino_t xinode; + xfs_inode_t *xip = NULL; + __u32 xigen; + vnode_t *vp = NULL; + struct inode *inode = NULL; + + +#ifndef PERMISSIONS_BY_USER + /* + * Only allow Sys Admin capable users. + */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + +#endif /* !PERMISSIONS_BY_USER */ + + /* + * Only allow handle opens under a directory. + */ + if (!S_ISDIR(parinode->i_mode)) + return -ENOTDIR; + + /* + * Copy the compound attribute/handle structure down. + */ + if (copy_from_user(&attr_hreq, (struct xfs_fsop_attr_handlereq *)arg, + sizeof(struct xfs_fsop_attr_handlereq))) + return -XFS_ERROR(EFAULT); + + /* + * Now copy the handle down from the user and validate + * that it looks to be in the correct format. + */ + if (copy_from_user(&hreq, (struct xfs_fsop_handlereq *)attr_hreq.hreq, + sizeof(struct xfs_fsop_handlereq))) + return -XFS_ERROR(EFAULT); + + if (!attr_hreq.ops) + return -XFS_ERROR(EINVAL); + + hanp = hreq.ihandle; + hlen = hreq.ihandlen; + handlep = &handle; + + if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep)) + return -XFS_ERROR(EINVAL); + + if (copy_from_user(handlep, hanp, hlen)) + return -XFS_ERROR(EFAULT); + + if (hlen < sizeof(*handlep)) + bzero(((char *)handlep) + hlen, sizeof(*handlep) - hlen); + + if (hlen > sizeof(handlep->ha_fsid)) { + + if (handlep->ha_fid.xfs_fid_len != + (hlen - sizeof(handlep->ha_fsid) + - sizeof(handlep->ha_fid.xfs_fid_len)) + || handlep->ha_fid.xfs_fid_pad) { + + return -XFS_ERROR(EINVAL); + } + } + + + /* + * Crack the handle, obtain the inode # & generation # + */ + + xfid = (struct xfs_fid *)&handlep->ha_fid; + + if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) { + xinode = xfid->xfs_fid_ino; + xigen = xfid->xfs_fid_gen; + } else { + /* + * Invalid. Since handles can be created in user + * space and passed in via gethandle(), this is not + * cause for a panic. + */ + return -XFS_ERROR(EINVAL); + } + + + /* get the xfs inode */ + error = xfs_iget(mp, NULL, xinode, XFS_ILOCK_SHARED, &xip, 0); + + if (error) + return -error; + + if (xip == NULL) + return -XFS_ERROR(EIO); + + if (xip->i_d.di_mode == 0 || xip->i_d.di_gen != xigen) { + xfs_iput(xip, XFS_ILOCK_SHARED); + return -XFS_ERROR(ENOENT); + } + + /* get vnode and linux inode */ + vp = XFS_ITOV(xip); + inode = LINVFS_GET_IP(vp); + + xfs_iunlock(xip, XFS_ILOCK_SHARED); + + + /* Copyin and hand off to VFS */ + lock_kernel(); + error = -EINVAL; + + /* allocate space for attribute ops */ + ops = (attr_op_t *) kmalloc(attr_hreq.count * sizeof(attr_op_t), GFP_KERNEL); + + if (!ops) { + error = -ENOMEM; + goto unlock; + } + + if (copy_from_user(ops, attr_hreq.ops, attr_hreq.count * sizeof(attr_op_t)) != 0) { + error = -EFAULT; + goto free_mem; + } + + UPDATE_ATIME(inode); + + /* call through to the vfs: note we know this is an XFS inode */ + error = inode->i_op->attrctl(inode, ops, attr_hreq.count); + + VN_RELE(vp); + + if (copy_to_user(attr_hreq.ops, ops, attr_hreq.count * sizeof(attr_op_t)) != 0) { + error = -EFAULT; + goto free_mem; + } + + free_mem: + kfree(ops); + + unlock: + unlock_kernel(); + return error; +#else /* !CONFIG_HAVE_ATTRCTL */ + return -ENOSYS; +#endif /* CONFIG_HAVE_ATTRCTL */ +} + + +int +xfs_ioctl( + bhv_desc_t *bdp, + struct inode *inode, + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + int error; + struct biosize bs; + struct dioattr da; + struct fsdmidata dmi; + struct fsxattr fa; + cred_t cred; /* Temporary cred workaround */ + vattr_t va; + vnode_t *vp; + vfs_t *vfsp; + xfs_fsop_geom_t fsgeo; + xfs_flock64_t bf; + xfs_inode_t *ip; + xfs_mount_t *mp; + + vp = LINVFS_GET_VN_ADDRESS(inode); + + ASSERT(vp); + + vn_trace_entry(vp, "xfs_ioctl", (inst_t *)__return_address); + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + vfsp = LINVFS_GET_VFS(inode->i_sb); + + ASSERT(vfsp); + + switch (cmd) { + case XFS_IOC_ALLOCSP: + case XFS_IOC_FREESP: + + case XFS_IOC_RESVSP: + case XFS_IOC_UNRESVSP: + + case XFS_IOC_ALLOCSP64: + case XFS_IOC_FREESP64: + + case XFS_IOC_RESVSP64: + case XFS_IOC_UNRESVSP64: { + int attr_flags; + + if (filp->f_flags & O_RDONLY) + return -XFS_ERROR(EBADF); + + if (vp->v_type != VREG) + return -XFS_ERROR(EINVAL); + + if (copy_from_user(&bf, (xfs_flock64_t *)arg, + sizeof(xfs_flock64_t))) + return -XFS_ERROR(EFAULT); + + attr_flags = (filp->f_flags & (O_NDELAY|O_NONBLOCK)) + ? ATTR_NONBLOCK : 0; + + if (filp->f_flags & O_INVISIBLE) + attr_flags |= ATTR_DMI; + + error = xfs_change_file_space(bdp, cmd, &bf, filp->f_pos, + &cred, attr_flags); + if (error) + return -error; + + return 0; + } + + case XFS_IOC_DIOINFO: + da.d_miniosz = mp->m_sb.sb_blocksize; + + da.d_mem = 512; + + /* + * this only really needs to be BBSIZE. + * it is set to the file system block size to + * avoid having to do block zeroing on short writes. + */ + da.d_maxiosz = XFS_FSB_TO_B(mp, + XFS_B_TO_FSBT(mp, pagebuf_max_direct())); + + if (copy_to_user((struct dioattr *)arg, &da, + sizeof(struct dioattr))) + return -XFS_ERROR(EFAULT); + + return 0; + + case XFS_IOC_FSBULKSTAT_SINGLE: + case XFS_IOC_FSBULKSTAT: { + int count; /* # of records returned */ + xfs_ino_t inlast; /* last inode number */ + int done; /* = 1 if there are more + * stats to get and if + * bulkstat should be called + * again. + * This is unused in syssgi + * but used in dmi */ + xfs_fsop_bulkreq_t bulkreq; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&bulkreq, (xfs_fsop_bulkreq_t *)arg, + sizeof(xfs_fsop_bulkreq_t))) + return -XFS_ERROR(EFAULT); + + if (copy_from_user(&inlast, (__s64 *)bulkreq.lastip, + sizeof(__s64))) + return -XFS_ERROR(EFAULT); + + if ((count = bulkreq.icount) <= 0) + return -XFS_ERROR(EINVAL); + + if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) { + error = xfs_bulkstat_single(mp, &inlast, + bulkreq.ubuffer, &done); + } else { + if (count == 1 && inlast != 0) { + inlast++; + + error = xfs_bulkstat_single(mp, &inlast, + bulkreq.ubuffer, &done); + } else { + error = xfs_bulkstat(mp, NULL, &inlast, &count, + (bulkstat_one_pf)xfs_bulkstat_one, + sizeof(xfs_bstat_t), bulkreq.ubuffer, + BULKSTAT_FG_QUICK, &done); + } + } + + if (error) + return -error; + + if (bulkreq.ocount != NULL) { + if (copy_to_user((xfs_ino_t *)bulkreq.lastip, &inlast, + sizeof(xfs_ino_t))) + return -XFS_ERROR(EFAULT); + + if (copy_to_user((__s32 *)bulkreq.ocount, &count, + sizeof(count))) + return -XFS_ERROR(EFAULT); + } + + return 0; + } + + case XFS_IOC_FSGEOMETRY: + error = xfs_fs_geometry(mp, &fsgeo, 3); + + if (error) + return -error; + + if (copy_to_user((xfs_fsop_geom_t *)arg, &fsgeo, + sizeof(xfs_fsop_geom_t))) + return -XFS_ERROR(EFAULT); + + return 0; + + case XFS_IOC_FSGETXATTR: + va.va_mask = AT_XFLAGS|AT_EXTSIZE|AT_NEXTENTS; + + error = xfs_getattr(bdp, &va, 0, &cred); + + if (error) + return -error; + + fa.fsx_xflags = va.va_xflags; + fa.fsx_extsize = va.va_extsize; + fa.fsx_nextents = va.va_nextents; + + if (copy_to_user((struct fsxattr *)arg, &fa, + sizeof(struct fsxattr))) + return -XFS_ERROR(EFAULT); + + return 0; + + case XFS_IOC_FSSETXATTR: { + int attr_flags; + + if (copy_from_user(&fa, (struct fsxattr *)arg, + sizeof(struct fsxattr))) + return -XFS_ERROR(EFAULT); + + va.va_mask = AT_XFLAGS | AT_EXTSIZE; + + va.va_xflags = fa.fsx_xflags; + va.va_extsize = fa.fsx_extsize; + + attr_flags = (filp->f_flags & (O_NDELAY|O_NONBLOCK) ) + ? ATTR_NONBLOCK : 0; + + error = xfs_setattr(bdp, &va, attr_flags, &cred); + + if (error) + return -error; + + return 0; + } + + case XFS_IOC_FSGETXATTRA: + va.va_mask = AT_XFLAGS|AT_EXTSIZE|AT_ANEXTENTS; + + error = xfs_getattr(bdp, &va, 0, &cred); + + if (error) + return -error; + + fa.fsx_xflags = va.va_xflags; + fa.fsx_extsize = va.va_extsize; + fa.fsx_nextents = va.va_anextents; + + if (copy_to_user((struct fsxattr *)arg, &fa, + sizeof(struct fsxattr))) + return -XFS_ERROR(EFAULT); + + return 0; + + case XFS_IOC_GETBIOSIZE: + error = xfs_get_uiosize(mp, ip, &bs, &cred); + if (error) + return -error; + + if (copy_to_user((struct biosize *)arg, &bs, + sizeof(struct biosize))) + return -XFS_ERROR(EFAULT); + + return 0; + + case XFS_IOC_SETBIOSIZE: + if (copy_from_user(&bs, (struct biosize *)arg, + sizeof(struct biosize))) + return -XFS_ERROR(EFAULT); + + error = xfs_set_uiosize(mp, ip, bs.biosz_flags, bs.biosz_read, + bs.biosz_write, &cred); + if (error) + return -error; + + return 0; + + case XFS_IOC_FSSETDM: + if (copy_from_user(&dmi, (struct fsdmidata *)arg, + sizeof(struct fsdmidata))) + return -XFS_ERROR(EFAULT); + + error = xfs_set_dmattrs(bdp, dmi.fsd_dmevmask, dmi.fsd_dmstate, + &cred); + if (error) + return -error; + + return 0; + + case XFS_IOC_GETBMAP: + case XFS_IOC_GETBMAPA: { + struct getbmap bm; + int iflags; + + if (copy_from_user(&bm, (struct getbmap *)arg, + sizeof(struct getbmap))) + return -XFS_ERROR(EFAULT); + + if (bm.bmv_count < 2) + return -XFS_ERROR(EINVAL); + + iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0); + + if (filp->f_flags & O_INVISIBLE) + iflags |= BMV_IF_NO_DMAPI_READ; + + error = xfs_getbmap(bdp, &bm, + (struct getbmap *)arg + 1, iflags); + + if (error) + return -error; + + if (copy_to_user((struct getbmap *)arg, &bm, sizeof(bm))) + return -XFS_ERROR(EFAULT); + + return 0; + + } + + case XFS_IOC_GETBMAPX: { + struct getbmapx bmx; + struct getbmap bm; + int iflags; + + + if (copy_from_user(&bmx, (struct getbmapx *)arg, + sizeof(struct getbmapx))) + return -XFS_ERROR(EFAULT); + + if (bmx.bmv_count < 2) + return -XFS_ERROR(EINVAL); + + /* + * Map input getbmapx structure to a getbmap + * structure for xfs_getbmap. + */ + GETBMAP_CONVERT(bmx, bm); + + iflags = bmx.bmv_iflags; + + if (iflags & (~BMV_IF_VALID)) + return -XFS_ERROR(EINVAL); + + iflags |= BMV_IF_EXTENDED; + + error = xfs_getbmap(bdp, &bm, + (struct getbmapx *)arg + 1, iflags); + if (error) + return -error; + + GETBMAP_CONVERT(bm, bmx); + + if (copy_to_user((struct getbmapx *)arg, &bmx, sizeof(bmx))) + return -XFS_ERROR(EFAULT); + + return 0; + } + + case XFS_IOC_PATH_TO_FSHANDLE: + case XFS_IOC_FD_TO_HANDLE: + case XFS_IOC_PATH_TO_HANDLE: { + /* + * XFS_IOC_PATH_TO_FSHANDLE + * returns fs handle for a mount point or path within + * that mount point + * XFS_IOC_FD_TO_HANDLE + * returns full handle for a FD opened in user space + * XFS_IOC_PATH_TO_HANDLE + * returns full handle for a path + */ + return xfs_find_handle(cmd, arg); + } + + case XFS_IOC_OPEN_BY_HANDLE: { + + return xfs_open_by_handle(cmd, arg, filp, inode, vfsp, mp); + } + + case XFS_IOC_READLINK_BY_HANDLE: { + + return xfs_readlink_by_handle(cmd, arg, filp, inode, vfsp, mp); + } + + case XFS_IOC_ATTRCTL_BY_HANDLE: { + + return xfs_attrctl_by_handle(cmd, arg, filp, inode, vfsp, mp); + } + + case XFS_IOC_SWAPEXT: { + + error = xfs_swapext((struct xfs_swapext *)arg); + + if (error) + return -error; + return 0; + + } + + case XFS_IOC_GETFSUUID: { + + if (copy_to_user((char *)arg, (char *)&mp->m_sb.sb_uuid, + sizeof(uuid_t))) + return -XFS_ERROR(EFAULT); + + return 0; + } + + case XFS_IOC_FSCOUNTS: { + xfs_fsop_counts_t out; + + error = xfs_fs_counts(mp, &out); + if (error) + return -error; + + if (copy_to_user((char *)arg, &out, sizeof(xfs_fsop_counts_t))) + return -XFS_ERROR(EFAULT); + + return 0; + } + + case XFS_IOC_SET_RESBLKS: { + xfs_fsop_resblks_t inout; + __uint64_t in; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + error = copy_from_user(&inout, (char *)arg, sizeof(xfs_fsop_resblks_t)); + if (error) + return -XFS_ERROR(EFAULT); + + /* input parameter is passed in resblks field of structure */ + in=inout.resblks; + error = xfs_reserve_blocks(mp, &in, &inout); + + if (copy_to_user((char *)arg, &inout, sizeof(xfs_fsop_resblks_t))) + return -XFS_ERROR(EFAULT); + + return 0; + } + + case XFS_IOC_GET_RESBLKS: { + xfs_fsop_resblks_t out; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + error = xfs_reserve_blocks(mp, NULL, &out); + if (error) + return -error; + + if (copy_to_user((char *)arg, &out, sizeof(xfs_fsop_resblks_t))) + return -XFS_ERROR(EFAULT); + + return 0; + } + + case XFS_IOC_FSGROWFSDATA: { + xfs_growfs_data_t in; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&in, (char *)arg, sizeof(xfs_growfs_data_t))) + return -XFS_ERROR(EFAULT); + + error = xfs_growfs_data(mp, &in); + if (error) + return -error; + return 0; + } + + case XFS_IOC_FSGROWFSLOG: { + xfs_growfs_log_t in; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&in, (char *)arg, sizeof(xfs_growfs_log_t))) + return -XFS_ERROR(EFAULT); + + error = xfs_growfs_log(mp, &in); + if (error) + return -error; + return 0; + } + + case XFS_IOC_FSGROWFSRT: { + xfs_growfs_rt_t in; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (copy_from_user(&in, (char *)arg, sizeof(xfs_growfs_rt_t))) + return -XFS_ERROR(EFAULT); + + error = xfs_growfs_rt(mp, &in); + if (error) + return -error; + return 0; + } + + case XFS_IOC_FREEZE: { + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + /* Stop new writers */ + xfs_start_freeze(mp, XFS_FREEZE_WRITE); + + /* Flush delalloc and delwri data */ + VFS_SYNC(vfsp, SYNC_DELWRI|SYNC_WAIT, sys_cred, error); + + /* Pause transaction subsystem */ + xfs_start_freeze(mp, XFS_FREEZE_TRANS); + + /* Flush log to disk */ + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE|XFS_LOG_SYNC); + + /* Flush any remaining inodes into buffers */ + VFS_SYNC(vfsp, SYNC_BDFLUSH|SYNC_ATTR, sys_cred, error); + + /* Push all the buffers out to disk */ + xfs_binval(mp->m_ddev_targ); + if (mp->m_rtdev != NODEV) { + xfs_binval(mp->m_rtdev_targ); + } + + /* Push the superblock and write an unmount record */ + xfs_log_unmount_write(mp); + xfs_unmountfs_writesb(mp); + return 0; + } + + case XFS_IOC_THAW: { + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + xfs_unmountfs_writesb(mp); + xfs_finish_freeze(mp); + return 0; + } + +#if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) + case XFS_IOC_ERROR_INJECTION: { + xfs_error_injection_t in; + error = copy_from_user(&in, (char *)arg, sizeof(xfs_error_injection_t)); + if (error) { + return -error; + } + error = xfs_errortag_add(in.errtag, mp); + if (error) { + return -error; + } + return 0; + } + + case XFS_IOC_ERROR_CLEARALL: { + error = xfs_errortag_clearall(mp); + return -error; + } +#endif /* DEBUG || INDUCE_IO_ERROR */ + + default: + return -EINVAL; + } +} diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_iops.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_iops.c --- linux-2.4.7/linux/fs/xfs/linux/xfs_iops.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_iops.c Mon Jun 25 15:12:14 2001 @@ -0,0 +1,828 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * fs/xfs/linux/xfs_iops.c + * This file would be called xfs_inode.c, but that is already taken + * in the standard XFS code. + * + */ + +#include +#include +#include +#include +#include + + +/* + * Pull the link count and size up from the xfs inode to the linux inode + */ + +static void validate_fields(struct inode *ip) +{ + vnode_t *vp = LINVFS_GET_VN_ADDRESS(ip); + vattr_t va; + int error; + + va.va_mask = AT_NLINK|AT_SIZE; + VOP_GETATTR(vp, &va, ATTR_LAZY, NULL, error); + ip->i_nlink = va.va_nlink; + ip->i_size = va.va_size; + ip->i_blocks = va.va_nblocks; +} + + +/* + * Common code used to create/instantiate various things in a directory. + */ + +int linvfs_common_cr(struct inode *dir, struct dentry *dentry, int mode, + enum vtype tp, int rdev) +{ + int error = 0; + vnode_t *dvp, *vp; + struct inode *ip; + vattr_t va; +#ifdef CONFIG_FS_POSIX_ACL + struct acl pdacl; /* parent default ACL */ +#endif + int have_default_acl; + + dvp = LINVFS_GET_VN_ADDRESS(dir); + ASSERT(dvp); + + vp = NULL; + + + bzero(&va, sizeof(va)); + va.va_mask = AT_TYPE|AT_MODE; + va.va_type = tp; + have_default_acl = _ACL_GET_DEFAULT(dvp, &pdacl); + if (!have_default_acl) { + mode &= ~current->fs->umask; + } + + va.va_mode = mode; + va.va_size = 0; + + if (tp == VREG) { + VOP_CREATE(dvp, (char *)dentry->d_name.name, &va, 0, 0, &vp, + NULL, error); + } else if (ISVDEV(tp)) { + /* + * Get the real type from the mode + */ + va.va_rdev = rdev; + va.va_mask |= AT_RDEV; + + va.va_type = IFTOVT(mode); + if (va.va_type == VNON) { + return -EINVAL; + } + VOP_CREATE(dvp, (char *)dentry->d_name.name, &va, 0, 0, &vp, + NULL, error); + } else if (tp == VDIR) { + VOP_MKDIR(dvp, (char *)dentry->d_name.name, &va, &vp, + NULL, error); + } else { + error = EINVAL; + } + + if (!error) { + ASSERT(vp); + ip = LINVFS_GET_IP(vp); + if (!ip) { + VN_RELE(vp); + return -ENOMEM; + } + if (ISVDEV(tp)) + ip->i_rdev = to_kdev_t(rdev); + linvfs_set_inode_ops(ip); + /* linvfs_revalidate_core returns (-) errors */ + error = -linvfs_revalidate_core(ip, ATTR_COMM); + validate_fields(dir); + d_instantiate(dentry, ip); + } + + if (!error && have_default_acl) { + error = _ACL_INHERIT(vp, &va, &pdacl); + VMODIFY(vp); + } + + return -error; +} + +/* + * Create a new file in dir using mode. + */ +int linvfs_create(struct inode *dir, struct dentry *dentry, int mode) +{ + return(linvfs_common_cr(dir, dentry, mode, VREG, 0)); +} + +struct dentry * linvfs_lookup(struct inode *dir, struct dentry *dentry) +{ + int error; + vnode_t *vp, *cvp; + pathname_t pn; + pathname_t *pnp = &pn; + struct inode *ip = NULL; + + vp = LINVFS_GET_VN_ADDRESS(dir); + + /* + * Initialize a pathname_t to pass down. + */ + bzero(pnp, sizeof(pathname_t)); + pnp->pn_complen = dentry->d_name.len; + pnp->pn_hash = dentry->d_name.hash; + pnp->pn_path = (char *)dentry->d_name.name; + + cvp = NULL; + + VOP_LOOKUP(vp, (char *)dentry->d_name.name, &cvp, pnp, 0, NULL, + NULL, error); + if (!error) { + ASSERT(cvp); + ip = LINVFS_GET_IP(cvp); + if (!ip) { + VN_RELE(cvp); + return ERR_PTR(-EACCES); + } + linvfs_set_inode_ops(ip); + error = linvfs_revalidate_core(ip, ATTR_COMM); + } + d_add(dentry, ip); /* Negative entry goes in if ip is NULL */ + return NULL; +} + + +int linvfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) +{ + int error; + vnode_t *tdvp; /* Target directory for new name/link */ + vnode_t *vp; /* vp of name being linked */ + struct inode *ip; /* inode of guy being linked to */ + + ip = old_dentry->d_inode; /* inode being linked to */ + if (S_ISDIR(ip->i_mode)) + return -EPERM; + + tdvp = LINVFS_GET_VN_ADDRESS(dir); + + vp = LINVFS_GET_VN_ADDRESS(ip); + + error = 0; + VOP_LINK(tdvp, vp, (char *)dentry->d_name.name, NULL, error); + if (!error) { + VMODIFY(tdvp); + ip->i_ctime = CURRENT_TIME; + VN_HOLD(vp); + validate_fields(ip); + d_instantiate(dentry, ip); + } + return -error; +} + + +int linvfs_unlink(struct inode *dir, struct dentry *dentry) +{ + int error; + struct inode *inode; + vnode_t *dvp; /* directory containing name to remove */ + + inode = dentry->d_inode; + + dvp = LINVFS_GET_VN_ADDRESS(dir); + + error = 0; + + VOP_REMOVE(dvp, (char *)dentry->d_name.name, NULL, error); + + if (!error) { + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_version = ++event; + + inode->i_ctime = dir->i_ctime; + validate_fields(dir); /* For size only */ + validate_fields(inode); + } + + return -error; +} + + +int linvfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) +{ + int error; + vnode_t *dvp; /* directory containing name to remove */ + vnode_t *cvp; /* used to lookup symlink to put in dentry */ + vattr_t va; + struct inode *ip = NULL; + + dvp = LINVFS_GET_VN_ADDRESS(dir); + + bzero(&va, sizeof(va)); + va.va_type = VLNK; + va.va_mode = 0777 & ~current->fs->umask; + va.va_mask = AT_TYPE|AT_MODE; /* AT_PROJID? */ + + error = 0; + VOP_SYMLINK(dvp, (char *)dentry->d_name.name, &va, (char *)symname, + &cvp, NULL, error); + if (!error) { + ASSERT(cvp); + ASSERT(cvp->v_type == VLNK); + ip = LINVFS_GET_IP(cvp); + if (!ip) { + error = ENOMEM; + VN_RELE(cvp); + } else { + linvfs_set_inode_ops(ip); + /* linvfs_revalidate_core returns (-) errors */ + error = -linvfs_revalidate_core(ip, ATTR_COMM); + d_instantiate(dentry, ip); + validate_fields(dir); + } + } + return -error; +} + + +int linvfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + return(linvfs_common_cr(dir, dentry, mode, VDIR, 0)); +} + + +int linvfs_rmdir(struct inode *dir, struct dentry *dentry) +{ + int error; + vnode_t *dvp, /* directory with name to remove */ + *pwd_vp; /* current working directory, vnode */ + struct inode *inode = dentry->d_inode; + + dvp = LINVFS_GET_VN_ADDRESS(dir); + + pwd_vp = NULL; /* Used for an unnecessary test */ + + /* + * Someday we could pass the dentry->d_inode into VOP_REMOVE so + * that it can skip the lookup. + */ + + error = 0; + VOP_RMDIR(dvp, (char *)dentry->d_name.name, pwd_vp, NULL, error); + if (!error) { + validate_fields(inode); + validate_fields(dir); + inode->i_version = ++event; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + } + return -error; +} + + +int linvfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) +{ + int error = 0; + enum vtype tp; + + if (S_ISCHR(mode)) { + tp = VCHR; + } else if (S_ISBLK(mode)) { + tp = VBLK; + } else if (S_ISFIFO(mode)) { + tp = VFIFO; + } else if (S_ISSOCK(mode)) { + tp = VSOCK; + } else { + return -EINVAL; + } + + /* linvfs_common_cr will return (-) errors */ + error = linvfs_common_cr(dir, dentry, mode, tp, rdev); + + return(error); +} + + +int linvfs_rename(struct inode *odir, struct dentry *odentry, + struct inode *ndir, struct dentry *ndentry) +{ + int error; + vnode_t *fvp; /* from directory */ + vnode_t *tvp; /* target directory */ + pathname_t pn; + pathname_t *pnp = &pn; + struct inode *new_inode = NULL; + + bzero(pnp, sizeof(pathname_t)); + pnp->pn_complen = ndentry->d_name.len; + pnp->pn_hash = ndentry->d_name.hash; + pnp->pn_path = (char *)ndentry->d_name.name; + + fvp = LINVFS_GET_VN_ADDRESS(odir); + + tvp = LINVFS_GET_VN_ADDRESS(ndir); + + new_inode = ndentry->d_inode; + + VOP_RENAME(fvp, (char *)odentry->d_name.name, tvp, + (char *)ndentry->d_name.name, pnp, NULL, error); + if (error) + return -error; + + ndir->i_version = ++event; + odir->i_version = ++event; + if (new_inode) { + new_inode->i_ctime = CURRENT_TIME; + validate_fields(new_inode); + } + + odir->i_ctime = odir->i_mtime = CURRENT_TIME; + + validate_fields(odir); + if (ndir != odir) + validate_fields(ndir); + return 0; +} + + +int linvfs_readlink(struct dentry *dentry, char *buf, int size) +{ + vnode_t *vp; + uio_t uio; + iovec_t iov; + int error = 0; + + vp = LINVFS_GET_VN_ADDRESS(dentry->d_inode); + + iov.iov_base = buf; + iov.iov_len = size; + + uio.uio_iov = &iov; + uio.uio_offset = 0; + uio.uio_segflg = UIO_USERSPACE; + uio.uio_resid = size; + + VOP_READLINK(vp, &uio, NULL, error); + if (error) + return -error; + + return (size - uio.uio_resid); +} + +/* + * careful here - this function can get called recusively up + * to 32 times, hence we need to be very careful about how much + * stack we use. uio is kmalloced for this reason... + */ + +int linvfs_follow_link(struct dentry *dentry, + struct nameidata *nd) +{ + vnode_t *vp; + uio_t *uio; + iovec_t iov; + int error = 0; + char *link; + + ASSERT(dentry); + ASSERT(nd); + + link = (char *)kmalloc(MAXNAMELEN+1, GFP_KERNEL); + if (!link) return -ENOMEM; + + uio = (uio_t*)kmalloc(sizeof(uio_t), GFP_KERNEL); + if (!uio) { + kfree(link); + return -ENOMEM; + } + + vp = LINVFS_GET_VN_ADDRESS(dentry->d_inode); + + iov.iov_base = link; + iov.iov_len = MAXNAMELEN; + + uio->uio_iov = &iov; + uio->uio_offset = 0; + uio->uio_segflg = UIO_SYSSPACE; + uio->uio_resid = MAXNAMELEN; + + VOP_READLINK(vp, uio, NULL, error); + if (error) { + kfree(uio); + kfree(link); + return -error; + } + + link[MAXNAMELEN - uio->uio_resid] = '\0'; + kfree(uio); + + /* vfs_follow_link returns (-) errors */ + error = vfs_follow_link(nd, link); + kfree(link); + return error; +} + +#ifdef CONFIG_HAVE_ATTRCTL +/* + * Implement attrctl(2) functions. + * Returns -ve on error (ie -ENOMEM). + * Updates ops[?].error fields with a +ve errno (ie +ENOMEM). + */ +int linvfs_attrctl( + struct inode *inode, + attr_op_t *ops, + int count) +{ + int i; + int error = 0; + vnode_t *vp; + + for (i = 0; i < count; i++) { + int flags = ops[i].flags; + /* common flags */ + flags &= ~(ATTR_ROOT | ATTR_DONTFOLLOW); + /* command specific */ + if (ops[i].opcode == ATTR_OP_SET) + flags &= ~(ATTR_CREATE | ATTR_REPLACE); + if (flags != 0x0) + return -EINVAL; + + /* permissions */ + if ((ops[i].flags & ATTR_ROOT) && ! capable(CAP_SYS_ADMIN)) + return -EPERM; + + vp = LINVFS_GET_VN_ADDRESS(inode); + + switch (ops[i].opcode) { + case ATTR_OP_GET: + VOP_ATTR_GET(vp, + ops[i].name, + ops[i].value, + &ops[i].length, + ops[i].flags, + (struct cred *) NULL, + ops[i].error); /* +ve return val */ + break; + + case ATTR_OP_SET: + VOP_ATTR_SET(vp, + ops[i].name, + ops[i].value, + ops[i].length, + ops[i].flags, + (struct cred *) NULL, + ops[i].error); + VMODIFY(vp); + break; + + case ATTR_OP_REMOVE: + VOP_ATTR_REMOVE(vp, + ops[i].name, + ops[i].flags, + (struct cred *) NULL, + ops[i].error); + VMODIFY(vp); + break; + + case ATTR_OP_IRIX_LIST: + VOP_ATTR_LIST(vp, + ops[i].value, + ops[i].length, + ops[i].flags, + ops[i].aux, + (struct cred *) NULL, + ops[i].error); + break; + + case ATTR_OP_LIST: + default: + error = ENOSYS; + } + + } + + return -error; +} +#endif /* CONFIG_HAVE_ATTRCTL */ + +#ifdef CONFIG_FS_POSIX_ACL + +int linvfs_acl_get( + struct dentry *dentry, + struct acl *acl, + struct acl *dacl) +{ + int error = 0; + vnode_t *vp; + + vp = LINVFS_GET_VN_ADDRESS(dentry->d_inode); + + VOP_ACL_GET(vp, acl, dacl, error); + + return -error; +} + + +int linvfs_acl_set( + struct dentry *dentry, + struct acl *acl, + struct acl *dacl) +{ + int error = 0; + vnode_t *vp; + + vp = LINVFS_GET_VN_ADDRESS(dentry->d_inode); + + VOP_ACL_SET(vp, acl, dacl, error); + VMODIFY(vp); + + return -error; +} + +#endif + +int linvfs_permission(struct inode *ip, int mode) +{ + vnode_t *vp; + int error; + + mode <<= 6; /* convert from linux to vnode access bits */ + + vp = LINVFS_GET_VN_ADDRESS(ip); + + VOP_ACCESS(vp, mode, NULL, error); + + return -error; +} + +/* Brute force approach for now - copy data into linux inode + * from the results of a getattr. This gets called out of things + * like stat. + */ +int linvfs_revalidate_core(struct inode *inode, int flags) +{ + vnode_t *vp; + + vp = LINVFS_GET_VP(inode); + ASSERT(vp); + /* vn_revalidate returns (-) error so this is ok */ + return vn_revalidate(vp, flags); +} + +STATIC int linvfs_revalidate(struct dentry *dentry) +{ + vnode_t *vp; + + vp = LINVFS_GET_VP(dentry->d_inode); + if (vp->v_flag & VMODIFIED) { + return linvfs_revalidate_core(dentry->d_inode, 0); + } + return 0; +} + + +int +linvfs_notify_change( + struct dentry *dentry, + struct iattr *attr) +{ + vnode_t *vp = LINVFS_GET_VN_ADDRESS(dentry->d_inode); + vattr_t vattr; + + unsigned int ia_valid = attr->ia_valid; + int error; + struct inode *inode; + + inode = dentry->d_inode; + error = inode_change_ok(inode, attr); + if (error){ + return(error); + } + + memset(&vattr, 0, sizeof(vattr_t)); + + + if (ia_valid & ATTR_UID) { + vattr.va_mask |= AT_UID; + vattr.va_uid = attr->ia_uid; + } + if (ia_valid & ATTR_GID) { + vattr.va_mask |= AT_GID; + vattr.va_gid = attr->ia_gid; + } + if (ia_valid & ATTR_SIZE) { + vattr.va_mask |= AT_SIZE; + vattr.va_size = attr->ia_size; + } + if (ia_valid & ATTR_ATIME) { + vattr.va_mask |= AT_ATIME; + vattr.va_atime.tv_sec = attr->ia_atime; + vattr.va_atime.tv_nsec = 0; + } + if (ia_valid & ATTR_MTIME) { + vattr.va_mask |= AT_MTIME; + vattr.va_mtime.tv_sec = attr->ia_mtime; + vattr.va_mtime.tv_nsec = 0; + } + if (ia_valid & ATTR_CTIME) { + vattr.va_mask |= AT_CTIME; + vattr.va_ctime.tv_sec = attr->ia_ctime; + vattr.va_ctime.tv_nsec = 0; + } + if (ia_valid & ATTR_MODE) { + vattr.va_mask |= AT_MODE; + vattr.va_mode = attr->ia_mode; + if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) + inode->i_mode &= ~S_ISGID; + } + + + VOP_SETATTR(vp, &vattr, 0, sys_cred, error); + + if (!error) { + inode_setattr(inode, attr); + } + + return(-error); +} + +int +linvfs_pb_bmap(struct inode *inode, + loff_t offset, + ssize_t count, + page_buf_bmap_t *pbmapp, + int maxpbbm, + int *retpbbm, + int flags) +{ + vnode_t *vp; + int error; + + vp = LINVFS_GET_VN_ADDRESS(inode); + + *retpbbm = maxpbbm; + + if (flags & PBF_FILE_ALLOCATE) { + VOP_STRATEGY(vp, offset, count, flags, NULL, + (struct page_buf_bmap_s *) pbmapp, retpbbm, error); + } else { + VOP_BMAP(vp, offset, count, flags, NULL, + (struct page_buf_bmap_s *) pbmapp, retpbbm, error); + } + if (flags & PBF_WRITE) + VMODIFY(vp); + + return -error; +} + +STATIC +int linvfs_bmap(struct address_space *mapping, long block) +{ + struct inode *inode = (struct inode *)mapping->host; + vnode_t *vp = LINVFS_GET_VN_ADDRESS(inode); + pb_bmap_t bmap = {0}; + int nbm = 1; + int error; + + /* block - linux disk blocks 512b */ + /* bmap input offset - bytes 1b */ + /* bmap outut bn - xfs BBs 512b */ + /* bmap outut delta - bytes 1b */ + + vn_trace_entry(vp, "linvfs_bmap", (inst_t *)__return_address); + + VOP_RWLOCK(vp, VRWLOCK_READ); + if (inode->i_data.nrpages) { + VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, 0, FI_REMAPF, error); + if (error) { + VOP_RWUNLOCK(vp, VRWLOCK_READ); + /* VOP_FLUSH_PAGES currently returns nothing but 0... */ + return -error; + } + } + + VOP_BMAP(vp, block << 9, 1, PBF_READ, NULL, + &bmap, &nbm, error); + VOP_RWUNLOCK(vp, VRWLOCK_READ); + if (error) + return -error; + return (int)(bmap.pbm_bn + (bmap.pbm_delta >> 9)); +} + +STATIC int linvfs_read_full_page(struct file *filp, struct page *page) +{ + return pagebuf_read_full_page(filp, page, linvfs_pb_bmap); +} + +STATIC int linvfs_write_full_page(struct page *page) +{ + int ret = pagebuf_write_full_page(page, linvfs_pb_bmap); + return ret < 0 ? 0 : ret; +} + +STATIC int linvfs_prepare_write( + struct file *file, + struct page *page, + unsigned from, + unsigned to) +{ + return pagebuf_prepare_write(file, page, from, to, linvfs_pb_bmap); +} + + +struct address_space_operations linvfs_aops = { + readpage: linvfs_read_full_page, + writepage: linvfs_write_full_page, + sync_page: block_sync_page, + bmap: linvfs_bmap, + prepare_write: linvfs_prepare_write, + commit_write: pagebuf_commit_write, +}; + +struct inode_operations linvfs_file_inode_operations = +{ + permission: linvfs_permission, + revalidate: linvfs_revalidate, + setattr: linvfs_notify_change, +#ifdef CONFIG_HAVE_ATTRCTL + attrctl: linvfs_attrctl, +#endif +#ifdef CONFIG_FS_POSIX_ACL + acl_get: linvfs_acl_get, + acl_set: linvfs_acl_set, +#endif +}; + +struct inode_operations linvfs_dir_inode_operations = +{ + create: linvfs_create, + lookup: linvfs_lookup, + link: linvfs_link, + unlink: linvfs_unlink, + symlink: linvfs_symlink, + mkdir: linvfs_mkdir, + rmdir: linvfs_rmdir, + mknod: linvfs_mknod, + rename: linvfs_rename, + permission: linvfs_permission, + revalidate: linvfs_revalidate, + setattr: linvfs_notify_change, +#ifdef CONFIG_HAVE_ATTRCTL + attrctl: linvfs_attrctl, +#endif +#ifdef CONFIG_FS_POSIX_ACL + acl_get: linvfs_acl_get, + acl_set: linvfs_acl_set, +#endif +}; + +struct inode_operations linvfs_symlink_inode_operations = +{ + readlink: linvfs_readlink, + follow_link: linvfs_follow_link, + permission: linvfs_permission, + revalidate: linvfs_revalidate, + setattr: linvfs_notify_change, +#ifdef CONFIG_HAVE_ATTRCTL + attrctl: linvfs_attrctl, +#endif +#ifdef CONFIG_FS_POSIX_ACL + acl_get: linvfs_acl_get, + acl_set: linvfs_acl_set, +#endif +}; + diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_iops.h linux-2.4-xfs/linux/fs/xfs/linux/xfs_iops.h --- linux-2.4.7/linux/fs/xfs/linux/xfs_iops.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_iops.h Mon Apr 16 16:06:55 2001 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef XFS_LINUX_OPS_INODE_DOT_H +#define XFS_LINUX_OPS_INODE_DOT_H + +extern struct inode_operations linvfs_file_inode_operations; +extern struct inode_operations linvfs_dir_inode_operations; +extern struct inode_operations linvfs_symlink_inode_operations; + +extern struct file_operations linvfs_file_operations; +extern struct file_operations linvfs_dir_operations; + +extern struct address_space_operations linvfs_aops; + +extern int linvfs_revalidate_core(struct inode *, int); + +extern void linvfs_set_inode_ops(struct inode *); +extern int linvfs_pb_bmap(struct inode *, loff_t, ssize_t, page_buf_bmap_t *, + int, int *, int); + +#endif /* XFS_LINUX_OPS_INODE_DOT_H */ + + diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_linux.h linux-2.4-xfs/linux/fs/xfs/linux/xfs_linux.h --- linux-2.4.7/linux/fs/xfs/linux/xfs_linux.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_linux.h Thu May 17 19:20:50 2001 @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_LINUX__ +#define __XFS_LINUX__ + +#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 + +#ifndef STATIC +#define STATIC +#endif + +typedef struct pathname { + char *pn_path; /* remaining pathname */ + u_long pn_hash; /* last component's hash */ + u_short pn_complen; /* last component length */ +} pathname_t; + +typedef struct statvfs { + ulong_t f_bsize; /* fundamental file system block size */ + ulong_t f_frsize; /* fragment size */ + __uint64_t f_blocks; /* total # of blocks of f_frsize on fs */ + __uint64_t f_bfree; /* total # of free blocks of f_frsize */ + __uint64_t f_bavail; /* # of free blocks avail to non-superuser */ + __uint64_t f_files; /* total # of file nodes (inodes) */ + __uint64_t f_ffree; /* total # of free file nodes */ + __uint64_t f_favail; /* # of free nodes avail to non-superuser */ + ulong_t f_namemax; /* maximum file name length */ + ulong_t f_fsid; /* file system id (dev for now) */ + char f_basetype[16]; /* target fs type name, null-terminated */ + char f_fstr[32]; /* filesystem-specific string */ +} statvfs_t; + +typedef struct xfs_dirent { /* data from readdir() */ + xfs_ino_t d_ino; /* inode number of entry */ + xfs_off_t d_off; /* offset of disk directory entry */ + unsigned short d_reclen;/* length of this record */ + char d_name[1]; /* name of file */ +} xfs_dirent_t; + +typedef struct xfs_dirent32 { /* Irix5 view of dirent structure */ + app32_ulong_t d_ino; /* inode number of entry */ + xfs32_off_t d_off; /* offset of disk directory entry */ + unsigned short d_reclen;/* length of this record */ + char d_name[1]; /* name of file */ +} xfs_dirent32_t; + +#define GETDENTS_ABI(abi, uiop) 1 +#define DIRENTBASESIZE (((xfs_dirent_t *)0)->d_name - (char *)0) +#define DIRENTSIZE(namelen) \ + ((DIRENTBASESIZE + (namelen) + \ + sizeof(xfs_off_t)) & ~(sizeof(xfs_off_t) - 1)) +#define DIRENT32BASESIZE (((xfs_dirent32_t *)0)->d_name - (char *)0) +#define DIRENT32SIZE(namelen) \ + ((DIRENT32BASESIZE + (namelen) + \ + sizeof(xfs32_off_t)) & ~(sizeof(xfs32_off_t) - 1)) + +#define ABI_IRIX5 0x02 /* an IRIX5/SVR4 ABI binary */ +#define ABI_IRIX5_64 0x04 /* an IRIX5-64 bit binary */ +#define ABI_IRIX5_N32 0x08 /* an IRIX5-32 bit binary (new abi) */ + +#define ABI_IS(set,abi) (((set) & (abi)) != 0) +#define ABI_IS_IRIX5(abi) (ABI_IS(ABI_IRIX5, abi)) +#define ABI_IS_IRIX5_N32(abi) (ABI_IS(ABI_IRIX5_N32, abi)) +#define ABI_IS_IRIX5_64(abi) (ABI_IS(ABI_IRIX5_64, abi)) +#define ABI_IS_IRIX5_N32(abi) (ABI_IS(ABI_IRIX5_N32, abi)) +/* try 64 bit first */ +#define get_current_abi() ABI_IRIX5_64 + +#define _PAGESZ PAGE_SIZE +#define NBPP PAGE_SIZE +#define DPPSHFT (PAGE_SHIFT - 9) +#define NDPP (1 << (PAGE_SHIFT - 9)) +#define dtop(DD) (((DD) + NDPP - 1) >> DPPSHFT) +#define dtopt(DD) ((DD) >> DPPSHFT) +#define dpoff(DD) ((DD) & (NDPP-1)) +#define NBBY 8 /* number of bits per byte */ + +/* + * Size of block device i/o is parameterized here. + * Currently the system supports page-sized i/o. + */ +#define BLKDEV_IOSHIFT BPCSHIFT +#define BLKDEV_IOSIZE (1<>BPCSHIFT) +#define btoct(x) ((__psunsigned_t)(x)>>BPCSHIFT) +#define btoc64(x) (((__uint64_t)(x)+(NBPC-1))>>BPCSHIFT) +#define btoct64(x) ((__uint64_t)(x)>>BPCSHIFT) +#define io_btoc(x) (((__psunsigned_t)(x)+(IO_NBPC-1))>>IO_BPCSHIFT) +#define io_btoct(x) ((__psunsigned_t)(x)>>IO_BPCSHIFT) +#else +#define btoc(x) (((__psunsigned_t)(x)+(NBPC-1))/NBPC) +#define btoct(x) ((__psunsigned_t)(x)/NBPC) +#define btoc64(x) (((__uint64_t)(x)+(NBPC-1))/NBPC) +#define btoct64(x) ((__uint64_t)(x)/NBPC) +#define io_btoc(x) (((__psunsigned_t)(x)+(IO_NBPC-1))/IO_NBPC) +#define io_btoct(x) ((__psunsigned_t)(x)/IO_NBPC) +#endif + +/* off_t bytes to clicks */ +#ifdef BPCSHIFT +#define offtoc(x) (((__uint64_t)(x)+(NBPC-1))>>BPCSHIFT) +#define offtoct(x) ((xfs_off_t)(x)>>BPCSHIFT) +#else +#define offtoc(x) (((__uint64_t)(x)+(NBPC-1))/NBPC) +#define offtoct(x) ((xfs_off_t)(x)/NBPC) +#endif + +/* clicks to off_t bytes */ +#ifdef BPCSHIFT +#define ctooff(x) ((xfs_off_t)(x)<>BPCSHIFT) +#define ctob64(x) ((__uint64_t)(x)<>BPCSHIFT) +#else +#define btoc(x) (((__psunsigned_t)(x)+(NBPC-1))/NBPC) +#endif + +#ifndef CELL_CAPABLE +#define CELL_ONLY(x) +#define CELL_NOT(x) (x) +#define CELL_IF(a, b) (b) +#define CELL_MUST(a) ASSERT(0) +#define CELL_ASSERT(x) +#define FSC_NOTIFY_NAME_CHANGED(vp) +#endif + + +/* + * XXX these need real values in errno.h. asm-i386/errno.h won't + * return errnos out of its known range in errno. + */ +#define ENOTSUP ENOTSUPP /* Not supported (POSIX 1003.1b) */ +#define ENOATTR ENODATA /* Attribute not found */ + +/* XXX also note these need to be < 1000 and fairly unique on linux */ +#define EFSCORRUPTED 990 /* Filesystem is corrupted */ +#define EWRONGFS 991 /* Mount with wrong filesystem type */ + +#define SYNCHRONIZE() ((void)0) +#define lbolt jiffies +#define rootdev ROOT_DEV +#define __return_address __builtin_return_address(0) +#define LONGLONG_MAX 9223372036854775807LL /* max "long long int" */ +#define nopkg() ( ENOSYS ) +#define getf(fd,fpp) ( printk("getf not implemented\n"), ASSERT(0), 0 ) + +/* IRIX uses a dynamic sizing algorithm (ndquot = 200 + numprocs*2) */ +/* we may well need to fine-tune this if it ever becomes an issue. */ +#define DQUOT_MAX_HEURISTIC 1024 /* NR_DQUOTS */ + +/* IRIX uses the current size of the name cache to guess a good value */ +/* - this isn't the same but is a good enough starting point for now. */ +#define DQUOT_HASH_HEURISTIC files_stat.nr_files + +#define MAXNAMELEN 256 +#define MAXPATHLEN 1024 + +#define PSWP 0 +#define PMEM 0 +#define PINOD 10 +#define PRIBIO 20 + +#define PLTWAIT 0x288 /* O'01000' */ +#define PVFS 27 + +#define FREAD 0x01 +#define FWRITE 0x02 +#define FNDELAY 0x04 +#define FNONBLOCK 0x80 +#define FINVIS 0x0100 /* don't update timestamps - XFS */ +#define FSOCKET 0x0200 /* open file refers to a vsocket */ + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) +#define howmany(x, y) (((x)+((y)-1))/(y)) +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) + +/* Move the kernel do_div definition off to one side */ + +#if defined __i386__ +/* For ia32 we need to pull some tricks to get past various versions + * of the compiler which do not like us using do_div in the middle + * of large functions. + */ +static inline __u32 xfs_do_div(void *a, __u32 b, int n) +{ + __u32 mod; + + switch (n) { + case 4: + mod = *(__u32 *)a % b; + *(__u32 *)a = *(__u32 *)a / b; + return mod; + case 8: + { + unsigned long __upper, __low, __high, __mod; + __u64 c = *(__u64 *)a; + __upper = __high = c >> 32; + __low = c; + if (__high) { + __upper = __high % (b); + __high = __high / (b); + } + asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper)); + asm("":"=A" (c):"a" (__low),"d" (__high)); + *(__u64 *)a = c; + return __mod; + } + } + + /* NOTREACHED */ + return 0; +} + +/* Side effect free 64 bit mod operation */ +static inline __u32 xfs_do_mod(void *a, __u32 b, int n) +{ + switch (n) { + case 4: + return *(__u32 *)a % b; + case 8: + { + unsigned long __upper, __low, __high, __mod; + __u64 c = *(__u64 *)a; + __upper = __high = c >> 32; + __low = c; + if (__high) { + __upper = __high % (b); + __high = __high / (b); + } + asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper)); + asm("":"=A" (c):"a" (__low),"d" (__high)); + return __mod; + } + } + + /* NOTREACHED */ + return 0; +} +#else +static inline __u32 xfs_do_div(void *a, __u32 b, int n) +{ + __u32 mod; + + switch (n) { + case 4: + mod = *(__u32 *)a % b; + *(__u32 *)a = *(__u32 *)a / b; + return mod; + case 8: + mod = do_div(*(__u64 *)a, b); + return mod; + } + + /* NOTREACHED */ + return 0; +} + +/* Side effect free 64 bit mod operation */ +static inline __u32 xfs_do_mod(void *a, __u32 b, int n) +{ + switch (n) { + case 4: + return *(__u32 *)a % b; + case 8: + { + __u64 c = *(__u64 *)a; + return do_div(c, b); + } + } + + /* NOTREACHED */ + return 0; +} +#endif + +#undef do_div +#define do_div(a, b) xfs_do_div(&(a), (b), sizeof(a)) +#define do_mod(a, b) xfs_do_mod(&(a), (b), sizeof(a)) + +extern inline __uint64_t roundup_64(__uint64_t x, __uint32_t y) +{ + x += y - 1; + do_div(x, y); + return(x * y); +} + +#endif /* __XFS_LINUX__ */ diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_lrw.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_lrw.c --- linux-2.4.7/linux/fs/xfs/linux/xfs_lrw.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_lrw.c Fri Jun 8 22:23:46 2001 @@ -0,0 +1,2060 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +/* + * fs/xfs/linux/xfs_lrw.c (Linux Read Write stuff) + * + */ + +#include +#include +#include +#include +#include + + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define XFS_WRITEIO_ALIGN(io,off) (((off) >> io->io_writeio_log) \ + << io->io_writeio_log) +#define XFS_STRAT_WRITE_IMAPS 2 + +int xfs_iomap_write_delay(xfs_iocore_t *, loff_t, size_t, pb_bmap_t *, + int *, int, int); +int xfs_iomap_write_direct(xfs_iocore_t *, loff_t, size_t, pb_bmap_t *, + int *, int, int); +int _xfs_imap_to_bmap(xfs_iocore_t *, xfs_off_t, xfs_bmbt_irec_t *, + pb_bmap_t *, int, int); + +#ifndef DEBUG +#define xfs_strat_write_check(io,off,count,imap,nimap) +#else /* DEBUG */ +STATIC void +xfs_strat_write_check( + xfs_iocore_t *io, + xfs_fileoff_t offset_fsb, + xfs_filblks_t buf_fsb, + xfs_bmbt_irec_t *imap, + int imap_count); + +#endif /* DEBUG */ + +ssize_t /* error (positive) */ +xfs_read( + bhv_desc_t *bdp, + uio_t *uiop, + int ioflag, + cred_t *credp, + flid_t *fl) + +{ + ssize_t ret; + int error = 0; + xfs_fsize_t n; + xfs_inode_t *ip; + struct file *filp = uiop->uio_fp; + struct inode *linux_ip = filp->f_dentry->d_inode; + char *buf; + size_t size; + loff_t *offsetp; + xfs_iocore_t *io; + xfs_mount_t *mp; + + ASSERT(uiop); /* we only support exactly 1 */ + ASSERT(uiop->uio_iovcnt == 1); /* iov in a uio on linux */ + ASSERT(uiop->uio_iov); + + buf = uiop->uio_iov->iov_base; + size = uiop->uio_iov->iov_len; + offsetp = &uiop->uio_offset; + + ip = XFS_BHVTOI(bdp); + io = &(ip->i_iocore); + mp = io->io_mount; + + if (filp->f_flags & O_DIRECT) { + if (((__psint_t)buf & (linux_ip->i_sb->s_blocksize - 1)) || + (uiop->uio_offset & mp->m_blockmask) || + (size & mp->m_blockmask)) { + if (uiop->uio_offset == XFS_SIZE(mp, io)) { + return (0); + } + return XFS_ERROR(EINVAL); + } + } + + + n = XFS_MAX_FILE_OFFSET - *offsetp; + if ((n <= 0) || (size == 0)) + return 0; + + if (n < size) + size = n; + + if (XFS_FORCED_SHUTDOWN(mp)) { + return EIO; + } + + XFS_ILOCK(mp, io, XFS_IOLOCK_SHARED); + +#ifdef CONFIG_XFS_DMAPI + if (DM_EVENT_ENABLED(BHV_TO_VNODE(bdp)->v_vfsp, ip, DM_EVENT_READ) && + !(filp->f_flags & (O_INVISIBLE))) { + + /*vrwlock_t locktype = VRWLOCK_READ;*/ + + error = xfs_dm_send_data_event(DM_EVENT_READ, bdp, + *offsetp, size, + FILP_DELAY_FLAG(filp), + NULL /*&locktype*/); + if (error) { + XFS_IUNLOCK(mp, io, XFS_IOLOCK_SHARED); + return error; + } + } +#endif /* CONFIG_XFS_DMAPI */ + + if (filp->f_flags & O_DIRECT) { + /* Flush and keep lock to keep out buffered writers */ + fs_flush_pages(bdp, *offsetp, *offsetp + size, 0, FI_NONE); + ret = pagebuf_direct_file_read(filp, buf, size, offsetp, + linvfs_pb_bmap); + XFS_IUNLOCK(mp, io, XFS_IOLOCK_SHARED); + } else { + /* Page locking protects this case */ + XFS_IUNLOCK(mp, io, XFS_IOLOCK_SHARED); + ret = generic_file_read(filp, buf, size, offsetp); + } + + /* + * In either case above, ret >= 0 is num bytes read + * ret < 0 is an error. + */ + if (ret > 0) { + uiop->uio_resid = size - ret; + } else { + /* return positive error */ + error = -(int)ret; + } + + if (!(filp->f_flags & O_INVISIBLE)) + XFS_CHGTIME(mp, io, XFS_ICHGTIME_ACC); + + ASSERT (error >= 0); + return error; +} + +/* + * This routine is called to handle zeroing any space in the last + * block of the file that is beyond the EOF. We do this since the + * size is being increased without writing anything to that block + * and we don't want anyone to read the garbage on the disk. + */ + +/* We don' want the IRIX poff */ +#define poff(x) ((x) & (PAGE_CACHE_SIZE - 1)) + +/* ARGSUSED */ +STATIC int /* error (positive) */ +xfs_zero_last_block( + struct inode *ip, + xfs_iocore_t *io, + xfs_off_t offset, + xfs_fsize_t isize, + struct pm *pmp) +{ + xfs_fileoff_t last_fsb; + xfs_fileoff_t next_fsb; + xfs_fileoff_t end_fsb; + xfs_fsblock_t firstblock; + xfs_mount_t *mp; + page_buf_t *pb; + int nimaps; + int zero_offset; + int zero_len; + int isize_fsb_offset; + int i; + int error = 0; + int hole; + xfs_bmbt_irec_t imap; + loff_t loff; + size_t lsize; + + + ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0); + ASSERT(offset > isize); + + mp = io->io_mount; + + /* + * If the file system block size is less than the page size, + * then there could be bytes in the last page after the last + * fsblock containing isize which have not been initialized. + * Since if such a page is in memory it will be + * fully accessible, we need to zero any part of + * it which is beyond the old file size. We don't need to send + * this out to disk, we're just initializing it to zeroes like + * we would have done in xfs_strat_read() had the size been bigger. + */ + if ((mp->m_sb.sb_blocksize < NBPP) && ((i = poff(isize)) != 0)) { + struct page *page; + + page = find_lock_page(&ip->i_data, isize >> PAGE_CACHE_SHIFT); + if (page) { + memset((void *)kmap(page)+i, 0, PAGE_SIZE-i); + kunmap(page); + + /* + * Now we check to see if there are any holes in the + * page over the end of the file that are beyond the + * end of the file. If so, we want to set the P_HOLE + * flag in the page and blow away any active mappings + * to it so that future faults on the page will cause + * the space where the holes are to be allocated. + * This keeps us from losing updates that are beyond + * the current end of file when the page is already + * in memory. + */ + next_fsb = XFS_B_TO_FSBT(mp, isize); + end_fsb = XFS_B_TO_FSB(mp, ctooff(offtoc(isize))); + hole = 0; + while (next_fsb < end_fsb) { + nimaps = 1; + firstblock = NULLFSBLOCK; + error = XFS_BMAPI(mp, NULL, io, next_fsb, 1, 0, + &firstblock, 0, &imap, + &nimaps, NULL); + if (error) { + UnlockPage(page); + page_cache_release(page); + return error; + } + ASSERT(nimaps > 0); + if (imap.br_startblock == HOLESTARTBLOCK) { + hole = 1; + break; + } + next_fsb++; + } + if (hole) { + printk("xfs_zero_last_block: hole found? need more implementation\n"); +#ifndef linux + /* + * In order to make processes notice the + * newly set P_HOLE flag, blow away any + * mappings to the file. We have to drop + * the inode lock while doing this to avoid + * deadlocks with the chunk cache. + */ + if (VN_MAPPED(vp)) { + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL | + XFS_EXTSIZE_RD); + VOP_PAGES_SETHOLE(vp, pfdp, 1, 1, + ctooff(offtoct(isize))); + XFS_ILOCK(mp, io, XFS_ILOCK_EXCL | + XFS_EXTSIZE_RD); + } +#endif + } + UnlockPage(page); + page_cache_release(page); + } + } + + isize_fsb_offset = XFS_B_FSB_OFFSET(mp, isize); + if (isize_fsb_offset == 0) { + /* + * There are no extra bytes in the last block on disk to + * zero, so return. + */ + return 0; + } + + last_fsb = XFS_B_TO_FSBT(mp, isize); + nimaps = 1; + firstblock = NULLFSBLOCK; + error = XFS_BMAPI(mp, NULL, io, last_fsb, 1, 0, &firstblock, 0, &imap, + &nimaps, NULL); + if (error) { + return error; + } + ASSERT(nimaps > 0); + /* + * If the block underlying isize is just a hole, then there + * is nothing to zero. + */ + if (imap.br_startblock == HOLESTARTBLOCK) + { + return 0; + } + /* + * Get a pagebuf for the last block, zero the part beyond the + * EOF, and write it out sync. We need to drop the ilock + * while we do this so we don't deadlock when the buffer cache + * calls back to us. + */ + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD); + loff = XFS_FSB_TO_B(mp, last_fsb); + lsize = BBTOB(XFS_FSB_TO_BB(mp, 1)); + + zero_offset = isize_fsb_offset; + zero_len = mp->m_sb.sb_blocksize - isize_fsb_offset; + + /* + * Realtime needs work here + */ + pb = pagebuf_lookup(ip, loff, lsize, PBF_ENTER_PAGES); + if (!pb) { + error = ENOMEM; + XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + return error; + } + if (io->io_flags & XFS_IOCORE_RT) { + pb->pb_dev = mp->m_rtdev; + } + + if ((imap.br_startblock > 0) && + (imap.br_startblock != DELAYSTARTBLOCK)) { + pb->pb_bn = XFS_FSB_TO_DB_IO(io, imap.br_startblock); + if (imap.br_state == XFS_EXT_UNWRITTEN) { + printk("xfs_zero_last_block: unwritten?\n"); + } + if (PBF_NOT_DONE(pb)) { + /* pagebuf functions return negative errors */ + if ((error = -pagebuf_iostart(pb, PBF_READ))) { + pagebuf_rele(pb); + goto out_lock; + } + } + } + + + if ((error = -pagebuf_iozero(ip, pb, zero_offset, zero_len))) { + pagebuf_rele(pb); + goto out_lock; + } + + /* + * We don't want to start a transaction here, so don't + * push out a buffer over a delayed allocation extent. + * Also, we can get away with it since the space isn't + * allocated so it's faster anyway. + * + * We don't bother to call xfs_b*write here since this is + * just userdata, and we don't want to bring the filesystem + * down if they hit an error. Since these will go through + * xfsstrategy anyway, we have control over whether to let the + * buffer go thru or not, in case of a forced shutdown. + */ + + if (imap.br_startblock == DELAYSTARTBLOCK || + imap.br_state == XFS_EXT_UNWRITTEN) { + pagebuf_rele(pb); + } else { + XFS_BUF_WRITE(pb); + XFS_BUF_ASYNC(pb); + XFS_bwrite(pb); + } + +out_lock: + XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + ASSERT(error >= 0); + return error; +} + +/* + * Zero any on disk space between the current EOF and the new, + * larger EOF. This handles the normal case of zeroing the remainder + * of the last block in the file and the unusual case of zeroing blocks + * out beyond the size of the file. This second case only happens + * with fixed size extents and when the system crashes before the inode + * size was updated but after blocks were allocated. If fill is set, + * then any holes in the range are filled and zeroed. If not, the holes + * are left alone as holes. + */ + +int /* error (positive) */ +xfs_zero_eof( + vnode_t *vp, + xfs_iocore_t *io, + xfs_off_t offset, + xfs_fsize_t isize, + struct pm *pmp) +{ + struct inode *ip = vp->v_inode; + xfs_fileoff_t start_zero_fsb; + xfs_fileoff_t end_zero_fsb; + xfs_fileoff_t prev_zero_fsb; + xfs_fileoff_t zero_count_fsb; + xfs_fileoff_t last_fsb; + xfs_fsblock_t firstblock; + xfs_extlen_t buf_len_fsb; + xfs_extlen_t prev_zero_count; + xfs_mount_t *mp; + page_buf_t *pb; + int nimaps; + int error = 0; + xfs_bmbt_irec_t imap; + loff_t loff; + size_t lsize; + + ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); + ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); + + mp = io->io_mount; + + /* + * First handle zeroing the block on which isize resides. + * We only zero a part of that block so it is handled specially. + */ + error = xfs_zero_last_block(ip, io, offset, isize, pmp); + if (error) { + ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); + ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); + return error; + } + + /* + * Calculate the range between the new size and the old + * where blocks needing to be zeroed may exist. To get the + * block where the last byte in the file currently resides, + * we need to subtract one from the size and truncate back + * to a block boundary. We subtract 1 in case the size is + * exactly on a block boundary. + */ + last_fsb = isize ? XFS_B_TO_FSBT(mp, isize - 1) : (xfs_fileoff_t)-1; + start_zero_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)isize); + end_zero_fsb = XFS_B_TO_FSBT(mp, offset - 1); + + ASSERT((xfs_sfiloff_t)last_fsb < (xfs_sfiloff_t)start_zero_fsb); + if (last_fsb == end_zero_fsb) { + /* + * The size was only incremented on its last block. + * We took care of that above, so just return. + */ + return 0; + } + + ASSERT(start_zero_fsb <= end_zero_fsb); + prev_zero_fsb = NULLFILEOFF; + prev_zero_count = 0; + /* + * Maybe change this loop to do the bmapi call and + * loop while we split the mappings into pagebufs? + */ + while (start_zero_fsb <= end_zero_fsb) { + nimaps = 1; + zero_count_fsb = end_zero_fsb - start_zero_fsb + 1; + firstblock = NULLFSBLOCK; + error = XFS_BMAPI(mp, NULL, io, start_zero_fsb, zero_count_fsb, + 0, &firstblock, 0, &imap, &nimaps, NULL); + if (error) { + ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); + ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); + return error; + } + ASSERT(nimaps > 0); + + if (imap.br_startblock == HOLESTARTBLOCK) + { + /* + * This loop handles initializing pages that were + * partially initialized by the code below this + * loop. It basically zeroes the part of the page + * that sits on a hole and sets the page as P_HOLE + * and calls remapf if it is a mapped file. + */ + prev_zero_fsb = NULLFILEOFF; + prev_zero_count = 0; + start_zero_fsb = imap.br_startoff + + imap.br_blockcount; + ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); + continue; + } + + /* + * There are blocks in the range requested. + * Zero them a single write at a time. We actually + * don't zero the entire range returned if it is + * too big and simply loop around to get the rest. + * That is not the most efficient thing to do, but it + * is simple and this path should not be exercised often. + */ + buf_len_fsb = XFS_FILBLKS_MIN(imap.br_blockcount, + io->io_writeio_blocks); + /* + * Drop the inode lock while we're doing the I/O. + * We'll still have the iolock to protect us. + */ + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + + loff = XFS_FSB_TO_B(mp, start_zero_fsb); + lsize = XFS_FSB_TO_B(mp, buf_len_fsb); + /* + * real-time files need work here + */ + + pb = pagebuf_lookup(ip, loff, lsize, PBF_ENTER_PAGES); + if (!pb) { + error = ENOMEM; + goto out_lock; + } + + if (imap.br_startblock != DELAYSTARTBLOCK) { + pb->pb_bn = XFS_FSB_TO_DB_IO(io, imap.br_startblock); + if (imap.br_state == XFS_EXT_UNWRITTEN) { + printk("xfs_zero_eof: unwritten? what do we do here?\n"); + } + } + + /* pagebuf_iozero returns negative error */ + if ((error = -pagebuf_iozero(ip, pb, 0, lsize))) { + pagebuf_rele(pb); + goto out_lock; + } + + if (imap.br_startblock == DELAYSTARTBLOCK || + imap.br_state == XFS_EXT_UNWRITTEN) { /* DELWRI */ + pagebuf_rele(pb); + } else { + XFS_BUF_WRITE(pb); + XFS_BUF_ASYNC(pb); + XFS_bwrite(pb); + } + if (error) { + goto out_lock; + } + + prev_zero_fsb = start_zero_fsb; + prev_zero_count = buf_len_fsb; + start_zero_fsb = imap.br_startoff + buf_len_fsb; + ASSERT(start_zero_fsb <= (end_zero_fsb + 1)); + + XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + } + + return 0; + +out_lock: + + XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + ASSERT(error >= 0); + return error; +} + +ssize_t /* error (positive) */ +xfs_write( + bhv_desc_t *bdp, + uio_t *uiop, + int ioflag, + cred_t *credp, + flid_t *fl) +{ + xfs_inode_t *xip; + struct file *filp = uiop->uio_fp; + struct inode *ip = filp->f_dentry->d_inode; + loff_t *offsetp = &uiop->uio_offset; + xfs_mount_t *mp; + xfs_trans_t *tp; + ssize_t ret; + int error = 0; + xfs_fsize_t isize; + xfs_fsize_t n, limit = XFS_MAX_FILE_OFFSET; + xfs_iocore_t *io; + vnode_t *vp; + int iolock; + int direct = filp->f_flags & O_DIRECT; +#ifdef CONFIG_XFS_DMAPI + int eventsent = 0; + loff_t savedsize = *offsetp; +#endif + vrwlock_t locktype; + char *buf; + size_t size; + unsigned int mode; + + + ASSERT(uiop); /* we only support exactly 1 */ + ASSERT(uiop->uio_iovcnt == 1); /* iov in a uio on linux */ + ASSERT(uiop->uio_iov); + + vp = BHV_TO_VNODE(bdp); + xip = XFS_BHVTOI(bdp); + if (XFS_FORCED_SHUTDOWN(xip->i_mount)) { + return EIO; + } + + buf = uiop->uio_iov->iov_base; + size = uiop->uio_iov->iov_len; + + if (size == 0) + return 0; + + io = &(xip->i_iocore); + mp = io->io_mount; + + xfs_check_frozen(mp, XFS_FREEZE_WRITE); + + if (direct) { + if (((__psint_t)buf & (ip->i_sb->s_blocksize - 1)) || + (uiop->uio_offset & mp->m_blockmask) || + (size & mp->m_blockmask)) { + return XFS_ERROR(EINVAL); + } + iolock = XFS_IOLOCK_SHARED; + locktype = VRWLOCK_WRITE_DIRECT; + } else { + iolock = XFS_IOLOCK_EXCL; + locktype = VRWLOCK_WRITE; + } + + xfs_ilock(xip, XFS_ILOCK_EXCL|iolock); + isize = xip->i_d.di_size; + +#ifdef CONFIG_XFS_DMAPI +start: +#endif + n = limit - *offsetp; + if (n <= 0) { + xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); + return EFBIG; + } + if (n < size) + size = n; + +#ifdef CONFIG_XFS_DMAPI + if ((DM_EVENT_ENABLED_IO(vp->v_vfsp, io, DM_EVENT_WRITE) && + !(filp->f_flags & O_INVISIBLE) && !eventsent)) { + + error = xfs_dm_send_data_event(DM_EVENT_WRITE, bdp, + *offsetp, size, + FILP_DELAY_FLAG(filp), &locktype); + if (error) { + xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); + return error; + } + eventsent = 1; + } + /* + * The iolock was dropped and reaquired in + * xfs_dm_send_data_event so we have to recheck the size + * when appending. We will only "goto start;" once, + * since having sent the event prevents another call + * to xfs_dm_send_data_event, which is what + * allows the size to change in the first place. + */ + if ((filp->f_flags & O_APPEND) && savedsize != xip->i_d.di_size) { + *offsetp = isize = xip->i_d.di_size; + goto start; + } +#endif /* CONFIG_XFS_DMAPI */ + + /* + * On Linux, generic_file_write updates the times even if + * no data is copied in so long as the write had a size. + * + * We must update xfs' times since revalidate will overcopy xfs. + */ + if (size) { + if (!(filp->f_flags & O_INVISIBLE)) + xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + } + + /* + * If the offset is beyond the size of the file, we have a couple + * of things to do. First, if there is already space allocated + * we need to either create holes or zero the disk or ... + * + * If there is a page where the previous size lands, we need + * to zero it out up to the new size. + */ + + if (!direct && (*offsetp > isize && isize)) { + io->io_writeio_blocks = mp->m_writeio_blocks; + error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, *offsetp, + isize, NULL); + if (error) { + xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); + return(error); + } + } + xfs_iunlock(xip, XFS_ILOCK_EXCL); + +#ifdef CONFIG_XFS_DMAPI +retry: +#endif + if (direct) { + xfs_inval_cached_pages(vp, &xip->i_iocore, *offsetp, + (xfs_off_t) size, (void *)vp); + } + + /* + * pagebuf_generic_file_write will return positive if bytes + * written, negative if error. We'll live with (-) error + * for the moment, but flip error sign before we pass it up + */ + + ret = pagebuf_generic_file_write(filp, buf, size, offsetp, + linvfs_pb_bmap); + +#ifdef CONFIG_XFS_DMAPI + if ((ret == -ENOSPC) && + DM_EVENT_ENABLED_IO(vp->v_vfsp, io, DM_EVENT_NOSPACE) && + !(filp->f_flags & O_INVISIBLE)) { + + VOP_RWUNLOCK(vp, locktype); + error = dm_send_namesp_event(DM_EVENT_NOSPACE, bdp, + DM_RIGHT_NULL, bdp, DM_RIGHT_NULL, NULL, NULL, + 0, 0, 0); /* Delay flag intentionally unused */ + if (error) + return error; + VOP_RWLOCK(vp, locktype); + *offsetp = ip->i_size; + goto retry; + + } +#endif /* CONFIG_XFS_DMAPI */ + + if (ret <=0) { /* + * ret from pagebuf_generic_file_write <= 0, it's + * an error, we want to return positive though + * then bail out... + */ + xfs_rwunlock(bdp, locktype); + error = -(int)ret; + return(error); + } + + /* + * ret > 0 == number of bytes written by pagebuf_generic_file_write() + * Keep track of any unwritten bytes in uio_resid. + */ + + uiop->uio_resid = size - ret; + + /* JIMJIM Lock? around the stuff below if Linux doesn't lock above */ + + /* set S_IGID if S_IXGRP is set, and always set S_ISUID */ + mode = (ip->i_mode & S_IXGRP)*(S_ISGID/S_IXGRP) | S_ISUID; + + /* were any of the uid bits set? */ + mode &= ip->i_mode; + if (mode && !capable(CAP_FSETID)) { + ip->i_mode &= ~mode; + xfs_write_clear_setuid(xip); + } + if (*offsetp > xip->i_d.di_size) { + XFS_SETSIZE(mp, io, *offsetp); + } + + /* Handle various SYNC-type writes */ + if (ioflag & PBF_SYNC) { + + /* Flush all inode data buffers */ + + fsync_inode_buffers(ip); + + /* + * If we're treating this as O_DSYNC and we have not updated the + * size, force the log. + */ + + if ((mp->m_flags & XFS_MOUNT_OSYNCISDSYNC) + && !(xip->i_update_size)) { + /* + * If an allocation transaction occurred + * without extending the size, then we have to force + * the log up the proper point to ensure that the + * allocation is permanent. We can't count on + * the fact that buffered writes lock out direct I/O + * writes - the direct I/O write could have extended + * the size nontransactionally, then finished before + * we started. xfs_write_file will think that the file + * didn't grow but the update isn't safe unless the + * size change is logged. + * + * Force the log if we've committed a transaction + * against the inode or if someone else has and + * the commit record hasn't gone to disk (e.g. + * the inode is pinned). This guarantees that + * all changes affecting the inode are permanent + * when we return. + */ + + xfs_inode_log_item_t *iip; + xfs_lsn_t lsn; + + iip = xip->i_itemp; + if (iip && iip->ili_last_lsn) { + lsn = iip->ili_last_lsn; + xfs_log_force(mp, lsn, + XFS_LOG_FORCE | XFS_LOG_SYNC); + } else if (xfs_ipincount(xip) > 0) { + xfs_log_force(mp, (xfs_lsn_t)0, + XFS_LOG_FORCE | XFS_LOG_SYNC); + } + + } else { + /* + * O_SYNC or O_DSYNC _with_ a size update are handled + * the same way. + * + * If the write was synchronous then we need to make + * sure that the inode modification time is permanent. + * We'll have updated the timestamp above, so here + * we use a synchronous transaction to log the inode. + * It's not fast, but it's necessary. + * + * If this a dsync write and the size got changed + * non-transactionally, then we need to ensure that + * the size change gets logged in a synchronous + * transaction. + */ + + tp = xfs_trans_alloc(mp, XFS_TRANS_WRITE_SYNC); + if ((error = xfs_trans_reserve(tp, 0, + XFS_SWRITE_LOG_RES(mp), + 0, 0, 0))) { + /* Transaction reserve failed */ + xfs_trans_cancel(tp, 0); + } else { + /* Transaction reserve successful */ + xfs_ilock(xip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, xip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, xip); + xfs_trans_log_inode(tp, xip, XFS_ILOG_CORE); + xfs_trans_set_sync(tp); + error = xfs_trans_commit(tp, 0, (xfs_lsn_t)0); + xfs_iunlock(xip, XFS_ILOCK_EXCL); + } + } + } /* (ioflag & PBF_SYNC) */ + + /* + * If we are coming from an nfsd thread then insert into the + * reference cache. + */ + + if (!strcmp(current->comm, "nfsd")) + xfs_refcache_insert(xip); + + /* Drop lock this way - the old refcache release is in here */ + xfs_rwunlock(bdp, locktype); + + ASSERT(ret >= 0); + return(error); +} + +/* + * xfs_bmap() is the same as the irix xfs_bmap from xfs_rw.c + * execpt for slight changes to the params + */ +int +xfs_bmap(bhv_desc_t *bdp, + xfs_off_t offset, + ssize_t count, + int flags, + struct cred *cred, + pb_bmap_t *pbmapp, + int *npbmaps) +{ + xfs_inode_t *ip; + int error; + int unlocked; + int lockmode; + int fsynced = 0; + vnode_t *vp; + + ip = XFS_BHVTOI(bdp); + ASSERT((ip->i_d.di_mode & IFMT) == IFREG); + ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) == + ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0)); + ASSERT((flags & PBF_READ) || (flags & PBF_WRITE)); + + if (XFS_FORCED_SHUTDOWN(ip->i_iocore.io_mount)) + return XFS_ERROR(EIO); + + if (flags & PBF_READ) { + unlocked = 0; + lockmode = xfs_ilock_map_shared(ip); + error = xfs_iomap_read(&ip->i_iocore, offset, count, + XFS_BMAPI_ENTIRE, pbmapp, npbmaps, NULL); + xfs_iunlock_map_shared(ip, lockmode); + } else { /* PBF_WRITE */ + ASSERT(flags & PBF_WRITE); + vp = BHV_TO_VNODE(bdp); + xfs_ilock(ip, XFS_ILOCK_EXCL); + + /* + * Make sure that the dquots are there. This doesn't hold + * the ilock across a disk read. + */ + + if (XFS_IS_QUOTA_ON(ip->i_mount)) { + if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) { + if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED))) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + return XFS_ERROR(error); + } + } + } +retry: + error = xfs_iomap_write(&ip->i_iocore, offset, count, + pbmapp, npbmaps, flags, NULL); + /* xfs_iomap_write unlocks/locks/unlocks */ + + if ((error == ENOSPC) && strcmp(current->comm, "nfsd")) { + switch (fsynced) { + case 0: + VOP_FLUSH_PAGES(vp, 0, -1, 0, FI_NONE, error); + error = 0; + fsynced = 1; + xfs_ilock(ip, XFS_ILOCK_EXCL); + goto retry; + case 1: + fsynced = 2; + if (!(flags & PBF_SYNC)) { + flags |= PBF_SYNC; + error = 0; + xfs_ilock(ip, XFS_ILOCK_EXCL); + goto retry; + } + case 2: + case 3: + VFS_SYNC(vp->v_vfsp, + SYNC_NOWAIT|SYNC_BDFLUSH|SYNC_FSDATA, + NULL, error); + error = 0; +/** + delay(HZ); +**/ + fsynced++; + xfs_ilock(ip, XFS_ILOCK_EXCL); + goto retry; + } + } + } + + return XFS_ERROR(error); +} + +int +xfs_strategy(bhv_desc_t *bdp, + xfs_off_t offset, + ssize_t count, + int flags, + struct cred *cred, + pb_bmap_t *pbmapp, + int *npbmaps) +{ + xfs_inode_t *ip; + xfs_iocore_t *io; + xfs_mount_t *mp; + int error; + xfs_fileoff_t offset_fsb; + xfs_fileoff_t end_fsb; + xfs_fileoff_t map_start_fsb; + xfs_fileoff_t last_block; + xfs_fsblock_t first_block; + xfs_bmap_free_t free_list; + xfs_filblks_t count_fsb; + int committed, i, loops, nimaps; + int is_xfs = 1; /* This will be a variable at some point */ + xfs_bmbt_irec_t imap[XFS_MAX_RW_NBMAPS]; + xfs_trans_t *tp; + + ip = XFS_BHVTOI(bdp); + io = &ip->i_iocore; + mp = ip->i_mount; + /* is_xfs = IO_IS_XFS(io); */ + ASSERT((ip->i_d.di_mode & IFMT) == IFREG); + ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) == + ((io->io_flags & XFS_IOCORE_RT) != 0)); + ASSERT((flags & PBF_READ) || (flags & PBF_WRITE)); + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + ASSERT(flags & PBF_WRITE); + + offset_fsb = XFS_B_TO_FSBT(mp, offset); + nimaps = min(XFS_MAX_RW_NBMAPS, *npbmaps); + end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); + first_block = NULLFSBLOCK; + + XFS_ILOCK(mp, io, XFS_ILOCK_SHARED | XFS_EXTSIZE_RD); + error = XFS_BMAPI(mp, NULL, io, offset_fsb, + (xfs_filblks_t)(end_fsb - offset_fsb), + XFS_BMAPI_ENTIRE, &first_block, 0, imap, + &nimaps, NULL); + XFS_IUNLOCK(mp, io, XFS_ILOCK_SHARED | XFS_EXTSIZE_RD); + if (error) { + return XFS_ERROR(error); + } + + if (nimaps && !ISNULLSTARTBLOCK(imap[0].br_startblock)) { + *npbmaps = _xfs_imap_to_bmap(&ip->i_iocore, offset, imap, + pbmapp, nimaps, *npbmaps); + return 0; + } + + /* + * Make sure that the dquots are there. + */ + + if (XFS_IS_QUOTA_ON(mp)) { + if (XFS_NOT_DQATTACHED(mp, ip)) { + if ((error = xfs_qm_dqattach(ip, 0))) { + return XFS_ERROR(error); + } + } + } + XFS_STATS_ADD(xfsstats.xs_xstrat_bytes, + XFS_FSB_TO_B(mp, imap[0].br_blockcount)); + + offset_fsb = imap[0].br_startoff; + count_fsb = imap[0].br_blockcount; + map_start_fsb = offset_fsb; + while (count_fsb != 0) { + /* + * Set up a transaction with which to allocate the + * backing store for the file. Do allocations in a + * loop until we get some space in the range we are + * interested in. The other space that might be allocated + * is in the delayed allocation extent on which we sit + * but before our buffer starts. + */ + nimaps = 0; + loops = 0; + while (nimaps == 0) { + if (is_xfs) { + tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE); + error = xfs_trans_reserve(tp, 0, + XFS_WRITE_LOG_RES(mp), + 0, XFS_TRANS_PERM_LOG_RES, + XFS_WRITE_LOG_COUNT); + if (error) { + xfs_trans_cancel(tp, 0); + goto error0; + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, + XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + } else { + tp = NULL; + XFS_ILOCK(mp, io, XFS_ILOCK_EXCL | + XFS_EXTSIZE_WR); + } + + + /* + * Allocate the backing store for the file. + */ + XFS_BMAP_INIT(&(free_list), + &(first_block)); + nimaps = XFS_STRAT_WRITE_IMAPS; + + /* + * Ensure we don't go beyond eof - it is possible + * the extents changed since we did the read call, + * we dropped the ilock in the interim. + */ + + end_fsb = XFS_B_TO_FSB(mp, XFS_SIZE(mp, io)); + xfs_bmap_last_offset(NULL, ip, &last_block, + XFS_DATA_FORK); + last_block = XFS_FILEOFF_MAX(last_block, end_fsb); + if ((map_start_fsb + count_fsb) > last_block) { + count_fsb = last_block - map_start_fsb; + if (count_fsb == 0) { + if (is_xfs) { + xfs_bmap_cancel(&free_list); + xfs_trans_cancel(tp, + (XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT)); + } + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL | + XFS_EXTSIZE_WR); + return XFS_ERROR(EAGAIN); + } + } + + error = XFS_BMAPI(mp, tp, io, map_start_fsb, count_fsb, + XFS_BMAPI_WRITE, &first_block, 1, + imap, &nimaps, &free_list); + if (error) { + xfs_bmap_cancel(&free_list); + xfs_trans_cancel(tp, + (XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT)); + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL | + XFS_EXTSIZE_WR); + + goto error0; + } + + if (is_xfs) { + error = xfs_bmap_finish(&(tp), &(free_list), + first_block, &committed); + if (error) { + xfs_bmap_cancel(&free_list); + xfs_trans_cancel(tp, + (XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT)); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + goto error0; + } + + error = xfs_trans_commit(tp, + XFS_TRANS_RELEASE_LOG_RES, + NULL); + if (error) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + goto error0; + } + } + + if (nimaps == 0) { + XFS_IUNLOCK(mp, io, + XFS_ILOCK_EXCL|XFS_EXTSIZE_WR); + } /* else hold 'till we maybe loop again below */ + } + + /* + * See if we were able to allocate an extent that + * covers at least part of the user's requested size. + */ + + offset_fsb = XFS_B_TO_FSBT(mp, offset); + for(i = 0; i < nimaps; i++) { + int maps; + if (offset_fsb >= imap[i].br_startoff && + (offset_fsb < (imap[i].br_startoff + imap[i].br_blockcount))) { + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL | XFS_EXTSIZE_WR); + maps = min(nimaps, *npbmaps); + *npbmaps = _xfs_imap_to_bmap(io, offset, &imap[i], + pbmapp, maps, *npbmaps); + XFS_STATS_INC(xfsstats.xs_xstrat_quick); + return 0; + } + count_fsb -= imap[i].br_blockcount; /* for next bmapi, + if needed. */ + } + + /* + * We didn't get an extent the caller can write into so + * loop around and try starting after the last imap we got back. + */ + + nimaps--; /* Index of last entry */ + ASSERT(nimaps >= 0); + ASSERT(offset_fsb >= imap[nimaps].br_startoff + imap[nimaps].br_blockcount); + ASSERT(count_fsb); + offset_fsb = imap[nimaps].br_startoff + imap[nimaps].br_blockcount; + map_start_fsb = offset_fsb; + XFS_STATS_INC(xfsstats.xs_xstrat_split); + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_WR); + } + + ASSERT(0); /* Should never get here */ + + error0: + if (error) { + ASSERT(count_fsb != 0); + ASSERT(is_xfs || XFS_FORCED_SHUTDOWN(mp)); + } + + return XFS_ERROR(error); +} + + +int +_xfs_imap_to_bmap( + xfs_iocore_t *io, + xfs_off_t offset, + xfs_bmbt_irec_t *imap, + pb_bmap_t *pbmapp, + int imaps, /* Number of imap entries */ + int pbmaps) /* Number of pbmap entries */ +{ + xfs_mount_t *mp; + xfs_fsize_t nisize; + int im, pbm; + xfs_fsblock_t start_block; + + mp = io->io_mount; + nisize = XFS_SIZE(mp, io); + if (io->io_new_size > nisize) + nisize = io->io_new_size; + + for (im=0, pbm=0; im < imaps && pbm < pbmaps; im++,pbmapp++,imap++,pbm++) { + if (io->io_flags & XFS_IOCORE_RT) { + pbmapp->pbm_dev = mp->m_rtdev; + } else { + pbmapp->pbm_dev = mp->m_dev; + } + pbmapp->pbm_offset = XFS_FSB_TO_B(mp, imap->br_startoff); + pbmapp->pbm_delta = offset - pbmapp->pbm_offset; + pbmapp->pbm_bsize = XFS_FSB_TO_B(mp, imap->br_blockcount); + pbmapp->pbm_flags = 0; + + + start_block = imap->br_startblock; + if (start_block == HOLESTARTBLOCK) { + pbmapp->pbm_bn = PAGE_BUF_DADDR_NULL; + pbmapp->pbm_flags = PBMF_HOLE; + } else if (start_block == DELAYSTARTBLOCK) { + pbmapp->pbm_bn = PAGE_BUF_DADDR_NULL; + pbmapp->pbm_flags = PBMF_DELAY; + } else { + pbmapp->pbm_bn = XFS_FSB_TO_DB_IO(io, start_block); + if (imap->br_state == XFS_EXT_UNWRITTEN) + pbmapp->pbm_flags |= PBMF_UNWRITTEN; + } + + if (XFS_FSB_TO_B(mp, pbmapp->pbm_offset + pbmapp->pbm_bsize) + >= nisize) { + pbmapp->pbm_flags |= PBMF_EOF; + } + + offset += pbmapp->pbm_bsize - pbmapp->pbm_delta; + } + return(pbm); /* Return the number filled */ +} + +int +xfs_iomap_read( + xfs_iocore_t *io, + loff_t offset, + size_t count, + int flags, + pb_bmap_t *pbmapp, + int *npbmaps, + struct pm *pmp) +{ + xfs_fileoff_t offset_fsb; + xfs_fileoff_t end_fsb; + xfs_fsblock_t firstblock; + int nimaps; + int error; + xfs_mount_t *mp; + xfs_bmbt_irec_t imap[XFS_MAX_RW_NBMAPS]; + + ASSERT(ismrlocked(io->io_lock, MR_UPDATE | MR_ACCESS) != 0); +/** ASSERT(ismrlocked(io->io_iolock, MR_UPDATE | MR_ACCESS) != 0); **/ +/* xfs_iomap_enter_trace(XFS_IOMAP_READ_ENTER, io, offset, count); */ + + mp = io->io_mount; + offset_fsb = XFS_B_TO_FSBT(mp, offset); + nimaps = sizeof(imap) / sizeof(imap[0]); + nimaps = min(nimaps, *npbmaps); /* Don't ask for more than caller has */ + end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); + firstblock = NULLFSBLOCK; + error = XFS_BMAPI(mp, NULL, io, offset_fsb, + (xfs_filblks_t)(end_fsb - offset_fsb), + flags, &firstblock, 0, imap, + &nimaps, NULL); + if (error) { + return XFS_ERROR(error); + } + + if(nimaps) { + *npbmaps = _xfs_imap_to_bmap(io, offset, imap, pbmapp, nimaps, + *npbmaps); + } else + *npbmaps = 0; + return XFS_ERROR(error); +} + +/* + * xfs_iomap_write: return pagebuf_bmap_t's telling higher layers + * where to write. + * There are 2 main cases: + * 1 the extents already exist + * 2 must allocate. + * There are 3 cases when we allocate: + * delay allocation (doesn't really allocate or use transactions) + * direct allocation (no previous delay allocation + * convert delay to real allocations + */ + +STATIC int +xfs_iomap_write( + xfs_iocore_t *io, + loff_t offset, + size_t count, + pb_bmap_t *pbmapp, + int *npbmaps, + int ioflag, + struct pm *pmp) +{ + int maps; + int error = 0; + +#define XFS_WRITE_IMAPS XFS_BMAP_MAX_NMAP + int found; + int flags = 0; + int iunlock = 1; /* Cleared if lower routine did unlock */ + + maps = *npbmaps; + if (!maps) + goto out; + + /* + * If we have extents that are allocated for this range, + * return them. + */ + + found = 0; + error = xfs_iomap_read(io, offset, count, flags, pbmapp, npbmaps, NULL); + if (error) + goto out; + + /* + * If we found mappings and they can just have data written + * without conversion, + * let the caller write these and call us again. + * + * If we have a HOLE or UNWRITTEN, proceed down lower to + * get the space or to convert to written. + */ + + if (*npbmaps) { + if (!(pbmapp->pbm_flags & PBMF_HOLE)) { + *npbmaps = 1; /* Only checked the first one. */ + /* We could check more, ... */ + goto out; + } + } + found = *npbmaps; + *npbmaps = maps; /* Restore to original requested */ + + if (ioflag & PBF_DIRECT) { + error = xfs_iomap_write_direct(io, offset, count, pbmapp, + npbmaps, ioflag, found); + } else { + error = xfs_iomap_write_delay(io, offset, count, pbmapp, + npbmaps, ioflag, found); + } + +out: + if (iunlock) + XFS_IUNLOCK(io->io_mount, io, XFS_ILOCK_EXCL); + + XFS_INODE_CLEAR_READ_AHEAD(io); + return XFS_ERROR(error); +} + +#ifdef DEBUG +/* + * xfs_strat_write_check + * + * Make sure that there are blocks or delayed allocation blocks + * underlying the entire area given. The imap parameter is simply + * given as a scratch area in order to reduce stack space. No + * values are returned within it. + */ +STATIC void +xfs_strat_write_check( + xfs_iocore_t *io, + xfs_fileoff_t offset_fsb, + xfs_filblks_t buf_fsb, + xfs_bmbt_irec_t *imap, + int imap_count) +{ + xfs_filblks_t count_fsb; + xfs_fsblock_t firstblock; + xfs_mount_t *mp; + int nimaps; + int n; + int error; + + if (!IO_IS_XFS(io)) return; + + mp = io->io_mount; + count_fsb = 0; + while (count_fsb < buf_fsb) { + nimaps = imap_count; + firstblock = NULLFSBLOCK; + error = XFS_BMAPI(mp, NULL, io, (offset_fsb + count_fsb), + (buf_fsb - count_fsb), 0, &firstblock, 0, + imap, &nimaps, NULL); + if (error) { + return; + } + ASSERT(nimaps > 0); + n = 0; + while (n < nimaps) { + ASSERT(imap[n].br_startblock != HOLESTARTBLOCK); + count_fsb += imap[n].br_blockcount; + ASSERT(count_fsb <= buf_fsb); + n++; + } + } + return; +} +#endif /* DEBUG */ + +/* + * Map the given I/O size and I/O alignment over the given extent. + * If we're at the end of the file and the underlying extent is + * delayed alloc, make sure we extend out to the + * next i_writeio_blocks boundary. Otherwise make sure that we + * are confined to the given extent. + */ +/*ARGSUSED*/ +STATIC void +xfs_write_bmap( + xfs_mount_t *mp, + xfs_iocore_t *io, + xfs_bmbt_irec_t *imapp, + pb_bmap_t *pbmapp, + int iosize, + xfs_fileoff_t ioalign, + xfs_fsize_t isize) +{ + __int64_t extra_blocks; + xfs_fileoff_t size_diff; + xfs_fileoff_t ext_offset; + xfs_fsblock_t start_block; + int length; /* length of this mapping in blocks */ + xfs_off_t offset; /* logical block offset of this mapping */ + + if (ioalign < imapp->br_startoff) { + /* + * The desired alignment doesn't end up on this + * extent. Move up to the beginning of the extent. + * Subtract whatever we drop from the iosize so that + * we stay aligned on iosize boundaries. + */ + size_diff = imapp->br_startoff - ioalign; + iosize -= (int)size_diff; + ASSERT(iosize > 0); + ext_offset = 0; + offset = imapp->br_startoff; + pbmapp->pbm_offset = XFS_FSB_TO_B(mp, imapp->br_startoff); + } else { + /* + * The alignment requested fits on this extent, + * so use it. + */ + ext_offset = ioalign - imapp->br_startoff; + offset = ioalign; + pbmapp->pbm_offset = XFS_FSB_TO_B(mp, ioalign); + } + start_block = imapp->br_startblock; + ASSERT(start_block != HOLESTARTBLOCK); + if (start_block != DELAYSTARTBLOCK) { + pbmapp->pbm_bn = XFS_FSB_TO_DB_IO(io, start_block + ext_offset); + if (imapp->br_state == XFS_EXT_UNWRITTEN) { + pbmapp->pbm_flags = PBMF_UNWRITTEN; + } + } else { + pbmapp->pbm_bn = PAGE_BUF_DADDR_NULL; + pbmapp->pbm_flags = PBMF_DELAY; + } + length = iosize; + + /* + * If the iosize from our offset extends beyond the end of + * the extent, then trim down length to match that of the extent. + */ + extra_blocks = (xfs_off_t)(offset + length) - + (__uint64_t)(imapp->br_startoff + + imapp->br_blockcount); + if (extra_blocks > 0) { + length -= extra_blocks; + ASSERT(length > 0); + } + + pbmapp->pbm_bsize = XFS_FSB_TO_B(mp, length); +} + +int +xfs_iomap_write_delay( + xfs_iocore_t *io, + loff_t offset, + size_t count, + pb_bmap_t *pbmapp, + int *npbmaps, + int ioflag, + int found) +{ + xfs_fileoff_t offset_fsb; + xfs_fileoff_t ioalign; + xfs_fileoff_t last_fsb; + xfs_fileoff_t start_fsb; + xfs_filblks_t count_fsb; + xfs_off_t aligned_offset; + xfs_fsize_t isize; + xfs_fsblock_t firstblock; + __uint64_t last_page_offset; + int nimaps; + int error; + int n; + unsigned int iosize; + short small_write; + xfs_mount_t *mp; +#define XFS_WRITE_IMAPS XFS_BMAP_MAX_NMAP + xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS]; + int aeof; +#ifdef DELALLOC_BUG + unsigned int writing_bytes; +#endif + + ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0); + +/* xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, io, offset, count); */ + + mp = io->io_mount; +/*** + ASSERT(! XFS_NOT_DQATTACHED(mp, ip)); +***/ + + isize = XFS_SIZE(mp, io); + if (io->io_new_size > isize) { + isize = io->io_new_size; + } + + aeof = 0; + offset_fsb = XFS_B_TO_FSBT(mp, offset); + last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); + /* + * If the caller is doing a write at the end of the file, + * then extend the allocation (and the buffer used for the write) + * out to the file system's write iosize. We clean up any extra + * space left over when the file is closed in xfs_inactive(). + * We can only do this if we are sure that we will create buffers + * over all of the space we allocate beyond the end of the file. + * Not doing so would allow us to create delalloc blocks with + * no pages in memory covering them. So, we need to check that + * there are not any real blocks in the area beyond the end of + * the file which we are optimistically going to preallocate. If + * there are then our buffers will stop when they encounter them + * and we may accidentally create delalloc blocks beyond them + * that we never cover with a buffer. All of this is because + * we are not actually going to write the extra blocks preallocated + * at this point. + * + * We don't bother with this for sync writes, because we need + * to minimize the amount we write for good performance. + */ + if (!(ioflag & PBF_SYNC) && ((offset + count) > XFS_SIZE(mp, io))) { + start_fsb = XFS_B_TO_FSBT(mp, + ((xfs_ufsize_t)(offset + count - 1))); + count_fsb = io->io_writeio_blocks; + while (count_fsb > 0) { + nimaps = XFS_WRITE_IMAPS; + firstblock = NULLFSBLOCK; + error = XFS_BMAPI(mp, NULL, io, start_fsb, count_fsb, + 0, &firstblock, 0, imap, &nimaps, + NULL); + if (error) { + return error; + } + for (n = 0; n < nimaps; n++) { + if ((imap[n].br_startblock != HOLESTARTBLOCK) && + (imap[n].br_startblock != DELAYSTARTBLOCK)) { + goto write_map; + } + start_fsb += imap[n].br_blockcount; + count_fsb -= imap[n].br_blockcount; + ASSERT(count_fsb < 0xffff000); + } + } + iosize = io->io_writeio_blocks; + aligned_offset = XFS_WRITEIO_ALIGN(io, (offset + count - 1)); + ioalign = XFS_B_TO_FSBT(mp, aligned_offset); + last_fsb = ioalign + iosize; + aeof = 1; + } + write_map: + nimaps = XFS_WRITE_IMAPS; + firstblock = NULLFSBLOCK; + + /* + * roundup the allocation request to m_dalign boundary if file size + * is greater that 512K and we are allocating past the allocation eof + */ + if (mp->m_dalign && (XFS_SIZE(mp, io) >= mp->m_dalign) && aeof) { + int eof; + xfs_fileoff_t new_last_fsb; + new_last_fsb = roundup_64(last_fsb, mp->m_dalign); + error = XFS_BMAP_EOF(mp, io, new_last_fsb, XFS_DATA_FORK, &eof); + if (error) { + return error; + } + if (eof) { + last_fsb = new_last_fsb; + } + } + + error = XFS_BMAPI(mp, NULL, io, offset_fsb, + (xfs_filblks_t)(last_fsb - offset_fsb), + XFS_BMAPI_DELAY | XFS_BMAPI_WRITE | + XFS_BMAPI_ENTIRE, &firstblock, 1, imap, + &nimaps, NULL); + /* + * This can be EDQUOT, if nimaps == 0 + */ + if (error) { + return XFS_ERROR(error); + } + /* + * If bmapi returned us nothing, and if we didn't get back EDQUOT, + * then we must have run out of space. + */ + if (nimaps == 0) { +/* xfs_iomap_enter_trace(XFS_IOMAP_WRITE_NOSPACE, + io, offset, count); */ + return XFS_ERROR(ENOSPC); + } + + if (!(ioflag & PBF_SYNC) || + ((last_fsb - offset_fsb) >= io->io_writeio_blocks)) { + /* + * For normal or large sync writes, align everything + * into i_writeio_blocks sized chunks. + */ + iosize = io->io_writeio_blocks; + aligned_offset = XFS_WRITEIO_ALIGN(io, offset); + ioalign = XFS_B_TO_FSBT(mp, aligned_offset); + small_write = 0; + /* XXX - Are we shrinking? XXXXX */ + } else { + /* + * For small sync writes try to minimize the amount + * of I/O we do. Round down and up to the larger of + * page or block boundaries. Set the small_write + * variable to 1 to indicate to the code below that + * we are not using the normal buffer alignment scheme. + */ + if (NBPP > mp->m_sb.sb_blocksize) { + ASSERT(!(offset & PAGE_MASK)); + aligned_offset = offset; + ioalign = XFS_B_TO_FSBT(mp, aligned_offset); + ASSERT(!((offset + count) & PAGE_MASK)); + last_page_offset = offset + count; + iosize = XFS_B_TO_FSBT(mp, last_page_offset - + aligned_offset); + } else { + ioalign = offset_fsb; + iosize = last_fsb - offset_fsb; + } + small_write = 1; + /* XXX - Are we shrinking? XXXXX */ + } + + /* + * Now map our desired I/O size and alignment over the + * extents returned by xfs_bmapi(). + */ + xfs_write_bmap(mp, io, imap, pbmapp, iosize, ioalign, isize); + pbmapp->pbm_delta = offset - pbmapp->pbm_offset; + + ASSERT((pbmapp->pbm_bsize > 0) + && (pbmapp->pbm_bsize - pbmapp->pbm_delta > 0)); + + /* + * A bmap is the EOF bmap when it reaches to or beyond the new + * inode size. + */ + if ((pbmapp->pbm_offset + pbmapp->pbm_bsize ) >= isize) { + pbmapp->pbm_flags |= PBMF_EOF; + } + +/* xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, + io, offset, count, bmapp, imap); */ + + /* On IRIX, we walk more imaps filling in more bmaps. On Linux + just handle one for now. To find the code on IRIX, + look in xfs_iomap_write() in xfs_rw.c. */ + + *npbmaps = 1; + return 0; +} + +STATIC int +xfs_iomap_write_direct( + xfs_iocore_t *io, + loff_t offset, + size_t count, + pb_bmap_t *pbmapp, + int *npbmaps, + int ioflag, + int found) +{ + xfs_inode_t *ip = XFS_IO_INODE(io); + xfs_mount_t *mp; + xfs_fileoff_t offset_fsb; + xfs_fileoff_t last_fsb; + xfs_filblks_t count_fsb; + xfs_fsize_t isize; + xfs_fsblock_t firstfsb; + int nimaps, maps; + int error; + xfs_trans_t *tp; + +#define XFS_WRITE_IMAPS XFS_BMAP_MAX_NMAP + xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS], *imapp; + xfs_bmap_free_t free_list; + int aeof; + int bmapi_flags; + xfs_filblks_t datablocks; + int rt; + int committed; + int numrtextents; + uint resblks; + int rtextsize; + + maps = min(XFS_WRITE_IMAPS, *npbmaps); + nimaps = maps; + + mp = io->io_mount; + isize = XFS_SIZE(mp, io); + if (io->io_new_size > isize) + isize = io->io_new_size; + + if ((offset + count) > isize) { + aeof = 1; + } else { + aeof = 0; + } + + offset_fsb = XFS_B_TO_FSBT(mp, offset); + last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); + count_fsb = last_fsb - offset_fsb; + if (found && (pbmapp->pbm_flags & PBMF_HOLE)) { + xfs_fileoff_t map_last_fsb; + map_last_fsb = XFS_B_TO_FSB(mp, + (pbmapp->pbm_bsize + pbmapp->pbm_offset)); + + if (map_last_fsb < last_fsb) { + last_fsb = map_last_fsb; + count_fsb = last_fsb - offset_fsb; + } + ASSERT(count_fsb > 0); + } + + /* + * roundup the allocation request to m_dalign boundary if file size + * is greater that 512K and we are allocating past the allocation eof + */ + if (!found && mp->m_dalign && (isize >= 524288) && aeof) { + int eof; + xfs_fileoff_t new_last_fsb; + new_last_fsb = roundup_64(last_fsb, mp->m_dalign); + printk("xfs_iomap_write_direct: about to XFS_BMAP_EOF %Ld\n", + new_last_fsb); + error = XFS_BMAP_EOF(mp, io, new_last_fsb, XFS_DATA_FORK, &eof); + if (error) { + goto error_out; + } + if (eof) + last_fsb = new_last_fsb; + } + + bmapi_flags = XFS_BMAPI_WRITE|XFS_BMAPI_DIRECT_IO|XFS_BMAPI_ENTIRE; + bmapi_flags &= ~XFS_BMAPI_DIRECT_IO; + + /* + * determine if this is a realtime file + */ + if ((rt = (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) != 0) { + rtextsize = mp->m_sb.sb_rextsize; + } else + rtextsize = 0; + + error = 0; + + /* + * allocate file space for the bmapp entries passed in. + */ + + /* + * determine if reserving space on + * the data or realtime partition. + */ + if (rt) { + numrtextents = (count_fsb + rtextsize - 1); + do_div(numrtextents, rtextsize); + datablocks = 0; + } else { + datablocks = count_fsb; + numrtextents = 0; + } + + /* + * allocate and setup the transaction + */ + tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); + resblks = XFS_DIOSTRAT_SPACE_RES(mp, datablocks); + + xfs_iunlock(ip, XFS_ILOCK_EXCL); + + error = xfs_trans_reserve(tp, + resblks, + XFS_WRITE_LOG_RES(mp), + numrtextents, + XFS_TRANS_PERM_LOG_RES, + XFS_WRITE_LOG_COUNT); + + /* + * check for running out of space + */ + if (error) { + /* + * Free the transaction structure. + */ + xfs_trans_cancel(tp, 0); + } + + xfs_ilock(ip, XFS_ILOCK_EXCL); + + if (error) { + goto error_out; /* Don't return in above if .. trans .., + need lock to return */ + } + + if (XFS_IS_QUOTA_ON(mp)) { + if (xfs_trans_reserve_quota(tp, + ip->i_udquot, + ip->i_gdquot, + resblks, 0, 0)) { + error = (EDQUOT); + goto error1; + } + nimaps = 1; + } else { + nimaps = 2; + } + + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + + /* + * issue the bmapi() call to allocate the blocks + */ + XFS_BMAP_INIT(&free_list, &firstfsb); + imapp = &imap[0]; + error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb, + bmapi_flags, &firstfsb, 1, imapp, &nimaps, &free_list); + if (error) { + goto error0; + } + + /* + * complete the transaction + */ + + error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed); + if (error) { + goto error0; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (error) { + goto error_out; + } + + /* copy any maps to caller's array and return any error. */ + if (nimaps == 0) { + error = (ENOSPC); + goto error_out; + } + + maps = min(nimaps, maps); + *npbmaps = _xfs_imap_to_bmap(io, offset, &imap[0], pbmapp, maps, *npbmaps); + if(*npbmaps) { + /* + * this is new since xfs_iomap_read + * didn't find it. + */ + if (*npbmaps != 1) { + printk("NEED MORE WORK FOR MULTIPLE BMAPS (which are new)\n"); + } + } + goto out; + + error0: /* Cancel bmap, unlock inode, and cancel trans */ + xfs_bmap_cancel(&free_list); + + error1: /* Just cancel transaction */ + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); + *npbmaps = 0; /* nothing set-up here */ + +error_out: +out: /* Just return error and any tracing at end of routine */ + return XFS_ERROR(error); +} + + +/* + * All xfs metadata buffers except log state machine buffers + * get this attached as their b_bdstrat callback function. + * This is so that we can catch a buffer + * after prematurely unpinning it to forcibly shutdown the filesystem. + */ +int +xfs_bdstrat_cb(struct xfs_buf *bp) +{ + xfs_mount_t *mp; + + mp = XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *); + if (!XFS_FORCED_SHUTDOWN(mp)) { + pagebuf_iorequest(bp); + return 0; + } else { + xfs_buftrace("XFS__BDSTRAT IOERROR", bp); + /* + * Metadata write that didn't get logged but + * written delayed anyway. These aren't associated + * with a transaction, and can be ignored. + */ + if (XFS_BUF_IODONE_FUNC(bp) == NULL && + (XFS_BUF_ISREAD(bp)) == 0) + return (xfs_bioerror_relse(bp)); + else + return (xfs_bioerror(bp)); + } +} +/* + * Wrapper around bdstrat so that we can stop data + * from going to disk in case we are shutting down the filesystem. + * Typically user data goes thru this path; one of the exceptions + * is the superblock. + */ +int +xfsbdstrat( + struct xfs_mount *mp, + struct xfs_buf *bp) +{ + ASSERT(mp); + if (!XFS_FORCED_SHUTDOWN(mp)) { + if (XFS_BUF_IS_GRIO(bp)) { + printk("xfsbdstrat needs grio_strategy\n"); + } else { + pagebuf_iorequest(bp); + } + + return 0; + } + + xfs_buftrace("XFSBDSTRAT IOERROR", bp); + return (xfs_bioerror_relse(bp)); +} + + +void +XFS_bflush(buftarg_t target) +{ + pagebuf_delwri_flush(target.pb_targ, PBDF_WAIT, NULL); +} + + +/* Try very hard to clean up a filesystem for READ ONLY status + * This is a very non deterministic method and such does not + * always work. + * In the case of shutting down a system that has an XFS root + * file system it works most of the time, since most processes + * have been killed prior to this happening. + * It appears the upper layer of linux will let stuff through + * even after the super block has been marked READ ONLY. + * More investigation is necessary in this area. + */ + +void +XFS_log_write_unmount_ro(bhv_desc_t *bdp) +{ + xfs_mount_t *mp; + int pincount = 0; + int count=0; + + mp = XFS_BHVTOM(bdp); + + do { + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); + pagebuf_delwri_flush(mp->m_ddev_targ.pb_targ, + PBDF_WAIT, &pincount); + if (pincount == 0) {delay(50); count++;} + } while (count < 2); + + /* ok this is a best guest at this point + * hopefully everybody has stopped writing to filesystem + * and the loop above has pushed everything out. + * write out the superblock which should be the last of + * transactions + */ + xfs_unmountfs_writesb(mp); + + do { + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); + pagebuf_delwri_flush(mp->m_ddev_targ.pb_targ, + PBDF_WAIT, &pincount); + } while (pincount); + + /* Ok now write out an unmount record */ + xfs_log_unmount_write(mp); +} + +/* + * In these two situations we disregard the readonly mount flag and + * temporarily enable writes (we must, to ensure metadata integrity). + */ +STATIC int +xfs_is_read_only(xfs_mount_t *mp) +{ + if (is_read_only(mp->m_dev) || is_read_only(mp->m_logdev)) { + cmn_err(CE_NOTE, + "XFS: write access unavailable, cannot proceed."); + return EROFS; + } + cmn_err(CE_NOTE, + "XFS: write access will be enabled during mount."); + XFS_MTOVFS(mp)->vfs_flag &= ~VFS_RDONLY; + return 0; +} + +int +xfs_recover_read_only(xlog_t *log) +{ + cmn_err(CE_NOTE, "XFS: WARNING: " + "recovery required on readonly filesystem."); + return xfs_is_read_only(log->l_mp); +} + +int +xfs_quotacheck_read_only(xfs_mount_t *mp) +{ + cmn_err(CE_NOTE, "XFS: WARNING: " + "quotacheck required on readonly filesystem."); + return xfs_is_read_only(mp); +} diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_lrw.h linux-2.4-xfs/linux/fs/xfs/linux/xfs_lrw.h --- linux-2.4.7/linux/fs/xfs/linux/xfs_lrw.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_lrw.h Mon Feb 26 20:43:46 2001 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef __XFS_LRW_H__ +#define __XFS_LRW_H__ + +#define XFS_IOMAP_READ_ENTER 3 +/* + * Maximum count of bmaps used by read and write paths. + */ +#define XFS_MAX_RW_NBMAPS 4 + +extern int xfs_bmap (bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, pb_bmap_t *, int *); +extern int xfs_strategy (bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, pb_bmap_t *, int *); +extern int xfs_iomap_read (xfs_iocore_t *, loff_t, size_t, int, + pb_bmap_t *, int *, struct pm *); +extern int xfs_iomap_write (xfs_iocore_t *, loff_t, size_t, pb_bmap_t *, + int *, int, struct pm *); +extern int xfsbdstrat (struct xfs_mount *, struct xfs_buf *); +extern int xfs_bdstrat_cb (struct xfs_buf *); + +extern int xfs_zero_eof (vnode_t *, struct xfs_iocore *, xfs_off_t, + xfs_fsize_t, struct pm *); +extern ssize_t xfs_read ( + struct bhv_desc *bdp, + struct uio *uiop, + int ioflag, + struct cred *credp, + struct flid *fl); +extern ssize_t xfs_write ( + struct bhv_desc *bdp, + struct uio *uiop, + int ioflag, + struct cred *credp, + struct flid *fl); + +extern int xfs_recover_read_only (xlog_t *); +extern int xfs_quotacheck_read_only (xfs_mount_t *); + +extern void XFS_log_write_unmount_ro (bhv_desc_t *); + +#define XFS_FSB_TO_DB_IO(io,fsb) \ + (((io)->io_flags & XFS_IOCORE_RT) ? \ + XFS_FSB_TO_BB((io)->io_mount, (fsb)) : \ + XFS_FSB_TO_DADDR((io)->io_mount, (fsb))) + +#endif /* __XFS_LRW_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_stats.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_stats.c --- linux-2.4.7/linux/fs/xfs/linux/xfs_stats.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_stats.c Wed Apr 18 21:37:23 2001 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * This file contains random functions which map IRIX stuff to a + * Linux implemetation. All the memory allocator mappings are + * here, as are some procfs and ktrace routines. + */ + +#include +#include +#include +#include + +#ifdef CONFIG_PROC_FS +static int +xfs_read_xfsstats(char *buffer, char **start, linux_off_t offset, + int count, int *eof, void *data) +{ + int i, j, len; + static struct xstats_entry { + char *desc; + int endpoint; + } xstats[] = { + { "extent_alloc", XFSSTAT_END_EXTENT_ALLOC }, + { "abt", XFSSTAT_END_ALLOC_BTREE }, + { "blk_map", XFSSTAT_END_BLOCK_MAPPING }, + { "bmbt", XFSSTAT_END_BLOCK_MAP_BTREE }, + { "dir", XFSSTAT_END_DIRECTORY_OPS }, + { "trans", XFSSTAT_END_TRANSACTIONS }, + { "ig", XFSSTAT_END_INODE_OPS }, + { "log", XFSSTAT_END_LOG_OPS }, + { "push_ail", XFSSTAT_END_TAIL_PUSHING }, + { "xstrat", XFSSTAT_END_WRITE_CONVERT }, + { "rw", XFSSTAT_END_READ_WRITE_OPS }, + { "attr", XFSSTAT_END_ATTRIBUTE_OPS }, + { "qm", XFSSTAT_END_QUOTA_OPS }, + { "icluster", XFSSTAT_END_INODE_CLUSTER }, + { "vnodes", XFSSTAT_END_VNODE_OPS }, + }; + + for (i=j=len = 0; i < sizeof(xstats)/sizeof(struct xstats_entry); i++) { + len += sprintf(buffer + len, xstats[i].desc); + /* inner loop does each group */ + while (j < xstats[i].endpoint) { + len += sprintf(buffer + len, " %u", + *(((__u32*)&xfsstats) + j)); + j++; + } + buffer[len++] = '\n'; + } + /* extra precision counters */ + len += sprintf(buffer + len, "xpc %Lu %Lu %Lu\n", + xfsstats.xs_xstrat_bytes, + xfsstats.xs_write_bytes, + xfsstats.xs_read_bytes); + + if (offset >= len) { + *start = buffer; + *eof = 1; + return 0; + } + *start = buffer + offset; + if ((len -= offset) > count) + return count; + *eof = 1; + + return len; +} + +static int +xfs_read_xfsquota(char *buffer, char **start, linux_off_t offset, + int count, int *eof, void *data) +{ + int len; + + /* maximum; incore; ratio free to inuse; freelist */ + len = sprintf(buffer, "%d\t%d\t%d\t%u\n", + ndquot, + xfs_Gqm? atomic_read(&xfs_Gqm->qm_totaldquots) : 0, + xfs_Gqm? xfs_Gqm->qm_dqfree_ratio : 0, + xfs_Gqm? xfs_Gqm->qm_dqfreelist.qh_nelems : 0); + + if (offset >= len) { + *start = buffer; + *eof = 1; + return 0; + } + *start = buffer + offset; + if ((len -= offset) > count) + return count; + *eof = 1; + + return len; +} +#endif /* CONFIG_PROC_FS */ + + +void +xfs_init_procfs(void) +{ +#ifdef CONFIG_PROC_FS + if (!proc_mkdir("fs/xfs", 0)) + return; + create_proc_read_entry("fs/xfs/stat", 0, 0, xfs_read_xfsstats, NULL); + create_proc_read_entry("fs/xfs/xqm", 0, 0, xfs_read_xfsquota, NULL); +#endif +} + + +void +xfs_cleanup_procfs(void) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("fs/xfs/stat", NULL); + remove_proc_entry("fs/xfs/xqm", NULL); + remove_proc_entry("fs/xfs", NULL); +#endif +} diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_stats.h linux-2.4-xfs/linux/fs/xfs/linux/xfs_stats.h --- linux-2.4.7/linux/fs/xfs/linux/xfs_stats.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_stats.h Mon Nov 13 20:57:58 2000 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_RANDOM_H__ +#define __XFS_RANDOM_H__ + +/* + * procfs interface + */ +extern void xfs_init_procfs(void); +extern void xfs_cleanup_procfs(void); + +#endif /* __XFS_RANDOM_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_super.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_super.c --- linux-2.4.7/linux/fs/xfs/linux/xfs_super.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_super.c Fri Jun 29 17:29:47 2001 @@ -0,0 +1,884 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* xfs_vfs[ops].c */ +extern void vfsinit(void); +extern int xfs_init(int fstype); +extern void xfs_cleanup(void); + +#ifdef CONFIG_XFS_DMAPI +extern void dmapi_init(void); +extern void dmapi_uninit(void); +#endif + +static struct super_operations linvfs_sops; + + +#define MS_DATA 0x04 + +#define MNTOPT_LOGBUFS "logbufs" /* number of XFS log buffers */ +#define MNTOPT_LOGBSIZE "logbsize" /* size of XFS log buffers */ +#define MNTOPT_LOGDEV "logdev" /* log device */ +#define MNTOPT_RTDEV "rtdev" /* realtime I/O device */ +#define MNTOPT_DMAPI "dmapi" /* DMI enabled (DMAPI / XDSM) */ +#define MNTOPT_XDSM "xdsm" /* DMI enabled (DMAPI / XDSM) */ +#define MNTOPT_BIOSIZE "biosize" /* log2 of preferred buffered io size */ +#define MNTOPT_WSYNC "wsync" /* safe-mode nfs compatible mount */ +#define MNTOPT_NOATIME "noatime" /* don't modify access times on reads */ +#define MNTOPT_INO64 "ino64" /* force inodes into 64-bit range */ +#define MNTOPT_NOALIGN "noalign" /* turn off stripe alignment */ +#define MNTOPT_SUNIT "sunit" /* data volume stripe unit */ +#define MNTOPT_SWIDTH "swidth" /* data volume stripe width */ +#define MNTOPT_NORECOVERY "norecovery" /* don't run XFS recovery */ +#define MNTOPT_OSYNCISDSYNC "osyncisdsync" /* o_sync == o_dsync on this fs */ +#define MNTOPT_QUOTA "quota" /* disk quotas */ +#define MNTOPT_MRQUOTA "mrquota" /* don't turnoff if SB has quotas on */ +#define MNTOPT_NOSUID "nosuid" /* disallow setuid program execution */ +#define MNTOPT_NOQUOTA "noquota" /* no quotas */ +#define MNTOPT_UQUOTA "usrquota" /* user quota enabled */ +#define MNTOPT_GQUOTA "grpquota" /* group quota enabled */ +#define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */ +#define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */ +#define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */ +#define MNTOPT_RO "ro" /* read only */ +#define MNTOPT_RW "rw" /* read/write */ +#define MNTOPT_NOUUID "nouuid" /* Ignore FS uuid */ + +STATIC int +mountargs_xfs( + char *options, + int flags, + struct xfs_args *args) +{ + char *this_char, *value, *eov; + int logbufs = -1; + int logbufsize = -1; + int dsunit, dswidth, vol_dsunit, vol_dswidth; + int iosize; + int error; + + iosize = dsunit = dswidth = vol_dsunit = vol_dswidth = 0; + memset(args, 0, sizeof(*args)); + args->version = 3; + args->flags = flags & MS_RDONLY; + if (flags & MS_NOATIME) + args->flags |= XFSMNT_NOATIME; + for (this_char = strtok (options, ","); + this_char != NULL; + this_char = strtok (NULL, ",")) { + + if ((value = strchr (this_char, '=')) != NULL) + *value++ = 0; + + if (!strcmp(this_char, MNTOPT_LOGBUFS)) { + if (!strcmp(value, "none")) { + logbufs = 0; + printk( + "mount: this FS is trash after writing to it\n"); + } else { + logbufs = simple_strtoul(value, &eov, 10); + if (logbufs < 2 || logbufs > 8) { + printk( + "mount: Illegal logbufs amount: %d\n", + logbufs); + return 1; + } + } + } else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) { + logbufsize = simple_strtoul(value, &eov, 10); + if (logbufsize != 16*1024 && logbufsize != 32*1024) { + printk( + "mount: Illegal logbufsize: %d (not 16k or 32k)\n", + logbufsize); + return 1; + } + } else if (!strcmp(this_char, MNTOPT_LOGDEV)) { + struct nameidata nd; + + if (!value) + continue; + + error = 0; + lock_kernel(); + if (path_init(value, LOOKUP_FOLLOW, &nd)) + error = path_walk(value, &nd); + + if (error) { + unlock_kernel(); + printk( + "mount: Invalid log device \"%s\", error = %d\n", + value, error); + return 1; + } + args->logdev = nd.dentry->d_inode->i_rdev; + path_release(&nd); + unlock_kernel(); + } else if (!strcmp(this_char, MNTOPT_DMAPI)) { + args->flags |= XFSMNT_DMAPI; + } else if (!strcmp(this_char, MNTOPT_XDSM)) { + args->flags |= XFSMNT_DMAPI; + } else if (!strcmp(this_char, MNTOPT_RTDEV)) { + struct nameidata nd; + + if (!value) + continue; + + error = 0; + lock_kernel(); + if (path_init(value, LOOKUP_FOLLOW, &nd)) + error = path_walk(value, &nd); + + if (error) { + unlock_kernel(); + printk( + "mount: Invalid realtime device \"%s\", error = %d\n", + value, error); + return 1; + } + args->rtdev = nd.dentry->d_inode->i_rdev; + path_release(&nd); + unlock_kernel(); + } else if (!strcmp(this_char, MNTOPT_BIOSIZE)) { + iosize = simple_strtoul(value, &eov, 10); + if (iosize > 255 || iosize <= 0) { + printk( + "mount: illegal biosize %d, value out of bounds\n", + iosize); + return 1; + } + args->flags |= XFSMNT_IOSIZE; + args->iosizelog = (uint8_t) iosize; + } else if (!strcmp(this_char, MNTOPT_WSYNC)) { + args->flags |= XFSMNT_WSYNC; + } else if (!strcmp(this_char, MNTOPT_NOATIME)) { + args->flags |= XFSMNT_NOATIME; + } else if (!strcmp(this_char, MNTOPT_OSYNCISDSYNC)) { + args->flags |= XFSMNT_OSYNCISDSYNC; + } else if (!strcmp(this_char, MNTOPT_NORECOVERY)) { + args->flags |= XFSMNT_NORECOVERY; + } else if (!strcmp(this_char, MNTOPT_INO64)) { +#ifdef XFS_BIG_FILESYSTEMS + args->flags |= XFSMNT_INO64; +#else + printk("mount: ino64 option not allowed on this system\n"); + return 1; +#endif + } else if (!strcmp(this_char, MNTOPT_UQUOTA)) { + args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_QUOTA)) { + args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_UQUOTANOENF)) { + args->flags |= XFSMNT_UQUOTA; + args->flags &= ~XFSMNT_UQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_QUOTANOENF)) { + args->flags |= XFSMNT_UQUOTA; + args->flags &= ~XFSMNT_UQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_MRQUOTA)) { + args->flags |= XFSMNT_QUOTAMAYBE; + } else if (!strcmp(this_char, MNTOPT_GQUOTA)) { + args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) { + args->flags |= XFSMNT_GQUOTA; + args->flags &= ~XFSMNT_GQUOTAENF; + } else if (!strcmp(this_char, MNTOPT_NOALIGN)) { + args->flags |= XFSMNT_NOALIGN; + } else if (!strcmp(this_char, MNTOPT_SUNIT)) { + dsunit = simple_strtoul(value, &eov, 10); + } else if (!strcmp(this_char, MNTOPT_SWIDTH)) { + dswidth = simple_strtoul(value, &eov, 10); + } else if (!strcmp(this_char, MNTOPT_RO)) { + args->flags |= MS_RDONLY; + } else if (!strcmp(this_char, MNTOPT_NOSUID)) { + args->flags |= MS_NOSUID; + } else if (!strcmp(this_char, MNTOPT_NOUUID)) { + args->flags |= XFSMNT_NOUUID; + } else { + printk( + "mount: unknown mount option \"%s\".\n", this_char); + return 1; + } + + } + + if (args->flags & XFSMNT_NORECOVERY) { + if ((args->flags & MS_RDONLY) == 0) { + printk( + "mount: no-recovery XFS mounts must be read-only.\n"); + return 1; + } + } + + if ((args->flags & XFSMNT_NOALIGN) && (dsunit || dswidth)) { + printk( +"mount: sunit and swidth options are incompatible with the noalign option\n"); + return 1; + } + + if ((dsunit && !dswidth) || (!dsunit && dswidth)) { + printk( +"mount: both sunit and swidth options have to be specified\n"); + return 1; + } + + if (dsunit && (dswidth % dsunit != 0)) { + printk( +"mount: stripe width (%d) has to be a multiple of the stripe unit (%d)\n", + dswidth, dsunit); + return 1; + } + + if ((args->flags & XFSMNT_NOALIGN) != XFSMNT_NOALIGN) { + + if (dsunit) { + args->sunit = dsunit; + args->flags |= XFSMNT_RETERR; + } else + args->sunit = vol_dsunit; + dswidth ? (args->swidth = dswidth) : + (args->swidth = vol_dswidth); + } else + args->sunit = args->swidth = 0; + + args->logbufs = logbufs; + args->logbufsize = logbufsize; + return 0; +} + +int +spectodevs( + struct super_block *sb, + struct xfs_args *args, + dev_t *ddevp, + dev_t *logdevp, + dev_t *rtdevp) +{ + *ddevp = sb->s_dev; + if (args->logdev) + *logdevp = args->logdev; + else + *logdevp = *ddevp; + if (args->rtdev) + *rtdevp = args->rtdev; + else + *rtdevp = 0; + return 0; +} + + +void +linvfs_release_target(struct pb_target *target) +{ + if (target) { + pagebuf_delwri_flush(target, PBDF_WAIT, NULL); + pagebuf_lock_disable(target); + } +} + + +struct super_block * +linvfs_read_super( + struct super_block *sb, + void *data, + int silent) +{ + vfsops_t *vfsops; + extern vfsops_t xfs_vfsops; + vfs_t *vfsp; + vnode_t *cvp, *rootvp; + + struct mounta ap; + struct mounta *uap = ≈ + char spec[256]; + struct xfs_args arg, *args = &arg; + int error; + statvfs_t statvfs; + struct inode *ip, *cip; + + /* Setup the uap structure */ + + memset(uap, 0, sizeof(struct mounta)); + + sprintf(spec, bdevname(sb->s_dev)); + uap->spec = spec; + + uap->flags = MS_DATA; + + if (mountargs_xfs((char *)data, sb->s_flags, args) != 0) { + return NULL; + } + + args->fsname = uap->spec; + + uap->dataptr = (char *)args; + uap->datalen = sizeof(*args); + + /* Kludge in XFS until we have other VFS/VNODE FSs */ + + vfsops = &xfs_vfsops; + + /* Set up the vfs_t structure */ + + vfsp = vfs_allocate(); + + if (sb->s_flags & MS_RDONLY) + vfsp->vfs_flag |= VFS_RDONLY; + + /* Setup up the cvp structure */ + + cip = (struct inode *)kmem_alloc(sizeof(struct inode),0); + bzero(cip, sizeof(*cip)); + + atomic_set(&cip->i_count, 1); + + cvp = LINVFS_GET_VN_ADDRESS(cip); + + cvp->v_type = VDIR; + cvp->v_number = 1; /* Place holder */ + cvp->v_inode = cip; + +#ifdef CONFIG_XFS_VNODE_TRACING + cvp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP); +#endif /* CONFIG_XFS_VNODE_TRACING */ + + vn_trace_entry(cvp, "linvfs_read_super", (inst_t *)__return_address); + + cvp->v_flag |= VMOUNTING; + + vn_bhv_head_init(VN_BHV_HEAD(cvp), "vnode"); /* for DMAPI */ + + LINVFS_SET_CVP(sb, cvp); + vfsp->vfs_super = sb; + +#ifdef CONFIG_FS_POSIX_ACL + sb->s_posix_acl_flag = 1; +#endif + + sb->s_blocksize = 512; + sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1; + set_blocksize(sb->s_dev, 512); + + sb->s_op = &linvfs_sops; + sb->dq_op = NULL; + + LINVFS_SET_VFS(sb, vfsp); + + VFSOPS_MOUNT(vfsops, vfsp, cvp, uap, NULL, sys_cred, error); + if (error) + goto fail_vfsop; + + VFS_STATVFS(vfsp, &statvfs, NULL, error); + if (error) + goto fail_unmount; + + sb->s_magic = XFS_SB_MAGIC; + sb->s_dirt = 1; /* Make sure we get regular syncs */ + + /* For kernels which have the s_maxbytes field - set it */ +#ifdef MAX_NON_LFS + sb->s_maxbytes = XFS_MAX_FILE_OFFSET; +#endif + + VFS_ROOT(vfsp, &rootvp, error); + if (error) + goto fail_unmount; + + ip = LINVFS_GET_IP(rootvp); + + linvfs_set_inode_ops(ip); + linvfs_revalidate_core(ip, ATTR_COMM); + + sb->s_root = d_alloc_root(ip); + + if (!sb->s_root) + goto fail_vnrele; + + if (is_bad_inode((struct inode *) sb->s_root)) + goto fail_vnrele; + + /* Don't set the VFS_DMI flag until here because we don't want + * to send events while replaying the log. + */ + if (args->flags & XFSMNT_DMAPI) + vfsp->vfs_flag |= VFS_DMI; + + vn_trace_exit(rootvp, "linvfs_read_super", (inst_t *)__return_address); + + return(sb); + +fail_vnrele: + VN_RELE(rootvp); + +fail_unmount: + VFS_UNMOUNT(vfsp, 0, sys_cred, error); + /* We need to do something here to shut down the + VNODE/VFS layer. */ + +fail_vfsop: + vfs_deallocate(vfsp); + +#ifdef CONFIG_XFS_VNODE_TRACING + ktrace_free(cvp->v_trace); + + cvp->v_trace = NULL; +#endif /* CONFIG_XFS_VNODE_TRACING */ + + kfree(cvp->v_inode); + return(NULL); +} + +void +linvfs_set_inode_ops( + struct inode *inode) +{ + vnode_t *vp; + + vp = LINVFS_GET_VN_ADDRESS(inode); + + inode->i_mode = VTTOIF(vp->v_type); + + if (vp->v_type == VNON) { + make_bad_inode(inode); + } else if (S_ISREG(inode->i_mode)) { + inode->i_op = &linvfs_file_inode_operations; + inode->i_fop = &linvfs_file_operations; + inode->i_mapping->a_ops = &linvfs_aops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &linvfs_dir_inode_operations; + inode->i_fop = &linvfs_dir_operations; + } else if (S_ISLNK(inode->i_mode)) { + inode->i_op = &linvfs_symlink_inode_operations; + if (inode->i_blocks) + inode->i_mapping->a_ops = &linvfs_aops; + } else { + inode->i_op = &linvfs_file_inode_operations; + init_special_inode(inode, inode->i_mode, inode->i_rdev); + } +} + +void +linvfs_read_inode( + struct inode *inode) +{ + vfs_t *vfsp = LINVFS_GET_VFS(inode->i_sb); + + if (vfsp) { + vn_initialize(vfsp, inode, 1); + } else { + make_bad_inode(inode); + return; + } + + inode->i_version = ++event; +} + + + +/* + * The write method is only used to + * trace interesting events in the life of a vnode. + */ + +#ifdef CONFIG_XFS_VNODE_TRACING + +void +linvfs_write_inode( + struct inode *inode, + int sync) +{ + vnode_t *vp = LINVFS_GET_VP(inode); + + if (vp) { + vn_trace_entry(vp, "linvfs_write_inode", + (inst_t *)__return_address); + } +} +#endif /* CONFIG_XFS_VNODE_TRACING */ + + +void +linvfs_delete_inode( + struct inode *inode) +{ + vnode_t *vp = LINVFS_GET_VP(inode); + + if (vp) { + + vn_trace_entry(vp, "linvfs_delete_inode", + (inst_t *)__return_address); + /* + * Remove the vnode, the nlink count + * is zero & the unlink will complete. + */ + vp->v_flag |= VPURGE; + vn_remove(vp); + } + + clear_inode(inode); +} + + +void +linvfs_clear_inode( + struct inode *inode) +{ + vnode_t *vp = LINVFS_GET_VP(inode); + + if (vp) { + + vn_trace_entry(vp, "linvfs_clear_inode", + (inst_t *)__return_address); + /* + * Do all our cleanup, and remove + * this vnode. + */ + vp->v_flag |= VPURGE; + vn_remove(vp); + } +} + +void +linvfs_put_inode( + struct inode *inode) +{ + vnode_t *vp = LINVFS_GET_VP(inode); + + if (vp) vn_put(vp); +} + +void +linvfs_put_super( + struct super_block *sb) +{ + int error; + int sector_size = 512; + kdev_t dev = sb->s_dev; + vfs_t *vfsp = LINVFS_GET_VFS(sb); + vnode_t *cvp; + + VFS_DOUNMOUNT(vfsp, 0, NULL, sys_cred, error); + + if (error) { + printk("XFS unmount got error %d\n", error); + printk("linvfs_put_super: vfsp/0x%p left dangling!\n", vfsp); + return; + } + + vfs_deallocate(vfsp); + + cvp = LINVFS_GET_CVP(sb); + +#ifdef CONFIG_XFS_VNODE_TRACING + ktrace_free(cvp->v_trace); + + cvp->v_trace = NULL; +#endif /* CONFIG_XFS_VNODE_TRACING */ + + kfree(cvp->v_inode); + + /* Do something to get rid of the VNODE/VFS layer here */ + + /* Reset device block size */ + if (hardsect_size[MAJOR(dev)]) + sector_size = hardsect_size[MAJOR(dev)][MINOR(dev)]; + + set_blocksize(dev, sector_size); +} + + +void +linvfs_write_super( + struct super_block *sb) +{ + vfs_t *vfsp = LINVFS_GET_VFS(sb); + int error; + + if (sb->s_flags & MS_RDONLY) { + return; + } + + VFS_SYNC(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_NOWAIT|SYNC_ATTR, + sys_cred, error); + + sb->s_dirt = 1; /* Keep the syncs coming. */ +} + + +int +linvfs_statfs( + struct super_block *sb, + struct statfs *buf) +{ + vfs_t *vfsp = LINVFS_GET_VFS(sb); + statvfs_t stat; + + int error; + + VFS_STATVFS(vfsp, &stat, NULL, error); + + if (error){ + return(-error); + } + + + buf->f_type = XFS_SB_MAGIC; + buf->f_bsize = stat.f_bsize; + buf->f_blocks = stat.f_blocks; + buf->f_bfree = stat.f_bfree; + buf->f_bavail = stat.f_bavail; + buf->f_files = stat.f_files; + buf->f_ffree = stat.f_ffree; + buf->f_fsid.val[0] = stat.f_fsid; + buf->f_fsid.val[1] = 0; + buf->f_namelen = stat.f_namemax; + + return 0; +} + + +int +linvfs_remount( + struct super_block *sb, + int *flags, + char *options) +{ + struct xfs_args args; + vfs_t *vfsp; + vnode_t *cvp; + + vfsp = LINVFS_GET_VFS(sb); + cvp = LINVFS_GET_CVP(sb); + +#ifdef CONFIG_FS_POSIX_ACL + sb->s_posix_acl_flag = 1; +#endif + + if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) + return 0; + + if (mountargs_xfs(options, *flags, &args) != 0) + return -ENOSPC; + + if (*flags & MS_RDONLY || args.flags & MS_RDONLY) { + int error; + int save = sb->s_flags; + xfs_mount_t *mp = XFS_BHVTOM(vfsp->vfs_fbhv); + + sb->s_flags |= MS_RDONLY; + + XFS_bflush(mp->m_ddev_targ); + VFS_SYNC(vfsp, SYNC_ATTR|SYNC_WAIT|SYNC_CLOSE, + sys_cred, error); + if (error) { + sb->s_flags=save; + return -error; + } + + XFS_log_write_unmount_ro(vfsp->vfs_fbhv); + vfsp->vfs_flag |= VFS_RDONLY; + } else { + vfsp->vfs_flag &= ~VFS_RDONLY; + sb->s_flags &= ~MS_RDONLY; + } + + return 0; +} + +void +linvfs_freeze_fs( + struct super_block *sb) +{ + vfs_t *vfsp; + vnode_t *vp; + int error; + + vfsp = LINVFS_GET_VFS(sb); + if (sb->s_flags & MS_RDONLY) { + return; + } + + VFS_ROOT(vfsp, &vp, error); + VOP_IOCTL(vp, LINVFS_GET_IP(vp), NULL, XFS_IOC_FREEZE, 0, error); + VN_RELE(vp); +} + +void +linvfs_unfreeze_fs( + struct super_block *sb) +{ + vfs_t *vfsp; + vnode_t *vp; + int error; + + vfsp = LINVFS_GET_VFS(sb); + VFS_ROOT(vfsp, &vp, error); + VOP_IOCTL(vp, LINVFS_GET_IP(vp), NULL, XFS_IOC_THAW, 0, error); +} + +int +linvfs_dmapi_mount( + struct super_block *sb, + char *dir_name) +{ + vfsops_t *vfsops; + extern vfsops_t xfs_vfsops; + char fsname[256]; + vnode_t *cvp; /* covered vnode */ + vfs_t *vfsp; /* mounted vfs */ + int error; + + vfsp = LINVFS_GET_VFS(sb); + if ( ! (vfsp->vfs_flag & VFS_DMI) ) + return 0; + cvp = LINVFS_GET_CVP(sb); + sprintf(fsname, bdevname(sb->s_dev)); + + /* Kludge in XFS until we have other VFS/VNODE FSs */ + vfsops = &xfs_vfsops; + + VFSOPS_DMAPI_MOUNT(vfsops, vfsp, cvp, dir_name, fsname, error); + if (error) { + vfsp->vfs_flag &= ~VFS_DMI; + return -error; + } + return 0; +} + + +int +linvfs_quotactl( + struct super_block *sb, + int cmd, + int type, + int id, + caddr_t addr) +{ + xfs_mount_t *mp; + vfs_t *vfsp; + int error; + + if (!IS_XQM_CMD(cmd)) + return -EINVAL; + + if (type == USRQUOTA) + type = XFS_DQ_USER; + else if (type == GRPQUOTA) + type = XFS_DQ_GROUP; + else + return -EINVAL; + + vfsp = LINVFS_GET_VFS(sb); + mp = XFS_BHVTOM(vfsp->vfs_fbhv); + ASSERT(mp); + + error = xfs_quotactl(mp, vfsp, cmd, id, type, addr); + + if (error) + return -error; + + return 0; +} + + +static struct super_operations linvfs_sops = { + read_inode: linvfs_read_inode, +#ifdef CONFIG_XFS_VNODE_TRACING + write_inode: linvfs_write_inode, +#endif +#ifdef CONFIG_XFS_DMAPI + dmapi_mount_event: linvfs_dmapi_mount, +#endif +#ifdef CONFIG_XFS_QUOTA + quotactl: linvfs_quotactl, +#endif + put_inode: linvfs_put_inode, + delete_inode: linvfs_delete_inode, + clear_inode: linvfs_clear_inode, + put_super: linvfs_put_super, + write_super: linvfs_write_super, + write_super_lockfs: linvfs_freeze_fs, + unlockfs: linvfs_unfreeze_fs, + statfs: linvfs_statfs, + remount_fs: linvfs_remount +}; + +DECLARE_FSTYPE_DEV(xfs_fs_type, XFS_NAME, linvfs_read_super); + +static int __init init_xfs_fs(void) +{ + struct sysinfo si; + + si_meminfo(&si); + + physmem = si.totalram; + + cred_init(); + + vfsinit(); + xfs_init(0); + +#ifdef CONFIG_XFS_GRIO + xfs_grio_init(); +#endif +#ifdef CONFIG_XFS_DMAPI + dmapi_init(); +#endif + return register_filesystem(&xfs_fs_type); +} + + + +static void __exit exit_xfs_fs(void) +{ +#ifdef CONFIG_XFS_DMAPI + dmapi_uninit(); +#endif +#ifdef CONFIG_XFS_GRIO + xfs_grio_uninit(); +#endif + xfs_cleanup(); + unregister_filesystem(&xfs_fs_type); +} + +EXPORT_NO_SYMBOLS; + +module_init(init_xfs_fs); +module_exit(exit_xfs_fs); + diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_super.h linux-2.4-xfs/linux/fs/xfs/linux/xfs_super.h --- linux-2.4.7/linux/fs/xfs/linux/xfs_super.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_super.h Thu May 10 09:44:32 2001 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPER_H__ +#define __XFS_SUPER_H__ + +struct xfs_args; + +void +linvfs_release_target( + struct pb_target *target); + +int +fs_dounmount( + bhv_desc_t *bdp, + int flags, + vnode_t *rootvp, + cred_t *cr); + +int +spectodevs( + struct super_block *sb, + struct xfs_args *args, + dev_t *ddevp, + dev_t *logdevp, + dev_t *rtdevp); + +#endif /* __XFS_SUPER_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_vfs.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_vfs.c --- linux-2.4.7/linux/fs/xfs/linux/xfs_vfs.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_vfs.c Tue Apr 24 13:43:41 2001 @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include + + +/* + * VFS global data. + */ +STATIC spinlock_t vfslock; /* spinlock protecting rootvfs and vfs_flag */ + +#define vfsp_wait(V,P,S) mp_sv_wait(&(V)->vfs_wait,P,&vfslock,s) +#define vfsp_waitsig(V,P,S) mp_sv_wait_sig(&(V)->vfs_wait,P,&vfslock,s) + +/* + * Allocate and initialize a new vfs + */ +vfs_t * +vfs_allocate(void) +{ + vfs_t *vfsp; + + vfsp = kmalloc(sizeof(vfs_t), GFP_KERNEL); + memset(vfsp, 0, sizeof(vfs_t)); + ASSERT(vfsp); + VFS_INIT(vfsp); + return (vfsp); +} + +void +vfs_deallocate(vfs_t *vfsp) +{ + VFS_FREE(vfsp); + kfree(vfsp); +} + +/* + * Implement a simplified multi-access, single-update protocol for vfs. + * + * Only one update-lock (mount/unmount) can be held at a time; if another + * process holds the vfs stucture with update capabilities, or is waiting + * to acquire update rights, other update calls fail. + * + * Multiple accessors are allowed: vfs_busycnt tracks the number of + * concurrent accesses. Update permission sleeps until the last access + * has finished, but leaves the VFS_MWANT flag to hold (if called via + * vfs_busy) or reject (called via vfs_busydev or vfs_lock) subsequent + * accesses/updates. + * Note that traverse understands the vfs locking model and waits for + * any update to complete, and retries the mount-point traversal. + * + * Accessors include: vfs_syncall, traverse, VFS_STATVFS, and quota checking. + */ +STATIC int +vfs_lock_flags(struct vfs *vfsp, int flags) +{ + register int error; + long s; + + spin_lock_irqsave(&vfslock, s); + if (vfsp->vfs_flag & (VFS_MLOCK|VFS_MWANT)) { + spin_unlock_irqrestore(&vfslock, s); + return EBUSY; + } + + while (vfsp->vfs_busycnt) { + ASSERT(vfsp->vfs_busycnt > 0); + ASSERT(!(vfsp->vfs_flag & (VFS_MLOCK|VFS_OFFLINE))); + vfsp->vfs_flag |= VFS_MWAIT|VFS_MWANT; + vfsp_waitsig(vfsp, PVFS, s); /* REMOVED setting error. */ + error = 0; /* JIMJIM always no error */ + spin_lock_irqsave(&vfslock, s); + if (error) { + ASSERT(vfsp->vfs_flag & VFS_MWANT); + vfsp->vfs_flag &= ~VFS_MWANT; + if (vfsp->vfs_flag & VFS_MWAIT) { + vfsp->vfs_flag &= ~VFS_MWAIT; + sv_broadcast(&vfsp->vfs_wait); + } + spin_unlock_irqrestore(&vfslock, s); + return EINTR; + } + ASSERT(vfsp->vfs_flag & VFS_MWANT); + vfsp->vfs_flag &= ~VFS_MWANT; + } + + ASSERT((vfsp->vfs_flag & (VFS_MLOCK|VFS_OFFLINE)) != VFS_OFFLINE); + if (vfsp->vfs_flag & VFS_MLOCK) { + error = EBUSY; + } else { + vfsp->vfs_flag |= VFS_MLOCK|flags; + error = 0; + } + spin_unlock_irqrestore(&vfslock, s); + return error; +} + +/* + * Lock a filesystem to prevent access to it while mounting. + * Returns error if already locked. + */ +int +vfs_lock(struct vfs *vfsp) +{ + return (vfs_lock_flags(vfsp, 0)); +} + +/* + * Lock a filesystem and mark it offline, + * to prevent access to it while unmounting. + * Returns error if already locked. + */ +int +vfs_lock_offline(struct vfs *vfsp) +{ + return (vfs_lock_flags(vfsp, VFS_OFFLINE)); +} + +/* + * Unlock a locked filesystem. + */ +void +vfs_unlock(register struct vfs *vfsp) +{ + long s; + + spin_lock_irqsave(&vfslock, s); + ASSERT((vfsp->vfs_flag & (VFS_MWANT|VFS_MLOCK)) == VFS_MLOCK); + vfsp->vfs_flag &= ~(VFS_MLOCK|VFS_OFFLINE); + + /* + * Wake accessors (traverse() or vfs_syncall()) + * waiting for the lock to clear. + */ + if (vfsp->vfs_flag & VFS_MWAIT) { + vfsp->vfs_flag &= ~VFS_MWAIT; + sv_broadcast(&vfsp->vfs_wait); + } + spin_unlock_irqrestore(&vfslock, s); +} + +/* + * Get access permission for vfsp. + */ +int +vfs_busy(struct vfs *vfsp) +{ + long s; + + spin_lock_irqsave(&vfslock, s); + ASSERT((vfsp->vfs_flag & (VFS_MLOCK|VFS_OFFLINE)) != VFS_OFFLINE); + while (vfsp->vfs_flag & (VFS_MLOCK|VFS_MWANT)) { + ASSERT(vfsp->vfs_flag & VFS_MWANT || vfsp->vfs_busycnt == 0); + if (vfsp->vfs_flag & VFS_OFFLINE) { + spin_unlock_irqrestore(&vfslock, s); + return EBUSY; + } + vfsp->vfs_flag |= VFS_MWAIT; + vfsp_waitsig(vfsp, PVFS, s); /* JIMJIM this has no sig "nificance". */ + spin_lock_irqsave(&vfslock, s); + } + + ASSERT(vfsp->vfs_busycnt >= 0); + vfsp->vfs_busycnt++; + spin_unlock_irqrestore(&vfslock, s); + + return 0; +} + +/* + * Given a pair, return the vfs-entry for it. + * If the type sent in is VFS_FSTYPE_ANY, then this'll only try to + * match the device number. + * + * This extra parameter was necessary since duplicate vfs entries with + * the same vfs_dev are possible because of lofs. + */ +struct vfs * +vfs_busydev(dev_t dev, int type) +{ + long s; + struct vfs *vfsp; + kdev_t kdev = MKDEV(MAJOR(dev), MINOR(dev)); + struct super_block *sb; + + lock_kernel(); + sb = get_super(kdev); + unlock_kernel(); + + if (!sb) + return NULL; + + vfsp = LINVFS_GET_VFS(sb); +again: + spin_lock_irqsave(&vfslock, s); + if (vfsp->vfs_dev == dev && + (type == VFS_FSTYPE_ANY || type == vfsp->vfs_fstype)) { + + if (vfsp->vfs_flag & VFS_OFFLINE) { + spin_unlock_irqrestore(&vfslock, s); + return NULL; + } + if (vfsp->vfs_flag & (VFS_MLOCK|VFS_MWANT)) { + ASSERT(vfsp->vfs_flag & VFS_MWANT || + vfsp->vfs_busycnt == 0); + vfsp->vfs_flag |= VFS_MWAIT; + vfsp_wait(vfsp, 0, s); /* JIMJIM removed PZERO */ + goto again; + } + + ASSERT(vfsp->vfs_busycnt >= 0); + vfsp->vfs_busycnt++; + } + spin_unlock_irqrestore(&vfslock, s); + return vfsp; +} + +STATIC void +vfs_unbusy_wakeup(register struct vfs *vfsp) +{ + /* + * If there's an updater (mount/unmount) waiting for the vfs lock, + * wake up only it. Updater should be the first on the sema queue. + * + * Otherwise, wake all accessors (traverse() or vfs_syncall()) + * waiting for the lock to clear. + */ + if (vfsp->vfs_flag & VFS_MWANT) { + sv_signal(&vfsp->vfs_wait); + } else if (vfsp->vfs_flag & VFS_MWAIT) { + vfsp->vfs_flag &= ~VFS_MWAIT; + sv_broadcast(&vfsp->vfs_wait); + } +} + +/* + * Same as vfs_devsearch without locking the list. + * Useful for debugging code, but put it here anyway. + */ +STATIC struct vfs * +vfs_devsearch_nolock(dev_t dev, int fstype) +{ + register struct vfs *vfsp; + kdev_t kdev = MKDEV(MAJOR(dev), MINOR(dev)); + struct super_block *sb; + + lock_kernel(); + sb = get_super(kdev); + + if (sb) { + vfsp = LINVFS_GET_VFS(sb); + if ((vfsp->vfs_dev == dev) && + (fstype == VFS_FSTYPE_ANY || fstype == vfsp->vfs_fstype)) { + unlock_kernel(); + return vfsp; + } + } + unlock_kernel(); + return NULL; +} + +void +vfs_unbusy(struct vfs *vfsp) +{ + long s; + + spin_lock_irqsave(&vfslock, s); + ASSERT(!(vfsp->vfs_flag & (VFS_MLOCK|VFS_OFFLINE))); + ASSERT(vfsp->vfs_busycnt > 0); + if (--vfsp->vfs_busycnt == 0) + vfs_unbusy_wakeup(vfsp); + spin_unlock_irqrestore(&vfslock, s); +} + +/* + * Search the vfs list for a specified device. Returns a pointer to it + * or NULL if no suitable entry is found. + * + * Any calls to this routine (as opposed to vfs_busydev) should + * considered extremely suspicious. Once the vfs_spinunlock is done, + * there is likely to be nothing guaranteeing that the vfs pointer + * returned continues to point to a vfs. There are numerous bugs + * which would quickly become intolerable if the frequency of unmount + * was to rise above its typically low level. + */ +struct vfs * +vfs_devsearch(dev_t dev, int fstype) +{ + register struct vfs *vfsp; + long s; + + spin_lock_irqsave(&vfslock, s); + vfsp = vfs_devsearch_nolock(dev, fstype); + spin_unlock_irqrestore(&vfslock, s); + return vfsp; +} + + +void +vfsinit(void) +{ + /* + * Initialize vfs stuff. + */ + spin_lock_init(&vfslock); + + /* + * Initialize vnode stuff. + */ + vn_init(); +} + +/* + * Called by fs dependent VFS_MOUNT code to link the VFS base file system + * dependent behavior with the VFS virtual object. + */ +void +vfs_insertbhv( + vfs_t *vfsp, + bhv_desc_t *bdp, + vfsops_t *vfsops, + void *mount) +{ + /* + * Initialize behavior desc with ops and data and then + * attach it to the vfs. + */ + bhv_desc_init(bdp, mount, vfsp, vfsops); + bhv_insert_initial(&vfsp->vfs_bh, bdp); +} + +void +vfs_setflag(vfs_t *vfsp, unsigned long f) +{ + long s = mp_mutex_spinlock(&vfslock); + vfsp->vfs_flag |= f; + mp_mutex_spinunlock(&vfslock, s); +} diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_vfs.h linux-2.4-xfs/linux/fs/xfs/linux/xfs_vfs.h --- linux-2.4.7/linux/fs/xfs/linux/xfs_vfs.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_vfs.h Tue Apr 24 13:43:41 2001 @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_VFS_H__ +#define __XFS_VFS_H__ + +#include +#ifdef __KERNEL_STRICT_NAMES +typedef __kernel_fsid_t fsid_t; +#endif + +struct statvfs; +struct vnode; +struct cred; +struct super_block; +struct fid; + +enum whymountroot { ROOT_INIT, ROOT_REMOUNT, ROOT_UNMOUNT }; +typedef enum whymountroot whymountroot_t; + +typedef struct vfs { + u_int vfs_flag; /* flags */ + dev_t vfs_dev; /* device of mounted VFS */ + short vfs_busycnt; /* # of accesses in progress */ + sv_t vfs_wait; /* busy mount point sync */ + u_int vfs_bsize; /* native block size */ + int vfs_fstype; /* file system type index */ + fsid_t vfs_fsid; /* file system id */ + fsid_t *vfs_altfsid; /* An ID fixed for life of FS */ + bhv_head_t vfs_bh; /* head of vfs behavior chain */ + struct super_block *vfs_super; /* pointer to super block structure */ +#if CELL_CAPABLE + __uint64_t vfs_opsflags; /* vfsops/vnodeops flags */ + struct vfs *vfs_next; /* next VFS in VFS list */ + struct vfs **vfs_prevp; /* ptr to previous vfs_next */ + struct vnode *vfs_vnodecovered; /* vnode mounted on */ + cell_t vfs_cell; /* device cell for this FS */ + char *vfs_expinfo; /* data exported by home instance + of file system. */ + size_t vfs_eisize; /* amount of data exported by + home instance of file system */ +#endif +} vfs_t; + +#define vfs_fbhv vfs_bh.bh_first /* 1st on vfs behavior chain */ +#define VFS_FOPS(vfsp) \ + ((vfsops_t *)((vfsp)->vfs_fbhv->bd_ops))/* ops for 1st behavior */ + + +#define bhvtovfs(bdp) ((struct vfs *)BHV_VOBJ(bdp)) +#define VFS_BHVHEAD(vfsp) (&(vfsp)->vfs_bh) + +#define VFS_FSTYPE_ANY -1 /* fstype arg to vfs_devsearch* , + vfs_busydev if the filesystem type + is irrelevant for the search */ + +#define VFS_INIT(vfsp) { \ + sv_init(&(vfsp)->vfs_wait, SV_DEFAULT, "vfs_wait"); \ + bhv_head_init(VFS_BHVHEAD(vfsp),"vfs"); \ +} + +#define VFS_FREE(vfsp) { \ + sv_destroy(&(vfsp)->vfs_wait); \ + bhv_head_destroy(VFS_BHVHEAD(vfsp)); \ +} + + +#define VFS_RDONLY 0x0001 /* read-only vfs */ +#define VFS_GRPID 0x0008 /* group-ID assigned from directory */ +#define VFS_REMOUNT 0x0010 /* modify mount options only */ +#define VFS_NOTRUNC 0x0020 /* does not truncate long file names */ +#define VFS_MLOCK 0x0100 /* lock vfs so that subtree is stable */ +#define VFS_MWAIT 0x0200 /* waiting for access lock */ +#define VFS_MWANT 0x0400 /* waiting for update */ + +#define VFS_LOCAL 0x1000 /* local filesystem, for find */ +#define VFS_OFFLINE 0x2000 /* filesystem is being unmounted */ +#define VFS_DMI 0x4000 /* filesystem has the DMI enabled */ + +#define SYNC_NOWAIT 0x0000 /* start delayed writes */ +#define SYNC_ATTR 0x0001 /* sync attributes */ +#define SYNC_CLOSE 0x0002 /* close file system down */ +#define SYNC_DELWRI 0x0004 /* look at delayed writes */ +#define SYNC_WAIT 0x0008 /* wait for i/o to complete */ +#define SYNC_FSDATA 0x0020 /* flush fs data (e.g. superblocks) */ +#define SYNC_BDFLUSH 0x0010 /* BDFLUSH is calling -- don't block */ +#define SYNC_PDFLUSH 0x0040 /* push v_dpages */ + + +struct mounta { + char *spec; + char *dir; + sysarg_t flags; + char *dataptr; + sysarg_t datalen; +}; + +typedef struct vfsops { +#ifdef CELL_CAPABLE + bhv_position_t vf_position; /* position within behavior chain */ +#endif + int (*vfs_mount)(struct vfs *, struct vnode *, + struct mounta *, char *, struct cred *); + /* mount file system */ + int (*vfs_rootinit)(struct vfs *); + /* 1st mount of root fs */ + int (*vfs_dounmount)(bhv_desc_t *, int, struct vnode *, + struct cred *); + /* preparation and unmount */ + int (*vfs_unmount)(bhv_desc_t *, int, struct cred *); + /* unmount file system */ + int (*vfs_root)(bhv_desc_t *, struct vnode **); + /* get root vnode */ + int (*vfs_statvfs)(bhv_desc_t *, struct statvfs *, struct vnode *); + /* get file system statistics */ + int (*vfs_sync)(bhv_desc_t *, int, struct cred *); + /* flush files */ + int (*vfs_vget)(bhv_desc_t *, struct vnode **, struct fid *); + /* get vnode from fid */ + int (*vfs_mountroot)(bhv_desc_t *, enum whymountroot); + /* mount the root filesystem */ + int (*vfs_get_vnode)(bhv_desc_t *, struct vnode **, xfs_ino_t); + /* get vnode using an ino_t */ + int (*vfs_dmapi_mount)(struct vfs *, struct vnode *, + char *, char *); + /* send dmapi mount event */ +#ifdef CELL_CAPABLE + int vfs_ops_magic; /* magic number for intfc extensions */ + __uint64_t vfs_ops_version; /* interface version number */ + __uint64_t vfs_ops_flags; /* interface flags */ +#endif +} vfsops_t; + +#define VFS_DOUNMOUNT(vfsp,f,vp,cr, rv) \ +{ \ + BHV_READ_LOCK(&(vfsp)->vfs_bh); \ + rv = (*(VFS_FOPS(vfsp)->vfs_dounmount))((vfsp)->vfs_fbhv, f, vp, cr); \ + BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \ +} +#define VFS_UNMOUNT(vfsp,f,cr, rv) \ +{ \ + BHV_READ_LOCK(&(vfsp)->vfs_bh); \ + rv = (*(VFS_FOPS(vfsp)->vfs_unmount))((vfsp)->vfs_fbhv, f, cr); \ + BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \ +} +#define VFS_ROOT(vfsp, vpp, rv) \ +{ \ + BHV_READ_LOCK(&(vfsp)->vfs_bh); \ + rv = (*(VFS_FOPS(vfsp)->vfs_root))((vfsp)->vfs_fbhv, vpp); \ + BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \ +} +#define VFS_STATVFS(vfsp, sp, vp, rv) \ +{ \ + BHV_READ_LOCK(&(vfsp)->vfs_bh); \ + rv = (*(VFS_FOPS(vfsp)->vfs_statvfs))((vfsp)->vfs_fbhv, sp, vp); \ + BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \ +} +#define VFS_SYNC(vfsp, flag, cr, rv) \ +{ \ + BHV_READ_LOCK(&(vfsp)->vfs_bh); \ + rv = (*(VFS_FOPS(vfsp)->vfs_sync))((vfsp)->vfs_fbhv, flag, cr); \ + BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \ +} +#define VFS_VGET(vfsp, vpp, fidp, rv) \ +{ \ + BHV_READ_LOCK(&(vfsp)->vfs_bh); \ + rv = (*(VFS_FOPS(vfsp)->vfs_vget))((vfsp)->vfs_fbhv, vpp, fidp); \ + BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \ +} +#define VFS_MOUNTROOT(vfsp, why, rv) \ +{ \ + BHV_READ_LOCK(&(vfsp)->vfs_bh); \ + rv = (*(VFS_FOPS(vfsp)->vfs_mountroot))((vfsp)->vfs_fbhv, why); \ + BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \ +} +#define VFS_GET_VNODE(vfsp, vpp, ino, rv) \ +{ \ + BHV_READ_LOCK(&(vfsp)->vfs_bh); \ + rv = (*(VFS_FOPS(vfsp)->vfs_get_vnode))((vfsp)->vfs_fbhv, vpp, ino); \ + BHV_READ_UNLOCK(&(vfsp)->vfs_bh); \ +} + +#define VFSOPS_DMAPI_MOUNT(vfs_op, vfsp, mvp, dir_name, fsname, rv) \ + rv = (*(vfs_op)->vfs_dmapi_mount)(vfsp, mvp, dir_name, fsname) +#define VFSOPS_MOUNT(vfs_op, vfsp, mvp, uap, attrs, cr, rv) \ + rv = (*(vfs_op)->vfs_mount)(vfsp, mvp, uap, attrs, cr) +#define VFSOPS_ROOTINIT(vfs_op, vfsp, rv) \ + rv = (*(vfs_op)->vfs_rootinit)(vfsp) + +#define VFS_REMOVEBHV(vfsp, bdp)\ +{ \ + bhv_remove(VFS_BHVHEAD(vfsp), bdp); \ +} + +#define PVFS_UNMOUNT(bdp,f,cr, rv) \ +{ \ + rv = (*((vfsops_t *)(bdp)->bd_ops)->vfs_unmount)(bdp, f, cr); \ +} + +#define PVFS_SYNC(bdp, flag, cr, rv) \ +{ \ + rv = (*((vfsops_t *)(bdp)->bd_ops)->vfs_sync)(bdp, flag, cr); \ +} + +extern vfs_t *vfs_allocate(void); /* Allocate a new vfs. */ +extern void vfs_deallocate(vfs_t *);/* Deallocate a vfs. */ +extern void vfs_insertbhv(vfs_t *, bhv_desc_t *, vfsops_t *, void *); + /* link vfs base behavior with vfs */ +extern int vfs_lock_offline(struct vfs *); +extern int vfs_lock(struct vfs *); /* lock and unlock a vfs */ +extern void vfs_unlock(struct vfs *); +extern int vfs_busy(struct vfs *); /* mark busy for serial sync/unmount */ +extern void vfs_unbusy(struct vfs *); +extern vfs_t *vfs_busydev(dev_t, int);/* to keep dev from unmounting */ +extern vfs_t *vfs_devsearch(dev_t, int);/* find vfs given device & opt. type */ +extern void vfs_setflag(struct vfs *, unsigned long); + +#endif /* __XFS_VFS_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_vnode.c linux-2.4-xfs/linux/fs/xfs/linux/xfs_vnode.c --- linux-2.4.7/linux/fs/xfs/linux/xfs_vnode.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_vnode.c Tue Jun 5 16:06:24 2001 @@ -0,0 +1,564 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +/* + * Private vnode spinlock manipulation. + * + * Nested means there is no need to deal with interrupts (disable/enable) + * so we can be quick about it. + */ +#define NESTED_VN_LOCK(vp) spin_lock(&(vp)->v_lock) +#define NESTED_VN_UNLOCK(vp) spin_unlock(&(vp)->v_lock) + +uint64_t vn_generation; /* vnode generation number */ + +spinlock_t vnumber_lock = SPIN_LOCK_UNLOCKED; + +/* + * Dedicated vnode inactive/reclaim sync semaphores. + * Prime number of hash buckets since address is used as the key. + */ +#define NVSYNC 37 +#define vptosync(v) (&vsync[((unsigned long)v) % NVSYNC]) +sv_t vsync[NVSYNC]; + +/* + * Translate stat(2) file types to vnode types and vice versa. + * Aware of numeric order of S_IFMT and vnode type values. + */ +enum vtype iftovt_tab[] = { + VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON, + VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VNON +}; + +u_short vttoif_tab[] = { + 0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFIFO, 0, S_IFSOCK +}; + +void +vn_init(void) +{ + register sv_t *svp; + register int i; + + for (svp = vsync, i = 0; i < NVSYNC; i++, svp++) + init_sv(svp, SV_DEFAULT, "vsy", i); +} + + +/* + * Clean a vnode of filesystem-specific data and prepare it for reuse. + */ +int +vn_reclaim(struct vnode *vp, int flag) +{ + int error, s; + + XFS_STATS_INC(xfsstats.vn_reclaim); + + vn_trace_entry(vp, "vn_reclaim", (inst_t *)__return_address); + + /* + * Only make the VOP_RECLAIM call if there are behaviors + * to call. + */ + if (vp->v_fbhv != NULL) { + VOP_RECLAIM(vp, flag, error); + if (error) + return -error; + } + ASSERT(vp->v_fbhv == NULL); + + s = VN_LOCK(vp); + + vp->v_flag &= (VRECLM|VWAIT|VLOCK); + VN_UNLOCK(vp, s); + + vp->v_type = VNON; + vp->v_fbhv = NULL; + +#ifdef CONFIG_XFS_VNODE_TRACING + ktrace_free(vp->v_trace); + + vp->v_trace = NULL; +#endif /* CONFIG_XFS_VNODE_TRACING */ + + return 0; +} + +STATIC void +vn_wakeup(struct vnode *vp) +{ + int s = VN_LOCK(vp); + if (vp->v_flag & VWAIT) { + sv_broadcast(vptosync(vp)); + } + vp->v_flag &= ~(VRECLM|VWAIT|VMODIFIED); + VN_UNLOCK(vp, s); +} + + +struct vnode * +vn_address(struct inode *inode) +{ + vnode_t *vp; + + + vp = (vnode_t *)(&((inode)->u.xfs_i.vnode)); + + if (vp->v_inode == NULL) + return NULL; + /* + * Catch half-constructed linux-inode/vnode/xfs-inode setups. + */ + if (vp->v_fbhv == NULL) + return NULL; + + return vp; +} + + +struct vnode * +vn_initialize(vfs_t *vfsp, struct inode *inode, int from_readinode) +{ + struct vnode *vp; + int s = 0; + + + XFS_STATS_INC(xfsstats.vn_active); + + vp = LINVFS_GET_VN_ADDRESS(inode); + + vp->v_inode = inode; + + vp->v_flag = VMODIFIED; + + spinlock_init(&vp->v_lock, "v_lock"); + if (from_readinode) + s = VN_LOCK(vp); + + spin_lock(&vnumber_lock); + vn_generation += 1; + vp->v_number = vn_generation; + spin_unlock(&vnumber_lock); + + ASSERT(vp->v_number); + + ASSERT(VN_CACHED(vp) == 0); + + /* Initialize the first behavior and the behavior chain head. */ + vn_bhv_head_init(VN_BHV_HEAD(vp), "vnode"); + +#ifdef CONFIG_XFS_VNODE_TRACING + vp->v_trace = ktrace_alloc(VNODE_TRACE_SIZE, KM_SLEEP); +#endif /* CONFIG_XFS_VNODE_TRACING */ + + /* + * Check to see if we've been called from + * read_inode, and we need to "stitch" it all + * together right now. + */ + if (from_readinode) { + + if (xfs_vn_iget(vfsp, vp, (xfs_ino_t)inode->i_ino)) { + make_bad_inode(inode); + } else { + linvfs_set_inode_ops(inode); + vn_revalidate(vp, ATTR_LAZY|ATTR_COMM); + + } + VN_UNLOCK(vp, s); + } + + vn_trace_exit(vp, "vn_initialize", (inst_t *)__return_address); + + return vp; +} + +/* + * Free an isolated vnode. + * The vnode must not have any other references. + */ +void +vn_free(struct vnode *vp) +{ + struct inode *inode; + + XFS_STATS_INC(xfsstats.vn_free); + + vn_trace_entry(vp, "vn_free", (inst_t *)__return_address); + + ASSERT(vn_count(vp) == 1); + + ASSERT((vp->v_flag & VPURGE) == 0); + vp->v_fbhv = NULL; + inode = LINVFS_GET_IP(vp); + inode->i_sb = NULL; + iput(inode); +} + + +/* + * Get a reference on a vnode. + */ +vnode_t * +vn_get(struct vnode *vp, vmap_t *vmap, uint flags) +{ + struct inode *inode; + + XFS_STATS_INC(xfsstats.vn_get); + inode = icreate(vmap->v_vfsp->vfs_super, vmap->v_ino); + + /* We do not want to create new inodes via vn_get, + * returning NULL here is OK. + */ + if (inode->i_state & I_NEW) { + make_bad_inode(inode); + unlock_new_inode(inode); + iput(inode); + return NULL; + } + + if (inode == NULL) /* Inode not present */ + return NULL; + + vn_trace_exit(vp, "vn_get", (inst_t *)__return_address); + ASSERT((vp->v_flag & VPURGE) == 0); + + return vp; +} + + +/* + * "Temporary" routine to return the linux inode + * hold count, after everybody else can directly + * reference the inode (header magic!), this + * routine is dead meat.. + */ +int +vn_count(struct vnode *vp) +{ + struct inode *inode; + + inode = LINVFS_GET_IP(vp); + + ASSERT(inode); + + return atomic_read(&inode->i_count); +} + +/* + * "revalidate" the linux inode. + */ +int +vn_revalidate(struct vnode *vp, int flags) +{ + int error; + struct inode *inode; + vattr_t va; + + vn_trace_entry(vp, "vn_revalidate", (inst_t *)__return_address); + + va.va_mask = AT_STAT|AT_GENCOUNT; + + ASSERT(vp->v_bh.bh_first != NULL); + + VOP_GETATTR(vp, &va, flags & ATTR_LAZY, NULL, error); + + if (! error) { + inode = LINVFS_GET_IP(vp); + + ASSERT(inode); + + inode->i_mode = VTTOIF(va.va_type) | va.va_mode; + inode->i_nlink = va.va_nlink; + inode->i_uid = va.va_uid; + inode->i_gid = va.va_gid; + inode->i_rdev = va.va_rdev; + inode->i_blksize = va.va_blksize; + inode->i_generation = va.va_gencount; + if ((flags & ATTR_COMM) || + S_ISREG(inode->i_mode) || + S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode)) { + inode->i_size = va.va_size; + inode->i_blocks = va.va_nblocks; + inode->i_atime = va.va_atime.tv_sec; + inode->i_mtime = va.va_mtime.tv_sec; + inode->i_ctime = va.va_ctime.tv_sec; + } + if (flags & ATTR_LAZY) + vp->v_flag &= ~VMODIFIED; + else + VUNMODIFY(vp); + } else { + vn_trace_exit(vp, "vn_revalidate.error", + (inst_t *)__return_address); + } + + return -error; +} + + +/* + * purge a vnode from the cache + * At this point the vnode is guaranteed to have no references (vn_count == 0) + * The caller has to make sure that there are no ways someone could + * get a handle (via vn_get) on the vnode (usually done via a mount/vfs lock). + */ +void +vn_purge(struct vnode *vp, vmap_t *vmap) +{ + vn_trace_entry(vp, "vn_purge", (inst_t *)__return_address); + + ASSERT(vp->v_flag & VPURGE); + +again: + /* + * Check whether vp has already been reclaimed since our caller + * sampled its version while holding a filesystem cache lock that + * its VOP_RECLAIM function acquires. + */ + NESTED_VN_LOCK(vp); + if (vp->v_number != vmap->v_number) { + NESTED_VN_UNLOCK(vp); + return; + } + + /* + * If vp is being reclaimed or inactivated, wait until it is inert, + * then proceed. Can't assume that vnode is actually reclaimed + * just because the reclaimed flag is asserted -- a vn_alloc + * reclaim can fail. + */ + if (vp->v_flag & (VINACT | VRECLM)) { + ASSERT(vn_count(vp) == 0); + vp->v_flag |= VWAIT; + sv_wait(vptosync(vp), PINOD, &vp->v_lock, 0); + goto again; + } + + /* + * Another process could have raced in and gotten this vnode... + */ + if (vn_count(vp) > 0) { + NESTED_VN_UNLOCK(vp); + return; + } + + XFS_STATS_DEC(xfsstats.vn_active); + vp->v_flag |= VRECLM; + NESTED_VN_UNLOCK(vp); + + /* + * Call VOP_RECLAIM and clean vp. The FSYNC_INVAL flag tells + * vp's filesystem to flush and invalidate all cached resources. + * When vn_reclaim returns, vp should have no private data, + * either in a system cache or attached to v_data. + */ + if (vn_reclaim(vp, FSYNC_INVAL) != 0) + panic("vn_purge: cannot reclaim"); + + /* + * Wakeup anyone waiting for vp to be reclaimed. + */ + vn_wakeup(vp); +} + +/* + * Add a reference to a referenced vnode. + */ +struct vnode * +vn_hold(struct vnode *vp) +{ + register int s = VN_LOCK(vp); + struct inode *inode; + + XFS_STATS_INC(xfsstats.vn_hold); + + inode = LINVFS_GET_IP(vp); + + inode = igrab(inode); + + ASSERT(inode); + + VN_UNLOCK(vp, s); + + return vp; +} + +/* + * Release a vnode. + */ +void +vn_rele(struct vnode *vp) +{ + iput(LINVFS_GET_IP(vp)); +} + +/* + * Call VOP_INACTIVE on last reference. + */ +void +vn_put(struct vnode *vp) +{ + int s; + int vcnt; + /* REFERENCED */ + int cache; + + XFS_STATS_INC(xfsstats.vn_rele); + + vn_trace_entry(vp, "vn_rele", (inst_t *)__return_address); + + s = VN_LOCK(vp); + + vcnt = vn_count(vp); + + ASSERT(vcnt > 0); + + /* + * Since we always get called from put_inode we know + * that i_count won't be decremented after we + * return. + */ + if (vcnt == 1) { + /* + * It is absolutely, positively the case that + * the lock manager will not be releasing vnodes + * without first having released all of its locks. + */ + ASSERT(!(vp->v_flag & VLOCKHOLD)); + + /* + * As soon as we turn this on, noone can find us in vn_get + * until we turn off VINACT or VRECLM + */ + vp->v_flag |= VINACT; + VN_UNLOCK(vp, s); + + /* + * Do not make the VOP_INACTIVE call if there + * are no behaviors attached to the vnode to call. + */ + if (vp->v_fbhv != NULL) { + VOP_INACTIVE(vp, get_current_cred(), cache); + } + + s = VN_LOCK(vp); + + vp->v_flag &= ~(VINACT|VWAIT|VRECLM|VGONE|VMODIFIED); + + } + + VN_UNLOCK(vp, s); + + vn_trace_exit(vp, "vn_rele", (inst_t *)__return_address); +} + + +/* + * Finish the removal of a vnode. + */ +void +vn_remove(struct vnode *vp) +{ + /* REFERENCED */ + vmap_t vmap; + + XFS_STATS_INC(xfsstats.vn_remove); + + vn_trace_exit(vp, "vn_remove", (inst_t *)__return_address); + + /* + * After the following purge the vnode + * will no longer exist. + */ + VMAP(vp, XFS_BHVTOI(vp->v_fbhv), vmap); + + vn_purge(vp, &vmap); + + vp->v_inode = NULL; /* No more references to inode */ +} + + +#ifdef CONFIG_XFS_VNODE_TRACING + +#define KTRACE_ENTER(vp, vk, s, line, ra) \ + ktrace_enter( (vp)->v_trace, \ +/* 0 */ (void *)(__psint_t)(vk), \ +/* 1 */ (void *)(s), \ +/* 2 */ (void *)(__psint_t) line, \ +/* 3 */ (void *)((vp)->v_inode ? vn_count((vp)): -9), \ +/* 4 */ (void *)(ra), \ +/* 5 */ (void *)(__psunsigned_t)(vp)->v_flag, \ +/* 6 */ (void *)(__psint_t)smp_processor_id(), \ +/* 7 */ (void *)(__psint_t)(current->pid), \ +/* 8 */ (void *)__return_address, \ +/* 9 */ 0, 0, 0, 0, 0, 0, 0) + +/* + * Vnode tracing code. + */ +void +vn_trace_entry(vnode_t *vp, char *func, inst_t *ra) +{ + KTRACE_ENTER(vp, VNODE_KTRACE_ENTRY, func, 0, ra); +} + +void +vn_trace_exit(vnode_t *vp, char *func, inst_t *ra) +{ + KTRACE_ENTER(vp, VNODE_KTRACE_EXIT, func, 0, ra); +} + +void +vn_trace_hold(vnode_t *vp, char *file, int line, inst_t *ra) +{ + KTRACE_ENTER(vp, VNODE_KTRACE_HOLD, file, line, ra); +} + +void +vn_trace_ref(vnode_t *vp, char *file, int line, inst_t *ra) +{ + KTRACE_ENTER(vp, VNODE_KTRACE_REF, file, line, ra); +} + +void +vn_trace_rele(vnode_t *vp, char *file, int line, inst_t *ra) +{ + KTRACE_ENTER(vp, VNODE_KTRACE_RELE, file, line, ra); +} +#endif /* CONFIG_XFS_VNODE_TRACING */ diff -rNu linux-2.4.7/linux/fs/xfs/linux/xfs_vnode.h linux-2.4-xfs/linux/fs/xfs/linux/xfs_vnode.h --- linux-2.4.7/linux/fs/xfs/linux/xfs_vnode.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/linux/xfs_vnode.h Fri May 25 15:33:07 2001 @@ -0,0 +1,910 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_VNODE_H__ +#define __XFS_VNODE_H__ + +#include + +#define ISVDEV(t) \ + ((t) == VCHR || (t) == VBLK || (t) == VFIFO || (t) == VSOCK) + +/* + * Conversion between vnode types/modes and encoded type/mode as + * seen by stat(2) and mknod(2). + */ +extern enum vtype iftovt_tab[]; +extern ushort vttoif_tab[]; +#define IFTOVT(M) (iftovt_tab[((M) & S_IFMT) >> 12]) +#define VTTOIF(T) (vttoif_tab[(int)(T)]) +#define MAKEIMODE(T, M) (VTTOIF(T) | ((M) & ~S_IFMT)) + +/* + * One file structure is allocated for each call to open/creat/pipe. + * Mainly used to hold the read/write pointer associated with each + * open file. + * vf_lock protects: + * vf_flag + */ +typedef struct vfile { + lock_t vf_lock; /* spinlock for vf_flag */ + int vf_flag; + void *__vf_data__; /* DON'T ACCESS DIRECTLY */ +} vfile_t; + +#define VF_TO_VNODE(vfp) \ + (ASSERT(!((vfp)->vf_flag & FSOCKET)), (vnode_t *)(vfp)->__vf_data__) +#define VF_IS_VNODE(vfp) (!((vfp)->vf_flag & FSOCKET)) + +/* + * Vnode flags. + * + * The vnode flags fall into two categories: + * 1) Local only - + * Flags that are relevant only to a particular cell + * 2) Single system image - + * Flags that must be maintained coherent across all cells + */ + /* Local only flags */ +#define VINACT 0x2 /* vnode is being inactivated */ +#define VRECLM 0x4 /* vnode is being reclaimed */ +#define VLOCK 0x0 /* no bit on Linux */ +#define VWAIT 0x20 /* waiting for VINACT + or VRECLM to finish */ +#define VGONE 0x80 /* vnode isn't really here */ +#define VREMAPPING 0x100 /* file data flush/inval in progress */ +#define VMOUNTING 0x200 /* mount in progress on vnode */ +#define VLOCKHOLD 0x400 /* VN_HOLD for remote locks */ +#define VINACTIVE_TEARDOWN 0x2000 /* vnode torn down at inactive time */ +#define VSEMAPHORE 0x4000 /* vnode ::= a Posix named semaphore */ +#define VUSYNC 0x8000 /* vnode aspace ::= usync objects */ + +#define VMODIFIED 0x10000 /* xfs inode state possibly different + * from linux inode state. + */ + +/* Single system image flags */ +#define VROOT 0x100000 /* root of its file system */ +#define VNOSWAP 0x200000 /* cannot be used as virt swap device */ +#define VISSWAP 0x400000 /* vnode is part of virt swap device */ +#define VREPLICABLE 0x800000 /* Vnode can have replicated pages */ +#define VNONREPLICABLE 0x1000000 /* Vnode has writers. Don't replicate */ +#define VDOCMP 0x2000000 /* Vnode has special VOP_CMP impl. */ +#define VSHARE 0x4000000 /* vnode part of global cache */ + /* VSHARE applies to local cell only */ +#define VFRLOCKS 0x8000000 /* vnode has FR locks applied */ +#define VENF_LOCKING 0x10000000 /* enf. mode FR locking in effect */ +#define VOPLOCK 0x20000000 /* oplock set on the vnode */ +#define VPURGE 0x40000000 /* In the linux 'put' thread */ + +typedef enum vrwlock { VRWLOCK_NONE, VRWLOCK_READ, + VRWLOCK_WRITE, VRWLOCK_WRITE_DIRECT, + VRWLOCK_TRY_READ, VRWLOCK_TRY_WRITE } vrwlock_t; + +/* + * flags for vn_create/VOP_CREATE/vn_open + */ +#define VEXCL 0x0001 +#define VZFS 0x0002 /* caller has a 0 RLIMIT_FSIZE */ + + +/* + * FROM_VN_KILL is a special 'kill' flag to VOP_CLOSE to signify a call + * from vn_kill. This is passed as the lastclose field + */ +typedef enum { L_FALSE, L_TRUE, FROM_VN_KILL } lastclose_t; + +/* + * Return values for VOP_INACTIVE. A return value of + * VN_INACTIVE_NOCACHE implies that the file system behavior + * has disassociated its state and bhv_desc_t from the vnode. + * To return VN_INACTIVE_NOCACHE, the vnode must have the + * VINACTIVE_TEARDOWN flag set. + */ +#define VN_INACTIVE_CACHE 0 +#define VN_INACTIVE_NOCACHE 1 + +/* + * Values for the cmd code given to VOP_VNODE_CHANGE. + */ +typedef enum vchange { + VCHANGE_FLAGS_FRLOCKS = 0, + VCHANGE_FLAGS_ENF_LOCKING = 1, + VCHANGE_FLAGS_TRUNCATED = 2, + VCHANGE_FLAGS_PAGE_DIRTY = 3, + VCHANGE_FLAGS_IOEXCL_COUNT = 4 +} vchange_t; + +/* + * Macros for dealing with the behavior descriptor inside of the vnode. + */ +#define BHV_TO_VNODE(bdp) ((vnode_t *)BHV_VOBJ(bdp)) +#define BHV_TO_VNODE_NULL(bdp) ((vnode_t *)BHV_VOBJNULL(bdp)) + +#define VNODE_TO_FIRST_BHV(vp) (BHV_HEAD_FIRST(&(vp)->v_bh)) +#define VN_BHV_HEAD(vp) ((vn_bhv_head_t *)(&((vp)->v_bh))) +#define VN_BHV_READ_LOCK(bhp) BHV_READ_LOCK(bhp) +#define VN_BHV_READ_UNLOCK(bhp) BHV_READ_UNLOCK(bhp) +#define VN_BHV_WRITE_LOCK(bhp) BHV_WRITE_LOCK(bhp) +#define VN_BHV_NOT_READ_LOCKED(bhp) BHV_NOT_READ_LOCKED(bhp) +#define VN_BHV_NOT_WRITE_LOCKED(bhp) BHV_NOT_WRITE_LOCKED(bhp) +#define vn_bhv_head_init(bhp,name) bhv_head_init(bhp,name) +#define vn_bhv_head_reinit(bhp) bhv_head_reinit(bhp) +#define vn_bhv_insert_initial(bhp,bdp) bhv_insert_initial(bhp,bdp) +#define vn_bhv_remove(bhp,bdp) bhv_remove(bhp,bdp) +#define vn_bhv_lookup(bhp,ops) bhv_lookup(bhp,ops) +#define vn_bhv_lookup_unlocked(bhp,ops) bhv_lookup_unlocked(bhp,ops) + +#define v_fbhv v_bh.bh_first /* first behavior */ +#define v_fops v_bh.bh_first->bd_ops /* ops for first behavior */ + + +struct cred; +struct vfs; +struct uio; +struct buf; +struct vattr; +struct pathname; +struct bmapval; +union rval; +struct attrlist_cursor_kern; +struct file; +struct page_buf_bmap_s; + +typedef int (*vop_open_t)(bhv_desc_t *, vnode_t **, mode_t, struct cred *); +typedef int (*vop_close_t)(bhv_desc_t *, int, lastclose_t, struct cred *); +typedef ssize_t (*vop_read_t)(bhv_desc_t *, struct uio *, int, struct cred *, + struct flid *); +typedef ssize_t (*vop_write_t)(bhv_desc_t *, struct uio *, int, struct cred *, + struct flid *); +typedef int (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *, unsigned int, unsigned long); +typedef int (*vop_getattr_t)(bhv_desc_t *, struct vattr *, int, + struct cred *); +typedef int (*vop_setattr_t)(bhv_desc_t *, struct vattr *, int, + struct cred *); +typedef int (*vop_access_t)(bhv_desc_t *, int, struct cred *); +typedef int (*vop_lookup_t)(bhv_desc_t *, char *, vnode_t **, + struct pathname *, int, vnode_t *, + struct cred *); +typedef int (*vop_create_t)(bhv_desc_t *, char *, struct vattr *, int, int, + vnode_t **, struct cred *); +typedef int (*vop_remove_t)(bhv_desc_t *, char *, struct cred *); +typedef int (*vop_link_t)(bhv_desc_t *, vnode_t *, char *, struct cred *); +typedef int (*vop_rename_t)(bhv_desc_t *, char *, vnode_t *, char *, + struct pathname *npnp, struct cred *); +typedef int (*vop_mkdir_t)(bhv_desc_t *, char *, struct vattr *, vnode_t **, + struct cred *); +typedef int (*vop_rmdir_t)(bhv_desc_t *, char *, vnode_t *, struct cred *); +typedef int (*vop_readdir_t)(bhv_desc_t *, struct uio *, struct cred *, + int *); +typedef int (*vop_symlink_t)(bhv_desc_t *, char *, struct vattr *, char *, + vnode_t **, struct cred *); +typedef int (*vop_readlink_t)(bhv_desc_t *, struct uio *, struct cred *); +typedef int (*vop_fsync_t)(bhv_desc_t *, int, struct cred *, xfs_off_t, xfs_off_t); +typedef int (*vop_inactive_t)(bhv_desc_t *, struct cred *); +typedef int (*vop_fid2_t)(bhv_desc_t *, struct fid *); +typedef int (*vop_release_t)(bhv_desc_t *); +typedef int (*vop_rwlock_t)(bhv_desc_t *, vrwlock_t); +typedef void (*vop_rwunlock_t)(bhv_desc_t *, vrwlock_t); +typedef int (*vop_seek_t)(bhv_desc_t *, xfs_off_t, xfs_off_t*); +typedef int (*vop_realvp_t)(bhv_desc_t *, vnode_t **); +typedef int (*vop_bmap_t)(bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, struct page_buf_bmap_s *, int *); +typedef int (*vop_strategy_t)(bhv_desc_t *, xfs_off_t, ssize_t, int, struct cred *, struct page_buf_bmap_s *, int *); +#ifdef CELL_CAPABLE +typedef int (*vop_allocstore_t)(bhv_desc_t *, xfs_off_t, size_t, struct cred *); +#endif +typedef int (*vop_fcntl_t)(bhv_desc_t *, int, void *, int, xfs_off_t, + struct cred *, union rval *); +typedef int (*vop_reclaim_t)(bhv_desc_t *, int); +typedef int (*vop_attr_get_t)(bhv_desc_t *, char *, char *, int *, int, + struct cred *); +typedef int (*vop_attr_set_t)(bhv_desc_t *, char *, char *, int, int, + struct cred *); +typedef int (*vop_attr_remove_t)(bhv_desc_t *, char *, int, struct cred *); +typedef int (*vop_attr_list_t)(bhv_desc_t *, char *, int, int, + struct attrlist_cursor_kern *, struct cred *); +typedef void (*vop_link_removed_t)(bhv_desc_t *, vnode_t *, int); +typedef void (*vop_vnode_change_t)(bhv_desc_t *, vchange_t, __psint_t); +typedef void (*vop_ptossvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); +typedef void (*vop_pflushinvalvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int); +typedef int (*vop_pflushvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, uint64_t, int); +typedef void (*vop_sethole_t)(bhv_desc_t *, void *, int, int, xfs_off_t); + +#ifdef CONFIG_FS_POSIX_ACL +typedef int (*vop_acl_get_t)(vnode_t *, struct acl *, struct acl *); +typedef int (*vop_acl_set_t)(vnode_t *, struct acl *, struct acl *); +#endif + + +typedef struct vnodeops { +#ifdef CELL_CAPABLE + bhv_position_t vn_position; /* position within behavior chain */ +#endif + vop_open_t vop_open; + vop_close_t vop_close; + vop_read_t vop_read; + vop_write_t vop_write; + vop_ioctl_t vop_ioctl; + vop_getattr_t vop_getattr; + vop_setattr_t vop_setattr; + vop_access_t vop_access; + vop_lookup_t vop_lookup; + vop_create_t vop_create; + vop_remove_t vop_remove; + vop_link_t vop_link; + vop_rename_t vop_rename; + vop_mkdir_t vop_mkdir; + vop_rmdir_t vop_rmdir; + vop_readdir_t vop_readdir; + vop_symlink_t vop_symlink; + vop_readlink_t vop_readlink; + vop_fsync_t vop_fsync; + vop_inactive_t vop_inactive; + vop_fid2_t vop_fid2; + vop_rwlock_t vop_rwlock; + vop_rwunlock_t vop_rwunlock; + vop_seek_t vop_seek; + vop_realvp_t vop_realvp; + vop_bmap_t vop_bmap; + vop_strategy_t vop_strategy; +#ifdef CELL_CAPABLE + vop_allocstore_t vop_allocstore; +#endif + vop_fcntl_t vop_fcntl; + vop_reclaim_t vop_reclaim; + vop_attr_get_t vop_attr_get; + vop_attr_set_t vop_attr_set; + vop_attr_remove_t vop_attr_remove; + vop_attr_list_t vop_attr_list; +#ifdef CONFIG_FS_POSIX_ACL + vop_acl_get_t vop_acl_get; + vop_acl_set_t vop_acl_set; +#endif + vop_link_removed_t vop_link_removed; + vop_vnode_change_t vop_vnode_change; + vop_ptossvp_t vop_tosspages; + vop_pflushinvalvp_t vop_flushinval_pages; + vop_pflushvp_t vop_flush_pages; + vop_sethole_t vop_pages_sethole; + vop_release_t vop_release; +} vnodeops_t; + +/* + * VOP's. + */ +#define _VOP_(op, vp) (*((vnodeops_t *)(vp)->v_fops)->op) + +/* + * Be careful with VOP_OPEN, since we're holding the chain lock on the + * original vnode and VOP_OPEN semantic allows the new vnode to be returned + * in vpp. The practice of passing &vp for vpp just doesn't work. + */ +#define VOP_READ(vp,uiop,iof,cr,fl,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_read, vp)((vp)->v_fbhv,uiop,iof,cr,fl); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_WRITE(vp,uiop,iof,cr,fl,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_write, vp)((vp)->v_fbhv,uiop,iof,cr,fl); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_BMAP(vp,of,sz,rw,cr,b,n,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,cr,b,n); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_STRATEGY(vp,of,sz,rw,cr,b,n,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_strategy, vp)((vp)->v_fbhv,of,sz,rw,cr,b,n); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_OPEN(vp, vpp, mode, cr, rv) \ +{ \ + ASSERT(&(vp) != vpp); \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_open, vp)((vp)->v_fbhv, vpp, mode, cr); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_CLOSE(vp,f,c,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_close, vp)((vp)->v_fbhv,f,c,cr); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_GETATTR(vp, vap, f, cr, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_getattr, vp)((vp)->v_fbhv, vap, f, cr); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_SETATTR(vp, vap, f, cr, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_setattr, vp)((vp)->v_fbhv, vap, f, cr); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_ACCESS(vp, mode, cr, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_access, vp)((vp)->v_fbhv, mode, cr); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_LOOKUP(vp,cp,vpp,pnp,f,rdir,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_lookup, vp)((vp)->v_fbhv,cp,vpp,pnp,f,rdir,cr); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_CREATE(dvp,p,vap,ex,mode,vpp,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(dvp)->v_bh); \ + rv = _VOP_(vop_create, dvp)((dvp)->v_fbhv,p,vap,ex,mode,vpp,cr);\ + VN_BHV_READ_UNLOCK(&(dvp)->v_bh); \ +} +#define VOP_REMOVE(dvp,p,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(dvp)->v_bh); \ + rv = _VOP_(vop_remove, dvp)((dvp)->v_fbhv,p,cr); \ + VN_BHV_READ_UNLOCK(&(dvp)->v_bh); \ +} +#define VOP_LINK(tdvp,fvp,p,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(tdvp)->v_bh); \ + rv = _VOP_(vop_link, tdvp)((tdvp)->v_fbhv,fvp,p,cr); \ + VN_BHV_READ_UNLOCK(&(tdvp)->v_bh); \ +} +#define VOP_RENAME(fvp,fnm,tdvp,tnm,tpnp,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(fvp)->v_bh); \ + rv = _VOP_(vop_rename, fvp)((fvp)->v_fbhv,fnm,tdvp,tnm,tpnp,cr);\ + VN_BHV_READ_UNLOCK(&(fvp)->v_bh); \ +} +#define VOP_MKDIR(dp,p,vap,vpp,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(dp)->v_bh); \ + rv = _VOP_(vop_mkdir, dp)((dp)->v_fbhv,p,vap,vpp,cr); \ + VN_BHV_READ_UNLOCK(&(dp)->v_bh); \ +} +#define VOP_RMDIR(dp,p,cdir,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(dp)->v_bh); \ + rv = _VOP_(vop_rmdir, dp)((dp)->v_fbhv,p,cdir,cr); \ + VN_BHV_READ_UNLOCK(&(dp)->v_bh); \ +} +#define VOP_READDIR(vp,uiop,cr,eofp,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_readdir, vp)((vp)->v_fbhv,uiop,cr,eofp); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_SYMLINK(dvp,lnm,vap,tnm,vpp,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(dvp)->v_bh); \ + rv = _VOP_(vop_symlink, dvp) ((dvp)->v_fbhv,lnm,vap,tnm,vpp,cr); \ + VN_BHV_READ_UNLOCK(&(dvp)->v_bh); \ +} +#define VOP_READLINK(vp,uiop,cr,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_readlink, vp)((vp)->v_fbhv,uiop,cr); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_FSYNC(vp,f,cr,b,e,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_fsync, vp)((vp)->v_fbhv,f,cr,b,e); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_INACTIVE(vp, cr, rv) \ +{ /* vnode not reference-able, so no need to lock chain */ \ + rv = _VOP_(vop_inactive, vp)((vp)->v_fbhv, cr); \ +} +#define VOP_RELEASE(vp, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_release, vp)((vp)->v_fbhv); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_FID2(vp, fidp, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_fid2, vp)((vp)->v_fbhv, fidp); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_RWLOCK(vp,i) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + (void)_VOP_(vop_rwlock, vp)((vp)->v_fbhv, i); \ + /* "allow" is done by rwunlock */ \ +} +#define VOP_RWLOCK_TRY(vp,i) \ + _VOP_(vop_rwlock, vp)((vp)->v_fbhv, i) + +#define VOP_RWUNLOCK(vp,i) \ +{ /* "prevent" was done by rwlock */ \ + (void)_VOP_(vop_rwunlock, vp)((vp)->v_fbhv, i); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_SEEK(vp, ooff, noffp, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_seek, vp)((vp)->v_fbhv, ooff, noffp); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_REALVP(vp1, vp2, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp1)->v_bh); \ + rv = _VOP_(vop_realvp, vp1)((vp1)->v_fbhv, vp2); \ + VN_BHV_READ_UNLOCK(&(vp1)->v_bh); \ +} +#define VOP_FCNTL(vp,cmd,a,f,of,cr,rvp,rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_fcntl, vp)((vp)->v_fbhv,cmd,a,f,of,cr,rvp); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_RECLAIM(vp, flag, rv) \ +{ /* vnode not reference-able, so no need to lock chain */ \ + ASSERT(!((vp)->v_flag & VINACTIVE_TEARDOWN)); \ + rv = _VOP_(vop_reclaim, vp)((vp)->v_fbhv, flag); \ +} +#define VOP_ATTR_GET(vp, name, val, vallenp, fl, cred, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_attr_get, vp)((vp)->v_fbhv,name,val,vallenp,fl,cred); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_ATTR_SET(vp, name, val, vallen, fl, cred, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_attr_set, vp)((vp)->v_fbhv,name,val,vallen,fl,cred); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_ATTR_REMOVE(vp, name, flags, cred, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_attr_remove, vp)((vp)->v_fbhv,name,flags,cred); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_ATTR_LIST(vp, buf, buflen, fl, cursor, cred, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_attr_list, vp)((vp)->v_fbhv,buf,buflen,fl,cursor,cred);\ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_LINK_REMOVED(vp, dvp, linkzero) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + (void)_VOP_(vop_link_removed, vp)((vp)->v_fbhv, dvp, linkzero); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} + +#ifdef CONFIG_FS_POSIX_ACL +#define VOP_ACL_GET(vp, acl, dacl, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_acl_get, vp)((vp),acl,dacl); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_ACL_SET(vp, acl, dacl, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_acl_set, vp)((vp),acl,dacl); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#endif + +#define VOP_VNODE_CHANGE(vp, cmd, val) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + (void)_VOP_(vop_vnode_change, vp)((vp)->v_fbhv,cmd,val); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +/* + * These are page cache functions that now go thru VOPs. + * 'last' parameter is unused and left in for IRIX compatibility + */ +#define VOP_TOSS_PAGES(vp, first, last, fiopt) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + _VOP_(vop_tosspages, vp)((vp)->v_fbhv,first, last, fiopt); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +/* + * 'last' parameter is unused and left in for IRIX compatibility + */ +#define VOP_FLUSHINVAL_PAGES(vp, first, last, fiopt) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + _VOP_(vop_flushinval_pages, vp)((vp)->v_fbhv,first,last,fiopt); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +/* + * 'last' parameter is unused and left in for IRIX compatibility + */ +#define VOP_FLUSH_PAGES(vp, first, last, flags, fiopt, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_flush_pages, vp)((vp)->v_fbhv,first,last,flags,fiopt);\ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_PAGES_SETHOLE(vp, pfd, cnt, doremap, remapoffset) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + _VOP_(vop_pages_sethole, vp)((vp)->v_fbhv,pfd,cnt,doremap,remapoffset);\ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} +#define VOP_IOCTL(vp, inode, filp, cmd, arg, rv) \ +{ \ + VN_BHV_READ_LOCK(&(vp)->v_bh); \ + rv = _VOP_(vop_ioctl, vp)((vp)->v_fbhv,inode,filp,cmd,arg); \ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); \ +} + +#define IO_APPEND 0x00001 /* append write (VOP_WRITE) */ +#define IO_SYNC 0x00002 /* sync file I/O (VOP_WRITE) */ +#define IO_DIRECT 0x00004 /* bypass page cache */ +#define IO_IGNCACHE 0x00008 /* ignore page cache coherency when doing i/o + (IO_DIRECT) */ +#define IO_GRIO 0x00010 /* this is a guaranteed rate request */ +#define IO_INVIS 0x00020 /* don't update inode timestamps */ +#define IO_DSYNC 0x00040 /* sync data I/O (VOP_WRITE) */ +#define IO_RSYNC 0x00080 /* sync data I/O (VOP_READ) */ +#define IO_NFS 0x00100 /* I/O from the NFS v2 server */ +#define IO_TRUSTEDDIO 0x00200 /* direct I/O from a trusted client + so block zeroing is unnecessary */ +#define IO_PRIORITY 0x00400 /* I/O is priority */ +#define IO_ISLOCKED 0x00800 /* for VOP_READ/WRITE, VOP_RWLOCK/RWUNLOCK is + being done by higher layer - file system + shouldn't do locking */ +#define IO_BULK 0x01000 /* loosen semantics for sequential bandwidth */ +#define IO_NFS3 0x02000 /* I/O from the NFS v3 server */ +#define IO_UIOSZ 0x04000 /* respect i/o size flags in uio struct */ +#define IO_ONEPAGE 0x08000 /* I/O must be fit into one page */ +#define IO_MTTHREAD 0x10000 /* I/O coming from threaded application, only + used by paging to indicate that fs can + return EAGAIN if this would deadlock. */ + +#ifdef CELL_CAPABLE +#define IO_PFUSE_SAFE 0x20000 /* VOP_WRITE/VOP_READ: vnode can take addr's, + kvatopfdat them, bump pf_use, and continue + to reference data after return from VOP_. + If IO_SYNC, only concern is kvatopfdat + returns legal pfdat. */ +#define IO_PAGE_DIRTY 0x40000 /* Pageing I/O writing to page */ +#define IO_TOKEN_MASK 0xF80000 /* Mask for CXFS to encode tokens in ioflag */ +#define IO_TOKEN_SHIFT 19 +#define IO_TOKEN_SET(i) (((i) & IO_TOKEN_MASK) >> IO_TOKEN_SHIFT) +#define IO_NESTEDLOCK 0x1000000 /* Indicates that XFS_IOLOCK_NESTED was used*/ +#define IO_LOCKED_EXCL 0x2000000 /* Indicates that iolock is held EXCL */ +#endif + +/* + * Flush/Invalidate options for VOP_TOSS_PAGES, VOP_FLUSHINVAL_PAGES and + * VOP_FLUSH_PAGES. + */ +#define FI_NONE 0 /* none */ +#define FI_REMAPF 1 /* Do a remapf prior to the operation */ +#define FI_REMAPF_LOCKED 2 /* Do a remapf prior to the operation. + Prevent VM access to the pages until + the operation completes. */ + +/* + * Vnode attributes. va_mask indicates those attributes the caller + * wants to set (setattr) or extract (getattr). + */ +typedef struct vattr { + int va_mask; /* bit-mask of attributes */ + vtype_t va_type; /* vnode type (for create) */ + mode_t va_mode; /* file access mode */ + uid_t va_uid; /* owner user id */ + gid_t va_gid; /* owner group id */ + dev_t va_fsid; /* file system id (dev for now) */ + xfs_ino_t va_nodeid; /* node id */ + nlink_t va_nlink; /* number of references to file */ + xfs_off_t va_size; /* file size in bytes */ + timespec_t va_atime; /* time of last access */ + timespec_t va_mtime; /* time of last modification */ + timespec_t va_ctime; /* time file ``created'' */ + dev_t va_rdev; /* device the file represents */ + u_long va_blksize; /* fundamental block size */ + __int64_t va_nblocks; /* # of blocks allocated */ + u_long va_vcode; /* version code */ + u_long va_xflags; /* random extended file flags */ + u_long va_extsize; /* file extent size */ + u_long va_nextents; /* number of extents in file */ + u_long va_anextents; /* number of attr extents in file */ + int va_projid; /* project id */ + u_int va_gencount; /* object generation count */ +} vattr_t; + +/* + * setattr or getattr attributes + */ +#define AT_TYPE 0x00000001 +#define AT_MODE 0x00000002 +#define AT_UID 0x00000004 +#define AT_GID 0x00000008 +#define AT_FSID 0x00000010 +#define AT_NODEID 0x00000020 +#define AT_NLINK 0x00000040 +#define AT_SIZE 0x00000080 +#define AT_ATIME 0x00000100 +#define AT_MTIME 0x00000200 +#define AT_CTIME 0x00000400 +#define AT_RDEV 0x00000800 +#define AT_BLKSIZE 0x00001000 +#define AT_NBLOCKS 0x00002000 +#define AT_VCODE 0x00004000 +#define AT_MAC 0x00008000 +#define AT_UPDATIME 0x00010000 +#define AT_UPDMTIME 0x00020000 +#define AT_UPDCTIME 0x00040000 +#define AT_ACL 0x00080000 +#define AT_CAP 0x00100000 +#define AT_INF 0x00200000 +#define AT_XFLAGS 0x00400000 +#define AT_EXTSIZE 0x00800000 +#define AT_NEXTENTS 0x01000000 +#define AT_ANEXTENTS 0x02000000 +#define AT_PROJID 0x04000000 +#define AT_SIZE_NOPERM 0x08000000 +#define AT_GENCOUNT 0x10000000 + +#ifdef CELL_CAPABLE +#define AT_ALL (AT_TYPE|AT_MODE|AT_UID|AT_GID|AT_FSID|AT_NODEID|\ + AT_NLINK|AT_SIZE|AT_ATIME|AT_MTIME|AT_CTIME|AT_RDEV|\ + AT_BLKSIZE|AT_NBLOCKS|AT_VCODE|AT_MAC|AT_ACL|AT_CAP|\ + AT_INF|AT_XFLAGS|AT_EXTSIZE|AT_NEXTENTS|AT_ANEXTENTS|\ + AT_PROJID|AT_GENCOUNT) +#endif + +#define AT_STAT (AT_TYPE|AT_MODE|AT_UID|AT_GID|AT_FSID|AT_NODEID|AT_NLINK|\ + AT_SIZE|AT_ATIME|AT_MTIME|AT_CTIME|AT_RDEV|AT_BLKSIZE|\ + AT_NBLOCKS|AT_PROJID) + +#ifdef CELL_CAPABLE +#define AT_TIMES (AT_ATIME|AT_MTIME|AT_CTIME) +#endif + +#define AT_UPDTIMES (AT_UPDATIME|AT_UPDMTIME|AT_UPDCTIME) + +#define AT_NOSET (AT_NLINK|AT_RDEV|AT_FSID|AT_NODEID|AT_TYPE|\ + AT_BLKSIZE|AT_NBLOCKS|AT_VCODE|AT_NEXTENTS|AT_ANEXTENTS|\ + AT_GENCOUNT) + +#define VSGID 02000 /* set group id on execution */ +#define VEXEC 00100 +#define MODEMASK 07777 /* mode bits plus permission bits */ + +/* + * Check whether mandatory file locking is enabled. + */ +#define MANDLOCK(vp, mode) \ + ((vp)->v_type == VREG && ((mode) & (VSGID|(VEXEC>>3))) == VSGID) + +/* + * This macro determines if a write is actually allowed + * on the node. This macro is used to check if a file's + * access time can be modified. + */ +#define WRITEALLOWED(vp) \ + (((vp)->v_vfsp && ((vp)->v_vfsp->vfs_flag & VFS_RDONLY) == 0) || \ + (((vp)->v_type != VREG ) && ((vp)->v_type != VDIR) && ((vp)->v_type != VLNK))) +/* + * Global vnode allocation: + * + * vp = vn_alloc(vfsp, type, rdev); + * vn_free(vp); + * + * Inactive vnodes are kept on an LRU freelist managed by vn_alloc, vn_free, + * vn_get, vn_purge, and vn_rele. When vn_rele inactivates a vnode, + * it puts the vnode at the end of the list unless there are no behaviors + * attached to it, which tells vn_rele to insert at the beginning of the + * freelist. When vn_get acquires an inactive vnode, it unlinks the vnode + * from the list; + * vn_purge puts inactive dead vnodes at the front of the list for rapid reuse. + * + * If the freelist is empty, vn_alloc dynamically allocates another vnode. + * Call vn_free to destroy a vn_alloc'd vnode that has no other references + * and no valid private data. Do not call vn_free from within VOP_INACTIVE; + * just remove the behaviors and vn_rele will do the right thing. + * + * A vnode might be deallocated after it is put on the freelist (after + * a VOP_RECLAIM, of course). In this case, the vn_epoch value is + * incremented to define a new vnode epoch. + */ +extern void vn_init(void); +extern void vn_free(struct vnode *); +extern vnode_t *vn_address(struct inode *); +extern vnode_t *vn_initialize(struct vfs *, struct inode *, int); + +/* + * Acquiring and invalidating vnodes: + * + * if (vn_get(vp, version, 0)) + * ...; + * vn_purge(vp, version); + * + * vn_get and vn_purge must be called with vmap_t arguments, sampled + * while a lock that the vnode's VOP_RECLAIM function acquires is + * held, to ensure that the vnode sampled with the lock held isn't + * recycled (VOP_RECLAIMed) or deallocated between the release of the lock + * and the subsequent vn_get or vn_purge. + */ + +/* + * vnode_map structures _must_ match vn_epoch and vnode structure sizes. + */ +typedef struct vnode_map { + vfs_t *v_vfsp; + vnumber_t v_number; /* in-core vnode number */ + xfs_ino_t v_ino; /* inode # */ +} vmap_t; + +#define VMAP(vp, ip, vmap) {(vmap).v_vfsp = (vp)->v_vfsp, \ + (vmap).v_number = (vp)->v_number, \ + (vmap).v_ino = (ip)->i_ino; } +extern int vn_count(struct vnode *); +extern void vn_purge(struct vnode *, vmap_t *); +extern vnode_t *vn_get(struct vnode *, vmap_t *, uint); +extern int vn_revalidate(struct vnode *, int); +extern void vn_remove(struct vnode *); + +/* + * Flags for vn_get(). + */ +#define VN_GET_NOWAIT 0x1 /* Don't wait for inactive or reclaim */ + +/* + * Vnode reference counting functions (and macros for compatibility). + */ +extern vnode_t *vn_hold(struct vnode *); +extern void vn_rele(struct vnode *); +extern void vn_put(struct vnode *); + +#if defined(CONFIG_XFS_VNODE_TRACING) + +#define VN_HOLD(vp) \ + ((void)vn_hold(vp), \ + vn_trace_hold(vp, __FILE__, __LINE__, (inst_t *)__return_address)) +#define VN_RELE(vp) \ + (vn_trace_rele(vp, __FILE__, __LINE__, (inst_t *)__return_address), \ + vn_rele(vp)) + +#else /* ! (defined(CONFIG_XFS_VNODE_TRACING)) */ + +#define VN_HOLD(vp) ((void)vn_hold(vp)) +#define VN_RELE(vp) (vn_rele(vp)) + +#endif /* ! (defined(CONFIG_XFS_VNODE_TRACING) */ + +/* + * Vnode spinlock manipulation. + */ +#define VN_LOCK(vp) mutex_spinlock(&(vp)->v_lock) +#define VN_UNLOCK(vp,s) mutex_spinunlock(&(vp)->v_lock,s) +#define VN_FLAGSET(vp,b) vn_flagset(vp,b) +#define VN_FLAGCLR(vp,b) vn_flagclr(vp,b) + +static __inline__ void vn_flagset(struct vnode *vp, uint flag) +{ + long flags; + spin_lock_irqsave(&vp->v_lock, flags); + vp->v_flag |= flag; + spin_unlock_irqrestore(&vp->v_lock, flags); +} + +static __inline__ void vn_flagclr(struct vnode *vp, uint flag) +{ + long flags; + spin_lock_irqsave(&vp->v_lock, flags); + vp->v_flag &= ~flag; + spin_unlock_irqrestore(&vp->v_lock, flags); +} + +/* + * Some useful predicates. + */ +#define VN_MAPPED(vp) (LINVFS_GET_IP(vp)->i_data.i_mmap != NULL) +#define VN_CACHED(vp) (LINVFS_GET_IP(vp)->i_data.nrpages) +#define VN_DIRTY(vp) (!list_empty(&(LINVFS_GET_IP(vp)->i_dirty_buffers))) +#define VMODIFY(vp) VN_FLAGSET(vp, VMODIFIED) +#define VUNMODIFY(vp) VN_FLAGCLR(vp, VMODIFIED) + +/* + * Flags to VOP_SETATTR/VOP_GETATTR. + */ +#define ATTR_UTIME 0x01 /* non-default utime(2) request */ +#define ATTR_EXEC 0x02 /* invocation from exec(2) */ +#define ATTR_COMM 0x04 /* yield common vp attributes */ +#define ATTR_DMI 0x08 /* invocation from a DMI function */ +#define ATTR_LAZY 0x80 /* set/get attributes lazily */ +#define ATTR_NONBLOCK 0x100 /* return EAGAIN if operation would block */ +#define ATTR_NOLOCK 0x200 /* Don't grab any conflicting locks */ +#define ATTR_NOSIZETOK 0x400 /* Don't get the DVN_SIZE_READ token */ + +/* + * Flags to VOP_FSYNC and VOP_RECLAIM. + */ +#define FSYNC_NOWAIT 0 /* asynchronous flush */ +#define FSYNC_WAIT 0x1 /* synchronous fsync or forced reclaim */ +#define FSYNC_INVAL 0x2 /* flush and invalidate cached data */ +#define FSYNC_DATA 0x4 /* synchronous fsync of data only */ + +/* + * Vnode list ops. + */ +#define vn_append(vp,vl) vn_insert(vp, (struct vnlist *)(vl)->vl_prev) + +extern void vn_initlist(struct vnlist *); +extern void vn_insert(struct vnode *, struct vnlist *); +extern void vn_unlink(struct vnode *); + + +#if (defined(CONFIG_XFS_VNODE_TRACING)) + +#define VNODE_TRACE_SIZE 16 /* number of trace entries */ + +/* + * Tracing entries. + */ +#define VNODE_KTRACE_ENTRY 1 +#define VNODE_KTRACE_EXIT 2 +#define VNODE_KTRACE_HOLD 3 +#define VNODE_KTRACE_REF 4 +#define VNODE_KTRACE_RELE 5 + +extern void vn_trace_entry(struct vnode *, char *, inst_t *); +extern void vn_trace_exit(struct vnode *, char *, inst_t *); +extern void vn_trace_hold(struct vnode *, char *, int, inst_t *); +extern void vn_trace_ref(struct vnode *, char *, int, inst_t *); +extern void vn_trace_rele(struct vnode *, char *, int, inst_t *); +#define VN_TRACE(vp) \ + vn_trace_ref(vp, __FILE__, __LINE__, (inst_t *)__return_address) + +#else /* ! (defined(CONFIG_XFS_VNODE_TRACING)) */ + +#define vn_trace_entry(a,b,c) +#define vn_trace_exit(a,b,c) +#define vn_trace_hold(a,b,c,d) +#define vn_trace_ref(a,b,c,d) +#define vn_trace_rele(a,b,c,d) +#define VN_TRACE(vp) + +#endif /* ! (defined(CONFIG_XFS_VNODE_TRACING)) */ + +#endif /* __XFS_VNODE_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/mac_xfs.c linux-2.4-xfs/linux/fs/xfs/mac_xfs.c --- linux-2.4.7/linux/fs/xfs/mac_xfs.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/mac_xfs.c Mon Mar 12 13:10:09 2001 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +int +mac_xfs_iaccess( xfs_inode_t *ip, mode_t mode, struct cred *cr ) +{ + struct mac_label mac; + struct mac_label *mp = mac_high_low_lp; + + if (cr == NULL || sys_cred == NULL ) { + return EACCES; + } + + if (xfs_attr_fetch(ip, SGI_MAC_FILE, (char *)&mac, + sizeof(struct mac_label)) == 0) { + if ((mp = mac_add_label(&mac)) == NULL) { + return mac_access(mac_high_low_lp, cr, mode); + } + } + + return mac_access(mp, cr, mode); +} diff -rNu linux-2.4.7/linux/fs/xfs/macstubs.c linux-2.4-xfs/linux/fs/xfs/macstubs.c --- linux-2.4.7/linux/fs/xfs/macstubs.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/macstubs.c Mon Jan 15 04:28:46 2001 @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * Mandatory Access Control stubs. + */ + +#ifdef DEBUG +#define DOPANIC(s) panic(s) +#else /* DEBUG */ +#define DOPANIC(s) +#endif /* DEBUG */ + +int mac_access(void) +{ + DOPANIC("mac_access stub"); + /* NOTREACHED */ return 0; +} + +int mac_cat_equ(void) +{ + DOPANIC("mac_cat_equ stub"); + /* NOTREACHED */ return 0; +} + +int mac_clntkudp_soattr(void) +{ + DOPANIC("mac_clntkudp_soattr stub"); + /* NOTREACHED */ return 0; +} + +int mac_copy(void) +{ + DOPANIC("mac_copy stub"); + /* NOTREACHED */ return 0; +} + +int mac_copyin_label(void) +{ + DOPANIC("mac_copyin_label stub"); + /* NOTREACHED */ return 0; +} + +int mac_dom(void) +{ + DOPANIC("mac_dom stub"); + /* NOTREACHED */ return 0; +} + +int mac_autofs_attr_get(void) +{ + DOPANIC("mac_autofs_attr_get stub"); + /* NOTREACHED */ return 0; +} + +int mac_autofs_attr_set(void) +{ + DOPANIC("mac_autofs_attr_set stub"); + /* NOTREACHED */ return 0; +} + +int mac_autofs_attr_list(void) +{ + DOPANIC("mac_autofs_attr_list stub"); + /* NOTREACHED */ return 0; +} + + +int mac_eag_getlabel(void) +{ + DOPANIC("mac_eag_getlabel stub"); + /* NOTREACHED */ return 0; +} + +int mac_efs_attr_get(void) +{ + DOPANIC("mac_efs_attr_get stub"); + /* NOTREACHED */ return 0; +} + +int mac_efs_attr_set(void) +{ + DOPANIC("mac_efs_attr_set stub"); + /* NOTREACHED */ return 0; +} + +int mac_fdfs_attr_get(void) +{ + DOPANIC("mac_fdfs_attr_get stub"); + /* NOTREACHED */ return 0; +} + +int mac_fifo_attr_get(void) +{ + DOPANIC("mac_fifo_attr_get stub"); + /* NOTREACHED */ return 0; +} + +int mac_pipe_attr_get(void) +{ + DOPANIC("mac_pipe_attr_get stub"); + /* NOTREACHED */ return 0; +} + +int mac_pipe_attr_set(void) +{ + DOPANIC("mac_pipe_attr_set stub"); + /* NOTREACHED */ return 0; +} + +int mac_proc_attr_get(void) +{ + DOPANIC("mac_proc_attr_get stub"); + /* NOTREACHED */ return 0; +} + +int mac_efs_iaccess(void) +{ + DOPANIC("mac_efs_iaccess stub"); + /* NOTREACHED */ return 0; +} + +int mac_efs_setlabel(void) +{ + DOPANIC("mac_efs_setlabel stub"); + /* NOTREACHED */ return 0; +} + +int mac_xfs_ext_attr_fetch(void) +{ + DOPANIC("mac_xfs_ext_attr_fetch stub"); + /* NOTREACHED */ return 0; +} + +int mac_xfs_attr_get(void) +{ + DOPANIC("mac_xfs_attr_get stub"); + /* NOTREACHED */ return 0; +} + +int mac_spec_attr_get(void) +{ + DOPANIC("mac_spec_attr_get stub"); + /* NOTREACHED */ return 0; +} + +int mac_xfs_attr_set(void) +{ + DOPANIC("mac_xfs_attr_set stub"); + /* NOTREACHED */ return 0; +} + +int mac_xfs_iaccess(struct xfs_inode *a, mode_t b, struct cred *c) +{ + DOPANIC("mac_xfs_iaccess stub"); + /* NOTREACHED */ return 0; +} + +int mac_xfs_vaccess(vnode_t *a, struct cred *b, mode_t c) +{ + DOPANIC("mac_xfs_vaccess stub"); + /* NOTREACHED */ return 0; +} + +int mac_xfs_setlabel(void) +{ + DOPANIC("mac_xfs_setlabel stub"); + /* NOTREACHED */ return 0; +} + +int mac_hwg_iaccess(void) { DOPANIC("mac_hwg_iaccess stub"); /* NOTREACHED */ return 0; } +int mac_hwg_get(void) { DOPANIC("mac_hwg_get stub"); /* NOTREACHED */ return 0; } +int mac_hwg_match(void) { DOPANIC("mac_hwg_match stub"); /* NOTREACHED */ return 0; } + +int mac_nfs_iaccess(void) +{ + DOPANIC("mac_nfs_iaccess stub"); + /* NOTREACHED */ return 0; +} + +int mac_nfs_default(void) +{ + DOPANIC("mac_nfs_default stub"); + /* NOTREACHED */ return 0; +} + +int mac_nfs_get(void) +{ + DOPANIC("mac_nfs_get stub"); + /* NOTREACHED */ return 0; +} + +int mac_equ(void) +{ + DOPANIC("mac_equ stub"); + /* NOTREACHED */ return 0; +} + +int mac_get(void) +{ + DOPANIC("mac_get stub"); + /* NOTREACHED */ return 0; +} + +int mac_getplabel(void) +{ + DOPANIC("mac_getplabel stub"); + /* NOTREACHED */ return 0; +} + +int mac_inrange(void) +{ + DOPANIC("mac_inrange stub"); + /* NOTREACHED */ return 0; +} + +int mac_invalid(void) +{ + DOPANIC("mac_invalid stub"); + /* NOTREACHED */ return 0; +} + +int mac_is_moldy(void) +{ + DOPANIC("mac_is_moldy stub"); + /* NOTREACHED */ return 0; +} + +int mac_mint_equ(void) +{ + DOPANIC("mac_mint_equ stub"); + /* NOTREACHED */ return 0; +} + +int mac_moldy_path(void) +{ + DOPANIC("mac_moldy_path stub"); + /* NOTREACHED */ return 0; +} + +int mac_initial_path(void) +{ + DOPANIC("mac_initial_path stub"); + /* NOTREACHED */ return 0; +} + +int mac_msg_access(void) +{ + DOPANIC("mac_msg_access stub"); + /* NOTREACHED */ return 0; +} + +int mac_revoke(void) +{ + DOPANIC("mac_revoke stub"); + /* NOTREACHED */ return 0; +} + +int mac_same(void) +{ + DOPANIC("mac_same stub"); + /* NOTREACHED */ return 0; +} + +int mac_sem_access(void) +{ + DOPANIC("mac_sem_access stub"); + /* NOTREACHED */ return 0; +} + +int mac_vsetlabel(void) +{ + DOPANIC("mac_vsetlabel stub"); + /* NOTREACHED */ return 0; +} + +int mac_set(void) +{ + DOPANIC("mac_set stub"); + /* NOTREACHED */ return 0; +} + +int mac_setplabel(void) +{ + DOPANIC("mac_setplabel stub"); + /* NOTREACHED */ return 0; +} + +int mac_shm_access(void) +{ + DOPANIC("mac_shm_access stub"); + /* NOTREACHED */ return 0; +} + +ssize_t mac_size(void) +{ + DOPANIC("mac_size stub"); + /* NOTREACHED */ return 0; +} + +int mac_vaccess(void) +{ + DOPANIC("mac_vaccess stub"); + /* NOTREACHED */ return 0;} + +struct mac_label; + +struct mac_label *mac_low_high_lp; +struct mac_label *mac_high_low_lp; +struct mac_label *mac_admin_high_lp; +struct mac_label *mac_equal_equal_lp; + +struct cred; + +struct cred *mac_process_cred; + +struct mac_label *mac_vtolp(void) +{ + DOPANIC("mac_vtolp stub"); + /* NOTREACHED */ return 0; +} + +void mac_importlabel(void) +{ + DOPANIC("mac_importlabel stub"); +} + + +struct mac_label *mac_add_label(void) +{ + DOPANIC("mac_add_label stub"); + /* NOTREACHED */ return 0; +} + +struct mac_label *mac_unmold(void) +{ + DOPANIC("mac_unmold stub"); + /* NOTREACHED */ return 0; +} + +int msen_valid(void) +{ + DOPANIC("msen_valid stub"); + /* NOTREACHED */ return 0; +} + +int mint_valid(void) +{ + DOPANIC("mint_valid stub"); + /* NOTREACHED */ return 0; +} + +struct mac_b_label *msen_add_label(void) +{ + DOPANIC("msen_add_label stub"); + /* NOTREACHED */ return 0; +} + +struct mac_b_label *mint_add_label(void) +{ + DOPANIC("mint_add_label stub"); + /* NOTREACHED */ return 0; +} + +ssize_t msen_size(void) +{ + DOPANIC("msen_size stub"); + /* NOTREACHED */ return 0; +} + +ssize_t mint_size(void) +{ + DOPANIC("mint_size stub"); + /* NOTREACHED */ return 0; +} + +struct mac_label *mac_demld(void) +{ + DOPANIC("mac_demld stub"); + /* NOTREACHED */ return 0; +} + +struct mac_label *mac_dup(void) +{ + DOPANIC("mac_dup stub"); + /* NOTREACHED */ return 0; +} + +struct mac_label *mac_efs_getlabel(void) +{ + DOPANIC("mac_efs_getlabel stub"); + /* NOTREACHED */ return 0; +} + +struct mac_label *mac_xfs_getlabel(void) +{ + DOPANIC("mac_xfs_getlabel stub"); + /* NOTREACHED */ return 0; +} + +struct mac_label *mac_set_moldy(void) +{ + DOPANIC("mac_set_moldy stub"); + /* NOTREACHED */ return 0; +} + + +void mac_init(void) {} /* Do not put a DOPANIC in this stub! */ +void mac_eag_enable(void) { DOPANIC("mac_eag_enable stub"); } +void mac_confignote(void) { DOPANIC("mac_confignote stub"); } +void mac_mount(void) { DOPANIC("mac_mount stub"); } +void mac_mountroot(void) { DOPANIC("mac_mountroot stub"); } +void mac_init_cred(void) { DOPANIC("mac_init_cred stub"); } +void mac_msg_init(void) { DOPANIC("mac_msg_init stub"); } +void mac_msg_setlabel(void) { DOPANIC("mac_msg_setlabel stub"); } +void mac_sem_init(void) { DOPANIC("mac_sem_init stub"); } +void mac_sem_setlabel(void) { DOPANIC("mac_sem_setlabel stub"); } +void mac_shm_init(void) { DOPANIC("mac_shm_init stub"); } +void mac_shm_setlabel(void) { DOPANIC("mac_shm_setlabel stub"); } diff -rNu linux-2.4.7/linux/fs/xfs/xfs.h linux-2.4-xfs/linux/fs/xfs/xfs.h --- linux-2.4.7/linux/fs/xfs/xfs.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs.h Wed Apr 25 00:02:25 2001 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_H__ +#define __XFS_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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#endif /* __XFS_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_acl.c linux-2.4-xfs/linux/fs/xfs/xfs_acl.c --- linux-2.4.7/linux/fs/xfs/xfs_acl.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_acl.c Tue Apr 17 00:16:51 2001 @@ -0,0 +1,828 @@ +/* + * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#define ACL_ACCESS 0 +#define ACL_DEFAULT 1 + +STATIC int xfs_acl_setmode(vnode_t *, struct acl *); +STATIC void xfs_acl_filter_mode(mode_t, struct acl *); +STATIC void xfs_acl_get_endian(struct acl *); +STATIC int xfs_acl_access(uid_t, gid_t, struct acl *, mode_t, cred_t *); +STATIC int xfs_acl_invalid (struct acl *aclp); +STATIC void xfs_acl_sync_mode(mode_t mode, struct acl *acl); + +int +xfs_acl_iaccess( xfs_inode_t *ip, mode_t mode, cred_t *cr ) +{ + struct acl acl; + + /* + * If the file has no ACL return -1. + */ + if (xfs_attr_fetch(ip, SGI_ACL_FILE, (char *)&acl, sizeof(struct acl))) + return -1; + xfs_acl_get_endian(&acl); + + /* + * If the file has an empty ACL return -1. + */ + if (acl.acl_cnt == ACL_NOT_PRESENT) + return -1; + + /* + * Synchronize ACL with mode bits + */ + xfs_acl_sync_mode(ip->i_d.di_mode, &acl); + + return xfs_acl_access(ip->i_d.di_uid, ip->i_d.di_gid, &acl, mode, cr); +} + +/* + * The access control process to determine the access permission: + * if uid == file owner id, use the file owner bits. + * if gid == file owner group id, use the file group bits. + * scan ACL for a maching user or group, and use matched entry + * permission. Use total permissions of all matching group entries, + * until all acl entries are exhausted. The final permission produced + * by matching acl entry or entries needs to be & with group permission. + * if not owner, owning group, or matching entry in ACL, use file + * other bits. + */ +STATIC int +xfs_acl_capability_check(mode_t mode, cred_t *cr) +{ + if ((mode & ACL_READ) && !capable_cred(cr, CAP_DAC_READ_SEARCH)) { + return EACCES; + } + if ((mode & ACL_WRITE) && !capable_cred(cr, CAP_DAC_OVERRIDE)) { + return EACCES; + } + if ((mode & ACL_EXECUTE) && !capable_cred(cr, CAP_DAC_OVERRIDE)) { + return EACCES; + } + return 0; +} + +/* + * Note: cr is only used here for the capability check if the ACL test fails. + * It is not used to find out the credentials uid or groups etc, + * as was done in IRIX. It is assumed that the uid and groups for the current + * thread are taken from "current" instead of the cr parameter. + */ + +STATIC int +xfs_acl_access(uid_t fuid, gid_t fgid, struct acl *fap, mode_t md, cred_t *cr) +{ + int i; + struct acl_entry matched; + int maskallows = -1; /* true, but not 1, either */ + int allows; + int seen_userobj = 0; + + /* + * Invalid type + */ + matched.ae_tag = 0; + /* + * Normalize the bits for comparison + */ + md >>= 6; + + for (i = 0; i < fap->acl_cnt; i++) { + /* + * Break out if we've got a user_obj entry or + * a user entry and the mask (and have processed USER_OBJ) + */ + if (matched.ae_tag == ACL_USER_OBJ) + break; + if (matched.ae_tag == ACL_USER) { + if (maskallows != -1 && seen_userobj) + break; + if (fap->acl_entry[i].ae_tag != ACL_MASK && + fap->acl_entry[i].ae_tag != ACL_USER_OBJ) + continue; + } + /* + * True iff this entry allows the requested access + */ + allows = ((fap->acl_entry[i].ae_perm & md) == md); + + switch (fap->acl_entry[i].ae_tag) { + case ACL_USER_OBJ: + seen_userobj = 1; + if (fuid != current->fsuid) + continue; + matched.ae_tag = ACL_USER_OBJ; + matched.ae_perm = allows; + break; + case ACL_USER: + if (fap->acl_entry[i].ae_id != current->fsuid) + continue; + matched.ae_tag = ACL_USER; + matched.ae_perm = allows; + break; + case ACL_GROUP_OBJ: + if ((matched.ae_tag == ACL_GROUP_OBJ || + matched.ae_tag == ACL_GROUP) && !allows) + continue; + if (!in_group_p(fgid)) + continue; + matched.ae_tag = ACL_GROUP_OBJ; + matched.ae_perm = allows; + break; + case ACL_GROUP: + if ((matched.ae_tag == ACL_GROUP_OBJ || + matched.ae_tag == ACL_GROUP) && !allows) + continue; + if (!in_group_p(fap->acl_entry[i].ae_id)) + continue; + matched.ae_tag = ACL_GROUP; + matched.ae_perm = allows; + break; + case ACL_MASK: + maskallows = allows; + break; + case ACL_OTHER_OBJ: + if (matched.ae_tag != 0) + continue; + matched.ae_tag = ACL_OTHER_OBJ; + matched.ae_perm = allows; + break; + } + } + /* + * First possibility is that no matched entry allows access. + * The capability to override DAC may exist, so check for it. + */ + switch (matched.ae_tag) { + case ACL_OTHER_OBJ: + case ACL_USER_OBJ: + if (matched.ae_perm) + return 0; + break; + case ACL_USER: + case ACL_GROUP_OBJ: + case ACL_GROUP: + if (maskallows && matched.ae_perm) + return 0; + break; + case 0: + break; + } + return xfs_acl_capability_check(md, cr); +} + +/* + * ACL validity checker. + * xfs_acl_invalid(struct acl *aclp) + * This acl validation routine does the check of each acl entry read + * from disk makes sense. + */ + +STATIC int +xfs_acl_invalid (struct acl *aclp) +{ + struct acl_entry *entry, *e; + int user = 0, group = 0, other = 0, mask = 0, mask_required = 0; + int i, j; + + + + if (aclp == NULL) + goto acl_invalid; + + if (aclp->acl_cnt > ACL_MAX_ENTRIES) + goto acl_invalid; + + for (i = 0; i < aclp->acl_cnt; i++) + { + + entry = &aclp->acl_entry[i]; + + switch (entry->ae_tag) + { + case ACL_USER_OBJ: + if (user++) + goto acl_invalid; + break; + case ACL_GROUP_OBJ: + if (group++) + goto acl_invalid; + break; + case ACL_OTHER_OBJ: + if (other++) + goto acl_invalid; + break; + case ACL_USER: + case ACL_GROUP: + for (j = i + 1; j < aclp->acl_cnt; j++) + { + e = &aclp->acl_entry[j]; + if (e->ae_id == entry->ae_id && e->ae_tag == entry->ae_tag) + goto acl_invalid; + } + mask_required++; + break; + case ACL_MASK: + if (mask++) + goto acl_invalid; + break; + default: + goto acl_invalid; + } + } + if (!user || !group || !other || (mask_required && !mask)) + goto acl_invalid; + else + return 0; +acl_invalid: + return EINVAL; +} + + +/* + * Do ACL endian conversion. + * Needed for VOP_ATTR_GET and xfs_attr_fetch on ACL attr. + */ +STATIC void +xfs_acl_get_endian(struct acl *aclp) +{ + struct acl_entry *ace, *end; + + /* do the endian conversion */ + INT_SET(aclp->acl_cnt, ARCH_CONVERT, aclp->acl_cnt); + + /* loop thru ACEs of ACL */ + end = &aclp->acl_entry[0]+aclp->acl_cnt; + for (ace=&aclp->acl_entry[0]; ace < end; ace++) { + INT_SET(ace->ae_tag, ARCH_CONVERT, ace->ae_tag); + INT_SET(ace->ae_id, ARCH_CONVERT, ace->ae_id); + INT_SET(ace->ae_perm, ARCH_CONVERT, ace->ae_perm); + } +} + +/* + * Get the ACL from the EA and do endian conversion. + */ +STATIC void +xfs_acl_get_attr(vnode_t *vp, struct acl *aclp, int kind, int *error) +{ + int len = sizeof(struct acl); + + VOP_ATTR_GET(vp, kind==ACL_ACCESS ? SGI_ACL_FILE: SGI_ACL_DEFAULT, + (char *) aclp, &len, ATTR_ROOT, sys_cred, *error); + if (*error) + return; + + xfs_acl_get_endian(aclp); +} + +/* + * Set the EA with the ACL and do endian conversion. + */ +STATIC void +xfs_acl_set_attr(vnode_t *vp, struct acl *aclp, int kind, int *error) +{ + struct acl_entry *ace, *newace, *end; + struct acl newacl; + int len = sizeof(struct acl); + + /* do the endian conversion */ + /* loop thru ACEs of ACL */ + end = &aclp->acl_entry[0]+aclp->acl_cnt; + for (ace=&aclp->acl_entry[0],newace=&newacl.acl_entry[0]; ace < end; + ace++,newace++) { + INT_SET(newace->ae_tag, ARCH_CONVERT, ace->ae_tag); + INT_SET(newace->ae_id, ARCH_CONVERT, ace->ae_id); + INT_SET(newace->ae_perm, ARCH_CONVERT, ace->ae_perm); + } + + INT_SET(newacl.acl_cnt, ARCH_CONVERT, aclp->acl_cnt); + + VOP_ATTR_SET(vp, kind==ACL_ACCESS ? SGI_ACL_FILE: SGI_ACL_DEFAULT, + (char *)&newacl, len, ATTR_ROOT, sys_cred, *error); +} + +STATIC int +xfs_acl_vtoacl(vnode_t *vp, struct acl *access_acl, struct acl *default_acl) +{ + int error = 0; + vattr_t va; + + if (access_acl != NULL) { + /* + * Get the Access ACL and the mode. If either cannot + * be obtained for some reason, invalidate the access ACL. + */ + xfs_acl_get_attr(vp, access_acl, ACL_ACCESS, &error); + + if (!error) { + /* + * Got the ACL, need the mode... + */ + va.va_mask = AT_MODE; + VOP_GETATTR(vp, &va, 0, sys_cred, error); + } + + if (error) { + access_acl->acl_cnt = ACL_NOT_PRESENT; + } else { + /* + * We have a good ACL and the file mode, + * synchronize them... + */ + xfs_acl_sync_mode(va.va_mode, access_acl); + } + } + + if (default_acl != NULL) { + xfs_acl_get_attr(vp, default_acl, ACL_DEFAULT, &error); + if (error) + default_acl->acl_cnt = ACL_NOT_PRESENT; + } + return error; +} + + +/* + * This function retrieves the parent directory's acl, processes it + * and lets the child inherit the acl(s) that it should. + */ + +int +xfs_acl_inherit(vnode_t *vp, vattr_t *vap, struct acl *pdaclp) +{ + struct acl cacl; + int error = 0; + + /* + * If the parent does not have a default ACL, or it's an + * invalid ACL, we're done. + */ + if (vp == NULL) + return (0); + if (pdaclp == NULL || xfs_acl_invalid(pdaclp)) + return (0); + + /* + * Copy the default ACL of the containing directory to + * the access ACL of the new file and use the mode that + * was passed in to set up the correct initial values for + * the u::,g::[m::], and o:: entries. This is what makes + * umask() "work" with ACL's. + */ + memcpy(&cacl, pdaclp, sizeof(cacl)); + xfs_acl_filter_mode(vap->va_mode, &cacl); + + /* set the mode to the acl */ + xfs_acl_setmode(vp, &cacl); + + /* + * Set the default and access acl on the file. The mode is already + * set on the file, so we don't need to worry about that. + * + * If the new file is a directory, its default ACL is a copy of + * the containing directory's default ACL. + * + */ + if (vp->v_type == VDIR) { + xfs_acl_set_attr(vp, pdaclp, ACL_DEFAULT, &error); + } + if (!error) { + xfs_acl_set_attr(vp, &cacl, ACL_ACCESS, &error); + } + + return (error); +} + + +STATIC int +xfs_acl_vget(vnode_t *vp, int kind, struct acl *acl) +{ + struct acl kacl; + int size = sizeof(kacl); + int error = 0; + vattr_t va; + +#ifdef SERIOUS_DEBUG + cmn_err(CE_NOTE, "xfs_acl_vget 0x%x %s 0x%x", vp, (kind == ACL_ACCESS) ? "ACCESS_ACL" : "DEFAULT_ACL", acl); +#endif /* SERIOUS_DEBUG */ + + /* + * Get the ACL if there is one... + */ + memset(&kacl, 0, size); /* Make sure we don't copyout random stack */ + xfs_acl_get_attr(vp, &kacl, kind, &error); + + if (!error && xfs_acl_invalid(&kacl)) { +#ifdef SERIOUS_DEBUG + cmn_err(CE_WARN, "Invalid acl fetched"); +#endif /* SERIOUS_DEBUG */ + error = EINVAL; + } + + if (!error && (kind == ACL_ACCESS)) { + /* + * For Access ACLs, get the mode for synchronization. + */ + va.va_mask = AT_MODE; + VOP_GETATTR(vp, &va, 0, sys_cred, error); + } + + /* + * If there was an error retrieving or validating the ACL or + * an Access ACL and we had trouble synchronizing the mode with the + * ACL, then the ACL is deemed NOT PRESENT. + */ + if (error) { + kacl.acl_cnt = ACL_NOT_PRESENT; + } else if (kind == ACL_ACCESS) { + /* + * Synchronize an Access ACL with the mode before + * copying it out. + */ + xfs_acl_sync_mode(va.va_mode, &kacl); + } + + + /* + * If the whole problem was that the requested ACL does not exist, then + * there is no problem. Just copy out a NOT PRESENT ACL. Otherwise, + * don't do the copyout (an error should leave user level data + * unchanged). + */ + if (error == ENOATTR) + error = 0; + + if (!error && copyout((caddr_t)&kacl, (caddr_t)acl, + sizeof(struct acl))) { + error = EFAULT; + } + return (error); +} + +int +xfs_acl_get(vnode_t *vp, struct acl *acl, struct acl *dacl) +{ + int error; + int derror = 0; + + if (!acl && !dacl) + return (EINVAL); + + VN_HOLD(vp); + + error = _MAC_VACCESS(vp, get_current_cred(), VREAD); + + if (!error) { + if (acl) + error = xfs_acl_vget(vp, ACL_ACCESS, acl); + if (dacl) + derror = xfs_acl_vget(vp, ACL_DEFAULT, dacl); + } + + VN_RELE(vp); + + /* + * It's not likely that this will happen. + */ + if (!error && derror) + error = derror; + + return (error); +} + +STATIC int +xfs_acl_vset(vnode_t *vp, struct acl *acl) +{ + int error; + +#ifdef NOISE + cmn_err(CE_NOTE, "xfs_acl_vset 0x%x 0x%x", vp, acl); +#endif /* NOISE */ + + /* + * Check for an ACL deletion (the caller specifies a + * NOT PRESENT ACL). + */ + if (acl->acl_cnt == ACL_NOT_PRESENT) { + /* + * Deletion, remove the ACL if there is one. + */ + VOP_ATTR_REMOVE(vp, SGI_ACL_FILE, ATTR_ROOT, sys_cred, error); + if (error == ENOATTR) { + /* There was no Access ACL to delete, no big deal. */ + error = 0; + } + return(error); + } + + /* + * The incoming ACL exists, so set the file mode based on + * the incoming ACL. + */ + xfs_acl_setmode(vp, acl); + + /* + * Now set the ACL. + */ + xfs_acl_set_attr(vp, acl, ACL_ACCESS, &error); + return error; +} + +STATIC int +xfs_dacl_vset(vnode_t *vp, struct acl *dacl) +{ + int error = 0; + + if (dacl->acl_cnt != ACL_NOT_PRESENT) { + /* Apply the default ACL to the file */ + xfs_acl_set_attr(vp, dacl, ACL_DEFAULT, &error); + } else { + /* + * Delete the ACL on the file. If none is there, ignore the + * error. Report other errors to the caller. + */ + VOP_ATTR_REMOVE(vp, SGI_ACL_DEFAULT, ATTR_ROOT, sys_cred, + error); + if (error == ENOATTR) { + /* There was no default ACL to delete, no big deal. */ + error = 0; + } + } + return(error); +} + +/* + * Set the ACLs on a file system object. Either or both the Access or + * Default ACL may be set using this function. If the 'acl' pointer is + * non-NULL the Access ACL is set, if the 'dacl' pointer is non-NULL the + * Default ACL is set. + */ +int +xfs_acl_set(vnode_t *vp, struct acl *acl, struct acl *dacl) +{ + struct acl kacl; + struct acl kdacl; + vattr_t va; + int error; + + if (!acl && !dacl) + return (EINVAL); + if (acl && copy_from_user((caddr_t)&kacl, (caddr_t)acl, + sizeof (struct acl))) + return (EFAULT); + if (dacl && copy_from_user((caddr_t)&kdacl, (caddr_t)dacl, + sizeof (struct acl))) + return (EFAULT); + + VN_HOLD(vp); + + /* + * Only directories may have default acls + * Better not try to update a read-only file system. + */ + if (dacl && vp->v_type != VDIR) + error = ENOTDIR; + else if (vp->v_vfsp->vfs_flag & VFS_RDONLY) + error = EROFS; + else { + error = _MAC_VACCESS(vp, NULL, VWRITE); + if (!error) { + va.va_mask = AT_UID; + VOP_GETATTR(vp, &va, 0, NULL, error); + if (!error && va.va_uid != current->fsuid && + !capable(CAP_FOWNER)) + error = EACCES; + } + if (!error && acl) + /* + * Set the access ACL. + */ + error = xfs_acl_vset(vp, &kacl); + if (!error && dacl) + /* + * Set the default ACL. + */ + error = xfs_dacl_vset(vp, &kdacl); + } + + VN_RELE(vp); + return (error); +} + +/* + * Set up the correct mode on the file based on the supplied ACL. This + * makes sure that the mode on the file reflects the state of the + * u::,g::[m::], and o:: entries in the ACL. Since the mode is where + * the ACL is going to get the permissions for these entries, we must + * synchronize the mode whenever we set the ACL on a file. + */ +STATIC int +xfs_acl_setmode(vnode_t *vp, struct acl *acl) +{ + vattr_t va; + acl_entry_t gap = (acl_entry_t)0; + acl_entry_t ap; + int nomask = 1; + int i; + int error; + + if (acl->acl_cnt == ACL_NOT_PRESENT) { + /* + * Nothing in the ACL, just return no error. + */ + return (0); + } + + /* + * Copy the u::, g::, o::, and m:: bits from the ACL into the + * mode. The m:: bits take precedence over the g:: bits. + */ + va.va_mask = AT_MODE; + VOP_GETATTR(vp, &va, 0, sys_cred, error); + if (error != 0) { + return (error); + } + va.va_mask = AT_MODE; + va.va_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO); + ap = acl->acl_entry; + for (i = 0; i < acl->acl_cnt; ++i) { + switch (ap->ae_tag) { + case ACL_USER_OBJ: + va.va_mode |= ap->ae_perm << 6; + break; + case ACL_GROUP_OBJ: + gap = ap; + break; + case ACL_MASK: + nomask = 0; + va.va_mode |= ap->ae_perm << 3; + break; + case ACL_OTHER_OBJ: + va.va_mode |= ap->ae_perm; + break; + default: + break; + } + ap++; + } + + /* + * Set the group bits from ACL_GROUP_OBJ iff there's no + * ACL_MASK + */ + if (gap && nomask) + va.va_mode |= gap->ae_perm << 3; + + VOP_SETATTR(vp, &va, 0, sys_cred, error); + + return error; +} + +/* + * The permissions for the special ACL entries (u::, g::[m::], o::) are + * actually stored in the file mode (if there is both a group and a mask, + * the group is stored in the ACL entry and the mask is stored on the file). + * This allows the mode to remain automatically in sync with the ACL without + * the need for a call-back to the ACL system at every point where the mode + * could change. This function takes the permissions from the specified mode + * and places it in the supplied ACL. + * + * This implementation draws its validity from the fact that, when the + * ACL was assigned, the mode was copied from the ACL (see xfs_acl_vset() + * and xfs_acl_setmode()). If the mode did not change, therefore, the mode + * remains exactly what was taken from the special ACL entries at + * assignment. If a subsequent chmod() was done, the POSIX spec says + * that the change in mode must cause an update to the ACL seen at user + * level and used for access checks. Before and after a mode change, + * therefore, the file mode most accurately reflects what the special + * ACL entries should permit / deny. + * + * CAVEAT: If someone sets the SGI_ACL_FILE attribute directly, + * the existing mode bits will override whatever is in the + * ACL. Similarly, if there is a pre-existing ACL that was + * never in sync with its mode (owing to a bug in 6.5 and + * before), it will now magically (or mystically) be + * synchronized. This could cause slight astonishment, but + * it is better than inconsistent permissions. + * + * The supplied ACL is a template that may contain any combination + * of special entries. These are treated as place holders when we fill + * out the ACL. This routine does not add or remove special entries, it + * simply unites each special entry with its associated set of permissions. + */ +STATIC void +xfs_acl_sync_mode(mode_t mode, struct acl *acl) +{ + int i; + int nomask = 1; + acl_entry_t ap; + acl_entry_t gap = NULL; + + /* + * Set ACL entries. POSIX1003.1eD16 requires that the MASK + * be set instead of the GROUP entry, if there is a MASK. + */ + for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) { + switch (ap->ae_tag) { + case ACL_USER_OBJ: + ap->ae_perm = (mode >> 6) & 0x7; + break; + case ACL_GROUP_OBJ: + gap = ap; + break; + case ACL_MASK: + nomask = 0; + ap->ae_perm = (mode >> 3) & 0x7; + break; + case ACL_OTHER_OBJ: + ap->ae_perm = mode & 0x7; + break; + default: + break; + } + } + /* + * Set the ACL_GROUP_OBJ if there's no ACL_MASK + */ + if (gap && nomask) + gap->ae_perm = (mode >> 3) & 0x7; +} + +/* + * When inheriting an access acl from a directory default acl, + * the acl bits are set to the intersection of the acl default + * permission bits and the file permission bits in mode. If there + * are no permission bits on the file then we must not give them + * the acl. This is what what makes umask() work with acls. + */ + +STATIC void +xfs_acl_filter_mode(mode_t mode, struct acl *acl) +{ + int i; + int nomask = 1; + acl_entry_t ap; + acl_entry_t gap = NULL; + + /* + * Set ACL entries. POSIX1003.1eD16 requires that the MASK + * be merged with GROUP entry, if there is a MASK. + */ + for (ap = acl->acl_entry, i = 0; i < acl->acl_cnt; ap++, i++) { + switch (ap->ae_tag) { + case ACL_USER_OBJ: + ap->ae_perm &= (mode >> 6) & 0x7; + break; + case ACL_GROUP_OBJ: + gap = ap; + break; + case ACL_MASK: + nomask = 0; + ap->ae_perm &= (mode >> 3) & 0x7; + break; + case ACL_OTHER_OBJ: + ap->ae_perm &= mode & 0x7; + break; + default: + break; + } + } + /* + * Set the ACL_GROUP_OBJ if there's no ACL_MASK + */ + if (gap && nomask) + gap->ae_perm &= (mode >> 3) & 0x7; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_acl.h linux-2.4-xfs/linux/fs/xfs/xfs_acl.h --- linux-2.4.7/linux/fs/xfs/xfs_acl.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_acl.h Tue Apr 17 00:16:51 2001 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + + +#ifndef __XFS_ACL_H__ +#define __XFS_ACL_H__ + +struct xfs_inode; +struct vattr; +struct vnode; + +extern int xfs_acl_inherit(struct vnode *, struct vattr *, struct acl *); +extern int xfs_acl_iaccess(struct xfs_inode *, mode_t, cred_t *); +extern int xfs_acl_get(struct vnode *, struct acl *, struct acl *); +extern int xfs_acl_set(struct vnode *, struct acl *, struct acl *); +extern int xfs_acl_vtoacl(vnode_t *, struct acl *, struct acl *); + +#ifdef CONFIG_FS_POSIX_ACL +#define _ACL_INHERIT(c,v,d) (xfs_acl_inherit(c,v,d)) +#define _ACL_GET_DEFAULT(pv,pd) (xfs_acl_vtoacl(pv,NULL,pd)==0) +#define _ACL_XFS_IACCESS(a,b,c) (xfs_acl_iaccess(a,b,c)) +#else +#define _ACL_INHERIT(c,v,d) (0) +#define _ACL_GET_DEFAULT(pv,pd) (0) +#define _ACL_XFS_IACCESS(a,b,c) (-1) +#endif + +#endif /* __XFS_ACL_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_ag.h linux-2.4-xfs/linux/fs/xfs/xfs_ag.h --- linux-2.4.7/linux/fs/xfs/xfs_ag.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_ag.h Mon May 14 10:27:31 2001 @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_AG_H__ +#define __XFS_AG_H__ + +/* + * Allocation group header + * This is divided into three structures, placed in sequential 512-byte + * buffers after a copy of the superblock (also in a 512-byte buffer). + */ + +struct xfs_buf; +struct xfs_mount; + +#define XFS_AGF_MAGIC 0x58414746 /* 'XAGF' */ +#define XFS_AGI_MAGIC 0x58414749 /* 'XAGI' */ +#define XFS_AGF_VERSION 1 +#define XFS_AGI_VERSION 1 +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGF_GOOD_VERSION) +int xfs_agf_good_version(unsigned v); +#define XFS_AGF_GOOD_VERSION(v) xfs_agf_good_version(v) +#else +#define XFS_AGF_GOOD_VERSION(v) ((v) == XFS_AGF_VERSION) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGI_GOOD_VERSION) +int xfs_agi_good_version(unsigned v); +#define XFS_AGI_GOOD_VERSION(v) xfs_agi_good_version(v) +#else +#define XFS_AGI_GOOD_VERSION(v) ((v) == XFS_AGI_VERSION) +#endif + +/* + * Btree number 0 is bno, 1 is cnt. This value gives the size of the + * arrays below. + */ +#define XFS_BTNUM_AGF ((int)XFS_BTNUM_CNTi + 1) + +/* + * The second word of agf_levels in the first a.g. overlaps the EFS + * superblock's magic number. Since the magic numbers valid for EFS + * are > 64k, our value cannot be confused for an EFS superblock's. + */ + +typedef struct xfs_agf +{ + /* + * Common allocation group header information + */ + __uint32_t agf_magicnum; /* magic number == XFS_AGF_MAGIC */ + __uint32_t agf_versionnum; /* header version == XFS_AGF_VERSION */ + xfs_agnumber_t agf_seqno; /* sequence # starting from 0 */ + xfs_agblock_t agf_length; /* size in blocks of a.g. */ + /* + * Freespace information + */ + xfs_agblock_t agf_roots[XFS_BTNUM_AGF]; /* root blocks */ + __uint32_t agf_spare0; /* spare field */ + __uint32_t agf_levels[XFS_BTNUM_AGF]; /* btree levels */ + __uint32_t agf_spare1; /* spare field */ + __uint32_t agf_flfirst; /* first freelist block's index */ + __uint32_t agf_fllast; /* last freelist block's index */ + __uint32_t agf_flcount; /* count of blocks in freelist */ + xfs_extlen_t agf_freeblks; /* total free blocks */ + xfs_extlen_t agf_longest; /* longest free space */ +} xfs_agf_t; + +#define XFS_AGF_MAGICNUM 0x00000001 +#define XFS_AGF_VERSIONNUM 0x00000002 +#define XFS_AGF_SEQNO 0x00000004 +#define XFS_AGF_LENGTH 0x00000008 +#define XFS_AGF_ROOTS 0x00000010 +#define XFS_AGF_LEVELS 0x00000020 +#define XFS_AGF_FLFIRST 0x00000040 +#define XFS_AGF_FLLAST 0x00000080 +#define XFS_AGF_FLCOUNT 0x00000100 +#define XFS_AGF_FREEBLKS 0x00000200 +#define XFS_AGF_LONGEST 0x00000400 +#define XFS_AGF_NUM_BITS 11 +#define XFS_AGF_ALL_BITS ((1 << XFS_AGF_NUM_BITS) - 1) + +/* disk block (xfs_daddr_t) in the AG */ +#define XFS_AGF_DADDR ((xfs_daddr_t)1) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGF_BLOCK) +xfs_agblock_t xfs_agf_block(struct xfs_mount *mp); +#define XFS_AGF_BLOCK(mp) xfs_agf_block(mp) +#else +#define XFS_AGF_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGF_DADDR) +#endif + +/* + * Size of the unlinked inode hash table in the agi. + */ +#define XFS_AGI_UNLINKED_BUCKETS 64 + +typedef struct xfs_agi +{ + /* + * Common allocation group header information + */ + __uint32_t agi_magicnum; /* magic number == XFS_AGI_MAGIC */ + __uint32_t agi_versionnum; /* header version == XFS_AGI_VERSION */ + xfs_agnumber_t agi_seqno; /* sequence # starting from 0 */ + xfs_agblock_t agi_length; /* size in blocks of a.g. */ + /* + * Inode information + * Inodes are mapped by interpreting the inode number, so no + * mapping data is needed here. + */ + xfs_agino_t agi_count; /* count of allocated inodes */ + xfs_agblock_t agi_root; /* root of inode btree */ + __uint32_t agi_level; /* levels in inode btree */ + xfs_agino_t agi_freecount; /* number of free inodes */ + xfs_agino_t agi_newino; /* new inode just allocated */ + xfs_agino_t agi_dirino; /* last directory inode chunk */ + /* + * Hash table of inodes which have been unlinked but are + * still being referenced. + */ + xfs_agino_t agi_unlinked[XFS_AGI_UNLINKED_BUCKETS]; +} xfs_agi_t; + +#define XFS_AGI_MAGICNUM 0x00000001 +#define XFS_AGI_VERSIONNUM 0x00000002 +#define XFS_AGI_SEQNO 0x00000004 +#define XFS_AGI_LENGTH 0x00000008 +#define XFS_AGI_COUNT 0x00000010 +#define XFS_AGI_ROOT 0x00000020 +#define XFS_AGI_LEVEL 0x00000040 +#define XFS_AGI_FREECOUNT 0x00000080 +#define XFS_AGI_NEWINO 0x00000100 +#define XFS_AGI_DIRINO 0x00000200 +#define XFS_AGI_UNLINKED 0x00000400 +#define XFS_AGI_NUM_BITS 11 +#define XFS_AGI_ALL_BITS ((1 << XFS_AGI_NUM_BITS) - 1) + +/* disk block (xfs_daddr_t) in the AG */ +#define XFS_AGI_DADDR ((xfs_daddr_t)2) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGI_BLOCK) +xfs_agblock_t xfs_agi_block(struct xfs_mount *mp); +#define XFS_AGI_BLOCK(mp) xfs_agi_block(mp) +#else +#define XFS_AGI_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGI_DADDR) +#endif + +/* + * The third a.g. block contains the a.g. freelist, an array + * of block pointers to blocks owned by the allocation btree code. + */ +#define XFS_AGFL_DADDR ((xfs_daddr_t)3) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGFL_BLOCK) +xfs_agblock_t xfs_agfl_block(struct xfs_mount *mp); +#define XFS_AGFL_BLOCK(mp) xfs_agfl_block(mp) +#else +#define XFS_AGFL_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGFL_DADDR) +#endif +#define XFS_AGFL_SIZE (BBSIZE / sizeof(xfs_agblock_t)) +typedef struct xfs_agfl +{ + xfs_agblock_t agfl_bno[XFS_AGFL_SIZE]; +} xfs_agfl_t; + +/* + * Per-ag incore structure, copies of information in agf and agi, + * to improve the performance of allocation group selection. + */ +typedef struct xfs_perag +{ + char pagf_init; /* this agf's entry is initialized */ + char pagi_init; /* this agi's entry is initialized */ + __uint8_t pagf_levels[XFS_BTNUM_AGF]; + /* # of levels in bno & cnt btree */ + __uint32_t pagf_flcount; /* count of blocks in freelist */ + xfs_extlen_t pagf_freeblks; /* total free blocks */ + xfs_extlen_t pagf_longest; /* longest free space */ + xfs_agino_t pagi_freecount; /* number of free inodes */ +} xfs_perag_t; + +#define XFS_AG_MIN_BYTES (1LL << 24) /* 16 MB */ +#define XFS_AG_BEST_BYTES (1LL << 30) /* 1 GB */ +#define XFS_AG_MAX_BYTES (1LL << 32) /* 4 GB */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_MIN_BLOCKS) +xfs_extlen_t xfs_ag_min_blocks(int bl); +#define XFS_AG_MIN_BLOCKS(bl) xfs_ag_min_blocks(bl) +#else +#define XFS_AG_MIN_BLOCKS(bl) ((xfs_extlen_t)(XFS_AG_MIN_BYTES >> bl)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_BEST_BLOCKS) +xfs_extlen_t xfs_ag_best_blocks(int bl, xfs_drfsbno_t blks); +#define XFS_AG_BEST_BLOCKS(bl,blks) xfs_ag_best_blocks(bl,blks) +#else +/*--#define XFS_AG_BEST_BLOCKS(bl) ((xfs_extlen_t)(XFS_AG_BEST_BYTES >> bl))*/ +/* + * Best is XFS_AG_BEST_BLOCKS at and below 64 Gigabyte filesystems, and + * XFS_AG_MAX_BLOCKS above 64 Gigabytes. + */ +#define XFS_AG_BEST_BLOCKS(bl,blks) ((xfs_extlen_t)((1LL << (36 - bl)) >= \ + blks) ? \ + ((xfs_extlen_t)(XFS_AG_BEST_BYTES >> bl)) : \ + XFS_AG_MAX_BLOCKS(bl)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_MAX_BLOCKS) +xfs_extlen_t xfs_ag_max_blocks(int bl); +#define XFS_AG_MAX_BLOCKS(bl) xfs_ag_max_blocks(bl) +#else +#define XFS_AG_MAX_BLOCKS(bl) ((xfs_extlen_t)(XFS_AG_MAX_BYTES >> bl)) +#endif + +#define XFS_MAX_AGNUMBER ((xfs_agnumber_t)(NULLAGNUMBER - 1)) + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_MAXLEVELS) +int xfs_ag_maxlevels(struct xfs_mount *mp); +#define XFS_AG_MAXLEVELS(mp) xfs_ag_maxlevels(mp) +#else +#define XFS_AG_MAXLEVELS(mp) ((mp)->m_ag_maxlevels) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MIN_FREELIST) +int xfs_min_freelist(xfs_agf_t *a, struct xfs_mount *mp); +#define XFS_MIN_FREELIST(a,mp) xfs_min_freelist(a,mp) +#else +#define XFS_MIN_FREELIST(a,mp) \ + XFS_MIN_FREELIST_RAW( \ + INT_GET((a)->agf_levels[XFS_BTNUM_BNOi], ARCH_CONVERT), \ + INT_GET((a)->agf_levels[XFS_BTNUM_CNTi], ARCH_CONVERT), mp) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MIN_FREELIST_PAG) +int xfs_min_freelist_pag(xfs_perag_t *pag, struct xfs_mount *mp); +#define XFS_MIN_FREELIST_PAG(pag,mp) xfs_min_freelist_pag(pag,mp) +#else +#define XFS_MIN_FREELIST_PAG(pag,mp) \ + XFS_MIN_FREELIST_RAW((pag)->pagf_levels[XFS_BTNUM_BNOi], \ + (pag)->pagf_levels[XFS_BTNUM_CNTi], mp) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MIN_FREELIST_RAW) +int xfs_min_freelist_raw(int bl, int cl, struct xfs_mount *mp); +#define XFS_MIN_FREELIST_RAW(bl,cl,mp) xfs_min_freelist_raw(bl,cl,mp) +#else +#define XFS_MIN_FREELIST_RAW(bl,cl,mp) \ + (MIN(bl + 1, XFS_AG_MAXLEVELS(mp)) + \ + MIN(cl + 1, XFS_AG_MAXLEVELS(mp))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGB_TO_FSB) +xfs_fsblock_t xfs_agb_to_fsb(struct xfs_mount *mp, xfs_agnumber_t agno, + xfs_agblock_t agbno); +#define XFS_AGB_TO_FSB(mp,agno,agbno) xfs_agb_to_fsb(mp,agno,agbno) +#else +#define XFS_AGB_TO_FSB(mp,agno,agbno) \ + (((xfs_fsblock_t)(agno) << (mp)->m_sb.sb_agblklog) | (agbno)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_TO_AGNO) +xfs_agnumber_t xfs_fsb_to_agno(struct xfs_mount *mp, xfs_fsblock_t fsbno); +#define XFS_FSB_TO_AGNO(mp,fsbno) xfs_fsb_to_agno(mp,fsbno) +#else +#define XFS_FSB_TO_AGNO(mp,fsbno) \ + ((xfs_agnumber_t)((fsbno) >> (mp)->m_sb.sb_agblklog)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_TO_AGBNO) +xfs_agblock_t xfs_fsb_to_agbno(struct xfs_mount *mp, xfs_fsblock_t fsbno); +#define XFS_FSB_TO_AGBNO(mp,fsbno) xfs_fsb_to_agbno(mp,fsbno) +#else +#define XFS_FSB_TO_AGBNO(mp,fsbno) \ + ((xfs_agblock_t)((fsbno) & XFS_MASK32LO((mp)->m_sb.sb_agblklog))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGB_TO_DADDR) +xfs_daddr_t xfs_agb_to_daddr(struct xfs_mount *mp, xfs_agnumber_t agno, + xfs_agblock_t agbno); +#define XFS_AGB_TO_DADDR(mp,agno,agbno) xfs_agb_to_daddr(mp,agno,agbno) +#else +#define XFS_AGB_TO_DADDR(mp,agno,agbno) \ + ((xfs_daddr_t)(XFS_FSB_TO_BB(mp, \ + (xfs_fsblock_t)(agno) * (mp)->m_sb.sb_agblocks + (agbno)))) +#endif +/* + * XFS_DADDR_TO_AGNO and XFS_DADDR_TO_AGBNO moved to xfs_mount.h + * to avoid header file ordering change + */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_DADDR) +xfs_daddr_t xfs_ag_daddr(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_daddr_t d); +#define XFS_AG_DADDR(mp,agno,d) xfs_ag_daddr(mp,agno,d) +#else +#define XFS_AG_DADDR(mp,agno,d) (XFS_AGB_TO_DADDR(mp, agno, 0) + (d)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_AGF) +xfs_agf_t *xfs_buf_to_agf(struct xfs_buf *bp); +#define XFS_BUF_TO_AGF(bp) xfs_buf_to_agf(bp) +#else +#define XFS_BUF_TO_AGF(bp) ((xfs_agf_t *)XFS_BUF_PTR(bp)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_AGI) +xfs_agi_t *xfs_buf_to_agi(struct xfs_buf *bp); +#define XFS_BUF_TO_AGI(bp) xfs_buf_to_agi(bp) +#else +#define XFS_BUF_TO_AGI(bp) ((xfs_agi_t *)XFS_BUF_PTR(bp)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_AGFL) +xfs_agfl_t *xfs_buf_to_agfl(struct xfs_buf *bp); +#define XFS_BUF_TO_AGFL(bp) xfs_buf_to_agfl(bp) +#else +#define XFS_BUF_TO_AGFL(bp) ((xfs_agfl_t *)XFS_BUF_PTR(bp)) +#endif + +/* + * For checking for bad ranges of xfs_daddr_t's, covering multiple + * allocation groups or a single xfs_daddr_t that's a superblock copy. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AG_CHECK_DADDR) +void xfs_ag_check_daddr(struct xfs_mount *mp, xfs_daddr_t d, xfs_extlen_t len); +#define XFS_AG_CHECK_DADDR(mp,d,len) xfs_ag_check_daddr(mp,d,len) +#else +#define XFS_AG_CHECK_DADDR(mp,d,len) \ + ((len) == 1 ? \ + ASSERT((d) == XFS_SB_DADDR || \ + XFS_DADDR_TO_AGBNO(mp, d) != XFS_SB_DADDR) : \ + ASSERT(XFS_DADDR_TO_AGNO(mp, d) == \ + XFS_DADDR_TO_AGNO(mp, (d) + (len) - 1))) +#endif + +#endif /* __XFS_AG_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_alloc.c linux-2.4-xfs/linux/fs/xfs/xfs_alloc.c --- linux-2.4.7/linux/fs/xfs/xfs_alloc.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_alloc.c Wed Apr 18 21:37:23 2001 @@ -0,0 +1,2388 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Free space allocation for XFS. + */ +#include + +#if defined(DEBUG) +/* + * Allocation tracing. + */ +ktrace_t *xfs_alloc_trace_buf; +#endif + +#define XFS_ABSDIFF(a,b) (((a) <= (b)) ? ((b) - (a)) : ((a) - (b))) + +#define XFSA_FIXUP_BNO_OK 1 +#define XFSA_FIXUP_CNT_OK 2 + +#if defined(XFS_ALLOC_TRACE) +#define TRACE_ALLOC(s,a) \ + xfs_alloc_trace_alloc(fname, s, a, __LINE__) +#define TRACE_FREE(s,a,b,x,f) \ + xfs_alloc_trace_free(fname, s, mp, a, b, x, f, __LINE__) +#define TRACE_MODAGF(s,a,f) \ + xfs_alloc_trace_modagf(fname, s, mp, a, f, __LINE__) +#else +#define TRACE_ALLOC(s,a) +#define TRACE_FREE(s,a,b,x,f) +#define TRACE_MODAGF(s,a,f) +#endif /* XFS_ALLOC_TRACE */ + +/* + * Prototypes for per-ag allocation routines + */ + +STATIC int xfs_alloc_ag_vextent_exact(xfs_alloc_arg_t *); +STATIC int xfs_alloc_ag_vextent_near(xfs_alloc_arg_t *); +STATIC int xfs_alloc_ag_vextent_size(xfs_alloc_arg_t *); +STATIC int xfs_alloc_ag_vextent_small(xfs_alloc_arg_t *, + xfs_btree_cur_t *, xfs_agblock_t *, xfs_extlen_t *, int *); + +/* + * Internal functions. + */ + +/* + * Compute aligned version of the found extent. + * Takes alignment and min length into account. + */ +STATIC int /* success (>= minlen) */ +xfs_alloc_compute_aligned( + xfs_agblock_t foundbno, /* starting block in found extent */ + xfs_extlen_t foundlen, /* length in found extent */ + xfs_extlen_t alignment, /* alignment for allocation */ + xfs_extlen_t minlen, /* minimum length for allocation */ + xfs_agblock_t *resbno, /* result block number */ + xfs_extlen_t *reslen) /* result length */ +{ + xfs_agblock_t bno; + xfs_extlen_t diff; + xfs_extlen_t len; + + if (alignment > 1 && foundlen >= minlen) { + bno = roundup(foundbno, alignment); + diff = bno - foundbno; + len = diff >= foundlen ? 0 : foundlen - diff; + } else { + bno = foundbno; + len = foundlen; + } + *resbno = bno; + *reslen = len; + return len >= minlen; +} + +/* + * Compute best start block and diff for "near" allocations. + * freelen >= wantlen already checked by caller. + */ +STATIC xfs_extlen_t /* difference value (absolute) */ +xfs_alloc_compute_diff( + xfs_agblock_t wantbno, /* target starting block */ + xfs_extlen_t wantlen, /* target length */ + xfs_extlen_t alignment, /* target alignment */ + xfs_agblock_t freebno, /* freespace's starting block */ + xfs_extlen_t freelen, /* freespace's length */ + xfs_agblock_t *newbnop) /* result: best start block from free */ +{ + xfs_agblock_t freeend; /* end of freespace extent */ + xfs_agblock_t newbno1; /* return block number */ + xfs_agblock_t newbno2; /* other new block number */ + xfs_extlen_t newlen1=0; /* length with newbno1 */ + xfs_extlen_t newlen2=0; /* length with newbno2 */ + xfs_agblock_t wantend; /* end of target extent */ + + ASSERT(freelen >= wantlen); + freeend = freebno + freelen; + wantend = wantbno + wantlen; + if (freebno >= wantbno) { + if ((newbno1 = roundup(freebno, alignment)) >= freeend) + newbno1 = NULLAGBLOCK; + } else if (freeend >= wantend && alignment > 1) { + newbno1 = roundup(wantbno, alignment); + newbno2 = newbno1 - alignment; + if (newbno1 >= freeend) + newbno1 = NULLAGBLOCK; + else + newlen1 = XFS_EXTLEN_MIN(wantlen, freeend - newbno1); + if (newbno2 < freebno) + newbno2 = NULLAGBLOCK; + else + newlen2 = XFS_EXTLEN_MIN(wantlen, freeend - newbno2); + if (newbno1 != NULLAGBLOCK && newbno2 != NULLAGBLOCK) { + if (newlen1 < newlen2 || + (newlen1 == newlen2 && + XFS_ABSDIFF(newbno1, wantbno) > + XFS_ABSDIFF(newbno2, wantbno))) + newbno1 = newbno2; + } else if (newbno2 != NULLAGBLOCK) + newbno1 = newbno2; + } else if (freeend >= wantend) { + newbno1 = wantbno; + } else if (alignment > 1) { + newbno1 = roundup(freeend - wantlen, alignment); + if (newbno1 > freeend - wantlen && + newbno1 - alignment >= freebno) + newbno1 -= alignment; + else if (newbno1 >= freeend) + newbno1 = NULLAGBLOCK; + } else + newbno1 = freeend - wantlen; + *newbnop = newbno1; + return newbno1 == NULLAGBLOCK ? 0 : XFS_ABSDIFF(newbno1, wantbno); +} + +/* + * Fix up the length, based on mod and prod. + * len should be k * prod + mod for some k. + * If len is too small it is returned unchanged. + * If len hits maxlen it is left alone. + */ +STATIC void +xfs_alloc_fix_len( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_extlen_t k; + xfs_extlen_t rlen; + + ASSERT(args->mod < args->prod); + rlen = args->len; + ASSERT(rlen >= args->minlen); + ASSERT(rlen <= args->maxlen); + if (args->prod <= 1 || rlen < args->mod || rlen == args->maxlen || + (args->mod == 0 && rlen < args->prod)) + return; + k = rlen % args->prod; + if (k == args->mod) + return; + if (k > args->mod) { + if ((int)(rlen = rlen - k - args->mod) < (int)args->minlen) + return; + } else { + if ((int)(rlen = rlen - args->prod - (args->mod - k)) < + (int)args->minlen) + return; + } + ASSERT(rlen >= args->minlen); + ASSERT(rlen <= args->maxlen); + args->len = rlen; +} + +/* + * Fix up length if there is too little space left in the a.g. + * Return 1 if ok, 0 if too little, should give up. + */ +STATIC int +xfs_alloc_fix_minleft( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_agf_t *agf; /* a.g. freelist header */ + int diff; /* free space difference */ + + if (args->minleft == 0) + return 1; + agf = XFS_BUF_TO_AGF(args->agbp); + diff = INT_GET(agf->agf_freeblks, ARCH_CONVERT) + + INT_GET(agf->agf_flcount, ARCH_CONVERT) + - args->len - args->minleft; + if (diff >= 0) + return 1; + args->len += diff; /* shrink the allocated space */ + if (args->len >= args->minlen) + return 1; + args->agbno = NULLAGBLOCK; + return 0; +} + +/* + * Update the two btrees, logically removing from freespace the extent + * starting at rbno, rlen blocks. The extent is contained within the + * actual (current) free extent fbno for flen blocks. + * Flags are passed in indicating whether the cursors are set to the + * relevant records. + */ +STATIC int /* error code */ +xfs_alloc_fixup_trees( + xfs_btree_cur_t *cnt_cur, /* cursor for by-size btree */ + xfs_btree_cur_t *bno_cur, /* cursor for by-block btree */ + xfs_agblock_t fbno, /* starting block of free extent */ + xfs_extlen_t flen, /* length of free extent */ + xfs_agblock_t rbno, /* starting block of returned extent */ + xfs_extlen_t rlen, /* length of returned extent */ + int flags) /* flags, XFSA_FIXUP_... */ +{ + int error; /* error code */ + int i; /* operation results */ + xfs_agblock_t nfbno1; /* first new free startblock */ + xfs_agblock_t nfbno2; /* second new free startblock */ + xfs_extlen_t nflen1=0; /* first new free length */ + xfs_extlen_t nflen2=0; /* second new free length */ + + /* + * Look up the record in the by-size tree if necessary. + */ + if (flags & XFSA_FIXUP_CNT_OK) { +#ifdef DEBUG + if ((error = xfs_alloc_get_rec(cnt_cur, &nfbno1, &nflen1, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN( + i == 1 && nfbno1 == fbno && nflen1 == flen); +#endif + } else { + if ((error = xfs_alloc_lookup_eq(cnt_cur, fbno, flen, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } + /* + * Look up the record in the by-block tree if necessary. + */ + if (flags & XFSA_FIXUP_BNO_OK) { +#ifdef DEBUG + if ((error = xfs_alloc_get_rec(bno_cur, &nfbno1, &nflen1, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN( + i == 1 && nfbno1 == fbno && nflen1 == flen); +#endif + } else { + if ((error = xfs_alloc_lookup_eq(bno_cur, fbno, flen, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } +#ifdef DEBUG + { + xfs_alloc_block_t *bnoblock; + xfs_alloc_block_t *cntblock; + + if (bno_cur->bc_nlevels == 1 && + cnt_cur->bc_nlevels == 1) { + bnoblock = XFS_BUF_TO_ALLOC_BLOCK(bno_cur->bc_bufs[0]); + cntblock = XFS_BUF_TO_ALLOC_BLOCK(cnt_cur->bc_bufs[0]); + XFS_WANT_CORRUPTED_RETURN( + INT_GET(bnoblock->bb_numrecs, ARCH_CONVERT) == INT_GET(cntblock->bb_numrecs, ARCH_CONVERT)); + } + } +#endif + /* + * Deal with all four cases: the allocated record is contained + * within the freespace record, so we can have new freespace + * at either (or both) end, or no freespace remaining. + */ + if (rbno == fbno && rlen == flen) + nfbno1 = nfbno2 = NULLAGBLOCK; + else if (rbno == fbno) { + nfbno1 = rbno + rlen; + nflen1 = flen - rlen; + nfbno2 = NULLAGBLOCK; + } else if (rbno + rlen == fbno + flen) { + nfbno1 = fbno; + nflen1 = flen - rlen; + nfbno2 = NULLAGBLOCK; + } else { + nfbno1 = fbno; + nflen1 = rbno - fbno; + nfbno2 = rbno + rlen; + nflen2 = (fbno + flen) - nfbno2; + } + /* + * Delete the entry from the by-size btree. + */ + if ((error = xfs_alloc_delete(cnt_cur, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + /* + * Add new by-size btree entry(s). + */ + if (nfbno1 != NULLAGBLOCK) { + if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno1, nflen1, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 0); + if ((error = xfs_alloc_insert(cnt_cur, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } + if (nfbno2 != NULLAGBLOCK) { + if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno2, nflen2, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 0); + if ((error = xfs_alloc_insert(cnt_cur, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } + /* + * Fix up the by-block btree entry(s). + */ + if (nfbno1 == NULLAGBLOCK) { + /* + * No remaining freespace, just delete the by-block tree entry. + */ + if ((error = xfs_alloc_delete(bno_cur, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } else { + /* + * Update the by-block entry to start later|be shorter. + */ + if ((error = xfs_alloc_update(bno_cur, nfbno1, nflen1))) + return error; + } + if (nfbno2 != NULLAGBLOCK) { + /* + * 2 resulting free entries, need to add one. + */ + if ((error = xfs_alloc_lookup_eq(bno_cur, nfbno2, nflen2, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 0); + if ((error = xfs_alloc_insert(bno_cur, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + } + return 0; +} + +/* + * Read in the allocation group free block array. + */ +STATIC int /* error */ +xfs_alloc_read_agfl( + xfs_mount_t *mp, /* mount point structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_buf_t **bpp) /* buffer for the ag free block array */ +{ + xfs_buf_t *bp; /* return value */ + xfs_daddr_t d; /* disk block address */ + int error; + + ASSERT(agno != NULLAGNUMBER); + d = XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, 1, 0, &bp))) + return error; + ASSERT(bp); + ASSERT(!XFS_BUF_GETERROR(bp)); + XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGFL, XFS_AGFL_REF); + *bpp = bp; + return 0; +} + +#if defined(XFS_ALLOC_TRACE) +/* + * Add an allocation trace entry for an alloc call. + */ +STATIC void +xfs_alloc_trace_alloc( + char *name, /* function tag string */ + char *str, /* additional string */ + xfs_alloc_arg_t *args, /* allocation argument structure */ + int line) /* source line number */ +{ + ktrace_enter(xfs_alloc_trace_buf, + (void *)(__psint_t)(XFS_ALLOC_KTRACE_ALLOC | (line << 16)), + (void *)name, + (void *)str, + (void *)args->mp, + (void *)(__psunsigned_t)args->agno, + (void *)(__psunsigned_t)args->agbno, + (void *)(__psunsigned_t)args->minlen, + (void *)(__psunsigned_t)args->maxlen, + (void *)(__psunsigned_t)args->mod, + (void *)(__psunsigned_t)args->prod, + (void *)(__psunsigned_t)args->minleft, + (void *)(__psunsigned_t)args->total, + (void *)(__psunsigned_t)args->alignment, + (void *)(__psunsigned_t)args->len, + (void *)((((__psint_t)args->type) << 16) | + (__psint_t)args->otype), + (void *)(__psint_t)((args->wasdel << 3) | + (args->wasfromfl << 2) | + (args->isfl << 1) | + (args->userdata << 0))); +} + +/* + * Add an allocation trace entry for a free call. + */ +STATIC void +xfs_alloc_trace_free( + char *name, /* function tag string */ + char *str, /* additional string */ + xfs_mount_t *mp, /* file system mount point */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* a.g. relative block number */ + xfs_extlen_t len, /* length of extent */ + int isfl, /* set if is freelist allocation/free */ + int line) /* source line number */ +{ + ktrace_enter(xfs_alloc_trace_buf, + (void *)(__psint_t)(XFS_ALLOC_KTRACE_FREE | (line << 16)), + (void *)name, + (void *)str, + (void *)mp, + (void *)(__psunsigned_t)agno, + (void *)(__psunsigned_t)agbno, + (void *)(__psunsigned_t)len, + (void *)(__psint_t)isfl, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); +} + +/* + * Add an allocation trace entry for modifying an agf. + */ +STATIC void +xfs_alloc_trace_modagf( + char *name, /* function tag string */ + char *str, /* additional string */ + xfs_mount_t *mp, /* file system mount point */ + xfs_agf_t *agf, /* new agf value */ + int flags, /* logging flags for agf */ + int line) /* source line number */ +{ + ktrace_enter(xfs_alloc_trace_buf, + (void *)(__psint_t)(XFS_ALLOC_KTRACE_MODAGF | (line << 16)), + (void *)name, + (void *)str, + (void *)mp, + (void *)(__psint_t)flags, + (void *)(__psunsigned_t)INT_GET(agf->agf_seqno, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_length, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_roots[XFS_BTNUM_BNO], + ARCH_CONVERT); + (void *)(__psunsigned_t)INT_GET(agf->agf_roots[XFS_BTNUM_CNT], + ARCH_CONVERT); + (void *)(__psunsigned_t)INT_GET(agf->agf_levels[XFS_BTNUM_BNO], + ARCH_CONVERT); + (void *)(__psunsigned_t)INT_GET(agf->agf_levels[XFS_BTNUM_CNT], + ARCH_CONVERT); + (void *)(__psunsigned_t)INT_GET(agf->agf_flfirst, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_fllast, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_flcount, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_freeblks, ARCH_CONVERT), + (void *)(__psunsigned_t)INT_GET(agf->agf_longest, ARCH_CONVERT)); +} +#endif /* XFS_ALLOC_TRACE */ + +/* + * Allocation group level functions. + */ + +/* + * Allocate a variable extent in the allocation group agno. + * Type and bno are used to determine where in the allocation group the + * extent will start. + * Extent's length (returned in *len) will be between minlen and maxlen, + * and of the form k * prod + mod unless there's nothing that large. + * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. + */ +STATIC int /* error */ +xfs_alloc_ag_vextent( + xfs_alloc_arg_t *args) /* argument structure for allocation */ +{ + int error=0; +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_ag_vextent"; +#endif + + ASSERT(args->minlen > 0); + ASSERT(args->maxlen > 0); + ASSERT(args->minlen <= args->maxlen); + ASSERT(args->mod < args->prod); + ASSERT(args->alignment > 0); + /* + * Branch to correct routine based on the type. + */ + args->wasfromfl = 0; + switch (args->type) { + case XFS_ALLOCTYPE_THIS_AG: + error = xfs_alloc_ag_vextent_size(args); + break; + case XFS_ALLOCTYPE_NEAR_BNO: + error = xfs_alloc_ag_vextent_near(args); + break; + case XFS_ALLOCTYPE_THIS_BNO: + error = xfs_alloc_ag_vextent_exact(args); + break; + default: + ASSERT(0); + /* NOTREACHED */ + } + if (error) + return error; + /* + * If the allocation worked, need to change the agf structure + * (and log it), and the superblock. + */ + if (args->agbno != NULLAGBLOCK) { + xfs_agf_t *agf; /* allocation group freelist header */ +#ifdef XFS_ALLOC_TRACE + xfs_mount_t *mp = args->mp; +#endif + long slen = (long)args->len; + + ASSERT(args->len >= args->minlen && args->len <= args->maxlen); + ASSERT(!(args->wasfromfl) || !args->isfl); + ASSERT(args->agbno % args->alignment == 0); + if (!(args->wasfromfl)) { + + agf = XFS_BUF_TO_AGF(args->agbp); + INT_MOD(agf->agf_freeblks, ARCH_CONVERT, -(args->len)); + xfs_trans_agblocks_delta(args->tp, + -((long)(args->len))); + args->pag->pagf_freeblks -= args->len; + ASSERT(INT_GET(agf->agf_freeblks, ARCH_CONVERT) + <= INT_GET(agf->agf_length, ARCH_CONVERT)); + TRACE_MODAGF(NULL, agf, XFS_AGF_FREEBLKS); + xfs_alloc_log_agf(args->tp, args->agbp, + XFS_AGF_FREEBLKS); + } + if (!args->isfl) + xfs_trans_mod_sb(args->tp, + args->wasdel ? XFS_TRANS_SB_RES_FDBLOCKS : + XFS_TRANS_SB_FDBLOCKS, -slen); + XFS_STATS_INC(xfsstats.xs_allocx); + XFS_STATS_ADD(xfsstats.xs_allocb, args->len); + } + return 0; +} + +/* + * Allocate a variable extent at exactly agno/bno. + * Extent's length (returned in *len) will be between minlen and maxlen, + * and of the form k * prod + mod unless there's nothing that large. + * Return the starting a.g. block (bno), or NULLAGBLOCK if we can't do it. + */ +STATIC int /* error */ +xfs_alloc_ag_vextent_exact( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_btree_cur_t *bno_cur;/* by block-number btree cursor */ + xfs_btree_cur_t *cnt_cur;/* by count btree cursor */ + xfs_agblock_t end; /* end of allocated extent */ + int error; + xfs_agblock_t fbno; /* start block of found extent */ + xfs_agblock_t fend; /* end block of found extent */ + xfs_extlen_t flen; /* length of found extent */ +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_ag_vextent_exact"; +#endif + int i; /* success/failure of operation */ + xfs_agblock_t maxend; /* end of maximal extent */ + xfs_agblock_t minend; /* end of minimal extent */ + xfs_extlen_t rlen; /* length of returned extent */ + + ASSERT(args->alignment == 1); + /* + * Allocate/initialize a cursor for the by-number freespace btree. + */ + bno_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_BNO, 0, 0); + /* + * Lookup bno and minlen in the btree (minlen is irrelevant, really). + * Look for the closest free block <= bno, it must contain bno + * if any free block does. + */ + if ((error = xfs_alloc_lookup_le(bno_cur, args->agbno, args->minlen, &i))) + goto error0; + if (!i) { + /* + * Didn't find it, return null. + */ + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + args->agbno = NULLAGBLOCK; + return 0; + } + /* + * Grab the freespace record. + */ + if ((error = xfs_alloc_get_rec(bno_cur, &fbno, &flen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + ASSERT(fbno <= args->agbno); + minend = args->agbno + args->minlen; + maxend = args->agbno + args->maxlen; + fend = fbno + flen; + /* + * Give up if the freespace isn't long enough for the minimum request. + */ + if (fend < minend) { + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + args->agbno = NULLAGBLOCK; + return 0; + } + /* + * End of extent will be smaller of the freespace end and the + * maximal requested end. + */ + end = XFS_AGBLOCK_MIN(fend, maxend); + /* + * Fix the length according to mod and prod if given. + */ + args->len = end - args->agbno; + xfs_alloc_fix_len(args); + if (!xfs_alloc_fix_minleft(args)) { + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + return 0; + } + rlen = args->len; + ASSERT(args->agbno + rlen <= fend); + end = args->agbno + rlen; + /* + * We are allocating agbno for rlen [agbno .. end] + * Allocate/initialize a cursor for the by-size btree. + */ + cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_CNT, 0, 0); + ASSERT(args->agbno + args->len <= + INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, + ARCH_CONVERT)); + if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, + args->agbno, args->len, XFSA_FIXUP_BNO_OK))) { + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); + goto error0; + } + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + TRACE_ALLOC("normal", args); + args->wasfromfl = 0; + return 0; + +error0: + xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); + TRACE_ALLOC("error", args); + return error; +} + +/* + * Allocate a variable extent near bno in the allocation group agno. + * Extent's length (returned in len) will be between minlen and maxlen, + * and of the form k * prod + mod unless there's nothing that large. + * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. + */ +STATIC int /* error */ +xfs_alloc_ag_vextent_near( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_btree_cur_t *bno_cur_gt; /* cursor for bno btree, right side */ + xfs_btree_cur_t *bno_cur_lt; /* cursor for bno btree, left side */ + xfs_btree_cur_t *cnt_cur; /* cursor for count btree */ +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_ag_vextent_near"; +#endif + xfs_agblock_t gtbno; /* start bno of right side entry */ + xfs_agblock_t gtbnoa; /* aligned ... */ + xfs_extlen_t gtdiff; /* difference to right side entry */ + xfs_extlen_t gtlen; /* length of right side entry */ + xfs_extlen_t gtlena; /* aligned ... */ + xfs_agblock_t gtnew; /* useful start bno of right side */ + int error; /* error code */ + int i; /* result code, temporary */ + int j; /* result code, temporary */ + xfs_agblock_t ltbno; /* start bno of left side entry */ + xfs_agblock_t ltbnoa; /* aligned ... */ + xfs_extlen_t ltdiff; /* difference to left side entry */ + /*REFERENCED*/ + xfs_agblock_t ltend; /* end bno of left side entry */ + xfs_extlen_t ltlen; /* length of left side entry */ + xfs_extlen_t ltlena; /* aligned ... */ + xfs_agblock_t ltnew; /* useful start bno of left side */ + xfs_extlen_t rlen; /* length of returned extent */ +#if defined(DEBUG) && defined(__KERNEL__) + /* + * Randomly don't execute the first algorithm. + */ + static int seed; /* randomizing seed value */ + int dofirst; /* set to do first algorithm */ + timespec_t now; /* current time */ + + if (!seed) { + nanotime(&now); + seed = (int)now.tv_sec ^ (int)now.tv_nsec; + } + dofirst = random() & 1; +#endif + /* + * Get a cursor for the by-size btree. + */ + cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_CNT, 0, 0); + ltlen = 0; + bno_cur_lt = bno_cur_gt = NULL; + /* + * See if there are any free extents as big as maxlen. + */ + if ((error = xfs_alloc_lookup_ge(cnt_cur, 0, args->maxlen, &i))) + goto error0; + /* + * If none, then pick up the last entry in the tree unless the + * tree is empty. + */ + if (!i) { + if ((error = xfs_alloc_ag_vextent_small(args, cnt_cur, <bno, + <len, &i))) + goto error0; + if (i == 0 || ltlen == 0) { + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + return 0; + } + ASSERT(i == 1); + } + args->wasfromfl = 0; + /* + * First algorithm. + * If the requested extent is large wrt the freespaces available + * in this a.g., then the cursor will be pointing to a btree entry + * near the right edge of the tree. If it's in the last btree leaf + * block, then we just examine all the entries in that block + * that are big enough, and pick the best one. + * This is written as a while loop so we can break out of it, + * but we never loop back to the top. + */ + while (xfs_btree_islastblock(cnt_cur, 0)) { + xfs_extlen_t bdiff; + int besti=0; + xfs_extlen_t blen=0; + xfs_agblock_t bnew=0; + +#if defined(DEBUG) && defined(__KERNEL__) + if (!dofirst) + break; +#endif + /* + * Start from the entry that lookup found, sequence through + * all larger free blocks. If we're actually pointing at a + * record smaller than maxlen, go to the start of this block, + * and skip all those smaller than minlen. + */ + if (ltlen || args->alignment > 1) { + cnt_cur->bc_ptrs[0] = 1; + do { + if ((error = xfs_alloc_get_rec(cnt_cur, <bno, + <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (ltlen >= args->minlen) + break; + if ((error = xfs_alloc_increment(cnt_cur, 0, &i))) + goto error0; + } while (i); + ASSERT(ltlen >= args->minlen); + if (!i) + break; + } + i = cnt_cur->bc_ptrs[0]; + for (j = 1, blen = 0, bdiff = 0; + !error && j && (blen < args->maxlen || bdiff > 0); + error = xfs_alloc_increment(cnt_cur, 0, &j)) { + /* + * For each entry, decide if it's better than + * the previous best entry. + */ + if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (!xfs_alloc_compute_aligned(ltbno, ltlen, + args->alignment, args->minlen, + <bnoa, <lena)) + continue; + args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); + xfs_alloc_fix_len(args); + ASSERT(args->len >= args->minlen); + if (args->len < blen) + continue; + ltdiff = xfs_alloc_compute_diff(args->agbno, args->len, + args->alignment, ltbno, ltlen, <new); + if (ltnew != NULLAGBLOCK && + (args->len > blen || ltdiff < bdiff)) { + bdiff = ltdiff; + bnew = ltnew; + blen = args->len; + besti = cnt_cur->bc_ptrs[0]; + } + } + /* + * It didn't work. We COULD be in a case where + * there's a good record somewhere, so try again. + */ + if (blen == 0) + break; + /* + * Point at the best entry, and retrieve it again. + */ + cnt_cur->bc_ptrs[0] = besti; + if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + ltend = ltbno + ltlen; + ASSERT(ltend <= INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, + ARCH_CONVERT)); + args->len = blen; + if (!xfs_alloc_fix_minleft(args)) { + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + TRACE_ALLOC("nominleft", args); + return 0; + } + blen = args->len; + /* + * We are allocating starting at bnew for blen blocks. + */ + args->agbno = bnew; + ASSERT(bnew >= ltbno); + ASSERT(bnew + blen <= ltend); + /* + * Set up a cursor for the by-bno tree. + */ + bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp, + args->agbp, args->agno, XFS_BTNUM_BNO, 0, 0); + /* + * Fix up the btree entries. + */ + if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, + ltlen, bnew, blen, XFSA_FIXUP_CNT_OK))) + goto error0; + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); + TRACE_ALLOC("first", args); + return 0; + } + /* + * Second algorithm. + * Search in the by-bno tree to the left and to the right + * simultaneously, until in each case we find a space big enough, + * or run into the edge of the tree. When we run into the edge, + * we deallocate that cursor. + * If both searches succeed, we compare the two spaces and pick + * the better one. + * With alignment, it's possible for both to fail; the upper + * level algorithm that picks allocation groups for allocations + * is not supposed to do this. + */ + /* + * Allocate and initialize the cursor for the leftward search. + */ + bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_BNO, 0, 0); + /* + * Lookup <= bno to find the leftward search's starting point. + */ + if ((error = xfs_alloc_lookup_le(bno_cur_lt, args->agbno, args->maxlen, &i))) + goto error0; + if (!i) { + /* + * Didn't find anything; use this cursor for the rightward + * search. + */ + bno_cur_gt = bno_cur_lt; + bno_cur_lt = 0; + } + /* + * Found something. Duplicate the cursor for the rightward search. + */ + else if ((error = xfs_btree_dup_cursor(bno_cur_lt, &bno_cur_gt))) + goto error0; + /* + * Increment the cursor, so we will point at the entry just right + * of the leftward entry if any, or to the leftmost entry. + */ + if ((error = xfs_alloc_increment(bno_cur_gt, 0, &i))) + goto error0; + if (!i) { + /* + * It failed, there are no rightward entries. + */ + xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + } + /* + * Loop going left with the leftward cursor, right with the + * rightward cursor, until either both directions give up or + * we find an entry at least as big as minlen. + */ + do { + if (bno_cur_lt) { + if ((error = xfs_alloc_get_rec(bno_cur_lt, <bno, <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (xfs_alloc_compute_aligned(ltbno, ltlen, + args->alignment, args->minlen, + <bnoa, <lena)) + break; + if ((error = xfs_alloc_decrement(bno_cur_lt, 0, &i))) + goto error0; + if (!i) { + xfs_btree_del_cursor(bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + } + } + if (bno_cur_gt) { + if ((error = xfs_alloc_get_rec(bno_cur_gt, >bno, >len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (xfs_alloc_compute_aligned(gtbno, gtlen, + args->alignment, args->minlen, + >bnoa, >lena)) + break; + if ((error = xfs_alloc_increment(bno_cur_gt, 0, &i))) + goto error0; + if (!i) { + xfs_btree_del_cursor(bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + } + } + } while (bno_cur_lt || bno_cur_gt); + /* + * Got both cursors still active, need to find better entry. + */ + if (bno_cur_lt && bno_cur_gt) { + /* + * Left side is long enough, look for a right side entry. + */ + if (ltlena >= args->minlen) { + /* + * Fix up the length. + */ + args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); + xfs_alloc_fix_len(args); + rlen = args->len; + ltdiff = xfs_alloc_compute_diff(args->agbno, rlen, + args->alignment, ltbno, ltlen, <new); + /* + * Not perfect. + */ + if (ltdiff) { + /* + * Look until we find a better one, run out of + * space, or run off the end. + */ + while (bno_cur_lt && bno_cur_gt) { + if ((error = xfs_alloc_get_rec( + bno_cur_gt, >bno, + >len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + xfs_alloc_compute_aligned(gtbno, gtlen, + args->alignment, args->minlen, + >bnoa, >lena); + /* + * The left one is clearly better. + */ + if (gtbnoa >= args->agbno + ltdiff) { + xfs_btree_del_cursor( + bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + break; + } + /* + * If we reach a big enough entry, + * compare the two and pick the best. + */ + if (gtlena >= args->minlen) { + args->len = + XFS_EXTLEN_MIN(gtlena, + args->maxlen); + xfs_alloc_fix_len(args); + rlen = args->len; + gtdiff = xfs_alloc_compute_diff( + args->agbno, rlen, + args->alignment, + gtbno, gtlen, >new); + /* + * Right side is better. + */ + if (gtdiff < ltdiff) { + xfs_btree_del_cursor( + bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + } + /* + * Left side is better. + */ + else { + xfs_btree_del_cursor( + bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + } + break; + } + /* + * Fell off the right end. + */ + if ((error = xfs_alloc_increment( + bno_cur_gt, 0, &i))) + goto error0; + if (!i) { + xfs_btree_del_cursor( + bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + break; + } + } + } + /* + * The left side is perfect, trash the right side. + */ + else { + xfs_btree_del_cursor(bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + } + } + /* + * It's the right side that was found first, look left. + */ + else { + /* + * Fix up the length. + */ + args->len = XFS_EXTLEN_MIN(gtlena, args->maxlen); + xfs_alloc_fix_len(args); + rlen = args->len; + gtdiff = xfs_alloc_compute_diff(args->agbno, rlen, + args->alignment, gtbno, gtlen, >new); + /* + * Right side entry isn't perfect. + */ + if (gtdiff) { + /* + * Look until we find a better one, run out of + * space, or run off the end. + */ + while (bno_cur_lt && bno_cur_gt) { + if ((error = xfs_alloc_get_rec( + bno_cur_lt, <bno, + <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + xfs_alloc_compute_aligned(ltbno, ltlen, + args->alignment, args->minlen, + <bnoa, <lena); + /* + * The right one is clearly better. + */ + if (ltbnoa <= args->agbno - gtdiff) { + xfs_btree_del_cursor( + bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + break; + } + /* + * If we reach a big enough entry, + * compare the two and pick the best. + */ + if (ltlena >= args->minlen) { + args->len = XFS_EXTLEN_MIN( + ltlena, args->maxlen); + xfs_alloc_fix_len(args); + rlen = args->len; + ltdiff = xfs_alloc_compute_diff( + args->agbno, rlen, + args->alignment, + ltbno, ltlen, <new); + /* + * Left side is better. + */ + if (ltdiff < gtdiff) { + xfs_btree_del_cursor( + bno_cur_gt, + XFS_BTREE_NOERROR); + bno_cur_gt = NULL; + } + /* + * Right side is better. + */ + else { + xfs_btree_del_cursor( + bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + } + break; + } + /* + * Fell off the left end. + */ + if ((error = xfs_alloc_decrement( + bno_cur_lt, 0, &i))) + goto error0; + if (!i) { + xfs_btree_del_cursor(bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + break; + } + } + } + /* + * The right side is perfect, trash the left side. + */ + else { + xfs_btree_del_cursor(bno_cur_lt, + XFS_BTREE_NOERROR); + bno_cur_lt = NULL; + } + } + } + /* + * If we couldn't get anything, give up. + */ + if (bno_cur_lt == NULL && bno_cur_gt == NULL) { + TRACE_ALLOC("neither", args); + args->agbno = NULLAGBLOCK; + return 0; + } + /* + * At this point we have selected a freespace entry, either to the + * left or to the right. If it's on the right, copy all the + * useful variables to the "left" set so we only have one + * copy of this code. + */ + if (bno_cur_gt) { + bno_cur_lt = bno_cur_gt; + bno_cur_gt = NULL; + ltbno = gtbno; + ltbnoa = gtbnoa; + ltlen = gtlen; + ltlena = gtlena; + j = 1; + } else + j = 0; + /* + * Fix up the length and compute the useful address. + */ + ltend = ltbno + ltlen; + args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); + xfs_alloc_fix_len(args); + if (!xfs_alloc_fix_minleft(args)) { + TRACE_ALLOC("nominleft", args); + xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + return 0; + } + rlen = args->len; + (void)xfs_alloc_compute_diff(args->agbno, rlen, args->alignment, ltbno, + ltlen, <new); + ASSERT(ltnew >= ltbno); + ASSERT(ltnew + rlen <= ltend); + ASSERT(ltnew + rlen <= INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, + ARCH_CONVERT)); + args->agbno = ltnew; + if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, ltlen, + ltnew, rlen, XFSA_FIXUP_BNO_OK))) + goto error0; + TRACE_ALLOC(j ? "gt" : "lt", args); + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); + return 0; + + error0: + TRACE_ALLOC("error", args); + if (cnt_cur != NULL) + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); + if (bno_cur_lt != NULL) + xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_ERROR); + if (bno_cur_gt != NULL) + xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_ERROR); + return error; +} + +/* + * Allocate a variable extent anywhere in the allocation group agno. + * Extent's length (returned in len) will be between minlen and maxlen, + * and of the form k * prod + mod unless there's nothing that large. + * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. + */ +STATIC int /* error */ +xfs_alloc_ag_vextent_size( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_btree_cur_t *bno_cur; /* cursor for bno btree */ + xfs_btree_cur_t *cnt_cur; /* cursor for cnt btree */ + int error; /* error result */ + xfs_agblock_t fbno; /* start of found freespace */ + xfs_extlen_t flen; /* length of found freespace */ +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_ag_vextent_size"; +#endif + int i; /* temp status variable */ + xfs_agblock_t rbno; /* returned block number */ + xfs_extlen_t rlen; /* length of returned extent */ + + /* + * Allocate and initialize a cursor for the by-size btree. + */ + cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_CNT, 0, 0); + bno_cur = NULL; + /* + * Look for an entry >= maxlen+alignment-1 blocks. + */ + if ((error = xfs_alloc_lookup_ge(cnt_cur, 0, + args->maxlen + args->alignment - 1, &i))) + goto error0; + /* + * If none, then pick up the last entry in the tree unless the + * tree is empty. + */ + if (!i) { + if ((error = xfs_alloc_ag_vextent_small(args, cnt_cur, &fbno, + &flen, &i))) + goto error0; + if (i == 0 || flen == 0) { + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + TRACE_ALLOC("noentry", args); + return 0; + } + ASSERT(i == 1); + } + /* + * There's a freespace as big as maxlen+alignment-1, get it. + */ + else { + if ((error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + /* + * In the first case above, we got the last entry in the + * by-size btree. Now we check to see if the space hits maxlen + * once aligned; if not, we search left for something better. + * This can't happen in the second case above. + */ + xfs_alloc_compute_aligned(fbno, flen, args->alignment, args->minlen, + &rbno, &rlen); + rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); + XFS_WANT_CORRUPTED_GOTO(rlen == 0 || + (rlen <= flen && rbno + rlen <= fbno + flen), error0); + if (rlen < args->maxlen) { + xfs_agblock_t bestfbno; + xfs_extlen_t bestflen; + xfs_agblock_t bestrbno; + xfs_extlen_t bestrlen; + + bestrlen = rlen; + bestrbno = rbno; + bestflen = flen; + bestfbno = fbno; + for (;;) { + if ((error = xfs_alloc_decrement(cnt_cur, 0, &i))) + goto error0; + if (i == 0) + break; + if ((error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, + &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (flen < bestrlen) + break; + xfs_alloc_compute_aligned(fbno, flen, args->alignment, + args->minlen, &rbno, &rlen); + rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); + XFS_WANT_CORRUPTED_GOTO(rlen == 0 || + (rlen <= flen && rbno + rlen <= fbno + flen), + error0); + if (rlen > bestrlen) { + bestrlen = rlen; + bestrbno = rbno; + bestflen = flen; + bestfbno = fbno; + if (rlen == args->maxlen) + break; + } + } + if ((error = xfs_alloc_lookup_eq(cnt_cur, bestfbno, bestflen, + &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + rlen = bestrlen; + rbno = bestrbno; + flen = bestflen; + fbno = bestfbno; + } + args->wasfromfl = 0; + /* + * Fix up the length. + */ + args->len = rlen; + xfs_alloc_fix_len(args); + if (rlen < args->minlen || !xfs_alloc_fix_minleft(args)) { + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + TRACE_ALLOC("nominleft", args); + args->agbno = NULLAGBLOCK; + return 0; + } + rlen = args->len; + XFS_WANT_CORRUPTED_GOTO(rlen <= flen, error0); + /* + * Allocate and initialize a cursor for the by-block tree. + */ + bno_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp, + args->agno, XFS_BTNUM_BNO, 0, 0); + if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, + rbno, rlen, XFSA_FIXUP_CNT_OK))) + goto error0; + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + cnt_cur = bno_cur = NULL; + args->len = rlen; + args->agbno = rbno; + XFS_WANT_CORRUPTED_GOTO( + args->agbno + args->len <= + INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, + ARCH_CONVERT), + error0); + TRACE_ALLOC("normal", args); + return 0; + +error0: + TRACE_ALLOC("error", args); + if (cnt_cur) + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); + if (bno_cur) + xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Deal with the case where only small freespaces remain. + * Either return the contents of the last freespace record, + * or allocate space from the freelist if there is nothing in the tree. + */ +STATIC int /* error */ +xfs_alloc_ag_vextent_small( + xfs_alloc_arg_t *args, /* allocation argument structure */ + xfs_btree_cur_t *ccur, /* by-size cursor */ + xfs_agblock_t *fbnop, /* result block number */ + xfs_extlen_t *flenp, /* result length */ + int *stat) /* status: 0-freelist, 1-normal/none */ +{ + int error; + xfs_agblock_t fbno; + xfs_extlen_t flen; +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_ag_vextent_small"; +#endif + int i; + + if ((error = xfs_alloc_decrement(ccur, 0, &i))) + goto error0; + if (i) { + if ((error = xfs_alloc_get_rec(ccur, &fbno, &flen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + /* + * Nothing in the btree, try the freelist. Make sure + * to respect minleft even when pulling from the + * freelist. + */ + else if (args->minlen == 1 && args->alignment == 1 && !args->isfl && + (INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_flcount, + ARCH_CONVERT) > args->minleft)) { + if ((error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno))) + goto error0; + if (fbno != NULLAGBLOCK) { + if (args->userdata) { + xfs_buf_t *bp; + + bp = xfs_btree_get_bufs(args->mp, args->tp, + args->agno, fbno, 0); + xfs_trans_binval(args->tp, bp); + /* + * Since blocks move to the free list without + * the coordination used in xfs_bmap_finish, + * we can't allow the user to write to the + * block until we know that the transaction + * that moved it to the free list is + * permanently on disk. The only way to + * ensure that is to make this transaction + * synchronous. + */ + xfs_trans_set_sync(args->tp); + } + args->len = 1; + args->agbno = fbno; + XFS_WANT_CORRUPTED_GOTO( + args->agbno + args->len <= + INT_GET(XFS_BUF_TO_AGF(args->agbp)->agf_length, + ARCH_CONVERT), + error0); + args->wasfromfl = 1; + TRACE_ALLOC("freelist", args); + *stat = 0; + return 0; + } + /* + * Nothing in the freelist. + */ + else + flen = 0; + } + /* + * Can't allocate from the freelist for some reason. + */ + else + flen = 0; + /* + * Can't do the allocation, give up. + */ + if (flen < args->minlen) { + args->agbno = NULLAGBLOCK; + TRACE_ALLOC("notenough", args); + flen = 0; + } + *fbnop = fbno; + *flenp = flen; + *stat = 1; + TRACE_ALLOC("normal", args); + return 0; + +error0: + TRACE_ALLOC("error", args); + return error; +} + +/* + * Free the extent starting at agno/bno for length. + */ +STATIC int /* error */ +xfs_free_ag_extent( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* buffer for a.g. freelist header */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t bno, /* starting block number */ + xfs_extlen_t len, /* length of extent */ + int isfl) /* set if is freelist blocks - no sb acctg */ +{ + xfs_btree_cur_t *bno_cur; /* cursor for by-block btree */ + xfs_btree_cur_t *cnt_cur; /* cursor for by-size btree */ + int error; /* error return value */ +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_free_ag_extent"; +#endif + xfs_agblock_t gtbno; /* start of right neighbor block */ + xfs_extlen_t gtlen; /* length of right neighbor block */ + int haveleft; /* have a left neighbor block */ + int haveright; /* have a right neighbor block */ + int i; /* temp, result code */ + xfs_agblock_t ltbno; /* start of left neighbor block */ + xfs_extlen_t ltlen; /* length of left neighbor block */ + xfs_mount_t *mp; /* mount point struct for filesystem */ + xfs_agblock_t nbno; /* new starting block of freespace */ + xfs_extlen_t nlen; /* new length of freespace */ + + mp = tp->t_mountp; + /* + * Allocate and initialize a cursor for the by-block btree. + */ + bno_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO, 0, + 0); + cnt_cur = NULL; + /* + * Look for a neighboring block on the left (lower block numbers) + * that is contiguous with this space. + */ + if ((error = xfs_alloc_lookup_le(bno_cur, bno, len, &haveleft))) + goto error0; + if (haveleft) { + /* + * There is a block to our left. + */ + if ((error = xfs_alloc_get_rec(bno_cur, <bno, <len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * It's not contiguous, though. + */ + if (ltbno + ltlen < bno) + haveleft = 0; + else { + /* + * If this failure happens the request to free this + * space was invalid, it's (partly) already free. + * Very bad. + */ + XFS_WANT_CORRUPTED_GOTO(ltbno + ltlen <= bno, error0); + } + } + /* + * Look for a neighboring block on the right (higher block numbers) + * that is contiguous with this space. + */ + if ((error = xfs_alloc_increment(bno_cur, 0, &haveright))) + goto error0; + if (haveright) { + /* + * There is a block to our right. + */ + if ((error = xfs_alloc_get_rec(bno_cur, >bno, >len, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * It's not contiguous, though. + */ + if (bno + len < gtbno) + haveright = 0; + else { + /* + * If this failure happens the request to free this + * space was invalid, it's (partly) already free. + * Very bad. + */ + XFS_WANT_CORRUPTED_GOTO(gtbno >= bno + len, error0); + } + } + /* + * Now allocate and initialize a cursor for the by-size tree. + */ + cnt_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT, 0, + 0); + /* + * Have both left and right contiguous neighbors. + * Merge all three into a single free block. + */ + if (haveleft && haveright) { + /* + * Delete the old by-size entry on the left. + */ + if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_delete(cnt_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Delete the old by-size entry on the right. + */ + if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_delete(cnt_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Delete the old by-block entry for the right block. + */ + if ((error = xfs_alloc_delete(bno_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Move the by-block cursor back to the left neighbor. + */ + if ((error = xfs_alloc_decrement(bno_cur, 0, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); +#ifdef DEBUG + /* + * Check that this is the right record: delete didn't + * mangle the cursor. + */ + { + xfs_agblock_t xxbno; + xfs_extlen_t xxlen; + + if ((error = xfs_alloc_get_rec(bno_cur, &xxbno, &xxlen, + &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO( + i == 1 && xxbno == ltbno && xxlen == ltlen, + error0); + } +#endif + /* + * Update remaining by-block entry to the new, joined block. + */ + nbno = ltbno; + nlen = len + ltlen + gtlen; + if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) + goto error0; + } + /* + * Have only a left contiguous neighbor. + * Merge it together with the new freespace. + */ + else if (haveleft) { + /* + * Delete the old by-size entry on the left. + */ + if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_delete(cnt_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Back up the by-block cursor to the left neighbor, and + * update its length. + */ + if ((error = xfs_alloc_decrement(bno_cur, 0, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + nbno = ltbno; + nlen = len + ltlen; + if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) + goto error0; + } + /* + * Have only a right contiguous neighbor. + * Merge it together with the new freespace. + */ + else if (haveright) { + /* + * Delete the old by-size entry on the right. + */ + if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_delete(cnt_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Update the starting block and length of the right + * neighbor in the by-block tree. + */ + nbno = bno; + nlen = len + gtlen; + if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) + goto error0; + } + /* + * No contiguous neighbors. + * Insert the new freespace into the by-block tree. + */ + else { + nbno = bno; + nlen = len; + if ((error = xfs_alloc_insert(bno_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); + bno_cur = NULL; + /* + * In all cases we need to insert the new freespace in the by-size tree. + */ + if ((error = xfs_alloc_lookup_eq(cnt_cur, nbno, nlen, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 0, error0); + if ((error = xfs_alloc_insert(cnt_cur, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); + cnt_cur = NULL; + /* + * Update the freespace totals in the ag and superblock. + */ + { + xfs_agf_t *agf; + xfs_perag_t *pag; /* per allocation group data */ + + agf = XFS_BUF_TO_AGF(agbp); + pag = &mp->m_perag[agno]; + INT_MOD(agf->agf_freeblks, ARCH_CONVERT, len); + xfs_trans_agblocks_delta(tp, len); + pag->pagf_freeblks += len; + XFS_WANT_CORRUPTED_GOTO( + INT_GET(agf->agf_freeblks, ARCH_CONVERT) + <= INT_GET(agf->agf_length, ARCH_CONVERT), + error0); + TRACE_MODAGF(NULL, agf, XFS_AGF_FREEBLKS); + xfs_alloc_log_agf(tp, agbp, XFS_AGF_FREEBLKS); + if (!isfl) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (long)len); + XFS_STATS_INC(xfsstats.xs_freex); + XFS_STATS_ADD(xfsstats.xs_freeb, len); + } + TRACE_FREE(haveleft ? + (haveright ? "both" : "left") : + (haveright ? "right" : "none"), + agno, bno, len, isfl); + return 0; + + error0: + TRACE_FREE("error", agno, bno, len, isfl); + if (bno_cur) + xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); + if (cnt_cur) + xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Visible (exported) allocation/free functions. + * Some of these are used just by xfs_alloc_btree.c and this file. + */ + +/* + * Compute and fill in value of m_ag_maxlevels. + */ +void +xfs_alloc_compute_maxlevels( + xfs_mount_t *mp) /* file system mount structure */ +{ + int level; + uint maxblocks; + uint maxleafents; + int minleafrecs; + int minnoderecs; + + maxleafents = (mp->m_sb.sb_agblocks + 1) / 2; + minleafrecs = mp->m_alloc_mnr[0]; + minnoderecs = mp->m_alloc_mnr[1]; + maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; + for (level = 1; maxblocks > 1; level++) + maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; + mp->m_ag_maxlevels = level; +} + +/* + * Decide whether to use this allocation group for this allocation. + * If so, fix up the btree freelist's size. + * This is external so mkfs can call it, too. + */ +int /* error */ +xfs_alloc_fix_freelist( + xfs_alloc_arg_t *args, /* allocation argument structure */ + int flags) /* XFS_ALLOC_FLAG_... */ +{ + xfs_buf_t *agbp; /* agf buffer pointer */ + xfs_agf_t *agf; /* a.g. freespace structure pointer */ + xfs_buf_t *agflbp;/* agfl buffer pointer */ + xfs_agblock_t bno; /* freelist block */ + xfs_extlen_t delta; /* new blocks needed in freelist */ + int error; /* error result code */ + xfs_extlen_t longest;/* longest extent in allocation group */ + xfs_mount_t *mp; /* file system mount point structure */ + xfs_extlen_t need; /* total blocks needed in freelist */ + xfs_perag_t *pag; /* per-ag information structure */ + xfs_alloc_arg_t targs; /* local allocation arguments */ + xfs_trans_t *tp; /* transaction pointer */ + + mp = args->mp; + + pag = args->pag; + tp = args->tp; + if (!pag->pagf_init) { + if ((error = xfs_alloc_read_agf(mp, tp, args->agno, flags, + &agbp))) + return error; + if (!pag->pagf_init) { + args->agbp = NULL; + return 0; + } + } else + agbp = NULL; + need = XFS_MIN_FREELIST_PAG(pag, mp); + delta = need > pag->pagf_flcount ? need - pag->pagf_flcount : 0; + /* + * If it looks like there isn't a long enough extent, or enough + * total blocks, reject it. + */ + longest = (pag->pagf_longest > delta) ? + (pag->pagf_longest - delta) : + (pag->pagf_flcount > 0 || pag->pagf_longest > 0); + if (args->minlen + args->alignment + args->minalignslop - 1 > longest || + (args->minleft && + (int)(pag->pagf_freeblks + pag->pagf_flcount - + need - args->total) < + (int)args->minleft)) { + if (agbp) + xfs_trans_brelse(tp, agbp); + args->agbp = NULL; + return 0; + } + /* + * Get the a.g. freespace buffer. + * Can fail if we're not blocking on locks, and it's held. + */ + if (agbp == NULL) { + if ((error = xfs_alloc_read_agf(mp, tp, args->agno, flags, + &agbp))) + return error; + if (agbp == NULL) { + args->agbp = NULL; + return 0; + } + } + /* + * Figure out how many blocks we should have in the freelist. + */ + agf = XFS_BUF_TO_AGF(agbp); + need = XFS_MIN_FREELIST(agf, mp); + delta = need > INT_GET(agf->agf_flcount, ARCH_CONVERT) ? + (need - INT_GET(agf->agf_flcount, ARCH_CONVERT)) : 0; + /* + * If there isn't enough total or single-extent, reject it. + */ + longest = INT_GET(agf->agf_longest, ARCH_CONVERT); + longest = (longest > delta) ? (longest - delta) : + (INT_GET(agf->agf_flcount, ARCH_CONVERT) > 0 || longest > 0); + if (args->minlen + args->alignment + args->minalignslop - 1 > longest || + (args->minleft && + (int)(INT_GET(agf->agf_freeblks, ARCH_CONVERT) + + INT_GET(agf->agf_flcount, ARCH_CONVERT) - need - args->total) < + (int)args->minleft)) { + xfs_trans_brelse(tp, agbp); + args->agbp = NULL; + return 0; + } + /* + * Make the freelist shorter if it's too long. + */ + while (INT_GET(agf->agf_flcount, ARCH_CONVERT) > need) { + xfs_buf_t *bp; + + if ((error = xfs_alloc_get_freelist(tp, agbp, &bno))) + return error; + if ((error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, 1))) + return error; + bp = xfs_btree_get_bufs(mp, tp, args->agno, bno, 0); + xfs_trans_binval(tp, bp); + /* + * Since blocks move to the free list without + * the coordination used in xfs_bmap_finish, + * we can't allow block to be available for reallocation + * and non-transaction writing (user data) + * until we know that the transaction + * that moved it to the free list is + * permanently on disk. The only way to + * ensure that is to make this transaction + * synchronous. The one exception to this + * is in the case of wsync-mounted filesystem + * where we know that any block that made it + * onto the freelist won't be seen again in + * the file from which it came since the transactions + * that free metadata blocks or shrink inodes in + * wsync filesystems are all themselves synchronous. + */ + if (!(mp->m_flags & XFS_MOUNT_WSYNC)) + xfs_trans_set_sync(tp); + } + /* + * Initialize the args structure. + */ + targs.tp = tp; + targs.mp = mp; + targs.agbp = agbp; + targs.agno = args->agno; + targs.mod = targs.minleft = targs.wasdel = targs.userdata = + targs.minalignslop = 0; + targs.alignment = targs.minlen = targs.prod = targs.isfl = 1; + targs.type = XFS_ALLOCTYPE_THIS_AG; + targs.pag = pag; + if ((error = xfs_alloc_read_agfl(mp, tp, targs.agno, &agflbp))) + return error; + /* + * Make the freelist longer if it's too short. + */ + while (INT_GET(agf->agf_flcount, ARCH_CONVERT) < need) { + targs.agbno = 0; + targs.maxlen = need - INT_GET(agf->agf_flcount, ARCH_CONVERT); + /* + * Allocate as many blocks as possible at once. + */ + if ((error = xfs_alloc_ag_vextent(&targs))) + return error; + /* + * Stop if we run out. Won't happen if callers are obeying + * the restrictions correctly. Can happen for free calls + * on a completely full ag. + */ + if (targs.agbno == NULLAGBLOCK) + break; + /* + * Put each allocated block on the list. + */ + for (bno = targs.agbno; bno < targs.agbno + targs.len; bno++) { + if ((error = xfs_alloc_put_freelist(tp, agbp, agflbp, + bno))) + return error; + } + } + args->agbp = agbp; + return 0; +} + +/* + * Get a block from the freelist. + * Returns with the buffer for the block gotten. + */ +int /* error */ +xfs_alloc_get_freelist( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* buffer containing the agf structure */ + xfs_agblock_t *bnop) /* block address retrieved from freelist */ +{ + xfs_agf_t *agf; /* a.g. freespace structure */ + xfs_agfl_t *agfl; /* a.g. freelist structure */ + xfs_buf_t *agflbp;/* buffer for a.g. freelist structure */ + xfs_agblock_t bno; /* block number returned */ + int error; +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_get_freelist"; +#endif + xfs_mount_t *mp; /* mount structure */ + xfs_perag_t *pag; /* per allocation group data */ + + agf = XFS_BUF_TO_AGF(agbp); + /* + * Freelist is empty, give up. + */ + if (INT_GET(agf->agf_flcount, ARCH_CONVERT) == 0) { + *bnop = NULLAGBLOCK; + return 0; + } + /* + * Read the array of free blocks. + */ + mp = tp->t_mountp; + if ((error = xfs_alloc_read_agfl(mp, tp, + INT_GET(agf->agf_seqno, ARCH_CONVERT), &agflbp))) + return error; + agfl = XFS_BUF_TO_AGFL(agflbp); + /* + * Get the block number and update the data structures. + */ + bno = INT_GET(agfl->agfl_bno[INT_GET(agf->agf_flfirst, ARCH_CONVERT)], ARCH_CONVERT); + INT_MOD(agf->agf_flfirst, ARCH_CONVERT, 1); + xfs_trans_brelse(tp, agflbp); + if (INT_GET(agf->agf_flfirst, ARCH_CONVERT) == XFS_AGFL_SIZE) + INT_ZERO(agf->agf_flfirst, ARCH_CONVERT); + pag = &mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)]; + INT_MOD(agf->agf_flcount, ARCH_CONVERT, -1); + xfs_trans_agflist_delta(tp, -1); + pag->pagf_flcount--; + TRACE_MODAGF(NULL, agf, XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT); + xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT); + *bnop = bno; + return 0; +} + +/* + * Log the given fields from the agf structure. + */ +void +xfs_alloc_log_agf( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *bp, /* buffer for a.g. freelist header */ + int fields) /* mask of fields to be logged (XFS_AGF_...) */ +{ + int first; /* first byte offset */ + int last; /* last byte offset */ + static const short offsets[] = { + offsetof(xfs_agf_t, agf_magicnum), + offsetof(xfs_agf_t, agf_versionnum), + offsetof(xfs_agf_t, agf_seqno), + offsetof(xfs_agf_t, agf_length), + offsetof(xfs_agf_t, agf_roots[0]), + offsetof(xfs_agf_t, agf_levels[0]), + offsetof(xfs_agf_t, agf_flfirst), + offsetof(xfs_agf_t, agf_fllast), + offsetof(xfs_agf_t, agf_flcount), + offsetof(xfs_agf_t, agf_freeblks), + offsetof(xfs_agf_t, agf_longest), + sizeof(xfs_agf_t) + }; + + xfs_btree_offsets(fields, offsets, XFS_AGF_NUM_BITS, &first, &last); + xfs_trans_log_buf(tp, bp, (uint)first, (uint)last); +} + +/* + * Interface for inode allocation to force the pag data to be initialized. + */ +int /* error */ +xfs_alloc_pagf_init( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + int flags) /* XFS_ALLOC_FLAGS_... */ +{ + xfs_buf_t *bp; + int error; + + if ((error = xfs_alloc_read_agf(mp, tp, agno, flags, &bp))) + return error; + if (bp) + xfs_trans_brelse(tp, bp); + return 0; +} + +/* + * Put the block on the freelist for the allocation group. + */ +int /* error */ +xfs_alloc_put_freelist( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* buffer for a.g. freelist header */ + xfs_buf_t *agflbp,/* buffer for a.g. free block array */ + xfs_agblock_t bno) /* block being freed */ +{ + xfs_agf_t *agf; /* a.g. freespace structure */ + xfs_agfl_t *agfl; /* a.g. free block array */ + xfs_agblock_t *blockp;/* pointer to array entry */ + int error; +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_put_freelist"; +#endif + xfs_mount_t *mp; /* mount structure */ + xfs_perag_t *pag; /* per allocation group data */ + + agf = XFS_BUF_TO_AGF(agbp); + mp = tp->t_mountp; + + if (!agflbp && (error = xfs_alloc_read_agfl(mp, tp, + INT_GET(agf->agf_seqno, ARCH_CONVERT), &agflbp))) + return error; + agfl = XFS_BUF_TO_AGFL(agflbp); + INT_MOD(agf->agf_fllast, ARCH_CONVERT, 1); + if (INT_GET(agf->agf_fllast, ARCH_CONVERT) == XFS_AGFL_SIZE) + INT_ZERO(agf->agf_fllast, ARCH_CONVERT); + pag = &mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)]; + INT_MOD(agf->agf_flcount, ARCH_CONVERT, 1); + xfs_trans_agflist_delta(tp, 1); + pag->pagf_flcount++; + ASSERT(INT_GET(agf->agf_flcount, ARCH_CONVERT) <= XFS_AGFL_SIZE); + blockp = &agfl->agfl_bno[INT_GET(agf->agf_fllast, ARCH_CONVERT)]; + INT_SET(*blockp, ARCH_CONVERT, bno); + TRACE_MODAGF(NULL, agf, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT); + xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT); + xfs_trans_log_buf(tp, agflbp, + (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl), + (int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl + + sizeof(xfs_agblock_t) - 1)); + return 0; +} + +/* + * Read in the allocation group header (free/alloc section). + */ +int /* error */ +xfs_alloc_read_agf( + xfs_mount_t *mp, /* mount point structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + int flags, /* XFS_ALLOC_FLAG_... */ + xfs_buf_t **bpp) /* buffer for the ag freelist header */ +{ + xfs_agf_t *agf; /* ag freelist header */ + int agf_ok; /* set if agf is consistent */ + xfs_buf_t *bp; /* return value */ + xfs_daddr_t d; /* disk block address */ + int error; + xfs_perag_t *pag; /* per allocation group data */ + + ASSERT(agno != NULLAGNUMBER); + d = XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, 1, + (flags & XFS_ALLOC_FLAG_TRYLOCK) ? XFS_BUF_TRYLOCK : 0U, + &bp))) + return error; + ASSERT(!bp || !XFS_BUF_GETERROR(bp)); + if (!bp) { + *bpp = NULL; + return 0; + } + /* + * Validate the magic number of the agf block. + */ + agf = XFS_BUF_TO_AGF(bp); + agf_ok = + INT_GET(agf->agf_magicnum, ARCH_CONVERT) == XFS_AGF_MAGIC && + XFS_AGF_GOOD_VERSION(INT_GET(agf->agf_versionnum, ARCH_CONVERT)) && + INT_GET(agf->agf_freeblks, ARCH_CONVERT) <= + INT_GET(agf->agf_length, ARCH_CONVERT) && + INT_GET(agf->agf_flfirst, ARCH_CONVERT) < XFS_AGFL_SIZE && + INT_GET(agf->agf_fllast, ARCH_CONVERT) < XFS_AGFL_SIZE && + INT_GET(agf->agf_flcount, ARCH_CONVERT) <= XFS_AGFL_SIZE; + if (XFS_TEST_ERROR(!agf_ok, mp, XFS_ERRTAG_ALLOC_READ_AGF, + XFS_RANDOM_ALLOC_READ_AGF)) { + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EFSCORRUPTED); + } + pag = &mp->m_perag[agno]; + if (!pag->pagf_init) { + pag->pagf_freeblks = INT_GET(agf->agf_freeblks, ARCH_CONVERT); + pag->pagf_flcount = INT_GET(agf->agf_flcount, ARCH_CONVERT); + pag->pagf_longest = INT_GET(agf->agf_longest, ARCH_CONVERT); + pag->pagf_levels[XFS_BTNUM_BNOi] = + INT_GET(agf->agf_levels[XFS_BTNUM_BNOi], ARCH_CONVERT); + pag->pagf_levels[XFS_BTNUM_CNTi] = + INT_GET(agf->agf_levels[XFS_BTNUM_CNTi], ARCH_CONVERT); + pag->pagf_init = 1; + } +#ifdef DEBUG + else if (!XFS_FORCED_SHUTDOWN(mp)) { + ASSERT(pag->pagf_freeblks == INT_GET(agf->agf_freeblks, ARCH_CONVERT)); + ASSERT(pag->pagf_flcount == INT_GET(agf->agf_flcount, ARCH_CONVERT)); + ASSERT(pag->pagf_longest == INT_GET(agf->agf_longest, ARCH_CONVERT)); + ASSERT(pag->pagf_levels[XFS_BTNUM_BNOi] == + INT_GET(agf->agf_levels[XFS_BTNUM_BNOi], ARCH_CONVERT)); + ASSERT(pag->pagf_levels[XFS_BTNUM_CNTi] == + INT_GET(agf->agf_levels[XFS_BTNUM_CNTi], ARCH_CONVERT)); + } +#endif + XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGF, XFS_AGF_REF); + *bpp = bp; + return 0; +} + +/* + * Allocate an extent (variable-size). + * Depending on the allocation type, we either look in a single allocation + * group or loop over the allocation groups to find the result. + */ +int /* error */ +xfs_alloc_vextent( + xfs_alloc_arg_t *args) /* allocation argument structure */ +{ + xfs_agblock_t agsize; /* allocation group size */ + int error; + int flags; /* XFS_ALLOC_FLAG_... locking flags */ +#ifdef XFS_ALLOC_TRACE + static char fname[] = "xfs_alloc_vextent"; +#endif + xfs_extlen_t minleft;/* minimum left value, temp copy */ + xfs_mount_t *mp; /* mount structure pointer */ + xfs_agnumber_t sagno; /* starting allocation group number */ + xfs_alloctype_t type; /* input allocation type */ + + mp = args->mp; + type = args->otype = args->type; + args->agbno = NULLAGBLOCK; + /* + * Just fix this up, for the case where the last a.g. is shorter + * (or there's only one a.g.) and the caller couldn't easily figure + * that out (xfs_bmap_alloc). + */ + agsize = mp->m_sb.sb_agblocks; + if (args->maxlen > agsize) + args->maxlen = agsize; + if (args->alignment == 0) + args->alignment = 1; + ASSERT(XFS_FSB_TO_AGNO(mp, args->fsbno) < mp->m_sb.sb_agcount); + ASSERT(XFS_FSB_TO_AGBNO(mp, args->fsbno) < agsize); + ASSERT(args->minlen <= args->maxlen); + ASSERT(args->minlen <= agsize); + ASSERT(args->mod < args->prod); + if (XFS_FSB_TO_AGNO(mp, args->fsbno) >= mp->m_sb.sb_agcount || + XFS_FSB_TO_AGBNO(mp, args->fsbno) >= agsize || + args->minlen > args->maxlen || args->minlen > agsize || + args->mod >= args->prod) { + args->fsbno = NULLFSBLOCK; + TRACE_ALLOC("badargs", args); + return 0; + } + switch (type) { + case XFS_ALLOCTYPE_THIS_AG: + case XFS_ALLOCTYPE_NEAR_BNO: + case XFS_ALLOCTYPE_THIS_BNO: + /* + * These three force us into a single a.g. + */ + args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); + mrlock(&mp->m_peraglock, MR_ACCESS, PINOD); + args->pag = &mp->m_perag[args->agno]; + minleft = args->minleft; + args->minleft = 0; + error = xfs_alloc_fix_freelist(args, 0); + args->minleft = minleft; + if (error) { + TRACE_ALLOC("nofix", args); + goto error0; + } + if (!args->agbp) { + mrunlock(&mp->m_peraglock); + TRACE_ALLOC("noagbp", args); + break; + } + args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); + if ((error = xfs_alloc_ag_vextent(args))) + goto error0; + mrunlock(&mp->m_peraglock); + break; + case XFS_ALLOCTYPE_START_BNO: + /* + * Try near allocation first, then anywhere-in-ag after + * the first a.g. fails. + */ + args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); + args->type = XFS_ALLOCTYPE_NEAR_BNO; + /* FALLTHROUGH */ + case XFS_ALLOCTYPE_ANY_AG: + case XFS_ALLOCTYPE_START_AG: + case XFS_ALLOCTYPE_FIRST_AG: + /* + * Rotate through the allocation groups looking for a winner. + */ + if (type == XFS_ALLOCTYPE_ANY_AG) { + /* + * Start with the last place we left off. + */ + args->agno = sagno = mp->m_agfrotor; + args->type = XFS_ALLOCTYPE_THIS_AG; + flags = XFS_ALLOC_FLAG_TRYLOCK; + } else if (type == XFS_ALLOCTYPE_FIRST_AG) { + /* + * Start with allocation group given by bno. + */ + args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); + args->type = XFS_ALLOCTYPE_THIS_AG; + sagno = 0; + flags = 0; + } else { + if (type == XFS_ALLOCTYPE_START_AG) + args->type = XFS_ALLOCTYPE_THIS_AG; + /* + * Start with the given allocation group. + */ + args->agno = sagno = XFS_FSB_TO_AGNO(mp, args->fsbno); + flags = XFS_ALLOC_FLAG_TRYLOCK; + } + /* + * Loop over allocation groups twice; first time with + * trylock set, second time without. + */ + for (;;) { + mrlock(&mp->m_peraglock, MR_ACCESS, PINOD); + args->pag = &mp->m_perag[args->agno]; + if ((error = xfs_alloc_fix_freelist(args, flags))) { + TRACE_ALLOC("nofix", args); + goto error0; + } + /* + * If we get a buffer back then the allocation will fly. + */ + if (args->agbp) { + if ((error = xfs_alloc_ag_vextent(args))) + goto error0; + mrunlock(&mp->m_peraglock); + break; + } + mrunlock(&mp->m_peraglock); + TRACE_ALLOC("loopfailed", args); + /* + * Didn't work, figure out the next iteration. + */ + if (args->agno == sagno && + type == XFS_ALLOCTYPE_START_BNO) + args->type = XFS_ALLOCTYPE_THIS_AG; + if (++(args->agno) == mp->m_sb.sb_agcount) + args->agno = 0; + /* + * Reached the starting a.g., must either be done + * or switch to non-trylock mode. + */ + if (args->agno == sagno) { + if (flags == 0) { + args->agbno = NULLAGBLOCK; + TRACE_ALLOC("allfailed", args); + break; + } + flags = 0; + if (type == XFS_ALLOCTYPE_START_BNO) { + args->agbno = XFS_FSB_TO_AGBNO(mp, + args->fsbno); + args->type = XFS_ALLOCTYPE_NEAR_BNO; + } + } + } + mp->m_agfrotor = (args->agno + 1) % mp->m_sb.sb_agcount; + break; + default: + ASSERT(0); + /* NOTREACHED */ + } + if (args->agbno == NULLAGBLOCK) + args->fsbno = NULLFSBLOCK; + else { + args->fsbno = XFS_AGB_TO_FSB(mp, args->agno, args->agbno); +#ifdef DEBUG + ASSERT(args->len >= args->minlen); + ASSERT(args->len <= args->maxlen); + ASSERT(args->agbno % args->alignment == 0); + XFS_AG_CHECK_DADDR(mp, XFS_FSB_TO_DADDR(mp, args->fsbno), + args->len); +#endif + } + return 0; +error0: + mrunlock(&mp->m_peraglock); + return error; +} + +/* + * Free an extent. + * Just break up the extent address and hand off to xfs_free_ag_extent + * after fixing up the freelist. + */ +int /* error */ +xfs_free_extent( + xfs_trans_t *tp, /* transaction pointer */ + xfs_fsblock_t bno, /* starting block number of extent */ + xfs_extlen_t len) /* length of extent */ +{ +#ifdef DEBUG + xfs_agf_t *agf; /* a.g. freespace header */ +#endif + xfs_alloc_arg_t args; /* allocation argument structure */ + int error; + + ASSERT(len != 0); + args.tp = tp; + args.mp = tp->t_mountp; + args.agno = XFS_FSB_TO_AGNO(args.mp, bno); + ASSERT(args.agno < args.mp->m_sb.sb_agcount); + args.agbno = XFS_FSB_TO_AGBNO(args.mp, bno); + args.alignment = 1; + args.minlen = args.minleft = args.minalignslop = 0; + mrlock(&args.mp->m_peraglock, MR_ACCESS, PINOD); + args.pag = &args.mp->m_perag[args.agno]; + if ((error = xfs_alloc_fix_freelist(&args, 0))) + goto error0; +#ifdef DEBUG + ASSERT(args.agbp != NULL); + agf = XFS_BUF_TO_AGF(args.agbp); + ASSERT(args.agbno + len <= INT_GET(agf->agf_length, ARCH_CONVERT)); +#endif + error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, + len, 0); +error0: + mrunlock(&args.mp->m_peraglock); + return error; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_alloc.h linux-2.4-xfs/linux/fs/xfs/xfs_alloc.h --- linux-2.4.7/linux/fs/xfs/xfs_alloc.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_alloc.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ALLOC_H__ +#define __XFS_ALLOC_H__ + +struct xfs_buf; +struct xfs_mount; +struct xfs_perag; +struct xfs_trans; + +/* + * Freespace allocation types. Argument to xfs_alloc_[v]extent. + */ +typedef enum xfs_alloctype +{ + XFS_ALLOCTYPE_ANY_AG, /* allocate anywhere, use rotor */ + XFS_ALLOCTYPE_FIRST_AG, /* ... start at ag 0 */ + XFS_ALLOCTYPE_START_AG, /* anywhere, start in this a.g. */ + XFS_ALLOCTYPE_THIS_AG, /* anywhere in this a.g. */ + XFS_ALLOCTYPE_START_BNO, /* near this block else anywhere */ + XFS_ALLOCTYPE_NEAR_BNO, /* in this a.g. and near this block */ + XFS_ALLOCTYPE_THIS_BNO /* at exactly this block */ +} xfs_alloctype_t; + +/* + * Flags for xfs_alloc_fix_freelist. + */ +#define XFS_ALLOC_FLAG_TRYLOCK 0x00000001 /* use trylock for buffer locking */ + +/* + * Argument structure for xfs_alloc routines. + * This is turned into a structure to avoid having 20 arguments passed + * down several levels of the stack. + */ +typedef struct xfs_alloc_arg { + struct xfs_trans *tp; /* transaction pointer */ + struct xfs_mount *mp; /* file system mount point */ + struct xfs_buf *agbp; /* buffer for a.g. freelist header */ + struct xfs_perag *pag; /* per-ag struct for this agno */ + xfs_fsblock_t fsbno; /* file system block number */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_agblock_t agbno; /* allocation group-relative block # */ + xfs_extlen_t minlen; /* minimum size of extent */ + xfs_extlen_t maxlen; /* maximum size of extent */ + xfs_extlen_t mod; /* mod value for extent size */ + xfs_extlen_t prod; /* prod value for extent size */ + xfs_extlen_t minleft; /* min blocks must be left after us */ + xfs_extlen_t total; /* total blocks needed in xaction */ + xfs_extlen_t alignment; /* align answer to multiple of this */ + xfs_extlen_t minalignslop; /* slop for minlen+alignment calcs */ + xfs_extlen_t len; /* output: actual size of extent */ + xfs_alloctype_t type; /* allocation type XFS_ALLOCTYPE_... */ + xfs_alloctype_t otype; /* original allocation type */ + char wasdel; /* set if allocation was prev delayed */ + char wasfromfl; /* set if allocation is from freelist */ + char isfl; /* set if is freelist blocks - !actg */ + char userdata; /* set if this is user data */ +} xfs_alloc_arg_t; + + +#ifdef __KERNEL__ + +/* + * Types for alloc tracing. + */ +#define XFS_ALLOC_KTRACE_ALLOC 1 +#define XFS_ALLOC_KTRACE_FREE 2 +#define XFS_ALLOC_KTRACE_MODAGF 3 +/* + * Allocation tracing buffer size. + */ +#define XFS_ALLOC_TRACE_SIZE 4096 + +#ifdef XFS_ALL_TRACE +#define XFS_ALLOC_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_ALLOC_TRACE +#endif + +/* + * Prototypes for visible xfs_alloc.c routines + */ + +/* + * Compute and fill in value of m_ag_maxlevels. + */ +void +xfs_alloc_compute_maxlevels( + struct xfs_mount *mp); /* file system mount structure */ + +/* + * Decide whether to use this allocation group for this allocation. + * If so, fix up the btree freelist's size. + * This is external so mkfs can call it, too. + */ +int /* error */ +xfs_alloc_fix_freelist( + xfs_alloc_arg_t *args, /* allocation argument structure */ + int flags); /* XFS_ALLOC_FLAG_... */ + +/* + * Get a block from the freelist. + * Returns with the buffer for the block gotten. + */ +int /* error */ +xfs_alloc_get_freelist( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_buf *agbp, /* buffer containing the agf structure */ + xfs_agblock_t *bnop); /* block address retrieved from freelist */ + +/* + * Log the given fields from the agf structure. + */ +void +xfs_alloc_log_agf( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_buf *bp, /* buffer for a.g. freelist header */ + int fields);/* mask of fields to be logged (XFS_AGF_...) */ + +/* + * Interface for inode allocation to force the pag data to be initialized. + */ +int /* error */ +xfs_alloc_pagf_init( + struct xfs_mount *mp, /* file system mount structure */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + int flags); /* XFS_ALLOC_FLAGS_... */ + +/* + * Put the block on the freelist for the allocation group. + */ +int /* error */ +xfs_alloc_put_freelist( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_buf *agbp, /* buffer for a.g. freelist header */ + struct xfs_buf *agflbp,/* buffer for a.g. free block array */ + xfs_agblock_t bno); /* block being freed */ + +/* + * Read in the allocation group header (free/alloc section). + */ +int /* error */ +xfs_alloc_read_agf( + struct xfs_mount *mp, /* mount point structure */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + int flags, /* XFS_ALLOC_FLAG_... */ + struct xfs_buf **bpp); /* buffer for the ag freelist header */ + +/* + * Allocate an extent (variable-size). + */ +int /* error */ +xfs_alloc_vextent( + xfs_alloc_arg_t *args); /* allocation argument structure */ + +/* + * Free an extent. + */ +int /* error */ +xfs_free_extent( + struct xfs_trans *tp, /* transaction pointer */ + xfs_fsblock_t bno, /* starting block number of extent */ + xfs_extlen_t len); /* length of extent */ + +#endif /* __KERNEL__ */ + +#endif /* __XFS_ALLOC_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_alloc_btree.c linux-2.4-xfs/linux/fs/xfs/xfs_alloc_btree.c --- linux-2.4.7/linux/fs/xfs/xfs_alloc_btree.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_alloc_btree.c Wed Apr 18 21:37:23 2001 @@ -0,0 +1,2155 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Free space allocation for XFS. + */ + +#include + +/* + * Prototypes for internal functions. + */ + +STATIC void xfs_alloc_log_block(xfs_trans_t *, xfs_buf_t *, int); +STATIC void xfs_alloc_log_keys(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC void xfs_alloc_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC void xfs_alloc_log_recs(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC int xfs_alloc_lshift(xfs_btree_cur_t *, int, int *); +STATIC int xfs_alloc_newroot(xfs_btree_cur_t *, int *); +STATIC int xfs_alloc_rshift(xfs_btree_cur_t *, int, int *); +STATIC int xfs_alloc_split(xfs_btree_cur_t *, int, xfs_agblock_t *, + xfs_alloc_key_t *, xfs_btree_cur_t **, int *); +STATIC int xfs_alloc_updkey(xfs_btree_cur_t *, xfs_alloc_key_t *, int); + +/* + * Internal functions. + */ + +/* + * Single level of the xfs_alloc_delete record deletion routine. + * Delete record pointed to by cur/level. + * Remove the record from its block then rebalance the tree. + * Return 0 for error, 1 for done, 2 to go on to the next level. + */ +STATIC int /* error */ +xfs_alloc_delrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level removing record from */ + int *stat) /* fail/done/go-on */ +{ + xfs_agf_t *agf; /* allocation group freelist header */ + xfs_alloc_block_t *block; /* btree block record/key lives in */ + xfs_agblock_t bno; /* btree block number */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ + int i; /* loop index */ + xfs_alloc_key_t key; /* kp points here if block is level 0 */ + xfs_agblock_t lbno; /* left block's block number */ + xfs_buf_t *lbp; /* left block's buffer pointer */ + xfs_alloc_block_t *left; /* left btree block */ + xfs_alloc_key_t *lkp=NULL; /* left block key pointer */ + xfs_alloc_ptr_t *lpp=NULL; /* left block address pointer */ + int lrecs=0; /* number of records in left block */ + xfs_alloc_rec_t *lrp; /* left block record pointer */ + xfs_mount_t *mp; /* mount structure */ + int ptr; /* index in btree block for this rec */ + xfs_agblock_t rbno; /* right block's block number */ + xfs_buf_t *rbp; /* right block's buffer pointer */ + xfs_alloc_block_t *right; /* right btree block */ + xfs_alloc_key_t *rkp; /* right block key pointer */ + xfs_alloc_ptr_t *rpp; /* right block address pointer */ + int rrecs=0; /* number of records in right block */ + xfs_alloc_rec_t *rrp; /* right block record pointer */ + xfs_btree_cur_t *tcur; /* temporary btree cursor */ + + /* + * Get the index of the entry being deleted, check for nothing there. + */ + ptr = cur->bc_ptrs[level]; + if (ptr == 0) { + *stat = 0; + return 0; + } + /* + * Get the buffer & block containing the record or key/ptr. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; +#endif + /* + * Fail if we're off the end of the block. + */ + if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + *stat = 0; + return 0; + } + XFS_STATS_INC(xfsstats.xs_abt_delrec); + /* + * It's a nonleaf. Excise the key and ptr being deleted, by + * sliding the entries past them down one. + * Log the changed areas of the block. + */ + if (level > 0) { + lkp = XFS_ALLOC_KEY_ADDR(block, 1, cur); + lpp = XFS_ALLOC_PTR_ADDR(block, 1, cur); +#ifdef DEBUG + for (i = ptr; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(lpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ovbcopy(&lkp[ptr], &lkp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*lkp)); /* INT_: mem copy */ + ovbcopy(&lpp[ptr], &lpp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*lpp)); /* INT_: mem copy */ + xfs_alloc_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + xfs_alloc_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + } + } + /* + * It's a leaf. Excise the record being deleted, by sliding the + * entries past it down one. Log the changed areas of the block. + */ + else { + lrp = XFS_ALLOC_REC_ADDR(block, 1, cur); + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ovbcopy(&lrp[ptr], &lrp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*lrp)); + xfs_alloc_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + } + /* + * If it's the first record in the block, we'll need a key + * structure to pass up to the next level (updkey). + */ + if (ptr == 1) { + key.ar_startblock = lrp->ar_startblock; /* INT_: direct copy */ + key.ar_blockcount = lrp->ar_blockcount; /* INT_: direct copy */ + lkp = &key; + } + } + /* + * Decrement and log the number of entries in the block. + */ + INT_MOD(block->bb_numrecs, ARCH_CONVERT, -1); + xfs_alloc_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS); + /* + * See if the longest free extent in the allocation group was + * changed by this operation. True if it's the by-size btree, and + * this is the leaf level, and there is no right sibling block, + * and this was the last record. + */ + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + mp = cur->bc_mp; + + if (level == 0 && + cur->bc_btnum == XFS_BTNUM_CNT && + INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK && + ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ASSERT(ptr == INT_GET(block->bb_numrecs, ARCH_CONVERT) + 1); + /* + * There are still records in the block. Grab the size + * from the last one. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + rrp = XFS_ALLOC_REC_ADDR(block, INT_GET(block->bb_numrecs, ARCH_CONVERT), cur); + INT_COPY(agf->agf_longest, rrp->ar_blockcount, ARCH_CONVERT); + } + /* + * No free extents left. + */ + else + INT_ZERO(agf->agf_longest, ARCH_CONVERT); + mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)].pagf_longest = + INT_GET(agf->agf_longest, ARCH_CONVERT); + xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, + XFS_AGF_LONGEST); + } + /* + * Is this the root level? If so, we're almost done. + */ + if (level == cur->bc_nlevels - 1) { + /* + * If this is the root level, + * and there's only one entry left, + * and it's NOT the leaf level, + * then we can get rid of this level. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) == 1 && level > 0) { + /* + * lpp is still set to the first pointer in the block. + * Make it the new root of the btree. + */ + bno = INT_GET(agf->agf_roots[cur->bc_btnum], ARCH_CONVERT); + INT_COPY(agf->agf_roots[cur->bc_btnum], *lpp, ARCH_CONVERT); + INT_MOD(agf->agf_levels[cur->bc_btnum], ARCH_CONVERT, -1); + mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)].pagf_levels[cur->bc_btnum]--; + /* + * Put this buffer/block on the ag's freelist. + */ + if ((error = xfs_alloc_put_freelist(cur->bc_tp, + cur->bc_private.a.agbp, NULL, bno))) + return error; + xfs_trans_agbtree_delta(cur->bc_tp, -1); + xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, + XFS_AGF_ROOTS | XFS_AGF_LEVELS); + /* + * Update the cursor so there's one fewer level. + */ + xfs_btree_setbuf(cur, level, 0); + cur->bc_nlevels--; + } else if (level > 0 && + (error = xfs_alloc_decrement(cur, level, &i))) + return error; + *stat = 1; + return 0; + } + /* + * If we deleted the leftmost entry in the block, update the + * key values above us in the tree. + */ + if (ptr == 1 && (error = xfs_alloc_updkey(cur, lkp, level + 1))) + return error; + /* + * If the number of records remaining in the block is at least + * the minimum, we're done. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) >= XFS_ALLOC_BLOCK_MINRECS(level, cur)) { + if (level > 0 && (error = xfs_alloc_decrement(cur, level, &i))) + return error; + *stat = 1; + return 0; + } + /* + * Otherwise, we have to move some records around to keep the + * tree balanced. Look at the left and right sibling blocks to + * see if we can re-balance by moving only one record. + */ + rbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + lbno = INT_GET(block->bb_leftsib, ARCH_CONVERT); + bno = NULLAGBLOCK; + ASSERT(rbno != NULLAGBLOCK || lbno != NULLAGBLOCK); + /* + * Duplicate the cursor so our btree manipulations here won't + * disrupt the next level up. + */ + if ((error = xfs_btree_dup_cursor(cur, &tcur))) + return error; + /* + * If there's a right sibling, see if it's ok to shift an entry + * out of it. + */ + if (rbno != NULLAGBLOCK) { + /* + * Move the temp cursor to the last entry in the next block. + * Actually any entry but the first would suffice. + */ + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_increment(tcur, level, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Grab a pointer to the block. + */ + rbp = tcur->bc_bufs[level]; + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + goto error0; +#endif + /* + * Grab the current block number, for future use. + */ + bno = INT_GET(right->bb_leftsib, ARCH_CONVERT); + /* + * If right block is full enough so that removing one entry + * won't make it too empty, and left-shifting an entry out + * of right to us works, we're done. + */ + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_ALLOC_BLOCK_MINRECS(level, cur)) { + if ((error = xfs_alloc_lshift(tcur, level, &i))) + goto error0; + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_ALLOC_BLOCK_MINRECS(level, cur)); + xfs_btree_del_cursor(tcur, + XFS_BTREE_NOERROR); + if (level > 0 && + (error = xfs_alloc_decrement(cur, level, + &i))) + return error; + *stat = 1; + return 0; + } + } + /* + * Otherwise, grab the number of records in right for + * future reference, and fix up the temp cursor to point + * to our block again (last record). + */ + rrecs = INT_GET(right->bb_numrecs, ARCH_CONVERT); + if (lbno != NULLAGBLOCK) { + i = xfs_btree_firstrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_decrement(tcur, level, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + } + /* + * If there's a left sibling, see if it's ok to shift an entry + * out of it. + */ + if (lbno != NULLAGBLOCK) { + /* + * Move the temp cursor to the first entry in the + * previous block. + */ + i = xfs_btree_firstrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_decrement(tcur, level, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + xfs_btree_firstrec(tcur, level); + /* + * Grab a pointer to the block. + */ + lbp = tcur->bc_bufs[level]; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + goto error0; +#endif + /* + * Grab the current block number, for future use. + */ + bno = INT_GET(left->bb_rightsib, ARCH_CONVERT); + /* + * If left block is full enough so that removing one entry + * won't make it too empty, and right-shifting an entry out + * of left to us works, we're done. + */ + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_ALLOC_BLOCK_MINRECS(level, cur)) { + if ((error = xfs_alloc_rshift(tcur, level, &i))) + goto error0; + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_ALLOC_BLOCK_MINRECS(level, cur)); + xfs_btree_del_cursor(tcur, + XFS_BTREE_NOERROR); + if (level == 0) + cur->bc_ptrs[0]++; + *stat = 1; + return 0; + } + } + /* + * Otherwise, grab the number of records in right for + * future reference. + */ + lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + /* + * Delete the temp cursor, we're done with it. + */ + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + /* + * If here, we need to do a join to keep the tree balanced. + */ + ASSERT(bno != NULLAGBLOCK); + /* + * See if we can join with the left neighbor block. + */ + if (lbno != NULLAGBLOCK && + lrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { + /* + * Set "right" to be the starting block, + * "left" to be the left neighbor. + */ + rbno = bno; + right = block; + rbp = bp; + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + cur->bc_private.a.agno, lbno, 0, &lbp, + XFS_ALLOC_BTREE_REF))) + return error; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; + } + /* + * If that won't work, see if we can join with the right neighbor block. + */ + else if (rbno != NULLAGBLOCK && + rrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= + XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { + /* + * Set "left" to be the starting block, + * "right" to be the right neighbor. + */ + lbno = bno; + left = block; + lbp = bp; + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + cur->bc_private.a.agno, rbno, 0, &rbp, + XFS_ALLOC_BTREE_REF))) + return error; + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + return error; + } + /* + * Otherwise, we can't fix the imbalance. + * Just return. This is probably a logic error, but it's not fatal. + */ + else { + if (level > 0 && (error = xfs_alloc_decrement(cur, level, &i))) + return error; + *stat = 1; + return 0; + } + /* + * We're now going to join "left" and "right" by moving all the stuff + * in "right" to "left" and deleting "right". + */ + if (level > 0) { + /* + * It's a non-leaf. Move keys and pointers. + */ + lkp = XFS_ALLOC_KEY_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + lpp = XFS_ALLOC_PTR_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur); + rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + bcopy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp)); /* INT_: structure copy */ + bcopy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp)); /* INT_: structure copy */ + xfs_alloc_log_keys(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_alloc_log_ptrs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } else { + /* + * It's a leaf. Move records. + */ + lrp = XFS_ALLOC_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rrp = XFS_ALLOC_REC_ADDR(right, 1, cur); + bcopy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp)); + xfs_alloc_log_recs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } + /* + * If we joined with the left neighbor, set the buffer in the + * cursor to the left block, and fix up the index. + */ + if (bp != lbp) { + xfs_btree_setbuf(cur, level, lbp); + cur->bc_ptrs[level] += INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + /* + * If we joined with the right neighbor and there's a level above + * us, increment the cursor at that level. + */ + else if (level + 1 < cur->bc_nlevels && + (error = xfs_alloc_increment(cur, level + 1, &i))) + return error; + /* + * Fix up the number of records in the surviving block. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + /* + * Fix up the right block pointer in the surviving block, and log it. + */ + left->bb_rightsib = right->bb_rightsib; /* INT_: direct copy */ + xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); + /* + * If there is a right sibling now, make it point to the + * remaining block. + */ + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_alloc_block_t *rrblock; + xfs_buf_t *rrbp; + + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + cur->bc_private.a.agno, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, + &rrbp, XFS_ALLOC_BTREE_REF))) + return error; + rrblock = XFS_BUF_TO_ALLOC_BLOCK(rrbp); + if ((error = xfs_btree_check_sblock(cur, rrblock, level, rrbp))) + return error; + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, lbno); + xfs_alloc_log_block(cur->bc_tp, rrbp, XFS_BB_LEFTSIB); + } + /* + * Free the deleting block by putting it on the freelist. + */ + if ((error = xfs_alloc_put_freelist(cur->bc_tp, cur->bc_private.a.agbp, + NULL, rbno))) + return error; + xfs_trans_agbtree_delta(cur->bc_tp, -1); + /* + * Adjust the current level's cursor so that we're left referring + * to the right node, after we're done. + * If this leaves the ptr value 0 our caller will fix it up. + */ + if (level > 0) + cur->bc_ptrs[level]--; + /* + * Return value means the next level up has something to do. + */ + *stat = 2; + return 0; + +error0: + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; +} + +/* + * Insert one record/level. Return information to the caller + * allowing the next level up to proceed if necessary. + */ +STATIC int /* error */ +xfs_alloc_insrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to insert record at */ + xfs_agblock_t *bnop, /* i/o: block number inserted */ + xfs_alloc_rec_t *recp, /* i/o: record data inserted */ + xfs_btree_cur_t **curp, /* output: new cursor replacing cur */ + int *stat) /* output: success/failure */ +{ + xfs_agf_t *agf; /* allocation group freelist header */ + xfs_alloc_block_t *block; /* btree block record/key lives in */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ + int i; /* loop index */ + xfs_alloc_key_t key; /* key value being inserted */ + xfs_alloc_key_t *kp; /* pointer to btree keys */ + xfs_agblock_t nbno; /* block number of allocated block */ + xfs_btree_cur_t *ncur; /* new cursor to be used at next lvl */ + xfs_alloc_key_t nkey; /* new key value, from split */ + xfs_alloc_rec_t nrec; /* new record value, for caller */ + int optr; /* old ptr value */ + xfs_alloc_ptr_t *pp; /* pointer to btree addresses */ + int ptr; /* index in btree block for this rec */ + xfs_alloc_rec_t *rp; /* pointer to btree records */ + + ASSERT(INT_GET(recp->ar_blockcount, ARCH_CONVERT) > 0); + /* + * If we made it to the root level, allocate a new root block + * and we're done. + */ + if (level >= cur->bc_nlevels) { + XFS_STATS_INC(xfsstats.xs_abt_insrec); + if ((error = xfs_alloc_newroot(cur, &i))) + return error; + *bnop = NULLAGBLOCK; + *stat = i; + return 0; + } + /* + * Make a key out of the record data to be inserted, and save it. + */ + key.ar_startblock = recp->ar_startblock; /* INT_: direct copy */ + key.ar_blockcount = recp->ar_blockcount; /* INT_: direct copy */ + optr = ptr = cur->bc_ptrs[level]; + /* + * If we're off the left edge, return failure. + */ + if (ptr == 0) { + *stat = 0; + return 0; + } + XFS_STATS_INC(xfsstats.xs_abt_insrec); + /* + * Get pointers to the btree buffer and block. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; + /* + * Check that the new entry is being inserted in the right place. + */ + if (ptr <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + if (level == 0) { + rp = XFS_ALLOC_REC_ADDR(block, ptr, cur); + xfs_btree_check_rec(cur->bc_btnum, recp, rp); + } else { + kp = XFS_ALLOC_KEY_ADDR(block, ptr, cur); + xfs_btree_check_key(cur->bc_btnum, &key, kp); + } + } +#endif + nbno = NULLAGBLOCK; + ncur = (xfs_btree_cur_t *)0; + /* + * If the block is full, we can't insert the new entry until we + * make the block un-full. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { + /* + * First, try shifting an entry to the right neighbor. + */ + if ((error = xfs_alloc_rshift(cur, level, &i))) + return error; + if (i) { + /* nothing */ + } + /* + * Next, try shifting an entry to the left neighbor. + */ + else { + if ((error = xfs_alloc_lshift(cur, level, &i))) + return error; + if (i) + optr = ptr = cur->bc_ptrs[level]; + else { + /* + * Next, try splitting the current block in + * half. If this works we have to re-set our + * variables because we could be in a + * different block now. + */ + if ((error = xfs_alloc_split(cur, level, &nbno, + &nkey, &ncur, &i))) + return error; + if (i) { + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = + xfs_btree_check_sblock(cur, + block, level, bp))) + return error; +#endif + ptr = cur->bc_ptrs[level]; + nrec.ar_startblock = nkey.ar_startblock; /* INT_: direct copy */ + nrec.ar_blockcount = nkey.ar_blockcount; /* INT_: direct copy */ + } + /* + * Otherwise the insert fails. + */ + else { + *stat = 0; + return 0; + } + } + } + } + /* + * At this point we know there's room for our new entry in the block + * we're pointing at. + */ + if (level > 0) { + /* + * It's a non-leaf entry. Make a hole for the new data + * in the key and ptr regions of the block. + */ + kp = XFS_ALLOC_KEY_ADDR(block, 1, cur); + pp = XFS_ALLOC_PTR_ADDR(block, 1, cur); +#ifdef DEBUG + for (i = INT_GET(block->bb_numrecs, ARCH_CONVERT); i >= ptr; i--) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(pp[i - 1], ARCH_CONVERT), level))) + return error; + } +#endif + ovbcopy(&kp[ptr - 1], &kp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*kp)); /* INT_: copy */ + ovbcopy(&pp[ptr - 1], &pp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*pp)); /* INT_: copy */ +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, *bnop, level))) + return error; +#endif + /* + * Now stuff the new data in, bump numrecs and log the new data. + */ + kp[ptr - 1] = key; + INT_SET(pp[ptr - 1], ARCH_CONVERT, *bnop); + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_alloc_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + xfs_alloc_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); +#ifdef DEBUG + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) + xfs_btree_check_key(cur->bc_btnum, kp + ptr - 1, + kp + ptr); +#endif + } else { + /* + * It's a leaf entry. Make a hole for the new record. + */ + rp = XFS_ALLOC_REC_ADDR(block, 1, cur); + ovbcopy(&rp[ptr - 1], &rp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*rp)); + /* + * Now stuff the new record in, bump numrecs + * and log the new data. + */ + rp[ptr - 1] = *recp; /* INT_: struct copy */ + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_alloc_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); +#ifdef DEBUG + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) + xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1, + rp + ptr); +#endif + } + /* + * Log the new number of records in the btree header. + */ + xfs_alloc_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS); + /* + * If we inserted at the start of a block, update the parents' keys. + */ + if (optr == 1 && (error = xfs_alloc_updkey(cur, &key, level + 1))) + return error; + /* + * Look to see if the longest extent in the allocation group + * needs to be updated. + */ + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + if (level == 0 && + cur->bc_btnum == XFS_BTNUM_CNT && + INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK && + INT_GET(recp->ar_blockcount, ARCH_CONVERT) > INT_GET(agf->agf_longest, ARCH_CONVERT)) { + /* + * If this is a leaf in the by-size btree and there + * is no right sibling block and this block is bigger + * than the previous longest block, update it. + */ + INT_COPY(agf->agf_longest, recp->ar_blockcount, ARCH_CONVERT); + cur->bc_mp->m_perag[INT_GET(agf->agf_seqno, ARCH_CONVERT)].pagf_longest + = INT_GET(recp->ar_blockcount, ARCH_CONVERT); + xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, + XFS_AGF_LONGEST); + } + /* + * Return the new block number, if any. + * If there is one, give back a record value and a cursor too. + */ + *bnop = nbno; + if (nbno != NULLAGBLOCK) { + *recp = nrec; /* INT_: struct copy */ + *curp = ncur; /* INT_: struct copy */ + } + *stat = 1; + return 0; +} + +/* + * Log header fields from a btree block. + */ +STATIC void +xfs_alloc_log_block( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *bp, /* buffer containing btree block */ + int fields) /* mask of fields: XFS_BB_... */ +{ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + static const short offsets[] = { /* table of offsets */ + offsetof(xfs_alloc_block_t, bb_magic), + offsetof(xfs_alloc_block_t, bb_level), + offsetof(xfs_alloc_block_t, bb_numrecs), + offsetof(xfs_alloc_block_t, bb_leftsib), + offsetof(xfs_alloc_block_t, bb_rightsib), + sizeof(xfs_alloc_block_t) + }; + + xfs_btree_offsets(fields, offsets, XFS_BB_NUM_BITS, &first, &last); + xfs_trans_log_buf(tp, bp, first, last); +} + +/* + * Log keys from a btree block (nonleaf). + */ +STATIC void +xfs_alloc_log_keys( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int kfirst, /* index of first key to log */ + int klast) /* index of last key to log */ +{ + xfs_alloc_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + xfs_alloc_key_t *kp; /* key pointer in btree block */ + int last; /* last byte offset logged */ + + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + kp = XFS_ALLOC_KEY_ADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&kp[kfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&kp[klast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Log block pointer fields from a btree block (nonleaf). + */ +STATIC void +xfs_alloc_log_ptrs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int pfirst, /* index of first pointer to log */ + int plast) /* index of last pointer to log */ +{ + xfs_alloc_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + xfs_alloc_ptr_t *pp; /* block-pointer pointer in btree blk */ + + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + pp = XFS_ALLOC_PTR_ADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&pp[pfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&pp[plast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Log records from a btree block (leaf). + */ +STATIC void +xfs_alloc_log_recs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int rfirst, /* index of first record to log */ + int rlast) /* index of last record to log */ +{ + xfs_alloc_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + xfs_alloc_rec_t *rp; /* record pointer for btree block */ + + + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + rp = XFS_ALLOC_REC_ADDR(block, 1, cur); +#ifdef DEBUG + { + xfs_agf_t *agf; + xfs_alloc_rec_t *p; + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + for (p = &rp[rfirst - 1]; p <= &rp[rlast - 1]; p++) + ASSERT(INT_GET(p->ar_startblock, ARCH_CONVERT) + INT_GET(p->ar_blockcount, ARCH_CONVERT) <= + INT_GET(agf->agf_length, ARCH_CONVERT)); + } +#endif + first = (int)((xfs_caddr_t)&rp[rfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&rp[rlast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Lookup the record. The cursor is made to point to it, based on dir. + * Return 0 if can't find any such record, 1 for success. + */ +STATIC int /* error */ +xfs_alloc_lookup( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_lookup_t dir, /* <=, ==, or >= */ + int *stat) /* success/failure */ +{ + xfs_agblock_t agbno; /* a.g. relative btree block number */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_alloc_block_t *block=NULL; /* current btree block */ + int diff; /* difference for the current key */ + int error; /* error return value */ + int keyno=0; /* current key number */ + int level; /* level in the btree */ + xfs_mount_t *mp; /* file system mount point */ + + XFS_STATS_INC(xfsstats.xs_abt_lookup); + /* + * Get the allocation group header, and the root block number. + */ + mp = cur->bc_mp; + + { + xfs_agf_t *agf; /* a.g. freespace header */ + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + agno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + agbno = INT_GET(agf->agf_roots[cur->bc_btnum], ARCH_CONVERT); + } + /* + * Iterate over each level in the btree, starting at the root. + * For each level above the leaves, find the key we need, based + * on the lookup record, then follow the corresponding block + * pointer down to the next level. + */ + for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) { + xfs_buf_t *bp; /* buffer pointer for btree block */ + xfs_daddr_t d; /* disk address of btree block */ + + /* + * Get the disk address we're looking for. + */ + d = XFS_AGB_TO_DADDR(mp, agno, agbno); + /* + * If the old buffer at this level is for a different block, + * throw it away, otherwise just use it. + */ + bp = cur->bc_bufs[level]; + if (bp && XFS_BUF_ADDR(bp) != d) + bp = (xfs_buf_t *)0; + if (!bp) { + /* + * Need to get a new buffer. Read it, then + * set it in the cursor, releasing the old one. + */ + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, agno, + agbno, 0, &bp, XFS_ALLOC_BTREE_REF))) + return error; + xfs_btree_setbuf(cur, level, bp); + /* + * Point to the btree block, now that we have the buffer + */ + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, level, + bp))) + return error; + } else + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + /* + * If we already had a key match at a higher level, we know + * we need to use the first entry in this block. + */ + if (diff == 0) + keyno = 1; + /* + * Otherwise we need to search this block. Do a binary search. + */ + else { + int high; /* high entry number */ + xfs_alloc_key_t *kkbase=NULL;/* base of keys in block */ + xfs_alloc_rec_t *krbase=NULL;/* base of records in block */ + int low; /* low entry number */ + + /* + * Get a pointer to keys or records. + */ + if (level > 0) + kkbase = XFS_ALLOC_KEY_ADDR(block, 1, cur); + else + krbase = XFS_ALLOC_REC_ADDR(block, 1, cur); + /* + * Set low and high entry numbers, 1-based. + */ + low = 1; + if (!(high = INT_GET(block->bb_numrecs, ARCH_CONVERT))) { + /* + * If the block is empty, the tree must + * be an empty leaf. + */ + ASSERT(level == 0 && cur->bc_nlevels == 1); + cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE; + *stat = 0; + return 0; + } + /* + * Binary search the block. + */ + while (low <= high) { + xfs_extlen_t blockcount; /* key value */ + xfs_agblock_t startblock; /* key value */ + + XFS_STATS_INC(xfsstats.xs_abt_compare); + /* + * keyno is average of low and high. + */ + keyno = (low + high) >> 1; + /* + * Get startblock & blockcount. + */ + if (level > 0) { + xfs_alloc_key_t *kkp; + + kkp = kkbase + keyno - 1; + startblock = INT_GET(kkp->ar_startblock, ARCH_CONVERT); + blockcount = INT_GET(kkp->ar_blockcount, ARCH_CONVERT); + } else { + xfs_alloc_rec_t *krp; + + krp = krbase + keyno - 1; + startblock = INT_GET(krp->ar_startblock, ARCH_CONVERT); + blockcount = INT_GET(krp->ar_blockcount, ARCH_CONVERT); + } + /* + * Compute difference to get next direction. + */ + if (cur->bc_btnum == XFS_BTNUM_BNO) + diff = (int)startblock - + (int)cur->bc_rec.a.ar_startblock; + else if (!(diff = (int)blockcount - + (int)cur->bc_rec.a.ar_blockcount)) + diff = (int)startblock - + (int)cur->bc_rec.a.ar_startblock; + /* + * Less than, move right. + */ + if (diff < 0) + low = keyno + 1; + /* + * Greater than, move left. + */ + else if (diff > 0) + high = keyno - 1; + /* + * Equal, we're done. + */ + else + break; + } + } + /* + * If there are more levels, set up for the next level + * by getting the block number and filling in the cursor. + */ + if (level > 0) { + /* + * If we moved left, need the previous key number, + * unless there isn't one. + */ + if (diff > 0 && --keyno < 1) + keyno = 1; + agbno = INT_GET(*XFS_ALLOC_PTR_ADDR(block, keyno, cur), ARCH_CONVERT); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, agbno, level))) + return error; +#endif + cur->bc_ptrs[level] = keyno; + } + } + /* + * Done with the search. + * See if we need to adjust the results. + */ + if (dir != XFS_LOOKUP_LE && diff < 0) { + keyno++; + /* + * If ge search and we went off the end of the block, but it's + * not the last block, we're in the wrong block. + */ + if (dir == XFS_LOOKUP_GE && + keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT) && + INT_GET(block->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + int i; + + cur->bc_ptrs[0] = keyno; + if ((error = xfs_alloc_increment(cur, 0, &i))) + return error; + XFS_WANT_CORRUPTED_RETURN(i == 1); + *stat = 1; + return 0; + } + } + else if (dir == XFS_LOOKUP_LE && diff > 0) + keyno--; + cur->bc_ptrs[0] = keyno; + /* + * Return if we succeeded or not. + */ + if (keyno == 0 || keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT)) + *stat = 0; + else + *stat = ((dir != XFS_LOOKUP_EQ) || (diff == 0)); + return 0; +} + +/* + * Move 1 record left from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_alloc_lshift( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to shift record on */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef DEBUG + int i; /* loop index */ +#endif + xfs_alloc_key_t key; /* key value for leaf level upward */ + xfs_buf_t *lbp; /* buffer for left neighbor block */ + xfs_alloc_block_t *left; /* left neighbor btree block */ + int nrec; /* new number of left block entries */ + xfs_buf_t *rbp; /* buffer for right (current) block */ + xfs_alloc_block_t *right; /* right (current) btree block */ + xfs_alloc_key_t *rkp=NULL; /* key pointer for right block */ + xfs_alloc_ptr_t *rpp=NULL; /* address pointer for right block */ + xfs_alloc_rec_t *rrp=NULL; /* record pointer for right block */ + + /* + * Set up variables for this block as "right". + */ + rbp = cur->bc_bufs[level]; + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + return error; +#endif + /* + * If we've got no left sibling then we can't shift an entry left. + */ + if (INT_GET(right->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * If the cursor entry is the one that would be moved, don't + * do it... it's too complicated. + */ + if (cur->bc_ptrs[level] <= 1) { + *stat = 0; + return 0; + } + /* + * Set up the left neighbor as "left". + */ + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.a.agno, INT_GET(right->bb_leftsib, ARCH_CONVERT), 0, &lbp, + XFS_ALLOC_BTREE_REF))) + return error; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; + /* + * If it's full, it can't take another entry. + */ + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { + *stat = 0; + return 0; + } + nrec = INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1; + /* + * If non-leaf, copy a key and a ptr to the left block. + */ + if (level > 0) { + xfs_alloc_key_t *lkp; /* key pointer for left block */ + xfs_alloc_ptr_t *lpp; /* address pointer for left block */ + + lkp = XFS_ALLOC_KEY_ADDR(left, nrec, cur); + rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur); + *lkp = *rkp; + xfs_alloc_log_keys(cur, lbp, nrec, nrec); + lpp = XFS_ALLOC_PTR_ADDR(left, nrec, cur); + rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, INT_GET(*rpp, ARCH_CONVERT), level))) + return error; +#endif + *lpp = *rpp; /* INT_: copy */ + xfs_alloc_log_ptrs(cur, lbp, nrec, nrec); + xfs_btree_check_key(cur->bc_btnum, lkp - 1, lkp); + } + /* + * If leaf, copy a record to the left block. + */ + else { + xfs_alloc_rec_t *lrp; /* record pointer for left block */ + + lrp = XFS_ALLOC_REC_ADDR(left, nrec, cur); + rrp = XFS_ALLOC_REC_ADDR(right, 1, cur); + *lrp = *rrp; + xfs_alloc_log_recs(cur, lbp, nrec, nrec); + xfs_btree_check_rec(cur->bc_btnum, lrp - 1, lrp); + } + /* + * Bump and log left's numrecs, decrement and log right's numrecs. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, +1); + xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); + INT_MOD(right->bb_numrecs, ARCH_CONVERT, -1); + xfs_alloc_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); + /* + * Slide the contents of right down one entry. + */ + if (level > 0) { +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i + 1], ARCH_CONVERT), + level))) + return error; + } +#endif + ovbcopy(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); + xfs_alloc_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_alloc_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } else { + ovbcopy(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_alloc_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + key.ar_startblock = rrp->ar_startblock; /* INT_: direct copy */ + key.ar_blockcount = rrp->ar_blockcount; /* INT_: direct copy */ + rkp = &key; + } + /* + * Update the parent key values of right. + */ + if ((error = xfs_alloc_updkey(cur, rkp, level + 1))) + return error; + /* + * Slide the cursor value left one. + */ + cur->bc_ptrs[level]--; + *stat = 1; + return 0; +} + +/* + * Allocate a new root block, fill it in. + */ +STATIC int /* error */ +xfs_alloc_newroot( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + xfs_agblock_t lbno; /* left block number */ + xfs_buf_t *lbp; /* left btree buffer */ + xfs_alloc_block_t *left; /* left btree block */ + xfs_mount_t *mp; /* mount structure */ + xfs_agblock_t nbno; /* new block number */ + xfs_buf_t *nbp; /* new (root) buffer */ + xfs_alloc_block_t *new; /* new (root) btree block */ + int nptr; /* new value for key index, 1 or 2 */ + xfs_agblock_t rbno; /* right block number */ + xfs_buf_t *rbp; /* right btree buffer */ + xfs_alloc_block_t *right; /* right btree block */ + + mp = cur->bc_mp; + + ASSERT(cur->bc_nlevels < XFS_AG_MAXLEVELS(mp)); + /* + * Get a buffer from the freelist blocks, for the new root. + */ + if ((error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp, + &nbno))) + return error; + /* + * None available, we fail. + */ + if (nbno == NULLAGBLOCK) { + *stat = 0; + return 0; + } + xfs_trans_agbtree_delta(cur->bc_tp, 1); + nbp = xfs_btree_get_bufs(mp, cur->bc_tp, cur->bc_private.a.agno, nbno, + 0); + new = XFS_BUF_TO_ALLOC_BLOCK(nbp); + /* + * Set the root data in the a.g. freespace structure. + */ + { + xfs_agf_t *agf; /* a.g. freespace header */ + xfs_agnumber_t seqno; + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + INT_SET(agf->agf_roots[cur->bc_btnum], ARCH_CONVERT, nbno); + INT_MOD(agf->agf_levels[cur->bc_btnum], ARCH_CONVERT, 1); + seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + mp->m_perag[seqno].pagf_levels[cur->bc_btnum]++; + xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, + XFS_AGF_ROOTS | XFS_AGF_LEVELS); + } + /* + * At the previous root level there are now two blocks: the old + * root, and the new block generated when it was split. + * We don't know which one the cursor is pointing at, so we + * set up variables "left" and "right" for each case. + */ + lbp = cur->bc_bufs[cur->bc_nlevels - 1]; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, cur->bc_nlevels - 1, lbp))) + return error; +#endif + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + /* + * Our block is left, pick up the right block. + */ + lbno = XFS_DADDR_TO_AGBNO(mp, XFS_BUF_ADDR(lbp)); + rbno = INT_GET(left->bb_rightsib, ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + cur->bc_private.a.agno, rbno, 0, &rbp, + XFS_ALLOC_BTREE_REF))) + return error; + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); + if ((error = xfs_btree_check_sblock(cur, right, + cur->bc_nlevels - 1, rbp))) + return error; + nptr = 1; + } else { + /* + * Our block is right, pick up the left block. + */ + rbp = lbp; + right = left; + rbno = XFS_DADDR_TO_AGBNO(mp, XFS_BUF_ADDR(rbp)); + lbno = INT_GET(right->bb_leftsib, ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + cur->bc_private.a.agno, lbno, 0, &lbp, + XFS_ALLOC_BTREE_REF))) + return error; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); + if ((error = xfs_btree_check_sblock(cur, left, + cur->bc_nlevels - 1, lbp))) + return error; + nptr = 2; + } + /* + * Fill in the new block's btree header and log it. + */ + INT_SET(new->bb_magic, ARCH_CONVERT, xfs_magics[cur->bc_btnum]); + INT_SET(new->bb_level, ARCH_CONVERT, (__uint16_t)cur->bc_nlevels); + INT_SET(new->bb_numrecs, ARCH_CONVERT, 2); + INT_SET(new->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(new->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + xfs_alloc_log_block(cur->bc_tp, nbp, XFS_BB_ALL_BITS); + ASSERT(lbno != NULLAGBLOCK && rbno != NULLAGBLOCK); + /* + * Fill in the key data in the new root. + */ + { + xfs_alloc_key_t *kp; /* btree key pointer */ + + kp = XFS_ALLOC_KEY_ADDR(new, 1, cur); + if (INT_GET(left->bb_level, ARCH_CONVERT) > 0) { + kp[0] = *XFS_ALLOC_KEY_ADDR(left, 1, cur); /* INT_: structure copy */ + kp[1] = *XFS_ALLOC_KEY_ADDR(right, 1, cur);/* INT_: structure copy */ + } else { + xfs_alloc_rec_t *rp; /* btree record pointer */ + + rp = XFS_ALLOC_REC_ADDR(left, 1, cur); + kp[0].ar_startblock = rp->ar_startblock; /* INT_: direct copy */ + kp[0].ar_blockcount = rp->ar_blockcount; /* INT_: direct copy */ + rp = XFS_ALLOC_REC_ADDR(right, 1, cur); + kp[1].ar_startblock = rp->ar_startblock; /* INT_: direct copy */ + kp[1].ar_blockcount = rp->ar_blockcount; /* INT_: direct copy */ + } + } + xfs_alloc_log_keys(cur, nbp, 1, 2); + /* + * Fill in the pointer data in the new root. + */ + { + xfs_alloc_ptr_t *pp; /* btree address pointer */ + + pp = XFS_ALLOC_PTR_ADDR(new, 1, cur); + INT_SET(pp[0], ARCH_CONVERT, lbno); + INT_SET(pp[1], ARCH_CONVERT, rbno); + } + xfs_alloc_log_ptrs(cur, nbp, 1, 2); + /* + * Fix up the cursor. + */ + xfs_btree_setbuf(cur, cur->bc_nlevels, nbp); + cur->bc_ptrs[cur->bc_nlevels] = nptr; + cur->bc_nlevels++; + *stat = 1; + return 0; +} + +/* + * Move 1 record right from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_alloc_rshift( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to shift record on */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* loop index */ + xfs_alloc_key_t key; /* key value for leaf level upward */ + xfs_buf_t *lbp; /* buffer for left (current) block */ + xfs_alloc_block_t *left; /* left (current) btree block */ + xfs_buf_t *rbp; /* buffer for right neighbor block */ + xfs_alloc_block_t *right; /* right neighbor btree block */ + xfs_alloc_key_t *rkp; /* key pointer for right block */ + xfs_btree_cur_t *tcur; /* temporary cursor */ + + /* + * Set up variables for this block as "left". + */ + lbp = cur->bc_bufs[level]; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; +#endif + /* + * If we've got no right sibling then we can't shift an entry right. + */ + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * If the cursor entry is the one that would be moved, don't + * do it... it's too complicated. + */ + if (cur->bc_ptrs[level] >= INT_GET(left->bb_numrecs, ARCH_CONVERT)) { + *stat = 0; + return 0; + } + /* + * Set up the right neighbor as "right". + */ + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.a.agno, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, &rbp, + XFS_ALLOC_BTREE_REF))) + return error; + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + return error; + /* + * If it's full, it can't take another entry. + */ + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { + *stat = 0; + return 0; + } + /* + * Make a hole at the start of the right neighbor block, then + * copy the last left block entry to the hole. + */ + if (level > 0) { + xfs_alloc_key_t *lkp; /* key pointer for left block */ + xfs_alloc_ptr_t *lpp; /* address pointer for left block */ + xfs_alloc_ptr_t *rpp; /* address pointer for right block */ + + lkp = XFS_ALLOC_KEY_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + lpp = XFS_ALLOC_PTR_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur); + rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1; i >= 0; i--) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + ovbcopy(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, INT_GET(*lpp, ARCH_CONVERT), level))) + return error; +#endif + *rkp = *lkp; /* INT_: copy */ + *rpp = *lpp; /* INT_: copy */ + xfs_alloc_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + xfs_alloc_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + xfs_btree_check_key(cur->bc_btnum, rkp, rkp + 1); + } else { + xfs_alloc_rec_t *lrp; /* record pointer for left block */ + xfs_alloc_rec_t *rrp; /* record pointer for right block */ + + lrp = XFS_ALLOC_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rrp = XFS_ALLOC_REC_ADDR(right, 1, cur); + ovbcopy(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + *rrp = *lrp; + xfs_alloc_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + key.ar_startblock = rrp->ar_startblock; /* INT_: direct copy */ + key.ar_blockcount = rrp->ar_blockcount; /* INT_: direct copy */ + rkp = &key; + xfs_btree_check_rec(cur->bc_btnum, rrp, rrp + 1); + } + /* + * Decrement and log left's numrecs, bump and log right's numrecs. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -1); + xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); + xfs_alloc_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); + /* + * Using a temporary cursor, update the parent key values of the + * block on the right. + */ + if ((error = xfs_btree_dup_cursor(cur, &tcur))) + return error; + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_alloc_increment(tcur, level, &i)) || + (error = xfs_alloc_updkey(tcur, rkp, level + 1))) + goto error0; + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + *stat = 1; + return 0; +error0: + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; +} + +/* + * Split cur/level block in half. + * Return new block number and its first record (to be inserted into parent). + */ +STATIC int /* error */ +xfs_alloc_split( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to split */ + xfs_agblock_t *bnop, /* output: block number allocated */ + xfs_alloc_key_t *keyp, /* output: first key of new block */ + xfs_btree_cur_t **curp, /* output: new cursor */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* loop index/record number */ + xfs_agblock_t lbno; /* left (current) block number */ + xfs_buf_t *lbp; /* buffer for left block */ + xfs_alloc_block_t *left; /* left (current) btree block */ + xfs_agblock_t rbno; /* right (new) block number */ + xfs_buf_t *rbp; /* buffer for right block */ + xfs_alloc_block_t *right; /* right (new) btree block */ + + /* + * Allocate the new block from the freelist. + * If we can't do it, we're toast. Give up. + */ + if ((error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp, + &rbno))) + return error; + if (rbno == NULLAGBLOCK) { + *stat = 0; + return 0; + } + xfs_trans_agbtree_delta(cur->bc_tp, 1); + rbp = xfs_btree_get_bufs(cur->bc_mp, cur->bc_tp, cur->bc_private.a.agno, + rbno, 0); + /* + * Set up the new block as "right". + */ + right = XFS_BUF_TO_ALLOC_BLOCK(rbp); + /* + * "Left" is the current (according to the cursor) block. + */ + lbp = cur->bc_bufs[level]; + left = XFS_BUF_TO_ALLOC_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; +#endif + /* + * Fill in the btree header for the new block. + */ + INT_SET(right->bb_magic, ARCH_CONVERT, xfs_magics[cur->bc_btnum]); + right->bb_level = left->bb_level; /* INT_: direct copy */ + INT_SET(right->bb_numrecs, ARCH_CONVERT, (__uint16_t)(INT_GET(left->bb_numrecs, ARCH_CONVERT) / 2)); + /* + * Make sure that if there's an odd number of entries now, that + * each new block will have the same number of entries. + */ + if ((INT_GET(left->bb_numrecs, ARCH_CONVERT) & 1) && + cur->bc_ptrs[level] <= INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1) + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); + i = INT_GET(left->bb_numrecs, ARCH_CONVERT) - INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1; + /* + * For non-leaf blocks, copy keys and addresses over to the new block. + */ + if (level > 0) { + xfs_alloc_key_t *lkp; /* left btree key pointer */ + xfs_alloc_ptr_t *lpp; /* left btree address pointer */ + xfs_alloc_key_t *rkp; /* right btree key pointer */ + xfs_alloc_ptr_t *rpp; /* right btree address pointer */ + + lkp = XFS_ALLOC_KEY_ADDR(left, i, cur); + lpp = XFS_ALLOC_PTR_ADDR(left, i, cur); + rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur); + rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(lpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + bcopy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); /* INT_: copy */ + bcopy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp));/* INT_: copy */ + xfs_alloc_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_alloc_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + *keyp = *rkp; + } + /* + * For leaf blocks, copy records over to the new block. + */ + else { + xfs_alloc_rec_t *lrp; /* left btree record pointer */ + xfs_alloc_rec_t *rrp; /* right btree record pointer */ + + lrp = XFS_ALLOC_REC_ADDR(left, i, cur); + rrp = XFS_ALLOC_REC_ADDR(right, 1, cur); + bcopy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_alloc_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + keyp->ar_startblock = rrp->ar_startblock; /* INT_: direct copy */ + keyp->ar_blockcount = rrp->ar_blockcount; /* INT_: direct copy */ + } + /* + * Find the left block number by looking in the buffer. + * Adjust numrecs, sibling pointers. + */ + lbno = XFS_DADDR_TO_AGBNO(cur->bc_mp, XFS_BUF_ADDR(lbp)); + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -(INT_GET(right->bb_numrecs, ARCH_CONVERT))); + right->bb_rightsib = left->bb_rightsib; /* INT_: direct copy */ + INT_SET(left->bb_rightsib, ARCH_CONVERT, rbno); + INT_SET(right->bb_leftsib, ARCH_CONVERT, lbno); + xfs_alloc_log_block(cur->bc_tp, rbp, XFS_BB_ALL_BITS); + xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); + /* + * If there's a block to the new block's right, make that block + * point back to right instead of to left. + */ + if (INT_GET(right->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_alloc_block_t *rrblock; /* rr btree block */ + xfs_buf_t *rrbp; /* buffer for rrblock */ + + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.a.agno, INT_GET(right->bb_rightsib, ARCH_CONVERT), 0, + &rrbp, XFS_ALLOC_BTREE_REF))) + return error; + rrblock = XFS_BUF_TO_ALLOC_BLOCK(rrbp); + if ((error = xfs_btree_check_sblock(cur, rrblock, level, rrbp))) + return error; + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, rbno); + xfs_alloc_log_block(cur->bc_tp, rrbp, XFS_BB_LEFTSIB); + } + /* + * If the cursor is really in the right block, move it there. + * If it's just pointing past the last entry in left, then we'll + * insert there, so don't change anything in that case. + */ + if (cur->bc_ptrs[level] > INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1) { + xfs_btree_setbuf(cur, level, rbp); + cur->bc_ptrs[level] -= INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + /* + * If there are more levels, we'll need another cursor which refers to + * the right block, no matter where this cursor was. + */ + if (level + 1 < cur->bc_nlevels) { + if ((error = xfs_btree_dup_cursor(cur, curp))) + return error; + (*curp)->bc_ptrs[level + 1]++; + } + *bnop = rbno; + *stat = 1; + return 0; +} + +/* + * Update keys at all levels from here to the root along the cursor's path. + */ +STATIC int /* error */ +xfs_alloc_updkey( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_alloc_key_t *keyp, /* new key value to update to */ + int level) /* starting level for update */ +{ + int ptr; /* index of key in block */ + + /* + * Go up the tree from this level toward the root. + * At each level, update the key value to the value input. + * Stop when we reach a level where the cursor isn't pointing + * at the first entry in the block. + */ + for (ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) { + xfs_alloc_block_t *block; /* btree block */ + xfs_buf_t *bp; /* buffer for block */ +#ifdef DEBUG + int error; /* error return value */ +#endif + xfs_alloc_key_t *kp; /* ptr to btree block keys */ + + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; +#endif + ptr = cur->bc_ptrs[level]; + kp = XFS_ALLOC_KEY_ADDR(block, ptr, cur); + *kp = *keyp; + xfs_alloc_log_keys(cur, bp, ptr, ptr); + } + return 0; +} + +/* + * Externally visible routines. + */ + +/* + * Decrement cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_alloc_decrement( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat) /* success/failure */ +{ + xfs_alloc_block_t *block; /* btree block */ + int error; /* error return value */ + int lev; /* btree level */ + + ASSERT(level < cur->bc_nlevels); + /* + * Read-ahead to the left at this level. + */ + xfs_btree_readahead(cur, level, XFS_BTCUR_LEFTRA); + /* + * Decrement the ptr at this level. If we're still in the block + * then we're done. + */ + if (--cur->bc_ptrs[level] > 0) { + *stat = 1; + return 0; + } + /* + * Get a pointer to the btree block. + */ + block = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[level]); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, + cur->bc_bufs[level]))) + return error; +#endif + /* + * If we just went off the left edge of the tree, return failure. + */ + if (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * March up the tree decrementing pointers. + * Stop when we don't go off the left edge of a block. + */ + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + if (--cur->bc_ptrs[lev] > 0) + break; + /* + * Read-ahead the left block, we're going to read it + * in the next loop. + */ + xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA); + } + /* + * If we went off the root then we are seriously confused. + */ + ASSERT(lev < cur->bc_nlevels); + /* + * Now walk back down the tree, fixing up the cursor's buffer + * pointers and key numbers. + */ + for (block = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[lev]); lev > level; ) { + xfs_agblock_t agbno; /* block number of btree block */ + xfs_buf_t *bp; /* buffer pointer for block */ + + agbno = INT_GET(*XFS_ALLOC_PTR_ADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.a.agno, agbno, 0, &bp, + XFS_ALLOC_BTREE_REF))) + return error; + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; + cur->bc_ptrs[lev] = INT_GET(block->bb_numrecs, ARCH_CONVERT); + } + *stat = 1; + return 0; +} + +/* + * Delete the record pointed to by cur. + * The cursor refers to the place where the record was (could be inserted) + * when the operation returns. + */ +int /* error */ +xfs_alloc_delete( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* result code */ + int level; /* btree level */ + + /* + * Go up the tree, starting at leaf level. + * If 2 is returned then a join was done; go to the next level. + * Otherwise we are done. + */ + for (level = 0, i = 2; i == 2; level++) { + if ((error = xfs_alloc_delrec(cur, level, &i))) + return error; + } + if (i == 0) { + for (level = 1; level < cur->bc_nlevels; level++) { + if (cur->bc_ptrs[level] == 0) { + if ((error = xfs_alloc_decrement(cur, level, &i))) + return error; + break; + } + } + } + *stat = i; + return 0; +} + +/* + * Get the data from the pointed-to record. + */ +int /* error */ +xfs_alloc_get_rec( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t *bno, /* output: starting block of extent */ + xfs_extlen_t *len, /* output: length of extent */ + int *stat) /* output: success/failure */ +{ + xfs_alloc_block_t *block; /* btree block */ +#ifdef DEBUG + int error; /* error return value */ +#endif + int ptr; /* record number */ + + ptr = cur->bc_ptrs[0]; + block = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[0]); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, 0, cur->bc_bufs[0]))) + return error; +#endif + /* + * Off the right end or left end, return failure. + */ + if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT) || ptr <= 0) { + *stat = 0; + return 0; + } + /* + * Point to the record and extract its data. + */ + { + xfs_alloc_rec_t *rec; /* record data */ + + rec = XFS_ALLOC_REC_ADDR(block, ptr, cur); + *bno = INT_GET(rec->ar_startblock, ARCH_CONVERT); + *len = INT_GET(rec->ar_blockcount, ARCH_CONVERT); + } + *stat = 1; + return 0; +} + +/* + * Increment cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_alloc_increment( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat) /* success/failure */ +{ + xfs_alloc_block_t *block; /* btree block */ + xfs_buf_t *bp; /* tree block buffer */ + int error; /* error return value */ + int lev; /* btree level */ + + ASSERT(level < cur->bc_nlevels); + /* + * Read-ahead to the right at this level. + */ + xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); + /* + * Get a pointer to the btree block. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; +#endif + /* + * Increment the ptr at this level. If we're still in the block + * then we're done. + */ + if (++cur->bc_ptrs[level] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + *stat = 1; + return 0; + } + /* + * If we just went off the right edge of the tree, return failure. + */ + if (INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * March up the tree incrementing pointers. + * Stop when we don't go off the right edge of a block. + */ + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + bp = cur->bc_bufs[lev]; + block = XFS_BUF_TO_ALLOC_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; +#endif + if (++cur->bc_ptrs[lev] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) + break; + /* + * Read-ahead the right block, we're going to read it + * in the next loop. + */ + xfs_btree_readahead(cur, lev, XFS_BTCUR_RIGHTRA); + } + /* + * If we went off the root then we are seriously confused. + */ + ASSERT(lev < cur->bc_nlevels); + /* + * Now walk back down the tree, fixing up the cursor's buffer + * pointers and key numbers. + */ + for (bp = cur->bc_bufs[lev], block = XFS_BUF_TO_ALLOC_BLOCK(bp); + lev > level; ) { + xfs_agblock_t agbno; /* block number of btree block */ + + agbno = INT_GET(*XFS_ALLOC_PTR_ADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.a.agno, agbno, 0, &bp, + XFS_ALLOC_BTREE_REF))) + return error; + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_ALLOC_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; + cur->bc_ptrs[lev] = 1; + } + *stat = 1; + return 0; +} + +/* + * Insert the current record at the point referenced by cur. + * The cursor may be inconsistent on return if splits have been done. + */ +int /* error */ +xfs_alloc_insert( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* result value, 0 for failure */ + int level; /* current level number in btree */ + xfs_agblock_t nbno; /* new block number (split result) */ + xfs_btree_cur_t *ncur; /* new cursor (split result) */ + xfs_alloc_rec_t nrec; /* record being inserted this level */ + xfs_btree_cur_t *pcur; /* previous level's cursor */ + + level = 0; + nbno = NULLAGBLOCK; + INT_SET(nrec.ar_startblock, ARCH_CONVERT, cur->bc_rec.a.ar_startblock); + INT_SET(nrec.ar_blockcount, ARCH_CONVERT, cur->bc_rec.a.ar_blockcount); + ncur = (xfs_btree_cur_t *)0; + pcur = cur; + /* + * Loop going up the tree, starting at the leaf level. + * Stop when we don't get a split block, that must mean that + * the insert is finished with this level. + */ + do { + /* + * Insert nrec/nbno into this level of the tree. + * Note if we fail, nbno will be null. + */ + if ((error = xfs_alloc_insrec(pcur, level++, &nbno, &nrec, &ncur, + &i))) { + if (pcur != cur) + xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); + return error; + } + /* + * See if the cursor we just used is trash. + * Can't trash the caller's cursor, but otherwise we should + * if ncur is a new cursor or we're about to be done. + */ + if (pcur != cur && (ncur || nbno == NULLAGBLOCK)) { + cur->bc_nlevels = pcur->bc_nlevels; + xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); + } + /* + * If we got a new cursor, switch to it. + */ + if (ncur) { + pcur = ncur; + ncur = (xfs_btree_cur_t *)0; + } + } while (nbno != NULLAGBLOCK); + *stat = i; + return 0; +} + +/* + * Lookup the record equal to [bno, len] in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_eq( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat) /* success/failure */ +{ + cur->bc_rec.a.ar_startblock = bno; + cur->bc_rec.a.ar_blockcount = len; + return xfs_alloc_lookup(cur, XFS_LOOKUP_EQ, stat); +} + +/* + * Lookup the first record greater than or equal to [bno, len] + * in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_ge( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat) /* success/failure */ +{ + cur->bc_rec.a.ar_startblock = bno; + cur->bc_rec.a.ar_blockcount = len; + return xfs_alloc_lookup(cur, XFS_LOOKUP_GE, stat); +} + +/* + * Lookup the first record less than or equal to [bno, len] + * in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_le( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat) /* success/failure */ +{ + cur->bc_rec.a.ar_startblock = bno; + cur->bc_rec.a.ar_blockcount = len; + return xfs_alloc_lookup(cur, XFS_LOOKUP_LE, stat); +} + +/* + * Update the record referred to by cur, to the value given by [bno, len]. + * This either works (return 0) or gets an EFSCORRUPTED error. + */ +int /* error */ +xfs_alloc_update( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len) /* length of extent */ +{ + xfs_alloc_block_t *block; /* btree block to update */ + int error; /* error return value */ + int ptr; /* current record number (updating) */ + + ASSERT(len > 0); + /* + * Pick up the a.g. freelist struct and the current block. + */ + block = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[0]); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, 0, cur->bc_bufs[0]))) + return error; +#endif + /* + * Get the address of the rec to be updated. + */ + ptr = cur->bc_ptrs[0]; + { + xfs_alloc_rec_t *rp; /* pointer to updated record */ + + rp = XFS_ALLOC_REC_ADDR(block, ptr, cur); + /* + * Fill in the new contents and log them. + */ + INT_SET(rp->ar_startblock, ARCH_CONVERT, bno); + INT_SET(rp->ar_blockcount, ARCH_CONVERT, len); + xfs_alloc_log_recs(cur, cur->bc_bufs[0], ptr, ptr); + } + /* + * If it's the by-size btree and it's the last leaf block and + * it's the last record... then update the size of the longest + * extent in the a.g., which we cache in the a.g. freelist header. + */ + if (cur->bc_btnum == XFS_BTNUM_CNT && + INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK && + ptr == INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + xfs_agf_t *agf; /* a.g. freespace header */ + xfs_agnumber_t seqno; + + agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); + seqno = INT_GET(agf->agf_seqno, ARCH_CONVERT); + cur->bc_mp->m_perag[seqno].pagf_longest = len; + INT_SET(agf->agf_longest, ARCH_CONVERT, len); + xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, + XFS_AGF_LONGEST); + } + /* + * Updating first record in leaf. Pass new key value up to our parent. + */ + if (ptr == 1) { + xfs_alloc_key_t key; /* key containing [bno, len] */ + + INT_SET(key.ar_startblock, ARCH_CONVERT, bno); + INT_SET(key.ar_blockcount, ARCH_CONVERT, len); + if ((error = xfs_alloc_updkey(cur, &key, 1))) + return error; + } + return 0; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_alloc_btree.h linux-2.4-xfs/linux/fs/xfs/xfs_alloc_btree.h --- linux-2.4.7/linux/fs/xfs/xfs_alloc_btree.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_alloc_btree.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ALLOC_BTREE_H__ +#define __XFS_ALLOC_BTREE_H__ + +/* + * Freespace on-disk structures + */ + +struct xfs_buf; +struct xfs_btree_cur; +struct xfs_btree_sblock; +struct xfs_mount; + +/* + * There are two on-disk btrees, one sorted by blockno and one sorted + * by blockcount and blockno. All blocks look the same to make the code + * simpler; if we have time later, we'll make the optimizations. + */ +#define XFS_ABTB_MAGIC 0x41425442 /* 'ABTB' for bno tree */ +#define XFS_ABTC_MAGIC 0x41425443 /* 'ABTC' for cnt tree */ + +/* + * Data record/key structure + */ +typedef struct xfs_alloc_rec +{ + xfs_agblock_t ar_startblock; /* starting block number */ + xfs_extlen_t ar_blockcount; /* count of free blocks */ +} xfs_alloc_rec_t, xfs_alloc_key_t; + +typedef xfs_agblock_t xfs_alloc_ptr_t; /* btree pointer type */ + /* btree block header type */ +typedef struct xfs_btree_sblock xfs_alloc_block_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_ALLOC_BLOCK) +xfs_alloc_block_t *xfs_buf_to_alloc_block(struct xfs_buf *bp); +#define XFS_BUF_TO_ALLOC_BLOCK(bp) xfs_buf_to_alloc_block(bp) +#else +#define XFS_BUF_TO_ALLOC_BLOCK(bp) ((xfs_alloc_block_t *)(XFS_BUF_PTR(bp))) +#endif + +/* + * Real block structures have a size equal to the disk block size. + */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_BLOCK_SIZE) +int xfs_alloc_block_size(int lev, struct xfs_btree_cur *cur); +#define XFS_ALLOC_BLOCK_SIZE(lev,cur) xfs_alloc_block_size(lev,cur) +#else +#define XFS_ALLOC_BLOCK_SIZE(lev,cur) (1 << (cur)->bc_blocklog) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_BLOCK_MAXRECS) +int xfs_alloc_block_maxrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_ALLOC_BLOCK_MAXRECS(lev,cur) xfs_alloc_block_maxrecs(lev,cur) +#else +#define XFS_ALLOC_BLOCK_MAXRECS(lev,cur) \ + ((cur)->bc_mp->m_alloc_mxr[lev != 0]) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_BLOCK_MINRECS) +int xfs_alloc_block_minrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_ALLOC_BLOCK_MINRECS(lev,cur) xfs_alloc_block_minrecs(lev,cur) +#else +#define XFS_ALLOC_BLOCK_MINRECS(lev,cur) \ + ((cur)->bc_mp->m_alloc_mnr[lev != 0]) +#endif + +/* + * Minimum and maximum blocksize. + * The blocksize upper limit is pretty much arbitrary. + */ +#define XFS_MIN_BLOCKSIZE_LOG 9 /* i.e. 512 bytes */ +#define XFS_MAX_BLOCKSIZE_LOG 16 /* i.e. 65536 bytes */ +#define XFS_MIN_BLOCKSIZE (1 << XFS_MIN_BLOCKSIZE_LOG) +#define XFS_MAX_BLOCKSIZE (1 << XFS_MAX_BLOCKSIZE_LOG) + +/* + * block numbers in the AG; SB is BB 0, AGF is BB 1, AGI is BB 2, AGFL is BB 3 + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BNO_BLOCK) +xfs_agblock_t xfs_bno_block(struct xfs_mount *mp); +#define XFS_BNO_BLOCK(mp) xfs_bno_block(mp) +#else +#define XFS_BNO_BLOCK(mp) ((xfs_agblock_t)(XFS_AGFL_BLOCK(mp) + 1)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CNT_BLOCK) +xfs_agblock_t xfs_cnt_block(struct xfs_mount *mp); +#define XFS_CNT_BLOCK(mp) xfs_cnt_block(mp) +#else +#define XFS_CNT_BLOCK(mp) ((xfs_agblock_t)(XFS_BNO_BLOCK(mp) + 1)) +#endif + +/* + * Record, key, and pointer address macros for btree blocks. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_REC_ADDR) +xfs_alloc_rec_t *xfs_alloc_rec_addr(xfs_alloc_block_t *bb, int i, + struct xfs_btree_cur *cur); +#define XFS_ALLOC_REC_ADDR(bb,i,cur) xfs_alloc_rec_addr(bb,i,cur) +#else +#define XFS_ALLOC_REC_ADDR(bb,i,cur) \ + XFS_BTREE_REC_ADDR(XFS_ALLOC_BLOCK_SIZE(0,cur), xfs_alloc, bb, i, \ + XFS_ALLOC_BLOCK_MAXRECS(0, cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_KEY_ADDR) +xfs_alloc_key_t *xfs_alloc_key_addr(xfs_alloc_block_t *bb, int i, + struct xfs_btree_cur *cur); +#define XFS_ALLOC_KEY_ADDR(bb,i,cur) xfs_alloc_key_addr(bb,i,cur) +#else +#define XFS_ALLOC_KEY_ADDR(bb,i,cur) \ + XFS_BTREE_KEY_ADDR(XFS_ALLOC_BLOCK_SIZE(1,cur), xfs_alloc, bb, i, \ + XFS_ALLOC_BLOCK_MAXRECS(1, cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ALLOC_PTR_ADDR) +xfs_alloc_ptr_t *xfs_alloc_ptr_addr(xfs_alloc_block_t *bb, int i, + struct xfs_btree_cur *cur); +#define XFS_ALLOC_PTR_ADDR(bb,i,cur) xfs_alloc_ptr_addr(bb,i,cur) +#else +#define XFS_ALLOC_PTR_ADDR(bb,i,cur) \ + XFS_BTREE_PTR_ADDR(XFS_ALLOC_BLOCK_SIZE(1,cur), xfs_alloc, bb, i, \ + XFS_ALLOC_BLOCK_MAXRECS(1, cur)) +#endif + +/* + * Prototypes for externally visible routines. + */ + +/* + * Decrement cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_alloc_decrement( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat); /* success/failure */ + +/* + * Delete the record pointed to by cur. + * The cursor refers to the place where the record was (could be inserted) + * when the operation returns. + */ +int /* error */ +xfs_alloc_delete( + struct xfs_btree_cur *cur, /* btree cursor */ + int *stat); /* success/failure */ + +/* + * Get the data from the pointed-to record. + */ +int /* error */ +xfs_alloc_get_rec( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agblock_t *bno, /* output: starting block of extent */ + xfs_extlen_t *len, /* output: length of extent */ + int *stat); /* output: success/failure */ + +/* + * Increment cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_alloc_increment( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat); /* success/failure */ + +/* + * Insert the current record at the point referenced by cur. + * The cursor may be inconsistent on return if splits have been done. + */ +int /* error */ +xfs_alloc_insert( + struct xfs_btree_cur *cur, /* btree cursor */ + int *stat); /* success/failure */ + +/* + * Lookup the record equal to [bno, len] in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_eq( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat); /* success/failure */ + +/* + * Lookup the first record greater than or equal to [bno, len] + * in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_ge( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat); /* success/failure */ + +/* + * Lookup the first record less than or equal to [bno, len] + * in the btree given by cur. + */ +int /* error */ +xfs_alloc_lookup_le( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat); /* success/failure */ + +/* + * Update the record referred to by cur, to the value given by [bno, len]. + * This either works (return 0) or gets an EFSCORRUPTED error. + */ +int /* error */ +xfs_alloc_update( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agblock_t bno, /* starting block of extent */ + xfs_extlen_t len); /* length of extent */ + +#endif /* __XFS_ALLOC_BTREE_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_arch.h linux-2.4-xfs/linux/fs/xfs/xfs_arch.h --- linux-2.4.7/linux/fs/xfs/xfs_arch.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_arch.h Wed Nov 15 20:50:50 2000 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ARCH_H__ +#define __XFS_ARCH_H__ + +#ifndef XFS_BIG_FILESYSTEMS +#error XFS_BIG_FILESYSTEMS must be defined true or false +#endif + +#define DIRINO4_GET_ARCH(pointer,arch) \ + ( ((arch) == ARCH_NOCONVERT) \ + ? \ + (INT_GET_UNALIGNED_32(pointer)) \ + : \ + (INT_GET_UNALIGNED_32_BE(pointer)) \ + ) + +#if XFS_BIG_FILESYSTEMS +#define DIRINO_GET_ARCH(pointer,arch) \ + ( ((arch) == ARCH_NOCONVERT) \ + ? \ + (INT_GET_UNALIGNED_64(pointer)) \ + : \ + (INT_GET_UNALIGNED_64_BE(pointer)) \ + ) +#else +/* MACHINE ARCHITECTURE dependent */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define DIRINO_GET_ARCH(pointer,arch) \ + DIRINO4_GET_ARCH((((__u8*)pointer)+4),arch) +#else +#define DIRINO_GET_ARCH(pointer,arch) \ + DIRINO4_GET_ARCH(pointer,arch) +#endif +#endif + +#define DIRINO_COPY_ARCH(from,to,arch) \ + if ((arch) == ARCH_NOCONVERT) { \ + bcopy(from,to,sizeof(xfs_ino_t)); \ + } else { \ + INT_SWAP_UNALIGNED_64(from,to); \ + } +#define DIRINO4_COPY_ARCH(from,to,arch) \ + if ((arch) == ARCH_NOCONVERT) { \ + bcopy((((__u8*)from+4)),to,sizeof(xfs_dir2_ino4_t)); \ + } else { \ + INT_SWAP_UNALIGNED_32(from,to); \ + } + +#endif /* __XFS_ARCH_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_attr.c linux-2.4-xfs/linux/fs/xfs/xfs_attr.c --- linux-2.4.7/linux/fs/xfs/xfs_attr.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_attr.c Wed Apr 18 21:37:23 2001 @@ -0,0 +1,2255 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * xfs_attr.c + * + * Provide the external interfaces to manage attribute lists. + */ + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Internal routines when attribute list fits inside the inode. + */ +STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args); + +/* + * Internal routines when attribute list is one block. + */ +STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args); +STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); +STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context); + +/* + * Internal routines when attribute list is more than one block. + */ +STATIC int xfs_attr_node_addname(xfs_da_args_t *args); +STATIC int xfs_attr_node_removename(xfs_da_args_t *args); +STATIC int xfs_attr_node_list(xfs_attr_list_context_t *context); +STATIC int xfs_attr_fillstate(xfs_da_state_t *state); +STATIC int xfs_attr_refillstate(xfs_da_state_t *state); + +/* + * Routines to manipulate out-of-line attribute values. + */ +STATIC int xfs_attr_rmtval_get(xfs_da_args_t *args); +STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args); +STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args); + +#define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ +#define ATTR_RMTVALUE_TRANSBLKS 8 /* max # of blks in a transaction */ + +#if defined(DEBUG) +ktrace_t *xfs_attr_trace_buf; +#endif + + + +/*======================================================================== + * Overall external interface routines. + *========================================================================*/ + +/*ARGSUSED*/ +int /* error */ +xfs_attr_get(bhv_desc_t *bdp, char *name, char *value, int *valuelenp, + int flags, struct cred *cred) +{ + xfs_da_args_t args; + int error; + int namelen; + + ASSERT(MAXNAMELEN-1<=0xff); /* length is stored in uint8 */ + namelen=strlen(name); + if (namelen>=MAXNAMELEN) return EFAULT; /* match irix behaviour */ + + XFS_STATS_INC(xfsstats.xs_attr_get); + + /* + * Fill in the arg structure for this request. + */ + bzero((char *)&args, sizeof(args)); + args.name = name; + args.namelen = namelen; + args.value = value; + args.valuelen = *valuelenp; + args.flags = flags; + args.hashval = xfs_da_hashname(args.name, args.namelen); + args.dp = XFS_BHVTOI(bdp); + args.whichfork = XFS_ATTR_FORK; + args.trans = NULL; + + if (XFS_FORCED_SHUTDOWN(args.dp->i_mount)) + return (EIO); + + /* + * Do we answer them, or ignore them? + */ + xfs_ilock(args.dp, XFS_ILOCK_SHARED); + if ((error = xfs_iaccess(XFS_BHVTOI(bdp), IREAD, cred))) { + xfs_iunlock(args.dp, XFS_ILOCK_SHARED); + return(XFS_ERROR(error)); + } + + /* + * Decide on what work routines to call based on the inode size. + */ + if (XFS_IFORK_Q(args.dp) == 0 || + (args.dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && + args.dp->i_d.di_anextents == 0)) { + error = XFS_ERROR(ENOATTR); + } else if (args.dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { + error = xfs_attr_shortform_getvalue(&args); + } else if (xfs_bmap_one_block(args.dp, XFS_ATTR_FORK)) { + error = xfs_attr_leaf_get(&args); + } else { + error = xfs_attr_node_get(&args); + } + xfs_iunlock(args.dp, XFS_ILOCK_SHARED); + + /* + * Return the number of bytes in the value to the caller. + */ + *valuelenp = args.valuelen; + + if (error == EEXIST) + error = 0; + return(error); +} + +/*ARGSUSED*/ +int /* error */ +xfs_attr_set(bhv_desc_t *bdp, char *name, char *value, int valuelen, int flags, + struct cred *cred) +{ + xfs_da_args_t args; + xfs_inode_t *dp; + xfs_fsblock_t firstblock; + xfs_bmap_free_t flist; + int error, err2, committed; + int local, size; + uint nblks; + xfs_mount_t *mp; + int rsvd = (flags & ATTR_ROOT) != 0; + int namelen; + + ASSERT(MAXNAMELEN-1<=0xff); /* length is stored in uint8 */ + namelen=strlen(name); + if (namelen>=MAXNAMELEN) return EFAULT; /* match irix behaviour */ + + XFS_STATS_INC(xfsstats.xs_attr_set); + /* + * Do we answer them, or ignore them? + */ + dp = XFS_BHVTOI(bdp); + mp = dp->i_mount; + if (XFS_FORCED_SHUTDOWN(mp)) + return (EIO); + + xfs_ilock(dp, XFS_ILOCK_SHARED); + if ((error = xfs_iaccess(dp, IWRITE, cred))) { + xfs_iunlock(dp, XFS_ILOCK_SHARED); + return(XFS_ERROR(error)); + } + xfs_iunlock(dp, XFS_ILOCK_SHARED); + + /* + * Attach the dquots to the inode. + */ + if (XFS_IS_QUOTA_ON(mp)) { + if ((error = xfs_qm_dqattach(dp, 0))) + return (error); + } + + /* + * If the inode doesn't have an attribute fork, add one. + * (inode must not be locked when we call this routine) + */ + if (XFS_IFORK_Q(dp) == 0) { + error = xfs_bmap_add_attrfork(dp, rsvd); + if (error) + return(error); + } + + /* + * Fill in the arg structure for this request. + */ + bzero((char *)&args, sizeof(args)); + args.name = name; + args.namelen = namelen; + args.value = value; + args.valuelen = valuelen; + args.flags = flags; + args.hashval = xfs_da_hashname(args.name, args.namelen); + args.dp = dp; + args.firstblock = &firstblock; + args.flist = &flist; + args.whichfork = XFS_ATTR_FORK; + args.oknoent = 1; + + /* Determine space new attribute will use, and if it will be inline + * or out of line. + */ + size = xfs_attr_leaf_newentsize(&args, mp->m_sb.sb_blocksize, &local); + + nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); + if (local) { + if (size > (mp->m_sb.sb_blocksize >> 1)) { + /* Double split possible */ + nblks <<= 1; + } + } else { + /* Out of line attribute, cannot double split, but make + * room for the attribute value itself. + */ + nblks += XFS_B_TO_FSB(mp, size); + nblks += XFS_NEXTENTADD_SPACE_RES(mp, size, XFS_ATTR_FORK); + } + + /* Size is now blocks for attribute data */ + args.total = nblks; + + /* + * Start our first transaction of the day. + * + * All future transactions during this code must be "chained" off + * this one via the trans_dup() call. All transactions will contain + * the inode, and the inode will always be marked with trans_ihold(). + * Since the inode will be locked in all transactions, we must log + * the inode in every transaction to let it float upward through + * the log. + */ + args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_SET); + + /* + * Root fork attributes can use reserved data blocks for this + * operation if necessary + */ + + if (rsvd) + args.trans->t_flags |= XFS_TRANS_RESERVE; + + if ((error = xfs_trans_reserve(args.trans, (uint) nblks, + XFS_ATTRSET_LOG_RES(mp, nblks), + 0, XFS_TRANS_PERM_LOG_RES, + XFS_ATTRSET_LOG_COUNT))) { + xfs_trans_cancel(args.trans, 0); + return(error); + } + xfs_ilock(dp, XFS_ILOCK_EXCL); + + if (XFS_IS_QUOTA_ON(mp)) { + if ((error = xfs_trans_reserve_blkquota(args.trans, dp, nblks))) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES); + return (error); + } + } + + xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args.trans, dp); + + /* + * If the attribute list is non-existant or a shortform list, + * upgrade it to a single-leaf-block attribute list. + */ + if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || + ((dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) && + (dp->i_d.di_anextents == 0))) { + + /* + * Build initial attribute list (if required). + */ + if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) + (void)xfs_attr_shortform_create(&args); + + /* + * Try to add the attr to the attribute list in + * the inode. + */ + error = xfs_attr_shortform_addname(&args); + if (error != ENOSPC) { + /* + * Commit the shortform mods, and we're done. + * NOTE: this is also the error path (EEXIST, etc). + */ + ASSERT(args.trans != NULL); + + /* + * If this is a synchronous mount, make sure that + * the transaction goes to disk before returning + * to the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(args.trans); + } + err2 = xfs_trans_commit(args.trans, + XFS_TRANS_RELEASE_LOG_RES, + NULL); + xfs_iunlock(dp, XFS_ILOCK_EXCL); + + /* + * Hit the inode change time. + */ + if (!error && (flags & ATTR_KERNOTIME) == 0) { + xfs_ichgtime(dp, XFS_ICHGTIME_CHG); + } + return(error == 0 ? err2 : error); + } + + /* + * It won't fit in the shortform, transform to a leaf block. + * GROT: another possible req'mt for a double-split btree op. + */ + XFS_BMAP_INIT(args.flist, args.firstblock); + error = xfs_attr_shortform_to_leaf(&args); + if (!error) { + error = xfs_bmap_finish(&args.trans, args.flist, + *args.firstblock, &committed); + } + if (error) { + ASSERT(committed); + args.trans = NULL; + xfs_bmap_cancel(&flist); + goto out; + } + + /* + * bmap_finish() may have committed the last trans and started + * a new one. We need the inode to be in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args.trans, dp); + } + + /* + * Commit the leaf transformation. We'll need another (linked) + * transaction to add the new attribute to the leaf. + */ + if ((error = xfs_attr_rolltrans(&args.trans, dp))) + goto out; + + } + + if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { + error = xfs_attr_leaf_addname(&args); + } else { + error = xfs_attr_node_addname(&args); + } + if (error) { + goto out; + } + + /* + * If this is a synchronous mount, make sure that the + * transaction goes to disk before returning to the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(args.trans); + } + + /* + * Commit the last in the sequence of transactions. + */ + xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); + error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES, + NULL); + xfs_iunlock(dp, XFS_ILOCK_EXCL); + + /* + * Hit the inode change time. + */ + if (!error && (flags & ATTR_KERNOTIME) == 0) { + xfs_ichgtime(dp, XFS_ICHGTIME_CHG); + } + + return(error); + +out: + if (args.trans) + xfs_trans_cancel(args.trans, + XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); + xfs_iunlock(dp, XFS_ILOCK_EXCL); + return(error); +} + +/* + * Generic handler routine to remove a name from an attribute list. + * Transitions attribute list from Btree to shortform as necessary. + */ +/*ARGSUSED*/ +int /* error */ +xfs_attr_remove(bhv_desc_t *bdp, char *name, int flags, struct cred *cred) +{ + xfs_da_args_t args; + xfs_inode_t *dp; + xfs_fsblock_t firstblock; + xfs_bmap_free_t flist; + int error; + xfs_mount_t *mp; + int namelen; + + ASSERT(MAXNAMELEN-1<=0xff); /* length is stored in uint8 */ + namelen=strlen(name); + if (namelen>=MAXNAMELEN) return EFAULT; /* match irix behaviour */ + + XFS_STATS_INC(xfsstats.xs_attr_remove); + + /* + * Do we answer them, or ignore them? + */ + dp = XFS_BHVTOI(bdp); + mp = dp->i_mount; + if (XFS_FORCED_SHUTDOWN(mp)) + return (EIO); + + xfs_ilock(dp, XFS_ILOCK_SHARED); + if ((error = xfs_iaccess(dp, IWRITE, cred))) { + xfs_iunlock(dp, XFS_ILOCK_SHARED); + return(XFS_ERROR(error)); + } else if (XFS_IFORK_Q(dp) == 0 || + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && + dp->i_d.di_anextents == 0)) { + xfs_iunlock(dp, XFS_ILOCK_SHARED); + return(XFS_ERROR(ENOATTR)); + } + xfs_iunlock(dp, XFS_ILOCK_SHARED); + + /* + * Fill in the arg structure for this request. + */ + bzero((char *)&args, sizeof(args)); + args.name = name; + args.namelen = namelen; + args.flags = flags; + args.hashval = xfs_da_hashname(args.name, args.namelen); + args.dp = dp; + args.firstblock = &firstblock; + args.flist = &flist; + args.total = 0; + args.whichfork = XFS_ATTR_FORK; + + /* + * Attach the dquots to the inode. + */ + if (XFS_IS_QUOTA_ON(mp)) { + if (XFS_NOT_DQATTACHED(mp, dp)) { + if ((error = xfs_qm_dqattach(dp, 0))) + return (error); + } + } + /* + * Start our first transaction of the day. + * + * All future transactions during this code must be "chained" off + * this one via the trans_dup() call. All transactions will contain + * the inode, and the inode will always be marked with trans_ihold(). + * Since the inode will be locked in all transactions, we must log + * the inode in every transaction to let it float upward through + * the log. + */ + args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_RM); + + /* + * Root fork attributes can use reserved data blocks for this + * operation if necessary + */ + + if (flags & ATTR_ROOT) + args.trans->t_flags |= XFS_TRANS_RESERVE; + + if ((error = xfs_trans_reserve(args.trans, + XFS_ATTRRM_SPACE_RES(mp), + XFS_ATTRRM_LOG_RES(mp), + 0, XFS_TRANS_PERM_LOG_RES, + XFS_ATTRRM_LOG_COUNT))) { + xfs_trans_cancel(args.trans, 0); + return(error); + + } + + xfs_ilock(dp, XFS_ILOCK_EXCL); + /* + * No need to make quota reservations here. We expect to release some + * blocks not allocate in the common case. + */ + xfs_trans_ijoin(args.trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args.trans, dp); + + /* + * Decide on what work routines to call based on the inode size. + */ + if (XFS_IFORK_Q(dp) == 0 || + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && + dp->i_d.di_anextents == 0)) { + error = XFS_ERROR(ENOATTR); + goto out; + } + if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { + ASSERT(dp->i_afp->if_flags & XFS_IFINLINE); + error = xfs_attr_shortform_remove(&args); + if (error) { + goto out; + } + } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { + error = xfs_attr_leaf_removename(&args); + } else { + error = xfs_attr_node_removename(&args); + } + if (error) { + goto out; + } + + /* + * If this is a synchronous mount, make sure that the + * transaction goes to disk before returning to the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(args.trans); + } + + /* + * Commit the last in the sequence of transactions. + */ + xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); + error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES, + NULL); + xfs_iunlock(dp, XFS_ILOCK_EXCL); + + /* + * Hit the inode change time. + */ + if (!error && (flags & ATTR_KERNOTIME) == 0) { + xfs_ichgtime(dp, XFS_ICHGTIME_CHG); + } + + return(error); + +out: + if (args.trans) + xfs_trans_cancel(args.trans, + XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); + xfs_iunlock(dp, XFS_ILOCK_EXCL); + return(error); +} + +/*ARGSUSED*/ +int /* error */ +xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags, + attrlist_cursor_kern_t *cursor, struct cred *cred) +{ + xfs_attr_list_context_t context; + xfs_inode_t *dp; + int error; + + XFS_STATS_INC(xfsstats.xs_attr_list); + + /* + * Validate the cursor. + */ + if (cursor->pad1 || cursor->pad2) { + return(XFS_ERROR(EINVAL)); + } + if ((cursor->initted == 0) && + (cursor->hashval || cursor->blkno || cursor->offset)) { + return(XFS_ERROR(EINVAL)); + } + + /* + * Check for a properly aligned buffer. + */ + if (((long)buffer) & (sizeof(int)-1)) { + return(XFS_ERROR(EFAULT)); + } + + /* + * Initialize the output buffer. + */ + context.dp = dp = XFS_BHVTOI(bdp); + context.cursor = cursor; + context.count = 0; + context.dupcnt = 0; + context.resynch = 1; + context.flags = flags; + context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */ + context.firstu = context.bufsize; + context.alist = (attrlist_t *)buffer; + context.alist->al_count = 0; + context.alist->al_more = 0; + context.alist->al_offset[0] = context.bufsize; + + if (XFS_FORCED_SHUTDOWN(dp->i_mount)) + return (EIO); + /* + * Do they have permission? + */ + xfs_ilock(dp, XFS_ILOCK_SHARED); + if ((error = xfs_iaccess(dp, IREAD, cred))) { + xfs_iunlock(dp, XFS_ILOCK_SHARED); + return(XFS_ERROR(error)); + } + + + /* + * Decide on what work routines to call based on the inode size. + */ + xfs_attr_trace_l_c("syscall start", &context); + if (XFS_IFORK_Q(dp) == 0 || + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && + dp->i_d.di_anextents == 0)) { + error = 0; + } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { + error = xfs_attr_shortform_list(&context); + } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { + error = xfs_attr_leaf_list(&context); + } else { + error = xfs_attr_node_list(&context); + } + xfs_iunlock(dp, XFS_ILOCK_SHARED); + xfs_attr_trace_l_c("syscall end", &context); + + return(error); +} + +int /* error */ +xfs_attr_inactive(xfs_inode_t *dp) +{ + xfs_trans_t *trans; + xfs_mount_t *mp; + int error; + + mp = dp->i_mount; + ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); + + /* XXXsup - why on earth are we taking ILOCK_EXCL here??? */ + xfs_ilock(dp, XFS_ILOCK_EXCL); + if ((XFS_IFORK_Q(dp) == 0) || + (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && + dp->i_d.di_anextents == 0)) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + return(0); + } + xfs_iunlock(dp, XFS_ILOCK_EXCL); + + /* + * Start our first transaction of the day. + * + * All future transactions during this code must be "chained" off + * this one via the trans_dup() call. All transactions will contain + * the inode, and the inode will always be marked with trans_ihold(). + * Since the inode will be locked in all transactions, we must log + * the inode in every transaction to let it float upward through + * the log. + */ + trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL); + if ((error = xfs_trans_reserve(trans, 0, XFS_ATTRINVAL_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_ATTRINVAL_LOG_COUNT))) { + xfs_trans_cancel(trans, 0); + return(error); + } + xfs_ilock(dp, XFS_ILOCK_EXCL); + + /* + * No need to make quota reservations here. We expect to release some + * blocks, not allocate, in the common case. + */ + xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(trans, dp); + + /* + * Decide on what work routines to call based on the inode size. + */ + if ((XFS_IFORK_Q(dp) == 0) || + (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || + (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && + dp->i_d.di_anextents == 0)) { + error = 0; + goto out; + } + error = xfs_attr_root_inactive(&trans, dp); + if (error) + goto out; + /* + * signal synchronous inactive transactions unless this + * is a synchronous mount filesystem in which case we + * know that we're here because we've been called out of + * xfs_inactive which means that the last reference is gone + * and the unlink transaction has already hit the disk so + * async inactive transactions are safe. + */ + if ((error = xfs_itruncate_finish(&trans, dp, 0LL, XFS_ATTR_FORK, + (!(mp->m_flags & XFS_MOUNT_WSYNC) + ? 1 : 0)))) + goto out; + + /* + * Commit the last in the sequence of transactions. + */ + xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); + error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES, + NULL); + xfs_iunlock(dp, XFS_ILOCK_EXCL); + + return(error); + +out: + xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); + xfs_iunlock(dp, XFS_ILOCK_EXCL); + return(error); +} + + + +/*======================================================================== + * External routines when attribute list is inside the inode + *========================================================================*/ + +/* + * Add a name to the shortform attribute list structure + * This is the external routine. + */ +STATIC int +xfs_attr_shortform_addname(xfs_da_args_t *args) +{ + int newsize, retval; + + retval = xfs_attr_shortform_lookup(args); + if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { + return(retval); + } else if (retval == EEXIST) { + if (args->flags & ATTR_CREATE) + return(retval); + retval = xfs_attr_shortform_remove(args); + ASSERT(retval == 0); + } + + newsize = XFS_ATTR_SF_TOTSIZE(args->dp); + newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); + if ((newsize <= XFS_IFORK_ASIZE(args->dp)) && + (args->namelen < XFS_ATTR_SF_ENTSIZE_MAX) && + (args->valuelen < XFS_ATTR_SF_ENTSIZE_MAX)) { + retval = xfs_attr_shortform_add(args); + ASSERT(retval == 0); + } else { + return(XFS_ERROR(ENOSPC)); + } + return(0); +} + + +/*======================================================================== + * External routines when attribute list is one block + *========================================================================*/ + +/* + * Add a name to the leaf attribute list structure + * + * This leaf block cannot have a "remote" value, we only call this routine + * if bmap_one_block() says there is only one block (ie: no remote blks). + */ +int +xfs_attr_leaf_addname(xfs_da_args_t *args) +{ + xfs_inode_t *dp; + xfs_dabuf_t *bp; + int retval, error, committed; + + /* + * Read the (only) block in the attribute list in. + */ + dp = args->dp; + args->blkno = 0; + error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, + XFS_ATTR_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + + /* + * Look up the given attribute in the leaf block. Figure out if + * the given flags produce an error or call for an atomic rename. + */ + retval = xfs_attr_leaf_lookup_int(bp, args); + if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { + xfs_da_brelse(args->trans, bp); + return(retval); + } else if (retval == EEXIST) { + if (args->flags & ATTR_CREATE) { /* pure create op */ + xfs_da_brelse(args->trans, bp); + return(retval); + } + args->rename = 1; /* an atomic rename */ + args->blkno2 = args->blkno; /* set 2nd entry info*/ + args->index2 = args->index; + args->rmtblkno2 = args->rmtblkno; + args->rmtblkcnt2 = args->rmtblkcnt; + } + + /* + * Add the attribute to the leaf block, transitioning to a Btree + * if required. + */ + retval = xfs_attr_leaf_add(bp, args); + xfs_da_buf_done(bp); + if (retval == ENOSPC) { + /* + * Promote the attribute list to the Btree format, then + * Commit that transaction so that the node_addname() call + * can manage its own transactions. + */ + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_attr_leaf_to_node(args); + if (!error) { + error = xfs_bmap_finish(&args->trans, args->flist, + *args->firstblock, &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + return(error); + } + + /* + * bmap_finish() may have committed the last trans and started + * a new one. We need the inode to be in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + + /* + * Commit the current trans (including the inode) and start + * a new one. + */ + if ((error = xfs_attr_rolltrans(&args->trans, dp))) + return (error); + + /* + * Fob the whole rest of the problem off on the Btree code. + */ + error = xfs_attr_node_addname(args); + return(error); + } + + /* + * Commit the transaction that added the attr name so that + * later routines can manage their own transactions. + */ + if ((error = xfs_attr_rolltrans(&args->trans, dp))) + return (error); + + /* + * If there was an out-of-line value, allocate the blocks we + * identified for its storage and copy the value. This is done + * after we create the attribute so that we don't overflow the + * maximum size of a transaction and/or hit a deadlock. + */ + if (args->rmtblkno > 0) { + error = xfs_attr_rmtval_set(args); + if (error) + return(error); + } + + /* + * If this is an atomic rename operation, we must "flip" the + * incomplete flags on the "new" and "old" attribute/value pairs + * so that one disappears and one appears atomically. Then we + * must remove the "old" attribute/value pair. + */ + if (args->rename) { + /* + * In a separate transaction, set the incomplete flag on the + * "old" attr and clear the incomplete flag on the "new" attr. + */ + error = xfs_attr_leaf_flipflags(args); + if (error) + return(error); + + /* + * Dismantle the "old" attribute/value pair by removing + * a "remote" value (if it exists). + */ + args->index = args->index2; + args->blkno = args->blkno2; + args->rmtblkno = args->rmtblkno2; + args->rmtblkcnt = args->rmtblkcnt2; + if (args->rmtblkno) { + error = xfs_attr_rmtval_remove(args); + if (error) + return(error); + } + + /* + * Read in the block containing the "old" attr, then + * remove the "old" attr from that block (neat, huh!) + */ + error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, + &bp, XFS_ATTR_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + (void)xfs_attr_leaf_remove(bp, args); + + /* + * If the result is small enough, shrink it all into the inode. + */ + if (xfs_attr_shortform_allfit(bp, dp)) { + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_attr_leaf_to_shortform(bp, args); + /* bp is gone due to xfs_da_shrink_inode */ + if (!error) { + error = xfs_bmap_finish(&args->trans, + args->flist, + *args->firstblock, + &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + return(error); + } + + /* + * bmap_finish() may have committed the last trans + * and started a new one. We need the inode to be + * in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + } else + xfs_da_buf_done(bp); + + /* + * Commit the remove and start the next trans in series. + */ + error = xfs_attr_rolltrans(&args->trans, dp); + + } else if (args->rmtblkno > 0) { + /* + * Added a "remote" value, just clear the incomplete flag. + */ + error = xfs_attr_leaf_clearflag(args); + } + return(error); +} + +/* + * Remove a name from the leaf attribute list structure + * + * This leaf block cannot have a "remote" value, we only call this routine + * if bmap_one_block() says there is only one block (ie: no remote blks). + */ +STATIC int +xfs_attr_leaf_removename(xfs_da_args_t *args) +{ + xfs_inode_t *dp; + xfs_dabuf_t *bp; + int committed; + int error; + + /* + * Remove the attribute. + */ + dp = args->dp; + args->blkno = 0; + error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, + XFS_ATTR_FORK); + if (error) { + return(error); + } + + ASSERT(bp != NULL); + error = xfs_attr_leaf_lookup_int(bp, args); + if (error == ENOATTR) { + xfs_da_brelse(args->trans, bp); + return(error); + } + + (void)xfs_attr_leaf_remove(bp, args); + + /* + * If the result is small enough, shrink it all into the inode. + */ + if (xfs_attr_shortform_allfit(bp, dp)) { + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_attr_leaf_to_shortform(bp, args); + /* bp is gone due to xfs_da_shrink_inode */ + if (!error) { + error = xfs_bmap_finish(&args->trans, args->flist, + *args->firstblock, &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + return(error); + } + + /* + * bmap_finish() may have committed the last trans and started + * a new one. We need the inode to be in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + } else + xfs_da_buf_done(bp); + return(0); +} + +/* + * Look up a name in a leaf attribute list structure. + * + * This leaf block cannot have a "remote" value, we only call this routine + * if bmap_one_block() says there is only one block (ie: no remote blks). + */ +int +xfs_attr_leaf_get(xfs_da_args_t *args) +{ + xfs_dabuf_t *bp; + int error; + + args->blkno = 0; + error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, + XFS_ATTR_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + + error = xfs_attr_leaf_lookup_int(bp, args); + if (error != EEXIST) { + xfs_da_brelse(args->trans, bp); + return(error); + } + error = xfs_attr_leaf_getvalue(bp, args); + xfs_da_brelse(args->trans, bp); + if ((error == 0) && (args->rmtblkno > 0)) { + error = xfs_attr_rmtval_get(args); + } + return(error); +} + +/* + * Copy out attribute entries for attr_list(), for leaf attribute lists. + */ +STATIC int +xfs_attr_leaf_list(xfs_attr_list_context_t *context) +{ + xfs_attr_leafblock_t *leaf; + int error; + xfs_dabuf_t *bp; + + context->cursor->blkno = 0; + error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + leaf = bp->data; + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + != XFS_ATTR_LEAF_MAGIC) { + xfs_da_brelse(NULL, bp); + return(XFS_ERROR(EFSCORRUPTED)); + } + + (void)xfs_attr_leaf_list_int(bp, context); + xfs_da_brelse(NULL, bp); + return(0); +} + + +/*======================================================================== + * External routines when attribute list size > XFS_LBSIZE(mp). + *========================================================================*/ + +/* + * Add a name to a Btree-format attribute list. + * + * This will involve walking down the Btree, and may involve splitting + * leaf nodes and even splitting intermediate nodes up to and including + * the root node (a special case of an intermediate node). + * + * "Remote" attribute values confuse the issue and atomic rename operations + * add a whole extra layer of confusion on top of that. + */ +STATIC int +xfs_attr_node_addname(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + xfs_da_state_blk_t *blk; + xfs_inode_t *dp; + xfs_mount_t *mp; + int committed, retval, error; + + /* + * Fill in bucket of arguments/results/context to carry around. + */ + dp = args->dp; + mp = dp->i_mount; +restart: + state = xfs_da_state_alloc(); + state->args = args; + state->mp = mp; + state->blocksize = state->mp->m_sb.sb_blocksize; + + /* + * Search to see if name already exists, and get back a pointer + * to where it should go. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) + goto out; + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); + if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) { + goto out; + } else if (retval == EEXIST) { + if (args->flags & ATTR_CREATE) + goto out; + args->rename = 1; /* atomic rename op */ + args->blkno2 = args->blkno; /* set 2nd entry info*/ + args->index2 = args->index; + args->rmtblkno2 = args->rmtblkno; + args->rmtblkcnt2 = args->rmtblkcnt; + args->rmtblkno = 0; + args->rmtblkcnt = 0; + } + + retval = xfs_attr_leaf_add(blk->bp, state->args); + if (retval == ENOSPC) { + if (state->path.active == 1) { + /* + * Its really a single leaf node, but it had + * out-of-line values so it looked like it *might* + * have been a b-tree. + */ + xfs_da_state_free(state); + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_attr_leaf_to_node(args); + if (!error) { + error = xfs_bmap_finish(&args->trans, + args->flist, + *args->firstblock, + &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + goto out; + } + + /* + * bmap_finish() may have committed the last trans + * and started a new one. We need the inode to be + * in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + + /* + * Commit the node conversion and start the next + * trans in the chain. + */ + if ((error = xfs_attr_rolltrans(&args->trans, dp))) + goto out; + + goto restart; + } + + /* + * Split as many Btree elements as required. + * This code tracks the new and old attr's location + * in the index/blkno/rmtblkno/rmtblkcnt fields and + * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields. + */ + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_da_split(state); + if (!error) { + error = xfs_bmap_finish(&args->trans, args->flist, + *args->firstblock, &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + goto out; + } + + /* + * bmap_finish() may have committed the last trans and started + * a new one. We need the inode to be in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + } else { + /* + * Addition succeeded, update Btree hashvals. + */ + xfs_da_fixhashpath(state, &state->path); + } + + /* + * Kill the state structure, we're done with it and need to + * allow the buffers to come back later. + */ + xfs_da_state_free(state); + state = NULL; + + /* + * Commit the leaf addition or btree split and start the next + * trans in the chain. + */ + if ((error = xfs_attr_rolltrans(&args->trans, dp))) + goto out; + + /* + * If there was an out-of-line value, allocate the blocks we + * identified for its storage and copy the value. This is done + * after we create the attribute so that we don't overflow the + * maximum size of a transaction and/or hit a deadlock. + */ + if (args->rmtblkno > 0) { + error = xfs_attr_rmtval_set(args); + if (error) + return(error); + } + + /* + * If this is an atomic rename operation, we must "flip" the + * incomplete flags on the "new" and "old" attribute/value pairs + * so that one disappears and one appears atomically. Then we + * must remove the "old" attribute/value pair. + */ + if (args->rename) { + /* + * In a separate transaction, set the incomplete flag on the + * "old" attr and clear the incomplete flag on the "new" attr. + */ + error = xfs_attr_leaf_flipflags(args); + if (error) + goto out; + + /* + * Dismantle the "old" attribute/value pair by removing + * a "remote" value (if it exists). + */ + args->index = args->index2; + args->blkno = args->blkno2; + args->rmtblkno = args->rmtblkno2; + args->rmtblkcnt = args->rmtblkcnt2; + if (args->rmtblkno) { + error = xfs_attr_rmtval_remove(args); + if (error) + return(error); + } + + /* + * Re-find the "old" attribute entry after any split ops. + * The INCOMPLETE flag means that we will find the "old" + * attr, not the "new" one. + */ + args->flags |= XFS_ATTR_INCOMPLETE; + state = xfs_da_state_alloc(); + state->args = args; + state->mp = mp; + state->blocksize = state->mp->m_sb.sb_blocksize; + state->inleaf = 0; + error = xfs_da_node_lookup_int(state, &retval); + if (error) + goto out; + + /* + * Remove the name and update the hashvals in the tree. + */ + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); + error = xfs_attr_leaf_remove(blk->bp, args); + xfs_da_fixhashpath(state, &state->path); + + /* + * Check to see if the tree needs to be collapsed. + */ + if (retval && (state->path.active > 1)) { + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_da_join(state); + if (!error) { + error = xfs_bmap_finish(&args->trans, + args->flist, + *args->firstblock, + &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + goto out; + } + + /* + * bmap_finish() may have committed the last trans + * and started a new one. We need the inode to be + * in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + } + + /* + * Commit and start the next trans in the chain. + */ + if ((error = xfs_attr_rolltrans(&args->trans, dp))) + goto out; + + } else if (args->rmtblkno > 0) { + /* + * Added a "remote" value, just clear the incomplete flag. + */ + error = xfs_attr_leaf_clearflag(args); + if (error) + goto out; + } + retval = error = 0; + +out: + if (state) + xfs_da_state_free(state); + if (error) + return(error); + return(retval); +} + +/* + * Remove a name from a B-tree attribute list. + * + * This will involve walking down the Btree, and may involve joining + * leaf nodes and even joining intermediate nodes up to and including + * the root node (a special case of an intermediate node). + */ +STATIC int +xfs_attr_node_removename(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + xfs_da_state_blk_t *blk; + xfs_inode_t *dp; + xfs_dabuf_t *bp; + int retval, error, committed; + + /* + * Tie a string around our finger to remind us where we are. + */ + dp = args->dp; + state = xfs_da_state_alloc(); + state->args = args; + state->mp = dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + + /* + * Search to see if name exists, and get back a pointer to it. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error || (retval != EEXIST)) { + if (error == 0) + error = retval; + goto out; + } + + /* + * If there is an out-of-line value, de-allocate the blocks. + * This is done before we remove the attribute so that we don't + * overflow the maximum size of a transaction and/or hit a deadlock. + */ + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->bp != NULL); + ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); + if (args->rmtblkno > 0) { + /* + * Fill in disk block numbers in the state structure + * so that we can get the buffers back after we commit + * several transactions in the following calls. + */ + error = xfs_attr_fillstate(state); + if (error) + goto out; + + /* + * Mark the attribute as INCOMPLETE, then bunmapi() the + * remote value. + */ + error = xfs_attr_leaf_setflag(args); + if (error) + goto out; + error = xfs_attr_rmtval_remove(args); + if (error) + goto out; + + /* + * Refill the state structure with buffers, the prior calls + * released our buffers. + */ + error = xfs_attr_refillstate(state); + if (error) + goto out; + } + + /* + * Remove the name and update the hashvals in the tree. + */ + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); + retval = xfs_attr_leaf_remove(blk->bp, args); + xfs_da_fixhashpath(state, &state->path); + + /* + * Check to see if the tree needs to be collapsed. + */ + if (retval && (state->path.active > 1)) { + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_da_join(state); + if (!error) { + error = xfs_bmap_finish(&args->trans, args->flist, + *args->firstblock, &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + goto out; + } + + /* + * bmap_finish() may have committed the last trans and started + * a new one. We need the inode to be in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + + /* + * Commit the Btree join operation and start a new trans. + */ + if ((error = xfs_attr_rolltrans(&args->trans, dp))) + goto out; + } + + /* + * If the result is small enough, push it all into the inode. + */ + if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { + /* + * Have to get rid of the copy of this dabuf in the state. + */ + ASSERT(state->path.active == 1); + ASSERT(state->path.blk[0].bp); + xfs_da_buf_done(state->path.blk[0].bp); + state->path.blk[0].bp = NULL; + + error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, + XFS_ATTR_FORK); + if (error) + goto out; + ASSERT(INT_GET(((xfs_attr_leafblock_t *) + bp->data)->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + + if (xfs_attr_shortform_allfit(bp, dp)) { + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_attr_leaf_to_shortform(bp, args); + /* bp is gone due to xfs_da_shrink_inode */ + if (!error) { + error = xfs_bmap_finish(&args->trans, + args->flist, + *args->firstblock, + &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + goto out; + } + + /* + * bmap_finish() may have committed the last trans + * and started a new one. We need the inode to be + * in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + } else + xfs_da_brelse(args->trans, bp); + } + error = 0; + +out: + xfs_da_state_free(state); + return(error); +} + +/* + * Fill in the disk block numbers in the state structure for the buffers + * that are attached to the state structure. + * This is done so that we can quickly reattach ourselves to those buffers + * after some set of transaction commit's has released these buffers. + */ +STATIC int +xfs_attr_fillstate(xfs_da_state_t *state) +{ + xfs_da_state_path_t *path; + xfs_da_state_blk_t *blk; + int level; + + /* + * Roll down the "path" in the state structure, storing the on-disk + * block number for those buffers in the "path". + */ + path = &state->path; + ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); + for (blk = path->blk, level = 0; level < path->active; blk++, level++) { + if (blk->bp) { + blk->disk_blkno = xfs_da_blkno(blk->bp); + xfs_da_buf_done(blk->bp); + blk->bp = NULL; + } else { + blk->disk_blkno = 0; + } + } + + /* + * Roll down the "altpath" in the state structure, storing the on-disk + * block number for those buffers in the "altpath". + */ + path = &state->altpath; + ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); + for (blk = path->blk, level = 0; level < path->active; blk++, level++) { + if (blk->bp) { + blk->disk_blkno = xfs_da_blkno(blk->bp); + xfs_da_buf_done(blk->bp); + blk->bp = NULL; + } else { + blk->disk_blkno = 0; + } + } + + return(0); +} + +/* + * Reattach the buffers to the state structure based on the disk block + * numbers stored in the state structure. + * This is done after some set of transaction commit's has released those + * buffers from our grip. + */ +STATIC int +xfs_attr_refillstate(xfs_da_state_t *state) +{ + xfs_da_state_path_t *path; + xfs_da_state_blk_t *blk; + int level, error; + + /* + * Roll down the "path" in the state structure, storing the on-disk + * block number for those buffers in the "path". + */ + path = &state->path; + ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); + for (blk = path->blk, level = 0; level < path->active; blk++, level++) { + if (blk->disk_blkno) { + error = xfs_da_read_buf(state->args->trans, + state->args->dp, + blk->blkno, blk->disk_blkno, + &blk->bp, XFS_ATTR_FORK); + if (error) + return(error); + } else { + blk->bp = NULL; + } + } + + /* + * Roll down the "altpath" in the state structure, storing the on-disk + * block number for those buffers in the "altpath". + */ + path = &state->altpath; + ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); + for (blk = path->blk, level = 0; level < path->active; blk++, level++) { + if (blk->disk_blkno) { + error = xfs_da_read_buf(state->args->trans, + state->args->dp, + blk->blkno, blk->disk_blkno, + &blk->bp, XFS_ATTR_FORK); + if (error) + return(error); + } else { + blk->bp = NULL; + } + } + + return(0); +} + +/* + * Look up a filename in a node attribute list. + * + * This routine gets called for any attribute fork that has more than one + * block, ie: both true Btree attr lists and for single-leaf-blocks with + * "remote" values taking up more blocks. + */ +int +xfs_attr_node_get(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + xfs_da_state_blk_t *blk; + int error, retval; + int i; + + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + + /* + * Search to see if name exists, and get back a pointer to it. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) { + retval = error; + } else if (retval == EEXIST) { + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->bp != NULL); + ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); + + /* + * Get the value, local or "remote" + */ + retval = xfs_attr_leaf_getvalue(blk->bp, args); + if ((retval == 0) && (args->rmtblkno > 0)) { + retval = xfs_attr_rmtval_get(args); + } + } + + /* + * If not in a transaction, we have to release all the buffers. + */ + for (i = 0; i < state->path.active; i++) { + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + + xfs_da_state_free(state); + return(retval); +} + +STATIC int /* error */ +xfs_attr_node_list(xfs_attr_list_context_t *context) +{ + attrlist_cursor_kern_t *cursor; + xfs_attr_leafblock_t *leaf; + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + int error, i; + xfs_dabuf_t *bp; + + cursor = context->cursor; + cursor->initted = 1; + + /* + * Do all sorts of validation on the passed-in cursor structure. + * If anything is amiss, ignore the cursor and look up the hashval + * starting from the btree root. + */ + bp = NULL; + if (cursor->blkno > 0) { + error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1, + &bp, XFS_ATTR_FORK); + if ((error != 0) && (error != EFSCORRUPTED)) + return(error); + if (bp) { + node = bp->data; + switch (INT_GET(node->hdr.info.magic, ARCH_CONVERT)) { + case XFS_DA_NODE_MAGIC: + xfs_attr_trace_l_cn("wrong blk", context, node); + xfs_da_brelse(NULL, bp); + bp = NULL; + break; + case XFS_ATTR_LEAF_MAGIC: + leaf = bp->data; + if (cursor->hashval > + INT_GET(leaf->entries[ + INT_GET(leaf->hdr.count, + ARCH_CONVERT)-1].hashval, + ARCH_CONVERT)) { + xfs_attr_trace_l_cl("wrong blk", + context, leaf); + xfs_da_brelse(NULL, bp); + bp = NULL; + } else if (cursor->hashval <= + INT_GET(leaf->entries[0].hashval, + ARCH_CONVERT)) { + xfs_attr_trace_l_cl("maybe wrong blk", + context, leaf); + xfs_da_brelse(NULL, bp); + bp = NULL; + } + break; + default: + xfs_attr_trace_l_c("wrong blk - ??", context); + xfs_da_brelse(NULL, bp); + bp = NULL; + } + } + } + + /* + * We did not find what we expected given the cursor's contents, + * so we start from the top and work down based on the hash value. + * Note that start of node block is same as start of leaf block. + */ + if (bp == NULL) { + cursor->blkno = 0; + for (;;) { + error = xfs_da_read_buf(NULL, context->dp, + cursor->blkno, -1, &bp, + XFS_ATTR_FORK); + if (error) + return(error); + if (bp == NULL) + return(XFS_ERROR(EFSCORRUPTED)); + node = bp->data; + if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC) + break; + if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) + != XFS_DA_NODE_MAGIC) { + xfs_da_brelse(NULL, bp); + return(XFS_ERROR(EFSCORRUPTED)); + } + btree = node->btree; + for (i = 0; + i < INT_GET(node->hdr.count, ARCH_CONVERT); + btree++, i++) { + if (cursor->hashval + <= INT_GET(btree->hashval, + ARCH_CONVERT)) { + cursor->blkno = INT_GET(btree->before, ARCH_CONVERT); + xfs_attr_trace_l_cb("descending", + context, btree); + break; + } + } + if (i == INT_GET(node->hdr.count, ARCH_CONVERT)) { + xfs_da_brelse(NULL, bp); + return(0); + } + xfs_da_brelse(NULL, bp); + } + } + ASSERT(bp != NULL); + + /* + * Roll upward through the blocks, processing each leaf block in + * order. As long as there is space in the result buffer, keep + * adding the information. + */ + for (;;) { + leaf = bp->data; + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + != XFS_ATTR_LEAF_MAGIC) { + xfs_da_brelse(NULL, bp); + return(XFS_ERROR(EFSCORRUPTED)); + } + error = xfs_attr_leaf_list_int(bp, context); + if (error || (INT_GET(leaf->hdr.info.forw, ARCH_CONVERT) == 0)) + break; /* not really an error, buffer full or EOF */ + cursor->blkno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT); + xfs_da_brelse(NULL, bp); + error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1, + &bp, XFS_ATTR_FORK); + if (error) + return(error); + if (bp == NULL) + return(XFS_ERROR(EFSCORRUPTED)); + } + xfs_da_brelse(NULL, bp); + return(0); +} + + +/*======================================================================== + * External routines for manipulating out-of-line attribute values. + *========================================================================*/ + +/* + * Read the value associated with an attribute from the out-of-line buffer + * that we stored it in. + */ +STATIC int +xfs_attr_rmtval_get(xfs_da_args_t *args) +{ + xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE]; + xfs_fsblock_t firstblock; + xfs_mount_t *mp; + xfs_daddr_t dblkno; + xfs_caddr_t dst; + xfs_buf_t *bp; + int nmap, error, tmp, valuelen, blkcnt, i; + xfs_dablk_t lblkno; + + mp = args->dp->i_mount; + dst = args->value; + valuelen = args->valuelen; + lblkno = args->rmtblkno; + while (valuelen > 0) { + firstblock = NULLFSBLOCK; + nmap = ATTR_RMTVALUE_MAPSIZE; + error = xfs_bmapi(args->trans, args->dp, (xfs_fileoff_t)lblkno, + args->rmtblkcnt, + XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, + &firstblock, 0, map, &nmap, NULL); + if (error) + return(error); + ASSERT(nmap >= 1); + + for (i = 0; (i < nmap) && (valuelen > 0); i++) { + ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) && + (map[i].br_startblock != HOLESTARTBLOCK)); + dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); + blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); + error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno, + blkcnt, XFS_BUF_LOCK, &bp); + if (error) + return(error); + + tmp = (valuelen < XFS_BUF_SIZE(bp)) + ? valuelen : XFS_BUF_SIZE(bp); + xfs_biomove(bp, 0, tmp, dst, XFS_B_READ); + xfs_buf_relse(bp); + dst += tmp; + valuelen -= tmp; + + lblkno += map[i].br_blockcount; + } + } + ASSERT(valuelen == 0); + return(0); +} + +/* + * Write the value associated with an attribute into the out-of-line buffer + * that we have defined for it. + */ +STATIC int +xfs_attr_rmtval_set(xfs_da_args_t *args) +{ + xfs_mount_t *mp; + xfs_fileoff_t lfileoff; + xfs_inode_t *dp; + xfs_bmbt_irec_t map; + xfs_daddr_t dblkno; + xfs_caddr_t src; + xfs_buf_t *bp; + xfs_dablk_t lblkno; + int blkcnt, valuelen, nmap, error, tmp, committed; + + dp = args->dp; + mp = dp->i_mount; + src = args->value; + + /* + * Find a "hole" in the attribute address space large enough for + * us to drop the new attribute's value into. + */ + blkcnt = XFS_B_TO_FSB(mp, args->valuelen); + lfileoff = 0; + error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, + XFS_ATTR_FORK); + if (error) { + return(error); + } + args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff; + args->rmtblkcnt = blkcnt; + + /* + * Roll through the "value", allocating blocks on disk as required. + */ + while (blkcnt > 0) { + /* + * Allocate a single extent, up to the size of the value. + */ + XFS_BMAP_INIT(args->flist, args->firstblock); + nmap = 1; + error = xfs_bmapi(args->trans, dp, (xfs_fileoff_t)lblkno, + blkcnt, + XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA | + XFS_BMAPI_WRITE, + args->firstblock, args->total, &map, &nmap, + args->flist); + if (!error) { + error = xfs_bmap_finish(&args->trans, args->flist, + *args->firstblock, &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + return(error); + } + + /* + * bmap_finish() may have committed the last trans and started + * a new one. We need the inode to be in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, dp); + } + + ASSERT(nmap == 1); + ASSERT((map.br_startblock != DELAYSTARTBLOCK) && + (map.br_startblock != HOLESTARTBLOCK)); + lblkno += map.br_blockcount; + blkcnt -= map.br_blockcount; + + /* + * Start the next trans in the chain. + */ + if ((error = xfs_attr_rolltrans(&args->trans, dp))) + return (error); + } + + /* + * Roll through the "value", copying the attribute value to the + * already-allocated blocks. Blocks are written synchronously + * so that we can know they are all on disk before we turn off + * the INCOMPLETE flag. + */ + lblkno = args->rmtblkno; + valuelen = args->valuelen; + while (valuelen > 0) { + /* + * Try to remember where we decided to put the value. + */ + XFS_BMAP_INIT(args->flist, args->firstblock); + nmap = 1; + error = xfs_bmapi(NULL, dp, (xfs_fileoff_t)lblkno, + args->rmtblkcnt, + XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, + args->firstblock, 0, &map, &nmap, NULL); + if (error) { + return(error); + } + ASSERT(nmap == 1); + ASSERT((map.br_startblock != DELAYSTARTBLOCK) && + (map.br_startblock != HOLESTARTBLOCK)); + + dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), + blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); + + bp = xfs_buf_get_flags(mp->m_ddev_targp, dblkno, + blkcnt, XFS_BUF_LOCK); + ASSERT(bp); + ASSERT(!XFS_BUF_GETERROR(bp)); + + tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen : + XFS_BUF_SIZE(bp); + xfs_biomove(bp, 0, tmp, src, XFS_B_WRITE); + if (tmp < XFS_BUF_SIZE(bp)) + xfs_biozero(bp, tmp, XFS_BUF_SIZE(bp) - tmp); + if ((error = xfs_bwrite(mp, bp))) {/* GROT: NOTE: synchronous write */ + return (error); + } + src += tmp; + valuelen -= tmp; + + lblkno += map.br_blockcount; + } + ASSERT(valuelen == 0); + return(0); +} + +/* + * Remove the value associated with an attribute by deleting the + * out-of-line buffer that it is stored on. + */ +STATIC int +xfs_attr_rmtval_remove(xfs_da_args_t *args) +{ + xfs_mount_t *mp; + xfs_bmbt_irec_t map; + xfs_buf_t *bp; + xfs_daddr_t dblkno; + xfs_dablk_t lblkno; + int valuelen, blkcnt, nmap, error, done, committed; + + mp = args->dp->i_mount; + + /* + * Roll through the "value", invalidating the attribute value's + * blocks. + */ + lblkno = args->rmtblkno; + valuelen = args->rmtblkcnt; + while (valuelen > 0) { + /* + * Try to remember where we decided to put the value. + */ + XFS_BMAP_INIT(args->flist, args->firstblock); + nmap = 1; + error = xfs_bmapi(NULL, args->dp, (xfs_fileoff_t)lblkno, + args->rmtblkcnt, + XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, + args->firstblock, 0, &map, &nmap, + args->flist); + if (error) { + return(error); + } + ASSERT(nmap == 1); + ASSERT((map.br_startblock != DELAYSTARTBLOCK) && + (map.br_startblock != HOLESTARTBLOCK)); + + dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), + blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); + + /* + * If the "remote" value is in the cache, remove it. + */ + /* bp = incore(mp->m_dev, dblkno, blkcnt, 1); */ + bp = xfs_incore(mp->m_ddev_targ, dblkno, blkcnt, 1); + if (bp) { + XFS_BUF_STALE(bp); + XFS_BUF_UNDELAYWRITE(bp); + xfs_buf_relse(bp); + bp = NULL; + } + + valuelen -= map.br_blockcount; + + lblkno += map.br_blockcount; + } + + /* + * Keep de-allocating extents until the remote-value region is gone. + */ + lblkno = args->rmtblkno; + blkcnt = args->rmtblkcnt; + done = 0; + while (!done) { + XFS_BMAP_INIT(args->flist, args->firstblock); + error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt, + XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, + 1, args->firstblock, args->flist, &done); + if (!error) { + error = xfs_bmap_finish(&args->trans, args->flist, + *args->firstblock, &committed); + } + if (error) { + ASSERT(committed); + args->trans = NULL; + xfs_bmap_cancel(args->flist); + return(error); + } + + /* + * bmap_finish() may have committed the last trans and started + * a new one. We need the inode to be in all transactions. + */ + if (committed) { + xfs_trans_ijoin(args->trans, args->dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(args->trans, args->dp); + } + + /* + * Close out trans and start the next one in the chain. + */ + if ((error = xfs_attr_rolltrans(&args->trans, args->dp))) + return (error); + } + return(0); +} + +#if defined(XFS_ATTR_TRACE) +/* + * Add a trace buffer entry for an attr_list context structure. + */ +void +xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context) +{ + xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where, + (__psunsigned_t)context->dp, + (__psunsigned_t)context->cursor->hashval, + (__psunsigned_t)context->cursor->blkno, + (__psunsigned_t)context->cursor->offset, + (__psunsigned_t)context->alist, + (__psunsigned_t)context->bufsize, + (__psunsigned_t)context->count, + (__psunsigned_t)context->firstu, + (__psunsigned_t) + (context->count > 0) + ? (ATTR_ENTRY(context->alist, + context->count-1)->a_valuelen) + : 0, + (__psunsigned_t)context->dupcnt, + (__psunsigned_t)context->flags, + (__psunsigned_t)NULL, + (__psunsigned_t)NULL, + (__psunsigned_t)NULL); +} + +/* + * Add a trace buffer entry for a context structure and a Btree node. + */ +void +xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context, + struct xfs_da_intnode *node) +{ + xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where, + (__psunsigned_t)context->dp, + (__psunsigned_t)context->cursor->hashval, + (__psunsigned_t)context->cursor->blkno, + (__psunsigned_t)context->cursor->offset, + (__psunsigned_t)context->alist, + (__psunsigned_t)context->bufsize, + (__psunsigned_t)context->count, + (__psunsigned_t)context->firstu, + (__psunsigned_t) + (context->count > 0) + ? (ATTR_ENTRY(context->alist, + context->count-1)->a_valuelen) + : 0, + (__psunsigned_t)context->dupcnt, + (__psunsigned_t)context->flags, + (__psunsigned_t)INT_GET(node->hdr.count, ARCH_CONVERT), + (__psunsigned_t)INT_GET(node->btree[0].hashval, ARCH_CONVERT), + (__psunsigned_t)INT_GET(node->btree[INT_GET(node->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT)); +} + +/* + * Add a trace buffer entry for a context structure and a Btree element. + */ +void +xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context, + struct xfs_da_node_entry *btree) +{ + xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where, + (__psunsigned_t)context->dp, + (__psunsigned_t)context->cursor->hashval, + (__psunsigned_t)context->cursor->blkno, + (__psunsigned_t)context->cursor->offset, + (__psunsigned_t)context->alist, + (__psunsigned_t)context->bufsize, + (__psunsigned_t)context->count, + (__psunsigned_t)context->firstu, + (__psunsigned_t) + (context->count > 0) + ? (ATTR_ENTRY(context->alist, + context->count-1)->a_valuelen) + : 0, + (__psunsigned_t)context->dupcnt, + (__psunsigned_t)context->flags, + (__psunsigned_t)INT_GET(btree->hashval, ARCH_CONVERT), + (__psunsigned_t)INT_GET(btree->before, ARCH_CONVERT), + (__psunsigned_t)NULL); +} + +/* + * Add a trace buffer entry for a context structure and a leaf block. + */ +void +xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, + struct xfs_attr_leafblock *leaf) +{ + xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where, + (__psunsigned_t)context->dp, + (__psunsigned_t)context->cursor->hashval, + (__psunsigned_t)context->cursor->blkno, + (__psunsigned_t)context->cursor->offset, + (__psunsigned_t)context->alist, + (__psunsigned_t)context->bufsize, + (__psunsigned_t)context->count, + (__psunsigned_t)context->firstu, + (__psunsigned_t) + (context->count > 0) + ? (ATTR_ENTRY(context->alist, + context->count-1)->a_valuelen) + : 0, + (__psunsigned_t)context->dupcnt, + (__psunsigned_t)context->flags, + (__psunsigned_t)INT_GET(leaf->hdr.count, ARCH_CONVERT), + (__psunsigned_t)INT_GET(leaf->entries[0].hashval, ARCH_CONVERT), + (__psunsigned_t)INT_GET(leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT)); +} + +/* + * Add a trace buffer entry for the arguments given to the routine, + * generic form. + */ +void +xfs_attr_trace_enter(int type, char *where, + __psunsigned_t a2, __psunsigned_t a3, + __psunsigned_t a4, __psunsigned_t a5, + __psunsigned_t a6, __psunsigned_t a7, + __psunsigned_t a8, __psunsigned_t a9, + __psunsigned_t a10, __psunsigned_t a11, + __psunsigned_t a12, __psunsigned_t a13, + __psunsigned_t a14, __psunsigned_t a15) +{ + ASSERT(xfs_attr_trace_buf); + ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type), + (void *)where, + (void *)a2, (void *)a3, (void *)a4, + (void *)a5, (void *)a6, (void *)a7, + (void *)a8, (void *)a9, (void *)a10, + (void *)a11, (void *)a12, (void *)a13, + (void *)a14, (void *)a15); +} +#endif /* XFS_ATTR_TRACE */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_attr.h linux-2.4-xfs/linux/fs/xfs/xfs_attr.h --- linux-2.4.7/linux/fs/xfs/xfs_attr.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_attr.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ATTR_H__ +#define __XFS_ATTR_H__ + +/* + * xfs_attr.h + * + * Large attribute lists are structured around Btrees where all the data + * elements are in the leaf nodes. Attribute names are hashed into an int, + * then that int is used as the index into the Btree. Since the hashval + * of an attribute name may not be unique, we may have duplicate keys. + * The internal links in the Btree are logical block offsets into the file. + * + * Small attribute lists use a different format and are packed as tightly + * as possible so as to fit into the literal area of the inode. + */ + +#ifdef XFS_ALL_TRACE +#define XFS_ATTR_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_ATTR_TRACE +#endif + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +struct cred; +struct vnode; +struct xfs_inode; +struct attrlist_cursor_kern; +struct xfs_ext_attr; +struct xfs_da_args; + +/* + * Overall external interface routines. + */ +int xfs_attr_get(bhv_desc_t *, char *, char *, int *, int, struct cred *); +int xfs_attr_set(bhv_desc_t *, char *, char *, int, int, struct cred *); +int xfs_attr_remove(bhv_desc_t *, char *, int, struct cred *); +int xfs_attr_list(bhv_desc_t *, char *, int, int, + struct attrlist_cursor_kern *, struct cred *); +int xfs_attr_inactive(struct xfs_inode *dp); + +int xfs_attr_node_get(struct xfs_da_args *); +int xfs_attr_leaf_get(struct xfs_da_args *); +int xfs_attr_shortform_getvalue(struct xfs_da_args *); +int xfs_attr_fetch(struct xfs_inode *, char *, char *, int); + +#endif /* __XFS_ATTR_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_attr_fetch.c linux-2.4-xfs/linux/fs/xfs/xfs_attr_fetch.c --- linux-2.4.7/linux/fs/xfs/xfs_attr_fetch.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_attr_fetch.c Mon Sep 25 00:42:07 2000 @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +int +xfs_attr_fetch(xfs_inode_t *ip, char *name, char *value, int valuelen) +{ + xfs_da_args_t args; + int error; + + /* + * Do the argument setup for the xfs_attr routines. + */ + bzero((char *)&args, sizeof(args)); + args.dp = ip; + args.flags = ATTR_ROOT; + args.whichfork = XFS_ATTR_FORK; + args.name = name; + args.namelen = strlen(name); + args.value = value; + args.valuelen = valuelen; + args.hashval = xfs_da_hashname(args.name, args.namelen); + args.oknoent = 1; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (XFS_IFORK_Q(args.dp) == 0) + error = ENOATTR; + else if (args.dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) + error = xfs_attr_shortform_getvalue(&args); + else if (xfs_bmap_one_block(args.dp, XFS_ATTR_FORK)) + error = xfs_attr_leaf_get(&args); + else + error = xfs_attr_node_get(&args); + + if (error == EEXIST) + error = 0; + + return(error); +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_attr_leaf.c linux-2.4-xfs/linux/fs/xfs/xfs_attr_leaf.c --- linux-2.4.7/linux/fs/xfs/xfs_attr_leaf.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_attr_leaf.c Tue Apr 10 20:44:54 2001 @@ -0,0 +1,2904 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +/* + * xfs_attr_leaf.c + * + * GROT: figure out how to recover gracefully when bmap returns ENOSPC. + */ + +#include + +/* + * xfs_attr_leaf.c + * + * Routines to implement leaf blocks of attributes as Btrees of hashed names. + */ + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Routines used for growing the Btree. + */ +STATIC int xfs_attr_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args, + int freemap_index); +STATIC void xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer); +STATIC void xfs_attr_leaf_rebalance(xfs_da_state_t *state, + xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2); +STATIC int xfs_attr_leaf_figure_balance(xfs_da_state_t *state, + xfs_da_state_blk_t *leaf_blk_1, + xfs_da_state_blk_t *leaf_blk_2, + int *number_entries_in_blk1, + int *number_usedbytes_in_blk1); + +/* + * Utility routines. + */ +STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf, + int src_start, + xfs_attr_leafblock_t *dst_leaf, + int dst_start, int move_count, + xfs_mount_t *mp); + + +/*======================================================================== + * External routines when dirsize < XFS_LITINO(mp). + *========================================================================*/ + +/* + * Create the initial contents of a shortform attribute list. + */ +int +xfs_attr_shortform_create(xfs_da_args_t *args) +{ + xfs_attr_sf_hdr_t *hdr; + xfs_inode_t *dp; + xfs_ifork_t *ifp; + + dp = args->dp; + ASSERT(dp != NULL); + ifp = dp->i_afp; + ASSERT(ifp != NULL); + ASSERT(ifp->if_bytes == 0); + if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) { + ifp->if_flags &= ~XFS_IFEXTENTS; /* just in case */ + dp->i_d.di_aformat = XFS_DINODE_FMT_LOCAL; + ifp->if_flags |= XFS_IFINLINE; + } else { + ASSERT(ifp->if_flags & XFS_IFINLINE); + } + xfs_idata_realloc(dp, sizeof(*hdr), XFS_ATTR_FORK); + hdr = (xfs_attr_sf_hdr_t *)ifp->if_u1.if_data; + INT_SET(hdr->count, ARCH_CONVERT, 0); + INT_SET(hdr->totsize, ARCH_CONVERT, sizeof(*hdr)); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); + return(0); +} + +/* + * Add a name/value pair to the shortform attribute list. + * Overflow from the inode has already been checked for. + */ +int +xfs_attr_shortform_add(xfs_da_args_t *args) +{ + xfs_attr_shortform_t *sf; + xfs_attr_sf_entry_t *sfe; + int i, offset, size; + xfs_inode_t *dp; + xfs_ifork_t *ifp; + + dp = args->dp; + ifp = dp->i_afp; + ASSERT(ifp->if_flags & XFS_IFINLINE); + sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; + sfe = &sf->list[0]; + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); + sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { + if (sfe->namelen != args->namelen) + continue; + if (bcmp(args->name, sfe->nameval, args->namelen) != 0) + continue; + if (((args->flags & ATTR_ROOT) != 0) != + ((sfe->flags & XFS_ATTR_ROOT) != 0)) + continue; + return(XFS_ERROR(EEXIST)); + } + + offset = (char *)sfe - (char *)sf; + size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); + xfs_idata_realloc(dp, size, XFS_ATTR_FORK); + sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; + sfe = (xfs_attr_sf_entry_t *)((char *)sf + offset); + + sfe->namelen = args->namelen; + INT_SET(sfe->valuelen, ARCH_CONVERT, args->valuelen); + sfe->flags = (args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0; + bcopy(args->name, sfe->nameval, args->namelen); + bcopy(args->value, &sfe->nameval[args->namelen], args->valuelen); + INT_MOD(sf->hdr.count, ARCH_CONVERT, 1); + INT_MOD(sf->hdr.totsize, ARCH_CONVERT, size); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); + + return(0); +} + +/* + * Remove a name from the shortform attribute list structure. + */ +int +xfs_attr_shortform_remove(xfs_da_args_t *args) +{ + xfs_attr_shortform_t *sf; + xfs_attr_sf_entry_t *sfe; + int base, size=0, end, totsize, i; + xfs_inode_t *dp; + + /* + * Remove the attribute. + */ + dp = args->dp; + base = sizeof(xfs_attr_sf_hdr_t); + sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data; + sfe = &sf->list[0]; + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); + sfe = XFS_ATTR_SF_NEXTENTRY(sfe), + base += size, i++) { + size = XFS_ATTR_SF_ENTSIZE(sfe); + if (sfe->namelen != args->namelen) + continue; + if (bcmp(sfe->nameval, args->name, args->namelen) != 0) + continue; + if (((args->flags & ATTR_ROOT) != 0) != + ((sfe->flags & XFS_ATTR_ROOT) != 0)) + continue; + break; + } + if (i == INT_GET(sf->hdr.count, ARCH_CONVERT)) + return(XFS_ERROR(ENOATTR)); + + end = base + size; + totsize = INT_GET(sf->hdr.totsize, ARCH_CONVERT); + if (end != totsize) { + ovbcopy(&((char *)sf)[end], &((char *)sf)[base], + totsize - end); + } + INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); + INT_MOD(sf->hdr.totsize, ARCH_CONVERT, -size); + xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); + + return(0); +} + +/* + * Look up a name in a shortform attribute list structure. + */ +/*ARGSUSED*/ +int +xfs_attr_shortform_lookup(xfs_da_args_t *args) +{ + xfs_attr_shortform_t *sf; + xfs_attr_sf_entry_t *sfe; + int i; + xfs_ifork_t *ifp; + + ifp = args->dp->i_afp; + ASSERT(ifp->if_flags & XFS_IFINLINE); + sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; + sfe = &sf->list[0]; + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); + sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { + if (sfe->namelen != args->namelen) + continue; + if (bcmp(args->name, sfe->nameval, args->namelen) != 0) + continue; + if (((args->flags & ATTR_ROOT) != 0) != + ((sfe->flags & XFS_ATTR_ROOT) != 0)) + continue; + return(XFS_ERROR(EEXIST)); + } + return(XFS_ERROR(ENOATTR)); +} + +/* + * Look up a name in a shortform attribute list structure. + */ +/*ARGSUSED*/ +int +xfs_attr_shortform_getvalue(xfs_da_args_t *args) +{ + xfs_attr_shortform_t *sf; + xfs_attr_sf_entry_t *sfe; + int i; + + ASSERT(args->dp->i_d.di_aformat == XFS_IFINLINE); + sf = (xfs_attr_shortform_t *)args->dp->i_afp->if_u1.if_data; + sfe = &sf->list[0]; + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); + sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { + if (sfe->namelen != args->namelen) + continue; + if (bcmp(args->name, sfe->nameval, args->namelen) != 0) + continue; + if (((args->flags & ATTR_ROOT) != 0) != + ((sfe->flags & XFS_ATTR_ROOT) != 0)) + continue; + if (args->valuelen < INT_GET(sfe->valuelen, ARCH_CONVERT)) { + args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT); + return(XFS_ERROR(E2BIG)); + } + args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT); + bcopy(&sfe->nameval[args->namelen], args->value, + args->valuelen); + return(XFS_ERROR(EEXIST)); + } + return(XFS_ERROR(ENOATTR)); +} + +/* + * Convert from using the shortform to the leaf. + */ +int +xfs_attr_shortform_to_leaf(xfs_da_args_t *args) +{ + xfs_inode_t *dp; + xfs_attr_shortform_t *sf; + xfs_attr_sf_entry_t *sfe; + xfs_da_args_t nargs; + char *tmpbuffer; + int error, i, size; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + xfs_ifork_t *ifp; + + dp = args->dp; + ifp = dp->i_afp; + sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; + size = INT_GET(sf->hdr.totsize, ARCH_CONVERT); + tmpbuffer = kmem_alloc(size, KM_SLEEP); + ASSERT(tmpbuffer != NULL); + bcopy(ifp->if_u1.if_data, tmpbuffer, size); + sf = (xfs_attr_shortform_t *)tmpbuffer; + + xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); + bp = NULL; + error = xfs_da_grow_inode(args, &blkno); + if (error) { + /* + * If we hit an IO error middle of the transaction inside + * grow_inode(), we may have inconsistent data. Bail out. + */ + if (error == EIO) + goto out; + xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ + bcopy(tmpbuffer, ifp->if_u1.if_data, size); /* it back */ + goto out; + } + + ASSERT(blkno == 0); + error = xfs_attr_leaf_create(args, blkno, &bp); + if (error) { + error = xfs_da_shrink_inode(args, 0, bp); + bp = NULL; + if (error) + goto out; + xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ + bcopy(tmpbuffer, ifp->if_u1.if_data, size); /* it back */ + goto out; + } + + bzero((char *)&nargs, sizeof(nargs)); + nargs.dp = dp; + nargs.firstblock = args->firstblock; + nargs.flist = args->flist; + nargs.total = args->total; + nargs.whichfork = XFS_ATTR_FORK; + nargs.trans = args->trans; + nargs.oknoent = 1; + + sfe = &sf->list[0]; + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { + nargs.name = (char *)sfe->nameval; + nargs.namelen = sfe->namelen; + nargs.value = (char *)&sfe->nameval[nargs.namelen]; + nargs.valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT); + nargs.hashval = xfs_da_hashname((char *)sfe->nameval, + sfe->namelen); + nargs.flags = (sfe->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0; + error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */ + ASSERT(error == ENOATTR); + error = xfs_attr_leaf_add(bp, &nargs); + ASSERT(error != ENOSPC); + if (error) + goto out; + sfe = XFS_ATTR_SF_NEXTENTRY(sfe); + } + error = 0; + +out: + xfs_da_buf_done(bp); + kmem_free(tmpbuffer, size); + return(error); +} + +STATIC int +xfs_attr_shortform_compare(const void *a, const void *b) +{ + xfs_attr_sf_sort_t *sa, *sb; + + sa = (xfs_attr_sf_sort_t *)a; + sb = (xfs_attr_sf_sort_t *)b; + if (INT_GET(sa->hash, ARCH_CONVERT) + < INT_GET(sb->hash, ARCH_CONVERT)) { + return(-1); + } else if (INT_GET(sa->hash, ARCH_CONVERT) + > INT_GET(sb->hash, ARCH_CONVERT)) { + return(1); + } else { + return(sa->entno - sb->entno); + } +} + +/* + * Copy out entries of shortform attribute lists for attr_list(). + * Shortform atrtribute lists are not stored in hashval sorted order. + * If the output buffer is not large enough to hold them all, then we + * we have to calculate each entries' hashvalue and sort them before + * we can begin returning them to the user. + */ +/*ARGSUSED*/ +int +xfs_attr_shortform_list(xfs_attr_list_context_t *context) +{ + attrlist_cursor_kern_t *cursor; + xfs_attr_sf_sort_t *sbuf, *sbp; + xfs_attr_shortform_t *sf; + xfs_attr_sf_entry_t *sfe; + xfs_inode_t *dp; + int sbsize, nsbuf, count, i; + + ASSERT(context != NULL); + dp = context->dp; + ASSERT(dp != NULL); + ASSERT(dp->i_afp != NULL); + sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data; + ASSERT(sf != NULL); + if (INT_GET(sf->hdr.count, ARCH_CONVERT) == 0) + return(0); + cursor = context->cursor; + ASSERT(cursor != NULL); + + xfs_attr_trace_l_c("sf start", context); + + /* + * If the buffer is large enough, do not bother with sorting. + * Note the generous fudge factor of 16 overhead bytes per entry. + */ + if ((dp->i_afp->if_bytes + INT_GET(sf->hdr.count, ARCH_CONVERT) * 16) + < context->bufsize) { + for (i = 0, sfe = &sf->list[0]; + i < INT_GET(sf->hdr.count, ARCH_CONVERT); + i++) { + if (((context->flags & ATTR_ROOT) != 0) != + ((sfe->flags & XFS_ATTR_ROOT) != 0)) { + sfe = XFS_ATTR_SF_NEXTENTRY(sfe); + continue; + } + (void)xfs_attr_put_listent(context, + (char *)sfe->nameval, + (int)sfe->namelen, + (int)INT_GET(sfe->valuelen, + ARCH_CONVERT)); + sfe = XFS_ATTR_SF_NEXTENTRY(sfe); + } + xfs_attr_trace_l_c("sf big-gulp", context); + return(0); + } + + /* + * It didn't all fit, so we have to sort everything on hashval. + */ + sbsize = INT_GET(sf->hdr.count, ARCH_CONVERT) * sizeof(*sbuf); + sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP); + + /* + * Scan the attribute list for the rest of the entries, storing + * the relevant info from only those that match into a buffer. + */ + nsbuf = 0; + for (i = 0, sfe = &sf->list[0]; + i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { + if (((char *)sfe < (char *)sf) || + ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)) || + (sfe->namelen >= MAXNAMELEN)) { + xfs_attr_trace_l_c("sf corrupted", context); + kmem_free(sbuf, sbsize); + return XFS_ERROR(EFSCORRUPTED); + } + if (((context->flags & ATTR_ROOT) != 0) != + ((sfe->flags & XFS_ATTR_ROOT) != 0)) { + sfe = XFS_ATTR_SF_NEXTENTRY(sfe); + continue; + } + sbp->entno = i; + INT_SET(sbp->hash, ARCH_CONVERT, + xfs_da_hashname((char *)sfe->nameval, sfe->namelen)); + sbp->name = (char *)sfe->nameval; + sbp->namelen = sfe->namelen; + INT_SET(sbp->valuelen, ARCH_CONVERT, + INT_GET(sfe->valuelen, ARCH_CONVERT)); + sfe = XFS_ATTR_SF_NEXTENTRY(sfe); + sbp++; + nsbuf++; + } + + /* + * Sort the entries on hash then entno. + */ + qsort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare); + + /* + * Re-find our place IN THE SORTED LIST. + */ + count = 0; + cursor->initted = 1; + cursor->blkno = 0; + for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) { + if (INT_GET(sbp->hash, ARCH_CONVERT) == cursor->hashval) { + if (cursor->offset == count) { + break; + } + count++; + } else if (INT_GET(sbp->hash, ARCH_CONVERT) > cursor->hashval) { + break; + } + } + if (i == nsbuf) { + kmem_free(sbuf, sbsize); + xfs_attr_trace_l_c("blk end", context); + return(0); + } + + /* + * Loop putting entries into the user buffer. + */ + for ( ; i < nsbuf; i++, sbp++) { + if (cursor->hashval != INT_GET(sbp->hash, ARCH_CONVERT)) { + cursor->hashval = INT_GET(sbp->hash, ARCH_CONVERT); + cursor->offset = 0; + } + if (xfs_attr_put_listent(context, sbp->name, sbp->namelen, + INT_GET(sbp->valuelen, ARCH_CONVERT))) { + break; + } + cursor->offset++; + } + + kmem_free(sbuf, sbsize); + xfs_attr_trace_l_c("sf E-O-F", context); + return(0); +} + +/* + * Check a leaf attribute block to see if all the entries would fit into + * a shortform attribute list. + */ +int +xfs_attr_shortform_allfit(xfs_dabuf_t *bp, xfs_inode_t *dp) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_local_t *name_loc; + int bytes, i; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + + entry = &leaf->entries[0]; + bytes = sizeof(struct xfs_attr_sf_hdr); + for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { + if (entry->flags & XFS_ATTR_INCOMPLETE) + continue; /* don't copy partial entries */ + if (!(entry->flags & XFS_ATTR_LOCAL)) + return(0); + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); + bytes += sizeof(struct xfs_attr_sf_entry)-1 + + name_loc->namelen + + INT_GET(name_loc->valuelen, ARCH_CONVERT); + } + return( bytes < XFS_IFORK_ASIZE(dp) ); +} + +/* + * Convert a leaf attribute list to shortform attribute list + */ +int +xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_local_t *name_loc; + xfs_da_args_t nargs; + xfs_inode_t *dp; + char *tmpbuffer; + int error, i; + + dp = args->dp; + tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP); + ASSERT(tmpbuffer != NULL); + + ASSERT(bp != NULL); + bcopy(bp->data, tmpbuffer, XFS_LBSIZE(dp->i_mount)); + leaf = (xfs_attr_leafblock_t *)tmpbuffer; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + bzero(bp->data, XFS_LBSIZE(dp->i_mount)); + + /* + * Clean out the prior contents of the attribute list. + */ + error = xfs_da_shrink_inode(args, 0, bp); + if (error) + goto out; + error = xfs_attr_shortform_create(args); + if (error) + goto out; + + /* + * Copy the attributes + */ + bzero((char *)&nargs, sizeof(nargs)); + nargs.dp = dp; + nargs.firstblock = args->firstblock; + nargs.flist = args->flist; + nargs.total = args->total; + nargs.whichfork = XFS_ATTR_FORK; + nargs.trans = args->trans; + nargs.oknoent = 1; + entry = &leaf->entries[0]; + for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { + if (entry->flags & XFS_ATTR_INCOMPLETE) + continue; /* don't copy partial entries */ + if (INT_GET(entry->nameidx, ARCH_CONVERT) == 0) + continue; + ASSERT(entry->flags & XFS_ATTR_LOCAL); + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); + nargs.name = (char *)name_loc->nameval; + nargs.namelen = name_loc->namelen; + nargs.value = (char *)&name_loc->nameval[nargs.namelen]; + nargs.valuelen = INT_GET(name_loc->valuelen, ARCH_CONVERT); + nargs.hashval = INT_GET(entry->hashval, ARCH_CONVERT); + nargs.flags = (entry->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0; + xfs_attr_shortform_add(&nargs); + } + error = 0; + +out: + kmem_free(tmpbuffer, XFS_LBSIZE(dp->i_mount)); + return(error); +} + +/* + * Convert from using a single leaf to a root node and a leaf. + */ +int +xfs_attr_leaf_to_node(xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_da_intnode_t *node; + xfs_inode_t *dp; + xfs_dabuf_t *bp1, *bp2; + xfs_dablk_t blkno; + int error; + + dp = args->dp; + bp1 = bp2 = NULL; + error = xfs_da_grow_inode(args, &blkno); + if (error) + goto out; + error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp1, + XFS_ATTR_FORK); + if (error) + goto out; + ASSERT(bp1 != NULL); + bp2 = NULL; + error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp2, + XFS_ATTR_FORK); + if (error) + goto out; + ASSERT(bp2 != NULL); + bcopy(bp1->data, bp2->data, XFS_LBSIZE(dp->i_mount)); + xfs_da_buf_done(bp1); + bp1 = NULL; + xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1); + + /* + * Set up the new root node. + */ + error = xfs_da_node_create(args, 0, 1, &bp1, XFS_ATTR_FORK); + if (error) + goto out; + node = bp1->data; + leaf = bp2->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + INT_SET(node->btree[0].hashval, ARCH_CONVERT, + INT_GET(leaf->entries[INT_GET(leaf->hdr.count, + ARCH_CONVERT)-1 ].hashval, + ARCH_CONVERT)); + INT_SET(node->btree[0].before, ARCH_CONVERT, blkno); + INT_SET(node->hdr.count, ARCH_CONVERT, 1); + xfs_da_log_buf(args->trans, bp1, 0, XFS_LBSIZE(dp->i_mount) - 1); + error = 0; +out: + if (bp1) + xfs_da_buf_done(bp1); + if (bp2) + xfs_da_buf_done(bp2); + return(error); +} + + +/*======================================================================== + * Routines used for growing the Btree. + *========================================================================*/ + +/* + * Create the initial contents of a leaf attribute list + * or a leaf in a node attribute list. + */ +int +xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_hdr_t *hdr; + xfs_inode_t *dp; + xfs_dabuf_t *bp; + int error; + + dp = args->dp; + ASSERT(dp != NULL); + error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp, + XFS_ATTR_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + leaf = bp->data; + bzero((char *)leaf, XFS_LBSIZE(dp->i_mount)); + hdr = &leaf->hdr; + INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_ATTR_LEAF_MAGIC); + INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount)); + if (INT_GET(hdr->firstused, ARCH_CONVERT) == 0) { + INT_SET(hdr->firstused, ARCH_CONVERT, + XFS_LBSIZE(dp->i_mount) - XFS_ATTR_LEAF_NAME_ALIGN); + } + + INT_SET(hdr->freemap[0].base, ARCH_CONVERT, + sizeof(xfs_attr_leaf_hdr_t)); + INT_SET(hdr->freemap[0].size, ARCH_CONVERT, + INT_GET(hdr->firstused, ARCH_CONVERT) + - INT_GET(hdr->freemap[0].base, + ARCH_CONVERT)); + + xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1); + + *bpp = bp; + return(0); +} + +/* + * Split the leaf node, rebalance, then add the new entry. + */ +int +xfs_attr_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, + xfs_da_state_blk_t *newblk) +{ + xfs_dablk_t blkno; + int error; + + /* + * Allocate space for a new leaf node. + */ + ASSERT(oldblk->magic == XFS_ATTR_LEAF_MAGIC); + error = xfs_da_grow_inode(state->args, &blkno); + if (error) + return(error); + error = xfs_attr_leaf_create(state->args, blkno, &newblk->bp); + if (error) + return(error); + newblk->blkno = blkno; + newblk->magic = XFS_ATTR_LEAF_MAGIC; + + /* + * Rebalance the entries across the two leaves. + * NOTE: rebalance() currently depends on the 2nd block being empty. + */ + xfs_attr_leaf_rebalance(state, oldblk, newblk); + error = xfs_da_blk_link(state, oldblk, newblk); + if (error) + return(error); + + /* + * Save info on "old" attribute for "atomic rename" ops, leaf_add() + * modifies the index/blkno/rmtblk/rmtblkcnt fields to show the + * "new" attrs info. Will need the "old" info to remove it later. + * + * Insert the "new" entry in the correct block. + */ + if (state->inleaf) + error = xfs_attr_leaf_add(oldblk->bp, state->args); + else + error = xfs_attr_leaf_add(newblk->bp, state->args); + + /* + * Update last hashval in each block since we added the name. + */ + oldblk->hashval = xfs_attr_leaf_lasthash(oldblk->bp, NULL); + newblk->hashval = xfs_attr_leaf_lasthash(newblk->bp, NULL); + return(error); +} + +/* + * Add a name to the leaf attribute list structure. + */ +int +xfs_attr_leaf_add(xfs_dabuf_t *bp, xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_hdr_t *hdr; + xfs_attr_leaf_map_t *map; + int tablesize, entsize, sum, tmp, i; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT((args->index >= 0) + && (args->index <= INT_GET(leaf->hdr.count, ARCH_CONVERT))); + hdr = &leaf->hdr; + entsize = xfs_attr_leaf_newentsize(args, + args->trans->t_mountp->m_sb.sb_blocksize, NULL); + + /* + * Search through freemap for first-fit on new name length. + * (may need to figure in size of entry struct too) + */ + tablesize = (INT_GET(hdr->count, ARCH_CONVERT) + 1) + * sizeof(xfs_attr_leaf_entry_t) + + sizeof(xfs_attr_leaf_hdr_t); + map = &hdr->freemap[XFS_ATTR_LEAF_MAPSIZE-1]; + for (sum = 0, i = XFS_ATTR_LEAF_MAPSIZE-1; i >= 0; map--, i--) { + if (tablesize > INT_GET(hdr->firstused, ARCH_CONVERT)) { + sum += INT_GET(map->size, ARCH_CONVERT); + continue; + } + if (INT_GET(map->size, ARCH_CONVERT) == 0) + continue; /* no space in this map */ + tmp = entsize; + if (INT_GET(map->base, ARCH_CONVERT) + < INT_GET(hdr->firstused, ARCH_CONVERT)) + tmp += sizeof(xfs_attr_leaf_entry_t); + if (INT_GET(map->size, ARCH_CONVERT) >= tmp) { + tmp = xfs_attr_leaf_add_work(bp, args, i); + return(tmp); + } + sum += INT_GET(map->size, ARCH_CONVERT); + } + + /* + * If there are no holes in the address space of the block, + * and we don't have enough freespace, then compaction will do us + * no good and we should just give up. + */ + if (!hdr->holes && (sum < entsize)) + return(XFS_ERROR(ENOSPC)); + + /* + * Compact the entries to coalesce free space. + * This may change the hdr->count via dropping INCOMPLETE entries. + */ + xfs_attr_leaf_compact(args->trans, bp); + + /* + * After compaction, the block is guaranteed to have only one + * free region, in freemap[0]. If it is not big enough, give up. + */ + if (INT_GET(hdr->freemap[0].size, ARCH_CONVERT) + < (entsize + sizeof(xfs_attr_leaf_entry_t))) + return(XFS_ERROR(ENOSPC)); + + return(xfs_attr_leaf_add_work(bp, args, 0)); +} + +/* + * Add a name to a leaf attribute list structure. + */ +STATIC int +xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_hdr_t *hdr; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_local_t *name_loc; + xfs_attr_leaf_name_remote_t *name_rmt; + xfs_attr_leaf_map_t *map; + xfs_mount_t *mp; + int tmp, i; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + hdr = &leaf->hdr; + ASSERT((mapindex >= 0) && (mapindex < XFS_ATTR_LEAF_MAPSIZE)); + ASSERT((args->index >= 0) + && (args->index <= INT_GET(hdr->count, ARCH_CONVERT))); + + /* + * Force open some space in the entry array and fill it in. + */ + entry = &leaf->entries[args->index]; + if (args->index < INT_GET(hdr->count, ARCH_CONVERT)) { + tmp = INT_GET(hdr->count, ARCH_CONVERT) - args->index; + tmp *= sizeof(xfs_attr_leaf_entry_t); + ovbcopy((char *)entry, (char *)(entry+1), tmp); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry))); + } + INT_MOD(hdr->count, ARCH_CONVERT, 1); + + /* + * Allocate space for the new string (at the end of the run). + */ + map = &hdr->freemap[mapindex]; + mp = args->trans->t_mountp; + ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT((INT_GET(map->base, ARCH_CONVERT) & 0x3) == 0); + ASSERT(INT_GET(map->size, ARCH_CONVERT) + >= xfs_attr_leaf_newentsize(args, + mp->m_sb.sb_blocksize, NULL)); + ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT((INT_GET(map->size, ARCH_CONVERT) & 0x3) == 0); + INT_MOD(map->size, ARCH_CONVERT, + -xfs_attr_leaf_newentsize(args, mp->m_sb.sb_blocksize, &tmp)); + INT_SET(entry->nameidx, ARCH_CONVERT, + INT_GET(map->base, ARCH_CONVERT) + + INT_GET(map->size, ARCH_CONVERT)); + INT_SET(entry->hashval, ARCH_CONVERT, args->hashval); + entry->flags = tmp ? XFS_ATTR_LOCAL : 0; + entry->flags |= (args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0; + if (args->rename) { + entry->flags |= XFS_ATTR_INCOMPLETE; + if ((args->blkno2 == args->blkno) && + (args->index2 <= args->index)) { + args->index2++; + } + } + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); + ASSERT((args->index == 0) || (INT_GET(entry->hashval, ARCH_CONVERT) + >= INT_GET((entry-1)->hashval, + ARCH_CONVERT))); + ASSERT((args->index == INT_GET(hdr->count, ARCH_CONVERT)-1) || + (INT_GET(entry->hashval, ARCH_CONVERT) + <= (INT_GET((entry+1)->hashval, ARCH_CONVERT)))); + + /* + * Copy the attribute name and value into the new space. + * + * For "remote" attribute values, simply note that we need to + * allocate space for the "remote" value. We can't actually + * allocate the extents in this transaction, and we can't decide + * which blocks they should be as we might allocate more blocks + * as part of this transaction (a split operation for example). + */ + if (entry->flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index); + name_loc->namelen = args->namelen; + INT_SET(name_loc->valuelen, ARCH_CONVERT, args->valuelen); + bcopy(args->name, (char *)name_loc->nameval, args->namelen); + bcopy(args->value, (char *)&name_loc->nameval[args->namelen], + INT_GET(name_loc->valuelen, ARCH_CONVERT)); + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); + name_rmt->namelen = args->namelen; + bcopy(args->name, (char *)name_rmt->name, args->namelen); + entry->flags |= XFS_ATTR_INCOMPLETE; + /* just in case */ + INT_SET(name_rmt->valuelen, ARCH_CONVERT, 0); + INT_SET(name_rmt->valueblk, ARCH_CONVERT, 0); + args->rmtblkno = 1; + args->rmtblkcnt = XFS_B_TO_FSB(mp, args->valuelen); + } + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, XFS_ATTR_LEAF_NAME(leaf, args->index), + xfs_attr_leaf_entsize(leaf, args->index))); + + /* + * Update the control info for this leaf node + */ + if (INT_GET(entry->nameidx, ARCH_CONVERT) + < INT_GET(hdr->firstused, ARCH_CONVERT)) { + INT_SET(hdr->firstused, ARCH_CONVERT, + INT_GET(entry->nameidx, ARCH_CONVERT)); + } + ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) + >= ((INT_GET(hdr->count, ARCH_CONVERT) + * sizeof(*entry))+sizeof(*hdr))); + tmp = (INT_GET(hdr->count, ARCH_CONVERT)-1) + * sizeof(xfs_attr_leaf_entry_t) + + sizeof(xfs_attr_leaf_hdr_t); + map = &hdr->freemap[0]; + for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; map++, i++) { + if (INT_GET(map->base, ARCH_CONVERT) == tmp) { + INT_MOD(map->base, ARCH_CONVERT, + sizeof(xfs_attr_leaf_entry_t)); + INT_MOD(map->size, ARCH_CONVERT, + -sizeof(xfs_attr_leaf_entry_t)); + } + } + INT_MOD(hdr->usedbytes, ARCH_CONVERT, + xfs_attr_leaf_entsize(leaf, args->index)); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); + return(0); +} + +/* + * Garbage collect a leaf attribute list block by copying it to a new buffer. + */ +STATIC void +xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp) +{ + xfs_attr_leafblock_t *leaf_s, *leaf_d; + xfs_attr_leaf_hdr_t *hdr_s, *hdr_d; + xfs_mount_t *mp; + char *tmpbuffer; + + mp = trans->t_mountp; + tmpbuffer = kmem_alloc(XFS_LBSIZE(mp), KM_SLEEP); + ASSERT(tmpbuffer != NULL); + bcopy(bp->data, tmpbuffer, XFS_LBSIZE(mp)); + bzero(bp->data, XFS_LBSIZE(mp)); + + /* + * Copy basic information + */ + leaf_s = (xfs_attr_leafblock_t *)tmpbuffer; + leaf_d = bp->data; + hdr_s = &leaf_s->hdr; + hdr_d = &leaf_d->hdr; + hdr_d->info = hdr_s->info; /* struct copy */ + INT_SET(hdr_d->firstused, ARCH_CONVERT, XFS_LBSIZE(mp)); + /* handle truncation gracefully */ + if (INT_GET(hdr_d->firstused, ARCH_CONVERT) == 0) { + INT_SET(hdr_d->firstused, ARCH_CONVERT, + XFS_LBSIZE(mp) - XFS_ATTR_LEAF_NAME_ALIGN); + } + INT_SET(hdr_d->usedbytes, ARCH_CONVERT, 0); + INT_SET(hdr_d->count, ARCH_CONVERT, 0); + hdr_d->holes = 0; + INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, + sizeof(xfs_attr_leaf_hdr_t)); + INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, + INT_GET(hdr_d->firstused, ARCH_CONVERT) + - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); + + /* + * Copy all entry's in the same (sorted) order, + * but allocate name/value pairs packed and in sequence. + */ + xfs_attr_leaf_moveents(leaf_s, 0, leaf_d, 0, + (int)INT_GET(hdr_s->count, ARCH_CONVERT), mp); + + xfs_da_log_buf(trans, bp, 0, XFS_LBSIZE(mp) - 1); + + kmem_free(tmpbuffer, XFS_LBSIZE(mp)); +} + +/* + * Redistribute the attribute list entries between two leaf nodes, + * taking into account the size of the new entry. + * + * NOTE: if new block is empty, then it will get the upper half of the + * old block. At present, all (one) callers pass in an empty second block. + * + * This code adjusts the args->index/blkno and args->index2/blkno2 fields + * to match what it is doing in splitting the attribute leaf block. Those + * values are used in "atomic rename" operations on attributes. Note that + * the "new" and "old" values can end up in different blocks. + */ +STATIC void +xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2) +{ + xfs_da_args_t *args; + xfs_da_state_blk_t *tmp_blk; + xfs_attr_leafblock_t *leaf1, *leaf2; + xfs_attr_leaf_hdr_t *hdr1, *hdr2; + int count, totallen, max, space, swap; + + /* + * Set up environment. + */ + ASSERT(blk1->magic == XFS_ATTR_LEAF_MAGIC); + ASSERT(blk2->magic == XFS_ATTR_LEAF_MAGIC); + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + args = state->args; + + /* + * Check ordering of blocks, reverse if it makes things simpler. + * + * NOTE: Given that all (current) callers pass in an empty + * second block, this code should never set "swap". + */ + swap = 0; + if (xfs_attr_leaf_order(blk1->bp, blk2->bp)) { + tmp_blk = blk1; + blk1 = blk2; + blk2 = tmp_blk; + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + swap = 1; + } + hdr1 = &leaf1->hdr; + hdr2 = &leaf2->hdr; + + /* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. Then get + * the direction to copy and the number of elements to move. + * + * "inleaf" is true if the new entry should be inserted into blk1. + * If "swap" is also true, then reverse the sense of "inleaf". + */ + state->inleaf = xfs_attr_leaf_figure_balance(state, blk1, blk2, + &count, &totallen); + if (swap) + state->inleaf = !state->inleaf; + + /* + * Move any entries required from leaf to leaf: + */ + if (count < INT_GET(hdr1->count, ARCH_CONVERT)) { + /* + * Figure the total bytes to be added to the destination leaf. + */ + /* number entries being moved */ + count = INT_GET(hdr1->count, ARCH_CONVERT) - count; + space = INT_GET(hdr1->usedbytes, ARCH_CONVERT) - totallen; + space += count * sizeof(xfs_attr_leaf_entry_t); + + /* + * leaf2 is the destination, compact it if it looks tight. + */ + max = INT_GET(hdr2->firstused, ARCH_CONVERT) + - sizeof(xfs_attr_leaf_hdr_t); + max -= INT_GET(hdr2->count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t); + if (space > max) { + xfs_attr_leaf_compact(args->trans, blk2->bp); + } + + /* + * Move high entries from leaf1 to low end of leaf2. + */ + xfs_attr_leaf_moveents(leaf1, + INT_GET(hdr1->count, ARCH_CONVERT)-count, + leaf2, 0, count, state->mp); + + xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1); + xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1); + } else if (count > INT_GET(hdr1->count, ARCH_CONVERT)) { + /* + * I assert that since all callers pass in an empty + * second buffer, this code should never execute. + */ + + /* + * Figure the total bytes to be added to the destination leaf. + */ + /* number entries being moved */ + count -= INT_GET(hdr1->count, ARCH_CONVERT); + space = totallen - INT_GET(hdr1->usedbytes, ARCH_CONVERT); + space += count * sizeof(xfs_attr_leaf_entry_t); + + /* + * leaf1 is the destination, compact it if it looks tight. + */ + max = INT_GET(hdr1->firstused, ARCH_CONVERT) + - sizeof(xfs_attr_leaf_hdr_t); + max -= INT_GET(hdr1->count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t); + if (space > max) { + xfs_attr_leaf_compact(args->trans, blk1->bp); + } + + /* + * Move low entries from leaf2 to high end of leaf1. + */ + xfs_attr_leaf_moveents(leaf2, 0, leaf1, + (int)INT_GET(hdr1->count, ARCH_CONVERT), count, + state->mp); + + xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1); + xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1); + } + + /* + * Copy out last hashval in each block for B-tree code. + */ + blk1->hashval = + INT_GET(leaf1->entries[INT_GET(leaf1->hdr.count, + ARCH_CONVERT)-1].hashval, ARCH_CONVERT); + blk2->hashval = + INT_GET(leaf2->entries[INT_GET(leaf2->hdr.count, + ARCH_CONVERT)-1].hashval, ARCH_CONVERT); + + /* + * Adjust the expected index for insertion. + * NOTE: this code depends on the (current) situation that the + * second block was originally empty. + * + * If the insertion point moved to the 2nd block, we must adjust + * the index. We must also track the entry just following the + * new entry for use in an "atomic rename" operation, that entry + * is always the "old" entry and the "new" entry is what we are + * inserting. The index/blkno fields refer to the "old" entry, + * while the index2/blkno2 fields refer to the "new" entry. + */ + if (blk1->index > INT_GET(leaf1->hdr.count, ARCH_CONVERT)) { + ASSERT(state->inleaf == 0); + blk2->index = blk1->index + - INT_GET(leaf1->hdr.count, ARCH_CONVERT); + args->index = args->index2 = blk2->index; + args->blkno = args->blkno2 = blk2->blkno; + } else if (blk1->index == INT_GET(leaf1->hdr.count, ARCH_CONVERT)) { + if (state->inleaf) { + args->index = blk1->index; + args->blkno = blk1->blkno; + args->index2 = 0; + args->blkno2 = blk2->blkno; + } else { + blk2->index = blk1->index + - INT_GET(leaf1->hdr.count, ARCH_CONVERT); + args->index = args->index2 = blk2->index; + args->blkno = args->blkno2 = blk2->blkno; + } + } else { + ASSERT(state->inleaf == 1); + args->index = args->index2 = blk1->index; + args->blkno = args->blkno2 = blk1->blkno; + } +} + +/* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. + * GROT: Is this really necessary? With other than a 512 byte blocksize, + * GROT: there will always be enough room in either block for a new entry. + * GROT: Do a double-split for this case? + */ +STATIC int +xfs_attr_leaf_figure_balance(xfs_da_state_t *state, + xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2, + int *countarg, int *usedbytesarg) +{ + xfs_attr_leafblock_t *leaf1, *leaf2; + xfs_attr_leaf_hdr_t *hdr1, *hdr2; + xfs_attr_leaf_entry_t *entry; + int count, max, index, totallen, half; + int lastdelta, foundit, tmp; + + /* + * Set up environment. + */ + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + hdr1 = &leaf1->hdr; + hdr2 = &leaf2->hdr; + foundit = 0; + totallen = 0; + + /* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. + */ + max = INT_GET(hdr1->count, ARCH_CONVERT) + + INT_GET(hdr2->count, ARCH_CONVERT); + half = (max+1) * sizeof(*entry); + half += INT_GET(hdr1->usedbytes, ARCH_CONVERT) + + INT_GET(hdr2->usedbytes, ARCH_CONVERT) + + xfs_attr_leaf_newentsize(state->args, + state->blocksize, NULL); + half /= 2; + lastdelta = state->blocksize; + entry = &leaf1->entries[0]; + for (count = index = 0; count < max; entry++, index++, count++) { + +#define XFS_ATTR_ABS(A) (((A) < 0) ? -(A) : (A)) + /* + * The new entry is in the first block, account for it. + */ + if (count == blk1->index) { + tmp = totallen + sizeof(*entry) + + xfs_attr_leaf_newentsize(state->args, + state->blocksize, + NULL); + if (XFS_ATTR_ABS(half - tmp) > lastdelta) + break; + lastdelta = XFS_ATTR_ABS(half - tmp); + totallen = tmp; + foundit = 1; + } + + /* + * Wrap around into the second block if necessary. + */ + if (count == INT_GET(hdr1->count, ARCH_CONVERT)) { + leaf1 = leaf2; + entry = &leaf1->entries[0]; + index = 0; + } + + /* + * Figure out if next leaf entry would be too much. + */ + tmp = totallen + sizeof(*entry) + xfs_attr_leaf_entsize(leaf1, + index); + if (XFS_ATTR_ABS(half - tmp) > lastdelta) + break; + lastdelta = XFS_ATTR_ABS(half - tmp); + totallen = tmp; +#undef XFS_ATTR_ABS + } + + /* + * Calculate the number of usedbytes that will end up in lower block. + * If new entry not in lower block, fix up the count. + */ + totallen -= count * sizeof(*entry); + if (foundit) { + totallen -= sizeof(*entry) + + xfs_attr_leaf_newentsize(state->args, + state->blocksize, + NULL); + } + + *countarg = count; + *usedbytesarg = totallen; + return(foundit); +} + +/*======================================================================== + * Routines used for shrinking the Btree. + *========================================================================*/ + +/* + * Check a leaf block and its neighbors to see if the block should be + * collapsed into one or the other neighbor. Always keep the block + * with the smaller block number. + * If the current block is over 50% full, don't try to join it, return 0. + * If the block is empty, fill in the state structure and return 2. + * If it can be collapsed, fill in the state structure and return 1. + * If nothing can be done, return 0. + * + * GROT: allow for INCOMPLETE entries in calculation. + */ +int +xfs_attr_leaf_toosmall(xfs_da_state_t *state, int *action) +{ + xfs_attr_leafblock_t *leaf; + xfs_da_state_blk_t *blk; + xfs_da_blkinfo_t *info; + int count, bytes, forward, error, retval, i; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + + /* + * Check for the degenerate case of the block being over 50% full. + * If so, it's not worth even looking to see if we might be able + * to coalesce with a sibling. + */ + blk = &state->path.blk[ state->path.active-1 ]; + info = blk->bp->data; + ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); + leaf = (xfs_attr_leafblock_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes = sizeof(xfs_attr_leaf_hdr_t) + + count * sizeof(xfs_attr_leaf_entry_t) + + INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); + if (bytes > (state->blocksize >> 1)) { + *action = 0; /* blk over 50%, dont try to join */ + return(0); + } + + /* + * Check for the degenerate case of the block being empty. + * If the block is empty, we'll simply delete it, no need to + * coalesce it with a sibling block. We choose (aribtrarily) + * to merge with the forward block unless it is NULL. + */ + if (count == 0) { + /* + * Make altpath point to the block we want to keep and + * path point to the block we want to drop (this one). + */ + forward = (INT_GET(info->forw, ARCH_CONVERT) != 0); + bcopy(&state->path, &state->altpath, sizeof(state->path)); + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + if (error) + return(error); + if (retval) { + *action = 0; + } else { + *action = 2; + } + return(0); + } + + /* + * Examine each sibling block to see if we can coalesce with + * at least 25% free space to spare. We need to figure out + * whether to merge with the forward or the backward block. + * We prefer coalescing with the lower numbered sibling so as + * to shrink an attribute list over time. + */ + /* start with smaller blk num */ + forward = (INT_GET(info->forw, ARCH_CONVERT) + < INT_GET(info->back, ARCH_CONVERT)); + for (i = 0; i < 2; forward = !forward, i++) { + if (forward) + blkno = INT_GET(info->forw, ARCH_CONVERT); + else + blkno = INT_GET(info->back, ARCH_CONVERT); + if (blkno == 0) + continue; + error = xfs_da_read_buf(state->args->trans, state->args->dp, + blkno, -1, &bp, XFS_ATTR_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + + leaf = (xfs_attr_leafblock_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes = state->blocksize - (state->blocksize>>2); + bytes -= INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + count += INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes -= INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); + bytes -= count * sizeof(xfs_attr_leaf_entry_t); + bytes -= sizeof(xfs_attr_leaf_hdr_t); + xfs_da_brelse(state->args->trans, bp); + if (bytes >= 0) + break; /* fits with at least 25% to spare */ + } + if (i >= 2) { + *action = 0; + return(0); + } + + /* + * Make altpath point to the block we want to keep (the lower + * numbered block) and path point to the block we want to drop. + */ + bcopy(&state->path, &state->altpath, sizeof(state->path)); + if (blkno < blk->blkno) { + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + } else { + error = xfs_da_path_shift(state, &state->path, forward, + 0, &retval); + } + if (error) + return(error); + if (retval) { + *action = 0; + } else { + *action = 1; + } + return(0); +} + +/* + * Remove a name from the leaf attribute list structure. + * + * Return 1 if leaf is less than 37% full, 0 if >= 37% full. + * If two leaves are 37% full, when combined they will leave 25% free. + */ +int +xfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_hdr_t *hdr; + xfs_attr_leaf_map_t *map; + xfs_attr_leaf_entry_t *entry; + int before, after, smallest, entsize; + int tablesize, tmp, i; + xfs_mount_t *mp; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + hdr = &leaf->hdr; + mp = args->trans->t_mountp; + ASSERT((INT_GET(hdr->count, ARCH_CONVERT) > 0) + && (INT_GET(hdr->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8))); + ASSERT((args->index >= 0) + && (args->index < INT_GET(hdr->count, ARCH_CONVERT))); + ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) + >= ((INT_GET(hdr->count, ARCH_CONVERT) + * sizeof(*entry))+sizeof(*hdr))); + entry = &leaf->entries[args->index]; + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) + >= INT_GET(hdr->firstused, ARCH_CONVERT)); + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp)); + + /* + * Scan through free region table: + * check for adjacency of free'd entry with an existing one, + * find smallest free region in case we need to replace it, + * adjust any map that borders the entry table, + */ + tablesize = INT_GET(hdr->count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t) + + sizeof(xfs_attr_leaf_hdr_t); + map = &hdr->freemap[0]; + tmp = INT_GET(map->size, ARCH_CONVERT); + before = after = -1; + smallest = XFS_ATTR_LEAF_MAPSIZE - 1; + entsize = xfs_attr_leaf_entsize(leaf, args->index); + for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; map++, i++) { + ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); + if (INT_GET(map->base, ARCH_CONVERT) == tablesize) { + INT_MOD(map->base, ARCH_CONVERT, + -sizeof(xfs_attr_leaf_entry_t)); + INT_MOD(map->size, ARCH_CONVERT, + sizeof(xfs_attr_leaf_entry_t)); + } + + if ((INT_GET(map->base, ARCH_CONVERT) + + INT_GET(map->size, ARCH_CONVERT)) + == INT_GET(entry->nameidx, ARCH_CONVERT)) { + before = i; + } else if (INT_GET(map->base, ARCH_CONVERT) + == (INT_GET(entry->nameidx, ARCH_CONVERT) + entsize)) { + after = i; + } else if (INT_GET(map->size, ARCH_CONVERT) < tmp) { + tmp = INT_GET(map->size, ARCH_CONVERT); + smallest = i; + } + } + + /* + * Coalesce adjacent freemap regions, + * or replace the smallest region. + */ + if ((before >= 0) || (after >= 0)) { + if ((before >= 0) && (after >= 0)) { + map = &hdr->freemap[before]; + INT_MOD(map->size, ARCH_CONVERT, entsize); + INT_MOD(map->size, ARCH_CONVERT, + INT_GET(hdr->freemap[after].size, + ARCH_CONVERT)); + INT_SET(hdr->freemap[after].base, ARCH_CONVERT, 0); + INT_SET(hdr->freemap[after].size, ARCH_CONVERT, 0); + } else if (before >= 0) { + map = &hdr->freemap[before]; + INT_MOD(map->size, ARCH_CONVERT, entsize); + } else { + map = &hdr->freemap[after]; + INT_SET(map->base, ARCH_CONVERT, + INT_GET(entry->nameidx, ARCH_CONVERT)); + INT_MOD(map->size, ARCH_CONVERT, entsize); + } + } else { + /* + * Replace smallest region (if it is smaller than free'd entry) + */ + map = &hdr->freemap[smallest]; + if (INT_GET(map->size, ARCH_CONVERT) < entsize) { + INT_SET(map->base, ARCH_CONVERT, + INT_GET(entry->nameidx, ARCH_CONVERT)); + INT_SET(map->size, ARCH_CONVERT, entsize); + } + } + + /* + * Did we remove the first entry? + */ + if (INT_GET(entry->nameidx, ARCH_CONVERT) + == INT_GET(hdr->firstused, ARCH_CONVERT)) + smallest = 1; + else + smallest = 0; + + /* + * Compress the remaining entries and zero out the removed stuff. + */ + bzero(XFS_ATTR_LEAF_NAME(leaf, args->index), entsize); + INT_MOD(hdr->usedbytes, ARCH_CONVERT, -entsize); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, XFS_ATTR_LEAF_NAME(leaf, args->index), + entsize)); + + tmp = (INT_GET(hdr->count, ARCH_CONVERT) - args->index) + * sizeof(xfs_attr_leaf_entry_t); + ovbcopy((char *)(entry+1), (char *)entry, tmp); + INT_MOD(hdr->count, ARCH_CONVERT, -1); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry))); + entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)]; + bzero((char *)entry, sizeof(xfs_attr_leaf_entry_t)); + + /* + * If we removed the first entry, re-find the first used byte + * in the name area. Note that if the entry was the "firstused", + * then we don't have a "hole" in our block resulting from + * removing the name. + */ + if (smallest) { + tmp = XFS_LBSIZE(mp); + entry = &leaf->entries[0]; + for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; + i >= 0; entry++, i--) { + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) + >= INT_GET(hdr->firstused, ARCH_CONVERT)); + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) + < XFS_LBSIZE(mp)); + if (INT_GET(entry->nameidx, ARCH_CONVERT) < tmp) + tmp = INT_GET(entry->nameidx, ARCH_CONVERT); + } + INT_SET(hdr->firstused, ARCH_CONVERT, tmp); + if (INT_GET(hdr->firstused, ARCH_CONVERT) == 0) { + INT_SET(hdr->firstused, ARCH_CONVERT, + tmp - XFS_ATTR_LEAF_NAME_ALIGN); + } + } else { + hdr->holes = 1; /* mark as needing compaction */ + } + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); + + /* + * Check if leaf is less than 50% full, caller may want to + * "join" the leaf with a sibling if so. + */ + tmp = sizeof(xfs_attr_leaf_hdr_t); + tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t); + tmp += INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT); + return(tmp < mp->m_attr_magicpct); /* leaf is < 37% full */ +} + +/* + * Move all the attribute list entries from drop_leaf into save_leaf. + */ +void +xfs_attr_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk) +{ + xfs_attr_leafblock_t *drop_leaf, *save_leaf, *tmp_leaf; + xfs_attr_leaf_hdr_t *drop_hdr, *save_hdr, *tmp_hdr; + xfs_mount_t *mp; + char *tmpbuffer; + + /* + * Set up environment. + */ + mp = state->mp; + ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC); + ASSERT(save_blk->magic == XFS_ATTR_LEAF_MAGIC); + drop_leaf = drop_blk->bp->data; + save_leaf = save_blk->bp->data; + ASSERT(INT_GET(drop_leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(INT_GET(save_leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + drop_hdr = &drop_leaf->hdr; + save_hdr = &save_leaf->hdr; + + /* + * Save last hashval from dying block for later Btree fixup. + */ + drop_blk->hashval = + INT_GET(drop_leaf->entries[INT_GET(drop_leaf->hdr.count, + ARCH_CONVERT)-1].hashval, + ARCH_CONVERT); + + /* + * Check if we need a temp buffer, or can we do it in place. + * Note that we don't check "leaf" for holes because we will + * always be dropping it, toosmall() decided that for us already. + */ + if (save_hdr->holes == 0) { + /* + * dest leaf has no holes, so we add there. May need + * to make some room in the entry array. + */ + if (xfs_attr_leaf_order(save_blk->bp, drop_blk->bp)) { + xfs_attr_leaf_moveents(drop_leaf, 0, save_leaf, 0, + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); + } else { + xfs_attr_leaf_moveents(drop_leaf, 0, save_leaf, + INT_GET(save_hdr->count, ARCH_CONVERT), + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), + mp); + } + } else { + /* + * Destination has holes, so we make a temporary copy + * of the leaf and add them both to that. + */ + tmpbuffer = kmem_alloc(state->blocksize, KM_SLEEP); + ASSERT(tmpbuffer != NULL); + bzero(tmpbuffer, state->blocksize); + tmp_leaf = (xfs_attr_leafblock_t *)tmpbuffer; + tmp_hdr = &tmp_leaf->hdr; + tmp_hdr->info = save_hdr->info; /* struct copy */ + INT_SET(tmp_hdr->count, ARCH_CONVERT, 0); + INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize); + if (INT_GET(tmp_hdr->firstused, ARCH_CONVERT) == 0) { + INT_SET(tmp_hdr->firstused, ARCH_CONVERT, + state->blocksize - XFS_ATTR_LEAF_NAME_ALIGN); + } + INT_SET(tmp_hdr->usedbytes, ARCH_CONVERT, 0); + if (xfs_attr_leaf_order(save_blk->bp, drop_blk->bp)) { + xfs_attr_leaf_moveents(drop_leaf, 0, tmp_leaf, 0, + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), + mp); + xfs_attr_leaf_moveents(save_leaf, 0, tmp_leaf, + INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), + (int)INT_GET(save_hdr->count, ARCH_CONVERT), + mp); + } else { + xfs_attr_leaf_moveents(save_leaf, 0, tmp_leaf, 0, + (int)INT_GET(save_hdr->count, ARCH_CONVERT), + mp); + xfs_attr_leaf_moveents(drop_leaf, 0, tmp_leaf, + INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), + mp); + } + bcopy((char *)tmp_leaf, (char *)save_leaf, state->blocksize); + kmem_free(tmpbuffer, state->blocksize); + } + + xfs_da_log_buf(state->args->trans, save_blk->bp, 0, + state->blocksize - 1); + + /* + * Copy out last hashval in each block for B-tree code. + */ + save_blk->hashval = + INT_GET(save_leaf->entries[INT_GET(save_leaf->hdr.count, + ARCH_CONVERT)-1].hashval, + ARCH_CONVERT); +} + +/*======================================================================== + * Routines used for finding things in the Btree. + *========================================================================*/ + +/* + * Look up a name in a leaf attribute list structure. + * This is the internal routine, it uses the caller's buffer. + * + * Note that duplicate keys are allowed, but only check within the + * current leaf node. The Btree code must check in adjacent leaf nodes. + * + * Return in args->index the index into the entry[] array of either + * the found entry, or where the entry should have been (insert before + * that entry). + * + * Don't change the args->value unless we find the attribute. + */ +int +xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_local_t *name_loc; + xfs_attr_leaf_name_remote_t *name_rmt; + int probe, span; + xfs_dahash_t hashval; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) + < (XFS_LBSIZE(args->dp->i_mount)/8)); + + /* + * Binary search. (note: small blocks will skip this loop) + */ + hashval = args->hashval; + probe = span = INT_GET(leaf->hdr.count, ARCH_CONVERT) / 2; + for (entry = &leaf->entries[probe]; span > 4; + entry = &leaf->entries[probe]) { + span /= 2; + if (INT_GET(entry->hashval, ARCH_CONVERT) < hashval) + probe += span; + else if (INT_GET(entry->hashval, ARCH_CONVERT) > hashval) + probe -= span; + else + break; + } + ASSERT((probe >= 0) && \ + ((INT_GET(leaf->hdr.count, ARCH_CONVERT) == 0) + || (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)))); + ASSERT((span <= 4) || (INT_GET(entry->hashval, ARCH_CONVERT) + == hashval)); + + /* + * Since we may have duplicate hashval's, find the first matching + * hashval in the leaf. + */ + while ((probe > 0) && (INT_GET(entry->hashval, ARCH_CONVERT) + >= hashval)) { + entry--; + probe--; + } + while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) + && (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)) { + entry++; + probe++; + } + if ((probe == INT_GET(leaf->hdr.count, ARCH_CONVERT)) + || (INT_GET(entry->hashval, ARCH_CONVERT) != hashval)) { + args->index = probe; + return(XFS_ERROR(ENOATTR)); + } + + /* + * Duplicate keys may be present, so search all of them for a match. + */ + for ( ; (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) + && (INT_GET(entry->hashval, ARCH_CONVERT) == hashval); + entry++, probe++) { +/* + * GROT: Add code to remove incomplete entries. + */ + /* + * If we are looking for INCOMPLETE entries, show only those. + * If we are looking for complete entries, show only those. + */ + if ((args->flags & XFS_ATTR_INCOMPLETE) != + (entry->flags & XFS_ATTR_INCOMPLETE)) { + continue; + } + if (entry->flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, probe); + if (name_loc->namelen != args->namelen) + continue; + if (bcmp(args->name, (char *)name_loc->nameval, + args->namelen) != 0) + continue; + if (((args->flags & ATTR_ROOT) != 0) != + ((entry->flags & XFS_ATTR_ROOT) != 0)) + continue; + args->index = probe; + return(XFS_ERROR(EEXIST)); + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, probe); + if (name_rmt->namelen != args->namelen) + continue; + if (bcmp(args->name, (char *)name_rmt->name, + args->namelen) != 0) + continue; + if (((args->flags & ATTR_ROOT) != 0) != + ((entry->flags & XFS_ATTR_ROOT) != 0)) + continue; + args->index = probe; + args->rmtblkno + = INT_GET(name_rmt->valueblk, ARCH_CONVERT); + args->rmtblkcnt = XFS_B_TO_FSB(args->dp->i_mount, + INT_GET(name_rmt->valuelen, + ARCH_CONVERT)); + return(XFS_ERROR(EEXIST)); + } + } + args->index = probe; + return(XFS_ERROR(ENOATTR)); +} + +/* + * Get the value associated with an attribute name from a leaf attribute + * list structure. + */ +int +xfs_attr_leaf_getvalue(xfs_dabuf_t *bp, xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_local_t *name_loc; + xfs_attr_leaf_name_remote_t *name_rmt; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) + < (XFS_LBSIZE(args->dp->i_mount)/8)); + ASSERT(args->index < ((int)INT_GET(leaf->hdr.count, ARCH_CONVERT))); + + entry = &leaf->entries[args->index]; + if (entry->flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index); + ASSERT(name_loc->namelen == args->namelen); + ASSERT(bcmp(args->name, name_loc->nameval, args->namelen) == 0); + if (args->valuelen + < INT_GET(name_loc->valuelen, ARCH_CONVERT)) { + args->valuelen + = INT_GET(name_loc->valuelen, ARCH_CONVERT); + return(XFS_ERROR(E2BIG)); + } + args->valuelen = INT_GET(name_loc->valuelen, ARCH_CONVERT); + bcopy(&name_loc->nameval[args->namelen], args->value, + args->valuelen); + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); + ASSERT(name_rmt->namelen == args->namelen); + ASSERT(bcmp(args->name, name_rmt->name, args->namelen) == 0); + args->rmtblkno = INT_GET(name_rmt->valueblk, ARCH_CONVERT); + args->rmtblkcnt = XFS_B_TO_FSB(args->dp->i_mount, + INT_GET(name_rmt->valuelen, + ARCH_CONVERT)); + if (args->valuelen < INT_GET(name_rmt->valuelen, + ARCH_CONVERT)) { + args->valuelen + = INT_GET(name_rmt->valuelen, ARCH_CONVERT); + return(XFS_ERROR(E2BIG)); + } + args->valuelen = INT_GET(name_rmt->valuelen, ARCH_CONVERT); + } + return(0); +} + +/*======================================================================== + * Utility routines. + *========================================================================*/ + +/* + * Move the indicated entries from one leaf to another. + * NOTE: this routine modifies both source and destination leaves. + */ +/*ARGSUSED*/ +STATIC void +xfs_attr_leaf_moveents(xfs_attr_leafblock_t *leaf_s, int start_s, + xfs_attr_leafblock_t *leaf_d, int start_d, + int count, xfs_mount_t *mp) +{ + xfs_attr_leaf_hdr_t *hdr_s, *hdr_d; + xfs_attr_leaf_entry_t *entry_s, *entry_d; + int desti, tmp, i; + + /* + * Check for nothing to do. + */ + if (count == 0) + return; + + /* + * Set up environment. + */ + ASSERT(INT_GET(leaf_s->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(INT_GET(leaf_d->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + hdr_s = &leaf_s->hdr; + hdr_d = &leaf_d->hdr; + ASSERT((INT_GET(hdr_s->count, ARCH_CONVERT) > 0) + && (INT_GET(hdr_s->count, ARCH_CONVERT) + < (XFS_LBSIZE(mp)/8))); + ASSERT(INT_GET(hdr_s->firstused, ARCH_CONVERT) >= + ((INT_GET(hdr_s->count, ARCH_CONVERT) + * sizeof(*entry_s))+sizeof(*hdr_s))); + ASSERT(INT_GET(hdr_d->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8)); + ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= + ((INT_GET(hdr_d->count, ARCH_CONVERT) + * sizeof(*entry_d))+sizeof(*hdr_d))); + + ASSERT(start_s < INT_GET(hdr_s->count, ARCH_CONVERT)); + ASSERT(start_d <= INT_GET(hdr_d->count, ARCH_CONVERT)); + ASSERT(count <= INT_GET(hdr_s->count, ARCH_CONVERT)); + + /* + * Move the entries in the destination leaf up to make a hole? + */ + if (start_d < INT_GET(hdr_d->count, ARCH_CONVERT)) { + tmp = INT_GET(hdr_d->count, ARCH_CONVERT) - start_d; + tmp *= sizeof(xfs_attr_leaf_entry_t); + entry_s = &leaf_d->entries[start_d]; + entry_d = &leaf_d->entries[start_d + count]; + ovbcopy((char *)entry_s, (char *)entry_d, tmp); + } + + /* + * Copy all entry's in the same (sorted) order, + * but allocate attribute info packed and in sequence. + */ + entry_s = &leaf_s->entries[start_s]; + entry_d = &leaf_d->entries[start_d]; + desti = start_d; + for (i = 0; i < count; entry_s++, entry_d++, desti++, i++) { + ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + >= INT_GET(hdr_s->firstused, ARCH_CONVERT)); + tmp = xfs_attr_leaf_entsize(leaf_s, start_s + i); +#ifdef GROT + /* + * Code to drop INCOMPLETE entries. Difficult to use as we + * may also need to change the insertion index. Code turned + * off for 6.2, should be revisited later. + */ + if (entry_s->flags & XFS_ATTR_INCOMPLETE) { /* skip partials? */ + bzero(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), tmp); + INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp); + INT_MOD(hdr_s->count, ARCH_CONVERT, -1); + entry_d--; /* to compensate for ++ in loop hdr */ + desti--; + if ((start_s + i) < offset) + result++; /* insertion index adjustment */ + } else { +#endif /* GROT */ + INT_MOD(hdr_d->firstused, ARCH_CONVERT, -tmp); + INT_SET(entry_d->hashval, ARCH_CONVERT, + INT_GET(entry_s->hashval, ARCH_CONVERT)); + INT_SET(entry_d->nameidx, ARCH_CONVERT, + INT_GET(hdr_d->firstused, + ARCH_CONVERT)); + entry_d->flags = entry_s->flags; + ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp + <= XFS_LBSIZE(mp)); + ovbcopy(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), + XFS_ATTR_LEAF_NAME(leaf_d, desti), tmp); + ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp + <= XFS_LBSIZE(mp)); + bzero(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), tmp); + INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp); + INT_MOD(hdr_d->usedbytes, ARCH_CONVERT, tmp); + INT_MOD(hdr_s->count, ARCH_CONVERT, -1); + INT_MOD(hdr_d->count, ARCH_CONVERT, 1); + tmp = INT_GET(hdr_d->count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t) + + sizeof(xfs_attr_leaf_hdr_t); + ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= tmp); +#ifdef GROT + } +#endif /* GROT */ + } + + /* + * Zero out the entries we just copied. + */ + if (start_s == INT_GET(hdr_s->count, ARCH_CONVERT)) { + tmp = count * sizeof(xfs_attr_leaf_entry_t); + entry_s = &leaf_s->entries[start_s]; + ASSERT(((char *)entry_s + tmp) <= + ((char *)leaf_s + XFS_LBSIZE(mp))); + bzero((char *)entry_s, tmp); + } else { + /* + * Move the remaining entries down to fill the hole, + * then zero the entries at the top. + */ + tmp = INT_GET(hdr_s->count, ARCH_CONVERT) - count; + tmp *= sizeof(xfs_attr_leaf_entry_t); + entry_s = &leaf_s->entries[start_s + count]; + entry_d = &leaf_s->entries[start_s]; + ovbcopy((char *)entry_s, (char *)entry_d, tmp); + + tmp = count * sizeof(xfs_attr_leaf_entry_t); + entry_s = &leaf_s->entries[INT_GET(hdr_s->count, + ARCH_CONVERT)]; + ASSERT(((char *)entry_s + tmp) <= + ((char *)leaf_s + XFS_LBSIZE(mp))); + bzero((char *)entry_s, tmp); + } + + /* + * Fill in the freemap information + */ + INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, + sizeof(xfs_attr_leaf_hdr_t)); + INT_MOD(hdr_d->freemap[0].base, ARCH_CONVERT, + INT_GET(hdr_d->count, ARCH_CONVERT) + * sizeof(xfs_attr_leaf_entry_t)); + INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, + INT_GET(hdr_d->firstused, ARCH_CONVERT) + - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); + INT_SET(hdr_d->freemap[1].base, ARCH_CONVERT, 0); + INT_SET(hdr_d->freemap[2].base, ARCH_CONVERT, 0); + INT_SET(hdr_d->freemap[1].size, ARCH_CONVERT, 0); + INT_SET(hdr_d->freemap[2].size, ARCH_CONVERT, 0); + hdr_s->holes = 1; /* leaf may not be compact */ +} + +/* + * Compare two leaf blocks "order". + * Return 0 unless leaf2 should go before leaf1. + */ +int +xfs_attr_leaf_order(xfs_dabuf_t *leaf1_bp, xfs_dabuf_t *leaf2_bp) +{ + xfs_attr_leafblock_t *leaf1, *leaf2; + + leaf1 = leaf1_bp->data; + leaf2 = leaf2_bp->data; + ASSERT((INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC) && + (INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC)); + if ( (INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0) + && (INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0) + && ( (INT_GET(leaf2->entries[ 0 ].hashval, ARCH_CONVERT) < + INT_GET(leaf1->entries[ 0 ].hashval, ARCH_CONVERT)) + || (INT_GET(leaf2->entries[INT_GET(leaf2->hdr.count, + ARCH_CONVERT)-1].hashval, ARCH_CONVERT) < + INT_GET(leaf1->entries[INT_GET(leaf1->hdr.count, + ARCH_CONVERT)-1].hashval, ARCH_CONVERT))) ) { + return(1); + } + return(0); +} + +/* + * Pick up the last hashvalue from a leaf block. + */ +xfs_dahash_t +xfs_attr_leaf_lasthash(xfs_dabuf_t *bp, int *count) +{ + xfs_attr_leafblock_t *leaf; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + if (count) + *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + if (INT_GET(leaf->hdr.count, ARCH_CONVERT) == 0) + return(0); + return(INT_GET(leaf->entries[INT_GET(leaf->hdr.count, + ARCH_CONVERT)-1].hashval, ARCH_CONVERT)); +} + +/* + * Calculate the number of bytes used to store the indicated attribute + * (whether local or remote only calculate bytes in this block). + */ +int +xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index) +{ + xfs_attr_leaf_name_local_t *name_loc; + xfs_attr_leaf_name_remote_t *name_rmt; + int size; + + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + if (leaf->entries[index].flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, index); + size = XFS_ATTR_LEAF_ENTSIZE_LOCAL(name_loc->namelen, + INT_GET(name_loc->valuelen, + ARCH_CONVERT)); + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, index); + size = XFS_ATTR_LEAF_ENTSIZE_REMOTE(name_rmt->namelen); + } + return(size); +} + +/* + * Calculate the number of bytes that would be required to store the new + * attribute (whether local or remote only calculate bytes in this block). + * This routine decides as a side effect whether the attribute will be + * a "local" or a "remote" attribute. + */ +int +xfs_attr_leaf_newentsize(xfs_da_args_t *args, int blocksize, int *local) +{ + int size; + + size = XFS_ATTR_LEAF_ENTSIZE_LOCAL(args->namelen, args->valuelen); + if (size < XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX(blocksize)) { + if (local) { + *local = 1; + } + } else { + size = XFS_ATTR_LEAF_ENTSIZE_REMOTE(args->namelen); + if (local) { + *local = 0; + } + } + return(size); +} + +/* + * Copy out attribute list entries for attr_list(), for leaf attribute lists. + */ +int +xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context) +{ + attrlist_cursor_kern_t *cursor; + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_local_t *name_loc; + xfs_attr_leaf_name_remote_t *name_rmt; + int retval, i; + + ASSERT(bp != NULL); + leaf = bp->data; + cursor = context->cursor; + cursor->initted = 1; + + xfs_attr_trace_l_cl("blk start", context, leaf); + + /* + * Re-find our place in the leaf block if this is a new syscall. + */ + if (context->resynch) { + entry = &leaf->entries[0]; + for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); + entry++, i++) { + if (INT_GET(entry->hashval, ARCH_CONVERT) + == cursor->hashval) { + if (cursor->offset == context->dupcnt) { + context->dupcnt = 0; + break; + } + context->dupcnt++; + } else if (INT_GET(entry->hashval, ARCH_CONVERT) + > cursor->hashval) { + context->dupcnt = 0; + break; + } + } + if (i == INT_GET(leaf->hdr.count, ARCH_CONVERT)) { + xfs_attr_trace_l_c("not found", context); + return(0); + } + } else { + entry = &leaf->entries[0]; + i = 0; + } + context->resynch = 0; + + /* + * We have found our place, start copying out the new attributes. + */ + retval = 0; + for ( ; (i < INT_GET(leaf->hdr.count, ARCH_CONVERT)) + && (retval == 0); entry++, i++) { + if (INT_GET(entry->hashval, ARCH_CONVERT) != cursor->hashval) { + cursor->hashval = INT_GET(entry->hashval, + ARCH_CONVERT); + cursor->offset = 0; + } + + if (entry->flags & XFS_ATTR_INCOMPLETE) + continue; /* skip incomplete entries */ + if (((context->flags & ATTR_ROOT) != 0) != + ((entry->flags & XFS_ATTR_ROOT) != 0)) + continue; /* skip non-matching entries */ + + if (entry->flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); + retval = xfs_attr_put_listent(context, + (char *)name_loc->nameval, + (int)name_loc->namelen, + (int)INT_GET(name_loc->valuelen, + ARCH_CONVERT)); + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i); + retval = xfs_attr_put_listent(context, + (char *)name_rmt->name, + (int)name_rmt->namelen, + (int)INT_GET(name_rmt->valuelen, + ARCH_CONVERT)); + } + if (retval == 0) { + cursor->offset++; + } + } + xfs_attr_trace_l_cl("blk end", context, leaf); + return(retval); +} + +#define ATTR_ENTBASESIZE /* minimum bytes used by an attr */ \ + (((struct attrlist_ent *) 0)->a_name - (char *) 0) +#define ATTR_ENTSIZE(namelen) /* actual bytes used by an attr */ \ + ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \ + & ~(sizeof(u_int32_t)-1)) + +/* + * Format an attribute and copy it out to the user's buffer. + * Take care to check values and protect against them changing later, + * we may be reading them directly out of a user buffer. + */ +/*ARGSUSED*/ +int +xfs_attr_put_listent(xfs_attr_list_context_t *context, + char *name, int namelen, int valuelen) +{ + attrlist_ent_t *aep; + int arraytop; + + ASSERT(context->count >= 0); + ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); + ASSERT(context->firstu >= sizeof(*context->alist)); + ASSERT(context->firstu <= context->bufsize); + + arraytop = sizeof(*context->alist) + + context->count * sizeof(context->alist->al_offset[0]); + context->firstu -= ATTR_ENTSIZE(namelen); + if (context->firstu < arraytop) { + xfs_attr_trace_l_c("buffer full", context); + context->alist->al_more = 1; + return(1); + } + + aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]); + aep->a_valuelen = valuelen; + bcopy(name, aep->a_name, namelen); + aep->a_name[ namelen ] = 0; + context->alist->al_offset[ context->count++ ] = context->firstu; + context->alist->al_count = context->count; + xfs_attr_trace_l_c("add", context); + return(0); +} + +/*======================================================================== + * Manage the INCOMPLETE flag in a leaf entry + *========================================================================*/ + +/* + * Clear the INCOMPLETE flag on an entry in a leaf block. + */ +int +xfs_attr_leaf_clearflag(xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_remote_t *name_rmt; + xfs_dabuf_t *bp; + int error; +#ifdef DEBUG + xfs_attr_leaf_name_local_t *name_loc; + int namelen; + char *name; +#endif /* DEBUG */ + + /* + * Set up the operation. + */ + error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, + XFS_ATTR_FORK); + if (error) { + return(error); + } + ASSERT(bp != NULL); + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(args->index < INT_GET(leaf->hdr.count, ARCH_CONVERT)); + ASSERT(args->index >= 0); + entry = &leaf->entries[ args->index ]; + ASSERT(entry->flags & XFS_ATTR_INCOMPLETE); + +#ifdef DEBUG + if (entry->flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index); + namelen = name_loc->namelen; + name = (char *)name_loc->nameval; + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); + namelen = name_rmt->namelen; + name = (char *)name_rmt->name; + } + ASSERT(INT_GET(entry->hashval, ARCH_CONVERT) == args->hashval); + ASSERT(namelen == args->namelen); + ASSERT(bcmp(name, args->name, namelen) == 0); +#endif /* DEBUG */ + + entry->flags &= ~XFS_ATTR_INCOMPLETE; + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); + + if (args->rmtblkno) { + ASSERT((entry->flags & XFS_ATTR_LOCAL) == 0); + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); + INT_SET(name_rmt->valueblk, ARCH_CONVERT, args->rmtblkno); + INT_SET(name_rmt->valuelen, ARCH_CONVERT, args->valuelen); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt))); + } + xfs_da_buf_done(bp); + + /* + * Commit the flag value change and start the next trans in series. + */ + error = xfs_attr_rolltrans(&args->trans, args->dp); + + return(error); +} + +/* + * Set the INCOMPLETE flag on an entry in a leaf block. + */ +int +xfs_attr_leaf_setflag(xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_remote_t *name_rmt; + xfs_dabuf_t *bp; + int error; + + /* + * Set up the operation. + */ + error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp, + XFS_ATTR_FORK); + if (error) { + return(error); + } + ASSERT(bp != NULL); + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(args->index < INT_GET(leaf->hdr.count, ARCH_CONVERT)); + ASSERT(args->index >= 0); + entry = &leaf->entries[ args->index ]; + + ASSERT((entry->flags & XFS_ATTR_INCOMPLETE) == 0); + entry->flags |= XFS_ATTR_INCOMPLETE; + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); + if ((entry->flags & XFS_ATTR_LOCAL) == 0) { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index); + INT_SET(name_rmt->valueblk, ARCH_CONVERT, 0); + INT_SET(name_rmt->valuelen, ARCH_CONVERT, 0); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt))); + } + xfs_da_buf_done(bp); + + /* + * Commit the flag value change and start the next trans in series. + */ + error = xfs_attr_rolltrans(&args->trans, args->dp); + + return(error); +} + +/* + * In a single transaction, clear the INCOMPLETE flag on the leaf entry + * given by args->blkno/index and set the INCOMPLETE flag on the leaf + * entry given by args->blkno2/index2. + * + * Note that they could be in different blocks, or in the same block. + */ +int +xfs_attr_leaf_flipflags(xfs_da_args_t *args) +{ + xfs_attr_leafblock_t *leaf1, *leaf2; + xfs_attr_leaf_entry_t *entry1, *entry2; + xfs_attr_leaf_name_remote_t *name_rmt; + xfs_dabuf_t *bp1, *bp2; + int error; +#ifdef DEBUG + xfs_attr_leaf_name_local_t *name_loc; + int namelen1, namelen2; + char *name1, *name2; +#endif /* DEBUG */ + + /* + * Read the block containing the "old" attr + */ + error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp1, + XFS_ATTR_FORK); + if (error) { + return(error); + } + ASSERT(bp1 != NULL); + + /* + * Read the block containing the "new" attr, if it is different + */ + if (args->blkno2 != args->blkno) { + error = xfs_da_read_buf(args->trans, args->dp, args->blkno2, + -1, &bp2, XFS_ATTR_FORK); + if (error) { + return(error); + } + ASSERT(bp2 != NULL); + } else { + bp2 = bp1; + } + + leaf1 = bp1->data; + ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(args->index < INT_GET(leaf1->hdr.count, ARCH_CONVERT)); + ASSERT(args->index >= 0); + entry1 = &leaf1->entries[ args->index ]; + + leaf2 = bp2->data; + ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + ASSERT(args->index2 < INT_GET(leaf2->hdr.count, ARCH_CONVERT)); + ASSERT(args->index2 >= 0); + entry2 = &leaf2->entries[ args->index2 ]; + +#ifdef DEBUG + if (entry1->flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf1, args->index); + namelen1 = name_loc->namelen; + name1 = (char *)name_loc->nameval; + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf1, args->index); + namelen1 = name_rmt->namelen; + name1 = (char *)name_rmt->name; + } + if (entry2->flags & XFS_ATTR_LOCAL) { + name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf2, args->index2); + namelen2 = name_loc->namelen; + name2 = (char *)name_loc->nameval; + } else { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf2, args->index2); + namelen2 = name_rmt->namelen; + name2 = (char *)name_rmt->name; + } + ASSERT(INT_GET(entry1->hashval, ARCH_CONVERT) == INT_GET(entry2->hashval, ARCH_CONVERT)); + ASSERT(namelen1 == namelen2); + ASSERT(bcmp(name1, name2, namelen1) == 0); +#endif /* DEBUG */ + + ASSERT(entry1->flags & XFS_ATTR_INCOMPLETE); + ASSERT((entry2->flags & XFS_ATTR_INCOMPLETE) == 0); + + entry1->flags &= ~XFS_ATTR_INCOMPLETE; + xfs_da_log_buf(args->trans, bp1, + XFS_DA_LOGRANGE(leaf1, entry1, sizeof(*entry1))); + if (args->rmtblkno) { + ASSERT((entry1->flags & XFS_ATTR_LOCAL) == 0); + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf1, args->index); + INT_SET(name_rmt->valueblk, ARCH_CONVERT, args->rmtblkno); + INT_SET(name_rmt->valuelen, ARCH_CONVERT, args->valuelen); + xfs_da_log_buf(args->trans, bp1, + XFS_DA_LOGRANGE(leaf1, name_rmt, sizeof(*name_rmt))); + } + + entry2->flags |= XFS_ATTR_INCOMPLETE; + xfs_da_log_buf(args->trans, bp2, + XFS_DA_LOGRANGE(leaf2, entry2, sizeof(*entry2))); + if ((entry2->flags & XFS_ATTR_LOCAL) == 0) { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf2, args->index2); + INT_SET(name_rmt->valueblk, ARCH_CONVERT, 0); + INT_SET(name_rmt->valuelen, ARCH_CONVERT, 0); + xfs_da_log_buf(args->trans, bp2, + XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt))); + } + xfs_da_buf_done(bp1); + if (bp1 != bp2) + xfs_da_buf_done(bp2); + + /* + * Commit the flag value change and start the next trans in series. + */ + error = xfs_attr_rolltrans(&args->trans, args->dp); + + return(error); +} + +/*======================================================================== + * Indiscriminately delete the entire attribute fork + *========================================================================*/ + +/* + * Recurse (gasp!) through the attribute nodes until we find leaves. + * We're doing a depth-first traversal in order to invalidate everything. + */ +int +xfs_attr_root_inactive(xfs_trans_t **trans, xfs_inode_t *dp) +{ + xfs_da_blkinfo_t *info; + xfs_daddr_t blkno; + xfs_dabuf_t *bp; + int error; + + /* + * Read block 0 to see what we have to work with. + * We only get here if we have extents, since we remove + * the extents in reverse order the extent containing + * block 0 must still be there. + */ + error = xfs_da_read_buf(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK); + if (error) + return(error); + blkno = xfs_da_blkno(bp); + + /* + * Invalidate the tree, even if the "tree" is only a single leaf block. + * This is a depth-first traversal! + */ + info = bp->data; + if (INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) { + error = xfs_attr_node_inactive(trans, dp, bp, 1); + } else if (INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC) { + error = xfs_attr_leaf_inactive(trans, dp, bp); + } else { + error = XFS_ERROR(EIO); + xfs_da_brelse(*trans, bp); + } + if (error) + return(error); + + /* + * Invalidate the incore copy of the root block. + */ + error = xfs_da_get_buf(*trans, dp, 0, blkno, &bp, XFS_ATTR_FORK); + if (error) + return(error); + xfs_da_binval(*trans, bp); /* remove from cache */ + /* + * Commit the invalidate and start the next transaction. + */ + error = xfs_attr_rolltrans(trans, dp); + + return (error); +} + +/* + * Recurse (gasp!) through the attribute nodes until we find leaves. + * We're doing a depth-first traversal in order to invalidate everything. + */ +int +xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp, + int level) +{ + xfs_da_blkinfo_t *info; + xfs_da_intnode_t *node; + xfs_dablk_t child_fsb; + xfs_daddr_t parent_blkno, child_blkno; + int error, count, i; + xfs_dabuf_t *child_bp; + + /* + * Since this code is recursive (gasp!) we must protect ourselves. + */ + if (level > XFS_DA_NODE_MAXDEPTH) { + xfs_da_brelse(*trans, bp); /* no locks for later trans */ + return(XFS_ERROR(EIO)); + } + + node = bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) + == XFS_DA_NODE_MAGIC); + parent_blkno = xfs_da_blkno(bp); /* save for re-read later */ + count = INT_GET(node->hdr.count, ARCH_CONVERT); + if (!count) { + xfs_da_brelse(*trans, bp); + return(0); + } + child_fsb = INT_GET(node->btree[0].before, ARCH_CONVERT); + xfs_da_brelse(*trans, bp); /* no locks for later trans */ + + /* + * If this is the node level just above the leaves, simply loop + * over the leaves removing all of them. If this is higher up + * in the tree, recurse downward. + */ + for (i = 0; i < count; i++) { + /* + * Read the subsidiary block to see what we have to work with. + * Don't do this in a transaction. This is a depth-first + * traversal of the tree so we may deal with many blocks + * before we come back to this one. + */ + error = xfs_da_read_buf(*trans, dp, child_fsb, -2, &child_bp, + XFS_ATTR_FORK); + if (error) + return(error); + if (child_bp) { + /* save for re-read later */ + child_blkno = xfs_da_blkno(child_bp); + + /* + * Invalidate the subtree, however we have to. + */ + info = child_bp->data; + if (INT_GET(info->magic, ARCH_CONVERT) + == XFS_DA_NODE_MAGIC) { + error = xfs_attr_node_inactive(trans, dp, + child_bp, level+1); + } else if (INT_GET(info->magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC) { + error = xfs_attr_leaf_inactive(trans, dp, + child_bp); + } else { + error = XFS_ERROR(EIO); + xfs_da_brelse(*trans, child_bp); + } + if (error) + return(error); + + /* + * Remove the subsidiary block from the cache + * and from the log. + */ + error = xfs_da_get_buf(*trans, dp, 0, child_blkno, + &child_bp, XFS_ATTR_FORK); + if (error) + return(error); + xfs_da_binval(*trans, child_bp); + } + + /* + * If we're not done, re-read the parent to get the next + * child block number. + */ + if ((i+1) < count) { + error = xfs_da_read_buf(*trans, dp, 0, parent_blkno, + &bp, XFS_ATTR_FORK); + if (error) + return(error); + child_fsb = INT_GET(node->btree[i+1].before, ARCH_CONVERT); + xfs_da_brelse(*trans, bp); + } + /* + * Atomically commit the whole invalidate stuff. + */ + if ((error = xfs_attr_rolltrans(trans, dp))) + return (error); + } + + return(0); +} + +/* + * Invalidate all of the "remote" value regions pointed to by a particular + * leaf block. + * Note that we must release the lock on the buffer so that we are not + * caught holding something that the logging code wants to flush to disk. + */ +int +xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp) +{ + xfs_attr_leafblock_t *leaf; + xfs_attr_leaf_entry_t *entry; + xfs_attr_leaf_name_remote_t *name_rmt; + xfs_attr_inactive_list_t *list, *lp; + int error, count, size, tmp, i; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) + == XFS_ATTR_LEAF_MAGIC); + + /* + * Count the number of "remote" value extents. + */ + count = 0; + entry = &leaf->entries[0]; + for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { + if ( INT_GET(entry->nameidx, ARCH_CONVERT) + && ((entry->flags & XFS_ATTR_LOCAL) == 0)) { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i); + if (INT_GET(name_rmt->valueblk, ARCH_CONVERT) != 0) + count++; + } + } + + /* + * If there are no "remote" values, we're done. + */ + if (count == 0) { + xfs_da_brelse(*trans, bp); + return(0); + } + + /* + * Allocate storage for a list of all the "remote" value extents. + */ + size = count * sizeof(xfs_attr_inactive_list_t); + list = (xfs_attr_inactive_list_t *)kmem_alloc(size, KM_SLEEP); + + /* + * Identify each of the "remote" value extents. + */ + lp = list; + entry = &leaf->entries[0]; + for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) { + if ( INT_GET(entry->nameidx, ARCH_CONVERT) + && ((entry->flags & XFS_ATTR_LOCAL) == 0)) { + name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i); + if (INT_GET(name_rmt->valueblk, ARCH_CONVERT) != 0) { + INT_SET(lp->valueblk, ARCH_CONVERT, + INT_GET(name_rmt->valueblk, + ARCH_CONVERT)); + INT_SET(lp->valuelen, ARCH_CONVERT, + XFS_B_TO_FSB(dp->i_mount, + INT_GET(name_rmt->valuelen, + ARCH_CONVERT))); + lp++; + } + } + } + xfs_da_brelse(*trans, bp); /* unlock for trans. in freextent() */ + + /* + * Invalidate each of the "remote" value extents. + */ + error = 0; + for (lp = list, i = 0; i < count; i++, lp++) { + tmp = xfs_attr_leaf_freextent(trans, dp, + INT_GET(lp->valueblk, + ARCH_CONVERT), + INT_GET(lp->valuelen, + ARCH_CONVERT)); + if (error == 0) + error = tmp; /* save only the 1st errno */ + } + + kmem_free((xfs_caddr_t)list, size); + return(error); +} + +/* + * Look at all the extents for this logical region, + * invalidate any buffers that are incore/in transactions. + */ +int +xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp, + xfs_dablk_t blkno, int blkcnt) +{ + xfs_bmbt_irec_t map; + xfs_dablk_t tblkno; + int tblkcnt, dblkcnt, nmap, error; + xfs_daddr_t dblkno; + xfs_buf_t *bp; + + /* + * Roll through the "value", invalidating the attribute value's + * blocks. + */ + tblkno = blkno; + tblkcnt = blkcnt; + while (tblkcnt > 0) { + /* + * Try to remember where we decided to put the value. + */ + nmap = 1; + error = xfs_bmapi(*trans, dp, (xfs_fileoff_t)tblkno, tblkcnt, + XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA, + NULL, 0, &map, &nmap, NULL); + if (error) { + return(error); + } + ASSERT(nmap == 1); + ASSERT(map.br_startblock != DELAYSTARTBLOCK); + + /* + * If it's a hole, these are already unmapped + * so there's nothing to invalidate. + */ + if (map.br_startblock != HOLESTARTBLOCK) { + + dblkno = XFS_FSB_TO_DADDR(dp->i_mount, + map.br_startblock); + dblkcnt = XFS_FSB_TO_BB(dp->i_mount, + map.br_blockcount); + bp = xfs_trans_get_buf(*trans, + dp->i_mount->m_ddev_targp, + dblkno, dblkcnt, 0); + xfs_trans_binval(*trans, bp); + /* + * Roll to next transaction. + */ + if ((error = xfs_attr_rolltrans(trans, dp))) + return (error); + } + + tblkno += map.br_blockcount; + tblkcnt -= map.br_blockcount; + } + + return(0); +} + + +/* + * Roll from one trans in the sequence of PERMANENT transactions to the next. + */ +int +xfs_attr_rolltrans(xfs_trans_t **transp, xfs_inode_t *dp) +{ + xfs_trans_t *trans; + unsigned int logres, count; + int error; + + /* + * Ensure that the inode is always logged. + */ + trans = *transp; + xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); + + /* + * Copy the critical parameters from one trans to the next. + */ + logres = trans->t_log_res; + count = trans->t_log_count; + *transp = xfs_trans_dup(trans); + + /* + * Commit the current transaction. + * If this commit failed, then it'd just unlock those items that + * are not marked ihold. That also means that a filesystem shutdown + * is in progress. The caller takes the responsibility to cancel + * the duplicate transaction that gets returned. + */ + if ((error = xfs_trans_commit(trans, 0, NULL))) + return (error); + + trans = *transp; + + /* + * Reserve space in the log for th next transaction. + * This also pushes items in the "AIL", the list of logged items, + * out to disk if they are taking up space at the tail of the log + * that we want to use. This requires that either nothing be locked + * across this call, or that anything that is locked be logged in + * the prior and the next transactions. + */ + error = xfs_trans_reserve(trans, 0, logres, 0, + XFS_TRANS_PERM_LOG_RES, count); + /* + * Ensure that the inode is in the new transaction and locked. + */ + if (!error) { + xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL); + xfs_trans_ihold(trans, dp); + } + return (error); + +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_attr_leaf.h linux-2.4-xfs/linux/fs/xfs/xfs_attr_leaf.h --- linux-2.4.7/linux/fs/xfs/xfs_attr_leaf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_attr_leaf.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ATTR_LEAF_H__ +#define __XFS_ATTR_LEAF_H__ + +/* + * Attribute storage layout, internal structure, access macros, etc. + * + * Attribute lists are structured around Btrees where all the data + * elements are in the leaf nodes. Attribute names are hashed into an int, + * then that int is used as the index into the Btree. Since the hashval + * of an attribute name may not be unique, we may have duplicate keys. The + * internal links in the Btree are logical block offsets into the file. + */ + +struct attrlist; +struct attrlist_cursor_kern; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_da_state; +struct xfs_da_state_blk; +struct xfs_inode; +struct xfs_trans; + +/*======================================================================== + * Attribute structure when equal to XFS_LBSIZE(mp) bytes. + *========================================================================*/ + +/* + * This is the structure of the leaf nodes in the Btree. + * + * Struct leaf_entry's are packed from the top. Name/values grow from the + * bottom but are not packed. The freemap contains run-length-encoded entries + * for the free bytes after the leaf_entry's, but only the N largest such, + * smaller runs are dropped. When the freemap doesn't show enough space + * for an allocation, we compact the name/value area and try again. If we + * still don't have enough space, then we have to split the block. The + * name/value structs (both local and remote versions) must be 32bit aligned. + * + * Since we have duplicate hash keys, for each key that matches, compare + * the actual name string. The root and intermediate node search always + * takes the first-in-the-block key match found, so we should only have + * to work "forw"ard. If none matches, continue with the "forw"ard leaf + * nodes until the hash key changes or the attribute name is found. + * + * We store the fact that an attribute is a ROOT versus USER attribute in + * the leaf_entry. The namespaces are independent only because we also look + * at the root/user bit when we are looking for a matching attribute name. + * + * We also store a "incomplete" bit in the leaf_entry. It shows that an + * attribute is in the middle of being created and should not be shown to + * the user if we crash during the time that the bit is set. We clear the + * bit when we have finished setting up the attribute. We do this because + * we cannot create some large attributes inside a single transaction, and we + * need some indication that we weren't finished if we crash in the middle. + */ +#define XFS_ATTR_LEAF_MAPSIZE 3 /* how many freespace slots */ + +typedef struct xfs_attr_leafblock { + struct xfs_attr_leaf_hdr { /* constant-structure header block */ + xfs_da_blkinfo_t info; /* block type, links, etc. */ + __uint16_t count; /* count of active leaf_entry's */ + __uint16_t usedbytes; /* num bytes of names/values stored */ + __uint16_t firstused; /* first used byte in name area */ + __uint8_t holes; /* != 0 if blk needs compaction */ + __uint8_t pad1; + struct xfs_attr_leaf_map { /* RLE map of free bytes */ + __uint16_t base; /* base of free region */ + __uint16_t size; /* length of free region */ + } freemap[XFS_ATTR_LEAF_MAPSIZE]; /* N largest free regions */ + } hdr; + struct xfs_attr_leaf_entry { /* sorted on key, not name */ + xfs_dahash_t hashval; /* hash value of name */ + __uint16_t nameidx; /* index into buffer of name/value */ + __uint8_t flags; /* LOCAL, ROOT and INCOMPLETE flags */ + __uint8_t pad2; /* unused pad byte */ + } entries[1]; /* variable sized array */ + struct xfs_attr_leaf_name_local { + __uint16_t valuelen; /* number of bytes in value */ + __uint8_t namelen; /* length of name bytes */ + __uint8_t nameval[1]; /* name/value bytes */ + } namelist; /* grows from bottom of buf */ + struct xfs_attr_leaf_name_remote { + xfs_dablk_t valueblk; /* block number of value bytes */ + __uint32_t valuelen; /* number of bytes in value */ + __uint8_t namelen; /* length of name bytes */ + __uint8_t name[1]; /* name bytes */ + } valuelist; /* grows from bottom of buf */ +} xfs_attr_leafblock_t; +typedef struct xfs_attr_leaf_hdr xfs_attr_leaf_hdr_t; +typedef struct xfs_attr_leaf_map xfs_attr_leaf_map_t; +typedef struct xfs_attr_leaf_entry xfs_attr_leaf_entry_t; +typedef struct xfs_attr_leaf_name_local xfs_attr_leaf_name_local_t; +typedef struct xfs_attr_leaf_name_remote xfs_attr_leaf_name_remote_t; + +/* + * Flags used in the leaf_entry[i].flags field. + * NOTE: the INCOMPLETE bit must not collide with the flags bits specified + * on the system call, they are "or"ed together for various operations. + */ +#define XFS_ATTR_LOCAL_BIT 0 /* attr is stored locally */ +#define XFS_ATTR_ROOT_BIT 1 /* limit access to attr to userid 0 */ +#define XFS_ATTR_INCOMPLETE_BIT 7 /* attr in middle of create/delete */ +#define XFS_ATTR_LOCAL (1 << XFS_ATTR_LOCAL_BIT) +#define XFS_ATTR_ROOT (1 << XFS_ATTR_ROOT_BIT) +#define XFS_ATTR_INCOMPLETE (1 << XFS_ATTR_INCOMPLETE_BIT) + +/* + * Alignment for namelist and valuelist entries (since they are mixed + * there can be only one alignment value) + */ +#define XFS_ATTR_LEAF_NAME_ALIGN ((uint)sizeof(xfs_dablk_t)) + +/* + * Cast typed pointers for "local" and "remote" name/value structs. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_NAME_REMOTE) +xfs_attr_leaf_name_remote_t * +xfs_attr_leaf_name_remote(xfs_attr_leafblock_t *leafp, int idx); +#define XFS_ATTR_LEAF_NAME_REMOTE(leafp,idx) \ + xfs_attr_leaf_name_remote(leafp,idx) +#else +#define XFS_ATTR_LEAF_NAME_REMOTE(leafp,idx) /* remote name struct ptr */ \ + ((xfs_attr_leaf_name_remote_t *) \ + &((char *)(leafp))[ INT_GET((leafp)->entries[idx].nameidx, ARCH_CONVERT) ]) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_NAME_LOCAL) +xfs_attr_leaf_name_local_t * +xfs_attr_leaf_name_local(xfs_attr_leafblock_t *leafp, int idx); +#define XFS_ATTR_LEAF_NAME_LOCAL(leafp,idx) \ + xfs_attr_leaf_name_local(leafp,idx) +#else +#define XFS_ATTR_LEAF_NAME_LOCAL(leafp,idx) /* local name struct ptr */ \ + ((xfs_attr_leaf_name_local_t *) \ + &((char *)(leafp))[ INT_GET((leafp)->entries[idx].nameidx, ARCH_CONVERT) ]) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_NAME) +char *xfs_attr_leaf_name(xfs_attr_leafblock_t *leafp, int idx); +#define XFS_ATTR_LEAF_NAME(leafp,idx) xfs_attr_leaf_name(leafp,idx) +#else +#define XFS_ATTR_LEAF_NAME(leafp,idx) /* generic name struct ptr */ \ + (&((char *)(leafp))[ INT_GET((leafp)->entries[idx].nameidx, ARCH_CONVERT) ]) +#endif + +/* + * Calculate total bytes used (including trailing pad for alignment) for + * a "local" name/value structure, a "remote" name/value structure, and + * a pointer which might be either. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_ENTSIZE_REMOTE) +int xfs_attr_leaf_entsize_remote(int nlen); +#define XFS_ATTR_LEAF_ENTSIZE_REMOTE(nlen) \ + xfs_attr_leaf_entsize_remote(nlen) +#else +#define XFS_ATTR_LEAF_ENTSIZE_REMOTE(nlen) /* space for remote struct */ \ + (((uint)sizeof(xfs_attr_leaf_name_remote_t) - 1 + (nlen) + \ + XFS_ATTR_LEAF_NAME_ALIGN - 1) & ~(XFS_ATTR_LEAF_NAME_ALIGN - 1)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_ENTSIZE_LOCAL) +int xfs_attr_leaf_entsize_local(int nlen, int vlen); +#define XFS_ATTR_LEAF_ENTSIZE_LOCAL(nlen,vlen) \ + xfs_attr_leaf_entsize_local(nlen,vlen) +#else +#define XFS_ATTR_LEAF_ENTSIZE_LOCAL(nlen,vlen) /* space for local struct */ \ + (((uint)sizeof(xfs_attr_leaf_name_local_t) - 1 + (nlen) + (vlen) + \ + XFS_ATTR_LEAF_NAME_ALIGN - 1) & ~(XFS_ATTR_LEAF_NAME_ALIGN - 1)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX) +int xfs_attr_leaf_entsize_local_max(int bsize); +#define XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX(bsize) \ + xfs_attr_leaf_entsize_local_max(bsize) +#else +#define XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX(bsize) /* max local struct size */ \ + (((bsize) >> 1) + ((bsize) >> 2)) +#endif + + +/*======================================================================== + * Structure used to pass context around among the routines. + *========================================================================*/ + +typedef struct xfs_attr_list_context { + struct xfs_inode *dp; /* inode */ + struct attrlist_cursor_kern *cursor;/* position in list */ + struct attrlist *alist; /* output buffer */ + int count; /* num used entries */ + int dupcnt; /* count dup hashvals seen */ + int bufsize;/* total buffer size */ + int firstu; /* first used byte in buffer */ + int flags; /* from VOP call */ + int resynch;/* T/F: resynch with cursor */ +} xfs_attr_list_context_t; + +/* + * Used to keep a list of "remote value" extents when unlinking an inode. + */ +typedef struct xfs_attr_inactive_list { + xfs_dablk_t valueblk; /* block number of value bytes */ + int valuelen; /* number of bytes in value */ +} xfs_attr_inactive_list_t; + + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Internal routines when dirsize < XFS_LITINO(mp). + */ +int xfs_attr_shortform_create(struct xfs_da_args *args); +int xfs_attr_shortform_add(struct xfs_da_args *add); +int xfs_attr_shortform_lookup(struct xfs_da_args *args); +int xfs_attr_shortform_getvalue(struct xfs_da_args *args); +int xfs_attr_shortform_to_leaf(struct xfs_da_args *args); +int xfs_attr_shortform_remove(struct xfs_da_args *remove); +int xfs_attr_shortform_list(struct xfs_attr_list_context *context); +int xfs_attr_shortform_replace(struct xfs_da_args *args); +int xfs_attr_shortform_allfit(struct xfs_dabuf *bp, struct xfs_inode *dp); + +/* + * Internal routines when dirsize == XFS_LBSIZE(mp). + */ +int xfs_attr_leaf_to_node(struct xfs_da_args *args); +int xfs_attr_leaf_to_shortform(struct xfs_dabuf *bp, + struct xfs_da_args *args); +int xfs_attr_leaf_clearflag(struct xfs_da_args *args); +int xfs_attr_leaf_setflag(struct xfs_da_args *args); +int xfs_attr_leaf_flipflags(xfs_da_args_t *args); + +/* + * Routines used for growing the Btree. + */ +int xfs_attr_leaf_create(struct xfs_da_args *args, xfs_dablk_t which_block, + struct xfs_dabuf **bpp); +int xfs_attr_leaf_split(struct xfs_da_state *state, + struct xfs_da_state_blk *oldblk, + struct xfs_da_state_blk *newblk); +int xfs_attr_leaf_lookup_int(struct xfs_dabuf *leaf, + struct xfs_da_args *args); +int xfs_attr_leaf_getvalue(struct xfs_dabuf *bp, struct xfs_da_args *args); +int xfs_attr_leaf_add(struct xfs_dabuf *leaf_buffer, + struct xfs_da_args *args); +int xfs_attr_leaf_remove(struct xfs_dabuf *leaf_buffer, + struct xfs_da_args *args); +int xfs_attr_leaf_list_int(struct xfs_dabuf *bp, + struct xfs_attr_list_context *context); + +/* + * Routines used for shrinking the Btree. + */ +int xfs_attr_leaf_toosmall(struct xfs_da_state *state, int *retval); +void xfs_attr_leaf_unbalance(struct xfs_da_state *state, + struct xfs_da_state_blk *drop_blk, + struct xfs_da_state_blk *save_blk); +int xfs_attr_root_inactive(struct xfs_trans **trans, struct xfs_inode *dp); +int xfs_attr_node_inactive(struct xfs_trans **trans, struct xfs_inode *dp, + struct xfs_dabuf *bp, int level); +int xfs_attr_leaf_inactive(struct xfs_trans **trans, struct xfs_inode *dp, + struct xfs_dabuf *bp); +int xfs_attr_leaf_freextent(struct xfs_trans **trans, struct xfs_inode *dp, + xfs_dablk_t blkno, int blkcnt); + +/* + * Utility routines. + */ +xfs_dahash_t xfs_attr_leaf_lasthash(struct xfs_dabuf *bp, int *count); +int xfs_attr_leaf_order(struct xfs_dabuf *leaf1_bp, + struct xfs_dabuf *leaf2_bp); +int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int blocksize, + int *local); +int xfs_attr_leaf_entsize(struct xfs_attr_leafblock *leaf, int index); +int xfs_attr_put_listent(struct xfs_attr_list_context *context, + char *name, int namelen, int valuelen); +int xfs_attr_rolltrans(struct xfs_trans **transp, struct xfs_inode *dp); + +#endif /* __XFS_ATTR_LEAF_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_attr_sf.h linux-2.4-xfs/linux/fs/xfs/xfs_attr_sf.h --- linux-2.4.7/linux/fs/xfs/xfs_attr_sf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_attr_sf.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ATTR_SF_H__ +#define __XFS_ATTR_SF_H__ + +/* + * Attribute storage when stored inside the inode. + * + * Small attribute lists are packed as tightly as possible so as + * to fit into the literal area of the inode. + */ + +struct xfs_inode; + +/* + * Entries are packed toward the top as tight as possible. + */ +typedef struct xfs_attr_shortform { + struct xfs_attr_sf_hdr { /* constant-structure header block */ + __uint16_t totsize; /* total bytes in shortform list */ + __uint8_t count; /* count of active entries */ + } hdr; + struct xfs_attr_sf_entry { + __uint8_t namelen; /* actual length of name (no NULL) */ + __uint8_t valuelen; /* actual length of value (no NULL) */ + __uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */ + __uint8_t nameval[1]; /* name & value bytes concatenated */ + } list[1]; /* variable sized array */ +} xfs_attr_shortform_t; +typedef struct xfs_attr_sf_hdr xfs_attr_sf_hdr_t; +typedef struct xfs_attr_sf_entry xfs_attr_sf_entry_t; + +/* + * We generate this then sort it, attr_list() must return things in hash-order. + */ +typedef struct xfs_attr_sf_sort { + __uint8_t entno; /* entry number in original list */ + __uint8_t namelen; /* length of name value (no null) */ + __uint8_t valuelen; /* length of value */ + xfs_dahash_t hash; /* this entry's hash value */ + char *name; /* name value, pointer into buffer */ +} xfs_attr_sf_sort_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_SF_ENTSIZE_BYNAME) +int xfs_attr_sf_entsize_byname(int nlen, int vlen); +#define XFS_ATTR_SF_ENTSIZE_BYNAME(nlen,vlen) \ + xfs_attr_sf_entsize_byname(nlen,vlen) +#else +#define XFS_ATTR_SF_ENTSIZE_BYNAME(nlen,vlen) /* space name/value uses */ \ + ((int)sizeof(xfs_attr_sf_entry_t)-1 + (nlen)+(vlen)) +#endif +#define XFS_ATTR_SF_ENTSIZE_MAX /* max space for name&value */ \ + ((1 << (NBBY*(int)sizeof(__uint8_t))) - 1) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_SF_ENTSIZE) +int xfs_attr_sf_entsize(xfs_attr_sf_entry_t *sfep); +#define XFS_ATTR_SF_ENTSIZE(sfep) xfs_attr_sf_entsize(sfep) +#else +#define XFS_ATTR_SF_ENTSIZE(sfep) /* space an entry uses */ \ + ((int)sizeof(xfs_attr_sf_entry_t)-1 + (sfep)->namelen+(sfep)->valuelen) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_SF_NEXTENTRY) +xfs_attr_sf_entry_t *xfs_attr_sf_nextentry(xfs_attr_sf_entry_t *sfep); +#define XFS_ATTR_SF_NEXTENTRY(sfep) xfs_attr_sf_nextentry(sfep) +#else +#define XFS_ATTR_SF_NEXTENTRY(sfep) /* next entry in struct */ \ + ((xfs_attr_sf_entry_t *) \ + ((char *)(sfep) + XFS_ATTR_SF_ENTSIZE(sfep))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ATTR_SF_TOTSIZE) +int xfs_attr_sf_totsize(struct xfs_inode *dp); +#define XFS_ATTR_SF_TOTSIZE(dp) xfs_attr_sf_totsize(dp) +#else +#define XFS_ATTR_SF_TOTSIZE(dp) /* total space in use */ \ + (INT_GET(((xfs_attr_shortform_t *)((dp)->i_afp->if_u1.if_data))->hdr.totsize, ARCH_CONVERT)) +#endif + +#ifdef XFS_ALL_TRACE +#define XFS_ATTR_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_ATTR_TRACE +#endif + +/* + * Kernel tracing support for attribute lists + */ +struct xfs_attr_list_context; +struct xfs_da_intnode; +struct xfs_da_node_entry; +struct xfs_attr_leafblock; + +#define XFS_ATTR_TRACE_SIZE 4096 /* size of global trace buffer */ + +/* + * Trace record types. + */ +#define XFS_ATTR_KTRACE_L_C 1 /* context */ +#define XFS_ATTR_KTRACE_L_CN 2 /* context, node */ +#define XFS_ATTR_KTRACE_L_CB 3 /* context, btree */ +#define XFS_ATTR_KTRACE_L_CL 4 /* context, leaf */ + +#if defined(XFS_ATTR_TRACE) + +void xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context); +void xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context, + struct xfs_da_intnode *node); +void xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context, + struct xfs_da_node_entry *btree); +void xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context, + struct xfs_attr_leafblock *leaf); +void xfs_attr_trace_enter(int type, char *where, + __psunsigned_t a2, __psunsigned_t a3, + __psunsigned_t a4, __psunsigned_t a5, + __psunsigned_t a6, __psunsigned_t a7, + __psunsigned_t a8, __psunsigned_t a9, + __psunsigned_t a10, __psunsigned_t a11, + __psunsigned_t a12, __psunsigned_t a13, + __psunsigned_t a14, __psunsigned_t a15); +#else +#define xfs_attr_trace_l_c(w,c) +#define xfs_attr_trace_l_cn(w,c,n) +#define xfs_attr_trace_l_cb(w,c,b) +#define xfs_attr_trace_l_cl(w,c,l) +#endif /* XFS_ATTR_TRACE */ + +#endif /* __XFS_ATTR_SF_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_bit.c linux-2.4-xfs/linux/fs/xfs/xfs_bit.c --- linux-2.4.7/linux/fs/xfs/xfs_bit.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_bit.c Tue Apr 10 20:44:54 2001 @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * XFS bit manipulation routines, used in non-realtime code. + */ + +#include + +/* + * Index of low bit number in byte, -1 for none set, 0..7 otherwise. + */ +const char xfs_lowbit[256] = { + -1, 0, 1, 0, 2, 0, 1, 0, /* 00 .. 07 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 08 .. 0f */ + 4, 0, 1, 0, 2, 0, 1, 0, /* 10 .. 17 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 18 .. 1f */ + 5, 0, 1, 0, 2, 0, 1, 0, /* 20 .. 27 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 28 .. 2f */ + 4, 0, 1, 0, 2, 0, 1, 0, /* 30 .. 37 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 38 .. 3f */ + 6, 0, 1, 0, 2, 0, 1, 0, /* 40 .. 47 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 48 .. 4f */ + 4, 0, 1, 0, 2, 0, 1, 0, /* 50 .. 57 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 58 .. 5f */ + 5, 0, 1, 0, 2, 0, 1, 0, /* 60 .. 67 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 68 .. 6f */ + 4, 0, 1, 0, 2, 0, 1, 0, /* 70 .. 77 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 78 .. 7f */ + 7, 0, 1, 0, 2, 0, 1, 0, /* 80 .. 87 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 88 .. 8f */ + 4, 0, 1, 0, 2, 0, 1, 0, /* 90 .. 97 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* 98 .. 9f */ + 5, 0, 1, 0, 2, 0, 1, 0, /* a0 .. a7 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* a8 .. af */ + 4, 0, 1, 0, 2, 0, 1, 0, /* b0 .. b7 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* b8 .. bf */ + 6, 0, 1, 0, 2, 0, 1, 0, /* c0 .. c7 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* c8 .. cf */ + 4, 0, 1, 0, 2, 0, 1, 0, /* d0 .. d7 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* d8 .. df */ + 5, 0, 1, 0, 2, 0, 1, 0, /* e0 .. e7 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* e8 .. ef */ + 4, 0, 1, 0, 2, 0, 1, 0, /* f0 .. f7 */ + 3, 0, 1, 0, 2, 0, 1, 0, /* f8 .. ff */ +}; + +/* + * Index of high bit number in byte, -1 for none set, 0..7 otherwise. + */ +const char xfs_highbit[256] = { + -1, 0, 1, 1, 2, 2, 2, 2, /* 00 .. 07 */ + 3, 3, 3, 3, 3, 3, 3, 3, /* 08 .. 0f */ + 4, 4, 4, 4, 4, 4, 4, 4, /* 10 .. 17 */ + 4, 4, 4, 4, 4, 4, 4, 4, /* 18 .. 1f */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 20 .. 27 */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 28 .. 2f */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 30 .. 37 */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 38 .. 3f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 40 .. 47 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 48 .. 4f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 50 .. 57 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 58 .. 5f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 60 .. 67 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 68 .. 6f */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 70 .. 77 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 78 .. 7f */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 80 .. 87 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 88 .. 8f */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 90 .. 97 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* 98 .. 9f */ + 7, 7, 7, 7, 7, 7, 7, 7, /* a0 .. a7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* a8 .. af */ + 7, 7, 7, 7, 7, 7, 7, 7, /* b0 .. b7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* b8 .. bf */ + 7, 7, 7, 7, 7, 7, 7, 7, /* c0 .. c7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* c8 .. cf */ + 7, 7, 7, 7, 7, 7, 7, 7, /* d0 .. d7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* d8 .. df */ + 7, 7, 7, 7, 7, 7, 7, 7, /* e0 .. e7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* e8 .. ef */ + 7, 7, 7, 7, 7, 7, 7, 7, /* f0 .. f7 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* f8 .. ff */ +}; + +/* + * Count of bits set in byte, 0..8. + */ +const char xfs_countbit[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, /* 00 .. 07 */ + 1, 2, 2, 3, 2, 3, 3, 4, /* 08 .. 0f */ + 1, 2, 2, 3, 2, 3, 3, 4, /* 10 .. 17 */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 18 .. 1f */ + 1, 2, 2, 3, 2, 3, 3, 4, /* 20 .. 27 */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 28 .. 2f */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 30 .. 37 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* 38 .. 3f */ + 1, 2, 2, 3, 2, 3, 3, 4, /* 40 .. 47 */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 48 .. 4f */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 50 .. 57 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* 58 .. 5f */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 60 .. 67 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* 68 .. 6f */ + 3, 4, 4, 5, 4, 5, 5, 6, /* 70 .. 77 */ + 4, 5, 5, 6, 5, 6, 6, 7, /* 78 .. 7f */ + 1, 2, 2, 3, 2, 3, 3, 4, /* 80 .. 87 */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 88 .. 8f */ + 2, 3, 3, 4, 3, 4, 4, 5, /* 90 .. 97 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* 98 .. 9f */ + 2, 3, 3, 4, 3, 4, 4, 5, /* a0 .. a7 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* a8 .. af */ + 3, 4, 4, 5, 4, 5, 5, 6, /* b0 .. b7 */ + 4, 5, 5, 6, 5, 6, 6, 7, /* b8 .. bf */ + 2, 3, 3, 4, 3, 4, 4, 5, /* c0 .. c7 */ + 3, 4, 4, 5, 4, 5, 5, 6, /* c8 .. cf */ + 3, 4, 4, 5, 4, 5, 5, 6, /* d0 .. d7 */ + 4, 5, 5, 6, 5, 6, 6, 7, /* d8 .. df */ + 3, 4, 4, 5, 4, 5, 5, 6, /* e0 .. e7 */ + 4, 5, 5, 6, 5, 6, 6, 7, /* e8 .. ef */ + 4, 5, 5, 6, 5, 6, 6, 7, /* f0 .. f7 */ + 5, 6, 6, 7, 6, 7, 7, 8, /* f8 .. ff */ +}; + +/* + * xfs_highbit32: get high bit set out of 32-bit argument, -1 if none set. + */ +int +xfs_highbit32( + __uint32_t v) +{ + int i; + + if (v & 0xffff0000) + if (v & 0xff000000) + i = 24; + else + i = 16; + else if (v & 0x0000ffff) + if (v & 0x0000ff00) + i = 8; + else + i = 0; + else + return -1; + return i + xfs_highbit[(v >> i) & 0xff]; +} + +/* + * xfs_lowbit64: get low bit set out of 64-bit argument, -1 if none set. + */ +int +xfs_lowbit64( + __uint64_t v) +{ + int i; +#if XFS_64 + if (v & 0x00000000ffffffff) + if (v & 0x000000000000ffff) + if (v & 0x00000000000000ff) + i = 0; + else + i = 8; + else + if (v & 0x0000000000ff0000) + i = 16; + else + i = 24; + else if (v & 0xffffffff00000000) + if (v & 0x0000ffff00000000) + if (v & 0x000000ff00000000) + i = 32; + else + i = 40; + else + if (v & 0x00ff000000000000) + i = 48; + else + i = 56; + else + return -1; + return i + xfs_lowbit[(v >> i) & 0xff]; +#else + __uint32_t vw; + + if ((vw = v)) { + if (vw & 0x0000ffff) + if (vw & 0x000000ff) + i = 0; + else + i = 8; + else + if (vw & 0x00ff0000) + i = 16; + else + i = 24; + return i + xfs_lowbit[(vw >> i) & 0xff]; + } else if ((vw = v >> 32)) { + if (vw & 0x0000ffff) + if (vw & 0x000000ff) + i = 32; + else + i = 40; + else + if (vw & 0x00ff0000) + i = 48; + else + i = 56; + return i + xfs_lowbit[(vw >> (i - 32)) & 0xff]; + } else + return -1; +#endif +} + +/* + * xfs_highbit64: get high bit set out of 64-bit argument, -1 if none set. + */ +int +xfs_highbit64( + __uint64_t v) +{ + int i; +#if XFS_64 + if (v & 0xffffffff00000000) + if (v & 0xffff000000000000) + if (v & 0xff00000000000000) + i = 56; + else + i = 48; + else + if (v & 0x0000ff0000000000) + i = 40; + else + i = 32; + else if (v & 0x00000000ffffffff) + if (v & 0x00000000ffff0000) + if (v & 0x00000000ff000000) + i = 24; + else + i = 16; + else + if (v & 0x000000000000ff00) + i = 8; + else + i = 0; + else + return -1; + return i + xfs_highbit[(v >> i) & 0xff]; +#else + __uint32_t vw; + + if ((vw = v >> 32)) { + if (vw & 0xffff0000) + if (vw & 0xff000000) + i = 56; + else + i = 48; + else + if (vw & 0x0000ff00) + i = 40; + else + i = 32; + return i + xfs_highbit[(vw >> (i - 32)) & 0xff]; + } else if ((vw = v)) { + if (vw & 0xffff0000) + if (vw & 0xff000000) + i = 24; + else + i = 16; + else + if (vw & 0x0000ff00) + i = 8; + else + i = 0; + return i + xfs_highbit[(vw >> i) & 0xff]; + } else + return -1; +#endif +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_bit.h linux-2.4-xfs/linux/fs/xfs/xfs_bit.h --- linux-2.4.7/linux/fs/xfs/xfs_bit.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_bit.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BIT_H__ +#define __XFS_BIT_H__ + +/* + * XFS bit manipulation routines. + */ + +/* + * masks with n high/low bits set, 32-bit values & 64-bit values + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MASK32HI) +__uint32_t xfs_mask32hi(int n); +#define XFS_MASK32HI(n) xfs_mask32hi(n) +#else +#define XFS_MASK32HI(n) ((__uint32_t)-1 << (32 - (n))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MASK64HI) +__uint64_t xfs_mask64hi(int n); +#define XFS_MASK64HI(n) xfs_mask64hi(n) +#else +#define XFS_MASK64HI(n) ((__uint64_t)-1 << (64 - (n))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MASK32LO) +__uint32_t xfs_mask32lo(int n); +#define XFS_MASK32LO(n) xfs_mask32lo(n) +#else +#define XFS_MASK32LO(n) (((__uint32_t)1 << (n)) - 1) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MASK64LO) +__uint64_t xfs_mask64lo(int n); +#define XFS_MASK64LO(n) xfs_mask64lo(n) +#else +#define XFS_MASK64LO(n) (((__uint64_t)1 << (n)) - 1) +#endif + +/* + * Index of low bit number in byte, -1 for none set, 0..7 otherwise. + */ +extern const char xfs_lowbit[256]; + +/* + * Index of high bit number in byte, -1 for none set, 0..7 otherwise. + */ +extern const char xfs_highbit[256]; + +/* + * Count of bits set in byte, 0..8. + */ +extern const char xfs_countbit[256]; + +/* + * xfs_lowbit32: get low bit set out of 32-bit argument, -1 if none set. + */ +extern int xfs_lowbit32(__uint32_t v); + +/* + * xfs_highbit32: get high bit set out of 32-bit argument, -1 if none set. + */ +extern int xfs_highbit32(__uint32_t v); + +/* + * xfs_lowbit64: get low bit set out of 64-bit argument, -1 if none set. + */ +extern int xfs_lowbit64(__uint64_t v); + +/* + * xfs_highbit64: get high bit set out of 64-bit argument, -1 if none set. + */ +extern int xfs_highbit64(__uint64_t); + +#endif /* __XFS_BIT_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_bmap.c linux-2.4-xfs/linux/fs/xfs/xfs_bmap.c --- linux-2.4.7/linux/fs/xfs/xfs_bmap.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_bmap.c Wed Apr 18 21:37:23 2001 @@ -0,0 +1,6255 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#ifdef DEBUG +ktrace_t *xfs_bmap_trace_buf; +#endif + +#ifdef XFSDEBUG +STATIC void +xfs_bmap_check_leaf_extents(xfs_btree_cur_t *cur, xfs_inode_t *ip, int whichfork); +#endif + +xfs_zone_t *xfs_bmap_free_item_zone; + +/* + * Prototypes for internal bmap routines. + */ + + +/* + * Called from xfs_bmap_add_attrfork to handle extents format files. + */ +STATIC int /* error */ +xfs_bmap_add_attrfork_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first block allocated */ + xfs_bmap_free_t *flist, /* blocks to free at commit */ + int *flags); /* inode logging flags */ + +/* + * Called from xfs_bmap_add_attrfork to handle local format files. + */ +STATIC int /* error */ +xfs_bmap_add_attrfork_local( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first block allocated */ + xfs_bmap_free_t *flist, /* blocks to free at commit */ + int *flags); /* inode logging flags */ + +/* + * Called by xfs_bmapi to update extent list structure and the btree + * after allocating space (or doing a delayed allocation). + */ +STATIC int /* error */ +xfs_bmap_add_extent( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + xfs_fsblock_t *first, /* pointer to firstblock variable */ + xfs_bmap_free_t *flist, /* list of extents to be freed */ + int *logflagsp, /* inode logging flags */ + int whichfork, /* data or attr fork */ + int rsvd); /* OK to allocate reserved blocks */ + +/* + * Called by xfs_bmap_add_extent to handle cases converting a delayed + * allocation to a real allocation. + */ +STATIC int /* error */ +xfs_bmap_add_extent_delay_real( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + xfs_filblks_t *dnew, /* new delayed-alloc indirect blocks */ + xfs_fsblock_t *first, /* pointer to firstblock variable */ + xfs_bmap_free_t *flist, /* list of extents to be freed */ + int *logflagsp, /* inode logging flags */ + int rsvd); /* OK to allocate reserved blocks */ + +/* + * Called by xfs_bmap_add_extent to handle cases converting a hole + * to a delayed allocation. + */ +STATIC int /* error */ +xfs_bmap_add_extent_hole_delay( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t *cur, /* if null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int *logflagsp,/* inode logging flags */ + int rsvd); /* OK to allocate reserved blocks */ + +/* + * Called by xfs_bmap_add_extent to handle cases converting a hole + * to a real allocation. + */ +STATIC int /* error */ +xfs_bmap_add_extent_hole_real( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t *cur, /* if null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int *logflagsp, /* inode logging flags */ + int whichfork); /* data or attr fork */ + +/* + * Called by xfs_bmap_add_extent to handle cases converting an unwritten + * allocation to a real allocation or vice versa. + */ +STATIC int /* error */ +xfs_bmap_add_extent_unwritten_real( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int *logflagsp); /* inode logging flags */ + +/* + * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. + * It figures out where to ask the underlying allocator to put the new extent. + */ +STATIC int /* error */ +xfs_bmap_alloc( + xfs_bmalloca_t *ap); /* bmap alloc argument struct */ + +/* + * Transform a btree format file with only one leaf node, where the + * extents list will fit in the inode, into an extents format file. + * Since the extent list is already in-core, all we have to do is + * give up the space for the btree root and pitch the leaf block. + */ +STATIC int /* error */ +xfs_bmap_btree_to_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_btree_cur_t *cur, /* btree cursor */ + int *logflagsp, /* inode logging flags */ + int whichfork, /* data or attr fork */ + int async); /* xaction can be async */ + +#ifdef XFSDEBUG +/* + * Check that the extents list for the inode ip is in the right order. + */ +STATIC void +xfs_bmap_check_extents( + xfs_inode_t *ip, /* incore inode pointer */ + int whichfork); /* data or attr fork */ +#else +#define xfs_bmap_check_extents(ip,w) +#endif + +/* + * Called by xfs_bmapi to update extent list structure and the btree + * after removing space (or undoing a delayed allocation). + */ +STATIC int /* error */ +xfs_bmap_del_extent( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_trans_t *tp, /* current trans pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_bmap_free_t *flist, /* list of extents to be freed */ + xfs_btree_cur_t *cur, /* if null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int iflags, /* input flags (meta-data or not) */ + int *logflagsp,/* inode logging flags */ + int whichfork, /* data or attr fork */ + int rsvd); /* OK to allocate reserved blocks */ + +/* + * Remove the entry "free" from the free item list. Prev points to the + * previous entry, unless "free" is the head of the list. + */ +STATIC void +xfs_bmap_del_free( + xfs_bmap_free_t *flist, /* free item list header */ + xfs_bmap_free_item_t *prev, /* previous item on list, if any */ + xfs_bmap_free_item_t *free); /* list item to be freed */ + +/* + * Remove count entries from the extents array for inode "ip", starting + * at index "idx". Copies the remaining items down over the deleted ones, + * and gives back the excess memory. + */ +STATIC void +xfs_bmap_delete_exlist( + xfs_inode_t *ip, /* incode inode pointer */ + xfs_extnum_t idx, /* starting delete index */ + xfs_extnum_t count, /* count of items to delete */ + int whichfork); /* data or attr fork */ + +/* + * Convert an extents-format file into a btree-format file. + * The new file will have a root block (in the inode) and a single child block. + */ +STATIC int /* error */ +xfs_bmap_extents_to_btree( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first-block-allocated */ + xfs_bmap_free_t *flist, /* blocks freed in xaction */ + xfs_btree_cur_t **curp, /* cursor returned to caller */ + int wasdel, /* converting a delayed alloc */ + int *logflagsp, /* inode logging flags */ + int whichfork); /* data or attr fork */ + +/* + * Insert new item(s) in the extent list for inode "ip". + * Count new items are inserted at offset idx. + */ +STATIC void +xfs_bmap_insert_exlist( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* starting index of new items */ + xfs_extnum_t count, /* number of inserted items */ + xfs_bmbt_irec_t *new, /* items to insert */ + int whichfork); /* data or attr fork */ + +/* + * Convert a local file to an extents file. + * This code is sort of bogus, since the file data needs to get + * logged so it won't be lost. The bmap-level manipulations are ok, though. + */ +STATIC int /* error */ +xfs_bmap_local_to_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first block allocated in xaction */ + xfs_extlen_t total, /* total blocks needed by transaction */ + int *logflagsp, /* inode logging flags */ + int whichfork); /* data or attr fork */ + +/* + * Search the extents list for the inode, for the extent containing bno. + * If bno lies in a hole, point to the next entry. If bno lies past eof, + * *eofp will be set, and *prevp will contain the last entry (null if none). + * Else, *lastxp will be set to the index of the found + * entry; *gotp will contain the entry. + */ +STATIC xfs_bmbt_rec_t * /* pointer to found extent entry */ +xfs_bmap_search_extents( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fileoff_t bno, /* block number searched for */ + int whichfork, /* data or attr fork */ + int *eofp, /* out: end of file found */ + xfs_extnum_t *lastxp, /* out: last extent index */ + xfs_bmbt_irec_t *gotp, /* out: extent entry found */ + xfs_bmbt_irec_t *prevp); /* out: previous extent entry found */ + +#ifdef XFS_BMAP_TRACE +/* + * Add a bmap trace buffer entry. Base routine for the others. + */ +STATIC void +xfs_bmap_trace_addentry( + int opcode, /* operation */ + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry(ies) */ + xfs_extnum_t cnt, /* count of entries, 1 or 2 */ + xfs_bmbt_rec_t *r1, /* first record */ + xfs_bmbt_rec_t *r2, /* second record or null */ + int whichfork); /* data or attr fork */ + +/* + * Add bmap trace entry prior to a call to xfs_bmap_delete_exlist. + */ +STATIC void +xfs_bmap_trace_delete( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry(entries) deleted */ + xfs_extnum_t cnt, /* count of entries deleted, 1 or 2 */ + int whichfork); /* data or attr fork */ + +/* + * Add bmap trace entry prior to a call to xfs_bmap_insert_exlist, or + * reading in the extents list from the disk (in the btree). + */ +STATIC void +xfs_bmap_trace_insert( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry(entries) inserted */ + xfs_extnum_t cnt, /* count of entries inserted, 1 or 2 */ + xfs_bmbt_irec_t *r1, /* inserted record 1 */ + xfs_bmbt_irec_t *r2, /* inserted record 2 or null */ + int whichfork); /* data or attr fork */ + +/* + * Add bmap trace entry after updating an extent list entry in place. + */ +STATIC void +xfs_bmap_trace_post_update( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry updated */ + int whichfork); /* data or attr fork */ + +/* + * Add bmap trace entry prior to updating an extent list entry in place. + */ +STATIC void +xfs_bmap_trace_pre_update( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry to be updated */ + int whichfork); /* data or attr fork */ + +#else +#define xfs_bmap_trace_delete(f,d,ip,i,c,w) +#define xfs_bmap_trace_insert(f,d,ip,i,c,r1,r2,w) +#define xfs_bmap_trace_post_update(f,d,ip,i,w) +#define xfs_bmap_trace_pre_update(f,d,ip,i,w) +#endif /* XFS_BMAP_TRACE */ + +/* + * Compute the worst-case number of indirect blocks that will be used + * for ip's delayed extent of length "len". + */ +STATIC xfs_filblks_t +xfs_bmap_worst_indlen( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_filblks_t len); /* delayed extent length */ + +#ifdef DEBUG +/* + * Perform various validation checks on the values being returned + * from xfs_bmapi(). + */ +STATIC void +xfs_bmap_validate_ret( + xfs_fileoff_t bno, + xfs_filblks_t len, + int flags, + xfs_bmbt_irec_t *mval, + int nmap, + int ret_nmap); +#else +#define xfs_bmap_validate_ret(bno,len,flags,mval,onmap,nmap) +#endif /* DEBUG */ + +#if defined(DEBUG) && defined(XFS_RW_TRACE) +STATIC void +xfs_bunmap_trace( + xfs_inode_t *ip, + xfs_fileoff_t bno, + xfs_filblks_t len, + int flags, + inst_t *ra); +#else +#define xfs_bunmap_trace(ip, bno, len, flags, ra) +#endif /* DEBUG && XFS_RW_TRACE */ + +STATIC int +xfs_bmap_count_tree( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_fsblock_t blockno, + int levelin, + int *count); + +STATIC int +xfs_bmap_count_leaves( + xfs_bmbt_rec_t *frp, + int numrecs, + int *count); + +/* + * Bmap internal routines. + */ + +/* + * Called from xfs_bmap_add_attrfork to handle btree format files. + */ +STATIC int /* error */ +xfs_bmap_add_attrfork_btree( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first block allocated */ + xfs_bmap_free_t *flist, /* blocks to free at commit */ + int *flags) /* inode logging flags */ +{ + xfs_btree_cur_t *cur; /* btree cursor */ + int error; /* error return value */ + xfs_mount_t *mp; /* file system mount struct */ + int stat; /* newroot status */ + + mp = ip->i_mount; + if (ip->i_df.if_broot_bytes <= XFS_IFORK_DSIZE(ip)) + *flags |= XFS_ILOG_DBROOT; + else { + cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip, + XFS_DATA_FORK); + cur->bc_private.b.flist = flist; + cur->bc_private.b.firstblock = *firstblock; + if ((error = xfs_bmbt_lookup_ge(cur, 0, 0, 0, &stat))) + goto error0; + ASSERT(stat == 1); /* must be at least one entry */ + if ((error = xfs_bmbt_newroot(cur, flags, &stat))) + goto error0; + if (stat == 0) { + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + return XFS_ERROR(ENOSPC); + } + *firstblock = cur->bc_private.b.firstblock; + cur->bc_private.b.allocated = 0; + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + } + return 0; +error0: + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Called from xfs_bmap_add_attrfork to handle extents format files. + */ +STATIC int /* error */ +xfs_bmap_add_attrfork_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first block allocated */ + xfs_bmap_free_t *flist, /* blocks to free at commit */ + int *flags) /* inode logging flags */ +{ + xfs_btree_cur_t *cur; /* bmap btree cursor */ + int error; /* error return value */ + + if (ip->i_d.di_nextents * sizeof(xfs_bmbt_rec_t) <= XFS_IFORK_DSIZE(ip)) + return 0; + cur = NULL; + error = xfs_bmap_extents_to_btree(tp, ip, firstblock, flist, &cur, 0, + flags, XFS_DATA_FORK); + if (cur) { + cur->bc_private.b.allocated = 0; + xfs_btree_del_cursor(cur, + error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); + } + return error; +} + +/* + * Called from xfs_bmap_add_attrfork to handle local format files. + */ +STATIC int /* error */ +xfs_bmap_add_attrfork_local( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first block allocated */ + xfs_bmap_free_t *flist, /* blocks to free at commit */ + int *flags) /* inode logging flags */ +{ + xfs_da_args_t dargs; /* args for dir/attr code */ + int error; /* error return value */ + xfs_mount_t *mp; /* mount structure pointer */ + + if (ip->i_df.if_bytes <= XFS_IFORK_DSIZE(ip)) + return 0; + if ((ip->i_d.di_mode & IFMT) == IFDIR) { + mp = ip->i_mount; + bzero(&dargs, sizeof(dargs)); + dargs.dp = ip; + dargs.firstblock = firstblock; + dargs.flist = flist; + dargs.total = mp->m_dirblkfsbs; + dargs.whichfork = XFS_DATA_FORK; + dargs.trans = tp; + error = XFS_DIR_SHORTFORM_TO_SINGLE(mp, &dargs); + } else + error = xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags, + XFS_DATA_FORK); + return error; +} + +/* + * Called by xfs_bmapi to update extent list structure and the btree + * after allocating space (or doing a delayed allocation). + */ +STATIC int /* error */ +xfs_bmap_add_extent( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + xfs_fsblock_t *first, /* pointer to firstblock variable */ + xfs_bmap_free_t *flist, /* list of extents to be freed */ + int *logflagsp, /* inode logging flags */ + int whichfork, /* data or attr fork */ + int rsvd) /* OK to use reserved data blocks */ +{ + xfs_btree_cur_t *cur; /* btree cursor or null */ + xfs_filblks_t da_new; /* new count del alloc blocks used */ + xfs_filblks_t da_old; /* old count del alloc blocks used */ + int error; /* error return value */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_add_extent"; +#endif + xfs_ifork_t *ifp; /* inode fork ptr */ + int logflags; /* returned value */ + xfs_extnum_t nextents; /* number of extents in file now */ + + XFS_STATS_INC(xfsstats.xs_add_exlist); + cur = *curp; + ifp = XFS_IFORK_PTR(ip, whichfork); + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + ASSERT(idx <= nextents); + da_old = da_new = 0; + error = 0; + /* + * This is the first extent added to a new/empty file. + * Special case this one, so other routines get to assume there are + * already extents in the list. + */ + if (nextents == 0) { + xfs_bmap_trace_insert(fname, "insert empty", ip, 0, 1, new, + NULL, whichfork); + xfs_bmap_insert_exlist(ip, 0, 1, new, whichfork); + ASSERT(cur == NULL); + ifp->if_lastex = 0; + if (!ISNULLSTARTBLOCK(new->br_startblock)) { + XFS_IFORK_NEXT_SET(ip, whichfork, 1); + logflags = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); + } else + logflags = 0; + } + /* + * Any kind of new delayed allocation goes here. + */ + else if (ISNULLSTARTBLOCK(new->br_startblock)) { + if (cur) + ASSERT((cur->bc_private.b.flags & + XFS_BTCUR_BPRV_WASDEL) == 0); + if ((error = xfs_bmap_add_extent_hole_delay(ip, idx, cur, new, + &logflags, rsvd))) + goto done; + } + /* + * Real allocation off the end of the file. + */ + else if (idx == nextents) { + if (cur) + ASSERT((cur->bc_private.b.flags & + XFS_BTCUR_BPRV_WASDEL) == 0); + if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new, + &logflags, whichfork))) + goto done; + } else { + xfs_bmbt_irec_t prev; /* old extent at offset idx */ + + /* + * Get the record referred to by idx. + */ + xfs_bmbt_get_all(&ifp->if_u1.if_extents[idx], &prev); + /* + * If it's a real allocation record, and the new allocation ends + * after the start of the referred to record, then we're filling + * in a delayed or unwritten allocation with a real one, or + * converting real back to unwritten. + */ + if (!ISNULLSTARTBLOCK(new->br_startblock) && + new->br_startoff + new->br_blockcount > prev.br_startoff) { + if (prev.br_state != XFS_EXT_UNWRITTEN && + ISNULLSTARTBLOCK(prev.br_startblock)) { + da_old = STARTBLOCKVAL(prev.br_startblock); + if (cur) + ASSERT(cur->bc_private.b.flags & + XFS_BTCUR_BPRV_WASDEL); + if ((error = xfs_bmap_add_extent_delay_real(ip, + idx, &cur, new, &da_new, first, flist, + &logflags, rsvd))) + goto done; + } else if (new->br_state == XFS_EXT_NORM) { + ASSERT(new->br_state == XFS_EXT_NORM); + if ((error = xfs_bmap_add_extent_unwritten_real( + ip, idx, &cur, new, &logflags))) + goto done; + } else { + ASSERT(new->br_state == XFS_EXT_UNWRITTEN); + if ((error = xfs_bmap_add_extent_unwritten_real( + ip, idx, &cur, new, &logflags))) + goto done; + } + ASSERT(*curp == cur || *curp == NULL); + } + /* + * Otherwise we're filling in a hole with an allocation. + */ + else { + if (cur) + ASSERT((cur->bc_private.b.flags & + XFS_BTCUR_BPRV_WASDEL) == 0); + if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, + new, &logflags, whichfork))) + goto done; + } + } + + ASSERT(*curp == cur || *curp == NULL); + /* + * Convert to a btree if necessary. + */ + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) { + int tmp_logflags; /* partial log flag return val */ + + ASSERT(cur == NULL); + error = xfs_bmap_extents_to_btree(ip->i_transp, ip, first, + flist, &cur, da_old > 0, &tmp_logflags, whichfork); + logflags |= tmp_logflags; + if (error) + goto done; + } + /* + * Adjust for changes in reserved delayed indirect blocks. + * Nothing to do for disk quotas here. + */ + if (da_old || da_new) { + xfs_filblks_t nblks; + + nblks = da_new; + if (cur) + nblks += cur->bc_private.b.allocated; + ASSERT(nblks <= da_old); + if (nblks < da_old) + xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS, + (int)(da_old - nblks), rsvd); + } + /* + * Clear out the allocated field, done with it now in any case. + */ + if (cur) { + cur->bc_private.b.allocated = 0; + *curp = cur; + } +done: +#ifdef XFSDEBUG + if (!error) + xfs_bmap_check_leaf_extents(*curp, ip, whichfork); +#endif + *logflagsp = logflags; + return error; +} + +/* + * Called by xfs_bmap_add_extent to handle cases converting a delayed + * allocation to a real allocation. + */ +STATIC int /* error */ +xfs_bmap_add_extent_delay_real( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + xfs_filblks_t *dnew, /* new delayed-alloc indirect blocks */ + xfs_fsblock_t *first, /* pointer to firstblock variable */ + xfs_bmap_free_t *flist, /* list of extents to be freed */ + int *logflagsp, /* inode logging flags */ + int rsvd) /* OK to use reserved data block allocation */ +{ + xfs_bmbt_rec_t *base; /* base of extent entry list */ + xfs_btree_cur_t *cur; /* btree cursor */ + int diff; /* temp value */ + xfs_bmbt_rec_t *ep; /* extent entry for idx */ + int error; /* error return value */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_add_extent_delay_real"; +#endif + int i; /* temp state */ + xfs_fileoff_t new_endoff; /* end offset of new entry */ + xfs_bmbt_irec_t r[3]; /* neighbor extent entries */ + /* left is 0, right is 1, prev is 2 */ + int rval=0; /* return value (logging flags) */ + int state = 0;/* state bits, accessed thru macros */ + xfs_filblks_t temp; /* value for dnew calculations */ + xfs_filblks_t temp2; /* value for dnew calculations */ + int tmp_rval; /* partial logging flags */ + enum { /* bit number definitions for state */ + LEFT_CONTIG, RIGHT_CONTIG, + LEFT_FILLING, RIGHT_FILLING, + LEFT_DELAY, RIGHT_DELAY, + LEFT_VALID, RIGHT_VALID + }; + +#define LEFT r[0] +#define RIGHT r[1] +#define PREV r[2] +#define MASK(b) (1 << (b)) +#define MASK2(a,b) (MASK(a) | MASK(b)) +#define MASK3(a,b,c) (MASK2(a,b) | MASK(c)) +#define MASK4(a,b,c,d) (MASK3(a,b,c) | MASK(d)) +#define STATE_SET(b,v) ((v) ? (state |= MASK(b)) : (state &= ~MASK(b))) +#define STATE_TEST(b) (state & MASK(b)) +#define STATE_SET_TEST(b,v) ((v) ? ((state |= MASK(b)), 1) : \ + ((state &= ~MASK(b)), 0)) +#define SWITCH_STATE \ + (state & MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG)) + + /* + * Set up a bunch of variables to make the tests simpler. + */ + cur = *curp; + base = ip->i_df.if_u1.if_extents; + ep = &base[idx]; + xfs_bmbt_get_all(ep, &PREV); + new_endoff = new->br_startoff + new->br_blockcount; + ASSERT(PREV.br_startoff <= new->br_startoff); + ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff); + /* + * Set flags determining what part of the previous delayed allocation + * extent is being replaced by a real allocation. + */ + STATE_SET(LEFT_FILLING, PREV.br_startoff == new->br_startoff); + STATE_SET(RIGHT_FILLING, + PREV.br_startoff + PREV.br_blockcount == new_endoff); + /* + * Check and set flags if this segment has a left neighbor. + * Don't set contiguous if the combined extent would be too large. + */ + if (STATE_SET_TEST(LEFT_VALID, idx > 0)) { + xfs_bmbt_get_all(ep - 1, &LEFT); + STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(LEFT.br_startblock)); + } + STATE_SET(LEFT_CONTIG, + STATE_TEST(LEFT_VALID) && !STATE_TEST(LEFT_DELAY) && + LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff && + LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock && + LEFT.br_state == new->br_state && + LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN); + /* + * Check and set flags if this segment has a right neighbor. + * Don't set contiguous if the combined extent would be too large. + * Also check for all-three-contiguous being too large. + */ + if (STATE_SET_TEST(RIGHT_VALID, + idx < + ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1)) { + xfs_bmbt_get_all(ep + 1, &RIGHT); + STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(RIGHT.br_startblock)); + } + STATE_SET(RIGHT_CONTIG, + STATE_TEST(RIGHT_VALID) && !STATE_TEST(RIGHT_DELAY) && + new_endoff == RIGHT.br_startoff && + new->br_startblock + new->br_blockcount == + RIGHT.br_startblock && + new->br_state == RIGHT.br_state && + new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN && + ((state & MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING)) != + MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING) || + LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount + <= MAXEXTLEN)); + error = 0; + /* + * Switch out based on the FILLING and CONTIG state bits. + */ + switch (SWITCH_STATE) { + + case MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + /* + * Filling in all of a previously delayed allocation extent. + * The left and right neighbors are both contiguous with new. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + PREV.br_blockcount + + RIGHT.br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|RF|LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmap_trace_delete(fname, "LF|RF|LC|RC", ip, idx, 2, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx, 2, XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + ip->i_d.di_nextents--; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, + RIGHT.br_startblock, + RIGHT.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + + PREV.br_blockcount + + RIGHT.br_blockcount, LEFT.br_state))) + goto done; + } + *dnew = 0; + break; + + case MASK3(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG): + /* + * Filling in all of a previously delayed allocation extent. + * The left neighbor is contiguous, the right is not. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + PREV.br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|RF|LC", ip, idx - 1, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + xfs_bmap_trace_delete(fname, "LF|RF|LC", ip, idx, 1, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx, 1, XFS_DATA_FORK); + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, LEFT.br_startoff, + LEFT.br_startblock, LEFT.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + + PREV.br_blockcount, LEFT.br_state))) + goto done; + } + *dnew = 0; + break; + + case MASK3(LEFT_FILLING, RIGHT_FILLING, RIGHT_CONTIG): + /* + * Filling in all of a previously delayed allocation extent. + * The right neighbor is contiguous, the left is not. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|RC", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_startblock(ep, new->br_startblock); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount + RIGHT.br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|RF|RC", ip, idx, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + xfs_bmap_trace_delete(fname, "LF|RF|RC", ip, idx + 1, 1, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx + 1, 1, XFS_DATA_FORK); + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, + RIGHT.br_startblock, + RIGHT.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, PREV.br_startoff, + new->br_startblock, + PREV.br_blockcount + + RIGHT.br_blockcount, PREV.br_state))) + goto done; + } + *dnew = 0; + break; + + case MASK2(LEFT_FILLING, RIGHT_FILLING): + /* + * Filling in all of a previously delayed allocation extent. + * Neither the left nor right neighbors are contiguous with + * the new one. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_startblock(ep, new->br_startblock); + xfs_bmap_trace_post_update(fname, "LF|RF", ip, idx, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 0); + cur->bc_rec.b.br_state = XFS_EXT_NORM; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + *dnew = 0; + break; + + case MASK2(LEFT_FILLING, LEFT_CONTIG): + /* + * Filling in the first part of a previous delayed allocation. + * The left neighbor is contiguous. + */ + xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + new->br_blockcount); + xfs_bmbt_set_startoff(ep, + PREV.br_startoff + new->br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx - 1, + XFS_DATA_FORK); + temp = PREV.br_blockcount - new->br_blockcount; + xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, temp); + ip->i_df.if_lastex = idx - 1; + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, LEFT.br_startoff, + LEFT.br_startblock, LEFT.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + + new->br_blockcount, + LEFT.br_state))) + goto done; + } + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + STARTBLOCKVAL(PREV.br_startblock)); + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx, + XFS_DATA_FORK); + *dnew = temp; + break; + + case MASK(LEFT_FILLING): + /* + * Filling in the first part of a previous delayed allocation. + * The left neighbor is not contiguous. + */ + xfs_bmap_trace_pre_update(fname, "LF", ip, idx, XFS_DATA_FORK); + xfs_bmbt_set_startoff(ep, new_endoff); + temp = PREV.br_blockcount - new->br_blockcount; + xfs_bmbt_set_blockcount(ep, temp); + xfs_bmap_trace_insert(fname, "LF", ip, idx, 1, new, NULL, + XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx, 1, new, XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 0); + cur->bc_rec.b.br_state = XFS_EXT_NORM; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && + ip->i_d.di_nextents > ip->i_df.if_ext_max) { + error = xfs_bmap_extents_to_btree(ip->i_transp, ip, + first, flist, &cur, 1, &tmp_rval, + XFS_DATA_FORK); + rval |= tmp_rval; + if (error) + goto done; + } + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + STARTBLOCKVAL(PREV.br_startblock) - + (cur ? cur->bc_private.b.allocated : 0)); + base = ip->i_df.if_u1.if_extents; + ep = &base[idx + 1]; + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "LF", ip, idx + 1, + XFS_DATA_FORK); + *dnew = temp; + break; + + case MASK2(RIGHT_FILLING, RIGHT_CONTIG): + /* + * Filling in the last part of a previous delayed allocation. + * The right neighbor is contiguous with the new allocation. + */ + temp = PREV.br_blockcount - new->br_blockcount; + xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx, + XFS_DATA_FORK); + xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx + 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, temp); + xfs_bmbt_set_allf(ep + 1, new->br_startoff, new->br_startblock, + new->br_blockcount + RIGHT.br_blockcount, + RIGHT.br_state); + xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx + 1, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, + RIGHT.br_startblock, + RIGHT.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, new->br_startoff, + new->br_startblock, + new->br_blockcount + + RIGHT.br_blockcount, + RIGHT.br_state))) + goto done; + } + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + STARTBLOCKVAL(PREV.br_startblock)); + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx, + XFS_DATA_FORK); + *dnew = temp; + break; + + case MASK(RIGHT_FILLING): + /* + * Filling in the last part of a previous delayed allocation. + * The right neighbor is not contiguous. + */ + temp = PREV.br_blockcount - new->br_blockcount; + xfs_bmap_trace_pre_update(fname, "RF", ip, idx, XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, temp); + xfs_bmap_trace_insert(fname, "RF", ip, idx + 1, 1, + new, NULL, XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx + 1, 1, new, XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 0); + cur->bc_rec.b.br_state = XFS_EXT_NORM; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && + ip->i_d.di_nextents > ip->i_df.if_ext_max) { + error = xfs_bmap_extents_to_btree(ip->i_transp, ip, + first, flist, &cur, 1, &tmp_rval, + XFS_DATA_FORK); + rval |= tmp_rval; + if (error) + goto done; + } + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + STARTBLOCKVAL(PREV.br_startblock) - + (cur ? cur->bc_private.b.allocated : 0)); + base = ip->i_df.if_u1.if_extents; + ep = &base[idx]; + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "RF", ip, idx, XFS_DATA_FORK); + *dnew = temp; + break; + + case 0: + /* + * Filling in the middle part of a previous delayed allocation. + * Contiguity is impossible here. + * This case is avoided almost all the time. + */ + temp = new->br_startoff - PREV.br_startoff; + xfs_bmap_trace_pre_update(fname, "0", ip, idx, XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, temp); + r[0] = *new; + r[1].br_startoff = new_endoff; + temp2 = PREV.br_startoff + PREV.br_blockcount - new_endoff; + r[1].br_blockcount = temp2; + xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 2, &r[0], &r[1], + XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx + 1, 2, &r[0], XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 0); + cur->bc_rec.b.br_state = XFS_EXT_NORM; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && + ip->i_d.di_nextents > ip->i_df.if_ext_max) { + error = xfs_bmap_extents_to_btree(ip->i_transp, ip, + first, flist, &cur, 1, &tmp_rval, + XFS_DATA_FORK); + rval |= tmp_rval; + if (error) + goto done; + } + temp = xfs_bmap_worst_indlen(ip, temp); + temp2 = xfs_bmap_worst_indlen(ip, temp2); + diff = (int)(temp + temp2 - STARTBLOCKVAL(PREV.br_startblock) - + (cur ? cur->bc_private.b.allocated : 0)); + if (diff > 0 && + xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS, -diff, rsvd)) { + /* + * Ick gross gag me with a spoon. + */ + ASSERT(0); /* want to see if this ever happens! */ + while (diff > 0) { + if (temp) { + temp--; + diff--; + if (!diff || + !xfs_mod_incore_sb(ip->i_mount, + XFS_SBS_FDBLOCKS, -diff, rsvd)) + break; + } + if (temp2) { + temp2--; + diff--; + if (!diff || + !xfs_mod_incore_sb(ip->i_mount, + XFS_SBS_FDBLOCKS, -diff, rsvd)) + break; + } + } + } + base = ip->i_df.if_u1.if_extents; + ep = &base[idx]; + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "0", ip, idx, XFS_DATA_FORK); + xfs_bmap_trace_pre_update(fname, "0", ip, idx + 2, + XFS_DATA_FORK); + xfs_bmbt_set_startblock(ep + 2, NULLSTARTBLOCK((int)temp2)); + xfs_bmap_trace_post_update(fname, "0", ip, idx + 2, + XFS_DATA_FORK); + *dnew = temp + temp2; + break; + + case MASK3(LEFT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + case MASK3(RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + case MASK2(LEFT_FILLING, RIGHT_CONTIG): + case MASK2(RIGHT_FILLING, LEFT_CONTIG): + case MASK2(LEFT_CONTIG, RIGHT_CONTIG): + case MASK(LEFT_CONTIG): + case MASK(RIGHT_CONTIG): + /* + * These cases are all impossible. + */ + ASSERT(0); + } + *curp = cur; +done: + *logflagsp = rval; + return error; +#undef LEFT +#undef RIGHT +#undef PREV +#undef MASK +#undef MASK2 +#undef MASK3 +#undef MASK4 +#undef STATE_SET +#undef STATE_TEST +#undef STATE_SET_TEST +#undef SWITCH_STATE +} + +/* + * Called by xfs_bmap_add_extent to handle cases converting an unwritten + * allocation to a real allocation or vice versa. + */ +STATIC int /* error */ +xfs_bmap_add_extent_unwritten_real( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int *logflagsp) /* inode logging flags */ +{ + xfs_bmbt_rec_t *base; /* base of extent entry list */ + xfs_btree_cur_t *cur; /* btree cursor */ + xfs_bmbt_rec_t *ep; /* extent entry for idx */ + int error; /* error return value */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_add_extent_unwritten_real"; +#endif + int i; /* temp state */ + xfs_fileoff_t new_endoff; /* end offset of new entry */ + xfs_exntst_t newext; /* new extent state */ + xfs_exntst_t oldext; /* old extent state */ + xfs_bmbt_irec_t r[3]; /* neighbor extent entries */ + /* left is 0, right is 1, prev is 2 */ + int rval=0; /* return value (logging flags) */ + int state = 0;/* state bits, accessed thru macros */ + enum { /* bit number definitions for state */ + LEFT_CONTIG, RIGHT_CONTIG, + LEFT_FILLING, RIGHT_FILLING, + LEFT_DELAY, RIGHT_DELAY, + LEFT_VALID, RIGHT_VALID + }; + +#define LEFT r[0] +#define RIGHT r[1] +#define PREV r[2] +#define MASK(b) (1 << (b)) +#define MASK2(a,b) (MASK(a) | MASK(b)) +#define MASK3(a,b,c) (MASK2(a,b) | MASK(c)) +#define MASK4(a,b,c,d) (MASK3(a,b,c) | MASK(d)) +#define STATE_SET(b,v) ((v) ? (state |= MASK(b)) : (state &= ~MASK(b))) +#define STATE_TEST(b) (state & MASK(b)) +#define STATE_SET_TEST(b,v) ((v) ? ((state |= MASK(b)), 1) : \ + ((state &= ~MASK(b)), 0)) +#define SWITCH_STATE \ + (state & MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG)) + + /* + * Set up a bunch of variables to make the tests simpler. + */ + error = 0; + cur = *curp; + base = ip->i_df.if_u1.if_extents; + ep = &base[idx]; + xfs_bmbt_get_all(ep, &PREV); + newext = new->br_state; + oldext = (newext == XFS_EXT_UNWRITTEN) ? + XFS_EXT_NORM : XFS_EXT_UNWRITTEN; + ASSERT(PREV.br_state == oldext); + new_endoff = new->br_startoff + new->br_blockcount; + ASSERT(PREV.br_startoff <= new->br_startoff); + ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff); + /* + * Set flags determining what part of the previous oldext allocation + * extent is being replaced by a newext allocation. + */ + STATE_SET(LEFT_FILLING, PREV.br_startoff == new->br_startoff); + STATE_SET(RIGHT_FILLING, + PREV.br_startoff + PREV.br_blockcount == new_endoff); + /* + * Check and set flags if this segment has a left neighbor. + * Don't set contiguous if the combined extent would be too large. + */ + if (STATE_SET_TEST(LEFT_VALID, idx > 0)) { + xfs_bmbt_get_all(ep - 1, &LEFT); + STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(LEFT.br_startblock)); + } + STATE_SET(LEFT_CONTIG, + STATE_TEST(LEFT_VALID) && !STATE_TEST(LEFT_DELAY) && + LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff && + LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock && + LEFT.br_state == newext && + LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN); + /* + * Check and set flags if this segment has a right neighbor. + * Don't set contiguous if the combined extent would be too large. + * Also check for all-three-contiguous being too large. + */ + if (STATE_SET_TEST(RIGHT_VALID, + idx < + ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1)) { + xfs_bmbt_get_all(ep + 1, &RIGHT); + STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(RIGHT.br_startblock)); + } + STATE_SET(RIGHT_CONTIG, + STATE_TEST(RIGHT_VALID) && !STATE_TEST(RIGHT_DELAY) && + new_endoff == RIGHT.br_startoff && + new->br_startblock + new->br_blockcount == + RIGHT.br_startblock && + newext == RIGHT.br_state && + new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN && + ((state & MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING)) != + MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING) || + LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount + <= MAXEXTLEN)); + /* + * Switch out based on the FILLING and CONTIG state bits. + */ + switch (SWITCH_STATE) { + + case MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + /* + * Setting all of a previous oldext extent to newext. + * The left and right neighbors are both contiguous with new. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + PREV.br_blockcount + + RIGHT.br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|RF|LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmap_trace_delete(fname, "LF|RF|LC|RC", ip, idx, 2, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx, 2, XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + ip->i_d.di_nextents -= 2; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, + RIGHT.br_startblock, + RIGHT.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + PREV.br_blockcount + + RIGHT.br_blockcount, LEFT.br_state))) + goto done; + } + break; + + case MASK3(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG): + /* + * Setting all of a previous oldext extent to newext. + * The left neighbor is contiguous, the right is not. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + PREV.br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|RF|LC", ip, idx - 1, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + xfs_bmap_trace_delete(fname, "LF|RF|LC", ip, idx, 1, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx, 1, XFS_DATA_FORK); + ip->i_d.di_nextents--; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, PREV.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + PREV.br_blockcount, + LEFT.br_state))) + goto done; + } + break; + + case MASK3(LEFT_FILLING, RIGHT_FILLING, RIGHT_CONTIG): + /* + * Setting all of a previous oldext extent to newext. + * The right neighbor is contiguous, the left is not. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF|RC", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount + RIGHT.br_blockcount); + xfs_bmbt_set_state(ep, newext); + xfs_bmap_trace_post_update(fname, "LF|RF|RC", ip, idx, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + xfs_bmap_trace_delete(fname, "LF|RF|RC", ip, idx + 1, 1, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx + 1, 1, XFS_DATA_FORK); + ip->i_d.di_nextents--; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, + RIGHT.br_startblock, + RIGHT.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, new->br_startoff, + new->br_startblock, + new->br_blockcount + RIGHT.br_blockcount, + newext))) + goto done; + } + break; + + case MASK2(LEFT_FILLING, RIGHT_FILLING): + /* + * Setting all of a previous oldext extent to newext. + * Neither the left nor right neighbors are contiguous with + * the new one. + */ + xfs_bmap_trace_pre_update(fname, "LF|RF", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_state(ep, newext); + xfs_bmap_trace_post_update(fname, "LF|RF", ip, idx, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + newext))) + goto done; + } + break; + + case MASK2(LEFT_FILLING, LEFT_CONTIG): + /* + * Setting the first part of a previous oldext extent to newext. + * The left neighbor is contiguous. + */ + xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, + LEFT.br_blockcount + new->br_blockcount); + xfs_bmbt_set_startoff(ep, + PREV.br_startoff + new->br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_startblock(ep, + new->br_startblock + new->br_blockcount); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount - new->br_blockcount); + xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, PREV.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, + PREV.br_startoff + new->br_blockcount, + PREV.br_startblock + new->br_blockcount, + PREV.br_blockcount - new->br_blockcount, + oldext))) + goto done; + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + goto done; + if (xfs_bmbt_update(cur, LEFT.br_startoff, + LEFT.br_startblock, + LEFT.br_blockcount + new->br_blockcount, + LEFT.br_state)) + goto done; + } + break; + + case MASK(LEFT_FILLING): + /* + * Setting the first part of a previous oldext extent to newext. + * The left neighbor is not contiguous. + */ + xfs_bmap_trace_pre_update(fname, "LF", ip, idx, XFS_DATA_FORK); + ASSERT(ep && xfs_bmbt_get_state(ep) == oldext); + xfs_bmbt_set_startoff(ep, new_endoff); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount - new->br_blockcount); + xfs_bmbt_set_startblock(ep, + new->br_startblock + new->br_blockcount); + xfs_bmap_trace_post_update(fname, "LF", ip, idx, XFS_DATA_FORK); + xfs_bmap_trace_insert(fname, "LF", ip, idx, 1, new, NULL, + XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx, 1, new, XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, PREV.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, + PREV.br_startoff + new->br_blockcount, + PREV.br_startblock + new->br_blockcount, + PREV.br_blockcount - new->br_blockcount, + oldext))) + goto done; + cur->bc_rec.b = *new; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + break; + + case MASK2(RIGHT_FILLING, RIGHT_CONTIG): + /* + * Setting the last part of a previous oldext extent to newext. + * The right neighbor is contiguous with the new allocation. + */ + xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx, + XFS_DATA_FORK); + xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx + 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount - new->br_blockcount); + xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx, + XFS_DATA_FORK); + xfs_bmbt_set_allf(ep + 1, new->br_startoff, new->br_startblock, + new->br_blockcount + RIGHT.br_blockcount, newext); + xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx + 1, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + if (cur == NULL) + rval = XFS_ILOG_DEXT; + else { + rval = 0; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, + PREV.br_blockcount, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, PREV.br_startoff, + PREV.br_startblock, + PREV.br_blockcount - new->br_blockcount, + oldext))) + goto done; + if ((error = xfs_bmbt_increment(cur, 0, &i))) + goto done; + if ((error = xfs_bmbt_update(cur, new->br_startoff, + new->br_startblock, + new->br_blockcount + RIGHT.br_blockcount, + newext))) + goto done; + } + break; + + case MASK(RIGHT_FILLING): + /* + * Setting the last part of a previous oldext extent to newext. + * The right neighbor is not contiguous. + */ + xfs_bmap_trace_pre_update(fname, "RF", ip, idx, XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, + PREV.br_blockcount - new->br_blockcount); + xfs_bmap_trace_post_update(fname, "RF", ip, idx, XFS_DATA_FORK); + xfs_bmap_trace_insert(fname, "RF", ip, idx + 1, 1, + new, NULL, XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx + 1, 1, new, XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + ip->i_d.di_nextents++; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, PREV.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_update(cur, PREV.br_startoff, + PREV.br_startblock, + PREV.br_blockcount - new->br_blockcount, + oldext))) + goto done; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, + &i))) + goto done; + ASSERT(i == 0); + cur->bc_rec.b.br_state = XFS_EXT_NORM; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + break; + + case 0: + /* + * Setting the middle part of a previous oldext extent to + * newext. Contiguity is impossible here. + * One extent becomes three extents. + */ + xfs_bmap_trace_pre_update(fname, "0", ip, idx, XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep, + new->br_startoff - PREV.br_startoff); + xfs_bmap_trace_post_update(fname, "0", ip, idx, XFS_DATA_FORK); + r[0] = *new; + r[1].br_startoff = new_endoff; + r[1].br_blockcount = + PREV.br_startoff + PREV.br_blockcount - new_endoff; + r[1].br_startblock = new->br_startblock + new->br_blockcount; + r[1].br_state = oldext; + xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 2, &r[0], &r[1], + XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx + 1, 2, &r[0], XFS_DATA_FORK); + ip->i_df.if_lastex = idx + 1; + ip->i_d.di_nextents += 2; + if (cur == NULL) + rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; + else { + rval = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, + PREV.br_startblock, PREV.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + /* new right extent - oldext */ + if ((error = xfs_bmbt_update(cur, r[1].br_startoff, + r[1].br_startblock, r[1].br_blockcount, + r[1].br_state))) + goto done; + /* new left extent - oldext */ + PREV.br_blockcount = + new->br_startoff - PREV.br_startoff; + cur->bc_rec.b = PREV; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + if ((error = xfs_bmbt_increment(cur, 0, &i))) + goto done; + ASSERT(i == 1); + /* new middle extent - newext */ + cur->bc_rec.b = *new; + if ((error = xfs_bmbt_insert(cur, &i))) + goto done; + ASSERT(i == 1); + } + break; + + case MASK3(LEFT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + case MASK3(RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG): + case MASK2(LEFT_FILLING, RIGHT_CONTIG): + case MASK2(RIGHT_FILLING, LEFT_CONTIG): + case MASK2(LEFT_CONTIG, RIGHT_CONTIG): + case MASK(LEFT_CONTIG): + case MASK(RIGHT_CONTIG): + /* + * These cases are all impossible. + */ + ASSERT(0); + } + *curp = cur; +done: + *logflagsp = rval; + return error; +#undef LEFT +#undef RIGHT +#undef PREV +#undef MASK +#undef MASK2 +#undef MASK3 +#undef MASK4 +#undef STATE_SET +#undef STATE_TEST +#undef STATE_SET_TEST +#undef SWITCH_STATE +} + +/* + * Called by xfs_bmap_add_extent to handle cases converting a hole + * to a delayed allocation. + */ +/*ARGSUSED*/ +STATIC int /* error */ +xfs_bmap_add_extent_hole_delay( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t *cur, /* if null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int *logflagsp, /* inode logging flags */ + int rsvd) /* OK to allocate reserved blocks */ +{ + xfs_bmbt_rec_t *base; /* base of extent entry list */ + xfs_bmbt_rec_t *ep; /* extent list entry for idx */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_add_extent_hole_delay"; +#endif + xfs_bmbt_irec_t left; /* left neighbor extent entry */ + xfs_filblks_t newlen=0; /* new indirect size */ + xfs_filblks_t oldlen=0; /* old indirect size */ + xfs_bmbt_irec_t right; /* right neighbor extent entry */ + int state; /* state bits, accessed thru macros */ + xfs_filblks_t temp; /* temp for indirect calculations */ + enum { /* bit number definitions for state */ + LEFT_CONTIG, RIGHT_CONTIG, + LEFT_DELAY, RIGHT_DELAY, + LEFT_VALID, RIGHT_VALID + }; + +#define MASK(b) (1 << (b)) +#define MASK2(a,b) (MASK(a) | MASK(b)) +#define STATE_SET(b,v) ((v) ? (state |= MASK(b)) : (state &= ~MASK(b))) +#define STATE_TEST(b) (state & MASK(b)) +#define STATE_SET_TEST(b,v) ((v) ? ((state |= MASK(b)), 1) : \ + ((state &= ~MASK(b)), 0)) +#define SWITCH_STATE (state & MASK2(LEFT_CONTIG, RIGHT_CONTIG)) + + base = ip->i_df.if_u1.if_extents; + ep = &base[idx]; + state = 0; + ASSERT(ISNULLSTARTBLOCK(new->br_startblock)); + /* + * Check and set flags if this segment has a left neighbor + */ + if (STATE_SET_TEST(LEFT_VALID, idx > 0)) { + xfs_bmbt_get_all(ep - 1, &left); + STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(left.br_startblock)); + } + /* + * Check and set flags if the current (right) segment exists. + * If it doesn't exist, we're converting the hole at end-of-file. + */ + if (STATE_SET_TEST(RIGHT_VALID, + idx < + ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t))) { + xfs_bmbt_get_all(ep, &right); + STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(right.br_startblock)); + } + /* + * Set contiguity flags on the left and right neighbors. + * Don't let extents get too large, even if the pieces are contiguous. + */ + STATE_SET(LEFT_CONTIG, + STATE_TEST(LEFT_VALID) && STATE_TEST(LEFT_DELAY) && + left.br_startoff + left.br_blockcount == new->br_startoff && + left.br_blockcount + new->br_blockcount <= MAXEXTLEN); + STATE_SET(RIGHT_CONTIG, + STATE_TEST(RIGHT_VALID) && STATE_TEST(RIGHT_DELAY) && + new->br_startoff + new->br_blockcount == right.br_startoff && + new->br_blockcount + right.br_blockcount <= MAXEXTLEN && + (!STATE_TEST(LEFT_CONTIG) || + (left.br_blockcount + new->br_blockcount + + right.br_blockcount <= MAXEXTLEN))); + /* + * Switch out based on the contiguity flags. + */ + switch (SWITCH_STATE) { + + case MASK2(LEFT_CONTIG, RIGHT_CONTIG): + /* + * New allocation is contiguous with delayed allocations + * on the left and on the right. + * Merge all three into a single extent list entry. + */ + temp = left.br_blockcount + new->br_blockcount + + right.br_blockcount; + xfs_bmap_trace_pre_update(fname, "LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, temp); + oldlen = STARTBLOCKVAL(left.br_startblock) + + STARTBLOCKVAL(new->br_startblock) + + STARTBLOCKVAL(right.br_startblock); + newlen = xfs_bmap_worst_indlen(ip, temp); + xfs_bmbt_set_startblock(ep - 1, NULLSTARTBLOCK((int)newlen)); + xfs_bmap_trace_post_update(fname, "LC|RC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmap_trace_delete(fname, "LC|RC", ip, idx, 1, + XFS_DATA_FORK); + xfs_bmap_delete_exlist(ip, idx, 1, XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + break; + + case MASK(LEFT_CONTIG): + /* + * New allocation is contiguous with a delayed allocation + * on the left. + * Merge the new allocation with the left neighbor. + */ + temp = left.br_blockcount + new->br_blockcount; + xfs_bmap_trace_pre_update(fname, "LC", ip, idx - 1, + XFS_DATA_FORK); + xfs_bmbt_set_blockcount(ep - 1, temp); + oldlen = STARTBLOCKVAL(left.br_startblock) + + STARTBLOCKVAL(new->br_startblock); + newlen = xfs_bmap_worst_indlen(ip, temp); + xfs_bmbt_set_startblock(ep - 1, NULLSTARTBLOCK((int)newlen)); + xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1, + XFS_DATA_FORK); + ip->i_df.if_lastex = idx - 1; + break; + + case MASK(RIGHT_CONTIG): + /* + * New allocation is contiguous with a delayed allocation + * on the right. + * Merge the new allocation with the right neighbor. + */ + xfs_bmap_trace_pre_update(fname, "RC", ip, idx, XFS_DATA_FORK); + temp = new->br_blockcount + right.br_blockcount; + oldlen = STARTBLOCKVAL(new->br_startblock) + + STARTBLOCKVAL(right.br_startblock); + newlen = xfs_bmap_worst_indlen(ip, temp); + xfs_bmbt_set_allf(ep, new->br_startoff, + NULLSTARTBLOCK((int)newlen), temp, right.br_state); + xfs_bmap_trace_post_update(fname, "RC", ip, idx, XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + break; + + case 0: + /* + * New allocation is not contiguous with another + * delayed allocation. + * Insert a new entry. + */ + oldlen = newlen = 0; + xfs_bmap_trace_insert(fname, "0", ip, idx, 1, new, NULL, + XFS_DATA_FORK); + xfs_bmap_insert_exlist(ip, idx, 1, new, XFS_DATA_FORK); + ip->i_df.if_lastex = idx; + break; + } + if (oldlen != newlen) { + ASSERT(oldlen > newlen); + xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS, + (int)(oldlen - newlen), rsvd); + /* + * Nothing to do for disk quota accounting here. + */ + } + *logflagsp = 0; + return 0; +#undef MASK +#undef MASK2 +#undef STATE_SET +#undef STATE_TEST +#undef STATE_SET_TEST +#undef SWITCH_STATE +} + +/* + * Called by xfs_bmap_add_extent to handle cases converting a hole + * to a real allocation. + */ +STATIC int /* error */ +xfs_bmap_add_extent_hole_real( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* extent number to update/insert */ + xfs_btree_cur_t *cur, /* if null, not a btree */ + xfs_bmbt_irec_t *new, /* new data to put in extent list */ + int *logflagsp, /* inode logging flags */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *ep; /* pointer to extent entry ins. point */ + int error; /* error return value */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_add_extent_hole_real"; +#endif + int i; /* temp state */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_irec_t left; /* left neighbor extent entry */ + xfs_bmbt_irec_t right; /* right neighbor extent entry */ + int state; /* state bits, accessed thru macros */ + enum { /* bit number definitions for state */ + LEFT_CONTIG, RIGHT_CONTIG, + LEFT_DELAY, RIGHT_DELAY, + LEFT_VALID, RIGHT_VALID + }; + +#define MASK(b) (1 << (b)) +#define MASK2(a,b) (MASK(a) | MASK(b)) +#define STATE_SET(b,v) ((v) ? (state |= MASK(b)) : (state &= ~MASK(b))) +#define STATE_TEST(b) (state & MASK(b)) +#define STATE_SET_TEST(b,v) ((v) ? ((state |= MASK(b)), 1) : \ + ((state &= ~MASK(b)), 0)) +#define SWITCH_STATE (state & MASK2(LEFT_CONTIG, RIGHT_CONTIG)) + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(idx <= ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)); + ep = &ifp->if_u1.if_extents[idx]; + state = 0; + /* + * Check and set flags if this segment has a left neighbor. + */ + if (STATE_SET_TEST(LEFT_VALID, idx > 0)) { + xfs_bmbt_get_all(ep - 1, &left); + STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(left.br_startblock)); + } + /* + * Check and set flags if this segment has a current value. + * Not true if we're inserting into the "hole" at eof. + */ + if (STATE_SET_TEST(RIGHT_VALID, + idx < + ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))) { + xfs_bmbt_get_all(ep, &right); + STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(right.br_startblock)); + } + /* + * We're inserting a real allocation between "left" and "right". + * Set the contiguity flags. Don't let extents get too large. + */ + STATE_SET(LEFT_CONTIG, + STATE_TEST(LEFT_VALID) && !STATE_TEST(LEFT_DELAY) && + left.br_startoff + left.br_blockcount == new->br_startoff && + left.br_startblock + left.br_blockcount == new->br_startblock && + left.br_state == new->br_state && + left.br_blockcount + new->br_blockcount <= MAXEXTLEN); + STATE_SET(RIGHT_CONTIG, + STATE_TEST(RIGHT_VALID) && !STATE_TEST(RIGHT_DELAY) && + new->br_startoff + new->br_blockcount == right.br_startoff && + new->br_startblock + new->br_blockcount == + right.br_startblock && + new->br_state == right.br_state && + new->br_blockcount + right.br_blockcount <= MAXEXTLEN && + (!STATE_TEST(LEFT_CONTIG) || + left.br_blockcount + new->br_blockcount + + right.br_blockcount <= MAXEXTLEN)); + + /* + * Select which case we're in here, and implement it. + */ + switch (SWITCH_STATE) { + + case MASK2(LEFT_CONTIG, RIGHT_CONTIG): + /* + * New allocation is contiguous with real allocations on the + * left and on the right. + * Merge all three into a single extent list entry. + */ + xfs_bmap_trace_pre_update(fname, "LC|RC", ip, idx - 1, + whichfork); + xfs_bmbt_set_blockcount(ep - 1, + left.br_blockcount + new->br_blockcount + + right.br_blockcount); + xfs_bmap_trace_post_update(fname, "LC|RC", ip, idx - 1, + whichfork); + xfs_bmap_trace_delete(fname, "LC|RC", ip, + idx, 1, whichfork); + xfs_bmap_delete_exlist(ip, idx, 1, whichfork); + ifp->if_lastex = idx - 1; + XFS_IFORK_NEXT_SET(ip, whichfork, + XFS_IFORK_NEXTENTS(ip, whichfork) - 1); + if (cur == NULL) { + *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); + return 0; + } + *logflagsp = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, right.br_startoff, + right.br_startblock, right.br_blockcount, &i))) + return error; + ASSERT(i == 1); + if ((error = xfs_bmbt_delete(cur, 0, &i))) + return error; + ASSERT(i == 1); + if ((error = xfs_bmbt_decrement(cur, 0, &i))) + return error; + ASSERT(i == 1); + error = xfs_bmbt_update(cur, left.br_startoff, + left.br_startblock, + left.br_blockcount + new->br_blockcount + + right.br_blockcount, left.br_state); + return error; + + case MASK(LEFT_CONTIG): + /* + * New allocation is contiguous with a real allocation + * on the left. + * Merge the new allocation with the left neighbor. + */ + xfs_bmap_trace_pre_update(fname, "LC", ip, idx - 1, whichfork); + xfs_bmbt_set_blockcount(ep - 1, + left.br_blockcount + new->br_blockcount); + xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1, whichfork); + ifp->if_lastex = idx - 1; + if (cur == NULL) { + *logflagsp = XFS_ILOG_FEXT(whichfork); + return 0; + } + *logflagsp = 0; + if ((error = xfs_bmbt_lookup_eq(cur, left.br_startoff, + left.br_startblock, left.br_blockcount, &i))) + return error; + ASSERT(i == 1); + error = xfs_bmbt_update(cur, left.br_startoff, + left.br_startblock, + left.br_blockcount + new->br_blockcount, + left.br_state); + return error; + + case MASK(RIGHT_CONTIG): + /* + * New allocation is contiguous with a real allocation + * on the right. + * Merge the new allocation with the right neighbor. + */ + xfs_bmap_trace_pre_update(fname, "RC", ip, idx, whichfork); + xfs_bmbt_set_allf(ep, new->br_startoff, new->br_startblock, + new->br_blockcount + right.br_blockcount, + right.br_state); + xfs_bmap_trace_post_update(fname, "RC", ip, idx, whichfork); + ifp->if_lastex = idx; + if (cur == NULL) { + *logflagsp = XFS_ILOG_FEXT(whichfork); + return 0; + } + *logflagsp = 0; + if ((error = xfs_bmbt_lookup_eq(cur, right.br_startoff, + right.br_startblock, right.br_blockcount, &i))) + return error; + ASSERT(i == 1); + error = xfs_bmbt_update(cur, new->br_startoff, + new->br_startblock, + new->br_blockcount + right.br_blockcount, + right.br_state); + return error; + + case 0: + /* + * New allocation is not contiguous with another + * real allocation. + * Insert a new entry. + */ + xfs_bmap_trace_insert(fname, "0", ip, idx, 1, new, NULL, + whichfork); + xfs_bmap_insert_exlist(ip, idx, 1, new, whichfork); + ifp->if_lastex = idx; + XFS_IFORK_NEXT_SET(ip, whichfork, + XFS_IFORK_NEXTENTS(ip, whichfork) + 1); + if (cur == NULL) { + *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); + return 0; + } + *logflagsp = XFS_ILOG_CORE; + if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, + new->br_startblock, new->br_blockcount, &i))) + return error; + ASSERT(i == 0); + cur->bc_rec.b.br_state = new->br_state; + if ((error = xfs_bmbt_insert(cur, &i))) + return error; + ASSERT(i == 1); + return 0; + } +#undef MASK +#undef MASK2 +#undef STATE_SET +#undef STATE_TEST +#undef STATE_SET_TEST +#undef SWITCH_STATE + /* NOTREACHED */ + ASSERT(0); + return 0; /* keep gcc quite */ +} + +#define XFS_ALLOC_GAP_UNITS 4 + +/* + * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. + * It figures out where to ask the underlying allocator to put the new extent. + */ +STATIC int /* error */ +xfs_bmap_alloc( + xfs_bmalloca_t *ap) /* bmap alloc argument struct */ +{ + xfs_fsblock_t adjust; /* adjustment to block numbers */ + xfs_alloctype_t atype=0; /* type for allocation routines */ + int error; /* error return value */ + xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */ + xfs_mount_t *mp; /* mount point structure */ + int nullfb; /* true if ap->firstblock isn't set */ + int rt; /* true if inode is realtime */ +#ifdef __KERNEL__ + xfs_extlen_t prod=0; /* product factor for allocators */ + xfs_extlen_t ralen=0; /* realtime allocation length */ +#endif + +#define ISLEGAL(x,y) \ + (rt ? \ + (x) < mp->m_sb.sb_rblocks : \ + XFS_FSB_TO_AGNO(mp, x) == XFS_FSB_TO_AGNO(mp, y) && \ + XFS_FSB_TO_AGNO(mp, x) < mp->m_sb.sb_agcount && \ + XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks) + + /* + * Set up variables. + */ + mp = ap->ip->i_mount; + nullfb = ap->firstblock == NULLFSBLOCK; + rt = (ap->ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && ap->userdata; + fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock); +#ifdef __KERNEL__ + if (rt) { + xfs_extlen_t extsz; /* file extent size for rt */ + xfs_fileoff_t nexto; /* next file offset */ + xfs_extlen_t orig_alen; /* original ap->alen */ + xfs_fileoff_t orig_end; /* original off+len */ + xfs_fileoff_t orig_off; /* original ap->off */ + xfs_extlen_t mod_off; /* modulus calculations */ + xfs_fileoff_t prevo; /* previous file offset */ + xfs_rtblock_t rtx; /* realtime extent number */ + xfs_extlen_t temp; /* temp for rt calculations */ + + /* + * Set prod to match the realtime extent size. + */ + if (!(extsz = ap->ip->i_d.di_extsize)) + extsz = mp->m_sb.sb_rextsize; + prod = extsz / mp->m_sb.sb_rextsize; + orig_off = ap->off; + orig_alen = ap->alen; + orig_end = orig_off + orig_alen; + /* + * If the file offset is unaligned vs. the extent size + * we need to align it. This will be possible unless + * the file was previously written with a kernel that didn't + * perform this alignment. + */ + mod_off = do_mod(orig_off, extsz); + if (mod_off) { + ap->alen += mod_off; + ap->off -= mod_off; + } + /* + * Same adjustment for the end of the requested area. + */ + if ((temp = (ap->alen % extsz))) + ap->alen += extsz - temp; + /* + * If the previous block overlaps with this proposed allocation + * then move the start forward without adjusting the length. + */ + prevo = + ap->prevp->br_startoff == NULLFILEOFF ? + 0 : + (ap->prevp->br_startoff + + ap->prevp->br_blockcount); + if (ap->off != orig_off && ap->off < prevo) + ap->off = prevo; + /* + * If the next block overlaps with this proposed allocation + * then move the start back without adjusting the length, + * but not before offset 0. + * This may of course make the start overlap previous block, + * and if we hit the offset 0 limit then the next block + * can still overlap too. + */ + nexto = (ap->eof || ap->gotp->br_startoff == NULLFILEOFF) ? + NULLFILEOFF : ap->gotp->br_startoff; + if (!ap->eof && + ap->off + ap->alen != orig_end && + ap->off + ap->alen > nexto) + ap->off = nexto > ap->alen ? nexto - ap->alen : 0; + /* + * If we're now overlapping the next or previous extent that + * means we can't fit an extsz piece in this hole. Just move + * the start forward to the first legal spot and set + * the length so we hit the end. + */ + if ((ap->off != orig_off && ap->off < prevo) || + (ap->off + ap->alen != orig_end && + ap->off + ap->alen > nexto)) { + ap->off = prevo; + ap->alen = nexto - prevo; + } + /* + * If the result isn't a multiple of rtextents we need to + * remove blocks until it is. + */ + if ((temp = (ap->alen % mp->m_sb.sb_rextsize))) { + /* + * We're not covering the original request, or + * we won't be able to once we fix the length. + */ + if (orig_off < ap->off || + orig_end > ap->off + ap->alen || + ap->alen - temp < orig_alen) + return XFS_ERROR(EINVAL); + /* + * Try to fix it by moving the start up. + */ + if (ap->off + temp <= orig_off) { + ap->alen -= temp; + ap->off += temp; + } + /* + * Try to fix it by moving the end in. + */ + else if (ap->off + ap->alen - temp >= orig_end) + ap->alen -= temp; + /* + * Set the start to the minimum then trim the length. + */ + else { + ap->alen -= orig_off - ap->off; + ap->off = orig_off; + ap->alen -= ap->alen % mp->m_sb.sb_rextsize; + } + /* + * Result doesn't cover the request, fail it. + */ + if (orig_off < ap->off || orig_end > ap->off + ap->alen) + return XFS_ERROR(EINVAL); + } + ASSERT(ap->alen % mp->m_sb.sb_rextsize == 0); + /* + * If the offset & length are not perfectly aligned + * then kill prod, it will just get us in trouble. + */ + if (do_mod(ap->off, extsz) || ap->alen % extsz) + prod = 1; + /* + * Set ralen to be the actual requested length in rtextents. + */ + ralen = ap->alen / mp->m_sb.sb_rextsize; + /* + * If the old value was close enough to MAXEXTLEN that + * we rounded up to it, cut it back so it's legal again. + * Note that if it's a really large request (bigger than + * MAXEXTLEN), we don't hear about that number, and can't + * adjust the starting point to match it. + */ + if (ralen * mp->m_sb.sb_rextsize >= MAXEXTLEN) + ralen = MAXEXTLEN / mp->m_sb.sb_rextsize; + /* + * If it's an allocation to an empty file at offset 0, + * pick an extent that will space things out in the rt area. + */ + if (ap->eof && ap->off == 0) { + error = xfs_rtpick_extent(mp, ap->tp, ralen, &rtx); + if (error) + return error; + ap->rval = rtx * mp->m_sb.sb_rextsize; + } else + ap->rval = 0; + } +#else + if (rt) + ap->rval = 0; +#endif /* __KERNEL__ */ + else if (nullfb) + ap->rval = XFS_INO_TO_FSB(mp, ap->ip->i_ino); + else + ap->rval = ap->firstblock; + /* + * If allocating at eof, and there's a previous real block, + * try to use it's last block as our starting point. + */ + if (ap->eof && ap->prevp->br_startoff != NULLFILEOFF && + !ISNULLSTARTBLOCK(ap->prevp->br_startblock) && + ISLEGAL(ap->prevp->br_startblock + ap->prevp->br_blockcount, + ap->prevp->br_startblock)) { + ap->rval = ap->prevp->br_startblock + ap->prevp->br_blockcount; + /* + * Adjust for the gap between prevp and us. + */ + adjust = ap->off - + (ap->prevp->br_startoff + ap->prevp->br_blockcount); + if (adjust && + ISLEGAL(ap->rval + adjust, ap->prevp->br_startblock)) + ap->rval += adjust; + } + /* + * If not at eof, then compare the two neighbor blocks. + * Figure out whether either one gives us a good starting point, + * and pick the better one. + */ + else if (!ap->eof) { + xfs_fsblock_t gotbno; /* right side block number */ + xfs_fsblock_t gotdiff=0; /* right side difference */ + xfs_fsblock_t prevbno; /* left side block number */ + xfs_fsblock_t prevdiff=0; /* left side difference */ + + /* + * If there's a previous (left) block, select a requested + * start block based on it. + */ + if (ap->prevp->br_startoff != NULLFILEOFF && + !ISNULLSTARTBLOCK(ap->prevp->br_startblock) && + (prevbno = ap->prevp->br_startblock + + ap->prevp->br_blockcount) && + ISLEGAL(prevbno, ap->prevp->br_startblock)) { + /* + * Calculate gap to end of previous block. + */ + adjust = prevdiff = ap->off - + (ap->prevp->br_startoff + + ap->prevp->br_blockcount); + /* + * Figure the startblock based on the previous block's + * end and the gap size. + * Heuristic! + * If the gap is large relative to the piece we're + * allocating, or using it gives us an illegal block + * number, then just use the end of the previous block. + */ + if (prevdiff <= XFS_ALLOC_GAP_UNITS * ap->alen && + ISLEGAL(prevbno + prevdiff, + ap->prevp->br_startblock)) + prevbno += adjust; + else + prevdiff += adjust; + /* + * If the firstblock forbids it, can't use it, + * must use default. + */ + if (!rt && !nullfb && + XFS_FSB_TO_AGNO(mp, prevbno) != fb_agno) + prevbno = NULLFSBLOCK; + } + /* + * No previous block or can't follow it, just default. + */ + else + prevbno = NULLFSBLOCK; + /* + * If there's a following (right) block, select a requested + * start block based on it. + */ + if (!ISNULLSTARTBLOCK(ap->gotp->br_startblock)) { + /* + * Calculate gap to start of next block. + */ + adjust = gotdiff = ap->gotp->br_startoff - ap->off; + /* + * Figure the startblock based on the next block's + * start and the gap size. + */ + gotbno = ap->gotp->br_startblock; + /* + * Heuristic! + * If the gap is large relative to the piece we're + * allocating, or using it gives us an illegal block + * number, then just use the start of the next block + * offset by our length. + */ + if (gotdiff <= XFS_ALLOC_GAP_UNITS * ap->alen && + ISLEGAL(gotbno - gotdiff, gotbno)) + gotbno -= adjust; + else if (ISLEGAL(gotbno - ap->alen, gotbno)) { + gotbno -= ap->alen; + gotdiff += adjust - ap->alen; + } else + gotdiff += adjust; + /* + * If the firstblock forbids it, can't use it, + * must use default. + */ + if (!rt && !nullfb && + XFS_FSB_TO_AGNO(mp, gotbno) != fb_agno) + gotbno = NULLFSBLOCK; + } + /* + * No next block, just default. + */ + else + gotbno = NULLFSBLOCK; + /* + * If both valid, pick the better one, else the only good + * one, else ap->rval is already set (to 0 or the inode block). + */ + if (prevbno != NULLFSBLOCK && gotbno != NULLFSBLOCK) + ap->rval = prevdiff <= gotdiff ? prevbno : gotbno; + else if (prevbno != NULLFSBLOCK) + ap->rval = prevbno; + else if (gotbno != NULLFSBLOCK) + ap->rval = gotbno; + } + /* + * If allowed, use ap->rval; otherwise must use firstblock since + * it's in the right allocation group. + */ + if (nullfb || rt || XFS_FSB_TO_AGNO(mp, ap->rval) == fb_agno) + ; + else + ap->rval = ap->firstblock; + /* + * Realtime allocation, done through xfs_rtallocate_extent. + */ + if (rt) { +#ifndef __KERNEL__ + ASSERT(0); +#else + xfs_rtblock_t rtb; + + atype = ap->rval == 0 ? + XFS_ALLOCTYPE_ANY_AG : XFS_ALLOCTYPE_NEAR_BNO; + do_div(ap->rval, mp->m_sb.sb_rextsize); + rtb = ap->rval; + ap->alen = ralen; + if ((error = xfs_rtallocate_extent(ap->tp, ap->rval, 1, ap->alen, + &ralen, atype, ap->wasdel, prod, &rtb))) + return error; + if (rtb == NULLFSBLOCK && prod > 1 && + (error = xfs_rtallocate_extent(ap->tp, ap->rval, 1, + ap->alen, &ralen, atype, + ap->wasdel, 1, &rtb))) + return error; + ap->rval = rtb; + if (ap->rval != NULLFSBLOCK) { + ap->rval *= mp->m_sb.sb_rextsize; + ralen *= mp->m_sb.sb_rextsize; + ap->alen = ralen; + ap->ip->i_d.di_nblocks += ralen; + xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE); + if (ap->wasdel) + ap->ip->i_delayed_blks -= ralen; + /* + * Adjust the disk quota also. This was reserved + * earlier. + */ + if (XFS_IS_QUOTA_ON(mp) && + ap->ip->i_ino != mp->m_sb.sb_uquotino && + ap->ip->i_ino != mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(ap->tp, ap->ip, + ap->wasdel ? + XFS_TRANS_DQ_DELRTBCOUNT : + XFS_TRANS_DQ_RTBCOUNT, + (long)ralen); + } else + ap->alen = 0; +#endif /* __KERNEL__ */ + } + /* + * Normal allocation, done through xfs_alloc_vextent. + */ + else { + xfs_agnumber_t ag; + xfs_alloc_arg_t args; + xfs_extlen_t blen; + xfs_extlen_t delta; + int isaligned; + xfs_extlen_t longest; + xfs_extlen_t need; + xfs_extlen_t nextminlen=0; + int notinit; + xfs_perag_t *pag; + xfs_agnumber_t startag; + int tryagain; + + tryagain = isaligned = 0; + args.tp = ap->tp; + args.mp = mp; + args.fsbno = ap->rval; + args.maxlen = MIN(ap->alen, mp->m_sb.sb_agblocks); + blen = 0; + if (nullfb) { + args.type = XFS_ALLOCTYPE_START_BNO; + args.total = ap->total; + /* + * Find the longest available space. + * We're going to try for the whole allocation at once. + */ + startag = ag = XFS_FSB_TO_AGNO(mp, args.fsbno); + notinit = 0; + mrlock(&mp->m_peraglock, MR_ACCESS, PINOD); + while (blen < ap->alen) { + pag = &mp->m_perag[ag]; + if (!pag->pagf_init && + (error = xfs_alloc_pagf_init(mp, args.tp, + ag, XFS_ALLOC_FLAG_TRYLOCK))) { + mrunlock(&mp->m_peraglock); + return error; + } + /* + * See xfs_alloc_fix_freelist... + */ + if (pag->pagf_init) { + need = XFS_MIN_FREELIST_PAG(pag, mp); + delta = need > pag->pagf_flcount ? + need - pag->pagf_flcount : 0; + longest = (pag->pagf_longest > delta) ? + (pag->pagf_longest - delta) : + (pag->pagf_flcount > 0 || + pag->pagf_longest > 0); + if (blen < longest) + blen = longest; + } else + notinit = 1; + if (++ag == mp->m_sb.sb_agcount) + ag = 0; + if (ag == startag) + break; + } + mrunlock(&mp->m_peraglock); + /* + * Since the above loop did a BUF_TRYLOCK, it is + * possible that there is space for this request. + */ + if (notinit || blen < ap->minlen) + args.minlen = ap->minlen; + /* + * If the best seen length is less than the request + * length, use the best as the minimum. + */ + else if (blen < ap->alen) + args.minlen = blen; + /* + * Otherwise we've seen an extent as big as alen, + * use that as the minimum. + */ + else + args.minlen = ap->alen; + } else if (ap->low) { + args.type = XFS_ALLOCTYPE_FIRST_AG; + args.total = args.minlen = ap->minlen; + } else { + args.type = XFS_ALLOCTYPE_NEAR_BNO; + args.total = ap->total; + args.minlen = ap->minlen; + } + if (ap->ip->i_d.di_extsize) { + args.prod = ap->ip->i_d.di_extsize; + if ((args.mod = (xfs_extlen_t)do_mod(ap->off, args.prod))) + args.mod = (xfs_extlen_t)(args.prod - args.mod); + } else if (mp->m_sb.sb_blocksize >= NBPP) { + args.prod = 1; + args.mod = 0; + } else { + args.prod = NBPP >> mp->m_sb.sb_blocklog; + if ((args.mod = (xfs_extlen_t)(do_mod(ap->off, args.prod)))) + args.mod = (xfs_extlen_t)(args.prod - args.mod); + } + /* + * If we are not low on available data blocks, and the + * underlying logical volume manager is a stripe, and + * the file offset is zero then try to allocate data + * blocks on stripe unit boundary. + * NOTE: ap->aeof is only set if the allocation length + * is >= the stripe unit and the allocation offset is + * at the end of file. + */ + if (!ap->low && ap->aeof) { + if (!ap->off) { + args.alignment = mp->m_dalign; + atype = args.type; + isaligned = 1; + /* + * Adjust for alignment + */ + if (blen > args.alignment && blen <= ap->alen) + args.minlen = blen - args.alignment; + args.minalignslop = 0; + } else { + /* + * First try an exact bno allocation. + * If it fails then do a near or start bno + * allocation with alignment turned on. + */ + atype = args.type; + tryagain = 1; + args.type = XFS_ALLOCTYPE_THIS_BNO; + args.alignment = 1; + /* + * Compute the minlen+alignment for the + * next case. Set slop so that the value + * of minlen+alignment+slop doesn't go up + * between the calls. + */ + if (blen > mp->m_dalign && blen <= ap->alen) + nextminlen = blen - mp->m_dalign; + else + nextminlen = args.minlen; + if (nextminlen + mp->m_dalign > args.minlen + 1) + args.minalignslop = + nextminlen + mp->m_dalign - + args.minlen - 1; + else + args.minalignslop = 0; + } + } else { + args.alignment = 1; + args.minalignslop = 0; + } + args.minleft = ap->minleft; + args.wasdel = ap->wasdel; + args.isfl = 0; + args.userdata = ap->userdata; + if ((error = xfs_alloc_vextent(&args))) + return error; + if (tryagain && args.fsbno == NULLFSBLOCK) { + /* + * Exact allocation failed. Now try with alignment + * turned on. + */ + args.type = atype; + args.fsbno = ap->rval; + args.alignment = mp->m_dalign; + args.minlen = nextminlen; + args.minalignslop = 0; + isaligned = 1; + if ((error = xfs_alloc_vextent(&args))) + return error; + } + if (isaligned && args.fsbno == NULLFSBLOCK) { + /* + * allocation failed, so turn off alignment and + * try again. + */ + args.type = atype; + args.fsbno = ap->rval; + args.alignment = 0; + if ((error = xfs_alloc_vextent(&args))) + return error; + } + if (args.fsbno == NULLFSBLOCK && nullfb && + args.minlen > ap->minlen) { + args.minlen = ap->minlen; + args.type = XFS_ALLOCTYPE_START_BNO; + args.fsbno = ap->rval; + if ((error = xfs_alloc_vextent(&args))) + return error; + } + if (args.fsbno == NULLFSBLOCK && nullfb) { + args.fsbno = 0; + args.type = XFS_ALLOCTYPE_FIRST_AG; + args.total = ap->minlen; + args.minleft = 0; + if ((error = xfs_alloc_vextent(&args))) + return error; + ap->low = 1; + } + if (args.fsbno != NULLFSBLOCK) { + ap->firstblock = ap->rval = args.fsbno; + ASSERT(nullfb || fb_agno == args.agno || + (ap->low && fb_agno < args.agno)); + ap->alen = args.len; + ap->ip->i_d.di_nblocks += args.len; + xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE); + if (ap->wasdel) + ap->ip->i_delayed_blks -= args.len; + /* + * Adjust the disk quota also. This was reserved + * earlier. + */ + if (XFS_IS_QUOTA_ON(mp) && + ap->ip->i_ino != mp->m_sb.sb_uquotino && + ap->ip->i_ino != mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(ap->tp, ap->ip, + ap->wasdel ? + XFS_TRANS_DQ_DELBCOUNT : + XFS_TRANS_DQ_BCOUNT, + (long)args.len); + } else { + ap->rval = NULLFSBLOCK; + ap->alen = 0; + } + } + return 0; +#undef ISLEGAL +} + +/* + * Transform a btree format file with only one leaf node, where the + * extents list will fit in the inode, into an extents format file. + * Since the extent list is already in-core, all we have to do is + * give up the space for the btree root and pitch the leaf block. + */ +STATIC int /* error */ +xfs_bmap_btree_to_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_btree_cur_t *cur, /* btree cursor */ + int *logflagsp, /* inode logging flags */ + int whichfork, /* data or attr fork */ + int async) /* xaction can be async */ +{ + /* REFERENCED */ + xfs_bmbt_block_t *cblock;/* child btree block */ + xfs_fsblock_t cbno; /* child block number */ + xfs_buf_t *cbp; /* child block's buffer */ + int error; /* error return value */ + xfs_ifork_t *ifp; /* inode fork data */ + xfs_mount_t *mp; /* mount point structure */ + xfs_bmbt_ptr_t *pp; /* ptr to block address */ + xfs_bmbt_block_t *rblock;/* root btree block */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_flags & XFS_IFEXTENTS); + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE); + rblock = ifp->if_broot; + ASSERT(INT_GET(rblock->bb_level, ARCH_CONVERT) == 1); + ASSERT(INT_GET(rblock->bb_numrecs, ARCH_CONVERT) == 1); + ASSERT(XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes) == 1); + mp = ip->i_mount; + pp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, ifp->if_broot_bytes); + *logflagsp = 0; +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), 1))) + return error; +#endif + cbno = INT_GET(*pp, ARCH_CONVERT); + if ((error = xfs_btree_read_bufl(mp, tp, cbno, 0, &cbp, + XFS_BMAP_BTREE_REF))) + return error; + cblock = XFS_BUF_TO_BMBT_BLOCK(cbp); + if ((error = xfs_btree_check_lblock(cur, cblock, 0, cbp))) + return error; + xfs_bmap_add_free(cbno, 1, cur->bc_private.b.flist, mp); + if (!async) + xfs_trans_set_sync(tp); + ip->i_d.di_nblocks--; + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); + xfs_trans_binval(tp, cbp); + if (cur->bc_bufs[0] == cbp) + cur->bc_bufs[0] = NULL; + xfs_iroot_realloc(ip, -1, whichfork); + ASSERT(ifp->if_broot == NULL); + ASSERT((ifp->if_flags & XFS_IFBROOT) == 0); + XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); + *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork); + return 0; +} + +/* + * Called by xfs_bmapi to update extent list structure and the btree + * after removing space (or undoing a delayed allocation). + */ +STATIC int /* error */ +xfs_bmap_del_extent( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_trans_t *tp, /* current transaction pointer */ + xfs_extnum_t idx, /* extent number to update/delete */ + xfs_bmap_free_t *flist, /* list of extents to be freed */ + xfs_btree_cur_t *cur, /* if null, not a btree */ + xfs_bmbt_irec_t *del, /* data to remove from extent list */ + int iflags, /* input flags */ + int *logflagsp, /* inode logging flags */ + int whichfork, /* data or attr fork */ + int rsvd) /* OK to allocate reserved blocks */ +{ + xfs_filblks_t da_new; /* new delay-alloc indirect blocks */ + xfs_filblks_t da_old; /* old delay-alloc indirect blocks */ + xfs_fsblock_t del_endblock=0; /* first block past del */ + xfs_fileoff_t del_endoff; /* first offset past del */ + int delay; /* current block is delayed allocated */ + int do_fx; /* free extent at end of routine */ + xfs_bmbt_rec_t *ep; /* current extent entry pointer */ + int error; /* error return value */ + int flags; /* inode logging flags */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_del_extent"; +#endif + xfs_bmbt_irec_t got; /* current extent entry */ + xfs_fileoff_t got_endoff; /* first offset past got */ + int i; /* temp state */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_mount_t *mp; /* mount structure */ + xfs_filblks_t nblks; /* quota/sb block count */ + xfs_bmbt_irec_t new; /* new record to be inserted */ + /* REFERENCED */ + xfs_extnum_t nextents; /* number of extents in list */ + uint qfield; /* quota field to update */ + xfs_filblks_t temp; /* for indirect length calculations */ + xfs_filblks_t temp2; /* for indirect length calculations */ + + XFS_STATS_INC(xfsstats.xs_del_exlist); + mp = ip->i_mount; + ifp = XFS_IFORK_PTR(ip, whichfork); + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + ASSERT(idx >= 0 && idx < nextents); + ASSERT(del->br_blockcount > 0); + ep = &ifp->if_u1.if_extents[idx]; + xfs_bmbt_get_all(ep, &got); + ASSERT(got.br_startoff <= del->br_startoff); + del_endoff = del->br_startoff + del->br_blockcount; + got_endoff = got.br_startoff + got.br_blockcount; + ASSERT(got_endoff >= del_endoff); + delay = ISNULLSTARTBLOCK(got.br_startblock); + ASSERT(ISNULLSTARTBLOCK(del->br_startblock) == delay); + flags = 0; + qfield = 0; + error = 0; + /* + * If deleting a real allocation, must free up the disk space. + */ + if (!delay) { + flags = XFS_ILOG_CORE; + /* + * Realtime allocation. Free it and record di_nblocks update. + */ + if (whichfork == XFS_DATA_FORK && + (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { + xfs_fsblock_t bno; + xfs_filblks_t len; + + ASSERT(do_mod(del->br_blockcount, + mp->m_sb.sb_rextsize) == 0); + ASSERT(do_mod(del->br_startblock, + mp->m_sb.sb_rextsize) == 0); + bno = del->br_startblock; + do_div(bno, mp->m_sb.sb_rextsize); + len = del->br_blockcount; + do_div(len, mp->m_sb.sb_rextsize); + if ((error = xfs_rtfree_extent(ip->i_transp, bno, + (xfs_extlen_t)len))) + goto done; + do_fx = 0; + nblks = len * mp->m_sb.sb_rextsize; + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) + qfield = XFS_TRANS_DQ_RTBCOUNT; + } + /* + * Ordinary allocation. + */ + else { + do_fx = 1; + nblks = del->br_blockcount; + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) + qfield = XFS_TRANS_DQ_BCOUNT; + /* + * If we're freeing meta-data, then the transaction + * that frees the blocks must be synchronous. This + * ensures that noone can reuse the blocks before + * they are permanently free. For regular data + * it is the callers responsibility to make the + * data permanently inaccessible before calling + * here to free it. + */ + if (iflags & XFS_BMAPI_METADATA) + xfs_trans_set_sync(tp); + } + /* + * Set up del_endblock and cur for later. + */ + del_endblock = del->br_startblock + del->br_blockcount; + if (cur) { + if ((error = xfs_bmbt_lookup_eq(cur, got.br_startoff, + got.br_startblock, got.br_blockcount, + &i))) + goto done; + ASSERT(i == 1); + } + da_old = da_new = 0; + } else { + da_old = STARTBLOCKVAL(got.br_startblock); + da_new = 0; + nblks = 0; + do_fx = 0; + } + /* + * Set flag value to use in switch statement. + * Left-contig is 2, right-contig is 1. + */ + switch (((got.br_startoff == del->br_startoff) << 1) | + (got_endoff == del_endoff)) { + case 3: + /* + * Matches the whole extent. Delete the entry. + */ + xfs_bmap_trace_delete(fname, "3", ip, idx, 1, whichfork); + xfs_bmap_delete_exlist(ip, idx, 1, whichfork); + ifp->if_lastex = idx; + if (delay) + break; + XFS_IFORK_NEXT_SET(ip, whichfork, + XFS_IFORK_NEXTENTS(ip, whichfork) - 1); + flags |= XFS_ILOG_CORE; + if (!cur) { + flags |= XFS_ILOG_FEXT(whichfork); + break; + } + if ((error = xfs_bmbt_delete(cur, iflags & XFS_BMAPI_ASYNC, &i))) + goto done; + ASSERT(i == 1); + break; + + case 2: + /* + * Deleting the first part of the extent. + */ + xfs_bmap_trace_pre_update(fname, "2", ip, idx, whichfork); + xfs_bmbt_set_startoff(ep, del_endoff); + temp = got.br_blockcount - del->br_blockcount; + xfs_bmbt_set_blockcount(ep, temp); + ifp->if_lastex = idx; + if (delay) { + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + da_old); + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "2", ip, idx, + whichfork); + da_new = temp; + break; + } + xfs_bmbt_set_startblock(ep, del_endblock); + xfs_bmap_trace_post_update(fname, "2", ip, idx, whichfork); + if (!cur) { + flags |= XFS_ILOG_FEXT(whichfork); + break; + } + if ((error = xfs_bmbt_update(cur, del_endoff, del_endblock, + got.br_blockcount - del->br_blockcount, + got.br_state))) + goto done; + break; + + case 1: + /* + * Deleting the last part of the extent. + */ + temp = got.br_blockcount - del->br_blockcount; + xfs_bmap_trace_pre_update(fname, "1", ip, idx, whichfork); + xfs_bmbt_set_blockcount(ep, temp); + ifp->if_lastex = idx; + if (delay) { + temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), + da_old); + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + xfs_bmap_trace_post_update(fname, "1", ip, idx, + whichfork); + da_new = temp; + break; + } + xfs_bmap_trace_post_update(fname, "1", ip, idx, whichfork); + if (!cur) { + flags |= XFS_ILOG_FEXT(whichfork); + break; + } + if ((error = xfs_bmbt_update(cur, got.br_startoff, + got.br_startblock, + got.br_blockcount - del->br_blockcount, + got.br_state))) + goto done; + break; + + case 0: + /* + * Deleting the middle of the extent. + */ + temp = del->br_startoff - got.br_startoff; + xfs_bmap_trace_pre_update(fname, "0", ip, idx, whichfork); + xfs_bmbt_set_blockcount(ep, temp); + new.br_startoff = del_endoff; + temp2 = got_endoff - del_endoff; + new.br_blockcount = temp2; + new.br_state = got.br_state; + if (!delay) { + new.br_startblock = del_endblock; + flags |= XFS_ILOG_CORE; + if (cur) { + if ((error = xfs_bmbt_update(cur, + got.br_startoff, + got.br_startblock, temp, + got.br_state))) + goto done; + if ((error = xfs_bmbt_increment(cur, 0, &i))) + goto done; + cur->bc_rec.b = new; + error = xfs_bmbt_insert(cur, &i); + if (error && error != ENOSPC) + goto done; + /* + * If get no-space back from btree insert, + * it tried a split, and we have a zero + * block reservation. + * Fix up our state and return the error. + */ + if (error == ENOSPC) { + /* + * Reset the cursor, don't trust + * it after any insert operation. + */ + if ((error = xfs_bmbt_lookup_eq(cur, + got.br_startoff, + got.br_startblock, + temp, &i))) + goto done; + ASSERT(i == 1); + /* + * Update the btree record back + * to the original value. + */ + if ((error = xfs_bmbt_update(cur, + got.br_startoff, + got.br_startblock, + got.br_blockcount, + got.br_state))) + goto done; + /* + * Reset the extent record back + * to the original value. + */ + xfs_bmbt_set_blockcount(ep, + got.br_blockcount); + flags = 0; + error = XFS_ERROR(ENOSPC); + goto done; + } + ASSERT(i == 1); + } else + flags |= XFS_ILOG_FEXT(whichfork); + XFS_IFORK_NEXT_SET(ip, whichfork, + XFS_IFORK_NEXTENTS(ip, whichfork) + 1); + } else { + ASSERT(whichfork == XFS_DATA_FORK); + temp = xfs_bmap_worst_indlen(ip, temp); + xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp)); + temp2 = xfs_bmap_worst_indlen(ip, temp2); + new.br_startblock = NULLSTARTBLOCK((int)temp2); + da_new = temp + temp2; + while (da_new > da_old) { + if (temp) { + temp--; + da_new--; + xfs_bmbt_set_startblock(ep, + NULLSTARTBLOCK((int)temp)); + } + if (da_new == da_old) + break; + if (temp2) { + temp2--; + da_new--; + new.br_startblock = + NULLSTARTBLOCK((int)temp2); + } + } + } + xfs_bmap_trace_post_update(fname, "0", ip, idx, whichfork); + xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 1, &new, NULL, + whichfork); + xfs_bmap_insert_exlist(ip, idx + 1, 1, &new, whichfork); + ifp->if_lastex = idx + 1; + break; + } + /* + * If we need to, add to list of extents to delete. + */ + if (do_fx) + xfs_bmap_add_free(del->br_startblock, del->br_blockcount, flist, + mp); + /* + * Adjust inode # blocks in the file. + */ + if (nblks) + ip->i_d.di_nblocks -= nblks; + /* + * Adjust quota data. + */ + if (qfield) + xfs_trans_mod_dquot_byino(tp, ip, qfield, (long)-nblks); + /* + * Account for change in delayed indirect blocks. + * Nothing to do for disk quota accounting here. + */ + ASSERT(da_old >= da_new); + if (da_old > da_new) + xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, (int)(da_old - da_new), + rsvd); +done: + *logflagsp = flags; + return error; +} + +/* + * Remove the entry "free" from the free item list. Prev points to the + * previous entry, unless "free" is the head of the list. + */ +STATIC void +xfs_bmap_del_free( + xfs_bmap_free_t *flist, /* free item list header */ + xfs_bmap_free_item_t *prev, /* previous item on list, if any */ + xfs_bmap_free_item_t *free) /* list item to be freed */ +{ + if (prev) + prev->xbfi_next = free->xbfi_next; + else + flist->xbf_first = free->xbfi_next; + flist->xbf_count--; + kmem_zone_free(xfs_bmap_free_item_zone, free); +} + +/* + * Remove count entries from the extents array for inode "ip", starting + * at index "idx". Copies the remaining items down over the deleted ones, + * and gives back the excess memory. + */ +STATIC void +xfs_bmap_delete_exlist( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* starting delete index */ + xfs_extnum_t count, /* count of items to delete */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* base of extent list */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t nextents; /* number of extents in list after */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_flags & XFS_IFEXTENTS); + base = ifp->if_u1.if_extents; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - count; + ovbcopy(&base[idx + count], &base[idx], + (nextents - idx) * sizeof(*base)); + xfs_iext_realloc(ip, -count, whichfork); +} + +/* + * Convert an extents-format file into a btree-format file. + * The new file will have a root block (in the inode) and a single child block. + */ +STATIC int /* error */ +xfs_bmap_extents_to_btree( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first-block-allocated */ + xfs_bmap_free_t *flist, /* blocks freed in xaction */ + xfs_btree_cur_t **curp, /* cursor returned to caller */ + int wasdel, /* converting a delayed alloc */ + int *logflagsp, /* inode logging flags */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_block_t *ablock; /* allocated (child) bt block */ + xfs_buf_t *abp; /* buffer for ablock */ + xfs_alloc_arg_t args; /* allocation arguments */ + xfs_bmbt_rec_t *arp; /* child record pointer */ + xfs_bmbt_block_t *block; /* btree root block */ + xfs_btree_cur_t *cur; /* bmap btree cursor */ + xfs_bmbt_rec_t *ep; /* extent list pointer */ + int error; /* error return value */ + xfs_extnum_t i; /* extent list index */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_key_t *kp; /* root block key pointer */ + xfs_mount_t *mp; /* mount structure */ + xfs_extnum_t nextents; /* extent list size */ + xfs_bmbt_ptr_t *pp; /* root block address pointer */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS); + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + /* + * Make space in the inode incore. + */ + xfs_iroot_realloc(ip, 1, whichfork); + ifp->if_flags |= XFS_IFBROOT; + /* + * Fill in the root. + */ + block = ifp->if_broot; + INT_SET(block->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC); + INT_SET(block->bb_level, ARCH_CONVERT, 1); + INT_SET(block->bb_numrecs, ARCH_CONVERT, 1); + INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLDFSBNO); + INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLDFSBNO); + /* + * Need a cursor. Can't allocate until bb_level is filled in. + */ + mp = ip->i_mount; + cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip, + whichfork); + cur->bc_private.b.firstblock = *firstblock; + cur->bc_private.b.flist = flist; + cur->bc_private.b.flags = wasdel ? XFS_BTCUR_BPRV_WASDEL : 0; + /* + * Convert to a btree with two levels, one record in root. + */ + XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_BTREE); + args.tp = tp; + args.mp = mp; + if (*firstblock == NULLFSBLOCK) { + args.type = XFS_ALLOCTYPE_START_BNO; + args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino); + } else if (flist->xbf_low) { + args.type = XFS_ALLOCTYPE_START_BNO; + args.fsbno = *firstblock; + } else { + args.type = XFS_ALLOCTYPE_NEAR_BNO; + args.fsbno = *firstblock; + } + args.minlen = args.maxlen = args.prod = 1; + args.total = args.minleft = args.alignment = args.mod = args.isfl = + args.minalignslop = 0; + args.wasdel = wasdel; + *logflagsp = 0; + if ((error = xfs_alloc_vextent(&args))) { + xfs_iroot_realloc(ip, -1, whichfork); + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; + } + /* + * Allocation can't fail, the space was reserved. + */ + ASSERT(args.fsbno != NULLFSBLOCK); + ASSERT(*firstblock == NULLFSBLOCK || + args.agno == XFS_FSB_TO_AGNO(mp, *firstblock) || + (flist->xbf_low && + args.agno > XFS_FSB_TO_AGNO(mp, *firstblock))); + *firstblock = cur->bc_private.b.firstblock = args.fsbno; + cur->bc_private.b.allocated++; + ip->i_d.di_nblocks++; + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L); + abp = xfs_btree_get_bufl(mp, tp, args.fsbno, 0); + /* + * Fill in the child block. + */ + ablock = XFS_BUF_TO_BMBT_BLOCK(abp); + INT_SET(ablock->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC); + INT_ZERO(ablock->bb_level, ARCH_CONVERT); + INT_ZERO(ablock->bb_numrecs, ARCH_CONVERT); + INT_SET(ablock->bb_leftsib, ARCH_CONVERT, NULLDFSBNO); + INT_SET(ablock->bb_rightsib, ARCH_CONVERT, NULLDFSBNO); + arp = XFS_BMAP_REC_IADDR(ablock, 1, cur); + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + for (ep = ifp->if_u1.if_extents, i = 0; i < nextents; i++, ep++) { + if (!ISNULLSTARTBLOCK(xfs_bmbt_get_startblock(ep))) { + *arp++ = *ep; + INT_MOD(ablock->bb_numrecs, ARCH_CONVERT, +1); + } + } + ASSERT(INT_GET(ablock->bb_numrecs, ARCH_CONVERT) == XFS_IFORK_NEXTENTS(ip, whichfork)); + /* + * Fill in the root key and pointer. + */ + kp = XFS_BMAP_KEY_IADDR(block, 1, cur); + arp = XFS_BMAP_REC_IADDR(ablock, 1, cur); + INT_SET(kp->br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(arp)); + pp = XFS_BMAP_PTR_IADDR(block, 1, cur); + INT_SET(*pp, ARCH_CONVERT, args.fsbno); + /* + * Do all this logging at the end so that + * the root is at the right level. + */ + xfs_bmbt_log_block(cur, abp, XFS_BB_ALL_BITS); + xfs_bmbt_log_recs(cur, abp, 1, INT_GET(ablock->bb_numrecs, ARCH_CONVERT)); + ASSERT(*curp == NULL); + *curp = cur; + *logflagsp = XFS_ILOG_CORE | XFS_ILOG_FBROOT(whichfork); + return 0; +} + +/* + * Insert new item(s) in the extent list for inode "ip". + * Count new items are inserted at offset idx. + */ +STATIC void +xfs_bmap_insert_exlist( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* starting index of new items */ + xfs_extnum_t count, /* number of inserted items */ + xfs_bmbt_irec_t *new, /* items to insert */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* extent list base */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t nextents; /* extent list size */ + xfs_extnum_t to; /* extent list index */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_flags & XFS_IFEXTENTS); + xfs_iext_realloc(ip, count, whichfork); + base = ifp->if_u1.if_extents; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + ovbcopy(&base[idx], &base[idx + count], + (nextents - (idx + count)) * sizeof(*base)); + for (to = idx; to < idx + count; to++, new++) + xfs_bmbt_set_all(&base[to], new); +} + +/* + * Convert a local file to an extents file. + * This code is out of bounds for data forks of regular files, + * since the file data needs to get logged so things will stay consistent. + * (The bmap-level manipulations are ok, though). + */ +STATIC int /* error */ +xfs_bmap_local_to_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fsblock_t *firstblock, /* first block allocated in xaction */ + xfs_extlen_t total, /* total blocks needed by transaction */ + int *logflagsp, /* inode logging flags */ + int whichfork) /* data or attr fork */ +{ + int error; /* error return value */ + int flags; /* logging flags returned */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_local_to_extents"; +#endif + xfs_ifork_t *ifp; /* inode fork pointer */ + + /* + * We don't want to deal with the case of keeping inode data inline yet. + * So sending the data fork of a regular inode is illegal. + */ + ASSERT(!((ip->i_d.di_mode & IFMT) == IFREG && + whichfork == XFS_DATA_FORK)); + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); + flags = 0; + error = 0; + if (ifp->if_bytes) { + xfs_alloc_arg_t args; /* allocation arguments */ + xfs_buf_t *bp; /* buffer for extent list block */ + xfs_bmbt_rec_t *ep; /* extent list pointer */ + + args.tp = tp; + args.mp = ip->i_mount; + ASSERT(ifp->if_flags & XFS_IFINLINE); + /* + * Allocate a block. We know we need only one, since the + * file currently fits in an inode. + */ + if (*firstblock == NULLFSBLOCK) { + args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino); + args.type = XFS_ALLOCTYPE_START_BNO; + } else { + args.fsbno = *firstblock; + args.type = XFS_ALLOCTYPE_NEAR_BNO; + } + args.total = total; + args.mod = args.minleft = args.alignment = args.wasdel = + args.isfl = args.minalignslop = 0; + args.minlen = args.maxlen = args.prod = 1; + if ((error = xfs_alloc_vextent(&args))) + goto done; + /* + * Can't fail, the space was reserved. + */ + ASSERT(args.fsbno != NULLFSBLOCK); + ASSERT(args.len == 1); + *firstblock = args.fsbno; + bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0); + bcopy(ifp->if_u1.if_data, (char *)XFS_BUF_PTR(bp), + ifp->if_bytes); + xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1); + xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); + xfs_iext_realloc(ip, 1, whichfork); + ep = ifp->if_u1.if_extents; + xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM); + xfs_bmap_trace_post_update(fname, "new", ip, 0, whichfork); + XFS_IFORK_NEXT_SET(ip, whichfork, 1); + ip->i_d.di_nblocks = 1; + if (XFS_IS_QUOTA_ON(args.mp) && + ip->i_ino != args.mp->m_sb.sb_uquotino && + ip->i_ino != args.mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, + 1L); + flags |= XFS_ILOG_FEXT(whichfork); + } else + ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0); + ifp->if_flags &= ~XFS_IFINLINE; + ifp->if_flags |= XFS_IFEXTENTS; + XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); + flags |= XFS_ILOG_CORE; +done: + *logflagsp = flags; + return error; +} + +xfs_bmbt_rec_t * /* pointer to found extent entry */ +xfs_bmap_do_search_extents( + xfs_bmbt_rec_t *base, /* base of extent list */ + xfs_extnum_t lastx, /* last extent index used */ + xfs_extnum_t nextents, /* extent list size */ + xfs_fileoff_t bno, /* block number searched for */ + int *eofp, /* out: end of file found */ + xfs_extnum_t *lastxp, /* out: last extent index */ + xfs_bmbt_irec_t *gotp, /* out: extent entry found */ + xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */ +{ + xfs_bmbt_rec_t *ep; /* extent list entry pointer */ + xfs_bmbt_irec_t got; /* extent list entry, decoded */ + int high; /* high index of binary search */ + int low; /* low index of binary search */ + + if (lastx != NULLEXTNUM && lastx < nextents) + ep = base + lastx; + else + ep = NULL; + prevp->br_startoff = NULLFILEOFF; + if (ep && bno >= (got.br_startoff = xfs_bmbt_get_startoff(ep)) && + bno < got.br_startoff + + (got.br_blockcount = xfs_bmbt_get_blockcount(ep))) + *eofp = 0; + else if (ep && lastx < nextents - 1 && + bno >= (got.br_startoff = xfs_bmbt_get_startoff(ep + 1)) && + bno < got.br_startoff + + (got.br_blockcount = xfs_bmbt_get_blockcount(ep + 1))) { + lastx++; + ep++; + *eofp = 0; + } else if (nextents == 0) + *eofp = 1; + else if (bno == 0 && + (got.br_startoff = xfs_bmbt_get_startoff(base)) == 0) { + ep = base; + lastx = 0; + got.br_blockcount = xfs_bmbt_get_blockcount(ep); + *eofp = 0; + } else { + /* binary search the extents array */ + low = 0; + high = nextents - 1; + while (low <= high) { + XFS_STATS_INC(xfsstats.xs_cmp_exlist); + lastx = (low + high) >> 1; + ep = base + lastx; + got.br_startoff = xfs_bmbt_get_startoff(ep); + got.br_blockcount = xfs_bmbt_get_blockcount(ep); + if (bno < got.br_startoff) + high = lastx - 1; + else if (bno >= got.br_startoff + got.br_blockcount) + low = lastx + 1; + else { + got.br_startblock = xfs_bmbt_get_startblock(ep); + got.br_state = xfs_bmbt_get_state(ep); + *eofp = 0; + *lastxp = lastx; + *gotp = got; + return ep; + } + } + if (bno >= got.br_startoff + got.br_blockcount) { + lastx++; + if (lastx == nextents) { + *eofp = 1; + got.br_startblock = xfs_bmbt_get_startblock(ep); + got.br_state = xfs_bmbt_get_state(ep); + *prevp = got; + ep = NULL; + } else { + *eofp = 0; + xfs_bmbt_get_all(ep, prevp); + ep++; + got.br_startoff = xfs_bmbt_get_startoff(ep); + got.br_blockcount = xfs_bmbt_get_blockcount(ep); + } + } else { + *eofp = 0; + if (ep > base) + xfs_bmbt_get_all(ep - 1, prevp); + } + } + if (ep) { + got.br_startblock = xfs_bmbt_get_startblock(ep); + got.br_state = xfs_bmbt_get_state(ep); + } + *lastxp = lastx; + *gotp = got; + return ep; +} + +/* + * Search the extents list for the inode, for the extent containing bno. + * If bno lies in a hole, point to the next entry. If bno lies past eof, + * *eofp will be set, and *prevp will contain the last entry (null if none). + * Else, *lastxp will be set to the index of the found + * entry; *gotp will contain the entry. + */ +STATIC xfs_bmbt_rec_t * /* pointer to found extent entry */ +xfs_bmap_search_extents( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fileoff_t bno, /* block number searched for */ + int whichfork, /* data or attr fork */ + int *eofp, /* out: end of file found */ + xfs_extnum_t *lastxp, /* out: last extent index */ + xfs_bmbt_irec_t *gotp, /* out: extent entry found */ + xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */ +{ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_rec_t *base; /* base of extent list */ + xfs_extnum_t lastx; /* last extent index used */ + xfs_extnum_t nextents; /* extent list size */ + + XFS_STATS_INC(xfsstats.xs_look_exlist); + ifp = XFS_IFORK_PTR(ip, whichfork); + lastx = ifp->if_lastex; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + base = &ifp->if_u1.if_extents[0]; + + return xfs_bmap_do_search_extents(base, lastx, nextents, bno, eofp, + lastxp, gotp, prevp); +} + + +#ifdef XFS_BMAP_TRACE +/* + * Add a bmap trace buffer entry. Base routine for the others. + */ +STATIC void +xfs_bmap_trace_addentry( + int opcode, /* operation */ + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry(ies) */ + xfs_extnum_t cnt, /* count of entries, 1 or 2 */ + xfs_bmbt_rec_t *r1, /* first record */ + xfs_bmbt_rec_t *r2, /* second record or null */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t tr2; + + ASSERT(cnt == 1 || cnt == 2); + ASSERT(r1 != NULL); + if (cnt == 1) { + ASSERT(r2 == NULL); + r2 = &tr2; + bzero(&tr2, sizeof(tr2)); + } else + ASSERT(r2 != NULL); + ktrace_enter(xfs_bmap_trace_buf, + (void *)(__psint_t)(opcode | (whichfork << 16)), + (void *)fname, (void *)desc, (void *)ip, + (void *)(__psint_t)idx, + (void *)(__psint_t)cnt, + (void *)(__psunsigned_t)(ip->i_ino >> 32), + (void *)(__psunsigned_t)(unsigned)ip->i_ino, +#if BMBT_USE_64 + (void *)(__psunsigned_t)(INT_GET(r1->l0, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r1->l0, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r1->l1, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r1->l1, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l0, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r2->l0, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l1, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r2->l1, ARCH_CONVERT)) +#else /* !BMBT_USE_64 */ + (void *)(__psunsigned_t)(INT_GET(r1->l0, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r1->l1, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r1->l2, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r1->l3, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l0, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l1, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l2, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l3, ARCH_CONVERT)) +#endif /* BMBT_USE_64 */ + ); + ASSERT(ip->i_xtrace); + ktrace_enter(ip->i_xtrace, + (void *)(__psint_t)(opcode | (whichfork << 16)), + (void *)fname, (void *)desc, (void *)ip, + (void *)(__psint_t)idx, + (void *)(__psint_t)cnt, + (void *)(__psunsigned_t)(ip->i_ino >> 32), + (void *)(__psunsigned_t)(unsigned)ip->i_ino, +#if BMBT_USE_64 + (void *)(__psunsigned_t)(INT_GET(r1->l0, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r1->l0, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r1->l1, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r1->l1, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l0, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r2->l0, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l1, ARCH_CONVERT) >> 32), + (void *)(__psunsigned_t)(unsigned)(INT_GET(r2->l1, ARCH_CONVERT)) +#else /* !BMBT_USE_64 */ + (void *)(__psunsigned_t)(INT_GET(r1->l0, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r1->l1, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r1->l2, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r1->l3, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l0, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l1, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l2, ARCH_CONVERT)), + (void *)(__psunsigned_t)(INT_GET(r2->l3, ARCH_CONVERT)) +#endif /* BMBT_USE_64 */ + ); +} + +/* + * Add bmap trace entry prior to a call to xfs_bmap_delete_exlist. + */ +STATIC void +xfs_bmap_trace_delete( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry(entries) deleted */ + xfs_extnum_t cnt, /* count of entries deleted, 1 or 2 */ + int whichfork) /* data or attr fork */ +{ + xfs_ifork_t *ifp; /* inode fork pointer */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + xfs_bmap_trace_addentry(XFS_BMAP_KTRACE_DELETE, fname, desc, ip, idx, + cnt, &ifp->if_u1.if_extents[idx], + cnt == 2 ? &ifp->if_u1.if_extents[idx + 1] : NULL, + whichfork); +} + +/* + * Add bmap trace entry prior to a call to xfs_bmap_insert_exlist, or + * reading in the extents list from the disk (in the btree). + */ +STATIC void +xfs_bmap_trace_insert( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry(entries) inserted */ + xfs_extnum_t cnt, /* count of entries inserted, 1 or 2 */ + xfs_bmbt_irec_t *r1, /* inserted record 1 */ + xfs_bmbt_irec_t *r2, /* inserted record 2 or null */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t tr1; /* compressed record 1 */ + xfs_bmbt_rec_t tr2; /* compressed record 2 if needed */ + + xfs_bmbt_set_all(&tr1, r1); + if (cnt == 2) { + ASSERT(r2 != NULL); + xfs_bmbt_set_all(&tr2, r2); + } else { + ASSERT(cnt == 1); + ASSERT(r2 == NULL); + } + xfs_bmap_trace_addentry(XFS_BMAP_KTRACE_INSERT, fname, desc, ip, idx, + cnt, &tr1, cnt == 2 ? &tr2 : NULL, whichfork); +} + +/* + * Add bmap trace entry after updating an extent list entry in place. + */ +STATIC void +xfs_bmap_trace_post_update( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry updated */ + int whichfork) /* data or attr fork */ +{ + xfs_ifork_t *ifp; /* inode fork pointer */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + xfs_bmap_trace_addentry(XFS_BMAP_KTRACE_POST_UP, fname, desc, ip, idx, + 1, &ifp->if_u1.if_extents[idx], NULL, whichfork); +} + +/* + * Add bmap trace entry prior to updating an extent list entry in place. + */ +STATIC void +xfs_bmap_trace_pre_update( + char *fname, /* function name */ + char *desc, /* operation description */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t idx, /* index of entry to be updated */ + int whichfork) /* data or attr fork */ +{ + xfs_ifork_t *ifp; /* inode fork pointer */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + xfs_bmap_trace_addentry(XFS_BMAP_KTRACE_PRE_UP, fname, desc, ip, idx, 1, + &ifp->if_u1.if_extents[idx], NULL, whichfork); +} +#endif /* XFS_BMAP_TRACE */ + +/* + * Compute the worst-case number of indirect blocks that will be used + * for ip's delayed extent of length "len". + */ +STATIC xfs_filblks_t +xfs_bmap_worst_indlen( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_filblks_t len) /* delayed extent length */ +{ + int level; /* btree level number */ + int maxrecs; /* maximum record count at this level */ + xfs_mount_t *mp; /* mount structure */ + xfs_filblks_t rval; /* return value */ + + mp = ip->i_mount; + maxrecs = mp->m_bmap_dmxr[0]; + for (level = 0, rval = 0; + level < XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK); + level++) { + len += maxrecs - 1; + do_div(len, maxrecs); + rval += len; + if (len == 1) + return rval + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - + level - 1; + if (level == 0) + maxrecs = mp->m_bmap_dmxr[1]; + } + return rval; +} + +#if defined(DEBUG) && defined(XFS_RW_TRACE) +STATIC void +xfs_bunmap_trace( + xfs_inode_t *ip, + xfs_fileoff_t bno, + xfs_filblks_t len, + int flags, + inst_t *ra) +{ + if (ip->i_rwtrace == NULL) + return; + ktrace_enter(ip->i_rwtrace, + (void *)(__psint_t)XFS_BUNMAPI, + (void *)ip, + (void *)(__psint_t)((ip->i_d.di_size >> 32) & 0xffffffff), + (void *)(__psint_t)(ip->i_d.di_size & 0xffffffff), + (void *)(__psint_t)(((xfs_dfiloff_t)bno >> 32) & 0xffffffff), + (void *)(__psint_t)((xfs_dfiloff_t)bno & 0xffffffff), + (void *)(__psint_t)len, + (void *)(__psint_t)flags, + (void *)(__psint_t)private.p_cpuid, + (void *)ra, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0); +} +#endif + +/* + * Convert inode from non-attributed to attributed. + * Must not be in a transaction, ip must not be locked. + */ +int /* error code */ +xfs_bmap_add_attrfork( + xfs_inode_t *ip, /* incore inode pointer */ + int rsvd) /* OK to allocated reserved blocks in trans */ +{ + int blks; /* space reservation */ + int committed; /* xaction was committed */ + int error; /* error return value */ + xfs_fsblock_t firstblock; /* 1st block/ag allocated */ + xfs_bmap_free_t flist; /* freed extent list */ + int logflags; /* logging flags */ + xfs_mount_t *mp; /* mount structure */ + int s; /* spinlock spl value */ + xfs_trans_t *tp; /* transaction pointer */ + + ASSERT(ip->i_df.if_ext_max == + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t)); + if (XFS_IFORK_Q(ip)) + return 0; + mp = ip->i_mount; + ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); + tp = xfs_trans_alloc(mp, XFS_TRANS_ADDAFORK); + blks = XFS_ADDAFORK_SPACE_RES(mp); + if (rsvd) + tp->t_flags |= XFS_TRANS_RESERVE; + if ((error = xfs_trans_reserve(tp, blks, XFS_ADDAFORK_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_ADDAFORK_LOG_COUNT))) + goto error0; + xfs_ilock(ip, XFS_ILOCK_EXCL); + if (XFS_IS_QUOTA_ON(mp) && + (error = xfs_trans_reserve_blkquota(tp, ip, blks))) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES); + return error; + } + if (XFS_IFORK_Q(ip)) + goto error1; + if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS) { + /* + * For inodes coming from pre-6.2 filesystems. + */ + ASSERT(ip->i_d.di_aformat == 0); + ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; + } + ASSERT(ip->i_d.di_anextents == 0); + VN_HOLD(XFS_ITOV(ip)); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + switch (ip->i_d.di_format) { + case XFS_DINODE_FMT_DEV: + ip->i_d.di_forkoff = roundup(sizeof(dev_t), 8) >> 3; + break; + case XFS_DINODE_FMT_UUID: + ip->i_d.di_forkoff = roundup(sizeof(uuid_t), 8) >> 3; + break; + case XFS_DINODE_FMT_LOCAL: + case XFS_DINODE_FMT_EXTENTS: + case XFS_DINODE_FMT_BTREE: + ip->i_d.di_forkoff = mp->m_attroffset >> 3; + break; + default: + ASSERT(0); + error = XFS_ERROR(EINVAL); + goto error1; + } + ip->i_df.if_ext_max = + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + ASSERT(ip->i_afp == NULL); + ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP); + ip->i_afp->if_ext_max = + XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + ip->i_afp->if_flags = XFS_IFEXTENTS; + logflags = 0; + XFS_BMAP_INIT(&flist, &firstblock); + switch (ip->i_d.di_format) { + case XFS_DINODE_FMT_LOCAL: + error = xfs_bmap_add_attrfork_local(tp, ip, &firstblock, &flist, + &logflags); + break; + case XFS_DINODE_FMT_EXTENTS: + error = xfs_bmap_add_attrfork_extents(tp, ip, &firstblock, + &flist, &logflags); + break; + case XFS_DINODE_FMT_BTREE: + error = xfs_bmap_add_attrfork_btree(tp, ip, &firstblock, &flist, + &logflags); + break; + default: + error = 0; + break; + } + if (logflags) + xfs_trans_log_inode(tp, ip, logflags); + if (error) + goto error2; + if (!XFS_SB_VERSION_HASATTR(&mp->m_sb)) { + s = XFS_SB_LOCK(mp); + if (!XFS_SB_VERSION_HASATTR(&mp->m_sb)) { + XFS_SB_VERSION_ADDATTR(&mp->m_sb); + XFS_SB_UNLOCK(mp, s); + xfs_mod_sb(tp, XFS_SB_VERSIONNUM); + } else + XFS_SB_UNLOCK(mp, s); + } + if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) + goto error2; + error = xfs_trans_commit(tp, XFS_TRANS_PERM_LOG_RES, NULL); + ASSERT(ip->i_df.if_ext_max == + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t)); + return error; +error2: + xfs_bmap_cancel(&flist); +error1: + ASSERT(ismrlocked(&ip->i_lock,MR_UPDATE)); + xfs_iunlock(ip, XFS_ILOCK_EXCL); +error0: + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); + ASSERT(ip->i_df.if_ext_max == + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t)); + return error; +} + +/* + * Add the extent to the list of extents to be free at transaction end. + * The list is maintained sorted (by block number). + */ +/* ARGSUSED */ +void +xfs_bmap_add_free( + xfs_fsblock_t bno, /* fs block number of extent */ + xfs_filblks_t len, /* length of extent */ + xfs_bmap_free_t *flist, /* list of extents */ + xfs_mount_t *mp) /* mount point structure */ +{ + xfs_bmap_free_item_t *cur; /* current (next) element */ + xfs_bmap_free_item_t *new; /* new element */ + xfs_bmap_free_item_t *prev; /* previous element */ +#ifdef DEBUG + xfs_agnumber_t agno; + xfs_agblock_t agbno; + + ASSERT(bno != NULLFSBLOCK); + ASSERT(len > 0); + ASSERT(len <= MAXEXTLEN); + ASSERT(!ISNULLSTARTBLOCK(bno)); + agno = XFS_FSB_TO_AGNO(mp, bno); + agbno = XFS_FSB_TO_AGBNO(mp, bno); + ASSERT(agno < mp->m_sb.sb_agcount); + ASSERT(agbno < mp->m_sb.sb_agblocks); + ASSERT(len < mp->m_sb.sb_agblocks); + ASSERT(agbno + len <= mp->m_sb.sb_agblocks); +#endif + ASSERT(xfs_bmap_free_item_zone != NULL); + new = kmem_zone_alloc(xfs_bmap_free_item_zone, KM_SLEEP); + new->xbfi_startblock = bno; + new->xbfi_blockcount = (xfs_extlen_t)len; + for (prev = NULL, cur = flist->xbf_first; + cur != NULL; + prev = cur, cur = cur->xbfi_next) { + if (cur->xbfi_startblock >= bno) + break; + } + if (prev) + prev->xbfi_next = new; + else + flist->xbf_first = new; + new->xbfi_next = cur; + flist->xbf_count++; +} + +/* + * Compute and fill in the value of the maximum depth of a bmap btree + * in this filesystem. Done once, during mount. + */ +void +xfs_bmap_compute_maxlevels( + xfs_mount_t *mp, /* file system mount structure */ + int whichfork) /* data or attr fork */ +{ + int level; /* btree level */ + uint maxblocks; /* max blocks at this level */ + uint maxleafents; /* max leaf entries possible */ + int maxrootrecs; /* max records in root block */ + int minleafrecs; /* min records in leaf block */ + int minnoderecs; /* min records in node block */ + int sz; /* root block size */ + + /* + * The maximum number of extents in a file, hence the maximum + * number of leaf entries, is controlled by the type of di_nextents + * (a signed 32-bit number, xfs_extnum_t), or by di_anextents + * (a signed 16-bit number, xfs_aextnum_t). + */ + maxleafents = (whichfork == XFS_DATA_FORK) ? MAXEXTNUM : MAXAEXTNUM; + minleafrecs = mp->m_bmap_dmnr[0]; + minnoderecs = mp->m_bmap_dmnr[1]; + sz = (whichfork == XFS_DATA_FORK) ? + mp->m_attroffset : + mp->m_sb.sb_inodesize - mp->m_attroffset; + maxrootrecs = (int)XFS_BTREE_BLOCK_MAXRECS(sz, xfs_bmdr, 0); + maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; + for (level = 1; maxblocks > 1; level++) { + if (maxblocks <= maxrootrecs) + maxblocks = 1; + else + maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; + } + mp->m_bm_maxlevels[whichfork] = level; +} + +/* + * Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi + * caller. Frees all the extents that need freeing, which must be done + * last due to locking considerations. We never free any extents in + * the first transaction. This is to allow the caller to make the first + * transaction a synchronous one so that the pointers to the data being + * broken in this transaction will be permanent before the data is actually + * freed. This is necessary to prevent blocks from being reallocated + * and written to before the free and reallocation are actually permanent. + * We do not just make the first transaction synchronous here, because + * there are more efficient ways to gain the same protection in some cases + * (see the file truncation code). + * + * Return 1 if the given transaction was committed and a new one + * started, and 0 otherwise in the committed parameter. + */ +/*ARGSUSED*/ +int /* error */ +xfs_bmap_finish( + xfs_trans_t **tp, /* transaction pointer addr */ + xfs_bmap_free_t *flist, /* i/o: list extents to free */ + xfs_fsblock_t firstblock, /* controlled ag for allocs */ + int *committed) /* xact committed or not */ +{ + xfs_efd_log_item_t *efd; /* extent free data */ + xfs_efi_log_item_t *efi; /* extent free intention */ + int error; /* error return value */ + xfs_bmap_free_item_t *free; /* free extent list item */ + unsigned int logres; /* new log reservation */ + unsigned int logcount; /* new log count */ + xfs_mount_t *mp; /* filesystem mount structure */ + xfs_bmap_free_item_t *next; /* next item on free list */ + xfs_trans_t *ntp; /* new transaction pointer */ + + ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES); + if (flist->xbf_count == 0) { + *committed = 0; + return 0; + } + ntp = *tp; + efi = xfs_trans_get_efi(ntp, flist->xbf_count); + for (free = flist->xbf_first; free; free = free->xbfi_next) + xfs_trans_log_efi_extent(ntp, efi, free->xbfi_startblock, + free->xbfi_blockcount); + logres = ntp->t_log_res; + logcount = ntp->t_log_count; + ntp = xfs_trans_dup(*tp); + error = xfs_trans_commit(*tp, 0, NULL); + *tp = ntp; + *committed = 1; + /* + * We have a new transaction, so we should return committed=1, + * even though we're returning an error. + */ + if (error) { + return error; + } + if ((error = xfs_trans_reserve(ntp, 0, logres, 0, XFS_TRANS_PERM_LOG_RES, + logcount))) + return error; + efd = xfs_trans_get_efd(ntp, efi, flist->xbf_count); + for (free = flist->xbf_first; free != NULL; free = next) { + next = free->xbfi_next; + if ((error = xfs_free_extent(ntp, free->xbfi_startblock, + free->xbfi_blockcount))) { + /* + * The bmap free list will be cleaned up at a + * higher level. The EFI will be canceled when + * this transaction is aborted. + * Need to force shutdown here to make sure it + * happens, since this transaction may not be + * dirty yet. + */ + mp = ntp->t_mountp; + if (!XFS_FORCED_SHUTDOWN(mp)) + xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR); + return error; + } + xfs_trans_log_efd_extent(ntp, efd, free->xbfi_startblock, + free->xbfi_blockcount); + xfs_bmap_del_free(flist, NULL, free); + } + return 0; +} + +/* + * Free up any items left in the list. + */ +void +xfs_bmap_cancel( + xfs_bmap_free_t *flist) /* list of bmap_free_items */ +{ + xfs_bmap_free_item_t *free; /* free list item */ + xfs_bmap_free_item_t *next; + + if (flist->xbf_count == 0) + return; + ASSERT(flist->xbf_first != NULL); + for (free = flist->xbf_first; free; free = next) { + next = free->xbfi_next; + xfs_bmap_del_free(flist, NULL, free); + } + ASSERT(flist->xbf_count == 0); +} + +/* + * Returns EINVAL if the specified file is not swappable. + */ +int /* error */ +xfs_bmap_check_swappable( + xfs_inode_t *ip) /* incore inode */ +{ + xfs_bmbt_rec_t *base; /* base of extent array */ + xfs_bmbt_rec_t *ep; /* pointer to an extent entry */ + xfs_fileoff_t end_fsb; /* last block of file within size */ + xfs_bmbt_irec_t ext; /* extent list entry, decoded */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_fileoff_t lastaddr; /* last block number seen */ + xfs_extnum_t nextents; /* number of extent entries */ + int retval = 0; /* return value */ + + xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + + /* + * Check for a zero length file. + */ + if (ip->i_d.di_size == 0) + goto check_done; + + ASSERT(XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_BTREE || + XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) == XFS_DINODE_FMT_EXTENTS); + + ifp = &ip->i_df; + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (retval = xfs_iread_extents(NULL, ip, XFS_DATA_FORK))) + goto check_done; + /* + * Scan extents until the file size is reached. Look for + * holes or unwritten extents, since I/O to these would cause + * a transaction. + */ + end_fsb = XFS_B_TO_FSB(ip->i_mount, ip->i_d.di_size); + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + base = &ifp->if_u1.if_extents[0]; + for (lastaddr = 0, ep = base; ep < &base[nextents]; ep++) { + xfs_bmbt_get_all(ep, &ext); + if (lastaddr < ext.br_startoff || + ext.br_state != XFS_EXT_NORM) { + goto error_done; + } + if (end_fsb <= (lastaddr = ext.br_startoff + + ext.br_blockcount)) + goto check_done; + } +error_done: + retval = XFS_ERROR(EINVAL); + + +check_done: + xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + return retval; +} + +/* + * Returns the file-relative block number of the first unused block(s) + * in the file with at least "len" logically contiguous blocks free. + * This is the lowest-address hole if the file has holes, else the first block + * past the end of file. + * Return 0 if the file is currently local (in-inode). + */ +int /* error */ +xfs_bmap_first_unused( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + xfs_extlen_t len, /* size of hole to find */ + xfs_fileoff_t *first_unused, /* unused block */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* base of extent array */ + xfs_bmbt_rec_t *ep; /* pointer to an extent entry */ + int error; /* error return value */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_fileoff_t lastaddr; /* last block number seen */ + xfs_fileoff_t lowest; /* lowest useful block */ + xfs_fileoff_t max; /* starting useful block */ + xfs_fileoff_t off; /* offset for this block */ + xfs_extnum_t nextents; /* number of extent entries */ + + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE || + XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS || + XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + *first_unused = 0; + return 0; + } + ifp = XFS_IFORK_PTR(ip, whichfork); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + lowest = *first_unused; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + base = &ifp->if_u1.if_extents[0]; + for (lastaddr = 0, max = lowest, ep = base; + ep < &base[nextents]; + ep++) { + off = xfs_bmbt_get_startoff(ep); + /* + * See if the hole before this extent will work. + */ + if (off >= lowest + len && off - max >= len) { + *first_unused = max; + return 0; + } + lastaddr = off + xfs_bmbt_get_blockcount(ep); + max = XFS_FILEOFF_MAX(lastaddr, lowest); + } + *first_unused = max; + return 0; +} + +/* + * Returns the file-relative block number of the last block + 1 before + * last_block (input value) in the file. + * This is not based on i_size, it is based on the extent list. + * Returns 0 for local files, as they do not have an extent list. + */ +int /* error */ +xfs_bmap_last_before( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + xfs_fileoff_t *last_block, /* last block */ + int whichfork) /* data or attr fork */ +{ + xfs_fileoff_t bno; /* input file offset */ + int eof; /* hit end of file */ + xfs_bmbt_rec_t *ep; /* pointer to last extent */ + int error; /* error return value */ + xfs_bmbt_irec_t got; /* current extent value */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t lastx; /* last extent used */ + xfs_bmbt_irec_t prev; /* previous extent value */ + + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) + return XFS_ERROR(EIO); + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + *last_block = 0; + return 0; + } + ifp = XFS_IFORK_PTR(ip, whichfork); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + bno = *last_block - 1; + ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, + &prev); + if (eof || xfs_bmbt_get_startoff(ep) > bno) { + if (prev.br_startoff == NULLFILEOFF) + *last_block = 0; + else + *last_block = prev.br_startoff + prev.br_blockcount; + } + /* + * Otherwise *last_block is already the right answer. + */ + return 0; +} + +/* + * Returns the file-relative block number of the first block past eof in + * the file. This is not based on i_size, it is based on the extent list. + * Returns 0 for local files, as they do not have an extent list. + */ +int /* error */ +xfs_bmap_last_offset( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + xfs_fileoff_t *last_block, /* last block */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* base of extent array */ + xfs_bmbt_rec_t *ep; /* pointer to last extent */ + int error; /* error return value */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t nextents; /* number of extent entries */ + + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) + return XFS_ERROR(EIO); + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + *last_block = 0; + return 0; + } + ifp = XFS_IFORK_PTR(ip, whichfork); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + if (!nextents) { + *last_block = 0; + return 0; + } + base = &ifp->if_u1.if_extents[0]; + ASSERT(base != NULL); + ep = &base[nextents - 1]; + *last_block = xfs_bmbt_get_startoff(ep) + xfs_bmbt_get_blockcount(ep); + return 0; +} + +/* + * Returns whether the selected fork of the inode has exactly one + * block or not. For the data fork we check this matches di_size, + * implying the file's range is 0..bsize-1. + */ +int /* 1=>1 block, 0=>otherwise */ +xfs_bmap_one_block( + xfs_inode_t *ip, /* incore inode */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *ep; /* ptr to fork's extent */ + xfs_ifork_t *ifp; /* inode fork pointer */ + int rval; /* return value */ + xfs_bmbt_irec_t s; /* internal version of extent */ + +#ifndef DEBUG + if (whichfork == XFS_DATA_FORK) + return ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize; +#endif /* !DEBUG */ + if (XFS_IFORK_NEXTENTS(ip, whichfork) != 1) + return 0; + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) + return 0; + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_flags & XFS_IFEXTENTS); + ep = ifp->if_u1.if_extents; + xfs_bmbt_get_all(ep, &s); + rval = s.br_startoff == 0 && s.br_blockcount == 1; + if (rval && whichfork == XFS_DATA_FORK) + ASSERT(ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize); + return rval; +} + +/* + * Read in the extents to if_extents. + * All inode fields are set up by caller, we just traverse the btree + * and copy the records in. If the file system cannot contain unwritten + * extents, the records are checked for no "state" flags. + */ +int /* error */ +xfs_bmap_read_extents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_block_t *block; /* current btree block */ + xfs_fsblock_t bno; /* block # of "block" */ + xfs_buf_t *bp; /* buffer for "block" */ + int error; /* error return value */ + xfs_exntfmt_t exntf; /* XFS_EXTFMT_NOSTATE, if checking */ +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_bmap_read_extents"; +#endif + xfs_extnum_t i; /* index into the extents list */ + xfs_ifork_t *ifp; /* fork structure */ + int level; /* btree level, for checking */ + xfs_mount_t *mp; /* file system mount structure */ + xfs_bmbt_ptr_t *pp; /* pointer to block address */ + /* REFERENCED */ + xfs_extnum_t room; /* number of entries there's room for */ + xfs_bmbt_rec_t *trp; /* target record pointer */ + + bno = NULLFSBLOCK; + mp = ip->i_mount; + ifp = XFS_IFORK_PTR(ip, whichfork); + exntf = (whichfork != XFS_DATA_FORK) ? XFS_EXTFMT_NOSTATE : + XFS_EXTFMT_INODE(ip); + block = ifp->if_broot; + /* + * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out. + */ + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + level = INT_GET(block->bb_level, ARCH_CONVERT); + pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes); + ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO); + ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount); + ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks); + bno = INT_GET(*pp, ARCH_CONVERT); + /* + * Go down the tree until leaf level is reached, following the first + * pointer (leftmost) at each level. + */ + while (level-- > 0) { + if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, + XFS_BMAP_BTREE_REF))) + return error; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + XFS_WANT_CORRUPTED_GOTO( + XFS_BMAP_SANITY_CHECK(mp, block, level), + error0); + if (level == 0) + break; + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, + 1, mp->m_bmap_dmxr[1]); + XFS_WANT_CORRUPTED_GOTO(XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)), error0); + bno = INT_GET(*pp, ARCH_CONVERT); + xfs_trans_brelse(tp, bp); + } + /* + * Here with bp and block set to the leftmost leaf node in the tree. + */ + room = ifp->if_bytes / (uint)sizeof(*trp); + trp = ifp->if_u1.if_extents; + i = 0; + /* + * Loop over all leaf nodes. Copy information to the extent list. + */ + for (;;) { + xfs_bmbt_rec_t *frp; + xfs_fsblock_t nextbno; + xfs_extnum_t num_recs; + + + num_recs = INT_GET(block->bb_numrecs, ARCH_CONVERT); + if (i + num_recs > room) { + ASSERT(i + num_recs <= room); + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt dinode %Lu, (btree extents). Unmount and run xfs_repair.", + ip->i_ino); + goto error0; + } + XFS_WANT_CORRUPTED_GOTO( + XFS_BMAP_SANITY_CHECK(mp, block, 0), + error0); + /* + * Read-ahead the next leaf block, if any. + */ + nextbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + if (nextbno != NULLFSBLOCK) + xfs_btree_reada_bufl(mp, nextbno, 1); + /* + * Copy records into the extent list. + */ + frp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, + block, 1, mp->m_bmap_dmxr[0]); + bcopy(frp, trp, num_recs * sizeof(*frp)); + if (exntf == XFS_EXTFMT_NOSTATE) { + /* + * Check all attribute bmap btree records and + * any "older" data bmap btree records for a + * set bit in the "extent flag" position. + */ + if (xfs_check_nostate_extents(trp, num_recs)) { + goto error0; + } + } + trp += num_recs; + i += num_recs; + xfs_trans_brelse(tp, bp); + bno = nextbno; + /* + * If we've reached the end, stop. + */ + if (bno == NULLFSBLOCK) + break; + if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, + XFS_BMAP_BTREE_REF))) + return error; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + } + ASSERT(i == ifp->if_bytes / (uint)sizeof(*trp)); + ASSERT(i == XFS_IFORK_NEXTENTS(ip, whichfork)); + xfs_bmap_trace_exlist(fname, ip, i, whichfork); + return 0; +error0: + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EFSCORRUPTED); +} + +#ifdef XFS_BMAP_TRACE +/* + * Add bmap trace insert entries for all the contents of the extent list. + */ +void +xfs_bmap_trace_exlist( + char *fname, /* function name */ + xfs_inode_t *ip, /* incore inode pointer */ + xfs_extnum_t cnt, /* count of entries in the list */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* base of extent list */ + xfs_bmbt_rec_t *ep; /* current entry in extent list */ + xfs_extnum_t idx; /* extent list entry number */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_irec_t s; /* extent list record */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(cnt == ifp->if_bytes / (uint)sizeof(*base)); + base = ifp->if_u1.if_extents; + for (idx = 0, ep = base; idx < cnt; idx++, ep++) { + xfs_bmbt_get_all(ep, &s); + xfs_bmap_trace_insert(fname, "exlist", ip, idx, 1, &s, NULL, + whichfork); + } +} +#endif + +#ifdef DEBUG +/* + * Validate that the bmbt_irecs being returned from bmapi are valid + * given the callers original parameters. Specifically check the + * ranges of the returned irecs to ensure that they only extent beyond + * the given parameters if the XFS_BMAPI_ENTIRE flag was set. + */ +STATIC void +xfs_bmap_validate_ret( + xfs_fileoff_t bno, + xfs_filblks_t len, + int flags, + xfs_bmbt_irec_t *mval, + int nmap, + int ret_nmap) +{ + int i; /* index to map values */ + + ASSERT(ret_nmap <= nmap); + + for (i = 0; i < ret_nmap; i++) { + ASSERT(mval[i].br_blockcount > 0); + if (!(flags & XFS_BMAPI_ENTIRE)) { + ASSERT(mval[i].br_startoff >= bno); + ASSERT(mval[i].br_blockcount <= len); + ASSERT(mval[i].br_startoff + mval[i].br_blockcount <= + bno + len); + } else { + ASSERT(mval[i].br_startoff < bno + len); + ASSERT(mval[i].br_startoff + mval[i].br_blockcount > + bno); + } + ASSERT(i == 0 || + mval[i - 1].br_startoff + mval[i - 1].br_blockcount == + mval[i].br_startoff); + if ((flags & XFS_BMAPI_WRITE) && !(flags & XFS_BMAPI_DELAY)) + ASSERT(mval[i].br_startblock != DELAYSTARTBLOCK && + mval[i].br_startblock != HOLESTARTBLOCK); + ASSERT(mval[i].br_state == XFS_EXT_NORM || + mval[i].br_state == XFS_EXT_UNWRITTEN); + } +} +#endif /* DEBUG */ + + +/* + * Map file blocks to filesystem blocks. + * File range is given by the bno/len pair. + * Adds blocks to file if a write ("flags & XFS_BMAPI_WRITE" set) + * into a hole or past eof. + * Only allocates blocks from a single allocation group, + * to avoid locking problems. + * The returned value in "firstblock" from the first call in a transaction + * must be remembered and presented to subsequent calls in "firstblock". + * An upper bound for the number of blocks to be allocated is supplied to + * the first call in "total"; if no allocation group has that many free + * blocks then the call will fail (return NULLFSBLOCK in "firstblock"). + */ +int /* error */ +xfs_bmapi( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + xfs_fileoff_t bno, /* starting file offs. mapped */ + xfs_filblks_t len, /* length to map in file */ + int flags, /* XFS_BMAPI_... */ + xfs_fsblock_t *firstblock, /* first allocated block + controls a.g. for allocs */ + xfs_extlen_t total, /* total blocks needed */ + xfs_bmbt_irec_t *mval, /* output: map values */ + int *nmap, /* i/o: mval size/count */ + xfs_bmap_free_t *flist) /* i/o: list extents to free */ +{ + xfs_fsblock_t abno; /* allocated block number */ + xfs_extlen_t alen; /* allocated extent length */ + xfs_fileoff_t aoff; /* allocated file offset */ + xfs_bmalloca_t bma; /* args for xfs_bmap_alloc */ + int contig; /* allocation must be one extent */ + xfs_btree_cur_t *cur; /* bmap btree cursor */ + char delay; /* this request is for delayed alloc */ + xfs_fileoff_t end; /* end of mapped file region */ + int eof; /* we've hit the end of extent list */ + xfs_bmbt_rec_t *ep; /* extent list entry pointer */ + int error; /* error return */ + char exact; /* don't do all of wasdelayed extent */ + xfs_bmbt_irec_t got; /* current extent list record */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extlen_t indlen; /* indirect blocks length */ + char inhole; /* current location is hole in file */ + xfs_extnum_t lastx; /* last useful extent number */ + int logflags; /* flags for transaction logging */ + xfs_extlen_t minleft; /* min blocks left after allocation */ + xfs_extlen_t minlen; /* min allocation size */ + xfs_mount_t *mp; /* xfs mount structure */ + int n; /* current extent index */ + int nallocs; /* number of extents alloc\'d */ + xfs_extnum_t nextents; /* number of extents in file */ + xfs_fileoff_t obno; /* old block number (offset) */ + xfs_bmbt_irec_t prev; /* previous extent list record */ + int stateless; /* ignore state flag set */ + int tmp_logflags; /* temp flags holder */ + char trim; /* output trimmed to match range */ + char userdata; /* allocating non-metadata */ + char wasdelay; /* old extent was delayed */ + int whichfork; /* data or attr fork */ + char wr; /* this is a write request */ + int rsvd; /* OK to allocate reserved blocks */ +#ifdef DEBUG + xfs_fileoff_t orig_bno; /* original block number value */ + int orig_flags; /* original flags arg value */ + xfs_filblks_t orig_len; /* original value of len arg */ + xfs_bmbt_irec_t *orig_mval; /* original value of mval */ + int orig_nmap; /* original value of *nmap */ + + orig_bno = bno; + orig_len = len; + orig_flags = flags; + orig_mval = mval; + orig_nmap = *nmap; +#endif + ASSERT(*nmap >= 1); + ASSERT(*nmap <= XFS_BMAP_MAX_NMAP || !(flags & XFS_BMAPI_WRITE)); + whichfork = (flags & XFS_BMAPI_ATTRFORK) ? + XFS_ATTR_FORK : XFS_DATA_FORK; + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) + return XFS_ERROR(EFSCORRUPTED); + mp = ip->i_mount; + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + if ((wr = (flags & XFS_BMAPI_WRITE)) != 0) + XFS_STATS_INC(xfsstats.xs_blk_mapw); + else + XFS_STATS_INC(xfsstats.xs_blk_mapr); + delay = (flags & XFS_BMAPI_DELAY) != 0; + trim = (flags & XFS_BMAPI_ENTIRE) == 0; + userdata = (flags & XFS_BMAPI_METADATA) == 0; + exact = (flags & XFS_BMAPI_EXACT) != 0; + rsvd = (flags & XFS_BMAPI_RSVBLOCKS) != 0; + contig = (flags & XFS_BMAPI_CONTIG) != 0; + /* + * stateless is used to combine extents which + * differ only due to the state of the extents. + * This technique is used from xfs_getbmap() + * when the caller does not wish to see the + * separation (which is the default). + * + * This technique is also used when writing a + * buffer which has been partially written, + * (usually by being flushed during a chunkread), + * to ensure one write takes place. This also + * prevents a change in the xfs inode extents at + * this time, intentionally. This change occurs + * on completion of the write operation, in + * xfs_strat_comp(), where the xfs_bmapi() call + * is transactioned, and the extents combined. + */ + stateless = (flags & XFS_BMAPI_IGSTATE) != 0; + if (stateless && wr) /* if writing unwritten space, no */ + wr = 0; /* allocations are allowed */ + ASSERT(wr || !delay); + logflags = 0; + nallocs = 0; + cur = NULL; + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + ASSERT(wr && tp); + if ((error = xfs_bmap_local_to_extents(tp, ip, firstblock, total, + &logflags, whichfork))) + goto error0; + } + if (wr && *firstblock == NULLFSBLOCK) { + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE) + minleft = INT_GET(ifp->if_broot->bb_level, ARCH_CONVERT) + 1; + else + minleft = 1; + } else + minleft = 0; + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + goto error0; + ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, + &prev); + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + n = 0; + end = bno + len; + obno = bno; + bma.ip = NULL; + while (bno < end && n < *nmap) { + /* + * Reading past eof, act as though there's a hole + * up to end. + */ + if (eof && !wr) + got.br_startoff = end; + inhole = eof || got.br_startoff > bno; + wasdelay = wr && !inhole && !delay && + ISNULLSTARTBLOCK(got.br_startblock); + /* + * First, deal with the hole before the allocated space + * that we found, if any. + */ + if (wr && (inhole || wasdelay)) { + /* + * For the wasdelay case, we could also just + * allocate the stuff asked for in this bmap call + * but that wouldn't be as good. + */ + if (wasdelay && !exact) { + alen = (xfs_extlen_t)got.br_blockcount; + aoff = got.br_startoff; + if (lastx != NULLEXTNUM && lastx) { + ep = &ifp->if_u1.if_extents[lastx - 1]; + xfs_bmbt_get_all(ep, &prev); + } + } else if (wasdelay) { + alen = (xfs_extlen_t) + XFS_FILBLKS_MIN(len, + (got.br_startoff + + got.br_blockcount) - bno); + aoff = bno; + } else { + alen = (xfs_extlen_t) + XFS_FILBLKS_MIN(len, MAXEXTLEN); + if (!eof) + alen = (xfs_extlen_t) + XFS_FILBLKS_MIN(alen, + got.br_startoff - bno); + aoff = bno; + } + minlen = contig ? alen : 1; + if (delay) { + indlen = (xfs_extlen_t) + xfs_bmap_worst_indlen(ip, alen); + ASSERT(indlen > 0); + /* + * Make a transaction-less quota reservation for + * delayed allocation blocks. This number gets + * adjusted later. + * We return EDQUOT if we haven't allocated + * blks already inside this loop; + */ + if (XFS_IS_QUOTA_ON(ip->i_mount) && + xfs_trans_reserve_blkquota(NULL, ip, + (long)alen)) { + if (n == 0) { + *nmap = 0; + ASSERT(cur == NULL); + return XFS_ERROR(EDQUOT); + } + break; + } + if (xfs_mod_incore_sb(ip->i_mount, + XFS_SBS_FDBLOCKS, + -(alen + indlen), rsvd)) { + if (XFS_IS_QUOTA_ON(ip->i_mount)) + xfs_trans_unreserve_blkquota( + NULL, ip, (long)alen); + break; + } + ip->i_delayed_blks += alen; + abno = NULLSTARTBLOCK(indlen); + } else { + /* + * If first time, allocate and fill in + * once-only bma fields. + */ + if (bma.ip == NULL) { + bma.tp = tp; + bma.ip = ip; + bma.prevp = &prev; + bma.gotp = &got; + bma.total = total; + bma.userdata = userdata; + } + /* + * Fill in changeable bma fields. + */ + bma.eof = eof; + bma.firstblock = *firstblock; + bma.alen = alen; + bma.off = aoff; + bma.wasdel = wasdelay; + bma.minlen = minlen; + bma.low = flist->xbf_low; + bma.minleft = minleft; + /* + * Only want to do the alignment at the + * eof if it is userdata and allocation length + * is larger than a stripe unit. + */ + if (mp->m_dalign && alen >= mp->m_dalign && + userdata && whichfork == XFS_DATA_FORK) { + if ((error = xfs_bmap_isaeof(ip, aoff, + whichfork, &bma.aeof))) + goto error0; + } else + bma.aeof = 0; + /* + * Call allocator. + */ + if ((error = xfs_bmap_alloc(&bma))) + goto error0; + /* + * Copy out result fields. + */ + abno = bma.rval; + if ((flist->xbf_low = bma.low)) + minleft = 0; + alen = bma.alen; + aoff = bma.off; + ASSERT(*firstblock == NULLFSBLOCK || + XFS_FSB_TO_AGNO(ip->i_mount, + *firstblock) == + XFS_FSB_TO_AGNO(ip->i_mount, + bma.firstblock) || + (flist->xbf_low && + XFS_FSB_TO_AGNO(ip->i_mount, + *firstblock) < + XFS_FSB_TO_AGNO(ip->i_mount, + bma.firstblock))); + *firstblock = bma.firstblock; + if (cur) + cur->bc_private.b.firstblock = + *firstblock; + if (abno == NULLFSBLOCK) + break; + if ((ifp->if_flags & XFS_IFBROOT) && !cur) { + cur = xfs_btree_init_cursor(ip->i_mount, + tp, NULL, 0, XFS_BTNUM_BMAP, + ip, whichfork); + cur->bc_private.b.firstblock = + *firstblock; + cur->bc_private.b.flist = flist; + } + /* + * Bump the number of extents we've allocated + * in this call. + */ + nallocs++; + } + if (cur) + cur->bc_private.b.flags = + wasdelay ? XFS_BTCUR_BPRV_WASDEL : 0; + got.br_startoff = aoff; + got.br_startblock = abno; + got.br_blockcount = alen; + got.br_state = XFS_EXT_NORM; /* assume normal */ + /* + * Determine state of extent, and the filesystem. + * A wasdelay extent has been initialized, so + * shouldn't be flagged as unwritten. + */ + if (wr && XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) { + if (!wasdelay && (flags & XFS_BMAPI_PREALLOC)) + got.br_state = XFS_EXT_UNWRITTEN; + } + error = xfs_bmap_add_extent(ip, lastx, &cur, &got, + firstblock, flist, &tmp_logflags, whichfork, + rsvd); + logflags |= tmp_logflags; + if (error) + goto error0; + lastx = ifp->if_lastex; + ep = &ifp->if_u1.if_extents[lastx]; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + xfs_bmbt_get_all(ep, &got); + ASSERT(got.br_startoff <= aoff); + ASSERT(got.br_startoff + got.br_blockcount >= + aoff + alen); +#ifdef DEBUG + if (delay) { + ASSERT(ISNULLSTARTBLOCK(got.br_startblock)); + ASSERT(STARTBLOCKVAL(got.br_startblock) > 0); + } + ASSERT(got.br_state == XFS_EXT_NORM || + got.br_state == XFS_EXT_UNWRITTEN); +#endif + /* + * Fall down into the found allocated space case. + */ + } else if (inhole) { + /* + * Reading in a hole. + */ + mval->br_startoff = bno; + mval->br_startblock = HOLESTARTBLOCK; + mval->br_blockcount = + XFS_FILBLKS_MIN(len, got.br_startoff - bno); + mval->br_state = XFS_EXT_NORM; + bno += mval->br_blockcount; + len -= mval->br_blockcount; + mval++; + n++; + continue; + } + /* + * Then deal with the allocated space we found. + */ + ASSERT(ep != NULL); + if (trim && (got.br_startoff + got.br_blockcount > obno)) { + if (obno > bno) + bno = obno; + ASSERT((bno >= obno) || (n == 0)); + ASSERT(bno < end); + mval->br_startoff = bno; + if (ISNULLSTARTBLOCK(got.br_startblock)) { + ASSERT(!wr || delay); + mval->br_startblock = DELAYSTARTBLOCK; + } else + mval->br_startblock = + got.br_startblock + + (bno - got.br_startoff); + /* + * Return the minimum of what we got and what we + * asked for for the length. We can use the len + * variable here because it is modified below + * and we could have been there before coming + * here if the first part of the allocation + * didn't overlap what was asked for. + */ + mval->br_blockcount = + XFS_FILBLKS_MIN(end - bno, got.br_blockcount - + (bno - got.br_startoff)); + mval->br_state = got.br_state; + ASSERT(mval->br_blockcount <= len); + } else { + *mval = got; + if (ISNULLSTARTBLOCK(mval->br_startblock)) { + ASSERT(!wr || delay); + mval->br_startblock = DELAYSTARTBLOCK; + } + } + + /* + * Check if writing previously allocated but + * unwritten extents. + */ + if (wr && mval->br_state == XFS_EXT_UNWRITTEN && + ((flags & (XFS_BMAPI_PREALLOC|XFS_BMAPI_DELAY)) == 0)) { + /* + * Modify (by adding) the state flag, if writing. + */ + ASSERT(mval->br_blockcount <= len); + if ((ifp->if_flags & XFS_IFBROOT) && !cur) { + cur = xfs_btree_init_cursor(ip->i_mount, + tp, NULL, 0, XFS_BTNUM_BMAP, + ip, whichfork); + cur->bc_private.b.firstblock = + *firstblock; + cur->bc_private.b.flist = flist; + } + mval->br_state = XFS_EXT_NORM; + error = xfs_bmap_add_extent(ip, lastx, &cur, mval, + firstblock, flist, &tmp_logflags, whichfork, + rsvd); + logflags |= tmp_logflags; + if (error) + goto error0; + lastx = ifp->if_lastex; + ep = &ifp->if_u1.if_extents[lastx]; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + xfs_bmbt_get_all(ep, &got); + /* + * We may have combined previously unwritten + * space with written space, so generate + * another request. + */ + if (mval->br_blockcount < len) + continue; + } + + ASSERT(!trim || + ((mval->br_startoff + mval->br_blockcount) <= end)); + ASSERT(!trim || (mval->br_blockcount <= len) || + (mval->br_startoff < obno)); + bno = mval->br_startoff + mval->br_blockcount; + len = end - bno; + if (n > 0 && mval->br_startoff == mval[-1].br_startoff) { + ASSERT(mval->br_startblock == mval[-1].br_startblock); + ASSERT(mval->br_blockcount > mval[-1].br_blockcount); + ASSERT(mval->br_state == mval[-1].br_state); + mval[-1].br_blockcount = mval->br_blockcount; + mval[-1].br_state = mval->br_state; + } else if (n > 0 && mval->br_startblock != DELAYSTARTBLOCK && + mval[-1].br_startblock != DELAYSTARTBLOCK && + mval[-1].br_startblock != HOLESTARTBLOCK && + mval->br_startblock == + mval[-1].br_startblock + mval[-1].br_blockcount && + (stateless || mval[-1].br_state == mval->br_state)) { + ASSERT(mval->br_startoff == + mval[-1].br_startoff + mval[-1].br_blockcount); + mval[-1].br_blockcount += mval->br_blockcount; + } else if (n > 0 && + mval->br_startblock == DELAYSTARTBLOCK && + mval[-1].br_startblock == DELAYSTARTBLOCK && + mval->br_startoff == + mval[-1].br_startoff + mval[-1].br_blockcount) { + mval[-1].br_blockcount += mval->br_blockcount; + mval[-1].br_state = mval->br_state; + } else if (!((n == 0) && + ((mval->br_startoff + mval->br_blockcount) <= + obno))) { + mval++; + n++; + } + /* + * If we're done, stop now. Stop when we've allocated + * XFS_BMAP_MAX_NMAP extents no matter what. Otherwise + * the transaction may get too big. + */ + if (bno >= end || n >= *nmap || nallocs >= *nmap) + break; + /* + * Else go on to the next record. + */ + ep++; + lastx++; + if (lastx >= nextents) { + eof = 1; + prev = got; + } else + xfs_bmbt_get_all(ep, &got); + } + ifp->if_lastex = lastx; + *nmap = n; + /* + * Transform from btree to extents, give it cur. + */ + if (tp && XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE && + XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max) { + ASSERT(wr && cur); + error = xfs_bmap_btree_to_extents(tp, ip, cur, + &tmp_logflags, whichfork, 0); + logflags |= tmp_logflags; + if (error) + goto error0; + } + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE || + XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max); + error = 0; + +error0: + /* + * Log everything. Do this after conversion, there's no point in + * logging the extent list if we've converted to btree format. + */ + if ((logflags & XFS_ILOG_FEXT(whichfork)) && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) + logflags &= ~XFS_ILOG_FEXT(whichfork); + else if ((logflags & XFS_ILOG_FBROOT(whichfork)) && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) + logflags &= ~XFS_ILOG_FBROOT(whichfork); + /* + * Log whatever the flags say, even if error. Otherwise we might miss + * detecting a case where the data is changed, there's an error, + * and it's not logged so we don't shutdown when we should. + */ + if (logflags) { + ASSERT(tp && wr); + xfs_trans_log_inode(tp, ip, logflags); + } + if (cur) { + if (!error) { + ASSERT(*firstblock == NULLFSBLOCK || + XFS_FSB_TO_AGNO(ip->i_mount, *firstblock) == + XFS_FSB_TO_AGNO(ip->i_mount, + cur->bc_private.b.firstblock) || + (flist->xbf_low && + XFS_FSB_TO_AGNO(ip->i_mount, *firstblock) < + XFS_FSB_TO_AGNO(ip->i_mount, + cur->bc_private.b.firstblock))); + *firstblock = cur->bc_private.b.firstblock; + } + xfs_btree_del_cursor(cur, + error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); + } + if (!error) + xfs_bmap_validate_ret(orig_bno, orig_len, orig_flags, orig_mval, + orig_nmap, *nmap); + return error; +} + +/* + * Map file blocks to filesystem blocks, simple version. + * One block (extent) only, read-only. + * For flags, only the XFS_BMAPI_ATTRFORK flag is examined. + * For the other flag values, the effect is as if XFS_BMAPI_METADATA + * was set and all the others were clear. + */ +int /* error */ +xfs_bmapi_single( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + int whichfork, /* data or attr fork */ + xfs_fsblock_t *fsb, /* output: mapped block */ + xfs_fileoff_t bno) /* starting file offs. mapped */ +{ + int eof; /* we've hit the end of extent list */ + int error; /* error return */ + xfs_bmbt_irec_t got; /* current extent list record */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t lastx; /* last useful extent number */ + xfs_bmbt_irec_t prev; /* previous extent list record */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) + return XFS_ERROR(EFSCORRUPTED); + if (XFS_FORCED_SHUTDOWN(ip->i_mount)) + return XFS_ERROR(EIO); + XFS_STATS_INC(xfsstats.xs_blk_mapr); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + (void)xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, + &prev); + /* + * Reading past eof, act as though there's a hole + * up to end. + */ + if (eof || got.br_startoff > bno) { + *fsb = NULLFSBLOCK; + return 0; + } + ASSERT(!ISNULLSTARTBLOCK(got.br_startblock)); + ASSERT(bno < got.br_startoff + got.br_blockcount); + *fsb = got.br_startblock + (bno - got.br_startoff); + ifp->if_lastex = lastx; + return 0; +} + +/* + * Unmap (remove) blocks from a file. + * If nexts is nonzero then the number of extents to remove is limited to + * that value. If not all extents in the block range can be removed then + * *done is set. + */ +int /* error */ +xfs_bunmapi( + xfs_trans_t *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t bno, /* starting offset to unmap */ + xfs_filblks_t len, /* length to unmap in file */ + int flags, /* misc flags */ + xfs_extnum_t nexts, /* number of extents max */ + xfs_fsblock_t *firstblock, /* first allocated block + controls a.g. for allocs */ + xfs_bmap_free_t *flist, /* i/o: list extents to free */ + int *done) /* set if not done yet */ +{ + int async; /* xactions can be async */ + xfs_btree_cur_t *cur; /* bmap btree cursor */ + xfs_bmbt_irec_t del; /* extent being deleted */ + int eof; /* is deleting at eof */ + xfs_bmbt_rec_t *ep; /* extent list entry pointer */ + int error; /* error return value */ + xfs_extnum_t extno; /* extent number in list */ + xfs_bmbt_irec_t got; /* current extent list entry */ + xfs_ifork_t *ifp; /* inode fork pointer */ + int isrt; /* freeing in rt area */ + xfs_extnum_t lastx; /* last extent index used */ + int logflags; /* transaction logging flags */ + xfs_extlen_t mod; /* rt extent offset */ + xfs_mount_t *mp; /* mount structure */ + xfs_extnum_t nextents; /* size of extent list */ + xfs_bmbt_irec_t prev; /* previous extent list entry */ + xfs_fileoff_t start; /* first file offset deleted */ + int tmp_logflags; /* partial logging flags */ + int wasdel; /* was a delayed alloc extent */ + int whichfork; /* data or attribute fork */ + int rsvd; /* OK to allocate reserved blocks */ + xfs_fsblock_t sum; + + xfs_bunmap_trace(ip, bno, len, flags, (inst_t *)__return_address); + whichfork = (flags & XFS_BMAPI_ATTRFORK) ? + XFS_ATTR_FORK : XFS_DATA_FORK; + ifp = XFS_IFORK_PTR(ip, whichfork); + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) + return XFS_ERROR(EFSCORRUPTED); + mp = ip->i_mount; + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + async = flags & XFS_BMAPI_ASYNC; + rsvd = (flags & XFS_BMAPI_RSVBLOCKS) != 0; + ASSERT(len > 0); + ASSERT(nexts >= 0); + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(tp, ip, whichfork))) + return error; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + if (nextents == 0) { + *done = 1; + return 0; + } + XFS_STATS_INC(xfsstats.xs_blk_unmap); + isrt = (whichfork == XFS_DATA_FORK) && + (ip->i_d.di_flags & XFS_DIFLAG_REALTIME); + start = bno; + bno = start + len - 1; + ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, + &prev); + /* + * Check to see if the given block number is past the end of the + * file, back up to the last block if so... + */ + if (eof) { + ep = &ifp->if_u1.if_extents[--lastx]; + xfs_bmbt_get_all(ep, &got); + bno = got.br_startoff + got.br_blockcount - 1; + } + logflags = 0; + if (ifp->if_flags & XFS_IFBROOT) { + ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE); + cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip, + whichfork); + cur->bc_private.b.firstblock = *firstblock; + cur->bc_private.b.flist = flist; + cur->bc_private.b.flags = 0; + } else + cur = NULL; + extno = 0; + while (bno != (xfs_fileoff_t)-1 && bno >= start && lastx >= 0 && + (nexts == 0 || extno < nexts)) { + /* + * Is the found extent after a hole in which bno lives? + * Just back up to the previous extent, if so. + */ + if (got.br_startoff > bno) { + if (--lastx < 0) + break; + ep--; + xfs_bmbt_get_all(ep, &got); + } + /* + * Is the last block of this extent before the range + * we're supposed to delete? If so, we're done. + */ + bno = XFS_FILEOFF_MIN(bno, + got.br_startoff + got.br_blockcount - 1); + if (bno < start) + break; + /* + * Then deal with the (possibly delayed) allocated space + * we found. + */ + ASSERT(ep != NULL); + del = got; + wasdel = ISNULLSTARTBLOCK(del.br_startblock); + if (got.br_startoff < start) { + del.br_startoff = start; + del.br_blockcount -= start - got.br_startoff; + if (!wasdel) + del.br_startblock += start - got.br_startoff; + } + if (del.br_startoff + del.br_blockcount > bno + 1) + del.br_blockcount = bno + 1 - del.br_startoff; + sum = del.br_startblock + del.br_blockcount; + if (isrt && + (mod = do_mod(sum, mp->m_sb.sb_rextsize))) { + /* + * Realtime extent not lined up at the end. + * The extent could have been split into written + * and unwritten pieces, or we could just be + * unmapping part of it. But we can't really + * get rid of part of a realtime extent. + */ + if (del.br_state == XFS_EXT_UNWRITTEN || + !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) { + /* + * This piece is unwritten, or we're not + * using unwritten extents. Skip over it. + */ + ASSERT(bno >= mod); + bno -= mod > del.br_blockcount ? + del.br_blockcount : mod; + if (bno < got.br_startoff) { + if (--lastx >= 0) + xfs_bmbt_get_all(--ep, &got); + } + continue; + } + /* + * It's written, turn it unwritten. + * This is better than zeroing it. + */ + ASSERT(del.br_state == XFS_EXT_NORM); + ASSERT(xfs_trans_get_block_res(tp) > 0); + /* + * If this spans a realtime extent boundary, + * chop it back to the start of the one we end at. + */ + if (del.br_blockcount > mod) { + del.br_startoff += del.br_blockcount - mod; + del.br_startblock += del.br_blockcount - mod; + del.br_blockcount = mod; + } + del.br_state = XFS_EXT_UNWRITTEN; + error = xfs_bmap_add_extent(ip, lastx, &cur, &del, + firstblock, flist, &logflags, XFS_DATA_FORK, 0); + if (error) + goto error0; + goto nodelete; + } + if (isrt && (mod = do_mod(del.br_startblock, mp->m_sb.sb_rextsize))) { + /* + * Realtime extent is lined up at the end but not + * at the front. We'll get rid of full extents if + * we can. + */ + mod = mp->m_sb.sb_rextsize - mod; + if (del.br_blockcount > mod) { + del.br_blockcount -= mod; + del.br_startoff += mod; + del.br_startblock += mod; + } else if ((del.br_startoff == start && + (del.br_state == XFS_EXT_UNWRITTEN || + xfs_trans_get_block_res(tp) == 0)) || + !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb)) { + /* + * Can't make it unwritten. There isn't + * a full extent here so just skip it. + */ + ASSERT(bno >= del.br_blockcount); + bno -= del.br_blockcount; + if (bno < got.br_startoff) { + if (--lastx >= 0) + xfs_bmbt_get_all(--ep, &got); + } + continue; + } else if (del.br_state == XFS_EXT_UNWRITTEN) { + /* + * This one is already unwritten. + * It must have a written left neighbor. + * Unwrite the killed part of that one and + * try again. + */ + ASSERT(lastx > 0); + xfs_bmbt_get_all(ep - 1, &prev); + ASSERT(prev.br_state == XFS_EXT_NORM); + ASSERT(!ISNULLSTARTBLOCK(prev.br_startblock)); + ASSERT(del.br_startblock == + prev.br_startblock + prev.br_blockcount); + if (prev.br_startoff < start) { + mod = start - prev.br_startoff; + prev.br_blockcount -= mod; + prev.br_startblock += mod; + prev.br_startoff = start; + } + prev.br_state = XFS_EXT_UNWRITTEN; + error = xfs_bmap_add_extent(ip, lastx - 1, &cur, + &prev, firstblock, flist, &logflags, + XFS_DATA_FORK, 0); + if (error) + goto error0; + goto nodelete; + } else { + ASSERT(del.br_state == XFS_EXT_NORM); + del.br_state = XFS_EXT_UNWRITTEN; + error = xfs_bmap_add_extent(ip, lastx, &cur, + &del, firstblock, flist, &logflags, + XFS_DATA_FORK, 0); + if (error) + goto error0; + goto nodelete; + } + } + if (wasdel) { + ASSERT(STARTBLOCKVAL(del.br_startblock) > 0); + xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, + (int)del.br_blockcount, rsvd); + if (XFS_IS_QUOTA_ON(ip->i_mount)) { + ASSERT(ip->i_ino != mp->m_sb.sb_uquotino); + ASSERT(ip->i_ino != mp->m_sb.sb_gquotino); + if (!isrt) + xfs_trans_unreserve_blkquota(NULL, ip, + (long)del.br_blockcount); + else + xfs_trans_unreserve_rtblkquota(NULL, ip, + (long)del.br_blockcount); + } + ip->i_delayed_blks -= del.br_blockcount; + if (cur) + cur->bc_private.b.flags |= + XFS_BTCUR_BPRV_WASDEL; + } else if (cur) + cur->bc_private.b.flags &= ~XFS_BTCUR_BPRV_WASDEL; + /* + * If it's the case where the directory code is running + * with no block reservation, and the deleted block is in + * the middle of its extent, and the resulting insert + * of an extent would cause transformation to btree format, + * then reject it. The calling code will then swap + * blocks around instead. + * We have to do this now, rather than waiting for the + * conversion to btree format, since the transaction + * will be dirty. + */ + if (!wasdel && xfs_trans_get_block_res(tp) == 0 && + XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_NEXTENTS(ip, whichfork) >= ifp->if_ext_max && + del.br_startoff > got.br_startoff && + del.br_startoff + del.br_blockcount < + got.br_startoff + got.br_blockcount) { + error = XFS_ERROR(ENOSPC); + goto error0; + } + error = xfs_bmap_del_extent(ip, tp, lastx, flist, cur, &del, + flags, &tmp_logflags, whichfork, rsvd); + logflags |= tmp_logflags; + if (error) + goto error0; + bno = del.br_startoff - 1; +nodelete: + lastx = ifp->if_lastex; + /* + * If not done go on to the next (previous) record. + * Reset ep in case the extents array was re-alloced. + */ + ep = &ifp->if_u1.if_extents[lastx]; + if (bno != (xfs_fileoff_t)-1 && bno >= start) { + if (lastx >= XFS_IFORK_NEXTENTS(ip, whichfork) || + xfs_bmbt_get_startoff(ep) > bno) { + lastx--; + ep--; + } + if (lastx >= 0) + xfs_bmbt_get_all(ep, &got); + extno++; + } + } + ifp->if_lastex = lastx; + *done = bno == (xfs_fileoff_t)-1 || bno < start || lastx < 0; + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + /* + * Convert to a btree if necessary. + */ + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && + XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) { + ASSERT(cur == NULL); + error = xfs_bmap_extents_to_btree(tp, ip, firstblock, flist, + &cur, 0, &tmp_logflags, whichfork); + logflags |= tmp_logflags; + if (error) + goto error0; + } + /* + * transform from btree to extents, give it cur + */ + else if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE && + XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max) { + ASSERT(cur != NULL); + error = xfs_bmap_btree_to_extents(tp, ip, cur, &tmp_logflags, + whichfork, async); + logflags |= tmp_logflags; + if (error) + goto error0; + } + /* + * transform from extents to local? + */ + ASSERT(ifp->if_ext_max == + XFS_IFORK_SIZE(ip, whichfork) / (uint)sizeof(xfs_bmbt_rec_t)); + error = 0; +error0: + /* + * Log everything. Do this after conversion, there's no point in + * logging the extent list if we've converted to btree format. + */ + if ((logflags & XFS_ILOG_FEXT(whichfork)) && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) + logflags &= ~XFS_ILOG_FEXT(whichfork); + else if ((logflags & XFS_ILOG_FBROOT(whichfork)) && + XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) + logflags &= ~XFS_ILOG_FBROOT(whichfork); + /* + * Log inode even in the error case, if the transaction + * is dirty we'll need to shut down the filesystem. + */ + if (logflags) + xfs_trans_log_inode(tp, ip, logflags); + if (cur) { + if (!error) { + *firstblock = cur->bc_private.b.firstblock; + cur->bc_private.b.allocated = 0; + } + xfs_btree_del_cursor(cur, + error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); + } + return error; +} + +/* + * Fcntl interface to xfs_bmapi. + */ +int /* error code */ +xfs_getbmap( + bhv_desc_t *bdp, /* XFS behavior descriptor*/ + struct getbmap *bmv, /* user bmap structure */ + void *ap, /* pointer to user's array */ + int interface) /* interface flags */ +{ + __int64_t bmvend; /* last block requested */ + int error; /* return value */ + xfs_fsblock_t firstblock; /* start block for bmapi */ + __int64_t fixlen; /* length for -1 case */ + int i; /* extent number */ + xfs_inode_t *ip; /* xfs incore inode pointer */ + vnode_t *vp; /* corresponding vnode */ + int lock; /* lock state */ + xfs_bmbt_irec_t *map; /* buffer for user's data */ + xfs_mount_t *mp; /* file system mount point */ + int nex; /* # of user extents can do */ + int nexleft; /* # of user extents left */ + int subnex; /* # of bmapi's can do */ + int nmap; /* number of map entries */ + struct getbmap out; /* output structure */ + int whichfork; /* data or attr fork */ + int prealloced; /* this is a file with + * preallocated data space */ + int sh_unwritten; /* true, if unwritten */ + /* extents listed seperately */ + int bmapi_flags; /* flags for xfs_bmapi */ + __int32_t oflags; /* getbmapx bmv_oflags field */ + + ip = XFS_BHVTOI(bdp); + vp = BHV_TO_VNODE(bdp); + + whichfork = interface & BMV_IF_ATTRFORK ? + XFS_ATTR_FORK : XFS_DATA_FORK; + sh_unwritten = (interface & BMV_IF_PREALLOC) != 0; + + + /* If the BMV_IF_NO_DMAPI_READ interface bit specified, do not + * generate a DMAPI read event. Otherwise, if the DM_EVENT_READ + * bit is set for the file, generate a read event in order + * that the DMAPI application may do its thing before we return + * the extents. Usually this means restoring user file data to + * regions of the file that look like holes. + * + * The "old behavior" (from XFS_IOC_GETBMAP) is to not specify + * BMV_IF_NO_DMAPI_READ so that read events are generated. + * If this were not true, callers of ioctl( XFS_IOC_GETBMAP ) + * could misinterpret holes in a DMAPI file as true holes, + * when in fact they may represent offline user data. + */ + if ( (interface & BMV_IF_NO_DMAPI_READ) == 0 + && DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_READ) + && whichfork == XFS_DATA_FORK) { + + error = xfs_dm_send_data_event(DM_EVENT_READ, bdp, + 0, 0, 0, NULL); + if (error) + return XFS_ERROR(error); + } + + if (whichfork == XFS_ATTR_FORK) { + if (XFS_IFORK_Q(ip)) { + if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS && + ip->i_d.di_aformat != XFS_DINODE_FMT_BTREE && + ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL) + return XFS_ERROR(EINVAL); + } else if (ip->i_d.di_aformat != 0 && + ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS) + return XFS_ERROR(EFSCORRUPTED); + } else if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS && + ip->i_d.di_format != XFS_DINODE_FMT_BTREE && + ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) + return XFS_ERROR(EINVAL); + + mp = ip->i_mount; + + if (whichfork == XFS_DATA_FORK) { + if (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) { + prealloced = 1; + fixlen = XFS_MAX_FILE_OFFSET; + } else { + prealloced = 0; + fixlen = ip->i_d.di_size; + } + } else { + prealloced = 0; + fixlen = 1LL << 32; + } + + if (bmv->bmv_length == -1) { + fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, fixlen)); + bmv->bmv_length = MAX(fixlen - bmv->bmv_offset, 0); + } else if (bmv->bmv_length < 0) + return XFS_ERROR(EINVAL); + if (bmv->bmv_length == 0) { + bmv->bmv_entries = 0; + return 0; + } + + nex = bmv->bmv_count - 1; + + if (nex <= 0) + return XFS_ERROR(EINVAL); + + bmvend = bmv->bmv_offset + bmv->bmv_length; + + xfs_ilock(ip, XFS_IOLOCK_SHARED); + + if (whichfork == XFS_DATA_FORK && ip->i_delayed_blks) { + + VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, 0, FI_REMAPF, error); + } + + ASSERT(whichfork == XFS_ATTR_FORK || ip->i_delayed_blks == 0); + + lock = xfs_ilock_map_shared(ip); + + /* + * Don't let nex be bigger than the number of extents + * we can have assuming alternating holes and real extents. + */ + if (nex > XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1) + nex = XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1; + + bmapi_flags = XFS_BMAPI_AFLAG(whichfork) | + ((sh_unwritten) ? 0 : XFS_BMAPI_IGSTATE); + + subnex = 16; /* XXXjtk - need a #define? */ + + /* + * Allocate enough space to handle "subnex" maps at a time. + */ + map = kmem_alloc(subnex * sizeof(*map), KM_SLEEP); + + bmv->bmv_entries = 0; + + if (XFS_IFORK_NEXTENTS(ip, whichfork) == 0) { + error = 0; + goto unlock_and_return; + } + + firstblock = NULLFSBLOCK; + + nexleft = nex; + + do { + if (nexleft > subnex) + nmap = subnex; + else + nmap = nexleft; + + error = xfs_bmapi(NULL, ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset), + XFS_BB_TO_FSB(mp, bmv->bmv_length), + bmapi_flags, &firstblock, 0, + map, &nmap, NULL); + ASSERT(nmap <= subnex); + + if (error) + goto unlock_and_return; + + for (error = i = 0; i < nmap && nexleft && bmv->bmv_length; i++) { + nexleft--; + + oflags = 0; + + out.bmv_offset = XFS_FSB_TO_BB(mp, map[i].br_startoff); + out.bmv_length = XFS_FSB_TO_BB(mp, map[i].br_blockcount); + + ASSERT(map[i].br_startblock != DELAYSTARTBLOCK); + + if ( prealloced + && map[i].br_startblock == HOLESTARTBLOCK + && out.bmv_offset + out.bmv_length == bmvend) { + /* + * came to hole at end of file + */ + goto unlock_and_return; + } else { + if (map[i].br_startblock == HOLESTARTBLOCK) + out.bmv_block = -1; + else + out.bmv_block = + XFS_FSB_TO_DB(ip, map[i].br_startblock); + + /* return either a getbmap or a getbmapx structure. */ + + if (interface & BMV_IF_EXTENDED) { + struct getbmapx outx; + + GETBMAP_CONVERT(out,outx); + + outx.bmv_oflags = oflags; + outx.bmv_unused1 = outx.bmv_unused2 = 0; + + if (copyout(&outx, ap, sizeof(outx))) { + error = XFS_ERROR(EFAULT); + goto unlock_and_return; + } + } else { + if (copyout(&out, ap, sizeof(out))) { + error = XFS_ERROR(EFAULT); + goto unlock_and_return; + } + } + + bmv->bmv_offset = out.bmv_offset + out.bmv_length; + bmv->bmv_length = MAX(0, bmvend - bmv->bmv_offset); + + bmv->bmv_entries++; + + if (interface & BMV_IF_EXTENDED) + ap = (void *)((struct getbmapx *)ap + 1); + else + ap = (void *)((struct getbmap *)ap + 1); + } + } +} while (nmap && nexleft && bmv->bmv_length); + +unlock_and_return: + xfs_iunlock_map_shared(ip, lock); + xfs_iunlock(ip, XFS_IOLOCK_SHARED); + + kmem_free(map, subnex * sizeof(*map)); + + return error; +} + +/* + * Check the last inode extent to determine whether this allocation will result + * in blocks being allocated at the end of the file. When we allocate new data + * blocks at the end of the file which do not start at the previous data block, + * we will try to align the new blocks at stripe unit boundaries. + */ +int /* error */ +xfs_bmap_isaeof( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fileoff_t off, /* file offset in fsblocks */ + int whichfork, /* data or attribute fork */ + int *aeof) /* return value */ +{ + int error; /* error return value */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_rec_t *lastrec; /* extent list entry pointer */ + xfs_extnum_t nextents; /* size of extent list */ + xfs_bmbt_irec_t s; /* expanded extent list entry */ + + ASSERT(whichfork == XFS_DATA_FORK); + ifp = XFS_IFORK_PTR(ip, whichfork); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(NULL, ip, whichfork))) + return error; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + if (nextents == 0) { + *aeof = 1; + return 0; + } + /* + * Go to the last extent + */ + lastrec = &ifp->if_u1.if_extents[nextents - 1]; + xfs_bmbt_get_all(lastrec, &s); + /* + * Check we are allocating in the last extent (for delayed allocations) + * or past the last extent for non-delayed allocations. + */ + *aeof = (off >= s.br_startoff && + off < s.br_startoff + s.br_blockcount && + ISNULLSTARTBLOCK(s.br_startblock)) || + off >= s.br_startoff + s.br_blockcount; + return 0; +} + +/* + * Check if the endoff is outside the last extent. If so the caller will grow + * the allocation to a stripe unit boundary. + */ +int /* error */ +xfs_bmap_eof( + xfs_inode_t *ip, /* incore inode pointer */ + xfs_fileoff_t endoff, /* file offset in fsblocks */ + int whichfork, /* data or attribute fork */ + int *eof) /* result value */ +{ + xfs_fsblock_t blockcount; /* extent block count */ + int error; /* error return value */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_bmbt_rec_t *lastrec; /* extent list entry pointer */ + xfs_extnum_t nextents; /* size of extent list */ + xfs_fileoff_t startoff; /* extent starting file offset */ + + ASSERT(whichfork == XFS_DATA_FORK); + ifp = XFS_IFORK_PTR(ip, whichfork); + if (!(ifp->if_flags & XFS_IFEXTENTS) && + (error = xfs_iread_extents(NULL, ip, whichfork))) + return error; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + if (nextents == 0) { + *eof = 1; + return 0; + } + /* + * Go to the last extent + */ + lastrec = &ifp->if_u1.if_extents[nextents - 1]; + startoff = xfs_bmbt_get_startoff(lastrec); + blockcount = xfs_bmbt_get_blockcount(lastrec); + *eof = endoff >= startoff + blockcount; + return 0; +} + +#ifdef XFSDEBUG +/* + * Check that the extents list for the inode ip is in the right order. + */ +STATIC void +xfs_bmap_check_extents( + xfs_inode_t *ip, /* incore inode pointer */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_rec_t *base; /* base of extents list */ + xfs_bmbt_rec_t *ep; /* current extent entry */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t nextents; /* number of extents in list */ + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ifp->if_flags & XFS_IFEXTENTS); + base = ifp->if_u1.if_extents; + nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + for (ep = base; ep < &base[nextents - 1]; ep++) { + xfs_btree_check_rec(XFS_BTNUM_BMAP, (void *)ep, + (void *)(ep + 1)); + } +} + +STATIC +xfs_buf_t * +xfs_bmap_get_bp( + xfs_btree_cur_t *cur, + xfs_fsblock_t bno) +{ + int i; + xfs_buf_t *bp; + + if (!cur) + return(NULL); + + bp = NULL; + for(i = 0; i < XFS_BTREE_MAXLEVELS; i++) { + bp = cur->bc_bufs[i]; + if (!bp) break; + if (XFS_BUF_ADDR(bp) == bno) + break; /* Found it */ + } + if (i == XFS_BTREE_MAXLEVELS) + bp = NULL; + + if (!bp) { /* Chase down all the log items to see if the bp is there */ + xfs_log_item_chunk_t *licp; + xfs_trans_t *tp; + + tp = cur->bc_tp; + licp = &tp->t_items; + while (!bp && licp != NULL) { + if (XFS_LIC_ARE_ALL_FREE(licp)) { + licp = licp->lic_next; + continue; + } + for (i = 0; i < licp->lic_unused; i++) { + xfs_log_item_desc_t *lidp; + xfs_log_item_t *lip; + xfs_buf_log_item_t *bip; + xfs_buf_t *lbp; + + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + lidp = XFS_LIC_SLOT(licp, i); + lip = lidp->lid_item; + if (lip->li_type != XFS_LI_BUF) + continue; + + bip = (xfs_buf_log_item_t *)lip; + lbp = bip->bli_buf; + + if (XFS_BUF_ADDR(lbp) == bno) { + bp = lbp; + break; /* Found it */ + } + } + licp = licp->lic_next; + } + } + return(bp); +} + +void +xfs_check_block( + xfs_bmbt_block_t *block, + xfs_mount_t *mp, + int root, + short sz) +{ + int i, j, dmxr; + xfs_bmbt_ptr_t *pp, *thispa; /* pointer to block address */ + xfs_bmbt_key_t *prevp, *keyp; + + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + + prevp = NULL; + for( i = 1; i <= INT_GET(block->bb_numrecs, ARCH_CONVERT);i++) { + dmxr = mp->m_bmap_dmxr[0]; + + if (root) { + keyp = XFS_BMAP_BROOT_KEY_ADDR(block, i, sz); + } else { + keyp = XFS_BTREE_KEY_ADDR(mp->m_sb.sb_blocksize, + xfs_bmbt, block, i, dmxr); + } + + if (prevp) { + xfs_btree_check_key(XFS_BTNUM_BMAP, prevp, keyp); + } + prevp = keyp; + + /* + * Compare the block numbers to see if there are dups. + */ + + if (root) { + pp = XFS_BMAP_BROOT_PTR_ADDR(block, i, sz); + } else { + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, + xfs_bmbt, block, i, dmxr); + } + for (j = i+1; j <= INT_GET(block->bb_numrecs, ARCH_CONVERT); j++) { + if (root) { + thispa = XFS_BMAP_BROOT_PTR_ADDR(block, j, sz); + } else { + thispa = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, + xfs_bmbt, block, j, dmxr); + } + if (INT_GET(*thispa, ARCH_CONVERT) == INT_GET(*pp, ARCH_CONVERT)) { + printk("xfs_check_block: thispa(%d) == pp(%d) %Ld\n", + j, i, INT_GET(*thispa, ARCH_CONVERT)); + panic("xfs_check_block: ptrs are equal in node\n"); + } + } + } +} + +/* + * Check that the extents for the inode ip are in the right order in all + * btree leaves. + */ + +STATIC void +xfs_bmap_check_leaf_extents( + xfs_btree_cur_t *cur, /* btree cursor or null */ + xfs_inode_t *ip, /* incore inode pointer */ + int whichfork) /* data or attr fork */ +{ + xfs_bmbt_block_t *block; /* current btree block */ + xfs_fsblock_t bno; /* block # of "block" */ + xfs_buf_t *bp; /* buffer for "block" */ + int error; /* error return value */ + xfs_extnum_t i=0; /* index into the extents list */ + xfs_ifork_t *ifp; /* fork structure */ + int level; /* btree level, for checking */ + xfs_mount_t *mp; /* file system mount structure */ + xfs_bmbt_ptr_t *pp; /* pointer to block address */ + xfs_bmbt_rec_t *ep, *lastp; /* extent pointers in block entry */ + int bp_release = 0; + + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) { + return; + } + + bno = NULLFSBLOCK; + mp = ip->i_mount; + ifp = XFS_IFORK_PTR(ip, whichfork); + block = ifp->if_broot; + /* + * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out. + */ + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + level = INT_GET(block->bb_level, ARCH_CONVERT); + xfs_check_block(block, mp, 1, ifp->if_broot_bytes); + pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes); + ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO); + ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount); + ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks); + bno = INT_GET(*pp, ARCH_CONVERT); + /* + * Go down the tree until leaf level is reached, following the first + * pointer (leftmost) at each level. + */ + while (level-- > 0) { + /* See if buf is in cur first */ + bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno)); + if (bp) { + bp_release = 0; + } else { + bp_release = 1; + } + if (!bp && (error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp, + XFS_BMAP_BTREE_REF))) + goto error_norelse; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + XFS_WANT_CORRUPTED_GOTO( + XFS_BMAP_SANITY_CHECK(mp, block, level), + error0); + if (level == 0) + break; + + /* + * Check this block for basic sanity (increasing keys and + * no duplicate blocks). + */ + + xfs_check_block(block, mp, 0, 0); + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, + 1, mp->m_bmap_dmxr[1]); + XFS_WANT_CORRUPTED_GOTO(XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)), error0); + bno = INT_GET(*pp, ARCH_CONVERT); + if (bp_release) { + bp_release = 0; + xfs_trans_brelse(NULL, bp); + } + } + + /* + * Here with bp and block set to the leftmost leaf node in the tree. + */ + i = 0; + + /* + * Loop over all leaf nodes checking that all extents are in the right order. + */ + lastp = NULL; + for (;;) { + xfs_bmbt_rec_t *frp; + xfs_fsblock_t nextbno; + xfs_extnum_t num_recs; + + + num_recs = INT_GET(block->bb_numrecs, ARCH_CONVERT); + + /* + * Read-ahead the next leaf block, if any. + */ + + nextbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + + /* + * Check all the extents to make sure they are OK. + * If we had a previous block, the last entry should + * conform with the first entry in this one. + */ + + frp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, + block, 1, mp->m_bmap_dmxr[0]); + + for (ep = frp;ep < frp + (num_recs - 1); ep++) { + if (lastp) { + xfs_btree_check_rec(XFS_BTNUM_BMAP, + (void *)lastp, (void *)ep); + } + xfs_btree_check_rec(XFS_BTNUM_BMAP, (void *)ep, + (void *)(ep + 1)); + } + lastp = frp + num_recs - 1; /* For the next iteration */ + + i += num_recs; + if (bp_release) { + bp_release = 0; + xfs_trans_brelse(NULL, bp); + } + bno = nextbno; + /* + * If we've reached the end, stop. + */ + if (bno == NULLFSBLOCK) + break; + + bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno)); + if (bp) { + bp_release = 0; + } else { + bp_release = 1; + } + if (!bp && (error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp, + XFS_BMAP_BTREE_REF))) + goto error_norelse; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + } + if (bp_release) { + bp_release = 0; + xfs_trans_brelse(NULL, bp); + } + return; + +error0: + printk("at error0\n"); + if (bp_release) + xfs_trans_brelse(NULL, bp); +error_norelse: + printk("xfs_bmap_check_leaf_extents: BAD after btree leaves for %d extents\n", i); + panic("xfs_bmap_check_leaf_extents: CORRUPTED BTREE OR SOMETHING"); + return; +} +#endif + +/* + * Count fsblocks of the given fork. + */ +int /* error */ +xfs_bmap_count_blocks( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *ip, /* incore inode */ + int whichfork, /* data or attr fork */ + int *count) /* out: count of blocks */ +{ + xfs_bmbt_block_t *block; /* current btree block */ + xfs_fsblock_t bno; /* block # of "block" */ + xfs_ifork_t *ifp; /* fork structure */ + int level; /* btree level, for checking */ + xfs_mount_t *mp; /* file system mount structure */ + xfs_bmbt_ptr_t *pp; /* pointer to block address */ + + bno = NULLFSBLOCK; + mp = ip->i_mount; + ifp = XFS_IFORK_PTR(ip, whichfork); + if ( XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS ) { + if (xfs_bmap_count_leaves(ifp->if_u1.if_extents, + ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t), + count) < 0) + return XFS_ERROR(EFSCORRUPTED); + return 0; + } + + /* + * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out. + */ + block = ifp->if_broot; + ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) > 0); + level = INT_GET(block->bb_level, ARCH_CONVERT); + pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes); + ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO); + ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount); + ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks); + bno = INT_GET(*pp, ARCH_CONVERT); + + if (xfs_bmap_count_tree(mp, tp, bno, level, count) < 0) + return XFS_ERROR(EFSCORRUPTED); + + return 0; +} + +/* + * Recursively walks each level of a btree + * to count total fsblocks is use. + */ +int /* error */ +xfs_bmap_count_tree( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_fsblock_t blockno, /* file system block number */ + int levelin, /* level in btree */ + int *count) /* Count of blocks */ +{ + int error; + xfs_buf_t *bp, *nbp; + int level = levelin; + xfs_bmbt_ptr_t *pp; + xfs_fsblock_t bno = blockno; + xfs_fsblock_t nextbno; + xfs_bmbt_block_t *block, *nextblock; + int numrecs; + xfs_bmbt_rec_t *frp; + + if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, XFS_BMAP_BTREE_REF))) + return error; + *count += 1; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + + if (--level) { + /* Not at node above leafs, count this level of nodes */ + nextbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + while (nextbno != NULLFSBLOCK) { + if ((error = xfs_btree_read_bufl(mp, tp, nextbno, + 0, &nbp, XFS_BMAP_BTREE_REF))) + return error; + *count += 1; + nextblock = XFS_BUF_TO_BMBT_BLOCK(nbp); + nextbno = INT_GET(nextblock->bb_rightsib, ARCH_CONVERT); + xfs_trans_brelse(tp, nbp); + } + + /* Dive to the next level */ + pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, + xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]); + bno = INT_GET(*pp, ARCH_CONVERT); + if ((error = + xfs_bmap_count_tree(mp, tp, bno, level, count)) < 0) { + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EFSCORRUPTED); + } + xfs_trans_brelse(tp, bp); + } else { + /* count all level 1 nodes and their leaves */ + for (;;) { + nextbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + numrecs = INT_GET(block->bb_numrecs, ARCH_CONVERT); + frp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, + xfs_bmbt, block, 1, mp->m_bmap_dmxr[0]); + if (xfs_bmap_count_leaves(frp, numrecs, count) < 0) { + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EFSCORRUPTED); + } + xfs_trans_brelse(tp, bp); + if (nextbno == NULLFSBLOCK) + break; + bno = nextbno; + if ((error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, + XFS_BMAP_BTREE_REF))) + return error; + *count += 1; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + } + } + return 0; +} + +/* + * Count leaf blocks given a pointer to an extent list. + */ +int +xfs_bmap_count_leaves( + xfs_bmbt_rec_t *frp, + int numrecs, + int *count) +{ + int b; + + for ( b = 1; b <= numrecs; b++, frp++) + *count += xfs_bmbt_get_blockcount(frp); + return 0; +} + diff -rNu linux-2.4.7/linux/fs/xfs/xfs_bmap.h linux-2.4-xfs/linux/fs/xfs/xfs_bmap.h --- linux-2.4.7/linux/fs/xfs/xfs_bmap.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_bmap.h Fri Sep 29 14:03:03 2000 @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BMAP_H__ +#define __XFS_BMAP_H__ + +struct getbmap; +struct xfs_bmbt_irec; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * List of extents to be free "later". + * The list is kept sorted on xbf_startblock. + */ +typedef struct xfs_bmap_free_item +{ + xfs_fsblock_t xbfi_startblock;/* starting fs block number */ + xfs_extlen_t xbfi_blockcount;/* number of blocks in extent */ + struct xfs_bmap_free_item *xbfi_next; /* link to next entry */ +} xfs_bmap_free_item_t; + +/* + * Header for free extent list. + */ +typedef struct xfs_bmap_free +{ + xfs_bmap_free_item_t *xbf_first; /* list of to-be-free extents */ + int xbf_count; /* count of items on list */ + int xbf_low; /* kludge: alloc in low mode */ +} xfs_bmap_free_t; + +#define XFS_BMAP_MAX_NMAP 4 + +/* + * Flags for xfs_bmapi + */ +#define XFS_BMAPI_WRITE 0x001 /* write operation: allocate space */ +#define XFS_BMAPI_DELAY 0x002 /* delayed write operation */ +#define XFS_BMAPI_ENTIRE 0x004 /* return entire extent, not trimmed */ +#define XFS_BMAPI_METADATA 0x008 /* mapping metadata not user data */ +#define XFS_BMAPI_EXACT 0x010 /* allocate only to spec'd bounds */ +#define XFS_BMAPI_ATTRFORK 0x020 /* use attribute fork not data */ +#define XFS_BMAPI_ASYNC 0x040 /* bunmapi xactions can be async */ +#define XFS_BMAPI_RSVBLOCKS 0x080 /* OK to alloc. reserved data blocks */ +#define XFS_BMAPI_PREALLOC 0x100 /* preallocation op: unwritten space */ +#define XFS_BMAPI_IGSTATE 0x200 /* Ignore state - */ + /* combine contig. space */ +#define XFS_BMAPI_CONTIG 0x400 /* must allocate only one extent */ +#define XFS_BMAPI_DIRECT_IO 0x800 /* Flag from cxfs client, not used + * by xfs directly. Indicates alloc + * request is for direct I/O not + * extent conversion by server */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAPI_AFLAG) +int xfs_bmapi_aflag(int w); +#define XFS_BMAPI_AFLAG(w) xfs_bmapi_aflag(w) +#else +#define XFS_BMAPI_AFLAG(w) ((w) == XFS_ATTR_FORK ? XFS_BMAPI_ATTRFORK : 0) +#endif + +/* + * Special values for xfs_bmbt_irec_t br_startblock field. + */ +#define DELAYSTARTBLOCK ((xfs_fsblock_t)-1LL) +#define HOLESTARTBLOCK ((xfs_fsblock_t)-2LL) + +/* + * Trace operations for bmap extent tracing + */ +#define XFS_BMAP_KTRACE_DELETE 1 +#define XFS_BMAP_KTRACE_INSERT 2 +#define XFS_BMAP_KTRACE_PRE_UP 3 +#define XFS_BMAP_KTRACE_POST_UP 4 + +#define XFS_BMAP_TRACE_SIZE 4096 /* size of global trace buffer */ +#define XFS_BMAP_KTRACE_SIZE 32 /* size of per-inode trace buffer */ + +#if defined(XFS_ALL_TRACE) +#define XFS_BMAP_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_BMAP_TRACE +#endif + + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_INIT) +void xfs_bmap_init(xfs_bmap_free_t *flp, xfs_fsblock_t *fbp); +#define XFS_BMAP_INIT(flp,fbp) xfs_bmap_init(flp,fbp) +#else +#define XFS_BMAP_INIT(flp,fbp) \ + ((flp)->xbf_first = NULL, (flp)->xbf_count = 0, \ + (flp)->xbf_low = 0, *(fbp) = NULLFSBLOCK) +#endif + +/* + * Argument structure for xfs_bmap_alloc. + */ +typedef struct xfs_bmalloca { + xfs_fsblock_t firstblock; /* i/o first block allocated */ + xfs_fsblock_t rval; /* starting block of new extent */ + xfs_fileoff_t off; /* offset in file filling in */ + struct xfs_trans *tp; /* transaction pointer */ + struct xfs_inode *ip; /* incore inode pointer */ + struct xfs_bmbt_irec *prevp; /* extent before the new one */ + struct xfs_bmbt_irec *gotp; /* extent after, or delayed */ + xfs_extlen_t alen; /* i/o length asked/allocated */ + xfs_extlen_t total; /* total blocks needed for xaction */ + xfs_extlen_t minlen; /* mininum allocation size (blocks) */ + xfs_extlen_t minleft; /* amount must be left after alloc */ + int eof; /* set if allocating past last extent */ + int wasdel; /* replacing a delayed allocation */ + int userdata;/* set if is user data */ + int low; /* low on space, using seq'l ags */ + int aeof; /* allocated space at eof */ +} xfs_bmalloca_t; + +#ifdef __KERNEL__ +/* + * Convert inode from non-attributed to attributed. + * Must not be in a transaction, ip must not be locked. + */ +int /* error code */ +xfs_bmap_add_attrfork( + struct xfs_inode *ip, /* incore inode pointer */ + int rsvd); /* flag for reserved block allocation */ + +/* + * Add the extent to the list of extents to be free at transaction end. + * The list is maintained sorted (by block number). + */ +void +xfs_bmap_add_free( + xfs_fsblock_t bno, /* fs block number of extent */ + xfs_filblks_t len, /* length of extent */ + xfs_bmap_free_t *flist, /* list of extents */ + struct xfs_mount *mp); /* mount point structure */ + +/* + * Routine to clean up the free list data structure when + * an error occurs during a transaction. + */ +void +xfs_bmap_cancel( + xfs_bmap_free_t *flist); /* free list to clean up */ + +/* + * Routine to check if a specified inode is swap capable. + */ +int +xfs_bmap_check_swappable( + struct xfs_inode *ip); /* incore inode */ + +/* + * Compute and fill in the value of the maximum depth of a bmap btree + * in this filesystem. Done once, during mount. + */ +void +xfs_bmap_compute_maxlevels( + struct xfs_mount *mp, /* file system mount structure */ + int whichfork); /* data or attr fork */ + +/* + * Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi + * caller. Frees all the extents that need freeing, which must be done + * last due to locking considerations. + * + * Return 1 if the given transaction was committed and a new one allocated, + * and 0 otherwise. + */ +int /* error */ +xfs_bmap_finish( + struct xfs_trans **tp, /* transaction pointer addr */ + xfs_bmap_free_t *flist, /* i/o: list extents to free */ + xfs_fsblock_t firstblock, /* controlled a.g. for allocs */ + int *committed); /* xact committed or not */ + +/* + * Returns the file-relative block number of the first unused block in the file. + * This is the lowest-address hole if the file has holes, else the first block + * past the end of file. + */ +int /* error */ +xfs_bmap_first_unused( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_extlen_t len, /* size of hole to find */ + xfs_fileoff_t *unused, /* unused block num */ + int whichfork); /* data or attr fork */ + +/* + * Returns the file-relative block number of the last block + 1 before + * last_block (input value) in the file. + * This is not based on i_size, it is based on the extent list. + * Returns 0 for local files, as they do not have an extent list. + */ +int /* error */ +xfs_bmap_last_before( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t *last_block, /* last block */ + int whichfork); /* data or attr fork */ + +/* + * Returns the file-relative block number of the first block past eof in + * the file. This is not based on i_size, it is based on the extent list. + * Returns 0 for local files, as they do not have an extent list. + */ +int /* error */ +xfs_bmap_last_offset( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t *unused, /* last block num */ + int whichfork); /* data or attr fork */ + +/* + * Returns whether the selected fork of the inode has exactly one + * block or not. For the data fork we check this matches di_size, + * implying the file's range is 0..bsize-1. + */ +int +xfs_bmap_one_block( + struct xfs_inode *ip, /* incore inode */ + int whichfork); /* data or attr fork */ + +/* + * Read in the extents to iu_extents. + * All inode fields are set up by caller, we just traverse the btree + * and copy the records in. + */ +int /* error */ +xfs_bmap_read_extents( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + int whichfork); /* data or attr fork */ + +#if defined(XFS_BMAP_TRACE) +/* + * Add bmap trace insert entries for all the contents of the extent list. + */ +void +xfs_bmap_trace_exlist( + char *fname, /* function name */ + struct xfs_inode *ip, /* incore inode pointer */ + xfs_extnum_t cnt, /* count of entries in list */ + int whichfork); /* data or attr fork */ +#else +#define xfs_bmap_trace_exlist(f,ip,c,w) +#endif + +/* + * Map file blocks to filesystem blocks. + * File range is given by the bno/len pair. + * Adds blocks to file if a write ("flags & XFS_BMAPI_WRITE" set) + * into a hole or past eof. + * Only allocates blocks from a single allocation group, + * to avoid locking problems. + * The returned value in "firstblock" from the first call in a transaction + * must be remembered and presented to subsequent calls in "firstblock". + * An upper bound for the number of blocks to be allocated is supplied to + * the first call in "total"; if no allocation group has that many free + * blocks then the call will fail (return NULLFSBLOCK in "firstblock"). + */ +int /* error */ +xfs_bmapi( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t bno, /* starting file offs. mapped */ + xfs_filblks_t len, /* length to map in file */ + int flags, /* XFS_BMAPI_... */ + xfs_fsblock_t *firstblock, /* first allocated block + controls a.g. for allocs */ + xfs_extlen_t total, /* total blocks needed */ + struct xfs_bmbt_irec *mval, /* output: map values */ + int *nmap, /* i/o: mval size/count */ + xfs_bmap_free_t *flist); /* i/o: list extents to free */ + +/* + * Map file blocks to filesystem blocks, simple version. + * One block only, read-only. + * For flags, only the XFS_BMAPI_ATTRFORK flag is examined. + * For the other flag values, the effect is as if XFS_BMAPI_METADATA + * was set and all the others were clear. + */ +int /* error */ +xfs_bmapi_single( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + int whichfork, /* data or attr fork */ + xfs_fsblock_t *fsb, /* output: mapped block */ + xfs_fileoff_t bno); /* starting file offs. mapped */ + +/* + * Unmap (remove) blocks from a file. + * If nexts is nonzero then the number of extents to remove is limited to + * that value. If not all extents in the block range can be removed then + * *done is set. + */ +int /* error */ +xfs_bunmapi( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_inode *ip, /* incore inode */ + xfs_fileoff_t bno, /* starting offset to unmap */ + xfs_filblks_t len, /* length to unmap in file */ + int flags, /* XFS_BMAPI_... */ + xfs_extnum_t nexts, /* number of extents max */ + xfs_fsblock_t *firstblock, /* first allocated block + controls a.g. for allocs */ + xfs_bmap_free_t *flist, /* i/o: list extents to free */ + int *done); /* set if not done yet */ + +/* + * Fcntl interface to xfs_bmapi. + */ +int /* error code */ +xfs_getbmap( + bhv_desc_t *bdp, /* XFS behavior descriptor*/ + struct getbmap *bmv, /* user bmap structure */ + void *ap, /* pointer to user's array */ + int iflags); /* interface flags */ + +/* + * Check the last inode extent to determine whether this allocation will result + * in blocks being allocated at the end of the file. When we allocate new data + * blocks at the end of the file which do not start at the previous data block, + * we will try to align the new blocks at stripe unit boundaries. + */ +int +xfs_bmap_isaeof( + struct xfs_inode *ip, + xfs_fileoff_t off, + int whichfork, + int *aeof); + +/* + * Check if the endoff is outside the last extent. If so the caller will grow + * the allocation to a stripe unit boundary + */ +int +xfs_bmap_eof( + struct xfs_inode *ip, + xfs_fileoff_t endoff, + int whichfork, + int *eof); + +/* + * Count fsblocks of the given fork. + */ +int +xfs_bmap_count_blocks( + xfs_trans_t *tp, + xfs_inode_t *ip, + int whichfork, + int *count); + +/* + * Check an extent list, which has just been read, for + * any bit in the extent flag field. + */ +int +xfs_check_nostate_extents( + xfs_bmbt_rec_t *ep, + xfs_extnum_t num); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_BMAP_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_bmap_btree.c linux-2.4-xfs/linux/fs/xfs/xfs_bmap_btree.c --- linux-2.4.7/linux/fs/xfs/xfs_bmap_btree.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_bmap_btree.c Wed Apr 18 21:37:23 2001 @@ -0,0 +1,2839 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#ifdef DEBUG +ktrace_t *xfs_bmbt_trace_buf; +#endif + +/* + * Prototypes for internal btree functions. + */ + + +STATIC int xfs_bmbt_killroot(xfs_btree_cur_t *, int); +STATIC void xfs_bmbt_log_keys(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC void xfs_bmbt_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC int xfs_bmbt_lshift(xfs_btree_cur_t *, int, int *); +STATIC int xfs_bmbt_rshift(xfs_btree_cur_t *, int, int *); +STATIC int xfs_bmbt_split(xfs_btree_cur_t *, int, xfs_fsblock_t *, + xfs_bmbt_key_t *, xfs_btree_cur_t **, int *); +STATIC int xfs_bmbt_updkey(xfs_btree_cur_t *, xfs_bmbt_key_t *, int); + + +#if defined(XFS_BMBT_TRACE) +/* + * Add a trace buffer entry for the arguments given to the routine, + * generic form. + */ +STATIC void +xfs_bmbt_trace_enter( + char *func, + xfs_btree_cur_t *cur, + char *s, + int type, + int line, + __psunsigned_t a0, + __psunsigned_t a1, + __psunsigned_t a2, + __psunsigned_t a3, + __psunsigned_t a4, + __psunsigned_t a5, + __psunsigned_t a6, + __psunsigned_t a7, + __psunsigned_t a8, + __psunsigned_t a9, + __psunsigned_t a10) +{ + xfs_inode_t *ip; + int whichfork; + + ip = cur->bc_private.b.ip; + whichfork = cur->bc_private.b.whichfork; + ktrace_enter(xfs_bmbt_trace_buf, + (void *)((__psint_t)type | (whichfork << 8) | (line << 16)), + (void *)func, (void *)s, (void *)ip, (void *)cur, + (void *)a0, (void *)a1, (void *)a2, (void *)a3, + (void *)a4, (void *)a5, (void *)a6, (void *)a7, + (void *)a8, (void *)a9, (void *)a10); + ASSERT(ip->i_btrace); + ktrace_enter(ip->i_btrace, + (void *)((__psint_t)type | (whichfork << 8) | (line << 16)), + (void *)func, (void *)s, (void *)ip, (void *)cur, + (void *)a0, (void *)a1, (void *)a2, (void *)a3, + (void *)a4, (void *)a5, (void *)a6, (void *)a7, + (void *)a8, (void *)a9, (void *)a10); +} +/* + * Add a trace buffer entry for arguments, for a buffer & 1 integer arg. + */ +STATIC void +xfs_bmbt_trace_argbi( + char *func, + xfs_btree_cur_t *cur, + xfs_buf_t *b, + int i, + int line) +{ + xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGBI, line, + (__psunsigned_t)b, i, 0, 0, + 0, 0, 0, 0, + 0, 0, 0); +} + +/* + * Add a trace buffer entry for arguments, for a buffer & 2 integer args. + */ +STATIC void +xfs_bmbt_trace_argbii( + char *func, + xfs_btree_cur_t *cur, + xfs_buf_t *b, + int i0, + int i1, + int line) +{ + xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGBII, line, + (__psunsigned_t)b, i0, i1, 0, + 0, 0, 0, 0, + 0, 0, 0); +} + +/* + * Add a trace buffer entry for arguments, for 3 block-length args + * and an integer arg. + */ +STATIC void +xfs_bmbt_trace_argfffi( + char *func, + xfs_btree_cur_t *cur, + xfs_dfiloff_t o, + xfs_dfsbno_t b, + xfs_dfilblks_t i, + int j, + int line) +{ + xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGFFFI, line, + o >> 32, (int)o, b >> 32, (int)b, + i >> 32, (int)i, (int)j, 0, + 0, 0, 0); +} + +/* + * Add a trace buffer entry for arguments, for one integer arg. + */ +STATIC void +xfs_bmbt_trace_argi( + char *func, + xfs_btree_cur_t *cur, + int i, + int line) +{ + xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGI, line, + i, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0); +} + +/* + * Add a trace buffer entry for arguments, for int, fsblock, key. + */ +STATIC void +xfs_bmbt_trace_argifk( + char *func, + xfs_btree_cur_t *cur, + int i, + xfs_fsblock_t f, + xfs_bmbt_key_t *k, + int line) +{ + xfs_dfsbno_t d; + xfs_dfiloff_t o; + + d = (xfs_dfsbno_t)f; + o = INT_GET(k->br_startoff, ARCH_CONVERT); + xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGIFK, line, + i, d >> 32, (int)d, o >> 32, + (int)o, 0, 0, 0, + 0, 0, 0); +} + +/* + * Add a trace buffer entry for arguments, for int, fsblock, rec. + */ +STATIC void +xfs_bmbt_trace_argifr( + char *func, + xfs_btree_cur_t *cur, + int i, + xfs_fsblock_t f, + xfs_bmbt_rec_t *r, + int line) +{ + xfs_dfsbno_t b; + xfs_dfilblks_t c; + xfs_dfsbno_t d; + xfs_dfiloff_t o; + xfs_bmbt_irec_t s; + + d = (xfs_dfsbno_t)f; + xfs_bmbt_get_all(r, &s); + o = (xfs_dfiloff_t)s.br_startoff; + b = (xfs_dfsbno_t)s.br_startblock; + c = s.br_blockcount; + xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGIFR, line, + i, d >> 32, (int)d, o >> 32, + (int)o, b >> 32, (int)b, c >> 32, + (int)c, 0, 0); +} + +/* + * Add a trace buffer entry for arguments, for int, key. + */ +STATIC void +xfs_bmbt_trace_argik( + char *func, + xfs_btree_cur_t *cur, + int i, + xfs_bmbt_key_t *k, + int line) +{ + xfs_dfiloff_t o; + + o = INT_GET(k->br_startoff, ARCH_CONVERT); + xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGIFK, line, + i, o >> 32, (int)o, 0, + 0, 0, 0, 0, + 0, 0, 0); +} + +/* + * Add a trace buffer entry for the cursor/operation. + */ +STATIC void +xfs_bmbt_trace_cursor( + char *func, + xfs_btree_cur_t *cur, + char *s, + int line) +{ + xfs_bmbt_rec_t r; + + xfs_bmbt_set_all(&r, &cur->bc_rec.b); + xfs_bmbt_trace_enter(func, cur, s, XFS_BMBT_KTRACE_CUR, line, + (cur->bc_nlevels << 24) | (cur->bc_private.b.flags << 16) | + cur->bc_private.b.allocated, +#if BMBT_USE_64 + INT_GET(r.l0, ARCH_CONVERT) >> 32, (int)INT_GET(r.l0, ARCH_CONVERT), INT_GET(r.l1, ARCH_CONVERT) >> 32, (int)INT_GET(r.l1, ARCH_CONVERT), +#else + INT_GET(r.l0, ARCH_CONVERT), INT_GET(r.l1, ARCH_CONVERT), INT_GET(r.l2, ARCH_CONVERT), INT_GET(r.l3, ARCH_CONVERT), +#endif + (unsigned long)cur->bc_bufs[0], (unsigned long)cur->bc_bufs[1], + (unsigned long)cur->bc_bufs[2], (unsigned long)cur->bc_bufs[3], + (cur->bc_ptrs[0] << 16) | cur->bc_ptrs[1], + (cur->bc_ptrs[2] << 16) | cur->bc_ptrs[3]); +} + +#define XFS_BMBT_TRACE_ARGBI(c,b,i) \ + xfs_bmbt_trace_argbi(fname, c, b, i, __LINE__) +#define XFS_BMBT_TRACE_ARGBII(c,b,i,j) \ + xfs_bmbt_trace_argbii(fname, c, b, i, j, __LINE__) +#define XFS_BMBT_TRACE_ARGFFFI(c,o,b,i,j) \ + xfs_bmbt_trace_argfffi(fname, c, o, b, i, j, __LINE__) +#define XFS_BMBT_TRACE_ARGI(c,i) \ + xfs_bmbt_trace_argi(fname, c, i, __LINE__) +#define XFS_BMBT_TRACE_ARGIFK(c,i,f,k) \ + xfs_bmbt_trace_argifk(fname, c, i, f, k, __LINE__) +#define XFS_BMBT_TRACE_ARGIFR(c,i,f,r) \ + xfs_bmbt_trace_argifr(fname, c, i, f, r, __LINE__) +#define XFS_BMBT_TRACE_ARGIK(c,i,k) \ + xfs_bmbt_trace_argik(fname, c, i, k, __LINE__) +#define XFS_BMBT_TRACE_CURSOR(c,s) \ + xfs_bmbt_trace_cursor(fname, c, s, __LINE__) +static char ARGS[] = "args"; +static char ENTRY[] = "entry"; +static char ERROR[] = "error"; +#undef EXIT +static char EXIT[] = "exit"; +#else +#define XFS_BMBT_TRACE_ARGBI(c,b,i) +#define XFS_BMBT_TRACE_ARGBII(c,b,i,j) +#define XFS_BMBT_TRACE_ARGFFFI(c,o,b,i,j) +#define XFS_BMBT_TRACE_ARGI(c,i) +#define XFS_BMBT_TRACE_ARGIFK(c,i,f,k) +#define XFS_BMBT_TRACE_ARGIFR(c,i,f,r) +#define XFS_BMBT_TRACE_ARGIK(c,i,k) +#define XFS_BMBT_TRACE_CURSOR(c,s) +#endif /* XFS_BMBT_TRACE */ + + +/* + * Internal functions. + */ + +/* + * Delete record pointed to by cur/level. + */ +STATIC int /* error */ +xfs_bmbt_delrec( + xfs_btree_cur_t *cur, + int level, + int async, /* deletion can be async */ + int *stat) /* success/failure */ +{ + xfs_bmbt_block_t *block; /* bmap btree block */ + xfs_fsblock_t bno; /* fs-relative block number */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_delrec"; +#endif + int i; /* loop counter */ + int j; /* temp state */ + xfs_bmbt_key_t key; /* bmap btree key */ + xfs_bmbt_key_t *kp=NULL; /* pointer to bmap btree key */ + xfs_fsblock_t lbno; /* left sibling block number */ + xfs_buf_t *lbp; /* left buffer pointer */ + xfs_bmbt_block_t *left; /* left btree block */ + xfs_bmbt_key_t *lkp; /* left btree key */ + xfs_bmbt_ptr_t *lpp; /* left address pointer */ + int lrecs=0; /* left record count */ + xfs_bmbt_rec_t *lrp; /* left record pointer */ + xfs_mount_t *mp; /* file system mount point */ + xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */ + int ptr; /* key/record index */ + xfs_fsblock_t rbno; /* right sibling block number */ + xfs_buf_t *rbp; /* right buffer pointer */ + xfs_bmbt_block_t *right; /* right btree block */ + xfs_bmbt_key_t *rkp; /* right btree key */ + xfs_bmbt_rec_t *rp; /* pointer to bmap btree rec */ + xfs_bmbt_ptr_t *rpp; /* right address pointer */ + xfs_bmbt_block_t *rrblock; /* right-right btree block */ + xfs_buf_t *rrbp; /* right-right buffer pointer */ + int rrecs=0; /* right record count */ + xfs_bmbt_rec_t *rrp; /* right record pointer */ + xfs_btree_cur_t *tcur; /* temporary btree cursor */ + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, level); + ptr = cur->bc_ptrs[level]; + tcur = (xfs_btree_cur_t *)0; + if (ptr == 0) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + block = xfs_bmbt_get_block(cur, level, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } +#endif + if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + XFS_STATS_INC(xfsstats.xs_bmbt_delrec); + if (level > 0) { + kp = XFS_BMAP_KEY_IADDR(block, 1, cur); + pp = XFS_BMAP_PTR_IADDR(block, 1, cur); +#ifdef DEBUG + for (i = ptr; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(pp[i], ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + } +#endif + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ovbcopy(&kp[ptr], &kp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*kp)); + ovbcopy(&pp[ptr], &pp[ptr - 1], /* INT_: direct copy */ + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*pp)); + xfs_bmbt_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + xfs_bmbt_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + } + } else { + rp = XFS_BMAP_REC_IADDR(block, 1, cur); + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ovbcopy(&rp[ptr], &rp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*rp)); + xfs_bmbt_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + } + if (ptr == 1) { + INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(rp)); + kp = &key; + } + } + INT_MOD(block->bb_numrecs, ARCH_CONVERT, -1); + xfs_bmbt_log_block(cur, bp, XFS_BB_NUMRECS); + /* + * We're at the root level. + * First, shrink the root block in-memory. + * Try to get rid of the next level down. + * If we can't then there's nothing left to do. + */ + if (level == cur->bc_nlevels - 1) { + xfs_iroot_realloc(cur->bc_private.b.ip, -1, + cur->bc_private.b.whichfork); + if ((error = xfs_bmbt_killroot(cur, async))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (level > 0 && (error = xfs_bmbt_decrement(cur, level, &j))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + if (ptr == 1 && (error = xfs_bmbt_updkey(cur, kp, level + 1))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) >= XFS_BMAP_BLOCK_IMINRECS(level, cur)) { + if (level > 0 && (error = xfs_bmbt_decrement(cur, level, &j))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + rbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + lbno = INT_GET(block->bb_leftsib, ARCH_CONVERT); + /* + * One child of root, need to get a chance to copy its contents + * into the root and delete it. Can't go up to next level, + * there's nothing to delete there. + */ + if (lbno == NULLFSBLOCK && rbno == NULLFSBLOCK && + level == cur->bc_nlevels - 2) { + if ((error = xfs_bmbt_killroot(cur, async))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (level > 0 && (error = xfs_bmbt_decrement(cur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + ASSERT(rbno != NULLFSBLOCK || lbno != NULLFSBLOCK); + if ((error = xfs_btree_dup_cursor(cur, &tcur))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + bno = NULLFSBLOCK; + if (rbno != NULLFSBLOCK) { + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_bmbt_increment(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + rbp = tcur->bc_bufs[level]; + right = XFS_BUF_TO_BMBT_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, right, level, rbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } +#endif + bno = INT_GET(right->bb_leftsib, ARCH_CONVERT); + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_BMAP_BLOCK_IMINRECS(level, cur)) { + if ((error = xfs_bmbt_lshift(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_BMAP_BLOCK_IMINRECS(level, tcur)); + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + tcur = NULL; + if (level > 0) { + if ((error = xfs_bmbt_decrement(cur, + level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, + ERROR); + goto error0; + } + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + } + rrecs = INT_GET(right->bb_numrecs, ARCH_CONVERT); + if (lbno != NULLFSBLOCK) { + i = xfs_btree_firstrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_bmbt_decrement(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + } + if (lbno != NULLFSBLOCK) { + i = xfs_btree_firstrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * decrement to last in block + */ + if ((error = xfs_bmbt_decrement(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + i = xfs_btree_firstrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + lbp = tcur->bc_bufs[level]; + left = XFS_BUF_TO_BMBT_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, left, level, lbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } +#endif + bno = INT_GET(left->bb_rightsib, ARCH_CONVERT); + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_BMAP_BLOCK_IMINRECS(level, cur)) { + if ((error = xfs_bmbt_rshift(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_BMAP_BLOCK_IMINRECS(level, tcur)); + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + tcur = NULL; + if (level == 0) + cur->bc_ptrs[0]++; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + } + lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + tcur = NULL; + mp = cur->bc_mp; + ASSERT(bno != NULLFSBLOCK); + if (lbno != NULLFSBLOCK && + lrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { + rbno = bno; + right = block; + rbp = bp; + if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, lbno, 0, &lbp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + left = XFS_BUF_TO_BMBT_BLOCK(lbp); + if ((error = xfs_btree_check_lblock(cur, left, level, lbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + } else if (rbno != NULLFSBLOCK && + rrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= + XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { + lbno = bno; + left = block; + lbp = bp; + if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, rbno, 0, &rbp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + right = XFS_BUF_TO_BMBT_BLOCK(rbp); + if ((error = xfs_btree_check_lblock(cur, right, level, rbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT); + } else { + if (level > 0 && (error = xfs_bmbt_decrement(cur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + if (level > 0) { + lkp = XFS_BMAP_KEY_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + lpp = XFS_BMAP_PTR_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rkp = XFS_BMAP_KEY_IADDR(right, 1, cur); + rpp = XFS_BMAP_PTR_IADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + } +#endif + bcopy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp)); + bcopy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp)); + xfs_bmbt_log_keys(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_bmbt_log_ptrs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } else { + lrp = XFS_BMAP_REC_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rrp = XFS_BMAP_REC_IADDR(right, 1, cur); + bcopy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp)); + xfs_bmbt_log_recs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } + INT_MOD(left->bb_numrecs, ARCH_CONVERT, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + left->bb_rightsib = right->bb_rightsib; /* INT_: direct copy */ + xfs_bmbt_log_block(cur, lbp, XFS_BB_RIGHTSIB | XFS_BB_NUMRECS); + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) != NULLDFSBNO) { + if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, + INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, &rrbp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + rrblock = XFS_BUF_TO_BMBT_BLOCK(rrbp); + if ((error = xfs_btree_check_lblock(cur, rrblock, level, rrbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, lbno); + xfs_bmbt_log_block(cur, rrbp, XFS_BB_LEFTSIB); + } + xfs_bmap_add_free(XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(rbp)), 1, + cur->bc_private.b.flist, mp); + if (!async) + xfs_trans_set_sync(cur->bc_tp); + cur->bc_private.b.ip->i_d.di_nblocks--; + xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, XFS_ILOG_CORE); + if (XFS_IS_QUOTA_ON(mp) && + cur->bc_private.b.ip->i_ino != mp->m_sb.sb_uquotino && + cur->bc_private.b.ip->i_ino != mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(cur->bc_tp, cur->bc_private.b.ip, + XFS_TRANS_DQ_BCOUNT, -1L); + xfs_trans_binval(cur->bc_tp, rbp); + if (bp != lbp) { + cur->bc_bufs[level] = lbp; + cur->bc_ptrs[level] += lrecs; + cur->bc_ra[level] = 0; + } else if ((error = xfs_bmbt_increment(cur, level + 1, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + goto error0; + } + if (level > 0) + cur->bc_ptrs[level]--; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 2; + return 0; + +error0: + if (tcur) + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; +} + +#ifdef XFSDEBUG +/* + * Get the data from the pointed-to record. + */ +int +xfs_bmbt_get_rec( + xfs_btree_cur_t *cur, + xfs_fileoff_t *off, + xfs_fsblock_t *bno, + xfs_filblks_t *len, + xfs_exntst_t *state, + int *stat) +{ + xfs_bmbt_block_t *block; + xfs_buf_t *bp; +#ifdef DEBUG + int error; +#endif + int ptr; + xfs_bmbt_rec_t *rp; + + block = xfs_bmbt_get_block(cur, 0, &bp); + ptr = cur->bc_ptrs[0]; +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, 0, bp))) + return error; +#endif + if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT) || ptr <= 0) { + *stat = 0; + return 0; + } + rp = XFS_BMAP_REC_IADDR(block, ptr, cur); + *off = xfs_bmbt_get_startoff(rp); + *bno = xfs_bmbt_get_startblock(rp); + *len = xfs_bmbt_get_blockcount(rp); + *state = xfs_bmbt_get_state(rp); + *stat = 1; + return 0; +} +#endif + +/* + * Insert one record/level. Return information to the caller + * allowing the next level up to proceed if necessary. + */ +STATIC int /* error */ +xfs_bmbt_insrec( + xfs_btree_cur_t *cur, + int level, + xfs_fsblock_t *bnop, + xfs_bmbt_rec_t *recp, + xfs_btree_cur_t **curp, + int *stat) /* no-go/done/continue */ +{ + xfs_bmbt_block_t *block; /* bmap btree block */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_insrec"; +#endif + int i; /* loop index */ + xfs_bmbt_key_t key; /* bmap btree key */ + xfs_bmbt_key_t *kp=NULL; /* pointer to bmap btree key */ + int logflags; /* inode logging flags */ + xfs_fsblock_t nbno; /* new block number */ + struct xfs_btree_cur *ncur; /* new btree cursor */ + xfs_bmbt_key_t nkey; /* new btree key value */ + xfs_bmbt_rec_t nrec; /* new record count */ + int optr; /* old key/record index */ + xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */ + int ptr; /* key/record index */ + xfs_bmbt_rec_t *rp=NULL; /* pointer to bmap btree rec */ + + ASSERT(level < cur->bc_nlevels); + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGIFR(cur, level, *bnop, recp); + ncur = (xfs_btree_cur_t *)0; + INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(recp)); + optr = ptr = cur->bc_ptrs[level]; + if (ptr == 0) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + XFS_STATS_INC(xfsstats.xs_bmbt_insrec); + block = xfs_bmbt_get_block(cur, level, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (ptr <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + if (level == 0) { + rp = XFS_BMAP_REC_IADDR(block, ptr, cur); + xfs_btree_check_rec(XFS_BTNUM_BMAP, recp, rp); + } else { + kp = XFS_BMAP_KEY_IADDR(block, ptr, cur); + xfs_btree_check_key(XFS_BTNUM_BMAP, &key, kp); + } + } +#endif + nbno = NULLFSBLOCK; + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) == XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) < XFS_BMAP_BLOCK_DMAXRECS(level, cur)) { + /* + * A root block, that can be made bigger. + */ + xfs_iroot_realloc(cur->bc_private.b.ip, 1, + cur->bc_private.b.whichfork); + block = xfs_bmbt_get_block(cur, level, &bp); + } else if (level == cur->bc_nlevels - 1) { + if ((error = xfs_bmbt_newroot(cur, &logflags, stat)) || + *stat == 0) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, + logflags); + block = xfs_bmbt_get_block(cur, level, &bp); + } else { + if ((error = xfs_bmbt_rshift(cur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (i) { + /* nothing */ + } else { + if ((error = xfs_bmbt_lshift(cur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (i) { + optr = ptr = cur->bc_ptrs[level]; + } else { + if ((error = xfs_bmbt_split(cur, level, + &nbno, &nkey, &ncur, + &i))) { + XFS_BMBT_TRACE_CURSOR(cur, + ERROR); + return error; + } + if (i) { + block = xfs_bmbt_get_block( + cur, level, &bp); +#ifdef DEBUG + if ((error = + xfs_btree_check_lblock(cur, + block, level, bp))) { + XFS_BMBT_TRACE_CURSOR( + cur, ERROR); + return error; + } +#endif + ptr = cur->bc_ptrs[level]; + xfs_bmbt_set_allf(&nrec, + nkey.br_startoff, 0, 0, + XFS_EXT_NORM); + } else { + XFS_BMBT_TRACE_CURSOR(cur, + EXIT); + *stat = 0; + return 0; + } + } + } + } + } + if (level > 0) { + kp = XFS_BMAP_KEY_IADDR(block, 1, cur); + pp = XFS_BMAP_PTR_IADDR(block, 1, cur); +#ifdef DEBUG + for (i = INT_GET(block->bb_numrecs, ARCH_CONVERT); i >= ptr; i--) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(pp[i - 1], ARCH_CONVERT), + level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + ovbcopy(&kp[ptr - 1], &kp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*kp)); + ovbcopy(&pp[ptr - 1], &pp[ptr], /* INT_: direct copy */ + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*pp)); +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, (xfs_bmbt_ptr_t)*bnop, + level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + kp[ptr - 1] = key; + INT_SET(pp[ptr - 1], ARCH_CONVERT, *bnop); + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_bmbt_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + xfs_bmbt_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + } else { + rp = XFS_BMAP_REC_IADDR(block, 1, cur); + ovbcopy(&rp[ptr - 1], &rp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*rp)); + rp[ptr - 1] = *recp; + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_bmbt_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + } + xfs_bmbt_log_block(cur, bp, XFS_BB_NUMRECS); +#ifdef DEBUG + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + if (level == 0) + xfs_btree_check_rec(XFS_BTNUM_BMAP, rp + ptr - 1, + rp + ptr); + else + xfs_btree_check_key(XFS_BTNUM_BMAP, kp + ptr - 1, + kp + ptr); + } +#endif + if (optr == 1 && (error = xfs_bmbt_updkey(cur, &key, level + 1))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + *bnop = nbno; + if (nbno != NULLFSBLOCK) { + *recp = nrec; + *curp = ncur; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +} + +STATIC int +xfs_bmbt_killroot( + xfs_btree_cur_t *cur, + int async) +{ + xfs_bmbt_block_t *block; + xfs_bmbt_block_t *cblock; + xfs_buf_t *cbp; + xfs_bmbt_key_t *ckp; + xfs_bmbt_ptr_t *cpp; +#ifdef DEBUG + int error; +#endif +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_killroot"; +#endif + int i; + xfs_bmbt_key_t *kp; + xfs_inode_t *ip; + xfs_ifork_t *ifp; + int level; + xfs_bmbt_ptr_t *pp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + level = cur->bc_nlevels - 1; + ASSERT(level >= 1); + /* + * Don't deal with the root block needs to be a leaf case. + * We're just going to turn the thing back into extents anyway. + */ + if (level == 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; + } + block = xfs_bmbt_get_block(cur, level, &cbp); + /* + * Give up if the root has multiple children. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) != 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; + } + /* + * Only do this if the next level will fit. + * Then the data must be copied up to the inode, + * instead of freeing the root you free the next level. + */ + cbp = cur->bc_bufs[level - 1]; + cblock = XFS_BUF_TO_BMBT_BLOCK(cbp); + if (INT_GET(cblock->bb_numrecs, ARCH_CONVERT) > XFS_BMAP_BLOCK_DMAXRECS(level, cur)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; + } + ASSERT(INT_GET(cblock->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO); + ASSERT(INT_GET(cblock->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO); + ip = cur->bc_private.b.ip; + ifp = XFS_IFORK_PTR(ip, cur->bc_private.b.whichfork); + ASSERT(XFS_BMAP_BLOCK_IMAXRECS(level, cur) == + XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes)); + i = (int)(INT_GET(cblock->bb_numrecs, ARCH_CONVERT) - XFS_BMAP_BLOCK_IMAXRECS(level, cur)); + if (i) { + xfs_iroot_realloc(ip, i, cur->bc_private.b.whichfork); + block = ifp->if_broot; + } + INT_MOD(block->bb_numrecs, ARCH_CONVERT, i); + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) == INT_GET(cblock->bb_numrecs, ARCH_CONVERT)); + kp = XFS_BMAP_KEY_IADDR(block, 1, cur); + ckp = XFS_BMAP_KEY_IADDR(cblock, 1, cur); + bcopy(ckp, kp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*kp)); + pp = XFS_BMAP_PTR_IADDR(block, 1, cur); + cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(cblock->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(cpp[i], ARCH_CONVERT), level - 1))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + bcopy(cpp, pp, INT_GET(block->bb_numrecs, ARCH_CONVERT) * sizeof(*pp)); + xfs_bmap_add_free(XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(cbp)), 1, + cur->bc_private.b.flist, cur->bc_mp); + if (!async) + xfs_trans_set_sync(cur->bc_tp); + ip->i_d.di_nblocks--; + if (XFS_IS_QUOTA_ON(cur->bc_mp) && + ip->i_ino != cur->bc_mp->m_sb.sb_uquotino && + ip->i_ino != cur->bc_mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(cur->bc_tp, ip, XFS_TRANS_DQ_BCOUNT, + -1L); + xfs_trans_binval(cur->bc_tp, cbp); + cur->bc_bufs[level - 1] = NULL; + INT_MOD(block->bb_level, ARCH_CONVERT, -1); + xfs_trans_log_inode(cur->bc_tp, ip, + XFS_ILOG_CORE | XFS_ILOG_FBROOT(cur->bc_private.b.whichfork)); + cur->bc_nlevels--; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; +} + +/* + * Log key values from the btree block. + */ +STATIC void +xfs_bmbt_log_keys( + xfs_btree_cur_t *cur, + xfs_buf_t *bp, + int kfirst, + int klast) +{ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_log_keys"; +#endif + xfs_trans_t *tp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGBII(cur, bp, kfirst, klast); + tp = cur->bc_tp; + if (bp) { + xfs_bmbt_block_t *block; + int first; + xfs_bmbt_key_t *kp; + int last; + + block = XFS_BUF_TO_BMBT_BLOCK(bp); + kp = XFS_BMAP_KEY_DADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&kp[kfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&kp[klast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(tp, bp, first, last); + } else { + xfs_inode_t *ip; + + ip = cur->bc_private.b.ip; + xfs_trans_log_inode(tp, ip, + XFS_ILOG_FBROOT(cur->bc_private.b.whichfork)); + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); +} + +/* + * Log pointer values from the btree block. + */ +STATIC void +xfs_bmbt_log_ptrs( + xfs_btree_cur_t *cur, + xfs_buf_t *bp, + int pfirst, + int plast) +{ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_log_ptrs"; +#endif + xfs_trans_t *tp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGBII(cur, bp, pfirst, plast); + tp = cur->bc_tp; + if (bp) { + xfs_bmbt_block_t *block; + int first; + int last; + xfs_bmbt_ptr_t *pp; + + block = XFS_BUF_TO_BMBT_BLOCK(bp); + pp = XFS_BMAP_PTR_DADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&pp[pfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&pp[plast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(tp, bp, first, last); + } else { + xfs_inode_t *ip; + + ip = cur->bc_private.b.ip; + xfs_trans_log_inode(tp, ip, + XFS_ILOG_FBROOT(cur->bc_private.b.whichfork)); + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); +} + +/* + * Lookup the record. The cursor is made to point to it, based on dir. + */ +STATIC int /* error */ +xfs_bmbt_lookup( + xfs_btree_cur_t *cur, + xfs_lookup_t dir, + int *stat) /* success/failure */ +{ + xfs_bmbt_block_t *block=NULL; + xfs_buf_t *bp; + xfs_daddr_t d; + xfs_sfiloff_t diff; + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_lookup"; +#endif + xfs_fsblock_t fsbno=0; + int high; + int i; + int keyno=0; + xfs_bmbt_key_t *kkbase=NULL; + xfs_bmbt_key_t *kkp; + xfs_bmbt_rec_t *krbase=NULL; + xfs_bmbt_rec_t *krp; + int level; + int low; + xfs_mount_t *mp; + xfs_bmbt_ptr_t *pp; + xfs_bmbt_irec_t *rp; + xfs_fileoff_t startoff; + xfs_trans_t *tp; + + XFS_STATS_INC(xfsstats.xs_bmbt_lookup); + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, (int)dir); + tp = cur->bc_tp; + mp = cur->bc_mp; + rp = &cur->bc_rec.b; + for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) { + if (level < cur->bc_nlevels - 1) { + d = XFS_FSB_TO_DADDR(mp, fsbno); + bp = cur->bc_bufs[level]; + if (bp && XFS_BUF_ADDR(bp) != d) + bp = (xfs_buf_t *)0; + if (!bp) { + if ((error = xfs_btree_read_bufl(mp, tp, fsbno, + 0, &bp, XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + xfs_btree_setbuf(cur, level, bp); + block = XFS_BUF_TO_BMBT_BLOCK(bp); + if ((error = xfs_btree_check_lblock(cur, block, + level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } else + block = XFS_BUF_TO_BMBT_BLOCK(bp); + } else + block = xfs_bmbt_get_block(cur, level, &bp); + if (diff == 0) + keyno = 1; + else { + if (level > 0) + kkbase = XFS_BMAP_KEY_IADDR(block, 1, cur); + else + krbase = XFS_BMAP_REC_IADDR(block, 1, cur); + low = 1; + if (!(high = INT_GET(block->bb_numrecs, ARCH_CONVERT))) { + ASSERT(level == 0); + cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + while (low <= high) { + XFS_STATS_INC(xfsstats.xs_bmbt_compare); + keyno = (low + high) >> 1; + if (level > 0) { + kkp = kkbase + keyno - 1; + startoff = INT_GET(kkp->br_startoff, ARCH_CONVERT); + } else { + krp = krbase + keyno - 1; + startoff = xfs_bmbt_get_startoff(krp); + } + diff = (xfs_sfiloff_t) + (startoff - rp->br_startoff); + if (diff < 0) + low = keyno + 1; + else if (diff > 0) + high = keyno - 1; + else + break; + } + } + if (level > 0) { + if (diff > 0 && --keyno < 1) + keyno = 1; + pp = XFS_BMAP_PTR_IADDR(block, keyno, cur); +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + fsbno = INT_GET(*pp, ARCH_CONVERT); + cur->bc_ptrs[level] = keyno; + } + } + if (dir != XFS_LOOKUP_LE && diff < 0) { + keyno++; + /* + * If ge search and we went off the end of the block, but it's + * not the last block, we're in the wrong block. + */ + if (dir == XFS_LOOKUP_GE && keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT) && + INT_GET(block->bb_rightsib, ARCH_CONVERT) != NULLDFSBNO) { + cur->bc_ptrs[0] = keyno; + if ((error = xfs_bmbt_increment(cur, 0, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + XFS_WANT_CORRUPTED_RETURN(i == 1); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + } + else if (dir == XFS_LOOKUP_LE && diff > 0) + keyno--; + cur->bc_ptrs[0] = keyno; + if (keyno == 0 || keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + } else { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = ((dir != XFS_LOOKUP_EQ) || (diff == 0)); + } + return 0; +} + +/* + * Move 1 record left from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_bmbt_lshift( + xfs_btree_cur_t *cur, + int level, + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_lshift"; +#endif +#ifdef DEBUG + int i; /* loop counter */ +#endif + xfs_bmbt_key_t key; /* bmap btree key */ + xfs_buf_t *lbp; /* left buffer pointer */ + xfs_bmbt_block_t *left; /* left btree block */ + xfs_bmbt_key_t *lkp=NULL; /* left btree key */ + xfs_bmbt_ptr_t *lpp; /* left address pointer */ + int lrecs; /* left record count */ + xfs_bmbt_rec_t *lrp=NULL; /* left record pointer */ + xfs_mount_t *mp; /* file system mount point */ + xfs_buf_t *rbp; /* right buffer pointer */ + xfs_bmbt_block_t *right; /* right btree block */ + xfs_bmbt_key_t *rkp=NULL; /* right btree key */ + xfs_bmbt_ptr_t *rpp=NULL; /* right address pointer */ + xfs_bmbt_rec_t *rrp=NULL; /* right record pointer */ + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, level); + if (level == cur->bc_nlevels - 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + rbp = cur->bc_bufs[level]; + right = XFS_BUF_TO_BMBT_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, right, level, rbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + if (INT_GET(right->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + if (cur->bc_ptrs[level] <= 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + mp = cur->bc_mp; + if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, INT_GET(right->bb_leftsib, ARCH_CONVERT), 0, + &lbp, XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + left = XFS_BUF_TO_BMBT_BLOCK(lbp); + if ((error = xfs_btree_check_lblock(cur, left, level, lbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) == XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1; + if (level > 0) { + lkp = XFS_BMAP_KEY_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rkp = XFS_BMAP_KEY_IADDR(right, 1, cur); + *lkp = *rkp; + xfs_bmbt_log_keys(cur, lbp, lrecs, lrecs); + lpp = XFS_BMAP_PTR_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rpp = XFS_BMAP_PTR_IADDR(right, 1, cur); +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, INT_GET(*rpp, ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + *lpp = *rpp; /* INT_: direct copy */ + xfs_bmbt_log_ptrs(cur, lbp, lrecs, lrecs); + } else { + lrp = XFS_BMAP_REC_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rrp = XFS_BMAP_REC_IADDR(right, 1, cur); + *lrp = *rrp; + xfs_bmbt_log_recs(cur, lbp, lrecs, lrecs); + } + INT_MOD(left->bb_numrecs, ARCH_CONVERT, +1); + xfs_bmbt_log_block(cur, lbp, XFS_BB_NUMRECS); +#ifdef DEBUG + if (level > 0) + xfs_btree_check_key(XFS_BTNUM_BMAP, lkp - 1, lkp); + else + xfs_btree_check_rec(XFS_BTNUM_BMAP, lrp - 1, lrp); +#endif + INT_MOD(right->bb_numrecs, ARCH_CONVERT, -1); + xfs_bmbt_log_block(cur, rbp, XFS_BB_NUMRECS); + if (level > 0) { +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i + 1], ARCH_CONVERT), + level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + ovbcopy(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); + xfs_bmbt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_bmbt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } else { + ovbcopy(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_bmbt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(rrp)); + rkp = &key; + } + if ((error = xfs_bmbt_updkey(cur, rkp, level + 1))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + cur->bc_ptrs[level]--; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +} + +/* + * Move 1 record right from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_bmbt_rshift( + xfs_btree_cur_t *cur, + int level, + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_rshift"; +#endif + int i; /* loop counter */ + xfs_bmbt_key_t key; /* bmap btree key */ + xfs_buf_t *lbp; /* left buffer pointer */ + xfs_bmbt_block_t *left; /* left btree block */ + xfs_bmbt_key_t *lkp; /* left btree key */ + xfs_bmbt_ptr_t *lpp; /* left address pointer */ + xfs_bmbt_rec_t *lrp; /* left record pointer */ + xfs_mount_t *mp; /* file system mount point */ + xfs_buf_t *rbp; /* right buffer pointer */ + xfs_bmbt_block_t *right; /* right btree block */ + xfs_bmbt_key_t *rkp; /* right btree key */ + xfs_bmbt_ptr_t *rpp; /* right address pointer */ + xfs_bmbt_rec_t *rrp=NULL; /* right record pointer */ + struct xfs_btree_cur *tcur; /* temporary btree cursor */ + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, level); + if (level == cur->bc_nlevels - 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + lbp = cur->bc_bufs[level]; + left = XFS_BUF_TO_BMBT_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, left, level, lbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + if (cur->bc_ptrs[level] >= INT_GET(left->bb_numrecs, ARCH_CONVERT)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + mp = cur->bc_mp; + if ((error = xfs_btree_read_bufl(mp, cur->bc_tp, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, + &rbp, XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + right = XFS_BUF_TO_BMBT_BLOCK(rbp); + if ((error = xfs_btree_check_lblock(cur, right, level, rbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) == XFS_BMAP_BLOCK_IMAXRECS(level, cur)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + if (level > 0) { + lkp = XFS_BMAP_KEY_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + lpp = XFS_BMAP_PTR_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rkp = XFS_BMAP_KEY_IADDR(right, 1, cur); + rpp = XFS_BMAP_PTR_IADDR(right, 1, cur); +#ifdef DEBUG + for (i = INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1; i >= 0; i--) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + ovbcopy(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, INT_GET(*lpp, ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + *rkp = *lkp; + *rpp = *lpp; /* INT_: direct copy */ + xfs_bmbt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + xfs_bmbt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + } else { + lrp = XFS_BMAP_REC_IADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rrp = XFS_BMAP_REC_IADDR(right, 1, cur); + ovbcopy(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + *rrp = *lrp; + xfs_bmbt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_get_startoff(rrp)); + rkp = &key; + } + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -1); + xfs_bmbt_log_block(cur, lbp, XFS_BB_NUMRECS); + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); +#ifdef DEBUG + if (level > 0) + xfs_btree_check_key(XFS_BTNUM_BMAP, rkp, rkp + 1); + else + xfs_btree_check_rec(XFS_BTNUM_BMAP, rrp, rrp + 1); +#endif + xfs_bmbt_log_block(cur, rbp, XFS_BB_NUMRECS); + if ((error = xfs_btree_dup_cursor(cur, &tcur))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_bmbt_increment(tcur, level, &i))) { + XFS_BMBT_TRACE_CURSOR(tcur, ERROR); + goto error1; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_bmbt_updkey(tcur, rkp, level + 1))) { + XFS_BMBT_TRACE_CURSOR(tcur, ERROR); + goto error1; + } + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +error0: + XFS_BMBT_TRACE_CURSOR(cur, ERROR); +error1: + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; +} + +/* + * Determine the extent state. + */ +/* ARGSUSED */ +STATIC xfs_exntst_t +xfs_extent_state( + xfs_filblks_t blks, + int extent_flag) +{ + if (extent_flag) { + ASSERT(blks != 0); /* saved for DMIG */ + return XFS_EXT_UNWRITTEN; + } + return XFS_EXT_NORM; +} + + +/* + * Split cur/level block in half. + * Return new block number and its first record (to be inserted into parent). + */ +STATIC int /* error */ +xfs_bmbt_split( + xfs_btree_cur_t *cur, + int level, + xfs_fsblock_t *bnop, + xfs_bmbt_key_t *keyp, + xfs_btree_cur_t **curp, + int *stat) /* success/failure */ +{ + xfs_alloc_arg_t args; /* block allocation args */ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_split"; +#endif + int i; /* loop counter */ + xfs_fsblock_t lbno; /* left sibling block number */ + xfs_buf_t *lbp; /* left buffer pointer */ + xfs_bmbt_block_t *left; /* left btree block */ + xfs_bmbt_key_t *lkp; /* left btree key */ + xfs_bmbt_ptr_t *lpp; /* left address pointer */ + xfs_bmbt_rec_t *lrp; /* left record pointer */ + xfs_buf_t *rbp; /* right buffer pointer */ + xfs_bmbt_block_t *right; /* right btree block */ + xfs_bmbt_key_t *rkp; /* right btree key */ + xfs_bmbt_ptr_t *rpp; /* right address pointer */ + xfs_bmbt_block_t *rrblock; /* right-right btree block */ + xfs_buf_t *rrbp; /* right-right buffer pointer */ + xfs_bmbt_rec_t *rrp; /* right record pointer */ + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGIFK(cur, level, *bnop, keyp); + args.tp = cur->bc_tp; + args.mp = cur->bc_mp; + lbp = cur->bc_bufs[level]; + lbno = XFS_DADDR_TO_FSB(args.mp, XFS_BUF_ADDR(lbp)); + left = XFS_BUF_TO_BMBT_BLOCK(lbp); + args.fsbno = cur->bc_private.b.firstblock; + if (args.fsbno == NULLFSBLOCK) { + args.fsbno = lbno; + args.type = XFS_ALLOCTYPE_START_BNO; + } else if (cur->bc_private.b.flist->xbf_low) + args.type = XFS_ALLOCTYPE_FIRST_AG; + else + args.type = XFS_ALLOCTYPE_NEAR_BNO; + args.mod = args.minleft = args.alignment = args.total = args.isfl = + args.userdata = args.minalignslop = 0; + args.minlen = args.maxlen = args.prod = 1; + args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; + if (!args.wasdel && xfs_trans_get_block_res(args.tp) == 0) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return XFS_ERROR(ENOSPC); + } + if ((error = xfs_alloc_vextent(&args))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (args.fsbno == NULLFSBLOCK) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + ASSERT(args.len == 1); + cur->bc_private.b.firstblock = args.fsbno; + cur->bc_private.b.allocated++; + cur->bc_private.b.ip->i_d.di_nblocks++; + xfs_trans_log_inode(args.tp, cur->bc_private.b.ip, XFS_ILOG_CORE); + if (XFS_IS_QUOTA_ON(args.mp) && + cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_uquotino && + cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip, + XFS_TRANS_DQ_BCOUNT, 1L); + rbp = xfs_btree_get_bufl(args.mp, args.tp, args.fsbno, 0); + right = XFS_BUF_TO_BMBT_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, left, level, rbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + INT_SET(right->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC); + right->bb_level = left->bb_level; /* INT_: direct copy */ + INT_SET(right->bb_numrecs, ARCH_CONVERT, (__uint16_t)(INT_GET(left->bb_numrecs, ARCH_CONVERT) / 2)); + if ((INT_GET(left->bb_numrecs, ARCH_CONVERT) & 1) && + cur->bc_ptrs[level] <= INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1) + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); + i = INT_GET(left->bb_numrecs, ARCH_CONVERT) - INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1; + if (level > 0) { + lkp = XFS_BMAP_KEY_IADDR(left, i, cur); + lpp = XFS_BMAP_PTR_IADDR(left, i, cur); + rkp = XFS_BMAP_KEY_IADDR(right, 1, cur); + rpp = XFS_BMAP_PTR_IADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(lpp[i], ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + bcopy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + bcopy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); + xfs_bmbt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_bmbt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + keyp->br_startoff = INT_GET(rkp->br_startoff, ARCH_CONVERT); + } else { + lrp = XFS_BMAP_REC_IADDR(left, i, cur); + rrp = XFS_BMAP_REC_IADDR(right, 1, cur); + bcopy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_bmbt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + keyp->br_startoff = xfs_bmbt_get_startoff(rrp); + } + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -(INT_GET(right->bb_numrecs, ARCH_CONVERT))); + right->bb_rightsib = left->bb_rightsib; /* INT_: direct copy */ + INT_SET(left->bb_rightsib, ARCH_CONVERT, args.fsbno); + INT_SET(right->bb_leftsib, ARCH_CONVERT, lbno); + xfs_bmbt_log_block(cur, rbp, XFS_BB_ALL_BITS); + xfs_bmbt_log_block(cur, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); + if (INT_GET(right->bb_rightsib, ARCH_CONVERT) != NULLDFSBNO) { + if ((error = xfs_btree_read_bufl(args.mp, args.tp, + INT_GET(right->bb_rightsib, ARCH_CONVERT), 0, &rrbp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + rrblock = XFS_BUF_TO_BMBT_BLOCK(rrbp); + if ((error = xfs_btree_check_lblock(cur, rrblock, level, rrbp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, args.fsbno); + xfs_bmbt_log_block(cur, rrbp, XFS_BB_LEFTSIB); + } + if (cur->bc_ptrs[level] > INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1) { + xfs_btree_setbuf(cur, level, rbp); + cur->bc_ptrs[level] -= INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + if (level + 1 < cur->bc_nlevels) { + if ((error = xfs_btree_dup_cursor(cur, curp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + (*curp)->bc_ptrs[level + 1]++; + } + *bnop = args.fsbno; + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +} + + +/* + * Update keys for the record. + */ +STATIC int +xfs_bmbt_updkey( + xfs_btree_cur_t *cur, + xfs_bmbt_key_t *keyp, /* on-disk format */ + int level) +{ + xfs_bmbt_block_t *block; + xfs_buf_t *bp; +#ifdef DEBUG + int error; +#endif +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_updkey"; +#endif + xfs_bmbt_key_t *kp; + int ptr; + + ASSERT(level >= 1); + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGIK(cur, level, keyp); + for (ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) { + block = xfs_bmbt_get_block(cur, level, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + ptr = cur->bc_ptrs[level]; + kp = XFS_BMAP_KEY_IADDR(block, ptr, cur); + *kp = *keyp; + xfs_bmbt_log_keys(cur, bp, ptr, ptr); + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; +} + +/* + * Convert on-disk form of btree root to in-memory form. + */ +void +xfs_bmdr_to_bmbt( + xfs_bmdr_block_t *dblock, + int dblocklen, + xfs_bmbt_block_t *rblock, + int rblocklen) +{ + int dmxr; + xfs_bmbt_key_t *fkp; + xfs_bmbt_ptr_t *fpp; + xfs_bmbt_key_t *tkp; + xfs_bmbt_ptr_t *tpp; + + INT_SET(rblock->bb_magic, ARCH_CONVERT, XFS_BMAP_MAGIC); + rblock->bb_level = dblock->bb_level; /* both in on-disk format */ + ASSERT(INT_GET(rblock->bb_level, ARCH_CONVERT) > 0); + rblock->bb_numrecs = dblock->bb_numrecs;/* both in on-disk format */ + INT_SET(rblock->bb_leftsib, ARCH_CONVERT, NULLDFSBNO); + INT_SET(rblock->bb_rightsib, ARCH_CONVERT, NULLDFSBNO); + dmxr = (int)XFS_BTREE_BLOCK_MAXRECS(dblocklen, xfs_bmdr, 0); + fkp = XFS_BTREE_KEY_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + tkp = XFS_BMAP_BROOT_KEY_ADDR(rblock, 1, rblocklen); + fpp = XFS_BTREE_PTR_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + tpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen); + dmxr = INT_GET(dblock->bb_numrecs, ARCH_CONVERT); + bcopy(fkp, tkp, sizeof(*fkp) * dmxr); + bcopy(fpp, tpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */ +} + +/* + * Decrement cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_bmbt_decrement( + xfs_btree_cur_t *cur, + int level, + int *stat) /* success/failure */ +{ + xfs_bmbt_block_t *block; + xfs_buf_t *bp; + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_decrement"; +#endif + xfs_fsblock_t fsbno; + int lev; + xfs_mount_t *mp; + xfs_trans_t *tp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, level); + ASSERT(level < cur->bc_nlevels); + if (level < cur->bc_nlevels - 1) + xfs_btree_readahead(cur, level, XFS_BTCUR_LEFTRA); + if (--cur->bc_ptrs[level] > 0) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + block = xfs_bmbt_get_block(cur, level, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + if (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + if (--cur->bc_ptrs[lev] > 0) + break; + if (lev < cur->bc_nlevels - 1) + xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA); + } + if (lev == cur->bc_nlevels) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + tp = cur->bc_tp; + mp = cur->bc_mp; + for (block = xfs_bmbt_get_block(cur, lev, &bp); lev > level; ) { + fsbno = INT_GET(*XFS_BMAP_PTR_IADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufl(mp, tp, fsbno, 0, &bp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_BMBT_BLOCK(bp); + if ((error = xfs_btree_check_lblock(cur, block, lev, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + cur->bc_ptrs[lev] = INT_GET(block->bb_numrecs, ARCH_CONVERT); + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +} + +/* + * Delete the record pointed to by cur. + */ +int /* error */ +xfs_bmbt_delete( + xfs_btree_cur_t *cur, + int async, /* deletion can be async */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_delete"; +#endif + int i; + int level; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + for (level = 0, i = 2; i == 2; level++) { + if ((error = xfs_bmbt_delrec(cur, level, async, &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } + if (i == 0) { + for (level = 1; level < cur->bc_nlevels; level++) { + if (cur->bc_ptrs[level] == 0) { + if ((error = xfs_bmbt_decrement(cur, level, + &i))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + break; + } + } + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = i; + return 0; +} + +/* + * Convert a compressed bmap extent record to an uncompressed form. + * This code must be in sync with the routines xfs_bmbt_get_startoff, + * xfs_bmbt_get_startblock, xfs_bmbt_get_blockcount and xfs_bmbt_get_state. + */ +void +xfs_bmbt_get_all( + xfs_bmbt_rec_t *r, + xfs_bmbt_irec_t *s) +{ + int ext_flag; + xfs_exntst_t st; + +#if BMBT_USE_64 + ext_flag = (int)((INT_GET(r->l0, ARCH_CONVERT)) >> (64 - BMBT_EXNTFLAG_BITLEN)); +#if XFS_BIG_FILES + s->br_startoff = ((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; +#else /* !XFS_BIG_FILES */ + { + xfs_dfiloff_t o; + + o = ((xfs_dfiloff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; + ASSERT((o >> 32) == 0); + s->br_startoff = (xfs_fileoff_t)o; + } +#endif /* XFS_BIG_FILES */ +#if XFS_BIG_FILESYSTEMS + s->br_startblock = (((xfs_fsblock_t)INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(9)) << 43) | + (((xfs_fsblock_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); +#else +#ifdef DEBUG + { + xfs_dfsbno_t b; + + b = (((xfs_dfsbno_t)INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(9)) << 43) | + (((xfs_dfsbno_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); + ASSERT((b >> 32) == 0 || ISNULLDSTARTBLOCK(b)); + s->br_startblock = (xfs_fsblock_t)b; + } +#else /* !DEBUG */ + s->br_startblock = (xfs_fsblock_t)(((xfs_dfsbno_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); +#endif /* DEBUG */ +#endif /* XFS_BIG_FILESYSTEMS */ + s->br_blockcount = (xfs_filblks_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK64LO(21)); +#else /* !BMBT_USE_64 */ + ext_flag = (INT_GET(r->l0, ARCH_CONVERT) >> (32 - BMBT_EXNTFLAG_BITLEN)); +#if XFS_BIG_FILES + s->br_startoff = (((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK32LO(32 - BMBT_EXNTFLAG_BITLEN)) << 23) | + (((xfs_fileoff_t)INT_GET(r->l1, ARCH_CONVERT)) >> 9); +#else /* !XFS_BIG_FILES */ +#ifdef DEBUG + { + xfs_dfiloff_t o; + + o = (((xfs_dfiloff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK32LO(32 - BMBT_EXNTFLAG_BITLEN)) << 23) | + (((xfs_dfiloff_t)INT_GET(r->l1, ARCH_CONVERT)) >> 9); + ASSERT((o >> 32) == 0); + s->br_startoff = (xfs_fileoff_t)o; + } +#else /* !DEBUG */ + s->br_startoff = (((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK32LO(32 - BMBT_EXNTFLAG_BITLEN)) << 23) | + (((xfs_fileoff_t)INT_GET(r->l1, ARCH_CONVERT)) >> 9); +#endif /* DEBUG */ +#endif /* XFS_BIG_FILES */ +#if XFS_BIG_FILESYSTEMS + s->br_startblock = + (((xfs_fsblock_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK32LO(9))) << 43) | + (((xfs_fsblock_t)INT_GET(r->l2, ARCH_CONVERT)) << 11) | + (((xfs_fsblock_t)INT_GET(r->l3, ARCH_CONVERT)) >> 21); +#else +#ifdef DEBUG + { + xfs_dfsbno_t b; + + b = (((xfs_dfsbno_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK32LO(9))) << 43) | + (((xfs_dfsbno_t)INT_GET(r->l2, ARCH_CONVERT)) << 11) | + (((xfs_dfsbno_t)INT_GET(r->l3, ARCH_CONVERT)) >> 21); + ASSERT((b >> 32) == 0 || ISNULLDSTARTBLOCK(b)); + s->br_startblock = (xfs_fsblock_t)b; + } +#else /* !DEBUG */ + s->br_startblock = (((xfs_fsblock_t)INT_GET(r->l2, ARCH_CONVERT)) << 11) | + (((xfs_fsblock_t)INT_GET(r->l3, ARCH_CONVERT)) >> 21); +#endif /* DEBUG */ +#endif /* XFS_BIG_FILESYSTEMS */ + s->br_blockcount = (xfs_filblks_t)(INT_GET(r->l3, ARCH_CONVERT) & XFS_MASK32LO(21)); +#endif /* BMBT_USE_64 */ + /* This is xfs_extent_state() in-line */ + if (ext_flag) { + ASSERT(s->br_blockcount != 0); /* saved for DMIG */ + st = XFS_EXT_UNWRITTEN; + } else + st = XFS_EXT_NORM; + s->br_state = st; +} + +/* + * Get the block pointer for the given level of the cursor. + * Fill in the buffer pointer, if applicable. + */ +xfs_bmbt_block_t * +xfs_bmbt_get_block( + xfs_btree_cur_t *cur, + int level, + xfs_buf_t **bpp) +{ + xfs_ifork_t *ifp; + xfs_bmbt_block_t *rval; + + if (level < cur->bc_nlevels - 1) { + *bpp = cur->bc_bufs[level]; + rval = XFS_BUF_TO_BMBT_BLOCK(*bpp); + } else { + *bpp = 0; + ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, + cur->bc_private.b.whichfork); + rval = ifp->if_broot; + } + return rval; +} + +/* + * Extract the blockcount field from a bmap extent record. + */ +xfs_filblks_t +xfs_bmbt_get_blockcount( + xfs_bmbt_rec_t *r) +{ +#if BMBT_USE_64 + return (xfs_filblks_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK64LO(21)); +#else /* !BMBT_USE_64 */ + return (xfs_filblks_t)(INT_GET(r->l3, ARCH_CONVERT) & XFS_MASK32LO(21)); +#endif /* BMBT_USE_64 */ +} + +/* + * Extract the startblock field from a bmap extent record. + */ +xfs_fsblock_t +xfs_bmbt_get_startblock( + xfs_bmbt_rec_t *r) +{ +#if BMBT_USE_64 +#if XFS_BIG_FILESYSTEMS + return (((xfs_fsblock_t)INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(9)) << 43) | + (((xfs_fsblock_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); +#else +#ifdef DEBUG + xfs_dfsbno_t b; + + b = (((xfs_dfsbno_t)INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(9)) << 43) | + (((xfs_dfsbno_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); + ASSERT((b >> 32) == 0 || ISNULLDSTARTBLOCK(b)); + return (xfs_fsblock_t)b; +#else /* !DEBUG */ + return (xfs_fsblock_t)(((xfs_dfsbno_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); +#endif /* DEBUG */ +#endif /* XFS_BIG_FILESYSTEMS */ +#else /* !BMBT_USE_64 */ +#if XFS_BIG_FILESYSTEMS + return (((xfs_fsblock_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK32LO(9))) << 43) | + (((xfs_fsblock_t)INT_GET(r->l2, ARCH_CONVERT)) << 11) | + (((xfs_fsblock_t)INT_GET(r->l3, ARCH_CONVERT)) >> 21); +#else +#ifdef DEBUG + xfs_dfsbno_t b; + + b = (((xfs_dfsbno_t)(INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK32LO(9))) << 43) | + (((xfs_dfsbno_t)INT_GET(r->l2, ARCH_CONVERT)) << 11) | + (((xfs_dfsbno_t)INT_GET(r->l3, ARCH_CONVERT)) >> 21); + ASSERT((b >> 32) == 0 || ISNULLDSTARTBLOCK(b)); + return (xfs_fsblock_t)b; +#else /* !DEBUG */ + return (((xfs_fsblock_t)INT_GET(r->l2, ARCH_CONVERT)) << 11) | + (((xfs_fsblock_t)INT_GET(r->l3, ARCH_CONVERT)) >> 21); +#endif /* DEBUG */ +#endif /* XFS_BIG_FILESYSTEMS */ +#endif /* BMBT_USE_64 */ +} + +/* + * Extract the startoff field from a bmap extent record. + */ +xfs_fileoff_t +xfs_bmbt_get_startoff( + xfs_bmbt_rec_t *r) +{ +#if BMBT_USE_64 +#if XFS_BIG_FILES + return ((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; +#else /* !XFS_BIG_FILES */ + xfs_dfiloff_t o; + + o = ((xfs_dfiloff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; + ASSERT((o >> 32) == 0); + return (xfs_fileoff_t)o; +#endif /* XFS_BIG_FILES */ +#else /* !BMBT_USE_64 */ +#if XFS_BIG_FILES + return (((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK32LO(32 - BMBT_EXNTFLAG_BITLEN)) << 23) | + (((xfs_fileoff_t)INT_GET(r->l1, ARCH_CONVERT)) >> 9); +#else /* !XFS_BIG_FILES */ +#ifdef DEBUG + xfs_dfiloff_t o; + + o = (((xfs_dfiloff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK32LO(32 - BMBT_EXNTFLAG_BITLEN)) << 23) | + (((xfs_dfiloff_t)INT_GET(r->l1, ARCH_CONVERT)) >> 9); + ASSERT((o >> 32) == 0); + return (xfs_fileoff_t)o; +#else /* !DEBUG */ + return (((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) & + XFS_MASK32LO(32 - BMBT_EXNTFLAG_BITLEN)) << 23) | + (((xfs_fileoff_t)INT_GET(r->l1, ARCH_CONVERT)) >> 9); +#endif /* DEBUG */ +#endif /* XFS_BIG_FILES */ +#endif /* BMBT_USE_64 */ +} + +xfs_exntst_t +xfs_bmbt_get_state( + xfs_bmbt_rec_t *r) +{ + int ext_flag; + +#if BMBT_USE_64 + ext_flag = (int)((INT_GET(r->l0, ARCH_CONVERT)) >> (64 - BMBT_EXNTFLAG_BITLEN)); +#else /* !BMBT_USE_64 */ + ext_flag = (INT_GET(r->l0, ARCH_CONVERT) >> (32 - BMBT_EXNTFLAG_BITLEN)); +#endif /* BMBT_USE_64 */ + return xfs_extent_state(xfs_bmbt_get_blockcount(r), + ext_flag); +} + + +/* + * Increment cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_bmbt_increment( + xfs_btree_cur_t *cur, + int level, + int *stat) /* success/failure */ +{ + xfs_bmbt_block_t *block; + xfs_buf_t *bp; + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_increment"; +#endif + xfs_fsblock_t fsbno; + int lev; + xfs_mount_t *mp; + xfs_trans_t *tp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGI(cur, level); + ASSERT(level < cur->bc_nlevels); + if (level < cur->bc_nlevels - 1) + xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); + block = xfs_bmbt_get_block(cur, level, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, level, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + if (++cur->bc_ptrs[level] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; + } + if (INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + block = xfs_bmbt_get_block(cur, lev, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, lev, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + if (++cur->bc_ptrs[lev] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) + break; + if (lev < cur->bc_nlevels - 1) + xfs_btree_readahead(cur, lev, XFS_BTCUR_RIGHTRA); + } + if (lev == cur->bc_nlevels) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + tp = cur->bc_tp; + mp = cur->bc_mp; + for (block = xfs_bmbt_get_block(cur, lev, &bp); lev > level; ) { + fsbno = INT_GET(*XFS_BMAP_PTR_IADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufl(mp, tp, fsbno, 0, &bp, + XFS_BMAP_BTREE_REF))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_BMBT_BLOCK(bp); + if ((error = xfs_btree_check_lblock(cur, block, lev, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + cur->bc_ptrs[lev] = 1; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 1; + return 0; +} + +/* + * Insert the current record at the point referenced by cur. + */ +int /* error */ +xfs_bmbt_insert( + xfs_btree_cur_t *cur, + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_insert"; +#endif + int i; + int level; + xfs_fsblock_t nbno; + xfs_btree_cur_t *ncur; + xfs_bmbt_rec_t nrec; + xfs_btree_cur_t *pcur; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + level = 0; + nbno = NULLFSBLOCK; + xfs_bmbt_set_all(&nrec, &cur->bc_rec.b); + ncur = (xfs_btree_cur_t *)0; + pcur = cur; + do { + if ((error = xfs_bmbt_insrec(pcur, level++, &nbno, &nrec, &ncur, + &i))) { + if (pcur != cur) + xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (pcur != cur && (ncur || nbno == NULLFSBLOCK)) { + cur->bc_nlevels = pcur->bc_nlevels; + cur->bc_private.b.allocated += + pcur->bc_private.b.allocated; + pcur->bc_private.b.allocated = 0; + ASSERT((cur->bc_private.b.firstblock != NULLFSBLOCK) || + (cur->bc_private.b.ip->i_d.di_flags & + XFS_DIFLAG_REALTIME)); + cur->bc_private.b.firstblock = + pcur->bc_private.b.firstblock; + ASSERT(cur->bc_private.b.flist == + pcur->bc_private.b.flist); + xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); + } + if (ncur) { + pcur = ncur; + ncur = (xfs_btree_cur_t *)0; + } + } while (nbno != NULLFSBLOCK); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = i; + return 0; +error0: + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; +} + +/* + * Log fields from the btree block header. + */ +void +xfs_bmbt_log_block( + xfs_btree_cur_t *cur, + xfs_buf_t *bp, + int fields) +{ + int first; +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_log_block"; +#endif + int last; + xfs_trans_t *tp; + static const short offsets[] = { + offsetof(xfs_bmbt_block_t, bb_magic), + offsetof(xfs_bmbt_block_t, bb_level), + offsetof(xfs_bmbt_block_t, bb_numrecs), + offsetof(xfs_bmbt_block_t, bb_leftsib), + offsetof(xfs_bmbt_block_t, bb_rightsib), + sizeof(xfs_bmbt_block_t) + }; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGBI(cur, bp, fields); + tp = cur->bc_tp; + if (bp) { + xfs_btree_offsets(fields, offsets, XFS_BB_NUM_BITS, &first, + &last); + xfs_trans_log_buf(tp, bp, first, last); + } else + xfs_trans_log_inode(tp, cur->bc_private.b.ip, + XFS_ILOG_FBROOT(cur->bc_private.b.whichfork)); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); +} + +/* + * Log record values from the btree block. + */ +void +xfs_bmbt_log_recs( + xfs_btree_cur_t *cur, + xfs_buf_t *bp, + int rfirst, + int rlast) +{ + xfs_bmbt_block_t *block; + int first; +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_log_recs"; +#endif + int last; + xfs_bmbt_rec_t *rp; + xfs_trans_t *tp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGBII(cur, bp, rfirst, rlast); + ASSERT(bp); + tp = cur->bc_tp; + block = XFS_BUF_TO_BMBT_BLOCK(bp); + rp = XFS_BMAP_REC_DADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&rp[rfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&rp[rlast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(tp, bp, first, last); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); +} + +int /* error */ +xfs_bmbt_lookup_eq( + xfs_btree_cur_t *cur, + xfs_fileoff_t off, + xfs_fsblock_t bno, + xfs_filblks_t len, + int *stat) /* success/failure */ +{ + cur->bc_rec.b.br_startoff = off; + cur->bc_rec.b.br_startblock = bno; + cur->bc_rec.b.br_blockcount = len; + return xfs_bmbt_lookup(cur, XFS_LOOKUP_EQ, stat); +} + +int /* error */ +xfs_bmbt_lookup_ge( + xfs_btree_cur_t *cur, + xfs_fileoff_t off, + xfs_fsblock_t bno, + xfs_filblks_t len, + int *stat) /* success/failure */ +{ + cur->bc_rec.b.br_startoff = off; + cur->bc_rec.b.br_startblock = bno; + cur->bc_rec.b.br_blockcount = len; + return xfs_bmbt_lookup(cur, XFS_LOOKUP_GE, stat); +} + +int /* error */ +xfs_bmbt_lookup_le( + xfs_btree_cur_t *cur, + xfs_fileoff_t off, + xfs_fsblock_t bno, + xfs_filblks_t len, + int *stat) /* success/failure */ +{ + cur->bc_rec.b.br_startoff = off; + cur->bc_rec.b.br_startblock = bno; + cur->bc_rec.b.br_blockcount = len; + return xfs_bmbt_lookup(cur, XFS_LOOKUP_LE, stat); +} + +/* + * Give the bmap btree a new root block. Copy the old broot contents + * down into a real block and make the broot point to it. + */ +int /* error */ +xfs_bmbt_newroot( + xfs_btree_cur_t *cur, /* btree cursor */ + int *logflags, /* logging flags for inode */ + int *stat) /* return status - 0 fail */ +{ + xfs_alloc_arg_t args; /* allocation arguments */ + xfs_bmbt_block_t *block; /* bmap btree block */ + xfs_buf_t *bp; /* buffer for block */ + xfs_bmbt_block_t *cblock; /* child btree block */ + xfs_bmbt_key_t *ckp; /* child key pointer */ + xfs_bmbt_ptr_t *cpp; /* child ptr pointer */ + int error; /* error return code */ +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_newroot"; +#endif +#ifdef DEBUG + int i; /* loop counter */ +#endif + xfs_bmbt_key_t *kp; /* pointer to bmap btree key */ + int level; /* btree level */ + xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */ + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + level = cur->bc_nlevels - 1; + block = xfs_bmbt_get_block(cur, level, &bp); + /* + * Copy the root into a real block. + */ + args.mp = cur->bc_mp; + pp = XFS_BMAP_PTR_IADDR(block, 1, cur); + args.tp = cur->bc_tp; + args.fsbno = cur->bc_private.b.firstblock; + args.mod = args.minleft = args.alignment = args.total = args.isfl = + args.userdata = args.minalignslop = 0; + args.minlen = args.maxlen = args.prod = 1; + args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; + if (args.fsbno == NULLFSBLOCK) { +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + args.fsbno = INT_GET(*pp, ARCH_CONVERT); + args.type = XFS_ALLOCTYPE_START_BNO; + } else if (args.wasdel) + args.type = XFS_ALLOCTYPE_FIRST_AG; + else + args.type = XFS_ALLOCTYPE_NEAR_BNO; + if ((error = xfs_alloc_vextent(&args))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + if (args.fsbno == NULLFSBLOCK) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *stat = 0; + return 0; + } + ASSERT(args.len == 1); + cur->bc_private.b.firstblock = args.fsbno; + cur->bc_private.b.allocated++; + cur->bc_private.b.ip->i_d.di_nblocks++; + if (XFS_IS_QUOTA_ON(args.mp) && + cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_uquotino && + cur->bc_private.b.ip->i_ino != args.mp->m_sb.sb_gquotino) + xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip, + XFS_TRANS_DQ_BCOUNT, 1L); + bp = xfs_btree_get_bufl(args.mp, cur->bc_tp, args.fsbno, 0); + cblock = XFS_BUF_TO_BMBT_BLOCK(bp); + *cblock = *block; + INT_MOD(block->bb_level, ARCH_CONVERT, +1); + INT_SET(block->bb_numrecs, ARCH_CONVERT, 1); + cur->bc_nlevels++; + cur->bc_ptrs[level + 1] = 1; + kp = XFS_BMAP_KEY_IADDR(block, 1, cur); + ckp = XFS_BMAP_KEY_IADDR(cblock, 1, cur); + bcopy(kp, ckp, INT_GET(cblock->bb_numrecs, ARCH_CONVERT) * sizeof(*kp)); + cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(cblock->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_lptr(cur, INT_GET(pp[i], ARCH_CONVERT), level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + } +#endif + bcopy(pp, cpp, INT_GET(cblock->bb_numrecs, ARCH_CONVERT) * sizeof(*pp)); +#ifdef DEBUG + if ((error = xfs_btree_check_lptr(cur, (xfs_bmbt_ptr_t)args.fsbno, + level))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + INT_SET(*pp, ARCH_CONVERT, args.fsbno); + xfs_iroot_realloc(cur->bc_private.b.ip, 1 - INT_GET(cblock->bb_numrecs, ARCH_CONVERT), + cur->bc_private.b.whichfork); + xfs_btree_setbuf(cur, level, bp); + /* + * Do all this logging at the end so that + * the root is at the right level. + */ + xfs_bmbt_log_block(cur, bp, XFS_BB_ALL_BITS); + xfs_bmbt_log_keys(cur, bp, 1, INT_GET(cblock->bb_numrecs, ARCH_CONVERT)); + xfs_bmbt_log_ptrs(cur, bp, 1, INT_GET(cblock->bb_numrecs, ARCH_CONVERT)); + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + *logflags |= + XFS_ILOG_CORE | XFS_ILOG_FBROOT(cur->bc_private.b.whichfork); + *stat = 1; + return 0; +} + +/* + * Set all the fields in a bmap extent record from the uncompressed form. + */ +void +xfs_bmbt_set_all( + xfs_bmbt_rec_t *r, + xfs_bmbt_irec_t *s) +{ + int extent_flag; + + ASSERT((s->br_state == XFS_EXT_NORM) || + (s->br_state == XFS_EXT_UNWRITTEN)); + extent_flag = (s->br_state == XFS_EXT_NORM) ? 0 : 1; +#if XFS_BIG_FILES + ASSERT((s->br_startoff & XFS_MASK64HI(9)) == 0); + ASSERT((s->br_blockcount & XFS_MASK64HI(43)) == 0); +#else /* !XFS_BIG_FILES */ + ASSERT((s->br_blockcount & XFS_MASK32HI(11)) == 0); +#endif /* XFS_BIG_FILES */ +#if XFS_BIG_FILESYSTEMS + ASSERT((s->br_startblock & XFS_MASK64HI(12)) == 0); +#endif /* XFS_BIG_FILESYSTEMS */ +#if BMBT_USE_64 +#if XFS_BIG_FILESYSTEMS + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)s->br_startoff << 9) | + ((xfs_bmbt_rec_base_t)s->br_startblock >> 43)); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | + ((xfs_bmbt_rec_base_t)s->br_blockcount & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); +#else /* !XFS_BIG_FILESYSTEMS */ + if (ISNULLSTARTBLOCK(s->br_startblock)) { + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)s->br_startoff << 9) | + (xfs_bmbt_rec_base_t)XFS_MASK64LO(9)); + INT_SET(r->l1, ARCH_CONVERT, XFS_MASK64HI(11) | + ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | + ((xfs_bmbt_rec_base_t)s->br_blockcount & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } else { + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)s->br_startoff << 9)); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)s->br_startblock << 21) | + ((xfs_bmbt_rec_base_t)s->br_blockcount & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } +#endif /* XFS_BIG_FILESYSTEMS */ +#else /* !BMBT_USE_64 */ + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 31) | + ((xfs_bmbt_rec_base_t)(s->br_startoff >> 23))); + INT_SET(r->l3, ARCH_CONVERT, (((xfs_bmbt_rec_base_t)s->br_startblock) << 21) | + ((xfs_bmbt_rec_base_t)(s->br_blockcount & XFS_MASK32LO(21)))); +#if XFS_BIG_FILESYSTEMS + INT_SET(r->l1, ARCH_CONVERT, (((xfs_bmbt_rec_base_t)s->br_startoff) << 9) | + ((xfs_bmbt_rec_base_t)(s->br_startblock >> 43))); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(s->br_startblock >> 11)); +#else /* !XFS_BIG_FILESYSTEMS */ + if (ISNULLSTARTBLOCK(s->br_startblock)) { + INT_SET(r->l1, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(s->br_startoff << 9) | + (xfs_bmbt_rec_base_t)XFS_MASK32LO(9)); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)XFS_MASK32HI(11) | + (xfs_bmbt_rec_base_t)(s->br_startblock >> 11)); + } else { + INT_SET(r->l1, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(s->br_startoff << 9)); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(s->br_startblock >> 11)); + } +#endif /* XFS_BIG_FILESYSTEMS */ +#endif /* BMBT_USE_64 */ +} + +/* + * Set all the fields in a bmap extent record from the arguments. + */ +void +xfs_bmbt_set_allf( + xfs_bmbt_rec_t *r, + xfs_fileoff_t o, + xfs_fsblock_t b, + xfs_filblks_t c, + xfs_exntst_t v) +{ + int extent_flag; + + ASSERT((v == XFS_EXT_NORM) || (v == XFS_EXT_UNWRITTEN)); + extent_flag = (v == XFS_EXT_NORM) ? 0 : 1; +#if XFS_BIG_FILES + ASSERT((o & XFS_MASK64HI(64-BMBT_STARTOFF_BITLEN)) == 0); + ASSERT((c & XFS_MASK64HI(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); +#else /* !XFS_BIG_FILES */ + ASSERT((c & XFS_MASK32HI(11)) == 0); +#endif /* XFS_BIG_FILES */ +#if XFS_BIG_FILESYSTEMS + ASSERT((b & XFS_MASK64HI(64-BMBT_STARTBLOCK_BITLEN)) == 0); +#endif /* XFS_BIG_FILESYSTEMS */ +#if BMBT_USE_64 +#if XFS_BIG_FILESYSTEMS + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)o << 9) | + ((xfs_bmbt_rec_base_t)b >> 43)); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)b << 21) | + ((xfs_bmbt_rec_base_t)c & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); +#else /* !XFS_BIG_FILESYSTEMS */ + if (ISNULLSTARTBLOCK(b)) { + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)o << 9) | + (xfs_bmbt_rec_base_t)XFS_MASK64LO(9)); + INT_SET(r->l1, ARCH_CONVERT, XFS_MASK64HI(11) | + ((xfs_bmbt_rec_base_t)b << 21) | + ((xfs_bmbt_rec_base_t)c & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } else { + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 63) | + ((xfs_bmbt_rec_base_t)o << 9)); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)b << 21) | + ((xfs_bmbt_rec_base_t)c & + (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } +#endif /* XFS_BIG_FILESYSTEMS */ +#else /* !BMBT_USE_64 */ + INT_SET(r->l0, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)extent_flag << 31) | + ((xfs_bmbt_rec_base_t)(o >> 23))); + INT_SET(r->l3, ARCH_CONVERT, (((xfs_bmbt_rec_base_t)b) << 21) | + ((xfs_bmbt_rec_base_t)(c & XFS_MASK32LO(21)))); +#if XFS_BIG_FILESYSTEMS + INT_SET(r->l1, ARCH_CONVERT, (((xfs_bmbt_rec_base_t)o) << 9) | + ((xfs_bmbt_rec_base_t)(b >> 43))); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(b >> 11)); +#else /* !XFS_BIG_FILESYSTEMS */ + if (ISNULLSTARTBLOCK(b)) { + INT_SET(r->l1, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(o << 9) | + (xfs_bmbt_rec_base_t)XFS_MASK32LO(9)); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)XFS_MASK32HI(11) | + (xfs_bmbt_rec_base_t)(b >> 11)); + } else { + INT_SET(r->l1, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(o << 9)); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(b >> 11)); + } +#endif /* XFS_BIG_FILESYSTEMS */ +#endif /* BMBT_USE_64 */ +} + +/* + * Set the blockcount field in a bmap extent record. + */ +void +xfs_bmbt_set_blockcount( + xfs_bmbt_rec_t *r, + xfs_filblks_t v) +{ +#if XFS_BIG_FILES + ASSERT((v & XFS_MASK64HI(43)) == 0); +#else /* !XFS_BIG_FILES */ + ASSERT((v & XFS_MASK32HI(11)) == 0); +#endif +#if BMBT_USE_64 + INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64HI(43)) | + (xfs_bmbt_rec_base_t)(v & XFS_MASK64LO(21))); +#else /* !BMBT_USE_64 */ + INT_SET(r->l3, ARCH_CONVERT, (INT_GET(r->l3, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK32HI(11)) | + ((xfs_bmbt_rec_base_t)v & XFS_MASK32LO(21))); +#endif /* BMBT_USE_64 */ +} + +/* + * Set the startblock field in a bmap extent record. + */ +void +xfs_bmbt_set_startblock( + xfs_bmbt_rec_t *r, + xfs_fsblock_t v) +{ +#if XFS_BIG_FILESYSTEMS + ASSERT((v & XFS_MASK64HI(12)) == 0); +#endif /* XFS_BIG_FILESYSTEMS */ +#if BMBT_USE_64 +#if XFS_BIG_FILESYSTEMS + INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64HI(55)) | + (xfs_bmbt_rec_base_t)(v >> 43)); + INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21)) | + (xfs_bmbt_rec_base_t)(v << 21)); +#else /* !XFS_BIG_FILESYSTEMS */ + if (ISNULLSTARTBLOCK(v)) { + INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) | (xfs_bmbt_rec_base_t)XFS_MASK64LO(9))); + INT_SET(r->l1, ARCH_CONVERT, (xfs_bmbt_rec_base_t)XFS_MASK64HI(11) | + ((xfs_bmbt_rec_base_t)v << 21) | + (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } else { + INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & ~(xfs_bmbt_rec_base_t)XFS_MASK64LO(9))); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)v << 21) | + (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(21))); + } +#endif /* XFS_BIG_FILESYSTEMS */ +#else /* !BMBT_USE_64 */ +#if XFS_BIG_FILESYSTEMS + INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) & XFS_MASK32HI(23)) | (xfs_bmbt_rec_base_t)(v >> 43)); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(v >> 11)); +#else /* !XFS_BIG_FILESYSTEMS */ + if (ISNULLSTARTBLOCK(v)) { + INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) | XFS_MASK32LO(9))); + INT_SET(r->l2, ARCH_CONVERT, XFS_MASK32HI(11) | (xfs_bmbt_rec_base_t)(v >> 11)); + } else { + INT_SET(r->l1, ARCH_CONVERT, (INT_GET(r->l1, ARCH_CONVERT) & ~XFS_MASK32LO(9))); + INT_SET(r->l2, ARCH_CONVERT, (xfs_bmbt_rec_base_t)(v >> 11)); + } +#endif /* XFS_BIG_FILESYSTEMS */ + INT_SET(r->l3, ARCH_CONVERT, (INT_GET(r->l3, ARCH_CONVERT) & XFS_MASK32LO(21)) | + (((xfs_bmbt_rec_base_t)v) << 21)); +#endif /* BMBT_USE_64 */ +} + +/* + * Set the startoff field in a bmap extent record. + */ +void +xfs_bmbt_set_startoff( + xfs_bmbt_rec_t *r, + xfs_fileoff_t v) +{ +#if XFS_BIG_FILES + ASSERT((v & XFS_MASK64HI(9)) == 0); +#endif /* XFS_BIG_FILES */ +#if BMBT_USE_64 + INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t) XFS_MASK64HI(1)) | + ((xfs_bmbt_rec_base_t)v << 9) | + (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK64LO(9))); +#else /* !BMBT_USE_64 */ + INT_SET(r->l0, ARCH_CONVERT, (INT_GET(r->l0, ARCH_CONVERT) & (xfs_bmbt_rec_base_t) XFS_MASK32HI(1)) | + (xfs_bmbt_rec_base_t)(v >> 23)); + INT_SET(r->l1, ARCH_CONVERT, ((xfs_bmbt_rec_base_t)v << 9) | + (INT_GET(r->l1, ARCH_CONVERT) & (xfs_bmbt_rec_base_t)XFS_MASK32LO(9))); +#endif /* BMBT_USE_64 */ +} + +/* + * Set the extent state field in a bmap extent record. + */ +void +xfs_bmbt_set_state( + xfs_bmbt_rec_t *r, + xfs_exntst_t v) +{ + ASSERT(v == XFS_EXT_NORM || v == XFS_EXT_UNWRITTEN); + if (v == XFS_EXT_NORM) +#if BMBT_USE_64 + INT_SET(r->l0, ARCH_CONVERT, INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)); +#else /* !BMBT_USE_64 */ + INT_SET(r->l0, ARCH_CONVERT, INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK32LO(32 - BMBT_EXNTFLAG_BITLEN)); +#endif /* BMBT_USE_64 */ + else +#if BMBT_USE_64 + INT_SET(r->l0, ARCH_CONVERT, INT_GET(r->l0, ARCH_CONVERT) | XFS_MASK64HI(BMBT_EXNTFLAG_BITLEN)); +#else /* !BMBT_USE_64 */ + INT_SET(r->l0, ARCH_CONVERT, INT_GET(r->l0, ARCH_CONVERT) | XFS_MASK32HI(BMBT_EXNTFLAG_BITLEN)); +#endif /* BMBT_USE_64 */ +} + +/* + * Convert in-memory form of btree root to on-disk form. + */ +void +xfs_bmbt_to_bmdr( + xfs_bmbt_block_t *rblock, + int rblocklen, + xfs_bmdr_block_t *dblock, + int dblocklen) +{ + int dmxr; + xfs_bmbt_key_t *fkp; + xfs_bmbt_ptr_t *fpp; + xfs_bmbt_key_t *tkp; + xfs_bmbt_ptr_t *tpp; + + ASSERT(INT_GET(rblock->bb_magic, ARCH_CONVERT) == XFS_BMAP_MAGIC); + ASSERT(INT_GET(rblock->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO); + ASSERT(INT_GET(rblock->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO); + ASSERT(INT_GET(rblock->bb_level, ARCH_CONVERT) > 0); + dblock->bb_level = rblock->bb_level; /* both in on-disk format */ + dblock->bb_numrecs = rblock->bb_numrecs;/* both in on-disk format */ + dmxr = (int)XFS_BTREE_BLOCK_MAXRECS(dblocklen, xfs_bmdr, 0); + fkp = XFS_BMAP_BROOT_KEY_ADDR(rblock, 1, rblocklen); + tkp = XFS_BTREE_KEY_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + fpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen); + tpp = XFS_BTREE_PTR_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + dmxr = INT_GET(dblock->bb_numrecs, ARCH_CONVERT); + bcopy(fkp, tkp, sizeof(*fkp) * dmxr); + bcopy(fpp, tpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */ +} + +/* + * Update the record to the passed values. + */ +int +xfs_bmbt_update( + xfs_btree_cur_t *cur, + xfs_fileoff_t off, + xfs_fsblock_t bno, + xfs_filblks_t len, + xfs_exntst_t state) +{ + xfs_bmbt_block_t *block; + xfs_buf_t *bp; + int error; +#ifdef XFS_BMBT_TRACE + static char fname[] = "xfs_bmbt_update"; +#endif + xfs_bmbt_key_t key; + int ptr; + xfs_bmbt_rec_t *rp; + + XFS_BMBT_TRACE_CURSOR(cur, ENTRY); + XFS_BMBT_TRACE_ARGFFFI(cur, (xfs_dfiloff_t)off, (xfs_dfsbno_t)bno, + (xfs_dfilblks_t)len, (int)state); + block = xfs_bmbt_get_block(cur, 0, &bp); +#ifdef DEBUG + if ((error = xfs_btree_check_lblock(cur, block, 0, bp))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } +#endif + ptr = cur->bc_ptrs[0]; + rp = XFS_BMAP_REC_IADDR(block, ptr, cur); + xfs_bmbt_set_allf(rp, off, bno, len, state); + xfs_bmbt_log_recs(cur, bp, ptr, ptr); + if (ptr > 1) { + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; + } + INT_SET(key.br_startoff, ARCH_CONVERT, off); + if ((error = xfs_bmbt_updkey(cur, &key, 1))) { + XFS_BMBT_TRACE_CURSOR(cur, ERROR); + return error; + } + XFS_BMBT_TRACE_CURSOR(cur, EXIT); + return 0; +} + +/* + * Check an extent list, which has just been read, for + * any bit in the extent flag field. ASSERT on debug + * kernels, as this condition should not occur. + * Return an error condition (1) if any flags found, + * otherwise return 0. + */ +int +xfs_check_nostate_extents( + xfs_bmbt_rec_t *ep, + xfs_extnum_t num) +{ + for (; num > 0; num--, ep++) { + if ( +#if BMBT_USE_64 + ((INT_GET(ep->l0, ARCH_CONVERT)) >> (64 - BMBT_EXNTFLAG_BITLEN)) != 0 +#else /* !BMBT_USE_64 */ + ((INT_GET(ep->l0, ARCH_CONVERT)) >> (32 - BMBT_EXNTFLAG_BITLEN)) != 0 +#endif /* BMBT_USE_64 */ + ) { + ASSERT(0); + return 1; + } + } + return 0; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_bmap_btree.h linux-2.4-xfs/linux/fs/xfs/xfs_bmap_btree.h --- linux-2.4.7/linux/fs/xfs/xfs_bmap_btree.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_bmap_btree.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,661 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BMAP_BTREE_H__ +#define __XFS_BMAP_BTREE_H__ + +#define XFS_BMAP_MAGIC 0x424d4150 /* 'BMAP' */ + +struct xfs_btree_cur; +struct xfs_btree_lblock; +struct xfs_mount; +struct xfs_inode; + +/* + * Bmap root header, on-disk form only. + */ +typedef struct xfs_bmdr_block +{ + __uint16_t bb_level; /* 0 is a leaf */ + __uint16_t bb_numrecs; /* current # of data records */ +} xfs_bmdr_block_t; + +/* + * Bmap btree record and extent descriptor. + * For 32-bit kernels, + * l0:31 is an extent flag (value 1 indicates non-normal). + * l0:0-30 and l1:9-31 are startoff. + * l1:0-8, l2:0-31, and l3:21-31 are startblock. + * l3:0-20 are blockcount. + * For 64-bit kernels, + * l0:63 is an extent flag (value 1 indicates non-normal). + * l0:9-62 are startoff. + * l0:0-8 and l1:21-63 are startblock. + * l1:0-20 are blockcount. + */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +#define BMBT_TOTAL_BITLEN 128 /* 128 bits, 16 bytes */ +#define BMBT_EXNTFLAG_BITOFF 0 +#define BMBT_EXNTFLAG_BITLEN 1 +#define BMBT_STARTOFF_BITOFF (BMBT_EXNTFLAG_BITOFF + BMBT_EXNTFLAG_BITLEN) +#define BMBT_STARTOFF_BITLEN 54 +#define BMBT_STARTBLOCK_BITOFF (BMBT_STARTOFF_BITOFF + BMBT_STARTOFF_BITLEN) +#define BMBT_STARTBLOCK_BITLEN 52 +#define BMBT_BLOCKCOUNT_BITOFF \ + (BMBT_STARTBLOCK_BITOFF + BMBT_STARTBLOCK_BITLEN) +#define BMBT_BLOCKCOUNT_BITLEN (BMBT_TOTAL_BITLEN - BMBT_BLOCKCOUNT_BITOFF) + +#else + +#define BMBT_TOTAL_BITLEN 128 /* 128 bits, 16 bytes */ +#define BMBT_EXNTFLAG_BITOFF 63 +#define BMBT_EXNTFLAG_BITLEN 1 +#define BMBT_STARTOFF_BITOFF (BMBT_EXNTFLAG_BITOFF - BMBT_STARTOFF_BITLEN) +#define BMBT_STARTOFF_BITLEN 54 +#define BMBT_STARTBLOCK_BITOFF 85 /* 128 - 43 (other 9 is in first word) */ +#define BMBT_STARTBLOCK_BITLEN 52 +#define BMBT_BLOCKCOUNT_BITOFF 64 /* Start of second 64 bit container */ +#define BMBT_BLOCKCOUNT_BITLEN 21 + +#endif + + +#define BMBT_USE_64 1 + +typedef struct xfs_bmbt_rec_32 +{ + __uint32_t l0, l1, l2, l3; +} xfs_bmbt_rec_32_t; +typedef struct xfs_bmbt_rec_64 +{ + __uint64_t l0, l1; +} xfs_bmbt_rec_64_t; + +#if BMBT_USE_64 +typedef __uint64_t xfs_bmbt_rec_base_t; /* use this for casts */ +typedef xfs_bmbt_rec_64_t xfs_bmbt_rec_t, xfs_bmdr_rec_t; +#else /* !BMBT_USE_64 */ +typedef __uint32_t xfs_bmbt_rec_base_t; /* use this for casts */ +typedef xfs_bmbt_rec_32_t xfs_bmbt_rec_t, xfs_bmdr_rec_t; +#endif /* BMBT_USE_64 */ + +/* + * Values and macros for delayed-allocation startblock fields. + */ +#define STARTBLOCKVALBITS 17 +#define STARTBLOCKMASKBITS (15 + XFS_BIG_FILESYSTEMS * 20) +#define DSTARTBLOCKMASKBITS (15 + 20) +#define STARTBLOCKMASK \ + (((((xfs_fsblock_t)1) << STARTBLOCKMASKBITS) - 1) << STARTBLOCKVALBITS) +#define DSTARTBLOCKMASK \ + (((((xfs_dfsbno_t)1) << DSTARTBLOCKMASKBITS) - 1) << STARTBLOCKVALBITS) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_ISNULLSTARTBLOCK) +int isnullstartblock(xfs_fsblock_t x); +#define ISNULLSTARTBLOCK(x) isnullstartblock(x) +#else +#define ISNULLSTARTBLOCK(x) (((x) & STARTBLOCKMASK) == STARTBLOCKMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_ISNULLDSTARTBLOCK) +int isnulldstartblock(xfs_dfsbno_t x); +#define ISNULLDSTARTBLOCK(x) isnulldstartblock(x) +#else +#define ISNULLDSTARTBLOCK(x) (((x) & DSTARTBLOCKMASK) == DSTARTBLOCKMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_NULLSTARTBLOCK) +xfs_fsblock_t nullstartblock(int k); +#define NULLSTARTBLOCK(k) nullstartblock(k) +#else +#define NULLSTARTBLOCK(k) \ + ((ASSERT(k < (1 << STARTBLOCKVALBITS))), (STARTBLOCKMASK | (k))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_STARTBLOCKVAL) +xfs_filblks_t startblockval(xfs_fsblock_t x); +#define STARTBLOCKVAL(x) startblockval(x) +#else +#define STARTBLOCKVAL(x) ((xfs_filblks_t)((x) & ~STARTBLOCKMASK)) +#endif + +/* + * Possible extent formats. + */ +typedef enum { + XFS_EXTFMT_NOSTATE = 0, + XFS_EXTFMT_HASSTATE +} xfs_exntfmt_t; + +/* + * Possible extent states. + */ +typedef enum { + XFS_EXT_NORM, XFS_EXT_UNWRITTEN, + XFS_EXT_DMAPI_OFFLINE +} xfs_exntst_t; + +/* + * Extent state and extent format macros. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_EXTFMT_INODE ) +xfs_exntfmt_t xfs_extfmt_inode(struct xfs_inode *ip); +#define XFS_EXTFMT_INODE(x) xfs_extfmt_inode(x) +#else +#define XFS_EXTFMT_INODE(x) \ + (XFS_SB_VERSION_HASEXTFLGBIT(&((x)->i_mount->m_sb)) ? \ + XFS_EXTFMT_HASSTATE : XFS_EXTFMT_NOSTATE) +#endif +#define ISUNWRITTEN(x) ((x) == XFS_EXT_UNWRITTEN) + +/* + * Incore version of above. + */ +typedef struct xfs_bmbt_irec +{ + xfs_fileoff_t br_startoff; /* starting file offset */ + xfs_fsblock_t br_startblock; /* starting block number */ + xfs_filblks_t br_blockcount; /* number of blocks */ + xfs_exntst_t br_state; /* extent state */ +} xfs_bmbt_irec_t; + +/* + * Key structure for non-leaf levels of the tree. + */ +typedef struct xfs_bmbt_key +{ + xfs_dfiloff_t br_startoff; /* starting file offset */ +} xfs_bmbt_key_t, xfs_bmdr_key_t; + +typedef xfs_dfsbno_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t; /* btree pointer type */ + /* btree block header type */ +typedef struct xfs_btree_lblock xfs_bmbt_block_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_BMBT_BLOCK) +xfs_bmbt_block_t *xfs_buf_to_bmbt_block(struct xfs_buf *bp); +#define XFS_BUF_TO_BMBT_BLOCK(bp) xfs_buf_to_bmbt_block(bp) +#else +#define XFS_BUF_TO_BMBT_BLOCK(bp) ((xfs_bmbt_block_t *)(XFS_BUF_PTR(bp))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_RBLOCK_DSIZE) +int xfs_bmap_rblock_dsize(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_RBLOCK_DSIZE(lev,cur) xfs_bmap_rblock_dsize(lev,cur) +#else +#define XFS_BMAP_RBLOCK_DSIZE(lev,cur) ((cur)->bc_private.b.forksize) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_RBLOCK_ISIZE) +int xfs_bmap_rblock_isize(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_RBLOCK_ISIZE(lev,cur) xfs_bmap_rblock_isize(lev,cur) +#else +#define XFS_BMAP_RBLOCK_ISIZE(lev,cur) \ + ((int)XFS_IFORK_PTR((cur)->bc_private.b.ip, \ + (cur)->bc_private.b.whichfork)->if_broot_bytes) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_IBLOCK_SIZE) +int xfs_bmap_iblock_size(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_IBLOCK_SIZE(lev,cur) xfs_bmap_iblock_size(lev,cur) +#else +#define XFS_BMAP_IBLOCK_SIZE(lev,cur) (1 << (cur)->bc_blocklog) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_DSIZE) +int xfs_bmap_block_dsize(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_DSIZE(lev,cur) xfs_bmap_block_dsize(lev,cur) +#else +#define XFS_BMAP_BLOCK_DSIZE(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BMAP_RBLOCK_DSIZE(lev,cur) : \ + XFS_BMAP_IBLOCK_SIZE(lev,cur)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_ISIZE) +int xfs_bmap_block_isize(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_ISIZE(lev,cur) xfs_bmap_block_isize(lev,cur) +#else +#define XFS_BMAP_BLOCK_ISIZE(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BMAP_RBLOCK_ISIZE(lev,cur) : \ + XFS_BMAP_IBLOCK_SIZE(lev,cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_DMAXRECS) +int xfs_bmap_block_dmaxrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_DMAXRECS(lev,cur) xfs_bmap_block_dmaxrecs(lev,cur) +#else +#define XFS_BMAP_BLOCK_DMAXRECS(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BTREE_BLOCK_MAXRECS(XFS_BMAP_RBLOCK_DSIZE(lev,cur), \ + xfs_bmdr, (lev) == 0) : \ + ((cur)->bc_mp->m_bmap_dmxr[(lev) != 0])) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_IMAXRECS) +int xfs_bmap_block_imaxrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_IMAXRECS(lev,cur) xfs_bmap_block_imaxrecs(lev,cur) +#else +#define XFS_BMAP_BLOCK_IMAXRECS(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BTREE_BLOCK_MAXRECS(XFS_BMAP_RBLOCK_ISIZE(lev,cur), \ + xfs_bmbt, (lev) == 0) : \ + ((cur)->bc_mp->m_bmap_dmxr[(lev) != 0])) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_DMINRECS) +int xfs_bmap_block_dminrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_DMINRECS(lev,cur) xfs_bmap_block_dminrecs(lev,cur) +#else +#define XFS_BMAP_BLOCK_DMINRECS(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BTREE_BLOCK_MINRECS(XFS_BMAP_RBLOCK_DSIZE(lev,cur), \ + xfs_bmdr, (lev) == 0) : \ + ((cur)->bc_mp->m_bmap_dmnr[(lev) != 0])) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BLOCK_IMINRECS) +int xfs_bmap_block_iminrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_BMAP_BLOCK_IMINRECS(lev,cur) xfs_bmap_block_iminrecs(lev,cur) +#else +#define XFS_BMAP_BLOCK_IMINRECS(lev,cur) \ + ((lev) == (cur)->bc_nlevels - 1 ? \ + XFS_BTREE_BLOCK_MINRECS(XFS_BMAP_RBLOCK_ISIZE(lev,cur), \ + xfs_bmbt, (lev) == 0) : \ + ((cur)->bc_mp->m_bmap_dmnr[(lev) != 0])) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_REC_DADDR) +xfs_bmbt_rec_t * +xfs_bmap_rec_daddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_REC_DADDR(bb,i,cur) xfs_bmap_rec_daddr(bb,i,cur) +#else +#define XFS_BMAP_REC_DADDR(bb,i,cur) \ + XFS_BTREE_REC_ADDR(XFS_BMAP_BLOCK_DSIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_REC_IADDR) +xfs_bmbt_rec_t * +xfs_bmap_rec_iaddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_REC_IADDR(bb,i,cur) xfs_bmap_rec_iaddr(bb,i,cur) +#else +#define XFS_BMAP_REC_IADDR(bb,i,cur) \ + XFS_BTREE_REC_ADDR(XFS_BMAP_BLOCK_ISIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_KEY_DADDR) +xfs_bmbt_key_t * +xfs_bmap_key_daddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_KEY_DADDR(bb,i,cur) xfs_bmap_key_daddr(bb,i,cur) +#else +#define XFS_BMAP_KEY_DADDR(bb,i,cur) \ + XFS_BTREE_KEY_ADDR(XFS_BMAP_BLOCK_DSIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_KEY_IADDR) +xfs_bmbt_key_t * +xfs_bmap_key_iaddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_KEY_IADDR(bb,i,cur) xfs_bmap_key_iaddr(bb,i,cur) +#else +#define XFS_BMAP_KEY_IADDR(bb,i,cur) \ + XFS_BTREE_KEY_ADDR(XFS_BMAP_BLOCK_ISIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_PTR_DADDR) +xfs_bmbt_ptr_t * +xfs_bmap_ptr_daddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_PTR_DADDR(bb,i,cur) xfs_bmap_ptr_daddr(bb,i,cur) +#else +#define XFS_BMAP_PTR_DADDR(bb,i,cur) \ + XFS_BTREE_PTR_ADDR(XFS_BMAP_BLOCK_DSIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_PTR_IADDR) +xfs_bmbt_ptr_t * +xfs_bmap_ptr_iaddr(xfs_bmbt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_BMAP_PTR_IADDR(bb,i,cur) xfs_bmap_ptr_iaddr(bb,i,cur) +#else +#define XFS_BMAP_PTR_IADDR(bb,i,cur) \ + XFS_BTREE_PTR_ADDR(XFS_BMAP_BLOCK_ISIZE( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur), \ + xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \ + INT_GET((bb)->bb_level, ARCH_CONVERT), cur)) +#endif + +/* + * These are to be used when we know the size of the block and + * we don't have a cursor. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_REC_ADDR) +xfs_bmbt_rec_t *xfs_bmap_broot_rec_addr(xfs_bmbt_block_t *bb, int i, int sz); +#define XFS_BMAP_BROOT_REC_ADDR(bb,i,sz) xfs_bmap_broot_rec_addr(bb,i,sz) +#else +#define XFS_BMAP_BROOT_REC_ADDR(bb,i,sz) \ + XFS_BTREE_REC_ADDR(sz,xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_KEY_ADDR) +xfs_bmbt_key_t *xfs_bmap_broot_key_addr(xfs_bmbt_block_t *bb, int i, int sz); +#define XFS_BMAP_BROOT_KEY_ADDR(bb,i,sz) xfs_bmap_broot_key_addr(bb,i,sz) +#else +#define XFS_BMAP_BROOT_KEY_ADDR(bb,i,sz) \ + XFS_BTREE_KEY_ADDR(sz,xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_PTR_ADDR) +xfs_bmbt_ptr_t *xfs_bmap_broot_ptr_addr(xfs_bmbt_block_t *bb, int i, int sz); +#define XFS_BMAP_BROOT_PTR_ADDR(bb,i,sz) xfs_bmap_broot_ptr_addr(bb,i,sz) +#else +#define XFS_BMAP_BROOT_PTR_ADDR(bb,i,sz) \ + XFS_BTREE_PTR_ADDR(sz,xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_NUMRECS) +int xfs_bmap_broot_numrecs(xfs_bmdr_block_t *bb); +#define XFS_BMAP_BROOT_NUMRECS(bb) xfs_bmap_broot_numrecs(bb) +#else +#define XFS_BMAP_BROOT_NUMRECS(bb) (INT_GET((bb)->bb_numrecs, ARCH_CONVERT)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_MAXRECS) +int xfs_bmap_broot_maxrecs(int sz); +#define XFS_BMAP_BROOT_MAXRECS(sz) xfs_bmap_broot_maxrecs(sz) +#else +#define XFS_BMAP_BROOT_MAXRECS(sz) XFS_BTREE_BLOCK_MAXRECS(sz,xfs_bmbt,0) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_SPACE_CALC) +int xfs_bmap_broot_space_calc(int nrecs); +#define XFS_BMAP_BROOT_SPACE_CALC(nrecs) xfs_bmap_broot_space_calc(nrecs) +#else +#define XFS_BMAP_BROOT_SPACE_CALC(nrecs) \ + ((int)(sizeof(xfs_bmbt_block_t) + \ + ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_BROOT_SPACE) +int xfs_bmap_broot_space(xfs_bmdr_block_t *bb); +#define XFS_BMAP_BROOT_SPACE(bb) xfs_bmap_broot_space(bb) +#else +#define XFS_BMAP_BROOT_SPACE(bb) \ + XFS_BMAP_BROOT_SPACE_CALC(INT_GET((bb)->bb_numrecs, ARCH_CONVERT)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMDR_SPACE_CALC) +int xfs_bmdr_space_calc(int nrecs); +#define XFS_BMDR_SPACE_CALC(nrecs) xfs_bmdr_space_calc(nrecs) +#else +#define XFS_BMDR_SPACE_CALC(nrecs) \ + ((int)(sizeof(xfs_bmdr_block_t) + \ + ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))) +#endif + +/* + * Maximum number of bmap btree levels. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BM_MAXLEVELS) +int xfs_bm_maxlevels(struct xfs_mount *mp, int w); +#define XFS_BM_MAXLEVELS(mp,w) xfs_bm_maxlevels(mp,w) +#else +#define XFS_BM_MAXLEVELS(mp,w) ((mp)->m_bm_maxlevels[w]) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BMAP_SANITY_CHECK) +int xfs_bmap_sanity_check(struct xfs_mount *mp, xfs_bmbt_block_t *bb, + int level); +#define XFS_BMAP_SANITY_CHECK(mp,bb,level) \ + xfs_bmap_sanity_check(mp,bb,level) +#else +#define XFS_BMAP_SANITY_CHECK(mp,bb,level) \ + (INT_GET((bb)->bb_magic, ARCH_CONVERT) == XFS_BMAP_MAGIC && \ + INT_GET((bb)->bb_level, ARCH_CONVERT) == level && \ + INT_GET((bb)->bb_numrecs, ARCH_CONVERT) > 0 && \ + INT_GET((bb)->bb_numrecs, ARCH_CONVERT) <= (mp)->m_bmap_dmxr[(level) != 0]) +#endif + +/* + * Trace buffer entry types. + */ +#define XFS_BMBT_KTRACE_ARGBI 1 +#define XFS_BMBT_KTRACE_ARGBII 2 +#define XFS_BMBT_KTRACE_ARGFFFI 3 +#define XFS_BMBT_KTRACE_ARGI 4 +#define XFS_BMBT_KTRACE_ARGIFK 5 +#define XFS_BMBT_KTRACE_ARGIFR 6 +#define XFS_BMBT_KTRACE_ARGIK 7 +#define XFS_BMBT_KTRACE_CUR 8 + +#define XFS_BMBT_TRACE_SIZE 4096 /* size of global trace buffer */ +#define XFS_BMBT_KTRACE_SIZE 32 /* size of per-inode trace buffer */ + +#if defined(XFS_ALL_TRACE) +#define XFS_BMBT_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_BMBT_TRACE +#endif + + +/* + * Prototypes for xfs_bmap.c to call. + */ + +void +xfs_bmdr_to_bmbt( + xfs_bmdr_block_t *, + int, + xfs_bmbt_block_t *, + int); + +int +xfs_bmbt_decrement( + struct xfs_btree_cur *, + int, + int *); + +int +xfs_bmbt_delete( + struct xfs_btree_cur *, + int, + int *); + +void +xfs_bmbt_get_all( + xfs_bmbt_rec_t *r, + xfs_bmbt_irec_t *s); + +xfs_bmbt_block_t * +xfs_bmbt_get_block( + struct xfs_btree_cur *cur, + int level, + struct xfs_buf **bpp); + +xfs_filblks_t +xfs_bmbt_get_blockcount( + xfs_bmbt_rec_t *r); + +xfs_fsblock_t +xfs_bmbt_get_startblock( + xfs_bmbt_rec_t *r); + +xfs_fileoff_t +xfs_bmbt_get_startoff( + xfs_bmbt_rec_t *r); + +xfs_exntst_t +xfs_bmbt_get_state( + xfs_bmbt_rec_t *r); + +int +xfs_bmbt_increment( + struct xfs_btree_cur *, + int, + int *); + +int +xfs_bmbt_insert( + struct xfs_btree_cur *, + int *); + +int +xfs_bmbt_insert_many( + struct xfs_btree_cur *, + int, + xfs_bmbt_rec_t *, + int *); + +void +xfs_bmbt_log_block( + struct xfs_btree_cur *, + struct xfs_buf *, + int); + +void +xfs_bmbt_log_recs( + struct xfs_btree_cur *, + struct xfs_buf *, + int, + int); + +int +xfs_bmbt_lookup_eq( + struct xfs_btree_cur *, + xfs_fileoff_t, + xfs_fsblock_t, + xfs_filblks_t, + int *); + +int +xfs_bmbt_lookup_ge( + struct xfs_btree_cur *, + xfs_fileoff_t, + xfs_fsblock_t, + xfs_filblks_t, + int *); + +int +xfs_bmbt_lookup_le( + struct xfs_btree_cur *, + xfs_fileoff_t, + xfs_fsblock_t, + xfs_filblks_t, + int *); + +/* + * Give the bmap btree a new root block. Copy the old broot contents + * down into a real block and make the broot point to it. + */ +int /* error */ +xfs_bmbt_newroot( + struct xfs_btree_cur *cur, /* btree cursor */ + int *logflags, /* logging flags for inode */ + int *stat); /* return status - 0 fail */ + +void +xfs_bmbt_set_all( + xfs_bmbt_rec_t *r, + xfs_bmbt_irec_t *s); + +void +xfs_bmbt_set_allf( + xfs_bmbt_rec_t *r, + xfs_fileoff_t o, + xfs_fsblock_t b, + xfs_filblks_t c, + xfs_exntst_t v); + +void +xfs_bmbt_set_blockcount( + xfs_bmbt_rec_t *r, + xfs_filblks_t v); + +void +xfs_bmbt_set_startblock( + xfs_bmbt_rec_t *r, + xfs_fsblock_t v); + +void +xfs_bmbt_set_startoff( + xfs_bmbt_rec_t *r, + xfs_fileoff_t v); + +void +xfs_bmbt_set_state( + xfs_bmbt_rec_t *r, + xfs_exntst_t v); + +void +xfs_bmbt_to_bmdr( + xfs_bmbt_block_t *, + int, + xfs_bmdr_block_t *, + int); + +int +xfs_bmbt_update( + struct xfs_btree_cur *, + xfs_fileoff_t, + xfs_fsblock_t, + xfs_filblks_t, + xfs_exntst_t); + +#ifdef XFSDEBUG +/* + * Get the data from the pointed-to record. + */ +int +xfs_bmbt_get_rec( + struct xfs_btree_cur *, + xfs_fileoff_t *, + xfs_fsblock_t *, + xfs_filblks_t *, + xfs_exntst_t *, + int *); +#endif + + +/* + * Search an extent list for the extent which includes block + * bno. + */ +xfs_bmbt_rec_t * +xfs_bmap_do_search_extents( + xfs_bmbt_rec_t *, + xfs_extnum_t, + xfs_extnum_t, + xfs_fileoff_t, + int *, + xfs_extnum_t *, + xfs_bmbt_irec_t *, + xfs_bmbt_irec_t *); + + +#endif /* __XFS_BMAP_BTREE_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_btree.c linux-2.4-xfs/linux/fs/xfs/xfs_btree.c --- linux-2.4.7/linux/fs/xfs/xfs_btree.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_btree.c Fri May 25 00:08:09 2001 @@ -0,0 +1,921 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * This file contains common code for the space manager's btree implementations. + */ + +#include + +/* + * Cursor allocation zone. + */ +xfs_zone_t *xfs_btree_cur_zone; + +/* + * Btree magic numbers. + */ +const __uint32_t xfs_magics[XFS_BTNUM_MAX] = +{ + XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC +}; + +/* + * Prototypes for internal routines. + */ + +/* + * Checking routine: return maxrecs for the block. + */ +STATIC int /* number of records fitting in block */ +xfs_btree_maxrecs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_block_t *block);/* generic btree block pointer */ + +/* + * Internal routines. + */ + +/* + * Checking routine: return maxrecs for the block. + */ +STATIC int /* number of records fitting in block */ +xfs_btree_maxrecs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_block_t *block) /* generic btree block pointer */ +{ + switch (cur->bc_btnum) { + case XFS_BTNUM_BNO: + case XFS_BTNUM_CNT: + return (int)XFS_ALLOC_BLOCK_MAXRECS(INT_GET(block->bb_h.bb_level, ARCH_CONVERT), cur); + case XFS_BTNUM_BMAP: + return (int)XFS_BMAP_BLOCK_IMAXRECS(INT_GET(block->bb_h.bb_level, ARCH_CONVERT), cur); + case XFS_BTNUM_INO: + return (int)XFS_INOBT_BLOCK_MAXRECS(INT_GET(block->bb_h.bb_level, ARCH_CONVERT), cur); + default: + ASSERT(0); + return 0; + } +} + +/* + * External routines. + */ + +#ifdef DEBUG +/* + * Debug routine: check that block header is ok. + */ +void +xfs_btree_check_block( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_block_t *block, /* generic btree block pointer */ + int level, /* level of the btree block */ + xfs_buf_t *bp) /* buffer containing block, if any */ +{ + if (XFS_BTREE_LONG_PTRS(cur->bc_btnum)) + xfs_btree_check_lblock(cur, (xfs_btree_lblock_t *)block, level, + bp); + else + xfs_btree_check_sblock(cur, (xfs_btree_sblock_t *)block, level, + bp); +} + +/* + * Debug routine: check that keys are in the right order. + */ +void +xfs_btree_check_key( + xfs_btnum_t btnum, /* btree identifier */ + void *ak1, /* pointer to left (lower) key */ + void *ak2) /* pointer to right (higher) key */ +{ + switch (btnum) { + case XFS_BTNUM_BNO: { + xfs_alloc_key_t *k1; + xfs_alloc_key_t *k2; + + k1 = ak1; + k2 = ak2; + ASSERT(INT_GET(k1->ar_startblock, ARCH_CONVERT) < INT_GET(k2->ar_startblock, ARCH_CONVERT)); + break; + } + case XFS_BTNUM_CNT: { + xfs_alloc_key_t *k1; + xfs_alloc_key_t *k2; + + k1 = ak1; + k2 = ak2; + ASSERT(INT_GET(k1->ar_blockcount, ARCH_CONVERT) < INT_GET(k2->ar_blockcount, ARCH_CONVERT) || + (INT_GET(k1->ar_blockcount, ARCH_CONVERT) == INT_GET(k2->ar_blockcount, ARCH_CONVERT) && + INT_GET(k1->ar_startblock, ARCH_CONVERT) < INT_GET(k2->ar_startblock, ARCH_CONVERT))); + break; + } + case XFS_BTNUM_BMAP: { + xfs_bmbt_key_t *k1; + xfs_bmbt_key_t *k2; + + k1 = ak1; + k2 = ak2; + ASSERT(INT_GET(k1->br_startoff, ARCH_CONVERT) < INT_GET(k2->br_startoff, ARCH_CONVERT)); + break; + } + case XFS_BTNUM_INO: { + xfs_inobt_key_t *k1; + xfs_inobt_key_t *k2; + + k1 = ak1; + k2 = ak2; + ASSERT(INT_GET(k1->ir_startino, ARCH_CONVERT) < INT_GET(k2->ir_startino, ARCH_CONVERT)); + break; + } + default: + ASSERT(0); + } +} +#endif /* DEBUG */ + +/* + * Checking routine: check that long form block header is ok. + */ +/* ARGSUSED */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_lblock( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_lblock_t *block, /* btree long form block pointer */ + int level, /* level of the btree block */ + xfs_buf_t *bp) /* buffer for block, if any */ +{ + int lblock_ok; /* block passes checks */ + xfs_mount_t *mp; /* file system mount point */ + + mp = cur->bc_mp; + lblock_ok = + INT_GET(block->bb_magic, ARCH_CONVERT) == xfs_magics[cur->bc_btnum] && + INT_GET(block->bb_level, ARCH_CONVERT) == level && + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= + xfs_btree_maxrecs(cur, (xfs_btree_block_t *)block) && + INT_GET(block->bb_leftsib, ARCH_CONVERT) != 0 && + (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLDFSBNO || + XFS_FSB_SANITY_CHECK(mp, INT_GET(block->bb_leftsib, ARCH_CONVERT))) && + INT_GET(block->bb_rightsib, ARCH_CONVERT) != 0 && + (INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLDFSBNO || + XFS_FSB_SANITY_CHECK(mp, INT_GET(block->bb_rightsib, ARCH_CONVERT))); + if (XFS_TEST_ERROR(!lblock_ok, mp, XFS_ERRTAG_BTREE_CHECK_LBLOCK, + XFS_RANDOM_BTREE_CHECK_LBLOCK)) { + if (bp) + xfs_buftrace("LBTREE ERROR", bp); + return XFS_ERROR(EFSCORRUPTED); + } + return 0; +} + +/* + * Checking routine: check that (long) pointer is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_lptr( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_dfsbno_t ptr, /* btree block disk address */ + int level) /* btree block level */ +{ + xfs_mount_t *mp; /* file system mount point */ + + mp = cur->bc_mp; + XFS_WANT_CORRUPTED_RETURN( + level > 0 && + ptr != NULLDFSBNO && + XFS_FSB_SANITY_CHECK(mp, ptr)); + return 0; +} + +#ifdef DEBUG +/* + * Debug routine: check that records are in the right order. + */ +void +xfs_btree_check_rec( + xfs_btnum_t btnum, /* btree identifier */ + void *ar1, /* pointer to left (lower) record */ + void *ar2) /* pointer to right (higher) record */ +{ + switch (btnum) { + case XFS_BTNUM_BNO: { + xfs_alloc_rec_t *r1; + xfs_alloc_rec_t *r2; + + r1 = ar1; + r2 = ar2; + ASSERT(INT_GET(r1->ar_startblock, ARCH_CONVERT) + INT_GET(r1->ar_blockcount, ARCH_CONVERT) <= + INT_GET(r2->ar_startblock, ARCH_CONVERT)); + break; + } + case XFS_BTNUM_CNT: { + xfs_alloc_rec_t *r1; + xfs_alloc_rec_t *r2; + + r1 = ar1; + r2 = ar2; + ASSERT(INT_GET(r1->ar_blockcount, ARCH_CONVERT) < INT_GET(r2->ar_blockcount, ARCH_CONVERT) || + (INT_GET(r1->ar_blockcount, ARCH_CONVERT) == INT_GET(r2->ar_blockcount, ARCH_CONVERT) && + INT_GET(r1->ar_startblock, ARCH_CONVERT) < INT_GET(r2->ar_startblock, ARCH_CONVERT))); + break; + } + case XFS_BTNUM_BMAP: { + xfs_bmbt_rec_t *r1; + xfs_bmbt_rec_t *r2; + + r1 = ar1; + r2 = ar2; + ASSERT(xfs_bmbt_get_startoff(r1) + + xfs_bmbt_get_blockcount(r1) <= + xfs_bmbt_get_startoff(r2)); + break; + } + case XFS_BTNUM_INO: { + xfs_inobt_rec_t *r1; + xfs_inobt_rec_t *r2; + + r1 = ar1; + r2 = ar2; + ASSERT(INT_GET(r1->ir_startino, ARCH_CONVERT) + XFS_INODES_PER_CHUNK <= + INT_GET(r2->ir_startino, ARCH_CONVERT)); + break; + } + default: + ASSERT(0); + } +} +#endif /* DEBUG */ + +/* + * Checking routine: check that block header is ok. + */ +/* ARGSUSED */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_sblock( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_sblock_t *block, /* btree short form block pointer */ + int level, /* level of the btree block */ + xfs_buf_t *bp) /* buffer containing block */ +{ + xfs_buf_t *agbp; /* buffer for ag. freespace struct */ + xfs_agf_t *agf; /* ag. freespace structure */ + xfs_agblock_t agflen; /* native ag. freespace length */ + int sblock_ok; /* block passes checks */ + + agbp = cur->bc_private.a.agbp; + agf = XFS_BUF_TO_AGF(agbp); + agflen = INT_GET(agf->agf_length, ARCH_CONVERT); + sblock_ok = + INT_GET(block->bb_magic, ARCH_CONVERT) == xfs_magics[cur->bc_btnum] && + INT_GET(block->bb_level, ARCH_CONVERT) == level && + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= + xfs_btree_maxrecs(cur, (xfs_btree_block_t *)block) && + (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK || + INT_GET(block->bb_leftsib, ARCH_CONVERT) < agflen) && + INT_GET(block->bb_leftsib, ARCH_CONVERT) != 0 && + (INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK || + INT_GET(block->bb_rightsib, ARCH_CONVERT) < agflen) && + INT_GET(block->bb_rightsib, ARCH_CONVERT) != 0; + if (XFS_TEST_ERROR(!sblock_ok, cur->bc_mp, + XFS_ERRTAG_BTREE_CHECK_SBLOCK, + XFS_RANDOM_BTREE_CHECK_SBLOCK)) { + if (bp) + xfs_buftrace("SBTREE ERROR", bp); + return XFS_ERROR(EFSCORRUPTED); + } + return 0; +} + +/* + * Checking routine: check that (short) pointer is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_sptr( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t ptr, /* btree block disk address */ + int level) /* btree block level */ +{ + xfs_buf_t *agbp; /* buffer for ag. freespace struct */ + xfs_agf_t *agf; /* ag. freespace structure */ + + agbp = cur->bc_private.a.agbp; + agf = XFS_BUF_TO_AGF(agbp); + XFS_WANT_CORRUPTED_RETURN( + level > 0 && + ptr != NULLAGBLOCK && ptr != 0 && + ptr < INT_GET(agf->agf_length, ARCH_CONVERT)); + return 0; +} + +/* + * Delete the btree cursor. + */ +void +xfs_btree_del_cursor( + xfs_btree_cur_t *cur, /* btree cursor */ + int error) /* del because of error */ +{ + int i; /* btree level */ + + /* + * Clear the buffer pointers, and release the buffers. + * If we're doing this in the face of an error, we + * need to make sure to inspect all of the entries + * in the bc_bufs array for buffers to be unlocked. + * This is because some of the btree code works from + * level n down to 0, and if we get an error along + * the way we won't have initialized all the entries + * down to 0. + */ + for (i = 0; i < cur->bc_nlevels; i++) { + if (cur->bc_bufs[i]) + xfs_btree_setbuf(cur, i, NULL); + else if (!error) + break; + } + /* + * Can't free a bmap cursor without having dealt with the + * allocated indirect blocks' accounting. + */ + ASSERT(cur->bc_btnum != XFS_BTNUM_BMAP || + cur->bc_private.b.allocated == 0); + /* + * Free the cursor. + */ + kmem_zone_free(xfs_btree_cur_zone, cur); +} + +/* + * Duplicate the btree cursor. + * Allocate a new one, copy the record, re-get the buffers. + */ +int /* error */ +xfs_btree_dup_cursor( + xfs_btree_cur_t *cur, /* input cursor */ + xfs_btree_cur_t **ncur) /* output cursor */ +{ + xfs_buf_t *bp; /* btree block's buffer pointer */ + int error; /* error return value */ + int i; /* level number of btree block */ + xfs_mount_t *mp; /* mount structure for filesystem */ + xfs_btree_cur_t *new; /* new cursor value */ + xfs_trans_t *tp; /* transaction pointer, can be NULL */ + + tp = cur->bc_tp; + mp = cur->bc_mp; + /* + * Allocate a new cursor like the old one. + */ + new = xfs_btree_init_cursor(mp, tp, cur->bc_private.a.agbp, + cur->bc_private.a.agno, cur->bc_btnum, cur->bc_private.b.ip, + cur->bc_private.b.whichfork); + /* + * Copy the record currently in the cursor. + */ + new->bc_rec = cur->bc_rec; + /* + * For each level current, re-get the buffer and copy the ptr value. + */ + for (i = 0; i < new->bc_nlevels; i++) { + new->bc_ptrs[i] = cur->bc_ptrs[i]; + new->bc_ra[i] = cur->bc_ra[i]; + if ((bp = cur->bc_bufs[i])) { + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, + XFS_BUF_ADDR(bp), mp->m_bsize, 0, &bp))) { + xfs_btree_del_cursor(new, error); + *ncur = NULL; + return error; + } + new->bc_bufs[i] = bp; + ASSERT(bp); + ASSERT(!XFS_BUF_GETERROR(bp)); + } else + new->bc_bufs[i] = NULL; + } + /* + * For bmap btrees, copy the firstblock, flist, and flags values, + * since init cursor doesn't get them. + */ + if (new->bc_btnum == XFS_BTNUM_BMAP) { + new->bc_private.b.firstblock = cur->bc_private.b.firstblock; + new->bc_private.b.flist = cur->bc_private.b.flist; + new->bc_private.b.flags = cur->bc_private.b.flags; + } + *ncur = new; + return 0; +} + +/* + * Change the cursor to point to the first record at the given level. + * Other levels are unaffected. + */ +int /* success=1, failure=0 */ +xfs_btree_firstrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level) /* level to change */ +{ + xfs_btree_block_t *block; /* generic btree block pointer */ + xfs_buf_t *bp; /* buffer containing block */ + + /* + * Get the block pointer for this level. + */ + block = xfs_btree_get_block(cur, level, &bp); + xfs_btree_check_block(cur, block, level, bp); + /* + * It's empty, there is no such record. + */ + if (INT_GET(block->bb_h.bb_numrecs, ARCH_CONVERT) == 0) + return 0; + /* + * Set the ptr value to 1, that's the first record/key. + */ + cur->bc_ptrs[level] = 1; + return 1; +} + +/* + * Retrieve the block pointer from the cursor at the given level. + * This may be a bmap btree root or from a buffer. + */ +xfs_btree_block_t * /* generic btree block pointer */ +xfs_btree_get_block( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree */ + xfs_buf_t **bpp) /* buffer containing the block */ +{ + xfs_btree_block_t *block; /* return value */ + xfs_buf_t *bp; /* return buffer */ + xfs_ifork_t *ifp; /* inode fork pointer */ + int whichfork; /* data or attr fork */ + + if (cur->bc_btnum == XFS_BTNUM_BMAP && level == cur->bc_nlevels - 1) { + whichfork = cur->bc_private.b.whichfork; + ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, whichfork); + block = (xfs_btree_block_t *)ifp->if_broot; + bp = NULL; + } else { + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_BLOCK(bp); + } + ASSERT(block != NULL); + *bpp = bp; + return block; +} + +/* + * Get a buffer for the block, return it with no data read. + * Long-form addressing. + */ +xfs_buf_t * /* buffer for fsbno */ +xfs_btree_get_bufl( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_fsblock_t fsbno, /* file system block number */ + uint lock) /* lock flags for get_buf */ +{ + xfs_buf_t *bp; /* buffer pointer (return value) */ + xfs_daddr_t d; /* real disk block address */ + + ASSERT(fsbno != NULLFSBLOCK); + d = XFS_FSB_TO_DADDR(mp, fsbno); + bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock); + ASSERT(bp); + ASSERT(!XFS_BUF_GETERROR(bp)); + return bp; +} + +/* + * Get a buffer for the block, return it with no data read. + * Short-form addressing. + */ +xfs_buf_t * /* buffer for agno/agbno */ +xfs_btree_get_bufs( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + uint lock) /* lock flags for get_buf */ +{ + xfs_buf_t *bp; /* buffer pointer (return value) */ + xfs_daddr_t d; /* real disk block address */ + + ASSERT(agno != NULLAGNUMBER); + ASSERT(agbno != NULLAGBLOCK); + d = XFS_AGB_TO_DADDR(mp, agno, agbno); + bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock); + ASSERT(bp); + ASSERT(!XFS_BUF_GETERROR(bp)); + return bp; +} + +/* + * Allocate a new btree cursor. + * The cursor is either for allocation (A) or bmap (B) or inodes (I). + */ +xfs_btree_cur_t * /* new btree cursor */ +xfs_btree_init_cursor( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* (A only) buffer for agf structure */ + /* (I only) buffer for agi structure */ + xfs_agnumber_t agno, /* (AI only) allocation group number */ + xfs_btnum_t btnum, /* btree identifier */ + xfs_inode_t *ip, /* (B only) inode owning the btree */ + int whichfork) /* (B only) data or attr fork */ +{ + xfs_agf_t *agf; /* (A) allocation group freespace */ + xfs_agi_t *agi; /* (I) allocation group inodespace */ + xfs_btree_cur_t *cur; /* return value */ + xfs_ifork_t *ifp; /* (I) inode fork pointer */ + int nlevels=0; /* number of levels in the btree */ + + ASSERT(xfs_btree_cur_zone != NULL); + /* + * Allocate a new cursor. + */ + cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); + /* + * Deduce the number of btree levels from the arguments. + */ + switch (btnum) { + case XFS_BTNUM_BNO: + case XFS_BTNUM_CNT: + agf = XFS_BUF_TO_AGF(agbp); + nlevels = INT_GET(agf->agf_levels[btnum], ARCH_CONVERT); + break; + case XFS_BTNUM_BMAP: + ifp = XFS_IFORK_PTR(ip, whichfork); + nlevels = INT_GET(ifp->if_broot->bb_level, ARCH_CONVERT) + 1; + break; + case XFS_BTNUM_INO: + agi = XFS_BUF_TO_AGI(agbp); + nlevels = INT_GET(agi->agi_level, ARCH_CONVERT); + break; + default: + ASSERT(0); + } + /* + * Fill in the common fields. + */ + cur->bc_tp = tp; + cur->bc_mp = mp; + cur->bc_nlevels = nlevels; + cur->bc_btnum = btnum; + cur->bc_blocklog = mp->m_sb.sb_blocklog; + /* + * Fill in private fields. + */ + switch (btnum) { + case XFS_BTNUM_BNO: + case XFS_BTNUM_CNT: + /* + * Allocation btree fields. + */ + cur->bc_private.a.agbp = agbp; + cur->bc_private.a.agno = agno; + break; + case XFS_BTNUM_BMAP: + /* + * Bmap btree fields. + */ + cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork); + cur->bc_private.b.ip = ip; + cur->bc_private.b.firstblock = NULLFSBLOCK; + cur->bc_private.b.flist = NULL; + cur->bc_private.b.allocated = 0; + cur->bc_private.b.flags = 0; + cur->bc_private.b.whichfork = whichfork; + break; + case XFS_BTNUM_INO: + /* + * Inode allocation btree fields. + */ + cur->bc_private.i.agbp = agbp; + cur->bc_private.i.agno = agno; + break; + default: + ASSERT(0); + } + return cur; +} + +/* + * Check for the cursor referring to the last block at the given level. + */ +int /* 1=is last block, 0=not last block */ +xfs_btree_islastblock( + xfs_btree_cur_t *cur, /* btree cursor */ + int level) /* level to check */ +{ + xfs_btree_block_t *block; /* generic btree block pointer */ + xfs_buf_t *bp; /* buffer containing block */ + + block = xfs_btree_get_block(cur, level, &bp); + xfs_btree_check_block(cur, block, level, bp); + if (XFS_BTREE_LONG_PTRS(cur->bc_btnum)) + return INT_GET(block->bb_u.l.bb_rightsib, ARCH_CONVERT) == NULLDFSBNO; + else + return INT_GET(block->bb_u.s.bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK; +} + +/* + * Change the cursor to point to the last record in the current block + * at the given level. Other levels are unaffected. + */ +int /* success=1, failure=0 */ +xfs_btree_lastrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level) /* level to change */ +{ + xfs_btree_block_t *block; /* generic btree block pointer */ + xfs_buf_t *bp; /* buffer containing block */ + + /* + * Get the block pointer for this level. + */ + block = xfs_btree_get_block(cur, level, &bp); + xfs_btree_check_block(cur, block, level, bp); + /* + * It's empty, there is no such record. + */ + if (INT_GET(block->bb_h.bb_numrecs, ARCH_CONVERT) == 0) + return 0; + /* + * Set the ptr value to numrecs, that's the last record/key. + */ + cur->bc_ptrs[level] = INT_GET(block->bb_h.bb_numrecs, ARCH_CONVERT); + return 1; +} + +/* + * Compute first and last byte offsets for the fields given. + * Interprets the offsets table, which contains struct field offsets. + */ +void +xfs_btree_offsets( + __int64_t fields, /* bitmask of fields */ + const short *offsets, /* table of field offsets */ + int nbits, /* number of bits to inspect */ + int *first, /* output: first byte offset */ + int *last) /* output: last byte offset */ +{ + int i; /* current bit number */ + __int64_t imask; /* mask for current bit number */ + + ASSERT(fields != 0); + /* + * Find the lowest bit, so the first byte offset. + */ + for (i = 0, imask = 1LL; ; i++, imask <<= 1) { + if (imask & fields) { + *first = offsets[i]; + break; + } + } + /* + * Find the highest bit, so the last byte offset. + */ + for (i = nbits - 1, imask = 1LL << i; ; i--, imask >>= 1) { + if (imask & fields) { + *last = offsets[i + 1] - 1; + break; + } + } +} + +/* + * Get a buffer for the block, return it read in. + * Long-form addressing. + */ +int /* error */ +xfs_btree_read_bufl( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_fsblock_t fsbno, /* file system block number */ + uint lock, /* lock flags for read_buf */ + xfs_buf_t **bpp, /* buffer for fsbno */ + int refval) /* ref count value for buffer */ +{ + xfs_buf_t *bp; /* return value */ + xfs_daddr_t d; /* real disk block address */ + int error; + + ASSERT(fsbno != NULLFSBLOCK); + d = XFS_FSB_TO_DADDR(mp, fsbno); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, + mp->m_bsize, lock, &bp))) { + return error; + } + ASSERT(!bp || !XFS_BUF_GETERROR(bp)); + if (bp != NULL) { + XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, refval); + } + *bpp = bp; + return 0; +} + +/* + * Get a buffer for the block, return it read in. + * Short-form addressing. + */ +int /* error */ +xfs_btree_read_bufs( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + uint lock, /* lock flags for read_buf */ + xfs_buf_t **bpp, /* buffer for agno/agbno */ + int refval) /* ref count value for buffer */ +{ + xfs_buf_t *bp; /* return value */ + xfs_daddr_t d; /* real disk block address */ + int error; + + ASSERT(agno != NULLAGNUMBER); + ASSERT(agbno != NULLAGBLOCK); + d = XFS_AGB_TO_DADDR(mp, agno, agbno); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, + mp->m_bsize, lock, &bp))) { + return error; + } + ASSERT(!bp || !XFS_BUF_GETERROR(bp)); + if (bp != NULL) { + switch (refval) { + case XFS_ALLOC_BTREE_REF: + XFS_BUF_SET_VTYPE_REF(bp, B_FS_MAP, refval); + break; + case XFS_INO_BTREE_REF: + XFS_BUF_SET_VTYPE_REF(bp, B_FS_INOMAP, refval); + break; + } + } + *bpp = bp; + return 0; +} + +/* + * Read-ahead the block, don't wait for it, don't return a buffer. + * Long-form addressing. + */ +/* ARGSUSED */ +void +xfs_btree_reada_bufl( + xfs_mount_t *mp, /* file system mount point */ + xfs_fsblock_t fsbno, /* file system block number */ + xfs_extlen_t count) /* count of filesystem blocks */ +{ + xfs_daddr_t d; + + ASSERT(fsbno != NULLFSBLOCK); + d = XFS_FSB_TO_DADDR(mp, fsbno); + xfs_baread(mp->m_ddev_targp, d, mp->m_bsize * count); +} + +/* + * Read-ahead the block, don't wait for it, don't return a buffer. + * Short-form addressing. + */ +/* ARGSUSED */ +void +xfs_btree_reada_bufs( + xfs_mount_t *mp, /* file system mount point */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + xfs_extlen_t count) /* count of filesystem blocks */ +{ + xfs_daddr_t d; + + ASSERT(agno != NULLAGNUMBER); + ASSERT(agbno != NULLAGBLOCK); + d = XFS_AGB_TO_DADDR(mp, agno, agbno); + xfs_baread(mp->m_ddev_targp, d, mp->m_bsize * count); +} + +/* + * Read-ahead btree blocks, at the given level. + * Bits in lr are set from XFS_BTCUR_{LEFT,RIGHT}RA. + */ +int +xfs_btree_readahead_core( + xfs_btree_cur_t *cur, /* btree cursor */ + int lev, /* level in btree */ + int lr) /* left/right bits */ +{ + xfs_alloc_block_t *a; + xfs_bmbt_block_t *b; + xfs_inobt_block_t *i; + int rval = 0; + + ASSERT(cur->bc_bufs[lev] != NULL); + cur->bc_ra[lev] |= lr; + switch (cur->bc_btnum) { + case XFS_BTNUM_BNO: + case XFS_BTNUM_CNT: + a = XFS_BUF_TO_ALLOC_BLOCK(cur->bc_bufs[lev]); + if ((lr & XFS_BTCUR_LEFTRA) && INT_GET(a->bb_leftsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, + INT_GET(a->bb_leftsib, ARCH_CONVERT), 1); + rval++; + } + if ((lr & XFS_BTCUR_RIGHTRA) && INT_GET(a->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, + INT_GET(a->bb_rightsib, ARCH_CONVERT), 1); + rval++; + } + break; + case XFS_BTNUM_BMAP: + b = XFS_BUF_TO_BMBT_BLOCK(cur->bc_bufs[lev]); + if ((lr & XFS_BTCUR_LEFTRA) && INT_GET(b->bb_leftsib, ARCH_CONVERT) != NULLDFSBNO) { + xfs_btree_reada_bufl(cur->bc_mp, INT_GET(b->bb_leftsib, ARCH_CONVERT), 1); + rval++; + } + if ((lr & XFS_BTCUR_RIGHTRA) && INT_GET(b->bb_rightsib, ARCH_CONVERT) != NULLDFSBNO) { + xfs_btree_reada_bufl(cur->bc_mp, INT_GET(b->bb_rightsib, ARCH_CONVERT), 1); + rval++; + } + break; + case XFS_BTNUM_INO: + i = XFS_BUF_TO_INOBT_BLOCK(cur->bc_bufs[lev]); + if ((lr & XFS_BTCUR_LEFTRA) && INT_GET(i->bb_leftsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.i.agno, + INT_GET(i->bb_leftsib, ARCH_CONVERT), 1); + rval++; + } + if ((lr & XFS_BTCUR_RIGHTRA) && INT_GET(i->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.i.agno, + INT_GET(i->bb_rightsib, ARCH_CONVERT), 1); + rval++; + } + break; + default: + ASSERT(0); + } + return rval; +} + +/* + * Set the buffer for level "lev" in the cursor to bp, releasing + * any previous buffer. + */ +void +xfs_btree_setbuf( + xfs_btree_cur_t *cur, /* btree cursor */ + int lev, /* level in btree */ + xfs_buf_t *bp) /* new buffer to set */ +{ + xfs_btree_block_t *b; /* btree block */ + xfs_buf_t *obp; /* old buffer pointer */ + + obp = cur->bc_bufs[lev]; + if (obp) + xfs_trans_brelse(cur->bc_tp, obp); + cur->bc_bufs[lev] = bp; + cur->bc_ra[lev] = 0; + if (!bp) + return; + b = XFS_BUF_TO_BLOCK(bp); + if (XFS_BTREE_LONG_PTRS(cur->bc_btnum)) { + if (INT_GET(b->bb_u.l.bb_leftsib, ARCH_CONVERT) == NULLDFSBNO) + cur->bc_ra[lev] |= XFS_BTCUR_LEFTRA; + if (INT_GET(b->bb_u.l.bb_rightsib, ARCH_CONVERT) == NULLDFSBNO) + cur->bc_ra[lev] |= XFS_BTCUR_RIGHTRA; + } else { + if (INT_GET(b->bb_u.s.bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK) + cur->bc_ra[lev] |= XFS_BTCUR_LEFTRA; + if (INT_GET(b->bb_u.s.bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK) + cur->bc_ra[lev] |= XFS_BTCUR_RIGHTRA; + } +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_btree.h linux-2.4-xfs/linux/fs/xfs/xfs_btree.h --- linux-2.4.7/linux/fs/xfs/xfs_btree.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_btree.h Tue Apr 3 12:32:55 2001 @@ -0,0 +1,587 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BTREE_H__ +#define __XFS_BTREE_H__ + +struct xfs_buf; +struct xfs_bmap_free; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * This nonsense is to make -wlint happy. + */ +#define XFS_LOOKUP_EQ ((xfs_lookup_t)XFS_LOOKUP_EQi) +#define XFS_LOOKUP_LE ((xfs_lookup_t)XFS_LOOKUP_LEi) +#define XFS_LOOKUP_GE ((xfs_lookup_t)XFS_LOOKUP_GEi) + +#define XFS_BTNUM_BNO ((xfs_btnum_t)XFS_BTNUM_BNOi) +#define XFS_BTNUM_CNT ((xfs_btnum_t)XFS_BTNUM_CNTi) +#define XFS_BTNUM_BMAP ((xfs_btnum_t)XFS_BTNUM_BMAPi) +#define XFS_BTNUM_INO ((xfs_btnum_t)XFS_BTNUM_INOi) + +/* + * Short form header: space allocation btrees. + */ +typedef struct xfs_btree_sblock +{ + __uint32_t bb_magic; /* magic number for block type */ + __uint16_t bb_level; /* 0 is a leaf */ + __uint16_t bb_numrecs; /* current # of data records */ + xfs_agblock_t bb_leftsib; /* left sibling block or NULLAGBLOCK */ + xfs_agblock_t bb_rightsib; /* right sibling block or NULLAGBLOCK */ +} xfs_btree_sblock_t; + +/* + * Long form header: bmap btrees. + */ +typedef struct xfs_btree_lblock +{ + __uint32_t bb_magic; /* magic number for block type */ + __uint16_t bb_level; /* 0 is a leaf */ + __uint16_t bb_numrecs; /* current # of data records */ + xfs_dfsbno_t bb_leftsib; /* left sibling block or NULLDFSBNO */ + xfs_dfsbno_t bb_rightsib; /* right sibling block or NULLDFSBNO */ +} xfs_btree_lblock_t; + +/* + * Combined header and structure, used by common code. + */ +typedef struct xfs_btree_hdr +{ + __uint32_t bb_magic; /* magic number for block type */ + __uint16_t bb_level; /* 0 is a leaf */ + __uint16_t bb_numrecs; /* current # of data records */ +} xfs_btree_hdr_t; + +typedef struct xfs_btree_block +{ + xfs_btree_hdr_t bb_h; /* header */ + union { + struct { + xfs_agblock_t bb_leftsib; + xfs_agblock_t bb_rightsib; + } s; /* short form pointers */ + struct { + xfs_dfsbno_t bb_leftsib; + xfs_dfsbno_t bb_rightsib; + } l; /* long form pointers */ + } bb_u; /* rest */ +} xfs_btree_block_t; + +/* + * For logging record fields. + */ +#define XFS_BB_MAGIC 0x01 +#define XFS_BB_LEVEL 0x02 +#define XFS_BB_NUMRECS 0x04 +#define XFS_BB_LEFTSIB 0x08 +#define XFS_BB_RIGHTSIB 0x10 +#define XFS_BB_NUM_BITS 5 +#define XFS_BB_ALL_BITS ((1 << XFS_BB_NUM_BITS) - 1) + +/* + * Boolean to select which form of xfs_btree_block_t.bb_u to use. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BTREE_LONG_PTRS) +int xfs_btree_long_ptrs(xfs_btnum_t btnum); +#define XFS_BTREE_LONG_PTRS(btnum) ((btnum) == XFS_BTNUM_BMAP) +#else +#define XFS_BTREE_LONG_PTRS(btnum) ((btnum) == XFS_BTNUM_BMAP) +#endif + +/* + * Magic numbers for btree blocks. + */ +extern const __uint32_t xfs_magics[]; + +/* + * Maximum and minimum records in a btree block. + * Given block size, type prefix, and leaf flag (0 or 1). + * The divisor below is equivalent to lf ? (e1) : (e2) but that produces + * compiler warnings. + */ +#define XFS_BTREE_BLOCK_MAXRECS(bsz,t,lf) \ + ((int)(((bsz) - (uint)sizeof(t ## _block_t)) / \ + (((lf) * (uint)sizeof(t ## _rec_t)) + \ + ((1 - (lf)) * \ + ((uint)sizeof(t ## _key_t) + (uint)sizeof(t ## _ptr_t)))))) +#define XFS_BTREE_BLOCK_MINRECS(bsz,t,lf) \ + (XFS_BTREE_BLOCK_MAXRECS(bsz,t,lf) / 2) + +/* + * Record, key, and pointer address calculation macros. + * Given block size, type prefix, block pointer, and index of requested entry + * (first entry numbered 1). + */ +#define XFS_BTREE_REC_ADDR(bsz,t,bb,i,mxr) \ + ((t ## _rec_t *)((char *)(bb) + sizeof(t ## _block_t) + \ + ((i) - 1) * sizeof(t ## _rec_t))) +#define XFS_BTREE_KEY_ADDR(bsz,t,bb,i,mxr) \ + ((t ## _key_t *)((char *)(bb) + sizeof(t ## _block_t) + \ + ((i) - 1) * sizeof(t ## _key_t))) +#define XFS_BTREE_PTR_ADDR(bsz,t,bb,i,mxr) \ + ((t ## _ptr_t *)((char *)(bb) + sizeof(t ## _block_t) + \ + (mxr) * sizeof(t ## _key_t) + ((i) - 1) * sizeof(t ## _ptr_t))) + +#define XFS_BTREE_MAXLEVELS 8 /* max of all btrees */ + +/* + * Btree cursor structure. + * This collects all information needed by the btree code in one place. + */ +typedef struct xfs_btree_cur +{ + struct xfs_trans *bc_tp; /* transaction we're in, if any */ + struct xfs_mount *bc_mp; /* file system mount struct */ + union { + xfs_alloc_rec_t a; + xfs_bmbt_irec_t b; + xfs_inobt_rec_t i; + } bc_rec; /* current insert/search record value */ + struct xfs_buf *bc_bufs[XFS_BTREE_MAXLEVELS]; /* buf ptr per level */ + int bc_ptrs[XFS_BTREE_MAXLEVELS]; /* key/record # */ + __uint8_t bc_ra[XFS_BTREE_MAXLEVELS]; /* readahead bits */ +#define XFS_BTCUR_LEFTRA 1 /* left sibling has been read-ahead */ +#define XFS_BTCUR_RIGHTRA 2 /* right sibling has been read-ahead */ + __uint8_t bc_nlevels; /* number of levels in the tree */ + __uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */ + xfs_btnum_t bc_btnum; /* identifies which btree type */ + union { + struct { /* needed for BNO, CNT */ + struct xfs_buf *agbp; /* agf buffer pointer */ + xfs_agnumber_t agno; /* ag number */ + } a; + struct { /* needed for BMAP */ + struct xfs_inode *ip; /* pointer to our inode */ + struct xfs_bmap_free *flist; /* list to free after */ + xfs_fsblock_t firstblock; /* 1st blk allocated */ + int allocated; /* count of alloced */ + short forksize; /* fork's inode space */ + char whichfork; /* data or attr fork */ + char flags; /* flags */ +#define XFS_BTCUR_BPRV_WASDEL 1 /* was delayed */ + } b; + struct { /* needed for INO */ + struct xfs_buf *agbp; /* agi buffer pointer */ + xfs_agnumber_t agno; /* ag number */ + } i; + } bc_private; /* per-btree type data */ +} xfs_btree_cur_t; + +#define XFS_BTREE_NOERROR 0 +#define XFS_BTREE_ERROR 1 + +/* + * Convert from buffer to btree block header. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_BLOCK) +xfs_btree_block_t *xfs_buf_to_block(struct xfs_buf *bp); +#define XFS_BUF_TO_BLOCK(bp) xfs_buf_to_block(bp) +#else +#define XFS_BUF_TO_BLOCK(bp) ((xfs_btree_block_t *)(XFS_BUF_PTR(bp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_LBLOCK) +xfs_btree_lblock_t *xfs_buf_to_lblock(struct xfs_buf *bp); +#define XFS_BUF_TO_LBLOCK(bp) xfs_buf_to_lblock(bp) +#else +#define XFS_BUF_TO_LBLOCK(bp) ((xfs_btree_lblock_t *)(XFS_BUF_PTR(bp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_SBLOCK) +xfs_btree_sblock_t *xfs_buf_to_sblock(struct xfs_buf *bp); +#define XFS_BUF_TO_SBLOCK(bp) xfs_buf_to_sblock(bp) +#else +#define XFS_BUF_TO_SBLOCK(bp) ((xfs_btree_sblock_t *)(XFS_BUF_PTR(bp))) +#endif + +#ifdef __KERNEL__ + +#ifdef DEBUG +/* + * Debug routine: check that block header is ok. + */ +void +xfs_btree_check_block( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_block_t *block, /* generic btree block pointer */ + int level, /* level of the btree block */ + struct xfs_buf *bp); /* buffer containing block, if any */ + +/* + * Debug routine: check that keys are in the right order. + */ +void +xfs_btree_check_key( + xfs_btnum_t btnum, /* btree identifier */ + void *ak1, /* pointer to left (lower) key */ + void *ak2); /* pointer to right (higher) key */ + +/* + * Debug routine: check that records are in the right order. + */ +void +xfs_btree_check_rec( + xfs_btnum_t btnum, /* btree identifier */ + void *ar1, /* pointer to left (lower) record */ + void *ar2); /* pointer to right (higher) record */ +#else +#define xfs_btree_check_block(a,b,c,d) +#define xfs_btree_check_key(a,b,c) +#define xfs_btree_check_rec(a,b,c) +#endif /* DEBUG */ + +/* + * Checking routine: check that long form block header is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_lblock( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_lblock_t *block, /* btree long form block pointer */ + int level, /* level of the btree block */ + struct xfs_buf *bp); /* buffer containing block, if any */ + +/* + * Checking routine: check that (long) pointer is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_lptr( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_dfsbno_t ptr, /* btree block disk address */ + int level); /* btree block level */ + +/* + * Checking routine: check that short form block header is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_sblock( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_btree_sblock_t *block, /* btree short form block pointer */ + int level, /* level of the btree block */ + struct xfs_buf *bp); /* buffer containing block */ + +/* + * Checking routine: check that (short) pointer is ok. + */ +int /* error (0 or EFSCORRUPTED) */ +xfs_btree_check_sptr( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agblock_t ptr, /* btree block disk address */ + int level); /* btree block level */ + +/* + * Delete the btree cursor. + */ +void +xfs_btree_del_cursor( + xfs_btree_cur_t *cur, /* btree cursor */ + int error); /* del because of error */ + +/* + * Duplicate the btree cursor. + * Allocate a new one, copy the record, re-get the buffers. + */ +int /* error */ +xfs_btree_dup_cursor( + xfs_btree_cur_t *cur, /* input cursor */ + xfs_btree_cur_t **ncur);/* output cursor */ + +/* + * Change the cursor to point to the first record in the current block + * at the given level. Other levels are unaffected. + */ +int /* success=1, failure=0 */ +xfs_btree_firstrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level); /* level to change */ + +/* + * Retrieve the block pointer from the cursor at the given level. + * This may be a bmap btree root or from a buffer. + */ +xfs_btree_block_t * /* generic btree block pointer */ +xfs_btree_get_block( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree */ + struct xfs_buf **bpp); /* buffer containing the block */ + +/* + * Get a buffer for the block, return it with no data read. + * Long-form addressing. + */ +struct xfs_buf * /* buffer for fsbno */ +xfs_btree_get_bufl( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_fsblock_t fsbno, /* file system block number */ + uint lock); /* lock flags for get_buf */ + +/* + * Get a buffer for the block, return it with no data read. + * Short-form addressing. + */ +struct xfs_buf * /* buffer for agno/agbno */ +xfs_btree_get_bufs( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + uint lock); /* lock flags for get_buf */ + +/* + * Allocate a new btree cursor. + * The cursor is either for allocation (A) or bmap (B). + */ +xfs_btree_cur_t * /* new btree cursor */ +xfs_btree_init_cursor( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_buf *agbp, /* (A only) buffer for agf structure */ + xfs_agnumber_t agno, /* (A only) allocation group number */ + xfs_btnum_t btnum, /* btree identifier */ + struct xfs_inode *ip, /* (B only) inode owning the btree */ + int whichfork); /* (B only) data/attr fork */ + +/* + * Check for the cursor referring to the last block at the given level. + */ +int /* 1=is last block, 0=not last block */ +xfs_btree_islastblock( + xfs_btree_cur_t *cur, /* btree cursor */ + int level); /* level to check */ + +/* + * Change the cursor to point to the last record in the current block + * at the given level. Other levels are unaffected. + */ +int /* success=1, failure=0 */ +xfs_btree_lastrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level); /* level to change */ + +/* + * Compute first and last byte offsets for the fields given. + * Interprets the offsets table, which contains struct field offsets. + */ +void +xfs_btree_offsets( + __int64_t fields, /* bitmask of fields */ + const short *offsets,/* table of field offsets */ + int nbits, /* number of bits to inspect */ + int *first, /* output: first byte offset */ + int *last); /* output: last byte offset */ + +/* + * Get a buffer for the block, return it read in. + * Long-form addressing. + */ +int /* error */ +xfs_btree_read_bufl( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_fsblock_t fsbno, /* file system block number */ + uint lock, /* lock flags for read_buf */ + struct xfs_buf **bpp, /* buffer for fsbno */ + int refval);/* ref count value for buffer */ + +/* + * Get a buffer for the block, return it read in. + * Short-form addressing. + */ +int /* error */ +xfs_btree_read_bufs( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + uint lock, /* lock flags for read_buf */ + struct xfs_buf **bpp, /* buffer for agno/agbno */ + int refval);/* ref count value for buffer */ + +/* + * Read-ahead the block, don't wait for it, don't return a buffer. + * Long-form addressing. + */ +void /* error */ +xfs_btree_reada_bufl( + struct xfs_mount *mp, /* file system mount point */ + xfs_fsblock_t fsbno, /* file system block number */ + xfs_extlen_t count); /* count of filesystem blocks */ + +/* + * Read-ahead the block, don't wait for it, don't return a buffer. + * Short-form addressing. + */ +void /* error */ +xfs_btree_reada_bufs( + struct xfs_mount *mp, /* file system mount point */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_agblock_t agbno, /* allocation group block number */ + xfs_extlen_t count); /* count of filesystem blocks */ + +/* + * Read-ahead btree blocks, at the given level. + * Bits in lr are set from XFS_BTCUR_{LEFT,RIGHT}RA. + */ +int /* readahead block count */ +xfs_btree_readahead_core( + xfs_btree_cur_t *cur, /* btree cursor */ + int lev, /* level in btree */ + int lr); /* left/right bits */ + +static inline int /* readahead block count */ +xfs_btree_readahead( + xfs_btree_cur_t *cur, /* btree cursor */ + int lev, /* level in btree */ + int lr) /* left/right bits */ +{ + if ((cur->bc_ra[lev] | lr) == cur->bc_ra[lev]) + return 0; + + return xfs_btree_readahead_core(cur, lev, lr); +} + + +/* + * Set the buffer for level "lev" in the cursor to bp, releasing + * any previous buffer. + */ +void +xfs_btree_setbuf( + xfs_btree_cur_t *cur, /* btree cursor */ + int lev, /* level in btree */ + struct xfs_buf *bp); /* new buffer to set */ + +#endif /* __KERNEL__ */ + + +/* + * Min and max functions for extlen, agblock, fileoff, and filblks types. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_EXTLEN_MIN) +xfs_extlen_t xfs_extlen_min(xfs_extlen_t a, xfs_extlen_t b); +#define XFS_EXTLEN_MIN(a,b) xfs_extlen_min(a,b) +#else +#define XFS_EXTLEN_MIN(a,b) \ + ((xfs_extlen_t)(a) < (xfs_extlen_t)(b) ? \ + (xfs_extlen_t)(a) : (xfs_extlen_t)(b)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_EXTLEN_MAX) +xfs_extlen_t xfs_extlen_max(xfs_extlen_t a, xfs_extlen_t b); +#define XFS_EXTLEN_MAX(a,b) xfs_extlen_max(a,b) +#else +#define XFS_EXTLEN_MAX(a,b) \ + ((xfs_extlen_t)(a) > (xfs_extlen_t)(b) ? \ + (xfs_extlen_t)(a) : (xfs_extlen_t)(b)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGBLOCK_MIN) +xfs_agblock_t xfs_agblock_min(xfs_agblock_t a, xfs_agblock_t b); +#define XFS_AGBLOCK_MIN(a,b) xfs_agblock_min(a,b) +#else +#define XFS_AGBLOCK_MIN(a,b) \ + ((xfs_agblock_t)(a) < (xfs_agblock_t)(b) ? \ + (xfs_agblock_t)(a) : (xfs_agblock_t)(b)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGBLOCK_MAX) +xfs_agblock_t xfs_agblock_max(xfs_agblock_t a, xfs_agblock_t b); +#define XFS_AGBLOCK_MAX(a,b) xfs_agblock_max(a,b) +#else +#define XFS_AGBLOCK_MAX(a,b) \ + ((xfs_agblock_t)(a) > (xfs_agblock_t)(b) ? \ + (xfs_agblock_t)(a) : (xfs_agblock_t)(b)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FILEOFF_MIN) +xfs_fileoff_t xfs_fileoff_min(xfs_fileoff_t a, xfs_fileoff_t b); +#define XFS_FILEOFF_MIN(a,b) xfs_fileoff_min(a,b) +#else +#define XFS_FILEOFF_MIN(a,b) \ + ((xfs_fileoff_t)(a) < (xfs_fileoff_t)(b) ? \ + (xfs_fileoff_t)(a) : (xfs_fileoff_t)(b)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FILEOFF_MAX) +xfs_fileoff_t xfs_fileoff_max(xfs_fileoff_t a, xfs_fileoff_t b); +#define XFS_FILEOFF_MAX(a,b) xfs_fileoff_max(a,b) +#else +#define XFS_FILEOFF_MAX(a,b) \ + ((xfs_fileoff_t)(a) > (xfs_fileoff_t)(b) ? \ + (xfs_fileoff_t)(a) : (xfs_fileoff_t)(b)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FILBLKS_MIN) +xfs_filblks_t xfs_filblks_min(xfs_filblks_t a, xfs_filblks_t b); +#define XFS_FILBLKS_MIN(a,b) xfs_filblks_min(a,b) +#else +#define XFS_FILBLKS_MIN(a,b) \ + ((xfs_filblks_t)(a) < (xfs_filblks_t)(b) ? \ + (xfs_filblks_t)(a) : (xfs_filblks_t)(b)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FILBLKS_MAX) +xfs_filblks_t xfs_filblks_max(xfs_filblks_t a, xfs_filblks_t b); +#define XFS_FILBLKS_MAX(a,b) xfs_filblks_max(a,b) +#else +#define XFS_FILBLKS_MAX(a,b) \ + ((xfs_filblks_t)(a) > (xfs_filblks_t)(b) ? \ + (xfs_filblks_t)(a) : (xfs_filblks_t)(b)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_SANITY_CHECK) +int xfs_fsb_sanity_check(struct xfs_mount *mp, xfs_fsblock_t fsb); +#define XFS_FSB_SANITY_CHECK(mp,fsb) xfs_fsb_sanity_check(mp,fsb) +#else +#define XFS_FSB_SANITY_CHECK(mp,fsb) \ + (XFS_FSB_TO_AGNO(mp, fsb) < mp->m_sb.sb_agcount && \ + XFS_FSB_TO_AGBNO(mp, fsb) < mp->m_sb.sb_agblocks) +#endif + +/* + * Macros to set EFSCORRUPTED & return/branch. + */ +#define XFS_WANT_CORRUPTED_GOTO(x,l) \ + { \ + int fs_is_ok = (x); \ + ASSERT(fs_is_ok); \ + if (!fs_is_ok) { \ + error = XFS_ERROR(EFSCORRUPTED); \ + goto l; \ + } \ + } + +#define XFS_WANT_CORRUPTED_RETURN(x) \ + { \ + int fs_is_ok = (x); \ + ASSERT(fs_is_ok); \ + if (!fs_is_ok) \ + return XFS_ERROR(EFSCORRUPTED); \ + } + +#endif /* __XFS_BTREE_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_buf.h linux-2.4-xfs/linux/fs/xfs/xfs_buf.h --- linux-2.4.7/linux/fs/xfs/xfs_buf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_buf.h Tue May 15 10:00:03 2001 @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BUF_H__ +#define __XFS_BUF_H__ + +/* These are just for xfs_syncsub... it sets an internal variable + * then passes it to VOP_FLUSH_PAGES or adds the flags to a newly gotten buf_t + */ +#define XFS_B_ASYNC PBF_ASYNC +#define XFS_B_DELWRI PBF_DELWRI +#define XFS_B_READ PBF_READ +#define XFS_B_WRITE PBF_WRITE +#define XFS_B_STALE (1 << 31) +#define XFS_BUF_TRYLOCK PBF_TRYLOCK +#define XFS_INCORE_TRYLOCK PBF_TRYLOCK +#define XFS_BUF_LOCK PBF_LOCK +#define XFS_BUF_MAPPED PBF_MAPPED + +#define BUF_BUSY PBF_DONT_BLOCK + +#define XFS_BUF_BFLAGS(x) ((x)->pb_flags) /* debugging routines might need this */ +#define XFS_BUF_ZEROFLAGS(x) \ + ((x)->pb_flags &= ~(PBF_READ|PBF_WRITE|PBF_ASYNC|PBF_SYNC|PBF_DELWRI)) + +#define XFS_BUF_STALE(x) ((x)->pb_flags |= XFS_B_STALE) +#define XFS_BUF_UNSTALE(x) ((x)->pb_flags &= ~XFS_B_STALE) +#define XFS_BUF_ISSTALE(x) ((x)->pb_flags & XFS_B_STALE) +#define XFS_BUF_SUPER_STALE(x) (x)->pb_flags |= XFS_B_STALE;\ + xfs_buf_undelay(x);\ + (x)->pb_flags &= ~(PBF_PARTIAL|PBF_NONE) + +static inline void xfs_buf_undelay(page_buf_t *pb) +{ + if (pb->pb_list.next != &pb->pb_list) { + pagebuf_delwri_dequeue(pb); + + /* + * Usually the hold count would be at least 2 + * here, with the irritating exception of + * the superblock case. + */ + if (pb->pb_hold > 1 ) + pagebuf_rele(pb); + + } else { + pb->pb_flags &= ~PBF_DELWRI; + } +} + +#define XFS_BUF_DELAYWRITE(x) ((x)->pb_flags |= PBF_DELWRI) +#define XFS_BUF_UNDELAYWRITE(x) xfs_buf_undelay(x) +#define XFS_BUF_ISDELAYWRITE(x) ((x)->pb_flags & PBF_DELWRI) + +#define XFS_BUF_ERROR(x,no) pagebuf_ioerror(x,no) +#define XFS_BUF_GETERROR(x) pagebuf_geterror(x) +#define XFS_BUF_ISERROR(x) (pagebuf_geterror(x)?1:0) + +#define XFS_BUF_DONE(x) ((x)->pb_flags &= ~(PBF_PARTIAL|PBF_NONE)) +#define XFS_BUF_UNDONE(x) ((x)->pb_flags |= PBF_PARTIAL|PBF_NONE) +#define XFS_BUF_ISDONE(x) (!(PBF_NOT_DONE(x))) + +#define XFS_BUF_BUSY(x) ((x)->pb_flags |= PBF_FORCEIO) +#define XFS_BUF_UNBUSY(x) ((x)->pb_flags &= ~PBF_FORCEIO) +#define XFS_BUF_ISBUSY(x) (1) + +#define XFS_BUF_ASYNC(x) ((x)->pb_flags |= PBF_ASYNC) +#define XFS_BUF_UNASYNC(x) ((x)->pb_flags &= ~PBF_ASYNC) +#define XFS_BUF_ISASYNC(x) ((x)->pb_flags & PBF_ASYNC) + +#define XFS_BUF_SHUT(x) printk("XFS_BUF_SHUT not implemented yet\n") +#define XFS_BUF_UNSHUT(x) printk("XFS_BUF_UNSHUT not implemented yet\n") +#define XFS_BUF_ISSHUT(x) (0) + +#define XFS_BUF_HOLD(x) pagebuf_hold(x) +#define XFS_BUF_READ(x) ((x)->pb_flags |= PBF_READ) +#define XFS_BUF_UNREAD(x) ((x)->pb_flags &= ~PBF_READ) +#define XFS_BUF_ISREAD(x) ((x)->pb_flags & PBF_READ) + +#define XFS_BUF_WRITE(x) ((x)->pb_flags |= PBF_WRITE) +#define XFS_BUF_UNWRITE(x) ((x)->pb_flags &= ~PBF_WRITE) +#define XFS_BUF_ISWRITE(x) ((x)->pb_flags & PBF_WRITE) + +#define XFS_BUF_UNCACHED(x) printk("XFS_BUF_UNCACHED not implemented yet\n") +#define XFS_BUF_UNUNCACHED(x) printk("XFS_BUF_UNUNCACHED not implemented yet\n") +#define XFS_BUF_ISUNCACHED(x) (0) + +#define XFS_BUF_ISUNINITIAL(x) ((x)->pb_flags & PBF_UNINITIAL) +#define XFS_BUF_UNUNINITIAL(x) ((x)->pb_flags &= ~PBF_UNINITIAL) + +#define XFS_BUF_AGE(x) printk("XFS_BUF_AGE not implemented yet\n") + +#define XFS_BUF_BP_ISMAPPED(bp) 1 +#define XFS_BUF_IS_GRIO(bp) ((bp)->pb_flags & PBF_GRIO) + +/* hmm what does the mean on linux? may go away */ +#define XFS_BUF_PAGEIO(x) printk("XFS_BUF_PAGEIO not implemented yet\n") +/* + * Flags for incore_match() and findchunk_match(). + */ +#define BUF_FSPRIV 0x1 +#define BUF_FSPRIV2 0x2 + +typedef struct page_buf_s xfs_buf_t; +#define xfs_buf page_buf_s + +struct inode; +struct xfs_mount; + +typedef struct buftarg { + struct pb_target *pb_targ; + dev_t dev; +} buftarg_t; + +#define XFS_BUF_IODONE_FUNC(buf) (buf)->pb_iodone +#define XFS_BUF_SET_IODONE_FUNC(buf, func) \ + (buf)->pb_iodone = (func) +#define XFS_BUF_CLR_IODONE_FUNC(buf) \ + (buf)->pb_iodone = NULL +#define XFS_BUF_SET_BDSTRAT_FUNC(buf, func) \ + (buf)->pb_strat = (func) +#define XFS_BUF_CLR_BDSTRAT_FUNC(buf) \ + (buf)->pb_strat = NULL + +#define XFS_BUF_FSPRIVATE(buf, type) \ + ((type)(buf)->pb_fspriv) +#define XFS_BUF_SET_FSPRIVATE(buf, value) \ + (buf)->pb_fspriv = (void *)(value) +#define XFS_BUF_FSPRIVATE2(buf, type) \ + ((type)(buf)->pb_fspriv2) +#define XFS_BUF_SET_FSPRIVATE2(buf, value) \ + (buf)->pb_fspriv2 = (void *)(value) +#define XFS_BUF_FSPRIVATE3(buf, type) \ + ((type)(buf)->pb_fspriv3) +#define XFS_BUF_SET_FSPRIVATE3(buf, value) \ + (buf)->pb_fspriv3 = (void *)(value) +#define XFS_BUF_SET_START(buf) + +#define XFS_BUF_SET_BRELSE_FUNC(buf, value) \ + (buf)->pb_relse = (value) + +#define XFS_BUF_PTR(bp) (xfs_caddr_t)((bp)->pb_addr) + +extern inline xfs_caddr_t xfs_buf_offset(page_buf_t *bp, off_t offset) +{ + if (bp->pb_flags & PBF_MAPPED) + return XFS_BUF_PTR(bp) + offset; + return (xfs_caddr_t) pagebuf_offset(bp, offset); +} + +#define XFS_BUF_SET_PTR(bp, val, count) \ + pagebuf_associate_memory(bp, val, count) +#define XFS_BUF_ADDR(bp) ((bp)->pb_bn) +#define XFS_BUF_OFFSET(bp) ((bp)->pb_file_offset >> 9) +#define XFS_BUF_SET_ADDR(bp, blk) \ + ((bp)->pb_bn = (page_buf_daddr_t)(blk)) +#define XFS_BUF_COUNT(bp) ((bp)->pb_count_desired) +#define XFS_BUF_SET_COUNT(bp, cnt) \ + ((bp)->pb_count_desired = cnt) +#define XFS_BUF_SIZE(bp) ((bp)->pb_buffer_length) +#define XFS_BUF_SET_SIZE(bp, cnt) \ + ((bp)->pb_buffer_length = cnt) +#define XFS_BUF_SET_VTYPE_REF(bp, type, ref) +#define XFS_BUF_SET_VTYPE(bp, type) +#define XFS_BUF_SET_REF(bp, ref) + +#define XFS_BUF_ISPINNED(bp) pagebuf_ispin(bp) + +#define XFS_BUF_VALUSEMA(bp) pagebuf_lock_value(bp) +#define XFS_BUF_CPSEMA(bp) (pagebuf_cond_lock(bp) == 0) +#define XFS_BUF_VSEMA(bp) pagebuf_unlock(bp) +#define XFS_BUF_PSEMA(bp,x) pagebuf_lock(bp) +#define XFS_BUF_V_IODONESEMA(bp) + +/* setup the buffer target from a buftarg structure */ +#define XFS_BUF_SET_TARGET(bp, target) \ + (bp)->pb_dev = (target)->dev + +#define XFS_BUF_TARGET(bp) ((bp)->pb_dev) +#define XFS_BUF_SET_VTYPE_REF(bp, type, ref) +#define XFS_BUF_SET_VTYPE(bp, type) +#define XFS_BUF_SET_REF(bp, ref) + +#define xfs_buf_read(target, blkno, len, flags) \ + pagebuf_get((target)->pb_targ, (blkno) << 9, (len) << 9, \ + PBF_LOCK | PBF_READ | PBF_MAPPED | PBF_MAPPABLE) +#define xfs_buf_get(target, blkno, len, flags) \ + pagebuf_get((target)->pb_targ, (blkno) << 9, (len) << 9, \ + PBF_LOCK | PBF_MAPPED | PBF_MAPPABLE) + +#define xfs_buf_read_flags(target, blkno, len, flags) \ + pagebuf_get((target)->pb_targ, (blkno) << 9, (len) << 9, \ + PBF_READ | PBF_MAPPABLE | flags) +#define xfs_buf_get_flags(target, blkno, len, flags) \ + pagebuf_get((target)->pb_targ, (blkno) << 9, (len) << 9, \ + PBF_MAPPABLE | flags) + +static inline int xfs_bawrite(void *mp, page_buf_t *bp) +{ + extern int xfs_bdstrat_cb(struct xfs_buf *); + int ret; + + bp->pb_fspriv3 = mp; + bp->pb_strat = xfs_bdstrat_cb; + xfs_buf_undelay(bp); + if ((ret = pagebuf_iostart(bp, PBF_WRITE | PBF_ASYNC)) == 0) + run_task_queue(&tq_disk); + return ret; +} + +static inline void xfs_buf_relse(page_buf_t *bp) +{ + if (bp->pb_relse == NULL) + pagebuf_unlock(bp); + + pagebuf_rele(bp); +} + + +#define xfs_bpin(bp) pagebuf_pin(bp) +#define xfs_bunpin(bp) pagebuf_unpin(bp) +#define xfs_bwait_unpin(bp) pagebuf_wait_unpin(bp) + +#ifdef PAGEBUF_TRACE +#define PB_DEFINE_TRACES +#include + +#define xfs_buftrace(id, bp) PB_TRACE(bp, (void *)id) +#else +#define xfs_buftrace(id, bp) +#endif + + +#define xfs_biodone(pb) \ + pagebuf_iodone(pb) + +#define xfs_incore(buftarg,blkno,len,lockit) \ + pagebuf_find(buftarg.pb_targ, blkno<<9 ,len<<9, lockit) + + +#define xfs_biomove(pb, off, len, data, rw) \ + pagebuf_iomove((pb), (off), (len), (data), \ + ((rw) == XFS_B_WRITE) ? PBRW_READ : PBRW_WRITE) + +#define xfs_biozero(pb, off, len) \ + pagebuf_iomove((pb), (off), (len), NULL, PBRW_ZERO) + + +static inline int XFS_bwrite(page_buf_t *pb) +{ + int sync = (pb->pb_flags & PBF_ASYNC) == 0; + int error; + + pb->pb_flags |= PBF_SYNC; + + xfs_buf_undelay(pb); + + __pagebuf_iorequest(pb); + + if (sync) { + error = pagebuf_iowait(pb); + xfs_buf_relse(pb); + } else { + run_task_queue(&tq_disk); + error = 0; + } + + return error; +} + + +#define XFS_bdwrite(pb) \ + pagebuf_iostart(pb, PBF_DELWRI | PBF_ASYNC) + +static inline int xfs_bdwrite(void *mp, page_buf_t *bp) +{ + extern int xfs_bdstrat_cb(struct xfs_buf *); + + bp->pb_strat = xfs_bdstrat_cb; + bp->pb_fspriv3 = mp; + + return pagebuf_iostart(bp, PBF_DELWRI | PBF_ASYNC); +} + +#define XFS_bdstrat(bp) pagebuf_iorequest(bp) + +#define xfs_iowait(pb) \ + pagebuf_iowait(pb) + + +/* + * Go through all incore buffers, and release buffers + * if they belong to the given device. This is used in + * filesystem error handling to preserve the consistency + * of its metadata. + */ + +extern void XFS_bflush(buftarg_t); +#define xfs_binval(buftarg) XFS_bflush(buftarg) + +#define xfs_incore_relse(buftarg,delwri_only,wait) \ + pagebuf_target_clear((buftarg)->pb_targ) + + +#define xfs_baread(target, rablkno, ralen) \ + pagebuf_readahead((target)->pb_targ, (rablkno) << 9, \ + (ralen) << 9, PBF_DONT_BLOCK) + +#define XFS_getrbuf(sleep,mp) \ + pagebuf_get_empty((mp)->m_ddev_targ.pb_targ) +#define XFS_ngetrbuf(len,mp) \ + pagebuf_get_no_daddr(len,(mp)->m_ddev_targ.pb_targ) +#define XFS_freerbuf(bp) pagebuf_free(bp) +#define XFS_nfreerbuf(bp) pagebuf_free(bp) + +#endif diff -rNu linux-2.4.7/linux/fs/xfs/xfs_buf_item.c linux-2.4-xfs/linux/fs/xfs/xfs_buf_item.c --- linux-2.4.7/linux/fs/xfs/xfs_buf_item.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_buf_item.c Wed Apr 11 11:27:03 2001 @@ -0,0 +1,1380 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * This file contains the implementation of the xfs_buf_log_item. + * It contains the item operations used to manipulate the buf log + * items as well as utility routines used by the buffer specific + * transaction routines. + */ + +#include + + +#define ROUNDUPNBWORD(x) (((x) + (NBWORD - 1)) & ~(NBWORD - 1)) + +xfs_zone_t *xfs_buf_item_zone; + +#ifdef XFS_TRANS_DEBUG +/* + * This function uses an alternate strategy for tracking the bytes + * that the user requests to be logged. This can then be used + * in conjunction with the bli_orig array in the buf log item to + * catch bugs in our callers' code. + * + * We also double check the bits set in xfs_buf_item_log using a + * simple algorithm to check that every byte is accounted for. + */ +STATIC void +xfs_buf_item_log_debug( + xfs_buf_log_item_t *bip, + uint first, + uint last) +{ + uint x; + uint byte; + uint nbytes; + uint chunk_num; + uint word_num; + uint bit_num; + uint bit_set; + uint *wordp; + + ASSERT(bip->bli_logged != NULL); + byte = first; + nbytes = last - first + 1; + bfset(bip->bli_logged, first, nbytes); + for (x = 0; x < nbytes; x++) { + chunk_num = byte >> XFS_BLI_SHIFT; + word_num = chunk_num >> BIT_TO_WORD_SHIFT; + bit_num = chunk_num & (NBWORD - 1); + wordp = &(bip->bli_format.blf_data_map[word_num]); + bit_set = *wordp & (1 << bit_num); + ASSERT(bit_set); + byte++; + } +} + +/* + * This function is called when we flush something into a buffer without + * logging it. This happens for things like inodes which are logged + * separately from the buffer. + */ +void +xfs_buf_item_flush_log_debug( + xfs_buf_t *bp, + uint first, + uint last) +{ + xfs_buf_log_item_t *bip; + uint nbytes; + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + if ((bip == NULL) || (bip->bli_item.li_type != XFS_LI_BUF)) { + return; + } + + ASSERT(bip->bli_logged != NULL); + nbytes = last - first + 1; + bfset(bip->bli_logged, first, nbytes); +} + +/* + * This function is called to verify that our caller's have logged + * all the bytes that they changed. + * + * It does this by comparing the original copy of the buffer stored in + * the buf log item's bli_orig array to the current copy of the buffer + * and ensuring that all bytes which miscompare are set in the bli_logged + * array of the buf log item. + */ +STATIC void +xfs_buf_item_log_check( + xfs_buf_log_item_t *bip) +{ + char *orig; + char *buffer; + int x; + xfs_buf_t *bp; + + ASSERT(bip->bli_orig != NULL); + ASSERT(bip->bli_logged != NULL); + + bp = bip->bli_buf; + ASSERT(XFS_BUF_COUNT(bp) > 0); + ASSERT(XFS_BUF_PTR(bp) != NULL); + orig = bip->bli_orig; + buffer = XFS_BUF_PTR(bp); + for (x = 0; x < XFS_BUF_COUNT(bp); x++) { + if (orig[x] != buffer[x] && !btst(bip->bli_logged, x)) + cmn_err(CE_PANIC, + "xfs_buf_item_log_check bip %x buffer %x orig %x index %d", + bip, bp, orig, x); + } +} +#else +#define xfs_buf_item_log_debug(x,y,z) +#define xfs_buf_item_log_check(x) +#endif + +STATIC void xfs_buf_error_relse(xfs_buf_t *bp); + +/* + * This returns the number of log iovecs needed to log the + * given buf log item. + * + * It calculates this as 1 iovec for the buf log format structure + * and 1 for each stretch of non-contiguous chunks to be logged. + * Contiguous chunks are logged in a single iovec. + * + * If the XFS_BLI_STALE flag has been set, then log nothing. + */ +uint +xfs_buf_item_size( + xfs_buf_log_item_t *bip) +{ + uint nvecs; + int next_bit; + int last_bit; + xfs_buf_t *bp; + + ASSERT(atomic_read(&bip->bli_refcount) > 0); + if (bip->bli_flags & XFS_BLI_STALE) { + /* + * The buffer is stale, so all we need to log + * is the buf log format structure with the + * cancel flag in it. + */ + xfs_buf_item_trace("SIZE STALE", bip); + ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); + return 1; + } + + bp = bip->bli_buf; + ASSERT(bip->bli_flags & XFS_BLI_LOGGED); + nvecs = 1; + last_bit = xfs_buf_item_next_bit(bip->bli_format.blf_data_map, + bip->bli_format.blf_map_size, 0); + ASSERT(last_bit != -1); + nvecs++; + while (last_bit != -1) { + /* + * This takes the bit number to start looking from and + * returns the next set bit from there. It returns -1 + * if there are no more bits set or the start bit is + * beyond the end of the bitmap. + */ + next_bit = xfs_buf_item_next_bit(bip->bli_format.blf_data_map, + bip->bli_format.blf_map_size, + last_bit + 1); + /* + * If we run out of bits, leave the loop, + * else if we find a new set of bits bump the number of vecs, + * else keep scanning the current set of bits. + */ + if (next_bit == -1) { + last_bit = -1; + } else if (next_bit != last_bit + 1) { + last_bit = next_bit; + nvecs++; + } else if (xfs_buf_offset(bp, next_bit * XFS_BLI_CHUNK) != + (xfs_buf_offset(bp, last_bit * XFS_BLI_CHUNK) + + XFS_BLI_CHUNK)) { + last_bit = next_bit; + nvecs++; + } else { + last_bit++; + } + } + + xfs_buf_item_trace("SIZE NORM", bip); + return nvecs; +} + +/* + * This is called to fill in the vector of log iovecs for the + * given log buf item. It fills the first entry with a buf log + * format structure, and the rest point to contiguous chunks + * within the buffer. + */ +void +xfs_buf_item_format( + xfs_buf_log_item_t *bip, + xfs_log_iovec_t *log_vector) +{ + uint base_size; + uint nvecs; + xfs_log_iovec_t *vecp; + xfs_buf_t *bp; + int first_bit; + int last_bit; + int next_bit; + uint nbits; + uint buffer_offset; + + ASSERT(atomic_read(&bip->bli_refcount) > 0); + ASSERT((bip->bli_flags & XFS_BLI_LOGGED) || + (bip->bli_flags & XFS_BLI_STALE)); + bp = bip->bli_buf; + ASSERT(XFS_BUF_BP_ISMAPPED(bp)); + vecp = log_vector; + + /* + * The size of the base structure is the size of the + * declared structure plus the space for the extra words + * of the bitmap. We subtract one from the map size, because + * the first element of the bitmap is accounted for in the + * size of the base structure. + */ + base_size = + (uint)(sizeof(xfs_buf_log_format_t) + + ((bip->bli_format.blf_map_size - 1) * sizeof(uint))); + vecp->i_addr = (xfs_caddr_t)&bip->bli_format; + vecp->i_len = base_size; + vecp++; + nvecs = 1; + + if (bip->bli_flags & XFS_BLI_STALE) { + /* + * The buffer is stale, so all we need to log + * is the buf log format structure with the + * cancel flag in it. + */ + xfs_buf_item_trace("FORMAT STALE", bip); + ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); + bip->bli_format.blf_size = nvecs; + return; + } + + /* + * Fill in an iovec for each set of contiguous chunks. + */ + first_bit = xfs_buf_item_next_bit(bip->bli_format.blf_data_map, + bip->bli_format.blf_map_size, 0); + ASSERT(first_bit != -1); + last_bit = first_bit; + nbits = 1; + for (;;) { + /* + * This takes the bit number to start looking from and + * returns the next set bit from there. It returns -1 + * if there are no more bits set or the start bit is + * beyond the end of the bitmap. + */ + next_bit = xfs_buf_item_next_bit(bip->bli_format.blf_data_map, + bip->bli_format.blf_map_size, + (uint)last_bit + 1); + /* + * If we run out of bits fill in the last iovec and get + * out of the loop. + * Else if we start a new set of bits then fill in the + * iovec for the series we were looking at and start + * counting the bits in the new one. + * Else we're still in the same set of bits so just + * keep counting and scanning. + */ + if (next_bit == -1) { + buffer_offset = first_bit * XFS_BLI_CHUNK; + vecp->i_addr = xfs_buf_offset(bp, buffer_offset); + vecp->i_len = nbits * XFS_BLI_CHUNK; + nvecs++; + break; + } else if (next_bit != last_bit + 1) { + buffer_offset = first_bit * XFS_BLI_CHUNK; + vecp->i_addr = xfs_buf_offset(bp, buffer_offset); + vecp->i_len = nbits * XFS_BLI_CHUNK; + nvecs++; + vecp++; + first_bit = next_bit; + last_bit = next_bit; + nbits = 1; + } else if (xfs_buf_offset(bp, next_bit * XFS_BLI_CHUNK) != + (xfs_buf_offset(bp, last_bit * XFS_BLI_CHUNK) + + XFS_BLI_CHUNK)) { + buffer_offset = first_bit * XFS_BLI_CHUNK; + vecp->i_addr = xfs_buf_offset(bp, buffer_offset); + vecp->i_len = nbits * XFS_BLI_CHUNK; + nvecs++; + vecp++; + first_bit = next_bit; + last_bit = next_bit; + } else { + last_bit++; + nbits++; + } + } + bip->bli_format.blf_size = nvecs; + + /* + * Check to make sure everything is consistent. + */ + xfs_buf_item_trace("FORMAT NORM", bip); + xfs_buf_item_log_check(bip); +} + +/* + * This is called to pin the buffer associated with the buf log + * item in memory so it cannot be written out. Simply call bpin() + * on the buffer to do this. + */ +void +xfs_buf_item_pin( + xfs_buf_log_item_t *bip) +{ + xfs_buf_t *bp; + + bp = bip->bli_buf; + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + ASSERT((bip->bli_flags & XFS_BLI_LOGGED) || + (bip->bli_flags & XFS_BLI_STALE)); + xfs_buf_item_trace("PIN", bip); + xfs_buftrace("XFS_PIN", bp); + xfs_bpin(bp); +} + + +/* + * This is called to unpin the buffer associated with the buf log + * item which was previously pinned with a call to xfs_buf_item_pin(). + * Just call bunpin() on the buffer to do this. + * + * Also drop the reference to the buf item for the current transaction. + * If the XFS_BLI_STALE flag is set and we are the last reference, + * then free up the buf log item and unlock the buffer. + */ +void +xfs_buf_item_unpin( + xfs_buf_log_item_t *bip) +{ + xfs_mount_t *mp; + xfs_buf_t *bp; + int freed; + SPLDECL(s); + + bp = bip->bli_buf; + ASSERT(bp != NULL); + ASSERT(XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *) == bip); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + xfs_buf_item_trace("UNPIN", bip); + xfs_buftrace("XFS_UNPIN", bp); + + freed = atomic_dec_and_test(&bip->bli_refcount); + mp = bip->bli_item.li_mountp; + xfs_bunpin(bp); + if (freed && (bip->bli_flags & XFS_BLI_STALE)) { + ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); + ASSERT(!(XFS_BUF_ISDELAYWRITE(bp))); + ASSERT(XFS_BUF_ISSTALE(bp)); +/** + ASSERT(bp->b_pincount == 0); +**/ + ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); + xfs_buf_item_trace("UNPIN STALE", bip); + xfs_buftrace("XFS_UNPIN STALE", bp); + AIL_LOCK(mp,s); + /* + * If we get called here because of an IO error, we may + * or may not have the item on the AIL. xfs_trans_delete_ail() + * will take care of that situation. + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip, s); + xfs_buf_item_relse(bp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL); + xfs_buf_relse(bp); + } + +} + +/* + * this is called from uncommit in the forced-shutdown path. + * we need to check to see if the reference count on the log item + * is going to drop to zero. If so, unpin will free the log item + * so we need to free the item's descriptor (that points to the item) + * in the transaction. + */ +void +xfs_buf_item_unpin_remove( + xfs_buf_log_item_t *bip, + xfs_trans_t *tp) +{ + /* REFERENCED */ + xfs_buf_t *bp; + xfs_log_item_desc_t *lidp; + + bp = bip->bli_buf; + /* + * will xfs_buf_item_unpin() call xfs_buf_item_relse()? + */ + if ((atomic_read(&bip->bli_refcount) == 1) && + (bip->bli_flags & XFS_BLI_STALE)) { + ASSERT(XFS_BUF_VALUSEMA(bip->bli_buf) <= 0); + xfs_buf_item_trace("UNPIN REMOVE", bip); + xfs_buftrace("XFS_UNPIN_REMOVE", bp); + /* + * yes -- clear the xaction descriptor in-use flag + * and free the chunk if required. We can safely + * do some work here and then call buf_item_unpin + * to do the rest because if the if is true, then + * we are holding the buffer locked so no one else + * will be able to bump up the refcount. + */ + lidp = xfs_trans_find_item(tp, (xfs_log_item_t *) bip); + xfs_trans_free_item(tp, lidp); + /* + * Since the transaction no longer refers to the buffer, + * the buffer should no longer refer to the transaction. + */ + XFS_BUF_SET_FSPRIVATE2(bp, NULL); + } + + xfs_buf_item_unpin(bip); + + return; +} + +/* + * This is called to attempt to lock the buffer associated with this + * buf log item. Don't sleep on the buffer lock. If we can't get + * the lock right away, return 0. If we can get the lock, pull the + * buffer from the free list, mark it busy, and return 1. + */ +uint +xfs_buf_item_trylock( + xfs_buf_log_item_t *bip) +{ + xfs_buf_t *bp; + + bp = bip->bli_buf; + + if (XFS_BUF_ISPINNED(bp)) { + return XFS_ITEM_PINNED; + } + + if (!XFS_BUF_CPSEMA(bp)) { + return XFS_ITEM_LOCKED; + } + + /* + * Remove the buffer from the free list. Only do this + * if it's on the free list. Private buffers like the + * superblock buffer are not. + */ + XFS_BUF_HOLD(bp); + + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + xfs_buf_item_trace("TRYLOCK SUCCESS", bip); + return XFS_ITEM_SUCCESS; +} + +/* + * Release the buffer associated with the buf log item. + * If there is no dirty logged data associated with the + * buffer recorded in the buf log item, then free the + * buf log item and remove the reference to it in the + * buffer. + * + * This call ignores the recursion count. It is only called + * when the buffer should REALLY be unlocked, regardless + * of the recursion count. + * + * If the XFS_BLI_HOLD flag is set in the buf log item, then + * free the log item if necessary but do not unlock the buffer. + * This is for support of xfs_trans_bhold(). Make sure the + * XFS_BLI_HOLD field is cleared if we don't free the item. + */ +void +xfs_buf_item_unlock( + xfs_buf_log_item_t *bip) +{ + int aborted; + xfs_buf_t *bp; + uint hold; + + bp = bip->bli_buf; + xfs_buftrace("XFS_UNLOCK", bp); + + /* + * Clear the buffer's association with this transaction. + */ + XFS_BUF_SET_FSPRIVATE2(bp, NULL); + + /* + * If this is a transaction abort, don't return early. + * Instead, allow the brelse to happen. + * Normally it would be done for stale (cancelled) buffers + * at unpin time, but we'll never go through the pin/unpin + * cycle if we abort inside commit. + */ + aborted = (bip->bli_item.li_flags & XFS_LI_ABORTED) != 0; + + /* + * If the buf item is marked stale, then don't do anything. + * We'll unlock the buffer and free the buf item when the + * buffer is unpinned for the last time. + */ + if (bip->bli_flags & XFS_BLI_STALE) { + bip->bli_flags &= ~XFS_BLI_LOGGED; + xfs_buf_item_trace("UNLOCK STALE", bip); + ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); + if (!aborted) + return; + } + + /* + * Drop the transaction's reference to the log item if + * it was not logged as part of the transaction. Otherwise + * we'll drop the reference in xfs_buf_item_unpin() when + * the transaction is really through with the buffer. + */ + if (!(bip->bli_flags & XFS_BLI_LOGGED)) { + atomic_dec(&bip->bli_refcount); + } else { + /* + * Clear the logged flag since this is per + * transaction state. + */ + bip->bli_flags &= ~XFS_BLI_LOGGED; + } + + /* + * Before possibly freeing the buf item, determine if we should + * release the buffer at the end of this routine. + */ + hold = bip->bli_flags & XFS_BLI_HOLD; + xfs_buf_item_trace("UNLOCK", bip); + + /* + * If the buf item isn't tracking any data, free it. + * Otherwise, if XFS_BLI_HOLD is set clear it. + */ + if (xfs_buf_item_bits(bip->bli_format.blf_data_map, + bip->bli_format.blf_map_size, 0) == 0) { + xfs_buf_item_relse(bp); + } else if (hold) { + bip->bli_flags &= ~XFS_BLI_HOLD; + } + + /* + * Release the buffer if XFS_BLI_HOLD was not set. + */ + if (!hold) { + xfs_buf_relse(bp); + } +} + +/* + * This is called to find out where the oldest active copy of the + * buf log item in the on disk log resides now that the last log + * write of it completed at the given lsn. + * We always re-log all the dirty data in a buffer, so usually the + * latest copy in the on disk log is the only one that matters. For + * those cases we simply return the given lsn. + * + * The one exception to this is for buffers full of newly allocated + * inodes. These buffers are only relogged with the XFS_BLI_INODE_BUF + * flag set, indicating that only the di_next_unlinked fields from the + * inodes in the buffers will be replayed during recovery. If the + * original newly allocated inode images have not yet been flushed + * when the buffer is so relogged, then we need to make sure that we + * keep the old images in the 'active' portion of the log. We do this + * by returning the original lsn of that transaction here rather than + * the current one. + */ +xfs_lsn_t +xfs_buf_item_committed( + xfs_buf_log_item_t *bip, + xfs_lsn_t lsn) +{ + xfs_buf_item_trace("COMMITTED", bip); + if ((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) && + (bip->bli_item.li_lsn != 0)) { + return bip->bli_item.li_lsn; + } + return (lsn); +} + +/* + * This is called when the transaction holding the buffer is aborted. + * Just behave as if the transaction had been cancelled. If we're shutting down + * and have aborted this transaction, we'll trap this buffer when it tries to + * get written out. + */ +void +xfs_buf_item_abort( + xfs_buf_log_item_t *bip) +{ + xfs_buf_t *bp; + + bp = bip->bli_buf; + xfs_buftrace("XFS_ABORT", bp); + XFS_BUF_SUPER_STALE(bp); + xfs_buf_item_unlock(bip); + return; +} + +/* + * This is called to asynchronously write the buffer associated with this + * buf log item out to disk. The buffer will already have been locked by + * a successful call to xfs_buf_item_trylock(). If the buffer still has + * B_DELWRI set, then get it going out to disk with a call to bawrite(). + * If not, then just release the buffer. + */ +void +xfs_buf_item_push( + xfs_buf_log_item_t *bip) +{ + xfs_buf_t *bp; + + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + xfs_buf_item_trace("PUSH", bip); + + bp = bip->bli_buf; + + if (XFS_BUF_ISDELAYWRITE(bp)) { + xfs_bawrite(bip->bli_item.li_mountp, bp); + } else { + xfs_buf_relse(bp); + } +} + +/* ARGSUSED */ +void +xfs_buf_item_committing(xfs_buf_log_item_t *bip, xfs_lsn_t commit_lsn) +{ +} + +/* + * This is the ops vector shared by all buf log items. + */ +struct xfs_item_ops xfs_buf_item_ops = { + iop_size: (uint(*)(xfs_log_item_t*))xfs_buf_item_size, + iop_format: (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) + xfs_buf_item_format, + iop_pin: (void(*)(xfs_log_item_t*))xfs_buf_item_pin, + iop_unpin: (void(*)(xfs_log_item_t*))xfs_buf_item_unpin, + iop_unpin_remove: (void(*)(xfs_log_item_t*, xfs_trans_t *)) + xfs_buf_item_unpin_remove, + iop_trylock: (uint(*)(xfs_log_item_t*))xfs_buf_item_trylock, + iop_unlock: (void(*)(xfs_log_item_t*))xfs_buf_item_unlock, + iop_committed: (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_buf_item_committed, + iop_push: (void(*)(xfs_log_item_t*))xfs_buf_item_push, + iop_abort: (void(*)(xfs_log_item_t*))xfs_buf_item_abort, + iop_pushbuf: NULL, + iop_committing: (void(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_buf_item_committing +}; + + +/* + * Allocate a new buf log item to go with the given buffer. + * Set the buffer's b_fsprivate field to point to the new + * buf log item. If there are other item's attached to the + * buffer (see xfs_buf_attach_iodone() below), then put the + * buf log item at the front. + */ +void +xfs_buf_item_init( + xfs_buf_t *bp, + xfs_mount_t *mp) +{ + xfs_log_item_t *lip; + xfs_buf_log_item_t *bip; + int chunks; + int map_size; + + /* + * Check to see if there is already a buf log item for + * this buffer. If there is, it is guaranteed to be + * the first. If we do already have one, there is + * nothing to do here so return. + */ + if (XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *) != mp) + XFS_BUF_SET_FSPRIVATE3(bp, mp); + XFS_BUF_SET_BDSTRAT_FUNC(bp, xfs_bdstrat_cb); + if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) { + lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); + if (lip->li_type == XFS_LI_BUF) { + return; + } + } + + /* + * chunks is the number of XFS_BLI_CHUNK size pieces + * the buffer can be divided into. Make sure not to + * truncate any pieces. map_size is the size of the + * bitmap needed to describe the chunks of the buffer. + */ + chunks = (int)((XFS_BUF_COUNT(bp) + (XFS_BLI_CHUNK - 1)) >> XFS_BLI_SHIFT); + map_size = (int)((chunks + NBWORD) >> BIT_TO_WORD_SHIFT); + + bip = (xfs_buf_log_item_t*)kmem_zone_zalloc(xfs_buf_item_zone, + KM_SLEEP); + bip->bli_item.li_type = XFS_LI_BUF; + bip->bli_item.li_ops = &xfs_buf_item_ops; + bip->bli_item.li_mountp = mp; + bip->bli_buf = bp; + bip->bli_format.blf_type = XFS_LI_BUF; + bip->bli_format.blf_blkno = (__int64_t)XFS_BUF_ADDR(bp); + bip->bli_format.blf_len = (ushort)BTOBB(XFS_BUF_COUNT(bp)); + bip->bli_format.blf_map_size = map_size; +#ifdef XFS_BLI_TRACE + bip->bli_trace = ktrace_alloc(XFS_BLI_TRACE_SIZE, KM_SLEEP); +#endif + +#ifdef XFS_TRANS_DEBUG + /* + * Allocate the arrays for tracking what needs to be logged + * and what our callers request to be logged. bli_orig + * holds a copy of the original, clean buffer for comparison + * against, and bli_logged keeps a 1 bit flag per byte in + * the buffer to indicate which bytes the callers have asked + * to have logged. + */ + bip->bli_orig = (char *)kmem_alloc(XFS_BUF_COUNT(bp), KM_SLEEP); + bcopy(XFS_BUF_PTR(bp), bip->bli_orig, XFS_BUF_COUNT(bp)); + bip->bli_logged = (char *)kmem_zalloc(XFS_BUF_COUNT(bp) / NBBY, KM_SLEEP); +#endif + + /* + * Put the buf item into the list of items attached to the + * buffer at the front. + */ + if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) { + bip->bli_item.li_bio_list = + XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); + } + XFS_BUF_SET_FSPRIVATE(bp, bip); +} + + +/* + * Mark bytes first through last inclusive as dirty in the buf + * item's bitmap. + */ +void +xfs_buf_item_log( + xfs_buf_log_item_t *bip, + uint first, + uint last) +{ + uint first_bit; + uint last_bit; + uint bits_to_set; + uint bits_set; + uint word_num; + uint *wordp; + uint bit; + uint end_bit; + uint mask; + + /* + * Mark the item as having some dirty data for + * quick reference in xfs_buf_item_dirty. + */ + bip->bli_flags |= XFS_BLI_DIRTY; + + /* + * Convert byte offsets to bit numbers. + */ + first_bit = first >> XFS_BLI_SHIFT; + last_bit = last >> XFS_BLI_SHIFT; + + /* + * Calculate the total number of bits to be set. + */ + bits_to_set = last_bit - first_bit + 1; + + /* + * Get a pointer to the first word in the bitmap + * to set a bit in. + */ + word_num = first_bit >> BIT_TO_WORD_SHIFT; + wordp = &(bip->bli_format.blf_data_map[word_num]); + + /* + * Calculate the starting bit in the first word. + */ + bit = first_bit & (uint)(NBWORD - 1); + + /* + * First set any bits in the first word of our range. + * If it starts at bit 0 of the word, it will be + * set below rather than here. That is what the variable + * bit tells us. The variable bits_set tracks the number + * of bits that have been set so far. End_bit is the number + * of the last bit to be set in this word plus one. + */ + if (bit) { + end_bit = MIN(bit + bits_to_set, (uint)NBWORD); + mask = ((1 << (end_bit - bit)) - 1) << bit; + *wordp |= mask; + wordp++; + bits_set = end_bit - bit; + } else { + bits_set = 0; + } + + /* + * Now set bits a whole word at a time that are between + * first_bit and last_bit. + */ + while ((bits_to_set - bits_set) >= NBWORD) { + *wordp |= 0xffffffff; + bits_set += NBWORD; + wordp++; + } + + /* + * Finally, set any bits left to be set in one last partial word. + */ + end_bit = bits_to_set - bits_set; + if (end_bit) { + mask = (1 << end_bit) - 1; + *wordp |= mask; + } + + xfs_buf_item_log_debug(bip, first, last); +} + + +/* + * Count the number of bits set in the bitmap starting with bit + * start_bit. Size is the size of the bitmap in words. + * + * Do the counting by mapping a byte value to the number of set + * bits for that value using the xfs_countbit array, i.e. + * xfs_countbit[0] == 0, xfs_countbit[1] == 1, xfs_countbit[2] == 1, + * xfs_countbit[3] == 2, etc. + */ +int +xfs_buf_item_bits( + uint *map, + uint size, + uint start_bit) +{ + register int bits; + register unsigned char *bytep; + register unsigned char *end_map; + int byte_bit; + + bits = 0; + end_map = (char*)(map + size); + bytep = (char*)(map + (start_bit & ~0x7)); + byte_bit = start_bit & 0x7; + + /* + * If the caller fell off the end of the map, return 0. + */ + if (bytep >= end_map) { + return (0); + } + + /* + * If start_bit is not byte aligned, then process the + * first byte separately. + */ + if (byte_bit != 0) { + /* + * Shift off the bits we don't want to look at, + * before indexing into xfs_countbit. + */ + bits += xfs_countbit[(*bytep >> byte_bit)]; + bytep++; + } + + /* + * Count the bits in each byte until the end of the bitmap. + */ + while (bytep < end_map) { + bits += xfs_countbit[*bytep]; + bytep++; + } + + return (bits); +} /* xfs_buf_item_bits */ + +/* + * Count the number of contiguous bits set in the bitmap starting with bit + * start_bit. Size is the size of the bitmap in words. + * + * Do the counting by mapping a byte value to the number of set + * bits for that value using the xfs_countbit array, i.e. + */ +int +xfs_buf_item_contig_bits( + uint *map, + uint size, + uint start_bit) +{ + register int bits; + register uint *wordp; + register uint cwordp; + register uint *end_map; + int word_bit; + int cnt; + + bits = 0; + end_map = (uint *)(map + size); + wordp = (uint *)(map + (start_bit >> 5)); + word_bit = start_bit & 0x1F; + + /* + * If the caller fell off the end of the map, return 0. + */ + if (wordp >= end_map) { + return (0); + } + + /* + * If start_bit is not byte aligned, then process just the + * relevant bits. + */ + if (word_bit != 0) { + cwordp = *wordp >> word_bit; + } else { + cwordp = *wordp; + word_bit = 0; + } + + /* + * Count the bits in each byte until the end of the bitmap. + */ + while (wordp < end_map) { + /* + * Cycle through bits left in word. If the low bit is + * set, we've found a 'contingous' bit. + */ + for (cnt = (int)(sizeof(int)*NBBY-word_bit); cnt > 0; cnt--) { + if (cwordp & 0x1) + bits++; + else + return bits; + cwordp >>= 1; + } + + /* Grab another word */ + wordp++; + cwordp = *wordp; + word_bit = 0; + } + + return (bits); +} /* xfs_buf_item_contig_bits */ + +/* + * This takes the bit number to start looking from and + * returns the next set bit from there. It returns -1 + * if there are no more bits set or the start bit is + * beyond the end of the bitmap. + * + * Size is the number of words, not bytes, in the bitmap. + */ +int +xfs_buf_item_next_bit( + uint *map, + uint size, + uint start_bit) +{ + uint * p = ((unsigned int *) map) + (start_bit >> BIT_TO_WORD_SHIFT); + uint result = start_bit & ~(NBWORD - 1); + uint tmp; + + size <<= BIT_TO_WORD_SHIFT; + + if (start_bit >= size) + return -1; + size -= result; + start_bit &= (NBWORD - 1); + if (start_bit) { + tmp = *p++; + /* set to zero first offset bits */ + tmp &= ~(~0UL >> (NBWORD-start_bit)); + if (size < NBWORD) + goto found_first; + if (tmp != 0U) + goto found_middle; + size -= NBWORD; + result += NBWORD; + } + while (size >= NBWORD) { + if ((tmp = *p++) != 0U) + goto found_middle; + result += NBWORD; + size -= NBWORD; + } + if (!size) + return -1; + tmp = *p; +found_first: +found_middle: + return result + ffs(tmp) - 1; +} + +/* + * Return 1 if the buffer has some data that has been logged (at any + * point, not just the current transaction) and 0 if not. + */ +uint +xfs_buf_item_dirty( + xfs_buf_log_item_t *bip) +{ + return (bip->bli_flags & XFS_BLI_DIRTY); +} + +/* + * This is called when the buf log item is no longer needed. It should + * free the buf log item associated with the given buffer and clear + * the buffer's pointer to the buf log item. If there are no more + * items in the list, clear the b_iodone field of the buffer (see + * xfs_buf_attach_iodone() below). + */ +void +xfs_buf_item_relse( + xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + + xfs_buftrace("XFS_RELSE", bp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + XFS_BUF_SET_FSPRIVATE(bp, bip->bli_item.li_bio_list); + if ((XFS_BUF_FSPRIVATE(bp, void *) == NULL) && + (XFS_BUF_IODONE_FUNC(bp) != NULL)) { +/** + ASSERT((XFS_BUF_ISUNINITIAL(bp)) == 0); +***/ + XFS_BUF_CLR_IODONE_FUNC(bp); + } + +#ifdef XFS_TRANS_DEBUG + kmem_free(bip->bli_orig, XFS_BUF_COUNT(bp)); + bip->bli_orig = NULL; + kmem_free(bip->bli_logged, XFS_BUF_COUNT(bp) / NBBY); + bip->bli_logged = NULL; +#endif /* XFS_TRANS_DEBUG */ + +#ifdef XFS_BLI_TRACE + ktrace_free(bip->bli_trace); +#endif + kmem_zone_free(xfs_buf_item_zone, bip); +} + + +/* + * Add the given log item with it's callback to the list of callbacks + * to be called when the buffer's I/O completes. If it is not set + * already, set the buffer's b_iodone() routine to be + * xfs_buf_iodone_callbacks() and link the log item into the list of + * items rooted at b_fsprivate. Items are always added as the second + * entry in the list if there is a first, because the buf item code + * assumes that the buf log item is first. + */ +void +xfs_buf_attach_iodone( + xfs_buf_t *bp, + void (*cb)(xfs_buf_t *, xfs_log_item_t *), + xfs_log_item_t *lip) +{ + xfs_log_item_t *head_lip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); + + lip->li_cb = cb; + if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) { + head_lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); + lip->li_bio_list = head_lip->li_bio_list; + head_lip->li_bio_list = lip; + } else { + XFS_BUF_SET_FSPRIVATE(bp, lip); + } + + ASSERT((XFS_BUF_IODONE_FUNC(bp) == xfs_buf_iodone_callbacks) || + (XFS_BUF_IODONE_FUNC(bp) == NULL)); + XFS_BUF_SET_IODONE_FUNC(bp, xfs_buf_iodone_callbacks); +} + +STATIC void +xfs_buf_do_callbacks( + xfs_buf_t *bp, + xfs_log_item_t *lip) +{ + xfs_log_item_t *nlip; + + while (lip != NULL) { + nlip = lip->li_bio_list; + ASSERT(lip->li_cb != NULL); + /* + * Clear the next pointer so we don't have any + * confusion if the item is added to another buf. + * Don't touch the log item after calling its + * callback, because it could have freed itself. + */ + lip->li_bio_list = NULL; + lip->li_cb(bp, lip); + lip = nlip; + } +} + +/* + * This is the iodone() function for buffers which have had callbacks + * attached to them by xfs_buf_attach_iodone(). It should remove each + * log item from the buffer's list and call the callback of each in turn. + * When done, the buffer's fsprivate field is set to NULL and the buffer + * is unlocked with a call to iodone(). + */ +void +xfs_buf_iodone_callbacks( + xfs_buf_t *bp) +{ + xfs_log_item_t *lip; + static time_t lasttime; + static dev_t lastdev; + xfs_mount_t *mp; + + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); + + if (XFS_BUF_GETERROR(bp) != 0) { + /* + * If we've already decided to shutdown the filesystem + * because of IO errors, there's no point in giving this + * a retry. + */ + mp = lip->li_mountp; + if (XFS_FORCED_SHUTDOWN(mp)) { + ASSERT(XFS_BUF_TARGET(bp) == mp->m_dev); + XFS_BUF_SUPER_STALE(bp); + xfs_buftrace("BUF_IODONE_CB", bp); + xfs_buf_do_callbacks(bp, lip); + XFS_BUF_SET_FSPRIVATE(bp, NULL); + XFS_BUF_CLR_IODONE_FUNC(bp); + + /* + * XFS_SHUT flag gets set when we go thru the + * entire buffer cache and deliberately start + * throwing away delayed write buffers. + * Since there's no biowait done on those, + * we should just brelse them. + */ + if (XFS_BUF_ISSHUT(bp)) { + XFS_BUF_UNSHUT(bp); + xfs_buf_relse(bp); + } else { + int flags = XFS_BUF_ISASYNC(bp); + + xfs_biodone(bp); + if(!flags) { + xfs_buf_relse(bp); + } + } + + return; + } + + if ((XFS_BUF_TARGET(bp) != lastdev) || + ((lbolt - lasttime) > 500)) { + prdev("XFS write error in file system meta-data " + "block 0x%Lx in %s", + (int)XFS_BUF_TARGET(bp), XFS_BUF_ADDR(bp), + mp->m_fsname); + lasttime = lbolt; + } + lastdev = XFS_BUF_TARGET(bp); + + if (XFS_BUF_ISASYNC(bp)) { + /* + * If the write was asynchronous then noone will be + * looking for the error. Clear the error state + * and write the buffer out again delayed write. + * + * XXXsup This is OK, so long as we catch these + * before we start the umount; we don't want these + * DELWRI metadata bufs to be hanging around. + */ + XFS_BUF_ERROR(bp,0); /* errno of 0 unsets the flag */ + + if (!(XFS_BUF_ISSTALE(bp))) { + XFS_BUF_DELAYWRITE(bp); + XFS_BUF_DONE(bp); + XFS_BUF_SET_START(bp); + } + ASSERT(XFS_BUF_IODONE_FUNC(bp)); + xfs_buftrace("BUF_IODONE ASYNC", bp); + xfs_buf_relse(bp); + } else { + /* + * If the write of the buffer was not asynchronous, + * then we want to make sure to return the error + * to the caller of bwrite(). Because of this we + * cannot clear the B_ERROR state at this point. + * Instead we install a callback function that + * will be called when the buffer is released, and + * that routine will clear the error state and + * set the buffer to be written out again after + * some delay. + */ + /* We actually overwrite the existing b-relse + function at times, but we're gonna be shutting down + anyway. */ + XFS_BUF_SET_BRELSE_FUNC(bp,xfs_buf_error_relse); + XFS_BUF_DONE(bp); + XFS_BUF_V_IODONESEMA(bp); + } + return; + } +#ifdef XFSERRORDEBUG + xfs_buftrace("XFS BUFCB NOERR", bp); +#endif + xfs_buf_do_callbacks(bp, lip); + XFS_BUF_SET_FSPRIVATE(bp, NULL); + XFS_BUF_CLR_IODONE_FUNC(bp); + xfs_biodone(bp); +} + +/* + * This is a callback routine attached to a buffer which gets an error + * when being written out synchronously. + */ +STATIC void +xfs_buf_error_relse( + xfs_buf_t *bp) +{ + xfs_log_item_t *lip; + xfs_mount_t *mp; + + lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); + mp = (xfs_mount_t *)lip->li_mountp; + ASSERT(XFS_BUF_TARGET(bp) == mp->m_dev); + + XFS_BUF_STALE(bp); + XFS_BUF_DONE(bp); + XFS_BUF_UNDELAYWRITE(bp); + XFS_BUF_ERROR(bp,0); + xfs_buftrace("BUF_ERROR_RELSE", bp); + if (! XFS_FORCED_SHUTDOWN(mp)) + xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR); + /* + * We have to unpin the pinned buffers so do the + * callbacks. + */ + xfs_buf_do_callbacks(bp, lip); + XFS_BUF_SET_FSPRIVATE(bp, NULL); + XFS_BUF_CLR_IODONE_FUNC(bp); + XFS_BUF_SET_BRELSE_FUNC(bp,NULL); + xfs_buf_relse(bp); + return; + +} + + +/* + * This is the iodone() function for buffers which have been + * logged. It is called when they are eventually flushed out. + * It should remove the buf item from the AIL, and free the buf item. + * It is called by xfs_buf_iodone_callbacks() above which will take + * care of cleaning up the buffer itself. + */ +/* ARGSUSED */ +void +xfs_buf_iodone( + xfs_buf_t *bp, + xfs_buf_log_item_t *bip) +{ + struct xfs_mount *mp; + SPLDECL(s); + + ASSERT(bip->bli_buf == bp); + + mp = bip->bli_item.li_mountp; + + /* + * If we are forcibly shutting down, this may well be + * off the AIL already. That's because we simulate the + * log-committed callbacks to unpin these buffers. Or we may never + * have put this item on AIL because of the transaction was + * aborted forcibly. xfs_trans_delete_ail() takes care of these. + * + * Either way, AIL is useless if we're forcing a shutdown. + */ + AIL_LOCK(mp,s); + /* + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip, s); + +#ifdef XFS_TRANS_DEBUG + kmem_free(bip->bli_orig, XFS_BUF_COUNT(bp)); + bip->bli_orig = NULL; + kmem_free(bip->bli_logged, XFS_BUF_COUNT(bp) / NBBY); + bip->bli_logged = NULL; +#endif /* XFS_TRANS_DEBUG */ + +#ifdef XFS_BLI_TRACE + ktrace_free(bip->bli_trace); +#endif + kmem_zone_free(xfs_buf_item_zone, bip); +} + +#if defined(XFS_BLI_TRACE) +void +xfs_buf_item_trace( + char *id, + xfs_buf_log_item_t *bip) +{ + xfs_buf_t *bp; + ASSERT(bip->bli_trace != NULL); + + bp = bip->bli_buf; + ktrace_enter(bip->bli_trace, + (void *)id, + (void *)bip->bli_buf, + (void *)((unsigned long)bip->bli_flags), + (void *)((unsigned long)bip->bli_recur), + (void *)((unsigned long)atomic_read(&bip->bli_refcount)), + (void *)XFS_BUF_ADDR(bp), + (void *)((unsigned long)XFS_BUF_COUNT(bp)), + (void *)((unsigned long)(0xFFFFFFFF & (XFS_BFLAGS(bp) >> 32))), + (void *)((unsigned long)(0xFFFFFFFF & XFS_BFLAGS(bp))), + XFS_BUF_FSPRIVATE(bp, void *), + XFS_BUF_FSPRIVATE2(bp, void *), + (void *)((unsigned long)bp->b_pincount), + (void *)XFS_BUF_IODONE_FUNC(bp), + (void *)((unsigned long)(XFS_BUF_VALUSEMA(bp))), + (void *)bip->bli_item.li_desc, + (void *)((unsigned long)bip->bli_item.li_flags)); +} +#endif /* XFS_BLI_TRACE */ + + diff -rNu linux-2.4.7/linux/fs/xfs/xfs_buf_item.h linux-2.4-xfs/linux/fs/xfs/xfs_buf_item.h --- linux-2.4.7/linux/fs/xfs/xfs_buf_item.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_buf_item.h Mon Apr 2 21:52:38 2001 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_BUF_ITEM_H__ +#define __XFS_BUF_ITEM_H__ + +/* + * This is the structure used to lay out a buf log item in the + * log. The data map describes which 128 byte chunks of the buffer + * have been logged. This structure works only on buffers that + * reside up to the first TB in the filesystem. These buffers are + * generated only by pre-6.2 systems and are known as XFS_LI_6_1_BUF. + */ +typedef struct xfs_buf_log_format_v1 { + unsigned short blf_type; /* buf log item type indicator */ + unsigned short blf_size; /* size of this item */ + __int32_t blf_blkno; /* starting blkno of this buf */ + ushort blf_flags; /* misc state */ + ushort blf_len; /* number of blocks in this buf */ + unsigned int blf_map_size; /* size of data bitmap in words */ + unsigned int blf_data_map[1];/* variable size bitmap of */ + /* regions of buffer in this item */ +} xfs_buf_log_format_v1_t; + +/* + * This is a form of the above structure with a 64 bit blkno field. + * For 6.2 and beyond, this is XFS_LI_BUF. We use this to log everything. + */ +typedef struct xfs_buf_log_format_t { + unsigned short blf_type; /* buf log item type indicator */ + unsigned short blf_size; /* size of this item */ + ushort blf_flags; /* misc state */ + ushort blf_len; /* number of blocks in this buf */ + __int64_t blf_blkno; /* starting blkno of this buf */ + unsigned int blf_map_size; /* size of data bitmap in words */ + unsigned int blf_data_map[1];/* variable size bitmap of */ + /* regions of buffer in this item */ +} xfs_buf_log_format_t; + +/* + * This flag indicates that the buffer contains on disk inodes + * and requires special recovery handling. + */ +#define XFS_BLI_INODE_BUF 0x1 +/* + * This flag indicates that the buffer should not be replayed + * during recovery because its blocks are being freed. + */ +#define XFS_BLI_CANCEL 0x2 +/* + * This flag indicates that the buffer contains on disk + * user or group dquots and may require special recovery handling. + */ +#define XFS_BLI_UDQUOT_BUF 0x4 +/* #define XFS_BLI_PDQUOT_BUF 0x8 */ +#define XFS_BLI_GDQUOT_BUF 0x10 + +#define XFS_BLI_CHUNK 128 +#define XFS_BLI_SHIFT 7 +#define BIT_TO_WORD_SHIFT 5 +#define NBWORD (NBBY * sizeof(unsigned int)) + +/* + * buf log item flags + */ +#define XFS_BLI_HOLD 0x01 +#define XFS_BLI_DIRTY 0x02 +#define XFS_BLI_STALE 0x04 +#define XFS_BLI_LOGGED 0x08 +#define XFS_BLI_INODE_ALLOC_BUF 0x10 + + +#ifdef __KERNEL__ + +struct xfs_buf; +struct ktrace; +struct xfs_mount; + +/* + * This is the in core log item structure used to track information + * needed to log buffers. It tracks how many times the lock has been + * locked, and which 128 byte chunks of the buffer are dirty. + */ +typedef struct xfs_buf_log_item { + xfs_log_item_t bli_item; /* common item structure */ + struct xfs_buf *bli_buf; /* real buffer pointer */ + unsigned int bli_flags; /* misc flags */ + unsigned int bli_recur; /* lock recursion count */ + atomic_t bli_refcount; /* cnt of tp refs */ +#ifdef DEBUG + struct ktrace *bli_trace; /* event trace buf */ +#endif +#ifdef XFS_TRANS_DEBUG + char *bli_orig; /* original buffer copy */ + char *bli_logged; /* bytes logged (bitmap) */ +#endif + xfs_buf_log_format_t bli_format; /* in-log header */ +} xfs_buf_log_item_t; + +/* + * This structure is used during recovery to record the buf log + * items which have been canceled and should not be replayed. + */ +typedef struct xfs_buf_cancel { + xfs_daddr_t bc_blkno; + uint bc_len; + int bc_refcount; + struct xfs_buf_cancel *bc_next; +} xfs_buf_cancel_t; + +#define XFS_BLI_TRACE_SIZE 32 + + +#if defined(XFS_ALL_TRACE) +#define XFS_BLI_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_BLI_TRACE +#endif + +#if defined(XFS_BLI_TRACE) +void xfs_buf_item_trace(char *, xfs_buf_log_item_t *); +#else +#define xfs_buf_item_trace(id, bip) +#endif + +void xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *); +void xfs_buf_item_relse(struct xfs_buf *); +void xfs_buf_item_log(xfs_buf_log_item_t *, uint, uint); +uint xfs_buf_item_dirty(xfs_buf_log_item_t *); +int xfs_buf_item_bits(uint *, uint, uint); +int xfs_buf_item_contig_bits(uint *, uint, uint); +int xfs_buf_item_next_bit(uint *, uint, uint); +void xfs_buf_attach_iodone(struct xfs_buf *, + void(*)(struct xfs_buf *, xfs_log_item_t *), + xfs_log_item_t *); +void xfs_buf_iodone_callbacks(struct xfs_buf *); +void xfs_buf_iodone(struct xfs_buf *, xfs_buf_log_item_t *); + +#ifdef XFS_TRANS_DEBUG +void +xfs_buf_item_flush_log_debug( + struct xfs_buf *bp, + uint first, + uint last); +#else +#define xfs_buf_item_flush_log_debug(bp, first, last) +#endif + +#endif /* __KERNEL__ */ + +#endif /* __XFS_BUF_ITEM_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_clnt.h linux-2.4-xfs/linux/fs/xfs/xfs_clnt.h --- linux-2.4.7/linux/fs/xfs/xfs_clnt.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_clnt.h Fri Jun 29 17:29:47 2001 @@ -0,0 +1,226 @@ +/* + * * + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_CLNT_H__ +#define __XFS_CLNT_H__ + +/* + * XFS arguments to the mount system call. + */ +struct xfs_args { + + /* + * These items common to all versions. + */ + int version; /* version of this */ + /* 1, see xfs_args_ver_1 */ + /* 2, see xfs_args_ver_2 */ + /* 3, see xfs_args_ver_3 */ + /* 4, see xfs_args_ver_4 */ + int flags; /* flags, see XFSMNT_... below */ + int logbufs; /* Number of log buffers, -1 to default */ + int logbufsize; /* Size of log buffers, -1 to default */ + char *fsname; /* filesystem name (mount point) */ + + /* + * The following items added in version 2. They are for stripe + * aligment. Set 0 for no alignment handling (see XFSMNT_NOALIGN + * flag). + */ + int sunit; /* stripe unit (bbs) */ + int swidth; /* stripe width (bbs), multiple of sunit */ + + /* + * The following items added in version 3. + */ + uchar_t iosizelog; /* log2 of the preferred I/O size */ + uchar_t reserved_0; /* reserved fields */ + short reserved_1; + dev_t logdev; /* Log device */ + dev_t rtdev; /* Realtime device */ + + /* + * The following items added in version 4. This stuff is for + * cxfs support. + */ + char **servlist; /* Table of hosts which may be servers */ + int *servlistlen; /* Table of hostname lengths. */ + int slcount; /* Count of hosts which may be servers. */ + int stimeout; /* Server timeout in milliseconds */ + int ctimeout; /* Client timeout in milliseconds */ + char *server; /* Designated server hostname (for remount). */ + int servlen; /* Length of server hostname (for remount). */ + int servcell; /* Server cell (internal testing only) */ +}; + +#ifdef __KERNEL__ + +struct xfs_args32_ver_1 { + __int32_t version; + __int32_t flags; + __int32_t logbufs; + __int32_t logbufsize; + app32_ptr_t fsname; +}; + +struct xfs_args32_ver_2 { + __int32_t version; + __int32_t flags; + __int32_t logbufs; + __int32_t logbufsize; + app32_ptr_t fsname; + __int32_t sunit; + __int32_t swidth; +}; + +struct xfs_args32_ver_3 { + __int32_t version; + __int32_t flags; + __int32_t logbufs; + __int32_t logbufsize; + app32_ptr_t fsname; + __int32_t sunit; + __int32_t swidth; + uint8_t iosizelog; + uint8_t reserved_3_0; + __int16_t reserved_3_1; + __int32_t reserved_3_2; + __int32_t reserved_3_3; +}; + +struct xfs_args32_ver_4 { + __int32_t version; + __int32_t flags; + __int32_t logbufs; + __int32_t logbufsize; + app32_ptr_t fsname; + __int32_t sunit; + __int32_t swidth; + uint8_t iosizelog; + uint8_t reserved_3_0; + __int16_t reserved_3_1; + __int32_t reserved_3_2; + __int32_t reserved_3_3; + app32_ptr_t servlist; + app32_ptr_t servlistlen; + __int32_t slcount; + __int32_t stimeout; + __int32_t ctimeout; + app32_ptr_t server; + __int32_t servlen; + __int32_t servcell; +}; + +struct xfs_args_ver_1 { + int version; + int flags; + int logbufs; + int logbufsize; + char *fsname; +}; + +struct xfs_args_ver_2 { + int version; + int flags; + int logbufs; + int logbufsize; + char *fsname; + int sunit; + int swidth; +}; + +struct xfs_args_ver_3 { + int version; + int flags; + int logbufs; + int logbufsize; + char *fsname; + int sunit; + int swidth; + uchar_t iosizelog; + uchar_t reserved_0; + short reserved_1; + int reserved_2; + int reserved_3; +}; + +#define XFSARGS_FOR_CXFSARR(ap) \ + ((ap)->servlist || (ap)->slcount >= 0 || \ + (ap)->stimeout >= 0 || (ap)->ctimeout >= 0 || \ + (ap)->flags & (XFSMNT_CLNTONLY | XFSMNT_UNSHARED)) + +#endif /* __KERNEL__ */ + +/* + * XFS mount option flags + */ +#define XFSMNT_CHKLOG 0x00000001 /* check log */ +#define XFSMNT_WSYNC 0x00000002 /* safe mode nfs mount + * compatible */ +#define XFSMNT_INO64 0x00000004 /* move inode numbers up + * past 2^32 */ +#define XFSMNT_UQUOTA 0x00000008 /* user quota accounting */ +#define XFSMNT_PQUOTA 0x00000010 /* IRIX prj quota accounting */ +#define XFSMNT_UQUOTAENF 0x00000020 /* user quota limit + * enforcement */ +#define XFSMNT_PQUOTAENF 0x00000040 /* IRIX project quota limit + * enforcement */ +#define XFSMNT_QUOTAMAYBE 0x00000080 /* don't turn off if SB + * has quotas on */ +#define XFSMNT_NOATIME 0x00000100 /* don't modify access + * times on reads */ +#define XFSMNT_NOALIGN 0x00000200 /* don't allocate at + * stripe boundaries*/ +#define XFSMNT_RETERR 0x00000400 /* return error to user */ +#define XFSMNT_NORECOVERY 0x00000800 /* no recovery, implies + * read-only mount */ +#define XFSMNT_SHARED 0x00001000 /* shared XFS mount */ +#define XFSMNT_IOSIZE 0x00002000 /* optimize for I/O size */ +#define XFSMNT_OSYNCISDSYNC 0x00004000 /* treat o_sync like o_dsync */ +#define XFSMNT_CLNTONLY 0x00008000 /* cxfs mount as client only */ +#define XFSMNT_UNSHARED 0x00010000 /* cxfs filesystem mounted + * unshared */ +#define XFSMNT_CHGCLNTONLY 0x00020000 /* changing client only flag */ + /* (for remount only) */ +#define XFSMNT_SERVCELL 0x00040000 /* setting server cell */ + /* (allowed on remount) */ +#define XFSMNT_MAKESERVER 0x00080000 /* become the server (remount */ + /* only) */ +#define XFSMNT_NOTSERVER 0x00100000 /* give up being the server */ + /* (remount only) */ +#define XFSMNT_DMAPI 0x00200000 /* enable dmapi/xdsm */ +#define XFSMNT_GQUOTA 0x00400000 /* group quota accounting */ +#define XFSMNT_GQUOTAENF 0x00800000 /* group quota limit + * enforcement */ +#define XFSMNT_NOUUID 0x01000000 /* Ignore fs uuid */ + +#endif /* __XFS_CLNT_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_cxfs.h linux-2.4-xfs/linux/fs/xfs/xfs_cxfs.h --- linux-2.4.7/linux/fs/xfs/xfs_cxfs.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_cxfs.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef __XFS_CXFS_H__ +#define __XFS_CXFS_H__ + +/* + * xfs_cxfs.h -- Interface cxfs presents to non-cell xfs code + * + * This header specifies the interface that cxfs V1 code presents to the + * non-cellular parts of xfs. When the specfied routines are not present, + * stubs will be provided. + */ + +struct xfs_inode; +struct xfs_mount; +struct xfs_args; +struct mounta; +struct vfs; +struct vfsops; +struct vnode; +struct xfs_buf; + +/* + * Array mount routines. Stubs provided for the non-CELL case. + */ +extern void cxfs_arrinit(void); /* Initialization for array mount logic. */ +extern int cxfs_mount( /* For any specia mount handling. */ + struct xfs_mount *mp, + struct xfs_args *ap, + dev_t dev, + int *client); +extern void cxfs_unmount( /* For any special unmount handling. */ + struct xfs_mount *mp); + +/* + * Other cxfs routines. Stubs provided in non-CELL case. + */ +extern void cxfs_inode_quiesce( /* Quiesce new inode for vfs */ + struct xfs_inode *ip); /* relocation. */ +extern int cxfs_inode_qset( /* Set quiesce flag on inode. */ + struct xfs_inode *ip); +extern int cxfs_remount_server( /* Modify mount parameters. This */ + struct xfs_mount *mp, /* may result in vfs relocation. */ + struct mounta *uap, /* There are separate implementa- */ + struct xfs_args *ap); /* tions for arrays and ssi as */ + /* well as a stub for non-CELL. */ + +extern struct xfs_mount *get_cxfs_mountp(struct vfs *); + +extern void cxfs_strat_complete_buf(struct xfs_buf *); + +extern __uint64_t cfs_start_defrag( + struct vnode *vp); +extern void cfs_end_defrag( + struct vnode *vp, + __uint64_t handle); + +#endif /* __XFS_CXFS_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_da_btree.c linux-2.4-xfs/linux/fs/xfs/xfs_da_btree.c --- linux-2.4.7/linux/fs/xfs/xfs_da_btree.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_da_btree.c Mon Jul 2 13:15:34 2001 @@ -0,0 +1,2578 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +#if defined(XFSDEBUG) && defined(CONFIG_KDB) +#undef xfs_buftrace +#define xfs_buftrace(A,B) panic(" xfs_buftrace : %s (0x%p)\n", A, B); +#endif + +/* + * xfs_da_btree.c + * + * Routines to implement directories as Btrees of hashed names. + */ + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Routines used for growing the Btree. + */ +STATIC int xfs_da_root_split(xfs_da_state_t *state, + xfs_da_state_blk_t *existing_root, + xfs_da_state_blk_t *new_child); +STATIC int xfs_da_node_split(xfs_da_state_t *state, + xfs_da_state_blk_t *existing_blk, + xfs_da_state_blk_t *split_blk, + xfs_da_state_blk_t *blk_to_add, + int treelevel, + int *result); +STATIC void xfs_da_node_rebalance(xfs_da_state_t *state, + xfs_da_state_blk_t *node_blk_1, + xfs_da_state_blk_t *node_blk_2); +STATIC void xfs_da_node_add(xfs_da_state_t *state, + xfs_da_state_blk_t *old_node_blk, + xfs_da_state_blk_t *new_node_blk); + +/* + * Routines used for shrinking the Btree. + */ +STATIC int xfs_da_root_join(xfs_da_state_t *state, + xfs_da_state_blk_t *root_blk); +STATIC int xfs_da_node_toosmall(xfs_da_state_t *state, int *retval); +STATIC void xfs_da_node_remove(xfs_da_state_t *state, + xfs_da_state_blk_t *drop_blk); +STATIC void xfs_da_node_unbalance(xfs_da_state_t *state, + xfs_da_state_blk_t *src_node_blk, + xfs_da_state_blk_t *dst_node_blk); + +/* + * Utility routines. + */ +STATIC uint xfs_da_node_lasthash(xfs_dabuf_t *bp, int *count); +STATIC int xfs_da_node_order(xfs_dabuf_t *node1_bp, xfs_dabuf_t *node2_bp); +STATIC xfs_dabuf_t *xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra, int); + + +/*======================================================================== + * Routines used for growing the Btree. + *========================================================================*/ + +/* + * Create the initial contents of an intermediate node. + */ +int +xfs_da_node_create(xfs_da_args_t *args, xfs_dablk_t blkno, int level, + xfs_dabuf_t **bpp, int whichfork) +{ + xfs_da_intnode_t *node; + xfs_dabuf_t *bp; + int error; + xfs_trans_t *tp; + + tp = args->trans; + error = xfs_da_get_buf(tp, args->dp, blkno, -1, &bp, whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + node = bp->data; + INT_ZERO(node->hdr.info.forw, ARCH_CONVERT); + INT_ZERO(node->hdr.info.back, ARCH_CONVERT); + INT_SET(node->hdr.info.magic, ARCH_CONVERT, XFS_DA_NODE_MAGIC); + INT_ZERO(node->hdr.info.pad, ARCH_CONVERT); + INT_ZERO(node->hdr.count, ARCH_CONVERT); + INT_SET(node->hdr.level, ARCH_CONVERT, level); + + xfs_da_log_buf(tp, bp, + XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr))); + + *bpp = bp; + return(0); +} + +/* + * Split a leaf node, rebalance, then possibly split + * intermediate nodes, rebalance, etc. + */ +int /* error */ +xfs_da_split(xfs_da_state_t *state) +{ + xfs_da_state_blk_t *oldblk, *newblk, *addblk; + xfs_da_intnode_t *node; + xfs_dabuf_t *bp; + int max, action, error, i; + + /* + * Walk back up the tree splitting/inserting/adjusting as necessary. + * If we need to insert and there isn't room, split the node, then + * decide which fragment to insert the new block from below into. + * Note that we may split the root this way, but we need more fixup. + */ + max = state->path.active - 1; + ASSERT((max >= 0) && (max < XFS_DA_NODE_MAXDEPTH)); + ASSERT(state->path.blk[max].magic == XFS_ATTR_LEAF_MAGIC || + state->path.blk[max].magic == XFS_DIRX_LEAF_MAGIC(state->mp)); + + addblk = &state->path.blk[max]; /* initial dummy value */ + for (i = max; (i >= 0) && addblk; state->path.active--, i--) { + oldblk = &state->path.blk[i]; + newblk = &state->altpath.blk[i]; + + /* + * If a leaf node then + * Allocate a new leaf node, then rebalance across them. + * else if an intermediate node then + * We split on the last layer, must we split the node? + */ + switch (oldblk->magic) { + case XFS_ATTR_LEAF_MAGIC: +#ifndef __KERNEL__ + return(ENOTTY); +#else + error = xfs_attr_leaf_split(state, oldblk, newblk); + if ((error != 0) && (error != ENOSPC)) { + return(error); /* GROT: attr is inconsistent */ + } + if (!error) { + addblk = newblk; + break; + } + /* + * Entry wouldn't fit, split the leaf again. + */ + state->extravalid = 1; + if (state->inleaf) { + state->extraafter = 0; /* before newblk */ + error = xfs_attr_leaf_split(state, oldblk, + &state->extrablk); + } else { + state->extraafter = 1; /* after newblk */ + error = xfs_attr_leaf_split(state, newblk, + &state->extrablk); + } + if (error) + return(error); /* GROT: attr inconsistent */ + addblk = newblk; + break; +#endif + case XFS_DIR_LEAF_MAGIC: + ASSERT(XFS_DIR_IS_V1(state->mp)); + error = xfs_dir_leaf_split(state, oldblk, newblk); + if ((error != 0) && (error != ENOSPC)) { + return(error); /* GROT: dir is inconsistent */ + } + if (!error) { + addblk = newblk; + break; + } + /* + * Entry wouldn't fit, split the leaf again. + */ + state->extravalid = 1; + if (state->inleaf) { + state->extraafter = 0; /* before newblk */ + error = xfs_dir_leaf_split(state, oldblk, + &state->extrablk); + if (error) + return(error); /* GROT: dir incon. */ + addblk = newblk; + } else { + state->extraafter = 1; /* after newblk */ + error = xfs_dir_leaf_split(state, newblk, + &state->extrablk); + if (error) + return(error); /* GROT: dir incon. */ + addblk = newblk; + } + break; + case XFS_DIR2_LEAFN_MAGIC: + ASSERT(XFS_DIR_IS_V2(state->mp)); + error = xfs_dir2_leafn_split(state, oldblk, newblk); + if (error) + return error; + addblk = newblk; + break; + case XFS_DA_NODE_MAGIC: + error = xfs_da_node_split(state, oldblk, newblk, addblk, + max - i, &action); + xfs_da_buf_done(addblk->bp); + addblk->bp = NULL; + if (error) + return(error); /* GROT: dir is inconsistent */ + /* + * Record the newly split block for the next time thru? + */ + if (action) + addblk = newblk; + else + addblk = NULL; + break; + } + + /* + * Update the btree to show the new hashval for this child. + */ + xfs_da_fixhashpath(state, &state->path); + /* + * If we won't need this block again, it's getting dropped + * from the active path by the loop control, so we need + * to mark it done now. + */ + if (i > 0 || !addblk) + xfs_da_buf_done(oldblk->bp); + } + if (!addblk) + return(0); + + /* + * Split the root node. + */ + ASSERT(state->path.active == 0); + oldblk = &state->path.blk[0]; + error = xfs_da_root_split(state, oldblk, addblk); + if (error) { + xfs_da_buf_done(oldblk->bp); + xfs_da_buf_done(addblk->bp); + addblk->bp = NULL; + return(error); /* GROT: dir is inconsistent */ + } + + /* + * Update pointers to the node which used to be block 0 and + * just got bumped because of the addition of a new root node. + * There might be three blocks involved if a double split occurred, + * and the original block 0 could be at any position in the list. + */ + + node = oldblk->bp->data; + if (!INT_ISZERO(node->hdr.info.forw, ARCH_CONVERT)) { + if (INT_GET(node->hdr.info.forw, ARCH_CONVERT) == addblk->blkno) { + bp = addblk->bp; + } else { + ASSERT(state->extravalid); + bp = state->extrablk.bp; + } + node = bp->data; + INT_SET(node->hdr.info.back, ARCH_CONVERT, oldblk->blkno); + xfs_da_log_buf(state->args->trans, bp, + XFS_DA_LOGRANGE(node, &node->hdr.info, + sizeof(node->hdr.info))); + } + node = oldblk->bp->data; + if (INT_GET(node->hdr.info.back, ARCH_CONVERT)) { + if (INT_GET(node->hdr.info.back, ARCH_CONVERT) == addblk->blkno) { + bp = addblk->bp; + } else { + ASSERT(state->extravalid); + bp = state->extrablk.bp; + } + node = bp->data; + INT_SET(node->hdr.info.forw, ARCH_CONVERT, oldblk->blkno); + xfs_da_log_buf(state->args->trans, bp, + XFS_DA_LOGRANGE(node, &node->hdr.info, + sizeof(node->hdr.info))); + } + xfs_da_buf_done(oldblk->bp); + xfs_da_buf_done(addblk->bp); + addblk->bp = NULL; + return(0); +} + +/* + * Split the root. We have to create a new root and point to the two + * parts (the split old root) that we just created. Copy block zero to + * the EOF, extending the inode in process. + */ +STATIC int /* error */ +xfs_da_root_split(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2) +{ + xfs_da_intnode_t *node, *oldroot; + xfs_da_args_t *args; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + int error, size; + xfs_inode_t *dp; + xfs_trans_t *tp; + xfs_mount_t *mp; + xfs_dir2_leaf_t *leaf; + + /* + * Copy the existing (incorrect) block from the root node position + * to a free space somewhere. + */ + args = state->args; + ASSERT(args != NULL); + error = xfs_da_grow_inode(args, &blkno); + if (error) + return(error); + dp = args->dp; + tp = args->trans; + mp = state->mp; + error = xfs_da_get_buf(tp, dp, blkno, -1, &bp, args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + node = bp->data; + oldroot = blk1->bp->data; + if (INT_GET(oldroot->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) { + size = (int)((char *)&oldroot->btree[INT_GET(oldroot->hdr.count, ARCH_CONVERT)] - + (char *)oldroot); + } else { + ASSERT(XFS_DIR_IS_V2(mp)); + ASSERT(INT_GET(oldroot->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + leaf = (xfs_dir2_leaf_t *)oldroot; + size = (int)((char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] - + (char *)leaf); + } + bcopy(oldroot, node, size); + xfs_da_log_buf(tp, bp, 0, size - 1); + xfs_da_buf_done(blk1->bp); + blk1->bp = bp; + blk1->blkno = blkno; + + /* + * Set up the new root node. + */ + error = xfs_da_node_create(args, + args->whichfork == XFS_DATA_FORK && + XFS_DIR_IS_V2(mp) ? mp->m_dirleafblk : 0, + INT_GET(node->hdr.level, ARCH_CONVERT) + 1, &bp, args->whichfork); + if (error) + return(error); + node = bp->data; + INT_SET(node->btree[0].hashval, ARCH_CONVERT, blk1->hashval); + INT_SET(node->btree[0].before, ARCH_CONVERT, blk1->blkno); + INT_SET(node->btree[1].hashval, ARCH_CONVERT, blk2->hashval); + INT_SET(node->btree[1].before, ARCH_CONVERT, blk2->blkno); + INT_SET(node->hdr.count, ARCH_CONVERT, 2); + if (XFS_DIR_IS_V2(mp)) { + ASSERT(blk1->blkno >= mp->m_dirleafblk && + blk1->blkno < mp->m_dirfreeblk); + ASSERT(blk2->blkno >= mp->m_dirleafblk && + blk2->blkno < mp->m_dirfreeblk); + } + /* Header is already logged by xfs_da_node_create */ + xfs_da_log_buf(tp, bp, + XFS_DA_LOGRANGE(node, node->btree, + sizeof(xfs_da_node_entry_t) * 2)); + xfs_da_buf_done(bp); + + return(0); +} + +/* + * Split the node, rebalance, then add the new entry. + */ +STATIC int /* error */ +xfs_da_node_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, + xfs_da_state_blk_t *newblk, + xfs_da_state_blk_t *addblk, + int treelevel, int *result) +{ + xfs_da_intnode_t *node; + xfs_dablk_t blkno; + int newcount, error; + int useextra; + + node = oldblk->bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + + /* + * With V2 the extra block is data or freespace. + */ + useextra = state->extravalid && XFS_DIR_IS_V1(state->mp); + newcount = 1 + useextra; + /* + * Do we have to split the node? + */ + if ((INT_GET(node->hdr.count, ARCH_CONVERT) + newcount) > XFS_DA_NODE_ENTRIES(state->mp)) { + /* + * Allocate a new node, add to the doubly linked chain of + * nodes, then move some of our excess entries into it. + */ + error = xfs_da_grow_inode(state->args, &blkno); + if (error) + return(error); /* GROT: dir is inconsistent */ + + error = xfs_da_node_create(state->args, blkno, treelevel, + &newblk->bp, state->args->whichfork); + if (error) + return(error); /* GROT: dir is inconsistent */ + newblk->blkno = blkno; + newblk->magic = XFS_DA_NODE_MAGIC; + xfs_da_node_rebalance(state, oldblk, newblk); + error = xfs_da_blk_link(state, oldblk, newblk); + if (error) + return(error); + *result = 1; + } else { + *result = 0; + } + + /* + * Insert the new entry(s) into the correct block + * (updating last hashval in the process). + * + * xfs_da_node_add() inserts BEFORE the given index, + * and as a result of using node_lookup_int() we always + * point to a valid entry (not after one), but a split + * operation always results in a new block whose hashvals + * FOLLOW the current block. + * + * If we had double-split op below us, then add the extra block too. + */ + node = oldblk->bp->data; + if (oldblk->index <= INT_GET(node->hdr.count, ARCH_CONVERT)) { + oldblk->index++; + xfs_da_node_add(state, oldblk, addblk); + if (useextra) { + if (state->extraafter) + oldblk->index++; + xfs_da_node_add(state, oldblk, &state->extrablk); + state->extravalid = 0; + } + } else { + newblk->index++; + xfs_da_node_add(state, newblk, addblk); + if (useextra) { + if (state->extraafter) + newblk->index++; + xfs_da_node_add(state, newblk, &state->extrablk); + state->extravalid = 0; + } + } + + return(0); +} + +/* + * Balance the btree elements between two intermediate nodes, + * usually one full and one empty. + * + * NOTE: if blk2 is empty, then it will get the upper half of blk1. + */ +STATIC void +xfs_da_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2) +{ + xfs_da_intnode_t *node1, *node2, *tmpnode; + xfs_da_node_entry_t *btree_s, *btree_d; + int count, tmp; + xfs_trans_t *tp; + + node1 = blk1->bp->data; + node2 = blk2->bp->data; + /* + * Figure out how many entries need to move, and in which direction. + * Swap the nodes around if that makes it simpler. + */ + if ((INT_GET(node1->hdr.count, ARCH_CONVERT) > 0) && (INT_GET(node2->hdr.count, ARCH_CONVERT) > 0) && + ((INT_GET(node2->btree[ 0 ].hashval, ARCH_CONVERT) < INT_GET(node1->btree[ 0 ].hashval, ARCH_CONVERT)) || + (INT_GET(node2->btree[ INT_GET(node2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) < + INT_GET(node1->btree[ INT_GET(node1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)))) { + tmpnode = node1; + node1 = node2; + node2 = tmpnode; + } + ASSERT(INT_GET(node1->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + ASSERT(INT_GET(node2->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + count = (INT_GET(node1->hdr.count, ARCH_CONVERT) - INT_GET(node2->hdr.count, ARCH_CONVERT)) / 2; + if (count == 0) + return; + tp = state->args->trans; + /* + * Two cases: high-to-low and low-to-high. + */ + if (count > 0) { + /* + * Move elements in node2 up to make a hole. + */ + if ((tmp = INT_GET(node2->hdr.count, ARCH_CONVERT)) > 0) { + tmp *= (uint)sizeof(xfs_da_node_entry_t); + btree_s = &node2->btree[0]; + btree_d = &node2->btree[count]; + ovbcopy(btree_s, btree_d, tmp); + } + + /* + * Move the req'd B-tree elements from high in node1 to + * low in node2. + */ + INT_MOD(node2->hdr.count, ARCH_CONVERT, count); + tmp = count * (uint)sizeof(xfs_da_node_entry_t); + btree_s = &node1->btree[INT_GET(node1->hdr.count, ARCH_CONVERT) - count]; + btree_d = &node2->btree[0]; + bcopy(btree_s, btree_d, tmp); + INT_MOD(node1->hdr.count, ARCH_CONVERT, -(count)); + + } else { + /* + * Move the req'd B-tree elements from low in node2 to + * high in node1. + */ + count = -count; + tmp = count * (uint)sizeof(xfs_da_node_entry_t); + btree_s = &node2->btree[0]; + btree_d = &node1->btree[INT_GET(node1->hdr.count, ARCH_CONVERT)]; + bcopy(btree_s, btree_d, tmp); + INT_MOD(node1->hdr.count, ARCH_CONVERT, count); + xfs_da_log_buf(tp, blk1->bp, + XFS_DA_LOGRANGE(node1, btree_d, tmp)); + + /* + * Move elements in node2 down to fill the hole. + */ + tmp = INT_GET(node2->hdr.count, ARCH_CONVERT) - count; + tmp *= (uint)sizeof(xfs_da_node_entry_t); + btree_s = &node2->btree[count]; + btree_d = &node2->btree[0]; + ovbcopy(btree_s, btree_d, tmp); + INT_MOD(node2->hdr.count, ARCH_CONVERT, -(count)); + } + + /* + * Log header of node 1 and all current bits of node 2. + */ + xfs_da_log_buf(tp, blk1->bp, + XFS_DA_LOGRANGE(node1, &node1->hdr, sizeof(node1->hdr))); + xfs_da_log_buf(tp, blk2->bp, + XFS_DA_LOGRANGE(node2, &node2->hdr, + sizeof(node2->hdr) + + sizeof(node2->btree[0]) * INT_GET(node2->hdr.count, ARCH_CONVERT))); + + /* + * Record the last hashval from each block for upward propagation. + * (note: don't use the swapped node pointers) + */ + node1 = blk1->bp->data; + node2 = blk2->bp->data; + blk1->hashval = INT_GET(node1->btree[ INT_GET(node1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + blk2->hashval = INT_GET(node2->btree[ INT_GET(node2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + + /* + * Adjust the expected index for insertion. + */ + if (blk1->index >= INT_GET(node1->hdr.count, ARCH_CONVERT)) { + blk2->index = blk1->index - INT_GET(node1->hdr.count, ARCH_CONVERT); + blk1->index = INT_GET(node1->hdr.count, ARCH_CONVERT) + 1; /* make it invalid */ + } +} + +/* + * Add a new entry to an intermediate node. + */ +STATIC void +xfs_da_node_add(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, + xfs_da_state_blk_t *newblk) +{ + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + int tmp; + xfs_mount_t *mp; + + node = oldblk->bp->data; + mp = state->mp; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + ASSERT((oldblk->index >= 0) && (oldblk->index <= INT_GET(node->hdr.count, ARCH_CONVERT))); + ASSERT(newblk->blkno != 0); + if (state->args->whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) + ASSERT(newblk->blkno >= mp->m_dirleafblk && + newblk->blkno < mp->m_dirfreeblk); + + /* + * We may need to make some room before we insert the new node. + */ + tmp = 0; + btree = &node->btree[ oldblk->index ]; + if (oldblk->index < INT_GET(node->hdr.count, ARCH_CONVERT)) { + tmp = (INT_GET(node->hdr.count, ARCH_CONVERT) - oldblk->index) * (uint)sizeof(*btree); + ovbcopy(btree, btree + 1, tmp); + } + INT_SET(btree->hashval, ARCH_CONVERT, newblk->hashval); + INT_SET(btree->before, ARCH_CONVERT, newblk->blkno); + xfs_da_log_buf(state->args->trans, oldblk->bp, + XFS_DA_LOGRANGE(node, btree, tmp + sizeof(*btree))); + INT_MOD(node->hdr.count, ARCH_CONVERT, +1); + xfs_da_log_buf(state->args->trans, oldblk->bp, + XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr))); + + /* + * Copy the last hash value from the oldblk to propagate upwards. + */ + oldblk->hashval = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); +} + +/*======================================================================== + * Routines used for shrinking the Btree. + *========================================================================*/ + +/* + * Deallocate an empty leaf node, remove it from its parent, + * possibly deallocating that block, etc... + */ +int +xfs_da_join(xfs_da_state_t *state) +{ + xfs_da_state_blk_t *drop_blk, *save_blk; + int action, error; + + action = 0; + drop_blk = &state->path.blk[ state->path.active-1 ]; + save_blk = &state->altpath.blk[ state->path.active-1 ]; + ASSERT(state->path.blk[0].magic == XFS_DA_NODE_MAGIC); + ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC || + drop_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp)); + + /* + * Walk back up the tree joining/deallocating as necessary. + * When we stop dropping blocks, break out. + */ + for ( ; state->path.active >= 2; drop_blk--, save_blk--, + state->path.active--) { + /* + * See if we can combine the block with a neighbor. + * (action == 0) => no options, just leave + * (action == 1) => coalesce, then unlink + * (action == 2) => block empty, unlink it + */ + switch (drop_blk->magic) { + case XFS_ATTR_LEAF_MAGIC: +#ifndef __KERNEL__ + error = ENOTTY; +#else + error = xfs_attr_leaf_toosmall(state, &action); +#endif + if (error) + return(error); + if (action == 0) + return(0); +#ifdef __KERNEL__ + xfs_attr_leaf_unbalance(state, drop_blk, save_blk); +#endif + break; + case XFS_DIR_LEAF_MAGIC: + ASSERT(XFS_DIR_IS_V1(state->mp)); + error = xfs_dir_leaf_toosmall(state, &action); + if (error) + return(error); + if (action == 0) + return(0); + xfs_dir_leaf_unbalance(state, drop_blk, save_blk); + break; + case XFS_DIR2_LEAFN_MAGIC: + ASSERT(XFS_DIR_IS_V2(state->mp)); + error = xfs_dir2_leafn_toosmall(state, &action); + if (error) + return error; + if (action == 0) + return 0; + xfs_dir2_leafn_unbalance(state, drop_blk, save_blk); + break; + case XFS_DA_NODE_MAGIC: + /* + * Remove the offending node, fixup hashvals, + * check for a toosmall neighbor. + */ + xfs_da_node_remove(state, drop_blk); + xfs_da_fixhashpath(state, &state->path); + error = xfs_da_node_toosmall(state, &action); + if (error) + return(error); + if (action == 0) + return 0; + xfs_da_node_unbalance(state, drop_blk, save_blk); + break; + } + xfs_da_fixhashpath(state, &state->altpath); + error = xfs_da_blk_unlink(state, drop_blk, save_blk); + xfs_da_state_kill_altpath(state); + if (error) + return(error); + error = xfs_da_shrink_inode(state->args, drop_blk->blkno, + drop_blk->bp); + drop_blk->bp = NULL; + if (error) + return(error); + } + /* + * We joined all the way to the top. If it turns out that + * we only have one entry in the root, make the child block + * the new root. + */ + xfs_da_node_remove(state, drop_blk); + xfs_da_fixhashpath(state, &state->path); + error = xfs_da_root_join(state, &state->path.blk[0]); + return(error); +} + +/* + * We have only one entry in the root. Copy the only remaining child of + * the old root to block 0 as the new root node. + */ +STATIC int +xfs_da_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk) +{ + xfs_da_intnode_t *oldroot; + /* REFERENCED */ + xfs_da_blkinfo_t *blkinfo; + xfs_da_args_t *args; + xfs_dablk_t child; + xfs_dabuf_t *bp; + int error; + + args = state->args; + ASSERT(args != NULL); + ASSERT(root_blk->magic == XFS_DA_NODE_MAGIC); + oldroot = root_blk->bp->data; + ASSERT(INT_GET(oldroot->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + ASSERT(INT_ISZERO(oldroot->hdr.info.forw, ARCH_CONVERT)); + ASSERT(INT_ISZERO(oldroot->hdr.info.back, ARCH_CONVERT)); + + /* + * If the root has more than one child, then don't do anything. + */ + if (INT_GET(oldroot->hdr.count, ARCH_CONVERT) > 1) + return(0); + + /* + * Read in the (only) child block, then copy those bytes into + * the root block's buffer and free the original child block. + */ + child = INT_GET(oldroot->btree[ 0 ].before, ARCH_CONVERT); + ASSERT(child != 0); + error = xfs_da_read_buf(args->trans, args->dp, child, -1, &bp, + args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + blkinfo = bp->data; + if (INT_GET(oldroot->hdr.level, ARCH_CONVERT) == 1) { + ASSERT(INT_GET(blkinfo->magic, ARCH_CONVERT) == XFS_DIRX_LEAF_MAGIC(state->mp) || + INT_GET(blkinfo->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); + } else { + ASSERT(INT_GET(blkinfo->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + } + ASSERT(INT_GET(blkinfo->forw, ARCH_CONVERT) == 0); + ASSERT(INT_GET(blkinfo->back, ARCH_CONVERT) == 0); + bcopy(bp->data, root_blk->bp->data, state->blocksize); + xfs_da_log_buf(args->trans, root_blk->bp, 0, state->blocksize - 1); + error = xfs_da_shrink_inode(args, child, bp); + return(error); +} + +/* + * Check a node block and its neighbors to see if the block should be + * collapsed into one or the other neighbor. Always keep the block + * with the smaller block number. + * If the current block is over 50% full, don't try to join it, return 0. + * If the block is empty, fill in the state structure and return 2. + * If it can be collapsed, fill in the state structure and return 1. + * If nothing can be done, return 0. + */ +STATIC int +xfs_da_node_toosmall(xfs_da_state_t *state, int *action) +{ + xfs_da_intnode_t *node; + xfs_da_state_blk_t *blk; + xfs_da_blkinfo_t *info; + int count, forward, error, retval, i; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + + /* + * Check for the degenerate case of the block being over 50% full. + * If so, it's not worth even looking to see if we might be able + * to coalesce with a sibling. + */ + blk = &state->path.blk[ state->path.active-1 ]; + info = blk->bp->data; + ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + node = (xfs_da_intnode_t *)info; + count = INT_GET(node->hdr.count, ARCH_CONVERT); + if (count > (XFS_DA_NODE_ENTRIES(state->mp) >> 1)) { + *action = 0; /* blk over 50%, dont try to join */ + return(0); /* blk over 50%, dont try to join */ + } + + /* + * Check for the degenerate case of the block being empty. + * If the block is empty, we'll simply delete it, no need to + * coalesce it with a sibling block. We choose (aribtrarily) + * to merge with the forward block unless it is NULL. + */ + if (count == 0) { + /* + * Make altpath point to the block we want to keep and + * path point to the block we want to drop (this one). + */ + forward = (!INT_ISZERO(info->forw, ARCH_CONVERT)); + bcopy(&state->path, &state->altpath, sizeof(state->path)); + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + if (error) + return(error); + if (retval) { + *action = 0; + } else { + *action = 2; + } + return(0); + } + + /* + * Examine each sibling block to see if we can coalesce with + * at least 25% free space to spare. We need to figure out + * whether to merge with the forward or the backward block. + * We prefer coalescing with the lower numbered sibling so as + * to shrink a directory over time. + */ + /* start with smaller blk num */ + forward = (INT_GET(info->forw, ARCH_CONVERT) + < INT_GET(info->back, ARCH_CONVERT)); + for (i = 0; i < 2; forward = !forward, i++) { + if (forward) + blkno = INT_GET(info->forw, ARCH_CONVERT); + else + blkno = INT_GET(info->back, ARCH_CONVERT); + if (blkno == 0) + continue; + error = xfs_da_read_buf(state->args->trans, state->args->dp, + blkno, -1, &bp, state->args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + + node = (xfs_da_intnode_t *)info; + count = XFS_DA_NODE_ENTRIES(state->mp); + count -= XFS_DA_NODE_ENTRIES(state->mp) >> 2; + count -= INT_GET(node->hdr.count, ARCH_CONVERT); + node = bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + count -= INT_GET(node->hdr.count, ARCH_CONVERT); + xfs_da_brelse(state->args->trans, bp); + if (count >= 0) + break; /* fits with at least 25% to spare */ + } + if (i >= 2) { + *action = 0; + return(0); + } + + /* + * Make altpath point to the block we want to keep (the lower + * numbered block) and path point to the block we want to drop. + */ + bcopy(&state->path, &state->altpath, sizeof(state->path)); + if (blkno < blk->blkno) { + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + if (error) { + return(error); + } + if (retval) { + *action = 0; + return(0); + } + } else { + error = xfs_da_path_shift(state, &state->path, forward, + 0, &retval); + if (error) { + return(error); + } + if (retval) { + *action = 0; + return(0); + } + } + *action = 1; + return(0); +} + +/* + * Walk back up the tree adjusting hash values as necessary, + * when we stop making changes, return. + */ +void +xfs_da_fixhashpath(xfs_da_state_t *state, xfs_da_state_path_t *path) +{ + xfs_da_state_blk_t *blk; + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + xfs_dahash_t lasthash=0; + int level, count; + + level = path->active-1; + blk = &path->blk[ level ]; + switch (blk->magic) { +#ifdef __KERNEL__ + case XFS_ATTR_LEAF_MAGIC: + lasthash = xfs_attr_leaf_lasthash(blk->bp, &count); + if (count == 0) + return; + break; +#endif + case XFS_DIR_LEAF_MAGIC: + ASSERT(XFS_DIR_IS_V1(state->mp)); + lasthash = xfs_dir_leaf_lasthash(blk->bp, &count); + if (count == 0) + return; + break; + case XFS_DIR2_LEAFN_MAGIC: + ASSERT(XFS_DIR_IS_V2(state->mp)); + lasthash = xfs_dir2_leafn_lasthash(blk->bp, &count); + if (count == 0) + return; + break; + case XFS_DA_NODE_MAGIC: + lasthash = xfs_da_node_lasthash(blk->bp, &count); + if (count == 0) + return; + break; + } + for (blk--, level--; level >= 0; blk--, level--) { + node = blk->bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + btree = &node->btree[ blk->index ]; + if (INT_GET(btree->hashval, ARCH_CONVERT) == lasthash) + break; + blk->hashval = lasthash; + INT_SET(btree->hashval, ARCH_CONVERT, lasthash); + xfs_da_log_buf(state->args->trans, blk->bp, + XFS_DA_LOGRANGE(node, btree, sizeof(*btree))); + + lasthash = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + } +} + +/* + * Remove an entry from an intermediate node. + */ +STATIC void +xfs_da_node_remove(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk) +{ + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + int tmp; + + node = drop_blk->bp->data; + ASSERT(drop_blk->index < INT_GET(node->hdr.count, ARCH_CONVERT)); + ASSERT(drop_blk->index >= 0); + + /* + * Copy over the offending entry, or just zero it out. + */ + btree = &node->btree[drop_blk->index]; + if (drop_blk->index < (INT_GET(node->hdr.count, ARCH_CONVERT)-1)) { + tmp = INT_GET(node->hdr.count, ARCH_CONVERT) - drop_blk->index - 1; + tmp *= (uint)sizeof(xfs_da_node_entry_t); + ovbcopy(btree + 1, btree, tmp); + xfs_da_log_buf(state->args->trans, drop_blk->bp, + XFS_DA_LOGRANGE(node, btree, tmp)); + btree = &node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ]; + } + bzero((char *)btree, sizeof(xfs_da_node_entry_t)); + xfs_da_log_buf(state->args->trans, drop_blk->bp, + XFS_DA_LOGRANGE(node, btree, sizeof(*btree))); + INT_MOD(node->hdr.count, ARCH_CONVERT, -1); + xfs_da_log_buf(state->args->trans, drop_blk->bp, + XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr))); + + /* + * Copy the last hash value from the block to propagate upwards. + */ + btree--; + drop_blk->hashval = INT_GET(btree->hashval, ARCH_CONVERT); +} + +/* + * Unbalance the btree elements between two intermediate nodes, + * move all Btree elements from one node into another. + */ +STATIC void +xfs_da_node_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk) +{ + xfs_da_intnode_t *drop_node, *save_node; + xfs_da_node_entry_t *btree; + int tmp; + xfs_trans_t *tp; + + drop_node = drop_blk->bp->data; + save_node = save_blk->bp->data; + ASSERT(INT_GET(drop_node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + ASSERT(INT_GET(save_node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + tp = state->args->trans; + + /* + * If the dying block has lower hashvals, then move all the + * elements in the remaining block up to make a hole. + */ + if ((INT_GET(drop_node->btree[ 0 ].hashval, ARCH_CONVERT) < INT_GET(save_node->btree[ 0 ].hashval, ARCH_CONVERT)) || + (INT_GET(drop_node->btree[ INT_GET(drop_node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) < + INT_GET(save_node->btree[ INT_GET(save_node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT))) + { + btree = &save_node->btree[ INT_GET(drop_node->hdr.count, ARCH_CONVERT) ]; + tmp = INT_GET(save_node->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_da_node_entry_t); + ovbcopy(&save_node->btree[0], btree, tmp); + btree = &save_node->btree[0]; + xfs_da_log_buf(tp, save_blk->bp, + XFS_DA_LOGRANGE(save_node, btree, + (INT_GET(save_node->hdr.count, ARCH_CONVERT) + INT_GET(drop_node->hdr.count, ARCH_CONVERT)) * + sizeof(xfs_da_node_entry_t))); + } else { + btree = &save_node->btree[ INT_GET(save_node->hdr.count, ARCH_CONVERT) ]; + xfs_da_log_buf(tp, save_blk->bp, + XFS_DA_LOGRANGE(save_node, btree, + INT_GET(drop_node->hdr.count, ARCH_CONVERT) * + sizeof(xfs_da_node_entry_t))); + } + + /* + * Move all the B-tree elements from drop_blk to save_blk. + */ + tmp = INT_GET(drop_node->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_da_node_entry_t); + bcopy(&drop_node->btree[0], btree, tmp); + INT_MOD(save_node->hdr.count, ARCH_CONVERT, INT_GET(drop_node->hdr.count, ARCH_CONVERT)); + + xfs_da_log_buf(tp, save_blk->bp, + XFS_DA_LOGRANGE(save_node, &save_node->hdr, + sizeof(save_node->hdr))); + + /* + * Save the last hashval in the remaining block for upward propagation. + */ + save_blk->hashval = INT_GET(save_node->btree[ INT_GET(save_node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); +} + +/*======================================================================== + * Routines used for finding things in the Btree. + *========================================================================*/ + +/* + * Walk down the Btree looking for a particular filename, filling + * in the state structure as we go. + * + * We will set the state structure to point to each of the elements + * in each of the nodes where either the hashval is or should be. + * + * We support duplicate hashval's so for each entry in the current + * node that could contain the desired hashval, descend. This is a + * pruned depth-first tree search. + */ +int /* error */ +xfs_da_node_lookup_int(xfs_da_state_t *state, int *result) +{ + xfs_da_state_blk_t *blk; + xfs_da_blkinfo_t *curr; + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + xfs_dablk_t blkno; + int probe, span, max, error, retval; + xfs_dahash_t hashval; + xfs_da_args_t *args; + + args = state->args; + /* + * Descend thru the B-tree searching each level for the right + * node to use, until the right hashval is found. + */ + if (args->whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(state->mp)) + blkno = state->mp->m_dirleafblk; + else + blkno = 0; + for (blk = &state->path.blk[0], state->path.active = 1; + state->path.active <= XFS_DA_NODE_MAXDEPTH; + blk++, state->path.active++) { + /* + * Read the next node down in the tree. + */ + blk->blkno = blkno; + error = xfs_da_read_buf(state->args->trans, state->args->dp, + blkno, -1, &blk->bp, + state->args->whichfork); + if (error) { + blk->blkno = 0; + state->path.active--; + return(error); + } + ASSERT(blk->bp != NULL); + curr = blk->bp->data; + ASSERT(INT_GET(curr->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC || + INT_GET(curr->magic, ARCH_CONVERT) == XFS_DIRX_LEAF_MAGIC(state->mp) || + INT_GET(curr->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); + + /* + * Search an intermediate node for a match. + */ + blk->magic = INT_GET(curr->magic, ARCH_CONVERT); + if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) { + node = blk->bp->data; + blk->hashval = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + + /* + * Binary search. (note: small blocks will skip loop) + */ + max = INT_GET(node->hdr.count, ARCH_CONVERT); + probe = span = max / 2; + hashval = state->args->hashval; + for (btree = &node->btree[probe]; span > 4; + btree = &node->btree[probe]) { + span /= 2; + if (INT_GET(btree->hashval, ARCH_CONVERT) < hashval) + probe += span; + else if (INT_GET(btree->hashval, ARCH_CONVERT) > hashval) + probe -= span; + else + break; + } + ASSERT((probe >= 0) && (probe < max)); + ASSERT((span <= 4) || (INT_GET(btree->hashval, ARCH_CONVERT) == hashval)); + + /* + * Since we may have duplicate hashval's, find the first + * matching hashval in the node. + */ + while ((probe > 0) && (INT_GET(btree->hashval, ARCH_CONVERT) >= hashval)) { + btree--; + probe--; + } + while ((probe < max) && (INT_GET(btree->hashval, ARCH_CONVERT) < hashval)) { + btree++; + probe++; + } + + /* + * Pick the right block to descend on. + */ + if (probe == max) { + blk->index = max-1; + blkno = INT_GET(node->btree[ max-1 ].before, ARCH_CONVERT); + } else { + blk->index = probe; + blkno = INT_GET(btree->before, ARCH_CONVERT); + } + } +#ifdef __KERNEL__ + else if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC) { + blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL); + break; + } +#endif + else if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC) { + blk->hashval = xfs_dir_leaf_lasthash(blk->bp, NULL); + break; + } + else if (INT_GET(curr->magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC) { + blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, NULL); + break; + } + } + + /* + * A leaf block that ends in the hashval that we are interested in + * (final hashval == search hashval) means that the next block may + * contain more entries with the same hashval, shift upward to the + * next leaf and keep searching. + */ + for (;;) { + if (blk->magic == XFS_DIR_LEAF_MAGIC) { + ASSERT(XFS_DIR_IS_V1(state->mp)); + retval = xfs_dir_leaf_lookup_int(blk->bp, state->args, + &blk->index); + } else if (blk->magic == XFS_DIR2_LEAFN_MAGIC) { + ASSERT(XFS_DIR_IS_V2(state->mp)); + retval = xfs_dir2_leafn_lookup_int(blk->bp, state->args, + &blk->index, state); + } +#ifdef __KERNEL__ + else if (blk->magic == XFS_ATTR_LEAF_MAGIC) { + retval = xfs_attr_leaf_lookup_int(blk->bp, state->args); + blk->index = state->args->index; + state->args->blkno = blk->blkno; + } +#endif + if (((retval == ENOENT) || (retval == ENOATTR)) && + (blk->hashval == state->args->hashval)) { + error = xfs_da_path_shift(state, &state->path, 1, 1, + &retval); + if (error) + return(error); + if (retval == 0) { + continue; + } +#ifdef __KERNEL__ + else if (blk->magic == XFS_ATTR_LEAF_MAGIC) { + /* path_shift() gives ENOENT */ + retval = XFS_ERROR(ENOATTR); + } +#endif + } + break; + } + *result = retval; + return(0); +} + +/*======================================================================== + * Utility routines. + *========================================================================*/ + +/* + * Link a new block into a doubly linked list of blocks (of whatever type). + */ +int /* error */ +xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk, + xfs_da_state_blk_t *new_blk) +{ + xfs_da_blkinfo_t *old_info, *new_info, *tmp_info; + xfs_da_args_t *args; + int before=0, error; + xfs_dabuf_t *bp; + + /* + * Set up environment. + */ + args = state->args; + ASSERT(args != NULL); + old_info = old_blk->bp->data; + new_info = new_blk->bp->data; + ASSERT(old_blk->magic == XFS_DA_NODE_MAGIC || + old_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp) || + old_blk->magic == XFS_ATTR_LEAF_MAGIC); + ASSERT(old_blk->magic == INT_GET(old_info->magic, ARCH_CONVERT)); + ASSERT(new_blk->magic == INT_GET(new_info->magic, ARCH_CONVERT)); + ASSERT(old_blk->magic == new_blk->magic); + + switch (old_blk->magic) { +#ifdef __KERNEL__ + case XFS_ATTR_LEAF_MAGIC: + before = xfs_attr_leaf_order(old_blk->bp, new_blk->bp); + break; +#endif + case XFS_DIR_LEAF_MAGIC: + ASSERT(XFS_DIR_IS_V1(state->mp)); + before = xfs_dir_leaf_order(old_blk->bp, new_blk->bp); + break; + case XFS_DIR2_LEAFN_MAGIC: + ASSERT(XFS_DIR_IS_V2(state->mp)); + before = xfs_dir2_leafn_order(old_blk->bp, new_blk->bp); + break; + case XFS_DA_NODE_MAGIC: + before = xfs_da_node_order(old_blk->bp, new_blk->bp); + break; + } + + /* + * Link blocks in appropriate order. + */ + if (before) { + /* + * Link new block in before existing block. + */ + INT_SET(new_info->forw, ARCH_CONVERT, old_blk->blkno); + new_info->back = old_info->back; /* INT_: direct copy */ + if (INT_GET(old_info->back, ARCH_CONVERT)) { + error = xfs_da_read_buf(args->trans, args->dp, + INT_GET(old_info->back, + ARCH_CONVERT), -1, &bp, + args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + tmp_info = bp->data; + ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT) == INT_GET(old_info->magic, ARCH_CONVERT)); + ASSERT(INT_GET(tmp_info->forw, ARCH_CONVERT) == old_blk->blkno); + INT_SET(tmp_info->forw, ARCH_CONVERT, new_blk->blkno); + xfs_da_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1); + xfs_da_buf_done(bp); + } + INT_SET(old_info->back, ARCH_CONVERT, new_blk->blkno); + } else { + /* + * Link new block in after existing block. + */ + new_info->forw = old_info->forw; /* INT_: direct copy */ + INT_SET(new_info->back, ARCH_CONVERT, old_blk->blkno); + if (INT_GET(old_info->forw, ARCH_CONVERT)) { + error = xfs_da_read_buf(args->trans, args->dp, + INT_GET(old_info->forw, ARCH_CONVERT), -1, &bp, + args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + tmp_info = bp->data; + ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT) + == INT_GET(old_info->magic, ARCH_CONVERT)); + ASSERT(INT_GET(tmp_info->back, ARCH_CONVERT) + == old_blk->blkno); + INT_SET(tmp_info->back, ARCH_CONVERT, new_blk->blkno); + xfs_da_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1); + xfs_da_buf_done(bp); + } + INT_SET(old_info->forw, ARCH_CONVERT, new_blk->blkno); + } + + xfs_da_log_buf(args->trans, old_blk->bp, 0, sizeof(*tmp_info) - 1); + xfs_da_log_buf(args->trans, new_blk->bp, 0, sizeof(*tmp_info) - 1); + return(0); +} + +/* + * Compare two intermediate nodes for "order". + */ +STATIC int +xfs_da_node_order(xfs_dabuf_t *node1_bp, xfs_dabuf_t *node2_bp) +{ + xfs_da_intnode_t *node1, *node2; + + node1 = node1_bp->data; + node2 = node2_bp->data; + ASSERT((INT_GET(node1->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) && + (INT_GET(node2->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC)); + if ((INT_GET(node1->hdr.count, ARCH_CONVERT) > 0) && (INT_GET(node2->hdr.count, ARCH_CONVERT) > 0) && + ((INT_GET(node2->btree[ 0 ].hashval, ARCH_CONVERT) < + INT_GET(node1->btree[ 0 ].hashval, ARCH_CONVERT)) || + (INT_GET(node2->btree[ INT_GET(node2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) < + INT_GET(node1->btree[ INT_GET(node1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)))) { + return(1); + } + return(0); +} + +/* + * Pick up the last hashvalue from an intermediate node. + */ +STATIC uint +xfs_da_node_lasthash(xfs_dabuf_t *bp, int *count) +{ + xfs_da_intnode_t *node; + + node = bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + if (count) + *count = INT_GET(node->hdr.count, ARCH_CONVERT); + if (INT_GET(node->hdr.count, ARCH_CONVERT) == 0) + return(0); + return(INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)); +} + +/* + * Unlink a block from a doubly linked list of blocks. + */ +int /* error */ +xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk) +{ + xfs_da_blkinfo_t *drop_info, *save_info, *tmp_info; + xfs_da_args_t *args; + xfs_dabuf_t *bp; + int error; + + /* + * Set up environment. + */ + args = state->args; + ASSERT(args != NULL); + save_info = save_blk->bp->data; + drop_info = drop_blk->bp->data; + ASSERT(save_blk->magic == XFS_DA_NODE_MAGIC || + save_blk->magic == XFS_DIRX_LEAF_MAGIC(state->mp) || + save_blk->magic == XFS_ATTR_LEAF_MAGIC); + ASSERT(save_blk->magic == INT_GET(save_info->magic, ARCH_CONVERT)); + ASSERT(drop_blk->magic == INT_GET(drop_info->magic, ARCH_CONVERT)); + ASSERT(save_blk->magic == drop_blk->magic); + ASSERT((INT_GET(save_info->forw, ARCH_CONVERT) == drop_blk->blkno) || + (INT_GET(save_info->back, ARCH_CONVERT) == drop_blk->blkno)); + ASSERT((INT_GET(drop_info->forw, ARCH_CONVERT) == save_blk->blkno) || + (INT_GET(drop_info->back, ARCH_CONVERT) == save_blk->blkno)); + + /* + * Unlink the leaf block from the doubly linked chain of leaves. + */ + if (INT_GET(save_info->back, ARCH_CONVERT) == drop_blk->blkno) { + save_info->back = drop_info->back; /* INT_: direct copy */ + if (INT_GET(drop_info->back, ARCH_CONVERT)) { + error = xfs_da_read_buf(args->trans, args->dp, + INT_GET(drop_info->back, + ARCH_CONVERT), -1, &bp, + args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + tmp_info = bp->data; + ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT) == INT_GET(save_info->magic, ARCH_CONVERT)); + ASSERT(INT_GET(tmp_info->forw, ARCH_CONVERT) == drop_blk->blkno); + INT_SET(tmp_info->forw, ARCH_CONVERT, save_blk->blkno); + xfs_da_log_buf(args->trans, bp, 0, + sizeof(*tmp_info) - 1); + xfs_da_buf_done(bp); + } + } else { + save_info->forw = drop_info->forw; /* INT_: direct copy */ + if (INT_GET(drop_info->forw, ARCH_CONVERT)) { + error = xfs_da_read_buf(args->trans, args->dp, + INT_GET(drop_info->forw, ARCH_CONVERT), -1, &bp, + args->whichfork); + if (error) + return(error); + ASSERT(bp != NULL); + tmp_info = bp->data; + ASSERT(INT_GET(tmp_info->magic, ARCH_CONVERT) + == INT_GET(save_info->magic, ARCH_CONVERT)); + ASSERT(INT_GET(tmp_info->back, ARCH_CONVERT) + == drop_blk->blkno); + INT_SET(tmp_info->back, ARCH_CONVERT, save_blk->blkno); + xfs_da_log_buf(args->trans, bp, 0, + sizeof(*tmp_info) - 1); + xfs_da_buf_done(bp); + } + } + + xfs_da_log_buf(args->trans, save_blk->bp, 0, sizeof(*save_info) - 1); + return(0); +} + +/* + * Move a path "forward" or "!forward" one block at the current level. + * + * This routine will adjust a "path" to point to the next block + * "forward" (higher hashvalues) or "!forward" (lower hashvals) in the + * Btree, including updating pointers to the intermediate nodes between + * the new bottom and the root. + */ +int /* error */ +xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path, + int forward, int release, int *result) +{ + xfs_da_state_blk_t *blk; + xfs_da_blkinfo_t *info; + xfs_da_intnode_t *node; + xfs_da_args_t *args; + xfs_dablk_t blkno=0; + int level, error; + + /* + * Roll up the Btree looking for the first block where our + * current index is not at the edge of the block. Note that + * we skip the bottom layer because we want the sibling block. + */ + args = state->args; + ASSERT(args != NULL); + ASSERT(path != NULL); + ASSERT((path->active > 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); + level = (path->active-1) - 1; /* skip bottom layer in path */ + for (blk = &path->blk[level]; level >= 0; blk--, level--) { + ASSERT(blk->bp != NULL); + node = blk->bp->data; + ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + if (forward && (blk->index < INT_GET(node->hdr.count, ARCH_CONVERT)-1)) { + blk->index++; + blkno = INT_GET(node->btree[ blk->index ].before, ARCH_CONVERT); + break; + } else if (!forward && (blk->index > 0)) { + blk->index--; + blkno = INT_GET(node->btree[ blk->index ].before, ARCH_CONVERT); + break; + } + } + if (level < 0) { + *result = XFS_ERROR(ENOENT); /* we're out of our tree */ + ASSERT(args->oknoent); + return(0); + } + + /* + * Roll down the edge of the subtree until we reach the + * same depth we were at originally. + */ + for (blk++, level++; level < path->active; blk++, level++) { + /* + * Release the old block. + * (if it's dirty, trans won't actually let go) + */ + if (release) + xfs_da_brelse(args->trans, blk->bp); + + /* + * Read the next child block. + */ + blk->blkno = blkno; + error = xfs_da_read_buf(args->trans, args->dp, blkno, -1, + &blk->bp, args->whichfork); + if (error) + return(error); + ASSERT(blk->bp != NULL); + info = blk->bp->data; + ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC || + INT_GET(info->magic, ARCH_CONVERT) == XFS_DIRX_LEAF_MAGIC(state->mp) || + INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC); + blk->magic = INT_GET(info->magic, ARCH_CONVERT); + if (INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) { + node = (xfs_da_intnode_t *)info; + blk->hashval = INT_GET(node->btree[ INT_GET(node->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + if (forward) + blk->index = 0; + else + blk->index = INT_GET(node->hdr.count, ARCH_CONVERT)-1; + blkno = INT_GET(node->btree[ blk->index ].before, ARCH_CONVERT); + } else { + ASSERT(level == path->active-1); + blk->index = 0; + switch(blk->magic) { +#ifdef __KERNEL__ + case XFS_ATTR_LEAF_MAGIC: + blk->hashval = xfs_attr_leaf_lasthash(blk->bp, + NULL); + break; +#endif + case XFS_DIR_LEAF_MAGIC: + ASSERT(XFS_DIR_IS_V1(state->mp)); + blk->hashval = xfs_dir_leaf_lasthash(blk->bp, + NULL); + break; + case XFS_DIR2_LEAFN_MAGIC: + ASSERT(XFS_DIR_IS_V2(state->mp)); + blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, + NULL); + break; + default: + ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC || + blk->magic == + XFS_DIRX_LEAF_MAGIC(state->mp)); + break; + } + } + } + *result = 0; + return(0); +} + + +/*======================================================================== + * Utility routines. + *========================================================================*/ + +/* + * Implement a simple hash on a character string. + * Rotate the hash value by 7 bits, then XOR each character in. + * This is implemented with some source-level loop unrolling. + */ +xfs_dahash_t +xfs_da_hashname(char *name, int namelen) +{ + xfs_dahash_t hash; + +#define ROTL(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#ifdef SLOWVERSION + /* + * This is the old one-byte-at-a-time version. + */ + for (hash = 0; namelen > 0; namelen--) { + hash = *name++ ^ ROTL(hash, 7); + } + return(hash); +#else + /* + * Do four characters at a time as long as we can. + */ + for (hash = 0; namelen >= 4; namelen -= 4, name += 4) { + hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^ + (name[3] << 0) ^ ROTL(hash, 7 * 4); + } + /* + * Now do the rest of the characters. + */ + switch (namelen) { + case 3: + return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^ + ROTL(hash, 7 * 3); + case 2: + return (name[0] << 7) ^ (name[1] << 0) ^ ROTL(hash, 7 * 2); + case 1: + return (name[0] << 0) ^ ROTL(hash, 7 * 1); + case 0: + return hash; + } + /* NOTREACHED */ +#endif +#undef ROTL + return 0; /* keep gcc happy */ +} + +/* + * Add a block to the btree ahead of the file. + * Return the new block number to the caller. + */ +int +xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno) +{ + xfs_fileoff_t bno, b; + xfs_bmbt_irec_t map; + xfs_bmbt_irec_t *mapp; + xfs_inode_t *dp; + int nmap, error, w, count, c, got, i, mapi; + xfs_fsize_t size; + xfs_trans_t *tp; + xfs_mount_t *mp; + + dp = args->dp; + mp = dp->i_mount; + w = args->whichfork; + tp = args->trans; + /* + * For new directories adjust the file offset and block count. + */ + if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) { + bno = mp->m_dirleafblk; + count = mp->m_dirblkfsbs; + } else { + bno = 0; + count = 1; + } + /* + * Find a spot in the file space to put the new block. + */ + if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, w))) { + return error; + } + if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) + ASSERT(bno >= mp->m_dirleafblk && bno < mp->m_dirfreeblk); + /* + * Try mapping it in one filesystem block. + */ + nmap = 1; + ASSERT(args->firstblock != NULL); + if ((error = xfs_bmapi(tp, dp, bno, count, + XFS_BMAPI_AFLAG(w)|XFS_BMAPI_WRITE|XFS_BMAPI_METADATA| + XFS_BMAPI_CONTIG, + args->firstblock, args->total, &map, &nmap, + args->flist))) { + return error; + } + ASSERT(nmap <= 1); + if (nmap == 1) { + mapp = ↦ + mapi = 1; + } + /* + * If we didn't get it and the block might work if fragmented, + * try without the CONTIG flag. Loop until we get it all. + */ + else if (nmap == 0 && count > 1) { + mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP); + for (b = bno, mapi = 0; b < bno + count; ) { + nmap = MIN(XFS_BMAP_MAX_NMAP, count); + c = (int)(bno + count - b); + if ((error = xfs_bmapi(tp, dp, b, c, + XFS_BMAPI_AFLAG(w)|XFS_BMAPI_WRITE| + XFS_BMAPI_METADATA, + args->firstblock, args->total, + &mapp[mapi], &nmap, args->flist))) { + kmem_free(mapp, sizeof(*mapp) * count); + return error; + } + if (nmap < 1) + break; + mapi += nmap; + b = mapp[mapi - 1].br_startoff + + mapp[mapi - 1].br_blockcount; + } + } else { + mapi = 0; + mapp = NULL; + } + /* + * Count the blocks we got, make sure it matches the total. + */ + for (i = 0, got = 0; i < mapi; i++) + got += mapp[i].br_blockcount; + if (got != count || mapp[0].br_startoff != bno || + mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != + bno + count) { + if (mapp != &map) + kmem_free(mapp, sizeof(*mapp) * count); + return XFS_ERROR(ENOSPC); + } + if (mapp != &map) + kmem_free(mapp, sizeof(*mapp) * count); + *new_blkno = (xfs_dablk_t)bno; + /* + * For version 1 directories, adjust the file size if it changed. + */ + if (w == XFS_DATA_FORK && XFS_DIR_IS_V1(mp)) { + ASSERT(mapi == 1); + if ((error = xfs_bmap_last_offset(tp, dp, &bno, w))) + return error; + size = XFS_FSB_TO_B(mp, bno); + if (size != dp->i_d.di_size) { + dp->i_d.di_size = size; + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + } + } + return 0; +} + +/* + * Ick. We need to always be able to remove a btree block, even + * if there's no space reservation because the filesystem is full. + * This is called if xfs_bunmapi on a btree block fails due to ENOSPC. + * It swaps the target block with the last block in the file. The + * last block in the file can always be removed since it can't cause + * a bmap btree split to do that. + */ +STATIC int +xfs_da_swap_lastblock(xfs_da_args_t *args, xfs_dablk_t *dead_blknop, + xfs_dabuf_t **dead_bufp) +{ + xfs_dablk_t dead_blkno, last_blkno, sib_blkno, par_blkno; + xfs_dabuf_t *dead_buf, *last_buf, *sib_buf, *par_buf; + xfs_fileoff_t lastoff; + xfs_inode_t *ip; + xfs_trans_t *tp; + xfs_mount_t *mp; + int error, w, entno, level, dead_level; + xfs_da_blkinfo_t *dead_info, *sib_info; + xfs_da_intnode_t *par_node, *dead_node; + xfs_dir_leafblock_t *dead_leaf; + xfs_dir2_leaf_t *dead_leaf2; + xfs_dahash_t dead_hash; + + dead_buf = *dead_bufp; + dead_blkno = *dead_blknop; + tp = args->trans; + ip = args->dp; + w = args->whichfork; + ASSERT(w == XFS_DATA_FORK); + mp = ip->i_mount; + if (XFS_DIR_IS_V2(mp)) { + lastoff = mp->m_dirfreeblk; + error = xfs_bmap_last_before(tp, ip, &lastoff, w); + } else + error = xfs_bmap_last_offset(tp, ip, &lastoff, w); + if (error) + return error; + if (lastoff == 0) + return XFS_ERROR(EFSCORRUPTED); + /* + * Read the last block in the btree space. + */ + last_blkno = (xfs_dablk_t)lastoff - mp->m_dirblkfsbs; + if ((error = xfs_da_read_buf(tp, ip, last_blkno, -1, &last_buf, w))) + return error; + /* + * Copy the last block into the dead buffer and log it. + */ + bcopy(last_buf->data, dead_buf->data, mp->m_dirblksize); + xfs_da_log_buf(tp, dead_buf, 0, mp->m_dirblksize - 1); + dead_info = dead_buf->data; + /* + * Get values from the moved block. + */ + if (INT_GET(dead_info->magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC) { + ASSERT(XFS_DIR_IS_V1(mp)); + dead_leaf = (xfs_dir_leafblock_t *)dead_info; + dead_level = 0; + dead_hash = + INT_GET(dead_leaf->entries[INT_GET(dead_leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); + } else if (INT_GET(dead_info->magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC) { + ASSERT(XFS_DIR_IS_V2(mp)); + dead_leaf2 = (xfs_dir2_leaf_t *)dead_info; + dead_level = 0; + dead_hash = INT_GET(dead_leaf2->ents[INT_GET(dead_leaf2->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); + } else { + ASSERT(INT_GET(dead_info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC); + dead_node = (xfs_da_intnode_t *)dead_info; + dead_level = INT_GET(dead_node->hdr.level, ARCH_CONVERT); + dead_hash = INT_GET(dead_node->btree[INT_GET(dead_node->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); + } + sib_buf = par_buf = NULL; + /* + * If the moved block has a left sibling, fix up the pointers. + */ + if ((sib_blkno = INT_GET(dead_info->back, ARCH_CONVERT))) { + if ((error = xfs_da_read_buf(tp, ip, sib_blkno, -1, &sib_buf, w))) + goto done; + sib_info = sib_buf->data; + if (INT_GET(sib_info->forw, ARCH_CONVERT) != last_blkno || + INT_GET(sib_info->magic, ARCH_CONVERT) != INT_GET(dead_info->magic, ARCH_CONVERT)) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + INT_SET(sib_info->forw, ARCH_CONVERT, dead_blkno); + xfs_da_log_buf(tp, sib_buf, + XFS_DA_LOGRANGE(sib_info, &sib_info->forw, + sizeof(sib_info->forw))); + xfs_da_buf_done(sib_buf); + sib_buf = NULL; + } + /* + * If the moved block has a right sibling, fix up the pointers. + */ + if ((sib_blkno = INT_GET(dead_info->forw, ARCH_CONVERT))) { + if ((error = xfs_da_read_buf(tp, ip, sib_blkno, -1, &sib_buf, w))) + goto done; + sib_info = sib_buf->data; + if ( INT_GET(sib_info->back, ARCH_CONVERT) != last_blkno + || INT_GET(sib_info->magic, ARCH_CONVERT) + != INT_GET(dead_info->magic, ARCH_CONVERT)) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + INT_SET(sib_info->back, ARCH_CONVERT, dead_blkno); + xfs_da_log_buf(tp, sib_buf, + XFS_DA_LOGRANGE(sib_info, &sib_info->back, + sizeof(sib_info->back))); + xfs_da_buf_done(sib_buf); + sib_buf = NULL; + } + par_blkno = XFS_DIR_IS_V1(mp) ? 0 : mp->m_dirleafblk; + level = -1; + /* + * Walk down the tree looking for the parent of the moved block. + */ + for (;;) { + if ((error = xfs_da_read_buf(tp, ip, par_blkno, -1, &par_buf, w))) + goto done; + par_node = par_buf->data; + if (INT_GET(par_node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC || + (level >= 0 && level != INT_GET(par_node->hdr.level, ARCH_CONVERT) + 1)) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + level = INT_GET(par_node->hdr.level, ARCH_CONVERT); + for (entno = 0; + entno < INT_GET(par_node->hdr.count, ARCH_CONVERT) && + INT_GET(par_node->btree[entno].hashval, ARCH_CONVERT) < dead_hash; + entno++) + continue; + if (entno == INT_GET(par_node->hdr.count, ARCH_CONVERT)) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + par_blkno = INT_GET(par_node->btree[entno].before, ARCH_CONVERT); + if (level == dead_level + 1) + break; + xfs_da_brelse(tp, par_buf); + par_buf = NULL; + } + /* + * We're in the right parent block. + * Look for the right entry. + */ + for (;;) { + for (; + entno < INT_GET(par_node->hdr.count, ARCH_CONVERT) && + INT_GET(par_node->btree[entno].before, ARCH_CONVERT) != last_blkno; + entno++) + continue; + if (entno < INT_GET(par_node->hdr.count, ARCH_CONVERT)) + break; + par_blkno = INT_GET(par_node->hdr.info.forw, ARCH_CONVERT); + xfs_da_brelse(tp, par_buf); + par_buf = NULL; + if (par_blkno == 0) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + if ((error = xfs_da_read_buf(tp, ip, par_blkno, -1, &par_buf, w))) + goto done; + par_node = par_buf->data; + if (INT_GET(par_node->hdr.level, ARCH_CONVERT) != level || + INT_GET(par_node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) { + error = XFS_ERROR(EFSCORRUPTED); + goto done; + } + entno = 0; + } + /* + * Update the parent entry pointing to the moved block. + */ + INT_SET(par_node->btree[entno].before, ARCH_CONVERT, dead_blkno); + xfs_da_log_buf(tp, par_buf, + XFS_DA_LOGRANGE(par_node, &par_node->btree[entno].before, + sizeof(par_node->btree[entno].before))); + xfs_da_buf_done(par_buf); + xfs_da_buf_done(dead_buf); + *dead_blknop = last_blkno; + *dead_bufp = last_buf; + return 0; +done: + if (par_buf) + xfs_da_brelse(tp, par_buf); + if (sib_buf) + xfs_da_brelse(tp, sib_buf); + xfs_da_brelse(tp, last_buf); + return error; +} + +/* + * Remove a btree block from a directory or attribute. + */ +int +xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, + xfs_dabuf_t *dead_buf) +{ + xfs_inode_t *dp; + int done, error, w, count; + xfs_fileoff_t bno; + xfs_fsize_t size; + xfs_trans_t *tp; + xfs_mount_t *mp; + + dp = args->dp; + w = args->whichfork; + tp = args->trans; + mp = dp->i_mount; + if (w == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) + count = mp->m_dirblkfsbs; + else + count = 1; + for (;;) { + /* + * Remove extents. If we get ENOSPC for a dir we have to move + * the last block to the place we want to kill. + */ + if ((error = xfs_bunmapi(tp, dp, dead_blkno, count, + XFS_BMAPI_AFLAG(w)|XFS_BMAPI_METADATA, + 0, args->firstblock, args->flist, + &done)) == ENOSPC) { + if (w != XFS_DATA_FORK) + goto done; + if ((error = xfs_da_swap_lastblock(args, &dead_blkno, + &dead_buf))) + goto done; + } else if (error) + goto done; + else + break; + } + ASSERT(done); + xfs_da_binval(tp, dead_buf); + /* + * Adjust the directory size for version 1. + */ + if (w == XFS_DATA_FORK && XFS_DIR_IS_V1(mp)) { + if ((error = xfs_bmap_last_offset(tp, dp, &bno, w))) + return error; + size = XFS_FSB_TO_B(dp->i_mount, bno); + if (size != dp->i_d.di_size) { + dp->i_d.di_size = size; + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + } + } + return 0; +done: + xfs_da_binval(tp, dead_buf); + return error; +} + +/* + * See if the mapping(s) for this btree block are valid, i.e. + * don't contain holes, are logically contiguous, and cover the whole range. + */ +STATIC int +xfs_da_map_covers_blocks( + int nmap, + xfs_bmbt_irec_t *mapp, + xfs_dablk_t bno, + int count) +{ + int i; + xfs_fileoff_t off; + + for (i = 0, off = bno; i < nmap; i++) { + if (mapp[i].br_startblock == HOLESTARTBLOCK || + mapp[i].br_startblock == DELAYSTARTBLOCK) { + return 0; + } + if (off != mapp[i].br_startoff) { + return 0; + } + off += mapp[i].br_blockcount; + } + return off == bno + count; +} + +/* + * Make a dabuf. + * Used for get_buf, read_buf, read_bufr, and reada_buf. + */ +STATIC int +xfs_da_do_buf( + xfs_trans_t *trans, + xfs_inode_t *dp, + xfs_dablk_t bno, + xfs_daddr_t *mappedbnop, + xfs_dabuf_t **bpp, + int whichfork, + int caller, + inst_t *ra) +{ + xfs_buf_t *bp = 0; + xfs_buf_t **bplist; + int error=0; + int i; + xfs_bmbt_irec_t map; + xfs_bmbt_irec_t *mapp; + xfs_daddr_t mappedbno; + xfs_mount_t *mp; + int nbplist=0; + int nfsb; + int nmap; + int mem_flags = trans ? KM_SLEEP : KM_SLEEP_IO; + xfs_dabuf_t *rbp; + + mp = dp->i_mount; + if (whichfork == XFS_DATA_FORK && XFS_DIR_IS_V2(mp)) + nfsb = mp->m_dirblkfsbs; + else + nfsb = 1; + mappedbno = *mappedbnop; + /* + * Caller doesn't have a mapping. -2 means don't complain + * if we land in a hole. + */ + if (mappedbno == -1 || mappedbno == -2) { + /* + * Optimize the one-block case. + */ + if (nfsb == 1) { + xfs_fsblock_t fsb; + + if ((error = + xfs_bmapi_single(trans, dp, whichfork, &fsb, + (xfs_fileoff_t)bno))) { + return error; + } + mapp = ↦ + if (fsb == NULLFSBLOCK) { + nmap = 0; + } else { + map.br_startblock = fsb; + map.br_startoff = (xfs_fileoff_t)bno; + map.br_blockcount = 1; + nmap = 1; + } + } else { + xfs_fsblock_t firstblock; + + firstblock = NULLFSBLOCK; + mapp = kmem_alloc(sizeof(*mapp) * nfsb, mem_flags); + nmap = nfsb; + if ((error = xfs_bmapi(trans, dp, (xfs_fileoff_t)bno, + nfsb, + XFS_BMAPI_METADATA | + XFS_BMAPI_AFLAG(whichfork), + &firstblock, 0, mapp, &nmap, NULL))) + goto exit0; + } + } else { + map.br_startblock = XFS_DADDR_TO_FSB(mp, mappedbno); + map.br_startoff = (xfs_fileoff_t)bno; + map.br_blockcount = nfsb; + mapp = ↦ + nmap = 1; + } + if (!xfs_da_map_covers_blocks(nmap, mapp, bno, nfsb)) { + error = mappedbno == -2 ? 0 : XFS_ERROR(EFSCORRUPTED); + goto exit0; + } + if (caller != 3 && nmap > 1) { + bplist = kmem_alloc(sizeof(*bplist) * nmap, mem_flags); + nbplist = 0; + } else + bplist = NULL; + /* + * Turn the mapping(s) into buffer(s). + */ + for (i = 0; i < nmap; i++) { + int nmapped; + + mappedbno = XFS_FSB_TO_DADDR(mp, mapp[i].br_startblock); + if (i == 0) + *mappedbnop = mappedbno; + nmapped = (int)XFS_FSB_TO_BB(mp, mapp[i].br_blockcount); + switch (caller) { + case 0: + bp = xfs_trans_get_buf(trans, mp->m_ddev_targp, + mappedbno, nmapped, 0); + error = bp ? XFS_BUF_GETERROR(bp) : XFS_ERROR(EIO); + break; + case 1: +#ifndef __KERNEL__ + case 2: +#endif + bp = NULL; + error = xfs_trans_read_buf(mp, trans, mp->m_ddev_targp, + mappedbno, nmapped, 0, &bp); + break; +#ifdef __KERNEL__ + case 3: + xfs_baread(mp->m_ddev_targp, mappedbno, nmapped); + error = 0; + bp = NULL; + break; +#endif + } + if (error) { + if (bp) + xfs_trans_brelse(trans, bp); + goto exit1; + } + if (!bp) + continue; + if (caller == 1) { + if (whichfork == XFS_ATTR_FORK) { + XFS_BUF_SET_VTYPE_REF(bp, B_FS_ATTR_BTREE, + XFS_ATTR_BTREE_REF); + } else { + XFS_BUF_SET_VTYPE_REF(bp, B_FS_DIR_BTREE, + XFS_DIR_BTREE_REF); + } + } + if (bplist) { + bplist[nbplist++] = bp; + } + } + /* + * Build a dabuf structure. + */ + if (bplist) { + rbp = xfs_da_buf_make(nbplist, bplist, ra, mem_flags); + } else if (bp) + rbp = xfs_da_buf_make(1, &bp, ra, mem_flags); + else + rbp = NULL; + /* + * For read_buf, check the magic number. + */ + if (caller == 1) { + xfs_dir2_data_t *data; + xfs_dir2_free_t *free; + xfs_da_blkinfo_t *info; + + info = rbp->data; + data = rbp->data; + free = rbp->data; + if (XFS_TEST_ERROR((INT_GET(info->magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) && + (INT_GET(info->magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) && + (INT_GET(info->magic, ARCH_CONVERT) != XFS_ATTR_LEAF_MAGIC) && + (INT_GET(info->magic, ARCH_CONVERT) != XFS_DIR2_LEAF1_MAGIC) && + (INT_GET(info->magic, ARCH_CONVERT) != XFS_DIR2_LEAFN_MAGIC) && + (INT_GET(data->hdr.magic, ARCH_CONVERT) != XFS_DIR2_BLOCK_MAGIC) && + (INT_GET(data->hdr.magic, ARCH_CONVERT) != XFS_DIR2_DATA_MAGIC) && + (INT_GET(free->hdr.magic, ARCH_CONVERT) != XFS_DIR2_FREE_MAGIC), + mp, XFS_ERRTAG_DA_READ_BUF, + XFS_RANDOM_DA_READ_BUF)) { + xfs_buftrace("DA READ ERROR", rbp->bps[0]); + error = XFS_ERROR(EFSCORRUPTED); + xfs_da_brelse(trans, rbp); + nbplist = 0; + goto exit1; + } + } + if (bplist) { + kmem_free(bplist, sizeof(*bplist) * nmap); + } + if (mapp != &map) { + kmem_free(mapp, sizeof(*mapp) * nfsb); + } + if (bpp) + *bpp = rbp; + return 0; +exit1: + if (bplist) { + for (i = 0; i < nbplist; i++) + xfs_trans_brelse(trans, bplist[i]); + kmem_free(bplist, sizeof(*bplist) * nmap); + } +exit0: + if (mapp != &map) + kmem_free(mapp, sizeof(*mapp) * nfsb); + if (bpp) + *bpp = NULL; + return error; +} + +/* + * Get a buffer for the dir/attr block. + */ +int +xfs_da_get_buf( + xfs_trans_t *trans, + xfs_inode_t *dp, + xfs_dablk_t bno, + xfs_daddr_t mappedbno, + xfs_dabuf_t **bpp, + int whichfork) +{ + return xfs_da_do_buf(trans, dp, bno, &mappedbno, bpp, whichfork, 0, + (inst_t *)__return_address); +} + +/* + * Get a buffer for the dir/attr block, fill in the contents. + */ +int +xfs_da_read_buf( + xfs_trans_t *trans, + xfs_inode_t *dp, + xfs_dablk_t bno, + xfs_daddr_t mappedbno, + xfs_dabuf_t **bpp, + int whichfork) +{ + return xfs_da_do_buf(trans, dp, bno, &mappedbno, bpp, whichfork, 1, + (inst_t *)__return_address); +} + +/* + * Readahead the dir/attr block. + */ +xfs_daddr_t +xfs_da_reada_buf( + xfs_trans_t *trans, + xfs_inode_t *dp, + xfs_dablk_t bno, + int whichfork) +{ + xfs_daddr_t rval; + + rval = -1; + if (xfs_da_do_buf(trans, dp, bno, &rval, NULL, whichfork, 3, + (inst_t *)__return_address)) + return -1; + else + return rval; +} + +/* + * Calculate the number of bits needed to hold i different values. + */ +uint +xfs_da_log2_roundup(uint i) +{ + uint rval; + + for (rval = 0; rval < NBBY * sizeof(i); rval++) { + if ((1 << rval) >= i) + break; + } + return(rval); +} + +xfs_zone_t *xfs_da_state_zone; /* anchor for state struct zone */ +xfs_zone_t *xfs_dabuf_zone; /* dabuf zone */ + +/* + * Allocate a dir-state structure. + * We don't put them on the stack since they're large. + */ +xfs_da_state_t * +xfs_da_state_alloc(void) +{ + return kmem_zone_zalloc(xfs_da_state_zone, KM_SLEEP); +} + +/* + * Kill the altpath contents of a da-state structure. + */ +void +xfs_da_state_kill_altpath(xfs_da_state_t *state) +{ + int i; + + for (i = 0; i < state->altpath.active; i++) { + if (state->altpath.blk[i].bp) { + if (state->altpath.blk[i].bp != state->path.blk[i].bp) + xfs_da_buf_done(state->altpath.blk[i].bp); + state->altpath.blk[i].bp = NULL; + } + } + state->altpath.active = 0; +} + +/* + * Free a da-state structure. + */ +void +xfs_da_state_free(xfs_da_state_t *state) +{ + int i; + + xfs_da_state_kill_altpath(state); + for (i = 0; i < state->path.active; i++) { + if (state->path.blk[i].bp) + xfs_da_buf_done(state->path.blk[i].bp); + } + if (state->extravalid && state->extrablk.bp) + xfs_da_buf_done(state->extrablk.bp); +#ifdef DEBUG + bzero((char *)state, sizeof(*state)); +#endif /* DEBUG */ + kmem_zone_free(xfs_da_state_zone, state); +} + +#ifdef XFS_DABUF_DEBUG +xfs_dabuf_t *xfs_dabuf_global_list; +lock_t xfs_dabuf_global_lock; +#endif + +/* + * Create a dabuf. + */ +/* ARGSUSED */ +STATIC xfs_dabuf_t * +xfs_da_buf_make(int nbuf, xfs_buf_t **bps, inst_t *ra, int mem_flags) +{ + xfs_buf_t *bp; + xfs_dabuf_t *dabuf; + int i; + int off; + + if (nbuf == 1) + dabuf = kmem_zone_alloc(xfs_dabuf_zone, mem_flags); + else + dabuf = kmem_alloc(XFS_DA_BUF_SIZE(nbuf), mem_flags); + dabuf->dirty = 0; +#ifdef XFS_DABUF_DEBUG + dabuf->ra = ra; + dabuf->dev = XFS_BUF_TARGET(bps[0]); + dabuf->blkno = XFS_BUF_ADDR(bps[0]); +#endif + if (nbuf == 1) { + dabuf->nbuf = 1; + bp = bps[0]; + dabuf->bbcount = (short)BTOBB(XFS_BUF_COUNT(bp)); + dabuf->data = XFS_BUF_PTR(bp); + dabuf->bps[0] = bp; + } else { + dabuf->nbuf = nbuf; + for (i = 0, dabuf->bbcount = 0; i < nbuf; i++) { + dabuf->bps[i] = bp = bps[i]; + dabuf->bbcount += BTOBB(XFS_BUF_COUNT(bp)); + } + dabuf->data = kmem_alloc(BBTOB(dabuf->bbcount), KM_SLEEP); + for (i = off = 0; i < nbuf; i++, off += XFS_BUF_COUNT(bp)) { + bp = bps[i]; + bcopy(XFS_BUF_PTR(bp), (char *)dabuf->data + off, + XFS_BUF_COUNT(bp)); + } + } +#ifdef XFS_DABUF_DEBUG + { + int s; + xfs_dabuf_t *p; + + s = mutex_spinlock(&xfs_dabuf_global_lock); + for (p = xfs_dabuf_global_list; p; p = p->next) { + ASSERT(p->blkno != dabuf->blkno || + p->dev != dabuf->dev); + } + dabuf->prev = NULL; + if (xfs_dabuf_global_list) + xfs_dabuf_global_list->prev = dabuf; + dabuf->next = xfs_dabuf_global_list; + xfs_dabuf_global_list = dabuf; + mutex_spinunlock(&xfs_dabuf_global_lock, s); + } +#endif + return dabuf; +} + +/* + * Un-dirty a dabuf. + */ +STATIC void +xfs_da_buf_clean(xfs_dabuf_t *dabuf) +{ + xfs_buf_t *bp; + int i; + int off; + + if (dabuf->dirty) { + ASSERT(dabuf->nbuf > 1); + dabuf->dirty = 0; + for (i = off = 0; i < dabuf->nbuf; + i++, off += XFS_BUF_COUNT(bp)) { + bp = dabuf->bps[i]; + bcopy((char *)dabuf->data + off, XFS_BUF_PTR(bp), + XFS_BUF_COUNT(bp)); + } + } +} + +/* + * Release a dabuf. + */ +void +xfs_da_buf_done(xfs_dabuf_t *dabuf) +{ + ASSERT(dabuf); + ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]); + if (dabuf->dirty) + xfs_da_buf_clean(dabuf); + if (dabuf->nbuf > 1) + kmem_free(dabuf->data, BBTOB(dabuf->bbcount)); +#ifdef XFS_DABUF_DEBUG + { + int s; + + s = mutex_spinlock(&xfs_dabuf_global_lock); + if (dabuf->prev) + dabuf->prev->next = dabuf->next; + else + xfs_dabuf_global_list = dabuf->next; + if (dabuf->next) + dabuf->next->prev = dabuf->prev; + mutex_spinunlock(&xfs_dabuf_global_lock, s); + } + bzero(dabuf, XFS_DA_BUF_SIZE(dabuf->nbuf)); +#endif + if (dabuf->nbuf == 1) + kmem_zone_free(xfs_dabuf_zone, dabuf); + else + kmem_free(dabuf, XFS_DA_BUF_SIZE(dabuf->nbuf)); +} + +/* + * Log transaction from a dabuf. + */ +void +xfs_da_log_buf(xfs_trans_t *tp, xfs_dabuf_t *dabuf, uint first, uint last) +{ + xfs_buf_t *bp; + uint f; + int i; + uint l; + int off; + + ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]); + if (dabuf->nbuf == 1) { + ASSERT(dabuf->data == (void *)XFS_BUF_PTR(dabuf->bps[0])); + xfs_trans_log_buf(tp, dabuf->bps[0], first, last); + return; + } + dabuf->dirty = 1; + ASSERT(first <= last); + for (i = off = 0; i < dabuf->nbuf; i++, off += XFS_BUF_COUNT(bp)) { + bp = dabuf->bps[i]; + f = off; + l = f + XFS_BUF_COUNT(bp) - 1; + if (f < first) + f = first; + if (l > last) + l = last; + if (f <= l) + xfs_trans_log_buf(tp, bp, f - off, l - off); + /* + * B_DONE is set by xfs_trans_log buf. + * If we don't set it on a new buffer (get not read) + * then if we don't put anything in the buffer it won't + * be set, and at commit it it released into the cache, + * and then a read will fail. + */ + else if (!(XFS_BUF_ISDONE(bp))) + XFS_BUF_DONE(bp); + } + ASSERT(last < off); +} + +/* + * Release dabuf from a transaction. + * Have to free up the dabuf before the buffers are released, + * since the synchronization on the dabuf is really the lock on the buffer. + */ +void +xfs_da_brelse(xfs_trans_t *tp, xfs_dabuf_t *dabuf) +{ + xfs_buf_t *bp; + xfs_buf_t **bplist; + int i; + int nbuf; + + ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]); + if ((nbuf = dabuf->nbuf) == 1) { + bplist = &bp; + bp = dabuf->bps[0]; + } else { + bplist = kmem_alloc(nbuf * sizeof(*bplist), KM_SLEEP); + bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist)); + } + xfs_da_buf_done(dabuf); + for (i = 0; i < nbuf; i++) + xfs_trans_brelse(tp, bplist[i]); + if (bplist != &bp) + kmem_free(bplist, nbuf * sizeof(*bplist)); +} + +/* + * Invalidate dabuf from a transaction. + */ +void +xfs_da_binval(xfs_trans_t *tp, xfs_dabuf_t *dabuf) +{ + xfs_buf_t *bp; + xfs_buf_t **bplist; + int i; + int nbuf; + + ASSERT(dabuf->nbuf && dabuf->data && dabuf->bbcount && dabuf->bps[0]); + if ((nbuf = dabuf->nbuf) == 1) { + bplist = &bp; + bp = dabuf->bps[0]; + } else { + bplist = kmem_alloc(nbuf * sizeof(*bplist), KM_SLEEP); + bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist)); + } + xfs_da_buf_done(dabuf); + for (i = 0; i < nbuf; i++) + xfs_trans_binval(tp, bplist[i]); + if (bplist != &bp) + kmem_free(bplist, nbuf * sizeof(*bplist)); +} + +/* + * Get the first daddr from a dabuf. + */ +xfs_daddr_t +xfs_da_blkno(xfs_dabuf_t *dabuf) +{ + ASSERT(dabuf->nbuf); + ASSERT(dabuf->data); + return XFS_BUF_ADDR(dabuf->bps[0]); +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_da_btree.h linux-2.4-xfs/linux/fs/xfs/xfs_da_btree.h --- linux-2.4.7/linux/fs/xfs/xfs_da_btree.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_da_btree.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DA_BTREE_H__ +#define __XFS_DA_BTREE_H__ + +struct xfs_buf; +struct xfs_bmap_free; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; +struct zone; + +/*======================================================================== + * Directory Structure when greater than XFS_LBSIZE(mp) bytes. + *========================================================================*/ + +/* + * This structure is common to both leaf nodes and non-leaf nodes in the Btree. + * + * Is is used to manage a doubly linked list of all blocks at the same + * level in the Btree, and to identify which type of block this is. + */ +#define XFS_DA_NODE_MAGIC 0xfebe /* magic number: non-leaf blocks */ +#define XFS_DIR_LEAF_MAGIC 0xfeeb /* magic number: directory leaf blks */ +#define XFS_ATTR_LEAF_MAGIC 0xfbee /* magic number: attribute leaf blks */ +#define XFS_DIR2_LEAF1_MAGIC 0xd2f1 /* magic number: v2 dirlf single blks */ +#define XFS_DIR2_LEAFN_MAGIC 0xd2ff /* magic number: v2 dirlf multi blks */ + +#define XFS_DIRX_LEAF_MAGIC(mp) \ + (XFS_DIR_IS_V1(mp) ? XFS_DIR_LEAF_MAGIC : XFS_DIR2_LEAFN_MAGIC) + +typedef struct xfs_da_blkinfo { + xfs_dablk_t forw; /* previous block in list */ + xfs_dablk_t back; /* following block in list */ + __uint16_t magic; /* validity check on block */ + __uint16_t pad; /* unused */ +} xfs_da_blkinfo_t; + +/* + * This is the structure of the root and intermediate nodes in the Btree. + * The leaf nodes are defined above. + * + * Entries are not packed. + * + * Since we have duplicate keys, use a binary search but always follow + * all match in the block, not just the first match found. + */ +#define XFS_DA_NODE_MAXDEPTH 5 /* max depth of Btree */ + +typedef struct xfs_da_intnode { + struct xfs_da_node_hdr { /* constant-structure header block */ + xfs_da_blkinfo_t info; /* block type, links, etc. */ + __uint16_t count; /* count of active entries */ + __uint16_t level; /* level above leaves (leaf == 0) */ + } hdr; + struct xfs_da_node_entry { + xfs_dahash_t hashval; /* hash value for this descendant */ + xfs_dablk_t before; /* Btree block before this key */ + } btree[1]; /* variable sized array of keys */ +} xfs_da_intnode_t; +typedef struct xfs_da_node_hdr xfs_da_node_hdr_t; +typedef struct xfs_da_node_entry xfs_da_node_entry_t; + +#define XFS_DA_NODE_ENTSIZE_BYNAME /* space a name uses */ \ + (sizeof(xfs_da_node_entry_t)) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_NODE_ENTRIES) +int xfs_da_node_entries(struct xfs_mount *mp); +#define XFS_DA_NODE_ENTRIES(mp) xfs_da_node_entries(mp) +#else +#define XFS_DA_NODE_ENTRIES(mp) ((mp)->m_da_node_ents) +#endif + +#define XFS_DA_MAXHASH ((xfs_dahash_t)-1) /* largest valid hash value */ + +/* + * Macros used by directory code to interface to the filesystem. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LBSIZE) +int xfs_lbsize(struct xfs_mount *mp); +#define XFS_LBSIZE(mp) xfs_lbsize(mp) +#else +#define XFS_LBSIZE(mp) ((mp)->m_sb.sb_blocksize) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LBLOG) +int xfs_lblog(struct xfs_mount *mp); +#define XFS_LBLOG(mp) xfs_lblog(mp) +#else +#define XFS_LBLOG(mp) ((mp)->m_sb.sb_blocklog) +#endif + +/* + * Macros used by directory code to interface to the kernel + */ + +/* + * Macros used to manipulate directory off_t's + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_MAKE_BNOENTRY) +__uint32_t xfs_da_make_bnoentry(struct xfs_mount *mp, xfs_dablk_t bno, + int entry); +#define XFS_DA_MAKE_BNOENTRY(mp,bno,entry) \ + xfs_da_make_bnoentry(mp,bno,entry) +#else +#define XFS_DA_MAKE_BNOENTRY(mp,bno,entry) \ + (((bno) << (mp)->m_dircook_elog) | (entry)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_MAKE_COOKIE) +xfs_off_t xfs_da_make_cookie(struct xfs_mount *mp, xfs_dablk_t bno, int entry, + xfs_dahash_t hash); +#define XFS_DA_MAKE_COOKIE(mp,bno,entry,hash) \ + xfs_da_make_cookie(mp,bno,entry,hash) +#else +#define XFS_DA_MAKE_COOKIE(mp,bno,entry,hash) \ + (((xfs_off_t)XFS_DA_MAKE_BNOENTRY(mp, bno, entry) << 32) | (hash)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_COOKIE_HASH) +xfs_dahash_t xfs_da_cookie_hash(struct xfs_mount *mp, xfs_off_t cookie); +#define XFS_DA_COOKIE_HASH(mp,cookie) xfs_da_cookie_hash(mp,cookie) +#else +#define XFS_DA_COOKIE_HASH(mp,cookie) ((xfs_dahash_t)(cookie)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_COOKIE_BNO) +xfs_dablk_t xfs_da_cookie_bno(struct xfs_mount *mp, xfs_off_t cookie); +#define XFS_DA_COOKIE_BNO(mp,cookie) xfs_da_cookie_bno(mp,cookie) +#else +#define XFS_DA_COOKIE_BNO(mp,cookie) \ + (((xfs_off_t)(cookie) >> 31) == -1LL ? \ + (xfs_dablk_t)0 : \ + (xfs_dablk_t)((xfs_off_t)(cookie) >> ((mp)->m_dircook_elog + 32))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_COOKIE_ENTRY) +int xfs_da_cookie_entry(struct xfs_mount *mp, xfs_off_t cookie); +#define XFS_DA_COOKIE_ENTRY(mp,cookie) xfs_da_cookie_entry(mp,cookie) +#else +#define XFS_DA_COOKIE_ENTRY(mp,cookie) \ + (((xfs_off_t)(cookie) >> 31) == -1LL ? \ + (xfs_dablk_t)0 : \ + (xfs_dablk_t)(((xfs_off_t)(cookie) >> 32) & \ + ((1 << (mp)->m_dircook_elog) - 1))) +#endif + + +/*======================================================================== + * Btree searching and modification structure definitions. + *========================================================================*/ + +/* + * Structure to ease passing around component names. + */ +typedef struct xfs_da_args { + char *name; /* string (maybe not NULL terminated) */ + int namelen; /* length of string (maybe no NULL) */ + char *value; /* set of bytes (maybe contain NULLs) */ + int valuelen; /* length of value */ + int flags; /* argument flags (eg: ATTR_NOCREATE) */ + xfs_dahash_t hashval; /* hash value of name */ + xfs_ino_t inumber; /* input/output inode number */ + struct xfs_inode *dp; /* directory inode to manipulate */ + xfs_fsblock_t *firstblock; /* ptr to firstblock for bmap calls */ + struct xfs_bmap_free *flist; /* ptr to freelist for bmap_finish */ + struct xfs_trans *trans; /* current trans (changes over time) */ + xfs_extlen_t total; /* total blocks needed, for 1st bmap */ + int whichfork; /* data or attribute fork */ + xfs_dablk_t blkno; /* blkno of attr leaf of interest */ + int index; /* index of attr of interest in blk */ + xfs_dablk_t rmtblkno; /* remote attr value starting blkno */ + int rmtblkcnt; /* remote attr value block count */ + int rename; /* T/F: this is an atomic rename op */ + xfs_dablk_t blkno2; /* blkno of 2nd attr leaf of interest */ + int index2; /* index of 2nd attr in blk */ + xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */ + int rmtblkcnt2; /* remote attr value block count */ + int justcheck; /* check for ok with no space */ + int addname; /* T/F: this is an add operation */ + int oknoent; /* T/F: ok to return ENOENT, else die */ +} xfs_da_args_t; + +/* + * Structure to describe buffer(s) for a block. + * This is needed in the directory version 2 format case, when + * multiple non-contiguous fsblocks might be needed to cover one + * logical directory block. + * If the buffer count is 1 then the data pointer points to the + * same place as the b_addr field for the buffer, else to kmem_alloced memory. + */ +typedef struct xfs_dabuf { + int nbuf; /* number of buffer pointers present */ + short dirty; /* data needs to be copied back */ + short bbcount; /* how large is data in bbs */ + void *data; /* pointer for buffers' data */ +#ifdef XFS_DABUF_DEBUG + inst_t *ra; /* return address of caller to make */ + struct xfs_dabuf *next; /* next in global chain */ + struct xfs_dabuf *prev; /* previous in global chain */ + dev_t dev; /* device for buffer */ + xfs_daddr_t blkno; /* daddr first in bps[0] */ +#endif + struct xfs_buf *bps[1]; /* actually nbuf of these */ +} xfs_dabuf_t; +#define XFS_DA_BUF_SIZE(n) \ + (sizeof(xfs_dabuf_t) + sizeof(struct xfs_buf *) * ((n) - 1)) + +#ifdef XFS_DABUF_DEBUG +extern xfs_dabuf_t *xfs_dabuf_global_list; +#endif + +/* + * Storage for holding state during Btree searches and split/join ops. + * + * Only need space for 5 intermediate nodes. With a minimum of 62-way + * fanout to the Btree, we can support over 900 million directory blocks, + * which is slightly more than enough. + */ +typedef struct xfs_da_state_blk { + xfs_dabuf_t *bp; /* buffer containing block */ + xfs_dablk_t blkno; /* filesystem blkno of buffer */ + xfs_daddr_t disk_blkno; /* on-disk blkno (in BBs) of buffer */ + int index; /* relevant index into block */ + xfs_dahash_t hashval; /* last hash value in block */ + int magic; /* blk's magic number, ie: blk type */ +} xfs_da_state_blk_t; + +typedef struct xfs_da_state_path { + int active; /* number of active levels */ + xfs_da_state_blk_t blk[XFS_DA_NODE_MAXDEPTH]; +} xfs_da_state_path_t; + +typedef struct xfs_da_state { + xfs_da_args_t *args; /* filename arguments */ + struct xfs_mount *mp; /* filesystem mount point */ + int blocksize; /* logical block size */ + int inleaf; /* insert into 1->lf, 0->splf */ + xfs_da_state_path_t path; /* search/split paths */ + xfs_da_state_path_t altpath; /* alternate path for join */ + int extravalid; /* T/F: extrablk is in use */ + int extraafter; /* T/F: extrablk is after new */ + xfs_da_state_blk_t extrablk; /* for double-splits on leafs */ + /* for dirv2 extrablk is data */ +} xfs_da_state_t; + +/* + * Utility macros to aid in logging changed structure fields. + */ +#define XFS_DA_LOGOFF(BASE, ADDR) ((char *)(ADDR) - (char *)(BASE)) +#define XFS_DA_LOGRANGE(BASE, ADDR, SIZE) \ + (uint)(XFS_DA_LOGOFF(BASE, ADDR)), \ + (uint)(XFS_DA_LOGOFF(BASE, ADDR)+(SIZE)-1) + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Routines used for growing the Btree. + */ +int xfs_da_node_create(xfs_da_args_t *args, xfs_dablk_t blkno, int level, + xfs_dabuf_t **bpp, int whichfork); +int xfs_da_split(xfs_da_state_t *state); + +/* + * Routines used for shrinking the Btree. + */ +int xfs_da_join(xfs_da_state_t *state); +void xfs_da_fixhashpath(xfs_da_state_t *state, + xfs_da_state_path_t *path_to_to_fix); + +/* + * Routines used for finding things in the Btree. + */ +int xfs_da_node_lookup_int(xfs_da_state_t *state, int *result); +int xfs_da_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path, + int forward, int release, int *result); +/* + * Utility routines. + */ +int xfs_da_blk_unlink(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk); +int xfs_da_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk, + xfs_da_state_blk_t *new_blk); + +/* + * Utility routines. + */ +int xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno); +int xfs_da_get_buf(struct xfs_trans *trans, struct xfs_inode *dp, + xfs_dablk_t bno, xfs_daddr_t mappedbno, + xfs_dabuf_t **bp, int whichfork); +int xfs_da_read_buf(struct xfs_trans *trans, struct xfs_inode *dp, + xfs_dablk_t bno, xfs_daddr_t mappedbno, + xfs_dabuf_t **bpp, int whichfork); +xfs_daddr_t xfs_da_reada_buf(struct xfs_trans *trans, struct xfs_inode *dp, + xfs_dablk_t bno, int whichfork); +int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, + xfs_dabuf_t *dead_buf); + +uint xfs_da_hashname(char *name_string, int name_length); +uint xfs_da_log2_roundup(uint i); +xfs_da_state_t *xfs_da_state_alloc(void); +void xfs_da_state_free(xfs_da_state_t *state); +void xfs_da_state_kill_altpath(xfs_da_state_t *state); + +void xfs_da_buf_done(xfs_dabuf_t *dabuf); +void xfs_da_log_buf(struct xfs_trans *tp, xfs_dabuf_t *dabuf, uint first, + uint last); +void xfs_da_brelse(struct xfs_trans *tp, xfs_dabuf_t *dabuf); +void xfs_da_binval(struct xfs_trans *tp, xfs_dabuf_t *dabuf); +xfs_daddr_t xfs_da_blkno(xfs_dabuf_t *dabuf); + +extern struct xfs_zone *xfs_da_state_zone; + +#endif /* __XFS_DA_BTREE_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dfrag.c linux-2.4-xfs/linux/fs/xfs/xfs_dfrag.c --- linux-2.4.7/linux/fs/xfs/xfs_dfrag.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dfrag.c Tue Apr 10 20:44:54 2001 @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + + +/* + * Syssgi interface for swapext + */ +int +xfs_swapext( + xfs_swapext_t *sxp) +{ + xfs_swapext_t sx; + xfs_inode_t *ip=NULL, *tip=NULL, *ips[2]; + xfs_trans_t *tp; + xfs_mount_t *mp; + xfs_bstat_t *sbp; + struct file *fp = NULL, *tfp = NULL; + vnode_t *vp, *tvp; + bhv_desc_t *bdp, *tbdp; + vn_bhv_head_t *bhp, *tbhp; + uint lock_flags=0; + int ilf_fields, tilf_fields; + int error = 0; + xfs_ifork_t tempif, *ifp, *tifp; + __uint64_t tmp; +/* __uint64_t cxfs_val; */ + int aforkblks = 0; + int taforkblks = 0; + int locked = 0; + + if (copyin(sxp, &sx, sizeof sx)) + return XFS_ERROR(EFAULT); + + /* Pull information for the target fd */ + if (((fp = fget((int)sx.sx_fdtarget)) == NULL) || + ((vp = LINVFS_GET_VP(fp->f_dentry->d_inode)) == NULL)) { + error = XFS_ERROR(EINVAL); + goto error0; + } + + bhp = VN_BHV_HEAD(vp); + VN_BHV_READ_LOCK(bhp); + bdp = vn_bhv_lookup(bhp, &xfs_vnodeops); + if (bdp == NULL) { + VN_BHV_READ_UNLOCK(bhp); + error = XFS_ERROR(EBADF); + goto error0; + } else { + ip = XFS_BHVTOI(bdp); + VN_BHV_READ_UNLOCK(bhp); + } + + if (((tfp = fget((int)sx.sx_fdtmp)) == NULL) || + ((tvp = LINVFS_GET_VP(tfp->f_dentry->d_inode)) == NULL)) { + error = XFS_ERROR(EINVAL); + goto error0; + } + + tbhp = VN_BHV_HEAD(tvp); + VN_BHV_READ_LOCK(tbhp); + tbdp = vn_bhv_lookup(tbhp, &xfs_vnodeops); + if (tbdp == NULL) { + VN_BHV_READ_UNLOCK(tbhp); + error = XFS_ERROR(EBADF); + goto error0; + } else { + tip = XFS_BHVTOI(tbdp); + VN_BHV_READ_UNLOCK(tbhp); + } + + if (ip->i_ino == tip->i_ino) { + error = XFS_ERROR(EINVAL); + goto error0; + } + + mp = ip->i_mount; + + sbp = &sx.sx_stat; + + if (XFS_FORCED_SHUTDOWN(mp)) { + error = XFS_ERROR(EIO); + goto error0; + } + + /* quit if either is the swap file */ + if (vp->v_flag & VISSWAP && vp->v_type == VREG) { + error = XFS_ERROR(EACCES); + goto error0; + } + if (tvp->v_flag & VISSWAP && tvp->v_type == VREG) { + error = XFS_ERROR(EACCES); + goto error0; + } + + locked = 1; + CELL_ONLY(cxfs_val = cfs_start_defrag(vp)); + + /* Lock in i_ino order */ + if (ip->i_ino < tip->i_ino) { + ips[0] = ip; + ips[1] = tip; + } else { + ips[0] = tip; + ips[1] = ip; + } + lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL; + xfs_lock_inodes(ips, 2, 0, lock_flags); + + /* Check permissions */ + if ((error = _MAC_XFS_IACCESS(ip, MACWRITE, NULL))) { + goto error0; + } + if ((error = _MAC_XFS_IACCESS(tip, MACWRITE, NULL))) { + goto error0; + } + if ((current->fsuid != ip->i_d.di_uid) && + (error = xfs_iaccess(ip, IWRITE, NULL)) && + !capable_cred(NULL, CAP_FOWNER)) { + goto error0; + } + if ((current->fsuid != tip->i_d.di_uid) && + (error = xfs_iaccess(tip, IWRITE, NULL)) && + !capable_cred(NULL, CAP_FOWNER)) { + goto error0; + } + + /* Verify both files are either real-time or non-realtime */ + if ((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != + (tip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { + error = XFS_ERROR(EINVAL); + goto error0; + } + + /* Should never get a local format */ + if (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL || + tip->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + error = XFS_ERROR(EINVAL); + goto error0; + } + + if (VN_CACHED(tvp) != 0) + xfs_inval_cached_pages(XFS_ITOV(tip), &(tip->i_iocore), + 0, tip->i_d.di_size, NULL); + + /* Verify O_DIRECT for ftmp */ + if (VN_CACHED(tvp) != 0) { + error = XFS_ERROR(EINVAL); + goto error0; + } + + /* Verify all data are being swapped */ + if (sx.sx_offset != 0 || + sx.sx_length != ip->i_d.di_size || + sx.sx_length != tip->i_d.di_size) { + error = XFS_ERROR(EFAULT); + goto error0; + } + + /* + * If the target has extended attributes, the tmp file + * must also in order to ensure the correct data fork + * format. + */ + if ( XFS_IFORK_Q(ip) != XFS_IFORK_Q(tip) ) { + error = XFS_ERROR(EINVAL); + goto error0; + } + + /* + * Compare the current change & modify times with that + * passed in. If they differ, we abort this swap. + * This is the mechanism used to ensure the calling + * process that the file was not changed out from + * under it. + */ + if ((sbp->bs_ctime.tv_sec != ip->i_d.di_ctime.t_sec) || + (sbp->bs_ctime.tv_nsec != ip->i_d.di_ctime.t_nsec) || + (sbp->bs_mtime.tv_sec != ip->i_d.di_mtime.t_sec) || + (sbp->bs_mtime.tv_nsec != ip->i_d.di_mtime.t_nsec)) { + error = XFS_ERROR(EBUSY); + goto error0; + } + + /* We need to fail if the file is memory mapped, we also need to + * prevent it from getting mapped before we have tossed the existing + * pages. By setting VREMAPPING here we force a pas_vfault to go to + * the filesystem for pages. Once we have tossed all existing pages + * we can clear VREMAPPING as the page fault will have no option but + * to go to the filesystem for pages. By making the page fault call + * VOP_READ (or write in the case of autogrow) they block on the iolock + * until we have switched the extents. + */ + VN_FLAGSET(vp, VREMAPPING); + if (VN_MAPPED(vp)) { + error = XFS_ERROR(EBUSY); + VN_FLAGCLR(vp, VREMAPPING); + goto error0; + } + + xfs_iunlock(ip, XFS_ILOCK_EXCL); + xfs_iunlock(tip, XFS_ILOCK_EXCL); + + /* + * There is a race condition here since we gave up the + * ilock. However, the data fork will not change since + * we have the iolock (locked for truncation too) so we + * are safe. We don't really care if non-io related + * fields change. + */ + + VOP_TOSS_PAGES(vp, 0, -1, FI_REMAPF); + VN_FLAGCLR(vp, VREMAPPING); + + tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT); + if ((error = xfs_trans_reserve(tp, 0, + XFS_ICHANGE_LOG_RES(mp), 0, + 0, 0))) { + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + xfs_iunlock(tip, XFS_IOLOCK_EXCL); + xfs_trans_cancel(tp, 0); + return error; + } + xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); + + /* + * Count the number of extended attribute blocks + */ + if ( ((XFS_IFORK_Q(ip) != 0) && (ip->i_d.di_anextents > 0)) && + (ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) { + error = xfs_bmap_count_blocks(tp, ip, XFS_ATTR_FORK, &aforkblks); + if (error) { + xfs_iunlock(ip, lock_flags); + xfs_iunlock(tip, lock_flags); + xfs_trans_cancel(tp, 0); + return error; + } + } + if ( ((XFS_IFORK_Q(tip) != 0) && (tip->i_d.di_anextents > 0)) && + (tip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) { + error = xfs_bmap_count_blocks(tp, tip, XFS_ATTR_FORK, + &taforkblks); + if (error) { + xfs_iunlock(ip, lock_flags); + xfs_iunlock(tip, lock_flags); + xfs_trans_cancel(tp, 0); + return error; + } + } + + /* + * Swap the data forks of the inodes + */ + ifp = &ip->i_df; + tifp = &tip->i_df; + tempif = *ifp; /* struct copy */ + *ifp = *tifp; /* struct copy */ + *tifp = tempif; /* struct copy */ + + /* + * Fix the on-disk inode values + */ + tmp = (__uint64_t)ip->i_d.di_nblocks; + ip->i_d.di_nblocks = tip->i_d.di_nblocks - taforkblks + aforkblks; + tip->i_d.di_nblocks = tmp + taforkblks - aforkblks; + + tmp = (__uint64_t) ip->i_d.di_nextents; + ip->i_d.di_nextents = tip->i_d.di_nextents; + tip->i_d.di_nextents = tmp; + + tmp = (__uint64_t) ip->i_d.di_format; + ip->i_d.di_format = tip->i_d.di_format; + tip->i_d.di_format = tmp; + + ilf_fields = XFS_ILOG_CORE; + + switch(ip->i_d.di_format) { + case XFS_DINODE_FMT_EXTENTS: + /* If the extents fit in the inode, fix the + * pointer. Otherwise it's already NULL or + * pointing to the extent. + */ + if (ip->i_d.di_nextents <= XFS_INLINE_EXTS) { + ifp->if_u1.if_extents = + ifp->if_u2.if_inline_ext; + } + ilf_fields |= XFS_ILOG_DEXT; + break; + case XFS_DINODE_FMT_BTREE: + ilf_fields |= XFS_ILOG_DBROOT; + break; + } + + tilf_fields = XFS_ILOG_CORE; + + switch(tip->i_d.di_format) { + case XFS_DINODE_FMT_EXTENTS: + /* If the extents fit in the inode, fix the + * pointer. Otherwise it's already NULL or + * pointing to the extent. + */ + if (tip->i_d.di_nextents <= XFS_INLINE_EXTS) { + tifp->if_u1.if_extents = + tifp->if_u2.if_inline_ext; + } + tilf_fields |= XFS_ILOG_DEXT; + break; + case XFS_DINODE_FMT_BTREE: + tilf_fields |= XFS_ILOG_DBROOT; + break; + } + + /* + * Increment vnode ref counts since xfs_trans_commit & + * xfs_trans_cancel will both unlock the inodes and + * decrement the associated ref counts. + */ + VN_HOLD(vp); + VN_HOLD(tvp); + + xfs_trans_ijoin(tp, ip, lock_flags); + xfs_trans_ijoin(tp, tip, lock_flags); + + xfs_trans_log_inode(tp, ip, ilf_fields); + xfs_trans_log_inode(tp, tip, tilf_fields); + + /* + * If this is a synchronous mount, make sure that the + * transaction goes to disk before returning to the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT, NULL); + + CELL_ONLY(cfs_end_defrag(vp, cxfs_val)); + + fput(fp); + fput(tfp); + + return error; + + error0: + if (locked) { + CELL_ONLY(cfs_end_defrag(vp, cxfs_val)); + xfs_iunlock(ip, lock_flags); + xfs_iunlock(tip, lock_flags); + } + + if (fp != NULL) fput(fp); + if (tfp != NULL) fput(tfp); + + return error; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dfrag.h linux-2.4-xfs/linux/fs/xfs/xfs_dfrag.h --- linux-2.4.7/linux/fs/xfs/xfs_dfrag.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dfrag.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DFRAG_H__ +#define __XFS_DFRAG_H__ + +/* + * Structure passed to xfs_swapext + */ + +typedef struct xfs_swapext +{ + __int64_t sx_version; /* version */ + __int64_t sx_fdtarget; /* fd of target file */ + __int64_t sx_fdtmp; /* fd of tmp file */ + xfs_off_t sx_offset; /* offset into file */ + xfs_off_t sx_length; /* leng from offset */ + char sx_pad[16]; /* pad space, unused */ + xfs_bstat_t sx_stat; /* stat of target b4 copy */ +} xfs_swapext_t; + +/* + * Version flag + */ +#define XFS_SX_VERSION 0 + +#ifdef __KERNEL__ +/* + * Prototypes for visible xfs_dfrag.c routines. + */ + +/* + * Syscall interface for xfs_swapext + */ +int xfs_swapext(struct xfs_swapext *sx); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_DFRAG_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dinode.h linux-2.4-xfs/linux/fs/xfs/xfs_dinode.h --- linux-2.4.7/linux/fs/xfs/xfs_dinode.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dinode.h Tue Nov 14 17:40:34 2000 @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DINODE_H__ +#define __XFS_DINODE_H__ + +struct xfs_buf; +struct xfs_mount; + +#define XFS_DINODE_VERSION_1 1 +#define XFS_DINODE_VERSION_2 2 +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DINODE_GOOD_VERSION) +int xfs_dinode_good_version(int v); +#define XFS_DINODE_GOOD_VERSION(v) xfs_dinode_good_version(v) +#else +#define XFS_DINODE_GOOD_VERSION(v) (((v) == XFS_DINODE_VERSION_1) || \ + ((v) == XFS_DINODE_VERSION_2)) +#endif +#define XFS_DINODE_MAGIC 0x494e /* 'IN' */ + +/* + * Disk inode structure. + * This is just the header; the inode is expanded to fill a variable size + * with the last field expanding. It is split into the core and "other" + * because we only need the core part in the in-core inode. + */ +typedef struct xfs_timestamp { + __int32_t t_sec; /* timestamp seconds */ + __int32_t t_nsec; /* timestamp nanoseconds */ +} xfs_timestamp_t; + +/* + * Note: Coordinate changes to this structure with the XFS_DI_* #defines + * below and the offsets table in xfs_ialloc_log_di(). + */ +typedef struct xfs_dinode_core +{ + __uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */ + __uint16_t di_mode; /* mode and type of file */ + __int8_t di_version; /* inode version */ + __int8_t di_format; /* format of di_c data */ + __uint16_t di_onlink; /* old number of links to file */ + __uint32_t di_uid; /* owner's user id */ + __uint32_t di_gid; /* owner's group id */ + __uint32_t di_nlink; /* number of links to file */ + __uint16_t di_projid; /* owner's project id */ + __uint8_t di_pad[10]; /* unused, zeroed space */ + xfs_timestamp_t di_atime; /* time last accessed */ + xfs_timestamp_t di_mtime; /* time last modified */ + xfs_timestamp_t di_ctime; /* time created/inode modified */ + xfs_fsize_t di_size; /* number of bytes in file */ + xfs_drfsbno_t di_nblocks; /* # of direct & btree blocks used */ + xfs_extlen_t di_extsize; /* basic/minimum extent size for file */ + xfs_extnum_t di_nextents; /* number of extents in data fork */ + xfs_aextnum_t di_anextents; /* number of extents in attribute fork*/ + __uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */ + __int8_t di_aformat; /* format of attr fork's data */ + __uint32_t di_dmevmask; /* DMIG event mask */ + __uint16_t di_dmstate; /* DMIG state info */ + __uint16_t di_flags; /* random flags, XFS_DIFLAG_... */ + __uint32_t di_gen; /* generation number */ +} xfs_dinode_core_t; + +typedef struct xfs_dinode +{ + xfs_dinode_core_t di_core; + /* + * In adding anything between the core and the union, be + * sure to update the macros like XFS_LITINO below and + * XFS_BMAP_RBLOCK_DSIZE in xfs_bmap_btree.h. + */ + xfs_agino_t di_next_unlinked;/* agi unlinked list ptr */ + union { + xfs_bmdr_block_t di_bmbt; /* btree root block */ + xfs_bmbt_rec_32_t di_bmx[1]; /* extent list */ + xfs_dir_shortform_t di_dirsf; /* shortform directory */ + xfs_dir2_sf_t di_dir2sf; /* shortform directory v2 */ + char di_c[1]; /* local contents */ + xfs_dev_t di_dev; /* device for IFCHR/IFBLK */ + uuid_t di_muuid; /* mount point value */ + char di_symlink[1]; /* local symbolic link */ + } di_u; + union { + xfs_bmdr_block_t di_abmbt; /* btree root block */ + xfs_bmbt_rec_32_t di_abmx[1]; /* extent list */ + xfs_attr_shortform_t di_attrsf; /* shortform attribute list */ + } di_a; +} xfs_dinode_t; + +/* + * The 32 bit link count in the inode theoretically maxes out at UINT_MAX. + * Since the pathconf interface is signed, we use 2^31 - 1 instead. + * The old inode format had a 16 bit link count, so its maximum is USHRT_MAX. + */ +#define XFS_MAXLINK ((1U << 31) - 1U) +#define XFS_MAXLINK_1 65535U + +/* + * Bit names for logging disk inodes only + */ +#define XFS_DI_MAGIC 0x0000001 +#define XFS_DI_MODE 0x0000002 +#define XFS_DI_VERSION 0x0000004 +#define XFS_DI_FORMAT 0x0000008 +#define XFS_DI_ONLINK 0x0000010 +#define XFS_DI_UID 0x0000020 +#define XFS_DI_GID 0x0000040 +#define XFS_DI_NLINK 0x0000080 +#define XFS_DI_PROJID 0x0000100 +#define XFS_DI_PAD 0x0000200 +#define XFS_DI_ATIME 0x0000400 +#define XFS_DI_MTIME 0x0000800 +#define XFS_DI_CTIME 0x0001000 +#define XFS_DI_SIZE 0x0002000 +#define XFS_DI_NBLOCKS 0x0004000 +#define XFS_DI_EXTSIZE 0x0008000 +#define XFS_DI_NEXTENTS 0x0010000 +#define XFS_DI_NAEXTENTS 0x0020000 +#define XFS_DI_FORKOFF 0x0040000 +#define XFS_DI_AFORMAT 0x0080000 +#define XFS_DI_DMEVMASK 0x0100000 +#define XFS_DI_DMSTATE 0x0200000 +#define XFS_DI_FLAGS 0x0400000 +#define XFS_DI_GEN 0x0800000 +#define XFS_DI_NEXT_UNLINKED 0x1000000 +#define XFS_DI_U 0x2000000 +#define XFS_DI_A 0x4000000 +#define XFS_DI_NUM_BITS 27 +#define XFS_DI_ALL_BITS ((1 << XFS_DI_NUM_BITS) - 1) +#define XFS_DI_CORE_BITS (XFS_DI_ALL_BITS & ~(XFS_DI_U|XFS_DI_A)) + +/* + * Values for di_format + */ +typedef enum xfs_dinode_fmt +{ + XFS_DINODE_FMT_DEV, /* CHR, BLK: di_dev */ + XFS_DINODE_FMT_LOCAL, /* DIR, REG: di_c */ + /* LNK: di_symlink */ + XFS_DINODE_FMT_EXTENTS, /* DIR, REG, LNK: di_bmx */ + XFS_DINODE_FMT_BTREE, /* DIR, REG, LNK: di_bmbt */ + XFS_DINODE_FMT_UUID /* MNT: di_uuid */ +} xfs_dinode_fmt_t; + +/* + * Inode minimum and maximum sizes. + */ +#define XFS_DINODE_MIN_LOG 8 +#define XFS_DINODE_MAX_LOG 11 +#define XFS_DINODE_MIN_SIZE (1 << XFS_DINODE_MIN_LOG) +#define XFS_DINODE_MAX_SIZE (1 << XFS_DINODE_MAX_LOG) + +/* + * Inode size for given fs. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LITINO) +int xfs_litino(struct xfs_mount *mp); +#define XFS_LITINO(mp) xfs_litino(mp) +#else +#define XFS_LITINO(mp) ((mp)->m_litino) +#endif +#define XFS_BROOT_SIZE_ADJ \ + (sizeof(xfs_bmbt_block_t) - sizeof(xfs_bmdr_block_t)) + +/* + * Fork identifiers. Here so utilities can use them without including + * xfs_inode.h. + */ +#define XFS_DATA_FORK 0 +#define XFS_ATTR_FORK 1 + +/* + * Inode data & attribute fork sizes, per inode. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_Q) +int xfs_cfork_q_arch(xfs_dinode_core_t *dcp, xfs_arch_t arch); +int xfs_cfork_q(xfs_dinode_core_t *dcp); +#define XFS_CFORK_Q_ARCH(dcp,arch) xfs_cfork_q_arch(dcp,arch) +#define XFS_CFORK_Q(dcp) xfs_cfork_q(dcp) +#else +#define XFS_CFORK_Q_ARCH(dcp,arch) (INT_GET((dcp)->di_forkoff, arch) != 0) +#define XFS_CFORK_Q(dcp) XFS_CFORK_Q_ARCH(dcp,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_BOFF) +int xfs_cfork_boff_arch(xfs_dinode_core_t *dcp, xfs_arch_t arch); +int xfs_cfork_boff(xfs_dinode_core_t *dcp); +#define XFS_CFORK_BOFF_ARCH(dcp,arch) xfs_cfork_boff_arch(dcp,arch) +#define XFS_CFORK_BOFF(dcp) xfs_cfork_boff(dcp) +#else +#define XFS_CFORK_BOFF_ARCH(dcp,arch) ((int)(INT_GET((dcp)->di_forkoff, arch) << 3)) +#define XFS_CFORK_BOFF(dcp) XFS_CFORK_BOFF_ARCH(dcp,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_DSIZE) +int xfs_cfork_dsize_arch(xfs_dinode_core_t *dcp, struct xfs_mount *mp, xfs_arch_t arch); +int xfs_cfork_dsize(xfs_dinode_core_t *dcp, struct xfs_mount *mp); +#define XFS_CFORK_DSIZE_ARCH(dcp,mp,arch) xfs_cfork_dsize_arch(dcp,mp,arch) +#define XFS_CFORK_DSIZE(dcp,mp) xfs_cfork_dsize(dcp,mp) +#else +#define XFS_CFORK_DSIZE_ARCH(dcp,mp,arch) \ + (XFS_CFORK_Q_ARCH(dcp, arch) ? XFS_CFORK_BOFF_ARCH(dcp, arch) : XFS_LITINO(mp)) +#define XFS_CFORK_DSIZE(dcp,mp) XFS_CFORK_DSIZE_ARCH(dcp,mp,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_ASIZE) +int xfs_cfork_asize_arch(xfs_dinode_core_t *dcp, struct xfs_mount *mp, xfs_arch_t arch); +int xfs_cfork_asize(xfs_dinode_core_t *dcp, struct xfs_mount *mp); +#define XFS_CFORK_ASIZE_ARCH(dcp,mp,arch) xfs_cfork_asize_arch(dcp,mp,arch) +#define XFS_CFORK_ASIZE(dcp,mp) xfs_cfork_asize(dcp,mp) +#else +#define XFS_CFORK_ASIZE_ARCH(dcp,mp,arch) \ + (XFS_CFORK_Q_ARCH(dcp, arch) ? XFS_LITINO(mp) - XFS_CFORK_BOFF_ARCH(dcp, arch) : 0) +#define XFS_CFORK_ASIZE(dcp,mp) XFS_CFORK_ASIZE_ARCH(dcp,mp,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_SIZE) +int xfs_cfork_size_arch(xfs_dinode_core_t *dcp, struct xfs_mount *mp, int w, xfs_arch_t arch); +int xfs_cfork_size(xfs_dinode_core_t *dcp, struct xfs_mount *mp, int w); +#define XFS_CFORK_SIZE_ARCH(dcp,mp,w,arch) xfs_cfork_size_arch(dcp,mp,w,arch) +#define XFS_CFORK_SIZE(dcp,mp,w) xfs_cfork_size(dcp,mp,w) +#else +#define XFS_CFORK_SIZE_ARCH(dcp,mp,w,arch) \ + ((w) == XFS_DATA_FORK ? \ + XFS_CFORK_DSIZE_ARCH(dcp, mp, arch) : XFS_CFORK_ASIZE_ARCH(dcp, mp, arch)) +#define XFS_CFORK_SIZE(dcp,mp,w) XFS_CFORK_SIZE_ARCH(dcp,mp,w,ARCH_NOCONVERT) + +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_DSIZE) +int xfs_dfork_dsize_arch(xfs_dinode_t *dip, struct xfs_mount *mp, xfs_arch_t arch); +int xfs_dfork_dsize(xfs_dinode_t *dip, struct xfs_mount *mp); +#define XFS_DFORK_DSIZE_ARCH(dip,mp,arch) xfs_dfork_dsize_arch(dip,mp,arch) +#define XFS_DFORK_DSIZE(dip,mp) xfs_dfork_dsize(dip,mp) +#else +#define XFS_DFORK_DSIZE_ARCH(dip,mp,arch) XFS_CFORK_DSIZE_ARCH(&(dip)->di_core, mp, arch) +#define XFS_DFORK_DSIZE(dip,mp) XFS_DFORK_DSIZE_ARCH(dip,mp,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_ASIZE) +int xfs_dfork_asize_arch(xfs_dinode_t *dip, struct xfs_mount *mp, xfs_arch_t arch); +int xfs_dfork_asize(xfs_dinode_t *dip, struct xfs_mount *mp); +#define XFS_DFORK_ASIZE_ARCH(dip,mp,arch) xfs_dfork_asize_arch(dip,mp,arch) +#define XFS_DFORK_ASIZE(dip,mp) xfs_dfork_asize(dip,mp) +#else +#define XFS_DFORK_ASIZE_ARCH(dip,mp,arch) XFS_CFORK_ASIZE_ARCH(&(dip)->di_core, mp, arch) +#define XFS_DFORK_ASIZE(dip,mp) XFS_DFORK_ASIZE_ARCH(dip,mp,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_SIZE) +int xfs_dfork_size_arch(xfs_dinode_t *dip, struct xfs_mount *mp, int w, xfs_arch_t arch); +int xfs_dfork_size(xfs_dinode_t *dip, struct xfs_mount *mp, int w); +#define XFS_DFORK_SIZE_ARCH(dip,mp,w,arch) xfs_dfork_size_arch(dip,mp,w,arch) +#define XFS_DFORK_SIZE(dip,mp,w) xfs_dfork_size(dip,mp,w) +#else +#define XFS_DFORK_SIZE_ARCH(dip,mp,w,arch) XFS_CFORK_SIZE_ARCH(&(dip)->di_core, mp, w, arch) +#define XFS_DFORK_SIZE(dip,mp,w) XFS_DFORK_SIZE_ARCH(dip,mp,w,ARCH_NOCONVERT) + +#endif + +/* + * Macros for accessing per-fork disk inode information. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_Q) +int xfs_dfork_q_arch(xfs_dinode_t *dip, xfs_arch_t arch); +int xfs_dfork_q(xfs_dinode_t *dip); +#define XFS_DFORK_Q_ARCH(dip,arch) xfs_dfork_q_arch(dip,arch) +#define XFS_DFORK_Q(dip) xfs_dfork_q(dip) +#else +#define XFS_DFORK_Q_ARCH(dip,arch) XFS_CFORK_Q_ARCH(&(dip)->di_core, arch) +#define XFS_DFORK_Q(dip) XFS_DFORK_Q_ARCH(dip,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_BOFF) +int xfs_dfork_boff_arch(xfs_dinode_t *dip, xfs_arch_t arch); +int xfs_dfork_boff(xfs_dinode_t *dip); +#define XFS_DFORK_BOFF_ARCH(dip,arch) xfs_dfork_boff_arch(dip,arch) +#define XFS_DFORK_BOFF(dip) xfs_dfork_boff(dip) +#else +#define XFS_DFORK_BOFF_ARCH(dip,arch) XFS_CFORK_BOFF_ARCH(&(dip)->di_core, arch) +#define XFS_DFORK_BOFF(dip) XFS_DFORK_BOFF_ARCH(dip,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_DPTR) +char *xfs_dfork_dptr_arch(xfs_dinode_t *dip, xfs_arch_t arch); +char *xfs_dfork_dptr(xfs_dinode_t *dip); +#define XFS_DFORK_DPTR_ARCH(dip,arch) xfs_dfork_dptr_arch(dip,arch) +#define XFS_DFORK_DPTR(dip) xfs_dfork_dptr(dip) +#else +#define XFS_DFORK_DPTR_ARCH(dip,arch) ((dip)->di_u.di_c) +#define XFS_DFORK_DPTR(dip) XFS_DFORK_DPTR_ARCH(dip,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_APTR) +char *xfs_dfork_aptr_arch(xfs_dinode_t *dip, xfs_arch_t arch); +char *xfs_dfork_aptr(xfs_dinode_t *dip); +#define XFS_DFORK_APTR_ARCH(dip,arch) xfs_dfork_aptr_arch(dip,arch) +#define XFS_DFORK_APTR(dip) xfs_dfork_aptr(dip) +#else +#define XFS_DFORK_APTR_ARCH(dip,arch) ((dip)->di_u.di_c + XFS_DFORK_BOFF_ARCH(dip, arch)) +#define XFS_DFORK_APTR(dip) XFS_DFORK_APTR_ARCH(dip,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_PTR) +char *xfs_dfork_ptr_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch); +char *xfs_dfork_ptr(xfs_dinode_t *dip, int w); +#define XFS_DFORK_PTR_ARCH(dip,w,arch) xfs_dfork_ptr_arch(dip,w,arch) +#define XFS_DFORK_PTR(dip,w) xfs_dfork_ptr(dip,w) +#else +#define XFS_DFORK_PTR_ARCH(dip,w,arch) \ + ((w) == XFS_DATA_FORK ? XFS_DFORK_DPTR_ARCH(dip, arch) : XFS_DFORK_APTR_ARCH(dip, arch)) +#define XFS_DFORK_PTR(dip,w) XFS_DFORK_PTR_ARCH(dip,w,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_FORMAT) +int xfs_cfork_format_arch(xfs_dinode_core_t *dcp, int w, xfs_arch_t arch); +int xfs_cfork_format(xfs_dinode_core_t *dcp, int w); +#define XFS_CFORK_FORMAT_ARCH(dcp,w,arch) xfs_cfork_format_arch(dcp,w,arch) +#define XFS_CFORK_FORMAT(dcp,w) xfs_cfork_format(dcp,w) +#else +#define XFS_CFORK_FORMAT_ARCH(dcp,w,arch) \ + ((w) == XFS_DATA_FORK ? INT_GET((dcp)->di_format, arch) : INT_GET((dcp)->di_aformat, arch)) +#define XFS_CFORK_FORMAT(dcp,w) XFS_CFORK_FORMAT_ARCH(dcp,w,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_FMT_SET) +void xfs_cfork_fmt_set_arch(xfs_dinode_core_t *dcp, int w, int n, xfs_arch_t arch); +void xfs_cfork_fmt_set(xfs_dinode_core_t *dcp, int w, int n); +#define XFS_CFORK_FMT_SET_ARCH(dcp,w,n,arch) xfs_cfork_fmt_set_arch(dcp,w,n,arch) +#define XFS_CFORK_FMT_SET(dcp,w,n) xfs_cfork_fmt_set(dcp,w,n) +#else +#define XFS_CFORK_FMT_SET_ARCH(dcp,w,n,arch) \ + ((w) == XFS_DATA_FORK ? \ + (INT_SET((dcp)->di_format, arch, (n))) : \ + (INT_SET((dcp)->di_aformat, arch, (n)))) +#define XFS_CFORK_FMT_SET(dcp,w,n) XFS_CFORK_FMT_SET_ARCH(dcp,w,n,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_NEXTENTS) +int xfs_cfork_nextents_arch(xfs_dinode_core_t *dcp, int w, xfs_arch_t arch); +int xfs_cfork_nextents(xfs_dinode_core_t *dcp, int w); +#define XFS_CFORK_NEXTENTS_ARCH(dcp,w,arch) xfs_cfork_nextents_arch(dcp,w,arch) +#define XFS_CFORK_NEXTENTS(dcp,w) xfs_cfork_nextents(dcp,w) +#else +#define XFS_CFORK_NEXTENTS_ARCH(dcp,w,arch) \ + ((w) == XFS_DATA_FORK ? INT_GET((dcp)->di_nextents, arch) : INT_GET((dcp)->di_anextents, arch)) +#define XFS_CFORK_NEXTENTS(dcp,w) XFS_CFORK_NEXTENTS_ARCH(dcp,w,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_CFORK_NEXT_SET) +void xfs_cfork_next_set_arch(xfs_dinode_core_t *dcp, int w, int n, xfs_arch_t arch); +void xfs_cfork_next_set(xfs_dinode_core_t *dcp, int w, int n); +#define XFS_CFORK_NEXT_SET_ARCH(dcp,w,n,arch) xfs_cfork_next_set_arch(dcp,w,n,arch) +#define XFS_CFORK_NEXT_SET(dcp,w,n) xfs_cfork_next_set(dcp,w,n) +#else +#define XFS_CFORK_NEXT_SET_ARCH(dcp,w,n,arch) \ + ((w) == XFS_DATA_FORK ? \ + (INT_SET((dcp)->di_nextents, arch, (n))) : \ + (INT_SET((dcp)->di_anextents, arch, (n)))) +#define XFS_CFORK_NEXT_SET(dcp,w,n) XFS_CFORK_NEXT_SET_ARCH(dcp,w,n,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_FORMAT) +int xfs_dfork_format_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch); +int xfs_dfork_format(xfs_dinode_t *dip, int w); +#define XFS_DFORK_FORMAT_ARCH(dip,w,arch) xfs_dfork_format_arch(dip,w,arch) +#define XFS_DFORK_FORMAT(dip,w) xfs_dfork_format(dip,w) +#else +#define XFS_DFORK_FORMAT_ARCH(dip,w,arch) XFS_CFORK_FORMAT_ARCH(&(dip)->di_core, w, arch) +#define XFS_DFORK_FORMAT(dip,w) XFS_DFORK_FORMAT_ARCH(dip,w,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_FMT_SET) +void xfs_dfork_fmt_set_arch(xfs_dinode_t *dip, int w, int n, xfs_arch_t arch); +void xfs_dfork_fmt_set(xfs_dinode_t *dip, int w, int n); +#define XFS_DFORK_FMT_SET_ARCH(dip,w,n,arch) xfs_dfork_fmt_set_arch(dip,w,n,arch) +#define XFS_DFORK_FMT_SET(dip,w,n) xfs_dfork_fmt_set(dip,w,n) +#else +#define XFS_DFORK_FMT_SET_ARCH(dip,w,n,arch) XFS_CFORK_FMT_SET_ARCH(&(dip)->di_core, w, n, arch) +#define XFS_DFORK_FMT_SET(dip,w,n) XFS_DFORK_FMT_SET_ARCH(dip,w,n,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_NEXTENTS) +int xfs_dfork_nextents_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch); +int xfs_dfork_nextents(xfs_dinode_t *dip, int w); +#define XFS_DFORK_NEXTENTS_ARCH(dip,w,arch) xfs_dfork_nextents_arch(dip,w,arch) +#define XFS_DFORK_NEXTENTS(dip,w) xfs_dfork_nextents(dip,w) +#else +#define XFS_DFORK_NEXTENTS_ARCH(dip,w,arch) XFS_CFORK_NEXTENTS_ARCH(&(dip)->di_core, w, arch) +#define XFS_DFORK_NEXTENTS(dip,w) XFS_DFORK_NEXTENTS_ARCH(dip,w,ARCH_NOCONVERT) + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DFORK_NEXT_SET) +void xfs_dfork_next_set_arch(xfs_dinode_t *dip, int w, int n, xfs_arch_t arch); +void xfs_dfork_next_set(xfs_dinode_t *dip, int w, int n); +#define XFS_DFORK_NEXT_SET_ARCH(dip,w,n,arch) xfs_dfork_next_set_arch(dip,w,n,arch) +#define XFS_DFORK_NEXT_SET(dip,w,n) xfs_dfork_next_set(dip,w,n) +#else +#define XFS_DFORK_NEXT_SET_ARCH(dip,w,n,arch) XFS_CFORK_NEXT_SET_ARCH(&(dip)->di_core, w, n, arch) +#define XFS_DFORK_NEXT_SET(dip,w,n) XFS_DFORK_NEXT_SET_ARCH(dip,w,n,ARCH_NOCONVERT) + +#endif + +/* + * File types (mode field) + */ +#define IFMT 0170000 /* type of file */ +#define IFIFO 0010000 /* named pipe (fifo) */ +#define IFCHR 0020000 /* character special */ +#define IFDIR 0040000 /* directory */ +#define IFBLK 0060000 /* block special */ +#define IFREG 0100000 /* regular */ +#define IFLNK 0120000 /* symbolic link */ +#define IFSOCK 0140000 /* socket */ +#define IFMNT 0160000 /* mount point */ + +/* + * File execution and access modes. + */ +#define ISUID 04000 /* set user id on execution */ +#define ISGID 02000 /* set group id on execution */ +#define ISVTX 01000 /* sticky directory */ +#define IREAD 0400 /* read, write, execute permissions */ +#define IWRITE 0200 +#define IEXEC 0100 + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_DINODE) +xfs_dinode_t *xfs_buf_to_dinode(struct xfs_buf *bp); +#define XFS_BUF_TO_DINODE(bp) xfs_buf_to_dinode(bp) +#else +#define XFS_BUF_TO_DINODE(bp) ((xfs_dinode_t *)(XFS_BUF_PTR(bp))) +#endif + +/* + * Values for di_flags + * There should be a one-to-one correspondence between these flags and the + * XFS_XFLAG_s. + */ +#define XFS_DIFLAG_REALTIME_BIT 0 /* file's blocks come from rt area */ +#define XFS_DIFLAG_PREALLOC_BIT 1 /* file space has been preallocated */ +#define XFS_DIFLAG_NEWRTBM_BIT 2 /* for rtbitmap inode, new format */ +#define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) +#define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) +#define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) +#define XFS_DIFLAG_ALL \ + (XFS_DIFLAG_REALTIME|XFS_DIFLAG_PREALLOC|XFS_DIFLAG_NEWRTBM) + +#endif /* __XFS_DINODE_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir.c linux-2.4-xfs/linux/fs/xfs/xfs_dir.c --- linux-2.4.7/linux/fs/xfs/xfs_dir.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir.c Wed Apr 18 21:37:23 2001 @@ -0,0 +1,1195 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +/* + * xfs_dir.c + * + * Provide the external interfaces to manage directories. + */ + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Functions for the dirops interfaces. + */ +static void xfs_dir_mount(struct xfs_mount *mp); + +static int xfs_dir_isempty(struct xfs_inode *dp); + +static int xfs_dir_init(struct xfs_trans *trans, + struct xfs_inode *dir, + struct xfs_inode *parent_dir); + +static int xfs_dir_createname(struct xfs_trans *trans, + struct xfs_inode *dp, + char *name_string, + int name_len, + xfs_ino_t inode_number, + xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, + xfs_extlen_t total); + +static int xfs_dir_lookup(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name_string, + int name_length, + xfs_ino_t *inode_number); + +static int xfs_dir_removename(struct xfs_trans *trans, + struct xfs_inode *dp, + char *name_string, + int name_length, + xfs_ino_t ino, + xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, + xfs_extlen_t total); + +static int xfs_dir_getdents(struct xfs_trans *tp, + struct xfs_inode *dp, + struct uio *uiop, + int *eofp); + +static int xfs_dir_replace(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name_string, + int name_length, + xfs_ino_t inode_number, + xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, + xfs_extlen_t total); + +static int xfs_dir_canenter(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name_string, + int name_length); + +static int xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp, + xfs_dinode_t *dip); + +xfs_dirops_t xfsv1_dirops = { + xd_mount: xfs_dir_mount, + xd_isempty: xfs_dir_isempty, + xd_init: xfs_dir_init, + xd_createname: xfs_dir_createname, + xd_lookup: xfs_dir_lookup, + xd_removename: xfs_dir_removename, + xd_getdents: xfs_dir_getdents, + xd_replace: xfs_dir_replace, + xd_canenter: xfs_dir_canenter, + xd_shortform_validate_ondisk: xfs_dir_shortform_validate_ondisk, + xd_shortform_to_single: xfs_dir_shortform_to_leaf, +}; + +/* + * Internal routines when dirsize == XFS_LBSIZE(mp). + */ +STATIC int xfs_dir_leaf_lookup(xfs_da_args_t *args); +STATIC int xfs_dir_leaf_removename(xfs_da_args_t *args, int *number_entries, + int *total_namebytes); +STATIC int xfs_dir_leaf_getdents(xfs_trans_t *trans, xfs_inode_t *dp, + uio_t *uio, int *eofp, + xfs_dirent_t *dbp, + xfs_dir_put_t put); +STATIC int xfs_dir_leaf_replace(xfs_da_args_t *args); + +/* + * Internal routines when dirsize > XFS_LBSIZE(mp). + */ +STATIC int xfs_dir_node_addname(xfs_da_args_t *args); +STATIC int xfs_dir_node_lookup(xfs_da_args_t *args); +STATIC int xfs_dir_node_removename(xfs_da_args_t *args); +STATIC int xfs_dir_node_getdents(xfs_trans_t *trans, xfs_inode_t *dp, + uio_t *uio, int *eofp, + xfs_dirent_t *dbp, + xfs_dir_put_t put); +STATIC int xfs_dir_node_replace(xfs_da_args_t *args); + +#if defined(DEBUG) +ktrace_t *xfs_dir_trace_buf; +#endif + + +/*======================================================================== + * Overall external interface routines. + *========================================================================*/ + +xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot; + +/* + * One-time startup routine called from xfs_init(). + */ +void +xfs_dir_startup(void) +{ + xfs_dir_hash_dot = xfs_da_hashname(".", 1); + xfs_dir_hash_dotdot = xfs_da_hashname("..", 2); +} + +/* + * Initialize directory-related fields in the mount structure. + */ +static void +xfs_dir_mount(xfs_mount_t *mp) +{ + uint shortcount, leafcount, count; + + mp->m_dirversion = 1; + shortcount = (mp->m_attroffset - (uint)sizeof(xfs_dir_sf_hdr_t)) / + (uint)sizeof(xfs_dir_sf_entry_t); + leafcount = (XFS_LBSIZE(mp) - (uint)sizeof(xfs_dir_leaf_hdr_t)) / + ((uint)sizeof(xfs_dir_leaf_entry_t) + + (uint)sizeof(xfs_dir_leaf_name_t)); + count = shortcount > leafcount ? shortcount : leafcount; + mp->m_dircook_elog = xfs_da_log2_roundup(count + 1); + ASSERT(mp->m_dircook_elog <= mp->m_sb.sb_blocklog); + mp->m_da_node_ents = + (XFS_LBSIZE(mp) - (uint)sizeof(xfs_da_node_hdr_t)) / + (uint)sizeof(xfs_da_node_entry_t); + mp->m_dir_magicpct = (XFS_LBSIZE(mp) * 37) / 100; + mp->m_dirblksize = mp->m_sb.sb_blocksize; + mp->m_dirblkfsbs = 1; +} + +/* + * Return 1 if directory contains only "." and "..". + */ +static int +xfs_dir_isempty(xfs_inode_t *dp) +{ + xfs_dir_sf_hdr_t *hdr; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (dp->i_d.di_size == 0) + return(1); + if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp)) + return(0); + hdr = (xfs_dir_sf_hdr_t *)dp->i_df.if_u1.if_data; + return(hdr->count == 0); +} + +/* + * Initialize a directory with its "." and ".." entries. + */ +static int +xfs_dir_init(xfs_trans_t *trans, xfs_inode_t *dir, xfs_inode_t *parent_dir) +{ + xfs_da_args_t args; + int error; + + bzero((char *)&args, sizeof(args)); + args.dp = dir; + args.trans = trans; + + ASSERT((dir->i_d.di_mode & IFMT) == IFDIR); + if ((error = xfs_dir_ino_validate(trans->t_mountp, parent_dir->i_ino))) + return error; + + return(xfs_dir_shortform_create(&args, parent_dir->i_ino)); +} + +/* + * Generic handler routine to add a name to a directory. + * Transitions directory from shortform to Btree as necessary. + */ +static int /* error */ +xfs_dir_createname(xfs_trans_t *trans, xfs_inode_t *dp, char *name, + int namelen, xfs_ino_t inum, xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, xfs_extlen_t total) +{ + xfs_da_args_t args; + int retval, newsize, done; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + + if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum))) + return (retval); + + XFS_STATS_INC(xfsstats.xs_dir_create); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = inum; + args.dp = dp; + args.firstblock = firstblock; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = trans; + args.justcheck = 0; + args.addname = args.oknoent = 1; + + /* + * Decide on what work routines to call based on the inode size. + */ + done = 0; + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + newsize = XFS_DIR_SF_ENTSIZE_BYNAME(args.namelen); + if ((dp->i_d.di_size + newsize) <= XFS_IFORK_DSIZE(dp)) { + retval = xfs_dir_shortform_addname(&args); + done = 1; + } else { + if (total == 0) + return XFS_ERROR(ENOSPC); + retval = xfs_dir_shortform_to_leaf(&args); + done = retval != 0; + } + } + if (!done && xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_addname(&args); + done = retval != ENOSPC; + if (!done) { + if (total == 0) + return XFS_ERROR(ENOSPC); + retval = xfs_dir_leaf_to_node(&args); + done = retval != 0; + } + } + if (!done) { + retval = xfs_dir_node_addname(&args); + } + return(retval); +} + +/* + * Generic handler routine to check if a name can be added to a directory, + * without adding any blocks to the directory. + */ +static int /* error */ +xfs_dir_canenter(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen) +{ + xfs_da_args_t args; + int retval, newsize; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = 0; + args.dp = dp; + args.firstblock = NULL; + args.flist = NULL; + args.total = 0; + args.whichfork = XFS_DATA_FORK; + args.trans = trans; + args.justcheck = args.addname = args.oknoent = 1; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + newsize = XFS_DIR_SF_ENTSIZE_BYNAME(args.namelen); + if ((dp->i_d.di_size + newsize) <= XFS_IFORK_DSIZE(dp)) + retval = 0; + else + retval = XFS_ERROR(ENOSPC); + } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_addname(&args); + } else { + retval = xfs_dir_node_addname(&args); + } + return(retval); +} + +/* + * Generic handler routine to remove a name from a directory. + * Transitions directory from Btree to shortform as necessary. + */ +static int /* error */ +xfs_dir_removename(xfs_trans_t *trans, xfs_inode_t *dp, char *name, + int namelen, xfs_ino_t ino, xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, xfs_extlen_t total) +{ + xfs_da_args_t args; + int count, totallen, newsize, retval; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + XFS_STATS_INC(xfsstats.xs_dir_remove); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = ino; + args.dp = dp; + args.firstblock = firstblock; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = trans; + args.justcheck = args.addname = args.oknoent = 0; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + retval = xfs_dir_shortform_removename(&args); + } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_removename(&args, &count, &totallen); + if (retval == 0) { + newsize = XFS_DIR_SF_ALLFIT(count, totallen); + if (newsize <= XFS_IFORK_DSIZE(dp)) { + retval = xfs_dir_leaf_to_shortform(&args); + } + } + } else { + retval = xfs_dir_node_removename(&args); + } + return(retval); +} + +static int /* error */ +xfs_dir_lookup(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen, + xfs_ino_t *inum) +{ + xfs_da_args_t args; + int retval; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (namelen >= MAXNAMELEN) { + return(XFS_ERROR(EINVAL)); + } + + XFS_STATS_INC(xfsstats.xs_dir_lookup); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = 0; + args.dp = dp; + args.firstblock = NULL; + args.flist = NULL; + args.total = 0; + args.whichfork = XFS_DATA_FORK; + args.trans = trans; + args.justcheck = args.addname = 0; + args.oknoent = 1; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + retval = xfs_dir_shortform_lookup(&args); + } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_lookup(&args); + } else { + retval = xfs_dir_node_lookup(&args); + } + if (retval == EEXIST) + retval = 0; + *inum = args.inumber; + return(retval); +} + +/* + * Implement readdir. + */ +static int /* error */ +xfs_dir_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, int *eofp) +{ + xfs_dirent_t *dbp; + int alignment, retval, is32; + xfs_dir_put_t put; + + XFS_STATS_INC(xfsstats.xs_dir_getdents); + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + + /* + * If our caller has given us a single contiguous memory buffer, + * just work directly within that buffer. If it's in user memory, + * lock it down first. + */ + is32 = ABI_IS_IRIX5(GETDENTS_ABI(get_current_abi(), uio)); + alignment = (is32 ? sizeof(xfs32_off_t) : sizeof(xfs_off_t)) - 1; + if ((uio->uio_iovcnt == 1) && +#if CELL_CAPABLE + !KT_CUR_ISXTHREAD() && +#endif + (((__psint_t)uio->uio_iov[0].iov_base & alignment) == 0) && + ((uio->uio_iov[0].iov_len & alignment) == 0)) { + dbp = NULL; + if (uio->uio_segflg == UIO_SYSSPACE) { + put = xfs_dir_put_dirent64_direct; + } else { + put = is32 ? + xfs_dir_put_dirent32_direct : + xfs_dir_put_dirent64_direct; + } + } else { + dbp = kmem_alloc(sizeof(*dbp) + MAXNAMELEN, KM_SLEEP); + put = is32 ? + xfs_dir_put_dirent32_uio : + xfs_dir_put_dirent64_uio; + } + + /* + * Decide on what work routines to call based on the inode size. + */ + *eofp = 0; + + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + retval = xfs_dir_shortform_getdents(dp, uio, eofp, dbp, put); + } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_getdents(trans, dp, uio, eofp, dbp, put); + } else { + retval = xfs_dir_node_getdents(trans, dp, uio, eofp, dbp, put); + } + if (dbp != NULL) + kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN); + + return(retval); +} + +static int /* error */ +xfs_dir_replace(xfs_trans_t *trans, xfs_inode_t *dp, char *name, int namelen, + xfs_ino_t inum, xfs_fsblock_t *firstblock, + xfs_bmap_free_t *flist, xfs_extlen_t total) +{ + xfs_da_args_t args; + int retval; + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (namelen >= MAXNAMELEN) { + return(XFS_ERROR(EINVAL)); + } + + if ((retval = xfs_dir_ino_validate(trans->t_mountp, inum))) + return retval; + + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = inum; + args.dp = dp; + args.firstblock = firstblock; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = trans; + args.justcheck = args.addname = args.oknoent = 0; + + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { + retval = xfs_dir_shortform_replace(&args); + } else if (xfs_bmap_one_block(dp, XFS_DATA_FORK)) { + retval = xfs_dir_leaf_replace(&args); + } else { + retval = xfs_dir_node_replace(&args); + } + + return(retval); +} + +static int +xfs_dir_shortform_validate_ondisk(xfs_mount_t *mp, xfs_dinode_t *dp) +{ + xfs_ino_t ino; + int namelen_sum; + int count; + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + int i; + + + + if ((INT_GET(dp->di_core.di_mode, ARCH_CONVERT) & IFMT) != IFDIR) { + return 0; + } + if (INT_GET(dp->di_core.di_format, ARCH_CONVERT) != XFS_DINODE_FMT_LOCAL) { + return 0; + } + if (INT_GET(dp->di_core.di_size, ARCH_CONVERT) < sizeof(sf->hdr)) { + xfs_fs_cmn_err(CE_WARN, mp, "Invalid shortform size: dp 0x%p\n", + dp); + return 1; + } + sf = (xfs_dir_shortform_t *)(&dp->di_u.di_dirsf); + ino = XFS_GET_DIR_INO_ARCH(mp, sf->hdr.parent, ARCH_CONVERT); + if (xfs_dir_ino_validate(mp, ino)) + return 1; + + count = sf->hdr.count; + if ((count < 0) || ((count * 10) > XFS_LITINO(mp))) { + xfs_fs_cmn_err(CE_WARN, mp, + "Invalid shortform count: dp 0x%p\n", dp); + return(1); + } + + if (count == 0) { + return 0; + } + + namelen_sum = 0; + sfe = &sf->list[0]; + for (i = sf->hdr.count - 1; i >= 0; i--) { + ino = XFS_GET_DIR_INO_ARCH(mp, sfe->inumber, ARCH_CONVERT); + xfs_dir_ino_validate(mp, ino); + if (sfe->namelen >= XFS_LITINO(mp)) { + xfs_fs_cmn_err(CE_WARN, mp, + "Invalid shortform namelen: dp 0x%p\n", dp); + return 1; + } + namelen_sum += sfe->namelen; + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + if (namelen_sum >= XFS_LITINO(mp)) { + xfs_fs_cmn_err(CE_WARN, mp, + "Invalid shortform namelen: dp 0x%p\n", dp); + return 1; + } + + return 0; +} + +/*======================================================================== + * External routines when dirsize == XFS_LBSIZE(dp->i_mount). + *========================================================================*/ + +/* + * Add a name to the leaf directory structure + * This is the external routine. + */ +int +xfs_dir_leaf_addname(xfs_da_args_t *args) +{ + int index, retval; + xfs_dabuf_t *bp; + + retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + + retval = xfs_dir_leaf_lookup_int(bp, args, &index); + if (retval == ENOENT) + retval = xfs_dir_leaf_add(bp, args, index); + xfs_da_buf_done(bp); + return(retval); +} + +/* + * Remove a name from the leaf directory structure + * This is the external routine. + */ +STATIC int +xfs_dir_leaf_removename(xfs_da_args_t *args, int *count, int *totallen) +{ + xfs_dir_leafblock_t *leaf; + int index, retval; + xfs_dabuf_t *bp; + + retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + retval = xfs_dir_leaf_lookup_int(bp, args, &index); + if (retval == EEXIST) { + (void)xfs_dir_leaf_remove(args->trans, bp, index); + *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + *totallen = INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); + retval = 0; + } + xfs_da_buf_done(bp); + return(retval); +} + +/* + * Look up a name in a leaf directory structure. + * This is the external routine. + */ +STATIC int +xfs_dir_leaf_lookup(xfs_da_args_t *args) +{ + int index, retval; + xfs_dabuf_t *bp; + + retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + retval = xfs_dir_leaf_lookup_int(bp, args, &index); + xfs_da_brelse(args->trans, bp); + return(retval); +} + +/* + * Copy out directory entries for getdents(), for leaf directories. + */ +STATIC int +xfs_dir_leaf_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, + int *eofp, xfs_dirent_t *dbp, xfs_dir_put_t put) +{ + xfs_dabuf_t *bp; + int retval, eob; + + retval = xfs_da_read_buf(dp->i_transp, dp, 0, -1, &bp, XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + retval = xfs_dir_leaf_getdents_int(bp, dp, 0, uio, &eob, dbp, put, -1); + xfs_da_brelse(trans, bp); + *eofp = (eob == 0); + return(retval); +} + +/* + * Look up a name in a leaf directory structure, replace the inode number. + * This is the external routine. + */ +STATIC int +xfs_dir_leaf_replace(xfs_da_args_t *args) +{ + int index, retval; + xfs_dabuf_t *bp; + xfs_ino_t inum; + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + + inum = args->inumber; + retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + retval = xfs_dir_leaf_lookup_int(bp, args, &index); + if (retval == EEXIST) { + leaf = bp->data; + entry = &leaf->entries[index]; + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + /* XXX - replace assert? */ + XFS_DIR_SF_PUT_DIRINO_ARCH(&inum, &namest->inumber, ARCH_CONVERT); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber))); + xfs_da_buf_done(bp); + retval = 0; + } else + xfs_da_brelse(args->trans, bp); + return(retval); +} + + +/*======================================================================== + * External routines when dirsize > XFS_LBSIZE(mp). + *========================================================================*/ + +/* + * Add a name to a Btree-format directory. + * + * This will involve walking down the Btree, and may involve splitting + * leaf nodes and even splitting intermediate nodes up to and including + * the root node (a special case of an intermediate node). + */ +STATIC int +xfs_dir_node_addname(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + xfs_da_state_blk_t *blk; + int retval, error; + + /* + * Fill in bucket of arguments/results/context to carry around. + */ + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + + /* + * Search to see if name already exists, and get back a pointer + * to where it should go. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) + retval = error; + if (retval != ENOENT) + goto error; + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); + retval = xfs_dir_leaf_add(blk->bp, args, blk->index); + if (retval == 0) { + /* + * Addition succeeded, update Btree hashvals. + */ + if (!args->justcheck) + xfs_da_fixhashpath(state, &state->path); + } else { + /* + * Addition failed, split as many Btree elements as required. + */ + if (args->total == 0) { + ASSERT(retval == ENOSPC); + goto error; + } + retval = xfs_da_split(state); + } +error: + xfs_da_state_free(state); + + return(retval); +} + +/* + * Remove a name from a B-tree directory. + * + * This will involve walking down the Btree, and may involve joining + * leaf nodes and even joining intermediate nodes up to and including + * the root node (a special case of an intermediate node). + */ +STATIC int +xfs_dir_node_removename(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + xfs_da_state_blk_t *blk; + int retval, error; + + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + + /* + * Search to see if name exists, and get back a pointer to it. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) + retval = error; + if (retval != EEXIST) { + xfs_da_state_free(state); + return(retval); + } + + /* + * Remove the name and update the hashvals in the tree. + */ + blk = &state->path.blk[ state->path.active-1 ]; + ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); + retval = xfs_dir_leaf_remove(args->trans, blk->bp, blk->index); + xfs_da_fixhashpath(state, &state->path); + + /* + * Check to see if the tree needs to be collapsed. + */ + error = 0; + if (retval) { + error = xfs_da_join(state); + } + + xfs_da_state_free(state); + if (error) + return(error); + return(0); +} + +/* + * Look up a filename in a int directory. + * Use an internal routine to actually do all the work. + */ +STATIC int +xfs_dir_node_lookup(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + int retval, error, i; + + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + + /* + * Search to see if name exists, + * and get back a pointer to it. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) { + retval = error; + } + + /* + * If not in a transaction, we have to release all the buffers. + */ + for (i = 0; i < state->path.active; i++) { + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + + xfs_da_state_free(state); + return(retval); +} + +STATIC int +xfs_dir_node_getdents(xfs_trans_t *trans, xfs_inode_t *dp, uio_t *uio, + int *eofp, xfs_dirent_t *dbp, xfs_dir_put_t put) +{ + xfs_da_intnode_t *node; + xfs_da_node_entry_t *btree; + xfs_dir_leafblock_t *leaf; + xfs_dablk_t bno, nextbno; + xfs_dahash_t cookhash; + xfs_mount_t *mp; + int error, eob, i; + xfs_dabuf_t *bp; + xfs_daddr_t nextda; + + /* + * Pick up our context. + */ + mp = dp->i_mount; + bp = NULL; + bno = XFS_DA_COOKIE_BNO(mp, uio->uio_offset); + cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset); + + xfs_dir_trace_g_du("node: start", dp, uio); + + /* + * Re-find our place, even if we're confused about what our place is. + * + * First we check the block number from the magic cookie, it is a + * cache of where we ended last time. If we find a leaf block, and + * the starting hashval in that block is less than our desired + * hashval, then we run with it. + */ + if (bno > 0) { + error = xfs_da_read_buf(trans, dp, bno, -1, &bp, XFS_DATA_FORK); + if ((error != 0) && (error != EFSCORRUPTED)) + return(error); + if (bp) + leaf = bp->data; + if (bp && INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) { + xfs_dir_trace_g_dub("node: block not a leaf", + dp, uio, bno); + xfs_da_brelse(trans, bp); + bp = NULL; + } + if (bp && INT_GET(leaf->entries[0].hashval, ARCH_CONVERT) > cookhash) { + xfs_dir_trace_g_dub("node: leaf hash too large", + dp, uio, bno); + xfs_da_brelse(trans, bp); + bp = NULL; + } + if (bp && + cookhash > INT_GET(leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT)) { + xfs_dir_trace_g_dub("node: leaf hash too small", + dp, uio, bno); + xfs_da_brelse(trans, bp); + bp = NULL; + } + } + + /* + * If we did not find a leaf block from the blockno in the cookie, + * or we there was no blockno in the cookie (eg: first time thru), + * the we start at the top of the Btree and re-find our hashval. + */ + if (bp == NULL) { + xfs_dir_trace_g_du("node: start at root" , dp, uio); + bno = 0; + for (;;) { + error = xfs_da_read_buf(trans, dp, bno, -1, &bp, + XFS_DATA_FORK); + if (error) + return(error); + if (bp == NULL) + return(XFS_ERROR(EFSCORRUPTED)); + node = bp->data; + if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) + break; + btree = &node->btree[0]; + xfs_dir_trace_g_dun("node: node detail", dp, uio, node); + for (i = 0; i < INT_GET(node->hdr.count, ARCH_CONVERT); btree++, i++) { + if (INT_GET(btree->hashval, ARCH_CONVERT) >= cookhash) { + bno = INT_GET(btree->before, ARCH_CONVERT); + break; + } + } + if (i == INT_GET(node->hdr.count, ARCH_CONVERT)) { + xfs_da_brelse(trans, bp); + xfs_dir_trace_g_du("node: hash beyond EOF", + dp, uio); + uio->uio_offset = XFS_DA_MAKE_COOKIE(mp, 0, 0, + XFS_DA_MAXHASH); + *eofp = 1; + return(0); + } + xfs_dir_trace_g_dub("node: going to block", + dp, uio, bno); + xfs_da_brelse(trans, bp); + } + } + ASSERT(cookhash != XFS_DA_MAXHASH); + + /* + * We've dropped down to the (first) leaf block that contains the + * hashval we are interested in. Continue rolling upward thru the + * leaf blocks until we fill up our buffer. + */ + for (;;) { + leaf = bp->data; + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) { + xfs_dir_trace_g_dul("node: not a leaf", dp, uio, leaf); + xfs_da_brelse(trans, bp); + return XFS_ERROR(EFSCORRUPTED); + } + xfs_dir_trace_g_dul("node: leaf detail", dp, uio, leaf); + if ((nextbno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT))) { + nextda = xfs_da_reada_buf(trans, dp, nextbno, + XFS_DATA_FORK); + } else + nextda = -1; + error = xfs_dir_leaf_getdents_int(bp, dp, bno, uio, &eob, dbp, + put, nextda); + xfs_da_brelse(trans, bp); + bno = nextbno; + if (eob) { + xfs_dir_trace_g_dub("node: E-O-B", dp, uio, bno); + *eofp = 0; + return(error); + } + if (bno == 0) + break; + error = xfs_da_read_buf(trans, dp, bno, nextda, &bp, + XFS_DATA_FORK); + if (error) + return(error); + if (bp == NULL) + return(XFS_ERROR(EFSCORRUPTED)); + } + *eofp = 1; + xfs_dir_trace_g_du("node: E-O-F", dp, uio); + return(0); +} + +/* + * Look up a filename in an int directory, replace the inode number. + * Use an internal routine to actually do the lookup. + */ +STATIC int +xfs_dir_node_replace(xfs_da_args_t *args) +{ + xfs_da_state_t *state; + xfs_da_state_blk_t *blk; + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + xfs_ino_t inum; + int retval, error, i; + xfs_dabuf_t *bp; + + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_sb.sb_blocksize; + inum = args->inumber; + + /* + * Search to see if name exists, + * and get back a pointer to it. + */ + error = xfs_da_node_lookup_int(state, &retval); + if (error) { + retval = error; + } + + if (retval == EEXIST) { + blk = &state->path.blk[state->path.active - 1]; + ASSERT(blk->magic == XFS_DIR_LEAF_MAGIC); + bp = blk->bp; + leaf = bp->data; + entry = &leaf->entries[blk->index]; + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + /* XXX - replace assert ? */ + XFS_DIR_SF_PUT_DIRINO_ARCH(&inum, &namest->inumber, ARCH_CONVERT); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, namest, sizeof(namest->inumber))); + xfs_da_buf_done(bp); + blk->bp = NULL; + retval = 0; + } else { + i = state->path.active - 1; + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + for (i = 0; i < state->path.active - 1; i++) { + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + + xfs_da_state_free(state); + return(retval); +} + +#if defined(XFS_DIR_TRACE) +/* + * Add a trace buffer entry for an inode and a uio. + */ +void +xfs_dir_trace_g_du(char *where, xfs_inode_t *dp, uio_t *uio) +{ + xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DU, where, + (__psunsigned_t)dp, (__psunsigned_t)dp->i_mount, + (__psunsigned_t)(uio->uio_offset >> 32), + (__psunsigned_t)(uio->uio_offset & 0xFFFFFFFF), + (__psunsigned_t)uio->uio_resid, + NULL, NULL, NULL, NULL, NULL, NULL, NULL); +} + +/* + * Add a trace buffer entry for an inode and a uio. + */ +void +xfs_dir_trace_g_dub(char *where, xfs_inode_t *dp, uio_t *uio, xfs_dablk_t bno) +{ + xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUB, where, + (__psunsigned_t)dp, (__psunsigned_t)dp->i_mount, + (__psunsigned_t)(uio->uio_offset >> 32), + (__psunsigned_t)(uio->uio_offset & 0xFFFFFFFF), + (__psunsigned_t)uio->uio_resid, + (__psunsigned_t)bno, + NULL, NULL, NULL, NULL, NULL, NULL); +} + +/* + * Add a trace buffer entry for an inode and a uio. + */ +void +xfs_dir_trace_g_dun(char *where, xfs_inode_t *dp, uio_t *uio, + xfs_da_intnode_t *node) +{ + xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUN, where, + (__psunsigned_t)dp, (__psunsigned_t)dp->i_mount, + (__psunsigned_t)(uio->uio_offset >> 32), + (__psunsigned_t)(uio->uio_offset & 0xFFFFFFFF), + (__psunsigned_t)uio->uio_resid, + (__psunsigned_t)INT_GET(node->hdr.info.forw, ARCH_CONVERT), + (__psunsigned_t)INT_GET(node->hdr.count, ARCH_CONVERT), + (__psunsigned_t)INT_GET(node->btree[0].hashval, ARCH_CONVERT), + (__psunsigned_t)INT_GET(node->btree[INT_GET(node->hdr.count, ARCH_CONVERT)-1].hashval, ARCH_CONVERT), + NULL, NULL, NULL); +} + +/* + * Add a trace buffer entry for an inode and a uio. + */ +void +xfs_dir_trace_g_dul(char *where, xfs_inode_t *dp, uio_t *uio, + xfs_dir_leafblock_t *leaf) +{ + xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUL, where, + (__psunsigned_t)dp, (__psunsigned_t)dp->i_mount, + (__psunsigned_t)(uio->uio_offset >> 32), + (__psunsigned_t)(uio->uio_offset & 0xFFFFFFFF), + (__psunsigned_t)uio->uio_resid, + (__psunsigned_t)INT_GET(leaf->hdr.info.forw, ARCH_CONVERT), + (__psunsigned_t)INT_GET(leaf->hdr.count, ARCH_CONVERT), + (__psunsigned_t)INT_GET(leaf->entries[0].hashval, ARCH_CONVERT), + (__psunsigned_t)INT_GET(leaf->entries[ INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT), + NULL, NULL, NULL); +} + +/* + * Add a trace buffer entry for an inode and a uio. + */ +void +xfs_dir_trace_g_due(char *where, xfs_inode_t *dp, uio_t *uio, + xfs_dir_leaf_entry_t *entry) +{ + xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUE, where, + (__psunsigned_t)dp, (__psunsigned_t)dp->i_mount, + (__psunsigned_t)(uio->uio_offset >> 32), + (__psunsigned_t)(uio->uio_offset & 0xFFFFFFFF), + (__psunsigned_t)uio->uio_resid, + (__psunsigned_t)INT_GET(entry->hashval, ARCH_CONVERT), + NULL, NULL, NULL, NULL, NULL, NULL); +} + +/* + * Add a trace buffer entry for an inode and a uio. + */ +void +xfs_dir_trace_g_duc(char *where, xfs_inode_t *dp, uio_t *uio, xfs_off_t cookie) +{ + xfs_dir_trace_enter(XFS_DIR_KTRACE_G_DUC, where, + (__psunsigned_t)dp, (__psunsigned_t)dp->i_mount, + (__psunsigned_t)(uio->uio_offset >> 32), + (__psunsigned_t)(uio->uio_offset & 0xFFFFFFFF), + (__psunsigned_t)uio->uio_resid, + (__psunsigned_t)(cookie >> 32), + (__psunsigned_t)(cookie & 0xFFFFFFFF), + NULL, NULL, NULL, NULL, NULL); +} + +/* + * Add a trace buffer entry for the arguments given to the routine, + * generic form. + */ +void +xfs_dir_trace_enter(int type, char *where, + __psunsigned_t a0, __psunsigned_t a1, + __psunsigned_t a2, __psunsigned_t a3, + __psunsigned_t a4, __psunsigned_t a5, + __psunsigned_t a6, __psunsigned_t a7, + __psunsigned_t a8, __psunsigned_t a9, + __psunsigned_t a10, __psunsigned_t a11) +{ + ASSERT(xfs_dir_trace_buf); + ktrace_enter(xfs_dir_trace_buf, (void *)((__psunsigned_t)type), + (void *)where, + (void *)a0, (void *)a1, (void *)a2, + (void *)a3, (void *)a4, (void *)a5, + (void *)a6, (void *)a7, (void *)a8, + (void *)a9, (void *)a10, (void *)a11, + NULL, NULL); +} +#endif /* XFS_DIR_TRACE */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir.h linux-2.4-xfs/linux/fs/xfs/xfs_dir.h --- linux-2.4.7/linux/fs/xfs/xfs_dir.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR_H__ +#define __XFS_DIR_H__ + +/* + * Large directories are structured around Btrees where all the data + * elements are in the leaf nodes. Filenames are hashed into an int, + * then that int is used as the index into the Btree. Since the hashval + * of a filename may not be unique, we may have duplicate keys. The + * internal links in the Btree are logical block offsets into the file. + * + * Small directories use a different format and are packed as tightly + * as possible so as to fit into the literal area of the inode. + */ + +#ifdef XFS_ALL_TRACE +#define XFS_DIR_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_DIR_TRACE +#endif + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +struct uio; +struct xfs_bmap_free; +struct xfs_da_args; +struct xfs_dinode; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * Directory function types. + * Put in structures (xfs_dirops_t) for v1 and v2 directories. + */ +typedef void (*xfs_dir_mount_t)(struct xfs_mount *mp); +typedef int (*xfs_dir_isempty_t)(struct xfs_inode *dp); +typedef int (*xfs_dir_init_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + struct xfs_inode *pdp); +typedef int (*xfs_dir_createname_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name, + int namelen, + xfs_ino_t inum, + xfs_fsblock_t *first, + struct xfs_bmap_free *flist, + xfs_extlen_t total); +typedef int (*xfs_dir_lookup_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name, + int namelen, + xfs_ino_t *inum); +typedef int (*xfs_dir_removename_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name, + int namelen, + xfs_ino_t ino, + xfs_fsblock_t *first, + struct xfs_bmap_free *flist, + xfs_extlen_t total); +typedef int (*xfs_dir_getdents_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + struct uio *uio, + int *eofp); +typedef int (*xfs_dir_replace_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name, + int namelen, + xfs_ino_t inum, + xfs_fsblock_t *first, + struct xfs_bmap_free *flist, + xfs_extlen_t total); +typedef int (*xfs_dir_canenter_t)(struct xfs_trans *tp, + struct xfs_inode *dp, + char *name, + int namelen); +typedef int (*xfs_dir_shortform_validate_ondisk_t)(struct xfs_mount *mp, + struct xfs_dinode *dip); +typedef int (*xfs_dir_shortform_to_single_t)(struct xfs_da_args *args); + +typedef struct xfs_dirops { + xfs_dir_mount_t xd_mount; + xfs_dir_isempty_t xd_isempty; + xfs_dir_init_t xd_init; + xfs_dir_createname_t xd_createname; + xfs_dir_lookup_t xd_lookup; + xfs_dir_removename_t xd_removename; + xfs_dir_getdents_t xd_getdents; + xfs_dir_replace_t xd_replace; + xfs_dir_canenter_t xd_canenter; + xfs_dir_shortform_validate_ondisk_t xd_shortform_validate_ondisk; + xfs_dir_shortform_to_single_t xd_shortform_to_single; +} xfs_dirops_t; + +/* + * Overall external interface routines. + */ +void xfs_dir_startup(void); /* called exactly once */ + +#define XFS_DIR_MOUNT(mp) \ + ((mp)->m_dirops.xd_mount(mp)) +#define XFS_DIR_ISEMPTY(mp,dp) \ + ((mp)->m_dirops.xd_isempty(dp)) +#define XFS_DIR_INIT(mp,tp,dp,pdp) \ + ((mp)->m_dirops.xd_init(tp,dp,pdp)) +#define XFS_DIR_CREATENAME(mp,tp,dp,name,namelen,inum,first,flist,total) \ + ((mp)->m_dirops.xd_createname(tp,dp,name,namelen,inum,first,flist,\ + total)) +#define XFS_DIR_LOOKUP(mp,tp,dp,name,namelen,inum) \ + ((mp)->m_dirops.xd_lookup(tp,dp,name,namelen,inum)) +#define XFS_DIR_REMOVENAME(mp,tp,dp,name,namelen,ino,first,flist,total) \ + ((mp)->m_dirops.xd_removename(tp,dp,name,namelen,ino,first,flist,total)) +#define XFS_DIR_GETDENTS(mp,tp,dp,uio,eofp) \ + ((mp)->m_dirops.xd_getdents(tp,dp,uio,eofp)) +#define XFS_DIR_REPLACE(mp,tp,dp,name,namelen,inum,first,flist,total) \ + ((mp)->m_dirops.xd_replace(tp,dp,name,namelen,inum,first,flist,total)) +#define XFS_DIR_CANENTER(mp,tp,dp,name,namelen) \ + ((mp)->m_dirops.xd_canenter(tp,dp,name,namelen)) +#define XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp,dip) \ + ((mp)->m_dirops.xd_shortform_validate_ondisk(mp,dip)) +#define XFS_DIR_SHORTFORM_TO_SINGLE(mp,args) \ + ((mp)->m_dirops.xd_shortform_to_single(args)) + +#define XFS_DIR_IS_V1(mp) ((mp)->m_dirversion == 1) +extern xfs_dirops_t xfsv1_dirops; + +#endif /* __XFS_DIR_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir2.c linux-2.4-xfs/linux/fs/xfs/xfs_dir2.c --- linux-2.4.7/linux/fs/xfs/xfs_dir2.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir2.c Mon Apr 23 14:52:01 2001 @@ -0,0 +1,933 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * XFS v2 directory implmentation. + * Top-level and utility routines. + */ + +#include + +/* + * Declarations for interface routines. + */ +static void xfs_dir2_mount(xfs_mount_t *mp); +static int xfs_dir2_isempty(xfs_inode_t *dp); +static int xfs_dir2_init(xfs_trans_t *tp, xfs_inode_t *dp, + xfs_inode_t *pdp); +static int xfs_dir2_createname(xfs_trans_t *tp, xfs_inode_t *dp, + char *name, int namelen, xfs_ino_t inum, + xfs_fsblock_t *first, + xfs_bmap_free_t *flist, xfs_extlen_t total); +static int xfs_dir2_lookup(xfs_trans_t *tp, xfs_inode_t *dp, char *name, + int namelen, xfs_ino_t *inum); +static int xfs_dir2_removename(xfs_trans_t *tp, xfs_inode_t *dp, + char *name, int namelen, xfs_ino_t ino, + xfs_fsblock_t *first, + xfs_bmap_free_t *flist, xfs_extlen_t total); +static int xfs_dir2_getdents(xfs_trans_t *tp, xfs_inode_t *dp, uio_t *uio, + int *eofp); +static int xfs_dir2_replace(xfs_trans_t *tp, xfs_inode_t *dp, char *name, + int namelen, xfs_ino_t inum, + xfs_fsblock_t *first, xfs_bmap_free_t *flist, + xfs_extlen_t total); +static int xfs_dir2_canenter(xfs_trans_t *tp, xfs_inode_t *dp, char *name, + int namelen); +static int xfs_dir2_shortform_validate_ondisk(xfs_mount_t *mp, + xfs_dinode_t *dip); + +/* + * Utility routine declarations. + */ +static int xfs_dir2_put_dirent32_direct(xfs_dir2_put_args_t *pa); +static int xfs_dir2_put_dirent32_uio(xfs_dir2_put_args_t *pa); +static int xfs_dir2_put_dirent64_direct(xfs_dir2_put_args_t *pa); +static int xfs_dir2_put_dirent64_uio(xfs_dir2_put_args_t *pa); + +/* + * Directory operations vector. + */ +xfs_dirops_t xfsv2_dirops = { + xd_mount: xfs_dir2_mount, + xd_isempty: xfs_dir2_isempty, + xd_init: xfs_dir2_init, + xd_createname: xfs_dir2_createname, + xd_lookup: xfs_dir2_lookup, + xd_removename: xfs_dir2_removename, + xd_getdents: xfs_dir2_getdents, + xd_replace: xfs_dir2_replace, + xd_canenter: xfs_dir2_canenter, + xd_shortform_validate_ondisk: xfs_dir2_shortform_validate_ondisk, + xd_shortform_to_single: xfs_dir2_sf_to_block, +}; + +/* + * Interface routines. + */ + +/* + * Initialize directory-related fields in the mount structure. + */ +static void +xfs_dir2_mount( + xfs_mount_t *mp) /* filesystem mount point */ +{ + mp->m_dirversion = 2; + ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <= + XFS_MAX_BLOCKSIZE); + mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog); + mp->m_dirblkfsbs = 1 << mp->m_sb.sb_dirblklog; + mp->m_dirdatablk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_DATA_FIRSTDB(mp)); + mp->m_dirleafblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_LEAF_FIRSTDB(mp)); + mp->m_dirfreeblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_FREE_FIRSTDB(mp)); + mp->m_da_node_ents = + (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) / + (uint)sizeof(xfs_da_node_entry_t); + mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100; +} + +/* + * Return 1 if directory contains only "." and "..". + */ +static int /* return code */ +xfs_dir2_isempty( + xfs_inode_t *dp) /* incore inode structure */ +{ + xfs_dir2_sf_t *sfp; /* shortform directory structure */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + /* + * Might happen during shutdown. + */ + if (dp->i_d.di_size == 0) { + return 1; + } + if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp)) + return 0; + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + return INT_ISZERO(sfp->hdr.count, ARCH_CONVERT); +} + +/* + * Initialize a directory with its "." and ".." entries. + */ +static int /* error */ +xfs_dir2_init( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + xfs_inode_t *pdp) /* incore parent directory inode */ +{ + xfs_da_args_t args; /* operation arguments */ + int error; /* error return value */ + + bzero((char *)&args, sizeof(args)); + args.dp = dp; + args.trans = tp; + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) { + return error; + } + return xfs_dir2_sf_create(&args, pdp->i_ino); +} + +/* + Enter a name in a directory. + */ +static int /* error */ +xfs_dir2_createname( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + char *name, /* new entry name */ + int namelen, /* new entry name length */ + xfs_ino_t inum, /* new entry inode number */ + xfs_fsblock_t *first, /* bmap's firstblock */ + xfs_bmap_free_t *flist, /* bmap's freeblock list */ + xfs_extlen_t total) /* bmap's total block count */ +{ + xfs_da_args_t args; /* operation arguments */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) { + return rval; + } + XFS_STATS_INC(xfsstats.xs_dir_create); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = inum; + args.dp = dp; + args.firstblock = first; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = tp; + args.justcheck = 0; + args.addname = args.oknoent = 1; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_addname(&args); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_block_addname(&args); + else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_leaf_addname(&args); + else + rval = xfs_dir2_node_addname(&args); + return rval; +} + +/* + * Lookup a name in a directory, give back the inode number. + */ +static int /* error */ +xfs_dir2_lookup( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + char *name, /* lookup name */ + int namelen, /* lookup name length */ + xfs_ino_t *inum) /* out: inode number */ +{ + xfs_da_args_t args; /* operation arguments */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (namelen >= MAXNAMELEN) { + return XFS_ERROR(EINVAL); + } + XFS_STATS_INC(xfsstats.xs_dir_lookup); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = 0; + args.dp = dp; + args.firstblock = NULL; + args.flist = NULL; + args.total = 0; + args.whichfork = XFS_DATA_FORK; + args.trans = tp; + args.justcheck = args.addname = 0; + args.oknoent = 1; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_lookup(&args); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_block_lookup(&args); + else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_leaf_lookup(&args); + else + rval = xfs_dir2_node_lookup(&args); + if (rval == EEXIST) + rval = 0; + if (rval == 0) + *inum = args.inumber; + return rval; +} + +/* + * Remove an entry from a directory. + */ +static int /* error */ +xfs_dir2_removename( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + char *name, /* name of entry to remove */ + int namelen, /* name length of entry to remove */ + xfs_ino_t ino, /* inode number of entry to remove */ + xfs_fsblock_t *first, /* bmap's firstblock */ + xfs_bmap_free_t *flist, /* bmap's freeblock list */ + xfs_extlen_t total) /* bmap's total block count */ +{ + xfs_da_args_t args; /* operation arguments */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + XFS_STATS_INC(xfsstats.xs_dir_remove); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = ino; + args.dp = dp; + args.firstblock = first; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = tp; + args.justcheck = args.addname = args.oknoent = 0; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_removename(&args); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_block_removename(&args); + else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_leaf_removename(&args); + else + rval = xfs_dir2_node_removename(&args); + return rval; +} + +/* + * Read a directory. + */ +static int /* error */ +xfs_dir2_getdents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + uio_t *uio, /* caller's buffer control */ + int *eofp) /* out: eof reached */ +{ + int alignment; /* alignment required for ABI */ + xfs_dirent_t *dbp; /* malloc'ed buffer */ + int is32; /* is O32 abi - 4 byte alignment */ + xfs_dir2_put_t put; /* entry formatting routine */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + XFS_STATS_INC(xfsstats.xs_dir_getdents); + /* + * If our caller has given us a single contiguous aligned memory buffer, + * just work directly within that buffer. If it's in user memory, + * lock it down first. + */ + is32 = ABI_IS_IRIX5(GETDENTS_ABI(get_current_abi(), uio)); + alignment = (is32 ? sizeof(xfs32_off_t) : sizeof(xfs_off_t)) - 1; + if ((uio->uio_iovcnt == 1) && +#if CELL_CAPABLE + !KT_CUR_ISXTHREAD() && +#endif + (((__psint_t)uio->uio_iov[0].iov_base & alignment) == 0) && + ((uio->uio_iov[0].iov_len & alignment) == 0)) { + dbp = NULL; + if (uio->uio_segflg == UIO_SYSSPACE) { + put = xfs_dir2_put_dirent64_direct; + } else { + put = is32 ? + xfs_dir2_put_dirent32_direct : + xfs_dir2_put_dirent64_direct; + } + } else { + dbp = kmem_alloc(sizeof(*dbp) + MAXNAMELEN, KM_SLEEP); + put = is32 ? + xfs_dir2_put_dirent32_uio : + xfs_dir2_put_dirent64_uio; + } + *eofp = 0; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_getdents(dp, uio, eofp, dbp, put); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + ; + } else if (v) + rval = xfs_dir2_block_getdents(tp, dp, uio, eofp, dbp, put); + else + rval = xfs_dir2_leaf_getdents(tp, dp, uio, eofp, dbp, put); + if (dbp != NULL) + kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN); + return rval; +} + +/* + * Replace the inode number of a directory entry. + */ +static int /* error */ +xfs_dir2_replace( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + char *name, /* name of entry to replace */ + int namelen, /* name length of entry to replace */ + xfs_ino_t inum, /* new inode number */ + xfs_fsblock_t *first, /* bmap's firstblock */ + xfs_bmap_free_t *flist, /* bmap's freeblock list */ + xfs_extlen_t total) /* bmap's total block count */ +{ + xfs_da_args_t args; /* operation arguments */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + if (namelen >= MAXNAMELEN) { + return XFS_ERROR(EINVAL); + } + if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) { + return rval; + } + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = inum; + args.dp = dp; + args.firstblock = first; + args.flist = flist; + args.total = total; + args.whichfork = XFS_DATA_FORK; + args.trans = tp; + args.justcheck = args.addname = args.oknoent = 0; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_replace(&args); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_block_replace(&args); + else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_leaf_replace(&args); + else + rval = xfs_dir2_node_replace(&args); + return rval; +} + +/* + * See if this entry can be added to the directory without allocating space. + */ +static int /* error */ +xfs_dir2_canenter( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + char *name, /* name of entry to add */ + int namelen) /* name length of entry to add */ +{ + xfs_da_args_t args; /* operation arguments */ + int rval; /* return value */ + int v; /* type-checking value */ + + ASSERT((dp->i_d.di_mode & IFMT) == IFDIR); + /* + * Fill in the arg structure for this request. + */ + args.name = name; + args.namelen = namelen; + args.hashval = xfs_da_hashname(name, namelen); + args.inumber = 0; + args.dp = dp; + args.firstblock = NULL; + args.flist = NULL; + args.total = 0; + args.whichfork = XFS_DATA_FORK; + args.trans = tp; + args.justcheck = args.addname = args.oknoent = 1; + /* + * Decide on what work routines to call based on the inode size. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) + rval = xfs_dir2_sf_addname(&args); + else if ((rval = xfs_dir2_isblock(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_block_addname(&args); + else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) { + return rval; + } else if (v) + rval = xfs_dir2_leaf_addname(&args); + else + rval = xfs_dir2_node_addname(&args); + return rval; +} + +/* + * Dummy routine for shortform inode validation. + * Can't really do this. + */ +/* ARGSUSED */ +static int /* error */ +xfs_dir2_shortform_validate_ondisk( + xfs_mount_t *mp, /* filesystem mount point */ + xfs_dinode_t *dip) /* ondisk inode */ +{ + return 0; +} + +/* + * Utility routines. + */ + +/* + * Add a block to the directory. + * This routine is for data and free blocks, not leaf/node blocks + * which are handled by xfs_da_grow_inode. + */ +int /* error */ +xfs_dir2_grow_inode( + xfs_da_args_t *args, /* operation arguments */ + int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */ + xfs_dir2_db_t *dbp) /* out: block number added */ +{ + xfs_fileoff_t bno; /* directory offset of new block */ + int count; /* count of filesystem blocks */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + int got; /* blocks actually mapped */ + int i; /* temp mapping index */ + xfs_bmbt_irec_t map; /* single structure for bmap */ + int mapi; /* mapping index */ + xfs_bmbt_irec_t *mapp; /* bmap mapping structure(s) */ + xfs_mount_t *mp; /* filesystem mount point */ + int nmap; /* number of bmap entries */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_s("grow_inode", args, space); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + /* + * Set lowest possible block in the space requested. + */ + bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE); + count = mp->m_dirblkfsbs; + /* + * Find the first hole for our block. + */ + if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, XFS_DATA_FORK))) { + return error; + } + nmap = 1; + ASSERT(args->firstblock != NULL); + /* + * Try mapping the new block contiguously (one extent). + */ + if ((error = xfs_bmapi(tp, dp, bno, count, + XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG, + args->firstblock, args->total, &map, &nmap, + args->flist))) { + return error; + } + ASSERT(nmap <= 1); + /* + * Got it in 1. + */ + if (nmap == 1) { + mapp = ↦ + mapi = 1; + } + /* + * Didn't work and this is a multiple-fsb directory block. + * Try again with contiguous flag turned on. + */ + else if (nmap == 0 && count > 1) { + xfs_fileoff_t b; /* current file offset */ + + /* + * Space for maximum number of mappings. + */ + mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP); + /* + * Iterate until we get to the end of our block. + */ + for (b = bno, mapi = 0; b < bno + count; ) { + int c; /* current fsb count */ + + /* + * Can't map more than MAX_NMAP at once. + */ + nmap = MIN(XFS_BMAP_MAX_NMAP, count); + c = (int)(bno + count - b); + if ((error = xfs_bmapi(tp, dp, b, c, + XFS_BMAPI_WRITE|XFS_BMAPI_METADATA, + args->firstblock, args->total, + &mapp[mapi], &nmap, args->flist))) { + kmem_free(mapp, sizeof(*mapp) * count); + return error; + } + if (nmap < 1) + break; + /* + * Add this bunch into our table, go to the next offset. + */ + mapi += nmap; + b = mapp[mapi - 1].br_startoff + + mapp[mapi - 1].br_blockcount; + } + } + /* + * Didn't work. + */ + else { + mapi = 0; + mapp = NULL; + } + /* + * See how many fsb's we got. + */ + for (i = 0, got = 0; i < mapi; i++) + got += mapp[i].br_blockcount; + /* + * Didn't get enough fsb's, or the first/last block's are wrong. + */ + if (got != count || mapp[0].br_startoff != bno || + mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != + bno + count) { + if (mapp != &map) + kmem_free(mapp, sizeof(*mapp) * count); + return XFS_ERROR(ENOSPC); + } + /* + * Done with the temporary mapping table. + */ + if (mapp != &map) + kmem_free(mapp, sizeof(*mapp) * count); + *dbp = XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)bno); + /* + * Update file's size if this is the data space and it grew. + */ + if (space == XFS_DIR2_DATA_SPACE) { + xfs_fsize_t size; /* directory file (data) size */ + + size = XFS_FSB_TO_B(mp, bno + count); + if (size > dp->i_d.di_size) { + dp->i_d.di_size = size; + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + } + } + return 0; +} + +/* + * See if the directory is a single-block form directory. + */ +int /* error */ +xfs_dir2_isblock( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + int *vp) /* out: 1 is block, 0 is not block */ +{ + xfs_fileoff_t last; /* last file offset */ + xfs_mount_t *mp; /* filesystem mount point */ + int rval; /* return value */ + + mp = dp->i_mount; + if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) { + return rval; + } + rval = XFS_FSB_TO_B(mp, last) == mp->m_dirblksize; + ASSERT(rval == 0 || dp->i_d.di_size == mp->m_dirblksize); + *vp = rval; + return 0; +} + +/* + * See if the directory is a single-leaf form directory. + */ +int /* error */ +xfs_dir2_isleaf( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + int *vp) /* out: 1 is leaf, 0 is not leaf */ +{ + xfs_fileoff_t last; /* last file offset */ + xfs_mount_t *mp; /* filesystem mount point */ + int rval; /* return value */ + + mp = dp->i_mount; + if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) { + return rval; + } + *vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog); + return 0; +} + +/* + * Getdents put routine for 32-bit ABI, direct form. + */ +static int /* error */ +xfs_dir2_put_dirent32_direct( + xfs_dir2_put_args_t *pa) /* argument bundle */ +{ + xfs_dirent32_t *idbp; /* dirent pointer */ + iovec_t *iovp; /* io vector */ + int namelen; /* entry name length */ + int reclen; /* entry total length */ + uio_t *uio; /* I/O control */ + +#if XFS_BIG_FILESYSTEMS + /* + * Error if the inode number is too big to fit. + */ + if (pa->ino > XFS_MAXINUMBER_32) { + pa->done = 0; + return XFS_ERROR(EOVERFLOW); + } +#endif + namelen = pa->namelen; + reclen = DIRENT32SIZE(namelen); + uio = pa->uio; + /* + * Won't fit in the remaining space. + */ + if (reclen > uio->uio_resid) { + pa->done = 0; + return 0; + } + iovp = uio->uio_iov; + idbp = (xfs_dirent32_t *)iovp->iov_base; + iovp->iov_base = (char *)idbp + reclen; + iovp->iov_len -= reclen; + uio->uio_resid -= reclen; + idbp->d_reclen = reclen; + idbp->d_ino = pa->ino; + idbp->d_off = pa->cook; + idbp->d_name[namelen] = '\0'; + pa->done = 1; + bcopy(pa->name, idbp->d_name, namelen); + return 0; +} + +/* + * Getdents put routine for 32-bit ABI, uio form. + */ +static int /* error */ +xfs_dir2_put_dirent32_uio( + xfs_dir2_put_args_t *pa) /* argument bundle */ +{ + xfs_dirent32_t *idbp; /* dirent pointer */ + int namelen; /* entry name length */ + int reclen; /* entry total length */ + int rval; /* return value */ + uio_t *uio; /* I/O control */ + +#if XFS_BIG_FILESYSTEMS + /* + * Error if the inode number is too big to fit. + */ + if (pa->ino > XFS_MAXINUMBER_32) { + pa->done = 0; + return XFS_ERROR(EOVERFLOW); + } +#endif + namelen = pa->namelen; + reclen = DIRENT32SIZE(namelen); + uio = pa->uio; + /* + * Won't fit in the remaining space. + */ + if (reclen > uio->uio_resid) { + pa->done = 0; + return 0; + } + idbp = (xfs_dirent32_t *)pa->dbp; + idbp->d_reclen = reclen; + idbp->d_ino = pa->ino; + idbp->d_off = pa->cook; + idbp->d_name[namelen] = '\0'; + bcopy(pa->name, idbp->d_name, namelen); + rval = uiomove((caddr_t)idbp, reclen, UIO_READ, uio); + pa->done = (rval == 0); + return rval; +} + +/* + * Getdents put routine for 64-bit ABI, direct form. + */ +static int /* error */ +xfs_dir2_put_dirent64_direct( + xfs_dir2_put_args_t *pa) /* argument bundle */ +{ + xfs_dirent_t *idbp; /* dirent pointer */ + iovec_t *iovp; /* io vector */ + int namelen; /* entry name length */ + int reclen; /* entry total length */ + uio_t *uio; /* I/O control */ + + namelen = pa->namelen; + reclen = DIRENTSIZE(namelen); + uio = pa->uio; + /* + * Won't fit in the remaining space. + */ + if (reclen > uio->uio_resid) { + pa->done = 0; + return 0; + } + iovp = uio->uio_iov; + idbp = (xfs_dirent_t *)iovp->iov_base; + iovp->iov_base = (char *)idbp + reclen; + iovp->iov_len -= reclen; + uio->uio_resid -= reclen; + idbp->d_reclen = reclen; + idbp->d_ino = pa->ino; + idbp->d_off = pa->cook; + idbp->d_name[namelen] = '\0'; + pa->done = 1; + bcopy(pa->name, idbp->d_name, namelen); + return 0; +} + +/* + * Getdents put routine for 64-bit ABI, uio form. + */ +static int /* error */ +xfs_dir2_put_dirent64_uio( + xfs_dir2_put_args_t *pa) /* argument bundle */ +{ + xfs_dirent_t *idbp; /* dirent pointer */ + int namelen; /* entry name length */ + int reclen; /* entry total length */ + int rval; /* return value */ + uio_t *uio; /* I/O control */ + + namelen = pa->namelen; + reclen = DIRENTSIZE(namelen); + uio = pa->uio; + /* + * Won't fit in the remaining space. + */ + if (reclen > uio->uio_resid) { + pa->done = 0; + return 0; + } + idbp = pa->dbp; + idbp->d_reclen = reclen; + idbp->d_ino = pa->ino; + idbp->d_off = pa->cook; + idbp->d_name[namelen] = '\0'; + bcopy(pa->name, idbp->d_name, namelen); + rval = uiomove((caddr_t)idbp, reclen, UIO_READ, uio); + pa->done = (rval == 0); + return rval; +} + +/* + * Remove the given block from the directory. + * This routine is used for data and free blocks, leaf/node are done + * by xfs_da_shrink_inode. + */ +int +xfs_dir2_shrink_inode( + xfs_da_args_t *args, /* operation arguments */ + xfs_dir2_db_t db, /* directory block number */ + xfs_dabuf_t *bp) /* block's buffer */ +{ + xfs_fileoff_t bno; /* directory file offset */ + xfs_dablk_t da; /* directory file offset */ + int done; /* bunmap is finished */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_db("shrink_inode", args, db, bp); + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + da = XFS_DIR2_DB_TO_DA(mp, db); + /* + * Unmap the fsblock(s). + */ + if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs, + XFS_BMAPI_METADATA, 0, args->firstblock, args->flist, + &done))) { + /* + * ENOSPC actually can happen if we're in a removename with + * no space reservation, and the resulting block removal + * would cause a bmap btree split or conversion from extents + * to btree. This can only happen for un-fragmented + * directory blocks, since you need to be punching out + * the middle of an extent. + * In this case we need to leave the block in the file, + * and not binval it. + * So the block has to be in a consistent empty state + * and appropriately logged. + * We don't free up the buffer, the caller can tell it + * hasn't happened since it got an error back. + */ + return error; + } + ASSERT(done); + /* + * Invalidate the buffer from the transaction. + */ + xfs_da_binval(tp, bp); + /* + * If it's not a data block, we're done. + */ + if (db >= XFS_DIR2_LEAF_FIRSTDB(mp)) + return 0; + /* + * If the block isn't the last one in the directory, we're done. + */ + if (dp->i_d.di_size > XFS_DIR2_DB_OFF_TO_BYTE(mp, db + 1, 0)) + return 0; + bno = da; + if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) { + /* + * This can't really happen unless there's kernel corruption. + */ + return error; + } + if (db == mp->m_dirdatablk) + ASSERT(bno == 0); + else + ASSERT(bno > 0); + /* + * Set the size to the new last block. + */ + dp->i_d.di_size = XFS_FSB_TO_B(mp, bno); + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + return 0; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir2.h linux-2.4-xfs/linux/fs/xfs/xfs_dir2.h --- linux-2.4.7/linux/fs/xfs/xfs_dir2.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir2.h Tue Apr 10 20:44:54 2001 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_H__ +#define __XFS_DIR2_H__ + +struct dirent; +struct uio; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_dir2_put_args; +struct xfs_inode; +struct xfs_trans; + +/* + * Directory version 2. + * There are 4 possible formats: + * shortform + * single block - data with embedded leaf at the end + * multiple data blocks, single leaf+freeindex block + * data blocks, node&leaf blocks (btree), freeindex blocks + * + * The shortform format is in xfs_dir2_sf.h. + * The single block format is in xfs_dir2_block.h. + * The data block format is in xfs_dir2_data.h. + * The leaf and freeindex block formats are in xfs_dir2_leaf.h. + * Node blocks are the same as the other version, in xfs_da_btree.h. + */ + +/* + * Byte offset in data block and shortform entry. + */ +typedef __uint16_t xfs_dir2_data_off_t; +#define NULLDATAOFF 0xffffU +typedef uint xfs_dir2_data_aoff_t; /* argument form */ + +/* + * Directory block number (logical dirblk in file) + */ +typedef __uint32_t xfs_dir2_db_t; + +/* + * Byte offset in a directory. + */ +typedef xfs_off_t xfs_dir2_off_t; + +/* + * For getdents, argument struct for put routines. + */ +typedef int (*xfs_dir2_put_t)(struct xfs_dir2_put_args *pa); +typedef struct xfs_dir2_put_args { + xfs_off_t cook; /* cookie of (next) entry */ + xfs_intino_t ino; /* inode number */ + struct xfs_dirent *dbp; /* buffer pointer */ + char *name; /* directory entry name */ + int namelen; /* length of name */ + int done; /* output: set if value was stored */ + xfs_dir2_put_t put; /* put function ptr (i/o) */ + struct uio *uio; /* uio control structure */ +} xfs_dir2_put_args_t; + +#define XFS_DIR_IS_V2(mp) ((mp)->m_dirversion == 2) +extern xfs_dirops_t xfsv2_dirops; + +/* + * Other interfaces used by the rest of the dir v2 code. + */ +extern int + xfs_dir2_grow_inode(struct xfs_da_args *args, int space, + xfs_dir2_db_t *dbp); + +extern int + xfs_dir2_isblock(struct xfs_trans *tp, struct xfs_inode *dp, int *vp); + +extern int + xfs_dir2_isleaf(struct xfs_trans *tp, struct xfs_inode *dp, int *vp); + +extern int + xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db, + struct xfs_dabuf *bp); + +#endif /* __XFS_DIR2_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir2_block.c linux-2.4-xfs/linux/fs/xfs/xfs_dir2_block.c --- linux-2.4.7/linux/fs/xfs/xfs_dir2_block.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir2_block.c Mon Apr 23 14:52:01 2001 @@ -0,0 +1,1222 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_block.c + * XFS V2 directory implementation, single-block form. + * See xfs_dir2_block.h for the format. + */ + +#include + + +/* + * Local function prototypes. + */ +static void xfs_dir2_block_log_leaf(xfs_trans_t *tp, xfs_dabuf_t *bp, int first, + int last); +static void xfs_dir2_block_log_tail(xfs_trans_t *tp, xfs_dabuf_t *bp); +static int xfs_dir2_block_lookup_int(xfs_da_args_t *args, xfs_dabuf_t **bpp, + int *entno); +static int xfs_dir2_block_sort(const void *a, const void *b); + +/* + * Add an entry to a block directory. + */ +int /* error */ +xfs_dir2_block_addname( + xfs_da_args_t *args) /* directory op arguments */ +{ + xfs_dir2_data_free_t *bf; /* bestfree table in block */ + xfs_dir2_block_t *block; /* directory block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dabuf_t *bp; /* buffer for block */ + xfs_dir2_block_tail_t *btp; /* block tail */ + int compact; /* need to compact leaf ents */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_inode_t *dp; /* directory inode */ + xfs_dir2_data_unused_t *dup; /* block unused entry */ + int error; /* error return value */ + xfs_dir2_data_unused_t *enddup=NULL; /* unused at end of data */ + xfs_dahash_t hash; /* hash value of found entry */ + int high; /* high index for binary srch */ + int highstale; /* high stale index */ + int lfloghigh=0; /* last final leaf to log */ + int lfloglow=0; /* first final leaf to log */ + int len; /* length of the new entry */ + int low; /* low index for binary srch */ + int lowstale; /* low stale index */ + int mid=0; /* midpoint for binary srch */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log header */ + int needscan; /* need to rescan freespace */ + xfs_dir2_data_off_t *tagp; /* pointer to tag value */ + xfs_trans_t *tp; /* transaction structure */ + + xfs_dir2_trace_args("block_addname", args); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + /* + * Read the (one and only) directory block into dabuf bp. + */ + if ((error = + xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) { + return error; + } + ASSERT(bp != NULL); + block = bp->data; + /* + * Check the magic number, corrupted if wrong. + */ + if (INT_GET(block->hdr.magic, ARCH_CONVERT) != XFS_DIR2_BLOCK_MAGIC) { + xfs_da_brelse(tp, bp); + return XFS_ERROR(EFSCORRUPTED); + } + len = XFS_DIR2_DATA_ENTSIZE(args->namelen); + /* + * Set up pointers to parts of the block. + */ + bf = block->hdr.bestfree; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * No stale entries? Need space for entry and new leaf. + */ + if (INT_GET(btp->stale, ARCH_CONVERT) == 0) { + /* + * Tag just before the first leaf entry. + */ + tagp = (xfs_dir2_data_off_t *)blp - 1; + /* + * Data object just before the first leaf entry. + */ + enddup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT)); + /* + * If it's not free then can't do this add without cleaning up: + * the space before the first leaf entry needs to be free so it + * can be expanded to hold the pointer to the new entry. + */ + if (INT_GET(enddup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG) + dup = enddup = NULL; + /* + * Check out the biggest freespace and see if it's the same one. + */ + else { + dup = (xfs_dir2_data_unused_t *) + ((char *)block + INT_GET(bf[0].offset, ARCH_CONVERT)); + if (dup == enddup) { + /* + * It is the biggest freespace, is it too small + * to hold the new leaf too? + */ + if (INT_GET(dup->length, ARCH_CONVERT) < len + (uint)sizeof(*blp)) { + /* + * Yes, we use the second-largest + * entry instead if it works. + */ + if (INT_GET(bf[1].length, ARCH_CONVERT) >= len) + dup = (xfs_dir2_data_unused_t *) + ((char *)block + + INT_GET(bf[1].offset, ARCH_CONVERT)); + else + dup = NULL; + } + } else { + /* + * Not the same free entry, + * just check its length. + */ + if (INT_GET(dup->length, ARCH_CONVERT) < len) { + dup = NULL; + } + } + } + compact = 0; + } + /* + * If there are stale entries we'll use one for the leaf. + * Is the biggest entry enough to avoid compaction? + */ + else if (INT_GET(bf[0].length, ARCH_CONVERT) >= len) { + dup = (xfs_dir2_data_unused_t *) + ((char *)block + INT_GET(bf[0].offset, ARCH_CONVERT)); + compact = 0; + } + /* + * Will need to compact to make this work. + */ + else { + /* + * Tag just before the first leaf entry. + */ + tagp = (xfs_dir2_data_off_t *)blp - 1; + /* + * Data object just before the first leaf entry. + */ + dup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT)); + /* + * If it's not free then the data will go where the + * leaf data starts now, if it works at all. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + if (INT_GET(dup->length, ARCH_CONVERT) + (INT_GET(btp->stale, ARCH_CONVERT) - 1) * + (uint)sizeof(*blp) < len) + dup = NULL; + } else if ((INT_GET(btp->stale, ARCH_CONVERT) - 1) * (uint)sizeof(*blp) < len) + dup = NULL; + else + dup = (xfs_dir2_data_unused_t *)blp; + compact = 1; + } + /* + * If this isn't a real add, we're done with the buffer. + */ + if (args->justcheck) + xfs_da_brelse(tp, bp); + /* + * If we don't have space for the new entry & leaf ... + */ + if (!dup) { + /* + * Not trying to actually do anything, or don't have + * a space reservation: return no-space. + */ + if (args->justcheck || args->total == 0) + return XFS_ERROR(ENOSPC); + /* + * Convert to the next larger format. + * Then add the new entry in that format. + */ + error = xfs_dir2_block_to_leaf(args, bp); + xfs_da_buf_done(bp); + if (error) + return error; + return xfs_dir2_leaf_addname(args); + } + /* + * Just checking, and it would work, so say so. + */ + if (args->justcheck) + return 0; + needlog = needscan = 0; + /* + * If need to compact the leaf entries, do it now. + * Leave the highest-numbered stale entry stale. + * XXX should be the one closest to mid but mid is not yet computed. + */ + if (compact) { + int fromidx; /* source leaf index */ + int toidx; /* target leaf index */ + + for (fromidx = toidx = INT_GET(btp->count, ARCH_CONVERT) - 1, + highstale = lfloghigh = -1; + fromidx >= 0; + fromidx--) { + if (INT_GET(blp[fromidx].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) { + if (highstale == -1) + highstale = toidx; + else { + if (lfloghigh == -1) + lfloghigh = toidx; + continue; + } + } + if (fromidx < toidx) + blp[toidx] = blp[fromidx]; + toidx--; + } + lfloglow = toidx + 1 - (INT_GET(btp->stale, ARCH_CONVERT) - 1); + lfloghigh -= INT_GET(btp->stale, ARCH_CONVERT) - 1; + INT_MOD(btp->count, ARCH_CONVERT, -(INT_GET(btp->stale, ARCH_CONVERT) - 1)); + xfs_dir2_data_make_free(tp, bp, + (xfs_dir2_data_aoff_t)((char *)blp - (char *)block), + (xfs_dir2_data_aoff_t)((INT_GET(btp->stale, ARCH_CONVERT) - 1) * sizeof(*blp)), + &needlog, &needscan); + blp += INT_GET(btp->stale, ARCH_CONVERT) - 1; + INT_SET(btp->stale, ARCH_CONVERT, 1); + /* + * If we now need to rebuild the bestfree map, do so. + * This needs to happen before the next call to use_free. + */ + if (needscan) { + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, + &needlog, NULL); + needscan = 0; + } + } + /* + * Set leaf logging boundaries to impossible state. + * For the no-stale case they're set explicitly. + */ + else if (INT_GET(btp->stale, ARCH_CONVERT)) { + lfloglow = INT_GET(btp->count, ARCH_CONVERT); + lfloghigh = -1; + } + /* + * Find the slot that's first lower than our hash value, -1 if none. + */ + for (low = 0, high = INT_GET(btp->count, ARCH_CONVERT) - 1; low <= high; ) { + mid = (low + high) >> 1; + if ((hash = INT_GET(blp[mid].hashval, ARCH_CONVERT)) == args->hashval) + break; + if (hash < args->hashval) + low = mid + 1; + else + high = mid - 1; + } + while (mid >= 0 && INT_GET(blp[mid].hashval, ARCH_CONVERT) >= args->hashval) { + mid--; + } + /* + * No stale entries, will use enddup space to hold new leaf. + */ + if (INT_GET(btp->stale, ARCH_CONVERT) == 0) { + /* + * Mark the space needed for the new leaf entry, now in use. + */ + xfs_dir2_data_use_free(tp, bp, enddup, + (xfs_dir2_data_aoff_t) + ((char *)enddup - (char *)block + INT_GET(enddup->length, ARCH_CONVERT) - + sizeof(*blp)), + (xfs_dir2_data_aoff_t)sizeof(*blp), + &needlog, &needscan); + /* + * Update the tail (entry count). + */ + INT_MOD(btp->count, ARCH_CONVERT, +1); + /* + * If we now need to rebuild the bestfree map, do so. + * This needs to happen before the next call to use_free. + */ + if (needscan) { + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, + &needlog, NULL); + needscan = 0; + } + /* + * Adjust pointer to the first leaf entry, we're about to move + * the table up one to open up space for the new leaf entry. + * Then adjust our index to match. + */ + blp--; + mid++; + if (mid) + ovbcopy(&blp[1], blp, mid * sizeof(*blp)); + lfloglow = 0; + lfloghigh = mid; + } + /* + * Use a stale leaf for our new entry. + */ + else { + for (lowstale = mid; + lowstale >= 0 && + INT_GET(blp[lowstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR; + lowstale--) + continue; + for (highstale = mid + 1; + highstale < INT_GET(btp->count, ARCH_CONVERT) && + INT_GET(blp[highstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR && + (lowstale < 0 || mid - lowstale > highstale - mid); + highstale++) + continue; + /* + * Move entries toward the low-numbered stale entry. + */ + if (lowstale >= 0 && + (highstale == INT_GET(btp->count, ARCH_CONVERT) || + mid - lowstale <= highstale - mid)) { + if (mid - lowstale) + ovbcopy(&blp[lowstale + 1], &blp[lowstale], + (mid - lowstale) * sizeof(*blp)); + lfloglow = MIN(lowstale, lfloglow); + lfloghigh = MAX(mid, lfloghigh); + } + /* + * Move entries toward the high-numbered stale entry. + */ + else { + ASSERT(highstale < INT_GET(btp->count, ARCH_CONVERT)); + mid++; + if (highstale - mid) + ovbcopy(&blp[mid], &blp[mid + 1], + (highstale - mid) * sizeof(*blp)); + lfloglow = MIN(mid, lfloglow); + lfloghigh = MAX(highstale, lfloghigh); + } + INT_MOD(btp->stale, ARCH_CONVERT, -1); + } + /* + * Point to the new data entry. + */ + dep = (xfs_dir2_data_entry_t *)dup; + /* + * Fill in the leaf entry. + */ + INT_SET(blp[mid].hashval, ARCH_CONVERT, args->hashval); + INT_SET(blp[mid].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block)); + xfs_dir2_block_log_leaf(tp, bp, lfloglow, lfloghigh); + /* + * Mark space for the data entry used. + */ + xfs_dir2_data_use_free(tp, bp, dup, + (xfs_dir2_data_aoff_t)((char *)dup - (char *)block), + (xfs_dir2_data_aoff_t)len, &needlog, &needscan); + /* + * Create the new data entry. + */ + INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); + dep->namelen = args->namelen; + bcopy(args->name, dep->name, args->namelen); + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block)); + /* + * Clean up the bestfree array and log the header, tail, and entry. + */ + if (needscan) + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog, + NULL); + if (needlog) + xfs_dir2_data_log_header(tp, bp); + xfs_dir2_block_log_tail(tp, bp); + xfs_dir2_data_log_entry(tp, bp, dep); + xfs_dir2_data_check(dp, bp); + xfs_da_buf_done(bp); + return 0; +} + +/* + * Readdir for block directories. + */ +int /* error */ +xfs_dir2_block_getdents( + xfs_trans_t *tp, /* transaction (NULL) */ + xfs_inode_t *dp, /* incore inode */ + uio_t *uio, /* caller's buffer control */ + int *eofp, /* eof reached? (out) */ + xfs_dirent_t *dbp, /* caller's buffer */ + xfs_dir2_put_t put) /* abi's formatting function */ +{ + xfs_dir2_block_t *block; /* directory block structure */ + xfs_dabuf_t *bp; /* buffer for block */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_dir2_data_unused_t *dup; /* block unused entry */ + char *endptr; /* end of the data entries */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_dir2_put_args_t p; /* arg package for put rtn */ + char *ptr; /* current data entry */ + char *savptr; /* saved data entry */ + int wantoff; /* starting block offset */ + + mp = dp->i_mount; + /* + * If the block number in the offset is out of range, we're done. + */ + if (XFS_DIR2_DATAPTR_TO_DB(mp, uio->uio_offset) > mp->m_dirdatablk) { + *eofp = 1; + return 0; + } + /* + * Can't read the block, give up, else get dabuf in bp. + */ + if ((error = + xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) { + return error; + } + ASSERT(bp != NULL); + /* + * Extract the byte offset we start at from the seek pointer. + * We'll skip entries before this. + */ + wantoff = XFS_DIR2_DATAPTR_TO_OFF(mp, uio->uio_offset); + block = bp->data; + xfs_dir2_data_check(dp, bp); + /* + * Set up values for the loop. + */ + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + ptr = (char *)block->u; + endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + p.dbp = dbp; + p.put = put; + p.uio = uio; + /* + * Loop over the data portion of the block. + * Each object is a real entry (dep) or an unused one (dup). + */ + while (ptr < endptr) { + dup = (xfs_dir2_data_unused_t *)ptr; + /* + * Unused, skip it. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + ptr += INT_GET(dup->length, ARCH_CONVERT); + continue; + } + + dep = (xfs_dir2_data_entry_t *)ptr; + + savptr = ptr; /* In case we need it.. */ + + /* + * Bump pointer for the next iteration. + */ + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + /* + * The entry is before the desired starting point, skip it. + */ + if ((char *)dep - (char *)block < wantoff) + continue; + /* + * Set up argument structure for put routine. + */ + p.namelen = dep->namelen; + + /* + * NOTE! Linux "filldir" semantics require that the + * offset "cookie" be for this entry, not the + * next; all the actual shuffling to make it + * "look right" to the user is done in filldir. + */ + p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + savptr - (char *)block); +#if XFS_BIG_FILESYSTEMS + p.ino = INT_GET(dep->inumber, ARCH_CONVERT) + mp->m_inoadd; +#else + p.ino = INT_GET(dep->inumber, ARCH_CONVERT); +#endif + p.name = (char *)dep->name; + + /* + * Put the entry in the caller's buffer. + */ + error = p.put(&p); + + /* + * If it didn't fit, set the final offset to here & return. + */ + if (!p.done) { + uio->uio_offset = + XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + (char *)dep - (char *)block); + xfs_da_brelse(tp, bp); + return error; + } + } + + /* + * Reached the end of the block. + * Set the offset to a nonexistent block 1 and return. + */ + *eofp = 1; + + uio->uio_offset = + XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk + 1, 0); + + xfs_da_brelse(tp, bp); + + return 0; +} + +/* + * Log leaf entries from the block. + */ +static void +xfs_dir2_block_log_leaf( + xfs_trans_t *tp, /* transaction structure */ + xfs_dabuf_t *bp, /* block buffer */ + int first, /* index of first logged leaf */ + int last) /* index of last logged leaf */ +{ + xfs_dir2_block_t *block; /* directory block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_mount_t *mp; /* filesystem mount point */ + + mp = tp->t_mountp; + block = bp->data; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + xfs_da_log_buf(tp, bp, (uint)((char *)&blp[first] - (char *)block), + (uint)((char *)&blp[last + 1] - (char *)block - 1)); +} + +/* + * Log the block tail. + */ +static void +xfs_dir2_block_log_tail( + xfs_trans_t *tp, /* transaction structure */ + xfs_dabuf_t *bp) /* block buffer */ +{ + xfs_dir2_block_t *block; /* directory block structure */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_mount_t *mp; /* filesystem mount point */ + + mp = tp->t_mountp; + block = bp->data; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + xfs_da_log_buf(tp, bp, (uint)((char *)btp - (char *)block), + (uint)((char *)(btp + 1) - (char *)block - 1)); +} + +/* + * Look up an entry in the block. This is the external routine, + * xfs_dir2_block_lookup_int does the real work. + */ +int /* error */ +xfs_dir2_block_lookup( + xfs_da_args_t *args) /* dir lookup arguments */ +{ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_inode_t *dp; /* incore inode */ + int ent; /* entry index */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + + xfs_dir2_trace_args("block_lookup", args); + /* + * Get the buffer, look up the entry. + * If not found (ENOENT) then return, have no buffer. + */ + if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) + return error; + dp = args->dp; + mp = dp->i_mount; + block = bp->data; + xfs_dir2_data_check(dp, bp); + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Get the offset from the leaf entry, to point to the data. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT))); + /* + * Fill in inode number, release the block. + */ + args->inumber = INT_GET(dep->inumber, ARCH_CONVERT); + xfs_da_brelse(args->trans, bp); + return XFS_ERROR(EEXIST); +} + +/* + * Internal block lookup routine. + */ +static int /* error */ +xfs_dir2_block_lookup_int( + xfs_da_args_t *args, /* dir lookup arguments */ + xfs_dabuf_t **bpp, /* returned block buffer */ + int *entno) /* returned entry number */ +{ + xfs_dir2_dataptr_t addr; /* data entry address */ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_inode_t *dp; /* incore inode */ + int error; /* error return value */ + xfs_dahash_t hash; /* found hash value */ + int high; /* binary search high index */ + int low; /* binary search low index */ + int mid; /* binary search current idx */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + /* + * Read the buffer, return error if we can't get it. + */ + if ((error = + xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) { + return error; + } + ASSERT(bp != NULL); + block = bp->data; + xfs_dir2_data_check(dp, bp); + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Loop doing a binary search for our hash value. + * Find our entry, ENOENT if it's not there. + */ + for (low = 0, high = INT_GET(btp->count, ARCH_CONVERT) - 1; ; ) { + ASSERT(low <= high); + mid = (low + high) >> 1; + if ((hash = INT_GET(blp[mid].hashval, ARCH_CONVERT)) == args->hashval) + break; + if (hash < args->hashval) + low = mid + 1; + else + high = mid - 1; + if (low > high) { + ASSERT(args->oknoent); + xfs_da_brelse(tp, bp); + return XFS_ERROR(ENOENT); + } + } + /* + * Back up to the first one with the right hash value. + */ + while (mid > 0 && INT_GET(blp[mid - 1].hashval, ARCH_CONVERT) == args->hashval) { + mid--; + } + /* + * Now loop forward through all the entries with the + * right hash value looking for our name. + */ + do { + if ((addr = INT_GET(blp[mid].address, ARCH_CONVERT)) == XFS_DIR2_NULL_DATAPTR) + continue; + /* + * Get pointer to the entry from the leaf. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, addr)); + /* + * Compare, if it's right give back buffer & entry number. + */ + if (dep->namelen == args->namelen && + dep->name[0] == args->name[0] && + bcmp(dep->name, args->name, args->namelen) == 0) { + *bpp = bp; + *entno = mid; + return 0; + } + } while (++mid < INT_GET(btp->count, ARCH_CONVERT) && INT_GET(blp[mid].hashval, ARCH_CONVERT) == hash); + /* + * No match, release the buffer and return ENOENT. + */ + ASSERT(args->oknoent); + xfs_da_brelse(tp, bp); + return XFS_ERROR(ENOENT); +} + +/* + * Remove an entry from a block format directory. + * If that makes the block small enough to fit in shortform, transform it. + */ +int /* error */ +xfs_dir2_block_removename( + xfs_da_args_t *args) /* directory operation args */ +{ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf pointer */ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_inode_t *dp; /* incore inode */ + int ent; /* block leaf entry index */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log block header */ + int needscan; /* need to fixup bestfree */ + xfs_dir2_sf_hdr_t sfh; /* shortform header */ + int size; /* shortform size */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args("block_removename", args); + /* + * Look up the entry in the block. Gets the buffer and entry index. + * It will always be there, the vnodeops level does a lookup first. + */ + if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) { + return error; + } + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + block = bp->data; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Point to the data entry using the leaf entry. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT))); + /* + * Mark the data entry's space free. + */ + needlog = needscan = 0; + xfs_dir2_data_make_free(tp, bp, + (xfs_dir2_data_aoff_t)((char *)dep - (char *)block), + XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan); + /* + * Fix up the block tail. + */ + INT_MOD(btp->stale, ARCH_CONVERT, +1); + xfs_dir2_block_log_tail(tp, bp); + /* + * Remove the leaf entry by marking it stale. + */ + INT_SET(blp[ent].address, ARCH_CONVERT, XFS_DIR2_NULL_DATAPTR); + xfs_dir2_block_log_leaf(tp, bp, ent, ent); + /* + * Fix up bestfree, log the header if necessary. + */ + if (needscan) + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog, + NULL); + if (needlog) + xfs_dir2_data_log_header(tp, bp); + xfs_dir2_data_check(dp, bp); + /* + * See if the size as a shortform is good enough. + */ + if ((size = xfs_dir2_block_sfsize(dp, block, &sfh)) > + XFS_IFORK_DSIZE(dp)) { + xfs_da_buf_done(bp); + return 0; + } + /* + * If it works, do the conversion. + */ + return xfs_dir2_block_to_sf(args, bp, size, &sfh); +} + +/* + * Replace an entry in a V2 block directory. + * Change the inode number to the new value. + */ +int /* error */ +xfs_dir2_block_replace( + xfs_da_args_t *args) /* directory operation args */ +{ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* block data entry */ + xfs_inode_t *dp; /* incore inode */ + int ent; /* leaf entry index */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + + xfs_dir2_trace_args("block_replace", args); + /* + * Lookup the entry in the directory. Get buffer and entry index. + * This will always succeed since the caller has already done a lookup. + */ + if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) { + return error; + } + dp = args->dp; + mp = dp->i_mount; + block = bp->data; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Point to the data entry we need to change. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT))); + ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) != args->inumber); + /* + * Change the inode number to the new value. + */ + INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); + xfs_dir2_data_log_entry(args->trans, bp, dep); + xfs_dir2_data_check(dp, bp); + xfs_da_buf_done(bp); + return 0; +} + +/* + * Qsort comparison routine for the block leaf entries. + */ +static int /* sort order */ +xfs_dir2_block_sort( + const void *a, /* first leaf entry */ + const void *b) /* second leaf entry */ +{ + const xfs_dir2_leaf_entry_t *la; /* first leaf entry */ + const xfs_dir2_leaf_entry_t *lb; /* second leaf entry */ + + la = a; + lb = b; + return INT_GET(la->hashval, ARCH_CONVERT) < INT_GET(lb->hashval, ARCH_CONVERT) ? -1 : + (INT_GET(la->hashval, ARCH_CONVERT) > INT_GET(lb->hashval, ARCH_CONVERT) ? 1 : 0); +} + +/* + * Convert a V2 leaf directory to a V2 block directory if possible. + */ +int /* error */ +xfs_dir2_leaf_to_block( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *lbp, /* leaf buffer */ + xfs_dabuf_t *dbp) /* data buffer */ +{ + xfs_dir2_data_off_t *bestsp; /* leaf bests table */ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_data_unused_t *dup; /* unused data entry */ + int error; /* error return value */ + int from; /* leaf from index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* file system mount point */ + int needlog; /* need to log data header */ + int needscan; /* need to scan for bestfree */ + xfs_dir2_sf_hdr_t sfh; /* shortform header */ + int size; /* bytes used */ + xfs_dir2_data_off_t *tagp; /* end of entry (tag) */ + int to; /* block/leaf to index */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_bb("leaf_to_block", args, lbp, dbp); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + leaf = lbp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC); + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + /* + * If there are data blocks other than the first one, take this + * opportunity to remove trailing empty data blocks that may have + * been left behind during no-space-reservation operations. + * These will show up in the leaf bests table. + */ + while (dp->i_d.di_size > mp->m_dirblksize) { + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + if (INT_GET(bestsp[INT_GET(ltp->bestcount, ARCH_CONVERT) - 1], ARCH_CONVERT) == + mp->m_dirblksize - (uint)sizeof(block->hdr)) { + if ((error = + xfs_dir2_leaf_trim_data(args, lbp, + (xfs_dir2_db_t)(INT_GET(ltp->bestcount, ARCH_CONVERT) - 1)))) + goto out; + } else { + error = 0; + goto out; + } + } + /* + * Read the data block if we don't already have it, give up if it fails. + */ + if (dbp == NULL && + (error = xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &dbp, + XFS_DATA_FORK))) { + goto out; + } + block = dbp->data; + ASSERT(INT_GET(block->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC); + /* + * Size of the "leaf" area in the block. + */ + size = (uint)sizeof(block->tail) + + (uint)sizeof(*lep) * (INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT)); + /* + * Look at the last data entry. + */ + tagp = (xfs_dir2_data_off_t *)((char *)block + mp->m_dirblksize) - 1; + dup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT)); + /* + * If it's not free or is too short we can't do it. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG || INT_GET(dup->length, ARCH_CONVERT) < size) { + error = 0; + goto out; + } + /* + * Start converting it to block form. + */ + INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_BLOCK_MAGIC); + needlog = 1; + needscan = 0; + /* + * Use up the space at the end of the block (blp/btp). + */ + xfs_dir2_data_use_free(tp, dbp, dup, mp->m_dirblksize - size, size, + &needlog, &needscan); + /* + * Initialize the block tail. + */ + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + INT_SET(btp->count, ARCH_CONVERT, INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT)); + INT_SET(btp->stale, ARCH_CONVERT, 0); + xfs_dir2_block_log_tail(tp, dbp); + /* + * Initialize the block leaf area. We compact out stale entries. + */ + lep = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + for (from = to = 0; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) { + if (INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + continue; + lep[to++] = leaf->ents[from]; + } + ASSERT(to == INT_GET(btp->count, ARCH_CONVERT)); + xfs_dir2_block_log_leaf(tp, dbp, 0, INT_GET(btp->count, ARCH_CONVERT) - 1); + /* + * Scan the bestfree if we need it and log the data block header. + */ + if (needscan) + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog, + NULL); + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + /* + * Pitch the old leaf block. + */ + error = xfs_da_shrink_inode(args, mp->m_dirleafblk, lbp); + lbp = NULL; + if (error) { + goto out; + } + /* + * Now see if the resulting block can be shrunken to shortform. + */ + if ((size = xfs_dir2_block_sfsize(dp, block, &sfh)) > + XFS_IFORK_DSIZE(dp)) { + error = 0; + goto out; + } + return xfs_dir2_block_to_sf(args, dbp, size, &sfh); +out: + if (lbp) + xfs_da_buf_done(lbp); + if (dbp) + xfs_da_buf_done(dbp); + return error; +} + +/* + * Convert the shortform directory to block form. + */ +int /* error */ +xfs_dir2_sf_to_block( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_dir2_db_t blkno; /* dir-relative block # (0) */ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_block_tail_t *btp; /* block tail pointer */ + char buf[XFS_DIR2_SF_MAX_SIZE]; /* sf buffer */ + xfs_dir2_data_entry_t *dep; /* data entry pointer */ + xfs_inode_t *dp; /* incore directory inode */ + int dummy; /* trash */ + xfs_dir2_data_unused_t *dup; /* unused entry pointer */ + int endoffset; /* end of data objects */ + int error; /* error return value */ + int i; /* index */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log block header */ + int needscan; /* need to scan block freespc */ + int newoffset; /* offset from current entry */ + int offset; /* target block offset */ + xfs_dir2_sf_entry_t *sfep; /* sf entry pointer */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + xfs_dir2_data_off_t *tagp; /* end of data entry */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args("sf_to_block", args); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Bomb out if the shortform directory is way too short. + */ + if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); + /* + * Copy the directory into the stack buffer. + * Then pitch the incore inode data so we can make extents. + */ + bcopy(sfp, buf, dp->i_df.if_bytes); + xfs_idata_realloc(dp, -dp->i_df.if_bytes, XFS_DATA_FORK); + dp->i_d.di_size = 0; + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + /* + * Reset pointer - old sfp is gone. + */ + sfp = (xfs_dir2_sf_t *)buf; + /* + * Add block 0 to the inode. + */ + error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno); + if (error) { + return error; + } + /* + * Initialize the data block. + */ + error = xfs_dir2_data_init(args, blkno, &bp); + if (error) { + return error; + } + block = bp->data; + INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_BLOCK_MAGIC); + /* + * Compute size of block "tail" area. + */ + i = (uint)sizeof(*btp) + + (INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t); + /* + * The whole thing is initialized to free by the init routine. + * Say we're using the leaf and tail area. + */ + dup = (xfs_dir2_data_unused_t *)block->u; + needlog = needscan = 0; + xfs_dir2_data_use_free(tp, bp, dup, mp->m_dirblksize - i, i, &needlog, + &needscan); + ASSERT(needscan == 0); + /* + * Fill in the tail. + */ + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + INT_SET(btp->count, ARCH_CONVERT, INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2); /* ., .. */ + INT_ZERO(btp->stale, ARCH_CONVERT); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + endoffset = (uint)((char *)blp - (char *)block); + /* + * Remove the freespace, we'll manage it. + */ + xfs_dir2_data_use_free(tp, bp, dup, + (xfs_dir2_data_aoff_t)((char *)dup - (char *)block), + INT_GET(dup->length, ARCH_CONVERT), &needlog, &needscan); + /* + * Create entry for . + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATA_DOT_OFFSET); + INT_SET(dep->inumber, ARCH_CONVERT, dp->i_ino); + dep->namelen = 1; + dep->name[0] = '.'; + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block)); + xfs_dir2_data_log_entry(tp, bp, dep); + INT_SET(blp[0].hashval, ARCH_CONVERT, xfs_dir_hash_dot); + INT_SET(blp[0].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block)); + /* + * Create entry for .. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATA_DOTDOT_OFFSET); + INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT)); + dep->namelen = 2; + dep->name[0] = dep->name[1] = '.'; + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block)); + xfs_dir2_data_log_entry(tp, bp, dep); + INT_SET(blp[1].hashval, ARCH_CONVERT, xfs_dir_hash_dotdot); + INT_SET(blp[1].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block)); + offset = XFS_DIR2_DATA_FIRST_OFFSET; + /* + * Loop over existing entries, stuff them in. + */ + if ((i = 0) == INT_GET(sfp->hdr.count, ARCH_CONVERT)) + sfep = NULL; + else + sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + /* + * Need to preserve the existing offset values in the sf directory. + * Insert holes (unused entries) where necessary. + */ + while (offset < endoffset) { + /* + * sfep is null when we reach the end of the list. + */ + if (sfep == NULL) + newoffset = endoffset; + else + newoffset = XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT); + /* + * There should be a hole here, make one. + */ + if (offset < newoffset) { + dup = (xfs_dir2_data_unused_t *) + ((char *)block + offset); + INT_SET(dup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + INT_SET(dup->length, ARCH_CONVERT, newoffset - offset); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t) + ((char *)dup - (char *)block)); + xfs_dir2_data_log_unused(tp, bp, dup); + (void)xfs_dir2_data_freeinsert((xfs_dir2_data_t *)block, + dup, &dummy); + offset += INT_GET(dup->length, ARCH_CONVERT); + continue; + } + /* + * Copy a real entry. + */ + dep = (xfs_dir2_data_entry_t *)((char *)block + newoffset); + INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT)); + dep->namelen = sfep->namelen; + bcopy(sfep->name, dep->name, dep->namelen); + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block)); + xfs_dir2_data_log_entry(tp, bp, dep); + INT_SET(blp[2 + i].hashval, ARCH_CONVERT, xfs_da_hashname((char *)sfep->name, sfep->namelen)); + INT_SET(blp[2 + i].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, + (char *)dep - (char *)block)); + offset = (int)((char *)(tagp + 1) - (char *)block); + if (++i == INT_GET(sfp->hdr.count, ARCH_CONVERT)) + sfep = NULL; + else + sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep); + } + /* + * Sort the leaf entries by hash value. + */ + qsort(blp, INT_GET(btp->count, ARCH_CONVERT), sizeof(*blp), xfs_dir2_block_sort); + /* + * Log the leaf entry area and tail. + * Already logged the header in data_init, ignore needlog. + */ + ASSERT(needscan == 0); + xfs_dir2_block_log_leaf(tp, bp, 0, INT_GET(btp->count, ARCH_CONVERT) - 1); + xfs_dir2_block_log_tail(tp, bp); + xfs_dir2_data_check(dp, bp); + xfs_da_buf_done(bp); + return 0; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir2_block.h linux-2.4-xfs/linux/fs/xfs/xfs_dir2_block.h --- linux-2.4.7/linux/fs/xfs/xfs_dir2_block.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir2_block.h Tue Apr 10 20:44:54 2001 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_BLOCK_H__ +#define __XFS_DIR2_BLOCK_H__ + +/* + * xfs_dir2_block.h + * Directory version 2, single block format structures + */ + +struct dirent; +struct uio; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_dir2_data_hdr; +struct xfs_dir2_leaf_entry; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * The single block format is as follows: + * xfs_dir2_data_hdr_t structure + * xfs_dir2_data_entry_t and xfs_dir2_data_unused_t structures + * xfs_dir2_leaf_entry_t structures + * xfs_dir2_block_tail_t structure + */ + +#define XFS_DIR2_BLOCK_MAGIC 0x58443242 /* XD2B: for one block dirs */ + +typedef struct xfs_dir2_block_tail { + __uint32_t count; /* count of leaf entries */ + __uint32_t stale; /* count of stale lf entries */ +} xfs_dir2_block_tail_t; + +/* + * Generic single-block structure, for xfs_db. + */ +typedef struct xfs_dir2_block { + xfs_dir2_data_hdr_t hdr; /* magic XFS_DIR2_BLOCK_MAGIC */ + xfs_dir2_data_union_t u[1]; + xfs_dir2_leaf_entry_t leaf[1]; + xfs_dir2_block_tail_t tail; +} xfs_dir2_block_t; + +/* + * Pointer to the leaf header embedded in a data block (1-block format) + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BLOCK_TAIL_P) +xfs_dir2_block_tail_t * +xfs_dir2_block_tail_p(struct xfs_mount *mp, xfs_dir2_block_t *block); +#define XFS_DIR2_BLOCK_TAIL_P(mp,block) xfs_dir2_block_tail_p(mp,block) +#else +#define XFS_DIR2_BLOCK_TAIL_P(mp,block) \ + (((xfs_dir2_block_tail_t *)((char *)(block) + (mp)->m_dirblksize)) - 1) +#endif + +/* + * Pointer to the leaf entries embedded in a data block (1-block format) + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BLOCK_LEAF_P) +struct xfs_dir2_leaf_entry *xfs_dir2_block_leaf_p_arch( + xfs_dir2_block_tail_t *btp, xfs_arch_t arch); +#define XFS_DIR2_BLOCK_LEAF_P_ARCH(btp,arch) \ + xfs_dir2_block_leaf_p_arch(btp,arch) +#else +#define XFS_DIR2_BLOCK_LEAF_P_ARCH(btp,arch) \ + (((struct xfs_dir2_leaf_entry *)(btp)) - INT_GET((btp)->count, arch)) +#endif + +/* + * Function declarations. + */ + +extern int + xfs_dir2_block_addname(struct xfs_da_args *args); + +extern int + xfs_dir2_block_getdents(struct xfs_trans *tp, struct xfs_inode *dp, + struct uio *uio, int *eofp, struct xfs_dirent *dbp, + xfs_dir2_put_t put); + +extern int + xfs_dir2_block_lookup(struct xfs_da_args *args); + +extern int + xfs_dir2_block_removename(struct xfs_da_args *args); + +extern int + xfs_dir2_block_replace(struct xfs_da_args *args); + +extern int + xfs_dir2_leaf_to_block(struct xfs_da_args *args, struct xfs_dabuf *lbp, + struct xfs_dabuf *dbp); + +extern int + xfs_dir2_sf_to_block(struct xfs_da_args *args); + +#endif /* __XFS_DIR2_BLOCK_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir2_data.c linux-2.4-xfs/linux/fs/xfs/xfs_dir2_data.c --- linux-2.4.7/linux/fs/xfs/xfs_dir2_data.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir2_data.c Thu Apr 12 18:35:02 2001 @@ -0,0 +1,833 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_data.c + * Core data block handling routines for XFS V2 directories. + * See xfs_dir2_data.h for data structures. + */ + +#include + + +#ifdef DEBUG +/* + * Check the consistency of the data block. + * The input can also be a block-format directory. + * Pop an assert if we find anything bad. + */ +void +xfs_dir2_data_check( + xfs_inode_t *dp, /* incore inode pointer */ + xfs_dabuf_t *bp) /* data block's buffer */ +{ + xfs_dir2_dataptr_t addr; /* addr for leaf lookup */ + xfs_dir2_data_free_t *bf; /* bestfree table */ + xfs_dir2_block_tail_t *btp=NULL; /* block tail */ + int count; /* count of entries found */ + xfs_dir2_data_t *d; /* data block pointer */ + xfs_dir2_data_entry_t *dep; /* data entry */ + xfs_dir2_data_free_t *dfp; /* bestfree entry */ + xfs_dir2_data_unused_t *dup; /* unused entry */ + char *endp; /* end of useful data */ + int freeseen; /* mask of bestfrees seen */ + xfs_dahash_t hash; /* hash of current name */ + int i; /* leaf index */ + int lastfree; /* last entry was unused */ + xfs_dir2_leaf_entry_t *lep=NULL; /* block leaf entries */ + xfs_mount_t *mp; /* filesystem mount point */ + char *p; /* current data position */ + int stale; /* count of stale leaves */ + + mp = dp->i_mount; + d = bp->data; + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + bf = d->hdr.bestfree; + p = (char *)d->u; + if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d); + lep = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + endp = (char *)lep; + } else + endp = (char *)d + mp->m_dirblksize; + count = lastfree = freeseen = 0; + /* + * Account for zero bestfree entries. + */ + if (INT_GET(bf[0].length, ARCH_CONVERT) == 0) { + ASSERT(INT_GET(bf[0].offset, ARCH_CONVERT) == 0); + freeseen |= 1 << 0; + } + if (INT_GET(bf[1].length, ARCH_CONVERT) == 0) { + ASSERT(INT_GET(bf[1].offset, ARCH_CONVERT) == 0); + freeseen |= 1 << 1; + } + if (INT_GET(bf[2].length, ARCH_CONVERT) == 0) { + ASSERT(INT_GET(bf[2].offset, ARCH_CONVERT) == 0); + freeseen |= 1 << 2; + } + ASSERT(INT_GET(bf[0].length, ARCH_CONVERT) >= INT_GET(bf[1].length, ARCH_CONVERT)); + ASSERT(INT_GET(bf[1].length, ARCH_CONVERT) >= INT_GET(bf[2].length, ARCH_CONVERT)); + /* + * Loop over the data/unused entries. + */ + while (p < endp) { + dup = (xfs_dir2_data_unused_t *)p; + /* + * If it's unused, look for the space in the bestfree table. + * If we find it, account for that, else make sure it + * doesn't need to be there. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + ASSERT(lastfree == 0); + ASSERT(INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT) == + (char *)dup - (char *)d); + dfp = xfs_dir2_data_freefind(d, dup); + if (dfp) { + i = (int)(dfp - bf); + ASSERT((freeseen & (1 << i)) == 0); + freeseen |= 1 << i; + } else + ASSERT(INT_GET(dup->length, ARCH_CONVERT) <= INT_GET(bf[2].length, ARCH_CONVERT)); + p += INT_GET(dup->length, ARCH_CONVERT); + lastfree = 1; + continue; + } + /* + * It's a real entry. Validate the fields. + * If this is a block directory then make sure it's + * in the leaf section of the block. + * The linear search is crude but this is DEBUG code. + */ + dep = (xfs_dir2_data_entry_t *)p; + ASSERT(dep->namelen != 0); + ASSERT(xfs_dir_ino_validate(mp, INT_GET(dep->inumber, ARCH_CONVERT)) == 0); + ASSERT(INT_GET(*XFS_DIR2_DATA_ENTRY_TAG_P(dep), ARCH_CONVERT) == + (char *)dep - (char *)d); + count++; + lastfree = 0; + if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + addr = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + (xfs_dir2_data_aoff_t) + ((char *)dep - (char *)d)); + hash = xfs_da_hashname((char *)dep->name, dep->namelen); + for (i = 0; i < INT_GET(btp->count, ARCH_CONVERT); i++) { + if (INT_GET(lep[i].address, ARCH_CONVERT) == addr && + INT_GET(lep[i].hashval, ARCH_CONVERT) == hash) + break; + } + ASSERT(i < INT_GET(btp->count, ARCH_CONVERT)); + } + p += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + /* + * Need to have seen all the entries and all the bestfree slots. + */ + ASSERT(freeseen == 7); + if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + for (i = stale = 0; i < INT_GET(btp->count, ARCH_CONVERT); i++) { + if (INT_GET(lep[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + stale++; + if (i > 0) + ASSERT(INT_GET(lep[i].hashval, ARCH_CONVERT) >= INT_GET(lep[i - 1].hashval, ARCH_CONVERT)); + } + ASSERT(count == INT_GET(btp->count, ARCH_CONVERT) - INT_GET(btp->stale, ARCH_CONVERT)); + ASSERT(stale == INT_GET(btp->stale, ARCH_CONVERT)); + } +} +#endif + +/* + * Given a data block and an unused entry from that block, + * return the bestfree entry if any that corresponds to it. + */ +xfs_dir2_data_free_t * +xfs_dir2_data_freefind( + xfs_dir2_data_t *d, /* data block */ + xfs_dir2_data_unused_t *dup) /* data unused entry */ +{ + xfs_dir2_data_free_t *dfp; /* bestfree entry */ + xfs_dir2_data_aoff_t off; /* offset value needed */ +#if defined(DEBUG) && defined(__KERNEL__) + int matched; /* matched the value */ + int seenzero; /* saw a 0 bestfree entry */ +#endif + + off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)d); +#if defined(DEBUG) && defined(__KERNEL__) + /* + * Validate some consistency in the bestfree table. + * Check order, non-overlapping entries, and if we find the + * one we're looking for it has to be exact. + */ + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + for (dfp = &d->hdr.bestfree[0], seenzero = matched = 0; + dfp < &d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT]; + dfp++) { + if (INT_GET(dfp->offset, ARCH_CONVERT) == 0) { + ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == 0); + seenzero = 1; + continue; + } + ASSERT(seenzero == 0); + if (INT_GET(dfp->offset, ARCH_CONVERT) == off) { + matched = 1; + ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(dup->length, ARCH_CONVERT)); + } else if (off < INT_GET(dfp->offset, ARCH_CONVERT)) + ASSERT(off + INT_GET(dup->length, ARCH_CONVERT) <= INT_GET(dfp->offset, ARCH_CONVERT)); + else + ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) + INT_GET(dfp->length, ARCH_CONVERT) <= off); + ASSERT(matched || INT_GET(dfp->length, ARCH_CONVERT) >= INT_GET(dup->length, ARCH_CONVERT)); + if (dfp > &d->hdr.bestfree[0]) + ASSERT(INT_GET(dfp[-1].length, ARCH_CONVERT) >= INT_GET(dfp[0].length, ARCH_CONVERT)); + } +#endif + /* + * If this is smaller than the smallest bestfree entry, + * it can't be there since they're sorted. + */ + if (INT_GET(dup->length, ARCH_CONVERT) < INT_GET(d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT - 1].length, ARCH_CONVERT)) + return NULL; + /* + * Look at the three bestfree entries for our guy. + */ + for (dfp = &d->hdr.bestfree[0]; + dfp < &d->hdr.bestfree[XFS_DIR2_DATA_FD_COUNT]; + dfp++) { + if (INT_GET(dfp->offset, ARCH_CONVERT) == 0) + return NULL; + if (INT_GET(dfp->offset, ARCH_CONVERT) == off) + return dfp; + } + /* + * Didn't find it. This only happens if there are duplicate lengths. + */ + return NULL; +} + +/* + * Insert an unused-space entry into the bestfree table. + */ +xfs_dir2_data_free_t * /* entry inserted */ +xfs_dir2_data_freeinsert( + xfs_dir2_data_t *d, /* data block pointer */ + xfs_dir2_data_unused_t *dup, /* unused space */ + int *loghead) /* log the data header (out) */ +{ + xfs_dir2_data_free_t *dfp; /* bestfree table pointer */ + xfs_dir2_data_free_t new; /* new bestfree entry */ + +#ifdef __KERNEL__ + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); +#endif + dfp = d->hdr.bestfree; + INT_COPY(new.length, dup->length, ARCH_CONVERT); + INT_SET(new.offset, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dup - (char *)d)); + /* + * Insert at position 0, 1, or 2; or not at all. + */ + if (INT_GET(new.length, ARCH_CONVERT) > INT_GET(dfp[0].length, ARCH_CONVERT)) { + dfp[2] = dfp[1]; + dfp[1] = dfp[0]; + dfp[0] = new; + *loghead = 1; + return &dfp[0]; + } + if (INT_GET(new.length, ARCH_CONVERT) > INT_GET(dfp[1].length, ARCH_CONVERT)) { + dfp[2] = dfp[1]; + dfp[1] = new; + *loghead = 1; + return &dfp[1]; + } + if (INT_GET(new.length, ARCH_CONVERT) > INT_GET(dfp[2].length, ARCH_CONVERT)) { + dfp[2] = new; + *loghead = 1; + return &dfp[2]; + } + return NULL; +} + +/* + * Remove a bestfree entry from the table. + */ +void +xfs_dir2_data_freeremove( + xfs_dir2_data_t *d, /* data block pointer */ + xfs_dir2_data_free_t *dfp, /* bestfree entry pointer */ + int *loghead) /* out: log data header */ +{ +#ifdef __KERNEL__ + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); +#endif + /* + * It's the first entry, slide the next 2 up. + */ + if (dfp == &d->hdr.bestfree[0]) { + d->hdr.bestfree[0] = d->hdr.bestfree[1]; + d->hdr.bestfree[1] = d->hdr.bestfree[2]; + } + /* + * It's the second entry, slide the 3rd entry up. + */ + else if (dfp == &d->hdr.bestfree[1]) + d->hdr.bestfree[1] = d->hdr.bestfree[2]; + /* + * Must be the last entry. + */ + else + ASSERT(dfp == &d->hdr.bestfree[2]); + /* + * Clear the 3rd entry, must be zero now. + */ + INT_ZERO(d->hdr.bestfree[2].length, ARCH_CONVERT); + INT_ZERO(d->hdr.bestfree[2].offset, ARCH_CONVERT); + *loghead = 1; +} + +/* + * Given a data block, reconstruct its bestfree map. + */ +void +xfs_dir2_data_freescan( + xfs_mount_t *mp, /* filesystem mount point */ + xfs_dir2_data_t *d, /* data block pointer */ + int *loghead, /* out: log data header */ + char *aendp) /* in: caller's endp */ +{ + xfs_dir2_block_tail_t *btp; /* block tail */ + xfs_dir2_data_entry_t *dep; /* active data entry */ + xfs_dir2_data_unused_t *dup; /* unused data entry */ + char *endp; /* end of block's data */ + char *p; /* current entry pointer */ + +#ifdef __KERNEL__ + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); +#endif + /* + * Start by clearing the table. + */ + bzero(d->hdr.bestfree, sizeof(d->hdr.bestfree)); + *loghead = 1; + /* + * Set up pointers. + */ + p = (char *)d->u; + if (aendp) + endp = aendp; + else if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d); + endp = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + } else + endp = (char *)d + mp->m_dirblksize; + /* + * Loop over the block's entries. + */ + while (p < endp) { + dup = (xfs_dir2_data_unused_t *)p; + /* + * If it's a free entry, insert it. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + ASSERT((char *)dup - (char *)d == + INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT)); + xfs_dir2_data_freeinsert(d, dup, loghead); + p += INT_GET(dup->length, ARCH_CONVERT); + } + /* + * For active entries, check their tags and skip them. + */ + else { + dep = (xfs_dir2_data_entry_t *)p; + ASSERT((char *)dep - (char *)d == + INT_GET(*XFS_DIR2_DATA_ENTRY_TAG_P(dep), ARCH_CONVERT)); + p += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + } +} + +/* + * Initialize a data block at the given block number in the directory. + * Give back the buffer for the created block. + */ +int /* error */ +xfs_dir2_data_init( + xfs_da_args_t *args, /* directory operation args */ + xfs_dir2_db_t blkno, /* logical dir block number */ + xfs_dabuf_t **bpp) /* output block buffer */ +{ + xfs_dabuf_t *bp; /* block buffer */ + xfs_dir2_data_t *d; /* pointer to block */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_data_unused_t *dup; /* unused entry pointer */ + int error; /* error return value */ + int i; /* bestfree index */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + int t; /* temp */ + + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + /* + * Get the buffer set up for the block. + */ + error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, blkno), -1, &bp, + XFS_DATA_FORK); + if (error) { + return error; + } + ASSERT(bp != NULL); + /* + * Initialize the header. + */ + d = bp->data; + INT_SET(d->hdr.magic, ARCH_CONVERT, XFS_DIR2_DATA_MAGIC); + INT_SET(d->hdr.bestfree[0].offset, ARCH_CONVERT, (xfs_dir2_data_off_t)sizeof(d->hdr)); + for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) { + INT_ZERO(d->hdr.bestfree[i].length, ARCH_CONVERT); + INT_ZERO(d->hdr.bestfree[i].offset, ARCH_CONVERT); + } + /* + * Set up an unused entry for the block's body. + */ + dup = &d->u[0].unused; + INT_SET(dup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + + t=mp->m_dirblksize - (uint)sizeof(d->hdr); + INT_SET(d->hdr.bestfree[0].length, ARCH_CONVERT, t); + INT_SET(dup->length, ARCH_CONVERT, t); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)dup - (char *)d)); + /* + * Log it and return it. + */ + xfs_dir2_data_log_header(tp, bp); + xfs_dir2_data_log_unused(tp, bp, dup); + *bpp = bp; + return 0; +} + +/* + * Log an active data entry from the block. + */ +void +xfs_dir2_data_log_entry( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* block buffer */ + xfs_dir2_data_entry_t *dep) /* data entry pointer */ +{ + xfs_dir2_data_t *d; /* data block pointer */ + + d = bp->data; + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + xfs_da_log_buf(tp, bp, (uint)((char *)dep - (char *)d), + (uint)((char *)(XFS_DIR2_DATA_ENTRY_TAG_P(dep) + 1) - + (char *)d - 1)); +} + +/* + * Log a data block header. + */ +void +xfs_dir2_data_log_header( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp) /* block buffer */ +{ + xfs_dir2_data_t *d; /* data block pointer */ + + d = bp->data; + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + xfs_da_log_buf(tp, bp, (uint)((char *)&d->hdr - (char *)d), + (uint)(sizeof(d->hdr) - 1)); +} + +/* + * Log a data unused entry. + */ +void +xfs_dir2_data_log_unused( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* block buffer */ + xfs_dir2_data_unused_t *dup) /* data unused pointer */ +{ + xfs_dir2_data_t *d; /* data block pointer */ + + d = bp->data; + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + /* + * Log the first part of the unused entry. + */ + xfs_da_log_buf(tp, bp, (uint)((char *)dup - (char *)d), + (uint)((char *)&dup->length + sizeof(dup->length) - + 1 - (char *)d)); + /* + * Log the end (tag) of the unused entry. + */ + xfs_da_log_buf(tp, bp, + (uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT) - (char *)d), + (uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT) - (char *)d + + sizeof(xfs_dir2_data_off_t) - 1)); +} + +/* + * Make a byte range in the data block unused. + * Its current contents are unimportant. + */ +void +xfs_dir2_data_make_free( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* block buffer */ + xfs_dir2_data_aoff_t offset, /* starting byte offset */ + xfs_dir2_data_aoff_t len, /* length in bytes */ + int *needlogp, /* out: log header */ + int *needscanp) /* out: regen bestfree */ +{ + xfs_dir2_data_t *d; /* data block pointer */ + xfs_dir2_data_free_t *dfp; /* bestfree pointer */ + char *endptr; /* end of data area */ + xfs_mount_t *mp; /* filesystem mount point */ + int needscan; /* need to regen bestfree */ + xfs_dir2_data_unused_t *newdup; /* new unused entry */ + xfs_dir2_data_unused_t *postdup; /* unused entry after us */ + xfs_dir2_data_unused_t *prevdup; /* unused entry before us */ + + mp = tp->t_mountp; + d = bp->data; + /* + * Figure out where the end of the data area is. + */ + if (INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC) + endptr = (char *)d + mp->m_dirblksize; + else { + xfs_dir2_block_tail_t *btp; /* block tail */ + + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d); + endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + } + /* + * If this isn't the start of the block, then back up to + * the previous entry and see if it's free. + */ + if (offset > sizeof(d->hdr)) { + xfs_dir2_data_off_t *tagp; /* tag just before us */ + + tagp = (xfs_dir2_data_off_t *)((char *)d + offset) - 1; + prevdup = (xfs_dir2_data_unused_t *)((char *)d + INT_GET(*tagp, ARCH_CONVERT)); + if (INT_GET(prevdup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG) + prevdup = NULL; + } else + prevdup = NULL; + /* + * If this isn't the end of the block, see if the entry after + * us is free. + */ + if ((char *)d + offset + len < endptr) { + postdup = + (xfs_dir2_data_unused_t *)((char *)d + offset + len); + if (INT_GET(postdup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG) + postdup = NULL; + } else + postdup = NULL; + ASSERT(*needscanp == 0); + needscan = 0; + /* + * Previous and following entries are both free, + * merge everything into a single free entry. + */ + if (prevdup && postdup) { + xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */ + + /* + * See if prevdup and/or postdup are in bestfree table. + */ + dfp = xfs_dir2_data_freefind(d, prevdup); + dfp2 = xfs_dir2_data_freefind(d, postdup); + /* + * We need a rescan unless there are exactly 2 free entries + * namely our two. Then we know what's happening, otherwise + * since the third bestfree is there, there might be more + * entries. + */ + needscan = INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT) != 0; + /* + * Fix up the new big freespace. + */ + INT_MOD(prevdup->length, ARCH_CONVERT, len + INT_GET(postdup->length, ARCH_CONVERT)); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(prevdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)prevdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, prevdup); + if (!needscan) { + /* + * Has to be the case that entries 0 and 1 are + * dfp and dfp2 (don't know which is which), and + * entry 2 is empty. + * Remove entry 1 first then entry 0. + */ + ASSERT(dfp && dfp2); + if (dfp == &d->hdr.bestfree[1]) { + dfp = &d->hdr.bestfree[0]; + ASSERT(dfp2 == dfp); + dfp2 = &d->hdr.bestfree[1]; + } + xfs_dir2_data_freeremove(d, dfp2, needlogp); + xfs_dir2_data_freeremove(d, dfp, needlogp); + /* + * Now insert the new entry. + */ + dfp = xfs_dir2_data_freeinsert(d, prevdup, needlogp); + ASSERT(dfp == &d->hdr.bestfree[0]); + ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(prevdup->length, ARCH_CONVERT)); + ASSERT(INT_GET(dfp[1].length, ARCH_CONVERT) == 0); + ASSERT(INT_GET(dfp[2].length, ARCH_CONVERT) == 0); + } + } + /* + * The entry before us is free, merge with it. + */ + else if (prevdup) { + dfp = xfs_dir2_data_freefind(d, prevdup); + INT_MOD(prevdup->length, ARCH_CONVERT, len); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(prevdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)prevdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, prevdup); + /* + * If the previous entry was in the table, the new entry + * is longer, so it will be in the table too. Remove + * the old one and add the new one. + */ + if (dfp) { + xfs_dir2_data_freeremove(d, dfp, needlogp); + (void)xfs_dir2_data_freeinsert(d, prevdup, needlogp); + } + /* + * Otherwise we need a scan if the new entry is big enough. + */ + else + needscan = INT_GET(prevdup->length, ARCH_CONVERT) > INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT); + } + /* + * The following entry is free, merge with it. + */ + else if (postdup) { + dfp = xfs_dir2_data_freefind(d, postdup); + newdup = (xfs_dir2_data_unused_t *)((char *)d + offset); + INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + INT_SET(newdup->length, ARCH_CONVERT, len + INT_GET(postdup->length, ARCH_CONVERT)); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup); + /* + * If the following entry was in the table, the new entry + * is longer, so it will be in the table too. Remove + * the old one and add the new one. + */ + if (dfp) { + xfs_dir2_data_freeremove(d, dfp, needlogp); + (void)xfs_dir2_data_freeinsert(d, newdup, needlogp); + } + /* + * Otherwise we need a scan if the new entry is big enough. + */ + else + needscan = INT_GET(newdup->length, ARCH_CONVERT) > INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT); + } + /* + * Neither neighbor is free. Make a new entry. + */ + else { + newdup = (xfs_dir2_data_unused_t *)((char *)d + offset); + INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + INT_SET(newdup->length, ARCH_CONVERT, len); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup); + (void)xfs_dir2_data_freeinsert(d, newdup, needlogp); + } + *needscanp = needscan; +} + +/* + * Take a byte range out of an existing unused space and make it un-free. + */ +void +xfs_dir2_data_use_free( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* data block buffer */ + xfs_dir2_data_unused_t *dup, /* unused entry */ + xfs_dir2_data_aoff_t offset, /* starting offset to use */ + xfs_dir2_data_aoff_t len, /* length to use */ + int *needlogp, /* out: need to log header */ + int *needscanp) /* out: need regen bestfree */ +{ + xfs_dir2_data_t *d; /* data block */ + xfs_dir2_data_free_t *dfp; /* bestfree pointer */ + int matchback; /* matches end of freespace */ + int matchfront; /* matches start of freespace */ + int needscan; /* need to regen bestfree */ + xfs_dir2_data_unused_t *newdup; /* new unused entry */ + xfs_dir2_data_unused_t *newdup2; /* another new unused entry */ + int oldlen; /* old unused entry's length */ + + d = bp->data; + ASSERT(INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC || + INT_GET(d->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC); + ASSERT(INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG); + ASSERT(offset >= (char *)dup - (char *)d); + ASSERT(offset + len <= (char *)dup + INT_GET(dup->length, ARCH_CONVERT) - (char *)d); + ASSERT((char *)dup - (char *)d == INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT)); + /* + * Look up the entry in the bestfree table. + */ + dfp = xfs_dir2_data_freefind(d, dup); + oldlen = INT_GET(dup->length, ARCH_CONVERT); + ASSERT(dfp || oldlen <= INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT)); + /* + * Check for alignment with front and back of the entry. + */ + matchfront = (char *)dup - (char *)d == offset; + matchback = (char *)dup + oldlen - (char *)d == offset + len; + ASSERT(*needscanp == 0); + needscan = 0; + /* + * If we matched it exactly we just need to get rid of it from + * the bestfree table. + */ + if (matchfront && matchback) { + if (dfp) { + needscan = INT_GET(d->hdr.bestfree[2].offset, ARCH_CONVERT) != 0; + if (!needscan) + xfs_dir2_data_freeremove(d, dfp, needlogp); + } + } + /* + * We match the first part of the entry. + * Make a new entry with the remaining freespace. + */ + else if (matchfront) { + newdup = (xfs_dir2_data_unused_t *)((char *)d + offset + len); + INT_SET(newdup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + INT_SET(newdup->length, ARCH_CONVERT, oldlen - len); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup); + /* + * If it was in the table, remove it and add the new one. + */ + if (dfp) { + xfs_dir2_data_freeremove(d, dfp, needlogp); + dfp = xfs_dir2_data_freeinsert(d, newdup, needlogp); + ASSERT(dfp != NULL); + ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(newdup->length, ARCH_CONVERT)); + ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) == (char *)newdup - (char *)d); + /* + * If we got inserted at the last slot, + * that means we don't know if there was a better + * choice for the last slot, or not. Rescan. + */ + needscan = dfp == &d->hdr.bestfree[2]; + } + } + /* + * We match the last part of the entry. + * Trim the allocated space off the tail of the entry. + */ + else if (matchback) { + newdup = dup; + INT_SET(newdup->length, ARCH_CONVERT, (xfs_dir2_data_off_t) + (((char *)d + offset) - (char *)newdup)); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup); + /* + * If it was in the table, remove it and add the new one. + */ + if (dfp) { + xfs_dir2_data_freeremove(d, dfp, needlogp); + dfp = xfs_dir2_data_freeinsert(d, newdup, needlogp); + ASSERT(dfp != NULL); + ASSERT(INT_GET(dfp->length, ARCH_CONVERT) == INT_GET(newdup->length, ARCH_CONVERT)); + ASSERT(INT_GET(dfp->offset, ARCH_CONVERT) == (char *)newdup - (char *)d); + /* + * If we got inserted at the last slot, + * that means we don't know if there was a better + * choice for the last slot, or not. Rescan. + */ + needscan = dfp == &d->hdr.bestfree[2]; + } + } + /* + * Poking out the middle of an entry. + * Make two new entries. + */ + else { + newdup = dup; + INT_SET(newdup->length, ARCH_CONVERT, (xfs_dir2_data_off_t) + (((char *)d + offset) - (char *)newdup)); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup); + newdup2 = (xfs_dir2_data_unused_t *)((char *)d + offset + len); + INT_SET(newdup2->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG); + INT_SET(newdup2->length, ARCH_CONVERT, oldlen - len - INT_GET(newdup->length, ARCH_CONVERT)); + INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(newdup2, ARCH_CONVERT), ARCH_CONVERT, + (xfs_dir2_data_off_t)((char *)newdup2 - (char *)d)); + xfs_dir2_data_log_unused(tp, bp, newdup2); + /* + * If the old entry was in the table, we need to scan + * if the 3rd entry was valid, since these entries + * are smaller than the old one. + * If we don't need to scan that means there were 1 or 2 + * entries in the table, and removing the old and adding + * the 2 new will work. + */ + if (dfp) { + needscan = INT_GET(d->hdr.bestfree[2].length, ARCH_CONVERT) != 0; + if (!needscan) { + xfs_dir2_data_freeremove(d, dfp, needlogp); + (void)xfs_dir2_data_freeinsert(d, newdup, + needlogp); + (void)xfs_dir2_data_freeinsert(d, newdup2, + needlogp); + } + } + } + *needscanp = needscan; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir2_data.h linux-2.4-xfs/linux/fs/xfs/xfs_dir2_data.h --- linux-2.4.7/linux/fs/xfs/xfs_dir2_data.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir2_data.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_DATA_H__ +#define __XFS_DIR2_DATA_H__ + +/* + * Directory format 2, data block structures. + */ + +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_inode; +struct xfs_trans; + +/* + * Constants. + */ +#define XFS_DIR2_DATA_MAGIC 0x58443244 /* XD2D: for multiblock dirs */ +#define XFS_DIR2_DATA_ALIGN_LOG 3 /* i.e., 8 bytes */ +#define XFS_DIR2_DATA_ALIGN (1 << XFS_DIR2_DATA_ALIGN_LOG) +#define XFS_DIR2_DATA_FREE_TAG 0xffff +#define XFS_DIR2_DATA_FD_COUNT 3 + +/* + * Directory address space divided into sections, + * spaces separated by 32gb. + */ +#define XFS_DIR2_SPACE_SIZE (1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG)) +#define XFS_DIR2_DATA_SPACE 0 +#define XFS_DIR2_DATA_OFFSET (XFS_DIR2_DATA_SPACE * XFS_DIR2_SPACE_SIZE) +#define XFS_DIR2_DATA_FIRSTDB(mp) \ + XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_DATA_OFFSET) + +/* + * Offsets of . and .. in data space (always block 0) + */ +#define XFS_DIR2_DATA_DOT_OFFSET \ + ((xfs_dir2_data_aoff_t)sizeof(xfs_dir2_data_hdr_t)) +#define XFS_DIR2_DATA_DOTDOT_OFFSET \ + (XFS_DIR2_DATA_DOT_OFFSET + XFS_DIR2_DATA_ENTSIZE(1)) +#define XFS_DIR2_DATA_FIRST_OFFSET \ + (XFS_DIR2_DATA_DOTDOT_OFFSET + XFS_DIR2_DATA_ENTSIZE(2)) + +/* + * Structures. + */ + +/* + * Describe a free area in the data block. + * The freespace will be formatted as a xfs_dir2_data_unused_t. + */ +typedef struct xfs_dir2_data_free { + xfs_dir2_data_off_t offset; /* start of freespace */ + xfs_dir2_data_off_t length; /* length of freespace */ +} xfs_dir2_data_free_t; + +/* + * Header for the data blocks. + * Always at the beginning of a directory-sized block. + * The code knows that XFS_DIR2_DATA_FD_COUNT is 3. + */ +typedef struct xfs_dir2_data_hdr { + __uint32_t magic; /* XFS_DIR2_DATA_MAGIC */ + /* or XFS_DIR2_BLOCK_MAGIC */ + xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT]; +} xfs_dir2_data_hdr_t; + +/* + * Active entry in a data block. Aligned to 8 bytes. + * Tag appears as the last 2 bytes. + */ +typedef struct xfs_dir2_data_entry { + xfs_ino_t inumber; /* inode number */ + __uint8_t namelen; /* name length */ + __uint8_t name[1]; /* name bytes, no null */ + /* variable offset */ + xfs_dir2_data_off_t tag; /* starting offset of us */ +} xfs_dir2_data_entry_t; + +/* + * Unused entry in a data block. Aligned to 8 bytes. + * Tag appears as the last 2 bytes. + */ +typedef struct xfs_dir2_data_unused { + __uint16_t freetag; /* XFS_DIR2_DATA_FREE_TAG */ + xfs_dir2_data_off_t length; /* total free length */ + /* variable offset */ + xfs_dir2_data_off_t tag; /* starting offset of us */ +} xfs_dir2_data_unused_t; + +typedef union { + xfs_dir2_data_entry_t entry; + xfs_dir2_data_unused_t unused; +} xfs_dir2_data_union_t; + +/* + * Generic data block structure, for xfs_db. + */ +typedef struct xfs_dir2_data { + xfs_dir2_data_hdr_t hdr; /* magic XFS_DIR2_DATA_MAGIC */ + xfs_dir2_data_union_t u[1]; +} xfs_dir2_data_t; + +/* + * Macros. + */ + +/* + * Size of a data entry. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATA_ENTSIZE) +int xfs_dir2_data_entsize(int n); +#define XFS_DIR2_DATA_ENTSIZE(n) xfs_dir2_data_entsize(n) +#else +#define XFS_DIR2_DATA_ENTSIZE(n) \ + ((int)(roundup(offsetof(xfs_dir2_data_entry_t, name[0]) + (n) + \ + (uint)sizeof(xfs_dir2_data_off_t), XFS_DIR2_DATA_ALIGN))) +#endif + +/* + * Pointer to an entry's tag word. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATA_ENTRY_TAG_P) +xfs_dir2_data_off_t *xfs_dir2_data_entry_tag_p(xfs_dir2_data_entry_t *dep); +#define XFS_DIR2_DATA_ENTRY_TAG_P(dep) xfs_dir2_data_entry_tag_p(dep) +#else +#define XFS_DIR2_DATA_ENTRY_TAG_P(dep) \ + ((xfs_dir2_data_off_t *)\ + ((char *)(dep) + XFS_DIR2_DATA_ENTSIZE((dep)->namelen) - \ + (uint)sizeof(xfs_dir2_data_off_t))) +#endif + +/* + * Pointer to a freespace's tag word. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATA_UNUSED_TAG_P) +xfs_dir2_data_off_t *xfs_dir2_data_unused_tag_p_arch( + xfs_dir2_data_unused_t *dup, xfs_arch_t arch); +#define XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup,arch) \ + xfs_dir2_data_unused_tag_p_arch(dup,arch) +#else +#define XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup,arch) \ + ((xfs_dir2_data_off_t *)\ + ((char *)(dup) + INT_GET((dup)->length, arch) \ + - (uint)sizeof(xfs_dir2_data_off_t))) +#endif + +/* + * Function declarations. + */ + +#ifdef DEBUG +extern void + xfs_dir2_data_check(struct xfs_inode *dp, struct xfs_dabuf *bp); +#else +#define xfs_dir2_data_check(dp,bp) +#endif + +extern xfs_dir2_data_free_t * + xfs_dir2_data_freefind(xfs_dir2_data_t *d, + xfs_dir2_data_unused_t *dup); + +extern xfs_dir2_data_free_t * + xfs_dir2_data_freeinsert(xfs_dir2_data_t *d, + xfs_dir2_data_unused_t *dup, int *loghead); + +extern void + xfs_dir2_data_freeremove(xfs_dir2_data_t *d, + xfs_dir2_data_free_t *dfp, int *loghead); + +extern void + xfs_dir2_data_freescan(struct xfs_mount *mp, xfs_dir2_data_t *d, + int *loghead, char *aendp); + +extern int + xfs_dir2_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno, + struct xfs_dabuf **bpp); + +extern void + xfs_dir2_data_log_entry(struct xfs_trans *tp, struct xfs_dabuf *bp, + xfs_dir2_data_entry_t *dep); + +extern void + xfs_dir2_data_log_header(struct xfs_trans *tp, struct xfs_dabuf *bp); + +extern void + xfs_dir2_data_log_unused(struct xfs_trans *tp, struct xfs_dabuf *bp, + xfs_dir2_data_unused_t *dup); + +extern void + xfs_dir2_data_make_free(struct xfs_trans *tp, struct xfs_dabuf *bp, + xfs_dir2_data_aoff_t offset, + xfs_dir2_data_aoff_t len, int *needlogp, + int *needscanp); + +extern void + xfs_dir2_data_use_free(struct xfs_trans *tp, struct xfs_dabuf *bp, + xfs_dir2_data_unused_t *dup, + xfs_dir2_data_aoff_t offset, + xfs_dir2_data_aoff_t len, int *needlogp, + int *needscanp); + +#endif /* __XFS_DIR2_DATA_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir2_leaf.c linux-2.4-xfs/linux/fs/xfs/xfs_dir2_leaf.c --- linux-2.4.7/linux/fs/xfs/xfs_dir2_leaf.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir2_leaf.c Mon Apr 23 14:52:01 2001 @@ -0,0 +1,1873 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_leaf.c + * XFS directory version 2 implementation - single leaf form + * see xfs_dir2_leaf.h for data structures. + * These directories have multiple XFS_DIR2_DATA blocks and one + * XFS_DIR2_LEAF1 block containing the hash table and freespace map. + */ + +#include + +/* + * Local function declarations. + */ +#ifdef DEBUG +static void xfs_dir2_leaf_check(xfs_inode_t *dp, xfs_dabuf_t *bp); +#else +#define xfs_dir2_leaf_check(dp, bp) +#endif +static int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, xfs_dabuf_t **lbpp, + int *indexp, xfs_dabuf_t **dbpp); + +/* + * Convert a block form directory to a leaf form directory. + */ +int /* error */ +xfs_dir2_block_to_leaf( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *dbp) /* input block's buffer */ +{ + xfs_dir2_data_off_t *bestsp; /* leaf's bestsp entries */ + xfs_dablk_t blkno; /* leaf block's bno */ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_leaf_entry_t *blp; /* block's leaf entries */ + xfs_dir2_block_tail_t *btp; /* block's tail */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + xfs_dabuf_t *lbp; /* leaf block's buffer */ + xfs_dir2_db_t ldb; /* leaf block's bno */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf's tail */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log block header */ + int needscan; /* need to rescan bestfree */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_b("block_to_leaf", args, dbp); + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + /* + * Add the leaf block to the inode. + * This interface will only put blocks in the leaf/node range. + * Since that's empty now, we'll get the root (block 0 in range). + */ + if ((error = xfs_da_grow_inode(args, &blkno))) { + return error; + } + ldb = XFS_DIR2_DA_TO_DB(mp, blkno); + ASSERT(ldb == XFS_DIR2_LEAF_FIRSTDB(mp)); + /* + * Initialize the leaf block, get a buffer for it. + */ + if ((error = xfs_dir2_leaf_init(args, ldb, &lbp, XFS_DIR2_LEAF1_MAGIC))) { + return error; + } + ASSERT(lbp != NULL); + leaf = lbp->data; + block = dbp->data; + xfs_dir2_data_check(dp, dbp); + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + /* + * Set the counts in the leaf header. + */ + INT_COPY(leaf->hdr.count, btp->count, ARCH_CONVERT); /* INT_: type change */ + INT_COPY(leaf->hdr.stale, btp->stale, ARCH_CONVERT); /* INT_: type change */ + /* + * Could compact these but I think we always do the conversion + * after squeezing out stale entries. + */ + bcopy(blp, leaf->ents, INT_GET(btp->count, ARCH_CONVERT) * sizeof(xfs_dir2_leaf_entry_t)); + xfs_dir2_leaf_log_ents(tp, lbp, 0, INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1); + needscan = 0; + needlog = 1; + /* + * Make the space formerly occupied by the leaf entries and block + * tail be free. + */ + xfs_dir2_data_make_free(tp, dbp, + (xfs_dir2_data_aoff_t)((char *)blp - (char *)block), + (xfs_dir2_data_aoff_t)((char *)block + mp->m_dirblksize - + (char *)blp), + &needlog, &needscan); + /* + * Fix up the block header, make it a data block. + */ + INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_DATA_MAGIC); + if (needscan) + xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog, + NULL); + /* + * Set up leaf tail and bests table. + */ + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + INT_SET(ltp->bestcount, ARCH_CONVERT, 1); + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + INT_COPY(bestsp[0], block->hdr.bestfree[0].length, ARCH_CONVERT); + /* + * Log the data header and leaf bests table. + */ + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + xfs_dir2_leaf_check(dp, lbp); + xfs_dir2_data_check(dp, dbp); + xfs_dir2_leaf_log_bests(tp, lbp, 0, 0); + xfs_da_buf_done(lbp); + return 0; +} + +/* + * Add an entry to a leaf form directory. + */ +int /* error */ +xfs_dir2_leaf_addname( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_dir2_data_off_t *bestsp; /* freespace table in leaf */ + int compact; /* need to compact leaves */ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data block entry */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_data_unused_t *dup; /* data unused entry */ + int error; /* error return value */ + int grown; /* allocated new data block */ + int highstale; /* index of next stale leaf */ + int i; /* temporary, index */ + int index; /* leaf table position */ + xfs_dabuf_t *lbp; /* leaf's buffer */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + int length; /* length of new entry */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry table pointer */ + int lfloglow; /* low leaf logging index */ + int lfloghigh; /* high leaf logging index */ + int lowstale; /* index of prev stale leaf */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail pointer */ + xfs_mount_t *mp; /* filesystem mount point */ + int needbytes; /* leaf block bytes needed */ + int needlog; /* need to log data header */ + int needscan; /* need to rescan data free */ + xfs_dir2_data_off_t *tagp; /* end of data entry */ + xfs_trans_t *tp; /* transaction pointer */ + xfs_dir2_db_t use_block; /* data block number */ + + xfs_dir2_trace_args("leaf_addname", args); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + /* + * Read the leaf block. + */ + error = xfs_da_read_buf(tp, dp, mp->m_dirleafblk, -1, &lbp, + XFS_DATA_FORK); + if (error) { + return error; + } + ASSERT(lbp != NULL); + /* + * Look up the entry by hash value and name. + * We know it's not there, our caller has already done a lookup. + * So the index is of the entry to insert in front of. + * But if there are dup hash values the index is of the first of those. + */ + index = xfs_dir2_leaf_search_hash(args, lbp); + leaf = lbp->data; + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + length = XFS_DIR2_DATA_ENTSIZE(args->namelen); + /* + * See if there are any entries with the same hash value + * and space in their block for the new entry. + * This is good because it puts multiple same-hash value entries + * in a data block, improving the lookup of those entries. + */ + for (use_block = -1, lep = &leaf->ents[index]; + index < INT_GET(leaf->hdr.count, ARCH_CONVERT) && INT_GET(lep->hashval, ARCH_CONVERT) == args->hashval; + index++, lep++) { + if (INT_GET(lep->address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + continue; + i = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT)); + ASSERT(i < INT_GET(ltp->bestcount, ARCH_CONVERT)); + ASSERT(INT_GET(bestsp[i], ARCH_CONVERT) != NULLDATAOFF); + if (INT_GET(bestsp[i], ARCH_CONVERT) >= length) { + use_block = i; + break; + } + } + /* + * Didn't find a block yet, linear search all the data blocks. + */ + if (use_block == -1) { + for (i = 0; i < INT_GET(ltp->bestcount, ARCH_CONVERT); i++) { + /* + * Remember a block we see that's missing. + */ + if (INT_GET(bestsp[i], ARCH_CONVERT) == NULLDATAOFF && use_block == -1) + use_block = i; + else if (INT_GET(bestsp[i], ARCH_CONVERT) >= length) { + use_block = i; + break; + } + } + } + /* + * How many bytes do we need in the leaf block? + */ + needbytes = + (INT_GET(leaf->hdr.stale, ARCH_CONVERT) != 0 ? 0 : (uint)sizeof(leaf->ents[0])) + + (use_block != -1 ? 0 : (uint)sizeof(leaf->bests[0])); + /* + * Now kill use_block if it refers to a missing block, so we + * can use it as an indication of allocation needed. + */ + if (use_block != -1 && INT_GET(bestsp[use_block], ARCH_CONVERT) == NULLDATAOFF) + use_block = -1; + /* + * If we don't have enough free bytes but we can make enough + * by compacting out stale entries, we'll do that. + */ + if ((char *)bestsp - (char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] < needbytes && + INT_GET(leaf->hdr.stale, ARCH_CONVERT) > 1) { + compact = 1; + } + /* + * Otherwise if we don't have enough free bytes we need to + * convert to node form. + */ + else if ((char *)bestsp - (char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] < + needbytes) { + /* + * Just checking or no space reservation, give up. + */ + if (args->justcheck || args->total == 0) { + xfs_da_brelse(tp, lbp); + return XFS_ERROR(ENOSPC); + } + /* + * Convert to node form. + */ + error = xfs_dir2_leaf_to_node(args, lbp); + xfs_da_buf_done(lbp); + if (error) + return error; + /* + * Then add the new entry. + */ + return xfs_dir2_node_addname(args); + } + /* + * Otherwise it will fit without compaction. + */ + else + compact = 0; + /* + * If just checking, then it will fit unless we needed to allocate + * a new data block. + */ + if (args->justcheck) { + xfs_da_brelse(tp, lbp); + return use_block == -1 ? XFS_ERROR(ENOSPC) : 0; + } + /* + * If no allocations are allowed, return now before we've + * changed anything. + */ + if (args->total == 0 && use_block == -1) { + xfs_da_brelse(tp, lbp); + return XFS_ERROR(ENOSPC); + } + /* + * Need to compact the leaf entries, removing stale ones. + * Leave one stale entry behind - the one closest to our + * insertion index - and we'll shift that one to our insertion + * point later. + */ + if (compact) { + xfs_dir2_leaf_compact_x1(lbp, &index, &lowstale, &highstale, + &lfloglow, &lfloghigh); + } + /* + * There are stale entries, so we'll need log-low and log-high + * impossibly bad values later. + */ + else if (INT_GET(leaf->hdr.stale, ARCH_CONVERT)) { + lfloglow = INT_GET(leaf->hdr.count, ARCH_CONVERT); + lfloghigh = -1; + } + /* + * If there was no data block space found, we need to allocate + * a new one. + */ + if (use_block == -1) { + /* + * Add the new data block. + */ + if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, + &use_block))) { + xfs_da_brelse(tp, lbp); + return error; + } + /* + * Initialize the block. + */ + if ((error = xfs_dir2_data_init(args, use_block, &dbp))) { + xfs_da_brelse(tp, lbp); + return error; + } + /* + * If we're adding a new data block on the end we need to + * extend the bests table. Copy it up one entry. + */ + if (use_block >= INT_GET(ltp->bestcount, ARCH_CONVERT)) { + bestsp--; + ovbcopy(&bestsp[1], &bestsp[0], + INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(bestsp[0])); + INT_MOD(ltp->bestcount, ARCH_CONVERT, +1); + xfs_dir2_leaf_log_tail(tp, lbp); + xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1); + } + /* + * If we're filling in a previously empty block just log it. + */ + else + xfs_dir2_leaf_log_bests(tp, lbp, use_block, use_block); + data = dbp->data; + INT_COPY(bestsp[use_block], data->hdr.bestfree[0].length, ARCH_CONVERT); + grown = 1; + } + /* + * Already had space in some data block. + * Just read that one in. + */ + else { + if ((error = + xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, use_block), + -1, &dbp, XFS_DATA_FORK))) { + xfs_da_brelse(tp, lbp); + return error; + } + data = dbp->data; + grown = 0; + } + xfs_dir2_data_check(dp, dbp); + /* + * Point to the biggest freespace in our data block. + */ + dup = (xfs_dir2_data_unused_t *) + ((char *)data + INT_GET(data->hdr.bestfree[0].offset, ARCH_CONVERT)); + ASSERT(INT_GET(dup->length, ARCH_CONVERT) >= length); + needscan = needlog = 0; + /* + * Mark the initial part of our freespace in use for the new entry. + */ + xfs_dir2_data_use_free(tp, dbp, dup, + (xfs_dir2_data_aoff_t)((char *)dup - (char *)data), length, + &needlog, &needscan); + /* + * Initialize our new entry (at last). + */ + dep = (xfs_dir2_data_entry_t *)dup; + INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); + dep->namelen = args->namelen; + bcopy(args->name, dep->name, dep->namelen); + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)data)); + /* + * Need to scan fix up the bestfree table. + */ + if (needscan) + xfs_dir2_data_freescan(mp, data, &needlog, NULL); + /* + * Need to log the data block's header. + */ + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + xfs_dir2_data_log_entry(tp, dbp, dep); + /* + * If the bests table needs to be changed, do it. + * Log the change unless we've already done that. + */ + if (INT_GET(bestsp[use_block], ARCH_CONVERT) != INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT)) { + INT_COPY(bestsp[use_block], data->hdr.bestfree[0].length, ARCH_CONVERT); + if (!grown) + xfs_dir2_leaf_log_bests(tp, lbp, use_block, use_block); + } + /* + * Now we need to make room to insert the leaf entry. + * If there are no stale entries, we just insert a hole at index. + */ + if (INT_GET(leaf->hdr.stale, ARCH_CONVERT) == 0) { + /* + * lep is still good as the index leaf entry. + */ + if (index < INT_GET(leaf->hdr.count, ARCH_CONVERT)) + ovbcopy(lep, lep + 1, + (INT_GET(leaf->hdr.count, ARCH_CONVERT) - index) * sizeof(*lep)); + /* + * Record low and high logging indices for the leaf. + */ + lfloglow = index; + lfloghigh = INT_GET(leaf->hdr.count, ARCH_CONVERT); + INT_MOD(leaf->hdr.count, ARCH_CONVERT, +1); + } + /* + * There are stale entries. + * We will use one of them for the new entry. + * It's probably not at the right location, so we'll have to + * shift some up or down first. + */ + else { + /* + * If we didn't compact before, we need to find the nearest + * stale entries before and after our insertion point. + */ + if (compact == 0) { + /* + * Find the first stale entry before the insertion + * point, if any. + */ + for (lowstale = index - 1; + lowstale >= 0 && + INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) != + XFS_DIR2_NULL_DATAPTR; + lowstale--) + continue; + /* + * Find the next stale entry at or after the insertion + * point, if any. Stop if we go so far that the + * lowstale entry would be better. + */ + for (highstale = index; + highstale < INT_GET(leaf->hdr.count, ARCH_CONVERT) && + INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) != + XFS_DIR2_NULL_DATAPTR && + (lowstale < 0 || + index - lowstale - 1 >= highstale - index); + highstale++) + continue; + } + /* + * If the low one is better, use it. + */ + if (lowstale >= 0 && + (highstale == INT_GET(leaf->hdr.count, ARCH_CONVERT) || + index - lowstale - 1 < highstale - index)) { + ASSERT(index - lowstale - 1 >= 0); + ASSERT(INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) == + XFS_DIR2_NULL_DATAPTR); + /* + * Copy entries up to cover the stale entry + * and make room for the new entry. + */ + if (index - lowstale - 1 > 0) + ovbcopy(&leaf->ents[lowstale + 1], + &leaf->ents[lowstale], + (index - lowstale - 1) * sizeof(*lep)); + lep = &leaf->ents[index - 1]; + lfloglow = MIN(lowstale, lfloglow); + lfloghigh = MAX(index - 1, lfloghigh); + } + /* + * The high one is better, so use that one. + */ + else { + ASSERT(highstale - index >= 0); + ASSERT(INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) == + XFS_DIR2_NULL_DATAPTR); + /* + * Copy entries down to copver the stale entry + * and make room for the new entry. + */ + if (highstale - index > 0) + ovbcopy(&leaf->ents[index], + &leaf->ents[index + 1], + (highstale - index) * sizeof(*lep)); + lep = &leaf->ents[index]; + lfloglow = MIN(index, lfloglow); + lfloghigh = MAX(highstale, lfloghigh); + } + INT_MOD(leaf->hdr.stale, ARCH_CONVERT, -1); + } + /* + * Fill in the new leaf entry. + */ + INT_SET(lep->hashval, ARCH_CONVERT, args->hashval); + INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_DB_OFF_TO_DATAPTR(mp, use_block, INT_GET(*tagp, ARCH_CONVERT))); + /* + * Log the leaf fields and give up the buffers. + */ + xfs_dir2_leaf_log_header(tp, lbp); + xfs_dir2_leaf_log_ents(tp, lbp, lfloglow, lfloghigh); + xfs_dir2_leaf_check(dp, lbp); + xfs_da_buf_done(lbp); + xfs_dir2_data_check(dp, dbp); + xfs_da_buf_done(dbp); + return 0; +} + +#ifdef DEBUG +/* + * Check the internal consistency of a leaf1 block. + * Pop an assert if something is wrong. + */ +void +xfs_dir2_leaf_check( + xfs_inode_t *dp, /* incore directory inode */ + xfs_dabuf_t *bp) /* leaf's buffer */ +{ + int i; /* leaf index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail pointer */ + xfs_mount_t *mp; /* filesystem mount point */ + int stale; /* count of stale leaves */ + + leaf = bp->data; + mp = dp->i_mount; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC); + /* + * This value is not restrictive enough. + * Should factor in the size of the bests table as well. + * We can deduce a value for that from di_size. + */ + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) <= XFS_DIR2_MAX_LEAF_ENTS(mp)); + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + /* + * Leaves and bests don't overlap. + */ + ASSERT((char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] <= + (char *)XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT)); + /* + * Check hash value order, count stale entries. + */ + for (i = stale = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); i++) { + if (i + 1 < INT_GET(leaf->hdr.count, ARCH_CONVERT)) + ASSERT(INT_GET(leaf->ents[i].hashval, ARCH_CONVERT) <= + INT_GET(leaf->ents[i + 1].hashval, ARCH_CONVERT)); + if (INT_GET(leaf->ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + stale++; + } + ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) == stale); +} +#endif /* DEBUG */ + +/* + * Compact out any stale entries in the leaf. + * Log the header and changed leaf entries, if any. + */ +void +xfs_dir2_leaf_compact( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *bp) /* leaf buffer */ +{ + int from; /* source leaf index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + int loglow; /* first leaf entry to log */ + int to; /* target leaf index */ + + leaf = bp->data; + if (INT_GET(leaf->hdr.stale, ARCH_CONVERT) == 0) { + return; + } + /* + * Compress out the stale entries in place. + */ + for (from = to = 0, loglow = -1; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) { + if (INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + continue; + /* + * Only actually copy the entries that are different. + */ + if (from > to) { + if (loglow == -1) + loglow = to; + leaf->ents[to] = leaf->ents[from]; + } + to++; + } + /* + * Update and log the header, log the leaf entries. + */ + ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) == from - to); + INT_MOD(leaf->hdr.count, ARCH_CONVERT, -(INT_GET(leaf->hdr.stale, ARCH_CONVERT))); + INT_SET(leaf->hdr.stale, ARCH_CONVERT, 0); + xfs_dir2_leaf_log_header(args->trans, bp); + if (loglow != -1) + xfs_dir2_leaf_log_ents(args->trans, bp, loglow, to - 1); +} + +/* + * Compact the leaf entries, removing stale ones. + * Leave one stale entry behind - the one closest to our + * insertion index - and the caller will shift that one to our insertion + * point later. + * Return new insertion index, where the remaining stale entry is, + * and leaf logging indices. + */ +void +xfs_dir2_leaf_compact_x1( + xfs_dabuf_t *bp, /* leaf buffer */ + int *indexp, /* insertion index */ + int *lowstalep, /* out: stale entry before us */ + int *highstalep, /* out: stale entry after us */ + int *lowlogp, /* out: low log index */ + int *highlogp) /* out: high log index */ +{ + int from; /* source copy index */ + int highstale; /* stale entry at/after index */ + int index; /* insertion index */ + int keepstale; /* source index of kept stale */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + int lowstale; /* stale entry before index */ + int newindex=0; /* new insertion index */ + int to; /* destination copy index */ + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) > 1); + index = *indexp; + /* + * Find the first stale entry before our index, if any. + */ + for (lowstale = index - 1; + lowstale >= 0 && + INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR; + lowstale--) + continue; + /* + * Find the first stale entry at or after our index, if any. + * Stop if the answer would be worse than lowstale. + */ + for (highstale = index; + highstale < INT_GET(leaf->hdr.count, ARCH_CONVERT) && + INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR && + (lowstale < 0 || index - lowstale > highstale - index); + highstale++) + continue; + /* + * Pick the better of lowstale and highstale. + */ + if (lowstale >= 0 && + (highstale == INT_GET(leaf->hdr.count, ARCH_CONVERT) || + index - lowstale <= highstale - index)) + keepstale = lowstale; + else + keepstale = highstale; + /* + * Copy the entries in place, removing all the stale entries + * except keepstale. + */ + for (from = to = 0; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) { + /* + * Notice the new value of index. + */ + if (index == from) + newindex = to; + if (from != keepstale && + INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) { + if (from == to) + *lowlogp = to; + continue; + } + /* + * Record the new keepstale value for the insertion. + */ + if (from == keepstale) + lowstale = highstale = to; + /* + * Copy only the entries that have moved. + */ + if (from > to) + leaf->ents[to] = leaf->ents[from]; + to++; + } + ASSERT(from > to); + /* + * If the insertion point was past the last entry, + * set the new insertion point accordingly. + */ + if (index == from) + newindex = to; + *indexp = newindex; + /* + * Adjust the leaf header values. + */ + INT_MOD(leaf->hdr.count, ARCH_CONVERT, -(from - to)); + INT_SET(leaf->hdr.stale, ARCH_CONVERT, 1); + /* + * Remember the low/high stale value only in the "right" + * direction. + */ + if (lowstale >= newindex) + lowstale = -1; + else + highstale = INT_GET(leaf->hdr.count, ARCH_CONVERT); + *highlogp = INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1; + *lowstalep = lowstale; + *highstalep = highstale; +} + +/* + * Getdents (readdir) for leaf and node directories. + * This reads the data blocks only, so is the same for both forms. + */ +int /* error */ +xfs_dir2_leaf_getdents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_inode_t *dp, /* incore directory inode */ + uio_t *uio, /* I/O control & vectors */ + int *eofp, /* out: reached end of dir */ + xfs_dirent_t *dbp, /* caller's buffer */ + xfs_dir2_put_t put) /* ABI formatting routine */ +{ + xfs_dabuf_t *bp; /* data block buffer */ + int byteoff; /* offset in current block */ + xfs_dir2_db_t curdb; /* db for current block */ + xfs_dir2_off_t curoff; /* current overall offset */ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dir2_data_entry_t *dep; /* data entry */ + xfs_dir2_data_unused_t *dup; /* unused entry */ + int eof; /* reached end of directory */ + int error=0; /* error return value */ + int i; /* temporary loop index */ + int j; /* temporary loop index */ + int length; /* temporary length value */ + xfs_bmbt_irec_t *map; /* map vector for blocks */ + xfs_extlen_t map_blocks; /* number of fsbs in map */ + xfs_dablk_t map_off; /* last mapped file offset */ + int map_size; /* total entries in *map */ + int map_valid; /* valid entries in *map */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_dir2_off_t newoff; /* new curoff after new blk */ + int nmap; /* mappings to ask xfs_bmapi */ + xfs_dir2_put_args_t p; /* formatting arg bundle */ + char *ptr=NULL; /* pointer to current data */ + int ra_current; /* number of read-ahead blks */ + int ra_index; /* *map index for read-ahead */ + int ra_offset; /* map entry offset for ra */ + int ra_want; /* readahead count wanted */ + + /* + * If the offset is at or past the largest allowed value, + * give up right away, return eof. + */ + if (uio->uio_offset >= XFS_DIR2_MAX_DATAPTR) { + *eofp = 1; + return 0; + } + mp = dp->i_mount; + /* + * Setup formatting arguments. + */ + p.dbp = dbp; + p.put = put; + p.uio = uio; + /* + * Set up to bmap a number of blocks based on the caller's + * buffer size, the directory block size, and the filesystem + * block size. + */ + map_size = + howmany(uio->uio_resid + mp->m_dirblksize, + mp->m_sb.sb_blocksize); + map = kmem_alloc(map_size * sizeof(*map), tp ? KM_SLEEP : KM_SLEEP_IO); + map_valid = ra_index = ra_offset = ra_current = map_blocks = 0; + bp = NULL; + eof = 1; + /* + * Inside the loop we keep the main offset value as a byte offset + * in the directory file. + */ + curoff = XFS_DIR2_DATAPTR_TO_BYTE(mp, uio->uio_offset); + /* + * Force this conversion through db so we truncate the offset + * down to get the start of the data block. + */ + map_off = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_BYTE_TO_DB(mp, curoff)); + /* + * Loop over directory entries until we reach the end offset. + * Get more blocks and readahead as necessary. + */ + while (curoff < XFS_DIR2_LEAF_OFFSET) { + /* + * If we have no buffer, or we're off the end of the + * current buffer, need to get another one. + */ + if (!bp || ptr >= (char *)bp->data + mp->m_dirblksize) { + /* + * If we have a buffer, we need to release it and + * take it out of the mapping. + */ + if (bp) { + xfs_da_brelse(tp, bp); + bp = NULL; + map_blocks -= mp->m_dirblkfsbs; + /* + * Loop to get rid of the extents for the + * directory block. + */ + for (i = mp->m_dirblkfsbs; i > 0; ) { + j = MIN(map->br_blockcount, i); + map->br_blockcount -= j; + map->br_startblock += j; + map->br_startoff += j; + /* + * If mapping is done, pitch it from + * the table. + */ + if (!map->br_blockcount && --map_valid) + ovbcopy(&map[1], &map[0], + sizeof(map[0]) * + map_valid); + i -= j; + } + } + /* + * Recalculate the readahead blocks wanted. + */ + ra_want = howmany(uio->uio_resid + mp->m_dirblksize, + mp->m_sb.sb_blocksize) - 1; + /* + * If we don't have as many as we want, and we haven't + * run out of data blocks, get some more mappings. + */ + if (1 + ra_want > map_blocks && + map_off < + XFS_DIR2_BYTE_TO_DA(mp, XFS_DIR2_LEAF_OFFSET)) { + /* + * Get more bmaps, fill in after the ones + * we already have in the table. + */ + nmap = map_size - map_valid; + error = xfs_bmapi(tp, dp, + map_off, + XFS_DIR2_BYTE_TO_DA(mp, + XFS_DIR2_LEAF_OFFSET) - map_off, + XFS_BMAPI_METADATA, NULL, 0, + &map[map_valid], &nmap, NULL); + /* + * Don't know if we should ignore this or + * try to return an error. + * The trouble with returning errors + * is that readdir will just stop without + * actually passing the error through. + */ + if (error) + break; /* XXX */ + /* + * If we got all the mappings we asked for, + * set the final map offset based on the + * last bmap value received. + * Otherwise, we've reached the end. + */ + if (nmap == map_size - map_valid) + map_off = + map[map_valid + nmap - 1].br_startoff + + map[map_valid + nmap - 1].br_blockcount; + else + map_off = + XFS_DIR2_BYTE_TO_DA(mp, + XFS_DIR2_LEAF_OFFSET); + /* + * Look for holes in the mapping, and + * eliminate them. Count up the valid blocks. + */ + for (i = map_valid; i < map_valid + nmap; ) { + if (map[i].br_startblock == + HOLESTARTBLOCK) { + nmap--; + length = map_valid + nmap - i; + if (length) + ovbcopy(&map[i + 1], + &map[i], + sizeof(map[i]) * + length); + } else { + map_blocks += + map[i].br_blockcount; + i++; + } + } + map_valid += nmap; + } + /* + * No valid mappings, so no more data blocks. + */ + if (!map_valid) { + curoff = XFS_DIR2_DA_TO_BYTE(mp, map_off); + break; + } + /* + * Read the directory block starting at the first + * mapping. + */ + curdb = XFS_DIR2_DA_TO_DB(mp, map->br_startoff); + error = xfs_da_read_buf(tp, dp, map->br_startoff, + map->br_blockcount >= mp->m_dirblkfsbs ? + XFS_FSB_TO_DADDR(mp, map->br_startblock) : + -1, + &bp, XFS_DATA_FORK); + /* + * Should just skip over the data block instead + * of giving up. + */ + if (error) + break; /* XXX */ + /* + * Adjust the current amount of read-ahead: we just + * read a block that was previously ra. + */ + if (ra_current) + ra_current -= mp->m_dirblkfsbs; + /* + * Do we need more readahead? + */ + for (ra_index = ra_offset = i = 0; + ra_want > ra_current && i < map_blocks; + i += mp->m_dirblkfsbs) { + ASSERT(ra_index < map_valid); + /* + * Read-ahead a contiguous directory block. + */ + if (i > ra_current && + map[ra_index].br_blockcount >= + mp->m_dirblkfsbs) { + xfs_baread(mp->m_ddev_targp, + XFS_FSB_TO_DADDR(mp, + map[ra_index].br_startblock + + ra_offset), + (int)BTOBB(mp->m_dirblksize)); + ra_current = i; + } + /* + * Read-ahead a non-contiguous directory block. + * This doesn't use our mapping, but this + * is a very rare case. + */ + else if (i > ra_current) { + (void)xfs_da_reada_buf(tp, dp, + map[ra_index].br_startoff + + ra_offset, XFS_DATA_FORK); + ra_current = i; + } + /* + * Advance offset through the mapping table. + */ + for (j = 0; j < mp->m_dirblkfsbs; j++) { + /* + * The rest of this extent but not + * more than a dir block. + */ + length = MIN(mp->m_dirblkfsbs, + map[ra_index].br_blockcount - + ra_offset); + j += length; + ra_offset += length; + /* + * Advance to the next mapping if + * this one is used up. + */ + if (ra_offset == + map[ra_index].br_blockcount) { + ra_offset = 0; + ra_index++; + } + } + } + /* + * Having done a read, we need to set a new offset. + */ + newoff = XFS_DIR2_DB_OFF_TO_BYTE(mp, curdb, 0); + /* + * Start of the current block. + */ + if (curoff < newoff) + curoff = newoff; + /* + * Make sure we're in the right block. + */ + else if (curoff > newoff) + ASSERT(XFS_DIR2_BYTE_TO_DB(mp, curoff) == + curdb); + data = bp->data; + xfs_dir2_data_check(dp, bp); + /* + * Find our position in the block. + */ + ptr = (char *)&data->u; + byteoff = XFS_DIR2_BYTE_TO_OFF(mp, curoff); + /* + * Skip past the header. + */ + if (byteoff == 0) + curoff += (uint)sizeof(data->hdr); + /* + * Skip past entries until we reach our offset. + */ + else { + while ((char *)ptr - (char *)data < byteoff) { + dup = (xfs_dir2_data_unused_t *)ptr; + + if (INT_GET(dup->freetag, ARCH_CONVERT) + == XFS_DIR2_DATA_FREE_TAG) { + + length = INT_GET(dup->length, + ARCH_CONVERT); + ptr += length; + continue; + } + dep = (xfs_dir2_data_entry_t *)ptr; + length = + XFS_DIR2_DATA_ENTSIZE(dep->namelen); + ptr += length; + } + /* + * Now set our real offset. + */ + curoff = + XFS_DIR2_DB_OFF_TO_BYTE(mp, + XFS_DIR2_BYTE_TO_DB(mp, curoff), + (char *)ptr - (char *)data); + } + } + /* + * We have a pointer to an entry. + * Is it a live one? + */ + dup = (xfs_dir2_data_unused_t *)ptr; + /* + * No, it's unused, skip over it. + */ + if (INT_GET(dup->freetag, ARCH_CONVERT) + == XFS_DIR2_DATA_FREE_TAG) { + length = INT_GET(dup->length, ARCH_CONVERT); + ptr += length; + curoff += length; + continue; + } + + /* + * Copy the entry into the putargs, and try formatting it. + */ + dep = (xfs_dir2_data_entry_t *)ptr; + + p.namelen = dep->namelen; + + length = XFS_DIR2_DATA_ENTSIZE(p.namelen); + + /* + * NOTE! Linux "filldir" semantics require that the + * offset "cookie" be for this entry, not the + * next; all the actual shuffling to make it + * "look right" to the user is done in filldir. + */ + p.cook = XFS_DIR2_BYTE_TO_DATAPTR(mp, curoff); + +#if XFS_BIG_FILESYSTEMS + p.ino = INT_GET(dep->inumber, ARCH_CONVERT) + mp->m_inoadd; +#else + p.ino = INT_GET(dep->inumber, ARCH_CONVERT); +#endif + p.name = (char *)dep->name; + + error = p.put(&p); + + /* + * Won't fit. Return to caller. + */ + if (!p.done) { + eof = 0; + break; + } + /* + * Advance to next entry in the block. + */ + ptr += length; + curoff += length; + } + + /* + * All done. Set output offset value to current offset. + */ + *eofp = eof; + if (curoff > XFS_DIR2_DATAPTR_TO_BYTE(mp, XFS_DIR2_MAX_DATAPTR)) + uio->uio_offset = XFS_DIR2_MAX_DATAPTR; + else + uio->uio_offset = XFS_DIR2_BYTE_TO_DATAPTR(mp, curoff); + kmem_free(map, map_size * sizeof(*map)); + if (bp) + xfs_da_brelse(tp, bp); + return error; +} + +/* + * Initialize a new leaf block, leaf1 or leafn magic accepted. + */ +int +xfs_dir2_leaf_init( + xfs_da_args_t *args, /* operation arguments */ + xfs_dir2_db_t bno, /* directory block number */ + xfs_dabuf_t **bpp, /* out: leaf buffer */ + int magic) /* magic number for block */ +{ + xfs_dabuf_t *bp; /* leaf buffer */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + ASSERT(dp != NULL); + tp = args->trans; + mp = dp->i_mount; + ASSERT(bno >= XFS_DIR2_LEAF_FIRSTDB(mp) && + bno < XFS_DIR2_FREE_FIRSTDB(mp)); + /* + * Get the buffer for the block. + */ + error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, bno), -1, &bp, + XFS_DATA_FORK); + if (error) { + return error; + } + ASSERT(bp != NULL); + leaf = bp->data; + /* + * Initialize the header. + */ + INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, magic); + INT_ZERO(leaf->hdr.info.forw, ARCH_CONVERT); + INT_ZERO(leaf->hdr.info.back, ARCH_CONVERT); + INT_ZERO(leaf->hdr.count, ARCH_CONVERT); + INT_ZERO(leaf->hdr.stale, ARCH_CONVERT); + xfs_dir2_leaf_log_header(tp, bp); + /* + * If it's a leaf-format directory initialize the tail. + * In this case our caller has the real bests table to copy into + * the block. + */ + if (magic == XFS_DIR2_LEAF1_MAGIC) { + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + INT_SET(ltp->bestcount, ARCH_CONVERT, 0); + xfs_dir2_leaf_log_tail(tp, bp); + } + *bpp = bp; + return 0; +} + +/* + * Log the bests entries indicated from a leaf1 block. + */ +void +xfs_dir2_leaf_log_bests( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* leaf buffer */ + int first, /* first entry to log */ + int last) /* last entry to log */ +{ + xfs_dir2_data_off_t *firstb; /* pointer to first entry */ + xfs_dir2_data_off_t *lastb; /* pointer to last entry */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC); + ltp = XFS_DIR2_LEAF_TAIL_P(tp->t_mountp, leaf); + firstb = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT) + first; + lastb = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT) + last; + xfs_da_log_buf(tp, bp, (uint)((char *)firstb - (char *)leaf), + (uint)((char *)lastb - (char *)leaf + sizeof(*lastb) - 1)); +} + +/* + * Log the leaf entries indicated from a leaf1 or leafn block. + */ +void +xfs_dir2_leaf_log_ents( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* leaf buffer */ + int first, /* first entry to log */ + int last) /* last entry to log */ +{ + xfs_dir2_leaf_entry_t *firstlep; /* pointer to first entry */ + xfs_dir2_leaf_entry_t *lastlep; /* pointer to last entry */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC || + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + firstlep = &leaf->ents[first]; + lastlep = &leaf->ents[last]; + xfs_da_log_buf(tp, bp, (uint)((char *)firstlep - (char *)leaf), + (uint)((char *)lastlep - (char *)leaf + sizeof(*lastlep) - 1)); +} + +/* + * Log the header of the leaf1 or leafn block. + */ +void +xfs_dir2_leaf_log_header( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp) /* leaf buffer */ +{ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC || + INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + xfs_da_log_buf(tp, bp, (uint)((char *)&leaf->hdr - (char *)leaf), + (uint)(sizeof(leaf->hdr) - 1)); +} + +/* + * Log the tail of the leaf1 block. + */ +void +xfs_dir2_leaf_log_tail( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp) /* leaf buffer */ +{ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* filesystem mount point */ + + mp = tp->t_mountp; + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC); + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + xfs_da_log_buf(tp, bp, (uint)((char *)ltp - (char *)leaf), + (uint)(mp->m_dirblksize - 1)); +} + +/* + * Look up the entry referred to by args in the leaf format directory. + * Most of the work is done by the xfs_dir2_leaf_lookup_int routine which + * is also used by the node-format code. + */ +int +xfs_dir2_leaf_lookup( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data block entry */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + int index; /* found entry index */ + xfs_dabuf_t *lbp; /* leaf buffer */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args("leaf_lookup", args); + /* + * Look up name in the leaf block, returning both buffers and index. + */ + if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { + return error; + } + tp = args->trans; + dp = args->dp; + xfs_dir2_leaf_check(dp, lbp); + leaf = lbp->data; + /* + * Get to the leaf entry and contained data entry address. + */ + lep = &leaf->ents[index]; + /* + * Point to the data entry. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)dbp->data + + XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, INT_GET(lep->address, ARCH_CONVERT))); + /* + * Return the found inode number. + */ + args->inumber = INT_GET(dep->inumber, ARCH_CONVERT); + xfs_da_brelse(tp, dbp); + xfs_da_brelse(tp, lbp); + return XFS_ERROR(EEXIST); +} + +/* + * Look up name/hash in the leaf block. + * Fill in indexp with the found index, and dbpp with the data buffer. + * If not found dbpp will be NULL, and ENOENT comes back. + * lbpp will always be filled in with the leaf buffer unless there's an error. + */ +static int /* error */ +xfs_dir2_leaf_lookup_int( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t **lbpp, /* out: leaf buffer */ + int *indexp, /* out: index in leaf block */ + xfs_dabuf_t **dbpp) /* out: data buffer */ +{ + xfs_dir2_db_t curdb; /* current data block number */ + xfs_dabuf_t *dbp; /* data buffer */ + xfs_dir2_data_entry_t *dep; /* data entry */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + int index; /* index in leaf block */ + xfs_dabuf_t *lbp; /* leaf buffer */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_dir2_db_t newdb; /* new data block number */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + /* + * Read the leaf block into the buffer. + */ + if ((error = + xfs_da_read_buf(tp, dp, mp->m_dirleafblk, -1, &lbp, + XFS_DATA_FORK))) { + return error; + } + *lbpp = lbp; + leaf = lbp->data; + xfs_dir2_leaf_check(dp, lbp); + /* + * Look for the first leaf entry with our hash value. + */ + index = xfs_dir2_leaf_search_hash(args, lbp); + /* + * Loop over all the entries with the right hash value + * looking to match the name. + */ + for (lep = &leaf->ents[index], dbp = NULL, curdb = -1; + index < INT_GET(leaf->hdr.count, ARCH_CONVERT) && INT_GET(lep->hashval, ARCH_CONVERT) == args->hashval; + lep++, index++) { + /* + * Skip over stale leaf entries. + */ + if (INT_GET(lep->address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + continue; + /* + * Get the new data block number. + */ + newdb = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT)); + /* + * If it's not the same as the old data block number, + * need to pitch the old one and read the new one. + */ + if (newdb != curdb) { + if (dbp) + xfs_da_brelse(tp, dbp); + if ((error = + xfs_da_read_buf(tp, dp, + XFS_DIR2_DB_TO_DA(mp, newdb), -1, &dbp, + XFS_DATA_FORK))) { + xfs_da_brelse(tp, lbp); + return error; + } + xfs_dir2_data_check(dp, dbp); + curdb = newdb; + } + /* + * Point to the data entry. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)dbp->data + + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT))); + /* + * If it matches then return it. + */ + if (dep->namelen == args->namelen && + dep->name[0] == args->name[0] && + bcmp(dep->name, args->name, args->namelen) == 0) { + *dbpp = dbp; + *indexp = index; + return 0; + } + } + /* + * No match found, return ENOENT. + */ + ASSERT(args->oknoent); + if (dbp) + xfs_da_brelse(tp, dbp); + xfs_da_brelse(tp, lbp); + return XFS_ERROR(ENOENT); +} + +/* + * Remove an entry from a leaf format directory. + */ +int /* error */ +xfs_dir2_leaf_removename( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_dir2_data_off_t *bestsp; /* leaf block best freespace */ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dir2_db_t db; /* data block number */ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data entry structure */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + xfs_dir2_db_t i; /* temporary data block # */ + int index; /* index into leaf entries */ + xfs_dabuf_t *lbp; /* leaf buffer */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log data header */ + int needscan; /* need to rescan data frees */ + xfs_dir2_data_off_t oldbest; /* old value of best free */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args("leaf_removename", args); + /* + * Lookup the leaf entry, get the leaf and data blocks read in. + */ + if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { + return error; + } + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + leaf = lbp->data; + data = dbp->data; + xfs_dir2_data_check(dp, dbp); + /* + * Point to the leaf entry, use that to point to the data entry. + */ + lep = &leaf->ents[index]; + db = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT)); + dep = (xfs_dir2_data_entry_t *) + ((char *)data + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT))); + needscan = needlog = 0; + oldbest = INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT); + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + ASSERT(INT_GET(bestsp[db], ARCH_CONVERT) == oldbest); + /* + * Mark the former data entry unused. + */ + xfs_dir2_data_make_free(tp, dbp, + (xfs_dir2_data_aoff_t)((char *)dep - (char *)data), + XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan); + /* + * We just mark the leaf entry stale by putting a null in it. + */ + INT_MOD(leaf->hdr.stale, ARCH_CONVERT, +1); + xfs_dir2_leaf_log_header(tp, lbp); + INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_NULL_DATAPTR); + xfs_dir2_leaf_log_ents(tp, lbp, index, index); + /* + * Scan the freespace in the data block again if necessary, + * log the data block header if necessary. + */ + if (needscan) + xfs_dir2_data_freescan(mp, data, &needlog, NULL); + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + /* + * If the longest freespace in the data block has changed, + * put the new value in the bests table and log that. + */ + if (INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) != oldbest) { + INT_COPY(bestsp[db], data->hdr.bestfree[0].length, ARCH_CONVERT); + xfs_dir2_leaf_log_bests(tp, lbp, db, db); + } + xfs_dir2_data_check(dp, dbp); + /* + * If the data block is now empty then get rid of the data block. + */ + if (INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) == + mp->m_dirblksize - (uint)sizeof(data->hdr)) { + ASSERT(db != mp->m_dirdatablk); + if ((error = xfs_dir2_shrink_inode(args, db, dbp))) { + /* + * Nope, can't get rid of it because it caused + * allocation of a bmap btree block to do so. + * Just go on, returning success, leaving the + * empty block in place. + */ + if (error == ENOSPC && args->total == 0) { + xfs_da_buf_done(dbp); + error = 0; + } + xfs_dir2_leaf_check(dp, lbp); + xfs_da_buf_done(lbp); + return error; + } + dbp = NULL; + /* + * If this is the last data block then compact the + * bests table by getting rid of entries. + */ + if (db == INT_GET(ltp->bestcount, ARCH_CONVERT) - 1) { + /* + * Look for the last active entry (i). + */ + for (i = db - 1; i > 0; i--) { + if (INT_GET(bestsp[i], ARCH_CONVERT) != NULLDATAOFF) + break; + } + /* + * Copy the table down so inactive entries at the + * end are removed. + */ + ovbcopy(bestsp, &bestsp[db - i], + (INT_GET(ltp->bestcount, ARCH_CONVERT) - (db - i)) * sizeof(*bestsp)); + INT_MOD(ltp->bestcount, ARCH_CONVERT, -(db - i)); + xfs_dir2_leaf_log_tail(tp, lbp); + xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1); + } else + INT_SET(bestsp[db], ARCH_CONVERT, NULLDATAOFF); + } + /* + * If the data block was not the first one, drop it. + */ + else if (db != mp->m_dirdatablk && dbp != NULL) { + xfs_da_buf_done(dbp); + dbp = NULL; + } + xfs_dir2_leaf_check(dp, lbp); + /* + * See if we can convert to block form. + */ + return xfs_dir2_leaf_to_block(args, lbp, dbp); +} + +/* + * Replace the inode number in a leaf format directory entry. + */ +int /* error */ +xfs_dir2_leaf_replace( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data block entry */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + int index; /* index of leaf entry */ + xfs_dabuf_t *lbp; /* leaf buffer */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args("leaf_replace", args); + /* + * Look up the entry. + */ + if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { + return error; + } + dp = args->dp; + leaf = lbp->data; + /* + * Point to the leaf entry, get data address from it. + */ + lep = &leaf->ents[index]; + /* + * Point to the data entry. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)dbp->data + + XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, INT_GET(lep->address, ARCH_CONVERT))); + ASSERT(args->inumber != INT_GET(dep->inumber, ARCH_CONVERT)); + /* + * Put the new inode number in, log it. + */ + INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); + tp = args->trans; + xfs_dir2_data_log_entry(tp, dbp, dep); + xfs_da_buf_done(dbp); + xfs_dir2_leaf_check(dp, lbp); + xfs_da_brelse(tp, lbp); + return 0; +} + +/* + * Return index in the leaf block (lbp) which is either the first + * one with this hash value, or if there are none, the insert point + * for that hash value. + */ +int /* index value */ +xfs_dir2_leaf_search_hash( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *lbp) /* leaf buffer */ +{ + xfs_dahash_t hash=0; /* hash from this entry */ + xfs_dahash_t hashwant; /* hash value looking for */ + int high; /* high leaf index */ + int low; /* low leaf index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + int mid=0; /* current leaf index */ + + leaf = lbp->data; +#ifndef __KERNEL__ + if (INT_GET(leaf->hdr.count, ARCH_CONVERT) == 0) + return 0; +#endif + /* + * Note, the table cannot be empty, so we have to go through the loop. + * Binary search the leaf entries looking for our hash value. + */ + for (lep = leaf->ents, low = 0, high = INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1, + hashwant = args->hashval; + low <= high; ) { + mid = (low + high) >> 1; + if ((hash = INT_GET(lep[mid].hashval, ARCH_CONVERT)) == hashwant) + break; + if (hash < hashwant) + low = mid + 1; + else + high = mid - 1; + } + /* + * Found one, back up through all the equal hash values. + */ + if (hash == hashwant) { + while (mid > 0 && INT_GET(lep[mid - 1].hashval, ARCH_CONVERT) == hashwant) { + mid--; + } + } + /* + * Need to point to an entry higher than ours. + */ + else if (hash < hashwant) + mid++; + return mid; +} + +/* + * Trim off a trailing data block. We know it's empty since the leaf + * freespace table says so. + */ +int /* error */ +xfs_dir2_leaf_trim_data( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *lbp, /* leaf buffer */ + xfs_dir2_db_t db) /* data block number */ +{ + xfs_dir2_data_off_t *bestsp; /* leaf bests table */ +#ifdef DEBUG + xfs_dir2_data_t *data; /* data block structure */ +#endif + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + /* + * Read the offending data block. We need its buffer. + */ + if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, db), -1, &dbp, + XFS_DATA_FORK))) { + return error; + } +#ifdef DEBUG + data = dbp->data; + ASSERT(INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC); +#endif + /* this seems to be an error + * data is only valid if DEBUG is defined? + * RMC 09/08/1999 + */ + + leaf = lbp->data; + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + ASSERT(INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) == + mp->m_dirblksize - (uint)sizeof(data->hdr)); + ASSERT(db == INT_GET(ltp->bestcount, ARCH_CONVERT) - 1); + /* + * Get rid of the data block. + */ + if ((error = xfs_dir2_shrink_inode(args, db, dbp))) { + ASSERT(error != ENOSPC); + xfs_da_brelse(tp, dbp); + return error; + } + /* + * Eliminate the last bests entry from the table. + */ + bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT); + INT_MOD(ltp->bestcount, ARCH_CONVERT, -1); + ovbcopy(&bestsp[0], &bestsp[1], INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(*bestsp)); + xfs_dir2_leaf_log_tail(tp, lbp); + xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1); + return 0; +} + +/* + * Convert node form directory to leaf form directory. + * The root of the node form dir needs to already be a LEAFN block. + * Just return if we can't do anything. + */ +int /* error */ +xfs_dir2_node_to_leaf( + xfs_da_state_t *state) /* directory operation state */ +{ + xfs_da_args_t *args; /* operation arguments */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + xfs_dabuf_t *fbp; /* buffer for freespace block */ + xfs_fileoff_t fo; /* freespace file offset */ + xfs_dir2_free_t *free; /* freespace structure */ + xfs_dabuf_t *lbp; /* buffer for leaf block */ + xfs_dir2_leaf_tail_t *ltp; /* tail of leaf structure */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_mount_t *mp; /* filesystem mount point */ + int rval; /* successful free trim? */ + xfs_trans_t *tp; /* transaction pointer */ + + /* + * There's more than a leaf level in the btree, so there must + * be multiple leafn blocks. Give up. + */ + if (state->path.active > 1) + return 0; + args = state->args; + xfs_dir2_trace_args("node_to_leaf", args); + mp = state->mp; + dp = args->dp; + tp = args->trans; + /* + * Get the last offset in the file. + */ + if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK))) { + return error; + } + fo -= mp->m_dirblkfsbs; + /* + * If there are freespace blocks other than the first one, + * take this opportunity to remove trailing empty freespace blocks + * that may have been left behind during no-space-reservation + * operations. + */ + while (fo > mp->m_dirfreeblk) { + if ((error = xfs_dir2_node_trim_free(args, fo, &rval))) { + return error; + } + if (rval) + fo -= mp->m_dirblkfsbs; + else + return 0; + } + /* + * Now find the block just before the freespace block. + */ + if ((error = xfs_bmap_last_before(tp, dp, &fo, XFS_DATA_FORK))) { + return error; + } + /* + * If it's not the single leaf block, give up. + */ + if (XFS_FSB_TO_B(mp, fo) > XFS_DIR2_LEAF_OFFSET + mp->m_dirblksize) + return 0; + lbp = state->path.blk[0].bp; + leaf = lbp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + /* + * Read the freespace block. + */ + if ((error = xfs_da_read_buf(tp, dp, mp->m_dirfreeblk, -1, &fbp, + XFS_DATA_FORK))) { + return error; + } + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + ASSERT(INT_ISZERO(free->hdr.firstdb, ARCH_CONVERT)); + /* + * Now see if the leafn and free data will fit in a leaf1. + * If not, release the buffer and give up. + */ + if ((uint)sizeof(leaf->hdr) + + (INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT)) * (uint)sizeof(leaf->ents[0]) + + INT_GET(free->hdr.nvalid, ARCH_CONVERT) * (uint)sizeof(leaf->bests[0]) + + (uint)sizeof(leaf->tail) > + mp->m_dirblksize) { + xfs_da_brelse(tp, fbp); + return 0; + } + /* + * If the leaf has any stale entries in it, compress them out. + * The compact routine will log the header. + */ + if (INT_GET(leaf->hdr.stale, ARCH_CONVERT)) + xfs_dir2_leaf_compact(args, lbp); + else + xfs_dir2_leaf_log_header(tp, lbp); + INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, XFS_DIR2_LEAF1_MAGIC); + /* + * Set up the leaf tail from the freespace block. + */ + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + INT_COPY(ltp->bestcount, free->hdr.nvalid, ARCH_CONVERT); + /* + * Set up the leaf bests table. + */ + bcopy(free->bests, XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT), + INT_GET(ltp->bestcount, ARCH_CONVERT) * sizeof(leaf->bests[0])); + xfs_dir2_leaf_log_bests(tp, lbp, 0, INT_GET(ltp->bestcount, ARCH_CONVERT) - 1); + xfs_dir2_leaf_log_tail(tp, lbp); + xfs_dir2_leaf_check(dp, lbp); + /* + * Get rid of the freespace block. + */ + error = xfs_dir2_shrink_inode(args, XFS_DIR2_FREE_FIRSTDB(mp), fbp); + if (error) { + /* + * This can't fail here because it can only happen when + * punching out the middle of an extent, and this is an + * isolated block. + */ + ASSERT(error != ENOSPC); + return error; + } + fbp = NULL; + /* + * Now see if we can convert the single-leaf directory + * down to a block form directory. + * This routine always kills the dabuf for the leaf, so + * eliminate it from the path. + */ + error = xfs_dir2_leaf_to_block(args, lbp, NULL); + state->path.blk[0].bp = NULL; + return error; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir2_leaf.h linux-2.4-xfs/linux/fs/xfs/xfs_dir2_leaf.h --- linux-2.4.7/linux/fs/xfs/xfs_dir2_leaf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir2_leaf.h Tue Apr 10 20:44:54 2001 @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_LEAF_H__ +#define __XFS_DIR2_LEAF_H__ + +/* + * Directory version 2, leaf block structures. + */ + +struct dirent; +struct uio; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * Constants. + */ + +/* + * Offset of the leaf/node space. First block in this space + * is the btree root. + */ +#define XFS_DIR2_LEAF_SPACE 1 +#define XFS_DIR2_LEAF_OFFSET (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE) +#define XFS_DIR2_LEAF_FIRSTDB(mp) \ + XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_LEAF_OFFSET) + +/* + * Types. + */ + +/* + * Offset in data space of a data entry. + */ +typedef __uint32_t xfs_dir2_dataptr_t; +#define XFS_DIR2_MAX_DATAPTR ((xfs_dir2_dataptr_t)0x7fffffff) +#define XFS_DIR2_NULL_DATAPTR ((xfs_dir2_dataptr_t)0) + +/* + * Structures. + */ + +/* + * Leaf block header. + */ +typedef struct xfs_dir2_leaf_hdr { + xfs_da_blkinfo_t info; /* header for da routines */ + __uint16_t count; /* count of entries */ + __uint16_t stale; /* count of stale entries */ +} xfs_dir2_leaf_hdr_t; + +/* + * Leaf block entry. + */ +typedef struct xfs_dir2_leaf_entry { + xfs_dahash_t hashval; /* hash value of name */ + xfs_dir2_dataptr_t address; /* address of data entry */ +} xfs_dir2_leaf_entry_t; + +/* + * Leaf block tail. + */ +typedef struct xfs_dir2_leaf_tail { + __uint32_t bestcount; +} xfs_dir2_leaf_tail_t; + +/* + * Leaf block. + * bests and tail are at the end of the block for single-leaf only + * (magic = XFS_DIR2_LEAF1_MAGIC not XFS_DIR2_LEAFN_MAGIC). + */ +typedef struct xfs_dir2_leaf { + xfs_dir2_leaf_hdr_t hdr; /* leaf header */ + xfs_dir2_leaf_entry_t ents[1]; /* entries */ + /* ... */ + xfs_dir2_data_off_t bests[1]; /* best free counts */ + xfs_dir2_leaf_tail_t tail; /* leaf tail */ +} xfs_dir2_leaf_t; + +/* + * Macros. + * The DB blocks are logical directory block numbers, not filesystem blocks. + */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_MAX_LEAF_ENTS) +int +xfs_dir2_max_leaf_ents(struct xfs_mount *mp); +#define XFS_DIR2_MAX_LEAF_ENTS(mp) \ + xfs_dir2_max_leaf_ents(mp) +#else +#define XFS_DIR2_MAX_LEAF_ENTS(mp) \ + ((int)(((mp)->m_dirblksize - (uint)sizeof(xfs_dir2_leaf_hdr_t)) / \ + (uint)sizeof(xfs_dir2_leaf_entry_t))) +#endif + +/* + * Get address of the bestcount field in the single-leaf block. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_LEAF_TAIL_P) +xfs_dir2_leaf_tail_t * +xfs_dir2_leaf_tail_p(struct xfs_mount *mp, xfs_dir2_leaf_t *lp); +#define XFS_DIR2_LEAF_TAIL_P(mp,lp) \ + xfs_dir2_leaf_tail_p(mp, lp) +#else +#define XFS_DIR2_LEAF_TAIL_P(mp,lp) \ + ((xfs_dir2_leaf_tail_t *)\ + ((char *)(lp) + (mp)->m_dirblksize - \ + (uint)sizeof(xfs_dir2_leaf_tail_t))) +#endif + +/* + * Get address of the bests array in the single-leaf block. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_LEAF_BESTS_P) +xfs_dir2_data_off_t * +xfs_dir2_leaf_bests_p_arch(xfs_dir2_leaf_tail_t *ltp, xfs_arch_t arch); +#define XFS_DIR2_LEAF_BESTS_P_ARCH(ltp,arch) xfs_dir2_leaf_bests_p_arch(ltp,arch) +#else +#define XFS_DIR2_LEAF_BESTS_P_ARCH(ltp,arch) \ + ((xfs_dir2_data_off_t *)(ltp) - INT_GET((ltp)->bestcount, arch)) +#endif + +/* + * Convert dataptr to byte in file space + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATAPTR_TO_BYTE) +xfs_dir2_off_t +xfs_dir2_dataptr_to_byte(struct xfs_mount *mp, xfs_dir2_dataptr_t dp); +#define XFS_DIR2_DATAPTR_TO_BYTE(mp,dp) xfs_dir2_dataptr_to_byte(mp, dp) +#else +#define XFS_DIR2_DATAPTR_TO_BYTE(mp,dp) \ + ((xfs_dir2_off_t)(dp) << XFS_DIR2_DATA_ALIGN_LOG) +#endif + +/* + * Convert byte in file space to dataptr. It had better be aligned. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BYTE_TO_DATAPTR) +xfs_dir2_dataptr_t +xfs_dir2_byte_to_dataptr(struct xfs_mount *mp, xfs_dir2_off_t by); +#define XFS_DIR2_BYTE_TO_DATAPTR(mp,by) xfs_dir2_byte_to_dataptr(mp,by) +#else +#define XFS_DIR2_BYTE_TO_DATAPTR(mp,by) \ + ((xfs_dir2_dataptr_t)((by) >> XFS_DIR2_DATA_ALIGN_LOG)) +#endif + +/* + * Convert dataptr to a block number + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATAPTR_TO_DB) +xfs_dir2_db_t +xfs_dir2_dataptr_to_db(struct xfs_mount *mp, xfs_dir2_dataptr_t dp); +#define XFS_DIR2_DATAPTR_TO_DB(mp,dp) xfs_dir2_dataptr_to_db(mp, dp) +#else +#define XFS_DIR2_DATAPTR_TO_DB(mp,dp) \ + XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_DATAPTR_TO_BYTE(mp, dp)) +#endif + +/* + * Convert dataptr to a byte offset in a block + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DATAPTR_TO_OFF) +xfs_dir2_data_aoff_t +xfs_dir2_dataptr_to_off(struct xfs_mount *mp, xfs_dir2_dataptr_t dp); +#define XFS_DIR2_DATAPTR_TO_OFF(mp,dp) xfs_dir2_dataptr_to_off(mp, dp) +#else +#define XFS_DIR2_DATAPTR_TO_OFF(mp,dp) \ + XFS_DIR2_BYTE_TO_OFF(mp, XFS_DIR2_DATAPTR_TO_BYTE(mp, dp)) +#endif + +/* + * Convert block and offset to byte in space + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DB_OFF_TO_BYTE) +xfs_dir2_off_t +xfs_dir2_db_off_to_byte(struct xfs_mount *mp, xfs_dir2_db_t db, + xfs_dir2_data_aoff_t o); +#define XFS_DIR2_DB_OFF_TO_BYTE(mp,db,o) \ + xfs_dir2_db_off_to_byte(mp, db, o) +#else +#define XFS_DIR2_DB_OFF_TO_BYTE(mp,db,o) \ + (((xfs_dir2_off_t)(db) << \ + ((mp)->m_sb.sb_blocklog + (mp)->m_sb.sb_dirblklog)) + (o)) +#endif + +/* + * Convert byte in space to (DB) block + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BYTE_TO_DB) +xfs_dir2_db_t xfs_dir2_byte_to_db(struct xfs_mount *mp, xfs_dir2_off_t by); +#define XFS_DIR2_BYTE_TO_DB(mp,by) xfs_dir2_byte_to_db(mp, by) +#else +#define XFS_DIR2_BYTE_TO_DB(mp,by) \ + ((xfs_dir2_db_t)((by) >> \ + ((mp)->m_sb.sb_blocklog + (mp)->m_sb.sb_dirblklog))) +#endif + +/* + * Convert byte in space to (DA) block + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BYTE_TO_DA) +xfs_dablk_t xfs_dir2_byte_to_da(struct xfs_mount *mp, xfs_dir2_off_t by); +#define XFS_DIR2_BYTE_TO_DA(mp,by) xfs_dir2_byte_to_da(mp, by) +#else +#define XFS_DIR2_BYTE_TO_DA(mp,by) \ + XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_BYTE_TO_DB(mp, by)) +#endif + +/* + * Convert byte in space to offset in a block + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_BYTE_TO_OFF) +xfs_dir2_data_aoff_t +xfs_dir2_byte_to_off(struct xfs_mount *mp, xfs_dir2_off_t by); +#define XFS_DIR2_BYTE_TO_OFF(mp,by) xfs_dir2_byte_to_off(mp, by) +#else +#define XFS_DIR2_BYTE_TO_OFF(mp,by) \ + ((xfs_dir2_data_aoff_t)((by) & \ + ((1 << ((mp)->m_sb.sb_blocklog + \ + (mp)->m_sb.sb_dirblklog)) - 1))) +#endif + +/* + * Convert block and offset to dataptr + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DB_OFF_TO_DATAPTR) +xfs_dir2_dataptr_t +xfs_dir2_db_off_to_dataptr(struct xfs_mount *mp, xfs_dir2_db_t db, + xfs_dir2_data_aoff_t o); +#define XFS_DIR2_DB_OFF_TO_DATAPTR(mp,db,o) \ + xfs_dir2_db_off_to_dataptr(mp, db, o) +#else +#define XFS_DIR2_DB_OFF_TO_DATAPTR(mp,db,o) \ + XFS_DIR2_BYTE_TO_DATAPTR(mp, XFS_DIR2_DB_OFF_TO_BYTE(mp, db, o)) +#endif + +/* + * Convert block (DB) to block (dablk) + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DB_TO_DA) +xfs_dablk_t xfs_dir2_db_to_da(struct xfs_mount *mp, xfs_dir2_db_t db); +#define XFS_DIR2_DB_TO_DA(mp,db) xfs_dir2_db_to_da(mp, db) +#else +#define XFS_DIR2_DB_TO_DA(mp,db) \ + ((xfs_dablk_t)((db) << (mp)->m_sb.sb_dirblklog)) +#endif + +/* + * Convert block (dablk) to block (DB) + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DA_TO_DB) +xfs_dir2_db_t xfs_dir2_da_to_db(struct xfs_mount *mp, xfs_dablk_t da); +#define XFS_DIR2_DA_TO_DB(mp,da) xfs_dir2_da_to_db(mp, da) +#else +#define XFS_DIR2_DA_TO_DB(mp,da) \ + ((xfs_dir2_db_t)((da) >> (mp)->m_sb.sb_dirblklog)) +#endif + +/* + * Convert block (dablk) to byte offset in space + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DA_TO_BYTE) +xfs_dir2_off_t xfs_dir2_da_to_byte(struct xfs_mount *mp, xfs_dablk_t da); +#define XFS_DIR2_DA_TO_BYTE(mp,da) xfs_dir2_da_to_byte(mp, da) +#else +#define XFS_DIR2_DA_TO_BYTE(mp,da) \ + XFS_DIR2_DB_OFF_TO_BYTE(mp, XFS_DIR2_DA_TO_DB(mp, da), 0) +#endif + +/* + * Function declarations. + */ + +extern int + xfs_dir2_block_to_leaf(struct xfs_da_args *args, struct xfs_dabuf *dbp); + +extern int + xfs_dir2_leaf_addname(struct xfs_da_args *args); + +extern void + xfs_dir2_leaf_compact(struct xfs_da_args *args, struct xfs_dabuf *bp); + +extern void + xfs_dir2_leaf_compact_x1(struct xfs_dabuf *bp, int *indexp, + int *lowstalep, int *highstalep, int *lowlogp, + int *highlogp); + +extern int + xfs_dir2_leaf_getdents(struct xfs_trans *tp, struct xfs_inode *dp, + struct uio *uio, int *eofp, struct xfs_dirent *dbp, + xfs_dir2_put_t put); + +extern int + xfs_dir2_leaf_init(struct xfs_da_args *args, xfs_dir2_db_t bno, + struct xfs_dabuf **bpp, int magic); + +extern void + xfs_dir2_leaf_log_ents(struct xfs_trans *tp, struct xfs_dabuf *bp, + int first, int last); + +extern void + xfs_dir2_leaf_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp, + int first, int last); + +extern void + xfs_dir2_leaf_log_header(struct xfs_trans *tp, struct xfs_dabuf *bp); + +extern void + xfs_dir2_leaf_log_tail(struct xfs_trans *tp, struct xfs_dabuf *bp); + +extern int + xfs_dir2_leaf_lookup(struct xfs_da_args *args); + +extern int + xfs_dir2_leaf_removename(struct xfs_da_args *args); + +extern int + xfs_dir2_leaf_replace(struct xfs_da_args *args); + +extern int + xfs_dir2_leaf_search_hash(struct xfs_da_args *args, + struct xfs_dabuf *lbp); +extern int + xfs_dir2_leaf_trim_data(struct xfs_da_args *args, struct xfs_dabuf *lbp, xfs_dir2_db_t db); + +extern int + xfs_dir2_node_to_leaf(struct xfs_da_state *state); + +#endif /* __XFS_DIR2_LEAF_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir2_node.c linux-2.4-xfs/linux/fs/xfs/xfs_dir2_node.c --- linux-2.4.7/linux/fs/xfs/xfs_dir2_node.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir2_node.c Mon Apr 23 14:52:01 2001 @@ -0,0 +1,1976 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_node.c + * XFS directory implementation, version 2, node form files + * See data structures in xfs_dir2_node.h and xfs_da_btree.h. + */ + +#include + +/* + * Function declarations. + */ +static void xfs_dir2_free_log_header(xfs_trans_t *tp, xfs_dabuf_t *bp); +static int xfs_dir2_leafn_add(xfs_dabuf_t *bp, xfs_da_args_t *args, int index); +#ifdef DEBUG +static void xfs_dir2_leafn_check(xfs_inode_t *dp, xfs_dabuf_t *bp); +#else +#define xfs_dir2_leafn_check(dp, bp) +#endif +static void xfs_dir2_leafn_moveents(xfs_da_args_t *args, xfs_dabuf_t *bp_s, + int start_s, xfs_dabuf_t *bp_d, int start_d, + int count); +static void xfs_dir2_leafn_rebalance(xfs_da_state_t *state, + xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2); +static int xfs_dir2_leafn_remove(xfs_da_args_t *args, xfs_dabuf_t *bp, + int index, xfs_da_state_blk_t *dblk, + int *rval); +static int xfs_dir2_node_addname_int(xfs_da_args_t *args, + xfs_da_state_blk_t *fblk); + +/* + * Log entries from a freespace block. + */ +void +xfs_dir2_free_log_bests( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp, /* freespace buffer */ + int first, /* first entry to log */ + int last) /* last entry to log */ +{ + xfs_dir2_free_t *free; /* freespace structure */ + + free = bp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + xfs_da_log_buf(tp, bp, + (uint)((char *)&free->bests[first] - (char *)free), + (uint)((char *)&free->bests[last] - (char *)free + + sizeof(free->bests[0]) - 1)); +} + +/* + * Log header from a freespace block. + */ +static void +xfs_dir2_free_log_header( + xfs_trans_t *tp, /* transaction pointer */ + xfs_dabuf_t *bp) /* freespace buffer */ +{ + xfs_dir2_free_t *free; /* freespace structure */ + + free = bp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + xfs_da_log_buf(tp, bp, (uint)((char *)&free->hdr - (char *)free), + (uint)(sizeof(xfs_dir2_free_hdr_t) - 1)); +} + +/* + * Convert a leaf-format directory to a node-format directory. + * We need to change the magic number of the leaf block, and copy + * the freespace table out of the leaf block into its own block. + */ +int /* error */ +xfs_dir2_leaf_to_node( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *lbp) /* leaf buffer */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + xfs_dabuf_t *fbp; /* freespace buffer */ + xfs_dir2_db_t fdb; /* freespace block number */ + xfs_dir2_free_t *free; /* freespace structure */ + xfs_dir2_data_off_t *from; /* pointer to freespace entry */ + int i; /* leaf freespace index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ + xfs_mount_t *mp; /* filesystem mount point */ + int n; /* count of live freespc ents */ + xfs_dir2_data_off_t off; /* freespace entry value */ + xfs_dir2_data_off_t *to; /* pointer to freespace entry */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_b("leaf_to_node", args, lbp); + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + /* + * Add a freespace block to the directory. + */ + if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, &fdb))) { + return error; + } + ASSERT(fdb == XFS_DIR2_FREE_FIRSTDB(mp)); + /* + * Get the buffer for the new freespace block. + */ + if ((error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fdb), -1, &fbp, + XFS_DATA_FORK))) { + return error; + } + ASSERT(fbp != NULL); + free = fbp->data; + leaf = lbp->data; + ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf); + /* + * Initialize the freespace block header. + */ + INT_SET(free->hdr.magic, ARCH_CONVERT, XFS_DIR2_FREE_MAGIC); + INT_ZERO(free->hdr.firstdb, ARCH_CONVERT); + ASSERT(INT_GET(ltp->bestcount, ARCH_CONVERT) <= (uint)dp->i_d.di_size / mp->m_dirblksize); + INT_COPY(free->hdr.nvalid, ltp->bestcount, ARCH_CONVERT); + /* + * Copy freespace entries from the leaf block to the new block. + * Count active entries. + */ + for (i = n = 0, from = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT), to = free->bests; + i < INT_GET(ltp->bestcount, ARCH_CONVERT); i++, from++, to++) { + if ((off = INT_GET(*from, ARCH_CONVERT)) != NULLDATAOFF) + n++; + INT_SET(*to, ARCH_CONVERT, off); + } + INT_SET(free->hdr.nused, ARCH_CONVERT, n); + INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, XFS_DIR2_LEAFN_MAGIC); + /* + * Log everything. + */ + xfs_dir2_leaf_log_header(tp, lbp); + xfs_dir2_free_log_header(tp, fbp); + xfs_dir2_free_log_bests(tp, fbp, 0, INT_GET(free->hdr.nvalid, ARCH_CONVERT) - 1); + xfs_da_buf_done(fbp); + xfs_dir2_leafn_check(dp, lbp); + return 0; +} + +/* + * Add a leaf entry to a leaf block in a node-form directory. + * The other work necessary is done from the caller. + */ +static int /* error */ +xfs_dir2_leafn_add( + xfs_dabuf_t *bp, /* leaf buffer */ + xfs_da_args_t *args, /* operation arguments */ + int index) /* insertion pt for new entry */ +{ + int compact; /* compacting stale leaves */ + xfs_inode_t *dp; /* incore directory inode */ + int highstale; /* next stale entry */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + int lfloghigh; /* high leaf entry logging */ + int lfloglow; /* low leaf entry logging */ + int lowstale; /* previous stale entry */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_sb("leafn_add", args, index, bp); + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + leaf = bp->data; + /* + * If there are already the maximum number of leaf entries in + * the block, if there are no stale entries it won't fit. + * Caller will do a split. If there are stale entries we'll do + * a compact. + */ + if (INT_GET(leaf->hdr.count, ARCH_CONVERT) == XFS_DIR2_MAX_LEAF_ENTS(mp)) { + if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) + return XFS_ERROR(ENOSPC); + compact = INT_GET(leaf->hdr.stale, ARCH_CONVERT) > 1; + } else + compact = 0; + ASSERT(index == 0 || INT_GET(leaf->ents[index - 1].hashval, ARCH_CONVERT) <= args->hashval); + ASSERT(index == INT_GET(leaf->hdr.count, ARCH_CONVERT) || + INT_GET(leaf->ents[index].hashval, ARCH_CONVERT) >= args->hashval); + + if (args->justcheck) + return 0; + + /* + * Compact out all but one stale leaf entry. Leaves behind + * the entry closest to index. + */ + if (compact) { + xfs_dir2_leaf_compact_x1(bp, &index, &lowstale, &highstale, + &lfloglow, &lfloghigh); + } + /* + * Set impossible logging indices for this case. + */ + else if (!INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) { + lfloglow = INT_GET(leaf->hdr.count, ARCH_CONVERT); + lfloghigh = -1; + } + /* + * No stale entries, just insert a space for the new entry. + */ + if (INT_ISZERO(leaf->hdr.stale, ARCH_CONVERT)) { + lep = &leaf->ents[index]; + if (index < INT_GET(leaf->hdr.count, ARCH_CONVERT)) + ovbcopy(lep, lep + 1, + (INT_GET(leaf->hdr.count, ARCH_CONVERT) - index) * sizeof(*lep)); + lfloglow = index; + lfloghigh = INT_GET(leaf->hdr.count, ARCH_CONVERT); + INT_MOD(leaf->hdr.count, ARCH_CONVERT, +1); + } + /* + * There are stale entries. We'll use one for the new entry. + */ + else { + /* + * If we didn't do a compact then we need to figure out + * which stale entry will be used. + */ + if (compact == 0) { + /* + * Find first stale entry before our insertion point. + */ + for (lowstale = index - 1; + lowstale >= 0 && + INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) != + XFS_DIR2_NULL_DATAPTR; + lowstale--) + continue; + /* + * Find next stale entry after insertion point. + * Stop looking if the answer would be worse than + * lowstale already found. + */ + for (highstale = index; + highstale < INT_GET(leaf->hdr.count, ARCH_CONVERT) && + INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) != + XFS_DIR2_NULL_DATAPTR && + (lowstale < 0 || + index - lowstale - 1 >= highstale - index); + highstale++) + continue; + } + /* + * Using the low stale entry. + * Shift entries up toward the stale slot. + */ + if (lowstale >= 0 && + (highstale == INT_GET(leaf->hdr.count, ARCH_CONVERT) || + index - lowstale - 1 < highstale - index)) { + ASSERT(INT_GET(leaf->ents[lowstale].address, ARCH_CONVERT) == + XFS_DIR2_NULL_DATAPTR); + ASSERT(index - lowstale - 1 >= 0); + if (index - lowstale - 1 > 0) + ovbcopy(&leaf->ents[lowstale + 1], + &leaf->ents[lowstale], + (index - lowstale - 1) * sizeof(*lep)); + lep = &leaf->ents[index - 1]; + lfloglow = MIN(lowstale, lfloglow); + lfloghigh = MAX(index - 1, lfloghigh); + } + /* + * Using the high stale entry. + * Shift entries down toward the stale slot. + */ + else { + ASSERT(INT_GET(leaf->ents[highstale].address, ARCH_CONVERT) == + XFS_DIR2_NULL_DATAPTR); + ASSERT(highstale - index >= 0); + if (highstale - index > 0) + ovbcopy(&leaf->ents[index], + &leaf->ents[index + 1], + (highstale - index) * sizeof(*lep)); + lep = &leaf->ents[index]; + lfloglow = MIN(index, lfloglow); + lfloghigh = MAX(highstale, lfloghigh); + } + INT_MOD(leaf->hdr.stale, ARCH_CONVERT, -1); + } + /* + * Insert the new entry, log everything. + */ + INT_SET(lep->hashval, ARCH_CONVERT, args->hashval); + INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_DB_OFF_TO_DATAPTR(mp, args->blkno, args->index)); + xfs_dir2_leaf_log_header(tp, bp); + xfs_dir2_leaf_log_ents(tp, bp, lfloglow, lfloghigh); + xfs_dir2_leafn_check(dp, bp); + return 0; +} + +#ifdef DEBUG +/* + * Check internal consistency of a leafn block. + */ +void +xfs_dir2_leafn_check( + xfs_inode_t *dp, /* incore directory inode */ + xfs_dabuf_t *bp) /* leaf buffer */ +{ + int i; /* leaf index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_mount_t *mp; /* filesystem mount point */ + int stale; /* count of stale leaves */ + + leaf = bp->data; + mp = dp->i_mount; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) <= XFS_DIR2_MAX_LEAF_ENTS(mp)); + for (i = stale = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); i++) { + if (i + 1 < INT_GET(leaf->hdr.count, ARCH_CONVERT)) { + ASSERT(INT_GET(leaf->ents[i].hashval, ARCH_CONVERT) <= + INT_GET(leaf->ents[i + 1].hashval, ARCH_CONVERT)); + } + if (INT_GET(leaf->ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + stale++; + } + ASSERT(INT_GET(leaf->hdr.stale, ARCH_CONVERT) == stale); +} +#endif /* DEBUG */ + +/* + * Return the last hash value in the leaf. + * Stale entries are ok. + */ +xfs_dahash_t /* hash value */ +xfs_dir2_leafn_lasthash( + xfs_dabuf_t *bp, /* leaf buffer */ + int *count) /* count of entries in leaf */ +{ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + if (count) + *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + if (INT_ISZERO(leaf->hdr.count, ARCH_CONVERT)) + return 0; + return INT_GET(leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); +} + +/* + * Look up a leaf entry in a node-format leaf block. + * If this is an addname then the extrablk in state is a freespace block, + * otherwise it's a data block. + */ +int +xfs_dir2_leafn_lookup_int( + xfs_dabuf_t *bp, /* leaf buffer */ + xfs_da_args_t *args, /* operation arguments */ + int *indexp, /* out: leaf entry index */ + xfs_da_state_t *state) /* state to fill in */ +{ + xfs_dabuf_t *curbp; /* current data/free buffer */ + xfs_dir2_db_t curdb; /* current data block number */ + xfs_dir2_db_t curfdb; /* current free block number */ + xfs_dir2_data_entry_t *dep; /* data block entry */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + int fi; /* free entry index */ + xfs_dir2_free_t *free=NULL; /* free block structure */ + int index; /* leaf entry index */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + int length=0; /* length of new data entry */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_dir2_db_t newdb; /* new data block number */ + xfs_dir2_db_t newfdb; /* new free block number */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); +#ifdef __KERNEL__ + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) > 0); +#endif + xfs_dir2_leafn_check(dp, bp); + /* + * Look up the hash value in the leaf entries. + */ + index = xfs_dir2_leaf_search_hash(args, bp); + /* + * Do we have a buffer coming in? + */ + if (state->extravalid) + curbp = state->extrablk.bp; + else + curbp = NULL; + /* + * For addname, it's a free block buffer, get the block number. + */ + if (args->addname) { + curfdb = curbp ? state->extrablk.blkno : -1; + curdb = -1; + length = XFS_DIR2_DATA_ENTSIZE(args->namelen); + if ((free = (curbp ? curbp->data : NULL))) + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + } + /* + * For others, it's a data block buffer, get the block number. + */ + else { + curfdb = -1; + curdb = curbp ? state->extrablk.blkno : -1; + } + /* + * Loop over leaf entries with the right hash value. + */ + for (lep = &leaf->ents[index]; + index < INT_GET(leaf->hdr.count, ARCH_CONVERT) && INT_GET(lep->hashval, ARCH_CONVERT) == args->hashval; + lep++, index++) { + /* + * Skip stale leaf entries. + */ + if (INT_GET(lep->address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + continue; + /* + * Pull the data block number from the entry. + */ + newdb = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT)); + /* + * For addname, we're looking for a place to put the new entry. + * We want to use a data block with an entry of equal + * hash value to ours if there is one with room. + */ + if (args->addname) { + /* + * If this block isn't the data block we already have + * in hand, take a look at it. + */ + if (newdb != curdb) { + curdb = newdb; + /* + * Convert the data block to the free block + * holding its freespace information. + */ + newfdb = XFS_DIR2_DB_TO_FDB(mp, newdb); + /* + * If it's not the one we have in hand, + * read it in. + */ + if (newfdb != curfdb) { + /* + * If we had one before, drop it. + */ + if (curbp) + xfs_da_brelse(tp, curbp); + /* + * Read the free block. + */ + if ((error = xfs_da_read_buf(tp, dp, + XFS_DIR2_DB_TO_DA(mp, + newfdb), + -1, &curbp, + XFS_DATA_FORK))) { + return error; + } + curfdb = newfdb; + free = curbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == + XFS_DIR2_FREE_MAGIC); + ASSERT((INT_GET(free->hdr.firstdb, ARCH_CONVERT) % + XFS_DIR2_MAX_FREE_BESTS(mp)) == + 0); + ASSERT(INT_GET(free->hdr.firstdb, ARCH_CONVERT) <= curdb); + ASSERT(curdb < + INT_GET(free->hdr.firstdb, ARCH_CONVERT) + + INT_GET(free->hdr.nvalid, ARCH_CONVERT)); + } + /* + * Get the index for our entry. + */ + fi = XFS_DIR2_DB_TO_FDINDEX(mp, curdb); + /* + * If it has room, return it. + */ + if (INT_GET(free->bests[fi], ARCH_CONVERT) == NULLDATAOFF) { + return XFS_ERROR(EFSCORRUPTED); + } + if (INT_GET(free->bests[fi], ARCH_CONVERT) >= length) { + *indexp = index; + state->extravalid = 1; + state->extrablk.bp = curbp; + state->extrablk.blkno = curfdb; + state->extrablk.index = fi; + state->extrablk.magic = + XFS_DIR2_FREE_MAGIC; + ASSERT(args->oknoent); + return XFS_ERROR(ENOENT); + } + } + } + /* + * Not adding a new entry, so we really want to find + * the name given to us. + */ + else { + /* + * If it's a different data block, go get it. + */ + if (newdb != curdb) { + /* + * If we had a block before, drop it. + */ + if (curbp) + xfs_da_brelse(tp, curbp); + /* + * Read the data block. + */ + if ((error = + xfs_da_read_buf(tp, dp, + XFS_DIR2_DB_TO_DA(mp, newdb), -1, + &curbp, XFS_DATA_FORK))) { + return error; + } + xfs_dir2_data_check(dp, curbp); + curdb = newdb; + } + /* + * Point to the data entry. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)curbp->data + + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT))); + /* + * Compare the entry, return it if it matches. + */ + if (dep->namelen == args->namelen && + dep->name[0] == args->name[0] && + bcmp(dep->name, args->name, args->namelen) == 0) { + args->inumber = INT_GET(dep->inumber, ARCH_CONVERT); + *indexp = index; + state->extravalid = 1; + state->extrablk.bp = curbp; + state->extrablk.blkno = curdb; + state->extrablk.index = + (int)((char *)dep - + (char *)curbp->data); + state->extrablk.magic = XFS_DIR2_DATA_MAGIC; + return XFS_ERROR(EEXIST); + } + } + } + /* + * Didn't find a match. + * If we are holding a buffer, give it back in case our caller + * finds it useful. + */ + if ((state->extravalid = (curbp != NULL))) { + state->extrablk.bp = curbp; + state->extrablk.index = -1; + /* + * For addname, giving back a free block. + */ + if (args->addname) { + state->extrablk.blkno = curfdb; + state->extrablk.magic = XFS_DIR2_FREE_MAGIC; + } + /* + * For other callers, giving back a data block. + */ + else { + state->extrablk.blkno = curdb; + state->extrablk.magic = XFS_DIR2_DATA_MAGIC; + } + } + /* + * Return the final index, that will be the insertion point. + */ + *indexp = index; + ASSERT(index == INT_GET(leaf->hdr.count, ARCH_CONVERT) || args->oknoent); + return XFS_ERROR(ENOENT); +} + +/* + * Move count leaf entries from source to destination leaf. + * Log entries and headers. Stale entries are preserved. + */ +static void +xfs_dir2_leafn_moveents( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *bp_s, /* source leaf buffer */ + int start_s, /* source leaf index */ + xfs_dabuf_t *bp_d, /* destination leaf buffer */ + int start_d, /* destination leaf index */ + int count) /* count of leaves to copy */ +{ + xfs_dir2_leaf_t *leaf_d; /* destination leaf structure */ + xfs_dir2_leaf_t *leaf_s; /* source leaf structure */ + int stale; /* count stale leaves copied */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_bibii("leafn_moveents", args, bp_s, start_s, bp_d, + start_d, count); + /* + * Silently return if nothing to do. + */ + if (count == 0) { + return; + } + tp = args->trans; + leaf_s = bp_s->data; + leaf_d = bp_d->data; + /* + * If the destination index is not the end of the current + * destination leaf entries, open up a hole in the destination + * to hold the new entries. + */ + if (start_d < INT_GET(leaf_d->hdr.count, ARCH_CONVERT)) { + ovbcopy(&leaf_d->ents[start_d], &leaf_d->ents[start_d + count], + (INT_GET(leaf_d->hdr.count, ARCH_CONVERT) - start_d) * + sizeof(xfs_dir2_leaf_entry_t)); + xfs_dir2_leaf_log_ents(tp, bp_d, start_d + count, + count + INT_GET(leaf_d->hdr.count, ARCH_CONVERT) - 1); + } + /* + * If the source has stale leaves, count the ones in the copy range + * so we can update the header correctly. + */ + if (!INT_ISZERO(leaf_s->hdr.stale, ARCH_CONVERT)) { + int i; /* temp leaf index */ + + for (i = start_s, stale = 0; i < start_s + count; i++) { + if (INT_GET(leaf_s->ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) + stale++; + } + } else + stale = 0; + /* + * Copy the leaf entries from source to destination. + */ + bcopy(&leaf_s->ents[start_s], &leaf_d->ents[start_d], + count * sizeof(xfs_dir2_leaf_entry_t)); + xfs_dir2_leaf_log_ents(tp, bp_d, start_d, start_d + count - 1); + /* + * If there are source entries after the ones we copied, + * delete the ones we copied by sliding the next ones down. + */ + if (start_s + count < INT_GET(leaf_s->hdr.count, ARCH_CONVERT)) { + ovbcopy(&leaf_s->ents[start_s + count], &leaf_s->ents[start_s], + count * sizeof(xfs_dir2_leaf_entry_t)); + xfs_dir2_leaf_log_ents(tp, bp_s, start_s, start_s + count - 1); + } + /* + * Update the headers and log them. + */ + INT_MOD(leaf_s->hdr.count, ARCH_CONVERT, -(count)); + INT_MOD(leaf_s->hdr.stale, ARCH_CONVERT, -(stale)); + INT_MOD(leaf_d->hdr.count, ARCH_CONVERT, count); + INT_MOD(leaf_d->hdr.stale, ARCH_CONVERT, stale); + xfs_dir2_leaf_log_header(tp, bp_s); + xfs_dir2_leaf_log_header(tp, bp_d); + xfs_dir2_leafn_check(args->dp, bp_s); + xfs_dir2_leafn_check(args->dp, bp_d); +} + +/* + * Determine the sort order of two leaf blocks. + * Returns 1 if both are valid and leaf2 should be before leaf1, else 0. + */ +int /* sort order */ +xfs_dir2_leafn_order( + xfs_dabuf_t *leaf1_bp, /* leaf1 buffer */ + xfs_dabuf_t *leaf2_bp) /* leaf2 buffer */ +{ + xfs_dir2_leaf_t *leaf1; /* leaf1 structure */ + xfs_dir2_leaf_t *leaf2; /* leaf2 structure */ + + leaf1 = leaf1_bp->data; + leaf2 = leaf2_bp->data; + ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + if (INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0 && + INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0 && + (INT_GET(leaf2->ents[0].hashval, ARCH_CONVERT) < INT_GET(leaf1->ents[0].hashval, ARCH_CONVERT) || + INT_GET(leaf2->ents[INT_GET(leaf2->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT) < + INT_GET(leaf1->ents[INT_GET(leaf1->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT))) + return 1; + return 0; +} + +/* + * Rebalance leaf entries between two leaf blocks. + * This is actually only called when the second block is new, + * though the code deals with the general case. + * A new entry will be inserted in one of the blocks, and that + * entry is taken into account when balancing. + */ +static void +xfs_dir2_leafn_rebalance( + xfs_da_state_t *state, /* btree cursor */ + xfs_da_state_blk_t *blk1, /* first btree block */ + xfs_da_state_blk_t *blk2) /* second btree block */ +{ + xfs_da_args_t *args; /* operation arguments */ + int count; /* count (& direction) leaves */ + int isleft; /* new goes in left leaf */ + xfs_dir2_leaf_t *leaf1; /* first leaf structure */ + xfs_dir2_leaf_t *leaf2; /* second leaf structure */ + int mid; /* midpoint leaf index */ +#ifdef DEBUG + int oldstale; /* old count of stale leaves */ +#endif + int oldsum; /* old total leaf count */ + int swap; /* swapped leaf blocks */ + + args = state->args; + /* + * If the block order is wrong, swap the arguments. + */ + if ((swap = xfs_dir2_leafn_order(blk1->bp, blk2->bp))) { + xfs_da_state_blk_t *tmp; /* temp for block swap */ + + tmp = blk1; + blk1 = blk2; + blk2 = tmp; + } + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + oldsum = INT_GET(leaf1->hdr.count, ARCH_CONVERT) + INT_GET(leaf2->hdr.count, ARCH_CONVERT); +#ifdef DEBUG + oldstale = INT_GET(leaf1->hdr.stale, ARCH_CONVERT) + INT_GET(leaf2->hdr.stale, ARCH_CONVERT); +#endif + mid = oldsum >> 1; + /* + * If the old leaf count was odd then the new one will be even, + * so we need to divide the new count evenly. + */ + if (oldsum & 1) { + xfs_dahash_t midhash; /* middle entry hash value */ + + if (mid >= INT_GET(leaf1->hdr.count, ARCH_CONVERT)) + midhash = INT_GET(leaf2->ents[mid - INT_GET(leaf1->hdr.count, ARCH_CONVERT)].hashval, ARCH_CONVERT); + else + midhash = INT_GET(leaf1->ents[mid].hashval, ARCH_CONVERT); + isleft = args->hashval <= midhash; + } + /* + * If the old count is even then the new count is odd, so there's + * no preferred side for the new entry. + * Pick the left one. + */ + else + isleft = 1; + /* + * Calculate moved entry count. Positive means left-to-right, + * negative means right-to-left. Then move the entries. + */ + count = INT_GET(leaf1->hdr.count, ARCH_CONVERT) - mid + (isleft == 0); + if (count > 0) + xfs_dir2_leafn_moveents(args, blk1->bp, + INT_GET(leaf1->hdr.count, ARCH_CONVERT) - count, blk2->bp, 0, count); + else if (count < 0) + xfs_dir2_leafn_moveents(args, blk2->bp, 0, blk1->bp, + INT_GET(leaf1->hdr.count, ARCH_CONVERT), count); + ASSERT(INT_GET(leaf1->hdr.count, ARCH_CONVERT) + INT_GET(leaf2->hdr.count, ARCH_CONVERT) == oldsum); + ASSERT(INT_GET(leaf1->hdr.stale, ARCH_CONVERT) + INT_GET(leaf2->hdr.stale, ARCH_CONVERT) == oldstale); + /* + * Mark whether we're inserting into the old or new leaf. + */ + if (INT_GET(leaf1->hdr.count, ARCH_CONVERT) < INT_GET(leaf2->hdr.count, ARCH_CONVERT)) + state->inleaf = swap; + else if (INT_GET(leaf1->hdr.count, ARCH_CONVERT) > INT_GET(leaf2->hdr.count, ARCH_CONVERT)) + state->inleaf = !swap; + else + state->inleaf = + swap ^ (args->hashval < INT_GET(leaf2->ents[0].hashval, ARCH_CONVERT)); + /* + * Adjust the expected index for insertion. + */ + if (!state->inleaf) + blk2->index = blk1->index - INT_GET(leaf1->hdr.count, ARCH_CONVERT); +} + +/* + * Remove an entry from a node directory. + * This removes the leaf entry and the data entry, + * and updates the free block if necessary. + */ +static int /* error */ +xfs_dir2_leafn_remove( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *bp, /* leaf buffer */ + int index, /* leaf entry index */ + xfs_da_state_blk_t *dblk, /* data block */ + int *rval) /* resulting block needs join */ +{ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dir2_db_t db; /* data block number */ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data block entry */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry */ + int longest; /* longest data free entry */ + int off; /* data block entry offset */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log data header */ + int needscan; /* need to rescan data frees */ + xfs_trans_t *tp; /* transaction pointer */ + + xfs_dir2_trace_args_sb("leafn_remove", args, index, bp); + dp = args->dp; + tp = args->trans; + mp = dp->i_mount; + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + /* + * Point to the entry we're removing. + */ + lep = &leaf->ents[index]; + /* + * Extract the data block and offset from the entry. + */ + db = XFS_DIR2_DATAPTR_TO_DB(mp, INT_GET(lep->address, ARCH_CONVERT)); + ASSERT(dblk->blkno == db); + off = XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(lep->address, ARCH_CONVERT)); + ASSERT(dblk->index == off); + /* + * Kill the leaf entry by marking it stale. + * Log the leaf block changes. + */ + INT_MOD(leaf->hdr.stale, ARCH_CONVERT, +1); + xfs_dir2_leaf_log_header(tp, bp); + INT_SET(lep->address, ARCH_CONVERT, XFS_DIR2_NULL_DATAPTR); + xfs_dir2_leaf_log_ents(tp, bp, index, index); + /* + * Make the data entry free. Keep track of the longest freespace + * in the data block in case it changes. + */ + dbp = dblk->bp; + data = dbp->data; + dep = (xfs_dir2_data_entry_t *)((char *)data + off); + longest = INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT); + needlog = needscan = 0; + xfs_dir2_data_make_free(tp, dbp, off, + XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan); + /* + * Rescan the data block freespaces for bestfree. + * Log the data block header if needed. + */ + if (needscan) + xfs_dir2_data_freescan(mp, data, &needlog, NULL); + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + xfs_dir2_data_check(dp, dbp); + /* + * If the longest data block freespace changes, need to update + * the corresponding freeblock entry. + */ + if (longest < INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT)) { + int error; /* error return value */ + xfs_dabuf_t *fbp; /* freeblock buffer */ + xfs_dir2_db_t fdb; /* freeblock block number */ + int findex; /* index in freeblock entries */ + xfs_dir2_free_t *free; /* freeblock structure */ + int logfree; /* need to log free entry */ + + /* + * Convert the data block number to a free block, + * read in the free block. + */ + fdb = XFS_DIR2_DB_TO_FDB(mp, db); + if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fdb), + -1, &fbp, XFS_DATA_FORK))) { + return error; + } + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + ASSERT(INT_GET(free->hdr.firstdb, ARCH_CONVERT) == + XFS_DIR2_MAX_FREE_BESTS(mp) * + (fdb - XFS_DIR2_FREE_FIRSTDB(mp))); + /* + * Calculate which entry we need to fix. + */ + findex = XFS_DIR2_DB_TO_FDINDEX(mp, db); + longest = INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT); + /* + * If the data block is now empty we can get rid of it + * (usually). + */ + if (longest == mp->m_dirblksize - (uint)sizeof(data->hdr)) { + /* + * Try to punch out the data block. + */ + error = xfs_dir2_shrink_inode(args, db, dbp); + if (error == 0) { + dblk->bp = NULL; + data = NULL; + } + /* + * We can get ENOSPC if there's no space reservation. + * In this case just drop the buffer and some one else + * will eventually get rid of the empty block. + */ + else if (error == ENOSPC && args->total == 0) + xfs_da_buf_done(dbp); + else + return error; + } + /* + * If we got rid of the data block, we can eliminate that entry + * in the free block. + */ + if (data == NULL) { + /* + * One less used entry in the free table. + */ + INT_MOD(free->hdr.nused, ARCH_CONVERT, -1); + xfs_dir2_free_log_header(tp, fbp); + /* + * If this was the last entry in the table, we can + * trim the table size back. There might be other + * entries at the end referring to non-existent + * data blocks, get those too. + */ + if (findex == INT_GET(free->hdr.nvalid, ARCH_CONVERT) - 1) { + int i; /* free entry index */ + + for (i = findex - 1; + i >= 0 && INT_GET(free->bests[i], ARCH_CONVERT) == NULLDATAOFF; + i--) + continue; + INT_SET(free->hdr.nvalid, ARCH_CONVERT, i + 1); + logfree = 0; + } + /* + * Not the last entry, just punch it out. + */ + else { + INT_SET(free->bests[findex], ARCH_CONVERT, NULLDATAOFF); + logfree = 1; + } + /* + * If there are no useful entries left in the block, + * get rid of the block if we can. + */ + if (INT_GET(free->hdr.nused, ARCH_CONVERT) == 0) { + error = xfs_dir2_shrink_inode(args, fdb, fbp); + if (error == 0) { + fbp = NULL; + logfree = 0; + } else if (error != ENOSPC || args->total != 0) + return error; + /* + * It's possible to get ENOSPC if there is no + * space reservation. In this case some one + * else will eventually get rid of this block. + */ + } + } + /* + * Data block is not empty, just set the free entry to + * the new value. + */ + else { + INT_SET(free->bests[findex], ARCH_CONVERT, longest); + logfree = 1; + } + /* + * Log the free entry that changed, unless we got rid of it. + */ + if (logfree) + xfs_dir2_free_log_bests(tp, fbp, findex, findex); + /* + * Drop the buffer if we still have it. + */ + if (fbp) + xfs_da_buf_done(fbp); + } + xfs_dir2_leafn_check(dp, bp); + /* + * Return indication of whether this leaf block is emtpy enough + * to justify trying to join it with a neighbor. + */ + *rval = + ((uint)sizeof(leaf->hdr) + + (uint)sizeof(leaf->ents[0]) * + (INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT))) < + mp->m_dir_magicpct; + return 0; +} + +/* + * Split the leaf entries in the old block into old and new blocks. + */ +int /* error */ +xfs_dir2_leafn_split( + xfs_da_state_t *state, /* btree cursor */ + xfs_da_state_blk_t *oldblk, /* original block */ + xfs_da_state_blk_t *newblk) /* newly created block */ +{ + xfs_da_args_t *args; /* operation arguments */ + xfs_dablk_t blkno; /* new leaf block number */ + int error; /* error return value */ + xfs_mount_t *mp; /* filesystem mount point */ + + /* + * Allocate space for a new leaf node. + */ + args = state->args; + mp = args->dp->i_mount; + ASSERT(args != NULL); + ASSERT(oldblk->magic == XFS_DIR2_LEAFN_MAGIC); + error = xfs_da_grow_inode(args, &blkno); + if (error) { + return error; + } + /* + * Initialize the new leaf block. + */ + error = xfs_dir2_leaf_init(args, XFS_DIR2_DA_TO_DB(mp, blkno), + &newblk->bp, XFS_DIR2_LEAFN_MAGIC); + if (error) { + return error; + } + newblk->blkno = blkno; + newblk->magic = XFS_DIR2_LEAFN_MAGIC; + /* + * Rebalance the entries across the two leaves, link the new + * block into the leaves. + */ + xfs_dir2_leafn_rebalance(state, oldblk, newblk); + error = xfs_da_blk_link(state, oldblk, newblk); + if (error) { + return error; + } + /* + * Insert the new entry in the correct block. + */ + if (state->inleaf) + error = xfs_dir2_leafn_add(oldblk->bp, args, oldblk->index); + else + error = xfs_dir2_leafn_add(newblk->bp, args, newblk->index); + /* + * Update last hashval in each block since we added the name. + */ + oldblk->hashval = xfs_dir2_leafn_lasthash(oldblk->bp, NULL); + newblk->hashval = xfs_dir2_leafn_lasthash(newblk->bp, NULL); + xfs_dir2_leafn_check(args->dp, oldblk->bp); + xfs_dir2_leafn_check(args->dp, newblk->bp); + return error; +} + +/* + * Check a leaf block and its neighbors to see if the block should be + * collapsed into one or the other neighbor. Always keep the block + * with the smaller block number. + * If the current block is over 50% full, don't try to join it, return 0. + * If the block is empty, fill in the state structure and return 2. + * If it can be collapsed, fill in the state structure and return 1. + * If nothing can be done, return 0. + */ +int /* error */ +xfs_dir2_leafn_toosmall( + xfs_da_state_t *state, /* btree cursor */ + int *action) /* resulting action to take */ +{ + xfs_da_state_blk_t *blk; /* leaf block */ + xfs_dablk_t blkno; /* leaf block number */ + xfs_dabuf_t *bp; /* leaf buffer */ + int bytes; /* bytes in use */ + int count; /* leaf live entry count */ + int error; /* error return value */ + int forward; /* sibling block direction */ + int i; /* sibling counter */ + xfs_da_blkinfo_t *info; /* leaf block header */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + int rval; /* result from path_shift */ + + /* + * Check for the degenerate case of the block being over 50% full. + * If so, it's not worth even looking to see if we might be able + * to coalesce with a sibling. + */ + blk = &state->path.blk[state->path.active - 1]; + info = blk->bp->data; + ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + leaf = (xfs_dir2_leaf_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT); + bytes = (uint)sizeof(leaf->hdr) + count * (uint)sizeof(leaf->ents[0]); + if (bytes > (state->blocksize >> 1)) { + /* + * Blk over 50%, don't try to join. + */ + *action = 0; + return 0; + } + /* + * Check for the degenerate case of the block being empty. + * If the block is empty, we'll simply delete it, no need to + * coalesce it with a sibling block. We choose (arbitrarily) + * to merge with the forward block unless it is NULL. + */ + if (count == 0) { + /* + * Make altpath point to the block we want to keep and + * path point to the block we want to drop (this one). + */ + forward = !INT_ISZERO(info->forw, ARCH_CONVERT); + bcopy(&state->path, &state->altpath, sizeof(state->path)); + error = xfs_da_path_shift(state, &state->altpath, forward, 0, + &rval); + if (error) + return error; + *action = rval ? 2 : 0; + return 0; + } + /* + * Examine each sibling block to see if we can coalesce with + * at least 25% free space to spare. We need to figure out + * whether to merge with the forward or the backward block. + * We prefer coalescing with the lower numbered sibling so as + * to shrink a directory over time. + */ + forward = INT_GET(info->forw, ARCH_CONVERT) < INT_GET(info->back, ARCH_CONVERT); + for (i = 0, bp = NULL; i < 2; forward = !forward, i++) { + blkno = forward ?INT_GET( info->forw, ARCH_CONVERT) : INT_GET(info->back, ARCH_CONVERT); + if (blkno == 0) + continue; + /* + * Read the sibling leaf block. + */ + if ((error = + xfs_da_read_buf(state->args->trans, state->args->dp, blkno, + -1, &bp, XFS_DATA_FORK))) { + return error; + } + ASSERT(bp != NULL); + /* + * Count bytes in the two blocks combined. + */ + leaf = (xfs_dir2_leaf_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT); + bytes = state->blocksize - (state->blocksize >> 2); + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + count += INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT); + bytes -= count * (uint)sizeof(leaf->ents[0]); + /* + * Fits with at least 25% to spare. + */ + if (bytes >= 0) + break; + xfs_da_brelse(state->args->trans, bp); + } + /* + * Didn't like either block, give up. + */ + if (i >= 2) { + *action = 0; + return 0; + } + /* + * Done with the sibling leaf block here, drop the dabuf + * so path_shift can get it. + */ + xfs_da_buf_done(bp); + /* + * Make altpath point to the block we want to keep (the lower + * numbered block) and path point to the block we want to drop. + */ + bcopy(&state->path, &state->altpath, sizeof(state->path)); + if (blkno < blk->blkno) + error = xfs_da_path_shift(state, &state->altpath, forward, 0, + &rval); + else + error = xfs_da_path_shift(state, &state->path, forward, 0, + &rval); + if (error) { + return error; + } + *action = rval ? 0 : 1; + return 0; +} + +/* + * Move all the leaf entries from drop_blk to save_blk. + * This is done as part of a join operation. + */ +void +xfs_dir2_leafn_unbalance( + xfs_da_state_t *state, /* cursor */ + xfs_da_state_blk_t *drop_blk, /* dead block */ + xfs_da_state_blk_t *save_blk) /* surviving block */ +{ + xfs_da_args_t *args; /* operation arguments */ + xfs_dir2_leaf_t *drop_leaf; /* dead leaf structure */ + xfs_dir2_leaf_t *save_leaf; /* surviving leaf structure */ + + args = state->args; + ASSERT(drop_blk->magic == XFS_DIR2_LEAFN_MAGIC); + ASSERT(save_blk->magic == XFS_DIR2_LEAFN_MAGIC); + drop_leaf = drop_blk->bp->data; + save_leaf = save_blk->bp->data; + ASSERT(INT_GET(drop_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + ASSERT(INT_GET(save_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC); + /* + * If there are any stale leaf entries, take this opportunity + * to purge them. + */ + if (INT_GET(drop_leaf->hdr.stale, ARCH_CONVERT)) + xfs_dir2_leaf_compact(args, drop_blk->bp); + if (INT_GET(save_leaf->hdr.stale, ARCH_CONVERT)) + xfs_dir2_leaf_compact(args, save_blk->bp); + /* + * Move the entries from drop to the appropriate end of save. + */ + drop_blk->hashval = INT_GET(drop_leaf->ents[INT_GET(drop_leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); + if (xfs_dir2_leafn_order(save_blk->bp, drop_blk->bp)) + xfs_dir2_leafn_moveents(args, drop_blk->bp, 0, save_blk->bp, 0, + INT_GET(drop_leaf->hdr.count, ARCH_CONVERT)); + else + xfs_dir2_leafn_moveents(args, drop_blk->bp, 0, save_blk->bp, + INT_GET(save_leaf->hdr.count, ARCH_CONVERT), INT_GET(drop_leaf->hdr.count, ARCH_CONVERT)); + save_blk->hashval = INT_GET(save_leaf->ents[INT_GET(save_leaf->hdr.count, ARCH_CONVERT) - 1].hashval, ARCH_CONVERT); + xfs_dir2_leafn_check(args->dp, save_blk->bp); +} + +/* + * Top-level node form directory addname routine. + */ +int /* error */ +xfs_dir2_node_addname( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_da_state_blk_t *blk; /* leaf block for insert */ + int error; /* error return value */ + int rval; /* sub-return value */ + xfs_da_state_t *state; /* btree cursor */ + + xfs_dir2_trace_args("node_addname", args); + /* + * Allocate and initialize the state (btree cursor). + */ + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_dirblksize; + /* + * Look up the name. We're not supposed to find it, but + * this gives us the insertion point. + */ + error = xfs_da_node_lookup_int(state, &rval); + if (error) + rval = error; + if (rval != ENOENT) { + goto done; + } + /* + * Add the data entry to a data block. + * Extravalid is set to a freeblock found by lookup. + */ + rval = xfs_dir2_node_addname_int(args, + state->extravalid ? &state->extrablk : NULL); + if (rval) { + goto done; + } + blk = &state->path.blk[state->path.active - 1]; + ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); + /* + * Add the new leaf entry. + */ + rval = xfs_dir2_leafn_add(blk->bp, args, blk->index); + if (rval == 0) { + /* + * It worked, fix the hash values up the btree. + */ + if (!args->justcheck) + xfs_da_fixhashpath(state, &state->path); + } else { + /* + * It didn't work, we need to split the leaf block. + */ + if (args->total == 0) { + ASSERT(rval == ENOSPC); + goto done; + } + /* + * Split the leaf block and insert the new entry. + */ + rval = xfs_da_split(state); + } +done: + xfs_da_state_free(state); + return rval; +} + +/* + * Add the data entry for a node-format directory name addition. + * The leaf entry is added in xfs_dir2_leafn_add. + * We may enter with a freespace block that the lookup found. + */ +static int /* error */ +xfs_dir2_node_addname_int( + xfs_da_args_t *args, /* operation arguments */ + xfs_da_state_blk_t *fblk) /* optional freespace block */ +{ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dir2_db_t dbno; /* data block number */ + xfs_dabuf_t *dbp; /* data block buffer */ + xfs_dir2_data_entry_t *dep; /* data entry pointer */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_data_unused_t *dup; /* data unused entry pointer */ + int error; /* error return value */ + xfs_dir2_db_t fbno; /* freespace block number */ + xfs_dabuf_t *fbp; /* freespace buffer */ + int findex; /* freespace entry index */ + xfs_dir2_db_t foundbno=0; /* found freespace block no */ + int foundindex=0; /* found freespace entry idx */ + xfs_dir2_free_t *free=NULL; /* freespace block structure */ + xfs_dir2_db_t ifbno; /* initial freespace block no */ + xfs_dir2_db_t lastfbno=0; /* highest freespace block no */ + int length; /* length of the new entry */ + int logfree; /* need to log free entry */ + xfs_mount_t *mp; /* filesystem mount point */ + int needlog; /* need to log data header */ + int needscan; /* need to rescan data frees */ + xfs_dir2_data_off_t *tagp; /* data entry tag pointer */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + length = XFS_DIR2_DATA_ENTSIZE(args->namelen); + /* + * If we came in with a freespace block that means that lookup + * found an entry with our hash value. This is the freespace + * block for that data entry. + */ + if (fblk) { + fbp = fblk->bp; + /* + * Remember initial freespace block number. + */ + ifbno = fblk->blkno; + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + findex = fblk->index; + /* + * This means the free entry showed that the data block had + * space for our entry, so we remembered it. + * Use that data block. + */ + if (findex >= 0) { + ASSERT(findex < INT_GET(free->hdr.nvalid, ARCH_CONVERT)); + ASSERT(INT_GET(free->bests[findex], ARCH_CONVERT) != NULLDATAOFF); + ASSERT(INT_GET(free->bests[findex], ARCH_CONVERT) >= length); + dbno = INT_GET(free->hdr.firstdb, ARCH_CONVERT) + findex; + } + /* + * The data block looked at didn't have enough room. + * We'll start at the beginning of the freespace entries. + */ + else { + dbno = -1; + findex = 0; + } + } + /* + * Didn't come in with a freespace block, so don't have a data block. + */ + else { + ifbno = dbno = -1; + fbp = NULL; + findex = 0; + } + /* + * If we don't have a data block yet, we're going to scan the + * freespace blocks looking for one. Figure out what the + * highest freespace block number is. + */ + if (dbno == -1) { + xfs_fileoff_t fo; /* freespace block number */ + + if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK))) + return error; + lastfbno = XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)fo); + fbno = ifbno; + foundindex = -1; + } + /* + * While we haven't identified a data block, search the freeblock + * data for a good data block. If we find a null freeblock entry, + * indicating a hole in the data blocks, remember that. + */ + while (dbno == -1) { + /* + * If we don't have a freeblock in hand, get the next one. + */ + if (fbp == NULL) { + /* + * Happens the first time through unless lookup gave + * us a freespace block to start with. + */ + if (++fbno == 0) + fbno = XFS_DIR2_FREE_FIRSTDB(mp); + /* + * If it's ifbno we already looked at it. + */ + if (fbno == ifbno) + fbno++; + /* + * If it's off the end we're done. + */ + if (fbno >= lastfbno) + break; + /* + * Read the block. There can be holes in the + * freespace blocks, so this might not succeed. + * This should be really rare, so there's no reason + * to avoid it. + */ + if ((error = xfs_da_read_buf(tp, dp, + XFS_DIR2_DB_TO_DA(mp, fbno), -1, &fbp, + XFS_DATA_FORK))) { + return error; + } + if (fbp == NULL) { + continue; + } + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + findex = 0; + } + /* + * Look at the current free entry. Is it good enough? + */ + if (INT_GET(free->bests[findex], ARCH_CONVERT) != NULLDATAOFF && + INT_GET(free->bests[findex], ARCH_CONVERT) >= length) + dbno = INT_GET(free->hdr.firstdb, ARCH_CONVERT) + findex; + else { + /* + * If we haven't found an empty entry yet, and this + * one is empty, remember this slot. + */ + if (foundindex == -1 && + INT_GET(free->bests[findex], ARCH_CONVERT) == NULLDATAOFF) { + foundindex = findex; + foundbno = fbno; + } + /* + * Are we done with the freeblock? + */ + if (++findex == INT_GET(free->hdr.nvalid, ARCH_CONVERT)) { + /* + * If there is space left in this freeblock, + * and we don't have an empty entry yet, + * remember this slot. + */ + if (foundindex == -1 && + findex < XFS_DIR2_MAX_FREE_BESTS(mp)) { + foundindex = findex; + foundbno = fbno; + } + /* + * Drop the block. + */ + xfs_da_brelse(tp, fbp); + fbp = NULL; + if (fblk && fblk->bp) + fblk->bp = NULL; + } + } + } + /* + * If we don't have a data block, and there's no free slot in a + * freeblock, we need to add a new freeblock. + */ + if (dbno == -1 && foundindex == -1) { + /* + * Not allowed to allocate, so return failure. + */ + if (args->justcheck || args->total == 0) { + return XFS_ERROR(ENOSPC); + } + /* + * Add the new freeblock. + */ + if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, + &fbno))) { + return error; + } + /* + * Get a buffer for the new block. + */ + if ((error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fbno), + -1, &fbp, XFS_DATA_FORK))) { + return error; + } + ASSERT(fbp != NULL); + /* + * Initialize the new block to be empty, and remember + * its first slot as our empty slot. + */ + free = fbp->data; + INT_SET(free->hdr.magic, ARCH_CONVERT, XFS_DIR2_FREE_MAGIC); + INT_SET(free->hdr.firstdb, ARCH_CONVERT, (fbno - XFS_DIR2_FREE_FIRSTDB(mp)) * + XFS_DIR2_MAX_FREE_BESTS(mp)); + INT_ZERO(free->hdr.nused, ARCH_CONVERT); + INT_ZERO(free->hdr.nvalid, ARCH_CONVERT); + foundindex = 0; + foundbno = fbno; + } + /* + * If we don't have a data block, and we don't have a freeblock buffer + * in hand (we dropped the one with the free slot in it), + * go read the freeblock again. + */ + if (dbno == -1 && fbp == NULL) { + /* + * We're going to use the empty slot we found before. + */ + findex = foundindex; + fbno = foundbno; + if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fbno), + -1, &fbp, XFS_DATA_FORK))) { + return error; + } + ASSERT(fbp != NULL); + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + } + /* + * If we don't have a data block, we need to allocate one and make + * the freespace entries refer to it. + */ + if (dbno == -1) { + /* + * Not allowed to allocate, return failure. + */ + if (args->justcheck || args->total == 0) { + /* + * Drop the freespace buffer unless it came from our + * caller. + */ + if (fblk == NULL || fblk->bp == NULL) + xfs_da_buf_done(fbp); + return XFS_ERROR(ENOSPC); + } + /* + * Allocate and initialize the new data block. + */ + if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, + &dbno)) || + (error = xfs_dir2_data_init(args, dbno, &dbp))) { + /* + * Drop the freespace buffer unless it came from our + * caller. + */ + if (fblk == NULL || fblk->bp == NULL) + xfs_da_buf_done(fbp); + return error; + } + /* + * If the freespace entry for this data block is not in the + * freespace block we have in hand, drop the one we have + * and get the right one. + */ + if (XFS_DIR2_DB_TO_FDB(mp, dbno) != fbno) { + xfs_da_brelse(tp, fbp); + if (fblk && fblk->bp) + fblk->bp = NULL; + fbno = XFS_DIR2_DB_TO_FDB(mp, dbno); + if ((error = xfs_da_read_buf(tp, dp, + XFS_DIR2_DB_TO_DA(mp, fbno), -1, &fbp, + XFS_DATA_FORK))) { + xfs_da_buf_done(dbp); + return error; + } + ASSERT(fbp != NULL); + free = fbp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + } + /* + * Set the freespace block index from the data block number. + */ + findex = XFS_DIR2_DB_TO_FDINDEX(mp, dbno); + /* + * If it's after the end of the current entries in the + * freespace block, extend that table. + */ + if (findex >= INT_GET(free->hdr.nvalid, ARCH_CONVERT)) { + ASSERT(findex < XFS_DIR2_MAX_FREE_BESTS(mp)); + INT_SET(free->hdr.nvalid, ARCH_CONVERT, findex + 1); + /* + * Tag new entry so nused will go up. + */ + INT_SET(free->bests[findex], ARCH_CONVERT, NULLDATAOFF); + } + /* + * If this entry was for an empty data block + * (this should always be true) then update the header. + */ + if (INT_GET(free->bests[findex], ARCH_CONVERT) == NULLDATAOFF) { + INT_MOD(free->hdr.nused, ARCH_CONVERT, +1); + xfs_dir2_free_log_header(tp, fbp); + } + /* + * Update the real value in the table. + * We haven't allocated the data entry yet so this will + * change again. + */ + data = dbp->data; + INT_COPY(free->bests[findex], data->hdr.bestfree[0].length, ARCH_CONVERT); + logfree = 1; + } + /* + * We had a data block so we don't have to make a new one. + */ + else { + /* + * If just checking, we succeeded. + */ + if (args->justcheck) { + if (fblk == NULL || fblk->bp == NULL) + xfs_da_buf_done(fbp); + return 0; + } + /* + * Read the data block in. + */ + if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, dbno), + -1, &dbp, XFS_DATA_FORK))) { + if (fblk == NULL || fblk->bp == NULL) + xfs_da_buf_done(fbp); + return error; + } + data = dbp->data; + logfree = 0; + } + ASSERT(INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT) >= length); + /* + * Point to the existing unused space. + */ + dup = (xfs_dir2_data_unused_t *) + ((char *)data + INT_GET(data->hdr.bestfree[0].offset, ARCH_CONVERT)); + needscan = needlog = 0; + /* + * Mark the first part of the unused space, inuse for us. + */ + xfs_dir2_data_use_free(tp, dbp, dup, + (xfs_dir2_data_aoff_t)((char *)dup - (char *)data), length, + &needlog, &needscan); + /* + * Fill in the new entry and log it. + */ + dep = (xfs_dir2_data_entry_t *)dup; + INT_SET(dep->inumber, ARCH_CONVERT, args->inumber); + dep->namelen = args->namelen; + bcopy(args->name, dep->name, dep->namelen); + tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep); + INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)data)); + xfs_dir2_data_log_entry(tp, dbp, dep); + /* + * Rescan the block for bestfree if needed. + */ + if (needscan) + xfs_dir2_data_freescan(mp, data, &needlog, NULL); + /* + * Log the data block header if needed. + */ + if (needlog) + xfs_dir2_data_log_header(tp, dbp); + /* + * If the freespace entry is now wrong, update it. + */ + if (INT_GET(free->bests[findex], ARCH_CONVERT) != INT_GET(data->hdr.bestfree[0].length, ARCH_CONVERT)) { + INT_COPY(free->bests[findex], data->hdr.bestfree[0].length, ARCH_CONVERT); + logfree = 1; + } + /* + * Log the freespace entry if needed. + */ + if (logfree) + xfs_dir2_free_log_bests(tp, fbp, findex, findex); + /* + * If the caller didn't hand us the freespace block, drop it. + */ + if (fblk == NULL || fblk->bp == NULL) + xfs_da_buf_done(fbp); + /* + * Return the data block and offset in args, then drop the data block. + */ + args->blkno = (xfs_dablk_t)dbno; + args->index = INT_GET(*tagp, ARCH_CONVERT); + xfs_da_buf_done(dbp); + return 0; +} + +/* + * Lookup an entry in a node-format directory. + * All the real work happens in xfs_da_node_lookup_int. + * The only real output is the inode number of the entry. + */ +int /* error */ +xfs_dir2_node_lookup( + xfs_da_args_t *args) /* operation arguments */ +{ + int error; /* error return value */ + int i; /* btree level */ + int rval; /* operation return value */ + xfs_da_state_t *state; /* btree cursor */ + + xfs_dir2_trace_args("node_lookup", args); + /* + * Allocate and initialize the btree cursor. + */ + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_dirblksize; + /* + * Fill in the path to the entry in the cursor. + */ + error = xfs_da_node_lookup_int(state, &rval); + if (error) + rval = error; + /* + * Release the btree blocks and leaf block. + */ + for (i = 0; i < state->path.active; i++) { + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + /* + * Release the data block if we have it. + */ + if (state->extravalid && state->extrablk.bp) { + xfs_da_brelse(args->trans, state->extrablk.bp); + state->extrablk.bp = NULL; + } + xfs_da_state_free(state); + return rval; +} + +/* + * Remove an entry from a node-format directory. + */ +int /* error */ +xfs_dir2_node_removename( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_da_state_blk_t *blk; /* leaf block */ + int error; /* error return value */ + int rval; /* operation return value */ + xfs_da_state_t *state; /* btree cursor */ + + xfs_dir2_trace_args("node_removename", args); + /* + * Allocate and initialize the btree cursor. + */ + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_dirblksize; + /* + * Look up the entry we're deleting, set up the cursor. + */ + error = xfs_da_node_lookup_int(state, &rval); + if (error) { + rval = error; + } + /* + * Didn't find it, upper layer screwed up. + */ + if (rval != EEXIST) { + xfs_da_state_free(state); + return rval; + } + blk = &state->path.blk[state->path.active - 1]; + ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); + ASSERT(state->extravalid); + /* + * Remove the leaf and data entries. + * Extrablk refers to the data block. + */ + error = xfs_dir2_leafn_remove(args, blk->bp, blk->index, + &state->extrablk, &rval); + if (error) { + return error; + } + /* + * Fix the hash values up the btree. + */ + xfs_da_fixhashpath(state, &state->path); + /* + * If we need to join leaf blocks, do it. + */ + if (rval && state->path.active > 1) + error = xfs_da_join(state); + /* + * If no errors so far, try conversion to leaf format. + */ + if (!error) + error = xfs_dir2_node_to_leaf(state); + xfs_da_state_free(state); + return error; +} + +/* + * Replace an entry's inode number in a node-format directory. + */ +int /* error */ +xfs_dir2_node_replace( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_da_state_blk_t *blk; /* leaf block */ + xfs_dir2_data_t *data; /* data block structure */ + xfs_dir2_data_entry_t *dep; /* data entry changed */ + int error; /* error return value */ + int i; /* btree level */ + xfs_ino_t inum; /* new inode number */ + xfs_dir2_leaf_t *leaf; /* leaf structure */ + xfs_dir2_leaf_entry_t *lep; /* leaf entry being changed */ + int rval; /* internal return value */ + xfs_da_state_t *state; /* btree cursor */ + + xfs_dir2_trace_args("node_replace", args); + /* + * Allocate and initialize the btree cursor. + */ + state = xfs_da_state_alloc(); + state->args = args; + state->mp = args->dp->i_mount; + state->blocksize = state->mp->m_dirblksize; + inum = args->inumber; + /* + * Lookup the entry to change in the btree. + */ + error = xfs_da_node_lookup_int(state, &rval); + if (error) { + rval = error; + } + /* + * It should be found, since the vnodeops layer has looked it up + * and locked it. But paranoia is good. + */ + if (rval == EEXIST) { + /* + * Find the leaf entry. + */ + blk = &state->path.blk[state->path.active - 1]; + ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); + leaf = blk->bp->data; + lep = &leaf->ents[blk->index]; + ASSERT(state->extravalid); + /* + * Point to the data entry. + */ + data = state->extrablk.bp->data; + ASSERT(INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC); + dep = (xfs_dir2_data_entry_t *) + ((char *)data + + XFS_DIR2_DATAPTR_TO_OFF(state->mp, INT_GET(lep->address, ARCH_CONVERT))); + ASSERT(inum != INT_GET(dep->inumber, ARCH_CONVERT)); + /* + * Fill in the new inode number and log the entry. + */ + INT_SET(dep->inumber, ARCH_CONVERT, inum); + xfs_dir2_data_log_entry(args->trans, state->extrablk.bp, dep); + rval = 0; + } + /* + * Didn't find it, and we're holding a data block. Drop it. + */ + else if (state->extravalid) { + xfs_da_brelse(args->trans, state->extrablk.bp); + state->extrablk.bp = NULL; + } + /* + * Release all the buffers in the cursor. + */ + for (i = 0; i < state->path.active; i++) { + xfs_da_brelse(args->trans, state->path.blk[i].bp); + state->path.blk[i].bp = NULL; + } + xfs_da_state_free(state); + return rval; +} + +/* + * Trim off a trailing empty freespace block. + * Return (in rvalp) 1 if we did it, 0 if not. + */ +int /* error */ +xfs_dir2_node_trim_free( + xfs_da_args_t *args, /* operation arguments */ + xfs_fileoff_t fo, /* free block number */ + int *rvalp) /* out: did something */ +{ + xfs_dabuf_t *bp; /* freespace buffer */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return code */ + xfs_dir2_free_t *free; /* freespace structure */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_trans_t *tp; /* transaction pointer */ + + dp = args->dp; + mp = dp->i_mount; + tp = args->trans; + /* + * Read the freespace block. + */ + if ((error = xfs_da_read_buf(tp, dp, (xfs_dablk_t)fo, -1, &bp, + XFS_DATA_FORK))) { + return error; + } + free = bp->data; + ASSERT(INT_GET(free->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC); + /* + * If there are used entries, there's nothing to do. + */ + if (INT_GET(free->hdr.nused, ARCH_CONVERT) > 0) { + xfs_da_brelse(tp, bp); + *rvalp = 0; + return 0; + } + /* + * Blow the block away. + */ + if ((error = + xfs_dir2_shrink_inode(args, XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)fo), + bp))) { + /* + * Can't fail with ENOSPC since that only happens with no + * space reservation, when breaking up an extent into two + * pieces. This is the last block of an extent. + */ + ASSERT(error != ENOSPC); + xfs_da_brelse(tp, bp); + return error; + } + /* + * Return that we succeeded. + */ + *rvalp = 1; + return 0; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir2_node.h linux-2.4-xfs/linux/fs/xfs/xfs_dir2_node.h --- linux-2.4.7/linux/fs/xfs/xfs_dir2_node.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir2_node.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_NODE_H__ +#define __XFS_DIR2_NODE_H__ + +/* + * Directory version 2, btree node format structures + */ + +struct dirent; +struct uio; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_da_state; +struct xfs_da_state_blk; +struct xfs_inode; +struct xfs_trans; + +/* + * Constants. + */ + +/* + * Offset of the freespace index. + */ +#define XFS_DIR2_FREE_SPACE 2 +#define XFS_DIR2_FREE_OFFSET (XFS_DIR2_FREE_SPACE * XFS_DIR2_SPACE_SIZE) +#define XFS_DIR2_FREE_FIRSTDB(mp) \ + XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_FREE_OFFSET) + +#define XFS_DIR2_FREE_MAGIC 0x58443246 /* XD2F */ + +/* + * Structures. + */ +typedef struct xfs_dir2_free_hdr { + __uint32_t magic; /* XFS_DIR2_FREE_MAGIC */ + __int32_t firstdb; /* db of first entry */ + __int32_t nvalid; /* count of valid entries */ + __int32_t nused; /* count of used entries */ +} xfs_dir2_free_hdr_t; + +typedef struct xfs_dir2_free { + xfs_dir2_free_hdr_t hdr; /* block header */ + xfs_dir2_data_off_t bests[1]; /* best free counts */ + /* unused entries are -1 */ +} xfs_dir2_free_t; +#define XFS_DIR2_MAX_FREE_BESTS(mp) \ + (((mp)->m_dirblksize - (uint)sizeof(xfs_dir2_free_hdr_t)) / \ + (uint)sizeof(xfs_dir2_data_off_t)) + +/* + * Macros. + */ + +/* + * Convert data space db to the corresponding free db. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DB_TO_FDB) +xfs_dir2_db_t +xfs_dir2_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db); +#define XFS_DIR2_DB_TO_FDB(mp,db) xfs_dir2_db_to_fdb(mp, db) +#else +#define XFS_DIR2_DB_TO_FDB(mp,db) \ + (XFS_DIR2_FREE_FIRSTDB(mp) + (db) / XFS_DIR2_MAX_FREE_BESTS(mp)) +#endif + +/* + * Convert data space db to the corresponding index in a free db. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_DB_TO_FDINDEX) +int +xfs_dir2_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db); +#define XFS_DIR2_DB_TO_FDINDEX(mp,db) xfs_dir2_db_to_fdindex(mp, db) +#else +#define XFS_DIR2_DB_TO_FDINDEX(mp,db) ((db) % XFS_DIR2_MAX_FREE_BESTS(mp)) +#endif + +/* + * Functions. + */ + +extern void + xfs_dir2_free_log_bests(struct xfs_trans *tp, struct xfs_dabuf *bp, + int first, int last); + +extern int + xfs_dir2_leaf_to_node(struct xfs_da_args *args, struct xfs_dabuf *lbp); + +extern xfs_dahash_t + xfs_dir2_leafn_lasthash(struct xfs_dabuf *bp, int *count); + +extern int + xfs_dir2_leafn_lookup_int(struct xfs_dabuf *bp, + struct xfs_da_args *args, int *indexp, + struct xfs_da_state *state); + +extern int + xfs_dir2_leafn_order(struct xfs_dabuf *leaf1_bp, + struct xfs_dabuf *leaf2_bp); + +extern int + xfs_dir2_leafn_split(struct xfs_da_state *state, + struct xfs_da_state_blk *oldblk, + struct xfs_da_state_blk *newblk); + +extern int + xfs_dir2_leafn_toosmall(struct xfs_da_state *state, int *action); + +extern void + xfs_dir2_leafn_unbalance(struct xfs_da_state *state, + struct xfs_da_state_blk *drop_blk, + struct xfs_da_state_blk *save_blk); + +extern int + xfs_dir2_node_addname(struct xfs_da_args *args); + +extern int + xfs_dir2_node_lookup(struct xfs_da_args *args); + +extern int + xfs_dir2_node_removename(struct xfs_da_args *args); + +extern int + xfs_dir2_node_replace(struct xfs_da_args *args); + +extern int + xfs_dir2_node_trim_free(struct xfs_da_args *args, xfs_fileoff_t fo, + int *rvalp); + +#endif /* __XFS_DIR2_NODE_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir2_sf.c linux-2.4-xfs/linux/fs/xfs/xfs_dir2_sf.c --- linux-2.4.7/linux/fs/xfs/xfs_dir2_sf.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir2_sf.c Mon Apr 23 14:52:01 2001 @@ -0,0 +1,1296 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_sf.c + * Shortform directory implementation for v2 directories. + */ + +#include + +/* + * Prototypes for internal functions. + */ +static void xfs_dir2_sf_addname_easy(xfs_da_args_t *args, + xfs_dir2_sf_entry_t *sfep, + xfs_dir2_data_aoff_t offset, + int new_isize); +static void xfs_dir2_sf_addname_hard(xfs_da_args_t *args, int objchange, + int new_isize); +static int xfs_dir2_sf_addname_pick(xfs_da_args_t *args, int objchange, + xfs_dir2_sf_entry_t **sfepp, + xfs_dir2_data_aoff_t *offsetp); +#ifdef DEBUG +static void xfs_dir2_sf_check(xfs_da_args_t *args); +#else +#define xfs_dir2_sf_check(args) +#endif /* DEBUG */ +#if XFS_BIG_FILESYSTEMS +static void xfs_dir2_sf_toino4(xfs_da_args_t *args); +static void xfs_dir2_sf_toino8(xfs_da_args_t *args); +#endif /* XFS_BIG_FILESYSTEMS */ + +/* + * Given a block directory (dp/block), calculate its size as a shortform (sf) + * directory and a header for the sf directory, if it will fit it the + * space currently present in the inode. If it won't fit, the output + * size is too big (but not accurate). + */ +int /* size for sf form */ +xfs_dir2_block_sfsize( + xfs_inode_t *dp, /* incore inode pointer */ + xfs_dir2_block_t *block, /* block directory data */ + xfs_dir2_sf_hdr_t *sfhp) /* output: header for sf form */ +{ + xfs_dir2_dataptr_t addr; /* data entry address */ + xfs_dir2_leaf_entry_t *blp; /* leaf area of the block */ + xfs_dir2_block_tail_t *btp; /* tail area of the block */ + int count; /* shortform entry count */ + xfs_dir2_data_entry_t *dep; /* data entry in the block */ + int i; /* block entry index */ + int i8count; /* count of big-inode entries */ + int isdot; /* entry is "." */ + int isdotdot; /* entry is ".." */ + xfs_mount_t *mp; /* mount structure pointer */ + int namelen; /* total name bytes */ + xfs_ino_t parent; /* parent inode number */ + int size=0; /* total computed size */ + + mp = dp->i_mount; + + count = i8count = namelen = 0; + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + + /* + * Iterate over the block's data entries by using the leaf pointers. + */ + for (i = 0; i < INT_GET(btp->count, ARCH_CONVERT); i++) { + if ((addr = INT_GET(blp[i].address, ARCH_CONVERT)) == XFS_DIR2_NULL_DATAPTR) + continue; + /* + * Calculate the pointer to the entry at hand. + */ + dep = (xfs_dir2_data_entry_t *) + ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, addr)); + /* + * Detect . and .., so we can special-case them. + * . is not included in sf directories. + * .. is included by just the parent inode number. + */ + isdot = dep->namelen == 1 && dep->name[0] == '.'; + isdotdot = + dep->namelen == 2 && + dep->name[0] == '.' && dep->name[1] == '.'; +#if XFS_BIG_FILESYSTEMS + if (!isdot) + i8count += INT_GET(dep->inumber, ARCH_CONVERT) > XFS_DIR2_MAX_SHORT_INUM; +#endif + if (!isdot && !isdotdot) { + count++; + namelen += dep->namelen; + } else if (isdotdot) + parent = INT_GET(dep->inumber, ARCH_CONVERT); + /* + * Calculate the new size, see if we should give up yet. + */ + size = XFS_DIR2_SF_HDR_SIZE(i8count) + /* header */ + count + /* namelen */ + count * (uint)sizeof(xfs_dir2_sf_off_t) + /* offset */ + namelen + /* name */ + (i8count ? /* inumber */ + (uint)sizeof(xfs_dir2_ino8_t) * count : + (uint)sizeof(xfs_dir2_ino4_t) * count); + if (size > XFS_IFORK_DSIZE(dp)) + return size; /* size value is a failure */ + } + /* + * Create the output header, if it worked. + */ + sfhp->count = count; + sfhp->i8count = i8count; + XFS_DIR2_SF_PUT_INUMBER_ARCH((xfs_dir2_sf_t *)sfhp, &parent, &sfhp->parent, ARCH_CONVERT); + return size; +} + +/* + * Convert a block format directory to shortform. + * Caller has already checked that it will fit, and built us a header. + */ +int /* error */ +xfs_dir2_block_to_sf( + xfs_da_args_t *args, /* operation arguments */ + xfs_dabuf_t *bp, /* block buffer */ + int size, /* shortform directory size */ + xfs_dir2_sf_hdr_t *sfhp) /* shortform directory hdr */ +{ + xfs_dir2_block_t *block; /* block structure */ + xfs_dir2_block_tail_t *btp; /* block tail pointer */ + xfs_dir2_data_entry_t *dep; /* data entry pointer */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_data_unused_t *dup; /* unused data pointer */ + char *endptr; /* end of data entries */ + int error; /* error return value */ + int logflags; /* inode logging flags */ + xfs_mount_t *mp; /* filesystem mount point */ + char *ptr; /* current data pointer */ + xfs_dir2_sf_entry_t *sfep; /* shortform entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + xfs_ino_t temp; + + xfs_dir2_trace_args_sb("block_to_sf", args, size, bp); + dp = args->dp; + mp = dp->i_mount; + + /* + * Make a copy of the block data, so we can shrink the inode + * and add local data. + */ + block = kmem_alloc(mp->m_dirblksize, KM_SLEEP); + bcopy(bp->data, block, mp->m_dirblksize); + logflags = XFS_ILOG_CORE; + if ((error = xfs_dir2_shrink_inode(args, mp->m_dirdatablk, bp))) { + ASSERT(error != ENOSPC); + goto out; + } + /* + * The buffer is now unconditionally gone, whether + * xfs_dir2_shrink_inode worked or not. + * + * Convert the inode to local format. + */ + dp->i_df.if_flags &= ~XFS_IFEXTENTS; + dp->i_df.if_flags |= XFS_IFINLINE; + dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; + ASSERT(dp->i_df.if_bytes == 0); + xfs_idata_realloc(dp, size, XFS_DATA_FORK); + logflags |= XFS_ILOG_DDATA; + /* + * Copy the header into the newly allocate local space. + */ + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + bcopy(sfhp, sfp, XFS_DIR2_SF_HDR_SIZE(sfhp->i8count)); + dp->i_d.di_size = size; + /* + * Set up to loop over the block's entries. + */ + btp = XFS_DIR2_BLOCK_TAIL_P(mp, block); + ptr = (char *)block->u; + endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT); + sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + /* + * Loop over the active and unused entries. + * Stop when we reach the leaf/tail portion of the block. + */ + while (ptr < endptr) { + /* + * If it's unused, just skip over it. + */ + dup = (xfs_dir2_data_unused_t *)ptr; + if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) { + ptr += INT_GET(dup->length, ARCH_CONVERT); + continue; + } + dep = (xfs_dir2_data_entry_t *)ptr; + /* + * Skip . + */ + if (dep->namelen == 1 && dep->name[0] == '.') + ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) == dp->i_ino); + /* + * Skip .., but make sure the inode number is right. + */ + else if (dep->namelen == 2 && + dep->name[0] == '.' && dep->name[1] == '.') + ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) == + XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT)); + /* + * Normal entry, copy it into shortform. + */ + else { + sfep->namelen = dep->namelen; + XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, + (xfs_dir2_data_aoff_t) + ((char *)dep - (char *)block), ARCH_CONVERT); + bcopy(dep->name, sfep->name, dep->namelen); + temp=INT_GET(dep->inumber, ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &temp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep); + } + ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen); + } + ASSERT((char *)sfep - (char *)sfp == size); + xfs_dir2_sf_check(args); +out: + xfs_trans_log_inode(args->trans, dp, logflags); + kmem_free(block, mp->m_dirblksize); + return error; +} + +/* + * Add a name to a shortform directory. + * There are two algorithms, "easy" and "hard" which we decide on + * before changing anything. + * Convert to block form if necessary, if the new entry won't fit. + */ +int /* error */ +xfs_dir2_sf_addname( + xfs_da_args_t *args) /* operation arguments */ +{ + int add_entsize; /* size of the new entry */ + xfs_inode_t *dp; /* incore directory inode */ + int error; /* error return value */ + int incr_isize; /* total change in size */ + int new_isize; /* di_size after adding name */ + int objchange; /* changing to 8-byte inodes */ + xfs_dir2_data_aoff_t offset; /* offset for new entry */ + int old_isize; /* di_size before adding name */ + int pick; /* which algorithm to use */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + xfs_dir2_sf_entry_t *sfep; /* shortform entry */ + + xfs_dir2_trace_args("sf_addname", args); + ASSERT(xfs_dir2_sf_lookup(args) == ENOENT); + dp = args->dp; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Make sure the shortform value has some of its header. + */ + if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); + /* + * Compute entry (and change in) size. + */ + add_entsize = XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, args->namelen); + incr_isize = add_entsize; +#if XFS_BIG_FILESYSTEMS + /* + * Do we have to change to 8 byte inodes? + */ + if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->hdr.i8count == 0) { + /* + * Yes, adjust the entry size and the total size. + */ + add_entsize += + (uint)sizeof(xfs_dir2_ino8_t) - + (uint)sizeof(xfs_dir2_ino4_t); + incr_isize += + (sfp->hdr.count + 2) * + ((uint)sizeof(xfs_dir2_ino8_t) - + (uint)sizeof(xfs_dir2_ino4_t)); + objchange = 1; + } else + objchange = 0; +#else + objchange = 0; +#endif + old_isize = (int)dp->i_d.di_size; + new_isize = old_isize + incr_isize; + /* + * Won't fit as shortform any more (due to size), + * or the pick routine says it won't (due to offset values). + */ + if (new_isize > XFS_IFORK_DSIZE(dp) || + (pick = + xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) { + /* + * Just checking or no space reservation, it doesn't fit. + */ + if (args->justcheck || args->total == 0) + return XFS_ERROR(ENOSPC); + /* + * Convert to block form then add the name. + */ + error = xfs_dir2_sf_to_block(args); + if (error) + return error; + return xfs_dir2_block_addname(args); + } + /* + * Just checking, it fits. + */ + if (args->justcheck) + return 0; + /* + * Do it the easy way - just add it at the end. + */ + if (pick == 1) + xfs_dir2_sf_addname_easy(args, sfep, offset, new_isize); + /* + * Do it the hard way - look for a place to insert the new entry. + * Convert to 8 byte inode numbers first if necessary. + */ + else { + ASSERT(pick == 2); +#if XFS_BIG_FILESYSTEMS + if (objchange) + xfs_dir2_sf_toino8(args); +#endif + xfs_dir2_sf_addname_hard(args, objchange, new_isize); + } + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + return 0; +} + +/* + * Add the new entry the "easy" way. + * This is copying the old directory and adding the new entry at the end. + * Since it's sorted by "offset" we need room after the last offset + * that's already there, and then room to convert to a block directory. + * This is already checked by the pick routine. + */ +static void +xfs_dir2_sf_addname_easy( + xfs_da_args_t *args, /* operation arguments */ + xfs_dir2_sf_entry_t *sfep, /* pointer to new entry */ + xfs_dir2_data_aoff_t offset, /* offset to use for new ent */ + int new_isize) /* new directory size */ +{ + int byteoff; /* byte offset in sf dir */ + xfs_inode_t *dp; /* incore directory inode */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + + dp = args->dp; + + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + byteoff = (int)((char *)sfep - (char *)sfp); + /* + * Grow the in-inode space. + */ + xfs_idata_realloc(dp, XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, args->namelen), + XFS_DATA_FORK); + /* + * Need to set up again due to realloc of the inode data. + */ + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff); + /* + * Fill in the new entry. + */ + sfep->namelen = args->namelen; + XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, offset, ARCH_CONVERT); + bcopy(args->name, sfep->name, sfep->namelen); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + /* + * Update the header and inode. + */ + sfp->hdr.count++; +#if XFS_BIG_FILESYSTEMS + if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) + sfp->hdr.i8count++; +#endif + dp->i_d.di_size = new_isize; + xfs_dir2_sf_check(args); +} + +/* + * Add the new entry the "hard" way. + * The caller has already converted to 8 byte inode numbers if necessary, + * in which case we need to leave the i8count at 1. + * Find a hole that the new entry will fit into, and copy + * the first part of the entries, the new entry, and the last part of + * the entries. + */ +/* ARGSUSED */ +static void +xfs_dir2_sf_addname_hard( + xfs_da_args_t *args, /* operation arguments */ + int objchange, /* changing inode number size */ + int new_isize) /* new directory size */ +{ + int add_datasize; /* data size need for new ent */ + char buf[XFS_DIR2_SF_MAX_SIZE]; /* buffer for old */ + xfs_inode_t *dp; /* incore directory inode */ + int eof; /* reached end of old dir */ + int nbytes; /* temp for byte copies */ + xfs_dir2_data_aoff_t new_offset; /* next offset value */ + xfs_dir2_data_aoff_t offset; /* current offset value */ + int old_isize; /* previous di_size */ + xfs_dir2_sf_entry_t *oldsfep; /* entry in original dir */ + xfs_dir2_sf_t *oldsfp; /* original shortform dir */ + xfs_dir2_sf_entry_t *sfep; /* entry in new dir */ + xfs_dir2_sf_t *sfp; /* new shortform dir */ + + /* + * Copy the old directory to the stack buffer. + */ + dp = args->dp; + + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + old_isize = (int)dp->i_d.di_size; + oldsfp = (xfs_dir2_sf_t *)buf; + bcopy(sfp, oldsfp, old_isize); + /* + * Loop over the old directory finding the place we're going + * to insert the new entry. + * If it's going to end up at the end then oldsfep will point there. + */ + for (offset = XFS_DIR2_DATA_FIRST_OFFSET, + oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp), + add_datasize = XFS_DIR2_DATA_ENTSIZE(args->namelen), + eof = (char *)oldsfep == &buf[old_isize]; + !eof; + offset = new_offset + XFS_DIR2_DATA_ENTSIZE(oldsfep->namelen), + oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep), + eof = (char *)oldsfep == &buf[old_isize]) { + new_offset = XFS_DIR2_SF_GET_OFFSET_ARCH(oldsfep, ARCH_CONVERT); + if (offset + add_datasize <= new_offset) + break; + } + /* + * Get rid of the old directory, then allocate space for + * the new one. We do this so xfs_idata_realloc won't copy + * the data. + */ + xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK); + xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK); + /* + * Reset the pointer since the buffer was reallocated. + */ + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + /* + * Copy the first part of the directory, including the header. + */ + nbytes = (int)((char *)oldsfep - (char *)oldsfp); + bcopy(oldsfp, sfp, nbytes); + sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes); + /* + * Fill in the new entry, and update the header counts. + */ + sfep->namelen = args->namelen; + XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, offset, ARCH_CONVERT); + bcopy(args->name, sfep->name, sfep->namelen); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + sfp->hdr.count++; +#if XFS_BIG_FILESYSTEMS + if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange) + sfp->hdr.i8count++; +#endif + /* + * If there's more left to copy, do that. + */ + if (!eof) { + sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep); + bcopy(oldsfep, sfep, old_isize - nbytes); + } + dp->i_d.di_size = new_isize; + xfs_dir2_sf_check(args); +} + +/* + * Decide if the new entry will fit at all. + * If it will fit, pick between adding the new entry to the end (easy) + * or somewhere else (hard). + * Return 0 (won't fit), 1 (easy), 2 (hard). + */ +/*ARGSUSED*/ +static int /* pick result */ +xfs_dir2_sf_addname_pick( + xfs_da_args_t *args, /* operation arguments */ + int objchange, /* inode # size changes */ + xfs_dir2_sf_entry_t **sfepp, /* out(1): new entry ptr */ + xfs_dir2_data_aoff_t *offsetp) /* out(1): new offset */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int holefit; /* found hole it will fit in */ + int i; /* entry number */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_dir2_data_aoff_t offset; /* data block offset */ + xfs_dir2_sf_entry_t *sfep; /* shortform entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + int size; /* entry's data size */ + int used; /* data bytes used */ + + dp = args->dp; + mp = dp->i_mount; + + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + size = XFS_DIR2_DATA_ENTSIZE(args->namelen); + offset = XFS_DIR2_DATA_FIRST_OFFSET; + sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + holefit = 0; + /* + * Loop over sf entries. + * Keep track of data offset and whether we've seen a place + * to insert the new entry. + */ + for (i = 0; i < sfp->hdr.count; i++) { + if (!holefit) + holefit = offset + size <= XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT); + offset = XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) + + XFS_DIR2_DATA_ENTSIZE(sfep->namelen); + sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep); + } + /* + * Calculate data bytes used excluding the new entry, if this + * was a data block (block form directory). + */ + used = offset + + (sfp->hdr.count + 3) * (uint)sizeof(xfs_dir2_leaf_entry_t) + + (uint)sizeof(xfs_dir2_block_tail_t); + /* + * If it won't fit in a block form then we can't insert it, + * we'll go back, convert to block, then try the insert and convert + * to leaf. + */ + if (used + (holefit ? 0 : size) > mp->m_dirblksize) + return 0; + /* + * If changing the inode number size, do it the hard way. + */ +#if XFS_BIG_FILESYSTEMS + if (objchange) { + return 2; + } +#else + ASSERT(objchange == 0); +#endif + /* + * If it won't fit at the end then do it the hard way (use the hole). + */ + if (used + size > mp->m_dirblksize) + return 2; + /* + * Do it the easy way. + */ + *sfepp = sfep; + *offsetp = offset; + return 1; +} + +#ifdef DEBUG +/* + * Check consistency of shortform directory, assert if bad. + */ +static void +xfs_dir2_sf_check( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int i; /* entry number */ + int i8count; /* number of big inode#s */ + xfs_ino_t ino; /* entry inode number */ + int offset; /* data offset */ + xfs_dir2_sf_entry_t *sfep; /* shortform dir entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + + dp = args->dp; + + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + offset = XFS_DIR2_DATA_FIRST_OFFSET; + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT); + i8count = ino > XFS_DIR2_MAX_SHORT_INUM; + + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) { + ASSERT(XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) >= offset); + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + i8count += ino > XFS_DIR2_MAX_SHORT_INUM; + offset = + XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT) + + XFS_DIR2_DATA_ENTSIZE(sfep->namelen); + } + ASSERT(i8count == sfp->hdr.i8count); +#if !XFS_BIG_FILESYSTEMS + ASSERT(i8count == 0); +#endif + ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size); + ASSERT(offset + + (sfp->hdr.count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) + + (uint)sizeof(xfs_dir2_block_tail_t) <= + dp->i_mount->m_dirblksize); +} +#endif /* DEBUG */ + +/* + * Create a new (shortform) directory. + */ +int /* error, always 0 */ +xfs_dir2_sf_create( + xfs_da_args_t *args, /* operation arguments */ + xfs_ino_t pino) /* parent inode number */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int i8count; /* parent inode is an 8-byte number */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + int size; /* directory size */ + + xfs_dir2_trace_args_i("sf_create", args, pino); + dp = args->dp; + + ASSERT(dp != NULL); + ASSERT(dp->i_d.di_size == 0); + /* + * If it's currently a zero-length extent file, + * convert it to local format. + */ + if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) { + dp->i_df.if_flags &= ~XFS_IFEXTENTS; /* just in case */ + dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); + dp->i_df.if_flags |= XFS_IFINLINE; + } + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + ASSERT(dp->i_df.if_bytes == 0); + i8count = pino > XFS_DIR2_MAX_SHORT_INUM; + size = XFS_DIR2_SF_HDR_SIZE(i8count); + /* + * Make a buffer for the data. + */ + xfs_idata_realloc(dp, size, XFS_DATA_FORK); + /* + * Fill in the header, + */ + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + sfp->hdr.i8count = i8count; + /* + * Now can put in the inode number, since i8count is set. + */ + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &pino, &sfp->hdr.parent, ARCH_CONVERT); + sfp->hdr.count = 0; + dp->i_d.di_size = size; + xfs_dir2_sf_check(args); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + return 0; +} + +int /* error */ +xfs_dir2_sf_getdents( + xfs_inode_t *dp, /* incore directory inode */ + uio_t *uio, /* caller's buffer control */ + int *eofp, /* eof reached? (out) */ + xfs_dirent_t *dbp, /* caller's buffer */ + xfs_dir2_put_t put) /* abi's formatting function */ +{ + int error; /* error return value */ + int i; /* shortform entry number */ + xfs_mount_t *mp; /* filesystem mount point */ + xfs_dir2_dataptr_t off; /* current entry's offset */ + xfs_dir2_put_args_t p; /* arg package for put rtn */ + xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + xfs_off_t dir_offset; + + mp = dp->i_mount; + + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Give up if the directory is way too short. + */ + if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + return XFS_ERROR(EIO); + } + + dir_offset = uio->uio_offset; + + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + + ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); + + /* + * If the block number in the offset is out of range, we're done. + */ + if (XFS_DIR2_DATAPTR_TO_DB(mp, dir_offset) > mp->m_dirdatablk) { + *eofp = 1; + return 0; + } + + /* + * Set up putargs structure. + */ + p.dbp = dbp; + p.put = put; + p.uio = uio; + /* + * Put . entry unless we're starting past it. + */ + if (dir_offset <= + XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + XFS_DIR2_DATA_DOT_OFFSET)) { + /* + * NOTE! Linux "filldir" semantics require that the + * offset "cookie" be for this entry, not the + * next; all the actual shuffling to make it + * "look right" to the user is done in filldir. + */ + p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, 0, + XFS_DIR2_DATA_DOT_OFFSET); +#if XFS_BIG_FILESYSTEMS + p.ino = dp->i_ino + mp->m_inoadd; +#else + p.ino = dp->i_ino; +#endif + p.name = "."; + p.namelen = 1; + + error = p.put(&p); + + if (!p.done) { + uio->uio_offset = + XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + XFS_DIR2_DATA_DOT_OFFSET); + return error; + } + } + + /* + * Put .. entry unless we're starting past it. + */ + if (dir_offset <= + XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + XFS_DIR2_DATA_DOTDOT_OFFSET)) { + /* + * NOTE! Linux "filldir" semantics require that the + * offset "cookie" be for this entry, not the + * next; all the actual shuffling to make it + * "look right" to the user is done in filldir. + */ + p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + XFS_DIR2_DATA_DOTDOT_OFFSET); +#if XFS_BIG_FILESYSTEMS + p.ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT) + + mp->m_inoadd; +#else + p.ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT); +#endif + p.name = ".."; + p.namelen = 2; + + error = p.put(&p); + + if (!p.done) { + uio->uio_offset = + XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + XFS_DIR2_DATA_DOTDOT_OFFSET); + return error; + } + } + + /* + * Loop while there are more entries and put'ing works. + */ + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) { + + off = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT)); + + if (dir_offset > off) + continue; + + p.namelen = sfep->namelen; + + /* + * NOTE! Linux "filldir" semantics require that the + * offset "cookie" be for this entry, not the + * next; all the actual shuffling to make it + * "look right" to the user is done in filldir. + */ + p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk, + XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, ARCH_CONVERT)); + +#if XFS_BIG_FILESYSTEMS + p.ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT) + + mp->m_inoadd; +#else + p.ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); +#endif + p.name = (char *)sfep->name; + + error = p.put(&p); + + if (!p.done) { + uio->uio_offset = off; + return error; + } + } + + /* + * They all fit. + */ + *eofp = 1; + + uio->uio_offset = + XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk + 1, 0); + + return 0; +} + +/* + * Lookup an entry in a shortform directory. + * Returns EEXIST if found, ENOENT if not found. + */ +int /* error */ +xfs_dir2_sf_lookup( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int i; /* entry index */ + xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + + xfs_dir2_trace_args("sf_lookup", args); + xfs_dir2_sf_check(args); + dp = args->dp; + + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Bail out if the directory is way too short. + */ + if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); + /* + * Special case for . + */ + if (args->namelen == 1 && args->name[0] == '.') { + args->inumber = dp->i_ino; + return XFS_ERROR(EEXIST); + } + /* + * Special case for .. + */ + if (args->namelen == 2 && + args->name[0] == '.' && args->name[1] == '.') { + args->inumber = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT); + return XFS_ERROR(EEXIST); + } + /* + * Loop over all the entries trying to match ours. + */ + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) { + if (sfep->namelen == args->namelen && + sfep->name[0] == args->name[0] && + bcmp(args->name, sfep->name, args->namelen) == 0) { + args->inumber = + XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + return XFS_ERROR(EEXIST); + } + } + /* + * Didn't find it. + */ + ASSERT(args->oknoent); + return XFS_ERROR(ENOENT); +} + +/* + * Remove an entry from a shortform directory. + */ +int /* error */ +xfs_dir2_sf_removename( + xfs_da_args_t *args) +{ + int byteoff; /* offset of removed entry */ + xfs_inode_t *dp; /* incore directory inode */ + int entsize; /* this entry's size */ + int i; /* shortform entry index */ + int newsize; /* new inode size */ + int oldsize; /* old inode size */ + xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + + xfs_dir2_trace_args("sf_removename", args); + dp = args->dp; + + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + oldsize = (int)dp->i_d.di_size; + /* + * Bail out if the directory is way too short. + */ + if (oldsize < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == oldsize); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(oldsize >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); + /* + * Loop over the old directory entries. + * Find the one we're deleting. + */ + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) { + if (sfep->namelen == args->namelen && + sfep->name[0] == args->name[0] && + bcmp(sfep->name, args->name, args->namelen) == 0) { + ASSERT(XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT) == + args->inumber); + break; + } + } + /* + * Didn't find it. + */ + if (i == sfp->hdr.count) { + return XFS_ERROR(ENOENT); + } + /* + * Calculate sizes. + */ + byteoff = (int)((char *)sfep - (char *)sfp); + entsize = XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, args->namelen); + newsize = oldsize - entsize; + /* + * Copy the part if any after the removed entry, sliding it down. + */ + if (byteoff + entsize < oldsize) + ovbcopy((char *)sfp + byteoff + entsize, (char *)sfp + byteoff, + oldsize - (byteoff + entsize)); + /* + * Fix up the header and file size. + */ + sfp->hdr.count--; + dp->i_d.di_size = newsize; + /* + * Reallocate, making it smaller. + */ + xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; +#if XFS_BIG_FILESYSTEMS + /* + * Are we changing inode number size? + */ + if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) { + if (sfp->hdr.i8count == 1) + xfs_dir2_sf_toino4(args); + else + sfp->hdr.i8count--; + } +#endif + xfs_dir2_sf_check(args); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + return 0; +} + +/* + * Replace the inode number of an entry in a shortform directory. + */ +int /* error */ +xfs_dir2_sf_replace( + xfs_da_args_t *args) /* operation arguments */ +{ + xfs_inode_t *dp; /* incore directory inode */ + int i; /* entry index */ +#if XFS_BIG_FILESYSTEMS || defined(DEBUG) + xfs_ino_t ino=0; /* entry old inode number */ +#endif + xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ + xfs_dir2_sf_t *sfp; /* shortform structure */ + + xfs_dir2_trace_args("sf_replace", args); + dp = args->dp; + + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Bail out if the shortform directory is way too small. + */ + if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)); +#if XFS_BIG_FILESYSTEMS + /* + * New inode number is large, and need to convert to 8-byte inodes. + */ + if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->hdr.i8count == 0) { + int error; /* error return value */ + int newsize; /* new inode size */ + + newsize = + dp->i_df.if_bytes + + (sfp->hdr.count + 1) * + ((uint)sizeof(xfs_dir2_ino8_t) - + (uint)sizeof(xfs_dir2_ino4_t)); + /* + * Won't fit as shortform, convert to block then do replace. + */ + if (newsize > XFS_IFORK_DSIZE(dp)) { + error = xfs_dir2_sf_to_block(args); + if (error) { + return error; + } + return xfs_dir2_block_replace(args); + } + /* + * Still fits, convert to 8-byte now. + */ + xfs_dir2_sf_toino8(args); + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + } +#endif + ASSERT(args->namelen != 1 || args->name[0] != '.'); + /* + * Replace ..'s entry. + */ + if (args->namelen == 2 && + args->name[0] == '.' && args->name[1] == '.') { +#if XFS_BIG_FILESYSTEMS || defined(DEBUG) + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT); + ASSERT(args->inumber != ino); +#endif + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber, &sfp->hdr.parent, ARCH_CONVERT); + } + /* + * Normal entry, look for the name. + */ + else { + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) { + if (sfep->namelen == args->namelen && + sfep->name[0] == args->name[0] && + bcmp(args->name, sfep->name, args->namelen) == 0) { +#if XFS_BIG_FILESYSTEMS || defined(DEBUG) + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + ASSERT(args->inumber != ino); +#endif + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &args->inumber, + XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + break; + } + } + /* + * Didn't find it. + */ + if (i == sfp->hdr.count) { + ASSERT(args->oknoent); + return XFS_ERROR(ENOENT); + } + } +#if XFS_BIG_FILESYSTEMS + /* + * See if the old number was large, the new number is small. + */ + if (ino > XFS_DIR2_MAX_SHORT_INUM && + args->inumber <= XFS_DIR2_MAX_SHORT_INUM) { + /* + * And the old count was one, so need to convert to small. + */ + if (sfp->hdr.i8count == 1) + xfs_dir2_sf_toino4(args); + else + sfp->hdr.i8count--; + } +#endif + xfs_dir2_sf_check(args); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); + return 0; +} + +#if XFS_BIG_FILESYSTEMS +/* + * Convert from 8-byte inode numbers to 4-byte inode numbers. + * The last 8-byte inode number is gone, but the count is still 1. + */ +static void +xfs_dir2_sf_toino4( + xfs_da_args_t *args) /* operation arguments */ +{ + char *buf; /* old dir's buffer */ + xfs_inode_t *dp; /* incore directory inode */ + int i; /* entry index */ + xfs_ino_t ino; /* entry inode number */ + int newsize; /* new inode size */ + xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ + xfs_dir2_sf_t *oldsfp; /* old sf directory */ + int oldsize; /* old inode size */ + xfs_dir2_sf_entry_t *sfep; /* new sf entry */ + xfs_dir2_sf_t *sfp; /* new sf directory */ + + xfs_dir2_trace_args("sf_toino4", args); + dp = args->dp; + + /* + * Copy the old directory to the buffer. + * Then nuke it from the inode, and add the new buffer to the inode. + * Don't want xfs_idata_realloc copying the data here. + */ + oldsize = dp->i_df.if_bytes; + buf = kmem_alloc(oldsize, KM_SLEEP); + oldsfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(oldsfp->hdr.i8count == 1); + bcopy(oldsfp, buf, oldsize); + /* + * Compute the new inode size. + */ + newsize = + oldsize - + (oldsfp->hdr.count + 1) * + ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)); + xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); + xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); + /* + * Reset our pointers, the data has moved. + */ + oldsfp = (xfs_dir2_sf_t *)buf; + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + /* + * Fill in the new header. + */ + sfp->hdr.count = oldsfp->hdr.count; + sfp->hdr.i8count = 0; + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, &oldsfp->hdr.parent, ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, &sfp->hdr.parent, ARCH_CONVERT); + /* + * Copy the entries field by field. + */ + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp), + oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep), + oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep)) { + sfep->namelen = oldsfep->namelen; + sfep->offset = oldsfep->offset; + bcopy(oldsfep->name, sfep->name, sfep->namelen); + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, + XFS_DIR2_SF_INUMBERP(oldsfep), ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + } + /* + * Clean up the inode. + */ + kmem_free(buf, oldsize); + dp->i_d.di_size = newsize; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); +} + +/* + * Convert from 4-byte inode numbers to 8-byte inode numbers. + * The new 8-byte inode number is not there yet, we leave with the + * count 1 but no corresponding entry. + */ +static void +xfs_dir2_sf_toino8( + xfs_da_args_t *args) /* operation arguments */ +{ + char *buf; /* old dir's buffer */ + xfs_inode_t *dp; /* incore directory inode */ + int i; /* entry index */ + xfs_ino_t ino; /* entry inode number */ + int newsize; /* new inode size */ + xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ + xfs_dir2_sf_t *oldsfp; /* old sf directory */ + int oldsize; /* old inode size */ + xfs_dir2_sf_entry_t *sfep; /* new sf entry */ + xfs_dir2_sf_t *sfp; /* new sf directory */ + + xfs_dir2_trace_args("sf_toino8", args); + dp = args->dp; + + /* + * Copy the old directory to the buffer. + * Then nuke it from the inode, and add the new buffer to the inode. + * Don't want xfs_idata_realloc copying the data here. + */ + oldsize = dp->i_df.if_bytes; + buf = kmem_alloc(oldsize, KM_SLEEP); + oldsfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + ASSERT(oldsfp->hdr.i8count == 0); + bcopy(oldsfp, buf, oldsize); + /* + * Compute the new inode size. + */ + newsize = + oldsize + + (oldsfp->hdr.count + 1) * + ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)); + xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); + xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); + /* + * Reset our pointers, the data has moved. + */ + oldsfp = (xfs_dir2_sf_t *)buf; + sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data; + /* + * Fill in the new header. + */ + sfp->hdr.count = oldsfp->hdr.count; + sfp->hdr.i8count = 1; + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, &oldsfp->hdr.parent, ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, &sfp->hdr.parent, ARCH_CONVERT); + /* + * Copy the entries field by field. + */ + for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp), + oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp); + i < sfp->hdr.count; + i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep), + oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep)) { + sfep->namelen = oldsfep->namelen; + sfep->offset = oldsfep->offset; + bcopy(oldsfep->name, sfep->name, sfep->namelen); + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(oldsfp, + XFS_DIR2_SF_INUMBERP(oldsfep), ARCH_CONVERT); + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT); + } + /* + * Clean up the inode. + */ + kmem_free(buf, oldsize); + dp->i_d.di_size = newsize; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); +} +#endif /* XFS_BIG_FILESYSTEMS */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir2_sf.h linux-2.4-xfs/linux/fs/xfs/xfs_dir2_sf.h --- linux-2.4.7/linux/fs/xfs/xfs_dir2_sf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir2_sf.h Tue Apr 10 20:44:54 2001 @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_SF_H__ +#define __XFS_DIR2_SF_H__ + +/* + * Directory layout when stored internal to an inode. + * + * Small directories are packed as tightly as possible so as to + * fit into the literal area of the inode. + */ + +struct dirent; +struct uio; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_dir2_block; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * Maximum size of a shortform directory. + */ +#define XFS_DIR2_SF_MAX_SIZE \ + (XFS_DINODE_MAX_SIZE - (uint)sizeof(xfs_dinode_core_t) - \ + (uint)sizeof(xfs_agino_t)) + +/* + * Inode number stored as 8 8-bit values. + */ +typedef struct { __uint8_t i[8]; } xfs_dir2_ino8_t; + +#define XFS_DIR2_SF_GET_INO8_ARCH(di,arch) \ + (xfs_ino_t)(DIRINO_GET_ARCH(&di,arch)) +#define XFS_DIR2_SF_GET_INO8(di) \ + XFS_DIR2_SF_GET_INO8_ARCH(di,ARCH_NOCONVERT) + +/* + * Inode number stored as 4 8-bit values. + * Works a lot of the time, when all the inode numbers in a directory + * fit in 32 bits. + */ +typedef struct { __uint8_t i[4]; } xfs_dir2_ino4_t; +#define XFS_DIR2_SF_GET_INO4_ARCH(di,arch) \ + (xfs_ino_t)(DIRINO4_GET_ARCH(&di,arch)) +#define XFS_DIR2_SF_GET_INO4(di) \ + XFS_DIR2_SF_GET_INO4_ARCH(di,ARCH_NOCONVERT) + +typedef union { + xfs_dir2_ino8_t i8; + xfs_dir2_ino4_t i4; +} xfs_dir2_inou_t; +#define XFS_DIR2_MAX_SHORT_INUM ((xfs_ino_t)0xffffffffULL) + +/* + * Normalized offset (in a data block) of the entry, really xfs_dir2_data_off_t. + * Only need 16 bits, this is the byte offset into the single block form. + */ +typedef struct { __uint8_t i[2]; } xfs_dir2_sf_off_t; + +/* + * The parent directory has a dedicated field, and the self-pointer must + * be calculated on the fly. + * + * Entries are packed toward the top as tightly as possible. The header + * and the elements must be bcopy()'d out into a work area to get correct + * alignment for the inode number fields. + */ +typedef struct xfs_dir2_sf_hdr { + __uint8_t count; /* count of entries */ + __uint8_t i8count; /* count of 8-byte inode #s */ + xfs_dir2_inou_t parent; /* parent dir inode number */ +} xfs_dir2_sf_hdr_t; + +typedef struct xfs_dir2_sf_entry { + __uint8_t namelen; /* actual name length */ + xfs_dir2_sf_off_t offset; /* saved offset */ + __uint8_t name[1]; /* name, variable size */ + xfs_dir2_inou_t inumber; /* inode number, var. offset */ +} xfs_dir2_sf_entry_t; + +typedef struct xfs_dir2_sf { + xfs_dir2_sf_hdr_t hdr; /* shortform header */ + xfs_dir2_sf_entry_t list[1]; /* shortform entries */ +} xfs_dir2_sf_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_HDR_SIZE) +int xfs_dir2_sf_hdr_size(int i8count); +#define XFS_DIR2_SF_HDR_SIZE(i8count) xfs_dir2_sf_hdr_size(i8count) +#else +#define XFS_DIR2_SF_HDR_SIZE(i8count) \ + ((uint)sizeof(xfs_dir2_sf_hdr_t) - \ + ((i8count) == 0) * \ + ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_INUMBERP) +xfs_dir2_inou_t *xfs_dir2_sf_inumberp(xfs_dir2_sf_entry_t *sfep); +#define XFS_DIR2_SF_INUMBERP(sfep) xfs_dir2_sf_inumberp(sfep) +#else +#define XFS_DIR2_SF_INUMBERP(sfep) \ + ((xfs_dir2_inou_t *)&(sfep)->name[(sfep)->namelen]) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_GET_INUMBER) +xfs_intino_t xfs_dir2_sf_get_inumber_arch(xfs_dir2_sf_t *sfp, xfs_dir2_inou_t *from, + xfs_arch_t arch); +#define XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, from, arch) \ + xfs_dir2_sf_get_inumber_arch(sfp, from, arch) + +#else +#define XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, from, arch) \ + ((sfp)->hdr.i8count == 0 ? \ + (xfs_intino_t)XFS_DIR2_SF_GET_INO4_ARCH(*(from), arch) : \ + (xfs_intino_t)XFS_DIR2_SF_GET_INO8_ARCH(*(from), arch)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_PUT_INUMBER) +void xfs_dir2_sf_put_inumber_arch(xfs_dir2_sf_t *sfp, xfs_ino_t *from, + xfs_dir2_inou_t *to, xfs_arch_t arch); +#define XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp,from,to,arch) \ + xfs_dir2_sf_put_inumber_arch(sfp,from,to,arch) +#else +#define XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp,from,to,arch) \ + if ((sfp)->hdr.i8count == 0) { \ + DIRINO4_COPY_ARCH(from,to,arch); \ + } else { \ + DIRINO_COPY_ARCH(from,to,arch); \ + } +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_GET_OFFSET) +xfs_dir2_data_aoff_t xfs_dir2_sf_get_offset_arch(xfs_dir2_sf_entry_t *sfep, + xfs_arch_t arch); +xfs_dir2_data_aoff_t xfs_dir2_sf_get_offset(xfs_dir2_sf_entry_t *sfep); +#define XFS_DIR2_SF_GET_OFFSET_ARCH(sfep,arch) \ + xfs_dir2_sf_get_offset_arch(sfep,arch) +#else +#define XFS_DIR2_SF_GET_OFFSET_ARCH(sfep,arch) \ + INT_GET_UNALIGNED_16_ARCH(&(sfep)->offset.i,arch) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_PUT_OFFSET) +void xfs_dir2_sf_put_offset_arch(xfs_dir2_sf_entry_t *sfep, + xfs_dir2_data_aoff_t off, xfs_arch_t arch); +#define XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep,off,arch) \ + xfs_dir2_sf_put_offset_arch(sfep,off,arch) +#else +#define XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep,off,arch) \ + INT_SET_UNALIGNED_16_ARCH(&(sfep)->offset.i,off,arch) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_ENTSIZE_BYNAME) +int xfs_dir2_sf_entsize_byname(xfs_dir2_sf_t *sfp, int len); +#define XFS_DIR2_SF_ENTSIZE_BYNAME(sfp,len) \ + xfs_dir2_sf_entsize_byname(sfp,len) +#else +#define XFS_DIR2_SF_ENTSIZE_BYNAME(sfp,len) /* space a name uses */ \ + ((uint)sizeof(xfs_dir2_sf_entry_t) - 1 + (len) - \ + ((sfp)->hdr.i8count == 0) * \ + ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_ENTSIZE_BYENTRY) +int xfs_dir2_sf_entsize_byentry(xfs_dir2_sf_t *sfp, xfs_dir2_sf_entry_t *sfep); +#define XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp,sfep) \ + xfs_dir2_sf_entsize_byentry(sfp,sfep) +#else +#define XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp,sfep) /* space an entry uses */ \ + ((uint)sizeof(xfs_dir2_sf_entry_t) - 1 + (sfep)->namelen - \ + ((sfp)->hdr.i8count == 0) * \ + ((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_FIRSTENTRY) +xfs_dir2_sf_entry_t *xfs_dir2_sf_firstentry(xfs_dir2_sf_t *sfp); +#define XFS_DIR2_SF_FIRSTENTRY(sfp) xfs_dir2_sf_firstentry(sfp) +#else +#define XFS_DIR2_SF_FIRSTENTRY(sfp) /* first entry in struct */ \ + ((xfs_dir2_sf_entry_t *) \ + ((char *)(sfp) + XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR2_SF_NEXTENTRY) +xfs_dir2_sf_entry_t *xfs_dir2_sf_nextentry(xfs_dir2_sf_t *sfp, + xfs_dir2_sf_entry_t *sfep); +#define XFS_DIR2_SF_NEXTENTRY(sfp,sfep) xfs_dir2_sf_nextentry(sfp,sfep) +#else +#define XFS_DIR2_SF_NEXTENTRY(sfp,sfep) /* next entry in struct */ \ + ((xfs_dir2_sf_entry_t *) \ + ((char *)(sfep) + XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp,sfep))) +#endif + +/* + * Functions. + */ + +extern int + xfs_dir2_block_sfsize(struct xfs_inode *dp, + struct xfs_dir2_block *block, + xfs_dir2_sf_hdr_t *sfhp); + +extern int + xfs_dir2_block_to_sf(struct xfs_da_args *args, struct xfs_dabuf *bp, + int size, xfs_dir2_sf_hdr_t *sfhp); + +extern int + xfs_dir2_sf_addname(struct xfs_da_args *args); + +extern int + xfs_dir2_sf_create(struct xfs_da_args *args, xfs_ino_t pino); + +extern int + xfs_dir2_sf_getdents(struct xfs_inode *dp, struct uio *uio, int *eofp, + struct xfs_dirent *dbp, xfs_dir2_put_t put); + +extern int + xfs_dir2_sf_lookup(struct xfs_da_args *args); + +extern int + xfs_dir2_sf_removename(struct xfs_da_args *args); + +extern int + xfs_dir2_sf_replace(struct xfs_da_args *args); + +#endif /* __XFS_DIR2_SF_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir2_trace.c linux-2.4-xfs/linux/fs/xfs/xfs_dir2_trace.c --- linux-2.4.7/linux/fs/xfs/xfs_dir2_trace.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir2_trace.c Mon Sep 25 00:42:07 2000 @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir2_trace.c + * Tracing for xfs v2 directories. + */ +#include + + +#ifdef DEBUG +ktrace_t *xfs_dir2_trace_buf; +#endif /* DEBUG */ + +#ifdef XFS_DIR2_TRACE +/* + * Enter something in the trace buffers. + */ +static void +xfs_dir2_trace_enter( + xfs_inode_t *dp, + int type, + char *where, + char *name, + int namelen, + __psunsigned_t a0, + __psunsigned_t a1, + __psunsigned_t a2, + __psunsigned_t a3, + __psunsigned_t a4, + __psunsigned_t a5, + __psunsigned_t a6) +{ + __psunsigned_t n[6]; + + ASSERT(xfs_dir2_trace_buf); + ASSERT(dp->i_dir_trace); + if (name) + bcopy(name, n, min(sizeof(n), namelen)); + else + bzero((char *)n, sizeof(n)); + ktrace_enter(xfs_dir2_trace_buf, + (void *)(__psunsigned_t)type, (void *)where, + (void *)a0, (void *)a1, (void *)a2, (void *)a3, + (void *)a4, (void *)a5, (void *)a6, + (void *)(__psunsigned_t)namelen, + (void *)n[0], (void *)n[1], (void *)n[2], + (void *)n[3], (void *)n[4], (void *)n[5]); + ktrace_enter(dp->i_dir_trace, + (void *)(__psunsigned_t)type, (void *)where, + (void *)a0, (void *)a1, (void *)a2, (void *)a3, + (void *)a4, (void *)a5, (void *)a6, + (void *)(__psunsigned_t)namelen, + (void *)n[0], (void *)n[1], (void *)n[2], + (void *)n[3], (void *)n[4], (void *)n[5]); +} + +void +xfs_dir2_trace_args( + char *where, + xfs_da_args_t *args) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->hashval, (__psunsigned_t)args->inumber, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)args->justcheck, 0, 0); +} + +void +xfs_dir2_trace_args_b( + char *where, + xfs_da_args_t *args, + xfs_dabuf_t *bp) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS_B, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->hashval, (__psunsigned_t)args->inumber, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)args->justcheck, + (__psunsigned_t)(bp ? bp->bps[0] : NULL), 0); +} + +void +xfs_dir2_trace_args_bb( + char *where, + xfs_da_args_t *args, + xfs_dabuf_t *lbp, + xfs_dabuf_t *dbp) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS_BB, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->hashval, (__psunsigned_t)args->inumber, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)args->justcheck, + (__psunsigned_t)(lbp ? lbp->bps[0] : NULL), + (__psunsigned_t)(dbp ? dbp->bps[0] : NULL)); +} + +void +xfs_dir2_trace_args_bibii( + char *where, + xfs_da_args_t *args, + xfs_dabuf_t *bs, + int ss, + xfs_dabuf_t *bd, + int sd, + int c) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS_BIBII, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)(bs ? bs->bps[0] : NULL), (__psunsigned_t)ss, + (__psunsigned_t)(bd ? bd->bps[0] : NULL), (__psunsigned_t)sd, + (__psunsigned_t)c); +} + +void +xfs_dir2_trace_args_db( + char *where, + xfs_da_args_t *args, + xfs_dir2_db_t db, + xfs_dabuf_t *bp) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS_DB, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->hashval, (__psunsigned_t)args->inumber, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)args->justcheck, (__psunsigned_t)db, + (__psunsigned_t)(bp ? bp->bps[0] : NULL)); +} + +void +xfs_dir2_trace_args_i( + char *where, + xfs_da_args_t *args, + xfs_ino_t i) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS_I, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->hashval, (__psunsigned_t)args->inumber, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)args->justcheck, (__psunsigned_t)i, 0); +} + +void +xfs_dir2_trace_args_s( + char *where, + xfs_da_args_t *args, + int s) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS_S, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->hashval, (__psunsigned_t)args->inumber, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)args->justcheck, (__psunsigned_t)s, 0); +} + +void +xfs_dir2_trace_args_sb( + char *where, + xfs_da_args_t *args, + int s, + xfs_dabuf_t *bp) +{ + xfs_dir2_trace_enter(args->dp, XFS_DIR2_KTRACE_ARGS_SB, where, + (char *)args->name, (int)args->namelen, + (__psunsigned_t)args->hashval, (__psunsigned_t)args->inumber, + (__psunsigned_t)args->dp, (__psunsigned_t)args->trans, + (__psunsigned_t)args->justcheck, (__psunsigned_t)s, + (__psunsigned_t)(bp ? bp->bps[0] : NULL)); +} +#endif /* XFS_DIR2_TRACE */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir2_trace.h linux-2.4-xfs/linux/fs/xfs/xfs_dir2_trace.h --- linux-2.4.7/linux/fs/xfs/xfs_dir2_trace.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir2_trace.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR2_TRACE_H__ +#define __XFS_DIR2_TRACE_H__ + +/* + * Tracing for xfs v2 directories. + */ + +struct ktrace; +struct xfs_dabuf; +struct xfs_da_args; + +#ifdef XFS_ALL_TRACE +#define XFS_DIR2_TRACE +#endif /* XFS_ALL_TRACE */ + +#if !defined(DEBUG) +#undef XFS_DIR2_TRACE +#endif /* !DEBUG */ + +#define XFS_DIR2_GTRACE_SIZE 4096 /* global buffer */ +#define XFS_DIR2_KTRACE_SIZE 32 /* per-inode buffer */ + +#define XFS_DIR2_KTRACE_ARGS 1 /* args only */ +#define XFS_DIR2_KTRACE_ARGS_B 2 /* args + buffer */ +#define XFS_DIR2_KTRACE_ARGS_BB 3 /* args + 2 buffers */ +#define XFS_DIR2_KTRACE_ARGS_DB 4 /* args, db, buffer */ +#define XFS_DIR2_KTRACE_ARGS_I 5 /* args, inum */ +#define XFS_DIR2_KTRACE_ARGS_S 6 /* args, int */ +#define XFS_DIR2_KTRACE_ARGS_SB 7 /* args, int, buffer */ +#define XFS_DIR2_KTRACE_ARGS_BIBII 8 /* args, buf/int/buf/int/int */ + +#ifdef XFS_DIR2_TRACE + +void xfs_dir2_trace_args(char *where, struct xfs_da_args *args); +void xfs_dir2_trace_args_b(char *where, struct xfs_da_args *args, + struct xfs_dabuf *bp); +void xfs_dir2_trace_args_bb(char *where, struct xfs_da_args *args, + struct xfs_dabuf *lbp, struct xfs_dabuf *dbp); +void xfs_dir2_trace_args_bibii(char *where, struct xfs_da_args *args, + struct xfs_dabuf *bs, int ss, + struct xfs_dabuf *bd, int sd, int c); +void xfs_dir2_trace_args_db(char *where, struct xfs_da_args *args, + xfs_dir2_db_t db, struct xfs_dabuf *bp); +void xfs_dir2_trace_args_i(char *where, struct xfs_da_args *args, xfs_ino_t i); +void xfs_dir2_trace_args_s(char *where, struct xfs_da_args *args, int s); +void xfs_dir2_trace_args_sb(char *where, struct xfs_da_args *args, int s, + struct xfs_dabuf *bp); + +#else /* XFS_DIR2_TRACE */ + +#define xfs_dir2_trace_args(where, args) +#define xfs_dir2_trace_args_b(where, args, bp) +#define xfs_dir2_trace_args_bb(where, args, lbp, dbp) +#define xfs_dir2_trace_args_bibii(where, args, bs, ss, bd, sd, c) +#define xfs_dir2_trace_args_db(where, args, db, bp) +#define xfs_dir2_trace_args_i(where, args, i) +#define xfs_dir2_trace_args_s(where, args, s) +#define xfs_dir2_trace_args_sb(where, args, s, bp) + +#endif /* XFS_DIR2_TRACE */ + +extern struct ktrace *xfs_dir2_trace_buf; + +#endif /* __XFS_DIR2_TRACE_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir_leaf.c linux-2.4-xfs/linux/fs/xfs/xfs_dir_leaf.c --- linux-2.4.7/linux/fs/xfs/xfs_dir_leaf.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir_leaf.c Thu Apr 12 18:35:02 2001 @@ -0,0 +1,2301 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * xfs_dir_leaf.c + * + * GROT: figure out how to recover gracefully when bmap returns ENOSPC. + */ + +#include + + +/* + * xfs_dir_leaf.c + * + * Routines to implement leaf blocks of directories as Btrees of hashed names. + */ + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Routines used for growing the Btree. + */ +STATIC void xfs_dir_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args, + int insertion_index, + int freemap_index); +STATIC int xfs_dir_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer, + int musthave, int justcheck); +STATIC void xfs_dir_leaf_rebalance(xfs_da_state_t *state, + xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2); +STATIC int xfs_dir_leaf_figure_balance(xfs_da_state_t *state, + xfs_da_state_blk_t *leaf_blk_1, + xfs_da_state_blk_t *leaf_blk_2, + int *number_entries_in_blk1, + int *number_namebytes_in_blk1); + +/* + * Utility routines. + */ +STATIC void xfs_dir_leaf_moveents(xfs_dir_leafblock_t *src_leaf, + int src_start, + xfs_dir_leafblock_t *dst_leaf, + int dst_start, int move_count, + xfs_mount_t *mp); + + +/*======================================================================== + * External routines when dirsize < XFS_IFORK_DSIZE(dp). + *========================================================================*/ + + +/* + * Validate a given inode number. + */ +int +xfs_dir_ino_validate(xfs_mount_t *mp, xfs_ino_t ino) +{ + xfs_agblock_t agblkno; + xfs_agino_t agino; + xfs_agnumber_t agno; + int ino_ok; + int ioff; + + agno = XFS_INO_TO_AGNO(mp, ino); + agblkno = XFS_INO_TO_AGBNO(mp, ino); + ioff = XFS_INO_TO_OFFSET(mp, ino); + agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff); + ino_ok = + agno < mp->m_sb.sb_agcount && + agblkno < mp->m_sb.sb_agblocks && + agblkno != 0 && + ioff < (1 << mp->m_sb.sb_inopblog) && + XFS_AGINO_TO_INO(mp, agno, agino) == ino; + if (XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE, + XFS_RANDOM_DIR_INO_VALIDATE)) { + xfs_fs_cmn_err(CE_WARN, mp, + "Invalid inode number 0x%Lx\n", ino); + return XFS_ERROR(EFSCORRUPTED); + } + return 0; +} + +/* + * Create the initial contents of a shortform directory. + */ +int +xfs_dir_shortform_create(xfs_da_args_t *args, xfs_ino_t parent) +{ + xfs_dir_sf_hdr_t *hdr; + xfs_inode_t *dp; + + dp = args->dp; + ASSERT(dp != NULL); + ASSERT(dp->i_d.di_size == 0); + if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) { + dp->i_df.if_flags &= ~XFS_IFEXTENTS; /* just in case */ + dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); + dp->i_df.if_flags |= XFS_IFINLINE; + } + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + ASSERT(dp->i_df.if_bytes == 0); + xfs_idata_realloc(dp, sizeof(*hdr), XFS_DATA_FORK); + hdr = (xfs_dir_sf_hdr_t *)dp->i_df.if_u1.if_data; + XFS_DIR_SF_PUT_DIRINO_ARCH(&parent, &hdr->parent, ARCH_CONVERT); + + INT_ZERO(hdr->count, ARCH_CONVERT); + dp->i_d.di_size = sizeof(*hdr); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + return(0); +} + +/* + * Add a name to the shortform directory structure. + * Overflow from the inode has already been checked for. + */ +int +xfs_dir_shortform_addname(xfs_da_args_t *args) +{ + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + int i, offset, size; + xfs_inode_t *dp; + + dp = args->dp; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Catch the case where the conversion from shortform to leaf + * failed part way through. + */ + if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + sfe = &sf->list[0]; + for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) { + if (sfe->namelen == args->namelen && + args->name[0] == sfe->name[0] && + bcmp(args->name, sfe->name, args->namelen) == 0) + return(XFS_ERROR(EEXIST)); + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + + offset = (int)((char *)sfe - (char *)sf); + size = XFS_DIR_SF_ENTSIZE_BYNAME(args->namelen); + xfs_idata_realloc(dp, size, XFS_DATA_FORK); + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + sfe = (xfs_dir_sf_entry_t *)((char *)sf + offset); + + XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sfe->inumber, ARCH_CONVERT); + sfe->namelen = args->namelen; + bcopy(args->name, sfe->name, sfe->namelen); + INT_MOD(sf->hdr.count, ARCH_CONVERT, +1); + + dp->i_d.di_size += size; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + + return(0); +} + +/* + * Remove a name from the shortform directory structure. + */ +int +xfs_dir_shortform_removename(xfs_da_args_t *args) +{ + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + int base, size, i; + xfs_inode_t *dp; + + dp = args->dp; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Catch the case where the conversion from shortform to leaf + * failed part way through. + */ + if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + base = sizeof(xfs_dir_sf_hdr_t); + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + sfe = &sf->list[0]; + for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) { + size = XFS_DIR_SF_ENTSIZE_BYENTRY(sfe); + if (sfe->namelen == args->namelen && + sfe->name[0] == args->name[0] && + bcmp(sfe->name, args->name, args->namelen) == 0) + break; + base += size; + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + if (i < 0) { + ASSERT(args->oknoent); + return(XFS_ERROR(ENOENT)); + } + + if ((base + size) != dp->i_d.di_size) { + ovbcopy(&((char *)sf)[base+size], &((char *)sf)[base], + dp->i_d.di_size - (base+size)); + } + INT_MOD(sf->hdr.count, ARCH_CONVERT, -1); + + xfs_idata_realloc(dp, -size, XFS_DATA_FORK); + dp->i_d.di_size -= size; + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); + + return(0); +} + +/* + * Look up a name in a shortform directory structure. + */ +int +xfs_dir_shortform_lookup(xfs_da_args_t *args) +{ + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + int i; + xfs_inode_t *dp; + + dp = args->dp; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Catch the case where the conversion from shortform to leaf + * failed part way through. + */ + if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + if (args->namelen == 2 && + args->name[0] == '.' && args->name[1] == '.') { + XFS_DIR_SF_GET_DIRINO_ARCH(&sf->hdr.parent, &args->inumber, ARCH_CONVERT); + return(XFS_ERROR(EEXIST)); + } + if (args->namelen == 1 && args->name[0] == '.') { + args->inumber = dp->i_ino; + return(XFS_ERROR(EEXIST)); + } + sfe = &sf->list[0]; + for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) { + if (sfe->namelen == args->namelen && + sfe->name[0] == args->name[0] && + bcmp(args->name, sfe->name, args->namelen) == 0) { + XFS_DIR_SF_GET_DIRINO_ARCH(&sfe->inumber, &args->inumber, ARCH_CONVERT); + return(XFS_ERROR(EEXIST)); + } + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + ASSERT(args->oknoent); + return(XFS_ERROR(ENOENT)); +} + +/* + * Convert from using the shortform to the leaf. + */ +int +xfs_dir_shortform_to_leaf(xfs_da_args_t *iargs) +{ + xfs_inode_t *dp; + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + xfs_da_args_t args; + xfs_ino_t inumber; + char *tmpbuffer; + int retval, i, size; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + + dp = iargs->dp; + /* + * Catch the case where the conversion from shortform to leaf + * failed part way through. + */ + if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + size = dp->i_df.if_bytes; + tmpbuffer = kmem_alloc(size, KM_SLEEP); + ASSERT(tmpbuffer != NULL); + + bcopy(dp->i_df.if_u1.if_data, tmpbuffer, size); + + sf = (xfs_dir_shortform_t *)tmpbuffer; + XFS_DIR_SF_GET_DIRINO_ARCH(&sf->hdr.parent, &inumber, ARCH_CONVERT); + + xfs_idata_realloc(dp, -size, XFS_DATA_FORK); + dp->i_d.di_size = 0; + xfs_trans_log_inode(iargs->trans, dp, XFS_ILOG_CORE); + retval = xfs_da_grow_inode(iargs, &blkno); + if (retval) + goto out; + + ASSERT(blkno == 0); + retval = xfs_dir_leaf_create(iargs, blkno, &bp); + if (retval) + goto out; + xfs_da_buf_done(bp); + + args.name = "."; + args.namelen = 1; + args.hashval = xfs_dir_hash_dot; + args.inumber = dp->i_ino; + args.dp = dp; + args.firstblock = iargs->firstblock; + args.flist = iargs->flist; + args.total = iargs->total; + args.whichfork = XFS_DATA_FORK; + args.trans = iargs->trans; + args.justcheck = 0; + args.addname = args.oknoent = 1; + retval = xfs_dir_leaf_addname(&args); + if (retval) + goto out; + + args.name = ".."; + args.namelen = 2; + args.hashval = xfs_dir_hash_dotdot; + args.inumber = inumber; + retval = xfs_dir_leaf_addname(&args); + if (retval) + goto out; + + sfe = &sf->list[0]; + for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { + args.name = (char *)(sfe->name); + args.namelen = sfe->namelen; + args.hashval = xfs_da_hashname((char *)(sfe->name), + sfe->namelen); + XFS_DIR_SF_GET_DIRINO_ARCH(&sfe->inumber, &args.inumber, ARCH_CONVERT); + retval = xfs_dir_leaf_addname(&args); + if (retval) + goto out; + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + retval = 0; + +out: + kmem_free(tmpbuffer, size); + return(retval); +} + +STATIC int +xfs_dir_shortform_compare(const void *a, const void *b) +{ + xfs_dir_sf_sort_t *sa, *sb; + + sa = (xfs_dir_sf_sort_t *)a; + sb = (xfs_dir_sf_sort_t *)b; + if (sa->hash < sb->hash) + return -1; + else if (sa->hash > sb->hash) + return 1; + else + return sa->entno - sb->entno; +} + +/* + * Copy out directory entries for getdents(), for shortform directories. + */ +/*ARGSUSED*/ +int +xfs_dir_shortform_getdents(xfs_inode_t *dp, uio_t *uio, int *eofp, + xfs_dirent_t *dbp, xfs_dir_put_t put) +{ + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + int retval, i, sbsize, nsbuf, lastresid=0, want_entno; + xfs_mount_t *mp; + xfs_dahash_t cookhash, hash; + xfs_dir_put_args_t p; + xfs_dir_sf_sort_t *sbuf, *sbp; + + mp = dp->i_mount; + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset); + want_entno = XFS_DA_COOKIE_ENTRY(mp, uio->uio_offset); + nsbuf = INT_GET(sf->hdr.count, ARCH_CONVERT) + 2; + sbsize = (nsbuf + 1) * sizeof(*sbuf); + sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP); + + xfs_dir_trace_g_du("sf: start", dp, uio); + + /* + * Collect all the entries into the buffer. + * Entry 0 is . + */ + sbp->entno = 0; + sbp->seqno = 0; + sbp->hash = xfs_dir_hash_dot; + sbp->ino = dp->i_ino; + sbp->name = "."; + sbp->namelen = 1; + sbp++; + + /* + * Entry 1 is .. + */ + sbp->entno = 1; + sbp->seqno = 0; + sbp->hash = xfs_dir_hash_dotdot; + sbp->ino = XFS_GET_DIR_INO_ARCH(mp, sf->hdr.parent, ARCH_CONVERT); + sbp->name = ".."; + sbp->namelen = 2; + sbp++; + + /* + * Scan the directory data for the rest of the entries. + */ + for (i = 0, sfe = &sf->list[0]; + i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) { + + if (((char *)sfe < (char *)sf) || + ((char *)sfe >= ((char *)sf + dp->i_df.if_bytes)) || + (sfe->namelen >= MAXNAMELEN)) { + xfs_dir_trace_g_du("sf: corrupted", dp, uio); + kmem_free(sbuf, sbsize); + return XFS_ERROR(EFSCORRUPTED); + } + + sbp->entno = i + 2; + sbp->seqno = 0; + sbp->hash = xfs_da_hashname((char *)sfe->name, sfe->namelen); + sbp->ino = XFS_GET_DIR_INO_ARCH(mp, sfe->inumber, ARCH_CONVERT); + sbp->name = (char *)sfe->name; + sbp->namelen = sfe->namelen; + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + sbp++; + } + + /* + * Sort the entries on hash then entno. + */ + qsort(sbuf, nsbuf, sizeof(*sbuf), xfs_dir_shortform_compare); + /* + * Stuff in last entry. + */ + sbp->entno = nsbuf; + sbp->hash = XFS_DA_MAXHASH; + sbp->seqno = 0; + /* + * Figure out the sequence numbers in case there's a hash duplicate. + */ + for (hash = sbuf->hash, sbp = sbuf + 1; + sbp < &sbuf[nsbuf + 1]; sbp++) { + if (sbp->hash == hash) + sbp->seqno = sbp[-1].seqno + 1; + else + hash = sbp->hash; + } + + /* + * Set up put routine. + */ + p.dbp = dbp; + p.put = put; + p.uio = uio; + + /* + * Find our place. + */ + for (sbp = sbuf; sbp < &sbuf[nsbuf + 1]; sbp++) { + if (sbp->hash > cookhash || + (sbp->hash == cookhash && sbp->seqno >= want_entno)) + break; + } + + /* + * Did we fail to find anything? We stop at the last entry, + * the one we put maxhash into. + */ + if (sbp == &sbuf[nsbuf]) { + kmem_free(sbuf, sbsize); + xfs_dir_trace_g_du("sf: hash beyond end", dp, uio); + uio->uio_offset = XFS_DA_MAKE_COOKIE(mp, 0, 0, XFS_DA_MAXHASH); + *eofp = 1; + return 0; + } + + /* + * Loop putting entries into the user buffer. + */ + while (sbp < &sbuf[nsbuf]) { + /* + * Save the first resid in a run of equal-hashval entries + * so that we can back them out if they don't all fit. + */ + if (sbp->seqno == 0 || sbp == sbuf) + lastresid = uio->uio_resid; + /* + * NOTE! Linux "filldir" semantics require that the + * offset "cookie" be for this entry, not the + * next; all the actual shuffling to make it + * "look right" to the user is done in filldir. + */ + XFS_PUT_COOKIE(p.cook, mp, 0, sbp->seqno, sbp->hash); + +#if XFS_BIG_FILESYSTEMS + p.ino = sbp->ino + mp->m_inoadd; +#else + p.ino = sbp->ino; +#endif + p.name = sbp->name; + p.namelen = sbp->namelen; + + retval = p.put(&p); + + if (!p.done) { + uio->uio_offset = + XFS_DA_MAKE_COOKIE(mp, 0, 0, sbp->hash); + kmem_free(sbuf, sbsize); + uio->uio_resid = lastresid; + xfs_dir_trace_g_du("sf: E-O-B", dp, uio); + return retval; + } + + sbp++; + } + + kmem_free(sbuf, sbsize); + + XFS_PUT_COOKIE(p.cook, mp, 0, 0, XFS_DA_MAXHASH); + + uio->uio_offset = p.cook.o; + + *eofp = 1; + + xfs_dir_trace_g_du("sf: E-O-F", dp, uio); + + return 0; +} + +/* + * Look up a name in a shortform directory structure, replace the inode number. + */ +int +xfs_dir_shortform_replace(xfs_da_args_t *args) +{ + xfs_dir_shortform_t *sf; + xfs_dir_sf_entry_t *sfe; + xfs_inode_t *dp; + int i; + + dp = args->dp; + ASSERT(dp->i_df.if_flags & XFS_IFINLINE); + /* + * Catch the case where the conversion from shortform to leaf + * failed part way through. + */ + if (dp->i_d.di_size < sizeof(xfs_dir_sf_hdr_t)) { + ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); + return XFS_ERROR(EIO); + } + ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); + ASSERT(dp->i_df.if_u1.if_data != NULL); + sf = (xfs_dir_shortform_t *)dp->i_df.if_u1.if_data; + if (args->namelen == 2 && + args->name[0] == '.' && args->name[1] == '.') { + /* XXX - replace assert? */ + XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sf->hdr.parent, ARCH_CONVERT); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); + return(0); + } + ASSERT(args->namelen != 1 || args->name[0] != '.'); + sfe = &sf->list[0]; + for (i = INT_GET(sf->hdr.count, ARCH_CONVERT)-1; i >= 0; i--) { + if (sfe->namelen == args->namelen && + sfe->name[0] == args->name[0] && + bcmp(args->name, sfe->name, args->namelen) == 0) { + ASSERT(bcmp((char *)&args->inumber, + (char *)&sfe->inumber, sizeof(xfs_ino_t))); + XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &sfe->inumber, ARCH_CONVERT); + xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); + return(0); + } + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } + ASSERT(args->oknoent); + return(XFS_ERROR(ENOENT)); +} + +/* + * Convert a leaf directory to shortform structure + */ +int +xfs_dir_leaf_to_shortform(xfs_da_args_t *iargs) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_hdr_t *hdr; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + xfs_da_args_t args; + xfs_inode_t *dp; + xfs_ino_t parent; + char *tmpbuffer; + int retval, i; + xfs_dabuf_t *bp; + + dp = iargs->dp; + tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP); + ASSERT(tmpbuffer != NULL); + + retval = xfs_da_read_buf(iargs->trans, iargs->dp, 0, -1, &bp, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + bcopy(bp->data, tmpbuffer, XFS_LBSIZE(dp->i_mount)); + leaf = (xfs_dir_leafblock_t *)tmpbuffer; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + bzero(bp->data, XFS_LBSIZE(dp->i_mount)); + + /* + * Find and special case the parent inode number + */ + hdr = &leaf->hdr; + entry = &leaf->entries[0]; + for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; i >= 0; entry++, i--) { + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + if ((entry->namelen == 2) && + (namest->name[0] == '.') && + (namest->name[1] == '.')) { + XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &parent, ARCH_CONVERT); + INT_ZERO(entry->nameidx, ARCH_CONVERT); + } else if ((entry->namelen == 1) && (namest->name[0] == '.')) { + INT_ZERO(entry->nameidx, ARCH_CONVERT); + } + } + retval = xfs_da_shrink_inode(iargs, 0, bp); + if (retval) + goto out; + retval = xfs_dir_shortform_create(iargs, parent); + if (retval) + goto out; + + /* + * Copy the rest of the filenames + */ + entry = &leaf->entries[0]; + args.dp = dp; + args.firstblock = iargs->firstblock; + args.flist = iargs->flist; + args.total = iargs->total; + args.whichfork = XFS_DATA_FORK; + args.trans = iargs->trans; + args.justcheck = 0; + args.addname = args.oknoent = 1; + for (i = 0; i < INT_GET(hdr->count, ARCH_CONVERT); entry++, i++) { + if (INT_GET(entry->nameidx, ARCH_CONVERT) == 0) + continue; + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + args.name = (char *)(namest->name); + args.namelen = entry->namelen; + args.hashval = INT_GET(entry->hashval, ARCH_CONVERT); + XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &args.inumber, ARCH_CONVERT); + xfs_dir_shortform_addname(&args); + } + +out: + kmem_free(tmpbuffer, XFS_LBSIZE(dp->i_mount)); + return(retval); +} + +/* + * Convert from using a single leaf to a root node and a leaf. + */ +int +xfs_dir_leaf_to_node(xfs_da_args_t *args) +{ + xfs_dir_leafblock_t *leaf; + xfs_da_intnode_t *node; + xfs_inode_t *dp; + xfs_dabuf_t *bp1, *bp2; + xfs_dablk_t blkno; + int retval; + + dp = args->dp; + retval = xfs_da_grow_inode(args, &blkno); + ASSERT(blkno == 1); + if (retval) + return(retval); + retval = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp1, + XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp1 != NULL); + retval = xfs_da_get_buf(args->trans, args->dp, 1, -1, &bp2, + XFS_DATA_FORK); + if (retval) { + xfs_da_buf_done(bp1); + return(retval); + } + ASSERT(bp2 != NULL); + bcopy(bp1->data, bp2->data, XFS_LBSIZE(dp->i_mount)); + xfs_da_buf_done(bp1); + xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1); + + /* + * Set up the new root node. + */ + retval = xfs_da_node_create(args, 0, 1, &bp1, XFS_DATA_FORK); + if (retval) { + xfs_da_buf_done(bp2); + return(retval); + } + node = bp1->data; + leaf = bp2->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + INT_SET(node->btree[0].hashval, ARCH_CONVERT, INT_GET(leaf->entries[ INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)); + xfs_da_buf_done(bp2); + INT_SET(node->btree[0].before, ARCH_CONVERT, blkno); + INT_SET(node->hdr.count, ARCH_CONVERT, 1); + xfs_da_log_buf(args->trans, bp1, + XFS_DA_LOGRANGE(node, &node->btree[0], sizeof(node->btree[0]))); + xfs_da_buf_done(bp1); + + return(retval); +} + + +/*======================================================================== + * Routines used for growing the Btree. + *========================================================================*/ + +/* + * Create the initial contents of a leaf directory + * or a leaf in a node directory. + */ +int +xfs_dir_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_hdr_t *hdr; + xfs_inode_t *dp; + xfs_dabuf_t *bp; + int retval; + + dp = args->dp; + ASSERT(dp != NULL); + retval = xfs_da_get_buf(args->trans, dp, blkno, -1, &bp, XFS_DATA_FORK); + if (retval) + return(retval); + ASSERT(bp != NULL); + leaf = bp->data; + bzero((char *)leaf, XFS_LBSIZE(dp->i_mount)); + hdr = &leaf->hdr; + INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_DIR_LEAF_MAGIC); + INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount)); + if (INT_ISZERO(hdr->firstused, ARCH_CONVERT)) + INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount) - 1); + INT_SET(hdr->freemap[0].base, ARCH_CONVERT, sizeof(xfs_dir_leaf_hdr_t)); + INT_SET(hdr->freemap[0].size, ARCH_CONVERT, INT_GET(hdr->firstused, ARCH_CONVERT) - INT_GET(hdr->freemap[0].base, ARCH_CONVERT)); + + xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1); + + *bpp = bp; + return(0); +} + +/* + * Split the leaf node, rebalance, then add the new entry. + */ +int +xfs_dir_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, + xfs_da_state_blk_t *newblk) +{ + xfs_dablk_t blkno; + xfs_da_args_t *args; + int error; + + /* + * Allocate space for a new leaf node. + */ + args = state->args; + ASSERT(args != NULL); + ASSERT(oldblk->magic == XFS_DIR_LEAF_MAGIC); + error = xfs_da_grow_inode(args, &blkno); + if (error) + return(error); + error = xfs_dir_leaf_create(args, blkno, &newblk->bp); + if (error) + return(error); + newblk->blkno = blkno; + newblk->magic = XFS_DIR_LEAF_MAGIC; + + /* + * Rebalance the entries across the two leaves. + */ + xfs_dir_leaf_rebalance(state, oldblk, newblk); + error = xfs_da_blk_link(state, oldblk, newblk); + if (error) + return(error); + + /* + * Insert the new entry in the correct block. + */ + if (state->inleaf) { + error = xfs_dir_leaf_add(oldblk->bp, args, oldblk->index); + } else { + error = xfs_dir_leaf_add(newblk->bp, args, newblk->index); + } + + /* + * Update last hashval in each block since we added the name. + */ + oldblk->hashval = xfs_dir_leaf_lasthash(oldblk->bp, NULL); + newblk->hashval = xfs_dir_leaf_lasthash(newblk->bp, NULL); + return(error); +} + +/* + * Add a name to the leaf directory structure. + * + * Must take into account fragmented leaves and leaves where spacemap has + * lost some freespace information (ie: holes). + */ +int +xfs_dir_leaf_add(xfs_dabuf_t *bp, xfs_da_args_t *args, int index) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_hdr_t *hdr; + xfs_dir_leaf_map_t *map; + int tablesize, entsize, sum, i, tmp, error; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + ASSERT((index >= 0) && (index <= INT_GET(leaf->hdr.count, ARCH_CONVERT))); + hdr = &leaf->hdr; + entsize = XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen); + + /* + * Search through freemap for first-fit on new name length. + * (may need to figure in size of entry struct too) + */ + tablesize = (INT_GET(hdr->count, ARCH_CONVERT) + 1) * (uint)sizeof(xfs_dir_leaf_entry_t) + + (uint)sizeof(xfs_dir_leaf_hdr_t); + map = &hdr->freemap[XFS_DIR_LEAF_MAPSIZE-1]; + for (sum = 0, i = XFS_DIR_LEAF_MAPSIZE-1; i >= 0; map--, i--) { + if (tablesize > INT_GET(hdr->firstused, ARCH_CONVERT)) { + sum += INT_GET(map->size, ARCH_CONVERT); + continue; + } + if (INT_GET(map->size, ARCH_CONVERT) == 0) + continue; /* no space in this map */ + tmp = entsize; + if (INT_GET(map->base, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT)) + tmp += (uint)sizeof(xfs_dir_leaf_entry_t); + if (INT_GET(map->size, ARCH_CONVERT) >= tmp) { + if (!args->justcheck) + xfs_dir_leaf_add_work(bp, args, index, i); + return(0); + } + sum += INT_GET(map->size, ARCH_CONVERT); + } + + /* + * If there are no holes in the address space of the block, + * and we don't have enough freespace, then compaction will do us + * no good and we should just give up. + */ + if (!hdr->holes && (sum < entsize)) + return(XFS_ERROR(ENOSPC)); + + /* + * Compact the entries to coalesce free space. + * Pass the justcheck flag so the checking pass can return + * an error, without changing anything, if it won't fit. + */ + error = xfs_dir_leaf_compact(args->trans, bp, + args->total == 0 ? + entsize + + (uint)sizeof(xfs_dir_leaf_entry_t) : 0, + args->justcheck); + if (error) + return(error); + /* + * After compaction, the block is guaranteed to have only one + * free region, in freemap[0]. If it is not big enough, give up. + */ + if (INT_GET(hdr->freemap[0].size, ARCH_CONVERT) < + (entsize + (uint)sizeof(xfs_dir_leaf_entry_t))) + return(XFS_ERROR(ENOSPC)); + + if (!args->justcheck) + xfs_dir_leaf_add_work(bp, args, index, 0); + return(0); +} + +/* + * Add a name to a leaf directory structure. + */ +STATIC void +xfs_dir_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int index, + int mapindex) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_hdr_t *hdr; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + xfs_dir_leaf_map_t *map; + /* REFERENCED */ + xfs_mount_t *mp; + int tmp, i; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + hdr = &leaf->hdr; + ASSERT((mapindex >= 0) && (mapindex < XFS_DIR_LEAF_MAPSIZE)); + ASSERT((index >= 0) && (index <= INT_GET(hdr->count, ARCH_CONVERT))); + + /* + * Force open some space in the entry array and fill it in. + */ + entry = &leaf->entries[index]; + if (index < INT_GET(hdr->count, ARCH_CONVERT)) { + tmp = INT_GET(hdr->count, ARCH_CONVERT) - index; + tmp *= (uint)sizeof(xfs_dir_leaf_entry_t); + ovbcopy(entry, entry + 1, tmp); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry))); + } + INT_MOD(hdr->count, ARCH_CONVERT, +1); + + /* + * Allocate space for the new string (at the end of the run). + */ + map = &hdr->freemap[mapindex]; + mp = args->trans->t_mountp; + ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT(INT_GET(map->size, ARCH_CONVERT) >= XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen)); + ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); + INT_MOD(map->size, ARCH_CONVERT, -(XFS_DIR_LEAF_ENTSIZE_BYNAME(args->namelen))); + INT_SET(entry->nameidx, ARCH_CONVERT, INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)); + INT_SET(entry->hashval, ARCH_CONVERT, args->hashval); + entry->namelen = args->namelen; + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); + + /* + * Copy the string and inode number into the new space. + */ + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + XFS_DIR_SF_PUT_DIRINO_ARCH(&args->inumber, &namest->inumber, ARCH_CONVERT); + bcopy(args->name, namest->name, args->namelen); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, namest, XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry))); + + /* + * Update the control info for this leaf node + */ + if (INT_GET(entry->nameidx, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT)) + INT_COPY(hdr->firstused, entry->nameidx, ARCH_CONVERT); + ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) >= ((INT_GET(hdr->count, ARCH_CONVERT)*sizeof(*entry))+sizeof(*hdr))); + tmp = (INT_GET(hdr->count, ARCH_CONVERT)-1) * (uint)sizeof(xfs_dir_leaf_entry_t) + + (uint)sizeof(xfs_dir_leaf_hdr_t); + map = &hdr->freemap[0]; + for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; map++, i++) { + if (INT_GET(map->base, ARCH_CONVERT) == tmp) { + INT_MOD(map->base, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_entry_t)); + INT_MOD(map->size, ARCH_CONVERT, -((uint)sizeof(xfs_dir_leaf_entry_t))); + } + } + INT_MOD(hdr->namebytes, ARCH_CONVERT, args->namelen); + xfs_da_log_buf(args->trans, bp, + XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); +} + +/* + * Garbage collect a leaf directory block by copying it to a new buffer. + */ +STATIC int +xfs_dir_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp, int musthave, + int justcheck) +{ + xfs_dir_leafblock_t *leaf_s, *leaf_d; + xfs_dir_leaf_hdr_t *hdr_s, *hdr_d; + xfs_mount_t *mp; + char *tmpbuffer; + char *tmpbuffer2=NULL; + int rval; + int lbsize; + + mp = trans->t_mountp; + lbsize = XFS_LBSIZE(mp); + tmpbuffer = kmem_alloc(lbsize, KM_SLEEP); + ASSERT(tmpbuffer != NULL); + bcopy(bp->data, tmpbuffer, lbsize); + + /* + * Make a second copy in case xfs_dir_leaf_moveents() + * below destroys the original. + */ + if (musthave || justcheck) { + tmpbuffer2 = kmem_alloc(lbsize, KM_SLEEP); + bcopy(bp->data, tmpbuffer2, lbsize); + } + bzero(bp->data, lbsize); + + /* + * Copy basic information + */ + leaf_s = (xfs_dir_leafblock_t *)tmpbuffer; + leaf_d = bp->data; + hdr_s = &leaf_s->hdr; + hdr_d = &leaf_d->hdr; + hdr_d->info = hdr_s->info; /* struct copy */ + INT_SET(hdr_d->firstused, ARCH_CONVERT, lbsize); + if (INT_GET(hdr_d->firstused, ARCH_CONVERT) == 0) + INT_SET(hdr_d->firstused, ARCH_CONVERT, lbsize - 1); + INT_ZERO(hdr_d->namebytes, ARCH_CONVERT); + INT_ZERO(hdr_d->count, ARCH_CONVERT); + hdr_d->holes = 0; + INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, sizeof(xfs_dir_leaf_hdr_t)); + INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, INT_GET(hdr_d->firstused, ARCH_CONVERT) - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); + + /* + * Copy all entry's in the same (sorted) order, + * but allocate filenames packed and in sequence. + * This changes the source (leaf_s) as well. + */ + xfs_dir_leaf_moveents(leaf_s, 0, leaf_d, 0, (int)INT_GET(hdr_s->count, ARCH_CONVERT), mp); + + if (musthave && INT_GET(hdr_d->freemap[0].size, ARCH_CONVERT) < musthave) + rval = XFS_ERROR(ENOSPC); + else + rval = 0; + + if (justcheck || rval == ENOSPC) { + ASSERT(tmpbuffer2); + bcopy(tmpbuffer2, bp->data, lbsize); + } else { + xfs_da_log_buf(trans, bp, 0, lbsize - 1); + } + + kmem_free(tmpbuffer, lbsize); + if (musthave || justcheck) + kmem_free(tmpbuffer2, lbsize); + return(rval); +} + +/* + * Redistribute the directory entries between two leaf nodes, + * taking into account the size of the new entry. + * + * NOTE: if new block is empty, then it will get the upper half of old block. + */ +STATIC void +xfs_dir_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2) +{ + xfs_da_state_blk_t *tmp_blk; + xfs_dir_leafblock_t *leaf1, *leaf2; + xfs_dir_leaf_hdr_t *hdr1, *hdr2; + int count, totallen, max, space, swap; + + /* + * Set up environment. + */ + ASSERT(blk1->magic == XFS_DIR_LEAF_MAGIC); + ASSERT(blk2->magic == XFS_DIR_LEAF_MAGIC); + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + + /* + * Check ordering of blocks, reverse if it makes things simpler. + */ + swap = 0; + if (xfs_dir_leaf_order(blk1->bp, blk2->bp)) { + tmp_blk = blk1; + blk1 = blk2; + blk2 = tmp_blk; + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + swap = 1; + } + hdr1 = &leaf1->hdr; + hdr2 = &leaf2->hdr; + + /* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. Then get + * the direction to copy and the number of elements to move. + */ + state->inleaf = xfs_dir_leaf_figure_balance(state, blk1, blk2, + &count, &totallen); + if (swap) + state->inleaf = !state->inleaf; + + /* + * Move any entries required from leaf to leaf: + */ + if (count < INT_GET(hdr1->count, ARCH_CONVERT)) { + /* + * Figure the total bytes to be added to the destination leaf. + */ + count = INT_GET(hdr1->count, ARCH_CONVERT) - count; /* number entries being moved */ + space = INT_GET(hdr1->namebytes, ARCH_CONVERT) - totallen; + space += count * ((uint)sizeof(xfs_dir_leaf_name_t)-1); + space += count * (uint)sizeof(xfs_dir_leaf_entry_t); + + /* + * leaf2 is the destination, compact it if it looks tight. + */ + max = INT_GET(hdr2->firstused, ARCH_CONVERT) - (uint)sizeof(xfs_dir_leaf_hdr_t); + max -= INT_GET(hdr2->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t); + if (space > max) { + xfs_dir_leaf_compact(state->args->trans, blk2->bp, + 0, 0); + } + + /* + * Move high entries from leaf1 to low end of leaf2. + */ + xfs_dir_leaf_moveents(leaf1, INT_GET(hdr1->count, ARCH_CONVERT) - count, + leaf2, 0, count, state->mp); + + xfs_da_log_buf(state->args->trans, blk1->bp, 0, + state->blocksize-1); + xfs_da_log_buf(state->args->trans, blk2->bp, 0, + state->blocksize-1); + + } else if (count > INT_GET(hdr1->count, ARCH_CONVERT)) { + /* + * Figure the total bytes to be added to the destination leaf. + */ + count -= INT_GET(hdr1->count, ARCH_CONVERT); /* number entries being moved */ + space = totallen - INT_GET(hdr1->namebytes, ARCH_CONVERT); + space += count * ((uint)sizeof(xfs_dir_leaf_name_t)-1); + space += count * (uint)sizeof(xfs_dir_leaf_entry_t); + + /* + * leaf1 is the destination, compact it if it looks tight. + */ + max = INT_GET(hdr1->firstused, ARCH_CONVERT) - (uint)sizeof(xfs_dir_leaf_hdr_t); + max -= INT_GET(hdr1->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t); + if (space > max) { + xfs_dir_leaf_compact(state->args->trans, blk1->bp, + 0, 0); + } + + /* + * Move low entries from leaf2 to high end of leaf1. + */ + xfs_dir_leaf_moveents(leaf2, 0, leaf1, (int)INT_GET(hdr1->count, ARCH_CONVERT), + count, state->mp); + + xfs_da_log_buf(state->args->trans, blk1->bp, 0, + state->blocksize-1); + xfs_da_log_buf(state->args->trans, blk2->bp, 0, + state->blocksize-1); + } + + /* + * Copy out last hashval in each block for B-tree code. + */ + blk1->hashval = INT_GET(leaf1->entries[ INT_GET(leaf1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + blk2->hashval = INT_GET(leaf2->entries[ INT_GET(leaf2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); + + /* + * Adjust the expected index for insertion. + * GROT: this doesn't work unless blk2 was originally empty. + */ + if (!state->inleaf) { + blk2->index = blk1->index - INT_GET(leaf1->hdr.count, ARCH_CONVERT); + } +} + +/* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. + * GROT: Is this really necessary? With other than a 512 byte blocksize, + * GROT: there will always be enough room in either block for a new entry. + * GROT: Do a double-split for this case? + */ +STATIC int +xfs_dir_leaf_figure_balance(xfs_da_state_t *state, + xfs_da_state_blk_t *blk1, + xfs_da_state_blk_t *blk2, + int *countarg, int *namebytesarg) +{ + xfs_dir_leafblock_t *leaf1, *leaf2; + xfs_dir_leaf_hdr_t *hdr1, *hdr2; + xfs_dir_leaf_entry_t *entry; + int count, max, totallen, half; + int lastdelta, foundit, tmp; + + /* + * Set up environment. + */ + leaf1 = blk1->bp->data; + leaf2 = blk2->bp->data; + hdr1 = &leaf1->hdr; + hdr2 = &leaf2->hdr; + foundit = 0; + totallen = 0; + + /* + * Examine entries until we reduce the absolute difference in + * byte usage between the two blocks to a minimum. + */ + max = INT_GET(hdr1->count, ARCH_CONVERT) + INT_GET(hdr2->count, ARCH_CONVERT); + half = (max+1) * (uint)(sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1); + half += INT_GET(hdr1->namebytes, ARCH_CONVERT) + INT_GET(hdr2->namebytes, ARCH_CONVERT) + state->args->namelen; + half /= 2; + lastdelta = state->blocksize; + entry = &leaf1->entries[0]; + for (count = 0; count < max; entry++, count++) { + +#define XFS_DIR_ABS(A) (((A) < 0) ? -(A) : (A)) + /* + * The new entry is in the first block, account for it. + */ + if (count == blk1->index) { + tmp = totallen + (uint)sizeof(*entry) + + XFS_DIR_LEAF_ENTSIZE_BYNAME(state->args->namelen); + if (XFS_DIR_ABS(half - tmp) > lastdelta) + break; + lastdelta = XFS_DIR_ABS(half - tmp); + totallen = tmp; + foundit = 1; + } + + /* + * Wrap around into the second block if necessary. + */ + if (count == INT_GET(hdr1->count, ARCH_CONVERT)) { + leaf1 = leaf2; + entry = &leaf1->entries[0]; + } + + /* + * Figure out if next leaf entry would be too much. + */ + tmp = totallen + (uint)sizeof(*entry) + + XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry); + if (XFS_DIR_ABS(half - tmp) > lastdelta) + break; + lastdelta = XFS_DIR_ABS(half - tmp); + totallen = tmp; +#undef XFS_DIR_ABS + } + + /* + * Calculate the number of namebytes that will end up in lower block. + * If new entry not in lower block, fix up the count. + */ + totallen -= + count * (uint)(sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1); + if (foundit) { + totallen -= (sizeof(*entry)+sizeof(xfs_dir_leaf_entry_t)-1) + + state->args->namelen; + } + + *countarg = count; + *namebytesarg = totallen; + return(foundit); +} + +/*======================================================================== + * Routines used for shrinking the Btree. + *========================================================================*/ + +/* + * Check a leaf block and its neighbors to see if the block should be + * collapsed into one or the other neighbor. Always keep the block + * with the smaller block number. + * If the current block is over 50% full, don't try to join it, return 0. + * If the block is empty, fill in the state structure and return 2. + * If it can be collapsed, fill in the state structure and return 1. + * If nothing can be done, return 0. + */ +int +xfs_dir_leaf_toosmall(xfs_da_state_t *state, int *action) +{ + xfs_dir_leafblock_t *leaf; + xfs_da_state_blk_t *blk; + xfs_da_blkinfo_t *info; + int count, bytes, forward, error, retval, i; + xfs_dablk_t blkno; + xfs_dabuf_t *bp; + + /* + * Check for the degenerate case of the block being over 50% full. + * If so, it's not worth even looking to see if we might be able + * to coalesce with a sibling. + */ + blk = &state->path.blk[ state->path.active-1 ]; + info = blk->bp->data; + ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + leaf = (xfs_dir_leafblock_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes = (uint)sizeof(xfs_dir_leaf_hdr_t) + + count * (uint)sizeof(xfs_dir_leaf_entry_t) + + count * ((uint)sizeof(xfs_dir_leaf_name_t)-1) + + INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); + if (bytes > (state->blocksize >> 1)) { + *action = 0; /* blk over 50%, dont try to join */ + return(0); + } + + /* + * Check for the degenerate case of the block being empty. + * If the block is empty, we'll simply delete it, no need to + * coalesce it with a sibling block. We choose (aribtrarily) + * to merge with the forward block unless it is NULL. + */ + if (count == 0) { + /* + * Make altpath point to the block we want to keep and + * path point to the block we want to drop (this one). + */ + forward = !INT_ISZERO(info->forw, ARCH_CONVERT); + bcopy(&state->path, &state->altpath, sizeof(state->path)); + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + if (error) + return(error); + if (retval) { + *action = 0; + } else { + *action = 2; + } + return(0); + } + + /* + * Examine each sibling block to see if we can coalesce with + * at least 25% free space to spare. We need to figure out + * whether to merge with the forward or the backward block. + * We prefer coalescing with the lower numbered sibling so as + * to shrink a directory over time. + */ + forward = (INT_GET(info->forw, ARCH_CONVERT) < INT_GET(info->back, ARCH_CONVERT)); /* start with smaller blk num */ + for (i = 0; i < 2; forward = !forward, i++) { + if (forward) + blkno = INT_GET(info->forw, ARCH_CONVERT); + else + blkno = INT_GET(info->back, ARCH_CONVERT); + if (blkno == 0) + continue; + error = xfs_da_read_buf(state->args->trans, state->args->dp, + blkno, -1, &bp, + XFS_DATA_FORK); + if (error) + return(error); + ASSERT(bp != NULL); + + leaf = (xfs_dir_leafblock_t *)info; + count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes = state->blocksize - (state->blocksize>>2); + bytes -= INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + count += INT_GET(leaf->hdr.count, ARCH_CONVERT); + bytes -= INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); + bytes -= count * ((uint)sizeof(xfs_dir_leaf_name_t) - 1); + bytes -= count * (uint)sizeof(xfs_dir_leaf_entry_t); + bytes -= (uint)sizeof(xfs_dir_leaf_hdr_t); + if (bytes >= 0) + break; /* fits with at least 25% to spare */ + + xfs_da_brelse(state->args->trans, bp); + } + if (i >= 2) { + *action = 0; + return(0); + } + xfs_da_buf_done(bp); + + /* + * Make altpath point to the block we want to keep (the lower + * numbered block) and path point to the block we want to drop. + */ + bcopy(&state->path, &state->altpath, sizeof(state->path)); + if (blkno < blk->blkno) { + error = xfs_da_path_shift(state, &state->altpath, forward, + 0, &retval); + } else { + error = xfs_da_path_shift(state, &state->path, forward, + 0, &retval); + } + if (error) + return(error); + if (retval) { + *action = 0; + } else { + *action = 1; + } + return(0); +} + +/* + * Remove a name from the leaf directory structure. + * + * Return 1 if leaf is less than 37% full, 0 if >= 37% full. + * If two leaves are 37% full, when combined they will leave 25% free. + */ +int +xfs_dir_leaf_remove(xfs_trans_t *trans, xfs_dabuf_t *bp, int index) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_hdr_t *hdr; + xfs_dir_leaf_map_t *map; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + int before, after, smallest, entsize; + int tablesize, tmp, i; + xfs_mount_t *mp; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + hdr = &leaf->hdr; + mp = trans->t_mountp; + ASSERT((INT_GET(hdr->count, ARCH_CONVERT) > 0) && (INT_GET(hdr->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8))); + ASSERT((index >= 0) && (index < INT_GET(hdr->count, ARCH_CONVERT))); + ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT) >= ((INT_GET(hdr->count, ARCH_CONVERT)*sizeof(*entry))+sizeof(*hdr))); + entry = &leaf->entries[index]; + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >= INT_GET(hdr->firstused, ARCH_CONVERT)); + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp)); + + /* + * Scan through free region table: + * check for adjacency of free'd entry with an existing one, + * find smallest free region in case we need to replace it, + * adjust any map that borders the entry table, + */ + tablesize = INT_GET(hdr->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t) + + (uint)sizeof(xfs_dir_leaf_hdr_t); + map = &hdr->freemap[0]; + tmp = INT_GET(map->size, ARCH_CONVERT); + before = after = -1; + smallest = XFS_DIR_LEAF_MAPSIZE - 1; + entsize = XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry); + for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; map++, i++) { + ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp)); + ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp)); + if (INT_GET(map->base, ARCH_CONVERT) == tablesize) { + INT_MOD(map->base, ARCH_CONVERT, -((uint)sizeof(xfs_dir_leaf_entry_t))); + INT_MOD(map->size, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_entry_t)); + } + + if ((INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)) == INT_GET(entry->nameidx, ARCH_CONVERT)) { + before = i; + } else if (INT_GET(map->base, ARCH_CONVERT) == (INT_GET(entry->nameidx, ARCH_CONVERT) + entsize)) { + after = i; + } else if (INT_GET(map->size, ARCH_CONVERT) < tmp) { + tmp = INT_GET(map->size, ARCH_CONVERT); + smallest = i; + } + } + + /* + * Coalesce adjacent freemap regions, + * or replace the smallest region. + */ + if ((before >= 0) || (after >= 0)) { + if ((before >= 0) && (after >= 0)) { + map = &hdr->freemap[before]; + INT_MOD(map->size, ARCH_CONVERT, entsize); + INT_MOD(map->size, ARCH_CONVERT, INT_GET(hdr->freemap[after].size, ARCH_CONVERT)); + INT_ZERO(hdr->freemap[after].base, ARCH_CONVERT); + INT_ZERO(hdr->freemap[after].size, ARCH_CONVERT); + } else if (before >= 0) { + map = &hdr->freemap[before]; + INT_MOD(map->size, ARCH_CONVERT, entsize); + } else { + map = &hdr->freemap[after]; + INT_COPY(map->base, entry->nameidx, ARCH_CONVERT); + INT_MOD(map->size, ARCH_CONVERT, entsize); + } + } else { + /* + * Replace smallest region (if it is smaller than free'd entry) + */ + map = &hdr->freemap[smallest]; + if (INT_GET(map->size, ARCH_CONVERT) < entsize) { + INT_COPY(map->base, entry->nameidx, ARCH_CONVERT); + INT_SET(map->size, ARCH_CONVERT, entsize); + } + } + + /* + * Did we remove the first entry? + */ + if (INT_GET(entry->nameidx, ARCH_CONVERT) == INT_GET(hdr->firstused, ARCH_CONVERT)) + smallest = 1; + else + smallest = 0; + + /* + * Compress the remaining entries and zero out the removed stuff. + */ + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + bzero((char *)namest, entsize); + xfs_da_log_buf(trans, bp, XFS_DA_LOGRANGE(leaf, namest, entsize)); + + INT_MOD(hdr->namebytes, ARCH_CONVERT, -(entry->namelen)); + tmp = (INT_GET(hdr->count, ARCH_CONVERT) - index) * (uint)sizeof(xfs_dir_leaf_entry_t); + ovbcopy(entry + 1, entry, tmp); + INT_MOD(hdr->count, ARCH_CONVERT, -1); + xfs_da_log_buf(trans, bp, + XFS_DA_LOGRANGE(leaf, entry, tmp + (uint)sizeof(*entry))); + entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)]; + bzero((char *)entry, sizeof(xfs_dir_leaf_entry_t)); + + /* + * If we removed the first entry, re-find the first used byte + * in the name area. Note that if the entry was the "firstused", + * then we don't have a "hole" in our block resulting from + * removing the name. + */ + if (smallest) { + tmp = XFS_LBSIZE(mp); + entry = &leaf->entries[0]; + for (i = INT_GET(hdr->count, ARCH_CONVERT)-1; i >= 0; entry++, i--) { + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) >= INT_GET(hdr->firstused, ARCH_CONVERT)); + ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp)); + if (INT_GET(entry->nameidx, ARCH_CONVERT) < tmp) + tmp = INT_GET(entry->nameidx, ARCH_CONVERT); + } + INT_SET(hdr->firstused, ARCH_CONVERT, tmp); + if (INT_GET(hdr->firstused, ARCH_CONVERT) == 0) + INT_SET(hdr->firstused, ARCH_CONVERT, tmp - 1); + } else { + hdr->holes = 1; /* mark as needing compaction */ + } + + xfs_da_log_buf(trans, bp, XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); + + /* + * Check if leaf is less than 50% full, caller may want to + * "join" the leaf with a sibling if so. + */ + tmp = (uint)sizeof(xfs_dir_leaf_hdr_t); + tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t); + tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT) * ((uint)sizeof(xfs_dir_leaf_name_t) - 1); + tmp += INT_GET(leaf->hdr.namebytes, ARCH_CONVERT); + if (tmp < mp->m_dir_magicpct) + return(1); /* leaf is < 37% full */ + return(0); +} + +/* + * Move all the directory entries from drop_leaf into save_leaf. + */ +void +xfs_dir_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, + xfs_da_state_blk_t *save_blk) +{ + xfs_dir_leafblock_t *drop_leaf, *save_leaf, *tmp_leaf; + xfs_dir_leaf_hdr_t *drop_hdr, *save_hdr, *tmp_hdr; + xfs_mount_t *mp; + char *tmpbuffer; + + /* + * Set up environment. + */ + mp = state->mp; + ASSERT(drop_blk->magic == XFS_DIR_LEAF_MAGIC); + ASSERT(save_blk->magic == XFS_DIR_LEAF_MAGIC); + drop_leaf = drop_blk->bp->data; + save_leaf = save_blk->bp->data; + ASSERT(INT_GET(drop_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + ASSERT(INT_GET(save_leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + drop_hdr = &drop_leaf->hdr; + save_hdr = &save_leaf->hdr; + + /* + * Save last hashval from dying block for later Btree fixup. + */ + drop_blk->hashval = INT_GET(drop_leaf->entries[ drop_leaf->hdr.count-1 ].hashval, ARCH_CONVERT); + + /* + * Check if we need a temp buffer, or can we do it in place. + * Note that we don't check "leaf" for holes because we will + * always be dropping it, toosmall() decided that for us already. + */ + if (save_hdr->holes == 0) { + /* + * dest leaf has no holes, so we add there. May need + * to make some room in the entry array. + */ + if (xfs_dir_leaf_order(save_blk->bp, drop_blk->bp)) { + xfs_dir_leaf_moveents(drop_leaf, 0, save_leaf, 0, + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); + } else { + xfs_dir_leaf_moveents(drop_leaf, 0, + save_leaf, INT_GET(save_hdr->count, ARCH_CONVERT), + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); + } + } else { + /* + * Destination has holes, so we make a temporary copy + * of the leaf and add them both to that. + */ + tmpbuffer = kmem_alloc(state->blocksize, KM_SLEEP); + ASSERT(tmpbuffer != NULL); + bzero(tmpbuffer, state->blocksize); + tmp_leaf = (xfs_dir_leafblock_t *)tmpbuffer; + tmp_hdr = &tmp_leaf->hdr; + tmp_hdr->info = save_hdr->info; /* struct copy */ + INT_ZERO(tmp_hdr->count, ARCH_CONVERT); + INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize); + if (INT_GET(tmp_hdr->firstused, ARCH_CONVERT) == 0) + INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize - 1); + INT_ZERO(tmp_hdr->namebytes, ARCH_CONVERT); + if (xfs_dir_leaf_order(save_blk->bp, drop_blk->bp)) { + xfs_dir_leaf_moveents(drop_leaf, 0, tmp_leaf, 0, + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); + xfs_dir_leaf_moveents(save_leaf, 0, + tmp_leaf, INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), + (int)INT_GET(save_hdr->count, ARCH_CONVERT), mp); + } else { + xfs_dir_leaf_moveents(save_leaf, 0, tmp_leaf, 0, + (int)INT_GET(save_hdr->count, ARCH_CONVERT), mp); + xfs_dir_leaf_moveents(drop_leaf, 0, + tmp_leaf, INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT), + (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp); + } + bcopy(tmp_leaf, save_leaf, state->blocksize); + kmem_free(tmpbuffer, state->blocksize); + } + + xfs_da_log_buf(state->args->trans, save_blk->bp, 0, + state->blocksize - 1); + + /* + * Copy out last hashval in each block for B-tree code. + */ + save_blk->hashval = INT_GET(save_leaf->entries[ INT_GET(save_leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT); +} + +/*======================================================================== + * Routines used for finding things in the Btree. + *========================================================================*/ + +/* + * Look up a name in a leaf directory structure. + * This is the internal routine, it uses the caller's buffer. + * + * Note that duplicate keys are allowed, but only check within the + * current leaf node. The Btree code must check in adjacent leaf nodes. + * + * Return in *index the index into the entry[] array of either the found + * entry, or where the entry should have been (insert before that entry). + * + * Don't change the args->inumber unless we find the filename. + */ +int +xfs_dir_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args, int *index) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + int probe, span; + xfs_dahash_t hashval; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) < (XFS_LBSIZE(args->dp->i_mount)/8)); + + /* + * Binary search. (note: small blocks will skip this loop) + */ + hashval = args->hashval; + probe = span = INT_GET(leaf->hdr.count, ARCH_CONVERT) / 2; + for (entry = &leaf->entries[probe]; span > 4; + entry = &leaf->entries[probe]) { + span /= 2; + if (INT_GET(entry->hashval, ARCH_CONVERT) < hashval) + probe += span; + else if (INT_GET(entry->hashval, ARCH_CONVERT) > hashval) + probe -= span; + else + break; + } + ASSERT((probe >= 0) && \ + ((INT_GET(leaf->hdr.count, ARCH_CONVERT) == 0) || (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)))); + ASSERT((span <= 4) || (INT_GET(entry->hashval, ARCH_CONVERT) == hashval)); + + /* + * Since we may have duplicate hashval's, find the first matching + * hashval in the leaf. + */ + while ((probe > 0) && (INT_GET(entry->hashval, ARCH_CONVERT) >= hashval)) { + entry--; + probe--; + } + while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) && (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)) { + entry++; + probe++; + } + if ((probe == INT_GET(leaf->hdr.count, ARCH_CONVERT)) || (INT_GET(entry->hashval, ARCH_CONVERT) != hashval)) { + *index = probe; + ASSERT(args->oknoent); + return(XFS_ERROR(ENOENT)); + } + + /* + * Duplicate keys may be present, so search all of them for a match. + */ + while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT)) && (INT_GET(entry->hashval, ARCH_CONVERT) == hashval)) { + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)); + if (entry->namelen == args->namelen && + namest->name[0] == args->name[0] && + bcmp(args->name, namest->name, args->namelen) == 0) { + XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &args->inumber, ARCH_CONVERT); + *index = probe; + return(XFS_ERROR(EEXIST)); + } + entry++; + probe++; + } + *index = probe; + ASSERT(probe == INT_GET(leaf->hdr.count, ARCH_CONVERT) || args->oknoent); + return(XFS_ERROR(ENOENT)); +} + +/*======================================================================== + * Utility routines. + *========================================================================*/ + +/* + * Move the indicated entries from one leaf to another. + * NOTE: this routine modifies both source and destination leaves. + */ +/* ARGSUSED */ +STATIC void +xfs_dir_leaf_moveents(xfs_dir_leafblock_t *leaf_s, int start_s, + xfs_dir_leafblock_t *leaf_d, int start_d, + int count, xfs_mount_t *mp) +{ + xfs_dir_leaf_hdr_t *hdr_s, *hdr_d; + xfs_dir_leaf_entry_t *entry_s, *entry_d; + int tmp, i; + + /* + * Check for nothing to do. + */ + if (count == 0) + return; + + /* + * Set up environment. + */ + ASSERT(INT_GET(leaf_s->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + ASSERT(INT_GET(leaf_d->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + hdr_s = &leaf_s->hdr; + hdr_d = &leaf_d->hdr; + ASSERT((INT_GET(hdr_s->count, ARCH_CONVERT) > 0) && (INT_GET(hdr_s->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8))); + ASSERT(INT_GET(hdr_s->firstused, ARCH_CONVERT) >= + ((INT_GET(hdr_s->count, ARCH_CONVERT)*sizeof(*entry_s))+sizeof(*hdr_s))); + ASSERT(INT_GET(hdr_d->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8)); + ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= + ((INT_GET(hdr_d->count, ARCH_CONVERT)*sizeof(*entry_d))+sizeof(*hdr_d))); + + ASSERT(start_s < INT_GET(hdr_s->count, ARCH_CONVERT)); + ASSERT(start_d <= INT_GET(hdr_d->count, ARCH_CONVERT)); + ASSERT(count <= INT_GET(hdr_s->count, ARCH_CONVERT)); + + /* + * Move the entries in the destination leaf up to make a hole? + */ + if (start_d < INT_GET(hdr_d->count, ARCH_CONVERT)) { + tmp = INT_GET(hdr_d->count, ARCH_CONVERT) - start_d; + tmp *= (uint)sizeof(xfs_dir_leaf_entry_t); + entry_s = &leaf_d->entries[start_d]; + entry_d = &leaf_d->entries[start_d + count]; + bcopy(entry_s, entry_d, tmp); + } + + /* + * Copy all entry's in the same (sorted) order, + * but allocate filenames packed and in sequence. + */ + entry_s = &leaf_s->entries[start_s]; + entry_d = &leaf_d->entries[start_d]; + for (i = 0; i < count; entry_s++, entry_d++, i++) { + ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) >= INT_GET(hdr_s->firstused, ARCH_CONVERT)); + ASSERT(entry_s->namelen < MAXNAMELEN); + tmp = XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry_s); + INT_MOD(hdr_d->firstused, ARCH_CONVERT, -(tmp)); + entry_d->hashval = entry_s->hashval; /* INT_: direct copy */ + INT_COPY(entry_d->nameidx, hdr_d->firstused, ARCH_CONVERT); + entry_d->namelen = entry_s->namelen; + ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp)); + bcopy(XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)), + XFS_DIR_LEAF_NAMESTRUCT(leaf_d, INT_GET(entry_d->nameidx, ARCH_CONVERT)), tmp); + ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp <= XFS_LBSIZE(mp)); + bzero((char *)XFS_DIR_LEAF_NAMESTRUCT(leaf_s, INT_GET(entry_s->nameidx, ARCH_CONVERT)), + tmp); + INT_MOD(hdr_s->namebytes, ARCH_CONVERT, -(entry_d->namelen)); + INT_MOD(hdr_d->namebytes, ARCH_CONVERT, entry_d->namelen); + INT_MOD(hdr_s->count, ARCH_CONVERT, -1); + INT_MOD(hdr_d->count, ARCH_CONVERT, +1); + tmp = INT_GET(hdr_d->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t) + + (uint)sizeof(xfs_dir_leaf_hdr_t); + ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= tmp); + + } + + /* + * Zero out the entries we just copied. + */ + if (start_s == INT_GET(hdr_s->count, ARCH_CONVERT)) { + tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t); + entry_s = &leaf_s->entries[start_s]; + ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp)); + bzero((char *)entry_s, tmp); + } else { + /* + * Move the remaining entries down to fill the hole, + * then zero the entries at the top. + */ + tmp = INT_GET(hdr_s->count, ARCH_CONVERT) - count; + tmp *= (uint)sizeof(xfs_dir_leaf_entry_t); + entry_s = &leaf_s->entries[start_s + count]; + entry_d = &leaf_s->entries[start_s]; + bcopy(entry_s, entry_d, tmp); + + tmp = count * (uint)sizeof(xfs_dir_leaf_entry_t); + entry_s = &leaf_s->entries[INT_GET(hdr_s->count, ARCH_CONVERT)]; + ASSERT((char *)entry_s + tmp <= (char *)leaf_s + XFS_LBSIZE(mp)); + bzero((char *)entry_s, tmp); + } + + /* + * Fill in the freemap information + */ + INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT, (uint)sizeof(xfs_dir_leaf_hdr_t)); + INT_MOD(hdr_d->freemap[0].base, ARCH_CONVERT, INT_GET(hdr_d->count, ARCH_CONVERT) * (uint)sizeof(xfs_dir_leaf_entry_t)); + INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT, INT_GET(hdr_d->firstused, ARCH_CONVERT) - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT)); + INT_SET(hdr_d->freemap[1].base, ARCH_CONVERT, INT_ZERO(hdr_d->freemap[2].base, ARCH_CONVERT)); + INT_SET(hdr_d->freemap[1].size, ARCH_CONVERT, INT_ZERO(hdr_d->freemap[2].size, ARCH_CONVERT)); + hdr_s->holes = 1; /* leaf may not be compact */ +} + +/* + * Compare two leaf blocks "order". + */ +int +xfs_dir_leaf_order(xfs_dabuf_t *leaf1_bp, xfs_dabuf_t *leaf2_bp) +{ + xfs_dir_leafblock_t *leaf1, *leaf2; + + leaf1 = leaf1_bp->data; + leaf2 = leaf2_bp->data; + ASSERT((INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC) && + (INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC)); + if ((INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0) && (INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0) && + ((INT_GET(leaf2->entries[ 0 ].hashval, ARCH_CONVERT) < + INT_GET(leaf1->entries[ 0 ].hashval, ARCH_CONVERT)) || + (INT_GET(leaf2->entries[ INT_GET(leaf2->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT) < + INT_GET(leaf1->entries[ INT_GET(leaf1->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)))) { + return(1); + } + return(0); +} + +/* + * Pick up the last hashvalue from a leaf block. + */ +xfs_dahash_t +xfs_dir_leaf_lasthash(xfs_dabuf_t *bp, int *count) +{ + xfs_dir_leafblock_t *leaf; + + leaf = bp->data; + ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC); + if (count) + *count = INT_GET(leaf->hdr.count, ARCH_CONVERT); + if (INT_GET(leaf->hdr.count, ARCH_CONVERT) == 0) + return(0); + return(INT_GET(leaf->entries[ INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval, ARCH_CONVERT)); +} + +/* + * Copy out directory entries for getdents(), for leaf directories. + */ +int +xfs_dir_leaf_getdents_int( + xfs_dabuf_t *bp, + xfs_inode_t *dp, + xfs_dablk_t bno, + uio_t *uio, + int *eobp, + xfs_dirent_t *dbp, + xfs_dir_put_t put, + xfs_daddr_t nextda) +{ + xfs_dir_leafblock_t *leaf; + xfs_dir_leaf_entry_t *entry; + xfs_dir_leaf_name_t *namest; + int entno, want_entno, i, nextentno; + xfs_mount_t *mp; + xfs_dahash_t cookhash; + xfs_dahash_t nexthash=0; +#if (XFS_64 == 0) + xfs_dahash_t lasthash; +#endif + xfs_dir_put_args_t p; + + mp = dp->i_mount; + leaf = bp->data; + if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) { + *eobp = 1; + return(XFS_ERROR(ENOENT)); /* XXX wrong code */ + } + + want_entno = XFS_DA_COOKIE_ENTRY(mp, uio->uio_offset); + + cookhash = XFS_DA_COOKIE_HASH(mp, uio->uio_offset); + + xfs_dir_trace_g_dul("leaf: start", dp, uio, leaf); + + /* + * Re-find our place. + */ + for (i = entno = 0, entry = &leaf->entries[0]; + i < INT_GET(leaf->hdr.count, ARCH_CONVERT); + entry++, i++) { + + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, + INT_GET(entry->nameidx, ARCH_CONVERT)); + + if (((char *)namest < (char *)leaf) || + ((char *)namest >= (char *)leaf + XFS_LBSIZE(mp)) || + (entry->namelen >= MAXNAMELEN)) { + xfs_dir_trace_g_du("leaf: corrupted", dp, uio); + return XFS_ERROR(EFSCORRUPTED); + } + if (INT_GET(entry->hashval, ARCH_CONVERT) >= cookhash) { + if ( entno < want_entno + && INT_GET(entry->hashval, ARCH_CONVERT) + == cookhash) { + /* + * Trying to get to a particular offset in a + * run of equal-hashval entries. + */ + entno++; + } else if ( want_entno > 0 + && entno == want_entno + && INT_GET(entry->hashval, ARCH_CONVERT) + == cookhash) { + break; + } else { + entno = 0; + break; + } + } + } + + if (i == INT_GET(leaf->hdr.count, ARCH_CONVERT)) { + xfs_dir_trace_g_du("leaf: hash not found", dp, uio); + if (!INT_GET(leaf->hdr.info.forw, ARCH_CONVERT)) + uio->uio_offset = + XFS_DA_MAKE_COOKIE(mp, 0, 0, XFS_DA_MAXHASH); + /* + * Don't set uio_offset if there's another block: + * the node code will be setting uio_offset anyway. + */ + *eobp = 0; + return(0); + } + xfs_dir_trace_g_due("leaf: hash found", dp, uio, entry); + + p.dbp = dbp; + p.put = put; + p.uio = uio; + + /* + * We're synchronized, start copying entries out to the user. + */ + for ( +#if (XFS_64 == 0) + lasthash = XFS_DA_MAXHASH +#endif + ; + entno >= 0 && i < INT_GET(leaf->hdr.count, ARCH_CONVERT); + entry++, i++, (entno = nextentno)) { + int lastresid=0, retval; + xfs_dircook_t lastoffset; + xfs_dahash_t thishash; + + /* + * Check for a damaged directory leaf block and pick up + * the inode number from this entry. + */ + namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, + INT_GET(entry->nameidx, ARCH_CONVERT)); + + if (((char *)namest < (char *)leaf) || + ((char *)namest >= (char *)leaf + XFS_LBSIZE(mp)) || + (entry->namelen >= MAXNAMELEN)) { + xfs_dir_trace_g_du("leaf: corrupted", dp, uio); + return XFS_ERROR(EFSCORRUPTED); + } + + thishash = INT_GET(entry->hashval, ARCH_CONVERT); + + /* + * NOTE! Linux "filldir" semantics require that the + * offset "cookie" be for this entry, not the + * next; all the actual shuffling to make it + * "look right" to the user is done in filldir. + */ + XFS_PUT_COOKIE(p.cook, mp, bno, entno, thishash); + + xfs_dir_trace_g_duc("leaf: middle cookie ", + dp, uio, p.cook.o); + + if (i < (INT_GET(leaf->hdr.count, ARCH_CONVERT) - 1)) { + nexthash = INT_GET(entry[1].hashval, ARCH_CONVERT); + + if (nexthash == INT_GET(entry->hashval, ARCH_CONVERT)) + nextentno = entno + 1; + else + nextentno = 0; + + } else if (INT_GET(leaf->hdr.info.forw, ARCH_CONVERT)) { + xfs_dabuf_t *bp2; + xfs_dir_leafblock_t *leaf2; + + ASSERT(nextda != -1); + + retval = xfs_da_read_buf(dp->i_transp, dp, + INT_GET(leaf->hdr.info.forw, + ARCH_CONVERT), nextda, + &bp2, XFS_DATA_FORK); + if (retval) + return(retval); + + ASSERT(bp2 != NULL); + + leaf2 = bp2->data; + + if ( (INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT) + != XFS_DIR_LEAF_MAGIC) + || (INT_GET(leaf2->hdr.info.back, ARCH_CONVERT) + != bno)) { /* GROT */ + + xfs_da_brelse(dp->i_transp, bp2); + + return(XFS_ERROR(EFSCORRUPTED)); + } + + nexthash = INT_GET(leaf2->entries[0].hashval, + ARCH_CONVERT); + nextentno = -1; + + xfs_da_brelse(dp->i_transp, bp2); + xfs_dir_trace_g_duc("leaf: next blk cookie", + dp, uio, p.cook.o); + } else { + nextentno = -1; + nexthash = XFS_DA_MAXHASH; + } + + /* + * Save off the cookie so we can fall back should the + * 'put' into the outgoing buffer fails. To handle a run + * of equal-hashvals, the off_t structure on 64bit + * builds has entno built into the cookie to ID the + * entry. On 32bit builds, we only have space for the + * hashval so we can't ID specific entries within a group + * of same hashval entries. For this, lastoffset is set + * to the first in the run of equal hashvals so we don't + * include any entries unless we can include all entries + * that share the same hashval. Hopefully the buffer + * provided is big enough to handle it (see pv763517). + */ +#if (XFS_64 == 0) + if (INT_GET(entry->hashval, ARCH_CONVERT) != lasthash) { +#endif + XFS_PUT_COOKIE(lastoffset, mp, bno, entno, thishash); + lastresid = uio->uio_resid; +#if (XFS_64 == 0) + lasthash = thishash; + } else { + xfs_dir_trace_g_duc("leaf: DUP COOKIES, skipped", + dp, uio, p.cook.o); + } +#endif + + /* + * Put the current entry into the outgoing buffer. If we fail + * then restore the UIO to the first entry in the current + * run of equal-hashval entries (probably one 1 entry long). + */ +#if XFS_BIG_FILESYSTEMS + p.ino = XFS_GET_DIR_INO_ARCH(mp, namest->inumber, ARCH_CONVERT) + mp->m_inoadd; +#else + p.ino = XFS_GET_DIR_INO_ARCH(mp, namest->inumber, ARCH_CONVERT); +#endif + p.name = (char *)namest->name; + p.namelen = entry->namelen; + + retval = p.put(&p); + + if (!p.done) { + uio->uio_offset = lastoffset.o; + uio->uio_resid = lastresid; + + *eobp = 1; + + xfs_dir_trace_g_du("leaf: E-O-B", dp, uio); + + return(retval); + } + } + + XFS_PUT_COOKIE(p.cook, mp, 0, 0, nexthash); + + uio->uio_offset = p.cook.o; + + *eobp = 0; + + xfs_dir_trace_g_du("leaf: E-O-F", dp, uio); + + return(0); +} + +/* + * Format a dirent structure and copy it out the the user's buffer. + */ +int +xfs_dir_put_dirent32_direct(xfs_dir_put_args_t *pa) +{ + iovec_t *iovp; + int reclen, namelen; + xfs_dirent32_t *idbp; + uio_t *uio; + +#if XFS_BIG_FILESYSTEMS + if (pa->ino > XFS_MAXINUMBER_32) { + pa->done = 0; + return XFS_ERROR(EOVERFLOW); + } +#endif + namelen = pa->namelen; + reclen = DIRENT32SIZE(namelen); + uio = pa->uio; + if (reclen > uio->uio_resid) { + pa->done = 0; + return 0; + } + iovp = uio->uio_iov; + idbp = (xfs_dirent32_t *)iovp->iov_base; + iovp->iov_base = (char *)idbp + reclen; + iovp->iov_len -= reclen; + uio->uio_resid -= reclen; + idbp->d_reclen = reclen; + idbp->d_ino = pa->ino; + idbp->d_off = pa->cook.o; + idbp->d_name[namelen] = '\0'; + pa->done = 1; + bcopy(pa->name, idbp->d_name, namelen); + return 0; +} + +/* + * Format a dirent structure and copy it out the the user's buffer. + */ +int +xfs_dir_put_dirent32_uio(xfs_dir_put_args_t *pa) +{ + int retval, reclen, namelen; + xfs_dirent32_t *idbp; + uio_t *uio; + +#if XFS_BIG_FILESYSTEMS + if (pa->ino > XFS_MAXINUMBER_32) { + pa->done = 0; + return XFS_ERROR(EOVERFLOW); + } +#endif + + namelen = pa->namelen; + reclen = DIRENT32SIZE(namelen); + uio = pa->uio; + if (reclen > uio->uio_resid) { + pa->done = 0; + return 0; + } + idbp = (xfs_dirent32_t *)pa->dbp; + idbp->d_reclen = reclen; + idbp->d_ino = pa->ino; + idbp->d_off = pa->cook.o; + idbp->d_name[namelen] = '\0'; + bcopy(pa->name, idbp->d_name, namelen); + retval = uiomove((caddr_t)idbp, reclen, UIO_READ, uio); + pa->done = (retval == 0); + return retval; +} + +/* + * Format a dirent64 structure and copy it out the the user's buffer. + */ +int +xfs_dir_put_dirent64_direct(xfs_dir_put_args_t *pa) +{ + iovec_t *iovp; + int reclen, namelen; + xfs_dirent_t *idbp; + uio_t *uio; + + namelen = pa->namelen; + reclen = DIRENTSIZE(namelen); + uio = pa->uio; + if (reclen > uio->uio_resid) { + pa->done = 0; + return 0; + } + iovp = uio->uio_iov; + idbp = (xfs_dirent_t *)iovp->iov_base; + iovp->iov_base = (char *)idbp + reclen; + iovp->iov_len -= reclen; + uio->uio_resid -= reclen; + idbp->d_reclen = reclen; + idbp->d_ino = pa->ino; + idbp->d_off = pa->cook.o; + idbp->d_name[namelen] = '\0'; + pa->done = 1; + bcopy(pa->name, idbp->d_name, namelen); + return 0; +} + +/* + * Format a dirent64 structure and copy it out the the user's buffer. + */ +int +xfs_dir_put_dirent64_uio(xfs_dir_put_args_t *pa) +{ + int retval, reclen, namelen; + xfs_dirent_t *idbp; + uio_t *uio; + + namelen = pa->namelen; + reclen = DIRENTSIZE(namelen); + uio = pa->uio; + if (reclen > uio->uio_resid) { + pa->done = 0; + return 0; + } + idbp = pa->dbp; + idbp->d_reclen = reclen; + idbp->d_ino = pa->ino; + idbp->d_off = pa->cook.o; + idbp->d_name[namelen] = '\0'; + bcopy(pa->name, idbp->d_name, namelen); + retval = uiomove((caddr_t)idbp, reclen, UIO_READ, uio); + pa->done = (retval == 0); + return retval; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir_leaf.h linux-2.4-xfs/linux/fs/xfs/xfs_dir_leaf.h --- linux-2.4.7/linux/fs/xfs/xfs_dir_leaf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir_leaf.h Tue Apr 10 20:44:54 2001 @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR_LEAF_H__ +#define __XFS_DIR_LEAF_H__ + +/* + * Directory layout, internal structure, access macros, etc. + * + * Large directories are structured around Btrees where all the data + * elements are in the leaf nodes. Filenames are hashed into an int, + * then that int is used as the index into the Btree. Since the hashval + * of a filename may not be unique, we may have duplicate keys. The + * internal links in the Btree are logical block offsets into the file. + */ + +struct dirent; +struct uio; +struct xfs_bmap_free; +struct xfs_dabuf; +struct xfs_da_args; +struct xfs_da_state; +struct xfs_da_state_blk; +struct xfs_dir_put_args; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/*======================================================================== + * Directory Structure when equal to XFS_LBSIZE(mp) bytes. + *========================================================================*/ + +/* + * This is the structure of the leaf nodes in the Btree. + * + * Struct leaf_entry's are packed from the top. Names grow from the bottom + * but are not packed. The freemap contains run-length-encoded entries + * for the free bytes after the leaf_entry's, but only the N largest such, + * smaller runs are dropped. When the freemap doesn't show enough space + * for an allocation, we compact the namelist area and try again. If we + * still don't have enough space, then we have to split the block. + * + * Since we have duplicate hash keys, for each key that matches, compare + * the actual string. The root and intermediate node search always takes + * the first-in-the-block key match found, so we should only have to work + * "forw"ard. If none matches, continue with the "forw"ard leaf nodes + * until the hash key changes or the filename is found. + * + * The parent directory and the self-pointer are explicitly represented + * (ie: there are entries for "." and ".."). + * + * Note that the count being a __uint16_t limits us to something like a + * blocksize of 1.3MB in the face of worst case (short) filenames. + */ +#define XFS_DIR_LEAF_MAPSIZE 3 /* how many freespace slots */ + +typedef struct xfs_dir_leafblock { + struct xfs_dir_leaf_hdr { /* constant-structure header block */ + xfs_da_blkinfo_t info; /* block type, links, etc. */ + __uint16_t count; /* count of active leaf_entry's */ + __uint16_t namebytes; /* num bytes of name strings stored */ + __uint16_t firstused; /* first used byte in name area */ + __uint8_t holes; /* != 0 if blk needs compaction */ + __uint8_t pad1; + struct xfs_dir_leaf_map {/* RLE map of free bytes */ + __uint16_t base; /* base of free region */ + __uint16_t size; /* run length of free region */ + } freemap[XFS_DIR_LEAF_MAPSIZE]; /* N largest free regions */ + } hdr; + struct xfs_dir_leaf_entry { /* sorted on key, not name */ + xfs_dahash_t hashval; /* hash value of name */ + __uint16_t nameidx; /* index into buffer of name */ + __uint8_t namelen; /* length of name string */ + __uint8_t pad2; + } entries[1]; /* var sized array */ + struct xfs_dir_leaf_name { + xfs_dir_ino_t inumber; /* inode number for this key */ + __uint8_t name[1]; /* name string itself */ + } namelist[1]; /* grows from bottom of buf */ +} xfs_dir_leafblock_t; +typedef struct xfs_dir_leaf_hdr xfs_dir_leaf_hdr_t; +typedef struct xfs_dir_leaf_map xfs_dir_leaf_map_t; +typedef struct xfs_dir_leaf_entry xfs_dir_leaf_entry_t; +typedef struct xfs_dir_leaf_name xfs_dir_leaf_name_t; + +/* + * Length of name for which a 512-byte block filesystem + * can get a double split. + */ +#define XFS_DIR_LEAF_CAN_DOUBLE_SPLIT_LEN \ + (512 - (uint)sizeof(xfs_dir_leaf_hdr_t) - \ + (uint)sizeof(xfs_dir_leaf_entry_t) * 2 - \ + (uint)sizeof(xfs_dir_leaf_name_t) * 2 - (MAXNAMELEN - 2) + 1 + 1) + +typedef int (*xfs_dir_put_t)(struct xfs_dir_put_args *pa); + +typedef union { + xfs_off_t o; /* offset (cookie) */ + /* + * Watch the order here (endian-ness dependent). + */ + struct { +#if __BYTE_ORDER == __LITTLE_ENDIAN + xfs_dahash_t h; /* hash value */ + __uint32_t be; /* block and entry */ +#else /* __BYTE_ORDER == __BIG_ENDIAN */ + __uint32_t be; /* block and entry */ + xfs_dahash_t h; /* hash value */ +#endif /* __BYTE_ORDER == __BIG_ENDIAN */ + } s; +} xfs_dircook_t; + +#define XFS_PUT_COOKIE(c,mp,bno,entry,hash) \ + ((c).s.be = XFS_DA_MAKE_BNOENTRY(mp, bno, entry), (c).s.h = (hash)) + +#define XFS_GET_DIR_INO_ARCH(mp,di,arch) \ + DIRINO_GET_ARCH(&(di),arch) +#define XFS_GET_DIR_INO(mp,di) \ + XFS_GET_DIR_INO_ARCH(mp,di,ARCH_NOCONVERT) + +typedef struct xfs_dir_put_args +{ + xfs_dircook_t cook; /* cookie of (next) entry */ + xfs_intino_t ino; /* inode number */ + struct xfs_dirent *dbp; /* buffer pointer */ + char *name; /* directory entry name */ + int namelen; /* length of name */ + int done; /* output: set if value was stored */ + xfs_dir_put_t put; /* put function ptr (i/o) */ + struct uio *uio; /* uio control structure */ +} xfs_dir_put_args_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_LEAF_ENTSIZE_BYNAME) +int xfs_dir_leaf_entsize_byname(int len); +#define XFS_DIR_LEAF_ENTSIZE_BYNAME(len) xfs_dir_leaf_entsize_byname(len) +#else +#define XFS_DIR_LEAF_ENTSIZE_BYNAME(len) /* space a name will use */ \ + ((uint)sizeof(xfs_dir_leaf_name_t)-1 + len) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_LEAF_ENTSIZE_BYENTRY) +int xfs_dir_leaf_entsize_byentry(xfs_dir_leaf_entry_t *entry); +#define XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry) \ + xfs_dir_leaf_entsize_byentry(entry) +#else +#define XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry) /* space an entry will use */ \ + ((uint)sizeof(xfs_dir_leaf_name_t)-1 + (entry)->namelen) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_LEAF_NAMESTRUCT) +xfs_dir_leaf_name_t * +xfs_dir_leaf_namestruct(xfs_dir_leafblock_t *leafp, int offset); +#define XFS_DIR_LEAF_NAMESTRUCT(leafp,offset) \ + xfs_dir_leaf_namestruct(leafp,offset) +#else +#define XFS_DIR_LEAF_NAMESTRUCT(leafp,offset) /* point to name struct */ \ + ((xfs_dir_leaf_name_t *)&((char *)(leafp))[offset]) +#endif + +/*======================================================================== + * Function prototypes for the kernel. + *========================================================================*/ + +/* + * Internal routines when dirsize < XFS_LITINO(mp). + */ +int xfs_dir_shortform_create(struct xfs_da_args *args, xfs_ino_t parent); +int xfs_dir_shortform_addname(struct xfs_da_args *args); +int xfs_dir_shortform_lookup(struct xfs_da_args *args); +int xfs_dir_shortform_to_leaf(struct xfs_da_args *args); +int xfs_dir_shortform_removename(struct xfs_da_args *args); +int xfs_dir_shortform_getdents(struct xfs_inode *dp, struct uio *uio, int *eofp, + struct xfs_dirent *dbp, xfs_dir_put_t put); +int xfs_dir_shortform_replace(struct xfs_da_args *args); + +/* + * Internal routines when dirsize == XFS_LBSIZE(mp). + */ +int xfs_dir_leaf_to_node(struct xfs_da_args *args); +int xfs_dir_leaf_to_shortform(struct xfs_da_args *args); + +/* + * Routines used for growing the Btree. + */ +int xfs_dir_leaf_create(struct xfs_da_args *args, xfs_dablk_t which_block, + struct xfs_dabuf **bpp); +int xfs_dir_leaf_split(struct xfs_da_state *state, + struct xfs_da_state_blk *oldblk, + struct xfs_da_state_blk *newblk); +int xfs_dir_leaf_add(struct xfs_dabuf *leaf_buffer, + struct xfs_da_args *args, int insertion_index); +int xfs_dir_leaf_addname(struct xfs_da_args *args); +int xfs_dir_leaf_lookup_int(struct xfs_dabuf *leaf_buffer, + struct xfs_da_args *args, + int *index_found_at); +int xfs_dir_leaf_remove(struct xfs_trans *trans, + struct xfs_dabuf *leaf_buffer, + int index_to_remove); +int xfs_dir_leaf_getdents_int(struct xfs_dabuf *bp, struct xfs_inode *dp, + xfs_dablk_t bno, struct uio *uio, + int *eobp, struct xfs_dirent *dbp, + xfs_dir_put_t put, xfs_daddr_t nextda); + +/* + * Routines used for shrinking the Btree. + */ +int xfs_dir_leaf_toosmall(struct xfs_da_state *state, int *retval); +void xfs_dir_leaf_unbalance(struct xfs_da_state *state, + struct xfs_da_state_blk *drop_blk, + struct xfs_da_state_blk *save_blk); + +/* + * Utility routines. + */ +uint xfs_dir_leaf_lasthash(struct xfs_dabuf *bp, int *count); +int xfs_dir_leaf_order(struct xfs_dabuf *leaf1_bp, + struct xfs_dabuf *leaf2_bp); +int xfs_dir_put_dirent32_direct(xfs_dir_put_args_t *pa); +int xfs_dir_put_dirent32_uio(xfs_dir_put_args_t *pa); +int xfs_dir_put_dirent64_direct(xfs_dir_put_args_t *pa); +int xfs_dir_put_dirent64_uio(xfs_dir_put_args_t *pa); +int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino); + + +/* + * Global data. + */ +extern xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot; + +#endif /* __XFS_DIR_LEAF_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dir_sf.h linux-2.4-xfs/linux/fs/xfs/xfs_dir_sf.h --- linux-2.4.7/linux/fs/xfs/xfs_dir_sf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dir_sf.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DIR_SF_H__ +#define __XFS_DIR_SF_H__ + +/* + * Directory layout when stored internal to an inode. + * + * Small directories are packed as tightly as possible so as to + * fit into the literal area of the inode. + */ + +typedef struct { __uint8_t i[sizeof(xfs_ino_t)]; } xfs_dir_ino_t; + +/* + * The parent directory has a dedicated field, and the self-pointer must + * be calculated on the fly. + * + * Entries are packed toward the top as tight as possible. The header + * and the elements much be bcopy()'d out into a work area to get correct + * alignment for the inode number fields. + */ +typedef struct xfs_dir_shortform { + struct xfs_dir_sf_hdr { /* constant-structure header block */ + xfs_dir_ino_t parent; /* parent dir inode number */ + __uint8_t count; /* count of active entries */ + } hdr; + struct xfs_dir_sf_entry { + xfs_dir_ino_t inumber; /* referenced inode number */ + __uint8_t namelen; /* actual length of name (no NULL) */ + __uint8_t name[1]; /* name */ + } list[1]; /* variable sized array */ +} xfs_dir_shortform_t; +typedef struct xfs_dir_sf_hdr xfs_dir_sf_hdr_t; +typedef struct xfs_dir_sf_entry xfs_dir_sf_entry_t; + +/* + * We generate this then sort it, so that readdirs are returned in + * hash-order. Else seekdir won't work. + */ +typedef struct xfs_dir_sf_sort { + __uint8_t entno; /* .=0, ..=1, else entry# + 2 */ + __uint8_t seqno; /* sequence # with same hash value */ + __uint8_t namelen; /* length of name value (no null) */ + xfs_dahash_t hash; /* this entry's hash value */ + xfs_intino_t ino; /* this entry's inode number */ + char *name; /* name value, pointer into buffer */ +} xfs_dir_sf_sort_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_GET_DIRINO) +void xfs_dir_sf_get_dirino_arch(xfs_dir_ino_t *from, xfs_ino_t *to, xfs_arch_t arch); +void xfs_dir_sf_get_dirino(xfs_dir_ino_t *from, xfs_ino_t *to); +#define XFS_DIR_SF_GET_DIRINO_ARCH(from,to,arch) xfs_dir_sf_get_dirino_arch(from, to, arch) +#define XFS_DIR_SF_GET_DIRINO(from,to) xfs_dir_sf_get_dirino(from, to) +#else +#define XFS_DIR_SF_GET_DIRINO_ARCH(from,to,arch) DIRINO_COPY_ARCH(from,to,arch) +#define XFS_DIR_SF_GET_DIRINO(from,to) DIRINO_COPY_ARCH(from,to,ARCH_NOCONVERT) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_PUT_DIRINO) +void xfs_dir_sf_put_dirino_arch(xfs_ino_t *from, xfs_dir_ino_t *to, xfs_arch_t arch); +void xfs_dir_sf_put_dirino(xfs_ino_t *from, xfs_dir_ino_t *to); +#define XFS_DIR_SF_PUT_DIRINO_ARCH(from,to,arch) xfs_dir_sf_put_dirino_arch(from, to, arch) +#define XFS_DIR_SF_PUT_DIRINO(from,to) xfs_dir_sf_put_dirino(from, to) +#else +#define XFS_DIR_SF_PUT_DIRINO_ARCH(from,to,arch) DIRINO_COPY_ARCH(from,to,arch) +#define XFS_DIR_SF_PUT_DIRINO(from,to) DIRINO_COPY_ARCH(from,to,ARCH_NOCONVERT) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_ENTSIZE_BYNAME) +int xfs_dir_sf_entsize_byname(int len); +#define XFS_DIR_SF_ENTSIZE_BYNAME(len) xfs_dir_sf_entsize_byname(len) +#else +#define XFS_DIR_SF_ENTSIZE_BYNAME(len) /* space a name uses */ \ + ((uint)sizeof(xfs_dir_sf_entry_t)-1 + (len)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_ENTSIZE_BYENTRY) +int xfs_dir_sf_entsize_byentry(xfs_dir_sf_entry_t *sfep); +#define XFS_DIR_SF_ENTSIZE_BYENTRY(sfep) xfs_dir_sf_entsize_byentry(sfep) +#else +#define XFS_DIR_SF_ENTSIZE_BYENTRY(sfep) /* space an entry uses */ \ + ((uint)sizeof(xfs_dir_sf_entry_t)-1 + (sfep)->namelen) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_NEXTENTRY) +xfs_dir_sf_entry_t *xfs_dir_sf_nextentry(xfs_dir_sf_entry_t *sfep); +#define XFS_DIR_SF_NEXTENTRY(sfep) xfs_dir_sf_nextentry(sfep) +#else +#define XFS_DIR_SF_NEXTENTRY(sfep) /* next entry in struct */ \ + ((xfs_dir_sf_entry_t *) \ + ((char *)(sfep) + XFS_DIR_SF_ENTSIZE_BYENTRY(sfep))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DIR_SF_ALLFIT) +int xfs_dir_sf_allfit(int count, int totallen); +#define XFS_DIR_SF_ALLFIT(count,totallen) \ + xfs_dir_sf_allfit(count,totallen) +#else +#define XFS_DIR_SF_ALLFIT(count,totallen) /* will all entries fit? */ \ + ((uint)sizeof(xfs_dir_sf_hdr_t) + \ + ((uint)sizeof(xfs_dir_sf_entry_t)-1)*(count) + (totallen)) +#endif + +#ifdef XFS_ALL_TRACE +#define XFS_DIR_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_DIR_TRACE +#endif + +/* + * Kernel tracing support for directories. + */ +struct uio; +struct xfs_inode; +struct xfs_da_intnode; +struct xfs_dinode; +struct xfs_dir_leafblock; +struct xfs_dir_leaf_entry; + +#define XFS_DIR_TRACE_SIZE 4096 /* size of global trace buffer */ + +/* + * Trace record types. + */ +#define XFS_DIR_KTRACE_G_DU 1 /* dp, uio */ +#define XFS_DIR_KTRACE_G_DUB 2 /* dp, uio, bno */ +#define XFS_DIR_KTRACE_G_DUN 3 /* dp, uio, node */ +#define XFS_DIR_KTRACE_G_DUL 4 /* dp, uio, leaf */ +#define XFS_DIR_KTRACE_G_DUE 5 /* dp, uio, leaf entry */ +#define XFS_DIR_KTRACE_G_DUC 6 /* dp, uio, cookie */ + +#if defined(XFS_DIR_TRACE) + +void xfs_dir_trace_g_du(char *where, struct xfs_inode *dp, struct uio *uio); +void xfs_dir_trace_g_dub(char *where, struct xfs_inode *dp, struct uio *uio, + xfs_dablk_t bno); +void xfs_dir_trace_g_dun(char *where, struct xfs_inode *dp, struct uio *uio, + struct xfs_da_intnode *node); +void xfs_dir_trace_g_dul(char *where, struct xfs_inode *dp, struct uio *uio, + struct xfs_dir_leafblock *leaf); +void xfs_dir_trace_g_due(char *where, struct xfs_inode *dp, struct uio *uio, + struct xfs_dir_leaf_entry *entry); +void xfs_dir_trace_g_duc(char *where, struct xfs_inode *dp, struct uio *uio, + xfs_off_t cookie); +void xfs_dir_trace_enter(int type, char *where, + __psunsigned_t a0, __psunsigned_t a1, + __psunsigned_t a2, __psunsigned_t a3, + __psunsigned_t a4, __psunsigned_t a5, + __psunsigned_t a6, __psunsigned_t a7, + __psunsigned_t a8, __psunsigned_t a9, + __psunsigned_t a10, __psunsigned_t a11); +#else +#define xfs_dir_trace_g_du(w,d,u) +#define xfs_dir_trace_g_dub(w,d,u,b) +#define xfs_dir_trace_g_dun(w,d,u,n) +#define xfs_dir_trace_g_dul(w,d,u,l) +#define xfs_dir_trace_g_due(w,d,u,e) +#define xfs_dir_trace_g_duc(w,d,u,c) +#endif /* DEBUG */ + +#endif /* __XFS_DIR_SF_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dmapi.c linux-2.4-xfs/linux/fs/xfs/xfs_dmapi.c --- linux-2.4.7/linux/fs/xfs/xfs_dmapi.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dmapi.c Thu May 24 18:17:45 2001 @@ -0,0 +1,3137 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include /* linvfs_revalidate_core() */ + +#define MAXNAMLEN MAXNAMELEN + +STATIC int prohibited_mr_events(bhv_desc_t *bdp); + +/* Structure used to hold the on-disk version of a dm_attrname_t. All + on-disk attribute names start with the 8-byte string "SGI_DMI_". +*/ + +typedef struct { + char dan_chars[DMATTR_PREFIXLEN + DM_ATTR_NAME_SIZE + 1]; +} dm_dkattrname_t; + +/* In the on-disk inode, DMAPI attribute names consist of the user-provided + name with the DMATTR_PREFIXSTRING pre-pended. This string must NEVER be + changed! +*/ + +STATIC const char dmattr_prefix[DMATTR_PREFIXLEN + 1] = DMATTR_PREFIXSTRING; + +STATIC dm_size_t dm_min_dio_xfer = 0; /* direct I/O disabled for now */ + + +/* See xfs_dm_get_dmattr() for a description of why this is needed. */ + +#define XFS_BUG_KLUDGE 256 /* max size of an in-inode attribute value */ + +#define DM_MAX_ATTR_BYTES_ON_DESTROY 256 + +/* events valid in dm_set_eventlist() when called with a filesystem handle. + These events are not persistent. +*/ + +#define DM_XFS_VALID_FS_EVENTS ( \ + (1 << DM_EVENT_PREUNMOUNT) | \ + (1 << DM_EVENT_UNMOUNT) | \ + (1 << DM_EVENT_NOSPACE) | \ + (1 << DM_EVENT_DEBUT) | \ + (1 << DM_EVENT_CREATE) | \ + (1 << DM_EVENT_POSTCREATE) | \ + (1 << DM_EVENT_REMOVE) | \ + (1 << DM_EVENT_POSTREMOVE) | \ + (1 << DM_EVENT_RENAME) | \ + (1 << DM_EVENT_POSTRENAME) | \ + (1 << DM_EVENT_LINK) | \ + (1 << DM_EVENT_POSTLINK) | \ + (1 << DM_EVENT_SYMLINK) | \ + (1 << DM_EVENT_POSTSYMLINK) | \ + (1 << DM_EVENT_ATTRIBUTE) | \ + (1 << DM_EVENT_DESTROY) ) + +/* Events valid in dm_set_eventlist() when called with a file handle for + a regular file or a symlink. These events are persistent. +*/ + +#define DM_XFS_VALID_FILE_EVENTS ( \ + (1 << DM_EVENT_ATTRIBUTE) | \ + (1 << DM_EVENT_DESTROY) ) + +/* Events valid in dm_set_eventlist() when called with a file handle for + a directory. These events are persistent. +*/ + +#define DM_XFS_VALID_DIRECTORY_EVENTS ( \ + (1 << DM_EVENT_CREATE) | \ + (1 << DM_EVENT_POSTCREATE) | \ + (1 << DM_EVENT_REMOVE) | \ + (1 << DM_EVENT_POSTREMOVE) | \ + (1 << DM_EVENT_RENAME) | \ + (1 << DM_EVENT_POSTRENAME) | \ + (1 << DM_EVENT_LINK) | \ + (1 << DM_EVENT_POSTLINK) | \ + (1 << DM_EVENT_SYMLINK) | \ + (1 << DM_EVENT_POSTSYMLINK) | \ + (1 << DM_EVENT_ATTRIBUTE) | \ + (1 << DM_EVENT_DESTROY) ) + + +/* Events supported by the XFS filesystem. */ +#define DM_XFS_SUPPORTED_EVENTS ( \ + (1 << DM_EVENT_MOUNT) | \ + (1 << DM_EVENT_PREUNMOUNT) | \ + (1 << DM_EVENT_UNMOUNT) | \ + (1 << DM_EVENT_NOSPACE) | \ + (1 << DM_EVENT_CREATE) | \ + (1 << DM_EVENT_POSTCREATE) | \ + (1 << DM_EVENT_REMOVE) | \ + (1 << DM_EVENT_POSTREMOVE) | \ + (1 << DM_EVENT_RENAME) | \ + (1 << DM_EVENT_POSTRENAME) | \ + (1 << DM_EVENT_LINK) | \ + (1 << DM_EVENT_POSTLINK) | \ + (1 << DM_EVENT_SYMLINK) | \ + (1 << DM_EVENT_POSTSYMLINK) | \ + (1 << DM_EVENT_READ) | \ + (1 << DM_EVENT_WRITE) | \ + (1 << DM_EVENT_TRUNCATE) | \ + (1 << DM_EVENT_ATTRIBUTE) | \ + (1 << DM_EVENT_DESTROY) ) + + +#define DM_STAT_SIZE(namelen) \ + (sizeof(dm_stat_t) + sizeof(xfs_handle_t) + namelen) +#define MAX_DIRENT_SIZE (sizeof(dirent_t) + MAXNAMELEN) + +#define DM_STAT_ALIGN (sizeof(__uint64_t)) + + +/* + * xfs_dm_send_data_event() + * + * Send data event to DMAPI. Drop IO lock (if specified) before + * the dm_send_data_event() call and reacquire it afterwards. + */ +int +xfs_dm_send_data_event( + dm_eventtype_t event, + bhv_desc_t *bdp, + xfs_off_t offset, + size_t length, + int flags, + vrwlock_t *locktype) +{ + int error; + vnode_t *vp; + + vp = BHV_TO_VNODE(bdp); + /* + * Now we need to simulate VOP_RWLOCK/VOP_RWLOCK. We can't + * just call the VOP though, or we'll wind up going through + * the dsvn layer for CXFS. We have to avoid getting tokens, + * so we go straight to XFS. + */ + ASSERT(BHV_IS_XFS(bdp)); +#ifdef CELL_CAPABLE + VN_BHV_READ_LOCK(&vp->v_bh); +#endif + if (locktype) + xfs_rwunlock(bdp, *locktype); + error = dm_send_data_event(event, bdp, DM_RIGHT_NULL, + offset, length, flags); + if (locktype) + xfs_rwlock(bdp, *locktype); +#ifdef CELL_CAPABLE + VN_BHV_READ_UNLOCK(&vp->v_bh); +#endif + + return error; +} + +/* xfs_dm_create_event + * + * Conditionally send a DM_EVENT_CREATE. The event will not be sent if + * we can check the directory and find the name (to be created) already + * there. Some sort of a "double check" is required since in the + * xfs_create and xfs_mkdir routines, we determine that there is not a + * duplicate with the directory ilock held. We cannot send an event with + * the ilock held, since this can potentially lead to a deadlock. + * Dropping the ilock while the event is being sent is unwise since the + * directory may have changed by the time we reacquire the lock. Hence + * this workaround. + * + * Note that after we have determined that the name does/does not exist, + * the situation might have changed by the time we get back to + * xfs_create/xfs_mkdir. So the workaround does not really solve the + * problem. The results can be missing or redundant create events. + */ + +int +xfs_dm_send_create_event( + bhv_desc_t *dir_bdp, + char *name, + mode_t new_mode, + int *good_event_sent) +{ + xfs_inode_t *dip; + xfs_ino_t inum; + vnode_t *dir_vp; +#ifdef __sgi + struct ncfastdata fd; +#endif + int error; + int name_len; + + dir_vp = BHV_TO_VNODE(dir_bdp); + + if (*name == '\0') + return 0; + + dip = XFS_BHVTOI (dir_bdp); + xfs_ilock (dip, XFS_ILOCK_EXCL); + + vn_trace_entry(dir_vp, "xfs_dm_send_create_event", + (inst_t *)__return_address); + + /* + * Handle degenerate pathname component. + */ + +#ifdef __sgi + /* + * Try the directory name lookup cache. + */ + if (bdp = dnlc_lookup_fast(dir_vp, name, NULL, &fd, NOCRED, VN_GET_NOWAIT)) { + xfs_iunlock (dip, XFS_ILOCK_EXCL); + VN_RELE (BHV_TO_VNODE(bdp)); + return 0; + } +#endif + + /* + * Else call the directory code. + */ + + name_len = strlen(name); + error = XFS_DIR_LOOKUP(dip->i_mount, NULL, dip, name, name_len, &inum); + xfs_iunlock (dip, XFS_ILOCK_EXCL); + if (error != ENOENT) + return 0; + error = dm_send_namesp_event(DM_EVENT_CREATE, dir_bdp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, + name, NULL, new_mode, 0, 0); + if (!error) + *good_event_sent = 1; + return error; +} + +/* prohibited_mr_events + * + * Return event bits representing any events which cannot have managed + * region events set due to memory mapping of the file. If the maximum + * protection allowed in any pregion includes PROT_WRITE, and the region + * is shared and not text, then neither READ nor WRITE events can be set. + * Otherwise if the file is memory mapped, no READ event can be set. + * + */ + +STATIC int +prohibited_mr_events(bhv_desc_t *bdp) +{ + int prohibited; +#ifdef __sgi + preg_t *preg; +#endif + vnode_t *vp = BHV_TO_VNODE(bdp); + + if (!VN_MAPPED(vp)) + return 0; + + prohibited = 1 << DM_EVENT_READ; +#ifdef __sgi + s = mutex_spinlock(&mreg_lock); + for (preg = vp->v_mreg; preg; preg = preg->p_vchain) { + if ((preg->p_maxprots & PROT_WRITE) && + preg->p_reg->r_type == RT_MAPFILE && + (preg->p_reg->r_flags & RG_TEXT) == 0 ){ + prohibited |= 1 << DM_EVENT_WRITE; + break; + } + } + mutex_spinunlock(&mreg_lock, s); +#endif + return prohibited; +} + + +#ifdef DEBUG_RIGHTS +STATIC int +xfs_bdp_to_hexhandle( + bhv_desc_t *bdp, + u_int type, + char *buffer) +{ + xfs_handle_t handle; + vnode_t *vp; + u_char *ip; + int length; + int error; + int i; + + vp = BHV_TO_VNODE(bdp); + + if ((error = dm_vp_to_handle(vp, &handle))) + return(error); + + if (type == DM_FSYS_OBJ) { /* a filesystem handle */ + length = FSHSIZE; + } else { +#ifdef __sgi + length = HSIZE(handle); +#else + length = XFS_HSIZE(handle); +#endif + } + for (ip = (u_char *)&handle, i = 0; i < length; i++) { + *buffer++ = "0123456789abcdef"[ip[i] >> 4]; + *buffer++ = "0123456789abcdef"[ip[i] & 0xf]; + } + *buffer = '\0'; + return(0); +} +#endif /* DEBUG_RIGHTS */ + + +#ifdef __sgi +/* + * Copy out a size_t possibly adjusting its size according to the abi. + */ + +STATIC int +xfs_cpoutsizet( + void *userptr, /* a user addr (of unknown size) */ + size_t value) /* value to set in the user addr */ +{ +#ifdef _K64U64 + if (get_current_abi()) + return(copyout(&value, userptr, sizeof(value))); +#endif + return(suword(userptr, (int)value)); +} +#endif + + +/* Copy in and validate an attribute name from user space. It should be a + string of at least one and at most DM_ATTR_NAME_SIZE characters. Because + the dm_attrname_t structure doesn't provide room for the trailing NULL + byte, we just copy in one extra character and then zero it if it + happens to be non-NULL. +*/ + +STATIC int +xfs_copyin_attrname( + dm_attrname_t *from, /* dm_attrname_t in user space */ + dm_dkattrname_t *to) /* name buffer in kernel space */ +{ + int error; + size_t len; + + strcpy(to->dan_chars, dmattr_prefix); + +#ifdef __sgi + error = copyinstr((char *)from, &to->dan_chars[DMATTR_PREFIXLEN], + DM_ATTR_NAME_SIZE + 1, NULL); +#else + len = strnlen_user((char*)from, DM_ATTR_NAME_SIZE); + error = copy_from_user(&to->dan_chars[DMATTR_PREFIXLEN], from, len); +#endif + + if (!error && (to->dan_chars[DMATTR_PREFIXLEN] == '\0')) + error = EINVAL; + if (error == ENAMETOOLONG) { + to->dan_chars[sizeof(to->dan_chars) - 1] = '\0'; + error = 0; + } + return(error); +} + + +/* This copies selected fields in an inode into a dm_stat structure. Because + these fields must return the same values as they would in stat(), the + majority of this code was copied directly from xfs_getattr(). Any future + changes to xfs_gettattr() must also be reflected here. + + The inode must be kept locked SHARED by the caller. +*/ + +STATIC void +xfs_ip_to_stat( + xfs_mount_t *mp, + dm_stat_t *buf, + xfs_inode_t *ip) +{ + vnode_t *vp = XFS_ITOV(ip); + + buf->dt_size = ip->i_d.di_size; + buf->dt_dev = ip->i_dev; + + buf->dt_ino = ip->i_ino; +#if XFS_BIG_FILESYSTEMS + buf->dt_ino += mp->m_inoadd; +#endif + /* + * Copy from in-core inode. + */ + buf->dt_mode = VTTOIF(vp->v_type) | (ip->i_d.di_mode & MODEMASK); + buf->dt_uid = ip->i_d.di_uid; + buf->dt_gid = ip->i_d.di_gid; + buf->dt_nlink = ip->i_d.di_nlink; + /* + * Minor optimization, check the common cases first. + */ + if ((vp->v_type == VREG) || (vp->v_type == VDIR)) { + buf->dt_rdev = 0; + } else if ((vp->v_type == VCHR) || (vp->v_type == VBLK) ) { + buf->dt_rdev = IRIX_DEV_TO_KDEVT(ip->i_df.if_u2.if_rdev); + } else { + buf->dt_rdev = 0; /* not a b/c spec. */ + } + + buf->dt_atime = ip->i_d.di_atime.t_sec; + buf->dt_mtime = ip->i_d.di_mtime.t_sec; + buf->dt_ctime = ip->i_d.di_ctime.t_sec; + + switch (ip->i_d.di_mode & IFMT) { + case IFBLK: + case IFCHR: + buf->dt_blksize = BLKDEV_IOSIZE; + break; + default: + /* + * We use the read buffer size as a recommended I/O + * size. This should always be larger than the + * write buffer size, so it should be OK. + * The value returned is in bytes. + */ + buf->dt_blksize = 1 << mp->m_readio_log; + break; + } + + /* + * XXX : truncate to 32 bits for now. + */ + buf->dt_blocks = + XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks); + + /* + * XFS-added attributes + */ + + /* + * convert di_flags to xflags + */ + buf->dt_xfs_xflags = 0; + if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) + buf->dt_xfs_xflags |= DM_XFLAG_REALTIME; + if (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) + buf->dt_xfs_xflags |= DM_XFLAG_PREALLOC; + if (XFS_IFORK_Q(ip)) + buf->dt_xfs_xflags |= DM_XFLAG_HASATTR; + buf->dt_xfs_extsize = ip->i_d.di_extsize << mp->m_sb.sb_blocklog; + buf->dt_xfs_extents = (ip->i_df.if_flags & XFS_IFEXTENTS) ? + ip->i_df.if_bytes / sizeof(xfs_bmbt_rec_t) : + ip->i_d.di_nextents; + if (ip->i_afp != NULL) { + buf->dt_xfs_aextents = + (ip->i_afp->if_flags & XFS_IFEXTENTS) ? + ip->i_afp->if_bytes / sizeof(xfs_bmbt_rec_t) : + ip->i_d.di_anextents; + } else { + buf->dt_xfs_aextents = 0; + } + + /* Now fill in the fields that xfs_getattr() doesn't do. */ + + buf->dt_emask = ip->i_d.di_dmevmask; + buf->dt_nevents = DM_EVENT_MAX; + buf->dt_pers = 0; + buf->dt_change = 0; + buf->dt_dtime = ip->i_d.di_ctime.t_sec; + buf->dt_xfs_dmstate = ip->i_d.di_dmstate; + buf->dt_xfs_igen = ip->i_d.di_gen; + + /* Set if one of READ, WRITE or TRUNCATE bits is set in emask */ + + buf->dt_pmanreg = ( DMEV_ISSET(DM_EVENT_READ, buf->dt_emask) || + DMEV_ISSET(DM_EVENT_WRITE, buf->dt_emask) || + DMEV_ISSET(DM_EVENT_TRUNCATE, buf->dt_emask) ) ? 1 : 0; +} + + +/* + * This is used by dm_get_bulkattr() as well as dm_get_dirattrs(). + * Given a inumber, it igets the inode and fills the given buffer + * with the dm_stat structure for the file. + */ +/* ARGSUSED */ +STATIC int +xfs_dm_bulkstat_one( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t ino, /* inode number to get data for */ + void *buffer, /* buffer to place output in */ + xfs_daddr_t bno, /* starting block of inode cluster */ + void *dip, /* on-disk inode pointer */ + int *res) /* bulkstat result code */ +{ + xfs_inode_t *ip; + dm_stat_t *buf; + xfs_handle_t handle; + u_int statstruct_sz; + int error; + + buf = (dm_stat_t *)buffer; + + if (ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino) { + *res = BULKSTAT_RV_NOTHING; + return EINVAL; + } + error = xfs_iget(mp, tp, ino, XFS_ILOCK_SHARED, &ip, bno); + if (error) { + *res = BULKSTAT_RV_NOTHING; + return(error); + } + if (ip->i_d.di_mode == 0) { + xfs_iput(ip, XFS_ILOCK_SHARED); + *res = BULKSTAT_RV_NOTHING; + return(ENOENT); + } + + /* + * copy everything to the dm_stat buffer + */ + xfs_ip_to_stat(mp, buf, ip); + + /* + * Make the handle and the link to the next dm_stat buffer + */ + dm_vp_to_handle(XFS_ITOV(ip), &handle); + bcopy(&handle, buf+1, sizeof(handle)); /* handle follows stat struct */ + + buf->dt_handle.vd_offset = (ssize_t) sizeof(dm_stat_t); + buf->dt_handle.vd_length = (size_t) XFS_HSIZE(handle); + + /* + * xfs_bulkstat increments the buf if calls the formatter with + * by the size passed into it, which is this here size. + */ + statstruct_sz = DM_STAT_SIZE(0); + statstruct_sz = (statstruct_sz+(DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1); + buf->_link = statstruct_sz; + + /* + * This is unused in bulkstat - so we zero it out. + */ + bzero((void *) &buf->dt_compname, sizeof(dm_vardata_t)); + + xfs_iput(ip, XFS_ILOCK_SHARED); + + *res = BULKSTAT_RV_DIDONE; + return(0); +} + + +STATIC int +xfs_get_dirents( + xfs_inode_t *dirp, + void *bufp, + size_t bufsz, + off_t *locp, + size_t *nreadp) +{ + int sink; + struct uio auio; + struct iovec aiov; + int rval; + + *nreadp = 0; + + aiov.iov_base = bufp; + aiov.iov_len = bufsz; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; +#ifdef __sgi + auio.uio_pio = 0; + auio.uio_pbuf = 0; +#endif + auio.uio_offset = *locp; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_resid = bufsz; + + rval = XFS_DIR_GETDENTS(dirp->i_mount, NULL, dirp, &auio, &sink); + if (! rval) { + *locp = (off_t) auio.uio_offset; + + /* + * number of bytes read into the dirent buffer + */ + *nreadp = bufsz - auio.uio_resid; + } + return(rval); +} + + +STATIC int +xfs_dirents_to_stats( + xfs_mount_t *mp, + xfs_dirent_t *direntp, /* array of dirent structs */ + void *bufp, /* buffer to fill */ + size_t direntbufsz, /* sz of filled part of dirent buf */ + size_t *spaceleftp, /* IO - space left in user buffer */ + size_t *nwrittenp, /* number of bytes written to 'bufp' */ + off_t *locp) +{ + xfs_dirent_t *p; + dm_stat_t *statp; + size_t reclen; + size_t namelen; + size_t spaceleft; + off_t prevoff; + int res; + + spaceleft = *spaceleftp; + *spaceleftp = 0; + *nwrittenp = 0; + prevoff = 0; /* sizeof this getdents record */ + + /* + * Go thru all the dirent records, making dm_stat structures from + * them, one by one, until dirent buffer is empty or stat buffer + * is full. + */ + p = direntp; + statp = (dm_stat_t *) bufp; + for (reclen = (size_t) p->d_reclen; direntbufsz > 0; + direntbufsz -= reclen, + p = (xfs_dirent_t *) ((char *) p + reclen), + reclen = (size_t) p->d_reclen) { + + namelen = strlen(p->d_name) + 1; + + /* + * Make sure we have enough space. + */ + if (spaceleft <= DM_STAT_SIZE(namelen)) { + /* + * d_off field in dirent_t points at the next entry. + */ + if (prevoff) /* did at least one; update location */ + *locp = prevoff; + *spaceleftp = 0; + + /* + * The last link is NULL. + */ + statp->_link = 0; + return(0); + } + + statp = (dm_stat_t *) bufp; + + (void)xfs_dm_bulkstat_one(mp, NULL, (xfs_ino_t)p->d_ino, statp, 0, 0, &res); + if (res != BULKSTAT_RV_DIDONE) + continue; + + /* + * On return from bulkstat_one(), stap->_link points + * at the end of the handle in the stat structure. + */ + statp->dt_compname.vd_offset = statp->_link; + statp->dt_compname.vd_length = namelen; + /* + * Directory entry name is guaranteed to be + * null terminated; the copy gets the '\0' too. + */ + bcopy(p->d_name, (char *) statp + statp->_link, namelen); + + /* Word-align the record */ + statp->_link = (statp->_link + namelen + (DM_STAT_ALIGN - 1)) + & ~(DM_STAT_ALIGN - 1); + + spaceleft -= statp->_link; + *nwrittenp += statp->_link; + bufp = (char *)statp + statp->_link; + + /* + * We need to rollback to this position if something happens. + * So we remember it. + */ + prevoff = p->d_off; + } + statp->_link = 0; + + /* + * If there's space left to put in more, caller should know that.. + */ + if (spaceleft > DM_STAT_SIZE(MAXNAMLEN)) { + *spaceleftp = spaceleft; + } + return(0); +} + + +/* xfs_dm_f_get_eventlist - return the dm_eventset_t mask for inode vp. */ + +STATIC int +xfs_dm_f_get_eventlist( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int *nelemp) /* in kernel space! */ +{ + dm_eventset_t eventset; + xfs_inode_t *ip; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + /* Note that we MUST return a regular file's managed region bits as + part of the mask because dm_get_eventlist is supposed to return the + union of all managed region flags in those bits. Since we only + support one region, we can just return the bits as they are. For + all other object types, the bits will already be zero. Handy, huh? + */ + + ip = XFS_BHVTOI(bdp); + eventset = ip->i_d.di_dmevmask; + + /* Now copy the event mask and event count back to the caller. We + return the lesser of nelem and DM_EVENT_MAX. + */ + + if (nelem > DM_EVENT_MAX) + nelem = DM_EVENT_MAX; + eventset &= (1 << nelem) - 1; + + *eventsetp = eventset; + *nelemp = nelem; + return(0); +} + + +/* xfs_dm_f_set_eventlist - update the dm_eventset_t mask in the inode vp. Only the + bits from zero to maxevent-1 are being replaced; higher bits are preserved. +*/ + +STATIC int +xfs_dm_f_set_eventlist( + bhv_desc_t *bdp, + dm_right_t right, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int maxevent) +{ + dm_eventset_t eventset; + dm_eventset_t max_mask; + dm_eventset_t valid_events; + vnode_t *vp; + xfs_inode_t *ip; + xfs_trans_t *tp; + xfs_mount_t *mp; + int error; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + eventset = *eventsetp; + if (maxevent >= sizeof(ip->i_d.di_dmevmask) * NBBY) + return(EINVAL); + max_mask = (1 << maxevent) - 1; + + vp = BHV_TO_VNODE(bdp); + if (vp->v_type == VDIR) { + valid_events = DM_XFS_VALID_DIRECTORY_EVENTS; + } else { /* file or symlink */ + valid_events = DM_XFS_VALID_FILE_EVENTS; + } + if ((eventset & max_mask) & ~valid_events) + return(EINVAL); + + /* Adjust the event mask so that the managed region bits will not + be altered. + */ + + max_mask &= ~(1 <i_mount; + tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS); + error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0); + if (error) { + xfs_trans_cancel(tp, 0); + return(error); + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + + ip->i_d.di_dmevmask = (eventset & max_mask) | (ip->i_d.di_dmevmask & ~max_mask); + ip->i_iocore.io_dmevmask = ip->i_d.di_dmevmask; + + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + VN_HOLD(vp); + xfs_trans_commit(tp, 0, NULL); + + return(0); +} + + +/* xfs_dm_fs_get_eventlist - return the dm_eventset_t mask for filesystem vfsp. */ + +STATIC int +xfs_dm_fs_get_eventlist( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int *nelemp) /* in kernel space! */ +{ + dm_eventset_t eventset; + xfs_mount_t *mp; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + mp = XFS_BHVTOI(bdp)->i_mount; + eventset = mp->m_dmevmask; + + /* Now copy the event mask and event count back to the caller. We + return the lesser of nelem and DM_EVENT_MAX. + */ + + if (nelem > DM_EVENT_MAX) + nelem = DM_EVENT_MAX; + eventset &= (1 << nelem) - 1; + + *eventsetp = eventset; + *nelemp = nelem; + return(0); +} + + +/* xfs_dm_fs_set_eventlist - update the dm_eventset_t mask in the mount structure for + filesystem vfsp. Only the bits from zero to maxevent-1 are being replaced; + higher bits are preserved. +*/ + +STATIC int +xfs_dm_fs_set_eventlist( + bhv_desc_t *bdp, + dm_right_t right, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int maxevent) +{ + dm_eventset_t eventset; + dm_eventset_t max_mask; + xfs_mount_t *mp; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + eventset = *eventsetp; + + mp = XFS_BHVTOI(bdp)->i_mount; + if (maxevent >= sizeof(mp->m_dmevmask) * NBBY) + return(EINVAL); + max_mask = (1 << maxevent) - 1; + + if ((eventset & max_mask) & ~DM_XFS_VALID_FS_EVENTS) + return(EINVAL); + + mp->m_dmevmask = (eventset & max_mask) | (mp->m_dmevmask & ~max_mask); + return(0); +} + + +/* Code in this routine must exactly match the logic in xfs_diordwr() in + order for this to work! +*/ + +STATIC int +xfs_dm_direct_ok( + bhv_desc_t *bdp, + dm_off_t off, + dm_size_t len, + void *bufp) +{ + xfs_mount_t *mp; + xfs_inode_t *ip; + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + /* Realtime files can ONLY do direct I/O. */ + + if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) + return(1); + + /* If direct I/O is disabled, or if the request is too small, use + buffered I/O. + */ + + if (!dm_min_dio_xfer || len < dm_min_dio_xfer) + return(0); + +#if 0 + /* If the request is not well-formed or is too large, use + buffered I/O. + */ + + if ((__psint_t)bufp & scache_linemask) /* if buffer not aligned */ + return(0); + if (off & mp->m_blockmask) /* if file offset not aligned */ + return(0); + if (len & mp->m_blockmask) /* if xfer length not aligned */ + return(0); + if (len > ctooff(v.v_maxdmasz - 1)) /* if transfer too large */ + return(0); + + /* A valid direct I/O candidate. */ + + return(1); +#else + return(0); +#endif +} + + +/* get a well-connected dentry. borrowed from nfsd_iget() */ +static struct dentry *dmapi_dget(struct inode *inode) +{ + struct list_head *lp; + struct dentry *result; + + spin_lock(&dcache_lock); + for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) { + result = list_entry(lp,struct dentry, d_alias); + if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) { + dget_locked(result); + spin_unlock(&dcache_lock); + /*iput(inode);*/ + return result; + } + } + spin_unlock(&dcache_lock); + result = d_alloc_root(inode); + if (result == NULL) { + /*iput(inode);*/ + return NULL; + } + result->d_flags |= DCACHE_NFSD_DISCONNECTED; + d_rehash(result); /* so a dput won't loose it */ + return result; +} + + +/* This routine started as a copy of routines rwv() and rdwr(), and then all + unnecessary code was removed. The copy was required because we need to + be able to select various combinations of FINVIS, FNONBLOCK, FDIRECT, and + FSYNC, yet we don't have a file descriptor and we don't have the file's + pathname. All we have is a handle. Hopefully someday rdwr() and rwv() + can be restructured such that all the file descriptor code stays in rwv(). + That way we could call rdwr() directly from here. +*/ + +STATIC int +xfs_dm_rdwr( + bhv_desc_t *bdp, + uint fflag, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp) +{ + int error; + int oflags; + ssize_t xfer; + vnode_t *vp = BHV_TO_VNODE(bdp); + struct file file; + struct inode *ip; + struct dentry *dentry; + uio_t uio; + iovec_t iov; + + if (off < 0 || vp->v_type != VREG) + return(EINVAL); + + + /* + * Disallow outsiders reading/writing swap. Not worried about data + * corruption so much as what happens when a process which has the + * vnode RWlock sleeps somewhere because there's no system memory, + * and the pager needs to acquire the lock to swap out pages: deadlock. + */ + if (vp->v_flag & VISSWAP && vp->v_type == VREG) + return EACCES; + + if (fflag & FMODE_READ) { + XFS_STATS_INC(xfsstats.xs_read_calls); + oflags = O_RDONLY; + } else { + XFS_STATS_INC(xfsstats.xs_write_calls); + oflags = O_WRONLY; + } + + /* Build file descriptor flags and I/O flags. FNONBLOCK is needed so + that we don't block on mandatory file locks. FINVIS is needed so + that we don't change any file timestamps. + */ + + oflags |= O_INVISIBLE | O_NONBLOCK; + if (xfs_dm_direct_ok(bdp, off, len, bufp)) + oflags |= O_DIRECT; + +/* XXX when will this be available in linux/XFS? + if (fflag & FSYNC) + fflags |= FSYNC; +*/ + + ip = LINVFS_GET_IP(vp); + if( ip->i_fop == NULL ){ + return(EINVAL); + } + + dentry = dmapi_dget(ip); + if( dentry == NULL ){ + return(ENOMEM); + } + + if( ip->i_ino != dentry->d_inode->i_ino ){ + dput(dentry); + return(EINVAL); + } + + error = init_private_file( &file, dentry, + (fflag&FMODE_READ ? FMODE_READ:FMODE_WRITE)); + if(error){ + dput(dentry); + return(EINVAL); + } + file.f_flags = oflags; + + uio.uio_iov = &iov; + uio.uio_offset = off; + uio.uio_fp = &file; + uio.uio_iovcnt = 1; + uio.uio_iov->iov_base = bufp; + uio.uio_iov->iov_len = uio.uio_resid = len; + + if (fflag & FMODE_READ) { + VOP_READ(vp, &uio, 0, NULL, NULL, error); + } else { + VOP_WRITE(vp, &uio, 0, NULL, NULL, error); + } + + dput(dentry); + + if (!error) + linvfs_revalidate_core(ip, ATTR_COMM); + + *rvp = xfer = len - uio.uio_resid; + + if (fflag & FMODE_READ) { + XFS_STATS_ADD(xfsstats.xs_read_bytes, xfer); + } else { + XFS_STATS_ADD(xfsstats.xs_write_bytes, xfer); + } + + return error; +} + +/* ARGSUSED */ +STATIC int +xfs_dm_clear_inherit( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrname_t *attrnamep) +{ + return(ENOSYS); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_create_by_handle( + bhv_desc_t *bdp, + dm_right_t right, + void *hanp, + size_t hlen, + char *cname) +{ + return(ENOSYS); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_downgrade_right( + bhv_desc_t *bdp, + dm_right_t right, + u_int type) /* DM_FSYS_OBJ or zero */ +{ +#ifdef DEBUG_RIGHTS + char buffer[sizeof(xfs_handle_t) * 2 + 1]; + + if (!xfs_bdp_to_hexhandle(bdp, type, buffer)) { + printf("dm_downgrade_right: old %d new %d type %d handle %s\n", + right, DM_RIGHT_SHARED, type, buffer); + } else { + printf("dm_downgrade_right: old %d new %d type %d handle " + "\n", right, DM_RIGHT_SHARED, type); + } +#endif /* DEBUG_RIGHTS */ + return(0); +} + + +/* Note: xfs_dm_get_allocinfo() makes no attempt to coalesce two adjacent + extents when both are of type DM_EXTENT_RES; this is left to the caller. + XFS guarantees that there will never be two adjacent DM_EXTENT_HOLE extents. + + In order to provide the caller with all extents in a file including + those beyond the file's last byte offset, we have to use the xfs_bmapi() + interface. (VOP_BMAP won't let us see past EOF, and xfs_getbmap is too + buggy.) +*/ + +STATIC int +xfs_dm_get_allocinfo_rvp( + bhv_desc_t *bdp, + dm_right_t right, + dm_off_t *offp, + u_int nelem, + dm_extent_t *extentp, + u_int *nelemp, + int *rvp) +{ + xfs_inode_t *ip; /* xfs incore inode pointer */ + xfs_mount_t *mp; /* file system mount point */ + xfs_fileoff_t fsb_offset; + xfs_filblks_t fsb_length; + dm_off_t startoff; + int elem; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + +#ifdef __sgi + if (copyin(offp, &startoff, sizeof(startoff))) + return(EFAULT); +#else + if (copy_from_user( &startoff, offp, sizeof(startoff))) + return(EFAULT); +#endif + + if (startoff > XFS_MAX_FILE_OFFSET) + return(EINVAL); + + if (nelem == 0) { +#ifdef __sgi + if (suword(nelemp, 1)) + return(EFAULT); +#else + if (put_user(1, nelemp)) + return(EFAULT); +#endif + return(E2BIG); + } + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + /* Convert the caller's starting offset into filesystem allocation + units as required by xfs_bmapi(). Round the offset down so that + it is sure to be included in the reply. + */ + + fsb_offset = XFS_B_TO_FSBT(mp, startoff); + fsb_length = XFS_B_TO_FSB(mp, XFS_MAX_FILE_OFFSET) - fsb_offset; + elem = 0; + + while (fsb_length && elem < nelem) { + xfs_bmbt_irec_t bmp[50]; + xfs_fsblock_t firstblock; /* start block for bmapi */ + dm_extent_t extent; + xfs_filblks_t fsb_bias; + dm_size_t bias; + int error; + int lock; + int num; + int i; + + /* Compute how many getbmap structures to use on the xfs_bmapi + call. + */ + + num = MIN(nelem - elem, sizeof(bmp) / sizeof(bmp[0])); + + xfs_ilock(ip, XFS_IOLOCK_SHARED); + lock = xfs_ilock_map_shared(ip); + + firstblock = NULLFSBLOCK; + error = xfs_bmapi(NULL, ip, fsb_offset, fsb_length, + XFS_BMAPI_ENTIRE, &firstblock, 0, bmp, &num, NULL); + + xfs_iunlock_map_shared(ip, lock); + xfs_iunlock(ip, XFS_IOLOCK_SHARED); + + if (error) + return(error); + + /* Fill in the caller's extents, adjusting the bias in the + first entry if necessary. + */ + + for (i = 0; i < num; i++, extentp++) { + bias = startoff - XFS_FSB_TO_B(mp, bmp[i].br_startoff); + extent.ex_offset = startoff; + extent.ex_length = + XFS_FSB_TO_B(mp, bmp[i].br_blockcount) - bias; + if (bmp[i].br_startblock == HOLESTARTBLOCK) { + extent.ex_type = DM_EXTENT_HOLE; + } else { + extent.ex_type = DM_EXTENT_RES; + } + startoff = extent.ex_offset + extent.ex_length; + +#ifdef __sgi + if (copyout(&extent, extentp, sizeof(extent))) + return(EFAULT); +#else + if (copy_to_user( extentp, &extent, sizeof(extent))) + return(EFAULT); +#endif + + fsb_bias = fsb_offset - bmp[i].br_startoff; + fsb_offset += bmp[i].br_blockcount - fsb_bias; + fsb_length -= bmp[i].br_blockcount - fsb_bias; + elem++; + } + } + + if (fsb_length == 0) { + startoff = 0; + } +#ifdef __sgi + if (copyout(&startoff, offp, sizeof(startoff))) + return(EFAULT); +#else + if (copy_to_user( offp, &startoff, sizeof(startoff))) + return(EFAULT); +#endif + +#ifdef __sgi + if (copyout(&elem, nelemp, sizeof(elem))) + return(EFAULT); +#else + if (copy_to_user( nelemp, &elem, sizeof(elem))) + return(EFAULT); +#endif + +#ifdef __sgi + rvp->r_val1 = (fsb_length == 0 ? 0 : 1); +#else + *rvp = (fsb_length == 0 ? 0 : 1); +#endif + + return(0); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_get_bulkall_rvp( + bhv_desc_t *bdp, + dm_right_t right, + u_int mask, + dm_attrname_t *attrnamep, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, /* address of buffer in user space */ + size_t *rlenp, /* user space address */ + int *rvalp) +{ + return(ENOSYS); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_get_bulkattr_rvp( + bhv_desc_t *bdp, + dm_right_t right, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvalp) +{ + int error, done; + int nelems; + u_int statstruct_sz; + dm_attrloc_t loc; + vnode_t *vp = BHV_TO_VNODE(bdp); + bhv_desc_t *vfs_bdp = bhv_lookup_unlocked(VFS_BHVHEAD(vp->v_vfsp), &xfs_vfsops); + xfs_mount_t *mp = XFS_BHVTOM (vfs_bdp); + + if (right < DM_RIGHT_SHARED) + return(EACCES); + +#ifdef __sgi + if (copyin(locp, &loc, sizeof(loc))) + return(EFAULT); +#else + if (copy_from_user( &loc, locp, sizeof(loc))) + return(EFAULT); +#endif + + /* Because we will write directly to the user's buffer, make sure that + the buffer is properly aligned. + */ + + if (((__psint_t)bufp & (DM_STAT_ALIGN - 1)) != 0) + return(EFAULT); + + /* size of the handle is constant for this function */ + + statstruct_sz = DM_STAT_SIZE(0); + statstruct_sz = (statstruct_sz+(DM_STAT_ALIGN-1)) & ~(DM_STAT_ALIGN-1); + + nelems = buflen / statstruct_sz; + if (! nelems) { +#ifdef __sgi + if (xfs_cpoutsizet(rlenp, statstruct_sz)) + return(EFAULT); +#else + if (put_user( statstruct_sz, rlenp )) + return(EFAULT); +#endif + return(E2BIG); + } + + /* + * fill the buffer with dm_stat_t's + */ + + error = xfs_bulkstat(mp, NULL, + (xfs_ino_t *)&loc, + &nelems, + xfs_dm_bulkstat_one, + statstruct_sz, + bufp, + BULKSTAT_FG_IGET, + &done); + if (error) + return(error); + if (!done) { +#ifdef __sgi + rvalp->r_val1 = 1; +#else + *rvalp = 1; +#endif + } else { +#ifdef __sgi + rvalp->r_val1 = 0; +#else + *rvalp = 0; +#endif + } +#ifdef __sgi + if (xfs_cpoutsizet(rlenp, statstruct_sz * nelems)) + return(EFAULT); +#else + if (put_user( statstruct_sz * nelems, rlenp )) + return(EFAULT); +#endif + +#ifdef __sgi + if (copyout(&loc, locp, sizeof(loc))) + return(EFAULT); +#else + if (copy_to_user( locp, &loc, sizeof(loc))) + return(EFAULT); +#endif + /* + * If we didn't do any, we must not have any more to do. + */ + if (nelems < 1) + return(0); + /* set _link in the last struct to zero */ +#ifdef __sgi + if (suword( + &((dm_stat_t *)((char *)bufp + statstruct_sz*(nelems-1)))->_link, + 0) + ) + return(EFAULT); +#else + if (put_user( 0, + &((dm_stat_t *)((char *)bufp + statstruct_sz*(nelems-1)))->_link) + ) + return(EFAULT); +#endif + return(0); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_get_config( + bhv_desc_t *bdp, + dm_right_t right, + dm_config_t flagname, + dm_size_t *retvalp) +{ + dm_size_t retval; + + switch (flagname) { + case DM_CONFIG_DTIME_OVERLOAD: + case DM_CONFIG_PERS_ATTRIBUTES: + case DM_CONFIG_PERS_EVENTS: + case DM_CONFIG_PERS_MANAGED_REGIONS: + case DM_CONFIG_PUNCH_HOLE: + case DM_CONFIG_WILL_RETRY: + retval = DM_TRUE; + break; + + case DM_CONFIG_CREATE_BY_HANDLE: /* these will never be done */ + case DM_CONFIG_LOCK_UPGRADE: + case DM_CONFIG_PERS_INHERIT_ATTRIBS: + retval = DM_FALSE; + break; + + case DM_CONFIG_BULKALL: /* these will be done someday */ + retval = DM_FALSE; + break; + case DM_CONFIG_MAX_ATTR_ON_DESTROY: + retval = DM_MAX_ATTR_BYTES_ON_DESTROY; + break; + + case DM_CONFIG_MAX_ATTRIBUTE_SIZE: + retval = ATTR_MAX_VALUELEN; + break; + + case DM_CONFIG_MAX_HANDLE_SIZE: + retval = DM_MAX_HANDLE_SIZE; + break; + + case DM_CONFIG_MAX_MANAGED_REGIONS: + retval = 1; + break; + + case DM_CONFIG_TOTAL_ATTRIBUTE_SPACE: + retval = 0x7fffffff; /* actually it's unlimited */ + break; + + default: + return(EINVAL); + } + + /* Copy the results back to the user. */ + +#ifdef __sgi + if (copyout(&retval, retvalp, sizeof(retval))) + return(EFAULT); +#else + if (copy_to_user( retvalp, &retval, sizeof(retval))) + return(EFAULT); +#endif + return(0); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_get_config_events( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp) +{ + dm_eventset_t eventset; + + if (nelem == 0) + return(EINVAL); + + eventset = DM_XFS_SUPPORTED_EVENTS; + + /* Now copy the event mask and event count back to the caller. We + return the lesser of nelem and DM_EVENT_MAX. + */ + + if (nelem > DM_EVENT_MAX) + nelem = DM_EVENT_MAX; + eventset &= (1 << nelem) - 1; + +#ifdef __sgi + if (copyout(&eventset, eventsetp, sizeof(eventset))) + return(EFAULT); +#else + if (copy_to_user( eventsetp, &eventset, sizeof(eventset))) + return(EFAULT); +#endif + +#ifdef __sgi + if (suword(nelemp, nelem)) + return(EFAULT); +#else + if (put_user(nelem, nelemp)) + return(EFAULT); +#endif + return(0); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_get_destroy_dmattr( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrname_t *attrnamep, + char **valuepp, + int *vlenp) +{ + char buffer[XFS_BUG_KLUDGE]; + dm_dkattrname_t dkattrname; + int alloc_size; + int value_len; + char *value; + int error; + vnode_t *vp = BHV_TO_VNODE(bdp); + + *vlenp = -1; /* assume failure by default */ + + if (attrnamep->an_chars[0] == '\0') + return(EINVAL); + + /* Build the on-disk version of the attribute name. */ + + strcpy(dkattrname.dan_chars, dmattr_prefix); + strncpy(&dkattrname.dan_chars[DMATTR_PREFIXLEN], + (char *)attrnamep->an_chars, DM_ATTR_NAME_SIZE + 1); + dkattrname.dan_chars[sizeof(dkattrname.dan_chars) - 1] = '\0'; + + /* VOP_ATTR_GET will not return anything if the buffer is too small, + and we don't know how big to make the buffer, so this may take + two tries to get it right. The initial try must use a buffer of + at least XFS_BUG_KLUDGE bytes to prevent buffer overflow because + of a bug in XFS. + */ + + alloc_size = 0; + value_len = sizeof(buffer); /* in/out parameter */ + value = buffer; + + VOP_ATTR_GET(vp, dkattrname.dan_chars, value, &value_len, + ATTR_ROOT, sys_cred, error); + + if (error == E2BIG) { + alloc_size = value_len; + value = kmem_alloc(alloc_size, KM_SLEEP); + + VOP_ATTR_GET(vp, dkattrname.dan_chars, value, + &value_len, ATTR_ROOT, sys_cred, error); + } + if (error) { + if (alloc_size) + kmem_free(value, alloc_size); + return(error); + } + + /* The attribute exists and has a value. Note that a value_len of + zero is valid! + */ + + if (value_len == 0) { + *vlenp = 0; + return(0); + } + + if (!alloc_size) { + value = kmem_alloc(value_len, KM_SLEEP); + bcopy(buffer, value, value_len); + } else if (value_len > DM_MAX_ATTR_BYTES_ON_DESTROY) { + int value_len2 = DM_MAX_ATTR_BYTES_ON_DESTROY; + char *value2; + + value2 = kmem_alloc(value_len2, KM_SLEEP); + bcopy(value, value2, value_len2); + kmem_free(value, value_len); + value = value2; + value_len = value_len2; + } + *vlenp = value_len; + *valuepp = value; + return(0); +} + +/* This code was taken from xfs_fcntl(F_DIOINFO) and modified slightly because + we don't have a flags parameter (no open file). + Taken from xfs_ioctl(XFS_IOC_DIOINFO) on Linux. +*/ + +STATIC int +xfs_dm_get_dioinfo( + bhv_desc_t *bdp, + dm_right_t right, + dm_dioinfo_t *diop) +{ + dm_dioinfo_t dio; + xfs_mount_t *mp; + xfs_inode_t *ip; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + +#ifdef __sgi + /* + * We align to the secondary cache line size so that we + * don't have to worry about nasty writeback caches on + * I/O incoherent machines. Making this less than a page + * requires setting the maximum I/O size to 1 page less + * than maxdmasz. This is for the case of a maximum + * size I/O that is not page aligned. It requires the + * maximum size plus 1 pages. + */ + ASSERT(scache_linemask != 0); + +#ifdef MH_R10000_SPECULATION_WAR + if (IS_R10000()) + dio.d_mem = _PAGESZ; + else + dio.d_mem = scache_linemask + 1; +#elif R10000_SPECULATION_WAR /* makes tlb invalidate during dma more + effective, by decreasing the likelihood of a valid reference in the + same page as dma user address space; leaving the tlb invalid avoids + the speculative reference. We return the more stringent + "requirements" on the fcntl(), but do *NOT* enforced them + in the read/write code, to be sure we don't break apps... */ + dio.d_mem = _PAGESZ; +#else + dio.d_mem = scache_linemask + 1; +#endif +#endif /* __sgi */ + + /* + * this only really needs to be BBSIZE. + * it is set to the file system block size to + * avoid having to do block zeroing on short writes. + */ + dio.d_miniosz = mp->m_sb.sb_blocksize; + dio.d_maxiosz = XFS_FSB_TO_B(mp, + XFS_B_TO_FSBT(mp, pagebuf_max_direct())); + dio.d_mem = 512; + + if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) { + dio.d_dio_only = DM_TRUE; + } else { + dio.d_dio_only = DM_FALSE; + } + +#ifdef __sgi + if (copyout(&dio, diop, sizeof(dio))) + return(EFAULT); +#else + if (copy_to_user(diop, &dio, sizeof(dio))) + return(EFAULT); +#endif + return(0); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_get_dirattrs_rvp( + bhv_desc_t *bdp, + dm_right_t right, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, /* address of buffer in user space */ + size_t *rlenp, /* user space address */ + int *rvp) +{ + xfs_inode_t *dp; + xfs_mount_t *mp; + size_t direntbufsz, statbufsz; + size_t nread, spaceleft, nwritten=0; + void *direntp, *statbufp; + uint lock_mode; + int error; + dm_attrloc_t loc; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + +#ifdef __sgi + if (copyin(locp, &loc, sizeof(loc))) + return(EFAULT); +#else + if (copy_from_user( &loc, locp, sizeof(loc))) + return(EFAULT); +#endif + + if ((buflen / DM_STAT_SIZE(MAXNAMLEN)) == 0) { +#ifdef __sgi + if (xfs_cpoutsizet(rlenp, DM_STAT_SIZE(MAXNAMLEN))) + return(EFAULT); +#else + if (put_user( DM_STAT_SIZE(MAXNAMLEN), rlenp )) + return(EFAULT); +#endif + return(E2BIG); + } + + dp = XFS_BHVTOI(bdp); + mp = dp->i_mount; + if ((dp->i_d.di_mode & IFMT) != IFDIR) + return(ENOTDIR); + + /* + * Don't get more dirents than are guaranteed to fit. + * The minimum that the stat buf holds is the buf size over + * maximum entry size. That times the minimum dirent size + * is an overly conservative size for the dirent buf. + */ + statbufsz = NBPP; + direntbufsz = (NBPP / DM_STAT_SIZE(MAXNAMLEN)) * sizeof(xfs_dirent_t); + + direntp = kmem_alloc(direntbufsz, KM_SLEEP); + statbufp = kmem_alloc(statbufsz, KM_SLEEP); + error = 0; + spaceleft = buflen; + /* + * Keep getting dirents until the ubuffer is packed with + * dm_stat structures. + */ + do { + ulong dir_gen = 0; + + lock_mode = xfs_ilock_map_shared(dp); + /* See if the directory was removed after it was opened. */ + if (dp->i_d.di_nlink <= 0) { + xfs_iunlock_map_shared(dp, lock_mode); + return(ENOENT); + } + if (dir_gen == 0) + dir_gen = dp->i_gen; + else if (dir_gen != dp->i_gen) { + /* if dir changed, quit. May be overzealous... */ + xfs_iunlock_map_shared(dp, lock_mode); + break; + } + error = xfs_get_dirents(dp, direntp, direntbufsz, (off_t *)&loc, + &nread); + xfs_iunlock_map_shared(dp, lock_mode); + + if (error) { + break; + } + if (nread == 0) + break; + /* + * Now iterate thru them and call bulkstat_one() on all + * of them + */ + error = xfs_dirents_to_stats(mp, + (xfs_dirent_t *) direntp, + statbufp, + nread, + &spaceleft, + &nwritten, + (off_t *)&loc); + if (error) { + break; + } + + if (nwritten) { +#ifdef __sgi + if (copyout(statbufp, bufp, nwritten)) { +#else + if (copy_to_user( bufp, statbufp, nwritten)) { +#endif + error = EFAULT; + break; + } + break; + } + } while (spaceleft); + /* + * If xfs_get_dirents found anything, there might be more to do. + * If it didn't read anything, signal all done (rval == 0). + * (Doesn't matter either way if there was an error.) + */ + if (nread) { +#ifdef __sgi + rvp->r_val1 = 1; +#else + *rvp = 1; +#endif + } else { +#ifdef __sgi + rvp->r_val1 = 0; +#else + *rvp = 0; +#endif + } + + kmem_free(statbufp, statbufsz); + kmem_free(direntp, direntbufsz); + if (!error){ +#ifdef __sgi + if (xfs_cpoutsizet(rlenp, buflen - spaceleft)) + return(EFAULT); +#else + if (put_user( buflen - spaceleft, rlenp)) + return(EFAULT); +#endif + } + +#ifdef __sgi + if (!error && copyout(&loc, locp, sizeof(loc))) + error = EFAULT; +#else + if (!error && copy_to_user(locp, &loc, sizeof(loc))) + error = EFAULT; +#endif + return(error); +} + + +STATIC int +xfs_dm_get_dmattr( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrname_t *attrnamep, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + dm_dkattrname_t name; + char *value; + int value_len; + int alloc_size; + int error; + vnode_t *vp = BHV_TO_VNODE(bdp); + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + if ((error = xfs_copyin_attrname(attrnamep, &name)) != 0) + return(error); + + /* Allocate a buffer to receive the attribute's value. We allocate + at least one byte even if the caller specified a buflen of zero. + (A buflen of zero is considered valid.) + + Allocating a minimum of XFS_BUG_KLUDGE bytes temporarily works + around a bug within XFS in which in-inode attribute values are not + checked to see if they will fit in the buffer before they are + copied. Since no in-core attribute value can be larger than 256 + bytes (an 8-bit size field), we allocate that minimum size here to + prevent buffer overrun in both the kernel's and user's buffers. + */ + + alloc_size = buflen; + if (alloc_size < XFS_BUG_KLUDGE) + alloc_size = XFS_BUG_KLUDGE; + if (alloc_size > ATTR_MAX_VALUELEN) + alloc_size = ATTR_MAX_VALUELEN; + value = kmem_alloc(alloc_size, KM_SLEEP); + + /* Get the attribute's value. */ + + value_len = alloc_size; /* in/out parameter */ + + VOP_ATTR_GET(vp, name.dan_chars, value, &value_len, + ATTR_ROOT, get_current_cred(), error); + + /* DMAPI requires an errno of ENOENT if an attribute does not exist, + so remap ENOATTR here. + */ + + if (error == ENOATTR) + error = ENOENT; + if (!error && value_len > buflen) + error = E2BIG; +#ifdef __sgi + if (!error && copyout(value, bufp, value_len)) + error = EFAULT; +#else + if (!error && copy_to_user(bufp, value, value_len)) + error = EFAULT; +#endif + if (!error || error == E2BIG) { +#ifdef __sgi + if (xfs_cpoutsizet(rlenp, value_len)) + error = EFAULT; +#else + if (put_user(value_len, rlenp)) + error = EFAULT; +#endif + } + + kmem_free(value, alloc_size); + return(error); +} + +STATIC int +xfs_dm_get_eventlist( + bhv_desc_t *bdp, + dm_right_t right, + u_int type, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp) +{ + int error; + + if (type == DM_FSYS_OBJ) { + error = xfs_dm_fs_get_eventlist(bdp, right, nelem, + eventsetp, nelemp); + } else { + error = xfs_dm_f_get_eventlist(bdp, right, nelem, + eventsetp, nelemp); + } + return(error); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_get_fileattr( + bhv_desc_t *bdp, + dm_right_t right, + u_int mask, /* not used; always return everything */ + dm_stat_t *statp) +{ + dm_stat_t stat; + xfs_inode_t *ip; + xfs_mount_t *mp; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + /* Find the mount point. */ + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + xfs_ilock(ip, XFS_ILOCK_SHARED); + xfs_ip_to_stat(mp, &stat, ip); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + +#ifdef __sgi + if (copyout(&stat, statp, sizeof(stat))) + return(EFAULT); +#else + if (copy_to_user( statp, &stat, sizeof(stat))) + return(EFAULT); +#endif + return(0); +} + + +/* We currently only support a maximum of one managed region per file, and + use the DM_EVENT_READ, DM_EVENT_WRITE, and DM_EVENT_TRUNCATE events in + the file's dm_eventset_t event mask to implement the DM_REGION_READ, + DM_REGION_WRITE, and DM_REGION_TRUNCATE flags for that single region. +*/ + +STATIC int +xfs_dm_get_region( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_region_t *regbufp, + u_int *nelemp) +{ + dm_eventset_t evmask; + dm_region_t region; + xfs_inode_t *ip; + u_int elem; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + ip = XFS_BHVTOI(bdp); + evmask = ip->i_d.di_dmevmask; /* read the mask "atomically" */ + + /* Get the file's current managed region flags out of the + dm_eventset_t mask and use them to build a managed region that + covers the entire file, i.e. set rg_offset and rg_size to zero. + */ + + bzero((char *)®ion, sizeof(region)); + + if (evmask & (1 << DM_EVENT_READ)) + region.rg_flags |= DM_REGION_READ; + if (evmask & (1 << DM_EVENT_WRITE)) + region.rg_flags |= DM_REGION_WRITE; + if (evmask & (1 << DM_EVENT_TRUNCATE)) + region.rg_flags |= DM_REGION_TRUNCATE; + + elem = (region.rg_flags ? 1 : 0); + +#ifdef __sgi + if (copyout(&elem, nelemp, sizeof(elem))) + return(EFAULT); +#else + if (copy_to_user( nelemp, &elem, sizeof(elem))) + return(EFAULT); +#endif + if (elem > nelem) + return(E2BIG); +#ifdef __sgi + if (elem && copyout(®ion, regbufp, sizeof(region))) + return(EFAULT); +#else + if (elem && copy_to_user(regbufp, ®ion, sizeof(region))) + return(EFAULT); +#endif + return(0); +} + + +STATIC int +xfs_dm_getall_dmattr( + bhv_desc_t *bdp, + dm_right_t right, + size_t buflen, + void *bufp, + size_t *rlenp) +{ + attrlist_cursor_kern_t cursor; + attrlist_t *attrlist; + dm_attrlist_t *ulist; + int *last_link; + int alignment; + int total_size; + int list_size = 8192; /* should be big enough */ + int error; + vnode_t *vp = BHV_TO_VNODE(bdp); + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + /* Verify that the user gave us a buffer that is 4-byte aligned, lock + it down, and work directly within that buffer. As a side-effect, + values of buflen < sizeof(int) return EINVAL. + */ + + alignment = sizeof(int) - 1; + if (((__psint_t)bufp & alignment) != 0) { + return(EFAULT); + } + buflen &= ~alignment; /* round down the alignment */ + +#if defined(HAVE_USERACC) + if ((error = useracc(bufp, buflen, B_READ, NULL)) != 0) + return error; +#endif + + /* Initialize all the structures and variables for the main loop. */ + + bzero(&cursor, sizeof(cursor)); + attrlist = (attrlist_t *)kmem_alloc(list_size, KM_SLEEP); + total_size = 0; + ulist = (dm_attrlist_t *)bufp; + last_link = NULL; + + /* Use VOP_ATTR_LIST to get the names of DMAPI attributes, and use + VOP_ATTR_GET to get their values. There is a risk here that the + DMAPI attributes could change between the VOP_ATTR_LIST and + VOP_ATTR_GET calls. If we can detect it, we return EIO to notify + the user. + */ + + do { + int i; + + /* Get a buffer full of attribute names. If there aren't any + more or if we encounter an error, then finish up. + */ + + VOP_ATTR_LIST(vp, (char *)attrlist, list_size, + ATTR_ROOT, &cursor, get_current_cred(), error); + + if (error || attrlist->al_count == 0) + break; + + for (i = 0; i < attrlist->al_count; i++) { + attrlist_ent_t *entry; + char *user_name; + int size_needed; + int value_len; + + /* Skip over all non-DMAPI attributes. If the + attribute name is too long, we assume it is + non-DMAPI even if it starts with the correct + prefix. + */ + + entry = ATTR_ENTRY(attrlist, i); + if (strncmp(entry->a_name, dmattr_prefix, DMATTR_PREFIXLEN)) + continue; + user_name = &entry->a_name[DMATTR_PREFIXLEN]; + if (strlen(user_name) > DM_ATTR_NAME_SIZE) + continue; + + /* We have a valid DMAPI attribute to return. If it + won't fit in the user's buffer, we still need to + keep track of the number of bytes for the user's + next call. + */ + + + size_needed = sizeof(*ulist) + entry->a_valuelen; + size_needed = (size_needed + alignment) & ~alignment; + + total_size += size_needed; + if (total_size > buflen) + continue; + + /* Start by filling in all the fields in the + dm_attrlist_t structure. + */ + + strncpy((char *)ulist->al_name.an_chars, user_name, + DM_ATTR_NAME_SIZE); + ulist->al_data.vd_offset = sizeof(*ulist); + ulist->al_data.vd_length = entry->a_valuelen; + ulist->_link = size_needed; + last_link = &ulist->_link; + + /* Next read the attribute's value into its correct + location after the dm_attrlist structure. Any sort + of error indicates that the data is moving under us, + so we return EIO to let the user know. + */ + + value_len = entry->a_valuelen; + + VOP_ATTR_GET(vp, entry->a_name, + (void *)(ulist + 1), &value_len, + ATTR_ROOT, get_current_cred(), error); + + if (error || value_len != entry->a_valuelen) { + error = EIO; + break; + } + + ulist = (dm_attrlist_t *)((char *)ulist + ulist->_link); + } + } while (!error && attrlist->al_more); + if (last_link) + *last_link = 0; + + if (!error && total_size > buflen) + error = E2BIG; + if (!error || error == E2BIG) { +#ifdef __sgi + if (xfs_cpoutsizet(rlenp, total_size)) + error = EFAULT; +#else + if (put_user(total_size, rlenp)) + error = EFAULT; +#endif + } + +#if defined(HAVE_USERACC) + unuseracc(bufp, buflen, B_READ); +#endif + kmem_free(attrlist, list_size); + return(error); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_getall_inherit( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_inherit_t *inheritbufp, + u_int *nelemp) +{ + return(ENOSYS); +} + + +/* Initialize location pointer for subsequent dm_get_dirattrs, + dm_get_bulkattr, and dm_get_bulkall calls. The same initialization must + work for vnode-based routines (dm_get_dirattrs) and filesystem-based + routines (dm_get_bulkattr and dm_get_bulkall). Filesystem-based functions + call this routine using the filesystem's root vnode. +*/ + +/* ARGSUSED */ +STATIC int +xfs_dm_init_attrloc( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrloc_t *locp) +{ + dm_attrloc_t loc = 0; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + +#ifdef __sgi + if (copyout(&loc, locp, sizeof(loc))) + return(EFAULT); +#else + if (copy_to_user( locp, &loc, sizeof(loc))) + return(EFAULT); +#endif + return(0); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_mkdir_by_handle( + bhv_desc_t *bdp, + dm_right_t right, + void *hanp, + size_t hlen, + char *cname) +{ + return(ENOSYS); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_probe_hole( + bhv_desc_t *bdp, + dm_right_t right, + dm_off_t off, + dm_size_t len, /* we ignore this for now */ + dm_off_t *roffp, + dm_size_t *rlenp) +{ + dm_off_t roff; + dm_size_t rlen; + xfs_inode_t *ip; + xfs_mount_t *mp; + uint lock_flags; + xfs_fsize_t realsize; + u_int bsize; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + ip = XFS_BHVTOI(bdp); + if ((ip->i_d.di_mode & IFMT) != IFREG) + return(EINVAL); + + mp = ip->i_mount; + bsize = mp->m_sb.sb_blocksize; + + lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL; + xfs_ilock(ip, lock_flags); + realsize = ip->i_d.di_size; + xfs_iunlock(ip, lock_flags); + if (off >= realsize) + return(E2BIG); + + roff = (off + bsize-1) & ~(bsize-1); + rlen = 0; /* Only support punches to EOF for now */ +#ifdef __sgi + if (copyout(&roff, roffp, sizeof(roff))) + return(EFAULT); +#else + if (copy_to_user( roffp, &roff, sizeof(roff))) + return(EFAULT); +#endif +#ifdef __sgi + if (copyout(&rlen, rlenp, sizeof(rlen))) + return(EFAULT); +#else + if (copy_to_user( rlenp, &rlen, sizeof(rlen))) + return(EFAULT); +#endif + return(0); +} + + +STATIC int +xfs_dm_punch_hole( + bhv_desc_t *bdp, + dm_right_t right, + dm_off_t off, + dm_size_t len) +{ + xfs_inode_t *ip; + xfs_trans_t *tp; + xfs_trans_t *tp2; + xfs_mount_t *mp; + vnode_t *vp = BHV_TO_VNODE(bdp); + int error; + uint lock_flags; + uint commit_flags; + xfs_fsize_t realsize; + u_int bsize; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + if (vp->v_type != VREG) + return(EINVAL); + if (len != 0) /* Only support punches to EOF for now */ + return(EAGAIN); + if (VN_MAPPED(vp)) + return(EBUSY); + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + bsize = mp->m_sb.sb_blocksize; + + if (off & (bsize-1)) + return(EAGAIN); + + lock_flags = XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL; + xfs_ilock(ip, lock_flags); + + realsize = ip->i_d.di_size; /* saved size to restore to */ + if (off >= realsize) { /* also check block boundary */ + xfs_iunlock(ip, lock_flags); + return(EINVAL); + } + + /* + * Before we join the inode to the transaction, take care of + * the part of the truncation that must be done without the + * inode lock. This needs to be done before joining the inode + * to the transaction, because the inode cannot be unlocked + * once it is a part of the transaction. + */ + xfs_iunlock(ip, XFS_ILOCK_EXCL); + tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE); + if ((error = xfs_trans_reserve(tp, 0, + XFS_ITRUNCATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return(error); + } + tp2 = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE); + if ((error = xfs_trans_reserve(tp2, 0, + XFS_ITRUNCATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + xfs_trans_cancel(tp2, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return(error); + } + commit_flags = XFS_TRANS_RELEASE_LOG_RES; + /* --- start of truncate --- */ + xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, (xfs_fsize_t) off); + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, lock_flags); + xfs_trans_ihold(tp, ip); + xfs_itruncate_finish(&tp, ip, (xfs_fsize_t) off, XFS_DATA_FORK, 0); + + /* + * If this is a synchronous mount, make sure that the + * transaction goes to disk before returning to the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + xfs_trans_commit(tp, commit_flags, NULL); + /* --- end of truncate --- */ + + /* --- start of grow --- */ + /* ip left locked after previous commit */ + xfs_igrow_start(ip, realsize, get_current_cred()); + xfs_trans_ijoin(tp2, ip, lock_flags); + xfs_igrow_finish(tp2, ip, realsize, 0); + + VN_HOLD(vp); + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp2); + } + xfs_trans_commit(tp2, commit_flags, NULL); + /* --- end of grow --- */ + + /* ip unlocked during the commit */ + return(0); +} + + +STATIC int +xfs_dm_read_invis_rvp( + bhv_desc_t *bdp, + dm_right_t right, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp) +{ + int fflag; + + if (right < DM_RIGHT_SHARED) + return(EACCES); + + fflag = FMODE_READ; + return(xfs_dm_rdwr(bdp, fflag, off, len, bufp, rvp)); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_release_right( + bhv_desc_t *bdp, + dm_right_t right, + u_int type) /* DM_FSYS_OBJ or zero */ +{ +#ifdef DEBUG_RIGHTS + char buffer[sizeof(xfs_handle_t) * 2 + 1]; + + if (!xfs_bdp_to_hexhandle(bdp, type, buffer)) { + printf("dm_release_right: old %d type %d handle %s\n", + right, type, buffer); + } else { + printf("dm_release_right: old %d type %d handle " + " \n", right, type); + } +#endif /* DEBUG_RIGHTS */ + return(0); +} + + +STATIC int +xfs_dm_remove_dmattr( + bhv_desc_t *bdp, + dm_right_t right, + int setdtime, + dm_attrname_t *attrnamep) +{ + dm_dkattrname_t name; + vnode_t *vp = BHV_TO_VNODE(bdp); + int error; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + if ((error = xfs_copyin_attrname(attrnamep, &name)) != 0) + return(error); + + /* Remove the attribute from the object. */ + + VOP_ATTR_REMOVE(vp, name.dan_chars, + (setdtime ? ATTR_ROOT : ATTR_ROOT|ATTR_KERNOTIME), + get_current_cred(), error); + + if (error == ENOATTR) + error = ENOENT; + return(error); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_request_right( + bhv_desc_t *bdp, + dm_right_t right, + u_int type, /* DM_FSYS_OBJ or zero */ + u_int flags, + dm_right_t newright) +{ +#ifdef DEBUG_RIGHTS + char buffer[sizeof(xfs_handle_t) * 2 + 1]; + + if (!xfs_bdp_to_hexhandle(bdp, type, buffer)) { + printf("dm_request_right: old %d new %d type %d flags 0x%x " + "handle %s\n", right, newright, type, flags, buffer); + } else { + printf("dm_request_right: old %d new %d type %d flags 0x%x " + "handle \n", right, newright, type, flags); + } +#endif /* DEBUG_RIGHTS */ + return(0); +} + + +STATIC int +xfs_dm_set_dmattr( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrname_t *attrnamep, + int setdtime, + size_t buflen, + void *bufp) +{ + dm_dkattrname_t name; + char *value; + int alloc_size; + vnode_t *vp = BHV_TO_VNODE(bdp); + int error; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + if ((error = xfs_copyin_attrname(attrnamep, &name)) != 0) + return(error); + if (buflen > ATTR_MAX_VALUELEN) + return(E2BIG); + + /* Copy in the attribute's value and store the pair in + the object. We allocate a buffer of at least one byte even if the + caller specified a buflen of zero. (A buflen of zero is considered + valid.) + */ + + alloc_size = (buflen == 0) ? 1 : buflen; + value = kmem_alloc(alloc_size, KM_SLEEP); +#ifdef __sgi + if (copyin(bufp, value, buflen)) { +#else + if (copy_from_user( value, bufp, buflen)) { +#endif + error = EFAULT; + } else { + VOP_ATTR_SET(vp, name.dan_chars, value, buflen, + (setdtime ? ATTR_ROOT : ATTR_ROOT|ATTR_KERNOTIME), + get_current_cred(), error); + } + kmem_free(value, alloc_size); + return(error); +} + +STATIC int +xfs_dm_set_eventlist( + bhv_desc_t *bdp, + dm_right_t right, + u_int type, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int maxevent) +{ + int error; + + if (type == DM_FSYS_OBJ) { + error = xfs_dm_fs_set_eventlist(bdp, right, eventsetp, maxevent); + } else { + error = xfs_dm_f_set_eventlist(bdp, right, eventsetp, maxevent); + } + return(error); +} + + +/* + * This turned out not XFS-specific, but leave it here with get_fileattr. + */ + +STATIC int +xfs_dm_set_fileattr( + bhv_desc_t *bdp, + dm_right_t right, + u_int mask, + dm_fileattr_t *statp) +{ + dm_fileattr_t stat; + vattr_t vat; + vnode_t *vp = BHV_TO_VNODE(bdp); + int error; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + +#ifdef __sgi + if (copyin(statp, &stat, sizeof(stat))) + return(EFAULT); +#else + if (copy_from_user( &stat, statp, sizeof(stat))) + return(EFAULT); +#endif + + vat.va_mask = 0; + + if (mask & DM_AT_MODE) { + vat.va_mask |= AT_MODE; + vat.va_mode = stat.fa_mode; + } + if (mask & DM_AT_UID) { + vat.va_mask |= AT_UID; + vat.va_uid = stat.fa_uid; + } + if (mask & DM_AT_GID) { + vat.va_mask |= AT_GID; + vat.va_gid = stat.fa_gid; + } + if (mask & DM_AT_ATIME) { + vat.va_mask |= AT_ATIME; + vat.va_atime.tv_sec = stat.fa_atime; + vat.va_atime.tv_nsec = 0; + } + if (mask & DM_AT_MTIME) { + vat.va_mask |= AT_MTIME; + vat.va_mtime.tv_sec = stat.fa_mtime; + vat.va_mtime.tv_nsec = 0; + } + if (mask & DM_AT_CTIME) { + vat.va_mask |= AT_CTIME; + vat.va_ctime.tv_sec = stat.fa_ctime; + vat.va_ctime.tv_nsec = 0; + } + + /* DM_AT_DTIME only takes effect if DM_AT_CTIME is not specified. We + overload ctime to also act as dtime, i.e. DM_CONFIG_DTIME_OVERLOAD. + */ + + if ((mask & DM_AT_DTIME) && !(mask & DM_AT_CTIME)) { + vat.va_mask |= AT_CTIME; + vat.va_ctime.tv_sec = stat.fa_dtime; + vat.va_ctime.tv_nsec = 0; + } + if (mask & DM_AT_SIZE) { + vat.va_mask |= AT_SIZE; + vat.va_size = stat.fa_size; + } + + VOP_SETATTR(vp, &vat, ATTR_DMI, get_current_cred(), error); + return(error); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_set_inherit( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrname_t *attrnamep, + mode_t mode) +{ + return(ENOSYS); +} + + +STATIC int +xfs_dm_set_region( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_region_t *regbufp, + dm_boolean_t *exactflagp) +{ + xfs_inode_t *ip; + xfs_trans_t *tp; + xfs_mount_t *mp; + dm_region_t region; + dm_eventset_t new_mask; + dm_eventset_t mr_mask; + int error; + u_int exactflag; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + /* If the caller gave us more than one dm_region_t structure, complain. + (He has to call dm_get_config() to find out what our limit is.) + */ + + if (nelem > 1) + return(E2BIG); + + /* If the user provided a dm_region_t structure, then copy it in, + validate it, and convert its flags to the corresponding bits in a + dm_set_eventlist() event mask. A call with zero regions is + equivalent to clearing all region flags. + */ + + new_mask = 0; + if (nelem == 1) { +#ifdef __sgi + if (copyin(regbufp, ®ion, sizeof(region))) + return(EFAULT); +#else + if (copy_from_user( ®ion, regbufp, sizeof(region))) + return(EFAULT); +#endif + if (region.rg_flags & ~(DM_REGION_READ|DM_REGION_WRITE|DM_REGION_TRUNCATE)) + return(EINVAL); + if (region.rg_flags & DM_REGION_READ) + new_mask |= 1 << DM_EVENT_READ; + if (region.rg_flags & DM_REGION_WRITE) + new_mask |= 1 << DM_EVENT_WRITE; + if (region.rg_flags & DM_REGION_TRUNCATE) + new_mask |= 1 << DM_EVENT_TRUNCATE; + } + if ((new_mask & prohibited_mr_events(bdp)) != 0) + return(EBUSY); + mr_mask = (1 << DM_EVENT_READ) | (1 << DM_EVENT_WRITE) | (1 << DM_EVENT_TRUNCATE); + + /* Get the file's existing event mask, clear the old managed region + bits, add in the new ones, and update the file's mask. + */ + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS); + error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES (mp), 0, 0, 0); + if (error) { + xfs_trans_cancel(tp, 0); + return(error); + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + + ip->i_d.di_dmevmask = (ip->i_d.di_dmevmask & ~mr_mask) | new_mask; + ip->i_iocore.io_dmevmask = ip->i_d.di_dmevmask; + + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + VN_HOLD(BHV_TO_VNODE(bdp)); + xfs_trans_commit(tp, 0, NULL); + + /* Return the proper value for *exactflagp depending upon whether or not + we "changed" the user's managed region. In other words, if the user + specified a non-zero value for either rg_offset or rg_size, we + round each of those values back to zero. + */ + + if (nelem && (region.rg_offset || region.rg_size)) { + exactflag = DM_FALSE; /* user region was changed */ + } else { + exactflag = DM_TRUE; /* user region was unchanged */ + } +#ifdef __sgi + if (copyout(&exactflag, exactflagp, sizeof(exactflag))) + return(EFAULT); +#else + if (copy_to_user( exactflagp, &exactflag, sizeof(exactflag))) + return(EFAULT); +#endif + return(0); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_symlink_by_handle( + bhv_desc_t *bdp, + dm_right_t right, + void *hanp, + size_t hlen, + char *cname, + char *path) +{ + return(ENOSYS); +} + + +STATIC int +xfs_dm_sync_by_handle ( + bhv_desc_t *bdp, + dm_right_t right) +{ + int error; + vnode_t *vp = BHV_TO_VNODE(bdp); + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + VOP_FSYNC(vp, FSYNC_WAIT, get_current_cred(), (off_t)0, (off_t)-1, error); + return(error); +} + + +/* ARGSUSED */ +STATIC int +xfs_dm_upgrade_right( + bhv_desc_t *bdp, + dm_right_t right, + u_int type) /* DM_FSYS_OBJ or zero */ +{ +#ifdef DEBUG_RIGHTS + char buffer[sizeof(xfs_handle_t) * 2 + 1]; + + if (!xfs_bdp_to_hexhandle(bdp, type, buffer)) { + printf("dm_upgrade_right: old %d new %d type %d handle %s\n", + right, DM_RIGHT_EXCL, type, buffer); + } else { + printf("dm_upgrade_right: old %d new %d type %d handle " + "\n", right, DM_RIGHT_EXCL, type); + } +#endif /* DEBUG_RIGHTS */ + return(0); +} + + +STATIC int +xfs_dm_write_invis_rvp( + bhv_desc_t *bdp, + dm_right_t right, + int flags, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp) +{ + int fflag; + + if (right < DM_RIGHT_EXCL) + return(EACCES); + + fflag = FMODE_WRITE; + if (flags & DM_WRITE_SYNC){ +/* XXX when will this be available in linux/XFS? */ +/* fflag |= FSYNC;*/ + printk("%s/%d: xfs FSYNC not implemented yet\n", __FUNCTION__, __LINE__); + } + return(xfs_dm_rdwr(bdp, fflag, off, len, bufp, rvp)); +} + + +STATIC fsys_function_vector_t xfs_fsys_vector[DM_FSYS_MAX]; + + +STATIC int +xfs_dm_get_fsys_vector( + dm_fcntl_t *dmfcntlp) +{ +static int initialized = 0; + fsys_function_vector_t *vecp; + int i = 0; + + dmfcntlp->u_fcntl.vecrq.count = + sizeof(xfs_fsys_vector) / sizeof(xfs_fsys_vector[0]); + dmfcntlp->u_fcntl.vecrq.vecp = xfs_fsys_vector; + if (initialized) + return(0); + dmfcntlp->u_fcntl.vecrq.code_level = DM_CLVL_XOPEN; + vecp = xfs_fsys_vector; + + vecp[i].func_no = DM_FSYS_CLEAR_INHERIT; + vecp[i++].u_fc.clear_inherit = xfs_dm_clear_inherit; + vecp[i].func_no = DM_FSYS_CREATE_BY_HANDLE; + vecp[i++].u_fc.create_by_handle = xfs_dm_create_by_handle; + vecp[i].func_no = DM_FSYS_DOWNGRADE_RIGHT; + vecp[i++].u_fc.downgrade_right = xfs_dm_downgrade_right; + vecp[i].func_no = DM_FSYS_GET_ALLOCINFO_RVP; + vecp[i++].u_fc.get_allocinfo_rvp = xfs_dm_get_allocinfo_rvp; + vecp[i].func_no = DM_FSYS_GET_BULKALL_RVP; + vecp[i++].u_fc.get_bulkall_rvp = xfs_dm_get_bulkall_rvp; + vecp[i].func_no = DM_FSYS_GET_BULKATTR_RVP; + vecp[i++].u_fc.get_bulkattr_rvp = xfs_dm_get_bulkattr_rvp; + vecp[i].func_no = DM_FSYS_GET_CONFIG; + vecp[i++].u_fc.get_config = xfs_dm_get_config; + vecp[i].func_no = DM_FSYS_GET_CONFIG_EVENTS; + vecp[i++].u_fc.get_config_events = xfs_dm_get_config_events; + vecp[i].func_no = DM_FSYS_GET_DESTROY_DMATTR; + vecp[i++].u_fc.get_destroy_dmattr = xfs_dm_get_destroy_dmattr; + vecp[i].func_no = DM_FSYS_GET_DIOINFO; + vecp[i++].u_fc.get_dioinfo = xfs_dm_get_dioinfo; + vecp[i].func_no = DM_FSYS_GET_DIRATTRS_RVP; + vecp[i++].u_fc.get_dirattrs_rvp = xfs_dm_get_dirattrs_rvp; + vecp[i].func_no = DM_FSYS_GET_DMATTR; + vecp[i++].u_fc.get_dmattr = xfs_dm_get_dmattr; + vecp[i].func_no = DM_FSYS_GET_EVENTLIST; + vecp[i++].u_fc.get_eventlist = xfs_dm_get_eventlist; + vecp[i].func_no = DM_FSYS_GET_FILEATTR; + vecp[i++].u_fc.get_fileattr = xfs_dm_get_fileattr; + vecp[i].func_no = DM_FSYS_GET_REGION; + vecp[i++].u_fc.get_region = xfs_dm_get_region; + vecp[i].func_no = DM_FSYS_GETALL_DMATTR; + vecp[i++].u_fc.getall_dmattr = xfs_dm_getall_dmattr; + vecp[i].func_no = DM_FSYS_GETALL_INHERIT; + vecp[i++].u_fc.getall_inherit = xfs_dm_getall_inherit; + vecp[i].func_no = DM_FSYS_INIT_ATTRLOC; + vecp[i++].u_fc.init_attrloc = xfs_dm_init_attrloc; + vecp[i].func_no = DM_FSYS_MKDIR_BY_HANDLE; + vecp[i++].u_fc.mkdir_by_handle = xfs_dm_mkdir_by_handle; + vecp[i].func_no = DM_FSYS_PROBE_HOLE; + vecp[i++].u_fc.probe_hole = xfs_dm_probe_hole; + vecp[i].func_no = DM_FSYS_PUNCH_HOLE; + vecp[i++].u_fc.punch_hole = xfs_dm_punch_hole; + vecp[i].func_no = DM_FSYS_READ_INVIS_RVP; + vecp[i++].u_fc.read_invis_rvp = xfs_dm_read_invis_rvp; + vecp[i].func_no = DM_FSYS_RELEASE_RIGHT; + vecp[i++].u_fc.release_right = xfs_dm_release_right; + vecp[i].func_no = DM_FSYS_REMOVE_DMATTR; + vecp[i++].u_fc.remove_dmattr = xfs_dm_remove_dmattr; + vecp[i].func_no = DM_FSYS_REQUEST_RIGHT; + vecp[i++].u_fc.request_right = xfs_dm_request_right; + vecp[i].func_no = DM_FSYS_SET_DMATTR; + vecp[i++].u_fc.set_dmattr = xfs_dm_set_dmattr; + vecp[i].func_no = DM_FSYS_SET_EVENTLIST; + vecp[i++].u_fc.set_eventlist = xfs_dm_set_eventlist; + vecp[i].func_no = DM_FSYS_SET_FILEATTR; + vecp[i++].u_fc.set_fileattr = xfs_dm_set_fileattr; + vecp[i].func_no = DM_FSYS_SET_INHERIT; + vecp[i++].u_fc.set_inherit = xfs_dm_set_inherit; + vecp[i].func_no = DM_FSYS_SET_REGION; + vecp[i++].u_fc.set_region = xfs_dm_set_region; + vecp[i].func_no = DM_FSYS_SYMLINK_BY_HANDLE; + vecp[i++].u_fc.symlink_by_handle = xfs_dm_symlink_by_handle; + vecp[i].func_no = DM_FSYS_SYNC_BY_HANDLE; + vecp[i++].u_fc.sync_by_handle = xfs_dm_sync_by_handle; + vecp[i].func_no = DM_FSYS_UPGRADE_RIGHT; + vecp[i++].u_fc.upgrade_right = xfs_dm_upgrade_right; + vecp[i].func_no = DM_FSYS_WRITE_INVIS_RVP; + vecp[i++].u_fc.write_invis_rvp = xfs_dm_write_invis_rvp; + + return(0); +} + + +/* xfs_dm_mapevent - send events needed for memory mapping a file. + * + * xfs_dm_map is a workaround called for files that are about to be + * mapped. DMAPI events are not being generated at a low enough level + * in the kernel for page reads/writes to generate the correct events. + * So for memory-mapped files we generate read or write events for the + * whole byte range being mapped. If the mmap call can never cause a + * write to the file, then only a read event is sent. + * + * Code elsewhere prevents adding managed regions to a file while it + * is still mapped. + */ + +/* ARGSUSED */ +STATIC int +xfs_dm_mapevent( + bhv_desc_t *bdp, + int flags, + xfs_off_t offset, + dm_fcntl_t *dmfcntlp) +{ + dm_fcntl_mapevent_t *mapevp; + xfs_fsize_t filesize; /* event read/write "size" */ + xfs_inode_t *ip; + off_t end_of_area, evsize; + vnode_t *vp = BHV_TO_VNODE(bdp); + struct vfs *vfsp = vp->v_vfsp; + + /* exit immediately if not regular file in a DMAPI file system */ + + mapevp = &dmfcntlp->u_fcntl.maprq; + mapevp->error = 0; /* assume success */ + + if ((vp->v_type != VREG) || !(vfsp->vfs_flag & VFS_DMI)) + return 0; + + if (mapevp->max_event != DM_EVENT_WRITE && + mapevp->max_event != DM_EVENT_READ) + return 0; + + /* Set file size to work with. */ + + ip = XFS_BHVTOI(bdp); + filesize = ip->i_iocore.io_new_size; + if (filesize < ip->i_d.di_size) { + filesize = ip->i_d.di_size; + } + + /* Set first byte number beyond the map area. */ + + if (mapevp->length) { + end_of_area = offset + mapevp->length; + if (end_of_area > filesize) + end_of_area = filesize; + } else { + end_of_area = filesize; + } + + /* Set the real amount being mapped. */ + evsize = end_of_area - offset; + if (evsize < 0) + evsize = 0; + + /* If write possible, try a DMAPI write event */ + if (mapevp->max_event == DM_EVENT_WRITE && + DM_EVENT_ENABLED (vp->v_vfsp, ip, DM_EVENT_WRITE)) { + mapevp->error = xfs_dm_send_data_event(DM_EVENT_WRITE, bdp, + offset, evsize, 0, NULL); + return(0); + } + + /* Try a read event if max_event was != DM_EVENT_WRITE or if it + * was DM_EVENT_WRITE but the WRITE event was not enabled. + */ + if (DM_EVENT_ENABLED (vp->v_vfsp, ip, DM_EVENT_READ)) { + mapevp->error = xfs_dm_send_data_event(DM_EVENT_READ, bdp, + offset, evsize, 0, NULL); + } + + return 0; +} + + + +/* xfs_dm_testevent() - test if events needed for a memory mapped file. + * + * xfs_dm_testevent() is called when a page from a memory mapped + * file is about to be modified. xfs_dm_testevent() will check if + * an event should be generated for the region specified. If (at + * least) one should be generated, it is up to the caller to drop + * any critical locks held and then issue the events via a + * DM_FCNTL_MAPEVENT fcntl() call. + * + * Returns 0 if xfs_dm_testevent() executed successfully. + * testevp->error = errno if an error detected. otherwise, + * testevp->error = 0 and testevp->issue_event = The "highest" + * event to be issued - DM_EVENT_WRITE, DM_EVENT_READ, or + * DM_EVENT_INVALID (for no event to be issued). + */ + +/* ARGSUSED */ +STATIC int +xfs_dm_testevent( + bhv_desc_t *bdp, + int flags, + off_t offset, + dm_fcntl_t *dmfcntlp) +{ + dm_fcntl_testevent_t *testevp; + xfs_inode_t *ip; + vnode_t *vp = BHV_TO_VNODE(bdp); + struct vfs *vfsp = vp->v_vfsp; + + /* exit immediately if not regular file in a DMAPI file system */ + + testevp = &dmfcntlp->u_fcntl.testrq; + testevp->error = 0; /* assume no error */ + testevp->issue_event = DM_EVENT_INVALID; /* assume no event */ + + if ((vp->v_type != VREG) || !(vfsp->vfs_flag & VFS_DMI)) + return 0; + + if (testevp->max_event != DM_EVENT_WRITE && + testevp->max_event != DM_EVENT_READ) + return 0; + + ip = XFS_BHVTOI(bdp); + + /* Set file size to work with. */ + + /* Return DM_EVENT_WRITE if write possible */ + if (testevp->max_event == DM_EVENT_WRITE && + DM_EVENT_ENABLED (vp->v_vfsp, ip, DM_EVENT_WRITE)) { + testevp->issue_event = DM_EVENT_WRITE; + } else if (DM_EVENT_ENABLED (vp->v_vfsp, ip, DM_EVENT_READ)) { + + /* Read event needed if max_event was != DM_EVENT_WRITE or if it + * was DM_EVENT_WRITE but the WRITE event was not enabled. + */ + testevp->issue_event = DM_EVENT_READ; + } + return 0; +} + + +/* ARGSUSED */ +int +xfs_dm_fcntl( + bhv_desc_t *bdp, + void *arg, + int flags, + xfs_off_t offset, + cred_t *credp, + int *rvalp) +{ + dm_fcntl_t *dmfcntlp; + +#ifdef __sgi + if (!cap_able_cred(credp, CAP_DEVICE_MGT)) + return(EPERM); +#else + if (!capable(CAP_MKNOD)) + return(EPERM); +#endif + + dmfcntlp = (dm_fcntl_t *)arg; + + switch (dmfcntlp->dmfc_subfunc) { + case DM_FCNTL_FSYSVECTOR: + return(xfs_dm_get_fsys_vector(dmfcntlp)); + case DM_FCNTL_MAPEVENT: + return(xfs_dm_mapevent(bdp, flags, offset, dmfcntlp)); + case DM_FCNTL_TESTEVENT: + return(xfs_dm_testevent(bdp, flags, offset, dmfcntlp)); + case DM_FCNTL_FSSETDM: + return xfs_set_dmattrs(bdp, dmfcntlp->u_fcntl.setdmrq.fsd_dmevmask, + dmfcntlp->u_fcntl.setdmrq.fsd_dmstate, + credp); + default: + break; + } + return(ENOSYS); +} + + +int +xfs_dm_mount( + vfs_t *vfsp, + vnode_t *mvp, + char *dir_name, + char *fsname) +{ + vnode_t *rootvp; + bhv_desc_t *mbdp, *rootbdp; + int error; + + VFS_ROOT(vfsp, &rootvp, error); + if (error) + return error; + + mbdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(mvp), &xfs_vnodeops); + rootbdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(rootvp), &xfs_vnodeops); + VN_RELE(rootvp); + error = dm_send_mount_event(vfsp, DM_RIGHT_NULL, mbdp, DM_RIGHT_NULL, + rootbdp, DM_RIGHT_NULL, dir_name, + fsname); + return error; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dmapi.h linux-2.4-xfs/linux/fs/xfs/xfs_dmapi.h --- linux-2.4.7/linux/fs/xfs/xfs_dmapi.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dmapi.h Tue Jan 16 22:01:25 2001 @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DMAPI_H__ +#define __XFS_DMAPI_H__ + +/* Values used to define the on-disk version of dm_attrname_t. All + * on-disk attribute names start with the 8-byte string "SGI_DMI_". + * + * In the on-disk inode, DMAPI attribute names consist of the user-provided + * name with the DMATTR_PREFIXSTRING pre-pended. This string must NEVER be + * changed. + */ + +#define DMATTR_PREFIXLEN 8 +#define DMATTR_PREFIXSTRING "SGI_DMI_" + +#ifdef __KERNEL__ +/* Defines for determining if an event message should be sent. */ +#define DM_EVENT_ENABLED(vfsp, ip, event) ( \ + ((vfsp)->vfs_flag & VFS_DMI) && \ + ( ((ip)->i_d.di_dmevmask & (1 << event)) || \ + ((ip)->i_mount->m_dmevmask & (1 << event)) ) \ + ) + +#define DM_EVENT_ENABLED_IO(vfsp, io, event) ( \ + ((vfsp)->vfs_flag & VFS_DMI) && \ + ( ((io)->io_dmevmask & (1 << event)) || \ + ((io)->io_mount->m_dmevmask & (1 << event)) ) \ + ) + +/* + * Macros to turn caller specified delay/block flags into + * dm_send_xxxx_event flag DM_FLAGS_NDELAY. + */ + +#ifdef CELL_CAPABLE +#define UIO_DELAY_FLAG(uiop) ((uiop->uio_fmode&(FNDELAY|FNONBLOCK)) ? \ + DM_FLAGS_NDELAY : 0) +#endif +#define FILP_DELAY_FLAG(filp) ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) ? \ + DM_FLAGS_NDELAY : 0) +#define AT_DELAY_FLAG(f) ((f&ATTR_NONBLOCK) ? DM_FLAGS_NDELAY : 0) + + +extern int +xfs_dm_mount( + vfs_t *vfsp, + vnode_t *mvp, + char *dir_name, + char *fsname); + +extern int +xfs_dm_send_data_event( + dm_eventtype_t event, + bhv_desc_t *bdp, + xfs_off_t offset, + size_t length, + int flags, + vrwlock_t *locktype); + +extern int +xfs_dm_send_create_event( + bhv_desc_t *dir_bdp, + char *name, + mode_t new_mode, + int *good_event_sent); + +extern int +xfs_dm_fcntl( + bhv_desc_t *bdp, + void *arg, + int flags, + xfs_off_t offset, + cred_t *credp, + int *rvalp); + +extern int +xfs_dm_mapevent( + bhv_desc_t *bdp, + int flags, + xfs_off_t offset, + dm_fcntl_t *dmfcntlp); + +/* + * Function defined in xfs_vnodeops.c used by DMAPI as well as by xfs_vnodeops.c + */ +extern int +xfs_set_dmattrs( + bhv_desc_t *bdp, + u_int evmask, + u_int16_t state, + cred_t *credp); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_DMAPI_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dqblk.h linux-2.4-xfs/linux/fs/xfs/xfs_dqblk.h --- linux-2.4.7/linux/fs/xfs/xfs_dqblk.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dqblk.h Mon Apr 2 21:52:38 2001 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DQBLK_H__ +#define __XFS_DQBLK_H__ + +/* + * The ondisk form of a dquot structure. + */ +#define XFS_DQUOT_MAGIC 0x4451 /* 'DQ' */ +#define XFS_DQUOT_VERSION (u_int8_t)0x01 /* latest version number */ + +/* + * This is the main portion of the on-disk representation of quota + * information for a user. This is the q_core of the xfs_dquot_t that + * is kept in kernel memory. We pad this with some more expansion room + * to construct the on disk structure. + */ +typedef struct xfs_disk_dquot { +/*16*/ u_int16_t d_magic; /* dquot magic = XFS_DQUOT_MAGIC */ +/*8 */ u_int8_t d_version; /* dquot version */ +/*8 */ u_int8_t d_flags; /* XFS_DQ_USER/PROJ/GROUP */ +/*32*/ xfs_dqid_t d_id; /* user,project,group id */ +/*64*/ xfs_qcnt_t d_blk_hardlimit;/* absolute limit on disk blks */ +/*64*/ xfs_qcnt_t d_blk_softlimit;/* preferred limit on disk blks */ +/*64*/ xfs_qcnt_t d_ino_hardlimit;/* maximum # allocated inodes */ +/*64*/ xfs_qcnt_t d_ino_softlimit;/* preferred inode limit */ +/*64*/ xfs_qcnt_t d_bcount; /* disk blocks owned by the user */ +/*64*/ xfs_qcnt_t d_icount; /* inodes owned by the user */ +/*32*/ __int32_t d_itimer; /* zero if within inode limits if not, + this is when we refuse service */ +/*32*/ __int32_t d_btimer; /* similar to above; for disk blocks */ +/*16*/ xfs_qwarncnt_t d_iwarns; /* warnings issued wrt num inodes */ +/*16*/ xfs_qwarncnt_t d_bwarns; /* warnings issued wrt disk blocks */ +/*32*/ __int32_t d_pad0; /* 64 bit align */ +/*64*/ xfs_qcnt_t d_rtb_hardlimit;/* absolute limit on realtime blks */ +/*64*/ xfs_qcnt_t d_rtb_softlimit;/* preferred limit on RT disk blks */ +/*64*/ xfs_qcnt_t d_rtbcount; /* realtime blocks owned */ +/*32*/ __int32_t d_rtbtimer; /* similar to above; for RT disk blocks */ +/*16*/ xfs_qwarncnt_t d_rtbwarns; /* warnings issued wrt RT disk blocks */ +/*16*/ __uint16_t d_pad; +} xfs_disk_dquot_t; + +/* + * This is what goes on disk. This is separated from the xfs_disk_dquot because + * carrying the unnecessary padding would be a waste of memory. + */ +typedef struct xfs_dqblk { + xfs_disk_dquot_t dd_diskdq; /* portion that lives incore as well */ + char dd_fill[32]; /* filling for posterity */ +} xfs_dqblk_t; + +/* + * flags for q_flags field in the dquot. + */ +#define XFS_DQ_USER 0x0001 /* a user quota */ +/* #define XFS_DQ_PROJ 0x0002 -- project quota (IRIX) */ +#define XFS_DQ_GROUP 0x0004 /* a group quota */ +#define XFS_DQ_FLOCKED 0x0008 /* flush lock taken */ +#define XFS_DQ_DIRTY 0x0010 /* dquot is dirty */ +#define XFS_DQ_WANT 0x0020 /* for lookup/reclaim race */ +#define XFS_DQ_INACTIVE 0x0040 /* dq off mplist & hashlist */ +#define XFS_DQ_MARKER 0x0080 /* sentinel */ + +/* + * In the worst case, when both user and group quotas are on, + * we can have a max of three dquots changing in a single transaction. + */ +#define XFS_DQUOT_LOGRES(mp) (sizeof(xfs_disk_dquot_t) * 3) + +#endif /* __XFS_DQBLK_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dquot.c linux-2.4-xfs/linux/fs/xfs/xfs_dquot.c --- linux-2.4.7/linux/fs/xfs/xfs_dquot.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dquot.c Wed Apr 18 21:37:23 2001 @@ -0,0 +1,1670 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + + +/* + LOCK ORDER + + inode lock (ilock) + dquot hash-chain lock (hashlock) + xqm dquot freelist lock (freelistlock + mount's dquot list lock (mplistlock) + user dquot lock - lock ordering among dquots is based on the uid or gid + group dquot lock - similar to udquots. Between the two dquots, the udquot + has to be locked first. + pin lock - the dquot lock must be held to take this lock. + flush lock - ditto. +*/ + +STATIC void xfs_qm_dqflush_done(xfs_buf_t *, xfs_dq_logitem_t *); + +#ifdef DEBUG +int xfs_do_dqerror = 0; +int xfs_dqreq_num = 0; +int xfs_dqerror_mod = 33; +dev_t xfs_dqerror_dev = 0; +#endif + +/* + * Allocate and initialize a dquot. We don't always allocate fresh memory; + * we try to reclaim a free dquot if the number of incore dquots are above + * a threshold. + * The only field inside the core that gets initialized at this point + * is the d_id field. The idea is to fill in the entire q_core + * when we read in the on disk dquot. + */ +xfs_dquot_t * +xfs_qm_dqinit( + xfs_mount_t *mp, + xfs_dqid_t id, + uint type) +{ + xfs_dquot_t *dqp; + boolean_t brandnewdquot; + + brandnewdquot = xfs_qm_dqalloc_incore(&dqp); + dqp->dq_flags = type; + INT_SET(dqp->q_core.d_id, ARCH_CONVERT, id); + dqp->q_mount = mp; + dqp->q_dev = mp->m_dev; + + /* + * No need to re-initialize these if this is a reclaimed dquot. + */ + if (brandnewdquot) { + dqp->dq_flnext = dqp->dq_flprev = dqp; + mutex_init(&dqp->q_qlock, MUTEX_DEFAULT, "xdq"); + initnsema(&dqp->q_flock, 1, "fdq"); + sv_init(&dqp->q_pinwait, SV_DEFAULT, "pdq"); + +#ifdef DQUOT_TRACING + dqp->q_trace = ktrace_alloc(DQUOT_TRACE_SIZE, KM_SLEEP); + xfs_dqtrace_entry(dqp, "DQINIT"); +#endif + } else { + /* + * Only the q_core portion was bzeroed in dqreclaim_one(). + * So, we need to reset others. + */ + dqp->q_nrefs = 0; + dqp->q_blkno = 0; + dqp->MPL_NEXT = dqp->HL_NEXT = NULL; + dqp->HL_PREVP = dqp->MPL_PREVP = NULL; + dqp->q_bufoffset = 0; + dqp->q_fileoffset = 0; + dqp->q_transp = NULL; + dqp->q_gdquot = NULL; + dqp->q_res_bcount = 0; + dqp->q_res_icount = 0; + dqp->q_res_rtbcount = 0; + dqp->q_pincount = 0; + dqp->q_hash = 0; + ASSERT(dqp->dq_flnext == dqp->dq_flprev); + +#ifdef DQUOT_TRACING + ASSERT(dqp->q_trace); + xfs_dqtrace_entry(dqp, "DQRECLAIMED_INIT"); +#endif + } + + /* + * log item gets initialized later + */ + return (dqp); +} + +/* + * This is called to free all the memory associated with a dquot + */ +void +xfs_qm_dqdestroy( + xfs_dquot_t *dqp) +{ + ASSERT(! XFS_DQ_IS_ON_FREELIST(dqp)); + + mutex_destroy(&dqp->q_qlock); + freesema(&dqp->q_flock); + sv_destroy(&dqp->q_pinwait); + +#ifdef DQUOT_TRACING + if (dqp->q_trace) + ktrace_free(dqp->q_trace); + dqp->q_trace = NULL; +#endif + kmem_zone_free(xfs_Gqm->qm_dqzone, dqp); + atomic_dec(&xfs_Gqm->qm_totaldquots); +} + +/* + * This is what a 'fresh' dquot inside a dquot chunk looks like on disk. + */ +STATIC void +xfs_qm_dqinit_core( + xfs_dqid_t id, + uint type, + xfs_dqblk_t *d) +{ + /* + * Caller has bzero'd the entire dquot 'chunk' already. + */ + INT_SET(d->dd_diskdq.d_magic, ARCH_CONVERT, XFS_DQUOT_MAGIC); + INT_SET(d->dd_diskdq.d_version, ARCH_CONVERT, XFS_DQUOT_VERSION); + INT_SET(d->dd_diskdq.d_id, ARCH_CONVERT, id); + INT_SET(d->dd_diskdq.d_flags, ARCH_CONVERT, type); +} + + +#ifdef DQUOT_TRACING +/* + * Dquot tracing for debugging. + */ +/* ARGSUSED */ +void +xfs_dqtrace_entry__( + xfs_dquot_t *dqp, + char *func, + void *retaddr, + xfs_inode_t *ip) +{ + xfs_dquot_t *udqp = NULL; + int ino; + + ASSERT(dqp->q_trace); + if (ip) { + ino = ip->i_ino; + udqp = ip->i_udquot; + } + ktrace_enter(dqp->q_trace, + (void *)(__psint_t)DQUOT_KTRACE_ENTRY, + (void *)func, + (void *)(__psint_t)dqp->q_nrefs, + (void *)(__psint_t)dqp->dq_flags, + (void *)(__psint_t)dqp->q_res_bcount, + (void *)(__psint_t)INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), + (void *)(__psint_t)INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), + (void *)(__psint_t)INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT), + (void *)(__psint_t)INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT), + (void *)(__psint_t)INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT), + (void *)(__psint_t)INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT), + (void *)(__psint_t)INT_GET(dqp->q_core.d_id, ARCH_CONVERT), /* 11 */ + (void *)(__psint_t)current_pid(), + (void *)(__psint_t)ino, + (void *)(__psint_t)retaddr, + (void *)(__psint_t)udqp); + return; +} +#endif + + +/* + * Check the limits and timers of a dquot and start or reset timers + * if necessary. + * This gets called even when quota enforcement is OFF, which makes our + * life a little less complicated. (We just don't reject any quota + * reservations in that case, when enforcement is off). + * We also return 0 as the values of the timers in Q_GETQUOTA calls, when + * enforcement's off. + * In contrast, warnings are a little different in that they don't + * 'automatically' get started when limits get exceeded. + */ +void +xfs_qm_adjust_dqtimers( + xfs_mount_t *mp, + xfs_disk_dquot_t *d) +{ + /* + * The dquot had better be locked. We are modifying it here. + */ + + /* + * root's limits are not real limits. + */ + if (INT_GET(d->d_id, ARCH_CONVERT) == 0) + return; + +#ifdef QUOTADEBUG + if (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)) + ASSERT(INT_GET(d->d_blk_softlimit, ARCH_CONVERT) <= INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)); + if (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)) + ASSERT(INT_GET(d->d_ino_softlimit, ARCH_CONVERT) <= INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)); +#endif + if (INT_GET(d->d_btimer, ARCH_CONVERT) == 0) { + if ((INT_GET(d->d_blk_softlimit, ARCH_CONVERT) && + (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) || + (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT) && + (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) { + INT_SET(d->d_btimer, ARCH_CONVERT, CURRENT_TIME + XFS_QI_BTIMELIMIT(mp)); + } + } else { + if ((INT_GET(d->d_blk_softlimit, ARCH_CONVERT) == 0 || + (INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) && + (INT_GET(d->d_blk_hardlimit, ARCH_CONVERT) == 0 || + (INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_hardlimit, ARCH_CONVERT)))) { + INT_ZERO(d->d_btimer, ARCH_CONVERT); + } + } + + if (INT_GET(d->d_itimer, ARCH_CONVERT) == 0) { + if ((INT_GET(d->d_ino_softlimit, ARCH_CONVERT) && + (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) || + (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT) && + (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) { + INT_SET(d->d_itimer, ARCH_CONVERT, CURRENT_TIME + XFS_QI_ITIMELIMIT(mp)); + } + } else { + if ((INT_GET(d->d_ino_softlimit, ARCH_CONVERT) == 0 || + (INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) && + (INT_GET(d->d_ino_hardlimit, ARCH_CONVERT) == 0 || + (INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_hardlimit, ARCH_CONVERT)))) { + INT_ZERO(d->d_itimer, ARCH_CONVERT); + } + } +} + +/* + * Increment or reset warnings of a given dquot. + */ +int +xfs_qm_dqwarn( + xfs_disk_dquot_t *d, + uint flags) +{ + int warned; + + /* + * root's limits are not real limits. + */ + if (INT_GET(d->d_id, ARCH_CONVERT) == 0) + return (0); + + warned = 0; + if (INT_GET(d->d_blk_softlimit, ARCH_CONVERT) && + (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) { + if (flags & XFS_QMOPT_DOWARN) { + INT_MOD(d->d_bwarns, ARCH_CONVERT, +1); + warned++; + } + } else { + if (INT_GET(d->d_blk_softlimit, ARCH_CONVERT) == 0 || + (INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) { + INT_ZERO(d->d_bwarns, ARCH_CONVERT); + } + } + + if (INT_GET(d->d_ino_softlimit, ARCH_CONVERT) > 0 && + (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) { + if (flags & XFS_QMOPT_DOWARN) { + INT_MOD(d->d_iwarns, ARCH_CONVERT, +1); + warned++; + } + } else { + if ((INT_GET(d->d_ino_softlimit, ARCH_CONVERT) == 0) || + (INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) { + INT_ZERO(d->d_iwarns, ARCH_CONVERT); + } + } +#ifdef QUOTADEBUG + if (INT_GET(d->d_iwarns, ARCH_CONVERT)) + printk("--------@@Inode warnings running : %Lu >= %Lu\n", + INT_GET(d->d_icount, ARCH_CONVERT), INT_GET(d->d_ino_softlimit, ARCH_CONVERT)); + if (INT_GET(d->d_bwarns, ARCH_CONVERT)) + printk("--------@@Blks warnings running : %Lu >= %Lu\n", + INT_GET(d->d_bcount, ARCH_CONVERT), INT_GET(d->d_blk_softlimit, ARCH_CONVERT)); +#endif + return (warned); +} + + +/* + * initialize a buffer full of dquots and log the whole thing + */ +STATIC void +xfs_qm_init_dquot_blk( + xfs_trans_t *tp, + xfs_mount_t *mp, + xfs_dqid_t id, + uint type, + xfs_buf_t *bp) +{ + xfs_dqblk_t *d; + int curid, i; + + ASSERT(tp); + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); + + d = (xfs_dqblk_t *)XFS_BUF_PTR(bp); + + /* + * ID of the first dquot in the block - id's are zero based. + */ + curid = id - (id % XFS_QM_DQPERBLK(mp)); + ASSERT(curid >= 0); + bzero(d, BBTOB(XFS_QI_DQCHUNKLEN(mp))); + for (i = 0; i < XFS_QM_DQPERBLK(mp); i++, d++, curid++) + xfs_qm_dqinit_core(curid, type, d); + xfs_trans_dquot_buf(tp, bp, + type & XFS_DQ_USER ? + XFS_BLI_UDQUOT_BUF : + XFS_BLI_GDQUOT_BUF); + xfs_trans_log_buf(tp, bp, 0, BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1); +} + + + +/* + * Allocate a block and fill it with dquots. + * This is called when the bmapi finds a hole. + */ +STATIC int +xfs_qm_dqalloc( + xfs_trans_t *tp, + xfs_mount_t *mp, + xfs_dquot_t *dqp, + xfs_inode_t *quotip, + xfs_fileoff_t offset_fsb, + xfs_buf_t **O_bpp) +{ + xfs_fsblock_t firstblock; + xfs_bmap_free_t flist; + xfs_bmbt_irec_t map; + int nmaps, error, committed; + xfs_buf_t *bp; + + ASSERT(tp != NULL); + xfs_dqtrace_entry(dqp, "DQALLOC"); + + /* + * Initialize the bmap freelist prior to calling bmapi code. + */ + XFS_BMAP_INIT(&flist, &firstblock); + xfs_ilock(quotip, XFS_ILOCK_EXCL); + /* + * Return if this type of quotas is turned off while we didn't + * have an inode lock + */ + if (XFS_IS_THIS_QUOTA_OFF(dqp)) { + xfs_iunlock(quotip, XFS_ILOCK_EXCL); + return (ESRCH); + } + + /* + * xfs_trans_commit normally decrements the vnode ref count + * when it unlocks the inode. Since we want to keep the quota + * inode around, we bump the vnode ref count now. + */ + VN_HOLD(XFS_ITOV(quotip)); + + xfs_trans_ijoin(tp, quotip, XFS_ILOCK_EXCL); + nmaps = 1; + if ((error = xfs_bmapi(tp, quotip, + offset_fsb, XFS_DQUOT_CLUSTER_SIZE_FSB, + XFS_BMAPI_METADATA | XFS_BMAPI_WRITE, + &firstblock, + XFS_QM_DQALLOC_SPACE_RES(mp), + &map, &nmaps, &flist))) { + goto error0; + } + ASSERT(map.br_blockcount == XFS_DQUOT_CLUSTER_SIZE_FSB); + ASSERT(nmaps == 1); + ASSERT((map.br_startblock != DELAYSTARTBLOCK) && + (map.br_startblock != HOLESTARTBLOCK)); + + /* + * Keep track of the blkno to save a lookup later + */ + dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock); + + /* now we can just get the buffer (there's nothing to read yet) */ + bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, + dqp->q_blkno, + XFS_QI_DQCHUNKLEN(mp), + 0); + if (!bp || (error = XFS_BUF_GETERROR(bp))) + goto error1; + /* + * Make a chunk of dquots out of this buffer and log + * the entire thing. + */ + xfs_qm_init_dquot_blk(tp, mp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT), + dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP), + bp); + + if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) { + goto error1; + } + + *O_bpp = bp; + return 0; + + error1: + xfs_bmap_cancel(&flist); + error0: + xfs_iunlock(quotip, XFS_ILOCK_EXCL); + + return (error); +} + +/* + * Maps a dquot to the buffer containing its on-disk version. + * This returns a ptr to the buffer containing the on-disk dquot + * in the bpp param, and a ptr to the on-disk dquot within that buffer + */ +STATIC int +xfs_qm_dqtobp( + xfs_trans_t *tp, + xfs_dquot_t *dqp, + xfs_disk_dquot_t **O_ddpp, + xfs_buf_t **O_bpp, + uint flags) +{ + xfs_fsblock_t firstblock; + xfs_bmbt_irec_t map; + int nmaps, error; + xfs_buf_t *bp; + xfs_inode_t *quotip; + xfs_mount_t *mp; + xfs_disk_dquot_t *ddq; + xfs_dqid_t id; + boolean_t newdquot; + + firstblock = NULLFSBLOCK; + mp = dqp->q_mount; + id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT); + nmaps = 1; + newdquot = B_FALSE; + + /* + * If we don't know where the dquot lives, find out. + */ + if (dqp->q_blkno == (xfs_daddr_t) 0) { + /* We use the id as an index */ + dqp->q_fileoffset = (xfs_fileoff_t) ((uint)id / + XFS_QM_DQPERBLK(mp)); + nmaps = 1; + quotip = XFS_DQ_TO_QIP(dqp); + xfs_ilock(quotip, XFS_ILOCK_SHARED); + /* + * Return if this type of quotas is turned off while we didn't + * have an inode lock + */ + if (XFS_IS_THIS_QUOTA_OFF(dqp)) { + xfs_iunlock(quotip, XFS_ILOCK_SHARED); + return (ESRCH); + } + /* + * Find the block map; no allocations yet + */ + error = xfs_bmapi(NULL, quotip, dqp->q_fileoffset, + XFS_DQUOT_CLUSTER_SIZE_FSB, + XFS_BMAPI_METADATA, + &firstblock, + 0, + &map, &nmaps, NULL); + + xfs_iunlock(quotip, XFS_ILOCK_SHARED); + if (error) + return (error); + ASSERT(nmaps == 1); + ASSERT(map.br_blockcount == 1); + + /* + * offset of dquot in the (fixed sized) dquot chunk. + */ + dqp->q_bufoffset = (id % XFS_QM_DQPERBLK(mp)) * + sizeof(xfs_dqblk_t); + if (map.br_startblock == HOLESTARTBLOCK) { + /* + * We don't allocate unless we're asked to + */ + if (!(flags & XFS_QMOPT_DQALLOC)) + return (ENOENT); + + ASSERT(tp); + if ((error = xfs_qm_dqalloc(tp, mp, dqp, quotip, + dqp->q_fileoffset, &bp))) + return (error); + newdquot = B_TRUE; + } else { + /* + * store the blkno etc so that we don't have to do the + * mapping all the time + */ + dqp->q_blkno = XFS_FSB_TO_DADDR(mp, map.br_startblock); + } + } + ASSERT(dqp->q_blkno != DELAYSTARTBLOCK); + ASSERT(dqp->q_blkno != HOLESTARTBLOCK); + + /* + * Read in the buffer, unless we've just done the allocation + * (in which case we already have the buf). + */ + if (! newdquot) { + xfs_dqtrace_entry(dqp, "DQTOBP READBUF"); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, + dqp->q_blkno, + XFS_QI_DQCHUNKLEN(mp), + 0, &bp))) { + return (error); + } + if (error || !bp) + return XFS_ERROR(error); + } + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); + + /* + * calculate the location of the dquot inside the buffer. + */ + ddq = (xfs_disk_dquot_t *)((char *)XFS_BUF_PTR(bp) + dqp->q_bufoffset); + + /* + * A simple sanity check in case we got a corrupted dquot... + */ + if (xfs_qm_dqcheck(ddq, id, + dqp->dq_flags & (XFS_DQ_USER|XFS_DQ_GROUP), + flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN), + "dqtobp")) { + if (!(flags & XFS_QMOPT_DQREPAIR)) { + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EIO); + } + XFS_BUF_BUSY(bp); /* We dirtied this */ + } + + *O_bpp = bp; + *O_ddpp = ddq; + + return (0); +} + + +/* + * Read in the ondisk dquot using dqtobp() then copy it to an incore version, + * and release the buffer immediately. + * + */ +/* ARGSUSED */ +STATIC int +xfs_qm_dqread( + xfs_trans_t *tp, + xfs_dqid_t id, + xfs_dquot_t *dqp, /* dquot to get filled in */ + uint flags) +{ + xfs_disk_dquot_t *ddqp; + xfs_buf_t *bp; + int error; + + /* + * get a pointer to the on-disk dquot and the buffer containing it + * dqp already knows its own type (GROUP/USER). + */ + xfs_dqtrace_entry(dqp, "DQREAD"); + if ((error = xfs_qm_dqtobp(tp, dqp, &ddqp, &bp, flags))) { + return (error); + } + + /* copy everything from disk dquot to the incore dquot */ + bcopy(ddqp, &dqp->q_core, sizeof(xfs_disk_dquot_t)); + ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id); + xfs_qm_dquot_logitem_init(dqp); + + /* + * Reservation counters are defined as reservation plus current usage + * to avoid having to add everytime. + */ + dqp->q_res_bcount = INT_GET(ddqp->d_bcount, ARCH_CONVERT); + dqp->q_res_icount = INT_GET(ddqp->d_icount, ARCH_CONVERT); + dqp->q_res_rtbcount = INT_GET(ddqp->d_rtbcount, ARCH_CONVERT); + + /* Mark the buf so that this will stay incore a little longer */ + XFS_BUF_SET_VTYPE_REF(bp, B_FS_DQUOT, XFS_DQUOT_REF); + + /* + * We got the buffer with a xfs_trans_read_buf() (in dqtobp()) + * So we need to release with xfs_trans_brelse(). + * The strategy here is identical to that of inodes; we lock + * the dquot in xfs_qm_dqget() before making it accessible to + * others. This is because dquots, like inodes, need a good level of + * concurrency, and we don't want to take locks on the entire buffers + * for dquot accesses. + * Note also that the dquot buffer may even be dirty at this point, if + * this particular dquot was repaired. We still aren't afraid to + * brelse it because we have the changes incore. + */ + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); + xfs_trans_brelse(tp, bp); + + return (error); +} + + +/* + * allocate an incore dquot from the kernel heap, + * and fill its core with quota information kept on disk. + * If XFS_QMOPT_DQALLOC is set, it'll allocate a dquot on disk + * if it wasn't already allocated. + */ +STATIC int +xfs_qm_idtodq( + xfs_mount_t *mp, + xfs_dqid_t id, /* gid or uid, depending on type */ + uint type, /* UDQUOT or GDQUOT */ + uint flags, /* DQALLOC, DQREPAIR */ + xfs_dquot_t **O_dqpp)/* OUT : incore dquot, not locked */ +{ + xfs_dquot_t *dqp; + int error; + xfs_trans_t *tp; + int cancelflags=0; + + dqp = xfs_qm_dqinit(mp, id, type); + tp = NULL; + if (flags & XFS_QMOPT_DQALLOC) { + tp = xfs_trans_alloc(mp, XFS_TRANS_QM_DQALLOC); + if ((error = xfs_trans_reserve(tp, + XFS_QM_DQALLOC_SPACE_RES(mp), + XFS_WRITE_LOG_RES(mp) + + BBTOB(XFS_QI_DQCHUNKLEN(mp)) - 1 + + 128, + 0, + XFS_TRANS_PERM_LOG_RES, + XFS_WRITE_LOG_COUNT))) { + cancelflags = 0; + goto error0; + } + cancelflags = XFS_TRANS_RELEASE_LOG_RES; + } + + /* + * Read it from disk; xfs_dqread() takes care of + * all the necessary initialization of dquot's fields (locks, etc) + */ + if ((error = xfs_qm_dqread(tp, id, dqp, flags))) { + /* + * This can happen if quotas got turned off (ESRCH), + * or if the dquot didn't exist on disk and we ask to + * allocate (ENOENT). + */ + xfs_dqtrace_entry(dqp, "DQREAD FAIL"); + cancelflags |= XFS_TRANS_ABORT; + goto error0; + } + if (tp) { + if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, + NULL))) + goto error1; + } + + *O_dqpp = dqp; + ASSERT(! XFS_DQ_IS_LOCKED(dqp)); + return (0); + + error0: + ASSERT(error); + if (tp) + xfs_trans_cancel(tp, cancelflags); + error1: + xfs_qm_dqdestroy(dqp); + *O_dqpp = NULL; + return (error); +} + +/* + * Lookup a dquot in the incore dquot hashtable. We keep two separate + * hashtables for user and group dquots; and, these are global tables + * inside the XQM, not per-filesystem tables. + * The hash chain must be locked by caller, and it is left locked + * on return. Returning dquot is locked. + */ +STATIC int +xfs_qm_dqlookup( + xfs_mount_t *mp, + xfs_dqid_t id, + xfs_dqhash_t *qh, + xfs_dquot_t **O_dqpp) +{ + xfs_dquot_t *dqp; + uint flist_locked; + xfs_dquot_t *d; + + ASSERT(XFS_DQ_IS_HASH_LOCKED(qh)); + + flist_locked = B_FALSE; + + /* + * Traverse the hashchain looking for a match + */ + for (dqp = qh->qh_next; dqp != NULL; dqp = dqp->HL_NEXT) { + /* + * We already have the hashlock. We don't need the + * dqlock to look at the id field of the dquot, since the + * id can't be modified without the hashlock anyway. + */ + if (INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id && dqp->q_mount == mp) { + xfs_dqtrace_entry(dqp, "DQFOUND BY LOOKUP"); + /* + * All in core dquots must be on the dqlist of mp + */ + ASSERT(dqp->MPL_PREVP != NULL); + + xfs_dqlock(dqp); + if (dqp->q_nrefs == 0) { + ASSERT (XFS_DQ_IS_ON_FREELIST(dqp)); + if (! xfs_qm_freelist_lock_nowait(xfs_Gqm)) { + xfs_dqtrace_entry(dqp, "DQLOOKUP: WANT"); + + /* + * We may have raced with dqreclaim_one() + * (and lost). So, flag that we don't + * want the dquot to be reclaimed. + */ + dqp->dq_flags |= XFS_DQ_WANT; + xfs_dqunlock(dqp); + xfs_qm_freelist_lock(xfs_Gqm); + xfs_dqlock(dqp); + dqp->dq_flags &= ~(XFS_DQ_WANT); + } + flist_locked = B_TRUE; + } + + /* + * id couldn't have changed; we had the hashlock all + * along + */ + ASSERT(INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id); + + if (flist_locked) { + if (dqp->q_nrefs != 0) { + xfs_qm_freelist_unlock(xfs_Gqm); + flist_locked = B_FALSE; + } else { + /* + * take it off the freelist + */ + xfs_dqtrace_entry(dqp, + "DQLOOKUP: TAKEOFF FL"); + XQM_FREELIST_REMOVE(dqp); + /* xfs_qm_freelist_print(&(xfs_Gqm-> + qm_dqfreelist), + "after removal"); */ + } + } + + /* + * grab a reference + */ + XFS_DQHOLD(dqp); + + if (flist_locked) + xfs_qm_freelist_unlock(xfs_Gqm); + /* + * move the dquot to the front of the hashchain + */ + ASSERT(XFS_DQ_IS_HASH_LOCKED(qh)); + if (dqp->HL_PREVP != &qh->qh_next) { + xfs_dqtrace_entry(dqp, + "DQLOOKUP: HASH MOVETOFRONT"); + if ((d = dqp->HL_NEXT)) + d->HL_PREVP = dqp->HL_PREVP; + *(dqp->HL_PREVP) = d; + d = qh->qh_next; + d->HL_PREVP = &dqp->HL_NEXT; + dqp->HL_NEXT = d; + dqp->HL_PREVP = &qh->qh_next; + qh->qh_next = dqp; + } + xfs_dqtrace_entry(dqp, "LOOKUP END"); + *O_dqpp = dqp; + ASSERT(XFS_DQ_IS_HASH_LOCKED(qh)); + return (0); + } + } + + *O_dqpp = NULL; + ASSERT(XFS_DQ_IS_HASH_LOCKED(qh)); + return (1); +} + +/* + * Given the file system, inode OR id, and type (UDQUOT/GDQUOT), return a + * a locked dquot, doing an allocation (if requested) as needed. + * When both an inode and an id are given, the inode's id takes precedence. + * That is, if the id changes while we dont hold the ilock inside this + * function, the new dquot is returned, not necessarily the one requested + * in the id argument. + */ +int +xfs_qm_dqget( + xfs_mount_t *mp, + xfs_inode_t *ip, /* locked inode (optional) */ + xfs_dqid_t id, /* gid or uid, depending on type */ + uint type, /* UDQUOT or GDQUOT */ + uint flags, /* DQALLOC, DQSUSER, DQREPAIR, DOWARN */ + xfs_dquot_t **O_dqpp) /* OUT : locked incore dquot */ +{ + xfs_dquot_t *dqp; + xfs_dqhash_t *h; + uint version; + int error; + + ASSERT(XFS_IS_QUOTA_RUNNING(mp)); + if ((! XFS_IS_UQUOTA_ON(mp) && type == XFS_DQ_USER) || + (! XFS_IS_GQUOTA_ON(mp) && type == XFS_DQ_GROUP)) { + return (ESRCH); + } + h = XFS_DQ_HASH(mp, id, type); + +#ifdef DEBUG + if (xfs_do_dqerror) { + if (xfs_dqerror_dev == mp->m_dev && + (xfs_dqreq_num++ % xfs_dqerror_mod) == 0) { + printk("Returning error in dqget\n"); + return (EIO); + } + } +#endif + + again: + +#ifdef DEBUG + ASSERT(type == XFS_DQ_USER || type == XFS_DQ_GROUP); + if (ip) { + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + if (type == XFS_DQ_USER) + ASSERT(ip->i_udquot == NULL); + else + ASSERT(ip->i_gdquot == NULL); + } +#endif + XFS_DQ_HASH_LOCK(h); + + /* + * Look in the cache (hashtable). + * The chain is kept locked during lookup. + */ + if (xfs_qm_dqlookup(mp, id, h, O_dqpp) == 0) { + XFS_STATS_INC(xfsstats.xs_qm_dqcachehits); + /* + * The dquot was found, moved to the front of the chain, + * taken off the freelist if it was on it, and locked + * at this point. Just unlock the hashchain and return. + */ + ASSERT(*O_dqpp); + ASSERT(XFS_DQ_IS_LOCKED(*O_dqpp)); + XFS_DQ_HASH_UNLOCK(h); + xfs_dqtrace_entry(*O_dqpp, "DQGET DONE (FROM CACHE)"); + return (0); /* success */ + } + XFS_STATS_INC(xfsstats.xs_qm_dqcachemisses); + + /* + * Dquot cache miss. We don't want to keep the inode lock across + * a (potential) disk read. Also we don't want to deal with the lock + * ordering between quotainode and this inode. OTOH, dropping the inode + * lock here means dealing with a chown that can happen before + * we re-acquire the lock. + */ + if (ip) + xfs_iunlock(ip, XFS_ILOCK_EXCL); + /* + * Save the hashchain version stamp, and unlock the chain, so that + * we don't keep the lock across a disk read + */ + version = h->qh_version; + XFS_DQ_HASH_UNLOCK(h); + + /* + * Allocate the dquot on the kernel heap, and read the ondisk + * portion off the disk. Also, do all the necessary initialization + * This can return ENOENT if dquot didn't exist on disk and we didn't + * ask it to allocate; ESRCH if quotas got turned off suddenly. + */ + if ((error = xfs_qm_idtodq(mp, id, type, + flags & (XFS_QMOPT_DQALLOC|XFS_QMOPT_DQREPAIR| + XFS_QMOPT_DOWARN), + &dqp))) { + if (ip) + xfs_ilock(ip, XFS_ILOCK_EXCL); + return (error); + } + + /* + * See if this is mount code calling to look at the overall quota limits + * which are stored in the id == 0 user or group's dquot. + * Since we may not have done a quotacheck by this point, just return + * the dquot without attaching it to any hashtables, lists, etc, or even + * taking a reference. + * The caller must dqdestroy this once done. + */ + if (flags & XFS_QMOPT_DQSUSER) { + ASSERT(id == 0); + ASSERT(! ip); + goto dqret; + } + + /* + * Dquot lock comes after hashlock in the lock ordering + */ + ASSERT(! XFS_DQ_IS_LOCKED(dqp)); + if (ip) { + xfs_ilock(ip, XFS_ILOCK_EXCL); + if (! XFS_IS_DQTYPE_ON(mp, type)) { + /* inode stays locked on return */ + xfs_qm_dqdestroy(dqp); + return XFS_ERROR(ESRCH); + } + /* + * A dquot could be attached to this inode by now, since + * we had dropped the ilock. + */ + if (type == XFS_DQ_USER) { + if (ip->i_udquot) { + xfs_qm_dqdestroy(dqp); + dqp = ip->i_udquot; + xfs_dqlock(dqp); + goto dqret; + } + } else { + if (ip->i_gdquot) { + xfs_qm_dqdestroy(dqp); + dqp = ip->i_gdquot; + xfs_dqlock(dqp); + goto dqret; + } + } + } + + /* + * Hashlock comes after ilock in lock order + */ + XFS_DQ_HASH_LOCK(h); + if (version != h->qh_version) { + xfs_dquot_t *tmpdqp; + /* + * Now, see if somebody else put the dquot in the + * hashtable before us. This can happen because we didn't + * keep the hashchain lock. We don't have to worry about + * lock order between the two dquots here since dqp isn't + * on any findable lists yet. + */ + if (xfs_qm_dqlookup(mp, id, h, &tmpdqp) == 0) { + /* + * Duplicate found. Just throw away the new dquot + * and start over. + */ + xfs_qm_dqput(tmpdqp); + XFS_DQ_HASH_UNLOCK(h); + xfs_qm_dqdestroy(dqp); + XFS_STATS_INC(xfsstats.xs_qm_dquot_dups); + goto again; + } + } + + /* + * Put the dquot at the beginning of the hash-chain and mp's list + * LOCK ORDER: hashlock, freelistlock, mplistlock, udqlock, gdqlock .. + */ + ASSERT(XFS_DQ_IS_HASH_LOCKED(h)); + dqp->q_hash = h; + XQM_HASHLIST_INSERT(h, dqp); + + /* + * Attach this dquot to this filesystem's list of all dquots, + * kept inside the mount structure in m_quotainfo field + */ + xfs_qm_mplist_lock(mp); + + /* + * We return a locked dquot to the caller, with a reference taken + */ + xfs_dqlock(dqp); + dqp->q_nrefs = 1; + + XQM_MPLIST_INSERT(&(XFS_QI_MPL_LIST(mp)), dqp); + + xfs_qm_mplist_unlock(mp); + XFS_DQ_HASH_UNLOCK(h); + dqret: + ASSERT((ip == NULL) || XFS_ISLOCKED_INODE_EXCL(ip)); + xfs_dqtrace_entry(dqp, "DQGET DONE"); + *O_dqpp = dqp; + return (0); +} + + +/* + * Release a reference to the dquot (decrement ref-count) + * and unlock it. If there is a group quota attached to this + * dquot, carefully release that too without tripping over + * deadlocks'n'stuff. + */ +void +xfs_qm_dqput( + xfs_dquot_t *dqp) +{ + xfs_dquot_t *gdqp; + + ASSERT(dqp->q_nrefs > 0); + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + xfs_dqtrace_entry(dqp, "DQPUT"); + + if (dqp->q_nrefs != 1) { + dqp->q_nrefs--; + xfs_dqunlock(dqp); + return; + } + + /* + * drop the dqlock and acquire the freelist and dqlock + * in the right order; but try to get it out-of-order first + */ + if (! xfs_qm_freelist_lock_nowait(xfs_Gqm)) { + xfs_dqtrace_entry(dqp, "DQPUT: FLLOCK-WAIT"); + xfs_dqunlock(dqp); + xfs_qm_freelist_lock(xfs_Gqm); + xfs_dqlock(dqp); + } + + while (1) { + gdqp = NULL; + + /* We can't depend on nrefs being == 1 here */ + if (--dqp->q_nrefs == 0) { + xfs_dqtrace_entry(dqp, "DQPUT: ON FREELIST"); + /* + * insert at end of the freelist. + */ + XQM_FREELIST_INSERT(&(xfs_Gqm->qm_dqfreelist), dqp); + + /* + * If we just added a udquot to the freelist, then + * we want to release the gdquot reference that + * it (probably) has. Otherwise it'll keep the + * gdquot from getting reclaimed. + */ + if ((gdqp = dqp->q_gdquot)) { + /* + * Avoid a recursive dqput call + */ + xfs_dqlock(gdqp); + dqp->q_gdquot = NULL; + } + + /* xfs_qm_freelist_print(&(xfs_Gqm->qm_dqfreelist), + "@@@@@++ Free list (after append) @@@@@+"); + */ + } + xfs_dqunlock(dqp); + + /* + * If we had a group quota inside the user quota as a hint, + * release it now. + */ + if (! gdqp) + break; + dqp = gdqp; + } + xfs_qm_freelist_unlock(xfs_Gqm); +} + +/* + * Release a dquot. Flush it if dirty, then dqput() it. + * dquot must not be locked. + */ +void +xfs_qm_dqrele( + xfs_dquot_t *dqp) +{ + ASSERT(dqp); + xfs_dqtrace_entry(dqp, "DQRELE"); + + xfs_dqlock(dqp); + /* + * We don't care to flush it if the dquot is dirty here. + * That will create stutters that we want to avoid. + * Instead we do a delayed write when we try to reclaim + * a dirty dquot. Also xfs_sync will take part of the burden... + */ + xfs_qm_dqput(dqp); +} + + +/* + * Write a modified dquot to disk. + * The dquot must be locked and the flush lock too taken by caller. + * The flush lock will not be unlocked until the dquot reaches the disk, + * but the dquot is free to be unlocked and modified by the caller + * in the interim. Dquot is still locked on return. This behavior is + * identical to that of inodes. + */ +int +xfs_qm_dqflush( + xfs_dquot_t *dqp, + uint flags) +{ + xfs_mount_t *mp; + xfs_buf_t *bp; + xfs_disk_dquot_t *ddqp; + int error; + SPLDECL(s); + + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp)); + xfs_dqtrace_entry(dqp, "DQFLUSH"); + + /* + * If not dirty, nada. + */ + if (!XFS_DQ_IS_DIRTY(dqp)) { + xfs_dqfunlock(dqp); + return (0); + } + + /* + * Cant flush a pinned dquot. Wait for it. + */ + xfs_qm_dqunpin_wait(dqp); + + /* + * This may have been unpinned because the filesystem is shutting + * down forcibly. If that's the case we must not write this dquot + * to disk, because the log record didn't make it to disk! + */ + if (XFS_FORCED_SHUTDOWN(dqp->q_mount)) { + dqp->dq_flags &= ~(XFS_DQ_DIRTY); + xfs_dqfunlock(dqp); + return XFS_ERROR(EIO); + } + + /* + * Get the buffer containing the on-disk dquot + * We don't need a transaction envelope because we know that the + * the ondisk-dquot has already been allocated for. + */ + if ((error = xfs_qm_dqtobp(NULL, dqp, &ddqp, &bp, XFS_QMOPT_DOWARN))) { + xfs_dqtrace_entry(dqp, "DQTOBP FAIL"); + ASSERT(error != ENOENT); + /* + * Quotas could have gotten turned off (ESRCH) + */ + xfs_dqfunlock(dqp); + return (error); + } + + if (xfs_qm_dqcheck(&dqp->q_core, INT_GET(ddqp->d_id, ARCH_CONVERT), 0, XFS_QMOPT_DOWARN, + "dqflush (incore copy)")) { + xfs_force_shutdown(dqp->q_mount, XFS_CORRUPT_INCORE); + return XFS_ERROR(EIO); + } + + /* This is the only portion of data that needs to persist */ + bcopy(&(dqp->q_core), ddqp, sizeof(xfs_disk_dquot_t)); + + /* + * Clear the dirty field and remember the flush lsn for later use. + */ + dqp->dq_flags &= ~(XFS_DQ_DIRTY); + mp = dqp->q_mount; + + /* lsn is 64 bits */ + AIL_LOCK(mp, s); + dqp->q_logitem.qli_flush_lsn = dqp->q_logitem.qli_item.li_lsn; + AIL_UNLOCK(mp, s); + + /* + * Attach an iodone routine so that we can remove this dquot from the + * AIL and release the flush lock once the dquot is synced to disk. + */ + xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t *, xfs_log_item_t *)) + xfs_qm_dqflush_done, &(dqp->q_logitem.qli_item)); + /* + * If the buffer is pinned then push on the log so we won't + * get stuck waiting in the write for too long. + */ + if (XFS_BUF_ISPINNED(bp)) { + xfs_dqtrace_entry(dqp, "DQFLUSH LOG FORCE"); + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); + } + + if (flags & XFS_QMOPT_DELWRI) { + xfs_bdwrite(mp, bp); + } else if (flags & XFS_QMOPT_ASYNC) { + xfs_bawrite(mp, bp); + } else { + error = xfs_bwrite(mp, bp); + } + xfs_dqtrace_entry(dqp, "DQFLUSH END"); + /* + * dqp is still locked, but caller is free to unlock it now. + */ + return (error); + +} + +/* + * This is the dquot flushing I/O completion routine. It is called + * from interrupt level when the buffer containing the dquot is + * flushed to disk. It is responsible for removing the dquot logitem + * from the AIL if it has not been re-logged, and unlocking the dquot's + * flush lock. This behavior is very similar to that of inodes.. + */ +/*ARGSUSED*/ +STATIC void +xfs_qm_dqflush_done( + xfs_buf_t *bp, + xfs_dq_logitem_t *qip) +{ + xfs_dquot_t *dqp; + SPLDECL(s); + + dqp = qip->qli_dquot; + + /* + * We only want to pull the item from the AIL if its + * location in the log has not changed since we started the flush. + * Thus, we only bother if the dquot's lsn has + * not changed. First we check the lsn outside the lock + * since it's cheaper, and then we recheck while + * holding the lock before removing the dquot from the AIL. + */ + if ((qip->qli_item.li_flags & XFS_LI_IN_AIL) && + qip->qli_item.li_lsn == qip->qli_flush_lsn) { + + AIL_LOCK(dqp->q_mount, s); + /* + * xfs_trans_delete_ail() drops the AIL lock. + */ + if (qip->qli_item.li_lsn == qip->qli_flush_lsn) + xfs_trans_delete_ail(dqp->q_mount, + (xfs_log_item_t*)qip, s); + else + AIL_UNLOCK(dqp->q_mount, s); + } + + /* + * Release the dq's flush lock since we're done with it. + */ + xfs_dqfunlock(dqp); +} + + +int +xfs_qm_dqflock_nowait( + xfs_dquot_t *dqp) +{ + int locked; + + locked = cpsema(&((dqp)->q_flock)); + + /* XXX ifdef these out */ + if (locked) + (dqp)->dq_flags |= XFS_DQ_FLOCKED; + return (locked); +} + + +int +xfs_qm_dqlock_nowait( + xfs_dquot_t *dqp) +{ + return (mutex_trylock(&((dqp)->q_qlock))); +} + +void +xfs_dqlock( + xfs_dquot_t *dqp) +{ + mutex_lock(&(dqp->q_qlock), PINOD); +} + +void +xfs_dqunlock( + xfs_dquot_t *dqp) +{ + mutex_unlock(&(dqp->q_qlock)); + if (dqp->q_logitem.qli_dquot == dqp) { + /* Once was dqp->q_mount, but might just have been cleared */ + xfs_trans_unlocked_item(dqp->q_logitem.qli_item.li_mountp, + (xfs_log_item_t*)&(dqp->q_logitem)); + } +} + + +void +xfs_dqunlock_nonotify( + xfs_dquot_t *dqp) +{ + mutex_unlock(&(dqp->q_qlock)); +} + +void +xfs_dqlock2( + xfs_dquot_t *d1, + xfs_dquot_t *d2) +{ + if (d1 && d2) { + ASSERT(d1 != d2); + if (INT_GET(d1->q_core.d_id, ARCH_CONVERT) > INT_GET(d2->q_core.d_id, ARCH_CONVERT)) { + xfs_dqlock(d2); + xfs_dqlock(d1); + } else { + xfs_dqlock(d1); + xfs_dqlock(d2); + } + } else { + if (d1) { + xfs_dqlock(d1); + } else if (d2) { + xfs_dqlock(d2); + } + } +} + + +/* + * A rarely used accessor. This exists because we don't really want + * to expose the internals of a dquot to the outside world. + */ +xfs_dqid_t +xfs_qm_dqid( + xfs_dquot_t *dqp) +{ + return (INT_GET(dqp->q_core.d_id, ARCH_CONVERT)); +} + + +/* + * Take a dquot out of the mount's dqlist as well as the hashlist. + * This is called via unmount as well as quotaoff, and the purge + * will always succeed unless there are soft (temp) references + * outstanding. + * + * This returns 0 if it was purged, 1 if it wasn't. It's not an error code + * that we're returning! XXXsup - not cool. + */ +/* ARGSUSED */ +int +xfs_qm_dqpurge( + xfs_dquot_t *dqp, + uint flags) +{ + xfs_dqhash_t *thishash; + xfs_mount_t *mp; + + mp = dqp->q_mount; + + ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp)); + ASSERT(XFS_DQ_IS_HASH_LOCKED(dqp->q_hash)); + + xfs_dqlock(dqp); + /* + * We really can't afford to purge a dquot that is + * referenced, because these are hard refs. + * It shouldn't happen in general because we went thru _all_ inodes in + * dqrele_all_inodes before calling this and didn't let the mountlock go. + * However it is possible that we have dquots with temporary + * references that are not attached to an inode. e.g. see xfs_setattr(). + */ + if (dqp->q_nrefs != 0) { + xfs_dqunlock(dqp); + XFS_DQ_HASH_UNLOCK(dqp->q_hash); + return (1); + } + + ASSERT(XFS_DQ_IS_ON_FREELIST(dqp)); + + /* + * If we're turning off quotas, we have to make sure that, for + * example, we don't delete quota disk blocks while dquots are + * in the process of getting written to those disk blocks. + * This dquot might well be on AIL, and we can't leave it there + * if we're turning off quotas. Basically, we need this flush + * lock, and are willing to block on it. + */ + if (! xfs_qm_dqflock_nowait(dqp)) { + /* + * Block on the flush lock after nudging dquot buffer, + * if it is incore. + */ + xfs_qm_dqflock_pushbuf_wait(dqp); + } + + /* + * XXXIf we're turning this type of quotas off, we don't care + * about the dirty metadata sitting in this dquot. OTOH, if + * we're unmounting, we do care, so we flush it and wait. + */ + if (XFS_DQ_IS_DIRTY(dqp)) { + xfs_dqtrace_entry(dqp, "DQPURGE ->DQFLUSH: DQDIRTY"); + /* dqflush unlocks dqflock */ + /* + * Given that dqpurge is a very rare occurence, it is OK + * that we're holding the hashlist and mplist locks + * across the disk write. But, ... XXXsup + * + * We don't care about getting disk errors here. We need + * to purge this dquot anyway, so we go ahead regardless. + */ + (void) xfs_qm_dqflush(dqp, XFS_QMOPT_SYNC); + xfs_dqflock(dqp); + } + ASSERT(dqp->q_pincount == 0); + ASSERT(XFS_FORCED_SHUTDOWN(mp) || + !(dqp->q_logitem.qli_item.li_flags & XFS_LI_IN_AIL)); + + thishash = dqp->q_hash; + XQM_HASHLIST_REMOVE(thishash, dqp); + XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(mp)), dqp); + /* + * XXX Move this to the front of the freelist, if we can get the + * freelist lock. + */ + ASSERT(XFS_DQ_IS_ON_FREELIST(dqp)); + + dqp->q_mount = NULL;; + dqp->q_hash = NULL; + dqp->dq_flags = XFS_DQ_INACTIVE; + bzero(&dqp->q_core, sizeof(dqp->q_core)); + xfs_dqfunlock(dqp); + xfs_dqunlock(dqp); + XFS_DQ_HASH_UNLOCK(thishash); + return (0); +} + + +/* + * Do some primitive error checking on ondisk dquot + * data structures. Not just for debugging, actually; + * this can be useful for detecting data corruption mainly due to + * disk failures. + */ +/* ARGSUSED */ +int +xfs_qm_dqcheck( + xfs_disk_dquot_t *ddq, + xfs_dqid_t id, + uint type, /* used only when IO_dorepair is true */ + uint flags, + char *str) +{ + int errs; + + errs = 0; + /* ASSERT(flags & (XFS_QMOPT_DQREPAIR|XFS_QMOPT_DOWARN)); */ + /* + * We can encounter an uninitialized dquot buffer for 2 reasons: + * 1. If we crash while deleting the quotainode(s), and those blks get used + * for some user data. This is because we take the path of regular + * file deletion; however, the size field of quotainodes is never + * updated, so all the tricks that we play in itruncate_finish + * don't quite matter. + * + * 2. We don't play the quota buffers when there's a quotaoff logitem. + * But the allocation will be replayed so we'll end up with an + * uninitialized quota block. + * + * This is all fine; things are still consistent, and we haven't lost + * any quota information. Just don't complain about bad dquot blks. + */ + if (INT_GET(ddq->d_magic, ARCH_CONVERT) != XFS_DQUOT_MAGIC) { + if (flags & XFS_QMOPT_DOWARN) + cmn_err(CE_ALERT, + "%s : XFS dquot ID 0x%x, magic 0x%x != 0x%x", + str, id, INT_GET(ddq->d_magic, ARCH_CONVERT), XFS_DQUOT_MAGIC); + errs++; + } + if (INT_GET(ddq->d_version, ARCH_CONVERT) != XFS_DQUOT_VERSION) { + if (flags & XFS_QMOPT_DOWARN) + cmn_err(CE_ALERT, + "%s : XFS dquot ID 0x%x, version 0x%x != 0x%x", + str, id, INT_GET(ddq->d_magic, ARCH_CONVERT), XFS_DQUOT_VERSION); + errs++; + } + + if (INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_USER && INT_GET(ddq->d_flags, ARCH_CONVERT) != XFS_DQ_GROUP) { + if (flags & XFS_QMOPT_DOWARN) + cmn_err(CE_ALERT, + "%s : XFS dquot ID 0x%x, unknown flags 0x%x", + str, id, INT_GET(ddq->d_flags, ARCH_CONVERT)); + errs++; + } + + if (id != -1 && id != INT_GET(ddq->d_id, ARCH_CONVERT)) { + if (flags & XFS_QMOPT_DOWARN) + cmn_err(CE_ALERT, + "%s : ondisk-dquot 0x%x, ID mismatch: " + "0x%x expected, found id 0x%x", + str, ddq, id, INT_GET(ddq->d_id, ARCH_CONVERT)); + errs++; + } + + if (! errs) { + if (INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT) && + INT_GET(ddq->d_bcount, ARCH_CONVERT) >= INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT)) { + if (INT_GET(ddq->d_btimer, ARCH_CONVERT) == 0 && INT_GET(ddq->d_id, ARCH_CONVERT) != 0) { + if (flags & XFS_QMOPT_DOWARN) + cmn_err(CE_ALERT, + "%s : Dquot ID 0x%x (0x%x) " + "BLK TIMER NOT STARTED", + str, (int) INT_GET(ddq->d_id, ARCH_CONVERT), ddq); + errs++; + } + } + if (INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT) && + INT_GET(ddq->d_icount, ARCH_CONVERT) >= INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT)) { + if (INT_GET(ddq->d_itimer, ARCH_CONVERT) == 0 && INT_GET(ddq->d_id, ARCH_CONVERT) != 0) { + if (flags & XFS_QMOPT_DOWARN) + cmn_err(CE_ALERT, + "%s : Dquot ID 0x%x (0x%x) " + "INODE TIMER NOT STARTED", + str, (int) INT_GET(ddq->d_id, ARCH_CONVERT), ddq); + errs++; + } + } + } + + if (!errs || !(flags & XFS_QMOPT_DQREPAIR)) + return (errs); + + if (flags & XFS_QMOPT_DOWARN) + cmn_err(CE_NOTE, "Re-initializing dquot ID 0x%x", id); + + /* + * Typically, a repair is only requested by quotacheck. + */ + ASSERT(id != -1); + ASSERT(flags & XFS_QMOPT_DQREPAIR); + bzero(ddq, sizeof(xfs_dqblk_t)); + xfs_qm_dqinit_core(id, type, (xfs_dqblk_t *)ddq); + return (errs); +} + +#ifdef QUOTADEBUG +void +xfs_qm_dqprint(xfs_dquot_t *dqp) +{ + printk( "-----------KERNEL DQUOT----------------\n"); + printk( "---- dquot ID = %d\n", (int) INT_GET(dqp->q_core.d_id, ARCH_CONVERT)); + printk( "---- type = %s\n", XFS_QM_ISUDQ(dqp) ? "USR" : "GRP"); + printk( "---- fs = 0x%p\n", dqp->q_mount); + printk( "---- blkno = 0x%x\n", (int) dqp->q_blkno); + printk( "---- boffset = 0x%x\n", (int) dqp->q_bufoffset); + printk( "---- blkhlimit = %Lu (0x%x)\n", + INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT), + (int) INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT)); + printk( "---- blkslimit = %Lu (0x%x)\n", + INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT), + (int)INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT)); + printk( "---- inohlimit = %Lu (0x%x)\n", + INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT), + (int)INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT)); + printk( "---- inoslimit = %Lu (0x%x)\n", + INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT), + (int)INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)); + printk( "---- bcount = %Lu (0x%x)\n", + INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), + (int)INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT)); + printk( "---- icount = %Lu (0x%x)\n", + INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), + (int)INT_GET(dqp->q_core.d_icount, ARCH_CONVERT)); + printk( "---- btimer = %d\n", (int)INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT)); + printk( "---- itimer = %d\n", (int)INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)); + + printk( "---------------------------\n"); +} +#endif + +/* + * Give the buffer a little push if it is incore and + * wait on the flush lock. + */ +void +xfs_qm_dqflock_pushbuf_wait( + xfs_dquot_t *dqp) +{ + xfs_buf_t *bp; + + /* + * Check to see if the dquot has been flushed delayed + * write. If so, grab its buffer and send it + * out immediately. We'll be able to acquire + * the flush lock when the I/O completes. + */ + /* + bp = incore(dqp->q_dev, dqp->q_blkno, + XFS_QI_DQCHUNKLEN(dqp->q_mount), + INCORE_TRYLOCK); + */ + bp = xfs_incore(dqp->q_mount->m_ddev_targ, dqp->q_blkno, + XFS_QI_DQCHUNKLEN(dqp->q_mount), + XFS_INCORE_TRYLOCK); + if (bp != NULL) { + if (XFS_BUF_ISDELAYWRITE(bp)) { + if (XFS_BUF_ISPINNED(bp)) { + xfs_log_force(dqp->q_mount, + (xfs_lsn_t)0, + XFS_LOG_FORCE); + } + xfs_bawrite(dqp->q_mount, bp); + } else { + xfs_buf_relse(bp); + } + } + xfs_dqflock(dqp); +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dquot.h linux-2.4-xfs/linux/fs/xfs/xfs_dquot.h --- linux-2.4.7/linux/fs/xfs/xfs_dquot.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dquot.h Wed May 23 00:32:22 2001 @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DQUOT_H__ +#define __XFS_DQUOT_H__ + +/* + * Dquots are structures that hold quota information about a user or a group, + * much like inodes are for files. In fact, dquots share many characteristics + * with inodes. However, dquots can also be a centralized resource, relative + * to a collection of inodes. In this respect, dquots share some characteristics + * of the superblock. + * XFS dquots exploit both those in its algorithms. They make every attempt + * to not be a bottleneck when quotas are on and have minimal impact, if any, + * when quotas are off. + */ + +/* + * The hash chain headers (hash buckets) + */ +typedef struct xfs_dqhash { + struct xfs_dquot *qh_next; + mutex_t qh_lock; + uint qh_version; /* ever increasing version */ + uint qh_nelems; /* number of dquots on the list */ +} xfs_dqhash_t; + +typedef struct xfs_dqlink { + struct xfs_dquot *ql_next; /* forward link */ + struct xfs_dquot **ql_prevp; /* pointer to prev ql_next */ +} xfs_dqlink_t; + +struct xfs_mount; +struct xfs_trans; + +/* + * This is the marker which is designed to occupy the first few + * bytes of the xfs_dquot_t structure. Even inside this, the freelist pointers + * must come first. + * This serves as the marker ("sentinel") when we have to restart list + * iterations because of locking considerations. + */ +typedef struct xfs_dqmarker { + struct xfs_dquot*dqm_flnext; /* link to freelist: must be first */ + struct xfs_dquot*dqm_flprev; + xfs_dqlink_t dqm_mplist; /* link to mount's list of dquots */ + xfs_dqlink_t dqm_hashlist; /* link to the hash chain */ + uint dqm_flags; /* various flags (XFS_DQ_*) */ +} xfs_dqmarker_t; + +/* + * The incore dquot structure + */ +typedef struct xfs_dquot { + xfs_dqmarker_t q_lists; /* list ptrs, q_flags (marker) */ + xfs_dqhash_t *q_hash; /* the hashchain header */ + struct xfs_mount*q_mount; /* filesystem this relates to */ + struct xfs_trans*q_transp; /* trans this belongs to currently */ + uint q_nrefs; /* # active refs from inodes */ + xfs_daddr_t q_blkno; /* blkno of dquot buffer */ + dev_t q_dev; /* dev for this dquot */ + int q_bufoffset; /* off of dq in buffer (# dquots) */ + xfs_fileoff_t q_fileoffset; /* offset in quotas file */ + + struct xfs_dquot*q_gdquot; /* group dquot, hint only */ + xfs_disk_dquot_t q_core; /* actual usage & quotas */ + xfs_dq_logitem_t q_logitem; /* dquot log item */ + xfs_qcnt_t q_res_bcount; /* total regular nblks used+reserved */ + xfs_qcnt_t q_res_icount; /* total inos allocd+reserved */ + xfs_qcnt_t q_res_rtbcount;/* total realtime blks used+reserved */ + mutex_t q_qlock; /* quota lock */ + sema_t q_flock; /* flush lock */ + uint q_pincount; /* pin count for this dquot */ + sv_t q_pinwait; /* sync var for pinning */ +#ifdef DQUOT_TRACING + struct ktrace *q_trace; /* trace header structure */ +#endif +} xfs_dquot_t; + + +#define dq_flnext q_lists.dqm_flnext +#define dq_flprev q_lists.dqm_flprev +#define dq_mplist q_lists.dqm_mplist +#define dq_hashlist q_lists.dqm_hashlist +#define dq_flags q_lists.dqm_flags + +#define XFS_DQHOLD(dqp) ((dqp)->q_nrefs++) + +/* + * Quota Accounting flags + */ +#define XFS_ALL_QUOTA_ACCT (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT) +#define XFS_ALL_QUOTA_ENFD (XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD) +#define XFS_ALL_QUOTA_CHKD (XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD) +#define XFS_ALL_QUOTA_ACTV (XFS_UQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE) +#define XFS_ALL_QUOTA_ACCT_ENFD (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ + XFS_GQUOTA_ACCT|XFS_GQUOTA_ENFD) + +#define XFS_IS_QUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT) +#define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT) +#define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT) + +/* + * Quota Limit Enforcement flags + */ +#define XFS_IS_QUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ENFD) +#define XFS_IS_UQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_UQUOTA_ENFD) +#define XFS_IS_GQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_GQUOTA_ENFD) + +#ifdef DEBUG +static inline int +XFS_DQ_IS_LOCKED(xfs_dquot_t *dqp) +{ + if (mutex_trylock(&dqp->q_qlock)) { + mutex_unlock(&dqp->q_qlock); + return 0; + } + return 1; +} +#endif + +/* + * The following three routines simply manage the q_flock + * semaphore embedded in the dquot. This semaphore synchronizes + * processes attempting to flush the in-core dquot back to disk. + */ +#define xfs_dqflock(dqp) { psema(&((dqp)->q_flock), PINOD | PRECALC);\ + (dqp)->dq_flags |= XFS_DQ_FLOCKED; } +#define xfs_dqfunlock(dqp) { ASSERT(valusema(&((dqp)->q_flock)) <= 0); \ + vsema(&((dqp)->q_flock)); \ + (dqp)->dq_flags &= ~(XFS_DQ_FLOCKED); } + +#define XFS_DQ_PINLOCK(dqp) mutex_spinlock( \ + &(XFS_DQ_TO_QINF(dqp)->qi_pinlock)) +#define XFS_DQ_PINUNLOCK(dqp, s) mutex_spinunlock( \ + &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s) + +#define XFS_DQ_IS_FLUSH_LOCKED(dqp) (valusema(&((dqp)->q_flock)) <= 0) +#define XFS_DQ_IS_ON_FREELIST(dqp) ((dqp)->dq_flnext != (dqp)) +#define XFS_DQ_IS_DIRTY(dqp) ((dqp)->dq_flags & XFS_DQ_DIRTY) +#define XFS_QM_ISUDQ(dqp) ((dqp)->dq_flags & XFS_DQ_USER) +#define XFS_DQ_TO_QINF(dqp) ((dqp)->q_mount->m_quotainfo) +#define XFS_DQ_TO_QIP(dqp) (XFS_QM_ISUDQ(dqp) ? \ + XFS_DQ_TO_QINF(dqp)->qi_uquotaip : \ + XFS_DQ_TO_QINF(dqp)->qi_gquotaip) + +#define XFS_IS_THIS_QUOTA_OFF(d) (! (XFS_QM_ISUDQ(d) ? \ + (XFS_IS_UQUOTA_ON((d)->q_mount)) : \ + (XFS_IS_GQUOTA_ON((d)->q_mount)))) +#ifdef DQUOT_TRACING +/* + * Dquot Tracing stuff. + */ +#define DQUOT_TRACE_SIZE 64 +#define DQUOT_KTRACE_ENTRY 1 + +#define xfs_dqtrace_entry_ino(a,b,ip) \ +xfs_dqtrace_entry__((a), (b), (void*)__return_address, (ip)) +#define xfs_dqtrace_entry(a,b) \ +xfs_dqtrace_entry__((a), (b), (void*)__return_address, NULL) +extern void xfs_dqtrace_entry__(xfs_dquot_t *dqp, char *func, + void *, xfs_inode_t *); +#else +#define xfs_dqtrace_entry(a,b) +#define xfs_dqtrace_entry_ino(a,b,ip) +#endif +#ifdef QUOTADEBUG +extern void xfs_qm_dqprint(xfs_dquot_t *); +#else +#define xfs_qm_dqprint(a) +#endif + +extern xfs_dquot_t *xfs_qm_dqinit(xfs_mount_t *, xfs_dqid_t, uint); +extern void xfs_qm_dqdestroy(xfs_dquot_t *); +extern int xfs_qm_dqflush(xfs_dquot_t *, uint); +extern int xfs_qm_dqpurge(xfs_dquot_t *, uint); +extern void xfs_qm_dqunpin_wait(xfs_dquot_t *); +extern int xfs_qm_dqlock_nowait(xfs_dquot_t *); +extern int xfs_qm_dqflock_nowait(xfs_dquot_t *); +extern void xfs_qm_dqflock_pushbuf_wait(xfs_dquot_t *dqp); +extern void xfs_qm_adjust_dqtimers(xfs_mount_t *, + xfs_disk_dquot_t *); +extern int xfs_qm_dqwarn(xfs_disk_dquot_t *, uint); + +#endif /* __XFS_DQUOT_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dquot_item.c linux-2.4-xfs/linux/fs/xfs/xfs_dquot_item.c --- linux-2.4.7/linux/fs/xfs/xfs_dquot_item.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dquot_item.c Wed Apr 11 11:27:03 2001 @@ -0,0 +1,673 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + + +/* + * returns the number of iovecs needed to log the given dquot item. + */ +/* ARGSUSED */ +STATIC uint +xfs_qm_dquot_logitem_size( + xfs_dq_logitem_t *logitem) +{ + /* + * we need only two iovecs, one for the format, one for the real thing + */ + return (2); +} + +/* + * fills in the vector of log iovecs for the given dquot log item. + */ +STATIC void +xfs_qm_dquot_logitem_format( + xfs_dq_logitem_t *logitem, + xfs_log_iovec_t *logvec) +{ + ASSERT(logitem); + ASSERT(logitem->qli_dquot); + + logvec->i_addr = (xfs_caddr_t)&logitem->qli_format; + logvec->i_len = sizeof(xfs_dq_logformat_t); + logvec++; + logvec->i_addr = (xfs_caddr_t)&logitem->qli_dquot->q_core; + logvec->i_len = sizeof(xfs_disk_dquot_t); + + ASSERT(2 == logitem->qli_item.li_desc->lid_size); + logitem->qli_format.qlf_size = 2; + +} + +/* + * Increment the pin count of the given dquot. + * This value is protected by pinlock spinlock in the xQM structure. + */ +STATIC void +xfs_qm_dquot_logitem_pin( + xfs_dq_logitem_t *logitem) +{ + int s; + xfs_dquot_t *dqp; + + dqp = logitem->qli_dquot; + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + s = XFS_DQ_PINLOCK(dqp); + dqp->q_pincount++; + XFS_DQ_PINUNLOCK(dqp, s); +} + +/* + * Decrement the pin count of the given dquot, and wake up + * anyone in xfs_dqwait_unpin() if the count goes to 0. The + * dquot must have been previously pinned with a call to xfs_dqpin(). + */ +STATIC void +xfs_qm_dquot_logitem_unpin( + xfs_dq_logitem_t *logitem) +{ + int s; + xfs_dquot_t *dqp; + + dqp = logitem->qli_dquot; + ASSERT(dqp->q_pincount > 0); + s = XFS_DQ_PINLOCK(dqp); + dqp->q_pincount--; + if (dqp->q_pincount == 0) { + sv_broadcast(&dqp->q_pinwait); + } + XFS_DQ_PINUNLOCK(dqp, s); +} + +/* ARGSUSED */ +STATIC void +xfs_qm_dquot_logitem_unpin_remove( + xfs_dq_logitem_t *logitem, + xfs_trans_t *tp) +{ + xfs_qm_dquot_logitem_unpin(logitem); +} + +/* + * Given the logitem, this writes the corresponding dquot entry to disk + * asynchronously. This is called with the dquot entry securely locked; + * we simply get xfs_qm_dqflush() to do the work, and unlock the dquot + * at the end. + */ +STATIC void +xfs_qm_dquot_logitem_push( + xfs_dq_logitem_t *logitem) +{ + xfs_dquot_t *dqp; + + dqp = logitem->qli_dquot; + + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + ASSERT(XFS_DQ_IS_FLUSH_LOCKED(dqp)); + + /* + * Since we were able to lock the dquot's flush lock and + * we found it on the AIL, the dquot must be dirty. This + * is because the dquot is removed from the AIL while still + * holding the flush lock in xfs_dqflush_done(). Thus, if + * we found it in the AIL and were able to obtain the flush + * lock without sleeping, then there must not have been + * anyone in the process of flushing the dquot. + */ + xfs_qm_dqflush(dqp, XFS_B_DELWRI); + xfs_dqunlock(dqp); +} + +/*ARGSUSED*/ +STATIC xfs_lsn_t +xfs_qm_dquot_logitem_committed( + xfs_dq_logitem_t *l, + xfs_lsn_t lsn) +{ + /* + * We always re-log the entire dquot when it becomes dirty, + * so, the latest copy _is_ the only one that matters. + */ + return (lsn); +} + + +/* + * This is called to wait for the given dquot to be unpinned. + * Most of these pin/unpin routines are plagiarized from inode code. + */ +void +xfs_qm_dqunpin_wait( + xfs_dquot_t *dqp) +{ + int s; + + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + if (dqp->q_pincount == 0) { + return; + } + + /* + * Give the log a push so we don't wait here too long. + */ + xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, XFS_LOG_FORCE); + s = XFS_DQ_PINLOCK(dqp); + if (dqp->q_pincount == 0) { + XFS_DQ_PINUNLOCK(dqp, s); + return; + } + sv_wait(&(dqp->q_pinwait), PINOD, + &(XFS_DQ_TO_QINF(dqp)->qi_pinlock), s); +} + +/* + * This is called when IOP_TRYLOCK returns XFS_ITEM_PUSHBUF to indicate that + * the dquot is locked by us, but the flush lock isn't. So, here we are + * going to see if the relevant dquot buffer is incore, waiting on DELWRI. + * If so, we want to push it out to help us take this item off the AIL as soon + * as possible. + * + * We must not be holding the AIL_LOCK at this point. Calling incore() to + * search the buffercache can be a time consuming thing, and AIL_LOCK is a + * spinlock. + */ +STATIC void +xfs_qm_dquot_logitem_pushbuf( + xfs_dq_logitem_t *qip) +{ + xfs_dquot_t *dqp; + xfs_mount_t *mp; + xfs_buf_t *bp; + uint dopush; + + dqp = qip->qli_dquot; + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + + /* + * The qli_pushbuf_flag keeps others from + * trying to duplicate our effort. + */ + ASSERT(qip->qli_pushbuf_flag != 0); + ASSERT(qip->qli_push_owner == get_thread_id()); + + /* + * If flushlock isn't locked anymore, chances are that the + * inode flush completed and the inode was taken off the AIL. + * So, just get out. + */ + if ((valusema(&(dqp->q_flock)) > 0) || + ((qip->qli_item.li_flags & XFS_LI_IN_AIL) == 0)) { + qip->qli_pushbuf_flag = 0; + xfs_dqunlock(dqp); + return; + } + mp = dqp->q_mount; + bp = xfs_incore(mp->m_ddev_targ, qip->qli_format.qlf_blkno, + XFS_QI_DQCHUNKLEN(mp), + XFS_INCORE_TRYLOCK); + if (bp != NULL) { + if (XFS_BUF_ISDELAYWRITE(bp)) { + dopush = ((qip->qli_item.li_flags & XFS_LI_IN_AIL) && + (valusema(&(dqp->q_flock)) <= 0)); + qip->qli_pushbuf_flag = 0; + xfs_dqunlock(dqp); + + if (XFS_BUF_ISPINNED(bp)) { + xfs_log_force(mp, (xfs_lsn_t)0, + XFS_LOG_FORCE); + } + if (dopush) { +#ifdef XFSRACEDEBUG + delay_for_intr(); + delay(300); +#endif + xfs_bawrite(mp, bp); + } else { + xfs_buf_relse(bp); + } + } else { + qip->qli_pushbuf_flag = 0; + xfs_dqunlock(dqp); + xfs_buf_relse(bp); + } + return; + } + + qip->qli_pushbuf_flag = 0; + xfs_dqunlock(dqp); +} + +/* + * This is called to attempt to lock the dquot associated with this + * dquot log item. Don't sleep on the dquot lock or the flush lock. + * If the flush lock is already held, indicating that the dquot has + * been or is in the process of being flushed, then see if we can + * find the dquot's buffer in the buffer cache without sleeping. If + * we can and it is marked delayed write, then we want to send it out. + * We delay doing so until the push routine, though, to avoid sleeping + * in any device strategy routines. + */ +STATIC uint +xfs_qm_dquot_logitem_trylock( + xfs_dq_logitem_t *qip) +{ + xfs_dquot_t *dqp; + uint retval; + + dqp = qip->qli_dquot; + if (dqp->q_pincount > 0) + return (XFS_ITEM_PINNED); + + if (! xfs_qm_dqlock_nowait(dqp)) + return (XFS_ITEM_LOCKED); + + retval = XFS_ITEM_SUCCESS; + if (! xfs_qm_dqflock_nowait(dqp)) { + /* + * The dquot is already being flushed. It may have been + * flushed delayed write, however, and we don't want to + * get stuck waiting for that to complete. So, we want to check + * to see if we can lock the dquot's buffer without sleeping. + * If we can and it is marked for delayed write, then we + * hold it and send it out from the push routine. We don't + * want to do that now since we might sleep in the device + * strategy routine. We also don't want to grab the buffer lock + * here because we'd like not to call into the buffer cache + * while holding the AIL_LOCK. + * Make sure to only return PUSHBUF if we set pushbuf_flag + * ourselves. If someone else is doing it then we don't + * want to go to the push routine and duplicate their efforts. + */ + if (qip->qli_pushbuf_flag == 0) { + qip->qli_pushbuf_flag = 1; + ASSERT(qip->qli_format.qlf_blkno == dqp->q_blkno); +#ifdef DEBUG + qip->qli_push_owner = get_thread_id(); +#endif + /* + * The dquot is left locked. + */ + retval = XFS_ITEM_PUSHBUF; + } else { + retval = XFS_ITEM_FLUSHING; + xfs_dqunlock_nonotify(dqp); + } + } + + ASSERT(qip->qli_item.li_flags & XFS_LI_IN_AIL); + return (retval); +} + + +/* + * Unlock the dquot associated with the log item. + * Clear the fields of the dquot and dquot log item that + * are specific to the current transaction. If the + * hold flags is set, do not unlock the dquot. + */ +STATIC void +xfs_qm_dquot_logitem_unlock( + xfs_dq_logitem_t *ql) +{ + xfs_dquot_t *dqp; + + ASSERT(ql != NULL); + dqp = ql->qli_dquot; + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + + /* + * Clear the transaction pointer in the dquot + */ + dqp->q_transp = NULL; + + /* + * dquots are never 'held' from getting unlocked at the end of + * a transaction. Their locking and unlocking is hidden inside the + * transaction layer, within trans_commit. Hence, no LI_HOLD flag + * for the logitem. + */ + xfs_dqunlock(dqp); +} + + +/* + * The transaction with the dquot locked has aborted. The dquot + * must not be dirty within the transaction. We simply unlock just + * as if the transaction had been cancelled. + */ +STATIC void +xfs_qm_dquot_logitem_abort( + xfs_dq_logitem_t *ql) +{ + xfs_qm_dquot_logitem_unlock(ql); +} + +/* + * this needs to stamp an lsn into the dquot, I think. + * rpc's that look at user dquot's would then have to + * push on the dependency recorded in the dquot + */ +/* ARGSUSED */ +STATIC void +xfs_qm_dquot_logitem_committing( + xfs_dq_logitem_t *l, + xfs_lsn_t lsn) +{ + return; +} + + +/* + * This is the ops vector for dquots + */ +struct xfs_item_ops xfs_dquot_item_ops = { + iop_size: (uint(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_size, + iop_format: (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) + xfs_qm_dquot_logitem_format, + iop_pin: (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_pin, + iop_unpin: (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_unpin, + iop_unpin_remove: (void(*)(xfs_log_item_t*, xfs_trans_t*)) + xfs_qm_dquot_logitem_unpin_remove, + iop_trylock: (uint(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_trylock, + iop_unlock: (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_unlock, + iop_committed: (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_qm_dquot_logitem_committed, + iop_push: (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_push, + iop_abort: (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_abort, + iop_pushbuf: (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_pushbuf, + iop_committing: (void(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_qm_dquot_logitem_committing +}; + +/* + * Initialize the dquot log item for a newly allocated dquot. + * The dquot isn't locked at this point, but it isn't on any of the lists + * either, so we don't care. + */ +void +xfs_qm_dquot_logitem_init( + struct xfs_dquot *dqp) +{ + xfs_dq_logitem_t *lp; + lp = &dqp->q_logitem; + + lp->qli_item.li_type = XFS_LI_DQUOT; + lp->qli_item.li_ops = &xfs_dquot_item_ops; + lp->qli_item.li_mountp = dqp->q_mount; + lp->qli_dquot = dqp; + lp->qli_format.qlf_type = XFS_LI_DQUOT; + lp->qli_format.qlf_id = INT_GET(dqp->q_core.d_id, ARCH_CONVERT); + lp->qli_format.qlf_blkno = dqp->q_blkno; + lp->qli_format.qlf_len = 1; + /* + * This is just the offset of this dquot within its buffer + * (which is currently 1 FSB and probably won't change). + * Hence 32 bits for this offset should be just fine. + * Alternatively, we can store (bufoffset / sizeof(xfs_dqblk_t)) + * here, and recompute it at recovery time. + */ + lp->qli_format.qlf_boffset = (__uint32_t)dqp->q_bufoffset; +} + +/*------------------ QUOTAOFF LOG ITEMS -------------------*/ + +/* + * This returns the number of iovecs needed to log the given quotaoff item. + * We only need 1 iovec for an quotaoff item. It just logs the + * quotaoff_log_format structure. + */ +/*ARGSUSED*/ +STATIC uint +xfs_qm_qoff_logitem_size(xfs_qoff_logitem_t *qf) +{ + return (1); +} + +/* + * This is called to fill in the vector of log iovecs for the + * given quotaoff log item. We use only 1 iovec, and we point that + * at the quotaoff_log_format structure embedded in the quotaoff item. + * It is at this point that we assert that all of the extent + * slots in the quotaoff item have been filled. + */ +STATIC void +xfs_qm_qoff_logitem_format(xfs_qoff_logitem_t *qf, + xfs_log_iovec_t *log_vector) +{ + ASSERT(qf->qql_format.qf_type == XFS_LI_QUOTAOFF); + + log_vector->i_addr = (xfs_caddr_t)&(qf->qql_format); + log_vector->i_len = sizeof(xfs_qoff_logitem_t); + qf->qql_format.qf_size = 1; +} + + +/* + * Pinning has no meaning for an quotaoff item, so just return. + */ +/*ARGSUSED*/ +STATIC void +xfs_qm_qoff_logitem_pin(xfs_qoff_logitem_t *qf) +{ + return; +} + + +/* + * Since pinning has no meaning for an quotaoff item, unpinning does + * not either. + */ +/*ARGSUSED*/ +STATIC void +xfs_qm_qoff_logitem_unpin(xfs_qoff_logitem_t *qf) +{ + return; +} + +/*ARGSUSED*/ +STATIC void +xfs_qm_qoff_logitem_unpin_remove(xfs_qoff_logitem_t *qf, xfs_trans_t *tp) +{ + return; +} + +/* + * Quotaoff items have no locking, so just return success. + */ +/*ARGSUSED*/ +STATIC uint +xfs_qm_qoff_logitem_trylock(xfs_qoff_logitem_t *qf) +{ + return XFS_ITEM_LOCKED; +} + +/* + * Quotaoff items have no locking or pushing, so return failure + * so that the caller doesn't bother with us. + */ +/*ARGSUSED*/ +STATIC void +xfs_qm_qoff_logitem_unlock(xfs_qoff_logitem_t *qf) +{ + return; +} + +/* + * The quotaoff-start-item is logged only once and cannot be moved in the log, + * so simply return the lsn at which it's been logged. + */ +/*ARGSUSED*/ +STATIC xfs_lsn_t +xfs_qm_qoff_logitem_committed(xfs_qoff_logitem_t *qf, xfs_lsn_t lsn) +{ + return (lsn); +} + +/* + * The transaction of which this QUOTAOFF is a part has been aborted. + * Just clean up after ourselves. + * Shouldn't this never happen in the case of qoffend logitems? XXX + */ +STATIC void +xfs_qm_qoff_logitem_abort(xfs_qoff_logitem_t *qf) +{ + kmem_free(qf, sizeof(xfs_qoff_logitem_t)); +} + +/* + * There isn't much you can do to push on an quotaoff item. It is simply + * stuck waiting for the log to be flushed to disk. + */ +/*ARGSUSED*/ +STATIC void +xfs_qm_qoff_logitem_push(xfs_qoff_logitem_t *qf) +{ + return; +} + + +/*ARGSUSED*/ +STATIC xfs_lsn_t +xfs_qm_qoffend_logitem_committed( + xfs_qoff_logitem_t *qfe, + xfs_lsn_t lsn) +{ + xfs_qoff_logitem_t *qfs; + SPLDECL(s); + + qfs = qfe->qql_start_lip; + AIL_LOCK(qfs->qql_item.li_mountp,s); + /* + * Delete the qoff-start logitem from the AIL. + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(qfs->qql_item.li_mountp, (xfs_log_item_t *)qfs, s); + kmem_free(qfs, sizeof(xfs_qoff_logitem_t)); + kmem_free(qfe, sizeof(xfs_qoff_logitem_t)); + return (xfs_lsn_t)-1; +} + +/* + * XXX rcc - don't know quite what to do with this. I think we can + * just ignore it. The only time that isn't the case is if we allow + * the client to somehow see that quotas have been turned off in which + * we can't allow that to get back until the quotaoff hits the disk. + * So how would that happen? Also, do we need different routines for + * quotaoff start and quotaoff end? I suspect the answer is yes but + * to be sure, I need to look at the recovery code and see how quota off + * recovery is handled (do we roll forward or back or do something else). + * If we roll forwards or backwards, then we need two separate routines, + * one that does nothing and one that stamps in the lsn that matters + * (truly makes the quotaoff irrevocable). If we do something else, + * then maybe we don't need two. + */ +/* ARGSUSED */ +STATIC void +xfs_qm_qoff_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn) +{ + return; +} + +/* ARGSUSED */ +STATIC void +xfs_qm_qoffend_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn) +{ + return; +} + +struct xfs_item_ops xfs_qm_qoffend_logitem_ops = { + iop_size: (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size, + iop_format: (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) + xfs_qm_qoff_logitem_format, + iop_pin: (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin, + iop_unpin: (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unpin, + iop_unpin_remove: (void(*)(xfs_log_item_t*,xfs_trans_t*)) + xfs_qm_qoff_logitem_unpin_remove, + iop_trylock: (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock, + iop_unlock: (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock, + iop_committed: (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_qm_qoffend_logitem_committed, + iop_push: (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push, + iop_abort: (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort, + iop_pushbuf: NULL, + iop_committing: (void(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_qm_qoffend_logitem_committing +}; + +/* + * This is the ops vector shared by all quotaoff-start log items. + */ +struct xfs_item_ops xfs_qm_qoff_logitem_ops = { + iop_size: (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size, + iop_format: (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) + xfs_qm_qoff_logitem_format, + iop_pin: (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_pin, + iop_unpin: (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unpin, + iop_unpin_remove: (void(*)(xfs_log_item_t*,xfs_trans_t*)) + xfs_qm_qoff_logitem_unpin_remove, + iop_trylock: (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_trylock, + iop_unlock: (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_unlock, + iop_committed: (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_qm_qoff_logitem_committed, + iop_push: (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push, + iop_abort: (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort, + iop_pushbuf: NULL, + iop_committing: (void(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_qm_qoff_logitem_committing +}; + +/* + * Allocate and initialize an quotaoff item of the correct quota type(s). + */ +xfs_qoff_logitem_t * +xfs_qm_qoff_logitem_init( + struct xfs_mount *mp, + xfs_qoff_logitem_t *start, + uint flags) +{ + xfs_qoff_logitem_t *qf; + + qf = (xfs_qoff_logitem_t*) kmem_zalloc(sizeof(xfs_qoff_logitem_t), KM_SLEEP); + + qf->qql_item.li_type = XFS_LI_QUOTAOFF; + if (start) + qf->qql_item.li_ops = &xfs_qm_qoffend_logitem_ops; + else + qf->qql_item.li_ops = &xfs_qm_qoff_logitem_ops; + qf->qql_item.li_mountp = mp; + qf->qql_format.qf_type = XFS_LI_QUOTAOFF; + qf->qql_format.qf_flags = flags; + qf->qql_start_lip = start; + return (qf); +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_dquot_item.h linux-2.4-xfs/linux/fs/xfs/xfs_dquot_item.h --- linux-2.4.7/linux/fs/xfs/xfs_dquot_item.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_dquot_item.h Mon Apr 2 21:52:38 2001 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_DQUOT_ITEM_H__ +#define __XFS_DQUOT_ITEM_H__ + +/* + * These are the structures used to lay out dquots and quotaoff + * records on the log. Quite similar to those of inodes. + */ + +/* + * log format struct for dquots. + * The first two fields must be the type and size fitting into + * 32 bits : log_recovery code assumes that. + */ +typedef struct xfs_dq_logformat { + __uint16_t qlf_type; /* dquot log item type */ + __uint16_t qlf_size; /* size of this item */ + xfs_dqid_t qlf_id; /* usr/grp id number : 32 bits */ + __int64_t qlf_blkno; /* blkno of dquot buffer */ + __int32_t qlf_len; /* len of dquot buffer */ + __uint32_t qlf_boffset; /* off of dquot in buffer */ +} xfs_dq_logformat_t; + +/* + * log format struct for QUOTAOFF records. + * The first two fields must be the type and size fitting into + * 32 bits : log_recovery code assumes that. + * We write two LI_QUOTAOFF logitems per quotaoff, the last one keeps a pointer + * to the first and ensures that the first logitem is taken out of the AIL + * only when the last one is securely committed. + */ +typedef struct xfs_qoff_logformat { + unsigned short qf_type; /* quotaoff log item type */ + unsigned short qf_size; /* size of this item */ + unsigned int qf_flags; /* USR and/or GRP */ + char qf_pad[12]; /* padding for future */ +} xfs_qoff_logformat_t; + + +#ifdef __KERNEL__ + +struct xfs_dquot; +struct xfs_trans; +struct xfs_mount; +typedef struct xfs_dq_logitem { + xfs_log_item_t qli_item; /* common portion */ + struct xfs_dquot *qli_dquot; /* dquot ptr */ + xfs_lsn_t qli_flush_lsn; /* lsn at last flush */ + unsigned short qli_pushbuf_flag; /* one bit used in push_ail */ +#ifdef DEBUG + uint64_t qli_push_owner; +#endif + xfs_dq_logformat_t qli_format; /* logged structure */ +} xfs_dq_logitem_t; + + +typedef struct xfs_qoff_logitem { + xfs_log_item_t qql_item; /* common portion */ + struct xfs_qoff_logitem *qql_start_lip; /* qoff-start logitem, if any */ + xfs_qoff_logformat_t qql_format; /* logged structure */ +} xfs_qoff_logitem_t; + + +extern void xfs_qm_dquot_logitem_init(struct xfs_dquot *); +extern xfs_qoff_logitem_t *xfs_qm_qoff_logitem_init(struct xfs_mount *, + xfs_qoff_logitem_t *, uint); +extern xfs_qoff_logitem_t *xfs_trans_get_qoff_item(struct xfs_trans *, + xfs_qoff_logitem_t *, uint); +extern void xfs_trans_log_quotaoff_item(struct xfs_trans *, + xfs_qoff_logitem_t *); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_DQUOT_ITEM_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_error.c linux-2.4-xfs/linux/fs/xfs/xfs_error.c --- linux-2.4.7/linux/fs/xfs/xfs_error.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_error.c Tue Apr 10 20:44:54 2001 @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +#ifdef DEBUG + +int xfs_etrap[XFS_ERROR_NTRAP] = { + 0, +}; + +int +xfs_error_trap(int e) +{ + int i; + + if (!e) + return 0; + for (i = 0; i < XFS_ERROR_NTRAP; i++) { + if (xfs_etrap[i] == 0) + break; + if (e != xfs_etrap[i]) + continue; + cmn_err(CE_NOTE, "xfs_error_trap: error %d", e); + debug_stop_all_cpus((void *)-1LL); + BUG(); + break; + } + return e; +} +#endif + +#if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) + +int xfs_etest[XFS_NUM_INJECT_ERROR]; +int64_t xfs_etest_fsid[XFS_NUM_INJECT_ERROR]; +char * xfs_etest_fsname[XFS_NUM_INJECT_ERROR]; + +void +xfs_error_test_init(void) +{ + bzero(xfs_etest, sizeof(xfs_etest)); + bzero(xfs_etest_fsid, sizeof(xfs_etest_fsid)); + bzero(xfs_etest_fsname, sizeof(xfs_etest_fsname)); +} + +int +xfs_error_test(int error_tag, int *fsidp, char *expression, + int line, char *file, unsigned long randfactor) +{ + int i; + int64_t fsid; + + if (random() % randfactor) + return 0; + + bcopy(fsidp, &fsid, sizeof(fsid_t)); + + for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { + if (xfs_etest[i] == error_tag && xfs_etest_fsid[i] == fsid) { + cmn_err(CE_WARN, + "Injecting error (%s) at file %s, line %d, on filesystem \"%s\"\n", + expression, file, line, xfs_etest_fsname[i]); + return 1; + } + } + + return 0; +} + +int +xfs_errortag_add(int error_tag, xfs_mount_t *mp) +{ + int i; + int len; + int64_t fsid; + + bcopy(mp->m_fixedfsid, &fsid, sizeof(fsid_t)); + + for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { + if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) { + cmn_err(CE_WARN, "XFS error tag #%d on", error_tag); + return 0; + } + } + + for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { + if (xfs_etest[i] == 0) { + cmn_err(CE_WARN, "Turned on XFS error tag #%d", + error_tag); + xfs_etest[i] = error_tag; + xfs_etest_fsid[i] = fsid; + len = strlen(mp->m_fsname); + xfs_etest_fsname[i] = kmem_alloc(len + 1, KM_SLEEP); + strcpy(xfs_etest_fsname[i], mp->m_fsname); + return 0; + } + } + + cmn_err(CE_WARN, "error tag overflow, too many turned on"); + + return 1; +} + +int +xfs_errortag_clear(int error_tag, xfs_mount_t *mp) +{ + int i; + int64_t fsid; + + bcopy(mp->m_fixedfsid, &fsid, sizeof(fsid_t)); + + for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { + if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) { + xfs_etest[i] = 0; + xfs_etest_fsid[i] = 0LL; + kmem_free(xfs_etest_fsname[i], + strlen(xfs_etest_fsname[i]) + 1); + xfs_etest_fsname[i] = NULL; + cmn_err(CE_WARN, "Cleared XFS error tag #%d", + error_tag); + return 0; + } + } + + cmn_err(CE_WARN, "XFS error tag %d not on", error_tag); + + return 1; +} + +int +xfs_errortag_clearall_umount(int64_t fsid, char *fsname, int loud) +{ + int i; + int cleared = 0; + + for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { + if ((fsid == 0LL || xfs_etest_fsid[i] == fsid) && + xfs_etest[i] != 0) { + cleared = 1; + cmn_err(CE_WARN, "Clearing XFS error tag #%d", + xfs_etest[i]); + xfs_etest[i] = 0; + xfs_etest_fsid[i] = 0LL; + kmem_free(xfs_etest_fsname[i], + strlen(xfs_etest_fsname[i]) + 1); + xfs_etest_fsname[i] = NULL; + } + } + + if (loud || cleared) + cmn_err(CE_WARN, + "Cleared all XFS error tags for filesystem \"%s\"", + fsname); + + return 0; +} + +int +xfs_errortag_clearall(xfs_mount_t *mp) +{ + int64_t fsid; + + bcopy(mp->m_fixedfsid, &fsid, sizeof(fsid_t)); + + return xfs_errortag_clearall_umount(fsid, mp->m_fsname, 1); +} +#endif /* DEBUG || INDUCE_IO_ERROR */ + +static void +xfs_fs_vcmn_err(int level, xfs_mount_t *mp, char *fmt, va_list ap) +{ + char *newfmt; + int len = 16 + mp->m_fsname_len + strlen(fmt); + + newfmt = kmem_alloc(len, KM_SLEEP); + sprintf(newfmt, "Filesystem \"%s\": %s", mp->m_fsname, fmt); + icmn_err(level, newfmt, ap); + kmem_free(newfmt, len); +} + +void +xfs_fs_cmn_err(int level, xfs_mount_t *mp, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + xfs_fs_vcmn_err(level, mp, fmt, ap); + va_end(ap); +} + +void +xfs_cmn_err(uint64_t panic_tag, int level, xfs_mount_t *mp, char *fmt, ...) +{ + va_list ap; + + if (xfs_panic_mask && (xfs_panic_mask & panic_tag) + && (level & CE_ALERT)) { + level &= ~CE_ALERT; + level |= CE_PANIC; + cmn_err(CE_ALERT, "Transforming an alert into a panic."); + } + va_start(ap, fmt); + xfs_fs_vcmn_err(level, mp, fmt, ap); + va_end(ap); +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_error.h linux-2.4-xfs/linux/fs/xfs/xfs_error.h --- linux-2.4.7/linux/fs/xfs/xfs_error.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_error.h Mon Mar 12 13:36:49 2001 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ERROR_H__ +#define __XFS_ERROR_H__ + +#define prdev(fmt,dev,args...) \ + printk("XFS: device 0x%x- " fmt "\n", dev, ## args) + +#define XFS_ERECOVER 1 /* Failure to recover log */ +#define XFS_ELOGSTAT 2 /* Failure to stat log in user space */ +#define XFS_ENOLOGSPACE 3 /* Reservation too large */ +#define XFS_ENOTSUP 4 /* Operation not supported */ +#define XFS_ENOLSN 5 /* Can't find the lsn you asked for */ +#define XFS_ENOTFOUND 6 +#define XFS_ENOTXFS 7 /* Not XFS filesystem */ + +#ifdef DEBUG +#define XFS_ERROR_NTRAP 10 +extern int xfs_etrap[XFS_ERROR_NTRAP]; +extern int xfs_error_trap(int); +#define XFS_ERROR(e) xfs_error_trap(e) +#else +#define XFS_ERROR(e) (e) +#endif + + +/* + * error injection tags - the labels can be anything you want + * but each tag should have its own unique number + */ + +#define XFS_ERRTAG_NOERROR 0 +#define XFS_ERRTAG_IFLUSH_1 1 +#define XFS_ERRTAG_IFLUSH_2 2 +#define XFS_ERRTAG_IFLUSH_3 3 +#define XFS_ERRTAG_IFLUSH_4 4 +#define XFS_ERRTAG_IFLUSH_5 5 +#define XFS_ERRTAG_IFLUSH_6 6 +#define XFS_ERRTAG_DA_READ_BUF 7 +#define XFS_ERRTAG_BTREE_CHECK_LBLOCK 8 +#define XFS_ERRTAG_BTREE_CHECK_SBLOCK 9 +#define XFS_ERRTAG_ALLOC_READ_AGF 10 +#define XFS_ERRTAG_IALLOC_READ_AGI 11 +#define XFS_ERRTAG_ITOBP_INOTOBP 12 +#define XFS_ERRTAG_IUNLINK 13 +#define XFS_ERRTAG_IUNLINK_REMOVE 14 +#define XFS_ERRTAG_DIR_INO_VALIDATE 15 +#define XFS_ERRTAG_BULKSTAT_READ_CHUNK 16 +#define XFS_ERRTAG_IODONE_IOERR 17 +#define XFS_ERRTAG_MAX 18 + +/* + * Random factors for above tags, 1 means always, 2 means 1/2 time, etc. + */ +#define XFS_RANDOM_DEFAULT 100 +#define XFS_RANDOM_IFLUSH_1 XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IFLUSH_2 XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IFLUSH_3 XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IFLUSH_4 XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IFLUSH_5 XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IFLUSH_6 XFS_RANDOM_DEFAULT +#define XFS_RANDOM_DA_READ_BUF XFS_RANDOM_DEFAULT +#define XFS_RANDOM_BTREE_CHECK_LBLOCK (XFS_RANDOM_DEFAULT/4) +#define XFS_RANDOM_BTREE_CHECK_SBLOCK XFS_RANDOM_DEFAULT +#define XFS_RANDOM_ALLOC_READ_AGF XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IALLOC_READ_AGI XFS_RANDOM_DEFAULT +#define XFS_RANDOM_ITOBP_INOTOBP XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IUNLINK XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IUNLINK_REMOVE XFS_RANDOM_DEFAULT +#define XFS_RANDOM_DIR_INO_VALIDATE XFS_RANDOM_DEFAULT +#define XFS_RANDOM_BULKSTAT_READ_CHUNK XFS_RANDOM_DEFAULT +#define XFS_RANDOM_IODONE_IOERR (XFS_RANDOM_DEFAULT/10) + +#if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) +extern int xfs_error_test(int, int *, char *, int, char *, unsigned long); +void xfs_error_test_init(void); + +#define XFS_NUM_INJECT_ERROR 10 + +#ifdef __ANSI_CPP__ +#define XFS_TEST_ERROR(expr, mp, tag, rf) \ + ((expr) || \ + xfs_error_test((tag), (mp)->m_fixedfsid, #expr, __LINE__, __FILE__, \ + (rf))) +#else +#define XFS_TEST_ERROR(expr, mp, tag, rf) \ + ((expr) || \ + xfs_error_test((tag), (mp)->m_fixedfsid, "expr", __LINE__, __FILE__, \ + (rf))) +#endif /* __ANSI_CPP__ */ + +int xfs_errortag_add(int error_tag, xfs_mount_t *mp); +int xfs_errortag_clear(int error_tag, xfs_mount_t *mp); + +int xfs_errortag_clearall(xfs_mount_t *mp); +int xfs_errortag_clearall_umount(int64_t fsid, char *fsname, + int loud); +#else +#define XFS_TEST_ERROR(expr, mp, tag, rf) (expr) +#endif /* (DEBUG || INDUCE_IO_ERROR) */ + +/* + * XFS panic tags -- allow a call to xfs_cmn_err() be turned into + * a panic by setting xfs_panic_mask in the + * stune file. + */ +#define XFS_NO_PTAG 0LL +#define XFS_PTAG_IFLUSH 0x0000000000000001LL +#define XFS_PTAG_LOGRES 0x0000000000000002LL +#define XFS_PTAG_AILDELETE 0x0000000000000004LL + +struct xfs_mount; +/* PRINTFLIKE4 */ +void xfs_cmn_err(uint64_t panic_tag, int level, struct xfs_mount *mp, + char *fmt, ...); +/* PRINTFLIKE3 */ +void xfs_fs_cmn_err(int level, struct xfs_mount *mp, char *fmt, ...); + +#endif /* __XFS_ERROR_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_extfree_item.c linux-2.4-xfs/linux/fs/xfs/xfs_extfree_item.c --- linux-2.4.7/linux/fs/xfs/xfs_extfree_item.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_extfree_item.c Wed Apr 11 11:27:03 2001 @@ -0,0 +1,655 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * This file contains the implementation of the xfs_efi_log_item + * and xfs_efd_log_item items. + */ + +#include + + +xfs_zone_t *xfs_efi_zone; +xfs_zone_t *xfs_efd_zone; + +STATIC void xfs_efi_item_unlock(xfs_efi_log_item_t *); +STATIC void xfs_efi_item_abort(xfs_efi_log_item_t *); +STATIC void xfs_efd_item_abort(xfs_efd_log_item_t *); + + + +/* + * This returns the number of iovecs needed to log the given efi item. + * We only need 1 iovec for an efi item. It just logs the efi_log_format + * structure. + */ +/*ARGSUSED*/ +STATIC uint +xfs_efi_item_size(xfs_efi_log_item_t *efip) +{ + return 1; +} + +/* + * This is called to fill in the vector of log iovecs for the + * given efi log item. We use only 1 iovec, and we point that + * at the efi_log_format structure embedded in the efi item. + * It is at this point that we assert that all of the extent + * slots in the efi item have been filled. + */ +STATIC void +xfs_efi_item_format(xfs_efi_log_item_t *efip, + xfs_log_iovec_t *log_vector) +{ + uint size; + + ASSERT(efip->efi_next_extent == efip->efi_format.efi_nextents); + + efip->efi_format.efi_type = XFS_LI_EFI; + + size = sizeof(xfs_efi_log_format_t); + size += (efip->efi_format.efi_nextents - 1) * sizeof(xfs_extent_t); + efip->efi_format.efi_size = 1; + + log_vector->i_addr = (xfs_caddr_t)&(efip->efi_format); + log_vector->i_len = size; + ASSERT(size >= sizeof(xfs_efi_log_format_t)); +} + + +/* + * Pinning has no meaning for an efi item, so just return. + */ +/*ARGSUSED*/ +STATIC void +xfs_efi_item_pin(xfs_efi_log_item_t *efip) +{ + return; +} + + +/* + * While EFIs cannot really be pinned, the unpin operation is the + * last place at which the EFI is manipulated during a transaction. + * Here we coordinate with xfs_efi_cancel() to determine who gets to + * free the EFI. + */ +/*ARGSUSED*/ +STATIC void +xfs_efi_item_unpin(xfs_efi_log_item_t *efip) +{ + int nexts; + int size; + xfs_mount_t *mp; + SPLDECL(s); + + mp = efip->efi_item.li_mountp; + AIL_LOCK(mp, s); + if (efip->efi_flags & XFS_EFI_CANCELED) { + /* + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); + + nexts = efip->efi_format.efi_nextents; + if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { + size = sizeof(xfs_efi_log_item_t); + size += (nexts - 1) * sizeof(xfs_extent_t); + kmem_free(efip, size); + } else { + kmem_zone_free(xfs_efi_zone, efip); + } + } else { + efip->efi_flags |= XFS_EFI_COMMITTED; + AIL_UNLOCK(mp, s); + } + + return; +} + +/* + * like unpin only we have to also clear the xaction descriptor + * pointing the log item if we free the item. This routine duplicates + * unpin because efi_flags is protected by the AIL lock. Freeing + * the descriptor and then calling unpin would force us to drop the AIL + * lock which would open up a race condition. + */ +STATIC void +xfs_efi_item_unpin_remove(xfs_efi_log_item_t *efip, xfs_trans_t *tp) +{ + int nexts; + int size; + xfs_mount_t *mp; + xfs_log_item_desc_t *lidp; + SPLDECL(s); + + mp = efip->efi_item.li_mountp; + AIL_LOCK(mp, s); + if (efip->efi_flags & XFS_EFI_CANCELED) { + /* + * free the xaction descriptor pointing to this item + */ + lidp = xfs_trans_find_item(tp, (xfs_log_item_t *) efip); + xfs_trans_free_item(tp, lidp); + /* + * pull the item off the AIL. + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); + /* + * now free the item itself + */ + nexts = efip->efi_format.efi_nextents; + if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { + size = sizeof(xfs_efi_log_item_t); + size += (nexts - 1) * sizeof(xfs_extent_t); + kmem_free(efip, size); + } else { + kmem_zone_free(xfs_efi_zone, efip); + } + } else { + efip->efi_flags |= XFS_EFI_COMMITTED; + AIL_UNLOCK(mp, s); + } + + return; +} + +/* + * Efi items have no locking or pushing. However, since EFIs are + * pulled from the AIL when their corresponding EFDs are committed + * to disk, their situation is very similar to being pinned. Return + * XFS_ITEM_PINNED so that the caller will eventually flush the log. + * This should help in getting the EFI out of the AIL. + */ +/*ARGSUSED*/ +STATIC uint +xfs_efi_item_trylock(xfs_efi_log_item_t *efip) +{ + return XFS_ITEM_PINNED; +} + +/* + * Efi items have no locking, so just return. + */ +/*ARGSUSED*/ +STATIC void +xfs_efi_item_unlock(xfs_efi_log_item_t *efip) +{ + if (efip->efi_item.li_flags & XFS_LI_ABORTED) + xfs_efi_item_abort(efip); + return; +} + +/* + * The EFI is logged only once and cannot be moved in the log, so + * simply return the lsn at which it's been logged. The canceled + * flag is not paid any attention here. Checking for that is delayed + * until the EFI is unpinned. + */ +/*ARGSUSED*/ +STATIC xfs_lsn_t +xfs_efi_item_committed(xfs_efi_log_item_t *efip, xfs_lsn_t lsn) +{ + return lsn; +} + +/* + * This is called when the transaction logging the EFI is aborted. + * Free up the EFI and return. No need to clean up the slot for + * the item in the transaction. That was done by the unpin code + * which is called prior to this routine in the abort/fs-shutdown path. + */ +STATIC void +xfs_efi_item_abort(xfs_efi_log_item_t *efip) +{ + int nexts; + int size; + + nexts = efip->efi_format.efi_nextents; + if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { + size = sizeof(xfs_efi_log_item_t); + size += (nexts - 1) * sizeof(xfs_extent_t); + kmem_free(efip, size); + } else { + kmem_zone_free(xfs_efi_zone, efip); + } + return; +} + +/* + * There isn't much you can do to push on an efi item. It is simply + * stuck waiting for all of its corresponding efd items to be + * committed to disk. + */ +/*ARGSUSED*/ +STATIC void +xfs_efi_item_push(xfs_efi_log_item_t *efip) +{ + return; +} + +/* + * The EFI dependency tracking op doesn't do squat. It can't because + * it doesn't know where the free extent is coming from. The dependency + * tracking has to be handled by the "enclosing" metadata object. For + * example, for inodes, the inode is locked throughout the extent freeing + * so the dependency should be recorded there. + */ +/*ARGSUSED*/ +STATIC void +xfs_efi_item_committing(xfs_efi_log_item_t *efip, xfs_lsn_t lsn) +{ + return; +} + +/* + * This is the ops vector shared by all efi log items. + */ +struct xfs_item_ops xfs_efi_item_ops = { + iop_size: (uint(*)(xfs_log_item_t*))xfs_efi_item_size, + iop_format: (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) + xfs_efi_item_format, + iop_pin: (void(*)(xfs_log_item_t*))xfs_efi_item_pin, + iop_unpin: (void(*)(xfs_log_item_t*))xfs_efi_item_unpin, + iop_unpin_remove: (void(*)(xfs_log_item_t*, xfs_trans_t *)) + xfs_efi_item_unpin_remove, + iop_trylock: (uint(*)(xfs_log_item_t*))xfs_efi_item_trylock, + iop_unlock: (void(*)(xfs_log_item_t*))xfs_efi_item_unlock, + iop_committed: (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_efi_item_committed, + iop_push: (void(*)(xfs_log_item_t*))xfs_efi_item_push, + iop_abort: (void(*)(xfs_log_item_t*))xfs_efi_item_abort, + iop_pushbuf: NULL, + iop_committing: (void(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_efi_item_committing +}; + + +/* + * Allocate and initialize an efi item with the given number of extents. + */ +xfs_efi_log_item_t * +xfs_efi_init(xfs_mount_t *mp, + uint nextents) + +{ + xfs_efi_log_item_t *efip; + uint size; + + ASSERT(nextents > 0); + if (nextents > XFS_EFI_MAX_FAST_EXTENTS) { + size = (uint)(sizeof(xfs_efi_log_item_t) + + ((nextents - 1) * sizeof(xfs_extent_t))); + efip = (xfs_efi_log_item_t*)kmem_zalloc(size, KM_SLEEP); + } else { + efip = (xfs_efi_log_item_t*)kmem_zone_zalloc(xfs_efi_zone, + KM_SLEEP); + } + + efip->efi_item.li_type = XFS_LI_EFI; + efip->efi_item.li_ops = &xfs_efi_item_ops; + efip->efi_item.li_mountp = mp; + efip->efi_format.efi_nextents = nextents; + efip->efi_format.efi_id = (__psint_t)(void*)efip; + + return (efip); +} + +/* + * This is called by the efd item code below to release references to + * the given efi item. Each efd calls this with the number of + * extents that it has logged, and when the sum of these reaches + * the total number of extents logged by this efi item we can free + * the efi item. + * + * Freeing the efi item requires that we remove it from the AIL. + * We'll use the AIL lock to protect our counters as well as + * the removal from the AIL. + */ +void +xfs_efi_release(xfs_efi_log_item_t *efip, + uint nextents) +{ + xfs_mount_t *mp; + int extents_left; + uint size; + int nexts; + SPLDECL(s); + + mp = efip->efi_item.li_mountp; + ASSERT(efip->efi_next_extent > 0); + ASSERT(efip->efi_flags & XFS_EFI_COMMITTED); + + AIL_LOCK(mp, s); + ASSERT(efip->efi_next_extent >= nextents); + efip->efi_next_extent -= nextents; + extents_left = efip->efi_next_extent; + if (extents_left == 0) { + /* + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); + } else { + AIL_UNLOCK(mp, s); + } + + if (extents_left == 0) { + nexts = efip->efi_format.efi_nextents; + if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { + size = sizeof(xfs_efi_log_item_t); + size += (nexts - 1) * sizeof(xfs_extent_t); + kmem_free(efip, size); + } else { + kmem_zone_free(xfs_efi_zone, efip); + } + } +} + +/* + * This is called when the transaction that should be committing the + * EFD corresponding to the given EFI is aborted. The committed and + * canceled flags are used to coordinate the freeing of the EFI and + * the references by the transaction that committed it. + */ +STATIC void +xfs_efi_cancel( + xfs_efi_log_item_t *efip) +{ + int nexts; + int size; + xfs_mount_t *mp; + SPLDECL(s); + + mp = efip->efi_item.li_mountp; + AIL_LOCK(mp, s); + if (efip->efi_flags & XFS_EFI_COMMITTED) { + /* + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s); + + nexts = efip->efi_format.efi_nextents; + if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { + size = sizeof(xfs_efi_log_item_t); + size += (nexts - 1) * sizeof(xfs_extent_t); + kmem_free(efip, size); + } else { + kmem_zone_free(xfs_efi_zone, efip); + } + } else { + efip->efi_flags |= XFS_EFI_CANCELED; + AIL_UNLOCK(mp, s); + } + + return; +} + + + + + +/* + * This returns the number of iovecs needed to log the given efd item. + * We only need 1 iovec for an efd item. It just logs the efd_log_format + * structure. + */ +/*ARGSUSED*/ +STATIC uint +xfs_efd_item_size(xfs_efd_log_item_t *efdp) +{ + return 1; +} + +/* + * This is called to fill in the vector of log iovecs for the + * given efd log item. We use only 1 iovec, and we point that + * at the efd_log_format structure embedded in the efd item. + * It is at this point that we assert that all of the extent + * slots in the efd item have been filled. + */ +STATIC void +xfs_efd_item_format(xfs_efd_log_item_t *efdp, + xfs_log_iovec_t *log_vector) +{ + uint size; + + ASSERT(efdp->efd_next_extent == efdp->efd_format.efd_nextents); + + efdp->efd_format.efd_type = XFS_LI_EFD; + + size = sizeof(xfs_efd_log_format_t); + size += (efdp->efd_format.efd_nextents - 1) * sizeof(xfs_extent_t); + efdp->efd_format.efd_size = 1; + + log_vector->i_addr = (xfs_caddr_t)&(efdp->efd_format); + log_vector->i_len = size; + ASSERT(size >= sizeof(xfs_efd_log_format_t)); +} + + +/* + * Pinning has no meaning for an efd item, so just return. + */ +/*ARGSUSED*/ +STATIC void +xfs_efd_item_pin(xfs_efd_log_item_t *efdp) +{ + return; +} + + +/* + * Since pinning has no meaning for an efd item, unpinning does + * not either. + */ +/*ARGSUSED*/ +STATIC void +xfs_efd_item_unpin(xfs_efd_log_item_t *efdp) +{ + return; +} + +/*ARGSUSED*/ +STATIC void +xfs_efd_item_unpin_remove(xfs_efd_log_item_t *efdp, xfs_trans_t *tp) +{ + return; +} + +/* + * Efd items have no locking, so just return success. + */ +/*ARGSUSED*/ +STATIC uint +xfs_efd_item_trylock(xfs_efd_log_item_t *efdp) +{ + return XFS_ITEM_LOCKED; +} + +/* + * Efd items have no locking or pushing, so return failure + * so that the caller doesn't bother with us. + */ +/*ARGSUSED*/ +STATIC void +xfs_efd_item_unlock(xfs_efd_log_item_t *efdp) +{ + if (efdp->efd_item.li_flags & XFS_LI_ABORTED) + xfs_efd_item_abort(efdp); + return; +} + +/* + * When the efd item is committed to disk, all we need to do + * is delete our reference to our partner efi item and then + * free ourselves. Since we're freeing ourselves we must + * return -1 to keep the transaction code from further referencing + * this item. + */ +/*ARGSUSED*/ +STATIC xfs_lsn_t +xfs_efd_item_committed(xfs_efd_log_item_t *efdp, xfs_lsn_t lsn) +{ + uint size; + int nexts; + + /* + * If we got a log I/O error, it's always the case that the LR with the + * EFI got unpinned and freed before the EFD got aborted. + */ + if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0) + xfs_efi_release(efdp->efd_efip, efdp->efd_format.efd_nextents); + + nexts = efdp->efd_format.efd_nextents; + if (nexts > XFS_EFD_MAX_FAST_EXTENTS) { + size = sizeof(xfs_efd_log_item_t); + size += (nexts - 1) * sizeof(xfs_extent_t); + kmem_free(efdp, size); + } else { + kmem_zone_free(xfs_efd_zone, efdp); + } + + return (xfs_lsn_t)-1; +} + +/* + * The transaction of which this EFD is a part has been aborted. + * Inform its companion EFI of this fact and then clean up after + * ourselves. No need to clean up the slot for the item in the + * transaction. That was done by the unpin code which is called + * prior to this routine in the abort/fs-shutdown path. + */ +STATIC void +xfs_efd_item_abort(xfs_efd_log_item_t *efdp) +{ + int nexts; + int size; + + /* + * If we got a log I/O error, it's always the case that the LR with the + * EFI got unpinned and freed before the EFD got aborted. So don't + * reference the EFI at all in that case. + */ + if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0) + xfs_efi_cancel(efdp->efd_efip); + + nexts = efdp->efd_format.efd_nextents; + if (nexts > XFS_EFD_MAX_FAST_EXTENTS) { + size = sizeof(xfs_efd_log_item_t); + size += (nexts - 1) * sizeof(xfs_extent_t); + kmem_free(efdp, size); + } else { + kmem_zone_free(xfs_efd_zone, efdp); + } + return; +} + +/* + * There isn't much you can do to push on an efd item. It is simply + * stuck waiting for the log to be flushed to disk. + */ +/*ARGSUSED*/ +STATIC void +xfs_efd_item_push(xfs_efd_log_item_t *efdp) +{ + return; +} + +/* + * The EFD dependency tracking op doesn't do squat. It can't because + * it doesn't know where the free extent is coming from. The dependency + * tracking has to be handled by the "enclosing" metadata object. For + * example, for inodes, the inode is locked throughout the extent freeing + * so the dependency should be recorded there. + */ +/*ARGSUSED*/ +STATIC void +xfs_efd_item_committing(xfs_efd_log_item_t *efip, xfs_lsn_t lsn) +{ + return; +} + +/* + * This is the ops vector shared by all efd log items. + */ +struct xfs_item_ops xfs_efd_item_ops = { + iop_size: (uint(*)(xfs_log_item_t*))xfs_efd_item_size, + iop_format: (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) + xfs_efd_item_format, + iop_pin: (void(*)(xfs_log_item_t*))xfs_efd_item_pin, + iop_unpin: (void(*)(xfs_log_item_t*))xfs_efd_item_unpin, + iop_unpin_remove: (void(*)(xfs_log_item_t*, xfs_trans_t*)) + xfs_efd_item_unpin_remove, + iop_trylock: (uint(*)(xfs_log_item_t*))xfs_efd_item_trylock, + iop_unlock: (void(*)(xfs_log_item_t*))xfs_efd_item_unlock, + iop_committed: (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_efd_item_committed, + iop_push: (void(*)(xfs_log_item_t*))xfs_efd_item_push, + iop_abort: (void(*)(xfs_log_item_t*))xfs_efd_item_abort, + iop_pushbuf: NULL, + iop_committing: (void(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_efd_item_committing +}; + + +/* + * Allocate and initialize an efd item with the given number of extents. + */ +xfs_efd_log_item_t * +xfs_efd_init(xfs_mount_t *mp, + xfs_efi_log_item_t *efip, + uint nextents) + +{ + xfs_efd_log_item_t *efdp; + uint size; + + ASSERT(nextents > 0); + if (nextents > XFS_EFD_MAX_FAST_EXTENTS) { + size = (uint)(sizeof(xfs_efd_log_item_t) + + ((nextents - 1) * sizeof(xfs_extent_t))); + efdp = (xfs_efd_log_item_t*)kmem_zalloc(size, KM_SLEEP); + } else { + efdp = (xfs_efd_log_item_t*)kmem_zone_zalloc(xfs_efd_zone, + KM_SLEEP); + } + + efdp->efd_item.li_type = XFS_LI_EFD; + efdp->efd_item.li_ops = &xfs_efd_item_ops; + efdp->efd_item.li_mountp = mp; + efdp->efd_efip = efip; + efdp->efd_format.efd_nextents = nextents; + efdp->efd_format.efd_efi_id = efip->efi_format.efi_id; + + return (efdp); +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_extfree_item.h linux-2.4-xfs/linux/fs/xfs/xfs_extfree_item.h --- linux-2.4.7/linux/fs/xfs/xfs_extfree_item.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_extfree_item.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_EXTFREE_ITEM_H__ +#define __XFS_EXTFREE_ITEM_H__ + +struct xfs_mount; +struct xfs_zone; + +typedef struct xfs_extent { + xfs_dfsbno_t ext_start; + xfs_extlen_t ext_len; +} xfs_extent_t; + +/* + * This is the structure used to lay out an efi log item in the + * log. The efi_extents field is a variable size array whose + * size is given by efi_nextents. + */ +typedef struct xfs_efi_log_format { + unsigned short efi_type; /* efi log item type */ + unsigned short efi_size; /* size of this item */ + uint efi_nextents; /* # extents to free */ + __uint64_t efi_id; /* efi identifier */ + xfs_extent_t efi_extents[1]; /* array of extents to free */ +} xfs_efi_log_format_t; + +/* + * This is the structure used to lay out an efd log item in the + * log. The efd_extents array is a variable size array whose + * size is given by efd_nextents; + */ +typedef struct xfs_efd_log_format { + unsigned short efd_type; /* efd log item type */ + unsigned short efd_size; /* size of this item */ + uint efd_nextents; /* # of extents freed */ + __uint64_t efd_efi_id; /* id of corresponding efi */ + xfs_extent_t efd_extents[1]; /* array of extents freed */ +} xfs_efd_log_format_t; + + +#ifdef __KERNEL__ + +/* + * Max number of extents in fast allocation path. + */ +#define XFS_EFI_MAX_FAST_EXTENTS 16 + +/* + * Define EFI flags. + */ +#define XFS_EFI_RECOVERED 0x1 +#define XFS_EFI_COMMITTED 0x2 +#define XFS_EFI_CANCELED 0x4 + +/* + * This is the "extent free intention" log item. It is used + * to log the fact that some extents need to be free. It is + * used in conjunction with the "extent free done" log item + * described below. + */ +typedef struct xfs_efi_log_item { + xfs_log_item_t efi_item; + uint efi_flags; /* misc flags */ + uint efi_next_extent; + xfs_efi_log_format_t efi_format; +} xfs_efi_log_item_t; + +/* + * This is the "extent free done" log item. It is used to log + * the fact that some extents earlier mentioned in an efi item + * have been freed. + */ +typedef struct xfs_efd_log_item { + xfs_log_item_t efd_item; + xfs_efi_log_item_t *efd_efip; + uint efd_next_extent; + xfs_efd_log_format_t efd_format; +} xfs_efd_log_item_t; + +/* + * Max number of extents in fast allocation path. + */ +#define XFS_EFD_MAX_FAST_EXTENTS 16 + +extern struct xfs_zone *xfs_efi_zone; +extern struct xfs_zone *xfs_efd_zone; + +xfs_efi_log_item_t *xfs_efi_init(struct xfs_mount *, uint); +xfs_efd_log_item_t *xfs_efd_init(struct xfs_mount *, xfs_efi_log_item_t *, + uint); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_EXTFREE_ITEM_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_fsops.c linux-2.4-xfs/linux/fs/xfs/xfs_fsops.c --- linux-2.4.7/linux/fs/xfs/xfs_fsops.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_fsops.c Tue Apr 10 20:44:54 2001 @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * File system operations + */ + +int +xfs_fs_geometry( + xfs_mount_t *mp, + xfs_fsop_geom_t *geo, + int new_version) +{ + geo->blocksize = mp->m_sb.sb_blocksize; + geo->rtextsize = mp->m_sb.sb_rextsize; + geo->agblocks = mp->m_sb.sb_agblocks; + geo->agcount = mp->m_sb.sb_agcount; + geo->logblocks = mp->m_sb.sb_logblocks; + geo->sectsize = mp->m_sb.sb_sectsize; + geo->inodesize = mp->m_sb.sb_inodesize; + geo->imaxpct = mp->m_sb.sb_imax_pct; + geo->datablocks = mp->m_sb.sb_dblocks; + geo->rtblocks = mp->m_sb.sb_rblocks; + geo->rtextents = mp->m_sb.sb_rextents; + geo->logstart = mp->m_sb.sb_logstart; + ASSERT(sizeof(geo->uuid)==sizeof(mp->m_sb.sb_uuid)); + memcpy(geo->uuid, &mp->m_sb.sb_uuid, sizeof(mp->m_sb.sb_uuid)); + if (new_version >= 2) { + geo->sunit = mp->m_sb.sb_unit; + geo->swidth = mp->m_sb.sb_width; + } + if (new_version >= 3) { + geo->version = XFS_FSOP_GEOM_VERSION; + geo->flags = + (XFS_SB_VERSION_HASATTR(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_ATTR : 0) | + (XFS_SB_VERSION_HASNLINK(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_NLINK : 0) | + (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_QUOTA : 0) | + (XFS_SB_VERSION_HASALIGN(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_IALIGN : 0) | + (XFS_SB_VERSION_HASDALIGN(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_DALIGN : 0) | + (XFS_SB_VERSION_HASSHARED(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_SHARED : 0) | + (XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_EXTFLG : 0) | + (XFS_SB_VERSION_HASDIRV2(&mp->m_sb) ? + XFS_FSOP_GEOM_FLAGS_DIRV2 : 0); + geo->logsectsize = mp->m_sb.sb_sectsize; /* XXX */ + geo->rtsectsize = mp->m_sb.sb_sectsize; /* XXX */ + geo->dirblocksize = mp->m_dirblksize; + } + return 0; +} + +static int +xfs_growfs_data_private( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_growfs_data_t *in) /* growfs data input struct */ +{ + xfs_agf_t *agf; + xfs_agi_t *agi; + xfs_agnumber_t agno; + xfs_extlen_t agsize; + xfs_extlen_t tmpsize; + xfs_alloc_rec_t *arec; + xfs_btree_sblock_t *block; + xfs_buf_t *bp; + int bsize; + int bucket; + int dpct; + int error; + xfs_agnumber_t nagcount; + xfs_rfsblock_t nb, nb_mod; + xfs_rfsblock_t new; + xfs_rfsblock_t nfree; + xfs_agnumber_t oagcount; + int pct; + xfs_sb_t *sbp; + int sectbb; + xfs_trans_t *tp; + + nb = in->newblocks; + pct = in->imaxpct; + if (nb < mp->m_sb.sb_dblocks || pct < 0 || pct > 100) + return XFS_ERROR(EINVAL); + dpct = pct - mp->m_sb.sb_imax_pct; + error = xfs_read_buf(mp, mp->m_ddev_targp, XFS_FSB_TO_BB(mp, nb) - 1, 1, + 0, &bp); + if (error) + return error; + ASSERT(bp); + xfs_buf_relse(bp); + + new = nb; /* use new as a temporary here */ + nb_mod = do_div(new, mp->m_sb.sb_agblocks); + nagcount = new + (nb_mod != 0); + if (nb_mod && nb_mod < XFS_MIN_AG_BLOCKS) { + nagcount--; + nb = nagcount * mp->m_sb.sb_agblocks; + if (nb < mp->m_sb.sb_dblocks) + return XFS_ERROR(EINVAL); + } + new = in->newblocks - mp->m_sb.sb_dblocks; + oagcount = mp->m_sb.sb_agcount; + if (nagcount > oagcount) { + mrlock(&mp->m_peraglock, MR_UPDATE, PINOD); + mp->m_perag = kmem_realloc(mp->m_perag, + sizeof(xfs_perag_t) * nagcount, + sizeof(xfs_perag_t) * oagcount, + KM_SLEEP); + bzero(&mp->m_perag[oagcount], + (nagcount - oagcount) * sizeof(xfs_perag_t)); + mrunlock(&mp->m_peraglock); + } + tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS); + if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp), + XFS_GROWDATA_LOG_RES(mp), 0, 0, 0))) { + xfs_trans_cancel(tp, 0); + return error; + } + /* new ag's */ + sectbb = BTOBB(mp->m_sb.sb_sectsize); + bsize = mp->m_sb.sb_blocksize; + + nfree = 0; + for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) { + /* + * AG freelist header block + */ + bp = xfs_buf_get(mp->m_ddev_targp, + XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR), + sectbb, 0); + agf = XFS_BUF_TO_AGF(bp); + bzero(agf, mp->m_sb.sb_sectsize); + INT_SET(agf->agf_magicnum, ARCH_CONVERT, XFS_AGF_MAGIC); + INT_SET(agf->agf_versionnum, ARCH_CONVERT, XFS_AGF_VERSION); + INT_SET(agf->agf_seqno, ARCH_CONVERT, agno); + if (agno == nagcount - 1) + agsize = + nb - + (agno * (xfs_rfsblock_t)mp->m_sb.sb_agblocks); + else + agsize = mp->m_sb.sb_agblocks; + INT_SET(agf->agf_length, ARCH_CONVERT, agsize); + INT_SET(agf->agf_roots[XFS_BTNUM_BNOi], ARCH_CONVERT, XFS_BNO_BLOCK(mp)); + INT_SET(agf->agf_roots[XFS_BTNUM_CNTi], ARCH_CONVERT, XFS_CNT_BLOCK(mp)); + INT_SET(agf->agf_levels[XFS_BTNUM_BNOi], ARCH_CONVERT, 1); + INT_SET(agf->agf_levels[XFS_BTNUM_CNTi], ARCH_CONVERT, 1); + INT_SET(agf->agf_flfirst, ARCH_CONVERT, 0); + INT_SET(agf->agf_fllast, ARCH_CONVERT, XFS_AGFL_SIZE - 1); + INT_SET(agf->agf_flcount, ARCH_CONVERT, 0); + tmpsize = agsize - XFS_PREALLOC_BLOCKS(mp); + INT_SET(agf->agf_freeblks, ARCH_CONVERT, tmpsize); + INT_SET(agf->agf_longest, ARCH_CONVERT, tmpsize); + error = xfs_bwrite(mp, bp); + if (error) { + goto error0; + } + /* + * AG inode header block + */ + bp = xfs_buf_get(mp->m_ddev_targp, + XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR), + sectbb, 0); + agi = XFS_BUF_TO_AGI(bp); + bzero(agi, mp->m_sb.sb_sectsize); + INT_SET(agi->agi_magicnum, ARCH_CONVERT, XFS_AGI_MAGIC); + INT_SET(agi->agi_versionnum, ARCH_CONVERT, XFS_AGI_VERSION); + INT_SET(agi->agi_seqno, ARCH_CONVERT, agno); + INT_SET(agi->agi_length, ARCH_CONVERT, agsize); + INT_SET(agi->agi_count, ARCH_CONVERT, 0); + INT_SET(agi->agi_root, ARCH_CONVERT, XFS_IBT_BLOCK(mp)); + INT_SET(agi->agi_level, ARCH_CONVERT, 1); + INT_SET(agi->agi_freecount, ARCH_CONVERT, 0); + INT_SET(agi->agi_newino, ARCH_CONVERT, NULLAGINO); + INT_SET(agi->agi_dirino, ARCH_CONVERT, NULLAGINO); + for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) + INT_SET(agi->agi_unlinked[bucket], ARCH_CONVERT, NULLAGINO); + error = xfs_bwrite(mp, bp); + if (error) { + goto error0; + } + /* + * BNO btree root block + */ + bp = xfs_buf_get(mp->m_ddev_targp, + XFS_AGB_TO_DADDR(mp, agno, XFS_BNO_BLOCK(mp)), + BTOBB(bsize), 0); + block = XFS_BUF_TO_SBLOCK(bp); + bzero(block, bsize); + INT_SET(block->bb_magic, ARCH_CONVERT, XFS_ABTB_MAGIC); + INT_SET(block->bb_level, ARCH_CONVERT, 0); + INT_SET(block->bb_numrecs, ARCH_CONVERT, 1); + INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + arec = XFS_BTREE_REC_ADDR(bsize, xfs_alloc, block, 1, + mp->m_alloc_mxr[0]); + INT_SET(arec->ar_startblock, ARCH_CONVERT, XFS_PREALLOC_BLOCKS(mp)); + INT_SET(arec->ar_blockcount, ARCH_CONVERT, agsize - INT_GET(arec->ar_startblock, ARCH_CONVERT)); + error = xfs_bwrite(mp, bp); + if (error) { + goto error0; + } + /* + * CNT btree root block + */ + bp = xfs_buf_get(mp->m_ddev_targp, + XFS_AGB_TO_DADDR(mp, agno, XFS_CNT_BLOCK(mp)), + BTOBB(bsize), 0); + block = XFS_BUF_TO_SBLOCK(bp); + bzero(block, bsize); + INT_SET(block->bb_magic, ARCH_CONVERT, XFS_ABTC_MAGIC); + INT_SET(block->bb_level, ARCH_CONVERT, 0); + INT_SET(block->bb_numrecs, ARCH_CONVERT, 1); + INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + arec = XFS_BTREE_REC_ADDR(bsize, xfs_alloc, block, 1, + mp->m_alloc_mxr[0]); + INT_SET(arec->ar_startblock, ARCH_CONVERT, XFS_PREALLOC_BLOCKS(mp)); + INT_SET(arec->ar_blockcount, ARCH_CONVERT, agsize - INT_GET(arec->ar_startblock, ARCH_CONVERT)); + nfree += INT_GET(arec->ar_blockcount, ARCH_CONVERT); + error = xfs_bwrite(mp, bp); + if (error) { + goto error0; + } + /* + * INO btree root block + */ + bp = xfs_buf_get(mp->m_ddev_targp, + XFS_AGB_TO_DADDR(mp, agno, XFS_IBT_BLOCK(mp)), + BTOBB(bsize), 0); + block = XFS_BUF_TO_SBLOCK(bp); + bzero(block, bsize); + INT_SET(block->bb_magic, ARCH_CONVERT, XFS_IBT_MAGIC); + INT_SET(block->bb_level, ARCH_CONVERT, 0); + INT_SET(block->bb_numrecs, ARCH_CONVERT, 0); + INT_SET(block->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(block->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + error = xfs_bwrite(mp, bp); + if (error) { + goto error0; + } + } + xfs_trans_agblocks_delta(tp, nfree); + /* + * There are new blocks in the old last a.g. + */ + if (new) { + /* + * Change the agi length. + */ + error = xfs_ialloc_read_agi(mp, tp, agno, &bp); + if (error) { + goto error0; + } + ASSERT(bp); + agi = XFS_BUF_TO_AGI(bp); + INT_MOD(agi->agi_length, ARCH_CONVERT, new); + ASSERT(nagcount == oagcount + || INT_GET(agi->agi_length, ARCH_CONVERT) == mp->m_sb.sb_agblocks); + xfs_ialloc_log_agi(tp, bp, XFS_AGI_LENGTH); + /* + * Change agf length. + */ + error = xfs_alloc_read_agf(mp, tp, agno, 0, &bp); + if (error) { + goto error0; + } + ASSERT(bp); + agf = XFS_BUF_TO_AGF(bp); + INT_MOD(agf->agf_length, ARCH_CONVERT, new); + ASSERT(INT_GET(agf->agf_length, ARCH_CONVERT) == + INT_GET(agi->agi_length, ARCH_CONVERT)); + /* + * Free the new space. + */ + error = xfs_free_extent(tp, XFS_AGB_TO_FSB(mp, agno, + INT_GET(agf->agf_length, ARCH_CONVERT) - new), new); + if (error) { + goto error0; + } + } + if (nagcount > oagcount) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount); + if (nb > mp->m_sb.sb_dblocks) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS, + nb - mp->m_sb.sb_dblocks); + if (nfree) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, nfree); + if (dpct) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct); + error = xfs_trans_commit(tp, 0, NULL); + if (error) { + return error; + } + if (mp->m_sb.sb_imax_pct) { + __uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct; + do_div(icount, 100); + mp->m_maxicount = icount << mp->m_sb.sb_inopblog; + } else + mp->m_maxicount = 0; + for (agno = 1; agno < nagcount; agno++) { + error = xfs_read_buf(mp, mp->m_ddev_targp, + XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), + sectbb, 0, &bp); + if (error) { + xfs_fs_cmn_err(CE_WARN, mp, + "error %d reading secondary superblock for ag %d\n", + error, agno); + break; + } + sbp = XFS_BUF_TO_SBP(bp); + xfs_xlatesb(sbp, &mp->m_sb, -1, ARCH_CONVERT, XFS_SB_ALL_BITS); + /* + * If we get an error writing out the alternate superblocks, + * just issue a warning and continue. The real work is + * already done and committed. + */ + if (!(error = xfs_bwrite(mp, bp))) { + continue; + } else { + xfs_fs_cmn_err(CE_WARN, mp, + "write error %d updating secondary superblock for ag %d\n", + error, agno); + break; /* no point in continuing */ + } + } + return 0; + + error0: + xfs_trans_cancel(tp, XFS_TRANS_ABORT); + return error; +} + +static int +xfs_growfs_log_private( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_growfs_log_t *in) /* growfs log input struct */ +{ + xfs_extlen_t nb; + + nb = in->newblocks; + if (nb < XFS_MIN_LOG_BLOCKS || nb < XFS_B_TO_FSB(mp, XFS_MIN_LOG_BYTES)) + return XFS_ERROR(EINVAL); + if (nb == mp->m_sb.sb_logblocks && + in->isint == (mp->m_sb.sb_logstart != 0)) + return XFS_ERROR(EINVAL); + /* + * Moving the log is hard, need new interfaces to sync + * the log first, hold off all activity while moving it. + * Can have shorter or longer log in the same space, + * or transform internal to external log or vice versa. + */ + return XFS_ERROR(ENOSYS); +} + +/* + * protected versions of growfs function acquire and release locks on the mount + * point - exported through ioctls: XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG, + * XFS_IOC_FSGROWFSRT + */ + + +int +xfs_growfs_data( + xfs_mount_t *mp, + xfs_growfs_data_t *in) +{ + int error; + if (!cpsema(&mp->m_growlock)) + return XFS_ERROR(EWOULDBLOCK); + error = xfs_growfs_data_private(mp, in); + vsema(&mp->m_growlock); + return error; +} + +int +xfs_growfs_log( + xfs_mount_t *mp, + xfs_growfs_log_t *in) +{ + int error; + if (!cpsema(&mp->m_growlock)) + return XFS_ERROR(EWOULDBLOCK); + error = xfs_growfs_log_private(mp, in); + vsema(&mp->m_growlock); + return error; +} + +/* + * exported through ioctl XFS_IOC_FSCOUNTS + */ + +int +xfs_fs_counts( + xfs_mount_t *mp, + xfs_fsop_counts_t *cnt) +{ + int s; + + s = XFS_SB_LOCK(mp); + cnt->freedata = mp->m_sb.sb_fdblocks; + cnt->freertx = mp->m_sb.sb_frextents; + cnt->freeino = mp->m_sb.sb_ifree; + cnt->allocino = mp->m_sb.sb_icount; + XFS_SB_UNLOCK(mp, s); + return 0; +} + +/* + * exported through ioctl XFS_IOC_SET_RESBLKS & XFS_IOC_GET_RESBLKS + * + * xfs_reserve_blocks is called to set m_resblks + * in the in-core mount table. The number of unused reserved blocks + * is kept in m_resbls_avail. + * + * Reserve the requested number of blocks if available. Otherwise return + * as many as possible to satisfy the request. The actual number + * reserved are returned in outval + * + * A null inval pointer indicates that only the current reserved blocks + * available should be returned no settings are changed. + */ + +int +xfs_reserve_blocks( + xfs_mount_t *mp, + __uint64_t *inval, + xfs_fsop_resblks_t *outval) +{ + __uint64_t lcounter, delta; + __uint64_t request; + int s; + + /* If inval is null, report current values and return */ + + if (inval == (__uint64_t *)NULL) { + outval->resblks = mp->m_resblks; + outval->resblks_avail = mp->m_resblks_avail; + return(0); + } + + request = *inval; + s = XFS_SB_LOCK(mp); + + /* + * If our previous reservation was larger than the current value, + * then move any unused blocks back to the free pool. + */ + + if (mp->m_resblks > request) { + lcounter = mp->m_resblks_avail - request; + if (lcounter > 0) { /* release unused blocks */ + mp->m_sb.sb_fdblocks += lcounter; + mp->m_resblks_avail -= lcounter; + } + mp->m_resblks = request; + } else { + delta = request - mp->m_resblks; + lcounter = mp->m_sb.sb_fdblocks; + lcounter -= delta; + if (lcounter < 0) { + /* We can't satisfy the request, just get what we can */ + mp->m_resblks += mp->m_sb.sb_fdblocks; + mp->m_resblks_avail += mp->m_sb.sb_fdblocks; + mp->m_sb.sb_fdblocks = 0; + } else { + mp->m_sb.sb_fdblocks = lcounter; + mp->m_resblks = request; + mp->m_resblks_avail += delta; + } + } + + outval->resblks = mp->m_resblks; + outval->resblks_avail = mp->m_resblks_avail; + XFS_SB_UNLOCK(mp, s); + return(0); +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_fsops.h linux-2.4-xfs/linux/fs/xfs/xfs_fsops.h --- linux-2.4.7/linux/fs/xfs/xfs_fsops.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_fsops.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_FSOPS_H__ +#define __XFS_FSOPS_H__ + +int +xfs_fs_geometry( + xfs_mount_t *mp, + xfs_fsop_geom_t *geo, + int new_version); + +int +xfs_growfs_data( + xfs_mount_t *mp, + xfs_growfs_data_t *in); + +int +xfs_growfs_log( + xfs_mount_t *mp, + xfs_growfs_log_t *in); + +int +xfs_growfs_rt( + xfs_mount_t *mp, + xfs_growfs_rt_t *in); + +int +xfs_fs_counts( + xfs_mount_t *mp, + xfs_fsop_counts_t *cnt); + +int +xfs_reserve_blocks( + xfs_mount_t *mp, + __uint64_t *inval, + xfs_fsop_resblks_t *outval); + +#endif /* __XFS_FSOPS_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_grio.c linux-2.4-xfs/linux/fs/xfs/xfs_grio.c --- linux-2.4.7/linux/fs/xfs/xfs_grio.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_grio.c Fri Jun 15 07:09:10 2001 @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#define IRELE(ip) VN_RELE(XFS_ITOV(ip)) + +extern void grioinit(void); + +/* + * xfs_get_file_extents() + * This routine creates the cononical forms of all the extents + * for the given file and returns them to the user. + * + * RETURNS: + * 0 on success + * non zero on failure + */ +int +xfs_get_file_extents( + sysarg_t sysarg_file_id, + sysarg_t sysarg_extents_addr, + sysarg_t sysarg_count) +{ + int i, recsize, num_extents = 0; + int error = 0; + dev_t fs_dev; + xfs_ino_t ino; + xfs_inode_t *ip; + xfs_bmbt_rec_t *ep; + xfs_bmbt_irec_t thisrec; + grio_bmbt_irec_t *grec; + grio_file_id_t fileid; + xfs_caddr_t extents, count; + + if (copy_from_user(&fileid, SYSARG_TO_PTR(sysarg_file_id), sizeof(grio_file_id_t))) { + error = -XFS_ERROR(EFAULT); + return( error ); + } + + fs_dev = fileid.fs_dev; + ino = fileid.ino; + + /* + * Get sysarg arguements + */ + extents = (xfs_caddr_t)SYSARG_TO_PTR(sysarg_extents_addr); + count = (xfs_caddr_t)SYSARG_TO_PTR(sysarg_count); + + /* + * Get the inode + */ + if (!(ip = xfs_get_inode( fs_dev, ino ))) { + error = -XFS_ERROR(ENOENT); + if (copy_to_user((xfs_caddr_t)count, &num_extents, + sizeof( num_extents))) { + + error = -XFS_ERROR(EFAULT); + } + return( error ); + } + + /* + * Get the number of extents in the file. + */ + num_extents = ip->i_d.di_nextents; + + if (num_extents) { + + /* + * Copy the extents if they exist. + */ + ASSERT(num_extents < XFS_MAX_INCORE_EXTENTS); + + /* + * Read in the file extents from disk if necessary. + */ + if (!(ip->i_df.if_flags & XFS_IFEXTENTS)) { + error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK); + if (error) { + goto out; + } + } + + recsize = sizeof(grio_bmbt_irec_t) * num_extents; + grec = kmem_alloc(recsize, KM_SLEEP ); + + ep = ip->i_df.if_u1.if_extents; + + ASSERT( ep ); + + for (i = 0; i < num_extents; i++, ep++) { + /* + * copy extent numbers; + */ + xfs_bmbt_get_all(ep, &thisrec); + grec[i].br_startoff = thisrec.br_startoff; + grec[i].br_startblock = thisrec.br_startblock; + grec[i].br_blockcount = thisrec.br_blockcount; + } + + if (copy_to_user((xfs_caddr_t)extents, grec, recsize )) { + error = -XFS_ERROR(EFAULT); + } + kmem_free(grec, recsize); + } + + /* + * copy out to user space along with count. + */ + if (copy_to_user((xfs_caddr_t)count, &num_extents, sizeof( num_extents))) { + error = -XFS_ERROR(EFAULT); + } + + out: + xfs_iunlock( ip, XFS_ILOCK_SHARED ); + IRELE( ip ); + return( error ); +} + +/* + * xfs_get_file_rt() + * This routine determines if the given file has real time + * extents. If so a 1 is written to the user memory pointed at + * by rt, if not a 0 is written. + * + * + * RETURNS: + * 0 on success + * non zero on failure + */ +int +xfs_get_file_rt( + sysarg_t sysarg_file_id, + sysarg_t sysarg_rt) +{ + int inodert = 0, error = 0; + dev_t fs_dev; + xfs_ino_t ino; + xfs_inode_t *ip; + xfs_caddr_t rt; + grio_file_id_t fileid; + + + if ( copy_from_user(&fileid, SYSARG_TO_PTR(sysarg_file_id), sizeof(grio_file_id_t))) { + error = -XFS_ERROR(EFAULT); + return( error ); + } + + rt = (xfs_caddr_t)SYSARG_TO_PTR(sysarg_rt); + fs_dev = fileid.fs_dev; + ino = fileid.ino; + + /* + * Get the inode. + */ + if (!(ip = xfs_get_inode( fs_dev, ino ))) { + return -XFS_ERROR( ENOENT ); + } + + /* + * Check if the inode is marked as real time. + */ + if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) { + inodert = 1; + } + + /* + * Copy the results to user space. + */ + if (copy_to_user((xfs_caddr_t)rt, &inodert, sizeof(int)) ) { + error = -XFS_ERROR(EFAULT); + } + + xfs_iunlock( ip, XFS_ILOCK_SHARED ); + IRELE( ip ); + return( error ); + +} + + +/* + * xfs_get_block_size() + * This routine determines the block size of the given + * file system copies it to the user memory pointed at by fs_size. + * + * RETURNS: + * 0 on success + * non zero on failure + */ +int +xfs_get_block_size( + sysarg_t sysarg_fs_dev, + sysarg_t sysarg_fs_size) +{ + int error = 0; + dev_t fs_dev; + xfs_caddr_t fs_size; + struct vfs *vfsp; + + fs_dev = (dev_t)sysarg_fs_dev; + fs_size = (xfs_caddr_t)SYSARG_TO_PTR(sysarg_fs_size); + + if ( vfsp = vfs_devsearch( fs_dev, xfs_fstype ) ) { + if (copy_to_user((xfs_caddr_t)fs_size, &(vfsp->vfs_bsize), + sizeof(u_int)) ) { + + error = -XFS_ERROR(EFAULT); + } + } else { + error = -XFS_ERROR( EIO ); + } + return( error ); +} + + + +/* + * xfs_grio_get_inumber + * Convert a users file descriptor to an inode number. + * + * RETURNS: + * 64 bit inode number + * + * CAVEAT: + * this must be called from context of the user process + */ +xfs_ino_t +xfs_grio_get_inumber( int fdes ) +{ + xfs_ino_t ino=-1; + struct file *filp; + + filp = fget(fdes); + if (filp) { + struct dentry *dentry = filp->f_dentry; + struct inode *inode = dentry->d_inode; + + ino=inode->i_ino; + fput(filp); + } + printk("xfs_grio_get_inumber fd %d -> ino %Ld\n", + fdes, ino); + + return ino; + +} + + +/* + * xfs_grio_get_fs_dev + * Convert a users file descriptor to a file system device. + * + * RETURNS: + * the dev_t of the file system where the file resides + * + * CAVEAT: + * this must be called from the context of the user process + */ +dev_t +xfs_grio_get_fs_dev( int fdes ) +{ + dev_t dev=0; + struct file *filp; + + filp = fget(fdes); + if (filp) { + struct dentry *dentry = filp->f_dentry; + struct inode *inode = dentry->d_inode; + + dev=inode->i_dev; + + fput(filp); + } + printk("xfs_grio_get_fs_dev fd %d -> dev 0x%x (%d)\n", + fdes, dev, dev); + + return( dev ); +} + +/* stubbed out - real version is in grio module */ +int grio_strategy(xfs_buf_t *bp) +{ + return pagebuf_iorequest(bp); +} + +/* make XFS GRIO syscall available thru /dev/grio ioctl */ + +int xfs_grio_ioctl ( + struct inode *inode, + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + + if (cmd!=XFS_GRIO_CMD) { + printk("xfs_grio_ioctl command %d (expect %d)\n", + cmd, XFS_GRIO_CMD); + return -EINVAL; + } + + /* XXX PORT do we need to check for FORCED_SHUTDOWN here? */ + + switch (cmd) { + + case XFS_GRIO_CMD: { + xfs_grio_ioctl_t grioio; + + if (copy_from_user(&grioio, (xfs_grio_ioctl_t *)arg, + sizeof(xfs_grio_ioctl_t))) + return -XFS_ERROR(EFAULT); + + return grio_config(grioio.cmd, + grioio.arg1, grioio.arg2, + grioio.arg3, grioio.arg4); + } + + default: + return -EINVAL; + } +} + +static atomic_t xfs_grio_isopen = ATOMIC_INIT(0); + +static int xfs_grio_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int xfs_grio_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static struct file_operations xfs_grio_fops = { + ioctl: xfs_grio_ioctl, + open: xfs_grio_open, + release: xfs_grio_release, +}; + +static struct miscdevice xfs_grio_dev= +{ + XFS_GRIO_MINOR, + "xfs_grio", + &xfs_grio_fops +}; + +void xfs_grio_init(void) +{ + printk("xfs_grio_init\n"); + printk("sizeof(grio_cmd_t)=%d\n", sizeof(grio_cmd_t)); + printk("%d %d %d %d %d\n", + offsetof(grio_cmd_t,gr_fp), + offsetof(grio_cmd_t,other_end), + offsetof(grio_cmd_t,memloc), + offsetof(grio_cmd_t,cmd_info), + offsetof(grio_cmd_t,gr_usecs_bw)); + printk("%d %d %d %d\n", + offsetof(struct end_info,gr_end_type), + offsetof(struct end_info,gr_dev), + offsetof(struct end_info,gr_ino), + sizeof(struct end_info)); + grioinit(); + misc_register(&xfs_grio_dev); +} + +void xfs_grio_uninit(void) +{ + printk("xfs_grio_uninit\n"); + misc_deregister(&xfs_grio_dev); +} + diff -rNu linux-2.4.7/linux/fs/xfs/xfs_grio.h linux-2.4-xfs/linux/fs/xfs/xfs_grio.h --- linux-2.4.7/linux/fs/xfs/xfs_grio.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_grio.h Tue Dec 5 22:48:11 2000 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef __XFS_GRIO_H__ +#define __XFS_GRIO_H__ + +#include + +void xfs_grio_init(void); +void xfs_grio_uninit(void); + +int grio_io_is_guaranteed(struct file *fp, stream_id_t *stream_id); +int grio_monitor_start(sysarg_t ); +int grio_monitor_io_start(stream_id_t *stream_id, __int64_t iosize); +int grio_monitor_io_end(stream_id_t *stream_id, int index ); + +int grio_strategy(xfs_buf_t *); +int grio_config(sysarg_t, sysarg_t, sysarg_t, sysarg_t, sysarg_t ); +void grio_iodone(xfs_buf_t *); + +/* Function to convert the device number to an pointer to + * structure containing grio_info + */ +grio_disk_info_t *grio_disk_info(dev_t gdev); + +#endif /* __XFS_GRIO_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_ialloc.c linux-2.4-xfs/linux/fs/xfs/xfs_ialloc.c --- linux-2.4.7/linux/fs/xfs/xfs_ialloc.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_ialloc.c Mon May 14 10:39:44 2001 @@ -0,0 +1,1272 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +/* + * Log specified fields for the inode given by bp and off. + */ +STATIC void +xfs_ialloc_log_di( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *bp, /* inode buffer */ + int off, /* index of inode in buffer */ + int fields) /* bitmask of fields to log */ +{ + int first; /* first byte number */ + int ioffset; /* off in bytes */ + int last; /* last byte number */ + xfs_mount_t *mp; /* mount point structure */ + static const short offsets[] = { /* field offsets */ + /* keep in sync with bits */ + offsetof(xfs_dinode_core_t, di_magic), + offsetof(xfs_dinode_core_t, di_mode), + offsetof(xfs_dinode_core_t, di_version), + offsetof(xfs_dinode_core_t, di_format), + offsetof(xfs_dinode_core_t, di_onlink), + offsetof(xfs_dinode_core_t, di_uid), + offsetof(xfs_dinode_core_t, di_gid), + offsetof(xfs_dinode_core_t, di_nlink), + offsetof(xfs_dinode_core_t, di_projid), + offsetof(xfs_dinode_core_t, di_pad), + offsetof(xfs_dinode_core_t, di_atime), + offsetof(xfs_dinode_core_t, di_mtime), + offsetof(xfs_dinode_core_t, di_ctime), + offsetof(xfs_dinode_core_t, di_size), + offsetof(xfs_dinode_core_t, di_nblocks), + offsetof(xfs_dinode_core_t, di_extsize), + offsetof(xfs_dinode_core_t, di_nextents), + offsetof(xfs_dinode_core_t, di_anextents), + offsetof(xfs_dinode_core_t, di_forkoff), + offsetof(xfs_dinode_core_t, di_aformat), + offsetof(xfs_dinode_core_t, di_dmevmask), + offsetof(xfs_dinode_core_t, di_dmstate), + offsetof(xfs_dinode_core_t, di_flags), + offsetof(xfs_dinode_core_t, di_gen), + offsetof(xfs_dinode_t, di_next_unlinked), + offsetof(xfs_dinode_t, di_u), + offsetof(xfs_dinode_t, di_a), + sizeof(xfs_dinode_t) + }; + + + ASSERT(offsetof(xfs_dinode_t, di_core) == 0); + ASSERT((fields & (XFS_DI_U|XFS_DI_A)) == 0); + mp = tp->t_mountp; + /* + * Get the inode-relative first and last bytes for these fields + */ + xfs_btree_offsets(fields, offsets, XFS_DI_NUM_BITS, &first, &last); + /* + * Convert to buffer offsets and log it. + */ + ioffset = off << mp->m_sb.sb_inodelog; + first += ioffset; + last += ioffset; + xfs_trans_log_buf(tp, bp, first, last); +} + +/* + * Allocation group level functions. + */ + +/* + * Allocate new inodes in the allocation group specified by agbp. + * Return 0 for success, else error code. + */ +STATIC int /* error code or 0 */ +xfs_ialloc_ag_alloc( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *agbp, /* alloc group buffer */ + int *alloc) +{ + xfs_agi_t *agi; /* allocation group header */ + xfs_alloc_arg_t args; /* allocation argument structure */ + int blks_per_cluster; /* fs blocks per inode cluster */ + xfs_btree_cur_t *cur; /* inode btree cursor */ + xfs_daddr_t d; /* disk addr of buffer */ + int error; + xfs_buf_t *fbuf; /* new free inodes' buffer */ + xfs_dinode_t *free; /* new free inode structure */ + int i; /* inode counter */ + int j; /* block counter */ + int nbufs; /* num bufs of new inodes */ + xfs_agino_t newino; /* new first inode's number */ + xfs_agino_t newlen; /* new number of inodes */ + int ninodes; /* num inodes per buf */ + xfs_agino_t thisino; /* current inode number, for loop */ + int version; /* inode version number to use */ + static xfs_timestamp_t ztime; /* zero xfs timestamp */ + int isaligned; /* inode allocation at stripe unit */ + /* boundary */ + xfs_dinode_core_t dic; /* a dinode_core to copy to new */ + /* inodes */ + + args.tp = tp; + args.mp = tp->t_mountp; + + /* + * Locking will ensure that we don't have two callers in here + * at one time. + */ + newlen = XFS_IALLOC_INODES(args.mp); + if (args.mp->m_maxicount && + args.mp->m_sb.sb_icount + newlen > args.mp->m_maxicount) + return XFS_ERROR(ENOSPC); + args.minlen = args.maxlen = XFS_IALLOC_BLOCKS(args.mp); + /* + * Set the alignment for the allocation. + * If stripe alignment is turned on then align at stripe unit + * boundary. + * If the cluster size is smaller than a filesystem block + * then we're doing I/O for inodes in filesystem block size pieces, + * so don't need alignment anyway. + */ + isaligned = 0; + if (args.mp->m_sinoalign) { + ASSERT(!(args.mp->m_flags & XFS_MOUNT_NOALIGN)); + args.alignment = args.mp->m_dalign; + isaligned = 1; + } else if (XFS_SB_VERSION_HASALIGN(&args.mp->m_sb) && + args.mp->m_sb.sb_inoalignmt >= + XFS_B_TO_FSBT(args.mp, XFS_INODE_CLUSTER_SIZE(args.mp))) + args.alignment = args.mp->m_sb.sb_inoalignmt; + else + args.alignment = 1; + agi = XFS_BUF_TO_AGI(agbp); + /* + * Need to figure out where to allocate the inode blocks. + * Ideally they should be spaced out through the a.g. + * For now, just allocate blocks up front. + */ + args.agbno = INT_GET(agi->agi_root, ARCH_CONVERT); + args.fsbno = XFS_AGB_TO_FSB(args.mp, INT_GET(agi->agi_seqno, ARCH_CONVERT), + args.agbno); + /* + * Allocate a fixed-size extent of inodes. + */ + args.type = XFS_ALLOCTYPE_NEAR_BNO; + args.mod = args.total = args.wasdel = args.isfl = args.userdata = + args.minalignslop = 0; + args.prod = 1; + /* + * Allow space for the inode btree to split. + */ + args.minleft = XFS_IN_MAXLEVELS(args.mp) - 1; + if ((error = xfs_alloc_vextent(&args))) + return error; + + /* + * If stripe alignment is turned on, then try again with cluster + * alignment. + */ + if (isaligned && args.fsbno == NULLFSBLOCK) { + args.type = XFS_ALLOCTYPE_NEAR_BNO; + args.agbno = INT_GET(agi->agi_root, ARCH_CONVERT); + args.fsbno = XFS_AGB_TO_FSB(args.mp, + INT_GET(agi->agi_seqno, ARCH_CONVERT), args.agbno); + if (XFS_SB_VERSION_HASALIGN(&args.mp->m_sb) && + args.mp->m_sb.sb_inoalignmt >= + XFS_B_TO_FSBT(args.mp, XFS_INODE_CLUSTER_SIZE(args.mp))) + args.alignment = args.mp->m_sb.sb_inoalignmt; + else + args.alignment = 1; + if ((error = xfs_alloc_vextent(&args))) + return error; + } + + if (args.fsbno == NULLFSBLOCK) { + *alloc = 0; + return 0; + } + ASSERT(args.len == args.minlen); + /* + * Convert the results. + */ + newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0); + /* + * Loop over the new block(s), filling in the inodes. + * For small block sizes, manipulate the inodes in buffers + * which are multiples of the blocks size. + */ + if (args.mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(args.mp)) { + blks_per_cluster = 1; + nbufs = (int)args.len; + ninodes = args.mp->m_sb.sb_inopblock; + } else { + blks_per_cluster = XFS_INODE_CLUSTER_SIZE(args.mp) / + args.mp->m_sb.sb_blocksize; + nbufs = (int)args.len / blks_per_cluster; + ninodes = blks_per_cluster * args.mp->m_sb.sb_inopblock; + } + /* + * Figure out what version number to use in the inodes we create. + * If the superblock version has caught up to the one that supports + * the new inode format, then use the new inode version. Otherwise + * use the old version so that old kernels will continue to be + * able to use the file system. + */ + if (XFS_SB_VERSION_HASNLINK(&args.mp->m_sb)) + version = XFS_DINODE_VERSION_2; + else + version = XFS_DINODE_VERSION_1; + for (j = 0; j < nbufs; j++) { + /* + * Get the block. + */ + d = XFS_AGB_TO_DADDR(args.mp, INT_GET(agi->agi_seqno, ARCH_CONVERT), + args.agbno + (j * blks_per_cluster)); + fbuf = xfs_trans_get_buf(tp, args.mp->m_ddev_targp, d, + args.mp->m_bsize * blks_per_cluster, + XFS_BUF_LOCK); + ASSERT(fbuf); + ASSERT(!XFS_BUF_GETERROR(fbuf)); + /* + * Loop over the inodes in this buffer. + */ + INT_SET(dic.di_magic, ARCH_CONVERT, XFS_DINODE_MAGIC); + INT_ZERO(dic.di_mode, ARCH_CONVERT); + INT_SET(dic.di_version, ARCH_CONVERT, version); + INT_ZERO(dic.di_format, ARCH_CONVERT); + INT_ZERO(dic.di_onlink, ARCH_CONVERT); + INT_ZERO(dic.di_uid, ARCH_CONVERT); + INT_ZERO(dic.di_gid, ARCH_CONVERT); + INT_ZERO(dic.di_nlink, ARCH_CONVERT); + INT_ZERO(dic.di_projid, ARCH_CONVERT); + bzero(&(dic.di_pad[0]),sizeof(dic.di_pad)); + INT_SET(dic.di_atime.t_sec, ARCH_CONVERT, ztime.t_sec); + INT_SET(dic.di_atime.t_nsec, ARCH_CONVERT, ztime.t_nsec); + + INT_SET(dic.di_mtime.t_sec, ARCH_CONVERT, ztime.t_sec); + INT_SET(dic.di_mtime.t_nsec, ARCH_CONVERT, ztime.t_nsec); + + INT_SET(dic.di_ctime.t_sec, ARCH_CONVERT, ztime.t_sec); + INT_SET(dic.di_ctime.t_nsec, ARCH_CONVERT, ztime.t_nsec); + + INT_ZERO(dic.di_size, ARCH_CONVERT); + INT_ZERO(dic.di_nblocks, ARCH_CONVERT); + INT_ZERO(dic.di_extsize, ARCH_CONVERT); + INT_ZERO(dic.di_nextents, ARCH_CONVERT); + INT_ZERO(dic.di_anextents, ARCH_CONVERT); + INT_ZERO(dic.di_forkoff, ARCH_CONVERT); + INT_ZERO(dic.di_aformat, ARCH_CONVERT); + INT_ZERO(dic.di_dmevmask, ARCH_CONVERT); + INT_ZERO(dic.di_dmstate, ARCH_CONVERT); + INT_ZERO(dic.di_flags, ARCH_CONVERT); + INT_ZERO(dic.di_gen, ARCH_CONVERT); + + for (i = 0; i < ninodes; i++) { + free = XFS_MAKE_IPTR(args.mp, fbuf, i); + bcopy (&dic, &(free->di_core), sizeof(xfs_dinode_core_t)); + INT_SET(free->di_next_unlinked, ARCH_CONVERT, NULLAGINO); + xfs_ialloc_log_di(tp, fbuf, i, + XFS_DI_CORE_BITS | XFS_DI_NEXT_UNLINKED); + } + xfs_trans_inode_alloc_buf(tp, fbuf); + } + INT_MOD(agi->agi_count, ARCH_CONVERT, newlen); + INT_MOD(agi->agi_freecount, ARCH_CONVERT, newlen); + mraccess(&args.mp->m_peraglock); + args.mp->m_perag[INT_GET(agi->agi_seqno, ARCH_CONVERT)].pagi_freecount += newlen; + mraccunlock(&args.mp->m_peraglock); + INT_SET(agi->agi_newino, ARCH_CONVERT, newino); + /* + * Insert records describing the new inode chunk into the btree. + */ + cur = xfs_btree_init_cursor(args.mp, tp, agbp, + INT_GET(agi->agi_seqno, ARCH_CONVERT), + XFS_BTNUM_INO, (xfs_inode_t *)0, 0); + for (thisino = newino; + thisino < newino + newlen; + thisino += XFS_INODES_PER_CHUNK) { + if ((error = xfs_inobt_lookup_eq(cur, thisino, + XFS_INODES_PER_CHUNK, XFS_INOBT_ALL_FREE, &i))) { + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; + } + ASSERT(i == 0); + if ((error = xfs_inobt_insert(cur, &i))) { + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; + } + ASSERT(i == 1); + } + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + /* + * Log allocation group header fields + */ + xfs_ialloc_log_agi(tp, agbp, + XFS_AGI_COUNT | XFS_AGI_FREECOUNT | XFS_AGI_NEWINO); + /* + * Modify/log superblock values for inode count and inode free count. + */ + xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, (long)newlen); + xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, (long)newlen); + *alloc = 1; + return 0; +} + +/* + * Select an allocation group to look for a free inode in, based on the parent + * inode and then mode. Return the allocation group buffer. + */ +STATIC xfs_buf_t * /* allocation group buffer */ +xfs_ialloc_ag_select( + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t parent, /* parent directory inode number */ + mode_t mode, /* bits set to indicate file type */ + int okalloc) /* ok to allocate more space */ +{ + xfs_buf_t *agbp; /* allocation group header buffer */ + xfs_agnumber_t agcount; /* number of ag's in the filesystem */ + xfs_agnumber_t agno; /* current ag number */ + int flags; /* alloc buffer locking flags */ + xfs_extlen_t ineed; /* blocks needed for inode allocation */ + xfs_extlen_t longest; /* longest extent available */ + xfs_mount_t *mp; /* mount point structure */ + int needspace; /* file mode implies space allocated */ + xfs_perag_t *pag; /* per allocation group data */ + xfs_agnumber_t pagno; /* parent (starting) ag number */ + + /* + * Files of these types need at least one block if length > 0 + * (and they won't fit in the inode, but that's hard to figure out). + */ + needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode); + mp = tp->t_mountp; + agcount = mp->m_sb.sb_agcount; + if (S_ISDIR(mode)) + pagno = atomicIncWithWrap((int *)&mp->m_agirotor, agcount); + else + pagno = XFS_INO_TO_AGNO(mp, parent); + ASSERT(pagno < agcount); + /* + * Loop through allocation groups, looking for one with a little + * free space in it. Note we don't look for free inodes, exactly. + * Instead, we include whether there is a need to allocate inodes + * to mean that blocks must be allocated for them, + * if none are currently free. + */ + agno = pagno; + flags = XFS_ALLOC_FLAG_TRYLOCK; + for (;;) { + mraccess(&mp->m_peraglock); + pag = &mp->m_perag[agno]; + if (!pag->pagi_init) { + if (xfs_ialloc_read_agi(mp, tp, agno, &agbp)) { + agbp = NULL; + mraccunlock(&mp->m_peraglock); + goto nextag; + } + } else + agbp = NULL; + /* + * Is there enough free space for the file plus a block + * of inodes (if we need to allocate some)? + */ + ineed = pag->pagi_freecount ? 0 : XFS_IALLOC_BLOCKS(mp); + if (ineed && !pag->pagf_init) { + if (agbp == NULL && + xfs_ialloc_read_agi(mp, tp, agno, &agbp)) { + agbp = NULL; + mraccunlock(&mp->m_peraglock); + goto nextag; + } + (void)xfs_alloc_pagf_init(mp, tp, agno, flags); + } + if (!ineed || pag->pagf_init) { + if (ineed && !(longest = pag->pagf_longest)) + longest = pag->pagf_flcount > 0; + if (!ineed || + (pag->pagf_freeblks >= needspace + ineed && + longest >= ineed && + okalloc)) { + if (agbp == NULL && + xfs_ialloc_read_agi(mp, tp, agno, &agbp)) { + agbp = NULL; + mraccunlock(&mp->m_peraglock); + goto nextag; + } + mraccunlock(&mp->m_peraglock); + return agbp; + } + } + mraccunlock(&mp->m_peraglock); + if (agbp) + xfs_trans_brelse(tp, agbp); +nextag: + /* + * No point in iterating over the rest, if we're shutting + * down. + */ + if (XFS_FORCED_SHUTDOWN(mp)) + return (xfs_buf_t *)0; + agno++; + if (agno == agcount) + agno = 0; + if (agno == pagno) { + if (flags == 0) + return (xfs_buf_t *)0; + flags = 0; + } + } +} + +/* + * Visible inode allocation functions. + */ + +/* + * Allocate an inode on disk. + * Mode is used to tell whether the new inode will need space, and whether + * it is a directory. + * + * The arguments IO_agbp and alloc_done are defined to work within + * the constraint of one allocation per transaction. + * xfs_dialloc() is designed to be called twice if it has to do an + * allocation to make more free inodes. On the first call, + * IO_agbp should be set to NULL. If an inode is available, + * i.e., xfs_dialloc() did not need to do an allocation, an inode + * number is returned. In this case, IO_agbp would be set to the + * current ag_buf and alloc_done set to false. + * If an allocation needed to be done, xfs_dialloc would return + * the current ag_buf in IO_agbp and set alloc_done to true. + * The caller should then commit the current transaction, allocate a new + * transaction, and call xfs_dialloc() again, passing in the previous + * value of IO_agbp. IO_agbp should be held across the transactions. + * Since the agbp is locked across the two calls, the second call is + * guaranteed to have a free inode available. + * + * Once we successfully pick an inode its number is returned and the + * on-disk data structures are updated. The inode itself is not read + * in, since doing so would break ordering constraints with xfs_reclaim. + */ +int +xfs_dialloc( + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t parent, /* parent inode (directory) */ + mode_t mode, /* mode bits for new inode */ + int okalloc, /* ok to allocate more space */ + xfs_buf_t **IO_agbp, /* in/out ag header's buffer */ + boolean_t *alloc_done, /* true if we needed to replenish + inode freelist */ + xfs_ino_t *inop) /* inode number allocated */ +{ + xfs_agnumber_t agcount; /* number of allocation groups */ + xfs_buf_t *agbp; /* allocation group header's buffer */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_agi_t *agi; /* allocation group header structure */ + xfs_btree_cur_t *cur; /* inode allocation btree cursor */ + int error; /* error return value */ + int i; /* result code */ + int ialloced; /* inode allocation status */ + int noroom = 0; /* no space for inode blk allocation */ + xfs_ino_t ino; /* fs-relative inode to be returned */ + /* REFERENCED */ + int j; /* result code */ + xfs_mount_t *mp; /* file system mount structure */ + int offset; /* index of inode in chunk */ + xfs_agino_t pagino; /* parent's a.g. relative inode # */ + xfs_agnumber_t pagno; /* parent's allocation group number */ + xfs_inobt_rec_t rec; /* inode allocation record */ + xfs_agnumber_t tagno; /* testing allocation group number */ + xfs_btree_cur_t *tcur; /* temp cursor */ + xfs_inobt_rec_t trec; /* temp inode allocation record */ + + + if (*IO_agbp == NULL) { + /* + * We do not have an agbp, so select an initial allocation + * group for inode allocation. + */ + agbp = xfs_ialloc_ag_select(tp, parent, mode, okalloc); + /* + * Couldn't find an allocation group satisfying the + * criteria, give up. + */ + if (!agbp) { + *inop = NULLFSINO; + return 0; + } + agi = XFS_BUF_TO_AGI(agbp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + } else { + /* + * Continue where we left off before. In this case, we + * know that the allocation group has free inodes. + */ + agbp = *IO_agbp; + agi = XFS_BUF_TO_AGI(agbp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + ASSERT(INT_GET(agi->agi_freecount, ARCH_CONVERT) > 0); + } + mp = tp->t_mountp; + agcount = mp->m_sb.sb_agcount; + agno = INT_GET(agi->agi_seqno, ARCH_CONVERT); + tagno = agno; + pagno = XFS_INO_TO_AGNO(mp, parent); + pagino = XFS_INO_TO_AGINO(mp, parent); + + /* + * If we have already hit the ceiling of inode blocks then clear + * okalloc so we scan all available agi structures for a free + * inode. + */ + + if (mp->m_maxicount && + mp->m_sb.sb_icount + XFS_IALLOC_INODES(mp) > mp->m_maxicount) { + noroom = 1; + okalloc = 0; + } + + /* + * Loop until we find an allocation group that either has free inodes + * or in which we can allocate some inodes. Iterate through the + * allocation groups upward, wrapping at the end. + */ + *alloc_done = B_FALSE; + while (INT_GET(agi->agi_freecount, ARCH_CONVERT) == 0) { + /* + * Don't do anything if we're not supposed to allocate + * any blocks, just go on to the next ag. + */ + if (okalloc) { + /* + * Try to allocate some new inodes in the allocation + * group. + */ + if ((error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced))) { + xfs_trans_brelse(tp, agbp); + if (error == ENOSPC) { + *inop = NULLFSINO; + return 0; + } else + return error; + } + if (ialloced) { + /* + * We successfully allocated some inodes, return + * the current context to the caller so that it + * can commit the current transaction and call + * us again where we left off. + */ + ASSERT(INT_GET(agi->agi_freecount, ARCH_CONVERT) > 0); + *alloc_done = B_TRUE; + *IO_agbp = agbp; + *inop = NULLFSINO; + return 0; + } + } + /* + * If it failed, give up on this ag. + */ + xfs_trans_brelse(tp, agbp); + /* + * Go on to the next ag: get its ag header. + */ +nextag: + if (++tagno == agcount) + tagno = 0; + if (tagno == agno) { + *inop = NULLFSINO; + return noroom ? ENOSPC : 0; + } + mraccess(&mp->m_peraglock); + error = xfs_ialloc_read_agi(mp, tp, tagno, &agbp); + mraccunlock(&mp->m_peraglock); + if (error) + goto nextag; + agi = XFS_BUF_TO_AGI(agbp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + } + /* + * Here with an allocation group that has a free inode. + * Reset agno since we may have chosen a new ag in the + * loop above. + */ + agno = tagno; + *IO_agbp = NULL; + cur = xfs_btree_init_cursor(mp, tp, agbp, INT_GET(agi->agi_seqno, ARCH_CONVERT), + XFS_BTNUM_INO, (xfs_inode_t *)0, 0); + /* + * If pagino is 0 (this is the root inode allocation) use newino. + * This must work because we've just allocated some. + */ + if (!pagino) + pagino = INT_GET(agi->agi_newino, ARCH_CONVERT); +#ifdef DEBUG + if (cur->bc_nlevels == 1) { + int freecount = 0; + + if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + do { + if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + freecount += rec.ir_freecount; + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error0; + } while (i == 1); + + ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) || + XFS_FORCED_SHUTDOWN(mp)); + } +#endif + /* + * If in the same a.g. as the parent, try to get near the parent. + */ + if (pagno == agno) { + if ((error = xfs_inobt_lookup_le(cur, pagino, 0, 0, &i))) + goto error0; + if (i != 0 && + (error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &j, ARCH_NOCONVERT)) == 0 && + j == 1 && + rec.ir_freecount > 0) { + /* + * Found a free inode in the same chunk + * as parent, done. + */ + } + /* + * In the same a.g. as parent, but parent's chunk is full. + */ + else { + int doneleft; /* done, to the left */ + int doneright; /* done, to the right */ + + if (error) + goto error0; + ASSERT(i == 1); + ASSERT(j == 1); + /* + * Duplicate the cursor, search left & right + * simultaneously. + */ + if ((error = xfs_btree_dup_cursor(cur, &tcur))) + goto error0; + /* + * Search left with tcur, back up 1 record. + */ + if ((error = xfs_inobt_decrement(tcur, 0, &i))) + goto error1; + doneleft = !i; + if (!doneleft) { + if ((error = xfs_inobt_get_rec(tcur, + &trec.ir_startino, + &trec.ir_freecount, + &trec.ir_free, &i, ARCH_NOCONVERT))) + goto error1; + XFS_WANT_CORRUPTED_GOTO(i == 1, error1); + } + /* + * Search right with cur, go forward 1 record. + */ + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error1; + doneright = !i; + if (!doneright) { + if ((error = xfs_inobt_get_rec(cur, + &rec.ir_startino, + &rec.ir_freecount, + &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error1; + XFS_WANT_CORRUPTED_GOTO(i == 1, error1); + } + /* + * Loop until we find the closest inode chunk + * with a free one. + */ + while (!doneleft || !doneright) { + int useleft; /* using left inode + chunk this time */ + + /* + * Figure out which block is closer, + * if both are valid. + */ + if (!doneleft && !doneright) + useleft = + pagino - + (trec.ir_startino + + XFS_INODES_PER_CHUNK - 1) < + rec.ir_startino - pagino; + else + useleft = !doneleft; + /* + * If checking the left, does it have + * free inodes? + */ + if (useleft && trec.ir_freecount) { + /* + * Yes, set it up as the chunk to use. + */ + rec = trec; + xfs_btree_del_cursor(cur, + XFS_BTREE_NOERROR); + cur = tcur; + break; + } + /* + * If checking the right, does it have + * free inodes? + */ + if (!useleft && rec.ir_freecount) { + /* + * Yes, it's already set up. + */ + xfs_btree_del_cursor(tcur, + XFS_BTREE_NOERROR); + break; + } + /* + * If used the left, get another one + * further left. + */ + if (useleft) { + if ((error = xfs_inobt_decrement(tcur, 0, + &i))) + goto error1; + doneleft = !i; + if (!doneleft) { + if ((error = xfs_inobt_get_rec( + tcur, + &trec.ir_startino, + &trec.ir_freecount, + &trec.ir_free, &i, ARCH_NOCONVERT))) + goto error1; + XFS_WANT_CORRUPTED_GOTO(i == 1, + error1); + } + } + /* + * If used the right, get another one + * further right. + */ + else { + if ((error = xfs_inobt_increment(cur, 0, + &i))) + goto error1; + doneright = !i; + if (!doneright) { + if ((error = xfs_inobt_get_rec( + cur, + &rec.ir_startino, + &rec.ir_freecount, + &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error1; + XFS_WANT_CORRUPTED_GOTO(i == 1, + error1); + } + } + } + ASSERT(!doneleft || !doneright); + } + } + /* + * In a different a.g. from the parent. + * See if the most recently allocated block has any free. + */ + else if (INT_GET(agi->agi_newino, ARCH_CONVERT) != NULLAGINO) { + if ((error = xfs_inobt_lookup_eq(cur, + INT_GET(agi->agi_newino, ARCH_CONVERT), 0, 0, &i))) + goto error0; + if (i == 1 && + (error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &j, ARCH_NOCONVERT)) == 0 && + j == 1 && + rec.ir_freecount > 0) { + /* + * The last chunk allocated in the group still has + * a free inode. + */ + } + /* + * None left in the last group, search the whole a.g. + */ + else { + if (error) + goto error0; + if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) + goto error0; + ASSERT(i == 1); + for (;;) { + if ((error = xfs_inobt_get_rec(cur, + &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, + &i, ARCH_NOCONVERT))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (rec.ir_freecount > 0) + break; + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + } + } + } + offset = XFS_IALLOC_FIND_FREE(&rec.ir_free); + ASSERT(offset >= 0); + ASSERT(offset < XFS_INODES_PER_CHUNK); + ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) % + XFS_INODES_PER_CHUNK) == 0); + ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset); + XFS_INOBT_CLR_FREE(&rec, offset, ARCH_NOCONVERT); + rec.ir_freecount--; + if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount, + rec.ir_free))) + goto error0; + INT_MOD(agi->agi_freecount, ARCH_CONVERT, -1); + xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); + mraccess(&mp->m_peraglock); + mp->m_perag[tagno].pagi_freecount--; + mraccunlock(&mp->m_peraglock); +#ifdef DEBUG + if (cur->bc_nlevels == 1) { + int freecount = 0; + + if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) + goto error0; + do { + if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + freecount += rec.ir_freecount; + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error0; + } while (i == 1); + ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) || + XFS_FORCED_SHUTDOWN(mp)); + } +#endif + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1); + *inop = ino; + return 0; +error1: + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); +error0: + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Free disk inode. Carefully avoids touching the incore inode, all + * manipulations incore are the caller's responsibility. + * The on-disk inode is not changed by this operation, only the + * btree (free inode mask) is changed. + */ +int +xfs_difree( + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t inode) /* inode to be freed */ +{ + /* REFERENCED */ + xfs_agblock_t agbno; /* block number containing inode */ + xfs_buf_t *agbp; /* buffer containing allocation group header */ + xfs_agino_t agino; /* inode number relative to allocation group */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_agi_t *agi; /* allocation group header */ + xfs_btree_cur_t *cur; /* inode btree cursor */ + int error; /* error return value */ + int i; /* result code */ + xfs_mount_t *mp; /* mount structure for filesystem */ + int off; /* offset of inode in inode chunk */ + xfs_inobt_rec_t rec; /* btree record */ + + mp = tp->t_mountp; + + /* + * Break up inode number into its components. + */ + agno = XFS_INO_TO_AGNO(mp, inode); + if (agno >= mp->m_sb.sb_agcount) { + cmn_err(CE_WARN, + "xfs_difree: agno >= mp->m_sb.sb_agcount (%d >= %d) on %s. Returning EINVAL.", + agno, mp->m_sb.sb_agcount, mp->m_fsname); + ASSERT(0); + return XFS_ERROR(EINVAL); + } + agino = XFS_INO_TO_AGINO(mp, inode); + if (inode != XFS_AGINO_TO_INO(mp, agno, agino)) { + cmn_err(CE_WARN, + "xfs_difree: inode != XFS_AGINO_TO_INO() (%d != %d) on %s. Returning EINVAL.", + inode, XFS_AGINO_TO_INO(mp, agno, agino), mp->m_fsname); + ASSERT(0); + return XFS_ERROR(EINVAL); + } + agbno = XFS_AGINO_TO_AGBNO(mp, agino); + if (agbno >= mp->m_sb.sb_agblocks) { + cmn_err(CE_WARN, + "xfs_difree: agbno >= mp->m_sb.sb_agblocks (%d >= %d) on %s. Returning EINVAL.", + agbno, mp->m_sb.sb_agblocks, mp->m_fsname); + ASSERT(0); + return XFS_ERROR(EINVAL); + } + /* + * Get the allocation group header. + */ + mraccess(&mp->m_peraglock); + error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); + mraccunlock(&mp->m_peraglock); + if (error) { + cmn_err(CE_WARN, + "xfs_difree: xfs_ialloc_read_agi() returned an error %d on %s. Returning error.", + error, mp->m_fsname); + return error; + } + agi = XFS_BUF_TO_AGI(agbp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + ASSERT(agbno < INT_GET(agi->agi_length, ARCH_CONVERT)); + /* + * Initialize the cursor. + */ + cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO, + (xfs_inode_t *)0, 0); +#ifdef DEBUG + if (cur->bc_nlevels == 1) { + int freecount = 0; + + if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) + goto error0; + do { + if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + freecount += rec.ir_freecount; + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error0; + } while (i == 1); + ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) || + XFS_FORCED_SHUTDOWN(mp)); + } +#endif + /* + * Look for the entry describing this inode. + */ + if ((error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i))) { + cmn_err(CE_WARN, + "xfs_difree: xfs_inobt_lookup_le returned() an error %d on %s. Returning error.", + error, mp->m_fsname); + goto error0; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, &rec.ir_freecount, + &rec.ir_free, &i, ARCH_NOCONVERT))) { + cmn_err(CE_WARN, + "xfs_difree: xfs_inobt_get_rec() returned an error %d on %s. Returning error.", + error, mp->m_fsname); + goto error0; + } + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Get the offset in the inode chunk. + */ + off = agino - rec.ir_startino; + ASSERT(off >= 0 && off < XFS_INODES_PER_CHUNK); + ASSERT(!XFS_INOBT_IS_FREE(&rec, off, ARCH_NOCONVERT)); + /* + * Mark the inode free & increment the count. + */ + XFS_INOBT_SET_FREE(&rec, off, ARCH_NOCONVERT); + rec.ir_freecount++; + if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount, rec.ir_free))) { + cmn_err(CE_WARN, + "xfs_difree: xfs_inobt_update() returned an error %d on %s. Returning error.", + error, mp->m_fsname); + goto error0; + } + /* + * Change the inode free counts and log the ag/sb changes. + */ + INT_MOD(agi->agi_freecount, ARCH_CONVERT, 1); + xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); + mraccess(&mp->m_peraglock); + mp->m_perag[agno].pagi_freecount++; + mraccunlock(&mp->m_peraglock); +#ifdef DEBUG + if (cur->bc_nlevels == 1) { + int freecount = 0; + + if ((error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &i))) + goto error0; + do { + if ((error = xfs_inobt_get_rec(cur, &rec.ir_startino, + &rec.ir_freecount, &rec.ir_free, &i, ARCH_NOCONVERT))) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + freecount += rec.ir_freecount; + if ((error = xfs_inobt_increment(cur, 0, &i))) + goto error0; + } while (i == 1); + ASSERT(freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) || + XFS_FORCED_SHUTDOWN(mp)); + } +#endif + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1); + return 0; + +error0: + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Return the location of the inode in bno/off, for mapping it into a buffer. + */ +/*ARGSUSED*/ +int +xfs_dilocate( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t ino, /* inode to locate */ + xfs_fsblock_t *bno, /* output: block containing inode */ + int *len, /* output: num blocks in inode cluster */ + int *off, /* output: index in block of inode */ + uint flags) /* flags concerning inode lookup */ +{ + xfs_agblock_t agbno; /* block number of inode in the alloc group */ + xfs_buf_t *agbp; /* agi buffer */ + xfs_agino_t agino; /* inode number within alloc group */ + xfs_agnumber_t agno; /* allocation group number */ + int blks_per_cluster; /* num blocks per inode cluster */ + xfs_agblock_t chunk_agbno; /* first block in inode chunk */ + xfs_agino_t chunk_agino; /* first agino in inode chunk */ + __int32_t chunk_cnt; /* count of free inodes in chunk */ + xfs_inofree_t chunk_free; /* mask of free inodes in chunk */ + xfs_agblock_t cluster_agbno; /* first block in inode cluster */ + xfs_btree_cur_t *cur; /* inode btree cursor */ + int error; /* error code */ + int i; /* temp state */ + int offset; /* index of inode in its buffer */ + int offset_agbno; /* blks from chunk start to inode */ + + ASSERT(ino != NULLFSINO); + /* + * Split up the inode number into its parts. + */ + agno = XFS_INO_TO_AGNO(mp, ino); + agino = XFS_INO_TO_AGINO(mp, ino); + agbno = XFS_AGINO_TO_AGBNO(mp, agino); + if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || + ino != XFS_AGINO_TO_INO(mp, agno, agino)) + return XFS_ERROR(EINVAL); + if ((mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp)) || + !(flags & XFS_IMAP_LOOKUP)) { + offset = XFS_INO_TO_OFFSET(mp, ino); + ASSERT(offset < mp->m_sb.sb_inopblock); + *bno = XFS_AGB_TO_FSB(mp, agno, agbno); + *off = offset; + *len = 1; + return 0; + } + blks_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_blocklog; + if (*bno != NULLFSBLOCK) { + offset = XFS_INO_TO_OFFSET(mp, ino); + ASSERT(offset < mp->m_sb.sb_inopblock); + cluster_agbno = XFS_FSB_TO_AGBNO(mp, *bno); + *off = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + + offset; + *len = blks_per_cluster; + return 0; + } + if (mp->m_inoalign_mask) { + offset_agbno = agbno & mp->m_inoalign_mask; + chunk_agbno = agbno - offset_agbno; + } else { + mraccess(&mp->m_peraglock); + error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); + mraccunlock(&mp->m_peraglock); + if (error) + return error; + cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO, + (xfs_inode_t *)0, 0); + if ((error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i))) + goto error0; + if ((error = xfs_inobt_get_rec(cur, &chunk_agino, &chunk_cnt, + &chunk_free, &i, ARCH_NOCONVERT))) + goto error0; + if (i == 0) + error = XFS_ERROR(EINVAL); + xfs_trans_brelse(tp, agbp); + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + if (error) + return error; + chunk_agbno = XFS_AGINO_TO_AGBNO(mp, chunk_agino); + offset_agbno = agbno - chunk_agbno; + } + ASSERT(agbno >= chunk_agbno); + cluster_agbno = chunk_agbno + + ((offset_agbno / blks_per_cluster) * blks_per_cluster); + offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + + XFS_INO_TO_OFFSET(mp, ino); + *bno = XFS_AGB_TO_FSB(mp, agno, cluster_agbno); + *off = offset; + *len = blks_per_cluster; + return 0; +error0: + xfs_trans_brelse(tp, agbp); + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + return error; +} + +/* + * Compute and fill in value of m_in_maxlevels. + */ +void +xfs_ialloc_compute_maxlevels( + xfs_mount_t *mp) /* file system mount structure */ +{ + int level; + uint maxblocks; + uint maxleafents; + int minleafrecs; + int minnoderecs; + + maxleafents = (1LL << XFS_INO_AGINO_BITS(mp)) >> + XFS_INODES_PER_CHUNK_LOG; + minleafrecs = mp->m_alloc_mnr[0]; + minnoderecs = mp->m_alloc_mnr[1]; + maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; + for (level = 1; maxblocks > 1; level++) + maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; + mp->m_in_maxlevels = level; +} + +/* + * Log specified fields for the ag hdr (inode section) + */ +void +xfs_ialloc_log_agi( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *bp, /* allocation group header buffer */ + int fields) /* bitmask of fields to log */ +{ + int first; /* first byte number */ + int last; /* last byte number */ + static const short offsets[] = { /* field starting offsets */ + /* keep in sync with bit definitions */ + offsetof(xfs_agi_t, agi_magicnum), + offsetof(xfs_agi_t, agi_versionnum), + offsetof(xfs_agi_t, agi_seqno), + offsetof(xfs_agi_t, agi_length), + offsetof(xfs_agi_t, agi_count), + offsetof(xfs_agi_t, agi_root), + offsetof(xfs_agi_t, agi_level), + offsetof(xfs_agi_t, agi_freecount), + offsetof(xfs_agi_t, agi_newino), + offsetof(xfs_agi_t, agi_dirino), + offsetof(xfs_agi_t, agi_unlinked), + sizeof(xfs_agi_t) + }; +#ifdef DEBUG + xfs_agi_t *agi; /* allocation group header */ + + agi = XFS_BUF_TO_AGI(bp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == + XFS_AGI_MAGIC); +#endif + /* + * Compute byte offsets for the first and last fields. + */ + xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS, &first, &last); + /* + * Log the allocation group inode header buffer. + */ + xfs_trans_log_buf(tp, bp, first, last); +} + +/* + * Read in the allocation group header (inode allocation section) + */ +int +xfs_ialloc_read_agi( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + xfs_buf_t **bpp) /* allocation group hdr buf */ +{ + xfs_agi_t *agi; /* allocation group header */ + int agi_ok; /* agi is consistent */ + xfs_buf_t *bp; /* allocation group hdr buf */ + xfs_daddr_t d; /* disk block address */ + int error; +#ifdef DEBUG + int i; +#endif + xfs_perag_t *pag; /* per allocation group data */ + + + ASSERT(agno != NULLAGNUMBER); + d = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + if ((error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, 1, 0, &bp))) + return error; + ASSERT(bp && !XFS_BUF_GETERROR(bp)); + /* + * Validate the magic number of the agi block. + */ + agi = XFS_BUF_TO_AGI(bp); + agi_ok = + INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC && + XFS_AGI_GOOD_VERSION(INT_GET(agi->agi_versionnum, ARCH_CONVERT)); + if (XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IALLOC_READ_AGI, + XFS_RANDOM_IALLOC_READ_AGI)) { + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EFSCORRUPTED); + } + pag = &mp->m_perag[agno]; + if (!pag->pagi_init) { + pag->pagi_freecount = INT_GET(agi->agi_freecount, ARCH_CONVERT); + pag->pagi_init = 1; + } else { + /* + * It's possible for these to be out of sync if + * we are in the middle of a forced shutdown. + */ + ASSERT(pag->pagi_freecount == INT_GET(agi->agi_freecount, ARCH_CONVERT) + || XFS_FORCED_SHUTDOWN(mp)); + } +#ifdef DEBUG + for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) + ASSERT(INT_GET(agi->agi_unlinked[i], ARCH_CONVERT) != 0); +#endif + XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGI, XFS_AGI_REF); + *bpp = bp; + return 0; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_ialloc.h linux-2.4-xfs/linux/fs/xfs/xfs_ialloc.h --- linux-2.4.7/linux/fs/xfs/xfs_ialloc.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_ialloc.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_IALLOC_H__ +#define __XFS_IALLOC_H__ + +struct xfs_buf; +struct xfs_dinode; +struct xfs_mount; +struct xfs_trans; + +/* + * Allocation parameters for inode allocation. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IALLOC_INODES) +int xfs_ialloc_inodes(struct xfs_mount *mp); +#define XFS_IALLOC_INODES(mp) xfs_ialloc_inodes(mp) +#else +#define XFS_IALLOC_INODES(mp) ((mp)->m_ialloc_inos) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IALLOC_BLOCKS) +xfs_extlen_t xfs_ialloc_blocks(struct xfs_mount *mp); +#define XFS_IALLOC_BLOCKS(mp) xfs_ialloc_blocks(mp) +#else +#define XFS_IALLOC_BLOCKS(mp) ((mp)->m_ialloc_blks) +#endif + +/* + * For small block file systems, move inodes in clusters of this size. + * When we don't have a lot of memory, however, we go a bit smaller + * to reduce the number of AGI and ialloc btree blocks we need to keep + * around for xfs_dilocate(). We choose which one to use in + * xfs_mount_int(). + */ +#define XFS_INODE_BIG_CLUSTER_SIZE 8192 +#define XFS_INODE_SMALL_CLUSTER_SIZE 4096 +#define XFS_INODE_CLUSTER_SIZE(mp) (mp)->m_inode_cluster_size + +/* + * Make an inode pointer out of the buffer/offset. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MAKE_IPTR) +struct xfs_dinode *xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o); +#define XFS_MAKE_IPTR(mp,b,o) xfs_make_iptr(mp,b,o) +#else +#define XFS_MAKE_IPTR(mp,b,o) \ + ((xfs_dinode_t *)(xfs_buf_offset(b, (o) << (mp)->m_sb.sb_inodelog))) +#endif + +/* + * Find a free (set) bit in the inode bitmask. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IALLOC_FIND_FREE) +int xfs_ialloc_find_free(xfs_inofree_t *fp); +#define XFS_IALLOC_FIND_FREE(fp) xfs_ialloc_find_free(fp) +#else +#define XFS_IALLOC_FIND_FREE(fp) xfs_lowbit64(*(fp)) +#endif + + +#ifdef __KERNEL__ + +/* + * Prototypes for visible xfs_ialloc.c routines. + */ + +/* + * Allocate an inode on disk. + * Mode is used to tell whether the new inode will need space, and whether + * it is a directory. + * + * To work within the constraint of one allocation per transaction, + * xfs_dialloc() is designed to be called twice if it has to do an + * allocation to make more free inodes. If an inode is + * available without an allocation, agbp would be set to the current + * agbp and alloc_done set to false. + * If an allocation needed to be done, agbp would be set to the + * inode header of the allocation group and alloc_done set to true. + * The caller should then commit the current transaction and allocate a new + * transaction. xfs_dialloc() should then be called again with + * the agbp value returned from the previous call. + * + * Once we successfully pick an inode its number is returned and the + * on-disk data structures are updated. The inode itself is not read + * in, since doing so would break ordering constraints with xfs_reclaim. + * + * *agbp should be set to NULL on the first call, *alloc_done set to FALSE. + */ +int /* error */ +xfs_dialloc( + struct xfs_trans *tp, /* transaction pointer */ + xfs_ino_t parent, /* parent inode (directory) */ + mode_t mode, /* mode bits for new inode */ + int okalloc, /* ok to allocate more space */ + struct xfs_buf **agbp, /* buf for a.g. inode header */ + boolean_t *alloc_done, /* an allocation was done to replenish + the free inodes */ + xfs_ino_t *inop); /* inode number allocated */ + +/* + * Free disk inode. Carefully avoids touching the incore inode, all + * manipulations incore are the caller's responsibility. + * The on-disk inode is not changed by this operation, only the + * btree (free inode mask) is changed. + */ +int /* error */ +xfs_difree( + struct xfs_trans *tp, /* transaction pointer */ + xfs_ino_t inode); /* inode to be freed */ + +/* + * Return the location of the inode in bno/len/off, + * for mapping it into a buffer. + */ +int +xfs_dilocate( + struct xfs_mount *mp, /* file system mount structure */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_ino_t ino, /* inode to locate */ + xfs_fsblock_t *bno, /* output: block containing inode */ + int *len, /* output: num blocks in cluster*/ + int *off, /* output: index in block of inode */ + uint flags); /* flags for inode btree lookup */ + +/* + * Compute and fill in value of m_in_maxlevels. + */ +void +xfs_ialloc_compute_maxlevels( + struct xfs_mount *mp); /* file system mount structure */ + +/* + * Log specified fields for the ag hdr (inode section) + */ +void +xfs_ialloc_log_agi( + struct xfs_trans *tp, /* transaction pointer */ + struct xfs_buf *bp, /* allocation group header buffer */ + int fields); /* bitmask of fields to log */ + +/* + * Read in the allocation group header (inode allocation section) + */ +int /* error */ +xfs_ialloc_read_agi( + struct xfs_mount *mp, /* file system mount structure */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_agnumber_t agno, /* allocation group number */ + struct xfs_buf **bpp); /* allocation group hdr buf */ + +#endif /* __KERNEL__ */ + +#endif /* __XFS_IALLOC_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_ialloc_btree.c linux-2.4-xfs/linux/fs/xfs/xfs_ialloc_btree.c --- linux-2.4.7/linux/fs/xfs/xfs_ialloc_btree.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_ialloc_btree.c Thu Apr 12 18:35:02 2001 @@ -0,0 +1,2104 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Inode allocation management for XFS. + */ + +#include + + +/* + * Prototypes for internal functions. + */ + +STATIC void xfs_inobt_log_block(xfs_trans_t *, xfs_buf_t *, int); +STATIC void xfs_inobt_log_keys(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC void xfs_inobt_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC void xfs_inobt_log_recs(xfs_btree_cur_t *, xfs_buf_t *, int, int); +STATIC int xfs_inobt_lshift(xfs_btree_cur_t *, int, int *); +STATIC int xfs_inobt_newroot(xfs_btree_cur_t *, int *); +STATIC int xfs_inobt_rshift(xfs_btree_cur_t *, int, int *); +STATIC int xfs_inobt_split(xfs_btree_cur_t *, int, xfs_agblock_t *, + xfs_inobt_key_t *, xfs_btree_cur_t **, int *); +STATIC int xfs_inobt_updkey(xfs_btree_cur_t *, xfs_inobt_key_t *, int); + +/* + * Internal functions. + */ + +#ifdef _NOTYET_ +/* + * Single level of the xfs_inobt_delete record deletion routine. + * Delete record pointed to by cur/level. + * Remove the record from its block then rebalance the tree. + * Return 0 for error, 1 for done, 2 to go on to the next level. + */ +STATIC int /* error */ +xfs_inobt_delrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level removing record from */ + int *stat) /* fail/done/go-on */ +{ + xfs_buf_t *agbp; /* buffer for a.g. inode header */ + xfs_agnumber_t agfbno; /* agf block of freed btree block */ + xfs_buf_t *agfbp; /* bp of agf block of freed block */ + xfs_agi_t *agi; /* allocation group inode header */ + xfs_inobt_block_t *block; /* btree block record/key lives in */ + xfs_agblock_t bno; /* btree block number */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ + int i; /* loop index */ + xfs_inobt_key_t key; /* kp points here if block is level 0 */ + xfs_inobt_key_t *kp; /* pointer to btree keys */ + xfs_agblock_t lbno; /* left block's block number */ + xfs_buf_t *lbp; /* left block's buffer pointer */ + xfs_inobt_block_t *left; /* left btree block */ + xfs_inobt_key_t *lkp; /* left block key pointer */ + xfs_inobt_ptr_t *lpp; /* left block address pointer */ + int lrecs; /* number of records in left block */ + xfs_inobt_rec_t *lrp; /* left block record pointer */ + xfs_inobt_ptr_t *pp; /* pointer to btree addresses */ + int ptr; /* index in btree block for this rec */ + xfs_agblock_t rbno; /* right block's block number */ + xfs_buf_t *rbp; /* right block's buffer pointer */ + xfs_inobt_block_t *right; /* right btree block */ + xfs_inobt_key_t *rkp; /* right block key pointer */ + xfs_inobt_rec_t *rp; /* pointer to btree records */ + xfs_inobt_ptr_t *rpp; /* right block address pointer */ + int rrecs; /* number of records in right block */ + xfs_inobt_rec_t *rrp; /* right block record pointer */ + xfs_btree_cur_t *tcur; /* temporary btree cursor */ + + + /* + * Get the index of the entry being deleted, check for nothing there. + */ + ptr = cur->bc_ptrs[level]; + if (ptr == 0) { + *stat = 0; + return 0; + } + /* + * Get the buffer & block containing the record or key/ptr. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if (error = xfs_btree_check_sblock(cur, block, level, bp)) + return error; +#endif + /* + * Fail if we're off the end of the block. + */ + if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + *stat = 0; + return 0; + } + /* + * It's a nonleaf. Excise the key and ptr being deleted, by + * sliding the entries past them down one. + * Log the changed areas of the block. + */ + if (level > 0) { + kp = XFS_INOBT_KEY_ADDR(block, 1, cur); + pp = XFS_INOBT_PTR_ADDR(block, 1, cur); +#ifdef DEBUG + for (i = ptr; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) { + if (error = xfs_btree_check_sptr(cur, INT_GET(pp[i], ARCH_CONVERT), level)) + return error; + } +#endif + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ovbcopy(&kp[ptr], &kp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*kp)); + ovbcopy(&pp[ptr], &pp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*pp)); + xfs_inobt_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + xfs_inobt_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + } + } + /* + * It's a leaf. Excise the record being deleted, by sliding the + * entries past it down one. Log the changed areas of the block. + */ + else { + rp = XFS_INOBT_REC_ADDR(block, 1, cur); + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + ovbcopy(&rp[ptr], &rp[ptr - 1], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr) * sizeof(*rp)); + xfs_inobt_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1); + } + /* + * If it's the first record in the block, we'll need a key + * structure to pass up to the next level (updkey). + */ + if (ptr == 1) { + INT_COPY(key.ir_startino, rp->ir_startino, ARCH_CONVERT); + kp = &key; + } + } + /* + * Decrement and log the number of entries in the block. + */ + INT_MOD(block->bb_numrecs, ARCH_CONVERT, -1); + xfs_inobt_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS); + /* + * Is this the root level? If so, we're almost done. + */ + if (level == cur->bc_nlevels - 1) { + /* + * If this is the root level, + * and there's only one entry left, + * and it's NOT the leaf level, + * then we can get rid of this level. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) == 1 && level > 0) { + agbp = cur->bc_private.i.agbp; + agi = XFS_BUF_TO_AGI(agbp); + /* + * pp is still set to the first pointer in the block. + * Make it the new root of the btree. + */ + bno = INT_GET(agi->agi_root, ARCH_CONVERT); + INT_COPY(agi->agi_root, *pp, ARCH_CONVERT); + INT_MOD(agi->agi_level, ARCH_CONVERT, -1); + /* + * Free the block. + */ + if (error = xfs_free_extent(cur->bc_tp, bno, 1)) + return error; + xfs_trans_binval(cur->bc_tp, bp); + xfs_ialloc_log_agi(cur->bc_tp, agbp, + XFS_AGI_ROOT | XFS_AGI_LEVEL); + /* + * Update the cursor so there's one fewer level. + */ + cur->bc_bufs[level] = NULL; + cur->bc_nlevels--; + /* + * To ensure that the freed block is not used for + * user data until this transaction is permanent, + * we lock the agf buffer for this ag until the + * transaction record makes it to the on-disk log. + */ + agfbno = XFS_AG_DADDR(cur->bc_mp, + cur->bc_private.i.agno, + XFS_AGF_DADDR); + if (error = xfs_trans_read_buf(cur->bc_mp, cur->bc_tp, + cur->bc_mp->m_ddev_targp, agfbno, 1, 0, + &agfbp)) + return error; + ASSERT(!XFS_BUF_GETERROR(agfbp)); + xfs_trans_bhold_until_committed(cur->bc_tp, agfbp); + } else if (level > 0 && + (error = xfs_inobt_decrement(cur, level, &i))) + return error; + *stat = 1; + return 0; + } + /* + * If we deleted the leftmost entry in the block, update the + * key values above us in the tree. + */ + if (ptr == 1 && (error = xfs_inobt_updkey(cur, kp, level + 1))) + return error; + /* + * If the number of records remaining in the block is at least + * the minimum, we're done. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) >= XFS_INOBT_BLOCK_MINRECS(level, cur)) { + if (level > 0 && + (error = xfs_inobt_decrement(cur, level, &i))) + return error; + *stat = 1; + return 0; + } + /* + * Otherwise, we have to move some records around to keep the + * tree balanced. Look at the left and right sibling blocks to + * see if we can re-balance by moving only one record. + */ + rbno = INT_GET(block->bb_rightsib, ARCH_CONVERT); + lbno = INT_GET(block->bb_leftsib, ARCH_CONVERT); + bno = NULLAGBLOCK; + ASSERT(rbno != NULLAGBLOCK || lbno != NULLAGBLOCK); + /* + * Duplicate the cursor so our btree manipulations here won't + * disrupt the next level up. + */ + if (error = xfs_btree_dup_cursor(cur, &tcur)) + return error; + /* + * If there's a right sibling, see if it's ok to shift an entry + * out of it. + */ + if (rbno != NULLAGBLOCK) { + /* + * Move the temp cursor to the last entry in the next block. + * Actually any entry but the first would suffice. + */ + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + if (error = xfs_inobt_increment(tcur, level, &i)) + goto error0; + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + i = xfs_btree_lastrec(tcur, level); + XFS_WANT_CORRUPTED_GOTO(i == 1, error0); + /* + * Grab a pointer to the block. + */ + rbp = tcur->bc_bufs[level]; + right = XFS_BUF_TO_INOBT_BLOCK(rbp); +#ifdef DEBUG + if (error = xfs_btree_check_sblock(cur, right, level, rbp)) + goto error0; +#endif + /* + * Grab the current block number, for future use. + */ + bno = INT_GET(right->bb_leftsib, ARCH_CONVERT); + /* + * If right block is full enough so that removing one entry + * won't make it too empty, and left-shifting an entry out + * of right to us works, we're done. + */ + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_INOBT_BLOCK_MINRECS(level, cur)) { + if (error = xfs_inobt_lshift(tcur, level, &i)) + goto error0; + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_INOBT_BLOCK_MINRECS(level, cur)); + xfs_btree_del_cursor(tcur, + XFS_BTREE_NOERROR); + if (level > 0 && + (error = xfs_inobt_decrement(cur, level, + &i))) + return error; + *stat = 1; + return 0; + } + } + /* + * Otherwise, grab the number of records in right for + * future reference, and fix up the temp cursor to point + * to our block again (last record). + */ + rrecs = INT_GET(right->bb_numrecs, ARCH_CONVERT); + if (lbno != NULLAGBLOCK) { + xfs_btree_firstrec(tcur, level); + if (error = xfs_inobt_decrement(tcur, level, &i)) + goto error0; + } + } + /* + * If there's a left sibling, see if it's ok to shift an entry + * out of it. + */ + if (lbno != NULLAGBLOCK) { + /* + * Move the temp cursor to the first entry in the + * previous block. + */ + xfs_btree_firstrec(tcur, level); + if (error = xfs_inobt_decrement(tcur, level, &i)) + goto error0; + xfs_btree_firstrec(tcur, level); + /* + * Grab a pointer to the block. + */ + lbp = tcur->bc_bufs[level]; + left = XFS_BUF_TO_INOBT_BLOCK(lbp); +#ifdef DEBUG + if (error = xfs_btree_check_sblock(cur, left, level, lbp)) + goto error0; +#endif + /* + * Grab the current block number, for future use. + */ + bno = INT_GET(left->bb_rightsib, ARCH_CONVERT); + /* + * If left block is full enough so that removing one entry + * won't make it too empty, and right-shifting an entry out + * of left to us works, we're done. + */ + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) - 1 >= + XFS_INOBT_BLOCK_MINRECS(level, cur)) { + if (error = xfs_inobt_rshift(tcur, level, &i)) + goto error0; + if (i) { + ASSERT(INT_GET(block->bb_numrecs, ARCH_CONVERT) >= + XFS_INOBT_BLOCK_MINRECS(level, cur)); + xfs_btree_del_cursor(tcur, + XFS_BTREE_NOERROR); + if (level == 0) + cur->bc_ptrs[0]++; + *stat = 1; + return 0; + } + } + /* + * Otherwise, grab the number of records in right for + * future reference. + */ + lrecs = INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + /* + * Delete the temp cursor, we're done with it. + */ + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + /* + * If here, we need to do a join to keep the tree balanced. + */ + ASSERT(bno != NULLAGBLOCK); + /* + * See if we can join with the left neighbor block. + */ + if (lbno != NULLAGBLOCK && + lrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= XFS_INOBT_BLOCK_MAXRECS(level, cur)) { + /* + * Set "right" to be the starting block, + * "left" to be the left neighbor. + */ + rbno = bno; + right = block; + rbp = bp; + if (error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, lbno, 0, &lbp, + XFS_INO_BTREE_REF)) + return error; + left = XFS_BUF_TO_INOBT_BLOCK(lbp); + if (error = xfs_btree_check_sblock(cur, left, level, lbp)) + return error; + } + /* + * If that won't work, see if we can join with the right neighbor block. + */ + else if (rbno != NULLAGBLOCK && + rrecs + INT_GET(block->bb_numrecs, ARCH_CONVERT) <= + XFS_INOBT_BLOCK_MAXRECS(level, cur)) { + /* + * Set "left" to be the starting block, + * "right" to be the right neighbor. + */ + lbno = bno; + left = block; + lbp = bp; + if (error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, rbno, 0, &rbp, + XFS_INO_BTREE_REF)) + return error; + right = XFS_BUF_TO_INOBT_BLOCK(rbp); + if (error = xfs_btree_check_sblock(cur, right, level, rbp)) + return error; + } + /* + * Otherwise, we can't fix the imbalance. + * Just return. This is probably a logic error, but it's not fatal. + */ + else { + if (level > 0 && (error = xfs_inobt_decrement(cur, level, &i))) + return error; + *stat = 1; + return 0; + } + /* + * We're now going to join "left" and "right" by moving all the stuff + * in "right" to "left" and deleting "right". + */ + if (level > 0) { + /* + * It's a non-leaf. Move keys and pointers. + */ + lkp = XFS_INOBT_KEY_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + lpp = XFS_INOBT_PTR_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rkp = XFS_INOBT_KEY_ADDR(right, 1, cur); + rpp = XFS_INOBT_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if (error = xfs_btree_check_sptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level)) + return error; + } +#endif + bcopy(rkp, lkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lkp)); + bcopy(rpp, lpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lpp)); + xfs_inobt_log_keys(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_inobt_log_ptrs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } else { + /* + * It's a leaf. Move records. + */ + lrp = XFS_INOBT_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, cur); + rrp = XFS_INOBT_REC_ADDR(right, 1, cur); + bcopy(rrp, lrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*lrp)); + xfs_inobt_log_recs(cur, lbp, INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1, + INT_GET(left->bb_numrecs, ARCH_CONVERT) + INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } + /* + * Fix up the number of records in the surviving block. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + /* + * Fix up the right block pointer in the surviving block, and log it. + */ + INT_COPY(left->bb_rightsib, right->bb_rightsib, ARCH_CONVERT); + xfs_inobt_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); + /* + * If there is a right sibling now, make it point to the + * remaining block. + */ + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_inobt_block_t *rrblock; + xfs_buf_t *rrbp; + + if (error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, + &rrbp, XFS_INO_BTREE_REF)) + return error; + rrblock = XFS_BUF_TO_INOBT_BLOCK(rrbp); + if (error = xfs_btree_check_sblock(cur, rrblock, level, rrbp)) + return error; + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, lbno); + xfs_inobt_log_block(cur->bc_tp, rrbp, XFS_BB_LEFTSIB); + } + /* + * Free the deleting block. + */ + if (error = xfs_free_extent(cur->bc_tp, rbno, 1)) + return error; + xfs_trans_binval(cur->bc_tp, rbp); + /* + * To ensure that the freed block is not used for + * user data until this transaction is permanent, + * we lock the agf buffer for this ag until the + * transaction record makes it to the on-disk log. + */ + agfbno = XFS_AG_DADDR(cur->bc_mp, cur->bc_private.i.agno, + XFS_AGF_DADDR); + if (error = xfs_trans_read_buf(cur->bc_mp, cur->bc_tp, + cur->bc_mp->m_ddev_targp, agfbno, 1, 0, &agfbp)) + return error; + ASSERT(!XFS_BUF_GETERROR(agfbp)); + xfs_trans_bhold_until_committed(cur->bc_tp, agfbp); + /* + * If we joined with the left neighbor, set the buffer in the + * cursor to the left block, and fix up the index. + */ + if (bp != lbp) { + cur->bc_bufs[level] = lbp; + cur->bc_ptrs[level] += INT_GET(left->bb_numrecs, ARCH_CONVERT); + cur->bc_ra[level] = 0; + } + /* + * If we joined with the right neighbor and there's a level above + * us, increment the cursor at that level. + */ + else if (level + 1 < cur->bc_nlevels && + (error = xfs_inobt_increment(cur, level + 1, &i))) { + return error; + } + /* + * Readjust the ptr at this level if it's not a leaf, since it's + * still pointing at the deletion point, which makes the cursor + * inconsistent. If this makes the ptr 0, the caller fixes it up. + * We can't use decrement because it would change the next level up. + */ + if (level > 0) + cur->bc_ptrs[level]--; + /* + * Return value means the next level up has something to do. + */ + *stat = 2; + return 0; + +error0: + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; +} +#endif /* _NOTYET_ */ + +/* + * Insert one record/level. Return information to the caller + * allowing the next level up to proceed if necessary. + */ +STATIC int /* error */ +xfs_inobt_insrec( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to insert record at */ + xfs_agblock_t *bnop, /* i/o: block number inserted */ + xfs_inobt_rec_t *recp, /* i/o: record data inserted */ + xfs_btree_cur_t **curp, /* output: new cursor replacing cur */ + int *stat) /* success/failure */ +{ + xfs_inobt_block_t *block; /* btree block record/key lives in */ + xfs_buf_t *bp; /* buffer for block */ + int error; /* error return value */ + int i; /* loop index */ + xfs_inobt_key_t key; /* key value being inserted */ + xfs_inobt_key_t *kp=NULL; /* pointer to btree keys */ + xfs_agblock_t nbno; /* block number of allocated block */ + xfs_btree_cur_t *ncur; /* new cursor to be used at next lvl */ + xfs_inobt_key_t nkey; /* new key value, from split */ + xfs_inobt_rec_t nrec; /* new record value, for caller */ + int optr; /* old ptr value */ + xfs_inobt_ptr_t *pp; /* pointer to btree addresses */ + int ptr; /* index in btree block for this rec */ + xfs_inobt_rec_t *rp=NULL; /* pointer to btree records */ + + /* + * If we made it to the root level, allocate a new root block + * and we're done. + */ + if (level >= cur->bc_nlevels) { + error = xfs_inobt_newroot(cur, &i); + *bnop = NULLAGBLOCK; + *stat = i; + return error; + } + /* + * Make a key out of the record data to be inserted, and save it. + */ + key.ir_startino = recp->ir_startino; /* INT_: direct copy */ + optr = ptr = cur->bc_ptrs[level]; + /* + * If we're off the left edge, return failure. + */ + if (ptr == 0) { + *stat = 0; + return 0; + } + /* + * Get pointers to the btree buffer and block. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; + /* + * Check that the new entry is being inserted in the right place. + */ + if (ptr <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + if (level == 0) { + rp = XFS_INOBT_REC_ADDR(block, ptr, cur); + xfs_btree_check_rec(cur->bc_btnum, recp, rp); + } else { + kp = XFS_INOBT_KEY_ADDR(block, ptr, cur); + xfs_btree_check_key(cur->bc_btnum, &key, kp); + } + } +#endif + nbno = NULLAGBLOCK; + ncur = (xfs_btree_cur_t *)0; + /* + * If the block is full, we can't insert the new entry until we + * make the block un-full. + */ + if (INT_GET(block->bb_numrecs, ARCH_CONVERT) == XFS_INOBT_BLOCK_MAXRECS(level, cur)) { + /* + * First, try shifting an entry to the right neighbor. + */ + if ((error = xfs_inobt_rshift(cur, level, &i))) + return error; + if (i) { + /* nothing */ + } + /* + * Next, try shifting an entry to the left neighbor. + */ + else { + if ((error = xfs_inobt_lshift(cur, level, &i))) + return error; + if (i) { + optr = ptr = cur->bc_ptrs[level]; + } else { + /* + * Next, try splitting the current block + * in half. If this works we have to + * re-set our variables because + * we could be in a different block now. + */ + if ((error = xfs_inobt_split(cur, level, &nbno, + &nkey, &ncur, &i))) + return error; + if (i) { + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, + block, level, bp))) + return error; +#endif + ptr = cur->bc_ptrs[level]; + nrec.ir_startino = nkey.ir_startino; /* INT_: direct copy */ + } else { + /* + * Otherwise the insert fails. + */ + *stat = 0; + return 0; + } + } + } + } + /* + * At this point we know there's room for our new entry in the block + * we're pointing at. + */ + if (level > 0) { + /* + * It's a non-leaf entry. Make a hole for the new data + * in the key and ptr regions of the block. + */ + kp = XFS_INOBT_KEY_ADDR(block, 1, cur); + pp = XFS_INOBT_PTR_ADDR(block, 1, cur); +#ifdef DEBUG + for (i = INT_GET(block->bb_numrecs, ARCH_CONVERT); i >= ptr; i--) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(pp[i - 1], ARCH_CONVERT), level))) + return error; + } +#endif + ovbcopy(&kp[ptr - 1], &kp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*kp)); + ovbcopy(&pp[ptr - 1], &pp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*pp)); + /* + * Now stuff the new data in, bump numrecs and log the new data. + */ +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, *bnop, level))) + return error; +#endif + kp[ptr - 1] = key; /* INT_: struct copy */ + INT_SET(pp[ptr - 1], ARCH_CONVERT, *bnop); + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_inobt_log_keys(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + xfs_inobt_log_ptrs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + } else { + /* + * It's a leaf entry. Make a hole for the new record. + */ + rp = XFS_INOBT_REC_ADDR(block, 1, cur); + ovbcopy(&rp[ptr - 1], &rp[ptr], + (INT_GET(block->bb_numrecs, ARCH_CONVERT) - ptr + 1) * sizeof(*rp)); + /* + * Now stuff the new record in, bump numrecs + * and log the new data. + */ + rp[ptr - 1] = *recp; /* INT_: struct copy */ + INT_MOD(block->bb_numrecs, ARCH_CONVERT, +1); + xfs_inobt_log_recs(cur, bp, ptr, INT_GET(block->bb_numrecs, ARCH_CONVERT)); + } + /* + * Log the new number of records in the btree header. + */ + xfs_inobt_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS); +#ifdef DEBUG + /* + * Check that the key/record is in the right place, now. + */ + if (ptr < INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + if (level == 0) + xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1, + rp + ptr); + else + xfs_btree_check_key(cur->bc_btnum, kp + ptr - 1, + kp + ptr); + } +#endif + /* + * If we inserted at the start of a block, update the parents' keys. + */ + if (optr == 1 && (error = xfs_inobt_updkey(cur, &key, level + 1))) + return error; + /* + * Return the new block number, if any. + * If there is one, give back a record value and a cursor too. + */ + *bnop = nbno; + if (nbno != NULLAGBLOCK) { + *recp = nrec; /* INT_: struct copy */ + *curp = ncur; + } + *stat = 1; + return 0; +} + +/* + * Log header fields from a btree block. + */ +STATIC void +xfs_inobt_log_block( + xfs_trans_t *tp, /* transaction pointer */ + xfs_buf_t *bp, /* buffer containing btree block */ + int fields) /* mask of fields: XFS_BB_... */ +{ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + static const short offsets[] = { /* table of offsets */ + offsetof(xfs_inobt_block_t, bb_magic), + offsetof(xfs_inobt_block_t, bb_level), + offsetof(xfs_inobt_block_t, bb_numrecs), + offsetof(xfs_inobt_block_t, bb_leftsib), + offsetof(xfs_inobt_block_t, bb_rightsib), + sizeof(xfs_inobt_block_t) + }; + + xfs_btree_offsets(fields, offsets, XFS_BB_NUM_BITS, &first, &last); + xfs_trans_log_buf(tp, bp, first, last); +} + +/* + * Log keys from a btree block (nonleaf). + */ +STATIC void +xfs_inobt_log_keys( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int kfirst, /* index of first key to log */ + int klast) /* index of last key to log */ +{ + xfs_inobt_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + xfs_inobt_key_t *kp; /* key pointer in btree block */ + int last; /* last byte offset logged */ + + block = XFS_BUF_TO_INOBT_BLOCK(bp); + kp = XFS_INOBT_KEY_ADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&kp[kfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&kp[klast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Log block pointer fields from a btree block (nonleaf). + */ +STATIC void +xfs_inobt_log_ptrs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int pfirst, /* index of first pointer to log */ + int plast) /* index of last pointer to log */ +{ + xfs_inobt_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + xfs_inobt_ptr_t *pp; /* block-pointer pointer in btree blk */ + + block = XFS_BUF_TO_INOBT_BLOCK(bp); + pp = XFS_INOBT_PTR_ADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&pp[pfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&pp[plast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Log records from a btree block (leaf). + */ +STATIC void +xfs_inobt_log_recs( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_buf_t *bp, /* buffer containing btree block */ + int rfirst, /* index of first record to log */ + int rlast) /* index of last record to log */ +{ + xfs_inobt_block_t *block; /* btree block to log from */ + int first; /* first byte offset logged */ + int last; /* last byte offset logged */ + xfs_inobt_rec_t *rp; /* record pointer for btree block */ + + block = XFS_BUF_TO_INOBT_BLOCK(bp); + rp = XFS_INOBT_REC_ADDR(block, 1, cur); + first = (int)((xfs_caddr_t)&rp[rfirst - 1] - (xfs_caddr_t)block); + last = (int)(((xfs_caddr_t)&rp[rlast] - 1) - (xfs_caddr_t)block); + xfs_trans_log_buf(cur->bc_tp, bp, first, last); +} + +/* + * Lookup the record. The cursor is made to point to it, based on dir. + * Return 0 if can't find any such record, 1 for success. + */ +STATIC int /* error */ +xfs_inobt_lookup( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_lookup_t dir, /* <=, ==, or >= */ + int *stat) /* success/failure */ +{ + xfs_agblock_t agbno; /* a.g. relative btree block number */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_inobt_block_t *block=NULL; /* current btree block */ + int diff; /* difference for the current key */ + int error; /* error return value */ + int keyno=0; /* current key number */ + int level; /* level in the btree */ + xfs_mount_t *mp; /* file system mount point */ + + /* + * Get the allocation group header, and the root block number. + */ + mp = cur->bc_mp; + { + xfs_agi_t *agi; /* a.g. inode header */ + + agi = XFS_BUF_TO_AGI(cur->bc_private.i.agbp); + agno = INT_GET(agi->agi_seqno, ARCH_CONVERT); + agbno = INT_GET(agi->agi_root, ARCH_CONVERT); + } + /* + * Iterate over each level in the btree, starting at the root. + * For each level above the leaves, find the key we need, based + * on the lookup record, then follow the corresponding block + * pointer down to the next level. + */ + for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) { + xfs_buf_t *bp; /* buffer pointer for btree block */ + xfs_daddr_t d; /* disk address of btree block */ + + /* + * Get the disk address we're looking for. + */ + d = XFS_AGB_TO_DADDR(mp, agno, agbno); + /* + * If the old buffer at this level is for a different block, + * throw it away, otherwise just use it. + */ + bp = cur->bc_bufs[level]; + if (bp && XFS_BUF_ADDR(bp) != d) + bp = (xfs_buf_t *)0; + if (!bp) { + /* + * Need to get a new buffer. Read it, then + * set it in the cursor, releasing the old one. + */ + if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, + agno, agbno, 0, &bp, XFS_INO_BTREE_REF))) + return error; + xfs_btree_setbuf(cur, level, bp); + /* + * Point to the btree block, now that we have the buffer + */ + block = XFS_BUF_TO_INOBT_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, level, + bp))) + return error; + } else + block = XFS_BUF_TO_INOBT_BLOCK(bp); + /* + * If we already had a key match at a higher level, we know + * we need to use the first entry in this block. + */ + if (diff == 0) + keyno = 1; + /* + * Otherwise we need to search this block. Do a binary search. + */ + else { + int high; /* high entry number */ + xfs_inobt_key_t *kkbase=NULL;/* base of keys in block */ + xfs_inobt_rec_t *krbase=NULL;/* base of records in block */ + int low; /* low entry number */ + + /* + * Get a pointer to keys or records. + */ + if (level > 0) + kkbase = XFS_INOBT_KEY_ADDR(block, 1, cur); + else + krbase = XFS_INOBT_REC_ADDR(block, 1, cur); + /* + * Set low and high entry numbers, 1-based. + */ + low = 1; + if (!(high = INT_GET(block->bb_numrecs, ARCH_CONVERT))) { + /* + * If the block is empty, the tree must + * be an empty leaf. + */ + ASSERT(level == 0 && cur->bc_nlevels == 1); + cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE; + *stat = 0; + return 0; + } + /* + * Binary search the block. + */ + while (low <= high) { + xfs_agino_t startino; /* key value */ + + /* + * keyno is average of low and high. + */ + keyno = (low + high) >> 1; + /* + * Get startino. + */ + if (level > 0) { + xfs_inobt_key_t *kkp; + + kkp = kkbase + keyno - 1; + startino = INT_GET(kkp->ir_startino, ARCH_CONVERT); + } else { + xfs_inobt_rec_t *krp; + + krp = krbase + keyno - 1; + startino = INT_GET(krp->ir_startino, ARCH_CONVERT); + } + /* + * Compute difference to get next direction. + */ + diff = (int)startino - cur->bc_rec.i.ir_startino; + /* + * Less than, move right. + */ + if (diff < 0) + low = keyno + 1; + /* + * Greater than, move left. + */ + else if (diff > 0) + high = keyno - 1; + /* + * Equal, we're done. + */ + else + break; + } + } + /* + * If there are more levels, set up for the next level + * by getting the block number and filling in the cursor. + */ + if (level > 0) { + /* + * If we moved left, need the previous key number, + * unless there isn't one. + */ + if (diff > 0 && --keyno < 1) + keyno = 1; + agbno = INT_GET(*XFS_INOBT_PTR_ADDR(block, keyno, cur), ARCH_CONVERT); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, agbno, level))) + return error; +#endif + cur->bc_ptrs[level] = keyno; + } + } + /* + * Done with the search. + * See if we need to adjust the results. + */ + if (dir != XFS_LOOKUP_LE && diff < 0) { + keyno++; + /* + * If ge search and we went off the end of the block, but it's + * not the last block, we're in the wrong block. + */ + if (dir == XFS_LOOKUP_GE && + keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT) && + INT_GET(block->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + int i; + + cur->bc_ptrs[0] = keyno; + if ((error = xfs_inobt_increment(cur, 0, &i))) + return error; + ASSERT(i == 1); + *stat = 1; + return 0; + } + } + else if (dir == XFS_LOOKUP_LE && diff > 0) + keyno--; + cur->bc_ptrs[0] = keyno; + /* + * Return if we succeeded or not. + */ + if (keyno == 0 || keyno > INT_GET(block->bb_numrecs, ARCH_CONVERT)) + *stat = 0; + else + *stat = ((dir != XFS_LOOKUP_EQ) || (diff == 0)); + return 0; +} + +/* + * Move 1 record left from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_inobt_lshift( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to shift record on */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ +#ifdef DEBUG + int i; /* loop index */ +#endif + xfs_inobt_key_t key; /* key value for leaf level upward */ + xfs_buf_t *lbp; /* buffer for left neighbor block */ + xfs_inobt_block_t *left; /* left neighbor btree block */ + xfs_inobt_key_t *lkp=NULL; /* key pointer for left block */ + xfs_inobt_ptr_t *lpp; /* address pointer for left block */ + xfs_inobt_rec_t *lrp=NULL; /* record pointer for left block */ + int nrec; /* new number of left block entries */ + xfs_buf_t *rbp; /* buffer for right (current) block */ + xfs_inobt_block_t *right; /* right (current) btree block */ + xfs_inobt_key_t *rkp=NULL; /* key pointer for right block */ + xfs_inobt_ptr_t *rpp=NULL; /* address pointer for right block */ + xfs_inobt_rec_t *rrp=NULL; /* record pointer for right block */ + + /* + * Set up variables for this block as "right". + */ + rbp = cur->bc_bufs[level]; + right = XFS_BUF_TO_INOBT_BLOCK(rbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + return error; +#endif + /* + * If we've got no left sibling then we can't shift an entry left. + */ + if (INT_GET(right->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * If the cursor entry is the one that would be moved, don't + * do it... it's too complicated. + */ + if (cur->bc_ptrs[level] <= 1) { + *stat = 0; + return 0; + } + /* + * Set up the left neighbor as "left". + */ + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, INT_GET(right->bb_leftsib, ARCH_CONVERT), 0, &lbp, + XFS_INO_BTREE_REF))) + return error; + left = XFS_BUF_TO_INOBT_BLOCK(lbp); + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; + /* + * If it's full, it can't take another entry. + */ + if (INT_GET(left->bb_numrecs, ARCH_CONVERT) == XFS_INOBT_BLOCK_MAXRECS(level, cur)) { + *stat = 0; + return 0; + } + nrec = INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1; + /* + * If non-leaf, copy a key and a ptr to the left block. + */ + if (level > 0) { + lkp = XFS_INOBT_KEY_ADDR(left, nrec, cur); + rkp = XFS_INOBT_KEY_ADDR(right, 1, cur); + *lkp = *rkp; + xfs_inobt_log_keys(cur, lbp, nrec, nrec); + lpp = XFS_INOBT_PTR_ADDR(left, nrec, cur); + rpp = XFS_INOBT_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, INT_GET(*rpp, ARCH_CONVERT), level))) + return error; +#endif + *lpp = *rpp; /* INT_: no-change copy */ + xfs_inobt_log_ptrs(cur, lbp, nrec, nrec); + } + /* + * If leaf, copy a record to the left block. + */ + else { + lrp = XFS_INOBT_REC_ADDR(left, nrec, cur); + rrp = XFS_INOBT_REC_ADDR(right, 1, cur); + *lrp = *rrp; + xfs_inobt_log_recs(cur, lbp, nrec, nrec); + } + /* + * Bump and log left's numrecs, decrement and log right's numrecs. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, +1); + xfs_inobt_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); +#ifdef DEBUG + if (level > 0) + xfs_btree_check_key(cur->bc_btnum, lkp - 1, lkp); + else + xfs_btree_check_rec(cur->bc_btnum, lrp - 1, lrp); +#endif + INT_MOD(right->bb_numrecs, ARCH_CONVERT, -1); + xfs_inobt_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); + /* + * Slide the contents of right down one entry. + */ + if (level > 0) { +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i + 1], ARCH_CONVERT), + level))) + return error; + } +#endif + ovbcopy(rkp + 1, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp + 1, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); + xfs_inobt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_inobt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + } else { + ovbcopy(rrp + 1, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_inobt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + key.ir_startino = rrp->ir_startino; /* INT_: direct copy */ + rkp = &key; + } + /* + * Update the parent key values of right. + */ + if ((error = xfs_inobt_updkey(cur, rkp, level + 1))) + return error; + /* + * Slide the cursor value left one. + */ + cur->bc_ptrs[level]--; + *stat = 1; + return 0; +} + +/* + * Allocate a new root block, fill it in. + */ +STATIC int /* error */ +xfs_inobt_newroot( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + xfs_agi_t *agi; /* a.g. inode header */ + xfs_alloc_arg_t args; /* allocation argument structure */ + xfs_inobt_block_t *block; /* one half of the old root block */ + xfs_buf_t *bp; /* buffer containing block */ + int error; /* error return value */ + xfs_inobt_key_t *kp; /* btree key pointer */ + xfs_agblock_t lbno; /* left block number */ + xfs_buf_t *lbp; /* left buffer pointer */ + xfs_inobt_block_t *left; /* left btree block */ + xfs_buf_t *nbp; /* new (root) buffer */ + xfs_inobt_block_t *new; /* new (root) btree block */ + int nptr; /* new value for key index, 1 or 2 */ + xfs_inobt_ptr_t *pp; /* btree address pointer */ + xfs_agblock_t rbno; /* right block number */ + xfs_buf_t *rbp; /* right buffer pointer */ + xfs_inobt_block_t *right; /* right btree block */ + xfs_inobt_rec_t *rp; /* btree record pointer */ + + ASSERT(cur->bc_nlevels < XFS_IN_MAXLEVELS(cur->bc_mp)); + + /* + * Get a block & a buffer. + */ + agi = XFS_BUF_TO_AGI(cur->bc_private.i.agbp); + args.tp = cur->bc_tp; + args.mp = cur->bc_mp; + args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.i.agno, + INT_GET(agi->agi_root, ARCH_CONVERT)); + args.mod = args.minleft = args.alignment = args.total = args.wasdel = + args.isfl = args.userdata = args.minalignslop = 0; + args.minlen = args.maxlen = args.prod = 1; + args.type = XFS_ALLOCTYPE_NEAR_BNO; + if ((error = xfs_alloc_vextent(&args))) + return error; + /* + * None available, we fail. + */ + if (args.fsbno == NULLFSBLOCK) { + *stat = 0; + return 0; + } + ASSERT(args.len == 1); + nbp = xfs_btree_get_bufs(args.mp, args.tp, args.agno, args.agbno, 0); + new = XFS_BUF_TO_INOBT_BLOCK(nbp); + /* + * Set the root data in the a.g. inode structure. + */ + INT_SET(agi->agi_root, ARCH_CONVERT, args.agbno); + INT_MOD(agi->agi_level, ARCH_CONVERT, 1); + xfs_ialloc_log_agi(args.tp, cur->bc_private.i.agbp, + XFS_AGI_ROOT | XFS_AGI_LEVEL); + /* + * At the previous root level there are now two blocks: the old + * root, and the new block generated when it was split. + * We don't know which one the cursor is pointing at, so we + * set up variables "left" and "right" for each case. + */ + bp = cur->bc_bufs[cur->bc_nlevels - 1]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, cur->bc_nlevels - 1, bp))) + return error; +#endif + if (INT_GET(block->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + /* + * Our block is left, pick up the right block. + */ + lbp = bp; + lbno = XFS_DADDR_TO_AGBNO(args.mp, XFS_BUF_ADDR(lbp)); + left = block; + rbno = INT_GET(left->bb_rightsib, ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(args.mp, args.tp, args.agno, + rbno, 0, &rbp, XFS_INO_BTREE_REF))) + return error; + bp = rbp; + right = XFS_BUF_TO_INOBT_BLOCK(rbp); + if ((error = xfs_btree_check_sblock(cur, right, + cur->bc_nlevels - 1, rbp))) + return error; + nptr = 1; + } else { + /* + * Our block is right, pick up the left block. + */ + rbp = bp; + rbno = XFS_DADDR_TO_AGBNO(args.mp, XFS_BUF_ADDR(rbp)); + right = block; + lbno = INT_GET(right->bb_leftsib, ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(args.mp, args.tp, args.agno, + lbno, 0, &lbp, XFS_INO_BTREE_REF))) + return error; + bp = lbp; + left = XFS_BUF_TO_INOBT_BLOCK(lbp); + if ((error = xfs_btree_check_sblock(cur, left, + cur->bc_nlevels - 1, lbp))) + return error; + nptr = 2; + } + /* + * Fill in the new block's btree header and log it. + */ + INT_SET(new->bb_magic, ARCH_CONVERT, xfs_magics[cur->bc_btnum]); + INT_SET(new->bb_level, ARCH_CONVERT, (__uint16_t)cur->bc_nlevels); + INT_SET(new->bb_numrecs, ARCH_CONVERT, 2); + INT_SET(new->bb_leftsib, ARCH_CONVERT, NULLAGBLOCK); + INT_SET(new->bb_rightsib, ARCH_CONVERT, NULLAGBLOCK); + xfs_inobt_log_block(args.tp, nbp, XFS_BB_ALL_BITS); + ASSERT(lbno != NULLAGBLOCK && rbno != NULLAGBLOCK); + /* + * Fill in the key data in the new root. + */ + kp = XFS_INOBT_KEY_ADDR(new, 1, cur); + if (INT_GET(left->bb_level, ARCH_CONVERT) > 0) { + kp[0] = *XFS_INOBT_KEY_ADDR(left, 1, cur); /* INT_: struct copy */ + kp[1] = *XFS_INOBT_KEY_ADDR(right, 1, cur); /* INT_: struct copy */ + } else { + rp = XFS_INOBT_REC_ADDR(left, 1, cur); + INT_COPY(kp[0].ir_startino, rp->ir_startino, ARCH_CONVERT); + rp = XFS_INOBT_REC_ADDR(right, 1, cur); + INT_COPY(kp[1].ir_startino, rp->ir_startino, ARCH_CONVERT); + } + xfs_inobt_log_keys(cur, nbp, 1, 2); + /* + * Fill in the pointer data in the new root. + */ + pp = XFS_INOBT_PTR_ADDR(new, 1, cur); + INT_SET(pp[0], ARCH_CONVERT, lbno); + INT_SET(pp[1], ARCH_CONVERT, rbno); + xfs_inobt_log_ptrs(cur, nbp, 1, 2); + /* + * Fix up the cursor. + */ + xfs_btree_setbuf(cur, cur->bc_nlevels, nbp); + cur->bc_ptrs[cur->bc_nlevels] = nptr; + cur->bc_nlevels++; + *stat = 1; + return 0; +} + +/* + * Move 1 record right from cur/level if possible. + * Update cur to reflect the new path. + */ +STATIC int /* error */ +xfs_inobt_rshift( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to shift record on */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* loop index */ + xfs_inobt_key_t key; /* key value for leaf level upward */ + xfs_buf_t *lbp; /* buffer for left (current) block */ + xfs_inobt_block_t *left; /* left (current) btree block */ + xfs_inobt_key_t *lkp; /* key pointer for left block */ + xfs_inobt_ptr_t *lpp; /* address pointer for left block */ + xfs_inobt_rec_t *lrp; /* record pointer for left block */ + xfs_buf_t *rbp; /* buffer for right neighbor block */ + xfs_inobt_block_t *right; /* right neighbor btree block */ + xfs_inobt_key_t *rkp; /* key pointer for right block */ + xfs_inobt_ptr_t *rpp; /* address pointer for right block */ + xfs_inobt_rec_t *rrp=NULL; /* record pointer for right block */ + xfs_btree_cur_t *tcur; /* temporary cursor */ + + /* + * Set up variables for this block as "left". + */ + lbp = cur->bc_bufs[level]; + left = XFS_BUF_TO_INOBT_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; +#endif + /* + * If we've got no right sibling then we can't shift an entry right. + */ + if (INT_GET(left->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * If the cursor entry is the one that would be moved, don't + * do it... it's too complicated. + */ + if (cur->bc_ptrs[level] >= INT_GET(left->bb_numrecs, ARCH_CONVERT)) { + *stat = 0; + return 0; + } + /* + * Set up the right neighbor as "right". + */ + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, INT_GET(left->bb_rightsib, ARCH_CONVERT), 0, &rbp, + XFS_INO_BTREE_REF))) + return error; + right = XFS_BUF_TO_INOBT_BLOCK(rbp); + if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) + return error; + /* + * If it's full, it can't take another entry. + */ + if (INT_GET(right->bb_numrecs, ARCH_CONVERT) == XFS_INOBT_BLOCK_MAXRECS(level, cur)) { + *stat = 0; + return 0; + } + /* + * Make a hole at the start of the right neighbor block, then + * copy the last left block entry to the hole. + */ + if (level > 0) { + lkp = XFS_INOBT_KEY_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + lpp = XFS_INOBT_PTR_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rkp = XFS_INOBT_KEY_ADDR(right, 1, cur); + rpp = XFS_INOBT_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = INT_GET(right->bb_numrecs, ARCH_CONVERT) - 1; i >= 0; i--) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + ovbcopy(rkp, rkp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + ovbcopy(rpp, rpp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); +#ifdef DEBUG + if ((error = xfs_btree_check_sptr(cur, INT_GET(*lpp, ARCH_CONVERT), level))) + return error; +#endif + *rkp = *lkp; /* INT_: no change copy */ + *rpp = *lpp; /* INT_: no change copy */ + xfs_inobt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + xfs_inobt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + } else { + lrp = XFS_INOBT_REC_ADDR(left, INT_GET(left->bb_numrecs, ARCH_CONVERT), cur); + rrp = XFS_INOBT_REC_ADDR(right, 1, cur); + ovbcopy(rrp, rrp + 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + *rrp = *lrp; + xfs_inobt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1); + key.ir_startino = rrp->ir_startino; /* INT_: direct copy */ + rkp = &key; + } + /* + * Decrement and log left's numrecs, bump and log right's numrecs. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -1); + xfs_inobt_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); +#ifdef DEBUG + if (level > 0) + xfs_btree_check_key(cur->bc_btnum, rkp, rkp + 1); + else + xfs_btree_check_rec(cur->bc_btnum, rrp, rrp + 1); +#endif + xfs_inobt_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); + /* + * Using a temporary cursor, update the parent key values of the + * block on the right. + */ + if ((error = xfs_btree_dup_cursor(cur, &tcur))) + return error; + xfs_btree_lastrec(tcur, level); + if ((error = xfs_inobt_increment(tcur, level, &i)) || + (error = xfs_inobt_updkey(tcur, rkp, level + 1))) { + xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); + return error; + } + xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); + *stat = 1; + return 0; +} + +/* + * Split cur/level block in half. + * Return new block number and its first record (to be inserted into parent). + */ +STATIC int /* error */ +xfs_inobt_split( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level to split */ + xfs_agblock_t *bnop, /* output: block number allocated */ + xfs_inobt_key_t *keyp, /* output: first key of new block */ + xfs_btree_cur_t **curp, /* output: new cursor */ + int *stat) /* success/failure */ +{ + xfs_alloc_arg_t args; /* allocation argument structure */ + int error; /* error return value */ + int i; /* loop index/record number */ + xfs_agblock_t lbno; /* left (current) block number */ + xfs_buf_t *lbp; /* buffer for left block */ + xfs_inobt_block_t *left; /* left (current) btree block */ + xfs_inobt_key_t *lkp; /* left btree key pointer */ + xfs_inobt_ptr_t *lpp; /* left btree address pointer */ + xfs_inobt_rec_t *lrp; /* left btree record pointer */ + xfs_buf_t *rbp; /* buffer for right block */ + xfs_inobt_block_t *right; /* right (new) btree block */ + xfs_inobt_key_t *rkp; /* right btree key pointer */ + xfs_inobt_ptr_t *rpp; /* right btree address pointer */ + xfs_inobt_rec_t *rrp; /* right btree record pointer */ + + /* + * Set up left block (current one). + */ + lbp = cur->bc_bufs[level]; + args.tp = cur->bc_tp; + args.mp = cur->bc_mp; + lbno = XFS_DADDR_TO_AGBNO(args.mp, XFS_BUF_ADDR(lbp)); + /* + * Allocate the new block. + * If we can't do it, we're toast. Give up. + */ + args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.i.agno, lbno); + args.mod = args.minleft = args.alignment = args.total = args.wasdel = + args.isfl = args.userdata = args.minalignslop = 0; + args.minlen = args.maxlen = args.prod = 1; + args.type = XFS_ALLOCTYPE_NEAR_BNO; + if ((error = xfs_alloc_vextent(&args))) + return error; + if (args.fsbno == NULLFSBLOCK) { + *stat = 0; + return 0; + } + ASSERT(args.len == 1); + rbp = xfs_btree_get_bufs(args.mp, args.tp, args.agno, args.agbno, 0); + /* + * Set up the new block as "right". + */ + right = XFS_BUF_TO_INOBT_BLOCK(rbp); + /* + * "Left" is the current (according to the cursor) block. + */ + left = XFS_BUF_TO_INOBT_BLOCK(lbp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) + return error; +#endif + /* + * Fill in the btree header for the new block. + */ + INT_SET(right->bb_magic, ARCH_CONVERT, xfs_magics[cur->bc_btnum]); + right->bb_level = left->bb_level; /* INT_: direct copy */ + INT_SET(right->bb_numrecs, ARCH_CONVERT, (__uint16_t)(INT_GET(left->bb_numrecs, ARCH_CONVERT) / 2)); + /* + * Make sure that if there's an odd number of entries now, that + * each new block will have the same number of entries. + */ + if ((INT_GET(left->bb_numrecs, ARCH_CONVERT) & 1) && + cur->bc_ptrs[level] <= INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1) + INT_MOD(right->bb_numrecs, ARCH_CONVERT, +1); + i = INT_GET(left->bb_numrecs, ARCH_CONVERT) - INT_GET(right->bb_numrecs, ARCH_CONVERT) + 1; + /* + * For non-leaf blocks, copy keys and addresses over to the new block. + */ + if (level > 0) { + lkp = XFS_INOBT_KEY_ADDR(left, i, cur); + lpp = XFS_INOBT_PTR_ADDR(left, i, cur); + rkp = XFS_INOBT_KEY_ADDR(right, 1, cur); + rpp = XFS_INOBT_PTR_ADDR(right, 1, cur); +#ifdef DEBUG + for (i = 0; i < INT_GET(right->bb_numrecs, ARCH_CONVERT); i++) { + if ((error = xfs_btree_check_sptr(cur, INT_GET(lpp[i], ARCH_CONVERT), level))) + return error; + } +#endif + bcopy(lkp, rkp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rkp)); + bcopy(lpp, rpp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rpp)); + xfs_inobt_log_keys(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + xfs_inobt_log_ptrs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + *keyp = *rkp; + } + /* + * For leaf blocks, copy records over to the new block. + */ + else { + lrp = XFS_INOBT_REC_ADDR(left, i, cur); + rrp = XFS_INOBT_REC_ADDR(right, 1, cur); + bcopy(lrp, rrp, INT_GET(right->bb_numrecs, ARCH_CONVERT) * sizeof(*rrp)); + xfs_inobt_log_recs(cur, rbp, 1, INT_GET(right->bb_numrecs, ARCH_CONVERT)); + keyp->ir_startino = rrp->ir_startino; /* INT_: direct copy */ + } + /* + * Find the left block number by looking in the buffer. + * Adjust numrecs, sibling pointers. + */ + INT_MOD(left->bb_numrecs, ARCH_CONVERT, -(INT_GET(right->bb_numrecs, ARCH_CONVERT))); + right->bb_rightsib = left->bb_rightsib; /* INT_: direct copy */ + INT_SET(left->bb_rightsib, ARCH_CONVERT, args.agbno); + INT_SET(right->bb_leftsib, ARCH_CONVERT, lbno); + xfs_inobt_log_block(args.tp, rbp, XFS_BB_ALL_BITS); + xfs_inobt_log_block(args.tp, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); + /* + * If there's a block to the new block's right, make that block + * point back to right instead of to left. + */ + if (INT_GET(right->bb_rightsib, ARCH_CONVERT) != NULLAGBLOCK) { + xfs_inobt_block_t *rrblock; /* rr btree block */ + xfs_buf_t *rrbp; /* buffer for rrblock */ + + if ((error = xfs_btree_read_bufs(args.mp, args.tp, args.agno, + INT_GET(right->bb_rightsib, ARCH_CONVERT), 0, &rrbp, + XFS_INO_BTREE_REF))) + return error; + rrblock = XFS_BUF_TO_INOBT_BLOCK(rrbp); + if ((error = xfs_btree_check_sblock(cur, rrblock, level, rrbp))) + return error; + INT_SET(rrblock->bb_leftsib, ARCH_CONVERT, args.agbno); + xfs_inobt_log_block(args.tp, rrbp, XFS_BB_LEFTSIB); + } + /* + * If the cursor is really in the right block, move it there. + * If it's just pointing past the last entry in left, then we'll + * insert there, so don't change anything in that case. + */ + if (cur->bc_ptrs[level] > INT_GET(left->bb_numrecs, ARCH_CONVERT) + 1) { + xfs_btree_setbuf(cur, level, rbp); + cur->bc_ptrs[level] -= INT_GET(left->bb_numrecs, ARCH_CONVERT); + } + /* + * If there are more levels, we'll need another cursor which refers + * the right block, no matter where this cursor was. + */ + if (level + 1 < cur->bc_nlevels) { + if ((error = xfs_btree_dup_cursor(cur, curp))) + return error; + (*curp)->bc_ptrs[level + 1]++; + } + *bnop = args.agbno; + *stat = 1; + return 0; +} + +/* + * Update keys at all levels from here to the root along the cursor's path. + */ +STATIC int /* error */ +xfs_inobt_updkey( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_inobt_key_t *keyp, /* new key value to update to */ + int level) /* starting level for update */ +{ + int ptr; /* index of key in block */ + + /* + * Go up the tree from this level toward the root. + * At each level, update the key value to the value input. + * Stop when we reach a level where the cursor isn't pointing + * at the first entry in the block. + */ + for (ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) { + xfs_buf_t *bp; /* buffer for block */ + xfs_inobt_block_t *block; /* btree block */ +#ifdef DEBUG + int error; /* error return value */ +#endif + xfs_inobt_key_t *kp; /* ptr to btree block keys */ + + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; +#endif + ptr = cur->bc_ptrs[level]; + kp = XFS_INOBT_KEY_ADDR(block, ptr, cur); + *kp = *keyp; + xfs_inobt_log_keys(cur, bp, ptr, ptr); + } + return 0; +} + +/* + * Externally visible routines. + */ + +/* + * Decrement cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_inobt_decrement( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat) /* success/failure */ +{ + xfs_inobt_block_t *block; /* btree block */ + int error; + int lev; /* btree level */ + + ASSERT(level < cur->bc_nlevels); + /* + * Read-ahead to the left at this level. + */ + xfs_btree_readahead(cur, level, XFS_BTCUR_LEFTRA); + /* + * Decrement the ptr at this level. If we're still in the block + * then we're done. + */ + if (--cur->bc_ptrs[level] > 0) { + *stat = 1; + return 0; + } + /* + * Get a pointer to the btree block. + */ + block = XFS_BUF_TO_INOBT_BLOCK(cur->bc_bufs[level]); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, + cur->bc_bufs[level]))) + return error; +#endif + /* + * If we just went off the left edge of the tree, return failure. + */ + if (INT_GET(block->bb_leftsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * March up the tree decrementing pointers. + * Stop when we don't go off the left edge of a block. + */ + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + if (--cur->bc_ptrs[lev] > 0) + break; + /* + * Read-ahead the left block, we're going to read it + * in the next loop. + */ + xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA); + } + /* + * If we went off the root then we are seriously confused. + */ + ASSERT(lev < cur->bc_nlevels); + /* + * Now walk back down the tree, fixing up the cursor's buffer + * pointers and key numbers. + */ + for (block = XFS_BUF_TO_INOBT_BLOCK(cur->bc_bufs[lev]); lev > level; ) { + xfs_agblock_t agbno; /* block number of btree block */ + xfs_buf_t *bp; /* buffer containing btree block */ + + agbno = INT_GET(*XFS_INOBT_PTR_ADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, agbno, 0, &bp, + XFS_INO_BTREE_REF))) + return error; + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_INOBT_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; + cur->bc_ptrs[lev] = INT_GET(block->bb_numrecs, ARCH_CONVERT); + } + *stat = 1; + return 0; +} + +#ifdef _NOTYET_ +/* + * Delete the record pointed to by cur. + * The cursor refers to the place where the record was (could be inserted) + * when the operation returns. + */ +int /* error */ +xfs_inobt_delete( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + int error; + int i; /* result code */ + int level; /* btree level */ + + /* + * Go up the tree, starting at leaf level. + * If 2 is returned then a join was done; go to the next level. + * Otherwise we are done. + */ + for (level = 0, i = 2; i == 2; level++) { + if (error = xfs_inobt_delrec(cur, level, &i)) + return error; + } + if (i == 0) { + for (level = 1; level < cur->bc_nlevels; level++) { + if (cur->bc_ptrs[level] == 0) { + if (error = xfs_inobt_decrement(cur, level, &i)) + return error; + break; + } + } + } + *stat = i; + return 0; +} +#endif /* _NOTYET_ */ + +/* + * Get the data from the pointed-to record. + */ +int /* error */ +xfs_inobt_get_rec( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agino_t *ino, /* output: starting inode of chunk */ + __int32_t *fcnt, /* output: number of free inodes */ + xfs_inofree_t *free, /* output: free inode mask */ + int *stat, /* output: success/failure */ + xfs_arch_t arch) /* input: architecture */ +{ + xfs_inobt_block_t *block; /* btree block */ + xfs_buf_t *bp; /* buffer containing btree block */ +#ifdef DEBUG + int error; /* error return value */ +#endif + int ptr; /* record number */ + xfs_inobt_rec_t *rec; /* record data */ + + bp = cur->bc_bufs[0]; + ptr = cur->bc_ptrs[0]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, 0, bp))) + return error; +#endif + /* + * Off the right end or left end, return failure. + */ + if (ptr > INT_GET(block->bb_numrecs, ARCH_CONVERT) || ptr <= 0) { + *stat = 0; + return 0; + } + /* + * Point to the record and extract its data. + */ + rec = XFS_INOBT_REC_ADDR(block, ptr, cur); + ASSERT(arch == ARCH_NOCONVERT || arch == ARCH_CONVERT); + if (arch == ARCH_NOCONVERT) { + *ino = INT_GET(rec->ir_startino, ARCH_CONVERT); + *fcnt = INT_GET(rec->ir_freecount, ARCH_CONVERT); + *free = INT_GET(rec->ir_free, ARCH_CONVERT); + } else { + INT_COPY(*ino, rec->ir_startino, ARCH_CONVERT); + INT_COPY(*fcnt, rec->ir_freecount, ARCH_CONVERT); + INT_COPY(*free, rec->ir_free, ARCH_CONVERT); + } + *stat = 1; + return 0; +} + +/* + * Increment cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_inobt_increment( + xfs_btree_cur_t *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat) /* success/failure */ +{ + xfs_inobt_block_t *block; /* btree block */ + xfs_buf_t *bp; /* buffer containing btree block */ + int error; /* error return value */ + int lev; /* btree level */ + + ASSERT(level < cur->bc_nlevels); + /* + * Read-ahead to the right at this level. + */ + xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); + /* + * Get a pointer to the btree block. + */ + bp = cur->bc_bufs[level]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, level, bp))) + return error; +#endif + /* + * Increment the ptr at this level. If we're still in the block + * then we're done. + */ + if (++cur->bc_ptrs[level] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) { + *stat = 1; + return 0; + } + /* + * If we just went off the right edge of the tree, return failure. + */ + if (INT_GET(block->bb_rightsib, ARCH_CONVERT) == NULLAGBLOCK) { + *stat = 0; + return 0; + } + /* + * March up the tree incrementing pointers. + * Stop when we don't go off the right edge of a block. + */ + for (lev = level + 1; lev < cur->bc_nlevels; lev++) { + bp = cur->bc_bufs[lev]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; +#endif + if (++cur->bc_ptrs[lev] <= INT_GET(block->bb_numrecs, ARCH_CONVERT)) + break; + /* + * Read-ahead the right block, we're going to read it + * in the next loop. + */ + xfs_btree_readahead(cur, lev, XFS_BTCUR_RIGHTRA); + } + /* + * If we went off the root then we are seriously confused. + */ + ASSERT(lev < cur->bc_nlevels); + /* + * Now walk back down the tree, fixing up the cursor's buffer + * pointers and key numbers. + */ + for (bp = cur->bc_bufs[lev], block = XFS_BUF_TO_INOBT_BLOCK(bp); + lev > level; ) { + xfs_agblock_t agbno; /* block number of btree block */ + + agbno = INT_GET(*XFS_INOBT_PTR_ADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT); + if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, + cur->bc_private.i.agno, agbno, 0, &bp, + XFS_INO_BTREE_REF))) + return error; + lev--; + xfs_btree_setbuf(cur, lev, bp); + block = XFS_BUF_TO_INOBT_BLOCK(bp); + if ((error = xfs_btree_check_sblock(cur, block, lev, bp))) + return error; + cur->bc_ptrs[lev] = 1; + } + *stat = 1; + return 0; +} + +/* + * Insert the current record at the point referenced by cur. + * The cursor may be inconsistent on return if splits have been done. + */ +int /* error */ +xfs_inobt_insert( + xfs_btree_cur_t *cur, /* btree cursor */ + int *stat) /* success/failure */ +{ + int error; /* error return value */ + int i; /* result value, 0 for failure */ + int level; /* current level number in btree */ + xfs_agblock_t nbno; /* new block number (split result) */ + xfs_btree_cur_t *ncur; /* new cursor (split result) */ + xfs_inobt_rec_t nrec; /* record being inserted this level */ + xfs_btree_cur_t *pcur; /* previous level's cursor */ + + level = 0; + nbno = NULLAGBLOCK; + INT_SET(nrec.ir_startino, ARCH_CONVERT, cur->bc_rec.i.ir_startino); + INT_SET(nrec.ir_freecount, ARCH_CONVERT, cur->bc_rec.i.ir_freecount); + INT_SET(nrec.ir_free, ARCH_CONVERT, cur->bc_rec.i.ir_free); + ncur = (xfs_btree_cur_t *)0; + pcur = cur; + /* + * Loop going up the tree, starting at the leaf level. + * Stop when we don't get a split block, that must mean that + * the insert is finished with this level. + */ + do { + /* + * Insert nrec/nbno into this level of the tree. + * Note if we fail, nbno will be null. + */ + if ((error = xfs_inobt_insrec(pcur, level++, &nbno, &nrec, &ncur, + &i))) { + if (pcur != cur) + xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); + return error; + } + /* + * See if the cursor we just used is trash. + * Can't trash the caller's cursor, but otherwise we should + * if ncur is a new cursor or we're about to be done. + */ + if (pcur != cur && (ncur || nbno == NULLAGBLOCK)) { + cur->bc_nlevels = pcur->bc_nlevels; + xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); + } + /* + * If we got a new cursor, switch to it. + */ + if (ncur) { + pcur = ncur; + ncur = (xfs_btree_cur_t *)0; + } + } while (nbno != NULLAGBLOCK); + *stat = i; + return 0; +} + +/* + * Lookup the record equal to ino in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_eq( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat) /* success/failure */ +{ + cur->bc_rec.i.ir_startino = ino; + cur->bc_rec.i.ir_freecount = fcnt; + cur->bc_rec.i.ir_free = free; + return xfs_inobt_lookup(cur, XFS_LOOKUP_EQ, stat); +} + +/* + * Lookup the first record greater than or equal to ino + * in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_ge( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat) /* success/failure */ +{ + cur->bc_rec.i.ir_startino = ino; + cur->bc_rec.i.ir_freecount = fcnt; + cur->bc_rec.i.ir_free = free; + return xfs_inobt_lookup(cur, XFS_LOOKUP_GE, stat); +} + +/* + * Lookup the first record less than or equal to ino + * in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_le( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat) /* success/failure */ +{ + cur->bc_rec.i.ir_startino = ino; + cur->bc_rec.i.ir_freecount = fcnt; + cur->bc_rec.i.ir_free = free; + return xfs_inobt_lookup(cur, XFS_LOOKUP_LE, stat); +} + +/* + * Update the record referred to by cur, to the value given + * by [ino, fcnt, free]. + * This either works (return 0) or gets an EFSCORRUPTED error. + */ +int /* error */ +xfs_inobt_update( + xfs_btree_cur_t *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free) /* free inode mask */ +{ + xfs_inobt_block_t *block; /* btree block to update */ + xfs_buf_t *bp; /* buffer containing btree block */ + int error; /* error return value */ + int ptr; /* current record number (updating) */ + xfs_inobt_rec_t *rp; /* pointer to updated record */ + + /* + * Pick up the current block. + */ + bp = cur->bc_bufs[0]; + block = XFS_BUF_TO_INOBT_BLOCK(bp); +#ifdef DEBUG + if ((error = xfs_btree_check_sblock(cur, block, 0, bp))) + return error; +#endif + /* + * Get the address of the rec to be updated. + */ + ptr = cur->bc_ptrs[0]; + rp = XFS_INOBT_REC_ADDR(block, ptr, cur); + /* + * Fill in the new contents and log them. + */ + INT_SET(rp->ir_startino, ARCH_CONVERT, ino); + INT_SET(rp->ir_freecount, ARCH_CONVERT, fcnt); + INT_SET(rp->ir_free, ARCH_CONVERT, free); + xfs_inobt_log_recs(cur, bp, ptr, ptr); + /* + * Updating first record in leaf. Pass new key value up to our parent. + */ + if (ptr == 1) { + xfs_inobt_key_t key; /* key containing [ino] */ + + INT_SET(key.ir_startino, ARCH_CONVERT, ino); + if ((error = xfs_inobt_updkey(cur, &key, 1))) + return error; + } + return 0; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_ialloc_btree.h linux-2.4-xfs/linux/fs/xfs/xfs_ialloc_btree.h --- linux-2.4.7/linux/fs/xfs/xfs_ialloc_btree.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_ialloc_btree.h Mon Sep 25 21:03:57 2000 @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_IALLOC_BTREE_H__ +#define __XFS_IALLOC_BTREE_H__ + +/* + * Inode map on-disk structures + */ + +struct xfs_buf; +struct xfs_btree_cur; +struct xfs_btree_sblock; +struct xfs_mount; + +/* + * There is a btree for the inode map per allocation group. + */ +#define XFS_IBT_MAGIC 0x49414254 /* 'IABT' */ + +typedef __uint64_t xfs_inofree_t; +#define XFS_INODES_PER_CHUNK (NBBY * sizeof(xfs_inofree_t)) +#define XFS_INODES_PER_CHUNK_LOG (XFS_NBBYLOG + 3) +#define XFS_INOBT_ALL_FREE ((xfs_inofree_t)-1) + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_MASKN) +xfs_inofree_t xfs_inobt_maskn(int i, int n); +#define XFS_INOBT_MASKN(i,n) xfs_inobt_maskn(i,n) +#else +#define XFS_INOBT_MASKN(i,n) \ + ((((n) >= XFS_INODES_PER_CHUNK ? \ + (xfs_inofree_t)0 : ((xfs_inofree_t)1 << (n))) - 1) << (i)) +#endif + +/* + * Data record structure + */ +typedef struct xfs_inobt_rec +{ + xfs_agino_t ir_startino; /* starting inode number */ + __int32_t ir_freecount; /* count of free inodes (set bits) */ + xfs_inofree_t ir_free; /* free inode mask */ +} xfs_inobt_rec_t; + +/* + * Key structure + */ +typedef struct xfs_inobt_key +{ + xfs_agino_t ir_startino; /* starting inode number */ +} xfs_inobt_key_t; + +typedef xfs_agblock_t xfs_inobt_ptr_t; /* btree pointer type */ + /* btree block header type */ +typedef struct xfs_btree_sblock xfs_inobt_block_t; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_INOBT_BLOCK) +xfs_inobt_block_t *xfs_buf_to_inobt_block(struct xfs_buf *bp); +#define XFS_BUF_TO_INOBT_BLOCK(bp) xfs_buf_to_inobt_block(bp) +#else +#define XFS_BUF_TO_INOBT_BLOCK(bp) ((xfs_inobt_block_t *)(XFS_BUF_PTR(bp))) +#endif + +/* + * Bit manipulations for ir_free. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_MASK) +xfs_inofree_t xfs_inobt_mask(int i); +#define XFS_INOBT_MASK(i) xfs_inobt_mask(i) +#else +#define XFS_INOBT_MASK(i) ((xfs_inofree_t)1 << (i)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_IS_FREE) +int xfs_inobt_is_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch); +#define XFS_INOBT_IS_FREE(rp,i,arch) xfs_inobt_is_free(rp,i,arch) +#else +#define XFS_INOBT_IS_FREE(rp,i,arch) ((INT_GET((rp)->ir_free, arch) \ + & XFS_INOBT_MASK(i)) != 0) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_SET_FREE) +void xfs_inobt_set_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch); +#define XFS_INOBT_SET_FREE(rp,i,arch) xfs_inobt_set_free(rp,i,arch) +#else +#define XFS_INOBT_SET_FREE(rp,i,arch) (INT_MOD_EXPR((rp)->ir_free, arch, |= XFS_INOBT_MASK(i))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_CLR_FREE) +void xfs_inobt_clr_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch); +#define XFS_INOBT_CLR_FREE(rp,i,arch) xfs_inobt_clr_free(rp,i,arch) +#else +#define XFS_INOBT_CLR_FREE(rp,i,arch) (INT_MOD_EXPR((rp)->ir_free, arch, &= ~XFS_INOBT_MASK(i))) +#endif + +/* + * Real block structures have a size equal to the disk block size. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_BLOCK_SIZE) +int xfs_inobt_block_size(int lev, struct xfs_btree_cur *cur); +#define XFS_INOBT_BLOCK_SIZE(lev,cur) xfs_inobt_block_size(lev,cur) +#else +#define XFS_INOBT_BLOCK_SIZE(lev,cur) (1 << (cur)->bc_blocklog) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_BLOCK_MAXRECS) +int xfs_inobt_block_maxrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_INOBT_BLOCK_MAXRECS(lev,cur) xfs_inobt_block_maxrecs(lev,cur) +#else +#define XFS_INOBT_BLOCK_MAXRECS(lev,cur) \ + ((cur)->bc_mp->m_inobt_mxr[lev != 0]) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_BLOCK_MINRECS) +int xfs_inobt_block_minrecs(int lev, struct xfs_btree_cur *cur); +#define XFS_INOBT_BLOCK_MINRECS(lev,cur) xfs_inobt_block_minrecs(lev,cur) +#else +#define XFS_INOBT_BLOCK_MINRECS(lev,cur) \ + ((cur)->bc_mp->m_inobt_mnr[lev != 0]) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_IS_LAST_REC) +int xfs_inobt_is_last_rec(struct xfs_btree_cur *cur); +#define XFS_INOBT_IS_LAST_REC(cur) xfs_inobt_is_last_rec(cur) +#else +#define XFS_INOBT_IS_LAST_REC(cur) \ + ((cur)->bc_ptrs[0] == \ + INT_GET(XFS_BUF_TO_INOBT_BLOCK((cur)->bc_bufs[0])->bb_numrecs, ARCH_CONVERT)) +#endif + +/* + * Maximum number of inode btree levels. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IN_MAXLEVELS) +int xfs_in_maxlevels(struct xfs_mount *mp); +#define XFS_IN_MAXLEVELS(mp) xfs_in_maxlevels(mp) +#else +#define XFS_IN_MAXLEVELS(mp) ((mp)->m_in_maxlevels) +#endif + +/* + * block numbers in the AG. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IBT_BLOCK) +xfs_agblock_t xfs_ibt_block(struct xfs_mount *mp); +#define XFS_IBT_BLOCK(mp) xfs_ibt_block(mp) +#else +#define XFS_IBT_BLOCK(mp) ((xfs_agblock_t)(XFS_CNT_BLOCK(mp) + 1)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_PREALLOC_BLOCKS) +xfs_agblock_t xfs_prealloc_blocks(struct xfs_mount *mp); +#define XFS_PREALLOC_BLOCKS(mp) xfs_prealloc_blocks(mp) +#else +#define XFS_PREALLOC_BLOCKS(mp) ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1)) +#endif + +/* + * Record, key, and pointer address macros for btree blocks. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_REC_ADDR) +xfs_inobt_rec_t * +xfs_inobt_rec_addr(xfs_inobt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_INOBT_REC_ADDR(bb,i,cur) xfs_inobt_rec_addr(bb,i,cur) +#else +#define XFS_INOBT_REC_ADDR(bb,i,cur) \ + XFS_BTREE_REC_ADDR(XFS_INOBT_BLOCK_SIZE(0,cur), xfs_inobt, bb, i, \ + XFS_INOBT_BLOCK_MAXRECS(0, cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_KEY_ADDR) +xfs_inobt_key_t * +xfs_inobt_key_addr(xfs_inobt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_INOBT_KEY_ADDR(bb,i,cur) xfs_inobt_key_addr(bb,i,cur) +#else +#define XFS_INOBT_KEY_ADDR(bb,i,cur) \ + XFS_BTREE_KEY_ADDR(XFS_INOBT_BLOCK_SIZE(1,cur), xfs_inobt, bb, i, \ + XFS_INOBT_BLOCK_MAXRECS(1, cur)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INOBT_PTR_ADDR) +xfs_inobt_ptr_t * +xfs_inobt_ptr_addr(xfs_inobt_block_t *bb, int i, struct xfs_btree_cur *cur); +#define XFS_INOBT_PTR_ADDR(bb,i,cur) xfs_inobt_ptr_addr(bb,i,cur) +#else +#define XFS_INOBT_PTR_ADDR(bb,i,cur) \ + XFS_BTREE_PTR_ADDR(XFS_INOBT_BLOCK_SIZE(1,cur), xfs_inobt, bb, i, \ + XFS_INOBT_BLOCK_MAXRECS(1, cur)) +#endif + +/* + * Prototypes for externally visible routines. + */ + +/* + * Decrement cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_inobt_decrement( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat); /* success/failure */ + +#ifdef _NOTYET_ +/* + * Delete the record pointed to by cur. + * The cursor refers to the place where the record was (could be inserted) + * when the operation returns. + */ +int /* error */ +xfs_inobt_delete( + struct xfs_btree_cur *cur, /* btree cursor */ + int *stat); /* success/failure */ +#endif /* _NOTYET_ */ + +/* + * Get the data from the pointed-to record. + */ +int /* error */ +xfs_inobt_get_rec( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agino_t *ino, /* output: starting inode of chunk */ + __int32_t *fcnt, /* output: number of free inodes */ + xfs_inofree_t *free, /* output: free inode mask */ + int *stat, /* output: success/failure */ + xfs_arch_t arch); /* output: architecture */ + +/* + * Increment cursor by one record at the level. + * For nonzero levels the leaf-ward information is untouched. + */ +int /* error */ +xfs_inobt_increment( + struct xfs_btree_cur *cur, /* btree cursor */ + int level, /* level in btree, 0 is leaf */ + int *stat); /* success/failure */ + +/* + * Insert the current record at the point referenced by cur. + * The cursor may be inconsistent on return if splits have been done. + */ +int /* error */ +xfs_inobt_insert( + struct xfs_btree_cur *cur, /* btree cursor */ + int *stat); /* success/failure */ + +/* + * Lookup the record equal to ino in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_eq( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat); /* success/failure */ + +/* + * Lookup the first record greater than or equal to ino + * in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_ge( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat); /* success/failure */ + +/* + * Lookup the first record less than or equal to ino + * in the btree given by cur. + */ +int /* error */ +xfs_inobt_lookup_le( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free, /* free inode mask */ + int *stat); /* success/failure */ + +/* + * Update the record referred to by cur, to the value given + * by [ino, fcnt, free]. + * This either works (return 0) or gets an EFSCORRUPTED error. + */ +int /* error */ +xfs_inobt_update( + struct xfs_btree_cur *cur, /* btree cursor */ + xfs_agino_t ino, /* starting inode of chunk */ + __int32_t fcnt, /* free inode count */ + xfs_inofree_t free); /* free inode mask */ + +#endif /* __XFS_IALLOC_BTREE_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_iget.c linux-2.4-xfs/linux/fs/xfs/xfs_iget.c --- linux-2.4.7/linux/fs/xfs/xfs_iget.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_iget.c Mon Jun 18 20:57:21 2001 @@ -0,0 +1,1084 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +void xfs_ilock_ra(xfs_inode_t *ip, uint lock_flags, void *return_address); + +/* + * Initialize the inode hash table for the newly mounted file system. + * + * mp -- this is the mount point structure for the file system being + * initialized + */ +void +xfs_ihash_init(xfs_mount_t *mp) +{ + int i; + + mp->m_ihsize = XFS_BUCKETS(mp); + mp->m_ihash = (xfs_ihash_t *)kmem_zalloc(mp->m_ihsize + * sizeof(xfs_ihash_t), KM_SLEEP_IO); + ASSERT(mp->m_ihash != NULL); + for (i = 0; i < mp->m_ihsize; i++) { + mrinit(&(mp->m_ihash[i].ih_lock),"xfshash"); + } +} + +/* + * Free up structures allocated by xfs_ihash_init, at unmount time. + */ +void +xfs_ihash_free(xfs_mount_t *mp) +{ + int i; + + for (i = 0; i < mp->m_ihsize; i++) + mrfree(&mp->m_ihash[i].ih_lock); + kmem_free(mp->m_ihash, mp->m_ihsize*sizeof(xfs_ihash_t)); + mp->m_ihash = NULL; +} + +/* + * Initialize the inode cluster hash table for the newly mounted file system. + * + * mp -- this is the mount point structure for the file system being + * initialized + */ +void +xfs_chash_init(xfs_mount_t *mp) +{ + int i; + + /* + * m_chash size is based on m_ihash + * with a minimum of 37 entries + */ + mp->m_chsize = (XFS_BUCKETS(mp)) / + (XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog); + if (mp->m_chsize < 37) { + mp->m_chsize = 37; + } + mp->m_chash = (xfs_chash_t *)kmem_zalloc(mp->m_chsize + * sizeof(xfs_chash_t), + KM_SLEEP_IO); + ASSERT(mp->m_chash != NULL); + + for (i = 0; i < mp->m_chsize; i++) { + spinlock_init(&mp->m_chash[i].ch_lock,"xfshash"); + } +} + +/* + * Free up structures allocated by xfs_chash_init, at unmount time. + */ +void +xfs_chash_free(xfs_mount_t *mp) +{ + int i; + + for (i = 0; i < mp->m_chsize; i++) { + spinlock_destroy(&mp->m_chash[i].ch_lock); + } + + kmem_free(mp->m_chash, mp->m_chsize*sizeof(xfs_chash_t)); + mp->m_chash = NULL; +} + + +static inline void +xfs_iget_vnode_init( + xfs_mount_t *mp, + vnode_t *vp, + xfs_inode_t *ip) +{ + vp->v_vfsp = XFS_MTOVFS(mp); + vp->v_inode = LINVFS_GET_IP(vp); + vp->v_type = IFTOVT(ip->i_d.di_mode); +} + + +/* + * Look up an inode by number in the given file system. + * The inode is looked up in the hash table for the file system + * represented by the mount point parameter mp. Each bucket of + * the hash table is guarded by an individual semaphore. + * + * If the inode is found in the hash table, its corresponding vnode + * is obtained with a call to vn_get(). This call takes care of + * coordination with the reclamation of the inode and vnode. Note + * that the vmap structure is filled in while holding the hash lock. + * This gives us the state of the inode/vnode when we found it and + * is used for coordination in vn_get(). + * + * If it is not in core, read it in from the file system's device and + * add the inode into the hash table. + * + * The inode is locked according to the value of the lock_flags parameter. + * This flag parameter indicates how and if the inode's IO lock and inode lock + * should be taken. + * + * mp -- the mount point structure for the current file system. It points + * to the inode hash table. + * tp -- a pointer to the current transaction if there is one. This is + * simply passed through to the xfs_iread() call. + * ino -- the number of the inode desired. This is the unique identifier + * within the file system for the inode being requested. + * lock_flags -- flags indicating how to lock the inode. See the comment + * for xfs_ilock() for a list of valid values. + * bno -- the block number starting the buffer containing the inode, + * if known (as by bulkstat), else 0. + */ +int +xfs_iget_core( + vnode_t *vp, + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + uint lock_flags, + xfs_inode_t **ipp, + xfs_daddr_t bno) +{ + xfs_ihash_t *ih; + xfs_inode_t *ip; + xfs_inode_t *iq; + vnode_t *inode_vp; + ulong version; + int error; + /* REFERENCED */ + int newnode; +#ifdef CELL_CAPABLE + int quiesce_new = 0; +#endif + xfs_chash_t *ch; + xfs_chashlist_t *chl, *chlnew; + SPLDECL(s); + + + ih = XFS_IHASH(mp, ino); + +again: + mraccess(&ih->ih_lock); + + for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) { + if (ip->i_ino == ino) { + + inode_vp = XFS_ITOV_NULL(ip); + + if (inode_vp == NULL) { + if (ip->i_flags & XFS_IRECLAIM) { + mrunlock(&ih->ih_lock); + delay(1); + XFS_STATS_INC(xfsstats.xs_ig_frecycle); + + goto again; + } + + xfs_iget_vnode_init(mp, vp, ip); + + vn_trace_exit(vp, "xfs_iget.alloc", + (inst_t *)__return_address); + + bhv_desc_init(&(ip->i_bhv_desc), ip, vp, + &xfs_vnodeops); + vn_bhv_insert_initial(VN_BHV_HEAD(vp), + &(ip->i_bhv_desc)); + + XFS_STATS_INC(xfsstats.xs_ig_found); + + mrunlock(&ih->ih_lock); + goto finish_inode; + + } else if (vp != inode_vp) { + struct inode *inode = inode_vp->v_inode; + + if (inode->i_state & (I_FREEING | I_CLEAR)) { + mrunlock(&ih->ih_lock); + delay(1); + XFS_STATS_INC(xfsstats.xs_ig_frecycle); + + goto again; + } +/* Chances are the other vnode (the one in the inode) is being torn + * down right now, and we landed on top of it. Question is, what do + * we do? Unhook the old inode and hook up the new one? + */ + cmn_err(CE_PANIC, + "xfs_iget_core: ambiguous vns: vp/0x%p, invp/0x%p", + inode_vp, vp); + BUG(); + } + + /* + * Inode cache hit: if ip is not at the front of + * its hash chain, move it there now. + * Do this with the lock held for update, but + * do statistics after releasing the lock. + */ + if (ip->i_prevp != &ih->ih_next + && mrtrypromote(&ih->ih_lock)) { + + if ((iq = ip->i_next)) { + iq->i_prevp = ip->i_prevp; + } + + *ip->i_prevp = iq; + iq = ih->ih_next; + iq->i_prevp = &ip->i_next; + ip->i_next = iq; + ip->i_prevp = &ih->ih_next; + ih->ih_next = ip; + } + + mrunlock(&ih->ih_lock); + + XFS_STATS_INC(xfsstats.xs_ig_found); + + /* + * Make sure the vnode and the inode are hooked up + */ + xfs_iget_vnode_init(mp, vp, ip); + +finish_inode: + if (lock_flags != 0) { + xfs_ilock(ip, lock_flags); + } + + newnode = (ip->i_d.di_mode == 0); + if (newnode) { + ip->i_flags &= ~XFS_IRECLAIM; + xfs_iocore_inode_reinit(ip); + } +#ifdef CELL_CAPABLE + quiesce_new = 0; +#endif + vn_trace_exit(vp, "xfs_iget.found", + (inst_t *)__return_address); + goto return_ip; + } + } + + /* + * Inode cache miss: save the hash chain version stamp and unlock + * the chain, so we don't deadlock in vn_alloc. + */ + XFS_STATS_INC(xfsstats.xs_ig_missed); + + version = ih->ih_version; + + mrunlock(&ih->ih_lock); + + /* + * Read the disk inode attributes into a new inode structure and get + * a new vnode for it. Initialize the inode lock so we can idestroy + * it soon if it's a dup. This should also initialize i_dev, i_ino, + * i_bno, i_mount, and i_index. + */ + error = xfs_iread(mp, tp, ino, &ip, bno); + if (error) { + return error; + } + + /* + * Vnode provided by vn_initialize. + */ + + xfs_iget_vnode_init(mp, vp, ip); + + vn_trace_exit(vp, "xfs_iget.alloc", (inst_t *)__return_address); + + if (vp->v_fbhv == NULL) { + bhv_desc_init(&(ip->i_bhv_desc), ip, vp, &xfs_vnodeops); + vn_bhv_insert_initial(VN_BHV_HEAD(vp), &(ip->i_bhv_desc)); + } + + xfs_inode_lock_init(ip, vp); + xfs_iocore_inode_init(ip); + +#ifdef CELL_CAPABLE + quiesce_new = 0; + if (mp->m_inode_quiesce) + quiesce_new = cxfs_inode_qset(ip); +#endif /* CELL_CAPABLE */ + + if (lock_flags != 0) { + xfs_ilock(ip, lock_flags); + } + + /* + * Put ip on its hash chain, unless someone else hashed a duplicate + * after we released the hash lock. + */ + mrupdate(&ih->ih_lock); + + if (ih->ih_version != version) { + for (iq = ih->ih_next; iq != NULL; iq = iq->i_next) { + if (iq->i_ino == ino) { + mrunlock(&ih->ih_lock); + xfs_idestroy(ip); + + XFS_STATS_INC(xfsstats.xs_ig_dup); + goto again; + } + } + } + + /* + * These values _must_ be set before releasing ihlock! + */ + ip->i_hash = ih; + if ((iq = ih->ih_next)) { + iq->i_prevp = &ip->i_next; + } + ip->i_next = iq; + ip->i_prevp = &ih->ih_next; + ih->ih_next = ip; + ip->i_udquot = ip->i_gdquot = NULL; + ih->ih_version++; + + /* + * put ip on its cluster's hash chain + */ + ASSERT(ip->i_chash == NULL && ip->i_cprev == NULL && + ip->i_cnext == NULL); + + chlnew = NULL; + ch = XFS_CHASH(mp, ip->i_blkno); + chlredo: + s = mutex_spinlock(&ch->ch_lock); + for (chl = ch->ch_list; chl != NULL; chl = chl->chl_next) { + if (chl->chl_blkno == ip->i_blkno) { + + /* insert this inode into the doubly-linked list + * where chl points */ + if ((iq = chl->chl_ip)) { + ip->i_cprev = iq->i_cprev; + iq->i_cprev->i_cnext = ip; + iq->i_cprev = ip; + ip->i_cnext = iq; + } else { + ip->i_cnext = ip; + ip->i_cprev = ip; + } + chl->chl_ip = ip; + ip->i_chash = chl; + break; + } + } + + /* no hash list found for this block; add a new hash list */ + if (chl == NULL) { + if (chlnew == NULL) { + mutex_spinunlock(&ch->ch_lock, s); + ASSERT(xfs_chashlist_zone != NULL); + chlnew = (xfs_chashlist_t *) + kmem_zone_zalloc(xfs_chashlist_zone, + tp ? KM_SLEEP : KM_SLEEP_IO); + ASSERT(chlnew != NULL); + goto chlredo; + } else { + ip->i_cnext = ip; + ip->i_cprev = ip; + ip->i_chash = chlnew; + chlnew->chl_ip = ip; + chlnew->chl_blkno = ip->i_blkno; + chlnew->chl_next = ch->ch_list; + ch->ch_list = chlnew; + chlnew = NULL; + } + } else { + if (chlnew != NULL) { + kmem_zone_free(xfs_chashlist_zone, chlnew); + } + } + + mutex_spinunlock(&ch->ch_lock, s); + + mrunlock(&ih->ih_lock); + + /* + * Link ip to its mount and thread it on the mount's inode list. + */ + XFS_MOUNT_ILOCK(mp); + if ((iq = mp->m_inodes)) { + ASSERT(iq->i_mprev->i_mnext == iq); + ip->i_mprev = iq->i_mprev; + iq->i_mprev->i_mnext = ip; + iq->i_mprev = ip; + ip->i_mnext = iq; + } else { + ip->i_mnext = ip; + ip->i_mprev = ip; + } + mp->m_inodes = ip; +#ifdef CELL_CAPABLE + ASSERT((quiesce_new == 0) || (mp->m_inode_quiesce != 0)); +#endif + + + XFS_MOUNT_IUNLOCK(mp); + + newnode = 1; + + return_ip: + ASSERT(ip->i_df.if_ext_max == + XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t)); + + ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) == + ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0)); +#ifdef CELL_CAPABLE + if (newnode) { + if (quiesce_new) + cxfs_inode_quiesce(ip); + } +#endif + + *ipp = ip; + + /* Update the linux inode */ + error = vn_revalidate(vp, ATTR_COMM|ATTR_LAZY); + + return 0; +} + + +/* + * The 'normal' internal xfs_iget, if needed it will + * 'allocate', or 'get', the vnode. + */ +int +xfs_iget( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + uint lock_flags, + xfs_inode_t **ipp, + xfs_daddr_t bno) +{ + struct inode *inode; + vnode_t *vp = NULL; + int error; + + XFS_STATS_INC(xfsstats.xs_ig_attempts); + + if ((inode = icreate(XFS_MTOVFS(mp)->vfs_super, ino))) { + bhv_desc_t *bdp; + xfs_inode_t *ip; + int newnode; + + + vp = LINVFS_GET_VN_ADDRESS(inode); + if (inode->i_state & I_NEW) { + vn_initialize(XFS_MTOVFS(mp), inode, 0); + error = xfs_iget_core(vp, mp, tp, ino, + lock_flags, ipp, bno); + if (error) + make_bad_inode(inode); + + unlock_new_inode(inode); + if (error) + iput(inode); + } else { + bdp = vn_bhv_lookup(VN_BHV_HEAD(vp), &xfs_vnodeops); + ip = XFS_BHVTOI(bdp); + if (lock_flags != 0) { + xfs_ilock(ip, lock_flags); + } + newnode = (ip->i_d.di_mode == 0); + if (newnode) { + ip->i_flags &= ~XFS_IRECLAIM; + xfs_iocore_inode_reinit(ip); + } + vn_revalidate(vp, ATTR_COMM|ATTR_LAZY); + XFS_STATS_INC(xfsstats.xs_ig_found); + *ipp = ip; + error = 0; + } + } else + error = ENOMEM; /* If we got no inode we are out of memory */ + + return error; +} + + +/* + * A 'special' interface to xfs_iget, where the + * vnode is already allocated. + */ +int +xfs_vn_iget( + vfs_t *vfsp, + struct vnode *vp, + xfs_ino_t ino) +{ + xfs_inode_t *ip; + xfs_mount_t *mp = XFS_BHVTOM(vfsp->vfs_fbhv); + int error; + + error = xfs_iget_core(vp, mp, NULL, ino, 0, &ip, 0); + + return error; +} + + +/* + * Do the setup for the various locks within the incore inode. + */ +void +xfs_inode_lock_init( + xfs_inode_t *ip, + vnode_t *vp) +{ + mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI, "xfsino", (long)vp->v_number); + mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", vp->v_number); +#ifdef NOTYET + mutex_init(&ip->i_range_lock.r_spinlock, MUTEX_SPIN, "xrange"); +#endif /* NOTYET */ + init_sema(&ip->i_flock, 1, "xfsfino", vp->v_number); + init_sv(&ip->i_pinsema, SV_DEFAULT, "xfspino", vp->v_number); + spinlock_init(&ip->i_ipinlock, "xfs_ipin"); +} + +/* + * Look for the inode corresponding to the given ino in the hash table. + * If it is there and its i_transp pointer matches tp, return it. + * Otherwise, return NULL. + */ +xfs_inode_t * +xfs_inode_incore(xfs_mount_t *mp, + xfs_ino_t ino, + xfs_trans_t *tp) +{ + xfs_ihash_t *ih; + xfs_inode_t *ip; + xfs_inode_t *iq; + + ih = XFS_IHASH(mp, ino); + mraccess(&ih->ih_lock); + for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) { + if (ip->i_ino == ino) { + /* + * If we find it and tp matches, return it. + * Also move it to the front of the hash list + * if we find it and it is not already there. + * Otherwise break from the loop and return + * NULL. + */ + if (ip->i_transp == tp) { + if (ip->i_prevp != &ih->ih_next && + mrtrypromote(&ih->ih_lock)) { + if ((iq = ip->i_next)) { + iq->i_prevp = ip->i_prevp; + } + *ip->i_prevp = iq; + iq = ih->ih_next; + iq->i_prevp = &ip->i_next; + ip->i_next = iq; + ip->i_prevp = &ih->ih_next; + ih->ih_next = ip; + } + mrunlock(&ih->ih_lock); + return (ip); + } + break; + } + } + mrunlock(&ih->ih_lock); + return (NULL); +} + +/* + * Decrement reference count of an inode structure and unlock it. + * + * ip -- the inode being released + * lock_flags -- this parameter indicates the inode's locks to be + * to be released. See the comment on xfs_iunlock() for a list + * of valid values. + */ +void +xfs_iput(xfs_inode_t *ip, + uint lock_flags) +{ + vnode_t *vp = XFS_ITOV(ip); + + vn_trace_entry(vp, "xfs_iput", (inst_t *)__return_address); + + xfs_iunlock(ip, lock_flags); + + VN_RELE(vp); +} + +/* + * This routine embodies the part of the reclaim code that pulls + * the inode from the inode hash table and the mount structure's + * inode list. + * This should only be called from xfs_reclaim(). + */ +void +xfs_ireclaim(xfs_inode_t *ip) +{ + vnode_t *vp; + + /* + * Remove from old hash list and mount list. + */ + XFS_STATS_INC(xfsstats.xs_ig_reclaims); + + xfs_iextract(ip); + + /* + * Here we do a spurious inode lock in order to coordinate with + * xfs_sync(). This is because xfs_sync() references the inodes + * in the mount list without taking references on the corresponding + * vnodes. We make that OK here by ensuring that we wait until + * the inode is unlocked in xfs_sync() before we go ahead and + * free it. We get both the regular lock and the io lock because + * the xfs_sync() code may need to drop the regular one but will + * still hold the io lock. + */ + xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + + /* + * Release dquots (and their references) if any. An inode may escape + * xfs_inactive and get here via vn_alloc->vn_reclaim path. + */ + if (ip->i_udquot || ip->i_gdquot) { + xfs_qm_dqdettach_inode(ip); + } + + /* + * Pull our behavior descriptor from the vnode chain. + */ + vp = XFS_ITOV_NULL(ip); + if (vp) { + vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip)); + } + + /* + * Free all memory associated with the inode. + */ + xfs_idestroy(ip); +} + +/* + * This routine removes an about-to-be-destroyed inode from + * all of the lists in which it is lcoated with the exception + * of the behavior chain. It is used by xfs_ireclaim and + * by cxfs relocation cocde, in which case, we are removing + * the xfs_inode but leaving the vnode alone since it has + * been transformed into a client vnode. + */ +void +xfs_iextract( + xfs_inode_t *ip) +{ + xfs_ihash_t *ih; + xfs_inode_t *iq; + xfs_mount_t *mp; + xfs_chash_t *ch; + xfs_chashlist_t *chl, *chm; + SPLDECL(s); + + ih = ip->i_hash; + mrupdate(&ih->ih_lock); + if ((iq = ip->i_next)) { + iq->i_prevp = ip->i_prevp; + } + *ip->i_prevp = iq; + + /* + * Remove from cluster hash list + * 1) delete the chashlist if this is the last inode on the chashlist + * 2) unchain from list of inodes + * 3) point chashlist->chl_ip to 'chl_next' if to this inode. + */ + mp = ip->i_mount; + ch = XFS_CHASH(mp, ip->i_blkno); + s = mutex_spinlock(&ch->ch_lock); + + if (ip->i_cnext == ip) { + /* Last inode on chashlist */ + ASSERT(ip->i_cnext == ip && ip->i_cprev == ip); + ASSERT(ip->i_chash != NULL); + chm=NULL; + for (chl = ch->ch_list; chl != NULL; chl = chl->chl_next) { + if (chl->chl_blkno == ip->i_blkno) { + if (chm == NULL) { + /* first item on the list */ + ch->ch_list = chl->chl_next; + } else { + chm->chl_next = chl->chl_next; + } + kmem_zone_free(xfs_chashlist_zone, chl); + break; + } else { + ASSERT(chl->chl_ip != ip); + chm = chl; + } + } + ASSERT_ALWAYS(chl != NULL); + } else { + /* delete one inode from a non-empty list */ + iq = ip->i_cnext; + iq->i_cprev = ip->i_cprev; + ip->i_cprev->i_cnext = iq; + if (ip->i_chash->chl_ip == ip) { + ip->i_chash->chl_ip = iq; + } + ip->i_chash = __return_address; + ip->i_cprev = __return_address; + ip->i_cnext = __return_address; + } + mutex_spinunlock(&ch->ch_lock, s); + mrunlock(&ih->ih_lock); + + /* + * Remove from mount's inode list. + */ + XFS_MOUNT_ILOCK(mp); + ASSERT((ip->i_mnext != NULL) && (ip->i_mprev != NULL)); + iq = ip->i_mnext; + iq->i_mprev = ip->i_mprev; + ip->i_mprev->i_mnext = iq; + + /* + * Fix up the head pointer if it points to the inode being deleted. + */ + if (mp->m_inodes == ip) { + if (ip == iq) { + mp->m_inodes = NULL; + } else { + mp->m_inodes = iq; + } + } + + mp->m_ireclaims++; + XFS_MOUNT_IUNLOCK(mp); +} + +/* + * This is a wrapper routine around the xfs_ilock() routine + * used to centralize some grungy code. It is used in places + * that wish to lock the inode solely for reading the extents. + * The reason these places can't just call xfs_ilock(SHARED) + * is that the inode lock also guards to bringing in of the + * extents from disk for a file in b-tree format. If the inode + * is in b-tree format, then we need to lock the inode exclusively + * until the extents are read in. Locking it exclusively all + * the time would limit our parallelism unnecessarily, though. + * What we do instead is check to see if the extents have been + * read in yet, and only lock the inode exclusively if they + * have not. + * + * The function returns a value which should be given to the + * corresponding xfs_iunlock_map_shared(). This value is + * the mode in which the lock was actually taken. + */ +uint +xfs_ilock_map_shared( + xfs_inode_t *ip) +{ + uint lock_mode; + + if ((ip->i_d.di_format == XFS_DINODE_FMT_BTREE) && + ((ip->i_df.if_flags & XFS_IFEXTENTS) == 0)) { + lock_mode = XFS_ILOCK_EXCL; + } else { + lock_mode = XFS_ILOCK_SHARED; + } + + xfs_ilock_ra(ip, lock_mode, (inst_t *)__return_address); + + return lock_mode; +} + +/* + * This is simply the unlock routine to go with xfs_ilock_map_shared(). + * All it does is call xfs_iunlock() with the given lock_mode. + */ +void +xfs_iunlock_map_shared( + xfs_inode_t *ip, + unsigned int lock_mode) +{ + xfs_iunlock(ip, lock_mode); +} + +/* + * The xfs inode contains 2 locks: a multi-reader lock called the + * i_iolock and a multi-reader lock called the i_lock. This routine + * allows either or both of the locks to be obtained. + * + * The 2 locks should always be ordered so that the IO lock is + * obtained first in order to prevent deadlock. + * + * ip -- the inode being locked + * lock_flags -- this parameter indicates the inode's locks + * to be locked. It can be: + * XFS_IOLOCK_SHARED, + * XFS_IOLOCK_SHARED | XFS_IOLOCK_NESTED, + * XFS_IOLOCK_EXCL, + * XFS_IOLOCK_EXCL | XFS_IOLOCK_NESTED, + * XFS_ILOCK_SHARED, + * XFS_ILOCK_EXCL, + * XFS_IOLOCK_SHARED | XFS_ILOCK_SHARED, + * XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL, + * XFS_IOLOCK_SHARED | XFS_IOLOCK_NESTED | XFS_ILOCK_SHARED, + * XFS_IOLOCK_SHARED | XFS_IOLOCK_NESTED | XFS_ILOCK_EXCL, + * XFS_IOLOCK_EXCL | XFS_ILOCK_SHARED, + * XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL + * XFS_IOLOCK_EXCL | XFS_IOLOCK_NESTED | XFS_ILOCK_SHARED, + * XFS_IOLOCK_EXCL | XFS_IOLOCK_NESTED | XFS_ILOCK_EXCL + */ +void +xfs_ilock_ra(xfs_inode_t *ip, + uint lock_flags, + void *return_address) +{ + /* + * You can't set both SHARED and EXCL for the same lock, + * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, + * and XFS_ILOCK_EXCL are valid values to set in lock_flags. + */ + ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) != + (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)); + ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) != + (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); + ASSERT((lock_flags & ~XFS_LOCK_MASK) == 0); + ASSERT(!(lock_flags & XFS_IOLOCK_NESTED)); + if (return_address == NULL) + return_address = (inst_t *)__return_address; + + if (!(lock_flags & XFS_IOLOCK_NESTED)) { + if (lock_flags & XFS_IOLOCK_EXCL) { + mrupdatef(&ip->i_iolock, PLTWAIT); + } else if (lock_flags & XFS_IOLOCK_SHARED) { + mraccessf(&ip->i_iolock, PLTWAIT); + } + } + if (lock_flags & XFS_ILOCK_EXCL) { + mrupdatef(&ip->i_lock, PLTWAIT); + ip->i_ilock_ra = return_address; + } else if (lock_flags & XFS_ILOCK_SHARED) { + mraccessf(&ip->i_lock, PLTWAIT); + } +#ifdef XFS_ILOCK_TRACE + xfs_ilock_trace(ip, 1, lock_flags, (inst_t *)return_address); +#endif +} + +void +xfs_ilock(xfs_inode_t *ip, + uint lock_flags) +{ + xfs_ilock_ra(ip, lock_flags, (inst_t *)__return_address); +} + +/* + * This is just like xfs_ilock(), except that the caller + * is guaranteed not to sleep. It returns 1 if it gets + * the requested locks and 0 otherwise. If the IO lock is + * obtained but the inode lock cannot be, then the IO lock + * is dropped before returning. + * + * ip -- the inode being locked + * lock_flags -- this parameter indicates the inode's locks to be + * to be locked. See the comment for xfs_ilock() for a list + * of valid values. + * + */ +int +xfs_ilock_nowait(xfs_inode_t *ip, + uint lock_flags) +{ + int iolocked; + int ilocked; + int iolock_recursive; + + /* + * You can't set both SHARED and EXCL for the same lock, + * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, + * and XFS_ILOCK_EXCL are valid values to set in lock_flags. + */ + ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) != + (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)); + ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) != + (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); + ASSERT((lock_flags & ~XFS_LOCK_MASK) == 0); + ASSERT(!(lock_flags & XFS_IOLOCK_NESTED)); + + iolocked = iolock_recursive = 0; + if (!(lock_flags & XFS_IOLOCK_NESTED)) { + if (lock_flags & XFS_IOLOCK_EXCL) { + iolocked = mrtryupdate(&ip->i_iolock); + if (!iolocked) { + return 0; + } + } else if (lock_flags & XFS_IOLOCK_SHARED) { + iolocked = mrtryaccess(&ip->i_iolock); + if (!iolocked) { + return 0; + } + } + } + if (lock_flags & XFS_ILOCK_EXCL) { + ilocked = mrtryupdate(&ip->i_lock); + if (!ilocked) { + if (iolocked) { + mrunlock(&ip->i_iolock); + } + return 0; + } + ip->i_ilock_ra = (inst_t *) __return_address; + } else if (lock_flags & XFS_ILOCK_SHARED) { + ilocked = mrtryaccess(&ip->i_lock); + if (!ilocked) { + if (iolocked) { + mrunlock(&ip->i_iolock); + } + return 0; + } + } +#ifdef XFS_ILOCK_TRACE + xfs_ilock_trace(ip, 2, lock_flags, (inst_t *)__return_address); +#endif + return 1; +} + +/* + * xfs_iunlock() is used to drop the inode locks acquired with + * xfs_ilock() and xfs_ilock_nowait(). The caller must pass + * in the flags given to xfs_ilock() or xfs_ilock_nowait() so + * that we know which locks to drop. + * + * ip -- the inode being unlocked + * lock_flags -- this parameter indicates the inode's locks to be + * to be unlocked. See the comment for xfs_ilock() for a list + * of valid values for this parameter. + * + */ +void +xfs_iunlock(xfs_inode_t *ip, + uint lock_flags) +{ + /* + * You can't set both SHARED and EXCL for the same lock, + * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, + * and XFS_ILOCK_EXCL are valid values to set in lock_flags. + */ + ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) != + (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)); + ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) != + (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); + ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_IUNLOCK_NONOTIFY)) == 0); + ASSERT(lock_flags != 0); + ASSERT(!(lock_flags & XFS_IOLOCK_NESTED)); + + if (!(lock_flags & XFS_IOLOCK_NESTED)) { + if (lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) { + ASSERT(!(lock_flags & XFS_IOLOCK_SHARED) || + (ismrlocked(&ip->i_iolock, MR_ACCESS))); + ASSERT(!(lock_flags & XFS_IOLOCK_EXCL) || + (ismrlocked(&ip->i_iolock, MR_UPDATE))); + mrunlock(&ip->i_iolock); + } + } + + if (lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) { + ASSERT(!(lock_flags & XFS_ILOCK_SHARED) || + (ismrlocked(&ip->i_lock, MR_ACCESS))); + ASSERT(!(lock_flags & XFS_ILOCK_EXCL) || + (ismrlocked(&ip->i_lock, MR_UPDATE))); + if (lock_flags & XFS_ILOCK_EXCL) + ip->i_ilock_ra = NULL; + mrunlock(&ip->i_lock); + } + + /* + * Let the AIL know that this item has been unlocked in case + * it is in the AIL and anyone is waiting on it. Don't do + * this if the caller has asked us not to. + */ + if (!(lock_flags & XFS_IUNLOCK_NONOTIFY) && ip->i_itemp != NULL) { + xfs_trans_unlocked_item(ip->i_mount, + (xfs_log_item_t*)(ip->i_itemp)); + } +#ifdef XFS_ILOCK_TRACE + xfs_ilock_trace(ip, 3, lock_flags, (inst_t *)__return_address); +#endif +} + +/* + * give up write locks. the i/o lock cannot be held nested + * if it is being demoted. + */ +void +xfs_ilock_demote(xfs_inode_t *ip, + uint lock_flags) +{ + ASSERT(lock_flags & (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)); + ASSERT((lock_flags & ~(XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)) == 0); + + if (lock_flags & XFS_ILOCK_EXCL) { + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + mrdemote(&ip->i_lock); + } + if (lock_flags & XFS_IOLOCK_EXCL) { + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); + mrdemote(&ip->i_iolock); + } +} + +/* + * The following three routines simply manage the i_flock + * semaphore embedded in the inode. This semaphore synchronizes + * processes attempting to flush the in-core inode back to disk. + */ +void +xfs_iflock(xfs_inode_t *ip) +{ + psema(&(ip->i_flock), PINOD|PLTWAIT); +} + +int +xfs_iflock_nowait(xfs_inode_t *ip) +{ + return (cpsema(&(ip->i_flock))); +} + +void +xfs_ifunlock(xfs_inode_t *ip) +{ + ASSERT(valusema(&(ip->i_flock)) <= 0); + vsema(&(ip->i_flock)); +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_imap.h linux-2.4-xfs/linux/fs/xfs/xfs_imap.h --- linux-2.4.7/linux/fs/xfs/xfs_imap.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_imap.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_IMAP_H__ +#define __XFS_IMAP_H__ + +/* + * This is the structure passed to xfs_imap() to map + * an inode number to its on disk location. + */ +typedef struct xfs_imap { + xfs_daddr_t im_blkno; /* starting BB of inode chunk */ + uint im_len; /* length in BBs of inode chunk */ + xfs_agblock_t im_agblkno; /* logical block of inode chunk in ag */ + ushort im_ioffset; /* inode offset in block in "inodes" */ + ushort im_boffset; /* inode offset in block in bytes */ +} xfs_imap_t; + +#ifdef __KERNEL__ +struct xfs_mount; +struct xfs_trans; +int xfs_imap(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, + xfs_imap_t *, uint); +#endif + +#endif /* __XFS_IMAP_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_inode.c linux-2.4-xfs/linux/fs/xfs/xfs_inode.c --- linux-2.4.7/linux/fs/xfs/xfs_inode.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_inode.c Fri Jun 8 15:55:16 2001 @@ -0,0 +1,3695 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +xfs_zone_t *xfs_ifork_zone; +xfs_zone_t *xfs_inode_zone; +xfs_zone_t *xfs_chashlist_zone; + +/* + * Used in xfs_itruncate(). This is the maximum number of extents + * freed from a file in a single transaction. + */ +#define XFS_ITRUNC_MAX_EXTENTS 2 + +STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *); +STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int, int); +STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int, int); +STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int, int); + + +#ifdef DEBUG +/* + * Make sure that the extents in the given memory buffer + * are valid. + */ +STATIC void +xfs_validate_extents( + xfs_bmbt_rec_32_t *ep, + int nrecs, + xfs_exntfmt_t fmt) +{ + xfs_bmbt_irec_t irec; + int i; + xfs_bmbt_rec_t rec; + + for (i = 0; i < nrecs; i++) { + bcopy(ep, &rec, sizeof(rec)); + xfs_bmbt_get_all(&rec, &irec); + if (fmt == XFS_EXTFMT_NOSTATE) + ASSERT(irec.br_state == XFS_EXT_NORM); + ep++; + } +} +#else /* DEBUG */ +#define xfs_validate_extents(ep, nrecs, fmt) +#endif /* DEBUG */ + +/* + * Check that none of the inode's in the buffer have a next + * unlinked field of 0. + */ +#if defined(DEBUG) +void +xfs_inobp_check( + xfs_mount_t *mp, + xfs_buf_t *bp) +{ + int i; + int j; + xfs_dinode_t *dip; + + j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog; + + for (i = 0; i < j; i++) { + dip = (xfs_dinode_t *)xfs_buf_offset(bp, + i * mp->m_sb.sb_inodesize); + if (INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT)) { + xfs_fs_cmn_err(CE_ALERT, mp, + "Detected a bogus zero next_unlinked field in incore inode buffer 0x%p. About to pop an ASSERT.", + bp); + ASSERT(!INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT)); + } + } +} +#endif + +/* + * called from bwrite on xfs inode buffers + */ +void +xfs_inobp_bwcheck(xfs_buf_t *bp) +{ + xfs_mount_t *mp; + int i; + int j; + xfs_dinode_t *dip; + + ASSERT(XFS_BUF_FSPRIVATE3(bp, void *) != NULL); + + mp = XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *); + + + j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog; + + for (i = 0; i < j; i++) { + dip = (xfs_dinode_t *) xfs_buf_offset(bp, + i * mp->m_sb.sb_inodesize); + if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) { + cmn_err(CE_WARN, +"Bad magic # 0x%x in XFS inode buffer 0x%Lx, starting blockno %Ld, offset 0x%x", + INT_GET(dip->di_core.di_magic, ARCH_CONVERT), + (__uint64_t)(__psunsigned_t) bp, + (__int64_t) XFS_BUF_ADDR(bp), + xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize)); + xfs_fs_cmn_err(CE_WARN, mp, + "corrupt, unmount and run xfs_repair"); + } + if (INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT)) { + cmn_err(CE_WARN, +"Bad next_unlinked field (0) in XFS inode buffer 0x%x, starting blockno %Ld, offset 0x%x", + (__uint64_t)(__psunsigned_t) bp, + (__int64_t) XFS_BUF_ADDR(bp), + xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize)); + xfs_fs_cmn_err(CE_WARN, mp, + "corrupt, unmount and run xfs_repair"); + } + } + + return; +} + +/* + * This routine is called to map an inode number within a file + * system to the buffer containing the on-disk version of the + * inode. It returns a pointer to the buffer containing the + * on-disk inode in the bpp parameter, and in the dip parameter + * it returns a pointer to the on-disk inode within that buffer. + * + * If a non-zero error is returned, then the contents of bpp and + * dipp are undefined. + * + * Use xfs_imap() to determine the size and location of the + * buffer to read from disk. + */ +int +xfs_inotobp( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + xfs_dinode_t **dipp, + xfs_buf_t **bpp, + int *offset) +{ + int di_ok; + xfs_imap_t imap; + xfs_buf_t *bp; + int error; + xfs_dinode_t *dip; + + /* + * Call the space managment code to find the location of the + * inode on disk. + */ + imap.im_blkno = 0; + error = xfs_imap(mp, tp, ino, &imap, XFS_IMAP_LOOKUP); + if (error != 0) { + cmn_err(CE_WARN, + "xfs_inotobp: xfs_imap() returned an " + "error %d on %s. Returning error.", error, mp->m_fsname); + return error; + } + + /* + * If the inode number maps to a block outside the bounds of the + * file system then return NULL rather than calling read_buf + * and panicing when we get an error from the driver. + */ + if ((imap.im_blkno + imap.im_len) > + XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) { + cmn_err(CE_WARN, + "xfs_inotobp: inode number (%d + %d) maps to a block outside the bounds " + "of the file system %s. Returning EINVAL.", + imap.im_blkno, imap.im_len,mp->m_fsname); + return XFS_ERROR(EINVAL); + } + + /* + * Read in the buffer. If tp is NULL, xfs_trans_read_buf() will + * default to just a read_buf() call. + */ + error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno, + (int)imap.im_len, XFS_BUF_LOCK, &bp); + + if (error) { + cmn_err(CE_WARN, + "xfs_inotobp: xfs_trans_read_buf() returned an " + "error %d on %s. Returning error.", error, mp->m_fsname); + return error; + } + dip = (xfs_dinode_t *)xfs_buf_offset(bp, 0); + di_ok = + INT_GET(dip->di_core.di_magic, ARCH_CONVERT) == XFS_DINODE_MAGIC && + XFS_DINODE_GOOD_VERSION(INT_GET(dip->di_core.di_version, ARCH_CONVERT)); + if (XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP, + XFS_RANDOM_ITOBP_INOTOBP)) { + xfs_trans_brelse(tp, bp); + cmn_err(CE_WARN, + "xfs_inotobp: XFS_TEST_ERROR() returned an " + "error on %s. Returning EFSCORRUPTED.", mp->m_fsname); + return XFS_ERROR(EFSCORRUPTED); + } + + xfs_inobp_check(mp, bp); + + /* + * Set *dipp to point to the on-disk inode in the buffer. + */ + *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset); + *bpp = bp; + *offset = imap.im_boffset; + return 0; +} + + +/* + * This routine is called to map an inode to the buffer containing + * the on-disk version of the inode. It returns a pointer to the + * buffer containing the on-disk inode in the bpp parameter, and in + * the dip parameter it returns a pointer to the on-disk inode within + * that buffer. + * + * If a non-zero error is returned, then the contents of bpp and + * dipp are undefined. + * + * If the inode is new and has not yet been initialized, use xfs_imap() + * to determine the size and location of the buffer to read from disk. + * If the inode has already been mapped to its buffer and read in once, + * then use the mapping information stored in the inode rather than + * calling xfs_imap(). This allows us to avoid the overhead of looking + * at the inode btree for small block file systems (see xfs_dilocate()). + * We can tell whether the inode has been mapped in before by comparing + * its disk block address to 0. Only uninitialized inodes will have + * 0 for the disk block address. + */ +int +xfs_itobp( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_inode_t *ip, + xfs_dinode_t **dipp, + xfs_buf_t **bpp, + xfs_daddr_t bno) +{ + xfs_buf_t *bp; + int error; + xfs_imap_t imap; +#ifdef __KERNEL__ + int i; + int ni; +#endif + + if (ip->i_blkno == (xfs_daddr_t)0) { + /* + * Call the space management code to find the location of the + * inode on disk. + */ + imap.im_blkno = bno; + error = xfs_imap(mp, tp, ip->i_ino, &imap, XFS_IMAP_LOOKUP); + if (error != 0) { + return error; + } + + /* + * If the inode number maps to a block outside the bounds + * of the file system then return NULL rather than calling + * read_buf and panicing when we get an error from the + * driver. + */ + if ((imap.im_blkno + imap.im_len) > + XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) { + return XFS_ERROR(EINVAL); + } + + /* + * Fill in the fields in the inode that will be used to + * map the inode to its buffer from now on. + */ + ip->i_blkno = imap.im_blkno; + ip->i_len = imap.im_len; + ip->i_boffset = imap.im_boffset; + } else { + /* + * We've already mapped the inode once, so just use the + * mapping that we saved the first time. + */ + imap.im_blkno = ip->i_blkno; + imap.im_len = ip->i_len; + imap.im_boffset = ip->i_boffset; + } + ASSERT(bno == 0 || bno == imap.im_blkno); + + /* + * Read in the buffer. If tp is NULL, xfs_trans_read_buf() will + * default to just a read_buf() call. + */ + error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap.im_blkno, + (int)imap.im_len, XFS_BUF_LOCK, &bp); + + if (error) { + return error; + } +#ifdef __KERNEL__ + /* + * Validate the magic number and version of every inode in the buffer + * (if DEBUG kernel) or the first inode in the buffer, otherwise. + */ +#ifdef DEBUG + ni = BBTOB(imap.im_len) >> mp->m_sb.sb_inodelog; +#else + ni = 1; +#endif + for (i = 0; i < ni; i++) { + int di_ok; + xfs_dinode_t *dip; + + dip = (xfs_dinode_t *)xfs_buf_offset(bp, + (i << mp->m_sb.sb_inodelog)); + di_ok = INT_GET(dip->di_core.di_magic, ARCH_CONVERT) == XFS_DINODE_MAGIC && + XFS_DINODE_GOOD_VERSION(INT_GET(dip->di_core.di_version, ARCH_CONVERT)); + if (XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP, + XFS_RANDOM_ITOBP_INOTOBP)) { +#ifdef DEBUG + prdev("bad inode magic/vsn daddr 0x%Lx #%d (magic=%x)", + mp->m_dev, imap.im_blkno, i, + INT_GET(dip->di_core.di_magic, ARCH_CONVERT)); +#endif + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EFSCORRUPTED); + } + } +#endif /* __KERNEL__ */ + + xfs_inobp_check(mp, bp); + + /* + * Mark the buffer as an inode buffer now that it looks good + */ + XFS_BUF_SET_VTYPE(bp, B_FS_INO); + + /* + * Set *dipp to point to the on-disk inode in the buffer. + */ + *dipp = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset); + *bpp = bp; + return 0; +} + +/* + * Move inode type and inode format specific information from the + * on-disk inode to the in-core inode. For fifos, devs, and sockets + * this means set if_rdev to the proper value. For files, directories, + * and symlinks this means to bring in the in-line data or extent + * pointers. For a file in B-tree format, only the root is immediately + * brought in-core. The rest will be in-lined in if_extents when it + * is first referenced (see xfs_iread_extents()). + */ +STATIC int +xfs_iformat( + xfs_inode_t *ip, + xfs_dinode_t *dip, + int alloc_mode) +{ + xfs_attr_shortform_t *atp; + int size; + int error; + xfs_fsize_t di_size; + ip->i_df.if_ext_max = + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + error = 0; + + if (INT_GET(dip->di_core.di_nextents, ARCH_CONVERT) + + INT_GET(dip->di_core.di_anextents, ARCH_CONVERT) > + INT_GET(dip->di_core.di_nblocks, ARCH_CONVERT)) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt dinode %Lu, extent total = %d, nblocks = %Ld. Unmount and run xfs_repair.", + ip->i_ino, + (int)(INT_GET(dip->di_core.di_nextents, ARCH_CONVERT) + INT_GET(dip->di_core.di_anextents, ARCH_CONVERT)), + INT_GET(dip->di_core.di_nblocks, ARCH_CONVERT)); + return XFS_ERROR(EFSCORRUPTED); + } + + if (INT_GET(dip->di_core.di_forkoff, ARCH_CONVERT) > ip->i_mount->m_sb.sb_inodesize) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt dinode %Lu, forkoff = 0x%x. Unmount and run xfs_repair.", + ip->i_ino, (int)(INT_GET(dip->di_core.di_forkoff, ARCH_CONVERT))); + return XFS_ERROR(EFSCORRUPTED); + } + + switch (ip->i_d.di_mode & IFMT) { + case IFIFO: + case IFCHR: + case IFBLK: + case IFSOCK: + if (INT_GET(dip->di_core.di_format, ARCH_CONVERT) != XFS_DINODE_FMT_DEV) + return XFS_ERROR(EFSCORRUPTED); + ip->i_d.di_size = 0; + ip->i_df.if_u2.if_rdev = INT_GET(dip->di_u.di_dev, ARCH_CONVERT); + break; + + case IFREG: + case IFLNK: + case IFDIR: + switch (INT_GET(dip->di_core.di_format, ARCH_CONVERT)) { + case XFS_DINODE_FMT_LOCAL: + /* + * no local regular files yet + */ + if ((INT_GET(dip->di_core.di_mode, ARCH_CONVERT) & IFMT) == IFREG) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt inode (local format for regular file) %Lu. Unmount and run xfs_repair.", + ip->i_ino); + return XFS_ERROR(EFSCORRUPTED); + } + + di_size=INT_GET(dip->di_core.di_size, ARCH_CONVERT); + if (di_size > + XFS_DFORK_DSIZE_ARCH(dip, ip->i_mount, ARCH_CONVERT)) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt inode %Lu (bad size %Ld for local inode). Unmount and run xfs_repair.", + ip->i_ino, di_size); + return XFS_ERROR(EFSCORRUPTED); + } + + size = (int)di_size; + error = xfs_iformat_local(ip, dip, XFS_DATA_FORK, + size, alloc_mode); + break; + case XFS_DINODE_FMT_EXTENTS: + error = xfs_iformat_extents(ip, dip, XFS_DATA_FORK, + alloc_mode); + break; + case XFS_DINODE_FMT_BTREE: + error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK, + alloc_mode); + break; + default: + return XFS_ERROR(EFSCORRUPTED); + } + break; + + default: + return XFS_ERROR(EFSCORRUPTED); + } + if (error) { + return error; + } + if (!XFS_DFORK_Q_ARCH(dip, ARCH_CONVERT)) + return 0; + ASSERT(ip->i_afp == NULL); + ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, alloc_mode); + ip->i_afp->if_ext_max = + XFS_IFORK_ASIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + switch (INT_GET(dip->di_core.di_aformat, ARCH_CONVERT)) { + case XFS_DINODE_FMT_LOCAL: + atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT); + size = (int)INT_GET(atp->hdr.totsize, ARCH_CONVERT); + error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size, + alloc_mode); + break; + case XFS_DINODE_FMT_EXTENTS: + error = xfs_iformat_extents(ip, dip, XFS_ATTR_FORK, + alloc_mode); + break; + case XFS_DINODE_FMT_BTREE: + error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK, + alloc_mode); + break; + default: + error = XFS_ERROR(EFSCORRUPTED); + break; + } + if (error) { + kmem_zone_free(xfs_ifork_zone, ip->i_afp); + ip->i_afp = NULL; + xfs_idestroy_fork(ip, XFS_DATA_FORK); + } + return error; +} + +/* + * The file is in-lined in the on-disk inode. + * If it fits into if_inline_data, then copy + * it there, otherwise allocate a buffer for it + * and copy the data there. Either way, set + * if_data to point at the data. + * If we allocate a buffer for the data, make + * sure that its size is a multiple of 4 and + * record the real size in i_real_bytes. + */ +STATIC int +xfs_iformat_local( + xfs_inode_t *ip, + xfs_dinode_t *dip, + int whichfork, + int size, + int alloc_mode) +{ + xfs_ifork_t *ifp; + int real_size; + + /* + * If the size is unreasonable, then something + * is wrong and we just bail out rather than crash in + * kmem_alloc() or bcopy() below. + */ + if (size > XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT)) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt inode %Lu (bad size %d for local fork, size = %d). Unmount and run xfs_repair.", + ip->i_ino, size, + XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT)); + return XFS_ERROR(EFSCORRUPTED); + } + ifp = XFS_IFORK_PTR(ip, whichfork); + real_size = 0; + if (size == 0) + ifp->if_u1.if_data = NULL; + else if (size <= sizeof(ifp->if_u2.if_inline_data)) + ifp->if_u1.if_data = ifp->if_u2.if_inline_data; + else { + real_size = roundup(size, 4); + ifp->if_u1.if_data = kmem_alloc(real_size, alloc_mode); + } + ifp->if_bytes = size; + ifp->if_real_bytes = real_size; + if (size) + bcopy(XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), ifp->if_u1.if_data, size); + ifp->if_flags &= ~XFS_IFEXTENTS; + ifp->if_flags |= XFS_IFINLINE; + return 0; +} + +/* + * The file consists of a set of extents all + * of which fit into the on-disk inode. + * If there are few enough extents to fit into + * the if_inline_ext, then copy them there. + * Otherwise allocate a buffer for them and copy + * them into it. Either way, set if_extents + * to point at the extents. + */ +STATIC int +xfs_iformat_extents( + xfs_inode_t *ip, + xfs_dinode_t *dip, + int whichfork, + int alloc_mode) +{ + xfs_ifork_t *ifp; + int nex; + int real_size; + int size; + + ifp = XFS_IFORK_PTR(ip, whichfork); + nex = XFS_DFORK_NEXTENTS_ARCH(dip, whichfork, ARCH_CONVERT); + size = nex * (uint)sizeof(xfs_bmbt_rec_t); + + /* + * If the number of extents is unreasonable, then something + * is wrong and we just bail out rather than crash in + * kmem_alloc() or bcopy() below. + */ + if (size < 0 || size > XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT)) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt inode %Lu ((a)extents = %d). Unmount and run xfs_repair.", + ip->i_ino, nex); + return XFS_ERROR(EFSCORRUPTED); + } + + real_size = 0; + if (nex == 0) + ifp->if_u1.if_extents = NULL; + else if (nex <= XFS_INLINE_EXTS) + ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; + else { + ifp->if_u1.if_extents = kmem_alloc(size, alloc_mode); + ASSERT(ifp->if_u1.if_extents != NULL); + real_size = size; + } + ifp->if_bytes = size; + ifp->if_real_bytes = real_size; + if (size) { + xfs_validate_extents( + (xfs_bmbt_rec_32_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), + nex, XFS_EXTFMT_INODE(ip)); + bcopy(XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT), ifp->if_u1.if_extents, + size); + xfs_bmap_trace_exlist("xfs_iformat_extents", ip, nex, + whichfork); + if (whichfork != XFS_DATA_FORK || + XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE) + if (xfs_check_nostate_extents( + ifp->if_u1.if_extents, nex)) + return XFS_ERROR(EFSCORRUPTED); + } + ifp->if_flags |= XFS_IFEXTENTS; + return 0; +} + +/* + * The file has too many extents to fit into + * the inode, so they are in B-tree format. + * Allocate a buffer for the root of the B-tree + * and copy the root into it. The i_extents + * field will remain NULL until all of the + * extents are read in (when they are needed). + */ +STATIC int +xfs_iformat_btree( + xfs_inode_t *ip, + xfs_dinode_t *dip, + int whichfork, + int alloc_mode) +{ + xfs_bmdr_block_t *dfp; + xfs_ifork_t *ifp; + /* REFERENCED */ + int nrecs; + int size; + + ifp = XFS_IFORK_PTR(ip, whichfork); + dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT); + size = XFS_BMAP_BROOT_SPACE(dfp); + nrecs = XFS_BMAP_BROOT_NUMRECS(dfp); + + /* + * blow out if -- fork has less extents than can fit in + * fork (fork shouldn't be a btree format), root btree + * block has more records than can fit into the fork, + * or the number of extents is greater than the number of + * blocks. + */ + if (XFS_IFORK_NEXTENTS(ip, whichfork) <= ifp->if_ext_max + || XFS_BMDR_SPACE_CALC(nrecs) > + XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT) + || XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks) { + xfs_fs_cmn_err(CE_WARN, ip->i_mount, + "corrupt inode %Lu (btree). Unmount and run xfs_repair.", + ip->i_ino); + return XFS_ERROR(EFSCORRUPTED); + } + + ifp->if_broot_bytes = size; + ifp->if_broot = kmem_alloc(size, alloc_mode); + ASSERT(ifp->if_broot != NULL); + /* + * Copy and convert from the on-disk structure + * to the in-memory structure. + */ + xfs_bmdr_to_bmbt(dfp, XFS_DFORK_SIZE_ARCH(dip, ip->i_mount, whichfork, ARCH_CONVERT), + ifp->if_broot, size); + ifp->if_flags &= ~XFS_IFEXTENTS; + ifp->if_flags |= XFS_IFBROOT; + + return 0; +} + +/* + * xfs_xlate_dinode_core - translate an xfs_inode_core_t between ondisk + * and native format + * + * buf = on-disk representation + * dip = native representation + * dir = direction - +ve -> disk to native + * -ve -> native to disk + * arch = on-disk architecture + */ + +void +xfs_xlate_dinode_core(xfs_caddr_t buf, xfs_dinode_core_t *dip, + int dir, xfs_arch_t arch) +{ + xfs_dinode_core_t *buf_core; + xfs_dinode_core_t *mem_core; + + ASSERT(dir); + + buf_core=(xfs_dinode_core_t*)buf; + mem_core=(xfs_dinode_core_t*)dip; + + if (arch == ARCH_NOCONVERT) { + if (dir>0) { + bcopy((xfs_caddr_t)buf_core, (xfs_caddr_t)mem_core, sizeof(xfs_dinode_core_t)); + } else { + bcopy((xfs_caddr_t)mem_core, (xfs_caddr_t)buf_core, sizeof(xfs_dinode_core_t)); + } + return; + } + + INT_XLATE(buf_core->di_magic, mem_core->di_magic, dir, arch); + INT_XLATE(buf_core->di_mode, mem_core->di_mode, dir, arch); + INT_XLATE(buf_core->di_version, mem_core->di_version, dir, arch); + INT_XLATE(buf_core->di_format, mem_core->di_format, dir, arch); + INT_XLATE(buf_core->di_onlink, mem_core->di_onlink, dir, arch); + INT_XLATE(buf_core->di_uid, mem_core->di_uid, dir, arch); + INT_XLATE(buf_core->di_gid, mem_core->di_gid, dir, arch); + INT_XLATE(buf_core->di_nlink, mem_core->di_nlink, dir, arch); + INT_XLATE(buf_core->di_projid, mem_core->di_projid, dir, arch); + + if (dir>0) { + bcopy(buf_core->di_pad, mem_core->di_pad, sizeof(buf_core->di_pad)); + } else { + bcopy(mem_core->di_pad, buf_core->di_pad, sizeof(buf_core->di_pad)); + } + + INT_XLATE(buf_core->di_atime.t_sec, mem_core->di_atime.t_sec, dir, arch); + INT_XLATE(buf_core->di_atime.t_nsec,mem_core->di_atime.t_nsec, dir, arch); + + INT_XLATE(buf_core->di_mtime.t_sec, mem_core->di_mtime.t_sec, dir, arch); + INT_XLATE(buf_core->di_mtime.t_nsec,mem_core->di_mtime.t_nsec, dir, arch); + + INT_XLATE(buf_core->di_ctime.t_sec, mem_core->di_ctime.t_sec, dir, arch); + INT_XLATE(buf_core->di_ctime.t_nsec,mem_core->di_ctime.t_nsec, dir, arch); + + INT_XLATE(buf_core->di_size, mem_core->di_size, dir, arch); + INT_XLATE(buf_core->di_nblocks, mem_core->di_nblocks, dir, arch); + INT_XLATE(buf_core->di_extsize, mem_core->di_extsize, dir, arch); + + INT_XLATE(buf_core->di_nextents, mem_core->di_nextents, dir, arch); + INT_XLATE(buf_core->di_anextents, mem_core->di_anextents, dir, arch); + INT_XLATE(buf_core->di_forkoff, mem_core->di_forkoff, dir, arch); + INT_XLATE(buf_core->di_aformat, mem_core->di_aformat, dir, arch); + INT_XLATE(buf_core->di_dmevmask, mem_core->di_dmevmask, dir, arch); + INT_XLATE(buf_core->di_dmstate, mem_core->di_dmstate, dir, arch); + INT_XLATE(buf_core->di_flags, mem_core->di_flags, dir, arch); + INT_XLATE(buf_core->di_gen, mem_core->di_gen, dir, arch); + +} + +/* + * Given a mount structure and an inode number, return a pointer + * to a newly allocated in-core inode coresponding to the given + * inode number. + * + * Initialize the inode's attributes and extent pointers if it + * already has them (it will not if the inode has no links). + */ +int +xfs_iread( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + xfs_inode_t **ipp, + xfs_daddr_t bno) +{ + xfs_buf_t *bp; + xfs_dinode_t *dip; + xfs_inode_t *ip; + int error; + int alloc_mode = tp ? KM_SLEEP : KM_SLEEP_IO; + + ASSERT(xfs_inode_zone != NULL); + + ip = kmem_zone_zalloc(xfs_inode_zone, alloc_mode); + ip->i_ino = ino; + ip->i_dev = mp->m_dev; + ip->i_mount = mp; + + /* + * Get pointer's to the on-disk inode and the buffer containing it. + * If the inode number refers to a block outside the file system + * then xfs_itobp() will return NULL. In this case we should + * return NULL as well. Set i_blkno to 0 so that xfs_itobp() will + * know that this is a new incore inode. + */ + error = xfs_itobp(mp, tp, ip, &dip, &bp, bno); + + if (error != 0) { + kmem_zone_free(xfs_inode_zone, ip); + return error; + } + + /* + * Initialize inode's trace buffers. + * Do this before xfs_iformat in case it adds entries. + */ +#ifdef XFS_BMAP_TRACE + ip->i_xtrace = ktrace_alloc(XFS_BMAP_KTRACE_SIZE, alloc_mode); +#endif +#ifdef XFS_BMBT_TRACE + ip->i_btrace = ktrace_alloc(XFS_BMBT_KTRACE_SIZE, alloc_mode); +#endif +#ifdef XFS_RW_TRACE + ip->i_rwtrace = ktrace_alloc(XFS_RW_KTRACE_SIZE, alloc_mode); +#endif +#ifdef XFS_STRAT_TRACE + ip->i_strat_trace = ktrace_alloc(XFS_STRAT_KTRACE_SIZE, alloc_mode); +#endif +#ifdef XFS_ILOCK_TRACE + ip->i_lock_trace = ktrace_alloc(XFS_ILOCK_KTRACE_SIZE, alloc_mode); +#endif +#ifdef XFS_DIR2_TRACE + ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, alloc_mode); +#endif + + /* + * If we got something that isn't an inode it means someone + * (nfs or dmi) has a stale handle. + */ + if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) { + kmem_zone_free(xfs_inode_zone, ip); + xfs_trans_brelse(tp, bp); + return XFS_ERROR(EINVAL); + } + + /* + * If the on-disk inode is already linked to a directory + * entry, copy all of the inode into the in-core inode. + * xfs_iformat() handles copying in the inode format + * specific information. + * Otherwise, just get the truly permanent information. + */ + if (!INT_ISZERO(dip->di_core.di_mode, ARCH_CONVERT)) { + xfs_xlate_dinode_core((xfs_caddr_t)&dip->di_core, + &(ip->i_d), 1, ARCH_CONVERT); + error = xfs_iformat(ip, dip, alloc_mode); + if (error) { + kmem_zone_free(xfs_inode_zone, ip); + xfs_trans_brelse(tp, bp); + return error; + } + } else { + ip->i_d.di_magic = INT_GET(dip->di_core.di_magic, ARCH_CONVERT); + ip->i_d.di_version = INT_GET(dip->di_core.di_version, ARCH_CONVERT); + ip->i_d.di_gen = INT_GET(dip->di_core.di_gen, ARCH_CONVERT); + /* + * Make sure to pull in the mode here as well in + * case the inode is released without being used. + * This ensures that xfs_inactive() will see that + * the inode is already free and not try to mess + * with the uninitialized part of it. + */ + ip->i_d.di_mode = 0; + /* + * Initialize the per-fork minima and maxima for a new + * inode here. xfs_iformat will do it for old inodes. + */ + ip->i_df.if_ext_max = + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + } + + /* + * The inode format changed when we moved the link count and + * made it 32 bits long. If this is an old format inode, + * convert it in memory to look like a new one. If it gets + * flushed to disk we will convert back before flushing or + * logging it. We zero out the new projid field and the old link + * count field. We'll handle clearing the pad field (the remains + * of the old uuid field) when we actually convert the inode to + * the new format. We don't change the version number so that we + * can distinguish this from a real new format inode. + */ + if (ip->i_d.di_version == XFS_DINODE_VERSION_1) { + ip->i_d.di_nlink = ip->i_d.di_onlink; + ip->i_d.di_onlink = 0; + ip->i_d.di_projid = 0; + } + + ip->i_delayed_blks = 0; + + /* + * Mark the buffer containing the inode as something to keep + * around for a while. This helps to keep recently accessed + * meta-data in-core longer. + */ + XFS_BUF_SET_REF(bp, XFS_INO_REF); + + /* + * Use xfs_trans_brelse() to release the buffer containing the + * on-disk inode, because it was acquired with xfs_trans_read_buf() + * in xfs_itobp() above. If tp is NULL, this is just a normal + * brelse(). If we're within a transaction, then xfs_trans_brelse() + * will only release the buffer if it is not dirty within the + * transaction. It will be OK to release the buffer in this case, + * because inodes on disk are never destroyed and we will be + * locking the new in-core inode before putting it in the hash + * table where other processes can find it. Thus we don't have + * to worry about the inode being changed just because we released + * the buffer. + */ + xfs_trans_brelse(tp, bp); + *ipp = ip; + return 0; +} + +/* + * Read in extents from a btree-format inode. + * Allocate and fill in if_extents. Real work is done in xfs_bmap.c. + */ +int +xfs_iread_extents( + xfs_trans_t *tp, + xfs_inode_t *ip, + int whichfork) +{ + int error; + xfs_ifork_t *ifp; + size_t size; + + if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) + return XFS_ERROR(EFSCORRUPTED); + size = XFS_IFORK_NEXTENTS(ip, whichfork) * (uint)sizeof(xfs_bmbt_rec_t); + ifp = XFS_IFORK_PTR(ip, whichfork); + /* + * We know that the size is legal (it's checked in iformat_btree) + */ + ifp->if_u1.if_extents = kmem_alloc(size, tp ? KM_SLEEP : KM_SLEEP_IO); + ASSERT(ifp->if_u1.if_extents != NULL); + ifp->if_lastex = NULLEXTNUM; + ifp->if_bytes = ifp->if_real_bytes = (int)size; + ifp->if_flags |= XFS_IFEXTENTS; + error = xfs_bmap_read_extents(tp, ip, whichfork); + if (error) { + kmem_free(ifp->if_u1.if_extents, size); + ifp->if_u1.if_extents = NULL; + ifp->if_bytes = ifp->if_real_bytes = 0; + ifp->if_flags &= ~XFS_IFEXTENTS; + return error; + } + xfs_validate_extents((xfs_bmbt_rec_32_t *)ifp->if_u1.if_extents, + XFS_IFORK_NEXTENTS(ip, whichfork), XFS_EXTFMT_INODE(ip)); + return 0; +} + +/* + * Allocate an inode on disk and return a copy of it's in-core version. + * The in-core inode is locked exclusively. Set mode, nlink, and rdev + * appropriately within the inode. The uid and gid for the inode are + * set according to the contents of the given cred structure. + * + * Use xfs_dialloc() to allocate the on-disk inode. If xfs_dialloc() + * has a free inode available, call xfs_iget() + * to obtain the in-core version of the allocated inode. Finally, + * fill in the inode and log its initial contents. In this case, + * ialloc_context would be set to NULL and call_again set to false. + * + * If xfs_dialloc() does not have an available inode, + * it will replenish its supply by doing an allocation. Since we can + * only do one allocation within a transaction without deadlocks, we + * must commit the current transaction before returning the inode itself. + * In this case, therefore, we will set call_again to true and return. + * The caller should then commit the current transaction, start a new + * transaction, and call xfs_ialloc() again to actually get the inode. + * + * To ensure that some other process does not grab the inode that + * was allocated during the first call to xfs_ialloc(), this routine + * also returns the [locked] bp pointing to the head of the freelist + * as ialloc_context. The caller should hold this buffer across + * the commit and pass it back into this routine on the second call. + */ +int +xfs_ialloc( + xfs_trans_t *tp, + xfs_inode_t *pip, + mode_t mode, + nlink_t nlink, + dev_t rdev, + cred_t *cr, + xfs_prid_t prid, + int okalloc, + xfs_buf_t **ialloc_context, + boolean_t *call_again, + xfs_inode_t **ipp) +{ + xfs_ino_t ino; + xfs_inode_t *ip; + vnode_t *vp; + uint flags; + int error; + + /* + * Call the space management code to pick + * the on-disk inode to be allocated. + */ + ASSERT(pip != NULL); + error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc, + ialloc_context, call_again, &ino); + if (error != 0) { + return error; + } + if (*call_again || ino == NULLFSINO) { + *ipp = NULL; + return 0; + } + ASSERT(*ialloc_context == NULL); + + /* + * Get the in-core inode with the lock held exclusively. + * This is because we're setting fields here we need + * to prevent others from looking at until we're done. + */ + error = xfs_trans_iget(tp->t_mountp, tp, ino, XFS_ILOCK_EXCL, &ip); + if (error != 0) { + return error; + } + ASSERT(ip != NULL); + + vp = XFS_ITOV(ip); + vp->v_type = IFTOVT(mode); + ip->i_d.di_mode = (__uint16_t)mode; + ip->i_d.di_onlink = 0; + ip->i_d.di_nlink = nlink; + ASSERT(ip->i_d.di_nlink == nlink); + ip->i_d.di_uid = current->fsuid; + ip->i_d.di_gid = current->fsgid; + ip->i_d.di_projid = prid; + bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad)); + + /* + * If the superblock version is up to where we support new format + * inodes and this is currently an old format inode, then change + * the inode version number now. This way we only do the conversion + * here rather than here and in the flush/logging code. + */ + if (XFS_SB_VERSION_HASNLINK(&tp->t_mountp->m_sb) && + ip->i_d.di_version == XFS_DINODE_VERSION_1) { + ip->i_d.di_version = XFS_DINODE_VERSION_2; + /* + * We've already zeroed the old link count, the projid field, + * and the pad field. + */ + } + + /* + * Project ids won't be stored on disk if we are using a version 1 inode. + */ + if ( (prid != 0) && (ip->i_d.di_version == XFS_DINODE_VERSION_1)) + xfs_bump_ino_vers2(tp, ip); + + if (XFS_INHERIT_GID(pip, vp->v_vfsp)) { + ip->i_d.di_gid = pip->i_d.di_gid; + if ((pip->i_d.di_mode & ISGID) && (mode & IFMT) == IFDIR) { + ip->i_d.di_mode |= ISGID; + } + } + + /* + * If the group ID of the new file does not match the effective group + * ID or one of the supplementary group IDs, the ISGID bit is + * cleared. + */ + if (ip->i_d.di_mode & ISGID) { + if (!in_group_p((gid_t)ip->i_d.di_gid)) { + ip->i_d.di_mode &= ~ISGID; + } + } + + ip->i_d.di_size = 0; + ip->i_d.di_nextents = 0; + ASSERT(ip->i_d.di_nblocks == 0); + xfs_ichgtime(ip, XFS_ICHGTIME_CHG|XFS_ICHGTIME_ACC|XFS_ICHGTIME_MOD); + /* + * di_gen will have been taken care of in xfs_iread. + */ + ip->i_d.di_extsize = 0; + ip->i_d.di_dmevmask = 0; + ip->i_d.di_dmstate = 0; + ip->i_d.di_flags = 0; + flags = XFS_ILOG_CORE; + switch (mode & IFMT) { + case IFIFO: + case IFCHR: + case IFBLK: + case IFSOCK: + ip->i_d.di_format = XFS_DINODE_FMT_DEV; + ip->i_df.if_u2.if_rdev = IRIX_MKDEV(MAJOR(rdev), MINOR(rdev)); + ip->i_df.if_flags = 0; + flags |= XFS_ILOG_DEV; + break; + case IFREG: + case IFDIR: + case IFLNK: + ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; + ip->i_df.if_flags = XFS_IFEXTENTS; + ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0; + ip->i_df.if_u1.if_extents = NULL; + break; + default: + ASSERT(0); + } + /* + * Attribute fork settings for new inode. + */ + ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; + ip->i_d.di_anextents = 0; + + /* + * Make sure the vnode's VENF_LOCKING flag corresponds with + * the inode's mode. Also do some sanity checking that + * other vnode flags are not set. + */ + if (MANDLOCK(vp, ip->i_d.di_mode)) + VN_FLAGSET(vp, VENF_LOCKING); + else + VN_FLAGCLR(vp, VENF_LOCKING); + +#if DEBUG + { + uint badflags = VNOSWAP | + VISSWAP | + VREPLICABLE | + /* VNONREPLICABLE | XXX uncomment this */ + VDOCMP | + VFRLOCKS | + VSEMAPHORE | + VUSYNC | + VREMAPPING | + VMOUNTING; + + /* + * For shared mounts, VNOSWAP is set in xfs_iget + */ + if (tp->t_mountp->m_cxfstype != XFS_CXFS_NOT) + badflags &= ~VNOSWAP; + + ASSERT(!(vp->v_flag & badflags)); + } +#endif /* DEBUG */ + + /* + * Log the new values stuffed into the inode. + */ + xfs_trans_log_inode(tp, ip, flags); + *ipp = ip; + return 0; +} + +/* + * Check to make sure that there are no blocks allocated to the + * file beyond the size of the file. We don't check this for + * files with fixed size extents or real time extents, but we + * at least do it for regular files. + */ +#ifdef DEBUG +void +xfs_isize_check( + xfs_mount_t *mp, + xfs_inode_t *ip, + xfs_fsize_t isize) +{ + xfs_fsblock_t firstblock; + xfs_fileoff_t map_first; + int nimaps; + xfs_bmbt_irec_t imaps[2]; + + if ((ip->i_d.di_mode & IFMT) != IFREG) + return; + + if ( ip->i_d.di_flags & XFS_DIFLAG_REALTIME ) + return; + + nimaps = 2; + map_first = XFS_B_TO_FSB(mp, (xfs_ufsize_t)isize); + firstblock = NULLFSBLOCK; + /* + * The filesystem could be shutting down, so bmapi may return + * an error. + */ + if (xfs_bmapi(NULL, ip, map_first, + (XFS_B_TO_FSB(mp, + (xfs_ufsize_t)XFS_MAX_FILE_OFFSET) - + map_first), + XFS_BMAPI_ENTIRE, &firstblock, 0, imaps, &nimaps, + NULL)) + return; + ASSERT(nimaps == 1); + ASSERT(imaps[0].br_startblock == HOLESTARTBLOCK); +} +#endif /* DEBUG */ + +/* + * Calculate the last possible buffered byte in a file. This must + * include data that was buffered beyond the EOF by the write code. + * This also needs to deal with overflowing the xfs_fsize_t type + * which can happen for sizes near the limit. + * + * We also need to take into account any blocks beyond the EOF. It + * may be the case that they were buffered by a write which failed. + * In that case the pages will still be in memory, but the inode size + * will never have been updated. + */ +xfs_fsize_t +xfs_file_last_byte( + xfs_inode_t *ip) +{ + xfs_mount_t *mp; + xfs_fsize_t last_byte; + xfs_fileoff_t last_block; + xfs_fileoff_t size_last_block; + int error; + + ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE | MR_ACCESS)); + + mp = ip->i_mount; + /* + * Only check for blocks beyond the EOF if the extents have + * been read in. This eliminates the need for the inode lock, + * and it also saves us from looking when it really isn't + * necessary. + */ + if (ip->i_df.if_flags & XFS_IFEXTENTS) { + error = xfs_bmap_last_offset(NULL, ip, &last_block, + XFS_DATA_FORK); + if (error) { + last_block = 0; + } + } else { + last_block = 0; + } + size_last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)ip->i_d.di_size); + last_block = XFS_FILEOFF_MAX(last_block, size_last_block); + + last_byte = XFS_FSB_TO_B(mp, last_block); + if (last_byte < 0) { + return XFS_MAX_FILE_OFFSET; + } + last_byte += (1 << ip->i_iocore.io_max_io_log); + if (last_byte < 0) { + return XFS_MAX_FILE_OFFSET; + } + return last_byte; +} + +#if defined(XFS_RW_TRACE) +STATIC void +xfs_itrunc_trace( + int tag, + xfs_inode_t *ip, + int flag, + xfs_fsize_t new_size, + xfs_off_t toss_start, + xfs_off_t toss_finish) +{ + if (ip->i_rwtrace == NULL) { + return; + } + + ktrace_enter(ip->i_rwtrace, + (void*)((long)tag), + (void*)ip, + (void*)((ip->i_d.di_size >> 32) & 0xffffffff), + (void*)(ip->i_d.di_size & 0xffffffff), + (void*)((long)flag), + (void*)((new_size >> 32) & 0xffffffff), + (void*)(new_size & 0xffffffff), + (void*)((toss_start >> 32) & 0xffffffff), + (void*)(toss_start & 0xffffffff), + (void*)((toss_finish >> 32) & 0xffffffff), + (void*)(toss_finish & 0xffffffff), + (void*)((long)private.p_cpuid), + (void*)0, + (void*)0, + (void*)0, + (void*)0); +} +#else +#define xfs_itrunc_trace(tag, ip, flag, new_size, toss_start, toss_finish) +#endif + +/* + * Start the truncation of the file to new_size. The new size + * must be smaller than the current size. This routine will + * clear the buffer and page caches of file data in the removed + * range, and xfs_itruncate_finish() will remove the underlying + * disk blocks. + * + * The inode must have its I/O lock locked EXCLUSIVELY, and it + * must NOT have the inode lock held at all. This is because we're + * calling into the buffer/page cache code and we can't hold the + * inode lock when we do so. + * + * The flags parameter can have either the value XFS_ITRUNC_DEFINITE + * or XFS_ITRUNC_MAYBE. The XFS_ITRUNC_MAYBE value should be used + * in the case that the caller is locking things out of order and + * may not be able to call xfs_itruncate_finish() with the inode lock + * held without dropping the I/O lock. If the caller must drop the + * I/O lock before calling xfs_itruncate_finish(), then xfs_itruncate_start() + * must be called again with all the same restrictions as the initial + * call. + */ +void +xfs_itruncate_start( + xfs_inode_t *ip, + uint flags, + xfs_fsize_t new_size) +{ + xfs_fsize_t last_byte; + xfs_off_t toss_start; + xfs_mount_t *mp; + vnode_t *vp; + + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0); + ASSERT((new_size == 0) || (new_size <= ip->i_d.di_size)); + ASSERT((flags == XFS_ITRUNC_DEFINITE) || + (flags == XFS_ITRUNC_MAYBE)); + + mp = ip->i_mount; + vp = XFS_ITOV(ip); + /* + * Call VOP_TOSS_PAGES() or VOP_FLUSHINVAL_PAGES() to get rid of pages and buffers + * overlapping the region being removed. We have to use + * the less efficient VOP_FLUSHINVAL_PAGES() in the case that the + * caller may not be able to finish the truncate without + * dropping the inode's I/O lock. Make sure + * to catch any pages brought in by buffers overlapping + * the EOF by searching out beyond the isize by our + * block size. We round new_size up to a block boundary + * so that we don't toss things on the same block as + * new_size but before it. + * + * Before calling VOP_TOSS_PAGES() or VOP_FLUSHINVAL_PAGES(), make sure to + * call remapf() over the same region if the file is mapped. + * This frees up mapped file references to the pages in the + * given range and for the VOP_FLUSHINVAL_PAGES() case it ensures + * that we get the latest mapped changes flushed out. + */ + toss_start = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size); + toss_start = XFS_FSB_TO_B(mp, toss_start); + if (toss_start < 0) { + /* + * The place to start tossing is beyond our maximum + * file size, so there is no way that the data extended + * out there. + */ + return; + } + last_byte = xfs_file_last_byte(ip); + xfs_itrunc_trace(XFS_ITRUNC_START, ip, flags, new_size, toss_start, + last_byte); + if (last_byte > toss_start) { + if (flags & XFS_ITRUNC_DEFINITE) { + VOP_TOSS_PAGES(vp, toss_start, -1, FI_REMAPF_LOCKED); + } else { + VOP_FLUSHINVAL_PAGES(vp, toss_start, -1, FI_REMAPF_LOCKED); + } + } + +#ifdef DEBUG + if (new_size == 0) { + ASSERT(ip->i_iocore.io_queued_bufs == 0); + ASSERT(VN_CACHED(vp) == 0); + } +#endif +} + +/* + * Shrink the file to the given new_size. The new + * size must be smaller than the current size. + * This will free up the underlying blocks + * in the removed range after a call to xfs_itruncate_start() + * or xfs_atruncate_start(). + * + * The transaction passed to this routine must have made + * a permanent log reservation of at least XFS_ITRUNCATE_LOG_RES. + * This routine may commit the given transaction and + * start new ones, so make sure everything involved in + * the transaction is tidy before calling here. + * Some transaction will be returned to the caller to be + * committed. The incoming transaction must already include + * the inode, and both inode locks must be held exclusively. + * The inode must also be "held" within the transaction. On + * return the inode will be "held" within the returned transaction. + * This routine does NOT require any disk space to be reserved + * for it within the transaction. + * + * The fork parameter must be either xfs_attr_fork or xfs_data_fork, + * and it indicates the fork which is to be truncated. For the + * attribute fork we only support truncation to size 0. + * + * We use the sync parameter to indicate whether or not the first + * transaction we perform might have to be synchronous. For the attr fork, + * it needs to be so if the unlink of the inode is not yet known to be + * permanent in the log. This keeps us from freeing and reusing the + * blocks of the attribute fork before the unlink of the inode becomes + * permanent. + * + * For the data fork, we normally have to run synchronously if we're + * being called out of the inactive path or we're being called + * out of the create path where we're truncating an existing file. + * Either way, the truncate needs to be sync so blocks don't reappear + * in the file with altered data in case of a crash. wsync filesystems + * can run the first case async because anything that shrinks the inode + * has to run sync so by the time we're called here from inactive, the + * inode size is permanently set to 0. + * + * Calls from the truncate path always need to be sync unless we're + * in a wsync filesystem and the file has already been unlinked. + * + * The caller is responsible for correctly setting the sync parameter. + * It gets too hard for us to guess here which path we're being called + * out of just based on inode state. + */ +int +xfs_itruncate_finish( + xfs_trans_t **tp, + xfs_inode_t *ip, + xfs_fsize_t new_size, + int fork, + int sync) +{ + xfs_fsblock_t first_block; + xfs_fileoff_t first_unmap_block; + xfs_fileoff_t last_block; + xfs_filblks_t unmap_len=0; + xfs_mount_t *mp; + xfs_trans_t *ntp; + int done; + int committed; + xfs_bmap_free_t free_list; + int error; + + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0); + ASSERT((new_size == 0) || (new_size <= ip->i_d.di_size)); + ASSERT(*tp != NULL); + ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES); + ASSERT(ip->i_transp == *tp); + ASSERT(ip->i_itemp != NULL); + ASSERT(ip->i_itemp->ili_flags & XFS_ILI_HOLD); + + + ntp = *tp; + mp = (ntp)->t_mountp; + ASSERT(! XFS_NOT_DQATTACHED(mp, ip)); + + /* + * We only support truncating the entire attribute fork. + */ + if (fork == XFS_ATTR_FORK) { + new_size = 0LL; + } + first_unmap_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size); + xfs_itrunc_trace(XFS_ITRUNC_FINISH1, ip, 0, new_size, 0, 0); + /* + * The first thing we do is set the size to new_size permanently + * on disk. This way we don't have to worry about anyone ever + * being able to look at the data being freed even in the face + * of a crash. What we're getting around here is the case where + * we free a block, it is allocated to another file, it is written + * to, and then we crash. If the new data gets written to the + * file but the log buffers containing the free and reallocation + * don't, then we'd end up with garbage in the blocks being freed. + * As long as we make the new_size permanent before actually + * freeing any blocks it doesn't matter if they get writtten to. + * + * The callers must signal into us whether or not the size + * setting here must be synchronous. There are a few cases + * where it doesn't have to be synchronous. Those cases + * occur if the file is unlinked and we know the unlink is + * permanent or if the blocks being truncated are guaranteed + * to be beyond the inode eof (regardless of the link count) + * and the eof value is permanent. Both of these cases occur + * only on wsync-mounted filesystems. In those cases, we're + * guaranteed that no user will ever see the data in the blocks + * that are being truncated so the truncate can run async. + * In the free beyond eof case, the file may wind up with + * more blocks allocated to it than it needs if we crash + * and that won't get fixed until the next time the file + * is re-opened and closed but that's ok as that shouldn't + * be too many blocks. + * + * However, we can't just make all wsync xactions run async + * because there's one call out of the create path that needs + * to run sync where it's truncating an existing file to size + * 0 whose size is > 0. + * + * It's probably possible to come up with a test in this + * routine that would correctly distinguish all the above + * cases from the values of the function parameters and the + * inode state but for sanity's sake, I've decided to let the + * layers above just tell us. It's simpler to correctly figure + * out in the layer above exactly under what conditions we + * can run async and I think it's easier for others read and + * follow the logic in case something has to be changed. + * cscope is your friend -- rcc. + * + * The attribute fork is much simpler. + * + * For the attribute fork we allow the caller to tell us whether + * the unlink of the inode that led to this call is yet permanent + * in the on disk log. If it is not and we will be freeing extents + * in this inode then we make the first transaction synchronous + * to make sure that the unlink is permanent by the time we free + * the blocks. + */ + if (fork == XFS_DATA_FORK) { + if (ip->i_d.di_nextents > 0) { + ip->i_d.di_size = new_size; + if (sync) + xfs_trans_set_sync(ntp); + xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE); + } + } else if (sync) { + ASSERT(!(mp->m_flags & XFS_MOUNT_WSYNC)); + if (ip->i_d.di_anextents > 0) + xfs_trans_set_sync(ntp); + } + ASSERT(fork == XFS_DATA_FORK || + (fork == XFS_ATTR_FORK && + ((sync && !(mp->m_flags & XFS_MOUNT_WSYNC)) || + (sync == 0 && (mp->m_flags & XFS_MOUNT_WSYNC))))); + + /* + * Since it is possible for space to become allocated beyond + * the end of the file (in a crash where the space is allocated + * but the inode size is not yet updated), simply remove any + * blocks which show up between the new EOF and the maximum + * possible file size. If the first block to be removed is + * beyond the maximum file size (ie it is the same as last_block), + * then there is nothing to do. + */ + last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAX_FILE_OFFSET); + ASSERT(first_unmap_block <= last_block); + done = 0; + if (last_block == first_unmap_block) { + done = 1; + } else { + unmap_len = last_block - first_unmap_block + 1; + } + while (!done) { + /* + * Free up up to XFS_ITRUNC_MAX_EXTENTS. xfs_bunmapi() + * will tell us whether it freed the entire range or + * not. If this is a synchronous mount (wsync), + * then we can tell bunmapi to keep all the + * transactions asynchronous since the unlink + * transaction that made this inode inactive has + * already hit the disk. There's no danger of + * the freed blocks being reused, there being a + * crash, and the reused blocks suddenly reappearing + * in this file with garbage in them once recovery + * runs. + */ + XFS_BMAP_INIT(&free_list, &first_block); + error = xfs_bunmapi(ntp, ip, first_unmap_block, + unmap_len, + XFS_BMAPI_AFLAG(fork) | + (sync ? 0 : XFS_BMAPI_ASYNC), + XFS_ITRUNC_MAX_EXTENTS, + &first_block, &free_list, &done); + if (error) { + /* + * If the bunmapi call encounters an error, + * return to the caller where the transaction + * can be properly aborted. We just need to + * make sure we're not holding any resources + * that we were not when we came in. + */ + xfs_bmap_cancel(&free_list); + return error; + } + + /* + * Duplicate the transaction that has the permanent + * reservation and commit the old transaction. + */ + error = xfs_bmap_finish(tp, &free_list, first_block, + &committed); + ntp = *tp; + if (error) { + /* + * If the bmap finish call encounters an error, + * return to the caller where the transaction + * can be properly aborted. We just need to + * make sure we're not holding any resources + * that we were not when we came in. + * + * Aborting from this point might lose some + * blocks in the file system, but oh well. + */ + xfs_bmap_cancel(&free_list); + if (committed) { + /* + * If the passed in transaction committed + * in xfs_bmap_finish(), then we want to + * add the inode to this one before returning. + * This keeps things simple for the higher + * level code, because it always knows that + * the inode is locked and held in the + * transaction that returns to it whether + * errors occur or not. We don't mark the + * inode dirty so that this transaction can + * be easily aborted if possible. + */ + xfs_trans_ijoin(ntp, ip, + XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ihold(ntp, ip); + } + return error; + } + + if (committed) { + /* + * The first xact was committed, + * so add the inode to the new one. + * Mark it dirty so it will be logged + * and moved forward in the log as + * part of every commit. + */ + xfs_trans_ijoin(ntp, ip, + XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ihold(ntp, ip); + xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE); + } + ntp = xfs_trans_dup(ntp); + (void) xfs_trans_commit(*tp, 0, NULL); + *tp = ntp; + error = xfs_trans_reserve(ntp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT); + /* + * Add the inode being truncated to the next chained + * transaction. + */ + xfs_trans_ijoin(ntp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ihold(ntp, ip); + if (error) + return (error); + } + /* + * Only update the size in the case of the data fork, but + * always re-log the inode so that our permanent transaction + * can keep on rolling it forward in the log. + */ + if (fork == XFS_DATA_FORK) { + xfs_isize_check(mp, ip, new_size); + ip->i_d.di_size = new_size; + } + xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE); + ASSERT((new_size != 0) || + (fork == XFS_ATTR_FORK) || + ((ip->i_delayed_blks == 0) && + (ip->i_iocore.io_queued_bufs == 0))); + ASSERT((new_size != 0) || + (fork == XFS_ATTR_FORK) || + (ip->i_d.di_nextents == 0)); + xfs_itrunc_trace(XFS_ITRUNC_FINISH2, ip, 0, new_size, 0, 0); + return 0; +} + + +/* + * xfs_igrow_start + * + * Do the first part of growing a file: zero any data in the last + * block that is beyond the old EOF. We need to do this before + * the inode is joined to the transaction to modify the i_size. + * That way we can drop the inode lock and call into the buffer + * cache to get the buffer mapping the EOF. + */ +int +xfs_igrow_start( + xfs_inode_t *ip, + xfs_fsize_t new_size, + cred_t *credp) +{ + xfs_fsize_t isize; + int error; + + ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0); + ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0); + ASSERT(new_size > ip->i_d.di_size); + + error = 0; + isize = ip->i_d.di_size; + /* + * Zero any pages that may have been created by + * xfs_write_file() beyond the end of the file + * and any blocks between the old and new file sizes. + */ + error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size, isize, NULL); + return error; +} + +/* + * xfs_igrow_finish + * + * This routine is called to extend the size of a file. + * The inode must have both the iolock and the ilock locked + * for update and it must be a part of the current transaction. + * The xfs_igrow_start() function must have been called previously. + * If the change_flag is not zero, the inode change timestamp will + * be updated. + */ +void +xfs_igrow_finish( + xfs_trans_t *tp, + xfs_inode_t *ip, + xfs_fsize_t new_size, + int change_flag) +{ + ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0); + ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0); + ASSERT(ip->i_transp == tp); + ASSERT(new_size > ip->i_d.di_size); + + /* + * Update the file size. Update the inode change timestamp + * if change_flag set. + */ + ip->i_d.di_size = new_size; + if (change_flag) + xfs_ichgtime(ip, XFS_ICHGTIME_CHG); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + +} + + +/* + * This is called when the inode's link count goes to 0. + * We place the on-disk inode on a list in the AGI. It + * will be pulled from this list when the inode is freed. + */ +int +xfs_iunlink( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + xfs_mount_t *mp; + xfs_agi_t *agi; + xfs_dinode_t *dip; + xfs_buf_t *agibp; + xfs_buf_t *ibp; + xfs_agnumber_t agno; + xfs_daddr_t agdaddr; + xfs_agino_t agino; + short bucket_index; + int offset; + int error; + int agi_ok; + + ASSERT(ip->i_d.di_nlink == 0); + ASSERT(ip->i_d.di_mode != 0); + ASSERT(ip->i_transp == tp); + + mp = tp->t_mountp; + + agno = XFS_INO_TO_AGNO(mp, ip->i_ino); + agdaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + + /* + * Get the agi buffer first. It ensures lock ordering + * on the list. + */ + error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, agdaddr, + 1, 0, &agibp); + if (error) { + return error; + } + /* + * Validate the magic number of the agi block. + */ + agi = XFS_BUF_TO_AGI(agibp); + agi_ok = + INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC && + XFS_AGI_GOOD_VERSION(INT_GET(agi->agi_versionnum, ARCH_CONVERT)); + if (XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IUNLINK, + XFS_RANDOM_IUNLINK)) { + xfs_trans_brelse(tp, agibp); + return XFS_ERROR(EFSCORRUPTED); + } + /* + * Get the index into the agi hash table for the + * list this inode will go on. + */ + agino = XFS_INO_TO_AGINO(mp, ip->i_ino); + ASSERT(agino != 0); + bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS; + ASSERT(INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT) != 0); + ASSERT(INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT) != agino); + + if (INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT) != NULLAGINO) { + /* + * There is already another inode in the bucket we need + * to add ourselves to. Add us at the front of the list. + * Here we put the head pointer into our next pointer, + * and then we fall through to point the head at us. + */ + error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0); + if (error) { + return error; + } + ASSERT(INT_GET(dip->di_next_unlinked, ARCH_CONVERT) == NULLAGINO); + ASSERT(!INT_ISZERO(dip->di_next_unlinked, ARCH_CONVERT)); + INT_SET(dip->di_next_unlinked, ARCH_CONVERT, + INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT)); + offset = ip->i_boffset + + offsetof(xfs_dinode_t, di_next_unlinked); + xfs_trans_inode_buf(tp, ibp); + xfs_trans_log_buf(tp, ibp, offset, + (offset + sizeof(xfs_agino_t) - 1)); + xfs_inobp_check(mp, ibp); + } + + /* + * Point the bucket head pointer at the inode being inserted. + */ + ASSERT(agino != 0); + INT_SET(agi->agi_unlinked[bucket_index], ARCH_CONVERT, agino); + offset = offsetof(xfs_agi_t, agi_unlinked) + + (sizeof(xfs_agino_t) * bucket_index); + xfs_trans_log_buf(tp, agibp, offset, + (offset + sizeof(xfs_agino_t) - 1)); + return 0; +} + +/* + * Pull the on-disk inode from the AGI unlinked list. + */ +STATIC int +xfs_iunlink_remove( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + xfs_ino_t next_ino; + xfs_mount_t *mp; + xfs_agi_t *agi; + xfs_dinode_t *dip; + xfs_buf_t *agibp; + xfs_buf_t *ibp; + xfs_agnumber_t agno; + xfs_daddr_t agdaddr; + xfs_agino_t agino; + xfs_agino_t next_agino; + xfs_buf_t *last_ibp; + xfs_dinode_t *last_dip; + short bucket_index; + int offset, last_offset; + int error; + int agi_ok; + + /* + * First pull the on-disk inode from the AGI unlinked list. + */ + mp = tp->t_mountp; + + agno = XFS_INO_TO_AGNO(mp, ip->i_ino); + agdaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + + /* + * Get the agi buffer first. It ensures lock ordering + * on the list. + */ + error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, agdaddr, + 1, 0, &agibp); + if (error != 0) { + cmn_err(CE_WARN, + "xfs_iunlink_remove: xfs_trans_read_buf() returned an error %d on %s. Returning error.", + error, mp->m_fsname); + return error; + } + /* + * Validate the magic number of the agi block. + */ + agi = XFS_BUF_TO_AGI(agibp); + agi_ok = + INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC && + XFS_AGI_GOOD_VERSION(INT_GET(agi->agi_versionnum, ARCH_CONVERT)); + if (XFS_TEST_ERROR(!agi_ok, mp, XFS_ERRTAG_IUNLINK_REMOVE, + XFS_RANDOM_IUNLINK_REMOVE)) { + xfs_trans_brelse(tp, agibp); + cmn_err(CE_WARN, + "xfs_iunlink_remove: XFS_TEST_ERROR() returned an error on %s. Returning EFSCORRUPTED.", + mp->m_fsname); + return XFS_ERROR(EFSCORRUPTED); + } + /* + * Get the index into the agi hash table for the + * list this inode will go on. + */ + agino = XFS_INO_TO_AGINO(mp, ip->i_ino); + ASSERT(agino != 0); + bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS; + ASSERT(INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT) != NULLAGINO); + ASSERT(INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT) != 0); + + if (INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT) == agino) { + /* + * We're at the head of the list. Get the inode's + * on-disk buffer to see if there is anyone after us + * on the list. Only modify our next pointer if it + * is not already NULLAGINO. This saves us the overhead + * of dealing with the buffer when there is no need to + * change it. + */ + error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0); + if (error) { + cmn_err(CE_WARN, + "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.", + error, mp->m_fsname); + return error; + } + next_agino = INT_GET(dip->di_next_unlinked, ARCH_CONVERT); + ASSERT(next_agino != 0); + if (next_agino != NULLAGINO) { + INT_SET(dip->di_next_unlinked, ARCH_CONVERT, NULLAGINO); + offset = ip->i_boffset + + offsetof(xfs_dinode_t, di_next_unlinked); + xfs_trans_inode_buf(tp, ibp); + xfs_trans_log_buf(tp, ibp, offset, + (offset + sizeof(xfs_agino_t) - 1)); + xfs_inobp_check(mp, ibp); + } else { + xfs_trans_brelse(tp, ibp); + } + /* + * Point the bucket head pointer at the next inode. + */ + ASSERT(next_agino != 0); + ASSERT(next_agino != agino); + INT_SET(agi->agi_unlinked[bucket_index], ARCH_CONVERT, next_agino); + offset = offsetof(xfs_agi_t, agi_unlinked) + + (sizeof(xfs_agino_t) * bucket_index); + xfs_trans_log_buf(tp, agibp, offset, + (offset + sizeof(xfs_agino_t) - 1)); + } else { + /* + * We need to search the list for the inode being freed. + */ + next_agino = INT_GET(agi->agi_unlinked[bucket_index], ARCH_CONVERT); + last_ibp = NULL; + while (next_agino != agino) { + /* + * If the last inode wasn't the one pointing to + * us, then release its buffer since we're not + * going to do anything with it. + */ + if (last_ibp != NULL) { + xfs_trans_brelse(tp, last_ibp); + } + next_ino = XFS_AGINO_TO_INO(mp, agno, next_agino); + error = xfs_inotobp(mp, tp, next_ino, &last_dip, + &last_ibp, &last_offset); + if (error) { + cmn_err(CE_WARN, + "xfs_iunlink_remove: xfs_inotobp() returned an error %d on %s. Returning error.", + error, mp->m_fsname); + return error; + } + next_agino = INT_GET(last_dip->di_next_unlinked, ARCH_CONVERT); + ASSERT(next_agino != NULLAGINO); + ASSERT(next_agino != 0); + } + /* + * Now last_ibp points to the buffer previous to us on + * the unlinked list. Pull us from the list. + */ + error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0); + if (error) { + cmn_err(CE_WARN, + "xfs_iunlink_remove: xfs_itobp() returned an error %d on %s. Returning error.", + error, mp->m_fsname); + return error; + } + next_agino = INT_GET(dip->di_next_unlinked, ARCH_CONVERT); + ASSERT(next_agino != 0); + ASSERT(next_agino != agino); + if (next_agino != NULLAGINO) { + INT_SET(dip->di_next_unlinked, ARCH_CONVERT, NULLAGINO); + offset = ip->i_boffset + + offsetof(xfs_dinode_t, di_next_unlinked); + xfs_trans_inode_buf(tp, ibp); + xfs_trans_log_buf(tp, ibp, offset, + (offset + sizeof(xfs_agino_t) - 1)); + xfs_inobp_check(mp, ibp); + } else { + xfs_trans_brelse(tp, ibp); + } + /* + * Point the previous inode on the list to the next inode. + */ + INT_SET(last_dip->di_next_unlinked, ARCH_CONVERT, next_agino); + ASSERT(next_agino != 0); + offset = last_offset + offsetof(xfs_dinode_t, di_next_unlinked); + xfs_trans_inode_buf(tp, last_ibp); + xfs_trans_log_buf(tp, last_ibp, offset, + (offset + sizeof(xfs_agino_t) - 1)); + xfs_inobp_check(mp, last_ibp); + } + return 0; +} + +/* + * This is called to return an inode to the inode free list. + * The inode should already be truncated to 0 length and have + * no pages associated with it. This routine also assumes that + * the inode is already a part of the transaction. + * + * The on-disk copy of the inode will have been added to the list + * of unlinked inodes in the AGI. We need to remove the inode from + * that list atomically with respect to freeing it here. + */ +int +xfs_ifree( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + int error; + + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + ASSERT(ip->i_transp == tp); + ASSERT(ip->i_d.di_nlink == 0); + ASSERT(ip->i_d.di_nextents == 0); + ASSERT(ip->i_d.di_anextents == 0); + ASSERT((ip->i_d.di_size == 0) || + ((ip->i_d.di_mode & IFMT) != IFREG)); + ASSERT(ip->i_d.di_nblocks == 0); + + /* + * Pull the on-disk inode from the AGI unlinked list. + */ + error = xfs_iunlink_remove(tp, ip); + if (error != 0) { + return error; + } + + error = xfs_difree(tp, ip->i_ino); + if (error != 0) { + return error; + } + ip->i_d.di_mode = 0; /* mark incore inode as free */ + ip->i_d.di_flags = 0; + ip->i_d.di_dmevmask = 0; + ip->i_d.di_forkoff = 0; /* mark the attr fork not in use */ + ip->i_df.if_ext_max = + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t); + ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; + ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; + + /* + * Bump the generation count so no one will be confused + * by reincarnations of this inode. + */ + ip->i_d.di_gen++; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + return 0; +} + +/* + * Reallocate the space for if_broot based on the number of records + * being added or deleted as indicated in rec_diff. Move the records + * and pointers in if_broot to fit the new size. When shrinking this + * will eliminate holes between the records and pointers created by + * the caller. When growing this will create holes to be filled in + * by the caller. + * + * The caller must not request to add more records than would fit in + * the on-disk inode root. If the if_broot is currently NULL, then + * if we adding records one will be allocated. The caller must also + * not request that the number of records go below zero, although + * it can go to zero. + * + * ip -- the inode whose if_broot area is changing + * ext_diff -- the change in the number of records, positive or negative, + * requested for the if_broot array. + */ +void +xfs_iroot_realloc( + xfs_inode_t *ip, + int rec_diff, + int whichfork) +{ + int cur_max; + xfs_ifork_t *ifp; + xfs_bmbt_block_t *new_broot; + int new_max; + size_t new_size; + char *np; + char *op; + + /* + * Handle the degenerate case quietly. + */ + if (rec_diff == 0) { + return; + } + + ifp = XFS_IFORK_PTR(ip, whichfork); + if (rec_diff > 0) { + /* + * If there wasn't any memory allocated before, just + * allocate it now and get out. + */ + if (ifp->if_broot_bytes == 0) { + new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(rec_diff); + ifp->if_broot = (xfs_bmbt_block_t*)kmem_alloc(new_size, + KM_SLEEP); + ifp->if_broot_bytes = (int)new_size; + return; + } + + /* + * If there is already an existing if_broot, then we need + * to realloc() it and shift the pointers to their new + * location. The records don't change location because + * they are kept butted up against the btree block header. + */ + cur_max = XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes); + new_max = cur_max + rec_diff; + new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max); + ifp->if_broot = (xfs_bmbt_block_t *) + kmem_realloc(ifp->if_broot, + new_size, + (size_t)XFS_BMAP_BROOT_SPACE_CALC(cur_max), /* old size */ + KM_SLEEP); + op = (char *)XFS_BMAP_BROOT_PTR_ADDR(ifp->if_broot, 1, + ifp->if_broot_bytes); + np = (char *)XFS_BMAP_BROOT_PTR_ADDR(ifp->if_broot, 1, + (int)new_size); + ifp->if_broot_bytes = (int)new_size; + ASSERT(ifp->if_broot_bytes <= + XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ); + ovbcopy(op, np, cur_max * (uint)sizeof(xfs_dfsbno_t)); + return; + } + + /* + * rec_diff is less than 0. In this case, we are shrinking the + * if_broot buffer. It must already exist. If we go to zero + * records, just get rid of the root and clear the status bit. + */ + ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0)); + cur_max = XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes); + new_max = cur_max + rec_diff; + ASSERT(new_max >= 0); + if (new_max > 0) + new_size = (size_t)XFS_BMAP_BROOT_SPACE_CALC(new_max); + else + new_size = 0; + if (new_size > 0) { + new_broot = (xfs_bmbt_block_t *)kmem_alloc(new_size, KM_SLEEP); + /* + * First copy over the btree block header. + */ + bcopy(ifp->if_broot, new_broot, sizeof(xfs_bmbt_block_t)); + } else { + new_broot = NULL; + ifp->if_flags &= ~XFS_IFBROOT; + } + + /* + * Only copy the records and pointers if there are any. + */ + if (new_max > 0) { + /* + * First copy the records. + */ + op = (char *)XFS_BMAP_BROOT_REC_ADDR(ifp->if_broot, 1, + ifp->if_broot_bytes); + np = (char *)XFS_BMAP_BROOT_REC_ADDR(new_broot, 1, + (int)new_size); + bcopy(op, np, new_max * (uint)sizeof(xfs_bmbt_rec_t)); + + /* + * Then copy the pointers. + */ + op = (char *)XFS_BMAP_BROOT_PTR_ADDR(ifp->if_broot, 1, + ifp->if_broot_bytes); + np = (char *)XFS_BMAP_BROOT_PTR_ADDR(new_broot, 1, + (int)new_size); + bcopy(op, np, new_max * (uint)sizeof(xfs_dfsbno_t)); + } + kmem_free(ifp->if_broot, ifp->if_broot_bytes); + ifp->if_broot = new_broot; + ifp->if_broot_bytes = (int)new_size; + ASSERT(ifp->if_broot_bytes <= + XFS_IFORK_SIZE(ip, whichfork) + XFS_BROOT_SIZE_ADJ); + return; +} + + +/* + * This is called when the amount of space needed for if_extents + * is increased or decreased. The change in size is indicated by + * the number of extents that need to be added or deleted in the + * ext_diff parameter. + * + * If the amount of space needed has decreased below the size of the + * inline buffer, then switch to using the inline buffer. Otherwise, + * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer + * to what is needed. + * + * ip -- the inode whose if_extents area is changing + * ext_diff -- the change in the number of extents, positive or negative, + * requested for the if_extents array. + */ +void +xfs_iext_realloc( + xfs_inode_t *ip, + int ext_diff, + int whichfork) +{ + int byte_diff; + xfs_ifork_t *ifp; + int new_size; + uint rnew_size; + + if (ext_diff == 0) { + return; + } + + ifp = XFS_IFORK_PTR(ip, whichfork); + byte_diff = ext_diff * (uint)sizeof(xfs_bmbt_rec_t); + new_size = (int)ifp->if_bytes + byte_diff; + ASSERT(new_size >= 0); + + if (new_size == 0) { + if (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext) { + ASSERT(ifp->if_real_bytes != 0); + kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes); + } + ifp->if_u1.if_extents = NULL; + rnew_size = 0; + } else if (new_size <= sizeof(ifp->if_u2.if_inline_ext)) { + /* + * If the valid extents can fit in if_inline_ext, + * copy them from the malloc'd vector and free it. + */ + if (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext) { + /* + * For now, empty files are format EXTENTS, + * so the if_extents pointer is null. + */ + if (ifp->if_u1.if_extents) { + bcopy(ifp->if_u1.if_extents, + ifp->if_u2.if_inline_ext, new_size); + kmem_free(ifp->if_u1.if_extents, + ifp->if_real_bytes); + } + ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; + } + rnew_size = 0; + } else { + rnew_size = new_size; + if ((rnew_size & (rnew_size - 1)) != 0) + rnew_size = xfs_iroundup(rnew_size); + /* + * Stuck with malloc/realloc. + */ + if (ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext) { + ifp->if_u1.if_extents = (xfs_bmbt_rec_t *) + kmem_alloc(rnew_size, KM_SLEEP); + bcopy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents, + sizeof(ifp->if_u2.if_inline_ext)); + } else if (rnew_size != ifp->if_real_bytes) { + ifp->if_u1.if_extents = (xfs_bmbt_rec_t *) + kmem_realloc(ifp->if_u1.if_extents, + rnew_size, + ifp->if_real_bytes, + KM_SLEEP); + } + } + ifp->if_real_bytes = rnew_size; + ifp->if_bytes = new_size; +} + + +/* + * This is called when the amount of space needed for if_data + * is increased or decreased. The change in size is indicated by + * the number of bytes that need to be added or deleted in the + * byte_diff parameter. + * + * If the amount of space needed has decreased below the size of the + * inline buffer, then switch to using the inline buffer. Otherwise, + * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer + * to what is needed. + * + * ip -- the inode whose if_data area is changing + * byte_diff -- the change in the number of bytes, positive or negative, + * requested for the if_data array. + */ +void +xfs_idata_realloc( + xfs_inode_t *ip, + int byte_diff, + int whichfork) +{ + xfs_ifork_t *ifp; + int new_size; + int real_size; + + if (byte_diff == 0) { + return; + } + + ifp = XFS_IFORK_PTR(ip, whichfork); + new_size = (int)ifp->if_bytes + byte_diff; + ASSERT(new_size >= 0); + + if (new_size == 0) { + if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { + kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes); + } + ifp->if_u1.if_data = NULL; + real_size = 0; + } else if (new_size <= sizeof(ifp->if_u2.if_inline_data)) { + /* + * If the valid extents/data can fit in if_inline_ext/data, + * copy them from the malloc'd vector and free it. + */ + if (ifp->if_u1.if_data == NULL) { + ifp->if_u1.if_data = ifp->if_u2.if_inline_data; + } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { + ASSERT(ifp->if_real_bytes != 0); + bcopy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data, + new_size); + kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes); + ifp->if_u1.if_data = ifp->if_u2.if_inline_data; + } + real_size = 0; + } else { + /* + * Stuck with malloc/realloc. + * For inline data, the underlying buffer must be + * a multiple of 4 bytes in size so that it can be + * logged and stay on word boundaries. We enforce + * that here. + */ + real_size = roundup(new_size, 4); + if (ifp->if_u1.if_data == NULL) { + ASSERT(ifp->if_real_bytes == 0); + ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP); + } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { + /* + * Only do the realloc if the underlying size + * is really changing. + */ + if (ifp->if_real_bytes != real_size) { + ifp->if_u1.if_data = + kmem_realloc(ifp->if_u1.if_data, + real_size, + ifp->if_real_bytes, + KM_SLEEP); + } + } else { + ASSERT(ifp->if_real_bytes == 0); + ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP); + bcopy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data, + ifp->if_bytes); + } + } + ifp->if_real_bytes = real_size; + ifp->if_bytes = new_size; + ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); +} + + + + +/* + * Map inode to disk block and offset. + * + * mp -- the mount point structure for the current file system + * tp -- the current transaction + * ino -- the inode number of the inode to be located + * imap -- this structure is filled in with the information necessary + * to retrieve the given inode from disk + * flags -- flags to pass to xfs_dilocate indicating whether or not + * lookups in the inode btree were OK or not + */ +int +xfs_imap( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + xfs_imap_t *imap, + uint flags) +{ + xfs_fsblock_t fsbno; + int len; + int off; + int error; + + fsbno = imap->im_blkno ? + XFS_DADDR_TO_FSB(mp, imap->im_blkno) : NULLFSBLOCK; + error = xfs_dilocate(mp, tp, ino, &fsbno, &len, &off, flags); + if (error != 0) { + return error; + } + imap->im_blkno = XFS_FSB_TO_DADDR(mp, fsbno); + imap->im_len = XFS_FSB_TO_BB(mp, len); + imap->im_agblkno = XFS_FSB_TO_AGBNO(mp, fsbno); + imap->im_ioffset = (ushort)off; + imap->im_boffset = (ushort)(off << mp->m_sb.sb_inodelog); + return 0; +} + +void +xfs_idestroy_fork( + xfs_inode_t *ip, + int whichfork) +{ + xfs_ifork_t *ifp; + + ifp = XFS_IFORK_PTR(ip, whichfork); + if (ifp->if_broot != NULL) { + kmem_free(ifp->if_broot, ifp->if_broot_bytes); + ifp->if_broot = NULL; + } + + /* + * If the format is local, then we can't have an extents + * array so just look for an inline data array. If we're + * not local then we may or may not have an extents list, + * so check and free it up if we do. + */ + if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { + if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) && + (ifp->if_u1.if_data != NULL)) { + ASSERT(ifp->if_real_bytes != 0); + kmem_free(ifp->if_u1.if_data, ifp->if_real_bytes); + ifp->if_u1.if_data = NULL; + ifp->if_real_bytes = 0; + } + } else if ((ifp->if_flags & XFS_IFEXTENTS) && + (ifp->if_u1.if_extents != NULL) && + (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)) { + ASSERT(ifp->if_real_bytes != 0); + kmem_free(ifp->if_u1.if_extents, ifp->if_real_bytes); + ifp->if_u1.if_extents = NULL; + ifp->if_real_bytes = 0; + } + ASSERT(ifp->if_u1.if_extents == NULL || + ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext); + ASSERT(ifp->if_real_bytes == 0); + if (whichfork == XFS_ATTR_FORK) { + kmem_zone_free(xfs_ifork_zone, ip->i_afp); + ip->i_afp = NULL; + } +} + +/* + * This is called free all the memory associated with an inode. + * It must free the inode itself and any buffers allocated for + * if_extents/if_data and if_broot. It must also free the lock + * associated with the inode. + */ +void +xfs_idestroy( + xfs_inode_t *ip) +{ + + switch (ip->i_d.di_mode & IFMT) { + case IFREG: + case IFDIR: + case IFLNK: + xfs_idestroy_fork(ip, XFS_DATA_FORK); + break; + } + if (ip->i_afp) + xfs_idestroy_fork(ip, XFS_ATTR_FORK); +#ifdef NOTYET + if (ip->i_range_lock.r_sleep != NULL) { + freesema(ip->i_range_lock.r_sleep); + kmem_free(ip->i_range_lock.r_sleep, sizeof(sema_t)); + } +#endif /* NOTYET */ + mrfree(&ip->i_lock); + mrfree(&ip->i_iolock); +#ifdef NOTYET + mutex_destroy(&ip->i_range_lock.r_spinlock); +#endif /* NOTYET */ + freesema(&ip->i_flock); + sv_destroy(&ip->i_pinsema); + spinlock_destroy(&ip->i_ipinlock); +#ifdef XFS_BMAP_TRACE + ktrace_free(ip->i_xtrace); +#endif +#ifdef XFS_BMBT_TRACE + ktrace_free(ip->i_btrace); +#endif +#ifdef XFS_RW_TRACE + ktrace_free(ip->i_rwtrace); +#endif +#ifdef XFS_STRAT_TRACE + ktrace_free(ip->i_strat_trace); +#endif +#ifdef XFS_ILOCK_TRACE + ktrace_free(ip->i_lock_trace); +#endif +#ifdef XFS_DIR2_TRACE + ktrace_free(ip->i_dir_trace); +#endif + if (ip->i_itemp) { + /* XXXdpd should be able to assert this but shutdown + * is leaving the AIL behind. */ + ASSERT(((ip->i_itemp->ili_item.li_flags & XFS_LI_IN_AIL) == 0) || + XFS_FORCED_SHUTDOWN(ip->i_mount)); + xfs_inode_item_destroy(ip); + } + kmem_zone_free(xfs_inode_zone, ip); +} + + +/* + * Increment the pin count of the given buffer. + * This value is protected by ipinlock spinlock in the mount structure. + */ +void +xfs_ipin( + xfs_inode_t *ip) +{ + int s; + + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + + s = mutex_spinlock(&ip->i_ipinlock); + ip->i_pincount++; + mutex_spinunlock(&ip->i_ipinlock, s); +} + +/* + * Decrement the pin count of the given inode, and wake up + * anyone in xfs_iwait_unpin() if the count goes to 0. The + * inode must have been previoulsy pinned with a call to xfs_ipin(). + */ +void +xfs_iunpin( + xfs_inode_t *ip) +{ + int s; + + ASSERT(ip->i_pincount > 0); + + s = mutex_spinlock(&ip->i_ipinlock); + ip->i_pincount--; + if (ip->i_pincount == 0) { + sv_broadcast(&ip->i_pinsema); + } + mutex_spinunlock(&ip->i_ipinlock, s); +} + +/* + * Returns the pincount at this given moment. + * Synchronizes with ipin/iunpin out of paranoia + */ +unsigned int +xfs_ipincount( + xfs_inode_t *ip) +{ + int s; + unsigned int cnt; + + s = mutex_spinlock(&ip->i_ipinlock); + cnt = ip->i_pincount; + mutex_spinunlock(&ip->i_ipinlock, s); + + return cnt; +} + +/* + * This is called to wait for the given inode to be unpinned. + * It will sleep until this happens. The caller must have the + * inode locked in at least shared mode so that the buffer cannot + * be subsequently pinned once someone is waiting for it to be + * unpinned. + * + * The ipinlock in the mount structure is used to guard the pincount + * values of all inodes in a file system. The i_pinsema is used to + * sleep until the inode is unpinned. + */ +void +xfs_iunpin_wait( + xfs_inode_t *ip) +{ + int s; + xfs_inode_log_item_t *iip; + xfs_lsn_t lsn; + + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE | MR_ACCESS)); + + if (ip->i_pincount == 0) { + return; + } + + iip = ip->i_itemp; + if (iip && iip->ili_last_lsn) { + lsn = iip->ili_last_lsn; + } else { + lsn = (xfs_lsn_t)0; + } + + /* + * Give the log a push so we don't wait here too long. + */ + xfs_log_force(ip->i_mount, lsn, XFS_LOG_FORCE); + + s = mutex_spinlock(&ip->i_ipinlock); + if (ip->i_pincount == 0) { + mutex_spinunlock(&ip->i_ipinlock, s); + return; + } + sv_wait(&(ip->i_pinsema), PINOD, &ip->i_ipinlock, s); + return; +} + + +/* + * xfs_iextents_copy() + * + * This is called to copy the REAL extents (as opposed to the delayed + * allocation extents) from the inode into the given buffer. It + * returns the number of bytes copied into the buffer. + * + * If there are no delayed allocation extents, then we can just + * bcopy() the extents into the buffer. Otherwise, we need to + * examine each extent in turn and skip those which are delayed. + */ +int +xfs_iextents_copy( + xfs_inode_t *ip, + xfs_bmbt_rec_32_t *buffer, + int whichfork) +{ + int copied; + xfs_bmbt_rec_32_t *dest_ep; + xfs_bmbt_rec_t *ep; +#ifdef DEBUG + xfs_exntfmt_t fmt = XFS_EXTFMT_INODE(ip); +#endif +#ifdef XFS_BMAP_TRACE + static char fname[] = "xfs_iextents_copy"; +#endif + int i; + xfs_ifork_t *ifp; + int nrecs; + xfs_fsblock_t start_block; + + ifp = XFS_IFORK_PTR(ip, whichfork); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS)); + ASSERT(ifp->if_bytes > 0); + + nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); + xfs_bmap_trace_exlist(fname, ip, nrecs, whichfork); + ASSERT(nrecs > 0); + if (nrecs == XFS_IFORK_NEXTENTS(ip, whichfork)) { + /* + * There are no delayed allocation extents, + * so just copy everything. + */ + ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); + ASSERT(ifp->if_bytes == + (XFS_IFORK_NEXTENTS(ip, whichfork) * + (uint)sizeof(xfs_bmbt_rec_t))); + bcopy(ifp->if_u1.if_extents, buffer, ifp->if_bytes); + xfs_validate_extents(buffer, nrecs, fmt); + return ifp->if_bytes; + } + + ASSERT(whichfork == XFS_DATA_FORK); + /* + * There are some delayed allocation extents in the + * inode, so copy the extents one at a time and skip + * the delayed ones. There must be at least one + * non-delayed extent. + */ + ASSERT(nrecs > ip->i_d.di_nextents); + ep = ifp->if_u1.if_extents; + dest_ep = buffer; + copied = 0; + for (i = 0; i < nrecs; i++) { + start_block = xfs_bmbt_get_startblock(ep); + if (ISNULLSTARTBLOCK(start_block)) { + /* + * It's a delayed allocation extent, so skip it. + */ + ep++; + continue; + } + + *dest_ep = *(xfs_bmbt_rec_32_t *)ep; + dest_ep++; + ep++; + copied++; + } + ASSERT(copied != 0); + ASSERT(copied == ip->i_d.di_nextents); + ASSERT((copied * (uint)sizeof(xfs_bmbt_rec_t)) <= XFS_IFORK_DSIZE(ip)); + xfs_validate_extents(buffer, copied, fmt); + + return (copied * (uint)sizeof(xfs_bmbt_rec_t)); +} + +/* + * Each of the following cases stores data into the same region + * of the on-disk inode, so only one of them can be valid at + * any given time. While it is possible to have conflicting formats + * and log flags, e.g. having XFS_ILOG_?DATA set when the fork is + * in EXTENTS format, this can only happen when the fork has + * changed formats after being modified but before being flushed. + * In these cases, the format always takes precedence, because the + * format indicates the current state of the fork. + */ +/*ARGSUSED*/ +STATIC int +xfs_iflush_fork( + xfs_inode_t *ip, + xfs_dinode_t *dip, + xfs_inode_log_item_t *iip, + int whichfork, + xfs_buf_t *bp) +{ + char *cp; + xfs_ifork_t *ifp; + xfs_mount_t *mp; +#ifdef XFS_TRANS_DEBUG + int first; +#endif + static const short brootflag[2] = + { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT }; + static const short dataflag[2] = + { XFS_ILOG_DDATA, XFS_ILOG_ADATA }; + static const short extflag[2] = + { XFS_ILOG_DEXT, XFS_ILOG_AEXT }; + + if (iip == NULL) + return 0; + ifp = XFS_IFORK_PTR(ip, whichfork); + /* + * This can happen if we gave up in iformat in an error path, + * for the attribute fork. + */ + if (ifp == NULL) { + ASSERT(whichfork == XFS_ATTR_FORK); + return 0; + } + cp = XFS_DFORK_PTR_ARCH(dip, whichfork, ARCH_CONVERT); + mp = ip->i_mount; + switch (XFS_IFORK_FORMAT(ip, whichfork)) { + case XFS_DINODE_FMT_LOCAL: + if ((iip->ili_format.ilf_fields & dataflag[whichfork]) && + (ifp->if_bytes > 0)) { + ASSERT(ifp->if_u1.if_data != NULL); + ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); + bcopy(ifp->if_u1.if_data, cp, ifp->if_bytes); + } + if (whichfork == XFS_DATA_FORK) { + if (XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp, dip)) { + return XFS_ERROR(EFSCORRUPTED); + } + } + break; + + case XFS_DINODE_FMT_EXTENTS: + ASSERT((ifp->if_flags & XFS_IFEXTENTS) || + !(iip->ili_format.ilf_fields & extflag[whichfork])); + ASSERT((ifp->if_u1.if_extents != NULL) || (ifp->if_bytes == 0)); + ASSERT((ifp->if_u1.if_extents == NULL) || (ifp->if_bytes > 0)); + if ((iip->ili_format.ilf_fields & extflag[whichfork]) && + (ifp->if_bytes > 0)) { + ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0); + (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_32_t *)cp, + whichfork); + } + break; + + case XFS_DINODE_FMT_BTREE: + if ((iip->ili_format.ilf_fields & brootflag[whichfork]) && + (ifp->if_broot_bytes > 0)) { + ASSERT(ifp->if_broot != NULL); + ASSERT(ifp->if_broot_bytes <= + (XFS_IFORK_SIZE(ip, whichfork) + + XFS_BROOT_SIZE_ADJ)); + xfs_bmbt_to_bmdr(ifp->if_broot, ifp->if_broot_bytes, + (xfs_bmdr_block_t *)cp, + XFS_DFORK_SIZE_ARCH(dip, mp, whichfork, ARCH_CONVERT)); + } + break; + + case XFS_DINODE_FMT_DEV: + if (iip->ili_format.ilf_fields & XFS_ILOG_DEV) { + ASSERT(whichfork == XFS_DATA_FORK); + INT_SET(dip->di_u.di_dev, ARCH_CONVERT, ip->i_df.if_u2.if_rdev); + } + break; + + case XFS_DINODE_FMT_UUID: + if (iip->ili_format.ilf_fields & XFS_ILOG_UUID) { + ASSERT(whichfork == XFS_DATA_FORK); + bcopy(&ip->i_df.if_u2.if_uuid, &dip->di_u.di_muuid, + sizeof(uuid_t)); + } + break; + + default: + ASSERT(0); + break; + } + + return 0; +} + +/* + * xfs_iflush() will write a modified inode's changes out to the + * inode's on disk home. The caller must have the inode lock held + * in at least shared mode and the inode flush semaphore must be + * held as well. The inode lock will still be held upon return from + * the call and the caller is free to unlock it. + * The inode flush lock will be unlocked when the inode reaches the disk. + * The flags indicate how the inode's buffer should be written out. + */ +int +xfs_iflush( + xfs_inode_t *ip, + uint flags) +{ + xfs_inode_log_item_t *iip; + xfs_buf_t *bp; + xfs_dinode_t *dip; + xfs_mount_t *mp; + int error; + /* REFERENCED */ + xfs_chash_t *ch; + xfs_inode_t *iq; + int clcount; /* count of inodes clustered */ + int bufwasdelwri; + enum { INT_DELWRI = (1 << 0), INT_ASYNC = (1 << 1) }; + SPLDECL(s); + + XFS_STATS_INC(xfsstats.xs_iflush_count); + + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS)); + ASSERT(valusema(&ip->i_flock) <= 0); + ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || + ip->i_d.di_nextents > ip->i_df.if_ext_max); + + iip = ip->i_itemp; + mp = ip->i_mount; + + /* + * If the inode isn't dirty, then just release the inode + * flush lock and do nothing. + */ + if ((ip->i_update_core == 0) && + ((iip == NULL) || !(iip->ili_format.ilf_fields & XFS_ILOG_ALL))) { + ASSERT((iip != NULL) ? + !(iip->ili_item.li_flags & XFS_LI_IN_AIL) : 1); + xfs_ifunlock(ip); + return 0; + } + + /* + * We can't flush the inode until it is unpinned, so + * wait for it. We know noone new can pin it, because + * we are holding the inode lock shared and you need + * to hold it exclusively to pin the inode. + */ + xfs_iunpin_wait(ip); + + /* + * This may have been unpinned because the filesystem is shutting + * down forcibly. If that's the case we must not write this inode + * to disk, because the log record didn't make it to disk! + */ + if (XFS_FORCED_SHUTDOWN(mp)) { + ip->i_update_core = 0; + if (iip) + iip->ili_format.ilf_fields = 0; + xfs_ifunlock(ip); + return XFS_ERROR(EIO); + } + + /* + * Get the buffer containing the on-disk inode. + */ + error = xfs_itobp(mp, NULL, ip, &dip, &bp, 0); + if (error != 0) { + xfs_ifunlock(ip); + return error; + } + + /* + * Decide how buffer will be flushed out. This is done before + * the call to xfs_iflush_int because this field is zeroed by it. + */ + if (iip != NULL && iip->ili_format.ilf_fields != 0) { + /* + * Flush out the inode buffer according to the directions + * of the caller. In the cases where the caller has given + * us a choice choose the non-delwri case. This is because + * the inode is in the AIL and we need to get it out soon. + */ + switch (flags) { + case XFS_IFLUSH_SYNC: + case XFS_IFLUSH_DELWRI_ELSE_SYNC: + flags = 0; + break; + case XFS_IFLUSH_ASYNC: + case XFS_IFLUSH_DELWRI_ELSE_ASYNC: + flags = INT_ASYNC; + break; + case XFS_IFLUSH_DELWRI: + flags = INT_DELWRI; + break; + default: + ASSERT(0); + flags = 0; + break; + } + } else { + switch (flags) { + case XFS_IFLUSH_DELWRI_ELSE_SYNC: + case XFS_IFLUSH_DELWRI_ELSE_ASYNC: + case XFS_IFLUSH_DELWRI: + flags = INT_DELWRI; + break; + case XFS_IFLUSH_ASYNC: + flags = INT_ASYNC; + break; + case XFS_IFLUSH_SYNC: + flags = 0; + break; + default: + ASSERT(0); + flags = 0; + break; + } + } + + /* + * First flush out the inode that xfs_iflush was called with. + */ + error = xfs_iflush_int(ip, bp); + if (error) { + goto corrupt_out; + } + + /* + * inode clustering: + * see if other inodes can be gathered into this write + */ + +#ifdef DEBUG + ip->i_chash->chl_buf = bp; /* inode clustering debug */ +#endif + + ch = XFS_CHASH(mp, ip->i_blkno); + s = mutex_spinlock(&ch->ch_lock); + + clcount = 0; + for (iq = ip->i_cnext; iq != ip; iq = iq->i_cnext) { + /* + * Do an un-protected check to see if the inode is dirty and + * is a candidate for flushing. These checks will be repeated + * later after the appropriate locks are acquired. + */ + iip = iq->i_itemp; + if ((iq->i_update_core == 0) && + ((iip == NULL) || + !(iip->ili_format.ilf_fields & XFS_ILOG_ALL)) && + iq->i_pincount == 0) { + continue; + } + + /* + * Try to get locks. If any are unavailable, + * then this inode cannot be flushed and is skipped. + */ + + /* get inode locks (just i_lock) */ + if (xfs_ilock_nowait(iq, XFS_ILOCK_SHARED)) { + /* get inode flush lock */ + if (xfs_iflock_nowait(iq)) { + /* check if ipined */ + if (xfs_ipincount(iq) == 0) { + /* arriving here means that + * this inode can be flushed. + * first re-check that it's + * dirty + */ + iip = iq->i_itemp; + if ((iq->i_update_core != 0)|| + ((iip != NULL) && + (iip->ili_format.ilf_fields & XFS_ILOG_ALL))) { + clcount++; + error = xfs_iflush_int(iq, bp); + if (error) { + xfs_iunlock(iq, + XFS_ILOCK_SHARED); + goto cluster_corrupt_out; + } + } else { + xfs_ifunlock(iq); + } + } else { + xfs_ifunlock(iq); + } + } + xfs_iunlock(iq, XFS_ILOCK_SHARED); + } + } + mutex_spinunlock(&ch->ch_lock, s); + + if (clcount) { + XFS_STATS_INC(xfsstats.xs_icluster_flushcnt); + XFS_STATS_ADD(xfsstats.xs_icluster_flushinode, clcount); + } + + /* + * If the buffer is pinned then push on the log so we won't + * get stuck waiting in the write for too long. + */ + if (XFS_BUF_ISPINNED(bp)){ + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); + } + + if (flags & INT_DELWRI) { + xfs_bdwrite(mp, bp); + } else if (flags & INT_ASYNC) { + xfs_bawrite(mp, bp); + } else { + error = xfs_bwrite(mp, bp); + } + return error; + +corrupt_out: + xfs_buf_relse(bp); + xfs_force_shutdown(mp, XFS_CORRUPT_INCORE); + xfs_iflush_abort(ip); + /* + * Unlocks the flush lock + */ + return XFS_ERROR(EFSCORRUPTED); + +cluster_corrupt_out: + /* Corruption detected in the clustering loop. Invalidate the + * inode buffer and shut down the filesystem. + */ + mutex_spinunlock(&ch->ch_lock, s); + + /* + * Clean up the buffer. If it was B_DELWRI, just release it -- + * brelse can handle it with no problems. If not, shut down the + * filesystem before releasing the buffer. + */ + if ((bufwasdelwri= XFS_BUF_ISDELAYWRITE(bp))) { + xfs_buf_relse(bp); + } + + xfs_force_shutdown(mp, XFS_CORRUPT_INCORE); + + if(!bufwasdelwri) { + /* + * Just like incore_relse: if we have b_iodone functions, + * mark the buffer as an error and call them. Otherwise + * mark it as stale and brelse. + */ + if (XFS_BUF_IODONE_FUNC(bp)) { + XFS_BUF_CLR_BDSTRAT_FUNC(bp); + XFS_BUF_UNDONE(bp); + XFS_BUF_STALE(bp); + XFS_BUF_SHUT(bp); + XFS_BUF_ERROR(bp,EIO); + xfs_biodone(bp); + } else { + XFS_BUF_STALE(bp); + xfs_buf_relse(bp); + } + } + + xfs_iflush_abort(iq); + /* + * Unlocks the flush lock + */ + return XFS_ERROR(EFSCORRUPTED); +} + + +STATIC int +xfs_iflush_int( + xfs_inode_t *ip, + xfs_buf_t *bp) +{ + xfs_inode_log_item_t *iip; + xfs_dinode_t *dip; + xfs_mount_t *mp; +#ifdef XFS_TRANS_DEBUG + int first; +#endif + SPLDECL(s); + + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS)); + ASSERT(valusema(&ip->i_flock) <= 0); + ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || + ip->i_d.di_nextents > ip->i_df.if_ext_max); + + iip = ip->i_itemp; + mp = ip->i_mount; + + + /* + * If the inode isn't dirty, then just release the inode + * flush lock and do nothing. + */ + if ((ip->i_update_core == 0) && + ((iip == NULL) || !(iip->ili_format.ilf_fields & XFS_ILOG_ALL))) { + xfs_ifunlock(ip); + return 0; + } + + /* set *dip = inode's place in the buffer */ + dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_boffset); + + /* + * Clear i_update_core before copying out the data. + * This is for coordination with our timestamp updates + * that don't hold the inode lock. They will always + * update the timestamps BEFORE setting i_update_core, + * so if we clear i_update_core after they set it we + * are guaranteed to see their updates to the timestamps. + * I believe that this depends on strongly ordered memory + * semantics, but we have that. We use the SYNCHRONIZE + * macro to make sure that the compiler does not reorder + * the i_update_core access below the data copy below. + */ + ip->i_update_core = 0; + SYNCHRONIZE(); + + if (XFS_TEST_ERROR(INT_GET(dip->di_core.di_magic,ARCH_CONVERT) != XFS_DINODE_MAGIC, + mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) { + xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp, + "xfs_iflush: Bad inode %Lu magic number 0x%x, ptr 0x%p", + ip->i_ino, (int) INT_GET(dip->di_core.di_magic, ARCH_CONVERT), dip); + goto corrupt_out; + } + if (XFS_TEST_ERROR(ip->i_d.di_magic != XFS_DINODE_MAGIC, + mp, XFS_ERRTAG_IFLUSH_2, XFS_RANDOM_IFLUSH_2)) { + xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp, + "xfs_iflush: Bad inode %Lu, ptr 0x%p, magic number 0x%x", + ip->i_ino, ip, ip->i_d.di_magic); + goto corrupt_out; + } + if ((ip->i_d.di_mode & IFMT) == IFREG) { + if (XFS_TEST_ERROR( + (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) && + (ip->i_d.di_format != XFS_DINODE_FMT_BTREE), + mp, XFS_ERRTAG_IFLUSH_3, XFS_RANDOM_IFLUSH_3)) { + xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp, + "xfs_iflush: Bad regular inode %Lu, ptr 0x%p", + ip->i_ino, ip); + goto corrupt_out; + } + } else if ((ip->i_d.di_mode & IFMT) == IFDIR) { + if (XFS_TEST_ERROR( + (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) && + (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) && + (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL), + mp, XFS_ERRTAG_IFLUSH_4, XFS_RANDOM_IFLUSH_4)) { + xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp, + "xfs_iflush: Bad directory inode %Lu, ptr 0x%p", + ip->i_ino, ip); + goto corrupt_out; + } + } + if (XFS_TEST_ERROR(ip->i_d.di_nextents + ip->i_d.di_anextents > + ip->i_d.di_nblocks, mp, XFS_ERRTAG_IFLUSH_5, + XFS_RANDOM_IFLUSH_5)) { + xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp, + "xfs_iflush: detected corrupt incore inode %Lu, total extents = %d, nblocks = %Ld, ptr 0x%p", + ip->i_ino, + ip->i_d.di_nextents + ip->i_d.di_anextents, + ip->i_d.di_nblocks, + ip); + goto corrupt_out; + } + if (XFS_TEST_ERROR(ip->i_d.di_forkoff > mp->m_sb.sb_inodesize, + mp, XFS_ERRTAG_IFLUSH_6, XFS_RANDOM_IFLUSH_6)) { + xfs_cmn_err(XFS_PTAG_IFLUSH, CE_ALERT, mp, + "xfs_iflush: bad inode %Lu, forkoff 0x%x, ptr 0x%p", + ip->i_ino, ip->i_d.di_forkoff, ip); + goto corrupt_out; + } + /* + * Copy the dirty parts of the inode into the on-disk + * inode. We always copy out the core of the inode, + * because if the inode is dirty at all the core must + * be. + */ + xfs_xlate_dinode_core((xfs_caddr_t)&(dip->di_core), &(ip->i_d), + -1, ARCH_CONVERT); + + /* + * If this is really an old format inode and the superblock version + * has not been updated to support only new format inodes, then + * convert back to the old inode format. If the superblock version + * has been updated, then make the conversion permanent. + */ + ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1 || + XFS_SB_VERSION_HASNLINK(&mp->m_sb)); + if (ip->i_d.di_version == XFS_DINODE_VERSION_1) { + if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) { + /* + * Convert it back. + */ + ASSERT(ip->i_d.di_nlink <= XFS_MAXLINK_1); + INT_SET(dip->di_core.di_onlink, ARCH_CONVERT, ip->i_d.di_nlink); + } else { + /* + * The superblock version has already been bumped, + * so just make the conversion to the new inode + * format permanent. + */ + ip->i_d.di_version = XFS_DINODE_VERSION_2; + INT_SET(dip->di_core.di_version, ARCH_CONVERT, XFS_DINODE_VERSION_2); + ip->i_d.di_onlink = 0; + INT_ZERO(dip->di_core.di_onlink, ARCH_CONVERT); + bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad)); + bzero(&(dip->di_core.di_pad[0]), + sizeof(dip->di_core.di_pad)); + ASSERT(ip->i_d.di_projid == 0); + } + } + + if (xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK, bp) == EFSCORRUPTED) { + goto corrupt_out; + } + + if (XFS_IFORK_Q(ip)) { + /* + * The only error from xfs_iflush_fork is on the data fork. + */ + (void) xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK, bp); + } + xfs_inobp_check(mp, bp); + + /* + * We've recorded everything logged in the inode, so we'd + * like to clear the ilf_fields bits so we don't log and + * flush things unnecessarily. However, we can't stop + * logging all this information until the data we've copied + * into the disk buffer is written to disk. If we did we might + * overwrite the copy of the inode in the log with all the + * data after re-logging only part of it, and in the face of + * a crash we wouldn't have all the data we need to recover. + * + * What we do is move the bits to the ili_last_fields field. + * When logging the inode, these bits are moved back to the + * ilf_fields field. In the xfs_iflush_done() routine we + * clear ili_last_fields, since we know that the information + * those bits represent is permanently on disk. As long as + * the flush completes before the inode is logged again, then + * both ilf_fields and ili_last_fields will be cleared. + * + * We can play with the ilf_fields bits here, because the inode + * lock must be held exclusively in order to set bits there + * and the flush lock protects the ili_last_fields bits. + * Set ili_logged so the flush done + * routine can tell whether or not to look in the AIL. + * Also, store the current LSN of the inode so that we can tell + * whether the item has moved in the AIL from xfs_iflush_done(). + * In order to read the lsn we need the AIL lock, because + * it is a 64 bit value that cannot be read atomically. + */ + if (iip != NULL && iip->ili_format.ilf_fields != 0) { + iip->ili_last_fields = iip->ili_format.ilf_fields; + iip->ili_format.ilf_fields = 0; + iip->ili_logged = 1; + + ASSERT(sizeof(xfs_lsn_t) == 8); /* don't lock if it shrinks */ + AIL_LOCK(mp,s); + iip->ili_flush_lsn = iip->ili_item.li_lsn; + AIL_UNLOCK(mp, s); + + /* + * Attach the function xfs_iflush_done to the inode's + * buffer. This will remove the inode from the AIL + * and unlock the inode's flush lock when the inode is + * completely written to disk. + */ + xfs_buf_attach_iodone(bp, (void(*)(xfs_buf_t*,xfs_log_item_t*)) + xfs_iflush_done, (xfs_log_item_t *)iip); + + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + ASSERT(XFS_BUF_IODONE_FUNC(bp) != NULL); + } else { + /* + * We're flushing an inode which is not in the AIL and has + * not been logged but has i_update_core set. For this + * case we can use a B_DELWRI flush and immediately drop + * the inode flush lock because we can avoid the whole + * AIL state thing. It's OK to drop the flush lock now, + * because we've already locked the buffer and to do anything + * you really need both. + */ + if (iip != NULL) { + ASSERT(iip->ili_logged == 0); + ASSERT(iip->ili_last_fields == 0); + ASSERT((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0); + } + xfs_ifunlock(ip); + } + + return 0; + +corrupt_out: + return XFS_ERROR(EFSCORRUPTED); +} + +/* + * Flush all inactive inodes in mp. Return true if no user references + * were found, false otherwise. + */ +int +xfs_iflush_all( + xfs_mount_t *mp, + int flag) +{ + int busy; + int done; + int purged; + xfs_inode_t *ip; + vmap_t vmap; + vnode_t *vp; + + busy = done = 0; + while (!done) { + purged = 0; + XFS_MOUNT_ILOCK(mp); + ip = mp->m_inodes; + if (ip == NULL) { + break; + } + do { + /* Make sure we skip markers inserted by sync */ + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } + + /* + * It's up to our caller to purge the root + * and quota vnodes later. + */ + vp = XFS_ITOV_NULL(ip); + + if (!vp) { + XFS_MOUNT_IUNLOCK(mp); + xfs_finish_reclaim(ip, 0, 1); + purged = 1; + break; + } + + if (vn_count(vp) != 0) { + if (vn_count(vp) == 1 && + (ip == mp->m_rootip || + (mp->m_quotainfo && + (ip->i_ino == mp->m_sb.sb_uquotino || + ip->i_ino == mp->m_sb.sb_gquotino)))) { + + ip = ip->i_mnext; + continue; + } + if (!(flag & XFS_FLUSH_ALL)) { + ASSERT(0); + busy = 1; + done = 1; + break; + } + /* + * Ignore busy inodes but continue flushing + * others. + */ + ip = ip->i_mnext; + continue; + } + /* + * Sample vp mapping while holding mp locked on MP + * systems, so we don't purge a reclaimed or + * nonexistent vnode. We break from the loop + * since we know that we modify + * it by pulling ourselves from it in xfs_reclaim() + * called via vn_purge() below. Set ip to the next + * entry in the list anyway so we'll know below + * whether we reached the end or not. + */ + VMAP(vp, ip, vmap); + vp->v_flag |= VPURGE; /* OK for vn_purge */ + XFS_MOUNT_IUNLOCK(mp); + + vn_purge(vp, &vmap); + + purged = 1; + break; + } while (ip != mp->m_inodes); + /* + * We need to distinguish between when we exit the loop + * after a purge and when we simply hit the end of the + * list. We can't use the (ip == mp->m_inodes) test, + * because when we purge an inode at the start of the list + * the next inode on the list becomes mp->m_inodes. That + * would cause such a test to bail out early. The purged + * variable tells us how we got out of the loop. + */ + if (!purged) { + done = 1; + } + } + XFS_MOUNT_IUNLOCK(mp); + return !busy; +} + + +/* + * xfs_iaccess: check accessibility of inode for mode. + */ +int +xfs_iaccess( + xfs_inode_t *ip, + mode_t mode, + cred_t *cr) +{ + int error; + mode_t orgmode = mode; + + /* + * Verify that the MAC policy allows the requested access. + */ + if ((error = _MAC_XFS_IACCESS(ip, mode, cr))) + return XFS_ERROR(error); + + if ((mode & IWRITE) && !WRITEALLOWED(XFS_ITOV(ip))) + return XFS_ERROR(EROFS); + + /* + * If there's an Access Control List it's used instead of + * the mode bits. + */ + if ((error = _ACL_XFS_IACCESS(ip, mode, cr)) != -1) + return error ? XFS_ERROR(error) : 0; + + if (current->fsuid != ip->i_d.di_uid) { + mode >>= 3; + if (!in_group_p((gid_t)ip->i_d.di_gid)) + mode >>= 3; + } + if (((ip->i_d.di_mode & mode) == mode) || capable_cred(cr, CAP_DAC_OVERRIDE)) + return 0; + + if ((orgmode == IREAD) || + (((ip->i_d.di_mode & IFMT) == IFDIR) && + (!(orgmode & ~(IWRITE|IEXEC))))) { + if (capable_cred(cr, CAP_DAC_READ_SEARCH)) + return 0; +#ifdef NOISE + cmn_err(CE_NOTE, "Ick: mode=%o, orgmode=%o", mode, orgmode); +#endif /* NOISE */ + return XFS_ERROR(EACCES); + } + return XFS_ERROR(EACCES); +} + +/* + * Return whether or not it is OK to swap to the given file in the + * given range. Return 0 for OK and otherwise return the error. + * + * It is only OK to swap to a file if it has no holes, and all + * extents have been initialized. + * + * We use the vnode behavior chain prevent and allow primitives + * to ensure that the vnode chain stays coherent while we do this. + * This allows us to walk the chain down to the bottom where XFS + * lives without worrying about it changing out from under us. + */ +int +xfs_swappable( + bhv_desc_t *bdp) +{ + xfs_inode_t *ip; + + ip = XFS_BHVTOI(bdp); + /* + * Verify that the file does not have any + * holes or unwritten exents. + */ + return xfs_bmap_check_swappable(ip); +} + +/* + * xfs_iroundup: round up argument to next power of two + */ +uint +xfs_iroundup( + uint v) +{ + int i; + uint m; + + if ((v & (v - 1)) == 0) + return v; + ASSERT((v & 0x80000000) == 0); + if ((v & (v + 1)) == 0) + return v + 1; + for (i = 0, m = 1; i < 31; i++, m <<= 1) { + if (v & m) + continue; + v |= m; + if ((v & (v + 1)) == 0) + return v + 1; + } + ASSERT(0); + return( 0 ); +} + +/* + * Change the requested timestamp in the given inode. + * We don't lock across timestamp updates, and we don't log them but + * we do record the fact that there is dirty information in core. + * + * NOTE -- callers MUST combine XFS_ICHGTIME_MOD or XFS_ICHGTIME_CHG + * with XFS_ICHGTIME_ACC to be sure that access time + * update will take. Calling first with XFS_ICHGTIME_ACC + * and then XFS_ICHGTIME_MOD may fail to modify the access + * timestamp if the filesystem is mounted noacctm. + */ +void +xfs_ichgtime(xfs_inode_t *ip, + int flags) +{ + timespec_t tv; + vnode_t *vp = XFS_ITOV(ip); + struct inode *inode = vp->v_inode; + + /* + * We're not supposed to change timestamps in readonly-mounted + * filesystems. Throw it away if anyone asks us. + */ + if (vp->v_vfsp->vfs_flag & VFS_RDONLY) + return; + + /* + * Don't update access timestamps on reads if mounted "noatime" + * Throw it away if anyone asks us. + */ + if (ip->i_mount->m_flags & XFS_MOUNT_NOATIME && + ((flags & (XFS_ICHGTIME_ACC|XFS_ICHGTIME_MOD|XFS_ICHGTIME_CHG)) + == XFS_ICHGTIME_ACC)) + return; + + nanotime(&tv); + if (flags & XFS_ICHGTIME_MOD) { + inode->i_mtime = ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec; + ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec; + } + if (flags & XFS_ICHGTIME_ACC) { + inode->i_atime = ip->i_d.di_atime.t_sec = (__int32_t)tv.tv_sec; + ip->i_d.di_atime.t_nsec = (__int32_t)tv.tv_nsec; + } + if (flags & XFS_ICHGTIME_CHG) { + inode->i_ctime = ip->i_d.di_ctime.t_sec = (__int32_t)tv.tv_sec; + ip->i_d.di_ctime.t_nsec = (__int32_t)tv.tv_nsec; + } + + /* + * We update the i_update_core field _after_ changing + * the timestamps in order to coordinate properly with + * xfs_iflush() so that we don't lose timestamp updates. + * This keeps us from having to hold the inode lock + * while doing this. We use the SYNCHRONIZE macro to + * ensure that the compiler does not reorder the update + * of i_update_core above the timestamp updates above. + */ + SYNCHRONIZE(); + ip->i_update_core = 1; +} + +/* + * xfs_get_inode() + * + * This routine takes the dev_t of a file system and an + * inode number on that file system, and returns a pointer + * to the corresponding incore xfs inode structure. + * + * RETURNS: + * xfs_inode_t pointer on success + * NULL on failure + * + */ +xfs_inode_t * +xfs_get_inode( dev_t fs_dev, xfs_ino_t ino) +{ + struct vfs *vfsp; + bhv_desc_t *bdp; + xfs_inode_t *ip = NULL ; + int error; + + /* + * Lookup the vfs structure and mark it busy. + * This prevents race conditions with unmount. + * + * If this returns NULL, the file system may be in the process + * of being unmounted. The unmount may succeed or fail. If the + * umount fails, the grio ticket will remain attached to the + * inode structure. It will be cleanup when the inode structure is + * freed. + */ + vfsp = vfs_busydev( fs_dev, xfs_fstype ); + + if (vfsp) { + + bdp = bhv_lookup_unlocked(VFS_BHVHEAD(vfsp), &xfs_vfsops); + error = xfs_iget( XFS_BHVTOM( bdp ), + NULL, ino, XFS_ILOCK_SHARED, &ip, 0); + + if ( error ) { + ip = NULL; + } + + if ( (ip == NULL) || (ip->i_d.di_mode == 0) ) { + if (ip) { + xfs_iunlock( ip, XFS_ILOCK_SHARED ); + } + ip = NULL; + } + + + /* + * Decrement the vfs busy count. + */ + vfs_unbusy( vfsp ); + } + + return( ip ); +} + +/* + * xfs_ibusy_check -- Checks whether inode reference count allows unmount + * + * The value returned is one if the reference count would prevent an unmount. + */ +int +xfs_ibusy_check( + xfs_inode_t *ip, + int refs) +{ + xfs_mount_t *mp = ip->i_mount; + + if ((refs == 1) && (ip == mp->m_rootip)) + return (0); + if ((refs == 1) && (ip == mp->m_rbmip)) + return (0); + if ((refs == 1) && (ip == mp->m_rsumip)) + return (0); + if (mp->m_quotainfo && ip->i_ino == mp->m_sb.sb_uquotino) + return (0); + if (mp->m_quotainfo && ip->i_ino == mp->m_sb.sb_gquotino) + return (0); + return (1); +} + +#ifdef XFS_ILOCK_TRACE +void +xfs_ilock_trace(xfs_inode_t *ip, int lock, unsigned int lockflags, inst_t *ra) +{ + ktrace_enter(ip->i_lock_trace, + (void *)ip, + (void *)(__psint_t)lock, /* 1 = LOCK, 3=UNLOCK, etc */ + (void *)(__psint_t)lockflags, /* XFS_ILOCK_EXCL etc */ + (void *)ra, /* caller of ilock */ + (void *)(__psint_t)cpuid(), + (void *)(__psint_t)current_pid(), + 0,0,0,0,0,0,0,0,0,0); + +} +#endif /* ILOCK_TRACE */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_inode.h linux-2.4-xfs/linux/fs/xfs/xfs_inode.h --- linux-2.4.7/linux/fs/xfs/xfs_inode.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_inode.h Fri Jun 8 15:55:16 2001 @@ -0,0 +1,602 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_INODE_H__ +#define __XFS_INODE_H__ + +/* + * File incore extent information, present for each of data & attr forks. + */ +#define XFS_INLINE_EXTS 2 +#define XFS_INLINE_DATA 32 +typedef struct xfs_ifork { + int if_bytes; /* bytes in if_u1 */ + int if_real_bytes; /* bytes allocated in if_u1 */ + xfs_bmbt_block_t *if_broot; /* file's incore btree root */ + short if_broot_bytes; /* bytes allocated for root */ + unsigned char if_flags; /* per-fork flags */ + unsigned char if_ext_max; /* max # of extent records */ + xfs_extnum_t if_lastex; /* last if_extents used */ + union { + xfs_bmbt_rec_t *if_extents; /* linear map file exts */ + char *if_data; /* inline file data */ + } if_u1; + union { + xfs_bmbt_rec_t if_inline_ext[XFS_INLINE_EXTS]; + /* very small file extents */ + char if_inline_data[XFS_INLINE_DATA]; + /* very small file data */ + xfs_dev_t if_rdev; /* dev number if special */ + uuid_t if_uuid; /* mount point value */ + } if_u2; +} xfs_ifork_t; + +/* + * Flags for xfs_ichgtime(). + */ +#define XFS_ICHGTIME_MOD 0x1 /* data fork modification timestamp */ +#define XFS_ICHGTIME_ACC 0x2 /* data fork access timestamp */ +#define XFS_ICHGTIME_CHG 0x4 /* inode field change timestamp */ + +/* + * Per-fork incore inode flags. + */ +#define XFS_IFINLINE 0x0001 /* Inline data is read in */ +#define XFS_IFEXTENTS 0x0002 /* All extent pointers are read in */ +#define XFS_IFBROOT 0x0004 /* i_broot points to the bmap b-tree root */ + +/* + * Flags for xfs_imap() and xfs_dilocate(). + */ +#define XFS_IMAP_LOOKUP 0x1 + +/* + * Maximum number of extent pointers in if_u1.if_extents. + */ +#define XFS_MAX_INCORE_EXTENTS 32768 + + +#ifdef __KERNEL__ +struct bhv_desc; +struct cred; +struct ktrace; +struct vnode; +struct xfs_buf; +struct xfs_bmap_free; +struct xfs_bmbt_irec; +struct xfs_bmbt_block; +struct xfs_ext_attr; +struct xfs_inode; +struct xfs_inode_log_item; +struct xfs_mount; +struct xfs_trans; +struct xfs_dquot; +struct pm; + + +/* + * This structure is used to communicate which extents of a file + * were holes when a write started from xfs_write_file() to + * xfs_strat_read(). This is necessary so that we can know which + * blocks need to be zeroed when they are read in in xfs_strat_read() + * if they weren\'t allocated when the buffer given to xfs_strat_read() + * was mapped. + * + * We keep a list of these attached to the inode. The list is + * protected by the inode lock and the fact that the io lock is + * held exclusively by writers. + */ +typedef struct xfs_gap { + struct xfs_gap *xg_next; + xfs_fileoff_t xg_offset_fsb; + xfs_extlen_t xg_count_fsb; +} xfs_gap_t; + +/* + * This structure is used to hold common pieces of the buffer + * and file for xfs_dio_write and xfs_dio_read. + */ +typedef struct xfs_dio { + struct xfs_buf *xd_bp; + bhv_desc_t *xd_bdp; + struct xfs_inode *xd_ip; + struct xfs_iocore *xd_io; + struct cred *xd_cr; + struct pm *xd_pmp; + int xd_blkalgn; + int xd_ioflag; + xfs_off_t xd_start; + size_t xd_length; +} xfs_dio_t; + + +typedef struct xfs_iocore { + void *io_obj; /* pointer to container + * inode or dcxvn structure */ + struct xfs_mount *io_mount; /* fs mount struct ptr */ + mrlock_t *io_lock; /* inode lock */ + mrlock_t *io_iolock; /* inode IO lock */ + sema_t *io_flock; /* inode flush lock */ + + /* I/O state */ + xfs_fsize_t io_new_size; /* sz when write completes */ + unsigned int io_readio_blocks; /* read buffer size */ + unsigned int io_writeio_blocks; /* write buffer size */ + uchar_t io_readio_log; /* log2 of read buffer size */ + uchar_t io_writeio_log; /* log2 of write buffer size */ + uchar_t io_max_io_log; /* max r/w io value */ + int io_queued_bufs; /* count of xfsd queued bufs*/ + + /* Miscellaneous state. */ + unsigned int io_flags; /* IO related flags */ + + /* DMAPI state */ + __uint32_t io_dmevmask; /* DMIG event mask */ + __uint16_t io_dmstate; /* DMIG state info */ +} xfs_iocore_t; + +#define XFS_IO_INODE(io) ((xfs_inode_t *) ((io)->io_obj)) +#define XFS_IO_DCXVN(io) ((dcxvn_t *) ((io)->io_obj)) + +/* + * Flags in the flags field + */ + +#define XFS_IOCORE_ISXFS 0x01 +#define XFS_IOCORE_ISCXFS 0x02 +#define XFS_IOCORE_RT 0x04 +#define XFS_IOCORE_UIOSZ 0x08 + +#define IO_IS_XFS(io) ((io)->io_flags & XFS_IOCORE_ISXFS) + +/* + * Clear out the read-ahead state in the in-core inode. + * We actually only need to clear i_next_offset and + * i_last_req_sz to get the effect of making all the + * read ahead state unusable. + */ +#define XFS_INODE_CLEAR_READ_AHEAD(io) + + +/* + * xfs_iocore prototypes + */ + +extern void xfs_iocore_inode_init(struct xfs_inode *); +extern void xfs_iocore_inode_reinit(struct xfs_inode *); +extern void xfs_iocore_reset(xfs_iocore_t *); + + +/* + * This is the type used in the xfs inode hash table. + * An array of these is allocated for each mounted + * file system to hash the inodes for that file system. + */ +typedef struct xfs_ihash { + struct xfs_inode *ih_next; + mrlock_t ih_lock; + uint ih_version; +} xfs_ihash_t; +#if defined(MP) +#pragma set type attribute xfs_ihash align=128 +#endif + +/* + * Inode hashing and hash bucket locking. + */ +#define XFS_BUCKETS(mp) (37*(mp)->m_sb.sb_agcount-1) +#define XFS_IHASH(mp,ino) ((mp)->m_ihash + (((uint)ino) % (mp)->m_ihsize)) + +/* + * This is the xfs inode cluster hash. This hash is used by xfs_iflush to + * find inodes that share a cluster and can be flushed to disk at the same + * time. + */ + +typedef struct xfs_chashlist { + struct xfs_chashlist *chl_next; + struct xfs_inode *chl_ip; + xfs_daddr_t chl_blkno; /* starting block number of + * the cluster */ +#ifdef DEBUG + struct xfs_buf *chl_buf; /* debug: the inode buffer */ +#endif +} xfs_chashlist_t; + +typedef struct xfs_chash { + xfs_chashlist_t *ch_list; + lock_t ch_lock; +} xfs_chash_t; + + +/* + * This is the xfs in-core inode structure. + * Most of the on-disk inode is embedded in the i_d field. + * + * The extent pointers/inline file space, however, are managed + * separately. The memory for this information is pointed to by + * the if_u1 unions depending on the type of the data. + * This is used to linearize the array of extents for fast in-core + * access. This is used until the file's number of extents + * surpasses XFS_MAX_INCORE_EXTENTS, at which point all extent pointers + * are accessed through the buffer cache. + * + * Other state kept in the in-core inode is used for identification, + * locking, transactional updating, etc of the inode. + * + * Generally, we do not want to hold the i_rlock while holding the + * i_ilock. Hierarchy is i_iolock followed by i_rlock. + * + * xfs_iptr_t contains all the inode fields upto and including the + * i_mnext and i_mprev fields, it is used as a marker in the inode + * chain off the mount structure by xfs_sync calls. + */ + +typedef struct { + struct xfs_ihash *ip_hash; /* pointer to hash header */ + struct xfs_inode *ip_next; /* inode hash link forw */ + struct xfs_inode *ip_mnext; /* next inode in mount list */ + struct xfs_inode *ip_mprev; /* ptr to prev inode */ + struct xfs_inode **ip_prevp; /* ptr to prev i_next */ + struct xfs_mount *ip_mount; /* fs mount struct ptr */ +} xfs_iptr_t; + +typedef struct xfs_inode { + /* Inode linking and identification information. */ + struct xfs_ihash *i_hash; /* pointer to hash header */ + struct xfs_inode *i_next; /* inode hash link forw */ + struct xfs_inode *i_mnext; /* next inode in mount list */ + struct xfs_inode *i_mprev; /* ptr to prev inode */ + struct xfs_inode **i_prevp; /* ptr to prev i_next */ + struct xfs_mount *i_mount; /* fs mount struct ptr */ + struct bhv_desc i_bhv_desc; /* inode behavior descriptor*/ + struct xfs_dquot *i_udquot; /* user dquot */ + struct xfs_dquot *i_gdquot; /* group dquot */ + + /* Inode location stuff */ + xfs_ino_t i_ino; /* inode number (agno/agino)*/ + xfs_daddr_t i_blkno; /* blkno of inode buffer */ + dev_t i_dev; /* dev for this inode */ + ushort i_len; /* len of inode buffer */ + ushort i_boffset; /* off of inode in buffer */ + + /* Extent information. */ + xfs_ifork_t *i_afp; /* attribute fork pointer */ + xfs_ifork_t i_df; /* data fork */ + + /* Transaction and locking information. */ + struct xfs_trans *i_transp; /* ptr to owning transaction*/ + struct xfs_inode_log_item *i_itemp; /* logging information */ + mrlock_t i_lock; /* inode lock */ + mrlock_t i_iolock; /* inode IO lock */ + sema_t i_flock; /* inode flush lock */ + unsigned int i_pincount; /* inode pin count */ + sv_t i_pinsema; /* inode pin sema */ + lock_t i_ipinlock; /* inode pinning mutex */ + struct xfs_inode **i_refcache; /* ptr to entry in ref cache */ + struct xfs_inode *i_release; /* inode to unref */ + + /* I/O state */ + xfs_iocore_t i_iocore; /* I/O core */ + + /* Miscellaneous state. */ + unsigned short i_flags; /* see defined flags below */ + unsigned short i_update_core; /* timestamps/size is dirty */ + unsigned short i_update_size; /* di_size field is dirty */ + unsigned int i_gen; /* generation count */ + unsigned int i_delayed_blks; /* count of delay alloc blks */ + struct xfs_ext_attr *i_ext_attr; /* Critical ext attributes */ + void *i_ilock_ra; /* current ilock ret addr */ + + xfs_dinode_core_t i_d; /* most of ondisk inode */ + xfs_chashlist_t *i_chash; /* cluster hash list header */ + struct xfs_inode *i_cnext; /* cluster hash link forward */ + struct xfs_inode *i_cprev; /* cluster hash link backward */ + +#ifdef DEBUG + /* Trace buffers per inode. */ + struct ktrace *i_xtrace; /* inode extent list trace */ + struct ktrace *i_btrace; /* inode bmap btree trace */ + struct ktrace *i_rwtrace; /* inode read/write trace */ + struct ktrace *i_strat_trace; /* inode strat_write trace */ + struct ktrace *i_lock_trace; /* inode lock/unlock trace */ + struct ktrace *i_dir_trace; /* inode directory trace */ +#endif /* DEBUG */ +} xfs_inode_t; + +#endif /* __KERNEL__ */ + + +/* + * Fork handling. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_PTR) +xfs_ifork_t *xfs_ifork_ptr(xfs_inode_t *ip, int w); +#define XFS_IFORK_PTR(ip,w) xfs_ifork_ptr(ip,w) +#else +#define XFS_IFORK_PTR(ip,w) ((w) == XFS_DATA_FORK ? &(ip)->i_df : (ip)->i_afp) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_Q) +int xfs_ifork_q(xfs_inode_t *ip); +#define XFS_IFORK_Q(ip) xfs_ifork_q(ip) +#else +#define XFS_IFORK_Q(ip) XFS_CFORK_Q(&(ip)->i_d) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_DSIZE) +int xfs_ifork_dsize(xfs_inode_t *ip); +#define XFS_IFORK_DSIZE(ip) xfs_ifork_dsize(ip) +#else +#define XFS_IFORK_DSIZE(ip) XFS_CFORK_DSIZE(&ip->i_d, ip->i_mount) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_ASIZE) +int xfs_ifork_asize(xfs_inode_t *ip); +#define XFS_IFORK_ASIZE(ip) xfs_ifork_asize(ip) +#else +#define XFS_IFORK_ASIZE(ip) XFS_CFORK_ASIZE(&ip->i_d, ip->i_mount) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_SIZE) +int xfs_ifork_size(xfs_inode_t *ip, int w); +#define XFS_IFORK_SIZE(ip,w) xfs_ifork_size(ip,w) +#else +#define XFS_IFORK_SIZE(ip,w) XFS_CFORK_SIZE(&ip->i_d, ip->i_mount, w) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_FORMAT) +int xfs_ifork_format(xfs_inode_t *ip, int w); +#define XFS_IFORK_FORMAT(ip,w) xfs_ifork_format(ip,w) +#else +#define XFS_IFORK_FORMAT(ip,w) XFS_CFORK_FORMAT(&ip->i_d, w) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_FMT_SET) +void xfs_ifork_fmt_set(xfs_inode_t *ip, int w, int n); +#define XFS_IFORK_FMT_SET(ip,w,n) xfs_ifork_fmt_set(ip,w,n) +#else +#define XFS_IFORK_FMT_SET(ip,w,n) XFS_CFORK_FMT_SET(&ip->i_d, w, n) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_NEXTENTS) +int xfs_ifork_nextents(xfs_inode_t *ip, int w); +#define XFS_IFORK_NEXTENTS(ip,w) xfs_ifork_nextents(ip,w) +#else +#define XFS_IFORK_NEXTENTS(ip,w) XFS_CFORK_NEXTENTS(&ip->i_d, w) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_IFORK_NEXT_SET) +void xfs_ifork_next_set(xfs_inode_t *ip, int w, int n); +#define XFS_IFORK_NEXT_SET(ip,w,n) xfs_ifork_next_set(ip,w,n) +#else +#define XFS_IFORK_NEXT_SET(ip,w,n) XFS_CFORK_NEXT_SET(&ip->i_d, w, n) +#endif + + +#ifdef __KERNEL__ + +/* + * In-core inode flags. + */ +#define XFS_IGRIO 0x0001 /* inode used for guaranteed rate i/o */ +#define XFS_IUIOSZ 0x0002 /* inode i/o sizes have been explicitly set */ +#define XFS_IQUIESCE 0x0004 /* we have started quiescing for this inode */ +#define XFS_IRECLAIM 0x0008 /* we have started reclaiming this inode */ + +/* + * Flags for inode locking. + */ +#define XFS_IOLOCK_EXCL 0x001 +#define XFS_IOLOCK_SHARED 0x002 +#define XFS_ILOCK_EXCL 0x004 +#define XFS_ILOCK_SHARED 0x008 +#define XFS_IUNLOCK_NONOTIFY 0x010 +#define XFS_IOLOCK_NESTED 0x020 +#define XFS_EXTENT_TOKEN_RD 0x040 +#define XFS_SIZE_TOKEN_RD 0x080 +#define XFS_EXTSIZE_RD (XFS_EXTENT_TOKEN_RD|XFS_SIZE_TOKEN_RD) +#define XFS_WILLLEND 0x100 /* Always acquire tokens for lending */ +#define XFS_EXTENT_TOKEN_WR (XFS_EXTENT_TOKEN_RD | XFS_WILLLEND) +#define XFS_SIZE_TOKEN_WR (XFS_SIZE_TOKEN_RD | XFS_WILLLEND) +#define XFS_EXTSIZE_WR (XFS_EXTSIZE_RD | XFS_WILLLEND) + + +#define XFS_LOCK_MASK \ + (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL | \ + XFS_IOLOCK_NESTED | \ + XFS_ILOCK_SHARED | XFS_EXTENT_TOKEN_RD | XFS_SIZE_TOKEN_RD | \ + XFS_WILLLEND) + +/* + * Flags for xfs_iflush() + */ +#define XFS_IFLUSH_DELWRI_ELSE_SYNC 1 +#define XFS_IFLUSH_DELWRI_ELSE_ASYNC 2 +#define XFS_IFLUSH_SYNC 3 +#define XFS_IFLUSH_ASYNC 4 +#define XFS_IFLUSH_DELWRI 5 + +/* + * Flags for xfs_iflush_all. + */ +#define XFS_FLUSH_ALL 0x1 + +/* + * Flags for xfs_itruncate_start(). + */ +#define XFS_ITRUNC_DEFINITE 0x1 +#define XFS_ITRUNC_MAYBE 0x2 + +/* + * Maximum file size. + * if XFS_BIG_FILES 2^63 - 1 (largest positive value of xfs_fsize_t) + * else 2^40 - 1 (40=31+9) (might be an int holding a block #) + * Note, we allow seeks to this offset, although you can't read or write. + * For the not XFS_BIG_FILES case, the value could be 1 higher but we don't + * do that, for symmetry. + */ +#if XFS_BIG_FILES +#define XFS_MAX_FILE_OFFSET ((long long)((1ULL<<63)-1ULL)) +#else +#define XFS_MAX_FILE_OFFSET ((1LL<<40)-1LL) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ITOV) +struct vnode *xfs_itov(xfs_inode_t *ip); +#define XFS_ITOV(ip) xfs_itov(ip) +#else +#define XFS_ITOV(ip) BHV_TO_VNODE(XFS_ITOBHV(ip)) +#endif +#define XFS_ITOV_NULL(ip) BHV_TO_VNODE_NULL(XFS_ITOBHV(ip)) +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ITOBHV) +struct bhv_desc *xfs_itobhv(xfs_inode_t *ip); +#define XFS_ITOBHV(ip) xfs_itobhv(ip) +#else +#define XFS_ITOBHV(ip) ((struct bhv_desc *)(&((ip)->i_bhv_desc))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BHVTOI) +xfs_inode_t *xfs_bhvtoi(struct bhv_desc *bhvp); +#define XFS_BHVTOI(bhvp) xfs_bhvtoi(bhvp) +#else +#define XFS_BHVTOI(bhvp) \ + ((xfs_inode_t *)((char *)(bhvp) - \ + (char *)&(((xfs_inode_t *)0)->i_bhv_desc))) +#endif + +#define BHV_IS_XFS(bdp) (BHV_OPS(bdp) == &xfs_vnodeops) + +/* + * Pick the inode cluster hash bucket + * (m_chash is the same size as m_ihash) + */ +#define XFS_CHASH(mp,blk) ((mp)->m_chash + (((uint)blk) % (mp)->m_chsize)) + +/* + * For multiple groups support: if ISGID bit is set in the parent + * directory, group of new file is set to that of the parent, and + * new subdirectory gets ISGID bit from parent. + */ +#define XFS_INHERIT_GID(pip, vfsp) ((pip) != NULL && \ + (((vfsp)->vfs_flag & VFS_GRPID) || ((pip)->i_d.di_mode & ISGID))) + +/* + * xfs_iget.c prototypes. + */ +void xfs_ihash_init(struct xfs_mount *); +void xfs_ihash_free(struct xfs_mount *); +void xfs_chash_init(struct xfs_mount *); +void xfs_chash_free(struct xfs_mount *); +xfs_inode_t *xfs_inode_incore(struct xfs_mount *, xfs_ino_t, + struct xfs_trans *); +void xfs_inode_lock_init(xfs_inode_t *, struct vnode *); +int xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, + uint, xfs_inode_t **, xfs_daddr_t); +int xfs_vn_iget(vfs_t *, struct vnode *, xfs_ino_t); +void xfs_iput(xfs_inode_t *, uint); +void xfs_ilock(xfs_inode_t *, uint); +int xfs_ilock_nowait(xfs_inode_t *, uint); +void xfs_iunlock(xfs_inode_t *, uint); +void xfs_ilock_demote(xfs_inode_t *, uint); +void xfs_iflock(xfs_inode_t *); +int xfs_iflock_nowait(xfs_inode_t *); +uint xfs_ilock_map_shared(xfs_inode_t *); +void xfs_iunlock_map_shared(xfs_inode_t *, uint); +void xfs_ifunlock(xfs_inode_t *); +void xfs_ireclaim(xfs_inode_t *); +int xfs_finish_reclaim(xfs_inode_t *, int, int); + +/* + * xfs_inode.c prototypes. + */ +int xfs_inotobp(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, + xfs_dinode_t **, struct xfs_buf **, int *); +int xfs_itobp(struct xfs_mount *, struct xfs_trans *, + xfs_inode_t *, xfs_dinode_t **, struct xfs_buf **, + xfs_daddr_t); +int xfs_iread(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, + xfs_inode_t **, xfs_daddr_t); +int xfs_iread_extents(struct xfs_trans *, xfs_inode_t *, int); +int xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t, nlink_t, + dev_t, struct cred *, xfs_prid_t, int, + struct xfs_buf **, boolean_t *, xfs_inode_t **); +void xfs_xlate_dinode_core(xfs_caddr_t, struct xfs_dinode_core *, int, + xfs_arch_t); +int xfs_ifree(struct xfs_trans *, xfs_inode_t *); +int xfs_atruncate_start(xfs_inode_t *); +void xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t); +int xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *, + xfs_fsize_t, int, int); +int xfs_iunlink(struct xfs_trans *, xfs_inode_t *); +int xfs_igrow_start(xfs_inode_t *, xfs_fsize_t, struct cred *); +void xfs_igrow_finish(struct xfs_trans *, xfs_inode_t *, + xfs_fsize_t, int); + +void xfs_idestroy_fork(xfs_inode_t *, int); +void xfs_idestroy(xfs_inode_t *); +void xfs_idata_realloc(xfs_inode_t *, int, int); +void xfs_iextract(xfs_inode_t *); +void xfs_iext_realloc(xfs_inode_t *, int, int); +void xfs_iroot_realloc(xfs_inode_t *, int, int); +void xfs_ipin(xfs_inode_t *); +void xfs_iunpin(xfs_inode_t *); +unsigned int xfs_ipincount(xfs_inode_t *); +int xfs_iextents_copy(xfs_inode_t *, xfs_bmbt_rec_32_t *, int); +int xfs_iflush(xfs_inode_t *, uint); +int xfs_iflush_all(struct xfs_mount *, int); +int xfs_ibusy_check(xfs_inode_t *, int); +int xfs_iaccess(xfs_inode_t *, mode_t, cred_t *); +uint xfs_iroundup(uint); +void xfs_ichgtime(xfs_inode_t *, int); +xfs_fsize_t xfs_file_last_byte(xfs_inode_t *); +xfs_inode_t *xfs_get_inode(dev_t, xfs_ino_t); +void xfs_lock_inodes(xfs_inode_t **, int, int, uint); + + +#ifdef DEBUG +void xfs_isize_check(struct xfs_mount *, xfs_inode_t *, xfs_fsize_t); +#else /* DEBUG */ +#define xfs_isize_check(mp, ip, isize) +#endif /* DEBUG */ + +#if defined(DEBUG) +void xfs_inobp_check(struct xfs_mount *, struct xfs_buf *); +#else +#define xfs_inobp_check(mp, bp) +#endif /* DEBUG */ + +extern struct xfs_zone *xfs_chashlist_zone; +extern struct xfs_zone *xfs_ifork_zone; +extern struct xfs_zone *xfs_inode_zone; +extern struct xfs_zone *xfs_ili_zone; +extern struct vnodeops xfs_vnodeops; + +#ifdef XFS_ILOCK_TRACE +#define XFS_ILOCK_KTRACE_SIZE 32 +void xfs_ilock_trace(xfs_inode_t *ip, int lock, unsigned int lockflags, + inst_t *ra); +#endif + +#endif /* __KERNEL__ */ + +#endif /* __XFS_INODE_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_inode_item.c linux-2.4-xfs/linux/fs/xfs/xfs_inode_item.c --- linux-2.4.7/linux/fs/xfs/xfs_inode_item.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_inode_item.c Mon Apr 9 20:57:29 2001 @@ -0,0 +1,1024 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * This file contains the implementation of the xfs_inode_log_item. + * It contains the item operations used to manipulate the inode log + * items as well as utility routines used by the inode specific + * transaction routines. + */ +#include + + +xfs_zone_t *xfs_ili_zone; /* inode log item zone */ + +/* + * This returns the number of iovecs needed to log the given inode item. + * + * We need one iovec for the inode log format structure, one for the + * inode core, and possibly one for the inode data/extents/b-tree root + * and one for the inode attribute data/extents/b-tree root. + */ +STATIC uint +xfs_inode_item_size( + xfs_inode_log_item_t *iip) +{ + uint nvecs; + xfs_inode_t *ip; + + ip = iip->ili_inode; + nvecs = 2; + + /* + * Only log the data/extents/b-tree root if there is something + * left to log. + */ + iip->ili_format.ilf_fields |= XFS_ILOG_CORE; + + switch (ip->i_d.di_format) { + case XFS_DINODE_FMT_EXTENTS: + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT | + XFS_ILOG_DEV | XFS_ILOG_UUID); + if ((iip->ili_format.ilf_fields & XFS_ILOG_DEXT) && + (ip->i_d.di_nextents > 0) && + (ip->i_df.if_bytes > 0)) { + ASSERT(ip->i_df.if_u1.if_extents != NULL); + nvecs++; + } else { + iip->ili_format.ilf_fields &= ~XFS_ILOG_DEXT; + } + break; + + case XFS_DINODE_FMT_BTREE: + ASSERT(ip->i_df.if_ext_max == + XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t)); + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_DDATA | XFS_ILOG_DEXT | + XFS_ILOG_DEV | XFS_ILOG_UUID); + if ((iip->ili_format.ilf_fields & XFS_ILOG_DBROOT) && + (ip->i_df.if_broot_bytes > 0)) { + ASSERT(ip->i_df.if_broot != NULL); + nvecs++; + } else { + ASSERT(!(iip->ili_format.ilf_fields & + XFS_ILOG_DBROOT)); +#ifdef XFS_TRANS_DEBUG + if (iip->ili_root_size > 0) { + ASSERT(iip->ili_root_size == + ip->i_df.if_broot_bytes); + ASSERT(bcmp(iip->ili_orig_root, + ip->i_df.if_broot, + iip->ili_root_size) == 0); + } else { + ASSERT(ip->i_df.if_broot_bytes == 0); + } +#endif + iip->ili_format.ilf_fields &= ~XFS_ILOG_DBROOT; + } + break; + + case XFS_DINODE_FMT_LOCAL: + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_DEXT | XFS_ILOG_DBROOT | + XFS_ILOG_DEV | XFS_ILOG_UUID); + if ((iip->ili_format.ilf_fields & XFS_ILOG_DDATA) && + (ip->i_df.if_bytes > 0)) { + ASSERT(ip->i_df.if_u1.if_data != NULL); + ASSERT(ip->i_d.di_size > 0); + nvecs++; + } else { + iip->ili_format.ilf_fields &= ~XFS_ILOG_DDATA; + } + break; + + case XFS_DINODE_FMT_DEV: + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT | + XFS_ILOG_DEXT | XFS_ILOG_UUID); + break; + + case XFS_DINODE_FMT_UUID: + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT | + XFS_ILOG_DEXT | XFS_ILOG_DEV); + break; + + default: + ASSERT(0); + break; + } + + /* + * If there are no attributes associated with this file, + * then there cannot be anything more to log. + * Clear all attribute-related log flags. + */ + if (!XFS_IFORK_Q(ip)) { + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT); + return nvecs; + } + + /* + * Log any necessary attribute data. + */ + switch (ip->i_d.di_aformat) { + case XFS_DINODE_FMT_EXTENTS: + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT); + if ((iip->ili_format.ilf_fields & XFS_ILOG_AEXT) && + (ip->i_d.di_anextents > 0) && + (ip->i_afp->if_bytes > 0)) { + ASSERT(ip->i_afp->if_u1.if_extents != NULL); + nvecs++; + } else { + iip->ili_format.ilf_fields &= ~XFS_ILOG_AEXT; + } + break; + + case XFS_DINODE_FMT_BTREE: + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_ADATA | XFS_ILOG_AEXT); + if ((iip->ili_format.ilf_fields & XFS_ILOG_ABROOT) && + (ip->i_afp->if_broot_bytes > 0)) { + ASSERT(ip->i_afp->if_broot != NULL); + nvecs++; + } else { + iip->ili_format.ilf_fields &= ~XFS_ILOG_ABROOT; + } + break; + + case XFS_DINODE_FMT_LOCAL: + iip->ili_format.ilf_fields &= + ~(XFS_ILOG_AEXT | XFS_ILOG_ABROOT); + if ((iip->ili_format.ilf_fields & XFS_ILOG_ADATA) && + (ip->i_afp->if_bytes > 0)) { + ASSERT(ip->i_afp->if_u1.if_data != NULL); + nvecs++; + } else { + iip->ili_format.ilf_fields &= ~XFS_ILOG_ADATA; + } + break; + + default: + ASSERT(0); + break; + } + + return nvecs; +} + +/* + * This is called to fill in the vector of log iovecs for the + * given inode log item. It fills the first item with an inode + * log format structure, the second with the on-disk inode structure, + * and a possible third and/or fourth with the inode data/extents/b-tree + * root and inode attributes data/extents/b-tree root. + */ +STATIC void +xfs_inode_item_format( + xfs_inode_log_item_t *iip, + xfs_log_iovec_t *log_vector) +{ + uint nvecs; + xfs_log_iovec_t *vecp; + xfs_inode_t *ip; + size_t data_bytes; + xfs_bmbt_rec_32_t *ext_buffer; + int nrecs; + xfs_mount_t *mp; + + ip = iip->ili_inode; + vecp = log_vector; + + vecp->i_addr = (xfs_caddr_t)&iip->ili_format; + vecp->i_len = sizeof(xfs_inode_log_format_t); + vecp++; + nvecs = 1; + + /* + * Clear i_update_core if the timestamps (or any other + * non-transactional modification) need flushing/logging + * and we're about to log them with the rest of the core. + * + * This is the same logic as xfs_iflush() but this code can't + * run at the same time as xfs_iflush because we're in commit + * processing here and so we have the inode lock held in + * exclusive mode. Although it doesn't really matter + * for the timestamps if both routines were to grab the + * timestamps or not. That would be ok. + * + * We clear i_update_core before copying out the data. + * This is for coordination with our timestamp updates + * that don't hold the inode lock. They will always + * update the timestamps BEFORE setting i_update_core, + * so if we clear i_update_core after they set it we + * are guaranteed to see their updates to the timestamps + * either here. Likewise, if they set it after we clear it + * here, we'll see it either on the next commit of this + * inode or the next time the inode gets flushed via + * xfs_iflush(). This depends on strongly ordered memory + * semantics, but we have that. We use the SYNCHRONIZE + * macro to make sure that the compiler does not reorder + * the i_update_core access below the data copy below. + */ + if (ip->i_update_core) { + ip->i_update_core = 0; + SYNCHRONIZE(); + } + + /* + * We don't have to worry about re-ordering here because + * the update_size field is protected by the inode lock + * and we have that held in exclusive mode. + */ + if (ip->i_update_size) + ip->i_update_size = 0; + + vecp->i_addr = (xfs_caddr_t)&ip->i_d; + vecp->i_len = sizeof(xfs_dinode_core_t); + vecp++; + nvecs++; + iip->ili_format.ilf_fields |= XFS_ILOG_CORE; + + /* + * If this is really an old format inode, then we need to + * log it as such. This means that we have to copy the link + * count from the new field to the old. We don't have to worry + * about the new fields, because nothing trusts them as long as + * the old inode version number is there. If the superblock already + * has a new version number, then we don't bother converting back. + */ + mp = ip->i_mount; + ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1 || + XFS_SB_VERSION_HASNLINK(&mp->m_sb)); + if (ip->i_d.di_version == XFS_DINODE_VERSION_1) { + if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) { + /* + * Convert it back. + */ + ASSERT(ip->i_d.di_nlink <= XFS_MAXLINK_1); + ip->i_d.di_onlink = ip->i_d.di_nlink; + } else { + /* + * The superblock version has already been bumped, + * so just make the conversion to the new inode + * format permanent. + */ + ip->i_d.di_version = XFS_DINODE_VERSION_2; + ip->i_d.di_onlink = 0; + bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad)); + } + } + + switch (ip->i_d.di_format) { + case XFS_DINODE_FMT_EXTENTS: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_DDATA | XFS_ILOG_DBROOT | + XFS_ILOG_DEV | XFS_ILOG_UUID))); + if (iip->ili_format.ilf_fields & XFS_ILOG_DEXT) { + ASSERT(ip->i_df.if_bytes > 0); + ASSERT(ip->i_df.if_u1.if_extents != NULL); + ASSERT(ip->i_d.di_nextents > 0); + ASSERT(iip->ili_extents_buf == NULL); + nrecs = ip->i_df.if_bytes / + (uint)sizeof(xfs_bmbt_rec_t); + ASSERT(nrecs > 0); + if (nrecs == ip->i_d.di_nextents) { + /* + * There are no delayed allocation + * extents, so just point to the + * real extents array. + */ + vecp->i_addr = + (char *)(ip->i_df.if_u1.if_extents); + vecp->i_len = ip->i_df.if_bytes; + } else { + /* + * There are delayed allocation extents + * in the inode. Use xfs_iextents_copy() + * to copy only the real extents into + * a separate buffer. We'll free the + * buffer in the unlock routine. + */ + ext_buffer = kmem_alloc(ip->i_df.if_bytes, + KM_SLEEP); + iip->ili_extents_buf = ext_buffer; + vecp->i_addr = (xfs_caddr_t)ext_buffer; + vecp->i_len = xfs_iextents_copy(ip, ext_buffer, + XFS_DATA_FORK); + } + ASSERT(vecp->i_len <= ip->i_df.if_bytes); + iip->ili_format.ilf_dsize = vecp->i_len; + vecp++; + nvecs++; + } + break; + + case XFS_DINODE_FMT_BTREE: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_DDATA | XFS_ILOG_DEXT | + XFS_ILOG_DEV | XFS_ILOG_UUID))); + if (iip->ili_format.ilf_fields & XFS_ILOG_DBROOT) { + ASSERT(ip->i_df.if_broot_bytes > 0); + ASSERT(ip->i_df.if_broot != NULL); + vecp->i_addr = (xfs_caddr_t)ip->i_df.if_broot; + vecp->i_len = ip->i_df.if_broot_bytes; + vecp++; + nvecs++; + iip->ili_format.ilf_dsize = ip->i_df.if_broot_bytes; + } + break; + + case XFS_DINODE_FMT_LOCAL: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_DBROOT | XFS_ILOG_DEXT | + XFS_ILOG_DEV | XFS_ILOG_UUID))); + if (iip->ili_format.ilf_fields & XFS_ILOG_DDATA) { + ASSERT(ip->i_df.if_bytes > 0); + ASSERT(ip->i_df.if_u1.if_data != NULL); + ASSERT(ip->i_d.di_size > 0); + + vecp->i_addr = (xfs_caddr_t)ip->i_df.if_u1.if_data; + /* + * Round i_bytes up to a word boundary. + * The underlying memory is guaranteed to + * to be there by xfs_idata_realloc(). + */ + data_bytes = roundup(ip->i_df.if_bytes, 4); + ASSERT((ip->i_df.if_real_bytes == 0) || + (ip->i_df.if_real_bytes == data_bytes)); + vecp->i_len = (int)data_bytes; + vecp++; + nvecs++; + iip->ili_format.ilf_dsize = (unsigned)data_bytes; + } + break; + + case XFS_DINODE_FMT_DEV: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_DBROOT | XFS_ILOG_DEXT | + XFS_ILOG_DDATA | XFS_ILOG_UUID))); + if (iip->ili_format.ilf_fields & XFS_ILOG_DEV) { + iip->ili_format.ilf_u.ilfu_rdev = + ip->i_df.if_u2.if_rdev; + } + break; + + case XFS_DINODE_FMT_UUID: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_DBROOT | XFS_ILOG_DEXT | + XFS_ILOG_DDATA | XFS_ILOG_DEV))); + if (iip->ili_format.ilf_fields & XFS_ILOG_UUID) { + iip->ili_format.ilf_u.ilfu_uuid = + ip->i_df.if_u2.if_uuid; + } + break; + + default: + ASSERT(0); + break; + } + + /* + * If there are no attributes associated with the file, + * then we're done. + * Assert that no attribute-related log flags are set. + */ + if (!XFS_IFORK_Q(ip)) { + ASSERT(nvecs == iip->ili_item.li_desc->lid_size); + iip->ili_format.ilf_size = nvecs; + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT))); + return; + } + + switch (ip->i_d.di_aformat) { + case XFS_DINODE_FMT_EXTENTS: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_ADATA | XFS_ILOG_ABROOT))); + if (iip->ili_format.ilf_fields & XFS_ILOG_AEXT) { + ASSERT(ip->i_afp->if_bytes > 0); + ASSERT(ip->i_afp->if_u1.if_extents != NULL); + ASSERT(ip->i_d.di_anextents > 0); +#ifdef DEBUG + nrecs = ip->i_afp->if_bytes / + (uint)sizeof(xfs_bmbt_rec_t); +#endif + ASSERT(nrecs > 0); + ASSERT(nrecs == ip->i_d.di_anextents); + /* + * There are not delayed allocation extents + * for attributes, so just point at the array. + */ + vecp->i_addr = (char *)(ip->i_afp->if_u1.if_extents); + vecp->i_len = ip->i_afp->if_bytes; + iip->ili_format.ilf_asize = vecp->i_len; + vecp++; + nvecs++; + } + break; + + case XFS_DINODE_FMT_BTREE: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_ADATA | XFS_ILOG_AEXT))); + if (iip->ili_format.ilf_fields & XFS_ILOG_ABROOT) { + ASSERT(ip->i_afp->if_broot_bytes > 0); + ASSERT(ip->i_afp->if_broot != NULL); + vecp->i_addr = (xfs_caddr_t)ip->i_afp->if_broot; + vecp->i_len = ip->i_afp->if_broot_bytes; + vecp++; + nvecs++; + iip->ili_format.ilf_asize = ip->i_afp->if_broot_bytes; + } + break; + + case XFS_DINODE_FMT_LOCAL: + ASSERT(!(iip->ili_format.ilf_fields & + (XFS_ILOG_ABROOT | XFS_ILOG_AEXT))); + if (iip->ili_format.ilf_fields & XFS_ILOG_ADATA) { + ASSERT(ip->i_afp->if_bytes > 0); + ASSERT(ip->i_afp->if_u1.if_data != NULL); + + vecp->i_addr = (xfs_caddr_t)ip->i_afp->if_u1.if_data; + /* + * Round i_bytes up to a word boundary. + * The underlying memory is guaranteed to + * to be there by xfs_idata_realloc(). + */ + data_bytes = roundup(ip->i_afp->if_bytes, 4); + ASSERT((ip->i_afp->if_real_bytes == 0) || + (ip->i_afp->if_real_bytes == data_bytes)); + vecp->i_len = (int)data_bytes; + vecp++; + nvecs++; + iip->ili_format.ilf_asize = (unsigned)data_bytes; + } + break; + + default: + ASSERT(0); + break; + } + + ASSERT(nvecs == iip->ili_item.li_desc->lid_size); + iip->ili_format.ilf_size = nvecs; +} + + +/* + * This is called to pin the inode associated with the inode log + * item in memory so it cannot be written out. Do this by calling + * xfs_ipin() to bump the pin count in the inode while holding the + * inode pin lock. + */ +STATIC void +xfs_inode_item_pin( + xfs_inode_log_item_t *iip) +{ + ASSERT(ismrlocked(&(iip->ili_inode->i_lock), MR_UPDATE)); + xfs_ipin(iip->ili_inode); +} + + +/* + * This is called to unpin the inode associated with the inode log + * item which was previously pinned with a call to xfs_inode_item_pin(). + * Just call xfs_iunpin() on the inode to do this. + */ +STATIC void +xfs_inode_item_unpin( + xfs_inode_log_item_t *iip) +{ + xfs_iunpin(iip->ili_inode); +} + +/* ARGSUSED */ +STATIC void +xfs_inode_item_unpin_remove( + xfs_inode_log_item_t *iip, + xfs_trans_t *tp) +{ + xfs_iunpin(iip->ili_inode); +} + +/* + * This is called to attempt to lock the inode associated with this + * inode log item, in preparation for the push routine which does the actual + * iflush. Don't sleep on the inode lock or the flush lock. + * + * If the flush lock is already held, indicating that the inode has + * been or is in the process of being flushed, then (ideally) we'd like to + * see if the inode's buffer is still incore, and if so give it a nudge. + * We delay doing so until the pushbuf routine, though, to avoid holding + * the AIL lock across a call to the blackhole which is the buffercache. + * Also we don't want to sleep in any device strategy routines, which can happen + * if we do the subsequent bawrite in here. + */ +STATIC uint +xfs_inode_item_trylock( + xfs_inode_log_item_t *iip) +{ + register xfs_inode_t *ip; + + ip = iip->ili_inode; + + if (ip->i_pincount > 0) { + return XFS_ITEM_PINNED; + } + + if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) { + return XFS_ITEM_LOCKED; + } + + if (!xfs_iflock_nowait(ip)) { + /* + * If someone else isn't already trying to push the inode + * buffer, we get to do it. + */ + if (iip->ili_pushbuf_flag == 0) { + iip->ili_pushbuf_flag = 1; +#ifdef DEBUG + iip->ili_push_owner = get_thread_id(); +#endif + /* + * Inode is left locked in shared mode. + * Pushbuf routine gets to unlock it. + */ + return XFS_ITEM_PUSHBUF; + } else { + /* + * We hold the AIL_LOCK, so we must specify the + * NONOTIFY flag so that we won't double trip. + */ + xfs_iunlock(ip, XFS_ILOCK_SHARED|XFS_IUNLOCK_NONOTIFY); + return XFS_ITEM_FLUSHING; + } + /* NOTREACHED */ + } +#ifdef DEBUG + if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { + ASSERT(iip->ili_format.ilf_fields != 0); + ASSERT(iip->ili_logged == 0); + ASSERT(iip->ili_item.li_flags & XFS_LI_IN_AIL); + } +#endif + return XFS_ITEM_SUCCESS; +} + +/* + * Unlock the inode associated with the inode log item. + * Clear the fields of the inode and inode log item that + * are specific to the current transaction. If the + * hold flags is set, do not unlock the inode. + */ +STATIC void +xfs_inode_item_unlock( + xfs_inode_log_item_t *iip) +{ + uint hold; + uint iolocked; + uint lock_flags; + xfs_inode_t *ip; + + ASSERT(iip != NULL); + ASSERT(iip->ili_inode->i_itemp != NULL); + ASSERT(ismrlocked(&(iip->ili_inode->i_lock), MR_UPDATE)); + ASSERT((!(iip->ili_inode->i_itemp->ili_flags & + XFS_ILI_IOLOCKED_EXCL)) || + ismrlocked(&(iip->ili_inode->i_iolock), MR_UPDATE)); + ASSERT((!(iip->ili_inode->i_itemp->ili_flags & + XFS_ILI_IOLOCKED_SHARED)) || + ismrlocked(&(iip->ili_inode->i_iolock), MR_ACCESS)); + /* + * Clear the transaction pointer in the inode. + */ + ip = iip->ili_inode; + ip->i_transp = NULL; + + /* + * If the inode needed a separate buffer with which to log + * its extents, then free it now. + */ + /* FIXME */ + if (iip->ili_extents_buf != NULL) { + ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS); + ASSERT(ip->i_d.di_nextents > 0); + ASSERT(iip->ili_format.ilf_fields & XFS_ILOG_DEXT); + ASSERT(ip->i_df.if_bytes > 0); + kmem_free(iip->ili_extents_buf, ip->i_df.if_bytes); + iip->ili_extents_buf = NULL; + } + + /* + * Figure out if we should unlock the inode or not. + */ + hold = iip->ili_flags & XFS_ILI_HOLD; + + /* + * Before clearing out the flags, remember whether we + * are holding the inode's IO lock. + */ + iolocked = iip->ili_flags & XFS_ILI_IOLOCKED_ANY; + + /* + * Clear out the fields of the inode log item particular + * to the current transaction. + */ + iip->ili_ilock_recur = 0; + iip->ili_iolock_recur = 0; + iip->ili_flags = 0; + + /* + * Unlock the inode if XFS_ILI_HOLD was not set. + */ + if (!hold) { + lock_flags = XFS_ILOCK_EXCL; + if (iolocked & XFS_ILI_IOLOCKED_EXCL) { + lock_flags |= XFS_IOLOCK_EXCL; + } else if (iolocked & XFS_ILI_IOLOCKED_SHARED) { + lock_flags |= XFS_IOLOCK_SHARED; + } + xfs_iput(iip->ili_inode, lock_flags); + } +} + +/* + * This is called to find out where the oldest active copy of the + * inode log item in the on disk log resides now that the last log + * write of it completed at the given lsn. Since we always re-log + * all dirty data in an inode, the latest copy in the on disk log + * is the only one that matters. Therefore, simply return the + * given lsn. + */ +/*ARGSUSED*/ +STATIC xfs_lsn_t +xfs_inode_item_committed( + xfs_inode_log_item_t *iip, + xfs_lsn_t lsn) +{ + return (lsn); +} + +/* + * The transaction with the inode locked has aborted. The inode + * must not be dirty within the transaction (unless we're forcibly + * shutting down). We simply unlock just as if the transaction + * had been cancelled. + */ +STATIC void +xfs_inode_item_abort( + xfs_inode_log_item_t *iip) +{ + xfs_inode_item_unlock(iip); + return; +} + + +/* + * This gets called by xfs_trans_push_ail(), when IOP_TRYLOCK + * failed to get the inode flush lock but did get the inode locked SHARED. + * Here we're trying to see if the inode buffer is incore, and if so whether it's + * marked delayed write. If that's the case, we'll initiate a bawrite on that + * buffer to expedite the process. + * + * We aren't holding the AIL_LOCK (or the flush lock) when this gets called, + * so it is inherently race-y. + */ +STATIC void +xfs_inode_item_pushbuf( + xfs_inode_log_item_t *iip) +{ + xfs_inode_t *ip; + xfs_mount_t *mp; + xfs_buf_t *bp; + uint dopush; + + ip = iip->ili_inode; + + ASSERT(ismrlocked(&(ip->i_lock), MR_ACCESS)); + + /* + * The ili_pushbuf_flag keeps others from + * trying to duplicate our effort. + */ + ASSERT(iip->ili_pushbuf_flag != 0); + ASSERT(iip->ili_push_owner == get_thread_id()); + + /* + * If flushlock isn't locked anymore, chances are that the + * inode flush completed and the inode was taken off the AIL. + * So, just get out. + */ + if ((valusema(&(ip->i_flock)) > 0) || + ((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0)) { + iip->ili_pushbuf_flag = 0; + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return; + } + + mp = ip->i_mount; + bp = xfs_incore(mp->m_ddev_targ, iip->ili_format.ilf_blkno, + iip->ili_format.ilf_len, XFS_INCORE_TRYLOCK); + + if (bp != NULL) { + if (XFS_BUF_ISDELAYWRITE(bp)) { + /* + * We were racing with iflush because we don't hold + * the AIL_LOCK or the flush lock. However, at this point, + * we have the buffer, and we know that it's dirty. + * So, it's possible that iflush raced with us, and + * this item is already taken off the AIL. + * If not, we can flush it async. + */ + dopush = ((iip->ili_item.li_flags & XFS_LI_IN_AIL) && + (valusema(&(ip->i_flock)) <= 0)); + iip->ili_pushbuf_flag = 0; + xfs_iunlock(ip, XFS_ILOCK_SHARED); + xfs_buftrace("INODE ITEM PUSH", bp); + if (XFS_BUF_ISPINNED(bp)) { + xfs_log_force(mp, (xfs_lsn_t)0, + XFS_LOG_FORCE); + } + if (dopush) { + xfs_bawrite(mp, bp); + } else { + xfs_buf_relse(bp); + } + } else { + iip->ili_pushbuf_flag = 0; + xfs_iunlock(ip, XFS_ILOCK_SHARED); + xfs_buf_relse(bp); + } + return; + } + /* + * We have to be careful about resetting pushbuf flag too early (above). + * Eventhough in theory we can do it as soon as we have the buflock, + * we don't want others to be doing work needlessly. They'll come to + * this function thinking that pushing the buffer is there responsibility + * only to find that the buffer is still locked by another doing the + * same thing.XXX + */ + iip->ili_pushbuf_flag = 0; + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return; +} + + +/* + * This is called to asynchronously write the inode associated with this + * inode log item out to disk. The inode will already have been locked by + * a successful call to xfs_inode_item_trylock(). + */ +STATIC void +xfs_inode_item_push( + xfs_inode_log_item_t *iip) +{ + xfs_inode_t *ip; + + ip = iip->ili_inode; + + ASSERT(ismrlocked(&(ip->i_lock), MR_ACCESS)); + ASSERT(valusema(&(ip->i_flock)) <= 0); + /* + * Since we were able to lock the inode's flush lock and + * we found it on the AIL, the inode must be dirty. This + * is because the inode is removed from the AIL while still + * holding the flush lock in xfs_iflush_done(). Thus, if + * we found it in the AIL and were able to obtain the flush + * lock without sleeping, then there must not have been + * anyone in the process of flushing the inode. + */ + ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || + iip->ili_format.ilf_fields != 0); + + /* + * Write out the inode. The completion routine ('iflush_done') will + * pull it from the AIL, mark it clean, unlock the flush lock. + */ + (void) xfs_iflush(ip, XFS_IFLUSH_DELWRI); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + return; +} + +/* + * XXX rcc - this one really has to do something. Probably needs + * to stamp in a new field in the incore inode. + */ +/* ARGSUSED */ +STATIC void +xfs_inode_item_committing( + xfs_inode_log_item_t *iip, + xfs_lsn_t lsn) +{ + iip->ili_last_lsn = lsn; + return; +} + +/* + * This is the ops vector shared by all buf log items. + */ +struct xfs_item_ops xfs_inode_item_ops = { + iop_size: (uint(*)(xfs_log_item_t*))xfs_inode_item_size, + iop_format: (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) + xfs_inode_item_format, + iop_pin: (void(*)(xfs_log_item_t*))xfs_inode_item_pin, + iop_unpin: (void(*)(xfs_log_item_t*))xfs_inode_item_unpin, + iop_unpin_remove: (void(*)(xfs_log_item_t*, xfs_trans_t*)) + xfs_inode_item_unpin_remove, + iop_trylock: (uint(*)(xfs_log_item_t*))xfs_inode_item_trylock, + iop_unlock: (void(*)(xfs_log_item_t*))xfs_inode_item_unlock, + iop_committed: (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_inode_item_committed, + iop_push: (void(*)(xfs_log_item_t*))xfs_inode_item_push, + iop_abort: (void(*)(xfs_log_item_t*))xfs_inode_item_abort, + iop_pushbuf: (void(*)(xfs_log_item_t*))xfs_inode_item_pushbuf, + iop_committing: (void(*)(xfs_log_item_t*, xfs_lsn_t)) + xfs_inode_item_committing +}; + + +/* + * Initialize the inode log item for a newly allocated (in-core) inode. + */ +void +xfs_inode_item_init( + xfs_inode_t *ip, + xfs_mount_t *mp) +{ + xfs_inode_log_item_t *iip; + + ASSERT(ip->i_itemp == NULL); + iip = ip->i_itemp = kmem_zone_zalloc(xfs_ili_zone, KM_SLEEP); + + iip->ili_item.li_type = XFS_LI_INODE; + iip->ili_item.li_ops = &xfs_inode_item_ops; + iip->ili_item.li_mountp = mp; + iip->ili_inode = ip; + + /* + We have bzeroed memory. No need ... + iip->ili_extents_buf = NULL; + iip->ili_pushbuf_flag = 0; + */ + + iip->ili_format.ilf_type = XFS_LI_INODE; + iip->ili_format.ilf_ino = ip->i_ino; + iip->ili_format.ilf_blkno = ip->i_blkno; + iip->ili_format.ilf_len = ip->i_len; + iip->ili_format.ilf_boffset = ip->i_boffset; +} + +/* + * Free the inode log item and any memory hanging off of it. + */ +void +xfs_inode_item_destroy( + xfs_inode_t *ip) +{ +#ifdef XFS_TRANS_DEBUG + if (ip->i_itemp->ili_root_size != 0) { + kmem_free(ip->i_itemp->ili_orig_root, + ip->i_itemp->ili_root_size); + } +#endif + kmem_zone_free(xfs_ili_zone, ip->i_itemp); +} + + +/* + * This is the inode flushing I/O completion routine. It is called + * from interrupt level when the buffer containing the inode is + * flushed to disk. It is responsible for removing the inode item + * from the AIL if it has not been re-logged, and unlocking the inode's + * flush lock. + */ +/*ARGSUSED*/ +void +xfs_iflush_done( + xfs_buf_t *bp, + xfs_inode_log_item_t *iip) +{ + xfs_inode_t *ip; + SPLDECL(s); + + ip = iip->ili_inode; + + /* + * We only want to pull the item from the AIL if it is + * actually there and its location in the log has not + * changed since we started the flush. Thus, we only bother + * if the ili_logged flag is set and the inode's lsn has not + * changed. First we check the lsn outside + * the lock since it's cheaper, and then we recheck while + * holding the lock before removing the inode from the AIL. + */ + if (iip->ili_logged && + (iip->ili_item.li_lsn == iip->ili_flush_lsn)) { + AIL_LOCK(ip->i_mount, s); + if (iip->ili_item.li_lsn == iip->ili_flush_lsn) { + /* + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(ip->i_mount, + (xfs_log_item_t*)iip, s); + } else { + AIL_UNLOCK(ip->i_mount, s); + } + } + + iip->ili_logged = 0; + + /* + * Clear the ili_last_fields bits now that we know that the + * data corresponding to them is safely on disk. + */ + iip->ili_last_fields = 0; + + /* + * Release the inode's flush lock since we're done with it. + */ + xfs_ifunlock(ip); + + return; +} + +/* + * This is the inode flushing abort routine. It is called + * from xfs_iflush when the filesystem is shutting down to clean + * up the inode state. + * It is responsible for removing the inode item + * from the AIL if it has not been re-logged, and unlocking the inode's + * flush lock. + */ +void +xfs_iflush_abort( + xfs_inode_t *ip) +{ + xfs_inode_log_item_t *iip; + xfs_mount_t *mp; + SPLDECL(s); + + iip = ip->i_itemp; + mp = ip->i_mount; + if (iip) { + if (iip->ili_item.li_flags & XFS_LI_IN_AIL) { + AIL_LOCK(mp, s); + if (iip->ili_item.li_flags & XFS_LI_IN_AIL) { + /* + * xfs_trans_delete_ail() drops the AIL lock. + */ + xfs_trans_delete_ail(mp, (xfs_log_item_t *)iip, + s); + } else + AIL_UNLOCK(mp, s); + } + iip->ili_logged = 0; + /* + * Clear the ili_last_fields bits now that we know that the + * data corresponding to them is safely on disk. + */ + iip->ili_last_fields = 0; + /* + * Clear the inode logging fields so no more flushes are + * attempted. + */ + iip->ili_format.ilf_fields = 0; + } + /* + * Release the inode's flush lock since we're done with it. + */ + xfs_ifunlock(ip); +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_inode_item.h linux-2.4-xfs/linux/fs/xfs/xfs_inode_item.h --- linux-2.4.7/linux/fs/xfs/xfs_inode_item.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_inode_item.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_INODE_ITEM_H__ +#define __XFS_INODE_ITEM_H__ + +/* + * This is the structure used to lay out an inode log item in the + * log. The size of the inline data/extents/b-tree root to be logged + * (if any) is indicated in the ilf_dsize field. Changes to this structure + * must be added on to the end. + * + * Convention for naming inode log item versions : The current version + * is always named XFS_LI_INODE. When an inode log item gets superseded, + * add the latest version of IRIX that will generate logs with that item + * to the version name. + * + * -Version 1 of this structure (XFS_LI_5_3_INODE) included up to the first + * union (ilf_u) field. This was released with IRIX 5.3-XFS. + * -Version 2 of this structure (XFS_LI_6_1_INODE) is currently the entire + * structure. This was released with IRIX 6.0.1-XFS and IRIX 6.1. + * -Version 3 of this structure (XFS_LI_INODE) is the same as version 2 + * so a new structure definition wasn't necessary. However, we had + * to add a new type because the inode cluster size changed from 4K + * to 8K and the version number had to be rev'ved to keep older kernels + * from trying to recover logs with the 8K buffers in them. The logging + * code can handle recovery on different-sized clusters now so hopefully + * this'll be the last time we need to change the inode log item just + * for a change in the inode cluster size. This new version was + * released with IRIX 6.2. + */ +typedef struct xfs_inode_log_format { + unsigned short ilf_type; /* inode log item type */ + unsigned short ilf_size; /* size of this item */ + uint ilf_fields; /* flags for fields logged */ + ushort ilf_asize; /* size of attr d/ext/root */ + ushort ilf_dsize; /* size of data/ext/root */ + xfs_ino_t ilf_ino; /* inode number */ + union { + xfs_dev_t ilfu_rdev; /* rdev value for dev inode*/ + uuid_t ilfu_uuid; /* mount point value */ + } ilf_u; + __int64_t ilf_blkno; /* blkno of inode buffer */ + int ilf_len; /* len of inode buffer */ + int ilf_boffset; /* off of inode in buffer */ +} xfs_inode_log_format_t; + +/* Initial version shipped with IRIX 5.3-XFS */ +typedef struct xfs_inode_log_format_v1 { + unsigned short ilf_type; /* inode log item type */ + unsigned short ilf_size; /* size of this item */ + uint ilf_fields; /* flags for fields logged */ + uint ilf_dsize; /* size of data/ext/root */ + xfs_ino_t ilf_ino; /* inode number */ + union { + xfs_dev_t ilfu_rdev; /* rdev value for dev inode*/ + uuid_t ilfu_uuid; /* mount point value */ + } ilf_u; +} xfs_inode_log_format_t_v1; + +/* + * Flags for xfs_trans_log_inode flags field. + */ +#define XFS_ILOG_CORE 0x001 /* log standard inode fields */ +#define XFS_ILOG_DDATA 0x002 /* log i_df.if_data */ +#define XFS_ILOG_DEXT 0x004 /* log i_df.if_extents */ +#define XFS_ILOG_DBROOT 0x008 /* log i_df.i_broot */ +#define XFS_ILOG_DEV 0x010 /* log the dev field */ +#define XFS_ILOG_UUID 0x020 /* log the uuid field */ +#define XFS_ILOG_ADATA 0x040 /* log i_af.if_data */ +#define XFS_ILOG_AEXT 0x080 /* log i_af.if_extents */ +#define XFS_ILOG_ABROOT 0x100 /* log i_af.i_broot */ + +#define XFS_ILOG_NONCORE (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ + XFS_ILOG_DBROOT | XFS_ILOG_DEV | \ + XFS_ILOG_UUID | XFS_ILOG_ADATA | \ + XFS_ILOG_AEXT | XFS_ILOG_ABROOT) + +#define XFS_ILOG_DFORK (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ + XFS_ILOG_DBROOT) + +#define XFS_ILOG_AFORK (XFS_ILOG_ADATA | XFS_ILOG_AEXT | \ + XFS_ILOG_ABROOT) + +#define XFS_ILOG_ALL (XFS_ILOG_CORE | XFS_ILOG_DDATA | \ + XFS_ILOG_DEXT | XFS_ILOG_DBROOT | \ + XFS_ILOG_DEV | XFS_ILOG_UUID | \ + XFS_ILOG_ADATA | XFS_ILOG_AEXT | \ + XFS_ILOG_ABROOT) + +#define XFS_ILI_HOLD 0x1 +#define XFS_ILI_IOLOCKED_EXCL 0x2 +#define XFS_ILI_IOLOCKED_SHARED 0x4 + +#define XFS_ILI_IOLOCKED_ANY (XFS_ILI_IOLOCKED_EXCL | XFS_ILI_IOLOCKED_SHARED) + + +#ifdef __KERNEL__ + +struct xfs_buf; +struct xfs_bmbt_rec_32; +struct xfs_inode; +struct xfs_mount; + + +typedef struct xfs_inode_log_item { + xfs_log_item_t ili_item; /* common portion */ + struct xfs_inode *ili_inode; /* inode ptr */ + xfs_lsn_t ili_flush_lsn; /* lsn at last flush */ + xfs_lsn_t ili_last_lsn; /* lsn at last transaction */ + unsigned short ili_ilock_recur; /* lock recursion count */ + unsigned short ili_iolock_recur; /* lock recursion count */ + unsigned short ili_flags; /* misc flags */ + unsigned short ili_logged; /* flushed logged data */ + unsigned int ili_last_fields; /* fields when flushed */ + struct xfs_bmbt_rec_32 *ili_extents_buf; /* array of logged exts */ + unsigned int ili_pushbuf_flag; /* one bit used in push_ail */ + +#ifdef DEBUG + uint64_t ili_push_owner; /* one who sets pushbuf_flag + above gets to push the buf */ +#endif +#ifdef XFS_TRANS_DEBUG + int ili_root_size; + char *ili_orig_root; +#endif + xfs_inode_log_format_t ili_format; /* logged structure */ +} xfs_inode_log_item_t; + + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ILOG_FDATA) +int xfs_ilog_fdata(int w); +#define XFS_ILOG_FDATA(w) xfs_ilog_fdata(w) +#else +#define XFS_ILOG_FDATA(w) \ + ((w) == XFS_DATA_FORK ? XFS_ILOG_DDATA : XFS_ILOG_ADATA) +#endif + +#endif /* __KERNEL__ */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ILOG_FBROOT) +int xfs_ilog_fbroot(int w); +#define XFS_ILOG_FBROOT(w) xfs_ilog_fbroot(w) +#else +#define XFS_ILOG_FBROOT(w) \ + ((w) == XFS_DATA_FORK ? XFS_ILOG_DBROOT : XFS_ILOG_ABROOT) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_ILOG_FEXT) +int xfs_ilog_fext(int w); +#define XFS_ILOG_FEXT(w) xfs_ilog_fext(w) +#else +#define XFS_ILOG_FEXT(w) \ + ((w) == XFS_DATA_FORK ? XFS_ILOG_DEXT : XFS_ILOG_AEXT) +#endif + +#ifdef __KERNEL__ + +void xfs_inode_item_init(struct xfs_inode *, struct xfs_mount *); +void xfs_inode_item_destroy(struct xfs_inode *); +void xfs_iflush_done(struct xfs_buf *, xfs_inode_log_item_t *); +void xfs_iflush_abort(struct xfs_inode *); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_INODE_ITEM_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_inum.h linux-2.4-xfs/linux/fs/xfs/xfs_inum.h --- linux-2.4.7/linux/fs/xfs/xfs_inum.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_inum.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_INUM_H__ +#define __XFS_INUM_H__ + +/* + * Inode number format: + * low inopblog bits - offset in block + * next agblklog bits - block number in ag + * next agno_log bits - ag number + * high agno_log-agblklog-inopblog bits - 0 + */ + +typedef __uint32_t xfs_agino_t; /* within allocation grp inode number */ + +/* + * Useful inode bits for this kernel. + * Used in some places where having 64-bits in the 32-bit kernels + * costs too much. + */ +#if XFS_BIG_FILESYSTEMS +typedef xfs_ino_t xfs_intino_t; +#else +typedef __uint32_t xfs_intino_t; +#endif + +#define NULLFSINO ((xfs_ino_t)-1) +#define NULLAGINO ((xfs_agino_t)-1) + +struct xfs_mount; + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_MASK) +__uint32_t xfs_ino_mask(int k); +#define XFS_INO_MASK(k) xfs_ino_mask(k) +#else +#define XFS_INO_MASK(k) ((__uint32_t)((1ULL << (k)) - 1)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_OFFSET_BITS) +int xfs_ino_offset_bits(struct xfs_mount *mp); +#define XFS_INO_OFFSET_BITS(mp) xfs_ino_offset_bits(mp) +#else +#define XFS_INO_OFFSET_BITS(mp) ((mp)->m_sb.sb_inopblog) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_AGBNO_BITS) +int xfs_ino_agbno_bits(struct xfs_mount *mp); +#define XFS_INO_AGBNO_BITS(mp) xfs_ino_agbno_bits(mp) +#else +#define XFS_INO_AGBNO_BITS(mp) ((mp)->m_sb.sb_agblklog) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_AGINO_BITS) +int xfs_ino_agino_bits(struct xfs_mount *mp); +#define XFS_INO_AGINO_BITS(mp) xfs_ino_agino_bits(mp) +#else +#define XFS_INO_AGINO_BITS(mp) ((mp)->m_agino_log) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_AGNO_BITS) +int xfs_ino_agno_bits(struct xfs_mount *mp); +#define XFS_INO_AGNO_BITS(mp) xfs_ino_agno_bits(mp) +#else +#define XFS_INO_AGNO_BITS(mp) ((mp)->m_agno_log) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_BITS) +int xfs_ino_bits(struct xfs_mount *mp); +#define XFS_INO_BITS(mp) xfs_ino_bits(mp) +#else +#define XFS_INO_BITS(mp) (XFS_INO_AGNO_BITS(mp) + XFS_INO_AGINO_BITS(mp)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_TO_AGNO) +xfs_agnumber_t xfs_ino_to_agno(struct xfs_mount *mp, xfs_ino_t i); +#define XFS_INO_TO_AGNO(mp,i) xfs_ino_to_agno(mp,i) +#else +#define XFS_INO_TO_AGNO(mp,i) \ + ((xfs_agnumber_t)((i) >> XFS_INO_AGINO_BITS(mp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_TO_AGINO) +xfs_agino_t xfs_ino_to_agino(struct xfs_mount *mp, xfs_ino_t i); +#define XFS_INO_TO_AGINO(mp,i) xfs_ino_to_agino(mp,i) +#else +#define XFS_INO_TO_AGINO(mp,i) \ + ((xfs_agino_t)(i) & XFS_INO_MASK(XFS_INO_AGINO_BITS(mp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_TO_AGBNO) +xfs_agblock_t xfs_ino_to_agbno(struct xfs_mount *mp, xfs_ino_t i); +#define XFS_INO_TO_AGBNO(mp,i) xfs_ino_to_agbno(mp,i) +#else +#define XFS_INO_TO_AGBNO(mp,i) \ + (((xfs_agblock_t)(i) >> XFS_INO_OFFSET_BITS(mp)) & \ + XFS_INO_MASK(XFS_INO_AGBNO_BITS(mp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_TO_OFFSET) +int xfs_ino_to_offset(struct xfs_mount *mp, xfs_ino_t i); +#define XFS_INO_TO_OFFSET(mp,i) xfs_ino_to_offset(mp,i) +#else +#define XFS_INO_TO_OFFSET(mp,i) \ + ((int)(i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(mp))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_INO_TO_FSB) +xfs_fsblock_t xfs_ino_to_fsb(struct xfs_mount *mp, xfs_ino_t i); +#define XFS_INO_TO_FSB(mp,i) xfs_ino_to_fsb(mp,i) +#else +#define XFS_INO_TO_FSB(mp,i) \ + XFS_AGB_TO_FSB(mp, XFS_INO_TO_AGNO(mp,i), XFS_INO_TO_AGBNO(mp,i)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGINO_TO_INO) +xfs_ino_t +xfs_agino_to_ino(struct xfs_mount *mp, xfs_agnumber_t a, xfs_agino_t i); +#define XFS_AGINO_TO_INO(mp,a,i) xfs_agino_to_ino(mp,a,i) +#else +#define XFS_AGINO_TO_INO(mp,a,i) \ + (((xfs_ino_t)(a) << XFS_INO_AGINO_BITS(mp)) | (i)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGINO_TO_AGBNO) +xfs_agblock_t xfs_agino_to_agbno(struct xfs_mount *mp, xfs_agino_t i); +#define XFS_AGINO_TO_AGBNO(mp,i) xfs_agino_to_agbno(mp,i) +#else +#define XFS_AGINO_TO_AGBNO(mp,i) ((i) >> XFS_INO_OFFSET_BITS(mp)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_AGINO_TO_OFFSET) +int xfs_agino_to_offset(struct xfs_mount *mp, xfs_agino_t i); +#define XFS_AGINO_TO_OFFSET(mp,i) xfs_agino_to_offset(mp,i) +#else +#define XFS_AGINO_TO_OFFSET(mp,i) \ + ((i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(mp))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_OFFBNO_TO_AGINO) +xfs_agino_t xfs_offbno_to_agino(struct xfs_mount *mp, xfs_agblock_t b, int o); +#define XFS_OFFBNO_TO_AGINO(mp,b,o) xfs_offbno_to_agino(mp,b,o) +#else +#define XFS_OFFBNO_TO_AGINO(mp,b,o) \ + ((xfs_agino_t)(((b) << XFS_INO_OFFSET_BITS(mp)) | (o))) +#endif + +#if XFS_BIG_FILESYSTEMS +#define XFS_MAXINUMBER ((xfs_ino_t)((1ULL << 56) - 1ULL)) +#define XFS_INO64_OFFSET ((xfs_ino_t)(1ULL << 32)) +#else +#define XFS_MAXINUMBER ((xfs_ino_t)((1ULL << 32) - 1ULL)) +#endif +#define XFS_MAXINUMBER_32 ((xfs_ino_t)((1ULL << 32) - 1ULL)) + +#endif /* __XFS_INUM_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_iocore.c linux-2.4-xfs/linux/fs/xfs/xfs_iocore.c --- linux-2.4.7/linux/fs/xfs/xfs_iocore.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_iocore.c Mon Apr 16 17:49:09 2001 @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +/* ARGSUSED */ +static int +xfs_rsync_fn( + xfs_inode_t *ip, + int ioflag, + xfs_off_t start, + xfs_off_t end) +{ + xfs_mount_t *mp = ip->i_mount; + int error = 0; + + if (ioflag & IO_SYNC) { + xfs_ilock(ip, XFS_ILOCK_SHARED); + xfs_iflock(ip); + error = xfs_iflush(ip, XFS_IFLUSH_SYNC); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return error; + } else { + if (ioflag & IO_DSYNC) { + xfs_log_force(mp, (xfs_lsn_t)0, + XFS_LOG_FORCE | XFS_LOG_SYNC ); + } + } + + return error; +} + + +static xfs_fsize_t +xfs_size_fn( + xfs_inode_t *ip) +{ + return (ip->i_d.di_size); +} + +static xfs_fsize_t +xfs_setsize_fn( + xfs_inode_t *ip, + xfs_fsize_t newsize) +{ + xfs_fsize_t isize; + + xfs_ilock(ip, XFS_ILOCK_EXCL); + if (newsize > ip->i_d.di_size) { + ip->i_d.di_size = newsize; + ip->i_update_core = 1; + ip->i_update_size = 1; + isize = newsize; + } else { + isize = ip->i_d.di_size; + } + xfs_iunlock(ip, XFS_ILOCK_EXCL); + + return isize; +} + + +xfs_ioops_t xfs_iocore_xfs = { +/* xfs_dio_write_func: (xfs_dio_write_t) xfs_dio_write, */ + xfs_dio_write_func: (xfs_dio_write_t)fs_nosys, +/* xfs_dio_read_func: (xfs_dio_read_t) xfs_dio_read, */ + xfs_dio_read_func: (xfs_dio_read_t)fs_nosys, +/* xfs_strat_write_func: (xfs_strat_write_t) xfs_strat_write, */ + xfs_strat_write_func: (xfs_strat_write_t)fs_nosys, + xfs_bmapi_func: (xfs_bmapi_t) xfs_bmapi, + xfs_bmap_eof_func: (xfs_bmap_eof_t) xfs_bmap_eof, + xfs_rsync_func: (xfs_rsync_t) xfs_rsync_fn, + xfs_lck_map_shared: (xfs_lck_map_shared_t) xfs_ilock_map_shared, + xfs_ilock: (xfs_lock_t) xfs_ilock, + xfs_ilock_demote: (xfs_lock_demote_t) xfs_ilock_demote, + xfs_ilock_nowait: (xfs_lock_nowait_t) xfs_ilock_nowait, + xfs_unlock: (xfs_unlk_t) xfs_iunlock, + xfs_chgtime: (xfs_chgtime_t) xfs_ichgtime, + xfs_size_func: (xfs_size_t) xfs_size_fn, + xfs_setsize_func: (xfs_setsize_t) xfs_setsize_fn, + xfs_lastbyte: (xfs_lastbyte_t) xfs_file_last_byte, +#ifdef CELL_CAPABLE +/* xfs_checklock: (xfs_checklock_t) xfs_checklock */ + xfs_checklock: (xfs_checklock_t) fs_nosys, +#endif +}; + +void +xfs_iocore_inode_reinit( + xfs_inode_t *ip) +{ + xfs_iocore_t *io = &ip->i_iocore; + + io->io_flags = XFS_IOCORE_ISXFS; + if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) { + io->io_flags |= XFS_IOCORE_RT; + } + + io->io_dmevmask = ip->i_d.di_dmevmask; + io->io_dmstate = ip->i_d.di_dmstate; +} + +void +xfs_iocore_inode_init( + xfs_inode_t *ip) +{ + xfs_iocore_t *io = &ip->i_iocore; + xfs_mount_t *mp = ip->i_mount; + + io->io_mount = mp; + io->io_lock = &ip->i_lock; + io->io_iolock = &ip->i_iolock; + + xfs_iocore_reset(io); + + io->io_obj = (void *)ip; + + xfs_iocore_inode_reinit(ip); +} + +void +xfs_iocore_reset( + xfs_iocore_t *io) +{ + xfs_mount_t *mp = io->io_mount; + + /* + * initialize read/write io sizes + */ + ASSERT(mp->m_readio_log <= 0xff); + ASSERT(mp->m_writeio_log <= 0xff); + + io->io_readio_log = (uchar_t) mp->m_readio_log; + io->io_writeio_log = (uchar_t) mp->m_writeio_log; + io->io_max_io_log = (uchar_t) mp->m_writeio_log; + io->io_readio_blocks = mp->m_readio_blocks; + io->io_writeio_blocks = mp->m_writeio_blocks; +} + +void +xfs_iocore_destroy( + xfs_iocore_t *io) +{ +} + diff -rNu linux-2.4.7/linux/fs/xfs/xfs_itable.c linux-2.4-xfs/linux/fs/xfs/xfs_itable.c --- linux-2.4.7/linux/fs/xfs/xfs_itable.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_itable.c Tue Apr 10 20:44:54 2001 @@ -0,0 +1,848 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * Return stat information for one inode. + * Return 0 if ok, else errno. + */ +int /* error status */ +xfs_bulkstat_one( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t ino, /* inode number to get data for */ + void *buffer, /* buffer to place output in */ + xfs_daddr_t bno, /* starting bno of inode cluster */ + void *dibuff, /* on-disk inode buffer */ + int *stat) /* BULKSTAT_RV_... */ +{ + xfs_bstat_t *buf; /* return buffer */ + int error; /* error value */ + xfs_dinode_t *dip; /* dinode inode pointer */ + xfs_dinode_core_t *dic; /* dinode core info pointer */ + xfs_inode_t *ip = NULL; /* incore inode pointer */ + xfs_arch_t arch; /* these are set according to */ + __uint16_t di_flags; /* temp */ + + buf = (xfs_bstat_t *)buffer; + dip = (xfs_dinode_t *)dibuff; + + if (! buf || ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino || + (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) && + (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino))) { + *stat = BULKSTAT_RV_NOTHING; + return XFS_ERROR(EINVAL); + } + + if (dip == NULL) { + /* We're not being passed a pointer to a dinode. This happens + * if BULKSTAT_FG_IGET is selected. Do the iget. + */ + error = xfs_iget(mp, tp, ino, XFS_ILOCK_SHARED, &ip, bno); + if (error) { + *stat = BULKSTAT_RV_NOTHING; + return error; + } + ASSERT(ip != NULL); + ASSERT(ip->i_blkno != (xfs_daddr_t)0); + if (ip->i_d.di_mode == 0) { + xfs_iput(ip, XFS_ILOCK_SHARED); + *stat = BULKSTAT_RV_NOTHING; + return XFS_ERROR(ENOENT); + } + dic = &ip->i_d; + arch = ARCH_NOCONVERT; /* in-core! */ + ASSERT(dic != NULL); + + /* xfs_iget returns the following without needing + * further change. + */ + buf->bs_nlink = dic->di_nlink; + buf->bs_projid = dic->di_projid; + + } else { + dic = &dip->di_core; + ASSERT(dic != NULL); + + /* buffer dinode_core is in on-disk arch */ + arch = ARCH_CONVERT; + + /* + * The inode format changed when we moved the link count and + * made it 32 bits long. If this is an old format inode, + * convert it in memory to look like a new one. If it gets + * flushed to disk we will convert back before flushing or + * logging it. We zero out the new projid field and the old link + * count field. We'll handle clearing the pad field (the remains + * of the old uuid field) when we actually convert the inode to + * the new format. We don't change the version number so that we + * can distinguish this from a real new format inode. + */ + if (INT_GET(dic->di_version, arch) == XFS_DINODE_VERSION_1) { + buf->bs_nlink = INT_GET(dic->di_onlink, arch); + buf->bs_projid = 0; + } + else { + buf->bs_nlink = INT_GET(dic->di_nlink, arch); + buf->bs_projid = INT_GET(dic->di_projid, arch); + } + + } + + buf->bs_ino = ino; + buf->bs_mode = INT_GET(dic->di_mode, arch); + buf->bs_uid = INT_GET(dic->di_uid, arch); + buf->bs_gid = INT_GET(dic->di_gid, arch); + buf->bs_size = INT_GET(dic->di_size, arch); + buf->bs_atime.tv_sec = INT_GET(dic->di_atime.t_sec, arch); + buf->bs_atime.tv_nsec = INT_GET(dic->di_atime.t_nsec, arch); + buf->bs_mtime.tv_sec = INT_GET(dic->di_mtime.t_sec, arch); + buf->bs_mtime.tv_nsec = INT_GET(dic->di_mtime.t_nsec, arch); + buf->bs_ctime.tv_sec = INT_GET(dic->di_ctime.t_sec, arch); + buf->bs_ctime.tv_nsec = INT_GET(dic->di_ctime.t_nsec, arch); + /* + * convert di_flags to bs_xflags. + */ + di_flags=INT_GET(dic->di_flags, arch); + + buf->bs_xflags = + ((di_flags & XFS_DIFLAG_REALTIME) ? + XFS_XFLAG_REALTIME : 0) | + ((di_flags & XFS_DIFLAG_PREALLOC) ? + XFS_XFLAG_PREALLOC : 0) | + (XFS_CFORK_Q_ARCH(dic, arch) ? + XFS_XFLAG_HASATTR : 0); + + buf->bs_extsize = INT_GET(dic->di_extsize, arch) << mp->m_sb.sb_blocklog; + buf->bs_extents = INT_GET(dic->di_nextents, arch); + buf->bs_gen = INT_GET(dic->di_gen, arch); + bzero(buf->bs_pad, sizeof(buf->bs_pad)); + buf->bs_dmevmask = INT_GET(dic->di_dmevmask, arch); + buf->bs_dmstate = INT_GET(dic->di_dmstate, arch); + buf->bs_aextents = INT_GET(dic->di_anextents, arch); + + switch (INT_GET(dic->di_format, arch)) { + case XFS_DINODE_FMT_DEV: + if ( ip ) { + buf->bs_rdev = ip->i_df.if_u2.if_rdev; + } else { + buf->bs_rdev = INT_GET(dip->di_u.di_dev, arch); + } + + buf->bs_blksize = BLKDEV_IOSIZE; + buf->bs_blocks = 0; + break; + case XFS_DINODE_FMT_LOCAL: + case XFS_DINODE_FMT_UUID: + buf->bs_rdev = 0; + buf->bs_blksize = mp->m_sb.sb_blocksize; + buf->bs_blocks = 0; + break; + case XFS_DINODE_FMT_EXTENTS: + case XFS_DINODE_FMT_BTREE: + buf->bs_rdev = 0; + buf->bs_blksize = mp->m_sb.sb_blocksize; + if ( ip ) { + buf->bs_blocks = INT_GET(dic->di_nblocks, arch) + ip->i_delayed_blks; + } else { + buf->bs_blocks = INT_GET(dic->di_nblocks, arch); + } + break; + } + + if (ip) { + xfs_iput(ip, XFS_ILOCK_SHARED); + } + + *stat = BULKSTAT_RV_DIDONE; + return 0; +} + +/* + * Return stat information in bulk (by-inode) for the filesystem. + */ +int /* error status */ +xfs_bulkstat( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t *lastinop, /* last inode returned */ + int *ubcountp, /* size of buffer/count returned */ + bulkstat_one_pf formatter, /* func that'd fill a single buf */ + size_t statstruct_size, /* sizeof struct filling */ + xfs_caddr_t ubuffer, /* buffer with inode stats */ + int flags, /* defined in xfs_itable.h */ + int *done) /* 1 if there're more stats to get */ +{ + xfs_agblock_t agbno=0; /* allocation group block number */ + xfs_buf_t *agbp; /* agi header buffer */ + xfs_agi_t *agi; /* agi header data */ + xfs_agino_t agino; /* inode # in allocation group */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_daddr_t bno; /* inode cluster start daddr */ + int chunkidx; /* current index into inode chunk */ + int clustidx; /* current index into inode cluster */ + xfs_btree_cur_t *cur; /* btree cursor for ialloc btree */ + int end_of_ag; /* set if we've seen the ag end */ + int error; /* error code */ + int fmterror;/* bulkstat formatter result */ + __int32_t gcnt; /* current btree rec's count */ + xfs_inofree_t gfree; /* current btree rec's free mask */ + xfs_agino_t gino; /* current btree rec's start inode */ + int i; /* loop index */ + int icount; /* count of inodes good in irbuf */ + xfs_ino_t ino; /* inode number (filesystem) */ + xfs_inobt_rec_t *irbp; /* current irec buffer pointer */ + xfs_inobt_rec_t *irbuf; /* start of irec buffer */ + xfs_inobt_rec_t *irbufend; /* end of good irec buffer entries */ + xfs_ino_t lastino=0; /* last inode number returned */ + int nbcluster; /* # of blocks in a cluster */ + int nicluster; /* # of inodes in a cluster */ + int nimask; /* mask for inode clusters */ + int nirbuf; /* size of irbuf */ + int rval; /* return value error code */ + int tmp; /* result value from btree calls */ + int ubcount; /* size of user's buffer */ + int ubleft; /* spaces left in user's buffer */ + xfs_caddr_t ubufp; /* current pointer into user's buffer */ + xfs_buf_t *bp; /* ptr to on-disk inode cluster buf */ + xfs_dinode_t *dip; /* ptr into bp for specific inode */ + xfs_inode_t *ip; /* ptr to in-core inode struct */ + vfs_t *vfsp; + int vfs_unbusy_needed = 0; + + + + /* + * Check that the device is valid/mounted and mark it busy + * for the duration of this call. + */ + vfsp = XFS_MTOVFS(mp); + if (!(flags & BULKSTAT_FG_VFSLOCKED)) { + if ((error = vfs_busy(vfsp))) + return error; + vfs_unbusy_needed = 1; + } + + /* + * Get the last inode value, see if there's nothing to do. + */ + ino = (xfs_ino_t)*lastinop; + dip = NULL; + agno = XFS_INO_TO_AGNO(mp, ino); + agino = XFS_INO_TO_AGINO(mp, ino); + if (agno >= mp->m_sb.sb_agcount || + ino != XFS_AGINO_TO_INO(mp, agno, agino)) { + *done = 1; + *ubcountp = 0; + if (vfs_unbusy_needed) { + vfs_unbusy(vfsp); + } + return 0; + } + ubcount = ubleft = *ubcountp; + *ubcountp = 0; + *done = 0; + fmterror = 0; + ubufp = ubuffer; + nicluster = mp->m_sb.sb_blocksize >= XFS_INODE_CLUSTER_SIZE(mp) ? + mp->m_sb.sb_inopblock : + (XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog); + nimask = ~(nicluster - 1); + nbcluster = nicluster >> mp->m_sb.sb_inopblog; + /* + * Lock down the user's buffer. If a buffer was not sent, as in the case + * disk quota code calls here, we skip this. + */ +#if defined(HAVE_USERACC) + if (ubuffer && + (error = useracc(ubuffer, ubcount * statstruct_size, + (B_READ|B_PHYS), NULL))) { + if (vfs_unbusy_needed) { + vfs_unbusy(vfsp); + } + return error; + } +#endif + /* + * Allocate a page-sized buffer for inode btree records. + * We could try allocating something smaller, but for normal + * calls we'll always (potentially) need the whole page. + */ + irbuf = kmem_alloc(NBPC, KM_SLEEP); + nirbuf = NBPC / sizeof(*irbuf); + /* + * Loop over the allocation groups, starting from the last + * inode returned; 0 means start of the allocation group. + */ + rval = 0; + while (ubleft > 0 && agno < mp->m_sb.sb_agcount) { + bp = NULL; + mrlock(&mp->m_peraglock, MR_ACCESS, PINOD); + error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); + mrunlock(&mp->m_peraglock); + if (error) { + /* + * Skip this allocation group and go to the next one. + */ + agno++; + agino = 0; + continue; + } + agi = XFS_BUF_TO_AGI(agbp); + /* + * Allocate and initialize a btree cursor for ialloc btree. + */ + cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO, + (xfs_inode_t *)0, 0); + irbp = irbuf; + irbufend = irbuf + nirbuf; + end_of_ag = 0; + /* + * If we're returning in the middle of an allocation group, + * we need to get the remainder of the chunk we're in. + */ + if (agino > 0) { + /* + * Lookup the inode chunk that this inode lives in. + */ + error = xfs_inobt_lookup_le(cur, agino, 0, 0, &tmp); + if (!error && /* no I/O error */ + tmp && /* lookup succeeded */ + /* got the record, should always work */ + !(error = xfs_inobt_get_rec(cur, &gino, &gcnt, + &gfree, &i, ARCH_NOCONVERT)) && + i == 1 && + /* this is the right chunk */ + agino < gino + XFS_INODES_PER_CHUNK && + /* lastino was not last in chunk */ + (chunkidx = agino - gino + 1) < + XFS_INODES_PER_CHUNK && + /* there are some left allocated */ + XFS_INOBT_MASKN(chunkidx, + XFS_INODES_PER_CHUNK - chunkidx) & ~gfree) { + /* + * Grab the chunk record. Mark all the + * uninteresting inodes (because they're + * before our start point) free. + */ + for (i = 0; i < chunkidx; i++) { + if (XFS_INOBT_MASK(i) & ~gfree) + gcnt++; + } + gfree |= XFS_INOBT_MASKN(0, chunkidx); + INT_SET(irbp->ir_startino, ARCH_CONVERT, gino); + INT_SET(irbp->ir_freecount, ARCH_CONVERT, gcnt); + INT_SET(irbp->ir_free, ARCH_CONVERT, gfree); + irbp++; + agino = gino + XFS_INODES_PER_CHUNK; + icount = XFS_INODES_PER_CHUNK - gcnt; + } else { + /* + * If any of those tests failed, bump the + * inode number (just in case). + */ + agino++; + icount = 0; + } + /* + * In any case, increment to the next record. + */ + if (!error) + error = xfs_inobt_increment(cur, 0, &tmp); + } else { + /* + * Start of ag. Lookup the first inode chunk. + */ + error = xfs_inobt_lookup_ge(cur, 0, 0, 0, &tmp); + icount = 0; + } + /* + * Loop through inode btree records in this ag, + * until we run out of inodes or space in the buffer. + */ + while (irbp < irbufend && icount < ubcount) { + /* + * Loop as long as we're unable to read the + * inode btree. + */ + while (error) { + agino += XFS_INODES_PER_CHUNK; + if (XFS_AGINO_TO_AGBNO(mp, agino) >= + INT_GET(agi->agi_length, ARCH_CONVERT)) + break; + error = xfs_inobt_lookup_ge(cur, agino, 0, 0, + &tmp); + } + /* + * If ran off the end of the ag either with an error, + * or the normal way, set end and stop collecting. + */ + if (error || + (error = xfs_inobt_get_rec(cur, &gino, &gcnt, + &gfree, &i, ARCH_NOCONVERT)) || + i == 0) { + end_of_ag = 1; + break; + } + /* + * If this chunk has any allocated inodes, save it. + */ + if (gcnt < XFS_INODES_PER_CHUNK) { + INT_SET(irbp->ir_startino, ARCH_CONVERT, gino); + INT_SET(irbp->ir_freecount, ARCH_CONVERT, gcnt); + INT_SET(irbp->ir_free, ARCH_CONVERT, gfree); + irbp++; + icount += XFS_INODES_PER_CHUNK - gcnt; + } + /* + * Set agino to after this chunk and bump the cursor. + */ + agino = gino + XFS_INODES_PER_CHUNK; + error = xfs_inobt_increment(cur, 0, &tmp); + } + /* + * Drop the btree buffers and the agi buffer. + * We can't hold any of the locks these represent + * when calling iget. + */ + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + xfs_trans_brelse(tp, agbp); + /* + * Now format all the good inodes into the user's buffer. + */ + irbufend = irbp; + for (irbp = irbuf; irbp < irbufend && ubleft > 0; irbp++) { + /* + * Read-ahead the next chunk's worth of inodes. + */ + if (&irbp[1] < irbufend) { + /* + * Loop over all clusters in the next chunk. + * Do a readahead if there are any allocated + * inodes in that cluster. + */ + for (agbno = XFS_AGINO_TO_AGBNO(mp, + INT_GET(irbp[1].ir_startino, ARCH_CONVERT)), + chunkidx = 0; + chunkidx < XFS_INODES_PER_CHUNK; + chunkidx += nicluster, + agbno += nbcluster) { + if (XFS_INOBT_MASKN(chunkidx, + nicluster) & + ~(INT_GET(irbp[1].ir_free, ARCH_CONVERT))) + xfs_btree_reada_bufs(mp, agno, + agbno, nbcluster); + } + } + /* + * Now process this chunk of inodes. + */ + for (agino = INT_GET(irbp->ir_startino, ARCH_CONVERT), chunkidx = 0, clustidx = 0; + ubleft > 0 && + INT_GET(irbp->ir_freecount, ARCH_CONVERT) < XFS_INODES_PER_CHUNK; + chunkidx++, clustidx++, agino++) { + ASSERT(chunkidx < XFS_INODES_PER_CHUNK); + /* + * Recompute agbno if this is the + * first inode of the cluster. + * + * Careful with clustidx. There can be + * multple clusters per chunk, a single + * cluster per chunk or a cluster that has + * inodes represented from several different + * chunks (if blocksize is large). + * + * Because of this, the starting clustidx is + * initialized to zero in this loop but must + * later be reset after reading in the cluster + * buffer. + */ + if ((chunkidx & (nicluster - 1)) == 0) { + agbno = XFS_AGINO_TO_AGBNO(mp, + INT_GET(irbp->ir_startino, ARCH_CONVERT)) + + ((chunkidx & nimask) >> + mp->m_sb.sb_inopblog); + + if (flags & BULKSTAT_FG_QUICK) { + ino = XFS_AGINO_TO_INO(mp, agno, + agino); + bno = XFS_AGB_TO_DADDR(mp, agno, + agbno); + + /* + * Get the inode cluster buffer + */ + ASSERT(xfs_inode_zone != NULL); + ip = kmem_zone_zalloc(xfs_inode_zone, + KM_SLEEP); + ip->i_ino = ino; + ip->i_dev = mp->m_dev; + ip->i_mount = mp; + if (bp) + xfs_trans_brelse(tp, bp); + error = xfs_itobp(mp, tp, ip, + &dip, &bp, bno); + kmem_zone_free(xfs_inode_zone, ip); + if (XFS_TEST_ERROR(error != 0, + mp, XFS_ERRTAG_BULKSTAT_READ_CHUNK, + XFS_RANDOM_BULKSTAT_READ_CHUNK)) { + break; + } + clustidx = ip->i_boffset / + mp->m_sb.sb_inodesize; + } + } + /* + * Skip if this inode is free. + */ + if (XFS_INOBT_MASK(chunkidx) & INT_GET(irbp->ir_free, ARCH_CONVERT)) + continue; + /* + * Count used inodes as free so we can tell + * when the chunk is used up. + */ + INT_MOD(irbp->ir_freecount, ARCH_CONVERT, +1); + ino = XFS_AGINO_TO_INO(mp, agno, agino); + bno = XFS_AGB_TO_DADDR(mp, agno, agbno); + if (flags & BULKSTAT_FG_QUICK) { + dip = (xfs_dinode_t *)xfs_buf_offset(bp, + (clustidx << mp->m_sb.sb_inodelog)); + + if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) + != XFS_DINODE_MAGIC + || !XFS_DINODE_GOOD_VERSION( + INT_GET(dip->di_core.di_version, ARCH_CONVERT))) + continue; + } + + /* + * Get the inode and fill in a single buffer. + * BULKSTAT_FG_QUICK uses dip to fill it in. + * BULKSTAT_FG_IGET uses igets. + * See: xfs_bulkstat_one & dm_bulkstat_one. + * This is also used to count inodes/blks, etc + * in xfs_qm_quotacheck. + */ + error = formatter(mp, tp, ino, ubufp, bno, dip, + &fmterror); + if (fmterror == BULKSTAT_RV_NOTHING) + continue; + if (fmterror == BULKSTAT_RV_GIVEUP) { + ubleft = 0; + ASSERT(error); + rval = error; + break; + } + if (ubufp) + ubufp += statstruct_size; + ubleft--; + lastino = ino; + } + } + + if (bp) + xfs_trans_brelse(tp, bp); + + /* + * Set up for the next loop iteration. + */ + if (ubleft > 0) { + if (end_of_ag) { + agno++; + agino = 0; + } else + agino = XFS_INO_TO_AGINO(mp, lastino); + } else + break; + } + /* + * Done, we're either out of filesystem or space to put the data. + */ + kmem_free(irbuf, NBPC); +#if defined(HAVE_USERACC) + if (ubuffer) + unuseracc(ubuffer, ubcount * statstruct_size, (B_READ|B_PHYS)); +#endif + *ubcountp = ubcount - ubleft; + if (agno >= mp->m_sb.sb_agcount) { + /* + * If we ran out of filesystem, mark lastino as off + * the end of the filesystem, so the next call + * will return immediately. + */ + *lastinop = (xfs_ino_t)XFS_AGINO_TO_INO(mp, agno, 0); + *done = 1; + } else + *lastinop = (xfs_ino_t)lastino; + if (vfs_unbusy_needed) { + vfs_unbusy(vfsp); + } + return rval; +} + +/* + * Return stat information in bulk (by-inode) for the filesystem. + * Special case for non-sequential one inode bulkstat. + */ +int /* error status */ +xfs_bulkstat_single( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_ino_t *lastinop, /* inode to return */ + xfs_caddr_t buffer, /* buffer with inode stats */ + int *done) /* 1 if there're more stats to get */ +{ + xfs_bstat_t bstat; /* one bulkstat result structure */ + int count; /* count value for bulkstat call */ + int error; /* return value */ + xfs_ino_t ino; /* filesystem inode number */ + int res; /* result from bs1 */ + + /* + * note that requesting valid inode numbers which are not allocated + * to inodes will most likely cause xfs_itobp to generate warning + * messages about bad magic numbers. This is ok. The fact that + * the inode isn't actually an inode is handled by the + * error check below. Done this way to make the usual case faster + * at the expense of the error case. + */ + + ino = (xfs_ino_t)*lastinop; + error = xfs_bulkstat_one(mp, NULL, ino, &bstat, 0, 0, &res); + if (error) { + /* + * Special case way failed, do it the "long" way + * to see if that works. + */ + (*lastinop)--; + count = 1; + if (xfs_bulkstat(mp, NULL, lastinop, &count, xfs_bulkstat_one, + sizeof(bstat), buffer, BULKSTAT_FG_IGET, done)) + return error; + if (count == 0 || (xfs_ino_t)*lastinop != ino) + return error == EFSCORRUPTED ? + XFS_ERROR(EINVAL) : error; + else + return 0; + } + *done = 0; + if (copyout(&bstat, buffer, sizeof(bstat))) + return XFS_ERROR(EFAULT); + return 0; +} + +#ifdef NOTYET +/* No callers of this on linux yet, lets not build it */ +/* + * Return inode number table for the filesystem. + */ +STATIC int /* error status */ +xfs_inumbers( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t *lastino, /* last inode returned */ + int *count, /* size of buffer/count returned */ + xfs_caddr_t ubuffer) /* buffer with inode descriptions */ +{ + xfs_buf_t *agbp; + xfs_agino_t agino; + xfs_agnumber_t agno; + int bcount; + xfs_inogrp_t *buffer; + int bufidx; + xfs_btree_cur_t *cur; + int error; + __int32_t gcnt; + xfs_inofree_t gfree; + xfs_agino_t gino; + int i; + xfs_ino_t ino; + int left; + int tmp; + + ino = (xfs_ino_t)*lastino; + agno = XFS_INO_TO_AGNO(mp, ino); + agino = XFS_INO_TO_AGINO(mp, ino); + left = *count; + *count = 0; + bcount = MIN(left, NBPP / sizeof(*buffer)); + buffer = kmem_alloc(bcount * sizeof(*buffer), KM_SLEEP); + error = bufidx = 0; + cur = NULL; + agbp = NULL; + while (left > 0 && agno < mp->m_sb.sb_agcount) { + if (agbp == NULL) { + mrlock(&mp->m_peraglock, MR_ACCESS, PINOD); + error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); + mrunlock(&mp->m_peraglock); + if (error) { + /* + * If we can't read the AGI of this ag, + * then just skip to the next one. + */ + ASSERT(cur == NULL); + agbp = NULL; + agno++; + agino = 0; + continue; + } + cur = xfs_btree_init_cursor(mp, tp, agbp, agno, + XFS_BTNUM_INO, (xfs_inode_t *)0, 0); + error = xfs_inobt_lookup_ge(cur, agino, 0, 0, &tmp); + if (error) { + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + cur = NULL; + xfs_trans_brelse(tp, agbp); + agbp = NULL; + /* + * Move up the the last inode in the current + * chunk. The lookup_ge will always get + * us the first inode in the next chunk. + */ + agino += XFS_INODES_PER_CHUNK - 1; + continue; + } + } + if ((error = xfs_inobt_get_rec(cur, &gino, &gcnt, &gfree, + &i, ARCH_NOCONVERT)) || + i == 0) { + xfs_trans_brelse(tp, agbp); + agbp = NULL; + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + cur = NULL; + agno++; + agino = 0; + continue; + } + agino = gino + XFS_INODES_PER_CHUNK - 1; + buffer[bufidx].xi_startino = XFS_AGINO_TO_INO(mp, agno, gino); + buffer[bufidx].xi_alloccount = XFS_INODES_PER_CHUNK - gcnt; + buffer[bufidx].xi_allocmask = ~gfree; + bufidx++; + left--; + if (bufidx == bcount) { + if (copyout((xfs_caddr_t)buffer, ubuffer, + bufidx * sizeof(*buffer))) { + error = XFS_ERROR(EFAULT); + break; + } + ubuffer += bufidx * sizeof(*buffer); + *count += bufidx; + bufidx = 0; + } + if (left) { + error = xfs_inobt_increment(cur, 0, &tmp); + if (error) { + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); + cur = NULL; + xfs_trans_brelse(tp, agbp); + agbp = NULL; + /* + * The agino value has already been bumped. + * Just try to skip up to it. + */ + agino += XFS_INODES_PER_CHUNK; + continue; + } + } + } + if (!error) { + if (bufidx) { + if (copyout((xfs_caddr_t)buffer, ubuffer, + bufidx * sizeof(*buffer))) + error = XFS_ERROR(EFAULT); + else + *count += bufidx; + } + *lastino = XFS_AGINO_TO_INO(mp, agno, agino); + } + kmem_free(buffer, bcount * sizeof(*buffer)); + if (cur) + xfs_btree_del_cursor(cur, (error ? XFS_BTREE_ERROR : + XFS_BTREE_NOERROR)); + if (agbp) + xfs_trans_brelse(tp, agbp); + return error; +} +#endif + +/* + * Convert file descriptor of a file in the filesystem to + * a mount structure pointer. + */ +int /* error status */ +xfs_fd_to_mp( + int fd, /* file descriptor to convert */ + int wperm, /* need write perm on device */ + xfs_mount_t **mpp, /* return mount pointer */ + int rperm) /* set if root per on file fd */ +{ + dev_t dev; + int error; + vfile_t *fp=NULL; + vfs_t *vfsp; + vnode_t *vp; + bhv_desc_t *bdp; + + if ((error = getf(fd, &fp))) + return XFS_ERROR(error); + if (!VF_IS_VNODE(fp)) + return XFS_ERROR(EINVAL); + + vp = VF_TO_VNODE(fp); + if (vp->v_type == VBLK || vp->v_type == VCHR) { + if (wperm && !(fp->vf_flag & FWRITE)) + return XFS_ERROR(EPERM); + dev = 0; /* broken */ + vfsp = vfs_devsearch(dev, xfs_fstype); + if (vfsp == NULL) + vfsp = vp->v_vfsp; + } else { + if (rperm && !capable(CAP_SYS_ADMIN)) + return XFS_ERROR(EPERM); + vfsp = vp->v_vfsp; + } + bdp = bhv_lookup_unlocked(VFS_BHVHEAD(vfsp), &xfs_vfsops); + if (!bdp) { +#if CELL_CAPABLE + if (cell_enabled && (rperm == 0)) { +#pragma mips_frequency_hint NEVER + *mpp = get_cxfs_mountp(vfsp); + if (*mpp) + return 0; + } +#endif + return XFS_ERROR(EINVAL); + } + *mpp = XFS_BHVTOM(bdp); + return 0; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_itable.h linux-2.4-xfs/linux/fs/xfs/xfs_itable.h --- linux-2.4.7/linux/fs/xfs/xfs_itable.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_itable.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_ITABLE_H__ +#define __XFS_ITABLE_H__ + +struct xfs_mount; +struct xfs_trans; + +/* + * Prototypes for visible xfs_itable.c routines. + */ + +/* + * Convert file descriptor of a file in the filesystem to + * a mount structure pointer. + */ +int /* error status */ +xfs_fd_to_mp( + int fd, /* file descriptor */ + int wperm, /* need write perm on device fd */ + struct xfs_mount **mpp, /* output: mount structure pointer */ + int rperm); /* need root perm on file fd */ + +/* + * xfs_bulkstat() is used to fill in xfs_bstat structures as well as dm_stat + * structures (by the dmi library). This is a pointer to a formatter function + * that will iget the inode and fill in the appropriate structure. + * see xfs_bulkstat_one() and dm_bulkstat_one() in dmi_xfs.c + */ +typedef int (*bulkstat_one_pf)(struct xfs_mount *mp, + struct xfs_trans *tp, + xfs_ino_t ino, + void *buffer, + xfs_daddr_t bno, + void *dip, + int *stat); +/* + * Values for stat return value. + */ +#define BULKSTAT_RV_NOTHING 0 +#define BULKSTAT_RV_DIDONE 1 +#define BULKSTAT_RV_GIVEUP 2 + +/* + * Values for bulkstat flag argument. + */ +#define BULKSTAT_FG_IGET 0x1 /* Go through the buffer cache */ +#define BULKSTAT_FG_QUICK 0x2 /* No iget, walk the dinode cluster */ +#define BULKSTAT_FG_VFSLOCKED 0x4 /* Already have vfs lock */ + +/* + * Return stat information in bulk (by-inode) for the filesystem. + */ +int /* error status */ +xfs_bulkstat( + struct xfs_mount *mp, /* mount point for filesystem */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_ino_t *lastino, /* last inode returned */ + int *count, /* size of buffer/count returned */ + bulkstat_one_pf formatter, /* func that'd fill a single buf */ + size_t statstruct_size,/* sizeof struct that we're filling */ + xfs_caddr_t ubuffer, /* buffer with inode stats */ + int flags, /* flag to control access method */ + int *done); /* 1 if there're more stats to get */ + +int +xfs_bulkstat_single( + struct xfs_mount *mp, + xfs_ino_t *lastinop, + xfs_caddr_t buffer, + int *done); + +int +xfs_bulkstat_one( + struct xfs_mount *mp, + struct xfs_trans *tp, + xfs_ino_t ino, + void *buffer, + xfs_daddr_t bno, + void *dibuff, + int *stat); + +#endif /* __XFS_ITABLE_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_log.c linux-2.4-xfs/linux/fs/xfs/xfs_log.c --- linux-2.4.7/linux/fs/xfs/xfs_log.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_log.c Wed May 16 21:58:46 2001 @@ -0,0 +1,3528 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * High level interface routines for log manager + */ + +#include + + +#define xlog_write_adv_cnt(ptr, len, off, bytes) \ + { (ptr) += (bytes); \ + (len) -= (bytes); \ + (off) += (bytes);} + +/* Local miscellaneous function prototypes */ +STATIC int xlog_bdstrat_cb(struct xfs_buf *); +STATIC int xlog_commit_record(xfs_mount_t *mp, xlog_ticket_t *ticket, + xfs_lsn_t *); +STATIC xlog_t * xlog_alloc_log(xfs_mount_t *mp, + dev_t log_dev, + xfs_daddr_t blk_offset, + int num_bblks); +STATIC int xlog_space_left(xlog_t *log, int cycle, int bytes); +STATIC int xlog_sync(xlog_t *log, xlog_in_core_t *iclog, uint flags); +STATIC void xlog_unalloc_log(xlog_t *log); +STATIC int xlog_write(xfs_mount_t *mp, xfs_log_iovec_t region[], + int nentries, xfs_log_ticket_t tic, + xfs_lsn_t *start_lsn, uint flags); + +/* local state machine functions */ +STATIC void xlog_state_done_syncing(xlog_in_core_t *iclog, int); +STATIC void xlog_state_do_callback(xlog_t *log,int aborted, xlog_in_core_t *iclog); +static inline void xlog_state_finish_copy(xlog_t *log, + xlog_in_core_t *iclog, + int first_write, + int bytes); +STATIC int xlog_state_get_iclog_space(xlog_t *log, + int len, + xlog_in_core_t **iclog, + xlog_ticket_t *ticket, + int *continued_write, + int *logoffsetp); +STATIC int xlog_state_lsn_is_synced(xlog_t *log, + xfs_lsn_t lsn, + xfs_log_callback_t *cb, + int *abortflg); +STATIC void xlog_state_put_ticket(xlog_t *log, + xlog_ticket_t *tic); +STATIC int xlog_state_release_iclog(xlog_t *log, + xlog_in_core_t *iclog); +STATIC void xlog_state_switch_iclogs(xlog_t *log, + xlog_in_core_t *iclog, + int eventual_size); +STATIC int xlog_state_sync(xlog_t *log, xfs_lsn_t lsn, uint flags); +STATIC int xlog_state_sync_all(xlog_t *log, uint flags); +STATIC void xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog); + +/* local functions to manipulate grant head */ +STATIC int xlog_grant_log_space(xlog_t *log, + xlog_ticket_t *xtic); +STATIC void xlog_grant_push_ail(xfs_mount_t *mp, + int need_bytes); +STATIC void xlog_regrant_reserve_log_space(xlog_t *log, + xlog_ticket_t *ticket); +STATIC int xlog_regrant_write_log_space(xlog_t *log, + xlog_ticket_t *ticket); +STATIC void xlog_ungrant_log_space(xlog_t *log, + xlog_ticket_t *ticket); + + +/* local ticket functions */ +STATIC void xlog_state_ticket_alloc(xlog_t *log); +STATIC xlog_ticket_t *xlog_ticket_get(xlog_t *log, + int unit_bytes, + int count, + char clientid, + uint flags); +STATIC void xlog_ticket_put(xlog_t *log, xlog_ticket_t *ticket); + +/* local debug functions */ +#if defined(DEBUG) && !defined(XLOG_NOLOG) +STATIC void xlog_verify_dest_ptr(xlog_t *log, __psint_t ptr); +#ifdef XFSDEBUG +STATIC void xlog_verify_disk_cycle_no(xlog_t *log, xlog_in_core_t *iclog); +#endif +STATIC void xlog_verify_grant_head(xlog_t *log, int equals); +STATIC void xlog_verify_iclog(xlog_t *log, xlog_in_core_t *iclog, + int count, boolean_t syncing); +STATIC void xlog_verify_tail_lsn(xlog_t *log, xlog_in_core_t *iclog, + xfs_lsn_t tail_lsn); +#else +#define xlog_verify_dest_ptr(a,b) +#define xlog_verify_disk_cycle_no(a,b) +#define xlog_verify_grant_head(a,b) +#define xlog_verify_iclog(a,b,c,d) +#define xlog_verify_tail_lsn(a,b,c) +#endif + +int xlog_iclogs_empty(xlog_t *log); + +#ifdef DEBUG +int xlog_do_error = 0; +int xlog_req_num = 0; +int xlog_error_mod = 33; +#endif + +#define XLOG_FORCED_SHUTDOWN(log) (log->l_flags & XLOG_IO_ERROR) + +/* + * 0 => disable log manager + * 1 => enable log manager + * 2 => enable log manager and log debugging + */ +#if defined(XLOG_NOLOG) || defined(DEBUG) +int xlog_debug = 1; +dev_t xlog_devt = 0; +#endif + +#if defined(XFS_LOG_TRACE) +void +xlog_trace_loggrant(xlog_t *log, xlog_ticket_t *tic, xfs_caddr_t string) +{ + if (! log->l_grant_trace) + log->l_grant_trace = ktrace_alloc(1024, KM_SLEEP); + + ktrace_enter(log->l_grant_trace, + (void *)tic, + (void *)log->l_reserve_headq, + (void *)log->l_write_headq, + (void *)((unsigned long)log->l_grant_reserve_cycle), + (void *)((unsigned long)log->l_grant_reserve_bytes), + (void *)((unsigned long)log->l_grant_write_cycle), + (void *)((unsigned long)log->l_grant_write_bytes), + (void *)((unsigned long)log->l_curr_cycle), + (void *)((unsigned long)log->l_curr_block), + (void *)((unsigned long)CYCLE_LSN(log->l_tail_lsn, ARCH_NOCONVERT)), + (void *)((unsigned long)BLOCK_LSN(log->l_tail_lsn, ARCH_NOCONVERT)), + (void *)string, + (void *)((unsigned long)13), + (void *)((unsigned long)14), + (void *)((unsigned long)15), + (void *)((unsigned long)16)); +} + +void +xlog_trace_tic(xlog_t *log, xlog_ticket_t *tic) +{ + if (! log->l_trace) + log->l_trace = ktrace_alloc(256, KM_SLEEP); + + ktrace_enter(log->l_trace, + (void *)tic, + (void *)((unsigned long)tic->t_curr_res), + (void *)((unsigned long)tic->t_unit_res), + (void *)((unsigned long)tic->t_ocnt), + (void *)((unsigned long)tic->t_cnt), + (void *)((unsigned long)tic->t_flags), + (void *)((unsigned long)7), + (void *)((unsigned long)8), + (void *)((unsigned long)9), + (void *)((unsigned long)10), + (void *)((unsigned long)11), + (void *)((unsigned long)12), + (void *)((unsigned long)13), + (void *)((unsigned long)14), + (void *)((unsigned long)15), + (void *)((unsigned long)16)); +} + +void +xlog_trace_iclog(xlog_in_core_t *iclog, uint state) +{ + pid_t pid; + + pid = current_pid(); + + if (!iclog->ic_trace) + iclog->ic_trace = ktrace_alloc(256, KM_SLEEP); + ktrace_enter(iclog->ic_trace, + (void *)((unsigned long)state), + (void *)((unsigned long)pid), + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0, + (void *)0); +} + +#else +#define xlog_trace_loggrant(log,tic,string) +#define xlog_trace_iclog(iclog,state) +#endif /* XFS_LOG_TRACE */ + +/* + * NOTES: + * + * 1. currblock field gets updated at startup and after in-core logs + * marked as with WANT_SYNC. + */ + +/* + * This routine is called when a user of a log manager ticket is done with + * the reservation. If the ticket was ever used, then a commit record for + * the associated transaction is written out as a log operation header with + * no data. The flag XLOG_TIC_INITED is set when the first write occurs with + * a given ticket. If the ticket was one with a permanent reservation, then + * a few operations are done differently. Permanent reservation tickets by + * default don't release the reservation. They just commit the current + * transaction with the belief that the reservation is still needed. A flag + * must be passed in before permanent reservations are actually released. + * When these type of tickets are not released, they need to be set into + * the inited state again. By doing this, a start record will be written + * out when the next write occurs. + */ +xfs_lsn_t +xfs_log_done(xfs_mount_t *mp, + xfs_log_ticket_t xtic, + uint flags) +{ + xlog_t *log = mp->m_log; + xlog_ticket_t *ticket = (xfs_log_ticket_t) xtic; + xfs_lsn_t lsn = 0; + +#if defined(DEBUG) || defined(XLOG_NOLOG) + if (! xlog_debug && xlog_devt == log->l_dev) + return 0; +#endif + + if (XLOG_FORCED_SHUTDOWN(log) || + /* + * If nothing was ever written, don't write out commit record. + * If we get an error, just continue and give back the log ticket. + */ + (((ticket->t_flags & XLOG_TIC_INITED) == 0) && + (xlog_commit_record(mp, ticket, &lsn)))) { + lsn = (xfs_lsn_t) -1; + if (ticket->t_flags & XLOG_TIC_PERM_RESERV) { + flags |= XFS_LOG_REL_PERM_RESERV; + } + } + + + if ((ticket->t_flags & XLOG_TIC_PERM_RESERV) == 0 || + (flags & XFS_LOG_REL_PERM_RESERV)) { + /* + * Release ticket if not permanent reservation or a specifc + * request has been made to release a permanent reservation. + */ + xlog_ungrant_log_space(log, ticket); + xlog_state_put_ticket(log, ticket); + } else { + xlog_regrant_reserve_log_space(log, ticket); + } + + /* If this ticket was a permanent reservation and we aren't + * trying to release it, reset the inited flags; so next time + * we write, a start record will be written out. + */ + if ((ticket->t_flags & XLOG_TIC_PERM_RESERV) && + (flags & XFS_LOG_REL_PERM_RESERV) == 0) + ticket->t_flags |= XLOG_TIC_INITED; + + return lsn; +} /* xfs_log_done */ + + +/* + * Force the in-core log to disk. If flags == XFS_LOG_SYNC, + * the force is done synchronously. + * + * Asynchronous forces are implemented by setting the WANT_SYNC + * bit in the appropriate in-core log and then returning. + * + * Synchronous forces are implemented with a semaphore. All callers + * to force a given lsn to disk will wait on a semaphore attached to the + * specific in-core log. When given in-core log finally completes its + * write to disk, that thread will wake up all threads waiting on the + * semaphore. + */ +int +xfs_log_force(xfs_mount_t *mp, + xfs_lsn_t lsn, + uint flags) +{ + int rval; + xlog_t *log = mp->m_log; + +#if defined(DEBUG) || defined(XLOG_NOLOG) + if (! xlog_debug && xlog_devt == log->l_dev) + return 0; +#endif + + ASSERT(flags & XFS_LOG_FORCE); + + XFS_STATS_INC(xfsstats.xs_log_force); + + if ((log->l_flags & XLOG_IO_ERROR) == 0) { + if (lsn == 0) + rval = xlog_state_sync_all(log, flags); + else + rval = xlog_state_sync(log, lsn, flags); + } else { + rval = XFS_ERROR(EIO); + } + + return rval; + +} /* xfs_log_force */ + + +/* + * This function will take a log sequence number and check to see if that + * lsn has been flushed to disk. If it has, then the callback function is + * called with the callback argument. If the relevant in-core log has not + * been synced to disk, we add the callback to the callback list of the + * in-core log. + */ +void +xfs_log_notify(xfs_mount_t *mp, /* mount of partition */ + xfs_lsn_t lsn, /* lsn looking for */ + xfs_log_callback_t *cb) +{ + xlog_t *log = mp->m_log; + int abortflg; + +#if defined(DEBUG) || defined(XLOG_NOLOG) + if (! xlog_debug && xlog_devt == log->l_dev) + return; +#endif + cb->cb_next = 0; + if (xlog_state_lsn_is_synced(log, lsn, cb, &abortflg)) + cb->cb_func(cb->cb_arg, abortflg); +} /* xfs_log_notify */ + + +/* + * Initialize log manager data. This routine is intended to be called when + * a system boots up. It is not a per filesystem initialization. + * + * As you can see, we currently do nothing. + */ +int +xfs_log_init(void) +{ + return( 0 ); +} + + +/* + * 1. Reserve an amount of on-disk log space and return a ticket corresponding + * to the reservation. + * 2. Potentially, push buffers at tail of log to disk. + * + * Each reservation is going to reserve extra space for a log record header. + * When writes happen to the on-disk log, we don't subtract the length of the + * log record header from any reservation. By wasting space in each + * reservation, we prevent over allocation problems. + */ +int +xfs_log_reserve(xfs_mount_t *mp, + int unit_bytes, + int cnt, + xfs_log_ticket_t *ticket, + char client, + uint flags) +{ + xlog_t *log = mp->m_log; + xlog_ticket_t *internal_ticket; + int retval; + +#if defined(DEBUG) || defined(XLOG_NOLOG) + if (! xlog_debug && xlog_devt == log->l_dev) + return 0; +#endif + retval = 0; + ASSERT(client == XFS_TRANSACTION || client == XFS_LOG); + ASSERT((flags & XFS_LOG_NOSLEEP) == 0); + + if (XLOG_FORCED_SHUTDOWN(log)) + return XFS_ERROR(EIO); + + XFS_STATS_INC(xfsstats.xs_try_logspace); + + if (*ticket != NULL) { + ASSERT(flags & XFS_LOG_PERM_RESERV); + internal_ticket = (xlog_ticket_t *)*ticket; + xlog_grant_push_ail(mp, internal_ticket->t_unit_res); + retval = xlog_regrant_write_log_space(log, internal_ticket); + } else { + /* may sleep if need to allocate more tickets */ + internal_ticket = xlog_ticket_get(log, unit_bytes, cnt, + client, flags); + *ticket = internal_ticket; + xlog_grant_push_ail(mp, + (internal_ticket->t_unit_res * + internal_ticket->t_cnt)); + retval = xlog_grant_log_space(log, internal_ticket); + } + + return retval; +} /* xfs_log_reserve */ + + +/* + * Mount a log filesystem + * + * mp - ubiquitous xfs mount point structure + * log_dev - device number of on-disk log device + * blk_offset - Start block # where block size is 512 bytes (BBSIZE) + * num_bblocks - Number of BBSIZE blocks in on-disk log + * + * Return error or zero. + */ +int +xfs_log_mount(xfs_mount_t *mp, + dev_t log_dev, + xfs_daddr_t blk_offset, + int num_bblks) +{ + xlog_t *log; + + if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) + cmn_err(CE_NOTE, + "!Start mounting filesystem: %s", mp->m_fsname); + else { + cmn_err(CE_NOTE, + "!Mounting filesystem \"%s\" in no-recovery mode. Filesystem will be inconsistent.", + mp->m_fsname); + ASSERT(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY); + } + + mp->m_log = log = xlog_alloc_log(mp, log_dev, blk_offset, num_bblks); + +#if defined(DEBUG) || defined(XLOG_NOLOG) + if (! xlog_debug) { + cmn_err(CE_NOTE, "log dev: 0x%x", log_dev); + return 0; + } +#endif + /* + * skip log recovery on a norecovery mount. pretend it all + * just worked. + */ + if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) { + int error; + + error = xlog_recover(log,XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY); + if (error) { + cmn_err(CE_WARN, "XFS: log mount/recovery failed"); + xlog_unalloc_log(log); + return error; + } + } + + /* Normal transactions can now occur */ + log->l_flags &= ~XLOG_ACTIVE_RECOVERY; + + /* End mounting message in xfs_log_mount_finish */ + return 0; +} /* xfs_log_mount */ + +/* + * Finish the recovery of the file system. This is separate from + * the xfs_log_mount() call, because it depends on the code in + * xfs_mountfs() to read in the root and real-time bitmap inodes + * between calling xfs_log_mount() and here. + * + * mp - ubiquitous xfs mount point structure + */ +int +xfs_log_mount_finish(xfs_mount_t *mp, int mfsi_flags) +{ + int error; + + if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) + error = xlog_recover_finish(mp->m_log, mfsi_flags); + else { + error = 0; + ASSERT(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY); + } + + return error; +} + +/* + * Unmount processing for the log. + */ +int +xfs_log_unmount(xfs_mount_t *mp) +{ + int error; + + error = xfs_log_unmount_write(mp); + xfs_log_unmount_dealloc(mp); + return (error); +} + +/* + * Final log writes as part of unmount. + * + * Mark the filesystem clean as unmount happens. Note that during relocation + * this routine needs to be executed as part of source-bag while the + * deallocation must not be done until source-end. + */ + +/* + * Unmount record used to have a string "Unmount filesystem--" in the + * data section where the "Un" was really a magic number (XLOG_UNMOUNT_TYPE). + * We just write the magic number now since that particular field isn't + * currently architecture converted and "nUmount" is a bit foo. + * As far as I know, there weren't any dependencies on the old behaviour. + */ + +int +xfs_log_unmount_write(xfs_mount_t *mp) +{ + xlog_t *log = mp->m_log; + xlog_in_core_t *iclog; +#ifdef DEBUG + xlog_in_core_t *first_iclog; +#endif + xfs_log_iovec_t reg[1]; + xfs_log_ticket_t tic = 0; + xfs_lsn_t lsn; + int error; + int spl; + + /* the data section must be 32 bit size aligned */ + struct { + __uint16_t magic; + __uint16_t pad1; + __uint32_t pad2; /* may as well make it 64 bits */ + } magic = { XLOG_UNMOUNT_TYPE, 0, 0 }; + +#if defined(DEBUG) || defined(XLOG_NOLOG) + if (! xlog_debug && xlog_devt == log->l_dev) + return 0; +#endif + + /* + * Don't write out unmount record on read-only mounts. + * Or, if we are doing a forced umount (typically because of IO errors). + */ + if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) + return 0; + + xfs_log_force(mp, 0, XFS_LOG_FORCE|XFS_LOG_SYNC); + +#ifdef DEBUG + first_iclog = iclog = log->l_iclog; + do { + if (!(iclog->ic_state & XLOG_STATE_IOERROR)) { + ASSERT(iclog->ic_state & XLOG_STATE_ACTIVE); + ASSERT(iclog->ic_offset == 0); + } + iclog = iclog->ic_next; + } while (iclog != first_iclog); +#endif + if (! (XLOG_FORCED_SHUTDOWN(log))) { + reg[0].i_addr = (void*)&magic; + reg[0].i_len = sizeof(magic); + + error = xfs_log_reserve(mp, 600, 1, &tic, XFS_LOG, 0); + if (!error) { + /* remove inited flag */ + ((xlog_ticket_t *)tic)->t_flags = 0; + error = xlog_write(mp, reg, 1, tic, &lsn, + XLOG_UNMOUNT_TRANS); + /* + * At this point, we're umounting anyway, + * so there's no point in transitioning log state + * to IOERROR. Just continue... + */ + } + + if (error) { + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_log_unmount: unmount record failed"); + } + + + spl = LOG_LOCK(log); + iclog = log->l_iclog; + iclog->ic_refcnt++; + LOG_UNLOCK(log, spl); + xlog_state_want_sync(log, iclog); + (void) xlog_state_release_iclog(log, iclog); + + spl = LOG_LOCK(log); + if (!(iclog->ic_state == XLOG_STATE_ACTIVE || + iclog->ic_state == XLOG_STATE_DIRTY)) { + if (!XLOG_FORCED_SHUTDOWN(log)) { + sv_wait(&iclog->ic_forcesema, PMEM, + &log->l_icloglock, spl); + } else { + LOG_UNLOCK(log, spl); + } + } else { + LOG_UNLOCK(log, spl); + } + if (tic) + xlog_state_put_ticket(log, tic); + } else { + /* + * We're already in forced_shutdown mode, couldn't + * even attempt to write out the unmount transaction. + * + * Go through the motions of sync'ing and releasing + * the iclog, even though no I/O will actually happen, + * we need to wait for other log I/O's that may already + * be in progress. Do this as a separate section of + * code so we'll know if we ever get stuck here that + * we're in this odd situation of trying to unmount + * a file system that went into forced_shutdown as + * the result of an unmount.. + */ + spl = LOG_LOCK(log); + iclog = log->l_iclog; + iclog->ic_refcnt++; + LOG_UNLOCK(log, spl); + + xlog_state_want_sync(log, iclog); + (void) xlog_state_release_iclog(log, iclog); + + spl = LOG_LOCK(log); + + if ( ! ( iclog->ic_state == XLOG_STATE_ACTIVE + || iclog->ic_state == XLOG_STATE_DIRTY + || iclog->ic_state == XLOG_STATE_IOERROR) ) { + + sv_wait(&iclog->ic_forcesema, PMEM, + &log->l_icloglock, spl); + } else { + LOG_UNLOCK(log, spl); + } + } + + return 0; +} /* xfs_log_unmount_write */ + +/* + * Deallocate log structures for unmount/relocation. + */ +void +xfs_log_unmount_dealloc(xfs_mount_t *mp) +{ + xlog_unalloc_log(mp->m_log); +} + +/* + * Write region vectors to log. The write happens using the space reservation + * of the ticket (tic). It is not a requirement that all writes for a given + * transaction occur with one call to xfs_log_write(). + */ +int +xfs_log_write(xfs_mount_t * mp, + xfs_log_iovec_t reg[], + int nentries, + xfs_log_ticket_t tic, + xfs_lsn_t *start_lsn) +{ + int error; + xlog_t *log = mp->m_log; +#if defined(DEBUG) || defined(XLOG_NOLOG) + + if (! xlog_debug && xlog_devt == log->l_dev) { + *start_lsn = 0; + return 0; + } +#endif + if (XLOG_FORCED_SHUTDOWN(log)) + return XFS_ERROR(EIO); + + if ((error = xlog_write(mp, reg, nentries, tic, start_lsn, 0))) { + xfs_force_shutdown(mp, XFS_LOG_IO_ERROR); + } + return (error); +} /* xfs_log_write */ + + +void +xfs_log_move_tail(xfs_mount_t *mp, + xfs_lsn_t tail_lsn) +{ + xlog_ticket_t *tic; + xlog_t *log = mp->m_log; + int need_bytes, free_bytes, cycle, bytes, spl; + +#if defined(DEBUG) || defined(XLOG_NOLOG) + if (!xlog_debug && xlog_devt == log->l_dev) + return; +#endif + /* XXXsup tmp */ + if (XLOG_FORCED_SHUTDOWN(log)) + return; + ASSERT(!XFS_FORCED_SHUTDOWN(mp)); + + if (tail_lsn == 0) { + /* needed since sync_lsn is 64 bits */ + spl = LOG_LOCK(log); + tail_lsn = log->l_last_sync_lsn; + LOG_UNLOCK(log, spl); + } + + spl = GRANT_LOCK(log); + + /* Also an illegal lsn. 1 implies that we aren't passing in a legal + * tail_lsn. + */ + if (tail_lsn != 1) + log->l_tail_lsn = tail_lsn; + + if ((tic = log->l_write_headq)) { +#ifdef DEBUG + if (log->l_flags & XLOG_ACTIVE_RECOVERY) + panic("Recovery problem"); +#endif + cycle = log->l_grant_write_cycle; + bytes = log->l_grant_write_bytes; + free_bytes = xlog_space_left(log, cycle, bytes); + do { + ASSERT(tic->t_flags & XLOG_TIC_PERM_RESERV); + + if (free_bytes < tic->t_unit_res) + break; + free_bytes -= tic->t_unit_res; + sv_signal(&tic->t_sema); + tic = tic->t_next; + } while (tic != log->l_write_headq); + } + if ((tic = log->l_reserve_headq)) { +#ifdef DEBUG + if (log->l_flags & XLOG_ACTIVE_RECOVERY) + panic("Recovery problem"); +#endif + cycle = log->l_grant_reserve_cycle; + bytes = log->l_grant_reserve_bytes; + free_bytes = xlog_space_left(log, cycle, bytes); + do { + if (tic->t_flags & XLOG_TIC_PERM_RESERV) + need_bytes = tic->t_unit_res*tic->t_cnt; + else + need_bytes = tic->t_unit_res; + if (free_bytes < need_bytes) + break; + free_bytes -= need_bytes; + sv_signal(&tic->t_sema); + tic = tic->t_next; + } while (tic != log->l_reserve_headq); + } + GRANT_UNLOCK(log, spl); +} /* xfs_log_move_tail */ + +/* + * Determine if we have a transaction that has gone to disk + * that needs to be covered. Log activity needs to be idle (no AIL and + * nothing in the iclogs). And, we need to be in the right state indicating + * something has gone out. + */ +int +xfs_log_need_covered(xfs_mount_t *mp) +{ + int spl, needed = 0, gen; + xlog_t *log = mp->m_log; + + if (mp->m_frozen) + return 0; + + spl = LOG_LOCK(log); + if (((log->l_covered_state == XLOG_STATE_COVER_NEED) || + (log->l_covered_state == XLOG_STATE_COVER_NEED2)) + && !xfs_trans_first_ail(mp, &gen) + && xlog_iclogs_empty(log)) { + if (log->l_covered_state == XLOG_STATE_COVER_NEED) + log->l_covered_state = XLOG_STATE_COVER_DONE; + else { + ASSERT(log->l_covered_state == XLOG_STATE_COVER_NEED2); + log->l_covered_state = XLOG_STATE_COVER_DONE2; + } + needed = 1; + } + LOG_UNLOCK(log, spl); + return(needed); +} + +/****************************************************************************** + * + * local routines + * + ****************************************************************************** + */ + +/* xfs_trans_tail_ail returns 0 when there is nothing in the list. + * The log manager must keep track of the last LR which was committed + * to disk. The lsn of this LR will become the new tail_lsn whenever + * xfs_trans_tail_ail returns 0. If we don't do this, we run into + * the situation where stuff could be written into the log but nothing + * was ever in the AIL when asked. Eventually, we panic since the + * tail hits the head. + * + * We may be holding the log iclog lock upon entering this routine. + */ +xfs_lsn_t +xlog_assign_tail_lsn(xfs_mount_t *mp, xlog_in_core_t *iclog) +{ + xfs_lsn_t tail_lsn; + int spl; + xlog_t *log = mp->m_log; + + tail_lsn = xfs_trans_tail_ail(mp); + spl = GRANT_LOCK(log); + if (tail_lsn != 0) + log->l_tail_lsn = tail_lsn; + else + tail_lsn = log->l_tail_lsn = log->l_last_sync_lsn; + if (iclog) + INT_SET(iclog->ic_header.h_tail_lsn, ARCH_CONVERT, tail_lsn); + GRANT_UNLOCK(log, spl); + + return tail_lsn; +} /* xlog_assign_tail_lsn */ + + +/* + * Return the space in the log between the tail and the head. The head + * is passed in the cycle/bytes formal parms. In the special case where + * the reserve head has wrapped passed the tail, this calculation is no + * longer valid. In this case, just return 0 which means there is no space + * in the log. This works for all places where this function is called + * with the reserve head. Of course, if the write head were to ever + * wrap the tail, we should blow up. Rather than catch this case here, + * we depend on other ASSERTions in other parts of the code. XXXmiken + * + * This code also handles the case where the reservation head is behind + * the tail. The details of this case are described below, but the end + * result is that we return the size of the log as the amount of space left. + */ +int +xlog_space_left(xlog_t *log, int cycle, int bytes) +{ + int free_bytes; + int tail_bytes; + int tail_cycle; + + tail_bytes = BBTOB(BLOCK_LSN(log->l_tail_lsn, ARCH_NOCONVERT)); + tail_cycle = CYCLE_LSN(log->l_tail_lsn, ARCH_NOCONVERT); + if ((tail_cycle == cycle) && (bytes >= tail_bytes)) { + free_bytes = log->l_logsize - (bytes - tail_bytes); + } else if ((tail_cycle + 1) < cycle) { + return 0; + } else if (tail_cycle < cycle) { + ASSERT(tail_cycle == (cycle - 1)); + free_bytes = tail_bytes - bytes; + } else { + /* + * The reservation head is behind the tail. + * This can only happen when the AIL is empty so the tail + * is equal to the head and the l_roundoff value in the + * log structure is taking up the difference between the + * reservation head and the tail. The bytes accounted for + * by the l_roundoff field are temporarily 'lost' to the + * reservation mechanism, but they are cleaned up when the + * log buffers that created them are reused. These lost + * bytes are what allow the reservation head to fall behind + * the tail in the case that the log is 'empty'. + * In this case we just want to return the size of the + * log as the amount of space left. + */ + ASSERT((tail_cycle == (cycle + 1)) || + ((bytes + log->l_roundoff) >= tail_bytes)); + free_bytes = log->l_logsize; + } + return free_bytes; +} /* xlog_space_left */ + + +/* + * Log function which is called when an io completes. + * + * The log manager needs its own routine, in order to control what + * happens with the buffer after the write completes. + */ +void +xlog_iodone(xfs_buf_t *bp) +{ + xlog_in_core_t *iclog; + int aborted; + + iclog = XFS_BUF_FSPRIVATE(bp, xlog_in_core_t *); + ASSERT(XFS_BUF_FSPRIVATE2(bp, unsigned long) == (unsigned long) 2); + XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1); + aborted = 0; + + /* + * Race to shutdown the filesystem if we see an error. + */ + if (XFS_BUF_GETERROR(bp)) { +#ifdef DEBUG + xfs_fs_cmn_err(CE_ALERT, iclog->ic_log->l_mp, + "xlog_iodone: log write error buf 0x%p", bp); +#endif + XFS_BUF_STALE(bp); + xfs_force_shutdown(iclog->ic_log->l_mp, XFS_LOG_IO_ERROR); + /* + * This flag will be propagated to the trans-committed + * callback routines to let them know that the log-commit + * didn't succeed. + */ + aborted = XFS_LI_ABORTED; + } else if (iclog->ic_state & XLOG_STATE_IOERROR) { + aborted = XFS_LI_ABORTED; + } + xlog_state_done_syncing(iclog, aborted); + if ( !(XFS_BUF_ISASYNC(bp)) ) { + /* + * Corresponding psema() will be done in bwrite(). If we don't + * vsema() here, panic. + */ + XFS_BUF_V_IODONESEMA(bp); + } +} /* xlog_iodone */ + +/* + * The bdstrat callback function for log bufs. This gives us a central + * place to trap bufs in case we get hit by a log I/O error and need to + * shutdown. Actually, in practice, even when we didn't get a log error, + * we transition the iclogs to IOERROR state *after* flushing all existing + * iclogs to disk. This is because we don't want anymore new transactions to be + * started or completed afterwards. + */ +STATIC int +xlog_bdstrat_cb(struct xfs_buf *bp) +{ + xlog_in_core_t *iclog; + + iclog = XFS_BUF_FSPRIVATE(bp, xlog_in_core_t *); + + if ((iclog->ic_state & XLOG_STATE_IOERROR) == 0) { + /* note for irix bstrat will need struct bdevsw passed + * Fix the following macro if the code ever is merged + */ + XFS_bdstrat(bp); + return 0; + } + + xfs_buftrace("XLOG__BDSTRAT IOERROR", bp); + XFS_BUF_ERROR(bp, EIO); + XFS_BUF_STALE(bp); + xfs_biodone(bp); + return (XFS_ERROR(EIO)); + + +} + +/* + * Return size of each in-core log record buffer. + * + * Low memory machines only get 2 16KB buffers. We don't want to waste + * memory here. However, all other machines get at least 2 32KB buffers. + * The number is hard coded because we don't care about the minimum + * memory size, just 32MB systems. + * + * If the filesystem blocksize is too large, we may need to choose a + * larger size since the directory code currently logs entire blocks. + * XXXmiken XXXcurtis + */ + +STATIC void +xlog_get_iclog_buffer_size(xfs_mount_t *mp, + xlog_t *log) +{ + int size; + +#if defined(DEBUG) || defined(XLOG_NOLOG) + /* + * When logbufs == 0, someone has disabled the log from the FSTAB + * file. This is not a documented feature. We need to set xlog_debug + * to zero (this deactivates the log) and set xlog_devt to the + * appropriate dev_t. Only one filesystem may be affected as such + * since this is just a performance hack to test what we might be able + * to get if the log were not present. + */ + if (mp->m_logbufs == 0) { + xlog_debug = 0; + xlog_devt = log->l_dev; + log->l_iclog_bufs = XLOG_NUM_ICLOGS; + } else +#endif + { + /* + * This is the normal path. If m_logbufs == -1, then the + * admin has chosen to use the system defaults for logbuffers. + */ + if (mp->m_logbufs == -1) + log->l_iclog_bufs = XLOG_NUM_ICLOGS; + else + log->l_iclog_bufs = mp->m_logbufs; + +#if defined(DEBUG) || defined(XLOG_NOLOG) + /* We are reactivating a filesystem after it was active */ + if (log->l_dev == xlog_devt) { + xlog_devt = 1; + xlog_debug = 1; + } +#endif + } + + /* + * We can't allow 64k log record sizes because there isn't enough + * room in the log record header for all the cycle numbers. + */ + ASSERT(XLOG_MAX_RECORD_BSIZE == 32*1024); + + /* + * Buffer size passed in from mount system call. + */ + if (mp->m_logbsize != -1) { + size = log->l_iclog_size = mp->m_logbsize; + log->l_iclog_size_log = 0; + while (size != 1) { + log->l_iclog_size_log++; + size >>= 1; + } + return; + } + + /* + * Special case machines that have less than 32MB of memory. + * All machines with more memory use 32KB buffers. + */ + if (physmem <= btoc(32*1024*1024)) { + /* Don't change; min configuration */ + log->l_iclog_size = XLOG_RECORD_BSIZE; /* 16k */ + log->l_iclog_size_log = XLOG_RECORD_BSHIFT; + } else { + log->l_iclog_size = XLOG_MAX_RECORD_BSIZE; /* 32k */ + log->l_iclog_size_log = XLOG_MAX_RECORD_BSHIFT; + } + + /* + * For 16KB, we use 3 32KB buffers. For 32KB block sizes, we use + * 4 32KB buffers. For 64KB block sizes, we use 8 32KB buffers. + */ + if (mp->m_sb.sb_blocksize >= 16*1024) { + log->l_iclog_size = XLOG_MAX_RECORD_BSIZE; + log->l_iclog_size_log = XLOG_MAX_RECORD_BSHIFT; + if (mp->m_logbufs == -1) { + switch (mp->m_sb.sb_blocksize) { + case 16*1024: /* 16 KB */ + log->l_iclog_bufs = 3; + break; + case 32*1024: /* 32 KB */ + log->l_iclog_bufs = 4; + break; + case 64*1024: /* 64 KB */ + log->l_iclog_bufs = 8; + break; + default: + xlog_panic("XFS: Illegal blocksize"); + break; + } + } + } +} /* xlog_get_iclog_buffer_size */ + + +/* + * This routine initializes some of the log structure for a given mount point. + * Its primary purpose is to fill in enough, so recovery can occur. However, + * some other stuff may be filled in too. + */ +STATIC xlog_t * +xlog_alloc_log(xfs_mount_t *mp, + dev_t log_dev, + xfs_daddr_t blk_offset, + int num_bblks) +{ + xlog_t *log; + xlog_rec_header_t *head; + xlog_in_core_t **iclogp; + xlog_in_core_t *iclog, *prev_iclog=NULL; + xfs_buf_t *bp; + int i; + int iclogsize; + + log = (void *)kmem_zalloc(sizeof(xlog_t), 0); + + log->l_mp = mp; + log->l_dev = log_dev; + log->l_logsize = BBTOB(num_bblks); + log->l_logBBstart = blk_offset; + log->l_logBBsize = num_bblks; + log->l_roundoff = 0; + log->l_covered_state = XLOG_STATE_COVER_IDLE; + log->l_flags |= XLOG_ACTIVE_RECOVERY; + + log->l_prev_block = -1; + ASSIGN_ANY_LSN(log->l_tail_lsn, 1, 0, ARCH_NOCONVERT); + /* log->l_tail_lsn = 0x100000000LL; cycle = 1; current block = 0 */ + log->l_last_sync_lsn = log->l_tail_lsn; + log->l_curr_cycle = 1; /* 0 is bad since this is initial value */ + log->l_curr_block = 0; /* filled in by xlog_recover */ + log->l_grant_reserve_bytes = 0; + log->l_grant_reserve_cycle = 1; + log->l_grant_write_bytes = 0; + log->l_grant_write_cycle = 1; + log->l_quotaoffs_flag = 0; /* XFS_LI_QUOTAOFF logitems */ + + xlog_get_iclog_buffer_size(mp, log); + bp = log->l_xbuf = XFS_getrbuf(0,mp); /* get my locked buffer */ /* mp needed for pagebuf/linux only */ + + XFS_BUF_SET_TARGET(bp, &mp->m_logdev_targ); + XFS_BUF_SET_SIZE(bp, log->l_iclog_size); + XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone); + XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb); + XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1); + ASSERT(XFS_BUF_ISBUSY(log->l_xbuf)); + ASSERT(XFS_BUF_VALUSEMA(log->l_xbuf) <= 0); + spinlock_init(&log->l_icloglock, "iclog"); + spinlock_init(&log->l_grant_lock, "grhead_iclog"); + initnsema(&log->l_flushsema, 0, "ic-flush"); + xlog_state_ticket_alloc(log); /* wait until after icloglock inited */ + + /* log record size must be multiple of BBSIZE; see xlog_rec_header_t */ + ASSERT((XFS_BUF_SIZE(bp) & BBMASK) == 0); + + iclogp = &log->l_iclog; + /* + * The amount of memory to allocate for the iclog structure is + * rather funky due to the way the structure is defined. It is + * done this way so that we can use different sizes for machines + * with different amounts of memory. See the definition of + * xlog_in_core_t in xfs_log_priv.h for details. + */ + iclogsize = sizeof(xlog_in_core_t) - 1 + + log->l_iclog_size - XLOG_HEADER_SIZE; + ASSERT(log->l_iclog_size >= 4096); + for (i=0; i < log->l_iclog_bufs; i++) { + *iclogp = (xlog_in_core_t *) + kmem_zalloc(iclogsize, KM_CACHEALIGN); + + + iclog = *iclogp; + iclog->ic_prev = prev_iclog; + prev_iclog = iclog; + log->l_iclog_bak[i] = (xfs_caddr_t)&(iclog->ic_header); + + head = &iclog->ic_header; + INT_SET(head->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM); + INT_SET(head->h_version, ARCH_CONVERT, 1); + INT_ZERO(head->h_lsn, ARCH_CONVERT); + INT_ZERO(head->h_tail_lsn, ARCH_CONVERT); + /* new fields */ + INT_SET(head->h_fmt, ARCH_CONVERT, XLOG_FMT); + memcpy(&head->h_fs_uuid, &mp->m_sb.sb_uuid, sizeof(uuid_t)); + + bp = iclog->ic_bp = XFS_getrbuf(0,mp); /* my locked buffer */ /* mp need for pagebuf/linux only */ + XFS_BUF_SET_TARGET(bp, &mp->m_logdev_targ); + XFS_BUF_SET_SIZE(bp, log->l_iclog_size); + XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone); + XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb); + XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1); + + iclog->ic_size = XFS_BUF_SIZE(bp) - XLOG_HEADER_SIZE; + iclog->ic_state = XLOG_STATE_ACTIVE; + iclog->ic_log = log; + iclog->ic_refcnt = 0; + iclog->ic_roundoff = 0; + iclog->ic_bwritecnt = 0; + iclog->ic_callback = 0; + iclog->ic_callback_tail = &(iclog->ic_callback); + + ASSERT(XFS_BUF_ISBUSY(iclog->ic_bp)); + ASSERT(XFS_BUF_VALUSEMA(iclog->ic_bp) <= 0); + sv_init(&iclog->ic_forcesema, SV_DEFAULT, "iclog-force"); + + iclogp = &iclog->ic_next; + } + *iclogp = log->l_iclog; /* complete ring */ + log->l_iclog->ic_prev = prev_iclog; /* re-write 1st prev ptr */ + + return log; +} /* xlog_alloc_log */ + + +/* + * Write out the commit record of a transaction associated with the given + * ticket. Return the lsn of the commit record. + */ +STATIC int +xlog_commit_record(xfs_mount_t *mp, + xlog_ticket_t *ticket, + xfs_lsn_t *commitlsnp) +{ + int error; + xfs_log_iovec_t reg[1]; + + reg[0].i_addr = 0; + reg[0].i_len = 0; + + if ((error = xlog_write(mp, reg, 1, ticket, commitlsnp, + XLOG_COMMIT_TRANS))) { + xfs_force_shutdown(mp, XFS_LOG_IO_ERROR); + } + return (error); +} /* xlog_commit_record */ + + +/* + * Push on the buffer cache code if we ever use more than 75% of the on-disk + * log space. This code pushes on the lsn which would supposedly free up + * the 25% which we want to leave free. We may need to adopt a policy which + * pushes on an lsn which is further along in the log once we reach the high + * water mark. In this manner, we would be creating a low water mark. + */ +void +xlog_grant_push_ail(xfs_mount_t *mp, + int need_bytes) +{ + xlog_t *log = mp->m_log; /* pointer to the log */ + xfs_lsn_t tail_lsn; /* lsn of the log tail */ + xfs_lsn_t threshold_lsn = 0; /* lsn we'd like to be at */ + int free_blocks; /* free blocks left to write to */ + int free_bytes; /* free bytes left to write to */ + int threshold_block; /* block in lsn we'd like to be at */ + int threshold_cycle; /* lsn cycle we'd like to be at */ + int spl; + int free_threshold; + + ASSERT(BTOBB(need_bytes) < log->l_logBBsize); + + spl = GRANT_LOCK(log); + free_bytes = xlog_space_left(log, + log->l_grant_reserve_cycle, + log->l_grant_reserve_bytes); + tail_lsn = log->l_tail_lsn; + free_blocks = BTOBBT(free_bytes); + + /* + * Set the threshold for the minimum number of free blocks in the + * log to the maximum of what the caller needs, one quarter of the + * log, and 256 blocks. + */ + free_threshold = BTOBB(need_bytes); + free_threshold = MAX(free_threshold, (log->l_logBBsize >> 2)); + free_threshold = MAX(free_threshold, 256); + if (free_blocks < free_threshold) { + threshold_block = BLOCK_LSN(tail_lsn, ARCH_NOCONVERT) + free_threshold; + threshold_cycle = CYCLE_LSN(tail_lsn, ARCH_NOCONVERT); + if (threshold_block >= log->l_logBBsize) { + threshold_block -= log->l_logBBsize; + threshold_cycle += 1; + } + ASSIGN_ANY_LSN(threshold_lsn, threshold_cycle, + threshold_block, ARCH_NOCONVERT); + + /* Don't pass in an lsn greater than the lsn of the last + * log record known to be on disk. + */ + if (XFS_LSN_CMP_ARCH(threshold_lsn, log->l_last_sync_lsn, ARCH_NOCONVERT) > 0) + threshold_lsn = log->l_last_sync_lsn; + } + GRANT_UNLOCK(log, spl); + + /* + * Get the transaction layer to kick the dirty buffers out to + * disk asynchronously. No point in trying to do this if + * the filesystem is shutting down. + */ + if (threshold_lsn && + !XLOG_FORCED_SHUTDOWN(log)) + xfs_trans_push_ail(mp, threshold_lsn); +} /* xlog_grant_push_ail */ + + +/* + * Flush out the in-core log (iclog) to the on-disk log in a synchronous or + * asynchronous fashion. Previously, we should have moved the current iclog + * ptr in the log to point to the next available iclog. This allows further + * write to continue while this code syncs out an iclog ready to go. + * Before an in-core log can be written out, the data section must be scanned + * to save away the 1st word of each BBSIZE block into the header. We replace + * it with the current cycle count. Each BBSIZE block is tagged with the + * cycle count because there in an implicit assumption that drives will + * guarantee that entire 512 byte blocks get written at once. In other words, + * we can't have part of a 512 byte block written and part not written. By + * tagging each block, we will know which blocks are valid when recovering + * after an unclean shutdown. + * + * This routine is single threaded on the iclog. No other thread can be in + * this routine with the same iclog. Changing contents of iclog can there- + * fore be done without grabbing the state machine lock. Updating the global + * log will require grabbing the lock though. + * + * The entire log manager uses a logical block numbering scheme. Only + * log_sync (and then only bwrite()) know about the fact that the log may + * not start with block zero on a given device. The log block start offset + * is added immediately before calling bwrite(). + */ +int +xlog_sync(xlog_t *log, + xlog_in_core_t *iclog, + uint flags) +{ + xfs_caddr_t dptr; /* pointer to byte sized element */ + xfs_buf_t *bp; + int i; + uint count; /* byte count of bwrite */ + int split = 0; /* split write into two regions */ + int error; + + XFS_STATS_INC(xfsstats.xs_log_writes); + ASSERT(iclog->ic_refcnt == 0); + +#ifdef DEBUG + if (flags != 0 && (flags & XFS_LOG_SYNC) ) + xlog_panic("xlog_sync: illegal flag"); +#endif + + xlog_pack_data(log, iclog); /* put cycle number in every block */ + INT_SET(iclog->ic_header.h_len, ARCH_CONVERT, iclog->ic_offset); /* real byte length */ + + bp = iclog->ic_bp; + ASSERT(XFS_BUF_FSPRIVATE2(bp, unsigned long) == (unsigned long)1); + XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)2); + XFS_BUF_SET_ADDR(bp, BLOCK_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT)); + + /* Round byte count up to a BBSIZE chunk */ + count = BBTOB(BTOBB(iclog->ic_offset)); + if (iclog->ic_offset != count) { + /* count of 0 is already accounted for up in + * xlog_state_sync_all(). Once in this routine, operations + * on the iclog are single threaded. + * + * Difference between rounded up size and size + */ + iclog->ic_roundoff = count - iclog->ic_offset; + log->l_roundoff += iclog->ic_roundoff; + } + + /* Add for LR header */ + count += XLOG_HEADER_SIZE; + XFS_STATS_ADD(xfsstats.xs_log_blocks, BTOBB(count)); + + /* Do we need to split this write into 2 parts? */ + if (XFS_BUF_ADDR(bp) + BTOBB(count) > log->l_logBBsize) { + split = count - (BBTOB(log->l_logBBsize - XFS_BUF_ADDR(bp))); + count = BBTOB(log->l_logBBsize - XFS_BUF_ADDR(bp)); + iclog->ic_bwritecnt = 2; /* split into 2 writes */ + } else { + iclog->ic_bwritecnt = 1; + } + XFS_BUF_SET_PTR(bp, (xfs_caddr_t) &(iclog->ic_header), count); + XFS_BUF_SET_FSPRIVATE(bp, iclog); /* save for later */ + if (flags & XFS_LOG_SYNC){ + XFS_BUF_BUSY(bp); + XFS_BUF_HOLD(bp); + } else { + XFS_BUF_BUSY(bp); + XFS_BUF_ASYNC(bp); + } + + ASSERT(XFS_BUF_ADDR(bp) <= log->l_logBBsize-1); + ASSERT(XFS_BUF_ADDR(bp) + BTOBB(count) <= log->l_logBBsize); + + xlog_verify_iclog(log, iclog, count, B_TRUE); + + /* account for log which doesn't start at block #0 */ + XFS_BUF_SET_ADDR(bp, XFS_BUF_ADDR(bp) + log->l_logBBstart); + /* + * Don't call xfs_bwrite here. We do log-syncs even when the filesystem + * is shutting down. + */ + XFS_BUF_WRITE(bp); + if ((error = XFS_bwrite(bp))) { + xfs_ioerror_alert("xlog_sync", log->l_mp, XFS_BUF_TARGET(bp), + XFS_BUF_ADDR(bp)); + return (error); + } + if (split) { + bp = iclog->ic_log->l_xbuf; + ASSERT(XFS_BUF_FSPRIVATE2(bp, unsigned long) == + (unsigned long)1); + XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)2); + XFS_BUF_SET_ADDR(bp, 0); /* logical 0 */ + XFS_BUF_SET_PTR(bp, (xfs_caddr_t)((__psint_t)&(iclog->ic_header)+ + (__psint_t)count), split); + XFS_BUF_SET_FSPRIVATE(bp, iclog); + XFS_BUF_BUSY(bp); + XFS_BUF_ASYNC(bp); + dptr = XFS_BUF_PTR(bp); + /* + * Bump the cycle numbers at the start of each block + * since this part of the buffer is at the start of + * a new cycle. Watch out for the header magic number + * case, though. + */ + for (i=0; il_logBBsize-1); + ASSERT(XFS_BUF_ADDR(bp) + BTOBB(count) <= log->l_logBBsize); + + /* account for internal log which does't start at block #0 */ + XFS_BUF_SET_ADDR(bp, XFS_BUF_ADDR(bp) + log->l_logBBstart); + XFS_BUF_WRITE(bp); + if ((error = XFS_bwrite(bp))) { + xfs_ioerror_alert("xlog_sync (split)", log->l_mp, + XFS_BUF_TARGET(bp), XFS_BUF_ADDR(bp)); + return (error); + } + } + return (0); +} /* xlog_sync */ + + +/* + * Unallocate a log structure + */ +void +xlog_unalloc_log(xlog_t *log) +{ + xlog_in_core_t *iclog, *next_iclog; + xlog_ticket_t *tic, *next_tic; + int i; + + + iclog = log->l_iclog; + for (i=0; il_iclog_bufs; i++) { + sv_destroy(&iclog->ic_forcesema); + XFS_freerbuf(iclog->ic_bp); +#ifdef DEBUG + if (iclog->ic_trace != NULL) { + ktrace_free(iclog->ic_trace); + } +#endif + next_iclog = iclog->ic_next; + kmem_free(iclog, + (sizeof(xlog_in_core_t) - 1 + + log->l_iclog_size - XLOG_HEADER_SIZE)); + iclog = next_iclog; + } + freesema(&log->l_flushsema); + spinlock_destroy(&log->l_icloglock); + spinlock_destroy(&log->l_grant_lock); + + /* XXXsup take a look at this again. */ + if ((log->l_ticket_cnt != log->l_ticket_tcnt) && + !XLOG_FORCED_SHUTDOWN(log)) { + xfs_fs_cmn_err(CE_WARN, log->l_mp, + "xlog_unalloc_log: (cnt: %d, total: %d)", + log->l_ticket_cnt, log->l_ticket_tcnt); + /* ASSERT(log->l_ticket_cnt == log->l_ticket_tcnt); */ + + } else { + tic = log->l_unmount_free; + while (tic) { + next_tic = tic->t_next; + kmem_free(tic, NBPP); + tic = next_tic; + } + } + XFS_freerbuf(log->l_xbuf); +#ifdef DEBUG + if (log->l_trace != NULL) { + ktrace_free(log->l_trace); + } + if (log->l_grant_trace != NULL) { + ktrace_free(log->l_grant_trace); + } +#endif + log->l_mp->m_log = NULL; + kmem_free(log, sizeof(xlog_t)); +} /* xlog_unalloc_log */ + + +/* + * Write some region out to in-core log + * + * This will be called when writing externally provided regions or when + * writing out a commit record for a given transaction. + * + * General algorithm: + * 1. Find total length of this write. This may include adding to the + * lengths passed in. + * 2. Check whether we violate the tickets reservation. + * 3. While writing to this iclog + * A. Reserve as much space in this iclog as can get + * B. If this is first write, save away start lsn + * C. While writing this region: + * 1. If first write of transaction, write start record + * 2. Write log operation header (header per region) + * 3. Find out if we can fit entire region into this iclog + * 4. Potentially, verify destination bcopy ptr + * 5. Bcopy (partial) region + * 6. If partial copy, release iclog; otherwise, continue + * copying more regions into current iclog + * 4. Mark want sync bit (in simulation mode) + * 5. Release iclog for potential flush to on-disk log. + * + * ERRORS: + * 1. Panic if reservation is overrun. This should never happen since + * reservation amounts are generated internal to the filesystem. + * NOTES: + * 1. Tickets are single threaded data structures. + * 2. The XLOG_END_TRANS & XLOG_CONTINUE_TRANS flags are passed down to the + * syncing routine. When a single log_write region needs to span + * multiple in-core logs, the XLOG_CONTINUE_TRANS bit should be set + * on all log operation writes which don't contain the end of the + * region. The XLOG_END_TRANS bit is used for the in-core log + * operation which contains the end of the continued log_write region. + * 3. When xlog_state_get_iclog_space() grabs the rest of the current iclog, + * we don't really know exactly how much space will be used. As a result, + * we don't update ic_offset until the end when we know exactly how many + * bytes have been written out. + */ +int +xlog_write(xfs_mount_t * mp, + xfs_log_iovec_t reg[], + int nentries, + xfs_log_ticket_t tic, + xfs_lsn_t *start_lsn, + uint flags) +{ + xlog_t *log = mp->m_log; + xlog_ticket_t *ticket = (xlog_ticket_t *)tic; + xlog_op_header_t *logop_head; /* ptr to log operation header */ + xlog_in_core_t *iclog; /* ptr to current in-core log */ + __psint_t ptr; /* copy address into data region */ + int len; /* # xlog_write() bytes 2 still copy */ + int index; /* region index currently copying */ + int log_offset; /* offset (from 0) into data region */ + int start_rec_copy; /* # bytes to copy for start record */ + int partial_copy; /* did we split a region? */ + int partial_copy_len;/* # bytes copied if split region */ + int need_copy; /* # bytes need to bcopy this region */ + int copy_len; /* # bytes actually bcopy'ing */ + int copy_off; /* # bytes from entry start */ + int contwr; /* continued write of in-core log? */ + int firstwr = 0; /* first write of transaction */ + int error; + + partial_copy_len = partial_copy = 0; + + /* Calculate potential maximum space. Each region gets its own + * xlog_op_header_t and may need to be double word aligned. + */ + len = 0; + if (ticket->t_flags & XLOG_TIC_INITED) /* acct for start rec of xact */ + len += sizeof(xlog_op_header_t); + + for (index = 0; index < nentries; index++) { + len += sizeof(xlog_op_header_t); /* each region gets >= 1 */ + len += reg[index].i_len; + } + contwr = *start_lsn = 0; + + if (ticket->t_curr_res < len) { +#ifdef DEBUG + xlog_panic( + "xfs_log_write: reservation ran out. Need to up reservation"); +#else + /* Customer configurable panic */ + xfs_cmn_err(XFS_PTAG_LOGRES, CE_ALERT, mp, + "xfs_log_write: reservation ran out. Need to up reservation"); + /* If we did not panic, shutdown the filesystem */ + xfs_force_shutdown(mp, XFS_CORRUPT_INCORE); +#endif + } else + ticket->t_curr_res -= len; + + for (index = 0; index < nentries; ) { + if ((error = xlog_state_get_iclog_space(log, len, &iclog, ticket, + &contwr, &log_offset))) + return (error); + + ASSERT(log_offset <= iclog->ic_size - 1); + ptr = (__psint_t) &iclog->ic_data[log_offset]; + + /* start_lsn is the first lsn written to. That's all we need. */ + if (! *start_lsn) + *start_lsn = INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT); + + /* This loop writes out as many regions as can fit in the amount + * of space which was allocated by xlog_state_get_iclog_space(). + */ + while (index < nentries) { + ASSERT(reg[index].i_len % sizeof(__int32_t) == 0); + ASSERT((__psint_t)ptr % sizeof(__int32_t) == 0); + start_rec_copy = 0; + + /* If first write for transaction, insert start record. + * We can't be trying to commit if we are inited. We can't + * have any "partial_copy" if we are inited. + */ + if (ticket->t_flags & XLOG_TIC_INITED) { + logop_head = (xlog_op_header_t *)ptr; + INT_SET(logop_head->oh_tid, ARCH_CONVERT, ticket->t_tid); + logop_head->oh_clientid = ticket->t_clientid; + INT_ZERO(logop_head->oh_len, ARCH_CONVERT); + logop_head->oh_flags = XLOG_START_TRANS; + INT_ZERO(logop_head->oh_res2, ARCH_CONVERT); + ticket->t_flags &= ~XLOG_TIC_INITED; /* clear bit */ + firstwr++; /* increment log ops below */ + + start_rec_copy = sizeof(xlog_op_header_t); + xlog_write_adv_cnt(ptr, len, log_offset, start_rec_copy); + } + + /* Copy log operation header directly into data section */ + logop_head = (xlog_op_header_t *)ptr; + INT_SET(logop_head->oh_tid, ARCH_CONVERT, ticket->t_tid); + logop_head->oh_clientid = ticket->t_clientid; + INT_ZERO(logop_head->oh_res2, ARCH_CONVERT); + + /* header copied directly */ + xlog_write_adv_cnt(ptr, len, log_offset, sizeof(xlog_op_header_t)); + + /* are we copying a commit or unmount record? */ + logop_head->oh_flags = flags; + + /* + * We've seen logs corrupted with bad transaction client + * ids. This makes sure that XFS doesn't generate them on. + * Turn this into an EIO and shut down the filesystem. + */ + switch (logop_head->oh_clientid) { + case XFS_TRANSACTION: + case XFS_VOLUME: + case XFS_LOG: + break; + default: + xfs_fs_cmn_err(CE_WARN, mp, + "Bad XFS transaction clientid 0x%x in ticket 0x%p", + logop_head->oh_clientid, tic); + return XFS_ERROR(EIO); + } + + /* Partial write last time? => (partial_copy != 0) + * need_copy is the amount we'd like to copy if everything could + * fit in the current bcopy. + */ + need_copy = reg[index].i_len - partial_copy_len; + + copy_off = partial_copy_len; + if (need_copy <= iclog->ic_size - log_offset) { /*complete write */ + INT_SET(logop_head->oh_len, ARCH_CONVERT, copy_len = need_copy); + if (partial_copy) + logop_head->oh_flags|= (XLOG_END_TRANS|XLOG_WAS_CONT_TRANS); + partial_copy_len = partial_copy = 0; + } else { /* partial write */ + copy_len = iclog->ic_size - log_offset; + INT_SET(logop_head->oh_len, ARCH_CONVERT, copy_len); + logop_head->oh_flags |= XLOG_CONTINUE_TRANS; + if (partial_copy) + logop_head->oh_flags |= XLOG_WAS_CONT_TRANS; + partial_copy_len += copy_len; + partial_copy++; + len += sizeof(xlog_op_header_t); /* from splitting of region */ + /* account for new log op header */ + ticket->t_curr_res -= sizeof(xlog_op_header_t); + } + xlog_verify_dest_ptr(log, ptr); + + /* copy region */ + ASSERT(copy_len >= 0); + bcopy(reg[index].i_addr + copy_off, (xfs_caddr_t)ptr, copy_len); + xlog_write_adv_cnt(ptr, len, log_offset, copy_len); + + /* make copy_len total bytes copied, including headers */ + copy_len += start_rec_copy + sizeof(xlog_op_header_t); + xlog_state_finish_copy(log, iclog, firstwr, (contwr? copy_len : 0)); + firstwr = 0; + if (partial_copy) { /* copied partial region */ + /* already marked WANT_SYNC by xlog_state_get_iclog_space */ + if ((error = xlog_state_release_iclog(log, iclog))) + return (error); + break; /* don't increment index */ + } else { /* copied entire region */ + index++; + partial_copy_len = partial_copy = 0; + + if (iclog->ic_size - log_offset <= sizeof(xlog_op_header_t)) { + xlog_state_want_sync(log, iclog); + if ((error = xlog_state_release_iclog(log, iclog))) + return (error); + if (index == nentries) + return 0; /* we are done */ + else + break; + } + } /* if (partial_copy) */ + } /* while (index < nentries) */ + } /* for (index = 0; index < nentries; ) */ + ASSERT(len == 0); + + return (xlog_state_release_iclog(log, iclog)); +} /* xlog_write */ + + +/***************************************************************************** + * + * State Machine functions + * + ***************************************************************************** + */ + +/* Clean iclogs starting from the head. This ordering must be + * maintained, so an iclog doesn't become ACTIVE beyond one that + * is SYNCING. This is also required to maintain the notion that we use + * a counting semaphore to hold off would be writers to the log when every + * iclog is trying to sync to disk. + * + * State Change: DIRTY -> ACTIVE + */ +void +xlog_state_clean_log(xlog_t *log) +{ + xlog_in_core_t *iclog; + int changed = 0; + + iclog = log->l_iclog; + do { + if (iclog->ic_state == XLOG_STATE_DIRTY) { + iclog->ic_state = XLOG_STATE_ACTIVE; + iclog->ic_offset = 0; + iclog->ic_callback = 0; /* don't need to free */ + /* + * If the number of ops in this iclog indicate it just + * contains the dummy transaction, we can + * change state into IDLE (the second time around). + * Otherwise we should change the state into NEED a dummy. + * We don't need to cover the dummy. + */ + if (!changed && + (INT_GET(iclog->ic_header.h_num_logops, ARCH_CONVERT) == XLOG_COVER_OPS)) { + changed = 1; + } else { /* we have two dirty iclogs so start over */ + /* This could also be num of ops indicates + this is not the dummy going out. */ + changed = 2; + } + INT_ZERO(iclog->ic_header.h_num_logops, ARCH_CONVERT); + bzero(iclog->ic_header.h_cycle_data, + sizeof(iclog->ic_header.h_cycle_data)); + INT_ZERO(iclog->ic_header.h_lsn, ARCH_CONVERT); + } else if (iclog->ic_state == XLOG_STATE_ACTIVE) + /* do nothing */; + else + break; /* stop cleaning */ + iclog = iclog->ic_next; + } while (iclog != log->l_iclog); + + /* log is locked when we are called */ + /* + * Change state for the dummy log recording. + * We usually go to NEED. But we go to NEED2 if the changed indicates + * we are done writing the dummy record. + * If we are done with the second dummy recored (DONE2), then + * we go to IDLE. + */ + if (changed) { + switch (log->l_covered_state) { + case XLOG_STATE_COVER_IDLE: + case XLOG_STATE_COVER_NEED: + case XLOG_STATE_COVER_NEED2: + log->l_covered_state = XLOG_STATE_COVER_NEED; + break; + + case XLOG_STATE_COVER_DONE: + if (changed == 1) + log->l_covered_state = XLOG_STATE_COVER_NEED2; + else + log->l_covered_state = XLOG_STATE_COVER_NEED; + break; + + case XLOG_STATE_COVER_DONE2: + if (changed == 1) + log->l_covered_state = XLOG_STATE_COVER_IDLE; + else + log->l_covered_state = XLOG_STATE_COVER_NEED; + break; + + default: + ASSERT(0); + } + } +} /* xlog_state_clean_log */ + +STATIC xfs_lsn_t +xlog_get_lowest_lsn( + xlog_t *log) +{ + xlog_in_core_t *lsn_log; + xfs_lsn_t lowest_lsn, lsn; + + lsn_log = log->l_iclog; + lowest_lsn = 0; + do { + if (!(lsn_log->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_DIRTY))) { + lsn = INT_GET(lsn_log->ic_header.h_lsn, ARCH_CONVERT); + if ((lsn && !lowest_lsn) || + (XFS_LSN_CMP_ARCH(lsn, lowest_lsn, ARCH_NOCONVERT) < 0)) { + lowest_lsn = lsn; + } + } + lsn_log = lsn_log->ic_next; + } while (lsn_log != log->l_iclog); + return(lowest_lsn); +} + + +STATIC void +xlog_state_do_callback( + xlog_t *log, + int aborted, + xlog_in_core_t *ciclog) +{ + xlog_in_core_t *iclog; + xlog_in_core_t *first_iclog; /* used to know when we've + * processed all iclogs once */ + xfs_log_callback_t *cb, *cb_next; + int spl; + int flushcnt = 0; + xfs_lsn_t lowest_lsn; + int ioerrors; /* counter: iclogs with errors */ + int loopdidcallbacks; /* flag: inner loop did callbacks*/ + int funcdidcallbacks; /* flag: function did callbacks */ + int repeats; /* for issuing console warnings if + * looping too many times */ + + spl = LOG_LOCK(log); + first_iclog = iclog = log->l_iclog; + ioerrors = 0; + funcdidcallbacks = 0; + repeats = 0; + + do { + /* + * Scan all iclogs starting with the one pointed to by the + * log. Reset this starting point each time the log is + * unlocked (during callbacks). + * + * Keep looping through iclogs until one full pass is made + * without running any callbacks. + */ + first_iclog = log->l_iclog; + iclog = log->l_iclog; + loopdidcallbacks = 0; + repeats++; + + do { + + /* skip all iclogs in the ACTIVE & DIRTY states */ + if (iclog->ic_state & + (XLOG_STATE_ACTIVE|XLOG_STATE_DIRTY)) { + iclog = iclog->ic_next; + continue; + } + + /* + * Between marking a filesystem SHUTDOWN and stopping + * the log, we do flush all iclogs to disk (if there + * wasn't a log I/O error). So, we do want things to + * go smoothly in case of just a SHUTDOWN w/o a + * LOG_IO_ERROR. + */ + if (!(iclog->ic_state & XLOG_STATE_IOERROR)) { + /* + * Can only perform callbacks in order. Since + * this iclog is not in the DONE_SYNC/ + * DO_CALLBACK state, we skip the rest and + * just try to clean up. If we set our iclog + * to DO_CALLBACK, we will not process it when + * we retry since a previous iclog is in the + * CALLBACK and the state cannot change since + * we are holding the LOG_LOCK. + */ + if (!(iclog->ic_state & + (XLOG_STATE_DONE_SYNC | + XLOG_STATE_DO_CALLBACK))) { + if (ciclog && (ciclog->ic_state == + XLOG_STATE_DONE_SYNC)) { + ciclog->ic_state = XLOG_STATE_DO_CALLBACK; + } + break; + } + /* + * We now have an iclog that is in either the + * DO_CALLBACK or DONE_SYNC states. The other + * states (WANT_SYNC, SYNCING, or CALLBACK were + * caught by the above if and are going to + * clean (i.e. we aren't doing their callbacks) + * see the above if. + */ + + /* + * We will do one more check here to see if we + * have chased our tail around. + */ + + lowest_lsn = xlog_get_lowest_lsn(log); + if (lowest_lsn && ( + XFS_LSN_CMP_ARCH( + lowest_lsn, + INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT), + ARCH_NOCONVERT + )<0)) { + iclog = iclog->ic_next; + continue; /* Leave this iclog for + * another thread */ + } + + iclog->ic_state = XLOG_STATE_CALLBACK; + + LOG_UNLOCK(log, spl); + + /* l_last_sync_lsn field protected by + * GRANT_LOCK. Don't worry about iclog's lsn. + * No one else can be here except us. + */ + spl = GRANT_LOCK(log); + ASSERT(XFS_LSN_CMP_ARCH( + log->l_last_sync_lsn, + INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT), + ARCH_NOCONVERT + )<=0); + log->l_last_sync_lsn = INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT); + GRANT_UNLOCK(log, spl); + + /* + * Keep processing entries in the callback list + * until we come around and it is empty. We + * need to atomically see that the list is + * empty and change the state to DIRTY so that + * we don't miss any more callbacks being added. + */ + spl = LOG_LOCK(log); + } else { + ioerrors++; + } + cb = iclog->ic_callback; + + while (cb != 0) { + iclog->ic_callback_tail = &(iclog->ic_callback); + iclog->ic_callback = 0; + LOG_UNLOCK(log, spl); + + /* perform callbacks in the order given */ + for (; cb != 0; cb = cb_next) { + cb_next = cb->cb_next; + cb->cb_func(cb->cb_arg, aborted); + } + spl = LOG_LOCK(log); + cb = iclog->ic_callback; + } + + loopdidcallbacks++; + funcdidcallbacks++; + + ASSERT(iclog->ic_callback == 0); + if (!(iclog->ic_state & XLOG_STATE_IOERROR)) + iclog->ic_state = XLOG_STATE_DIRTY; + + /* wake up threads waiting in xfs_log_force() */ + sv_broadcast(&iclog->ic_forcesema); + + iclog = iclog->ic_next; + } while (first_iclog != iclog); + if (repeats && (repeats % 10) == 0) { + xfs_fs_cmn_err(CE_WARN, log->l_mp, + "xlog_state_do_callback: looping %d\n", repeats); + } + } while (!ioerrors && loopdidcallbacks); + + /* + * make one last gasp attempt to see if iclogs are being left in + * limbo.. + */ +#ifdef DEBUG + if (funcdidcallbacks) { + first_iclog = iclog = log->l_iclog; + do { + ASSERT(iclog->ic_state != XLOG_STATE_DO_CALLBACK); + /* + * Terminate the loop if iclogs are found in states + * which will cause other threads to clean up iclogs. + * + * SYNCING - i/o completion will go through logs + * DONE_SYNC - interrupt thread should be waiting for + * LOG_LOCK + * IOERROR - give up hope all ye who enter here + */ + if (iclog->ic_state == XLOG_STATE_SYNCING || + iclog->ic_state == XLOG_STATE_DONE_SYNC || + iclog->ic_state == XLOG_STATE_IOERROR ) + break; + iclog = iclog->ic_next; + } while (first_iclog != iclog); + } +#endif + + /* + * Transition from DIRTY to ACTIVE if applicable. NOP if + * STATE_IOERROR. + */ + xlog_state_clean_log(log); + + if (log->l_iclog->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR)) { + flushcnt = log->l_flushcnt; + log->l_flushcnt = 0; + } + LOG_UNLOCK(log, spl); + while (flushcnt--) + vsema(&log->l_flushsema); +} /* xlog_state_do_callback */ + + +/* + * Finish transitioning this iclog to the dirty state. + * + * Make sure that we completely execute this routine only when this is + * the last call to the iclog. There is a good chance that iclog flushes, + * when we reach the end of the physical log, get turned into 2 separate + * calls to bwrite. Hence, one iclog flush could generate two calls to this + * routine. By using the reference count bwritecnt, we guarantee that only + * the second completion goes through. + * + * Callbacks could take time, so they are done outside the scope of the + * global state machine log lock. Assume that the calls to cvsema won't + * take a long time. At least we know it won't sleep. + */ +void +xlog_state_done_syncing( + xlog_in_core_t *iclog, + int aborted) +{ + int spl; + xlog_t *log = iclog->ic_log; + + spl = LOG_LOCK(log); + + ASSERT(iclog->ic_state == XLOG_STATE_SYNCING || + iclog->ic_state == XLOG_STATE_IOERROR); + ASSERT(iclog->ic_refcnt == 0); + ASSERT(iclog->ic_bwritecnt == 1 || iclog->ic_bwritecnt == 2); + + + /* + * If we got an error, either on the first buffer, or in the case of + * split log writes, on the second, we mark ALL iclogs STATE_IOERROR, + * and none should ever be attempted to be written to disk + * again. + */ + if (iclog->ic_state != XLOG_STATE_IOERROR) { + if (--iclog->ic_bwritecnt == 1) { + LOG_UNLOCK(log, spl); + return; + } + iclog->ic_state = XLOG_STATE_DONE_SYNC; + } + + /* + * Someone could be sleeping on the next iclog even though it is + * in the ACTIVE state. We kick off one thread to force the + * iclog buffer out. + */ + if (iclog->ic_next->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR)) + sv_signal(&iclog->ic_next->ic_forcesema); + LOG_UNLOCK(log, spl); + xlog_state_do_callback(log, aborted, iclog); /* also cleans log */ +} /* xlog_state_done_syncing */ + + +/* + * Update counters atomically now that bcopy is done. + */ +/* ARGSUSED */ +static inline void +xlog_state_finish_copy(xlog_t *log, + xlog_in_core_t *iclog, + int first_write, + int copy_bytes) +{ + int spl; + + spl = LOG_LOCK(log); + + if (first_write) + INT_MOD(iclog->ic_header.h_num_logops, ARCH_CONVERT, +1); + INT_MOD(iclog->ic_header.h_num_logops, ARCH_CONVERT, +1); + iclog->ic_offset += copy_bytes; + + LOG_UNLOCK(log, spl); +} /* xlog_state_finish_copy */ + + + +/* + * If the head of the in-core log ring is not (ACTIVE or DIRTY), then we must + * sleep. The flush semaphore is set to the number of in-core buffers and + * decremented around disk syncing. Therefore, if all buffers are syncing, + * this semaphore will cause new writes to sleep until a sync completes. + * Otherwise, this code just does p() followed by v(). This approximates + * a sleep/wakeup except we can't race. + * + * The in-core logs are used in a circular fashion. They are not used + * out-of-order even when an iclog past the head is free. + * + * return: + * * log_offset where xlog_write() can start writing into the in-core + * log's data space. + * * in-core log pointer to which xlog_write() should write. + * * boolean indicating this is a continued write to an in-core log. + * If this is the last write, then the in-core log's offset field + * needs to be incremented, depending on the amount of data which + * is copied. + */ +int +xlog_state_get_iclog_space(xlog_t *log, + int len, + xlog_in_core_t **iclogp, + xlog_ticket_t *ticket, + int *continued_write, + int *logoffsetp) +{ + int spl; + int log_offset; + xlog_rec_header_t *head; + xlog_in_core_t *iclog; + int error; + + xlog_state_do_callback(log, 0, NULL); /* also cleans log */ + +restart: + spl = LOG_LOCK(log); + if (XLOG_FORCED_SHUTDOWN(log)) { + LOG_UNLOCK(log, spl); + return XFS_ERROR(EIO); + } + + iclog = log->l_iclog; + if (! (iclog->ic_state == XLOG_STATE_ACTIVE)) { + log->l_flushcnt++; + LOG_UNLOCK(log, spl); + xlog_trace_iclog(iclog, XLOG_TRACE_SLEEP_FLUSH); + XFS_STATS_INC(xfsstats.xs_log_noiclogs); + /* Ensure that log writes happen */ + psema(&log->l_flushsema, PINOD); + goto restart; + } + ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE); + head = &iclog->ic_header; + + iclog->ic_refcnt++; /* prevents sync */ + log_offset = iclog->ic_offset; + + /* On the 1st write to an iclog, figure out lsn. This works + * if iclogs marked XLOG_STATE_WANT_SYNC always write out what they are + * committing to. If the offset is set, that's how many blocks + * must be written. + */ + if (log_offset == 0) { + ticket->t_curr_res -= XLOG_HEADER_SIZE; + INT_SET(head->h_cycle, ARCH_CONVERT, log->l_curr_cycle); + ASSIGN_LSN(head->h_lsn, log, ARCH_CONVERT); + ASSERT(log->l_curr_block >= 0); + + /* round off error from last write with this iclog */ + ticket->t_curr_res -= iclog->ic_roundoff; + log->l_roundoff -= iclog->ic_roundoff; + iclog->ic_roundoff = 0; + } + + /* If there is enough room to write everything, then do it. Otherwise, + * claim the rest of the region and make sure the XLOG_STATE_WANT_SYNC + * bit is on, so this will get flushed out. Don't update ic_offset + * until you know exactly how many bytes get copied. Therefore, wait + * until later to update ic_offset. + * + * xlog_write() algorithm assumes that at least 2 xlog_op_header_t's + * can fit into remaining data section. + */ + if (iclog->ic_size - iclog->ic_offset < 2*sizeof(xlog_op_header_t)) { + xlog_state_switch_iclogs(log, iclog, iclog->ic_size); + + /* If I'm the only one writing to this iclog, sync it to disk */ + if (iclog->ic_refcnt == 1) { + LOG_UNLOCK(log, spl); + if ((error = xlog_state_release_iclog(log, iclog))) + return (error); + } else { + iclog->ic_refcnt--; + LOG_UNLOCK(log, spl); + } + goto restart; + } + + /* Do we have enough room to write the full amount in the remainder + * of this iclog? Or must we continue a write on the next iclog and + * mark this iclog as completely taken? In the case where we switch + * iclogs (to mark it taken), this particular iclog will release/sync + * to disk in xlog_write(). + */ + if (len <= iclog->ic_size - iclog->ic_offset) { + *continued_write = 0; + iclog->ic_offset += len; + } else { + *continued_write = 1; + xlog_state_switch_iclogs(log, iclog, iclog->ic_size); + } + *iclogp = iclog; + + ASSERT(iclog->ic_offset <= iclog->ic_size); + LOG_UNLOCK(log, spl); + + *logoffsetp = log_offset; + return 0; +} /* xlog_state_get_iclog_space */ + +/* + * Atomically get the log space required for a log ticket. + * + * Once a ticket gets put onto the reserveq, it will only return after + * the needed reservation is satisfied. + */ +STATIC int +xlog_grant_log_space(xlog_t *log, + xlog_ticket_t *tic) +{ + int free_bytes; + int need_bytes; + int spl; +#ifdef DEBUG + xfs_lsn_t tail_lsn; +#endif + + +#ifdef DEBUG + if (log->l_flags & XLOG_ACTIVE_RECOVERY) + panic("grant Recovery problem"); +#endif + + /* Is there space or do we need to sleep? */ + spl = GRANT_LOCK(log); + xlog_trace_loggrant(log, tic, "xlog_grant_log_space: enter"); + + /* something is already sleeping; insert new transaction at end */ + if (log->l_reserve_headq) { + XLOG_INS_TICKETQ(log->l_reserve_headq, tic); + xlog_trace_loggrant(log, tic, + "xlog_grant_log_space: sleep 1"); + /* + * Gotta check this before going to sleep, while we're + * holding the grant lock. + */ + if (XLOG_FORCED_SHUTDOWN(log)) + goto error_return; + + XFS_STATS_INC(xfsstats.xs_sleep_logspace); + sv_wait(&tic->t_sema, PINOD|PLTWAIT, &log->l_grant_lock, spl); + /* + * If we got an error, and the filesystem is shutting down, + * we'll catch it down below. So just continue... + */ + xlog_trace_loggrant(log, tic, + "xlog_grant_log_space: wake 1"); + spl = GRANT_LOCK(log); + } + if (tic->t_flags & XFS_LOG_PERM_RESERV) + need_bytes = tic->t_unit_res*tic->t_ocnt; + else + need_bytes = tic->t_unit_res; + +redo: + if (XLOG_FORCED_SHUTDOWN(log)) + goto error_return; + + free_bytes = xlog_space_left(log, log->l_grant_reserve_cycle, + log->l_grant_reserve_bytes); + if (free_bytes < need_bytes) { + if ((tic->t_flags & XLOG_TIC_IN_Q) == 0) + XLOG_INS_TICKETQ(log->l_reserve_headq, tic); + xlog_trace_loggrant(log, tic, + "xlog_grant_log_space: sleep 2"); + XFS_STATS_INC(xfsstats.xs_sleep_logspace); + sv_wait(&tic->t_sema, PINOD|PLTWAIT, &log->l_grant_lock, spl); + + if (XLOG_FORCED_SHUTDOWN(log)) { + spl = GRANT_LOCK(log); + goto error_return; + } + + xlog_trace_loggrant(log, tic, + "xlog_grant_log_space: wake 2"); + xlog_grant_push_ail(log->l_mp, need_bytes); + spl = GRANT_LOCK(log); + goto redo; + } else if (tic->t_flags & XLOG_TIC_IN_Q) + XLOG_DEL_TICKETQ(log->l_reserve_headq, tic); + + /* we've got enough space */ + XLOG_GRANT_ADD_SPACE(log, need_bytes, 'w'); + XLOG_GRANT_ADD_SPACE(log, need_bytes, 'r'); +#ifdef DEBUG + tail_lsn = log->l_tail_lsn; + /* + * Check to make sure the grant write head didn't just over lap the + * tail. If the cycles are the same, we can't be overlapping. + * Otherwise, make sure that the cycles differ by exactly one and + * check the byte count. + */ + if (CYCLE_LSN(tail_lsn, ARCH_NOCONVERT) != log->l_grant_write_cycle) { + ASSERT(log->l_grant_write_cycle-1 == CYCLE_LSN(tail_lsn, ARCH_NOCONVERT)); + ASSERT(log->l_grant_write_bytes <= BBTOB(BLOCK_LSN(tail_lsn, ARCH_NOCONVERT))); + } +#endif + xlog_trace_loggrant(log, tic, "xlog_grant_log_space: exit"); + xlog_verify_grant_head(log, 1); + GRANT_UNLOCK(log, spl); + return 0; + + error_return: + if (tic->t_flags & XLOG_TIC_IN_Q) + XLOG_DEL_TICKETQ(log->l_reserve_headq, tic); + xlog_trace_loggrant(log, tic, "xlog_grant_log_space: err_ret"); + /* + * If we are failing, make sure the ticket doesn't have any + * current reservations. We don't want to add this back when + * the ticket/transaction gets cancelled. + */ + tic->t_curr_res = 0; + tic->t_cnt = 0; /* ungrant will give back unit_res * t_cnt. */ + GRANT_UNLOCK(log, spl); + return XFS_ERROR(EIO); +} /* xlog_grant_log_space */ + + +/* + * Replenish the byte reservation required by moving the grant write head. + * + * + */ +STATIC int +xlog_regrant_write_log_space(xlog_t *log, + xlog_ticket_t *tic) +{ + int spl; + int free_bytes, need_bytes; + xlog_ticket_t *ntic; +#ifdef DEBUG + xfs_lsn_t tail_lsn; +#endif + + tic->t_curr_res = tic->t_unit_res; + + if (tic->t_cnt > 0) + return (0); + +#ifdef DEBUG + if (log->l_flags & XLOG_ACTIVE_RECOVERY) + panic("regrant Recovery problem"); +#endif + + spl = GRANT_LOCK(log); + xlog_trace_loggrant(log, tic, "xlog_regrant_write_log_space: enter"); + + if (XLOG_FORCED_SHUTDOWN(log)) + goto error_return; + + /* If there are other waiters on the queue then give them a + * chance at logspace before us. Wake up the first waiters, + * if we do not wake up all the waiters then go to sleep waiting + * for more free space, otherwise try to get some space for + * this transaction. + */ + + if ((ntic = log->l_write_headq)) { + free_bytes = xlog_space_left(log, log->l_grant_write_cycle, + log->l_grant_write_bytes); + do { + ASSERT(ntic->t_flags & XLOG_TIC_PERM_RESERV); + + if (free_bytes < ntic->t_unit_res) + break; + free_bytes -= ntic->t_unit_res; + sv_signal(&ntic->t_sema); + ntic = ntic->t_next; + } while (ntic != log->l_write_headq); + + if (ntic != log->l_write_headq) { + if ((tic->t_flags & XLOG_TIC_IN_Q) == 0) + XLOG_INS_TICKETQ(log->l_write_headq, tic); + + xlog_trace_loggrant(log, tic, + "xlog_regrant_write_log_space: sleep 1"); + XFS_STATS_INC(xfsstats.xs_sleep_logspace); + sv_wait(&tic->t_sema, PINOD|PLTWAIT, + &log->l_grant_lock, spl); + + /* If we're shutting down, this tic is already + * off the queue */ + if (XLOG_FORCED_SHUTDOWN(log)) { + spl = GRANT_LOCK(log); + goto error_return; + } + + xlog_trace_loggrant(log, tic, + "xlog_regrant_write_log_space: wake 1"); + xlog_grant_push_ail(log->l_mp, tic->t_unit_res); + spl = GRANT_LOCK(log); + } + } + + need_bytes = tic->t_unit_res; + +redo: + if (XLOG_FORCED_SHUTDOWN(log)) + goto error_return; + + free_bytes = xlog_space_left(log, log->l_grant_write_cycle, + log->l_grant_write_bytes); + if (free_bytes < need_bytes) { + if ((tic->t_flags & XLOG_TIC_IN_Q) == 0) + XLOG_INS_TICKETQ(log->l_write_headq, tic); + XFS_STATS_INC(xfsstats.xs_sleep_logspace); + sv_wait(&tic->t_sema, PINOD|PLTWAIT, &log->l_grant_lock, spl); + + /* If we're shutting down, this tic is already off the queue */ + if (XLOG_FORCED_SHUTDOWN(log)) { + spl = GRANT_LOCK(log); + goto error_return; + } + + xlog_trace_loggrant(log, tic, + "xlog_regrant_write_log_space: wake 2"); + xlog_grant_push_ail(log->l_mp, need_bytes); + spl = GRANT_LOCK(log); + goto redo; + } else if (tic->t_flags & XLOG_TIC_IN_Q) + XLOG_DEL_TICKETQ(log->l_write_headq, tic); + + XLOG_GRANT_ADD_SPACE(log, need_bytes, 'w'); /* we've got enough space */ +#ifdef DEBUG + tail_lsn = log->l_tail_lsn; + if (CYCLE_LSN(tail_lsn, ARCH_NOCONVERT) != log->l_grant_write_cycle) { + ASSERT(log->l_grant_write_cycle-1 == CYCLE_LSN(tail_lsn, ARCH_NOCONVERT)); + ASSERT(log->l_grant_write_bytes <= BBTOB(BLOCK_LSN(tail_lsn, ARCH_NOCONVERT))); + } +#endif + + xlog_trace_loggrant(log, tic, "xlog_regrant_write_log_space: exit"); + xlog_verify_grant_head(log, 1); + GRANT_UNLOCK(log, spl); + return (0); + + + error_return: + if (tic->t_flags & XLOG_TIC_IN_Q) + XLOG_DEL_TICKETQ(log->l_reserve_headq, tic); + xlog_trace_loggrant(log, tic, "xlog_regrant_write_log_space: err_ret"); + /* + * If we are failing, make sure the ticket doesn't have any + * current reservations. We don't want to add this back when + * the ticket/transaction gets cancelled. + */ + tic->t_curr_res = 0; + tic->t_cnt = 0; /* ungrant will give back unit_res * t_cnt. */ + GRANT_UNLOCK(log, spl); + return XFS_ERROR(EIO); +} /* xlog_regrant_write_log_space */ + + +/* The first cnt-1 times through here we don't need to + * move the grant write head because the permanent + * reservation has reserved cnt times the unit amount. + * Release part of current permanent unit reservation and + * reset current reservation to be one units worth. Also + * move grant reservation head forward. + */ +STATIC void +xlog_regrant_reserve_log_space(xlog_t *log, + xlog_ticket_t *ticket) +{ + int spl; + + xlog_trace_loggrant(log, ticket, + "xlog_regrant_reserve_log_space: enter"); + if (ticket->t_cnt > 0) + ticket->t_cnt--; + + spl = GRANT_LOCK(log); + XLOG_GRANT_SUB_SPACE(log, ticket->t_curr_res, 'w'); + XLOG_GRANT_SUB_SPACE(log, ticket->t_curr_res, 'r'); + ticket->t_curr_res = ticket->t_unit_res; + xlog_trace_loggrant(log, ticket, + "xlog_regrant_reserve_log_space: sub current res"); + xlog_verify_grant_head(log, 1); + + /* just return if we still have some of the pre-reserved space */ + if (ticket->t_cnt > 0) { + GRANT_UNLOCK(log, spl); + return; + } + + XLOG_GRANT_ADD_SPACE(log, ticket->t_unit_res, 'r'); + xlog_trace_loggrant(log, ticket, + "xlog_regrant_reserve_log_space: exit"); + xlog_verify_grant_head(log, 0); + GRANT_UNLOCK(log, spl); + ticket->t_curr_res = ticket->t_unit_res; +} /* xlog_regrant_reserve_log_space */ + + +/* + * Give back the space left from a reservation. + * + * All the information we need to make a correct determination of space left + * is present. For non-permanent reservations, things are quite easy. The + * count should have been decremented to zero. We only need to deal with the + * space remaining in the current reservation part of the ticket. If the + * ticket contains a permanent reservation, there may be left over space which + * needs to be released. A count of N means that N-1 refills of the current + * reservation can be done before we need to ask for more space. The first + * one goes to fill up the first current reservation. Once we run out of + * space, the count will stay at zero and the only space remaining will be + * in the current reservation field. + */ +STATIC void +xlog_ungrant_log_space(xlog_t *log, + xlog_ticket_t *ticket) +{ + int spl; + + if (ticket->t_cnt > 0) + ticket->t_cnt--; + + spl = GRANT_LOCK(log); + xlog_trace_loggrant(log, ticket, "xlog_ungrant_log_space: enter"); + + XLOG_GRANT_SUB_SPACE(log, ticket->t_curr_res, 'w'); + XLOG_GRANT_SUB_SPACE(log, ticket->t_curr_res, 'r'); + + xlog_trace_loggrant(log, ticket, "xlog_ungrant_log_space: sub current"); + + /* If this is a permanent reservation ticket, we may be able to free + * up more space based on the remaining count. + */ + if (ticket->t_cnt > 0) { + ASSERT(ticket->t_flags & XLOG_TIC_PERM_RESERV); + XLOG_GRANT_SUB_SPACE(log, ticket->t_unit_res*ticket->t_cnt,'w'); + XLOG_GRANT_SUB_SPACE(log, ticket->t_unit_res*ticket->t_cnt,'r'); + } + + xlog_trace_loggrant(log, ticket, "xlog_ungrant_log_space: exit"); + xlog_verify_grant_head(log, 1); + GRANT_UNLOCK(log, spl); + xfs_log_move_tail(log->l_mp, 1); +} /* xlog_ungrant_log_space */ + + +/* + * If the lsn is not found or the iclog with the lsn is in the callback + * state, we need to call the function directly. This is done outside + * this function's scope. Otherwise, we insert the callback at the end + * of the iclog's callback list. + */ +int +xlog_state_lsn_is_synced(xlog_t *log, + xfs_lsn_t lsn, + xfs_log_callback_t *cb, + int *abortflg) +{ + xlog_in_core_t *iclog; + int spl; + int lsn_is_synced = 1; + + *abortflg = 0; + spl = LOG_LOCK(log); + + iclog = log->l_iclog; + do { + if (INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT) != lsn) { + iclog = iclog->ic_next; + continue; + } else { + if (iclog->ic_state & XLOG_STATE_DIRTY) /* call it*/ + break; + + if (iclog->ic_state & XLOG_STATE_IOERROR) { + *abortflg = XFS_LI_ABORTED; + break; + } + /* insert callback onto end of list */ + cb->cb_next = 0; + *(iclog->ic_callback_tail) = cb; + iclog->ic_callback_tail = &(cb->cb_next); + lsn_is_synced = 0; + break; + } + } while (iclog != log->l_iclog); + + LOG_UNLOCK(log, spl); + return lsn_is_synced; +} /* xlog_state_lsn_is_synced */ + + +/* + * Atomically put back used ticket. + */ +void +xlog_state_put_ticket(xlog_t *log, + xlog_ticket_t *tic) +{ + int spl; + + spl = LOG_LOCK(log); + xlog_ticket_put(log, tic); + LOG_UNLOCK(log, spl); +} /* xlog_state_put_ticket */ + + +/* + * Flush iclog to disk if this is the last reference to the given iclog and + * the WANT_SYNC bit is set. + * + * When this function is entered, the iclog is not necessarily in the + * WANT_SYNC state. It may be sitting around waiting to get filled. + * + * + */ +int +xlog_state_release_iclog(xlog_t *log, + xlog_in_core_t *iclog) +{ + int spl; + int sync = 0; /* do we sync? */ + + xlog_assign_tail_lsn(log->l_mp, 0); + + spl = LOG_LOCK(log); + + if (iclog->ic_state & XLOG_STATE_IOERROR) { + LOG_UNLOCK(log, spl); + return XFS_ERROR(EIO); + } + + ASSERT(iclog->ic_refcnt > 0); + ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE || + iclog->ic_state == XLOG_STATE_WANT_SYNC); + + if (--iclog->ic_refcnt == 0 && + iclog->ic_state == XLOG_STATE_WANT_SYNC) { + sync++; + iclog->ic_state = XLOG_STATE_SYNCING; + INT_SET(iclog->ic_header.h_tail_lsn, ARCH_CONVERT, log->l_tail_lsn); + xlog_verify_tail_lsn(log, iclog, log->l_tail_lsn); + /* cycle incremented when incrementing curr_block */ + } + + LOG_UNLOCK(log, spl); + + /* + * We let the log lock go, so it's possible that we hit a log I/O + * error or someother SHUTDOWN condition that marks the iclog + * as XLOG_STATE_IOERROR before the bwrite. However, we know that + * this iclog has consistent data, so we ignore IOERROR + * flags after this point. + */ + if (sync) { + return (xlog_sync(log, iclog, 0)); + } + return (0); + +} /* xlog_state_release_iclog */ + + +/* + * This routine will mark the current iclog in the ring as WANT_SYNC + * and move the current iclog pointer to the next iclog in the ring. + * When this routine is called from xlog_state_get_iclog_space(), the + * exact size of the iclog has not yet been determined. All we know is + * that every data block. We have run out of space in this log record. + */ +STATIC void +xlog_state_switch_iclogs(xlog_t *log, + xlog_in_core_t *iclog, + int eventual_size) +{ + ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE); + if (!eventual_size) + eventual_size = iclog->ic_offset; + iclog->ic_state = XLOG_STATE_WANT_SYNC; + INT_SET(iclog->ic_header.h_prev_block, ARCH_CONVERT, log->l_prev_block); + log->l_prev_block = log->l_curr_block; + log->l_prev_cycle = log->l_curr_cycle; + + /* roll log?: ic_offset changed later */ + log->l_curr_block += BTOBB(eventual_size)+1; + if (log->l_curr_block >= log->l_logBBsize) { + log->l_curr_cycle++; + if (log->l_curr_cycle == XLOG_HEADER_MAGIC_NUM) + log->l_curr_cycle++; + log->l_curr_block -= log->l_logBBsize; + ASSERT(log->l_curr_block >= 0); + } + ASSERT(iclog == log->l_iclog); + log->l_iclog = iclog->ic_next; +} /* xlog_state_switch_iclogs */ + + +/* + * Write out all data in the in-core log as of this exact moment in time. + * + * Data may be written to the in-core log during this call. However, + * we don't guarantee this data will be written out. A change from past + * implementation means this routine will *not* write out zero length LRs. + * + * Basically, we try and perform an intelligent scan of the in-core logs. + * If we determine there is no flushable data, we just return. There is no + * flushable data if: + * + * 1. the current iclog is active and has no data; the previous iclog + * is in the active or dirty state. + * 2. the current iclog is drity, and the previous iclog is in the + * active or dirty state. + * + * We may sleep (call psema) if: + * + * 1. the current iclog is not in the active nor dirty state. + * 2. the current iclog dirty, and the previous iclog is not in the + * active nor dirty state. + * 3. the current iclog is active, and there is another thread writing + * to this particular iclog. + * 4. a) the current iclog is active and has no other writers + * b) when we return from flushing out this iclog, it is still + * not in the active nor dirty state. + */ +STATIC int +xlog_state_sync_all(xlog_t *log, uint flags) +{ + xlog_in_core_t *iclog; + xfs_lsn_t lsn; + int spl; + + spl = LOG_LOCK(log); + + iclog = log->l_iclog; + if (iclog->ic_state & XLOG_STATE_IOERROR) { + LOG_UNLOCK(log, spl); + return XFS_ERROR(EIO); + } + + /* If the head iclog is not active nor dirty, we just attach + * ourselves to the head and go to sleep. + */ + if (iclog->ic_state == XLOG_STATE_ACTIVE || + iclog->ic_state == XLOG_STATE_DIRTY) { + /* + * If the head is dirty or (active and empty), then + * we need to look at the previous iclog. If the previous + * iclog is active or dirty we are done. There is nothing + * to sync out. Otherwise, we attach ourselves to the + * previous iclog and go to sleep. + */ + if (iclog->ic_state == XLOG_STATE_DIRTY || + (iclog->ic_refcnt == 0 && iclog->ic_offset == 0)) { + iclog = iclog->ic_prev; + if (iclog->ic_state == XLOG_STATE_ACTIVE || + iclog->ic_state == XLOG_STATE_DIRTY) + goto no_sleep; + else + goto maybe_sleep; + } else { + if (iclog->ic_refcnt == 0) { + /* We are the only one with access to this + * iclog. Flush it out now. There should + * be a roundoff of zero to show that someone + * has already taken care of the roundoff from + * the previous sync. + */ + ASSERT(iclog->ic_roundoff == 0); + iclog->ic_refcnt++; + lsn = INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT); + xlog_state_switch_iclogs(log, iclog, 0); + LOG_UNLOCK(log, spl); + + if (xlog_state_release_iclog(log, iclog)) + return XFS_ERROR(EIO); + spl = LOG_LOCK(log); + if (INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT) == lsn && + iclog->ic_state != XLOG_STATE_DIRTY) + goto maybe_sleep; + else + goto no_sleep; + } else { + /* Someone else is writing to this iclog. + * Use its call to flush out the data. However, + * the other thread may not force out this LR, + * so we mark it WANT_SYNC. + */ + xlog_state_switch_iclogs(log, iclog, 0); + goto maybe_sleep; + } + } + } + + /* By the time we come around again, the iclog could've been filled + * which would give it another lsn. If we have a new lsn, just + * return because the relevant data has been flushed. + */ +maybe_sleep: + if (flags & XFS_LOG_SYNC) { + /* + * We must check if we're shutting down here, before + * we wait, while we're holding the LOG_LOCK. + * Then we check again after waking up, in case our + * sleep was disturbed by a bad news. + */ + if (iclog->ic_state & XLOG_STATE_IOERROR) { + LOG_UNLOCK(log, spl); + return XFS_ERROR(EIO); + } + XFS_STATS_INC(xfsstats.xs_log_force_sleep); + sv_wait(&iclog->ic_forcesema, PINOD, &log->l_icloglock, spl); + /* + * No need to grab the log lock here since we're + * only deciding whether or not to return EIO + * and the memory read should be atomic. + */ + if (iclog->ic_state & XLOG_STATE_IOERROR) + return XFS_ERROR(EIO); + + } else { + +no_sleep: + LOG_UNLOCK(log, spl); + } + return 0; +} /* xlog_state_sync_all */ + + +/* + * Used by code which implements synchronous log forces. + * + * Find in-core log with lsn. + * If it is in the DIRTY state, just return. + * If it is in the ACTIVE state, move the in-core log into the WANT_SYNC + * state and go to sleep or return. + * If it is in any other state, go to sleep or return. + * + * If filesystem activity goes to zero, the iclog will get flushed only by + * bdflush(). + */ +int +xlog_state_sync(xlog_t *log, + xfs_lsn_t lsn, + uint flags) +{ + xlog_in_core_t *iclog; + int spl; + int already_slept = 0; + + +try_again: + spl = LOG_LOCK(log); + iclog = log->l_iclog; + + if (iclog->ic_state & XLOG_STATE_IOERROR) { + LOG_UNLOCK(log, spl); + return XFS_ERROR(EIO); + } + + do { + if (INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT) != lsn) { + iclog = iclog->ic_next; + continue; + } + + if (iclog->ic_state == XLOG_STATE_DIRTY) { + LOG_UNLOCK(log, spl); + return 0; + } + + if (iclog->ic_state == XLOG_STATE_ACTIVE) { + /* + * We sleep here if we haven't already slept (e.g. + * this is the first time we've looked at the correct + * iclog buf) and the buffer before us is going to + * be sync'ed. We have to do that to ensure that the + * log records go out in the proper order. When it's + * done, someone waiting on this buffer will be woken up + * (maybe us) to flush this buffer out. + * + * Otherwise, we mark the buffer WANT_SYNC, and bump + * up the refcnt so we can release the log (which drops + * the ref count). The state switch keeps new transaction + * commits from using this buffer. When the current commits + * finish writing into the buffer, the refcount will drop to + * zero and the buffer will go out then. + */ + if (!already_slept && + (iclog->ic_prev->ic_state & (XLOG_STATE_WANT_SYNC | + XLOG_STATE_SYNCING))) { + ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR)); + XFS_STATS_INC(xfsstats.xs_log_force_sleep); + sv_wait(&iclog->ic_prev->ic_forcesema, PSWP, + &log->l_icloglock, spl); + already_slept = 1; + goto try_again; + } else { + iclog->ic_refcnt++; + xlog_state_switch_iclogs(log, iclog, 0); + LOG_UNLOCK(log, spl); + if (xlog_state_release_iclog(log, iclog)) + return XFS_ERROR(EIO); + spl = LOG_LOCK(log); + } + } + + if ((flags & XFS_LOG_SYNC) && /* sleep */ + !(iclog->ic_state & (XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY))) { + + /* + * Don't wait on the forcesema if we know that we've + * gotten a log write error. + */ + if (iclog->ic_state & XLOG_STATE_IOERROR) { + LOG_UNLOCK(log, spl); + return XFS_ERROR(EIO); + } + XFS_STATS_INC(xfsstats.xs_log_force_sleep); + sv_wait(&iclog->ic_forcesema, PSWP, &log->l_icloglock, spl); + /* + * No need to grab the log lock here since we're + * only deciding whether or not to return EIO + * and the memory read should be atomic. + */ + if (iclog->ic_state & XLOG_STATE_IOERROR) + return XFS_ERROR(EIO); + } else { /* just return */ + LOG_UNLOCK(log, spl); + } + return 0; + + } while (iclog != log->l_iclog); + + LOG_UNLOCK(log, spl); + return (0); +} /* xlog_state_sync */ + + +/* + * Called when we want to mark the current iclog as being ready to sync to + * disk. + */ +void +xlog_state_want_sync(xlog_t *log, xlog_in_core_t *iclog) +{ + int spl; + + spl = LOG_LOCK(log); + + if (iclog->ic_state == XLOG_STATE_ACTIVE) { + xlog_state_switch_iclogs(log, iclog, 0); + } else { + ASSERT(iclog->ic_state & + (XLOG_STATE_WANT_SYNC|XLOG_STATE_IOERROR)); + } + + LOG_UNLOCK(log, spl); +} /* xlog_state_want_sync */ + + + +/***************************************************************************** + * + * TICKET functions + * + ***************************************************************************** + */ + +/* + * Algorithm doesn't take into account page size. ;-( + */ +STATIC void +xlog_state_ticket_alloc(xlog_t *log) +{ + xlog_ticket_t *t_list; + xlog_ticket_t *next; + xfs_caddr_t buf; + int spl; + uint i = (NBPP / sizeof(xlog_ticket_t)) - 2; + + /* + * The kmem_zalloc may sleep, so we shouldn't be holding the + * global lock. XXXmiken: may want to use zone allocator. + */ + buf = (xfs_caddr_t) kmem_zalloc(NBPP, 0); + + spl = LOG_LOCK(log); + + /* Attach 1st ticket to Q, so we can keep track of allocated memory */ + t_list = (xlog_ticket_t *)buf; + t_list->t_next = log->l_unmount_free; + log->l_unmount_free = t_list++; + log->l_ticket_cnt++; + log->l_ticket_tcnt++; + + /* Next ticket becomes first ticket attached to ticket free list */ + if (log->l_freelist != NULL) { + ASSERT(log->l_tail != NULL); + log->l_tail->t_next = t_list; + } else { + log->l_freelist = t_list; + } + log->l_ticket_cnt++; + log->l_ticket_tcnt++; + + /* Cycle through rest of alloc'ed memory, building up free Q */ + for ( ; i > 0; i--) { + next = t_list + 1; + t_list->t_next = next; + t_list = next; + log->l_ticket_cnt++; + log->l_ticket_tcnt++; + } + t_list->t_next = 0; + log->l_tail = t_list; + LOG_UNLOCK(log, spl); +} /* xlog_state_ticket_alloc */ + + +/* + * Put ticket into free list + * + * Assumption: log lock is held around this call. + */ +STATIC void +xlog_ticket_put(xlog_t *log, + xlog_ticket_t *ticket) +{ + sv_destroy(&ticket->t_sema); + + /* + * Don't think caching will make that much difference. It's + * more important to make debug easier. + */ +#if 0 + /* real code will want to use LIFO for caching */ + ticket->t_next = log->l_freelist; + log->l_freelist = ticket; + /* no need to clear fields */ +#else + /* When we debug, it is easier if tickets are cycled */ + ticket->t_next = 0; + if (log->l_tail != 0) { + log->l_tail->t_next = ticket; + } else { + ASSERT(log->l_freelist == 0); + log->l_freelist = ticket; + } + log->l_tail = ticket; +#endif /* DEBUG */ + log->l_ticket_cnt++; +} /* xlog_ticket_put */ + + +/* + * Grab ticket off freelist or allocation some more + */ +xlog_ticket_t * +xlog_ticket_get(xlog_t *log, + int unit_bytes, + int cnt, + char client, + uint xflags) +{ + xlog_ticket_t *tic; + int spl; + + alloc: + if (log->l_freelist == NULL) + xlog_state_ticket_alloc(log); /* potentially sleep */ + + spl = LOG_LOCK(log); + if (log->l_freelist == NULL) { + LOG_UNLOCK(log, spl); + goto alloc; + } + tic = log->l_freelist; + log->l_freelist = tic->t_next; + if (log->l_freelist == NULL) + log->l_tail = NULL; + log->l_ticket_cnt--; + LOG_UNLOCK(log, spl); + + /* + * Permanent reservations have up to 'cnt'-1 active log operations + * in the log. A unit in this case is the amount of space for one + * of these log operations. Normal reservations have a cnt of 1 + * and their unit amount is the total amount of space required. + * The following line of code adds one log record header length + * for each part of an operation which may fall on a different + * log record. + * + * One more XLOG_HEADER_SIZE is added to account for possible + * round off errors when syncing a LR to disk. The bytes are + * subtracted if the thread using this ticket is the first writer + * to a new LR. + * + * We add an extra log header for the possibility that the commit + * record is the first data written to a new log record. In this + * case it is separate from the rest of the transaction data and + * will be charged for the log record header. + */ + unit_bytes += XLOG_HEADER_SIZE * (XLOG_BTOLRBB(unit_bytes) + 2); + + tic->t_unit_res = unit_bytes; + tic->t_curr_res = unit_bytes; + tic->t_cnt = cnt; + tic->t_ocnt = cnt; + tic->t_tid = (xlog_tid_t)((__psint_t)tic & 0xffffffff); + tic->t_clientid = client; + tic->t_flags = XLOG_TIC_INITED; + if (xflags & XFS_LOG_PERM_RESERV) + tic->t_flags |= XLOG_TIC_PERM_RESERV; + sv_init(&(tic->t_sema), SV_DEFAULT, "logtick"); + + return tic; +} /* xlog_ticket_get */ + + +/****************************************************************************** + * + * Log debug routines + * + ****************************************************************************** + */ +#if defined(DEBUG) && !defined(XLOG_NOLOG) +/* + * Make sure that the destination ptr is within the valid data region of + * one of the iclogs. This uses backup pointers stored in a different + * part of the log in case we trash the log structure. + */ +void +xlog_verify_dest_ptr(xlog_t *log, + __psint_t ptr) +{ + int i; + int good_ptr = 0; + + for (i=0; i < log->l_iclog_bufs; i++) { + if (ptr >= (__psint_t)log->l_iclog_bak[i] && + ptr <= (__psint_t)log->l_iclog_bak[i]+log->l_iclog_size) + good_ptr++; + } + if (! good_ptr) + xlog_panic("xlog_verify_dest_ptr: invalid ptr"); +} /* xlog_verify_dest_ptr */ + + +#ifdef XFSDEBUG +/* check split LR write */ +STATIC void +xlog_verify_disk_cycle_no(xlog_t *log, + xlog_in_core_t *iclog) +{ + xfs_buf_t *bp; + uint cycle_no; + xfs_daddr_t i; + + if (BLOCK_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT) < 10) { + cycle_no = CYCLE_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT); + bp = xlog_get_bp(1, log->l_mp); + ASSERT(bp); + for (i = 0; i < BLOCK_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT); i++) { + xlog_bread(log, i, 1, bp); + if (GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT) != cycle_no) + xlog_warn("XFS: xlog_verify_disk_cycle_no: bad cycle no"); + } + xlog_put_bp(bp); + } +} /* xlog_verify_disk_cycle_no */ +#endif + +STATIC void +xlog_verify_grant_head(xlog_t *log, int equals) +{ + if (log->l_grant_reserve_cycle == log->l_grant_write_cycle) { + if (equals) + ASSERT(log->l_grant_reserve_bytes >= log->l_grant_write_bytes); + else + ASSERT(log->l_grant_reserve_bytes > log->l_grant_write_bytes); + } else { + ASSERT(log->l_grant_reserve_cycle-1 == log->l_grant_write_cycle); + ASSERT(log->l_grant_write_bytes >= log->l_grant_reserve_bytes); + } +} /* xlog_verify_grant_head */ + +/* check if it will fit */ +STATIC void +xlog_verify_tail_lsn(xlog_t *log, + xlog_in_core_t *iclog, + xfs_lsn_t tail_lsn) +{ + int blocks; + + if (CYCLE_LSN(tail_lsn, ARCH_NOCONVERT) == log->l_prev_cycle) { + blocks = + log->l_logBBsize - (log->l_prev_block - BLOCK_LSN(tail_lsn, ARCH_NOCONVERT)); + if (blocks < BTOBB(iclog->ic_offset)+1) + xlog_panic("xlog_verify_tail_lsn: ran out of log space"); + } else { + ASSERT(CYCLE_LSN(tail_lsn, ARCH_NOCONVERT)+1 == log->l_prev_cycle); + + if (BLOCK_LSN(tail_lsn, ARCH_NOCONVERT) == log->l_prev_block) + xlog_panic("xlog_verify_tail_lsn: tail wrapped"); + + blocks = BLOCK_LSN(tail_lsn, ARCH_NOCONVERT) - log->l_prev_block; + if (blocks < BTOBB(iclog->ic_offset) + 1) + xlog_panic("xlog_verify_tail_lsn: ran out of log space"); + } +} /* xlog_verify_tail_lsn */ + +/* + * Perform a number of checks on the iclog before writing to disk. + * + * 1. Make sure the iclogs are still circular + * 2. Make sure we have a good magic number + * 3. Make sure we don't have magic numbers in the data + * 4. Check fields of each log operation header for: + * A. Valid client identifier + * B. tid ptr value falls in valid ptr space (user space code) + * C. Length in log record header is correct according to the + * individual operation headers within record. + * 5. When a bwrite will occur within 5 blocks of the front of the physical + * log, check the preceding blocks of the physical log to make sure all + * the cycle numbers agree with the current cycle number. + */ +STATIC void +xlog_verify_iclog(xlog_t *log, + xlog_in_core_t *iclog, + int count, + boolean_t syncing) +{ + xlog_op_header_t *ophead; + xlog_in_core_t *icptr; + xfs_caddr_t ptr; + xfs_caddr_t base_ptr; + __psint_t field_offset; + char clientid; + int len, i, op_len, spl; + int idx; + + /* check validity of iclog pointers */ + spl = LOG_LOCK(log); + icptr = log->l_iclog; + for (i=0; i < log->l_iclog_bufs; i++) { + if (icptr == 0) + xlog_panic("xlog_verify_iclog: illegal ptr"); + icptr = icptr->ic_next; + } + if (icptr != log->l_iclog) + xlog_panic("xlog_verify_iclog: corrupt iclog ring"); + LOG_UNLOCK(log, spl); + + /* check log magic numbers */ + ptr = (xfs_caddr_t) &(iclog->ic_header); + if (INT_GET(*(uint *)ptr, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) + xlog_panic("xlog_verify_iclog: illegal magic num"); + + for (ptr += BBSIZE; ptr < ((xfs_caddr_t)&(iclog->ic_header))+count; + ptr += BBSIZE) { + if (INT_GET(*(uint *)ptr, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) + xlog_panic("xlog_verify_iclog: unexpected magic num"); + } + + /* check fields */ + len = INT_GET(iclog->ic_header.h_len, ARCH_CONVERT); + ptr = iclog->ic_data; + base_ptr = ptr; + ophead = (xlog_op_header_t *)ptr; + for (i=0; iic_header.h_num_logops, ARCH_CONVERT); i++) { + ophead = (xlog_op_header_t *)ptr; + + /* clientid is only 1 byte */ + field_offset = (__psint_t) + ((xfs_caddr_t)&(ophead->oh_clientid) - base_ptr); + if (syncing == B_FALSE || (field_offset & 0x1ff)) { + clientid = ophead->oh_clientid; + } else { + idx = BTOBB(&ophead->oh_clientid - iclog->ic_data); + clientid = GET_CLIENT_ID(iclog->ic_header.h_cycle_data[idx], ARCH_CONVERT); + } + if (clientid != XFS_TRANSACTION && clientid != XFS_LOG) + xlog_panic("xlog_verify_iclog: illegal client"); + + /* check length */ + field_offset = (__psint_t) + ((xfs_caddr_t)&(ophead->oh_len) - base_ptr); + if (syncing == B_FALSE || (field_offset & 0x1ff)) { + op_len = INT_GET(ophead->oh_len, ARCH_CONVERT); + } else { + idx = BTOBB((__psint_t)&ophead->oh_len - + (__psint_t)iclog->ic_data); + op_len = INT_GET(iclog->ic_header.h_cycle_data[idx], ARCH_CONVERT); + } + len -= sizeof(xlog_op_header_t) + op_len; + ptr += sizeof(xlog_op_header_t) + op_len; + } + if (len != 0) + xlog_panic("xlog_verify_iclog: illegal iclog"); + +} /* xlog_verify_iclog */ +#endif /* DEBUG && !XLOG_NOLOG */ + +/* + * Mark all iclogs IOERROR. LOG_LOCK is held by the caller. + */ +STATIC int +xlog_state_ioerror( + xlog_t *log) +{ + xlog_in_core_t *iclog, *ic; + + iclog = log->l_iclog; + if (! (iclog->ic_state & XLOG_STATE_IOERROR)) { + /* + * Mark all the incore logs IOERROR. + * From now on, no log flushes will result. + */ + ic = iclog; + do { + ic->ic_state = XLOG_STATE_IOERROR; + ic = ic->ic_next; + } while (ic != iclog); + return (0); + } + /* + * Return non-zero, if state transition has already happened. + */ + return (1); +} + +/* + * This is called from xfs_force_shutdown, when we're forcibly + * shutting down the filesystem, typically because of an IO error. + * Our main objectives here are to make sure that: + * a. the filesystem gets marked 'SHUTDOWN' for all interested + * parties to find out, 'atomically'. + * b. those who're sleeping on log reservations, pinned objects and + * other resources get woken up, and be told the bad news. + * c. nothing new gets queued up after (a) and (b) are done. + * d. if !logerror, flush the iclogs to disk, then seal them off + * for business. + */ +int +xfs_log_force_umount( + struct xfs_mount *mp, + int logerror) +{ + xlog_ticket_t *tic; + int spl, spl2; + xlog_t *log; + int retval; + + log = mp->m_log; + + /* + * If this happens during log recovery, don't worry about + * locking; the log isn't open for business yet. + */ + if (!log || + log->l_flags & XLOG_ACTIVE_RECOVERY) { + mp->m_flags |= XFS_MOUNT_FS_SHUTDOWN; + XFS_BUF_DONE(mp->m_sb_bp); + return (0); + } + + /* + * Somebody could've already done the hard work for us. + * No need to get locks for this. + */ + if (logerror && log->l_iclog->ic_state & XLOG_STATE_IOERROR) { + ASSERT(XLOG_FORCED_SHUTDOWN(log)); + return (1); + } + retval = 0; + /* + * We must hold both the GRANT lock and the LOG lock, + * before we mark the filesystem SHUTDOWN and wake + * everybody up to tell the bad news. + */ + spl = GRANT_LOCK(log); + spl2 = LOG_LOCK(log); + mp->m_flags |= XFS_MOUNT_FS_SHUTDOWN; + XFS_BUF_DONE(mp->m_sb_bp); + /* + * This flag is sort of redundant because of the mount flag, but + * it's good to maintain the separation between the log and the rest + * of XFS. + */ + log->l_flags |= XLOG_IO_ERROR; + + /* + * If we hit a log error, we want to mark all the iclogs IOERROR + * while we're still holding the loglock. + */ + if (logerror) + retval = xlog_state_ioerror(log); + LOG_UNLOCK(log, spl2); + + /* + * We don't want anybody waiting for log reservations + * after this. That means we have to wake up everybody + * queued up on reserve_headq as well as write_headq. + * In addition, we make sure in xlog_{re}grant_log_space + * that we don't enqueue anything once the SHUTDOWN flag + * is set, and this action is protected by the GRANTLOCK. + */ + if ((tic = log->l_reserve_headq)) { + do { + sv_signal(&tic->t_sema); + tic = tic->t_next; + } while (tic != log->l_reserve_headq); + } + + if ((tic = log->l_write_headq)) { + do { + sv_signal(&tic->t_sema); + tic = tic->t_next; + } while (tic != log->l_write_headq); + } + GRANT_UNLOCK(log, spl); + + if (! (log->l_iclog->ic_state & XLOG_STATE_IOERROR)) { + ASSERT(!logerror); + /* + * Force the incore logs to disk before shutting the + * log down completely. + */ + xlog_state_sync_all(log, XFS_LOG_FORCE|XFS_LOG_SYNC); + spl2 = LOG_LOCK(log); + retval = xlog_state_ioerror(log); + LOG_UNLOCK(log, spl2); + } + /* + * Wake up everybody waiting on xfs_log_force. + * Callback all log item committed functions as if the + * log writes were completed. + */ + xlog_state_do_callback(log, XFS_LI_ABORTED, NULL); + +#ifdef XFSERRORDEBUG + { + xlog_in_core_t *iclog; + + spl = LOG_LOCK(log); + iclog = log->l_iclog; + do { + ASSERT(iclog->ic_callback == 0); + iclog = iclog->ic_next; + } while (iclog != log->l_iclog); + LOG_UNLOCK(log, spl); + } +#endif + /* return non-zero if log IOERROR transition had already happened */ + return (retval); +} + +int +xlog_iclogs_empty(xlog_t *log) +{ + xlog_in_core_t *iclog; + + iclog = log->l_iclog; + do { + if (INT_GET(iclog->ic_header.h_num_logops, ARCH_CONVERT)) + return(0); + iclog = iclog->ic_next; + } while (iclog != log->l_iclog); + return(1); +} + diff -rNu linux-2.4.7/linux/fs/xfs/xfs_log.h linux-2.4-xfs/linux/fs/xfs/xfs_log.h --- linux-2.4.7/linux/fs/xfs/xfs_log.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_log.h Wed Apr 18 11:19:03 2001 @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_LOG_H__ +#define __XFS_LOG_H__ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define LSN_FIELD_CYCLE(arch) (((arch)==ARCH_NOCONVERT)?1:0) +#define LSN_FIELD_BLOCK(arch) (((arch)==ARCH_NOCONVERT)?0:1) +#else +#define LSN_FIELD_CYCLE(arch) (0) +#define LSN_FIELD_BLOCK(arch) (1) +#endif + +/* get lsn fields */ + +#define CYCLE_LSN(lsn,arch) (INT_GET(((uint *)&(lsn))[LSN_FIELD_CYCLE(arch)], arch)) +#define BLOCK_LSN(lsn,arch) (INT_GET(((uint *)&(lsn))[LSN_FIELD_BLOCK(arch)], arch)) + +#ifdef __KERNEL__ +/* + * By comparing each compnent, we don't have to worry about extra + * endian issues in treating two 32 bit numbers as one 64 bit number + */ +static +#ifdef __GNUC__ +# if !((__GNUC__ == 2) && (__GNUC_MINOR__ == 95)) +__inline__ +#endif +#endif +xfs_lsn_t _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2, xfs_arch_t arch) +{ + if (CYCLE_LSN(lsn1, arch) != CYCLE_LSN(lsn2, arch)) + return (CYCLE_LSN(lsn1, arch)> XLOG_RECORD_BSHIFT) +#endif + +#define XLOG_HEADER_SIZE 512 + +/* + * set lsns + */ + +#define ASSIGN_LSN_CYCLE(lsn,cycle,arch) \ + INT_SET(((uint *)&(lsn))[LSN_FIELD_CYCLE(arch)], arch, (cycle)); +#define ASSIGN_LSN_BLOCK(lsn,block,arch) \ + INT_SET(((uint *)&(lsn))[LSN_FIELD_BLOCK(arch)], arch, (block)); +#define ASSIGN_ANY_LSN(lsn,cycle,block,arch) \ + { \ + ASSIGN_LSN_CYCLE(lsn,cycle,arch); \ + ASSIGN_LSN_BLOCK(lsn,block,arch); \ + } +#define ASSIGN_LSN(lsn,log,arch) \ + ASSIGN_ANY_LSN(lsn,(log)->l_curr_cycle,(log)->l_curr_block,arch); + +#define XLOG_SET(f,b) (((f) & (b)) == (b)) + +#define GET_CYCLE(ptr, arch) \ + (INT_GET(*(uint *)(ptr), arch) == XLOG_HEADER_MAGIC_NUM ? \ + INT_GET(*((uint *)(ptr)+1), arch) : \ + INT_GET(*(uint *)(ptr), arch) \ + ) + +#define BLK_AVG(blk1, blk2) ((blk1+blk2) >> 1) + + +#ifdef __KERNEL__ +/* + * get client id from packed copy. + * + * this hack is here because the xlog_pack code copies four bytes + * of xlog_op_header containing the fields oh_clientid, oh_flags + * and oh_res2 into the packed copy. + * + * later on this four byte chunk is treated as an int and the + * client id is pulled out. + * + * this has endian issues, of course. + */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define GET_CLIENT_ID(i,arch) \ + ((i) & 0xff) +#else +#define GET_CLIENT_ID(i,arch) \ + ((i) >> 24) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XLOG_GRANT_SUB_SPACE) +void xlog_grant_sub_space(struct log *log, int bytes, int type); +#define XLOG_GRANT_SUB_SPACE(log,bytes,type) \ + xlog_grant_sub_space(log,bytes,type) +#else +#define XLOG_GRANT_SUB_SPACE(log,bytes,type) \ + { \ + if (type == 'w') { \ + (log)->l_grant_write_bytes -= (bytes); \ + if ((log)->l_grant_write_bytes < 0) { \ + (log)->l_grant_write_bytes += (log)->l_logsize; \ + (log)->l_grant_write_cycle--; \ + } \ + } else { \ + (log)->l_grant_reserve_bytes -= (bytes); \ + if ((log)->l_grant_reserve_bytes < 0) { \ + (log)->l_grant_reserve_bytes += (log)->l_logsize;\ + (log)->l_grant_reserve_cycle--; \ + } \ + } \ + } +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XLOG_GRANT_ADD_SPACE) +void xlog_grant_add_space(struct log *log, int bytes, int type); +#define XLOG_GRANT_ADD_SPACE(log,bytes,type) \ + xlog_grant_add_space(log,bytes,type) +#else +#define XLOG_GRANT_ADD_SPACE(log,bytes,type) \ + { \ + if (type == 'w') { \ + (log)->l_grant_write_bytes += (bytes); \ + if ((log)->l_grant_write_bytes > (log)->l_logsize) { \ + (log)->l_grant_write_bytes -= (log)->l_logsize; \ + (log)->l_grant_write_cycle++; \ + } \ + } else { \ + (log)->l_grant_reserve_bytes += (bytes); \ + if ((log)->l_grant_reserve_bytes > (log)->l_logsize) { \ + (log)->l_grant_reserve_bytes -= (log)->l_logsize;\ + (log)->l_grant_reserve_cycle++; \ + } \ + } \ + } +#endif +#define XLOG_INS_TICKETQ(q,tic) \ + { \ + if (q) { \ + (tic)->t_next = (q); \ + (tic)->t_prev = (q)->t_prev; \ + (q)->t_prev->t_next = (tic); \ + (q)->t_prev = (tic); \ + } else { \ + (tic)->t_prev = (tic)->t_next = (tic); \ + (q) = (tic); \ + } \ + (tic)->t_flags |= XLOG_TIC_IN_Q; \ + } +#define XLOG_DEL_TICKETQ(q,tic) \ + { \ + if ((tic) == (tic)->t_next) { \ + (q) = NULL; \ + } else { \ + (q) = (tic)->t_next; \ + (tic)->t_next->t_prev = (tic)->t_prev; \ + (tic)->t_prev->t_next = (tic)->t_next; \ + } \ + (tic)->t_next = (tic)->t_prev = NULL; \ + (tic)->t_flags &= ~XLOG_TIC_IN_Q; \ + } + + +#define GRANT_LOCK(log) mutex_spinlock(&(log)->l_grant_lock) +#define GRANT_UNLOCK(log, s) mutex_spinunlock(&(log)->l_grant_lock, s) +#define LOG_LOCK(log) mutex_spinlock(&(log)->l_icloglock) +#define LOG_UNLOCK(log, s) mutex_spinunlock(&(log)->l_icloglock, s) + +#define xlog_panic(s) {cmn_err(CE_PANIC, s); } +#define xlog_exit(s) {cmn_err(CE_PANIC, s); } +#define xlog_warn(s) {cmn_err(CE_WARN, s); } + +/* + * In core log state + */ +#define XLOG_STATE_ACTIVE 0x0001 /* Current IC log being written to */ +#define XLOG_STATE_WANT_SYNC 0x0002 /* Want to sync this iclog; no more writes */ +#define XLOG_STATE_SYNCING 0x0004 /* This IC log is syncing */ +#define XLOG_STATE_DONE_SYNC 0x0008 /* Done syncing to disk */ +#define XLOG_STATE_DO_CALLBACK \ + 0x0010 /* Process callback functions */ +#define XLOG_STATE_CALLBACK 0x0020 /* Callback functions now */ +#define XLOG_STATE_DIRTY 0x0040 /* Dirty IC log, not ready for ACTIVE status*/ +#define XLOG_STATE_IOERROR 0x0080 /* IO error happened in sync'ing log */ +#define XLOG_STATE_ALL 0x7FFF /* All possible valid flags */ +#define XLOG_STATE_NOTUSED 0x8000 /* This IC log not being used */ +#endif /* __KERNEL__ */ + +/* + * Flags to log operation header + * + * The first write of a new transaction will be preceded with a start + * record, XLOG_START_TRANS. Once a transaction is committed, a commit + * record is written, XLOG_COMMIT_TRANS. If a single region can not fit into + * the remainder of the current active in-core log, it is split up into + * multiple regions. Each partial region will be marked with a + * XLOG_CONTINUE_TRANS until the last one, which gets marked with XLOG_END_TRANS. + * + */ +#define XLOG_START_TRANS 0x01 /* Start a new transaction */ +#define XLOG_COMMIT_TRANS 0x02 /* Commit this transaction */ +#define XLOG_CONTINUE_TRANS 0x04 /* Cont this trans into new region */ +#define XLOG_WAS_CONT_TRANS 0x08 /* Cont this trans into new region */ +#define XLOG_END_TRANS 0x10 /* End a continued transaction */ +#define XLOG_UNMOUNT_TRANS 0x20 /* Unmount a filesystem transaction */ +#define XLOG_SKIP_TRANS (XLOG_COMMIT_TRANS | XLOG_CONTINUE_TRANS | \ + XLOG_WAS_CONT_TRANS | XLOG_END_TRANS | \ + XLOG_UNMOUNT_TRANS) + +#ifdef __KERNEL__ +/* + * Flags to log ticket + */ +#define XLOG_TIC_INITED 0x1 /* has been initialized */ +#define XLOG_TIC_PERM_RESERV 0x2 /* permanent reservation */ +#define XLOG_TIC_IN_Q 0x4 +#endif /* __KERNEL__ */ + +#define XLOG_UNMOUNT_TYPE 0x556e /* Un for Unmount */ + +/* + * Flags for log structure + */ +#define XLOG_CHKSUM_MISMATCH 0x1 /* used only during recovery */ +#define XLOG_ACTIVE_RECOVERY 0x2 /* in the middle of recovery */ +#define XLOG_RECOVERY_NEEDED 0x4 /* log was recovered */ +#define XLOG_IO_ERROR 0x8 /* log hit an I/O error, and being + shutdown */ +typedef __uint32_t xlog_tid_t; + + +#ifdef __KERNEL__ +/* + * Below are states for covering allocation transactions. + * By covering, we mean changing the h_tail_lsn in the last on-disk + * log write such that no allocation transactions will be re-done during + * recovery after a system crash. Recovery starts at the last on-disk + * log write. + * + * These states are used to insert dummy log entries to cover + * space allocation transactions which can undo non-transactional changes + * after a crash. Writes to a file with space + * already allocated do not result in any transactions. Allocations + * might include space beyond the EOF. So if we just push the EOF a + * little, the last transaction for the file could contain the wrong + * size. If there is no file system activity, after an allocation + * transaction, and the system crashes, the allocation transaction + * will get replayed and the file will be truncated. This could + * be hours/days/... after the allocation occurred. + * + * The fix for this is to do two dummy transactions when the + * system is idle. We need two dummy transaction because the h_tail_lsn + * in the log record header needs to point beyond the last possible + * non-dummy transaction. The first dummy changes the h_tail_lsn to + * the first transaction before the dummy. The second dummy causes + * h_tail_lsn to point to the first dummy. Recovery starts at h_tail_lsn. + * + * These dummy transactions get committed when everything + * is idle (after there has been some activity). + * + * There are 5 states used to control this. + * + * IDLE -- no logging has been done on the file system or + * we are done covering previous transactions. + * NEED -- logging has occurred and we need a dummy transaction + * when the log becomes idle. + * DONE -- we were in the NEED state and have committed a dummy + * transaction. + * NEED2 -- we detected that a dummy transaction has gone to the + * on disk log with no other transactions. + * DONE2 -- we committed a dummy transaction when in the NEED2 state. + * + * There are two places where we switch states: + * + * 1.) In xfs_sync, when we detect an idle log and are in NEED or NEED2. + * We commit the dummy transaction and switch to DONE or DONE2, + * respectively. In all other states, we don't do anything. + * + * 2.) When we finish writing the on-disk log (xlog_state_clean_log). + * + * No matter what state we are in, if this isn't the dummy + * transaction going out, the next state is NEED. + * So, if we aren't in the DONE or DONE2 states, the next state + * is NEED. We can't be finishing a write of the dummy record + * unless it was committed and the state switched to DONE or DONE2. + * + * If we are in the DONE state and this was a write of the + * dummy transaction, we move to NEED2. + * + * If we are in the DONE2 state and this was a write of the + * dummy transaction, we move to IDLE. + * + * + * Writing only one dummy transaction can get appended to + * one file space allocation. When this happens, the log recovery + * code replays the space allocation and a file could be truncated. + * This is why we have the NEED2 and DONE2 states before going idle. + */ + +#define XLOG_STATE_COVER_IDLE 0 +#define XLOG_STATE_COVER_NEED 1 +#define XLOG_STATE_COVER_DONE 2 +#define XLOG_STATE_COVER_NEED2 3 +#define XLOG_STATE_COVER_DONE2 4 + +#define XLOG_COVER_OPS 5 + +typedef struct xlog_ticket { + sv_t t_sema; /* sleep on this semaphore :20 */ + struct xlog_ticket *t_next; /* : 4 */ + struct xlog_ticket *t_prev; /* : 4 */ + xlog_tid_t t_tid; /* transaction identifier : 4 */ + int t_curr_res; /* current reservation in bytes : 4 */ + int t_unit_res; /* unit reservation in bytes : 4 */ + char t_ocnt; /* original count : 1 */ + char t_cnt; /* current count : 1 */ + char t_clientid; /* who does this belong to; : 1 */ + char t_flags; /* properties of reservation : 1 */ +} xlog_ticket_t; +#endif + + +typedef struct xlog_op_header { + xlog_tid_t oh_tid; /* transaction id of operation : 4 b */ + int oh_len; /* bytes in data region : 2 b */ + char oh_clientid; /* who sent me this : 1 b */ + char oh_flags; /* : 1 b */ + ushort oh_res2; /* 32 bit align : 2 b */ +} xlog_op_header_t; + + +/* valid values for h_fmt */ +#define XLOG_FMT_UNKNOWN 0 +#define XLOG_FMT_LINUX_LE 1 +#define XLOG_FMT_LINUX_BE 2 +#define XLOG_FMT_IRIX_BE 3 + +/* our fmt */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define XLOG_FMT XLOG_FMT_LINUX_LE +#else +#if __BYTE_ORDER == __BIG_ENDIAN +#define XLOG_FMT XLOG_FMT_LINUX_BE +#else +#error unknown byte order +#endif +#endif + +typedef struct xlog_rec_header { + uint h_magicno; /* log record (LR) identifier : 4 */ + uint h_cycle; /* write cycle of log : 4 */ + int h_version; /* LR version : 4 */ + int h_len; /* len in bytes; should be 64-bit aligned: 4 */ + xfs_lsn_t h_lsn; /* lsn of this LR : 8 */ + xfs_lsn_t h_tail_lsn; /* lsn of 1st LR w/ buffers not committed: 8 */ + uint h_chksum; /* may not be used; non-zero if used : 4 */ + int h_prev_block; /* block number to previous LR : 4 */ + int h_num_logops; /* number of log operations in this LR : 4 */ + uint h_cycle_data[XLOG_MAX_RECORD_BSIZE / BBSIZE]; + /* new fields */ + int h_fmt; /* format of log record : 4 */ + uuid_t h_fs_uuid; /* uuid of FS : 16 */ +} xlog_rec_header_t; + +#ifdef __KERNEL__ +/* + * - A log record header is 512 bytes. There is plenty of room to grow the + * xlog_rec_header_t into the reserved space. + * - ic_data follows, so a write to disk can start at the beginning of + * the iclog. + * - ic_forcesema is used to implement synchronous forcing of the iclog to disk. + * - ic_next is the pointer to the next iclog in the ring. + * - ic_bp is a pointer to the buffer used to write this incore log to disk. + * - ic_log is a pointer back to the global log structure. + * - ic_callback is a linked list of callback function/argument pairs to be + * called after an iclog finishes writing. + * - ic_size is the full size of the header plus data. + * - ic_offset is the current number of bytes written to in this iclog. + * - ic_refcnt is bumped when someone is writing to the log. + * - ic_state is the state of the iclog. + */ +typedef struct xlog_iclog_fields { + sv_t ic_forcesema; + struct xlog_in_core *ic_next; + struct xlog_in_core *ic_prev; + struct xfs_buf *ic_bp; + struct log *ic_log; + xfs_log_callback_t *ic_callback; + xfs_log_callback_t **ic_callback_tail; +#ifdef DEBUG + struct ktrace *ic_trace; +#endif + int ic_size; + int ic_offset; + int ic_refcnt; + int ic_roundoff; + int ic_bwritecnt; + ushort_t ic_state; +} xlog_iclog_fields_t; + +typedef struct xlog_in_core { + union { + xlog_iclog_fields_t hic_fields; + char hic_pad[BBSIZE]; + } ic_h1; + union { + xlog_rec_header_t hic_header; + char hic_sector[XLOG_HEADER_SIZE]; + } ic_h2; + char ic_data[1]; +} xlog_in_core_t; + +/* + * Defines to save our code from this glop. + */ +#define ic_forcesema ic_h1.hic_fields.ic_forcesema +#define ic_next ic_h1.hic_fields.ic_next +#define ic_prev ic_h1.hic_fields.ic_prev +#define ic_bp ic_h1.hic_fields.ic_bp +#define ic_log ic_h1.hic_fields.ic_log +#define ic_callback ic_h1.hic_fields.ic_callback +#define ic_callback_tail ic_h1.hic_fields.ic_callback_tail +#define ic_trace ic_h1.hic_fields.ic_trace +#define ic_size ic_h1.hic_fields.ic_size +#define ic_offset ic_h1.hic_fields.ic_offset +#define ic_refcnt ic_h1.hic_fields.ic_refcnt +#define ic_roundoff ic_h1.hic_fields.ic_roundoff +#define ic_bwritecnt ic_h1.hic_fields.ic_bwritecnt +#define ic_state ic_h1.hic_fields.ic_state +#define ic_header ic_h2.hic_header + +/* + * The reservation head lsn is not made up of a cycle number and block number. + * Instead, it uses a cycle number and byte number. Logs don't expect to + * overflow 31 bits worth of byte offset, so using a byte number will mean + * that round off problems won't occur when releasing partial reservations. + */ +typedef struct log { + /* The following block of fields are changed while holding icloglock */ + sema_t l_flushsema; /* iclog flushing semaphore */ + int l_flushcnt; /* # of procs waiting on this sema */ + int l_ticket_cnt; /* free ticket count */ + int l_ticket_tcnt; /* total ticket count */ + int l_covered_state;/* state of "covering disk log entries" */ + xlog_ticket_t *l_freelist; /* free list of tickets */ + xlog_ticket_t *l_unmount_free;/* kmem_free these addresses */ + xlog_ticket_t *l_tail; /* free list of tickets */ + xlog_in_core_t *l_iclog; /* head log queue */ + lock_t l_icloglock; /* grab to change iclog state */ + xfs_lsn_t l_tail_lsn; /* lsn of 1st LR w/ unflush buffers */ + xfs_lsn_t l_last_sync_lsn;/* lsn of last LR on disk */ + struct xfs_mount *l_mp; /* mount point */ + struct xfs_buf *l_xbuf; /* extra buffer for log wrapping */ + dev_t l_dev; /* dev_t of log */ + xfs_daddr_t l_logBBstart; /* start block of log */ + int l_logsize; /* size of log in bytes */ + int l_logBBsize; /* size of log in 512 byte chunks */ + int l_roundoff; /* round off error of all iclogs */ + int l_curr_cycle; /* Cycle number of log writes */ + int l_prev_cycle; /* Cycle # b4 last block increment */ + int l_curr_block; /* current logical block of log */ + int l_prev_block; /* previous logical block of log */ + int l_iclog_size; /* size of log in bytes */ + int l_iclog_size_log;/* log power size of log */ + int l_iclog_bufs; /* number of iclog buffers */ + + /* The following field are used for debugging; need to hold icloglock */ + char *l_iclog_bak[XLOG_MAX_ICLOGS]; + + /* The following block of fields are changed while holding grant_lock */ + lock_t l_grant_lock; /* protects below fields */ + xlog_ticket_t *l_reserve_headq; /* */ + xlog_ticket_t *l_write_headq; /* */ + int l_grant_reserve_cycle; /* */ + int l_grant_reserve_bytes; /* */ + int l_grant_write_cycle; /* */ + int l_grant_write_bytes; /* */ + + /* The following fields don't need locking */ +#ifdef DEBUG + struct ktrace *l_trace; + struct ktrace *l_grant_trace; +#endif + uint l_flags; + uint l_quotaoffs_flag;/* XFS_DQ_*, if QUOTAOFFs found */ + struct xfs_buf_cancel **l_buf_cancel_table; +} xlog_t; + + +/* common routines */ +extern xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp, + xlog_in_core_t *iclog); +extern int xlog_find_head(xlog_t *log, xfs_daddr_t *head_blk); +extern int xlog_find_tail(xlog_t *log, + xfs_daddr_t *head_blk, + xfs_daddr_t *tail_blk, + int readonly); +extern int xlog_print_find_oldest(xlog_t *log, xfs_daddr_t *last_blk); +extern int xlog_recover(xlog_t *log, int readonly); +extern int xlog_recover_finish(xlog_t *log, int mfsi_flags); +extern void xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog); +extern struct xfs_buf *xlog_get_bp(int,xfs_mount_t *); +extern void xlog_put_bp(struct xfs_buf *); +extern int xlog_bread(xlog_t *, xfs_daddr_t blkno, int bblks, struct xfs_buf *bp); +extern void xlog_recover_process_iunlinks(xlog_t *log); + +#define XLOG_TRACE_GRAB_FLUSH 1 +#define XLOG_TRACE_REL_FLUSH 2 +#define XLOG_TRACE_SLEEP_FLUSH 3 +#define XLOG_TRACE_WAKE_FLUSH 4 + +#endif /* __KERNEL__ */ + +#endif /* __XFS_LOG_PRIV_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_log_recover.c linux-2.4-xfs/linux/fs/xfs/xfs_log_recover.c --- linux-2.4.7/linux/fs/xfs/xfs_log_recover.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_log_recover.c Fri Apr 13 11:34:37 2001 @@ -0,0 +1,3520 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +STATIC int xlog_find_zeroed(struct log *log, xfs_daddr_t *blk_no); + +STATIC int xlog_clear_stale_blocks(xlog_t *log, xfs_lsn_t tail_lsn); +STATIC void xlog_recover_insert_item_backq(xlog_recover_item_t **q, + xlog_recover_item_t *item); + +#if defined(DEBUG) +STATIC void xlog_recover_check_summary(xlog_t *log); +STATIC void xlog_recover_check_ail(xfs_mount_t *mp, xfs_log_item_t *lip, + int gen); +#else +#define xlog_recover_check_summary(log) +#define xlog_recover_check_ail(mp, lip, gen) +#endif /* DEBUG */ + + +xfs_buf_t * +xlog_get_bp(int num_bblks,xfs_mount_t *mp) +{ + xfs_buf_t *bp; + + ASSERT(num_bblks > 0); + + bp = XFS_ngetrbuf(BBTOB(num_bblks),mp); + return bp; +} /* xlog_get_bp */ + + +void +xlog_put_bp(xfs_buf_t *bp) +{ + XFS_nfreerbuf(bp); +} /* xlog_put_bp */ + + +/* + * nbblks should be uint, but oh well. Just want to catch that 32-bit length. + */ +int +xlog_bread(xlog_t *log, + xfs_daddr_t blk_no, + int nbblks, + xfs_buf_t *bp) +{ + int error; + + ASSERT(log); + ASSERT(nbblks > 0); + ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp)); + ASSERT(bp); + + XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no); + XFS_BUF_READ(bp); + XFS_BUF_BUSY(bp); + XFS_BUF_SET_COUNT(bp, BBTOB(nbblks)); + XFS_BUF_SET_TARGET(bp, &log->l_mp->m_logdev_targ); + + xfsbdstrat(log->l_mp, bp); + if ((error = xfs_iowait(bp))) { + xfs_ioerror_alert("xlog_bread", log->l_mp, + XFS_BUF_TARGET(bp), XFS_BUF_ADDR(bp)); + return (error); + } + return error; +} /* xlog_bread */ + + +/* + * Write out the buffer at the given block for the given number of blocks. + * The buffer is kept locked across the write and is returned locked. + * This can only be used for synchronous log writes. + */ +int +xlog_bwrite( + xlog_t *log, + xfs_daddr_t blk_no, + int nbblks, + xfs_buf_t *bp) +{ + int error; + + ASSERT(nbblks > 0); + ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp)); + + XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no); + XFS_BUF_ZEROFLAGS(bp); + XFS_BUF_BUSY(bp); + XFS_BUF_HOLD(bp); + XFS_BUF_SET_COUNT(bp, BBTOB(nbblks)); + XFS_BUF_SET_TARGET(bp, &log->l_mp->m_logdev_targ); + + if ((error = xfs_bwrite(log->l_mp, bp))) + xfs_ioerror_alert("xlog_bwrite", log->l_mp, + XFS_BUF_TARGET(bp), XFS_BUF_ADDR(bp)); + + return (error); +} /* xlog_bwrite */ + +#ifdef DEBUG +/* + * check log record header for recovery + */ + +static void +xlog_header_check_dump(xfs_mount_t *mp, xlog_rec_header_t *head) +{ + int b; + + printk("xlog_header_check_dump:\n SB : uuid = "); + for (b=0;b<16;b++) printk("%02x",((unsigned char *)&mp->m_sb.sb_uuid)[b]); + printk(", fmt = %d\n",XLOG_FMT); + printk(" log: uuid = "); + for (b=0;b<16;b++) printk("%02x",((unsigned char *)&head->h_fs_uuid)[b]); + printk(", fmt = %d\n", INT_GET(head->h_fmt, ARCH_CONVERT)); +} +#endif + +/* + * check log record header for recovery + */ + +STATIC int +xlog_header_check_recover(xfs_mount_t *mp, xlog_rec_header_t *head) +{ + ASSERT(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); + + /* + * IRIX doesn't write the h_fmt field and leaves it zeroed + * (XLOG_FMT_UNKNOWN). This stops us from trying to recover + * a dirty log created in IRIX. + */ + + if (INT_GET(head->h_fmt, ARCH_CONVERT) != XLOG_FMT) { + xlog_warn("XFS: dirty log written in incompatible format - can't recover"); +#ifdef DEBUG + xlog_header_check_dump(mp, head); +#endif + return XFS_ERROR(EFSCORRUPTED); + } else if (!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) { + xlog_warn("XFS: dirty log entry has mismatched uuid - can't recover"); +#ifdef DEBUG + xlog_header_check_dump(mp, head); +#endif + return XFS_ERROR(EFSCORRUPTED); + } + + return 0; +} + +/* + * read the head block of the log and check the header + */ + +STATIC int +xlog_header_check_mount(xfs_mount_t *mp, xlog_rec_header_t *head) +{ + ASSERT(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); + + if (uuid_is_nil(&head->h_fs_uuid)) { + + /* + * IRIX doesn't write the h_fs_uuid or h_fmt fields. If + * h_fs_uuid is nil, we assume this log was last mounted + * by IRIX and continue. + */ + + xlog_warn("XFS: nil uuid in log - IRIX style log"); + + } else if (!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid)) { + xlog_warn("XFS: log has mismatched uuid - can't recover"); +#ifdef DEBUG + xlog_header_check_dump(mp, head); +#endif + return XFS_ERROR(EFSCORRUPTED); + } + + return 0; +} + +STATIC void +xlog_recover_iodone( + struct xfs_buf *bp) +{ + xfs_mount_t *mp; + ASSERT(XFS_BUF_FSPRIVATE(bp, void *)); + + if (XFS_BUF_GETERROR(bp)) { + /* + * We're not going to bother about retrying + * this during recovery. One strike! + */ + mp = XFS_BUF_FSPRIVATE(bp, xfs_mount_t *); + xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR); + } + XFS_BUF_SET_FSPRIVATE(bp, NULL); + XFS_BUF_CLR_IODONE_FUNC(bp); + xfs_biodone(bp); +} + +/* + * This routine finds (to an approximation) the first block in the physical + * log which contains the given cycle. It uses a binary search algorithm. + * Note that the algorithm can not be perfect because the disk will not + * necessarily be perfect. + */ +int +xlog_find_cycle_start(xlog_t *log, + xfs_buf_t *bp, + xfs_daddr_t first_blk, + xfs_daddr_t *last_blk, + uint cycle) +{ + xfs_daddr_t mid_blk; + uint mid_cycle; + int error; + + mid_blk = BLK_AVG(first_blk, *last_blk); + while (mid_blk != first_blk && mid_blk != *last_blk) { + if ((error = xlog_bread(log, mid_blk, 1, bp))) + return error; + mid_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + if (mid_cycle == cycle) { + *last_blk = mid_blk; + /* last_half_cycle == mid_cycle */ + } else { + first_blk = mid_blk; + /* first_half_cycle == mid_cycle */ + } + mid_blk = BLK_AVG(first_blk, *last_blk); + } + ASSERT((mid_blk == first_blk && mid_blk+1 == *last_blk) || + (mid_blk == *last_blk && mid_blk-1 == first_blk)); + + return 0; +} /* xlog_find_cycle_start */ + + +/* + * Check that the range of blocks does not contain the cycle number + * given. The scan needs to occur from front to back and the ptr into the + * region must be updated since a later routine will need to perform another + * test. If the region is completely good, we end up returning the same + * last block number. + * + * Return -1 if we encounter no errors. This is an invalid block number + * since we don't ever expect logs to get this large. + */ + +STATIC xfs_daddr_t +xlog_find_verify_cycle( xlog_t *log, + xfs_daddr_t start_blk, + int nbblks, + uint stop_on_cycle_no) +{ + int i, j; + uint cycle; + xfs_buf_t *bp; + char *buf = NULL; + int error = 0; + int bufblks = nbblks; + + while (!(bp = xlog_get_bp(bufblks, log->l_mp))) { + /* can't get enough memory to do everything in one big buffer */ + bufblks >>= 1; + if (!bufblks) + return -ENOMEM; + } + + + for (i = start_blk; i < start_blk + nbblks; i += bufblks) { + if ((error = xlog_bread(log, i, bufblks, bp))) + goto out; + + buf = XFS_BUF_PTR(bp); + for (j = 0; j < bufblks; j++) { + cycle = GET_CYCLE(buf, ARCH_CONVERT); + if (cycle == stop_on_cycle_no) { + error = i; + goto out; + } + + buf += BBSIZE; + } + } + + error = -1; + +out: + xlog_put_bp(bp); + + return error; +} /* xlog_find_verify_cycle */ + + +/* + * Potentially backup over partial log record write. + * + * In the typical case, last_blk is the number of the block directly after + * a good log record. Therefore, we subtract one to get the block number + * of the last block in the given buffer. extra_bblks contains the number + * of blocks we would have read on a previous read. This happens when the + * last log record is split over the end of the physical log. + * + * extra_bblks is the number of blocks potentially verified on a previous + * call to this routine. + */ + +STATIC int +xlog_find_verify_log_record(xlog_t *log, + xfs_daddr_t start_blk, + xfs_daddr_t *last_blk, + int extra_bblks) +{ + xfs_daddr_t i; + xfs_buf_t *bp; + char *buf = NULL; + xlog_rec_header_t *head = NULL; + int error = 0; + int smallmem = 0; + int num_blks = *last_blk - start_blk; + + ASSERT(start_blk != 0 || *last_blk != start_blk); + + if (!(bp = xlog_get_bp(num_blks, log->l_mp))) { + if (!(bp = xlog_get_bp(1, log->l_mp))) + return -ENOMEM; + smallmem = 1; + buf = XFS_BUF_PTR(bp); + } else { + if ((error = xlog_bread(log, start_blk, num_blks, bp))) + goto out; + buf = XFS_BUF_PTR(bp) + (num_blks - 1) * BBSIZE; + } + + + for (i=(*last_blk)-1; i>=0; i--) { + if (i < start_blk) { + /* legal log record not found */ + xlog_warn("XFS: Log inconsistent (didn't find previous header)"); +#ifdef __KERNEL__ + ASSERT(0); +#endif + error = XFS_ERROR(EIO); + goto out; + } + + if (smallmem && (error = xlog_bread(log, i, 1, bp))) + goto out; + head = (xlog_rec_header_t*)buf; + + if (INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) + break; + + if (!smallmem) + buf -= BBSIZE; + } + + /* + * We hit the beginning of the physical log & still no header. Return + * to caller. If caller can handle a return of -1, then this routine + * will be called again for the end of the physical log. + */ + if (i == -1) { + error = -1; + goto out; + } + + /* we have the final block of the good log (the first block + * of the log record _before_ the head. So we check the uuid. + */ + + if ((error = xlog_header_check_mount(log->l_mp, head))) + goto out; + + /* + * We may have found a log record header before we expected one. + * last_blk will be the 1st block # with a given cycle #. We may end + * up reading an entire log record. In this case, we don't want to + * reset last_blk. Only when last_blk points in the middle of a log + * record do we update last_blk. + */ + if (*last_blk - i + extra_bblks + != BTOBB(INT_GET(head->h_len, ARCH_CONVERT))+1) + *last_blk = i; + +out: + xlog_put_bp(bp); + + return error; +} /* xlog_find_verify_log_record */ + +/* + * Head is defined to be the point of the log where the next log write + * write could go. This means that incomplete LR writes at the end are + * eliminated when calculating the head. We aren't guaranteed that previous + * LR have complete transactions. We only know that a cycle number of + * current cycle number -1 won't be present in the log if we start writing + * from our current block number. + * + * last_blk contains the block number of the first block with a given + * cycle number. + * + * Also called from xfs_log_print.c + * + * Return: zero if normal, non-zero if error. + */ +int +xlog_find_head(xlog_t *log, + xfs_daddr_t *return_head_blk) +{ + xfs_buf_t *bp; + xfs_daddr_t new_blk, first_blk, start_blk, last_blk, head_blk; + int num_scan_bblks; + uint first_half_cycle, last_half_cycle; + uint stop_on_cycle; + int error, log_bbnum = log->l_logBBsize; + + /* Is the end of the log device zeroed? */ + if ((error = xlog_find_zeroed(log, &first_blk)) == -1) { + *return_head_blk = first_blk; + + /* is the whole lot zeroed? */ + if (!first_blk) { + /* Linux XFS shouldn't generate totally zeroed logs - + * mkfs etc write a dummy unmount record to a fresh + * log so we can store the uuid in there + */ + xlog_warn("XFS: totally zeroed log\n"); + } + + return 0; + } else if (error) { + xlog_warn("XFS: empty log check failed"); + return error; + } + + first_blk = 0; /* get cycle # of 1st block */ + bp = xlog_get_bp(1,log->l_mp); + if (!bp) + return -ENOMEM; + if ((error = xlog_bread(log, 0, 1, bp))) + goto bp_err; + first_half_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + + last_blk = head_blk = log_bbnum-1; /* get cycle # of last block */ + if ((error = xlog_bread(log, last_blk, 1, bp))) + goto bp_err; + last_half_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + ASSERT(last_half_cycle != 0); + + /* + * If the 1st half cycle number is equal to the last half cycle number, + * then the entire log is stamped with the same cycle number. In this + * case, head_blk can't be set to zero (which makes sense). The below + * math doesn't work out properly with head_blk equal to zero. Instead, + * we set it to log_bbnum which is an illegal block number, but this + * value makes the math correct. If head_blk doesn't changed through + * all the tests below, *head_blk is set to zero at the very end rather + * than log_bbnum. In a sense, log_bbnum and zero are the same block + * in a circular file. + */ + if (first_half_cycle == last_half_cycle) { + /* + * In this case we believe that the entire log should have cycle + * number last_half_cycle. We need to scan backwards from the + * end verifying that there are no holes still containing + * last_half_cycle - 1. If we find such a hole, then the start + * of that hole will be the new head. The simple case looks like + * x | x ... | x - 1 | x + * Another case that fits this picture would be + * x | x + 1 | x ... | x + * In this case the head really is somwhere at the end of the + * log, as one of the latest writes at the beginning was incomplete. + * One more case is + * x | x + 1 | x ... | x - 1 | x + * This is really the combination of the above two cases, and the + * head has to end up at the start of the x-1 hole at the end of + * the log. + * + * In the 256k log case, we will read from the beginning to the + * end of the log and search for cycle numbers equal to x-1. We + * don't worry about the x+1 blocks that we encounter, because + * we know that they cannot be the head since the log started with + * x. + */ + head_blk = log_bbnum; + stop_on_cycle = last_half_cycle - 1; + } else { + /* + * In this case we want to find the first block with cycle number + * matching last_half_cycle. We expect the log to be some + * variation on + * x + 1 ... | x ... + * The first block with cycle number x (last_half_cycle) will be + * where the new head belongs. First we do a binary search for + * the first occurrence of last_half_cycle. The binary search + * may not be totally accurate, so then we scan back from there + * looking for occurrences of last_half_cycle before us. If + * that backwards scan wraps around the beginning of the log, + * then we look for occurrences of last_half_cycle - 1 at the + * end of the log. The cases we're looking for look like + * x + 1 ... | x | x + 1 | x ... + * ^ binary search stopped here + * or + * x + 1 ... | x ... | x - 1 | x + * <---------> less than scan distance + */ + stop_on_cycle = last_half_cycle; + if ((error = xlog_find_cycle_start(log, bp, first_blk, + &head_blk, last_half_cycle))) + goto bp_err; + } + + /* + * Now validate the answer. Scan back some number of maximum possible + * blocks and make sure each one has the expected cycle number. The + * maximum is determined by the total possible amount of buffering + * in the in-core log. The following number can be made tighter if + * we actually look at the block size of the filesystem. + */ + num_scan_bblks = BTOBB(XLOG_MAX_ICLOGS<= num_scan_bblks) { + /* + * We are guaranteed that the entire check can be performed + * in one buffer. + */ + start_blk = head_blk - num_scan_bblks; + new_blk = xlog_find_verify_cycle(log, start_blk, num_scan_bblks, + stop_on_cycle); + if (new_blk != -1) + head_blk = new_blk; + } else { /* need to read 2 parts of log */ + /* + * We are going to scan backwards in the log in two parts. First + * we scan the physical end of the log. In this part of the log, + * we are looking for blocks with cycle number last_half_cycle - 1. + * If we find one, then we know that the log starts there, as we've + * found a hole that didn't get written in going around the end + * of the physical log. The simple case for this is + * x + 1 ... | x ... | x - 1 | x + * <---------> less than scan distance + * If all of the blocks at the end of the log have cycle number + * last_half_cycle, then we check the blocks at the start of the + * log looking for occurrences of last_half_cycle. If we find one, + * then our current estimate for the location of the first + * occurrence of last_half_cycle is wrong and we move back to the + * hole we've found. This case looks like + * x + 1 ... | x | x + 1 | x ... + * ^ binary search stopped here + * Another case we need to handle that only occurs in 256k logs is + * x + 1 ... | x ... | x+1 | x ... + * ^ binary search stops here + * In a 256k log, the scan at the end of the log will see the x+1 + * blocks. We need to skip past those since that is certainly not + * the head of the log. By searching for last_half_cycle-1 we + * accomplish that. + */ + start_blk = log_bbnum - num_scan_bblks + head_blk; + ASSERT(head_blk <= INT_MAX && (xfs_daddr_t) num_scan_bblks-head_blk >= 0); + new_blk= xlog_find_verify_cycle(log, start_blk, + num_scan_bblks-(int)head_blk, (stop_on_cycle - 1)); + if (new_blk != -1) { + head_blk = new_blk; + goto bad_blk; + } + + /* + * Scan beginning of log now. The last part of the physical log + * is good. This scan needs to verify that it doesn't find the + * last_half_cycle. + */ + start_blk = 0; + ASSERT(head_blk <= INT_MAX); + new_blk = xlog_find_verify_cycle(log, start_blk, (int) head_blk, + stop_on_cycle); + if (new_blk != -1) + head_blk = new_blk; + } + +bad_blk: + /* + * Now we need to make sure head_blk is not pointing to a block in + * the middle of a log record. + */ + num_scan_bblks = BTOBB(XLOG_MAX_RECORD_BSIZE); + if (head_blk >= num_scan_bblks) { + start_blk = head_blk - num_scan_bblks; /* don't read head_blk */ + + /* start ptr at last block ptr before head_blk */ + if ((error = xlog_find_verify_log_record(log, + start_blk, + &head_blk, + 0)) == -1) { + error = XFS_ERROR(EIO); + goto bp_err; + } else if (error) + goto bp_err; + } else { + start_blk = 0; + ASSERT(head_blk <= INT_MAX); + if ((error = xlog_find_verify_log_record(log, + start_blk, + &head_blk, + 0)) == -1) { + /* We hit the beginning of the log during our search */ + start_blk = log_bbnum - num_scan_bblks + head_blk; + new_blk = log_bbnum; + ASSERT(start_blk <= INT_MAX && (xfs_daddr_t) log_bbnum-start_blk >= 0); + ASSERT(head_blk <= INT_MAX); + if ((error = xlog_find_verify_log_record(log, + start_blk, + &new_blk, + (int)head_blk)) == -1) { + error = XFS_ERROR(EIO); + goto bp_err; + } else if (error) + goto bp_err; + if (new_blk != log_bbnum) + head_blk = new_blk; + } else if (error) + goto bp_err; + } + + xlog_put_bp(bp); + if (head_blk == log_bbnum) + *return_head_blk = 0; + else + *return_head_blk = head_blk; + /* + * When returning here, we have a good block number. Bad block + * means that during a previous crash, we didn't have a clean break + * from cycle number N to cycle number N-1. In this case, we need + * to find the first block with cycle number N-1. + */ + return 0; + +bp_err: + xlog_put_bp(bp); + + if (error) + xlog_warn("XFS: failed to find log head"); + + return error; +} /* xlog_find_head */ + +/* + * Find the sync block number or the tail of the log. + * + * This will be the block number of the last record to have its + * associated buffers synced to disk. Every log record header has + * a sync lsn embedded in it. LSNs hold block numbers, so it is easy + * to get a sync block number. The only concern is to figure out which + * log record header to believe. + * + * The following algorithm uses the log record header with the largest + * lsn. The entire log record does not need to be valid. We only care + * that the header is valid. + * + * We could speed up search by using current head_blk buffer, but it is not + * available. + */ +int +xlog_find_tail(xlog_t *log, + xfs_daddr_t *head_blk, + xfs_daddr_t *tail_blk, + int readonly) +{ + xlog_rec_header_t *rhead; + xlog_op_header_t *op_head; + xfs_buf_t *bp; + int error, i, found; + xfs_daddr_t umount_data_blk; + xfs_daddr_t after_umount_blk; + xfs_lsn_t tail_lsn; + + found = error = 0; + + /* + * Find previous log record + */ + if ((error = xlog_find_head(log, head_blk))) + return error; + + bp = xlog_get_bp(1,log->l_mp); + if (!bp) + return -ENOMEM; + if (*head_blk == 0) { /* special case */ + if ((error = xlog_bread(log, 0, 1, bp))) + goto bread_err; + if (GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT) == 0) { + *tail_blk = 0; + /* leave all other log inited values alone */ + goto exit; + } + } + + /* + * Search backwards looking for log record header block + */ + ASSERT(*head_blk < INT_MAX); + for (i=(int)(*head_blk)-1; i>=0; i--) { + if ((error = xlog_bread(log, i, 1, bp))) + goto bread_err; + if (INT_GET(*(uint *)(XFS_BUF_PTR(bp)), ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) { + found = 1; + break; + } + } + /* + * If we haven't found the log record header block, start looking + * again from the end of the physical log. XXXmiken: There should be + * a check here to make sure we didn't search more than N blocks in + * the previous code. + */ + if (!found) { + for (i=log->l_logBBsize-1; i>=(int)(*head_blk); i--) { + if ((error = xlog_bread(log, i, 1, bp))) + goto bread_err; + if (INT_GET(*(uint*)(XFS_BUF_PTR(bp)), ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM) { + found = 2; + break; + } + } + } + if (!found) { + xlog_warn("XFS: xlog_find_tail: couldn't find sync record"); + ASSERT(0); + return XFS_ERROR(EIO); + } + + /* find blk_no of tail of log */ + rhead = (xlog_rec_header_t *)XFS_BUF_PTR(bp); + *tail_blk = BLOCK_LSN(rhead->h_tail_lsn, ARCH_CONVERT); + + /* + * Reset log values according to the state of the log when we + * crashed. In the case where head_blk == 0, we bump curr_cycle + * one because the next write starts a new cycle rather than + * continuing the cycle of the last good log record. At this + * point we have guaranteed that all partial log records have been + * accounted for. Therefore, we know that the last good log record + * written was complete and ended exactly on the end boundary + * of the physical log. + */ + log->l_prev_block = i; + log->l_curr_block = (int)*head_blk; + log->l_curr_cycle = INT_GET(rhead->h_cycle, ARCH_CONVERT); + if (found == 2) + log->l_curr_cycle++; + log->l_tail_lsn = INT_GET(rhead->h_tail_lsn, ARCH_CONVERT); + log->l_last_sync_lsn = INT_GET(rhead->h_lsn, ARCH_CONVERT); + log->l_grant_reserve_cycle = log->l_curr_cycle; + log->l_grant_reserve_bytes = BBTOB(log->l_curr_block); + log->l_grant_write_cycle = log->l_curr_cycle; + log->l_grant_write_bytes = BBTOB(log->l_curr_block); + + /* + * Look for unmount record. If we find it, then we know there + * was a clean unmount. Since 'i' could be the last block in + * the physical log, we convert to a log block before comparing + * to the head_blk. + * + * Save the current tail lsn to use to pass to + * xlog_clear_stale_blocks() below. We won't want to clear the + * unmount record if there is one, so we pass the lsn of the + * unmount record rather than the block after it. + */ + after_umount_blk = (i + 2) % log->l_logBBsize; + tail_lsn = log->l_tail_lsn; + if (*head_blk == after_umount_blk && INT_GET(rhead->h_num_logops, ARCH_CONVERT) == 1) { + umount_data_blk = (i + 1) % log->l_logBBsize; + if ((error = xlog_bread(log, umount_data_blk, 1, bp))) { + goto bread_err; + } + op_head = (xlog_op_header_t *)XFS_BUF_PTR(bp); + if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) { + /* + * Set tail and last sync so that newly written + * log records will point recovery to after the + * current unmount record. + */ + ASSIGN_ANY_LSN(log->l_tail_lsn, log->l_curr_cycle, + after_umount_blk, ARCH_NOCONVERT); + ASSIGN_ANY_LSN(log->l_last_sync_lsn, log->l_curr_cycle, + after_umount_blk, ARCH_NOCONVERT); + *tail_blk = after_umount_blk; + } + } + +#ifdef __KERNEL__ + /* + * Make sure that there are no blocks in front of the head + * with the same cycle number as the head. This can happen + * because we allow multiple outstanding log writes concurrently, + * and the later writes might make it out before earlier ones. + * + * We use the lsn from before modifying it so that we'll never + * overwrite the unmount record after a clean unmount. + * + * Do this only if we are going to recover the filesystem + */ + if (!readonly) + error = xlog_clear_stale_blocks(log, tail_lsn); +#endif + +bread_err: +exit: + xlog_put_bp(bp); + + if (error) + xlog_warn("XFS: failed to locate log tail"); + + return error; +} /* xlog_find_tail */ + + +/* + * Is the log zeroed at all? + * + * The last binary search should be changed to perform an X block read + * once X becomes small enough. You can then search linearly through + * the X blocks. This will cut down on the number of reads we need to do. + * + * If the log is partially zeroed, this routine will pass back the blkno + * of the first block with cycle number 0. It won't have a complete LR + * preceding it. + * + * Return: + * 0 => the log is completely written to + * -1 => use *blk_no as the first block of the log + * >0 => error has occurred + */ +int +xlog_find_zeroed(struct log *log, + xfs_daddr_t *blk_no) +{ + xfs_buf_t *bp; + uint first_cycle, last_cycle; + xfs_daddr_t new_blk, last_blk, start_blk; + xfs_daddr_t num_scan_bblks; + int error, log_bbnum = log->l_logBBsize; + + error = 0; + /* check totally zeroed log */ + bp = xlog_get_bp(1,log->l_mp); + if (!bp) + return -ENOMEM; + if ((error = xlog_bread(log, 0, 1, bp))) + goto bp_err; + first_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + if (first_cycle == 0) { /* completely zeroed log */ + *blk_no = 0; + xlog_put_bp(bp); + return -1; + } + + /* check partially zeroed log */ + if ((error = xlog_bread(log, log_bbnum-1, 1, bp))) + goto bp_err; + last_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT); + if (last_cycle != 0) { /* log completely written to */ + xlog_put_bp(bp); + return 0; + } else if (first_cycle != 1) { + /* + * If the cycle of the last block is zero, the cycle of + * the first block must be 1. If it's not, maybe we're + * not looking at a log... Bail out. + */ + xlog_warn("XFS: Log inconsistent or not a log (last==0, first!=1)"); + return XFS_ERROR(EINVAL); + } + + /* we have a partially zeroed log */ + last_blk = log_bbnum-1; + if ((error = xlog_find_cycle_start(log, bp, 0, &last_blk, 0))) + goto bp_err; + + /* + * Validate the answer. Because there is no way to guarantee that + * the entire log is made up of log records which are the same size, + * we scan over the defined maximum blocks. At this point, the maximum + * is not chosen to mean anything special. XXXmiken + */ + num_scan_bblks = BTOBB(XLOG_MAX_ICLOGS<l_mp))) { + if (!(bp = xlog_get_bp(1, log->l_mp))) + return -ENOMEM; + smallmem = 1; + } + + buf = XFS_BUF_PTR(bp); + recp = (xlog_rec_header_t*)buf; + + memset(buf, 0, BBSIZE); + INT_SET(recp->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM); + INT_SET(recp->h_cycle, ARCH_CONVERT, cycle); + INT_SET(recp->h_version, ARCH_CONVERT, 1); + INT_ZERO(recp->h_len, ARCH_CONVERT); + ASSIGN_ANY_LSN(recp->h_tail_lsn, tail_cycle, tail_block, ARCH_CONVERT); + INT_ZERO(recp->h_chksum, ARCH_CONVERT); + INT_ZERO(recp->h_prev_block, ARCH_CONVERT); /* unused */ + INT_ZERO(recp->h_num_logops, ARCH_CONVERT); + + if (smallmem) { + /* for small mem, we keep modifying the block and writing */ + for (i = start_block; i < start_block + blocks; i++) { + ASSIGN_ANY_LSN(recp->h_lsn, cycle, i, ARCH_CONVERT); + if ((error = xlog_bwrite(log, i, 1, bp))) + break; + } + } else { + ASSIGN_ANY_LSN(recp->h_lsn, cycle, start_block, ARCH_CONVERT); + for (i = start_block+1; i < start_block + blocks; i++) { + /* with plenty of memory, we duplicate the block + * right through the buffer and modify each entry + */ + buf += BBSIZE; + recp = (xlog_rec_header_t*)buf; + memcpy(buf, XFS_BUF_PTR(bp), BBSIZE); + ASSIGN_ANY_LSN(recp->h_lsn, cycle, i, ARCH_CONVERT); + } + /* then write the whole lot out at once */ + error = xlog_bwrite(log, start_block, blocks, bp); + } + xlog_put_bp(bp); + + return error; +} + +/* + * This routine is called to blow away any incomplete log writes out + * in front of the log head. We do this so that we won't become confused + * if we come up, write only a little bit more, and then crash again. + * If we leave the partial log records out there, this situation could + * cause us to think those partial writes are valid blocks since they + * have the current cycle number. We get rid of them by overwriting them + * with empty log records with the old cycle number rather than the + * current one. + * + * The tail lsn is passed in rather than taken from + * the log so that we will not write over the unmount record after a + * clean unmount in a 512 block log. Doing so would leave the log without + * any valid log records in it until a new one was written. If we crashed + * during that time we would not be able to recover. + */ +STATIC int +xlog_clear_stale_blocks( + xlog_t *log, + xfs_lsn_t tail_lsn) +{ + int tail_cycle; + int head_cycle; + int tail_block; + int head_block; + int tail_distance; + int max_distance; + int distance; + int error; + + tail_cycle = CYCLE_LSN(tail_lsn, ARCH_NOCONVERT); + tail_block = BLOCK_LSN(tail_lsn, ARCH_NOCONVERT); + head_cycle = log->l_curr_cycle; + head_block = log->l_curr_block; + + /* + * Figure out the distance between the new head of the log + * and the tail. We want to write over any blocks beyond the + * head that we may have written just before the crash, but + * we don't want to overwrite the tail of the log. + */ + if (head_cycle == tail_cycle) { + /* + * The tail is behind the head in the physical log, + * so the distance from the head to the tail is the + * distance from the head to the end of the log plus + * the distance from the beginning of the log to the + * tail. + */ + if (head_block < tail_block || head_block >= log->l_logBBsize) + return XFS_ERROR(EFSCORRUPTED); + tail_distance = tail_block + + (log->l_logBBsize - head_block); + } else { + /* + * The head is behind the tail in the physical log, + * so the distance from the head to the tail is just + * the tail block minus the head block. + */ + if (head_block >= tail_block || head_cycle != (tail_cycle + 1)) + return XFS_ERROR(EFSCORRUPTED); + tail_distance = tail_block - head_block; + } + + /* + * If the head is right up against the tail, we can't clear + * anything. + */ + if (tail_distance <= 0) { + ASSERT(tail_distance == 0); + return 0; + } + + max_distance = BTOBB(XLOG_MAX_ICLOGS << XLOG_MAX_RECORD_BSHIFT); + /* + * Take the smaller of the maximum amount of outstanding I/O + * we could have and the distance to the tail to clear out. + * We take the smaller so that we don't overwrite the tail and + * we don't waste all day writing from the head to the tail + * for no reason. + */ + max_distance = MIN(max_distance, tail_distance); + + if ((head_block + max_distance) <= log->l_logBBsize) { + /* + * We can stomp all the blocks we need to without + * wrapping around the end of the log. Just do it + * in a single write. Use the cycle number of the + * current cycle minus one so that the log will look like: + * n ... | n - 1 ... + */ + error = xlog_write_log_records(log, (head_cycle - 1), + head_block, max_distance, tail_cycle, + tail_block); + } else { + /* + * We need to wrap around the end of the physical log in + * order to clear all the blocks. Do it in two separate + * I/Os. The first write should be from the head to the + * end of the physical log, and it should use the current + * cycle number minus one just like above. + */ + distance = log->l_logBBsize - head_block; + error = xlog_write_log_records(log, (head_cycle - 1), + head_block, distance, tail_cycle, + tail_block); + + if (error) + return error; + + /* + * Now write the blocks at the start of the physical log. + * This writes the remainder of the blocks we want to clear. + * It uses the current cycle number since we're now on the + * same cycle as the head so that we get: + * n ... n ... | n - 1 ... + * ^^^^^ blocks we're writing + */ + distance = max_distance - (log->l_logBBsize - head_block); + error = xlog_write_log_records(log, head_cycle, 0, distance, + tail_cycle, tail_block); + } + + return 0; +} + +/****************************************************************************** + * + * Log recover routines + * + ****************************************************************************** + */ + +STATIC xlog_recover_t * +xlog_recover_find_tid(xlog_recover_t *q, + xlog_tid_t tid) +{ + xlog_recover_t *p = q; + + while (p != NULL) { + if (p->r_log_tid == tid) + break; + p = p->r_next; + } + return p; +} /* xlog_recover_find_tid */ + + +STATIC void +xlog_recover_put_hashq(xlog_recover_t **q, + xlog_recover_t *trans) +{ + trans->r_next = *q; + *q = trans; +} /* xlog_recover_put_hashq */ + + +STATIC void +xlog_recover_add_item(xlog_recover_item_t **itemq) +{ + xlog_recover_item_t *item; + + item = kmem_zalloc(sizeof(xlog_recover_item_t), 0); + xlog_recover_insert_item_backq(itemq, item); +} /* xlog_recover_add_item */ + + +STATIC int +xlog_recover_add_to_cont_trans(xlog_recover_t *trans, + xfs_caddr_t dp, + int len) +{ + xlog_recover_item_t *item; + xfs_caddr_t ptr, old_ptr; + int old_len; + + item = trans->r_itemq; + if (item == 0) { + /* finish copying rest of trans header */ + xlog_recover_add_item(&trans->r_itemq); + ptr = (xfs_caddr_t)&trans->r_theader+sizeof(xfs_trans_header_t)-len; + bcopy(dp, ptr, len); /* s, d, l */ + return 0; + } + item = item->ri_prev; + + old_ptr = item->ri_buf[item->ri_cnt-1].i_addr; + old_len = item->ri_buf[item->ri_cnt-1].i_len; + + ptr = kmem_realloc(old_ptr, len+old_len, old_len, 0); + bcopy(dp , &ptr[old_len], len); /* s, d, l */ + item->ri_buf[item->ri_cnt-1].i_len += len; + item->ri_buf[item->ri_cnt-1].i_addr = ptr; + return 0; +} /* xlog_recover_add_to_cont_trans */ + + +/* The next region to add is the start of a new region. It could be + * a whole region or it could be the first part of a new region. Because + * of this, the assumption here is that the type and size fields of all + * format structures fit into the first 32 bits of the structure. + * + * This works because all regions must be 32 bit aligned. Therefore, we + * either have both fields or we have neither field. In the case we have + * neither field, the data part of the region is zero length. We only have + * a log_op_header and can throw away the header since a new one will appear + * later. If we have at least 4 bytes, then we can determine how many regions + * will appear in the current log item. + */ +STATIC int +xlog_recover_add_to_trans(xlog_recover_t *trans, + xfs_caddr_t dp, + int len) +{ + xfs_inode_log_format_t *in_f; /* any will do */ + xlog_recover_item_t *item; + xfs_caddr_t ptr; + + if (!len) + return 0; + ptr = kmem_zalloc(len, 0); + bcopy(dp, ptr, len); + + in_f = (xfs_inode_log_format_t *)ptr; + item = trans->r_itemq; + if (item == 0) { + ASSERT(*(uint *)dp == XFS_TRANS_HEADER_MAGIC); + if (len == sizeof(xfs_trans_header_t)) + xlog_recover_add_item(&trans->r_itemq); + bcopy(dp, &trans->r_theader, len); /* s, d, l */ + return 0; + } + if (item->ri_prev->ri_total != 0 && + item->ri_prev->ri_total == item->ri_prev->ri_cnt) { + xlog_recover_add_item(&trans->r_itemq); + } + item = trans->r_itemq; + item = item->ri_prev; + + if (item->ri_total == 0) { /* first region to be added */ + item->ri_total = in_f->ilf_size; + ASSERT(item->ri_total <= XLOG_MAX_REGIONS_IN_ITEM); + item->ri_buf = kmem_zalloc((item->ri_total * + sizeof(xfs_log_iovec_t)), 0); + } + ASSERT(item->ri_total > item->ri_cnt); + /* Description region is ri_buf[0] */ + item->ri_buf[item->ri_cnt].i_addr = ptr; + item->ri_buf[item->ri_cnt].i_len = len; + item->ri_cnt++; + return 0; +} /* xlog_recover_add_to_trans */ + + +STATIC void +xlog_recover_new_tid(xlog_recover_t **q, + xlog_tid_t tid, + xfs_lsn_t lsn) +{ + xlog_recover_t *trans; + + trans = kmem_zalloc(sizeof(xlog_recover_t), 0); + trans->r_log_tid = tid; + trans->r_lsn = lsn; + xlog_recover_put_hashq(q, trans); +} /* xlog_recover_new_tid */ + + +STATIC int +xlog_recover_unlink_tid(xlog_recover_t **q, + xlog_recover_t *trans) +{ + xlog_recover_t *tp; + int found = 0; + + ASSERT(trans != 0); + if (trans == *q) { + *q = (*q)->r_next; + } else { + tp = *q; + while (tp != 0) { + if (tp->r_next == trans) { + found = 1; + break; + } + tp = tp->r_next; + } + if (!found) { + xlog_warn( + "XFS: xlog_recover_unlink_tid: trans not found"); + ASSERT(0); + return XFS_ERROR(EIO); + } + tp->r_next = tp->r_next->r_next; + } + return 0; +} /* xlog_recover_unlink_tid */ + +STATIC void +xlog_recover_insert_item_backq(xlog_recover_item_t **q, + xlog_recover_item_t *item) +{ + if (*q == 0) { + item->ri_prev = item->ri_next = item; + *q = item; + } else { + item->ri_next = *q; + item->ri_prev = (*q)->ri_prev; + (*q)->ri_prev = item; + item->ri_prev->ri_next = item; + } +} /* xlog_recover_insert_item_backq */ + +STATIC void +xlog_recover_insert_item_frontq(xlog_recover_item_t **q, + xlog_recover_item_t *item) +{ + xlog_recover_insert_item_backq(q, item); + *q = item; +} /* xlog_recover_insert_item_frontq */ + +STATIC int +xlog_recover_reorder_trans(xlog_t *log, + xlog_recover_t *trans) +{ + xlog_recover_item_t *first_item, *itemq, *itemq_next; + + first_item = itemq = trans->r_itemq; + trans->r_itemq = NULL; + do { + itemq_next = itemq->ri_next; + switch (ITEM_TYPE(itemq)) { + case XFS_LI_BUF: + case XFS_LI_6_1_BUF: + case XFS_LI_5_3_BUF: { + xlog_recover_insert_item_frontq(&trans->r_itemq, itemq); + break; + } + case XFS_LI_INODE: + case XFS_LI_6_1_INODE: + case XFS_LI_5_3_INODE: + case XFS_LI_DQUOT: + case XFS_LI_QUOTAOFF: + case XFS_LI_EFD: + case XFS_LI_EFI: { + xlog_recover_insert_item_backq(&trans->r_itemq, itemq); + break; + } + default: { + xlog_warn( + "XFS: xlog_recover_reorder_trans: unrecognized type of log operation"); + ASSERT(0); + return XFS_ERROR(EIO); + } + } + itemq = itemq_next; + } while (first_item != itemq); + return 0; +} /* xlog_recover_reorder_trans */ + + +/* + * Build up the table of buf cancel records so that we don't replay + * cancelled data in the second pass. For buffer records that are + * not cancel records, there is nothing to do here so we just return. + * + * If we get a cancel record which is already in the table, this indicates + * that the buffer was cancelled multiple times. In order to ensure + * that during pass 2 we keep the record in the table until we reach its + * last occurrence in the log, we keep a reference count in the cancel + * record in the table to tell us how many times we expect to see this + * record during the second pass. + */ +STATIC void +xlog_recover_do_buffer_pass1(xlog_t *log, + xfs_buf_log_format_t *buf_f) +{ + xfs_buf_cancel_t *bcp; + xfs_buf_cancel_t *nextp; + xfs_buf_cancel_t *prevp; + xfs_buf_cancel_t **bucket; + xfs_buf_log_format_v1_t *obuf_f; + xfs_daddr_t blkno=0; + uint len=0; + ushort flags=0; + + switch (buf_f->blf_type) { + case XFS_LI_BUF: + blkno = buf_f->blf_blkno; + len = buf_f->blf_len; + flags = buf_f->blf_flags; + break; + case XFS_LI_6_1_BUF: + case XFS_LI_5_3_BUF: + obuf_f = (xfs_buf_log_format_v1_t*)buf_f; + blkno = (xfs_daddr_t) obuf_f->blf_blkno; + len = obuf_f->blf_len; + flags = obuf_f->blf_flags; + break; + } + + /* + * If this isn't a cancel buffer item, then just return. + */ + if (!(flags & XFS_BLI_CANCEL)) { + return; + } + + /* + * Insert an xfs_buf_cancel record into the hash table of + * them. If there is already an identical record, bump + * its reference count. + */ + bucket = &log->l_buf_cancel_table[(__uint64_t)blkno % + XLOG_BC_TABLE_SIZE]; + /* + * If the hash bucket is empty then just insert a new record into + * the bucket. + */ + if (*bucket == NULL) { + bcp = (xfs_buf_cancel_t*)kmem_alloc(sizeof(xfs_buf_cancel_t), + KM_SLEEP); + bcp->bc_blkno = blkno; + bcp->bc_len = len; + bcp->bc_refcount = 1; + bcp->bc_next = NULL; + *bucket = bcp; + return; + } + + /* + * The hash bucket is not empty, so search for duplicates of our + * record. If we find one them just bump its refcount. If not + * then add us at the end of the list. + */ + prevp = NULL; + nextp = *bucket; + while (nextp != NULL) { + if (nextp->bc_blkno == blkno && nextp->bc_len == len) { + nextp->bc_refcount++; + return; + } + prevp = nextp; + nextp = nextp->bc_next; + } + ASSERT(prevp != NULL); + bcp = (xfs_buf_cancel_t*)kmem_alloc(sizeof(xfs_buf_cancel_t), + KM_SLEEP); + bcp->bc_blkno = blkno; + bcp->bc_len = len; + bcp->bc_refcount = 1; + bcp->bc_next = NULL; + prevp->bc_next = bcp; +} + +/* + * Check to see whether the buffer being recovered has a corresponding + * entry in the buffer cancel record table. If it does then return 1 + * so that it will be cancelled, otherwise return 0. If the buffer is + * actually a buffer cancel item (XFS_BLI_CANCEL is set), then decrement + * the refcount on the entry in the table and remove it from the table + * if this is the last reference. + * + * We remove the cancel record from the table when we encounter its + * last occurrence in the log so that if the same buffer is re-used + * again after its last cancellation we actually replay the changes + * made at that point. + */ +STATIC int +xlog_recover_do_buffer_pass2(xlog_t *log, + xfs_buf_log_format_t *buf_f) +{ + xfs_buf_cancel_t *bcp; + xfs_buf_cancel_t *prevp; + xfs_buf_cancel_t **bucket; + xfs_buf_log_format_v1_t *obuf_f; + xfs_daddr_t blkno=0; + ushort flags=0; + uint len=0; + + + switch (buf_f->blf_type) { + case XFS_LI_BUF: + blkno = buf_f->blf_blkno; + flags = buf_f->blf_flags; + len = buf_f->blf_len; + break; + case XFS_LI_6_1_BUF: + case XFS_LI_5_3_BUF: + obuf_f = (xfs_buf_log_format_v1_t*)buf_f; + blkno = (xfs_daddr_t) obuf_f->blf_blkno; + flags = obuf_f->blf_flags; + len = (xfs_daddr_t) obuf_f->blf_len; + break; + } + if (log->l_buf_cancel_table == NULL) { + /* + * There is nothing in the table built in pass one, + * so this buffer must not be cancelled. + */ + ASSERT(!(flags & XFS_BLI_CANCEL)); + return 0; + } + + bucket = &log->l_buf_cancel_table[(__uint64_t)blkno % + XLOG_BC_TABLE_SIZE]; + bcp = *bucket; + if (bcp == NULL) { + /* + * There is no corresponding entry in the table built + * in pass one, so this buffer has not been cancelled. + */ + ASSERT(!(flags & XFS_BLI_CANCEL)); + return 0; + } + + /* + * Search for an entry in the buffer cancel table that + * matches our buffer. + */ + prevp = NULL; + while (bcp != NULL) { + if (bcp->bc_blkno == blkno && bcp->bc_len == len) { + /* + * We've go a match, so return 1 so that the + * recovery of this buffer is cancelled. + * If this buffer is actually a buffer cancel + * log item, then decrement the refcount on the + * one in the table and remove it if this is the + * last reference. + */ + if (flags & XFS_BLI_CANCEL) { + bcp->bc_refcount--; + if (bcp->bc_refcount == 0) { + if (prevp == NULL) { + *bucket = bcp->bc_next; + } else { + prevp->bc_next = bcp->bc_next; + } + kmem_free(bcp, + sizeof(xfs_buf_cancel_t)); + } + } + return 1; + } + prevp = bcp; + bcp = bcp->bc_next; + } + /* + * We didn't find a corresponding entry in the table, so + * return 0 so that the buffer is NOT cancelled. + */ + ASSERT(!(flags & XFS_BLI_CANCEL)); + return 0; +} + + +/* + * Perform recovery for a buffer full of inodes. In these buffers, + * the only data which should be recovered is that which corresponds + * to the di_next_unlinked pointers in the on disk inode structures. + * The rest of the data for the inodes is always logged through the + * inodes themselves rather than the inode buffer and is recovered + * in xlog_recover_do_inode_trans(). + * + * The only time when buffers full of inodes are fully recovered is + * when the buffer is full of newly allocated inodes. In this case + * the buffer will not be marked as an inode buffer and so will be + * sent to xlog_recover_do_reg_buffer() below during recovery. + */ +STATIC int +xlog_recover_do_inode_buffer(xfs_mount_t *mp, + xlog_recover_item_t *item, + xfs_buf_t *bp, + xfs_buf_log_format_t *buf_f) +{ + int i; + int item_index; + int bit; + int nbits; + int reg_buf_offset; + int reg_buf_bytes; + int next_unlinked_offset; + int inodes_per_buf; + xfs_agino_t *logged_nextp; + xfs_agino_t *buffer_nextp; + xfs_buf_log_format_v1_t *obuf_f; + unsigned int *data_map=NULL; + unsigned int map_size=0; + + switch (buf_f->blf_type) { + case XFS_LI_BUF: + data_map = buf_f->blf_data_map; + map_size = buf_f->blf_map_size; + break; + case XFS_LI_6_1_BUF: + case XFS_LI_5_3_BUF: + obuf_f = (xfs_buf_log_format_v1_t*)buf_f; + data_map = obuf_f->blf_data_map; + map_size = obuf_f->blf_map_size; + break; + } + /* + * Set the variables corresponding to the current region to + * 0 so that we'll initialize them on the first pass through + * the loop. + */ + reg_buf_offset = 0; + reg_buf_bytes = 0; + bit = 0; + nbits = 0; + item_index = 0; + inodes_per_buf = XFS_BUF_COUNT(bp) >> mp->m_sb.sb_inodelog; + for (i = 0; i < inodes_per_buf; i++) { + next_unlinked_offset = (i * mp->m_sb.sb_inodesize) + + offsetof(xfs_dinode_t, di_next_unlinked); + + while (next_unlinked_offset >= + (reg_buf_offset + reg_buf_bytes)) { + /* + * The next di_next_unlinked field is beyond + * the current logged region. Find the next + * logged region that contains or is beyond + * the current di_next_unlinked field. + */ + bit += nbits; + bit = xfs_buf_item_next_bit(data_map, map_size, bit); + + /* + * If there are no more logged regions in the + * buffer, then we're done. + */ + if (bit == -1) { + return 0; + } + + nbits = xfs_buf_item_contig_bits(data_map, map_size, + bit); + reg_buf_offset = bit << XFS_BLI_SHIFT; + reg_buf_bytes = nbits << XFS_BLI_SHIFT; + item_index++; + } + + /* + * If the current logged region starts after the current + * di_next_unlinked field, then move on to the next + * di_next_unlinked field. + */ + if (next_unlinked_offset < reg_buf_offset) { + continue; + } + + ASSERT(item->ri_buf[item_index].i_addr != NULL); + ASSERT((item->ri_buf[item_index].i_len % XFS_BLI_CHUNK) == 0); + ASSERT((reg_buf_offset + reg_buf_bytes) <= XFS_BUF_COUNT(bp)); + + /* + * The current logged region contains a copy of the + * current di_next_unlinked field. Extract its value + * and copy it to the buffer copy. + */ + logged_nextp = (xfs_agino_t *) + ((char *)(item->ri_buf[item_index].i_addr) + + (next_unlinked_offset - reg_buf_offset)); + if (*logged_nextp == 0) { + xfs_fs_cmn_err(CE_ALERT, mp, + "bad inode buffer log record (ptr = 0x%p, bp = 0x%p). XFS trying to replay bad (0) inode di_next_unlinked field", + item, bp); + return XFS_ERROR(EFSCORRUPTED); + } + + buffer_nextp = (xfs_agino_t *)xfs_buf_offset(bp, + next_unlinked_offset); + INT_SET(*buffer_nextp, ARCH_CONVERT, *logged_nextp); + } + + return 0; +} /* xlog_recover_do_inode_buffer */ + +/* + * Perform a 'normal' buffer recovery. Each logged region of the + * buffer should be copied over the corresponding region in the + * given buffer. The bitmap in the buf log format structure indicates + * where to place the logged data. + */ +/*ARGSUSED*/ +STATIC void +xlog_recover_do_reg_buffer(xfs_mount_t *mp, + xlog_recover_item_t *item, + xfs_buf_t *bp, + xfs_buf_log_format_t *buf_f) +{ + int i; + int bit; + int nbits; + xfs_buf_log_format_v1_t *obuf_f; + unsigned int *data_map=NULL; + unsigned int map_size=0; + int error; + + switch (buf_f->blf_type) { + case XFS_LI_BUF: + data_map = buf_f->blf_data_map; + map_size = buf_f->blf_map_size; + break; + case XFS_LI_6_1_BUF: + case XFS_LI_5_3_BUF: + obuf_f = (xfs_buf_log_format_v1_t*)buf_f; + data_map = obuf_f->blf_data_map; + map_size = obuf_f->blf_map_size; + break; + } + bit = 0; + i = 1; /* 0 is the buf format structure */ + while (1) { + bit = xfs_buf_item_next_bit(data_map, map_size, bit); + if (bit == -1) + break; + nbits = xfs_buf_item_contig_bits(data_map, map_size, bit); + ASSERT(item->ri_buf[i].i_addr != 0); + ASSERT(item->ri_buf[i].i_len % XFS_BLI_CHUNK == 0); + ASSERT(XFS_BUF_COUNT(bp) >= + ((uint)bit << XFS_BLI_SHIFT)+(nbits<blf_flags & (XFS_BLI_UDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) { + /* OK, if this returns nopkg() */ + error = xfs_qm_dqcheck((xfs_disk_dquot_t *) + item->ri_buf[i].i_addr, + -1, 0, XFS_QMOPT_DOWARN, + "dquot_buf_recover"); + } + if (!error) + bcopy(item->ri_buf[i].i_addr, /* source */ + xfs_buf_offset(bp, (uint)bit << XFS_BLI_SHIFT), /* dest */ + nbits<ri_total); +} /* xlog_recover_do_reg_buffer */ + + +/* + * Perform a dquot buffer recovery. + * Simple algorithm: if we have found a QUOTAOFF logitem of the same type + * (ie. USR or GRP), then just toss this buffer away; don't recover it. + * Else, treat it as a regular buffer and do recovery. + */ +STATIC void +xlog_recover_do_dquot_buffer( + xfs_mount_t *mp, + xlog_t *log, + xlog_recover_item_t *item, + xfs_buf_t *bp, + xfs_buf_log_format_t *buf_f) +{ + uint type; + + /* + * Non-root filesystems are required to send in quota flags + * at mount time. However, we may also get QUOTA_MAYBE flag set, + * indicating that quota should stay on (and stay consistent), + * if it already is. (so, we have to replay dquot log records + * when MAYBE flag's set). + */ + if (mp->m_qflags == 0 && mp->m_dev != rootdev) { + return; + } + + type = 0; + if (buf_f->blf_flags & XFS_BLI_UDQUOT_BUF) + type |= XFS_DQ_USER; + if (buf_f->blf_flags & XFS_BLI_GDQUOT_BUF) + type |= XFS_DQ_GROUP; + /* + * This type of quotas was turned off, so ignore this buffer + */ + if (log->l_quotaoffs_flag & type) + return; + + xlog_recover_do_reg_buffer(mp, item, bp, buf_f); +} + +/* + * This routine replays a modification made to a buffer at runtime. + * There are actually two types of buffer, regular and inode, which + * are handled differently. Inode buffers are handled differently + * in that we only recover a specific set of data from them, namely + * the inode di_next_unlinked fields. This is because all other inode + * data is actually logged via inode records and any data we replay + * here which overlaps that may be stale. + * + * When meta-data buffers are freed at run time we log a buffer item + * with the XFS_BLI_CANCEL bit set to indicate that previous copies + * of the buffer in the log should not be replayed at recovery time. + * This is so that if the blocks covered by the buffer are reused for + * file data before we crash we don't end up replaying old, freed + * meta-data into a user's file. + * + * To handle the cancellation of buffer log items, we make two passes + * over the log during recovery. During the first we build a table of + * those buffers which have been cancelled, and during the second we + * only replay those buffers which do not have corresponding cancel + * records in the table. See xlog_recover_do_buffer_pass[1,2] above + * for more details on the implementation of the table of cancel records. + */ +STATIC int +xlog_recover_do_buffer_trans(xlog_t *log, + xlog_recover_item_t *item, + int pass) +{ + xfs_buf_log_format_t *buf_f; + xfs_buf_log_format_v1_t *obuf_f; + xfs_mount_t *mp; + xfs_buf_t *bp; + int error; + int cancel; + xfs_daddr_t blkno; + int len; + ushort flags; + + buf_f = (xfs_buf_log_format_t *)item->ri_buf[0].i_addr; + + if (pass == XLOG_RECOVER_PASS1) { + /* + * In this pass we're only looking for buf items + * with the XFS_BLI_CANCEL bit set. + */ + xlog_recover_do_buffer_pass1(log, buf_f); + return 0; + } else { + /* + * In this pass we want to recover all the buffers + * which have not been cancelled and are not + * cancellation buffers themselves. The routine + * we call here will tell us whether or not to + * continue with the replay of this buffer. + */ + cancel = xlog_recover_do_buffer_pass2(log, buf_f); + if (cancel) { + return 0; + } + } + switch (buf_f->blf_type) { + case XFS_LI_BUF: + blkno = buf_f->blf_blkno; + len = buf_f->blf_len; + flags = buf_f->blf_flags; + break; + case XFS_LI_6_1_BUF: + case XFS_LI_5_3_BUF: + obuf_f = (xfs_buf_log_format_v1_t*)buf_f; + blkno = obuf_f->blf_blkno; + len = obuf_f->blf_len; + flags = obuf_f->blf_flags; + break; + default: + xfs_fs_cmn_err(CE_ALERT, log->l_mp, + "xfs_log_recover: unknown buffer type 0x%x, dev 0x%x", + buf_f->blf_type, log->l_dev); + return XFS_ERROR(EFSCORRUPTED); + } + + mp = log->l_mp; + if (flags & XFS_BLI_INODE_BUF) { + bp = xfs_buf_read_flags(mp->m_ddev_targp, blkno, len, + XFS_BUF_LOCK); + } else { + bp = xfs_buf_read(mp->m_ddev_targp, blkno, len, 0); + } + if (XFS_BUF_ISERROR(bp)) { + xfs_ioerror_alert("xlog_recover_do..(read)", log->l_mp, + mp->m_dev, blkno); + error = XFS_BUF_GETERROR(bp); + xfs_buf_relse(bp); + return error; + } + + error = 0; + if (flags & XFS_BLI_INODE_BUF) { + error = xlog_recover_do_inode_buffer(mp, item, bp, buf_f); + } else if (flags & (XFS_BLI_UDQUOT_BUF | XFS_BLI_GDQUOT_BUF)) { + xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f); + } else { + xlog_recover_do_reg_buffer(mp, item, bp, buf_f); + } + if (error) + return XFS_ERROR(error); + + /* + * Perform delayed write on the buffer. Asynchronous writes will be + * slower when taking into account all the buffers to be flushed. + * + * Also make sure that only inode buffers with good sizes stay in + * the buffer cache. The kernel moves inodes in buffers of 1 block + * or XFS_INODE_CLUSTER_SIZE bytes, whichever is bigger. The inode + * buffers in the log can be a different size if the log was generated + * by an older kernel using unclustered inode buffers or a newer kernel + * running with a different inode cluster size. Regardless, if the + * the inode buffer size isn't MAX(blocksize, XFS_INODE_CLUSTER_SIZE) + * for *our* value of XFS_INODE_CLUSTER_SIZE, then we need to keep + * the buffer out of the buffer cache so that the buffer won't + * overlap with future reads of those inodes. + */ + error = 0; + if ((INT_GET(*((__uint16_t *)(xfs_buf_offset(bp, 0))), ARCH_CONVERT) == XFS_DINODE_MAGIC) && + (XFS_BUF_COUNT(bp) != MAX(log->l_mp->m_sb.sb_blocksize, + XFS_INODE_CLUSTER_SIZE(log->l_mp)))) { + XFS_BUF_STALE(bp); + error = xfs_bwrite(mp, bp); + } else { + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL || + XFS_BUF_FSPRIVATE(bp, xfs_mount_t *) == mp); + XFS_BUF_SET_FSPRIVATE(bp, mp); + XFS_BUF_SET_IODONE_FUNC(bp, xlog_recover_iodone); + xfs_bdwrite(mp, bp); + } + + return (error); +} /* xlog_recover_do_buffer_trans */ + +STATIC int +xlog_recover_do_inode_trans(xlog_t *log, + xlog_recover_item_t *item, + int pass) +{ + xfs_inode_log_format_t *in_f; + xfs_mount_t *mp; + xfs_buf_t *bp; + xfs_imap_t imap; + xfs_dinode_t *dip; + xfs_ino_t ino; + int len; + xfs_caddr_t src; + xfs_caddr_t dest; + int error; + int attr_index; + uint fields; + xfs_dinode_core_t *dicp; + + if (pass == XLOG_RECOVER_PASS1) { + return 0; + } + + in_f = (xfs_inode_log_format_t *)item->ri_buf[0].i_addr; + ino = in_f->ilf_ino; + mp = log->l_mp; + if (ITEM_TYPE(item) == XFS_LI_INODE) { + imap.im_blkno = (xfs_daddr_t)in_f->ilf_blkno; + imap.im_len = in_f->ilf_len; + imap.im_boffset = in_f->ilf_boffset; + } else { + /* + * It's an old inode format record. We don't know where + * its cluster is located on disk, and we can't allow + * xfs_imap() to figure it out because the inode btrees + * are not ready to be used. Therefore do not pass the + * XFS_IMAP_LOOKUP flag to xfs_imap(). This will give + * us only the single block in which the inode lives + * rather than its cluster, so we must make sure to + * invalidate the buffer when we write it out below. + */ + imap.im_blkno = 0; + xfs_imap(log->l_mp, 0, ino, &imap, 0); + } + bp = xfs_buf_read_flags(mp->m_ddev_targp, imap.im_blkno, imap.im_len, + XFS_BUF_LOCK); + if (XFS_BUF_ISERROR(bp)) { + xfs_ioerror_alert("xlog_recover_do..(read)", mp, + mp->m_dev, imap.im_blkno); + error = XFS_BUF_GETERROR(bp); + xfs_buf_relse(bp); + return error; + } + error = 0; + xfs_inobp_check(mp, bp); + ASSERT(in_f->ilf_fields & XFS_ILOG_CORE); + dip = (xfs_dinode_t *)xfs_buf_offset(bp, imap.im_boffset); + + /* + * Make sure the place we're flushing out to really looks + * like an inode! + */ + if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) { + xfs_buf_relse(bp); + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_inode_recover: Bad inode magic number, dino ptr = 0x%p, dino bp = 0x%p, ino = %Ld", + dip, bp, ino); + return XFS_ERROR(EFSCORRUPTED); + } + dicp = (xfs_dinode_core_t*)(item->ri_buf[1].i_addr); + if (dicp->di_magic != XFS_DINODE_MAGIC) { + xfs_buf_relse(bp); + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_inode_recover: Bad inode log record, rec ptr 0x%p, ino %Ld", + item, ino); + return XFS_ERROR(EFSCORRUPTED); + } + if ((dicp->di_mode & IFMT) == IFREG) { + if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) && + (dicp->di_format != XFS_DINODE_FMT_BTREE)) { + xfs_buf_relse(bp); + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_inode_recover: Bad regular inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", + item, dip, bp, ino); + return XFS_ERROR(EFSCORRUPTED); + } + } else if ((dicp->di_mode & IFMT) == IFDIR) { + if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) && + (dicp->di_format != XFS_DINODE_FMT_BTREE) && + (dicp->di_format != XFS_DINODE_FMT_LOCAL)) { + xfs_buf_relse(bp); + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_inode_recover: Bad dir inode log record, rec ptr 0x%p, ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", + item, dip, bp, ino); + return XFS_ERROR(EFSCORRUPTED); + } + } + if (dicp->di_nextents + dicp->di_anextents > dicp->di_nblocks) { + xfs_buf_relse(bp); + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_inode_recover: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, dino bp 0x%p, ino %Ld, total extents = %d, nblocks = %Ld", + item, dip, bp, ino, + dicp->di_nextents + dicp->di_anextents, + dicp->di_nblocks); + return XFS_ERROR(EFSCORRUPTED); + } + if (dicp->di_forkoff > mp->m_sb.sb_inodesize) { + xfs_buf_relse(bp); + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_inode_recover: Bad inode log rec ptr 0x%p, dino ptr 0x%p, dino bp 0x%p, ino %Ld, forkoff 0x%x", + item, dip, bp, ino, dicp->di_forkoff); + return XFS_ERROR(EFSCORRUPTED); + } + if (item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t)) { + xfs_buf_relse(bp); + xfs_fs_cmn_err(CE_ALERT, mp, + "xfs_inode_recover: Bad inode log record length %d, rec ptr 0x%p", + item->ri_buf[1].i_len, item); + return XFS_ERROR(EFSCORRUPTED); + } + + /* The core is in in-core format */ + xfs_xlate_dinode_core((xfs_caddr_t)&dip->di_core, + (xfs_dinode_core_t*)item->ri_buf[1].i_addr, + -1, ARCH_CONVERT); + /* the rest is in on-disk format */ + if (item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t)) { + bcopy(item->ri_buf[1].i_addr + sizeof(xfs_dinode_core_t), + (xfs_caddr_t) dip + sizeof(xfs_dinode_core_t), + item->ri_buf[1].i_len - sizeof(xfs_dinode_core_t)); + } + + if (in_f->ilf_size == 2) + goto write_inode_buffer; + len = item->ri_buf[2].i_len; + src = item->ri_buf[2].i_addr; + fields = in_f->ilf_fields; + ASSERT(in_f->ilf_size <= 4); + ASSERT((in_f->ilf_size == 3) || (fields & XFS_ILOG_AFORK)); + ASSERT(!(fields & XFS_ILOG_DFORK) || + (len == in_f->ilf_dsize)); + + switch (fields & (XFS_ILOG_DFORK | XFS_ILOG_DEV | XFS_ILOG_UUID)) { + case XFS_ILOG_DDATA: + case XFS_ILOG_DEXT: + bcopy(src, &dip->di_u, len); + break; + + case XFS_ILOG_DBROOT: + xfs_bmbt_to_bmdr((xfs_bmbt_block_t *)src, len, + &(dip->di_u.di_bmbt), + XFS_DFORK_DSIZE(dip, mp)); + break; + + case XFS_ILOG_DEV: + INT_SET(dip->di_u.di_dev, ARCH_CONVERT, in_f->ilf_u.ilfu_rdev); + break; + + case XFS_ILOG_UUID: + dip->di_u.di_muuid = in_f->ilf_u.ilfu_uuid; + break; + + default: + /* + * There are no data fork, dev or uuid flags set. + */ + ASSERT((fields & + (XFS_ILOG_DFORK|XFS_ILOG_DEV|XFS_ILOG_UUID)) == 0); + break; + } + + + + /* + * If we logged any attribute data, recover it. There may or + * may not have been any other non-core data logged in this + * transaction. + */ + if (in_f->ilf_fields & XFS_ILOG_AFORK) { + if (in_f->ilf_fields & XFS_ILOG_DFORK) { + attr_index = 3; + } else { + attr_index = 2; + } + len = item->ri_buf[attr_index].i_len; + src = item->ri_buf[attr_index].i_addr; + ASSERT(len == in_f->ilf_asize); + + switch (in_f->ilf_fields & XFS_ILOG_AFORK) { + case XFS_ILOG_ADATA: + case XFS_ILOG_AEXT: + dest = XFS_DFORK_APTR(dip); + ASSERT(len <= XFS_DFORK_ASIZE(dip, mp)); + bcopy(src, dest, len); + break; + + case XFS_ILOG_ABROOT: + dest = XFS_DFORK_APTR(dip); + xfs_bmbt_to_bmdr((xfs_bmbt_block_t *)src, len, + (xfs_bmdr_block_t*)dest, + XFS_DFORK_ASIZE(dip, mp)); + break; + + default: + xlog_warn("XFS: xlog_recover_do_inode_trans: Illegal flag"); + ASSERT(0); + xfs_buf_relse(bp); + return XFS_ERROR(EIO); + } + } + + +write_inode_buffer: +#if 0 + /* + * Can't do this if the transaction didn't log the current + * contents, e.g. rmdir. + */ + XFS_DIR_SHORTFORM_VALIDATE_ONDISK(mp, dip); +#endif + xfs_inobp_check(mp, bp); + if (ITEM_TYPE(item) == XFS_LI_INODE) { + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL || + XFS_BUF_FSPRIVATE(bp, xfs_mount_t *) == mp); + XFS_BUF_SET_FSPRIVATE(bp, mp); + XFS_BUF_SET_IODONE_FUNC(bp, xlog_recover_iodone); + xfs_bdwrite(mp, bp); + } else { + XFS_BUF_STALE(bp); + error = xfs_bwrite(mp, bp); + } + + return (error); +} /* xlog_recover_do_inode_trans */ + + +/* + * Recover QUOTAOFF records. We simply make a note of it in the xlog_t + * structure, so that we know not to do any dquot item or dquot buffer recovery, + * of that type. + */ +STATIC int +xlog_recover_do_quotaoff_trans(xlog_t *log, + xlog_recover_item_t *item, + int pass) +{ + xfs_qoff_logformat_t *qoff_f; + + if (pass == XLOG_RECOVER_PASS2) { + return (0); + } + + qoff_f = (xfs_qoff_logformat_t *)item->ri_buf[0].i_addr; + ASSERT(qoff_f); + + /* + * The logitem format's flag tells us if this was user quotaoff, + * group quotaoff or both. + */ + if (qoff_f->qf_flags & XFS_UQUOTA_ACCT) + log->l_quotaoffs_flag |= XFS_DQ_USER; + if (qoff_f->qf_flags & XFS_GQUOTA_ACCT) + log->l_quotaoffs_flag |= XFS_DQ_GROUP; + + return (0); +} + + +/* + * Recover a dquot record + */ +STATIC int +xlog_recover_do_dquot_trans(xlog_t *log, + xlog_recover_item_t *item, + int pass) +{ + xfs_mount_t *mp; + xfs_buf_t *bp; + struct xfs_disk_dquot *ddq, *recddq; + int error; + xfs_dq_logformat_t *dq_f; + uint type; + + if (pass == XLOG_RECOVER_PASS1) { + return 0; + } + mp = log->l_mp; + + /* + * Non-root filesystems are required to send in quota flags + * at mount time. However, we may also get QUOTA_MAYBE flag set, + * indicating that quota should stay on (and stay consistent), + * if it already is. (so, we have to replay dquot log records + * when MAYBE flag's set). + */ + if (mp->m_qflags == 0 && + mp->m_dev != rootdev) { + return (0); + } + + recddq = (xfs_disk_dquot_t *)item->ri_buf[1].i_addr; + ASSERT(recddq); + /* + * This type of quotas was turned off, so ignore this record. + */ + type = INT_GET(recddq->d_flags, ARCH_CONVERT)&(XFS_DQ_USER|XFS_DQ_GROUP); + ASSERT(type); + if (log->l_quotaoffs_flag & type) + return (0); + + /* + * At this point we know that if we are recovering a root filesystem + * then quota was _not_ turned off. Since there is no other flag + * indicate to us otherwise, this must mean that quota's on, + * and the dquot needs to be replayed. Remember that we may not have + * fully recovered the superblock yet, so we can't do the usual trick + * of looking at the SB quota bits. + * + * The other possibility, of course, is that the quota subsystem was + * removed since the last mount - nopkg(). + */ + dq_f = (xfs_dq_logformat_t *)item->ri_buf[0].i_addr; + ASSERT(dq_f); + if ((error = xfs_qm_dqcheck(recddq, + dq_f->qlf_id, + 0, XFS_QMOPT_DOWARN, + "xlog_recover_do_dquot_trans (log copy)"))) { + if ((error == nopkg())) + return (0); + return XFS_ERROR(EIO); + } + ASSERT(dq_f->qlf_len == 1); + + error = xfs_read_buf(mp, mp->m_ddev_targp, + dq_f->qlf_blkno, + XFS_FSB_TO_BB(mp, dq_f->qlf_len), + 0, &bp); + if (error) { + xfs_ioerror_alert("xlog_recover_do..(read)", mp, + mp->m_dev, dq_f->qlf_blkno); + return error; + } + ASSERT(bp); + ddq = (xfs_disk_dquot_t *)xfs_buf_offset(bp, dq_f->qlf_boffset); + + /* + * At least the magic num portion should be on disk because this + * was among a chunk of dquots created earlier, and we did some + * minimal initialization then. + */ + if (xfs_qm_dqcheck(ddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN, + "xlog_recover_do_dquot_trans")) { + xfs_buf_relse(bp); + return XFS_ERROR(EIO); + } + + bcopy(recddq, ddq, item->ri_buf[1].i_len); + + ASSERT(dq_f->qlf_size == 2); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL || + XFS_BUF_FSPRIVATE(bp, xfs_mount_t *) == mp); + XFS_BUF_SET_FSPRIVATE(bp, mp); + XFS_BUF_SET_IODONE_FUNC(bp, xlog_recover_iodone); + xfs_bdwrite(mp, bp); + + return (0); +} /* xlog_recover_do_dquot_trans */ + +/* + * This routine is called to create an in-core extent free intent + * item from the efi format structure which was logged on disk. + * It allocates an in-core efi, copies the extents from the format + * structure into it, and adds the efi to the AIL with the given + * LSN. + */ +STATIC void +xlog_recover_do_efi_trans(xlog_t *log, + xlog_recover_item_t *item, + xfs_lsn_t lsn, + int pass) +{ + xfs_mount_t *mp; + xfs_efi_log_item_t *efip; + xfs_efi_log_format_t *efi_formatp; + SPLDECL(spl); + + if (pass == XLOG_RECOVER_PASS1) { + return; + } + + efi_formatp = (xfs_efi_log_format_t *)item->ri_buf[0].i_addr; + ASSERT(item->ri_buf[0].i_len == + (sizeof(xfs_efi_log_format_t) + + ((efi_formatp->efi_nextents - 1) * sizeof(xfs_extent_t)))); + + mp = log->l_mp; + efip = xfs_efi_init(mp, efi_formatp->efi_nextents); + bcopy((char *)efi_formatp, (char *)&(efip->efi_format), + sizeof(xfs_efi_log_format_t) + + ((efi_formatp->efi_nextents - 1) * sizeof(xfs_extent_t))); + efip->efi_next_extent = efi_formatp->efi_nextents; + efip->efi_flags |= XFS_EFI_COMMITTED; + + AIL_LOCK(mp,spl); + /* + * xfs_trans_update_ail() drops the AIL lock. + */ + xfs_trans_update_ail(mp, (xfs_log_item_t *)efip, lsn, spl); +} /* xlog_recover_do_efi_trans */ + + +/* + * This routine is called when an efd format structure is found in + * a committed transaction in the log. It's purpose is to cancel + * the corresponding efi if it was still in the log. To do this + * it searches the AIL for the efi with an id equal to that in the + * efd format structure. If we find it, we remove the efi from the + * AIL and free it. + */ +STATIC void +xlog_recover_do_efd_trans(xlog_t *log, + xlog_recover_item_t *item, + int pass) +{ + xfs_mount_t *mp; + xfs_efd_log_format_t *efd_formatp; + xfs_efi_log_item_t *efip=NULL; + xfs_log_item_t *lip; + int gen; + int nexts; + __uint64_t efi_id; + SPLDECL(spl); + + if (pass == XLOG_RECOVER_PASS1) { + return; + } + + efd_formatp = (xfs_efd_log_format_t *)item->ri_buf[0].i_addr; + ASSERT(item->ri_buf[0].i_len == + (sizeof(xfs_efd_log_format_t) + + ((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_t)))); + efi_id = efd_formatp->efd_efi_id; + + /* + * Search for the efi with the id in the efd format structure + * in the AIL. + */ + mp = log->l_mp; + AIL_LOCK(mp,spl); + lip = xfs_trans_first_ail(mp, &gen); + while (lip != NULL) { + if (lip->li_type == XFS_LI_EFI) { + efip = (xfs_efi_log_item_t *)lip; + if (efip->efi_format.efi_id == efi_id) { + /* + * xfs_trans_delete_ail() drops the + * AIL lock. + */ + xfs_trans_delete_ail(mp, lip, spl); + break; + } + } + lip = xfs_trans_next_ail(mp, lip, &gen, NULL); + } + if (lip == NULL) { + AIL_UNLOCK(mp, spl); + } + + /* + * If we found it, then free it up. If it wasn't there, it + * must have been overwritten in the log. Oh well. + */ + if (lip != NULL) { + nexts = efip->efi_format.efi_nextents; + if (nexts > XFS_EFI_MAX_FAST_EXTENTS) { + kmem_free(lip, sizeof(xfs_efi_log_item_t) + + ((nexts - 1) * sizeof(xfs_extent_t))); + } else { + kmem_zone_free(xfs_efi_zone, efip); + } + } +} /* xlog_recover_do_efd_trans */ + +/* + * Perform the transaction + * + * If the transaction modifies a buffer or inode, do it now. Otherwise, + * EFIs and EFDs get queued up by adding entries into the AIL for them. + */ +STATIC int +xlog_recover_do_trans(xlog_t *log, + xlog_recover_t *trans, + int pass) +{ + int error = 0; + xlog_recover_item_t *item, *first_item; + + if ((error = xlog_recover_reorder_trans(log, trans))) + return error; + first_item = item = trans->r_itemq; + do { + /* + * we don't need to worry about the block number being + * truncated in > 1 TB buffers because in user-land, + * we're now n32 or 64-bit so xfs_daddr_t is 64-bits so + * the blkno's will get through the user-mode buffer + * cache properly. The only bad case is o32 kernels + * where xfs_daddr_t is 32-bits but mount will warn us + * off a > 1 TB filesystem before we get here. + */ + if ((ITEM_TYPE(item) == XFS_LI_BUF) || + (ITEM_TYPE(item) == XFS_LI_6_1_BUF) || + (ITEM_TYPE(item) == XFS_LI_5_3_BUF)) { + if ((error = xlog_recover_do_buffer_trans(log, item, + pass))) + break; + } else if ((ITEM_TYPE(item) == XFS_LI_INODE) || + (ITEM_TYPE(item) == XFS_LI_6_1_INODE) || + (ITEM_TYPE(item) == XFS_LI_5_3_INODE)) { + if ((error = xlog_recover_do_inode_trans(log, item, + pass))) + break; + } else if (ITEM_TYPE(item) == XFS_LI_EFI) { + xlog_recover_do_efi_trans(log, item, trans->r_lsn, + pass); + } else if (ITEM_TYPE(item) == XFS_LI_EFD) { + xlog_recover_do_efd_trans(log, item, pass); + } else if (ITEM_TYPE(item) == XFS_LI_DQUOT) { + if ((error = xlog_recover_do_dquot_trans(log, item, + pass))) + break; + } else if ((ITEM_TYPE(item) == XFS_LI_QUOTAOFF)) { + if ((error = xlog_recover_do_quotaoff_trans(log, item, + pass))) + break; + } else { + xlog_warn("XFS: xlog_recover_do_trans"); + ASSERT(0); + error = XFS_ERROR(EIO); + break; + } + item = item->ri_next; + } while (first_item != item); + + return error; +} /* xlog_recover_do_trans */ + + +/* + * Free up any resources allocated by the transaction + * + * Remember that EFIs, EFDs, and IUNLINKs are handled later. + */ +STATIC void +xlog_recover_free_trans(xlog_recover_t *trans) +{ + xlog_recover_item_t *first_item, *item, *free_item; + int i; + + item = first_item = trans->r_itemq; + do { + free_item = item; + item = item->ri_next; + /* Free the regions in the item. */ + for (i = 0; i < free_item->ri_cnt; i++) { + kmem_free(free_item->ri_buf[i].i_addr, + free_item->ri_buf[i].i_len); + } + /* Free the item itself */ + kmem_free(free_item->ri_buf, + (free_item->ri_total * sizeof(xfs_log_iovec_t))); + kmem_free(free_item, sizeof(xlog_recover_item_t)); + } while (first_item != item); + /* Free the transaction recover structure */ + kmem_free(trans, sizeof(xlog_recover_t)); +} /* xlog_recover_free_trans */ + + +STATIC int +xlog_recover_commit_trans(xlog_t *log, + xlog_recover_t **q, + xlog_recover_t *trans, + int pass) +{ + int error; + + if ((error = xlog_recover_unlink_tid(q, trans))) + return error; + if ((error = xlog_recover_do_trans(log, trans, pass))) + return error; + xlog_recover_free_trans(trans); /* no error */ + return 0; +} /* xlog_recover_commit_trans */ + + +/*ARGSUSED*/ +STATIC int +xlog_recover_unmount_trans(xlog_recover_t *trans) +{ + /* Do nothing now */ + xlog_warn("XFS: xlog_recover_unmount_trans: Unmount LR"); + return( 0 ); +} /* xlog_recover_unmount_trans */ + + +/* + * There are two valid states of the r_state field. 0 indicates that the + * transaction structure is in a normal state. We have either seen the + * start of the transaction or the last operation we added was not a partial + * operation. If the last operation we added to the transaction was a + * partial operation, we need to mark r_state with XLOG_WAS_CONT_TRANS. + * + * NOTE: skip LRs with 0 data length. + */ +STATIC int +xlog_recover_process_data(xlog_t *log, + xlog_recover_t *rhash[], + xlog_rec_header_t *rhead, + xfs_caddr_t dp, + int pass) +{ + xfs_caddr_t lp = dp+INT_GET(rhead->h_len, ARCH_CONVERT); + int num_logops = INT_GET(rhead->h_num_logops, ARCH_CONVERT); + xlog_op_header_t *ohead; + xlog_recover_t *trans; + xlog_tid_t tid; + int error; + unsigned long hash; + uint flags; + + /* check the log format matches our own - else we can't recover */ + if (xlog_header_check_recover(log->l_mp, rhead)) + return (XFS_ERROR(EIO)); + + while (dp < lp) { + ASSERT(dp + sizeof(xlog_op_header_t) <= lp); + ohead = (xlog_op_header_t *)dp; + dp += sizeof(xlog_op_header_t); + if (ohead->oh_clientid != XFS_TRANSACTION && + ohead->oh_clientid != XFS_LOG) { + xlog_warn("XFS: xlog_recover_process_data: bad clientid"); + ASSERT(0); + return (XFS_ERROR(EIO)); + } + tid = INT_GET(ohead->oh_tid, ARCH_CONVERT); + hash = XLOG_RHASH(tid); + trans = xlog_recover_find_tid(rhash[hash], tid); + if (trans == NULL) { /* not found; add new tid */ + if (ohead->oh_flags & XLOG_START_TRANS) + xlog_recover_new_tid(&rhash[hash], tid, INT_GET(rhead->h_lsn, ARCH_CONVERT)); + } else { + ASSERT(dp+INT_GET(ohead->oh_len, ARCH_CONVERT) <= lp); + flags = ohead->oh_flags & ~XLOG_END_TRANS; + if (flags & XLOG_WAS_CONT_TRANS) + flags &= ~XLOG_CONTINUE_TRANS; + switch (flags) { + case XLOG_COMMIT_TRANS: { + error = xlog_recover_commit_trans(log, &rhash[hash], + trans, pass); + break; + } + case XLOG_UNMOUNT_TRANS: { + error = xlog_recover_unmount_trans(trans); + break; + } + case XLOG_WAS_CONT_TRANS: { + error = xlog_recover_add_to_cont_trans(trans, dp, + INT_GET(ohead->oh_len, ARCH_CONVERT)); + break; + } + case XLOG_START_TRANS : { + xlog_warn("XFS: xlog_recover_process_data: bad transaction"); + ASSERT(0); + error = XFS_ERROR(EIO); + break; + } + case 0: + case XLOG_CONTINUE_TRANS: { + error = xlog_recover_add_to_trans(trans, dp, + INT_GET(ohead->oh_len, ARCH_CONVERT)); + break; + } + default: { + xlog_warn("XFS: xlog_recover_process_data: bad flag"); + ASSERT(0); + error = XFS_ERROR(EIO); + break; + } + } /* switch */ + if (error) + return error; + } /* if */ + dp += INT_GET(ohead->oh_len, ARCH_CONVERT); + num_logops--; + } + return( 0 ); +} /* xlog_recover_process_data */ + + +/* + * Process an extent free intent item that was recovered from + * the log. We need to free the extents that it describes. + */ +STATIC void +xlog_recover_process_efi(xfs_mount_t *mp, + xfs_efi_log_item_t *efip) +{ + xfs_efd_log_item_t *efdp; + xfs_trans_t *tp; + int i; + xfs_extent_t *extp; + xfs_fsblock_t startblock_fsb; + + ASSERT(!(efip->efi_flags & XFS_EFI_RECOVERED)); + + /* + * First check the validity of the extents described by the + * EFI. If any are bad, then assume that all are bad and + * just toss the EFI. + */ + for (i = 0; i < efip->efi_format.efi_nextents; i++) { + extp = &(efip->efi_format.efi_extents[i]); + startblock_fsb = XFS_BB_TO_FSB(mp, + XFS_FSB_TO_DADDR(mp, extp->ext_start)); + if ((startblock_fsb == 0) || + (extp->ext_len == 0) || + (startblock_fsb >= mp->m_sb.sb_dblocks) || + (extp->ext_len >= mp->m_sb.sb_agblocks)) { + /* + * This will pull the EFI from the AIL and + * free the memory associated with it. + */ + xfs_efi_release(efip, efip->efi_format.efi_nextents); + return; + } + } + + tp = xfs_trans_alloc(mp, 0); + xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, 0, 0); + efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents); + + for (i = 0; i < efip->efi_format.efi_nextents; i++) { + extp = &(efip->efi_format.efi_extents[i]); + xfs_free_extent(tp, extp->ext_start, extp->ext_len); + xfs_trans_log_efd_extent(tp, efdp, extp->ext_start, + extp->ext_len); + } + + efip->efi_flags |= XFS_EFI_RECOVERED; + xfs_trans_commit(tp, 0, NULL); +} /* xlog_recover_process_efi */ + + +/* + * Verify that once we've encountered something other than an EFI + * in the AIL that there are no more EFIs in the AIL. + */ +#if defined(DEBUG) +STATIC void +xlog_recover_check_ail(xfs_mount_t *mp, + xfs_log_item_t *lip, + int gen) +{ + int orig_gen; + + orig_gen = gen; + do { + ASSERT(lip->li_type != XFS_LI_EFI); + lip = xfs_trans_next_ail(mp, lip, &gen, NULL); + /* + * The check will be bogus if we restart from the + * beginning of the AIL, so ASSERT that we don't. + * We never should since we're holding the AIL lock + * the entire time. + */ + ASSERT(gen == orig_gen); + } while (lip != NULL); +} +#endif /* DEBUG */ + + +/* + * When this is called, all of the EFIs which did not have + * corresponding EFDs should be in the AIL. What we do now + * is free the extents associated with each one. + * + * Since we process the EFIs in normal transactions, they + * will be removed at some point after the commit. This prevents + * us from just walking down the list processing each one. + * We'll use a flag in the EFI to skip those that we've already + * processed and use the AIL iteration mechanism's generation + * count to try to speed this up at least a bit. + * + * When we start, we know that the EFIs are the only things in + * the AIL. As we process them, however, other items are added + * to the AIL. Since everything added to the AIL must come after + * everything already in the AIL, we stop processing as soon as + * we see something other than an EFI in the AIL. + */ +STATIC void +xlog_recover_process_efis(xlog_t *log) +{ + xfs_log_item_t *lip; + xfs_efi_log_item_t *efip; + int gen; + xfs_mount_t *mp; + SPLDECL(spl); + + mp = log->l_mp; + AIL_LOCK(mp,spl); + + lip = xfs_trans_first_ail(mp, &gen); + while (lip != NULL) { + /* + * We're done when we see something other than an EFI. + */ + if (lip->li_type != XFS_LI_EFI) { + xlog_recover_check_ail(mp, lip, gen); + break; + } + + /* + * Skip EFIs that we've already processed. + */ + efip = (xfs_efi_log_item_t *)lip; + if (efip->efi_flags & XFS_EFI_RECOVERED) { + lip = xfs_trans_next_ail(mp, lip, &gen, NULL); + continue; + } + + AIL_UNLOCK(mp, spl); + xlog_recover_process_efi(mp, efip); + AIL_LOCK(mp,spl); + lip = xfs_trans_next_ail(mp, lip, &gen, NULL); + } + AIL_UNLOCK(mp, spl); +} /* xlog_recover_process_efis */ + + +/* + * This routine performs a transaction to null out a bad inode pointer + * in an agi unlinked inode hash bucket. + */ +STATIC void +xlog_recover_clear_agi_bucket( + xfs_mount_t *mp, + xfs_agnumber_t agno, + int bucket) +{ + xfs_trans_t *tp; + xfs_agi_t *agi; + xfs_daddr_t agidaddr; + xfs_buf_t *agibp; + int offset; + int error; + + tp = xfs_trans_alloc(mp, XFS_TRANS_CLEAR_AGI_BUCKET); + xfs_trans_reserve(tp, 0, XFS_CLEAR_AGI_BUCKET_LOG_RES(mp), 0, 0, 0); + + agidaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, agidaddr, + 1, 0, &agibp); + if (error) { + xfs_trans_cancel(tp, XFS_TRANS_ABORT); + return; + } + + agi = XFS_BUF_TO_AGI(agibp); + if (INT_GET(agi->agi_magicnum, ARCH_CONVERT) != XFS_AGI_MAGIC) { + xfs_trans_cancel(tp, XFS_TRANS_ABORT); + return; + } + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + + INT_SET(agi->agi_unlinked[bucket], ARCH_CONVERT, NULLAGINO); + offset = offsetof(xfs_agi_t, agi_unlinked) + + (sizeof(xfs_agino_t) * bucket); + xfs_trans_log_buf(tp, agibp, offset, + (offset + sizeof(xfs_agino_t) - 1)); + + (void) xfs_trans_commit(tp, 0, NULL); +} /* xlog_recover_clear_agi_bucket */ + + +/* + * xlog_iunlink_recover + * + * This is called during recovery to process any inodes which + * we unlinked but not freed when the system crashed. These + * inodes will be on the lists in the AGI blocks. What we do + * here is scan all the AGIs and fully truncate and free any + * inodes found on the lists. Each inode is removed from the + * lists when it has been fully truncated and is freed. The + * freeing of the inode and its removal from the list must be + * atomic. + */ +void +xlog_recover_process_iunlinks(xlog_t *log) +{ + xfs_mount_t *mp; + xfs_agnumber_t agno; + xfs_agi_t *agi; + xfs_daddr_t agidaddr; + xfs_buf_t *agibp; + xfs_inode_t *ip; + xfs_agino_t agino; + xfs_ino_t ino; + int bucket; + int error; + xfs_ino_t last_ino; +#if CONFIG_XFS_DMAPI + uint mp_dmevmask; +#endif /* CONFIG_XFS_DMAPI */ + + mp = log->l_mp; + +#if CONFIG_XFS_DMAPI + /* + * Prevent any DMAPI event from being while in this function. + * Not a problem for xfs since the file system isn't mounted + * yet. It is a problem for cxfs. + */ + mp_dmevmask = mp->m_dmevmask; + mp->m_dmevmask = 0; +#endif /* CONFIG_XFS_DMAPI */ + + last_ino = 0; + for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { + /* + * Find the agi for this ag. + */ + agidaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + agibp = xfs_buf_read(mp->m_ddev_targp, agidaddr, 1, 0); + agi = XFS_BUF_TO_AGI(agibp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + + bucket = 0; + while (bucket < XFS_AGI_UNLINKED_BUCKETS) { + /* + * If there is nothing in the current bucket, + * then continue on to the next one. + */ + agino = INT_GET(agi->agi_unlinked[bucket], ARCH_CONVERT); + if (agino == NULLAGINO) { + bucket++; + continue; + } + + /* + * Release the agi buffer so that it can + * be acquired in the normal course of the + * transaction to truncate and free the inode. + */ + xfs_buf_relse(agibp); + + ino = XFS_AGINO_TO_INO(mp, agno, agino); + error = xfs_iget(mp, NULL, ino, 0, &ip, 0); + +#ifdef CONFIG_XFS_DMAPI + /* + * Prevent any DMAPI event from being sent when + * the reference on the inode is dropped. Not + * a problem for xfs since the file system isn't + * mounted yet. It is a problem for cxfs. + */ + if (!error) { + ip->i_d.di_dmevmask = 0; + } +#endif /* CONFIG_XFS_DMAPI */ + + /* + * This inode is messed up. Just + * ditch this bucket of inodes. We + * will lose some inodes and space, + * but at least we won't hang. + */ + if (!error && + (ino != last_ino) && + (ip->i_d.di_nlink == 0) && + (ip->i_d.di_mode != 0)) { + ASSERT(ip != NULL); + ASSERT(ip->i_d.di_nlink == 0); + ASSERT(ip->i_d.di_mode != 0); + + /* + * Drop our reference to the inode. This + * will send the inode to xfs_inactive() + * which will truncate the file and free + * the inode. + */ + VN_RELE(XFS_ITOV(ip)); + last_ino = ino; + } else { + /* + * Skip this bucket if we can't read in + * the inode it points to. Call + * xlog_recover_clear_agi_bucket() + * to perform a transaction to clear + * the inode pointer in the bucket. + */ + if (!error) { + VN_RELE(XFS_ITOV(ip)); + } + + xlog_recover_clear_agi_bucket(mp, agno, bucket); + + bucket++; + } + + /* + * Reacquire the agibuffer and continue around + * the loop. + */ + agidaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + agibp = xfs_buf_read(mp->m_ddev_targp, + agidaddr, 1, 0); + agi = XFS_BUF_TO_AGI(agibp); + ASSERT(INT_GET(agi->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + } + + /* + * Release the buffer for the current agi so we can + * go on to the next one. + */ + xfs_buf_relse(agibp); + } + +#ifdef CONFIG_XFS_DMAPI + mp->m_dmevmask = mp_dmevmask; +#endif /* CONFIG_XFS_DMAPI */ + +} /* xlog_recover_process_iunlinks */ + + +/* + * Stamp cycle number in every block + * + * This routine is also called in xfs_log.c + */ +/*ARGSUSED*/ +void +xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog) +{ + int i; + xfs_caddr_t dp; +#ifdef DEBUG + uint *up; + uint chksum = 0; + + up = (uint *)iclog->ic_data; + /* divide length by 4 to get # words */ + for (i=0; iic_offset >> 2; i++) { + chksum ^= INT_GET(*up, ARCH_CONVERT); + up++; + } + INT_SET(iclog->ic_header.h_chksum, ARCH_CONVERT, chksum); +#endif /* DEBUG */ + + dp = iclog->ic_data; + for (i = 0; iic_offset); i++) { + INT_SET(iclog->ic_header.h_cycle_data[i], ARCH_CONVERT, INT_GET(*(uint *)dp, ARCH_CONVERT)); + INT_SET(*(uint *)dp, ARCH_CONVERT, CYCLE_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT)); + dp += BBSIZE; + } +} /* xlog_pack_data */ + + +/*ARGSUSED*/ +STATIC void +xlog_unpack_data(xlog_rec_header_t *rhead, + xfs_caddr_t dp, + xlog_t *log) +{ + int i; +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + uint *up = (uint *)dp; + uint chksum = 0; +#endif + + for (i=0; ih_len, ARCH_CONVERT)); i++) { + INT_SET(*(uint *)dp, ARCH_CONVERT, INT_GET(*(uint *)&rhead->h_cycle_data[i], ARCH_CONVERT)); + dp += BBSIZE; + } +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + /* divide length by 4 to get # words */ + for (i=0; i < INT_GET(rhead->h_len, ARCH_CONVERT) >> 2; i++) { + chksum ^= INT_GET(*up, ARCH_CONVERT); + up++; + } + if (chksum != INT_GET(rhead->h_chksum, ARCH_CONVERT)) { + if (!INT_ISZERO(rhead->h_chksum, ARCH_CONVERT) || + ((log->l_flags & XLOG_CHKSUM_MISMATCH) == 0)) { + cmn_err(CE_DEBUG, + "XFS: LogR chksum mismatch: was (0x%x) is (0x%x)", + INT_GET(rhead->h_chksum, ARCH_CONVERT), chksum); + cmn_err(CE_DEBUG, +"XFS: Disregard message if filesystem was created with non-DEBUG kernel"); + log->l_flags |= XLOG_CHKSUM_MISMATCH; + } + } +#endif /* DEBUG && XFS_LOUD_RECOVERY */ +} /* xlog_unpack_data */ + + +/* + * Read the log from tail to head and process the log records found. + * Handle the two cases where the tail and head are in the same cycle + * and where the active portion of the log wraps around the end of + * the physical log separately. The pass parameter is passed through + * to the routines called to process the data and is not looked at + * here. + */ +STATIC int +xlog_do_recovery_pass(xlog_t *log, + xfs_daddr_t head_blk, + xfs_daddr_t tail_blk, + int pass) +{ + xlog_rec_header_t *rhead; + xfs_daddr_t blk_no; + xfs_caddr_t bufaddr; + xfs_buf_t *hbp, *dbp; + int error; + int bblks, split_bblks; + xlog_recover_t *rhash[XLOG_RHASH_SIZE]; + + error = 0; + hbp = xlog_get_bp(1,log->l_mp); + if (!hbp) + return -ENOMEM; + dbp = xlog_get_bp(BTOBB(XLOG_MAX_RECORD_BSIZE),log->l_mp); + if (!dbp) { + xlog_put_bp(hbp); + return -ENOMEM; + } + bzero(rhash, sizeof(rhash)); + if (tail_blk <= head_blk) { + for (blk_no = tail_blk; blk_no < head_blk; ) { + if ((error = xlog_bread(log, blk_no, 1, hbp))) + goto bread_err; + rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp); + ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); + ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX)); + bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); /* blocks in data section */ + if (bblks > 0) { + if ((error = xlog_bread(log, blk_no+1, bblks, dbp))) + goto bread_err; + xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log); + if ((error = xlog_recover_process_data(log, rhash, + rhead, XFS_BUF_PTR(dbp), + pass))) + goto bread_err; + } + blk_no += (bblks+1); + } + } else { + /* + * Perform recovery around the end of the physical log. When the head + * is not on the same cycle number as the tail, we can't do a sequential + * recovery as above. + */ + blk_no = tail_blk; + while (blk_no < log->l_logBBsize) { + + /* Read header of one block */ + if ((error = xlog_bread(log, blk_no, 1, hbp))) + goto bread_err; + rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp); + ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); + ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX)); + bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); + + /* LR body must have data or it wouldn't have been written */ + ASSERT(bblks > 0); + blk_no++; /* successfully read header */ + ASSERT(blk_no <= log->l_logBBsize); + + if ((INT_GET(rhead->h_magicno, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) || + (BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) > INT_MAX)) || + (bblks <= 0) || + (blk_no > log->l_logBBsize)) { + error = EFSCORRUPTED; + goto bread_err; + } + + /* Read in data for log record */ + if (blk_no+bblks <= log->l_logBBsize) { + if ((error = xlog_bread(log, blk_no, bblks, dbp))) + goto bread_err; + } else { + /* This log record is split across physical end of log */ + split_bblks = 0; + if (blk_no != log->l_logBBsize) { + + /* some data is before physical end of log */ + ASSERT(blk_no <= INT_MAX); + split_bblks = log->l_logBBsize - (int)blk_no; + ASSERT(split_bblks > 0); + if ((error = xlog_bread(log, blk_no, split_bblks, dbp))) + goto bread_err; + } + bufaddr = XFS_BUF_PTR(dbp); + XFS_BUF_SET_PTR(dbp, bufaddr + BBTOB(split_bblks), + BBTOB(bblks - split_bblks)); + if ((error = xlog_bread(log, 0, bblks - split_bblks, dbp))) + goto bread_err; + XFS_BUF_SET_PTR(dbp, bufaddr, XLOG_MAX_RECORD_BSIZE); + } + xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log); + if ((error = xlog_recover_process_data(log, rhash, + rhead, XFS_BUF_PTR(dbp), + pass))) + goto bread_err; + blk_no += bblks; + } + + ASSERT(blk_no >= log->l_logBBsize); + blk_no -= log->l_logBBsize; + + /* read first part of physical log */ + while (blk_no < head_blk) { + if ((error = xlog_bread(log, blk_no, 1, hbp))) + goto bread_err; + rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp); + ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM); + ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX)); + bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); + ASSERT(bblks > 0); + if ((error = xlog_bread(log, blk_no+1, bblks, dbp))) + goto bread_err; + xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log); + if ((error = xlog_recover_process_data(log, rhash, + rhead, XFS_BUF_PTR(dbp), + pass))) + goto bread_err; + blk_no += (bblks+1); + } + } + +bread_err: + xlog_put_bp(dbp); + xlog_put_bp(hbp); + + return error; +} + +/* + * Do the recovery of the log. We actually do this in two phases. + * The two passes are necessary in order to implement the function + * of cancelling a record written into the log. The first pass + * determines those things which have been cancelled, and the + * second pass replays log items normally except for those which + * have been cancelled. The handling of the replay and cancellations + * takes place in the log item type specific routines. + * + * The table of items which have cancel records in the log is allocated + * and freed at this level, since only here do we know when all of + * the log recovery has been completed. + */ +STATIC int +xlog_do_log_recovery(xlog_t *log, + xfs_daddr_t head_blk, + xfs_daddr_t tail_blk) +{ + int error; +#ifdef DEBUG + int i; +#endif + + /* + * First do a pass to find all of the cancelled buf log items. + * Store them in the buf_cancel_table for use in the second pass. + */ + log->l_buf_cancel_table = + (xfs_buf_cancel_t **)kmem_zalloc(XLOG_BC_TABLE_SIZE * + sizeof(xfs_buf_cancel_t*), + KM_SLEEP); + error = xlog_do_recovery_pass(log, head_blk, tail_blk, + XLOG_RECOVER_PASS1); + if (error != 0) { + kmem_free(log->l_buf_cancel_table, + XLOG_BC_TABLE_SIZE * sizeof(xfs_buf_cancel_t*)); + log->l_buf_cancel_table = NULL; + return error; + } + /* + * Then do a second pass to actually recover the items in the log. + * When it is complete free the table of buf cancel items. + */ + error = xlog_do_recovery_pass(log, head_blk, tail_blk, + XLOG_RECOVER_PASS2); +#ifdef DEBUG + for (i = 0; i < XLOG_BC_TABLE_SIZE; i++) { + ASSERT(log->l_buf_cancel_table[i] == NULL); + } +#endif /* DEBUG */ + kmem_free(log->l_buf_cancel_table, + XLOG_BC_TABLE_SIZE * sizeof(xfs_buf_cancel_t*)); + log->l_buf_cancel_table = NULL; + + return error; +} + +/* + * Do the actual recovery + */ +STATIC int +xlog_do_recover(xlog_t *log, + xfs_daddr_t head_blk, + xfs_daddr_t tail_blk) +{ + int error; + xfs_buf_t *bp; + xfs_sb_t *sbp; + + /* + * First replay the images in the log. + */ + error = xlog_do_log_recovery(log, head_blk, tail_blk); + if (error) { + return error; + } + + XFS_bflush(log->l_mp->m_ddev_targ); + + /* + * If IO errors happened during recovery, bail out. + */ + if (XFS_FORCED_SHUTDOWN(log->l_mp)) { + return (EIO); + } + + /* + * We now update the tail_lsn since much of the recovery has completed + * and there may be space available to use. If there were no extent + * or iunlinks, we can free up the entire log and set the tail_lsn to + * be the last_sync_lsn. This was set in xlog_find_tail to be the + * lsn of the last known good LR on disk. If there are extent frees + * or iunlinks they will have some entries in the AIL; so we look at + * the AIL to determine how to set the tail_lsn. + */ + xlog_assign_tail_lsn(log->l_mp, NULL); + + /* + * Now that we've finished replaying all buffer and inode + * updates, re-read in the superblock. + */ + bp = xfs_getsb(log->l_mp, 0); + XFS_BUF_UNDONE(bp); + XFS_BUF_READ(bp); + xfsbdstrat(log->l_mp, bp); + if ((error = xfs_iowait(bp))) { + ASSERT(0); + xfs_buf_relse(bp); + return error; + } + + /* convert superblock from on-disk format */ + + sbp=&log->l_mp->m_sb; + xfs_xlatesb(XFS_BUF_TO_SBP(bp), sbp, 1, ARCH_CONVERT, XFS_SB_ALL_BITS); + ASSERT(sbp->sb_magicnum == XFS_SB_MAGIC); + ASSERT(XFS_SB_GOOD_VERSION(sbp)); + xfs_buf_relse(bp); + + xlog_recover_check_summary(log); + + /* Normal transactions can now occur */ + log->l_flags &= ~XLOG_ACTIVE_RECOVERY; + return 0; +} /* xlog_do_recover */ + +/* + * Perform recovery and re-initialize some log variables in xlog_find_tail. + * + * Return error or zero. + */ +int +xlog_recover(xlog_t *log, int readonly) +{ + xfs_daddr_t head_blk, tail_blk; + int error; + + /* find the tail of the log */ + + if ((error = xlog_find_tail(log, &head_blk, &tail_blk, readonly))) + return error; + + if (tail_blk != head_blk) { +#ifndef __KERNEL__ + extern xfs_daddr_t HEAD_BLK, TAIL_BLK; + head_blk = HEAD_BLK; + tail_blk = TAIL_BLK; +#endif + /* There used to be a comment here: + * + * disallow recovery on read-only mounts. note -- mount + * checks for ENOSPC and turns it into an intelligent + * error message. + * ...but this is no longer true. Now, unless you specify + * NORECOVERY (in which case this function would never be + * called), it enables read-write access long enough to do + * recovery. + */ + if (readonly) { +#ifdef __KERNEL__ + if ((error = xfs_recover_read_only(log))) + return error; +#else + return ENOSPC; +#endif + } + +#ifdef __KERNEL__ +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + cmn_err(CE_NOTE, + "Starting XFS recovery on filesystem: %s (dev: %d/%d)", + log->l_mp->m_fsname, MAJOR(log->l_dev), + MINOR(log->l_dev)); +#else + cmn_err(CE_NOTE, + "!Starting XFS recovery on filesystem: %s (dev: %d/%d)", + log->l_mp->m_fsname, MAJOR(log->l_dev), + MINOR(log->l_dev)); +#endif +#endif + error = xlog_do_recover(log, head_blk, tail_blk); + log->l_flags |= XLOG_RECOVERY_NEEDED; + if (readonly) + XFS_MTOVFS(log->l_mp)->vfs_flag |= VFS_RDONLY; + } + return error; +} /* xlog_recover */ + + +/* + * In the first part of recovery we replay inodes and buffers and build + * up the list of extent free items which need to be processed. Here + * we process the extent free items and clean up the on disk unlinked + * inode lists. This is separated from the first part of recovery so + * that the root and real-time bitmap inodes can be read in from disk in + * between the two stages. This is necessary so that we can free space + * in the real-time portion of the file system. + */ +int +xlog_recover_finish(xlog_t *log, int mfsi_flags) +{ + /* + * Now we're ready to do the transactions needed for the + * rest of recovery. Start with completing all the extent + * free intent records and then process the unlinked inode + * lists. At this point, we essentially run in normal mode + * except that we're still performing recovery actions + * rather than accepting new requests. + */ + if (log->l_flags & XLOG_RECOVERY_NEEDED) { + xlog_recover_process_efis(log); + /* + * Sync the log to get all the EFIs out of the AIL. + * This isn't absolutely necessary, but it helps in + * case the unlink transactions would have problems + * pushing the EFIs out of the way. + */ + xfs_log_force(log->l_mp, (xfs_lsn_t)0, + (XFS_LOG_FORCE | XFS_LOG_SYNC)); + + if ( (mfsi_flags & XFS_MFSI_NOUNLINK) == 0 ) { + + xlog_recover_process_iunlinks(log); + } + + xlog_recover_check_summary(log); + +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + cmn_err(CE_NOTE, + "Ending XFS recovery on filesystem: %s (dev: %d/%d)", + log->l_mp->m_fsname, MAJOR(log->l_dev), + MINOR(log->l_dev)); +#else + cmn_err(CE_NOTE, + "!Ending XFS recovery on filesystem: %s (dev: %d/%d)", + log->l_mp->m_fsname, MAJOR(log->l_dev), + MINOR(log->l_dev)); +#endif + log->l_flags &= ~XLOG_RECOVERY_NEEDED; + } else { + cmn_err(CE_NOTE, + "!Ending clean XFS mount for filesystem: %s", + log->l_mp->m_fsname); + } + return 0; +} /* xlog_recover_finish */ + + +#if defined(DEBUG) +/* + * Read all of the agf and agi counters and check that they + * are consistent with the superblock counters. + */ +void +xlog_recover_check_summary(xlog_t *log) +{ + xfs_mount_t *mp; + xfs_agf_t *agfp; + xfs_agi_t *agip; + xfs_buf_t *agfbp; + xfs_buf_t *agibp; + xfs_daddr_t agfdaddr; + xfs_daddr_t agidaddr; + xfs_buf_t *sbbp; +#ifdef XFS_LOUD_RECOVERY + xfs_sb_t *sbp; +#endif + xfs_agnumber_t agno; + __uint64_t freeblks; + __uint64_t itotal; + __uint64_t ifree; + + mp = log->l_mp; + + freeblks = 0LL; + itotal = 0LL; + ifree = 0LL; + for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { + agfdaddr = XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR); + agfbp = xfs_buf_read(mp->m_ddev_targp, agfdaddr, 1, 0); + agfp = XFS_BUF_TO_AGF(agfbp); + ASSERT(INT_GET(agfp->agf_magicnum, ARCH_CONVERT) == XFS_AGF_MAGIC); + ASSERT(XFS_AGF_GOOD_VERSION(INT_GET(agfp->agf_versionnum, ARCH_CONVERT))); + ASSERT(INT_GET(agfp->agf_seqno, ARCH_CONVERT) == agno); + + freeblks += INT_GET(agfp->agf_freeblks, ARCH_CONVERT) + + INT_GET(agfp->agf_flcount, ARCH_CONVERT); + xfs_buf_relse(agfbp); + + agidaddr = XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR); + agibp = xfs_buf_read(mp->m_ddev_targp, agidaddr, 1, 0); + agip = XFS_BUF_TO_AGI(agibp); + ASSERT(INT_GET(agip->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC); + ASSERT(XFS_AGI_GOOD_VERSION(INT_GET(agip->agi_versionnum, ARCH_CONVERT))); + ASSERT(INT_GET(agip->agi_seqno, ARCH_CONVERT) == agno); + + itotal += INT_GET(agip->agi_count, ARCH_CONVERT); + ifree += INT_GET(agip->agi_freecount, ARCH_CONVERT); + xfs_buf_relse(agibp); + } + + sbbp = xfs_getsb(mp, 0); +#ifdef XFS_LOUD_RECOVERY + sbp = XFS_BUF_TO_SBP(sbbp); + cmn_err(CE_NOTE, + "xlog_recover_check_summary: sb_icount %Lu itotal %Lu", + sbp->sb_icount, itotal); + cmn_err(CE_NOTE, + "xlog_recover_check_summary: sb_ifree %Lu itotal %Lu", + sbp->sb_ifree, ifree); + cmn_err(CE_NOTE, + "xlog_recover_check_summary: sb_fdblocks %Lu freeblks %Lu", + sbp->sb_fdblocks, freeblks); +#if 0 + /* + * This is turned off until I account for the allocation + * btree blocks which live in free space. + */ + ASSERT(sbp->sb_icount == itotal); + ASSERT(sbp->sb_ifree == ifree); + ASSERT(sbp->sb_fdblocks == freeblks); +#endif +#endif + xfs_buf_relse(sbbp); +} +#endif /* DEBUG */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_log_recover.h linux-2.4-xfs/linux/fs/xfs/xfs_log_recover.h --- linux-2.4.7/linux/fs/xfs/xfs_log_recover.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_log_recover.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_LOG_RECOVER_H__ +#define __XFS_LOG_RECOVER_H__ + +/* + * Macros, structures, prototypes for internal log manager use. + */ + +#define XLOG_RHASH_BITS 4 +#define XLOG_RHASH_SIZE 16 +#define XLOG_RHASH_SHIFT 2 +#define XLOG_RHASH(tid) \ + ((((__uint32_t)tid)>>XLOG_RHASH_SHIFT) & (XLOG_RHASH_SIZE-1)) + +#define XLOG_MAX_REGIONS_IN_ITEM (XFS_MAX_BLOCKSIZE / XFS_BLI_CHUNK / 2 + 1) + + +/* + * item headers are in ri_buf[0]. Additional buffers follow. + */ +typedef struct xlog_recover_item { + struct xlog_recover_item *ri_next; + struct xlog_recover_item *ri_prev; + int ri_type; + int ri_cnt; /* count of regions found */ + int ri_total; /* total regions */ + xfs_log_iovec_t *ri_buf; /* ptr to regions buffer */ +} xlog_recover_item_t; + +struct xlog_tid; +typedef struct xlog_recover { + struct xlog_recover *r_next; + xlog_tid_t r_log_tid; /* log's transaction id */ + xfs_trans_header_t r_theader; /* trans header for partial */ + int r_state; /* not needed */ + xfs_lsn_t r_lsn; /* xact lsn */ + xlog_recover_item_t *r_itemq; /* q for items */ +} xlog_recover_t; + +#define ITEM_TYPE(i) (*(ushort *)(i)->ri_buf[0].i_addr) + +/* + * This is the number of entries in the l_buf_cancel_table used during + * recovery. + */ +#define XLOG_BC_TABLE_SIZE 64 + +#define XLOG_RECOVER_PASS1 1 +#define XLOG_RECOVER_PASS2 2 + +#endif /* __XFS_LOG_RECOVER_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_macros.c linux-2.4-xfs/linux/fs/xfs/xfs_macros.c --- linux-2.4.7/linux/fs/xfs/xfs_macros.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_macros.c Mon May 14 10:27:31 2001 @@ -0,0 +1,2228 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#define XFS_MACRO_C + +#include + + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_ISNULLDSTARTBLOCK) +int +isnulldstartblock(xfs_dfsbno_t x) +{ + return ISNULLDSTARTBLOCK(x); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_ISNULLSTARTBLOCK) +int +isnullstartblock(xfs_fsblock_t x) +{ + return ISNULLSTARTBLOCK(x); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_NULLSTARTBLOCK) +xfs_fsblock_t +nullstartblock(int k) +{ + return NULLSTARTBLOCK(k); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_STARTBLOCKVAL) +xfs_filblks_t +startblockval(xfs_fsblock_t x) +{ + return STARTBLOCKVAL(x); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_CHECK_DADDR) +void +xfs_ag_check_daddr(xfs_mount_t *mp, xfs_daddr_t d, xfs_extlen_t len) +{ + XFS_AG_CHECK_DADDR(mp, d, len); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_DADDR) +xfs_daddr_t +xfs_ag_daddr(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_daddr_t d) +{ + return XFS_AG_DADDR(mp, agno, d); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_BEST_BLOCKS) +xfs_extlen_t +xfs_ag_best_blocks(int bl, xfs_drfsbno_t blks) +{ + return XFS_AG_BEST_BLOCKS(bl, blks); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_MAX_BLOCKS) +xfs_extlen_t +xfs_ag_max_blocks(int bl) +{ + return XFS_AG_MAX_BLOCKS(bl); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_MAXLEVELS) +int +xfs_ag_maxlevels(xfs_mount_t *mp) +{ + return XFS_AG_MAXLEVELS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AG_MIN_BLOCKS) +xfs_extlen_t +xfs_ag_min_blocks(int bl) +{ + return XFS_AG_MIN_BLOCKS(bl); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGB_TO_DADDR) +xfs_daddr_t +xfs_agb_to_daddr(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agblock_t agbno) +{ + return XFS_AGB_TO_DADDR(mp, agno, agbno); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGB_TO_FSB) +xfs_fsblock_t +xfs_agb_to_fsb(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agblock_t agbno) +{ + return XFS_AGB_TO_FSB(mp, agno, agbno); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGBLOCK_MAX) +xfs_agblock_t +xfs_agblock_max(xfs_agblock_t a, xfs_agblock_t b) +{ + return XFS_AGBLOCK_MAX(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGBLOCK_MIN) +xfs_agblock_t +xfs_agblock_min(xfs_agblock_t a, xfs_agblock_t b) +{ + return XFS_AGBLOCK_MIN(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGF_BLOCK) +xfs_agblock_t +xfs_agf_block(xfs_mount_t *mp) +{ + return XFS_AGF_BLOCK(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGF_GOOD_VERSION) +int +xfs_agf_good_version(unsigned v) +{ + return XFS_AGF_GOOD_VERSION(v); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGFL_BLOCK) +xfs_agblock_t +xfs_agfl_block(xfs_mount_t *mp) +{ + return XFS_AGFL_BLOCK(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGI_BLOCK) +xfs_agblock_t +xfs_agi_block(xfs_mount_t *mp) +{ + return XFS_AGI_BLOCK(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGI_GOOD_VERSION) +int +xfs_agi_good_version(unsigned v) +{ + return XFS_AGI_GOOD_VERSION(v); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGINO_TO_AGBNO) +xfs_agblock_t +xfs_agino_to_agbno(xfs_mount_t *mp, xfs_agino_t i) +{ + return XFS_AGINO_TO_AGBNO(mp, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGINO_TO_INO) +xfs_ino_t +xfs_agino_to_ino(xfs_mount_t *mp, xfs_agnumber_t a, xfs_agino_t i) +{ + return XFS_AGINO_TO_INO(mp, a, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_AGINO_TO_OFFSET) +int +xfs_agino_to_offset(xfs_mount_t *mp, xfs_agino_t i) +{ + return XFS_AGINO_TO_OFFSET(mp, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ALLOC_BLOCK_MAXRECS) +int +xfs_alloc_block_maxrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_ALLOC_BLOCK_MAXRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ALLOC_BLOCK_MINRECS) +int +xfs_alloc_block_minrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_ALLOC_BLOCK_MINRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ALLOC_BLOCK_SIZE) +/*ARGSUSED1*/ +int +xfs_alloc_block_size(int lev, xfs_btree_cur_t *cur) +{ + return XFS_ALLOC_BLOCK_SIZE(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ALLOC_KEY_ADDR) +/*ARGSUSED3*/ +xfs_alloc_key_t * +xfs_alloc_key_addr(xfs_alloc_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_ALLOC_KEY_ADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ALLOC_PTR_ADDR) +xfs_alloc_ptr_t * +xfs_alloc_ptr_addr(xfs_alloc_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_ALLOC_PTR_ADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ALLOC_REC_ADDR) +/*ARGSUSED3*/ +xfs_alloc_rec_t * +xfs_alloc_rec_addr(xfs_alloc_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_ALLOC_REC_ADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_LEAF_ENTSIZE_LOCAL) +int +xfs_attr_leaf_entsize_local(int nlen, int vlen) +{ + return XFS_ATTR_LEAF_ENTSIZE_LOCAL(nlen, vlen); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX) +int +xfs_attr_leaf_entsize_local_max(int bsize) +{ + return XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX(bsize); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_LEAF_ENTSIZE_REMOTE) +int +xfs_attr_leaf_entsize_remote(int nlen) +{ + return XFS_ATTR_LEAF_ENTSIZE_REMOTE(nlen); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_LEAF_NAME) +char * +xfs_attr_leaf_name(xfs_attr_leafblock_t *leafp, int idx) +{ + return XFS_ATTR_LEAF_NAME(leafp, idx); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_LEAF_NAME_LOCAL) +xfs_attr_leaf_name_local_t * +xfs_attr_leaf_name_local(xfs_attr_leafblock_t *leafp, int idx) +{ + return XFS_ATTR_LEAF_NAME_LOCAL(leafp, idx); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_LEAF_NAME_REMOTE) +xfs_attr_leaf_name_remote_t * +xfs_attr_leaf_name_remote(xfs_attr_leafblock_t *leafp, int idx) +{ + return XFS_ATTR_LEAF_NAME_REMOTE(leafp, idx); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_SF_ENTSIZE) +int +xfs_attr_sf_entsize(xfs_attr_sf_entry_t *sfep) +{ + return XFS_ATTR_SF_ENTSIZE(sfep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_SF_ENTSIZE_BYNAME) +int +xfs_attr_sf_entsize_byname(int nlen, int vlen) +{ + return XFS_ATTR_SF_ENTSIZE_BYNAME(nlen, vlen); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_SF_NEXTENTRY) +xfs_attr_sf_entry_t * +xfs_attr_sf_nextentry(xfs_attr_sf_entry_t *sfep) +{ + return XFS_ATTR_SF_NEXTENTRY(sfep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ATTR_SF_TOTSIZE) +int +xfs_attr_sf_totsize(xfs_inode_t *dp) +{ + return XFS_ATTR_SF_TOTSIZE(dp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BHVTOI) +xfs_inode_t * +xfs_bhvtoi(bhv_desc_t *bhvp) +{ + return XFS_BHVTOI(bhvp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BHVTOM) +xfs_mount_t * +xfs_bhvtom(bhv_desc_t *bdp) +{ + return XFS_BHVTOM(bdp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BM_MAXLEVELS) +int +xfs_bm_maxlevels(xfs_mount_t *mp, int w) +{ + return XFS_BM_MAXLEVELS(mp, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BLOCK_DMAXRECS) +int +xfs_bmap_block_dmaxrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_BLOCK_DMAXRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BLOCK_DMINRECS) +int +xfs_bmap_block_dminrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_BLOCK_DMINRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BLOCK_DSIZE) +int +xfs_bmap_block_dsize(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_BLOCK_DSIZE(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BLOCK_IMAXRECS) +int +xfs_bmap_block_imaxrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_BLOCK_IMAXRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BLOCK_IMINRECS) +int +xfs_bmap_block_iminrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_BLOCK_IMINRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BLOCK_ISIZE) +int +xfs_bmap_block_isize(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_BLOCK_ISIZE(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BROOT_KEY_ADDR) +/*ARGSUSED3*/ +xfs_bmbt_key_t * +xfs_bmap_broot_key_addr(xfs_bmbt_block_t *bb, int i, int sz) +{ + return XFS_BMAP_BROOT_KEY_ADDR(bb, i, sz); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BROOT_MAXRECS) +int +xfs_bmap_broot_maxrecs(int sz) +{ + return XFS_BMAP_BROOT_MAXRECS(sz); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BROOT_NUMRECS) +int +xfs_bmap_broot_numrecs(xfs_bmdr_block_t *bb) +{ + return XFS_BMAP_BROOT_NUMRECS(bb); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BROOT_PTR_ADDR) +xfs_bmbt_ptr_t * +xfs_bmap_broot_ptr_addr(xfs_bmbt_block_t *bb, int i, int sz) +{ + return XFS_BMAP_BROOT_PTR_ADDR(bb, i, sz); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BROOT_REC_ADDR) +/*ARGSUSED3*/ +xfs_bmbt_rec_t * +xfs_bmap_broot_rec_addr(xfs_bmbt_block_t *bb, int i, int sz) +{ + return XFS_BMAP_BROOT_REC_ADDR(bb, i, sz); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BROOT_SPACE) +int +xfs_bmap_broot_space(xfs_bmdr_block_t *bb) +{ + return XFS_BMAP_BROOT_SPACE(bb); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_BROOT_SPACE_CALC) +int +xfs_bmap_broot_space_calc(int nrecs) +{ + return XFS_BMAP_BROOT_SPACE_CALC(nrecs); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_IBLOCK_SIZE) +/*ARGSUSED1*/ +int +xfs_bmap_iblock_size(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_IBLOCK_SIZE(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_INIT) +void +xfs_bmap_init(xfs_bmap_free_t *flp, xfs_fsblock_t *fbp) +{ + XFS_BMAP_INIT(flp, fbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_KEY_DADDR) +/*ARGSUSED3*/ +xfs_bmbt_key_t * +xfs_bmap_key_daddr(xfs_bmbt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_KEY_DADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_KEY_IADDR) +/*ARGSUSED3*/ +xfs_bmbt_key_t * +xfs_bmap_key_iaddr(xfs_bmbt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_KEY_IADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_PTR_DADDR) +xfs_bmbt_ptr_t * +xfs_bmap_ptr_daddr(xfs_bmbt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_PTR_DADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_PTR_IADDR) +xfs_bmbt_ptr_t * +xfs_bmap_ptr_iaddr(xfs_bmbt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_PTR_IADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_RBLOCK_DSIZE) +/*ARGSUSED1*/ +int +xfs_bmap_rblock_dsize(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_RBLOCK_DSIZE(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_RBLOCK_ISIZE) +/*ARGSUSED1*/ +int +xfs_bmap_rblock_isize(int lev, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_RBLOCK_ISIZE(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_REC_DADDR) +/*ARGSUSED3*/ +xfs_bmbt_rec_t * +xfs_bmap_rec_daddr(xfs_bmbt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_REC_DADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_REC_IADDR) +/*ARGSUSED3*/ +xfs_bmbt_rec_t * +xfs_bmap_rec_iaddr(xfs_bmbt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_BMAP_REC_IADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAP_SANITY_CHECK) +int +xfs_bmap_sanity_check(xfs_mount_t *mp, xfs_bmbt_block_t *bb, int level) +{ + return XFS_BMAP_SANITY_CHECK(mp, bb, level); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMAPI_AFLAG) +int +xfs_bmapi_aflag(int w) +{ + return XFS_BMAPI_AFLAG(w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BMDR_SPACE_CALC) +int +xfs_bmdr_space_calc(int nrecs) +{ + return XFS_BMDR_SPACE_CALC(nrecs); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BNO_BLOCK) +xfs_agblock_t +xfs_bno_block(xfs_mount_t *mp) +{ + return XFS_BNO_BLOCK(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BTREE_LONG_PTRS) +int +xfs_btree_long_ptrs(xfs_btnum_t btnum) +{ + return XFS_BTREE_LONG_PTRS(btnum); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_AGF) +xfs_agf_t * +xfs_buf_to_agf(xfs_buf_t *bp) +{ + return XFS_BUF_TO_AGF(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_AGFL) +xfs_agfl_t * +xfs_buf_to_agfl(xfs_buf_t *bp) +{ + return XFS_BUF_TO_AGFL(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_AGI) +xfs_agi_t * +xfs_buf_to_agi(xfs_buf_t *bp) +{ + return XFS_BUF_TO_AGI(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_ALLOC_BLOCK) +xfs_alloc_block_t * +xfs_buf_to_alloc_block(xfs_buf_t *bp) +{ + return XFS_BUF_TO_ALLOC_BLOCK(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_BLOCK) +xfs_btree_block_t * +xfs_buf_to_block(xfs_buf_t *bp) +{ + return XFS_BUF_TO_BLOCK(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_BMBT_BLOCK) +xfs_bmbt_block_t * +xfs_buf_to_bmbt_block(xfs_buf_t *bp) +{ + return XFS_BUF_TO_BMBT_BLOCK(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_DINODE) +xfs_dinode_t * +xfs_buf_to_dinode(xfs_buf_t *bp) +{ + return XFS_BUF_TO_DINODE(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_INOBT_BLOCK) +xfs_inobt_block_t * +xfs_buf_to_inobt_block(xfs_buf_t *bp) +{ + return XFS_BUF_TO_INOBT_BLOCK(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_LBLOCK) +xfs_btree_lblock_t * +xfs_buf_to_lblock(xfs_buf_t *bp) +{ + return XFS_BUF_TO_LBLOCK(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_SBLOCK) +xfs_btree_sblock_t * +xfs_buf_to_sblock(xfs_buf_t *bp) +{ + return XFS_BUF_TO_SBLOCK(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_BUF_TO_SBP) +xfs_sb_t * +xfs_buf_to_sbp(xfs_buf_t *bp) +{ + return XFS_BUF_TO_SBP(bp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_ASIZE) +int +xfs_cfork_asize_arch(xfs_dinode_core_t *dcp, xfs_mount_t *mp, xfs_arch_t arch) +{ + return XFS_CFORK_ASIZE_ARCH(dcp, mp, arch); +} +int +xfs_cfork_asize(xfs_dinode_core_t *dcp, xfs_mount_t *mp) +{ + return XFS_CFORK_ASIZE(dcp, mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_BOFF) +int +xfs_cfork_boff_arch(xfs_dinode_core_t *dcp, xfs_arch_t arch) +{ + return XFS_CFORK_BOFF_ARCH(dcp, arch); +} +int +xfs_cfork_boff(xfs_dinode_core_t *dcp) +{ + return XFS_CFORK_BOFF(dcp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_DSIZE) +int +xfs_cfork_dsize_arch(xfs_dinode_core_t *dcp, xfs_mount_t *mp, xfs_arch_t arch) +{ + return XFS_CFORK_DSIZE_ARCH(dcp, mp, arch); +} +int +xfs_cfork_dsize(xfs_dinode_core_t *dcp, xfs_mount_t *mp) +{ + return XFS_CFORK_DSIZE(dcp, mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_FMT_SET) +void +xfs_cfork_fmt_set_arch(xfs_dinode_core_t *dcp, int w, int n, xfs_arch_t arch) +{ + XFS_CFORK_FMT_SET_ARCH(dcp, w, n, arch); +} +void +xfs_cfork_fmt_set(xfs_dinode_core_t *dcp, int w, int n) +{ + XFS_CFORK_FMT_SET(dcp, w, n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_FORMAT) +int +xfs_cfork_format_arch(xfs_dinode_core_t *dcp, int w, xfs_arch_t arch) +{ + return XFS_CFORK_FORMAT_ARCH(dcp, w, arch); +} +int +xfs_cfork_format(xfs_dinode_core_t *dcp, int w) +{ + return XFS_CFORK_FORMAT(dcp, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_NEXT_SET) +void +xfs_cfork_next_set_arch(xfs_dinode_core_t *dcp, int w, int n, xfs_arch_t arch) +{ + XFS_CFORK_NEXT_SET_ARCH(dcp, w, n, arch); +} +void +xfs_cfork_next_set(xfs_dinode_core_t *dcp, int w, int n) +{ + XFS_CFORK_NEXT_SET(dcp, w, n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_NEXTENTS) +int +xfs_cfork_nextents_arch(xfs_dinode_core_t *dcp, int w, xfs_arch_t arch) +{ + return XFS_CFORK_NEXTENTS_ARCH(dcp, w, arch); +} +int +xfs_cfork_nextents(xfs_dinode_core_t *dcp, int w) +{ + return XFS_CFORK_NEXTENTS(dcp, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_Q) +int +xfs_cfork_q_arch(xfs_dinode_core_t *dcp, xfs_arch_t arch) +{ + return XFS_CFORK_Q_ARCH(dcp, arch); +} +int +xfs_cfork_q(xfs_dinode_core_t *dcp) +{ + return XFS_CFORK_Q(dcp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CFORK_SIZE) +int +xfs_cfork_size_arch(xfs_dinode_core_t *dcp, xfs_mount_t *mp, int w, xfs_arch_t arch) +{ + return XFS_CFORK_SIZE_ARCH(dcp, mp, w, arch); +} +int +xfs_cfork_size(xfs_dinode_core_t *dcp, xfs_mount_t *mp, int w) +{ + return XFS_CFORK_SIZE(dcp, mp, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_CNT_BLOCK) +xfs_agblock_t +xfs_cnt_block(xfs_mount_t *mp) +{ + return XFS_CNT_BLOCK(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DA_COOKIE_BNO) +xfs_dablk_t +xfs_da_cookie_bno(xfs_mount_t *mp, xfs_off_t cookie) +{ + return XFS_DA_COOKIE_BNO(mp, cookie); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DA_COOKIE_ENTRY) +int +xfs_da_cookie_entry(xfs_mount_t *mp, xfs_off_t cookie) +{ + return XFS_DA_COOKIE_ENTRY(mp, cookie); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DA_COOKIE_HASH) +/*ARGSUSED1*/ +xfs_dahash_t +xfs_da_cookie_hash(xfs_mount_t *mp, xfs_off_t cookie) +{ + return XFS_DA_COOKIE_HASH(mp, cookie); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DA_MAKE_BNOENTRY) +__uint32_t +xfs_da_make_bnoentry(xfs_mount_t *mp, xfs_dablk_t bno, int entry) +{ + return XFS_DA_MAKE_BNOENTRY(mp, bno, entry); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DA_MAKE_COOKIE) +xfs_off_t +xfs_da_make_cookie(xfs_mount_t *mp, xfs_dablk_t bno, int entry, + xfs_dahash_t hash) +{ + return XFS_DA_MAKE_COOKIE(mp, bno, entry, hash); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DA_NODE_ENTRIES) +int +xfs_da_node_entries(xfs_mount_t *mp) +{ + return XFS_DA_NODE_ENTRIES(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DADDR_TO_AGBNO) +xfs_agblock_t +xfs_daddr_to_agbno(xfs_mount_t *mp, xfs_daddr_t d) +{ + return XFS_DADDR_TO_AGBNO(mp, d); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DADDR_TO_AGNO) +xfs_agnumber_t +xfs_daddr_to_agno(xfs_mount_t *mp, xfs_daddr_t d) +{ + return XFS_DADDR_TO_AGNO(mp, d); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DADDR_TO_FSB) +xfs_fsblock_t +xfs_daddr_to_fsb(xfs_mount_t *mp, xfs_daddr_t d) +{ + return XFS_DADDR_TO_FSB(mp, d); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_APTR) +char * +xfs_dfork_aptr_arch(xfs_dinode_t *dip, xfs_arch_t arch) +{ + return XFS_DFORK_APTR_ARCH(dip, arch); +} +char * +xfs_dfork_aptr(xfs_dinode_t *dip) +{ + return XFS_DFORK_APTR(dip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_ASIZE) +int +xfs_dfork_asize_arch(xfs_dinode_t *dip, xfs_mount_t *mp, xfs_arch_t arch) +{ + return XFS_DFORK_ASIZE_ARCH(dip, mp, arch); +} +int +xfs_dfork_asize(xfs_dinode_t *dip, xfs_mount_t *mp) +{ + return XFS_DFORK_ASIZE(dip, mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_BOFF) +int +xfs_dfork_boff_arch(xfs_dinode_t *dip, xfs_arch_t arch) +{ + return XFS_DFORK_BOFF_ARCH(dip, arch); +} +int +xfs_dfork_boff(xfs_dinode_t *dip) +{ + return XFS_DFORK_BOFF(dip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_DPTR) +char * +xfs_dfork_dptr_arch(xfs_dinode_t *dip, xfs_arch_t arch) +{ + return XFS_DFORK_DPTR_ARCH(dip, arch); +} +char * +xfs_dfork_dptr(xfs_dinode_t *dip) +{ + return XFS_DFORK_DPTR(dip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_DSIZE) +int +xfs_dfork_dsize_arch(xfs_dinode_t *dip, xfs_mount_t *mp, xfs_arch_t arch) +{ + return XFS_DFORK_DSIZE_ARCH(dip, mp, arch); +} +int +xfs_dfork_dsize(xfs_dinode_t *dip, xfs_mount_t *mp) +{ + return XFS_DFORK_DSIZE(dip, mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_FMT_SET) +void +xfs_dfork_fmt_set_arch(xfs_dinode_t *dip, int w, int n, xfs_arch_t arch) +{ + XFS_DFORK_FMT_SET_ARCH(dip, w, n, arch); +} +void +xfs_dfork_fmt_set(xfs_dinode_t *dip, int w, int n) +{ + XFS_DFORK_FMT_SET(dip, w, n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_FORMAT) +int +xfs_dfork_format_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch) +{ + return XFS_DFORK_FORMAT_ARCH(dip, w, arch); +} +int +xfs_dfork_format(xfs_dinode_t *dip, int w) +{ + return XFS_DFORK_FORMAT(dip, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_NEXT_SET) +void +xfs_dfork_next_set_arch(xfs_dinode_t *dip, int w, int n, xfs_arch_t arch) +{ + XFS_DFORK_NEXT_SET_ARCH(dip, w, n, arch); +} +void +xfs_dfork_next_set(xfs_dinode_t *dip, int w, int n) +{ + XFS_DFORK_NEXT_SET(dip, w, n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_NEXTENTS) +int +xfs_dfork_nextents_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch) +{ + return XFS_DFORK_NEXTENTS_ARCH(dip, w, arch); +} +int +xfs_dfork_nextents(xfs_dinode_t *dip, int w) +{ + return XFS_DFORK_NEXTENTS(dip, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_PTR) +char * +xfs_dfork_ptr_arch(xfs_dinode_t *dip, int w, xfs_arch_t arch) +{ + return XFS_DFORK_PTR_ARCH(dip, w, arch); +} +char * +xfs_dfork_ptr(xfs_dinode_t *dip, int w) +{ + return XFS_DFORK_PTR(dip, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_Q) +int +xfs_dfork_q_arch(xfs_dinode_t *dip, xfs_arch_t arch) +{ + return XFS_DFORK_Q_ARCH(dip, arch); +} +int +xfs_dfork_q(xfs_dinode_t *dip) +{ + return XFS_DFORK_Q(dip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DFORK_SIZE) +int +xfs_dfork_size_arch(xfs_dinode_t *dip, xfs_mount_t *mp, int w, xfs_arch_t arch) +{ + return XFS_DFORK_SIZE_ARCH(dip, mp, w, arch); +} +int +xfs_dfork_size(xfs_dinode_t *dip, xfs_mount_t *mp, int w) +{ + return XFS_DFORK_SIZE(dip, mp, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DINODE_GOOD_VERSION) +int +xfs_dinode_good_version(int v) +{ + return XFS_DINODE_GOOD_VERSION(v); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_LEAF_ENTSIZE_BYENTRY) +int +xfs_dir_leaf_entsize_byentry(xfs_dir_leaf_entry_t *entry) +{ + return XFS_DIR_LEAF_ENTSIZE_BYENTRY(entry); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_LEAF_ENTSIZE_BYNAME) +int +xfs_dir_leaf_entsize_byname(int len) +{ + return XFS_DIR_LEAF_ENTSIZE_BYNAME(len); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_LEAF_NAMESTRUCT) +xfs_dir_leaf_name_t * +xfs_dir_leaf_namestruct(xfs_dir_leafblock_t *leafp, int offset) +{ + return XFS_DIR_LEAF_NAMESTRUCT(leafp, offset); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_SF_ALLFIT) +int +xfs_dir_sf_allfit(int count, int totallen) +{ + return XFS_DIR_SF_ALLFIT(count, totallen); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_SF_ENTSIZE_BYENTRY) +int +xfs_dir_sf_entsize_byentry(xfs_dir_sf_entry_t *sfep) +{ + return XFS_DIR_SF_ENTSIZE_BYENTRY(sfep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_SF_ENTSIZE_BYNAME) +int +xfs_dir_sf_entsize_byname(int len) +{ + return XFS_DIR_SF_ENTSIZE_BYNAME(len); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_SF_GET_DIRINO) +void +xfs_dir_sf_get_dirino_arch(xfs_dir_ino_t *from, xfs_ino_t *to, xfs_arch_t arch) +{ + XFS_DIR_SF_GET_DIRINO_ARCH(from, to, arch); +} +void +xfs_dir_sf_get_dirino(xfs_dir_ino_t *from, xfs_ino_t *to) +{ + XFS_DIR_SF_GET_DIRINO(from, to); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_SF_NEXTENTRY) +xfs_dir_sf_entry_t * +xfs_dir_sf_nextentry(xfs_dir_sf_entry_t *sfep) +{ + return XFS_DIR_SF_NEXTENTRY(sfep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR_SF_PUT_DIRINO) +void +xfs_dir_sf_put_dirino_arch(xfs_ino_t *from, xfs_dir_ino_t *to, xfs_arch_t arch) +{ + XFS_DIR_SF_PUT_DIRINO_ARCH(from, to, arch); +} +void +xfs_dir_sf_put_dirino(xfs_ino_t *from, xfs_dir_ino_t *to) +{ + XFS_DIR_SF_PUT_DIRINO(from, to); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_BLOCK_LEAF_P) +xfs_dir2_leaf_entry_t * +xfs_dir2_block_leaf_p_arch(xfs_dir2_block_tail_t *btp, xfs_arch_t arch) +{ + return XFS_DIR2_BLOCK_LEAF_P_ARCH(btp,arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_BLOCK_TAIL_P) +xfs_dir2_block_tail_t * +xfs_dir2_block_tail_p(xfs_mount_t *mp, xfs_dir2_block_t *block) +{ + return XFS_DIR2_BLOCK_TAIL_P(mp, block); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_BYTE_TO_DA) +xfs_dablk_t +xfs_dir2_byte_to_da(xfs_mount_t *mp, xfs_dir2_off_t by) +{ + return XFS_DIR2_BYTE_TO_DA(mp, by); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_BYTE_TO_DATAPTR) +/* ARGSUSED */ +xfs_dir2_dataptr_t +xfs_dir2_byte_to_dataptr(xfs_mount_t *mp, xfs_dir2_off_t by) +{ + return XFS_DIR2_BYTE_TO_DATAPTR(mp, by); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_BYTE_TO_DB) +xfs_dir2_db_t +xfs_dir2_byte_to_db(xfs_mount_t *mp, xfs_dir2_off_t by) +{ + return XFS_DIR2_BYTE_TO_DB(mp, by); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_BYTE_TO_OFF) +xfs_dir2_data_aoff_t +xfs_dir2_byte_to_off(xfs_mount_t *mp, xfs_dir2_off_t by) +{ + return XFS_DIR2_BYTE_TO_OFF(mp, by); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DA_TO_BYTE) +xfs_dir2_off_t +xfs_dir2_da_to_byte(xfs_mount_t *mp, xfs_dablk_t da) +{ + return XFS_DIR2_DA_TO_BYTE(mp, da); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DA_TO_DB) +xfs_dir2_db_t +xfs_dir2_da_to_db(xfs_mount_t *mp, xfs_dablk_t da) +{ + return XFS_DIR2_DA_TO_DB(mp, da); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DATA_ENTRY_TAG_P) +xfs_dir2_data_off_t * +xfs_dir2_data_entry_tag_p(xfs_dir2_data_entry_t *dep) +{ + return XFS_DIR2_DATA_ENTRY_TAG_P(dep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DATA_ENTSIZE) +int +xfs_dir2_data_entsize(int n) +{ + return XFS_DIR2_DATA_ENTSIZE(n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DATA_UNUSED_TAG_P) +xfs_dir2_data_off_t * +xfs_dir2_data_unused_tag_p_arch(xfs_dir2_data_unused_t *dup, xfs_arch_t arch) +{ + return XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup,arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DATAPTR_TO_BYTE) +/* ARGSUSED */ +xfs_dir2_off_t +xfs_dir2_dataptr_to_byte(xfs_mount_t *mp, xfs_dir2_dataptr_t dp) +{ + return XFS_DIR2_DATAPTR_TO_BYTE(mp, dp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DATAPTR_TO_DB) +xfs_dir2_db_t +xfs_dir2_dataptr_to_db(xfs_mount_t *mp, xfs_dir2_dataptr_t dp) +{ + return XFS_DIR2_DATAPTR_TO_DB(mp, dp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DATAPTR_TO_OFF) +xfs_dir2_data_aoff_t +xfs_dir2_dataptr_to_off(xfs_mount_t *mp, xfs_dir2_dataptr_t dp) +{ + return XFS_DIR2_DATAPTR_TO_OFF(mp, dp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DB_OFF_TO_BYTE) +xfs_dir2_off_t +xfs_dir2_db_off_to_byte(xfs_mount_t *mp, xfs_dir2_db_t db, + xfs_dir2_data_aoff_t o) +{ + return XFS_DIR2_DB_OFF_TO_BYTE(mp, db, o); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DB_OFF_TO_DATAPTR) +xfs_dir2_dataptr_t +xfs_dir2_db_off_to_dataptr(xfs_mount_t *mp, xfs_dir2_db_t db, + xfs_dir2_data_aoff_t o) +{ + return XFS_DIR2_DB_OFF_TO_DATAPTR(mp, db, o); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DB_TO_DA) +xfs_dablk_t +xfs_dir2_db_to_da(xfs_mount_t *mp, xfs_dir2_db_t db) +{ + return XFS_DIR2_DB_TO_DA(mp, db); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DB_TO_FDB) +xfs_dir2_db_t +xfs_dir2_db_to_fdb(xfs_mount_t *mp, xfs_dir2_db_t db) +{ + return XFS_DIR2_DB_TO_FDB(mp, db); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_DB_TO_FDINDEX) +int +xfs_dir2_db_to_fdindex(xfs_mount_t *mp, xfs_dir2_db_t db) +{ + return XFS_DIR2_DB_TO_FDINDEX(mp, db); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_LEAF_BESTS_P) +xfs_dir2_data_off_t * +xfs_dir2_leaf_bests_p_arch(xfs_dir2_leaf_tail_t *ltp, xfs_arch_t arch) +{ + return XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_LEAF_TAIL_P) +xfs_dir2_leaf_tail_t * +xfs_dir2_leaf_tail_p(xfs_mount_t *mp, xfs_dir2_leaf_t *lp) +{ + return XFS_DIR2_LEAF_TAIL_P(mp, lp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_MAX_LEAF_ENTS) +int +xfs_dir2_max_leaf_ents(xfs_mount_t *mp) +{ + return XFS_DIR2_MAX_LEAF_ENTS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_ENTSIZE_BYENTRY) +int +xfs_dir2_sf_entsize_byentry(xfs_dir2_sf_t *sfp, xfs_dir2_sf_entry_t *sfep) +{ + return XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_FIRSTENTRY) +xfs_dir2_sf_entry_t * +xfs_dir2_sf_firstentry(xfs_dir2_sf_t *sfp) +{ + return XFS_DIR2_SF_FIRSTENTRY(sfp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_ENTSIZE_BYNAME) +int +xfs_dir2_sf_entsize_byname(xfs_dir2_sf_t *sfp, int len) +{ + return XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, len); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_GET_INUMBER) +xfs_intino_t +xfs_dir2_sf_get_inumber_arch(xfs_dir2_sf_t *sfp, xfs_dir2_inou_t *from, xfs_arch_t arch) +{ + return XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, from, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_GET_OFFSET) +xfs_dir2_data_aoff_t +xfs_dir2_sf_get_offset_arch(xfs_dir2_sf_entry_t *sfep, xfs_arch_t arch) +{ + return XFS_DIR2_SF_GET_OFFSET_ARCH(sfep, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_HDR_SIZE) +int +xfs_dir2_sf_hdr_size(int i8count) +{ + return XFS_DIR2_SF_HDR_SIZE(i8count); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_INUMBERP) +xfs_dir2_inou_t * +xfs_dir2_sf_inumberp(xfs_dir2_sf_entry_t *sfep) +{ + return XFS_DIR2_SF_INUMBERP(sfep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_NEXTENTRY) +xfs_dir2_sf_entry_t * +xfs_dir2_sf_nextentry(xfs_dir2_sf_t *sfp, xfs_dir2_sf_entry_t *sfep) +{ + return XFS_DIR2_SF_NEXTENTRY(sfp, sfep); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_PUT_INUMBER) +void +xfs_dir2_sf_put_inumber_arch(xfs_dir2_sf_t *sfp, xfs_ino_t *from, xfs_dir2_inou_t *to, xfs_arch_t arch) +{ + XFS_DIR2_SF_PUT_INUMBER_ARCH(sfp, from, to, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DIR2_SF_PUT_OFFSET) +void +xfs_dir2_sf_put_offset_arch(xfs_dir2_sf_entry_t *sfep, xfs_dir2_data_aoff_t off, xfs_arch_t arch) +{ + XFS_DIR2_SF_PUT_OFFSET_ARCH(sfep, off, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_EXTFMT_INODE ) +xfs_exntfmt_t +xfs_extfmt_inode(struct xfs_inode *ip) +{ + return XFS_EXTFMT_INODE(ip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_EXTLEN_MAX) +xfs_extlen_t +xfs_extlen_max(xfs_extlen_t a, xfs_extlen_t b) +{ + return XFS_EXTLEN_MAX(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_EXTLEN_MIN) +xfs_extlen_t +xfs_extlen_min(xfs_extlen_t a, xfs_extlen_t b) +{ + return XFS_EXTLEN_MIN(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FILBLKS_MAX) +xfs_filblks_t +xfs_filblks_max(xfs_filblks_t a, xfs_filblks_t b) +{ + return XFS_FILBLKS_MAX(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FILBLKS_MIN) +xfs_filblks_t +xfs_filblks_min(xfs_filblks_t a, xfs_filblks_t b) +{ + return XFS_FILBLKS_MIN(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FILEOFF_MAX) +xfs_fileoff_t +xfs_fileoff_max(xfs_fileoff_t a, xfs_fileoff_t b) +{ + return XFS_FILEOFF_MAX(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FILEOFF_MIN) +xfs_fileoff_t +xfs_fileoff_min(xfs_fileoff_t a, xfs_fileoff_t b) +{ + return XFS_FILEOFF_MIN(a, b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FSB_SANITY_CHECK) +int +xfs_fsb_sanity_check(xfs_mount_t *mp, xfs_fsblock_t fsbno) +{ + return XFS_FSB_SANITY_CHECK(mp, fsbno); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FSB_TO_AGBNO) +xfs_agblock_t +xfs_fsb_to_agbno(xfs_mount_t *mp, xfs_fsblock_t fsbno) +{ + return XFS_FSB_TO_AGBNO(mp, fsbno); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FSB_TO_AGNO) +xfs_agnumber_t +xfs_fsb_to_agno(xfs_mount_t *mp, xfs_fsblock_t fsbno) +{ + return XFS_FSB_TO_AGNO(mp, fsbno); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FSB_TO_DADDR) +xfs_daddr_t +xfs_fsb_to_daddr(xfs_mount_t *mp, xfs_fsblock_t fsbno) +{ + return XFS_FSB_TO_DADDR(mp, fsbno); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_FSB_TO_DB) +xfs_daddr_t +xfs_fsb_to_db(xfs_inode_t *ip, xfs_fsblock_t fsb) +{ + return XFS_FSB_TO_DB(ip, fsb); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_HDR_BLOCK) +xfs_agblock_t +xfs_hdr_block(xfs_mount_t *mp, xfs_daddr_t d) +{ + return XFS_HDR_BLOCK(mp, d); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IALLOC_BLOCKS) +xfs_extlen_t +xfs_ialloc_blocks(xfs_mount_t *mp) +{ + return XFS_IALLOC_BLOCKS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IALLOC_FIND_FREE) +int +xfs_ialloc_find_free(xfs_inofree_t *fp) +{ + return XFS_IALLOC_FIND_FREE(fp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IALLOC_INODES) +int +xfs_ialloc_inodes(xfs_mount_t *mp) +{ + return XFS_IALLOC_INODES(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IBT_BLOCK) +xfs_agblock_t +xfs_ibt_block(xfs_mount_t *mp) +{ + return XFS_IBT_BLOCK(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_ASIZE) +int +xfs_ifork_asize(xfs_inode_t *ip) +{ + return XFS_IFORK_ASIZE(ip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_DSIZE) +int +xfs_ifork_dsize(xfs_inode_t *ip) +{ + return XFS_IFORK_DSIZE(ip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_FMT_SET) +void +xfs_ifork_fmt_set(xfs_inode_t *ip, int w, int n) +{ + XFS_IFORK_FMT_SET(ip, w, n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_FORMAT) +int +xfs_ifork_format(xfs_inode_t *ip, int w) +{ + return XFS_IFORK_FORMAT(ip, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_NEXT_SET) +void +xfs_ifork_next_set(xfs_inode_t *ip, int w, int n) +{ + XFS_IFORK_NEXT_SET(ip, w, n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_NEXTENTS) +int +xfs_ifork_nextents(xfs_inode_t *ip, int w) +{ + return XFS_IFORK_NEXTENTS(ip, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_PTR) +xfs_ifork_t * +xfs_ifork_ptr(xfs_inode_t *ip, int w) +{ + return XFS_IFORK_PTR(ip, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_Q) +int +xfs_ifork_q(xfs_inode_t *ip) +{ + return XFS_IFORK_Q(ip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IFORK_SIZE) +int +xfs_ifork_size(xfs_inode_t *ip, int w) +{ + return XFS_IFORK_SIZE(ip, w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ILOG_FBROOT) +int +xfs_ilog_fbroot(int w) +{ + return XFS_ILOG_FBROOT(w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ILOG_FDATA) +int +xfs_ilog_fdata(int w) +{ + return XFS_ILOG_FDATA(w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ILOG_FEXT) +int +xfs_ilog_fext(int w) +{ + return XFS_ILOG_FEXT(w); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_IN_MAXLEVELS) +int +xfs_in_maxlevels(xfs_mount_t *mp) +{ + return XFS_IN_MAXLEVELS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_AGBNO_BITS) +int +xfs_ino_agbno_bits(xfs_mount_t *mp) +{ + return XFS_INO_AGBNO_BITS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_AGINO_BITS) +int +xfs_ino_agino_bits(xfs_mount_t *mp) +{ + return XFS_INO_AGINO_BITS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_AGNO_BITS) +int +xfs_ino_agno_bits(xfs_mount_t *mp) +{ + return XFS_INO_AGNO_BITS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_BITS) +int +xfs_ino_bits(xfs_mount_t *mp) +{ + return XFS_INO_BITS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_MASK) +__uint32_t +xfs_ino_mask(int k) +{ + return XFS_INO_MASK(k); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_OFFSET_BITS) +int +xfs_ino_offset_bits(xfs_mount_t *mp) +{ + return XFS_INO_OFFSET_BITS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_TO_AGBNO) +xfs_agblock_t +xfs_ino_to_agbno(xfs_mount_t *mp, xfs_ino_t i) +{ + return XFS_INO_TO_AGBNO(mp, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_TO_AGINO) +xfs_agino_t +xfs_ino_to_agino(xfs_mount_t *mp, xfs_ino_t i) +{ + return XFS_INO_TO_AGINO(mp, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_TO_AGNO) +xfs_agnumber_t +xfs_ino_to_agno(xfs_mount_t *mp, xfs_ino_t i) +{ + return XFS_INO_TO_AGNO(mp, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_TO_FSB) +xfs_fsblock_t +xfs_ino_to_fsb(xfs_mount_t *mp, xfs_ino_t i) +{ + return XFS_INO_TO_FSB(mp, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INO_TO_OFFSET) +int +xfs_ino_to_offset(xfs_mount_t *mp, xfs_ino_t i) +{ + return XFS_INO_TO_OFFSET(mp, i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_BLOCK_MAXRECS) +int +xfs_inobt_block_maxrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_INOBT_BLOCK_MAXRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_BLOCK_MINRECS) +int +xfs_inobt_block_minrecs(int lev, xfs_btree_cur_t *cur) +{ + return XFS_INOBT_BLOCK_MINRECS(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_BLOCK_SIZE) +/*ARGSUSED1*/ +int +xfs_inobt_block_size(int lev, xfs_btree_cur_t *cur) +{ + return XFS_INOBT_BLOCK_SIZE(lev, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_CLR_FREE) +void +xfs_inobt_clr_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch) +{ + XFS_INOBT_CLR_FREE(rp, i, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_IS_FREE) +int +xfs_inobt_is_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch) +{ + return XFS_INOBT_IS_FREE(rp, i, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_IS_LAST_REC) +int +xfs_inobt_is_last_rec(xfs_btree_cur_t *cur) +{ + return XFS_INOBT_IS_LAST_REC(cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_KEY_ADDR) +/*ARGSUSED3*/ +xfs_inobt_key_t * +xfs_inobt_key_addr(xfs_inobt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_INOBT_KEY_ADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_MASK) +xfs_inofree_t +xfs_inobt_mask(int i) +{ + return XFS_INOBT_MASK(i); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_MASKN) +xfs_inofree_t +xfs_inobt_maskn(int i, int n) +{ + return XFS_INOBT_MASKN(i, n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_PTR_ADDR) +xfs_inobt_ptr_t * +xfs_inobt_ptr_addr(xfs_inobt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_INOBT_PTR_ADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_REC_ADDR) +/*ARGSUSED3*/ +xfs_inobt_rec_t * +xfs_inobt_rec_addr(xfs_inobt_block_t *bb, int i, xfs_btree_cur_t *cur) +{ + return XFS_INOBT_REC_ADDR(bb, i, cur); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INOBT_SET_FREE) +void +xfs_inobt_set_free(xfs_inobt_rec_t *rp, int i, xfs_arch_t arch) +{ + XFS_INOBT_SET_FREE(rp, i, arch); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_INODE_CLEAR_READ_AHEAD) +void +xfs_inode_clear_read_ahead(xfs_iocore_t *io) +{ + XFS_INODE_CLEAR_READ_AHEAD(io); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ITOBHV) +bhv_desc_t * +xfs_itobhv(xfs_inode_t *ip) +{ + return XFS_ITOBHV(ip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_ITOV) +vnode_t * +xfs_itov(xfs_inode_t *ip) +{ + return XFS_ITOV(ip); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LBLOG) +int +xfs_lblog(xfs_mount_t *mp) +{ + return XFS_LBLOG(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LBSIZE) +int +xfs_lbsize(xfs_mount_t *mp) +{ + return XFS_LBSIZE(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_ALL_FREE) +void +xfs_lic_all_free(xfs_log_item_chunk_t *cp) +{ + XFS_LIC_ALL_FREE(cp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_ARE_ALL_FREE) +int +xfs_lic_are_all_free(xfs_log_item_chunk_t *cp) +{ + return XFS_LIC_ARE_ALL_FREE(cp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_CLAIM) +void +xfs_lic_claim(xfs_log_item_chunk_t *cp, int slot) +{ + XFS_LIC_CLAIM(cp, slot); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_DESC_TO_CHUNK) +xfs_log_item_chunk_t * +xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp) +{ + return XFS_LIC_DESC_TO_CHUNK(dp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_DESC_TO_SLOT) +int +xfs_lic_desc_to_slot(xfs_log_item_desc_t *dp) +{ + return XFS_LIC_DESC_TO_SLOT(dp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_INIT) +void +xfs_lic_init(xfs_log_item_chunk_t *cp) +{ + XFS_LIC_INIT(cp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_INIT_SLOT) +void +xfs_lic_init_slot(xfs_log_item_chunk_t *cp, int slot) +{ + XFS_LIC_INIT_SLOT(cp, slot); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_ISFREE) +int +xfs_lic_isfree(xfs_log_item_chunk_t *cp, int slot) +{ + return XFS_LIC_ISFREE(cp, slot); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_RELSE) +void +xfs_lic_relse(xfs_log_item_chunk_t *cp, int slot) +{ + XFS_LIC_RELSE(cp, slot); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_SLOT) +xfs_log_item_desc_t * +xfs_lic_slot(xfs_log_item_chunk_t *cp, int slot) +{ + return XFS_LIC_SLOT(cp, slot); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LIC_VACANCY) +int +xfs_lic_vacancy(xfs_log_item_chunk_t *cp) +{ + return XFS_LIC_VACANCY(cp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_LITINO) +int +xfs_litino(xfs_mount_t *mp) +{ + return XFS_LITINO(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MAKE_IPTR) +xfs_dinode_t * +xfs_make_iptr(xfs_mount_t *mp, xfs_buf_t *b, int o) +{ + return XFS_MAKE_IPTR(mp, b, o); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MASK32HI) +__uint32_t +xfs_mask32hi(int n) +{ + return XFS_MASK32HI(n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MASK32LO) +__uint32_t +xfs_mask32lo(int n) +{ + return XFS_MASK32LO(n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MASK64HI) +__uint64_t +xfs_mask64hi(int n) +{ + return XFS_MASK64HI(n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MASK64LO) +__uint64_t +xfs_mask64lo(int n) +{ + return XFS_MASK64LO(n); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MIN_FREELIST) +int +xfs_min_freelist(xfs_agf_t *a, xfs_mount_t *mp) +{ + return XFS_MIN_FREELIST(a, mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MIN_FREELIST_PAG) +int +xfs_min_freelist_pag(xfs_perag_t *pag, xfs_mount_t *mp) +{ + return XFS_MIN_FREELIST_PAG(pag, mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MIN_FREELIST_RAW) +int +xfs_min_freelist_raw(int bl, int cl, xfs_mount_t *mp) +{ + return XFS_MIN_FREELIST_RAW(bl, cl, mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_MTOVFS) +vfs_t * +xfs_mtovfs(xfs_mount_t *mp) +{ + return XFS_MTOVFS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_OFFBNO_TO_AGINO) +xfs_agino_t +xfs_offbno_to_agino(xfs_mount_t *mp, xfs_agblock_t b, int o) +{ + return XFS_OFFBNO_TO_AGINO(mp, b, o); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_PREALLOC_BLOCKS) +xfs_agblock_t +xfs_prealloc_blocks(xfs_mount_t *mp) +{ + return XFS_PREALLOC_BLOCKS(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_BLOCK) +xfs_agblock_t +xfs_sb_block(xfs_mount_t *mp) +{ + return XFS_SB_BLOCK(mp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_GOOD_VERSION) +int +xfs_sb_good_version(xfs_sb_t *sbp) +{ + return XFS_SB_GOOD_VERSION(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_ADDATTR) +void +xfs_sb_version_addattr(xfs_sb_t *sbp) +{ + XFS_SB_VERSION_ADDATTR(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_ADDDALIGN) +void +xfs_sb_version_adddalign(xfs_sb_t *sbp) +{ + XFS_SB_VERSION_ADDDALIGN(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_ADDNLINK) +void +xfs_sb_version_addnlink(xfs_sb_t *sbp) +{ + XFS_SB_VERSION_ADDNLINK(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_ADDQUOTA) +void +xfs_sb_version_addquota(xfs_sb_t *sbp) +{ + XFS_SB_VERSION_ADDQUOTA(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_ADDSHARED) +void +xfs_sb_version_addshared(xfs_sb_t *sbp) +{ + XFS_SB_VERSION_ADDSHARED(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASALIGN) +int +xfs_sb_version_hasalign(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASALIGN(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASATTR) +int +xfs_sb_version_hasattr(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASATTR(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASDALIGN) +int +xfs_sb_version_hasdalign(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASDALIGN(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASDIRV2) +int +xfs_sb_version_hasdirv2(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASDIRV2(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASEXTFLGBIT) +int +xfs_sb_version_hasextflgbit(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASEXTFLGBIT(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASNLINK) +int +xfs_sb_version_hasnlink(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASNLINK(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASQUOTA) +int +xfs_sb_version_hasquota(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASQUOTA(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASSHARED) +int +xfs_sb_version_hasshared(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_HASSHARED(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_NUM) +int +xfs_sb_version_num(xfs_sb_t *sbp) +{ + return XFS_SB_VERSION_NUM(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_SUBALIGN) +void +xfs_sb_version_subalign(xfs_sb_t *sbp) +{ + XFS_SB_VERSION_SUBALIGN(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_SUBSHARED) +void +xfs_sb_version_subshared(xfs_sb_t *sbp) +{ + XFS_SB_VERSION_SUBSHARED(sbp); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_TONEW) +unsigned +xfs_sb_version_tonew(unsigned v) +{ + return XFS_SB_VERSION_TONEW(v); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_TOOLD) +unsigned +xfs_sb_version_toold(unsigned v) +{ + return XFS_SB_VERSION_TOOLD(v); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XLOG_BTOLRBB) +int +xlog_btolrbb(int b) +{ + return XLOG_BTOLRBB(b); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XLOG_GRANT_ADD_SPACE) +void +xlog_grant_add_space(xlog_t *log, int bytes, int type) +{ + XLOG_GRANT_ADD_SPACE(log, bytes, type); +} +#endif + +#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XLOG_GRANT_SUB_SPACE) +void +xlog_grant_sub_space(xlog_t *log, int bytes, int type) +{ + XLOG_GRANT_SUB_SPACE(log, bytes, type); +} +#endif diff -rNu linux-2.4.7/linux/fs/xfs/xfs_macros.h linux-2.4-xfs/linux/fs/xfs/xfs_macros.h --- linux-2.4.7/linux/fs/xfs/xfs_macros.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_macros.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_MACROS_H__ +#define __XFS_MACROS_H__ + +/* + * Set for debug kernels and simulation, and 32-bit kernels, + * but not for standalone. These replacements save space. + * Used in xfs_macros.c. + */ +#define XFS_WANT_SPACE_C \ + (!defined(_STANDALONE) && \ + (defined(DEBUG) || (defined(_KERNEL)))) + +/* + * Set for debug simulation and kernel builds, but not for standalone. + * These replacements do not save space. + * Used in xfs_macros.c. + */ +#define XFS_WANT_FUNCS_C \ + (!defined(_STANDALONE) && defined(DEBUG)) + +/* + * Corresponding names used in .h files. + */ +#define XFS_WANT_SPACE (XFS_WANT_SPACE_C && !defined(XFS_MACRO_C)) +#define XFS_WANT_FUNCS (XFS_WANT_FUNCS_C && !defined(XFS_MACRO_C)) + +/* + * These are the macros that get turned into functions to save space. + */ +#define XFSSO_NULLSTARTBLOCK 1 +#define XFSSO_XFS_AGB_TO_DADDR 1 +#define XFSSO_XFS_AGB_TO_FSB 1 +#define XFSSO_XFS_AGINO_TO_INO 1 +#define XFSSO_XFS_ALLOC_BLOCK_MINRECS 1 +#define XFSSO_XFS_ATTR_SF_NEXTENTRY 1 +#define XFSSO_XFS_BMAP_BLOCK_DMAXRECS 1 +#define XFSSO_XFS_BMAP_BLOCK_IMAXRECS 1 +#define XFSSO_XFS_BMAP_BLOCK_IMINRECS 1 +#define XFSSO_XFS_BMAP_INIT 1 +#define XFSSO_XFS_BMAP_PTR_IADDR 1 +#define XFSSO_XFS_BMAP_SANITY_CHECK 1 +#define XFSSO_XFS_BMAPI_AFLAG 1 +#define XFSSO_XFS_CFORK_SIZE 1 +#define XFSSO_XFS_DA_COOKIE_BNO 1 +#define XFSSO_XFS_DA_COOKIE_ENTRY 1 +#define XFSSO_XFS_DADDR_TO_AGBNO 1 +#define XFSSO_XFS_DADDR_TO_FSB 1 +#define XFSSO_XFS_DFORK_PTR 1 +#define XFSSO_XFS_DIR_SF_GET_DIRINO 1 +#define XFSSO_XFS_DIR_SF_NEXTENTRY 1 +#define XFSSO_XFS_DIR_SF_PUT_DIRINO 1 +#define XFSSO_XFS_FILBLKS_MIN 1 +#define XFSSO_XFS_FSB_SANITY_CHECK 1 +#define XFSSO_XFS_FSB_TO_DADDR 1 +#define XFSSO_XFS_FSB_TO_DB 1 +#define XFSSO_XFS_IALLOC_INODES 1 +#define XFSSO_XFS_IFORK_ASIZE 1 +#define XFSSO_XFS_IFORK_DSIZE 1 +#define XFSSO_XFS_IFORK_FORMAT 1 +#define XFSSO_XFS_IFORK_NEXT_SET 1 +#define XFSSO_XFS_IFORK_NEXTENTS 1 +#define XFSSO_XFS_IFORK_PTR 1 +#define XFSSO_XFS_ILOG_FBROOT 1 +#define XFSSO_XFS_ILOG_FEXT 1 +#define XFSSO_XFS_INO_MASK 1 +#define XFSSO_XFS_INO_TO_FSB 1 +#define XFSSO_XFS_INODE_CLEAR_READ_AHEAD 1 +#define XFSSO_XFS_MIN_FREELIST 1 +#define XFSSO_XFS_SB_GOOD_VERSION 1 +#define XFSSO_XFS_SB_VERSION_HASNLINK 1 +#define XFSSO_XLOG_GRANT_ADD_SPACE 1 +#define XFSSO_XLOG_GRANT_SUB_SPACE 1 + +#endif /* __XFS_MACROS_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_mount.c linux-2.4-xfs/linux/fs/xfs/xfs_mount.c --- linux-2.4.7/linux/fs/xfs/xfs_mount.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_mount.c Fri Jun 29 17:29:47 2001 @@ -0,0 +1,1650 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +STATIC void xfs_sb_relse(xfs_buf_t *); +STATIC void xfs_mount_reset_sbqflags(xfs_mount_t *); +STATIC void xfs_mount_log_sbunit(xfs_mount_t *, __int64_t); +STATIC int xfs_uuid_mount(xfs_mount_t *); + +mutex_t xfs_uuidtabmon; /* monitor for uuidtab */ +STATIC int xfs_uuidtab_size; +STATIC uuid_t *xfs_uuidtab; + +STATIC void xfs_uuid_unmount(xfs_mount_t *); + +void xfs_xlatesb(void *, xfs_sb_t *, int, xfs_arch_t, __int64_t); + +static struct { + short offset; + short type; /* 0 = integer + * 1 = binary / string (no translation) + */ +} xfs_sb_info[] = { + { offsetof(xfs_sb_t, sb_magicnum), 0 }, + { offsetof(xfs_sb_t, sb_blocksize), 0 }, + { offsetof(xfs_sb_t, sb_dblocks), 0 }, + { offsetof(xfs_sb_t, sb_rblocks), 0 }, + { offsetof(xfs_sb_t, sb_rextents), 0 }, + { offsetof(xfs_sb_t, sb_uuid), 1 }, + { offsetof(xfs_sb_t, sb_logstart), 0 }, + { offsetof(xfs_sb_t, sb_rootino), 0 }, + { offsetof(xfs_sb_t, sb_rbmino), 0 }, + { offsetof(xfs_sb_t, sb_rsumino), 0 }, + { offsetof(xfs_sb_t, sb_rextsize), 0 }, + { offsetof(xfs_sb_t, sb_agblocks), 0 }, + { offsetof(xfs_sb_t, sb_agcount), 0 }, + { offsetof(xfs_sb_t, sb_rbmblocks), 0 }, + { offsetof(xfs_sb_t, sb_logblocks), 0 }, + { offsetof(xfs_sb_t, sb_versionnum), 0 }, + { offsetof(xfs_sb_t, sb_sectsize), 0 }, + { offsetof(xfs_sb_t, sb_inodesize), 0 }, + { offsetof(xfs_sb_t, sb_inopblock), 0 }, + { offsetof(xfs_sb_t, sb_fname[0]), 1 }, + { offsetof(xfs_sb_t, sb_blocklog), 0 }, + { offsetof(xfs_sb_t, sb_sectlog), 0 }, + { offsetof(xfs_sb_t, sb_inodelog), 0 }, + { offsetof(xfs_sb_t, sb_inopblog), 0 }, + { offsetof(xfs_sb_t, sb_agblklog), 0 }, + { offsetof(xfs_sb_t, sb_rextslog), 0 }, + { offsetof(xfs_sb_t, sb_inprogress), 0 }, + { offsetof(xfs_sb_t, sb_imax_pct), 0 }, + { offsetof(xfs_sb_t, sb_icount), 0 }, + { offsetof(xfs_sb_t, sb_ifree), 0 }, + { offsetof(xfs_sb_t, sb_fdblocks), 0 }, + { offsetof(xfs_sb_t, sb_frextents), 0 }, + { offsetof(xfs_sb_t, sb_uquotino), 0 }, + { offsetof(xfs_sb_t, sb_gquotino), 0 }, + { offsetof(xfs_sb_t, sb_qflags), 0 }, + { offsetof(xfs_sb_t, sb_flags), 0 }, + { offsetof(xfs_sb_t, sb_shared_vn), 0 }, + { offsetof(xfs_sb_t, sb_inoalignmt), 0 }, + { offsetof(xfs_sb_t, sb_unit), 0 }, + { offsetof(xfs_sb_t, sb_width), 0 }, + { offsetof(xfs_sb_t, sb_dirblklog), 0 }, + { offsetof(xfs_sb_t, sb_dummy), 1 }, + { sizeof(xfs_sb_t), 0 } +}; + +/* + * Return a pointer to an initialized xfs_mount structure. + */ +xfs_mount_t * +xfs_mount_init(void) +{ + xfs_mount_t *mp; + + mp = kmem_zalloc(sizeof(*mp), KM_SLEEP_IO); + + AIL_LOCKINIT(&mp->m_ail_lock, "xfs_ail"); + spinlock_init(&mp->m_sb_lock, "xfs_sb"); + mutex_init(&mp->m_ilock, MUTEX_DEFAULT, "xfs_ilock"); + initnsema(&mp->m_growlock, 1, "xfs_grow"); + /* + * Initialize the AIL. + */ + xfs_trans_ail_init(mp); + + /* Init freeze sync structures */ + spinlock_init(&mp->m_freeze_lock, "xfs_freeze"); + init_sv(&mp->m_wait_unfreeze, SV_DEFAULT, "xfs_freeze", 0); + atomic_set(&mp->m_active_trans, 0); + + return mp; +} /* xfs_mount_init */ + +/* + * Free up the resources associated with a mount structure. Assume that + * the structure was initially zeroed, so we can tell which fields got + * initialized. + */ +void +xfs_mount_free( + xfs_mount_t *mp, + int remove_bhv) +{ + if (mp->m_ihash) + xfs_ihash_free(mp); + if (mp->m_chash) + xfs_chash_free(mp); + + if (mp->m_perag) { + mrfree(&mp->m_peraglock); + kmem_free(mp->m_perag, + sizeof(xfs_perag_t) * mp->m_sb.sb_agcount); + } + +#if 0 + /* + * XXXdpd - Doesn't work now for shutdown case. + * Should at least free the memory. + */ + ASSERT(mp->m_ail.ail_back == (xfs_log_item_t*)&(mp->m_ail)); + ASSERT(mp->m_ail.ail_forw == (xfs_log_item_t*)&(mp->m_ail)); +#endif + AIL_LOCK_DESTROY(&mp->m_ail_lock); + spinlock_destroy(&mp->m_sb_lock); + mutex_destroy(&mp->m_ilock); + freesema(&mp->m_growlock); + + if (mp->m_fsname != NULL) { + kmem_free(mp->m_fsname, mp->m_fsname_len); + } + if (mp->m_quotainfo != NULL) { + xfs_qm_unmount_quotadestroy(mp); + } + + if (remove_bhv) { + VFS_REMOVEBHV(XFS_MTOVFS(mp), &mp->m_bhv); + } + spinlock_destroy(&mp->m_freeze_lock); + sv_destroy(&mp->m_wait_unfreeze); + kmem_free(mp, sizeof(xfs_mount_t)); +} + + +/* + * Check the validity of the SB found. + */ +STATIC int +xfs_mount_validate_sb( + xfs_mount_t *mp, + xfs_sb_t *sbp) +{ + /* + * If the log device and data device have the + * same device number, the log is internal. + * Consequently, the sb_logstart should be non-zero. If + * we have a zero sb_logstart in this case, we may be trying to mount + * a volume filesystem in a non-volume manner. + */ + if (sbp->sb_magicnum != XFS_SB_MAGIC) { + cmn_err(CE_WARN, "XFS: bad magic number"); + return XFS_ERROR(EWRONGFS); + } + + if (!XFS_SB_GOOD_VERSION(sbp)) { + cmn_err(CE_WARN, "XFS: bad version"); + return XFS_ERROR(EWRONGFS); + } + + if (sbp->sb_logstart == 0 && mp->m_logdev == mp->m_dev) { + cmn_err(CE_WARN, "XFS: filesystem is marked as having an external log; specify logdev on the\nmount command line."); + return XFS_ERROR(EFSCORRUPTED); + } + + if (sbp->sb_logstart != 0 && mp->m_logdev && mp->m_logdev != mp->m_dev) { + cmn_err(CE_WARN, "XFS: filesystem is marked as having an internal log; don't specify logdev on\nthe mount command line."); + return XFS_ERROR(EFSCORRUPTED); + } + + /* + * More sanity checking. These were stolen directly from + * xfs_repair. + */ + if (sbp->sb_blocksize <= 0 || + sbp->sb_agcount <= 0 || + sbp->sb_sectsize <= 0 || + sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || + sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || + sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || + sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || + (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || + (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || + sbp->sb_imax_pct > 100) { + cmn_err(CE_WARN, "XFS: SB sanity check 1 failed"); + return XFS_ERROR(EFSCORRUPTED); + } + + /* + * sanity check ag count, size fields against data size field + */ + if (sbp->sb_dblocks == 0 || + sbp->sb_dblocks > + (xfs_drfsbno_t)sbp->sb_agcount * sbp->sb_agblocks || + sbp->sb_dblocks < (xfs_drfsbno_t)(sbp->sb_agcount - 1) * + sbp->sb_agblocks + XFS_MIN_AG_BLOCKS) { + cmn_err(CE_WARN, "XFS: SB sanity check 2 failed"); + return XFS_ERROR(EFSCORRUPTED); + } + +#if !XFS_BIG_FILESYSTEMS + if (sbp->sb_dblocks > INT_MAX || sbp->sb_rblocks > INT_MAX) { + cmn_err(CE_WARN, +"XFS: File systems greater than 1TB not supported on this system."); + return XFS_ERROR(E2BIG); + } +#endif + + if (sbp->sb_inprogress) { + cmn_err(CE_WARN, "XFS: file system busy"); + return XFS_ERROR(EFSCORRUPTED); + } + + /* + * Until this is fixed only page-sized data blocks work. + */ + if (sbp->sb_blocksize != PAGE_SIZE) { + cmn_err(CE_WARN, + "XFS: Trying to mount file system with blocksize %d bytes", + sbp->sb_blocksize); + cmn_err(CE_WARN, + "XFS: Only page-sized (%d bytes) blocksize currently works.", + PAGE_SIZE); + return XFS_ERROR(EWRONGFS); + } + return (0); +} + +/* + * xfs_xlatesb + * + * data - on disk version of sb + * sb - a superblock + * dir - conversion direction: <0 - convert sb to buf + * >0 - convert buf to sb + * arch - architecture to read/write from/to buf + * fields - which fields to copy (bitmask) + */ +void +xfs_xlatesb(void *data, xfs_sb_t *sb, int dir, xfs_arch_t arch, + __int64_t fields) +{ + xfs_caddr_t buf_ptr; + xfs_caddr_t mem_ptr; + + ASSERT(dir); + ASSERT(fields); + + if (!fields) + return; + + buf_ptr=(xfs_caddr_t)data; + mem_ptr=(xfs_caddr_t)sb; + + while (fields) { + xfs_sb_field_t f; + int first; + int size; + + f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields); + first = xfs_sb_info[f].offset; + size = xfs_sb_info[f + 1].offset - first; + + ASSERT(xfs_sb_info[f].type==0 || xfs_sb_info[f].type==1); + + if (arch == ARCH_NOCONVERT || size==1 || xfs_sb_info[f].type==1) { + if (dir>0) { + bcopy(buf_ptr + first, mem_ptr + first, size); + } else { + bcopy(mem_ptr + first, buf_ptr + first, size); + } + } else { + switch (size) { + case 2: + INT_XLATE(*(__uint16_t*)(buf_ptr+first), + *(__uint16_t*)(mem_ptr+first), dir, arch); + break; + case 4: + INT_XLATE(*(__uint32_t*)(buf_ptr+first), + *(__uint32_t*)(mem_ptr+first), dir, arch); + break; + case 8: + INT_XLATE(*(__uint64_t*)(buf_ptr+first), + *(__uint64_t*)(mem_ptr+first), dir, arch); + break; + default: + ASSERT(0); + } + } + fields &= ~(1LL << f); + } + +} + +/* + * xfs_readsb + * + * Does the initial read of the superblock. This has been split out from + * xfs_mountfs so that the cxfs v1 array mount code can get at the + * unique id for the file system before deciding whether we are going + * to mount things as a cxfs client or server. + */ +int +xfs_readsb(xfs_mount_t *mp, dev_t dev) +{ + xfs_buf_t *bp; + xfs_sb_t *sbp; + int error = 0; + + ASSERT(mp->m_sb_bp == 0); + + /* + * Allocate a (locked) buffer to hold the superblock. + * This will be kept around at all time to optimize + * access to the superblock. + */ + bp = XFS_ngetrbuf(BBTOB(BTOBB(sizeof(xfs_sb_t))),mp); + ASSERT(bp != NULL); + ASSERT(XFS_BUF_ISBUSY(bp) && XFS_BUF_VALUSEMA(bp) <= 0); + + /* + * Initialize and read in the superblock buffer. + */ + XFS_BUF_SET_BRELSE_FUNC(bp,xfs_sb_relse); + XFS_BUF_SET_ADDR(bp, XFS_SB_DADDR); + XFS_BUF_READ(bp); + XFS_BUF_SET_TARGET(bp, mp->m_ddev_targp); + xfsbdstrat(mp, bp); + if ((error = xfs_iowait(bp))) { + cmn_err(CE_WARN, "XFS: SB read failed"); + goto err; + } + + /* + * Initialize the mount structure from the superblock. + * But first do some basic consistency checking. + */ + sbp = XFS_BUF_TO_SBP(bp); + xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), 1, ARCH_CONVERT, XFS_SB_ALL_BITS); + if ((error = xfs_mount_validate_sb(mp, &(mp->m_sb)))) { + cmn_err(CE_WARN, "XFS: SB validate failed"); + goto err; + } + + mp->m_sb_bp = bp; + xfs_buf_relse(bp); + ASSERT(XFS_BUF_VALUSEMA(bp) > 0); + return 0; + + err: + XFS_nfreerbuf(bp); + return error; +} + + +/* + * xfs_mount_common + * + * Mount initialization code establishing various mount + * fields from the superblock associated with the given + * mount structure + */ +void +xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp) +{ + int i; + + mp->m_agfrotor = mp->m_agirotor = 0; + mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG; + mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT; + mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1; + mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog; + mp->m_litino = sbp->sb_inodesize - + ((uint)sizeof(xfs_dinode_core_t) + (uint)sizeof(xfs_agino_t)); + mp->m_blockmask = sbp->sb_blocksize - 1; + mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG; + mp->m_blockwmask = mp->m_blockwsize - 1; + + /* + * Setup for attributes, in case they get created. + * This value is for inodes getting attributes for the first time, + * the per-inode value is for old attribute values. + */ + ASSERT(sbp->sb_inodesize >= 256 && sbp->sb_inodesize <= 2048); + switch (sbp->sb_inodesize) { + case 256: + mp->m_attroffset = XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(2); + break; + case 512: + case 1024: + case 2048: + mp->m_attroffset = XFS_BMDR_SPACE_CALC(12); + break; + default: + ASSERT(0); + } + ASSERT(mp->m_attroffset < XFS_LITINO(mp)); + + for (i = 0; i < 2; i++) { + mp->m_alloc_mxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, + xfs_alloc, i == 0); + mp->m_alloc_mnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, + xfs_alloc, i == 0); + } + for (i = 0; i < 2; i++) { + mp->m_bmap_dmxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, + xfs_bmbt, i == 0); + mp->m_bmap_dmnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, + xfs_bmbt, i == 0); + } + for (i = 0; i < 2; i++) { + mp->m_inobt_mxr[i] = XFS_BTREE_BLOCK_MAXRECS(sbp->sb_blocksize, + xfs_inobt, i == 0); + mp->m_inobt_mnr[i] = XFS_BTREE_BLOCK_MINRECS(sbp->sb_blocksize, + xfs_inobt, i == 0); + } + + mp->m_bsize = XFS_FSB_TO_BB(mp, 1); + mp->m_ialloc_inos = (int)MAX(XFS_INODES_PER_CHUNK, sbp->sb_inopblock); + mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog; +} + +/* + * xfs_mountfs + * + * This function does the following on an initial mount of a file system: + * - reads the superblock from disk and init the mount struct + * - if we're a 32-bit kernel, do a size check on the superblock + * so we don't mount terabyte filesystems + * - init mount struct realtime fields + * - allocate inode hash table for fs + * - init directory manager + * - perform recovery and init the log manager + * - if XFS_MFSI_CLIENT is set then we are doing an import + * or an enterprise mount in client mode. We do not go + * near the log, and do not mess with a bunch of stuff. + * - If XFS_MFSI_SECOND is set then we are doing a secondary + * mount operation for cxfs which may be client mode + * import or enterprise or a server-mode secondary + * mount operation as part of relocation or recovery. + */ +int +xfs_mountfs( + vfs_t *vfsp, + xfs_mount_t *mp, + dev_t dev, + int mfsi_flags) +{ + xfs_buf_t *bp; + xfs_sb_t *sbp = &(mp->m_sb); + int error = 0; + xfs_inode_t *rip; + vnode_t *rvp = 0; + int readio_log; + int writeio_log; + vmap_t vmap; + xfs_daddr_t d; + extern xfs_ioops_t xfs_iocore_xfs; /* from xfs_iocore.c */ + __uint64_t ret64; + uint quotaflags, quotaondisk, rootqcheck, needquotacheck; + boolean_t needquotamount; + __int64_t update_flags; + int noio; + int uuid_mounted = 0; + + noio = dev == 0 && mp->m_sb_bp != NULL; + if (mp->m_sb_bp == NULL) { + if ((error = xfs_readsb(mp, dev))) { + return (error); + } + } + xfs_mount_common(mp, sbp); + + /* + * Check if sb_agblocks is aligned at stripe boundary + * If sb_agblocks is NOT aligned turn off m_dalign since + * allocator alignment is within an ag, therefore ag has + * to be aligned at stripe boundary. + */ + update_flags = 0LL; + if (mp->m_dalign && !(mfsi_flags & XFS_MFSI_SECOND)) { + /* + * If stripe unit and stripe width are not multiples + * of the fs blocksize turn off alignment. + */ + if ((BBTOB(mp->m_dalign) & mp->m_blockmask) || + (BBTOB(mp->m_swidth) & mp->m_blockmask)) { + if (mp->m_flags & XFS_MOUNT_RETERR) { + cmn_err(CE_WARN, "XFS: alignment check 1 failed"); + error = XFS_ERROR(EINVAL); + goto error1; + } + mp->m_dalign = mp->m_swidth = 0; + } else { + /* + * Convert the stripe unit and width to FSBs. + */ + mp->m_dalign = XFS_BB_TO_FSBT(mp, mp->m_dalign); + if (mp->m_dalign && (sbp->sb_agblocks % mp->m_dalign)) { + if (mp->m_flags & XFS_MOUNT_RETERR) { + error = XFS_ERROR(EINVAL); + goto error1; + } + mp->m_dalign = 0; + mp->m_swidth = 0; + } else if (mp->m_dalign) { + mp->m_swidth = XFS_BB_TO_FSBT(mp, mp->m_swidth); + } else { + if (mp->m_flags & XFS_MOUNT_RETERR) { + cmn_err(CE_WARN, "XFS: alignment check 3 failed"); + error = XFS_ERROR(EINVAL); + goto error1; + } + mp->m_swidth = 0; + } + } + + /* + * Update superblock with new values + * and log changes + */ + if (XFS_SB_VERSION_HASDALIGN(sbp)) { + if (sbp->sb_unit != mp->m_dalign) { + sbp->sb_unit = mp->m_dalign; + update_flags |= XFS_SB_UNIT; + } + if (sbp->sb_width != mp->m_swidth) { + sbp->sb_width = mp->m_swidth; + update_flags |= XFS_SB_WIDTH; + } + } + } else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN && + XFS_SB_VERSION_HASDALIGN(&mp->m_sb)) { + mp->m_dalign = sbp->sb_unit; + mp->m_swidth = sbp->sb_width; + } + + xfs_alloc_compute_maxlevels(mp); + xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK); + xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK); + xfs_ialloc_compute_maxlevels(mp); + + vfsp->vfs_bsize = (u_int)XFS_FSB_TO_B(mp, 1); + + if (sbp->sb_imax_pct) { + __uint64_t icount; + + /* Make sure the maximum inode count is a multiple of the + * units we allocate inodes in. + */ + + icount = sbp->sb_dblocks * sbp->sb_imax_pct; + do_div(icount, 100); + do_div(icount, mp->m_ialloc_blks); + mp->m_maxicount = (icount * mp->m_ialloc_blks) << + sbp->sb_inopblog; + } else + mp->m_maxicount = 0; + + /* + * XFS uses the uuid from the superblock as the unique + * identifier for fsid. We can not use the uuid from the volume + * since a single partition filesystem is identical to a single + * partition volume/filesystem. + */ + if ((mfsi_flags & XFS_MFSI_SECOND) == 0 && (mp->m_flags & XFS_MOUNT_NOUUID) == 0) { + if (xfs_uuid_mount(mp)) { + error = XFS_ERROR(EINVAL); + goto error1; + } + uuid_mounted=1; + ret64 = uuid_hash64(&sbp->sb_uuid); + bcopy(&ret64, &vfsp->vfs_fsid, sizeof(ret64)); + } + + /* + * Set the default minimum read and write sizes unless + * already specified in a mount option. + * We use smaller I/O sizes when the file system + * is being used for NFS service (wsync mount option). + */ + if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)) { + if (mp->m_flags & XFS_MOUNT_WSYNC) { + readio_log = XFS_WSYNC_READIO_LOG; + writeio_log = XFS_WSYNC_WRITEIO_LOG; + } else { + readio_log = XFS_READIO_LOG_LARGE; + writeio_log = XFS_WRITEIO_LOG_LARGE; + } + } else { + readio_log = mp->m_readio_log; + writeio_log = mp->m_writeio_log; + } + + /* + * Set the number of readahead buffers to use based on + * physical memory size. + */ + if (physmem <= 4096) /* <= 16MB */ + mp->m_nreadaheads = XFS_RW_NREADAHEAD_16MB; + else if (physmem <= 8192) /* <= 32MB */ + mp->m_nreadaheads = XFS_RW_NREADAHEAD_32MB; + else + mp->m_nreadaheads = XFS_RW_NREADAHEAD_K32; + if (sbp->sb_blocklog > readio_log) { + mp->m_readio_log = sbp->sb_blocklog; + } else { + mp->m_readio_log = readio_log; + } + mp->m_readio_blocks = 1 << (mp->m_readio_log - sbp->sb_blocklog); + if (sbp->sb_blocklog > writeio_log) { + mp->m_writeio_log = sbp->sb_blocklog; + } else { + mp->m_writeio_log = writeio_log; + } + mp->m_writeio_blocks = 1 << (mp->m_writeio_log - sbp->sb_blocklog); + + /* + * Set the inode cluster size based on the physical memory + * size. This may still be overridden by the file system + * block size if it is larger than the chosen cluster size. + */ + if (physmem <= btoc(32 * 1024 * 1024)) { /* <= 32 MB */ + mp->m_inode_cluster_size = XFS_INODE_SMALL_CLUSTER_SIZE; + } else { + mp->m_inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE; + } + /* + * Set whether we're using inode alignment. + */ + if (XFS_SB_VERSION_HASALIGN(&mp->m_sb) && + mp->m_sb.sb_inoalignmt >= + XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) + mp->m_inoalign_mask = mp->m_sb.sb_inoalignmt - 1; + else + mp->m_inoalign_mask = 0; + /* + * If we are using stripe alignment, check whether + * the stripe unit is a multiple of the inode alignment + */ + if (mp->m_dalign && mp->m_inoalign_mask && + !(mp->m_dalign & mp->m_inoalign_mask)) + mp->m_sinoalign = mp->m_dalign; + else + mp->m_sinoalign = 0; + /* + * Check that the data (and log if separate) are an ok size. + */ + d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks); + if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) { + cmn_err(CE_WARN, "XFS: size check 1 failed"); + error = XFS_ERROR(E2BIG); + goto error1; + } + if (!noio) { + error = xfs_read_buf(mp, mp->m_ddev_targp, d - 1, 1, 0, &bp); + if (!error) { + xfs_buf_relse(bp); + } else { + cmn_err(CE_WARN, "XFS: size check 2 failed"); + if (error == ENOSPC) { + error = XFS_ERROR(E2BIG); + } + goto error1; + } + } + + if (!noio && ((mfsi_flags & XFS_MFSI_CLIENT) == 0) && + mp->m_logdev && mp->m_logdev != mp->m_dev) { + d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); + if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) { + cmn_err(CE_WARN, "XFS: size check 3 failed"); + error = XFS_ERROR(E2BIG); + goto error1; + } + error = xfs_read_buf(mp, &mp->m_logdev_targ, d - 1, 1, 0, &bp); + if (!error) { + xfs_buf_relse(bp); + } else { + cmn_err(CE_WARN, "XFS: size check 3 failed"); + if (error == ENOSPC) { + error = XFS_ERROR(E2BIG); + } + goto error1; + } + } + + /* + * Disallow mount attempts with (IRIX) project quota enabled + */ + if (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) && + (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT)) { + cmn_err(CE_WARN, "XFS: IRIX project quota are enabled"); + error = XFS_ERROR(ENOSYS); + goto error1; + } + + /* + * Initialize realtime fields in the mount structure + */ + if ((error = xfs_rtmount_init(mp))) { + cmn_err(CE_WARN, "XFS: RT mount failed"); + goto error1; + } + + /* + * For client case we are done now + */ + if (mfsi_flags & XFS_MFSI_CLIENT) { + return(0); + } + + /* Initialize the I/O function vector with XFS functions */ + mp->m_io_ops = xfs_iocore_xfs; + + /* + * Copies the low order bits of the timestamp and the randomly + * set "sequence" number out of a UUID. + */ + uuid_getnodeuniq(&sbp->sb_uuid, mp->m_fixedfsid); + + /* + * The vfs structure needs to have a file system independent + * way of checking for the invariant file system ID. Since it + * can't look at mount structures it has a pointer to the data + * in the mount structure. + * + * File systems that don't support user level file handles (i.e. + * all of them except for XFS) will leave vfs_altfsid as NULL. + */ + vfsp->vfs_altfsid = (fsid_t *)mp->m_fixedfsid; + mp->m_dmevmask = 0; /* not persistent; set after each mount */ + + /* + * Select the right directory manager. + */ + mp->m_dirops = + XFS_SB_VERSION_HASDIRV2(&mp->m_sb) ? + xfsv2_dirops : + xfsv1_dirops; + + /* + * Initialize directory manager's entries. + */ + XFS_DIR_MOUNT(mp); + + /* + * Initialize the attribute manager's entries. + */ + mp->m_attr_magicpct = (mp->m_sb.sb_blocksize * 37) / 100; + + /* + * Initialize the precomputed transaction reservations values. + */ + xfs_trans_init(mp); + if (noio) { + ASSERT((mfsi_flags & XFS_MFSI_CLIENT) == 0); + return 0; + } + + /* + * Allocate and initialize the inode hash table for this + * file system. + */ + xfs_ihash_init(mp); + xfs_chash_init(mp); + + /* + * Allocate and initialize the per-ag data. + */ + mrinit(&mp->m_peraglock, "xperag"); + mp->m_perag = + kmem_zalloc(sbp->sb_agcount * sizeof(xfs_perag_t), KM_SLEEP_IO); + + /* + * log's mount-time initialization. Perform 1st part recovery if needed + */ + if (sbp->sb_logblocks > 0) { /* check for volume case */ + error = xfs_log_mount(mp, mp->m_logdev, + XFS_FSB_TO_DADDR(mp, sbp->sb_logstart), + XFS_FSB_TO_BB(mp, sbp->sb_logblocks)); + if (error) { + cmn_err(CE_WARN, "XFS: log mount failed"); + goto error2; + } + } else { /* No log has been defined */ + cmn_err(CE_WARN, "XFS: no log defined"); + error = XFS_ERROR(EFSCORRUPTED); + goto error2; + } + + /* + * Get and sanity-check the root inode. + * Save the pointer to it in the mount structure. + */ + error = xfs_iget(mp, NULL, sbp->sb_rootino, XFS_ILOCK_EXCL, &rip, 0); + if (error) { + cmn_err(CE_WARN, "XFS: failed to read root inode"); + goto error2; + } + + ASSERT(rip != NULL); + rvp = XFS_ITOV(rip); + if ((rip->i_d.di_mode & IFMT) != IFDIR) { + cmn_err(CE_WARN, "XFS: corrupted root inode"); + VMAP(rvp, rip, vmap); + prdev("Root inode %Ld is not a directory", + (int)rip->i_dev, rip->i_ino); + xfs_iunlock(rip, XFS_ILOCK_EXCL); + VN_RELE(rvp); + vn_purge(rvp, &vmap); + error = XFS_ERROR(EFSCORRUPTED); + goto error2; + } + VN_FLAGSET(rvp, VROOT); + mp->m_rootip = rip; /* save it */ + + xfs_iunlock(rip, XFS_ILOCK_EXCL); + + /* + * Initialize realtime inode pointers in the mount structure + */ + if ((error = xfs_rtmount_inodes(mp))) { + /* + * Free up the root inode. + */ + cmn_err(CE_WARN, "XFS: failed to read RT inodes"); + VMAP(rvp, rip, vmap); + VN_RELE(rvp); + vn_purge(rvp, &vmap); + goto error2; + } + + /* + * If fs is not mounted readonly, then update the superblock + * unit and width changes. + */ + if (update_flags && !(vfsp->vfs_flag & VFS_RDONLY)) + xfs_mount_log_sbunit(mp, update_flags); + + quotaflags = 0; + needquotamount = B_FALSE; + quotaondisk = XFS_SB_VERSION_HASQUOTA(&mp->m_sb) && + mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT); + /* + * Figure out if we'll need to do a quotacheck. + * The requirements are a little different depending on whether + * this fs is root or not. + */ + rootqcheck = (mp->m_dev == rootdev && quotaondisk && + ((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT && + (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD) == 0) || + (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT && + (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD) == 0))); + needquotacheck = rootqcheck || XFS_QM_NEED_QUOTACHECK(mp); + if (XFS_IS_QUOTA_ON(mp) || quotaondisk) { + /* + * Call mount_quotas at this point only if we won't have to do + * a quotacheck. + */ + if (quotaondisk && !needquotacheck) { + /* + * If the xfs quota code isn't installed, + * we have to reset the quotachk'd bit. + * If an error occured, qm_mount_quotas code + * has already disabled quotas. So, just finish + * mounting, and get on with the boring life + * without disk quotas. + */ + if (xfs_qm_mount_quotas(mp)) + xfs_mount_reset_sbqflags(mp); + } else { + /* + * Clear the quota flags, but remember them. This + * is so that the quota code doesn't get invoked + * before we're ready. This can happen when an + * inode goes inactive and wants to free blocks, + * or via xfs_log_mount_finish. + */ + quotaflags = mp->m_qflags; + mp->m_qflags = 0; + needquotamount = B_TRUE; + } + } + + /* + * Finish recovering the file system. This part needed to be + * delayed until after the root and real-time bitmap inodes + * were consistently read in. + */ + error = xfs_log_mount_finish(mp, mfsi_flags); + if (error) { + cmn_err(CE_WARN, "XFS: log mount finish failed"); + goto error2; + } + + if (needquotamount) { + ASSERT(mp->m_qflags == 0); + mp->m_qflags = quotaflags; + rootqcheck = ((XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) && + mp->m_dev == rootdev && needquotacheck); + if (rootqcheck && (error = xfs_quotacheck_read_only(mp))) + goto error2; + if (xfs_qm_mount_quotas(mp)) + xfs_mount_reset_sbqflags(mp); + if (rootqcheck) + XFS_MTOVFS(mp)->vfs_flag |= VFS_RDONLY; + } + +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + if (! (XFS_IS_QUOTA_ON(mp))) + xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas not turned on"); + else + xfs_fs_cmn_err(CE_NOTE, mp, "Disk quotas turned on"); +#endif + +#ifdef QUOTADEBUG + if (XFS_IS_QUOTA_ON(mp) && xfs_qm_internalqcheck(mp)) + cmn_err(CE_WARN, "XFS: mount internalqcheck failed"); +#endif + + return (0); + + error2: + xfs_ihash_free(mp); + xfs_chash_free(mp); + mrfree(&mp->m_peraglock); + kmem_free(mp->m_perag, sbp->sb_agcount * sizeof(xfs_perag_t)); + mp->m_perag = NULL; + /* FALLTHROUGH */ + error1: + if (uuid_mounted) + xfs_uuid_unmount(mp); + xfs_freesb(mp); + return error; +} + +/* + * xfs_unmountfs + * + * This flushes out the inodes,dquots and the superblock, unmounts the + * log and makes sure that incore structures are freed. + */ +int +xfs_unmountfs(xfs_mount_t *mp, int vfs_flags, struct cred *cr) +{ + int ndquots; +#if defined(DEBUG) || defined(INDUCE_IO_ERROR) + int64_t fsid; +#endif + + xfs_iflush_all(mp, XFS_FLUSH_ALL); + + /* + * Purge the dquot cache. + * None of the dquots should really be busy at this point. + */ + if (mp->m_quotainfo) { + while ((ndquots = xfs_qm_dqpurge_all(mp, + XFS_QMOPT_UQUOTA| + XFS_QMOPT_GQUOTA| + XFS_QMOPT_UMOUNTING))) { + delay(ndquots * 10); + } + } + + /* + * Flush out the log synchronously so that we know for sure + * that nothing is pinned. This is important because bflush() + * will skip pinned buffers. + */ + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); + + xfs_binval(mp->m_ddev_targ); + if (mp->m_rtdev != NODEV) { + xfs_binval(mp->m_rtdev_targ); + } + + xfs_unmountfs_writesb(mp); + + xfs_log_unmount(mp); /* Done! No more fs ops. */ + + xfs_freesb(mp); + + + /* + * All inodes from this mount point should be freed. + */ + ASSERT(mp->m_inodes == NULL); + + /* + * We may have bufs that are in the process of getting written still. + * We must wait for the I/O completion of those. The sync flag here + * does a two pass iteration thru the bufcache. + */ + if (XFS_FORCED_SHUTDOWN(mp)) { + (void)xfs_incore_relse(&mp->m_ddev_targ, 0, 1); /* synchronous*/ + } + xfs_unmountfs_close(mp, vfs_flags, cr); + if ((mp->m_flags & XFS_MOUNT_NOUUID) == 0) + xfs_uuid_unmount(mp); + +#if defined(DEBUG) || defined(INDUCE_IO_ERROR) + /* + * clear all error tags on this filesystem + */ + bcopy(&(XFS_MTOVFS(mp)->vfs_fsid), &fsid, sizeof(int64_t)); + (void) xfs_errortag_clearall_umount(fsid, mp->m_fsname, 0); +#endif + +#ifdef CELL_CAPABLE + cxfs_unmount(mp); +#endif + xfs_mount_free(mp, 1); + return 0; +} + +void +xfs_unmountfs_close(xfs_mount_t *mp, int vfs_flags, struct cred *cr) +{ + if (mp->m_ddev_targ.pb_targ) { + linvfs_release_target(mp->m_ddev_targ.pb_targ); + } + if (mp->m_rtdev_targ.pb_targ) { + linvfs_release_target(mp->m_rtdev_targ.pb_targ); + } + if (mp->m_logdev_targ.pb_targ && + mp->m_logdev_targ.pb_targ != mp->m_ddev_targ.pb_targ) { + linvfs_release_target(mp->m_logdev_targ.pb_targ); + } +} + +int +xfs_unmountfs_writesb(xfs_mount_t *mp) +{ + xfs_buf_t *sbp; + xfs_sb_t *sb; + int error = 0; + + /* + * skip superblock write if fs is read-only, or + * if we are doing a forced umount. + */ + sbp = xfs_getsb(mp, 0); + if (!(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY || + XFS_FORCED_SHUTDOWN(mp))) { + /* + * mark shared-readonly if desired + */ + sb = XFS_BUF_TO_SBP(sbp); + if (mp->m_mk_sharedro) { + if (!(sb->sb_flags & XFS_SBF_READONLY)) + sb->sb_flags |= XFS_SBF_READONLY; + if (!XFS_SB_VERSION_HASSHARED(sb)) + XFS_SB_VERSION_ADDSHARED(sb); + xfs_fs_cmn_err(CE_NOTE, mp, + "Unmounting, marking shared read-only"); + } + XFS_BUF_UNDONE(sbp); + XFS_BUF_UNREAD(sbp); + XFS_BUF_UNDELAYWRITE(sbp); + XFS_BUF_WRITE(sbp); + XFS_BUF_UNASYNC(sbp); + ASSERT(XFS_BUF_TARGET(sbp) == mp->m_dev); + xfsbdstrat(mp, sbp); + /* Nevermind errors we might get here. */ + error = xfs_iowait(sbp); + if (error && mp->m_mk_sharedro) + xfs_fs_cmn_err(CE_ALERT, mp, "Superblock write error detected while unmounting. Filesystem may not be marked shared readonly"); + } + xfs_buf_relse(sbp); + return (error); +} + +/* + * xfs_mod_sb() can be used to copy arbitrary changes to the + * in-core superblock into the superblock buffer to be logged. + * It does not provide the higher level of locking that is + * needed to protect the in-core superblock from concurrent + * access. + */ +void +xfs_mod_sb(xfs_trans_t *tp, __int64_t fields) +{ + xfs_buf_t *bp; + int first; + int last; + xfs_mount_t *mp; + xfs_sb_t *sbp; + xfs_sb_field_t f; + + ASSERT(fields); + if (!fields) + return; + mp = tp->t_mountp; + bp = xfs_trans_getsb(tp, mp, 0); + sbp = XFS_BUF_TO_SBP(bp); + first = sizeof(xfs_sb_t); + last = 0; + + /* translate/copy */ + + xfs_xlatesb(XFS_BUF_PTR(bp), &(mp->m_sb), -1, ARCH_CONVERT, fields); + + /* find modified range */ + + f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields); + ASSERT((1LL << f) & XFS_SB_MOD_BITS); + first = xfs_sb_info[f].offset; + + f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields); + ASSERT((1LL << f) & XFS_SB_MOD_BITS); + last = xfs_sb_info[f + 1].offset - 1; + + xfs_trans_log_buf(tp, bp, first, last); +} + +/* + * xfs_mod_incore_sb_unlocked() is a utility routine common used to apply + * a delta to a specified field in the in-core superblock. Simply + * switch on the field indicated and apply the delta to that field. + * Fields are not allowed to dip below zero, so if the delta would + * do this do not apply it and return EINVAL. + * + * The SB_LOCK must be held when this routine is called. + */ +STATIC int +xfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field, + int delta, int rsvd) +{ + int scounter; /* short counter for 32 bit fields */ + long long lcounter; /* long counter for 64 bit fields */ + long long res_used, rem; + + /* + * With the in-core superblock spin lock held, switch + * on the indicated field. Apply the delta to the + * proper field. If the fields value would dip below + * 0, then do not apply the delta and return EINVAL. + */ + switch (field) { + case XFS_SBS_ICOUNT: + lcounter = (long long)mp->m_sb.sb_icount; + lcounter += delta; + if (lcounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_icount = lcounter; + return (0); + case XFS_SBS_IFREE: + lcounter = (long long)mp->m_sb.sb_ifree; + lcounter += delta; + if (lcounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_ifree = lcounter; + return (0); + case XFS_SBS_FDBLOCKS: + + lcounter = (long long)mp->m_sb.sb_fdblocks; + res_used = (long long)(mp->m_resblks - mp->m_resblks_avail); + + if (delta > 0) { /* Putting blocks back */ + if (res_used > delta) { + mp->m_resblks_avail += delta; + } else { + rem = delta - res_used; + mp->m_resblks_avail = mp->m_resblks; + lcounter += rem; + } + } else { /* Taking blocks away */ + + lcounter += delta; + + /* + * If were out of blocks, use any available reserved blocks if + * were allowed to. + */ + + if (lcounter < 0) { + if (rsvd) { + lcounter = (long long)mp->m_resblks_avail + delta; + if (lcounter < 0) { + return (XFS_ERROR(ENOSPC)); + } + mp->m_resblks_avail = lcounter; + return (0); + } else { /* not reserved */ + return (XFS_ERROR(ENOSPC)); + } + } + } + + mp->m_sb.sb_fdblocks = lcounter; + return (0); + case XFS_SBS_FREXTENTS: + lcounter = (long long)mp->m_sb.sb_frextents; + lcounter += delta; + if (lcounter < 0) { + return (XFS_ERROR(ENOSPC)); + } + mp->m_sb.sb_frextents = lcounter; + return (0); + case XFS_SBS_DBLOCKS: + lcounter = (long long)mp->m_sb.sb_dblocks; + lcounter += delta; + if (lcounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_dblocks = lcounter; + return (0); + case XFS_SBS_AGCOUNT: + scounter = mp->m_sb.sb_agcount; + scounter += delta; + if (scounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_agcount = scounter; + return (0); + case XFS_SBS_IMAX_PCT: + scounter = mp->m_sb.sb_imax_pct; + scounter += delta; + if (scounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_imax_pct = scounter; + return (0); + case XFS_SBS_REXTSIZE: + scounter = mp->m_sb.sb_rextsize; + scounter += delta; + if (scounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_rextsize = scounter; + return (0); + case XFS_SBS_RBMBLOCKS: + scounter = mp->m_sb.sb_rbmblocks; + scounter += delta; + if (scounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_rbmblocks = scounter; + return (0); + case XFS_SBS_RBLOCKS: + lcounter = (long long)mp->m_sb.sb_rblocks; + lcounter += delta; + if (lcounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_rblocks = lcounter; + return (0); + case XFS_SBS_REXTENTS: + lcounter = (long long)mp->m_sb.sb_rextents; + lcounter += delta; + if (lcounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_rextents = lcounter; + return (0); + case XFS_SBS_REXTSLOG: + scounter = mp->m_sb.sb_rextslog; + scounter += delta; + if (scounter < 0) { + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } + mp->m_sb.sb_rextslog = scounter; + return (0); + default: + ASSERT(0); + return (XFS_ERROR(EINVAL)); + } +} + +/* + * xfs_mod_incore_sb() is used to change a field in the in-core + * superblock structure by the specified delta. This modification + * is protected by the SB_LOCK. Just use the xfs_mod_incore_sb_unlocked() + * routine to do the work. + */ +int +xfs_mod_incore_sb(xfs_mount_t *mp, xfs_sb_field_t field, int delta, int rsvd) +{ + int s; + int status; + + s = XFS_SB_LOCK(mp); + status = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd); + XFS_SB_UNLOCK(mp, s); + return (status); +} + +/* + * xfs_mod_incore_sb_batch() is used to change more than one field + * in the in-core superblock structure at a time. This modification + * is protected by a lock internal to this module. The fields and + * changes to those fields are specified in the array of xfs_mod_sb + * structures passed in. + * + * Either all of the specified deltas will be applied or none of + * them will. If any modified field dips below 0, then all modifications + * will be backed out and EINVAL will be returned. + */ +int +xfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd) +{ + int s; + int status=0; + xfs_mod_sb_t *msbp; + + /* + * Loop through the array of mod structures and apply each + * individually. If any fail, then back out all those + * which have already been applied. Do all of this within + * the scope of the SB_LOCK so that all of the changes will + * be atomic. + */ + s = XFS_SB_LOCK(mp); + msbp = &msb[0]; + for (msbp = &msbp[0]; msbp < (msb + nmsb); msbp++) { + /* + * Apply the delta at index n. If it fails, break + * from the loop so we'll fall into the undo loop + * below. + */ + status = xfs_mod_incore_sb_unlocked(mp, msbp->msb_field, + msbp->msb_delta, rsvd); + if (status != 0) { + break; + } + } + + /* + * If we didn't complete the loop above, then back out + * any changes made to the superblock. If you add code + * between the loop above and here, make sure that you + * preserve the value of status. Loop back until + * we step below the beginning of the array. Make sure + * we don't touch anything back there. + */ + if (status != 0) { + msbp--; + while (msbp >= msb) { + status = xfs_mod_incore_sb_unlocked(mp, + msbp->msb_field, -(msbp->msb_delta), rsvd); + ASSERT(status == 0); + msbp--; + } + } + XFS_SB_UNLOCK(mp, s); + return (status); +} + +/* + * xfs_getsb() is called to obtain the buffer for the superblock. + * The buffer is returned locked and read in from disk. + * The buffer should be released with a call to xfs_brelse(). + * + * If the flags parameter is BUF_TRYLOCK, then we'll only return + * the superblock buffer if it can be locked without sleeping. + * If it can't then we'll return NULL. + */ +xfs_buf_t * +xfs_getsb(xfs_mount_t *mp, + int flags) +{ + xfs_buf_t *bp; + + ASSERT(mp->m_sb_bp != NULL); + bp = mp->m_sb_bp; + if (flags & XFS_BUF_TRYLOCK) { + if (!XFS_BUF_CPSEMA(bp)) { + return NULL; + } + } else { + XFS_BUF_PSEMA(bp, PRIBIO); + } + ASSERT(XFS_BUF_ISDONE(bp)); + return (bp); +} + +/* + * Used to free the superblock along various error paths. + */ +void +xfs_freesb( + xfs_mount_t *mp) +{ + xfs_buf_t *bp; + + /* + * Use xfs_getsb() so that the buffer will be locked + * when we call nfreerbuf(). + */ + bp = xfs_getsb(mp, 0); + XFS_nfreerbuf(bp); + mp->m_sb_bp = NULL; +} + +/* + * This is the brelse function for the private superblock buffer. + * All it needs to do is unlock the buffer and clear any spurious + * flags. + */ +STATIC void +xfs_sb_relse(xfs_buf_t *bp) +{ + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); + XFS_BUF_UNASYNC(bp); + XFS_BUF_UNREAD(bp); + XFS_BUF_VSEMA(bp); +} + +/* + * See if the uuid is unique among mounted xfs filesystems. + * Mount fails if UUID is nil or a FS with the same UUID is already + * mounted + */ +STATIC int +xfs_uuid_mount(xfs_mount_t *mp) +{ + int hole; + int i; + + if (uuid_is_nil(&mp->m_sb.sb_uuid)) { + cmn_err(CE_WARN, "XFS: Filesystem has nil UUID - can't mount"); + return -1; + } + + mutex_lock(&xfs_uuidtabmon, PVFS); + for (i = 0, hole = -1; i < xfs_uuidtab_size; i++) { + if (uuid_is_nil(&xfs_uuidtab[i])) { + hole = i; + continue; + } + if (uuid_equal(&mp->m_sb.sb_uuid, &xfs_uuidtab[i])) { + cmn_err(CE_WARN, "XFS: Filesystem has duplicate UUID - can't mount"); + mutex_unlock(&xfs_uuidtabmon); + return -1; + } + } + if (hole < 0) { + xfs_uuidtab = kmem_realloc(xfs_uuidtab, + (xfs_uuidtab_size + 1) * sizeof(*xfs_uuidtab), + xfs_uuidtab_size * sizeof(*xfs_uuidtab), + KM_SLEEP_IO); + hole = xfs_uuidtab_size++; + } + xfs_uuidtab[hole] = mp->m_sb.sb_uuid; + mutex_unlock(&xfs_uuidtabmon); + + return 0; +} + +/* + * Remove filesystem from the uuid table. + */ +STATIC void +xfs_uuid_unmount(xfs_mount_t *mp) +{ + int i; + + mutex_lock(&xfs_uuidtabmon, PVFS); + for (i = 0; i < xfs_uuidtab_size; i++) { + if (uuid_is_nil(&xfs_uuidtab[i])) + continue; + if (!uuid_equal(&mp->m_sb.sb_uuid, &xfs_uuidtab[i])) + continue; + uuid_create_nil(&xfs_uuidtab[i]); + break; + } + ASSERT(i < xfs_uuidtab_size); + mutex_unlock(&xfs_uuidtabmon); +} + +/* + * When xfsquotas isn't installed and the superblock had quotas, we need to + * clear the quotaflags from superblock. + */ +STATIC void +xfs_mount_reset_sbqflags( + xfs_mount_t *mp) +{ + xfs_trans_t *tp; + int s; + + mp->m_qflags = 0; + /* + * It is OK to look at sb_qflags here in mount path, + * without SB_LOCK. + */ + if (mp->m_sb.sb_qflags == 0) + return; + s = XFS_SB_LOCK(mp); + mp->m_sb.sb_qflags = 0; + XFS_SB_UNLOCK(mp, s); + + /* + * if the fs is readonly, let the incore superblock run + * with quotas off but don't flush the update out to disk + */ + if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) + return; +#ifdef QUOTADEBUG + xfs_fs_cmn_err(CE_NOTE, mp, "Writing superblock quota changes"); +#endif + tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE); + if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, + XFS_DEFAULT_LOG_COUNT)) { + xfs_trans_cancel(tp, 0); + return; + } + xfs_mod_sb(tp, XFS_SB_QFLAGS); + (void)xfs_trans_commit(tp, 0, NULL); +} + +/* + * Used to log changes to the superblock unit and width fields which could + * be altered by the mount options. Only the first superblock is updated. + */ +STATIC void +xfs_mount_log_sbunit( + xfs_mount_t *mp, + __int64_t fields) +{ + xfs_trans_t *tp; + + ASSERT(fields & (XFS_SB_UNIT|XFS_SB_WIDTH|XFS_SB_UUID)); + + tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT); + if (xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0, + XFS_DEFAULT_LOG_COUNT)) { + xfs_trans_cancel(tp, 0); + return; + } + xfs_mod_sb(tp, fields); + (void)xfs_trans_commit(tp, 0, NULL); +} + +/* Functions used to lock access out of the filesystem for snapshotting + * via special purpose hardware or via a logical volume manager + */ + +void +xfs_start_freeze( + xfs_mount_t *mp, + int level) +{ + int s = mutex_spinlock(&mp->m_freeze_lock); + + mp->m_frozen = level; + mutex_spinunlock(&mp->m_freeze_lock, s); + + if (level == XFS_FREEZE_TRANS) { + while (atomic_read(&mp->m_active_trans) > 0) + delay(100); + } +} + +void +xfs_finish_freeze( + xfs_mount_t *mp) +{ + int s = mutex_spinlock(&mp->m_freeze_lock); + + if (mp->m_frozen) { + mp->m_frozen = 0; + sv_broadcast(&mp->m_wait_unfreeze); + } + + mutex_spinunlock(&mp->m_freeze_lock, s); +} + +void +xfs_check_frozen( + xfs_mount_t *mp, + int level) +{ + int s; + + if (!mp->m_frozen) { + if (level == XFS_FREEZE_TRANS) + atomic_inc(&mp->m_active_trans); + return; + } + + s = mutex_spinlock(&mp->m_freeze_lock); + + if (mp->m_frozen < level) { + mutex_spinunlock(&mp->m_freeze_lock, s); + if (level == XFS_FREEZE_TRANS) + atomic_inc(&mp->m_active_trans); + return; + } + sv_wait(&mp->m_wait_unfreeze, PINOD, &mp->m_freeze_lock, s); + if (level == XFS_FREEZE_TRANS) + atomic_inc(&mp->m_active_trans); +} + diff -rNu linux-2.4.7/linux/fs/xfs/xfs_mount.h linux-2.4-xfs/linux/fs/xfs/xfs_mount.h --- linux-2.4.7/linux/fs/xfs/xfs_mount.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_mount.h Fri Jun 29 17:29:47 2001 @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_MOUNT_H__ +#define __XFS_MOUNT_H__ + + +typedef struct xfs_trans_reservations { + uint tr_write; /* extent alloc trans */ + uint tr_itruncate; /* truncate trans */ + uint tr_rename; /* rename trans */ + uint tr_link; /* link trans */ + uint tr_remove; /* unlink trans */ + uint tr_symlink; /* symlink trans */ + uint tr_create; /* create trans */ + uint tr_mkdir; /* mkdir trans */ + uint tr_ifree; /* inode free trans */ + uint tr_ichange; /* inode update trans */ + uint tr_growdata; /* fs data section grow trans */ + uint tr_swrite; /* sync write inode trans */ + uint tr_addafork; /* cvt inode to attributed trans */ + uint tr_writeid; /* write setuid/setgid file */ + uint tr_attrinval; /* attr fork buffer invalidation */ + uint tr_attrset; /* set/create an attribute */ + uint tr_attrrm; /* remove an attribute */ + uint tr_clearagi; /* clear bad agi unlinked ino bucket */ + uint tr_growrtalloc; /* grow realtime allocations */ + uint tr_growrtzero; /* grow realtime zeroing */ + uint tr_growrtfree; /* grow realtime freeing */ +} xfs_trans_reservations_t; + + +#ifndef __KERNEL__ +/* + * Moved here from xfs_ag.h to avoid reordering header files + */ +#define XFS_DADDR_TO_AGNO(mp,d) \ + ((xfs_agnumber_t)(XFS_BB_TO_FSBT(mp, d) / (mp)->m_sb.sb_agblocks)) +#define XFS_DADDR_TO_AGBNO(mp,d) \ + ((xfs_agblock_t)(XFS_BB_TO_FSBT(mp, d) % (mp)->m_sb.sb_agblocks)) +#else +struct cred; +struct mounta; +struct vfs; +struct vnode; +struct xfs_args; +struct xfs_ihash; +struct xfs_chash; +struct xfs_inode; +struct xfs_perag; +struct xfs_quotainfo; +struct xfs_iocore; +struct xfs_dio; +struct xfs_bmbt_irec; +struct xfs_bmap_free; + +#if defined(INTERRUPT_LATENCY_TESTING) +#define SPLDECL(s) +#define AIL_LOCK_T mutex_t +#define AIL_LOCKINIT(x,y) mutex_init(x,MUTEX_DEFAULT, y) +#define AIL_LOCK_DESTROY(x) mutex_destroy(x) +#define AIL_LOCK(mp,s) mutex_lock(&(mp)->m_ail_lock, PZERO) +#define AIL_UNLOCK(mp,s) mutex_unlock(&(mp)->m_ail_lock) +#else /* !INTERRUPT_LATENCY_TESTING */ +#define SPLDECL(s) int s +#define AIL_LOCK_T lock_t +#define AIL_LOCKINIT(x,y) spinlock_init(x,y) +#define AIL_LOCK_DESTROY(x) spinlock_destroy(x) +#define AIL_LOCK(mp,s) s=mutex_spinlock(&(mp)->m_ail_lock) +#define AIL_UNLOCK(mp,s) mutex_spinunlock(&(mp)->m_ail_lock, s) +#endif /* !INTERRUPT_LATENCY_TESTING */ + + +/* Prototypes and functions for I/O core modularization, a vector + * of functions is used to indirect from xfs/cxfs independent code + * to the xfs/cxfs dependent code. + * The vector is placed in the mount structure so that we can + * minimize the number of memory indirections involved. + */ + +typedef int (*xfs_dio_write_t)(struct xfs_dio *); +typedef int (*xfs_dio_read_t)(struct xfs_dio *); +typedef int (*xfs_strat_write_t)(struct xfs_iocore *, struct xfs_buf *); +typedef int (*xfs_bmapi_t)(struct xfs_trans *, void *, + xfs_fileoff_t, xfs_filblks_t, int, + xfs_fsblock_t *, xfs_extlen_t, + struct xfs_bmbt_irec *, int *, + struct xfs_bmap_free *); +typedef int (*xfs_bmap_eof_t)(void *, xfs_fileoff_t, int, int *); +typedef int (*xfs_rsync_t)(void *, int, xfs_off_t, xfs_off_t); +typedef uint (*xfs_lck_map_shared_t)(void *); +typedef void (*xfs_lock_t)(void *, uint); +typedef void (*xfs_lock_demote_t)(void *, uint); +typedef int (*xfs_lock_nowait_t)(void *, uint); +typedef void (*xfs_unlk_t)(void *, unsigned int); +typedef void (*xfs_chgtime_t)(void *, int); +typedef xfs_fsize_t (*xfs_size_t)(void *); +typedef xfs_fsize_t (*xfs_setsize_t)(void *, xfs_off_t); +typedef xfs_fsize_t (*xfs_lastbyte_t)(void *); + +#ifdef CELL_CAPABLE +typedef int (*xfs_checklock_t)(bhv_desc_t *, struct vnode *, + int, off_t, off_t, int, struct cred *, + struct flid *, vrwlock_t, int); +#endif + +typedef struct xfs_ioops { + xfs_dio_write_t xfs_dio_write_func; + xfs_dio_read_t xfs_dio_read_func; + xfs_strat_write_t xfs_strat_write_func; + xfs_bmapi_t xfs_bmapi_func; + xfs_bmap_eof_t xfs_bmap_eof_func; + xfs_rsync_t xfs_rsync_func; + xfs_lck_map_shared_t xfs_lck_map_shared; + xfs_lock_t xfs_ilock; + xfs_lock_demote_t xfs_ilock_demote; + xfs_lock_nowait_t xfs_ilock_nowait; + xfs_unlk_t xfs_unlock; + xfs_chgtime_t xfs_chgtime; + xfs_size_t xfs_size_func; + xfs_setsize_t xfs_setsize_func; + xfs_lastbyte_t xfs_lastbyte; +#ifdef CELL_CAPABLE + xfs_checklock_t xfs_checklock; +#endif +} xfs_ioops_t; + + +#define XFS_DIO_WRITE(mp, diop) \ + (*(mp)->m_io_ops.xfs_dio_write_func)(diop) + +#define XFS_DIO_READ(mp, diop) \ + (*(mp)->m_io_ops.xfs_dio_read_func)(diop) + +#define XFS_STRAT_WRITE(mp, io, bp) \ + (*(mp)->m_io_ops.xfs_strat_write_func)(io, bp) + +#define XFS_BMAPI(mp, trans,io,bno,len,f,first,tot,mval,nmap,flist) \ + (*(mp)->m_io_ops.xfs_bmapi_func) \ + (trans,(io)->io_obj,bno,len,f,first,tot,mval,nmap,flist) + +#define XFS_BMAP_EOF(mp, io, endoff, whichfork, eof) \ + (*(mp)->m_io_ops.xfs_bmap_eof_func) \ + ((io)->io_obj, endoff, whichfork, eof) + +#define XFS_RSYNC(mp, io, ioflag, start, end) \ + (*(mp)->m_io_ops.xfs_rsync_func)((io)->io_obj, ioflag, start, end) + +#define XFS_LCK_MAP_SHARED(mp, io) \ + (*(mp)->m_io_ops.xfs_lck_map_shared)((io)->io_obj) + +#define XFS_UNLK_MAP_SHARED(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_unlock)((io)->io_obj, mode) + +#define XFS_ILOCK(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_ilock)((io)->io_obj, mode) + +#define XFS_ILOCK_NOWAIT(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_ilock_nowait)((io)->io_obj, mode) + +#define XFS_IUNLOCK(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_unlock)((io)->io_obj, mode) + +#define XFS_ILOCK_DEMOTE(mp, io, mode) \ + (*(mp)->m_io_ops.xfs_ilock_demote)((io)->io_obj, mode) + +#define XFS_CHGTIME(mp, io, flags) \ + (*(mp)->m_io_ops.xfs_chgtime)((io)->io_obj, flags) + +#define XFS_SIZE(mp, io) \ + (*(mp)->m_io_ops.xfs_size_func)((io)->io_obj) + +#define XFS_SETSIZE(mp, io, newsize) \ + (*(mp)->m_io_ops.xfs_setsize_func)((io)->io_obj, newsize) + +#define XFS_LASTBYTE(mp, io) \ + (*(mp)->m_io_ops.xfs_lastbyte)((io)->io_obj) + + +typedef struct xfs_mount { + bhv_desc_t m_bhv; /* vfs xfs behavior */ + xfs_tid_t m_tid; /* next unused tid for fs */ + AIL_LOCK_T m_ail_lock; /* fs AIL mutex */ + xfs_ail_entry_t m_ail; /* fs active log item list */ + uint m_ail_gen; /* fs AIL generation count */ + xfs_sb_t m_sb; /* copy of fs superblock */ + lock_t m_sb_lock; /* sb counter mutex */ + struct xfs_buf *m_sb_bp; /* buffer for superblock */ + char *m_fsname; /* filesystem name */ + int m_fsname_len; /* strlen of fs name */ + int m_bsize; /* fs logical block size */ + xfs_agnumber_t m_agfrotor; /* last ag where space found */ + xfs_agnumber_t m_agirotor; /* last ag dir inode alloced */ + int m_ihsize; /* size of next field */ + struct xfs_ihash *m_ihash; /* fs private inode hash table*/ + struct xfs_inode *m_inodes; /* active inode list */ + mutex_t m_ilock; /* inode list mutex */ + uint m_ireclaims; /* count of calls to reclaim*/ + uint m_readio_log; /* min read size log bytes */ + uint m_readio_blocks; /* min read size blocks */ + uint m_writeio_log; /* min write size log bytes */ + uint m_writeio_blocks; /* min write size blocks */ + void *m_log; /* log specific stuff */ + int m_logbufs; /* number of log buffers */ + int m_logbsize; /* size of each log buffer */ + uint m_rsumlevels; /* rt summary levels */ + uint m_rsumsize; /* size of rt summary, bytes */ + struct xfs_inode *m_rbmip; /* pointer to bitmap inode */ + struct xfs_inode *m_rsumip; /* pointer to summary inode */ + struct xfs_inode *m_rootip; /* pointer to root directory */ + struct xfs_quotainfo *m_quotainfo; /* disk quota information */ + buftarg_t m_ddev_targ; /* ptr to data device */ + buftarg_t m_logdev_targ; /* ptr to log device */ + buftarg_t m_rtdev_targ; /* ptr to rt device */ + buftarg_t *m_ddev_targp; /* saves taking the address */ +#define m_dev m_ddev_targ.dev +#define m_logdev m_logdev_targ.dev +#define m_rtdev m_rtdev_targ.dev + __uint8_t m_dircook_elog; /* log d-cookie entry bits */ + __uint8_t m_blkbit_log; /* blocklog + NBBY */ + __uint8_t m_blkbb_log; /* blocklog - BBSHIFT */ + __uint8_t m_agno_log; /* log #ag's */ + __uint8_t m_agino_log; /* #bits for agino in inum */ + __uint8_t m_nreadaheads; /* #readahead buffers */ + __uint16_t m_inode_cluster_size;/* min inode buf size */ + uint m_blockmask; /* sb_blocksize-1 */ + uint m_blockwsize; /* sb_blocksize in words */ + uint m_blockwmask; /* blockwsize-1 */ + uint m_alloc_mxr[2]; /* XFS_ALLOC_BLOCK_MAXRECS */ + uint m_alloc_mnr[2]; /* XFS_ALLOC_BLOCK_MINRECS */ + uint m_bmap_dmxr[2]; /* XFS_BMAP_BLOCK_DMAXRECS */ + uint m_bmap_dmnr[2]; /* XFS_BMAP_BLOCK_DMINRECS */ + uint m_inobt_mxr[2]; /* XFS_INOBT_BLOCK_MAXRECS */ + uint m_inobt_mnr[2]; /* XFS_INOBT_BLOCK_MINRECS */ + uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */ + uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */ + uint m_in_maxlevels; /* XFS_IN_MAXLEVELS */ + struct xfs_perag *m_perag; /* per-ag accounting info */ + mrlock_t m_peraglock; /* lock for m_perag (pointer) */ + sema_t m_growlock; /* growfs mutex */ + int m_fixedfsid[2]; /* unchanged for life of FS */ + uint m_dmevmask; /* DMI events for this FS */ + uint m_flags; /* global mount flags */ + uint m_attroffset; /* inode attribute offset */ + int m_da_node_ents; /* how many entries in danode */ + int m_ialloc_inos; /* inodes in inode allocation */ + int m_ialloc_blks; /* blocks in inode allocation */ + int m_litino; /* size of inode union area */ + int m_inoalign_mask;/* mask sb_inoalignmt if used */ + uint m_qflags; /* quota status flags */ + xfs_trans_reservations_t m_reservations;/* precomputed res values */ + __uint64_t m_maxicount; /* maximum inode count */ + __uint64_t m_resblks; /* total reserved blocks */ + __uint64_t m_resblks_avail;/* available reserved blocks */ +#if XFS_BIG_FILESYSTEMS + xfs_ino_t m_inoadd; /* add value for ino64_offset */ +#endif + int m_dalign; /* stripe unit */ + int m_swidth; /* stripe width */ + int m_sinoalign; /* stripe unit inode alignmnt */ + int m_attr_magicpct;/* 37% of the blocksize */ + int m_dir_magicpct; /* 37% of the dir blocksize */ + __uint8_t m_mk_sharedro; /* mark shared ro on unmount */ + __uint8_t m_inode_quiesce;/* call quiesce on new inodes. + field governed by m_ilock */ + __uint8_t m_dirversion; /* 1 or 2 */ + xfs_dirops_t m_dirops; /* table of dir funcs */ + int m_dirblksize; /* directory block sz--bytes */ + int m_dirblkfsbs; /* directory block sz--fsbs */ + xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */ + xfs_dablk_t m_dirleafblk; /* blockno of dir non-data v2 */ + xfs_dablk_t m_dirfreeblk; /* blockno of dirfreeindex v2 */ + int m_chsize; /* size of next field */ + struct xfs_chash *m_chash; /* fs private inode per-cluster + * hash table */ + struct xfs_ioops m_io_ops; /* vector of I/O ops */ + struct xfs_expinfo *m_expinfo; /* info to export to other + cells. */ + uint64_t m_shadow_pinmask; + /* which bits matter in rpc + log item pin masks */ + uint m_cxfstype; /* mounted shared, etc. */ + lock_t m_freeze_lock; + uint m_frozen; + sv_t m_wait_unfreeze; + atomic_t m_active_trans; +} xfs_mount_t; + +/* + * Flags for m_flags. + */ +#define XFS_MOUNT_WSYNC 0x00000001 /* for nfs - all metadata ops + must be synchronous except + for space allocations */ +#if XFS_BIG_FILESYSTEMS +#define XFS_MOUNT_INO64 0x00000002 +#endif +#define XFS_MOUNT_ROOTQCHECK 0x00000004 + /* 0x00000008 -- currently unused */ +#define XFS_MOUNT_FS_SHUTDOWN 0x00000010 /* atomic stop of all filesystem + operations, typically for + disk errors in metadata */ +#define XFS_MOUNT_NOATIME 0x00000020 /* don't modify inode access + times on reads */ +#define XFS_MOUNT_RETERR 0x00000040 /* return alignment errors to + user */ +#define XFS_MOUNT_NOALIGN 0x00000080 /* turn off stripe alignment + allocations */ + /* 0x00000100 -- currently unused */ +#define XFS_MOUNT_REGISTERED 0x00000200 /* registered with cxfs master + cell logic */ +#define XFS_MOUNT_NORECOVERY 0x00000400 /* no recovery - dirty fs */ +#define XFS_MOUNT_SHARED 0x00000800 /* shared mount */ +#define XFS_MOUNT_DFLT_IOSIZE 0x00001000 /* set default i/o size */ +#define XFS_MOUNT_OSYNCISDSYNC 0x00002000 /* treat o_sync like o_dsync */ +#define XFS_MOUNT_NOUUID 0x00004000 /* ignore uuid during mount */ + +/* + * Flags for m_cxfstype + */ +#define XFS_CXFS_NOT 0x00000001 /* local mount */ +#define XFS_CXFS_SERVER 0x00000002 /* we're the CXFS server */ +#define XFS_CXFS_CLIENT 0x00000004 /* We're a CXFS client */ +#define XFS_CXFS_REC_ENABLED 0x00000008 /* recovery is enabled */ + +#define XFS_FORCED_SHUTDOWN(mp) ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN) + +/* + * Default minimum read and write sizes. + */ +#define XFS_READIO_LOG_LARGE 12 /* > 32MB memory */ +#define XFS_WRITEIO_LOG_LARGE 12 + +/* + * max and min values for UIO and mount-option defined I/O sizes + * min value can't be less than a page. Lower limit for 4K machines + * is 4K because that's what was tested. + */ +#define XFS_MAX_IO_LOG 16 /* 64K */ + +#if (_PAGESZ == 16384) || (_PAGESZ == 8192) +#define XFS_MIN_IO_LOG 14 /* 16K */ +#elif _PAGESZ == 4096 +#define XFS_MIN_IO_LOG 12 /* 4K */ +#else +#error "Unknown page size" +#endif + + +/* + * Synchronous read and write sizes. This should be + * better for NFSv2 wsync filesystems. + */ +#define XFS_WSYNC_READIO_LOG 15 /* 32K */ +#define XFS_WSYNC_WRITEIO_LOG 14 /* 16K */ + +#define xfs_force_shutdown(m,f) _xfs_force_shutdown(m,f,__FILE__,__LINE__); +/* + * Flags sent to xfs_force_shutdown. + */ +#define XFS_METADATA_IO_ERROR 0x1 +#define XFS_LOG_IO_ERROR 0x2 +#define XFS_FORCE_UMOUNT 0x4 +#define XFS_CORRUPT_INCORE 0x8 /* corrupt in-memory data structures */ +#if CELL_CAPABLE +#define XFS_SHUTDOWN_REMOTE_REQ 0x10 /* shutdown req came from remote cell */ +#endif + +/* + * xflags for xfs_syncsub + */ +#define XFS_XSYNC_RELOC 0x01 + +/* + * Flags for xfs_mountfs + */ +#define XFS_MFSI_SECOND 0x01 /* Is a cxfs secondary mount -- skip */ + /* stuff which should only be done */ + /* once. */ +#define XFS_MFSI_CLIENT 0x02 /* Is a client -- skip lots of stuff */ +#define XFS_MFSI_NOUNLINK 0x08 /* Skip unlinked inode processing in */ + /* log recovery */ + +/* + * Macros for getting from mount to vfs and back. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_MTOVFS) +struct vfs *xfs_mtovfs(xfs_mount_t *mp); +#define XFS_MTOVFS(mp) xfs_mtovfs(mp) +#else +#define XFS_MTOVFS(mp) (bhvtovfs(&(mp)->m_bhv)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BHVTOM) +xfs_mount_t *xfs_bhvtom(bhv_desc_t *bdp); +#define XFS_BHVTOM(bdp) xfs_bhvtom(bdp) +#else +#define XFS_BHVTOM(bdp) ((xfs_mount_t *)BHV_PDATA(bdp)) +#endif + + +/* + * Moved here from xfs_ag.h to avoid reordering header files + */ + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DADDR_TO_AGNO) +xfs_agnumber_t xfs_daddr_to_agno(struct xfs_mount *mp, xfs_daddr_t d); +#define XFS_DADDR_TO_AGNO(mp,d) xfs_daddr_to_agno(mp,d) +#else + +static inline xfs_agnumber_t XFS_DADDR_TO_AGNO(xfs_mount_t *mp, xfs_daddr_t d) +{ + d = XFS_BB_TO_FSBT(mp, d); + do_div(d, mp->m_sb.sb_agblocks); + return (xfs_agnumber_t) d; +} + +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DADDR_TO_AGBNO) +xfs_agblock_t xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d); +#define XFS_DADDR_TO_AGBNO(mp,d) xfs_daddr_to_agbno(mp,d) +#else + +static inline xfs_agblock_t XFS_DADDR_TO_AGBNO(xfs_mount_t *mp, xfs_daddr_t d) +{ + d = XFS_BB_TO_FSBT(mp, d); + return (xfs_agblock_t) do_div(d, mp->m_sb.sb_agblocks); +} + +#endif + +/* + * This structure is for use by the xfs_mod_incore_sb_batch() routine. + */ +typedef struct xfs_mod_sb { + xfs_sb_field_t msb_field; /* Field to modify, see below */ + int msb_delta; /* change to make to the specified field */ +} xfs_mod_sb_t; + +#define XFS_MOUNT_ILOCK(mp) mutex_lock(&((mp)->m_ilock), PINOD) +#define XFS_MOUNT_IUNLOCK(mp) mutex_unlock(&((mp)->m_ilock)) +#define XFS_SB_LOCK(mp) mutex_spinlock(&(mp)->m_sb_lock) +#define XFS_SB_UNLOCK(mp,s) mutex_spinunlock(&(mp)->m_sb_lock,(s)) + +void xfs_mod_sb(xfs_trans_t *, __int64_t); +xfs_mount_t *xfs_mount_init(void); +void xfs_mount_free(xfs_mount_t *mp, int remove_bhv); +int xfs_mountfs(struct vfs *, xfs_mount_t *mp, dev_t, int); +int xfs_mountargs(struct mounta *, struct xfs_args *); + +int xfs_unmountfs(xfs_mount_t *, int, struct cred *); +void xfs_unmountfs_close(xfs_mount_t *, int, struct cred *); +int xfs_unmountfs_writesb(xfs_mount_t *); +int xfs_unmount_flush(xfs_mount_t *, int); +int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int, int); +int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *, uint, int); +int xfs_readsb(xfs_mount_t *mp, dev_t); +struct xfs_buf *xfs_getsb(xfs_mount_t *, int); +void xfs_freesb(xfs_mount_t *); +void _xfs_force_shutdown(struct xfs_mount *, int, char *, int); +int xfs_syncsub(xfs_mount_t *, int, int, int *); +void xfs_xlatesb(void *, struct xfs_sb *, int, xfs_arch_t, __int64_t); + +#define XFS_FREEZE_WRITE 1 +#define XFS_FREEZE_TRANS 2 + +void xfs_start_freeze(xfs_mount_t *, int); +void xfs_finish_freeze(xfs_mount_t *); +void xfs_check_frozen(xfs_mount_t *, int); + +extern struct vfsops xfs_vfsops; + +#endif /* __KERNEL__ */ + +#endif /* __XFS_MOUNT_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_qm.c linux-2.4-xfs/linux/fs/xfs/xfs_qm.c --- linux-2.4.7/linux/fs/xfs/xfs_qm.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_qm.c Wed May 23 22:34:41 2001 @@ -0,0 +1,2937 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + + +struct xfs_qm *xfs_Gqm; +mutex_t xfs_Gqm_lock; +xfs_zone_t *qm_dqzone; +xfs_zone_t *qm_dqtrxzone; + +STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int); +STATIC void xfs_qm_list_destroy(xfs_dqlist_t *); +STATIC int xfs_qm_quotacheck(xfs_mount_t *); + +STATIC int xfs_qm_init_quotainos(xfs_mount_t *); +STATIC int xfs_qm_shake(int); + +#ifdef DEBUG +extern mutex_t qcheck_lock; +#endif + +/* + * quotacheck can shoot itself in the foot if we're not careful. + * In IRIX, low memory conditions are catered for using a shaked + * callback - xfs_qm_shake - there is no equivalent in Linux. + * For filesystems with lots of unique uid/gid's, quotacheck does + * alot of allocs - on Linux, we need to ensure we don't alloc + * without bound. + */ +#define XQM_CHECK_FREE do { \ + if (free_shortage()) { xfs_qm_shake((0)); } \ + } while (0) + +#ifdef QUOTADEBUG +#define XQM_LIST_PRINT(l, NXT, title) \ +{ \ + xfs_dquot_t *dqp; int i = 0;\ + printk("%s (#%d)\n", title, (int) (l)->qh_nelems); \ + for (dqp = (l)->qh_next; dqp != NULL; dqp = dqp->NXT) { \ + printk("\t%d.\t\"%d (%s)\"\t bcnt = %d, icnt = %d refs = %d\n", \ + ++i, (int) INT_GET(dqp->q_core.d_id, ARCH_CONVERT), \ + DQFLAGTO_TYPESTR(dqp), \ + (int) INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), \ + (int) INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), \ + (int) dqp->q_nrefs); } \ +} +#endif + +/* + * Initialize the XQM structure. + * Note that there is not one quota manager per file system. + */ +struct xfs_qm * +xfs_qm_init(void) +{ + xfs_qm_t *xqm; + int hsize, i; + + xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP); + ASSERT(xqm); + + /* + * Initialize the dquot hash tables. + */ + hsize = (DQUOT_HASH_HEURISTIC < XFS_QM_NCSIZE_THRESHOLD) ? + XFS_QM_HASHSIZE_LOW : XFS_QM_HASHSIZE_HIGH; + xqm->qm_dqhashmask = hsize - 1; + + /* + * XXXsup We could keep reference counts on usr and grp quotas + * inside XQM separately, and avoid having two hashtables even + * when only one 'type' is active in the system. + */ + xqm->qm_usr_dqhtable = (xfs_dqhash_t *)kmem_zalloc(hsize * + sizeof(xfs_dqhash_t), + KM_SLEEP); + xqm->qm_grp_dqhtable = (xfs_dqhash_t *)kmem_zalloc(hsize * + sizeof(xfs_dqhash_t), + KM_SLEEP); + ASSERT(xqm->qm_usr_dqhtable != NULL); + ASSERT(xqm->qm_grp_dqhtable != NULL); + + for (i = 0; i < hsize; i++) { + xfs_qm_list_init(&(xqm->qm_usr_dqhtable[i]), "uxdqh", i); + xfs_qm_list_init(&(xqm->qm_grp_dqhtable[i]), "gxdqh", i); + } + + /* + * Freelist of all dquots of all file systems + */ + xfs_qm_freelist_init(&(xqm->qm_dqfreelist)); + + /* + * dquot zone. we register our own low-memory callback. + */ + if (!qm_dqzone) { + xqm->qm_dqzone = kmem_zone_init(sizeof(xfs_dquot_t), + "xfs_dquots"); + qm_dqzone = xqm->qm_dqzone; + } else + xqm->qm_dqzone = qm_dqzone; + +#ifdef SHAKEMGR_MEMORY /* not defined in Linux */ + /* Ideally, we need a more generic low-memory callback facility */ + shake_register(SHAKEMGR_MEMORY, xfs_qm_shake); +#endif + + /* + * The t_dqinfo portion of transactions. + */ + if (!qm_dqtrxzone) { + xqm->qm_dqtrxzone = kmem_zone_init(sizeof(xfs_dquot_acct_t), + "xfs_dqtrx"); + qm_dqtrxzone = xqm->qm_dqtrxzone; + } else + xqm->qm_dqtrxzone = qm_dqtrxzone; + + atomic_set(&xqm->qm_totaldquots, 0); + xqm->qm_dqfree_ratio = XFS_QM_DQFREE_RATIO; + xqm->qm_nrefs = 0; +#ifdef DEBUG + mutex_init(&qcheck_lock, MUTEX_DEFAULT, "qchk"); +#endif + return (xqm); +} + +/* + * Destroy the global quota manager when its reference count goes to zero. + */ +void +xfs_qm_destroy( + struct xfs_qm *xqm) +{ + int hsize, i; + + ASSERT(xqm != NULL); + ASSERT(xqm->qm_nrefs == 0); + hsize = xqm->qm_dqhashmask + 1; + for (i = 0; i < hsize; i++) { + xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i])); + xfs_qm_list_destroy(&(xqm->qm_grp_dqhtable[i])); + } + kmem_free(xqm->qm_usr_dqhtable, hsize * sizeof(xfs_dqhash_t)); + kmem_free(xqm->qm_grp_dqhtable, hsize * sizeof(xfs_dqhash_t)); + xqm->qm_usr_dqhtable = NULL; + xqm->qm_grp_dqhtable = NULL; + xqm->qm_dqhashmask = 0; + xfs_qm_freelist_destroy(&(xqm->qm_dqfreelist)); +#ifdef DEBUG + mutex_destroy(&qcheck_lock); +#endif + kmem_free(xqm, sizeof(xfs_qm_t)); +} + +/* + * Called at mount time to let XQM know that another file system is + * starting quotas. This isn't crucial information as the individual mount + * structures are pretty independent, but it helps the XQM keep a + * global view of what's going on. + */ +/* ARGSUSED */ +STATIC int +xfs_qm_hold_quotafs_ref( + struct xfs_mount *mp) +{ + /* + * Need to lock the xfs_Gqm structure for things like this. For example, + * the structure could disappear between the entry to this routine and + * a HOLD operation if not locked. + */ + XFS_QM_LOCK(xfs_Gqm); + + if (xfs_Gqm == NULL) { + if ((xfs_Gqm = xfs_qm_init()) == NULL) { + return (XFS_ERROR(EINVAL)); + } + } + /* + * We can keep a list of all filesystems with quotas mounted for + * debugging and statistical purposes, but ... + * Just take a reference and get out. + */ + XFS_QM_HOLD(xfs_Gqm); + XFS_QM_UNLOCK(xfs_Gqm); + + return 0; +} + + +/* + * Release the reference that a filesystem took at mount time, + * so that we know when we need to destroy the entire quota manager. + */ +/* ARGSUSED */ +STATIC void +xfs_qm_rele_quotafs_ref( + struct xfs_mount *mp) +{ + xfs_dquot_t *dqp, *nextdqp; + + ASSERT(xfs_Gqm); + ASSERT(xfs_Gqm->qm_nrefs > 0); + + /* + * Go thru the freelist and destroy all inactive dquots. + */ + xfs_qm_freelist_lock(xfs_Gqm); + + for (dqp = xfs_Gqm->qm_dqfreelist.qh_next; + dqp != (xfs_dquot_t *)&(xfs_Gqm->qm_dqfreelist); ) { + xfs_dqlock(dqp); + nextdqp = dqp->dq_flnext; + if (dqp->dq_flags & XFS_DQ_INACTIVE) { + ASSERT(dqp->q_mount == NULL); + ASSERT(! XFS_DQ_IS_DIRTY(dqp)); + ASSERT(dqp->HL_PREVP == NULL); + ASSERT(dqp->MPL_PREVP == NULL); + XQM_FREELIST_REMOVE(dqp); + xfs_dqunlock(dqp); + xfs_qm_dqdestroy(dqp); + } else { + xfs_dqunlock(dqp); + } + dqp = nextdqp; + } + xfs_qm_freelist_unlock(xfs_Gqm); + + /* + * Destroy the entire XQM. If somebody mounts with quotaon, this'll + * be restarted. + */ + XFS_QM_LOCK(xfs_Gqm); + XFS_QM_RELE(xfs_Gqm); + if (xfs_Gqm->qm_nrefs == 0) { + xfs_qm_destroy(xfs_Gqm); + xfs_Gqm = NULL; + } + XFS_QM_UNLOCK(xfs_Gqm); +} + +/* + * This is called at mount time from xfs_mountfs to initialize the quotainfo + * structure and start the global quotamanager (xfs_Gqm) if it hasn't done + * so already. Note that the superblock has not been read in yet. + */ +void +xfs_qm_mount_quotainit( + xfs_mount_t *mp, + uint flags) +{ + /* + * User or group quotas has to be on, or we must have the + * QUOTAMAYBE flag set. + */ + ASSERT(flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA | XFSMNT_QUOTAMAYBE)); + + /* + * Initialize the flags in the mount structure. From this point + * onwards we look at m_qflags to figure out if quotas's ON/OFF, etc. + * Note that we enforce nothing if accounting is off. + * ie. XFSMNT_*QUOTA must be ON for XFSMNT_*QUOTAENF. + * It isn't necessary to take the quotaoff lock to do this; this is + * called from mount. + */ + if (flags & XFSMNT_UQUOTA) { + mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE); + if (flags & XFSMNT_UQUOTAENF) + mp->m_qflags |= XFS_UQUOTA_ENFD; + } + if (flags & XFSMNT_GQUOTA) { + mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE); + if (flags & XFSMNT_GQUOTAENF) + mp->m_qflags |= XFS_GQUOTA_ENFD; + } + /* + * Typically, we turn quotas off if we weren't explicitly asked to mount + * quotas. This is the mount option not to do that. + * This option is handy in the miniroot, when trying to mount /root. + * We can't really know what's in /etc/fstab until /root is already + * mounted! This stops quotas getting turned off in the root + * filesystem everytime the system boots up a miniroot. + */ + if (flags & XFSMNT_QUOTAMAYBE) + mp->m_qflags |= XFS_QUOTA_MAYBE; +} + +/* + * Just destroy the quotainfo structure. + */ +void +xfs_qm_unmount_quotadestroy( + xfs_mount_t *mp) +{ + xfs_qm_destroy_quotainfo(mp); +} + + +/* + * This is called from xfs_mountfs to start quotas and initialize all + * necessary data structures like quotainfo, and in the rootfs's case + * xfs_Gqm. This is also responsible for running a quotacheck as necessary. + * We are guaranteed that the superblock is consistently read in at this + * point. + */ +int +xfs_qm_mount_quotas( + xfs_mount_t *mp) +{ + int s; + int error; + uint sbf; + + error = 0; + /* + * If a non-root file system had quotas running earlier, but decided + * to mount without -o quota/pquota options, revoke the quotachecked + * license, and bail out. + * Unless, of course the XFS_QUOTA_MAYBE flag is specified. + */ + if (mp->m_qflags & XFS_QUOTA_MAYBE) { + mp->m_qflags &= ~(XFS_QUOTA_MAYBE); + if (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) { + mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_MOUNT_QUOTA_ALL); + mp->m_qflags |= XFS_UQUOTA_ACTIVE; + } + if (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) { + mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_MOUNT_QUOTA_ALL); + mp->m_qflags |= XFS_GQUOTA_ACTIVE; + } + } + if (! XFS_IS_QUOTA_ON(mp) && + (mp->m_dev != rootdev) && + (mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT))) { + mp->m_qflags = 0; + goto write_changes; + } + + /* + * If quotas on realtime volumes is not supported, we disable + * quotas immediately. + */ + if (mp->m_sb.sb_rextents) { + cmn_err(CE_NOTE, + "Cannot turn on quotas for realtime filesystem %s", + mp->m_fsname); + mp->m_qflags = 0; + goto write_changes; + } + +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + cmn_err(CE_NOTE, "Attempting to turn on disk quotas."); +#endif + /* + * If this is the root file system, mark flags in mount struct first. + * We couldn't do this earlier because we didn't have the superblock + * read in. + */ + if (mp->m_dev == rootdev) { + ASSERT(XFS_SB_VERSION_HASQUOTA(&mp->m_sb)); + ASSERT(mp->m_sb.sb_qflags & + (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT)); + if (xfs_Gqm == NULL) { + if ((xfs_Gqm = xfs_qm_init()) == NULL) { + mp->m_qflags = 0; + error = EINVAL; + goto write_changes; + } + } + mp->m_qflags = mp->m_sb.sb_qflags; + if (mp->m_qflags & XFS_UQUOTA_ACCT) + mp->m_qflags |= XFS_UQUOTA_ACTIVE; + if (mp->m_qflags & XFS_GQUOTA_ACCT) + mp->m_qflags |= XFS_GQUOTA_ACTIVE; + /* + * The quotainode of the root file system may or may not + * exist at this point. + */ + } + + ASSERT(XFS_IS_QUOTA_RUNNING(mp)); + /* + * Allocate the quotainfo structure inside the mount struct, and + * create quotainode(s), and change/rev superblock if necessary. + */ + if ((error = xfs_qm_init_quotainfo(mp))) { + /* + * We must turn off quotas. + */ + ASSERT(mp->m_quotainfo == NULL); + mp->m_qflags = 0; + goto write_changes; + } + /* + * If any of the quotas are not consistent, do a quotacheck. + */ + if (XFS_QM_NEED_QUOTACHECK(mp)) { +#ifdef DEBUG + cmn_err(CE_NOTE, "Doing a quotacheck. Please wait."); +#endif + if ((error = xfs_qm_quotacheck(mp))) { + cmn_err(CE_WARN, "Quotacheck unsuccessful (Error %d): " + "Disabling quotas.", + error); + /* + * We must turn off quotas. + */ + ASSERT(mp->m_quotainfo != NULL); + ASSERT(xfs_Gqm != NULL); + xfs_qm_destroy_quotainfo(mp); + mp->m_qflags = 0; + goto write_changes; + } +#ifdef DEBUG + cmn_err(CE_NOTE, "Done quotacheck."); +#endif + } + write_changes: + /* + * We actually don't have to acquire the SB_LOCK at all. + * This can only be called from mount, and that's single threaded. XXX + */ + s = XFS_SB_LOCK(mp); + sbf = mp->m_sb.sb_qflags; + mp->m_sb.sb_qflags = mp->m_qflags & XFS_MOUNT_QUOTA_ALL; + XFS_SB_UNLOCK(mp, s); + + if (sbf != (mp->m_qflags & XFS_MOUNT_QUOTA_ALL)) { + if (xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS)) { + /* + * We could only have been turning quotas off. + * We aren't in very good shape actually because + * the incore structures are convinced that quotas are + * off, but the on disk superblock doesn't know that ! + */ + ASSERT(!(XFS_IS_QUOTA_RUNNING(mp))); + xfs_fs_cmn_err(CE_ALERT, mp, + "XFS mount_quotas: Superblock update failed!"); + } + } + + if (error) { + xfs_fs_cmn_err(CE_WARN, mp, + "Failed to initialize disk quotas."); + } + return XFS_ERROR(error); +} + +/* + * Called from the vfsops layer. + */ +int +xfs_qm_unmount_quotas( + xfs_mount_t *mp) +{ + xfs_inode_t *uqp, *gqp; + int error; + + error = 0; + + /* + * Release the dquots that root inode, et al might be holding, + * before we flush quotas and blow away the quotainfo structure. + */ + ASSERT(mp->m_rootip); + if (mp->m_rootip->i_udquot || mp->m_rootip->i_gdquot) + xfs_qm_dqdettach_inode(mp->m_rootip); + if (mp->m_rbmip && + (mp->m_rbmip->i_udquot || mp->m_rbmip->i_gdquot)) + xfs_qm_dqdettach_inode(mp->m_rbmip); + if (mp->m_rsumip && + (mp->m_rsumip->i_udquot || mp->m_rsumip->i_gdquot)) + xfs_qm_dqdettach_inode(mp->m_rsumip); + + /* + * Flush out the quota inodes. + */ + uqp = gqp = NULL; + if (mp->m_quotainfo) { + if ((uqp = mp->m_quotainfo->qi_uquotaip) != NULL) { + xfs_ilock(uqp, XFS_ILOCK_EXCL); + xfs_iflock(uqp); + error = xfs_iflush(uqp, XFS_IFLUSH_SYNC); + xfs_iunlock(uqp, XFS_ILOCK_EXCL); + if (error == EFSCORRUPTED) + goto out; + } + if ((gqp = mp->m_quotainfo->qi_gquotaip) != NULL) { + xfs_ilock(gqp, XFS_ILOCK_EXCL); + xfs_iflock(gqp); + error = xfs_iflush(gqp, XFS_IFLUSH_SYNC); + xfs_iunlock(gqp, XFS_ILOCK_EXCL); + if (error == EFSCORRUPTED) + goto out; + } + } + if (uqp) { + XFS_PURGE_INODE(uqp); + mp->m_quotainfo->qi_uquotaip = NULL; + } + if (gqp) { + XFS_PURGE_INODE(gqp); + mp->m_quotainfo->qi_gquotaip = NULL; + } +out: + return XFS_ERROR(error); +} + +/* + * Flush all dquots of the given file system to disk. The dquots are + * _not_ purged from memory here, just their data written to disk. + */ +int +xfs_qm_dqflush_all( + xfs_mount_t *mp, + int flags) +{ + int recl; + xfs_dquot_t *dqp; + int niters; + int error; + + if (mp->m_quotainfo == NULL) + return (0); + niters = 0; +again: + xfs_qm_mplist_lock(mp); + FOREACH_DQUOT_IN_MP(dqp, mp) { + xfs_dqlock(dqp); + if (! XFS_DQ_IS_DIRTY(dqp)) { + xfs_dqunlock(dqp); + continue; + } + xfs_dqtrace_entry(dqp, "FLUSHALL: DQDIRTY"); + /* XXX a sentinel would be better */ + recl = XFS_QI_MPLRECLAIMS(mp); + if (! xfs_qm_dqflock_nowait(dqp)) { + /* + * If we can't grab the flush lock then check + * to see if the dquot has been flushed delayed + * write. If so, grab its buffer and send it + * out immediately. We'll be able to acquire + * the flush lock when the I/O completes. + */ + xfs_qm_dqflock_pushbuf_wait(dqp); + } + /* + * Let go of the mplist lock. We don't want to hold it + * across a disk write. + */ + xfs_qm_mplist_unlock(mp); + error = xfs_qm_dqflush(dqp, flags); + xfs_dqunlock(dqp); + if (error) + return (error); + + /* + * If this is the root filesystem doing a quotacheck, + * we should do periodic bflushes. This is because there's + * no bflushd at this point. + */ + if (mp->m_flags & XFS_MOUNT_ROOTQCHECK) { + if (++niters == XFS_QM_MAX_DQCLUSTER_LOGSZ) { + xfs_log_force(mp, (xfs_lsn_t)0, + XFS_LOG_FORCE | XFS_LOG_SYNC); + XFS_bflush(mp->m_ddev_targ); + niters = 0; + } + } + + xfs_qm_mplist_lock(mp); + if (recl != XFS_QI_MPLRECLAIMS(mp)) { + xfs_qm_mplist_unlock(mp); + /* XXX restart limit */ + goto again; + } + } + + xfs_qm_mplist_unlock(mp); + /* return ! busy */ + return (0); +} +/* + * Release the group dquot pointers the user dquots may be + * carrying around as a hint. mplist is locked on entry and exit. + */ +STATIC void +xfs_qm_detach_gdquots( + xfs_mount_t *mp) +{ + xfs_dquot_t *dqp, *gdqp; + int nrecl; + + again: + ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp)); + dqp = XFS_QI_MPLNEXT(mp); + while (dqp) { + xfs_dqlock(dqp); + if ((gdqp = dqp->q_gdquot)) { + xfs_dqlock(gdqp); + dqp->q_gdquot = NULL; + } + xfs_dqunlock(dqp); + + if (gdqp) { + /* + * Can't hold the mplist lock across a dqput. + * XXXmust convert to marker based iterations here. + */ + nrecl = XFS_QI_MPLRECLAIMS(mp); + xfs_qm_mplist_unlock(mp); + xfs_qm_dqput(gdqp); + + xfs_qm_mplist_lock(mp); + if (nrecl != XFS_QI_MPLRECLAIMS(mp)) + goto again; + } + dqp = dqp->MPL_NEXT; + } +} + +/* + * Go through all the incore dquots of this file system and take them + * off the mplist and hashlist, if the dquot type matches the dqtype + * parameter. This is used when turning off quota accounting for + * users and/or groups, as well as when the filesystem is unmounting. + */ +int +xfs_qm_dqpurge_all( + xfs_mount_t *mp, + uint flags) /* QUOTAOFF/UMOUNTING/UQUOTA/GQUOTA */ +{ + xfs_dquot_t *dqp; + uint dqtype; + int nrecl; + xfs_dquot_t *nextdqp; + int nmisses; + + if (mp->m_quotainfo == NULL) + return (0); + + dqtype = (flags & XFS_QMOPT_UQUOTA) ? XFS_DQ_USER : 0; + dqtype |= (flags & XFS_QMOPT_GQUOTA) ? XFS_DQ_GROUP : 0; + + xfs_qm_mplist_lock(mp); + + /* + * In the first pass through all incore dquots of this filesystem, + * we release the group dquot pointers the user dquots may be + * carrying around as a hint. We need to do this irrespective of + * what's being turned off. + */ + xfs_qm_detach_gdquots(mp); + + again: + nmisses = 0; + ASSERT(XFS_QM_IS_MPLIST_LOCKED(mp)); + /* + * Try to get rid of all of the unwanted dquots. The idea is to + * get them off mplist and hashlist, but leave them on freelist. + */ + dqp = XFS_QI_MPLNEXT(mp); + while (dqp) { + /* + * It's OK to look at the type without taking dqlock here. + * We're holding the mplist lock here, and that's needed for + * a dqreclaim. + */ + if ((dqp->dq_flags & dqtype) == 0) { + dqp = dqp->MPL_NEXT; + continue; + } + + if (! xfs_qm_dqhashlock_nowait(dqp)) { + nrecl = XFS_QI_MPLRECLAIMS(mp); + xfs_qm_mplist_unlock(mp); + XFS_DQ_HASH_LOCK(dqp->q_hash); + xfs_qm_mplist_lock(mp); + + /* + * XXXTheoretically, we can get into a very long + * ping pong game here. + * No one can be adding dquots to the mplist at + * this point, but somebody might be taking things off. + */ + if (nrecl != XFS_QI_MPLRECLAIMS(mp)) { + XFS_DQ_HASH_UNLOCK(dqp->q_hash); + goto again; + } + } + + /* + * Take the dquot off the mplist and hashlist. It may remain on + * freelist in INACTIVE state. + */ + nextdqp = dqp->MPL_NEXT; + nmisses += xfs_qm_dqpurge(dqp, flags); + dqp = nextdqp; + } + xfs_qm_mplist_unlock(mp); + return (nmisses); +} + +STATIC int +xfs_qm_dqattach_one( + xfs_inode_t *ip, + xfs_dqid_t id, + uint type, + uint doalloc, + uint dolock, + xfs_dquot_t *udqhint, /* hint */ + xfs_dquot_t **IO_idqpp) +{ + xfs_dquot_t *dqp; + int error; + + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + error = 0; + /* + * See if we already have it in the inode itself. IO_idqpp is + * &i_udquot or &i_gdquot. This made the code look weird, but + * made the logic a lot simpler. + */ + if ((dqp = *IO_idqpp)) { + if (dolock) + xfs_dqlock(dqp); + xfs_dqtrace_entry(dqp, "DQATTACH: found in ip"); + goto done; + } + + /* + * udqhint is the i_udquot field in inode, and is non-NULL only + * when the type arg is XFS_DQ_GROUP. Its purpose is to save a + * lookup by dqid (xfs_qm_dqget) by caching a group dquot inside + * the user dquot. + */ + ASSERT(!udqhint || type == XFS_DQ_GROUP); + if (udqhint && !dolock) + xfs_dqlock(udqhint); + + /* + * No need to take dqlock to look at the id. + * The ID can't change until it gets reclaimed, and it won't + * be reclaimed as long as we have a ref from inode and we hold + * the ilock. + */ + if (udqhint && + (dqp = udqhint->q_gdquot) && + (INT_GET(dqp->q_core.d_id, ARCH_CONVERT) == id)) { + ASSERT(XFS_DQ_IS_LOCKED(udqhint)); + xfs_dqlock(dqp); + XFS_DQHOLD(dqp); + ASSERT(*IO_idqpp == NULL); + *IO_idqpp = dqp; + if (!dolock) { + xfs_dqunlock(dqp); + xfs_dqunlock(udqhint); + } + /* XXX XFS_STATS */ + goto done; + } + /* + * We can't hold a dquot lock when we call the dqget code. + * We'll deadlock in no time, because of (not conforming to) + * lock ordering - the inodelock comes before any dquot lock, + * and we may drop and reacquire the ilock in xfs_qm_dqget(). + */ + if (udqhint) + xfs_dqunlock(udqhint); + /* + * Find the dquot from somewhere. This bumps the + * reference count of dquot and returns it locked. + * This can return ENOENT if dquot didn't exist on + * disk and we didn't ask it to allocate; + * ESRCH if quotas got turned off suddenly. + */ + if ((error = xfs_qm_dqget(ip->i_mount, ip, id, type, + doalloc|XFS_QMOPT_DOWARN, &dqp))) { + if (udqhint && dolock) + xfs_dqlock(udqhint); + goto done; + } + + xfs_dqtrace_entry(dqp, "DQATTACH: found by dqget"); + /* + * dqget may have dropped and re-acquired the ilock, but it guarantees + * that the dquot returned is the one that should go in the inode. + */ + *IO_idqpp = dqp; + ASSERT(dqp); + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + if (! dolock) { + xfs_dqunlock(dqp); + ASSERT(!udqhint || !XFS_DQ_IS_LOCKED(udqhint)); + goto done; + } + if (! udqhint) + goto done; + + ASSERT(udqhint); + ASSERT(dolock); + ASSERT(! XFS_DQ_IS_LOCKED(udqhint)); + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + if (! xfs_qm_dqlock_nowait(udqhint)) { + xfs_dqunlock(dqp); + xfs_dqlock(udqhint); + xfs_dqlock(dqp); + } + done: +#ifdef QUOTADEBUG + if (udqhint) { + if (dolock) + ASSERT(XFS_DQ_IS_LOCKED(udqhint)); + else + ASSERT(! XFS_DQ_IS_LOCKED(udqhint)); + } + if (! error) { + if (dolock) + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + else + ASSERT(! XFS_DQ_IS_LOCKED(dqp)); + } +#endif + return (error); +} + + +/* + * Given a udquot and gdquot, attach a ptr to the group dquot in the + * udquot as a hint for future lookups. The idea sounds simple, but the + * execution isn't, because the udquot might have a group dquot attached + * already and getting rid of that gets us into lock ordering contraints. + * The process is complicated more by the fact that the dquots may or may not + * be locked on entry. + */ +STATIC void +xfs_qm_dqattach_grouphint( + xfs_dquot_t *udq, + xfs_dquot_t *gdq, + uint locked) +{ + xfs_dquot_t *tmp; + +#ifdef QUOTADEBUG + if (locked) { + ASSERT(XFS_DQ_IS_LOCKED(udq)); + ASSERT(XFS_DQ_IS_LOCKED(gdq)); + } else { + ASSERT(! XFS_DQ_IS_LOCKED(udq)); + ASSERT(! XFS_DQ_IS_LOCKED(gdq)); + } +#endif + if (! locked) + xfs_dqlock(udq); + + if ((tmp = udq->q_gdquot)) { + if (tmp == gdq) { + if (! locked) + xfs_dqunlock(udq); + return; + } + + udq->q_gdquot = NULL; + /* + * We can't keep any dqlocks when calling dqrele, + * because the freelist lock comes before dqlocks. + */ + xfs_dqunlock(udq); + if (locked) + xfs_dqunlock(gdq); + /* + * we took a hard reference once upon a time in dqget, + * so give it back when the udquot no longer points at it + * dqput() does the unlocking of the dquot. + */ + xfs_qm_dqrele(tmp); + + ASSERT(! XFS_DQ_IS_LOCKED(udq)); + ASSERT(! XFS_DQ_IS_LOCKED(gdq)); + xfs_dqlock(udq); + xfs_dqlock(gdq); + + } else { + ASSERT(XFS_DQ_IS_LOCKED(udq)); + if (! locked) { + ASSERT(! XFS_DQ_IS_LOCKED(gdq)); + xfs_dqlock(gdq); + } + } + + ASSERT(XFS_DQ_IS_LOCKED(udq)); + ASSERT(XFS_DQ_IS_LOCKED(gdq)); + /* + * Somebody could have attached a gdquot here, + * when we dropped the uqlock. If so, just do nothing. + */ + if (udq->q_gdquot == NULL) { + XFS_DQHOLD(gdq); + udq->q_gdquot = gdq; + } + if (! locked) { + xfs_dqunlock(gdq); + xfs_dqunlock(udq); + } +} + + +/* + * Given a locked inode, attach dquot(s) to it, taking UQUOTAON / GQUOTAON + * in to account. + * If XFS_QMOPT_DQALLOC, the dquot(s) will be allocated if needed. + * If XFS_QMOPT_DQLOCK, the dquot(s) will be returned locked. This option pretty + * much made this code a complete mess, but it has been pretty useful. + * If XFS_QMOPT_ILOCKED, then inode sent is already locked EXCL. + * Inode may get unlocked and relocked in here, and the caller must deal with + * the consequences. + */ +int +xfs_qm_dqattach( + xfs_inode_t *ip, + uint flags) +{ + int error; + xfs_mount_t *mp; + uint nquotas; + + mp = ip->i_mount; + ASSERT(ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino); + + ASSERT((flags & XFS_QMOPT_ILOCKED) == 0 || + XFS_ISLOCKED_INODE_EXCL(ip)); + + nquotas = 0; + error = 0; + if (! (flags & XFS_QMOPT_ILOCKED)) + xfs_ilock(ip, XFS_ILOCK_EXCL); + + if (XFS_IS_UQUOTA_ON(mp)) { + if ((error = xfs_qm_dqattach_one(ip, ip->i_d.di_uid, XFS_DQ_USER, + flags & XFS_QMOPT_DQALLOC, + flags & XFS_QMOPT_DQLOCK, + NULL, &ip->i_udquot))) + goto done; + nquotas++; + } + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + if (XFS_IS_GQUOTA_ON(mp)) { + if ((error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP, + flags & XFS_QMOPT_DQALLOC, + flags & XFS_QMOPT_DQLOCK, + ip->i_udquot, &ip->i_gdquot))) + /* + * Don't worry about the udquot that we may have + * attached above. It'll get dettached, if not already. + */ + goto done; + nquotas++; + } + + /* + * Attach this group quota to the user quota as a hint. + * This WON'T, in general, result in a thrash. + */ + if (nquotas == 2) { + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + ASSERT(ip->i_udquot); + ASSERT(ip->i_gdquot); + + /* + * We may or may not have the i_udquot locked at this point, + * but this check is OK since we don't depend on the i_gdquot to + * be accurate 100% all the time. It is just a hint, and this + * will succeed in general. + */ + if (ip->i_udquot->q_gdquot == ip->i_gdquot) + goto done; + /* + * Attach i_gdquot to the gdquot hint inside the i_udquot. + */ + xfs_qm_dqattach_grouphint(ip->i_udquot, ip->i_gdquot, + flags & XFS_QMOPT_DQLOCK); + } + + done: + +#ifdef QUOTADEBUG + if (! error) { + if (ip->i_udquot) { + if (flags & XFS_QMOPT_DQLOCK) + ASSERT(XFS_DQ_IS_LOCKED(ip->i_udquot)); + else + ASSERT(! XFS_DQ_IS_LOCKED(ip->i_udquot)); + } + if (ip->i_gdquot) { + if (flags & XFS_QMOPT_DQLOCK) + ASSERT(XFS_DQ_IS_LOCKED(ip->i_gdquot)); + else + ASSERT(! XFS_DQ_IS_LOCKED(ip->i_gdquot)); + } + if (XFS_IS_UQUOTA_ON(mp)) + ASSERT(ip->i_udquot); + if (XFS_IS_GQUOTA_ON(mp)) + ASSERT(ip->i_gdquot); + } +#endif + + if (! (flags & XFS_QMOPT_ILOCKED)) + xfs_iunlock(ip, XFS_ILOCK_EXCL); + +#ifdef QUOTADEBUG + else + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); +#endif + return (error); +} + +/* + * Release dquots (and their references) if any. + * The inode should be locked EXCL except when this's called by + * xfs_ireclaim. + */ +void +xfs_qm_dqdettach_inode( + xfs_inode_t *ip) +{ + ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_uquotino); + ASSERT(ip->i_ino != ip->i_mount->m_sb.sb_gquotino); + if (ip->i_udquot) + xfs_dqtrace_entry_ino(ip->i_udquot, "DQDETTACH", ip); + if (ip->i_udquot) { + xfs_qm_dqrele(ip->i_udquot); + ip->i_udquot = NULL; + } + if (ip->i_gdquot) { + xfs_qm_dqrele(ip->i_gdquot); + ip->i_gdquot = NULL; + } +} + +int +xfs_qm_unmount( + xfs_mount_t *mp) +{ + vnode_t *vp; + + if (XFS_IS_UQUOTA_ON(mp)) { + vp = XFS_ITOV(XFS_QI_UQIP(mp)); + VN_RELE(vp); + if (vn_count(vp) > 1) + cmn_err(CE_WARN, "UQUOTA busy vp=0x%x count=%d\n", + vp, vn_count(vp)); + } + if (XFS_IS_GQUOTA_ON(mp)) { + vp = XFS_ITOV(XFS_QI_GQIP(mp)); + VN_RELE(vp); + if (vn_count(vp) > 1) + cmn_err(CE_WARN, "GQUOTA busy vp=0x%x count=%d\n", + vp, vn_count(vp)); + } + + return (0); +} + + +/* + * This is called by xfs_sync and flags arg determines the caller, + * and its motives, as done in xfs_sync. + * + * vfs_sync: SYNC_FSDATA|SYNC_ATTR|SYNC_BDFLUSH|SYNC_NOWAIT 0x31 + * syscall sync: SYNC_FSDATA|SYNC_ATTR|SYNC_DELWRI 0x25 + * umountroot : SYNC_WAIT | SYNC_CLOSE | SYNC_ATTR | SYNC_FSDATA + */ + +int +xfs_qm_sync( + xfs_mount_t *mp, + short flags) +{ + int recl, restarts; + xfs_dquot_t *dqp; + uint flush_flags; + boolean_t nowait; + int error; + + restarts = 0; + /* + * We won't block unless we are asked to. + */ + nowait = (boolean_t)(flags & SYNC_BDFLUSH || (flags & SYNC_WAIT) == 0); + + again: + xfs_qm_mplist_lock(mp); + /* + * dqpurge_all() also takes the mplist lock and iterate thru all dquots + * in quotaoff. However, if the QUOTA_ACTIVE bits are not cleared + * when we have the mplist lock, we know that dquots will be consistent + * as long as we have it locked. + */ + if (! XFS_IS_QUOTA_ON(mp)) { + xfs_qm_mplist_unlock(mp); + return (0); + } + FOREACH_DQUOT_IN_MP(dqp, mp) { + /* + * If this is vfs_sync calling, then skip the dquots that + * don't 'seem' to be dirty. ie. don't acquire dqlock. + * This is very similar to what xfs_sync does with inodes. + */ + if (flags & SYNC_BDFLUSH) { + if (! XFS_DQ_IS_DIRTY(dqp)) + continue; + } + + if (nowait) { + /* + * Try to acquire the dquot lock. We are NOT out of + * lock order, but we just don't want to wait for this + * lock, unless somebody wanted us to. + */ + if (! xfs_qm_dqlock_nowait(dqp)) + continue; + } else { + xfs_dqlock(dqp); + } + + /* + * Now, find out for sure if this dquot is dirty or not. + */ + if (! XFS_DQ_IS_DIRTY(dqp)) { + xfs_dqunlock(dqp); + continue; + } + + /* XXX a sentinel would be better */ + recl = XFS_QI_MPLRECLAIMS(mp); + if (! xfs_qm_dqflock_nowait(dqp)) { + if (nowait) { + xfs_dqunlock(dqp); + continue; + } + /* + * If we can't grab the flush lock then if the caller + * really wanted us to give this our best shot, + * see if we can give a push to the buffer before we wait + * on the flush lock. At this point, we know that + * eventhough the dquot is being flushed, + * it has (new) dirty data. + */ + xfs_qm_dqflock_pushbuf_wait(dqp); + } + /* + * Let go of the mplist lock. We don't want to hold it + * across a disk write + */ + flush_flags = (nowait) ? XFS_QMOPT_DELWRI : XFS_QMOPT_SYNC; + xfs_qm_mplist_unlock(mp); + xfs_dqtrace_entry(dqp, "XQM_SYNC: DQFLUSH"); + error = xfs_qm_dqflush(dqp, flush_flags); + xfs_dqunlock(dqp); + if (error && XFS_FORCED_SHUTDOWN(mp)) + return(0); /* Need to prevent umount failure */ + else if (error) + return (error); + + xfs_qm_mplist_lock(mp); + if (recl != XFS_QI_MPLRECLAIMS(mp)) { + if (++restarts >= XFS_QM_SYNC_MAX_RESTARTS) + break; + + xfs_qm_mplist_unlock(mp); + goto again; + } + } + + xfs_qm_mplist_unlock(mp); + return (0); +} + + +/* + * This initializes all the quota information that's kept in the + * mount structure + */ +int +xfs_qm_init_quotainfo( + xfs_mount_t *mp) +{ + xfs_quotainfo_t *qinf; + int error; + xfs_dquot_t *dqp; + + ASSERT(XFS_IS_QUOTA_RUNNING(mp)); + + /* + * Tell XQM that we exist as soon as possible. + */ + if ((error = xfs_qm_hold_quotafs_ref(mp))) { + return (error); + } + + qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), KM_SLEEP); + + /* + * See if quotainodes are setup, and if not, allocate them, + * and change the superblock accordingly. + */ + if ((error = xfs_qm_init_quotainos(mp))) { + kmem_free(qinf, sizeof(xfs_quotainfo_t)); + mp->m_quotainfo = NULL; + return (error); + } + + spinlock_init(&qinf->qi_pinlock, "xfs_qinf_pin"); + xfs_qm_list_init(&qinf->qi_dqlist, "mpdqlist", 0); + qinf->qi_dqreclaims = 0; + + /* mutex used to serialize quotaoffs */ + mutex_init(&qinf->qi_quotaofflock, MUTEX_DEFAULT, "qoff"); + + /* Precalc some constants */ + qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB); + ASSERT(qinf->qi_dqchunklen); + qinf->qi_dqperchunk = BBTOB(qinf->qi_dqchunklen); + do_div(qinf->qi_dqperchunk, sizeof(xfs_dqblk_t)); + + mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD); + + /* + * We try to get the limits from the superuser's limits fields. + * This is quite hacky, but it is standard quota practice. + * We look at the USR dquot with id == 0 first, but if user quotas + * are not enabled we goto the GRP dquot with id == 0. + * We don't really care to keep separate default limits for user + * and group quotas, at least not at this point. + */ + error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)0, + (XFS_IS_UQUOTA_RUNNING(mp)) ? + XFS_DQ_USER : XFS_DQ_GROUP, + XFS_QMOPT_DQSUSER|XFS_QMOPT_DOWARN, + &dqp); + if (! error) { + /* + * The warnings and timers set the grace period given to + * a user or group before he or she can not perform any + * more writing. If it is zero, a default is used. + */ + qinf->qi_btimelimit = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) ? + INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) : XFS_QM_BTIMELIMIT; + qinf->qi_itimelimit = INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) ? + INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) : XFS_QM_ITIMELIMIT; + qinf->qi_rtbtimelimit = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) ? + INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT) : XFS_QM_RTBTIMELIMIT; + qinf->qi_bwarnlimit = INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) ? + INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) : XFS_QM_BWARNLIMIT; + qinf->qi_iwarnlimit = INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) ? + INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) : XFS_QM_IWARNLIMIT; + + /* + * We sent the XFS_QMOPT_DQSUSER flag to dqget because + * we don't want this dquot cached. We haven't done a + * quotacheck yet, and quotacheck doesn't like incore dquots. + */ + xfs_qm_dqdestroy(dqp); + } else { + qinf->qi_btimelimit = XFS_QM_BTIMELIMIT; + qinf->qi_itimelimit = XFS_QM_ITIMELIMIT; + qinf->qi_rtbtimelimit = XFS_QM_RTBTIMELIMIT; + qinf->qi_bwarnlimit = XFS_QM_BWARNLIMIT; + qinf->qi_iwarnlimit = XFS_QM_IWARNLIMIT; + } + + return (0); +} + + +/* + * Gets called when unmounting a filesystem or when all quotas get + * turned off. + * This purges the quota inodes, destroys locks and frees itself. + */ +void +xfs_qm_destroy_quotainfo( + xfs_mount_t *mp) +{ + xfs_quotainfo_t *qi; + + qi = mp->m_quotainfo; + ASSERT(qi != NULL); + ASSERT(xfs_Gqm != NULL); + + /* + * Release the reference that XQM kept, so that we know + * when the XQM structure should be freed. We cannot assume + * that xfs_Gqm is non-null after this point. + */ + xfs_qm_rele_quotafs_ref(mp); + + spinlock_destroy(&qi->qi_pinlock); + xfs_qm_list_destroy(&qi->qi_dqlist); + + if (qi->qi_uquotaip) { + XFS_PURGE_INODE(qi->qi_uquotaip); + qi->qi_uquotaip = NULL; /* paranoia */ + } + if (qi->qi_gquotaip) { + XFS_PURGE_INODE(qi->qi_gquotaip); + qi->qi_gquotaip = NULL; + } + mutex_destroy(&qi->qi_quotaofflock); + kmem_free(qi, sizeof(xfs_quotainfo_t)); + mp->m_quotainfo = NULL; +} + + + +/* ------------------- PRIVATE STATIC FUNCTIONS ----------------------- */ + +/* ARGSUSED */ +STATIC void +xfs_qm_list_init( + xfs_dqlist_t *list, + char *str, + int n) +{ + mutex_init(&list->qh_lock, MUTEX_DEFAULT, str); + list->qh_next = NULL; + list->qh_version = 0; + list->qh_nelems = 0; +} + +STATIC void +xfs_qm_list_destroy( + xfs_dqlist_t *list) +{ + mutex_destroy(&(list->qh_lock)); +} + + +/* + * Stripped down version of dqattach. This doesn't attach, or even look at the + * dquots attached to the inode. The rationale is that there won't be any + * attached at the time this is called from quotacheck. + */ +STATIC int +xfs_qm_dqget_noattach( + xfs_inode_t *ip, + xfs_dquot_t **O_udqpp, + xfs_dquot_t **O_gdqpp) +{ + int error; + xfs_mount_t *mp; + xfs_dquot_t *udqp, *gdqp; + + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + mp = ip->i_mount; + udqp = NULL; + gdqp = NULL; + + if (XFS_IS_UQUOTA_ON(mp)) { + ASSERT(ip->i_udquot == NULL); + /* + * We want the dquot allocated if it doesn't exist. + */ + if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_uid, XFS_DQ_USER, + XFS_QMOPT_DQALLOC | XFS_QMOPT_DOWARN, + &udqp))) { + /* + * Shouldn't be able to turn off quotas here. + */ + ASSERT(error != ESRCH); + ASSERT(error != ENOENT); + return (error); + } + ASSERT(udqp); + } + + if (XFS_IS_GQUOTA_ON(mp)) { + ASSERT(ip->i_gdquot == NULL); + if (udqp) + xfs_dqunlock(udqp); + if ((error = xfs_qm_dqget(mp, ip, ip->i_d.di_gid, XFS_DQ_GROUP, + XFS_QMOPT_DQALLOC|XFS_QMOPT_DOWARN, + &gdqp))) { + if (udqp) + xfs_qm_dqrele(udqp); + ASSERT(error != ESRCH); + ASSERT(error != ENOENT); + return (error); + } + ASSERT(gdqp); + + /* Reacquire the locks in the right order */ + if (udqp) { + if (! xfs_qm_dqlock_nowait(udqp)) { + xfs_dqunlock(gdqp); + xfs_dqlock(udqp); + xfs_dqlock(gdqp); + } + } + } + + *O_udqpp = udqp; + *O_gdqpp = gdqp; + +#ifdef QUOTADEBUG + if (udqp) ASSERT(XFS_DQ_IS_LOCKED(udqp)); + if (gdqp) ASSERT(XFS_DQ_IS_LOCKED(gdqp)); +#endif + return (0); +} + +/* + * Create an inode and return with a reference already taken, but unlocked + * This is how we create quota inodes + */ +STATIC int +xfs_qm_qino_alloc( + xfs_mount_t *mp, + xfs_inode_t **ip, + __int64_t sbfields, + uint flags) +{ + xfs_trans_t *tp; + int error, s; + cred_t zerocr; + int committed; + + tp = xfs_trans_alloc(mp,XFS_TRANS_QM_QINOCREATE); + if ((error = xfs_trans_reserve(tp, + XFS_QM_QINOCREATE_SPACE_RES(mp), + XFS_CREATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_CREATE_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + return (error); + } + bzero(&zerocr, sizeof(zerocr)); + + if ((error = xfs_dir_ialloc(&tp, mp->m_rootip, IFREG, 1, mp->m_dev, + &zerocr, 0, 1, ip, &committed))) { + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT); + return (error); + } + + /* + * Keep an extra reference to this quota inode. This inode is + * locked exclusively and joined to the transaction already. + */ + ASSERT(XFS_ISLOCKED_INODE_EXCL(*ip)); + VN_HOLD(XFS_ITOV((*ip))); + + /* + * Make the changes in the superblock, and log those too. + * sbfields arg may contain fields other than *QUOTINO; + * VERSIONNUM for example. + */ + s = XFS_SB_LOCK(mp); + if (flags & XFS_QMOPT_SBVERSION) { +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + unsigned oldv = mp->m_sb.sb_versionnum; +#endif + ASSERT(!XFS_SB_VERSION_HASQUOTA(&mp->m_sb)); + ASSERT((sbfields & (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | + XFS_SB_GQUOTINO | XFS_SB_QFLAGS)) == + (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | + XFS_SB_GQUOTINO | XFS_SB_QFLAGS)); + + XFS_SB_VERSION_ADDQUOTA(&mp->m_sb); + mp->m_sb.sb_uquotino = NULLFSINO; + mp->m_sb.sb_gquotino = NULLFSINO; + + /* qflags will get updated _after_ quotacheck */ + mp->m_sb.sb_qflags = 0; +#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY) + cmn_err(CE_NOTE, + "Old superblock version %x, converting to %x.", + oldv, mp->m_sb.sb_versionnum); +#endif + } + if (flags & XFS_QMOPT_UQUOTA) + mp->m_sb.sb_uquotino = (*ip)->i_ino; + else + mp->m_sb.sb_gquotino = (*ip)->i_ino; + XFS_SB_UNLOCK(mp, s); + xfs_mod_sb(tp, sbfields); + + if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, + NULL))) { + xfs_fs_cmn_err(CE_ALERT, mp, "XFS qino_alloc failed!"); + return (error); + } + return (0); +} + + +STATIC int +xfs_qm_reset_dqcounts( + xfs_mount_t *mp, + xfs_buf_t *bp, + xfs_dqid_t id, + uint type) +{ + xfs_disk_dquot_t *ddq; + int j; + + xfs_buftrace("RESET DQUOTS", bp); + /* + * Reset all counters and timers. They'll be + * started afresh by xfs_qm_quotacheck. + */ +#ifdef DEBUG + j = XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB); + do_div(j, sizeof(xfs_dqblk_t)); + ASSERT(XFS_QM_DQPERBLK(mp) == j); +#endif + ddq = (xfs_disk_dquot_t *)XFS_BUF_PTR(bp); + for (j = 0; j < XFS_QM_DQPERBLK(mp); j++) { + /* + * Do a sanity check, and if needed, repair the dqblk. Don't + * output any warnings because it's perfectly possible to + * find unitialized dquot blks. See comment in xfs_qm_dqcheck. + */ + (void) xfs_qm_dqcheck(ddq, id+j, type, XFS_QMOPT_DQREPAIR, + "xfs_quotacheck"); + INT_SET(ddq->d_bcount, ARCH_CONVERT, 0ULL); + INT_SET(ddq->d_icount, ARCH_CONVERT, 0ULL); + INT_SET(ddq->d_rtbcount, ARCH_CONVERT, 0ULL); + INT_SET(ddq->d_btimer, ARCH_CONVERT, (time_t)0); + INT_SET(ddq->d_itimer, ARCH_CONVERT, (time_t)0); + INT_SET(ddq->d_bwarns, ARCH_CONVERT, 0UL); + INT_SET(ddq->d_iwarns, ARCH_CONVERT, 0UL); + ddq = (xfs_disk_dquot_t *) ((xfs_dqblk_t *)ddq + 1); + } + + return (0); +} + +STATIC int +xfs_qm_dqiter_bufs( + xfs_mount_t *mp, + xfs_dqid_t firstid, + xfs_fsblock_t bno, + xfs_filblks_t blkcnt, + uint flags) +{ + xfs_buf_t *bp; + int error; + int notcommitted; + int incr; + + ASSERT(blkcnt > 0); + notcommitted = 0; + incr = (blkcnt > XFS_QM_MAX_DQCLUSTER_LOGSZ) ? + XFS_QM_MAX_DQCLUSTER_LOGSZ : blkcnt; + error = 0; + + /* + * Blkcnt arg can be a very big number, and might even be + * larger than the log itself. So, we have to break it up into + * manageable-sized transactions. + * Note that we don't start a permanent transaction here; we might + * not be able to get a log reservation for the whole thing up front, + * and we don't really care to either, because we just discard + * everything if we were to crash in the middle of this loop. + */ + while (blkcnt--) { + error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, + XFS_FSB_TO_DADDR(mp, bno), + (int)XFS_QI_DQCHUNKLEN(mp), 0, &bp); + if (error) + break; + + (void) xfs_qm_reset_dqcounts(mp, bp, firstid, + flags & XFS_QMOPT_UQUOTA ? + XFS_DQ_USER : XFS_DQ_GROUP); + xfs_bdwrite(mp, bp); + /* + * When quotachecking the root filesystem, + * we may not have bdflush, and we may fill + * up all available freebufs. + * The workaround here is to push on the + * log and do a bflush on the rootdev + * periodically. + */ + if (mp->m_flags & XFS_MOUNT_ROOTQCHECK) { + if (++notcommitted == incr) { + xfs_log_force(mp, (xfs_lsn_t)0, + XFS_LOG_FORCE | XFS_LOG_SYNC); + XFS_bflush(mp->m_ddev_targ); + notcommitted = 0; + } + } + /* + * goto the next block. + */ + bno++; + firstid += XFS_QM_DQPERBLK(mp); + } + return (error); +} + +/* + * Iterate over all allocated USR/GRP dquots in the system, calling a + * caller supplied function for every chunk of dquots that we find. + */ +STATIC int +xfs_qm_dqiterate( + xfs_mount_t *mp, + xfs_inode_t *qip, + uint flags) +{ + xfs_bmbt_irec_t map[XFS_DQITER_MAP_SIZE]; + int i, nmaps; /* number of map entries */ + int error; /* return value */ + xfs_fileoff_t lblkno; + xfs_filblks_t maxlblkcnt; + xfs_dqid_t firstid; + xfs_fsblock_t rablkno; + xfs_filblks_t rablkcnt; + + error = 0; + /* + * This looks racey, but we can't keep an inode lock across a + * trans_reserve. But, this gets called during quotacheck, and that + * happens only at mount time which is single threaded. + */ + if (qip->i_d.di_nblocks == 0) + return (0); + + lblkno = 0; + maxlblkcnt = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAX_FILE_OFFSET); + do { + nmaps = XFS_DQITER_MAP_SIZE; + /* + * We aren't changing the inode itself. Just changing + * some of its data. No new blocks are added here, and + * the inode is never added to the transaction. + */ + xfs_ilock(qip, XFS_ILOCK_SHARED); + error = xfs_bmapi(NULL, qip, lblkno, + maxlblkcnt - lblkno, + XFS_BMAPI_METADATA, + NULL, + 0, map, &nmaps, NULL); + xfs_iunlock(qip, XFS_ILOCK_SHARED); + if (error) + break; + + ASSERT(nmaps <= XFS_DQITER_MAP_SIZE); + for (i = 0; i < nmaps; i++) { + ASSERT(map[i].br_startblock != DELAYSTARTBLOCK); + ASSERT(map[i].br_blockcount); + + + lblkno += map[i].br_blockcount; + + if (map[i].br_startblock == HOLESTARTBLOCK) + continue; + + firstid = (xfs_dqid_t) map[i].br_startoff * + XFS_QM_DQPERBLK(mp); + /* + * Do a read-ahead on the next extent. + */ + if ((i+1 < nmaps) && + (map[i+1].br_startblock != HOLESTARTBLOCK)) { + rablkcnt = map[i+1].br_blockcount; + rablkno = map[i+1].br_startblock; + while (rablkcnt--) { + xfs_baread(mp->m_ddev_targp, + XFS_FSB_TO_DADDR(mp, rablkno), + (int)XFS_QI_DQCHUNKLEN(mp)); + rablkno++; + } + } + /* + * Iterate thru all the blks in the extent and + * reset the counters of all the dquots inside them. + */ + if ((error = xfs_qm_dqiter_bufs(mp, + firstid, + map[i].br_startblock, + map[i].br_blockcount, + flags))) { + break; + } + } + + if (error) + break; + } while (nmaps > 0); + + return (error); +} + +/* + * Called by dqusage_adjust in doing a quotacheck. + * Given the inode, and a dquot (either USR or GRP, doesn't matter), + * this updates its incore copy as well as the buffer copy. This is + * so that once the quotacheck is done, we can just log all the buffers, + * as opposed to logging numerous updates to individual dquots. + */ +STATIC void +xfs_qm_quotacheck_dqadjust( + xfs_dquot_t *dqp, + xfs_qcnt_t nblks, + xfs_qcnt_t rtblks) +{ + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + xfs_dqtrace_entry(dqp, "QCHECK DQADJUST"); + /* + * Adjust the inode count and the block count to reflect this inode's + * resource usage. + */ + INT_MOD(dqp->q_core.d_icount, ARCH_CONVERT, +1); + dqp->q_res_icount++; + if (nblks) { + INT_MOD(dqp->q_core.d_bcount, ARCH_CONVERT, nblks); + dqp->q_res_bcount += nblks; + } + if (rtblks) { + INT_MOD(dqp->q_core.d_rtbcount, ARCH_CONVERT, rtblks); + dqp->q_res_rtbcount += rtblks; + } + + /* + * Adjust the timers since we just changed usages + */ + if (! XFS_IS_SUSER_DQUOT(dqp)) + xfs_qm_adjust_dqtimers(dqp->q_mount, &dqp->q_core); + + dqp->dq_flags |= XFS_DQ_DIRTY; +} + +STATIC int +xfs_qm_get_rtblks( + xfs_inode_t *ip, + xfs_qcnt_t *O_rtblks) +{ + xfs_filblks_t rtblks; /* total rt blks */ + xfs_ifork_t *ifp; /* inode fork pointer */ + xfs_extnum_t nextents; /* number of extent entries */ + xfs_bmbt_rec_t *base; /* base of extent array */ + xfs_bmbt_rec_t *ep; /* pointer to an extent entry */ + int error; + + ASSERT(XFS_IS_REALTIME_INODE(ip)); + ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); + if (!(ifp->if_flags & XFS_IFEXTENTS)) { + if ((error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK))) + return (error); + } + rtblks = 0; + nextents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); + base = &ifp->if_u1.if_extents[0]; + for (ep = base; ep < &base[nextents]; ep++) + rtblks += xfs_bmbt_get_blockcount(ep); + *O_rtblks = (xfs_qcnt_t)rtblks; + return (0); +} + +/* + * callback routine supplied to bulkstat(). Given an inumber, find its + * dquots and update them to account for resources taken by that inode. + */ +/* ARGSUSED */ +STATIC int +xfs_qm_dqusage_adjust( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_trans_t *tp, /* transaction pointer - NULL */ + xfs_ino_t ino, /* inode number to get data for */ + void *buffer, /* not used */ + xfs_daddr_t bno, /* starting block of inode cluster */ + void *dip, /* on-disk inode pointer (not used) */ + int *res) /* result code value */ +{ + xfs_inode_t *ip; + xfs_dquot_t *udqp, *gdqp; + xfs_qcnt_t nblks, rtblks; + int error; + + ASSERT(XFS_IS_QUOTA_RUNNING(mp)); + + /* + * rootino must have its resources accounted for, not so with the quota + * inodes. + */ + if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) { + *res = BULKSTAT_RV_NOTHING; + return XFS_ERROR(EINVAL); + } + + /* + * We don't _need_ to take the ilock EXCL. However, the xfs_qm_dqget + * interface expects the inode to be exclusively locked because that's + * the case in all other instances. It's OK that we do this because + * quotacheck is done only at mount time. + */ + if ((error = xfs_iget(mp, tp, ino, XFS_ILOCK_EXCL, &ip, bno))) { + *res = BULKSTAT_RV_NOTHING; + return (error); + } + + if (ip->i_d.di_mode == 0) { + xfs_iput(ip, XFS_ILOCK_EXCL); + *res = BULKSTAT_RV_NOTHING; + return XFS_ERROR(ENOENT); + } + + /* + * Obtain the locked dquots. In case of an error (eg. allocation + * fails for ENOSPC), we return the negative of the error number + * to bulkstat, so that it can get propagated to quotacheck() and + * making us disable quotas for the file system. + */ + if ((error = xfs_qm_dqget_noattach(ip, &udqp, &gdqp))) { + xfs_iput(ip, XFS_ILOCK_EXCL); + *res = BULKSTAT_RV_GIVEUP; + return (error); + } + + rtblks = 0; + if (! XFS_IS_REALTIME_INODE(ip)) { + nblks = (xfs_qcnt_t)ip->i_d.di_nblocks; + } else { + /* + * Walk thru the extent list and count the realtime blocks. + */ + if ((error = xfs_qm_get_rtblks(ip, &rtblks))) { + xfs_iput(ip, XFS_ILOCK_EXCL); + if (udqp) + xfs_qm_dqput(udqp); + if (gdqp) + xfs_qm_dqput(gdqp); + *res = BULKSTAT_RV_GIVEUP; + return (error); + } + nblks = (xfs_qcnt_t)ip->i_d.di_nblocks - rtblks; + } + ASSERT(ip->i_delayed_blks == 0); + + /* + * We can't release the inode while holding its dquot locks. + * The inode can go into inactive and might try to acquire the dquotlocks. + * So, just unlock here and do a vn_rele at the end. + */ + xfs_iunlock(ip, XFS_ILOCK_EXCL); + + /* + * Add the (disk blocks and inode) resources occupied by this + * inode to its dquots. We do this adjustment in the incore dquot, + * and also copy the changes to its buffer. + * We don't care about putting these changes in a transaction + * envelope because if we crash in the middle of a 'quotacheck' + * we have to start from the beginning anyway. + * Once we're done, we'll log all the dquot bufs. + * + * The *QUOTA_ON checks below may look pretty racey, but quotachecks + * and quotaoffs don't race. (Quotachecks happen at mount time only). + */ + if (XFS_IS_UQUOTA_ON(mp)) { + ASSERT(udqp); + xfs_qm_quotacheck_dqadjust(udqp, nblks, rtblks); + xfs_qm_dqput(udqp); + } + if (XFS_IS_GQUOTA_ON(mp)) { + ASSERT(gdqp); + xfs_qm_quotacheck_dqadjust(gdqp, nblks, rtblks); + xfs_qm_dqput(gdqp); + } + /* + * Now release the inode. This will send it to 'inactive', and + * possibly even free blocks. + */ + VN_RELE(XFS_ITOV(ip)); + + /* + * Goto next inode. + */ + *res = BULKSTAT_RV_DIDONE; + return (0); +} + +/* + * Walk thru all the filesystem inodes and construct a consistent view + * of the disk quota world. + */ +STATIC int +xfs_qm_quotacheck( + xfs_mount_t *mp) +{ + int done, count, error; + xfs_ino_t lastino; + size_t structsz; + xfs_inode_t *uip, *gip; + uint flags; + + count = INT_MAX; + structsz = 1; + lastino = 0; + flags = 0; + + ASSERT(XFS_QI_UQIP(mp) || XFS_QI_GQIP(mp)); + ASSERT(XFS_IS_QUOTA_RUNNING(mp)); + + /* + * There should be no cached dquots. The (simplistic) quotacheck + * algorithm doesn't like that. + */ + ASSERT(XFS_QI_MPLNDQUOTS(mp) == 0); + + cmn_err(CE_NOTE, "XFS quotacheck %s: Please wait.", mp->m_fsname); + + /* + * First we go thru all the dquots on disk, USR and GRP, and reset + * their counters to zero. We need a clean slate. + * We don't log our changes till later. + */ + if ((uip = XFS_QI_UQIP(mp))) { + if ((error = xfs_qm_dqiterate(mp, uip, XFS_QMOPT_UQUOTA))) + goto error_return; + flags |= XFS_UQUOTA_CHKD; + } + + if ((gip = XFS_QI_GQIP(mp))) { + if ((error = xfs_qm_dqiterate(mp, gip, XFS_QMOPT_GQUOTA))) + goto error_return; + flags |= XFS_GQUOTA_CHKD; + } + + do { + /* + * Iterate thru all the inodes in the file system, + * adjusting the corresponding dquot counters in core. + */ + if ((error = xfs_bulkstat(mp, NULL, &lastino, &count, + xfs_qm_dqusage_adjust, + structsz, NULL, + BULKSTAT_FG_IGET|BULKSTAT_FG_VFSLOCKED, + &done))) + break; + + XQM_CHECK_FREE; + + } while (! done); + + /* + * We can get this error if we couldn't do a dquot allocation inside + * xfs_qm_dqusage_adjust (via bulkstat). We don't care about the + * dirty dquots that might be cached, we just want to get rid of them + * and turn quotaoff. The dquots won't be attached to any of the inodes + * at this point (because we intentionally didn't in dqget_noattach). + */ + if (error) { + xfs_qm_dqpurge_all(mp, + XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA| + XFS_QMOPT_QUOTAOFF); + goto error_return; + } + /* + * We've made all the changes that we need to make incore. + * Now flush_them down to disk buffers. + */ + xfs_qm_dqflush_all(mp, XFS_QMOPT_DELWRI); + + /* + * We didn't log anything, because if we crashed, we'll have to + * start the quotacheck from scratch anyway. However, we must make + * sure that our dquot changes are secure before we put the + * quotacheck'd stamp on the superblock. So, here we do a synchronous + * flush. + */ + XFS_bflush(mp->m_ddev_targ); + + /* + * If one type of quotas is off, then it will lose its + * quotachecked status, since we won't be doing accounting for + * that type anymore. + */ + mp->m_qflags &= ~(XFS_GQUOTA_CHKD | XFS_UQUOTA_CHKD); + mp->m_qflags |= flags; + +#ifdef QUOTADEBUG + XQM_LIST_PRINT(&(XFS_QI_MPL_LIST(mp)), MPL_NEXT, "++++ Mp list +++"); +#endif + + error_return: + cmn_err(CE_NOTE, "XFS quotacheck %s: Done.", mp->m_fsname); + mp->m_flags &= ~(XFS_MOUNT_ROOTQCHECK); + return (error); +} + +/* + * This is called after the superblock has been read in and we're ready to + * iget the quota inodes. + */ +STATIC int +xfs_qm_init_quotainos( + xfs_mount_t *mp) +{ + xfs_inode_t *uip, *gip; + int error; + __int64_t sbflags; + uint flags; + + ASSERT(mp->m_quotainfo); + uip = gip = NULL; + sbflags = 0; + flags = 0; + + /* + * Get the uquota and gquota inodes + */ + if (XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) { + if (XFS_IS_UQUOTA_ON(mp) && + mp->m_sb.sb_uquotino != NULLFSINO) { + ASSERT(mp->m_sb.sb_uquotino > 0); + if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, + 0, &uip, 0))) + return XFS_ERROR(error); + } + if (XFS_IS_GQUOTA_ON(mp) && + mp->m_sb.sb_gquotino != NULLFSINO) { + ASSERT(mp->m_sb.sb_gquotino > 0); + if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, + 0, &gip, 0))) { + if (uip) + VN_RELE(XFS_ITOV(uip)); + return XFS_ERROR(error); + } + } + } else { + flags |= XFS_QMOPT_SBVERSION; + sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | + XFS_SB_GQUOTINO | XFS_SB_QFLAGS); + } + + /* + * Create the two inodes, if they don't exist already. The changes + * made above will get added to a transaction and logged in one of + * the qino_alloc calls below. + */ + if (XFS_IS_UQUOTA_ON(mp) && uip == NULL) { + if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) + return XFS_ERROR(EROFS); + if ((error = xfs_qm_qino_alloc(mp, &uip, + sbflags | XFS_SB_UQUOTINO, + flags | XFS_QMOPT_UQUOTA))) + return XFS_ERROR(error); + + flags &= ~XFS_QMOPT_SBVERSION; + } + if (XFS_IS_GQUOTA_ON(mp) && gip == NULL) { + if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) { + if (uip) + VN_RELE(XFS_ITOV(uip)); + return XFS_ERROR(EROFS); + } + if ((error = xfs_qm_qino_alloc(mp, &gip, + sbflags | XFS_SB_GQUOTINO, + flags | XFS_QMOPT_GQUOTA))) { + if (uip) + VN_RELE(XFS_ITOV(uip)); + + return XFS_ERROR(error); + } + } + + XFS_QI_UQIP(mp) = uip; + XFS_QI_GQIP(mp) = gip; + + return (0); +} + + +/* + * Traverse the freelist of dquots and attempt to reclaim a maximum of + * 'howmany' dquots. This operation races with dqlookup(), and attempts to + * favor the lookup function ... + * XXXsup merge this with qm_reclaim_one(). + */ +STATIC int +xfs_qm_shake_freelist( + int howmany) +{ + int nreclaimed; + xfs_dqhash_t *hash; + xfs_dquot_t *dqp, *nextdqp; + int restarts; + int nflushes; + + if (howmany <= 0) + return (0); + + nreclaimed = 0; + restarts = 0; + nflushes = 0; + +#ifdef QUOTADEBUG + printk("Shake free 0x%x\n", howmany); +#endif + /* lock order is : hashchainlock, freelistlock, mplistlock */ + tryagain: + xfs_qm_freelist_lock(xfs_Gqm); + + for (dqp = xfs_Gqm->qm_dqfreelist.qh_next; + ((dqp != (xfs_dquot_t *) &xfs_Gqm->qm_dqfreelist) && + nreclaimed < howmany); ) { + xfs_dqlock(dqp); + + /* + * We are racing with dqlookup here. Naturally we don't + * want to reclaim a dquot that lookup wants. + */ + if (dqp->dq_flags & XFS_DQ_WANT) { + xfs_dqunlock(dqp); + xfs_qm_freelist_unlock(xfs_Gqm); + if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS) + return (nreclaimed != howmany); + XFS_STATS_INC(xfsstats.xs_qm_dqwants); + goto tryagain; + } + + /* + * If the dquot is inactive, we are assured that it is + * not on the mplist or the hashlist, and that makes our + * life easier. + */ + if (dqp->dq_flags & XFS_DQ_INACTIVE) { + ASSERT(dqp->q_mount == NULL); + ASSERT(! XFS_DQ_IS_DIRTY(dqp)); + ASSERT(dqp->HL_PREVP == NULL); + ASSERT(dqp->MPL_PREVP == NULL); + XFS_STATS_INC(xfsstats.xs_qm_dqinact_reclaims); + nextdqp = dqp->dq_flnext; + goto off_freelist; + } + + ASSERT(dqp->MPL_PREVP); + /* + * Try to grab the flush lock. If this dquot is in the process of + * getting flushed to disk, we don't want to reclaim it. + */ + if (! xfs_qm_dqflock_nowait(dqp)) { + xfs_dqunlock(dqp); + dqp = dqp->dq_flnext; + continue; + } + + /* + * We have the flush lock so we know that this is not in the + * process of being flushed. So, if this is dirty, flush it + * DELWRI so that we don't get a freelist infested with + * dirty dquots. + */ + if (XFS_DQ_IS_DIRTY(dqp)) { + xfs_dqtrace_entry(dqp, "DQSHAKE: DQDIRTY"); + /* + * We'll be doing a dqflush, and it is + * possible to fill up the entire buffer cache + * with dirty delayed write buffers when doing + * this on a root filesystem, if bdflush isn't + * running. So, do a flush periodically. + */ + if (dqp->q_mount->m_flags & XFS_MOUNT_ROOTQCHECK) { + if (!(++nflushes % XFS_QM_MAX_DQCLUSTER_LOGSZ)){ + xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, + XFS_LOG_FORCE | XFS_LOG_SYNC); + XFS_bflush(dqp->q_mount->m_ddev_targ); + } + } + /* + * We flush it delayed write, so don't bother + * releasing the mplock. + */ + (void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI); + xfs_dqunlock(dqp); /* dqflush unlocks dqflock */ + dqp = dqp->dq_flnext; + continue; + } + /* + * We're trying to get the hashlock out of order. This races + * with dqlookup; so, we giveup and goto the next dquot if + * we couldn't get the hashlock. This way, we won't starve + * a dqlookup process that holds the hashlock that is + * waiting for the freelist lock. + */ + if (! xfs_qm_dqhashlock_nowait(dqp)) { + xfs_dqfunlock(dqp); + xfs_dqunlock(dqp); + dqp = dqp->dq_flnext; + continue; + } + /* + * This races with dquot allocation code as well as dqflush_all + * and reclaim code. So, if we failed to grab the mplist lock, + * giveup everything and start over. + */ + hash = dqp->q_hash; + ASSERT(hash); + if (! xfs_qm_mplist_nowait(dqp->q_mount)) { + /* XXX put a sentinel so that we can come back here */ + xfs_dqfunlock(dqp); + xfs_dqunlock(dqp); + XFS_DQ_HASH_UNLOCK(hash); + xfs_qm_freelist_unlock(xfs_Gqm); + if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS) + return (nreclaimed != howmany); + goto tryagain; + } + xfs_dqtrace_entry(dqp, "DQSHAKE: UNLINKING"); +#ifdef QUOTADEBUG + printk("Shake 0x%p, ID 0x%x\n", dqp, INT_GET(dqp->q_core.d_id, ARCH_CONVERT)); +#endif + ASSERT(dqp->q_nrefs == 0); + nextdqp = dqp->dq_flnext; + XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp); + XQM_HASHLIST_REMOVE(hash, dqp); + xfs_dqfunlock(dqp); + xfs_qm_mplist_unlock(dqp->q_mount); + XFS_DQ_HASH_UNLOCK(hash); + + off_freelist: + XQM_FREELIST_REMOVE(dqp); + xfs_dqunlock(dqp); + nreclaimed++; + XFS_STATS_INC(xfsstats.xs_qm_dqshake_reclaims); + xfs_qm_dqdestroy(dqp); + dqp = nextdqp; + } + xfs_qm_freelist_unlock(xfs_Gqm); + return (nreclaimed != howmany); +} + + +/* + * The shake manager routine called by shaked() when memory is + * running low. + */ +/* ARGSUSED */ +STATIC int +xfs_qm_shake(int level) +{ + int ndqused, nfree, n; + + if (xfs_Gqm == NULL) + return (0); + + nfree = xfs_Gqm->qm_dqfreelist.qh_nelems; /* free dquots */ + /* incore dquots in all f/s's */ + ndqused = atomic_read(&xfs_Gqm->qm_totaldquots) - nfree; + + ASSERT(ndqused >= 0); + + if (nfree <= ndqused && nfree < ndquot) + return 0; + + ndqused *= xfs_Gqm->qm_dqfree_ratio; /* target # of free dquots */ + n = nfree - ndqused - ndquot; /* # over target */ + + return xfs_qm_shake_freelist(MAX(nfree, n)); +} + + +/* + * Just pop the least recently used dquot off the freelist and + * recycle it. The returned dquot is locked. + */ +STATIC xfs_dquot_t * +xfs_qm_dqreclaim_one(void) +{ + xfs_dquot_t *dqpout; + xfs_dquot_t *dqp; + int restarts; + int nflushes; + + restarts = 0; + dqpout = NULL; + nflushes = 0; + + /* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */ + startagain: + xfs_qm_freelist_lock(xfs_Gqm); + + FOREACH_DQUOT_IN_FREELIST(dqp, &(xfs_Gqm->qm_dqfreelist)) { + xfs_dqlock(dqp); + + /* + * We are racing with dqlookup here. Naturally we don't + * want to reclaim a dquot that lookup wants. We release the + * freelist lock and start over, so that lookup will grab + * both the dquot and the freelistlock. + */ + if (dqp->dq_flags & XFS_DQ_WANT) { + ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE)); + xfs_dqtrace_entry(dqp, "DQRECLAIM: DQWANT"); + xfs_dqunlock(dqp); + xfs_qm_freelist_unlock(xfs_Gqm); + if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS) + return (NULL); + XFS_STATS_INC(xfsstats.xs_qm_dqwants); + goto startagain; + } + + /* + * If the dquot is inactive, we are assured that it is + * not on the mplist or the hashlist, and that makes our + * life easier. + */ + if (dqp->dq_flags & XFS_DQ_INACTIVE) { + ASSERT(dqp->q_mount == NULL); + ASSERT(! XFS_DQ_IS_DIRTY(dqp)); + ASSERT(dqp->HL_PREVP == NULL); + ASSERT(dqp->MPL_PREVP == NULL); + XQM_FREELIST_REMOVE(dqp); + xfs_dqunlock(dqp); + dqpout = dqp; + XFS_STATS_INC(xfsstats.xs_qm_dqinact_reclaims); + break; + } + + ASSERT(dqp->q_hash); + ASSERT(dqp->MPL_PREVP); + + /* + * Try to grab the flush lock. If this dquot is in the process of + * getting flushed to disk, we don't want to reclaim it. + */ + if (! xfs_qm_dqflock_nowait(dqp)) { + xfs_dqunlock(dqp); + continue; + } + + /* + * We have the flush lock so we know that this is not in the + * process of being flushed. So, if this is dirty, flush it + * DELWRI so that we don't get a freelist infested with + * dirty dquots. + */ + if (XFS_DQ_IS_DIRTY(dqp)) { + xfs_dqtrace_entry(dqp, "DQRECLAIM: DQDIRTY"); + /* + * We'll be doing a dqflush, and it is + * possible to fill up the entire buffer cache + * with dirty delayed write buffers when doing + * this on a root filesystem, if bdflush isn't + * running. So, do a flush periodically. + */ + if (dqp->q_mount->m_flags & XFS_MOUNT_ROOTQCHECK) { + if (!(++nflushes % XFS_QM_MAX_DQCLUSTER_LOGSZ)) { + xfs_log_force(dqp->q_mount, (xfs_lsn_t)0, + XFS_LOG_FORCE | XFS_LOG_SYNC); + XFS_bflush(dqp->q_mount->m_ddev_targ); + } + } + + /* + * We flush it delayed write, so don't bother + * releasing the freelist lock. + */ + (void) xfs_qm_dqflush(dqp, XFS_QMOPT_DELWRI); + xfs_dqunlock(dqp); /* dqflush unlocks dqflock */ + continue; + } + + if (! xfs_qm_mplist_nowait(dqp->q_mount)) { + xfs_dqfunlock(dqp); + xfs_dqunlock(dqp); + continue; + } + + if (! xfs_qm_dqhashlock_nowait(dqp)) + goto mplistunlock; + + ASSERT(dqp->q_nrefs == 0); + xfs_dqtrace_entry(dqp, "DQRECLAIM: UNLINKING"); + XQM_MPLIST_REMOVE(&(XFS_QI_MPL_LIST(dqp->q_mount)), dqp); + XQM_HASHLIST_REMOVE(dqp->q_hash, dqp); + XQM_FREELIST_REMOVE(dqp); + dqpout = dqp; + XFS_DQ_HASH_UNLOCK(dqp->q_hash); + mplistunlock: + xfs_qm_mplist_unlock(dqp->q_mount); + xfs_dqfunlock(dqp); + xfs_dqunlock(dqp); + if (dqpout) + break; + } + + xfs_qm_freelist_unlock(xfs_Gqm); + return (dqpout); +} + + +/*------------------------------------------------------------------*/ + +/* + * Return a new incore dquot. Depending on the number of + * dquots in the system, we either allocate a new one on the kernel heap, + * or reclaim a free one. + * Return value is B_TRUE if we allocated a new dquot, B_FALSE if we managed + * to reclaim an existing one from the freelist. + */ +boolean_t +xfs_qm_dqalloc_incore( + xfs_dquot_t **O_dqpp) +{ + xfs_dquot_t *dqp; + + /* + * Check against high water mark to see if we want to pop + * a nincompoop dquot off the freelist. + */ + if (atomic_read(&xfs_Gqm->qm_totaldquots) >= ndquot) { + /* + * Try to recycle a dquot from the freelist. + */ + if ((dqp = xfs_qm_dqreclaim_one())) { + XFS_STATS_INC(xfsstats.xs_qm_dqreclaims); + /* + * Just bzero the core here. The rest will get + * reinitialized by caller. XXX we shouldn't even + * do this bzero ... + */ + bzero(&dqp->q_core, sizeof(dqp->q_core)); + *O_dqpp = dqp; + return (B_FALSE); + } + XFS_STATS_INC(xfsstats.xs_qm_dqreclaim_misses); + } + + XQM_CHECK_FREE; + + /* + * Allocate a brand new dquot on the kernel heap and return it + * to the caller to initialize. + */ + ASSERT(xfs_Gqm->qm_dqzone != NULL); + *O_dqpp = kmem_zone_zalloc(xfs_Gqm->qm_dqzone, KM_SLEEP); + atomic_inc(&xfs_Gqm->qm_totaldquots); + + return (B_TRUE); +} + + +/* + * Start a transaction and write the incore superblock changes to + * disk. flags parameter indicates which fields have changed. + */ +int +xfs_qm_write_sb_changes( + xfs_mount_t *mp, + __int64_t flags) +{ + xfs_trans_t *tp; + int error; + +#ifdef QUOTADEBUG + cmn_err(CE_NOTE, + "Writing superblock quota changes :%s", + mp->m_fsname); +#endif + tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE); + if ((error = xfs_trans_reserve(tp, 0, + mp->m_sb.sb_sectsize + 128, 0, + 0, + XFS_DEFAULT_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + return (error); + } + + xfs_mod_sb(tp, flags); + (void) xfs_trans_commit(tp, 0, NULL); + + return (0); +} + + +/* --------------- utility functions for vnodeops ---------------- */ + + +/* + * Given an inode, a uid and gid (from cred_t) make sure that we have + * allocated relevant dquot(s) on disk, and that we won't exceed inode + * quotas by creating this file. + * This also attaches dquot(s) to the given inode after locking it, + * and returns the dquots corresponding to the uid and/or gid. + * + * in : inode (unlocked) + * out : udquot, gdquot with references taken and unlocked + */ +int +xfs_qm_vop_dqalloc( + xfs_mount_t *mp, + xfs_inode_t *ip, + uid_t uid, + gid_t gid, + uint flags, + xfs_dquot_t **O_udqpp, + xfs_dquot_t **O_gdqpp) +{ + int error; + xfs_dquot_t *uq, *gq; + uint lockflags; + + lockflags = XFS_ILOCK_EXCL; + xfs_ilock(ip, lockflags); + + if ((flags & XFS_QMOPT_INHERIT) && + XFS_INHERIT_GID(ip, XFS_MTOVFS(mp))) + gid = ip->i_d.di_gid; + + /* + * Attach the dquot(s) to this inode, doing a dquot allocation + * if necessary. The dquot(s) will not be locked. + */ + if (XFS_NOT_DQATTACHED(mp, ip)) { + if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_DQALLOC | + XFS_QMOPT_ILOCKED))) { + xfs_iunlock(ip, lockflags); + return (error); + } + } + + uq = gq = NULL; + if ((flags & XFS_QMOPT_UQUOTA) && + XFS_IS_UQUOTA_ON(mp)) { + if (ip->i_d.di_uid != uid) { + /* + * What we need is the dquot that has this uid, and + * if we send the inode to dqget, the uid of the inode + * takes priority over what's sent in the uid argument. + * We must unlock inode here before calling dqget if + * we're not sending the inode, because otherwise + * we'll deadlock by doing trans_reserve while + * holding ilock. + */ + xfs_iunlock(ip, lockflags); + if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t) uid, + XFS_DQ_USER, + XFS_QMOPT_DQALLOC | + XFS_QMOPT_DOWARN, + &uq))) { + ASSERT(error != ENOENT); + return (error); + } + /* + * Get the ilock in the right order. + */ + xfs_dqunlock(uq); + lockflags = XFS_ILOCK_SHARED; + xfs_ilock(ip, lockflags); + } else { + /* + * Take an extra reference, because we'll return + * this to caller + */ + ASSERT(ip->i_udquot); + uq = ip->i_udquot; + xfs_dqlock(uq); + XFS_DQHOLD(uq); + xfs_dqunlock(uq); + } + } + if ((flags & XFS_QMOPT_GQUOTA) && + XFS_IS_GQUOTA_ON(mp)) { + if (ip->i_d.di_gid != gid) { + xfs_iunlock(ip, lockflags); + if ((error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid, + XFS_DQ_GROUP, + XFS_QMOPT_DQALLOC | + XFS_QMOPT_DOWARN, + &gq))) { + if (uq) + xfs_qm_dqrele(uq); + ASSERT(error != ENOENT); + return (error); + } + xfs_dqunlock(gq); + lockflags = XFS_ILOCK_SHARED; + xfs_ilock(ip, lockflags); + } else { + ASSERT(ip->i_gdquot); + gq = ip->i_gdquot; + xfs_dqlock(gq); + XFS_DQHOLD(gq); + xfs_dqunlock(gq); + } + } + if (uq) + xfs_dqtrace_entry_ino(uq, "DQALLOC", ip); + + xfs_iunlock(ip, lockflags); + if (O_udqpp) + *O_udqpp = uq; + else if (uq) + xfs_qm_dqrele(uq); + if (O_gdqpp) + *O_gdqpp = gq; + else if (gq) + xfs_qm_dqrele(gq); + return (0); +} + +/* + * Actually transfer ownership, and do dquot modifications. + * These were already reserved. + */ +xfs_dquot_t * +xfs_qm_vop_chown( + xfs_trans_t *tp, + xfs_inode_t *ip, + xfs_dquot_t **IO_olddq, + xfs_dquot_t *newdq) +{ + xfs_dquot_t *prevdq; + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount)); + + /* old dquot */ + prevdq = *IO_olddq; + ASSERT(prevdq); + ASSERT(prevdq != newdq); + + xfs_trans_mod_dquot(tp, prevdq, + XFS_TRANS_DQ_BCOUNT, + -(ip->i_d.di_nblocks)); + xfs_trans_mod_dquot(tp, prevdq, + XFS_TRANS_DQ_ICOUNT, + -1); + + /* the sparkling new dquot */ + xfs_trans_mod_dquot(tp, newdq, + XFS_TRANS_DQ_BCOUNT, + ip->i_d.di_nblocks); + xfs_trans_mod_dquot(tp, newdq, + XFS_TRANS_DQ_ICOUNT, + 1); + + /* + * Take an extra reference, because the inode + * is going to keep this dquot pointer even + * after the trans_commit. + */ + xfs_dqlock(newdq); + XFS_DQHOLD(newdq); + xfs_dqunlock(newdq); + *IO_olddq = newdq; + + return (prevdq); +} + +/* + * Quota reservations for setattr(AT_UID|AT_GID). + */ +int +xfs_qm_vop_chown_reserve( + xfs_trans_t *tp, + xfs_inode_t *ip, + xfs_dquot_t *udqp, + xfs_dquot_t *gdqp, + uint privileged) +{ + int error; + xfs_mount_t *mp; + uint delblks; + xfs_dquot_t *unresudq, *unresgdq, *delblksudq, *delblksgdq; + + ASSERT(XFS_ISLOCKED_INODE(ip)); + mp = ip->i_mount; + ASSERT(XFS_IS_QUOTA_RUNNING(mp)); + + delblks = ip->i_delayed_blks; + delblksudq = delblksgdq = unresudq = unresgdq = NULL; + + if (XFS_IS_UQUOTA_ON(mp) && udqp && + ip->i_d.di_uid != (uid_t)INT_GET(udqp->q_core.d_id, ARCH_CONVERT)) { + delblksudq = udqp; + /* + * If there are delayed allocation blocks, then we have to + * unreserve those from the old dquot, and add them to the + * new dquot. + */ + if (delblks) { + ASSERT(ip->i_udquot); + unresudq = ip->i_udquot; + } + } + if (XFS_IS_GQUOTA_ON(ip->i_mount) && gdqp && + ip->i_d.di_gid != INT_GET(gdqp->q_core.d_id, ARCH_CONVERT)) { + delblksgdq = gdqp; + if (delblks) { + ASSERT(ip->i_gdquot); + unresgdq = ip->i_gdquot; + } + } + + if ((error = xfs_trans_reserve_quota(tp, delblksudq, + delblksgdq, + ip->i_d.di_nblocks, 1, + privileged))) + return (error); + + + /* + * Do the delayed blks reservations/unreservations now. Since, these + * are done without the help of a transaction, if a reservation fails + * its previous reservations won't be automatically undone by trans + * code. So, we have to do it manually here. + */ + if (delblks) { + /* + * Do the reservations first. Unreservation can't fail. + */ + ASSERT(delblksudq || delblksgdq); + ASSERT(unresudq || unresgdq); + if ((error = xfs_trans_reserve_quota(NULL, + delblksudq, delblksgdq, + (xfs_qcnt_t)delblks, 0, + privileged))) + return (error); + (void) xfs_trans_unreserve_quota(NULL, + unresudq, unresgdq, + (xfs_qcnt_t)delblks, 0, + 0); + } + + return (0); +} + +int +xfs_qm_vop_rename_dqattach( + xfs_inode_t **i_tab) +{ + xfs_inode_t *ip; + int i; + int error; + + ip = i_tab[0]; + + if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) { + error = xfs_qm_dqattach(ip, 0); + if (error) + return (error); + } + for (i = 1; (i < 4 && i_tab[i]); i++) { + /* + * Watch out for duplicate entries in the table. + */ + if ((ip = i_tab[i]) != i_tab[i-1]) { + if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) { + error = xfs_qm_dqattach(ip, 0); + if (error) + return (error); + } + } + } + return (0); +} + +void +xfs_qm_vop_dqattach_and_dqmod_newinode( + xfs_trans_t *tp, + xfs_inode_t *ip, + xfs_dquot_t *udqp, + xfs_dquot_t *gdqp) +{ + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + ASSERT(XFS_IS_QUOTA_RUNNING(tp->t_mountp)); + + if (udqp) { + xfs_dqlock(udqp); + XFS_DQHOLD(udqp); + xfs_dqunlock(udqp); + ASSERT(ip->i_udquot == NULL); + ip->i_udquot = udqp; + ASSERT(ip->i_d.di_uid == INT_GET(udqp->q_core.d_id, ARCH_CONVERT)); + xfs_trans_mod_dquot(tp, udqp, XFS_TRANS_DQ_ICOUNT, 1); + } + if (gdqp) { + xfs_dqlock(gdqp); + XFS_DQHOLD(gdqp); + xfs_dqunlock(gdqp); + ASSERT(ip->i_gdquot == NULL); + ip->i_gdquot = gdqp; + ASSERT(ip->i_d.di_gid == INT_GET(gdqp->q_core.d_id, ARCH_CONVERT)); + xfs_trans_mod_dquot(tp, gdqp, XFS_TRANS_DQ_ICOUNT, 1); + } +} + +/* ------------- list stuff -----------------*/ +void +xfs_qm_freelist_init(xfs_frlist_t *ql) +{ + ql->qh_next = ql->qh_prev = (xfs_dquot_t *) ql; + mutex_init(&ql->qh_lock, MUTEX_DEFAULT, "dqf"); + ql->qh_version = 0; + ql->qh_nelems = 0; +} + +void +xfs_qm_freelist_destroy(xfs_frlist_t *ql) +{ + xfs_dquot_t *dqp, *nextdqp; + + mutex_lock(&ql->qh_lock, PINOD); + for (dqp = ql->qh_next; + dqp != (xfs_dquot_t *)ql; ) { + xfs_dqlock(dqp); + nextdqp = dqp->dq_flnext; +#ifdef QUOTADEBUG + printk("FREELIST destroy 0x%p\n", dqp); +#endif + XQM_FREELIST_REMOVE(dqp); + xfs_dqunlock(dqp); + xfs_qm_dqdestroy(dqp); + dqp = nextdqp; + } + /* + * Don't bother about unlocking. + */ + mutex_destroy(&ql->qh_lock); + + ASSERT(ql->qh_nelems == 0); +} + +void +xfs_qm_freelist_insert(xfs_frlist_t *ql, xfs_dquot_t *dq) +{ + dq->dq_flnext = ql->qh_next; + dq->dq_flprev = (xfs_dquot_t *)ql; + ql->qh_next = dq; + dq->dq_flnext->dq_flprev = dq; + xfs_Gqm->qm_dqfreelist.qh_nelems++; + xfs_Gqm->qm_dqfreelist.qh_version++; +} + +void +xfs_qm_freelist_unlink(xfs_dquot_t *dq) +{ + xfs_dquot_t *next = dq->dq_flnext; + xfs_dquot_t *prev = dq->dq_flprev; + + next->dq_flprev = prev; + prev->dq_flnext = next; + dq->dq_flnext = dq->dq_flprev = dq; + xfs_Gqm->qm_dqfreelist.qh_nelems--; + xfs_Gqm->qm_dqfreelist.qh_version++; +} + +#ifdef QUOTADEBUG +void +xfs_qm_freelist_print(xfs_frlist_t *qlist, char *title) +{ + xfs_dquot_t *dq; + int i = 0; + printk("%s (#%d)\n", title, (int) qlist->qh_nelems); + FOREACH_DQUOT_IN_FREELIST(dq, qlist) { + printk("\t%d.\t\"%d (%s:0x%p)\"\t bcnt = %d, icnt = %d " + "refs = %d\n", + ++i, INT_GET(dq->q_core.d_id, ARCH_CONVERT), + DQFLAGTO_TYPESTR(dq), dq, + (int) INT_GET(dq->q_core.d_bcount, ARCH_CONVERT), + (int) INT_GET(dq->q_core.d_icount, ARCH_CONVERT), + (int) dq->q_nrefs); + } +} +#endif + +void +xfs_qm_freelist_append(xfs_frlist_t *ql, xfs_dquot_t *dq) +{ + xfs_qm_freelist_insert((xfs_frlist_t *)ql->qh_prev, dq); +} + +int +xfs_qm_dqhashlock_nowait( + xfs_dquot_t *dqp) +{ + int locked; + + locked = mutex_trylock(&((dqp)->q_hash->qh_lock)); + return (locked); +} + +int +xfs_qm_freelist_lock_nowait( + xfs_qm_t *xqm) +{ + int locked; + + locked = mutex_trylock(&(xqm->qm_dqfreelist.qh_lock)); + return (locked); +} + +int +xfs_qm_mplist_nowait( + xfs_mount_t *mp) +{ + int locked; + + ASSERT(mp->m_quotainfo); + locked = mutex_trylock(&(XFS_QI_MPLLOCK(mp))); + return (locked); +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_qm.h linux-2.4-xfs/linux/fs/xfs/xfs_qm.h --- linux-2.4.7/linux/fs/xfs/xfs_qm.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_qm.h Mon Apr 2 21:52:38 2001 @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_QM_H__ +#define __XFS_QM_H__ + +struct xfs_dqhash; +struct xfs_inode; +struct xfs_dquot; +struct xfs_qm; + +/* + * The global quota manager. There is only one of these for the entire + * system, _not_ one per file system. XQM keeps track of the overall + * quota functionality, including maintaining the freelist and hash + * tables of dquots. + */ +extern struct xfs_qm *xfs_Gqm; + +/* + * Used in xfs_qm_sync called by xfs_sync to count the max times that it can + * iterate over the mountpt's dquot list in one call. + */ +#define XFS_QM_SYNC_MAX_RESTARTS 7 + +/* + * Ditto, for xfs_qm_dqreclaim_one. + */ +#define XFS_QM_RECLAIM_MAX_RESTARTS 4 + +/* + * Ideal ratio of free to in use dquots. Quota manager makes an attempt + * to keep this balance. + */ +#define XFS_QM_DQFREE_RATIO 2 + +/* + * Dquot hashtable constants/threshold values. + */ +#define XFS_QM_NCSIZE_THRESHOLD 5000 +#define XFS_QM_HASHSIZE_LOW 32 +#define XFS_QM_HASHSIZE_HIGH 64 + +/* + * We output a cmn_err when quotachecking a quota file with more than + * this many fsbs. + */ +#define XFS_QM_BIG_QCHECK_NBLKS 500 + +/* + * This defines the unit of allocation of dquots. + * Currently, it is just one file system block, and a 4K blk contains 30 + * (136 * 30 = 4080) dquots. It's probably not worth trying to make + * this more dynamic. + * XXXsup However, if this number is changed, we have to make sure that we don't + * implicitly assume that we do allocations in chunks of a single filesystem + * block in the dquot/xqm code. + */ +#define XFS_DQUOT_CLUSTER_SIZE_FSB (xfs_filblks_t)1 +/* + * When doing a quotacheck, we log dquot clusters of this many FSBs at most + * in a single transaction. We don't want to ask for too huge a log reservation. + */ +#define XFS_QM_MAX_DQCLUSTER_LOGSZ 3 + +typedef xfs_dqhash_t xfs_dqlist_t; +/* + * The freelist head. The first two fields match the first two in the + * xfs_dquot_t structure (in xfs_dqmarker_t) + */ +typedef struct xfs_frlist { + struct xfs_dquot *qh_next; + struct xfs_dquot *qh_prev; + mutex_t qh_lock; + uint qh_version; + uint qh_nelems; +} xfs_frlist_t; + +/* + * Quota Manager (global) structure. Lives only in core. + */ +typedef struct xfs_qm { + xfs_dqlist_t *qm_usr_dqhtable;/* udquot hash table */ + xfs_dqlist_t *qm_grp_dqhtable;/* gdquot hash table */ + uint qm_dqhashmask; /* # buckets in dq hashtab - 1 */ + xfs_frlist_t qm_dqfreelist; /* freelist of dquots */ + atomic_t qm_totaldquots; /* total incore dquots */ + uint qm_nrefs; /* file systems with quota on */ + int qm_dqfree_ratio;/* ratio of free to inuse dquots */ + xfs_zone_t *qm_dqzone; /* dquot mem-alloc zone */ + xfs_zone_t *qm_dqtrxzone; /* t_dqinfo of transactions */ +} xfs_qm_t; + +/* + * Various quota information for individual filesystems. + * The mount structure keeps a pointer to this. + */ +typedef struct xfs_quotainfo { + xfs_inode_t *qi_uquotaip; /* user quota inode */ + xfs_inode_t *qi_gquotaip; /* group quota inode */ + lock_t qi_pinlock; /* dquot pinning mutex */ + xfs_dqlist_t qi_dqlist; /* all dquots in filesys */ + int qi_dqreclaims; /* a change here indicates + a removal in the dqlist */ + time_t qi_btimelimit; /* limit for blks timer */ + time_t qi_itimelimit; /* limit for inodes timer */ + time_t qi_rtbtimelimit;/* limit for rt blks timer */ + xfs_qwarncnt_t qi_bwarnlimit; /* limit for num warnings */ + xfs_qwarncnt_t qi_iwarnlimit; /* limit for num warnings */ + mutex_t qi_quotaofflock;/* to serialize quotaoff */ + /* Some useful precalculated constants */ + xfs_filblks_t qi_dqchunklen; /* # BBs in a chunk of dqs */ + uint qi_dqperchunk; /* # ondisk dqs in above chunk */ +} xfs_quotainfo_t; + + +/* + * The structure kept inside the xfs_trans_t keep track of dquot changes + * within a transaction and apply them later. + */ +typedef struct xfs_dqtrx { + struct xfs_dquot *qt_dquot; /* the dquot this refers to */ + ulong qt_blk_res; /* blks reserved on a dquot */ + ulong qt_blk_res_used; /* blks used from the reservation */ + ulong qt_ino_res; /* inode reserved on a dquot */ + ulong qt_ino_res_used; /* inodes used from the reservation */ + long qt_bcount_delta; /* dquot blk count changes */ + long qt_delbcnt_delta; /* delayed dquot blk count changes */ + long qt_icount_delta; /* dquot inode count changes */ + ulong qt_rtblk_res; /* # blks reserved on a dquot */ + ulong qt_rtblk_res_used;/* # blks used from reservation */ + long qt_rtbcount_delta;/* dquot realtime blk changes */ + long qt_delrtb_delta; /* delayed RT blk count changes */ +} xfs_dqtrx_t; + +/* + * We keep the usr and grp dquots separately so that locking will be easier + * to do at commit time. All transactions that we know of at this point + * affect no more than two dquots of one type. Hence, the TRANS_MAXDQS value. + */ +#define XFS_QM_TRANS_MAXDQS 2 +typedef struct xfs_dquot_acct { + xfs_dqtrx_t dqa_usrdquots[XFS_QM_TRANS_MAXDQS]; + xfs_dqtrx_t dqa_grpdquots[XFS_QM_TRANS_MAXDQS]; +} xfs_dquot_acct_t; + +/* + * Users are allowed to have a usage exceeding their softlimit for + * a period this long. + */ +#define XFS_QM_BTIMELIMIT DQ_BTIMELIMIT +#define XFS_QM_RTBTIMELIMIT DQ_BTIMELIMIT +#define XFS_QM_ITIMELIMIT DQ_FTIMELIMIT + +#define XFS_QM_BWARNLIMIT 5 +#define XFS_QM_IWARNLIMIT 5 + +#define XFS_QM_LOCK(xqm) (mutex_lock(&xqm##_lock, PINOD)) +#define XFS_QM_UNLOCK(xqm) (mutex_unlock(&xqm##_lock)) +#define XFS_QM_HOLD(xqm) ((xqm)->qm_nrefs++) +#define XFS_QM_RELE(xqm) ((xqm)->qm_nrefs--) + +#ifdef DEBUG +extern int xfs_qm_internalqcheck(xfs_mount_t *); +#endif + +extern int xfs_qm_init_quotainfo(xfs_mount_t *); +extern void xfs_qm_destroy_quotainfo(xfs_mount_t *); +extern void xfs_qm_dqunlink(xfs_dquot_t *); +extern boolean_t xfs_qm_dqalloc_incore(xfs_dquot_t **); +extern int xfs_qm_write_sb_changes(xfs_mount_t *, __int64_t); +extern int xfs_qm_scall_quotaoff(xfs_mount_t *, uint, boolean_t); + +/* list stuff */ +extern void xfs_qm_freelist_init(xfs_frlist_t *); +extern void xfs_qm_freelist_destroy(xfs_frlist_t *); +extern void xfs_qm_freelist_insert(xfs_frlist_t *, xfs_dquot_t *); +extern void xfs_qm_freelist_append(xfs_frlist_t *, xfs_dquot_t *); +extern void xfs_qm_freelist_unlink(xfs_dquot_t *); +extern int xfs_qm_freelist_lock_nowait(xfs_qm_t *); +extern int xfs_qm_mplist_nowait(xfs_mount_t *); +extern int xfs_qm_dqhashlock_nowait(xfs_dquot_t *); + +#ifdef QUOTADEBUG +extern void xfs_qm_freelist_print(xfs_frlist_t *, char *); +#else +#define xfs_qm_freelist_print(a, b) +#endif + +#endif /* __XFS_QM_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_qm_syscalls.c linux-2.4-xfs/linux/fs/xfs/xfs_qm_syscalls.c --- linux-2.4.7/linux/fs/xfs/xfs_qm_syscalls.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_qm_syscalls.c Tue Apr 10 20:44:54 2001 @@ -0,0 +1,1481 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + + +STATIC int xfs_qm_scall_trunc_qfiles(xfs_mount_t *, uint); +STATIC int xfs_qm_scall_getquota(xfs_mount_t *, xfs_dqid_t, uint, xfs_caddr_t); +STATIC int xfs_qm_scall_getqstat(xfs_mount_t *, xfs_caddr_t); +STATIC int xfs_qm_scall_setqlim(xfs_mount_t *, xfs_dqid_t, uint, xfs_caddr_t); +STATIC int xfs_qm_scall_quotaon(xfs_mount_t *, uint); +STATIC int xfs_qm_scall_qwarn(xfs_mount_t *, xfs_dqid_t, xfs_caddr_t); +STATIC int xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint); +STATIC int xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *, + uint); +STATIC uint xfs_qm_import_flags(uint *); +STATIC uint xfs_qm_export_flags(uint); +STATIC uint xfs_qm_import_qtype_flags(uint *); +STATIC uint xfs_qm_export_qtype_flags(uint); +STATIC void xfs_qm_export_dquot(xfs_mount_t *, xfs_disk_dquot_t *, + struct fs_disk_quota *); + + +/* + * The main distribution switch of all XFS quotactl system calls. + */ +int +xfs_quotactl( + xfs_mount_t *mp, + struct vfs *vfsp, + int cmd, + int id, + int type, + xfs_caddr_t addr) +{ + +#ifdef QUOTADEBUG + static int count = 0; + if (count++ == 50) + return xfs_qm_internalqcheck(mp); +#endif + + if (addr == NULL && cmd != Q_XQUOTAOFF) + return XFS_ERROR(EINVAL); + + /* + * The following commands are valid even when quotaoff. + */ + switch (cmd) { + case Q_XQUOTARM: + /* truncate quota files. quota must be off. */ + if (XFS_IS_QUOTA_ON(mp)) + return XFS_ERROR(EINVAL); + if (vfsp->vfs_flag & VFS_RDONLY) + return XFS_ERROR(EROFS); + return xfs_qm_scall_trunc_qfiles(mp, + xfs_qm_import_qtype_flags((uint *)addr)); + + case Q_XGETQSTAT: + /* Get quota status information. */ + return xfs_qm_scall_getqstat(mp, addr); + + case Q_XQUOTAON: + /* + * QUOTAON for root f/s and quota enforcement on others.. + * Quota accounting for non-root f/s's must be turned on + * at mount time. + */ + if (vfsp->vfs_flag & VFS_RDONLY) + return XFS_ERROR(EROFS); + return xfs_qm_scall_quotaon(mp, + xfs_qm_import_flags((uint *)addr)); + + case Q_XQUOTAOFF: + if (vfsp->vfs_flag & VFS_RDONLY) + return XFS_ERROR(EROFS); + if (mp->m_dev == rootdev) + return xfs_qm_scall_quotaoff(mp, + xfs_qm_import_flags((uint *)addr), B_FALSE); + break; + } + + if (!XFS_IS_QUOTA_ON(mp)) + return XFS_ERROR(ESRCH); + + switch (cmd) { + case Q_XQUOTAOFF: + if (vfsp->vfs_flag & VFS_RDONLY) + return XFS_ERROR(EROFS); + return xfs_qm_scall_quotaoff(mp, + xfs_qm_import_flags((uint *)addr), B_FALSE); + + case Q_XGETQUOTA: + return xfs_qm_scall_getquota(mp, (xfs_dqid_t)id, type, addr); + + case Q_XSETQLIM: + /* Set limits, both hard and soft. */ + if (vfsp->vfs_flag & VFS_RDONLY) + return XFS_ERROR(EROFS); + return xfs_qm_scall_setqlim(mp, (xfs_dqid_t)id, type, addr); + } + return XFS_ERROR(EINVAL); +} + + +/* + * Turn off quota accounting and/or enforcement for all udquots and/or + * gdquots. Called only at unmount time. + * + * This assumes that there are no dquots of this file system cached + * incore, and modifies the ondisk dquot directly. Therefore, for example, + * it is an error to call this twice, without purging the cache. + */ +int +xfs_qm_scall_quotaoff( + xfs_mount_t *mp, + uint flags, + boolean_t force) +{ + uint dqtype; + int s; + int error; + uint inactivate_flags; + xfs_qoff_logitem_t *qoffstart; + uint sbflags, newflags; + int nculprits; + + if (!force && !capable(CAP_SYS_ADMIN)) + return XFS_ERROR(EPERM); + /* + * Only root file system can have quotas enabled on disk but not + * in core. Note that quota utilities (like quotaoff) _expect_ + * errno == EEXIST here. + */ + if (mp->m_dev != rootdev && (mp->m_qflags & flags) == 0) + return XFS_ERROR(EEXIST); + error = 0; + + flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD); + + /* + * We don't want to deal with two quotaoffs messing up each other, + * so we're going to serialize it. quotaoff isn't exactly a performance + * critical thing. + * If quotaoff, then we must be dealing with the root filesystem. + */ + ASSERT(mp->m_quotainfo || mp->m_dev == rootdev); + if (mp->m_quotainfo) + mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD); + + /* + * Root file system may or may not have quotas on in core. + * We have to perform the quotaoff accordingly. + */ + if (mp->m_dev == rootdev) { + s = XFS_SB_LOCK(mp); + sbflags = mp->m_sb.sb_qflags; + if ((mp->m_qflags & flags) == 0) { + mp->m_sb.sb_qflags &= ~(flags); + newflags = mp->m_sb.sb_qflags; + XFS_SB_UNLOCK(mp, s); + if (mp->m_quotainfo) + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + if (sbflags != newflags) + error = xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS); + return (error); + } + XFS_SB_UNLOCK(mp, s); + + if ((sbflags & flags) != (mp->m_qflags & flags)) { + /* + * This can happen only with grp+usr quota + * combination. Note: 1) accounting cannot be turned + * off without enforcement also getting turned off. + * 2) Every flag that exists in mpqflags MUST exist + * in sbqflags (but not vice versa). + * which means at this point sbqflags = UQ+GQ+.., + * and mpqflags = UQ or GQ. + */ + ASSERT(sbflags & XFS_GQUOTA_ACCT); + ASSERT((sbflags & XFS_ALL_QUOTA_ACCT) != + (mp->m_qflags & XFS_ALL_QUOTA_ACCT)); + + /* XXX TBD Finish this for group quota support */ + /* We need to update the SB and mp separately */ + return XFS_ERROR(EINVAL); + } + } + ASSERT(mp->m_quotainfo); + + /* + * if we're just turning off quota enforcement, change mp and go. + */ + if ((flags & XFS_ALL_QUOTA_ACCT) == 0) { + mp->m_qflags &= ~(flags); + + s = XFS_SB_LOCK(mp); + mp->m_sb.sb_qflags = mp->m_qflags; + XFS_SB_UNLOCK(mp, s); + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + + /* XXX what to do if error ? Revert back to old vals incore ? */ + error = xfs_qm_write_sb_changes(mp, XFS_SB_QFLAGS); + return (error); + } + + dqtype = 0; + inactivate_flags = 0; + /* + * If accounting is off, we must turn enforcement off, clear the + * quota 'CHKD' certificate to make it known that we have to + * do a quotacheck the next time this quota is turned on. + */ + if (flags & XFS_UQUOTA_ACCT) { + dqtype |= XFS_QMOPT_UQUOTA; + flags |= (XFS_UQUOTA_CHKD | XFS_UQUOTA_ENFD); + inactivate_flags |= XFS_UQUOTA_ACTIVE; + } + if (flags & XFS_GQUOTA_ACCT) { + dqtype |= XFS_QMOPT_GQUOTA; + flags |= (XFS_GQUOTA_CHKD | XFS_GQUOTA_ENFD); + inactivate_flags |= XFS_GQUOTA_ACTIVE; + } + + /* + * Nothing to do? Don't complain. + * This happens when we're just turning off quota enforcement. + */ + if ((mp->m_qflags & flags) == 0) { + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + return (0); + } + + /* + * Write the LI_QUOTAOFF log record, and do SB changes atomically, + * and synchronously. + */ + xfs_qm_log_quotaoff(mp, &qoffstart, flags); + + /* + * Next we clear the XFS_MOUNT_*DQ_ACTIVE bit(s) in the mount struct + * to take care of the race between dqget and quotaoff. We don't take + * any special locks to reset these bits. All processes need to check + * these bits *after* taking inode lock(s) to see if the particular + * quota type is in the process of being turned off. If *ACTIVE, it is + * guaranteed that all dquot structures and all quotainode ptrs will all + * stay valid as long as that inode is kept locked. + * + * There is no turning back after this. + */ + mp->m_qflags &= ~inactivate_flags; + + /* + * Give back all the dquot reference(s) held by inodes. + * Here we go thru every single incore inode in this file system, and + * do a dqrele on the i_udquot/i_gdquot that it may have. + * Essentially, as long as somebody has an inode locked, this guarantees + * that quotas will not be turned off. This is handy because in a + * transaction once we lock the inode(s) and check for quotaon, we can + * depend on the quota inodes (and other things) being valid as long as + * we keep the lock(s). + */ + xfs_qm_dqrele_all_inodes(mp, flags); + + /* + * Next we make the changes in the quota flag in the mount struct. + * This isn't protected by a particular lock directly, because we + * don't want to take a mrlock everytime we depend on quotas being on. + */ + mp->m_qflags &= ~(flags); + + /* + * Go through all the dquots of this file system and purge them, + * according to what was turned off. We may not be able to get rid + * of all dquots, because dquots can have temporary references that + * are not attached to inodes. eg. xfs_setattr, xfs_create. + * So, if we couldn't purge all the dquots from the filesystem, + * we can't get rid of the incore data structures. + */ + while ((nculprits = xfs_qm_dqpurge_all(mp, dqtype|XFS_QMOPT_QUOTAOFF))) { + delay(10 * nculprits); + } + + /* + * Transactions that had started before ACTIVE state bit was cleared + * could have logged many dquots, so they'd have higher LSNs than + * the first QUOTAOFF log record does. If we happen to crash when + * the tail of the log has gone past the QUOTAOFF record, but + * before the last dquot modification, those dquots __will__ + * recover, and that's not good. + * + * So, we have QUOTAOFF start and end logitems; the start + * logitem won't get overwritten until the end logitem appears... + */ + xfs_qm_log_quotaoff_end(mp, qoffstart, flags); + + /* + * If quotas is completely disabled, close shop. + */ + if ((flags & XFS_MOUNT_QUOTA_ALL) == XFS_MOUNT_QUOTA_ALL) { + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + xfs_qm_destroy_quotainfo(mp); + return (0); + } + + /* + * Release our quotainode references, and vn_purge them, + * if we don't need them anymore. + */ + if ((dqtype & XFS_QMOPT_UQUOTA) && XFS_QI_UQIP(mp)) { + XFS_PURGE_INODE(XFS_QI_UQIP(mp)); + XFS_QI_UQIP(mp) = NULL; + } + if ((dqtype & XFS_QMOPT_GQUOTA) && XFS_QI_GQIP(mp)) { + XFS_PURGE_INODE(XFS_QI_GQIP(mp)); + XFS_QI_GQIP(mp) = NULL; + } + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + + return (error); +} + +STATIC int +xfs_qm_scall_trunc_qfiles( + xfs_mount_t *mp, + uint flags) +{ + int error; + xfs_inode_t *qip; + + if (!capable(CAP_SYS_ADMIN)) + return XFS_ERROR(EPERM); + error = 0; + if (!XFS_SB_VERSION_HASQUOTA(&mp->m_sb) || flags == 0) + return XFS_ERROR(EINVAL); + + if ((flags & XFS_DQ_USER) && mp->m_sb.sb_uquotino != NULLFSINO) { + error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &qip, 0); + if (! error) { + (void) xfs_truncate_file(mp, qip); + VN_RELE(XFS_ITOV(qip)); + } + } + + if ((flags & XFS_DQ_GROUP) && mp->m_sb.sb_gquotino != NULLFSINO) { + error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &qip, 0); + if (! error) { + (void) xfs_truncate_file(mp, qip); + VN_RELE(XFS_ITOV(qip)); + } + } + + return (error); +} + + +/* + * This does two separate functions: + * Switch on quotas for the root file system. This will take effect only + * on reboot. + * Switch on (a given) quota enforcement for both root and non-root filesystems. + * This takes effect immediately. + */ +STATIC int +xfs_qm_scall_quotaon( + xfs_mount_t *mp, + uint flags) +{ + int error, s; + uint qf; + uint accflags; + __int64_t sbflags; + boolean_t rootfs; + boolean_t delay; + + if (!capable(CAP_SYS_ADMIN)) + return XFS_ERROR(EPERM); + + rootfs = (boolean_t) (mp->m_dev == rootdev); + + flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD); + /* + * If caller wants to turn on accounting on /, but accounting + * is already turned on, ignore ACCTing flags. + * Switching on quota accounting for non-root filesystems + * must be done at mount time. + */ + accflags = flags & XFS_ALL_QUOTA_ACCT; + if (!rootfs || + (accflags && rootfs && ((mp->m_qflags & accflags) == accflags))) { + flags &= ~(XFS_ALL_QUOTA_ACCT); + } + + sbflags = 0; + delay = (boolean_t) ((flags & XFS_ALL_QUOTA_ACCT) != 0); + + if (flags == 0) + return XFS_ERROR(EINVAL); + + /* Only rootfs can turn on quotas with a delayed effect */ + ASSERT(!delay || rootfs); + + /* + * Can't enforce without accounting. We check the superblock + * qflags here instead of m_qflags because rootfs can have + * quota acct on ondisk without m_qflags' knowing. + */ + if (((flags & XFS_UQUOTA_ACCT) == 0 && + (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 && + (flags & XFS_UQUOTA_ENFD)) + || + ((flags & XFS_GQUOTA_ACCT) == 0 && + (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 && + (flags & XFS_GQUOTA_ENFD))) { +#ifdef QUOTADEBUG + printk("Can't enforce without accounting.\n"); +#endif + return XFS_ERROR(EINVAL); + } + /* + * If everything's upto-date incore, then don't waste time. + */ + if ((mp->m_qflags & flags) == flags) + return XFS_ERROR(EEXIST); + + /* + * Change superblock version (if needed) for the root filesystem + */ + if (rootfs && !XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) { +#ifdef DEBUG + unsigned oldv = mp->m_sb.sb_versionnum; +#endif + s = XFS_SB_LOCK(mp); + XFS_SB_VERSION_ADDQUOTA(&mp->m_sb); + mp->m_sb.sb_uquotino = NULLFSINO; + mp->m_sb.sb_gquotino = NULLFSINO; + mp->m_sb.sb_qflags = 0; + XFS_SB_UNLOCK(mp, s); +#ifdef DEBUG + printk(KERN_INFO + "Old superblock version %x, converting to %x.", + oldv, mp->m_sb.sb_versionnum); +#endif + sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | + XFS_SB_GQUOTINO | XFS_SB_QFLAGS); + } + + /* + * Change sb_qflags on disk but not incore mp->qflags + * if this is the root filesystem. + */ + s = XFS_SB_LOCK(mp); + qf = mp->m_sb.sb_qflags; + mp->m_sb.sb_qflags = qf | flags; + XFS_SB_UNLOCK(mp, s); + + /* + * There's nothing to change if it's the same. + */ + if ((qf & flags) == flags && sbflags == 0) + return XFS_ERROR(EEXIST); + sbflags |= XFS_SB_QFLAGS; + + if ((error = xfs_qm_write_sb_changes(mp, sbflags))) + return (error); + /* + * If we had just turned on quotas (ondisk) for rootfs, or if we aren't + * trying to switch on quota enforcement, we are done. + */ + if (delay || + ((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) != + (mp->m_qflags & XFS_UQUOTA_ACCT)) || + (flags & XFS_ALL_QUOTA_ENFD) == 0) + return (0); + + if (! XFS_IS_QUOTA_RUNNING(mp)) + return XFS_ERROR(ESRCH); + + /* + * Switch on quota enforcement in core. This applies to both root + * and non-root file systems. + */ + mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD); + mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD); + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + + return (0); +} + + + +/* + * Return quota status information, such as uquota-off, enforcements, etc. + */ +STATIC int +xfs_qm_scall_getqstat( + xfs_mount_t *mp, + xfs_caddr_t addr) +{ + fs_quota_stat_t out; + xfs_inode_t *uip, *gip; + boolean_t tempuqip, tempgqip; + __uint16_t sbflags; + + uip = gip = NULL; + tempuqip = tempgqip = B_FALSE; + bzero(&out, sizeof(fs_quota_stat_t)); + + out.qs_version = FS_QSTAT_VERSION; + if (! XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) { + out.qs_uquota.qfs_ino = NULLFSINO; + out.qs_gquota.qfs_ino = NULLFSINO; + goto done; + } + out.qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags & + (XFS_ALL_QUOTA_ACCT| + XFS_ALL_QUOTA_ENFD)); + /* + * If the qflags are different on disk, as can be the case when + * root filesystem's quotas are being turned on, return them in the + * HI 8 bits. + */ + if (mp->m_dev == rootdev) { + sbflags = (__uint16_t) xfs_qm_export_flags(mp->m_sb.sb_qflags & + (XFS_ALL_QUOTA_ACCT| + XFS_ALL_QUOTA_ENFD)); + ASSERT((out.qs_flags & 0xff00) == 0); + if (sbflags != out.qs_flags) + out.qs_flags |= ((sbflags & 0x00ff) << 8); + } + + out.qs_pad = 0; + out.qs_uquota.qfs_ino = mp->m_sb.sb_uquotino; + out.qs_gquota.qfs_ino = mp->m_sb.sb_gquotino; + if (mp->m_quotainfo) { + uip = mp->m_quotainfo->qi_uquotaip; + gip = mp->m_quotainfo->qi_gquotaip; + } + if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) { + if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &uip, 0) == 0) + tempuqip = B_TRUE; + } + if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) { + if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &gip, 0) == 0) + tempgqip = B_TRUE; + } + if (uip) { + out.qs_uquota.qfs_nblks = uip->i_d.di_nblocks; + out.qs_uquota.qfs_nextents = uip->i_d.di_nextents; + if (tempuqip) + VN_RELE(XFS_ITOV(uip)); + } + if (gip) { + out.qs_gquota.qfs_nblks = gip->i_d.di_nblocks; + out.qs_gquota.qfs_nextents = gip->i_d.di_nextents; + if (tempgqip) + VN_RELE(XFS_ITOV(gip)); + } + if (mp->m_quotainfo) { + out.qs_incoredqs = XFS_QI_MPLNDQUOTS(mp); + out.qs_btimelimit = XFS_QI_BTIMELIMIT(mp); + out.qs_itimelimit = XFS_QI_ITIMELIMIT(mp); + out.qs_rtbtimelimit = XFS_QI_RTBTIMELIMIT(mp); + out.qs_bwarnlimit = XFS_QI_BWARNLIMIT(mp); + out.qs_iwarnlimit = XFS_QI_IWARNLIMIT(mp); + } + done: + if (copyout(&out, addr, sizeof(fs_quota_stat_t))) + return XFS_ERROR(EFAULT); + return (0); +} + +/* + * Adjust quota limits, and start/stop timers accordingly. + */ +STATIC int +xfs_qm_scall_setqlim( + xfs_mount_t *mp, + xfs_dqid_t id, + uint type, + xfs_caddr_t addr) +{ + xfs_disk_dquot_t *ddq; + fs_disk_quota_t newlim; + xfs_dquot_t *dqp; + xfs_trans_t *tp; + int error; + xfs_qcnt_t hard, soft; + + if (!capable(CAP_SYS_ADMIN)) + return XFS_ERROR(EPERM); + if (copyin(addr, &newlim, sizeof newlim)) + return XFS_ERROR(EFAULT); + + if ((newlim.d_fieldmask & (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK)) == 0) + return (0); + + tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM); + if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_disk_dquot_t) + 128, + 0, 0, XFS_DEFAULT_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + return (error); + } + + /* + * We don't want to race with a quotaoff so take the quotaoff lock. + * (We don't hold an inode lock, so there's nothing else to stop + * a quotaoff from happening). (XXXThis doesn't currently happen + * because we take the vfslock before calling xfs_qm_sysent). + */ + mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD); + + /* + * Get the dquot (locked), and join it to the transaction. + * Allocate the dquot if this doesn't exist. + */ + if ((error = xfs_qm_dqget(mp, NULL, id, type, XFS_QMOPT_DQALLOC, &dqp))) { + xfs_trans_cancel(tp, XFS_TRANS_ABORT); + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + ASSERT(error != ENOENT); + return (error); + } + xfs_dqtrace_entry(dqp, "Q_SETQLIM: AFT DQGET"); + xfs_trans_dqjoin(tp, dqp); + ddq = &dqp->q_core; + + /* + * Make sure that hardlimits are >= soft limits before changing. + */ + hard = (newlim.d_fieldmask & FS_DQ_BHARD) ? + (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim.d_blk_hardlimit) : + INT_GET(ddq->d_blk_hardlimit, ARCH_CONVERT); + soft = (newlim.d_fieldmask & FS_DQ_BSOFT) ? + (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim.d_blk_softlimit) : + INT_GET(ddq->d_blk_softlimit, ARCH_CONVERT); + if (hard == 0 || hard >= soft) { + INT_SET(ddq->d_blk_hardlimit, ARCH_CONVERT, hard); + INT_SET(ddq->d_blk_softlimit, ARCH_CONVERT, soft); + } +#ifdef QUOTADEBUG + else + printk("blkhard %Ld < blksoft %Ld\n", hard, soft); +#endif + hard = (newlim.d_fieldmask & FS_DQ_RTBHARD) ? + (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim.d_rtb_hardlimit) : + INT_GET(ddq->d_rtb_hardlimit, ARCH_CONVERT); + soft = (newlim.d_fieldmask & FS_DQ_RTBSOFT) ? + (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim.d_rtb_softlimit) : + INT_GET(ddq->d_rtb_softlimit, ARCH_CONVERT); + if (hard == 0 || hard >= soft) { + INT_SET(ddq->d_rtb_hardlimit, ARCH_CONVERT, hard); + INT_SET(ddq->d_rtb_softlimit, ARCH_CONVERT, soft); + } +#ifdef QUOTADEBUG + else + printk("rtbhard %Ld < rtbsoft %Ld\n", hard, soft); +#endif + + hard = (newlim.d_fieldmask & FS_DQ_IHARD) ? + (xfs_qcnt_t) newlim.d_ino_hardlimit : INT_GET(ddq->d_ino_hardlimit, ARCH_CONVERT); + soft = (newlim.d_fieldmask & FS_DQ_ISOFT) ? + (xfs_qcnt_t) newlim.d_ino_softlimit : INT_GET(ddq->d_ino_softlimit, ARCH_CONVERT); + if (hard == 0 || hard >= soft) { + INT_SET(ddq->d_ino_hardlimit, ARCH_CONVERT, hard); + INT_SET(ddq->d_ino_softlimit, ARCH_CONVERT, soft); + } +#ifdef QUOTADEBUG + else + printk("ihard %Ld < isoft %Ld\n", hard, soft); +#endif + if (id == 0) { + /* + * Timelimits for the super user set the relative time + * the other users can be over quota for this file system. + * If it is zero a default is used. + */ + if (newlim.d_fieldmask & FS_DQ_BTIMER) { + mp->m_quotainfo->qi_btimelimit = newlim.d_btimer; + INT_SET(dqp->q_core.d_btimer, ARCH_CONVERT, newlim.d_btimer); + } + if (newlim.d_fieldmask & FS_DQ_ITIMER) { + mp->m_quotainfo->qi_itimelimit = newlim.d_itimer; + INT_SET(dqp->q_core.d_itimer, ARCH_CONVERT, newlim.d_itimer); + } + if (newlim.d_fieldmask & FS_DQ_RTBTIMER) { + mp->m_quotainfo->qi_rtbtimelimit = newlim.d_rtbtimer; + INT_SET(dqp->q_core.d_rtbtimer, ARCH_CONVERT, newlim.d_rtbtimer); + } +#ifdef NOTYET + /* + * Ditto, for warning limits. + * XXXthese aren't quite in use yet. + */ + if (newlim.d_bwarns > 0) { + mp->m_quotainfo->qi_bwarnlimit = newlim.d_bwarns; + INT_SET(dqp->q_core.d_bwarns, ARCH_CONVERT, newlim.d_bwarns); + } + if (newlim.d_iwarns > 0) { + mp->m_quotainfo->qi_iwarnlimit = newlim.d_iwarns; + INT_SET(dqp->q_core.d_iwarns, ARCH_CONVERT, newlim.d_iwarns); + } + if (newlim.d_rtbwarns > 0) { + INT_SET(dqp->q_core.d_rtbwarns, ARCH_CONVERT, newlim.d_rtbwarns); + } +#endif + } else /* if (XFS_IS_QUOTA_ENFORCED(mp)) */ { + /* + * If the user is now over quota, start the timelimit. + * The user will not be 'warned'. + * Note that we keep the timers ticking, whether enforcement + * is on or off. We don't really want to bother with iterating + * over all ondisk dquots and turning the timers on/off. + */ + xfs_qm_adjust_dqtimers(mp, ddq); + } + dqp->dq_flags |= XFS_DQ_DIRTY; + xfs_trans_log_dquot(tp, dqp); + + xfs_dqtrace_entry(dqp, "Q_SETQLIM: COMMIT"); + xfs_trans_commit(tp, 0, NULL); + xfs_qm_dqprint(dqp); + xfs_qm_dqrele(dqp); + mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); + + return (0); +} + +STATIC int +xfs_qm_scall_getquota( + xfs_mount_t *mp, + xfs_dqid_t id, + uint type, + xfs_caddr_t addr) +{ + xfs_dquot_t *dqp; + fs_disk_quota_t out; + int error; + + /* + * Try to get the dquot. We don't want it allocated on disk, so + * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't + * exist, we'll get ENOENT back. + */ + if ((error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp))) { + return (error); + } + + xfs_dqtrace_entry(dqp, "Q_GETQUOTA SUCCESS"); + /* + * If everything's NULL, this dquot doesn't quite exist as far as + * our utility programs are concerned. + */ + if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) { + xfs_qm_dqput(dqp); + return XFS_ERROR(ENOENT); + } + /* xfs_qm_dqprint(dqp); */ + /* + * Convert the disk dquot to the exportable format + */ + xfs_qm_export_dquot(mp, &dqp->q_core, &out); + error = copyout(&out, addr, sizeof(out)); + xfs_qm_dqput(dqp); + return (error ? XFS_ERROR(EFAULT) : 0); +} + + +STATIC int +xfs_qm_log_quotaoff_end( + xfs_mount_t *mp, + xfs_qoff_logitem_t *startqoff, + uint flags) +{ + xfs_trans_t *tp; + int error; + xfs_qoff_logitem_t *qoffi; + + tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END); + + if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_qoff_logitem_t) * 2, + 0, 0, XFS_DEFAULT_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + return (error); + } + + qoffi = xfs_trans_get_qoff_item(tp, startqoff, + flags & XFS_ALL_QUOTA_ACCT); + xfs_trans_log_quotaoff_item(tp, qoffi); + + /* + * We have to make sure that the transaction is secure on disk before we + * return and actually stop quota accounting. So, make it synchronous. + * We don't care about quotoff's performance. + */ + xfs_trans_set_sync(tp); + error = xfs_trans_commit(tp, 0, NULL); + return (error); +} + + +STATIC int +xfs_qm_log_quotaoff( + xfs_mount_t *mp, + xfs_qoff_logitem_t **qoffstartp, + uint flags) +{ + xfs_trans_t *tp; + int error, s; + xfs_qoff_logitem_t *qoffi=NULL; + uint oldsbqflag=0; + + tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF); + if ((error = xfs_trans_reserve(tp, 0, + sizeof(xfs_qoff_logitem_t) * 2 + + mp->m_sb.sb_sectsize + 128, + 0, + 0, + XFS_DEFAULT_LOG_COUNT))) { + goto error0; + } + + qoffi = xfs_trans_get_qoff_item(tp, NULL, flags & XFS_ALL_QUOTA_ACCT); + xfs_trans_log_quotaoff_item(tp, qoffi); + + s = XFS_SB_LOCK(mp); + oldsbqflag = mp->m_sb.sb_qflags; + mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL; + XFS_SB_UNLOCK(mp, s); + + xfs_mod_sb(tp, XFS_SB_QFLAGS); + + /* + * We have to make sure that the transaction is secure on disk before we + * return and actually stop quota accounting. So, make it synchronous. + * We don't care about quotoff's performance. + */ + xfs_trans_set_sync(tp); + error = xfs_trans_commit(tp, 0, NULL); + +error0: + if (error) { + xfs_trans_cancel(tp, 0); + /* + * No one else is modifying sb_qflags, so this is OK. + * We still hold the quotaofflock. + */ + s = XFS_SB_LOCK(mp); + mp->m_sb.sb_qflags = oldsbqflag; + XFS_SB_UNLOCK(mp, s); + } + *qoffstartp = qoffi; + return (error); +} + + +/* + * Translate an internal style on-disk-dquot to the exportable format. + * The main differences are that the counters/limits are all in Basic + * Blocks (BBs) instead of the internal FSBs, and all on-disk data has + * to be converted to the native endianness. + */ +STATIC void +xfs_qm_export_dquot( + xfs_mount_t *mp, + xfs_disk_dquot_t *src, + struct fs_disk_quota *dst) +{ + bzero(dst, sizeof(*dst)); + dst->d_version = FS_DQUOT_VERSION; /* different from src->d_version */ + dst->d_flags = + xfs_qm_export_qtype_flags(INT_GET(src->d_flags, ARCH_CONVERT)); + dst->d_id = INT_GET(src->d_id, ARCH_CONVERT); + dst->d_blk_hardlimit = (__uint64_t) + XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_hardlimit, ARCH_CONVERT)); + dst->d_blk_softlimit = (__uint64_t) + XFS_FSB_TO_BB(mp, INT_GET(src->d_blk_softlimit, ARCH_CONVERT)); + dst->d_ino_hardlimit = (__uint64_t) + INT_GET(src->d_ino_hardlimit, ARCH_CONVERT); + dst->d_ino_softlimit = (__uint64_t) + INT_GET(src->d_ino_softlimit, ARCH_CONVERT); + dst->d_bcount = (__uint64_t) + XFS_FSB_TO_BB(mp, INT_GET(src->d_bcount, ARCH_CONVERT)); + dst->d_icount = (__uint64_t) INT_GET(src->d_icount, ARCH_CONVERT); + dst->d_btimer = (__uint32_t) INT_GET(src->d_btimer, ARCH_CONVERT); + dst->d_itimer = (__uint32_t) INT_GET(src->d_itimer, ARCH_CONVERT); + dst->d_iwarns = INT_GET(src->d_iwarns, ARCH_CONVERT); + dst->d_bwarns = INT_GET(src->d_bwarns, ARCH_CONVERT); + + dst->d_rtb_hardlimit = (__uint64_t) + XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_hardlimit, ARCH_CONVERT)); + dst->d_rtb_softlimit = (__uint64_t) + XFS_FSB_TO_BB(mp, INT_GET(src->d_rtb_softlimit, ARCH_CONVERT)); + dst->d_rtbcount = (__uint64_t) + XFS_FSB_TO_BB(mp, INT_GET(src->d_rtbcount, ARCH_CONVERT)); + dst->d_rtbtimer = (__uint32_t) INT_GET(src->d_rtbtimer, ARCH_CONVERT); + dst->d_rtbwarns = INT_GET(src->d_rtbwarns, ARCH_CONVERT); + + /* + * Internally, we don't reset all the timers when quota enforcement + * gets turned off. No need to confuse the userlevel code, + * so return zeroes in that case. + */ + if (! XFS_IS_QUOTA_ENFORCED(mp)) { + dst->d_btimer = 0; + dst->d_itimer = 0; + dst->d_rtbtimer = 0; + } + +#ifdef QUOTADEBUG + if (XFS_IS_QUOTA_ENFORCED(mp) && dst->d_id != 0) { + if (((int) dst->d_bcount >= (int) dst->d_blk_softlimit) && + (dst->d_blk_softlimit > 0)) { + ASSERT(dst->d_btimer != 0); + } + if (((int) dst->d_icount >= (int) dst->d_ino_softlimit) && + (dst->d_ino_softlimit > 0)) { + ASSERT(dst->d_itimer != 0); + } + } +#endif +} + +STATIC uint +xfs_qm_import_qtype_flags( + uint *uflagsp) +{ + uint uflags; + + if (copyin(uflagsp, &uflags, sizeof(uint)) < 0) { + return (0); + } + + /* + * Can't be both at the same time. + */ + if (((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == + (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) || + ((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == 0)) + return (0); + + return (uflags & XFS_USER_QUOTA) ? + XFS_DQ_USER : XFS_DQ_GROUP; +} + +STATIC uint +xfs_qm_export_qtype_flags( + uint flags) +{ + /* + * Can't be both at the same time. + */ + ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) != + (XFS_GROUP_QUOTA | XFS_USER_QUOTA)); + ASSERT((flags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) != 0); + + return (flags & XFS_DQ_USER) ? + XFS_USER_QUOTA : XFS_GROUP_QUOTA; +} + +STATIC uint +xfs_qm_import_flags( + uint *uflagsp) +{ + uint flags, uflags; + + if (copyin(uflagsp, &uflags, sizeof(uint)) < 0) + return (0); + + flags = 0; + if (uflags & XFS_QUOTA_UDQ_ACCT) + flags |= XFS_UQUOTA_ACCT; + if (uflags & XFS_QUOTA_GDQ_ACCT) + flags |= XFS_GQUOTA_ACCT; + if (uflags & XFS_QUOTA_UDQ_ENFD) + flags |= XFS_UQUOTA_ENFD; + if (uflags & XFS_QUOTA_GDQ_ENFD) + flags |= XFS_GQUOTA_ENFD; + return (flags); +} + + +STATIC uint +xfs_qm_export_flags( + uint flags) +{ + uint uflags; + + uflags = 0; + if (flags & XFS_UQUOTA_ACCT) + uflags |= XFS_QUOTA_UDQ_ACCT; + if (flags & XFS_GQUOTA_ACCT) + uflags |= XFS_QUOTA_GDQ_ACCT; + if (flags & XFS_UQUOTA_ENFD) + uflags |= XFS_QUOTA_UDQ_ENFD; + if (flags & XFS_GQUOTA_ENFD) + uflags |= XFS_QUOTA_GDQ_ENFD; + return (uflags); +} + + +/* + * Go thru all the inodes in the file system, releasing their dquots. + * Note that the mount structure gets modified to indicate that quotas are off + * AFTER this, in the case of quotaoff. This also gets called from + * xfs_rootumount. + */ +void +xfs_qm_dqrele_all_inodes( + struct xfs_mount *mp, + uint flags) +{ + vmap_t vmap; + xfs_inode_t *ip, *topino; + uint ireclaims; + vnode_t *vp; + boolean_t vnode_refd; + + ASSERT(mp->m_quotainfo); + +again: + XFS_MOUNT_ILOCK(mp); + ip = mp->m_inodes; + if (ip == NULL) { + XFS_MOUNT_IUNLOCK(mp); + return; + } + do { + /* + * skip markers from xfs_sync + */ + + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } + + /* + * Rootinode, rbmip and rsumip have blocks associated with it. + */ + if (ip == XFS_QI_UQIP(mp) || ip == XFS_QI_GQIP(mp)) { + ASSERT(ip->i_udquot == NULL); + ASSERT(ip->i_gdquot == NULL); + ip = ip->i_mnext; + continue; + } + vp = XFS_ITOV(ip); + vnode_refd = B_FALSE; + if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) { + /* + * Sample vp mapping while holding the mplock, lest + * we come across a non-existent vnode. + */ + VMAP(vp, ip, vmap); + ireclaims = mp->m_ireclaims; + topino = mp->m_inodes; + XFS_MOUNT_IUNLOCK(mp); + + /* XXX restart limit ? */ + if ( ! (vp = vn_get(vp, &vmap, 0))) + goto again; + xfs_ilock(ip, XFS_ILOCK_EXCL); + vnode_refd = B_TRUE; + } else { + ireclaims = mp->m_ireclaims; + topino = mp->m_inodes; + XFS_MOUNT_IUNLOCK(mp); + } + + /* + * We don't keep the mountlock across the dqrele() call, + * since it can take a while.. + */ + if ((flags & XFS_UQUOTA_ACCT) && ip->i_udquot) { + xfs_qm_dqrele(ip->i_udquot); + ip->i_udquot = NULL; + } + if ((flags & XFS_GQUOTA_ACCT) && ip->i_gdquot) { + xfs_qm_dqrele(ip->i_gdquot); + ip->i_gdquot = NULL; + } + xfs_iunlock(ip, XFS_ILOCK_EXCL); + /* + * Wait until we've dropped the ilock and mountlock to + * do the vn_rele. Or be condemned to an eternity in the + * inactive code in hell. + */ + if (vnode_refd) + VN_RELE(vp); + XFS_MOUNT_ILOCK(mp); + /* + * If an inode was inserted or removed, we gotta + * start over again. + */ + if (topino != mp->m_inodes || mp->m_ireclaims != ireclaims) { + /* XXX use a sentinel */ + XFS_MOUNT_IUNLOCK(mp); + goto again; + } + ip = ip->i_mnext; + } while (ip != mp->m_inodes); + + XFS_MOUNT_IUNLOCK(mp); +} + +/*------------------------------------------------------------------------*/ +#ifdef DEBUG +/* + * This contains all the test functions for XFS disk quotas. + * Currently it does a quota accounting check. ie. it walks through + * all inodes in the file system, calculating the dquot accounting fields, + * and prints out any inconsistencies. + */ +xfs_dqhash_t *qmtest_udqtab; +xfs_dqhash_t *qmtest_gdqtab; +int qmtest_hashmask; +int qmtest_nfails; +mutex_t qcheck_lock; + +#define DQTEST_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \ + (__psunsigned_t)(id)) & \ + (qmtest_hashmask - 1)) + +#define DQTEST_HASH(mp, id, type) ((type & XFS_DQ_USER) ? \ + (qmtest_udqtab + \ + DQTEST_HASHVAL(mp, id)) : \ + (qmtest_gdqtab + \ + DQTEST_HASHVAL(mp, id))) + +#define DQTEST_LIST_PRINT(l, NXT, title) \ +{ \ + xfs_dqtest_t *dqp; int i = 0;\ + printk("%s (#%d)\n", title, (int) (l)->qh_nelems); \ + for (dqp = (xfs_dqtest_t *)(l)->qh_next; dqp != NULL; \ + dqp = (xfs_dqtest_t *)dqp->NXT) { \ + printk("\t%d\.\t\"%d (%s)\"\t bcnt = %d, icnt = %d\n", \ + ++i, dqp->d_id, DQFLAGTO_TYPESTR(dqp), \ + dqp->d_bcount, dqp->d_icount); } \ +} + +typedef struct dqtest { + xfs_dqmarker_t q_lists; + xfs_dqhash_t *q_hash; /* the hashchain header */ + xfs_mount_t *q_mount; /* filesystem this relates to */ + xfs_dqid_t d_id; /* user id or group id */ + xfs_qcnt_t d_bcount; /* # disk blocks owned by the user */ + xfs_qcnt_t d_icount; /* # inodes owned by the user */ +} xfs_dqtest_t; + +STATIC void +xfs_qm_hashinsert(xfs_dqhash_t *h, xfs_dqtest_t *dqp) +{ + xfs_dquot_t *d; + if (((d) = (h)->qh_next)) + (d)->HL_PREVP = &((dqp)->HL_NEXT); + (dqp)->HL_NEXT = d; + (dqp)->HL_PREVP = &((h)->qh_next); + (h)->qh_next = (xfs_dquot_t *)dqp; + (h)->qh_version++; + (h)->qh_nelems++; +} +STATIC void +xfs_qm_dqtest_print( + xfs_dqtest_t *d) +{ + printk("-----------DQTEST DQUOT----------------\n"); + printk("---- dquot ID = %d\n", d->d_id); + printk("---- type = %s\n", XFS_QM_ISUDQ(d) ? "USR" : "GRP"); + printk("---- fs = 0x%p\n", d->q_mount); + printk("---- bcount = %Lu (0x%x)\n", d->d_bcount, (int)d->d_bcount); + printk("---- icount = %Lu (0x%x)\n", d->d_icount, (int)d->d_icount); + printk("---------------------------\n"); +} + +STATIC void +xfs_qm_dqtest_failed( + xfs_dqtest_t *d, + xfs_dquot_t *dqp, + char *reason, + xfs_qcnt_t a, + xfs_qcnt_t b, + int error) +{ + qmtest_nfails++; + if (error) + printk("quotacheck failed for %d, error = %d\nreason = %s\n", + INT_GET(d->d_id, ARCH_CONVERT), error, reason); + else + printk("quotacheck failed for %d (%s) [%d != %d]\n", + INT_GET(d->d_id, ARCH_CONVERT), reason, (int)a, (int)b); + xfs_qm_dqtest_print(d); + if (dqp) + xfs_qm_dqprint(dqp); +} + +STATIC int +xfs_dqtest_cmp2( + xfs_dqtest_t *d, + xfs_dquot_t *dqp) +{ + int err = 0; + if (INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) != d->d_icount) { + xfs_qm_dqtest_failed(d, dqp, "icount mismatch", + INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), d->d_icount, 0); + err++; + } + if (INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) != d->d_bcount) { + xfs_qm_dqtest_failed(d, dqp, "bcount mismatch", + INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), d->d_bcount, 0); + err++; + } + if (INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT) && + INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) >= INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT)) { + if (INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT) == 0 && + INT_GET(dqp->q_core.d_id, ARCH_CONVERT) != 0) { + printk("%d [%s] [0x%p] BLK TIMER NOT STARTED\n", + d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount); + err++; + } + } + if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) && + INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) { + if (INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) == 0 && + INT_GET(dqp->q_core.d_id, ARCH_CONVERT) != 0) { + printk("%d [%s] [0x%p] INO TIMER NOT STARTED\n", + d->d_id, DQFLAGTO_TYPESTR(d), d->q_mount); + err++; + } + } +#if 0 + if (!err) { + printk("%d [%s] [0x%p] qchecked\n", + d->d_id, XFS_QM_ISUDQ(d) ? "USR" : "GRP", d->q_mount); + } +#endif + return (err); +} + +STATIC void +xfs_dqtest_cmp( + xfs_dqtest_t *d) +{ + xfs_dquot_t *dqp; + int error; + + /* xfs_qm_dqtest_print(d); */ + if ((error = xfs_qm_dqget(d->q_mount, NULL, d->d_id, d->dq_flags, 0, + &dqp))) { + xfs_qm_dqtest_failed(d, NULL, "dqget failed", 0, 0, error); + return; + } + xfs_dqtest_cmp2(d, dqp); + xfs_qm_dqput(dqp); +} + +STATIC int +xfs_qm_internalqcheck_dqget( + xfs_mount_t *mp, + xfs_dqid_t id, + uint type, + xfs_dqtest_t **O_dq) +{ + xfs_dqtest_t *d; + xfs_dqhash_t *h; + + h = DQTEST_HASH(mp, id, type); + for (d = (xfs_dqtest_t *) h->qh_next; d != NULL; + d = (xfs_dqtest_t *) d->HL_NEXT) { + /* DQTEST_LIST_PRINT(h, HL_NEXT, "@@@@@ dqtestlist @@@@@"); */ + if (d->d_id == id && mp == d->q_mount) { + *O_dq = d; + return (0); + } + } + d = kmem_zalloc(sizeof(xfs_dqtest_t), KM_SLEEP); + d->dq_flags = type; + d->d_id = id; + d->q_mount = mp; + d->q_hash = h; + xfs_qm_hashinsert(h, d); + *O_dq = d; + return (0); +} + +STATIC void +xfs_qm_internalqcheck_get_dquots( + xfs_mount_t *mp, + xfs_dqid_t uid, + xfs_dqid_t gid, + xfs_dqtest_t **ud, + xfs_dqtest_t **gd) +{ + if (XFS_IS_UQUOTA_ON(mp)) + xfs_qm_internalqcheck_dqget(mp, uid, XFS_DQ_USER, ud); + if (XFS_IS_GQUOTA_ON(mp)) + xfs_qm_internalqcheck_dqget(mp, gid, XFS_DQ_GROUP, gd); +} + + +STATIC void +xfs_qm_internalqcheck_dqadjust( + xfs_inode_t *ip, + xfs_dqtest_t *d) +{ + d->d_icount++; + d->d_bcount += (xfs_qcnt_t)ip->i_d.di_nblocks; +} + +STATIC int +xfs_qm_internalqcheck_adjust( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_ino_t ino, /* inode number to get data for */ + void *buffer, /* not used */ + xfs_daddr_t bno, /* starting block of inode cluster */ + void *dip, /* not used */ + int *res) /* bulkstat result code */ +{ + xfs_inode_t *ip; + xfs_dqtest_t *ud, *gd; + uint lock_flags; + boolean_t ipreleased; + int error; + + ASSERT(XFS_IS_QUOTA_RUNNING(mp)); + + if (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino) { + *res = BULKSTAT_RV_NOTHING; + return XFS_ERROR(EINVAL); + } + ipreleased = B_FALSE; + again: + lock_flags = XFS_ILOCK_SHARED; + if ((error = xfs_iget(mp, tp, ino, lock_flags, &ip, bno))) { + *res = BULKSTAT_RV_NOTHING; + return (error); + } + + if (ip->i_d.di_mode == 0) { + xfs_iput(ip, lock_flags); + *res = BULKSTAT_RV_NOTHING; + return XFS_ERROR(ENOENT); + } + + /* + * This inode can have blocks after eof which can get released + * when we send it to inactive. Since we don't check the dquot + * until the after all our calculations are done, we must get rid + * of those now. + */ + if (! ipreleased) { + xfs_iput(ip, lock_flags); + ipreleased = B_TRUE; + goto again; + } + xfs_qm_internalqcheck_get_dquots(mp, + (xfs_dqid_t) ip->i_d.di_uid, + (xfs_dqid_t) ip->i_d.di_gid, + &ud, &gd); + if (XFS_IS_UQUOTA_ON(mp)) { + ASSERT(ud); + xfs_qm_internalqcheck_dqadjust(ip, ud); + } + if (XFS_IS_GQUOTA_ON(mp)) { + ASSERT(gd); + xfs_qm_internalqcheck_dqadjust(ip, gd); + } + xfs_iput(ip, lock_flags); + *res = BULKSTAT_RV_DIDONE; + return (0); +} + + +/* PRIVATE, debugging */ +int +xfs_qm_internalqcheck( + xfs_mount_t *mp) +{ + xfs_ino_t lastino; + int done, count; + int i; + xfs_dqtest_t *d, *e; + xfs_dqhash_t *h1; + int error; + + lastino = 0; + qmtest_hashmask = 32; + count = 5; + done = 0; + qmtest_nfails = 0; + + if (! XFS_IS_QUOTA_ON(mp)) + return XFS_ERROR(ESRCH); + + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); + XFS_bflush(mp->m_ddev_targ); + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); + XFS_bflush(mp->m_ddev_targ); + + mutex_lock(&qcheck_lock, PINOD); + /* There should be absolutely no quota activity while this + is going on. */ + qmtest_udqtab = kmem_zalloc(qmtest_hashmask * + sizeof(xfs_dqhash_t), KM_SLEEP); + qmtest_gdqtab = kmem_zalloc(qmtest_hashmask * + sizeof(xfs_dqhash_t), KM_SLEEP); + do { + /* + * Iterate thru all the inodes in the file system, + * adjusting the corresponding dquot counters + */ + if ((error = xfs_bulkstat(mp, NULL, &lastino, &count, + xfs_qm_internalqcheck_adjust, + 0, NULL, BULKSTAT_FG_IGET, &done))) { + break; + } + } while (! done); + if (error) { + printk("Bulkstat returned error 0x%x\n", + error); + } + printk("Checking results against system dquots\n"); + for (i = 0; i < qmtest_hashmask; i++) { + h1 = &qmtest_udqtab[i]; + for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) { + xfs_dqtest_cmp(d); + e = (xfs_dqtest_t *) d->HL_NEXT; + kmem_free(d, sizeof(xfs_dqtest_t)); + d = e; + } + h1 = &qmtest_gdqtab[i]; + for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) { + xfs_dqtest_cmp(d); + e = (xfs_dqtest_t *) d->HL_NEXT; + kmem_free(d, sizeof(xfs_dqtest_t)); + d = e; + } + } + + if (qmtest_nfails) { + printk("************** quotacheck failed **************\n"); + printk("failures = %d\n", qmtest_nfails); + } else { + printk("************** quotacheck successful! **************\n"); + } + kmem_free(qmtest_udqtab, qmtest_hashmask * sizeof(xfs_dqhash_t)); + kmem_free(qmtest_gdqtab, qmtest_hashmask * sizeof(xfs_dqhash_t)); + mutex_unlock(&qcheck_lock); + return (qmtest_nfails); +} + +#endif /* DEBUG */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_quota.h linux-2.4-xfs/linux/fs/xfs/xfs_quota.h --- linux-2.4.7/linux/fs/xfs/xfs_quota.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_quota.h Mon Apr 16 20:11:30 2001 @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_QUOTA_H__ +#define __XFS_QUOTA_H__ + +/* + * uid_t and gid_t are hard-coded to 32 bits in the inode. + * Hence, an 'id' in a dquot is 32 bits.. + */ +typedef __int32_t xfs_dqid_t; + +/* + * Eventhough users may not have quota limits occupying all 64-bits, + * they may need 64-bit accounting. Hence, 64-bit quota-counters, + * and quota-limits. This is a waste in the common case, but hey ... + */ +typedef __uint64_t xfs_qcnt_t; +typedef __uint16_t xfs_qwarncnt_t; + +/* + * Disk quotas status in m_qflags, and also sb_qflags. 16 bits. + */ +#define XFS_UQUOTA_ACCT 0x0001 /* user quota accounting ON */ +#define XFS_UQUOTA_ENFD 0x0002 /* user quota limits enforced */ +#define XFS_UQUOTA_CHKD 0x0004 /* quotacheck run on usr quotas */ +#define XFS_PQUOTA_ACCT 0x0008 /* (IRIX) project quota accounting ON */ +#define XFS_GQUOTA_ENFD 0x0010 /* group quota limits enforced */ +#define XFS_GQUOTA_CHKD 0x0020 /* quotacheck run on grp quotas */ +#define XFS_GQUOTA_ACCT 0x0040 /* group quota accounting ON */ + +/* + * Incore only flags for quotaoff - these bits get cleared when quota(s) + * are in the process of getting turned off. These flags are in m_qflags but + * never in sb_qflags. + */ +#define XFS_UQUOTA_ACTIVE 0x0080 /* uquotas are being turned off */ +#define XFS_GQUOTA_ACTIVE 0x0100 /* gquotas are being turned off */ + +/* + * Typically, we turn quotas off if we weren't explicitly asked to + * mount quotas. This is the mount option not to do that. + * This option is handy in the miniroot, when trying to mount /root. + * We can't really know what's in /etc/fstab until /root is already mounted! + * This stops quotas getting turned off in the root filesystem everytime + * the system boots up a miniroot. + */ +#define XFS_QUOTA_MAYBE 0x0200 /* Turn quotas on if SB has quotas on */ + +/* + * Checking XFS_IS_*QUOTA_ON() while holding any inode lock guarantees + * quota will be not be switched off as long as that inode lock is held. + */ +#define XFS_IS_QUOTA_ON(mp) ((mp)->m_qflags & (XFS_UQUOTA_ACTIVE | \ + XFS_GQUOTA_ACTIVE)) +#define XFS_IS_UQUOTA_ON(mp) ((mp)->m_qflags & XFS_UQUOTA_ACTIVE) +#define XFS_IS_GQUOTA_ON(mp) ((mp)->m_qflags & XFS_GQUOTA_ACTIVE) + +/* + * Flags to tell various functions what to do. Not all of these are meaningful + * to a single function. None of these XFS_QMOPT_* flags are meant to have + * persistent values (ie. their values can and will change between versions) + */ +#define XFS_QMOPT_DQLOCK 0x0000001 /* dqlock */ +#define XFS_QMOPT_DQALLOC 0x0000002 /* alloc dquot ondisk if needed */ +#define XFS_QMOPT_UQUOTA 0x0000004 /* user dquot requested */ +#define XFS_QMOPT_GQUOTA 0x0000008 /* group dquot requested */ +#define XFS_QMOPT_FORCE_RES 0x0000010 /* ignore quota limits */ +#define XFS_QMOPT_DQSUSER 0x0000020 /* don't cache super users dquot */ +#define XFS_QMOPT_SBVERSION 0x0000040 /* change superblock version num */ +#define XFS_QMOPT_QUOTAOFF 0x0000080 /* quotas are being turned off */ +#define XFS_QMOPT_UMOUNTING 0x0000100 /* filesys is being unmounted */ +#define XFS_QMOPT_DOLOG 0x0000200 /* log buf changes (in quotacheck) */ +#define XFS_QMOPT_DOWARN 0x0000400 /* increase warning cnt if necessary */ +#define XFS_QMOPT_ILOCKED 0x0000800 /* inode is already locked (excl) */ +#define XFS_QMOPT_DQREPAIR 0x0001000 /* repair dquot, if damaged. */ + +/* + * flags to xfs_trans_mod_dquot to indicate which field needs to be + * modified. + */ +#define XFS_QMOPT_RES_REGBLKS 0x0010000 +#define XFS_QMOPT_RES_RTBLKS 0x0020000 +#define XFS_QMOPT_BCOUNT 0x0040000 +#define XFS_QMOPT_ICOUNT 0x0080000 +#define XFS_QMOPT_RTBCOUNT 0x0100000 +#define XFS_QMOPT_DELBCOUNT 0x0200000 +#define XFS_QMOPT_DELRTBCOUNT 0x0400000 +#define XFS_QMOPT_RES_INOS 0x0800000 + +/* + * flags for dqflush and dqflush_all. + */ +#define XFS_QMOPT_SYNC 0x1000000 +#define XFS_QMOPT_ASYNC 0x2000000 +#define XFS_QMOPT_DELWRI 0x4000000 + +/* + * flags for dqalloc. + */ +#define XFS_QMOPT_INHERIT 0x8000000 + +/* + * flags to xfs_trans_mod_dquot. + */ +#define XFS_TRANS_DQ_RES_BLKS XFS_QMOPT_RES_REGBLKS +#define XFS_TRANS_DQ_RES_RTBLKS XFS_QMOPT_RES_RTBLKS +#define XFS_TRANS_DQ_RES_INOS XFS_QMOPT_RES_INOS +#define XFS_TRANS_DQ_BCOUNT XFS_QMOPT_BCOUNT +#define XFS_TRANS_DQ_DELBCOUNT XFS_QMOPT_DELBCOUNT +#define XFS_TRANS_DQ_ICOUNT XFS_QMOPT_ICOUNT +#define XFS_TRANS_DQ_RTBCOUNT XFS_QMOPT_RTBCOUNT +#define XFS_TRANS_DQ_DELRTBCOUNT XFS_QMOPT_DELRTBCOUNT + + +#define XFS_QMOPT_QUOTALL (XFS_QMOPT_UQUOTA|XFS_QMOPT_GQUOTA) +#define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS) + +/* + * This check is done typically without holding the inode lock; + * that may seem racey, but it is harmless in the context that it is used. + * The inode cannot go inactive as long a reference is kept, and + * therefore if dquot(s) were attached, they'll stay consistent. + * If, for example, the ownership of the inode changes while + * we didnt have the inode locked, the appropriate dquot(s) will be + * attached atomically. + */ +#define XFS_NOT_DQATTACHED(mp, ip) ((XFS_IS_UQUOTA_ON(mp) &&\ + (ip)->i_udquot == NULL) || \ + (XFS_IS_GQUOTA_ON(mp) && \ + (ip)->i_gdquot == NULL)) + +#define XFS_QM_NEED_QUOTACHECK(mp) ((XFS_IS_UQUOTA_ON(mp) && \ + (mp->m_sb.sb_qflags & \ + XFS_UQUOTA_CHKD) == 0) || \ + (XFS_IS_GQUOTA_ON(mp) && \ + (mp->m_sb.sb_qflags & \ + XFS_GQUOTA_CHKD) == 0)) + +#define XFS_MOUNT_QUOTA_ALL (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ + XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\ + XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD) +#define XFS_MOUNT_QUOTA_MASK (XFS_MOUNT_QUOTA_ALL | XFS_UQUOTA_ACTIVE | \ + XFS_GQUOTA_ACTIVE) + +#define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) + + +#ifdef __KERNEL__ +/* + * External Interface to the XFS disk quota subsystem. + */ +struct bhv_desc; +struct vfs; +struct xfs_disk_dquot; +struct xfs_dqhash; +struct xfs_dquot; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +/* + * Quota Manager Interface. + */ +extern struct xfs_qm *xfs_qm_init(void); +extern void xfs_qm_destroy(struct xfs_qm *); +extern int xfs_qm_dqflush_all(struct xfs_mount *, int); +extern int xfs_qm_dqattach(struct xfs_inode *, uint); +extern int xfs_qm_dqpurge_all(struct xfs_mount *, uint); +extern void xfs_qm_mount_quotainit(struct xfs_mount *, uint); +extern void xfs_qm_unmount_quotadestroy(struct xfs_mount *); +extern int xfs_qm_mount_quotas(struct xfs_mount *); +extern int xfs_qm_unmount_quotas(struct xfs_mount *); +extern void xfs_qm_dqdettach_inode(struct xfs_inode *); +extern int xfs_qm_sync(struct xfs_mount *, short); + + +/* + * system call interface + */ +extern int xfs_quotactl(xfs_mount_t *, struct vfs *, int, int, + int, xfs_caddr_t); + +/* + * dquot interface. + */ +extern void xfs_dqlock(struct xfs_dquot *); +extern void xfs_dqunlock(struct xfs_dquot *); +extern void xfs_dqunlock_nonotify(struct xfs_dquot *); +extern void xfs_dqlock2(struct xfs_dquot *, struct xfs_dquot *); +extern void xfs_qm_dqput(struct xfs_dquot *); +extern void xfs_qm_dqrele(struct xfs_dquot *); +extern xfs_dqid_t xfs_qm_dqid(struct xfs_dquot *); +extern int xfs_qm_dqget(struct xfs_mount *, + struct xfs_inode *, xfs_dqid_t, + uint, uint, struct xfs_dquot **); +extern int xfs_qm_dqcheck(struct xfs_disk_dquot *, + xfs_dqid_t, uint, uint, char *); + +/* + * Vnodeops specific code that should actually be _in_ xfs_vnodeops.c, but + * is here because it's nicer to keep vnodeops (therefore, XFS) lean + * and clean. + */ +extern struct xfs_dquot * xfs_qm_vop_chown(struct xfs_trans *, + struct xfs_inode *, + struct xfs_dquot **, + struct xfs_dquot *); +extern int xfs_qm_vop_dqalloc(struct xfs_mount *, + struct xfs_inode *, + uid_t, gid_t, uint, + struct xfs_dquot **, + struct xfs_dquot **); + +extern int xfs_qm_vop_chown_dqalloc(struct xfs_mount *, + struct xfs_inode *, + int, uid_t, gid_t, + struct xfs_dquot **, + struct xfs_dquot **); + +extern int xfs_qm_vop_chown_reserve(struct xfs_trans *, + struct xfs_inode *, + struct xfs_dquot *, + struct xfs_dquot *, + uint); + +extern int xfs_qm_vop_rename_dqattach(struct xfs_inode **); +extern void xfs_qm_vop_dqattach_and_dqmod_newinode( + struct xfs_trans *, + struct xfs_inode *, + struct xfs_dquot *, + struct xfs_dquot *); + + +/* + * Dquot Transaction interface + */ +extern void xfs_trans_alloc_dqinfo(struct xfs_trans *); +extern void xfs_trans_free_dqinfo(struct xfs_trans *); +extern void xfs_trans_dup_dqinfo(struct xfs_trans *, + struct xfs_trans *); +extern void xfs_trans_mod_dquot(struct xfs_trans *, + struct xfs_dquot *, + uint, long); +extern int xfs_trans_mod_dquot_byino(struct xfs_trans *, + struct xfs_inode *, + uint, long); +extern void xfs_trans_apply_dquot_deltas(struct xfs_trans *); +extern void xfs_trans_unreserve_and_mod_dquots(struct xfs_trans *); + +extern int xfs_trans_reserve_quota_nblks(struct xfs_trans *, + struct xfs_inode *, + long, long, uint); + + +extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *, + struct xfs_dquot *, + struct xfs_dquot *, + long, long, uint); +extern void xfs_trans_log_dquot(struct xfs_trans *, + struct xfs_dquot *); +extern void xfs_trans_dqjoin(struct xfs_trans *, + struct xfs_dquot *); +extern void xfs_qm_dqrele_all_inodes(struct xfs_mount *, uint); + +/* + * Regular disk block quota reservations + */ +#define xfs_trans_reserve_blkquota(tp, ip, nblks) \ +xfs_trans_reserve_quota_nblks(tp, ip, nblks, 0, XFS_QMOPT_RES_REGBLKS) + +#define xfs_trans_unreserve_blkquota(tp, ip, nblks) \ +xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), 0, XFS_QMOPT_RES_REGBLKS) + +#define xfs_trans_reserve_quota(tp, udq, gdq, nb, ni, f) \ +xfs_trans_reserve_quota_bydquots(tp, udq, gdq, nb, ni, f|XFS_QMOPT_RES_REGBLKS) + +#define xfs_trans_unreserve_quota(tp, ud, gd, b, i, f) \ +xfs_trans_reserve_quota_bydquots(tp, ud, gd, -(b), -(i), f|XFS_QMOPT_RES_REGBLKS) + +/* + * Realtime disk block quota reservations + */ +#define xfs_trans_reserve_rtblkquota(mp, tp, ip, nblks) \ +xfs_trans_reserve_quota_nblks(tp, ip, nblks, 0, XFS_QMOPT_RES_RTBLKS) + +#define xfs_trans_unreserve_rtblkquota(tp, ip, nblks) \ +xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), 0, XFS_QMOPT_RES_RTBLKS) + +#define xfs_trans_reserve_rtquota(mp, tp, uq, pq, blks, f) \ +xfs_trans_reserve_quota_bydquots(mp, tp, uq, pq, blks, 0, f|XFS_QMOPT_RES_RTBLKS) + +#define xfs_trans_unreserve_rtquota(tp, uq, pq, blks) \ +xfs_trans_reserve_quota_bydquots(tp, uq, pq, -(blks), XFS_QMOPT_RES_RTBLKS) + +#endif /* __KERNEL__ */ + +#endif /* __XFS_QUOTA_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_quota_priv.h linux-2.4-xfs/linux/fs/xfs/xfs_quota_priv.h --- linux-2.4.7/linux/fs/xfs/xfs_quota_priv.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_quota_priv.h Wed May 23 00:32:22 2001 @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_QUOTA_PRIV_H__ +#define __XFS_QUOTA_PRIV_H__ + +/* + * Number of bmaps that we ask from bmapi when doing a quotacheck. + * We make this restriction to keep the memory usage to a minimum. + */ +#define XFS_DQITER_MAP_SIZE 10 + +/* Number of dquots that fit in to a dquot block */ +#define XFS_QM_DQPERBLK(mp) ((mp)->m_quotainfo->qi_dqperchunk) + +#define XFS_ISLOCKED_INODE(ip) (ismrlocked(&(ip)->i_lock, \ + MR_UPDATE | MR_ACCESS) != 0) +#define XFS_ISLOCKED_INODE_EXCL(ip) (ismrlocked(&(ip)->i_lock, \ + MR_UPDATE) != 0) + +#define XFS_DQ_IS_ADDEDTO_TRX(t, d) ((d)->q_transp == (t)) + +#define XFS_QI_MPLRECLAIMS(mp) ((mp)->m_quotainfo->qi_dqreclaims) +#define XFS_QI_UQIP(mp) ((mp)->m_quotainfo->qi_uquotaip) +#define XFS_QI_GQIP(mp) ((mp)->m_quotainfo->qi_gquotaip) +#define XFS_QI_DQCHUNKLEN(mp) ((mp)->m_quotainfo->qi_dqchunklen) +#define XFS_QI_BTIMELIMIT(mp) ((mp)->m_quotainfo->qi_btimelimit) +#define XFS_QI_RTBTIMELIMIT(mp) ((mp)->m_quotainfo->qi_rtbtimelimit) +#define XFS_QI_ITIMELIMIT(mp) ((mp)->m_quotainfo->qi_itimelimit) +#define XFS_QI_BWARNLIMIT(mp) ((mp)->m_quotainfo->qi_bwarnlimit) +#define XFS_QI_IWARNLIMIT(mp) ((mp)->m_quotainfo->qi_iwarnlimit) +#define XFS_QI_QOFFLOCK(mp) ((mp)->m_quotainfo->qi_quotaofflock) + +#define XFS_QI_MPL_LIST(mp) ((mp)->m_quotainfo->qi_dqlist) +#define XFS_QI_MPLLOCK(mp) ((mp)->m_quotainfo->qi_dqlist.qh_lock) +#define XFS_QI_MPLNEXT(mp) ((mp)->m_quotainfo->qi_dqlist.qh_next) +#define XFS_QI_MPLNDQUOTS(mp) ((mp)->m_quotainfo->qi_dqlist.qh_nelems) + +#define XQMLCK(h) (mutex_lock(&((h)->qh_lock), PINOD)) +#define XQMUNLCK(h) (mutex_unlock(&((h)->qh_lock))) +#ifdef DEBUG +static inline int +XQMISLCKD(xfs_dqhash_t *h) +{ + if (mutex_trylock(&h->qh_lock)) { + mutex_unlock(&h->qh_lock); + return 0; + } + return 1; +} +#endif + +#define XFS_DQ_HASH_LOCK(h) XQMLCK(h) +#define XFS_DQ_HASH_UNLOCK(h) XQMUNLCK(h) +#define XFS_DQ_IS_HASH_LOCKED(h) XQMISLCKD(h) + +#define xfs_qm_mplist_lock(mp) XQMLCK(&(XFS_QI_MPL_LIST(mp))) +#define xfs_qm_mplist_unlock(mp) XQMUNLCK(&(XFS_QI_MPL_LIST(mp))) +#define XFS_QM_IS_MPLIST_LOCKED(mp) XQMISLCKD(&(XFS_QI_MPL_LIST(mp))) + +#define xfs_qm_freelist_lock(qm) XQMLCK(&((qm)->qm_dqfreelist)) +#define xfs_qm_freelist_unlock(qm) XQMUNLCK(&((qm)->qm_dqfreelist)) +#define XFS_QM_IS_FREELIST_LOCKED(qm) XQMISLCKD(&((qm)->qm_dqfreelist)) + +/* + * Hash into a bucket in the dquot hash table, based on . + */ +#define XFS_DQ_HASHVAL(mp, id) (((__psunsigned_t)(mp) + \ + (__psunsigned_t)(id)) & \ + (xfs_Gqm->qm_dqhashmask - 1)) +#define XFS_DQ_HASH(mp, id, type) (type == XFS_DQ_USER ? \ + (xfs_Gqm->qm_usr_dqhtable + \ + XFS_DQ_HASHVAL(mp, id)) : \ + (xfs_Gqm->qm_grp_dqhtable + \ + XFS_DQ_HASHVAL(mp, id))) +#define XFS_IS_DQTYPE_ON(mp, type) (type == XFS_DQ_USER ? \ + XFS_IS_UQUOTA_ON(mp):XFS_IS_GQUOTA_ON(mp)) +#define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \ + INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT) == 0ULL && \ + INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT) == 0ULL && \ + INT_GET(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT) == 0ULL && \ + INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT) == 0ULL && \ + INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) == 0ULL && \ + INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) == 0ULL && \ + INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT) == 0ULL && \ + INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT) == 0ULL && \ + INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) == 0ULL ) + +#define HL_PREVP dq_hashlist.ql_prevp +#define HL_NEXT dq_hashlist.ql_next +#define MPL_PREVP dq_mplist.ql_prevp +#define MPL_NEXT dq_mplist.ql_next + + +#define _LIST_REMOVE(h, dqp, PVP, NXT) \ + { \ + xfs_dquot_t *d; \ + if (((d) = (dqp)->NXT)) \ + (d)->PVP = (dqp)->PVP; \ + *((dqp)->PVP) = d; \ + (dqp)->NXT = NULL; \ + (dqp)->PVP = NULL; \ + (h)->qh_version++; \ + (h)->qh_nelems--; \ + } + +#define _LIST_INSERT(h, dqp, PVP, NXT) \ + { \ + xfs_dquot_t *d; \ + if (((d) = (h)->qh_next)) \ + (d)->PVP = &((dqp)->NXT); \ + (dqp)->NXT = d; \ + (dqp)->PVP = &((h)->qh_next); \ + (h)->qh_next = dqp; \ + (h)->qh_version++; \ + (h)->qh_nelems++; \ + } + +#define FOREACH_DQUOT_IN_MP(dqp, mp) \ + for ((dqp) = XFS_QI_MPLNEXT(mp); (dqp) != NULL; (dqp) = (dqp)->MPL_NEXT) + +#define FOREACH_DQUOT_IN_FREELIST(dqp, qlist) \ +for ((dqp) = (qlist)->qh_next; (dqp) != (xfs_dquot_t *)(qlist); \ + (dqp) = (dqp)->dq_flnext) + +#define XQM_HASHLIST_INSERT(h, dqp) \ + _LIST_INSERT(h, dqp, HL_PREVP, HL_NEXT) + +#define XQM_FREELIST_INSERT(h, dqp) \ + xfs_qm_freelist_append(h, dqp) + +#define XQM_MPLIST_INSERT(h, dqp) \ + _LIST_INSERT(h, dqp, MPL_PREVP, MPL_NEXT) + +#define XQM_HASHLIST_REMOVE(h, dqp) \ + _LIST_REMOVE(h, dqp, HL_PREVP, HL_NEXT) +#define XQM_FREELIST_REMOVE(dqp) \ + xfs_qm_freelist_unlink(dqp) +#define XQM_MPLIST_REMOVE(h, dqp) \ + { _LIST_REMOVE(h, dqp, MPL_PREVP, MPL_NEXT); \ + XFS_QI_MPLRECLAIMS((dqp)->q_mount)++; } + +#define XFS_DQ_IS_LOGITEM_INITD(dqp) ((dqp)->q_logitem.qli_dquot == (dqp)) + +#define XFS_QM_DQP_TO_DQACCT(tp, dqp) (XFS_QM_ISUDQ(dqp) ? \ + (tp)->t_dqinfo->dqa_usrdquots : \ + (tp)->t_dqinfo->dqa_grpdquots) +#define XFS_IS_SUSER_DQUOT(dqp) \ + (INT_GET((dqp)->q_core.d_id, ARCH_CONVERT) == 0) + +#define XFS_PURGE_INODE(ip) \ + { \ + vmap_t dqvmap; \ + vnode_t *dqvp; \ + dqvp = XFS_ITOV(ip); \ + VMAP(dqvp, ip, dqvmap); \ + VN_RELE(dqvp); \ + } + +#define DQFLAGTO_TYPESTR(d) (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \ + (((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : "???")) +#define DQFLAGTO_DIRTYSTR(d) (XFS_DQ_IS_DIRTY(d) ? "DIRTY" : "NOTDIRTY") + +#endif /* __XFS_QUOTA_PRIV_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_rename.c linux-2.4-xfs/linux/fs/xfs/xfs_rename.c --- linux-2.4.7/linux/fs/xfs/xfs_rename.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_rename.c Tue Apr 10 20:44:54 2001 @@ -0,0 +1,1111 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +/* + * Given an array of up to 4 inode pointers, unlock the pointed to inodes. + * If there are fewer than 4 entries in the array, the empty entries will + * be at the end and will have NULL pointers in them. + */ +STATIC void +xfs_rename_unlock4( + xfs_inode_t **i_tab, + uint lock_mode) +{ + int i; + + xfs_iunlock(i_tab[0], lock_mode); + for (i = 1; i < 4; i++) { + if (i_tab[i] == NULL) { + break; + } + /* + * Watch out for duplicate entries in the table. + */ + if (i_tab[i] != i_tab[i-1]) { + xfs_iunlock(i_tab[i], lock_mode); + } + } +} + +/* + * Compare the i_gen fields of the inodes pointed to in the array of + * inode pointers to the gen values stored at the same offset in the + * array of generation counts. Return 0 if they are the same and 1 + * if they are different. + * + * There are a maximum of 4 entries in the array. If there are + * fewer than that, the first empty entry will have a NULL pointer. + */ +STATIC int +xfs_rename_compare_gencounts( + xfs_inode_t **i_tab, + int *i_gencounts) +{ + int i; + int compare; + + compare = 0; + for (i = 0; i < 4; i++) { + if (i_tab[i] == NULL) { + break; + } + if (i_tab[i]->i_gen != i_gencounts[i]) { + compare = 1; + break; + } + } + return compare; +} + +#ifdef DEBUG +int xfs_rename_check0, xfs_rename_check1, xfs_rename_check2; +#endif +/* + * The following routine needs all inodes locked before being called. + * It checks to see if the inums and names are still valid as passed in. + * + * For now, only check if dp1 == dp2. + * + * Return 1 if still OK. + * Return 0 otherwize. + */ +STATIC int +xfs_rename_check_ok( + xfs_inode_t *dp1, /* old (source) directory inode */ + xfs_inode_t *dp2, /* new (target) directory inode */ + char *name1, /* old entry name */ + char *name2, /* new entry name */ + xfs_inode_t *ip1, /* inode of old entry */ + xfs_inode_t *ip2) /* inode of new entry, if it + already existed, NULL otherwise. */ +{ + xfs_ino_t inum1, inum2; + int error, diffdirs; + + ASSERT(dp1); + ASSERT(dp2); + ASSERT(ip1); + ASSERT((dp1->i_d.di_mode & IFMT) == IFDIR); + ASSERT((dp2->i_d.di_mode & IFMT) == IFDIR); + + diffdirs = (dp1 != dp2); + +#ifdef DEBUG + xfs_rename_check0++; +#endif + + if (dp1->i_d.di_nlink == 0 || (diffdirs && (dp2->i_d.di_nlink == 0))) { + return(0); + } + + if ((ip1->i_d.di_mode & IFMT) == IFDIR) { + return(0); + } + + if (ip2 && ((ip2->i_d.di_mode & IFMT) == IFDIR)) { + return(0); + } + + /* + * Get the inum for name1 and compare to the value in ip1. + * Need to worry about dead-lock here since we have all the inode + * locks. + */ + + error = xfs_dir_lookup_int(NULL, XFS_ITOBHV(dp1), DLF_NODNLC, + name1, NULL, &inum1, NULL, NULL); + + if (error) { /* name1 must be gone or .... */ + return(0); + } + + if (inum1 != ip1->i_ino) { /* name1 is now a different inode */ + return(0); + } + +#ifdef DEBUG + xfs_rename_check1++; +#endif + + /* + * Get the inum for name2 and compare to the value in ip2. + * Need to worry about dead-lock here since we have all the inode + * locks. + */ + + error = xfs_dir_lookup_int(NULL, XFS_ITOBHV(dp2), DLF_NODNLC, + name2, NULL, &inum2, NULL, NULL); + + /* + * If we have an unsuccessful lookup and ip2 was passed in, the dest is + * now gone so we need to start over. + * If we have a successful lookup and ip2 was not found before, + * we need to start over, too. + */ + if ((error && ip2) || (!error && !ip2)) { + return(0); + } + + if (ip2 && (inum2 != ip2->i_ino)) { /* name2 is now a different inode */ + return(0); + } + +#ifdef DEBUG + xfs_rename_check2++; +#endif + return(1); +} + +#ifdef DEBUG +int xfs_rename_skip, xfs_rename_nskip; +#endif + +/* + * The following routine will acquire the locks required for a rename + * operation. The code understands the semantics of renames and will + * validate that name1 exists under dp1 & that name2 may or may not + * exist under dp2. + * + * We are renaming dp1/name1 to dp2/name2. + * + * Return ENOENT if dp1 does not exist, other lookup errors, or 0 for success. + * Return EAGAIN if the caller needs to try again. + */ +STATIC int +xfs_lock_for_rename( + xfs_inode_t *dp1, /* old (source) directory inode */ + xfs_inode_t *dp2, /* new (target) directory inode */ + char *name1, /* old entry name */ + char *name2, /* new entry name */ + xfs_inode_t **ipp1, /* inode of old entry */ + xfs_inode_t **ipp2, /* inode of new entry, if it + already exists, NULL otherwise. */ + xfs_inode_t **i_tab,/* array of inode returned, sorted */ + int *num_inodes, /* number of inodes in array */ + int *i_gencounts) /* array of inode gen counts */ +{ + xfs_inode_t *ip1, *ip2, *temp; + xfs_ino_t inum1, inum2; + unsigned long dir_gen1, dir_gen2; + int error; + int i, j; + uint lock_mode; + uint dir_unlocked; + uint lookup_flags; + int diff_dirs = (dp1 != dp2); + + ip2 = NULL; + + /* + * First, find out the current inums of the entries so that we + * can determine the initial locking order. We'll have to + * sanity check stuff after all the locks have been acquired + * to see if we still have the right inodes, directories, etc. + */ + lock_mode = xfs_ilock_map_shared(dp1); + + /* + * We don't want to do lookups in unlinked directories. + */ + if (dp1->i_d.di_nlink == 0) { + xfs_iunlock_map_shared(dp1, lock_mode); + return XFS_ERROR(ENOENT); + } + + lookup_flags = DLF_IGET; + if (lock_mode == XFS_ILOCK_SHARED) { + lookup_flags |= DLF_LOCK_SHARED; + } + error = xfs_dir_lookup_int(NULL, XFS_ITOBHV(dp1), lookup_flags, + name1, NULL, &inum1, &ip1, &dir_unlocked); + + /* + * Save the current generation so that we can detect if it's + * modified between when we drop the lock & reacquire it down + * below. We only need to do this for the src directory since + * the target entry does not need to exist yet. + */ + dir_gen1 = dp1->i_gen; + + if (error) { + xfs_iunlock_map_shared(dp1, lock_mode); + return error; + } + ASSERT (ip1); + ITRACE(ip1); + + /* + * Unlock dp1 and lock dp2 if they are different. + */ + + if (diff_dirs) { + xfs_iunlock_map_shared(dp1, lock_mode); + lock_mode = xfs_ilock_map_shared(dp2); + /* + * We don't want to do lookups in unlinked directories. + */ + if (dp2->i_d.di_nlink == 0) { + xfs_iunlock_map_shared(dp2, lock_mode); + return XFS_ERROR(ENOENT); + } + } + + + lookup_flags = DLF_IGET; + if (lock_mode == XFS_ILOCK_SHARED) { + lookup_flags |= DLF_LOCK_SHARED; + } + error = xfs_dir_lookup_int(NULL, XFS_ITOBHV(dp2), lookup_flags, + name2, NULL, &inum2, &ip2, &dir_unlocked); + dir_gen2 = dp2->i_gen; + if (error == ENOENT) { /* target does not need to exist. */ + inum2 = 0; + } else if (error) { + /* + * If dp2 and dp1 are the same, the next line unlocks dp1. + * Got it? + */ + xfs_iunlock_map_shared(dp2, lock_mode); + IRELE (ip1); + return error; + } else { + ITRACE(ip2); + } + + /* + * i_tab contains a list of pointers to inodes. We initialize + * the table here & we'll sort it. We will then use it to + * order the acquisition of the inode locks. + * + * Note that the table may contain duplicates. e.g., dp1 == dp2. + */ + i_tab[0] = dp1; + i_tab[1] = dp2; + i_tab[2] = ip1; + if (inum2 == 0) { + *num_inodes = 3; + i_tab[3] = NULL; + } else { + *num_inodes = 4; + i_tab[3] = ip2; + } + + /* + * Sort the elements via bubble sort. (Remember, there are at + * most 4 elements to sort, so this is adequate.) + */ + for (i=0; i < *num_inodes; i++) { + for (j=1; j < *num_inodes; j++) { + if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) { + temp = i_tab[j]; + i_tab[j] = i_tab[j-1]; + i_tab[j-1] = temp; + } + } + } + + /* + * We have dp2 locked. If it isn't first, unlock it. + * If it is first, tell xfs_lock_inodes so it can skip it + * when locking. if dp1 == dp2, xfs_lock_inodes will skip both + * since they are equal. xfs_lock_inodes needs all these inodes + * so that it can unlock and retry if there might be a dead-lock + * potential with the log. + */ + + if (i_tab[0] == dp2 && lock_mode == XFS_ILOCK_SHARED) { +#ifdef DEBUG + xfs_rename_skip++; +#endif + xfs_lock_inodes(i_tab, *num_inodes, 1, XFS_ILOCK_SHARED); + } else { +#ifdef DEBUG + xfs_rename_nskip++; +#endif + xfs_iunlock_map_shared(dp2, lock_mode); + xfs_lock_inodes(i_tab, *num_inodes, 0, XFS_ILOCK_SHARED); + } + + /* + * See if either of the directories was modified during the + * interval between when the locks were released and when + * they were reacquired. + */ + if (dp1->i_gen != dir_gen1 || (diff_dirs && (dp2->i_gen != dir_gen2))) { + /* + * Someone else may have linked in a new inode + * with the same name. If so, we'll need to + * release our locks & go through the whole + * thing again. + */ + + xfs_iunlock(i_tab[0], XFS_ILOCK_SHARED); + for (i=1; i < *num_inodes; i++) { + if (i_tab[i] != i_tab[i-1]) + xfs_iunlock(i_tab[i], XFS_ILOCK_SHARED); + } + if (*num_inodes == 4) { + IRELE (ip2); + } + IRELE (ip1); + return XFS_ERROR(EAGAIN); + } + + + /* + * Set the return value. Return the gen counts of the inodes in + * i_tab in i_gencounts. Null out any unused entries in i_tab. + */ + *ipp1 = *ipp2 = NULL; + for (i=0; i < *num_inodes; i++) { + if (i_tab[i]->i_ino == inum1) { + *ipp1 = i_tab[i]; + } + if (i_tab[i]->i_ino == inum2) { + *ipp2 = i_tab[i]; + } + i_gencounts[i] = i_tab[i]->i_gen; + } + for (;i < 4; i++) { + i_tab[i] = NULL; + } + return 0; +} + + +int rename_which_error_return = 0; + +/* + * Do all the mundane error checking for xfs_rename(). The code + * assumes that all of the non-NULL inodes have already been locked. + */ +STATIC int +xfs_rename_error_checks( + xfs_inode_t *src_dp, + xfs_inode_t *target_dp, + xfs_inode_t *src_ip, + xfs_inode_t *target_ip, + char *src_name, + char *target_name, + cred_t *credp, + int *status) +{ + int src_is_directory; + int error; + + *status = 0; + error = 0; + /* + * If the target directory has been removed, we can't create any + * more files in it. We don't need to check the source dir, + * because it was checked in xfs_lock_for_rename() while looking + * for the source inode. If it had been removed the source + * dir's gen count would have been bumped removing the last entry + * and then we'd have noticed that its link count had gone to zero. + */ + if (target_dp->i_d.di_nlink == 0) { + error = XFS_ERROR(ENOENT); + *status = __LINE__; + goto error_return; + } +#if 0 + if (error = xfs_iaccess(src_dp, IEXEC | IWRITE, credp)) { + *status = __LINE__; + goto error_return; + } + if (error = xfs_stickytest(src_dp, src_ip, credp)) { + *status = __LINE__; + goto error_return; + } + + if (target_dp && (src_dp != target_dp)) { + if (error = xfs_iaccess(target_dp, IEXEC | IWRITE, credp)) { + *status = __LINE__; + goto error_return; + } + if ((target_ip != NULL) && + (error = xfs_stickytest(target_dp, target_ip, credp))) { + *status = __LINE__; + goto error_return; + } + } else { + if ((target_ip != NULL) && + (error = xfs_stickytest(src_dp, target_ip, credp))) { + *status = __LINE__; + goto error_return; + } + } +#endif + + if ((src_ip == src_dp) || (target_ip == target_dp)) { + error = XFS_ERROR(EINVAL); + *status = __LINE__; + goto error_return; + } + + /* Do some generic error tests now that we have the lock */ + if ((error = xfs_pre_rename(XFS_ITOV(src_ip)))) { + error = XFS_ERROR(error); + *status = __LINE__; + goto error_return; + } + + /* + * Source and target are identical. + */ + if (src_ip == target_ip) { + /* + * There is no error in this case, but we want to get + * out anyway. Set error to 0 so that no error will + * be returned, but set *status so that the caller + * will know that it should give up on the rename. + */ + error = 0; + *status = __LINE__; + goto error_return; + } + + /* + * Directory renames require special checks. + */ + src_is_directory = ((src_ip->i_d.di_mode & IFMT) == IFDIR); + + if (src_is_directory) { + + ASSERT(src_ip->i_d.di_nlink >= 2); + + /* + * Check for link count overflow on target_dp + */ + if (target_ip == NULL && (src_dp != target_dp) && + target_dp->i_d.di_nlink >= XFS_MAXLINK) { + error = XFS_ERROR(EMLINK); + *status = __LINE__; + goto error_return; + } + + /* + * Cannot rename ".." + */ + if ((src_name[0] == '.') && (src_name[1] == '.') && + (src_name[2] == '\0')) { + error = XFS_ERROR(EINVAL); + *status = __LINE__; + goto error_return; + } + if ((target_name[0] == '.') && (target_name[1] == '.') && + (target_name[2] == '\0')) { + error = XFS_ERROR(EINVAL); + *status = __LINE__; + goto error_return; + } + + } + + error_return: + return error; +} + +/* + * Perform error checking on the target inode after the ancestor check + * has been done in xfs_rename(). + */ +STATIC int +xfs_rename_target_checks( + xfs_inode_t *target_ip, + int src_is_directory) +{ + int error; + + error = 0; + /* + * If target exists and it's a directory, check that both + * target and source are directories and that target can be + * destroyed, or that neither is a directory. + */ + if ((target_ip->i_d.di_mode & IFMT) == IFDIR) { + + /* + * Make sure src is a directory. + */ + if (!src_is_directory) { + error = XFS_ERROR(EISDIR); + rename_which_error_return = __LINE__; + goto error_return; + } + + /* + * Make sure target dir is empty. + */ + if (!(XFS_DIR_ISEMPTY(target_ip->i_mount, target_ip)) || + (target_ip->i_d.di_nlink > 2)) { + error = XFS_ERROR(EEXIST); + rename_which_error_return = __LINE__; + goto error_return; + } + + if ((error = xfs_pre_rmdir(XFS_ITOV(target_ip)))) { + error = XFS_ERROR(error); + rename_which_error_return = __LINE__; + goto error_return; + } + + } else { + if ((error = xfs_pre_remove(XFS_ITOV(target_ip)))) { + error = XFS_ERROR(error); + rename_which_error_return = __LINE__; + goto error_return; + } + + if (src_is_directory) { + error = XFS_ERROR(ENOTDIR); + rename_which_error_return = __LINE__; + goto error_return; + } + } + + error_return: + return error; +} + +#ifdef DEBUG +int xfs_rename_agains; +int xfs_renames; +int xfs_rename_tries; +int xfs_rename_max; +int xfs_rename_big; +int xfs_rename_retries0; +int xfs_rename_retries1; +int xfs_rename_retries2; +int xfs_rename_retries3; +#endif + +/* + * xfs_rename + */ +int +xfs_rename( + bhv_desc_t *src_dir_bdp, + char *src_name, + vnode_t *target_dir_vp, + char *target_name, + pathname_t *target_pnp, + cred_t *credp) +{ + xfs_trans_t *tp; + xfs_inode_t *src_dp, *target_dp, *src_ip, *target_ip; + xfs_mount_t *mp; + int new_parent; /* moving to a new dir */ + int src_is_directory; /* src_name is a directory */ + int error; + xfs_bmap_free_t free_list; + xfs_fsblock_t first_block; + int cancel_flags; + int committed; + int status; + xfs_inode_t *inodes[4]; + int gencounts[4]; + int target_ip_dropped = 0; /* dropped target_ip link? */ + vnode_t *src_dir_vp; + bhv_desc_t *target_dir_bdp; + int spaceres; + int target_link_zero = 0; + int num_inodes; + int src_namelen; + int target_namelen; +#ifdef DEBUG + int retries; + + xfs_renames++; +#endif + src_dir_vp = BHV_TO_VNODE(src_dir_bdp); + vn_trace_entry(src_dir_vp, "xfs_rename", (inst_t *)__return_address); + vn_trace_entry(target_dir_vp, "xfs_rename", (inst_t *)__return_address); + + /* + * Find the XFS behavior descriptor for the target directory + * vnode since it was not handed to us. + */ + target_dir_bdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(target_dir_vp), + &xfs_vnodeops); + if (target_dir_bdp == NULL) { + return XFS_ERROR(EXDEV); + } + src_namelen = strlen(src_name); + if (src_namelen >= MAXNAMELEN) + return XFS_ERROR(EINVAL); + target_namelen = strlen(target_name); + if (target_namelen >= MAXNAMELEN) + return XFS_ERROR(EINVAL); + src_dp = XFS_BHVTOI(src_dir_bdp); + target_dp = XFS_BHVTOI(target_dir_bdp); + if (DM_EVENT_ENABLED(src_dir_vp->v_vfsp, src_dp, DM_EVENT_RENAME) || + DM_EVENT_ENABLED(target_dir_vp->v_vfsp, + target_dp, DM_EVENT_RENAME)) { + error = dm_send_namesp_event(DM_EVENT_RENAME, + src_dir_bdp, DM_RIGHT_NULL, + target_dir_bdp, DM_RIGHT_NULL, + src_name, target_name, + 0, 0, 0); + if (error) { + return error; + } + } + /* Return through std_return after this point. */ + +#ifdef DEBUG + retries = 0; +#endif + start_over: + /* + * Lock all the participating inodes. Depending upon whether + * the target_name exists in the target directory, and + * whether the target directory is the same as the source + * directory, we can lock from 2 to 4 inodes. + * xfs_lock_for_rename() will return ENOENT if src_name + * does not exist in the source directory. + */ + tp = NULL; + do { + error = xfs_lock_for_rename(src_dp, target_dp, src_name, + target_name, &src_ip, &target_ip, inodes, + &num_inodes, gencounts); +#ifdef DEBUG + if (error == EAGAIN) xfs_rename_agains++; +#endif + } while (error == EAGAIN); + if (error) { + rename_which_error_return = __LINE__; + /* + * We have nothing locked, no inode references, and + * no transaction, so just get out. + */ + goto std_return; + } + + ASSERT(src_ip != NULL); + + error = xfs_rename_error_checks(src_dp, target_dp, src_ip, + target_ip, src_name, target_name, credp, &status); + if (error || status) { + rename_which_error_return = status; + xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); + goto rele_return; + } + + new_parent = (src_dp != target_dp); + src_is_directory = ((src_ip->i_d.di_mode & IFMT) == IFDIR); + + /* + * Drop the locks on our inodes so that we can do the ancestor + * check if necessary and start the transaction. We have already + * saved the i_gen fields of each of the inode in the gencounts + * array when we called xfs_lock_for_rename(). + */ + xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED); + + XFS_BMAP_INIT(&free_list, &first_block); + mp = src_dp->i_mount; + tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME); + cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + spaceres = XFS_RENAME_SPACE_RES(mp, target_namelen); + error = xfs_trans_reserve(tp, spaceres, XFS_RENAME_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT); + if (error == ENOSPC) { + spaceres = 0; + error = xfs_trans_reserve(tp, 0, XFS_RENAME_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT); + } + if (error) { + rename_which_error_return = __LINE__; + xfs_trans_cancel(tp, 0); + goto rele_return; + } + + /* + * Attach the dquots to the inodes + */ + if (XFS_IS_QUOTA_ON(mp)) { + if ((error = xfs_qm_vop_rename_dqattach(inodes))) { + xfs_trans_cancel(tp, cancel_flags); + rename_which_error_return = __LINE__; + goto rele_return; + } + } + + /* + * Reacquire the inode locks we dropped above. Then check the + * generation counts on the inodes. If any of them have changed, + * we cancel the transaction and start over from the top. + */ + xfs_lock_inodes(inodes, num_inodes, 0, XFS_ILOCK_EXCL); + + if (xfs_rename_compare_gencounts(inodes, gencounts)) { + + /* + * If the ancestors don't need to be checked, see if + * the gencount change indicates that we really need + * to start over. + */ + + if(!xfs_rename_check_ok(src_dp, target_dp, src_name, + target_name, src_ip, target_ip)) { + xfs_trans_cancel(tp, cancel_flags); + xfs_rename_unlock4(inodes, XFS_ILOCK_EXCL); + IRELE(src_ip); + if (target_ip != NULL) { + IRELE(target_ip); + } +#ifdef DEBUG + xfs_rename_tries++; + retries++; + if (retries > xfs_rename_max) + xfs_rename_max = retries; + + if (retries < 5) xfs_rename_retries0++; + else if (retries < 100) xfs_rename_retries1++; + else xfs_rename_retries2++; + + if (retries > 100000) { + xfs_rename_big++; + } +#endif + goto start_over; +#ifdef DEBUG + } else { + xfs_rename_retries3++; +#endif + } + } + + /* + * Join all the inodes to the transaction. From this point on, + * we can rely on either trans_commit or trans_cancel to unlock + * them. Note that we need to add a vnode reference to the + * directories since trans_commit & trans_cancel will decrement + * them when they unlock the inodes. Also, we need to be careful + * not to add an inode to the transaction more than once. + */ + VN_HOLD(src_dir_vp); + xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL); + if (new_parent) { + VN_HOLD(target_dir_vp); + xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL); + } + if ((src_ip != src_dp) && (src_ip != target_dp)) { + xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL); + } + if ((target_ip != NULL) && + (target_ip != src_ip) && + (target_ip != src_dp) && + (target_ip != target_dp)) { + xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL); + } + + /* + * We should be in the same file system. + */ + ASSERT(src_dp->i_mount == target_dp->i_mount); + + /* + * We have to redo all of the checks we did above, because we've + * unlocked all of the inodes in the interim. + */ + error = xfs_rename_error_checks(src_dp, target_dp, src_ip, + target_ip, src_name, target_name, credp, &status); + if (error || status) { + rename_which_error_return = status; + goto error_return; + } + + /* + * Set up the target. + */ + if (target_ip == NULL) { + /* + * If there's no space reservation, check the entry will + * fit before actually inserting it. + */ + if (spaceres == 0 && + (error = XFS_DIR_CANENTER(mp, tp, target_dp, target_name, + target_namelen))) { + rename_which_error_return = __LINE__; + goto error_return; + } + /* + * If target does not exist and the rename crosses + * directories, adjust the target directory link count + * to account for the ".." reference from the new entry. + */ + error = XFS_DIR_CREATENAME(mp, tp, target_dp, target_name, + target_namelen, src_ip->i_ino, + &first_block, &free_list, spaceres); + if (error == ENOSPC) { + rename_which_error_return = __LINE__; + goto error_return; + } + if (error) { + rename_which_error_return = __LINE__; + goto abort_return; + } + xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + if (new_parent && src_is_directory) { + error = xfs_bumplink(tp, target_dp); + if (error) { + rename_which_error_return = __LINE__; + goto abort_return; + } + } + } else { /* target_ip != NULL */ + + error = xfs_rename_target_checks(target_ip, + src_is_directory); + if (error) { + goto error_return; + } + + /* + * Link the source inode under the target name. + * If the source inode is a directory and we are moving + * it across directories, its ".." entry will be + * inconsistent until we replace that down below. + * + * In case there is already an entry with the same + * name at the destination directory, remove it first. + */ + error = XFS_DIR_REPLACE(mp, tp, target_dp, target_name, + ((target_pnp != NULL) ? target_pnp->pn_complen : + target_namelen), src_ip->i_ino, &first_block, + &free_list, spaceres); + if (error) { + rename_which_error_return = __LINE__; + goto abort_return; + } + xfs_ichgtime(target_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + /* + * Decrement the link count on the target since the target + * dir no longer points to it. + */ + error = xfs_droplink(tp, target_ip); + if (error) { + rename_which_error_return = __LINE__; + goto abort_return;; + } + target_ip_dropped = 1; + + /* Do this test while we still hold the locks */ + target_link_zero = (target_ip)->i_d.di_nlink==0; + + if (src_is_directory) { + /* + * Drop the link from the old "." entry. + */ + error = xfs_droplink(tp, target_ip); + if (error) { + rename_which_error_return = __LINE__; + goto abort_return; + } + } + + } /* target_ip != NULL */ + + /* + * Remove the source. + */ + if (new_parent && src_is_directory) { + + /* + * Rewrite the ".." entry to point to the new + * directory. + */ + error = XFS_DIR_REPLACE(mp, tp, src_ip, "..", 2, + target_dp->i_ino, &first_block, + &free_list, spaceres); + ASSERT(error != EEXIST); + if (error) { + rename_which_error_return = __LINE__; + goto abort_return; + } + xfs_ichgtime(src_ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + } else { + /* + * We always want to hit the ctime on the source inode. + * We do it in the if clause above for the 'new_parent && + * src_is_directory' case, and here we get all the other + * cases. This isn't strictly required by the standards + * since the source inode isn't really being changed, + * but old unix file systems did it and some incremental + * backup programs won't work without it. + */ + xfs_ichgtime(src_ip, XFS_ICHGTIME_CHG); + } + + /* + * Adjust the link count on src_dp. This is necessary when + * renaming a directory, either within one parent when + * the target existed, or across two parent directories. + */ + if (src_is_directory && (new_parent || target_ip != NULL)) { + + /* + * Decrement link count on src_directory since the + * entry that's moved no longer points to it. + */ + error = xfs_droplink(tp, src_dp); + if (error) { + rename_which_error_return = __LINE__; + goto abort_return; + } + } + + error = XFS_DIR_REMOVENAME(mp, tp, src_dp, src_name, src_namelen, + src_ip->i_ino, &first_block, &free_list, spaceres); + if (error) { + rename_which_error_return = __LINE__; + goto abort_return; + } + xfs_ichgtime(src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + /* + * Update the generation counts on all the directory inodes + * that we're modifying. + */ + src_dp->i_gen++; + xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE); + + if (new_parent) { + target_dp->i_gen++; + xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE); + } + + /* + * If there was a target inode, take an extra reference on + * it here so that it doesn't go to xfs_inactive() from + * within the commit. + */ + if (target_ip != NULL) { + IHOLD(target_ip); + } + + /* + * If this is a synchronous mount, make sure that the + * rename transaction goes to disk before returning to + * the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + /* + * Take refs. for vop_link_removed calls below. No need to worry + * about directory refs. because the caller holds them. + * + * Do holds before the xfs_bmap_finish since it might rele them down + * to zero. + */ + + if (target_ip_dropped) + IHOLD(target_ip); + IHOLD(src_ip); + + error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); + if (error) { + xfs_bmap_cancel(&free_list); + xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT)); + if (target_ip != NULL) { + IRELE(target_ip); + } + if (target_ip_dropped) { + IRELE(target_ip); + } + IRELE(src_ip); + goto std_return; + } + + /* + * trans_commit will unlock src_ip, target_ip & decrement + * the vnode references. + */ + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (target_ip != NULL) { + xfs_refcache_purge_ip(target_ip); + IRELE(target_ip); + } + /* + * Let interposed file systems know about removed links. + */ + if (target_ip_dropped) { + VOP_LINK_REMOVED(XFS_ITOV(target_ip), target_dir_vp, + target_link_zero); + IRELE(target_ip); + } + + FSC_NOTIFY_NAME_CHANGED(XFS_ITOV(src_ip)); + + IRELE(src_ip); + + /* Fall through to std_return with error = 0 or errno from + * xfs_trans_commit */ +std_return: + if (DM_EVENT_ENABLED(src_dir_vp->v_vfsp, src_dp, DM_EVENT_POSTRENAME) || + DM_EVENT_ENABLED(target_dir_vp->v_vfsp, + target_dp, DM_EVENT_POSTRENAME)) { + (void) dm_send_namesp_event(DM_EVENT_POSTRENAME, + src_dir_bdp, DM_RIGHT_NULL, + target_dir_bdp, DM_RIGHT_NULL, + src_name, target_name, + 0, error, 0); + } + return error; + + abort_return: + cancel_flags |= XFS_TRANS_ABORT; + /* FALLTHROUGH */ + error_return: + xfs_bmap_cancel(&free_list); + xfs_trans_cancel(tp, cancel_flags); + goto std_return; + + rele_return: + IRELE(src_ip); + if (target_ip != NULL) { + IRELE(target_ip); + } + goto std_return; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_rtalloc.c linux-2.4-xfs/linux/fs/xfs/xfs_rtalloc.c --- linux-2.4.7/linux/fs/xfs/xfs_rtalloc.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_rtalloc.c Tue Jun 26 16:08:42 2001 @@ -0,0 +1,2428 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Free realtime space allocation for XFS. + */ + +#include +#include + + +/* + * Prototypes for internal functions. + */ + + +STATIC int xfs_rtallocate_range(xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, + xfs_extlen_t, xfs_buf_t**, xfs_fsblock_t *); +STATIC int xfs_rtany_summary(xfs_mount_t *, xfs_trans_t *, int, int, + xfs_rtblock_t, xfs_buf_t **, xfs_fsblock_t *, int *); +STATIC int xfs_rtcheck_range(xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, + xfs_extlen_t, int, xfs_rtblock_t *, int *); +STATIC int xfs_rtfind_back(xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, + xfs_rtblock_t, xfs_rtblock_t *); +STATIC int xfs_rtfind_forw(xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, + xfs_rtblock_t, xfs_rtblock_t *); +STATIC int xfs_rtget_summary( xfs_mount_t *, xfs_trans_t *, int, + xfs_rtblock_t, xfs_buf_t **, xfs_fsblock_t *, xfs_suminfo_t *); +STATIC int xfs_rtmodify_range(xfs_mount_t *, xfs_trans_t *, xfs_rtblock_t, + xfs_extlen_t, int); +STATIC int xfs_rtmodify_summary(xfs_mount_t *, xfs_trans_t *, int, + xfs_rtblock_t, int, xfs_buf_t **, xfs_fsblock_t *); + +/* + * Internal functions. + */ + +/* + * Allocate space to the bitmap or summary file, and zero it, for growfs. + */ +STATIC int /* error */ +xfs_growfs_rt_alloc( + xfs_mount_t *mp, /* file system mount point */ + xfs_extlen_t oblocks, /* old count of blocks */ + xfs_extlen_t nblocks, /* new count of blocks */ + xfs_ino_t ino) /* inode number (bitmap/summary) */ +{ + xfs_fileoff_t bno; /* block number in file */ + xfs_buf_t *bp; /* temporary buffer for zeroing */ + int cancelflags; /* flags for xfs_trans_cancel */ + int committed; /* transaction committed flag */ + xfs_daddr_t d; /* disk block address */ + int error; /* error return value */ + xfs_fsblock_t firstblock; /* first block allocated in xaction */ + xfs_bmap_free_t flist; /* list of freed blocks */ + xfs_fsblock_t fsbno; /* filesystem block for bno */ + xfs_inode_t *ip; /* pointer to incore inode */ + xfs_bmbt_irec_t map; /* block map output */ + int nmap; /* number of block maps */ + int resblks; /* space reservation */ + xfs_trans_t *tp; /* transaction pointer */ + + /* + * Allocate space to the file, as necessary. + */ + while (oblocks < nblocks) { + tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_ALLOC); + resblks = XFS_GROWFSRT_SPACE_RES(mp, nblocks - oblocks); + cancelflags = 0; + /* + * Reserve space & log for one extent added to the file. + */ + if ((error = xfs_trans_reserve(tp, resblks, + XFS_GROWRTALLOC_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_DEFAULT_PERM_LOG_COUNT))) + goto error_exit; + cancelflags = XFS_TRANS_RELEASE_LOG_RES; + /* + * Lock the inode. + */ + if ((error = xfs_trans_iget(mp, tp, ino, XFS_ILOCK_EXCL, &ip))) + goto error_exit; + XFS_BMAP_INIT(&flist, &firstblock); + /* + * Allocate blocks to the bitmap file. + */ + nmap = 1; + cancelflags |= XFS_TRANS_ABORT; + error = xfs_bmapi(tp, ip, oblocks, nblocks - oblocks, + XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, &firstblock, + resblks, &map, &nmap, &flist); + if (!error && nmap < 1) + error = XFS_ERROR(ENOSPC); + if (error) + goto error_exit; + /* + * Free any blocks freed up in the transaction, then commit. + */ + error = xfs_bmap_finish(&tp, &flist, firstblock, &committed); + if (error) + goto error_exit; + xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + /* + * Now we need to clear the allocated blocks. + * Do this one block per transaction, to keep it simple. + */ + cancelflags = 0; + for (bno = map.br_startoff, fsbno = map.br_startblock; + bno < map.br_startoff + map.br_blockcount; + bno++, fsbno++) { + tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_ZERO); + /* + * Reserve log for one block zeroing. + */ + if ((error = xfs_trans_reserve(tp, 0, + XFS_GROWRTZERO_LOG_RES(mp), 0, 0, 0))) + goto error_exit; + /* + * Lock the bitmap inode. + */ + if ((error = xfs_trans_iget(mp, tp, ino, XFS_ILOCK_EXCL, + &ip))) + goto error_exit; + /* + * Get a buffer for the block. + */ + d = XFS_FSB_TO_DADDR(mp, fsbno); + bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, + mp->m_bsize, 0); + if (bp == NULL) { + error = XFS_ERROR(EIO); + goto error_exit; + } + bzero(XFS_BUF_PTR(bp), mp->m_sb.sb_blocksize); + xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1); + /* + * Commit the transaction. + */ + xfs_trans_commit(tp, 0, NULL); + } + /* + * Go on to the next extent, if any. + */ + oblocks = map.br_startoff + map.br_blockcount; + } + return 0; +error_exit: + xfs_trans_cancel(tp, cancelflags); + return error; +} + +/* + * Attempt to allocate an extent minlen<=len<=maxlen starting from + * bitmap block bbno. If we don't get maxlen then use prod to trim + * the length, if given. Returns error; returns starting block in *rtblock. + * The lengths are all in rtextents. + */ +STATIC int /* error */ +xfs_rtallocate_extent_block( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t bbno, /* bitmap block number */ + xfs_extlen_t minlen, /* minimum length to allocate */ + xfs_extlen_t maxlen, /* maximum length to allocate */ + xfs_extlen_t *len, /* out: actual length allocated */ + xfs_rtblock_t *nextp, /* out: next block to try */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb, /* in/out: summary block number */ + xfs_extlen_t prod, /* extent product factor */ + xfs_rtblock_t *rtblock) /* out: start block allocated */ +{ + xfs_rtblock_t besti; /* best rtblock found so far */ + xfs_rtblock_t bestlen; /* best length found so far */ + xfs_rtblock_t end; /* last rtblock in chunk */ + int error; /* error value */ + xfs_rtblock_t i; /* current rtblock trying */ + xfs_rtblock_t next; /* next rtblock to try */ + int stat; /* status from internal calls */ + + /* + * Loop over all the extents starting in this bitmap block, + * looking for one that's long enough. + */ + for (i = XFS_BLOCKTOBIT(mp, bbno), besti = -1, bestlen = 0, + end = XFS_BLOCKTOBIT(mp, bbno + 1) - 1; + i <= end; + i++) { + /* + * See if there's a free extent of maxlen starting at i. + * If it's not so then next will contain the first non-free. + */ + error = xfs_rtcheck_range(mp, tp, i, maxlen, 1, &next, &stat); + if (error) { + return error; + } + if (stat) { + /* + * i for maxlen is all free, allocate and return that. + */ + error = xfs_rtallocate_range(mp, tp, i, maxlen, rbpp, + rsb); + if (error) { + return error; + } + *len = maxlen; + *rtblock = i; + return 0; + } + /* + * In the case where we have a variable-sized allocation + * request, figure out how big this free piece is, + * and if it's big enough for the minimum, and the best + * so far, remember it. + */ + if (minlen < maxlen) { + xfs_rtblock_t thislen; /* this extent size */ + + thislen = next - i; + if (thislen >= minlen && thislen > bestlen) { + besti = i; + bestlen = thislen; + } + } + /* + * If not done yet, find the start of the next free space. + */ + if (next < end) { + error = xfs_rtfind_forw(mp, tp, next, end, &i); + if (error) { + return error; + } + } else + break; + } + /* + * Searched the whole thing & didn't find a maxlen free extent. + */ + if (minlen < maxlen && besti != -1) { + xfs_extlen_t p; /* amount to trim length by */ + + /* + * If size should be a multiple of prod, make that so. + */ + if (prod > 1 && (p = do_mod(bestlen, prod))) + bestlen -= p; + /* + * Allocate besti for bestlen & return that. + */ + error = xfs_rtallocate_range(mp, tp, besti, bestlen, rbpp, rsb); + if (error) { + return error; + } + *len = bestlen; + *rtblock = besti; + return 0; + } + /* + * Allocation failed. Set *nextp to the next block to try. + */ + *nextp = next; + *rtblock = NULLRTBLOCK; + return 0; +} + +/* + * Allocate an extent of length minlen<=len<=maxlen, starting at block + * bno. If we don't get maxlen then use prod to trim the length, if given. + * Returns error; returns starting block in *rtblock. + * The lengths are all in rtextents. + */ +STATIC int /* error */ +xfs_rtallocate_extent_exact( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number to allocate */ + xfs_extlen_t minlen, /* minimum length to allocate */ + xfs_extlen_t maxlen, /* maximum length to allocate */ + xfs_extlen_t *len, /* out: actual length allocated */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb, /* in/out: summary block number */ + xfs_extlen_t prod, /* extent product factor */ + xfs_rtblock_t *rtblock) /* out: start block allocated */ +{ + int error; /* error value */ + xfs_extlen_t i; /* extent length trimmed due to prod */ + int isfree; /* extent is free */ + xfs_rtblock_t next; /* next block to try (dummy) */ + + ASSERT(minlen % prod == 0 && maxlen % prod == 0); + /* + * Check if the range in question (for maxlen) is free. + */ + error = xfs_rtcheck_range(mp, tp, bno, maxlen, 1, &next, &isfree); + if (error) { + return error; + } + if (isfree) { + /* + * If it is, allocate it and return success. + */ + error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb); + if (error) { + return error; + } + *len = maxlen; + *rtblock = bno; + return 0; + } + /* + * If not, allocate what there is, if it's at least minlen. + */ + maxlen = next - bno; + if (maxlen < minlen) { + /* + * Failed, return failure status. + */ + *rtblock = NULLRTBLOCK; + return 0; + } + /* + * Trim off tail of extent, if prod is specified. + */ + if (prod > 1 && (i = maxlen % prod)) { + maxlen -= i; + if (maxlen < minlen) { + /* + * Now we can't do it, return failure status. + */ + *rtblock = NULLRTBLOCK; + return 0; + } + } + /* + * Allocate what we can and return it. + */ + error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb); + if (error) { + return error; + } + *len = maxlen; + *rtblock = bno; + return 0; +} + +/* + * Allocate an extent of length minlen<=len<=maxlen, starting as near + * to bno as possible. If we don't get maxlen then use prod to trim + * the length, if given. The lengths are all in rtextents. + */ +STATIC int /* error */ +xfs_rtallocate_extent_near( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number to allocate */ + xfs_extlen_t minlen, /* minimum length to allocate */ + xfs_extlen_t maxlen, /* maximum length to allocate */ + xfs_extlen_t *len, /* out: actual length allocated */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb, /* in/out: summary block number */ + xfs_extlen_t prod, /* extent product factor */ + xfs_rtblock_t *rtblock) /* out: start block allocated */ +{ + int any; /* any useful extents from summary */ + xfs_rtblock_t bbno; /* bitmap block number */ + int error; /* error value */ + int i; /* bitmap block offset (loop control) */ + int j; /* secondary loop control */ + int log2len; /* log2 of minlen */ + xfs_rtblock_t n; /* next block to try */ + xfs_rtblock_t r; /* result block */ + + ASSERT(minlen % prod == 0 && maxlen % prod == 0); + /* + * If the block number given is off the end, silently set it to + * the last block. + */ + if (bno >= mp->m_sb.sb_rextents) + bno = mp->m_sb.sb_rextents - 1; + /* + * Try the exact allocation first. + */ + error = xfs_rtallocate_extent_exact(mp, tp, bno, minlen, maxlen, len, + rbpp, rsb, prod, &r); + if (error) { + return error; + } + /* + * If the exact allocation worked, return that. + */ + if (r != NULLRTBLOCK) { + *rtblock = r; + return 0; + } + bbno = XFS_BITTOBLOCK(mp, bno); + i = 0; + log2len = xfs_highbit32(minlen); + /* + * Loop over all bitmap blocks (bbno + i is current block). + */ + for (;;) { + /* + * Get summary information of extents of all useful levels + * starting in this bitmap block. + */ + error = xfs_rtany_summary(mp, tp, log2len, mp->m_rsumlevels - 1, + bbno + i, rbpp, rsb, &any); + if (error) { + return error; + } + /* + * If there are any useful extents starting here, try + * allocating one. + */ + if (any) { + /* + * On the positive side of the starting location. + */ + if (i >= 0) { + /* + * Try to allocate an extent starting in + * this block. + */ + error = xfs_rtallocate_extent_block(mp, tp, + bbno + i, minlen, maxlen, len, &n, rbpp, + rsb, prod, &r); + if (error) { + return error; + } + /* + * If it worked, return it. + */ + if (r != NULLRTBLOCK) { + *rtblock = r; + return 0; + } + } + /* + * On the negative side of the starting location. + */ + else { /* i < 0 */ + /* + * Loop backwards through the bitmap blocks from + * the starting point-1 up to where we are now. + * There should be an extent which ends in this + * bitmap block and is long enough. + */ + for (j = -1; j > i; j--) { + /* + * Grab the summary information for + * this bitmap block. + */ + error = xfs_rtany_summary(mp, tp, + log2len, mp->m_rsumlevels - 1, + bbno + j, rbpp, rsb, &any); + if (error) { + return error; + } + /* + * If there's no extent given in the + * summary that means the extent we + * found must carry over from an + * earlier block. If there is an + * extent given, we've already tried + * that allocation, don't do it again. + */ + if (any) + continue; + error = xfs_rtallocate_extent_block(mp, + tp, bbno + j, minlen, maxlen, + len, &n, rbpp, rsb, prod, &r); + if (error) { + return error; + } + /* + * If it works, return the extent. + */ + if (r != NULLRTBLOCK) { + *rtblock = r; + return 0; + } + } + /* + * There weren't intervening bitmap blocks + * with a long enough extent, or the + * allocation didn't work for some reason + * (i.e. it's a little * too short). + * Try to allocate from the summary block + * that we found. + */ + error = xfs_rtallocate_extent_block(mp, tp, + bbno + i, minlen, maxlen, len, &n, rbpp, + rsb, prod, &r); + if (error) { + return error; + } + /* + * If it works, return the extent. + */ + if (r != NULLRTBLOCK) { + *rtblock = r; + return 0; + } + } + } + /* + * Loop control. If we were on the positive side, and there's + * still more blocks on the negative side, go there. + */ + if (i > 0 && (int)bbno - i >= 0) + i = -i; + /* + * If positive, and no more negative, but there are more + * positive, go there. + */ + else if (i > 0 && (int)bbno + i < mp->m_sb.sb_rbmblocks - 1) + i++; + /* + * If negative or 0 (just started), and there are positive + * blocks to go, go there. The 0 case moves to block 1. + */ + else if (i <= 0 && (int)bbno - i < mp->m_sb.sb_rbmblocks - 1) + i = 1 - i; + /* + * If negative or 0 and there are more negative blocks, + * go there. + */ + else if (i <= 0 && (int)bbno + i > 0) + i--; + /* + * Must be done. Return failure. + */ + else + break; + } + *rtblock = NULLRTBLOCK; + return 0; +} + +/* + * Allocate an extent of length minlen<=len<=maxlen, with no position + * specified. If we don't get maxlen then use prod to trim + * the length, if given. The lengths are all in rtextents. + */ +STATIC int /* error */ +xfs_rtallocate_extent_size( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_extlen_t minlen, /* minimum length to allocate */ + xfs_extlen_t maxlen, /* maximum length to allocate */ + xfs_extlen_t *len, /* out: actual length allocated */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb, /* in/out: summary block number */ + xfs_extlen_t prod, /* extent product factor */ + xfs_rtblock_t *rtblock) /* out: start block allocated */ +{ + int error; /* error value */ + int i; /* bitmap block number */ + int l; /* level number (loop control) */ + xfs_rtblock_t n; /* next block to be tried */ + xfs_rtblock_t r; /* result block number */ + xfs_suminfo_t sum; /* summary information for extents */ + + ASSERT(minlen % prod == 0 && maxlen % prod == 0); + /* + * Loop over all the levels starting with maxlen. + * At each level, look at all the bitmap blocks, to see if there + * are extents starting there that are long enough (>= maxlen). + * Note, only on the initial level can the allocation fail if + * the summary says there's an extent. + */ + for (l = xfs_highbit32(maxlen); l < mp->m_rsumlevels; l++) { + /* + * Loop over all the bitmap blocks. + */ + for (i = 0; i < mp->m_sb.sb_rbmblocks; i++) { + /* + * Get the summary for this level/block. + */ + error = xfs_rtget_summary(mp, tp, l, i, rbpp, rsb, + &sum); + if (error) { + return error; + } + /* + * Nothing there, on to the next block. + */ + if (!sum) + continue; + /* + * Try allocating the extent. + */ + error = xfs_rtallocate_extent_block(mp, tp, i, maxlen, + maxlen, len, &n, rbpp, rsb, prod, &r); + if (error) { + return error; + } + /* + * If it worked, return that. + */ + if (r != NULLRTBLOCK) { + *rtblock = r; + return 0; + } + /* + * If the "next block to try" returned from the + * allocator is beyond the next bitmap block, + * skip to that bitmap block. + */ + if (XFS_BITTOBLOCK(mp, n) > i + 1) + i = XFS_BITTOBLOCK(mp, n) - 1; + } + } + /* + * Didn't find any maxlen blocks. Try smaller ones, unless + * we're asking for a fixed size extent. + */ + if (minlen > --maxlen) { + *rtblock = NULLRTBLOCK; + return 0; + } + /* + * Loop over sizes, from maxlen down to minlen. + * This time, when we do the allocations, allow smaller ones + * to succeed. + */ + for (l = xfs_highbit32(maxlen); l >= xfs_highbit32(minlen); l--) { + /* + * Loop over all the bitmap blocks, try an allocation + * starting in that block. + */ + for (i = 0; i < mp->m_sb.sb_rbmblocks; i++) { + /* + * Get the summary information for this level/block. + */ + error = xfs_rtget_summary(mp, tp, l, i, rbpp, rsb, + &sum); + if (error) { + return error; + } + /* + * If nothing there, go on to next. + */ + if (!sum) + continue; + /* + * Try the allocation. Make sure the specified + * minlen/maxlen are in the possible range for + * this summary level. + */ + error = xfs_rtallocate_extent_block(mp, tp, i, + XFS_RTMAX(minlen, 1 << l), + XFS_RTMIN(maxlen, (1 << (l + 1)) - 1), + len, &n, rbpp, rsb, prod, &r); + if (error) { + return error; + } + /* + * If it worked, return that extent. + */ + if (r != NULLRTBLOCK) { + *rtblock = r; + return 0; + } + /* + * If the "next block to try" returned from the + * allocator is beyond the next bitmap block, + * skip to that bitmap block. + */ + if (XFS_BITTOBLOCK(mp, n) > i + 1) + i = XFS_BITTOBLOCK(mp, n) - 1; + } + } + /* + * Got nothing, return failure. + */ + *rtblock = NULLRTBLOCK; + return 0; +} + +/* + * Mark an extent specified by start and len allocated. + * Updates all the summary information as well as the bitmap. + */ +STATIC int /* error */ +xfs_rtallocate_range( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* start block to allocate */ + xfs_extlen_t len, /* length to allocate */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb) /* in/out: summary block number */ +{ + xfs_rtblock_t end; /* end of the allocated extent */ + int error; /* error value */ + xfs_rtblock_t postblock; /* first block allocated > end */ + xfs_rtblock_t preblock; /* first block allocated < start */ + + end = start + len - 1; + /* + * Assume we're allocating out of the middle of a free extent. + * We need to find the beginning and end of the extent so we can + * properly update the summary. + */ + error = xfs_rtfind_back(mp, tp, start, 0, &preblock); + if (error) { + return error; + } + /* + * Find the next allocated block (end of free extent). + */ + error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1, + &postblock); + if (error) { + return error; + } + /* + * Decrement the summary information corresponding to the entire + * (old) free extent. + */ + error = xfs_rtmodify_summary(mp, tp, + XFS_RTBLOCKLOG(postblock + 1 - preblock), + XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb); + if (error) { + return error; + } + /* + * If there are blocks not being allocated at the front of the + * old extent, add summary data for them to be free. + */ + if (preblock < start) { + error = xfs_rtmodify_summary(mp, tp, + XFS_RTBLOCKLOG(start - preblock), + XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb); + if (error) { + return error; + } + } + /* + * If there are blocks not being allocated at the end of the + * old extent, add summary data for them to be free. + */ + if (postblock > end) { + error = xfs_rtmodify_summary(mp, tp, + XFS_RTBLOCKLOG(postblock - end), + XFS_BITTOBLOCK(mp, end + 1), 1, rbpp, rsb); + if (error) { + return error; + } + } + /* + * Modify the bitmap to mark this extent allocated. + */ + error = xfs_rtmodify_range(mp, tp, start, len, 0); + return error; +} + +/* + * Return whether there are any free extents in the size range given + * by low and high, for the bitmap block bbno. + */ +STATIC int /* error */ +xfs_rtany_summary( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + int low, /* low log2 extent size */ + int high, /* high log2 extent size */ + xfs_rtblock_t bbno, /* bitmap block number */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb, /* in/out: summary block number */ + int *stat) /* out: any good extents here? */ +{ + int error; /* error value */ + int log; /* loop counter, log2 of ext. size */ + xfs_suminfo_t sum; /* summary data */ + + /* + * Loop over logs of extent sizes. Order is irrelevant. + */ + for (log = low; log <= high; log++) { + /* + * Get one summary datum. + */ + error = xfs_rtget_summary(mp, tp, log, bbno, rbpp, rsb, &sum); + if (error) { + return error; + } + /* + * If there are any, return success. + */ + if (sum) { + *stat = 1; + return 0; + } + } + /* + * Found nothing, return failure. + */ + *stat = 0; + return 0; +} + +/* + * Get a buffer for the bitmap or summary file block specified. + * The buffer is returned read and locked. + */ +STATIC int /* error */ +xfs_rtbuf_get( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t block, /* block number in bitmap or summary */ + int issum, /* is summary not bitmap */ + xfs_buf_t **bpp) /* output: buffer for the block */ +{ + xfs_buf_t *bp; /* block buffer, result */ + xfs_daddr_t d; /* disk addr of block */ + int error; /* error value */ + xfs_fsblock_t fsb; /* fs block number for block */ + xfs_inode_t *ip; /* bitmap or summary inode */ + + ip = issum ? mp->m_rsumip : mp->m_rbmip; + /* + * Map from the file offset (block) and inode number to the + * file system block. + */ + error = xfs_bmapi_single(tp, ip, XFS_DATA_FORK, &fsb, block); + if (error) { + return error; + } + ASSERT(fsb != NULLFSBLOCK); + /* + * Convert to disk address for buffer cache. + */ + d = XFS_FSB_TO_DADDR(mp, fsb); + /* + * Read the buffer. + */ + error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, + mp->m_bsize, 0, &bp); + if (error) { + return error; + } + ASSERT(bp && !XFS_BUF_GETERROR(bp)); + *bpp = bp; + return 0; +} + +#ifdef DEBUG +/* + * Check that the given extent (block range) is allocated already. + */ +STATIC int /* error */ +xfs_rtcheck_alloc_range( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat) /* out: 1 for allocated, 0 for not */ +{ + xfs_rtblock_t new; /* dummy for xfs_rtcheck_range */ + + return xfs_rtcheck_range(mp, tp, bno, len, 0, &new, stat); +} +#endif + +#ifdef DEBUG +/* + * Check whether the given block in the bitmap has the given value. + */ +STATIC int /* 1 for matches, 0 for not */ +xfs_rtcheck_bit( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* bit (block) to check */ + int val) /* 1 for free, 0 for allocated */ +{ + int bit; /* bit number in the word */ + xfs_rtblock_t block; /* bitmap block number */ + xfs_buf_t *bp; /* buf for the block */ + xfs_rtword_t *bufp; /* pointer into the buffer */ + /* REFERENCED */ + int error; /* error value */ + xfs_rtword_t wdiff; /* difference between bit & expected */ + int word; /* word number in the buffer */ + xfs_rtword_t wval; /* word value from buffer */ + + block = XFS_BITTOBLOCK(mp, start); + error = xfs_rtbuf_get(mp, tp, block, 0, &bp); + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = XFS_BITTOWORD(mp, start); + bit = (int)(start & (XFS_NBWORD - 1)); + wval = bufp[word]; + xfs_trans_brelse(tp, bp); + wdiff = (wval ^ -val) & ((xfs_rtword_t)1 << bit); + return !wdiff; +} +#endif /* DEBUG */ + +#if 0 +/* + * Check that the given extent (block range) is free already. + */ +STATIC int /* error */ +xfs_rtcheck_free_range( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number of extent */ + xfs_extlen_t len, /* length of extent */ + int *stat) /* out: 1 for free, 0 for not */ +{ + xfs_rtblock_t new; /* dummy for xfs_rtcheck_range */ + + return xfs_rtcheck_range(mp, tp, bno, len, 1, &new, stat); +} +#endif + +/* + * Check that the given range is either all allocated (val = 0) or + * all free (val = 1). + */ +STATIC int /* error */ +xfs_rtcheck_range( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block number of extent */ + xfs_extlen_t len, /* length of extent */ + int val, /* 1 for free, 0 for allocated */ + xfs_rtblock_t *new, /* out: first block not matching */ + int *stat) /* out: 1 for matches, 0 for not */ +{ + xfs_rtword_t *b; /* current word in buffer */ + int bit; /* bit number in the word */ + xfs_rtblock_t block; /* bitmap block number */ + xfs_buf_t *bp; /* buf for the block */ + xfs_rtword_t *bufp; /* starting word in buffer */ + int error; /* error value */ + xfs_rtblock_t i; /* current bit number rel. to start */ + xfs_rtblock_t lastbit; /* last useful bit in word */ + xfs_rtword_t mask; /* mask of relevant bits for value */ + xfs_rtword_t wdiff; /* difference from wanted value */ + int word; /* word number in the buffer */ + + /* + * Compute starting bitmap block number + */ + block = XFS_BITTOBLOCK(mp, start); + /* + * Read the bitmap block. + */ + error = xfs_rtbuf_get(mp, tp, block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + /* + * Compute the starting word's address, and starting bit. + */ + word = XFS_BITTOWORD(mp, start); + b = &bufp[word]; + bit = (int)(start & (XFS_NBWORD - 1)); + /* + * 0 (allocated) => all zero's; 1 (free) => all one's. + */ + val = -val; + /* + * If not starting on a word boundary, deal with the first + * (partial) word. + */ + if (bit) { + /* + * Compute first bit not examined. + */ + lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); + /* + * Mask of relevant bits. + */ + mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = (*b ^ val) & mask)) { + /* + * Different, compute first wrong bit and return. + */ + xfs_trans_brelse(tp, bp); + i = XFS_RTLOBIT(wdiff) - bit; + *new = start + i; + *stat = 0; + return 0; + } + i = lastbit - bit; + /* + * Go on to next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * If done with this block, get the next one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the next word in the buffer. + */ + b++; + } + } else { + /* + * Starting on a word boundary, no partial word. + */ + i = 0; + } + /* + * Loop over whole words in buffers. When we use up one buffer + * we move on to the next one. + */ + while (len - i >= XFS_NBWORD) { + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = *b ^ val)) { + /* + * Different, compute first wrong bit and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_RTLOBIT(wdiff); + *new = start + i; + *stat = 0; + return 0; + } + i += XFS_NBWORD; + /* + * Go on to next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * If done with this block, get the next one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the next word in the buffer. + */ + b++; + } + } + /* + * If not ending on a word boundary, deal with the last + * (partial) word. + */ + if ((lastbit = len - i)) { + /* + * Mask of relevant bits. + */ + mask = ((xfs_rtword_t)1 << lastbit) - 1; + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = (*b ^ val) & mask)) { + /* + * Different, compute first wrong bit and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_RTLOBIT(wdiff); + *new = start + i; + *stat = 0; + return 0; + } else + i = len; + } + /* + * Successful, return. + */ + xfs_trans_brelse(tp, bp); + *new = start + i; + *stat = 1; + return 0; +} + +/* + * Copy and transform the summary file, given the old and new + * parameters in the mount structures. + */ +STATIC int /* error */ +xfs_rtcopy_summary( + xfs_mount_t *omp, /* old file system mount point */ + xfs_mount_t *nmp, /* new file system mount point */ + xfs_trans_t *tp) /* transaction pointer */ +{ + xfs_rtblock_t bbno; /* bitmap block number */ + xfs_buf_t *bp; /* summary buffer */ + int error; /* error return value */ + int log; /* summary level number (log length) */ + xfs_suminfo_t sum; /* summary data */ + xfs_fsblock_t sumbno; /* summary block number */ + + bp = NULL; + for (log = omp->m_rsumlevels - 1; log >= 0; log--) { + for (bbno = omp->m_sb.sb_rbmblocks - 1; + (xfs_srtblock_t)bbno >= 0; + bbno--) { + error = xfs_rtget_summary(omp, tp, log, bbno, &bp, + &sumbno, &sum); + if (error) + return error; + if (sum == 0) + continue; + error = xfs_rtmodify_summary(omp, tp, log, bbno, -sum, + &bp, &sumbno); + if (error) + return error; + error = xfs_rtmodify_summary(nmp, tp, log, bbno, sum, + &bp, &sumbno); + if (error) + return error; + ASSERT(sum > 0); + } + } + return 0; +} + +/* + * Searching backward from start to limit, find the first block whose + * allocated/free state is different from start's. + */ +STATIC int /* error */ +xfs_rtfind_back( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to look at */ + xfs_rtblock_t limit, /* last block to look at */ + xfs_rtblock_t *rtblock) /* out: start block found */ +{ + xfs_rtword_t *b; /* current word in buffer */ + int bit; /* bit number in the word */ + xfs_rtblock_t block; /* bitmap block number */ + xfs_buf_t *bp; /* buf for the block */ + xfs_rtword_t *bufp; /* starting word in buffer */ + int error; /* error value */ + xfs_rtblock_t firstbit; /* first useful bit in the word */ + xfs_rtblock_t i; /* current bit number rel. to start */ + xfs_rtblock_t len; /* length of inspected area */ + xfs_rtword_t mask; /* mask of relevant bits for value */ + xfs_rtword_t want; /* mask for "good" values */ + xfs_rtword_t wdiff; /* difference from wanted value */ + int word; /* word number in the buffer */ + + /* + * Compute and read in starting bitmap block for starting block. + */ + block = XFS_BITTOBLOCK(mp, start); + error = xfs_rtbuf_get(mp, tp, block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + /* + * Get the first word's index & point to it. + */ + word = XFS_BITTOWORD(mp, start); + b = &bufp[word]; + bit = (int)(start & (XFS_NBWORD - 1)); + len = start - limit + 1; + /* + * Compute match value, based on the bit at start: if 1 (free) + * then all-ones, else all-zeroes. + */ + want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0; + /* + * If the starting position is not word-aligned, deal with the + * partial word. + */ + if (bit < XFS_NBWORD - 1) { + /* + * Calculate first (leftmost) bit number to look at, + * and mask for all the relevant bits in this word. + */ + firstbit = XFS_RTMAX((xfs_srtblock_t)(bit - len + 1), 0); + mask = (((xfs_rtword_t)1 << (bit - firstbit + 1)) - 1) << + firstbit; + /* + * Calculate the difference between the value there + * and what we're looking for. + */ + if ((wdiff = (*b ^ want) & mask)) { + /* + * Different. Mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i = bit - XFS_RTHIBIT(wdiff); + *rtblock = start - i + 1; + return 0; + } + i = bit - firstbit + 1; + /* + * Go on to previous block if that's where the previous word is + * and we need the previous word. + */ + if (--word == -1 && i < len) { + /* + * If done with this block, get the previous one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, --block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = XFS_BLOCKWMASK(mp); + b = &bufp[word]; + } else { + /* + * Go on to the previous word in the buffer. + */ + b--; + } + } else { + /* + * Starting on a word boundary, no partial word. + */ + i = 0; + } + /* + * Loop over whole words in buffers. When we use up one buffer + * we move on to the previous one. + */ + while (len - i >= XFS_NBWORD) { + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = *b ^ want)) { + /* + * Different, mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff); + *rtblock = start - i + 1; + return 0; + } + i += XFS_NBWORD; + /* + * Go on to previous block if that's where the previous word is + * and we need the previous word. + */ + if (--word == -1 && i < len) { + /* + * If done with this block, get the previous one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, --block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = XFS_BLOCKWMASK(mp); + b = &bufp[word]; + } else { + /* + * Go on to the previous word in the buffer. + */ + b--; + } + } + /* + * If not ending on a word boundary, deal with the last + * (partial) word. + */ + if (len - i) { + /* + * Calculate first (leftmost) bit number to look at, + * and mask for all the relevant bits in this word. + */ + firstbit = XFS_NBWORD - (len - i); + mask = (((xfs_rtword_t)1 << (len - i)) - 1) << firstbit; + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = (*b ^ want) & mask)) { + /* + * Different, mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff); + *rtblock = start - i + 1; + return 0; + } else + i = len; + } + /* + * No match, return that we scanned the whole area. + */ + xfs_trans_brelse(tp, bp); + *rtblock = start - i + 1; + return 0; +} + +/* + * Searching forward from start to limit, find the first block whose + * allocated/free state is different from start's. + */ +STATIC int /* error */ +xfs_rtfind_forw( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to look at */ + xfs_rtblock_t limit, /* last block to look at */ + xfs_rtblock_t *rtblock) /* out: start block found */ +{ + xfs_rtword_t *b; /* current word in buffer */ + int bit; /* bit number in the word */ + xfs_rtblock_t block; /* bitmap block number */ + xfs_buf_t *bp; /* buf for the block */ + xfs_rtword_t *bufp; /* starting word in buffer */ + int error; /* error value */ + xfs_rtblock_t i; /* current bit number rel. to start */ + xfs_rtblock_t lastbit; /* last useful bit in the word */ + xfs_rtblock_t len; /* length of inspected area */ + xfs_rtword_t mask; /* mask of relevant bits for value */ + xfs_rtword_t want; /* mask for "good" values */ + xfs_rtword_t wdiff; /* difference from wanted value */ + int word; /* word number in the buffer */ + + /* + * Compute and read in starting bitmap block for starting block. + */ + block = XFS_BITTOBLOCK(mp, start); + error = xfs_rtbuf_get(mp, tp, block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + /* + * Get the first word's index & point to it. + */ + word = XFS_BITTOWORD(mp, start); + b = &bufp[word]; + bit = (int)(start & (XFS_NBWORD - 1)); + len = limit - start + 1; + /* + * Compute match value, based on the bit at start: if 1 (free) + * then all-ones, else all-zeroes. + */ + want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0; + /* + * If the starting position is not word-aligned, deal with the + * partial word. + */ + if (bit) { + /* + * Calculate last (rightmost) bit number to look at, + * and mask for all the relevant bits in this word. + */ + lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); + mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; + /* + * Calculate the difference between the value there + * and what we're looking for. + */ + if ((wdiff = (*b ^ want) & mask)) { + /* + * Different. Mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i = XFS_RTLOBIT(wdiff) - bit; + *rtblock = start + i - 1; + return 0; + } + i = lastbit - bit; + /* + * Go on to next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * If done with this block, get the previous one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the previous word in the buffer. + */ + b++; + } + } else { + /* + * Starting on a word boundary, no partial word. + */ + i = 0; + } + /* + * Loop over whole words in buffers. When we use up one buffer + * we move on to the next one. + */ + while (len - i >= XFS_NBWORD) { + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = *b ^ want)) { + /* + * Different, mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_RTLOBIT(wdiff); + *rtblock = start + i - 1; + return 0; + } + i += XFS_NBWORD; + /* + * Go on to next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * If done with this block, get the next one. + */ + xfs_trans_brelse(tp, bp); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the next word in the buffer. + */ + b++; + } + } + /* + * If not ending on a word boundary, deal with the last + * (partial) word. + */ + if ((lastbit = len - i)) { + /* + * Calculate mask for all the relevant bits in this word. + */ + mask = ((xfs_rtword_t)1 << lastbit) - 1; + /* + * Compute difference between actual and desired value. + */ + if ((wdiff = (*b ^ want) & mask)) { + /* + * Different, mark where we are and return. + */ + xfs_trans_brelse(tp, bp); + i += XFS_RTLOBIT(wdiff); + *rtblock = start + i - 1; + return 0; + } else + i = len; + } + /* + * No match, return that we scanned the whole area. + */ + xfs_trans_brelse(tp, bp); + *rtblock = start + i - 1; + return 0; +} + +/* + * Mark an extent specified by start and len freed. + * Updates all the summary information as well as the bitmap. + */ +STATIC int /* error */ +xfs_rtfree_range( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to free */ + xfs_extlen_t len, /* length to free */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb) /* in/out: summary block number */ +{ + xfs_rtblock_t end; /* end of the freed extent */ + int error; /* error value */ + xfs_rtblock_t postblock; /* first block freed > end */ + xfs_rtblock_t preblock; /* first block freed < start */ + + end = start + len - 1; + /* + * Modify the bitmap to mark this extent freed. + */ + error = xfs_rtmodify_range(mp, tp, start, len, 1); + if (error) { + return error; + } + /* + * Assume we're freeing out of the middle of an allocated extent. + * We need to find the beginning and end of the extent so we can + * properly update the summary. + */ + error = xfs_rtfind_back(mp, tp, start, 0, &preblock); + if (error) { + return error; + } + /* + * Find the next allocated block (end of allocated extent). + */ + error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1, + &postblock); + /* + * If there are blocks not being freed at the front of the + * old extent, add summary data for them to be allocated. + */ + if (preblock < start) { + error = xfs_rtmodify_summary(mp, tp, + XFS_RTBLOCKLOG(start - preblock), + XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb); + if (error) { + return error; + } + } + /* + * If there are blocks not being freed at the end of the + * old extent, add summary data for them to be allocated. + */ + if (postblock > end) { + error = xfs_rtmodify_summary(mp, tp, + XFS_RTBLOCKLOG(postblock - end), + XFS_BITTOBLOCK(mp, end + 1), -1, rbpp, rsb); + if (error) { + return error; + } + } + /* + * Increment the summary information corresponding to the entire + * (new) free extent. + */ + error = xfs_rtmodify_summary(mp, tp, + XFS_RTBLOCKLOG(postblock + 1 - preblock), + XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb); + return error; +} + +/* + * Read and return the summary information for a given extent size, + * bitmap block combination. + * Keeps track of a current summary block, so we don't keep reading + * it from the buffer cache. + */ +STATIC int /* error */ +xfs_rtget_summary( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + int log, /* log2 of extent size */ + xfs_rtblock_t bbno, /* bitmap block number */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb, /* in/out: summary block number */ + xfs_suminfo_t *sum) /* out: summary info for this block */ +{ + xfs_buf_t *bp; /* buffer for summary block */ + int error; /* error value */ + xfs_fsblock_t sb; /* summary fsblock */ + int so; /* index into the summary file */ + xfs_suminfo_t *sp; /* pointer to returned data */ + + /* + * Compute entry number in the summary file. + */ + so = XFS_SUMOFFS(mp, log, bbno); + /* + * Compute the block number in the summary file. + */ + sb = XFS_SUMOFFSTOBLOCK(mp, so); + /* + * If we have an old buffer, and the block number matches, use that. + */ + if (rbpp && *rbpp && *rsb == sb) + bp = *rbpp; + /* + * Otherwise we have to get the buffer. + */ + else { + /* + * If there was an old one, get rid of it first. + */ + if (rbpp && *rbpp) + xfs_trans_brelse(tp, *rbpp); + error = xfs_rtbuf_get(mp, tp, sb, 1, &bp); + if (error) { + return error; + } + /* + * Remember this buffer and block for the next call. + */ + if (rbpp) { + *rbpp = bp; + *rsb = sb; + } + } + /* + * Point to the summary information & copy it out. + */ + sp = XFS_SUMPTR(mp, bp, so); + *sum = *sp; + /* + * Drop the buffer if we're not asked to remember it. + */ + if (!rbpp) + xfs_trans_brelse(tp, bp); + return 0; +} + +/* + * Set the given range of bitmap bits to the given value. + * Do whatever I/O and logging is required. + */ +STATIC int /* error */ +xfs_rtmodify_range( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to modify */ + xfs_extlen_t len, /* length of extent to modify */ + int val) /* 1 for free, 0 for allocated */ +{ + xfs_rtword_t *b; /* current word in buffer */ + int bit; /* bit number in the word */ + xfs_rtblock_t block; /* bitmap block number */ + xfs_buf_t *bp; /* buf for the block */ + xfs_rtword_t *bufp; /* starting word in buffer */ + int error; /* error value */ + xfs_rtword_t *first; /* first used word in the buffer */ + int i; /* current bit number rel. to start */ + int lastbit; /* last useful bit in word */ + xfs_rtword_t mask; /* mask o frelevant bits for value */ + int word; /* word number in the buffer */ + + /* + * Compute starting bitmap block number. + */ + block = XFS_BITTOBLOCK(mp, start); + /* + * Read the bitmap block, and point to its data. + */ + error = xfs_rtbuf_get(mp, tp, block, 0, &bp); + if (error) { + return error; + } + bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + /* + * Compute the starting word's address, and starting bit. + */ + word = XFS_BITTOWORD(mp, start); + first = b = &bufp[word]; + bit = (int)(start & (XFS_NBWORD - 1)); + /* + * 0 (allocated) => all zeroes; 1 (free) => all ones. + */ + val = -val; + /* + * If not starting on a word boundary, deal with the first + * (partial) word. + */ + if (bit) { + /* + * Compute first bit not changed and mask of relevant bits. + */ + lastbit = XFS_RTMIN(bit + len, XFS_NBWORD); + mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit; + /* + * Set/clear the active bits. + */ + if (val) + *b |= mask; + else + *b &= ~mask; + i = lastbit - bit; + /* + * Go on to the next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * Log the changed part of this block. + * Get the next one. + */ + xfs_trans_log_buf(tp, bp, + (uint)((char *)first - (char *)bufp), + (uint)((char *)b - (char *)bufp)); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + first = b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the next word in the buffer + */ + b++; + } + } else { + /* + * Starting on a word boundary, no partial word. + */ + i = 0; + } + /* + * Loop over whole words in buffers. When we use up one buffer + * we move on to the next one. + */ + while (len - i >= XFS_NBWORD) { + /* + * Set the word value correctly. + */ + *b = val; + i += XFS_NBWORD; + /* + * Go on to the next block if that's where the next word is + * and we need the next word. + */ + if (++word == XFS_BLOCKWSIZE(mp) && i < len) { + /* + * Log the changed part of this block. + * Get the next one. + */ + xfs_trans_log_buf(tp, bp, + (uint)((char *)first - (char *)bufp), + (uint)((char *)b - (char *)bufp)); + error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp); + if (error) { + return error; + } + first = b = bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); + word = 0; + } else { + /* + * Go on to the next word in the buffer + */ + b++; + } + } + /* + * If not ending on a word boundary, deal with the last + * (partial) word. + */ + if ((lastbit = len - i)) { + /* + * Compute a mask of relevant bits. + */ + bit = 0; + mask = ((xfs_rtword_t)1 << lastbit) - 1; + /* + * Set/clear the active bits. + */ + if (val) + *b |= mask; + else + *b &= ~mask; + b++; + } + /* + * Log any remaining changed bytes. + */ + if (b > first) + xfs_trans_log_buf(tp, bp, (uint)((char *)first - (char *)bufp), + (uint)((char *)b - (char *)bufp - 1)); + return 0; +} + +/* + * Read and modify the summary information for a given extent size, + * bitmap block combination. + * Keeps track of a current summary block, so we don't keep reading + * it from the buffer cache. + */ +STATIC int /* error */ +xfs_rtmodify_summary( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + int log, /* log2 of extent size */ + xfs_rtblock_t bbno, /* bitmap block number */ + int delta, /* change to make to summary info */ + xfs_buf_t **rbpp, /* in/out: summary block buffer */ + xfs_fsblock_t *rsb) /* in/out: summary block number */ +{ + xfs_buf_t *bp; /* buffer for the summary block */ + int error; /* error value */ + xfs_fsblock_t sb; /* summary fsblock */ + int so; /* index into the summary file */ + xfs_suminfo_t *sp; /* pointer to returned data */ + + /* + * Compute entry number in the summary file. + */ + so = XFS_SUMOFFS(mp, log, bbno); + /* + * Compute the block number in the summary file. + */ + sb = XFS_SUMOFFSTOBLOCK(mp, so); + /* + * If we have an old buffer, and the block number matches, use that. + */ + if (rbpp && *rbpp && *rsb == sb) + bp = *rbpp; + /* + * Otherwise we have to get the buffer. + */ + else { + /* + * If there was an old one, get rid of it first. + */ + if (rbpp && *rbpp) + xfs_trans_brelse(tp, *rbpp); + error = xfs_rtbuf_get(mp, tp, sb, 1, &bp); + if (error) { + return error; + } + /* + * Remember this buffer and block for the next call. + */ + if (rbpp) { + *rbpp = bp; + *rsb = sb; + } + } + /* + * Point to the summary information, modify and log it. + */ + sp = XFS_SUMPTR(mp, bp, so); + *sp += delta; + xfs_trans_log_buf(tp, bp, (uint)((char *)sp - (char *)XFS_BUF_PTR(bp)), + (uint)((char *)sp - (char *)XFS_BUF_PTR(bp) + sizeof(*sp) - 1)); + return 0; +} + +/* + * Visible (exported) functions. + */ + +/* + * Grow the realtime area of the filesystem. + */ +int +xfs_growfs_rt( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_growfs_rt_t *in) /* growfs rt input struct */ +{ + xfs_rtblock_t bmbno; /* bitmap block number */ + xfs_buf_t *bp; /* temporary buffer */ + int cancelflags; /* flags for xfs_trans_cancel */ + int error; /* error return value */ + xfs_inode_t *ip; /* bitmap inode, used as lock */ + xfs_mount_t *nmp; /* new (fake) mount structure */ + xfs_drfsbno_t nrblocks; /* new number of realtime blocks */ + xfs_extlen_t nrbmblocks; /* new number of rt bitmap blocks */ + xfs_drtbno_t nrextents; /* new number of realtime extents */ + uint8_t nrextslog; /* new log2 of sb_rextents */ + xfs_extlen_t nrsumblocks; /* new number of summary blocks */ + uint nrsumlevels; /* new rt summary levels */ + uint nrsumsize; /* new size of rt summary, bytes */ + xfs_sb_t *nsbp; /* new superblock */ + xfs_extlen_t rbmblocks; /* current number of rt bitmap blocks */ + xfs_extlen_t rsumblocks; /* current number of rt summary blks */ + xfs_sb_t *sbp; /* old superblock */ + xfs_fsblock_t sumbno; /* summary block number */ + xfs_trans_t *tp; /* transaction pointer */ + + sbp = &mp->m_sb; + /* + * Initial error checking. + */ + if (mp->m_rtdev == NODEV || mp->m_rbmip == NULL || + (nrblocks = in->newblocks) <= sbp->sb_rblocks || + (sbp->sb_rblocks && (in->extsize != sbp->sb_rextsize))) + return XFS_ERROR(EINVAL); + /* + * Read in the last block of the device, make sure it exists. + */ + error = xfs_read_buf(mp, &mp->m_rtdev_targ, + XFS_FSB_TO_BB(mp, in->newblocks) - 1, 1, 0, &bp); + if (error) + return error; + ASSERT(bp); + xfs_buf_relse(bp); + /* + * Calculate new parameters. These are the final values to be reached. + */ + nrextents = do_div(nrblocks, in->extsize); + nrbmblocks = roundup_64(nrextents, NBBY * sbp->sb_blocksize); + nrextslog = xfs_highbit32(nrextents); + nrsumlevels = nrextslog + 1; + nrsumsize = (uint)sizeof(xfs_suminfo_t) * nrsumlevels * nrbmblocks; + nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize); + nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks); + /* + * New summary size can't be more than half the size of + * the log. This prevents us from getting a log overflow, + * since we'll log basically the whole summary file at once. + */ + if (nrsumblocks > (mp->m_sb.sb_logblocks >> 1)) + return XFS_ERROR(EINVAL); + /* + * Get the old block counts for bitmap and summary inodes. + * These can't change since other growfs callers are locked out. + */ + rbmblocks = XFS_B_TO_FSB(mp, mp->m_rbmip->i_d.di_size); + rsumblocks = XFS_B_TO_FSB(mp, mp->m_rsumip->i_d.di_size); + /* + * Allocate space to the bitmap and summary files, as necessary. + */ + if ((error = xfs_growfs_rt_alloc(mp, rbmblocks, nrbmblocks, + mp->m_sb.sb_rbmino))) + return error; + if ((error = xfs_growfs_rt_alloc(mp, rsumblocks, nrsumblocks, + mp->m_sb.sb_rsumino))) + return error; + nmp = NULL; + /* + * Loop over the bitmap blocks. + * We will do everything one bitmap block at a time. + * Skip the current block if it is exactly full. + * This also deals with the case where there were no rtextents before. + */ + for (bmbno = sbp->sb_rbmblocks - + ((sbp->sb_rextents & ((1 << mp->m_blkbit_log) - 1)) != 0); + bmbno < nrbmblocks; + bmbno++) { + /* + * Allocate a new (fake) mount/sb. + */ + nmp = kmem_alloc(sizeof(*nmp), KM_SLEEP); + *nmp = *mp; + nsbp = &nmp->m_sb; + /* + * Calculate new sb and mount fields for this round. + */ + nsbp->sb_rextsize = in->extsize; + nsbp->sb_rbmblocks = bmbno + 1; + nsbp->sb_rblocks = + XFS_RTMIN(nrblocks, + nsbp->sb_rbmblocks * NBBY * + nsbp->sb_blocksize * nsbp->sb_rextsize); + nsbp->sb_rextents = do_div(nsbp->sb_rblocks, nsbp->sb_rextsize); + nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents); + nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1; + nrsumsize = + (uint)sizeof(xfs_suminfo_t) * nrsumlevels * + nsbp->sb_rbmblocks; + nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize); + nmp->m_rsumsize = nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks); + /* + * Start a transaction, get the log reservation. + */ + tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_FREE); + cancelflags = 0; + if ((error = xfs_trans_reserve(tp, 0, + XFS_GROWRTFREE_LOG_RES(nmp), 0, 0, 0))) + goto error_exit; + /* + * Lock out other callers by grabbing the bitmap inode lock. + */ + if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, + XFS_ILOCK_EXCL, &ip))) + goto error_exit; + ASSERT(ip == mp->m_rbmip); + /* + * Update the bitmap inode's size. + */ + mp->m_rbmip->i_d.di_size = + nsbp->sb_rbmblocks * nsbp->sb_blocksize; + xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE); + cancelflags |= XFS_TRANS_ABORT; + /* + * Get the summary inode into the transaction. + */ + if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, + XFS_ILOCK_EXCL, &ip))) + goto error_exit; + ASSERT(ip == mp->m_rsumip); + /* + * Update the summary inode's size. + */ + mp->m_rsumip->i_d.di_size = nmp->m_rsumsize; + xfs_trans_log_inode(tp, mp->m_rsumip, XFS_ILOG_CORE); + /* + * Copy summary data from old to new sizes. + * Do this when the real size (not block-aligned) changes. + */ + if (sbp->sb_rbmblocks != nsbp->sb_rbmblocks || + mp->m_rsumlevels != nmp->m_rsumlevels) { + error = xfs_rtcopy_summary(mp, nmp, tp); + if (error) + goto error_exit; + } + /* + * Update superblock fields. + */ + if (nsbp->sb_rextsize != sbp->sb_rextsize) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSIZE, + nsbp->sb_rextsize - sbp->sb_rextsize); + if (nsbp->sb_rbmblocks != sbp->sb_rbmblocks) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBMBLOCKS, + nsbp->sb_rbmblocks - sbp->sb_rbmblocks); + if (nsbp->sb_rblocks != sbp->sb_rblocks) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBLOCKS, + nsbp->sb_rblocks - sbp->sb_rblocks); + if (nsbp->sb_rextents != sbp->sb_rextents) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTENTS, + nsbp->sb_rextents - sbp->sb_rextents); + if (nsbp->sb_rextslog != sbp->sb_rextslog) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSLOG, + nsbp->sb_rextslog - sbp->sb_rextslog); + /* + * Free new extent. + */ + bp = NULL; + error = xfs_rtfree_range(nmp, tp, sbp->sb_rextents, + nsbp->sb_rextents - sbp->sb_rextents, &bp, &sumbno); + if (error) + goto error_exit; + /* + * Mark more blocks free in the superblock. + */ + xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, + nsbp->sb_rextents - sbp->sb_rextents); + /* + * Free the fake mp structure. + */ + kmem_free(nmp, sizeof(*nmp)); + nmp = NULL; + /* + * Update mp values into the real mp structure. + */ + mp->m_rsumlevels = nrsumlevels; + mp->m_rsumsize = nrsumsize; + /* + * Commit the transaction. + */ + xfs_trans_commit(tp, 0, NULL); + } + return 0; + + /* + * Error paths come here. + */ +error_exit: + if (nmp) + kmem_free(nmp, sizeof(*nmp)); + xfs_trans_cancel(tp, cancelflags); + return error; +} + +/* + * Allocate an extent in the realtime subvolume, with the usual allocation + * parameters. The length units are all in realtime extents, as is the + * result block number. + */ +int /* error */ +xfs_rtallocate_extent( + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number to allocate */ + xfs_extlen_t minlen, /* minimum length to allocate */ + xfs_extlen_t maxlen, /* maximum length to allocate */ + xfs_extlen_t *len, /* out: actual length allocated */ + xfs_alloctype_t type, /* allocation type XFS_ALLOCTYPE... */ + int wasdel, /* was a delayed allocation extent */ + xfs_extlen_t prod, /* extent product factor */ + xfs_rtblock_t *rtblock) /* out: start block allocated */ +{ + int error; /* error value */ + xfs_inode_t *ip; /* inode for bitmap file */ + xfs_mount_t *mp; /* file system mount structure */ + xfs_rtblock_t r; /* result allocated block */ + xfs_fsblock_t sb; /* summary file block number */ + xfs_buf_t *sumbp; /* summary file block buffer */ + + ASSERT(minlen > 0 && minlen <= maxlen); + mp = tp->t_mountp; + /* + * If prod is set then figure out what to do to minlen and maxlen. + */ + if (prod > 1) { + xfs_extlen_t i; + + if ((i = maxlen % prod)) + maxlen -= i; + if ((i = minlen % prod)) + minlen += prod - i; + if (maxlen < minlen) { + *rtblock = NULLRTBLOCK; + return 0; + } + } + /* + * Lock out other callers by grabbing the bitmap inode lock. + */ + error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip); + if (error) { + return error; + } + sumbp = NULL; + /* + * Allocate by size, or near another block, or exactly at some block. + */ + switch (type) { + case XFS_ALLOCTYPE_ANY_AG: + error = xfs_rtallocate_extent_size(mp, tp, minlen, maxlen, len, + &sumbp, &sb, prod, &r); + break; + case XFS_ALLOCTYPE_NEAR_BNO: + error = xfs_rtallocate_extent_near(mp, tp, bno, minlen, maxlen, + len, &sumbp, &sb, prod, &r); + break; + case XFS_ALLOCTYPE_THIS_BNO: + error = xfs_rtallocate_extent_exact(mp, tp, bno, minlen, maxlen, + len, &sumbp, &sb, prod, &r); + break; + default: + ASSERT(0); + } + if (error) { + return error; + } + /* + * If it worked, update the superblock. + */ + if (r != NULLRTBLOCK) { + long slen = (long)*len; + + ASSERT(*len >= minlen && *len <= maxlen); + if (wasdel) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FREXTENTS, -slen); + else + xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, -slen); + } + *rtblock = r; + return 0; +} + +/* + * Free an extent in the realtime subvolume. Length is expressed in + * realtime extents, as is the block number. + */ +int /* error */ +xfs_rtfree_extent( + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number to free */ + xfs_extlen_t len) /* length of extent freed */ +{ + int error; /* error value */ + xfs_inode_t *ip; /* bitmap file inode */ + xfs_mount_t *mp; /* file system mount structure */ + xfs_fsblock_t sb; /* summary file block number */ + xfs_buf_t *sumbp; /* summary file block buffer */ + + mp = tp->t_mountp; + /* + * Synchronize by locking the bitmap inode. + */ + error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip); + if (error) { + return error; + } +#if defined(__KERNEL__) && defined(DEBUG) + /* + * Check to see that this whole range is currently allocated. + */ + { + int stat; /* result from checking range */ + + error = xfs_rtcheck_alloc_range(mp, tp, bno, len, &stat); + if (error) { + return error; + } + ASSERT(stat); + } +#endif + sumbp = NULL; + /* + * Free the range of realtime blocks. + */ + error = xfs_rtfree_range(mp, tp, bno, len, &sumbp, &sb); + if (error) { + return error; + } + /* + * Mark more blocks free in the superblock. + */ + xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len); + /* + * If we've now freed all the blocks, reset the file sequence + * number to 0. + */ + if (tp->t_frextents_delta + mp->m_sb.sb_frextents == + mp->m_sb.sb_rextents) { + if (!(ip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) + ip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM; + *(__uint64_t *)&ip->i_d.di_atime = 0; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + } + return 0; +} + +/* + * Initialize realtime fields in the mount structure. + */ +int /* error */ +xfs_rtmount_init( + xfs_mount_t *mp) /* file system mount structure */ +{ + xfs_buf_t *bp; /* buffer for last block of subvolume */ + xfs_daddr_t d; /* address of last block of subvolume */ + int error; /* error return value */ + xfs_sb_t *sbp; /* filesystem superblock copy in mount */ + + sbp = &mp->m_sb; + if (sbp->sb_rblocks == 0) + return 0; + if (!mp->m_rtdev) { + printk(KERN_WARNING + "XFS: This FS has an RT subvol - specify -o rtdev on mount\n"); + return XFS_ERROR(ENODEV); + } + mp->m_rsumlevels = sbp->sb_rextslog + 1; + mp->m_rsumsize = + (uint)sizeof(xfs_suminfo_t) * mp->m_rsumlevels * + sbp->sb_rbmblocks; + mp->m_rsumsize = roundup(mp->m_rsumsize, sbp->sb_blocksize); + mp->m_rbmip = mp->m_rsumip = NULL; + /* + * Check that the realtime section is an ok size. + */ + d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks); + if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_rblocks) { + printk(KERN_WARNING "XFS: RT mount - %llu != %llu\n", + XFS_BB_TO_FSB(mp, d), mp->m_sb.sb_rblocks); + return XFS_ERROR(E2BIG); + } + error = xfs_read_buf(mp, &mp->m_rtdev_targ, d - 1, 1, 0, &bp); + if (error) { + printk(KERN_WARNING + "XFS: RT mount - xfs_read_buf returned %d\n", error); + if (error == ENOSPC) + return XFS_ERROR(E2BIG); + return error; + } + xfs_buf_relse(bp); + return 0; +} + +/* + * Get the bitmap and summary inodes into the mount structure + * at mount time. + */ +int /* error */ +xfs_rtmount_inodes( + xfs_mount_t *mp) /* file system mount structure */ +{ + int error; /* error return value */ + xfs_sb_t *sbp; + + sbp = &mp->m_sb; + if (sbp->sb_rbmino == NULLFSINO) + return 0; + error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, &mp->m_rbmip, 0); + if (error) + return error; + ASSERT(mp->m_rbmip != NULL); + ASSERT(sbp->sb_rsumino != NULLFSINO); + error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, &mp->m_rsumip, 0); + if (error) { + vnode_t *rbmvp; /* vnode for bitmap file */ + vmap_t vmap; /* vmap to delete vnode */ + + rbmvp = XFS_ITOV(mp->m_rbmip); + VMAP(rbmvp, mp->m_rbmip, vmap); + VN_RELE(rbmvp); + vn_purge(rbmvp, &vmap); + return error; + } + ASSERT(mp->m_rsumip != NULL); + return 0; +} + +/* + * Pick an extent for allocation at the start of a new realtime file. + * Use the sequence number stored in the atime field of the bitmap inode. + * Translate this to a fraction of the rtextents, and return the product + * of rtextents and the fraction. + * The fraction sequence is 0, 1/2, 1/4, 3/4, 1/8, ..., 7/8, 1/16, ... + */ +int /* error */ +xfs_rtpick_extent( + xfs_mount_t *mp, /* file system mount point */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_extlen_t len, /* allocation length (rtextents) */ + xfs_rtblock_t *pick) /* result rt extent */ +{ + xfs_rtblock_t b; /* result block */ + int error; /* error return value */ + xfs_inode_t *ip; /* bitmap incore inode */ + int log2; /* log of sequence number */ + __uint64_t resid; /* residual after log removed */ + __uint64_t seq; /* sequence number of file creation */ + __uint64_t *seqp; /* pointer to seqno in inode */ + + error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip); + if (error) + return error; + ASSERT(ip == mp->m_rbmip); + seqp = (__uint64_t *)&ip->i_d.di_atime; + if (!(ip->i_d.di_flags & XFS_DIFLAG_NEWRTBM)) { + ip->i_d.di_flags |= XFS_DIFLAG_NEWRTBM; + *seqp = 0; + } + seq = *seqp; + if ((log2 = xfs_highbit64(seq)) == -1) + b = 0; + else { + resid = seq - (1ULL << log2); + b = (mp->m_sb.sb_rextents * ((resid << 1) + 1ULL)) >> + (log2 + 1); + if (b >= mp->m_sb.sb_rextents) + b = do_mod(b, mp->m_sb.sb_rextents); + if (b + len > mp->m_sb.sb_rextents) + b = mp->m_sb.sb_rextents - len; + } + *seqp = seq + 1; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + *pick = b; + return 0; +} + +#ifdef DEBUG +/* + * Debug code: print out the value of a range in the bitmap. + */ +void +xfs_rtprint_range( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to print */ + xfs_extlen_t len) /* length to print */ +{ + xfs_extlen_t i; /* block number in the extent */ + + printk("%Ld: ", start); + for (i = 0; i < len; i++) + printk("%d", xfs_rtcheck_bit(mp, tp, start + i, 1)); + printk("\n"); +} + +/* + * Debug code: print the summary file. + */ +void +xfs_rtprint_summary( + xfs_mount_t *mp, /* file system mount structure */ + xfs_trans_t *tp) /* transaction pointer */ +{ + xfs_suminfo_t c; /* summary data */ + xfs_rtblock_t i; /* bitmap block number */ + int l; /* summary information level */ + int p; /* flag for printed anything */ + xfs_fsblock_t sb; /* summary block number */ + xfs_buf_t *sumbp; /* summary block buffer */ + + sumbp = NULL; + for (l = 0; l < mp->m_rsumlevels; l++) { + for (p = 0, i = 0; i < mp->m_sb.sb_rbmblocks; i++) { + (void)xfs_rtget_summary(mp, tp, l, i, &sumbp, &sb, &c); + if (c) { + if (!p) { + printk("%Ld-%Ld:", 1LL << l, + XFS_RTMIN((1LL << l) + + ((1LL << l) - 1LL), + mp->m_sb.sb_rextents)); + p = 1; + } + printk(" %Ld:%d", i, c); + } + } + if (p) + printk("\n"); + } + if (sumbp) + xfs_trans_brelse(tp, sumbp); +} +#endif /* DEBUG */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_rtalloc.h linux-2.4-xfs/linux/fs/xfs/xfs_rtalloc.h --- linux-2.4.7/linux/fs/xfs/xfs_rtalloc.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_rtalloc.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_RTALLOC_H__ +#define __XFS_RTALLOC_H__ + +struct xfs_mount; +struct xfs_trans; + +/* Min and max rt extent sizes, specified in bytes */ +#define XFS_MAX_RTEXTSIZE (1024 * 1024 * 1024) /* 1GB */ +#define XFS_DFL_RTEXTSIZE (64 * 1024) /* 64KB */ +#define XFS_MIN_RTEXTSIZE (4 * 1024) /* 4KB */ + +/* + * Constants for bit manipulations. + */ +#define XFS_NBBYLOG 3 /* log2(NBBY) */ +#define XFS_WORDLOG 2 /* log2(sizeof(xfs_rtword_t)) */ +#define XFS_NBWORDLOG (XFS_NBBYLOG + XFS_WORDLOG) +#define XFS_NBWORD (1 << XFS_NBWORDLOG) +#define XFS_WORDMASK ((1 << XFS_WORDLOG) - 1) + +#define XFS_BLOCKSIZE(mp) ((mp)->m_sb.sb_blocksize) +#define XFS_BLOCKMASK(mp) ((mp)->m_blockmask) +#define XFS_BLOCKWSIZE(mp) ((mp)->m_blockwsize) +#define XFS_BLOCKWMASK(mp) ((mp)->m_blockwmask) + +/* + * Summary and bit manipulation macros. + */ +#define XFS_SUMOFFS(mp,ls,bb) ((int)((ls) * (mp)->m_sb.sb_rbmblocks + (bb))) +#define XFS_SUMOFFSTOBLOCK(mp,s) \ + (((s) * (uint)sizeof(xfs_suminfo_t)) >> (mp)->m_sb.sb_blocklog) +#define XFS_SUMPTR(mp,bp,so) \ + ((xfs_suminfo_t *)((char *)XFS_BUF_PTR(bp) + \ + (((so) * (uint)sizeof(xfs_suminfo_t)) & XFS_BLOCKMASK(mp)))) + +#define XFS_BITTOBLOCK(mp,bi) ((bi) >> (mp)->m_blkbit_log) +#define XFS_BLOCKTOBIT(mp,bb) ((bb) << (mp)->m_blkbit_log) +#define XFS_BITTOWORD(mp,bi) \ + ((int)(((bi) >> XFS_NBWORDLOG) & XFS_BLOCKWMASK(mp))) + +#define XFS_RTMIN(a,b) ((a) < (b) ? (a) : (b)) +#define XFS_RTMAX(a,b) ((a) > (b) ? (a) : (b)) + +#define XFS_RTLOBIT(w) xfs_lowbit32(w) +#define XFS_RTHIBIT(w) xfs_highbit32(w) + +#if XFS_BIG_FILESYSTEMS +#define XFS_RTBLOCKLOG(b) xfs_highbit64(b) +#else +#define XFS_RTBLOCKLOG(b) xfs_highbit32(b) +#endif + +/* + * Function prototypes for exported functions. + */ + +/* + * Allocate an extent in the realtime subvolume, with the usual allocation + * parameters. The length units are all in realtime extents, as is the + * result block number. + */ +int /* error */ +xfs_rtallocate_extent( + struct xfs_trans *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number to allocate */ + xfs_extlen_t minlen, /* minimum length to allocate */ + xfs_extlen_t maxlen, /* maximum length to allocate */ + xfs_extlen_t *len, /* out: actual length allocated */ + xfs_alloctype_t type, /* allocation type XFS_ALLOCTYPE... */ + int wasdel, /* was a delayed allocation extent */ + xfs_extlen_t prod, /* extent product factor */ + xfs_rtblock_t *rtblock); /* out: start block allocated */ + +/* + * Free an extent in the realtime subvolume. Length is expressed in + * realtime extents, as is the block number. + */ +int /* error */ +xfs_rtfree_extent( + struct xfs_trans *tp, /* transaction pointer */ + xfs_rtblock_t bno, /* starting block number to free */ + xfs_extlen_t len); /* length of extent freed */ + +/* + * Initialize realtime fields in the mount structure. + */ +int /* error */ +xfs_rtmount_init( + struct xfs_mount *mp); /* file system mount structure */ + +/* + * Get the bitmap and summary inodes into the mount structure + * at mount time. + */ +int /* error */ +xfs_rtmount_inodes( + struct xfs_mount *mp); /* file system mount structure */ + +/* + * Pick an extent for allocation at the start of a new realtime file. + * Use the sequence number stored in the atime field of the bitmap inode. + * Translate this to a fraction of the rtextents, and return the product + * of rtextents and the fraction. + * The fraction sequence is 0, 1/2, 1/4, 3/4, 1/8, ..., 7/8, 1/16, ... + */ +int /* error */ +xfs_rtpick_extent( + struct xfs_mount *mp, /* file system mount point */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_extlen_t len, /* allocation length (rtextents) */ + xfs_rtblock_t *pick); /* result rt extent */ + +#ifdef XFSDEBUG +/* + * Debug code: print out the value of a range in the bitmap. + */ +void +xfs_rtprint_range( + struct xfs_mount *mp, /* file system mount structure */ + struct xfs_trans *tp, /* transaction pointer */ + xfs_rtblock_t start, /* starting block to print */ + xfs_extlen_t len); /* length to print */ + +/* + * Debug code: print the summary file. + */ +void +xfs_rtprint_summary( + struct xfs_mount *mp, /* file system mount structure */ + struct xfs_trans *tp); /* transaction pointer */ +#endif /* XFSDEBUG */ + +#endif /* __XFS_RTALLOC_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_rtbit.c linux-2.4-xfs/linux/fs/xfs/xfs_rtbit.c --- linux-2.4.7/linux/fs/xfs/xfs_rtbit.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_rtbit.c Mon Sep 25 00:42:07 2000 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * XFS bit manipulation routines, used only in realtime code. + */ + +#include + +/* + * xfs_lowbit32: get low bit set out of 32-bit argument, -1 if none set. + */ +int +xfs_lowbit32( + __uint32_t v) +{ + int i; + + if (v & 0x0000ffff) + if (v & 0x000000ff) + i = 0; + else + i = 8; + else if (v & 0xffff0000) + if (v & 0x00ff0000) + i = 16; + else + i = 24; + else + return -1; + return i + xfs_lowbit[(v >> i) & 0xff]; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_rw.c linux-2.4-xfs/linux/fs/xfs/xfs_rw.c --- linux-2.4.7/linux/fs/xfs/xfs_rw.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_rw.c Mon May 14 10:39:44 2001 @@ -0,0 +1,709 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +STATIC void +xfs_delalloc_cleanup( + xfs_inode_t *ip, + xfs_fileoff_t start_fsb, + xfs_filblks_t count_fsb); + +/* + * Round the given file offset down to the nearest read/write + * size boundary. + */ +#define XFS_READIO_ALIGN(io,off) (((off) >> io->io_readio_log) \ + << io->io_readio_log) +#define XFS_WRITEIO_ALIGN(io,off) (((off) >> io->io_writeio_log) \ + << io->io_writeio_log) +/* + * This is a subroutine for xfs_write() and other writers (xfs_ioctl) + * which clears the setuid and setgid bits when a file is written. + */ +int +xfs_write_clear_setuid( + xfs_inode_t *ip) +{ + xfs_mount_t *mp; + xfs_trans_t *tp; + int error; + + mp = ip->i_mount; + tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID); + if ((error = xfs_trans_reserve(tp, 0, + XFS_WRITEID_LOG_RES(mp), + 0, 0, 0))) { + xfs_trans_cancel(tp, 0); + return error; + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + ip->i_d.di_mode &= ~ISUID; + + /* + * Note that we don't have to worry about mandatory + * file locking being disabled here because we only + * clear the ISGID bit if the Group execute bit is + * on, but if it was on then mandatory locking wouldn't + * have been enabled. + */ + if (ip->i_d.di_mode & (IEXEC >> 3)) { + ip->i_d.di_mode &= ~ISGID; + } + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + xfs_trans_set_sync(tp); + error = xfs_trans_commit(tp, 0, NULL); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + return 0; +} + +/* + * Force a shutdown of the filesystem instantly while keeping + * the filesystem consistent. We don't do an unmount here; just shutdown + * the shop, make sure that absolutely nothing persistent happens to + * this filesystem after this point. + */ + +void +_xfs_force_shutdown( + xfs_mount_t *mp, + int flags, + char *fname, + int lnnum) +{ + int ntries; + int logerror; + +#if defined(XFSDEBUG) && 0 + printk("xfs_force_shutdown entered [0x%p, %d]\n", + mp, flags); + KDB_ENTER(); +#endif + +#define XFS_MAX_DRELSE_RETRIES 10 + logerror = flags & XFS_LOG_IO_ERROR; + + cmn_err(CE_NOTE, + "xfs_force_shutdown(%s,0x%x) called from line %d of file %s. Return address = 0x%x", + mp->m_fsname,flags,lnnum,fname,__return_address); + /* + * No need to duplicate efforts. + */ + if (XFS_FORCED_SHUTDOWN(mp) && !logerror) + return; + + if (XFS_MTOVFS(mp)->vfs_dev == rootdev) + cmn_err(CE_PANIC, "Fatal error on root filesystem"); + + /* + * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't + * queue up anybody new on the log reservations, and wakes up + * everybody who's sleeping on log reservations and tells + * them the bad news. + */ + if (xfs_log_force_umount(mp, logerror)) + return; + + if (flags & XFS_CORRUPT_INCORE) + cmn_err(CE_ALERT, + "Corruption of in-memory data detected. Shutting down filesystem: %s", + mp->m_fsname); + else + cmn_err(CE_ALERT, + "I/O Error Detected. Shutting down filesystem: %s", + mp->m_fsname); + + cmn_err(CE_ALERT, + "Please umount the filesystem, and rectify the problem(s)"); + + /* + * Release all delayed write buffers for this device. + * It wouldn't be a fatal error if we couldn't release all + * delwri bufs; in general they all get unpinned eventually. + */ + ntries = 0; +#ifdef XFSERRORDEBUG + { + int nbufs; + while (nbufs = xfs_incore_relse(&mp->m_ddev_targ, 1, 0)) { + printf("XFS: released 0x%x bufs\n", nbufs); + if (ntries >= XFS_MAX_DRELSE_RETRIES) { + printf("XFS: ntries 0x%x\n", ntries); + debug("ntries"); + break; + } + delay(++ntries * 5); + } + } +#else + while (xfs_incore_relse(&mp->m_ddev_targ, 1, 0)) { + if (ntries >= XFS_MAX_DRELSE_RETRIES) + break; + delay(++ntries * 5); + } + +#endif + +#if CELL_CAPABLE + if (cell_enabled && !(flags & XFS_SHUTDOWN_REMOTE_REQ)) { + extern void cxfs_force_shutdown(xfs_mount_t *, int); /*@@@*/ + + /* + * We're being called for a problem discovered locally. + * Tell CXFS to pass along the shutdown request. + */ + cxfs_force_shutdown(mp, flags); + } +#endif /* CELL_CAPABLE */ +} + + +/* + * Called when we want to stop a buffer from getting written or read. + * We attach the EIO error, muck with its flags, and call biodone + * so that the proper iodone callbacks get called. + */ +int +xfs_bioerror( + xfs_buf_t *bp) +{ + +#ifdef XFSERRORDEBUG + ASSERT(XFS_BUF_ISREAD(bp) || bp->b_iodone); +#endif + + /* + * No need to wait until the buffer is unpinned. + * We aren't flushing it. + */ + xfs_buftrace("XFS IOERROR", bp); + XFS_BUF_ERROR(bp, EIO); + /* + * We're calling biodone, so delete B_DONE flag. Either way + * we have to call the iodone callback, and calling biodone + * probably is the best way since it takes care of + * GRIO as well. + */ + XFS_BUF_UNREAD(bp); + XFS_BUF_UNDELAYWRITE(bp); + XFS_BUF_UNDONE(bp); + XFS_BUF_STALE(bp); + + XFS_BUF_CLR_BDSTRAT_FUNC(bp); + xfs_biodone(bp); + + return (EIO); +} + +/* + * Same as xfs_bioerror, except that we are releasing the buffer + * here ourselves, and avoiding the biodone call. + * This is meant for userdata errors; metadata bufs come with + * iodone functions attached, so that we can track down errors. + */ +int +xfs_bioerror_relse( + xfs_buf_t *bp) +{ + int64_t fl; + + ASSERT(XFS_BUF_IODONE_FUNC(bp) != xfs_buf_iodone_callbacks); + ASSERT(XFS_BUF_IODONE_FUNC(bp) != xlog_iodone); + + xfs_buftrace("XFS IOERRELSE", bp); + fl = XFS_BUF_BFLAGS(bp); + /* + * No need to wait until the buffer is unpinned. + * We aren't flushing it. + * + * chunkhold expects B_DONE to be set, whether + * we actually finish the I/O or not. We don't want to + * change that interface. + */ + XFS_BUF_UNREAD(bp); + XFS_BUF_UNDELAYWRITE(bp); + XFS_BUF_DONE(bp); + XFS_BUF_STALE(bp); + XFS_BUF_CLR_IODONE_FUNC(bp); + XFS_BUF_CLR_BDSTRAT_FUNC(bp); + if (!(fl & XFS_B_ASYNC)) { + /* + * Mark b_error and B_ERROR _both_. + * Lot's of chunkcache code assumes that. + * There's no reason to mark error for + * ASYNC buffers. + */ + XFS_BUF_ERROR(bp, EIO); + XFS_BUF_V_IODONESEMA(bp); + } else { + xfs_buf_relse(bp); + } + return (EIO); +} +/* + * Prints out an ALERT message about I/O error. + */ +void +xfs_ioerror_alert( + char *func, + struct xfs_mount *mp, + dev_t dev, + xfs_daddr_t blkno) +{ + cmn_err(CE_ALERT, + "I/O error in filesystem (\"%s\") meta-data dev 0x%x block 0x%Lx:\n" + " %s", + mp->m_fsname, (int)dev, (__uint64_t)blkno, func); +} + +/* + * This isn't an absolute requirement, but it is + * just a good idea to call xfs_read_buf instead of + * directly doing a read_buf call. For one, we shouldn't + * be doing this disk read if we are in SHUTDOWN state anyway, + * so this stops that from happening. Secondly, this does all + * the error checking stuff and the brelse if appropriate for + * the caller, so the code can be a little leaner. + */ + +int +xfs_read_buf( + struct xfs_mount *mp, + buftarg_t *target, + xfs_daddr_t blkno, + int len, + uint flags, + xfs_buf_t **bpp) +{ + xfs_buf_t *bp; + int error; + + if (flags) + bp = xfs_buf_read_flags(target, blkno, len, flags); + else + bp = xfs_buf_read(target, blkno, len, flags); + if (!bp) + return XFS_ERROR(EIO); + error = XFS_BUF_GETERROR(bp); + if (bp && !error && !XFS_FORCED_SHUTDOWN(mp)) { + *bpp = bp; + } else { + *bpp = NULL; + if (!error) + error = XFS_ERROR(EIO); + if (bp) { + XFS_BUF_UNDONE(bp); + XFS_BUF_UNDELAYWRITE(bp); + XFS_BUF_STALE(bp); + /* + * brelse clears B_ERROR and b_error + */ + xfs_buf_relse(bp); + } + } + return (error); +} + +/* + * Wrapper around bwrite() so that we can trap + * write errors, and act accordingly. + */ +int +xfs_bwrite( + struct xfs_mount *mp, + struct xfs_buf *bp) +{ + int error; + + /* + * XXXsup how does this work for quotas. + */ + XFS_BUF_SET_BDSTRAT_FUNC(bp, xfs_bdstrat_cb); + XFS_BUF_SET_FSPRIVATE3(bp, mp); + XFS_BUF_WRITE(bp); + + if ((error = XFS_bwrite(bp))) { + ASSERT(mp); + /* + * Cannot put a buftrace here since if the buffer is not + * B_HOLD then we will brelse() the buffer before returning + * from bwrite and we could be tracing a buffer that has + * been reused. + */ + xfs_force_shutdown(mp, XFS_METADATA_IO_ERROR); + } + return (error); +} + +/* + * xfs_inval_cached_pages() + * This routine is responsible for keeping direct I/O and buffered I/O + * somewhat coherent. From here we make sure that we're at least + * temporarily holding the inode I/O lock exclusively and then call + * the page cache to flush and invalidate any cached pages. If there + * are no cached pages this routine will be very quick. + */ +void +xfs_inval_cached_pages( + vnode_t *vp, + xfs_iocore_t *io, + xfs_off_t offset, + xfs_off_t len, + void *dio) +{ + xfs_dio_t *diop = (xfs_dio_t *)dio; + int relock; + __uint64_t flush_end; + xfs_mount_t *mp; + + if (!VN_CACHED(vp)) { + return; + } + + mp = io->io_mount; + + /* + * We need to get the I/O lock exclusively in order + * to safely invalidate pages and mappings. + */ + relock = ismrlocked(io->io_iolock, MR_ACCESS); + if (relock) { + XFS_IUNLOCK(mp, io, XFS_IOLOCK_SHARED); + XFS_ILOCK(mp, io, XFS_IOLOCK_EXCL); + } + + /* Writing beyond EOF creates a hole that must be zeroed */ + if (diop && (offset > XFS_SIZE(mp, io))) { + xfs_fsize_t isize; + + XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + isize = XFS_SIZE(mp, io); + if (offset > isize) { + xfs_zero_eof(vp, io, offset, isize, NULL); + } + XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); + } + + /* + * Round up to the next page boundary and then back + * off by one byte. We back off by one because this + * is a first byte/last byte interface rather than + * a start/len interface. We round up to a page + * boundary because the page/chunk cache code is + * slightly broken and won't invalidate all the right + * buffers otherwise. + * + * We also have to watch out for overflow, so if we + * go over the maximum off_t value we just pull back + * to that max. + */ + flush_end = (__uint64_t)ctooff(offtoc(offset + len)) - 1; + if (flush_end > (__uint64_t)LONGLONG_MAX) { + flush_end = LONGLONG_MAX; + } + VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(offset)), -1, FI_REMAPF_LOCKED); + if (relock) { + XFS_IUNLOCK(mp, io, XFS_IOLOCK_EXCL); + XFS_ILOCK(mp, io, XFS_IOLOCK_SHARED); + } +} + + + +spinlock_t xfs_refcache_lock = SPIN_LOCK_UNLOCKED; +xfs_inode_t **xfs_refcache; +int xfs_refcache_size; +int xfs_refcache_index; +int xfs_refcache_busy; +int xfs_refcache_count; + +/* + * Insert the given inode into the reference cache. + */ +void +xfs_refcache_insert( + xfs_inode_t *ip) +{ + vnode_t *vp; + xfs_inode_t *release_ip; + xfs_inode_t **refcache; + + ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE)); + + /* + * If an unmount is busy blowing entries out of the cache, + * then don't bother. + */ + if (xfs_refcache_busy) { + return; + } + + /* + * The inode is already in the refcache, so don't bother + * with it. + */ + if (ip->i_refcache != NULL) { + return; + } + + vp = XFS_ITOV(ip); + /* ASSERT(vp->v_count > 0); */ + VN_HOLD(vp); + + /* + * We allocate the reference cache on use so that we don't + * waste the memory on systems not being used as NFS servers. + */ + if (xfs_refcache == NULL) { + refcache = (xfs_inode_t **)kmem_zalloc(xfs_refcache_size * + sizeof(xfs_inode_t *), + KM_SLEEP); + } else { + refcache = NULL; + } + + spin_lock(&xfs_refcache_lock); + + /* + * If we allocated memory for the refcache above and it still + * needs it, then use the memory we allocated. Otherwise we'll + * free the memory below. + */ + if (refcache != NULL) { + if (xfs_refcache == NULL) { + xfs_refcache = refcache; + refcache = NULL; + } + } + + /* + * If an unmount is busy clearing out the cache, don't add new + * entries to it. + */ + if ((xfs_refcache_busy) || (vp->v_vfsp->vfs_flag & VFS_OFFLINE)) { + spin_unlock(&xfs_refcache_lock); + VN_RELE(vp); + /* + * If we allocated memory for the refcache above but someone + * else beat us to using it, then free the memory now. + */ + if (refcache != NULL) { + kmem_free(refcache, + xfs_refcache_size * sizeof(xfs_inode_t *)); + } + return; + } + release_ip = xfs_refcache[xfs_refcache_index]; + if (release_ip != NULL) { + release_ip->i_refcache = NULL; + xfs_refcache_count--; + ASSERT(xfs_refcache_count >= 0); + } + xfs_refcache[xfs_refcache_index] = ip; + ASSERT(ip->i_refcache == NULL); + ip->i_refcache = &(xfs_refcache[xfs_refcache_index]); + xfs_refcache_count++; + ASSERT(xfs_refcache_count <= xfs_refcache_size); + xfs_refcache_index++; + if (xfs_refcache_index == xfs_refcache_size) { + xfs_refcache_index = 0; + } + spin_unlock(&xfs_refcache_lock); + + /* + * Save the pointer to the inode to be released so that we can + * VN_RELE it once we've dropped our inode locks in xfs_rwunlock(). + * The pointer may be NULL, but that's OK. + */ + ip->i_release = release_ip; + + /* + * If we allocated memory for the refcache above but someone + * else beat us to using it, then free the memory now. + */ + if (refcache != NULL) { + kmem_free(refcache, + xfs_refcache_size * sizeof(xfs_inode_t *)); + } + return; +} + + +/* + * If the given inode is in the reference cache, purge its entry and + * release the reference on the vnode. + */ +void +xfs_refcache_purge_ip( + xfs_inode_t *ip) +{ + vnode_t *vp; + int error; + + /* + * If we're not pointing to our entry in the cache, then + * we must not be in the cache. + */ + if (ip->i_refcache == NULL) { + return; + } + + spin_lock(&xfs_refcache_lock); + if (ip->i_refcache == NULL) { + spin_unlock(&xfs_refcache_lock); + return; + } + + /* + * Clear both our pointer to the cache entry and its pointer + * back to us. + */ + ASSERT(*(ip->i_refcache) == ip); + *(ip->i_refcache) = NULL; + ip->i_refcache = NULL; + xfs_refcache_count--; + ASSERT(xfs_refcache_count >= 0); + spin_unlock(&xfs_refcache_lock); + + vp = XFS_ITOV(ip); + /* ASSERT(vp->v_count > 1); */ + VOP_RELEASE(vp, error); + VN_RELE(vp); + + return; +} + + +/* + * This is called from the XFS unmount code to purge all entries for the + * given mount from the cache. It uses the refcache busy counter to + * make sure that new entries are not added to the cache as we purge them. + */ +void +xfs_refcache_purge_mp( + xfs_mount_t *mp) +{ + vnode_t *vp; + int error, i; + xfs_inode_t *ip; + + if (xfs_refcache == NULL) { + return; + } + + spin_lock(&xfs_refcache_lock); + /* + * Bumping the busy counter keeps new entries from being added + * to the cache. We use a counter since multiple unmounts could + * be in here simultaneously. + */ + xfs_refcache_busy++; + + for (i = 0; i < xfs_refcache_size; i++) { + ip = xfs_refcache[i]; + if ((ip != NULL) && (ip->i_mount == mp)) { + xfs_refcache[i] = NULL; + ip->i_refcache = NULL; + xfs_refcache_count--; + ASSERT(xfs_refcache_count >= 0); + spin_unlock(&xfs_refcache_lock); + vp = XFS_ITOV(ip); + VOP_RELEASE(vp, error); + VN_RELE(vp); + spin_lock(&xfs_refcache_lock); + } + } + + xfs_refcache_busy--; + ASSERT(xfs_refcache_busy >= 0); + spin_unlock(&xfs_refcache_lock); +} + + +/* + * This is called from the XFS sync code to ensure that the refcache + * is emptied out over time. We purge a small number of entries with + * each call. + */ +void +xfs_refcache_purge_some(void) +{ + int error, i; + xfs_inode_t *ip; + int iplist_index; +#define XFS_REFCACHE_PURGE_COUNT 10 + xfs_inode_t *iplist[XFS_REFCACHE_PURGE_COUNT]; + + if ((xfs_refcache == NULL) || (xfs_refcache_count == 0)) { + return; + } + + iplist_index = 0; + spin_lock(&xfs_refcache_lock); + + /* + * Store any inodes we find in the next several entries + * into the iplist array to be released after dropping + * the spinlock. We always start looking from the currently + * oldest place in the cache. We move the refcache index + * forward as we go so that we are sure to eventually clear + * out the entire cache when the system goes idle. + */ + for (i = 0; i < XFS_REFCACHE_PURGE_COUNT; i++) { + ip = xfs_refcache[xfs_refcache_index]; + if (ip != NULL) { + xfs_refcache[xfs_refcache_index] = NULL; + ip->i_refcache = NULL; + xfs_refcache_count--; + ASSERT(xfs_refcache_count >= 0); + iplist[iplist_index] = ip; + iplist_index++; + } + xfs_refcache_index++; + if (xfs_refcache_index == xfs_refcache_size) { + xfs_refcache_index = 0; + } + } + + spin_unlock(&xfs_refcache_lock); + + /* + * Now drop the inodes we collected. + */ + for (i = 0; i < iplist_index; i++) { + VOP_RELEASE(XFS_ITOV(iplist[i]), error); + VN_RELE(XFS_ITOV(iplist[i])); + } +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_rw.h linux-2.4-xfs/linux/fs/xfs/xfs_rw.h --- linux-2.4.7/linux/fs/xfs/xfs_rw.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_rw.h Tue Mar 6 13:44:15 2001 @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_RW_H__ +#define __XFS_RW_H__ + +struct bhv_desc; +struct bmapval; +struct xfs_buf; +struct cred; +struct flid; +struct uio; +struct vnode; +struct xfs_inode; +struct xfs_iocore; +struct xfs_mount; +struct xfs_trans; +struct xfs_dio; +struct pm; + +/* + * Maximum count of bmaps used by read and write paths. + */ +#define XFS_MAX_RW_NBMAPS 4 + +/* + * Counts of readahead buffers to use based on physical memory size. + * None of these should be more than XFS_MAX_RW_NBMAPS. + */ +#define XFS_RW_NREADAHEAD_16MB 2 +#define XFS_RW_NREADAHEAD_32MB 3 +#define XFS_RW_NREADAHEAD_K32 4 +#define XFS_RW_NREADAHEAD_K64 4 + +/* + * Maximum size of a buffer that we\'ll map. Making this + * too big will degrade performance due to the number of + * pages which need to be gathered. Making it too small + * will prevent us from doing large I/O\'s to hardware that + * needs it. + * + * This is currently set to 512 KB. + */ +#define XFS_MAX_BMAP_LEN_BB 1024 +#define XFS_MAX_BMAP_LEN_BYTES 524288 + +/* + * Convert the given file system block to a disk block. + * We have to treat it differently based on whether the + * file is a real time file or not, because the bmap code + * does. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_TO_DB) +xfs_daddr_t xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb); +#define XFS_FSB_TO_DB(ip,fsb) xfs_fsb_to_db(ip,fsb) +#else +#define XFS_FSB_TO_DB(ip,fsb) \ + (((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) ? \ + (xfs_daddr_t)XFS_FSB_TO_BB((ip)->i_mount, (fsb)) : \ + XFS_FSB_TO_DADDR((ip)->i_mount, (fsb))) +#endif + +#define XFS_FSB_TO_DB_IO(io,fsb) \ + (((io)->io_flags & XFS_IOCORE_RT) ? \ + XFS_FSB_TO_BB((io)->io_mount, (fsb)) : \ + XFS_FSB_TO_DADDR((io)->io_mount, (fsb))) + +/* + * Defines for the trace mechanisms in xfs_rw.c. + */ +#define XFS_RW_KTRACE_SIZE 64 +#define XFS_STRAT_KTRACE_SIZE 64 +#define XFS_STRAT_GTRACE_SIZE 512 + +#define XFS_READ_ENTER 1 +#define XFS_WRITE_ENTER 2 +#define XFS_IOMAP_READ_ENTER 3 +#define XFS_IOMAP_WRITE_ENTER 4 +#define XFS_IOMAP_READ_MAP 5 +#define XFS_IOMAP_WRITE_MAP 6 +#define XFS_IOMAP_WRITE_NOSPACE 7 +#define XFS_ITRUNC_START 8 +#define XFS_ITRUNC_FINISH1 9 +#define XFS_ITRUNC_FINISH2 10 +#define XFS_CTRUNC1 11 +#define XFS_CTRUNC2 12 +#define XFS_CTRUNC3 13 +#define XFS_CTRUNC4 14 +#define XFS_CTRUNC5 15 +#define XFS_CTRUNC6 16 +#define XFS_BUNMAPI 17 +#define XFS_INVAL_CACHED 18 +#define XFS_DIORD_ENTER 19 +#define XFS_DIOWR_ENTER 20 + +#if defined(XFS_ALL_TRACE) +#define XFS_RW_TRACE +#define XFS_STRAT_TRACE +#endif + +#if !defined(DEBUG) +#undef XFS_RW_TRACE +#undef XFS_STRAT_TRACE +#endif + +/* + * Prototypes for functions in xfs_rw.c. + */ + +int +xfs_write_clear_setuid( + struct xfs_inode *ip); + +int +xfs_bwrite( + struct xfs_mount *mp, + struct xfs_buf *bp); + +void +xfs_inval_cached_pages( + struct vnode *vp, + struct xfs_iocore *io, + xfs_off_t offset, + xfs_off_t len, + void *dio); + +void +xfs_refcache_insert( + struct xfs_inode *ip); + +void +xfs_refcache_purge_ip( + struct xfs_inode *ip); + +void +xfs_refcache_purge_mp( + struct xfs_mount *mp); + +void +xfs_refcache_purge_some(void); + + +int +xfs_bioerror( + struct xfs_buf *b); + +/* + * XFS I/O core functions + */ +extern int xfs_bioerror_relse(struct xfs_buf *); + + +/* + * Needed by xfs_rw.c + */ +int +xfs_rwlock( + bhv_desc_t *bdp, + vrwlock_t write_lock); + +void +xfs_rwunlock( + bhv_desc_t *bdp, + vrwlock_t write_lock); + +int +xfs_read_buf( + struct xfs_mount *mp, + buftarg_t *target, + xfs_daddr_t blkno, + int len, + uint flags, + struct xfs_buf **bpp); + +void +xfs_ioerror_alert( + char *func, + struct xfs_mount *mp, + dev_t dev, + xfs_daddr_t blkno); + +#endif /* __XFS_RW_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_sb.h linux-2.4-xfs/linux/fs/xfs/xfs_sb.h --- linux-2.4.7/linux/fs/xfs/xfs_sb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_sb.h Mon Apr 2 21:52:38 2001 @@ -0,0 +1,490 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SB_H__ +#define __XFS_SB_H__ + +/* + * Super block + * Fits into a 512-byte buffer at daddr_t 0 of each allocation group. + * Only the first of these is ever updated except during growfs. + */ + +struct xfs_buf; +struct xfs_mount; + +#define XFS_SB_MAGIC 0x58465342 /* 'XFSB' */ +#define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */ +#define XFS_SB_VERSION_2 2 /* 6.2 - attributes */ +#define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */ +#define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */ +#define XFS_SB_VERSION_NUMBITS 0x000f +#define XFS_SB_VERSION_ALLFBITS 0xfff0 +#define XFS_SB_VERSION_SASHFBITS 0xf000 +#define XFS_SB_VERSION_REALFBITS 0x0ff0 +#define XFS_SB_VERSION_ATTRBIT 0x0010 +#define XFS_SB_VERSION_NLINKBIT 0x0020 +#define XFS_SB_VERSION_QUOTABIT 0x0040 +#define XFS_SB_VERSION_ALIGNBIT 0x0080 +#define XFS_SB_VERSION_DALIGNBIT 0x0100 +#define XFS_SB_VERSION_SHAREDBIT 0x0200 +#define XFS_SB_VERSION_EXTFLGBIT 0x1000 +#define XFS_SB_VERSION_DIRV2BIT 0x2000 +#define XFS_SB_VERSION_OKSASHFBITS \ + (XFS_SB_VERSION_EXTFLGBIT | \ + XFS_SB_VERSION_DIRV2BIT) +#define XFS_SB_VERSION_OKREALFBITS \ + (XFS_SB_VERSION_ATTRBIT | \ + XFS_SB_VERSION_NLINKBIT | \ + XFS_SB_VERSION_QUOTABIT | \ + XFS_SB_VERSION_ALIGNBIT | \ + XFS_SB_VERSION_DALIGNBIT | \ + XFS_SB_VERSION_SHAREDBIT) +#define XFS_SB_VERSION_OKSASHBITS \ + (XFS_SB_VERSION_NUMBITS | \ + XFS_SB_VERSION_REALFBITS | \ + XFS_SB_VERSION_OKSASHFBITS) +#define XFS_SB_VERSION_OKREALBITS \ + (XFS_SB_VERSION_NUMBITS | \ + XFS_SB_VERSION_OKREALFBITS | \ + XFS_SB_VERSION_OKSASHFBITS) +#define XFS_SB_VERSION_MKFS(ia,dia,extflag,dirv2) \ + (((ia) || (dia) || (extflag) || (dirv2)) ? \ + (XFS_SB_VERSION_4 | \ + ((ia) ? XFS_SB_VERSION_ALIGNBIT : 0) | \ + ((dia) ? XFS_SB_VERSION_DALIGNBIT : 0) | \ + ((extflag) ? XFS_SB_VERSION_EXTFLGBIT : 0) | \ + ((dirv2) ? XFS_SB_VERSION_DIRV2BIT : 0)) : \ + XFS_SB_VERSION_1) + +typedef struct xfs_sb +{ + __uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */ + __uint32_t sb_blocksize; /* logical block size, bytes */ + xfs_drfsbno_t sb_dblocks; /* number of data blocks */ + xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */ + xfs_drtbno_t sb_rextents; /* number of realtime extents */ + uuid_t sb_uuid; /* file system unique id */ + xfs_dfsbno_t sb_logstart; /* starting block of log if internal */ + xfs_ino_t sb_rootino; /* root inode number */ + xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */ + xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */ + xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */ + xfs_agblock_t sb_agblocks; /* size of an allocation group */ + xfs_agnumber_t sb_agcount; /* number of allocation groups */ + xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */ + xfs_extlen_t sb_logblocks; /* number of log blocks */ + __uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */ + __uint16_t sb_sectsize; /* volume sector size, bytes */ + __uint16_t sb_inodesize; /* inode size, bytes */ + __uint16_t sb_inopblock; /* inodes per block */ + char sb_fname[12]; /* file system name */ + __uint8_t sb_blocklog; /* log2 of sb_blocksize */ + __uint8_t sb_sectlog; /* log2 of sb_sectsize */ + __uint8_t sb_inodelog; /* log2 of sb_inodesize */ + __uint8_t sb_inopblog; /* log2 of sb_inopblock */ + __uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */ + __uint8_t sb_rextslog; /* log2 of sb_rextents */ + __uint8_t sb_inprogress; /* mkfs is in progress, don't mount */ + __uint8_t sb_imax_pct; /* max % of fs for inode space */ + /* statistics */ + /* + * These fields must remain contiguous. If you really + * want to change their layout, make sure you fix the + * code in xfs_trans_apply_sb_deltas(). + */ + __uint64_t sb_icount; /* allocated inodes */ + __uint64_t sb_ifree; /* free inodes */ + __uint64_t sb_fdblocks; /* free data blocks */ + __uint64_t sb_frextents; /* free realtime extents */ + /* + * End contiguous fields. + */ + xfs_ino_t sb_uquotino; /* user quota inode */ + xfs_ino_t sb_gquotino; /* group quota inode */ + __uint16_t sb_qflags; /* quota flags */ + __uint8_t sb_flags; /* misc. flags */ + __uint8_t sb_shared_vn; /* shared version number */ + xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */ + __uint32_t sb_unit; /* stripe or raid unit */ + __uint32_t sb_width; /* stripe or raid width */ + __uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */ + __uint8_t sb_dummy[7]; /* padding */ +} xfs_sb_t; + +/* + * Sequence number values for the fields. + */ +typedef enum { + XFS_SBS_MAGICNUM, XFS_SBS_BLOCKSIZE, XFS_SBS_DBLOCKS, XFS_SBS_RBLOCKS, + XFS_SBS_REXTENTS, XFS_SBS_UUID, XFS_SBS_LOGSTART, XFS_SBS_ROOTINO, + XFS_SBS_RBMINO, XFS_SBS_RSUMINO, XFS_SBS_REXTSIZE, XFS_SBS_AGBLOCKS, + XFS_SBS_AGCOUNT, XFS_SBS_RBMBLOCKS, XFS_SBS_LOGBLOCKS, + XFS_SBS_VERSIONNUM, XFS_SBS_SECTSIZE, XFS_SBS_INODESIZE, + XFS_SBS_INOPBLOCK, XFS_SBS_FNAME, XFS_SBS_BLOCKLOG, + XFS_SBS_SECTLOG, XFS_SBS_INODELOG, XFS_SBS_INOPBLOG, XFS_SBS_AGBLKLOG, + XFS_SBS_REXTSLOG, XFS_SBS_INPROGRESS, XFS_SBS_IMAX_PCT, XFS_SBS_ICOUNT, + XFS_SBS_IFREE, XFS_SBS_FDBLOCKS, XFS_SBS_FREXTENTS, XFS_SBS_UQUOTINO, + XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN, + XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG, + XFS_SBS_DUMMY, + XFS_SBS_FIELDCOUNT +} xfs_sb_field_t; + +/* + * Mask values, defined based on the xfs_sb_field_t values. + * Only define the ones we're using. + */ +#define XFS_SB_MVAL(x) (1LL << XFS_SBS_ ## x) +#define XFS_SB_UUID XFS_SB_MVAL(UUID) +#define XFS_SB_FNAME XFS_SB_MVAL(FNAME) +#define XFS_SB_ROOTINO XFS_SB_MVAL(ROOTINO) +#define XFS_SB_RBMINO XFS_SB_MVAL(RBMINO) +#define XFS_SB_RSUMINO XFS_SB_MVAL(RSUMINO) +#define XFS_SB_VERSIONNUM XFS_SB_MVAL(VERSIONNUM) +#define XFS_SB_UQUOTINO XFS_SB_MVAL(UQUOTINO) +#define XFS_SB_GQUOTINO XFS_SB_MVAL(GQUOTINO) +#define XFS_SB_QFLAGS XFS_SB_MVAL(QFLAGS) +#define XFS_SB_SHARED_VN XFS_SB_MVAL(SHARED_VN) +#define XFS_SB_UNIT XFS_SB_MVAL(UNIT) +#define XFS_SB_WIDTH XFS_SB_MVAL(WIDTH) +#define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT) +#define XFS_SB_ALL_BITS ((1LL << XFS_SB_NUM_BITS) - 1) +#define XFS_SB_MOD_BITS \ + (XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \ + XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \ + XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH) + +/* + * Misc. Flags - warning - these will be cleared by xfs_repair unless + * a feature bit is set when the flag is used. + */ +#define XFS_SBF_NOFLAGS 0x00 /* no flags set */ +#define XFS_SBF_READONLY 0x01 /* only read-only mounts allowed */ + +/* + * define max. shared version we can interoperate with + */ +#define XFS_SB_MAX_SHARED_VN 0 + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_NUM) +int xfs_sb_version_num(xfs_sb_t *sbp); +#define XFS_SB_VERSION_NUM(sbp) xfs_sb_version_num(sbp) +#else +#define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_GOOD_VERSION) +int xfs_sb_good_version(xfs_sb_t *sbp); +#define XFS_SB_GOOD_VERSION(sbp) xfs_sb_good_version(sbp) +#else +#define XFS_SB_GOOD_VERSION_INT(sbp) \ + ((((sbp)->sb_versionnum >= XFS_SB_VERSION_1) && \ + ((sbp)->sb_versionnum <= XFS_SB_VERSION_3)) || \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + !((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS) +#ifdef __KERNEL__ +#define XFS_SB_GOOD_VERSION(sbp) \ + (XFS_SB_GOOD_VERSION_INT(sbp) && \ + (sbp)->sb_shared_vn <= XFS_SB_MAX_SHARED_VN) )) +#else +/* + * extra 2 paren's here (( to unconfuse paren-matching editors + * like vi because XFS_SB_GOOD_VERSION_INT is a partial expression + * and the two XFS_SB_GOOD_VERSION's each 2 more close paren's to + * complete the expression. + */ +#define XFS_SB_GOOD_VERSION(sbp) \ + (XFS_SB_GOOD_VERSION_INT(sbp) && \ + (!((sbp)->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) || \ + (sbp)->sb_shared_vn <= XFS_SB_MAX_SHARED_VN)) )) +#endif /* __KERNEL__ */ +#endif + +#define XFS_SB_GOOD_SASH_VERSION(sbp) \ + ((((sbp)->sb_versionnum >= XFS_SB_VERSION_1) && \ + ((sbp)->sb_versionnum <= XFS_SB_VERSION_3)) || \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + !((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKSASHBITS))) + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_TONEW) +unsigned xfs_sb_version_tonew(unsigned v); +#define XFS_SB_VERSION_TONEW(v) xfs_sb_version_tonew(v) +#else +#define XFS_SB_VERSION_TONEW(v) \ + ((((v) == XFS_SB_VERSION_1) ? \ + 0 : \ + (((v) == XFS_SB_VERSION_2) ? \ + XFS_SB_VERSION_ATTRBIT : \ + (XFS_SB_VERSION_ATTRBIT | XFS_SB_VERSION_NLINKBIT))) | \ + XFS_SB_VERSION_4) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_TOOLD) +unsigned xfs_sb_version_toold(unsigned v); +#define XFS_SB_VERSION_TOOLD(v) xfs_sb_version_toold(v) +#else +#define XFS_SB_VERSION_TOOLD(v) \ + (((v) & (XFS_SB_VERSION_QUOTABIT | XFS_SB_VERSION_ALIGNBIT)) ? \ + 0 : \ + (((v) & XFS_SB_VERSION_NLINKBIT) ? \ + XFS_SB_VERSION_3 : \ + (((v) & XFS_SB_VERSION_ATTRBIT) ? \ + XFS_SB_VERSION_2 : \ + XFS_SB_VERSION_1))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASATTR) +int xfs_sb_version_hasattr(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASATTR(sbp) xfs_sb_version_hasattr(sbp) +#else +#define XFS_SB_VERSION_HASATTR(sbp) \ + (((sbp)->sb_versionnum == XFS_SB_VERSION_2) || \ + ((sbp)->sb_versionnum == XFS_SB_VERSION_3) || \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_ATTRBIT))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDATTR) +void xfs_sb_version_addattr(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDATTR(sbp) xfs_sb_version_addattr(sbp) +#else +#define XFS_SB_VERSION_ADDATTR(sbp) \ + ((sbp)->sb_versionnum = \ + (((sbp)->sb_versionnum == XFS_SB_VERSION_1) ? \ + XFS_SB_VERSION_2 : \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) ? \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_ATTRBIT) : \ + (XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT)))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASNLINK) +int xfs_sb_version_hasnlink(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASNLINK(sbp) xfs_sb_version_hasnlink(sbp) +#else +#define XFS_SB_VERSION_HASNLINK(sbp) \ + (((sbp)->sb_versionnum == XFS_SB_VERSION_3) || \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_NLINKBIT))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDNLINK) +void xfs_sb_version_addnlink(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDNLINK(sbp) xfs_sb_version_addnlink(sbp) +#else +#define XFS_SB_VERSION_ADDNLINK(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum <= XFS_SB_VERSION_2 ? \ + XFS_SB_VERSION_3 : \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_NLINKBIT))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASQUOTA) +int xfs_sb_version_hasquota(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASQUOTA(sbp) xfs_sb_version_hasquota(sbp) +#else +#define XFS_SB_VERSION_HASQUOTA(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_QUOTABIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDQUOTA) +void xfs_sb_version_addquota(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDQUOTA(sbp) xfs_sb_version_addquota(sbp) +#else +#define XFS_SB_VERSION_ADDQUOTA(sbp) \ + ((sbp)->sb_versionnum = \ + (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 ? \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_QUOTABIT) : \ + (XFS_SB_VERSION_TONEW((sbp)->sb_versionnum) | \ + XFS_SB_VERSION_QUOTABIT))) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASALIGN) +int xfs_sb_version_hasalign(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASALIGN(sbp) xfs_sb_version_hasalign(sbp) +#else +#define XFS_SB_VERSION_HASALIGN(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_ALIGNBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_SUBALIGN) +void xfs_sb_version_subalign(xfs_sb_t *sbp); +#define XFS_SB_VERSION_SUBALIGN(sbp) xfs_sb_version_subalign(sbp) +#else +#define XFS_SB_VERSION_SUBALIGN(sbp) \ + ((sbp)->sb_versionnum = \ + XFS_SB_VERSION_TOOLD((sbp)->sb_versionnum & ~XFS_SB_VERSION_ALIGNBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASDALIGN) +int xfs_sb_version_hasdalign(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASDALIGN(sbp) xfs_sb_version_hasdalign(sbp) +#else +#define XFS_SB_VERSION_HASDALIGN(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_DALIGNBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDDALIGN) +int xfs_sb_version_adddalign(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDDALIGN(sbp) xfs_sb_version_adddalign(sbp) +#else +#define XFS_SB_VERSION_ADDDALIGN(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_DALIGNBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASSHARED) +int xfs_sb_version_hasshared(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASSHARED(sbp) xfs_sb_version_hasshared(sbp) +#else +#define XFS_SB_VERSION_HASSHARED(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_SHAREDBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDSHARED) +int xfs_sb_version_addshared(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDSHARED(sbp) xfs_sb_version_addshared(sbp) +#else +#define XFS_SB_VERSION_ADDSHARED(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_SHAREDBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_SUBSHARED) +int xfs_sb_version_subshared(xfs_sb_t *sbp); +#define XFS_SB_VERSION_SUBSHARED(sbp) xfs_sb_version_subshared(sbp) +#else +#define XFS_SB_VERSION_SUBSHARED(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum & ~XFS_SB_VERSION_SHAREDBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASDIRV2) +int xfs_sb_version_hasdirv2(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASDIRV2(sbp) xfs_sb_version_hasdirv2(sbp) +#else +#define XFS_SB_VERSION_HASDIRV2(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_DIRV2BIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASEXTFLGBIT) +int xfs_sb_version_hasextflgbit(xfs_sb_t *sbp); +#define XFS_SB_VERSION_HASEXTFLGBIT(sbp) xfs_sb_version_hasextflgbit(sbp) +#else +#define XFS_SB_VERSION_HASEXTFLGBIT(sbp) \ + ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \ + ((sbp)->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDEXTFLGBIT) +int xfs_sb_version_addextflgbit(xfs_sb_t *sbp); +#define XFS_SB_VERSION_ADDEXTFLGBIT(sbp) xfs_sb_version_addextflgbit(sbp) +#else +#define XFS_SB_VERSION_ADDEXTFLGBIT(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum | XFS_SB_VERSION_EXTFLGBIT)) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_SUBEXTFLGBIT) +int xfs_sb_version_subextflgbit(xfs_sb_t *sbp); +#define XFS_SB_VERSION_SUBEXTFLGBIT(sbp) xfs_sb_version_subextflgbit(sbp) +#else +#define XFS_SB_VERSION_SUBEXTFLGBIT(sbp) \ + ((sbp)->sb_versionnum = \ + ((sbp)->sb_versionnum & ~XFS_SB_VERSION_EXTFLGBIT)) +#endif + +/* + * end of superblock version macros + */ + +#define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in filesystem/ag */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_BLOCK) +xfs_agblock_t xfs_sb_block(struct xfs_mount *mp); +#define XFS_SB_BLOCK(mp) xfs_sb_block(mp) +#else +#define XFS_SB_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_SB_DADDR) +#endif + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_HDR_BLOCK) +xfs_agblock_t xfs_hdr_block(struct xfs_mount *mp, xfs_daddr_t d); +#define XFS_HDR_BLOCK(mp,d) xfs_hdr_block(mp,d) +#else +#define XFS_HDR_BLOCK(mp,d) ((xfs_agblock_t)(XFS_BB_TO_FSBT(mp,d))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DADDR_TO_FSB) +xfs_fsblock_t xfs_daddr_to_fsb(struct xfs_mount *mp, xfs_daddr_t d); +#define XFS_DADDR_TO_FSB(mp,d) xfs_daddr_to_fsb(mp,d) +#else +#define XFS_DADDR_TO_FSB(mp,d) \ + XFS_AGB_TO_FSB(mp, XFS_DADDR_TO_AGNO(mp,d), XFS_DADDR_TO_AGBNO(mp,d)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_TO_DADDR) +xfs_daddr_t xfs_fsb_to_daddr(struct xfs_mount *mp, xfs_fsblock_t fsbno); +#define XFS_FSB_TO_DADDR(mp,fsbno) xfs_fsb_to_daddr(mp,fsbno) +#else +#define XFS_FSB_TO_DADDR(mp,fsbno) \ + XFS_AGB_TO_DADDR(mp, XFS_FSB_TO_AGNO(mp,fsbno), \ + XFS_FSB_TO_AGBNO(mp,fsbno)) +#endif + +/* + * File system block to basic block conversions. + */ +#define XFS_FSB_TO_BB(mp,fsbno) ((fsbno) << (mp)->m_blkbb_log) +#define XFS_BB_TO_FSB(mp,bb) \ + (((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log) +#define XFS_BB_TO_FSBT(mp,bb) ((bb) >> (mp)->m_blkbb_log) +#define XFS_BB_FSB_OFFSET(mp,bb) ((bb) & ((mp)->m_bsize - 1)) + +/* + * File system block to byte conversions. + */ +#define XFS_FSB_TO_B(mp,fsbno) ((xfs_fsize_t)(fsbno) << \ + (mp)->m_sb.sb_blocklog) +#define XFS_B_TO_FSB(mp,b) \ + ((((__uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog) +#define XFS_B_TO_FSBT(mp,b) (((__uint64_t)(b)) >> (mp)->m_sb.sb_blocklog) +#define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask) + +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_SBP) +xfs_sb_t *xfs_buf_to_sbp(struct xfs_buf *bp); +#define XFS_BUF_TO_SBP(bp) xfs_buf_to_sbp(bp) +#else +#define XFS_BUF_TO_SBP(bp) ((xfs_sb_t *)XFS_BUF_PTR(bp)) +#endif + +#endif /* __XFS_SB_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_trans.c linux-2.4-xfs/linux/fs/xfs/xfs_trans.c --- linux-2.4.7/linux/fs/xfs/xfs_trans.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_trans.c Wed May 16 21:58:46 2001 @@ -0,0 +1,1218 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +STATIC void xfs_trans_apply_sb_deltas(xfs_trans_t *); +STATIC uint xfs_trans_count_vecs(xfs_trans_t *); +STATIC void xfs_trans_fill_vecs(xfs_trans_t *, xfs_log_iovec_t *); +STATIC void xfs_trans_uncommit(xfs_trans_t *, uint); +STATIC void xfs_trans_committed(xfs_trans_t *, int); +STATIC void xfs_trans_chunk_committed(xfs_log_item_chunk_t *, xfs_lsn_t, int); +STATIC void xfs_trans_free(xfs_trans_t *); + +xfs_zone_t *xfs_trans_zone; + + +/* + * Initialize the precomputed transaction reservation values + * in the mount structure. + */ +void +xfs_trans_init( + xfs_mount_t *mp) +{ + xfs_trans_reservations_t *resp; + + resp = &(mp->m_reservations); + resp->tr_write = + (uint)(XFS_CALC_WRITE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_itruncate = + (uint)(XFS_CALC_ITRUNCATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_rename = + (uint)(XFS_CALC_RENAME_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_link = (uint)XFS_CALC_LINK_LOG_RES(mp); + resp->tr_remove = + (uint)(XFS_CALC_REMOVE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_symlink = + (uint)(XFS_CALC_SYMLINK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_create = + (uint)(XFS_CALC_CREATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_mkdir = + (uint)(XFS_CALC_MKDIR_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_ifree = + (uint)(XFS_CALC_IFREE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_ichange = + (uint)(XFS_CALC_ICHANGE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_growdata = (uint)XFS_CALC_GROWDATA_LOG_RES(mp); + resp->tr_swrite = (uint)XFS_CALC_SWRITE_LOG_RES(mp); + resp->tr_writeid = (uint)XFS_CALC_WRITEID_LOG_RES(mp); + resp->tr_addafork = + (uint)(XFS_CALC_ADDAFORK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_attrinval = (uint)XFS_CALC_ATTRINVAL_LOG_RES(mp); + resp->tr_attrset = + (uint)(XFS_CALC_ATTRSET_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_attrrm = + (uint)(XFS_CALC_ATTRRM_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp)); + resp->tr_clearagi = (uint)XFS_CALC_CLEAR_AGI_BUCKET_LOG_RES(mp); + resp->tr_growrtalloc = (uint)XFS_CALC_GROWRTALLOC_LOG_RES(mp); + resp->tr_growrtzero = (uint)XFS_CALC_GROWRTZERO_LOG_RES(mp); + resp->tr_growrtfree = (uint)XFS_CALC_GROWRTFREE_LOG_RES(mp); +} + +/* + * This routine is called to allocate a transaction structure. + * The type parameter indicates the type of the transaction. These + * are enumerated in xfs_trans.h. + * + * Dynamically allocate the transaction structure from the transaction + * zone, initialize it, and return it to the caller. + */ +xfs_trans_t * +xfs_trans_alloc( + xfs_mount_t *mp, + uint type) +{ + xfs_trans_t *tp; + + xfs_check_frozen(mp, XFS_FREEZE_TRANS); + + ASSERT(xfs_trans_zone != NULL); + tp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP_IO); + tp->t_dqinfo = NULL; + + /* + * Initialize the transaction structure. + */ + tp->t_magic = XFS_TRANS_MAGIC; + tp->t_type = type; + tp->t_mountp = mp; + tp->t_items_free = XFS_LIC_NUM_SLOTS; + XFS_LIC_INIT(&(tp->t_items)); + + return (tp); +} + +/* + * This is called to create a new transaction which will share the + * permanent log reservation of the given transaction. The remaining + * unused block and rt extent reservations are also inherited. This + * implies that the original transaction is no longer allowed to allocate + * blocks. Locks and log items, however, are no inherited. They must + * be added to the new transaction explicitly. + */ +xfs_trans_t * +xfs_trans_dup( + xfs_trans_t *tp) +{ + xfs_trans_t *ntp; + + ntp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP); + + /* + * Initialize the new transaction structure. + */ + ntp->t_magic = XFS_TRANS_MAGIC; + ntp->t_type = tp->t_type; + ntp->t_mountp = tp->t_mountp; + ntp->t_items_free = XFS_LIC_NUM_SLOTS; + XFS_LIC_INIT(&(ntp->t_items)); + + ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); + +#if defined(XLOG_NOLOG) || defined(DEBUG) + ASSERT(!xlog_debug || tp->t_ticket != NULL); +#else + ASSERT(tp->t_ticket != NULL); +#endif + ntp->t_flags = XFS_TRANS_PERM_LOG_RES | (tp->t_flags & XFS_TRANS_RESERVE); + ntp->t_ticket = tp->t_ticket; + ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used; + tp->t_blk_res = tp->t_blk_res_used; + ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used; + tp->t_rtx_res = tp->t_rtx_res_used; + + /* + * dup the dquot stuff too. + */ + if (tp->t_dqinfo) + xfs_trans_dup_dqinfo(tp, ntp); + + atomic_inc(&tp->t_mountp->m_active_trans); + return ntp; +} + +/* + * This is called to reserve free disk blocks and log space for the + * given transaction. This must be done before allocating any resources + * within the transaction. + * + * This will return ENOSPC if there are not enough blocks available. + * It will sleep waiting for available log space. + * The only valid value for the flags parameter is XFS_RES_LOG_PERM, which + * is used by long running transactions. If any one of the reservations + * fails then they will all be backed out. + * + * This does not do quota reservations. That typically is done by the + * caller afterwards. + */ +int +xfs_trans_reserve( + xfs_trans_t *tp, + uint blocks, + uint logspace, + uint rtextents, + uint flags, + uint logcount) +{ + int log_flags; + int error; + int rsvd; + + error = 0; + rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; + /* + * Attempt to reserve the needed disk blocks by decrementing + * the number needed from the number available. This will + * fail if the count would go below zero. + */ + if (blocks > 0) { + error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS, + -blocks, rsvd); + if (error != 0) { + return (XFS_ERROR(ENOSPC)); + } + tp->t_blk_res += blocks; + } + + /* + * Reserve the log space needed for this transaction. + */ + if (logspace > 0) { + ASSERT((tp->t_log_res == 0) || (tp->t_log_res == logspace)); + ASSERT((tp->t_log_count == 0) || + (tp->t_log_count == logcount)); + if (flags & XFS_TRANS_PERM_LOG_RES) { + log_flags = XFS_LOG_PERM_RESERV; + tp->t_flags |= XFS_TRANS_PERM_LOG_RES; + } else { + ASSERT(tp->t_ticket == NULL); + ASSERT(!(tp->t_flags & XFS_TRANS_PERM_LOG_RES)); + log_flags = 0; + } + + error = xfs_log_reserve(tp->t_mountp, logspace, logcount, + &tp->t_ticket, + XFS_TRANSACTION, log_flags); + if (error) { + goto undo_blocks; + } + tp->t_log_res = logspace; + tp->t_log_count = logcount; + } + + /* + * Attempt to reserve the needed realtime extents by decrementing + * the number needed from the number available. This will + * fail if the count would go below zero. + */ + if (rtextents > 0) { + error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FREXTENTS, + -rtextents, rsvd); + if (error) { + error = XFS_ERROR(ENOSPC); + goto undo_log; + } + tp->t_rtx_res += rtextents; + } + + return 0; + + /* + * Error cases jump to one of these labels to undo any + * reservations which have already been performed. + */ +undo_log: + if (logspace > 0) { + if (flags & XFS_TRANS_PERM_LOG_RES) { + log_flags = XFS_LOG_REL_PERM_RESERV; + } else { + log_flags = 0; + } + xfs_log_done(tp->t_mountp, tp->t_ticket, log_flags); + tp->t_ticket = NULL; + tp->t_log_res = 0; + tp->t_flags &= ~XFS_TRANS_PERM_LOG_RES; + } + +undo_blocks: + if (blocks > 0) { + (void) xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS, + blocks, rsvd); + tp->t_blk_res = 0; + } + + return (error); +} + + +/* + * This is called to set the a callback to be called when the given + * transaction is committed to disk. The transaction pointer and the + * argument pointer will be passed to the callback routine. + * + * Only one callback can be associated with any single transaction. + */ +void +xfs_trans_callback( + xfs_trans_t *tp, + xfs_trans_callback_t callback, + void *arg) +{ + ASSERT(tp->t_callback == NULL); + tp->t_callback = callback; + tp->t_callarg = arg; +} + + +/* + * Record the indicated change to the given field for application + * to the file system's superblock when the transaction commits. + * For now, just store the change in the transaction structure. + * + * Mark the transaction structure to indicate that the superblock + * needs to be updated before committing. + */ +void +xfs_trans_mod_sb( + xfs_trans_t *tp, + uint field, + long delta) +{ + + switch (field) { + case XFS_TRANS_SB_ICOUNT: + ASSERT(delta > 0); + tp->t_icount_delta += delta; + break; + case XFS_TRANS_SB_IFREE: + tp->t_ifree_delta += delta; + break; + case XFS_TRANS_SB_FDBLOCKS: + /* + * Track the number of blocks allocated in the + * transaction. Make sure it does not exceed the + * number reserved. + */ + if (delta < 0) { + tp->t_blk_res_used += (uint)-delta; + ASSERT(tp->t_blk_res_used <= tp->t_blk_res); + } + tp->t_fdblocks_delta += delta; + break; + case XFS_TRANS_SB_RES_FDBLOCKS: + /* + * The allocation has already been applied to the + * in-core superblock's counter. This should only + * be applied to the on-disk superblock. + */ + ASSERT(delta < 0); + tp->t_res_fdblocks_delta += delta; + break; + case XFS_TRANS_SB_FREXTENTS: + /* + * Track the number of blocks allocated in the + * transaction. Make sure it does not exceed the + * number reserved. + */ + if (delta < 0) { + tp->t_rtx_res_used += (uint)-delta; + ASSERT(tp->t_rtx_res_used <= tp->t_rtx_res); + } + tp->t_frextents_delta += delta; + break; + case XFS_TRANS_SB_RES_FREXTENTS: + /* + * The allocation has already been applied to the + * in-core superblocks's counter. This should only + * be applied to the on-disk superblock. + */ + ASSERT(delta < 0); + tp->t_res_frextents_delta += delta; + break; + case XFS_TRANS_SB_DBLOCKS: + ASSERT(delta > 0); + tp->t_dblocks_delta += delta; + break; + case XFS_TRANS_SB_AGCOUNT: + ASSERT(delta > 0); + tp->t_agcount_delta += delta; + break; + case XFS_TRANS_SB_IMAXPCT: + tp->t_imaxpct_delta += delta; + break; + case XFS_TRANS_SB_REXTSIZE: + tp->t_rextsize_delta += delta; + break; + case XFS_TRANS_SB_RBMBLOCKS: + tp->t_rbmblocks_delta += delta; + break; + case XFS_TRANS_SB_RBLOCKS: + tp->t_rblocks_delta += delta; + break; + case XFS_TRANS_SB_REXTENTS: + tp->t_rextents_delta += delta; + break; + case XFS_TRANS_SB_REXTSLOG: + tp->t_rextslog_delta += delta; + break; + default: + ASSERT(0); + return; + } + + tp->t_flags |= (XFS_TRANS_SB_DIRTY | XFS_TRANS_DIRTY); +} + +/* + * xfs_trans_apply_sb_deltas() is called from the commit code + * to bring the superblock buffer into the current transaction + * and modify it as requested by earlier calls to xfs_trans_mod_sb(). + * + * For now we just look at each field allowed to change and change + * it if necessary. + */ +STATIC void +xfs_trans_apply_sb_deltas( + xfs_trans_t *tp) +{ + xfs_sb_t *sbp; + xfs_buf_t *bp; + int whole = 0; + + bp = xfs_trans_getsb(tp, tp->t_mountp, 0); + sbp = XFS_BUF_TO_SBP(bp); + + /* + * Check that superblock mods match the mods made to AGF counters. + */ + ASSERT((tp->t_fdblocks_delta + tp->t_res_fdblocks_delta) == + (tp->t_ag_freeblks_delta + tp->t_ag_flist_delta + + tp->t_ag_btree_delta)); + + if (tp->t_icount_delta != 0) { + INT_MOD(sbp->sb_icount, ARCH_CONVERT, tp->t_icount_delta); + } + if (tp->t_ifree_delta != 0) { + INT_MOD(sbp->sb_ifree, ARCH_CONVERT, tp->t_ifree_delta); + } + + if (tp->t_fdblocks_delta != 0) { + INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_fdblocks_delta); + } + if (tp->t_res_fdblocks_delta != 0) { + INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_res_fdblocks_delta); + } + + if (tp->t_frextents_delta != 0) { + INT_MOD(sbp->sb_frextents, ARCH_CONVERT, tp->t_frextents_delta); + } + if (tp->t_dblocks_delta != 0) { + INT_MOD(sbp->sb_dblocks, ARCH_CONVERT, tp->t_dblocks_delta); + whole = 1; + } + if (tp->t_agcount_delta != 0) { + INT_MOD(sbp->sb_agcount, ARCH_CONVERT, tp->t_agcount_delta); + whole = 1; + } + if (tp->t_imaxpct_delta != 0) { + INT_MOD(sbp->sb_imax_pct, ARCH_CONVERT, tp->t_imaxpct_delta); + whole = 1; + } + if (tp->t_rextsize_delta != 0) { + INT_MOD(sbp->sb_rextsize, ARCH_CONVERT, tp->t_rextsize_delta); + whole = 1; + } + if (tp->t_rbmblocks_delta != 0) { + INT_MOD(sbp->sb_rbmblocks, ARCH_CONVERT, tp->t_rbmblocks_delta); + whole = 1; + } + if (tp->t_rblocks_delta != 0) { + INT_MOD(sbp->sb_rblocks, ARCH_CONVERT, tp->t_rblocks_delta); + whole = 1; + } + if (tp->t_rextents_delta != 0) { + INT_MOD(sbp->sb_rextents, ARCH_CONVERT, tp->t_rextents_delta); + whole = 1; + } + if (tp->t_rextslog_delta != 0) { + INT_MOD(sbp->sb_rextslog, ARCH_CONVERT, tp->t_rextslog_delta); + whole = 1; + } + + if (whole) + /* + * Log the whole thing, the fields are discontiguous. + */ + xfs_trans_log_buf(tp, bp, 0, sizeof(xfs_sb_t) - 1); + else + /* + * Since all the modifiable fields are contiguous, we + * can get away with this. + */ + xfs_trans_log_buf(tp, bp, offsetof(xfs_sb_t, sb_icount), + offsetof(xfs_sb_t, sb_frextents) + + sizeof(sbp->sb_frextents) - 1); +} + +/* + * xfs_trans_unreserve_and_mod_sb() is called to release unused + * reservations and apply superblock counter changes to the in-core + * superblock. + * + * This is done efficiently with a single call to xfs_mod_incore_sb_batch(). + */ +void +xfs_trans_unreserve_and_mod_sb( + xfs_trans_t *tp) +{ + xfs_mod_sb_t msb[14]; /* If you add cases, add entries */ + xfs_mod_sb_t *msbp; + /* REFERENCED */ + int error; + int rsvd; + + msbp = msb; + rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; + + /* + * Release any reserved blocks. Any that were allocated + * will be taken back again by fdblocks_delta below. + */ + if (tp->t_blk_res > 0) { + msbp->msb_field = XFS_SBS_FDBLOCKS; + msbp->msb_delta = tp->t_blk_res; + msbp++; + } + + /* + * Release any reserved real time extents . Any that were + * allocated will be taken back again by frextents_delta below. + */ + if (tp->t_rtx_res > 0) { + msbp->msb_field = XFS_SBS_FREXTENTS; + msbp->msb_delta = tp->t_rtx_res; + msbp++; + } + + /* + * Apply any superblock modifications to the in-core version. + * The t_res_fdblocks_delta and t_res_frextents_delta fields are + * explicity NOT applied to the in-core superblock. + * The idea is that that has already been done. + */ + if (tp->t_flags & XFS_TRANS_SB_DIRTY) { + if (tp->t_icount_delta != 0) { + msbp->msb_field = XFS_SBS_ICOUNT; + msbp->msb_delta = (int)tp->t_icount_delta; + msbp++; + } + if (tp->t_ifree_delta != 0) { + msbp->msb_field = XFS_SBS_IFREE; + msbp->msb_delta = (int)tp->t_ifree_delta; + msbp++; + } + if (tp->t_fdblocks_delta != 0) { + msbp->msb_field = XFS_SBS_FDBLOCKS; + msbp->msb_delta = (int)tp->t_fdblocks_delta; + msbp++; + } + if (tp->t_frextents_delta != 0) { + msbp->msb_field = XFS_SBS_FREXTENTS; + msbp->msb_delta = (int)tp->t_frextents_delta; + msbp++; + } + if (tp->t_dblocks_delta != 0) { + msbp->msb_field = XFS_SBS_DBLOCKS; + msbp->msb_delta = (int)tp->t_dblocks_delta; + msbp++; + } + if (tp->t_agcount_delta != 0) { + msbp->msb_field = XFS_SBS_AGCOUNT; + msbp->msb_delta = (int)tp->t_agcount_delta; + msbp++; + } + if (tp->t_imaxpct_delta != 0) { + msbp->msb_field = XFS_SBS_IMAX_PCT; + msbp->msb_delta = (int)tp->t_imaxpct_delta; + msbp++; + } + if (tp->t_rextsize_delta != 0) { + msbp->msb_field = XFS_SBS_REXTSIZE; + msbp->msb_delta = (int)tp->t_rextsize_delta; + msbp++; + } + if (tp->t_rbmblocks_delta != 0) { + msbp->msb_field = XFS_SBS_RBMBLOCKS; + msbp->msb_delta = (int)tp->t_rbmblocks_delta; + msbp++; + } + if (tp->t_rblocks_delta != 0) { + msbp->msb_field = XFS_SBS_RBLOCKS; + msbp->msb_delta = (int)tp->t_rblocks_delta; + msbp++; + } + if (tp->t_rextents_delta != 0) { + msbp->msb_field = XFS_SBS_REXTENTS; + msbp->msb_delta = (int)tp->t_rextents_delta; + msbp++; + } + if (tp->t_rextslog_delta != 0) { + msbp->msb_field = XFS_SBS_REXTSLOG; + msbp->msb_delta = (int)tp->t_rextslog_delta; + msbp++; + } + } + + /* + * If we need to change anything, do it. + */ + if (msbp > msb) { + error = xfs_mod_incore_sb_batch(tp->t_mountp, msb, + (uint)(msbp - msb), rsvd); + ASSERT(error == 0); + } +} + + +/* + * xfs_trans_commit + * + * Commit the given transaction to the log a/synchronously. + * + * XFS disk error handling mechanism is not based on a typical + * transaction abort mechanism. Logically after the filesystem + * gets marked 'SHUTDOWN', we can't let any new transactions + * be durable - ie. committed to disk - because some metadata might + * be inconsistent. In such cases, this returns an error, and the + * caller may assume that all locked objects joined to the transaction + * have already been unlocked as if the commit had succeeded. + * It's illegal to reference the transaction structure after this call. + */ + /*ARGSUSED*/ +int +xfs_trans_commit( + xfs_trans_t *tp, + uint flags, + xfs_lsn_t *commit_lsn_p) +{ + xfs_log_iovec_t *log_vector; + int nvec; + xfs_mount_t *mp; + xfs_lsn_t commit_lsn; + /* REFERENCED */ + int error; + int log_flags; + int sync; +#define XFS_TRANS_LOGVEC_COUNT 16 + xfs_log_iovec_t log_vector_fast[XFS_TRANS_LOGVEC_COUNT]; +#if defined(XLOG_NOLOG) || defined(DEBUG) + static xfs_lsn_t trans_lsn = 1; +#endif + int shutdown; + + commit_lsn = -1; + + /* + * Determine whether this commit is releasing a permanent + * log reservation or not. + */ + if (flags & XFS_TRANS_RELEASE_LOG_RES) { + ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); + log_flags = XFS_LOG_REL_PERM_RESERV; + } else { + log_flags = 0; + } + mp = tp->t_mountp; + + /* + * If there is nothing to be logged by the transaction, + * then unlock all of the items associated with the + * transaction and free the transaction structure. + * Also make sure to return any reserved blocks to + * the free pool. + */ +shut_us_down: + shutdown = XFS_FORCED_SHUTDOWN(mp) ? EIO : 0; + if (!(tp->t_flags & XFS_TRANS_DIRTY) || shutdown) { + xfs_trans_unreserve_and_mod_sb(tp); + /* + * It is indeed possible for the transaction to be + * not dirty but the dqinfo portion to be. All that + * means is that we have some (non-persistent) quota + * reservations that need to be unreserved. + */ + if (tp->t_dqinfo && (tp->t_flags & XFS_TRANS_DQ_DIRTY)) { + xfs_trans_unreserve_and_mod_dquots(tp); + } + if (tp->t_ticket) { + commit_lsn = xfs_log_done(mp, tp->t_ticket, log_flags); + if (commit_lsn == -1 && !shutdown) + shutdown = XFS_ERROR(EIO); + } + xfs_trans_free_items(tp, shutdown? XFS_TRANS_ABORT : 0); + xfs_trans_free(tp); + XFS_STATS_INC(xfsstats.xs_trans_empty); + if (commit_lsn_p) + *commit_lsn_p = commit_lsn; + return (shutdown); + } +#if defined(XLOG_NOLOG) || defined(DEBUG) + ASSERT(!xlog_debug || tp->t_ticket != NULL); +#else + ASSERT(tp->t_ticket != NULL); +#endif + + /* + * If we need to update the superblock, then do it now. + */ + if (tp->t_flags & XFS_TRANS_SB_DIRTY) { + xfs_trans_apply_sb_deltas(tp); + } + if (tp->t_flags & XFS_TRANS_DQ_DIRTY) { + xfs_trans_apply_dquot_deltas(tp); + } + + /* + * Ask each log item how many log_vector entries it will + * need so we can figure out how many to allocate. + * Try to avoid the kmem_alloc() call in the common case + * by using a vector from the stack when it fits. + */ + nvec = xfs_trans_count_vecs(tp); + + if (nvec == 0) { + xfs_force_shutdown(mp, XFS_LOG_IO_ERROR); + goto shut_us_down; + } + + + if (nvec <= XFS_TRANS_LOGVEC_COUNT) { + log_vector = log_vector_fast; + } else { + log_vector = (xfs_log_iovec_t *)kmem_alloc(nvec * + sizeof(xfs_log_iovec_t), + KM_SLEEP); + } + + /* + * Fill in the log_vector and pin the logged items, and + * then write the transaction to the log. + */ + xfs_trans_fill_vecs(tp, log_vector); + + /* + * Ignore errors here. xfs_log_done would do the right thing. + * We need to put the ticket, etc. away. + */ + error = xfs_log_write(mp, log_vector, nvec, tp->t_ticket, + &(tp->t_lsn)); + +#if defined(XLOG_NOLOG) || defined(DEBUG) + if (xlog_debug) { + commit_lsn = xfs_log_done(mp, tp->t_ticket, + log_flags); + } else { + commit_lsn = 0; + tp->t_lsn = trans_lsn++; + } +#else + /* + * This is the regular case. At this point (after the call finishes), + * the transaction is committed incore and could go out to disk at + * any time. However, all the items associated with the transaction + * are still locked and pinned in memory. + */ + commit_lsn = xfs_log_done(mp, tp->t_ticket, log_flags); +#endif + + if (nvec > XFS_TRANS_LOGVEC_COUNT) { + kmem_free(log_vector, nvec * sizeof(xfs_log_iovec_t)); + } + + if (commit_lsn_p) + *commit_lsn_p = commit_lsn; + + /* + * If we got a log write error. Unpin the logitems that we + * had pinned, clean up, free trans structure, and return error. + */ + if (error || commit_lsn == -1) { + xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT); + return XFS_ERROR(EIO); + } + + /* + * Once all the items of the transaction have been copied + * to the in core log we can release them. Do that here. + * This will free descriptors pointing to items which were + * not logged since there is nothing more to do with them. + * For items which were logged, we will keep pointers to them + * so they can be unpinned after the transaction commits to disk. + * This will also stamp each modified meta-data item with + * the commit lsn of this transaction for dependency tracking + * purposes. + */ + xfs_trans_unlock_items(tp, commit_lsn); + + /* + * Once the transaction has committed, unused + * reservations need to be released and changes to + * the superblock need to be reflected in the in-core + * version. Do that now. + */ + xfs_trans_unreserve_and_mod_sb(tp); + + sync = tp->t_flags & XFS_TRANS_SYNC; + + /* + * Tell the LM to call the transaction completion routine + * when the log write with LSN commit_lsn completes (e.g. + * when the transaction commit really hits the on-disk log). + * After this call we cannot reference tp, because the call + * can happen at any time and the call will free the transaction + * structure pointed to by tp. The only case where we call + * the completion routine (xfs_trans_committed) directly is + * if the log is turned off on a debug kernel or we're + * running in simulation mode (the log is explicitly turned + * off). + */ +#if defined(XLOG_NOLOG) || defined(DEBUG) + if (xlog_debug) { + tp->t_logcb.cb_func = (void(*)(void*, int))xfs_trans_committed; + tp->t_logcb.cb_arg = tp; + xfs_log_notify(mp, commit_lsn, &(tp->t_logcb)); + } else { + xfs_trans_committed(tp, 0); + } +#else + tp->t_logcb.cb_func = (void(*)(void*, int))xfs_trans_committed; + tp->t_logcb.cb_arg = tp; + xfs_log_notify(mp, commit_lsn, &(tp->t_logcb)); +#endif + /* + * If the transaction needs to be synchronous, then force the + * log out now and wait for it. + */ + if (sync) { + error = xfs_log_force(mp, commit_lsn, + XFS_LOG_FORCE | XFS_LOG_SYNC); + XFS_STATS_INC(xfsstats.xs_trans_sync); + } else { + XFS_STATS_INC(xfsstats.xs_trans_async); + } + return (error); +} + + +/* + * Total up the number of log iovecs needed to commit this + * transaction. The transaction itself needs one for the + * transaction header. Ask each dirty item in turn how many + * it needs to get the total. + */ +STATIC uint +xfs_trans_count_vecs( + xfs_trans_t *tp) +{ + int nvecs; + xfs_log_item_desc_t *lidp; + + nvecs = 1; + lidp = xfs_trans_first_item(tp); + ASSERT(lidp != NULL); + + /* In the non-debug case we need to start bailing out if we + * didn't find a log_item here, return zero and let trans_commit + * deal with it. + */ + if (lidp == NULL) + return 0; + + while (lidp != NULL) { + /* + * Skip items which aren't dirty in this transaction. + */ + if (!(lidp->lid_flags & XFS_LID_DIRTY)) { + lidp = xfs_trans_next_item(tp, lidp); + continue; + } + lidp->lid_size = IOP_SIZE(lidp->lid_item); + nvecs += lidp->lid_size; + lidp = xfs_trans_next_item(tp, lidp); + } + + return nvecs; +} + +/* + * Called from the trans_commit code when we notice that + * the filesystem is in the middle of a forced shutdown. + */ +STATIC void +xfs_trans_uncommit( + xfs_trans_t *tp, + uint flags) +{ + xfs_log_item_desc_t *lidp; + + for (lidp = xfs_trans_first_item(tp); + lidp != NULL; + lidp = xfs_trans_next_item(tp, lidp)) { + /* + * Unpin all but those that aren't dirty. + */ + if (lidp->lid_flags & XFS_LID_DIRTY) + IOP_UNPIN_REMOVE(lidp->lid_item, tp); + } + + xfs_trans_unreserve_and_mod_sb(tp); + if (tp->t_dqinfo && (tp->t_flags & XFS_TRANS_DQ_DIRTY)) { + xfs_trans_unreserve_and_mod_dquots(tp); + } + + xfs_trans_free_items(tp, flags); + xfs_trans_free(tp); +} + +/* + * Fill in the vector with pointers to data to be logged + * by this transaction. The transaction header takes + * the first vector, and then each dirty item takes the + * number of vectors it indicated it needed in xfs_trans_count_vecs(). + * + * As each item fills in the entries it needs, also pin the item + * so that it cannot be flushed out until the log write completes. + */ +STATIC void +xfs_trans_fill_vecs( + xfs_trans_t *tp, + xfs_log_iovec_t *log_vector) +{ + xfs_log_item_desc_t *lidp; + xfs_log_iovec_t *vecp; + uint nitems; + + /* + * Skip over the entry for the transaction header, we'll + * fill that in at the end. + */ + vecp = log_vector + 1; /* pointer arithmetic */ + + nitems = 0; + lidp = xfs_trans_first_item(tp); + ASSERT(lidp != NULL); + while (lidp != NULL) { + /* + * Skip items which aren't dirty in this transaction. + */ + if (!(lidp->lid_flags & XFS_LID_DIRTY)) { + lidp = xfs_trans_next_item(tp, lidp); + continue; + } + /* + * The item may be marked dirty but not log anything. + * This can be used to get called when a transaction + * is committed. + */ + if (lidp->lid_size) { + nitems++; + } + IOP_FORMAT(lidp->lid_item, vecp); + vecp += lidp->lid_size; /* pointer arithmetic */ + IOP_PIN(lidp->lid_item); + lidp = xfs_trans_next_item(tp, lidp); + } + + /* + * Now that we've counted the number of items in this + * transaction, fill in the transaction header. + */ + tp->t_header.th_magic = XFS_TRANS_HEADER_MAGIC; + tp->t_header.th_type = tp->t_type; + tp->t_header.th_num_items = nitems; + log_vector->i_addr = (xfs_caddr_t)&tp->t_header; + log_vector->i_len = sizeof(xfs_trans_header_t); +} + + +/* + * Unlock all of the transaction's items and free the transaction. + * The transaction must not have modified any of its items, because + * there is no way to restore them to their previous state. + * + * If the transaction has made a log reservation, make sure to release + * it as well. + */ +void +xfs_trans_cancel( + xfs_trans_t *tp, + int flags) +{ + int log_flags; +#ifdef DEBUG + xfs_log_item_chunk_t *licp; + xfs_log_item_desc_t *lidp; + xfs_log_item_t *lip; + int i; +#endif + + /* + * See if the caller is being too lazy to figure out if + * the transaction really needs an abort. + */ + if ((flags & XFS_TRANS_ABORT) && !(tp->t_flags & XFS_TRANS_DIRTY)) + flags &= ~XFS_TRANS_ABORT; + /* + * See if the caller is relying on us to shut down the + * filesystem. This happens in paths where we detect + * corruption and decide to give up. + */ + if ((tp->t_flags & XFS_TRANS_DIRTY) && + !XFS_FORCED_SHUTDOWN(tp->t_mountp)) + xfs_force_shutdown(tp->t_mountp, XFS_METADATA_IO_ERROR); +#ifdef DEBUG + if (!(flags & XFS_TRANS_ABORT)) { + licp = &(tp->t_items); + while (licp != NULL) { + lidp = licp->lic_descs; + for (i = 0; i < licp->lic_unused; i++, lidp++) { + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + lip = lidp->lid_item; + if (!XFS_FORCED_SHUTDOWN(tp->t_mountp)) + ASSERT(!(lip->li_type == XFS_LI_EFD)); + } + licp = licp->lic_next; + } + } +#endif + xfs_trans_unreserve_and_mod_sb(tp); + + if (tp->t_dqinfo && (tp->t_flags & XFS_TRANS_DQ_DIRTY)) + xfs_trans_unreserve_and_mod_dquots(tp); + + if (tp->t_ticket) { + if (flags & XFS_TRANS_RELEASE_LOG_RES) { + ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); + log_flags = XFS_LOG_REL_PERM_RESERV; + } else { + log_flags = 0; + } + xfs_log_done(tp->t_mountp, tp->t_ticket, log_flags); + } + xfs_trans_free_items(tp, flags); + xfs_trans_free(tp); +} + + +/* + * Free the transaction structure. If there is more clean up + * to do when the structure is freed, add it here. + */ +STATIC void +xfs_trans_free( + xfs_trans_t *tp) +{ + atomic_dec(&tp->t_mountp->m_active_trans); + if (tp->t_dqinfo) + xfs_trans_free_dqinfo(tp); + kmem_zone_free(xfs_trans_zone, tp); +} + + +/* + * THIS SHOULD BE REWRITTEN TO USE xfs_trans_next_item(). + * + * This is typically called by the LM when a transaction has been fully + * committed to disk. It needs to unpin the items which have + * been logged by the transaction and update their positions + * in the AIL if necessary. + * This also gets called when the transactions didn't get written out + * because of an I/O error. Abortflag & XFS_LI_ABORTED is set then. + * + * Call xfs_trans_chunk_committed() to process the items in + * each chunk. + */ +STATIC void +xfs_trans_committed( + xfs_trans_t *tp, + int abortflag) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_chunk_t *next_licp; + + /* + * Call the transaction's completion callback if there + * is one. + */ + if (tp->t_callback != NULL) { + tp->t_callback(tp, tp->t_callarg); + } + + /* + * Special case the chunk embedded in the transaction. + */ + licp = &(tp->t_items); + if (!(XFS_LIC_ARE_ALL_FREE(licp))) { + xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag); + } + + /* + * Process the items in each chunk in turn. + */ + licp = licp->lic_next; + while (licp != NULL) { + ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); + xfs_trans_chunk_committed(licp, tp->t_lsn, abortflag); + next_licp = licp->lic_next; + kmem_free(licp, sizeof(xfs_log_item_chunk_t)); + licp = next_licp; + } + + /* + * That's it for the transaction structure. Free it. + */ + xfs_trans_free(tp); +} + +/* + * This is called to perform the commit processing for each + * item described by the given chunk. + * + * The commit processing consists of unlocking items which were + * held locked with the SYNC_UNLOCK attribute, calling the committed + * routine of each logged item, updating the item's position in the AIL + * if necessary, and unpinning each item. If the committed routine + * returns -1, then do nothing further with the item because it + * may have been freed. + * + * Since items are unlocked when they are copied to the incore + * log, it is possible for two transactions to be completing + * and manipulating the same item simultaneously. The AIL lock + * will protect the lsn field of each item. The value of this + * field can never go backwards. + * + * We unpin the items after repositioning them in the AIL, because + * otherwise they could be immediately flushed and we'd have to race + * with the flusher trying to pull the item from the AIL as we add it. + */ +STATIC void +xfs_trans_chunk_committed( + xfs_log_item_chunk_t *licp, + xfs_lsn_t lsn, + int aborted) +{ + xfs_log_item_desc_t *lidp; + xfs_log_item_t *lip; + xfs_lsn_t item_lsn; + struct xfs_mount *mp; + int i; + SPLDECL(s); + + lidp = licp->lic_descs; + for (i = 0; i < licp->lic_unused; i++, lidp++) { + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + lip = lidp->lid_item; + if (aborted) + lip->li_flags |= XFS_LI_ABORTED; + + if (lidp->lid_flags & XFS_LID_SYNC_UNLOCK) { + IOP_UNLOCK(lip); + } + + /* + * Send in the ABORTED flag to the COMMITTED routine + * so that it knows whether the transaction was aborted + * or not. + */ + item_lsn = IOP_COMMITTED(lip, lsn); + + /* + * If the committed routine returns -1, make + * no more references to the item. + */ + if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0) { + continue; + } + + /* + * If the returned lsn is greater than what it + * contained before, update the location of the + * item in the AIL. If it is not, then do nothing. + * Items can never move backwards in the AIL. + * + * While the new lsn should usually be greater, it + * is possible that a later transaction completing + * simultaneously with an earlier one using the + * same item could complete first with a higher lsn. + * This would cause the earlier transaction to fail + * the test below. + */ + mp = lip->li_mountp; + AIL_LOCK(mp,s); + if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0) { + /* + * This will set the item's lsn to item_lsn + * and update the position of the item in + * the AIL. + * + * xfs_trans_update_ail() drops the AIL lock. + */ + xfs_trans_update_ail(mp, lip, item_lsn, s); + } else { + AIL_UNLOCK(mp, s); + } + + /* + * Now that we've repositioned the item in the AIL, + * unpin it so it can be flushed. + */ + IOP_UNPIN(lip); + } +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_trans.h linux-2.4-xfs/linux/fs/xfs/xfs_trans.h --- linux-2.4.7/linux/fs/xfs/xfs_trans.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_trans.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,1000 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_TRANS_H__ +#define __XFS_TRANS_H__ + +/* + * This is the structure written in the log at the head of + * every transaction. It identifies the type and id of the + * transaction, and contains the number of items logged by + * the transaction so we know how many to expect during recovery. + * + * Do not change the below structure without redoing the code in + * xlog_recover_add_to_trans() and xlog_recover_add_to_cont_trans(). + */ +typedef struct xfs_trans_header { + uint th_magic; /* magic number */ + uint th_type; /* transaction type */ + __int32_t th_tid; /* transaction id (unused) */ + uint th_num_items; /* num items logged by trans */ +} xfs_trans_header_t; + +#define XFS_TRANS_HEADER_MAGIC 0x5452414e /* TRAN */ + +/* + * Log item types. + */ +#define XFS_LI_5_3_BUF 0x1234 /* v1 bufs, 1-block inode buffers */ +#define XFS_LI_5_3_INODE 0x1235 /* 1-block inode buffers */ +#define XFS_LI_EFI 0x1236 +#define XFS_LI_EFD 0x1237 +#define XFS_LI_IUNLINK 0x1238 +#define XFS_LI_6_1_INODE 0x1239 /* 4K non-aligned inode bufs */ +#define XFS_LI_6_1_BUF 0x123a /* v1, 4K inode buffers */ +#define XFS_LI_INODE 0x123b /* aligned ino chunks, var-size ibufs */ +#define XFS_LI_BUF 0x123c /* v2 bufs, variable sized inode bufs */ +#define XFS_LI_DQUOT 0x123d +#define XFS_LI_QUOTAOFF 0x123e +#define XFS_LI_RPC 0x123f /* CXFS RPC return info */ + +/* + * Transaction types. Used to distinguish types of buffers. + */ +#define XFS_TRANS_SETATTR_NOT_SIZE 1 +#define XFS_TRANS_SETATTR_SIZE 2 +#define XFS_TRANS_INACTIVE 3 +#define XFS_TRANS_CREATE 4 +#define XFS_TRANS_CREATE_TRUNC 5 +#define XFS_TRANS_TRUNCATE_FILE 6 +#define XFS_TRANS_REMOVE 7 +#define XFS_TRANS_LINK 8 +#define XFS_TRANS_RENAME 9 +#define XFS_TRANS_MKDIR 10 +#define XFS_TRANS_RMDIR 11 +#define XFS_TRANS_SYMLINK 12 +#define XFS_TRANS_SET_DMATTRS 13 +#define XFS_TRANS_GROWFS 14 +#define XFS_TRANS_STRAT_WRITE 15 +#define XFS_TRANS_DIOSTRAT 16 +#define XFS_TRANS_WRITE_SYNC 17 +#define XFS_TRANS_WRITEID 18 +#define XFS_TRANS_ADDAFORK 19 +#define XFS_TRANS_ATTRINVAL 20 +#define XFS_TRANS_ATRUNCATE 21 +#define XFS_TRANS_ATTR_SET 22 +#define XFS_TRANS_ATTR_RM 23 +#define XFS_TRANS_ATTR_FLAG 24 +#define XFS_TRANS_CLEAR_AGI_BUCKET 25 +#define XFS_TRANS_QM_SBCHANGE 26 +/* + * Dummy entries since we use the transaction type to index into the + * trans_type[] in xlog_recover_print_trans_head() + */ +#define XFS_TRANS_DUMMY1 27 +#define XFS_TRANS_DUMMY2 28 +#define XFS_TRANS_QM_QUOTAOFF 29 +#define XFS_TRANS_QM_DQALLOC 30 +#define XFS_TRANS_QM_SETQLIM 31 +#define XFS_TRANS_QM_DQCLUSTER 32 +#define XFS_TRANS_QM_QINOCREATE 33 +#define XFS_TRANS_QM_QUOTAOFF_END 34 +#define XFS_TRANS_SB_UNIT 35 +#define XFS_TRANS_FSYNC_TS 36 +#define XFS_TRANS_GROWFSRT_ALLOC 37 +#define XFS_TRANS_GROWFSRT_ZERO 38 +#define XFS_TRANS_GROWFSRT_FREE 39 +#define XFS_TRANS_SWAPEXT 40 +/* new transaction types need to be reflected in xfs_logprint(8) */ + + +#ifdef __KERNEL__ +struct xfs_buf; +struct buftarg; +struct xfs_efd_log_item; +struct xfs_efi_log_item; +struct xfs_inode; +struct xfs_item_ops; +struct xfs_log_iovec; +struct xfs_log_item; +struct xfs_log_item_desc; +struct xfs_mount; +struct xfs_trans; +struct xfs_dquot_acct; + +typedef struct xfs_ail_entry { + struct xfs_log_item *ail_forw; /* AIL forw pointer */ + struct xfs_log_item *ail_back; /* AIL back pointer */ +} xfs_ail_entry_t; + +/* + * This structure is passed as a parameter to xfs_trans_push_ail() + * and is used to track the what LSN the waiting processes are + * waiting to become unused. + */ +typedef struct xfs_ail_ticket { + xfs_lsn_t at_lsn; /* lsn waitin for */ + struct xfs_ail_ticket *at_forw; /* wait list ptr */ + struct xfs_ail_ticket *at_back; /* wait list ptr */ + sv_t at_sema; /* wait sema */ +} xfs_ail_ticket_t; + + +typedef struct xfs_log_item { + xfs_ail_entry_t li_ail; /* AIL pointers */ + xfs_lsn_t li_lsn; /* last on-disk lsn */ + struct xfs_log_item_desc *li_desc; /* ptr to current desc*/ + struct xfs_mount *li_mountp; /* ptr to fs mount */ + uint li_type; /* item type */ + uint li_flags; /* misc flags */ + struct xfs_log_item *li_bio_list; /* buffer item list */ + void (*li_cb)(struct xfs_buf *, + struct xfs_log_item *); + /* buffer item iodone */ + /* callback func */ + struct xfs_item_ops *li_ops; /* function list */ +} xfs_log_item_t; + +#define XFS_LI_IN_AIL 0x1 +#define XFS_LI_ABORTED 0x2 + +typedef struct xfs_item_ops { + uint (*iop_size)(xfs_log_item_t *); + void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *); + void (*iop_pin)(xfs_log_item_t *); + void (*iop_unpin)(xfs_log_item_t *); + void (*iop_unpin_remove)(xfs_log_item_t *, struct xfs_trans *); + uint (*iop_trylock)(xfs_log_item_t *); + void (*iop_unlock)(xfs_log_item_t *); + xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t); + void (*iop_push)(xfs_log_item_t *); + void (*iop_abort)(xfs_log_item_t *); + void (*iop_pushbuf)(xfs_log_item_t *); + void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t); +} xfs_item_ops_t; + +#define IOP_SIZE(ip) (*(ip)->li_ops->iop_size)(ip) +#define IOP_FORMAT(ip,vp) (*(ip)->li_ops->iop_format)(ip, vp) +#define IOP_PIN(ip) (*(ip)->li_ops->iop_pin)(ip) +#define IOP_UNPIN(ip) (*(ip)->li_ops->iop_unpin)(ip) +#define IOP_UNPIN_REMOVE(ip,tp) (*(ip)->li_ops->iop_unpin_remove)(ip, tp) +#define IOP_TRYLOCK(ip) (*(ip)->li_ops->iop_trylock)(ip) +#define IOP_UNLOCK(ip) (*(ip)->li_ops->iop_unlock)(ip) +#define IOP_COMMITTED(ip, lsn) (*(ip)->li_ops->iop_committed)(ip, lsn) +#define IOP_PUSH(ip) (*(ip)->li_ops->iop_push)(ip) +#define IOP_ABORT(ip) (*(ip)->li_ops->iop_abort)(ip) +#define IOP_PUSHBUF(ip) (*(ip)->li_ops->iop_pushbuf)(ip) +#define IOP_COMMITTING(ip, lsn) (*(ip)->li_ops->iop_committing)(ip, lsn) + +/* + * Return values for the IOP_TRYLOCK() routines. + */ +#define XFS_ITEM_SUCCESS 0 +#define XFS_ITEM_PINNED 1 +#define XFS_ITEM_LOCKED 2 +#define XFS_ITEM_FLUSHING 3 +#define XFS_ITEM_PUSHBUF 4 + +#endif /* __KERNEL__ */ + +/* + * This structure is used to track log items associated with + * a transaction. It points to the log item and keeps some + * flags to track the state of the log item. It also tracks + * the amount of space needed to log the item it describes + * once we get to commit processing (see xfs_trans_commit()). + */ +typedef struct xfs_log_item_desc { + xfs_log_item_t *lid_item; + ushort lid_size; + unsigned char lid_flags; + unsigned char lid_index; +} xfs_log_item_desc_t; + +#define XFS_LID_DIRTY 0x1 +#define XFS_LID_PINNED 0x2 +#define XFS_LID_SYNC_UNLOCK 0x4 + +/* + * This structure is used to maintain a chunk list of log_item_desc + * structures. The free field is a bitmask indicating which descriptors + * in this chunk's array are free. The unused field is the first value + * not used since this chunk was allocated. + */ +#define XFS_LIC_NUM_SLOTS 15 +typedef struct xfs_log_item_chunk { + struct xfs_log_item_chunk *lic_next; + ushort lic_free; + ushort lic_unused; + xfs_log_item_desc_t lic_descs[XFS_LIC_NUM_SLOTS]; +} xfs_log_item_chunk_t; + +#define XFS_LIC_MAX_SLOT (XFS_LIC_NUM_SLOTS - 1) +#define XFS_LIC_FREEMASK ((1 << XFS_LIC_NUM_SLOTS) - 1) + + +/* + * Initialize the given chunk. Set the chunk's free descriptor mask + * to indicate that all descriptors are free. The caller gets to set + * lic_unused to the right value (0 matches all free). The + * lic_descs.lid_index values are set up as each desc is allocated. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_INIT) +void xfs_lic_init(xfs_log_item_chunk_t *cp); +#define XFS_LIC_INIT(cp) xfs_lic_init(cp) +#else +#define XFS_LIC_INIT(cp) ((cp)->lic_free = XFS_LIC_FREEMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_INIT_SLOT) +void xfs_lic_init_slot(xfs_log_item_chunk_t *cp, int slot); +#define XFS_LIC_INIT_SLOT(cp,slot) xfs_lic_init_slot(cp, slot) +#else +#define XFS_LIC_INIT_SLOT(cp,slot) \ + ((cp)->lic_descs[slot].lid_index = (unsigned char)(slot)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_VACANCY) +int xfs_lic_vacancy(xfs_log_item_chunk_t *cp); +#define XFS_LIC_VACANCY(cp) xfs_lic_vacancy(cp) +#else +#define XFS_LIC_VACANCY(cp) (((cp)->lic_free) & XFS_LIC_FREEMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_ALL_FREE) +void xfs_lic_all_free(xfs_log_item_chunk_t *cp); +#define XFS_LIC_ALL_FREE(cp) xfs_lic_all_free(cp) +#else +#define XFS_LIC_ALL_FREE(cp) ((cp)->lic_free = XFS_LIC_FREEMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_ARE_ALL_FREE) +int xfs_lic_are_all_free(xfs_log_item_chunk_t *cp); +#define XFS_LIC_ARE_ALL_FREE(cp) xfs_lic_are_all_free(cp) +#else +#define XFS_LIC_ARE_ALL_FREE(cp) (((cp)->lic_free & XFS_LIC_FREEMASK) ==\ + XFS_LIC_FREEMASK) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_ISFREE) +int xfs_lic_isfree(xfs_log_item_chunk_t *cp, int slot); +#define XFS_LIC_ISFREE(cp,slot) xfs_lic_isfree(cp,slot) +#else +#define XFS_LIC_ISFREE(cp,slot) ((cp)->lic_free & (1 << (slot))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_CLAIM) +void xfs_lic_claim(xfs_log_item_chunk_t *cp, int slot); +#define XFS_LIC_CLAIM(cp,slot) xfs_lic_claim(cp,slot) +#else +#define XFS_LIC_CLAIM(cp,slot) ((cp)->lic_free &= ~(1 << (slot))) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_RELSE) +void xfs_lic_relse(xfs_log_item_chunk_t *cp, int slot); +#define XFS_LIC_RELSE(cp,slot) xfs_lic_relse(cp,slot) +#else +#define XFS_LIC_RELSE(cp,slot) ((cp)->lic_free |= 1 << (slot)) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_SLOT) +xfs_log_item_desc_t *xfs_lic_slot(xfs_log_item_chunk_t *cp, int slot); +#define XFS_LIC_SLOT(cp,slot) xfs_lic_slot(cp,slot) +#else +#define XFS_LIC_SLOT(cp,slot) (&((cp)->lic_descs[slot])) +#endif +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_DESC_TO_SLOT) +int xfs_lic_desc_to_slot(xfs_log_item_desc_t *dp); +#define XFS_LIC_DESC_TO_SLOT(dp) xfs_lic_desc_to_slot(dp) +#else +#define XFS_LIC_DESC_TO_SLOT(dp) ((uint)((dp)->lid_index)) +#endif +/* + * Calculate the address of a chunk given a descriptor pointer: + * dp - dp->lid_index give the address of the start of the lic_descs array. + * From this we subtract the offset of the lic_descs field in a chunk. + * All of this yields the address of the chunk, which is + * cast to a chunk pointer. + */ +#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_LIC_DESC_TO_CHUNK) +xfs_log_item_chunk_t *xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp); +#define XFS_LIC_DESC_TO_CHUNK(dp) xfs_lic_desc_to_chunk(dp) +#else +#define XFS_LIC_DESC_TO_CHUNK(dp) ((xfs_log_item_chunk_t*) \ + (((xfs_caddr_t)((dp) - (dp)->lid_index)) -\ + (xfs_caddr_t)(((xfs_log_item_chunk_t*) \ + 0)->lic_descs))) +#endif + +#ifdef __KERNEL__ +/* + * This is the type of function which can be given to xfs_trans_callback() + * to be called upon the transaction's commit to disk. + */ +typedef void (*xfs_trans_callback_t)(struct xfs_trans *, void *); + +/* + * This is the structure maintained for every active transaction. + */ +typedef struct xfs_trans { + unsigned int t_magic; /* magic number */ + xfs_log_callback_t t_logcb; /* log callback struct */ + struct xfs_trans *t_forw; /* async list pointers */ + struct xfs_trans *t_back; /* async list pointers */ + unsigned int t_type; /* transaction type */ + unsigned int t_log_res; /* amt of log space resvd */ + unsigned int t_log_count; /* count for perm log res */ + unsigned int t_blk_res; /* # of blocks resvd */ + unsigned int t_blk_res_used; /* # of resvd blocks used */ + unsigned int t_rtx_res; /* # of rt extents resvd */ + unsigned int t_rtx_res_used; /* # of resvd rt extents used */ + xfs_log_ticket_t t_ticket; /* log mgr ticket */ + sema_t t_sema; /* sema for commit completion */ + xfs_lsn_t t_lsn; /* log seq num of trans commit*/ + struct xfs_mount *t_mountp; /* ptr to fs mount struct */ + struct xfs_dquot_acct *t_dqinfo; /* accting info for dquots */ + xfs_trans_callback_t t_callback; /* transaction callback */ + void *t_callarg; /* callback arg */ + unsigned int t_flags; /* misc flags */ + long t_icount_delta; /* superblock icount change */ + long t_ifree_delta; /* superblock ifree change */ + long t_fdblocks_delta; /* superblock fdblocks chg */ + long t_res_fdblocks_delta; /* on-disk only chg */ + long t_frextents_delta;/* superblock freextents chg*/ + long t_res_frextents_delta; /* on-disk only chg */ + long t_ag_freeblks_delta; /* debugging counter */ + long t_ag_flist_delta; /* debugging counter */ + long t_ag_btree_delta; /* debugging counter */ + long t_dblocks_delta;/* superblock dblocks change */ + long t_agcount_delta;/* superblock agcount change */ + long t_imaxpct_delta;/* superblock imaxpct change */ + long t_rextsize_delta;/* superblock rextsize chg */ + long t_rbmblocks_delta;/* superblock rbmblocks chg */ + long t_rblocks_delta;/* superblock rblocks change */ + long t_rextents_delta;/* superblocks rextents chg */ + long t_rextslog_delta;/* superblocks rextslog chg */ + unsigned int t_items_free; /* log item descs free */ + xfs_log_item_chunk_t t_items; /* first log item desc chunk */ + xfs_trans_header_t t_header; /* header for in-log trans */ +} xfs_trans_t; + +#endif /* __KERNEL__ */ + + +#define XFS_TRANS_MAGIC 0x5452414E /* 'TRAN' */ +/* + * Values for t_flags. + */ +#define XFS_TRANS_DIRTY 0x01 /* something needs to be logged */ +#define XFS_TRANS_SB_DIRTY 0x02 /* superblock is modified */ +#define XFS_TRANS_PERM_LOG_RES 0x04 /* xact took a permanent log res */ +#define XFS_TRANS_SYNC 0x08 /* make commit synchronous */ +#define XFS_TRANS_DQ_DIRTY 0x10 /* at least one dquot in trx dirty */ +#define XFS_TRANS_RESERVE 0x20 /* OK to use reserved data blocks */ + +/* + * Values for call flags parameter. + */ +#define XFS_TRANS_NOSLEEP 0x1 +#define XFS_TRANS_WAIT 0x2 +#define XFS_TRANS_RELEASE_LOG_RES 0x4 +#define XFS_TRANS_ABORT 0x8 + +/* + * Field values for xfs_trans_mod_sb. + */ +#define XFS_TRANS_SB_ICOUNT 0x00000001 +#define XFS_TRANS_SB_IFREE 0x00000002 +#define XFS_TRANS_SB_FDBLOCKS 0x00000004 +#define XFS_TRANS_SB_RES_FDBLOCKS 0x00000008 +#define XFS_TRANS_SB_FREXTENTS 0x00000010 +#define XFS_TRANS_SB_RES_FREXTENTS 0x00000020 +#define XFS_TRANS_SB_DBLOCKS 0x00000040 +#define XFS_TRANS_SB_AGCOUNT 0x00000080 +#define XFS_TRANS_SB_IMAXPCT 0x00000100 +#define XFS_TRANS_SB_REXTSIZE 0x00000200 +#define XFS_TRANS_SB_RBMBLOCKS 0x00000400 +#define XFS_TRANS_SB_RBLOCKS 0x00000800 +#define XFS_TRANS_SB_REXTENTS 0x00001000 +#define XFS_TRANS_SB_REXTSLOG 0x00002000 + + +/* + * Various log reservation values. + * These are based on the size of the file system block + * because that is what most transactions manipulate. + * Each adds in an additional 128 bytes per item logged to + * try to account for the overhead of the transaction mechanism. + * + * Note: + * Most of the reservations underestimate the number of allocation + * groups into which they could free extents in the xfs_bmap_finish() + * call. This is because the number in the worst case is quite high + * and quite unusual. In order to fix this we need to change + * xfs_bmap_finish() to free extents in only a single AG at a time. + * This will require changes to the EFI code as well, however, so that + * the EFI for the extents not freed is logged again in each transaction. + * See bug 261917. + */ + +/* + * Per-extent log reservation for the allocation btree changes + * involved in freeing or allocating an extent. + * 2 trees * (2 blocks/level * max depth - 1) * block size + */ +#define XFS_ALLOCFREE_LOG_RES(mp,nx) \ + ((nx) * (2 * XFS_FSB_TO_B((mp), 2 * XFS_AG_MAXLEVELS(mp) - 1))) +#define XFS_ALLOCFREE_LOG_COUNT(mp,nx) \ + ((nx) * (2 * (2 * XFS_AG_MAXLEVELS(mp) - 1))) + +/* + * Per-directory log reservation for any directory change. + * dir blocks: (1 btree block per level + data block + free block) * dblock size + * bmap btree: (levels + 2) * max depth * block size + * v2 directory blocks can be fragmented below the dirblksize down to the fsb + * size, so account for that in the DAENTER macros. + */ +#define XFS_DIROP_LOG_RES(mp) \ + (XFS_FSB_TO_B(mp, XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK)) + \ + (XFS_FSB_TO_B(mp, XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1))) +#define XFS_DIROP_LOG_COUNT(mp) \ + (XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK) + \ + XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1) + +/* + * In a write transaction we can allocate a maximum of 2 + * extents. This gives: + * the inode getting the new extents: inode size + * the inode\'s bmap btree: max depth * block size + * the agfs of the ags from which the extents are allocated: 2 * sector + * the superblock free block counter: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size + * And the bmap_finish transaction can free bmap blocks in a join: + * the agfs of the ags containing the blocks: 2 * sector size + * the agfls of the ags containing the blocks: 2 * sector size + * the super block free block counter: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_WRITE_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)) + \ + (2 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 2) + \ + (128 * (4 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))),\ + ((2 * (mp)->m_sb.sb_sectsize) + \ + (2 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 2) + \ + (128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))))) + +#define XFS_WRITE_LOG_RES(mp) ((mp)->m_reservations.tr_write) + +/* + * In truncating a file we free up to two extents at once. We can modify: + * the inode being truncated: inode size + * the inode\'s bmap btree: (max depth + 1) * block size + * And the bmap_finish transaction can free the blocks and bmap blocks: + * the agf for each of the ags: 4 * sector size + * the agfl for each of the ags: 4 * sector size + * the super block to reflect the freed blocks: sector size + * worst case split in allocation btrees per extent assuming 4 extents: + * 4 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_ITRUNCATE_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1) + \ + (128 * (2 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)))), \ + ((4 * (mp)->m_sb.sb_sectsize) + \ + (4 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 4) + \ + (128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4)))))) + +#define XFS_ITRUNCATE_LOG_RES(mp) ((mp)->m_reservations.tr_itruncate) + +/* + * In renaming a files we can modify: + * the four inodes involved: 4 * inode size + * the two directory btrees: 2 * (max depth + v2) * dir block size + * the two directory bmap btrees: 2 * max depth * block size + * And the bmap_finish transaction can free dir and bmap blocks (two sets + * of bmap blocks) giving: + * the agf for the ags in which the blocks live: 3 * sector size + * the agfl for the ags in which the blocks live: 3 * sector size + * the superblock for the free block count: sector size + * the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_RENAME_LOG_RES(mp) \ + (MAX( \ + ((4 * (mp)->m_sb.sb_inodesize) + \ + (2 * XFS_DIROP_LOG_RES(mp)) + \ + (128 * (4 + 2 * XFS_DIROP_LOG_COUNT(mp)))), \ + ((3 * (mp)->m_sb.sb_sectsize) + \ + (3 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 3) + \ + (128 * (7 + XFS_ALLOCFREE_LOG_COUNT(mp, 3)))))) + +#define XFS_RENAME_LOG_RES(mp) ((mp)->m_reservations.tr_rename) + +/* + * For creating a link to an inode: + * the parent directory inode: inode size + * the linked inode: inode size + * the directory btree could split: (max depth + v2) * dir block size + * the directory bmap btree could join or split: (max depth + v2) * blocksize + * And the bmap_finish transaction can free some bmap blocks giving: + * the agf for the ag in which the blocks live: sector size + * the agfl for the ag in which the blocks live: sector size + * the superblock for the free block count: sector size + * the allocation btrees: 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_LINK_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_inodesize + \ + XFS_DIROP_LOG_RES(mp) + \ + (128 * (2 + XFS_DIROP_LOG_COUNT(mp)))), \ + ((mp)->m_sb.sb_sectsize + \ + (mp)->m_sb.sb_sectsize + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (3 + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))))) + +#define XFS_LINK_LOG_RES(mp) ((mp)->m_reservations.tr_link) + +/* + * For removing a directory entry we can modify: + * the parent directory inode: inode size + * the removed inode: inode size + * the directory btree could join: (max depth + v2) * dir block size + * the directory bmap btree could join or split: (max depth + v2) * blocksize + * And the bmap_finish transaction can free the dir and bmap blocks giving: + * the agf for the ag in which the blocks live: 2 * sector size + * the agfl for the ag in which the blocks live: 2 * sector size + * the superblock for the free block count: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_REMOVE_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_inodesize + \ + XFS_DIROP_LOG_RES(mp) + \ + (128 * (2 + XFS_DIROP_LOG_COUNT(mp)))), \ + ((2 * (mp)->m_sb.sb_sectsize) + \ + (2 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 2) + \ + (128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))))) + +#define XFS_REMOVE_LOG_RES(mp) ((mp)->m_reservations.tr_remove) + +/* + * For symlink we can modify: + * the parent directory inode: inode size + * the new inode: inode size + * the inode btree entry: 1 block + * the directory btree: (max depth + v2) * dir block size + * the directory inode\'s bmap btree: (max depth + v2) * block size + * the blocks for the symlink: 1 KB + * Or in the first xact we allocate some inodes giving: + * the agi and agf of the ag getting the new inodes: 2 * sectorsize + * the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize + * the inode btree: max depth * blocksize + * the allocation btrees: 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_SYMLINK_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_inodesize + \ + XFS_FSB_TO_B(mp, 1) + \ + XFS_DIROP_LOG_RES(mp) + \ + 1024 + \ + (128 * (4 + XFS_DIROP_LOG_COUNT(mp)))), \ + (2 * (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B((mp), XFS_IALLOC_BLOCKS((mp))) + \ + XFS_FSB_TO_B((mp), XFS_IN_MAXLEVELS(mp)) + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (2 + XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp) + \ + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))))) + +#define XFS_SYMLINK_LOG_RES(mp) ((mp)->m_reservations.tr_symlink) + +/* + * For create we can modify: + * the parent directory inode: inode size + * the new inode: inode size + * the inode btree entry: block size + * the superblock for the nlink flag: sector size + * the directory btree: (max depth + v2) * dir block size + * the directory inode\'s bmap btree: (max depth + v2) * block size + * Or in the first xact we allocate some inodes giving: + * the agi and agf of the ag getting the new inodes: 2 * sectorsize + * the superblock for the nlink flag: sector size + * the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize + * the inode btree: max depth * blocksize + * the allocation btrees: 2 trees * (max depth - 1) * block size + */ +#define XFS_CALC_CREATE_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B(mp, 1) + \ + XFS_DIROP_LOG_RES(mp) + \ + (128 * (3 + XFS_DIROP_LOG_COUNT(mp)))), \ + (3 * (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B((mp), XFS_IALLOC_BLOCKS((mp))) + \ + XFS_FSB_TO_B((mp), XFS_IN_MAXLEVELS(mp)) + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (2 + XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp) + \ + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))))) + +#define XFS_CREATE_LOG_RES(mp) ((mp)->m_reservations.tr_create) + +/* + * Making a new directory is the same as creating a new file. + */ +#define XFS_CALC_MKDIR_LOG_RES(mp) XFS_CALC_CREATE_LOG_RES(mp) + +#define XFS_MKDIR_LOG_RES(mp) ((mp)->m_reservations.tr_mkdir) + +/* + * In freeing an inode we can modify: + * the inode being freed: inode size + * the super block free inode counter: sector size + * the agi hash list and counters: sector size + * the inode btree entry: block size + * the on disk inode before ours in the agi hash list: inode cluster size + */ +#define XFS_CALC_IFREE_LOG_RES(mp) \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_sectsize + \ + (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B((mp), 1) + \ + MAX(XFS_FSB_TO_B((mp), 1), XFS_INODE_CLUSTER_SIZE(mp)) + \ + (128 * 5)) + +#define XFS_IFREE_LOG_RES(mp) ((mp)->m_reservations.tr_ifree) + +/* + * When only changing the inode we log the inode and possibly the superblock + * We also add a bit of slop for the transaction stuff. + */ +#define XFS_CALC_ICHANGE_LOG_RES(mp) ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_sectsize + 512) + +#define XFS_ICHANGE_LOG_RES(mp) ((mp)->m_reservations.tr_ichange) + +/* + * Growing the data section of the filesystem. + * superblock + * agi and agf + * allocation btrees + */ +#define XFS_CALC_GROWDATA_LOG_RES(mp) \ + ((mp)->m_sb.sb_sectsize * 3 + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (3 + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) + +#define XFS_GROWDATA_LOG_RES(mp) ((mp)->m_reservations.tr_growdata) + +/* + * Growing the rt section of the filesystem. + * In the first set of transactions (ALLOC) we allocate space to the + * bitmap or summary files. + * superblock: sector size + * agf of the ag from which the extent is allocated: sector size + * bmap btree for bitmap/summary inode: max depth * blocksize + * bitmap/summary inode: inode size + * allocation btrees for 1 block alloc: 2 * (2 * maxdepth - 1) * blocksize + */ +#define XFS_CALC_GROWRTALLOC_LOG_RES(mp) \ + (2 * (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)) + \ + (mp)->m_sb.sb_inodesize + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * \ + (3 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + \ + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) + +#define XFS_GROWRTALLOC_LOG_RES(mp) ((mp)->m_reservations.tr_growrtalloc) + +/* + * Growing the rt section of the filesystem. + * In the second set of transactions (ZERO) we zero the new metadata blocks. + * one bitmap/summary block: blocksize + */ +#define XFS_CALC_GROWRTZERO_LOG_RES(mp) \ + ((mp)->m_sb.sb_blocksize + 128) + +#define XFS_GROWRTZERO_LOG_RES(mp) ((mp)->m_reservations.tr_growrtzero) + +/* + * Growing the rt section of the filesystem. + * In the third set of transactions (FREE) we update metadata without + * allocating any new blocks. + * superblock: sector size + * bitmap inode: inode size + * summary inode: inode size + * one bitmap block: blocksize + * summary blocks: new summary size + */ +#define XFS_CALC_GROWRTFREE_LOG_RES(mp) \ + ((mp)->m_sb.sb_sectsize + \ + 2 * (mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_blocksize + \ + (mp)->m_rsumsize + \ + (128 * 5)) + +#define XFS_GROWRTFREE_LOG_RES(mp) ((mp)->m_reservations.tr_growrtfree) + +/* + * Logging the inode modification timestamp on a synchronous write. + * inode + */ +#define XFS_CALC_SWRITE_LOG_RES(mp) \ + ((mp)->m_sb.sb_inodesize + 128) + +#define XFS_SWRITE_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) + +/* + * Logging the inode timestamps on an fsync -- same as SWRITE + * as long as SWRITE logs the entire inode core + */ +#define XFS_FSYNC_TS_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) + +/* + * Logging the inode mode bits when writing a setuid/setgid file + * inode + */ +#define XFS_CALC_WRITEID_LOG_RES(mp) \ + ((mp)->m_sb.sb_inodesize + 128) + +#define XFS_WRITEID_LOG_RES(mp) ((mp)->m_reservations.tr_swrite) + +/* + * Converting the inode from non-attributed to attributed. + * the inode being converted: inode size + * agf block and superblock (for block allocation) + * the new block (directory sized) + * bmap blocks for the new directory block + * allocation btrees + */ +#define XFS_CALC_ADDAFORK_LOG_RES(mp) \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_sectsize * 2 + \ + (mp)->m_dirblksize + \ + (XFS_DIR_IS_V1(mp) ? 0 : \ + XFS_FSB_TO_B(mp, (XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1))) + \ + XFS_ALLOCFREE_LOG_RES(mp, 1) + \ + (128 * (4 + \ + (XFS_DIR_IS_V1(mp) ? 0 : \ + XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1) + \ + XFS_ALLOCFREE_LOG_COUNT(mp, 1)))) + +#define XFS_ADDAFORK_LOG_RES(mp) ((mp)->m_reservations.tr_addafork) + +/* + * Removing the attribute fork of a file + * the inode being truncated: inode size + * the inode\'s bmap btree: max depth * block size + * And the bmap_finish transaction can free the blocks and bmap blocks: + * the agf for each of the ags: 4 * sector size + * the agfl for each of the ags: 4 * sector size + * the super block to reflect the freed blocks: sector size + * worst case split in allocation btrees per extent assuming 4 extents: + * 4 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_ATTRINVAL_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + \ + (128 * (1 + XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)))), \ + ((4 * (mp)->m_sb.sb_sectsize) + \ + (4 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 4) + \ + (128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4)))))) + +#define XFS_ATTRINVAL_LOG_RES(mp) ((mp)->m_reservations.tr_attrinval) + +/* + * Setting an attribute. + * the inode getting the attribute + * the superblock for allocations + * the agfs extents are allocated from + * the attribute btree * max depth + * the inode allocation btree + * Since attribute transaction space is dependent on the size of the attribute, + * the calculation is done partially at mount time and partially at runtime. + */ +#define XFS_CALC_ATTRSET_LOG_RES(mp) \ + ((mp)->m_sb.sb_inodesize + \ + (mp)->m_sb.sb_sectsize + \ + XFS_FSB_TO_B((mp), XFS_DA_NODE_MAXDEPTH) + \ + (128 * (2 + XFS_DA_NODE_MAXDEPTH))) + +#define XFS_ATTRSET_LOG_RES(mp, ext) \ + ((mp)->m_reservations.tr_attrset + \ + (ext * (mp)->m_sb.sb_sectsize) + \ + (ext * XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK))) + \ + (128 * (ext + (ext * XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK))))) + +/* + * Removing an attribute. + * the inode: inode size + * the attribute btree could join: max depth * block size + * the inode bmap btree could join or split: max depth * block size + * And the bmap_finish transaction can free the attr blocks freed giving: + * the agf for the ag in which the blocks live: 2 * sector size + * the agfl for the ag in which the blocks live: 2 * sector size + * the superblock for the free block count: sector size + * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size + */ +#define XFS_CALC_ATTRRM_LOG_RES(mp) \ + (MAX( \ + ((mp)->m_sb.sb_inodesize + \ + XFS_FSB_TO_B((mp), XFS_DA_NODE_MAXDEPTH) + \ + XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + \ + (128 * (1 + XFS_DA_NODE_MAXDEPTH + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)))), \ + ((2 * (mp)->m_sb.sb_sectsize) + \ + (2 * (mp)->m_sb.sb_sectsize) + \ + (mp)->m_sb.sb_sectsize + \ + XFS_ALLOCFREE_LOG_RES(mp, 2) + \ + (128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))))) + +#define XFS_ATTRRM_LOG_RES(mp) ((mp)->m_reservations.tr_attrrm) + +/* + * Clearing a bad agino number in an agi hash bucket. + */ +#define XFS_CALC_CLEAR_AGI_BUCKET_LOG_RES(mp) \ + ((mp)->m_sb.sb_sectsize + 128) + +#define XFS_CLEAR_AGI_BUCKET_LOG_RES(mp) ((mp)->m_reservations.tr_clearagi) + + +/* + * Various log count values. + */ +#define XFS_DEFAULT_LOG_COUNT 1 +#define XFS_DEFAULT_PERM_LOG_COUNT 2 +#define XFS_ITRUNCATE_LOG_COUNT 2 +#define XFS_CREATE_LOG_COUNT 2 +#define XFS_MKDIR_LOG_COUNT 3 +#define XFS_SYMLINK_LOG_COUNT 3 +#define XFS_REMOVE_LOG_COUNT 2 +#define XFS_LINK_LOG_COUNT 2 +#define XFS_RENAME_LOG_COUNT 2 +#define XFS_WRITE_LOG_COUNT 2 +#define XFS_ADDAFORK_LOG_COUNT 2 +#define XFS_ATTRINVAL_LOG_COUNT 1 +#define XFS_ATTRSET_LOG_COUNT 3 +#define XFS_ATTRRM_LOG_COUNT 3 + +/* + * Here we centralize the specification of XFS meta-data buffer + * reference count values. This determine how hard the buffer + * cache tries to hold onto the buffer. + */ +#define XFS_AGF_REF 4 +#define XFS_AGI_REF 4 +#define XFS_AGFL_REF 3 +#define XFS_INO_BTREE_REF 3 +#define XFS_ALLOC_BTREE_REF 2 +#define XFS_BMAP_BTREE_REF 2 +#define XFS_DIR_BTREE_REF 2 +#define XFS_ATTR_BTREE_REF 1 +#define XFS_INO_REF 1 +#define XFS_DQUOT_REF 1 + +#ifdef __KERNEL__ +/* + * XFS transaction mechanism exported interfaces that are + * actually macros. + */ +#define xfs_trans_get_log_res(tp) ((tp)->t_log_res) +#define xfs_trans_get_log_count(tp) ((tp)->t_log_count) +#define xfs_trans_get_block_res(tp) ((tp)->t_blk_res) +#define xfs_trans_set_sync(tp) ((tp)->t_flags |= XFS_TRANS_SYNC) + +#ifdef DEBUG +#define xfs_trans_agblocks_delta(tp, d) ((tp)->t_ag_freeblks_delta += (long)d) +#define xfs_trans_agflist_delta(tp, d) ((tp)->t_ag_flist_delta += (long)d) +#define xfs_trans_agbtree_delta(tp, d) ((tp)->t_ag_btree_delta += (long)d) +#else +#define xfs_trans_agblocks_delta(tp, d) +#define xfs_trans_agflist_delta(tp, d) +#define xfs_trans_agbtree_delta(tp, d) +#endif + +/* + * XFS transaction mechanism exported interfaces. + */ +void xfs_trans_init(struct xfs_mount *); +xfs_trans_t *xfs_trans_alloc(struct xfs_mount *, uint); +xfs_trans_t *xfs_trans_dup(xfs_trans_t *); +int xfs_trans_reserve(xfs_trans_t *, uint, uint, uint, + uint, uint); +void xfs_trans_callback(xfs_trans_t *, + void (*)(xfs_trans_t *, void *), void *); +void xfs_trans_mod_sb(xfs_trans_t *, uint, long); +struct xfs_buf *xfs_trans_get_buf(xfs_trans_t *, struct buftarg *, xfs_daddr_t, + int, uint); +int xfs_trans_read_buf(struct xfs_mount *, xfs_trans_t *, + struct buftarg *, xfs_daddr_t, int, uint, + struct xfs_buf **); +struct xfs_buf *xfs_trans_getsb(xfs_trans_t *, struct xfs_mount *, int); + +void xfs_trans_brelse(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_bjoin(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_bhold(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_bhold_until_committed(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_binval(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *); +void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint); +void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *); +int xfs_trans_iget(struct xfs_mount *, xfs_trans_t *, + xfs_ino_t , uint, struct xfs_inode **); +void xfs_trans_iput(xfs_trans_t *, struct xfs_inode *, uint); +void xfs_trans_ijoin(xfs_trans_t *, struct xfs_inode *, uint); +void xfs_trans_ihold(xfs_trans_t *, struct xfs_inode *); +void xfs_trans_ihold_release(xfs_trans_t *, struct xfs_inode *); +void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint); +void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint); +struct xfs_efi_log_item *xfs_trans_get_efi(xfs_trans_t *, uint); +void xfs_efi_release(struct xfs_efi_log_item *, uint); +void xfs_trans_log_efi_extent(xfs_trans_t *, + struct xfs_efi_log_item *, + xfs_fsblock_t, + xfs_extlen_t); +struct xfs_efd_log_item *xfs_trans_get_efd(xfs_trans_t *, + struct xfs_efi_log_item *, + uint); +void xfs_trans_log_efd_extent(xfs_trans_t *, + struct xfs_efd_log_item *, + xfs_fsblock_t, + xfs_extlen_t); +void xfs_trans_log_create_rpc(xfs_trans_t *, int, xfs_ino_t); +void xfs_trans_log_setattr_rpc(xfs_trans_t *, int); +int xfs_trans_commit(xfs_trans_t *, uint flags, xfs_lsn_t *); +void xfs_trans_commit_async(struct xfs_mount *); +void xfs_trans_cancel(xfs_trans_t *, int); +void xfs_trans_ail_init(struct xfs_mount *); +xfs_lsn_t xfs_trans_push_ail(struct xfs_mount *, xfs_lsn_t); +xfs_lsn_t xfs_trans_tail_ail(struct xfs_mount *); +void xfs_trans_unlocked_item(struct xfs_mount *, + xfs_log_item_t *); + +/* + * Not necessarily exported, but used outside a single file. + */ +int xfs_trans_lsn_danger(struct xfs_mount *, xfs_lsn_t); + +#endif /* __KERNEL__ */ + +#endif /* __XFS_TRANS_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_trans_ail.c linux-2.4-xfs/linux/fs/xfs/xfs_trans_ail.c --- linux-2.4.7/linux/fs/xfs/xfs_trans_ail.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_trans_ail.c Wed Apr 18 21:37:23 2001 @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +STATIC void xfs_ail_insert(xfs_ail_entry_t *, xfs_log_item_t *); +STATIC xfs_log_item_t * xfs_ail_delete(xfs_ail_entry_t *, xfs_log_item_t *); +STATIC xfs_log_item_t * xfs_ail_min(xfs_ail_entry_t *); +STATIC xfs_log_item_t * xfs_ail_next(xfs_ail_entry_t *, xfs_log_item_t *); + +#ifdef XFSDEBUG +STATIC void xfs_ail_check(xfs_ail_entry_t *); +#else +#define xfs_ail_check(a) +#endif /* XFSDEBUG */ + + +/* + * This is called by the log manager code to determine the LSN + * of the tail of the log. This is exactly the LSN of the first + * item in the AIL. If the AIL is empty, then this function + * returns 0. + * + * We need the AIL lock in order to get a coherent read of the + * lsn of the last item in the AIL. + */ +xfs_lsn_t +xfs_trans_tail_ail( + xfs_mount_t *mp) +{ + xfs_lsn_t lsn; + xfs_log_item_t *lip; + SPLDECL(s); + + AIL_LOCK(mp,s); + lip = xfs_ail_min(&(mp->m_ail)); + if (lip == NULL) { + lsn = (xfs_lsn_t)0; + } else { + lsn = lip->li_lsn; + } + AIL_UNLOCK(mp, s); + + return lsn; +} + +/* + * xfs_trans_push_ail + * + * This routine is called to move the tail of the AIL + * forward. It does this by trying to flush items in the AIL + * whose lsns are below the given threshold_lsn. + * + * The routine returns the lsn of the tail of the log. + */ +xfs_lsn_t +xfs_trans_push_ail( + xfs_mount_t *mp, + xfs_lsn_t threshold_lsn) +{ + xfs_lsn_t lsn; + xfs_log_item_t *lip; + int gen; + int restarts; + int lock_result; + int flush_log; + SPLDECL(s); + +#define XFS_TRANS_PUSH_AIL_RESTARTS 10 + + AIL_LOCK(mp,s); + lip = xfs_trans_first_ail(mp, &gen); + if (lip == NULL || XFS_FORCED_SHUTDOWN(mp)) { + /* + * Just return if the AIL is empty. + */ + AIL_UNLOCK(mp, s); + return (xfs_lsn_t)0; + } + + XFS_STATS_INC(xfsstats.xs_push_ail); + + /* + * While the item we are looking at is below the given threshold + * try to flush it out. Make sure to limit the number of times + * we allow xfs_trans_next_ail() to restart scanning from the + * beginning of the list. We'd like not to stop until we've at least + * tried to push on everything in the AIL with an LSN less than + * the given threshold. However, we may give up before that if + * we realize that we've been holding the AIL_LOCK for 'too long', + * blocking interrupts. Currently, too long is < 500us roughly. + */ + flush_log = 0; + restarts = 0; + while (((restarts < XFS_TRANS_PUSH_AIL_RESTARTS) && + (XFS_LSN_CMP(lip->li_lsn, threshold_lsn) < 0))) { + /* + * If we can lock the item without sleeping, unlock + * the AIL lock and flush the item. Then re-grab the + * AIL lock so we can look for the next item on the + * AIL. Since we unlock the AIL while we flush the + * item, the next routine may start over again at the + * the beginning of the list if anything has changed. + * That is what the generation count is for. + * + * If we can't lock the item, either its holder will flush + * it or it is already being flushed or it is being relogged. + * In any of these case it is being taken care of and we + * can just skip to the next item in the list. + */ + lock_result = IOP_TRYLOCK(lip); + switch (lock_result) { + case XFS_ITEM_SUCCESS: + AIL_UNLOCK(mp, s); + XFS_STATS_INC(xfsstats.xs_push_ail_success); + IOP_PUSH(lip); + AIL_LOCK(mp,s); + break; + + case XFS_ITEM_PUSHBUF: + AIL_UNLOCK(mp, s); + XFS_STATS_INC(xfsstats.xs_push_ail_pushbuf); +#ifdef XFSRACEDEBUG + delay_for_intr(); + delay(300); +#endif + ASSERT(lip->li_ops->iop_pushbuf); + ASSERT(lip); + IOP_PUSHBUF(lip); + AIL_LOCK(mp,s); + break; + + case XFS_ITEM_PINNED: + XFS_STATS_INC(xfsstats.xs_push_ail_pinned); + flush_log = 1; + break; + + case XFS_ITEM_LOCKED: + XFS_STATS_INC(xfsstats.xs_push_ail_locked); + break; + + case XFS_ITEM_FLUSHING: + XFS_STATS_INC(xfsstats.xs_push_ail_flushing); + break; + + default: + ASSERT(0); + break; + } + + lip = xfs_trans_next_ail(mp, lip, &gen, &restarts); + if (lip == NULL) { + break; + } + if (XFS_FORCED_SHUTDOWN(mp)) { + /* + * Just return if we shut down during the last try. + */ + AIL_UNLOCK(mp, s); + return (xfs_lsn_t)0; + } + + } + + if (flush_log) { + /* + * If something we need to push out was pinned, then + * push out the log so it will become unpinned and + * move forward in the AIL. + */ + AIL_UNLOCK(mp, s); + XFS_STATS_INC(xfsstats.xs_push_ail_flush); + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); + AIL_LOCK(mp, s); + } + + lip = xfs_ail_min(&(mp->m_ail)); + if (lip == NULL) { + lsn = (xfs_lsn_t)0; + } else { + lsn = lip->li_lsn; + } + + AIL_UNLOCK(mp, s); + return lsn; +} /* xfs_trans_push_ail */ + + +/* + * This is to be called when an item is unlocked that may have + * been in the AIL. It will wake up the first member of the AIL + * wait list if this item's unlocking might allow it to progress. + * If the item is in the AIL, then we need to get the AIL lock + * while doing our checking so we don't race with someone going + * to sleep waiting for this event in xfs_trans_push_ail(). + */ +void +xfs_trans_unlocked_item( + xfs_mount_t *mp, + xfs_log_item_t *lip) +{ + xfs_log_item_t *min_lip; + + /* + * If we're forcibly shutting down, we may have + * unlocked log items arbitrarily. The last thing + * we want to do is to move the tail of the log + * over some potentially valid data. + */ + if (!(lip->li_flags & XFS_LI_IN_AIL) || + XFS_FORCED_SHUTDOWN(mp)) { + return; + } + + /* + * This is the one case where we can call into xfs_ail_min() + * without holding the AIL lock because we only care about the + * case where we are at the tail of the AIL. If the object isn't + * at the tail, it doesn't matter what result we get back. This + * is slightly racy because since we were just unlocked, we could + * go to sleep between the call to xfs_ail_min and the call to + * xfs_log_move_tail, have someone else lock us, commit to us disk, + * move us out of the tail of the AIL, and then we wake up. However, + * the call to xfs_log_move_tail() doesn't do anything if there's + * not enough free space to wake people up so we're safe calling it. + */ + min_lip = xfs_ail_min(&mp->m_ail); + + if (min_lip == lip) + xfs_log_move_tail(mp, 1); +} /* xfs_trans_unlocked_item */ + + +/* + * Update the position of the item in the AIL with the new + * lsn. If it is not yet in the AIL, add it. Otherwise, move + * it to its new position by removing it and re-adding it. + * + * Wakeup anyone with an lsn less than the item's lsn. If the item + * we move in the AIL is the minimum one, update the tail lsn in the + * log manager. + * + * Increment the AIL's generation count to indicate that the tree + * has changed. + * + * This function must be called with the AIL lock held. The lock + * is dropped before returning, so the caller must pass in the + * cookie returned by AIL_LOCK. + */ +void +_xfs_trans_update_ail( + xfs_mount_t *mp, + xfs_log_item_t *lip, + xfs_lsn_t lsn +#if !defined(INTERRUPT_LATENCY_TESTING) + , int s +#endif + ) +{ + xfs_ail_entry_t *ailp; + xfs_log_item_t *dlip=NULL; + xfs_log_item_t *mlip; /* ptr to minimum lip */ + + ailp = &(mp->m_ail); + mlip = xfs_ail_min(ailp); + + if (lip->li_flags & XFS_LI_IN_AIL) { + dlip = xfs_ail_delete(ailp, lip); + ASSERT(dlip == lip); + } else { + lip->li_flags |= XFS_LI_IN_AIL; + } + + lip->li_lsn = lsn; + + xfs_ail_insert(ailp, lip); + mp->m_ail_gen++; + + if (mlip == dlip) { + mlip = xfs_ail_min(&(mp->m_ail)); + AIL_UNLOCK(mp, s); + xfs_log_move_tail(mp, mlip->li_lsn); + } else { + AIL_UNLOCK(mp, s); + } + + +} /* xfs_trans_update_ail */ + +/* + * Delete the given item from the AIL. It must already be in + * the AIL. + * + * Wakeup anyone with an lsn less than item's lsn. If the item + * we delete in the AIL is the minimum one, update the tail lsn in the + * log manager. + * + * Clear the IN_AIL flag from the item, reset its lsn to 0, and + * bump the AIL's generation count to indicate that the tree + * has changed. + * + * This function must be called with the AIL lock held. The lock + * is dropped before returning, so the caller must pass in the + * cookie returned by AIL_LOCK. + */ +void +_xfs_trans_delete_ail( + xfs_mount_t *mp, + xfs_log_item_t *lip +#if !defined(INTERRUPT_LATENCY_TESTING) + , int s +#endif + ) + +{ + xfs_ail_entry_t *ailp; + xfs_log_item_t *dlip; + xfs_log_item_t *mlip; + + if (lip->li_flags & XFS_LI_IN_AIL) { + ailp = &(mp->m_ail); + mlip = xfs_ail_min(ailp); + dlip = xfs_ail_delete(ailp, lip); + ASSERT(dlip == lip); + + + lip->li_flags &= ~XFS_LI_IN_AIL; + lip->li_lsn = 0; + mp->m_ail_gen++; + + if (mlip == dlip) { + mlip = xfs_ail_min(&(mp->m_ail)); + AIL_UNLOCK(mp, s); + xfs_log_move_tail(mp, (mlip ? mlip->li_lsn : 0)); + } else { + AIL_UNLOCK(mp, s); + } + } + else { + /* + * If the file system is not being shutdown, we are in + * serious trouble if we get to this stage. + */ + if (XFS_FORCED_SHUTDOWN(mp)) + AIL_UNLOCK(mp, s); + else { + xfs_cmn_err(XFS_PTAG_AILDELETE, CE_ALERT, mp, + "_xfs_trans_delete_ail: attempting to delete a log item that is not in the AIL"); + xfs_force_shutdown(mp, XFS_CORRUPT_INCORE); + AIL_UNLOCK(mp, s); + } + } +} + + + +/* + * Return the item in the AIL with the smallest lsn. + * Return the current tree generation number for use + * in calls to xfs_trans_next_ail(). + */ +xfs_log_item_t * +xfs_trans_first_ail( + xfs_mount_t *mp, + int *gen) +{ + xfs_log_item_t *lip; + + lip = xfs_ail_min(&(mp->m_ail)); + *gen = (int)mp->m_ail_gen; + + return (lip); +} + +/* + * If the generation count of the tree has not changed since the + * caller last took something from the AIL, then return the elmt + * in the tree which follows the one given. If the count has changed, + * then return the minimum elmt of the AIL and bump the restarts counter + * if one is given. + */ +xfs_log_item_t * +xfs_trans_next_ail( + xfs_mount_t *mp, + xfs_log_item_t *lip, + int *gen, + int *restarts) +{ + xfs_log_item_t *nlip; + + ASSERT(mp && lip && gen); + if (mp->m_ail_gen == *gen) { + nlip = xfs_ail_next(&(mp->m_ail), lip); + } else { + nlip = xfs_ail_min(&(mp->m_ail)); + *gen = (int)mp->m_ail_gen; + if (restarts != NULL) { + XFS_STATS_INC(xfsstats.xs_push_ail_restarts); + (*restarts)++; + } + } + + return (nlip); +} + + +/* + * The active item list (AIL) is a doubly linked list of log + * items sorted by ascending lsn. The base of the list is + * a forw/back pointer pair embedded in the xfs mount structure. + * The base is initialized with both pointers pointing to the + * base. This case always needs to be distinguished, because + * the base has no lsn to look at. We almost always insert + * at the end of the list, so on inserts we search from the + * end of the list to find where the new item belongs. + */ + +/* + * Initialize the doubly linked list to point only to itself. + */ +void +xfs_trans_ail_init( + xfs_mount_t *mp) +{ + mp->m_ail.ail_forw = (xfs_log_item_t*)&(mp->m_ail); + mp->m_ail.ail_back = (xfs_log_item_t*)&(mp->m_ail); +} + +/* + * Insert the given log item into the AIL. + * We almost always insert at the end of the list, so on inserts + * we search from the end of the list to find where the + * new item belongs. + */ +STATIC void +xfs_ail_insert( + xfs_ail_entry_t *base, + xfs_log_item_t *lip) +/* ARGSUSED */ +{ + xfs_log_item_t *next_lip; + + /* + * If the list is empty, just insert the item. + */ + if (base->ail_back == (xfs_log_item_t*)base) { + base->ail_forw = lip; + base->ail_back = lip; + lip->li_ail.ail_forw = (xfs_log_item_t*)base; + lip->li_ail.ail_back = (xfs_log_item_t*)base; + return; + } + + next_lip = base->ail_back; + while ((next_lip != (xfs_log_item_t*)base) && + (XFS_LSN_CMP(next_lip->li_lsn, lip->li_lsn) > 0)) { + next_lip = next_lip->li_ail.ail_back; + } + ASSERT((next_lip == (xfs_log_item_t*)base) || + (XFS_LSN_CMP(next_lip->li_lsn, lip->li_lsn) <= 0)); + lip->li_ail.ail_forw = next_lip->li_ail.ail_forw; + lip->li_ail.ail_back = next_lip; + next_lip->li_ail.ail_forw = lip; + lip->li_ail.ail_forw->li_ail.ail_back = lip; + + xfs_ail_check(base); + return; +} + +/* + * Delete the given item from the AIL. Return a pointer to the item. + */ +/*ARGSUSED*/ +STATIC xfs_log_item_t * +xfs_ail_delete( + xfs_ail_entry_t *base, + xfs_log_item_t *lip) +/* ARGSUSED */ +{ + lip->li_ail.ail_forw->li_ail.ail_back = lip->li_ail.ail_back; + lip->li_ail.ail_back->li_ail.ail_forw = lip->li_ail.ail_forw; + lip->li_ail.ail_forw = NULL; + lip->li_ail.ail_back = NULL; + + xfs_ail_check(base); + return lip; +} + +/* + * Return a pointer to the first item in the AIL. + * If the AIL is empty, then return NULL. + */ +STATIC xfs_log_item_t * +xfs_ail_min( + xfs_ail_entry_t *base) +/* ARGSUSED */ +{ + register xfs_log_item_t *forw = base->ail_forw; + if (forw == (xfs_log_item_t*)base) { + return NULL; + } + return forw; +} + +/* + * Return a pointer to the item which follows + * the given item in the AIL. If the given item + * is the last item in the list, then return NULL. + */ +STATIC xfs_log_item_t * +xfs_ail_next( + xfs_ail_entry_t *base, + xfs_log_item_t *lip) +/* ARGSUSED */ +{ + if (lip->li_ail.ail_forw == (xfs_log_item_t*)base) { + return NULL; + } + return lip->li_ail.ail_forw; + +} + +#ifdef XFSDEBUG +/* + * Check that the list is sorted as it should be. + */ +STATIC void +xfs_ail_check( + xfs_ail_entry_t *base) +{ + xfs_log_item_t *lip; + xfs_log_item_t *prev_lip; + + lip = base->ail_forw; + if (lip == (xfs_log_item_t*)base) { + /* + * Make sure the pointers are correct when the list + * is empty. + */ + ASSERT(base->ail_back == (xfs_log_item_t*)base); + return; + } + + /* + * Walk the list checking forward and backward pointers, + * lsn ordering, and that every entry has the XFS_LI_IN_AIL + * flag set. + */ + prev_lip = (xfs_log_item_t*)base; + while (lip != (xfs_log_item_t*)base) { + if (prev_lip != (xfs_log_item_t*)base) { + ASSERT(prev_lip->li_ail.ail_forw == lip); + ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) <= 0); + } + ASSERT(lip->li_ail.ail_back == prev_lip); + ASSERT((lip->li_flags & XFS_LI_IN_AIL) != 0); + prev_lip = lip; + lip = lip->li_ail.ail_forw; + } + ASSERT(lip == (xfs_log_item_t*)base); + ASSERT(base->ail_back == prev_lip); +} +#endif /* XFSDEBUG */ + + + diff -rNu linux-2.4.7/linux/fs/xfs/xfs_trans_buf.c linux-2.4-xfs/linux/fs/xfs/xfs_trans_buf.c --- linux-2.4.7/linux/fs/xfs/xfs_trans_buf.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_trans_buf.c Tue Jun 26 15:52:59 2001 @@ -0,0 +1,1081 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +STATIC xfs_buf_t *xfs_trans_buf_item_match(xfs_trans_t *, buftarg_t *, + xfs_daddr_t, int); +STATIC xfs_buf_t *xfs_trans_buf_item_match_all(xfs_trans_t *, buftarg_t *, + xfs_daddr_t, int); + + +/* + * Get and lock the buffer for the caller if it is not already + * locked within the given transaction. If it is already locked + * within the transaction, just increment its lock recursion count + * and return a pointer to it. + * + * Use the fast path function xfs_trans_buf_item_match() or the buffer + * cache routine incore_match() to find the buffer + * if it is already owned by this transaction. + * + * If we don't already own the buffer, use get_buf() to get it. + * If it doesn't yet have an associated xfs_buf_log_item structure, + * then allocate one and add the item to this transaction. + * + * If the transaction pointer is NULL, make this just a normal + * get_buf() call. + */ +xfs_buf_t * +xfs_trans_get_buf(xfs_trans_t *tp, + buftarg_t *target_dev, + xfs_daddr_t blkno, + int len, + uint flags) +{ + xfs_buf_t *bp; + xfs_buf_log_item_t *bip; + + if (flags == 0) + flags = XFS_BUF_LOCK | XFS_BUF_MAPPED; + + /* + * Default to a normal get_buf() call if the tp is NULL. + */ + if (tp == NULL) { + bp = xfs_buf_get_flags(target_dev, blkno, len, flags); + return(bp); + } + + /* + * If we find the buffer in the cache with this transaction + * pointer in its b_fsprivate2 field, then we know we already + * have it locked. In this case we just increment the lock + * recursion count and return the buffer to the caller. + */ + if (tp->t_items.lic_next == NULL) { + bp = xfs_trans_buf_item_match(tp, target_dev, blkno, len); + } else { + bp = xfs_trans_buf_item_match_all(tp, target_dev, blkno, len); + } + if (bp != NULL) { + ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); + if (XFS_FORCED_SHUTDOWN(tp->t_mountp)) { + xfs_buftrace("TRANS GET RECUR SHUT", bp); + XFS_BUF_SUPER_STALE(bp); + } + /* + * If the buffer is stale then it was binval'ed + * since last read. This doesn't matter since the + * caller isn't allowed to use the data anyway. + */ + else if (XFS_BUF_ISSTALE(bp)) { + xfs_buftrace("TRANS GET RECUR STALE", bp); + ASSERT(!XFS_BUF_ISDELAYWRITE(bp)); + } + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(bip != NULL); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + bip->bli_recur++; + xfs_buftrace("TRANS GET RECUR", bp); + xfs_buf_item_trace("GET RECUR", bip); + return (bp); + } + + /* + * We always specify the BUF_BUSY flag within a transaction so + * that get_buf does not try to push out a delayed write buffer + * which might cause another transaction to take place (if the + * buffer was delayed alloc). Such recursive transactions can + * easily deadlock with our current transaction as well as cause + * us to run out of stack space. + */ + bp = xfs_buf_get_flags(target_dev, blkno, len, flags | BUF_BUSY); + if (bp == NULL) { + return NULL; + } + + ASSERT(!XFS_BUF_GETERROR(bp)); + + /* + * The xfs_buf_log_item pointer is stored in b_fsprivate. If + * it doesn't have one yet, then allocate one and initialize it. + * The checks to see if one is there are in xfs_buf_item_init(). + */ + xfs_buf_item_init(bp, tp->t_mountp); + + /* + * Set the recursion count for the buffer within this transaction + * to 0. + */ + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); + ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); + bip->bli_recur = 0; + + /* + * Take a reference for this transaction on the buf item. + */ + atomic_inc(&bip->bli_refcount); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)bip); + + /* + * Initialize b_fsprivate2 so we can find it with incore_match() + * above. + */ + XFS_BUF_SET_FSPRIVATE2(bp, tp); + + xfs_buftrace("TRANS GET", bp); + xfs_buf_item_trace("GET", bip); + return (bp); +} + +/* + * Get and lock the superblock buffer of this file system for the + * given transaction. + * + * We don't need to use incore_match() here, because the superblock + * buffer is a private buffer which we keep a pointer to in the + * mount structure. + */ +xfs_buf_t * +xfs_trans_getsb(xfs_trans_t *tp, + struct xfs_mount *mp, + int flags) +{ + xfs_buf_t *bp; + xfs_buf_log_item_t *bip; + + /* + * Default to just trying to lock the superblock buffer + * if tp is NULL. + */ + if (tp == NULL) { + return (xfs_getsb(mp, flags)); + } + + /* + * If the superblock buffer already has this transaction + * pointer in its b_fsprivate2 field, then we know we already + * have it locked. In this case we just increment the lock + * recursion count and return the buffer to the caller. + */ + bp = mp->m_sb_bp; + if (XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp) { + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + ASSERT(bip != NULL); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + bip->bli_recur++; + xfs_buf_item_trace("GETSB RECUR", bip); + return (bp); + } + + bp = xfs_getsb(mp, flags); + if (bp == NULL) { + return NULL; + } + + /* + * The xfs_buf_log_item pointer is stored in b_fsprivate. If + * it doesn't have one yet, then allocate one and initialize it. + * The checks to see if one is there are in xfs_buf_item_init(). + */ + xfs_buf_item_init(bp, mp); + + /* + * Set the recursion count for the buffer within this transaction + * to 0. + */ + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); + ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); + bip->bli_recur = 0; + + /* + * Take a reference for this transaction on the buf item. + */ + atomic_inc(&bip->bli_refcount); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)bip); + + /* + * Initialize b_fsprivate2 so we can find it with incore_match() + * above. + */ + XFS_BUF_SET_FSPRIVATE2(bp, tp); + + xfs_buf_item_trace("GETSB", bip); + return (bp); +} + +#ifdef DEBUG +dev_t xfs_error_dev = 0; +int xfs_do_error; +int xfs_req_num; +int xfs_error_mod = 33; +#endif + +/* + * Get and lock the buffer for the caller if it is not already + * locked within the given transaction. If it has not yet been + * read in, read it from disk. If it is already locked + * within the transaction and already read in, just increment its + * lock recursion count and return a pointer to it. + * + * Use the fast path function xfs_trans_buf_item_match() or the buffer + * cache routine incore_match() to find the buffer + * if it is already owned by this transaction. + * + * If we don't already own the buffer, use read_buf() to get it. + * If it doesn't yet have an associated xfs_buf_log_item structure, + * then allocate one and add the item to this transaction. + * + * If the transaction pointer is NULL, make this just a normal + * read_buf() call. + */ +int +xfs_trans_read_buf( + xfs_mount_t *mp, + xfs_trans_t *tp, + buftarg_t *target, + xfs_daddr_t blkno, + int len, + uint flags, + xfs_buf_t **bpp) +{ + xfs_buf_t *bp; + xfs_buf_log_item_t *bip; + int error; + + if (flags == 0) + flags = XFS_BUF_LOCK | XFS_BUF_MAPPED; + + /* + * Default to a normal get_buf() call if the tp is NULL. + */ + if (tp == NULL) { + bp = xfs_buf_read_flags(target, blkno, len, flags); + if ((bp != NULL) && (XFS_BUF_GETERROR(bp) != 0)) { + xfs_ioerror_alert("xfs_trans_read_buf", mp, + target->dev, blkno); + error = XFS_BUF_GETERROR(bp); + xfs_buf_relse(bp); + return error; + } +#ifdef DEBUG + if (xfs_do_error && (bp != NULL)) { + if (xfs_error_dev == target->dev) { + if (((xfs_req_num++) % xfs_error_mod) == 0) { + xfs_buf_relse(bp); + printk("Returning error!\n"); + return XFS_ERROR(EIO); + } + } + } +#endif + if (XFS_FORCED_SHUTDOWN(mp)) + goto shutdown_abort; + *bpp = bp; + return 0; + } + + /* + * If we find the buffer in the cache with this transaction + * pointer in its b_fsprivate2 field, then we know we already + * have it locked. If it is already read in we just increment + * the lock recursion count and return the buffer to the caller. + * If the buffer is not yet read in, then we read it in, increment + * the lock recursion count, and return it to the caller. + */ + if (tp->t_items.lic_next == NULL) { + bp = xfs_trans_buf_item_match(tp, target, blkno, len); + } else { + bp = xfs_trans_buf_item_match_all(tp, target, blkno, len); + } + if (bp != NULL) { + ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + ASSERT((XFS_BUF_ISERROR(bp)) == 0); + if (!(XFS_BUF_ISDONE(bp))) { + xfs_buftrace("READ_BUF_INCORE !DONE", bp); + ASSERT(!XFS_BUF_ISASYNC(bp)); + XFS_BUF_READ(bp); + xfsbdstrat(tp->t_mountp, bp); + xfs_iowait(bp); + if (XFS_BUF_GETERROR(bp) != 0) { + xfs_ioerror_alert("xfs_trans_read_buf", mp, + target->dev, blkno); + error = XFS_BUF_GETERROR(bp); + xfs_buf_relse(bp); + /* + * We can gracefully recover from most + * read errors. Ones we can't are those + * that happen after the transaction's + * already dirty. + */ + if (tp->t_flags & XFS_TRANS_DIRTY) + xfs_force_shutdown(tp->t_mountp, + XFS_METADATA_IO_ERROR); + return error; + } + } + /* + * We never locked this buf ourselves, so we shouldn't + * brelse it either. Just get out. + */ + if (XFS_FORCED_SHUTDOWN(mp)) { + xfs_buftrace("READ_BUF_INCORE XFSSHUTDN", bp); + *bpp = NULL; + return XFS_ERROR(EIO); + } + + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + bip->bli_recur++; + + ASSERT(atomic_read(&bip->bli_refcount) > 0); + xfs_buf_item_trace("READ RECUR", bip); + *bpp = bp; + return 0; + } + + /* + * We always specify the BUF_BUSY flag within a transaction so + * that get_buf does not try to push out a delayed write buffer + * which might cause another transaction to take place (if the + * buffer was delayed alloc). Such recursive transactions can + * easily deadlock with our current transaction as well as cause + * us to run out of stack space. + */ + bp = xfs_buf_read_flags(target, blkno, len, flags | BUF_BUSY); + if (bp == NULL) { + *bpp = NULL; + return 0; + } + if (XFS_BUF_GETERROR(bp) != 0) { + XFS_BUF_SUPER_STALE(bp); + xfs_buftrace("READ ERROR", bp); + error = XFS_BUF_GETERROR(bp); + + xfs_ioerror_alert("xfs_trans_read_buf", mp, + target->dev, blkno); + if (tp->t_flags & XFS_TRANS_DIRTY) + xfs_force_shutdown(tp->t_mountp, XFS_METADATA_IO_ERROR); + xfs_buf_relse(bp); + return error; + } +#ifdef DEBUG + if (xfs_do_error && !(tp->t_flags & XFS_TRANS_DIRTY)) { + if (xfs_error_dev == target->dev) { + if (((xfs_req_num++) % xfs_error_mod) == 0) { + xfs_force_shutdown(tp->t_mountp, + XFS_METADATA_IO_ERROR); + xfs_buf_relse(bp); + printk("Returning error in trans!\n"); + return XFS_ERROR(EIO); + } + } + } +#endif + if (XFS_FORCED_SHUTDOWN(mp)) + goto shutdown_abort; + + /* + * The xfs_buf_log_item pointer is stored in b_fsprivate. If + * it doesn't have one yet, then allocate one and initialize it. + * The checks to see if one is there are in xfs_buf_item_init(). + */ + xfs_buf_item_init(bp, tp->t_mountp); + + /* + * Set the recursion count for the buffer within this transaction + * to 0. + */ + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); + ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); + bip->bli_recur = 0; + + /* + * Take a reference for this transaction on the buf item. + */ + atomic_inc(&bip->bli_refcount); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)bip); + + /* + * Initialize b_fsprivate2 so we can find it with incore_match() + * above. + */ + XFS_BUF_SET_FSPRIVATE2(bp, tp); + + xfs_buftrace("TRANS READ", bp); + xfs_buf_item_trace("READ", bip); + *bpp = bp; + return 0; + +shutdown_abort: + /* + * the theory here is that buffer is good but we're + * bailing out because the filesystem is being forcibly + * shut down. So we should leave the b_flags alone since + * the buffer's not staled and just get out. + */ +#if defined(DEBUG) + if (XFS_BUF_ISSTALE(bp) && XFS_BUF_ISDELAYWRITE(bp)) + cmn_err(CE_NOTE, "about to pop assert, bp == 0x%x\n", bp); +#endif + ASSERT((XFS_BUF_BFLAGS(bp) & (XFS_B_STALE|XFS_B_DELWRI)) != + (XFS_B_STALE|XFS_B_DELWRI)); + + xfs_buftrace("READ_BUF XFSSHUTDN", bp); + xfs_buf_relse(bp); + *bpp = NULL; + return XFS_ERROR(EIO); +} + + +/* + * Release the buffer bp which was previously acquired with one of the + * xfs_trans_... buffer allocation routines if the buffer has not + * been modified within this transaction. If the buffer is modified + * within this transaction, do decrement the recursion count but do + * not release the buffer even if the count goes to 0. If the buffer is not + * modified within the transaction, decrement the recursion count and + * release the buffer if the recursion count goes to 0. + * + * If the buffer is to be released and it was not modified before + * this transaction began, then free the buf_log_item associated with it. + * + * If the transaction pointer is NULL, make this just a normal + * brelse() call. + */ +void +xfs_trans_brelse(xfs_trans_t *tp, + xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + xfs_log_item_t *lip; + xfs_log_item_desc_t *lidp; + + /* + * Default to a normal brelse() call if the tp is NULL. + */ + if (tp == NULL) { + ASSERT(XFS_BUF_FSPRIVATE2(bp, void *) == NULL); + /* + * If there's a buf log item attached to the buffer, + * then let the AIL know that the buffer is being + * unlocked. + */ + if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) { + lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); + if (lip->li_type == XFS_LI_BUF) { + bip = XFS_BUF_FSPRIVATE(bp,xfs_buf_log_item_t*); + xfs_trans_unlocked_item( + bip->bli_item.li_mountp, + lip); + } + } + xfs_buf_relse(bp); + return; + } + + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(bip->bli_item.li_type == XFS_LI_BUF); + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + + /* + * Find the item descriptor pointing to this buffer's + * log item. It must be there. + */ + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip); + ASSERT(lidp != NULL); + + /* + * If the release is just for a recursive lock, + * then decrement the count and return. + */ + if (bip->bli_recur > 0) { + bip->bli_recur--; + xfs_buf_item_trace("RELSE RECUR", bip); + return; + } + + /* + * If the buffer is dirty within this transaction, we can't + * release it until we commit. + */ + if (lidp->lid_flags & XFS_LID_DIRTY) { + xfs_buf_item_trace("RELSE DIRTY", bip); + return; + } + + /* + * If the buffer has been invalidated, then we can't release + * it until the transaction commits to disk unless it is re-dirtied + * as part of this transaction. This prevents us from pulling + * the item from the AIL before we should. + */ + if (bip->bli_flags & XFS_BLI_STALE) { + xfs_buf_item_trace("RELSE STALE", bip); + return; + } + + ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); + xfs_buf_item_trace("RELSE", bip); + + /* + * Free up the log item descriptor tracking the released item. + */ + xfs_trans_free_item(tp, lidp); + + /* + * Clear the hold flag in the buf log item if it is set. + * We wouldn't want the next user of the buffer to + * get confused. + */ + if (bip->bli_flags & XFS_BLI_HOLD) { + bip->bli_flags &= ~XFS_BLI_HOLD; + } + + /* + * Drop our reference to the buf log item. + */ + atomic_dec(&bip->bli_refcount); + + /* + * If the buf item is not tracking data in the log, then + * we must free it before releasing the buffer back to the + * free pool. Before releasing the buffer to the free pool, + * clear the transaction pointer in b_fsprivate2 to dissolve + * its relation to this transaction. + */ + if (!xfs_buf_item_dirty(bip)) { +/*** + ASSERT(bp->b_pincount == 0); +***/ + ASSERT(atomic_read(&bip->bli_refcount) == 0); + ASSERT(!(bip->bli_item.li_flags & XFS_LI_IN_AIL)); + ASSERT(!(bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF)); + xfs_buf_item_relse(bp); + bip = NULL; + } + XFS_BUF_SET_FSPRIVATE2(bp, NULL); + + /* + * If we've still got a buf log item on the buffer, then + * tell the AIL that the buffer is being unlocked. + */ + if (bip != NULL) { + xfs_trans_unlocked_item(bip->bli_item.li_mountp, + (xfs_log_item_t*)bip); + } + + xfs_buf_relse(bp); + return; +} + +/* + * Add the locked buffer to the transaction. + * The buffer must be locked, and it cannot be associated with any + * transaction. + * + * If the buffer does not yet have a buf log item associated with it, + * then allocate one for it. Then add the buf item to the transaction. + */ +void +xfs_trans_bjoin(xfs_trans_t *tp, + xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, void *) == NULL); + + /* + * The xfs_buf_log_item pointer is stored in b_fsprivate. If + * it doesn't have one yet, then allocate one and initialize it. + * The checks to see if one is there are in xfs_buf_item_init(). + */ + xfs_buf_item_init(bp, tp->t_mountp); + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); + ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); + + /* + * Take a reference for this transaction on the buf item. + */ + atomic_inc(&bip->bli_refcount); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t *)bip); + + /* + * Initialize b_fsprivate2 so we can find it with incore_match() + * in xfs_trans_get_buf() and friends above. + */ + XFS_BUF_SET_FSPRIVATE2(bp, tp); + + xfs_buf_item_trace("BJOIN", bip); +} + +/* + * Mark the buffer as not needing to be unlocked when the buf item's + * IOP_UNLOCK() routine is called. The buffer must already be locked + * and associated with the given transaction. + */ +/* ARGSUSED */ +void +xfs_trans_bhold(xfs_trans_t *tp, + xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + bip->bli_flags |= XFS_BLI_HOLD; + xfs_buf_item_trace("BHOLD", bip); +} + +/* + * This function is used to indicate that the buffer should not be + * unlocked until the transaction is committed to disk. Since we + * are going to keep the lock held, make the transaction synchronous + * so that the lock is not held too long. + * + * It uses the log item descriptor flag XFS_LID_SYNC_UNLOCK to + * delay the buf items's unlock call until the transaction is + * committed to disk or aborted. + */ +void +xfs_trans_bhold_until_committed(xfs_trans_t *tp, + xfs_buf_t *bp) +{ + xfs_log_item_desc_t *lidp; + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_CANCEL)); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip); + ASSERT(lidp != NULL); + + lidp->lid_flags |= XFS_LID_SYNC_UNLOCK; + xfs_buf_item_trace("BHOLD UNTIL COMMIT", bip); + + xfs_trans_set_sync(tp); +} + +/* + * This is called to mark bytes first through last inclusive of the given + * buffer as needing to be logged when the transaction is committed. + * The buffer must already be associated with the given transaction. + * + * First and last are numbers relative to the beginning of this buffer, + * so the first byte in the buffer is numbered 0 regardless of the + * value of b_blkno. + */ +void +xfs_trans_log_buf(xfs_trans_t *tp, + xfs_buf_t *bp, + uint first, + uint last) +{ + xfs_buf_log_item_t *bip; + xfs_log_item_desc_t *lidp; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + ASSERT((first <= last) && (last < XFS_BUF_COUNT(bp))); + ASSERT((XFS_BUF_IODONE_FUNC(bp) == NULL) || + (XFS_BUF_IODONE_FUNC(bp) == xfs_buf_iodone_callbacks)); + + /* + * Mark the buffer as needing to be written out eventually, + * and set its iodone function to remove the buffer's buf log + * item from the AIL and free it when the buffer is flushed + * to disk. See xfs_buf_attach_iodone() for more details + * on li_cb and xfs_buf_iodone_callbacks(). + * If we end up aborting this transaction, we trap this buffer + * inside the b_bdstrat callback so that this won't get written to + * disk. + */ + XFS_BUF_DELAYWRITE(bp); + XFS_BUF_DONE(bp); + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + XFS_BUF_SET_IODONE_FUNC(bp, xfs_buf_iodone_callbacks); + bip->bli_item.li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*))xfs_buf_iodone; + + /* + * If we invalidated the buffer within this transaction, then + * cancel the invalidation now that we're dirtying the buffer + * again. There are no races with the code in xfs_buf_item_unpin(), + * because we have a reference to the buffer this entire time. + */ + if (bip->bli_flags & XFS_BLI_STALE) { + xfs_buf_item_trace("BLOG UNSTALE", bip); + bip->bli_flags &= ~XFS_BLI_STALE; + /* note this will have to change for page_buf interface... unstale isn't really an option RMC */ + ASSERT(XFS_BUF_ISSTALE(bp)); + XFS_BUF_UNSTALE(bp); + bip->bli_format.blf_flags &= ~XFS_BLI_CANCEL; + } + + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip); + ASSERT(lidp != NULL); + + tp->t_flags |= XFS_TRANS_DIRTY; + lidp->lid_flags |= XFS_LID_DIRTY; + bip->bli_flags |= XFS_BLI_LOGGED; + xfs_buf_item_log(bip, first, last); + xfs_buf_item_trace("BLOG", bip); +} + + +/* + * This called to invalidate a buffer that is being used within + * a transaction. Typically this is because the blocks in the + * buffer are being freed, so we need to prevent it from being + * written out when we're done. Allowing it to be written again + * might overwrite data in the free blocks if they are reallocated + * to a file. + * + * We prevent the buffer from being written out by clearing the + * B_DELWRI flag. We can't always + * get rid of the buf log item at this point, though, because + * the buffer may still be pinned by another transaction. If that + * is the case, then we'll wait until the buffer is committed to + * disk for the last time (we can tell by the ref count) and + * free it in xfs_buf_item_unpin(). Until it is cleaned up we + * will keep the buffer locked so that the buffer and buf log item + * are not reused. + */ +void +xfs_trans_binval( + xfs_trans_t *tp, + xfs_buf_t *bp) +{ + xfs_log_item_desc_t *lidp; + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)bip); + ASSERT(lidp != NULL); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + + if (bip->bli_flags & XFS_BLI_STALE) { + /* + * If the buffer is already invalidated, then + * just return. + */ + ASSERT(!(XFS_BUF_ISDELAYWRITE(bp))); + ASSERT(XFS_BUF_ISSTALE(bp)); + ASSERT(!(bip->bli_flags & (XFS_BLI_LOGGED | XFS_BLI_DIRTY))); + ASSERT(!(bip->bli_format.blf_flags & XFS_BLI_INODE_BUF)); + ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); + ASSERT(lidp->lid_flags & XFS_LID_DIRTY); + ASSERT(tp->t_flags & XFS_TRANS_DIRTY); + xfs_buftrace("XFS_BINVAL RECUR", bp); + xfs_buf_item_trace("BINVAL RECUR", bip); + return; + } + + /* + * Clear the dirty bit in the buffer and set the STALE flag + * in the buf log item. The STALE flag will be used in + * xfs_buf_item_unpin() to determine if it should clean up + * when the last reference to the buf item is given up. + * We set the XFS_BLI_CANCEL flag in the buf log format structure + * and log the buf item. This will be used at recovery time + * to determine that copies of the buffer in the log before + * this should not be replayed. + * We mark the item descriptor and the transaction dirty so + * that we'll hold the buffer until after the commit. + * + * Since we're invalidating the buffer, we also clear the state + * about which parts of the buffer have been logged. We also + * clear the flag indicating that this is an inode buffer since + * the data in the buffer will no longer be valid. + * + * We set the stale bit in the buffer as well since we're getting + * rid of it. + */ + XFS_BUF_UNDELAYWRITE(bp); + XFS_BUF_STALE(bp); + bip->bli_flags |= XFS_BLI_STALE; + bip->bli_flags &= ~(XFS_BLI_LOGGED | XFS_BLI_DIRTY); + bip->bli_format.blf_flags &= ~XFS_BLI_INODE_BUF; + bip->bli_format.blf_flags |= XFS_BLI_CANCEL; + bzero((char *)(bip->bli_format.blf_data_map), + (bip->bli_format.blf_map_size * sizeof(uint))); + lidp->lid_flags |= XFS_LID_DIRTY; + tp->t_flags |= XFS_TRANS_DIRTY; + xfs_buftrace("XFS_BINVAL", bp); + xfs_buf_item_trace("BINVAL", bip); +} + +/* + * This call is used to indicate that the buffer contains on-disk + * inodes which must be handled specially during recovery. They + * require special handling because only the di_next_unlinked from + * the inodes in the buffer should be recovered. The rest of the + * data in the buffer is logged via the inodes themselves. + * + * All we do is set the XFS_BLI_INODE_BUF flag in the buffer's log + * format structure so that we'll know what to do at recovery time. + */ +/* ARGSUSED */ +void +xfs_trans_inode_buf( + xfs_trans_t *tp, + xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + + bip->bli_format.blf_flags |= XFS_BLI_INODE_BUF; +} + + +/* + * Mark the buffer as being one which contains newly allocated + * inodes. We need to make sure that even if this buffer is + * relogged as an 'inode buf' we still recover all of the inode + * images in the face of a crash. This works in coordination with + * xfs_buf_item_committed() to ensure that the buffer remains in the + * AIL at its original location even after it has been relogged. + */ +/* ARGSUSED */ +void +xfs_trans_inode_alloc_buf( + xfs_trans_t *tp, + xfs_buf_t *bp) +{ + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + ASSERT(!(bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF)); + + bip->bli_flags |= XFS_BLI_INODE_ALLOC_BUF; +} + + +/* + * Similar to xfs_trans_inode_buf(), this marks the buffer as a cluster of + * dquots. However, unlike in inode buffer recovery, dquot buffers get + * recovered in their entirety. (Hence, no XFS_BLI_DQUOT_ALLOC_BUF flag). + * The only thing that makes dquot buffers different from regular + * buffers is that we must not replay dquot bufs when recovering + * if a _corresponding_ quotaoff has happened. We also have to distinguish + * between usr dquot bufs and grp dquot bufs, because usr and grp quotas + * can be turned off independently. + */ +/* ARGSUSED */ +void +xfs_trans_dquot_buf( + xfs_trans_t *tp, + xfs_buf_t *bp, + uint type) +{ + xfs_buf_log_item_t *bip; + + ASSERT(XFS_BUF_ISBUSY(bp)); + ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); + ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); + ASSERT(type == XFS_BLI_UDQUOT_BUF || + type == XFS_BLI_GDQUOT_BUF); + + bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); + ASSERT(atomic_read(&bip->bli_refcount) > 0); + + bip->bli_format.blf_flags |= type; +} + +/* + * Check to see if a buffer matching the given parameters is already + * a part of the given transaction. Only check the first, embedded + * chunk, since we don't want to spend all day scanning large transactions. + */ +STATIC xfs_buf_t * +xfs_trans_buf_item_match( + xfs_trans_t *tp, + buftarg_t *target, + xfs_daddr_t blkno, + int len) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_desc_t *lidp; + xfs_buf_log_item_t *blip; + xfs_buf_t *bp; + int i; + + bp = NULL; + len = BBTOB(len); + licp = &tp->t_items; + if (!XFS_LIC_ARE_ALL_FREE(licp)) { + for (i = 0; i < licp->lic_unused; i++) { + /* + * Skip unoccupied slots. + */ + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + lidp = XFS_LIC_SLOT(licp, i); + blip = (xfs_buf_log_item_t *)lidp->lid_item; + if (blip->bli_item.li_type != XFS_LI_BUF) { + continue; + } + + bp = blip->bli_buf; + if ((XFS_BUF_TARGET(bp) == target->dev) && + (XFS_BUF_ADDR(bp) == blkno) && + (XFS_BUF_COUNT(bp) == len)) { + /* + * We found it. Break out and + * return the pointer to the buffer. + */ + break; + } else { + bp = NULL; + } + } + } + return bp; +} + +/* + * Check to see if a buffer matching the given parameters is already + * a part of the given transaction. Check all the chunks, we + * want to be thorough. + */ +STATIC xfs_buf_t * +xfs_trans_buf_item_match_all( + xfs_trans_t *tp, + buftarg_t *target, + xfs_daddr_t blkno, + int len) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_desc_t *lidp; + xfs_buf_log_item_t *blip; + xfs_buf_t *bp; + int i; + + bp = NULL; + len = BBTOB(len); + for (licp = &tp->t_items; licp != NULL; licp = licp->lic_next) { + if (XFS_LIC_ARE_ALL_FREE(licp)) { + ASSERT(licp == &tp->t_items); + ASSERT(licp->lic_next == NULL); + return NULL; + } + for (i = 0; i < licp->lic_unused; i++) { + /* + * Skip unoccupied slots. + */ + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + lidp = XFS_LIC_SLOT(licp, i); + blip = (xfs_buf_log_item_t *)lidp->lid_item; + if (blip->bli_item.li_type != XFS_LI_BUF) { + continue; + } + + bp = blip->bli_buf; + if ((XFS_BUF_TARGET(bp) == target->dev) && + (XFS_BUF_ADDR(bp) == blkno) && + (XFS_BUF_COUNT(bp) == len)) { + /* + * We found it. Break out and + * return the pointer to the buffer. + */ + return bp; + } + } + } + return NULL; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_trans_dquot.c linux-2.4-xfs/linux/fs/xfs/xfs_trans_dquot.c --- linux-2.4.7/linux/fs/xfs/xfs_trans_dquot.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_trans_dquot.c Wed Apr 11 11:27:03 2001 @@ -0,0 +1,853 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + + +/* + * Add the locked dquot to the transaction. + * The dquot must be locked, and it cannot be associated with any + * transaction. + */ +void +xfs_trans_dqjoin( + xfs_trans_t *tp, + xfs_dquot_t *dqp) +{ + xfs_dq_logitem_t *lp; + + ASSERT(! XFS_DQ_IS_ADDEDTO_TRX(tp, dqp)); + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + ASSERT(XFS_DQ_IS_LOGITEM_INITD(dqp)); + lp = &dqp->q_logitem; + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)(lp)); + + /* + * Initialize i_transp so we can later determine if this dquot is + * associated with this transaction. + */ + dqp->q_transp = tp; +} + + +/* + * This is called to mark the dquot as needing + * to be logged when the transaction is committed. The dquot must + * already be associated with the given transaction. + * Note that it marks the entire transaction as dirty. In the ordinary + * case, this gets called via xfs_trans_commit, after the transaction + * is already dirty. However, there's nothing stop this from getting + * called directly, as done by xfs_qm_scall_setqlim. Hence, the TRANS_DIRTY + * flag. + */ +void +xfs_trans_log_dquot( + xfs_trans_t *tp, + xfs_dquot_t *dqp) +{ + xfs_log_item_desc_t *lidp; + + ASSERT(XFS_DQ_IS_ADDEDTO_TRX(tp, dqp)); + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(&dqp->q_logitem)); + ASSERT(lidp != NULL); + + tp->t_flags |= XFS_TRANS_DIRTY; + lidp->lid_flags |= XFS_LID_DIRTY; +} + +/* + * Carry forward whatever is left of the quota blk reservation to + * the spanky new transaction + */ +void +xfs_trans_dup_dqinfo( + xfs_trans_t *otp, + xfs_trans_t *ntp) +{ + xfs_dqtrx_t *oq, *nq; + int i,j; + xfs_dqtrx_t *oqa, *nqa; + + xfs_trans_alloc_dqinfo(ntp); + oqa = otp->t_dqinfo->dqa_usrdquots; + nqa = ntp->t_dqinfo->dqa_usrdquots; + + /* + * Because the quota blk reservation is carried forward, + * it is also necessary to carry forward the DQ_DIRTY flag. + */ + if(otp->t_flags & XFS_TRANS_DQ_DIRTY) + ntp->t_flags |= XFS_TRANS_DQ_DIRTY; + + for (j = 0; j < 2; j++) { + for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) { + if (oqa[i].qt_dquot == NULL) + break; + oq = &oqa[i]; + nq = &nqa[i]; + + nq->qt_dquot = oq->qt_dquot; + nq->qt_bcount_delta = nq->qt_icount_delta = 0; + nq->qt_rtbcount_delta = 0; + + /* + * Transfer whatever is left of the reservations. + */ + nq->qt_blk_res = oq->qt_blk_res - oq->qt_blk_res_used; + oq->qt_blk_res = oq->qt_blk_res_used; + + nq->qt_rtblk_res = oq->qt_rtblk_res - + oq->qt_rtblk_res_used; + oq->qt_rtblk_res = oq->qt_rtblk_res_used; + + nq->qt_ino_res = oq->qt_ino_res - oq->qt_ino_res_used; + oq->qt_ino_res = oq->qt_ino_res_used; + + } + oqa = otp->t_dqinfo->dqa_grpdquots; + nqa = ntp->t_dqinfo->dqa_grpdquots; + } +} + +/* + * Wrap around mod_dquot to account for both user and group quotas. + */ +int +xfs_trans_mod_dquot_byino( + xfs_trans_t *tp, + xfs_inode_t *ip, + uint field, + long delta) +{ + ASSERT(tp); + + if (tp->t_dqinfo == NULL) + xfs_trans_alloc_dqinfo(tp); + + if (XFS_IS_UQUOTA_ON(tp->t_mountp) && ip->i_udquot) { + (void) xfs_trans_mod_dquot(tp, ip->i_udquot, field, delta); + } + if (XFS_IS_GQUOTA_ON(tp->t_mountp) && ip->i_gdquot) { + (void) xfs_trans_mod_dquot(tp, ip->i_gdquot, field, delta); + } + return (0); +} + +STATIC xfs_dqtrx_t * +xfs_trans_get_dqtrx( + xfs_trans_t *tp, + xfs_dquot_t *dqp) +{ + int i; + xfs_dqtrx_t *qa; + + for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) { + qa = XFS_QM_DQP_TO_DQACCT(tp, dqp); + + if (qa[i].qt_dquot == NULL || + qa[i].qt_dquot == dqp) { + return (&qa[i]); + } + } + + return (NULL); +} + +/* + * Make the changes in the transaction structure. + * The moral equivalent to xfs_trans_mod_sb(). + * We don't touch any fields in the dquot, so we don't care + * if it's locked or not (most of the time it won't be). + */ +void +xfs_trans_mod_dquot( + xfs_trans_t *tp, + xfs_dquot_t *dqp, + uint field, + long delta) +{ + xfs_dqtrx_t *qtrx; + + ASSERT(tp); + qtrx = NULL; + + if (tp->t_dqinfo == NULL) + xfs_trans_alloc_dqinfo(tp); + /* + * Find either the first free slot or the slot that belongs + * to this dquot. + */ + qtrx = xfs_trans_get_dqtrx(tp, dqp); + ASSERT(qtrx); + if (qtrx->qt_dquot == NULL) + qtrx->qt_dquot = dqp; + + switch (field) { + + /* + * regular disk blk reservation + */ + case XFS_TRANS_DQ_RES_BLKS: + qtrx->qt_blk_res += (ulong)delta; + break; + + /* + * inode reservation + */ + case XFS_TRANS_DQ_RES_INOS: + qtrx->qt_ino_res += (ulong)delta; + break; + + /* + * disk blocks used. + */ + case XFS_TRANS_DQ_BCOUNT: + if (qtrx->qt_blk_res && delta > 0) { + qtrx->qt_blk_res_used += (ulong)delta; + ASSERT(qtrx->qt_blk_res >= qtrx->qt_blk_res_used); + } + qtrx->qt_bcount_delta += delta; + break; + + case XFS_TRANS_DQ_DELBCOUNT: + qtrx->qt_delbcnt_delta += delta; + break; + + /* + * Inode Count + */ + case XFS_TRANS_DQ_ICOUNT: + if (qtrx->qt_ino_res && delta > 0) { + qtrx->qt_ino_res_used += (ulong)delta; + ASSERT(qtrx->qt_ino_res >= qtrx->qt_ino_res_used); + } + qtrx->qt_icount_delta += delta; + break; + + /* + * rtblk reservation + */ + case XFS_TRANS_DQ_RES_RTBLKS: + qtrx->qt_rtblk_res += (ulong)delta; + break; + + /* + * rtblk count + */ + case XFS_TRANS_DQ_RTBCOUNT: + if (qtrx->qt_rtblk_res && delta > 0) { + qtrx->qt_rtblk_res_used += (ulong)delta; + ASSERT(qtrx->qt_rtblk_res >= qtrx->qt_rtblk_res_used); + } + qtrx->qt_rtbcount_delta += delta; + break; + + case XFS_TRANS_DQ_DELRTBCOUNT: + qtrx->qt_delrtb_delta += delta; + break; + + default: + ASSERT(0); + } + tp->t_flags |= XFS_TRANS_DQ_DIRTY; +} + + +/* + * Given an array of dqtrx structures, lock all the dquots associated + * and join them to the transaction, provided they have been modified. + * We know that the highest number of dquots (of one type - usr OR grp), + * involved in a transaction is 2 and that both usr and grp combined - 3. + * So, we don't attempt to make this very generic. + */ +STATIC void +xfs_trans_dqlockedjoin( + xfs_trans_t *tp, + xfs_dqtrx_t *q) +{ + ASSERT(q[0].qt_dquot != NULL); + if (q[1].qt_dquot == NULL) { + xfs_dqlock(q[0].qt_dquot); + xfs_trans_dqjoin(tp, q[0].qt_dquot); + } else { + ASSERT(XFS_QM_TRANS_MAXDQS == 2); + xfs_dqlock2(q[0].qt_dquot, q[1].qt_dquot); + xfs_trans_dqjoin(tp, q[0].qt_dquot); + xfs_trans_dqjoin(tp, q[1].qt_dquot); + } +} + + +/* + * Called by xfs_trans_commit() and similar in spirit to + * xfs_trans_apply_sb_deltas(). + * Go thru all the dquots belonging to this transaction and modify the + * INCORE dquot to reflect the actual usages. + * Unreserve just the reservations done by this transaction + * dquot is still left locked at exit. + */ +void +xfs_trans_apply_dquot_deltas( + xfs_trans_t *tp) +{ + int i, j; + xfs_dquot_t *dqp; + xfs_dqtrx_t *qtrx, *qa; + xfs_disk_dquot_t *d; + long totalbdelta; + long totalrtbdelta; + + ASSERT(tp->t_dqinfo); + qa = tp->t_dqinfo->dqa_usrdquots; + for (j = 0; j < 2; j++) { + if (qa[0].qt_dquot == NULL) { + qa = tp->t_dqinfo->dqa_grpdquots; + continue; + } + + /* + * Lock all of the dquots and join them to the transaction. + */ + xfs_trans_dqlockedjoin(tp, qa); + + for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) { + qtrx = &qa[i]; + /* + * The array of dquots is filled + * sequentially, not sparsely. + */ + if ((dqp = qtrx->qt_dquot) == NULL) + break; + + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + ASSERT(XFS_DQ_IS_ADDEDTO_TRX(tp, dqp)); + + /* + * adjust the actual number of blocks used + */ + d = &dqp->q_core; + + /* + * The issue here is - sometimes we don't make a blkquota + * reservation intentionally to be fair to users + * (when the amount is small). On the other hand, + * delayed allocs do make reservations, but that's + * outside of a transaction, so we have no + * idea how much was really reserved. + * So, here we've accumulated delayed allocation blks and + * non-delay blks. The assumption is that the + * delayed ones are always reserved (outside of a + * transaction), and the others may or may not have + * quota reservations. + */ + totalbdelta = qtrx->qt_bcount_delta + + qtrx->qt_delbcnt_delta; + totalrtbdelta = qtrx->qt_rtbcount_delta + + qtrx->qt_delrtb_delta; +#ifdef QUOTADEBUG + if (totalbdelta < 0) + ASSERT(INT_GET(d->d_bcount, ARCH_CONVERT) >= + (xfs_qcnt_t) -totalbdelta); + + if (totalrtbdelta < 0) + ASSERT(INT_GET(d->d_rtbcount, ARCH_CONVERT) >= + (xfs_qcnt_t) -totalrtbdelta); + + if (qtrx->qt_icount_delta < 0) + ASSERT(INT_GET(d->d_icount, ARCH_CONVERT) >= + (xfs_qcnt_t) -qtrx->qt_icount_delta); +#endif + if (totalbdelta) + INT_MOD(d->d_bcount, ARCH_CONVERT, (xfs_qcnt_t)totalbdelta); + + if (qtrx->qt_icount_delta) + INT_MOD(d->d_icount, ARCH_CONVERT, (xfs_qcnt_t)qtrx->qt_icount_delta); + + if (totalrtbdelta) + INT_MOD(d->d_rtbcount, ARCH_CONVERT, (xfs_qcnt_t)totalrtbdelta); + + /* + * Start/reset the timer(s) if needed. + */ + xfs_qm_adjust_dqtimers(tp->t_mountp, d); + + dqp->dq_flags |= XFS_DQ_DIRTY; + /* + * add this to the list of items to get logged + */ + xfs_trans_log_dquot(tp, dqp); + /* + * Take off what's left of the original reservation. + * In case of delayed allocations, there's no + * reservation that a transaction structure knows of. + */ + if (qtrx->qt_blk_res != 0) { + if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) { + if (qtrx->qt_blk_res > + qtrx->qt_blk_res_used) + dqp->q_res_bcount -= (xfs_qcnt_t) + (qtrx->qt_blk_res - + qtrx->qt_blk_res_used); + else + dqp->q_res_bcount -= (xfs_qcnt_t) + (qtrx->qt_blk_res_used - + qtrx->qt_blk_res); + } + } else { + /* + * These blks were never reserved, either inside + * a transaction or outside one (in a delayed + * allocation). Also, this isn't always a + * negative number since we sometimes + * deliberately skip quota reservations. + */ + if (qtrx->qt_bcount_delta) { + dqp->q_res_bcount += + (xfs_qcnt_t)qtrx->qt_bcount_delta; + } + } + /* + * Adjust the RT reservation. + */ + if (qtrx->qt_rtblk_res != 0) { + if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) { + if (qtrx->qt_rtblk_res > + qtrx->qt_rtblk_res_used) + dqp->q_res_rtbcount -= (xfs_qcnt_t) + (qtrx->qt_rtblk_res - + qtrx->qt_rtblk_res_used); + else + dqp->q_res_rtbcount -= (xfs_qcnt_t) + (qtrx->qt_rtblk_res_used - + qtrx->qt_rtblk_res); + } + } else { + if (qtrx->qt_rtbcount_delta) + dqp->q_res_rtbcount += + (xfs_qcnt_t)qtrx->qt_rtbcount_delta; + } + + /* + * Adjust the inode reservation. + */ + if (qtrx->qt_ino_res != 0) { + ASSERT(qtrx->qt_ino_res >= + qtrx->qt_ino_res_used); + if (qtrx->qt_ino_res > qtrx->qt_ino_res_used) + dqp->q_res_icount -= (xfs_qcnt_t) + (qtrx->qt_ino_res - + qtrx->qt_ino_res_used); + } else { + if (qtrx->qt_icount_delta) + dqp->q_res_icount += + (xfs_qcnt_t)qtrx->qt_icount_delta; + } + + +#ifdef QUOTADEBUG + if (qtrx->qt_rtblk_res != 0) + printk("RT res %d for 0x%p\n", + (int) qtrx->qt_rtblk_res, + dqp); +#endif + ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT)); + ASSERT(dqp->q_res_icount >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT)); + ASSERT(dqp->q_res_rtbcount >= INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT)); + } + /* + * Do the group quotas next + */ + qa = tp->t_dqinfo->dqa_grpdquots; + } +} + +/* + * Release the reservations, and adjust the dquots accordingly. + * This is called only when the transaction is being aborted. If by + * any chance we have done dquot modifications incore (ie. deltas) already, + * we simply throw those away, since that's the expected behavior + * when a transaction is curtailed without a commit. + */ +void +xfs_trans_unreserve_and_mod_dquots( + xfs_trans_t *tp) +{ + int i, j; + xfs_dquot_t *dqp; + xfs_dqtrx_t *qtrx, *qa; + boolean_t locked; + + ASSERT(tp->t_dqinfo); + qa = tp->t_dqinfo->dqa_usrdquots; + + for (j = 0; j < 2; j++) { + for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) { + qtrx = &qa[i]; + /* + * We assume that the array of dquots is filled + * sequentially, not sparsely. + */ + if ((dqp = qtrx->qt_dquot) == NULL) + break; + /* + * Unreserve the original reservation. We don't care + * about the number of blocks used field, or deltas. + * Also we don't bother to zero the fields. + */ + locked = B_FALSE; + if (qtrx->qt_blk_res) { + xfs_dqlock(dqp); + locked = B_TRUE; + dqp->q_res_bcount -= + (xfs_qcnt_t)qtrx->qt_blk_res; + } + if (qtrx->qt_ino_res) { + if (!locked) { + xfs_dqlock(dqp); + locked = B_TRUE; + } + dqp->q_res_icount -= + (xfs_qcnt_t)qtrx->qt_ino_res; + } + + if (qtrx->qt_rtblk_res) { + if (!locked) { + xfs_dqlock(dqp); + locked = B_TRUE; + } + dqp->q_res_rtbcount -= + (xfs_qcnt_t)qtrx->qt_rtblk_res; + } + if (locked) + xfs_dqunlock(dqp); + + } + qa = tp->t_dqinfo->dqa_grpdquots; + } +} + +/* + * This reserves disk blocks and inodes against a dquot. + * Flags indicate if the dquot is to be locked here and also + * if the blk reservation is for RT or regular blocks. + * Sending in XFS_QMOPT_FORCE_RES flag skips the quota check. + * Returns EDQUOT if quota is exceeded. + */ +STATIC int +xfs_trans_dqresv( + xfs_trans_t *tp, + xfs_dquot_t *dqp, + long nblks, + long ninos, + uint flags) +{ + int error; + xfs_qcnt_t hardlimit; + xfs_qcnt_t softlimit; + time_t btimer; + xfs_qcnt_t *resbcountp; + + if (! (flags & XFS_QMOPT_DQLOCK)) { + xfs_dqlock(dqp); + } + ASSERT(XFS_DQ_IS_LOCKED(dqp)); + if (flags & XFS_TRANS_DQ_RES_BLKS) { + hardlimit = INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT); + softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT); + btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT); + resbcountp = &dqp->q_res_bcount; + } else { + ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS); + hardlimit = INT_GET(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT); + softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT); + btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT); + resbcountp = &dqp->q_res_rtbcount; + } + error = 0; + + if ((flags & XFS_QMOPT_FORCE_RES) == 0 && + INT_GET(dqp->q_core.d_id, ARCH_CONVERT) != 0 && + XFS_IS_QUOTA_ENFORCED(dqp->q_mount)) { +#ifdef QUOTADEBUG + printk("BLK Res: nblks=%ld + resbcount=%Ld > hardlimit=%Ld?\n", + nblks, *resbcountp, hardlimit); +#endif + if (nblks > 0) { + /* + * dquot is locked already. See if we'd go over the + * hardlimit or exceed the timelimit if we allocate + * nblks. + */ + if (hardlimit > 0ULL && + (hardlimit <= nblks + *resbcountp)) { + error = EDQUOT; + goto error_return; + } + + if (softlimit > 0ULL && + (softlimit <= nblks + *resbcountp)) { + /* + * If timer or warnings has expired, + * return EDQUOT + */ + if ((btimer != 0 && CURRENT_TIME > btimer) || + (INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) != 0 && + INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) >= + XFS_QI_BWARNLIMIT(dqp->q_mount))) { + error = EDQUOT; + goto error_return; + } + } + } + if (ninos > 0) { + if (INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) > 0ULL && + INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= + INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT)) { + error = EDQUOT; + goto error_return; + } else if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) > 0ULL && + INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= + INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) { + /* + * If timer or warnings has expired, + * return EDQUOT + */ + if ((INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT) != 0 && + CURRENT_TIME > INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)) || + (INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) != 0 && + INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) >= + XFS_QI_IWARNLIMIT(dqp->q_mount))) { + error = EDQUOT; + goto error_return; + } + } + } + } + + /* + * Change the reservation, but not the actual usage. + * Note that q_res_bcount = q_core.d_bcount + resv + */ + (*resbcountp) += (xfs_qcnt_t)nblks; + if (ninos != 0) + dqp->q_res_icount += (xfs_qcnt_t)ninos; + + /* + * note the reservation amt in the trans struct too, + * so that the transaction knows how much was reserved by + * it against this particular dquot. + * We don't do this when we are reserving for a delayed allocation, + * because we don't have the luxury of a transaction envelope then. + */ + if (tp) { + ASSERT(tp->t_dqinfo); + ASSERT(flags & XFS_QMOPT_RESBLK_MASK); + if (nblks != 0) + xfs_trans_mod_dquot(tp, dqp, + flags & XFS_QMOPT_RESBLK_MASK, + nblks); + if (ninos != 0) + xfs_trans_mod_dquot(tp, dqp, + XFS_TRANS_DQ_RES_INOS, + ninos); + } + ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT)); + ASSERT(dqp->q_res_rtbcount >= INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT)); + ASSERT(dqp->q_res_icount >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT)); + +error_return: + if (! (flags & XFS_QMOPT_DQLOCK)) { + xfs_dqunlock(dqp); + } + return (error); +} + + +/* + * Given a dquot(s), make disk block and/or inode reservations against them. + * The fact that this does the reservation against both the usr and + * grp quotas is important, because this follows a both-or-nothing + * approach. + * + * flags = XFS_QMOPT_DQLOCK indicate if dquot(s) need to be locked. + * XFS_QMOPT_FORCE_RES evades limit enforcement. Used by chown. + * XFS_TRANS_DQ_RES_BLKS reserves regular disk blocks + * XFS_TRANS_DQ_RES_RTBLKS reserves realtime disk blocks + * dquots are unlocked on return, if they were not locked by caller. + */ +int +xfs_trans_reserve_quota_bydquots( + xfs_trans_t *tp, + xfs_dquot_t *udqp, + xfs_dquot_t *gdqp, + long nblks, + long ninos, + uint flags) +{ + int resvd; + + if (tp && tp->t_dqinfo == NULL) + xfs_trans_alloc_dqinfo(tp); + + ASSERT(flags & XFS_QMOPT_RESBLK_MASK); + resvd = 0; + + if (udqp) { + if (xfs_trans_dqresv(tp, udqp, nblks, ninos, flags)) + return (EDQUOT); + resvd = 1; + } + + if (gdqp) { + if (xfs_trans_dqresv(tp, gdqp, nblks, ninos, flags)) { + /* + * can't do it, so backout previous reservation + */ + if (resvd) { + xfs_trans_dqresv(tp, udqp, -nblks, -ninos, + flags); + } + return (EDQUOT); + } + } + + /* + * Didnt change anything critical, so, no need to log + */ + return (0); +} + + +/* + * Lock the dquot and change the reservation if we can. + * This doesnt change the actual usage, just the reservation. + * The inode sent in is locked. + * + * Returns 0 on success, EDQUOT or other errors otherwise + */ +int +xfs_trans_reserve_quota_nblks( + xfs_trans_t *tp, + xfs_inode_t *ip, + long nblks, + long ninos, + uint type) +{ + int error; + +#ifdef QUOTADEBUG + if (ip->i_udquot) + ASSERT(! XFS_DQ_IS_LOCKED(ip->i_udquot)); + if (ip->i_gdquot) + ASSERT(! XFS_DQ_IS_LOCKED(ip->i_gdquot)); +#endif + + ASSERT(XFS_ISLOCKED_INODE_EXCL(ip)); + ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount)); + ASSERT(type == XFS_TRANS_DQ_RES_RTBLKS || + type == XFS_TRANS_DQ_RES_BLKS); + + /* + * Reserve nblks against these dquots, with trans as the mediator. + */ + error = xfs_trans_reserve_quota_bydquots(tp, + ip->i_udquot, ip->i_gdquot, + nblks, ninos, + type); + return (error); +} + +/* + * This routine is called to allocate a quotaoff log item. + */ +xfs_qoff_logitem_t * +xfs_trans_get_qoff_item( + xfs_trans_t *tp, + xfs_qoff_logitem_t *startqoff, + uint flags) +{ + xfs_qoff_logitem_t *q; + + ASSERT(tp != NULL); + + q = xfs_qm_qoff_logitem_init(tp->t_mountp, startqoff, flags); + ASSERT(q != NULL); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)q); + + return (q); +} + + +/* + * This is called to mark the quotaoff logitem as needing + * to be logged when the transaction is committed. The logitem must + * already be associated with the given transaction. + */ +void +xfs_trans_log_quotaoff_item( + xfs_trans_t *tp, + xfs_qoff_logitem_t *qlp) +{ + xfs_log_item_desc_t *lidp; + + lidp = xfs_trans_find_item(tp, (xfs_log_item_t *)qlp); + ASSERT(lidp != NULL); + + tp->t_flags |= XFS_TRANS_DIRTY; + lidp->lid_flags |= XFS_LID_DIRTY; +} + +void +xfs_trans_alloc_dqinfo( + xfs_trans_t *tp) +{ + (tp)->t_dqinfo = kmem_zone_zalloc(xfs_Gqm->qm_dqtrxzone, KM_SLEEP); +} + +void +xfs_trans_free_dqinfo( + xfs_trans_t *tp) +{ + kmem_zone_free(xfs_Gqm->qm_dqtrxzone, (tp)->t_dqinfo); + (tp)->t_dqinfo = NULL; +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_trans_extfree.c linux-2.4-xfs/linux/fs/xfs/xfs_trans_extfree.c --- linux-2.4.7/linux/fs/xfs/xfs_trans_extfree.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_trans_extfree.c Mon Sep 25 00:42:07 2000 @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +/* + * This routine is called to allocate an "extent free intention" + * log item that will hold nextents worth of extents. The + * caller must use all nextents extents, because we are not + * flexible about this at all. + */ +xfs_efi_log_item_t * +xfs_trans_get_efi(xfs_trans_t *tp, + uint nextents) +{ + xfs_efi_log_item_t *efip; + + ASSERT(tp != NULL); + ASSERT(nextents > 0); + + efip = xfs_efi_init(tp->t_mountp, nextents); + ASSERT(efip != NULL); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)efip); + + return (efip); +} + +/* + * This routine is called to indicate that the described + * extent is to be logged as needing to be freed. It should + * be called once for each extent to be freed. + */ +void +xfs_trans_log_efi_extent(xfs_trans_t *tp, + xfs_efi_log_item_t *efip, + xfs_fsblock_t start_block, + xfs_extlen_t ext_len) +{ + xfs_log_item_desc_t *lidp; + uint next_extent; + xfs_extent_t *extp; + + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)efip); + ASSERT(lidp != NULL); + + tp->t_flags |= XFS_TRANS_DIRTY; + lidp->lid_flags |= XFS_LID_DIRTY; + + next_extent = efip->efi_next_extent; + ASSERT(next_extent < efip->efi_format.efi_nextents); + extp = &(efip->efi_format.efi_extents[next_extent]); + extp->ext_start = start_block; + extp->ext_len = ext_len; + efip->efi_next_extent++; +} + + +/* + * This routine is called to allocate an "extent free done" + * log item that will hold nextents worth of extents. The + * caller must use all nextents extents, because we are not + * flexible about this at all. + */ +xfs_efd_log_item_t * +xfs_trans_get_efd(xfs_trans_t *tp, + xfs_efi_log_item_t *efip, + uint nextents) +{ + xfs_efd_log_item_t *efdp; + + ASSERT(tp != NULL); + ASSERT(nextents > 0); + + efdp = xfs_efd_init(tp->t_mountp, efip, nextents); + ASSERT(efdp != NULL); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)efdp); + + return (efdp); +} + +/* + * This routine is called to indicate that the described + * extent is to be logged as having been freed. It should + * be called once for each extent freed. + */ +void +xfs_trans_log_efd_extent(xfs_trans_t *tp, + xfs_efd_log_item_t *efdp, + xfs_fsblock_t start_block, + xfs_extlen_t ext_len) +{ + xfs_log_item_desc_t *lidp; + uint next_extent; + xfs_extent_t *extp; + + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)efdp); + ASSERT(lidp != NULL); + + tp->t_flags |= XFS_TRANS_DIRTY; + lidp->lid_flags |= XFS_LID_DIRTY; + + next_extent = efdp->efd_next_extent; + ASSERT(next_extent < efdp->efd_format.efd_nextents); + extp = &(efdp->efd_format.efd_extents[next_extent]); + extp->ext_start = start_block; + extp->ext_len = ext_len; + efdp->efd_next_extent++; +} + + + + + diff -rNu linux-2.4.7/linux/fs/xfs/xfs_trans_inode.c linux-2.4-xfs/linux/fs/xfs/xfs_trans_inode.c --- linux-2.4.7/linux/fs/xfs/xfs_trans_inode.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_trans_inode.c Mon Sep 25 00:42:07 2000 @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +#ifdef XFS_TRANS_DEBUG +STATIC void +xfs_trans_inode_broot_debug( + xfs_inode_t *ip); +#else +#define xfs_trans_inode_broot_debug(ip) +#endif + + +/* + * Get and lock the inode for the caller if it is not already + * locked within the given transaction. If it is already locked + * within the transaction, just increment its lock recursion count + * and return a pointer to it. + * + * For an inode to be locked in a transaction, the inode lock, as + * opposed to the io lock, must be taken exclusively. This ensures + * that the inode can be involved in only 1 transaction at a time. + * Lock recursion is handled on the io lock, but only for lock modes + * of equal or lesser strength. That is, you can recur on the io lock + * held EXCL with a SHARED request but not vice versa. Also, if + * the inode is already a part of the transaction then you cannot + * go from not holding the io lock to having it EXCL or SHARED. + * + * Use the inode cache routine xfs_inode_incore() to find the inode + * if it is already owned by this transaction. + * + * If we don't already own the inode, use xfs_iget() to get it. + * Since the inode log item structure is embedded in the incore + * inode structure and is initialized when the inode is brought + * into memory, there is nothing to do with it here. + * + * If the given transaction pointer is NULL, just call xfs_iget(). + * This simplifies code which must handle both cases. + */ +int +xfs_trans_iget( + xfs_mount_t *mp, + xfs_trans_t *tp, + xfs_ino_t ino, + uint lock_flags, + xfs_inode_t **ipp) +{ + int error; + xfs_inode_t *ip; + xfs_inode_log_item_t *iip; + + /* + * If the transaction pointer is NULL, just call the normal + * xfs_iget(). + */ + if (tp == NULL) { + return (xfs_iget(mp, NULL, ino, lock_flags, ipp, 0)); + } + + /* + * If we find the inode in core with this transaction + * pointer in its i_transp field, then we know we already + * have it locked. In this case we just increment the lock + * recursion count and return the inode to the caller. + * Assert that the inode is already locked in the mode requested + * by the caller. We cannot do lock promotions yet, so + * die if someone gets this wrong. + */ + if ((ip = xfs_inode_incore(tp->t_mountp, ino, tp)) != NULL) { + /* + * Make sure that the inode lock is held EXCL and + * that the io lock is never upgraded when the inode + * is already a part of the transaction. + */ + ASSERT(ip->i_itemp != NULL); + ASSERT(lock_flags & XFS_ILOCK_EXCL); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + ASSERT((!(lock_flags & XFS_IOLOCK_EXCL)) || + ismrlocked(&ip->i_iolock, MR_UPDATE)); + ASSERT((!(lock_flags & XFS_IOLOCK_EXCL)) || + (ip->i_itemp->ili_flags & XFS_ILI_IOLOCKED_EXCL)); + ASSERT((!(lock_flags & XFS_IOLOCK_SHARED)) || + ismrlocked(&ip->i_iolock, (MR_UPDATE | MR_ACCESS))); + ASSERT((!(lock_flags & XFS_IOLOCK_SHARED)) || + (ip->i_itemp->ili_flags & XFS_ILI_IOLOCKED_ANY)); + + if (lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) { + ip->i_itemp->ili_iolock_recur++; + } + if (lock_flags & XFS_ILOCK_EXCL) { + ip->i_itemp->ili_ilock_recur++; + } + *ipp = ip; + return 0; + } + + ASSERT(lock_flags & XFS_ILOCK_EXCL); + error = xfs_iget(tp->t_mountp, tp, ino, lock_flags, &ip, 0); + if (error) { + return error; + } + ASSERT(ip != NULL); + + /* + * Get a log_item_desc to point at the new item. + */ + if (ip->i_itemp == NULL) + xfs_inode_item_init(ip, mp); + iip = ip->i_itemp; + (void) xfs_trans_add_item(tp, (xfs_log_item_t *)(iip)); + + xfs_trans_inode_broot_debug(ip); + + /* + * If the IO lock has been acquired, mark that in + * the inode log item so we'll know to unlock it + * when the transaction commits. + */ + ASSERT(iip->ili_flags == 0); + if (lock_flags & XFS_IOLOCK_EXCL) { + iip->ili_flags |= XFS_ILI_IOLOCKED_EXCL; + } else if (lock_flags & XFS_IOLOCK_SHARED) { + iip->ili_flags |= XFS_ILI_IOLOCKED_SHARED; + } + + /* + * Initialize i_transp so we can find it with xfs_inode_incore() + * above. + */ + ip->i_transp = tp; + + *ipp = ip; + return 0; +} + + +/* + * Release the inode ip which was previously acquired with xfs_trans_iget() + * or added with xfs_trans_ijoin(). This will decrement the lock + * recursion count of the inode item. If the count goes to less than 0, + * the inode will be unlocked and disassociated from the transaction. + * + * If the inode has been modified within the transaction, it will not be + * unlocked until the transaction commits. + */ +void +xfs_trans_iput( + xfs_trans_t *tp, + xfs_inode_t *ip, + uint lock_flags) +{ + xfs_inode_log_item_t *iip; + xfs_log_item_desc_t *lidp; + + /* + * If the transaction pointer is NULL, just call xfs_iput(). + */ + if (tp == NULL) { + xfs_iput(ip, lock_flags); + } + + ASSERT(ip->i_transp == tp); + iip = ip->i_itemp; + ASSERT(iip != NULL); + + /* + * Find the item descriptor pointing to this inode's + * log item. It must be there. + */ + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)iip); + ASSERT(lidp != NULL); + ASSERT(lidp->lid_item == (xfs_log_item_t*)iip); + + /* + * Be consistent about the bookkeeping for the inode's + * io lock, but it doesn't mean much really. + */ + ASSERT((iip->ili_flags & XFS_ILI_IOLOCKED_ANY) != XFS_ILI_IOLOCKED_ANY); + if (lock_flags & (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED)) { + ASSERT(iip->ili_flags & XFS_ILI_IOLOCKED_ANY); + ASSERT((!(lock_flags & XFS_IOLOCK_EXCL)) || + (iip->ili_flags & XFS_ILI_IOLOCKED_EXCL)); + ASSERT((!(lock_flags & XFS_IOLOCK_SHARED)) || + (iip->ili_flags & + (XFS_ILI_IOLOCKED_EXCL | XFS_ILI_IOLOCKED_SHARED))); + if (iip->ili_iolock_recur > 0) { + iip->ili_iolock_recur--; + } + } + + /* + * If the release is just for a recursive lock on the inode lock, + * then decrement the count and return. We can assert that + * the caller is dropping an EXCL lock on the inode, because + * inode must be locked EXCL within transactions. + */ + ASSERT(lock_flags & XFS_ILOCK_EXCL); + if (iip->ili_ilock_recur > 0) { + iip->ili_ilock_recur--; + return; + } + ASSERT(iip->ili_iolock_recur == 0); + + /* + * If the inode was dirtied within this transaction, it cannot + * be released until the transaction commits. + */ + if (lidp->lid_flags & XFS_LID_DIRTY) { + return; + } + + xfs_trans_free_item(tp, lidp); + + /* + * Clear the hold and iolocked flags in the inode log item. + * We wouldn't want the next user of the inode to + * get confused. Assert that if the iolocked flag is set + * in the item then we are unlocking it in the call to xfs_iput() + * below. + */ + ASSERT((!(iip->ili_flags & XFS_ILI_IOLOCKED_ANY)) || + (lock_flags & (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED))); + if (iip->ili_flags & (XFS_ILI_HOLD | XFS_ILI_IOLOCKED_ANY)) { + iip->ili_flags &= ~(XFS_ILI_HOLD | XFS_ILI_IOLOCKED_ANY); + } + + /* + * Unlike xfs_brelse() the inode log item cannot be + * freed, because it is embedded within the inode. + * All we have to do is release the inode. + */ + xfs_iput(ip, lock_flags); + return; +} + + +/* + * Add the locked inode to the transaction. + * The inode must be locked, and it cannot be associated with any + * transaction. The caller must specify the locks already held + * on the inode. + */ +void +xfs_trans_ijoin( + xfs_trans_t *tp, + xfs_inode_t *ip, + uint lock_flags) +{ + xfs_inode_log_item_t *iip; + + ASSERT(ip->i_transp == NULL); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + ASSERT(lock_flags & XFS_ILOCK_EXCL); + if (ip->i_itemp == NULL) + xfs_inode_item_init(ip, ip->i_mount); + iip = ip->i_itemp; + ASSERT(iip->ili_flags == 0); + ASSERT(iip->ili_ilock_recur == 0); + ASSERT(iip->ili_iolock_recur == 0); + + /* + * Get a log_item_desc to point at the new item. + */ + (void) xfs_trans_add_item(tp, (xfs_log_item_t*)(iip)); + + xfs_trans_inode_broot_debug(ip); + + /* + * If the IO lock is already held, mark that in the inode log item. + */ + if (lock_flags & XFS_IOLOCK_EXCL) { + iip->ili_flags |= XFS_ILI_IOLOCKED_EXCL; + } else if (lock_flags & XFS_IOLOCK_SHARED) { + iip->ili_flags |= XFS_ILI_IOLOCKED_SHARED; + } + + /* + * Initialize i_transp so we can find it with xfs_inode_incore() + * in xfs_trans_iget() above. + */ + ip->i_transp = tp; +} + + + +/* + * Mark the inode as not needing to be unlocked when the inode item's + * IOP_UNLOCK() routine is called. The inode must already be locked + * and associated with the given transaction. + */ +/*ARGSUSED*/ +void +xfs_trans_ihold( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + ASSERT(ip->i_transp == tp); + ASSERT(ip->i_itemp != NULL); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + + ip->i_itemp->ili_flags |= XFS_ILI_HOLD; +} + +/* + * Cancel the previous inode hold request made on this inode + * for this transaction. + */ +/*ARGSUSED*/ +void +xfs_trans_ihold_release( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + ASSERT(ip->i_transp == tp); + ASSERT(ip->i_itemp != NULL); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + ASSERT(ip->i_itemp->ili_flags & XFS_ILI_HOLD); + + ip->i_itemp->ili_flags &= ~XFS_ILI_HOLD; +} + + +/* + * This is called to mark the fields indicated in fieldmask as needing + * to be logged when the transaction is committed. The inode must + * already be associated with the given transaction. + * + * The values for fieldmask are defined in xfs_inode_item.h. We always + * log all of the core inode if any of it has changed, and we always log + * all of the inline data/extents/b-tree root if any of them has changed. + */ +void +xfs_trans_log_inode( + xfs_trans_t *tp, + xfs_inode_t *ip, + uint flags) +{ + xfs_log_item_desc_t *lidp; + + ASSERT(ip->i_transp == tp); + ASSERT(ip->i_itemp != NULL); + ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE)); + + lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(ip->i_itemp)); + ASSERT(lidp != NULL); + + tp->t_flags |= XFS_TRANS_DIRTY; + lidp->lid_flags |= XFS_LID_DIRTY; + + /* + * Always OR in the bits from the ili_last_fields field. + * This is to coordinate with the xfs_iflush() and xfs_iflush_done() + * routines in the eventual clearing of the ilf_fields bits. + * See the big comment in xfs_iflush() for an explanation of + * this coorination mechanism. + */ + flags |= ip->i_itemp->ili_last_fields; + ip->i_itemp->ili_format.ilf_fields |= flags; +} + +#ifdef XFS_TRANS_DEBUG +/* + * Keep track of the state of the inode btree root to make sure we + * log it properly. + */ +STATIC void +xfs_trans_inode_broot_debug( + xfs_inode_t *ip) +{ + xfs_inode_log_item_t *iip; + + ASSERT(ip->i_itemp != NULL); + iip = ip->i_itemp; + if (iip->ili_root_size != 0) { + ASSERT(iip->ili_orig_root != NULL); + kmem_free(iip->ili_orig_root, iip->ili_root_size); + iip->ili_root_size = 0; + iip->ili_orig_root = NULL; + } + if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) { + ASSERT((ip->i_df.if_broot != NULL) && + (ip->i_df.if_broot_bytes > 0)); + iip->ili_root_size = ip->i_df.if_broot_bytes; + iip->ili_orig_root = + (char*)kmem_alloc(iip->ili_root_size, KM_SLEEP); + bcopy((char*)(ip->i_df.if_broot), iip->ili_orig_root, + iip->ili_root_size); + } +} +#endif + + + + + + + + + + + + diff -rNu linux-2.4.7/linux/fs/xfs/xfs_trans_item.c linux-2.4-xfs/linux/fs/xfs/xfs_trans_item.c --- linux-2.4.7/linux/fs/xfs/xfs_trans_item.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_trans_item.c Tue Apr 10 20:44:54 2001 @@ -0,0 +1,448 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +STATIC int xfs_trans_unlock_chunk(xfs_log_item_chunk_t *, + int, int, xfs_lsn_t); + +/* + * This is called to add the given log item to the transaction's + * list of log items. It must find a free log item descriptor + * or allocate a new one and add the item to that descriptor. + * The function returns a pointer to item descriptor used to point + * to the new item. The log item will now point to its new descriptor + * with its li_desc field. + */ +xfs_log_item_desc_t * +xfs_trans_add_item(xfs_trans_t *tp, xfs_log_item_t *lip) +{ + xfs_log_item_desc_t *lidp; + xfs_log_item_chunk_t *licp; + int i=0; + + /* + * If there are no free descriptors, allocate a new chunk + * of them and put it at the front of the chunk list. + */ + if (tp->t_items_free == 0) { + licp = (xfs_log_item_chunk_t*) + kmem_alloc(sizeof(xfs_log_item_chunk_t), KM_SLEEP); + ASSERT(licp != NULL); + /* + * Initialize the chunk, and then + * claim the first slot in the newly allocated chunk. + */ + XFS_LIC_INIT(licp); + XFS_LIC_CLAIM(licp, 0); + licp->lic_unused = 1; + XFS_LIC_INIT_SLOT(licp, 0); + lidp = XFS_LIC_SLOT(licp, 0); + + /* + * Link in the new chunk and update the free count. + */ + licp->lic_next = tp->t_items.lic_next; + tp->t_items.lic_next = licp; + tp->t_items_free = XFS_LIC_NUM_SLOTS - 1; + + /* + * Initialize the descriptor and the generic portion + * of the log item. + * + * Point the new slot at this item and return it. + * Also point the log item at its currently active + * descriptor and set the item's mount pointer. + */ + lidp->lid_item = lip; + lidp->lid_flags = 0; + lidp->lid_size = 0; + lip->li_desc = lidp; + lip->li_mountp = tp->t_mountp; + return (lidp); + } + + /* + * Find the free descriptor. It is somewhere in the chunklist + * of descriptors. + */ + licp = &tp->t_items; + while (licp != NULL) { + if (XFS_LIC_VACANCY(licp)) { + if (licp->lic_unused <= XFS_LIC_MAX_SLOT) { + i = licp->lic_unused; + ASSERT(XFS_LIC_ISFREE(licp, i)); + break; + } + for (i = 0; i <= XFS_LIC_MAX_SLOT; i++) { + if (XFS_LIC_ISFREE(licp, i)) + break; + } + ASSERT(i <= XFS_LIC_MAX_SLOT); + break; + } + licp = licp->lic_next; + } + ASSERT(licp != NULL); + /* + * If we find a free descriptor, claim it, + * initialize it, and return it. + */ + XFS_LIC_CLAIM(licp, i); + if (licp->lic_unused <= i) { + licp->lic_unused = i + 1; + XFS_LIC_INIT_SLOT(licp, i); + } + lidp = XFS_LIC_SLOT(licp, i); + tp->t_items_free--; + lidp->lid_item = lip; + lidp->lid_flags = 0; + lidp->lid_size = 0; + lip->li_desc = lidp; + lip->li_mountp = tp->t_mountp; + return (lidp); +} + +/* + * Free the given descriptor. + * + * This requires setting the bit in the chunk's free mask corresponding + * to the given slot. + */ +void +xfs_trans_free_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp) +{ + uint slot; + xfs_log_item_chunk_t *licp; + xfs_log_item_chunk_t **licpp; + + slot = XFS_LIC_DESC_TO_SLOT(lidp); + licp = XFS_LIC_DESC_TO_CHUNK(lidp); + XFS_LIC_RELSE(licp, slot); + lidp->lid_item->li_desc = NULL; + tp->t_items_free++; + + /* + * If there are no more used items in the chunk and this is not + * the chunk embedded in the transaction structure, then free + * the chunk. First pull it from the chunk list and then + * free it back to the heap. We didn't bother with a doubly + * linked list here because the lists should be very short + * and this is not a performance path. It's better to save + * the memory of the extra pointer. + * + * Also decrement the transaction structure's count of free items + * by the number in a chunk since we are freeing an empty chunk. + */ + if (XFS_LIC_ARE_ALL_FREE(licp) && (licp != &(tp->t_items))) { + licpp = &(tp->t_items.lic_next); + while (*licpp != licp) { + ASSERT(*licpp != NULL); + licpp = &((*licpp)->lic_next); + } + *licpp = licp->lic_next; + kmem_free(licp, sizeof(xfs_log_item_chunk_t)); + tp->t_items_free -= XFS_LIC_NUM_SLOTS; + } +} + +/* + * This is called to find the descriptor corresponding to the given + * log item. It returns a pointer to the descriptor. + * The log item MUST have a corresponding descriptor in the given + * transaction. This routine does not return NULL, it panics. + * + * The descriptor pointer is kept in the log item's li_desc field. + * Just return it. + */ +/*ARGSUSED*/ +xfs_log_item_desc_t * +xfs_trans_find_item(xfs_trans_t *tp, xfs_log_item_t *lip) +{ + ASSERT(lip->li_desc != NULL); + + return (lip->li_desc); +} + + +/* + * Return a pointer to the first descriptor in the chunk list. + * This does not return NULL if there are none, it panics. + * + * The first descriptor must be in either the first or second chunk. + * This is because the only chunk allowed to be empty is the first. + * All others are freed when they become empty. + * + * At some point this and xfs_trans_next_item() should be optimized + * to quickly look at the mask to determine if there is anything to + * look at. + */ +xfs_log_item_desc_t * +xfs_trans_first_item(xfs_trans_t *tp) +{ + xfs_log_item_chunk_t *licp; + int i; + + licp = &tp->t_items; + /* + * If it's not in the first chunk, skip to the second. + */ + if (XFS_LIC_ARE_ALL_FREE(licp)) { + licp = licp->lic_next; + } + + /* + * Return the first non-free descriptor in the chunk. + */ + ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); + for (i = 0; i < licp->lic_unused; i++) { + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + return (XFS_LIC_SLOT(licp, i)); + } + cmn_err(CE_WARN, "xfs_trans_first_item() -- no first item"); + return(NULL); +} + + +/* + * Given a descriptor, return the next descriptor in the chunk list. + * This returns NULL if there are no more used descriptors in the list. + * + * We do this by first locating the chunk in which the descriptor resides, + * and then scanning forward in the chunk and the list for the next + * used descriptor. + */ +/*ARGSUSED*/ +xfs_log_item_desc_t * +xfs_trans_next_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp) +{ + xfs_log_item_chunk_t *licp; + int i; + + licp = XFS_LIC_DESC_TO_CHUNK(lidp); + + /* + * First search the rest of the chunk. The for loop keeps us + * from referencing things beyond the end of the chunk. + */ + for (i = (int)XFS_LIC_DESC_TO_SLOT(lidp) + 1; i < licp->lic_unused; i++) { + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + return (XFS_LIC_SLOT(licp, i)); + } + + /* + * Now search the next chunk. It must be there, because the + * next chunk would have been freed if it were empty. + * If there is no next chunk, return NULL. + */ + if (licp->lic_next == NULL) { + return (NULL); + } + + licp = licp->lic_next; + ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); + for (i = 0; i < licp->lic_unused; i++) { + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + return (XFS_LIC_SLOT(licp, i)); + } + ASSERT(0); + /* NOTREACHED */ + return 0; /* keep gcc quite */ +} + +/* + * This is called to unlock all of the items of a transaction and to free + * all the descriptors of that transaction. + * + * It walks the list of descriptors and unlocks each item. It frees + * each chunk except that embedded in the transaction as it goes along. + */ +void +xfs_trans_free_items( + xfs_trans_t *tp, + int flags) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_chunk_t *next_licp; + int abort; + + abort = flags & XFS_TRANS_ABORT; + licp = &tp->t_items; + /* + * Special case the embedded chunk so we don't free it below. + */ + if (!XFS_LIC_ARE_ALL_FREE(licp)) { + (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN); + XFS_LIC_ALL_FREE(licp); + licp->lic_unused = 0; + } + licp = licp->lic_next; + + /* + * Unlock each item in each chunk and free the chunks. + */ + while (licp != NULL) { + ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); + (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN); + next_licp = licp->lic_next; + kmem_free(licp, sizeof(xfs_log_item_chunk_t)); + licp = next_licp; + } + + /* + * Reset the transaction structure's free item count. + */ + tp->t_items_free = XFS_LIC_NUM_SLOTS; + tp->t_items.lic_next = NULL; +} + + + +/* + * This is called to unlock the items associated with a transaction. + * Items which were not logged should be freed. + * Those which were logged must still be tracked so they can be unpinned + * when the transaction commits. + */ +void +xfs_trans_unlock_items(xfs_trans_t *tp, xfs_lsn_t commit_lsn) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_chunk_t *next_licp; + xfs_log_item_chunk_t **licpp; + int freed; + + freed = 0; + licp = &tp->t_items; + + /* + * Special case the embedded chunk so we don't free. + */ + if (!XFS_LIC_ARE_ALL_FREE(licp)) { + freed = xfs_trans_unlock_chunk(licp, 0, 0, commit_lsn); + } + licpp = &(tp->t_items.lic_next); + licp = licp->lic_next; + + /* + * Unlock each item in each chunk, free non-dirty descriptors, + * and free empty chunks. + */ + while (licp != NULL) { + ASSERT(!XFS_LIC_ARE_ALL_FREE(licp)); + freed += xfs_trans_unlock_chunk(licp, 0, 0, commit_lsn); + next_licp = licp->lic_next; + if (XFS_LIC_ARE_ALL_FREE(licp)) { + *licpp = next_licp; + kmem_free(licp, sizeof(xfs_log_item_chunk_t)); + freed -= XFS_LIC_NUM_SLOTS; + } else { + licpp = &(licp->lic_next); + } + ASSERT(*licpp == next_licp); + licp = next_licp; + } + + /* + * Fix the free descriptor count in the transaction. + */ + tp->t_items_free += freed; +} + +/* + * Unlock each item pointed to by a descriptor in the given chunk. + * Stamp the commit lsn into each item if necessary. + * Free descriptors pointing to items which are not dirty if freeing_chunk + * is zero. If freeing_chunk is non-zero, then we need to unlock all + * items in the chunk including those with XFS_LID_SYNC_UNLOCK set. + * Return the number of descriptors freed. + */ +STATIC int +xfs_trans_unlock_chunk( + xfs_log_item_chunk_t *licp, + int freeing_chunk, + int abort, + xfs_lsn_t commit_lsn) +{ + xfs_log_item_desc_t *lidp; + xfs_log_item_t *lip; + int i; + int freed; + + freed = 0; + lidp = licp->lic_descs; + for (i = 0; i < licp->lic_unused; i++, lidp++) { + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + lip = lidp->lid_item; + lip->li_desc = NULL; + + if (commit_lsn != NULLCOMMITLSN) + IOP_COMMITTING(lip, commit_lsn); + + /* XXXsup */ + if (abort) + lip->li_flags |= XFS_LI_ABORTED; + + /* if (abort) { + IOP_ABORT(lip); + } else */ + if (!(lidp->lid_flags & XFS_LID_SYNC_UNLOCK) || + freeing_chunk || abort) { + IOP_UNLOCK(lip); + } + + /* + * Free the descriptor if the item is not dirty + * within this transaction and the caller is not + * going to just free the entire thing regardless. + */ + if (!(freeing_chunk) && + (!(lidp->lid_flags & XFS_LID_DIRTY) || abort)) { + XFS_LIC_RELSE(licp, i); + freed++; + } + } + + return (freed); +} diff -rNu linux-2.4.7/linux/fs/xfs/xfs_trans_priv.h linux-2.4-xfs/linux/fs/xfs/xfs_trans_priv.h --- linux-2.4.7/linux/fs/xfs/xfs_trans_priv.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_trans_priv.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_TRANS_PRIV_H__ +#define __XFS_TRANS_PRIV_H__ + +struct xfs_log_item; +struct xfs_log_item_desc; +struct xfs_mount; +struct xfs_trans; + +/* + * From xfs_trans_item.c + */ +struct xfs_log_item_desc *xfs_trans_add_item(struct xfs_trans *, + struct xfs_log_item *); +void xfs_trans_free_item(struct xfs_trans *, + struct xfs_log_item_desc *); +struct xfs_log_item_desc *xfs_trans_find_item(struct xfs_trans *, + struct xfs_log_item *); +struct xfs_log_item_desc *xfs_trans_first_item(struct xfs_trans *); +struct xfs_log_item_desc *xfs_trans_next_item(struct xfs_trans *, + struct xfs_log_item_desc *); +void xfs_trans_free_items(struct xfs_trans *, int); +void xfs_trans_unlock_items(struct xfs_trans *, + xfs_lsn_t); + + +/* + * From xfs_trans_ail.c + */ +#if defined(INTERRUPT_LATENCY_TESTING) +#define xfs_trans_update_ail(a,b,c,d) _xfs_trans_update_ail(a,b,c) +#define xfs_trans_delete_ail(a,b,c) _xfs_trans_delete_ail(a,b) +void _xfs_trans_update_ail(struct xfs_mount *, + struct xfs_log_item *, xfs_lsn_t); +void _xfs_trans_delete_ail(struct xfs_mount *, + struct xfs_log_item *); +#else /* INTERRUPT_LATENCY_TESTING */ +#define xfs_trans_update_ail(a,b,c,d) _xfs_trans_update_ail(a,b,c,d) +#define xfs_trans_delete_ail(a,b,c) _xfs_trans_delete_ail(a,b,c) +void xfs_trans_update_ail(struct xfs_mount *, + struct xfs_log_item *, xfs_lsn_t, int); +void xfs_trans_delete_ail(struct xfs_mount *, + struct xfs_log_item *, int); +#endif /* INTERRUPT_LATENCY_TESTING */ +struct xfs_log_item *xfs_trans_first_ail(struct xfs_mount *, int *); +struct xfs_log_item *xfs_trans_next_ail(struct xfs_mount *, + struct xfs_log_item *, int *, int *); + + +#endif /* __XFS_TRANS_PRIV_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_trans_space.h linux-2.4-xfs/linux/fs/xfs/xfs_trans_space.h --- linux-2.4.7/linux/fs/xfs/xfs_trans_space.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_trans_space.h Mon Sep 25 00:42:07 2000 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_TRANS_SPACE_H__ +#define __XFS_TRANS_SPACE_H__ + +/* + * Components of space reservations. + */ +#define XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) \ + (((mp)->m_alloc_mxr[0]) - ((mp)->m_alloc_mnr[0])) +#define XFS_EXTENTADD_SPACE_RES(mp,w) (XFS_BM_MAXLEVELS(mp,w) - 1) +#define XFS_NEXTENTADD_SPACE_RES(mp,b,w)\ + (((b + XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) - 1) / \ + XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp)) * \ + XFS_EXTENTADD_SPACE_RES(mp,w)) +#define XFS_DAENTER_1B(mp,w) ((w) == XFS_DATA_FORK ? (mp)->m_dirblkfsbs : 1) +#define XFS_DAENTER_DBS(mp,w) \ + (XFS_DA_NODE_MAXDEPTH + \ + ((XFS_DIR_IS_V2(mp) && (w) == XFS_DATA_FORK) ? 2 : 0)) +#define XFS_DAENTER_BLOCKS(mp,w) \ + (XFS_DAENTER_1B(mp,w) * XFS_DAENTER_DBS(mp,w)) +#define XFS_DAENTER_BMAP1B(mp,w) \ + XFS_NEXTENTADD_SPACE_RES(mp, XFS_DAENTER_1B(mp, w), w) +#define XFS_DAENTER_BMAPS(mp,w) \ + (XFS_DAENTER_DBS(mp,w) * XFS_DAENTER_BMAP1B(mp,w)) +#define XFS_DAENTER_SPACE_RES(mp,w) \ + (XFS_DAENTER_BLOCKS(mp,w) + XFS_DAENTER_BMAPS(mp,w)) +#define XFS_DAREMOVE_SPACE_RES(mp,w) XFS_DAENTER_BMAPS(mp,w) +#define XFS_DIRENTER_MAX_SPLIT(mp,nl) \ + (((mp)->m_sb.sb_blocksize == 512 && \ + XFS_DIR_IS_V1(mp) && \ + (nl) >= XFS_DIR_LEAF_CAN_DOUBLE_SPLIT_LEN) ? 2 : 1) +#define XFS_DIRENTER_SPACE_RES(mp,nl) \ + (XFS_DAENTER_SPACE_RES(mp, XFS_DATA_FORK) * \ + XFS_DIRENTER_MAX_SPLIT(mp,nl)) +#define XFS_DIRREMOVE_SPACE_RES(mp) \ + XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK) +#define XFS_IALLOC_SPACE_RES(mp) \ + (XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp)-1) + +/* + * Space reservation values for various transactions. + */ +#define XFS_ADDAFORK_SPACE_RES(mp) \ + ((mp)->m_dirblkfsbs + \ + (XFS_DIR_IS_V1(mp) ? 0 : XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK))) +#define XFS_ATTRRM_SPACE_RES(mp) \ + XFS_DAREMOVE_SPACE_RES(mp, XFS_ATTR_FORK) +/* This macro is not used - see inline code in xfs_attr_set */ +#define XFS_ATTRSET_SPACE_RES(mp, v) \ + (XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) + XFS_B_TO_FSB(mp, v)) +#define XFS_CREATE_SPACE_RES(mp,nl) \ + (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) +#define XFS_DIOSTRAT_SPACE_RES(mp, v) \ + (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + (v)) +#define XFS_GROWFS_SPACE_RES(mp) \ + (2 * XFS_AG_MAXLEVELS(mp)) +#define XFS_GROWFSRT_SPACE_RES(mp,b) \ + ((b) + XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK)) +#define XFS_LINK_SPACE_RES(mp,nl) \ + XFS_DIRENTER_SPACE_RES(mp,nl) +#define XFS_MKDIR_SPACE_RES(mp,nl) \ + (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) +#define XFS_QM_DQALLOC_SPACE_RES(mp) \ + (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + \ + XFS_DQUOT_CLUSTER_SIZE_FSB) +#define XFS_QM_QINOCREATE_SPACE_RES(mp) \ + XFS_IALLOC_SPACE_RES(mp) +#define XFS_REMOVE_SPACE_RES(mp) \ + XFS_DIRREMOVE_SPACE_RES(mp) +#define XFS_RENAME_SPACE_RES(mp,nl) \ + (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) +#define XFS_SYMLINK_SPACE_RES(mp,nl,b) \ + (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b)) + +#endif /* __XFS_TRANS_SPACE_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_types.h linux-2.4-xfs/linux/fs/xfs/xfs_types.h --- linux-2.4.7/linux/fs/xfs/xfs_types.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_types.h Wed Apr 18 21:37:23 2001 @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_TYPES_H__ +#define __XFS_TYPES_H__ + +/* + * Some types are conditional based on the selected configuration. + * Set XFS_BIG_FILES=1 or 0 and XFS_BIG_FILESYSTEMS=1 or 0 depending + * on the desired configuration. + * XFS_BIG_FILES needs pgno_t to be 64 bits (64-bit kernels). + * XFS_BIG_FILESYSTEMS needs daddr_t to be 64 bits (N32 and 64-bit kernels). + * + * Expect these to be set from klocaldefs, or from the machine-type + * defs files for the normal case. + */ + +#define XFS_BIG_FILES 1 +#define XFS_BIG_FILESYSTEMS 1 + +typedef __uint32_t xfs_agblock_t; /* blockno in alloc. group */ +typedef __uint32_t xfs_extlen_t; /* extent length in blocks */ +typedef __uint32_t xfs_agnumber_t; /* allocation group number */ +typedef __int32_t xfs_extnum_t; /* # of extents in a file */ +typedef __int16_t xfs_aextnum_t; /* # extents in an attribute fork */ +typedef __int64_t xfs_fsize_t; /* bytes in a file */ +typedef __uint64_t xfs_ufsize_t; /* unsigned bytes in a file */ + +typedef __int32_t xfs_suminfo_t; /* type of bitmap summary info */ +typedef __int32_t xfs_rtword_t; /* word type for bitmap manipulations */ + +typedef __int64_t xfs_lsn_t; /* log sequence number */ +typedef __int32_t xfs_tid_t; /* transaction identifier */ + +typedef __uint32_t xfs_dablk_t; /* dir/attr block number (in file) */ +typedef __uint32_t xfs_dahash_t; /* dir/attr hash value */ + +typedef __uint16_t xfs_prid_t; /* prid_t truncated to 16bits in XFS */ + +/* + * These types are 64 bits on disk but are either 32 or 64 bits in memory. + * Disk based types: + */ +typedef __uint64_t xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */ +typedef __uint64_t xfs_drfsbno_t; /* blockno in filesystem (raw) */ +typedef __uint64_t xfs_drtbno_t; /* extent (block) in realtime area */ +typedef __uint64_t xfs_dfiloff_t; /* block number in a file */ +typedef __uint64_t xfs_dfilblks_t; /* number of blocks in a file */ + +/* + * Memory based types are conditional. + */ +#if XFS_BIG_FILESYSTEMS +typedef __uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */ +typedef __uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */ +typedef __uint64_t xfs_rtblock_t; /* extent (block) in realtime area */ +typedef __int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */ +#else +typedef __uint32_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */ +typedef __uint32_t xfs_rfsblock_t; /* blockno in filesystem (raw) */ +typedef __uint32_t xfs_rtblock_t; /* extent (block) in realtime area */ +typedef __int32_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */ +#endif +#if XFS_BIG_FILES +typedef __uint64_t xfs_fileoff_t; /* block number in a file */ +typedef __int64_t xfs_sfiloff_t; /* signed block number in a file */ +typedef __uint64_t xfs_filblks_t; /* number of blocks in a file */ +#else +typedef __uint32_t xfs_fileoff_t; /* block number in a file */ +typedef __int32_t xfs_sfiloff_t; /* signed block number in a file */ +typedef __uint32_t xfs_filblks_t; /* number of blocks in a file */ +#endif + +typedef __uint8_t xfs_arch_t; /* architecutre of an xfs fs */ + +/* + * Null values for the types. + */ +#define NULLDFSBNO ((xfs_dfsbno_t)-1) +#define NULLDRFSBNO ((xfs_drfsbno_t)-1) +#define NULLDRTBNO ((xfs_drtbno_t)-1) +#define NULLDFILOFF ((xfs_dfiloff_t)-1) + +#define NULLFSBLOCK ((xfs_fsblock_t)-1) +#define NULLRFSBLOCK ((xfs_rfsblock_t)-1) +#define NULLRTBLOCK ((xfs_rtblock_t)-1) +#define NULLFILEOFF ((xfs_fileoff_t)-1) + +#define NULLAGBLOCK ((xfs_agblock_t)-1) +#define NULLAGNUMBER ((xfs_agnumber_t)-1) +#define NULLEXTNUM ((xfs_extnum_t)-1) + +#define NULLCOMMITLSN ((xfs_lsn_t)-1) + +/* + * Max values for extlen, extnum, aextnum. + */ +#define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */ +#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */ +#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */ + +/* + * MAXNAMELEN is the length (including the terminating null) of + * the longest permissible file (component) name. + */ +#define MAXNAMELEN 256 + +typedef enum { + XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi +} xfs_lookup_t; + +typedef enum { + XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi, + XFS_BTNUM_MAX +} xfs_btnum_t; + + +#if defined(CONFIG_PROC_FS) && defined(__KERNEL__) +/* + * XFS global statistics + */ +struct xfsstats { +# define XFSSTAT_END_EXTENT_ALLOC 4 + __uint32_t xs_allocx; + __uint32_t xs_allocb; + __uint32_t xs_freex; + __uint32_t xs_freeb; +# define XFSSTAT_END_ALLOC_BTREE (XFSSTAT_END_EXTENT_ALLOC+4) + __uint32_t xs_abt_lookup; + __uint32_t xs_abt_compare; + __uint32_t xs_abt_insrec; + __uint32_t xs_abt_delrec; +# define XFSSTAT_END_BLOCK_MAPPING (XFSSTAT_END_ALLOC_BTREE+7) + __uint32_t xs_blk_mapr; + __uint32_t xs_blk_mapw; + __uint32_t xs_blk_unmap; + __uint32_t xs_add_exlist; + __uint32_t xs_del_exlist; + __uint32_t xs_look_exlist; + __uint32_t xs_cmp_exlist; +# define XFSSTAT_END_BLOCK_MAP_BTREE (XFSSTAT_END_BLOCK_MAPPING+4) + __uint32_t xs_bmbt_lookup; + __uint32_t xs_bmbt_compare; + __uint32_t xs_bmbt_insrec; + __uint32_t xs_bmbt_delrec; +# define XFSSTAT_END_DIRECTORY_OPS (XFSSTAT_END_BLOCK_MAP_BTREE+4) + __uint32_t xs_dir_lookup; + __uint32_t xs_dir_create; + __uint32_t xs_dir_remove; + __uint32_t xs_dir_getdents; +# define XFSSTAT_END_TRANSACTIONS (XFSSTAT_END_DIRECTORY_OPS+3) + __uint32_t xs_trans_sync; + __uint32_t xs_trans_async; + __uint32_t xs_trans_empty; +# define XFSSTAT_END_INODE_OPS (XFSSTAT_END_TRANSACTIONS+7) + __uint32_t xs_ig_attempts; + __uint32_t xs_ig_found; + __uint32_t xs_ig_frecycle; + __uint32_t xs_ig_missed; + __uint32_t xs_ig_dup; + __uint32_t xs_ig_reclaims; + __uint32_t xs_ig_attrchg; +# define XFSSTAT_END_LOG_OPS (XFSSTAT_END_INODE_OPS+5) + __uint32_t xs_log_writes; + __uint32_t xs_log_blocks; + __uint32_t xs_log_noiclogs; + __uint32_t xs_log_force; + __uint32_t xs_log_force_sleep; +# define XFSSTAT_END_TAIL_PUSHING (XFSSTAT_END_LOG_OPS+10) + __uint32_t xs_try_logspace; + __uint32_t xs_sleep_logspace; + __uint32_t xs_push_ail; + __uint32_t xs_push_ail_success; + __uint32_t xs_push_ail_pushbuf; + __uint32_t xs_push_ail_pinned; + __uint32_t xs_push_ail_locked; + __uint32_t xs_push_ail_flushing; + __uint32_t xs_push_ail_restarts; + __uint32_t xs_push_ail_flush; +# define XFSSTAT_END_WRITE_CONVERT (XFSSTAT_END_TAIL_PUSHING+2) + __uint32_t xs_xstrat_quick; + __uint32_t xs_xstrat_split; +# define XFSSTAT_END_READ_WRITE_OPS (XFSSTAT_END_WRITE_CONVERT+2) + __uint32_t xs_write_calls; + __uint32_t xs_read_calls; +# define XFSSTAT_END_ATTRIBUTE_OPS (XFSSTAT_END_READ_WRITE_OPS+4) + __uint32_t xs_attr_get; + __uint32_t xs_attr_set; + __uint32_t xs_attr_remove; + __uint32_t xs_attr_list; +# define XFSSTAT_END_QUOTA_OPS (XFSSTAT_END_ATTRIBUTE_OPS+8) + __uint32_t xs_qm_dqreclaims; + __uint32_t xs_qm_dqreclaim_misses; + __uint32_t xs_qm_dquot_dups; + __uint32_t xs_qm_dqcachemisses; + __uint32_t xs_qm_dqcachehits; + __uint32_t xs_qm_dqwants; + __uint32_t xs_qm_dqshake_reclaims; + __uint32_t xs_qm_dqinact_reclaims; +# define XFSSTAT_END_INODE_CLUSTER (XFSSTAT_END_QUOTA_OPS+3) + __uint32_t xs_iflush_count; + __uint32_t xs_icluster_flushcnt; + __uint32_t xs_icluster_flushinode; +# define XFSSTAT_END_VNODE_OPS (XFSSTAT_END_INODE_CLUSTER+8) + __uint32_t vn_active; /* # vnodes not on free lists */ + __uint32_t vn_alloc; /* # times vn_alloc called */ + __uint32_t vn_get; /* # times vn_get called */ + __uint32_t vn_hold; /* # times vn_hold called */ + __uint32_t vn_rele; /* # times vn_rele called */ + __uint32_t vn_reclaim; /* # times vn_reclaim called */ + __uint32_t vn_remove; /* # times vn_remove called */ + __uint32_t vn_free; /* # times vn_free called */ +/* Extra precision counters */ + __uint64_t xs_xstrat_bytes; + __uint64_t xs_write_bytes; + __uint64_t xs_read_bytes; +} xfsstats; + +# define XFS_STATS_INC(count) ( (count)++ ) +# define XFS_STATS_DEC(count) ( (count)-- ) +# define XFS_STATS_ADD(count, inc) ( (count) += (inc) ) +#else /* !CONFIG_PROC_FS */ +# define XFS_STATS_INC(count) +# define XFS_STATS_DEC(count) +# define XFS_STATS_ADD(count, inc) +#endif /* !CONFIG_PROC_FS */ + + +#ifdef __KERNEL__ + +/* juggle IRIX device numbers - still used in ondisk structures */ + +#define IRIX_DEV_BITSMAJOR 14 +#define IRIX_DEV_BITSMINOR 18 +#define IRIX_DEV_MAXMAJ 0x1ff +#define IRIX_DEV_MAXMIN 0x3ffff +#define IRIX_DEV_MAJOR(dev) ((int)(((unsigned)(dev)>>IRIX_DEV_BITSMINOR) \ + & IRIX_DEV_MAXMAJ)) +#define IRIX_DEV_MINOR(dev) ((int)((dev)&IRIX_DEV_MAXMIN)) +#define IRIX_MKDEV(major,minor) ((xfs_dev_t)(((major)< + + +/* + * Test the sticky attribute of a directory. We can unlink from a sticky + * directory that's writable by us if: we are superuser, we own the file, + * we own the directory, or the file is writable. + */ +int +xfs_stickytest( + xfs_inode_t *dp, + xfs_inode_t *ip, + cred_t *cr) +{ + if (!(dp->i_d.di_mode & ISVTX)) + return 0; + if (current->fsuid == ip->i_d.di_uid) + return 0; + if (current->fsuid == dp->i_d.di_uid) + return 0; + if (!capable_cred(cr, CAP_FOWNER)) { + if (xpg4_sticky_dir) { + return XFS_ERROR(EACCES); + } else { + return xfs_iaccess(ip, IWRITE, cr); + } + } + return 0; +} + +/* + * Wrapper around xfs_dir_lookup. + * + * If DLF_IGET is set, then this routine will also return the inode. + * Note that the inode will not be locked. Note, however, that the + * vnode will have an additional reference in this case. + */ +int +xfs_dir_lookup_int( + xfs_trans_t *tp, + bhv_desc_t *dir_bdp, + int flags, + char *name, + struct pathname *pnp, + xfs_ino_t *inum, + xfs_inode_t **ipp, + uint *dir_unlocked) +{ + vnode_t *vp; + vnode_t *dir_vp; + xfs_inode_t *dp; + xfs_ino_t curr_inum; + int name_len; + int error; + int do_iget; + uint dir_gen; + uint lock_mode; + bhv_desc_t *bdp; + + dir_vp = BHV_TO_VNODE(dir_bdp); + vn_trace_entry(dir_vp, "xfs_dir_lookup_int", + (inst_t *)__return_address); + do_iget = flags & DLF_IGET; + ASSERT((flags & (DLF_IGET | DLF_NODNLC)) != (DLF_IGET | DLF_NODNLC)); + error = 0; + ASSERT(!(flags & DLF_IGET) || (dir_unlocked != NULL)); + if (dir_unlocked != NULL) { + *dir_unlocked = 0; + } + + /* + * Handle degenerate pathname component. + */ + if (*name == '\0') { + VN_HOLD(dir_vp); + *inum = XFS_BHVTOI(dir_bdp)->i_ino; + if (do_iget) { + *ipp = XFS_BHVTOI(dir_bdp); + } + return 0; + } + if (flags & DLF_LOCK_SHARED) { + lock_mode = XFS_ILOCK_SHARED; + } else { + lock_mode = XFS_ILOCK_EXCL; + } + + dp = XFS_BHVTOI(dir_bdp); + + bdp = NULL; + + /* + * If all else fails, call the directory code. + */ + if (pnp != NULL) + name_len = pnp->pn_complen; + else + name_len = strlen(name); + + error = XFS_DIR_LOOKUP(dp->i_mount, tp, dp, name, name_len, inum); + if (!error && do_iget) { + *dir_unlocked = 1; + for (;;) { + /* + * Unlock the directory and save the directory's + * generation count. We do this because we can't + * hold the directory lock while doing the vn_get() + * in xfs_iget(). Doing so could cause us to hold + * a lock while waiting for the inode to finish + * being inactive while it's waiting for a log + * reservation in the inactive routine. + */ + dir_gen = dp->i_gen; + xfs_iunlock(dp, lock_mode); + + if (bdp) { + VN_RELE(BHV_TO_VNODE(bdp)); + bdp = NULL; + } + + error = xfs_iget(dp->i_mount, NULL, *inum, + 0, ipp, 0); + + xfs_ilock(dp, lock_mode); + + if (error) { + *ipp = NULL; + return error; + } + + /* + * If something changed in the directory try again. + * If we get an error just return the error. That + * includes the case where the file is removed + * (ENOENT). If the inode number has changed, then + * drop the inode we have and get the latest one. + * If the inode number is the same, then we just + * go with it. This includes the case where the + * inode is freed and recreated under the same + * name while we're doing the iget. It is OK + * to use the inode we already have in that case, + * as there is only one copy of an inode in the + * cache at a time (regardless of generation count) + * and it just looks like the first lookup never + * occurred. + */ + if (dp->i_gen != dir_gen) { + /* + * If the directory was removed while + * we left it unlocked then just get + * out of here. + */ + if (dp->i_d.di_nlink == 0) { + vp = XFS_ITOV(*ipp); + xfs_iunlock(dp, lock_mode); + VN_RELE(vp); + xfs_ilock(dp, lock_mode); + return XFS_ERROR(ENOENT); + } + + error = XFS_DIR_LOOKUP(dp->i_mount, tp, dp, + name, name_len, + &curr_inum); + + if (error || (curr_inum != *inum)) { + vp = XFS_ITOV(*ipp); + xfs_iunlock(dp, lock_mode); + VN_RELE(vp); + xfs_ilock(dp, lock_mode); + if (error) { + return error; + } else { + /* + * Drop the directory + * lock and do the iget + * again. Save the ino + * that we found in *inum + * for when we do the + * check again. + */ + *inum = curr_inum; + continue; + } + } + } + /* + * Everything is consistent, so just go with + * what we've got. + */ + break; + } + + if ((*ipp)->i_d.di_mode == 0) { + vp = XFS_ITOV(*ipp); + /* + * The inode has been freed. Something is + * wrong so just get out of here. + */ + *ipp = NULL; + xfs_iunlock(dp, lock_mode); + VN_RELE(vp); + xfs_ilock(dp, lock_mode); + error = XFS_ERROR(ENOENT); + } else { + bdp = XFS_ITOBHV(*ipp); + bdp = NULL; + } + } + if (bdp) { + /* The only time we should get here is if the dir_lookup + * failed. + */ + ASSERT(error); + xfs_iunlock(dp, lock_mode); + VN_RELE(BHV_TO_VNODE(bdp)); + xfs_ilock(dp, lock_mode); + if (dir_unlocked != NULL) *dir_unlocked = 1; + } + return error; +} + + + +/* + * Allocates a new inode from disk and return a pointer to the + * incore copy. This routine will internally commit the current + * transaction and allocate a new one if the Space Manager needed + * to do an allocation to replenish the inode free-list. + * + * This routine is designed to be called from xfs_create and + * xfs_create_dir. + * + */ +int +xfs_dir_ialloc( + xfs_trans_t **tpp, /* input: current transaction; + output: may be a new transaction. */ + xfs_inode_t *dp, /* directory within whose allocate + the inode. */ + mode_t mode, + nlink_t nlink, + dev_t rdev, + cred_t *credp, + prid_t prid, /* project id */ + int okalloc, /* ok to allocate new space */ + xfs_inode_t **ipp, /* pointer to inode; it will be + locked. */ + int *committed) + +{ + xfs_trans_t *tp; + xfs_trans_t *ntp; + xfs_inode_t *ip; + xfs_buf_t *ialloc_context = NULL; + boolean_t call_again = B_FALSE; + int code; + uint log_res; + uint log_count; + void *dqinfo; + uint tflags; + + tp = *tpp; + ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); + + /* + * xfs_ialloc will return a pointer to an incore inode if + * the Space Manager has an available inode on the free + * list. Otherwise, it will do an allocation and replenish + * the freelist. Since we can only do one allocation per + * transaction without deadlocks, we will need to commit the + * current transaction and start a new one. We will then + * need to call xfs_ialloc again to get the inode. + * + * If xfs_ialloc did an allocation to replenish the freelist, + * it returns the bp containing the head of the freelist as + * ialloc_context. We will hold a lock on it across the + * transaction commit so that no other process can steal + * the inode(s) that we've just allocated. + */ + code = xfs_ialloc(tp, dp, mode, nlink, rdev, credp, prid, okalloc, + &ialloc_context, &call_again, &ip); + + /* + * Return an error if we were unable to allocate a new inode. + * This should only happen if we run out of space on disk or + * encounter a disk error. + */ + if (code) { + *ipp = NULL; + return code; + } + if (!call_again && (ip == NULL)) { + *ipp = NULL; + return XFS_ERROR(ENOSPC); + } + + /* + * If call_again is set, then we were unable to get an + * inode in one operation. We need to commit the current + * transaction and call xfs_ialloc() again. It is guaranteed + * to succeed the second time. + */ + if (call_again) { + + /* + * Normally, xfs_trans_commit releases all the locks. + * We call bhold to hang on to the ialloc_context across + * the commit. Holding this buffer prevents any other + * processes from doing any allocations in this + * allocation group. + */ + xfs_trans_bhold(tp, ialloc_context); + /* + * Save the log reservation so we can use + * them in the next transaction. + */ + log_res = xfs_trans_get_log_res(tp); + log_count = xfs_trans_get_log_count(tp); + + /* + * We want the quota changes to be associated with the next + * transaction, NOT this one. So, detach the dqinfo from this + * and attach it to the next transaction. + */ + dqinfo = NULL; + tflags = 0; + if (tp->t_dqinfo) { + dqinfo = (void *)tp->t_dqinfo; + tp->t_dqinfo = NULL; + tflags = tp->t_flags & XFS_TRANS_DQ_DIRTY; + tp->t_flags &= ~(XFS_TRANS_DQ_DIRTY); + } + + ntp = xfs_trans_dup(tp); + code = xfs_trans_commit(tp, 0, NULL); + tp = ntp; + if (committed != NULL) { + *committed = 1; + } + /* + * If we get an error during the commit processing, + * release the buffer that is still held and return + * to the caller. + */ + if (code) { + xfs_buf_relse(ialloc_context); + if (dqinfo) { + tp->t_dqinfo = dqinfo; + xfs_trans_free_dqinfo(tp); + } + *tpp = ntp; + *ipp = NULL; + return code; + } + code = xfs_trans_reserve(tp, 0, log_res, 0, + XFS_TRANS_PERM_LOG_RES, log_count); + /* + * Re-attach the quota info that we detached from prev trx. + */ + if (dqinfo) { + tp->t_dqinfo = dqinfo; + tp->t_flags |= tflags; + } + + if (code) { + xfs_buf_relse(ialloc_context); + *tpp = ntp; + *ipp = NULL; + return code; + } + xfs_trans_bjoin (tp, ialloc_context); + + /* + * Call ialloc again. Since we've locked out all + * other allocations in this allocation group, + * this call should always succeed. + */ + code = xfs_ialloc(tp, dp, mode, nlink, rdev, credp, prid, + okalloc, &ialloc_context, &call_again, &ip); + + /* + * If we get an error at this point, return to the caller + * so that the current transaction can be aborted. + */ + if (code) { + *tpp = tp; + *ipp = NULL; + return code; + } + ASSERT ((!call_again) && (ip != NULL)); + + } else { + if (committed != NULL) { + *committed = 0; + } + } + + *ipp = ip; + *tpp = tp; + + return 0; +} + +/* + * Decrement the link count on an inode & log the change. + * If this causes the link count to go to zero, initiate the + * logging activity required to truncate a file. + */ +int /* error */ +xfs_droplink( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + int error; + + xfs_ichgtime(ip, XFS_ICHGTIME_CHG); + + ASSERT (ip->i_d.di_nlink > 0); + ip->i_d.di_nlink--; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + + error = 0; + if (ip->i_d.di_nlink == 0) { + /* + * We're dropping the last link to this file. + * Move the on-disk inode to the AGI unlinked list. + * From xfs_inactive() we will pull the inode from + * the list and free it. + */ + error = xfs_iunlink(tp, ip); + } + return error; +} + +/* + * This gets called when the inode's version needs to be changed from 1 to 2. + * Currently this happens when the nlink field overflows the old 16-bit value + * or when chproj is called to change the project for the first time. + * As a side effect the superblock version will also get rev'd + * to contain the NLINK bit. + */ +void +xfs_bump_ino_vers2( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + xfs_mount_t *mp; + int s; + + ASSERT(ismrlocked (&ip->i_lock, MR_UPDATE)); + ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1); + + ip->i_d.di_version = XFS_DINODE_VERSION_2; + ip->i_d.di_onlink = 0; + bzero(&(ip->i_d.di_pad[0]), sizeof(ip->i_d.di_pad)); + mp = tp->t_mountp; + if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) { + s = XFS_SB_LOCK(mp); + if (!XFS_SB_VERSION_HASNLINK(&mp->m_sb)) { + XFS_SB_VERSION_ADDNLINK(&mp->m_sb); + XFS_SB_UNLOCK(mp, s); + xfs_mod_sb(tp, XFS_SB_VERSIONNUM); + } else { + XFS_SB_UNLOCK(mp, s); + } + } + /* Caller must log the inode */ +} + +/* + * Increment the link count on an inode & log the change. + */ +int +xfs_bumplink( + xfs_trans_t *tp, + xfs_inode_t *ip) +{ + if (ip->i_d.di_nlink >= XFS_MAXLINK) + return XFS_ERROR(EMLINK); + xfs_ichgtime(ip, XFS_ICHGTIME_CHG); + + ASSERT(ip->i_d.di_nlink > 0); + ip->i_d.di_nlink++; + if ((ip->i_d.di_version == XFS_DINODE_VERSION_1) && + (ip->i_d.di_nlink > XFS_MAXLINK_1)) { + /* + * The inode has increased its number of links beyond + * what can fit in an old format inode. It now needs + * to be converted to a version 2 inode with a 32 bit + * link count. If this is the first inode in the file + * system to do this, then we need to bump the superblock + * version number as well. + */ + xfs_bump_ino_vers2(tp, ip); + } + + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + return 0; +} + +/* + * Try to truncate the given file to 0 length. Currently called + * only out of xfs_remove when it has to truncate a file to free + * up space for the remove to proceed. + */ +int +xfs_truncate_file( + xfs_mount_t *mp, + xfs_inode_t *ip) +{ + xfs_trans_t *tp; + int error; + +#ifdef QUOTADEBUG + /* + * This is called to truncate the quotainodes too. + */ + if (XFS_IS_UQUOTA_ON(mp)) { + if (ip->i_ino != mp->m_sb.sb_uquotino) + ASSERT(ip->i_udquot); + } + if (XFS_IS_GQUOTA_ON(mp)) { + if (ip->i_ino != mp->m_sb.sb_gquotino) + ASSERT(ip->i_gdquot); + } +#endif + /* + * Make the call to xfs_itruncate_start before starting the + * transaction, because we cannot make the call while we're + * in a transaction. + */ + xfs_ilock(ip, XFS_IOLOCK_EXCL); + xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, (xfs_fsize_t)0); + + tp = xfs_trans_alloc(mp, XFS_TRANS_TRUNCATE_FILE); + if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return error; + } + + /* + * Follow the normal truncate locking protocol. Since we + * hold the inode in the transaction, we know that it's number + * of references will stay constant. + */ + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ihold(tp, ip); + /* + * Signal a sync xaction. The only case where that isn't + * the case is if we're truncating an already unlinked file + * on a wsync fs. In that case, we know the blocks can't + * reappear in the file because the links to file are + * permanently toast. Currently, we're always going to + * want a sync transaction because this code is being + * called from places where nlink is guaranteed to be 1 + * but I'm leaving the tests in to protect against future + * changes -- rcc. + */ + error = xfs_itruncate_finish(&tp, ip, (xfs_fsize_t)0, + XFS_DATA_FORK, + ((ip->i_d.di_nlink != 0 || + !(mp->m_flags & XFS_MOUNT_WSYNC)) + ? 1 : 0)); + if (error) { + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT); + } else { + xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, + NULL); + } + xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + + return error; +} + +#if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) +/* + * for error injection + */ +int +xfs_get_fsinfo(int fd, char **fsname, int64_t *fsid) +{ + xfs_mount_t *mp; + int error; + + if ((error = xfs_fd_to_mp(fd, 0, &mp, 1))) + return XFS_ERROR(error); + + *fsname = mp->m_fsname; + bcopy(mp->m_fixedfsid, fsid, sizeof(fsid_t)); + + return 0; +} +#endif /* DEBUG || INDUCE_IO_ERROR */ + +/* Called by filesystems VOP_RENAME + * once it has found the source vnode to + * unlink. Note that an the VOP_RENAME + * should also call vn_pre_{remove,rmdir} if the + * target node exists (and therefore it is being removed). + */ +int +xfs_pre_rename( struct vnode *vp ) +{ + if (vp->v_flag & VISSWAP && vp->v_type == VREG) { + return EBUSY; + } + /* JIMJIM - investigate need to check if inode/dentry is mounted on */ + if (vp->v_flag & VMOUNTING) { + return EBUSY; + } + return 0; +} + +/* Called by every filesystems VOP_REMOVE + * once it has the vnode that it is going to unlink. + * Verifies generic rules about whether such an + * unlink is legal. + * Also called by VOP_RENAME if the target exists and + * therefore will be removed. + */ +int +xfs_pre_remove( struct vnode *vp ) +{ + if (vp->v_type == VDIR) { return EPERM; } + if (vp->v_flag & VISSWAP && vp->v_type == VREG) { + return EBUSY; + } + /* JIMJIM - investigate need to check if inode/dentry is mounted on */ + if (vp->v_flag & VMOUNTING) { + return EBUSY; + } + return 0; +} + +/* Called by every filesystems VOP_RMDIR + * once it has the vnode that it is going to unlink. + * Verifies generic rules about whether such an + * unlink is legal. + * + * Also called by VOP_RENAME if the target exists and + * therefore will be removed. + */ +int +xfs_pre_rmdir( struct vnode *vp ) +{ + if (vp->v_type != VDIR) { return EPERM; } + /* JIMJIM - investigate need to check if inode/dentry is mounted on */ + if (vp->v_flag & VMOUNTING) { + return EBUSY; + } + return 0; +} + +#ifdef DEBUG +int +xfs_isshutdown(bhv_desc_t *bhv) +{ + xfs_inode_t *ip = XFS_BHVTOI(bhv); + xfs_mount_t *mp = ip->i_mount; + + return XFS_FORCED_SHUTDOWN(mp) != 0; +} +#endif /* DEBUG */ diff -rNu linux-2.4.7/linux/fs/xfs/xfs_utils.h linux-2.4-xfs/linux/fs/xfs/xfs_utils.h --- linux-2.4.7/linux/fs/xfs/xfs_utils.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_utils.h Mon Jan 15 04:28:46 2001 @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_UTILS_H__ +#define __XFS_UTILS_H__ + +#define IRELE(ip) VN_RELE(XFS_ITOV(ip)) +#define IHOLD(ip) VN_HOLD(XFS_ITOV(ip)) +#define ITRACE(ip) vn_trace_ref(XFS_ITOV(ip), __FILE__, __LINE__, \ + (inst_t *)__return_address) + +#define DLF_IGET 0x01 /* get entry inode if name lookup succeeds */ +#define DLF_NODNLC 0x02 /* don't use the dnlc */ +#define DLF_LOCK_SHARED 0x04 /* directory locked shared */ + +struct bhv_desc; +struct cred; +struct pathname; +struct vnode; +struct xfs_inode; +struct xfs_mount; +struct xfs_trans; + +extern int +xfs_rename( + struct bhv_desc *src_dir_bdp, + char *src_name, + struct vnode *target_dir_vp, + char *target_name, + struct pathname *target_pnp, + struct cred *credp); + +extern int +xfs_link( + bhv_desc_t *target_dir_bdp, + struct vnode *src_vp, + char *target_name, + struct cred *credp); + +#ifdef CELL_CAPABLE +extern int +cxfs_rename( + struct bhv_desc *src_dir_bdp, + char *src_name, + struct vnode *target_dir_vp, + char *target_name, + struct pathname *target_pnp, + struct cred *credp); + +extern int +cxfs_link( + bhv_desc_t *target_dir_bdp, + struct vnode *src_vp, + char *target_name, + struct cred *credp); + +#endif /* CELL_CAPABLE */ + +extern int +xfs_dir_lookup_int( + struct xfs_trans *tp, + struct bhv_desc *dir_bdp, + int flags, + char *name, + struct pathname *pnp, + xfs_ino_t *inum, + struct xfs_inode **ipp, + uint *dir_unlocked); + +extern int +xfs_truncate_file( + struct xfs_mount *mp, + struct xfs_inode *ip); + +extern int +xfs_dir_ialloc( + struct xfs_trans **tpp, + struct xfs_inode *dp, + mode_t mode, + nlink_t nlink, + dev_t rdev, + struct cred *credp, + prid_t prid, + int okalloc, + struct xfs_inode **ipp, + int *committed); + +extern int +xfs_stickytest( + struct xfs_inode *dp, + struct xfs_inode *ip, + struct cred *cr); + +extern int +xfs_droplink( + struct xfs_trans *tp, + struct xfs_inode *ip); + +extern int +xfs_bumplink( + struct xfs_trans *tp, + struct xfs_inode *ip); + +extern void +xfs_bump_ino_vers2( + struct xfs_trans *tp, + struct xfs_inode *ip); + +#if defined(DEBUG) || defined(INDUCE_IO_ERROR) +extern int +xfs_get_fsinfo( + int fd, + char **fsname, + int64_t *fsid); +#endif + +extern int +xfs_mk_sharedro( + int fd); + +extern int +xfs_clear_sharedro( + int fd); + +extern int xfs_pre_rename(struct vnode *vp); +extern int xfs_pre_remove(struct vnode *vp); +extern int xfs_pre_rmdir(struct vnode *vp); + + +#ifdef DEBUG +extern int +xfs_isshutdown( + struct bhv_desc *bhv); +#endif + +#endif /* XFS_UTILS_H */ + diff -rNu linux-2.4.7/linux/fs/xfs/xfs_vfsops.c linux-2.4-xfs/linux/fs/xfs/xfs_vfsops.c --- linux-2.4.7/linux/fs/xfs/xfs_vfsops.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_vfsops.c Mon Jul 2 17:36:00 2001 @@ -0,0 +1,2036 @@ +/* + * XFS filesystem operations. + * + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +#define NONROOT_MOUNT ROOT_UNMOUNT +#define whymount_t whymountroot_t +static char *whymount[] = { "initial mount", "remount", "unmount" }; + +STATIC xfs_mount_t *xfs_get_vfsmount(vfs_t *, dev_t, dev_t, dev_t); +STATIC int xfs_ibusy(xfs_mount_t *); +STATIC int xfs_sync(bhv_desc_t *, int, cred_t *); +STATIC int xfs_unmount(bhv_desc_t *, int, cred_t *); + +/* + * xfs_init + * + * This is called through the vfs switch at system initialization + * to initialize any global state associated with XFS. All we + * need to do currently is save the type given to XFS in xfs_fstype. + * + * vswp -- pointer to the XFS entry in the vfs switch table + * fstype -- index of XFS in the vfs switch table used as the XFS fs type. + */ +/* ARGSUSED */ +int +xfs_init(int fstype) +{ + extern xfs_zone_t *xfs_da_state_zone; + extern xfs_zone_t *xfs_bmap_free_item_zone; + extern xfs_zone_t *xfs_btree_cur_zone; + extern xfs_zone_t *xfs_inode_zone; + extern xfs_zone_t *xfs_chashlist_zone; + extern xfs_zone_t *xfs_trans_zone; + extern xfs_zone_t *xfs_buf_item_zone; + extern xfs_zone_t *xfs_efd_zone; + extern xfs_zone_t *xfs_efi_zone; + extern xfs_zone_t *xfs_dabuf_zone; + extern mutex_t xfs_uuidtabmon; + extern mutex_t xfs_Gqm_lock; +#ifdef DEBUG_NOT + extern ktrace_t *xfs_alloc_trace_buf; + extern ktrace_t *xfs_bmap_trace_buf; + extern ktrace_t *xfs_bmbt_trace_buf; + extern ktrace_t *xfs_dir_trace_buf; + extern ktrace_t *xfs_attr_trace_buf; + extern ktrace_t *xfs_dir2_trace_buf; +#endif /* DEBUG */ +#ifdef XFS_DABUF_DEBUG + extern lock_t xfs_dabuf_global_lock; +#endif + extern int xfs_refcache_size; + + xfs_fstype = fstype; + +#ifdef XFS_DABUF_DEBUG + spinlock_init(&xfs_dabuf_global_lock, "xfsda"); +#endif + mutex_init(&xfs_uuidtabmon, MUTEX_DEFAULT, "xfs_uuidtab"); + mutex_init(&xfs_Gqm_lock, MUTEX_DEFAULT, "xfs_qmlock"); + ndquot = DQUOT_MAX_HEURISTIC; + + /* + * Initialize all of the zone allocators we use. + */ + xfs_bmap_free_item_zone = kmem_zone_init(sizeof(xfs_bmap_free_item_t), + "xfs_bmap_free_item"); + xfs_btree_cur_zone = kmem_zone_init(sizeof(xfs_btree_cur_t), + "xfs_btree_cur"); + xfs_inode_zone = kmem_zone_init(sizeof(xfs_inode_t), "xfs_inode"); + xfs_trans_zone = kmem_zone_init(sizeof(xfs_trans_t), "xfs_trans"); + xfs_da_state_zone = + kmem_zone_init(sizeof(xfs_da_state_t), "xfs_da_state"); + xfs_dabuf_zone = kmem_zone_init(sizeof(xfs_dabuf_t), "xfs_dabuf"); + + /* + * The size of the zone allocated buf log item is the maximum + * size possible under XFS. This wastes a little bit of memory, + * but it is much faster. + */ + xfs_buf_item_zone = + kmem_zone_init((sizeof(xfs_buf_log_item_t) + + (((XFS_MAX_BLOCKSIZE / XFS_BLI_CHUNK) / + NBWORD) * sizeof(int))), + "xfs_buf_item"); + xfs_efd_zone = kmem_zone_init((sizeof(xfs_efd_log_item_t) + + (15 * sizeof(xfs_extent_t))), + "xfs_efd_item"); + xfs_efi_zone = kmem_zone_init((sizeof(xfs_efi_log_item_t) + + (15 * sizeof(xfs_extent_t))), + "xfs_efi_item"); + xfs_ifork_zone = kmem_zone_init(sizeof(xfs_ifork_t), "xfs_ifork"); + xfs_ili_zone = kmem_zone_init(sizeof(xfs_inode_log_item_t), "xfs_ili"); + xfs_chashlist_zone = kmem_zone_init(sizeof(xfs_chashlist_t), + "xfs_chashlist"); + +#ifdef CONFIG_XFS_VNODE_TRACING + ktrace_init(VNODE_TRACE_SIZE); +#else +#ifdef DEBUG + ktrace_init(64); +#endif +#endif + + /* + * Allocate global trace buffers. + */ +#ifdef XFS_ALLOC_TRACE + xfs_alloc_trace_buf = ktrace_alloc(XFS_ALLOC_TRACE_SIZE, KM_SLEEP); +#endif +#ifdef XFS_BMAP_TRACE + xfs_bmap_trace_buf = ktrace_alloc(XFS_BMAP_TRACE_SIZE, KM_SLEEP); +#endif +#ifdef XFS_BMBT_TRACE + xfs_bmbt_trace_buf = ktrace_alloc(XFS_BMBT_TRACE_SIZE, KM_SLEEP); +#endif +#ifdef XFS_DIR_TRACE + xfs_dir_trace_buf = ktrace_alloc(XFS_DIR_TRACE_SIZE, KM_SLEEP); +#endif +#ifdef XFS_ATTR_TRACE + xfs_attr_trace_buf = ktrace_alloc(XFS_ATTR_TRACE_SIZE, KM_SLEEP); +#endif +#ifdef XFS_DIR2_TRACE + xfs_dir2_trace_buf = ktrace_alloc(XFS_DIR2_GTRACE_SIZE, KM_SLEEP); +#endif + + xfs_dir_startup(); + +#ifdef CELL_CAPABLE + /* + * Special initialization for cxfs + */ + cxfs_arrinit(); +#endif + +#if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) + xfs_error_test_init(); +#endif /* DEBUG || INDUCE_IO_ERROR */ + + xfs_init_procfs(); + + xfs_refcache_size = 512; + + /* + * The inode hash table is created on a per mounted + * file system bases. + */ + + return 0; +} + +/* + * xfs_fill_buftarg + * + * Put the "appropriate" things in a buftarg_t structure. + */ +STATIC +void +xfs_fill_buftarg(buftarg_t *btp, dev_t dev, struct super_block *sb) +{ + btp->pb_targ = pagebuf_lock_enable(dev, sb); + btp->dev = dev; +} + +void +xfs_cleanup(void) +{ + extern xfs_zone_t *xfs_bmap_free_item_zone; + extern xfs_zone_t *xfs_btree_cur_zone; + extern xfs_zone_t *xfs_inode_zone; + extern xfs_zone_t *xfs_trans_zone; + extern xfs_zone_t *xfs_da_state_zone; + extern xfs_zone_t *xfs_dabuf_zone; + extern xfs_zone_t *xfs_efd_zone; + extern xfs_zone_t *xfs_efi_zone; + extern xfs_zone_t *xfs_buf_item_zone; + extern xfs_zone_t *xfs_chashlist_zone; + extern xfs_zone_t *qm_dqzone; + extern xfs_zone_t *qm_dqtrxzone; + + xfs_cleanup_procfs(); + kmem_cache_destroy(xfs_bmap_free_item_zone); + kmem_cache_destroy(xfs_btree_cur_zone); + kmem_cache_destroy(xfs_inode_zone); + kmem_cache_destroy(xfs_trans_zone); + kmem_cache_destroy(xfs_da_state_zone); + kmem_cache_destroy(xfs_dabuf_zone); + kmem_cache_destroy(xfs_buf_item_zone); + kmem_cache_destroy(xfs_efd_zone); + kmem_cache_destroy(xfs_efi_zone); + kmem_cache_destroy(xfs_ifork_zone); + kmem_cache_destroy(xfs_ili_zone); + kmem_cache_destroy(xfs_chashlist_zone); + if (qm_dqzone) + kmem_cache_destroy(qm_dqzone); + if (qm_dqtrxzone) + kmem_cache_destroy(qm_dqtrxzone); +#if (defined(DEBUG) || defined(CONFIG_XFS_VNODE_TRACING)) + ktrace_uninit(); +#endif +} + +/* + * xfs_cmountfs + * + * This function is the common mount file system function for XFS. + */ +STATIC int +xfs_cmountfs( + vfs_t *vfsp, + dev_t ddev, + dev_t logdev, + dev_t rtdev, + whymount_t why, + struct xfs_args *ap, + struct mounta *args, + struct cred *cr) +{ + xfs_mount_t *mp; + int error = 0; + int vfs_flags; +/* size_t n; */ +/* char *tmp_fsname_buffer; */ + int client = 0; + + /* + * The new use of remount to update various cxfs parameters + * should of already been picked of before this. If anything + * has gotten by, it shouldn't have. + */ + ASSERT((vfsp->vfs_flag & VFS_REMOUNT) == 0); + if (vfsp->vfs_flag & VFS_REMOUNT) + return 0; + + mp = xfs_get_vfsmount(vfsp, ddev, logdev, rtdev); + + /* + * Open the data and real time devices now. + */ + + vfs_flags = (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE; + xfs_fill_buftarg(&mp->m_ddev_targ, ddev, vfsp->vfs_super); + if (logdev != ddev) { + xfs_fill_buftarg(&mp->m_logdev_targ, logdev, vfsp->vfs_super); + } + if (rtdev != 0) { + xfs_fill_buftarg(&mp->m_rtdev_targ, rtdev, vfsp->vfs_super); + } + mp->m_ddev_targp = &mp->m_ddev_targ; + + /* Values are in BBs */ + if ((ap != NULL) && (ap->version >= 2) && + (ap->flags & XFSMNT_NOALIGN) != XFSMNT_NOALIGN) { + /* + * At this point the superblock has not been read + * in, therefore we do not know the block size. + * Before, the mount call ends we will convert + * these to FSBs. + */ + mp->m_dalign = ap->sunit; + mp->m_swidth = ap->swidth; + } else { + mp->m_dalign = 0; + mp->m_swidth = 0; + } + if (logdev != 0) { + if (logdev == ddev) { + mp->m_logdev_targ = mp->m_ddev_targ; + } else { + /* Ensure that logdev isn't already mounted */ + if (vfs_devsearch(logdev, VFS_FSTYPE_ANY) != NULL) { + error = XFS_ERROR(EBUSY); + goto error3; + } + + /* Set the log device's block size */ + set_blocksize(logdev, 512); + } + if (ap != NULL && ap->version != 0) { + /* Called through the mount system call */ + if ((ap->version < 1) || (ap->version > 4)) { + error = XFS_ERROR(EINVAL); + goto error3; + } + if (ap->logbufs != 0 && + ap->logbufs != -1 && + (ap->logbufs < 2 || ap->logbufs > 8)) { + cmn_err(CE_WARN, + "xfs: invalid logbufs value"); + error = XFS_ERROR(EINVAL); + goto error3; + } + mp->m_logbufs = ap->logbufs; + if (ap->logbufsize != -1 && + ap->logbufsize != 16 * 1024 && + ap->logbufsize != 32 * 1024) { + cmn_err(CE_WARN, "xfs: invalid logbufsize"); + error = XFS_ERROR(EINVAL); + goto error3; + } + mp->m_logbsize = ap->logbufsize; + mp->m_fsname_len = strlen(args->spec) + 1; + mp->m_fsname = kmem_alloc(mp->m_fsname_len, KM_SLEEP); + strcpy(mp->m_fsname, args->spec); + } else { + /* + * Called through vfs_mountroot/xfs_mountroot. + * Or, called by mount with no args structure. + * In this case use the dev number (in hex) for + * the filesystem name. + */ + mp->m_logbufs = -1; + mp->m_logbsize = -1; + mp->m_fsname_len = ap ? 11 : 2; + mp->m_fsname = kmem_alloc(mp->m_fsname_len, KM_SLEEP); + if (ap) + sprintf(mp->m_fsname, "0x%x", ddev); + else + strcpy(mp->m_fsname, "/"); + } + } + if (rtdev != 0) { + if (rtdev == ddev || rtdev == logdev) { + cmn_err(CE_WARN, "XFS: Cannot mount filesystem with identical rtdev and logdev."); + error = XFS_ERROR(EINVAL); + goto error3; + } else { + /* Ensure that rtdev isn't already mounted */ + if (vfs_devsearch(rtdev, VFS_FSTYPE_ANY) != NULL) { + error = XFS_ERROR(EBUSY); + goto error3; + } + + /* Set the realtime device's block size */ + set_blocksize(rtdev, 512); + } + } + /* + * Pull in the 'wsync' and 'ino64' mount options before we do the real + * work of mounting and recovery. The arg pointer will + * be NULL when we are being called from the root mount code. + */ +#if XFS_BIG_FILESYSTEMS + mp->m_inoadd = 0; +#endif + if (ap != NULL) { + if (ap->flags & XFSMNT_WSYNC) + mp->m_flags |= XFS_MOUNT_WSYNC; +#if XFS_BIG_FILESYSTEMS + if (ap->flags & XFSMNT_INO64) { + mp->m_flags |= XFS_MOUNT_INO64; + mp->m_inoadd = XFS_INO64_OFFSET; + } +#endif + if (ap->flags & XFSMNT_NOATIME) + mp->m_flags |= XFS_MOUNT_NOATIME; + + if (ap->flags & (XFSMNT_UQUOTA | XFSMNT_GQUOTA | + XFSMNT_QUOTAMAYBE)) + xfs_qm_mount_quotainit(mp, ap->flags); + + if (ap->flags & XFSMNT_RETERR) + mp->m_flags |= XFS_MOUNT_RETERR; + + if (ap->flags & XFSMNT_NOALIGN) + mp->m_flags |= XFS_MOUNT_NOALIGN; + + if (ap->flags & XFSMNT_OSYNCISDSYNC) + mp->m_flags |= XFS_MOUNT_OSYNCISDSYNC; + + if (ap->flags & XFSMNT_IOSIZE) { + if (ap->version < 3 || + ap->iosizelog > XFS_MAX_IO_LOG || + ap->iosizelog < XFS_MIN_IO_LOG) { + cmn_err(CE_WARN, "xfs: invalid log iosize"); + error = XFS_ERROR(EINVAL); + goto error3; + } + + mp->m_flags |= XFS_MOUNT_DFLT_IOSIZE; + mp->m_readio_log = mp->m_writeio_log = ap->iosizelog; + } + + /* + * no recovery flag requires a read-only mount + */ + if (ap->flags & XFSMNT_NORECOVERY) { + if (!(vfsp->vfs_flag & VFS_RDONLY)) { + cmn_err(CE_WARN, "xfs: tried to mount a FS read-write without recovery!"); + error = XFS_ERROR(EINVAL); + goto error3; + } + mp->m_flags |= XFS_MOUNT_NORECOVERY; + } + + if (ap->flags & XFSMNT_NOUUID) + mp->m_flags |= XFS_MOUNT_NOUUID; + } + + /* + * read in superblock to check read-only flags and shared + * mount status + */ + if ((error = xfs_readsb(mp, ddev))) { + goto error3; + } + + /* + * prohibit r/w mounts of read-only filesystems + */ + if (mp->m_sb.sb_flags & XFS_SBF_READONLY && + !(vfsp->vfs_flag & VFS_RDONLY)) { + cmn_err(CE_WARN, "xfs: cannot mount a read-only filesystem as read-write"); + error = XFS_ERROR(EROFS); + xfs_freesb(mp); + goto error3; + } + + /* + * check for shared mount. + */ + if (ap && ap->flags & XFSMNT_SHARED) { + if (!XFS_SB_VERSION_HASSHARED(&mp->m_sb)) { + error = XFS_ERROR(EINVAL); + xfs_freesb(mp); + goto error3; + } + + /* + * For IRIX 6.5, shared mounts must have the shared + * version bit set, have the persistent readonly + * field set, must be version 0 and can only be mounted + * read-only. + */ + if (!(vfsp->vfs_flag & VFS_RDONLY) || + !(mp->m_sb.sb_flags & XFS_SBF_READONLY) || + mp->m_sb.sb_shared_vn != 0) { + error = XFS_ERROR(EINVAL); + xfs_freesb(mp); + goto error3; + } + + mp->m_flags |= XFS_MOUNT_SHARED; + + /* + * Shared XFS V0 can't deal with DMI. Return EINVAL. + */ +#if 0 + if (mp->m_sb.sb_shared_vn == 0 && (args->flags & MS_DMI)) { +#else + if (mp->m_sb.sb_shared_vn == 0 && (ap->flags & XFSMNT_DMAPI)) { +#endif + error = XFS_ERROR(EINVAL); + xfs_freesb(mp); + goto error3; + } + } + + /* Default to local- cxfs_arrmount will change this if necessary. */ + mp->m_cxfstype = XFS_CXFS_NOT; + +#ifdef CELL_CAPABLE + error = cxfs_mount(mp, ap, ddev, &client); +#endif + if (error) { + goto error3; + } + + if (client == 0) { + if ((error = xfs_mountfs(vfsp, mp, ddev, 0))) { +#ifdef DEBUG + cmn_err(CE_WARN, "xfs: xfs_mountfs failed: error %d.", + error); +#endif + goto error3; + } + } + + return error; + + /* + * Be careful not to clobber the value of 'error' here. + */ + error3: + /* It's impossible to get here before buftargs are filled */ + xfs_binval(mp->m_ddev_targ); + linvfs_release_target(mp->m_ddev_targ.pb_targ); + if (logdev && logdev != ddev) { + xfs_binval(mp->m_logdev_targ); + linvfs_release_target(mp->m_logdev_targ.pb_targ); + } + if (rtdev != 0) { + xfs_binval(mp->m_rtdev_targ); + linvfs_release_target(mp->m_rtdev_targ.pb_targ); + } + if (error) { +#ifdef CELL_CAPABLE + cxfs_unmount(mp); +#endif + xfs_mount_free(mp, 1); + } + return error; +} + + +/* + * xfs_get_vfsmount() ensures that the given vfs struct has an + * associated mount struct. If a mount struct doesn't exist, as + * is the case during the initial mount, a mount structure is + * created and initialized. + */ +STATIC xfs_mount_t * +xfs_get_vfsmount( + vfs_t *vfsp, + dev_t ddev, + dev_t logdev, + dev_t rtdev) +{ + xfs_mount_t *mp; + + /* + * Allocate VFS private data (xfs mount structure). + */ + mp = xfs_mount_init(); + mp->m_dev = ddev; + mp->m_logdev = logdev; + mp->m_rtdev = rtdev; + + vfsp->vfs_flag |= VFS_NOTRUNC|VFS_LOCAL; + /* vfsp->vfs_bsize filled in later from superblock */ + vfsp->vfs_fstype = xfs_fstype; + vfs_insertbhv(vfsp, &mp->m_bhv, &xfs_vfsops, mp); + vfsp->vfs_dev = ddev; + /* vfsp->vfs_fsid is filled in later from superblock */ + + return mp; +} + +/* + * xfs_mountargs -- Copy in xfs mount arguments + * + * Does the intialization and copying of xfs mount arguments taking account + * of the various xfs argument versions and abi's. + * + * The value returned is an error code. + */ +int +xfs_mountargs( + struct mounta *uap, + struct xfs_args *ap) +{ + bzero(ap, sizeof (struct xfs_args)); + ap->slcount = -1; + ap->stimeout = -1; + ap->ctimeout = -1; + + if (uap->datalen && uap->dataptr) { + + /* Copy in the xfs_args version number */ + memcpy(ap, uap->dataptr, sizeof(ap->version)); + + if (ap->version != 3) { + return XFS_ERROR(EINVAL); + } + memcpy(ap, uap->dataptr, sizeof(struct xfs_args_ver_3)); + } + + ap->fsname = uap->spec; + + return (0); +} + +/* + * xfs_mount + * + * The file system configurations are: + * (1) device (partition) with data and internal log + * (2) logical volume with data and log subvolumes. + * (3) logical volume with data, log, and realtime subvolumes. + * + */ +STATIC int +xfs_mount( + vfs_t *vfsp, + vnode_t *mvp, + struct mounta *uap, + cred_t *credp) +{ + struct xfs_args args; /* xfs mount arguments */ + dev_t ddev; + dev_t logdev; + dev_t rtdev; + int error; + + if (mvp->v_type != VDIR) + return XFS_ERROR(ENOTDIR); + + if ( ((uap->flags & MS_REMOUNT) == 0) + && ((vn_count(mvp) != 1) || (mvp->v_flag & VROOT)) ) + return XFS_ERROR(EBUSY); + + /* + * Copy in XFS-specific arguments. + */ + error = xfs_mountargs(uap, &args); + if (error) + return (error); + + if ((error = spectodevs(vfsp->vfs_super, &args, &ddev, &logdev, &rtdev))) + return error; + + error = xfs_cmountfs(vfsp, ddev, logdev, rtdev, NONROOT_MOUNT, + &args, uap, credp); + return error; + +} + + +/* VFS_MOUNT */ +/*ARGSUSED*/ +STATIC int +xfs_vfsmount( + vfs_t *vfsp, + vnode_t *mvp, + struct mounta *uap, + char *attrs, + cred_t *credp) +{ + int error; + + vfs_lock(vfsp); + error = xfs_mount(vfsp, mvp, uap, credp); + vfs_unlock(vfsp); + return (error); +} + + +/* + * xfs_mountroot() mounts the root file system. + * + * This function is called by vfs_mountroot(), which is called my main(). + * Must check that the root device has a XFS superblock and as such a + * XFS file system. If the device does not, reject the mountroot request + * and return error so that vfs_mountroot() knows to continue its search + * for someone able to mount root. + * + * "why" is: + * ROOT_INIT initial call. + * ROOT_REMOUNT remount the root file system. + * ROOT_UNMOUNT unmounting the root (e.g., as part a system shutdown). + */ +STATIC int +xfs_mountroot( + vfs_t *vfsp, + bhv_desc_t *bdp, + enum whymountroot why) +{ + int error; + static int xfsrootdone; + struct cred *cr = get_current_cred(); + dev_t ddev, logdev, rtdev; + xfs_mount_t *mp; + xfs_buf_t *bp; + + /* + * Check that the root device holds an XFS file system. + * + * If the device is an XLV volume, cannot check for an + * XFS superblock because the device is not yet open. + if ((why == ROOT_INIT) && + (MAJOR(rootdev) != XLV_MAJOR) && + (xfs_isdev(rootdev))) { + return XFS_ERROR(ENOSYS); + } + */ + + switch (why) { + case ROOT_INIT: + if (xfsrootdone++) + return XFS_ERROR(EBUSY); + + if (rootdev == NODEV) + return XFS_ERROR(ENODEV); + + vfsp->vfs_dev = rootdev; + break; + + case ROOT_REMOUNT: + vfs_setflag(vfsp, VFS_REMOUNT); + break; + + case ROOT_UNMOUNT: + mp = XFS_BHVTOM(bdp); + if (xfs_ibusy(mp)) { + XFS_bflush(mp->m_ddev_targ); + /* + * There are still busy vnodes in the file system. + * Flush what we can and then get out without + * unmounting cleanly. This will force recovery + * to run when we reboot. We return an error + * even though nobody looks at it since we're + * going down. + * + * It turns out that we always take this path, + * because init and the uadmin command still have + * files open when we get here. We just try to + * flush everything so that we'll be clean + * anyway. + * + * First try the inodes. xfs_sync() will try to + * flush even those inodes which are currently + * being referenced. xfs_iflush_all() will purge + * and flush all the unreferenced vnodes. + */ + xfs_sync(bdp, + (SYNC_WAIT | SYNC_CLOSE | + SYNC_ATTR | SYNC_FSDATA), + cr); + xfs_iflush_all(mp, XFS_FLUSH_ALL); + if (mp->m_quotainfo) { + xfs_qm_dqrele_all_inodes(mp, + XFS_UQUOTA_ACCT | + XFS_GQUOTA_ACCT); + xfs_qm_dqpurge_all(mp, + XFS_QMOPT_UQUOTA| + XFS_QMOPT_GQUOTA| + XFS_QMOPT_UMOUNTING); + } + /* + * Force the log to unpin as many buffers as + * possible and then sync them out. + */ + xfs_log_force(mp, (xfs_lsn_t)0, + XFS_LOG_FORCE | XFS_LOG_SYNC); + xfs_binval(mp->m_ddev_targ); + if (mp->m_rtdev != NODEV) { + xfs_binval(mp->m_rtdev_targ); + } + + /* + * Force the log again to sync out any changes + * caused by any delayed allocation buffers just + * getting flushed out now. Even though it seems + * silly, flush the file system device again so that + * any meta-data in the log gets flushed. + */ + xfs_log_force(mp, (xfs_lsn_t)0, + XFS_LOG_FORCE | XFS_LOG_SYNC); + xfs_binval(mp->m_ddev_targ); + + /* + * Finally, try to flush out the superblock. If + * it is pinned at this point we can't, because + * we don't want to get stuck waiting for it to + * be unpinned. It should be unpinned normally + * because of the log flushes above. + */ + bp = xfs_getsb(mp, 0); + if (!(XFS_BUF_ISPINNED(bp))) { + XFS_BUF_UNDONE(bp); + XFS_BUF_UNREAD(bp); + XFS_BUF_WRITE(bp); + ASSERT(mp->m_dev == XFS_BUF_TARGET(bp)); + xfsbdstrat(mp, bp); + (void) xfs_iowait(bp); + } + return XFS_ERROR(EBUSY); + } + error = xfs_unmount(bdp, 0, NULL); + return error; + } + error = vfs_lock(vfsp); + if (error) { + goto bad; + } + + ddev = logdev = rootdev; + rtdev = 0; + + ASSERT(ddev && logdev); + + error = xfs_cmountfs(vfsp, ddev, logdev, rtdev, why, NULL, NULL, cr); + + if (error) { + vfs_unlock(vfsp); + goto bad; + } + vfs_unlock(vfsp); + return(0); +bad: + cmn_err(CE_WARN, "%s of root device %V failed with errno %d\n", + whymount[why], rootdev, error); + return error; +} + + +/* VFS_ROOTINIT */ +STATIC int +xfs_rootinit( + vfs_t *vfsp) +{ + return(xfs_mountroot(vfsp, NULL, ROOT_INIT)); +} + +/* VFS_MOUNTROOT */ +STATIC int +xfs_vfsmountroot( + bhv_desc_t *bdp, + enum whymountroot why) +{ + return(xfs_mountroot(bhvtovfs(bdp), bdp, why)); +} + +/* + * xfs_ibusy searches for a busy inode in the mounted file system. + * + * Return 0 if there are no active inodes otherwise return 1. + */ +STATIC int +xfs_ibusy( + xfs_mount_t *mp) +{ + xfs_inode_t *ip; + vnode_t *vp; + int busy; + + busy = 0; + + XFS_MOUNT_ILOCK(mp); + + ip = mp->m_inodes; + if (ip == NULL) { + XFS_MOUNT_IUNLOCK(mp); + return busy; + } + + do { + /* Skip markers inserted by xfs_sync */ + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } + + vp = XFS_ITOV_NULL(ip); + + if (vp && vn_count(vp) != 0) { + if (xfs_ibusy_check(ip, vn_count(vp)) == 0) { + ip = ip->i_mnext; + continue; + } +#ifdef DEBUG + printk("busy vp=0x%p ip=0x%p inum %Ld count=%d\n", + vp, ip, ip->i_ino, vn_count(vp)); +#endif + busy++; + } + ip = ip->i_mnext; + } while ((ip != mp->m_inodes) && !busy); + + XFS_MOUNT_IUNLOCK(mp); + + return busy; +} + + +/*ARGSUSED*/ +STATIC int +xfs_unmount( + bhv_desc_t *bdp, + int flags, + cred_t *credp) +{ + xfs_mount_t *mp; + xfs_inode_t *rip; + vnode_t *rvp = 0; + int vfs_flags; + struct vfs *vfsp = bhvtovfs(bdp); + int unmount_event_wanted = 0; + int unmount_event_flags = 0; + int xfs_unmountfs_needed = 0; + int error; + + mp = XFS_BHVTOM(bdp); + rip = mp->m_rootip; + rvp = XFS_ITOV(rip); + + if (vfsp->vfs_flag & VFS_DMI) { + bhv_desc_t *rbdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(rvp), &xfs_vnodeops); + + error = dm_send_namesp_event(DM_EVENT_PREUNMOUNT, + rbdp, DM_RIGHT_NULL, rbdp, DM_RIGHT_NULL, + NULL, NULL, 0, 0, + (mp->m_dmevmask & (1 << DM_EVENT_PREUNMOUNT)) != 0 ? + 0:DM_FLAGS_UNWANTED); + if (error) + return XFS_ERROR(error); + unmount_event_wanted = 1; + unmount_event_flags = (mp->m_dmevmask & (1 << DM_EVENT_UNMOUNT)) != 0 ? + 0 : DM_FLAGS_UNWANTED; + } + + /* + * First blow any referenced inode from this file system + * out of the reference cache. + */ + xfs_refcache_purge_mp(mp); + + + /* + * Make sure there are no active users. + */ + if (xfs_ibusy(mp)) { + error = XFS_ERROR(EBUSY); + printk("xfs_unmount: xfs_ibusy says error/%d\n", error); + goto out; + } + + XFS_bflush(mp->m_ddev_targ); + error = xfs_unmount_flush(mp, 0); + if (error) + goto out; + + ASSERT(vn_count(rvp) == 1); + + /* + * Drop the reference count, and then + * run the vnode through vn_remove. + */ + rvp->v_flag |= VPURGE; /* OK for vn_purge */ + VN_RELE(rvp); + + vn_remove(rvp); + + /* + * If we're forcing a shutdown, typically because of a media error, + * we want to make sure we invalidate dirty pages that belong to + * referenced vnodes as well. + */ + if (XFS_FORCED_SHUTDOWN(mp)) { + error = xfs_sync(&mp->m_bhv, + (SYNC_WAIT | SYNC_CLOSE), credp); + ASSERT(error != EFSCORRUPTED); + } + xfs_unmountfs_needed = 1; + +out: + /* Send DMAPI event, if required. + * Then do xfs_unmountfs() if needed. + * Then return error (or zero). + */ + if (unmount_event_wanted) { + /* Note: mp structure must still exist for + * dm_send_unmount_event() call. + */ + dm_send_unmount_event(vfsp, error == 0 ? rvp : NULL, + DM_RIGHT_NULL, 0, error, unmount_event_flags); + } + if (xfs_unmountfs_needed) { + /* + * Call common unmount function to flush to disk + * and free the super block buffer & mount structures. + */ + vfs_flags = (vfsp->vfs_flag & VFS_RDONLY) ? FREAD : FREAD|FWRITE; + xfs_unmountfs(mp, vfs_flags, credp); + } + + return XFS_ERROR(error); + +} + +/* + * xfs_unmount_flush implements a set of flush operation on special + * inodes, which are needed as a separate set of operations so that + * they can be called as part of relocation process. + */ +int +xfs_unmount_flush( + xfs_mount_t *mp, /* Mount structure we are getting + rid of. */ + int relocation) /* Called from vfs relocation. */ +{ + xfs_inode_t *rip = mp->m_rootip; + xfs_inode_t *rbmip; + xfs_inode_t *rsumip=NULL; + vnode_t *rvp = XFS_ITOV(rip); + int error; + + xfs_ilock(rip, XFS_ILOCK_EXCL); + xfs_iflock(rip); + + /* + * Flush out the real time inodes. + */ + if ((rbmip = mp->m_rbmip) != NULL) { + xfs_ilock(rbmip, XFS_ILOCK_EXCL); + xfs_iflock(rbmip); + error = xfs_iflush(rbmip, XFS_IFLUSH_SYNC); + xfs_iunlock(rbmip, XFS_ILOCK_EXCL); + + if (error == EFSCORRUPTED) + goto fscorrupt_out; + + ASSERT(vn_count(XFS_ITOV(rbmip)) == 1); + + rsumip = mp->m_rsumip; + xfs_ilock(rsumip, XFS_ILOCK_EXCL); + xfs_iflock(rsumip); + error = xfs_iflush(rsumip, XFS_IFLUSH_SYNC); + xfs_iunlock(rsumip, XFS_ILOCK_EXCL); + + if (error == EFSCORRUPTED) + goto fscorrupt_out; + + ASSERT(vn_count(XFS_ITOV(rsumip)) == 1); + } + + /* + * synchronously flush root inode to disk + */ + error = xfs_iflush(rip, XFS_IFLUSH_SYNC); + + if (error == EFSCORRUPTED) + goto fscorrupt_out2; + + if (vn_count(rvp) != 1 && !relocation) { + xfs_iunlock(rip, XFS_ILOCK_EXCL); + error = XFS_ERROR(EBUSY); + return (error); + } + /* + * Release dquot that rootinode, rbmino and rsumino might be holding, + * flush and purge the quota inodes. + */ + error = xfs_qm_unmount_quotas(mp); + if (error == EFSCORRUPTED) + goto fscorrupt_out2; + + if (rbmip) { + VN_RELE(XFS_ITOV(rbmip)); + VN_RELE(XFS_ITOV(rsumip)); + } + + xfs_iunlock(rip, XFS_ILOCK_EXCL); + return (0); + +fscorrupt_out: + xfs_ifunlock(rip); + +fscorrupt_out2: + xfs_iunlock(rip, XFS_ILOCK_EXCL); + + error = XFS_ERROR(EFSCORRUPTED); + return (error); +} + +/* + * xfs_root extracts the root vnode from a vfs. + * This function is called by traverse() and vfs_mountroot() + * when crossing a mount point. + * + * vfsp -- the vfs struct for the desired file system + * vpp -- address of the caller's vnode pointer which should be + * set to the desired fs root vnode + */ +STATIC int +xfs_root( + bhv_desc_t *bdp, + vnode_t **vpp) +{ + vnode_t *vp; + + vp = XFS_ITOV((XFS_BHVTOM(bdp))->m_rootip); + VN_HOLD(vp); + *vpp = vp; + + return 0; +} + +/* + * xfs_statvfs + * + * Fill in the statvfs structure for the given file system. We use + * the superblock lock in the mount structure to ensure a consistent + * snapshot of the counters returned. + */ +STATIC int +xfs_statvfs( + bhv_desc_t *bdp, + statvfs_t *statp, + vnode_t *vp) +{ + __uint64_t fakeinos; + xfs_extlen_t lsize; + xfs_mount_t *mp; + xfs_sb_t *sbp; + int s; + + mp = XFS_BHVTOM(bdp); + sbp = &(mp->m_sb); + + s = XFS_SB_LOCK(mp); + statp->f_bsize = sbp->sb_blocksize; + statp->f_frsize = sbp->sb_blocksize; + lsize = sbp->sb_logstart ? sbp->sb_logblocks : 0; + statp->f_blocks = sbp->sb_dblocks - lsize; + statp->f_bfree = statp->f_bavail = sbp->sb_fdblocks; + fakeinos = statp->f_bfree << sbp->sb_inopblog; +#if XFS_BIG_FILESYSTEMS + fakeinos += mp->m_inoadd; +#endif + statp->f_files = MIN(sbp->sb_icount + fakeinos, XFS_MAXINUMBER); + if (mp->m_maxicount) +#if XFS_BIG_FILESYSTEMS + if (!mp->m_inoadd) +#endif + statp->f_files = MIN(statp->f_files, mp->m_maxicount); + statp->f_ffree = statp->f_favail = + statp->f_files - (sbp->sb_icount - sbp->sb_ifree); + XFS_SB_UNLOCK(mp, s); + + statp->f_fsid = mp->m_dev; + strcpy(statp->f_basetype, XFS_NAME); + statp->f_namemax = MAXNAMELEN - 1; + bcopy((char *)&(mp->m_sb.sb_uuid), statp->f_fstr, sizeof(uuid_t)); + bzero(&(statp->f_fstr[sizeof(uuid_t)]), + (sizeof(statp->f_fstr) - sizeof(uuid_t))); + + return 0; +} + + +/* + * xfs_sync flushes any pending I/O to file system vfsp. + * + * This routine is called by vfs_sync() to make sure that things make it + * out to disk eventually, on sync() system calls to flush out everything, + * and when the file system is unmounted. For the vfs_sync() case, all + * we really need to do is sync out the log to make all of our meta-data + * updates permanent (except for timestamps). For calls from pflushd(), + * dirty pages are kept moving by calling pdflush() on the inodes + * containing them. We also flush the inodes that we can lock without + * sleeping and the superblock if we can lock it without sleeping from + * vfs_sync() so that items at the tail of the log are always moving out. + * + * Flags: + * SYNC_BDFLUSH - We're being called from vfs_sync() so we don't want + * to sleep if we can help it. All we really need + * to do is ensure that the log is synced at least + * periodically. We also push the inodes and + * superblock if we can lock them without sleeping + * and they are not pinned. + * SYNC_ATTR - We need to flush the inodes. If SYNC_BDFLUSH is not + * set, then we really want to lock each inode and flush + * it. + * SYNC_WAIT - All the flushes that take place in this call should + * be synchronous. + * SYNC_DELWRI - This tells us to push dirty pages associated with + * inodes. SYNC_WAIT and SYNC_BDFLUSH are used to + * determine if they should be flushed sync, async, or + * delwri. + * SYNC_CLOSE - This flag is passed when the system is being + * unmounted. We should sync and invalidate everthing. + * SYNC_FSDATA - This indicates that the caller would like to make + * sure the superblock is safe on disk. We can ensure + * this by simply makeing sure the log gets flushed + * if SYNC_BDFLUSH is set, and by actually writing it + * out otherwise. + * + */ +/*ARGSUSED*/ +STATIC int +xfs_sync( + bhv_desc_t *bdp, + int flags, + cred_t *credp) +{ + xfs_mount_t *mp; + + mp = XFS_BHVTOM(bdp); + return (xfs_syncsub(mp, flags, 0, NULL)); +} + +/* + * xfs sync routine for internal use + * + * This routine supports all of the flags defined for the generic VFS_SYNC + * interface as explained above under xys_sync. In the interests of not + * changing interfaces within the 6.5 family, additional internallly- + * required functions are specified within a separate xflags parameter, + * only available by calling this routine. + * + * xflags: + * XFS_XSYNC_RELOC - Sync for relocation. Don't try to get behavior + * locks as this will cause you to hang. Not all + * combinations of flags are necessarily supported + * when this is specified. + */ +int +xfs_syncsub( + xfs_mount_t *mp, + int flags, + int xflags, + int *bypassed) +{ + xfs_inode_t *ip = NULL; + xfs_inode_t *ip_next; + xfs_buf_t *bp; + vnode_t *vp = NULL; + vmap_t vmap; + int error; + int last_error; + uint64_t fflag; + uint lock_flags; + uint base_lock_flags; + uint log_flags; + boolean_t mount_locked; + boolean_t vnode_refed; + int preempt; + xfs_dinode_t *dip; + xfs_buf_log_item_t *bip; + xfs_iptr_t *ipointer; +#ifdef DEBUG + boolean_t ipointer_in = B_FALSE; + +#define IPOINTER_SET ipointer_in = B_TRUE +#define IPOINTER_CLR ipointer_in = B_FALSE +#else +#define IPOINTER_SET +#define IPOINTER_CLR +#endif + + +/* Insert a marker record into the inode list after inode ip. The list + * must be locked when this is called. After the call the list will no + * longer be locked. + */ +#define IPOINTER_INSERT(ip, mp) { \ + ASSERT(ipointer_in == B_FALSE); \ + ipointer->ip_mnext = ip->i_mnext; \ + ipointer->ip_mprev = ip; \ + ip->i_mnext = (xfs_inode_t *)ipointer; \ + ipointer->ip_mnext->i_mprev = (xfs_inode_t *)ipointer; \ + preempt = 0; \ + XFS_MOUNT_IUNLOCK(mp); \ + mount_locked = B_FALSE; \ + IPOINTER_SET; \ + } + +/* Remove the marker from the inode list. If the marker was the only item + * in the list then there are no remaining inodes and we should zero out + * the whole list. If we are the current head of the list then move the head + * past us. + */ +#define IPOINTER_REMOVE(ip, mp) { \ + ASSERT(ipointer_in == B_TRUE); \ + if (ipointer->ip_mnext != (xfs_inode_t *)ipointer) { \ + ip = ipointer->ip_mnext; \ + ip->i_mprev = ipointer->ip_mprev; \ + ipointer->ip_mprev->i_mnext = ip; \ + if (mp->m_inodes == (xfs_inode_t *)ipointer) { \ + mp->m_inodes = ip; \ + } \ + } else { \ + ASSERT(mp->m_inodes == (xfs_inode_t *)ipointer); \ + mp->m_inodes = NULL; \ + ip = NULL; \ + } \ + IPOINTER_CLR; \ + } + +#define PREEMPT_MASK 0x7f + + if (bypassed) + *bypassed = 0; + if (XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY) + return 0; + error = 0; + last_error = 0; + preempt = 0; + + /* Allocate a reference marker */ + ipointer = (xfs_iptr_t *)kmem_zalloc(sizeof(xfs_iptr_t), KM_SLEEP_IO); + + fflag = XFS_B_ASYNC; /* default is don't wait */ + if (flags & SYNC_BDFLUSH) + fflag = XFS_B_DELWRI; + if (flags & SYNC_WAIT) + fflag = 0; /* synchronous overrides all */ + + base_lock_flags = XFS_ILOCK_SHARED; + if (flags & (SYNC_DELWRI | SYNC_CLOSE)) { + /* + * We need the I/O lock if we're going to call any of + * the flush/inval routines. + */ + base_lock_flags |= XFS_IOLOCK_SHARED; + } + + /* + * Sync out the log. This ensures that the log is periodically + * flushed even if there is not enough activity to fill it up. + */ + if (flags & SYNC_WAIT) { + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); + } else { + xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); + } + + XFS_MOUNT_ILOCK(mp); + + ip = mp->m_inodes; + + mount_locked = B_TRUE; + vnode_refed = B_FALSE; + + IPOINTER_CLR; + + do { + ASSERT(ipointer_in == B_FALSE); + ASSERT(vnode_refed == B_FALSE); + + lock_flags = base_lock_flags; + + /* + * There were no inodes in the list, just break out + * of the loop. + */ + if (ip == NULL) { + break; + } + + /* + * We found another sync thread marker - skip it + */ + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } + + vp = XFS_ITOV_NULL(ip); + + /* + * If the vnode is gone then this is being torn down, + * call reclaim if it is flushed, else let regular flush + * code deal with it later in the loop. + */ + + if (vp == NULL) { + /* Skip ones already in reclaim */ + if (ip->i_flags & XFS_IRECLAIM) { + ip = ip->i_mnext; + continue; + } + if ((ip->i_update_core == 0) && + ((ip->i_itemp == NULL) || + !(ip->i_itemp->ili_format.ilf_fields & XFS_ILOG_ALL))) { + if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) { + ip = ip->i_mnext; + } else if ((ip->i_pincount == 0) && + xfs_iflock_nowait(ip)) { + IPOINTER_INSERT(ip, mp); + + xfs_finish_reclaim(ip, 1, 0); + + XFS_MOUNT_ILOCK(mp); + mount_locked = B_TRUE; + IPOINTER_REMOVE(ip, mp); + } else { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + ip = ip->i_mnext; + } + continue; + } + } + + /* + * We don't mess with swap files from here since it is + * too easy to deadlock on memory. + */ + if (vp && (vp->v_flag & VISSWAP)) { + ip = ip->i_mnext; + continue; + } + + if (XFS_FORCED_SHUTDOWN(mp) && !(flags & SYNC_CLOSE)) { + XFS_MOUNT_IUNLOCK(mp); + kmem_free(ipointer, sizeof(xfs_iptr_t)); + return 0; + } + + /* + * If this is just vfs_sync() or pflushd() calling + * then we can skip inodes for which it looks like + * there is nothing to do. Since we don't have the + * inode locked this is racey, but these are periodic + * calls so it doesn't matter. For the others we want + * to know for sure, so we at least try to lock them. + */ + if (flags & SYNC_BDFLUSH) { + if (((ip->i_itemp == NULL) || + !(ip->i_itemp->ili_format.ilf_fields & + XFS_ILOG_ALL)) && + (ip->i_update_core == 0)) { + ip = ip->i_mnext; + continue; + } + } + + /* + * Try to lock without sleeping. We're out of order with + * the inode list lock here, so if we fail we need to drop + * the mount lock and try again. If we're called from + * bdflush() here, then don't bother. + * + * The inode lock here actually coordinates with the + * almost spurious inode lock in xfs_ireclaim() to prevent + * the vnode we handle here without a reference from + * being freed while we reference it. If we lock the inode + * while it's on the mount list here, then the spurious inode + * lock in xfs_ireclaim() after the inode is pulled from + * the mount list will sleep until we release it here. + * This keeps the vnode from being freed while we reference + * it. It is also cheaper and simpler than actually doing + * a vn_get() for every inode we touch here. + */ + if (xfs_ilock_nowait(ip, lock_flags) == 0) { + + if ((flags & SYNC_BDFLUSH) || (vp == NULL)) { + ip = ip->i_mnext; + continue; + } + + /* + * We need to unlock the inode list lock in order + * to lock the inode. Insert a marker record into + * the inode list to remember our position, dropping + * the lock is now done inside the IPOINTER_INSERT + * macro. + * + * We also use the inode list lock to protect us + * in taking a snapshot of the vnode version number + * for use in calling vn_get(). + */ + VMAP(vp, ip, vmap); + IPOINTER_INSERT(ip, mp); + + vp = vn_get(vp, &vmap, 0); + if (vp == NULL) { + /* + * The vnode was reclaimed once we let go + * of the inode list lock. Skip to the + * next list entry. Remove the marker. + */ + + XFS_MOUNT_ILOCK(mp); + + mount_locked = B_TRUE; + vnode_refed = B_FALSE; + + IPOINTER_REMOVE(ip, mp); + + continue; + } + + xfs_ilock(ip, lock_flags); + + ASSERT(vp == XFS_ITOV(ip)); + ASSERT(ip->i_mount == mp); + + vnode_refed = B_TRUE; + } + + /* From here on in the loop we may have a marker record + * in the inode list. + */ + + if ((flags & SYNC_CLOSE) && (vp != NULL)) { + /* + * This is the shutdown case. We just need to + * flush and invalidate all the pages associated + * with the inode. Drop the inode lock since + * we can't hold it across calls to the buffer + * cache. + * + * We don't set the VREMAPPING bit in the vnode + * here, because we don't hold the vnode lock + * exclusively. It doesn't really matter, though, + * because we only come here when we're shutting + * down anyway. + */ + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + if (XFS_FORCED_SHUTDOWN(mp)) { + if (xflags & XFS_XSYNC_RELOC) { + fs_tosspages(XFS_ITOBHV(ip), 0, -1, + FI_REMAPF); + } + else { + VOP_TOSS_PAGES(vp, 0, -1, FI_REMAPF); + } + } else { + if (xflags & XFS_XSYNC_RELOC) { + fs_flushinval_pages(XFS_ITOBHV(ip), + 0, -1, FI_REMAPF); + } + else { + VOP_FLUSHINVAL_PAGES(vp, 0, -1, FI_REMAPF); + } + } + + xfs_ilock(ip, XFS_ILOCK_SHARED); + + } else if ((flags & SYNC_DELWRI) && (vp != NULL)) { + if (VN_DIRTY(vp)) { + /* We need to have dropped the lock here, + * so insert a marker if we have not already + * done so. + */ + if (mount_locked) { + IPOINTER_INSERT(ip, mp); + } + + /* + * Drop the inode lock since we can't hold it + * across calls to the buffer cache. + */ + xfs_iunlock(ip, XFS_ILOCK_SHARED); + VOP_FLUSH_PAGES(vp, (xfs_off_t)0, -1, + fflag, FI_NONE, error); + + xfs_ilock(ip, XFS_ILOCK_SHARED); + } + + } + + if (flags & SYNC_BDFLUSH) { + if ((flags & SYNC_ATTR) && + ((ip->i_update_core) || + ((ip->i_itemp != NULL) && + (ip->i_itemp->ili_format.ilf_fields != 0)))) { + + /* Insert marker and drop lock if not already + * done. + */ + if (mount_locked) { + IPOINTER_INSERT(ip, mp); + } + + /* + * We don't want the periodic flushing of the + * inodes by vfs_sync() to interfere with + * I/O to the file, especially read I/O + * where it is only the access time stamp + * that is being flushed out. To prevent + * long periods where we have both inode + * locks held shared here while reading the + * inode's buffer in from disk, we drop the + * inode lock while reading in the inode + * buffer. We have to release the buffer + * and reacquire the inode lock so that they + * are acquired in the proper order (inode + * locks first). The buffer will go at the + * end of the lru chain, though, so we can + * expect it to still be there when we go + * for it again in xfs_iflush(). + */ + if ((ip->i_pincount == 0) && + xfs_iflock_nowait(ip)) { + + xfs_ifunlock(ip); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + error = xfs_itobp(mp, NULL, ip, + &dip, &bp, 0); + if (!error) { + xfs_buf_relse(bp); + } else { + /* Bailing out, remove the + * marker and free it. + */ + XFS_MOUNT_ILOCK(mp); + + IPOINTER_REMOVE(ip, mp); + + XFS_MOUNT_IUNLOCK(mp); + + ASSERT(!(lock_flags & + XFS_IOLOCK_SHARED)); + + kmem_free(ipointer, + sizeof(xfs_iptr_t)); + return (0); + } + + /* + * Since we dropped the inode lock, + * the inode may have been reclaimed. + * Therefore, we reacquire the mount + * lock and check to see if we were the + * inode reclaimed. If this happened + * then the ipointer marker will no + * longer point back at us. In this + * case, move ip along to the inode + * after the marker, remove the marker + * and continue. + */ + XFS_MOUNT_ILOCK(mp); + mount_locked = B_TRUE; + + if (ip != ipointer->ip_mprev) { + IPOINTER_REMOVE(ip, mp); + + ASSERT(!vnode_refed); + ASSERT(!(lock_flags & + XFS_IOLOCK_SHARED)); + continue; + } + + ASSERT(ip->i_mount == mp); + + if (xfs_ilock_nowait(ip, + XFS_ILOCK_SHARED) == 0) { + ASSERT(ip->i_mount == mp); + /* + * We failed to reacquire + * the inode lock without + * sleeping, so just skip + * the inode for now. We + * clear the ILOCK bit from + * the lock_flags so that we + * won't try to drop a lock + * we don't hold below. + */ + lock_flags &= ~XFS_ILOCK_SHARED; + IPOINTER_REMOVE(ip_next, mp); + } else if ((ip->i_pincount == 0) && + xfs_iflock_nowait(ip)) { + ASSERT(ip->i_mount == mp); + /* + * Since this is vfs_sync() + * calling we only flush the + * inode out if we can lock + * it without sleeping and + * it is not pinned. Drop + * the mount lock here so + * that we don't hold it for + * too long. We already have + * a marker in the list here. + */ + XFS_MOUNT_IUNLOCK(mp); + mount_locked = B_FALSE; + error = xfs_iflush(ip, + XFS_IFLUSH_DELWRI); + } else { + ASSERT(ip->i_mount == mp); + IPOINTER_REMOVE(ip_next, mp); + } + } + + } + + } else { + if ((flags & SYNC_ATTR) && + ((ip->i_update_core) || + ((ip->i_itemp != NULL) && + (ip->i_itemp->ili_format.ilf_fields != 0)))) { + if (mount_locked) { + IPOINTER_INSERT(ip, mp); + } + + if (flags & SYNC_WAIT) { + xfs_iflock(ip); + error = xfs_iflush(ip, + XFS_IFLUSH_SYNC); + } else { + /* + * If we can't acquire the flush + * lock, then the inode is already + * being flushed so don't bother + * waiting. If we can lock it then + * do a delwri flush so we can + * combine multiple inode flushes + * in each disk write. + */ + if (xfs_iflock_nowait(ip)) { + error = xfs_iflush(ip, + XFS_IFLUSH_DELWRI); + } + else if (bypassed) + (*bypassed)++; + } + } + } + + if (lock_flags != 0) { + xfs_iunlock(ip, lock_flags); + } + + if (vnode_refed) { + /* + * If we had to take a reference on the vnode + * above, then wait until after we've unlocked + * the inode to release the reference. This is + * because we can be already holding the inode + * lock when VN_RELE() calls xfs_inactive(). + * + * Make sure to drop the mount lock before calling + * VN_RELE() so that we don't trip over ourselves if + * we have to go for the mount lock again in the + * inactive code. + */ + if (mount_locked) { + IPOINTER_INSERT(ip, mp); + } + + VN_RELE(vp); + + vnode_refed = B_FALSE; + } + + if (error) { + last_error = error; + } + + /* + * bail out if the filesystem is corrupted. + */ + if (error == EFSCORRUPTED) { + if (!mount_locked) { + XFS_MOUNT_ILOCK(mp); + IPOINTER_REMOVE(ip, mp); + } + XFS_MOUNT_IUNLOCK(mp); + ASSERT(ipointer_in == B_FALSE); + kmem_free(ipointer, sizeof(xfs_iptr_t)); + return XFS_ERROR(error); + } + + /* Let other threads have a chance at the mount lock + * if we have looped many times without dropping the + * lock. + */ + if ((++preempt & PREEMPT_MASK) == 0) { + if (mount_locked) { + IPOINTER_INSERT(ip, mp); + } + } + + if (mount_locked == B_FALSE) { + XFS_MOUNT_ILOCK(mp); + mount_locked = B_TRUE; + IPOINTER_REMOVE(ip, mp); + continue; + } + + ASSERT(ipointer_in == B_FALSE); + ip = ip->i_mnext; + + } while (ip->i_mnext != mp->m_inodes); + + XFS_MOUNT_IUNLOCK(mp); + + ASSERT(ipointer_in == B_FALSE); + + /* + * Get the Quota Manager to flush the dquots in a similar manner. + */ + if (XFS_IS_QUOTA_ON(mp)) { + if ((error = xfs_qm_sync(mp, flags))) { + /* + * If we got an IO error, we will be shutting down. + * So, there's nothing more for us to do here. + */ + ASSERT(error != EIO || XFS_FORCED_SHUTDOWN(mp)); + if (XFS_FORCED_SHUTDOWN(mp)) { + kmem_free(ipointer, sizeof(xfs_iptr_t)); + return XFS_ERROR(error); + } + } + } + + /* + * Flushing out dirty data above probably generated more + * log activity, so if this isn't vfs_sync() then flush + * the log again. If SYNC_WAIT is set then do it synchronously. + */ + if (!(flags & SYNC_BDFLUSH)) { + log_flags = XFS_LOG_FORCE; + if (flags & SYNC_WAIT) { + log_flags |= XFS_LOG_SYNC; + } + xfs_log_force(mp, (xfs_lsn_t)0, log_flags); + } + + if (flags & SYNC_FSDATA) { + /* + * If this is vfs_sync() then only sync the superblock + * if we can lock it without sleeping and it is not pinned. + */ + if (flags & SYNC_BDFLUSH) { + bp = xfs_getsb(mp, XFS_BUF_TRYLOCK); + if (bp != NULL) { + bip = XFS_BUF_FSPRIVATE(bp,xfs_buf_log_item_t*); + if ((bip != NULL) && + xfs_buf_item_dirty(bip)) { + if (!(XFS_BUF_ISPINNED(bp))) { + XFS_BUF_ASYNC(bp); + error = xfs_bwrite(mp, bp); + } else { + xfs_buf_relse(bp); + } + } else { + xfs_buf_relse(bp); + } + } + } else { + bp = xfs_getsb(mp, 0); + /* + * If the buffer is pinned then push on the log so + * we won't get stuck waiting in the write for + * someone, maybe ourselves, to flush the log. + * Even though we just pushed the log above, we + * did not have the superblock buffer locked at + * that point so it can become pinned in between + * there and here. + */ + if (XFS_BUF_ISPINNED(bp)) { + xfs_log_force(mp, (xfs_lsn_t)0, + XFS_LOG_FORCE); + } + XFS_BUF_BFLAGS(bp) |= fflag; + error = xfs_bwrite(mp, bp); + } + if (error) { + last_error = error; + } + } + + /* + * If this is the 30 second sync, then kick some entries out of + * the reference cache. This ensures that idle entries are + * eventually kicked out of the cache. + */ + if (flags & SYNC_BDFLUSH) { + xfs_refcache_purge_some(); + } + + /* + * Now check to see if the log needs a "dummy" transaction. + */ + + if (xfs_log_need_covered(mp)) { + xfs_trans_t *tp; + + /* + * Put a dummy transaction in the log to tell + * recovery that all others are OK. + */ + tp = xfs_trans_alloc(mp, XFS_TRANS_DUMMY1); + if ((error = xfs_trans_reserve(tp, 0, + XFS_ICHANGE_LOG_RES(mp), + 0, 0, 0))) { + xfs_trans_cancel(tp, 0); + kmem_free(ipointer, sizeof(xfs_iptr_t)); + return error; + } + + ip = mp->m_rootip; + xfs_ilock(ip, XFS_ILOCK_EXCL); + + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + error = xfs_trans_commit(tp, 0, NULL); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + } + + /* + * When shutting down, we need to insure that the AIL is pushed + * to disk or the filesystem can appear corrupt from the PROM. + */ + if ((flags & (SYNC_CLOSE|SYNC_WAIT)) == (SYNC_CLOSE|SYNC_WAIT)) { + XFS_bflush(mp->m_ddev_targ); + if (mp->m_rtdev != NODEV) { + XFS_bflush(mp->m_rtdev_targ); + } + } + + kmem_free(ipointer, sizeof(xfs_iptr_t)); + return XFS_ERROR(last_error); +} + + +/* + * xfs_vget - called by DMAPI to get vnode from file handle + */ +STATIC int +xfs_vget( + bhv_desc_t *bdp, + vnode_t **vpp, + fid_t *fidp) +{ + xfs_fid_t *xfid; + xfs_fid2_t *xfid2; + xfs_inode_t *ip; + int error; + xfs_ino_t ino; + unsigned int igen; + xfs_mount_t *mp; + + xfid = (struct xfs_fid *)fidp; + xfid2 = (struct xfs_fid2 *)fidp; +#if 0 + if (xfid->fid_len == sizeof *xfid - sizeof xfid->fid_len) { + /* + * The 10 byte fid used by NFS, using 48 bits of inode number + */ + ino = (xfs_ino_t)xfid->fid_ino | ((xfs_ino_t)xfid->fid_pad << 32); + igen = xfid->fid_gen; + } else +#endif + if (xfid2->fid_len == sizeof *xfid2 - sizeof xfid2->fid_len) { + ino = xfid2->fid_ino; + igen = xfid2->fid_gen; + } else { + /* + * Invalid. Since handles can be created in user space + * and passed in via gethandle(), this is not cause for + * a panic. + */ + return XFS_ERROR(EINVAL); + } + mp = XFS_BHVTOM(bdp); + error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, 0); + if (error) { + *vpp = NULL; + return error; + } + if (ip == NULL) { + *vpp = NULL; + return XFS_ERROR(EIO); + } + + if (ip->i_d.di_mode == 0 || ip->i_d.di_gen != igen) { + xfs_iput(ip, XFS_ILOCK_SHARED); + *vpp = NULL; + return 0; + } + + xfs_iunlock(ip, XFS_ILOCK_SHARED); + *vpp = XFS_ITOV(ip); + return 0; +} + + +STATIC int +xfs_get_vnode(bhv_desc_t *bdp, + vnode_t **vpp, + xfs_ino_t ino) +{ + xfs_mount_t *mp; + xfs_ihash_t *ih; + xfs_inode_t *ip; + + *vpp = NULL; + + mp = XFS_BHVTOM(bdp); + ih = XFS_IHASH(mp, ino); + + mraccess(&ih->ih_lock); + + for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) { + if (ip->i_ino == ino) { + *vpp = XFS_ITOV(ip); + break; + } + } + + mrunlock(&ih->ih_lock); + + if (!*vpp) { + if (xfs_iget(mp, NULL, (xfs_ino_t) ino, 0, &ip, 0)) { + return XFS_ERROR(ENOENT); + } + *vpp = XFS_ITOV(ip); + } + + return(0); +} + + +vfsops_t xfs_vfsops = { + vfs_mount: xfs_vfsmount, + vfs_rootinit: xfs_rootinit, + vfs_dounmount: fs_dounmount, + vfs_unmount: xfs_unmount, + vfs_root: xfs_root, + vfs_statvfs: xfs_statvfs, + vfs_sync: xfs_sync, + vfs_vget: xfs_vget, + vfs_mountroot: xfs_vfsmountroot, + vfs_get_vnode: xfs_get_vnode, + vfs_dmapi_mount: xfs_dm_mount +}; diff -rNu linux-2.4.7/linux/fs/xfs/xfs_vnodeops.c linux-2.4-xfs/linux/fs/xfs/xfs_vnodeops.c --- linux-2.4.7/linux/fs/xfs/xfs_vnodeops.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfs_vnodeops.c Tue Jun 26 17:07:29 2001 @@ -0,0 +1,5960 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + + +/* + * The maximum pathlen is 1024 bytes. Since the minimum file system + * blocksize is 512 bytes, we can get a max of 2 extents back from + * bmapi. + */ +#define SYMLINK_MAPS 2 + +extern int xfs_ioctl(bhv_desc_t *, struct inode *, struct file *, + unsigned int, unsigned long); + + +#ifdef XFS_RW_TRACE +STATIC void +xfs_ctrunc_trace( + int tag, + xfs_inode_t *ip); +#else +#define xfs_ctrunc_trace(tag, ip) +#endif /* DEBUG */ + +/* + * For xfs, we check that the file isn't too big to be opened by this kernel. + * No other open action is required for regular files. Devices are handled + * through the specfs file system, pipes through fifofs. Device and + * fifo vnodes are "wrapped" by specfs and fifofs vnodes, respectively, + * when a new vnode is first looked up or created. + */ +/*ARGSUSED*/ +STATIC int +xfs_open( + bhv_desc_t *bdp, + vnode_t **vpp, + mode_t flag, + cred_t *credp) +{ + int mode; + int rval = 0; + vnode_t *vp; + xfs_inode_t *ip; + + vp = BHV_TO_VNODE(bdp); + ip = XFS_BHVTOI(bdp); + + if (XFS_FORCED_SHUTDOWN(ip->i_mount)) + return XFS_ERROR(EIO); + + /* + * If it's a directory with any blocks, read-ahead block 0 + * as we're almost certain to have the next operation be a read there. + */ + if (vp->v_type == VDIR && ip->i_d.di_nextents > 0) { + mode = xfs_ilock_map_shared(ip); + (void)xfs_da_reada_buf(NULL, ip, 0, XFS_DATA_FORK); + xfs_iunlock(ip, mode); + } +#if !XFS_BIG_FILES + else if (vp->v_type == VREG) { + xfs_ilock(ip, XFS_ILOCK_SHARED); + if (ip->i_d.di_size > XFS_MAX_FILE_OFFSET) + rval = XFS_ERROR(EFBIG); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + } +#endif + return rval; +} + +/* + * xfs_close + * + */ +/*ARGSUSED*/ +STATIC int +xfs_close( + bhv_desc_t *bdp, + int flag, + lastclose_t lastclose, + cred_t *credp) +{ + /* REFERENCED */ + vnode_t *vp; + + vp = BHV_TO_VNODE(bdp); + + vn_trace_exit(vp, "xfs_close", (inst_t *)__return_address); + + return 0; +} + + +/* + * xfs_getattr + */ +/*ARGSUSED*/ +int +xfs_getattr( + bhv_desc_t *bdp, + vattr_t *vap, + int flags, + cred_t *credp) +{ + xfs_inode_t *ip; + xfs_mount_t *mp; + vnode_t *vp; + + vp = BHV_TO_VNODE(bdp); + + vn_trace_entry(vp, "xfs_getattr", (inst_t *)__return_address); + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + if (!(flags & ATTR_LAZY)) + xfs_ilock(ip, XFS_ILOCK_SHARED); + + vap->va_size = ip->i_d.di_size; + if (vap->va_mask == AT_SIZE) { + if (!(flags & ATTR_LAZY)) + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return 0; + } + vap->va_nblocks = + XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks); + vap->va_fsid = ip->i_dev; +#if XFS_BIG_FILESYSTEMS + vap->va_nodeid = ip->i_ino + mp->m_inoadd; +#else + vap->va_nodeid = ip->i_ino; +#endif + vap->va_nlink = ip->i_d.di_nlink; + + /* + * Quick exit for non-stat callers + */ + if ((vap->va_mask & ~(AT_SIZE|AT_FSID|AT_NODEID|AT_NLINK)) == 0) { + if (!(flags & ATTR_LAZY)) + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return 0; + } + + /* + * Copy from in-core inode. + */ + vap->va_type = vp->v_type; + vap->va_mode = ip->i_d.di_mode & MODEMASK; + vap->va_uid = ip->i_d.di_uid; + vap->va_gid = ip->i_d.di_gid; + vap->va_projid = ip->i_d.di_projid; + + /* + * Check vnode type block/char vs. everything else. + * Do it with bitmask because that's faster than looking + * for multiple values individually. + */ + if (((1 << vp->v_type) & ((1<va_rdev = 0; + + if (!(ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) { + + vap->va_blksize = mp->m_swidth ? + /* + * If the underlying volume is a stripe, then + * return the stripe width in bytes as the + * recommended I/O size. + */ + (mp->m_swidth << mp->m_sb.sb_blocklog) : + /* + * Return the largest of the preferred buffer + * sizes since doing small I/Os into larger + * buffers causes buffers to be decommissioned. + * The value returned is in bytes. + */ + (1 << (int)MAX(ip->i_iocore.io_readio_log, + ip->i_iocore.io_writeio_log)); + + } else { + + /* + * If the file blocks are being allocated from a + * realtime partition, then return the inode's + * realtime extent size or the realtime volume's + * extent size. + */ + vap->va_blksize = ip->i_d.di_extsize ? + (ip->i_d.di_extsize << mp->m_sb.sb_blocklog) : + (mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog); + } + } else { + vap->va_rdev = IRIX_DEV_TO_KDEVT(ip->i_df.if_u2.if_rdev); + vap->va_blksize = BLKDEV_IOSIZE; + } + + vap->va_atime.tv_sec = ip->i_d.di_atime.t_sec; + vap->va_atime.tv_nsec = ip->i_d.di_atime.t_nsec; + vap->va_mtime.tv_sec = ip->i_d.di_mtime.t_sec; + vap->va_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; + vap->va_ctime.tv_sec = ip->i_d.di_ctime.t_sec; + vap->va_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; + + /* + * Exit for stat callers. See if any of the rest of the fields + * to be filled in are needed. + */ + if ((vap->va_mask & + (AT_XFLAGS|AT_EXTSIZE|AT_NEXTENTS|AT_ANEXTENTS| + AT_GENCOUNT|AT_VCODE)) == 0) { + if (!(flags & ATTR_LAZY)) + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return 0; + } + /* + * convert di_flags to xflags + */ + vap->va_xflags = + ((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) ? + XFS_XFLAG_REALTIME : 0) | + ((ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) ? + XFS_XFLAG_PREALLOC : 0); + vap->va_extsize = ip->i_d.di_extsize << mp->m_sb.sb_blocklog; + vap->va_nextents = + (ip->i_df.if_flags & XFS_IFEXTENTS) ? + ip->i_df.if_bytes / sizeof(xfs_bmbt_rec_t) : + ip->i_d.di_nextents; + if (ip->i_afp != NULL) + vap->va_anextents = + (ip->i_afp->if_flags & XFS_IFEXTENTS) ? + ip->i_afp->if_bytes / sizeof(xfs_bmbt_rec_t) : + ip->i_d.di_anextents; + else + vap->va_anextents = 0; + vap->va_gencount = ip->i_d.di_gen; + vap->va_vcode = 0L; + + if (!(flags & ATTR_LAZY)) + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return 0; +} + + +/* + * xfs_setattr + */ +STATIC int +xfs_setattr( + bhv_desc_t *bdp, + vattr_t *vap, + int flags, + cred_t *credp) +{ + xfs_inode_t *ip; + xfs_trans_t *tp; + xfs_mount_t *mp; + int mask; + int code; + uint lock_flags; + uint commit_flags=0; + uid_t uid=0, iuid=0; + gid_t gid=0, igid=0; + int timeflags = 0; + vnode_t *vp; + xfs_prid_t projid=0, iprojid=0; + int privileged; + int mandlock_before, mandlock_after; + uint qflags; + struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; + int file_owner; + + vp = BHV_TO_VNODE(bdp); + + vn_trace_entry(vp, "xfs_setattr", (inst_t *)__return_address); + /* + * Cannot set certain attributes. + */ + mask = vap->va_mask; + if (mask & AT_NOSET) { + return XFS_ERROR(EINVAL); + } + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + /* + * Timestamps do not need to be logged and hence do not + * need to be done within a transaction. + */ + if (mask & AT_UPDTIMES) { + ASSERT((mask & ~AT_UPDTIMES) == 0); + timeflags = ((mask & AT_UPDATIME) ? XFS_ICHGTIME_ACC : 0) | + ((mask & AT_UPDCTIME) ? XFS_ICHGTIME_CHG : 0) | + ((mask & AT_UPDMTIME) ? XFS_ICHGTIME_MOD : 0); + xfs_ichgtime(ip, timeflags); + return 0; + } + + olddquot1 = olddquot2 = NULL; + udqp = gdqp = NULL; + + /* + * If disk quotas is on, we make sure that the dquots do exist on disk, + * before we start any other transactions. Trying to do this later + * is messy. We don't care to take a readlock to look at the ids + * in inode here, because we can't hold it across the trans_reserve. + * If the IDs do change before we take the ilock, we're covered + * because the i_*dquot fields will get updated anyway. + */ + if (XFS_IS_QUOTA_ON(mp) && (mask & (AT_UID|AT_GID))) { + qflags = 0; + if (mask & AT_UID) { + uid = vap->va_uid; + qflags |= XFS_QMOPT_UQUOTA; + } else { + uid = ip->i_d.di_uid; + } + if (mask & AT_GID) { + gid = vap->va_gid; + qflags |= XFS_QMOPT_GQUOTA; + } else { + gid = ip->i_d.di_gid; + } + /* + * We take a reference when we initialize udqp and gdqp, + * so it is important that we never blindly double trip on + * the same variable. See xfs_create() for an example. + */ + ASSERT(udqp == NULL); + ASSERT(gdqp == NULL); + if ((code = xfs_qm_vop_dqalloc(mp, ip, uid, gid, qflags, + &udqp, &gdqp))) + return (code); + } + + /* + * For the other attributes, we acquire the inode lock and + * first do an error checking pass. + */ + tp = NULL; + lock_flags = XFS_ILOCK_EXCL; + if (!(mask & AT_SIZE)) { + tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); + commit_flags = 0; + if ((code = xfs_trans_reserve(tp, 0, + XFS_ICHANGE_LOG_RES(mp), 0, + 0, 0))) { + lock_flags = 0; + goto error_return; + } + } else { + if (DM_EVENT_ENABLED (vp->v_vfsp, ip, DM_EVENT_TRUNCATE) && + !(flags & ATTR_DMI)) { + code = xfs_dm_send_data_event (DM_EVENT_TRUNCATE, bdp, + vap->va_size, 0, AT_DELAY_FLAG(flags), NULL); + if (code) { + lock_flags = 0; + goto error_return; + } + } + lock_flags |= XFS_IOLOCK_EXCL; + } + + xfs_ilock(ip, lock_flags); + + if (_MAC_XFS_IACCESS(ip, MACWRITE, credp)) { + code = XFS_ERROR(EACCES); + goto error_return; + } + + /* boolean: are we the file owner? */ + file_owner = (current->fsuid == ip->i_d.di_uid); + + /* + * Change various properties of a file. + * Only the owner or users with CAP_FOWNER + * capability may do these things. + */ + if (mask & (AT_MODE|AT_XFLAGS|AT_EXTSIZE|AT_UID|AT_GID|AT_PROJID)) { + /* + * CAP_FOWNER overrides the following restrictions: + * + * The user ID of the calling process must be equal + * to the file owner ID, except in cases where the + * CAP_FSETID capability is applicable. + */ + if (!file_owner && !capable(CAP_FOWNER)) { + code = XFS_ERROR(EPERM); + goto error_return; + } + + /* + * CAP_FSETID overrides the following restrictions: + * + * The effective user ID of the calling process shall match + * the file owner when setting the set-user-ID and + * set-group-ID bits on that file. + * + * The effective group ID or one of the supplementary group + * IDs of the calling process shall match the group owner of + * the file when setting the set-group-ID bit on that file + */ + if (mask & AT_MODE) { + mode_t m = 0; + + if ((vap->va_mode & ISUID) && !file_owner) + m |= ISUID; + if ((vap->va_mode & ISGID) && + !in_group_p((gid_t)ip->i_d.di_gid)) + m |= ISGID; + if ((vap->va_mode & ISVTX) && vp->v_type != VDIR) + m |= ISVTX; + if (m && !capable(CAP_FSETID)) + vap->va_mode &= ~m; + } + } + + /* + * Change file ownership. Must be the owner or privileged. + * If the system was configured with the "restricted_chown" + * option, the owner is not permitted to give away the file, + * and can change the group id only to a group of which he + * or she is a member. + */ + if (mask & (AT_UID|AT_GID|AT_PROJID)) { + /* + * These IDs could have changed since we last looked at them. + * But, we're assured that if the ownership did change + * while we didn't have the inode locked, inode's dquot(s) + * would have changed also. + */ + iuid = ip->i_d.di_uid; + iprojid = ip->i_d.di_projid; + igid = ip->i_d.di_gid; + gid = (mask & AT_GID) ? vap->va_gid : igid; + uid = (mask & AT_UID) ? vap->va_uid : iuid; + projid = (mask & AT_PROJID) ? (xfs_prid_t)vap->va_projid : + iprojid; + + /* + * CAP_CHOWN overrides the following restrictions: + * + * If _POSIX_CHOWN_RESTRICTED is defined, this capability + * shall override the restriction that a process cannot + * change the user ID of a file it owns and the restriction + * that the group ID supplied to the chown() function + * shall be equal to either the group ID or one of the + * supplementary group IDs of the calling process. + * + * XXX: How does restricted_chown affect projid? + */ + if (restricted_chown && + (iuid != uid || (igid != gid && + !in_group_p((gid_t)gid))) && + !capable(CAP_CHOWN)) { + code = XFS_ERROR(EPERM); + goto error_return; + } + /* + * Do a quota reservation only if uid or gid is actually + * going to change. + */ + if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) || + (XFS_IS_GQUOTA_ON(mp) && igid != gid)) { + ASSERT(tp); + /* + * XXX:casey - This may result in unnecessary auditing. + */ + privileged = capable(CAP_FOWNER); + if ((code = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp, + privileged ? + XFS_QMOPT_FORCE_RES : + 0))) + /* out of quota */ + goto error_return; + } + } + + /* + * Truncate file. Must have write permission and not be a directory. + */ + if (mask & AT_SIZE) { + /* Short circuit the truncate case for zero length files */ + if ((vap->va_size == 0) && + (ip->i_d.di_size == 0) && (ip->i_d.di_nextents == 0)) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + lock_flags &= ~XFS_ILOCK_EXCL; + if (mask & AT_CTIME) + xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + code = 0; + goto error_return; + } + + if (vp->v_type == VDIR) { + code = XFS_ERROR(EISDIR); + goto error_return; + } else if (vp->v_type != VREG) { + code = XFS_ERROR(EINVAL); + goto error_return; + } + if (vp->v_flag & VISSWAP) { + code = XFS_ERROR(EACCES); + goto error_return; + } + /* + * Make sure that the dquots are attached to the inode. + */ + if (XFS_IS_QUOTA_ON(mp) && XFS_NOT_DQATTACHED(mp, ip)) { + if ((code = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED))) + goto error_return; + } + } + + /* + * Change file access or modified times. + */ + if (mask & (AT_ATIME|AT_MTIME)) { + if (!file_owner) { + if ((flags & ATTR_UTIME) && + !capable(CAP_FOWNER)) { + code = XFS_ERROR(EPERM); + goto error_return; + } + } + } + + /* + * Change extent size or realtime flag. + */ + if (mask & (AT_EXTSIZE|AT_XFLAGS)) { + /* + * Can't change extent size if any extents are allocated. + */ + if (ip->i_d.di_nextents && (mask & AT_EXTSIZE) && + ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != + vap->va_extsize) ) { + code = XFS_ERROR(EINVAL); /* EFBIG? */ + goto error_return; + } + + /* + * Can't set extent size unless the file is marked, or + * about to be marked as a realtime file. + * + * This check will be removed when fixed size extents + * with buffered data writes is implemented. + * + */ + if ((mask & AT_EXTSIZE) && + ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != + vap->va_extsize) && + (!((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) || + ((mask & AT_XFLAGS) && + (vap->va_xflags & XFS_XFLAG_REALTIME))))) { + code = XFS_ERROR(EINVAL); + goto error_return; + } + + /* + * Can't change realtime flag if any extents are allocated. + */ + if (ip->i_d.di_nextents && (mask & AT_XFLAGS) && + (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != + (vap->va_xflags & XFS_XFLAG_REALTIME)) { + code = XFS_ERROR(EINVAL); /* EFBIG? */ + goto error_return; + } + /* + * Extent size must be a multiple of the appropriate block + * size, if set at all. + */ + if ((mask & AT_EXTSIZE) && vap->va_extsize != 0) { + xfs_extlen_t size; + + if ((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) || + ((mask & AT_XFLAGS) && + (vap->va_xflags & XFS_XFLAG_REALTIME))) { + size = mp->m_sb.sb_rextsize << + mp->m_sb.sb_blocklog; + } else { + size = mp->m_sb.sb_blocksize; + } + if (vap->va_extsize % size) { + code = XFS_ERROR(EINVAL); + goto error_return; + } + } + /* + * If realtime flag is set then must have realtime data. + */ + if ((mask & AT_XFLAGS) && + (vap->va_xflags & XFS_XFLAG_REALTIME)) { + if ((mp->m_sb.sb_rblocks == 0) || + (mp->m_sb.sb_rextsize == 0) || + (ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) { + code = XFS_ERROR(EINVAL); + goto error_return; + } + } + } + + /* + * Now we can make the changes. Before we join the inode + * to the transaction, if AT_SIZE is set then take care of + * the part of the truncation that must be done without the + * inode lock. This needs to be done before joining the inode + * to the transaction, because the inode cannot be unlocked + * once it is a part of the transaction. + */ + if (mask & AT_SIZE) { + if (vap->va_size > ip->i_d.di_size) { + code = xfs_igrow_start(ip, vap->va_size, credp); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + } else if (vap->va_size < ip->i_d.di_size) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, + (xfs_fsize_t)vap->va_size); + code = 0; + } else { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + code = 0; + } + if (code) { + ASSERT(tp == NULL); + lock_flags &= ~XFS_ILOCK_EXCL; + ASSERT(lock_flags == XFS_IOLOCK_EXCL); + goto error_return; + } + tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE); + if ((code = xfs_trans_reserve(tp, 0, + XFS_ITRUNCATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT))) { + xfs_trans_cancel(tp, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return code; + } + commit_flags = XFS_TRANS_RELEASE_LOG_RES; + xfs_ilock(ip, XFS_ILOCK_EXCL); + } + + xfs_trans_ijoin(tp, ip, lock_flags); + xfs_trans_ihold(tp, ip); + + /* determine whether mandatory locking mode changes */ + mandlock_before = MANDLOCK(vp, ip->i_d.di_mode); + + /* + * Truncate file. Must have write permission and not be a directory. + */ + if (mask & AT_SIZE) { + if (vap->va_size > ip->i_d.di_size) { + xfs_igrow_finish(tp, ip, vap->va_size, + !(flags & ATTR_DMI)); + } else if ((vap->va_size < ip->i_d.di_size) || + ((vap->va_size == 0) && ip->i_d.di_nextents)) { + /* + * signal a sync transaction unless + * we're truncating an already unlinked + * file on a wsync filesystem + */ + code = xfs_itruncate_finish(&tp, ip, + (xfs_fsize_t)vap->va_size, + XFS_DATA_FORK, + ((ip->i_d.di_nlink != 0 || + !(mp->m_flags & XFS_MOUNT_WSYNC)) + ? 1 : 0)); + if (code) { + goto abort_return; + } + } + /* + * Have to do this even if the file's size doesn't change. + */ + timeflags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; + } + + /* + * Change file access modes. + */ + if (mask & AT_MODE) { + ip->i_d.di_mode &= IFMT; + ip->i_d.di_mode |= vap->va_mode & ~IFMT; + + xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); + timeflags |= XFS_ICHGTIME_CHG; + } + + /* + * Change file ownership. Must be the owner or privileged. + * If the system was configured with the "restricted_chown" + * option, the owner is not permitted to give away the file, + * and can change the group id only to a group of which he + * or she is a member. + */ + if (mask & (AT_UID|AT_GID|AT_PROJID)) { + /* + * CAP_FSETID overrides the following restrictions: + * + * The set-user-ID and set-group-ID bits of a file will be + * cleared upon successful return from chown() + */ + if ((ip->i_d.di_mode & (ISUID|ISGID)) && + !capable(CAP_FSETID)) { + ip->i_d.di_mode &= ~(ISUID|ISGID); + } + + /* + * Change the ownerships and register quota modifications + * in the transaction. + */ + if (iuid != uid) { + if (XFS_IS_UQUOTA_ON(mp)) { + ASSERT(mask & AT_UID); + ASSERT(udqp); + ASSERT(xfs_qm_dqid(udqp) == (xfs_dqid_t)uid); + olddquot1 = xfs_qm_vop_chown(tp, ip, + &ip->i_udquot, + udqp); + /* + * We'll dqrele olddquot at the end. + */ + } + ip->i_d.di_uid = uid; + } + if (igid != gid) { + if (XFS_IS_GQUOTA_ON(mp)) { + ASSERT(mask & AT_GID); + ASSERT(gdqp); + ASSERT(xfs_qm_dqid(gdqp) == gid); + olddquot2 = xfs_qm_vop_chown(tp, ip, + &ip->i_gdquot, + gdqp); + } + ip->i_d.di_gid = gid; + } + if (iprojid != projid) { + ip->i_d.di_projid = projid; + /* + * We may have to rev the inode as well as + * the superblock version number since projids didn't + * exist before DINODE_VERSION_2 and SB_VERSION_NLINK. + */ + if (ip->i_d.di_version == XFS_DINODE_VERSION_1) + xfs_bump_ino_vers2(tp, ip); + } + + xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE); + timeflags |= XFS_ICHGTIME_CHG; + } + + + /* + * Change file access or modified times. + */ + if (mask & (AT_ATIME|AT_MTIME)) { + if (mask & AT_ATIME) { + ip->i_d.di_atime.t_sec = vap->va_atime.tv_sec; + ip->i_d.di_atime.t_nsec = vap->va_atime.tv_nsec; + ip->i_update_core = 1; + timeflags &= ~XFS_ICHGTIME_ACC; + } + if (mask & AT_MTIME) { + ip->i_d.di_mtime.t_sec = vap->va_mtime.tv_sec; + ip->i_d.di_mtime.t_nsec = vap->va_mtime.tv_nsec; + timeflags &= ~XFS_ICHGTIME_MOD; + timeflags |= XFS_ICHGTIME_CHG; + } + } + + /* + * Change XFS-added attributes. + */ + if (mask & (AT_EXTSIZE|AT_XFLAGS)) { + if (mask & AT_EXTSIZE) { + /* + * Converting bytes to fs blocks. + */ + ip->i_d.di_extsize = vap->va_extsize >> + mp->m_sb.sb_blocklog; + } + if (mask & AT_XFLAGS) { + ip->i_d.di_flags = 0; + if (vap->va_xflags & XFS_XFLAG_REALTIME) { + ip->i_d.di_flags |= XFS_DIFLAG_REALTIME; + /* This is replicated in the io core for + * CXFS use + */ + ip->i_iocore.io_flags |= XFS_IOCORE_RT; + } + /* can't set PREALLOC this way, just ignore it */ + } + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + timeflags |= XFS_ICHGTIME_CHG; + } + + /* + * Change file inode change time only if AT_CTIME set + * AND we have been called by a DMI function. + */ + + if ( (flags & ATTR_DMI) && (mask & AT_CTIME) ) { + ip->i_d.di_ctime.t_sec = vap->va_ctime.tv_sec; + ip->i_d.di_ctime.t_nsec = vap->va_ctime.tv_nsec; + ip->i_update_core = 1; + timeflags &= ~XFS_ICHGTIME_CHG; + } + + /* + * Send out timestamp changes that need to be set to the + * current time. Not done when called by a DMI function. + */ + if (timeflags && !(flags & ATTR_DMI)) + xfs_ichgtime(ip, timeflags); + + XFS_STATS_INC(xfsstats.xs_ig_attrchg); + + /* + * If this is a synchronous mount, make sure that the + * transaction goes to disk before returning to the user. + * This is slightly sub-optimal in that truncates require + * two sync transactions instead of one for wsync filesytems. + * One for the truncate and one for the timestamps since we + * don't want to change the timestamps unless we're sure the + * truncate worked. Truncates are less than 1% of the laddis + * mix so this probably isn't worth the trouble to optimize. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) + xfs_trans_set_sync(tp); + + code = xfs_trans_commit(tp, commit_flags, NULL); + + /* + * If the (regular) file's mandatory locking mode changed, then + * notify the vnode. We do this under the inode lock to prevent + * racing calls to vop_vnode_change. + */ + mandlock_after = MANDLOCK(vp, ip->i_d.di_mode); + if (mandlock_before != mandlock_after) { + VOP_VNODE_CHANGE(vp, VCHANGE_FLAGS_ENF_LOCKING, + mandlock_after); + } + + xfs_iunlock(ip, lock_flags); + + /* + * release any dquot(s) inode had kept before chown + */ + if (olddquot1) + xfs_qm_dqrele(olddquot1); + if (olddquot2) + xfs_qm_dqrele(olddquot2); + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + + if (code) { + return code; + } + + if (DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_ATTRIBUTE) && + !(flags & ATTR_DMI)) { + (void) dm_send_namesp_event (DM_EVENT_ATTRIBUTE, bdp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, NULL, NULL, + 0, 0, AT_DELAY_FLAG(flags)); + } + return 0; + + abort_return: + commit_flags |= XFS_TRANS_ABORT; + /* FALLTHROUGH */ + error_return: + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + if (tp) { + xfs_trans_cancel(tp, commit_flags); + } + if (lock_flags != 0) { + xfs_iunlock(ip, lock_flags); + } + return code; +} /* xfs_setattr */ + + +/* + * xfs_access + * Null conversion from vnode mode bits to inode mode bits, as in efs. + */ +/*ARGSUSED*/ +STATIC int +xfs_access( + bhv_desc_t *bdp, + int mode, + cred_t *credp) +{ + xfs_inode_t *ip; + int error; + + vn_trace_entry(BHV_TO_VNODE(bdp), "xfs_access", + (inst_t *)__return_address); + + ip = XFS_BHVTOI(bdp); + xfs_ilock(ip, XFS_ILOCK_SHARED); + error = xfs_iaccess(ip, mode, credp); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return error; +} + + +/* + * xfs_readlink + * + */ +/*ARGSUSED*/ +STATIC int +xfs_readlink( + bhv_desc_t *bdp, + uio_t *uiop, + cred_t *credp) +{ + xfs_inode_t *ip; + int count; + xfs_off_t offset; + int pathlen; + vnode_t *vp; + int error = 0; + xfs_mount_t *mp; + xfs_fsblock_t firstblock; + int nmaps; + xfs_bmbt_irec_t mval[SYMLINK_MAPS]; + xfs_daddr_t d; + int byte_cnt; + int n; + xfs_buf_t *bp; + + vp = BHV_TO_VNODE(bdp); + + vn_trace_entry(vp, "xfs_readlink", (inst_t *)__return_address); + + if (vp->v_type != VLNK) + return XFS_ERROR(EINVAL); + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + xfs_ilock(ip, XFS_ILOCK_SHARED); + + ASSERT((ip->i_d.di_mode & IFMT) == IFLNK); + + offset = uiop->uio_offset; + count = uiop->uio_resid; + + if (offset < 0) { + error = XFS_ERROR(EINVAL); + goto error_return; + } + if (count <= 0) { + error = 0; + goto error_return; + } + + if (!(uiop->uio_fmode & FINVIS)) { + xfs_ichgtime(ip, XFS_ICHGTIME_ACC); + } + + /* + * See if the symlink is stored inline. + */ + pathlen = (int)ip->i_d.di_size; + + if (ip->i_df.if_flags & XFS_IFINLINE) { + error = uiomove(ip->i_df.if_u1.if_data, pathlen, UIO_READ, uiop); + } + else { + /* + * Symlink not inline. Call bmap to get it in. + */ + nmaps = SYMLINK_MAPS; + firstblock = NULLFSBLOCK; + + error = xfs_bmapi(NULL, ip, 0, XFS_B_TO_FSB(mp, pathlen), + 0, &firstblock, 0, mval, &nmaps, NULL); + + if (error) { + goto error_return; + } + + for (n = 0; n < nmaps; n++) { + d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); + byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); + bp = xfs_buf_read(mp->m_ddev_targp, d, + BTOBB(byte_cnt), 0); + error = XFS_BUF_GETERROR(bp); + if (error) { + xfs_buf_relse(bp); + goto error_return; + } + if (pathlen < byte_cnt) + byte_cnt = pathlen; + pathlen -= byte_cnt; + + error = uiomove(XFS_BUF_PTR(bp), byte_cnt, + UIO_READ, uiop); + xfs_buf_relse (bp); + } + + } + + +error_return: + + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + return error; +} + +/* + * xfs_fsync + * + * This is called to sync the inode and its data out to disk. + * We need to hold the I/O lock while flushing the data, and + * the inode lock while flushing the inode. The inode lock CANNOT + * be held while flushing the data, so acquire after we're done + * with that. + */ +/*ARGSUSED*/ +STATIC int +xfs_fsync( + bhv_desc_t *bdp, + int flag, + cred_t *credp, + xfs_off_t start, + xfs_off_t stop) +{ + xfs_inode_t *ip; + int error; + /* REFERENCED */ + int error2; + /* REFERENCED */ + int syncall; + vnode_t *vp; + xfs_trans_t *tp; + + vp = BHV_TO_VNODE(bdp); + + vn_trace_entry(vp, "xfs_fsync", (inst_t *)__return_address); + + ip = XFS_BHVTOI(bdp); + + ASSERT(start >= 0 && stop >= -1); + + if (XFS_FORCED_SHUTDOWN(ip->i_mount)) + return XFS_ERROR(EIO); + + xfs_ilock(ip, XFS_IOLOCK_EXCL); + + syncall = error = error2 = 0; + + if (stop == -1) { + ASSERT(start >= 0); + if (start == 0) + syncall = 1; + stop = xfs_file_last_byte(ip); + } + + /* + * If we're invalidating, always flush since we want to + * tear things down. Otherwise, don't flush anything if + * we're not dirty. + */ + if (flag & FSYNC_INVAL) { + if (ip->i_df.if_flags & XFS_IFEXTENTS && + ip->i_df.if_bytes > 0) { + VOP_FLUSHINVAL_PAGES(vp, start, -1, FI_REMAPF_LOCKED); + } + ASSERT(syncall == 0 || (VN_CACHED(vp) == 0)); + } else { + /* + * In the non-invalidating case, calls to fsync() do not + * flush all the dirty mmap'd pages. That requires a + * call to msync(). + */ + VOP_FLUSH_PAGES(vp, start, -1, + (flag & FSYNC_WAIT) ? 0 : XFS_B_ASYNC, + FI_NONE, error2); + } + + if (error2) { + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return XFS_ERROR(error2); + } + + /* + * Make sure that we flushed everything in a full sync. + * We used to assert that i_delayed_blks was 0 here, + * but we can't do that since xfs_allocstore() could + * come in and add more even though we have the I/O + * lock here. All it needs to do so is the inode lock, + * and we don't want to force it to acquire the I/O + * lock unnecessarily. + */ + ASSERT(!(flag & (FSYNC_INVAL | FSYNC_WAIT)) || + syncall == 0 || (ip->i_iocore.io_queued_bufs == 0)); + + /* + * We always need to make sure that the required inode state + * is safe on disk. The vnode might be clean but because + * of committed transactions that haven't hit the disk yet. + * Likewise, there could be unflushed non-transactional + * changes to the inode core that have to go to disk. + * + * The following code depends on one assumption: that + * any transaction that changes an inode logs the core + * because it has to change some field in the inode core + * (typically nextents or nblocks). That assumption + * implies that any transactions against an inode will + * catch any non-transactional updates. If inode-altering + * transactions exist that violate this assumption, the + * code breaks. Right now, it figures that if the involved + * update_* field is clear and the inode is unpinned, the + * inode is clean. Either it's been flushed or it's been + * committed and the commit has hit the disk unpinning the inode. + * (Note that xfs_inode_item_format() called at commit clears + * the update_* fields.) + */ + if (!(flag & FSYNC_DATA)) { + xfs_ilock(ip, XFS_ILOCK_SHARED); + + if (ip->i_update_core == 0) { + /* + * Timestamps/size haven't changed since last inode + * flush or inode transaction commit. That means + * either nothing got written or a transaction + * committed which caught the updates. If the + * latter happened and the transaction hasn't + * hit the disk yet, the inode will be still + * be pinned. If it is, force the log. + */ + if (xfs_ipincount(ip) == 0) { + xfs_iunlock(ip, XFS_IOLOCK_EXCL | + XFS_ILOCK_SHARED); + } else { + xfs_iunlock(ip, XFS_IOLOCK_EXCL | + XFS_ILOCK_SHARED); + xfs_log_force(ip->i_mount, (xfs_lsn_t)0, + XFS_LOG_FORCE | + ((flag & FSYNC_WAIT) + ? XFS_LOG_SYNC : 0)); + } + error = 0; + } else { + /* + * Kick off a transaction to log the inode + * core to get the updates. Make it + * sync if FSYNC_WAIT is passed in (which + * is done by everybody but specfs). The + * sync transaction will also force the log. + */ + xfs_iunlock(ip, XFS_ILOCK_SHARED); + tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_FSYNC_TS); + if ((error = xfs_trans_reserve(tp, 0, + XFS_FSYNC_TS_LOG_RES(ip->i_mount), + 0, 0, 0))) { + xfs_trans_cancel(tp, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return error; + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + + /* + * Note - it's possible that we might have pushed + * ourselves out of the way during trans_reserve + * which would flush the inode. But there's no + * guarantee that the inode buffer has actually + * gone out yet (it's delwri). Plus the buffer + * could be pinned anyway if it's part of an + * inode in another recent transaction. So we + * play it safe and fire off the transaction anyway. + */ + xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + if (flag & FSYNC_WAIT) + xfs_trans_set_sync(tp); + error = xfs_trans_commit(tp, 0, NULL); + + xfs_iunlock(ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL); + } + } else { + /* + * We don't care about the timestamps here. We + * only care about the size field growing on us + * and forcing any space allocation transactions. + * We have to flush changes to the size fields + * otherwise we could write out data that + * becomes inaccessible after a crash. + */ + xfs_ilock(ip, XFS_ILOCK_SHARED); + + if (ip->i_update_size == 0) { + /* + * Force the log if the inode is pinned. + * That ensures that all transactions committed + * against the inode hit the disk. This may do + * too much work but it's safe. + */ + if (xfs_ipincount(ip) == 0) { + xfs_iunlock(ip, XFS_IOLOCK_EXCL | + XFS_ILOCK_SHARED); + } else { + xfs_iunlock(ip, XFS_IOLOCK_EXCL | + XFS_ILOCK_SHARED); + xfs_log_force(ip->i_mount, (xfs_lsn_t)0, + XFS_LOG_FORCE | + ((flag & FSYNC_WAIT) + ? XFS_LOG_SYNC : 0)); + } + error = 0; + } else { + /* + * Kick off a sync transaction to log the inode + * core. The transaction has to be sync since + * we need these updates to guarantee that the + * data written will be seen. The sync + * transaction will also force the log. + */ + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_FSYNC_TS); + if ((error = xfs_trans_reserve(tp, 0, + XFS_FSYNC_TS_LOG_RES(ip->i_mount), + 0, 0, 0))) { + xfs_trans_cancel(tp, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return error; + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + + /* + * Note - it's possible that we might have pushed + * ourselves out of the way during trans_reserve + * which would flush the inode. But there's no + * guarantee that the inode buffer has actually + * gone out yet (it's delwri). Plus the buffer + * could be pinned anyway if it's part of an + * inode in another recent transaction. So we + * play it safe and fire off the transaction anyway. + */ + xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + if (flag & FSYNC_WAIT) + xfs_trans_set_sync(tp); + error = xfs_trans_commit(tp, 0, NULL); + + xfs_iunlock(ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL); + } + } + return error; +} + + +#if 0 +/* + * This is a utility routine for xfs_inactive. It is called when a + * transaction attempting to free up the disk space for a file encounters + * an error. It cancels the old transaction and starts up a new one + * to be used to free up the inode. It also sets the inode size and extent + * counts to 0 and frees up any memory being used to store inline data, + * extents, or btree roots. + */ +STATIC void +xfs_itruncate_cleanup( + xfs_trans_t **tpp, + xfs_inode_t *ip, + int commit_flags, + int fork) +{ + xfs_mount_t *mp; + /* REFERENCED */ + int error; + + mp = ip->i_mount; + if (*tpp) { + xfs_trans_cancel(*tpp, commit_flags | XFS_TRANS_ABORT); + } + xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + *tpp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); + error = xfs_trans_reserve(*tpp, 0, XFS_IFREE_LOG_RES(mp), 0, 0, + XFS_DEFAULT_LOG_COUNT); + if (error) { + return; + } + + xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ijoin(*tpp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + xfs_trans_ihold(*tpp, ip); + + xfs_idestroy_fork(ip, fork); + + if (fork == XFS_DATA_FORK) { + ip->i_d.di_nblocks = 0; + ip->i_d.di_nextents = 0; + ip->i_d.di_size = 0; + } else { + ip->i_d.di_anextents = 0; + } + xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE); +} +#endif + +/* + * This is called by xfs_inactive to free any blocks beyond eof, + * when the link count isn't zero. + */ +STATIC int +xfs_inactive_free_eofblocks( + xfs_mount_t *mp, + xfs_inode_t *ip) +{ + xfs_trans_t *tp; + int error; + xfs_fileoff_t end_fsb; + xfs_fileoff_t last_fsb; + xfs_filblks_t map_len; + int nimaps; + xfs_bmbt_irec_t imap; + xfs_fsblock_t first_block; + + /* + * Figure out if there are any blocks beyond the end + * of the file. If not, then there is nothing to do. + */ + end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_d.di_size)); + last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAX_FILE_OFFSET); + map_len = last_fsb - end_fsb; + if (map_len <= 0) + return (0); + + nimaps = 1; + first_block = NULLFSBLOCK; + xfs_ilock(ip, XFS_ILOCK_SHARED); + error = xfs_bmapi(NULL, ip, end_fsb, map_len, 0, + &first_block, 0, &imap, &nimaps, + NULL); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + if (!error && (nimaps != 0) && + (imap.br_startblock != HOLESTARTBLOCK)) { + /* + * Attach the dquots to the inode up front. + */ + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) { + if (XFS_NOT_DQATTACHED(mp, ip)) { + if ((error = xfs_qm_dqattach(ip, 0))) + return (error); + } + } + + /* + * There are blocks after the end of file. + * Free them up now by truncating the file to + * its current size. + */ + tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); + + /* + * Do the xfs_itruncate_start() call before + * reserving any log space because + * itruncate_start will call into the buffer + * cache and we can't + * do that within a transaction. + */ + xfs_ilock(ip, XFS_IOLOCK_EXCL); + xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, + ip->i_d.di_size); + + error = xfs_trans_reserve(tp, 0, + XFS_ITRUNCATE_LOG_RES(mp), + 0, XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT); + if (error) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + xfs_trans_cancel(tp, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return (error); + } + + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, + XFS_IOLOCK_EXCL | + XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + + error = xfs_itruncate_finish(&tp, ip, + ip->i_d.di_size, + XFS_DATA_FORK, + 0); + /* + * If we get an error at this point we + * simply don't bother truncating the file. + */ + if (error) { + xfs_trans_cancel(tp, + (XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT)); + } else { + error = xfs_trans_commit(tp, + XFS_TRANS_RELEASE_LOG_RES, + NULL); + } + xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + } + return (error); +} + +/* + * Free a symlink that has blocks associated with it. + */ +STATIC int +xfs_inactive_symlink_rmt( + xfs_inode_t *ip, + xfs_trans_t **tpp) +{ + xfs_buf_t *bp; + int committed; + int done; + int error; + xfs_fsblock_t first_block; + xfs_bmap_free_t free_list; + int i; + xfs_mount_t *mp; + xfs_bmbt_irec_t mval[SYMLINK_MAPS]; + int nmaps; + xfs_trans_t *ntp; + int size; + xfs_trans_t *tp; + + tp = *tpp; + mp = ip->i_mount; + ASSERT(ip->i_d.di_size > XFS_IFORK_DSIZE(ip)); + /* + * We're freeing a symlink that has some + * blocks allocated to it. Free the + * blocks here. We know that we've got + * either 1 or 2 extents and that we can + * free them all in one bunmapi call. + */ + ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2); + if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + xfs_trans_cancel(tp, 0); + *tpp = NULL; + return error; + } + /* + * Lock the inode, fix the size, and join it to the transaction. + * Hold it so in the normal path, we still have it locked for + * the second transaction. In the error paths we need it + * held so the cancel won't rele it, see below. + */ + xfs_ilock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + size = (int)ip->i_d.di_size; + ip->i_d.di_size = 0; + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ihold(tp, ip); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + /* + * Find the block(s) so we can inval and unmap them. + */ + done = 0; + XFS_BMAP_INIT(&free_list, &first_block); + nmaps = sizeof(mval) / sizeof(mval[0]); + if ((error = xfs_bmapi(tp, ip, 0, XFS_B_TO_FSB(mp, size), + XFS_BMAPI_METADATA, &first_block, 0, mval, &nmaps, + &free_list))) + goto error0; + /* + * Invalidate the block(s). + */ + for (i = 0; i < nmaps; i++) { + bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, + XFS_FSB_TO_DADDR(mp, mval[i].br_startblock), + XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0); + xfs_trans_binval(tp, bp); + } + /* + * Unmap the dead block(s) to the free_list. + */ + if ((error = xfs_bunmapi(tp, ip, 0, size, XFS_BMAPI_METADATA, nmaps, + &first_block, &free_list, &done))) + goto error1; + ASSERT(done); + /* + * Commit the first transaction. This logs the EFI and the inode. + */ + if ((error = xfs_bmap_finish(&tp, &free_list, first_block, &committed))) + goto error1; + /* + * The transaction must have been committed, since there were + * actually extents freed by xfs_bunmapi. See xfs_bmap_finish. + * The new tp has the extent freeing and EFDs. + */ + ASSERT(committed); + /* + * The first xact was committed, so add the inode to the new one. + * Mark it dirty so it will be logged and moved forward in the log as + * part of every commit. + */ + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ihold(tp, ip); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + /* + * Get a new, empty transaction to return to our caller. + */ + ntp = xfs_trans_dup(tp); + /* + * Commit the transaction containing extent freeing and EFD's. + * If we get an error on the commit here or on the reserve below, + * we need to unlock the inode since the new transaction doesn't + * have the inode attached. + */ + error = xfs_trans_commit(tp, 0, NULL); + tp = ntp; + if (error) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + goto error0; + } + /* + * Remove the memory for extent descriptions (just bookkeeping). + */ + if (ip->i_df.if_bytes) + xfs_idata_realloc(ip, -ip->i_df.if_bytes, XFS_DATA_FORK); + ASSERT(ip->i_df.if_bytes == 0); + /* + * Put an itruncate log reservation in the new transaction + * for our caller. + */ + if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + goto error0; + } + /* + * Return with the inode locked but not joined to the transaction. + */ + *tpp = tp; + return 0; + + error1: + xfs_bmap_cancel(&free_list); + error0: + /* + * Have to come here with the inode locked and either + * (held and in the transaction) or (not in the transaction). + * If the inode isn't held then cancel would iput it, but + * that's wrong since this is inactive and the vnode ref + * count is 0 already. + * Cancel won't do anything to the inode if held, but it still + * needs to be locked until the cancel is done, if it was + * joined to the transaction. + */ + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); + xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + *tpp = NULL; + return error; + +} + +STATIC int +xfs_inactive_symlink_local( + xfs_inode_t *ip, + xfs_trans_t **tpp) +{ + int error; + ASSERT(ip->i_d.di_size <= XFS_IFORK_DSIZE(ip)); + /* + * We're freeing a symlink which fit into + * the inode. Just free the memory used + * to hold the old symlink. + */ + error = xfs_trans_reserve(*tpp, 0, + XFS_ITRUNCATE_LOG_RES(ip->i_mount), + 0, XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT); + + if (error) { + xfs_trans_cancel(*tpp, 0); + *tpp = NULL; + return (error); + } + xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + + /* + * Zero length symlinks _can_ exist. + */ + if (ip->i_df.if_bytes > 0) { + xfs_idata_realloc(ip, + -(ip->i_df.if_bytes), + XFS_DATA_FORK); + ASSERT(ip->i_df.if_bytes == 0); + } + return (0); +} + +/* + * + */ +STATIC int +xfs_inactive_attrs( + xfs_inode_t *ip, + xfs_trans_t **tpp, + int *commitflags) +{ + xfs_trans_t *tp; + int error; + xfs_mount_t *mp; + + ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE)); + tp = *tpp; + mp = ip->i_mount; + ASSERT(ip->i_d.di_forkoff != 0); + xfs_trans_commit(tp, *commitflags, NULL); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + *commitflags = 0; + + error = xfs_attr_inactive(ip); + if (error) { + *tpp = NULL; + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return (error); /* goto out*/ + } + + tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); + error = xfs_trans_reserve(tp, 0, + XFS_IFREE_LOG_RES(mp), + 0, 0, + XFS_DEFAULT_LOG_COUNT); + if (error) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + xfs_trans_cancel(tp, 0); + *tpp = NULL; + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return (error); + } + + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + xfs_idestroy_fork(ip, XFS_ATTR_FORK); + + ASSERT(ip->i_d.di_anextents == 0); + + *tpp = tp; + return (0); +} + +/*ARGSUSED*/ +STATIC int +xfs_release( + bhv_desc_t *bdp) +{ + xfs_inode_t *ip; + vnode_t *vp; + xfs_mount_t *mp; + int error; + + vp = BHV_TO_VNODE(bdp); + ip = XFS_BHVTOI(bdp); + + if ((vp->v_type != VREG) || (ip->i_d.di_mode == 0)) { + return 0; + } + + /* If we are in the NFS reference cache then don't do this now */ + if (ip->i_refcache) + return 0; + + mp = ip->i_mount; + + if (ip->i_d.di_nlink != 0) { + if ((((ip->i_d.di_mode & IFMT) == IFREG) && + ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0)) && + (ip->i_df.if_flags & XFS_IFEXTENTS)) && + (!(ip->i_d.di_flags & XFS_DIFLAG_PREALLOC))) { + if ((error = xfs_inactive_free_eofblocks(mp, ip))) + return (error); + } + } + + if (vp->v_type == VREG) { + XFS_INODE_CLEAR_READ_AHEAD(&ip->i_iocore); + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_iocore_reset(&ip->i_iocore); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + } + + return 0; +} + +/* + * xfs_inactive + * + * This is called when the vnode reference count for the vnode + * goes to zero. If the file has been unlinked, then it must + * now be truncated. Also, we clear all of the read-ahead state + * kept for the inode here since the file is now closed. + */ +/*ARGSUSED*/ +STATIC int +xfs_inactive( + bhv_desc_t *bdp, + cred_t *credp) +{ + xfs_inode_t *ip; + /* REFERENCED */ + vnode_t *vp; + xfs_trans_t *tp; + xfs_mount_t *mp; + int error; + int commit_flags; + int truncate; + + vp = BHV_TO_VNODE(bdp); + + vn_trace_entry(vp, "xfs_inactive", (inst_t *)__return_address); + + ip = XFS_BHVTOI(bdp); + + /* + * If the inode is already free, then there can be nothing + * to clean up here. + */ + if (ip->i_d.di_mode == 0) { + ASSERT(ip->i_df.if_real_bytes == 0); + ASSERT(ip->i_df.if_broot_bytes == 0); + return VN_INACTIVE_CACHE; + } + + /* + * Only do a truncate if it's a regular file with + * some actual space in it. It's OK to look at the + * inode's fields without the lock because we're the + * only one with a reference to the inode. + */ + truncate = ((ip->i_d.di_nlink == 0) && + ((ip->i_d.di_size != 0) || (ip->i_d.di_nextents > 0)) && + ((ip->i_d.di_mode & IFMT) == IFREG)); + + mp = ip->i_mount; + + if (ip->i_d.di_nlink == 0 && + DM_EVENT_ENABLED(vp->v_vfsp, ip, DM_EVENT_DESTROY)) { + (void) dm_send_destroy_event(bdp, DM_RIGHT_NULL); + } + /* + * We don't mark the TEARDOWN flag, so + * xfs_inactive always returns VN_INACTIVE_CACHE. + */ + ASSERT(! (vp->v_flag & VINACTIVE_TEARDOWN)); + + error = 0; + if (ip->i_d.di_nlink != 0) { + if ((((ip->i_d.di_mode & IFMT) == IFREG) && + ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0)) && + (ip->i_df.if_flags & XFS_IFEXTENTS)) && + (!(ip->i_d.di_flags & XFS_DIFLAG_PREALLOC) || + (ip->i_delayed_blks != 0))) { + if ((error = xfs_inactive_free_eofblocks(mp, ip))) + return (VN_INACTIVE_CACHE); + } + goto out; + } + + ASSERT(ip->i_d.di_nlink == 0); + + if (XFS_IS_QUOTA_ON(mp) && + ip->i_ino != mp->m_sb.sb_uquotino && + ip->i_ino != mp->m_sb.sb_gquotino) { + if (XFS_NOT_DQATTACHED(mp, ip)) { + if ((error = xfs_qm_dqattach(ip, 0))) + return (VN_INACTIVE_CACHE); + } + } + tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); + if (truncate) { + /* + * Do the xfs_itruncate_start() call before + * reserving any log space because itruncate_start + * will call into the buffer cache and we can't + * do that within a transaction. + */ + xfs_ilock(ip, XFS_IOLOCK_EXCL); + + xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0); + + error = xfs_trans_reserve(tp, 0, + XFS_ITRUNCATE_LOG_RES(mp), + 0, XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT); + if (error) { + /* Don't call itruncate_cleanup */ + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + xfs_trans_cancel(tp, 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return (VN_INACTIVE_CACHE); + } + + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + + /* + * normally, we have to run xfs_itruncate_finish sync. + * But if filesystem is wsync and we're in the inactive + * path, then we know that nlink == 0, and that the + * xaction that made nlink == 0 is permanently committed + * since xfs_remove runs as a synchronous transaction. + */ + error = xfs_itruncate_finish(&tp, ip, 0, XFS_DATA_FORK, + (!(mp->m_flags & XFS_MOUNT_WSYNC) ? 1 : 0)); + commit_flags = XFS_TRANS_RELEASE_LOG_RES; + + if (error) { + xfs_trans_cancel(tp, commit_flags | XFS_TRANS_ABORT); + xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + return (VN_INACTIVE_CACHE); + } + } else if ((ip->i_d.di_mode & IFMT) == IFLNK) { + + /* + * If we get an error while cleaning up a + * symlink we bail out. + */ + error = (ip->i_d.di_size > XFS_IFORK_DSIZE(ip)) ? + xfs_inactive_symlink_rmt(ip, &tp) : + xfs_inactive_symlink_local(ip, &tp); + + if (error) { + ASSERT(tp == NULL); + return (VN_INACTIVE_CACHE); + } + + xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + commit_flags = XFS_TRANS_RELEASE_LOG_RES; + + } else { + error = xfs_trans_reserve(tp, 0, + XFS_IFREE_LOG_RES(mp), + 0, 0, + XFS_DEFAULT_LOG_COUNT); + if (error) { + ASSERT(XFS_FORCED_SHUTDOWN(mp)); + xfs_trans_cancel(tp, 0); + return (VN_INACTIVE_CACHE); + } + + xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + commit_flags = 0; + } + + /* + * If there are attributes associated with the file + * then blow them away now. The code calls a routine + * that recursively deconstructs the attribute fork. + * We need to just commit the current transaction + * because we can't use it for xfs_attr_inactive(). + */ + if (ip->i_d.di_anextents > 0) { + error = xfs_inactive_attrs(ip, &tp, &commit_flags); + /* + * If we got an error, the transaction is already + * cancelled, and the inode is unlocked. Just get out. + */ + if (error) + return (VN_INACTIVE_CACHE); + } else if (ip->i_afp) { + xfs_idestroy_fork(ip, XFS_ATTR_FORK); + } + + /* + * Free the inode. + */ + error = xfs_ifree(tp, ip); + if (error) { + /* + * If we fail to free the inode, shut down. The cancel + * might do that, we need to make sure. Otherwise the + * inode might be lost for a long time or forever. + */ + if (!XFS_FORCED_SHUTDOWN(tp->t_mountp)) { + cmn_err(CE_NOTE, + "xfs_inactive: xfs_ifree() returned an error = %d on %s", + error,tp->t_mountp->m_fsname); + xfs_force_shutdown(tp->t_mountp, XFS_METADATA_IO_ERROR); + } + xfs_trans_cancel(tp, commit_flags | XFS_TRANS_ABORT); + } else { + /* + * Credit the quota account(s). The inode is gone. + */ + if (XFS_IS_QUOTA_ON(tp->t_mountp)) + (void) xfs_trans_mod_dquot_byino(tp, ip, + XFS_TRANS_DQ_ICOUNT, + -1); + + /* + * Just ignore errors at this point. There is + * nothing we can do except to try to keep going. + */ + (void) xfs_trans_commit(tp, commit_flags, NULL); + } + /* + * Release the dquots held by inode, if any. + */ + if (ip->i_udquot || ip->i_gdquot) + xfs_qm_dqdettach_inode(ip); + + xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); + + out: + /* + * Clear all the inode's read-ahead state. We need to take + * the lock here even though the inode is inactive, because + * someone might be in xfs_sync() where we play with + * inodes without taking references. Of course, this is only + * necessary if it is a regular file since no other inodes + * use the read ahead state. Also reset the read/write io + * sizes. Like read-ahead, only regular files override the + * default read/write io sizes. + * Bug 516806: We do not need the ilock around the clearing + * of the readahead state since it is protected by its own + * mutex now. vfs_sync->buffer_cache->read path we also take + * this mutex so this is not dangerous. + */ + if (vp->v_type == VREG) { + XFS_INODE_CLEAR_READ_AHEAD(&ip->i_iocore); + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_iocore_reset(&ip->i_iocore); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + } + + return VN_INACTIVE_CACHE; +} + + +/* + * xfs_lookup + */ +/*ARGSUSED*/ +STATIC int +xfs_lookup( + bhv_desc_t *dir_bdp, + char *name, + vnode_t **vpp, + pathname_t *pnp, + int flags, + vnode_t *rdir, + cred_t *credp) +{ + xfs_inode_t *dp, *ip; + struct vnode *vp; + xfs_ino_t e_inum; + int error; + uint lock_mode; + uint lookup_flags; + uint dir_unlocked; + vnode_t *dir_vp; + + dir_vp = BHV_TO_VNODE(dir_bdp); + + vn_trace_entry(dir_vp, "xfs_lookup", (inst_t *)__return_address); + + /* + * If it's not a directory, fail the request. + */ + if (dir_vp->v_type != VDIR) { + return XFS_ERROR(ENOTDIR); + } + + dp = XFS_BHVTOI(dir_bdp); + + if (XFS_FORCED_SHUTDOWN(dp->i_mount)) + return XFS_ERROR(EIO); + + lock_mode = xfs_ilock_map_shared(dp); + + /* + * If the directory has been removed, then fail all lookups. + */ + if (dp->i_d.di_nlink == 0) { + xfs_iunlock_map_shared(dp, lock_mode); + return XFS_ERROR(ENOENT); + } + + lookup_flags = DLF_IGET; + if (lock_mode == XFS_ILOCK_SHARED) { + lookup_flags |= DLF_LOCK_SHARED; + } + error = xfs_dir_lookup_int(NULL, dir_bdp, lookup_flags, name, pnp, + &e_inum, &ip, &dir_unlocked); + if (error) { + xfs_iunlock_map_shared(dp, lock_mode); + return error; + } + + vp = XFS_ITOV(ip); + + if (dir_unlocked) { + /* + * If the directory had to be unlocked in the call, + * then its permissions may have changed. Make sure + * that it is OK to give this inode back to the caller. + */ + if ((error = xfs_iaccess(dp, IEXEC, credp))) { + xfs_iunlock_map_shared(dp, lock_mode); + VN_RELE(vp); + return error; + } + } + ITRACE(ip); + + xfs_iunlock_map_shared(dp, lock_mode); + + *vpp = vp; + + return 0; +} + +#ifdef XFS_RW_TRACE +STATIC void +xfs_ctrunc_trace( + int tag, + xfs_inode_t *ip) +{ + if (ip->i_rwtrace == NULL) { + return; + } + + ktrace_enter(ip->i_rwtrace, + (void*)((long)tag), + (void*)ip, + (void*)((long)private.p_cpuid), + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0, + (void*)0); +} +#endif /* XFS_RW_TRACE */ + +STATIC void xfs_create_broken(xfs_mount_t *, xfs_inode_t *, xfs_ino_t, uint); + +#define XFS_CREATE_NEW_MAXTRIES 10000 + +/* + * xfs_create (create a new file). + * It might still find name exists out there, though. + * But vpp, doens't point at a vnode. + */ +STATIC int +xfs_create( + bhv_desc_t *dir_bdp, + char *name, + vattr_t *vap, + int flags, + int I_mode, + vnode_t **vpp, + cred_t *credp) +{ + vnode_t *dir_vp; + xfs_inode_t *dp, *ip; + vnode_t *vp=NULL; + xfs_trans_t *tp; + xfs_ino_t e_inum; + xfs_mount_t *mp; + dev_t rdev; + int error; + xfs_bmap_free_t free_list; + xfs_fsblock_t first_block; + boolean_t dp_joined_to_trans; + boolean_t truncated; + boolean_t created = B_FALSE; + boolean_t inode_change = B_FALSE; + int dm_event_sent = 0; + uint cancel_flags; + int committed; + uint dir_unlocked; + xfs_prid_t prid; + struct xfs_dquot *udqp, *gdqp; + uint resblks; + int dm_di_mode; + int xfs_create_retries = 0; + xfs_ino_t e_inum_saved; /* for retry trap code */ + int namelen; + + ASSERT(!*vpp); + dir_vp = BHV_TO_VNODE(dir_bdp); + dp = XFS_BHVTOI(dir_bdp); + + vn_trace_entry(dir_vp, "xfs_create", (inst_t *)__return_address); + + dm_di_mode = vap->va_mode|VTTOIF(vap->va_type); + namelen = strlen(name); + if (namelen >= MAXNAMELEN) + return XFS_ERROR(EINVAL); + + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) { + error = xfs_dm_send_create_event(dir_bdp, name, + dm_di_mode, &dm_event_sent); + if (error) + return error; + } + + /* Return through std_return after this point. */ + + mp = dp->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + udqp = gdqp = NULL; + if (vap->va_mask & AT_PROJID) + prid = (xfs_prid_t)vap->va_projid; + else + prid = (xfs_prid_t)dfltprid; + + /* + * Make sure that we have allocated dquot(s) on disk. + */ + if (XFS_IS_QUOTA_ON(mp)) { + error = xfs_qm_vop_dqalloc(mp, dp, + current->fsuid, current->fsgid, + XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, + &udqp, &gdqp); + if (error) + goto std_return; + } + + try_again: + ip = NULL; + dp_joined_to_trans = B_FALSE; + truncated = B_FALSE; + + tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE); + cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + resblks = XFS_CREATE_SPACE_RES(mp, namelen); + /* + * Initially assume that the file does not exist and + * reserve the resources for that case. If that is not + * the case we'll drop the one we have and get a more + * appropriate transaction later. + */ + error = xfs_trans_reserve(tp, resblks, XFS_CREATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); + if (error == ENOSPC) { + resblks = 0; + error = xfs_trans_reserve(tp, 0, XFS_CREATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT); + } + if (error) { + cancel_flags = 0; + dp = NULL; + goto error_return; + } + + xfs_ilock(dp, XFS_ILOCK_EXCL); + + /* + * If the directory has been removed, then fail all creates. + */ + if (dp->i_d.di_nlink == 0) { + error = XFS_ERROR(ENOENT); + goto error_return; + } + + + /* + * At this point we cannot do an xfs_iget() of the entry named + * since we are already holding a log reservation and it could + * be in xfs_inactive waiting for a log reservation. We'd just + * end up waiting forever for the inactive to complete. Instead + * we just look to see if there is an entry with the name. In + * the case where there is not, we didn't need the inode anyway. + * In the case where there is an entry, we'll get it later after + * dropping our transaction. + */ + error = xfs_dir_lookup_int(NULL, dir_bdp, DLF_NODNLC, name, + NULL, &e_inum, NULL, NULL); + if (error && (error != ENOENT)) { + goto error_return; + } + + XFS_BMAP_INIT(&free_list, &first_block); + + if (error == ENOENT) { + + ASSERT(ip == NULL); + + /* + * XPG4 says create cannot allocate a file if the + * file size limit is set to 0. + */ + if (flags & VZFS) { + error = XFS_ERROR(EFBIG); + goto error_return; + } + + /* + * Reserve disk quota and the inode. + */ + if (XFS_IS_QUOTA_ON(mp)) { + if (xfs_trans_reserve_quota(tp, udqp, gdqp, resblks, + 1, 0)) { + error = EDQUOT; + goto error_return; + } + } + if (resblks == 0 && + (error = XFS_DIR_CANENTER(mp, tp, dp, name, namelen))) + goto error_return; + rdev = (vap->va_mask & AT_RDEV) ? vap->va_rdev : NODEV; + error = xfs_dir_ialloc(&tp, dp, + MAKEIMODE(vap->va_type,vap->va_mode), 1, + rdev, credp, prid, resblks > 0, + &ip, &committed); + if (error) { + if (error == ENOSPC) + goto error_return; + goto abort_return; + } + ITRACE(ip); + + /* + * At this point, we've gotten a newly allocated inode. + * It is locked (and joined to the transaction). + */ + + ASSERT(ismrlocked (&ip->i_lock, MR_UPDATE)); + + /* + * Now we join the directory inode to the transaction. + * We do not do it earlier because xfs_dir_ialloc + * might commit the previous transaction (and release + * all the locks). + */ + + VN_HOLD(dir_vp); + xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); + dp_joined_to_trans = B_TRUE; + + error = XFS_DIR_CREATENAME(mp, tp, dp, name, namelen, ip->i_ino, + &first_block, &free_list, + resblks ? resblks - XFS_IALLOC_SPACE_RES(mp) : 0); + if (error) { + ASSERT(error != ENOSPC); + goto abort_return; + } + xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + + /* + * If this is a synchronous mount, make sure that the + * create transaction goes to disk before returning to + * the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + dp->i_gen++; + + /* + * Attach the dquot(s) to the inodes and modify them incore. + * These ids of the inode couldn't have changed since the new + * inode has been locked ever since it was created. + */ + if (XFS_IS_QUOTA_ON(mp)) + xfs_qm_vop_dqattach_and_dqmod_newinode(tp, ip, udqp, + gdqp); + created = B_TRUE; + } else { + e_inum_saved = e_inum; + + /* + * The file already exists, so we're in the wrong + * transaction for this operation. Cancel the old + * transaction and start a new one. We have to drop + * our locks in doing this. But, we don't care + * if the directory changes. We have already checked + * if the dir exists and is EXEC by the user. + * After all, we already have the vnode held. + * + * All we need to do is truncate it. + */ + xfs_trans_cancel(tp, cancel_flags); + tp = NULL; + + /* + * Now that we've dropped our log reservation, get a + * reference to the inode we are re-creating. If we + * have to drop the directory lock in the call and + * the entry is removed, then just start over. + */ + error = xfs_dir_lookup_int(NULL, dir_bdp, DLF_IGET, name, + NULL, &e_inum, &ip, &dir_unlocked); + if (error) { + if (error == ENOENT) { + if (++xfs_create_retries > + XFS_CREATE_NEW_MAXTRIES) { + xfs_create_broken(mp, dp, + e_inum_saved, dir_unlocked); + error = XFS_ERROR(EFSCORRUPTED); + goto error_return; + } + + ASSERT(dir_unlocked); + xfs_iunlock(dp, XFS_ILOCK_EXCL); + goto try_again; + } + goto error_return; + } + ITRACE(ip); + + xfs_iunlock(dp, XFS_ILOCK_EXCL); + dp = NULL; + + /* + * Done with directory. Don't care about it + * anymore. + */ + + /* + * Since we're at a good, clean point, check for any + * obvious problems and get out if they occur. + */ + vp = XFS_ITOV(ip); + if (!error) { + if (flags & VEXCL) { + error = XFS_ERROR(EEXIST); + } else if (vp->v_type == VDIR) { + error = XFS_ERROR(EISDIR); + } else if (vp->v_type == VREG && + (vap->va_mask & AT_SIZE) && + DM_EVENT_ENABLED (vp->v_vfsp, ip, + DM_EVENT_TRUNCATE)) { + error = xfs_dm_send_data_event( + DM_EVENT_TRUNCATE, + XFS_ITOBHV(ip), + vap->va_size, 0, 0, NULL); + } + } + + if (!error && XFS_IS_QUOTA_ON(mp)) { + if (XFS_NOT_DQATTACHED(mp, ip)) + error = xfs_qm_dqattach(ip, 0); + } + + if (error) { + IRELE(ip); + goto error_return; + } + + /* Need the behaviour lock before the iolock as we are + * potentially going to make a VOP call on vp. */ + VN_BHV_READ_LOCK(&(vp)->v_bh); + + /* + * We need to do the xfs_itruncate_start call before + * reserving any log space in the transaction. + */ + xfs_ilock(ip, XFS_IOLOCK_EXCL); + xfs_ctrunc_trace(XFS_CTRUNC1, ip); + if ((vp->v_type == VREG) && + (vap->va_mask & AT_SIZE) && + ((ip->i_d.di_size != 0) || (ip->i_d.di_nextents != 0))) { + xfs_itruncate_start(ip, XFS_ITRUNC_MAYBE, 0); + } + + /* Once we got the I/O lock we can drop the behaviour + * lock. + */ + VN_BHV_READ_UNLOCK(&(vp)->v_bh); + + tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE_TRUNC); + if ((error = xfs_trans_reserve(tp, 0, + XFS_ITRUNCATE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_ITRUNCATE_LOG_COUNT))) { + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + IRELE(ip); + cancel_flags = 0; + xfs_ctrunc_trace(XFS_CTRUNC2, ip); + goto error_return; + } + + /* + * Now lock inode. + */ + xfs_ilock(ip, XFS_ILOCK_EXCL); + + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + + if (error) { + xfs_ctrunc_trace(XFS_CTRUNC4, ip); + goto error_return; + } + + if (vp->v_type == VREG && (vap->va_mask & AT_SIZE)) { + /* + * Truncate the file. The timestamps must + * be updated whether the file is changed + * or not. + */ + ASSERT(vap->va_size == 0); + if ((ip->i_d.di_size > 0) || (ip->i_d.di_nextents)) { + xfs_ctrunc_trace(XFS_CTRUNC5, ip); + xfs_trans_ihold(tp, ip); + /* + * always signal sync xaction. We're + * truncating an existing file so the + * xaction must be sync regardless + * of whether the filesystem is wsync + * to make the truncate persistent + * in the face of a crash. + */ + error = xfs_itruncate_finish(&tp, ip, + (xfs_fsize_t)0, + XFS_DATA_FORK, 1); + if (error) { + ASSERT(ip->i_transp == tp); + xfs_trans_ihold_release(tp, ip); + goto abort_return; + } + truncated = B_TRUE; + xfs_ichgtime(ip, + XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + } else { + xfs_ichgtime(ip, + XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + } + inode_change = B_TRUE; + + } + xfs_ctrunc_trace(XFS_CTRUNC6, ip); + } + + + /* + * xfs_trans_commit normally decrements the vnode ref count + * when it unlocks the inode. Since we want to return the + * vnode to the caller, we bump the vnode ref count now. + */ + IHOLD(ip); + vp = XFS_ITOV(ip); + + error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); + if (error) { + xfs_bmap_cancel(&free_list); + if (truncated) { + /* + * If we truncated the file, then the inode will + * have been held within the previous transaction + * and must be unlocked now. + */ + xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + ASSERT(vn_count(vp) >= 2); + IRELE(ip); + } + goto abort_rele; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (truncated) { + /* + * If we truncated the file, then the inode will + * have been held within the transaction and must + * be unlocked now. + */ + xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + ASSERT(vn_count(vp) >= 2); + IRELE(ip); + } + if (error) { + IRELE(ip); + tp = NULL; + goto error_return; + } + + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + +#ifdef CELL_CAPABLE + /* + * Propogate the fact that the vnode changed after the + * xfs_inode locks have been released. + */ + if (cell_enabled) { +#pragma mips_frequency_hint NEVER + if (inode_change == B_TRUE) + VOP_VNODE_CHANGE(vp, VCHANGE_FLAGS_TRUNCATED, 0); + } +#endif /* CELL_CAPABLE */ + + *vpp = vp; + + /* Fallthrough to std_return with error = 0 */ + +std_return: + if ( (created || (error != 0 && dm_event_sent != 0)) && + DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp), + DM_EVENT_POSTCREATE)) { + (void) dm_send_namesp_event(DM_EVENT_POSTCREATE, + dir_bdp, DM_RIGHT_NULL, + created ? vn_bhv_lookup_unlocked(VN_BHV_HEAD(vp), &xfs_vnodeops):NULL, + DM_RIGHT_NULL, name, NULL, + dm_di_mode, error, 0); + } + return error; + + abort_return: + cancel_flags |= XFS_TRANS_ABORT; + /* FALLTHROUGH */ + error_return: + + if (tp != NULL) + xfs_trans_cancel(tp, cancel_flags); + + if (!dp_joined_to_trans && (dp != NULL)) + xfs_iunlock(dp, XFS_ILOCK_EXCL); + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + + goto std_return; + + abort_rele: + /* + * Wait until after the current transaction is aborted to + * release the inode. This prevents recursive transactions + * and deadlocks from xfs_inactive. + */ + cancel_flags |= XFS_TRANS_ABORT; + xfs_trans_cancel(tp, cancel_flags); + IRELE(ip); + + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + + goto std_return; +} + + +/* + * xfs_create_broken is a trap routine to isolate the cause of a infinite + * loop condition reported in IRIX 6.4 by PV 522864. If no occurances + * of this error recur (that is, the trap code isn't hit), this routine + * should be removed in future releases. + */ +/* ARGSUSED */ +STATIC void +xfs_create_broken( + xfs_mount_t *mp, + xfs_inode_t *dp, + xfs_ino_t e_inum_saved, + uint dir_unlocked) +{ + cmn_err(CE_WARN, + "xfs_create looping, dir ino 0x%Lx, ino 0x%Lx, %s\n", + dp->i_ino, e_inum_saved, mp->m_fsname); +#ifdef DEBUG + BUG(); +#endif /* DEBUG */ +} + + +/* + * xfs_get_dir_entry is used to get a reference to an inode given + * its parent directory inode and the name of the file. It does + * not lock the child inode, and it unlocks the directory before + * returning. The directory's generation number is returned for + * use by a later call to xfs_lock_dir_and_entry. + */ +STATIC int +xfs_get_dir_entry( + xfs_inode_t *dp, + char *name, + xfs_inode_t **ipp, /* inode of entry 'name' */ + int *dir_generationp) +{ + xfs_inode_t *ip; + xfs_ino_t e_inum; + int error; + uint dir_unlocked; + + xfs_ilock(dp, XFS_ILOCK_EXCL); + + /* + * If the link count on the directory is 0, there are no + * entries to look for. + */ + if (dp->i_d.di_nlink == 0) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + *ipp = NULL; + return XFS_ERROR(ENOENT); + } + + if (*ipp == NULL) { + error = xfs_dir_lookup_int(NULL, XFS_ITOBHV(dp), DLF_IGET, + name, NULL, &e_inum, &ip, + &dir_unlocked); + if (error) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + *ipp = NULL; + return error; + } + ASSERT((e_inum != 0) && ip); + } else { + VN_HOLD(XFS_ITOV(*ipp)); + ip = *ipp; + } + + ITRACE(ip); + + *dir_generationp = dp->i_gen; + xfs_iunlock(dp, XFS_ILOCK_EXCL); + + *ipp = ip; + return 0; +} + +#ifdef DEBUG + +/* + * Some counters to see if (and how often) we are hitting some deadlock + * prevention code paths. + */ + +int xfs_rm_locks; +int xfs_rm_lock_delays; +int xfs_rm_attempts; +#endif + +/* + * The following routine will lock the inodes associated with the + * directory and the named entry in the directory. The locks are + * acquired in increasing inode number. + * + * If the entry is "..", then only the directory is locked. The + * vnode ref count will still include that from the .. entry in + * this case. + * + * The inode passed in will have been looked up using xfs_get_dir_entry(). + * Since that lookup the directory lock will have been dropped, so + * we need to validate that the inode given is still pointed to by the + * directory. We use the directory inode in memory generation count + * as an optimization to tell if a new lookup is necessary. If the + * directory no longer points to the given inode with the given name, + * then we drop the directory lock, set the entry_changed parameter to 1, + * and return. It is up to the caller to drop the reference to the inode. + * + * There is a dealock we need to worry about. If the locked directory is + * in the AIL, it might be blocking up the log. The next inode we lock + * could be already locked by another thread waiting for log space (e.g + * a permanent log reservation with a long running transaction (see + * xfs_itruncate_finish)). To solve this, we must check if the directory + * is in the ail and use lock_nowait. If we can't lock, we need to + * drop the inode lock on the directory and try again. xfs_iunlock will + * potentially push the tail if we were holding up the log. + */ +STATIC int +xfs_lock_dir_and_entry( + xfs_inode_t *dp, + char *name, + xfs_inode_t *ip, /* inode of entry 'name' */ + int dir_generation, + int *entry_changed) +{ + int attempts; + xfs_ino_t e_inum; + int error; + int new_dir_gen; + xfs_inode_t *ips[2]; + xfs_log_item_t *lp; + +#ifdef DEBUG + xfs_rm_locks++; +#endif + attempts = 0; + +again: + *entry_changed = 0; + xfs_ilock(dp, XFS_ILOCK_EXCL); + + if (dp->i_gen != dir_generation) { + /* + * If the link count on the directory is 0, there are no + * entries to lock. + */ + if (dp->i_d.di_nlink == 0) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + return XFS_ERROR(ENOENT); + } + /* + * The directory has changed somehow, so do the lookup + * for the entry again. If it is changed we'll have to + * give up and return to our caller. + */ + error = xfs_dir_lookup_int(NULL, XFS_ITOBHV(dp), DLF_NODNLC, + name, NULL, &e_inum, NULL, NULL); + if (error) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + return error; + } + + /* + * The entry with the given name has changed since the + * call to xfs_get_dir_entry(). Just return with + * *entry_changed set to 1 so the caller can deal with it. + */ + ASSERT(e_inum != 0); + if (e_inum != ip->i_ino) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + *entry_changed = 1; + return 0; + } + } else { + e_inum = ip->i_ino; + } + + ITRACE(ip); + + /* + * We want to lock in increasing inum. Since we've already + * acquired the lock on the directory, we may need to release + * if if the inum of the entry turns out to be less. + */ + if (e_inum > dp->i_ino) { + /* + * We are already in the right order, so just + * lock on the inode of the entry. + * We need to use nowait if dp is in the AIL. + */ + + lp = (xfs_log_item_t *)dp->i_itemp; + if (lp && (lp->li_flags & XFS_LI_IN_AIL)) { + if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) { + attempts++; +#ifdef DEBUG + xfs_rm_attempts++; +#endif + + /* + * Unlock dp and try again. + * xfs_iunlock will try to push the tail + * if the inode is in the AIL. + */ + + xfs_iunlock(dp, XFS_ILOCK_EXCL); + + if ((attempts % 5) == 0) { + delay(1); /* Don't just spin the CPU */ +#ifdef DEBUG + xfs_rm_lock_delays++; +#endif + } + goto again; + } + } else { + xfs_ilock(ip, XFS_ILOCK_EXCL); + } + } else if (e_inum < dp->i_ino) { + new_dir_gen = dp->i_gen; + xfs_iunlock(dp, XFS_ILOCK_EXCL); + + ips[0] = ip; + ips[1] = dp; + xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); + + /* + * Make sure that things are still consistent during + * the period we dropped the directory lock. + * Do a new lookup if directory was changed. + */ + if (dp->i_gen != new_dir_gen) { + /* + * If the directory has been unlinked, we're + * not going to find our entry there anymore. + */ + if (dp->i_d.di_nlink == 0) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + return XFS_ERROR(ENOENT); + } + /* + * The directory has changed somehow, so do the + * lookup for the entry again. If it is changed + * we'll have to give up and return to our caller. + */ + error = xfs_dir_lookup_int(NULL, XFS_ITOBHV(dp), + DLF_NODNLC, name, NULL, &e_inum, NULL, NULL); + + if (error) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + return error; + } + + if (e_inum != ip->i_ino) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + *entry_changed = 1; + return 0; + } + } + } + /* else e_inum == dp->i_ino */ + /* This can happen if we're asked to lock /x/.. + * the entry is "..", which is also the parent directory. + */ + + return 0; +} + +#ifdef DEBUG +int xfs_locked_n; +int xfs_small_retries; +int xfs_middle_retries; +int xfs_lots_retries; +int xfs_lock_delays; +#endif + +/* + * The following routine will lock n inodes in exclusive mode. + * We assume the caller calls us with the inodes in i_ino order. + * + * We need to detect deadlock where an inode that we lock + * is in the AIL and we start waiting for another inode that is locked + * by a thread in a long running transaction (such as truncate). This can + * result in deadlock since the long running trans might need to wait + * for the inode we just locked in order to push the tail and free space + * in the log. + */ +void +xfs_lock_inodes (xfs_inode_t **ips, + int inodes, + int first_locked, + uint lock_mode) +{ + int attempts = 0, i, j, try_lock; + xfs_log_item_t *lp; + + ASSERT(ips && (inodes >= 2)); /* we need at least two */ + + if (first_locked) { + try_lock = 1; + i = 1; + } else { + try_lock = 0; + i = 0; + } + +again: + for (; i < inodes; i++) { + ASSERT(ips[i]); + + if (i && (ips[i] == ips[i-1])) /* Already locked */ + continue; + + /* + * If try_lock is not set yet, make sure all locked inodes + * are not in the AIL. + * If any are, set try_lock to be used later. + */ + + if (!try_lock) { + for (j = (i - 1); j >= 0 && !try_lock; j--) { + lp = (xfs_log_item_t *)ips[j]->i_itemp; + if (lp && (lp->li_flags & XFS_LI_IN_AIL)) { + try_lock++; + } + } + } + + /* + * If any of the previous locks we have locked is in the AIL, + * we must TRY to get the second and subsequent locks. If + * we can't get any, we must release all we have + * and try again. + */ + + if (try_lock) { + /* try_lock must be 0 if i is 0. */ + /* + * try_lock means we have an inode locked + * that is in the AIL. + */ + ASSERT(i != 0); + if (!xfs_ilock_nowait(ips[i], lock_mode)) { + attempts++; + + /* + * Unlock all previous guys and try again. + * xfs_iunlock will try to push the tail + * if the inode is in the AIL. + */ + + for(j = i - 1; j >= 0; j--) { + + /* + * Check to see if we've already + * unlocked this one. + * Not the first one going back, + * and the inode ptr is the same. + */ + if ((j != (i - 1)) && ips[j] == + ips[j+1]) + continue; + + xfs_iunlock(ips[j], lock_mode); + } + + if ((attempts % 5) == 0) { + delay(1); /* Don't just spin the CPU */ +#ifdef DEBUG + xfs_lock_delays++; +#endif + } + i = 0; + try_lock = 0; + goto again; + } + } else { + xfs_ilock(ips[i], lock_mode); + } + } + +#ifdef DEBUG + if (attempts) { + if (attempts < 5) xfs_small_retries++; + else if (attempts < 100) xfs_middle_retries++; + else xfs_lots_retries++; + } else { + xfs_locked_n++; + } +#endif +} + +#ifdef DEBUG +#define REMOVE_DEBUG_TRACE(x) {remove_which_error_return = (x);} +int remove_which_error_return = 0; +#else /* ! DEBUG */ +#define REMOVE_DEBUG_TRACE(x) +#endif /* ! DEBUG */ + +/* + * xfs_remove + * + */ +STATIC int +xfs_remove( + bhv_desc_t *dir_bdp, + char *name, + cred_t *credp) +{ + vnode_t *dir_vp; + xfs_inode_t *dp, *ip; + xfs_trans_t *tp = NULL; + xfs_mount_t *mp; + int error = 0; + xfs_bmap_free_t free_list; + xfs_fsblock_t first_block; + int cancel_flags; + int committed; + int dir_generation; + int entry_changed; + int dm_di_mode = 0; + int link_zero; + uint resblks; + int namelen; +/* bhv_desc_t *bdp; */ + + dir_vp = BHV_TO_VNODE(dir_bdp); + + vn_trace_entry(dir_vp, "xfs_remove", (inst_t *)__return_address); + + dp = XFS_BHVTOI(dir_bdp); + mp = dp->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + namelen = strlen(name); + if (namelen >= MAXNAMELEN) + return XFS_ERROR(EINVAL); + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) { + error = dm_send_namesp_event(DM_EVENT_REMOVE, dir_bdp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, + name, NULL, 0, 0, 0); + if (error) + return error; + } + + /* From this point on, return through std_return */ + retry: + ip = NULL; + + /* + * We need to get a reference to ip before we get our log + * reservation. The reason for this is that we cannot call + * xfs_iget for an inode for which we do not have a reference + * once we've acquired a log reservation. This is because the + * inode we are trying to get might be in xfs_inactive going + * for a log reservation. Since we'll have to wait for the + * inactive code to complete before returning from xfs_iget, + * we need to make sure that we don't have log space reserved + * when we call xfs_iget. Instead we get an unlocked referece + * to the inode before getting our log reservation. + */ + error = xfs_get_dir_entry(dp, name, &ip, &dir_generation); + if (error) { + REMOVE_DEBUG_TRACE(__LINE__); + goto std_return; + } + + dm_di_mode = ip->i_d.di_mode; + + vn_trace_entry(XFS_ITOV(ip), "xfs_remove", (inst_t *)__return_address); + + ITRACE(ip); + + if (XFS_IS_QUOTA_ON(mp)) { + ASSERT(! error); + if (XFS_NOT_DQATTACHED(mp, dp)) + error = xfs_qm_dqattach(dp, 0); + if (!error && dp != ip && XFS_NOT_DQATTACHED(mp, ip)) + error = xfs_qm_dqattach(ip, 0); + if (error) { + REMOVE_DEBUG_TRACE(__LINE__); + IRELE(ip); + goto std_return; + } + } + + tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE); + cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + /* + * We try to get the real space reservation first, + * allowing for directory btree deletion(s) implying + * possible bmap insert(s). If we can't get the space + * reservation then we use 0 instead, and avoid the bmap + * btree insert(s) in the directory code by, if the bmap + * insert tries to happen, instead trimming the LAST + * block from the directory. + */ + resblks = XFS_REMOVE_SPACE_RES(mp); + error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); + if (error == ENOSPC) { + resblks = 0; + error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT); + } + if (error) { + ASSERT(error != ENOSPC); + REMOVE_DEBUG_TRACE(__LINE__); + xfs_trans_cancel(tp, 0); + IRELE(ip); + return error; + } + + error = xfs_lock_dir_and_entry(dp, name, ip, dir_generation, + &entry_changed); + if (error) { + REMOVE_DEBUG_TRACE(__LINE__); + xfs_trans_cancel(tp, cancel_flags); + IRELE(ip); + goto std_return; + } + + /* + * If the inode we found in the first pass is no longer + * the entry with the given name, then drop our transaction and + * inode reference and start over. + */ + if (entry_changed) { + xfs_trans_cancel(tp, cancel_flags); + IRELE(ip); + goto retry; + } + + /* + * At this point, we've gotten both the directory and the entry + * inodes locked. + */ + xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); + if (dp != ip) { + /* + * Increment vnode ref count only in this case since + * there's an extra vnode reference in the case where + * dp == ip. + */ + IHOLD(dp); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + } + + if ((error = _MAC_XFS_IACCESS(ip, MACWRITE, credp))) { + REMOVE_DEBUG_TRACE(__LINE__); + goto error_return; + } +#if 0 + if ((error = xfs_stickytest(dp, ip, credp))) { + REMOVE_DEBUG_TRACE(__LINE__); + goto error_return; + } +#endif + + if ((error = xfs_pre_remove(XFS_ITOV(ip)))) { + error = XFS_ERROR(error); + REMOVE_DEBUG_TRACE(__LINE__); + goto error_return; + } + if ((ip->i_d.di_mode & IFMT) == IFDIR) { + error = XFS_ERROR(EPERM); + REMOVE_DEBUG_TRACE(__LINE__); + goto error_return; + } + + /* + * Return error when removing . and .. + */ + if (name[0] == '.') { + if (name[1] == '\0') { + error = XFS_ERROR(EINVAL); + REMOVE_DEBUG_TRACE(__LINE__); + goto error_return; + } + else if (name[1] == '.' && name[2] == '\0') { + error = XFS_ERROR(EEXIST); + REMOVE_DEBUG_TRACE(__LINE__); + goto error_return; + } + } + + /* + * Entry must exist since we did a lookup in xfs_lock_dir_and_entry. + */ + XFS_BMAP_INIT(&free_list, &first_block); + error = XFS_DIR_REMOVENAME(mp, tp, dp, name, namelen, ip->i_ino, + &first_block, &free_list, 0); + if (error) { + ASSERT(error != ENOENT); + REMOVE_DEBUG_TRACE(__LINE__); + goto error1; + } + xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + dp->i_gen++; + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + + error = xfs_droplink(tp, ip); + if (error) { + REMOVE_DEBUG_TRACE(__LINE__); + goto error1; + } + + /* Determine if this is the last link while + * we are in the transaction. + */ + link_zero = (ip)->i_d.di_nlink==0; + + /* + * Take an extra ref on the inode so that it doesn't + * go to xfs_inactive() from within the commit. + */ + IHOLD(ip); + + /* + * If this is a synchronous mount, make sure that the + * remove transaction goes to disk before returning to + * the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); + if (error) { + REMOVE_DEBUG_TRACE(__LINE__); + goto error_rele; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (error) { + IRELE(ip); + goto std_return; + } + + /* + * Before we drop our extra reference to the inode, purge it + * from the refcache if it is there. By waiting until afterwards + * to do the IRELE, we ensure that we won't go inactive in the + * xfs_refcache_purge_ip routine (although that would be OK). + */ + xfs_refcache_purge_ip(ip); + + vn_trace_exit(XFS_ITOV(ip), "xfs_remove", + (inst_t *)__return_address); + + /* + * Let interposed file systems know about removed links. + */ + VOP_LINK_REMOVED(XFS_ITOV(ip), dir_vp, link_zero); + + IRELE(ip); + +/* Fall through to std_return with error = 0 */ + +std_return: + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, + DM_EVENT_POSTREMOVE)) { + (void) dm_send_namesp_event(DM_EVENT_POSTREMOVE, + dir_bdp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, + name, NULL, dm_di_mode, error, 0); + } + return error; + + error1: + xfs_bmap_cancel(&free_list); + cancel_flags |= XFS_TRANS_ABORT; + + error_return: + xfs_trans_cancel(tp, cancel_flags); + goto std_return; + + error_rele: + /* + * In this case make sure to not release the inode until after + * the current transaction is aborted. Releasing it beforehand + * can cause us to go to xfs_inactive and start a recursive + * transaction which can easily deadlock with the current one. + */ + xfs_bmap_cancel(&free_list); + cancel_flags |= XFS_TRANS_ABORT; + xfs_trans_cancel(tp, cancel_flags); + + /* + * Before we drop our extra reference to the inode, purge it + * from the refcache if it is there. By waiting until afterwards + * to do the IRELE, we ensure that we won't go inactive in the + * xfs_refcache_purge_ip routine (although that would be OK). + */ + xfs_refcache_purge_ip(ip); + + IRELE(ip); + + goto std_return; +} + + +/* + * xfs_link + * + */ +int +xfs_link( + bhv_desc_t *target_dir_bdp, + vnode_t *src_vp, + char *target_name, + cred_t *credp) +{ + vnode_t *realvp; + xfs_inode_t *tdp, *sip; + xfs_ino_t e_inum; + xfs_trans_t *tp; + xfs_mount_t *mp; + xfs_inode_t *ips[2]; + int error; + xfs_bmap_free_t free_list; + xfs_fsblock_t first_block; + int cancel_flags; + int committed; + vnode_t *target_dir_vp; + bhv_desc_t *src_bdp; + int resblks; + int target_namelen; + + target_dir_vp = BHV_TO_VNODE(target_dir_bdp); + + vn_trace_entry(target_dir_vp, "xfs_link", (inst_t *)__return_address); + + target_namelen = strlen(target_name); + if (target_namelen >= MAXNAMELEN) + return XFS_ERROR(EINVAL); + /* + * Get the real vnode. + */ + VOP_REALVP(src_vp, &realvp, error); + if (!error) { + src_vp = realvp; + } + + vn_trace_entry(src_vp, "xfs_link", (inst_t *)__return_address); + + if (src_vp->v_type == VDIR) { + return XFS_ERROR(EPERM); + } + + /* + * For now, manually find the XFS behavior descriptor for + * the source vnode. If it doesn't exist then something + * is wrong and we should just return an error. + * Eventually we need to figure out how link is going to + * work in the face of stacked vnodes. + */ + src_bdp = vn_bhv_lookup_unlocked(VN_BHV_HEAD(src_vp), &xfs_vnodeops); + if (src_bdp == NULL) { + return XFS_ERROR(EXDEV); + } + sip = XFS_BHVTOI(src_bdp); + tdp = XFS_BHVTOI(target_dir_bdp); + mp = tdp->i_mount; + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + if (DM_EVENT_ENABLED(src_vp->v_vfsp, tdp, DM_EVENT_LINK)) { + error = dm_send_namesp_event(DM_EVENT_LINK, + target_dir_bdp, DM_RIGHT_NULL, + src_bdp, DM_RIGHT_NULL, + target_name, NULL, 0, 0, 0); + if (error) + return error; + } + + /* Return through std_return after this point. */ + + if (XFS_IS_QUOTA_ON(mp)) { + error = 0; + if (XFS_NOT_DQATTACHED(mp, sip)) + error = xfs_qm_dqattach(sip, 0); + if (!error && sip != tdp && XFS_NOT_DQATTACHED(mp, tdp)) + error = xfs_qm_dqattach(tdp, 0); + if (error) + goto std_return; + } + + tp = xfs_trans_alloc(mp, XFS_TRANS_LINK); + cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + resblks = XFS_LINK_SPACE_RES(mp, target_namelen); + error = xfs_trans_reserve(tp, resblks, XFS_LINK_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT); + if (error == ENOSPC) { + resblks = 0; + error = xfs_trans_reserve(tp, 0, XFS_LINK_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT); + } + if (error) { + cancel_flags = 0; + goto error_return; + } + + if (sip->i_ino < tdp->i_ino) { + ips[0] = sip; + ips[1] = tdp; + } else { + ips[0] = tdp; + ips[1] = sip; + } + + xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL); + + /* + * Increment vnode ref counts since xfs_trans_commit & + * xfs_trans_cancel will both unlock the inodes and + * decrement the associated ref counts. + */ + VN_HOLD(src_vp); + VN_HOLD(target_dir_vp); + xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL); + + /* + * If the source has too many links, we can't make any more to it. + */ + if (sip->i_d.di_nlink >= XFS_MAXLINK) { + error = XFS_ERROR(EMLINK); + goto error_return; + } + + /* + * If the source has been unlinked and put on the unlinked + * list, we can't link to it. Doing so would cause the inode + * to be placed on the list a second time when the link + * created here is removed. + */ + if (sip->i_d.di_nlink == 0) { + error = XFS_ERROR(ENOENT); + goto error_return; + } + + /* + * If the target directory has been removed, we can't link + * any more files in it. + */ + if (tdp->i_d.di_nlink == 0) { + error = XFS_ERROR(ENOENT); + goto error_return; + } + + + /* + * Make sure that nothing with the given name exists in the + * target directory. + */ + error = xfs_dir_lookup_int(NULL, target_dir_bdp, DLF_NODNLC, + target_name, NULL, &e_inum, NULL, NULL); + if (error != ENOENT) { + if (error == 0) { + error = XFS_ERROR(EEXIST); + } + goto error_return; + } + + if (resblks == 0 && + (error = XFS_DIR_CANENTER(mp, tp, tdp, target_name, + target_namelen))) + goto error_return; + + XFS_BMAP_INIT(&free_list, &first_block); + + error = XFS_DIR_CREATENAME(mp, tp, tdp, target_name, target_namelen, + sip->i_ino, &first_block, &free_list, + resblks); + if (error) + goto abort_return; + xfs_ichgtime(tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + tdp->i_gen++; + xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE); + + error = xfs_bumplink(tp, sip); + if (error) { + goto abort_return; + } + + /* + * If this is a synchronous mount, make sure that the + * link transaction goes to disk before returning to + * the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + error = xfs_bmap_finish (&tp, &free_list, first_block, &committed); + if (error) { + xfs_bmap_cancel(&free_list); + goto abort_return; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (error) { + goto std_return; + } + + /* Fall through to std_return with error = 0. */ +std_return: + if (DM_EVENT_ENABLED(src_vp->v_vfsp, sip, + DM_EVENT_POSTLINK)) { + (void) dm_send_namesp_event(DM_EVENT_POSTLINK, + target_dir_bdp, DM_RIGHT_NULL, + src_bdp, DM_RIGHT_NULL, + target_name, NULL, 0, error, 0); + } + return error; + + abort_return: + cancel_flags |= XFS_TRANS_ABORT; + /* FALLTHROUGH */ + error_return: + xfs_trans_cancel(tp, cancel_flags); + + goto std_return; +} + + + + +/* + * xfs_mkdir + * + */ +STATIC int +xfs_mkdir( + bhv_desc_t *dir_bdp, + char *dir_name, + vattr_t *vap, + vnode_t **vpp, + cred_t *credp) +{ + xfs_inode_t *dp; + xfs_inode_t *cdp; /* inode of created dir */ + vnode_t *cvp; /* vnode of created dir */ + xfs_trans_t *tp; + xfs_ino_t e_inum; + dev_t rdev; + mode_t mode; + xfs_mount_t *mp; + int cancel_flags; + int error; + int committed; + xfs_bmap_free_t free_list; + xfs_fsblock_t first_block; + vnode_t *dir_vp; + boolean_t dp_joined_to_trans; + boolean_t created = B_FALSE; + int dm_event_sent = 0; + xfs_prid_t prid; + struct xfs_dquot *udqp, *gdqp; + uint resblks; + int dm_di_mode; + int dir_namelen; + + dir_vp = BHV_TO_VNODE(dir_bdp); + dp = XFS_BHVTOI(dir_bdp); + mp = dp->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + dir_namelen = strlen(dir_name); + if (dir_namelen >= MAXNAMELEN) + return XFS_ERROR(EINVAL); + + tp = NULL; + dp_joined_to_trans = B_FALSE; + dm_di_mode = vap->va_mode|VTTOIF(vap->va_type); + + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_CREATE)) { + error = xfs_dm_send_create_event(dir_bdp, dir_name, + dm_di_mode, &dm_event_sent); + if (error) + return error; + } + + /* Return through std_return after this point. */ + + vn_trace_entry(dir_vp, "xfs_mkdir", (inst_t *)__return_address); + + mp = dp->i_mount; + udqp = gdqp = NULL; + if (vap->va_mask & AT_PROJID) + prid = (xfs_prid_t)vap->va_projid; + else + prid = (xfs_prid_t)dfltprid; + + /* + * Make sure that we have allocated dquot(s) on disk. + */ + if (XFS_IS_QUOTA_ON(mp)) { + error = xfs_qm_vop_dqalloc(mp, dp, + current->fsuid, current->fsgid, + XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, + &udqp, &gdqp); + if (error) + goto std_return; + } + + tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR); + cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + resblks = XFS_MKDIR_SPACE_RES(mp, dir_namelen); + error = xfs_trans_reserve(tp, resblks, XFS_MKDIR_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_MKDIR_LOG_COUNT); + if (error == ENOSPC) { + resblks = 0; + error = xfs_trans_reserve(tp, 0, XFS_MKDIR_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, + XFS_MKDIR_LOG_COUNT); + } + if (error) { + cancel_flags = 0; + dp = NULL; + goto error_return; + } + + xfs_ilock(dp, XFS_ILOCK_EXCL); + + /* + * Since dp was not locked between VOP_LOOKUP and VOP_MKDIR, + * the directory could have been removed. + */ + if (dp->i_d.di_nlink == 0) { + error = XFS_ERROR(ENOENT); + goto error_return; + } + + /* + * Check for directory link count overflow. + */ + if (dp->i_d.di_nlink >= XFS_MAXLINK) { + error = XFS_ERROR(EMLINK); + goto error_return; + } + + /* + * Make sure that nothing with the given name exists in the + * target directory. + */ + error = xfs_dir_lookup_int(NULL, dir_bdp, DLF_NODNLC, dir_name, + NULL, &e_inum, NULL, NULL); + if (error != ENOENT) { + if (error == 0) + error = XFS_ERROR(EEXIST); + goto error_return; + } + + + /* + * Reserve disk quota and the inode. + */ + if (XFS_IS_QUOTA_ON(mp)) { + if (xfs_trans_reserve_quota(tp, udqp, gdqp, resblks, 1, 0)) { + error = XFS_ERROR(EDQUOT); + goto error_return; + } + } + + if (resblks == 0 && + (error = XFS_DIR_CANENTER(mp, tp, dp, dir_name, dir_namelen))) + goto error_return; + /* + * create the directory inode. + */ + rdev = (vap->va_mask & AT_RDEV) ? vap->va_rdev : NODEV; + mode = IFDIR | (vap->va_mode & ~IFMT); + error = xfs_dir_ialloc(&tp, dp, mode, 2, rdev, credp, prid, resblks > 0, + &cdp, NULL); + if (error) { + if (error == ENOSPC) + goto error_return; + goto abort_return; + } + ITRACE(cdp); + + /* + * Now we add the directory inode to the transaction. + * We waited until now since xfs_dir_ialloc might start + * a new transaction. Had we joined the transaction + * earlier, the locks might have gotten released. + */ + VN_HOLD(dir_vp); + xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); + dp_joined_to_trans = B_TRUE; + + XFS_BMAP_INIT(&free_list, &first_block); + + error = XFS_DIR_CREATENAME(mp, tp, dp, dir_name, dir_namelen, + cdp->i_ino, &first_block, &free_list, + resblks ? resblks - XFS_IALLOC_SPACE_RES(mp) : 0); + if (error) { + ASSERT(error != ENOSPC); + goto error1; + } + xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + /* + * Bump the in memory version number of the parent directory + * so that other processes accessing it will recognize that + * the directory has changed. + */ + dp->i_gen++; + + error = XFS_DIR_INIT(mp, tp, cdp, dp); + if (error) { + goto error2; + } + + cdp->i_gen = 1; + error = xfs_bumplink(tp, dp); + if (error) { + goto error2; + } + + cvp = XFS_ITOV(cdp); + + created = B_TRUE; + + *vpp = cvp; + IHOLD(cdp); + + /* + * Attach the dquots to the new inode and modify the icount incore. + */ + if (XFS_IS_QUOTA_ON(mp)) { + xfs_qm_vop_dqattach_and_dqmod_newinode(tp, cdp, udqp, gdqp); + } + + /* + * If this is a synchronous mount, make sure that the + * mkdir transaction goes to disk before returning to + * the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); + if (error) { + IRELE(cdp); + goto error2; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + + if (error) { + IRELE(cdp); + } + + /* Fall through to std_return with error = 0 or errno from + * xfs_trans_commit. */ + +std_return: + if ( (created || (error != 0 && dm_event_sent != 0)) && + DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp), + DM_EVENT_POSTCREATE)) { + (void) dm_send_namesp_event(DM_EVENT_POSTCREATE, + dir_bdp, DM_RIGHT_NULL, + created ? XFS_ITOBHV(cdp):NULL, + DM_RIGHT_NULL, + dir_name, NULL, + dm_di_mode, error, 0); + } + return error; + + error2: + error1: + xfs_bmap_cancel(&free_list); + abort_return: + cancel_flags |= XFS_TRANS_ABORT; + error_return: + xfs_trans_cancel(tp, cancel_flags); + + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + + if (!dp_joined_to_trans && (dp != NULL)) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + } + + goto std_return; +} + + +/* + * xfs_rmdir + * + */ +STATIC int +xfs_rmdir( + bhv_desc_t *dir_bdp, + char *name, + vnode_t *current_dir_vp, + cred_t *credp) +{ + xfs_inode_t *dp; + xfs_inode_t *cdp; /* child directory */ + xfs_trans_t *tp; + xfs_mount_t *mp; +/* bhv_desc_t *bdp;*/ + int error; + xfs_bmap_free_t free_list; + xfs_fsblock_t first_block; + int cancel_flags; + int committed; + int dir_generation; + int entry_changed; + vnode_t *dir_vp; + int dm_di_mode = 0; + int last_cdp_link; + int namelen; + uint resblks; + + dir_vp = BHV_TO_VNODE(dir_bdp); + dp = XFS_BHVTOI(dir_bdp); + + vn_trace_entry(dir_vp, "xfs_rmdir", (inst_t *)__return_address); + + if (XFS_FORCED_SHUTDOWN(XFS_BHVTOI(dir_bdp)->i_mount)) + return XFS_ERROR(EIO); + namelen = strlen(name); + if (namelen >= MAXNAMELEN) + return XFS_ERROR(EINVAL); + + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) { + error = dm_send_namesp_event(DM_EVENT_REMOVE, + dir_bdp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, + name, NULL, 0, 0, 0); + if (error) + return XFS_ERROR(error); + } + + /* Return through std_return after this point. */ + + retry: + cdp = NULL; + + /* + * We need to get a reference to cdp before we get our log + * reservation. The reason for this is that we cannot call + * xfs_iget for an inode for which we do not have a reference + * once we've acquired a log reservation. This is because the + * inode we are trying to get might be in xfs_inactive going + * for a log reservation. Since we'll have to wait for the + * inactive code to complete before returning from xfs_iget, + * we need to make sure that we don't have log space reserved + * when we call xfs_iget. Instead we get an unlocked referece + * to the inode before getting our log reservation. + */ + error = xfs_get_dir_entry(dp, name, &cdp, &dir_generation); + if (error) { + REMOVE_DEBUG_TRACE(__LINE__); + goto std_return; + } + mp = dp->i_mount; + dm_di_mode = cdp->i_d.di_mode; + + /* + * Get the dquots for the inodes. + */ + if (XFS_IS_QUOTA_ON(mp)) { + ASSERT(! error); + if (XFS_NOT_DQATTACHED(mp, dp)) + error = xfs_qm_dqattach(dp, 0); + if (!error && dp != cdp && XFS_NOT_DQATTACHED(mp, cdp)) + error = xfs_qm_dqattach(cdp, 0); + if (error) { + IRELE(cdp); + REMOVE_DEBUG_TRACE(__LINE__); + goto std_return; + } + } + + tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR); + cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + /* + * We try to get the real space reservation first, + * allowing for directory btree deletion(s) implying + * possible bmap insert(s). If we can't get the space + * reservation then we use 0 instead, and avoid the bmap + * btree insert(s) in the directory code by, if the bmap + * insert tries to happen, instead trimming the LAST + * block from the directory. + */ + resblks = XFS_REMOVE_SPACE_RES(mp); + error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT); + if (error == ENOSPC) { + resblks = 0; + error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_DEFAULT_LOG_COUNT); + } + if (error) { + ASSERT(error != ENOSPC); + cancel_flags = 0; + IRELE(cdp); + goto error_return; + } + XFS_BMAP_INIT(&free_list, &first_block); + + /* + * Now lock the child directory inode and the parent directory + * inode in the proper order. This will take care of validating + * that the directory entry for the child directory inode has + * not changed while we were obtaining a log reservation. + */ + error = xfs_lock_dir_and_entry(dp, name, cdp, dir_generation, + &entry_changed); + if (error) { + xfs_trans_cancel(tp, cancel_flags); + IRELE(cdp); + goto std_return; + } + + /* + * If the inode we found in the first pass is no longer + * the entry with the given name, then drop our transaction and + * inode reference and start over. + */ + if (entry_changed) { + xfs_trans_cancel(tp, cancel_flags); + IRELE(cdp); + goto retry; + } + + xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); + if (dp != cdp) { + /* + * Only increment the parent directory vnode count if + * we didn't bump it in looking up cdp. The only time + * we don't bump it is when we're looking up ".". + */ + VN_HOLD(dir_vp); + } + + ITRACE(cdp); + xfs_trans_ijoin(tp, cdp, XFS_ILOCK_EXCL); + + if ((error = _MAC_XFS_IACCESS(cdp, MACWRITE, credp))) { + goto error_return; + } + + if ((cdp == dp) || (XFS_ITOV(cdp) == current_dir_vp)) { + error = XFS_ERROR(EINVAL); + goto error_return; + } + if ((cdp->i_d.di_mode & IFMT) != IFDIR) { + error = XFS_ERROR(ENOTDIR); + goto error_return; + } + if ((error = xfs_pre_rmdir(XFS_ITOV(cdp)))) { + error = XFS_ERROR(error); + goto error_return; + } + ASSERT(cdp->i_d.di_nlink >= 2); + if (cdp->i_d.di_nlink != 2) { + error = XFS_ERROR(ENOTEMPTY); + goto error_return; + } + if (!XFS_DIR_ISEMPTY(mp, cdp)) { + error = XFS_ERROR(ENOTEMPTY); + goto error_return; + } + + error = XFS_DIR_REMOVENAME(mp, tp, dp, name, namelen, cdp->i_ino, + &first_block, &free_list, resblks); + if (error) { + goto error1; + } + + xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + /* + * Bump the in memory generation count on the parent + * directory so that other can know that it has changed. + */ + dp->i_gen++; + + /* + * Drop the link from cdp's "..". + */ + error = xfs_droplink(tp, dp); + if (error) { + goto error1; + } + + /* + * Drop the link from dp to cdp. + */ + error = xfs_droplink(tp, cdp); + if (error) { + goto error1; + } + + /* + * Drop the "." link from cdp to self. + */ + error = xfs_droplink(tp, cdp); + if (error) { + goto error1; + } + + /* Determine these before committing transaction */ + last_cdp_link = (cdp)->i_d.di_nlink==0; + + /* + * Take an extra ref on the child vnode so that it + * does not go to xfs_inactive() from within the commit. + */ + IHOLD(cdp); + + /* + * If this is a synchronous mount, make sure that the + * rmdir transaction goes to disk before returning to + * the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + error = xfs_bmap_finish (&tp, &free_list, first_block, &committed); + if (error) { + xfs_bmap_cancel(&free_list); + xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | + XFS_TRANS_ABORT)); + IRELE(cdp); + goto std_return; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (error) { + IRELE(cdp); + goto std_return; + } + + + /* + * Let interposed file systems know about removed links. + */ + VOP_LINK_REMOVED(XFS_ITOV(cdp), dir_vp, last_cdp_link); + + IRELE(cdp); + + /* Fall through to std_return with error = 0 or the errno + * from xfs_trans_commit. */ +std_return: + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, + DM_EVENT_POSTREMOVE)) { + (void) dm_send_namesp_event(DM_EVENT_POSTREMOVE, + dir_bdp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, + name, NULL, dm_di_mode, + error, 0); + } + return error; + + error1: + xfs_bmap_cancel(&free_list); + cancel_flags |= XFS_TRANS_ABORT; + error_return: + xfs_trans_cancel(tp, cancel_flags); + goto std_return; +} + + + +/* + * xfs_readdir + * + * Read dp's entries starting at uiop->uio_offset and translate them into + * bufsize bytes worth of struct dirents starting at bufbase. + */ +/*ARGSUSED*/ +STATIC int +xfs_readdir( + bhv_desc_t *dir_bdp, + uio_t *uiop, + cred_t *credp, + int *eofp) +{ + xfs_inode_t *dp; + xfs_trans_t *tp = NULL; + int error = 0; + uint lock_mode; + xfs_off_t start_offset; + + vn_trace_entry(BHV_TO_VNODE(dir_bdp), "xfs_readdir", + (inst_t *)__return_address); + dp = XFS_BHVTOI(dir_bdp); + + if (XFS_FORCED_SHUTDOWN(dp->i_mount)) { + return XFS_ERROR(EIO); + } + + lock_mode = xfs_ilock_map_shared(dp); + + if ((dp->i_d.di_mode & IFMT) != IFDIR) { + xfs_iunlock_map_shared(dp, lock_mode); + return XFS_ERROR(ENOTDIR); + } + + /* If the directory has been removed after it was opened. */ + if (dp->i_d.di_nlink == 0) { + xfs_iunlock_map_shared(dp, lock_mode); + return 0; + } + + start_offset = uiop->uio_offset; + error = XFS_DIR_GETDENTS(dp->i_mount, tp, dp, uiop, eofp); + if (start_offset != uiop->uio_offset) { + xfs_ichgtime(dp, XFS_ICHGTIME_ACC); + } + + xfs_iunlock_map_shared(dp, lock_mode); + + return error; +} + +/* + * xfs_symlink + * + */ +STATIC int +xfs_symlink( + bhv_desc_t *dir_bdp, + char *link_name, + vattr_t *vap, + char *target_path, + vnode_t **vpp, + cred_t *credp) +{ + xfs_trans_t *tp; + xfs_mount_t *mp; + xfs_inode_t *dp; + xfs_inode_t *ip; + int error; + int pathlen; + xfs_ino_t e_inum; + dev_t rdev; + xfs_bmap_free_t free_list; + xfs_fsblock_t first_block; + boolean_t dp_joined_to_trans; + vnode_t *dir_vp; + uint cancel_flags; + int committed; + xfs_fileoff_t first_fsb; + xfs_filblks_t fs_blocks; + int nmaps; + xfs_bmbt_irec_t mval[SYMLINK_MAPS]; + xfs_daddr_t d; + char *cur_chunk; + int byte_cnt; + int n; + xfs_buf_t *bp; + xfs_prid_t prid; + struct xfs_dquot *udqp, *gdqp; + uint resblks; + int link_namelen; + + *vpp = NULL; + dir_vp = BHV_TO_VNODE(dir_bdp); + dp = XFS_BHVTOI(dir_bdp); + dp_joined_to_trans = B_FALSE; + error = 0; + ip = NULL; + tp = NULL; + + vn_trace_entry(dir_vp, "xfs_symlink", (inst_t *)__return_address); + + mp = dp->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + link_namelen = strlen(link_name); + if (link_namelen >= MAXNAMELEN) + return XFS_ERROR(EINVAL); + /* + * Check component lengths of the target path name. + */ + pathlen = strlen(target_path); + if (pathlen >= MAXPATHLEN) /* total string too long */ + return XFS_ERROR(ENAMETOOLONG); + if (pathlen >= MAXNAMELEN) { /* is any component too long? */ + int len, total; + char *path; + + for(total = 0, path = target_path; total < pathlen;) { + /* + * Skip any slashes. + */ + while(*path == '/') { + total++; + path++; + } + + /* + * Count up to the next slash or end of path. + * Error out if the component is bigger than MAXNAMELEN. + */ + for(len = 0; *path != '/' && total < pathlen;total++, path++) { + if (++len >= MAXNAMELEN) { + error = ENAMETOOLONG; + return error; + } + } + } + } + + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_SYMLINK)) { + error = dm_send_namesp_event(DM_EVENT_SYMLINK, dir_bdp, DM_RIGHT_NULL, + NULL, DM_RIGHT_NULL, + link_name, target_path, + 0, 0, 0); + if (error) + return error; + } + + /* Return through std_return after this point. */ + + udqp = gdqp = NULL; + if (vap->va_mask & AT_PROJID) + prid = (xfs_prid_t)vap->va_projid; + else + prid = (xfs_prid_t)dfltprid; + + /* + * Make sure that we have allocated dquot(s) on disk. + */ + if (XFS_IS_QUOTA_ON(mp)) { + error = xfs_qm_vop_dqalloc(mp, dp, + current->fsuid, current->fsgid, + XFS_QMOPT_QUOTALL|XFS_QMOPT_INHERIT, + &udqp, &gdqp); + if (error) + goto std_return; + } + + tp = xfs_trans_alloc(mp, XFS_TRANS_SYMLINK); + cancel_flags = XFS_TRANS_RELEASE_LOG_RES; + /* + * The symlink will fit into the inode data fork? + * There can't be any attributes so we get the whole variable part. + */ + if (pathlen <= XFS_LITINO(mp)) + fs_blocks = 0; + else + fs_blocks = XFS_B_TO_FSB(mp, pathlen); + resblks = XFS_SYMLINK_SPACE_RES(mp, link_namelen, fs_blocks); + error = xfs_trans_reserve(tp, resblks, XFS_SYMLINK_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT); + if (error == ENOSPC && fs_blocks == 0) { + resblks = 0; + error = xfs_trans_reserve(tp, 0, XFS_SYMLINK_LOG_RES(mp), 0, + XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT); + } + if (error) { + cancel_flags = 0; + dp = NULL; + goto error_return; + } + + xfs_ilock(dp, XFS_ILOCK_EXCL); + + /* + * If the directory has been removed, then we can't create + * anything in it. + */ + if (dp->i_d.di_nlink == 0) { + error = XFS_ERROR(ENOENT); + goto error_return; + } + + + /* + * Since we've already started a transaction, we cannot allow + * the lookup to do a vn_get(). + */ + error = xfs_dir_lookup_int(NULL, dir_bdp, DLF_NODNLC, link_name, + NULL, &e_inum, NULL, NULL); + if (error != ENOENT) { + if (!error) { + error = XFS_ERROR(EEXIST); + } + goto error_return; + } + /* + * Reserve disk quota : blocks and inode. + */ + if (XFS_IS_QUOTA_ON(mp)) { + if (xfs_trans_reserve_quota(tp, udqp, gdqp, resblks, 1, 0)) { + error = XFS_ERROR(EDQUOT); + goto error_return; + } + } + + /* + * Check for ability to enter directory entry, if no space reserved. + */ + if (resblks == 0 && + (error = XFS_DIR_CANENTER(mp, tp, dp, link_name, link_namelen))) + goto error_return; + /* + * Initialize the bmap freelist prior to calling either + * bmapi or the directory create code. + */ + XFS_BMAP_INIT(&free_list, &first_block); + + /* + * Allocate an inode for the symlink. + */ + rdev = (vap->va_mask & AT_RDEV) ? vap->va_rdev : NODEV; + + error = xfs_dir_ialloc(&tp, dp, IFLNK | (vap->va_mode&~IFMT), + 1, rdev, credp, prid, resblks > 0, &ip, NULL); + if (error) { + if (error == ENOSPC) + goto error_return; + goto error1; + } + ITRACE(ip); + + VN_HOLD(dir_vp); + xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL); + dp_joined_to_trans = B_TRUE; + + /* + * Also attach the dquot(s) to it, if applicable. + */ + if (XFS_IS_QUOTA_ON(mp)) { + xfs_qm_vop_dqattach_and_dqmod_newinode(tp, ip, udqp, gdqp); + } + + if (resblks) + resblks -= XFS_IALLOC_SPACE_RES(mp); + /* + * If the symlink will fit into the inode, write it inline. + */ + if (pathlen <= XFS_IFORK_DSIZE(ip)) { + xfs_idata_realloc(ip, pathlen, XFS_DATA_FORK); + bcopy(target_path, ip->i_df.if_u1.if_data, pathlen); + ip->i_d.di_size = pathlen; + + /* + * The inode was initially created in extent format. + */ + ip->i_df.if_flags &= ~(XFS_IFEXTENTS | XFS_IFBROOT); + ip->i_df.if_flags |= XFS_IFINLINE; + + ip->i_d.di_format = XFS_DINODE_FMT_LOCAL; + xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE); + + } else { + first_fsb = 0; + nmaps = SYMLINK_MAPS; + + error = xfs_bmapi(tp, ip, first_fsb, fs_blocks, + XFS_BMAPI_WRITE | XFS_BMAPI_METADATA, + &first_block, resblks, mval, &nmaps, + &free_list); + if (error) { + goto error1; + } + + if (resblks) + resblks -= fs_blocks; + ip->i_d.di_size = pathlen; + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + + cur_chunk = target_path; + for (n = 0; n < nmaps; n++) { + d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); + byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); + bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, + BTOBB(byte_cnt), 0); + ASSERT(bp && !XFS_BUF_GETERROR(bp)); + if (pathlen < byte_cnt) { + byte_cnt = pathlen; + } + pathlen -= byte_cnt; + + bcopy(cur_chunk, XFS_BUF_PTR(bp), byte_cnt); + cur_chunk += byte_cnt; + + xfs_trans_log_buf(tp, bp, 0, byte_cnt - 1); + } + } + + /* + * Create the directory entry for the symlink. + */ + error = XFS_DIR_CREATENAME(mp, tp, dp, link_name, link_namelen, + ip->i_ino, &first_block, &free_list, resblks); + if (error) { + goto error1; + } + xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); + + /* + * Bump the in memory version number of the parent directory + * so that other processes accessing it will recognize that + * the directory has changed. + */ + dp->i_gen++; + + /* + * If this is a synchronous mount, make sure that the + * symlink transaction goes to disk before returning to + * the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) { + xfs_trans_set_sync(tp); + } + + /* + * xfs_trans_commit normally decrements the vnode ref count + * when it unlocks the inode. Since we want to return the + * vnode to the caller, we bump the vnode ref count now. + */ + IHOLD(ip); + + error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); + if (error) { + goto error2; + } + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + + /* Fall through to std_return with error = 0 or errno from + * xfs_trans_commit */ +std_return: + if (DM_EVENT_ENABLED(dir_vp->v_vfsp, XFS_BHVTOI(dir_bdp), + DM_EVENT_POSTSYMLINK)) { + (void) dm_send_namesp_event(DM_EVENT_POSTSYMLINK, + dir_bdp, DM_RIGHT_NULL, + error? NULL:XFS_ITOBHV(ip), + DM_RIGHT_NULL, + link_name, target_path, + 0, error, 0); + } + + if (!error) { + vnode_t *vp; + + ASSERT(ip); + vp = XFS_ITOV(ip); + *vpp = vp; + } + return error; + + error2: + IRELE(ip); + error1: + xfs_bmap_cancel(&free_list); + cancel_flags |= XFS_TRANS_ABORT; + error_return: + xfs_trans_cancel(tp, cancel_flags); + if (udqp) + xfs_qm_dqrele(udqp); + if (gdqp) + xfs_qm_dqrele(gdqp); + + if (!dp_joined_to_trans && (dp != NULL)) { + xfs_iunlock(dp, XFS_ILOCK_EXCL); + } + + goto std_return; +} + + +/* + * xfs_fid2 + * + * A fid routine that takes a pointer to a previously allocated + * fid structure (like xfs_fast_fid) but uses a 64 bit inode number. + */ +STATIC int +xfs_fid2( + bhv_desc_t *bdp, + fid_t *fidp) +{ + xfs_inode_t *ip; + xfs_fid2_t *xfid; + + vn_trace_entry(BHV_TO_VNODE(bdp), "xfs_fid2", + (inst_t *)__return_address); + ASSERT(sizeof(fid_t) >= sizeof(xfs_fid2_t)); + + xfid = (xfs_fid2_t *)fidp; + ip = XFS_BHVTOI(bdp); + xfid->fid_len = sizeof(xfs_fid2_t) - sizeof(xfid->fid_len); + xfid->fid_pad = 0; + /* + * use bcopy because the inode is a long long and there's no + * assurance that xfid->fid_ino is properly aligned. + */ + bcopy(&ip->i_ino, &xfid->fid_ino, sizeof xfid->fid_ino); + xfid->fid_gen = ip->i_d.di_gen; + + return 0; +} + + +/* + * xfs_rwlock + */ +int +xfs_rwlock( + bhv_desc_t *bdp, + vrwlock_t locktype) +{ + xfs_inode_t *ip; + vnode_t *vp; + + vp = BHV_TO_VNODE(bdp); + if (vp->v_type == VDIR) + return 1; + ip = XFS_BHVTOI(bdp); + if (locktype == VRWLOCK_WRITE) { + xfs_ilock(ip, XFS_IOLOCK_EXCL); + } else if (locktype == VRWLOCK_TRY_READ) { + return (xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED)); + } else if (locktype == VRWLOCK_TRY_WRITE) { + return (xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)); + } else { + ASSERT((locktype == VRWLOCK_READ) || + (locktype == VRWLOCK_WRITE_DIRECT)); + xfs_ilock(ip, XFS_IOLOCK_SHARED); + } + + return 1; +} + + +/* + * xfs_rwunlock + */ +void +xfs_rwunlock( + bhv_desc_t *bdp, + vrwlock_t locktype) +{ + xfs_inode_t *ip; + xfs_inode_t *release_ip; + vnode_t *vp; + + vp = BHV_TO_VNODE(bdp); + if (vp->v_type == VDIR) + return; + ip = XFS_BHVTOI(bdp); + if (locktype == VRWLOCK_WRITE) { + /* + * In the write case, we may have added a new entry to + * the reference cache. This might store a pointer to + * an inode to be released in this inode. If it is there, + * clear the pointer and release the inode after unlocking + * this one. + */ + release_ip = ip->i_release; + ip->i_release = NULL; + xfs_iunlock (ip, XFS_IOLOCK_EXCL); + + if (release_ip != NULL) { + VN_RELE(XFS_ITOV(release_ip)); + } + } else { + ASSERT((locktype == VRWLOCK_READ) || + (locktype == VRWLOCK_WRITE_DIRECT)); + xfs_iunlock(ip, XFS_IOLOCK_SHARED); + } + return; +} + +/* + * xfs_seek + * + * Return an error if the new offset has overflowed and gone below + * 0 or is greater than our maximum defined file offset. Just checking + * for overflow is not enough since off_t may be an __int64_t but the + * file size may be limited to some number of bits between 32 and 64. + */ +/*ARGSUSED*/ +STATIC int +xfs_seek( + bhv_desc_t *bdp, + xfs_off_t old_offset, + xfs_off_t *new_offsetp) +{ + vnode_t *vp; + + vp = BHV_TO_VNODE(bdp); + if (vp->v_type == VDIR) + return(0); + if ((*new_offsetp > XFS_MAX_FILE_OFFSET) || + (*new_offsetp < 0)) { + return XFS_ERROR(EINVAL); + } else { + return 0; + } +} + + +/* + * xfs_allocstore + * + * This is called to reserve or allocate space for the given range. + * Currently, this only supports reserving the space for a single + * page. By using NDPP (number of BBs per page) bmbt_irec structures, + * we ensure that the entire page can be mapped in a single bmap call. + * This simplifies the back out code in that all the information we need + * to back out is in the single bmbt_irec array orig_imap. + */ +/*ARGSUSED*/ +STATIC int +xfs_allocstore( + bhv_desc_t *bdp, + xfs_off_t offset, + size_t count, + cred_t *credp) +{ + xfs_mount_t *mp; + xfs_inode_t *ip; + xfs_off_t isize; + xfs_fileoff_t offset_fsb; + xfs_fileoff_t last_fsb; + xfs_fileoff_t curr_off_fsb; + xfs_fileoff_t unmap_offset_fsb; + xfs_filblks_t count_fsb; + xfs_filblks_t unmap_len_fsb; + xfs_fsblock_t firstblock; + xfs_bmbt_irec_t *imapp; + xfs_bmbt_irec_t *last_imapp; + int i; + int nimaps; + int orig_nimaps; + int error; + xfs_bmbt_irec_t imap[XFS_BMAP_MAX_NMAP]; + xfs_bmbt_irec_t orig_imap[NDPP]; + + + vn_trace_entry(BHV_TO_VNODE(bdp), "xfs_allocstore", + (inst_t *)__return_address); + /* + * This code currently only works for a single page. + */ +/*** + ASSERT(poff(offset) == 0); +***/ + ASSERT(count == NBPP); + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + offset_fsb = XFS_B_TO_FSBT(mp, offset); + xfs_ilock(ip, XFS_ILOCK_EXCL); + + /* + * Make sure that the dquots exist, and that they are attached to + * the inode. XXXwhy do we DQALLOC here? sup + */ + if (XFS_IS_QUOTA_ON(mp)) { + if (XFS_NOT_DQATTACHED(mp, ip)) { + if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_DQALLOC | + XFS_QMOPT_ILOCKED))) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + return (error); + } + } + } + isize = ip->i_d.di_size; + if (offset >= isize) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + return XFS_ERROR(EINVAL); + } + if ((offset + count) > isize) { + count = isize - offset; + } + last_fsb = XFS_B_TO_FSB(mp, offset + count); + count_fsb = (xfs_filblks_t)(last_fsb - offset_fsb); + orig_nimaps = NDPP; + firstblock = NULLFSBLOCK; + error = xfs_bmapi(NULL, ip, offset_fsb, count_fsb, 0, &firstblock, 0, + orig_imap, &orig_nimaps, NULL); + if (error) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + return error; + } + ASSERT(orig_nimaps > 0); + + curr_off_fsb = offset_fsb; + while (count_fsb > 0) { + nimaps = XFS_BMAP_MAX_NMAP; + firstblock = NULLFSBLOCK; + error = xfs_bmapi(NULL, ip, curr_off_fsb, + (xfs_filblks_t)(last_fsb - curr_off_fsb), + XFS_BMAPI_DELAY | XFS_BMAPI_WRITE, + &firstblock, 1, imap, &nimaps, NULL); + if (error || (nimaps == 0)) { + /* + * If we didn't get anything back, we must be + * out of space (or quota). Break out of the loop and + * back out whatever we've done so far. + * bmapi with BMAPI_DELAY can return EDQUOT. + */ + break; + } + + /* + * Count up the amount of space returned. + */ + for (i = 0; i < nimaps; i++) { + ASSERT(imap[i].br_startblock != HOLESTARTBLOCK); + count_fsb -= imap[i].br_blockcount; + ASSERT(count_fsb >= 0LL); + curr_off_fsb += imap[i].br_blockcount; + ASSERT(curr_off_fsb <= last_fsb); + } + } + + /* + * Clear out any read-ahead info since the allocations may + * have made it invalid. + */ + XFS_INODE_CLEAR_READ_AHEAD(&ip->i_iocore); + + if (count_fsb == 0) { + /* + * We go it all, so get out of here. + */ + xfs_iunlock(ip, XFS_ILOCK_EXCL); + return 0; + } + + /* + * We didn't get it all, so back out anything new that we did + * create. What we do is unmap all of the holes in the original + * map. This will do at least one unnecessary unmap, but it's + * much simpler than being exact and it still works fine since + * we hold the inode lock all along. + * + * We know we can't get errors here, since the extent list has + * already been read in and we're only removing delayed allocation + * extents. + */ + unmap_offset_fsb = offset_fsb; + imapp = &orig_imap[0]; + last_imapp = &orig_imap[orig_nimaps - 1]; + while (imapp <= last_imapp) { + if (unmap_offset_fsb != imapp->br_startoff) { + unmap_len_fsb = imapp->br_startoff - unmap_offset_fsb; + firstblock = NULLFSBLOCK; + (void) xfs_bunmapi(NULL, ip, unmap_offset_fsb, + unmap_len_fsb, 0, 1, &firstblock, + NULL, NULL); + } + unmap_offset_fsb = imapp->br_startoff + imapp->br_blockcount; + if (imapp == last_imapp) { + if (unmap_offset_fsb < (offset_fsb + count_fsb)) { + /* + * There is a hole after the last original + * imap, so unmap it as well. + */ + unmap_len_fsb = (offset_fsb + count_fsb) - + unmap_offset_fsb; + firstblock = NULLFSBLOCK; + (void) xfs_bunmapi(NULL, ip, + unmap_offset_fsb, + unmap_len_fsb, 0, 1, + &firstblock, NULL, NULL); + } + } + imapp++; + } + xfs_iunlock(ip, XFS_ILOCK_EXCL); + if (!error) { + error = XFS_ERROR(ENOSPC); + } + return error; +} + +/* + * xfs_get_uiosize - get uio size info + */ +int +xfs_get_uiosize( + xfs_mount_t *mp, + xfs_inode_t *ip, + struct biosize *bs, + cred_t *credp) +{ + int error; + + if ((error = xfs_iaccess(ip, IREAD, credp))) + return error; + + xfs_ilock(ip, XFS_ILOCK_SHARED); + + bs->biosz_flags = (ip->i_iocore.io_flags & XFS_IOCORE_UIOSZ) ? 1 : 0; + bs->biosz_read = ip->i_iocore.io_readio_log; + bs->biosz_write = ip->i_iocore.io_writeio_log; + bs->dfl_biosz_read = mp->m_readio_log; + bs->dfl_biosz_write = mp->m_writeio_log; + + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + return 0; +} + +/* + * xfs_set_biosize + * + */ +int +xfs_set_uiosize( + xfs_mount_t *mp, + xfs_inode_t *ip, + uint flags, + int read_iosizelog, + int write_iosizelog, + cred_t *credp) +{ + int max_iosizelog; + int min_iosizelog; + int memlimit; + int error; + + if ((error = xfs_iaccess(ip, IWRITE, credp))) + return error; + + memlimit = NBPP; + + switch (memlimit) { + case 4096: + memlimit = 12; + break; + case 16384: + memlimit = 14; + break; + default: + return XFS_ERROR(EINVAL); + } + + if (flags == 2) { + /* + * reset the io sizes to the filesystem default values. + * leave the maxio size alone since it won't have changed. + */ + xfs_ilock(ip, XFS_ILOCK_EXCL); + + ip->i_iocore.io_readio_log = mp->m_readio_log; + ip->i_iocore.io_readio_blocks = 1 << (int) (ip->i_iocore.io_readio_log - + mp->m_sb.sb_blocklog); + ip->i_iocore.io_writeio_log = mp->m_writeio_log; + ip->i_iocore.io_writeio_blocks = 1 << (int) (ip->i_iocore.io_writeio_log - + mp->m_sb.sb_blocklog); + ip->i_iocore.io_flags &= ~XFS_IOCORE_UIOSZ; + + xfs_iunlock(ip, XFS_ILOCK_EXCL); + + return 0; + } + + /* + * set iosizes to specified values -- screen out bogus values + */ + max_iosizelog = MAX(read_iosizelog, write_iosizelog); + min_iosizelog = MIN(read_iosizelog, write_iosizelog); + + /* + * new values can't be less than a page, less than the filesystem + * blocksize, or out of the range of tested values + */ + if (max_iosizelog < mp->m_sb.sb_blocklog || + max_iosizelog < memlimit || + min_iosizelog < mp->m_sb.sb_blocklog || + min_iosizelog < memlimit || + min_iosizelog < XFS_MIN_IO_LOG || + max_iosizelog > XFS_MAX_IO_LOG || + flags >= 2) + return XFS_ERROR(EINVAL); + + xfs_ilock(ip, XFS_ILOCK_EXCL); + + if (!(ip->i_iocore.io_flags & XFS_IOCORE_UIOSZ)) { + ip->i_iocore.io_readio_log = (uchar_t) read_iosizelog; + ip->i_iocore.io_readio_blocks = 1 << (int) (ip->i_iocore.io_readio_log - + mp->m_sb.sb_blocklog); + ip->i_iocore.io_writeio_log = (uchar_t) write_iosizelog; + ip->i_iocore.io_writeio_blocks = 1 << (int) (ip->i_iocore.io_writeio_log - + mp->m_sb.sb_blocklog); + ip->i_iocore.io_flags |= XFS_IOCORE_UIOSZ; + ip->i_iocore.io_max_io_log = MAX(max_iosizelog, ip->i_iocore.io_max_io_log); + } else { + /* + * if inode already has non-default values set, + * only allow the values to get smaller unless + * explictly overridden (flags == 1) + */ + if (read_iosizelog < ip->i_iocore.io_readio_log || flags == 1) { + ip->i_iocore.io_readio_log = (uchar_t) read_iosizelog; + ip->i_iocore.io_readio_blocks = 1 << (int) (ip->i_iocore.io_readio_log - + mp->m_sb.sb_blocklog); + ip->i_iocore.io_max_io_log = MAX(max_iosizelog, ip->i_iocore.io_max_io_log); + } + if (write_iosizelog < ip->i_iocore.io_writeio_log || flags == 1) { + ip->i_iocore.io_writeio_log = (uchar_t) write_iosizelog; + ip->i_iocore.io_writeio_blocks = 1 << (int) (ip->i_iocore.io_writeio_log - + mp->m_sb.sb_blocklog); + ip->i_iocore.io_max_io_log = MAX(max_iosizelog, ip->i_iocore.io_max_io_log); + } + } + + xfs_iunlock(ip, XFS_ILOCK_EXCL); + + return 0; +} + +int +xfs_set_dmattrs ( + bhv_desc_t *bdp, + u_int evmask, + u_int16_t state, + cred_t *credp) +{ + xfs_inode_t *ip; + xfs_trans_t *tp; + xfs_mount_t *mp; + int error; + + if (!capable(CAP_SYS_ADMIN)) + return XFS_ERROR(EPERM); + + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS); + error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES (mp), 0, 0, 0); + if (error) { + xfs_trans_cancel(tp, 0); + return error; + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + + ip->i_iocore.io_dmevmask = ip->i_d.di_dmevmask = evmask; + ip->i_iocore.io_dmstate = ip->i_d.di_dmstate = state; + + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + IHOLD(ip); + error = xfs_trans_commit(tp, 0, NULL); + + return error; +} + + +/* + * xfs_reclaim + */ +STATIC int +xfs_reclaim( + bhv_desc_t *bdp, + int flag) +{ + xfs_inode_t *ip; + int locked; + vnode_t *vp; + xfs_ihash_t *ih; + + vp = BHV_TO_VNODE(bdp); + + vn_trace_entry(vp, "xfs_reclaim", (inst_t *)__return_address); + + ASSERT(!VN_MAPPED(vp)); + ip = XFS_BHVTOI(bdp); + + ASSERT(ip->i_iocore.io_queued_bufs >= 0); + locked = 0; + + /* + * If this is not an unmount (flag == 0) and the inode's data + * still needs to be flushed, then we do not allow + * the inode to be reclaimed. This is to avoid many different + * deadlocks. + * + * Doing the VOP_FLUSHINVAL_PAGES() can cause + * us to wait in the buffer cache. We can be called here via + * vn_alloc() from xfs_iget(). We can be holding any number of + * locks at that point in the middle of a transaction, so we + * can't do anything that might need log space or the locks we + * might be holding. Flushing our buffers can require log space + * to allocate the space for delayed allocation extents underlying + * them. If the transaction we're already in has all the log + * space, then we won't be able to get any more and we'll hang. + * + * Not allowing the inode to be reclaimed if it has dirty data + * also prevents memory deadlocks where it is vhand calling here + * via the vnode shake routine. Since our dirty data might be + * delayed allocation dirty data which will require us to allocate + * memory to flush, we can't do this from vhand. + * + * It is OK to return an error here. The vnode cache will just + * come back later. + * + * XXXajs Distinguish vhand from vn_alloc and fail vhand case + * if the inode is dirty. This will prevent deadlocks where the + * process with the inode buffer locked needs memory. We can't + * always fail when the inode is dirty because then we don't + * reclaim enough. The vnode cache then grows far too large. + */ + if (!(flag & FSYNC_INVAL)) { + if (VN_DIRTY(vp) || ip->i_iocore.io_queued_bufs > 0) { + return XFS_ERROR(EAGAIN); + } + if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) { + return XFS_ERROR(EAGAIN); + } + if (!xfs_iflock_nowait(ip)) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + return XFS_ERROR(EAGAIN); + } + if ((ip->i_itemp != NULL) && + ((ip->i_itemp->ili_format.ilf_fields != 0) || + (ip->i_itemp->ili_last_fields != 0))) { + (void) xfs_iflush(ip, XFS_IFLUSH_DELWRI); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + return XFS_ERROR(EAGAIN); + } + locked = 1; + } + if ((ip->i_d.di_mode & IFMT) == IFREG) { + if (ip->i_d.di_size > 0) { + /* + * Flush and invalidate any data left around that is + * a part of this file. + * + * Get the inode's i/o lock so that buffers are pushed + * out while holding the proper lock. We can't hold + * the inode lock here since flushing out buffers may + * cause us to try to get the lock in xfs_strategy(). + * + * We don't have to call remapf() here, because there + * cannot be any mapped file references to this vnode + * since it is being reclaimed. + */ + if (locked) { + xfs_ifunlock(ip); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + locked = 0; + } + xfs_ilock(ip, XFS_IOLOCK_EXCL); + + /* + * If we hit an IO error, we need to make sure that the + * buffer and page caches of file data for + * the file are tossed away. We don't want to use + * VOP_FLUSHINVAL_PAGES here because we don't want dirty + * pages to stay attached to the vnode, but be + * marked P_BAD. pdflush/vnode_pagebad + * hates that. + */ + if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { + VOP_FLUSHINVAL_PAGES(vp, 0, -1, FI_NONE); + } else { + VOP_TOSS_PAGES(vp, 0, -1, FI_NONE); + } + + ASSERT((ip->i_iocore.io_queued_bufs == 0) && + (VN_CACHED(vp) == 0)); + ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || + ip->i_delayed_blks == 0); + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + } else if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { + /* + * di_size field may not be quite accurate if we're + * shutting down. + */ + VOP_TOSS_PAGES(vp, 0, -1, FI_NONE); + ASSERT((ip->i_iocore.io_queued_bufs == 0) && + (VN_CACHED(vp) == 0)); + } + } + + ih = ip->i_hash; + mrupdate(&ih->ih_lock); + vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip)); + mrunlock(&ih->ih_lock); + + if (!ip->i_update_core && (ip->i_itemp == NULL)) { + return xfs_finish_reclaim(ip, locked, 0); + } + + if (locked) { + xfs_ifunlock(ip); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + } + + return 0; +} + +int +xfs_finish_reclaim( + xfs_inode_t *ip, + int locked, + int from_umount) +{ + int error; + xfs_ihash_t *ih = ip->i_hash; + int sync_mode; + + mrupdate(&ih->ih_lock); + if (XFS_ITOV_NULL(ip)) { + mrunlock(&ih->ih_lock); + return(0); + } + if (locked) { + ip->i_flags |= XFS_IRECLAIM; + mrunlock(&ih->ih_lock); + } + + sync_mode = from_umount ? XFS_IFLUSH_ASYNC : + XFS_IFLUSH_DELWRI_ELSE_SYNC; + + /* + * If the inode is still dirty, then flush it out. If the inode + * is not in the AIL, then it will be OK to flush it delwri as + * long as xfs_iflush() does not keep any references to the inode. + * We leave that decision up to xfs_iflush() since it has the + * knowledge of whether it's OK to simply do a delwri flush of + * the inode or whether we need to wait until the inode is + * pulled from the AIL. + * We get the flush lock regardless, though, just to make sure + * we don't free it while it is being flushed. + */ + if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { + if (!locked) { + xfs_ilock(ip, XFS_ILOCK_EXCL); + if (ip->i_flags & XFS_IRECLAIM) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + mrunlock(&ih->ih_lock); + return(1); + } + ip->i_flags |= XFS_IRECLAIM; + mrunlock(&ih->ih_lock); + xfs_iflock(ip); + } + + if (ip->i_update_core || + ((ip->i_itemp != NULL) && + (ip->i_itemp->ili_format.ilf_fields != 0))) { + error = xfs_iflush(ip, sync_mode); + /* + * If we hit an error, typically because of filesystem + * shutdown, we don't need to let vn_reclaim to know + * because we're gonna reclaim the inode anyway. + */ + if (error) { + xfs_iunlock(ip, XFS_ILOCK_EXCL); + xfs_ireclaim(ip); + return (0); + } + xfs_iflock(ip); /* synchronize with xfs_iflush_done */ + } + + xfs_iunlock(ip, XFS_ILOCK_EXCL); + + ASSERT(ip->i_update_core == 0); + ASSERT(ip->i_itemp == NULL || + ip->i_itemp->ili_format.ilf_fields == 0); + ASSERT(ip->i_iocore.io_queued_bufs == 0); + } else { + if (!locked) + mrunlock(&ih->ih_lock); + else + xfs_iunlock(ip, XFS_ILOCK_EXCL); + } + + xfs_ireclaim(ip); + return 0; +} + +/* + * xfs_alloc_file_space() + * This routine allocates disk space for the given file. + * + * If alloc_type == 0, this request is for an ALLOCSP type + * request which will change the file size. In this case, no + * DMAPI event will be generated by the call. A TRUNCATE event + * will be generated later by xfs_setattr. + * + * If alloc_type != 0, this request is for a RESVSP type + * request, and a DMAPI DM_EVENT_WRITE will be generated if the + * lower block boundary byte address is less than the file's + * length. + * + * RETURNS: + * 0 on success + * errno on error + * + */ +int +xfs_alloc_file_space( + xfs_inode_t *ip, + xfs_off_t offset, + xfs_off_t len, + int alloc_type, + int attr_flags) +{ + xfs_filblks_t allocated_fsb; + xfs_filblks_t allocatesize_fsb; + int committed; + xfs_off_t count; + xfs_filblks_t datablocks; + int error; + xfs_fsblock_t firstfsb; + xfs_bmap_free_t free_list; + xfs_bmbt_irec_t *imapp; + xfs_bmbt_irec_t imaps[1]; + xfs_mount_t *mp; + int numrtextents; + int reccount; + uint resblks; + int rt; + int rtextsize; + xfs_fileoff_t startoffset_fsb; + xfs_trans_t *tp; + int xfs_bmapi_flags; + + vn_trace_entry(XFS_ITOV(ip), "xfs_alloc_file_space", + (inst_t *)__return_address); + mp = ip->i_mount; + + if (XFS_FORCED_SHUTDOWN(mp)) + return XFS_ERROR(EIO); + + /* + * determine if this is a realtime file + */ + if ((rt = (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) != 0) { + if (ip->i_d.di_extsize) + rtextsize = ip->i_d.di_extsize; + else + rtextsize = mp->m_sb.sb_rextsize; + } else + rtextsize = 0; + + if (XFS_IS_QUOTA_ON(mp)) { + if (XFS_NOT_DQATTACHED(mp, ip)) { + if ((error = xfs_qm_dqattach(ip, 0))) + return error; + } + } + + if (len <= 0) + return XFS_ERROR(EINVAL); + + count = len; + error = 0; + imapp = &imaps[0]; + reccount = 1; + xfs_bmapi_flags = XFS_BMAPI_WRITE | (alloc_type ? XFS_BMAPI_PREALLOC : 0); + startoffset_fsb = XFS_B_TO_FSBT(mp, offset); + allocatesize_fsb = XFS_B_TO_FSB(mp, count); + + /* Generate a DMAPI event if needed. */ + if (alloc_type != 0 && offset < ip->i_d.di_size && + (attr_flags&ATTR_DMI) == 0 && + DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) { + xfs_off_t end_dmi_offset; + + end_dmi_offset = offset+len; + if (end_dmi_offset > ip->i_d.di_size) + end_dmi_offset = ip->i_d.di_size; + error = xfs_dm_send_data_event(DM_EVENT_WRITE, XFS_ITOBHV(ip), + offset, end_dmi_offset - offset, + 0, NULL); + if (error) + return(error); + } + + /* + * allocate file space until done or until there is an error + */ +retry: + while (allocatesize_fsb && !error) { + /* + * determine if reserving space on + * the data or realtime partition. + */ + if (rt) { + xfs_fileoff_t s, e; + + s = startoffset_fsb; + do_div(s, rtextsize); + s *= rtextsize; + e = roundup_64(startoffset_fsb + allocatesize_fsb, + rtextsize); + numrtextents = (int)(e - s) / mp->m_sb.sb_rextsize; + datablocks = 0; + } else { + datablocks = allocatesize_fsb; + numrtextents = 0; + } + + /* + * allocate and setup the transaction + */ + tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); + resblks = XFS_DIOSTRAT_SPACE_RES(mp, datablocks); + error = xfs_trans_reserve(tp, + resblks, + XFS_WRITE_LOG_RES(mp), + numrtextents, + XFS_TRANS_PERM_LOG_RES, + XFS_WRITE_LOG_COUNT); + + /* + * check for running out of space + */ + if (error) { + /* + * Free the transaction structure. + */ + ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp)); + xfs_trans_cancel(tp, 0); + break; + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + if (XFS_IS_QUOTA_ON(mp)) { + if (xfs_trans_reserve_quota(tp, + ip->i_udquot, + ip->i_gdquot, + resblks, 0, 0)) { + error = XFS_ERROR(EDQUOT); + goto error1; + } + } + + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + + /* + * issue the bmapi() call to allocate the blocks + */ + XFS_BMAP_INIT(&free_list, &firstfsb); + error = xfs_bmapi(tp, ip, startoffset_fsb, + allocatesize_fsb, xfs_bmapi_flags, + &firstfsb, 0, imapp, &reccount, + &free_list); + if (error) { + goto error0; + } + + /* + * complete the transaction + */ + error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed); + if (error) { + goto error0; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + XFS_INODE_CLEAR_READ_AHEAD(&ip->i_iocore); + if (error) { + break; + } + + allocated_fsb = imapp->br_blockcount; + + if (reccount == 0) { + error = XFS_ERROR(ENOSPC); + break; + } + + startoffset_fsb += allocated_fsb; + allocatesize_fsb -= allocated_fsb; + } +dmapi_enospc_check: + if (error == ENOSPC && (attr_flags&ATTR_DMI) == 0 && + DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_NOSPACE)) { + + error = dm_send_namesp_event(DM_EVENT_NOSPACE, + XFS_ITOBHV(ip), DM_RIGHT_NULL, + XFS_ITOBHV(ip), DM_RIGHT_NULL, + NULL, NULL, 0, 0, 0); /* Delay flag intentionally unused */ + if (error == 0) + goto retry; /* Maybe DMAPI app. has made space */ + /* else fall through with error = xfs_dm_send_data_event result. */ + } + + return error; + + error0: + xfs_bmap_cancel(&free_list); + error1: + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + goto dmapi_enospc_check; +} + +/* + * Zero file bytes between startoff and endoff inclusive. + * The iolock is held exclusive and no blocks are buffered. + */ +STATIC int +xfs_zero_remaining_bytes( + xfs_inode_t *ip, + xfs_off_t startoff, + xfs_off_t endoff) +{ + xfs_buf_t *bp; + int error=0; + xfs_bmbt_irec_t imap; + xfs_off_t lastoffset; + xfs_mount_t *mp; + int nimap; + xfs_off_t offset; + xfs_fileoff_t offset_fsb; + + mp = ip->i_mount; + bp = XFS_ngetrbuf(mp->m_sb.sb_blocksize,mp); + ASSERT(!XFS_BUF_GETERROR(bp)); + + if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) { + XFS_BUF_SET_TARGET(bp, &mp->m_rtdev_targ); + } else { + XFS_BUF_SET_TARGET(bp, mp->m_ddev_targp); + } + + for (offset = startoff; offset <= endoff; offset = lastoffset + 1) { + offset_fsb = XFS_B_TO_FSBT(mp, offset); + nimap = 1; + error = xfs_bmapi(NULL, ip, offset_fsb, 1, 0, NULL, 0, &imap, + &nimap, NULL); + if (error || nimap < 1) + break; + ASSERT(imap.br_blockcount >= 1); + ASSERT(imap.br_startoff == offset_fsb); + lastoffset = XFS_FSB_TO_B(mp, imap.br_startoff + 1) - 1; + if (lastoffset > endoff) + lastoffset = endoff; + if (imap.br_startblock == HOLESTARTBLOCK) + continue; + ASSERT(imap.br_startblock != DELAYSTARTBLOCK); + if (imap.br_state == XFS_EXT_UNWRITTEN) + continue; + XFS_BUF_UNDONE(bp); + XFS_BUF_UNWRITE(bp); + XFS_BUF_READ(bp); + XFS_BUF_SET_ADDR(bp, XFS_FSB_TO_DB(ip, imap.br_startblock)); + xfsbdstrat(mp, bp); + if ((error = xfs_iowait(bp))) + break; + bzero(XFS_BUF_PTR(bp) + + (offset - XFS_FSB_TO_B(mp, imap.br_startoff)), + lastoffset - offset + 1); + XFS_BUF_UNDONE(bp); + XFS_BUF_UNREAD(bp); + XFS_BUF_WRITE(bp); + xfsbdstrat(mp, bp); + if ((error = xfs_iowait(bp))) + break; + } + XFS_nfreerbuf(bp); + return error; +} + +/* + * xfs_free_file_space() + * This routine frees disk space for the given file. + * + * This routine is only called by xfs_change_file_space + * for an UNRESVSP type call. + * + * RETURNS: + * 0 on success + * errno on error + * + */ +STATIC int +xfs_free_file_space( + xfs_inode_t *ip, + xfs_off_t offset, + xfs_off_t len, + int attr_flags) +{ + int committed; + int done; + xfs_off_t end_dmi_offset; + xfs_fileoff_t endoffset_fsb; + int error; + xfs_fsblock_t firstfsb; + xfs_bmap_free_t free_list; + xfs_off_t ilen; + xfs_bmbt_irec_t imap; + xfs_off_t ioffset; + xfs_extlen_t mod=0; + xfs_mount_t *mp; + int nimap; + uint resblks; + int rounding; + int specrt; + xfs_fileoff_t startoffset_fsb; + xfs_trans_t *tp; + + vn_trace_entry(XFS_ITOV(ip), "xfs_free_file_space", + (inst_t *)__return_address); + mp = ip->i_mount; + + if (XFS_IS_QUOTA_ON(mp)) { + if (XFS_NOT_DQATTACHED(mp, ip)) { + if ((error = xfs_qm_dqattach(ip, 0))) + return error; + } + } + + error = 0; + if (len <= 0) /* if nothing being freed */ + return error; + specrt = + (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && + !XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb); + startoffset_fsb = XFS_B_TO_FSB(mp, offset); + end_dmi_offset = offset + len; + endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset); + + if (offset < ip->i_d.di_size && + (attr_flags&ATTR_DMI) == 0 && + DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) { + if (end_dmi_offset > ip->i_d.di_size) + end_dmi_offset = ip->i_d.di_size; + error = xfs_dm_send_data_event(DM_EVENT_WRITE, XFS_ITOBHV(ip), + offset, end_dmi_offset - offset, + AT_DELAY_FLAG(attr_flags), NULL); + if (error) + return(error); + } + + xfs_ilock(ip, XFS_IOLOCK_EXCL); + rounding = MAX(1 << mp->m_sb.sb_blocklog, NBPP); + ilen = len + (offset & (rounding - 1)); + ioffset = offset & ~(rounding - 1); + if (ilen & (rounding - 1)) + ilen = (ilen + rounding) & ~(rounding - 1); + xfs_inval_cached_pages(XFS_ITOV(ip), &(ip->i_iocore), + ioffset, ilen, NULL); + /* + * Need to zero the stuff we're not freeing, on disk. + * If its specrt (realtime & can't use unwritten extents) then + * we actually need to zero the extent edges. Otherwise xfs_bunmapi + * will take care of it for us. + */ + if (specrt) { + nimap = 1; + error = xfs_bmapi(NULL, ip, startoffset_fsb, 1, 0, NULL, 0, + &imap, &nimap, NULL); + if (error) + return error; + ASSERT(nimap == 0 || nimap == 1); + if (nimap && imap.br_startblock != HOLESTARTBLOCK) { + xfs_daddr_t block; + + ASSERT(imap.br_startblock != DELAYSTARTBLOCK); + block = imap.br_startblock; + mod = do_div(block, mp->m_sb.sb_rextsize); + if (mod) + startoffset_fsb += mp->m_sb.sb_rextsize - mod; + } + nimap = 1; + error = xfs_bmapi(NULL, ip, endoffset_fsb - 1, 1, 0, NULL, 0, + &imap, &nimap, NULL); + if (error) + return error; + ASSERT(nimap == 0 || nimap == 1); + if (nimap && imap.br_startblock != HOLESTARTBLOCK) { + ASSERT(imap.br_startblock != DELAYSTARTBLOCK); + mod++; + if (mod && (mod != mp->m_sb.sb_rextsize)) + endoffset_fsb -= mod; + } + } + if ((done = (endoffset_fsb <= startoffset_fsb))) + /* + * One contiguous piece to clear + */ + error = xfs_zero_remaining_bytes(ip, offset, offset + len - 1); + else { + /* + * Some full blocks, possibly two pieces to clear + */ + if (offset < XFS_FSB_TO_B(mp, startoffset_fsb)) + error = xfs_zero_remaining_bytes(ip, offset, + XFS_FSB_TO_B(mp, startoffset_fsb) - 1); + if (!error && + XFS_FSB_TO_B(mp, endoffset_fsb) < offset + len) + error = xfs_zero_remaining_bytes(ip, + XFS_FSB_TO_B(mp, endoffset_fsb), + offset + len - 1); + } + + /* + * free file space until done or until there is an error + */ + resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); + while (!error && !done) { + + /* + * allocate and setup the transaction + */ + tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT); + error = xfs_trans_reserve(tp, + resblks, + XFS_WRITE_LOG_RES(mp), + 0, + XFS_TRANS_PERM_LOG_RES, + XFS_WRITE_LOG_COUNT); + + /* + * check for running out of space + */ + if (error) { + /* + * Free the transaction structure. + */ + ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp)); + xfs_trans_cancel(tp, 0); + break; + } + xfs_ilock(ip, XFS_ILOCK_EXCL); + if (XFS_IS_QUOTA_ON(mp)) { + if (xfs_trans_reserve_quota(tp, + ip->i_udquot, + ip->i_gdquot, + resblks, 0, 0)) { + error = XFS_ERROR(EDQUOT); + goto error1; + } + } + + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + + /* + * issue the bunmapi() call to free the blocks + */ + XFS_BMAP_INIT(&free_list, &firstfsb); + error = xfs_bunmapi(tp, ip, startoffset_fsb, + endoffset_fsb - startoffset_fsb, + 0, 2, &firstfsb, &free_list, &done); + if (error) { + goto error0; + } + + /* + * complete the transaction + */ + error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed); + if (error) { + goto error0; + } + + error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); + xfs_iunlock(ip, XFS_ILOCK_EXCL); + XFS_INODE_CLEAR_READ_AHEAD(&ip->i_iocore); + } + + xfs_iunlock(ip, XFS_IOLOCK_EXCL); + return error; + + error0: + xfs_bmap_cancel(&free_list); + error1: + xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT); + xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); + return error; +} + +/* + * xfs_change_file_space() + * This routine allocates or frees disk space for the given file. + * The user specified parameters are checked for alignment and size + * limitations. + * + * RETURNS: + * 0 on success + * errno on error + * + */ +int +xfs_change_file_space( + bhv_desc_t *bdp, + int cmd, + xfs_flock64_t *bf, + xfs_off_t offset, + cred_t *credp, + int attr_flags) +{ + int clrprealloc; + int error; + xfs_fsize_t fsize; + xfs_inode_t *ip; + xfs_mount_t *mp; + int setprealloc; + xfs_off_t startoffset; + xfs_off_t llen; + xfs_trans_t *tp; + vattr_t va; + vnode_t *vp; + + vp = BHV_TO_VNODE(bdp); + + vn_trace_entry(vp, "xfs_change_file_space", + (inst_t *)__return_address); + ip = XFS_BHVTOI(bdp); + mp = ip->i_mount; + + /* + * must be a regular file and have write permission + */ + if (vp->v_type != VREG) + return XFS_ERROR(EINVAL); + + xfs_ilock(ip, XFS_ILOCK_SHARED); + + if ((error = xfs_iaccess(ip, IWRITE, credp))) { + xfs_iunlock(ip, XFS_ILOCK_SHARED); + return error; + } + + xfs_iunlock(ip, XFS_ILOCK_SHARED); + + switch (bf->l_whence) { + case 0: /*SEEK_SET*/ + break; + case 1: /*SEEK_CUR*/ + bf->l_start += offset; + break; + case 2: /*SEEK_END*/ + bf->l_start += ip->i_d.di_size; + break; + default: + return XFS_ERROR(EINVAL); + } + + llen = bf->l_len > 0 ? bf->l_len - 1 : bf->l_len; + + if ( (bf->l_start < 0) + || (bf->l_start > XFS_MAX_FILE_OFFSET) + || (bf->l_start + llen < 0) + || (bf->l_start + llen > XFS_MAX_FILE_OFFSET)) + return XFS_ERROR(EINVAL); + + bf->l_whence = 0; + + startoffset = bf->l_start; + fsize = ip->i_d.di_size; + + /* + * XFS_IOC_RESVSP and XFS_IOC_UNRESVSP will reserve or unreserve + * file space. + * These calls do NOT zero the data space allocated to the file, + * nor do they change the file size. + * + * XFS_IOC_ALLOCSP and XFS_IOC_FREESP will allocate and free file + * space. + * These calls cause the new file data to be zeroed and the file + * size to be changed. + */ + setprealloc = clrprealloc = 0; + + switch (cmd) { + case XFS_IOC_RESVSP: + case XFS_IOC_RESVSP64: + error = xfs_alloc_file_space(ip, startoffset, bf->l_len, + 1, attr_flags); + if (error) + return error; + setprealloc = 1; + break; + + case XFS_IOC_UNRESVSP: + case XFS_IOC_UNRESVSP64: + if ((error = xfs_free_file_space(ip, startoffset, bf->l_len, + attr_flags))) + return error; + break; + + case XFS_IOC_ALLOCSP: + case XFS_IOC_ALLOCSP64: + case XFS_IOC_FREESP: + case XFS_IOC_FREESP64: + if (startoffset > fsize) { + error = xfs_alloc_file_space(ip, fsize, + startoffset - fsize, 0, attr_flags); + if (error) + break; + } + + va.va_mask = AT_SIZE; + va.va_size = startoffset; + + error = xfs_setattr(bdp, &va, attr_flags, credp); + + if (error) + return error; + + clrprealloc = 1; + break; + + default: + ASSERT(0); + return XFS_ERROR(EINVAL); + } + + /* + * update the inode timestamp, mode, and prealloc flag bits + */ + tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID); + + if ((error = xfs_trans_reserve(tp, 0, XFS_WRITEID_LOG_RES(mp), + 0, 0, 0))) { + /* ASSERT(0); */ + xfs_trans_cancel(tp, 0); + return error; + } + + xfs_ilock(ip, XFS_ILOCK_EXCL); + + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_ihold(tp, ip); + + ip->i_d.di_mode &= ~ISUID; + + /* + * Note that we don't have to worry about mandatory + * file locking being disabled here because we only + * clear the ISGID bit if the Group execute bit is + * on, but if it was on then mandatory locking wouldn't + * have been enabled. + */ + if (ip->i_d.di_mode & (IEXEC >> 3)) + ip->i_d.di_mode &= ~ISGID; + + xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); + + if (setprealloc) + ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; + else if (clrprealloc) + ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC; + + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + xfs_trans_set_sync(tp); + + error = xfs_trans_commit(tp, 0, NULL); + + xfs_iunlock(ip, XFS_ILOCK_EXCL); + + return error; +} + +vnodeops_t xfs_vnodeops = { +#ifdef CELL_CAPABLE + vop_open: BHV_IDENTITY_INIT(VN_BHV_XFS,VNODE_POSITION_BASE), +#endif + vop_open: xfs_open, + vop_close: xfs_close, + vop_read: (vop_read_t)xfs_read, + vop_write: (vop_write_t)xfs_write, + vop_ioctl: xfs_ioctl, + vop_getattr: xfs_getattr, + vop_setattr: xfs_setattr, + vop_access: xfs_access, + vop_lookup: xfs_lookup, + vop_create: xfs_create, + vop_remove: xfs_remove, + vop_link: xfs_link, + vop_rename: xfs_rename, + vop_mkdir: xfs_mkdir, + vop_rmdir: xfs_rmdir, + vop_readdir: xfs_readdir, + vop_symlink: xfs_symlink, + vop_readlink: xfs_readlink, + vop_fsync: xfs_fsync, + vop_inactive: xfs_inactive, + vop_fid2: xfs_fid2, + vop_rwlock: xfs_rwlock, + vop_rwunlock: xfs_rwunlock, + vop_seek: xfs_seek, + vop_realvp: (vop_realvp_t)fs_nosys, + vop_bmap: (vop_bmap_t)xfs_bmap, + vop_strategy: (vop_strategy_t)xfs_strategy, +#ifdef CELL_CAPABLE + vop_allocstore: xfs_allocstore, +#endif + vop_fcntl: (vop_fcntl_t)fs_nosys, + vop_reclaim: xfs_reclaim, + vop_attr_get: (vop_attr_get_t)xfs_attr_get, + vop_attr_set: (vop_attr_set_t)xfs_attr_set, + vop_attr_remove: (vop_attr_remove_t)xfs_attr_remove, + vop_attr_list: (vop_attr_list_t)xfs_attr_list, +#ifdef CONFIG_FS_POSIX_ACL + vop_acl_get: (vop_acl_get_t)xfs_acl_get, + vop_acl_set: (vop_acl_set_t)xfs_acl_set, +#endif + vop_link_removed: (vop_link_removed_t)fs_noval, + vop_vnode_change: fs_vnode_change, + vop_tosspages: fs_tosspages, + vop_flushinval_pages: fs_flushinval_pages, + vop_flush_pages: fs_flush_pages, + vop_pages_sethole: fs_pages_sethole, + vop_release: xfs_release, +}; diff -rNu linux-2.4.7/linux/fs/xfs/xfsdmapistubs.c linux-2.4-xfs/linux/fs/xfs/xfsdmapistubs.c --- linux-2.4.7/linux/fs/xfs/xfsdmapistubs.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfsdmapistubs.c Tue Sep 26 01:26:39 2000 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* Stub routines needed for the X/open implementration of the DMAPI + * spec. + */ + +#include + + +int xfs_dm_fcntl(bhv_desc_t *bdp, void *arg, int flags, xfs_off_t offset, + cred_t *credp, int *rvalp) { return nopkg(); } + +int xfs_dm_send_create_event(bhv_desc_t *dir_bdp, char *name, + mode_t new_mode, int *good_event_sent) { return 0; } + +int xfs_dm_send_data_event(dm_eventtype_t event, bhv_desc_t *bdp, + xfs_off_t offset, size_t length, int flags, vrwlock_t *locktype) + { return nopkg(); } diff -rNu linux-2.4.7/linux/fs/xfs/xfsidbg.c linux-2.4-xfs/linux/fs/xfs/xfsidbg.c --- linux-2.4.7/linux/fs/xfs/xfsidbg.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfsidbg.c Wed May 16 21:58:46 2001 @@ -0,0 +1,4695 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#undef DEBUG +#undef XFSDEBUG + +#include +#include +#include + +#include +#include +#include + +/* + * External functions & data not in header files. + */ + +static xfs_qm_t *xfs_Gqm = NULL; + +/* + * Command table functions. + */ +static void xfsidbg_xagf(xfs_agf_t *); +static void xfsidbg_xagi(xfs_agi_t *); +static void xfsidbg_xaildump(xfs_mount_t *); +static void xfsidbg_xalloc(xfs_alloc_arg_t *); +static void xfsidbg_xattrcontext(xfs_attr_list_context_t *); +static void xfsidbg_xattrleaf(xfs_attr_leafblock_t *); +static void xfsidbg_xattrsf(xfs_attr_shortform_t *); +static void xfsidbg_xbirec(xfs_bmbt_irec_t *r); +static void xfsidbg_xbmalla(xfs_bmalloca_t *); +static void xfsidbg_xbrec(xfs_bmbt_rec_64_t *); +static void xfsidbg_xbroot(xfs_inode_t *); +static void xfsidbg_xbroota(xfs_inode_t *); +static void xfsidbg_xbtcur(xfs_btree_cur_t *); +static void xfsidbg_xbuf(xfs_buf_t *); +static void xfsidbg_xbuf_real(xfs_buf_t *, int); +static void xfsidbg_xchash(xfs_mount_t *mp); +static void xfsidbg_xchashlist(xfs_chashlist_t *chl); +static void xfsidbg_xdaargs(xfs_da_args_t *); +static void xfsidbg_xdabuf(xfs_dabuf_t *); +static void xfsidbg_xdanode(xfs_da_intnode_t *); +static void xfsidbg_xdastate(xfs_da_state_t *); +static void xfsidbg_xdirleaf(xfs_dir_leafblock_t *); +static void xfsidbg_xdirsf(xfs_dir_shortform_t *); +static void xfsidbg_xdir2free(xfs_dir2_free_t *); +static void xfsidbg_xdir2sf(xfs_dir2_sf_t *); +static void xfsidbg_xexlist(xfs_inode_t *); +static void xfsidbg_xflist(xfs_bmap_free_t *); +static void xfsidbg_xhelp(void); +static void xfsidbg_xiclog(xlog_in_core_t *); +static void xfsidbg_xiclogall(xlog_in_core_t *); +static void xfsidbg_xiclogcb(xlog_in_core_t *); +static void xfsidbg_xihash(xfs_mount_t *mp); +static void xfsidbg_xinodes(xfs_mount_t *); +static void xfsidbg_xlog(xlog_t *); +static void xfsidbg_xlog_ritem(xlog_recover_item_t *); +static void xfsidbg_xlog_rtrans(xlog_recover_t *); +static void xfsidbg_xlog_rtrans_entire(xlog_recover_t *); +static void xfsidbg_xlog_tic(xlog_ticket_t *); +static void xfsidbg_xlogitem(xfs_log_item_t *); +static void xfsidbg_xmount(xfs_mount_t *); +static void xfsidbg_xnode(xfs_inode_t *ip); +static void xfsidbg_xcore(xfs_iocore_t *io); +static void xfsidbg_xperag(xfs_mount_t *); +static void xfsidbg_xqm(void); +static void xfsidbg_xqm_diskdq(xfs_disk_dquot_t *); +static void xfsidbg_xqm_dqattached_inos(xfs_mount_t *); +static void xfsidbg_xqm_dquot(xfs_dquot_t *); +static void xfsidbg_xqm_freelist_print(xfs_frlist_t *qlist, char *title); +static void xfsidbg_xqm_freelist(void); +static void xfsidbg_xqm_htab(void); +static void xfsidbg_xqm_mplist(xfs_mount_t *); +static void xfsidbg_xqm_qinfo(xfs_mount_t *mp); +static void xfsidbg_xqm_tpdqinfo(xfs_trans_t *tp); +static void xfsidbg_xsb(xfs_sb_t *, int convert); +static void xfsidbg_xtp(xfs_trans_t *); +static void xfsidbg_xtrans_res(xfs_mount_t *); + +/* kdb wrappers */ + +static int kdbm_xfs_xagf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xagf((xfs_agf_t *)addr); + return 0; +} + +static int kdbm_xfs_xagi( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xagi((xfs_agi_t *)addr); + return 0; +} + +static int kdbm_xfs_xaildump( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xaildump((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xalloc( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xalloc((xfs_alloc_arg_t *) addr); + return 0; +} + +static int kdbm_xfs_xattrcontext( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xattrcontext((xfs_attr_list_context_t *) addr); + return 0; +} + +static int kdbm_xfs_xattrleaf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xattrleaf((xfs_attr_leafblock_t *) addr); + return 0; +} + +static int kdbm_xfs_xattrsf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xattrsf((xfs_attr_shortform_t *) addr); + return 0; +} + +static int kdbm_xfs_xbirec( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xbirec((xfs_bmbt_irec_t *) addr); + return 0; +} + +static int kdbm_xfs_xbmalla( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xbmalla((xfs_bmalloca_t *)addr); + return 0; +} + +static int kdbm_xfs_xbrec( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xbrec((xfs_bmbt_rec_64_t *) addr); + return 0; +} + +static int kdbm_xfs_xbroot( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xbroot((xfs_inode_t *) addr); + return 0; +} + +static int kdbm_xfs_xbroota( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xbroota((xfs_inode_t *) addr); + return 0; +} + +static int kdbm_xfs_xbtcur( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xbtcur((xfs_btree_cur_t *) addr); + return 0; +} + +static int kdbm_xfs_xbuf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xbuf((xfs_buf_t *) addr); + return 0; +} + + +static int kdbm_xfs_xchash( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xchash((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xchashlist( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xchashlist((xfs_chashlist_t *) addr); + return 0; +} + + +static int kdbm_xfs_xdaargs( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdaargs((xfs_da_args_t *) addr); + return 0; +} + +static int kdbm_xfs_xdabuf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdabuf((xfs_dabuf_t *) addr); + return 0; +} + +static int kdbm_xfs_xdanode( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdanode((xfs_da_intnode_t *) addr); + return 0; +} + +static int kdbm_xfs_xdastate( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdastate((xfs_da_state_t *) addr); + return 0; +} + +static int kdbm_xfs_xdirleaf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdirleaf((xfs_dir_leafblock_t *) addr); + return 0; +} + +static int kdbm_xfs_xdirsf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdirsf((xfs_dir_shortform_t *) addr); + return 0; +} + +static int kdbm_xfs_xdir2free( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdir2free((xfs_dir2_free_t *) addr); + return 0; +} + +static int kdbm_xfs_xdir2sf( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xdir2sf((xfs_dir2_sf_t *) addr); + return 0; +} + +static int kdbm_xfs_xexlist( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xexlist((xfs_inode_t *) addr); + return 0; +} + +static int kdbm_xfs_xflist( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xflist((xfs_bmap_free_t *) addr); + return 0; +} + +static int kdbm_xfs_xhelp( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + if (argc != 0) + return KDB_ARGCOUNT; + + xfsidbg_xhelp(); + return 0; +} + +static int kdbm_xfs_xiclog( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xiclog((xlog_in_core_t *) addr); + return 0; +} + +static int kdbm_xfs_xiclogall( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xiclogall((xlog_in_core_t *) addr); + return 0; +} + +static int kdbm_xfs_xiclogcb( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xiclogcb((xlog_in_core_t *) addr); + return 0; +} + +static int kdbm_xfs_xihash( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xihash((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xinodes( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xinodes((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xlog( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xlog((xlog_t *) addr); + return 0; +} + +static int kdbm_xfs_xlog_ritem( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xlog_ritem((xlog_recover_item_t *) addr); + return 0; +} + +static int kdbm_xfs_xlog_rtrans( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xlog_rtrans((xlog_recover_t *) addr); + return 0; +} + +static int kdbm_xfs_xlog_rtrans_entire( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xlog_rtrans_entire((xlog_recover_t *) addr); + return 0; +} + +static int kdbm_xfs_xlog_tic( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xlog_tic((xlog_ticket_t *) addr); + return 0; +} + +static int kdbm_xfs_xlogitem( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xlogitem((xfs_log_item_t *) addr); + return 0; +} + +static int kdbm_xfs_xmount( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xmount((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xnode( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xnode((xfs_inode_t *) addr); + return 0; +} + +static int kdbm_xfs_xcore( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xcore((xfs_iocore_t *) addr); + return 0; +} + +static int kdbm_xfs_xperag( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xperag((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xqm( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + if (argc != 0) + return KDB_ARGCOUNT; + + xfsidbg_xqm(); + return 0; +} + +static int kdbm_xfs_xqm_diskdq( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xqm_diskdq((xfs_disk_dquot_t *) addr); + return 0; +} + +static int kdbm_xfs_xqm_dqattached_inos( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xqm_dqattached_inos((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xqm_dquot( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xqm_dquot((xfs_dquot_t *) addr); + return 0; +} + +static int kdbm_xfs_xqm_freelist( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + if (argc != 0) + return KDB_ARGCOUNT; + + xfsidbg_xqm_freelist(); + return 0; +} + +static int kdbm_xfs_xqm_htab( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + if (argc != 0) + return KDB_ARGCOUNT; + + xfsidbg_xqm_htab(); + return 0; +} + +static int kdbm_xfs_xqm_mplist( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xqm_mplist((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xqm_qinfo( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xqm_qinfo((xfs_mount_t *) addr); + return 0; +} + +static int kdbm_xfs_xqm_tpdqinfo( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xqm_tpdqinfo((xfs_trans_t *) addr); + return 0; +} + +static int kdbm_xfs_xsb( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + unsigned long convert=0; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1 && argc!=2) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + if (argc==2) { + /* extra argument - conversion flag */ + diag = kdbgetaddrarg(argc, argv, &nextarg, &convert, &offset, NULL, regs); + if (diag) + return diag; + } + + xfsidbg_xsb((xfs_sb_t *) addr, (int)convert); + return 0; +} + +static int kdbm_xfs_xtp( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xtp((xfs_trans_t *) addr); + return 0; +} + +static int kdbm_xfs_xtrans_res( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + xfsidbg_xtrans_res((xfs_mount_t *) addr); + return 0; +} + +/* + * Vnode descriptor dump. + * This table is a string version of all the flags defined in vnode.h. + */ +char *tab_vflags[] = { + /* local only flags */ + "INVALID0x01", /* 0x01 */ + "VINACT", /* 0x02 */ + "VRECLM", /* 0x04 */ + "INVALID0x08", /* 0x08 */ + "INVALID0x10", /* 0x10 */ + "VWAIT", /* 0x20 */ + "INVALID0x40", /* 0x40 */ + "VGONE", /* 0x80 */ + "VREMAPPING", /* 0x100 */ + "VMOUNTING", /* 0x200 */ + "VLOCKHOLD", /* 0x400 */ + "INVALID0x800", /* 0x800 */ + "INVALID0x1000", /* 0x1000 */ + "VINACTIVE_TEARDOWN", /* 0x2000 */ + "VSEMAPHORE", /* 0x4000 */ + "VUSYNC", /* 0x8000 */ + "INVALID0x10000", /* 0x10000 */ + "INVALID0x20000", /* 0x20000 */ + "INVALID0x40000", /* 0x40000 */ + "INVALID0x80000", /* 0x80000 */ + "VROOT", /* 0x100000 */ + "VNOSWAP", /* 0x200000 */ + "VISSWAP", /* 0x400000 */ + "VREPLICABLE", /* 0x800000 */ + "VNOTREPLICABLE", /* 0x1000000 */ + "VDOCMP", /* 0x2000000 */ + "VSHARE", /* 0x4000000 */ + "VFRLOCKS", /* 0x8000000 */ + "VENF_LOCKING", /* 0x10000000 */ + "VOPLOCK", /* 0x20000000 */ + "VPURGE", /* 0x40000000 */ + "INVALID0x80000000", /* 0x80000000 */ + 0 +}; + + +static char *vnode_type[] = { + "VNON", "VREG", "VDIR", "VBLK", "VLNK", "VFIFO", "VBAD", "VSOCK" +}; + +static void +printflags(register uint64_t flags, + register char **strings, + register char *name) +{ + register uint64_t mask = 1; + + if (name) + kdb_printf("%s 0x%Lx <", name, flags); + + while (flags != 0 && *strings) { + if (mask & flags) { + kdb_printf("%s ", *strings); + flags &= ~mask; + } + mask <<= 1; + strings++; + } + + if (name) + kdb_printf("> "); + + return; +} + + +static void printvnode(vnode_t *vp) +{ + bhv_desc_t *bh; + kdb_symtab_t symtab; + + + kdb_printf("vnode: 0x%p type %s\n", vp, vnode_type[vp->v_type]); + + if ((bh = vp->v_bh.bh_first)) { + kdb_printf(" v_inode 0x%p v_bh->bh_first 0x%p pobj 0x%p\n", + vp->v_inode, bh, bh->bd_pdata); + + if (kdbnearsym((unsigned int)bh->bd_ops, &symtab)) + kdb_printf(" ops %s ", symtab.sym_name); + else + kdb_printf(" ops %s/0x%p ", + "???", (void *)bh->bd_ops); + } else { + kdb_printf(" v_inode 0x%p v_bh->bh_first = NULLBHV ", + vp->v_inode); + } + + printflags((__psunsigned_t)vp->v_flag, tab_vflags, "flag ="); + kdb_printf("\n"); + +#ifdef CONFIG_XFS_VNODE_TRACING + kdb_printf(" v_trace 0x%p\n", vp->v_trace); +#endif /* CONFIG_XFS_VNODE_TRACING */ +} + + +static int kdbm_vnode( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + unsigned long addr; + int nextarg = 1; + long offset = 0; + int diag; + vnode_t *vp; +/* bhv_desc_t *bh; */ +/* kdb_symtab_t symtab;*/ + + if (argc != 1) + return KDB_ARGCOUNT; + + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + + if (diag) + return diag; + + vp = (vnode_t *)addr; + + printvnode(vp); + + return 0; +} + +#ifdef CONFIG_XFS_VNODE_TRACING +/* + * Print a vnode trace entry. + */ +static int +vn_trace_pr_entry(ktrace_entry_t *ktep) +{ + char funcname[128]; + kdb_symtab_t symtab; + + + if ((__psint_t)ktep->val[0] == 0) + return 0; + + if (kdbnearsym((unsigned int)ktep->val[8], &symtab)) { + unsigned long offval; + + offval = (unsigned int)ktep->val[8] - symtab.sym_start; + + if (offval) + sprintf(funcname, "%s+0x%lx", symtab.sym_name, offval); + else + sprintf(funcname, "%s", symtab.sym_name); + } else + funcname[0] = '\0'; + + + switch ((__psint_t)ktep->val[0]) { + case VNODE_KTRACE_ENTRY: + kdb_printf("entry to %s i_count = %d", + (char *)ktep->val[1], + (__psint_t)ktep->val[3]); + break; + + case VNODE_KTRACE_EXIT: + kdb_printf("exit from %s i_count = %d", + (char *)ktep->val[1], + (__psint_t)ktep->val[3]); + break; + + case VNODE_KTRACE_HOLD: + if ((__psint_t)ktep->val[3] != 1) + kdb_printf("hold @%s:%d(%s) i_count %d => %d ", + (char *)ktep->val[1], + (__psint_t)ktep->val[2], + funcname, + (__psint_t)ktep->val[3] - 1, + (__psint_t)ktep->val[3]); + else + kdb_printf("get @%s:%d(%s) i_count = %d", + (char *)ktep->val[1], + (__psint_t)ktep->val[2], + funcname, + (__psint_t)ktep->val[3]); + break; + + case VNODE_KTRACE_REF: + kdb_printf("ref @%s:%d(%s) i_count = %d", + (char *)ktep->val[1], + (__psint_t)ktep->val[2], + funcname, + (__psint_t)ktep->val[3]); + break; + + case VNODE_KTRACE_RELE: + if ((__psint_t)ktep->val[3] != 1) + kdb_printf("rele @%s:%d(%s) i_count %d => %d ", + (char *)ktep->val[1], + (__psint_t)ktep->val[2], + funcname, + (__psint_t)ktep->val[3], + (__psint_t)ktep->val[3] - 1); + else + kdb_printf("free @%s:%d(%s) i_count = %d", + (char *)ktep->val[1], + (__psint_t)ktep->val[2], + funcname, + (__psint_t)ktep->val[3]); + break; + + default: + kdb_printf("unknown vntrace record\n"); + return 1; + } + + kdb_printf("\n"); + + kdb_printf(" cpu = %d pid = %d ", + (__psint_t)ktep->val[6], (pid_t)ktep->val[7]); + + printflags((__psunsigned_t)ktep->val[5], tab_vflags, "flag ="); + + if (kdbnearsym((unsigned int)ktep->val[4], &symtab)) { + unsigned long offval; + + offval = (unsigned int)ktep->val[4] - symtab.sym_start; + + if (offval) + kdb_printf(" ra = %s+0x%lx", symtab.sym_name, offval); + else + kdb_printf(" ra = %s", symtab.sym_name); + } else + kdb_printf(" ra = ?? 0x%p", (void *)ktep->val[4]); + + return 1; +} + + +/* + * Print out the trace buffer attached to the given vnode. + */ +static int kdbm_vntrace( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + int diag; + int nextarg = 1; + long offset = 0; + unsigned long addr; + vnode_t *vp; + ktrace_entry_t *ktep; + ktrace_snap_t kts; + + + if (argc != 1) + return KDB_ARGCOUNT; + + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + + if (diag) + return diag; + + vp = (vnode_t *)addr; + + if (vp->v_trace == NULL) { + kdb_printf("The vnode trace buffer is not initialized\n"); + + return 0; + } + + kdb_printf("vntrace vp 0x%p\n", vp); + + ktep = ktrace_first(vp->v_trace, &kts); + + while (ktep != NULL) { + if (vn_trace_pr_entry(ktep)) + kdb_printf("\n"); + + ktep = ktrace_next(vp->v_trace, &kts); + } + + return 0; +} +/* + * Print out the trace buffer attached to the given vnode. + */ +static int kdbm_vntraceaddr( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + int diag; + int nextarg = 1; + long offset = 0; + unsigned long addr; + struct ktrace *kt; + ktrace_entry_t *ktep; + ktrace_snap_t kts; + + + if (argc != 1) + return KDB_ARGCOUNT; + + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + + if (diag) + return diag; + + kt = (struct ktrace *)addr; + + kdb_printf("vntraceaddr kt 0x%p\n", kt); + + ktep = ktrace_first(kt, &kts); + + while (ktep != NULL) { + if (vn_trace_pr_entry(ktep)) + kdb_printf("\n"); + + ktep = ktrace_next(kt, &kts); + } + + return 0; +} +#endif /* CONFIG_XFS_VNODE_TRACING */ + + +static void printinode(struct inode *ip) +{ + unsigned char *iaddr; + unsigned long addr; + + + if (ip == NULL) + return; + + kdb_printf(" i_ino = %lu i_count = %u i_dev = 0x%x i_size %Ld\n", + ip->i_ino, atomic_read(&ip->i_count), + ip->i_dev, ip->i_size); + + kdb_printf( + " i_mode = 0x%x i_nlink = %d i_rdev = 0x%x i_state = 0x%lx\n", + ip->i_mode, ip->i_nlink, + ip->i_rdev, ip->i_state); + + kdb_printf(" i_hash.nxt = 0x%p i_hash.prv = 0x%p\n", + ip->i_hash.next, ip->i_hash.prev); + kdb_printf(" i_list.nxt = 0x%p i_list.prv = 0x%p\n", + ip->i_list.next, ip->i_list.prev); + kdb_printf(" i_dentry.nxt = 0x%p i_dentry.prv = 0x%p\n", + ip->i_dentry.next, + ip->i_dentry.prev); + + addr = (unsigned long)ip; + + kdb_printf(" i_sb = 0x%p i_op = 0x%p i_data = 0x%lx nrpages = %lu\n", + ip->i_sb, ip->i_op, + addr + offsetof(struct inode, i_data), + ip->i_data.nrpages); + + iaddr = (char *)ip; + iaddr += offsetof(struct inode, u.xfs_i.vnode); + + kdb_printf(" vnode ptr 0x%p\n", iaddr); +} + + +static int kdbm_vn( + int argc, + const char **argv, + const char **envp, + struct pt_regs *regs) +{ + int diag; + int nextarg = 1; +/* char *symname; */ + long offset = 0; + unsigned long addr; + struct inode *ip; +/* bhv_desc_t *bh; */ +#ifdef CONFIG_XFS_VNODE_TRACING + ktrace_entry_t *ktep; + ktrace_snap_t kts; +#endif + vnode_t *vp; + + if (argc != 1) + return KDB_ARGCOUNT; + + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + + if (diag) + return diag; + + vp = (vnode_t *)addr; + + ip = vp->v_inode; + + kdb_printf("--> Inode @ 0x%p\n", ip); + printinode(ip); + + kdb_printf("--> Vnode @ 0x%p\n", vp); + printvnode(vp); + +#ifdef CONFIG_XFS_VNODE_TRACING + + kdb_printf("--> Vntrace @ 0x%p/0x%p\n", vp, vp->v_trace); + + if (vp->v_trace == NULL) + return 0; + + ktep = ktrace_first(vp->v_trace, &kts); + + while (ktep != NULL) { + if (vn_trace_pr_entry(ktep)) + kdb_printf("\n"); + + ktep = ktrace_next(vp->v_trace, &kts); + } +#endif /* CONFIG_XFS_VNODE_TRACING */ + + return 0; +} + + + +static struct xif { + char *name; + int (*func)(int, const char **, const char **, struct pt_regs *); + char *args; + char *help; +} xfsidbg_funcs[] = { + { "vn", kdbm_vn, "", "Dump inode/vnode/trace"}, + { "vnode", kdbm_vnode, "", "Dump vnode"}, +#ifdef CONFIG_XFS_VNODE_TRACING + { "vntrace", kdbm_vntrace, "", "Dump vnode Trace"}, + { "vntraceaddr", kdbm_vntraceaddr, "", "Dump vnode Trace by Address"}, +#endif /* CONFIG_XFS_VNODE_TRACING */ + { "xagf", kdbm_xfs_xagf, "", + "Dump XFS allocation group freespace" }, + { "xagi", kdbm_xfs_xagi, "", + "Dump XFS allocation group inode" }, + { "xail", kdbm_xfs_xaildump, "", + "Dump XFS AIL for a mountpoint" }, + { "xalloc", kdbm_xfs_xalloc, "", + "Dump XFS allocation args structure" }, + { "xattrcx", kdbm_xfs_xattrcontext, "", + "Dump XFS attr_list context struct"}, + { "xattrlf", kdbm_xfs_xattrleaf, "", + "Dump XFS attribute leaf block"}, + { "xattrsf", kdbm_xfs_xattrsf, "", + "Dump XFS attribute shortform"}, + { "xbirec", kdbm_xfs_xbirec, "", + "Dump XFS bmalloc args structure"}, + { "xbrec", kdbm_xfs_xbrec, "", + "Dump XFS bmap btree root (data)"}, + { "xbroota", kdbm_xfs_xbroota, "", + "Dump XFS bmap btree root (attr)"}, + { "xbtcur", kdbm_xfs_xbtcur, "", + "Dump XFS btree cursor"}, + { "xbuf", kdbm_xfs_xbuf, "", + "Dump XFS data from a buffer"}, + { "xchash", kdbm_xfs_xchash, "", + "Dump XFS cluster hash"}, + { "xchlist", kdbm_xfs_xchashlist, "", + "Dump XFS cluster hash list"}, + { "xd2free", kdbm_xfs_xdir2free, "", + "Dump XFS directory v2 freemap"}, + { "xdaargs", kdbm_xfs_xdaargs, "", + "Dump XFS dir/attr args structure"}, + { "xdabuf", kdbm_xfs_xdabuf, "", + "Dump XFS dir/attr buf structure"}, + { "xdanode", kdbm_xfs_xdanode, "", + "Dump XFS dir/attr node block"}, + { "xdastat", kdbm_xfs_xdastate, "", + "Dump XFS dir/attr state_blk struct"}, + { "xdirlf", kdbm_xfs_xdirleaf, "", + "Dump XFS directory leaf block"}, + { "xdirsf", kdbm_xfs_xdirsf, "", + "Dump XFS directory shortform"}, + { "xdir2sf", kdbm_xfs_xdir2sf, "", + "Dump XFS directory v2 shortform"}, + { "xdiskdq", kdbm_xfs_xqm_diskdq, "", + "Dump XFS ondisk dquot (quota) struct"}, + { "xdqatt", kdbm_xfs_xqm_dqattached_inos, "", + "All incore inodes with dquots"}, + { "xdqinfo", kdbm_xfs_xqm_tpdqinfo, "", + "Dump dqinfo structure of a trans"}, + { "xdquot", kdbm_xfs_xqm_dquot, "", + "Dump XFS dquot (quota) structure"}, + { "xexlist", kdbm_xfs_xexlist, "", + "Dump XFS bmap extents in inode"}, + { "xflist", kdbm_xfs_xflist, "", + "Dump XFS to-be-freed extent list"}, + { "xhelp", kdbm_xfs_xhelp, "", + "Print idbg-xfs help"}, + { "xicall", kdbm_xfs_xiclogall, "", + "Dump All XFS in-core logs"}, + { "xiclog", kdbm_xfs_xiclog, "", + "Dump XFS in-core log"}, + { "xihash", kdbm_xfs_xihash, "", + "Dump XFS inode hash statistics"}, + { "xinodes", kdbm_xfs_xinodes, "", + "Dump XFS inodes per mount"}, + { "xl_rcit", kdbm_xfs_xlog_ritem, "", + "Dump XFS recovery item"}, + { "xl_rctr", kdbm_xfs_xlog_rtrans, "", + "Dump XFS recovery transaction"}, + { "xl_rctr2",kdbm_xfs_xlog_rtrans_entire, "", + "Dump entire recovery transaction"}, + { "xl_tic", kdbm_xfs_xlog_tic, "", + "Dump XFS log ticket"}, + { "xlog", kdbm_xfs_xlog, "", + "Dump XFS log"}, + { "xlogcb", kdbm_xfs_xiclogcb, "", + "Dump XFS in-core log callbacks"}, + { "xlogitm", kdbm_xfs_xlogitem, "", + "Dump XFS log item structure"}, + { "xmount", kdbm_xfs_xmount, "", + "Dump XFS mount structure"}, + { "xnode", kdbm_xfs_xnode, "", + "Dump XFS inode"}, + { "xiocore", kdbm_xfs_xcore, "", + "Dump XFS iocore"}, + { "xperag", kdbm_xfs_xperag, "", + "Dump XFS per-allocation group data"}, + { "xqinfo", kdbm_xfs_xqm_qinfo, "", + "Dump mount->m_quotainfo structure"}, + { "xqm", kdbm_xfs_xqm, "", + "Dump XFS quota manager structure"}, + { "xqmfree", kdbm_xfs_xqm_freelist, "", + "Dump XFS global freelist of dquots"}, + { "xqmhtab", kdbm_xfs_xqm_htab, "", + "Dump XFS hashtable of dquots"}, + { "xqmplist",kdbm_xfs_xqm_mplist, "", + "Dump XFS all dquots of a f/s"}, + { "xsb", kdbm_xfs_xsb, " ", + "Dump XFS superblock"}, + { "xtp", kdbm_xfs_xtp, "", + "Dump XFS transaction structure"}, + { "xtrres", kdbm_xfs_xtrans_res, "", + "Dump XFS reservation values"}, + { 0, 0, 0 } +}; + +int +init_module(void) +{ + struct xif *p; + + for (p = xfsidbg_funcs; p->name; p++) + kdb_register(p->name, p->func, p->args, p->help, 0); + return 0; +} + +void +cleanup_module(void) +{ + struct xif *p; + + for (p = xfsidbg_funcs; p->name; p++) + kdb_unregister(p->name); +} + +/* + * Argument to xfs_alloc routines, for allocation type. + */ +static char *xfs_alloctype[] = { + "any_ag", "first_ag", "start_ag", "this_ag", + "start_bno", "near_bno", "this_bno" +}; + + +/* + * Prototypes for static functions. + */ +static void xfs_broot(xfs_inode_t *ip, xfs_ifork_t *f); +static void xfs_btalloc(xfs_alloc_block_t *bt, int bsz); +static void xfs_btbmap(xfs_bmbt_block_t *bt, int bsz); +static void xfs_btino(xfs_inobt_block_t *bt, int bsz); +static void xfs_buf_item_print(xfs_buf_log_item_t *blip, int summary); +static void xfs_convert_extent(xfs_bmbt_rec_64_t *rp, xfs_dfiloff_t *op, + xfs_dfsbno_t *sp, xfs_dfilblks_t *cp, int *fp); +static void xfs_dastate_path(xfs_da_state_path_t *p); +static void xfs_dir2data(void *addr, int size); +static void xfs_dir2leaf(xfs_dir2_leaf_t *leaf, int size); +static void xfs_dquot_item_print(xfs_dq_logitem_t *lip, int summary); +static void xfs_efd_item_print(xfs_efd_log_item_t *efdp, int summary); +static void xfs_efi_item_print(xfs_efi_log_item_t *efip, int summary); +static char *xfs_fmtformat(xfs_dinode_fmt_t f); +static char *xfs_fmtfsblock(xfs_fsblock_t bno, xfs_mount_t *mp); +static char *xfs_fmtino(xfs_ino_t ino, xfs_mount_t *mp); +static char *xfs_fmtlsn(xfs_lsn_t *lsnp); +static char *xfs_fmtmode(int m); +static char *xfs_fmtsize(size_t i); +static char *xfs_fmtuuid(uuid_t *); +static void xfs_inode_item_print(xfs_inode_log_item_t *ilip, int summary); +static void xfs_inodebuf(xfs_buf_t *bp); +static void xfs_prdinode(xfs_dinode_t *di, int coreonly, int convert); +static void xfs_prdinode_core(xfs_dinode_core_t *dip, int convert); +static void xfs_qoff_item_print(xfs_qoff_logitem_t *lip, int summary); +static void xfs_xexlist_fork(xfs_inode_t *ip, int whichfork); +static void xfs_xnode_fork(char *name, xfs_ifork_t *f); + +/* + * Static functions. + */ + + +/* + * Print an xfs in-inode bmap btree root. + */ +static void +xfs_broot(xfs_inode_t *ip, xfs_ifork_t *f) +{ + xfs_bmbt_block_t *broot; + int format; + int i; + xfs_bmbt_key_t *kp; + xfs_bmbt_ptr_t *pp; + + format = f == &ip->i_df ? ip->i_d.di_format : ip->i_d.di_aformat; + if ((f->if_flags & XFS_IFBROOT) == 0 || + format != XFS_DINODE_FMT_BTREE) { + kdb_printf("inode 0x%p not btree format\n", ip); + return; + } + broot = f->if_broot; + kdb_printf("block @0x%p magic %x level %d numrecs %d\n", + broot, INT_GET(broot->bb_magic, ARCH_CONVERT), INT_GET(broot->bb_level, ARCH_CONVERT), INT_GET(broot->bb_numrecs, ARCH_CONVERT)); + kp = XFS_BMAP_BROOT_KEY_ADDR(broot, 1, f->if_broot_bytes); + pp = XFS_BMAP_BROOT_PTR_ADDR(broot, 1, f->if_broot_bytes); + for (i = 1; i <= INT_GET(broot->bb_numrecs, ARCH_CONVERT); i++) + kdb_printf("\t%d: startoff %Ld ptr %Lx %s\n", + i, INT_GET(kp[i - 1].br_startoff, ARCH_CONVERT), INT_GET(pp[i - 1], ARCH_CONVERT), + xfs_fmtfsblock(INT_GET(pp[i - 1], ARCH_CONVERT), ip->i_mount)); +} + +/* + * Print allocation btree block. + */ +static void +xfs_btalloc(xfs_alloc_block_t *bt, int bsz) +{ + int i; + + kdb_printf("magic 0x%x level %d numrecs %d leftsib 0x%x rightsib 0x%x\n", + INT_GET(bt->bb_magic, ARCH_CONVERT), INT_GET(bt->bb_level, ARCH_CONVERT), INT_GET(bt->bb_numrecs, ARCH_CONVERT), + INT_GET(bt->bb_leftsib, ARCH_CONVERT), INT_GET(bt->bb_rightsib, ARCH_CONVERT)); + if (INT_GET(bt->bb_level, ARCH_CONVERT) == 0) { + + for (i = 1; i <= INT_GET(bt->bb_numrecs, ARCH_CONVERT); i++) { + xfs_alloc_rec_t *r; + + r = XFS_BTREE_REC_ADDR(bsz, xfs_alloc, bt, i, 0); + kdb_printf("rec %d startblock 0x%x blockcount %d\n", + i, INT_GET(r->ar_startblock, ARCH_CONVERT), INT_GET(r->ar_blockcount, ARCH_CONVERT)); + } + } else { + int mxr; + + mxr = XFS_BTREE_BLOCK_MAXRECS(bsz, xfs_alloc, 0); + for (i = 1; i <= INT_GET(bt->bb_numrecs, ARCH_CONVERT); i++) { + xfs_alloc_key_t *k; + xfs_alloc_ptr_t *p; + + k = XFS_BTREE_KEY_ADDR(bsz, xfs_alloc, bt, i, mxr); + p = XFS_BTREE_PTR_ADDR(bsz, xfs_alloc, bt, i, mxr); + kdb_printf("key %d startblock 0x%x blockcount %d ptr 0x%x\n", + i, INT_GET(k->ar_startblock, ARCH_CONVERT), INT_GET(k->ar_blockcount, ARCH_CONVERT), *p); + } + } +} + +/* + * Print a bmap btree block. + */ +static void +xfs_btbmap(xfs_bmbt_block_t *bt, int bsz) +{ + int i; + + kdb_printf("magic 0x%x level %d numrecs %d leftsib %Lx ", + INT_GET(bt->bb_magic, ARCH_CONVERT), + INT_GET(bt->bb_level, ARCH_CONVERT), + INT_GET(bt->bb_numrecs, ARCH_CONVERT), + INT_GET(bt->bb_leftsib, ARCH_CONVERT)); + kdb_printf("rightsib %Lx\n", INT_GET(bt->bb_rightsib, ARCH_CONVERT)); + if (INT_GET(bt->bb_level, ARCH_CONVERT) == 0) { + for (i = 1; i <= INT_GET(bt->bb_numrecs, ARCH_CONVERT); i++) { + xfs_bmbt_rec_64_t *r; + xfs_dfiloff_t o; + xfs_dfsbno_t s; + xfs_dfilblks_t c; + int fl; + + r = (xfs_bmbt_rec_64_t *)XFS_BTREE_REC_ADDR(bsz, + xfs_bmbt, bt, i, 0); + xfs_convert_extent(r, &o, &s, &c, &fl); + kdb_printf("rec %d startoff %Ld ", i, o); + kdb_printf("startblock %Lx ", s); + kdb_printf("blockcount %Ld flag %d\n", c, fl); + } + } else { + int mxr; + + mxr = XFS_BTREE_BLOCK_MAXRECS(bsz, xfs_bmbt, 0); + for (i = 1; i <= INT_GET(bt->bb_numrecs, ARCH_CONVERT); i++) { + xfs_bmbt_key_t *k; + xfs_bmbt_ptr_t *p; + + k = XFS_BTREE_KEY_ADDR(bsz, xfs_bmbt, bt, i, mxr); + p = XFS_BTREE_PTR_ADDR(bsz, xfs_bmbt, bt, i, mxr); + kdb_printf("key %d startoff %Ld ", + i, INT_GET(k->br_startoff, ARCH_CONVERT)); + kdb_printf("ptr %Lx\n", INT_GET(*p, ARCH_CONVERT)); + } + } +} + +/* + * Print an inode btree block. + */ +static void +xfs_btino(xfs_inobt_block_t *bt, int bsz) +{ + int i; + + kdb_printf("magic 0x%x level %d numrecs %d leftsib 0x%x rightsib 0x%x\n", + INT_GET(bt->bb_magic, ARCH_CONVERT), INT_GET(bt->bb_level, ARCH_CONVERT), INT_GET(bt->bb_numrecs, ARCH_CONVERT), + INT_GET(bt->bb_leftsib, ARCH_CONVERT), INT_GET(bt->bb_rightsib, ARCH_CONVERT)); + if (INT_GET(bt->bb_level, ARCH_CONVERT) == 0) { + + for (i = 1; i <= INT_GET(bt->bb_numrecs, ARCH_CONVERT); i++) { + xfs_inobt_rec_t *r; + + r = XFS_BTREE_REC_ADDR(bsz, xfs_inobt, bt, i, 0); + kdb_printf("rec %d startino 0x%x freecount %d, free %Lx\n", + i, INT_GET(r->ir_startino, ARCH_CONVERT), INT_GET(r->ir_freecount, ARCH_CONVERT), + INT_GET(r->ir_free, ARCH_CONVERT)); + } + } else { + int mxr; + + mxr = XFS_BTREE_BLOCK_MAXRECS(bsz, xfs_inobt, 0); + for (i = 1; i <= INT_GET(bt->bb_numrecs, ARCH_CONVERT); i++) { + xfs_inobt_key_t *k; + xfs_inobt_ptr_t *p; + + k = XFS_BTREE_KEY_ADDR(bsz, xfs_inobt, bt, i, mxr); + p = XFS_BTREE_PTR_ADDR(bsz, xfs_inobt, bt, i, mxr); + kdb_printf("key %d startino 0x%x ptr 0x%x\n", + i, INT_GET(k->ir_startino, ARCH_CONVERT), INT_GET(*p, ARCH_CONVERT)); + } + } +} + +/* + * Print a buf log item. + */ +static void +xfs_buf_item_print(xfs_buf_log_item_t *blip, int summary) +{ + static char *bli_flags[] = { + "hold", /* 0x1 */ + "dirty", /* 0x2 */ + "stale", /* 0x4 */ + "logged", /* 0x8 */ + "ialloc", /* 0x10 */ + 0 + }; + static char *blf_flags[] = { + "inode", /* 0x1 */ + "cancel", /* 0x2 */ + 0 + }; + + if (summary) { + kdb_printf("buf 0x%p blkno 0x%Lx ", blip->bli_buf, + blip->bli_format.blf_blkno); + printflags(blip->bli_flags, bli_flags, "flags:"); + kdb_printf("\n "); + xfsidbg_xbuf_real(blip->bli_buf, 1); + return; + } + kdb_printf("buf 0x%p recur %d refcount %d flags:", + blip->bli_buf, blip->bli_recur, + atomic_read(&blip->bli_refcount)); + printflags(blip->bli_flags, bli_flags, NULL); + kdb_printf("\n"); + kdb_printf("size %d blkno 0x%Lx len 0x%x map size %d map 0x%p\n", + blip->bli_format.blf_size, blip->bli_format.blf_blkno, + (uint) blip->bli_format.blf_len, blip->bli_format.blf_map_size, + &(blip->bli_format.blf_data_map[0])); + kdb_printf("blf flags: "); + printflags((uint)blip->bli_format.blf_flags, blf_flags, NULL); +#ifdef XFS_TRANS_DEBUG + kdb_printf("orig 0x%x logged 0x%x", + blip->bli_orig, blip->bli_logged); +#endif + kdb_printf("\n"); +} + +/* + * Convert an external extent descriptor to internal form. + */ +static void +xfs_convert_extent(xfs_bmbt_rec_64_t *rp, xfs_dfiloff_t *op, xfs_dfsbno_t *sp, + xfs_dfilblks_t *cp, int *fp) +{ + xfs_dfiloff_t o; + xfs_dfsbno_t s; + xfs_dfilblks_t c; + int flag; + + flag = (int)((INT_GET(rp->l0, ARCH_CONVERT)) >> (64 - 1 )); + o = ((xfs_fileoff_t)INT_GET(rp->l0, ARCH_CONVERT) & + (((__uint64_t)1 << ( 64 - 1 )) - 1) ) >> 9; + s = (((xfs_fsblock_t)INT_GET(rp->l0, ARCH_CONVERT) & (((__uint64_t)1 << ( 9 )) - 1) ) << 43) | + (((xfs_fsblock_t)INT_GET(rp->l1, ARCH_CONVERT)) >> 21); + c = (xfs_filblks_t)(INT_GET(rp->l1, ARCH_CONVERT) & (((__uint64_t)1 << ( 21 )) - 1) ); + *op = o; + *sp = s; + *cp = c; + *fp = flag; +} + + +/* + * Print an xfs_da_state_path structure. + */ +static void +xfs_dastate_path(xfs_da_state_path_t *p) +{ + int i; + + kdb_printf("active %d\n", p->active); + for (i = 0; i < XFS_DA_NODE_MAXDEPTH; i++) { +#if XFS_BIG_FILES + kdb_printf(" blk %d bp 0x%p blkno 0x%x", +#else + kdb_printf(" blk %d bp 0x%p blkno 0x%Lx", +#endif + i, p->blk[i].bp, p->blk[i].blkno); + kdb_printf(" index %d hashval 0x%x ", + p->blk[i].index, (uint_t)p->blk[i].hashval); + switch(p->blk[i].magic) { + case XFS_DA_NODE_MAGIC: kdb_printf("NODE\n"); break; + case XFS_DIR_LEAF_MAGIC: kdb_printf("DIR\n"); break; + case XFS_ATTR_LEAF_MAGIC: kdb_printf("ATTR\n"); break; + case XFS_DIR2_LEAFN_MAGIC: kdb_printf("DIR2\n"); break; + default: kdb_printf("type ??\n"); break; + } + } +} + + +/* + * Print an efd log item. + */ +static void +xfs_efd_item_print(xfs_efd_log_item_t *efdp, int summary) +{ + int i; + xfs_extent_t *ep; + + if (summary) { + kdb_printf("Extent Free Done: ID 0x%Lx nextents %d (at 0x%p)\n", + efdp->efd_format.efd_efi_id, + efdp->efd_format.efd_nextents, efdp); + return; + } + kdb_printf("size %d nextents %d next extent %d efip 0x%p\n", + efdp->efd_format.efd_size, efdp->efd_format.efd_nextents, + efdp->efd_next_extent, efdp->efd_efip); + kdb_printf("efi_id 0x%Lx\n", efdp->efd_format.efd_efi_id); + kdb_printf("efd extents:\n"); + ep = &(efdp->efd_format.efd_extents[0]); + for (i = 0; i < efdp->efd_next_extent; i++, ep++) { + kdb_printf(" block %Lx len %d\n", + ep->ext_start, ep->ext_len); + } +} + +/* + * Print an efi log item. + */ +static void +xfs_efi_item_print(xfs_efi_log_item_t *efip, int summary) +{ + int i; + xfs_extent_t *ep; + static char *efi_flags[] = { + "recovered", /* 0x1 */ + "committed", /* 0x2 */ + "cancelled", /* 0x4 */ + 0, + }; + + if (summary) { + kdb_printf("Extent Free Intention: ID 0x%Lx nextents %d (at 0x%p)\n", + efip->efi_format.efi_id, + efip->efi_format.efi_nextents, efip); + return; + } + kdb_printf("size %d nextents %d next extent %d\n", + efip->efi_format.efi_size, efip->efi_format.efi_nextents, + efip->efi_next_extent); + kdb_printf("id %Lx", efip->efi_format.efi_id); + printflags(efip->efi_flags, efi_flags, "flags :"); + kdb_printf("\n"); + kdb_printf("efi extents:\n"); + ep = &(efip->efi_format.efi_extents[0]); + for (i = 0; i < efip->efi_next_extent; i++, ep++) { + kdb_printf(" block %Lx len %d\n", + ep->ext_start, ep->ext_len); + } +} + +/* + * Format inode "format" into a static buffer & return it. + */ +static char * +xfs_fmtformat(xfs_dinode_fmt_t f) +{ + static char *t[] = { + "dev", + "local", + "extents", + "btree", + "uuid" + }; + + return t[f]; +} + +/* + * Format fsblock number into a static buffer & return it. + */ +static char * +xfs_fmtfsblock(xfs_fsblock_t bno, xfs_mount_t *mp) +{ + static char rval[50]; + + if (bno == NULLFSBLOCK) + sprintf(rval, "NULLFSBLOCK"); + else if (ISNULLSTARTBLOCK(bno)) + sprintf(rval, "NULLSTARTBLOCK(%Ld)", STARTBLOCKVAL(bno)); + else if (mp) + sprintf(rval, "%Ld[%x:%x]", (xfs_dfsbno_t)bno, + XFS_FSB_TO_AGNO(mp, bno), XFS_FSB_TO_AGBNO(mp, bno)); + else + sprintf(rval, "%Ld", (xfs_dfsbno_t)bno); + return rval; +} + +/* + * Format inode number into a static buffer & return it. + */ +static char * +xfs_fmtino(xfs_ino_t ino, xfs_mount_t *mp) +{ + static char rval[50]; + + if (mp) + sprintf(rval, "%Ld[%x:%x:%x]", ino, XFS_INO_TO_AGNO(mp, ino), + XFS_INO_TO_AGBNO(mp, ino), XFS_INO_TO_OFFSET(mp, ino)); + else + sprintf(rval, "%Ld", ino); + return rval; +} + +/* + * Format an lsn for printing into a static buffer & return it. + */ +static char * +xfs_fmtlsn(xfs_lsn_t *lsnp) +{ + uint *wordp; + uint *word2p; + static char buf[20]; + + wordp = (uint *)lsnp; + word2p = wordp++; + sprintf(buf, "[%x:%x]", *wordp, *word2p); + + return buf; +} + +/* + * Format file mode into a static buffer & return it. + */ +static char * +xfs_fmtmode(int m) +{ + static char rval[16]; + + sprintf(rval, "%c%c%c%c%c%c%c%c%c%c%c%c%c", + "?fc?dxb?r?l?S?m?"[(m & IFMT) >> 12], + m & ISUID ? 'u' : '-', + m & ISGID ? 'g' : '-', + m & ISVTX ? 'v' : '-', + m & IREAD ? 'r' : '-', + m & IWRITE ? 'w' : '-', + m & IEXEC ? 'x' : '-', + m & (IREAD >> 3) ? 'r' : '-', + m & (IWRITE >> 3) ? 'w' : '-', + m & (IEXEC >> 3) ? 'x' : '-', + m & (IREAD >> 6) ? 'r' : '-', + m & (IWRITE >> 6) ? 'w' : '-', + m & (IEXEC >> 6) ? 'x' : '-'); + return rval; +} + +/* + * Format a size into a static buffer & return it. + */ +static char * +xfs_fmtsize(size_t i) +{ + static char rval[20]; + + /* size_t is 32 bits in 32-bit kernel, 64 bits in 64-bit kernel */ + sprintf(rval, "0x%x", i); + return rval; +} + +/* + * Format a uuid into a static buffer & return it. + */ +static char * +xfs_fmtuuid(uuid_t *uu) +{ + static char rval[40]; + char *o = rval; + char *i = (unsigned char*)uu; + int b; + + for (b=0;b<16;b++) { + o+=sprintf(o, "%02x", *i++); + if (b==3||b==5||b==7||b==9) *o++='-'; + } + *o='\0'; + + return rval; +} + +/* + * Print an inode log item. + */ +static void +xfs_inode_item_print(xfs_inode_log_item_t *ilip, int summary) +{ + static char *ili_flags[] = { + "hold", /* 0x1 */ + "iolock excl", /* 0x2 */ + "iolock shrd", /* 0x4 */ + 0 + }; + static char *ilf_fields[] = { + "core", /* 0x001 */ + "ddata", /* 0x002 */ + "dexts", /* 0x004 */ + "dbroot", /* 0x008 */ + "dev", /* 0x010 */ + "uuid", /* 0x020 */ + "adata", /* 0x040 */ + "aext", /* 0x080 */ + "abroot", /* 0x100 */ + 0 + }; + + if (summary) { + kdb_printf("inode 0x%p logged %d ", + ilip->ili_inode, ilip->ili_logged); + printflags(ilip->ili_flags, ili_flags, "flags:"); + printflags(ilip->ili_format.ilf_fields, ilf_fields, "format:"); + printflags(ilip->ili_last_fields, ilf_fields, "lastfield:"); + kdb_printf("\n"); + return; + } + kdb_printf("inode 0x%p ino 0x%Lx logged %d flags: ", + ilip->ili_inode, ilip->ili_format.ilf_ino, ilip->ili_logged); + printflags(ilip->ili_flags, ili_flags, NULL); + kdb_printf("\n"); + kdb_printf("ilock recur %d iolock recur %d ext buf 0x%p\n", + ilip->ili_ilock_recur, ilip->ili_iolock_recur, + ilip->ili_extents_buf); +#ifdef XFS_TRANS_DEBUG + kdb_printf("root bytes %d root orig 0x%x\n", + ilip->ili_root_size, ilip->ili_orig_root); +#endif + kdb_printf("size %d fields: ", ilip->ili_format.ilf_size); + printflags(ilip->ili_format.ilf_fields, ilf_fields, "formatfield"); + kdb_printf(" last fields: "); + printflags(ilip->ili_last_fields, ilf_fields, "lastfield"); + kdb_printf("\n"); + kdb_printf(" flush lsn %s last lsn %s\n", + xfs_fmtlsn(&(ilip->ili_flush_lsn)), + xfs_fmtlsn(&(ilip->ili_last_lsn))); + kdb_printf("dsize %d, asize %d, rdev 0x%x\n", + ilip->ili_format.ilf_dsize, + ilip->ili_format.ilf_asize, + ilip->ili_format.ilf_u.ilfu_rdev); + kdb_printf("blkno 0x%Lx len 0x%x boffset 0x%x\n", + ilip->ili_format.ilf_blkno, + ilip->ili_format.ilf_len, + ilip->ili_format.ilf_boffset); +} + +/* + * Print a dquot log item. + */ +/* ARGSUSED */ +static void +xfs_dquot_item_print(xfs_dq_logitem_t *lip, int summary) +{ + kdb_printf("dquot 0x%p\n", + lip->qli_dquot); + +} + +/* + * Print a quotaoff log item. + */ +/* ARGSUSED */ +static void +xfs_qoff_item_print(xfs_qoff_logitem_t *lip, int summary) +{ + kdb_printf("start qoff item 0x%p flags 0x%x\n", + lip->qql_start_lip, lip->qql_format.qf_flags); + +} + +/* + * Print buffer full of inodes. + */ +static void +xfs_inodebuf(xfs_buf_t *bp) +{ + xfs_dinode_t *di; + int n, i; + + n = XFS_BUF_COUNT(bp) >> 8; + for (i = 0; i < n; i++) { + di = (xfs_dinode_t *)xfs_buf_offset(bp, + i * 256); + xfs_prdinode(di, 0, ARCH_CONVERT); + } +} + + +/* + * Print disk inode. + */ +static void +xfs_prdinode(xfs_dinode_t *di, int coreonly, int convert) +{ + xfs_prdinode_core(&di->di_core, convert); + if (!coreonly) + kdb_printf("next_unlinked 0x%x u@0x%p\n", + INT_GET(di->di_next_unlinked, convert), + &di->di_u); +} + +/* + * Print disk inode core. + */ +static void +xfs_prdinode_core(xfs_dinode_core_t *dip, int convert) +{ + static char *diflags[] = { + "realtime", /* XFS_DIFLAG_REALTIME */ + "prealloc", /* XFS_DIFLAG_PREALLOC */ + NULL + }; + + kdb_printf("magic 0x%x mode 0%o (%s) version 0x%x format 0x%x (%s)\n", + INT_GET(dip->di_magic, convert), + INT_GET(dip->di_mode, convert), + xfs_fmtmode(INT_GET(dip->di_mode, convert)), + INT_GET(dip->di_version, convert), + INT_GET(dip->di_format, convert), + xfs_fmtformat( + (xfs_dinode_fmt_t)INT_GET(dip->di_format, convert))); + kdb_printf("nlink 0x%x uid 0x%x gid 0x%x projid 0x%x\n", + INT_GET(dip->di_nlink, convert), + INT_GET(dip->di_uid, convert), + INT_GET(dip->di_gid, convert), + (uint)INT_GET(dip->di_projid, convert)); + kdb_printf("atime 0x%x:%x mtime 0x%x:%x ctime 0x%x:%x\n", + INT_GET(dip->di_atime.t_sec, convert), + INT_GET(dip->di_atime.t_nsec, convert), + INT_GET(dip->di_mtime.t_sec, convert), + INT_GET(dip->di_mtime.t_nsec, convert), + INT_GET(dip->di_ctime.t_sec, convert), + INT_GET(dip->di_ctime.t_nsec, convert)); + kdb_printf("size 0x%Lx ", INT_GET(dip->di_size, convert)); + kdb_printf("nblocks %Ld extsize 0x%x nextents 0x%x anextents 0x%x\n", + INT_GET(dip->di_nblocks, convert), + INT_GET(dip->di_extsize, convert), + INT_GET(dip->di_nextents, convert), + INT_GET(dip->di_anextents, convert)); + kdb_printf("forkoff %d aformat 0x%x (%s) dmevmask 0x%x dmstate 0x%x ", + INT_GET(dip->di_forkoff, convert), + INT_GET(dip->di_aformat, convert), + xfs_fmtformat( + (xfs_dinode_fmt_t)INT_GET(dip->di_aformat, convert)), + INT_GET(dip->di_dmevmask, convert), + INT_GET(dip->di_dmstate, convert)); + printflags(INT_GET(dip->di_flags, convert), diflags, "flags"); + kdb_printf("gen 0x%x\n", INT_GET(dip->di_gen, convert)); +} + +/* + * Print xfs extent list for a fork. + */ +static void +xfs_xexlist_fork(xfs_inode_t *ip, int whichfork) +{ + int nextents, i; + xfs_dfiloff_t o; + xfs_dfsbno_t s; + xfs_dfilblks_t c; + int flag; + xfs_ifork_t *ifp; + + ifp = XFS_IFORK_PTR(ip, whichfork); + if (ifp->if_flags & XFS_IFEXTENTS) { + nextents = ifp->if_bytes / sizeof(xfs_bmbt_rec_64_t); + kdb_printf("inode 0x%p %cf extents 0x%p nextents 0x%x\n", + ip, "da"[whichfork], ifp->if_u1.if_extents, nextents); + for (i = 0; i < nextents; i++) { + xfs_convert_extent( + (xfs_bmbt_rec_64_t *)&ifp->if_u1.if_extents[i], + &o, &s, &c, &flag); + kdb_printf( + "%d: startoff %Ld startblock %s blockcount %Ld flag %d\n", + i, o, xfs_fmtfsblock(s, ip->i_mount), c, flag); + } + } +} + +static void +xfs_xnode_fork(char *name, xfs_ifork_t *f) +{ + static char *tab_flags[] = { + "inline", /* XFS_IFINLINE */ + "extents", /* XFS_IFEXTENTS */ + "broot", /* XFS_IFBROOT */ + NULL + }; + int *p; + + kdb_printf("%s fork", name); + if (f == NULL) { + kdb_printf(" empty\n"); + return; + } else + kdb_printf("\n"); + kdb_printf(" bytes %s ", xfs_fmtsize(f->if_bytes)); + kdb_printf("real_bytes %s lastex 0x%x u1:%s 0x%p\n", + xfs_fmtsize(f->if_real_bytes), f->if_lastex, + f->if_flags & XFS_IFINLINE ? "data" : "extents", + f->if_flags & XFS_IFINLINE ? + f->if_u1.if_data : + (char *)f->if_u1.if_extents); + kdb_printf(" broot 0x%p broot_bytes %s ext_max %d ", + f->if_broot, xfs_fmtsize(f->if_broot_bytes), f->if_ext_max); + printflags(f->if_flags, tab_flags, "flags"); + kdb_printf("\n"); + kdb_printf(" u2"); + for (p = (int *)&f->if_u2; + p < (int *)((char *)&f->if_u2 + XFS_INLINE_DATA); + p++) + kdb_printf(" 0x%x", *p); + kdb_printf("\n"); +} + +/* + * Command-level xfs-idbg functions. + */ + +/* + * Print xfs allocation group freespace header. + */ +static void +xfsidbg_xagf(xfs_agf_t *agf) +{ + kdb_printf("magicnum 0x%x versionnum 0x%x seqno 0x%x length 0x%x\n", + INT_GET(agf->agf_magicnum, ARCH_CONVERT), + INT_GET(agf->agf_versionnum, ARCH_CONVERT), + INT_GET(agf->agf_seqno, ARCH_CONVERT), + INT_GET(agf->agf_length, ARCH_CONVERT)); + kdb_printf("roots b 0x%x c 0x%x levels b %d c %d\n", + INT_GET(agf->agf_roots[XFS_BTNUM_BNO], ARCH_CONVERT), + INT_GET(agf->agf_roots[XFS_BTNUM_CNT], ARCH_CONVERT), + INT_GET(agf->agf_levels[XFS_BTNUM_BNO], ARCH_CONVERT), + INT_GET(agf->agf_levels[XFS_BTNUM_CNT], ARCH_CONVERT)); + kdb_printf("flfirst %d fllast %d flcount %d freeblks %d longest %d\n", + INT_GET(agf->agf_flfirst, ARCH_CONVERT), + INT_GET(agf->agf_fllast, ARCH_CONVERT), + INT_GET(agf->agf_flcount, ARCH_CONVERT), + INT_GET(agf->agf_freeblks, ARCH_CONVERT), + INT_GET(agf->agf_longest, ARCH_CONVERT)); +} + +/* + * Print xfs allocation group inode header. + */ +static void +xfsidbg_xagi(xfs_agi_t *agi) +{ + int i; + int j; + + kdb_printf("magicnum 0x%x versionnum 0x%x seqno 0x%x length 0x%x\n", + INT_GET(agi->agi_magicnum, ARCH_CONVERT), + INT_GET(agi->agi_versionnum, ARCH_CONVERT), + INT_GET(agi->agi_seqno, ARCH_CONVERT), + INT_GET(agi->agi_length, ARCH_CONVERT)); + kdb_printf("count 0x%x root 0x%x level 0x%x\n", + INT_GET(agi->agi_count, ARCH_CONVERT), + INT_GET(agi->agi_root, ARCH_CONVERT), + INT_GET(agi->agi_level, ARCH_CONVERT)); + kdb_printf("freecount 0x%x newino 0x%x dirino 0x%x\n", + INT_GET(agi->agi_freecount, ARCH_CONVERT), + INT_GET(agi->agi_newino, ARCH_CONVERT), + INT_GET(agi->agi_dirino, ARCH_CONVERT)); + + kdb_printf("unlinked buckets\n"); + for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) { + for (j = 0; j < 4; j++, i++) { + kdb_printf("0x%08x ", + INT_GET(agi->agi_unlinked[i], ARCH_CONVERT)); + } + kdb_printf("\n"); + } +} + + +/* + * Print an allocation argument structure for XFS. + */ +static void +xfsidbg_xalloc(xfs_alloc_arg_t *args) +{ + kdb_printf("tp 0x%p mp 0x%p agbp 0x%p pag 0x%p fsbno %s\n", + args->tp, args->mp, args->agbp, args->pag, + xfs_fmtfsblock(args->fsbno, args->mp)); + kdb_printf("agno 0x%x agbno 0x%x minlen 0x%x maxlen 0x%x mod 0x%x\n", + args->agno, args->agbno, args->minlen, args->maxlen, args->mod); + kdb_printf("prod 0x%x minleft 0x%x total 0x%x alignment 0x%x\n", + args->prod, args->minleft, args->total, args->alignment); + kdb_printf("minalignslop 0x%x len 0x%x type %s otype %s wasdel %d\n", + args->minalignslop, args->len, xfs_alloctype[args->type], + xfs_alloctype[args->otype], args->wasdel); + kdb_printf("wasfromfl %d isfl %d userdata %d\n", + args->wasfromfl, args->isfl, args->userdata); +} + + + +/* + * Print an attr_list() context structure. + */ +static void +xfsidbg_xattrcontext(xfs_attr_list_context_t *context) +{ + static char *attr_arg_flags[] = { + "DONTFOLLOW", /* 0x0001 */ + "?", /* 0x0002 */ + "?", /* 0x0004 */ + "?", /* 0x0008 */ + "CREATE", /* 0x0010 */ + "?", /* 0x0020 */ + "?", /* 0x0040 */ + "?", /* 0x0080 */ + "?", /* 0x0100 */ + "?", /* 0x0200 */ + "?", /* 0x0400 */ + "?", /* 0x0800 */ + "KERNOTIME", /* 0x1000 */ + NULL + }; + + kdb_printf("dp 0x%p, dupcnt %d, resynch %d", + context->dp, context->dupcnt, context->resynch); + printflags((__psunsigned_t)context->flags, attr_arg_flags, ", flags"); + kdb_printf("\ncursor h/b/o 0x%x/0x%x/%d -- p/p/i 0x%x/0x%x/0x%x\n", + context->cursor->hashval, context->cursor->blkno, + context->cursor->offset, context->cursor->pad1, + context->cursor->pad2, context->cursor->initted); + kdb_printf("alist 0x%p, bufsize 0x%x, count %d, firstu 0x%x\n", + context->alist, context->bufsize, context->count, + context->firstu); +} + +/* + * Print attribute leaf block. + */ +static void +xfsidbg_xattrleaf(xfs_attr_leafblock_t *leaf) +{ + xfs_attr_leaf_hdr_t *h; + xfs_da_blkinfo_t *i; + xfs_attr_leaf_map_t *m; + xfs_attr_leaf_entry_t *e; + xfs_attr_leaf_name_local_t *l; + xfs_attr_leaf_name_remote_t *r; + int j, k; + + h = &leaf->hdr; + i = &h->info; + kdb_printf("hdr info forw 0x%x back 0x%x magic 0x%x\n", + i->forw, i->back, i->magic); + kdb_printf("hdr count %d usedbytes %d firstused %d holes %d\n", + INT_GET(h->count, ARCH_CONVERT), + INT_GET(h->usedbytes, ARCH_CONVERT), + INT_GET(h->firstused, ARCH_CONVERT), h->holes); + for (j = 0, m = h->freemap; j < XFS_ATTR_LEAF_MAPSIZE; j++, m++) { + kdb_printf("hdr freemap %d base %d size %d\n", + j, INT_GET(m->base, ARCH_CONVERT), + INT_GET(m->size, ARCH_CONVERT)); + } + for (j = 0, e = leaf->entries; j < INT_GET(h->count, ARCH_CONVERT); j++, e++) { + kdb_printf("[%2d] hash 0x%x nameidx %d flags 0x%x", + j, INT_GET(e->hashval, ARCH_CONVERT), + INT_GET(e->nameidx, ARCH_CONVERT), e->flags); + if (e->flags & XFS_ATTR_LOCAL) + kdb_printf("LOCAL "); + if (e->flags & XFS_ATTR_ROOT) + kdb_printf("ROOT "); + if (e->flags & XFS_ATTR_INCOMPLETE) + kdb_printf("INCOMPLETE "); + k = ~(XFS_ATTR_LOCAL | XFS_ATTR_ROOT | XFS_ATTR_INCOMPLETE); + if ((e->flags & k) != 0) + kdb_printf("0x%x", e->flags & k); + kdb_printf(">\n name \""); + if (e->flags & XFS_ATTR_LOCAL) { + l = XFS_ATTR_LEAF_NAME_LOCAL(leaf, j); + for (k = 0; k < l->namelen; k++) + kdb_printf("%c", l->nameval[k]); + kdb_printf("\"(%d) value \"", l->namelen); + for (k = 0; (k < INT_GET(l->valuelen, ARCH_CONVERT)) && (k < 32); k++) + kdb_printf("%c", l->nameval[l->namelen + k]); + if (k == 32) + kdb_printf("..."); + kdb_printf("\"(%d)\n", + INT_GET(l->valuelen, ARCH_CONVERT)); + } else { + r = XFS_ATTR_LEAF_NAME_REMOTE(leaf, j); + for (k = 0; k < r->namelen; k++) + kdb_printf("%c", r->name[k]); + kdb_printf("\"(%d) value blk 0x%x len %d\n", + r->namelen, + INT_GET(r->valueblk, ARCH_CONVERT), + INT_GET(r->valuelen, ARCH_CONVERT)); + } + } +} + +/* + * Print a shortform attribute list. + */ +static void +xfsidbg_xattrsf(xfs_attr_shortform_t *s) +{ + xfs_attr_sf_hdr_t *sfh; + xfs_attr_sf_entry_t *sfe; + int i, j; + + sfh = &s->hdr; + kdb_printf("hdr count %d\n", INT_GET(sfh->count, ARCH_CONVERT)); + for (i = 0, sfe = s->list; i < INT_GET(sfh->count, ARCH_CONVERT); i++) { + kdb_printf("entry %d namelen %d name \"", i, sfe->namelen); + for (j = 0; j < sfe->namelen; j++) + kdb_printf("%c", sfe->nameval[j]); + kdb_printf("\" valuelen %d value \"", INT_GET(sfe->valuelen, ARCH_CONVERT)); + for (j = 0; (j < INT_GET(sfe->valuelen, ARCH_CONVERT)) && (j < 32); j++) + kdb_printf("%c", sfe->nameval[sfe->namelen + j]); + if (j == 32) + kdb_printf("..."); + kdb_printf("\"\n"); + sfe = XFS_ATTR_SF_NEXTENTRY(sfe); + } +} + + +/* + * Print xfs bmap internal record + */ +static void +xfsidbg_xbirec(xfs_bmbt_irec_t *r) +{ + kdb_printf( + "startoff %Ld startblock %Lx blockcount %Ld state %Ld\n", + (__uint64_t)r->br_startoff, + (__uint64_t)r->br_startblock, + (__uint64_t)r->br_blockcount, + (__uint64_t)r->br_state); +} + + +/* + * Print a bmap alloc argument structure for XFS. + */ +static void +xfsidbg_xbmalla(xfs_bmalloca_t *a) +{ + kdb_printf("tp 0x%p ip 0x%p eof %d prevp 0x%p\n", + a->tp, a->ip, a->eof, a->prevp); + kdb_printf("gotp 0x%p firstblock %s alen %d total %d\n", + a->gotp, xfs_fmtfsblock(a->firstblock, a->ip->i_mount), + a->alen, a->total); + kdb_printf("off %s wasdel %d userdata %d minlen %d\n", + xfs_fmtfsblock(a->off, a->ip->i_mount), a->wasdel, + a->userdata, a->minlen); + kdb_printf("minleft %d low %d rval %s aeof %d\n", + a->minleft, a->low, xfs_fmtfsblock(a->rval, a->ip->i_mount), + a->aeof); +} + + +/* + * Print xfs bmap record + */ +static void +xfsidbg_xbrec(xfs_bmbt_rec_64_t *r) +{ + xfs_dfiloff_t o; + xfs_dfsbno_t s; + xfs_dfilblks_t c; + int flag; + + xfs_convert_extent(r, &o, &s, &c, &flag); + kdb_printf("startoff %Ld startblock %Lx blockcount %Ld flag %d\n", + o, s, c, flag); +} + +/* + * Print an xfs in-inode bmap btree root (data fork). + */ +static void +xfsidbg_xbroot(xfs_inode_t *ip) +{ + xfs_broot(ip, &ip->i_df); +} + +/* + * Print an xfs in-inode bmap btree root (attribute fork). + */ +static void +xfsidbg_xbroota(xfs_inode_t *ip) +{ + if (ip->i_afp) + xfs_broot(ip, ip->i_afp); +} + +/* + * Print xfs btree cursor. + */ +static void +xfsidbg_xbtcur(xfs_btree_cur_t *c) +{ + int l; + + kdb_printf("tp 0x%p mp 0x%p\n", + c->bc_tp, + c->bc_mp); + if (c->bc_btnum == XFS_BTNUM_BMAP) { + kdb_printf("rec.b "); + xfsidbg_xbirec(&c->bc_rec.b); + } else if (c->bc_btnum == XFS_BTNUM_INO) { + kdb_printf("rec.i startino 0x%x freecount 0x%x free %Lx\n", + c->bc_rec.i.ir_startino, c->bc_rec.i.ir_freecount, + c->bc_rec.i.ir_free); + } else { + kdb_printf("rec.a startblock 0x%x blockcount 0x%x\n", + c->bc_rec.a.ar_startblock, + c->bc_rec.a.ar_blockcount); + } + kdb_printf("bufs"); + for (l = 0; l < c->bc_nlevels; l++) + kdb_printf(" 0x%p", c->bc_bufs[l]); + kdb_printf("\n"); + kdb_printf("ptrs"); + for (l = 0; l < c->bc_nlevels; l++) + kdb_printf(" 0x%x", c->bc_ptrs[l]); + kdb_printf(" ra"); + for (l = 0; l < c->bc_nlevels; l++) + kdb_printf(" %d", c->bc_ra[l]); + kdb_printf("\n"); + kdb_printf("nlevels %d btnum %s blocklog %d\n", + c->bc_nlevels, + c->bc_btnum == XFS_BTNUM_BNO ? "bno" : + (c->bc_btnum == XFS_BTNUM_CNT ? "cnt" : + (c->bc_btnum == XFS_BTNUM_BMAP ? "bmap" : "ino")), + c->bc_blocklog); + if (c->bc_btnum == XFS_BTNUM_BMAP) { + kdb_printf("private forksize 0x%x whichfork %d ip 0x%p flags %d\n", + c->bc_private.b.forksize, + c->bc_private.b.whichfork, + c->bc_private.b.ip, + c->bc_private.b.flags); + kdb_printf("private firstblock %s flist 0x%p allocated 0x%x\n", + xfs_fmtfsblock(c->bc_private.b.firstblock, c->bc_mp), + c->bc_private.b.flist, + c->bc_private.b.allocated); + } else if (c->bc_btnum == XFS_BTNUM_INO) { + kdb_printf("private agbp 0x%p agno 0x%x\n", + c->bc_private.i.agbp, + c->bc_private.i.agno); + } else { + kdb_printf("private agbp 0x%p agno 0x%x\n", + c->bc_private.a.agbp, + c->bc_private.a.agno); + } +} + +/* + * Figure out what kind of xfs block the buffer contains, + * and invoke a print routine. + */ +static void +xfsidbg_xbuf(xfs_buf_t *bp) +{ + xfsidbg_xbuf_real(bp, 0); +} + +/* + * Figure out what kind of xfs block the buffer contains, + * and invoke a print routine (if asked to). + */ +static void +xfsidbg_xbuf_real(xfs_buf_t *bp, int summary) +{ + void *d; + xfs_agf_t *agf; + xfs_agi_t *agi; + xfs_sb_t *sb; + xfs_alloc_block_t *bta; + xfs_bmbt_block_t *btb; + xfs_inobt_block_t *bti; + xfs_attr_leafblock_t *aleaf; + xfs_dir_leafblock_t *dleaf; + xfs_da_intnode_t *node; + xfs_dinode_t *di; + xfs_disk_dquot_t *dqb; + xfs_dir2_block_t *d2block; + xfs_dir2_data_t *d2data; + xfs_dir2_leaf_t *d2leaf; + xfs_dir2_free_t *d2free; + + d = XFS_BUF_PTR(bp); + if (INT_GET((agf = d)->agf_magicnum, ARCH_CONVERT) == XFS_AGF_MAGIC) { + if (summary) { + kdb_printf("freespace hdr for AG %d (at 0x%p)\n", + INT_GET(agf->agf_seqno, ARCH_CONVERT), agf); + } else { + kdb_printf("buf 0x%p agf 0x%p\n", bp, agf); + xfsidbg_xagf(agf); + } + } else if (INT_GET((agi = d)->agi_magicnum, ARCH_CONVERT) == XFS_AGI_MAGIC) { + if (summary) { + kdb_printf("Inode hdr for AG %d (at 0x%p)\n", + INT_GET(agi->agi_seqno, ARCH_CONVERT), agi); + } else { + kdb_printf("buf 0x%p agi 0x%p\n", bp, agi); + xfsidbg_xagi(agi); + } + } else if (INT_GET((bta = d)->bb_magic, ARCH_CONVERT) == XFS_ABTB_MAGIC) { + if (summary) { + kdb_printf("Alloc BNO Btree blk, level %d (at 0x%p)\n", + INT_GET(bta->bb_level, ARCH_CONVERT), bta); + } else { + kdb_printf("buf 0x%p abtbno 0x%p\n", bp, bta); + xfs_btalloc(bta, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET((bta = d)->bb_magic, ARCH_CONVERT) == XFS_ABTC_MAGIC) { + if (summary) { + kdb_printf("Alloc COUNT Btree blk, level %d (at 0x%p)\n", + INT_GET(bta->bb_level, ARCH_CONVERT), bta); + } else { + kdb_printf("buf 0x%p abtcnt 0x%p\n", bp, bta); + xfs_btalloc(bta, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET((btb = d)->bb_magic, ARCH_CONVERT) == XFS_BMAP_MAGIC) { + if (summary) { + kdb_printf("Bmap Btree blk, level %d (at 0x%p)\n", + INT_GET(btb->bb_level, ARCH_CONVERT), btb); + } else { + kdb_printf("buf 0x%p bmapbt 0x%p\n", bp, btb); + xfs_btbmap(btb, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET((bti = d)->bb_magic, ARCH_CONVERT) == XFS_IBT_MAGIC) { + if (summary) { + kdb_printf("Inode Btree blk, level %d (at 0x%p)\n", + INT_GET(bti->bb_level, ARCH_CONVERT), bti); + } else { + kdb_printf("buf 0x%p inobt 0x%p\n", bp, bti); + xfs_btino(bti, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET((aleaf = d)->hdr.info.magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC) { + if (summary) { + kdb_printf("Attr Leaf, 1st hash 0x%x (at 0x%p)\n", + INT_GET(aleaf->entries[0].hashval, ARCH_CONVERT), aleaf); + } else { + kdb_printf("buf 0x%p attr leaf 0x%p\n", bp, aleaf); + xfsidbg_xattrleaf(aleaf); + } + } else if (INT_GET((dleaf = d)->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC) { + if (summary) { + kdb_printf("Dir Leaf, 1st hash 0x%x (at 0x%p)\n", + dleaf->entries[0].hashval, dleaf); + } else { + kdb_printf("buf 0x%p dir leaf 0x%p\n", bp, dleaf); + xfsidbg_xdirleaf(dleaf); + } + } else if (INT_GET((node = d)->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) { + if (summary) { + kdb_printf("Dir/Attr Node, level %d, 1st hash 0x%x (at 0x%p)\n", + node->hdr.level, node->btree[0].hashval, node); + } else { + kdb_printf("buf 0x%p dir/attr node 0x%p\n", bp, node); + xfsidbg_xdanode(node); + } + } else if (INT_GET((di = d)->di_core.di_magic, ARCH_CONVERT) == XFS_DINODE_MAGIC) { + if (summary) { + kdb_printf("Disk Inode (at 0x%p)\n", di); + } else { + kdb_printf("buf 0x%p dinode 0x%p\n", bp, di); + xfs_inodebuf(bp); + } + } else if (INT_GET((sb = d)->sb_magicnum, ARCH_CONVERT) == XFS_SB_MAGIC) { + if (summary) { + kdb_printf("Superblock (at 0x%p)\n", sb); + } else { + kdb_printf("buf 0x%p sb 0x%p\n", bp, sb); + /* SB in a buffer - we need to convert */ + xfsidbg_xsb(sb, 1); + } + } else if ((dqb = d)->d_magic == XFS_DQUOT_MAGIC) { +#define XFSIDBG_DQTYPESTR(d) \ + ((INT_GET((d)->d_flags, ARCH_CONVERT) & XFS_DQ_USER) ? "USR" : \ + ((INT_GET((d)->d_flags, ARCH_CONVERT) & XFS_DQ_GROUP) ? "GRP" : "???")) + kdb_printf("Quota blk starting ID [%d], type %s at 0x%p\n", + INT_GET(dqb->d_id, ARCH_CONVERT), XFSIDBG_DQTYPESTR(dqb), dqb); + + } else if (INT_GET((d2block = d)->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) { + if (summary) { + kdb_printf("Dir2 block (at 0x%p)\n", d2block); + } else { + kdb_printf("buf 0x%p dir2 block 0x%p\n", bp, d2block); + xfs_dir2data((void *)d2block, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET((d2data = d)->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC) { + if (summary) { + kdb_printf("Dir2 data (at 0x%p)\n", d2data); + } else { + kdb_printf("buf 0x%p dir2 data 0x%p\n", bp, d2data); + xfs_dir2data((void *)d2data, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET((d2leaf = d)->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC) { + if (summary) { + kdb_printf("Dir2 leaf(1) (at 0x%p)\n", d2leaf); + } else { + kdb_printf("buf 0x%p dir2 leaf 0x%p\n", bp, d2leaf); + xfs_dir2leaf(d2leaf, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET(d2leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC) { + if (summary) { + kdb_printf("Dir2 leaf(n) (at 0x%p)\n", d2leaf); + } else { + kdb_printf("buf 0x%p dir2 leaf 0x%p\n", bp, d2leaf); + xfs_dir2leaf(d2leaf, XFS_BUF_COUNT(bp)); + } + } else if (INT_GET((d2free = d)->hdr.magic, ARCH_CONVERT) == XFS_DIR2_FREE_MAGIC) { + if (summary) { + kdb_printf("Dir2 free (at 0x%p)\n", d2free); + } else { + kdb_printf("buf 0x%p dir2 free 0x%p\n", bp, d2free); + xfsidbg_xdir2free(d2free); + } + } else { + kdb_printf("buf 0x%p unknown 0x%p\n", bp, d); + } +} + + +/* + * Print an xfs_da_args structure. + */ +static void +xfsidbg_xdaargs(xfs_da_args_t *n) +{ + char *ch; + int i; + + kdb_printf(" name \""); + for (i = 0; i < n->namelen; i++) { + kdb_printf("%c", n->name[i]); + } + kdb_printf("\"(%d) value ", n->namelen); + if (n->value) { + kdb_printf("\""); + ch = n->value; + for (i = 0; (i < n->valuelen) && (i < 32); ch++, i++) { + switch(*ch) { + case '\n': kdb_printf("\n"); break; + case '\b': kdb_printf("\b"); break; + case '\t': kdb_printf("\t"); break; + default: kdb_printf("%c", *ch); break; + } + } + if (i == 32) + kdb_printf("..."); + kdb_printf("\"(%d)\n", n->valuelen); + } else { + kdb_printf("(NULL)(%d)\n", n->valuelen); + } + kdb_printf(" hashval 0x%x whichfork %d flags <", + (uint_t)n->hashval, n->whichfork); + if (n->flags & ATTR_ROOT) + kdb_printf("ROOT "); + if (n->flags & ATTR_CREATE) + kdb_printf("CREATE "); + if (n->flags & ATTR_REPLACE) + kdb_printf("REPLACE "); + if (n->flags & XFS_ATTR_INCOMPLETE) + kdb_printf("INCOMPLETE "); + i = ~(ATTR_ROOT | ATTR_CREATE | ATTR_REPLACE | XFS_ATTR_INCOMPLETE); + if ((n->flags & i) != 0) + kdb_printf("0x%x", n->flags & i); + kdb_printf(">\n"); + kdb_printf(" rename %d justcheck %d addname %d oknoent %d\n", + n->rename, n->justcheck, n->addname, n->oknoent); + kdb_printf(" leaf: blkno %d index %d rmtblkno %d rmtblkcnt %d\n", + n->blkno, n->index, n->rmtblkno, n->rmtblkcnt); + kdb_printf(" leaf2: blkno %d index %d rmtblkno %d rmtblkcnt %d\n", + n->blkno2, n->index2, n->rmtblkno2, n->rmtblkcnt2); + kdb_printf(" inumber %Ld dp 0x%p firstblock 0x%p flist 0x%p\n", + n->inumber, n->dp, n->firstblock, n->flist); + kdb_printf(" trans 0x%p total %d\n", + n->trans, n->total); +} + +/* + * Print a da buffer structure. + */ +static void +xfsidbg_xdabuf(xfs_dabuf_t *dabuf) +{ + int i; + + kdb_printf("nbuf %d dirty %d bbcount %d data 0x%p bps", + dabuf->nbuf, dabuf->dirty, dabuf->bbcount, dabuf->data); + for (i = 0; i < dabuf->nbuf; i++) + kdb_printf(" %d:0x%p", i, dabuf->bps[i]); + kdb_printf("\n"); +#ifdef XFS_DABUF_DEBUG + kdb_printf(" ra 0x%x prev 0x%x next 0x%x dev 0x%x blkno 0x%x\n", + dabuf->ra, dabuf->prev, dabuf->next, dabuf->dev, dabuf->blkno); +#endif +} + +/* + * Print a directory/attribute internal node block. + */ +static void +xfsidbg_xdanode(xfs_da_intnode_t *node) +{ + xfs_da_node_hdr_t *h; + xfs_da_blkinfo_t *i; + xfs_da_node_entry_t *e; + int j; + + h = &node->hdr; + i = &h->info; + kdb_printf("hdr info forw 0x%x back 0x%x magic 0x%x\n", + INT_GET(i->forw, ARCH_CONVERT), INT_GET(i->back, ARCH_CONVERT), INT_GET(i->magic, ARCH_CONVERT)); + kdb_printf("hdr count %d level %d\n", + INT_GET(h->count, ARCH_CONVERT), INT_GET(h->level, ARCH_CONVERT)); + for (j = 0, e = node->btree; j < INT_GET(h->count, ARCH_CONVERT); j++, e++) { + kdb_printf("btree %d hashval 0x%x before 0x%x\n", + j, (uint_t)INT_GET(e->hashval, ARCH_CONVERT), INT_GET(e->before, ARCH_CONVERT)); + } +} + +/* + * Print an xfs_da_state_blk structure. + */ +static void +xfsidbg_xdastate(xfs_da_state_t *s) +{ + xfs_da_state_blk_t *eblk; + + kdb_printf("args 0x%p mp 0x%p blocksize %d inleaf %d\n", + s->args, s->mp, s->blocksize, s->inleaf); + if (s->args) + xfsidbg_xdaargs(s->args); + + kdb_printf("path: "); + xfs_dastate_path(&s->path); + + kdb_printf("altpath: "); + xfs_dastate_path(&s->altpath); + + eblk = &s->extrablk; + kdb_printf("extra: valid %d, after %d\n", s->extravalid, s->extraafter); +#if XFS_BIG_FILES + kdb_printf(" bp 0x%p blkno 0x%x ", eblk->bp, eblk->blkno); +#else + kdb_printf(" bp 0x%x blkno 0x%x ", eblk->bp, eblk->blkno); +#endif + kdb_printf("index %d hashval 0x%x\n", eblk->index, (uint_t)eblk->hashval); +} + +/* + * Print a directory leaf block. + */ +static void +xfsidbg_xdirleaf(xfs_dir_leafblock_t *leaf) +{ + xfs_dir_leaf_hdr_t *h; + xfs_da_blkinfo_t *i; + xfs_dir_leaf_map_t *m; + xfs_dir_leaf_entry_t *e; + xfs_dir_leaf_name_t *n; + int j, k; + xfs_ino_t ino; + + h = &leaf->hdr; + i = &h->info; + kdb_printf("hdr info forw 0x%x back 0x%x magic 0x%x\n", + INT_GET(i->forw, ARCH_CONVERT), INT_GET(i->back, ARCH_CONVERT), INT_GET(i->magic, ARCH_CONVERT)); + kdb_printf("hdr count %d namebytes %d firstused %d holes %d\n", + INT_GET(h->count, ARCH_CONVERT), INT_GET(h->namebytes, ARCH_CONVERT), INT_GET(h->firstused, ARCH_CONVERT), h->holes); + for (j = 0, m = h->freemap; j < XFS_DIR_LEAF_MAPSIZE; j++, m++) { + kdb_printf("hdr freemap %d base %d size %d\n", + j, INT_GET(m->base, ARCH_CONVERT), INT_GET(m->size, ARCH_CONVERT)); + } + for (j = 0, e = leaf->entries; j < INT_GET(h->count, ARCH_CONVERT); j++, e++) { + n = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(e->nameidx, ARCH_CONVERT)); + XFS_DIR_SF_GET_DIRINO_ARCH(&n->inumber, &ino, ARCH_CONVERT); + kdb_printf("leaf %d hashval 0x%x nameidx %d inumber %Ld ", + j, (uint_t)INT_GET(e->hashval, ARCH_CONVERT), INT_GET(e->nameidx, ARCH_CONVERT), ino); + kdb_printf("namelen %d name \"", e->namelen); + for (k = 0; k < e->namelen; k++) + kdb_printf("%c", n->name[k]); + kdb_printf("\"\n"); + } +} + +/* + * Print a directory v2 data block, single or multiple. + */ +static void +xfs_dir2data(void *addr, int size) +{ + xfs_dir2_data_t *db; + xfs_dir2_block_t *bb; + xfs_dir2_data_hdr_t *h; + xfs_dir2_data_free_t *m; + xfs_dir2_data_entry_t *e; + xfs_dir2_data_unused_t *u; + xfs_dir2_leaf_entry_t *l=NULL; + int j, k; + char *p; + char *t; + xfs_dir2_block_tail_t *tail=NULL; + + db = (xfs_dir2_data_t *)addr; + bb = (xfs_dir2_block_t *)addr; + h = &db->hdr; + kdb_printf("hdr magic 0x%x (%s)\nhdr bestfree", INT_GET(h->magic, ARCH_CONVERT), + INT_GET(h->magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC ? "DATA" : + (INT_GET(h->magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC ? "BLOCK" : "")); + for (j = 0, m = h->bestfree; j < XFS_DIR2_DATA_FD_COUNT; j++, m++) { + kdb_printf(" %d: 0x%x@0x%x", j, INT_GET(m->length, ARCH_CONVERT), INT_GET(m->offset, ARCH_CONVERT)); + } + kdb_printf("\n"); + if (INT_GET(h->magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC) + t = (char *)db + size; + else { + /* XFS_DIR2_BLOCK_TAIL_P */ + tail = (xfs_dir2_block_tail_t *) + ((char *)bb + size - sizeof(xfs_dir2_block_tail_t)); + l = XFS_DIR2_BLOCK_LEAF_P_ARCH(tail, ARCH_CONVERT); + t = (char *)l; + } + for (p = (char *)(h + 1); p < t; ) { + u = (xfs_dir2_data_unused_t *)p; + if (u->freetag == XFS_DIR2_DATA_FREE_TAG) { + kdb_printf("0x%x unused freetag 0x%x length 0x%x tag 0x%x\n", + p - (char *)addr, INT_GET(u->freetag, ARCH_CONVERT), INT_GET(u->length, ARCH_CONVERT), + INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(u, ARCH_CONVERT), ARCH_CONVERT)); + p += INT_GET(u->length, ARCH_CONVERT); + continue; + } + e = (xfs_dir2_data_entry_t *)p; + kdb_printf("0x%x entry inumber %Ld namelen %d name \"", + p - (char *)addr, INT_GET(e->inumber, ARCH_CONVERT), e->namelen); + for (k = 0; k < e->namelen; k++) + kdb_printf("%c", e->name[k]); + kdb_printf("\" tag 0x%x\n", INT_GET(*XFS_DIR2_DATA_ENTRY_TAG_P(e), ARCH_CONVERT)); + p += XFS_DIR2_DATA_ENTSIZE(e->namelen); + } + if (INT_GET(h->magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC) + return; + for (j = 0; j < INT_GET(tail->count, ARCH_CONVERT); j++, l++) { + kdb_printf("0x%x leaf %d hashval 0x%x address 0x%x (byte 0x%x)\n", + (char *)l - (char *)addr, j, + (uint_t)INT_GET(l->hashval, ARCH_CONVERT), INT_GET(l->address, ARCH_CONVERT), + /* XFS_DIR2_DATAPTR_TO_BYTE */ + INT_GET(l->address, ARCH_CONVERT) << XFS_DIR2_DATA_ALIGN_LOG); + } + kdb_printf("0x%x tail count %d\n", + (char *)tail - (char *)addr, INT_GET(tail->count, ARCH_CONVERT)); +} + +static void +xfs_dir2leaf(xfs_dir2_leaf_t *leaf, int size) +{ + xfs_dir2_leaf_hdr_t *h; + xfs_da_blkinfo_t *i; + xfs_dir2_leaf_entry_t *e; + xfs_dir2_data_off_t *b; + xfs_dir2_leaf_tail_t *t; + int j; + + h = &leaf->hdr; + i = &h->info; + e = leaf->ents; + kdb_printf("hdr info forw 0x%x back 0x%x magic 0x%x\n", + INT_GET(i->forw, ARCH_CONVERT), INT_GET(i->back, ARCH_CONVERT), INT_GET(i->magic, ARCH_CONVERT)); + kdb_printf("hdr count %d stale %d\n", INT_GET(h->count, ARCH_CONVERT), INT_GET(h->stale, ARCH_CONVERT)); + for (j = 0; j < INT_GET(h->count, ARCH_CONVERT); j++, e++) { + kdb_printf("0x%x ent %d hashval 0x%x address 0x%x (byte 0x%x)\n", + (char *)e - (char *)leaf, j, + (uint_t)INT_GET(e->hashval, ARCH_CONVERT), INT_GET(e->address, ARCH_CONVERT), + /* XFS_DIR2_DATAPTR_TO_BYTE */ + INT_GET(e->address, ARCH_CONVERT) << XFS_DIR2_DATA_ALIGN_LOG); + } + if (INT_GET(i->magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC) + return; + /* XFS_DIR2_LEAF_TAIL_P */ + t = (xfs_dir2_leaf_tail_t *)((char *)leaf + size - sizeof(*t)); + b = XFS_DIR2_LEAF_BESTS_P_ARCH(t, ARCH_CONVERT); + for (j = 0; j < INT_GET(t->bestcount, ARCH_CONVERT); j++, b++) { + kdb_printf("0x%x best %d 0x%x\n", + (char *)b - (char *)leaf, j, INT_GET(*b, ARCH_CONVERT)); + } + kdb_printf("tail bestcount %d\n", INT_GET(t->bestcount, ARCH_CONVERT)); +} + +/* + * Print a shortform directory. + */ +static void +xfsidbg_xdirsf(xfs_dir_shortform_t *s) +{ + xfs_dir_sf_hdr_t *sfh; + xfs_dir_sf_entry_t *sfe; + xfs_ino_t ino; + int i, j; + + sfh = &s->hdr; + XFS_DIR_SF_GET_DIRINO_ARCH(&sfh->parent, &ino, ARCH_CONVERT); + kdb_printf("hdr parent %Ld", ino); + kdb_printf(" count %d\n", sfh->count); + for (i = 0, sfe = s->list; i < sfh->count; i++) { + XFS_DIR_SF_GET_DIRINO_ARCH(&sfe->inumber, &ino, ARCH_CONVERT); + kdb_printf("entry %d inumber %Ld", i, ino); + kdb_printf(" namelen %d name \"", sfe->namelen); + for (j = 0; j < sfe->namelen; j++) + kdb_printf("%c", sfe->name[j]); + kdb_printf("\"\n"); + sfe = XFS_DIR_SF_NEXTENTRY(sfe); + } +} + +/* + * Print a shortform v2 directory. + */ +static void +xfsidbg_xdir2sf(xfs_dir2_sf_t *s) +{ + xfs_dir2_sf_hdr_t *sfh; + xfs_dir2_sf_entry_t *sfe; + xfs_ino_t ino; + int i, j; + + sfh = &s->hdr; + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(s, &sfh->parent, ARCH_CONVERT); + kdb_printf("hdr count %d i8count %d parent %Ld\n", + sfh->count, sfh->i8count, ino); + for (i = 0, sfe = XFS_DIR2_SF_FIRSTENTRY(s); i < sfh->count; i++) { + ino = XFS_DIR2_SF_GET_INUMBER_ARCH(s, XFS_DIR2_SF_INUMBERP(sfe), ARCH_CONVERT); + kdb_printf("entry %d inumber %Ld offset 0x%x namelen %d name \"", + i, ino, XFS_DIR2_SF_GET_OFFSET_ARCH(sfe, ARCH_CONVERT), sfe->namelen); + for (j = 0; j < sfe->namelen; j++) + kdb_printf("%c", sfe->name[j]); + kdb_printf("\"\n"); + sfe = XFS_DIR2_SF_NEXTENTRY(s, sfe); + } +} + +/* + * Print a node-form v2 directory freemap block. + */ +static void +xfsidbg_xdir2free(xfs_dir2_free_t *f) +{ + int i; + + kdb_printf("hdr magic 0x%x firstdb %d nvalid %d nused %d\n", + INT_GET(f->hdr.magic, ARCH_CONVERT), INT_GET(f->hdr.firstdb, ARCH_CONVERT), INT_GET(f->hdr.nvalid, ARCH_CONVERT), INT_GET(f->hdr.nused, ARCH_CONVERT)); + for (i = 0; i < INT_GET(f->hdr.nvalid, ARCH_CONVERT); i++) { + kdb_printf("entry %d db %d count %d\n", + i, i + INT_GET(f->hdr.firstdb, ARCH_CONVERT), INT_GET(f->bests[i], ARCH_CONVERT)); + } +} + + +/* + * Print xfs extent list. + */ +static void +xfsidbg_xexlist(xfs_inode_t *ip) +{ + xfs_xexlist_fork(ip, XFS_DATA_FORK); + if (XFS_IFORK_Q(ip)) + xfs_xexlist_fork(ip, XFS_ATTR_FORK); +} + +/* + * Print an xfs free-extent list. + */ +static void +xfsidbg_xflist(xfs_bmap_free_t *flist) +{ + xfs_bmap_free_item_t *item; + + kdb_printf("flist@0x%p: first 0x%p count %d low %d\n", flist, + flist->xbf_first, flist->xbf_count, flist->xbf_low); + for (item = flist->xbf_first; item; item = item->xbfi_next) { + kdb_printf("item@0x%p: startblock %Lx blockcount %d", item, + (xfs_dfsbno_t)item->xbfi_startblock, + item->xbfi_blockcount); + } +} + +/* + * Print out the help messages for these functions. + */ +static void +xfsidbg_xhelp(void) +{ + struct xif *p; + + for (p = xfsidbg_funcs; p->name; p++) + kdb_printf("%-16s %s %s\n", p->name, p->args, p->help); +} + +/* + * Print out an XFS in-core log structure. + */ +static void +xfsidbg_xiclog(xlog_in_core_t *iclog) +{ + int i; + static char *ic_flags[] = { + "ACTIVE", /* 0x0001 */ + "WANT_SYNC", /* 0x0002 */ + "SYNCING", /* 0X0004 */ + "DONE_SYNC", /* 0X0008 */ + "DO_CALLBACK", /* 0X0010 */ + "CALLBACK", /* 0X0020 */ + "DIRTY", /* 0X0040 */ + "IOERROR", /* 0X0080 */ + "NOTUSED", /* 0X8000 */ + 0 + }; + + kdb_printf("xlog_in_core/header at 0x%p\n", iclog); + kdb_printf("magicno: %x cycle: %d version: %d lsn: 0x%Lx\n", + INT_GET(iclog->ic_header.h_magicno, ARCH_CONVERT), INT_GET(iclog->ic_header.h_cycle, ARCH_CONVERT), + INT_GET(iclog->ic_header.h_version, ARCH_CONVERT), INT_GET(iclog->ic_header.h_lsn, ARCH_CONVERT)); + kdb_printf("tail_lsn: 0x%Lx len: %d prev_block: %d num_ops: %d\n", + INT_GET(iclog->ic_header.h_tail_lsn, ARCH_CONVERT), INT_GET(iclog->ic_header.h_len, ARCH_CONVERT), + INT_GET(iclog->ic_header.h_prev_block, ARCH_CONVERT), INT_GET(iclog->ic_header.h_num_logops, ARCH_CONVERT)); + kdb_printf("cycle_data: "); + for (i=0; i<(iclog->ic_size>>BBSHIFT); i++) { + kdb_printf("%x ", INT_GET(iclog->ic_header.h_cycle_data[i], ARCH_CONVERT)); + } + kdb_printf("\n"); + kdb_printf("--------------------------------------------------\n"); + kdb_printf("data: 0x%p &forcesema: 0x%p next: 0x%p bp: 0x%p\n", + iclog->ic_data, &iclog->ic_forcesema, iclog->ic_next, + iclog->ic_bp); + kdb_printf("log: 0x%p callb: 0x%p callb_tail: 0x%p roundoff: %d\n", + iclog->ic_log, iclog->ic_callback, iclog->ic_callback_tail, + iclog->ic_roundoff); + kdb_printf("size: %d (OFFSET: %d) trace: 0x%p refcnt: %d bwritecnt: %d", + iclog->ic_size, iclog->ic_offset, + NULL, + iclog->ic_refcnt, iclog->ic_bwritecnt); + kdb_printf(" state: "); + if (iclog->ic_state & XLOG_STATE_ALL) + printflags(iclog->ic_state, ic_flags,"state"); + else + kdb_printf("ILLEGAL"); + kdb_printf("\n"); +} /* xfsidbg_xiclog */ + + +/* + * Print all incore logs. + */ +static void +xfsidbg_xiclogall(xlog_in_core_t *iclog) +{ + xlog_in_core_t *first_iclog = iclog; + + do { + xfsidbg_xiclog(iclog); + kdb_printf("=================================================\n"); + iclog = iclog->ic_next; + } while (iclog != first_iclog); +} /* xfsidbg_xiclogall */ + +/* + * Print out the callback structures attached to an iclog. + */ +static void +xfsidbg_xiclogcb(xlog_in_core_t *iclog) +{ + xfs_log_callback_t *cb; + kdb_symtab_t symtab; + + for (cb = iclog->ic_callback; cb != NULL; cb = cb->cb_next) { + + if (kdbnearsym((unsigned long)cb->cb_func, &symtab)) { + unsigned long offval; + + offval = (unsigned long)cb->cb_func - symtab.sym_start; + + if (offval) + kdb_printf("func = %s+0x%lx", + symtab.sym_name, + offval); + else + kdb_printf("func = %s", symtab.sym_name); + } else + kdb_printf("func = ?? 0x%p", (void *)cb->cb_func); + + kdb_printf(" arg 0x%p next 0x%p\n", cb->cb_arg, cb->cb_next); + } +} + + +/* + * Print all of the inodes attached to the given mount structure. + */ +static void +xfsidbg_xinodes(xfs_mount_t *mp) +{ + xfs_inode_t *ip; + + kdb_printf("xfs_mount at 0x%p\n", mp); + ip = mp->m_inodes; + if (ip != NULL) { + do { + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } + kdb_printf("\n"); + xfsidbg_xnode(ip); + ip = ip->i_mnext; + } while (ip != mp->m_inodes); + } + kdb_printf("\nEnd of Inodes\n"); +} + +static char * +xfsidbg_get_cstate(int state) +{ + switch(state) { + case XLOG_STATE_COVER_IDLE: + return("idle"); + case XLOG_STATE_COVER_NEED: + return("need"); + case XLOG_STATE_COVER_DONE: + return("done"); + case XLOG_STATE_COVER_NEED2: + return("need2"); + case XLOG_STATE_COVER_DONE2: + return("done2"); + default: + return("unknown"); + } +} + +/* + * Print out an XFS log structure. + */ +static void +xfsidbg_xlog(xlog_t *log) +{ + int rbytes; + int wbytes; + static char *t_flags[] = { + "CHKSUM_MISMATCH", /* 0x01 */ + "ACTIVE_RECOVERY", /* 0x02 */ + "RECOVERY_NEEDED", /* 0x04 */ + "IO_ERROR", /* 0x08 */ + 0 + }; + + kdb_printf("xlog at 0x%p\n", log); + kdb_printf("&flushsm: 0x%p tic_cnt: %d tic_tcnt: %d \n", + &log->l_flushsema, log->l_ticket_cnt, log->l_ticket_tcnt); + kdb_printf("freelist: 0x%p tail: 0x%p ICLOG: 0x%p \n", + log->l_freelist, log->l_tail, log->l_iclog); + kdb_printf("&icloglock: 0x%p tail_lsn: 0x%Lx last_sync_lsn: 0x%Lx \n", + &log->l_icloglock, log->l_tail_lsn, log->l_last_sync_lsn); + kdb_printf("mp: 0x%p xbuf: 0x%p roundoff: %d l_covered_state: %s \n", + log->l_mp, log->l_xbuf, log->l_roundoff, + xfsidbg_get_cstate(log->l_covered_state)); + kdb_printf("flags: "); + printflags(log->l_flags, t_flags,"log"); + kdb_printf(" dev: 0x%x logBBstart: %Ld logsize: %d logBBsize: %d\n", + log->l_dev, log->l_logBBstart, log->l_logsize,log->l_logBBsize); + kdb_printf("curr_cycle: %d prev_cycle: %d curr_block: %d prev_block: %d\n", + log->l_curr_cycle, log->l_prev_cycle, log->l_curr_block, + log->l_prev_block); + kdb_printf("iclog_bak: 0x%p iclog_size: 0x%x (%d) num iclogs: %d\n", + log->l_iclog_bak, log->l_iclog_size, log->l_iclog_size, + log->l_iclog_bufs); + kdb_printf("&grant_lock: 0x%p resHeadQ: 0x%p wrHeadQ: 0x%p\n", + &log->l_grant_lock, log->l_reserve_headq, log->l_write_headq); + kdb_printf("GResCycle: %d GResBytes: %d GWrCycle: %d GWrBytes: %d\n", + log->l_grant_reserve_cycle, log->l_grant_reserve_bytes, + log->l_grant_write_cycle, log->l_grant_write_bytes); + rbytes = log->l_grant_reserve_bytes + log->l_roundoff; + wbytes = log->l_grant_write_bytes + log->l_roundoff; + kdb_printf("GResBlocks: %d GResRemain: %d GWrBlocks: %d GWrRemain: %d\n", + rbytes / BBSIZE, rbytes % BBSIZE, + wbytes / BBSIZE, wbytes % BBSIZE); +} /* xfsidbg_xlog */ + + +/* + * Print out an XFS recovery transaction + */ +static void +xfsidbg_xlog_ritem(xlog_recover_item_t *item) +{ + int i = XLOG_MAX_REGIONS_IN_ITEM; + + kdb_printf("(xlog_recover_item 0x%p) ", item); + kdb_printf("next: 0x%p prev: 0x%p type: %d cnt: %d ttl: %d\n", + item->ri_next, item->ri_prev, item->ri_type, item->ri_cnt, + item->ri_total); + for ( ; i > 0; i--) { + if (!item->ri_buf[XLOG_MAX_REGIONS_IN_ITEM-i].i_addr) + break; + kdb_printf("a: 0x%p l: %d ", + item->ri_buf[XLOG_MAX_REGIONS_IN_ITEM-i].i_addr, + item->ri_buf[XLOG_MAX_REGIONS_IN_ITEM-i].i_len); + } + kdb_printf("\n"); +} /* xfsidbg_xlog_ritem */ + +/* + * Print out an XFS recovery transaction + */ +static void +xfsidbg_xlog_rtrans(xlog_recover_t *trans) +{ + xlog_recover_item_t *rip, *first_rip; + + kdb_printf("(xlog_recover 0x%p) ", trans); + kdb_printf("tid: %x type: %d items: %d ttid: 0x%x ", + trans->r_log_tid, trans->r_theader.th_type, + trans->r_theader.th_num_items, trans->r_theader.th_tid); + kdb_printf("itemq: 0x%p\n", trans->r_itemq); + if (trans->r_itemq) { + rip = first_rip = trans->r_itemq; + do { + kdb_printf("(recovery item: 0x%p) ", rip); + kdb_printf("type: %d cnt: %d total: %d\n", + rip->ri_type, rip->ri_cnt, rip->ri_total); + rip = rip->ri_next; + } while (rip != first_rip); + } +} /* xfsidbg_xlog_rtrans */ + +static void +xfsidbg_xlog_buf_logitem(xlog_recover_item_t *item) +{ + xfs_buf_log_format_t *buf_f; + int i, j; + int bit; + int nbits; + unsigned int *data_map; + unsigned int map_size; + int size; + + buf_f = (xfs_buf_log_format_t *)item->ri_buf[0].i_addr; + if (buf_f->blf_flags & XFS_BLI_INODE_BUF) { + kdb_printf("\tINODE BUF \n", + buf_f->blf_blkno, buf_f->blf_len); + } else if (buf_f->blf_flags & (XFS_BLI_UDQUOT_BUF | XFS_BLI_GDQUOT_BUF)) { + kdb_printf("\tDQUOT BUF \n", + buf_f->blf_blkno, buf_f->blf_len); + } else { + kdb_printf("\tREG BUF \n", + buf_f->blf_blkno, buf_f->blf_len); + data_map = buf_f->blf_data_map; + map_size = buf_f->blf_map_size; + bit = 0; + i = 1; /* 0 is the buf format structure */ + while (1) { + size = 1; + kdb_printf("\t\tlogbuf.i_addr 0x%p, size 0x%xB\n", + item->ri_buf[i].i_addr, size); + kdb_printf("\t\t\t\""); + for (j=0; j<8 && jri_buf[i].i_addr)[j]); + } + kdb_printf("...\"\n"); + i++; + bit += nbits; + } + + } +} + +/* + * Print out an ENTIRE XFS recovery transaction + */ +static void +xfsidbg_xlog_rtrans_entire(xlog_recover_t *trans) +{ + xlog_recover_item_t *item, *first_rip; + + kdb_printf("(Recovering Xact 0x%p) ", trans); + kdb_printf("tid: %x type: %d nitems: %d ttid: 0x%x ", + trans->r_log_tid, trans->r_theader.th_type, + trans->r_theader.th_num_items, trans->r_theader.th_tid); + kdb_printf("itemq: 0x%p\n", trans->r_itemq); + if (trans->r_itemq) { + item = first_rip = trans->r_itemq; + do { + /* + kdb_printf("(recovery item: 0x%x) ", item); + kdb_printf("type: %d cnt: %d total: %d\n", + item->ri_type, item->ri_cnt, item->ri_total); + */ + if ((ITEM_TYPE(item) == XFS_LI_BUF) || + (ITEM_TYPE(item) == XFS_LI_6_1_BUF) || + (ITEM_TYPE(item) == XFS_LI_5_3_BUF)) { + kdb_printf("BUF:"); + xfsidbg_xlog_buf_logitem(item); + } else if ((ITEM_TYPE(item) == XFS_LI_INODE) || + (ITEM_TYPE(item) == XFS_LI_6_1_INODE) || + (ITEM_TYPE(item) == XFS_LI_5_3_INODE)) { + kdb_printf("INODE:\n"); + } else if (ITEM_TYPE(item) == XFS_LI_EFI) { + kdb_printf("EFI:\n"); + } else if (ITEM_TYPE(item) == XFS_LI_EFD) { + kdb_printf("EFD:\n"); + } else if (ITEM_TYPE(item) == XFS_LI_DQUOT) { + kdb_printf("DQUOT:\n"); + } else if ((ITEM_TYPE(item) == XFS_LI_QUOTAOFF)) { + kdb_printf("QUOTAOFF:\n"); + } else { + kdb_printf("UNKNOWN LOGITEM 0x%x\n", ITEM_TYPE(item)); + } + item = item->ri_next; + } while (item != first_rip); + } +} /* xfsidbg_xlog_rtrans */ + +/* + * Print out an XFS ticket structure. + */ +static void +xfsidbg_xlog_tic(xlog_ticket_t *tic) +{ + static char *t_flags[] = { + "INIT", /* 0x1 */ + "PERM_RES", /* 0x2 */ + "IN_Q", /* 0x4 */ + 0 + }; + + kdb_printf("xlog_ticket at 0x%p\n", tic); + kdb_printf("next: 0x%p prev: 0x%p tid: 0x%x \n", + tic->t_next, tic->t_prev, tic->t_tid); + kdb_printf("curr_res: %d unit_res: %d ocnt: %d cnt: %d\n", + tic->t_curr_res, tic->t_unit_res, (int)tic->t_ocnt, + (int)tic->t_cnt); + kdb_printf("clientid: %c \n", tic->t_clientid); + printflags(tic->t_flags, t_flags,"ticket"); + kdb_printf("\n"); +} /* xfsidbg_xlog_tic */ + +/* + * Print out a single log item. + */ +static void +xfsidbg_xlogitem(xfs_log_item_t *lip) +{ + xfs_log_item_t *bio_lip; + static char *lid_type[] = { + "???", /* 0 */ + "5-3-buf", /* 1 */ + "5-3-inode", /* 2 */ + "efi", /* 3 */ + "efd", /* 4 */ + "iunlink", /* 5 */ + "6-1-inode", /* 6 */ + "6-1-buf", /* 7 */ + "inode", /* 8 */ + "buf", /* 9 */ + "dquot", /* 10 */ + 0 + }; + static char *li_flags[] = { + "in ail", /* 0x1 */ + 0 + }; + + kdb_printf("type %s mountp 0x%p flags ", + lid_type[lip->li_type - XFS_LI_5_3_BUF + 1], + lip->li_mountp); + printflags((uint)(lip->li_flags), li_flags,"log"); + kdb_printf("\n"); + kdb_printf("ail forw 0x%p ail back 0x%p lsn %s desc %p ops 0x%p\n", + lip->li_ail.ail_forw, lip->li_ail.ail_back, + xfs_fmtlsn(&(lip->li_lsn)), lip->li_desc, lip->li_ops); + kdb_printf("iodonefunc &0x%p\n", lip->li_cb); + if (lip->li_type == XFS_LI_BUF) { + bio_lip = lip->li_bio_list; + if (bio_lip != NULL) { + kdb_printf("iodone list:\n"); + } + while (bio_lip != NULL) { + kdb_printf("item 0x%p func 0x%p\n", + bio_lip, bio_lip->li_cb); + bio_lip = bio_lip->li_bio_list; + } + } + switch (lip->li_type) { + case XFS_LI_BUF: + xfs_buf_item_print((xfs_buf_log_item_t *)lip, 0); + break; + case XFS_LI_INODE: + xfs_inode_item_print((xfs_inode_log_item_t *)lip, 0); + break; + case XFS_LI_EFI: + xfs_efi_item_print((xfs_efi_log_item_t *)lip, 0); + break; + case XFS_LI_EFD: + xfs_efd_item_print((xfs_efd_log_item_t *)lip, 0); + break; + case XFS_LI_DQUOT: + xfs_dquot_item_print((xfs_dq_logitem_t *)lip, 0); + break; + case XFS_LI_QUOTAOFF: + xfs_qoff_item_print((xfs_qoff_logitem_t *)lip, 0); + break; + + default: + kdb_printf("Unknown item type %d\n", lip->li_type); + break; + } +} + +/* + * Print out a summary of the AIL hanging off of a mount struct. + */ +static void +xfsidbg_xaildump(xfs_mount_t *mp) +{ + xfs_log_item_t *lip; + static char *lid_type[] = { + "???", /* 0 */ + "5-3-buf", /* 1 */ + "5-3-inode", /* 2 */ + "efi", /* 3 */ + "efd", /* 4 */ + "iunlink", /* 5 */ + "6-1-inode", /* 6 */ + "6-1-buf", /* 7 */ + "inode", /* 8 */ + "buf", /* 9 */ + "dquot", /* 10 */ + 0 + }; + static char *li_flags[] = { + "in ail", /* 0x1 */ + 0 + }; + int count; + + if ((mp->m_ail.ail_forw == NULL) || + (mp->m_ail.ail_forw == (xfs_log_item_t *)&mp->m_ail)) { + kdb_printf("AIL is empty\n"); + return; + } + kdb_printf("AIL for mp 0x%p, oldest first\n", mp); + lip = (xfs_log_item_t*)mp->m_ail.ail_forw; + for (count = 0; lip; count++) { + kdb_printf("[%d] type %s ", count, + lid_type[lip->li_type - XFS_LI_5_3_BUF + 1]); + printflags((uint)(lip->li_flags), li_flags, "flags:"); + kdb_printf(" lsn %s\n ", xfs_fmtlsn(&(lip->li_lsn))); + switch (lip->li_type) { + case XFS_LI_BUF: + xfs_buf_item_print((xfs_buf_log_item_t *)lip, 1); + break; + case XFS_LI_INODE: + xfs_inode_item_print((xfs_inode_log_item_t *)lip, 1); + break; + case XFS_LI_EFI: + xfs_efi_item_print((xfs_efi_log_item_t *)lip, 1); + break; + case XFS_LI_EFD: + xfs_efd_item_print((xfs_efd_log_item_t *)lip, 1); + break; + case XFS_LI_DQUOT: + xfs_dquot_item_print((xfs_dq_logitem_t *)lip, 1); + break; + case XFS_LI_QUOTAOFF: + xfs_qoff_item_print((xfs_qoff_logitem_t *)lip, 1); + break; + default: + kdb_printf("Unknown item type %d\n", lip->li_type); + break; + } + + if (lip->li_ail.ail_forw == (xfs_log_item_t*)&mp->m_ail) { + lip = NULL; + } else { + lip = lip->li_ail.ail_forw; + } + } +} + +/* + * Print xfs mount structure. + */ +static void +xfsidbg_xmount(xfs_mount_t *mp) +{ + static char *xmount_flags[] = { + "WSYNC", /* 0x0001 */ + "INO64", /* 0x0002 */ + "RQCHK", /* 0x0004 */ + "FSCLEAN", /* 0x0008 */ + "FSSHUTDN", /* 0x0010 */ + "NOATIME", /* 0x0020 */ + "RETERR", /* 0x0040 */ + "NOALIGN", /* 0x0080 */ + "UNSHRD", /* 0x0100 */ + "RGSTRD", /* 0x0200 */ + "NORECVR", /* 0x0400 */ + "SHRD", /* 0x0800 */ + "IOSZ", /* 0x1000 */ + "DSYNC", /* 0x2000 */ + 0 + }; + + static char *quota_flags[] = { + "UQ", /* 0x0001 */ + "UQE", /* 0x0002 */ + "UQCHKD", /* 0x0004 */ + "PQ", /* 0x0008 (IRIX ondisk) */ + "GQE", /* 0x0010 */ + "GQCHKD", /* 0x0020 */ + "GQ", /* 0x0040 */ + "UQACTV", /* 0x0080 */ + "GQACTV", /* 0x0100 */ + "QMAYBE", /* 0x0200 */ + 0 + }; + + kdb_printf("xfs_mount at 0x%p\n", mp); + kdb_printf("vfsp 0x%p tid 0x%x ail_lock 0x%p &ail 0x%p\n", + XFS_MTOVFS(mp), mp->m_tid, &mp->m_ail_lock, &mp->m_ail); + kdb_printf("ail_gen 0x%x &sb 0x%p\n", + mp->m_ail_gen, &mp->m_sb); + kdb_printf("sb_lock 0x%p sb_bp 0x%p dev 0x%x logdev 0x%x rtdev 0x%x\n", + &mp->m_sb_lock, mp->m_sb_bp, mp->m_dev, mp->m_logdev, + mp->m_rtdev); + kdb_printf("bsize %d agfrotor %d agirotor %d ihash 0x%p ihsize %d\n", + mp->m_bsize, mp->m_agfrotor, mp->m_agirotor, + mp->m_ihash, mp->m_ihsize); + kdb_printf("inodes 0x%p ilock 0x%p ireclaims 0x%x\n", + mp->m_inodes, &mp->m_ilock, mp->m_ireclaims); + kdb_printf("readio_log 0x%x readio_blocks 0x%x ", + mp->m_readio_log, mp->m_readio_blocks); + kdb_printf("writeio_log 0x%x writeio_blocks 0x%x\n", + mp->m_writeio_log, mp->m_writeio_blocks); + kdb_printf("logbufs %d logbsize %d LOG 0x%p\n", mp->m_logbufs, + mp->m_logbsize, mp->m_log); + kdb_printf("rsumlevels 0x%x rsumsize 0x%x rbmip 0x%p rsumip 0x%p\n", + mp->m_rsumlevels, mp->m_rsumsize, mp->m_rbmip, mp->m_rsumip); + kdb_printf("rootip 0x%p\n", mp->m_rootip); + kdb_printf("dircook_elog %d blkbit_log %d blkbb_log %d agno_log %d\n", + mp->m_dircook_elog, mp->m_blkbit_log, mp->m_blkbb_log, + mp->m_agno_log); + kdb_printf("agino_log %d nreadaheads %d inode cluster size %d\n", + mp->m_agino_log, mp->m_nreadaheads, + mp->m_inode_cluster_size); + kdb_printf("blockmask 0x%x blockwsize 0x%x blockwmask 0x%x\n", + mp->m_blockmask, mp->m_blockwsize, mp->m_blockwmask); + kdb_printf("alloc_mxr[lf,nd] %d %d alloc_mnr[lf,nd] %d %d\n", + mp->m_alloc_mxr[0], mp->m_alloc_mxr[1], + mp->m_alloc_mnr[0], mp->m_alloc_mnr[1]); + kdb_printf("bmap_dmxr[lfnr,ndnr] %d %d bmap_dmnr[lfnr,ndnr] %d %d\n", + mp->m_bmap_dmxr[0], mp->m_bmap_dmxr[1], + mp->m_bmap_dmnr[0], mp->m_bmap_dmnr[1]); + kdb_printf("inobt_mxr[lf,nd] %d %d inobt_mnr[lf,nd] %d %d\n", + mp->m_inobt_mxr[0], mp->m_inobt_mxr[1], + mp->m_inobt_mnr[0], mp->m_inobt_mnr[1]); + kdb_printf("ag_maxlevels %d bm_maxlevels[d,a] %d %d in_maxlevels %d\n", + mp->m_ag_maxlevels, mp->m_bm_maxlevels[0], + mp->m_bm_maxlevels[1], mp->m_in_maxlevels); + kdb_printf("perag 0x%p &peraglock 0x%p &growlock 0x%p\n", + mp->m_perag, &mp->m_peraglock, &mp->m_growlock); + printflags(mp->m_flags, xmount_flags,"flags"); + kdb_printf("ialloc_inos %d ialloc_blks %d litino %d\n", + mp->m_ialloc_inos, mp->m_ialloc_blks, mp->m_litino); + kdb_printf("attroffset %d da_node_ents %d maxicount %Ld inoalign_mask %d\n", + mp->m_attroffset, mp->m_da_node_ents, mp->m_maxicount, + mp->m_inoalign_mask); + kdb_printf("resblks %Ld resblks_avail %Ld\n", mp->m_resblks, + mp->m_resblks_avail); +#if XFS_BIG_FILESYSTEMS + kdb_printf(" inoadd %Lx\n", mp->m_inoadd); +#else + kdb_printf("\n"); +#endif + if (mp->m_quotainfo) + kdb_printf("quotainfo 0x%p (uqip = 0x%p, gqip = 0x%p)\n", + mp->m_quotainfo, + mp->m_quotainfo->qi_uquotaip, + mp->m_quotainfo->qi_gquotaip); + else + kdb_printf("quotainfo NULL\n"); + printflags(mp->m_qflags, quota_flags,"quotaflags"); + kdb_printf("\n"); + kdb_printf("dalign %d swidth %d sinoalign %d attr_magicpct %d dir_magicpct %d\n", + mp->m_dalign, mp->m_swidth, mp->m_sinoalign, + mp->m_attr_magicpct, mp->m_dir_magicpct); + kdb_printf("mk_sharedro %d dirversion %d dirblkfsbs %d &dirops 0x%p\n", + mp->m_mk_sharedro, mp->m_dirversion, mp->m_dirblkfsbs, + &mp->m_dirops); + kdb_printf("dirblksize %d dirdatablk 0x%Lx dirleafblk 0x%Lx dirfreeblk 0x%Lx\n", + mp->m_dirblksize, + (xfs_dfiloff_t)mp->m_dirdatablk, + (xfs_dfiloff_t)mp->m_dirleafblk, + (xfs_dfiloff_t)mp->m_dirfreeblk); + kdb_printf("chsize %d chash 0x%p\n", + mp->m_chsize, mp->m_chash); + kdb_printf("m_frozen %d m_active_trans %d\n", + mp->m_frozen, mp->m_active_trans.counter); + if (mp->m_fsname != NULL) + kdb_printf("mountpoint \"%s\"\n", mp->m_fsname); + else + kdb_printf("No name!!!\n"); + +} + +static void +xfsidbg_xihash(xfs_mount_t *mp) +{ + xfs_ihash_t *ih; + int i; + int j; + int total; + int numzeros; + xfs_inode_t *ip; + int *hist; + int hist_bytes = mp->m_ihsize * sizeof(int); + int hist2[21]; + + hist = (int *) kmalloc(hist_bytes, GFP_KERNEL); + + if (hist == NULL) { + kdb_printf("xfsidbg_xihash: kmalloc(%d) failed!\n", + hist_bytes); + return; + } + + for (i = 0; i < mp->m_ihsize; i++) { + ih = mp->m_ihash + i; + j = 0; + for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) + j++; + hist[i] = j; + } + + numzeros = total = 0; + + for (i = 0; i < 21; i++) + hist2[i] = 0; + + for (i = 0; i < mp->m_ihsize; i++) { + kdb_printf("%d ", hist[i]); + total += hist[i]; + numzeros += hist[i] == 0 ? 1 : 0; + if (hist[i] > 20) + j = 20; + else + j = hist[i]; + + if (! (j <= 20)) { + kdb_printf("xfsidbg_xihash: (j > 20)/%d @ line # %d\n", + j, __LINE__); + return; + } + + hist2[j]++; + } + + kdb_printf("\n"); + + kdb_printf("total inodes = %d, average length = %d, adjusted average = %d \n", + total, total / mp->m_ihsize, + total / (mp->m_ihsize - numzeros)); + + for (i = 0; i < 21; i++) { + kdb_printf("%d - %d , ", i, hist2[i]); + } + kdb_printf("\n"); + kfree(hist); +} + +/* + * Command to print xfs inodes: kp xnode + */ +static void +xfsidbg_xnode(xfs_inode_t *ip) +{ + static char *tab_flags[] = { + "grio", /* XFS_IGRIO */ + "uiosize", /* XFS_IUIOSZ */ + "quiesce", /* XFS_IQUIESCE */ + "reclaim", /* XFS_IRECLAIM */ + NULL + }; + + kdb_printf("hash 0x%p next 0x%p prevp 0x%p mount 0x%p\n", + ip->i_hash, + ip->i_next, + ip->i_prevp, + ip->i_mount); + kdb_printf("mnext 0x%p mprev 0x%p vnode 0x%p \n", + ip->i_mnext, + ip->i_mprev, + XFS_ITOV_NULL(ip)); + kdb_printf("dev %x ino %s\n", + ip->i_dev, + xfs_fmtino(ip->i_ino, ip->i_mount)); + kdb_printf("blkno 0x%Lx len 0x%x boffset 0x%x\n", + ip->i_blkno, + ip->i_len, + ip->i_boffset); + kdb_printf("transp 0x%p &itemp 0x%p\n", + ip->i_transp, + ip->i_itemp); + kdb_printf("&lock 0x%p &iolock 0x%p ni_lock_ra", + &ip->i_lock, + &ip->i_iolock); + kdb_symbol_print((unsigned int) ip->i_ilock_ra, NULL, + KDB_SP_SPACEB|KDB_SP_PAREN|KDB_SP_NEWLINE); + kdb_printf("&flock 0x%p (%d) &pinlock 0x%p pincount 0x%x &pinsema 0x%p\n", + &ip->i_flock, valusema(&ip->i_flock), + &ip->i_ipinlock, + ip->i_pincount, + &ip->i_pinsema); + kdb_printf("udquotp 0x%p gdquotp 0x%p\n", + ip->i_udquot, ip->i_gdquot); + kdb_printf("new_size %Lx\n", ip->i_iocore.io_new_size); + kdb_printf( +"readiolog %u, readioblocks %u, writeiolog %u, writeioblocks %u, maxiolog %u\n", + (unsigned int) ip->i_iocore.io_readio_log, + ip->i_iocore.io_readio_blocks, + (unsigned int) ip->i_iocore.io_writeio_log, + ip->i_iocore.io_writeio_blocks, + (unsigned int) ip->i_iocore.io_max_io_log); + printflags((int)ip->i_flags, tab_flags, "flags"); + kdb_printf("\n"); + kdb_printf("update_core 0x%x update size 0x%x\n", + (int)(ip->i_update_core), (int) ip->i_update_size); + kdb_printf("gen 0x%x qbufs %d delayed blks %d", + ip->i_gen, + ip->i_iocore.io_queued_bufs, + ip->i_delayed_blks); + kdb_printf("\n"); + kdb_printf("chash 0x%p cnext 0x%p cprev 0x%p\n", + ip->i_chash, + ip->i_cnext, + ip->i_cprev); + xfs_xnode_fork("data", &ip->i_df); + xfs_xnode_fork("attr", ip->i_afp); + kdb_printf("\n"); + xfs_prdinode_core(&ip->i_d, ARCH_NOCONVERT); +} + +static void +xfsidbg_xcore(xfs_iocore_t *io) +{ + if (IO_IS_XFS(io)) { + kdb_printf("io_obj 0x%p (xinode) io_mount 0x%p\n", + io->io_obj, io->io_mount); + } else { + kdb_printf("io_obj 0x%p (dcxvn) io_mount 0x%p\n", + io->io_obj, io->io_mount); + } + kdb_printf("&lock 0x%p &iolock 0x%p &flock 0x%p\n", + io->io_lock, io->io_iolock, + io->io_flock); + kdb_printf("new_size %Lx\n", io->io_new_size); + kdb_printf( +"readiolog %u, readioblocks %u, writeiolog %u, writeioblocks %u, maxiolog %u\n", + (unsigned int) io->io_readio_log, + io->io_readio_blocks, + (unsigned int) io->io_writeio_log, + io->io_writeio_blocks, + (unsigned int) io->io_max_io_log); +} + +/* + * Command to print xfs inode cluster hash table: kp xchash + */ +static void +xfsidbg_xchash(xfs_mount_t *mp) +{ + int i; + xfs_chash_t *ch; + + kdb_printf("m_chash 0x%p size %d\n", + mp->m_chash, mp->m_chsize); + for (i = 0; i < mp->m_chsize; i++) { + ch = mp->m_chash + i; + kdb_printf("[%3d] ch 0x%p chashlist 0x%p\n", i, ch, ch->ch_list); + xfsidbg_xchashlist(ch->ch_list); + } +} + +/* + * Command to print xfs inode cluster hash list: kp xchashlist + */ +static void +xfsidbg_xchashlist(xfs_chashlist_t *chl) +{ + xfs_inode_t *ip; + + while (chl != NULL) { + kdb_printf("hashlist inode 0x%p blkno %Ld ", + chl->chl_ip, chl->chl_blkno); + + kdb_printf("\n"); + + /* print inodes on chashlist */ + ip = chl->chl_ip; + do { + kdb_printf("0x%p ", ip); + ip = ip->i_cnext; + } while (ip != chl->chl_ip); + kdb_printf("\n"); + + chl=chl->chl_next; + } +} + +/* + * Print xfs per-ag data structures for filesystem. + */ +static void +xfsidbg_xperag(xfs_mount_t *mp) +{ + xfs_agnumber_t agno; + xfs_perag_t *pag; + + pag = mp->m_perag; + for (agno = 0; agno < mp->m_sb.sb_agcount; agno++, pag++) { + kdb_printf("ag %d f_init %d i_init %d\n", + agno, pag->pagf_init, pag->pagi_init); + if (pag->pagf_init) + kdb_printf( + " f_levels[b,c] %d,%d f_flcount %d f_freeblks %d f_longest %d\n", + pag->pagf_levels[XFS_BTNUM_BNOi], + pag->pagf_levels[XFS_BTNUM_CNTi], + pag->pagf_flcount, pag->pagf_freeblks, + pag->pagf_longest); + if (pag->pagi_init) + kdb_printf(" i_freecount %d\n", pag->pagi_freecount); + } +} + + + +static void +xfsidbg_xqm() +{ + if (xfs_Gqm == NULL) { + kdb_printf("NULL XQM!!\n"); + return; + } + + kdb_printf("usrhtab 0x%p\tgrphtab 0x%p\tndqfree 0x%x\thashmask 0x%x\n", + xfs_Gqm->qm_usr_dqhtable, + xfs_Gqm->qm_grp_dqhtable, + xfs_Gqm->qm_dqfreelist.qh_nelems, + xfs_Gqm->qm_dqhashmask); + kdb_printf("&freelist 0x%p, totaldquots 0x%x nrefs 0x%x\n", + &xfs_Gqm->qm_dqfreelist, + atomic_read(&xfs_Gqm->qm_totaldquots), + xfs_Gqm->qm_nrefs); +} + +static void +xfsidbg_xqm_diskdq(xfs_disk_dquot_t *d) +{ + kdb_printf("magic 0x%x\tversion 0x%x\tID 0x%x (%d)\t\n", INT_GET(d->d_magic, ARCH_CONVERT), + INT_GET(d->d_version, ARCH_CONVERT), INT_GET(d->d_id, ARCH_CONVERT), INT_GET(d->d_id, ARCH_CONVERT)); + kdb_printf("blk_hard 0x%x\tblk_soft 0x%x\tino_hard 0x%x\tino_soft 0x%x\n", + (int)INT_GET(d->d_blk_hardlimit, ARCH_CONVERT), (int)INT_GET(d->d_blk_softlimit, ARCH_CONVERT), + (int)INT_GET(d->d_ino_hardlimit, ARCH_CONVERT), (int)INT_GET(d->d_ino_softlimit, ARCH_CONVERT)); + kdb_printf("bcount 0x%x (%d) icount 0x%x (%d)\n", + (int)INT_GET(d->d_bcount, ARCH_CONVERT), (int)INT_GET(d->d_bcount, ARCH_CONVERT), + (int)INT_GET(d->d_icount, ARCH_CONVERT), (int)INT_GET(d->d_icount, ARCH_CONVERT)); + kdb_printf("btimer 0x%x itimer 0x%x \n", + (int)INT_GET(d->d_btimer, ARCH_CONVERT), (int)INT_GET(d->d_itimer, ARCH_CONVERT)); +} + +static void +xfsidbg_xqm_dquot(xfs_dquot_t *dqp) +{ + static char *qflags[] = { + "USR", + "GRP", + "LCKD", + "FLKD", + "DIRTY", + "WANT", + "INACT", + "MARKER", + 0 + }; + kdb_printf("mount 0x%p hash 0x%p gdquotp 0x%p HL_next 0x%p HL_prevp 0x%p\n", + dqp->q_mount, + dqp->q_hash, + dqp->q_gdquot, + dqp->HL_NEXT, + dqp->HL_PREVP); + kdb_printf("MPL_next 0x%p MPL_prevp 0x%p FL_next 0x%p FL_prev 0x%p\n", + dqp->MPL_NEXT, + dqp->MPL_PREVP, + dqp->dq_flnext, + dqp->dq_flprev); + + kdb_printf("nrefs 0x%x, res_bcount %d, ", + dqp->q_nrefs, (int) dqp->q_res_bcount); + printflags(dqp->dq_flags, qflags, "flags:"); + kdb_printf("\nblkno 0x%x\tdev 0x%x\tboffset 0x%x\n", (int) dqp->q_blkno, + (int) dqp->q_dev, (int) dqp->q_bufoffset); + kdb_printf("qlock 0x%p flock 0x%p (%s) pincount 0x%x\n", + &dqp->q_qlock, + &dqp->q_flock, + (valusema(&dqp->q_flock) <= 0) ? "LCK" : "UNLKD", + dqp->q_pincount); + kdb_printf("disk-dquot 0x%p\n", &dqp->q_core); + xfsidbg_xqm_diskdq(&dqp->q_core); + +} + + +#define XQMIDBG_LIST_PRINT(l, NXT) \ +{ \ + xfs_dquot_t *dqp;\ + int i = 0; \ + kdb_printf("[#%d dquots]\n", (int) (l)->qh_nelems); \ + for (dqp = (l)->qh_next; dqp != NULL; dqp = dqp->NXT) {\ + kdb_printf( \ + "\t%d. [0x%p] \"%d (%s)\"\t blks = %d, inos = %d refs = %d\n", \ + ++i, dqp, (int) INT_GET(dqp->q_core.d_id, ARCH_CONVERT), \ + DQFLAGTO_TYPESTR(dqp), \ + (int) INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT), \ + (int) INT_GET(dqp->q_core.d_icount, ARCH_CONVERT), \ + (int) dqp->q_nrefs); }\ + kdb_printf("\n"); \ +} + +static void +xfsidbg_xqm_dqattached_inos(xfs_mount_t *mp) +{ + xfs_inode_t *ip; + int n = 0; + + ip = mp->m_inodes; + do { + if (ip->i_mount == NULL) { + ip = ip->i_mnext; + continue; + } + if (ip->i_udquot || ip->i_gdquot) { + n++; + kdb_printf("inode = 0x%p, ino %d: udq 0x%p, gdq 0x%p\n", + ip, (int)ip->i_ino, ip->i_udquot, ip->i_gdquot); + } + ip = ip->i_mnext; + } while (ip != mp->m_inodes); + kdb_printf("\nNumber of inodes with dquots attached: %d\n", n); +} + + +static void +xfsidbg_xqm_freelist_print(xfs_frlist_t *qlist, char *title) +{ + xfs_dquot_t *dq; + int i = 0; + kdb_printf("%s (#%d)\n", title, (int) qlist->qh_nelems); + FOREACH_DQUOT_IN_FREELIST(dq, qlist) { + kdb_printf("\t%d.\t\"%d (%s:0x%p)\"\t bcnt = %d, icnt = %d " + "refs = %d\n", + ++i, (int) INT_GET(dq->q_core.d_id, ARCH_CONVERT), + DQFLAGTO_TYPESTR(dq), dq, + (int) INT_GET(dq->q_core.d_bcount, ARCH_CONVERT), + (int) INT_GET(dq->q_core.d_icount, ARCH_CONVERT), + (int) dq->q_nrefs); + } +} + +static void +xfsidbg_xqm_freelist(void) +{ + if (xfs_Gqm) { + xfsidbg_xqm_freelist_print(&(xfs_Gqm->qm_dqfreelist), "Freelist"); + } else + kdb_printf("NULL XQM!!\n"); +} + +static void +xfsidbg_xqm_mplist(xfs_mount_t *mp) +{ + if (mp->m_quotainfo == NULL) { + kdb_printf("NULL quotainfo\n"); + return; + } + + XQMIDBG_LIST_PRINT(&(mp->m_quotainfo->qi_dqlist), MPL_NEXT); + +} + +static void +xfsidbg_xqm_htab(void) +{ + int i; + xfs_dqhash_t *h; + + if (xfs_Gqm == NULL) { + kdb_printf("NULL XQM!!\n"); + return; + } + for (i = 0; i <= xfs_Gqm->qm_dqhashmask; i++) { + h = &xfs_Gqm->qm_usr_dqhtable[i]; + if (h->qh_next) { + kdb_printf("USR %d: ", i); + XQMIDBG_LIST_PRINT(h, HL_NEXT); + } + } + for (i = 0; i <= xfs_Gqm->qm_dqhashmask; i++) { + h = &xfs_Gqm->qm_grp_dqhtable[i]; + if (h->qh_next) { + kdb_printf("GRP %d: ", i); + XQMIDBG_LIST_PRINT(h, HL_NEXT); + } + } +} + + +static void +xfsidbg_xqm_qinfo(xfs_mount_t *mp) +{ + if (mp == NULL || mp->m_quotainfo == NULL) { + kdb_printf("NULL quotainfo\n"); + return; + } + + kdb_printf("uqip 0x%p, gqip 0x%p, &pinlock 0x%p &dqlist 0x%p\n", + mp->m_quotainfo->qi_uquotaip, + mp->m_quotainfo->qi_gquotaip, + &mp->m_quotainfo->qi_pinlock, + &mp->m_quotainfo->qi_dqlist); + + kdb_printf("nreclaims %d, btmlimit 0x%x, itmlimit 0x%x, RTbtmlim 0x%x\n", + (int)mp->m_quotainfo->qi_dqreclaims, + (int)mp->m_quotainfo->qi_btimelimit, + (int)mp->m_quotainfo->qi_itimelimit, + (int)mp->m_quotainfo->qi_rtbtimelimit); + + kdb_printf("bwarnlim 0x%x, iwarnlim 0x%x, &qofflock 0x%p, " + "chunklen 0x%x, dqperchunk 0x%x\n", + (int)mp->m_quotainfo->qi_bwarnlimit, + (int)mp->m_quotainfo->qi_iwarnlimit, + &mp->m_quotainfo->qi_quotaofflock, + (int)mp->m_quotainfo->qi_dqchunklen, + (int)mp->m_quotainfo->qi_dqperchunk); +} + +static void +xfsidbg_xqm_tpdqinfo(xfs_trans_t *tp) +{ + xfs_dqtrx_t *qa, *q; + int i,j; + + kdb_printf("dqinfo 0x%p\n", tp->t_dqinfo); + if (! tp->t_dqinfo) + return; + kdb_printf("USR: \n"); + qa = tp->t_dqinfo->dqa_usrdquots; + for (j = 0; j < 2; j++) { + for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) { + if (qa[i].qt_dquot == NULL) + break; + q = &qa[i]; + kdb_printf( + "\"%d\"[0x%p]: bres %d, bres-used %d, bdelta %d, del-delta %d, icnt-delta %d\n", + (int) q->qt_dquot->q_core.d_id, + q->qt_dquot, + (int) q->qt_blk_res, + (int) q->qt_blk_res_used, + (int) q->qt_bcount_delta, + (int) q->qt_delbcnt_delta, + (int) q->qt_icount_delta); + } + if (j == 0) { + qa = tp->t_dqinfo->dqa_grpdquots; + kdb_printf("GRP: \n"); + } + } + +} + + + +/* + * Print xfs superblock. + */ +static void +xfsidbg_xsb(xfs_sb_t *sbp, int convert) +{ + xfs_arch_t arch=convert?ARCH_CONVERT:ARCH_NOCONVERT; + + kdb_printf(convert?"\n":"\n"); + + kdb_printf("magicnum 0x%x blocksize 0x%x dblocks %Ld rblocks %Ld\n", + INT_GET(sbp->sb_magicnum, arch), INT_GET(sbp->sb_blocksize, arch), + INT_GET(sbp->sb_dblocks, arch), INT_GET(sbp->sb_rblocks, arch)); + kdb_printf("rextents %Ld uuid %s logstart %s\n", + INT_GET(sbp->sb_rextents, arch), + xfs_fmtuuid(&sbp->sb_uuid), + xfs_fmtfsblock(INT_GET(sbp->sb_logstart, arch), NULL)); + kdb_printf("rootino %s ", + xfs_fmtino(INT_GET(sbp->sb_rootino, arch), NULL)); + kdb_printf("rbmino %s ", + xfs_fmtino(INT_GET(sbp->sb_rbmino, arch), NULL)); + kdb_printf("rsumino %s\n", + xfs_fmtino(INT_GET(sbp->sb_rsumino, arch), NULL)); + kdb_printf("rextsize 0x%x agblocks 0x%x agcount 0x%x rbmblocks 0x%x\n", + INT_GET(sbp->sb_rextsize, arch), + INT_GET(sbp->sb_agblocks, arch), + INT_GET(sbp->sb_agcount, arch), + INT_GET(sbp->sb_rbmblocks, arch)); + kdb_printf("logblocks 0x%x versionnum 0x%x sectsize 0x%x inodesize 0x%x\n", + INT_GET(sbp->sb_logblocks, arch), + INT_GET(sbp->sb_versionnum, arch), + INT_GET(sbp->sb_sectsize, arch), + INT_GET(sbp->sb_inodesize, arch)); + kdb_printf("inopblock 0x%x blocklog 0x%x sectlog 0x%x inodelog 0x%x\n", + INT_GET(sbp->sb_inopblock, arch), + INT_GET(sbp->sb_blocklog, arch), + INT_GET(sbp->sb_sectlog, arch), + INT_GET(sbp->sb_inodelog, arch)); + kdb_printf("inopblog %d agblklog %d rextslog %d inprogress %d imax_pct %d\n", + INT_GET(sbp->sb_inopblog, arch), + INT_GET(sbp->sb_agblklog, arch), + INT_GET(sbp->sb_rextslog, arch), + INT_GET(sbp->sb_inprogress, arch), + INT_GET(sbp->sb_imax_pct, arch)); + kdb_printf("icount %Lx ifree %Lx fdblocks %Lx frextents %Lx\n", + INT_GET(sbp->sb_icount, arch), + INT_GET(sbp->sb_ifree, arch), + INT_GET(sbp->sb_fdblocks, arch), + INT_GET(sbp->sb_frextents, arch)); + kdb_printf("uquotino %s ", xfs_fmtino(INT_GET(sbp->sb_uquotino, arch), NULL)); + kdb_printf("gquotino %s ", xfs_fmtino(INT_GET(sbp->sb_gquotino, arch), NULL)); + kdb_printf("qflags 0x%x flags 0x%x shared_vn %d inoaligmt %d\n", + INT_GET(sbp->sb_qflags, arch), INT_GET(sbp->sb_flags, arch), INT_GET(sbp->sb_shared_vn, arch), + INT_GET(sbp->sb_inoalignmt, arch)); + kdb_printf("unit %d width %d dirblklog %d\n", + INT_GET(sbp->sb_unit, arch), INT_GET(sbp->sb_width, arch), INT_GET(sbp->sb_dirblklog, arch)); +} + + +/* + * Print out an XFS transaction structure. Print summaries for + * each of the items. + */ +static void +xfsidbg_xtp(xfs_trans_t *tp) +{ + xfs_log_item_chunk_t *licp; + xfs_log_item_desc_t *lidp; + int i; + int chunk; + static char *xtp_flags[] = { + "dirty", /* 0x1 */ + "sb_dirty", /* 0x2 */ + "perm_log_res", /* 0x4 */ + "sync", /* 0x08 */ + "dq_dirty", /* 0x10 */ + 0 + }; + static char *lid_flags[] = { + "dirty", /* 0x1 */ + "pinned", /* 0x2 */ + "sync unlock", /* 0x4 */ + 0 + }; + + kdb_printf("tp 0x%p type ", tp); + switch (tp->t_type) { + case XFS_TRANS_SETATTR_NOT_SIZE: kdb_printf("SETATTR_NOT_SIZE"); break; + case XFS_TRANS_SETATTR_SIZE: kdb_printf("SETATTR_SIZE"); break; + case XFS_TRANS_INACTIVE: kdb_printf("INACTIVE"); break; + case XFS_TRANS_CREATE: kdb_printf("CREATE"); break; + case XFS_TRANS_CREATE_TRUNC: kdb_printf("CREATE_TRUNC"); break; + case XFS_TRANS_TRUNCATE_FILE: kdb_printf("TRUNCATE_FILE"); break; + case XFS_TRANS_REMOVE: kdb_printf("REMOVE"); break; + case XFS_TRANS_LINK: kdb_printf("LINK"); break; + case XFS_TRANS_RENAME: kdb_printf("RENAME"); break; + case XFS_TRANS_MKDIR: kdb_printf("MKDIR"); break; + case XFS_TRANS_RMDIR: kdb_printf("RMDIR"); break; + case XFS_TRANS_SYMLINK: kdb_printf("SYMLINK"); break; + case XFS_TRANS_SET_DMATTRS: kdb_printf("SET_DMATTRS"); break; + case XFS_TRANS_GROWFS: kdb_printf("GROWFS"); break; + case XFS_TRANS_STRAT_WRITE: kdb_printf("STRAT_WRITE"); break; + case XFS_TRANS_DIOSTRAT: kdb_printf("DIOSTRAT"); break; + case XFS_TRANS_WRITE_SYNC: kdb_printf("WRITE_SYNC"); break; + case XFS_TRANS_WRITEID: kdb_printf("WRITEID"); break; + case XFS_TRANS_ADDAFORK: kdb_printf("ADDAFORK"); break; + case XFS_TRANS_ATTRINVAL: kdb_printf("ATTRINVAL"); break; + case XFS_TRANS_ATRUNCATE: kdb_printf("ATRUNCATE"); break; + case XFS_TRANS_ATTR_SET: kdb_printf("ATTR_SET"); break; + case XFS_TRANS_ATTR_RM: kdb_printf("ATTR_RM"); break; + case XFS_TRANS_ATTR_FLAG: kdb_printf("ATTR_FLAG"); break; + case XFS_TRANS_CLEAR_AGI_BUCKET: kdb_printf("CLEAR_AGI_BUCKET"); break; + case XFS_TRANS_QM_SBCHANGE: kdb_printf("QM_SBCHANGE"); break; + case XFS_TRANS_QM_QUOTAOFF: kdb_printf("QM_QUOTAOFF"); break; + case XFS_TRANS_QM_DQALLOC: kdb_printf("QM_DQALLOC"); break; + case XFS_TRANS_QM_SETQLIM: kdb_printf("QM_SETQLIM"); break; + case XFS_TRANS_QM_DQCLUSTER: kdb_printf("QM_DQCLUSTER"); break; + case XFS_TRANS_QM_QINOCREATE: kdb_printf("QM_QINOCREATE"); break; + case XFS_TRANS_QM_QUOTAOFF_END: kdb_printf("QM_QOFF_END"); break; + case XFS_TRANS_SB_UNIT: kdb_printf("SB_UNIT"); break; + case XFS_TRANS_FSYNC_TS: kdb_printf("FSYNC_TS"); break; + case XFS_TRANS_GROWFSRT_ALLOC: kdb_printf("GROWFSRT_ALLOC"); break; + case XFS_TRANS_GROWFSRT_ZERO: kdb_printf("GROWFSRT_ZERO"); break; + case XFS_TRANS_GROWFSRT_FREE: kdb_printf("GROWFSRT_FREE"); break; + + default: kdb_printf("0x%x", tp->t_type); break; + } + kdb_printf(" mount 0x%p\n", tp->t_mountp); + kdb_printf("flags "); + printflags(tp->t_flags, xtp_flags,"xtp"); + kdb_printf("\n"); + kdb_printf("callback 0x%p forw 0x%p back 0x%p\n", + &tp->t_logcb, tp->t_forw, tp->t_back); + kdb_printf("log res %d block res %d block res used %d\n", + tp->t_log_res, tp->t_blk_res, tp->t_blk_res_used); + kdb_printf("rt res %d rt res used %d\n", tp->t_rtx_res, + tp->t_rtx_res_used); + kdb_printf("ticket 0x%x lsn %s\n", + (uint32_t) tp->t_ticket, xfs_fmtlsn(&tp->t_lsn)); + kdb_printf("callback 0x%p callarg 0x%p\n", + tp->t_callback, tp->t_callarg); + kdb_printf("icount delta %ld ifree delta %ld\n", + tp->t_icount_delta, tp->t_ifree_delta); + kdb_printf("blocks delta %ld res blocks delta %ld\n", + tp->t_fdblocks_delta, tp->t_res_fdblocks_delta); + kdb_printf("rt delta %ld res rt delta %ld\n", + tp->t_frextents_delta, tp->t_res_frextents_delta); + kdb_printf("ag freeblks delta %ld ag flist delta %ld ag btree delta %ld\n", + tp->t_ag_freeblks_delta, tp->t_ag_flist_delta, + tp->t_ag_btree_delta); + kdb_printf("dblocks delta %ld agcount delta %ld imaxpct delta %ld\n", + tp->t_dblocks_delta, tp->t_agcount_delta, tp->t_imaxpct_delta); + kdb_printf("rextsize delta %ld rbmblocks delta %ld\n", + tp->t_rextsize_delta, tp->t_rbmblocks_delta); + kdb_printf("rblocks delta %ld rextents delta %ld rextslog delta %ld\n", + tp->t_rblocks_delta, tp->t_rextents_delta, + tp->t_rextslog_delta); + kdb_printf("dqinfo 0x%p\n", tp->t_dqinfo); + kdb_printf("log items:\n"); + licp = &tp->t_items; + chunk = 0; + while (licp != NULL) { + if (XFS_LIC_ARE_ALL_FREE(licp)) { + licp = licp->lic_next; + chunk++; + continue; + } + for (i = 0; i < licp->lic_unused; i++) { + if (XFS_LIC_ISFREE(licp, i)) { + continue; + } + + lidp = XFS_LIC_SLOT(licp, i); + kdb_printf("\n"); + kdb_printf("chunk %d index %d item 0x%p size %d\n", + chunk, i, lidp->lid_item, lidp->lid_size); + kdb_printf("flags "); + printflags(lidp->lid_flags, lid_flags,"lic"); + kdb_printf("\n"); + xfsidbg_xlogitem(lidp->lid_item); + } + chunk++; + licp = licp->lic_next; + } +} + +static void +xfsidbg_xtrans_res( + xfs_mount_t *mp) +{ + xfs_trans_reservations_t *xtrp; + + xtrp = &mp->m_reservations; + kdb_printf("write: %d\ttruncate: %d\trename: %d\n", + xtrp->tr_write, xtrp->tr_itruncate, xtrp->tr_rename); + kdb_printf("link: %d\tremove: %d\tsymlink: %d\n", + xtrp->tr_link, xtrp->tr_remove, xtrp->tr_symlink); + kdb_printf("create: %d\tmkdir: %d\tifree: %d\n", + xtrp->tr_create, xtrp->tr_mkdir, xtrp->tr_ifree); + kdb_printf("ichange: %d\tgrowdata: %d\tswrite: %d\n", + xtrp->tr_ichange, xtrp->tr_growdata, xtrp->tr_swrite); + kdb_printf("addafork: %d\twriteid: %d\tattrinval: %d\n", + xtrp->tr_addafork, xtrp->tr_writeid, xtrp->tr_attrinval); + kdb_printf("attrset: %d\tattrrm: %d\tclearagi: %d\n", + xtrp->tr_attrset, xtrp->tr_attrrm, xtrp->tr_clearagi); + kdb_printf("growrtalloc: %d\tgrowrtzero: %d\tgrowrtfree: %d\n", + xtrp->tr_growrtalloc, xtrp->tr_growrtzero, xtrp->tr_growrtfree); +} + diff -rNu linux-2.4.7/linux/fs/xfs/xfsquotasstubs.c linux-2.4-xfs/linux/fs/xfs/xfsquotasstubs.c --- linux-2.4.7/linux/fs/xfs/xfsquotasstubs.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfsquotasstubs.c Wed May 23 22:34:41 2001 @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * XFS Disk Quota stubs + */ +#include + +struct xfs_qm *xfs_Gqm; +mutex_t xfs_Gqm_lock; +xfs_zone_t *qm_dqzone; +xfs_zone_t *qm_dqtrxzone; + +/* + * Quota Manager Interface. + */ +struct xfs_qm *xfs_qm_init(void) { return NULL; } +void xfs_qm_destroy(struct xfs_qm *a) { return; } +int xfs_qm_dqflush_all(struct xfs_mount *a, int b) + { return nopkg(); } +int xfs_qm_dqattach(struct xfs_inode *a, uint b) { return nopkg(); } +int xfs_qm_dqpurge_all(struct xfs_mount *a, uint b) { return nopkg(); } +void xfs_qm_mount_quotainit(struct xfs_mount *a, uint b) { return; } +void xfs_qm_unmount_quotadestroy(struct xfs_mount *a) { return; } +int xfs_qm_mount_quotas(struct xfs_mount *a) { return nopkg(); } +int xfs_qm_unmount_quotas(struct xfs_mount *a) { return nopkg(); } +void xfs_qm_dqdettach_inode(struct xfs_inode *a) { return; } +int xfs_qm_sync(struct xfs_mount *a, short b) { return nopkg(); } + +/* + * quotactl(2) system call interface + */ +int xfs_quotactl(xfs_mount_t *a, struct vfs *b, int c, int d, + int e, xfs_caddr_t f) { return nopkg(); }; + +/* + * dquot interface + */ +void xfs_dqlock(struct xfs_dquot *a) { return; } +void xfs_dqunlock(struct xfs_dquot *a) { return; } +void xfs_dqunlock_nonotify(struct xfs_dquot *a) { return; } +void xfs_dqlock2(struct xfs_dquot *a, struct xfs_dquot *b) {return;} +void xfs_qm_dqput(struct xfs_dquot *a) { return; } +void xfs_qm_dqrele(struct xfs_dquot *a) { return; } +int xfs_qm_dqid(struct xfs_dquot *a) { return -1; } +int xfs_qm_dqget(struct xfs_mount *a, struct xfs_inode *b, + xfs_dqid_t c, uint d, uint e, struct xfs_dquot **f) + { return nopkg(); } +int xfs_qm_dqcheck(struct xfs_disk_dquot *a, xfs_dqid_t b, uint c, + uint d, char *e) { return nopkg(); } + +/* + * Dquot Transaction interface + */ +void xfs_trans_alloc_dqinfo(struct xfs_trans *a) { return; } +void xfs_trans_free_dqinfo(struct xfs_trans *a) { return; } +void xfs_trans_dup_dqinfo(struct xfs_trans *a, struct xfs_trans *b) + { return; } +void xfs_trans_mod_dquot(struct xfs_trans *a, struct xfs_dquot *b, + uint c, long d) { return; } +int xfs_trans_mod_dquot_byino(struct xfs_trans *a, struct xfs_inode *b, + uint c, long d) { return nopkg(); } +void xfs_trans_apply_dquot_deltas(struct xfs_trans *a) { return; } +void xfs_trans_unreserve_and_mod_dquots(struct xfs_trans *a) { return; } +int xfs_trans_reserve_quota_nblks(struct xfs_trans *a, struct xfs_inode *b, + long c, long d, uint e) { return nopkg(); } +int xfs_trans_reserve_quota_bydquots(struct xfs_trans *a, + struct xfs_dquot *b, struct xfs_dquot *c, long d, long e, + uint f) { return nopkg(); } +void xfs_trans_log_dquot(struct xfs_trans *a, struct xfs_dquot *b) + { return; } +void xfs_trans_dqjoin(struct xfs_trans *a, struct xfs_dquot *b) { return; } +void xfs_qm_dqrele_all_inodes(struct xfs_mount *a, uint b) { return; } + + +/* + * Vnodeops Utility Functions + */ + +struct xfs_dquot *xfs_qm_vop_chown(struct xfs_trans *a, + struct xfs_inode *b, struct xfs_dquot **c, + struct xfs_dquot *d) { return NULL; } +int xfs_qm_vop_dqalloc(struct xfs_mount *a, struct xfs_inode *b, + uid_t c, gid_t d, uint e, struct xfs_dquot **f, + struct xfs_dquot **g) { return nopkg(); } +int xfs_qm_vop_chown_dqalloc(struct xfs_mount *a, + struct xfs_inode *b, int c, uid_t d, gid_t e, + struct xfs_dquot **f, struct xfs_dquot **g) { return nopkg(); } +int xfs_qm_vop_chown_reserve(struct xfs_trans *a, + struct xfs_inode *b, struct xfs_dquot *c, struct xfs_dquot *d, + uint e) { return nopkg(); } +int xfs_qm_vop_rename_dqattach(struct xfs_inode **a) { return nopkg(); } +void xfs_qm_vop_dqattach_and_dqmod_newinode(struct xfs_trans *t, + struct xfs_inode *a, struct xfs_dquot *b, struct xfs_dquot *c) + { return; } + + diff -rNu linux-2.4.7/linux/fs/xfs/xfsrtstubs.c linux-2.4-xfs/linux/fs/xfs/xfsrtstubs.c --- linux-2.4.7/linux/fs/xfs/xfsrtstubs.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs/xfsrtstubs.c Wed Mar 7 14:19:24 2001 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + + +int +xfs_rtallocate_extent( + struct xfs_trans *tp, + xfs_rtblock_t bno, + xfs_extlen_t minlen, + xfs_extlen_t maxlen, + xfs_extlen_t *len, + xfs_alloctype_t type, + int wasdel, + xfs_extlen_t prod, + xfs_rtblock_t *rtblock) +{ + return nopkg(); +} + +int +xfs_rtfree_extent( + struct xfs_trans *tp, + xfs_rtblock_t bno, + xfs_extlen_t len) +{ + return nopkg(); +} + +int +xfs_rtpick_extent( + struct xfs_mount *mp, + struct xfs_trans *tp, + xfs_extlen_t len, + xfs_rtblock_t *pick) +{ + return nopkg(); +} + +int +xfs_rtmount_init(xfs_mount_t *mp) +{ + if (mp->m_sb.sb_rblocks == 0) + return 0; + cmn_err(CE_WARN, "XFS: RT not enabled (CONFIG_XFS_RT)\n"); + return nopkg(); +} + +int +xfs_rtmount_inodes(xfs_mount_t *mp) +{ + if (mp->m_sb.sb_rblocks == 0) + return 0; + return nopkg(); +} + +int +xfs_growfs_rt( + xfs_mount_t *mp, + xfs_growfs_rt_t *in) +{ + return nopkg(); +} + diff -rNu linux-2.4.7/linux/fs/xfs_support/CVS/Entries linux-2.4-xfs/linux/fs/xfs_support/CVS/Entries --- linux-2.4.7/linux/fs/xfs_support/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/CVS/Entries Thu Jul 5 12:04:31 2001 @@ -0,0 +1,28 @@ +/Makefile/1.2/Wed Mar 14 08:07:20 2001/-ko/ +/arch.h/1.2/Wed May 9 07:05:17 2001/-ko/ +/atomic.h/1.1/Wed Mar 14 06:04:19 2001/-ko/ +/debug.c/1.2/Wed Mar 14 08:07:20 2001/-ko/ +/debug.h/1.1/Wed Mar 14 06:04:19 2001/-ko/ +/kmem.c/1.9/Tue Jul 3 02:29:39 2001/-ko/ +/kmem.h/1.5/Tue May 22 20:23:15 2001/-ko/ +/ktrace.c/1.2/Wed Mar 14 08:07:20 2001/-ko/ +/ktrace.h/1.2/Wed Mar 14 08:07:20 2001/-ko/ +/move.c/1.2/Wed Mar 14 08:07:20 2001/-ko/ +/move.h/1.3/Thu Mar 15 23:33:20 2001/-ko/ +/mrlock.c/1.2/Wed Mar 14 08:07:20 2001/-ko/ +/mrlock.h/1.1/Wed Mar 14 06:04:19 2001/-ko/ +/mutex.c/1.2/Wed Mar 14 08:07:20 2001/-ko/ +/mutex.h/1.1/Wed Mar 14 06:04:19 2001/-ko/ +/qsort.c/1.1/Wed Mar 14 06:04:19 2001/-ko/ +/qsort.h/1.1/Wed Mar 14 06:04:19 2001/-ko/ +/sema.h/1.1/Wed Mar 14 06:04:19 2001/-ko/ +/spin.h/1.1/Wed Mar 14 06:04:19 2001/-ko/ +/support.c/1.4/Thu May 17 03:10:40 2001/-ko/ +/support.h/1.2/Wed Mar 14 08:07:20 2001/-ko/ +/sv.c/1.2/Wed Mar 14 08:07:20 2001/-ko/ +/sv.h/1.1/Wed Mar 14 06:04:19 2001/-ko/ +/time.h/1.1/Wed Mar 14 06:04:19 2001/-ko/ +/types.h/1.2/Wed Apr 11 01:44:54 2001/-ko/ +/uuid.c/1.3/Wed May 16 02:10:14 2001/-ko/ +/uuid.h/1.3/Wed May 16 02:10:14 2001/-ko/ +D diff -rNu linux-2.4.7/linux/fs/xfs_support/CVS/Repository linux-2.4-xfs/linux/fs/xfs_support/CVS/Repository --- linux-2.4.7/linux/fs/xfs_support/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/CVS/Repository Thu Jul 5 12:04:30 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/fs/xfs_support diff -rNu linux-2.4.7/linux/fs/xfs_support/CVS/Root linux-2.4-xfs/linux/fs/xfs_support/CVS/Root --- linux-2.4.7/linux/fs/xfs_support/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/CVS/Root Thu Jul 5 12:04:30 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/fs/xfs_support/Makefile linux-2.4-xfs/linux/fs/xfs_support/Makefile --- linux-2.4.7/linux/fs/xfs_support/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/Makefile Wed Mar 14 02:07:20 2001 @@ -0,0 +1,51 @@ +# +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write the Free Software Foundation, Inc., 59 +# Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, +# Mountain View, CA 94043, or: +# +# http://www.sgi.com +# +# For further information regarding this notice, see: +# +# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ +# +# Makefile for XFS on Linux. +# + +ifeq ($(CONFIG_XFS_DEBUG),y) + EXTRA_CFLAGS += -DDEBUG -DXFSDEBUG +endif +# xfs support include files should really be in linux/include, not hidden +# somewhere under fs. Keith Owens. +EXTRA_CFLAGS += -I $(TOPDIR)/fs + +O_TARGET := xfs_support.o +obj-m := $(O_TARGET) + +export-objs := debug.o kmem.o ktrace.o move.o mrlock.o mutex.o qsort.o sv.o uuid.o + +obj-y := support.o qsort.o kmem.o ktrace.o debug.o \ + mrlock.o sv.o mutex.o move.o uuid.o + +include $(TOPDIR)/Rules.make diff -rNu linux-2.4.7/linux/fs/xfs_support/arch.h linux-2.4-xfs/linux/fs/xfs_support/arch.h --- linux-2.4.7/linux/fs/xfs_support/arch.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/arch.h Wed May 9 02:05:17 2001 @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_ARCH_H__ +#define __XFS_SUPPORT_ARCH_H__ + +#ifdef __KERNEL__ + +#include + +#ifdef __LITTLE_ENDIAN +# define __BYTE_ORDER __LITTLE_ENDIAN +#endif +#ifdef __BIG_ENDIAN +# define __BYTE_ORDER __BIG_ENDIAN +#endif + +#endif /* __KERNEL__ */ + +/* do we need conversion? */ + +#define ARCH_NOCONVERT 1 +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define ARCH_CONVERT 0 +#else +#define ARCH_CONVERT ARCH_NOCONVERT +#endif + +/* generic swapping macros */ + +#define INT_SWAP16(A) ((typeof(A))(__swab16((__u16)A))) +#define INT_SWAP32(A) ((typeof(A))(__swab32((__u32)A))) +#define INT_SWAP64(A) ((typeof(A))(__swab64((__u64)A))) + +#define INT_SWAP(type, var) \ + ((sizeof(type) == 8) ? INT_SWAP64(var) : \ + ((sizeof(type) == 4) ? INT_SWAP32(var) : \ + ((sizeof(type) == 2) ? INT_SWAP16(var) : \ + (var)))) + + +#define INT_SWAP_UNALIGNED_32(from,to) \ + { \ + ((__u8*)(to))[0] = ((__u8*)(from))[3]; \ + ((__u8*)(to))[1] = ((__u8*)(from))[2]; \ + ((__u8*)(to))[2] = ((__u8*)(from))[1]; \ + ((__u8*)(to))[3] = ((__u8*)(from))[0]; \ + } + +#define INT_SWAP_UNALIGNED_64(from,to) \ + { \ + INT_SWAP_UNALIGNED_32( ((__u8*)(from)) + 4, ((__u8*)(to))); \ + INT_SWAP_UNALIGNED_32( ((__u8*)(from)), ((__u8*)(to)) + 4); \ + } + +/* + * get and set integers from potentially unaligned locations + */ + +#define INT_GET_UNALIGNED_16_LE(pointer) \ + ((__u16)((((__u8*)(pointer))[0] ) | (((__u8*)(pointer))[1] << 8 ))) +#define INT_GET_UNALIGNED_16_BE(pointer) \ + ((__u16)((((__u8*)(pointer))[0] << 8) | (((__u8*)(pointer))[1]))) +#define INT_SET_UNALIGNED_16_LE(pointer,value) \ + { \ + ((__u8*)(pointer))[0] = (((value) ) & 0xff); \ + ((__u8*)(pointer))[1] = (((value) >> 8) & 0xff); \ + } +#define INT_SET_UNALIGNED_16_BE(pointer,value) \ + { \ + ((__u8*)(pointer))[0] = (((value) >> 8) & 0xff); \ + ((__u8*)(pointer))[1] = (((value) ) & 0xff); \ + } + +#define INT_GET_UNALIGNED_32_LE(pointer) \ + ((__u32)((((__u8*)(pointer))[0] ) | (((__u8*)(pointer))[1] << 8 ) \ + |(((__u8*)(pointer))[2] << 16) | (((__u8*)(pointer))[3] << 24))) +#define INT_GET_UNALIGNED_32_BE(pointer) \ + ((__u32)((((__u8*)(pointer))[0] << 24) | (((__u8*)(pointer))[1] << 16) \ + |(((__u8*)(pointer))[2] << 8) | (((__u8*)(pointer))[3] ))) + +#define INT_GET_UNALIGNED_64_LE(pointer) \ + (((__u64)(INT_GET_UNALIGNED_32_LE(((__u8*)(pointer))+4)) << 32 ) \ + |((__u64)(INT_GET_UNALIGNED_32_LE(((__u8*)(pointer)) )) )) +#define INT_GET_UNALIGNED_64_BE(pointer) \ + (((__u64)(INT_GET_UNALIGNED_32_BE(((__u8*)(pointer)) )) << 32 ) \ + |((__u64)(INT_GET_UNALIGNED_32_BE(((__u8*)(pointer))+4)) )) + +/* + * now pick the right ones for our MACHINE ARCHITECTURE + */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define INT_GET_UNALIGNED_16(pointer) INT_GET_UNALIGNED_16_LE(pointer) +#define INT_SET_UNALIGNED_16(pointer,value) INT_SET_UNALIGNED_16_LE(pointer,value) +#define INT_GET_UNALIGNED_32(pointer) INT_GET_UNALIGNED_32_LE(pointer) +#define INT_GET_UNALIGNED_64(pointer) INT_GET_UNALIGNED_64_LE(pointer) +#else +#define INT_GET_UNALIGNED_16(pointer) INT_GET_UNALIGNED_16_BE(pointer) +#define INT_SET_UNALIGNED_16(pointer,value) INT_SET_UNALIGNED_16_BE(pointer,value) +#define INT_GET_UNALIGNED_32(pointer) INT_GET_UNALIGNED_32_BE(pointer) +#define INT_GET_UNALIGNED_64(pointer) INT_GET_UNALIGNED_64_BE(pointer) +#endif + +/* define generic INT_ macros */ + +#define INT_GET(reference,arch) \ + (((arch) == ARCH_NOCONVERT) \ + ? \ + (reference) \ + : \ + INT_SWAP((reference),(reference)) \ + ) + +/* does not return a value */ +#define INT_SET(reference,arch,valueref) \ + (void)( \ + ((reference) = (valueref)), \ + ( \ + ((arch) != ARCH_NOCONVERT) ? \ + (reference) = INT_SWAP((reference),(reference)) \ + : 0 \ + ) \ + ) + +/* does not return a value */ +#define INT_MOD_EXPR(reference,arch,code) \ + (void)(((arch) == ARCH_NOCONVERT) \ + ? \ + ((reference) code) \ + : \ + ( \ + (reference) = INT_GET((reference),arch) , \ + ((reference) code), \ + INT_SET(reference, arch, reference) \ + ) \ + ) + +/* does not return a value */ +#define INT_MOD(reference,arch,delta) \ + (void)( \ + INT_MOD_EXPR(reference,arch,+=(delta)) \ + ) + +/* + * INT_COPY - copy a value between two locations with the + * _same architecture_ but _potentially different sizes_ + * + * if the types of the two parameters are equal or they are + * in native architecture, a simple copy is done + * + * otherwise, architecture conversions are done + * + */ + +/* does not return a value */ +#define INT_COPY(dst,src,arch) \ + (void)( \ + ((sizeof(dst) == sizeof(src)) || ((arch) == ARCH_NOCONVERT)) \ + ? \ + ((dst) = (src)) \ + : \ + INT_SET(dst, arch, INT_GET(src, arch)) \ + ) + +/* + * INT_XLATE - copy a value in either direction between two locations + * with different architectures + * + * dir < 0 - copy from memory to buffer (native to arch) + * dir > 0 - copy from buffer to memory (arch to native) + */ + +/* does not return a value */ +#define INT_XLATE(buf,mem,dir,arch) {\ + ASSERT(dir); \ + if (dir>0) { \ + (mem)=INT_GET(buf, arch); \ + } else { \ + INT_SET(buf, arch, mem); \ + } \ +} + +#define INT_ISZERO(reference,arch) \ + ((reference) == 0) + +#define INT_ZERO(reference,arch) \ + ((reference) = 0) + +#define INT_GET_UNALIGNED_16_ARCH(pointer,arch) \ + ( ((arch) == ARCH_NOCONVERT) \ + ? \ + (INT_GET_UNALIGNED_16(pointer)) \ + : \ + (INT_GET_UNALIGNED_16_BE(pointer)) \ + ) +#define INT_SET_UNALIGNED_16_ARCH(pointer,value,arch) \ + if ((arch) == ARCH_NOCONVERT) { \ + INT_SET_UNALIGNED_16(pointer,value); \ + } else { \ + INT_SET_UNALIGNED_16_BE(pointer,value); \ + } + +#endif /* __XFS_SUPPORT_ARCH_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs_support/atomic.h linux-2.4-xfs/linux/fs/xfs_support/atomic.h --- linux-2.4.7/linux/fs/xfs_support/atomic.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/atomic.h Wed Mar 14 00:04:19 2001 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_ATOMIC_H__ +#define __XFS_SUPPORT_ATOMIC_H__ + +#include +#include +#include +#include +#include + +/* + * This is used for two variables in XFS, one of which is a debug trace + * buffer index. They are not accessed via any other atomic operations + * so this is safe. All other atomic increments and decrements in XFS + * now use the linux built in functions. + */ + +extern spinlock_t Atomic_spin; + +static __inline__ int atomicIncWithWrap(int *ip, int val) +{ + unsigned long flags; + int ret; + spin_lock_irqsave(&Atomic_spin, flags); + ret = *ip; + (*ip)++; + if (*ip == val) *ip = 0; + spin_unlock_irqrestore(&Atomic_spin, flags); + return ret; +} + +#endif /* __XFS_SUPPORT_ATOMIC_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs_support/debug.c linux-2.4-xfs/linux/fs/xfs_support/debug.c --- linux-2.4.7/linux/fs/xfs_support/debug.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/debug.c Wed Mar 14 02:07:20 2001 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include + +#include +#include +#include +#include /* for EXPORT_SYMBOL */ + +/* XXX we really should be able to move this into DEBUG below */ + +int doass = 1; + +void +assfail(char *a, char *f, int l) +{ + printk("XFS assertion failed: %s, file: %s, line: %d\n", a, f, l); + BUG(); +} + +#ifdef DEBUG + +unsigned long +random(void) +{ + static unsigned long RandomValue = 1; + /* cycles pseudo-randomly through all values between 1 and 2^31 - 2 */ + register long rv = RandomValue; + register long lo; + register long hi; + + hi = rv / 127773; + lo = rv % 127773; + rv = 16807 * lo - 2836 * hi; + if( rv <= 0 ) rv += 2147483647; + return( RandomValue = rv ); +} + +int +get_thread_id(void) +{ + return current->pid; +} + +EXPORT_SYMBOL(random); +EXPORT_SYMBOL(get_thread_id); + +#endif + +void +cmn_err(register int level, char *fmt, ...) +{ + char *fp = fmt; + char message[256]; + va_list ap; + + va_start(ap, fmt); + if (*fmt == '!') fp++; + vsprintf(message, fp, ap); + switch (level) { + case CE_CONT: + case CE_DEBUG: + printk("%s", message); + break; + default: + printk("%s\n", message); + break; + } + va_end(ap); +} + + +void +icmn_err(register int level, char *fmt, va_list ap) +{ + char message[256]; + + vsprintf(message, fmt, ap); + switch (level) { + case CE_CONT: + case CE_DEBUG: + printk("%s", message); + break; + default: + printk("cmn_err level %d ", level); + printk("%s\n", message); + break; + } +} + +EXPORT_SYMBOL(icmn_err); +EXPORT_SYMBOL(cmn_err); +EXPORT_SYMBOL(doass); +EXPORT_SYMBOL(assfail); diff -rNu linux-2.4.7/linux/fs/xfs_support/debug.h linux-2.4-xfs/linux/fs/xfs_support/debug.h --- linux-2.4.7/linux/fs/xfs_support/debug.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/debug.h Wed Mar 14 00:04:19 2001 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_DEBUG_H__ +#define __XFS_SUPPORT_DEBUG_H__ + +#include + +#define CE_DEBUG 7 /* debug */ +#define CE_CONT 6 /* continuation */ +#define CE_NOTE 5 /* notice */ +#define CE_WARN 4 /* warning */ +#define CE_ALERT 1 /* alert */ +#define CE_PANIC 0 /* panic */ + +extern void icmn_err(int, char *, va_list); +extern void cmn_err(int, char *, ...); + +#if defined(DEBUG) +# ifdef lint +# define ASSERT(EX) ((void)0) /* avoid "constant in conditional" babble */ +# else +# define ASSERT(EX) ((!doass||(EX))?((void)0):assfail(#EX, __FILE__, __LINE__)) +# endif /* lint */ +#else /* !DEBUG */ +# define ASSERT(x) ((void)0) +#endif /* !DEBUG */ + +extern int doass; /* dynamically turn off asserts */ +extern void assfail(char *, char *, int); +#ifdef DEBUG /* XXX - should be able to move DEBUG up 2 lines */ +extern unsigned long random(void); +extern int get_thread_id(void); +#endif + +#define ASSERT_ALWAYS(EX) ((EX)?((void)0):assfail(#EX, __FILE__, __LINE__)) +#define debug_stop_all_cpus(param) /* param is "cpumask_t *" */ + +#endif /* __XFS_SUPPORT_DEBUG_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs_support/kmem.c linux-2.4-xfs/linux/fs/xfs_support/kmem.c --- linux-2.4.7/linux/fs/xfs_support/kmem.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/kmem.c Mon Jul 2 21:29:39 2001 @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include /* for EXPORT_SYMBOL */ +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6) +#define SLAB_NOFS SLAB_BUFFER +#define GFP_NOFS GFP_BUFFER +#endif + +static __inline__ unsigned int flag_convert(int flags) +{ + if (flags & KM_NOSLEEP) return GFP_ATOMIC; + if (flags & KM_SLEEP_IO) return GFP_KERNEL; + return GFP_NOFS; +} + +#define DEF_PRIORITY (6) + +static __inline__ void kmem_shake(int priority, int gfp_mask) +{ + /* + * Try pruning the i/dcache to free up some space ... + */ + lock_kernel(); + + shrink_dcache_memory(priority, gfp_mask); + shrink_icache_memory(priority, gfp_mask); + + unlock_kernel(); + pagebuf_daemon_wakeup(1); + delay(10); +} + +#define MAX_SLAB_SIZE 0x20000 + +/* ARGSUSED */ +void * +kmem_alloc(size_t size, int flags) +{ + int shrink = DEF_PRIORITY; /* # times to try to shrink cache */ + void *rval; + +repeat: + if (MAX_SLAB_SIZE < size) { + /* Avoid doing filesystem sensitive stuff to get this */ + rval = __vmalloc(size, flag_convert(flags), PAGE_KERNEL); + } else { + rval = kmalloc(size, flag_convert(flags)); + } + + if (rval || (flags & KM_NOSLEEP)) + return rval; + + /* + * KM_SLEEP callers don't expect a failure + */ + if (shrink) { + kmem_shake(shrink, flag_convert(flags)); + + shrink--; + goto repeat; + } + + rval = __vmalloc(size, flag_convert(flags), PAGE_KERNEL); + if (!rval && !(flags & KM_SLEEP)) + panic("kmem_alloc: NULL memory on KM_SLEEP request!"); + + return rval; +} + +/* ARGSUSED */ +void * +kmem_zalloc(size_t size, int flags) +{ + void *ptr; + + ptr = kmem_alloc(size, flags); + + if (ptr) + memset((char *)ptr, 0, (int)size); + + return (ptr); +} + +/* ARGSUSED */ +void +kmem_free(void *ptr, size_t size) +{ + if (MAX_SLAB_SIZE < size){ + vfree(ptr); + } else { + kfree(ptr); + } +} + +/* ARGSUSED */ +void * +kmem_realloc(void *ptr, size_t newsize, size_t oldsize, int flags) +{ + void *new; + + new = kmem_alloc(newsize, flags); + if (ptr) { + memcpy(new, ptr, ((oldsize < newsize) ? oldsize : newsize)); + kmem_free(ptr, oldsize); + } + + return new; +} + +kmem_zone_t * +kmem_zone_init(int size, char *zone_name) +{ + kmem_zone_t *rval = NULL; + + rval = kmem_cache_create(zone_name, size, 0, 0, NULL, NULL); + return rval; +} + +void * +kmem_zone_alloc(kmem_zone_t *zone, int flags) +{ + int shrink = DEF_PRIORITY; /* # times to try to shrink cache */ + void *ptr = NULL; + +repeat: + ptr = kmem_cache_alloc(zone, flag_convert(flags)); + + if (ptr || (flags & KM_NOSLEEP)) + return ptr; + + /* + * KM_SLEEP callers don't expect a failure + */ + if (shrink) { + kmem_shake(shrink, flag_convert(flags)); + + shrink--; + goto repeat; + } + + if (flags & KM_SLEEP) + panic("kmem_zone_alloc: NULL memory on KM_SLEEP request!"); + + return NULL; +} + +void * +kmem_zone_zalloc(kmem_zone_t *zone, int flags) +{ + int shrink = DEF_PRIORITY; /* # times to try to shrink cache */ + void *ptr = NULL; + +repeat: + ptr = kmem_cache_zalloc(zone, flag_convert(flags)); + + if (ptr || (flags & KM_NOSLEEP)) + return ptr; + + /* + * KM_SLEEP callers don't expect a failure + */ + if (shrink) { + kmem_shake(shrink, flag_convert(flags)); + + shrink--; + goto repeat; + } + + if (flags & KM_SLEEP) + panic("kmem_zone_zalloc: NULL memory on KM_SLEEP request!"); + + return NULL; +} + +void +kmem_zone_free(kmem_zone_t *zone, void *ptr) +{ + kmem_cache_free(zone, ptr); +} + +EXPORT_SYMBOL(kmem_zone_init); +EXPORT_SYMBOL(kmem_zone_zalloc); +EXPORT_SYMBOL(kmem_zone_alloc); +EXPORT_SYMBOL(kmem_zone_free); +EXPORT_SYMBOL(kmem_alloc); +EXPORT_SYMBOL(kmem_realloc); +EXPORT_SYMBOL(kmem_zalloc); +EXPORT_SYMBOL(kmem_free); diff -rNu linux-2.4.7/linux/fs/xfs_support/kmem.h linux-2.4-xfs/linux/fs/xfs_support/kmem.h --- linux-2.4.7/linux/fs/xfs_support/kmem.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/kmem.h Tue May 22 15:23:15 2001 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_KMEM_H__ +#define __XFS_SUPPORT_KMEM_H__ + +#include +#include + +/* + * memory management routines + */ +#define KM_SLEEP 0x0001 +#define KM_NOSLEEP 0x0002 /* must match VM_NOSLEEP */ +#define KM_SLEEP_IO 0x0004 /* xfs disk I/O during allocate is OK */ +#define KM_PHYSCONTIG 0x0008 +#define KM_CACHEALIGN 0x0010 /* guarantee that memory is cache aligned */ + +#define VM_NOSLEEP KM_NOSLEEP +#define VM_PHYSCONTIG KM_PHYSCONTIG +#define VM_CACHEALIGN KM_CACHEALIGN +#define VM_DIRECT KM_PHYSCONTIG +#define VM_UNCACHED 0x0020 + +typedef struct kmem_cache_s kmem_zone_t; + +extern kmem_zone_t *kmem_zone_init(int, char *); +extern void *kmem_zone_zalloc(kmem_zone_t *, int); +extern void *kmem_zone_alloc(kmem_zone_t *, int); +extern void kmem_zone_free(kmem_zone_t *, void *); + +extern void *kmem_alloc(size_t, int); +extern void *kmem_realloc(void *, size_t, size_t, int); +extern void *kmem_zalloc(size_t, int); +extern void kmem_free(void *, size_t); + +#endif /* __XFS_SUPPORT_KMEM_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs_support/ktrace.c linux-2.4-xfs/linux/fs/xfs_support/ktrace.c --- linux-2.4.7/linux/fs/xfs_support/ktrace.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/ktrace.c Wed Mar 14 02:07:20 2001 @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include /* for EXPORT_SYMBOL */ + +#include +#include +#include + +#if (defined(DEBUG) || defined(CONFIG_XFS_VNODE_TRACING)) + +static kmem_zone_t *ktrace_hdr_zone; +static kmem_zone_t *ktrace_ent_zone; +static int ktrace_zentries; + +void +ktrace_init(int zentries) +{ + ktrace_zentries = zentries; + + ktrace_hdr_zone = kmem_zone_init(sizeof(ktrace_t), + "ktrace_hdr"); + ASSERT(ktrace_hdr_zone); + + ktrace_ent_zone = kmem_zone_init(ktrace_zentries + * sizeof(ktrace_entry_t), + "ktrace_ent"); + ASSERT(ktrace_ent_zone); +} + +void +ktrace_uninit(void) +{ + kmem_cache_destroy(ktrace_hdr_zone); + kmem_cache_destroy(ktrace_ent_zone); +} + +/* + * ktrace_alloc() + * + * Allocate a ktrace header and enough buffering for the given + * number of entries. + */ +ktrace_t * +ktrace_alloc(int nentries, int sleep) +{ + ktrace_t *ktp; + ktrace_entry_t *ktep; + + ktp = (ktrace_t*)kmem_zone_alloc(ktrace_hdr_zone, sleep); + + if (ktp == (ktrace_t*)NULL) { + /* + * KM_SLEEP callers don't expect failure. + */ + if (sleep & KM_SLEEP) + panic("ktrace_alloc: NULL memory on KM_SLEEP request!"); + + return NULL; + } + + /* + * Special treatment for buffers with the ktrace_zentries entries + */ + if (nentries == ktrace_zentries) { + ktep = (ktrace_entry_t*)kmem_zone_zalloc(ktrace_ent_zone, + sleep); + } else { + ktep = (ktrace_entry_t*)kmem_zalloc((nentries * sizeof(*ktep)), + sleep); + } + + if (ktep == NULL) { + /* + * KM_SLEEP callers don't expect failure. + */ + if (sleep & KM_SLEEP) + panic("ktrace_alloc: NULL memory on KM_SLEEP request!"); + + kmem_free(ktp, sizeof(*ktp)); + + return NULL; + } + + spinlock_init(&(ktp->kt_lock), "kt_lock"); + + ktp->kt_entries = ktep; + ktp->kt_nentries = nentries; + ktp->kt_index = 0; + ktp->kt_rollover = 0; + + return ktp; +} + + +/* + * ktrace_free() + * + * Free up the ktrace header and buffer. It is up to the caller + * to ensure that no-one is referencing it. + */ +void +ktrace_free(ktrace_t *ktp) +{ + int entries_size; + + if (ktp == (ktrace_t *)NULL) + return; + + spinlock_destroy(&ktp->kt_lock); + + /* + * Special treatment for the Vnode trace buffer. + */ + if (ktp->kt_nentries == ktrace_zentries) { + kmem_zone_free(ktrace_ent_zone, ktp->kt_entries); + } else { + entries_size = (int)(ktp->kt_nentries * sizeof(ktrace_entry_t)); + + kmem_free(ktp->kt_entries, entries_size); + } + + kmem_zone_free(ktrace_hdr_zone, ktp); +} + + +/* + * Enter the given values into the "next" entry in the trace buffer. + * kt_index is always the index of the next entry to be filled. + */ +void +ktrace_enter( + ktrace_t *ktp, + void *val0, + void *val1, + void *val2, + void *val3, + void *val4, + void *val5, + void *val6, + void *val7, + void *val8, + void *val9, + void *val10, + void *val11, + void *val12, + void *val13, + void *val14, + void *val15) +{ + int index; + ktrace_entry_t *ktep; + + ASSERT(ktp != NULL); + + /* + * Grab an entry by pushing the index up to the next one. + */ + index = atomicIncWithWrap(&ktp->kt_index, ktp->kt_nentries); + + if (!ktp->kt_rollover && index == ktp->kt_nentries - 1) + ktp->kt_rollover = 1; + + ASSERT((index >= 0) && (index < ktp->kt_nentries)); + + ktep = &(ktp->kt_entries[index]); + + ktep->val[0] = val0; + ktep->val[1] = val1; + ktep->val[2] = val2; + ktep->val[3] = val3; + ktep->val[4] = val4; + ktep->val[5] = val5; + ktep->val[6] = val6; + ktep->val[7] = val7; + ktep->val[8] = val8; + ktep->val[9] = val9; + ktep->val[10] = val10; + ktep->val[11] = val11; + ktep->val[12] = val12; + ktep->val[13] = val13; + ktep->val[14] = val14; + ktep->val[15] = val15; +} + +/* + * Return the number of entries in the trace buffer. + */ +int +ktrace_nentries( + ktrace_t *ktp) +{ + if (ktp == NULL) { + return 0; + } + + return (ktp->kt_rollover ? ktp->kt_nentries : ktp->kt_index); +} + + +/* + * ktrace_first() + * + * This is used to find the start of the trace buffer. + * In conjunction with ktrace_next() it can be used to + * iterate through the entire trace buffer. This code does + * not do any locking because it is assumed that it is called + * from the debugger. + * + * The caller must pass in a pointer to a ktrace_snap + * structure in which we will keep some state used to + * iterate through the buffer. This state must not touched + * by any code outside of this module. + */ +ktrace_entry_t * +ktrace_first(ktrace_t *ktp, ktrace_snap_t *ktsp) +{ + ktrace_entry_t *ktep; + int index; + int nentries; + + if (ktp->kt_rollover) + index = ktp->kt_index; + else + index = 0; + + ktsp->ks_start = index; + ktep = &(ktp->kt_entries[index]); + + nentries = ktrace_nentries(ktp); + index++; + if (index < nentries) { + ktsp->ks_index = index; + } else { + ktsp->ks_index = 0; + if (index > nentries) + ktep = NULL; + } + return ktep; +} + + +/* + * ktrace_next() + * + * This is used to iterate through the entries of the given + * trace buffer. The caller must pass in the ktrace_snap_t + * structure initialized by ktrace_first(). The return value + * will be either a pointer to the next ktrace_entry or NULL + * if all of the entries have been traversed. + */ +ktrace_entry_t * +ktrace_next( + ktrace_t *ktp, + ktrace_snap_t *ktsp) +{ + int index; + ktrace_entry_t *ktep; + + index = ktsp->ks_index; + if (index == ktsp->ks_start) { + ktep = NULL; + } else { + ktep = &ktp->kt_entries[index]; + } + + index++; + if (index == ktrace_nentries(ktp)) { + ktsp->ks_index = 0; + } else { + ktsp->ks_index = index; + } + + return ktep; +} + +/* + * ktrace_skip() + * + * Skip the next "count" entries and return the entry after that. + * Return NULL if this causes us to iterate past the beginning again. + */ + +ktrace_entry_t * +ktrace_skip( + ktrace_t *ktp, + int count, + ktrace_snap_t *ktsp) +{ + int index; + int new_index; + ktrace_entry_t *ktep; + int nentries = ktrace_nentries(ktp); + + index = ktsp->ks_index; + new_index = index + count; + while (new_index >= nentries) { + new_index -= nentries; + } + if (index == ktsp->ks_start) { + /* + * We've iterated around to the start, so we're done. + */ + ktep = NULL; + } else if ((new_index < index) && (index < ktsp->ks_index)) { + /* + * We've skipped past the start again, so we're done. + */ + ktep = NULL; + ktsp->ks_index = ktsp->ks_start; + } else { + ktep = &(ktp->kt_entries[new_index]); + new_index++; + if (new_index == nentries) { + ktsp->ks_index = 0; + } else { + ktsp->ks_index = new_index; + } + } + return ktep; +} + +EXPORT_SYMBOL(ktrace_init); +EXPORT_SYMBOL(ktrace_uninit); +EXPORT_SYMBOL(ktrace_enter); +EXPORT_SYMBOL(ktrace_free); +EXPORT_SYMBOL(ktrace_nentries); +EXPORT_SYMBOL(ktrace_first); +EXPORT_SYMBOL(ktrace_next); +EXPORT_SYMBOL(ktrace_skip); + +#else /* ! (defined(DEBUG) || defined(CONFIG_XFS_VNODE_TRACING)) */ + +ktrace_t * +ktrace_alloc(int nentries, int sleep) +{ + /* + * KM_SLEEP callers don't expect failure. + */ + if (sleep & KM_SLEEP) + panic("ktrace_alloc: NULL memory on KM_SLEEP request!"); + + return NULL; +} +#endif /* ! (defined(DEBUG) || defined(CONFIG_XFS_VNODE_TRACING)) */ + +EXPORT_SYMBOL(ktrace_alloc); diff -rNu linux-2.4.7/linux/fs/xfs_support/ktrace.h linux-2.4-xfs/linux/fs/xfs_support/ktrace.h --- linux-2.4.7/linux/fs/xfs_support/ktrace.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/ktrace.h Wed Mar 14 02:07:20 2001 @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_KTRACE_H__ +#define __XFS_SUPPORT_KTRACE_H__ + +#include + +/* + * Trace buffer entry structure. + */ +typedef struct ktrace_entry { + void *val[16]; +} ktrace_entry_t; + +/* + * Trace buffer header structure. + */ +typedef struct ktrace { + lock_t kt_lock; /* mutex to guard counters */ + int kt_nentries; /* number of entries in trace buf */ + int kt_index; /* current index in entries */ + int kt_rollover; + ktrace_entry_t *kt_entries; /* buffer of entries */ +} ktrace_t; + +/* + * Trace buffer snapshot structure. + */ +typedef struct ktrace_snap { + int ks_start; /* kt_index at time of snap */ + int ks_index; /* current index */ +} ktrace_snap_t; + +/* + * Exported interfaces. + */ +extern ktrace_t *ktrace_alloc(int, int); + +#if (defined(DEBUG) || defined(CONFIG_XFS_VNODE_TRACING)) + +extern void ktrace_init(int zentries); +extern void ktrace_uninit(void); + +extern void ktrace_free(ktrace_t *); + +extern void ktrace_enter( + ktrace_t *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *, + void *); + +extern ktrace_entry_t *ktrace_first(ktrace_t *, ktrace_snap_t *); +extern int ktrace_nentries(ktrace_t *); +extern ktrace_entry_t *ktrace_next(ktrace_t *, ktrace_snap_t *); +extern ktrace_entry_t *ktrace_skip(ktrace_t *, int, ktrace_snap_t *); + +#else /* ! (defined(DEBUG) || defined(CONFIG_XFS_VNODE_TRACING)) */ + +#define ktrace_free(ktp) +#define ktrace_enter(ktp,v0,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v15) + +#endif /* ! (defined(DEBUG) || defined(CONFIG_XFS_VNODE_TRACING)) */ + +#endif /* __XFS_SUPPORT_KTRACE_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs_support/move.c linux-2.4-xfs/linux/fs/xfs_support/move.c --- linux-2.4.7/linux/fs/xfs_support/move.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/move.c Wed Mar 14 02:07:20 2001 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include + +#include /* for EXPORT_SYMBOL */ +#include + +/* + * Move "n" bytes at byte address "cp"; "rw" indicates the direction + * of the move, and the I/O parameters are provided in "uio", which is + * update to reflect the data which was moved. Returns 0 on success or + * a non-zero errno on failure. + */ +int +uiomove(void *cp, size_t n, enum uio_rw rw, struct uio *uio) +{ + register struct iovec *iov; + u_int cnt; + int error; + + while (n > 0 && uio->uio_resid) { + iov = uio->uio_iov; + cnt = (u_int)iov->iov_len; + if (cnt == 0) { + uio->uio_iov++; + uio->uio_iovcnt--; + continue; + } + if (cnt > n) + cnt = (u_int)n; + switch (uio->uio_segflg) { + + case UIO_USERSPACE: + if (rw == UIO_READ) + error = copyout(cp, iov->iov_base, cnt); + else + error = copyin(iov->iov_base, cp, cnt); + if (error) + return EFAULT; + break; + + case UIO_USERISPACE: + ASSERT(0); + break; + + case UIO_SYSSPACE: + if (rw == UIO_READ) + bcopy(cp, iov->iov_base, cnt); + else + bcopy(iov->iov_base, cp, cnt); + break; + } + iov->iov_base = (void *)((char *)iov->iov_base + cnt); + iov->iov_len -= cnt; + uio->uio_resid -= cnt; + uio->uio_offset += cnt; + cp = (void *)((char *)cp + cnt); + n -= cnt; + } + return 0; +} + +EXPORT_SYMBOL(uiomove); diff -rNu linux-2.4.7/linux/fs/xfs_support/move.h linux-2.4-xfs/linux/fs/xfs_support/move.h --- linux-2.4.7/linux/fs/xfs_support/move.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/move.h Thu Mar 15 17:33:20 2001 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef __XFS_SUPPORT_MOVE_H__ +#define __XFS_SUPPORT_MOVE_H__ + +#include +#include +#include + +#define bzero(p,s) memset((p), 0, (s)) +#define bcopy(s,d,n) memcpy((d),(s),(n)) +#define bcmp(s1,s2,l) memcmp(s1,s2,l) +#define ovbcopy(from,to,count) memmove(to,from,count) + +typedef struct iovec iovec_t; + +typedef struct uio { + iovec_t *uio_iov; /* pointer to array of iovecs */ + int uio_iovcnt; /* number of iovecs */ + int uio_fmode; /* file mode flags */ + xfs_off_t uio_offset; /* file offset */ + short uio_segflg; /* address space (kernel or user) */ + ssize_t uio_resid; /* residual count */ + + struct file * uio_fp; /* file associated with io */ +} uio_t; + +/* + * I/O direction. + */ +typedef enum uio_rw { UIO_READ, UIO_WRITE } uio_rw_t; + +/* + * Segment flag values. + */ +typedef enum uio_seg { + UIO_NOSPACE = -1, /* no data movement (used for pagein) */ + UIO_USERSPACE, /* uio_iov describes user space */ + UIO_SYSSPACE, /* uio_iov describes system space */ + UIO_USERISPACE /* uio_iov describes instruction space */ +} uio_seg_t; + + +extern int uiomove (void *, size_t, uio_rw_t, uio_t *); + +/* + * map these directly... trying to use a #define causes + * many strange side affects + */ +/* + * copyin/copyout on irix return 0 on success, -1 on failure + */ +static __inline__ int +copyout( void* from, void* to, int size ) +{ + return copy_to_user(to, from, size ) ? -1 : 0; +} + +static __inline__ int +copyin( void* from, void* to, int size ) +{ + return copy_from_user(to, from, size ) ? -1 : 0; +} + +#endif /* __XFS_SUPPORT_MOVE_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs_support/mrlock.c linux-2.4-xfs/linux/fs/xfs_support/mrlock.c --- linux-2.4.7/linux/fs/xfs_support/mrlock.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/mrlock.c Wed Mar 14 02:07:20 2001 @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include /* for EXPORT_SYMBOL */ + +#include + +spinlock_t Atomic_spin = SPIN_LOCK_UNLOCKED; + + +#if USE_RW_WAIT_QUEUE_SPINLOCK +# define wq_write_lock write_lock +#else +# define wq_write_lock spin_lock +#endif + +/* + * We don't seem to need lock_type (only one supported), name, or + * sequence. But, XFS will pass it so let's leave them here for now. + */ +/* ARGSUSED */ +void +mrlock_init(mrlock_t *mrp, int lock_type, char *name, long sequence) +{ + mrp->mr_count = 0; + mrp->mr_reads_waiting = 0; + mrp->mr_writes_waiting = 0; + mrp->owner = NULL; + init_waitqueue_head(&mrp->mr_readerq); + init_waitqueue_head(&mrp->mr_writerq); + mrp->mr_lock = SPIN_LOCK_UNLOCKED; +} + +/* + * Macros to lock/unlock the mrlock_t. + */ + +#define MRLOCK_INT(m, s) spin_lock_irqsave(&(m)->mr_lock, s); +#define MRUNLOCK_INT(m, s) spin_unlock_irqrestore(&(m)->mr_lock, s); +#define MRLOCK(m) spin_lock_irq(&(m)->mr_lock); +#define MRUNLOCK(m) spin_unlock_irq(&(m)->mr_lock); + + +/* + * lock_wait should never be called in an interrupt thread. + * + * mrlocks can sleep (i.e. call schedule) and so they can't ever + * be called from an interrupt thread. + * + * threads that wake-up should also never be invoked from interrupt threads. + * + * But, waitqueue_lock is locked from interrupt threads - and we are + * called with interrupts disabled, so it is all OK. + */ + +/* ARGSUSED */ +void +lock_wait(wait_queue_head_t *q, spinlock_t *lock, int rw) +{ + DECLARE_WAITQUEUE( wait, current ); + + set_current_state(TASK_UNINTERRUPTIBLE); + + wq_write_lock(&q->lock); + if (rw) { + __add_wait_queue_tail(q, &wait); + } else { + __add_wait_queue(q, &wait); + } + + wq_write_unlock(&q->lock); + spin_unlock_irq(lock); /* Interrupts reenabled */ + + schedule(); + + set_current_state(TASK_RUNNING); + + wq_write_lock_irq(&q->lock); + __remove_wait_queue(q, &wait); + wq_write_unlock(&q->lock); + + spin_lock(lock); + + /* return with interrupts off and lock held */ +} + +/* ARGSUSED */ +void +mrfree(mrlock_t *mrp) +{ +} + +/* ARGSUSED */ +void +mrlock(mrlock_t *mrp, int type, int flags) +{ + if (type == MR_ACCESS) + mraccess(mrp); + else + mrupdate(mrp); +} + +/* ARGSUSED */ +void +mraccessf(mrlock_t *mrp, int flags) +{ + MRLOCK(mrp); + if(mrp->mr_writes_waiting > 0) { + mrp->mr_reads_waiting++; + lock_wait(&mrp->mr_readerq, &mrp->mr_lock, 0); + mrp->mr_reads_waiting--; + } + while (mrp->mr_count < 0) { + mrp->mr_reads_waiting++; + lock_wait(&mrp->mr_readerq, &mrp->mr_lock, 0); + mrp->mr_reads_waiting--; + } + mrp->mr_count++; + MRUNLOCK(mrp); +} + +/* ARGSUSED */ +void +mrupdatef(mrlock_t *mrp, int flags) +{ + MRLOCK(mrp); + while(mrp->mr_count) { + mrp->mr_writes_waiting++; + lock_wait(&mrp->mr_writerq, &mrp->mr_lock, 1); + mrp->mr_writes_waiting--; + } + + mrp->mr_count = -1; /* writer on it */ + mrp->owner = current; + MRUNLOCK(mrp); +} + +int +mrtryaccess(mrlock_t *mrp) +{ + long s; + + MRLOCK_INT(mrp, s); + /* + * If anyone is waiting for update access or the lock is held for update + * fail the request. + */ + if(mrp->mr_writes_waiting > 0 || mrp->mr_count < 0) { + MRUNLOCK_INT(mrp, s); + return 0; + } + mrp->mr_count++; + MRUNLOCK_INT(mrp, s); + return 1; +} + +int +mrtrypromote(mrlock_t *mrp) +{ + long s; + + MRLOCK_INT(mrp, s); + + if(mrp->mr_count == 1) { /* We are the only thread with the lock */ + mrp->mr_count = -1; /* writer on it */ + mrp->owner = current; + MRUNLOCK_INT(mrp, s); + return 1; + } + + MRUNLOCK_INT(mrp, s); + return 0; +} + +int +mrtryupdate(mrlock_t *mrp) +{ + long s; + + MRLOCK_INT(mrp, s); + + if(mrp->mr_count) { + MRUNLOCK_INT(mrp, s); + return 0; + } + + mrp->owner = current; + mrp->mr_count = -1; /* writer on it */ + MRUNLOCK_INT(mrp, s); + return 1; +} + +static __inline__ void mrwake(mrlock_t *mrp) +{ + /* + * First, if the count is now 0, we need to wake-up anyone waiting. + */ + if (!mrp->mr_count) { + if (mrp->mr_writes_waiting) { /* Wake-up first writer waiting */ + wake_up(&mrp->mr_writerq); + } else if (mrp->mr_reads_waiting) { /* Wakeup any readers waiting */ + wake_up(&mrp->mr_readerq); + } + } +} + +void +mraccunlock(mrlock_t *mrp) +{ + long s; + + MRLOCK_INT(mrp, s); + mrp->mr_count--; + mrwake(mrp); + MRUNLOCK_INT(mrp, s); +} + +void +mrunlock(mrlock_t *mrp) +{ + long s; + + MRLOCK_INT(mrp, s); + if (mrp->mr_count < 0) { + mrp->mr_count = 0; + mrp->owner = NULL; + } else { + mrp->mr_count--; + } + mrwake(mrp); + MRUNLOCK_INT(mrp, s); +} + +int +ismrlocked(mrlock_t *mrp, int type) /* No need to lock since info can change */ +{ + if (type == MR_ACCESS) + return (mrp->mr_count > 0); /* Read lock */ + else if (type == MR_UPDATE) + return (mrp->mr_count < 0); /* Write lock */ + else if (type == (MR_UPDATE | MR_ACCESS)) + return (mrp->mr_count); /* Any type of lock held */ + else /* Any waiters */ + return (mrp->mr_reads_waiting | mrp->mr_writes_waiting); +} + +/* + * Demote from update to access. We better be the only thread with the + * lock in update mode so it should be easy to set to 1. + * Wake-up any readers waiting. + */ + +void +mrdemote(mrlock_t *mrp) +{ + MRLOCK(mrp); + mrp->mr_count = 1; + mrp->owner = NULL; + if (mrp->mr_reads_waiting) { /* Wakeup all readers waiting */ + wake_up(&mrp->mr_readerq); + } + MRUNLOCK(mrp); +} + +int +mrislocked_access(mrlock_t *mrp) +{ + return(mrp->mr_count > 0); +} + +int +mrislocked_update(mrlock_t *mrp) +{ + return(mrp->mr_count < 0); +} + +EXPORT_SYMBOL(mraccessf); +EXPORT_SYMBOL(mrupdatef); +EXPORT_SYMBOL(mrlock); +EXPORT_SYMBOL(mrunlock); +EXPORT_SYMBOL(mraccunlock); +EXPORT_SYMBOL(mrtryupdate); +EXPORT_SYMBOL(mrtryaccess); +EXPORT_SYMBOL(mrtrypromote); +EXPORT_SYMBOL(mrdemote); +EXPORT_SYMBOL(ismrlocked); +EXPORT_SYMBOL(mrlock_init); +EXPORT_SYMBOL(mrfree); +EXPORT_SYMBOL(Atomic_spin); diff -rNu linux-2.4.7/linux/fs/xfs_support/mrlock.h linux-2.4-xfs/linux/fs/xfs_support/mrlock.h --- linux-2.4.7/linux/fs/xfs_support/mrlock.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/mrlock.h Wed Mar 14 00:04:19 2001 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_MRLOCK_H__ +#define __XFS_SUPPORT_MRLOCK_H__ + +#include +#include +#include +#include +#include + +/* + * Implement mrlocks on Linux that work for XFS. + * + * These are sleep locks and not spinlocks. If one wants read/write spinlocks, + * use read_lock, write_lock, ... see spinlock.h. + */ + +typedef struct mrlock_s { + int mr_count; + uint mr_reads_waiting; + uint mr_writes_waiting; + void *owner; + wait_queue_head_t mr_readerq; + wait_queue_head_t mr_writerq; + spinlock_t mr_lock; +} mrlock_t; + +#define MR_ACCESS 1 +#define MR_UPDATE 2 + +#define MRLOCK_BARRIER 0x1 +#define MRLOCK_ALLOW_EQUAL_PRI 0x8 + +/* + * mraccessf/mrupdatef take flags to be passed in while sleeping; + * only PLTWAIT is currently supported. + */ + +extern void mraccessf(mrlock_t *, int); +extern void mrupdatef(mrlock_t *, int); +extern void mrlock(mrlock_t *, int, int); +extern void mrunlock(mrlock_t *); +extern void mraccunlock(mrlock_t *); +extern int mrtryupdate(mrlock_t *); +extern int mrtryaccess(mrlock_t *); +extern int mrtrypromote(mrlock_t *); +extern void mrdemote(mrlock_t *); + +extern int ismrlocked(mrlock_t *, int); +extern void mrlock_init(mrlock_t *, int type, char *name, long sequence); +extern void mrfree(mrlock_t *); + +#define mrinit(mrp, name) mrlock_init(mrp, MRLOCK_BARRIER, name, -1) +#define mraccess(mrp) mraccessf(mrp, 0) /* grab for READ/ACCESS */ +#define mrupdate(mrp) mrupdatef(mrp, 0) /* grab for WRITE/UPDATE */ + +#endif /* __XFS_SUPPORT_MRLOCK_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs_support/mutex.c linux-2.4-xfs/linux/fs/xfs_support/mutex.c --- linux-2.4.7/linux/fs/xfs_support/mutex.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/mutex.c Wed Mar 14 02:07:20 2001 @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include /* for EXPORT_SYMBOL */ + +#include + +/* Mutex locks ------------------------------------------------------ */ + + +void _mutex_init( mutex_t *mutex) +{ + mutex->state = 1; + sema_init( &mutex->sema, 1 ); +} + +void _mutex_destroy( mutex_t *mutex) +{ + mutex->state = 0xdead; + sema_init( &mutex->sema, -99); /* Anyone using it again will block */ +} + +void _mutex_lock( mutex_t *mutex) +{ + mutex->state--; + down( &mutex->sema ); +} + +void _mutex_unlock( mutex_t *mutex) +{ + mutex->state++; + up( &mutex->sema ); +} + +int _mutex_trylock( mutex_t *mutex) +{ + int ret; + + ret = down_trylock( &mutex->sema ); + if (ret == 0) { + mutex->state--; + } + return (ret==0) ? 1 : 0; +} + +EXPORT_SYMBOL(_mutex_init); +EXPORT_SYMBOL(_mutex_lock); +EXPORT_SYMBOL(_mutex_unlock); +EXPORT_SYMBOL(_mutex_trylock); +EXPORT_SYMBOL(_mutex_destroy); diff -rNu linux-2.4.7/linux/fs/xfs_support/mutex.h linux-2.4-xfs/linux/fs/xfs_support/mutex.h --- linux-2.4.7/linux/fs/xfs_support/mutex.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/mutex.h Wed Mar 14 00:04:19 2001 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_MUTEX_H__ +#define __XFS_SUPPORT_MUTEX_H__ + +#include +#include +#include +#include +#include + +/* + * Map the mutex'es from IRIX to Linux semaphores. + * + * Destroy just simply initializes to -99 which should block all other + * callers. + */ + +typedef struct mutex_s { + struct semaphore sema; + int state; +} mutex_t; + + +#define init_mutex(ptr, type, name, sequence) mutex_init(ptr, type, name) + +void _mutex_init( mutex_t *mutex); +void _mutex_lock( mutex_t *mutex); +void _mutex_unlock( mutex_t *mutex); +int _mutex_trylock( mutex_t *mutex); +void _mutex_destroy( mutex_t *mutex); + +#define mutex_init(lock, type, name) _mutex_init(lock) +#define mutex_lock(lock, num) _mutex_lock(lock) +#define mutex_trylock(lock) _mutex_trylock(lock) +#define mutex_unlock(lock) _mutex_unlock(lock) +#define mutex_destroy(lock) _mutex_destroy(lock) + +/* + * mp_mutex_spinlock is used in xfs_rw.c during an interrupt thread so it + * must be irq safe. This happens when a write finishes and we queue + * a request to xfsc to update the unwritten extent flag. + * There may be other places. + * + * mutex_spinlock is also called extensively by interrupt threads. + * + * spin_lock_irqsave needs a long. + * mutex_spinlock and mp_mutex_spinlock use ints. On i386 this should be OK. + * since an int and long are both 4 bytes. Other architectures may be a problem. + * We don't want to change all the code that interfaces with mutex_spinlock and + * mp_mutex_spinlock to pass longs, but .... + */ + +static __inline__ int mutex_spinlock(spinlock_t *l) +{ + long flags; + spin_lock_irqsave(l, flags); + return(flags); +} + +#define mutex_spinunlock(lockp,flags) spin_unlock_irqrestore(lockp, flags) + +#define mp_mutex_spinlock(lockp) mutex_spinlock(lockp) +#define mp_mutex_spinunlock(lockp,flags) spin_unlock_irqrestore(lockp, flags) + + +/* + * Types for mutex_init(), mutex_alloc() + */ +#define MUTEX_DEFAULT 0x0 + +/* + * void mutex_init(mutex_t *mp, int type, char *name); + * void init_mutex(mutex_t *mp, int type, char *name, long sequence); + * + * Name may be null -- it is only used when metering mutexes are installed, + * tag the metering structure with an ascii name. + * Only METER_NAMSZ-1 characters are recorded. + * + * If init_mutex interface is used to initialize, metering name is + * constructed from 'name' prefix and and ascii suffix generated from + * the 'sequence' argument: [ "MyLock", 12 ] becomes "MyLock00012" + */ + + +#endif /* __XFS_SUPPORT_MUTEX_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs_support/qsort.c linux-2.4-xfs/linux/fs/xfs_support/qsort.c --- linux-2.4.7/linux/fs/xfs_support/qsort.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/qsort.c Wed Mar 14 00:04:19 2001 @@ -0,0 +1,247 @@ +/* Copyright (C) 1991, 1992, 1996, 1997 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Written by Douglas C. Schmidt (schmidt@ics.uci.edu). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include /* for EXPORT_SYMBOL */ +#include + + +/* Byte-wise swap two items of size SIZE. */ +#define SWAP(a, b, size) \ + do \ + { \ + register size_t __size = (size); \ + register char *__a = (a), *__b = (b); \ + do \ + { \ + char __tmp = *__a; \ + *__a++ = *__b; \ + *__b++ = __tmp; \ + } while (--__size > 0); \ + } while (0) + +/* Discontinue quicksort algorithm when partition gets below this size. + This particular magic number was chosen to work best on a Sun 4/260. */ +#define MAX_THRESH 4 + +/* Stack node declarations used to store unfulfilled partition obligations. */ +typedef struct + { + char *lo; + char *hi; + } stack_node; + +/* The next 4 #defines implement a very fast in-line stack abstraction. */ +#define STACK_SIZE (8 * sizeof(unsigned long int)) +#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top)) +#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi))) +#define STACK_NOT_EMPTY (stack < top) + + +/* Order size using quicksort. This implementation incorporates + four optimizations discussed in Sedgewick: + + 1. Non-recursive, using an explicit stack of pointer that store the + next array partition to sort. To save time, this maximum amount + of space required to store an array of MAX_INT is allocated on the + stack. Assuming a 32-bit integer, this needs only 32 * + sizeof(stack_node) == 136 bits. Pretty cheap, actually. + + 2. Chose the pivot element using a median-of-three decision tree. + This reduces the probability of selecting a bad pivot value and + eliminates certain extraneous comparisons. + + 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving + insertion sort to order the MAX_THRESH items within each partition. + This is a big win, since insertion sort is faster for small, mostly + sorted array segments. + + 4. The larger of the two sub-partitions is always pushed onto the + stack first, with the algorithm then concentrating on the + smaller partition. This *guarantees* no more than log (n) + stack size is needed (actually O(1) in this case)! */ + +void +qsort ( + void *const pbase, + size_t total_elems, + size_t size, + int (*cmp)(const void *, const void *)) +{ + register char *base_ptr = (char *) pbase; + + /* Allocating SIZE bytes for a pivot buffer facilitates a better + algorithm below since we can do comparisons directly on the pivot. */ + char *pivot_buffer = (char *) kmalloc (size, GFP_KERNEL); + const size_t max_thresh = MAX_THRESH * size; + + if (total_elems == 0) + /* Avoid lossage with unsigned arithmetic below. */ + return; + + if (total_elems > MAX_THRESH) + { + char *lo = base_ptr; + char *hi = &lo[size * (total_elems - 1)]; + /* Largest size needed for 32-bit int!!! */ + stack_node stack[STACK_SIZE]; + stack_node *top = stack + 1; + + while (STACK_NOT_EMPTY) + { + char *left_ptr; + char *right_ptr; + + char *pivot = pivot_buffer; + + /* Select median value from among LO, MID, and HI. Rearrange + LO and HI so the three values are sorted. This lowers the + probability of picking a pathological pivot value and + skips a comparison for both the LEFT_PTR and RIGHT_PTR. */ + + char *mid = lo + size * ((hi - lo) / size >> 1); + + if ((*cmp) ((void *) mid, (void *) lo) < 0) + SWAP (mid, lo, size); + if ((*cmp) ((void *) hi, (void *) mid) < 0) + SWAP (mid, hi, size); + else + goto jump_over; + if ((*cmp) ((void *) mid, (void *) lo) < 0) + SWAP (mid, lo, size); + jump_over:; + memcpy (pivot, mid, size); + pivot = pivot_buffer; + + left_ptr = lo + size; + right_ptr = hi - size; + + /* Here's the famous ``collapse the walls'' section of quicksort. + Gotta like those tight inner loops! They are the main reason + that this algorithm runs much faster than others. */ + do + { + while ((*cmp) ((void *) left_ptr, (void *) pivot) < 0) + left_ptr += size; + + while ((*cmp) ((void *) pivot, (void *) right_ptr) < 0) + right_ptr -= size; + + if (left_ptr < right_ptr) + { + SWAP (left_ptr, right_ptr, size); + left_ptr += size; + right_ptr -= size; + } + else if (left_ptr == right_ptr) + { + left_ptr += size; + right_ptr -= size; + break; + } + } + while (left_ptr <= right_ptr); + + /* Set up pointers for next iteration. First determine whether + left and right partitions are below the threshold size. If so, + ignore one or both. Otherwise, push the larger partition's + bounds on the stack and continue sorting the smaller one. */ + + if ((size_t) (right_ptr - lo) <= max_thresh) + { + if ((size_t) (hi - left_ptr) <= max_thresh) + /* Ignore both small partitions. */ + POP (lo, hi); + else + /* Ignore small left partition. */ + lo = left_ptr; + } + else if ((size_t) (hi - left_ptr) <= max_thresh) + /* Ignore small right partition. */ + hi = right_ptr; + else if ((right_ptr - lo) > (hi - left_ptr)) + { + /* Push larger left partition indices. */ + PUSH (lo, right_ptr); + lo = left_ptr; + } + else + { + /* Push larger right partition indices. */ + PUSH (left_ptr, hi); + hi = right_ptr; + } + } + } + + /* Once the BASE_PTR array is partially sorted by quicksort the rest + is completely sorted using insertion sort, since this is efficient + for partitions below MAX_THRESH size. BASE_PTR points to the beginning + of the array to sort, and END_PTR points at the very last element in + the array (*not* one beyond it!). */ + +#define min(x, y) ((x) < (y) ? (x) : (y)) + + { + char *const end_ptr = &base_ptr[size * (total_elems - 1)]; + char *tmp_ptr = base_ptr; + char *thresh = min(end_ptr, base_ptr + max_thresh); + register char *run_ptr; + + /* Find smallest element in first threshold and place it at the + array's beginning. This is the smallest array element, + and the operation speeds up insertion sort's inner loop. */ + + for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size) + if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr) < 0) + tmp_ptr = run_ptr; + + if (tmp_ptr != base_ptr) + SWAP (tmp_ptr, base_ptr, size); + + /* Insertion sort, running from left-hand-side up to right-hand-side. */ + + run_ptr = base_ptr + size; + while ((run_ptr += size) <= end_ptr) + { + tmp_ptr = run_ptr - size; + while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr) < 0) + tmp_ptr -= size; + + tmp_ptr += size; + if (tmp_ptr != run_ptr) + { + char *trav; + + trav = run_ptr + size; + while (--trav >= run_ptr) + { + char c = *trav; + char *hi, *lo; + + for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo) + *hi = *lo; + *hi = c; + } + } + } + } + kfree(pivot_buffer); +} + +EXPORT_SYMBOL(qsort); diff -rNu linux-2.4.7/linux/fs/xfs_support/qsort.h linux-2.4-xfs/linux/fs/xfs_support/qsort.h --- linux-2.4.7/linux/fs/xfs_support/qsort.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/qsort.h Wed Mar 14 00:04:19 2001 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef QSORT_H +#define QSORT_H + +extern void qsort (void *const pbase, + size_t total_elems, + size_t size, + int (*cmp)(const void *, const void *)); + +#endif diff -rNu linux-2.4.7/linux/fs/xfs_support/sema.h linux-2.4-xfs/linux/fs/xfs_support/sema.h --- linux-2.4.7/linux/fs/xfs_support/sema.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/sema.h Wed Mar 14 00:04:19 2001 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_SEMA_H__ +#define __XFS_SUPPORT_SEMA_H__ + +#include +#include +#include +#include +#include + +/* + * sema_t structure just maps to struct semaphore in Linux kernel. + */ + +typedef struct semaphore sema_t; + +#define init_sema(sp, val, c, d) sema_init(sp, val) +#define initsema(sp, val) sema_init(sp, val) +#define initnsema(sp, val, name) sema_init(sp, val) +#define psema(sp, b) down(sp) +#define vsema(sp) up(sp) +#define valusema(sp) (atomic_read(&(sp)->count)) +#define freesema(sema) + +/* + * Map cpsema (try to get the sema) to down_trylock. We need to switch + * the return values since cpsema returns 1 (acquired) 0 (failed) and + * down_trylock returns the reverse 0 (acquired) 1 (failed). + */ + +#define cpsema(sp) (down_trylock(sp) ? 0 : 1) + +/* + * Didn't do cvsema(sp). Not sure how to map this to up/down/... + * It does a vsema if the values is < 0 other wise nothing. + */ + +#endif /* __XFS_SUPPORT_SEMA_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs_support/spin.h linux-2.4-xfs/linux/fs/xfs_support/spin.h --- linux-2.4.7/linux/fs/xfs_support/spin.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/spin.h Wed Mar 14 00:04:19 2001 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_SPIN_H__ +#define __XFS_SUPPORT_SPIN_H__ + +#include +#include +#include +#include +#include +#include + +/* + * Map the spinlocks from IRIX to Linux. + * For now, make them all as if they were used in interrupt thread (irq safe). + */ +#define spinlock_init(lock, name) spin_lock_init(lock) +#define init_spinlock(lock, name, ll) spin_lock_init(lock) +#define spinlock_destroy(lock) + +/* + * Map lock_t from IRIX to Linux spinlocks. + * + * Note that linux turns on/off spinlocks depending on CONFIG_SMP. + * We don't need to worry about SMP or not here. + * + * The irq safe calls get mapped from spinlocks and IRQ safe calls + * to just spls. + */ + +typedef spinlock_t lock_t; + +#define nested_spinunlock(a) spin_unlock(a) +#define nested_spinlock(a) spin_lock(a) +#define nested_spintrylock(a) spin_trylock(a) + +#endif /* __XFS_SUPPORT_SPIN_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs_support/support.c linux-2.4-xfs/linux/fs/xfs_support/support.c --- linux-2.4.7/linux/fs/xfs_support/support.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/support.c Wed May 16 22:10:40 2001 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("SGI "); +MODULE_DESCRIPTION("Support library for XFS"); + +#ifdef MODULE +int init_module(void) +{ + return 0; +} + +void cleanup_module(void) +{ +} + + +#endif diff -rNu linux-2.4.7/linux/fs/xfs_support/support.h linux-2.4-xfs/linux/fs/xfs_support/support.h --- linux-2.4.7/linux/fs/xfs_support/support.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/support.h Wed Mar 14 02:07:20 2001 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_H__ +#define __XFS_SUPPORT_H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* __XFS_SUPPORT_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs_support/sv.c linux-2.4-xfs/linux/fs/xfs_support/sv.c --- linux-2.4.7/linux/fs/xfs_support/sv.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/sv.c Wed Mar 14 02:07:20 2001 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include +#include /* for EXPORT_SYMBOL */ + +#include + +/* Synchronisation variables ---------------------------------------- */ + +void _sv_init( sv_t *sv) +{ + init_waitqueue_head( &sv->waiters ); + spin_lock_init(&sv->lock); +} + +void _sv_wait( sv_t *sv, spinlock_t *lock, int spl, int intr, struct timespec *timeout) +{ + DECLARE_WAITQUEUE( wait, current ); + + spin_lock(&sv->lock); /* No need to do interrupts since + they better be disabled */ + + /* Don't restore interrupts until we are done with both locks */ + spin_unlock( lock ); + add_wait_queue_exclusive( &sv->waiters, &wait ); +#if 0 + if (intr) { + set_current_state(TASK_INTERRUPTIBLE | TASK_EXCLUSIVE); + } else { + set_current_state(TASK_UNINTERRUPTIBLE | TASK_EXCLUSIVE); + } +#endif + if (intr) { + set_current_state(TASK_INTERRUPTIBLE ); + } else { + set_current_state(TASK_UNINTERRUPTIBLE ); + } + spin_unlock_irqrestore( & sv->lock, (long)spl ); + + if (timeout) { + schedule_timeout(timespec_to_jiffies(timeout)); + } else { + schedule(); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue( &sv->waiters, &wait ); +} + +void +_sv_broadcast(sv_t *sv) +{ + unsigned long flags; + + spin_lock_irqsave(&sv->lock, flags); + + wake_up_all(&sv->waiters ); + spin_unlock_irqrestore(&sv->lock, flags); +} + +/* + * Set runnable, at most, one thread waiting on sync variable. + * Returns # of threads set runnable (0 or 1). + */ +void +_sv_signal(sv_t *svp) +{ + unsigned long flags; + + spin_lock_irqsave(&svp->lock, flags); + wake_up(&svp->waiters); + spin_unlock_irqrestore(&svp->lock, flags); +} + +EXPORT_SYMBOL(_sv_init); +EXPORT_SYMBOL(_sv_wait); +EXPORT_SYMBOL(_sv_broadcast); +EXPORT_SYMBOL(_sv_signal); + diff -rNu linux-2.4.7/linux/fs/xfs_support/sv.h linux-2.4-xfs/linux/fs/xfs_support/sv.h --- linux-2.4.7/linux/fs/xfs_support/sv.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/sv.h Wed Mar 14 00:04:19 2001 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_SV_H__ +#define __XFS_SUPPORT_SV_H__ + +#include +#include +#include +#include +#include + +/* + * Synchronisation variables + * + * parameters "pri", "svf" and "rts" are not (yet?) implemented + * + */ + +#define init_sv(sv,type,name,flag) \ + _sv_init(sv) +#define sv_init(sv,flag,name) \ + _sv_init(sv) +#define sv_wait(sv, pri, lock, spl) \ + _sv_wait(sv, lock, spl, 0, NULL) +#define sv_wait_sig(sv, pri, lock, spl) \ + _sv_wait(sv, lock, spl, 1, NULL) +#define sv_timedwait(sv, pri, lock, spl, svf, ts, rts) \ + _sv_wait(sv, lock, spl, 0, ts) +#define sv_timedwait_sig(sv, pri, lock, spl, svf, ts, rts) \ + _sv_wait(sv, lock, spl, 1, ts) +#define mp_sv_wait(sv, pri, lock, spl) \ + _sv_wait(sv, lock, spl, 0, NULL) +#define mp_sv_wait_sig(sv, pri, lock, spl) \ + _sv_wait(sv, lock, spl, 1, NULL) +#define sv_broadcast(sv) \ + _sv_broadcast(sv) + +typedef struct sv_s { + wait_queue_head_t waiters; + spinlock_t lock; +} sv_t; + +void _sv_init(sv_t *sv); +void _sv_wait(sv_t *sv, spinlock_t *lock, int spl, int intr, struct timespec *timeout); +void _sv_broadcast(sv_t *sv); +void _sv_signal(sv_t *sv); + +#define sv_signal(sv) _sv_signal(sv) +#define sv_broadcast(sv) _sv_broadcast(sv) +#define sv_destroy(sv) + +/* + * Initialize sync variables. + * + * void sv_init(sv_t *svp, int type, char *name); + * void init_sv(sv_t *svp, int type, char *name, long sequencer); + * + * Name may be null; used only when metering routines are installed + * (see mutex_init, init_mutex above). + */ + +#define SV_FIFO 0x0 /* sv_t is FIFO type */ +#define SV_LIFO 0x2 /* sv_t is LIFO type */ +#define SV_PRIO 0x4 /* sv_t is PRIO type */ +#define SV_KEYED 0x6 /* sv_t is KEYED type */ +#define SV_DEFAULT SV_FIFO + +#endif /* __XFS_SUPPORT_SV_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs_support/time.h linux-2.4-xfs/linux/fs/xfs_support/time.h --- linux-2.4.7/linux/fs/xfs_support/time.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/time.h Wed Mar 14 00:04:19 2001 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_TIME_H__ +#define __XFS_SUPPORT_TIME_H__ + +#include + +static inline void delay(long ticks) +{ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(ticks); +} + +static inline void nanotime(timespec_t *tvp) +{ + tvp->tv_sec = xtime.tv_sec; + tvp->tv_nsec = xtime.tv_usec * 1000; +} + +#endif /* __XFS_SUPPORT_TIME_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs_support/types.h linux-2.4-xfs/linux/fs/xfs_support/types.h --- linux-2.4.7/linux/fs/xfs_support/types.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/types.h Tue Apr 10 20:44:54 2001 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_TYPES_H__ +#define __XFS_SUPPORT_TYPES_H__ + +#include + +/* + * Additional type declarations for XFS + */ + +typedef signed char __int8_t; +typedef unsigned char __uint8_t; +typedef signed short int __int16_t; +typedef unsigned short int __uint16_t; +typedef signed int __int32_t; +typedef unsigned int __uint32_t; +typedef signed long long int __int64_t; +typedef unsigned long long int __uint64_t; + +/* POSIX Extensions */ +typedef unsigned char uchar_t; +typedef unsigned short ushort_t; +typedef unsigned int uint_t; +typedef unsigned long ulong_t; + +typedef enum { B_FALSE, B_TRUE } boolean_t; + +typedef __int64_t prid_t; /* project ID */ +typedef __uint32_t inst_t; /* an instruction */ + +typedef __uint32_t app32_ulong_t; +typedef __uint32_t app32_ptr_t; + +#if (BITS_PER_LONG == 32) +#define XFS_64 0 +typedef __int64_t sysarg_t; +#elif (BITS_PER_LONG == 64) +#define XFS_64 1 +typedef int sysarg_t; +#else +#error BITS_PER_LONG must be 32 or 64 +#endif + +typedef struct timespec timespec_t; + +typedef __u64 xfs_off_t; +typedef __s32 xfs32_off_t; +typedef __u64 xfs_ino_t; /* type */ +typedef __s64 xfs_daddr_t; /* type */ +typedef char * xfs_caddr_t; /* type */ +typedef off_t linux_off_t; +typedef __kernel_ino_t linux_ino_t; +typedef __uint32_t xfs_dev_t; + +/* these are more generic than linux_ */ +typedef off_t sys_off_t; +typedef __kernel_ino_t sys_ino_t; + + +#ifdef __KERNEL__ +typedef struct { + unsigned char __u_bits[16]; +} uuid_t; +#endif + +/* alias kmem zones for xfs */ + +#define xfs_zone_t kmem_zone_t +#define xfs_zone kmem_cache_s + +#endif /* __XFS_SUPPORT_TYPES_H__ */ diff -rNu linux-2.4.7/linux/fs/xfs_support/uuid.c linux-2.4-xfs/linux/fs/xfs_support/uuid.c --- linux-2.4.7/linux/fs/xfs_support/uuid.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/uuid.c Tue May 15 21:10:14 2001 @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#include +#include +#include +#include +#include + +#include +#include +#include /* for EXPORT_SYMBOL */ + +#ifdef __sparc__ +#include +#else +#include +#endif + +/* NODE_SIZE is the number of bytes used for the node identifier portion. */ +#define NODE_SIZE 6 + +/* + * Total size must be 128 bits. N.B. definition of uuid_t in uuid.h! + */ +typedef struct { + u_int32_t uu_timelow; /* time "low" */ + u_int16_t uu_timemid; /* time "mid" */ + u_int16_t uu_timehi; /* time "hi" and version */ + u_int16_t uu_clockseq; /* "reserved" and clock sequence */ + u_int16_t uu_node[NODE_SIZE / 2]; /* ethernet hardware address */ +} uu_t; + +/* + * The Time Base Correction is the amount to add on to a UNIX-based + * time value (i.e. seconds since 1 Jan. 1970) to convert it to the + * time base for UUIDs (15 Oct. 1582). + */ +#define UUID_TBC 0x01B21DD2138140LL + +static short uuid_eaddr[NODE_SIZE / 2]; /* ethernet address */ +static __int64_t uuid_time; /* last time basis used */ +static u_int16_t uuid_clockseq; /* boot-time randomizer */ +DECLARE_MUTEX(uuid_lock); + +/* + * uuid_init - called from out of init_tbl[] + */ +void +uuid_init(void) +{ +} + +/* + * uuid_getnodeuniq - obtain the node unique fields of a UUID. + * + * This is not in any way a standard or condoned UUID function; + * it just something that's needed for user-level file handles. + */ +void +uuid_getnodeuniq(uuid_t *uuid, int fsid [2]) +{ + char *uu=(char*)uuid; + + /* on IRIX, this function assumes big-endian fields within + * the uuid, so we use INT_GET to get the same result on + * little-endian systems + */ + + fsid[0] = (INT_GET(*(u_int16_t*)(uu+8), ARCH_CONVERT) << 16) + + INT_GET(*(u_int16_t*)(uu+4), ARCH_CONVERT); + fsid[1] = INT_GET(*(u_int32_t*)(uu ), ARCH_CONVERT); +} + +void +uuid_create_nil(uuid_t *uuid) +{ + bzero(uuid, sizeof *uuid); +} + +int +uuid_is_nil(uuid_t *uuid) +{ + int i; + char *cp = (char *)uuid; + + if (uuid == NULL) + return B_TRUE; + /* implied check of version number here... */ + for (i = 0; i < sizeof *uuid; i++) + if (*cp++) return B_FALSE; /* not nil */ + return B_TRUE; /* is nil */ +} + +int +uuid_equal(uuid_t *uuid1, uuid_t *uuid2) +{ + return bcmp(uuid1, uuid2, sizeof(uuid_t)) ? B_FALSE : B_TRUE; +} + +/* + * Given a 128-bit uuid, return a 64-bit value by adding the top and bottom + * 64-bit words. NOTE: This function can not be changed EVER. Although + * brain-dead, some applications depend on this 64-bit value remaining + * persistent. Specifically, DMI vendors store the value as a persistent + * filehandle. + */ +__uint64_t +uuid_hash64(uuid_t *uuid) +{ + __uint64_t *sp = (__uint64_t *)uuid; + + return sp[0] + sp[1]; +} /* uuid_hash64 */ + +static void +get_eaddr(char *junk) +{ +#ifdef __sparc__ + memcpy(uuid_eaddr, idprom->id_ethaddr, 6); +#else + struct net_device *dev; + + dev = dev_get_by_name("eth0"); + if (!dev || !dev->addr_len) { + get_random_bytes(uuid_eaddr, sizeof(uuid_eaddr)); + } else { + memcpy(uuid_eaddr, dev->dev_addr, + dev->addr_lenaddr_len:sizeof(uuid_eaddr)); + dev_put(dev); + } +#endif +} + +/* + * uuid_create - kernel version, does the actual work + */ +void +uuid_create(uuid_t *uuid) +{ + int i; + uu_t *uu = (uu_t *)uuid; + static int uuid_have_eaddr = 0; /* ethernet addr inited? */ + static int uuid_is_init = 0; /* time/clockseq inited? */ + + down(&uuid_lock); + if (!uuid_is_init) { + timespec_t ts; + + nanotime(&ts); + /* + * The clock sequence must be initialized randomly. + */ + uuid_clockseq = ((unsigned long)jiffies & 0xfff) | 0x8000; + /* + * Initialize the uuid time, it's in 100 nanosecond + * units since a time base in 1582. + */ + uuid_time = ts.tv_sec * 10000000LL + + ts.tv_nsec / 100LL + + UUID_TBC; + uuid_is_init = 1; + } + if (!uuid_have_eaddr) { + uuid_have_eaddr = 1; + get_eaddr((char *)uuid_eaddr); + } + uuid_time++; + uu->uu_timelow = (u_int32_t)(uuid_time & 0x00000000ffffffffLL); + uu->uu_timemid = (u_int16_t)((uuid_time >> 32) & 0x0000ffff); + uu->uu_timehi = (u_int16_t)((uuid_time >> 48) & 0x00000fff) | 0x1000; + up(&uuid_lock); + uu->uu_clockseq = uuid_clockseq; + for (i = 0; i < (NODE_SIZE / 2); i++) + uu->uu_node [i] = uuid_eaddr [i]; +} + +int +uuid_compare(uuid_t *uuid1, uuid_t *uuid2) +{ + int i; + char *cp1 = (char *) uuid1; + char *cp2 = (char *) uuid2; + + if (uuid1 == NULL) { + if (uuid2 == NULL) { + return 0; /* equal because both are nil */ + } else { + return -1; /* uuid1 nil, so precedes uuid2 */ + } + } else if (uuid2 == NULL) { + return 1; + } + + /* implied check of version number here... */ + for (i = 0; i < sizeof(uuid_t); i++) { + if (*cp1 < *cp2) + return -1; + if (*cp1++ > *cp2++) + return 1; + } + return 0; /* they're equal */ +} + +EXPORT_SYMBOL(uuid_create_nil); +EXPORT_SYMBOL(uuid_is_nil); +EXPORT_SYMBOL(uuid_equal); +EXPORT_SYMBOL(uuid_getnodeuniq); +EXPORT_SYMBOL(uuid_hash64); +EXPORT_SYMBOL(uuid_compare); +EXPORT_SYMBOL(uuid_create); diff -rNu linux-2.4.7/linux/fs/xfs_support/uuid.h linux-2.4-xfs/linux/fs/xfs_support/uuid.h --- linux-2.4.7/linux/fs/xfs_support/uuid.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/fs/xfs_support/uuid.h Tue May 15 21:10:14 2001 @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XFS_SUPPORT_UUID_H__ +#define __XFS_SUPPORT_UUID_H__ + +#include + +void uuid_create_nil(uuid_t *uuid); +int uuid_is_nil(uuid_t *uuid); +int uuid_equal(uuid_t *uuid1, uuid_t *uuid2); +void uuid_getnodeuniq(uuid_t *uuid, int fsid [2]); +__uint64_t uuid_hash64(uuid_t *uuid); + +#endif /* __XFS_SUPPORT_UUID_H__ */ diff -rNu linux-2.4.7/linux/include/CVS/Entries linux-2.4-xfs/linux/include/CVS/Entries --- linux-2.4.7/linux/include/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/CVS/Entries Thu Jul 5 12:04:31 2001 @@ -0,0 +1 @@ +D diff -rNu linux-2.4.7/linux/include/CVS/Entries.Log linux-2.4-xfs/linux/include/CVS/Entries.Log --- linux-2.4.7/linux/include/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/CVS/Entries.Log Thu Jul 5 12:06:57 2001 @@ -0,0 +1,22 @@ +A D/asm-alpha//// +A D/asm-arm//// +A D/asm-cris//// +A D/asm-generic//// +A D/asm-i386//// +A D/asm-ia64//// +A D/asm-m68k//// +A D/asm-mips//// +A D/asm-mips64//// +A D/asm-parisc//// +A D/asm-ppc//// +A D/asm-s390//// +A D/asm-s390x//// +A D/asm-sh//// +A D/asm-sparc//// +A D/asm-sparc64//// +A D/linux//// +A D/math-emu//// +A D/net//// +A D/pcmcia//// +A D/scsi//// +A D/video//// diff -rNu linux-2.4.7/linux/include/CVS/Repository linux-2.4-xfs/linux/include/CVS/Repository --- linux-2.4.7/linux/include/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/CVS/Repository Thu Jul 5 12:04:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include diff -rNu linux-2.4.7/linux/include/CVS/Root linux-2.4-xfs/linux/include/CVS/Root --- linux-2.4.7/linux/include/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/CVS/Root Thu Jul 5 12:04:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-alpha/CVS/Entries linux-2.4-xfs/linux/include/asm-alpha/CVS/Entries --- linux-2.4.7/linux/include/asm-alpha/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-alpha/CVS/Entries Thu Jul 5 12:04:35 2001 @@ -0,0 +1,102 @@ +/a.out.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/asm_offsets.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/atomic.h/1.6/Sat Nov 25 08:05:45 2000/-ko/ +/bitops.h/1.9/Tue May 29 19:53:13 2001/-ko/ +/bugs.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/byteorder.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/cache.h/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/checksum.h/1.3/Tue Feb 1 23:02:54 2000/-ko/ +/compiler.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/console.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/core_apecs.h/1.6/Mon Mar 20 18:07:46 2000/-ko/ +/core_cia.h/1.8/Mon Mar 20 18:07:46 2000/-ko/ +/core_irongate.h/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/core_lca.h/1.7/Mon Mar 20 18:07:46 2000/-ko/ +/core_mcpcia.h/1.8/Mon Mar 20 18:07:46 2000/-ko/ +/core_polaris.h/1.7/Mon Mar 20 18:07:46 2000/-ko/ +/core_t2.h/1.6/Mon Mar 20 18:07:46 2000/-ko/ +/core_titan.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/core_tsunami.h/1.11/Tue May 29 19:53:13 2001/-ko/ +/core_wildfire.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/current.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/delay.h/1.9/Thu Jun 21 15:45:04 2001/-ko/ +/div64.h/1.2/Wed Nov 24 20:36:16 1999/-ko/ +/dma.h/1.5/Tue Dec 7 07:08:23 1999/-ko/ +/elf.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/errno.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/fcntl.h/1.9/Tue Feb 27 16:13:07 2001/-ko/ +/floppy.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/fpu.h/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/gentrap.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/hardirq.h/1.12/Sat Jun 9 02:44:24 2001/-ko/ +/hdreg.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/hw_irq.h/1.3/Fri Mar 3 01:42:02 2000/-ko/ +/hwrpb.h/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/ide.h/1.5/Fri Jun 2 00:22:59 2000/-ko/ +/init.h/1.3/Sun Aug 29 02:28:51 1999/-ko/ +/io.h/1.14/Wed May 2 06:22:13 2001/-ko/ +/ioctl.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ioctls.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/ipcbuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/irq.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/jensen.h/1.4/Fri Feb 11 01:00:06 2000/-ko/ +/kdb.h/1.2/Wed Oct 4 11:42:46 2000/-ko/ +/keyboard.h/1.3/Tue Oct 12 19:12:19 1999/-ko/ +/linux_logo.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/machvec.h/1.11/Mon Apr 2 17:13:32 2001/-ko/ +/mc146818rtc.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/md.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mman.h/1.3/Mon Mar 20 18:07:46 2000/-ko/ +/mmu.h/1.1/Thu Dec 21 05:48:12 2000/-ko/ +/mmu_context.h/1.11/Thu Dec 21 05:48:12 2000/-ko/ +/mmzone.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/module.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/msgbuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/namei.h/1.3/Fri Apr 21 16:16:46 2000/-ko/ +/page.h/1.10/Tue May 29 19:53:13 2001/-ko/ +/pal.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/param.h/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/parport.h/1.4/Wed Mar 15 18:20:34 2000/-ko/ +/pci.h/1.13/Tue May 29 19:53:13 2001/-ko/ +/pgalloc.h/1.10/Tue May 29 19:53:13 2001/-ko/ +/pgtable.h/1.26/Tue May 29 19:53:13 2001/-ko/ +/poll.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/posix_types.h/1.5/Fri Jan 21 19:20:14 2000/-ko/ +/processor.h/1.11/Wed Jan 3 01:43:05 2001/-ko/ +/ptrace.h/1.3/Tue Jul 27 20:02:32 1999/-ko/ +/reg.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/resource.h/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/scatterlist.h/1.3/Fri Feb 11 01:00:06 2000/-ko/ +/segment.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/semaphore.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/sembuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/serial.h/1.3/Wed Sep 15 20:42:56 1999/-ko/ +/sfp-machine.h/1.2/Fri Mar 24 21:32:44 2000/-ko/ +/shmbuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/shmparam.h/1.3/Mon Nov 8 22:55:41 1999/-ko/ +/sigcontext.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/siginfo.h/1.4/Fri Jun 2 00:22:59 2000/-ko/ +/signal.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/smp.h/1.16/Tue May 29 19:53:13 2001/-ko/ +/smplock.h/1.4/Fri Mar 24 21:32:44 2000/-ko/ +/socket.h/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/sockios.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/softirq.h/1.7/Sat Jun 9 02:44:24 2001/-ko/ +/spinlock.h/1.11/Tue May 29 19:53:13 2001/-ko/ +/stat.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/statfs.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/string.h/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/sysinfo.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/system.h/1.15/Tue May 29 19:53:13 2001/-ko/ +/termbits.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/termios.h/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/timex.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/types.h/1.3/Fri Feb 11 01:00:06 2000/-ko/ +/uaccess.h/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/ucontext.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/unaligned.h/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/unistd.h/1.14/Thu Feb 1 17:10:24 2001/-ko/ +/user.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/vga.h/1.6/Mon Mar 20 18:07:46 2000/-ko/ +/xor.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-alpha/CVS/Repository linux-2.4-xfs/linux/include/asm-alpha/CVS/Repository --- linux-2.4.7/linux/include/asm-alpha/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-alpha/CVS/Repository Thu Jul 5 12:04:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-alpha diff -rNu linux-2.4.7/linux/include/asm-alpha/CVS/Root linux-2.4-xfs/linux/include/asm-alpha/CVS/Root --- linux-2.4.7/linux/include/asm-alpha/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-alpha/CVS/Root Thu Jul 5 12:04:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-alpha/fcntl.h linux-2.4-xfs/linux/include/asm-alpha/fcntl.h --- linux-2.4.7/linux/include/asm-alpha/fcntl.h Sun Oct 8 11:04:04 2000 +++ linux-2.4-xfs/linux/include/asm-alpha/fcntl.h Tue Feb 27 10:13:07 2001 @@ -21,6 +21,7 @@ #define O_DIRECTORY 0100000 /* must be a directory */ #define O_NOFOLLOW 0200000 /* don't follow links */ #define O_LARGEFILE 0400000 /* will be set by the kernel on every open */ +#define O_INVISIBLE 02000000 /* invisible I/O, for DMAPI/XDSM */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff -rNu linux-2.4.7/linux/include/asm-alpha/kdb.h linux-2.4-xfs/linux/include/asm-alpha/kdb.h --- linux-2.4.7/linux/include/asm-alpha/kdb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-alpha/kdb.h Wed Oct 4 06:42:46 2000 @@ -0,0 +1,10 @@ +/* + * Dummy include/asm/kdb.h for alpha. + */ +#if !defined(_ASM_KDB_H) +#define _ASM_KDB_H +#define KDB_ENTER() +struct pt_regs; +typedef struct pt_regs *kdb_eframe_t; +typedef unsigned long kdb_machreg_t; +#endif /* ASM_KDB_H */ diff -rNu linux-2.4.7/linux/include/asm-arm/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/CVS/Entries Thu Jul 5 12:04:38 2001 @@ -0,0 +1,95 @@ +/a.out.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/assembler.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/atomic.h/1.7/Mon Oct 23 18:56:35 2000/-ko/ +/bitops.h/1.6/Thu Jun 28 05:21:16 2001/-ko/ +/bugs.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/byteorder.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/cache.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/checksum.h/1.8/Mon Oct 23 18:56:35 2000/-ko/ +/cpu-multi26.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/cpu-multi32.h/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/cpu-single.h/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/current.h/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/delay.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/div64.h/1.2/Fri Jan 21 19:20:14 2000/-ko/ +/dma.h/1.7/Mon Oct 23 18:56:35 2000/-ko/ +/ecard.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/elf.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/errno.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fcntl.h/1.7/Mon Oct 23 18:56:35 2000/-ko/ +/fiq.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/floppy.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/hardirq.h/1.8/Thu Jul 5 06:13:42 2001/-ko/ +/hardware.h/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/hdreg.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/ide.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/io.h/1.15/Thu Jun 28 05:21:16 2001/-ko/ +/ioctl.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ioctls.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/ipc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ipcbuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/irq.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/kdb.h/1.2/Wed Oct 4 11:42:46 2000/-ko/ +/keyboard.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/leds.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/limits.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/linux_logo.h/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/mc146818rtc.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/memory.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/mman.h/1.3/Mon Mar 20 18:07:46 2000/-ko/ +/mmu.h/1.1/Thu Dec 21 05:48:12 2000/-ko/ +/mmu_context.h/1.8/Mon Oct 23 18:56:35 2000/-ko/ +/mmzone.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/module.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/msgbuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/namei.h/1.4/Fri Apr 21 16:16:46 2000/-ko/ +/nwflash.h/1.1/Sat Oct 23 02:22:05 1999/-ko/ +/page.h/1.11/Thu Sep 28 22:42:39 2000/-ko/ +/param.h/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/parport.h/1.8/Mon Oct 23 18:56:35 2000/-ko/ +/pci.h/1.11/Thu Jun 28 05:21:16 2001/-ko/ +/pgalloc.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/pgtable.h/1.18/Wed May 2 06:22:13 2001/-ko/ +/poll.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/posix_types.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/proc-fns.h/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/processor.h/1.16/Wed May 2 06:22:13 2001/-ko/ +/procinfo.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/ptrace.h/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/resource.h/1.7/Mon Oct 23 18:56:35 2000/-ko/ +/scatterlist.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/segment.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/semaphore-helper.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/semaphore.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/sembuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/serial.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/setup.h/1.9/Wed May 2 06:22:13 2001/-ko/ +/shmbuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/shmparam.h/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/sigcontext.h/1.3/Fri Jan 21 19:20:14 2000/-ko/ +/siginfo.h/1.5/Fri Jun 2 00:22:59 2000/-ko/ +/signal.h/1.3/Wed Nov 24 20:36:16 1999/-ko/ +/smp.h/1.3/Tue May 2 22:18:18 2000/-ko/ +/smplock.h/1.4/Fri Mar 24 21:32:44 2000/-ko/ +/socket.h/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/sockios.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/softirq.h/1.5/Thu Jul 5 06:13:42 2001/-ko/ +/spinlock.h/1.4/Wed Sep 15 22:45:13 1999/-ko/ +/stat.h/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/statfs.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/string.h/1.7/Fri May 26 01:52:46 2000/-ko/ +/system.h/1.15/Sun Dec 17 19:15:00 2000/-ko/ +/termbits.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/termios.h/1.8/Sat Jun 9 02:44:24 2001/-ko/ +/therm.h/1.1/Sat Oct 23 02:22:05 1999/-ko/ +/timex.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/types.h/1.3/Fri Feb 11 01:00:06 2000/-ko/ +/uaccess.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/ucontext.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/unaligned.h/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/unistd.h/1.16/Wed May 2 06:22:13 2001/-ko/ +/user.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/vga.h/1.3/Wed Dec 15 00:05:45 1999/-ko/ +/vt.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/xor.h/1.4/Thu Jun 28 05:21:16 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/CVS/Entries.Log linux-2.4-xfs/linux/include/asm-arm/CVS/Entries.Log --- linux-2.4.7/linux/include/asm-arm/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/CVS/Entries.Log Thu Jul 5 12:04:44 2001 @@ -0,0 +1,15 @@ +A D/arch-arc//// +A D/arch-cl7500//// +A D/arch-ebsa110//// +A D/arch-ebsa285//// +A D/arch-integrator//// +A D/arch-l7200//// +A D/arch-nexuspci//// +A D/arch-rpc//// +A D/arch-sa1100//// +A D/arch-shark//// +A D/arch-tbox//// +A D/hardware//// +A D/mach//// +A D/proc-armo//// +A D/proc-armv//// diff -rNu linux-2.4.7/linux/include/asm-arm/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/CVS/Repository Thu Jul 5 12:04:35 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm diff -rNu linux-2.4.7/linux/include/asm-arm/CVS/Root linux-2.4-xfs/linux/include/asm-arm/CVS/Root --- linux-2.4.7/linux/include/asm-arm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/CVS/Root Thu Jul 5 12:04:35 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-arm/arch-arc/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/arch-arc/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/arch-arc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-arc/CVS/Entries Thu Jul 5 12:04:38 2001 @@ -0,0 +1,16 @@ +/dma.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/hardware.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/ide.h/1.7/Mon Oct 23 18:56:35 2000/-ko/ +/io.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/irq.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/irqs.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/keyboard.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/memory.h/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/oldlatches.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/param.h/1.1/Sat Oct 23 02:22:05 1999/-ko/ +/serial.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/system.h/1.10/Wed May 2 06:22:13 2001/-ko/ +/time.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/timex.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/uncompress.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/arch-arc/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/arch-arc/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/arch-arc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-arc/CVS/Repository Thu Jul 5 12:04:38 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm/arch-arc diff -rNu linux-2.4.7/linux/include/asm-arm/arch-arc/CVS/Root linux-2.4-xfs/linux/include/asm-arm/arch-arc/CVS/Root --- linux-2.4.7/linux/include/asm-arm/arch-arc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-arc/CVS/Root Thu Jul 5 12:04:38 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-arm/arch-cl7500/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/arch-cl7500/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/arch-cl7500/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-cl7500/CVS/Entries Thu Jul 5 12:04:39 2001 @@ -0,0 +1,17 @@ +/acornfb.h/1.2/Tue Dec 7 07:08:23 1999/-ko/ +/dma.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/hardware.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/ide.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/io.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/irq.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/irqs.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/keyboard.h/1.1/Wed Nov 24 20:36:16 1999/-ko/ +/memory.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/param.h/1.2/Fri Mar 3 01:42:02 2000/-ko/ +/serial.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/system.h/1.10/Wed May 2 06:22:13 2001/-ko/ +/time.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/timex.h/1.1/Wed Nov 24 20:36:16 1999/-ko/ +/uncompress.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/vmalloc.h/1.2/Tue May 2 22:18:18 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/arch-cl7500/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/arch-cl7500/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/arch-cl7500/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-cl7500/CVS/Repository Thu Jul 5 12:04:38 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm/arch-cl7500 diff -rNu linux-2.4.7/linux/include/asm-arm/arch-cl7500/CVS/Root linux-2.4-xfs/linux/include/asm-arm/arch-cl7500/CVS/Root --- linux-2.4.7/linux/include/asm-arm/arch-cl7500/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-cl7500/CVS/Root Thu Jul 5 12:04:38 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-arm/arch-ebsa110/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/arch-ebsa110/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/arch-ebsa110/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-ebsa110/CVS/Entries Thu Jul 5 12:04:39 2001 @@ -0,0 +1,15 @@ +/dma.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/hardware.h/1.9/Wed May 2 06:22:13 2001/-ko/ +/ide.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/io.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/irq.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/irqs.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/memory.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/param.h/1.3/Sat Oct 23 02:22:05 1999/-ko/ +/serial.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/system.h/1.9/Mon Oct 23 18:56:35 2000/-ko/ +/time.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/timex.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/uncompress.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/vmalloc.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/arch-ebsa110/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/arch-ebsa110/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/arch-ebsa110/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-ebsa110/CVS/Repository Thu Jul 5 12:04:39 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm/arch-ebsa110 diff -rNu linux-2.4.7/linux/include/asm-arm/arch-ebsa110/CVS/Root linux-2.4-xfs/linux/include/asm-arm/arch-ebsa110/CVS/Root --- linux-2.4.7/linux/include/asm-arm/arch-ebsa110/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-ebsa110/CVS/Root Thu Jul 5 12:04:39 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-arm/arch-ebsa285/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/arch-ebsa285/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/arch-ebsa285/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-ebsa285/CVS/Entries Thu Jul 5 12:04:39 2001 @@ -0,0 +1,16 @@ +/dma.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/hardware.h/1.9/Sun Dec 17 19:15:00 2000/-ko/ +/ide.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/io.h/1.11/Thu Jul 5 06:13:42 2001/-ko/ +/irq.h/1.14/Wed May 2 06:22:13 2001/-ko/ +/irqs.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/keyboard.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/memory.h/1.9/Sun Dec 17 19:15:00 2000/-ko/ +/param.h/1.3/Sat Oct 23 02:22:05 1999/-ko/ +/serial.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/system.h/1.11/Tue May 29 19:53:13 2001/-ko/ +/time.h/1.10/Mon Oct 23 18:56:35 2000/-ko/ +/timex.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/uncompress.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/vmalloc.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/arch-ebsa285/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/arch-ebsa285/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/arch-ebsa285/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-ebsa285/CVS/Repository Thu Jul 5 12:04:39 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm/arch-ebsa285 diff -rNu linux-2.4.7/linux/include/asm-arm/arch-ebsa285/CVS/Root linux-2.4-xfs/linux/include/asm-arm/arch-ebsa285/CVS/Root --- linux-2.4.7/linux/include/asm-arm/arch-ebsa285/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-ebsa285/CVS/Root Thu Jul 5 12:04:39 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-arm/arch-integrator/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/arch-integrator/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/arch-integrator/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-integrator/CVS/Entries Thu Jul 5 12:04:40 2001 @@ -0,0 +1,18 @@ +/bits.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/dma.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/hardware.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/io.h/1.2/Thu Jul 5 06:13:42 2001/-ko/ +/irq.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/irqs.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/keyboard.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/memory.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/param.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/platform.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/serial.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/sizes.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/system.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/time.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/timex.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/uncompress.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/vmalloc.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/arch-integrator/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/arch-integrator/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/arch-integrator/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-integrator/CVS/Repository Thu Jul 5 12:04:39 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm/arch-integrator diff -rNu linux-2.4.7/linux/include/asm-arm/arch-integrator/CVS/Root linux-2.4-xfs/linux/include/asm-arm/arch-integrator/CVS/Root --- linux-2.4.7/linux/include/asm-arm/arch-integrator/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-integrator/CVS/Root Thu Jul 5 12:04:39 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-arm/arch-l7200/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/arch-l7200/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/arch-l7200/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-l7200/CVS/Entries Thu Jul 5 12:04:40 2001 @@ -0,0 +1,24 @@ +/aux_reg.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/dma.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/gp_timers.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/gpio.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/hardware.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/ide.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/io.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/irq.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/irqs.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/keyboard.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/memory.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/param.h/1.1/Fri May 26 01:52:46 2000/-ko/ +/pmpcon.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/pmu.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/serial.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/serial_l7200.h/1.1/Fri May 26 01:52:46 2000/-ko/ +/sib.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/sys-clock.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/system.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/time.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/timex.h/1.1/Fri May 26 01:52:46 2000/-ko/ +/uncompress.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/vmalloc.h/1.1/Fri May 26 01:52:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/arch-l7200/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/arch-l7200/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/arch-l7200/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-l7200/CVS/Repository Thu Jul 5 12:04:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm/arch-l7200 diff -rNu linux-2.4.7/linux/include/asm-arm/arch-l7200/CVS/Root linux-2.4-xfs/linux/include/asm-arm/arch-l7200/CVS/Root --- linux-2.4.7/linux/include/asm-arm/arch-l7200/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-l7200/CVS/Root Thu Jul 5 12:04:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-arm/arch-nexuspci/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/arch-nexuspci/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/arch-nexuspci/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-nexuspci/CVS/Entries Thu Jul 5 12:04:40 2001 @@ -0,0 +1,15 @@ +/dma.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/hardware.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/ide.h/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/io.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/irq.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/irqs.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/keyboard.h/1.1/Fri Mar 3 01:42:02 2000/-ko/ +/memory.h/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/param.h/1.3/Sat Oct 23 02:22:05 1999/-ko/ +/system.h/1.8/Mon Oct 23 18:56:35 2000/-ko/ +/time.h/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/timex.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/uncompress.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/vmalloc.h/1.1/Fri Apr 21 16:16:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/arch-nexuspci/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/arch-nexuspci/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/arch-nexuspci/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-nexuspci/CVS/Repository Thu Jul 5 12:04:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm/arch-nexuspci diff -rNu linux-2.4.7/linux/include/asm-arm/arch-nexuspci/CVS/Root linux-2.4-xfs/linux/include/asm-arm/arch-nexuspci/CVS/Root --- linux-2.4.7/linux/include/asm-arm/arch-nexuspci/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-nexuspci/CVS/Root Thu Jul 5 12:04:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-arm/arch-rpc/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/arch-rpc/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/arch-rpc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-rpc/CVS/Entries Thu Jul 5 12:04:41 2001 @@ -0,0 +1,17 @@ +/acornfb.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/dma.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/hardware.h/1.9/Wed May 2 06:22:13 2001/-ko/ +/ide.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/io.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/irq.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/irqs.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/keyboard.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/memory.h/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/param.h/1.3/Sat Oct 23 02:22:05 1999/-ko/ +/serial.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/system.h/1.11/Wed May 2 06:22:13 2001/-ko/ +/time.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/timex.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/uncompress.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/vmalloc.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/arch-rpc/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/arch-rpc/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/arch-rpc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-rpc/CVS/Repository Thu Jul 5 12:04:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm/arch-rpc diff -rNu linux-2.4.7/linux/include/asm-arm/arch-rpc/CVS/Root linux-2.4-xfs/linux/include/asm-arm/arch-rpc/CVS/Root --- linux-2.4.7/linux/include/asm-arm/arch-rpc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-rpc/CVS/Root Thu Jul 5 12:04:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-arm/arch-sa1100/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/arch-sa1100/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/arch-sa1100/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-sa1100/CVS/Entries Thu Jul 5 12:04:43 2001 @@ -0,0 +1,28 @@ +/SA-1100.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/SA-1101.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/SA-1111.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/assabet.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/bitfield.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/bitsy.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/cerf.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/dma.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/graphicsclient.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/hardware.h/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/ide.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/io.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/irq.h/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/irqs.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/keyboard.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/memory.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/mmzone.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/pangolin.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/param.h/1.2/Fri Jan 21 19:20:14 2000/-ko/ +/pcmcia.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/serial.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/serial_reg.h/1.1/Sat Oct 23 02:22:05 1999/-ko/ +/system.h/1.11/Wed May 2 06:22:13 2001/-ko/ +/time.h/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/timex.h/1.1/Sat Oct 23 02:22:05 1999/-ko/ +/uncompress.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/vmalloc.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/arch-sa1100/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/arch-sa1100/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/arch-sa1100/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-sa1100/CVS/Repository Thu Jul 5 12:04:41 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm/arch-sa1100 diff -rNu linux-2.4.7/linux/include/asm-arm/arch-sa1100/CVS/Root linux-2.4-xfs/linux/include/asm-arm/arch-sa1100/CVS/Root --- linux-2.4.7/linux/include/asm-arm/arch-sa1100/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-sa1100/CVS/Root Thu Jul 5 12:04:41 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-arm/arch-shark/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/arch-shark/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/arch-shark/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-shark/CVS/Entries Thu Jul 5 12:04:43 2001 @@ -0,0 +1,16 @@ +/dma.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/hardware.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/ide.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/io.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/irq.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/irqs.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/keyboard.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/memory.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/param.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/serial.h/1.1/Fri Apr 21 16:16:46 2000/-ko/ +/system.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/time.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/timex.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/uncompress.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/vmalloc.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/arch-shark/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/arch-shark/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/arch-shark/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-shark/CVS/Repository Thu Jul 5 12:04:43 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm/arch-shark diff -rNu linux-2.4.7/linux/include/asm-arm/arch-shark/CVS/Root linux-2.4-xfs/linux/include/asm-arm/arch-shark/CVS/Root --- linux-2.4.7/linux/include/asm-arm/arch-shark/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-shark/CVS/Root Thu Jul 5 12:04:43 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-arm/arch-tbox/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/arch-tbox/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/arch-tbox/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-tbox/CVS/Entries Thu Jul 5 12:04:43 2001 @@ -0,0 +1,16 @@ +/dma.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/hardware.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/ide.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/io.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/irq.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/irqs.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/keyboard.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/memory.h/1.2/Sun Dec 17 19:15:00 2000/-ko/ +/param.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/serial.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/system.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/time.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/timex.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/uncompress.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/vmalloc.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/arch-tbox/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/arch-tbox/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/arch-tbox/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-tbox/CVS/Repository Thu Jul 5 12:04:43 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm/arch-tbox diff -rNu linux-2.4.7/linux/include/asm-arm/arch-tbox/CVS/Root linux-2.4-xfs/linux/include/asm-arm/arch-tbox/CVS/Root --- linux-2.4.7/linux/include/asm-arm/arch-tbox/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/arch-tbox/CVS/Root Thu Jul 5 12:04:43 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-arm/fcntl.h linux-2.4-xfs/linux/include/asm-arm/fcntl.h --- linux-2.4.7/linux/include/asm-arm/fcntl.h Fri Sep 22 16:21:19 2000 +++ linux-2.4-xfs/linux/include/asm-arm/fcntl.h Mon Oct 23 13:56:35 2000 @@ -20,6 +20,7 @@ #define O_NOFOLLOW 0100000 /* don't follow links */ #define O_DIRECT 0200000 /* direct disk access hint - currently ignored */ #define O_LARGEFILE 0400000 +#define O_INVISIBLE 01000000 /* invisible I/O, for DMAPI/XDSM */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff -rNu linux-2.4.7/linux/include/asm-arm/hardware/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/hardware/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/hardware/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/hardware/CVS/Entries Thu Jul 5 12:04:44 2001 @@ -0,0 +1,10 @@ +/amba_kmi.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/clps7111.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/dec21285.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/ep7212.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/ioc.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/iomd.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/memc.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/pci_v3.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/serial_amba.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/hardware/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/hardware/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/hardware/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/hardware/CVS/Repository Thu Jul 5 12:04:43 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm/hardware diff -rNu linux-2.4.7/linux/include/asm-arm/hardware/CVS/Root linux-2.4-xfs/linux/include/asm-arm/hardware/CVS/Root --- linux-2.4.7/linux/include/asm-arm/hardware/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/hardware/CVS/Root Thu Jul 5 12:04:43 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-arm/kdb.h linux-2.4-xfs/linux/include/asm-arm/kdb.h --- linux-2.4.7/linux/include/asm-arm/kdb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/kdb.h Wed Oct 4 06:42:46 2000 @@ -0,0 +1,10 @@ +/* + * Dummy include/asm/kdb.h for arm. + */ +#if !defined(_ASM_KDB_H) +#define _ASM_KDB_H +#define KDB_ENTER() +struct pt_regs; +typedef struct pt_regs *kdb_eframe_t; +typedef unsigned long kdb_machreg_t; +#endif /* ASM_KDB_H */ diff -rNu linux-2.4.7/linux/include/asm-arm/mach/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/mach/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/mach/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/mach/CVS/Entries Thu Jul 5 12:04:44 2001 @@ -0,0 +1,7 @@ +/amba_kmi.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/arch.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/dma.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/irq.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/map.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/pci.h/1.3/Thu Jul 5 06:13:42 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/mach/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/mach/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/mach/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/mach/CVS/Repository Thu Jul 5 12:04:44 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm/mach diff -rNu linux-2.4.7/linux/include/asm-arm/mach/CVS/Root linux-2.4-xfs/linux/include/asm-arm/mach/CVS/Root --- linux-2.4.7/linux/include/asm-arm/mach/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/mach/CVS/Root Thu Jul 5 12:04:44 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-arm/proc-armo/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/proc-armo/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/proc-armo/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/proc-armo/CVS/Entries Thu Jul 5 12:04:44 2001 @@ -0,0 +1,14 @@ +/assembler.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/cache.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/elf.h/1.4/Tue May 2 22:18:18 2000/-ko/ +/locks.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/page.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/pgalloc.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/pgtable.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/processor.h/1.8/Sun Dec 17 19:15:00 2000/-ko/ +/ptrace.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/shmparam.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/system.h/1.9/Thu Jun 28 05:21:16 2001/-ko/ +/uaccess.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/uncompress.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/proc-armo/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/proc-armo/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/proc-armo/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/proc-armo/CVS/Repository Thu Jul 5 12:04:44 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm/proc-armo diff -rNu linux-2.4.7/linux/include/asm-arm/proc-armo/CVS/Root linux-2.4-xfs/linux/include/asm-arm/proc-armo/CVS/Root --- linux-2.4.7/linux/include/asm-arm/proc-armo/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/proc-armo/CVS/Root Thu Jul 5 12:04:44 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-arm/proc-armv/CVS/Entries linux-2.4-xfs/linux/include/asm-arm/proc-armv/CVS/Entries --- linux-2.4.7/linux/include/asm-arm/proc-armv/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/proc-armv/CVS/Entries Thu Jul 5 12:04:45 2001 @@ -0,0 +1,15 @@ +/assembler.h/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/cache.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/domain.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/elf.h/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/locks.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/page.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/pgalloc.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/pgtable.h/1.12/Wed May 2 06:22:13 2001/-ko/ +/processor.h/1.8/Sun Dec 17 19:15:00 2000/-ko/ +/ptrace.h/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/shmparam.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/system.h/1.11/Thu Jun 28 05:21:16 2001/-ko/ +/uaccess.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/uncompress.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-arm/proc-armv/CVS/Repository linux-2.4-xfs/linux/include/asm-arm/proc-armv/CVS/Repository --- linux-2.4.7/linux/include/asm-arm/proc-armv/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/proc-armv/CVS/Repository Thu Jul 5 12:04:44 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-arm/proc-armv diff -rNu linux-2.4.7/linux/include/asm-arm/proc-armv/CVS/Root linux-2.4-xfs/linux/include/asm-arm/proc-armv/CVS/Root --- linux-2.4.7/linux/include/asm-arm/proc-armv/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-arm/proc-armv/CVS/Root Thu Jul 5 12:04:44 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-cris/CVS/Entries linux-2.4-xfs/linux/include/asm-cris/CVS/Entries --- linux-2.4.7/linux/include/asm-cris/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-cris/CVS/Entries Thu Jul 5 12:04:49 2001 @@ -0,0 +1,79 @@ +/a.out.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/atomic.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/axisflashmap.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/bitops.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/bugs.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/byteorder.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/cache.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/checksum.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/current.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/delay.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/div64.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/dma.h/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/elf.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/errno.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/eshlibld.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/etraxgpio.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/etraxi2c.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/fcntl.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/hardirq.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/hdreg.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ide.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/io.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/ioctl.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ioctls.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ipc.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ipcbuf.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/irq.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/locks.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/mman.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/mmu.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/mmu_context.h/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/module.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/msgbuf.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/namei.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/page.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/param.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/pci.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/pgalloc.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/pgtable.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/poll.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/posix_types.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/processor.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/ptrace.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/resource.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/rtc.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/segment.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/semaphore-helper.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/semaphore.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/sembuf.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/setup.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/shmbuf.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/shmparam.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/sigcontext.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/siginfo.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/signal.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/smp.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/smp_lock.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/smplock.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/socket.h/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/sockios.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/softirq.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/stat.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/statfs.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/string.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/sv_addr.agh/1.2/Wed May 2 06:22:13 2001/-ko/ +/sv_addr_ag.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/svinto.h/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/sync_serial.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/system.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/termbits.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/termios.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/timex.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/types.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/uaccess.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ucontext.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/unaligned.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/unistd.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/user.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-cris/CVS/Repository linux-2.4-xfs/linux/include/asm-cris/CVS/Repository --- linux-2.4.7/linux/include/asm-cris/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-cris/CVS/Repository Thu Jul 5 12:04:45 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-cris diff -rNu linux-2.4.7/linux/include/asm-cris/CVS/Root linux-2.4-xfs/linux/include/asm-cris/CVS/Root --- linux-2.4.7/linux/include/asm-cris/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-cris/CVS/Root Thu Jul 5 12:04:45 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-cris/delay.h linux-2.4-xfs/linux/include/asm-cris/delay.h --- linux-2.4.7/linux/include/asm-cris/delay.h Thu Jul 5 10:49:38 2001 +++ linux-2.4-xfs/linux/include/asm-cris/delay.h Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: delay.h,v 1.4 2001/05/31 06:40:53 markusl Exp $ */ +/* $Id: delay.h,v 1.3 2001/02/23 13:47:33 bjornw Exp $ */ #ifndef _CRIS_DELAY_H #define _CRIS_DELAY_H diff -rNu linux-2.4.7/linux/include/asm-cris/dma.h linux-2.4-xfs/linux/include/asm-cris/dma.h --- linux-2.4.7/linux/include/asm-cris/dma.h Thu Jul 5 10:49:38 2001 +++ linux-2.4-xfs/linux/include/asm-cris/dma.h Thu Jul 5 00:29:17 2001 @@ -1,4 +1,4 @@ -/* $Id: dma.h,v 1.2 2001/05/09 12:17:42 johana Exp $ +/* $Id: dma.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ * linux/include/asm/dma.h: Defines for using and allocating dma channels. */ diff -rNu linux-2.4.7/linux/include/asm-cris/irq.h linux-2.4-xfs/linux/include/asm-cris/irq.h --- linux-2.4.7/linux/include/asm-cris/irq.h Thu Jul 5 10:49:38 2001 +++ linux-2.4-xfs/linux/include/asm-cris/irq.h Thu Jul 5 00:29:17 2001 @@ -5,7 +5,7 @@ * * Authors: Bjorn Wesen (bjornw@axis.com) * - * $Id: irq.h,v 1.11 2001/06/01 14:57:17 starvik Exp $ + * $Id$ */ #ifndef _ASM_IRQ_H diff -rNu linux-2.4.7/linux/include/asm-cris/semaphore.h linux-2.4-xfs/linux/include/asm-cris/semaphore.h --- linux-2.4.7/linux/include/asm-cris/semaphore.h Thu Jul 5 10:49:38 2001 +++ linux-2.4-xfs/linux/include/asm-cris/semaphore.h Wed May 2 01:22:13 2001 @@ -1,4 +1,4 @@ -/* $Id: semaphore.h,v 1.3 2001/05/08 13:54:09 bjornw Exp $ */ +/* $Id: semaphore.h,v 1.2 2000/07/13 16:52:46 bjornw Exp $ */ /* On the i386 these are coded in asm, perhaps we should as well. Later.. */ diff -rNu linux-2.4.7/linux/include/asm-generic/CVS/Entries linux-2.4-xfs/linux/include/asm-generic/CVS/Entries --- linux-2.4.7/linux/include/asm-generic/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-generic/CVS/Entries Thu Jul 5 12:04:49 2001 @@ -0,0 +1,7 @@ +/bitops.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/kdb.h/1.2/Wed Oct 4 11:42:46 2000/-ko/ +/pgtable.h/1.2/Sun Dec 17 19:15:00 2000/-ko/ +/smplock.h/1.4/Fri Mar 24 21:32:44 2000/-ko/ +/unaligned.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/xor.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-generic/CVS/Repository linux-2.4-xfs/linux/include/asm-generic/CVS/Repository --- linux-2.4.7/linux/include/asm-generic/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-generic/CVS/Repository Thu Jul 5 12:04:49 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-generic diff -rNu linux-2.4.7/linux/include/asm-generic/CVS/Root linux-2.4-xfs/linux/include/asm-generic/CVS/Root --- linux-2.4.7/linux/include/asm-generic/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-generic/CVS/Root Thu Jul 5 12:04:49 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-generic/kdb.h linux-2.4-xfs/linux/include/asm-generic/kdb.h --- linux-2.4.7/linux/include/asm-generic/kdb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-generic/kdb.h Wed Oct 4 06:42:46 2000 @@ -0,0 +1,10 @@ +/* + * Dummy include/asm/kdb.h for generic. + */ +#if !defined(_ASM_KDB_H) +#define _ASM_KDB_H +#define KDB_ENTER() +struct pt_regs; +typedef struct pt_regs *kdb_eframe_t; +typedef unsigned long kdb_machreg_t; +#endif /* ASM_KDB_H */ diff -rNu linux-2.4.7/linux/include/asm-i386/CVS/Entries linux-2.4-xfs/linux/include/asm-i386/CVS/Entries --- linux-2.4.7/linux/include/asm-i386/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-i386/CVS/Entries Thu Jul 5 12:04:54 2001 @@ -0,0 +1,109 @@ +/a.out.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/apic.h/1.10/Sun Dec 17 19:15:00 2000/-ko/ +/apicdef.h/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/atomic.h/1.11/Wed May 2 06:22:13 2001/-ko/ +/bitops.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/boot.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/bugs.h/1.14/Thu Feb 1 17:10:24 2001/-ko/ +/byteorder.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cache.h/1.6/Wed Nov 1 21:35:42 2000/-ko/ +/checksum.h/1.4/Tue Feb 1 23:02:54 2000/-ko/ +/cobalt.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cpufeature.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/current.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/debugreg.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/delay.h/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/desc.h/1.6/Thu Dec 21 05:48:12 2000/-ko/ +/div64.h/1.1/Fri Nov 12 18:56:11 1999/-ko/ +/dma.h/1.4/Wed Sep 15 22:45:13 1999/-ko/ +/e820.h/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/elf.h/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/errno.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/fcntl.h/1.7/Tue Feb 27 16:13:07 2001/-ko/ +/fixmap.h/1.7/Fri Jan 21 19:20:14 2000/-ko/ +/floppy.h/1.5/Fri Jan 5 18:42:30 2001/-ko/ +/hardirq.h/1.14/Sat Jun 9 02:44:24 2001/-ko/ +/hdreg.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/highmem.h/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/hw_irq.h/1.18/Thu Jun 21 15:45:04 2001/-ko/ +/i387.h/1.4/Thu Feb 1 17:10:24 2001/-ko/ +/ide.h/1.6/Fri Jun 2 00:22:59 2000/-ko/ +/init.h/1.3/Sun Aug 29 02:28:51 1999/-ko/ +/io.h/1.14/Wed May 2 06:22:13 2001/-ko/ +/io_apic.h/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/ioctl.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ioctls.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ipc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ipcbuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/irq.h/1.3/Tue Oct 12 19:12:19 1999/-ko/ +/kdb.h/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/kdbprivate.h/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/keyboard.h/1.7/Wed Oct 4 11:42:46 2000/-ko/ +/kmap_types.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/ldt.h/1.3/Tue Jul 27 20:02:32 1999/-ko/ +/linux_logo.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/lithium.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/locks.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/math_emu.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mc146818rtc.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/mca_dma.h/1.5/Wed Jun 13 03:24:09 2001/-ko/ +/mman.h/1.3/Wed Mar 15 18:20:34 2000/-ko/ +/mmu.h/1.1/Thu Dec 21 05:48:12 2000/-ko/ +/mmu_context.h/1.12/Wed Jan 3 01:43:05 2001/-ko/ +/mmx.h/1.2/Tue Nov 2 22:58:37 1999/-ko/ +/module.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/mpspec.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/msgbuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/msr.h/1.8/Sun Dec 17 19:15:00 2000/-ko/ +/mtrr.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/namei.h/1.3/Fri Apr 21 16:16:46 2000/-ko/ +/page.h/1.15/Sun Dec 17 19:15:00 2000/-ko/ +/param.h/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/parport.h/1.6/Wed Mar 15 18:20:34 2000/-ko/ +/pci.h/1.9/Thu Jun 21 15:45:04 2001/-ko/ +/pgalloc.h/1.9/Wed May 2 06:22:13 2001/-ko/ +/pgtable-2level.h/1.6/Wed Nov 1 21:35:42 2000/-ko/ +/pgtable-3level.h/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/pgtable.h/1.26/Mon Apr 2 17:13:32 2001/-ko/ +/poll.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/posix_types.h/1.4/Fri Jan 21 19:20:14 2000/-ko/ +/processor.h/1.23/Thu Jul 5 06:13:42 2001/-ko/ +/ptrace.h/1.7/Wed Nov 1 21:35:42 2000/-ko/ +/resource.h/1.7/Mon Oct 23 18:56:35 2000/-ko/ +/rwlock.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/rwsem.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/scatterlist.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/segment.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/semaphore.h/1.14/Wed May 2 06:22:13 2001/-ko/ +/sembuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/serial.h/1.3/Mon Sep 6 21:49:56 1999/-ko/ +/setup.h/1.2/Mon Nov 15 18:18:49 1999/-ko/ +/shmbuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/shmparam.h/1.3/Mon Nov 8 22:55:41 1999/-ko/ +/sigcontext.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/siginfo.h/1.5/Fri Jun 2 00:22:59 2000/-ko/ +/signal.h/1.4/Wed Nov 24 20:36:16 1999/-ko/ +/smp.h/1.9/Sun Feb 27 22:49:22 2000/-ko/ +/smplock.h/1.9/Mon Jun 12 22:19:02 2000/-ko/ +/socket.h/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/sockios.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/softirq.h/1.8/Thu Jun 21 15:45:04 2001/-ko/ +/spinlock.h/1.19/Sun Dec 17 19:15:00 2000/-ko/ +/stat.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/statfs.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/string-486.h/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/string.h/1.10/Wed May 2 06:22:13 2001/-ko/ +/system.h/1.17/Tue May 29 19:53:13 2001/-ko/ +/termbits.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/termios.h/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/timex.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/types.h/1.3/Sat Jan 29 23:15:44 2000/-ko/ +/uaccess.h/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/ucontext.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/unaligned.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/unistd.h/1.15/Thu Feb 1 04:38:20 2001/-ko/ +/user.h/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/vga.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/vm86.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/xor.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-i386/CVS/Repository linux-2.4-xfs/linux/include/asm-i386/CVS/Repository --- linux-2.4.7/linux/include/asm-i386/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-i386/CVS/Repository Thu Jul 5 12:04:49 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-i386 diff -rNu linux-2.4.7/linux/include/asm-i386/CVS/Root linux-2.4-xfs/linux/include/asm-i386/CVS/Root --- linux-2.4.7/linux/include/asm-i386/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-i386/CVS/Root Thu Jul 5 12:04:49 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-i386/apic.h linux-2.4-xfs/linux/include/asm-i386/apic.h --- linux-2.4.7/linux/include/asm-i386/apic.h Tue Jul 3 17:42:55 2001 +++ linux-2.4-xfs/linux/include/asm-i386/apic.h Sun Dec 17 13:15:00 2000 @@ -2,6 +2,7 @@ #define __ASM_APIC_H #include +#include #include #include @@ -75,6 +76,67 @@ extern void init_apic_mappings(void); extern void smp_local_timer_interrupt(struct pt_regs * regs); extern void setup_APIC_clocks(void); -#endif + +/* NMI watchdog is driven from the IO-APIC or from the local APIC. NMI + * related data has to be defined somewhere, may as well be here. + * Keith Owens. + */ + +extern int nmi_watchdog, proc_nmi_watchdog, nmi_watchdog_source; +extern int set_nmi_watchdog(int); +extern int setup_apic_nmi_watchdog(int); +extern int set_nmi_counter_local(void); + +#endif /* CONFIG_X86_LOCAL_APIC */ + +/* + * {rd,wr}msr_eio by HPA, moved from arch/i386/msr.c to here. + * Keith Owens. + */ + +/* Note: "err" is handled in a funny way below. Otherwise one version + of gcc or another breaks. */ + +extern inline int wrmsr_eio(u32 reg, u32 eax, u32 edx) +{ + int err; + + asm volatile( + "1: wrmsr\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl %4,%0\n" + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,3b\n" + ".previous" + : "=&bDS" (err) + : "a" (eax), "d" (edx), "c" (reg), "i" (-EIO), "0" (0)); + + return err; +} + +extern inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx) +{ + int err; + + asm volatile( + "1: rdmsr\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: movl %4,%0\n" + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,3b\n" + ".previous" + : "=&bDS" (err), "=a" (*eax), "=d" (*edx) + : "c" (reg), "i" (-EIO), "0" (0)); + + return err; +} #endif diff -rNu linux-2.4.7/linux/include/asm-i386/fcntl.h linux-2.4-xfs/linux/include/asm-i386/fcntl.h --- linux-2.4.7/linux/include/asm-i386/fcntl.h Fri Sep 22 16:21:19 2000 +++ linux-2.4-xfs/linux/include/asm-i386/fcntl.h Tue Feb 27 10:13:07 2001 @@ -20,6 +20,7 @@ #define O_LARGEFILE 0100000 #define O_DIRECTORY 0200000 /* must be a directory */ #define O_NOFOLLOW 0400000 /* don't follow links */ +#define O_INVISIBLE 02000000 /* invisible I/O, for DMAPI/XDSM */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff -rNu linux-2.4.7/linux/include/asm-i386/hw_irq.h linux-2.4-xfs/linux/include/asm-i386/hw_irq.h --- linux-2.4.7/linux/include/asm-i386/hw_irq.h Tue Jul 3 17:42:54 2001 +++ linux-2.4-xfs/linux/include/asm-i386/hw_irq.h Thu Jun 21 10:45:04 2001 @@ -23,6 +23,7 @@ #define FIRST_EXTERNAL_VECTOR 0x20 #define SYSCALL_VECTOR 0x80 +#define KDBENTER_VECTOR 0x81 /* * Vectors 0x20-0x2f are used for ISA interrupts. @@ -42,6 +43,7 @@ #define INVALIDATE_TLB_VECTOR 0xfd #define RESCHEDULE_VECTOR 0xfc #define CALL_FUNCTION_VECTOR 0xfb +#define KDB_VECTOR 0xfa /* * Local APIC timer IRQ vector is on a different priority level, diff -rNu linux-2.4.7/linux/include/asm-i386/kdb.h linux-2.4-xfs/linux/include/asm-i386/kdb.h --- linux-2.4.7/linux/include/asm-i386/kdb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-i386/kdb.h Thu Feb 22 15:09:04 2001 @@ -0,0 +1,62 @@ +/* + * Minimalist Kernel Debugger + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * + * See the file LIA-COPYRIGHT for additional information. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Richard Bass 1999/07/20 + * Many bug fixes and enhancements. + * Scott Foehner + * Port to ia64 + * Scott Lurndal 1999/12/12 + * v1.0 restructuring. + */ +#if !defined(_ASM_KDB_H) +#define _ASM_KDB_H + + /* + * KDB_ENTER() is a macro which causes entry into the kernel + * debugger from any point in the kernel code stream. If it + * is intended to be used from interrupt level, it must use + * a non-maskable entry method. + */ +#define KDB_ENTER() asm("\tint $129\n") + + /* + * Define the exception frame for this architeture + */ +struct pt_regs; +typedef struct pt_regs *kdb_eframe_t; + + /* + * Needed for exported symbols. + */ +typedef unsigned long kdb_machreg_t; + +#define kdb_machreg_fmt "0x%lx" +#define kdb_machreg_fmt0 "0x%08lx" +#define kdb_bfd_vma_fmt "0x%lx" +#define kdb_bfd_vma_fmt0 "0x%08lx" +#define kdb_elfw_addr_fmt "0x%x" +#define kdb_elfw_addr_fmt0 "0x%08x" + + /* + * Per cpu arch specific kdb state. Must be in range 0xff000000. + */ +#define KDB_STATE_A_IF 0x01000000 /* Saved IF flag */ + + /* + * Interface from kernel trap handling code to kernel debugger. + */ +extern int kdba_callback_die(struct pt_regs *, int, long, void*); +extern int kdba_callback_bp(struct pt_regs *, int, long, void*); +extern int kdba_callback_debug(struct pt_regs *, int, long, void *); + +#endif /* ASM_KDB_H */ diff -rNu linux-2.4.7/linux/include/asm-i386/kdbprivate.h linux-2.4-xfs/linux/include/asm-i386/kdbprivate.h --- linux-2.4.7/linux/include/asm-i386/kdbprivate.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-i386/kdbprivate.h Thu Feb 22 15:09:04 2001 @@ -0,0 +1,178 @@ +/* + * Minimalist Kernel Debugger + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * + * See the file LIA-COPYRIGHT for additional information. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Richard Bass 1999/07/20 + * Many bug fixes and enhancements. + * Scott Foehner + * Port to ia64 + * Scott Lurndal 1999/12/12 + * v1.0 restructuring. + * Keith Owens 2000/05/23 + * KDB v1.2 + */ +#if !defined(_ASM_KDBPRIVATE_H) +#define _ASM_KDBPRIVATE_H + +typedef unsigned char kdb_machinst_t; + + /* + * KDB_MAXBPT describes the total number of breakpoints + * supported by this architecure. + */ +#define KDB_MAXBPT 16 + /* + * KDB_MAXHARDBPT describes the total number of hardware + * breakpoint registers that exist. + */ +#define KDB_MAXHARDBPT 4 + /* + * Provide space for KDB_MAX_COMMANDS commands. + */ +#define KDB_MAX_COMMANDS 125 + + /* + * Platform specific environment entries + */ +#define KDB_PLATFORM_ENV "IDMODE=x86", "BYTESPERWORD=4", "IDCOUNT=16" + + /* + * Define the direction that the stack grows + */ +#define KDB_STACK_DIRECTION -1 /* Stack grows down */ + + /* + * Support for ia32 debug registers + */ +typedef struct _kdbhard_bp { + kdb_machreg_t bph_reg; /* Register this breakpoint uses */ + + unsigned int bph_free:1; /* Register available for use */ + unsigned int bph_data:1; /* Data Access breakpoint */ + + unsigned int bph_write:1; /* Write Data breakpoint */ + unsigned int bph_mode:2; /* 0=inst, 1=write, 2=io, 3=read */ + unsigned int bph_length:2; /* 0=1, 1=2, 2=BAD, 3=4 (bytes) */ +} kdbhard_bp_t; + +extern kdbhard_bp_t kdb_hardbreaks[/* KDB_MAXHARDBPT */]; + +#define IA32_BREAKPOINT_INSTRUCTION 0xcc + +#define DR6_BT 0x00008000 +#define DR6_BS 0x00004000 +#define DR6_BD 0x00002000 + +#define DR6_B3 0x00000008 +#define DR6_B2 0x00000004 +#define DR6_B1 0x00000002 +#define DR6_B0 0x00000001 + +#define DR7_RW_VAL(dr, drnum) \ + (((dr) >> (16 + (4 * (drnum)))) & 0x3) + +#define DR7_RW_SET(dr, drnum, rw) \ + do { \ + (dr) &= ~(0x3 << (16 + (4 * (drnum)))); \ + (dr) |= (((rw) & 0x3) << (16 + (4 * (drnum)))); \ + } while (0) + +#define DR7_RW0(dr) DR7_RW_VAL(dr, 0) +#define DR7_RW0SET(dr,rw) DR7_RW_SET(dr, 0, rw) +#define DR7_RW1(dr) DR7_RW_VAL(dr, 1) +#define DR7_RW1SET(dr,rw) DR7_RW_SET(dr, 1, rw) +#define DR7_RW2(dr) DR7_RW_VAL(dr, 2) +#define DR7_RW2SET(dr,rw) DR7_RW_SET(dr, 2, rw) +#define DR7_RW3(dr) DR7_RW_VAL(dr, 3) +#define DR7_RW3SET(dr,rw) DR7_RW_SET(dr, 3, rw) + + +#define DR7_LEN_VAL(dr, drnum) \ + (((dr) >> (18 + (4 * (drnum)))) & 0x3) + +#define DR7_LEN_SET(dr, drnum, rw) \ + do { \ + (dr) &= ~(0x3 << (18 + (4 * (drnum)))); \ + (dr) |= (((rw) & 0x3) << (18 + (4 * (drnum)))); \ + } while (0) +#define DR7_LEN0(dr) DR7_LEN_VAL(dr, 0) +#define DR7_LEN0SET(dr,len) DR7_LEN_SET(dr, 0, len) +#define DR7_LEN1(dr) DR7_LEN_VAL(dr, 1) +#define DR7_LEN1SET(dr,len) DR7_LEN_SET(dr, 1, len) +#define DR7_LEN2(dr) DR7_LEN_VAL(dr, 2) +#define DR7_LEN2SET(dr,len) DR7_LEN_SET(dr, 2, len) +#define DR7_LEN3(dr) DR7_LEN_VAL(dr, 3) +#define DR7_LEN3SET(dr,len) DR7_LEN_SET(dr, 3, len) + +#define DR7_G0(dr) (((dr)>>1)&0x1) +#define DR7_G0SET(dr) ((dr) |= 0x2) +#define DR7_G0CLR(dr) ((dr) &= ~0x2) +#define DR7_G1(dr) (((dr)>>3)&0x1) +#define DR7_G1SET(dr) ((dr) |= 0x8) +#define DR7_G1CLR(dr) ((dr) &= ~0x8) +#define DR7_G2(dr) (((dr)>>5)&0x1) +#define DR7_G2SET(dr) ((dr) |= 0x20) +#define DR7_G2CLR(dr) ((dr) &= ~0x20) +#define DR7_G3(dr) (((dr)>>7)&0x1) +#define DR7_G3SET(dr) ((dr) |= 0x80) +#define DR7_G3CLR(dr) ((dr) &= ~0x80) + +#define DR7_L0(dr) (((dr))&0x1) +#define DR7_L0SET(dr) ((dr) |= 0x1) +#define DR7_L0CLR(dr) ((dr) &= ~0x1) +#define DR7_L1(dr) (((dr)>>2)&0x1) +#define DR7_L1SET(dr) ((dr) |= 0x4) +#define DR7_L1CLR(dr) ((dr) &= ~0x4) +#define DR7_L2(dr) (((dr)>>4)&0x1) +#define DR7_L2SET(dr) ((dr) |= 0x10) +#define DR7_L2CLR(dr) ((dr) &= ~0x10) +#define DR7_L3(dr) (((dr)>>6)&0x1) +#define DR7_L3SET(dr) ((dr) |= 0x40) +#define DR7_L3CLR(dr) ((dr) &= ~0x40) + +#define DR7_GD 0x00002000 /* General Detect Enable */ +#define DR7_GE 0x00000200 /* Global exact */ +#define DR7_LE 0x00000100 /* Local exact */ + +extern kdb_machreg_t kdba_getdr6(void); +extern void kdba_putdr6(kdb_machreg_t); + +extern kdb_machreg_t kdba_getdr7(void); + +extern kdb_machreg_t kdba_getdr(int); +extern void kdba_putdr(int, kdb_machreg_t); + +extern kdb_machreg_t kdb_getcr(int); + +#define KDB_HAVE_LONGJMP +#ifdef KDB_HAVE_LONGJMP +/* + * Support for setjmp/longjmp + */ +#define JB_BX 0 +#define JB_SI 1 +#define JB_DI 2 +#define JB_BP 3 +#define JB_SP 4 +#define JB_PC 5 + +typedef struct __kdb_jmp_buf { + unsigned long regs[6]; /* kdb_setjmp assumes fixed offsets here */ +} kdb_jmp_buf; + +extern int kdb_setjmp(kdb_jmp_buf *); +extern void kdb_longjmp(kdb_jmp_buf *, int); + +extern kdb_jmp_buf kdbjmpbuf[]; +#endif /* KDB_HAVE_LONGJMP */ + +#endif /* !_ASM_KDBPRIVATE_H */ diff -rNu linux-2.4.7/linux/include/asm-i386/keyboard.h linux-2.4-xfs/linux/include/asm-i386/keyboard.h --- linux-2.4.7/linux/include/asm-i386/keyboard.h Tue Jul 3 17:45:29 2001 +++ linux-2.4-xfs/linux/include/asm-i386/keyboard.h Wed Oct 4 06:42:46 2000 @@ -38,6 +38,7 @@ #define kbd_sysrq_xlate pckbd_sysrq_xlate #define SYSRQ_KEY 0x54 +#define E1_PAUSE 119 /* PAUSE key */ /* resource allocation */ #define kbd_request_region() diff -rNu linux-2.4.7/linux/include/asm-i386/msr.h linux-2.4-xfs/linux/include/asm-i386/msr.h --- linux-2.4.7/linux/include/asm-i386/msr.h Mon Dec 11 15:42:08 2000 +++ linux-2.4-xfs/linux/include/asm-i386/msr.h Sun Dec 17 13:15:00 2000 @@ -34,3 +34,22 @@ #define MSR_IA32_PLATFORM_ID 0x17 #define MSR_IA32_UCODE_WRITE 0x79 #define MSR_IA32_UCODE_REV 0x8B + +#define MCG_STATUS_MSR 0x17a +#define MCG_CAP 0x179 +#define MCG_CTL 0x17b +#define MC0_BASE 0x400 +#define MC0_CTL_OFFSET 0x0 +#define MC0_STATUS_OFFSET 0x1 +#define MC0_ADDR_OFFSET 0x2 +#define MC0_MISC_OFFSET 0x3 +#define MC0_BANK_COUNT 0x4 +#define DEBUGCTLMSR 0x1d9 +#define LASTBRANCHFROMIP 0x1db +#define LASTBRANCHTOIP 0x1dc +#define LASTINTFROMIP 0x1dd +#define LASTINTTOIP 0x1de +#define PERFCTR0 0xc1 +#define PERFCTR1 0xc2 +#define EVNTSEL0 0x186 +#define EVNTSEL1 0x187 diff -rNu linux-2.4.7/linux/include/asm-i386/ptrace.h linux-2.4-xfs/linux/include/asm-i386/ptrace.h --- linux-2.4.7/linux/include/asm-i386/ptrace.h Mon Oct 30 16:46:53 2000 +++ linux-2.4-xfs/linux/include/asm-i386/ptrace.h Wed Nov 1 15:35:42 2000 @@ -54,6 +54,29 @@ /* options set using PTRACE_SETOPTIONS */ #define PTRACE_O_TRACESYSGOOD 0x00000001 +enum EFLAGS { + EF_CF = 0x00000001, + EF_PF = 0x00000004, + EF_AF = 0x00000010, + EF_ZF = 0x00000040, + EF_SF = 0x00000080, + EF_TF = 0x00000100, + EF_IE = 0x00000200, + EF_DF = 0x00000400, + EF_OF = 0x00000800, + EF_IOPL = 0x00003000, + EF_IOPL_RING0 = 0x00000000, + EF_IOPL_RING1 = 0x00001000, + EF_IOPL_RING2 = 0x00002000, + EF_NT = 0x00004000, /* nested task */ + EF_RF = 0x00010000, /* resume */ + EF_VM = 0x00020000, /* virtual mode */ + EF_AC = 0x00040000, /* alignment */ + EF_VIF = 0x00080000, /* virtual interrupt */ + EF_VIP = 0x00100000, /* virtual interrupt pending */ + EF_ID = 0x00200000, /* id */ +}; + #ifdef __KERNEL__ #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs)) #define instruction_pointer(regs) ((regs)->eip) diff -rNu linux-2.4.7/linux/include/asm-i386/unistd.h linux-2.4-xfs/linux/include/asm-i386/unistd.h --- linux-2.4.7/linux/include/asm-i386/unistd.h Fri Aug 11 16:39:23 2000 +++ linux-2.4-xfs/linux/include/asm-i386/unistd.h Wed Jan 31 22:38:20 2001 @@ -227,6 +227,10 @@ #define __NR_madvise1 219 /* delete when C lib stub is removed */ #define __NR_getdents64 220 #define __NR_fcntl64 221 +#define __NR__attrctl 250 +#define __NR__acl_get 251 +#define __NR__acl_set 252 + /* user-visible error numbers are in the range -1 - -124: see */ diff -rNu linux-2.4.7/linux/include/asm-ia64/CVS/Entries linux-2.4-xfs/linux/include/asm-ia64/CVS/Entries --- linux-2.4.7/linux/include/asm-ia64/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/CVS/Entries Thu Jul 5 12:05:00 2001 @@ -0,0 +1,101 @@ +/a.out.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/acpi-ext.h/1.4/Fri Jan 5 18:42:30 2001/-ko/ +/acpikcfg.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/asmmacro.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/atomic.h/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/bitops.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/break.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/bugs.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/byteorder.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/cache.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/checksum.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/current.h/1.2/Tue May 2 22:18:18 2000/-ko/ +/delay.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/div64.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/dma.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/efi.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/elf.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/errno.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/fcntl.h/1.6/Tue Feb 27 16:13:07 2001/-ko/ +/fpswa.h/1.2/Mon Feb 14 19:32:36 2000/-ko/ +/fpu.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/hardirq.h/1.9/Wed May 2 06:22:13 2001/-ko/ +/hdreg.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/hw_irq.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/ia32.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/ide.h/1.5/Fri Jun 2 00:22:59 2000/-ko/ +/io.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/ioctl.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/ioctls.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/iosapic.h/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/ipc.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/ipcbuf.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/irq.h/1.2/Sat Mar 11 02:39:30 2000/-ko/ +/kdb.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/kdbprivate.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/keyboard.h/1.3/Tue May 2 22:18:18 2000/-ko/ +/kregs.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/linux_logo.h/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/machvec.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/machvec_dig.h/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/machvec_hpsim.h/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/machvec_init.h/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/machvec_sn1.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/mca.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/mca_asm.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/mman.h/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/mmu.h/1.1/Thu Dec 21 05:48:12 2000/-ko/ +/mmu_context.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/module.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/msgbuf.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/namei.h/1.2/Fri Apr 21 16:16:46 2000/-ko/ +/offsets.h/1.9/Wed May 2 06:22:13 2001/-ko/ +/page.h/1.9/Wed May 2 06:22:13 2001/-ko/ +/pal.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/param.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/parport.h/1.1/Wed Nov 1 21:35:42 2000/-ko/ +/pci.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/perfmon.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/pgalloc.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/pgtable.h/1.11/Wed May 2 06:22:13 2001/-ko/ +/poll.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/posix_types.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/processor.h/1.10/Wed May 2 06:22:13 2001/-ko/ +/ptrace.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/ptrace_offsets.h/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/resource.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/rse.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/sal.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/scatterlist.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/segment.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/semaphore.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/sembuf.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/serial.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/shmbuf.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/shmparam.h/1.2/Fri Jan 5 18:42:30 2001/-ko/ +/sigcontext.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/siginfo.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/signal.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/smp.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/smplock.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/socket.h/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/sockios.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/softirq.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/spinlock.h/1.6/Fri Jan 5 18:42:30 2001/-ko/ +/stat.h/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/statfs.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/string.h/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/system.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/termbits.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/termios.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/timex.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/types.h/1.3/Tue May 2 22:18:18 2000/-ko/ +/uaccess.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/ucontext.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/unaligned.h/1.2/Wed Nov 1 21:35:42 2000/-ko/ +/unistd.h/1.11/Mon Jul 2 03:31:14 2001/-ko/ +/unwind.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/user.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/vga.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/xor.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-ia64/CVS/Entries.Log linux-2.4-xfs/linux/include/asm-ia64/CVS/Entries.Log --- linux-2.4.7/linux/include/asm-ia64/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/CVS/Entries.Log Thu Jul 5 12:05:00 2001 @@ -0,0 +1 @@ +A D/sn//// diff -rNu linux-2.4.7/linux/include/asm-ia64/CVS/Repository linux-2.4-xfs/linux/include/asm-ia64/CVS/Repository --- linux-2.4.7/linux/include/asm-ia64/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/CVS/Repository Thu Jul 5 12:04:54 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-ia64 diff -rNu linux-2.4.7/linux/include/asm-ia64/CVS/Root linux-2.4-xfs/linux/include/asm-ia64/CVS/Root --- linux-2.4.7/linux/include/asm-ia64/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/CVS/Root Thu Jul 5 12:04:54 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-ia64/fcntl.h linux-2.4-xfs/linux/include/asm-ia64/fcntl.h --- linux-2.4.7/linux/include/asm-ia64/fcntl.h Mon Oct 9 19:54:58 2000 +++ linux-2.4-xfs/linux/include/asm-ia64/fcntl.h Tue Feb 27 10:13:07 2001 @@ -28,6 +28,7 @@ #define O_LARGEFILE 0100000 #define O_DIRECTORY 0200000 /* must be a directory */ #define O_NOFOLLOW 0400000 /* don't follow links */ +#define O_INVISIBLE 02000000 /* invisible I/O, for DMAPI/XDSM */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff -rNu linux-2.4.7/linux/include/asm-ia64/kdb.h linux-2.4-xfs/linux/include/asm-ia64/kdb.h --- linux-2.4.7/linux/include/asm-ia64/kdb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/kdb.h Thu Feb 22 15:09:04 2001 @@ -0,0 +1,54 @@ +/* + * Minimalist Kernel Debugger + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * + * See the file LIA-COPYRIGHT for additional information. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Richard Bass 1999/07/20 + * Many bug fixes and enhancements. + * Scott Foehner + * Port to ia64 + * Scott Lurndal 1999/12/12 + * v1.0 restructuring. + */ +#if !defined(_ASM_KDB_H) +#define _ASM_KDB_H + + /* + * KDB_ENTER() is a macro which causes entry into the kernel + * debugger from any point in the kernel code stream. If it + * is intended to be used from interrupt level, it must use + * a non-maskable entry method. + */ +#define KDB_BREAK_BREAK 0x80100 /* kdb breakpoint in kernel */ +#define KDB_BREAK_ENTER 0x80101 /* KDB_ENTER() */ +#define KDB_ENTER2(b) asm("\tbreak "#b"\n") +#define KDB_ENTER1(b) KDB_ENTER2(b) +#define KDB_ENTER() KDB_ENTER1(KDB_BREAK_ENTER) + + /* + * Define the exception frame for this architeture + */ +struct pt_regs; +typedef struct pt_regs *kdb_eframe_t; + + /* + * Needed for exported symbols. + */ +typedef unsigned long kdb_machreg_t; + +#define kdb_machreg_fmt "0x%lx" +#define kdb_machreg_fmt0 "0x%016lx" +#define kdb_bfd_vma_fmt "0x%llx" +#define kdb_bfd_vma_fmt0 "0x%016llx" +#define kdb_elfw_addr_fmt "0x%lx" +#define kdb_elfw_addr_fmt0 "0x%016lx" + +#endif /* ASM_KDB_H */ diff -rNu linux-2.4.7/linux/include/asm-ia64/kdbprivate.h linux-2.4-xfs/linux/include/asm-ia64/kdbprivate.h --- linux-2.4.7/linux/include/asm-ia64/kdbprivate.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/kdbprivate.h Thu Feb 22 15:09:04 2001 @@ -0,0 +1,119 @@ +/* + * Minimalist Kernel Debugger + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * + * See the file LIA-COPYRIGHT for additional information. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Richard Bass 1999/07/20 + * Many bug fixes and enhancements. + * Scott Foehner + * Port to ia64 + * Scott Lurndal 1999/12/12 + * v1.0 restructuring. + */ +#if !defined(_ASM_KDBPRIVATE_H) +#define _ASM_KDBPRIVATE_H + +/* Definition of an machine instruction. + * Takes care of VLIW processors like Itanium + */ + +typedef struct { + unsigned long inst[2]; + } kdb_machinst_t; + + /* + * KDB_MAXBPT describes the total number of breakpoints + * supported by this architecure. + */ +#define KDB_MAXBPT 16 + /* + * KDB_MAXHARDBPT describes the total number of hardware + * breakpoint registers that exist. + */ +#define KDB_MAXHARDBPT 4 + /* + * Provide space for KDB_MAX_COMMANDS commands. + */ +#define KDB_MAX_COMMANDS 125 + + /* + * Platform specific environment entries + */ +#define KDB_PLATFORM_ENV "IDMODE=ia64", "BYTESPERWORD=4", "IDCOUNT=8" + + /* + * Define the direction that the stack grows + */ +#define KDB_STACK_DIRECTION -1 /* Stack grows down */ + + /* + * Support for IA64 debug registers + */ +typedef struct _kdbhard_bp { + kdb_machreg_t bph_reg; /* Register this breakpoint uses */ + + unsigned int bph_free:1; /* Register available for use */ + unsigned int bph_data:1; /* Data Access breakpoint */ + + unsigned int bph_write:1; /* Write Data breakpoint */ + unsigned int bph_mode:2; /* 0=inst, 1=write, 2=io, 3=read */ + unsigned int bph_length:2; /* 0=1, 1=2, 2=BAD, 3=4 (bytes) */ +} kdbhard_bp_t; + +extern kdbhard_bp_t kdb_hardbreaks[/* KDB_MAXHARDBPT */]; + +#define getprsregs(regs) ((struct switch_stack *)regs -1) + +/* bkpt support using break inst instead of IBP reg */ + +/* + * Define certain specific instructions + */ +#define BREAK_INSTR (long)(KDB_BREAK_BREAK << (5+6)) +#define INST_SLOT0_MASK (0x1ffffffffffL << 5) + +#define BKPTMODE_DATAR 3 +#define BKPTMODE_IO 2 +#define BKPTMODE_DATAW 1 +#define BKPTMODE_INST 0 + +/* Some of the fault registers needed by kdb but not passed with + * regs or switch stack. + */ +typedef struct fault_regs { + unsigned long isr ; + unsigned long ifa ; + unsigned long iim ; + unsigned long itir ; +} fault_regs_t ; + +#ifdef KDB_HAVE_LONGJMP +/* + * Support for setjmp/longjmp + */ +#define JB_BX 0 +#define JB_SI 1 +#define JB_DI 2 +#define JB_BP 3 +#define JB_SP 4 +#define JB_PC 5 + +typedef struct __kdb_jmp_buf { + unsigned long regs[6]; +} kdb_jmp_buf; + +extern int kdb_setjmp(kdb_jmp_buf *); +extern void kdb_longjmp(kdb_jmp_buf *, int); + +extern kdb_jmp_buf kdbjmpbuf[]; +#endif /* KDB_HAVE_LONGJMP */ + +#endif /* !_ASM_KDBPRIVATE_H */ diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/CVS/Entries linux-2.4-xfs/linux/include/asm-ia64/sn/CVS/Entries --- linux-2.4.7/linux/include/asm-ia64/sn/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/CVS/Entries Thu Jul 5 12:05:02 2001 @@ -0,0 +1,50 @@ +/addrs.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/agent.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/alenlist.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/arch.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/cdl.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/clksupport.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/dmamap.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/driver.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/eeprom.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/gda.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/hack.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/hcl.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/hcl_util.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/hubspc.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/hwcntrs.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/intr.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/intr_public.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/invent.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/io.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/iobus.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/ioc3.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/ioerror.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/ioerror_handling.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/iograph.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/klconfig.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/kldir.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/labelcl.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/mem_refcnt.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/mmzone.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/mmzone_default.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/mmzone_sn1.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/module.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/nic.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/nodemask.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/nodepda.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/pio.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/prio.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/router.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/sgi.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/slotnum.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/sn_cpuid.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/sn_fru.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/sn_private.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/sn_sal.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/sv.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/synergy.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/systeminfo.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/types.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/vector.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/CVS/Entries.Log linux-2.4-xfs/linux/include/asm-ia64/sn/CVS/Entries.Log --- linux-2.4.7/linux/include/asm-ia64/sn/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/CVS/Entries.Log Thu Jul 5 12:05:15 2001 @@ -0,0 +1,5 @@ +A D/arc//// +A D/ksys//// +A D/pci//// +A D/sn1//// +A D/xtalk//// diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/CVS/Repository linux-2.4-xfs/linux/include/asm-ia64/sn/CVS/Repository --- linux-2.4.7/linux/include/asm-ia64/sn/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/CVS/Repository Thu Jul 5 12:05:00 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-ia64/sn diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/CVS/Root linux-2.4-xfs/linux/include/asm-ia64/sn/CVS/Root --- linux-2.4.7/linux/include/asm-ia64/sn/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/CVS/Root Thu Jul 5 12:05:00 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/arc/CVS/Entries linux-2.4-xfs/linux/include/asm-ia64/sn/arc/CVS/Entries --- linux-2.4.7/linux/include/asm-ia64/sn/arc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/arc/CVS/Entries Thu Jul 5 12:05:02 2001 @@ -0,0 +1,3 @@ +/hinv.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/types.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/arc/CVS/Repository linux-2.4-xfs/linux/include/asm-ia64/sn/arc/CVS/Repository --- linux-2.4.7/linux/include/asm-ia64/sn/arc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/arc/CVS/Repository Thu Jul 5 12:05:02 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-ia64/sn/arc diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/arc/CVS/Root linux-2.4-xfs/linux/include/asm-ia64/sn/arc/CVS/Root --- linux-2.4.7/linux/include/asm-ia64/sn/arc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/arc/CVS/Root Thu Jul 5 12:05:02 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/ksys/CVS/Entries linux-2.4-xfs/linux/include/asm-ia64/sn/ksys/CVS/Entries --- linux-2.4.7/linux/include/asm-ia64/sn/ksys/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/ksys/CVS/Entries Thu Jul 5 12:05:02 2001 @@ -0,0 +1,4 @@ +/elsc.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/i2c.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/l1.h/1.2/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/ksys/CVS/Repository linux-2.4-xfs/linux/include/asm-ia64/sn/ksys/CVS/Repository --- linux-2.4.7/linux/include/asm-ia64/sn/ksys/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/ksys/CVS/Repository Thu Jul 5 12:05:02 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-ia64/sn/ksys diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/ksys/CVS/Root linux-2.4-xfs/linux/include/asm-ia64/sn/ksys/CVS/Root --- linux-2.4.7/linux/include/asm-ia64/sn/ksys/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/ksys/CVS/Root Thu Jul 5 12:05:02 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/pci/CVS/Entries linux-2.4-xfs/linux/include/asm-ia64/sn/pci/CVS/Entries --- linux-2.4.7/linux/include/asm-ia64/sn/pci/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/pci/CVS/Entries Thu Jul 5 12:05:04 2001 @@ -0,0 +1,9 @@ +/bridge.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/pci_bus_cvlink.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/pci_defs.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/pciba.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/pcibr.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/pcibr_private.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/pciio.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/pciio_private.h/1.2/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/pci/CVS/Repository linux-2.4-xfs/linux/include/asm-ia64/sn/pci/CVS/Repository --- linux-2.4.7/linux/include/asm-ia64/sn/pci/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/pci/CVS/Repository Thu Jul 5 12:05:02 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-ia64/sn/pci diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/pci/CVS/Root linux-2.4-xfs/linux/include/asm-ia64/sn/pci/CVS/Root --- linux-2.4.7/linux/include/asm-ia64/sn/pci/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/pci/CVS/Root Thu Jul 5 12:05:02 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/sn1/CVS/Entries linux-2.4-xfs/linux/include/asm-ia64/sn/sn1/CVS/Entries --- linux-2.4.7/linux/include/asm-ia64/sn/sn1/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/sn1/CVS/Entries Thu Jul 5 12:05:15 2001 @@ -0,0 +1,25 @@ +/addrs.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/arch.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/bedrock.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/hubdev.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/hubio.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/hubio_next.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/hublb.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/hublb_next.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/hubmd.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/hubmd_next.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/hubni.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/hubni_next.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/hubpi.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/hubpi_next.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/hubxb.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/hubxb_next.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/ip27config.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/kldir.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/leds.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/promlog.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/router.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/slotnum.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/sn1.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/uart16550.h/1.2/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/sn1/CVS/Repository linux-2.4-xfs/linux/include/asm-ia64/sn/sn1/CVS/Repository --- linux-2.4.7/linux/include/asm-ia64/sn/sn1/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/sn1/CVS/Repository Thu Jul 5 12:05:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-ia64/sn/sn1 diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/sn1/CVS/Root linux-2.4-xfs/linux/include/asm-ia64/sn/sn1/CVS/Root --- linux-2.4.7/linux/include/asm-ia64/sn/sn1/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/sn1/CVS/Root Thu Jul 5 12:05:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/xtalk/CVS/Entries linux-2.4-xfs/linux/include/asm-ia64/sn/xtalk/CVS/Entries --- linux-2.4.7/linux/include/asm-ia64/sn/xtalk/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/xtalk/CVS/Entries Thu Jul 5 12:05:16 2001 @@ -0,0 +1,8 @@ +/xbow.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/xbow_info.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/xswitch.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +/xtalk.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/xtalk_private.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/xtalkaddrs.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/xwidget.h/1.1/Fri Jan 5 18:42:30 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/xtalk/CVS/Repository linux-2.4-xfs/linux/include/asm-ia64/sn/xtalk/CVS/Repository --- linux-2.4.7/linux/include/asm-ia64/sn/xtalk/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/xtalk/CVS/Repository Thu Jul 5 12:05:15 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-ia64/sn/xtalk diff -rNu linux-2.4.7/linux/include/asm-ia64/sn/xtalk/CVS/Root linux-2.4-xfs/linux/include/asm-ia64/sn/xtalk/CVS/Root --- linux-2.4.7/linux/include/asm-ia64/sn/xtalk/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ia64/sn/xtalk/CVS/Root Thu Jul 5 12:05:15 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-ia64/unistd.h linux-2.4-xfs/linux/include/asm-ia64/unistd.h --- linux-2.4.7/linux/include/asm-ia64/unistd.h Thu Jan 4 14:50:18 2001 +++ linux-2.4-xfs/linux/include/asm-ia64/unistd.h Sun Jul 1 22:31:14 2001 @@ -204,6 +204,9 @@ #define __NR_fstat 1212 #define __NR_clone2 1213 #define __NR_getdents64 1214 +#define __NR__attrctl 1260 +#define __NR__acl_get 1261 +#define __NR__acl_set 1262 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER) diff -rNu linux-2.4.7/linux/include/asm-m68k/CVS/Entries linux-2.4-xfs/linux/include/asm-m68k/CVS/Entries --- linux-2.4.7/linux/include/asm-m68k/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-m68k/CVS/Entries Thu Jul 5 12:05:22 2001 @@ -0,0 +1,154 @@ +/a.out.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/adb.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/adb_iop.h/1.1/Mon Feb 14 19:32:36 2000/-ko/ +/adb_mouse.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/amigahw.h/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/amigaints.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/amigayle.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/amipcmcia.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/apollodma.h/1.1/Sat Jan 29 23:15:44 2000/-ko/ +/apollohw.h/1.3/Sat Jan 29 23:15:44 2000/-ko/ +/atafd.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/atafdreg.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/atari_SCCserial.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/atari_SLM.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/atari_acsi.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/atari_joystick.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/atari_stdma.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/atari_stram.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/atarihw.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/atariints.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/atarikb.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/atomic.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/bitops.h/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/blinken.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/bootinfo.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/bugs.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/bvme6000hw.h/1.3/Sat Jan 29 23:15:44 2000/-ko/ +/byteorder.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cache.h/1.4/Sat Jan 29 23:15:44 2000/-ko/ +/cachectl.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/checksum.h/1.3/Tue Feb 1 23:02:54 2000/-ko/ +/contregs.h/1.1/Wed Jan 3 01:43:05 2001/-ko/ +/current.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/delay.h/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/div64.h/1.1/Sat Jan 29 23:15:44 2000/-ko/ +/dma.h/1.3/Sat Jan 29 23:15:44 2000/-ko/ +/dsp56k.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dvma.h/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/elf.h/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/entry.h/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/errno.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbio.h/1.1/Wed Jan 3 01:43:05 2001/-ko/ +/fcntl.h/1.7/Sun Dec 17 19:15:00 2000/-ko/ +/floppy.h/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/fpu.h/1.3/Sun Aug 29 03:09:59 1999/-ko/ +/hardirq.h/1.7/Wed Jan 3 01:43:05 2001/-ko/ +/hdreg.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/hwtest.h/1.3/Mon Sep 6 21:49:56 1999/-ko/ +/ide.h/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/idprom.h/1.1/Wed Jan 3 01:43:05 2001/-ko/ +/init.h/1.5/Tue Feb 1 23:02:54 2000/-ko/ +/intersil.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/io.h/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/ioctl.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ioctls.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ipc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ipcbuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/irq.h/1.5/Mon Feb 14 19:32:36 2000/-ko/ +/kbio.h/1.1/Wed Jan 3 01:43:05 2001/-ko/ +/kdb.h/1.2/Wed Oct 4 11:42:46 2000/-ko/ +/keyboard.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/linux_logo.h/1.4/Wed Jun 13 03:24:09 2001/-ko/ +/mac_asc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mac_baboon.h/1.1/Mon Feb 14 19:32:36 2000/-ko/ +/mac_iop.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/mac_mouse.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mac_oss.h/1.1/Wed Sep 15 20:42:56 1999/-ko/ +/mac_psc.h/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/mac_via.h/1.1/Wed Sep 15 20:42:56 1999/-ko/ +/machdep.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/machines.h/1.1/Wed Sep 15 20:42:56 1999/-ko/ +/machw.h/1.3/Wed Sep 15 20:42:56 1999/-ko/ +/macintosh.h/1.4/Mon Feb 14 19:32:36 2000/-ko/ +/macints.h/1.4/Mon Feb 14 19:32:36 2000/-ko/ +/math-emu.h/1.1/Sun Aug 29 03:09:59 1999/-ko/ +/mc146818rtc.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/md.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mman.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/mmu.h/1.1/Thu Dec 21 05:48:12 2000/-ko/ +/mmu_context.h/1.9/Wed Jan 3 01:43:05 2001/-ko/ +/module.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/motorola_pgalloc.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/motorola_pgtable.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/movs.h/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/msgbuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/mvme147hw.h/1.3/Sat Jan 29 23:15:44 2000/-ko/ +/mvme16xhw.h/1.3/Sat Jan 29 23:15:44 2000/-ko/ +/namei.h/1.3/Fri Apr 21 16:16:46 2000/-ko/ +/openprom.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/oplib.h/1.3/Wed Sep 15 20:42:56 1999/-ko/ +/page.h/1.9/Sun Dec 17 19:15:00 2000/-ko/ +/page_offset.h/1.1/Sat Jan 29 23:15:44 2000/-ko/ +/param.h/1.6/Fri Jan 5 18:42:30 2001/-ko/ +/parport.h/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/pci.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/pgalloc.h/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/pgtable.h/1.13/Sun Dec 17 19:15:00 2000/-ko/ +/poll.h/1.3/Sat Jan 29 23:15:44 2000/-ko/ +/posix_types.h/1.4/Fri Jan 21 19:20:14 2000/-ko/ +/processor.h/1.11/Wed Jan 3 01:43:05 2001/-ko/ +/ptrace.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/q40_keyboard.h/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/q40_master.h/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/q40ints.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/raw_io.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/resource.h/1.6/Mon Oct 23 18:56:35 2000/-ko/ +/rtc.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/sbus.h/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/scatterlist.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/segment.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/semaphore-helper.h/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/semaphore.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/sembuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/serial.h/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/setup.h/1.5/Sat Jan 29 23:15:44 2000/-ko/ +/shm.h/1.4/Mon Nov 15 18:18:49 1999/-ko/ +/shmbuf.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/shmparam.h/1.4/Mon Nov 8 22:55:41 1999/-ko/ +/sigcontext.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/siginfo.h/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/signal.h/1.3/Wed Nov 24 20:36:16 1999/-ko/ +/smplock.h/1.4/Fri Mar 24 21:32:44 2000/-ko/ +/socket.h/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/sockios.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/softirq.h/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/spinlock.h/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/stat.h/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/statfs.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/string.h/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/sun3-head.h/1.1/Wed Sep 15 20:42:56 1999/-ko/ +/sun3_pgalloc.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/sun3_pgtable.h/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/sun3ints.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/sun3mmu.h/1.1/Wed Sep 15 20:42:56 1999/-ko/ +/sun3x.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/sun3xflop.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/sun3xprom.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/swim_iop.h/1.1/Wed Sep 15 20:42:56 1999/-ko/ +/system.h/1.7/Sat Jun 9 02:44:24 2001/-ko/ +/termbits.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/termios.h/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/timex.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/traps.h/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/types.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/uaccess.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/ucontext.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/unaligned.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/unistd.h/1.10/Thu Feb 1 04:38:20 2001/-ko/ +/user.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/virtconvert.h/1.4/Sat Jan 29 23:15:44 2000/-ko/ +/vuid_event.h/1.1/Wed Jan 3 01:43:05 2001/-ko/ +/xor.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/zorro.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-m68k/CVS/Repository linux-2.4-xfs/linux/include/asm-m68k/CVS/Repository --- linux-2.4.7/linux/include/asm-m68k/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-m68k/CVS/Repository Thu Jul 5 12:05:16 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-m68k diff -rNu linux-2.4.7/linux/include/asm-m68k/CVS/Root linux-2.4-xfs/linux/include/asm-m68k/CVS/Root --- linux-2.4.7/linux/include/asm-m68k/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-m68k/CVS/Root Thu Jul 5 12:05:16 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-m68k/fcntl.h linux-2.4-xfs/linux/include/asm-m68k/fcntl.h --- linux-2.4.7/linux/include/asm-m68k/fcntl.h Mon Nov 27 20:00:49 2000 +++ linux-2.4-xfs/linux/include/asm-m68k/fcntl.h Sun Dec 17 13:15:00 2000 @@ -20,6 +20,7 @@ #define O_NOFOLLOW 0100000 /* don't follow links */ #define O_DIRECT 0200000 /* direct disk access hint - currently ignored */ #define O_LARGEFILE 0400000 +#define O_INVISIBLE 01000000 /* invisible I/O, for DMAPI/XDSM */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff -rNu linux-2.4.7/linux/include/asm-m68k/kdb.h linux-2.4-xfs/linux/include/asm-m68k/kdb.h --- linux-2.4.7/linux/include/asm-m68k/kdb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-m68k/kdb.h Wed Oct 4 06:42:46 2000 @@ -0,0 +1,10 @@ +/* + * Dummy include/asm/kdb.h for m68k. + */ +#if !defined(_ASM_KDB_H) +#define _ASM_KDB_H +#define KDB_ENTER() +struct pt_regs; +typedef struct pt_regs *kdb_eframe_t; +typedef unsigned long kdb_machreg_t; +#endif /* ASM_KDB_H */ diff -rNu linux-2.4.7/linux/include/asm-mips/CVS/Entries linux-2.4-xfs/linux/include/asm-mips/CVS/Entries --- linux-2.4.7/linux/include/asm-mips/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/CVS/Entries Thu Jul 5 12:05:31 2001 @@ -0,0 +1,131 @@ +/a.out.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/addrspace.h/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/asm.h/1.3/Sun Feb 27 22:49:22 2000/-ko/ +/asmmacro.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/atomic.h/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/bcache.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/bitops.h/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/bootinfo.h/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/branch.h/1.4/Fri May 26 01:52:46 2000/-ko/ +/bugs.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/byteorder.h/1.4/Fri May 26 01:52:46 2000/-ko/ +/cache.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/cachectl.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cacheops.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/checksum.h/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/cpu.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/current.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/ddb5074.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/delay.h/1.8/Tue Jul 3 02:33:57 2001/-ko/ +/div64.h/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/dma.h/1.6/Fri May 26 01:52:46 2000/-ko/ +/ds1286.h/1.4/Fri May 26 01:52:46 2000/-ko/ +/elf.h/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/errno.h/1.4/Tue Jul 3 02:33:57 2001/-ko/ +/fcntl.h/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/floppy.h/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/fp.h/1.4/Fri May 26 01:52:46 2000/-ko/ +/fpregdef.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fpu_emulator.h/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/gdb-stub.h/1.4/Fri May 26 01:52:46 2000/-ko/ +/gfx.h/1.4/Fri May 26 01:52:46 2000/-ko/ +/hardirq.h/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/hdreg.h/1.4/Tue Jul 3 02:33:57 2001/-ko/ +/hw_irq.h/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/ide.h/1.8/Tue Jul 3 02:33:57 2001/-ko/ +/init.h/1.5/Sun Feb 27 22:49:22 2000/-ko/ +/inst.h/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/inventory.h/1.4/Fri May 26 01:52:46 2000/-ko/ +/io.h/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/ioctl.h/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/ioctls.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/ipc.h/1.3/Fri Jul 2 09:56:47 1999/-ko/ +/ipcbuf.h/1.1/Sun Feb 27 22:49:22 2000/-ko/ +/irq.h/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/isadep.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/it8712.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/jazz.h/1.5/Fri May 26 01:52:46 2000/-ko/ +/jazzdma.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/kdb.h/1.2/Wed Oct 4 11:42:46 2000/-ko/ +/keyboard.h/1.8/Tue Jul 3 02:33:57 2001/-ko/ +/linux_logo.h/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/mc146818rtc.h/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/mips32_cache.h/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/mipsprom.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mipsregs.h/1.8/Tue Jul 3 02:33:57 2001/-ko/ +/mman.h/1.4/Fri May 26 01:52:46 2000/-ko/ +/mmu.h/1.1/Thu Dec 21 05:48:12 2000/-ko/ +/mmu_context.h/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/module.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/msgbuf.h/1.1/Sun Feb 27 22:49:22 2000/-ko/ +/namei.h/1.5/Fri May 26 01:52:46 2000/-ko/ +/ng1.h/1.5/Fri May 26 01:52:46 2000/-ko/ +/ng1hw.h/1.3/Fri May 26 01:52:46 2000/-ko/ +/nile4.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/paccess.h/1.1/Fri May 26 01:52:46 2000/-ko/ +/page.h/1.7/Thu Sep 28 22:42:39 2000/-ko/ +/param.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/parport.h/1.3/Fri May 26 01:52:46 2000/-ko/ +/pci.h/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/pgalloc.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/pgtable.h/1.13/Tue Jul 3 02:33:57 2001/-ko/ +/poll.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/posix_types.h/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/prctl.h/1.4/Fri May 26 01:52:46 2000/-ko/ +/processor.h/1.15/Tue Jul 3 02:33:57 2001/-ko/ +/ptrace.h/1.8/Tue Jul 3 02:33:57 2001/-ko/ +/r4kcache.h/1.4/Fri May 26 01:52:46 2000/-ko/ +/reboot.h/1.3/Sun Feb 27 22:49:22 2000/-ko/ +/reg.h/1.3/Sun Feb 27 22:49:22 2000/-ko/ +/regdef.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/resource.h/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/riscos-syscall.h/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/rrm.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/scatterlist.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/segment.h/1.3/Sun Feb 27 22:49:22 2000/-ko/ +/semaphore-helper.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/semaphore.h/1.8/Tue Jul 3 02:33:57 2001/-ko/ +/sembuf.h/1.1/Sun Feb 27 22:49:22 2000/-ko/ +/serial.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/sfp-machine.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/sgialib.h/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/sgiarcs.h/1.5/Fri May 26 01:52:46 2000/-ko/ +/sgidefs.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/shmbuf.h/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/shmiq.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/shmparam.h/1.6/Fri May 26 01:52:46 2000/-ko/ +/sigcontext.h/1.4/Fri May 26 01:52:46 2000/-ko/ +/siginfo.h/1.6/Fri Jun 2 00:22:59 2000/-ko/ +/signal.h/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/smp.h/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/smplock.h/1.5/Fri Mar 24 21:32:44 2000/-ko/ +/sni.h/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/socket.h/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/sockios.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/softirq.h/1.5/Fri May 26 01:52:46 2000/-ko/ +/spinlock.h/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/stackframe.h/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/stat.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/statfs.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/string.h/1.5/Fri May 26 01:52:46 2000/-ko/ +/sysmips.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/system.h/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/termbits.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/termios.h/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/time.h/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/timex.h/1.4/Fri May 26 01:52:46 2000/-ko/ +/tlb.h/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/tx3912.h/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/types.h/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/uaccess.h/1.7/Thu Sep 28 22:42:39 2000/-ko/ +/ucontext.h/1.4/Fri May 26 01:52:46 2000/-ko/ +/umap.h/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/unaligned.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/unistd.h/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/user.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/usioctl.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/vga.h/1.3/Fri Jul 2 09:56:47 1999/-ko/ +/watch.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/wbflush.h/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/xor.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-mips/CVS/Entries.Log linux-2.4-xfs/linux/include/asm-mips/CVS/Entries.Log --- linux-2.4.7/linux/include/asm-mips/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/CVS/Entries.Log Thu Jul 5 12:05:32 2001 @@ -0,0 +1,6 @@ +A D/arc//// +A D/baget//// +A D/dec//// +A D/it8172//// +A D/pmc//// +A D/sgi//// diff -rNu linux-2.4.7/linux/include/asm-mips/CVS/Repository linux-2.4-xfs/linux/include/asm-mips/CVS/Repository --- linux-2.4.7/linux/include/asm-mips/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/CVS/Repository Thu Jul 5 12:05:22 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-mips diff -rNu linux-2.4.7/linux/include/asm-mips/CVS/Root linux-2.4-xfs/linux/include/asm-mips/CVS/Root --- linux-2.4.7/linux/include/asm-mips/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/CVS/Root Thu Jul 5 12:05:22 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-mips/arc/CVS/Entries linux-2.4-xfs/linux/include/asm-mips/arc/CVS/Entries --- linux-2.4.7/linux/include/asm-mips/arc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/arc/CVS/Entries Thu Jul 5 12:05:31 2001 @@ -0,0 +1,2 @@ +/types.h/1.1/Fri May 26 01:52:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-mips/arc/CVS/Repository linux-2.4-xfs/linux/include/asm-mips/arc/CVS/Repository --- linux-2.4.7/linux/include/asm-mips/arc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/arc/CVS/Repository Thu Jul 5 12:05:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-mips/arc diff -rNu linux-2.4.7/linux/include/asm-mips/arc/CVS/Root linux-2.4-xfs/linux/include/asm-mips/arc/CVS/Root --- linux-2.4.7/linux/include/asm-mips/arc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/arc/CVS/Root Thu Jul 5 12:05:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-mips/baget/CVS/Entries linux-2.4-xfs/linux/include/asm-mips/baget/CVS/Entries --- linux-2.4.7/linux/include/asm-mips/baget/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/baget/CVS/Entries Thu Jul 5 12:05:31 2001 @@ -0,0 +1,4 @@ +/baget.h/1.3/Fri May 26 01:52:46 2000/-ko/ +/vac.h/1.3/Fri May 26 01:52:46 2000/-ko/ +/vic.h/1.3/Fri May 26 01:52:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-mips/baget/CVS/Repository linux-2.4-xfs/linux/include/asm-mips/baget/CVS/Repository --- linux-2.4.7/linux/include/asm-mips/baget/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/baget/CVS/Repository Thu Jul 5 12:05:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-mips/baget diff -rNu linux-2.4.7/linux/include/asm-mips/baget/CVS/Root linux-2.4-xfs/linux/include/asm-mips/baget/CVS/Root --- linux-2.4.7/linux/include/asm-mips/baget/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/baget/CVS/Root Thu Jul 5 12:05:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-mips/dec/CVS/Entries linux-2.4-xfs/linux/include/asm-mips/dec/CVS/Entries --- linux-2.4.7/linux/include/asm-mips/dec/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/dec/CVS/Entries Thu Jul 5 12:05:31 2001 @@ -0,0 +1,12 @@ +/interrupts.h/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/ioasic_addrs.h/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/ioasic_ints.h/1.2/Sun Feb 27 22:49:22 2000/-ko/ +/kn01.h/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/kn02.h/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/kn02xa.h/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/kn03.h/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/machtype.h/1.2/Sun Feb 27 22:49:22 2000/-ko/ +/tc.h/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/tcinfo.h/1.1/Fri Jul 2 09:56:47 1999/-ko/ +/tcmodule.h/1.1/Fri Jul 2 09:56:47 1999/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-mips/dec/CVS/Repository linux-2.4-xfs/linux/include/asm-mips/dec/CVS/Repository --- linux-2.4.7/linux/include/asm-mips/dec/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/dec/CVS/Repository Thu Jul 5 12:05:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-mips/dec diff -rNu linux-2.4.7/linux/include/asm-mips/dec/CVS/Root linux-2.4-xfs/linux/include/asm-mips/dec/CVS/Root --- linux-2.4.7/linux/include/asm-mips/dec/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/dec/CVS/Root Thu Jul 5 12:05:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-mips/fcntl.h linux-2.4-xfs/linux/include/asm-mips/fcntl.h --- linux-2.4.7/linux/include/asm-mips/fcntl.h Mon Jul 2 15:56:40 2001 +++ linux-2.4-xfs/linux/include/asm-mips/fcntl.h Mon Jul 2 21:33:57 2001 @@ -26,6 +26,7 @@ #define O_DIRECT 0x8000 /* direct disk access hint - currently ignored */ #define O_DIRECTORY 0x10000 /* must be a directory */ #define O_NOFOLLOW 0x20000 /* don't follow links */ +#define O_INVISIBLE 0x80000 /* invisible I/O, for DMAPI/XDSM */ #define O_NDELAY O_NONBLOCK diff -rNu linux-2.4.7/linux/include/asm-mips/it8172/CVS/Entries linux-2.4-xfs/linux/include/asm-mips/it8172/CVS/Entries --- linux-2.4.7/linux/include/asm-mips/it8172/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/it8172/CVS/Entries Thu Jul 5 12:05:31 2001 @@ -0,0 +1,7 @@ +/it8172.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/it8172_cir.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/it8172_dbg.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/it8172_int.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/it8172_lpc.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/it8172_pci.h/1.1/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-mips/it8172/CVS/Repository linux-2.4-xfs/linux/include/asm-mips/it8172/CVS/Repository --- linux-2.4.7/linux/include/asm-mips/it8172/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/it8172/CVS/Repository Thu Jul 5 12:05:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-mips/it8172 diff -rNu linux-2.4.7/linux/include/asm-mips/it8172/CVS/Root linux-2.4-xfs/linux/include/asm-mips/it8172/CVS/Root --- linux-2.4.7/linux/include/asm-mips/it8172/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/it8172/CVS/Root Thu Jul 5 12:05:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-mips/kdb.h linux-2.4-xfs/linux/include/asm-mips/kdb.h --- linux-2.4.7/linux/include/asm-mips/kdb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/kdb.h Wed Oct 4 06:42:46 2000 @@ -0,0 +1,10 @@ +/* + * Dummy include/asm/kdb.h for mips. + */ +#if !defined(_ASM_KDB_H) +#define _ASM_KDB_H +#define KDB_ENTER() +struct pt_regs; +typedef struct pt_regs *kdb_eframe_t; +typedef unsigned long kdb_machreg_t; +#endif /* ASM_KDB_H */ diff -rNu linux-2.4.7/linux/include/asm-mips/pmc/CVS/Entries linux-2.4-xfs/linux/include/asm-mips/pmc/CVS/Entries --- linux-2.4.7/linux/include/asm-mips/pmc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/pmc/CVS/Entries Thu Jul 5 12:05:32 2001 @@ -0,0 +1,3 @@ +/ev64120.h/1.1/Tue Jul 3 02:33:57 2001/-ko/ +/ev64120int.h/1.1/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-mips/pmc/CVS/Repository linux-2.4-xfs/linux/include/asm-mips/pmc/CVS/Repository --- linux-2.4.7/linux/include/asm-mips/pmc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/pmc/CVS/Repository Thu Jul 5 12:05:31 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-mips/pmc diff -rNu linux-2.4.7/linux/include/asm-mips/pmc/CVS/Root linux-2.4-xfs/linux/include/asm-mips/pmc/CVS/Root --- linux-2.4.7/linux/include/asm-mips/pmc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/pmc/CVS/Root Thu Jul 5 12:05:31 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-mips/sgi/CVS/Entries linux-2.4-xfs/linux/include/asm-mips/sgi/CVS/Entries --- linux-2.4.7/linux/include/asm-mips/sgi/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/sgi/CVS/Entries Thu Jul 5 12:05:33 2001 @@ -0,0 +1,5 @@ +/sgi.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/sgihpc.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/sgimc.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/sgint23.h/1.3/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-mips/sgi/CVS/Repository linux-2.4-xfs/linux/include/asm-mips/sgi/CVS/Repository --- linux-2.4.7/linux/include/asm-mips/sgi/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/sgi/CVS/Repository Thu Jul 5 12:05:32 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-mips/sgi diff -rNu linux-2.4.7/linux/include/asm-mips/sgi/CVS/Root linux-2.4-xfs/linux/include/asm-mips/sgi/CVS/Root --- linux-2.4.7/linux/include/asm-mips/sgi/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips/sgi/CVS/Root Thu Jul 5 12:05:32 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-mips64/CVS/Entries linux-2.4-xfs/linux/include/asm-mips64/CVS/Entries --- linux-2.4.7/linux/include/asm-mips64/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/CVS/Entries Thu Jul 5 12:05:38 2001 @@ -0,0 +1,113 @@ +/a.out.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/addrspace.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/asm.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/asmmacro.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/atomic.h/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/bcache.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/bitops.h/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/bootinfo.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/branch.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/bugs.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/byteorder.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/cache.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/cachectl.h/1.1/Sun Feb 27 22:49:22 2000/-ko/ +/checksum.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/cpu.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/current.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/delay.h/1.6/Thu Jul 5 05:29:17 2001/-ko/ +/div64.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/dma.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/ds1286.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/elf.h/1.6/Thu Jul 5 05:29:17 2001/-ko/ +/errno.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/fcntl.h/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/floppy.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/fpregdef.h/1.1/Sun Feb 27 22:49:22 2000/-ko/ +/gfx.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/hardirq.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/hdreg.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/hw_irq.h/1.1/Fri May 26 01:52:46 2000/-ko/ +/ide.h/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/init.h/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/inst.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/io.h/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/ioctl.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/ioctls.h/1.4/Thu Jul 5 06:13:42 2001/-ko/ +/ipc.h/1.1/Sun Feb 27 23:06:35 2000/-ko/ +/ipcbuf.h/1.1/Sun Feb 27 23:06:35 2000/-ko/ +/irq.h/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/kdb.h/1.2/Wed Oct 4 11:42:46 2000/-ko/ +/keyboard.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/linux_logo.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/m48t35.h/1.1/Sun Feb 27 23:06:35 2000/-ko/ +/mc146818rtc.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/mipsregs.h/1.6/Thu Jul 5 05:29:17 2001/-ko/ +/mman.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/mmu.h/1.1/Thu Dec 21 05:48:12 2000/-ko/ +/mmu_context.h/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/mmzone.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/module.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/msgbuf.h/1.1/Sun Feb 27 23:06:35 2000/-ko/ +/namei.h/1.3/Fri May 26 01:52:46 2000/-ko/ +/ng1.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/paccess.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/page.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/param.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/parport.h/1.3/Fri May 26 01:52:46 2000/-ko/ +/pci.h/1.6/Thu Jul 5 05:29:17 2001/-ko/ +/pgalloc.h/1.7/Thu Jul 5 05:29:17 2001/-ko/ +/pgtable.h/1.8/Thu Jul 5 05:29:17 2001/-ko/ +/poll.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/posix_types.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/processor.h/1.9/Thu Jul 5 05:29:17 2001/-ko/ +/ptrace.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/r10kcache.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/r10kcacheops.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/r4kcache.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/r4kcacheops.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/reg.h/1.1/Sun Feb 27 23:06:35 2000/-ko/ +/regdef.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/resource.h/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/riscos-syscall.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/rrm.h/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/scatterlist.h/1.1/Sun Feb 27 23:06:35 2000/-ko/ +/segment.h/1.1/Sun Feb 27 23:06:35 2000/-ko/ +/semaphore-helper.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/semaphore.h/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/sembuf.h/1.1/Sun Feb 27 23:06:35 2000/-ko/ +/serial.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/sfp-machine.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/sgialib.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/sgiarcs.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/sgidefs.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/shmbuf.h/1.1/Sun Feb 27 23:06:35 2000/-ko/ +/shmiq.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/shmparam.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/sigcontext.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/siginfo.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/signal.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/smp.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/smplock.h/1.1/Fri May 26 01:52:46 2000/-ko/ +/socket.h/1.7/Thu Jul 5 05:29:17 2001/-ko/ +/sockios.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/softirq.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/spinlock.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/stackframe.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/stat.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/statfs.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/string.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/sysmips.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/system.h/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/termbits.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/termios.h/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/timex.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/types.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/uaccess.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/ucontext.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/unaligned.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/unistd.h/1.7/Thu Feb 1 04:38:20 2001/-ko/ +/user.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/usioctl.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/watch.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/xor.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-mips64/CVS/Entries.Log linux-2.4-xfs/linux/include/asm-mips64/CVS/Entries.Log --- linux-2.4.7/linux/include/asm-mips64/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/CVS/Entries.Log Thu Jul 5 12:05:40 2001 @@ -0,0 +1,6 @@ +A D/arc//// +A D/gcc//// +A D/pci//// +A D/sgi//// +A D/sn//// +A D/xtalk//// diff -rNu linux-2.4.7/linux/include/asm-mips64/CVS/Repository linux-2.4-xfs/linux/include/asm-mips64/CVS/Repository --- linux-2.4.7/linux/include/asm-mips64/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/CVS/Repository Thu Jul 5 12:05:33 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-mips64 diff -rNu linux-2.4.7/linux/include/asm-mips64/CVS/Root linux-2.4-xfs/linux/include/asm-mips64/CVS/Root --- linux-2.4.7/linux/include/asm-mips64/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/CVS/Root Thu Jul 5 12:05:33 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-mips64/arc/CVS/Entries linux-2.4-xfs/linux/include/asm-mips64/arc/CVS/Entries --- linux-2.4.7/linux/include/asm-mips64/arc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/arc/CVS/Entries Thu Jul 5 12:05:38 2001 @@ -0,0 +1,3 @@ +/hinv.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/types.h/1.1/Sun Feb 27 22:49:22 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-mips64/arc/CVS/Repository linux-2.4-xfs/linux/include/asm-mips64/arc/CVS/Repository --- linux-2.4.7/linux/include/asm-mips64/arc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/arc/CVS/Repository Thu Jul 5 12:05:38 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-mips64/arc diff -rNu linux-2.4.7/linux/include/asm-mips64/arc/CVS/Root linux-2.4-xfs/linux/include/asm-mips64/arc/CVS/Root --- linux-2.4.7/linux/include/asm-mips64/arc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/arc/CVS/Root Thu Jul 5 12:05:38 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-mips64/fcntl.h linux-2.4-xfs/linux/include/asm-mips64/fcntl.h --- linux-2.4.7/linux/include/asm-mips64/fcntl.h Tue Nov 28 23:42:04 2000 +++ linux-2.4-xfs/linux/include/asm-mips64/fcntl.h Sun Dec 17 13:15:00 2000 @@ -27,6 +27,7 @@ #define O_DIRECT 0x8000 /* direct disk access hint - currently ignored */ #define O_DIRECTORY 0x10000 /* must be a directory */ #define O_NOFOLLOW 0x20000 /* don't follow links */ +#define O_INVISIBLE 0x80000 /* invisible I/O, for DMAPI/XDSM */ #define O_NDELAY O_NONBLOCK diff -rNu linux-2.4.7/linux/include/asm-mips64/gcc/CVS/Entries linux-2.4-xfs/linux/include/asm-mips64/gcc/CVS/Entries --- linux-2.4.7/linux/include/asm-mips64/gcc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/gcc/CVS/Entries Thu Jul 5 12:05:38 2001 @@ -0,0 +1,2 @@ +/sgidefs.h/1.1/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-mips64/gcc/CVS/Repository linux-2.4-xfs/linux/include/asm-mips64/gcc/CVS/Repository --- linux-2.4.7/linux/include/asm-mips64/gcc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/gcc/CVS/Repository Thu Jul 5 12:05:38 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-mips64/gcc diff -rNu linux-2.4.7/linux/include/asm-mips64/gcc/CVS/Root linux-2.4-xfs/linux/include/asm-mips64/gcc/CVS/Root --- linux-2.4.7/linux/include/asm-mips64/gcc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/gcc/CVS/Root Thu Jul 5 12:05:38 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-mips64/kdb.h linux-2.4-xfs/linux/include/asm-mips64/kdb.h --- linux-2.4.7/linux/include/asm-mips64/kdb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/kdb.h Wed Oct 4 06:42:46 2000 @@ -0,0 +1,10 @@ +/* + * Dummy include/asm/kdb.h for mips64. + */ +#if !defined(_ASM_KDB_H) +#define _ASM_KDB_H +#define KDB_ENTER() +struct pt_regs; +typedef struct pt_regs *kdb_eframe_t; +typedef unsigned long kdb_machreg_t; +#endif /* ASM_KDB_H */ diff -rNu linux-2.4.7/linux/include/asm-mips64/pci/CVS/Entries linux-2.4-xfs/linux/include/asm-mips64/pci/CVS/Entries --- linux-2.4.7/linux/include/asm-mips64/pci/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/pci/CVS/Entries Thu Jul 5 12:05:38 2001 @@ -0,0 +1,2 @@ +/bridge.h/1.3/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-mips64/pci/CVS/Repository linux-2.4-xfs/linux/include/asm-mips64/pci/CVS/Repository --- linux-2.4.7/linux/include/asm-mips64/pci/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/pci/CVS/Repository Thu Jul 5 12:05:38 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-mips64/pci diff -rNu linux-2.4.7/linux/include/asm-mips64/pci/CVS/Root linux-2.4-xfs/linux/include/asm-mips64/pci/CVS/Root --- linux-2.4.7/linux/include/asm-mips64/pci/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/pci/CVS/Root Thu Jul 5 12:05:38 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-mips64/sgi/CVS/Entries linux-2.4-xfs/linux/include/asm-mips64/sgi/CVS/Entries --- linux-2.4.7/linux/include/asm-mips64/sgi/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/sgi/CVS/Entries Thu Jul 5 12:05:38 2001 @@ -0,0 +1,6 @@ +/io.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/sgi.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/sgihpc.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/sgimc.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/sgint23.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-mips64/sgi/CVS/Repository linux-2.4-xfs/linux/include/asm-mips64/sgi/CVS/Repository --- linux-2.4.7/linux/include/asm-mips64/sgi/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/sgi/CVS/Repository Thu Jul 5 12:05:38 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-mips64/sgi diff -rNu linux-2.4.7/linux/include/asm-mips64/sgi/CVS/Root linux-2.4-xfs/linux/include/asm-mips64/sgi/CVS/Root --- linux-2.4.7/linux/include/asm-mips64/sgi/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/sgi/CVS/Root Thu Jul 5 12:05:38 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-mips64/sn/CVS/Entries linux-2.4-xfs/linux/include/asm-mips64/sn/CVS/Entries --- linux-2.4.7/linux/include/asm-mips64/sn/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/sn/CVS/Entries Thu Jul 5 12:05:39 2001 @@ -0,0 +1,17 @@ +/addrs.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/agent.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/arch.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/gda.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/intr.h/1.1/Fri May 26 01:52:46 2000/-ko/ +/intr_public.h/1.1/Fri May 26 01:52:46 2000/-ko/ +/io.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/ioc3.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/klconfig.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/kldir.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/klkernvars.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/launch.h/1.1/Fri May 26 01:52:46 2000/-ko/ +/mapped_kernel.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/nmi.h/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/sn_private.h/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/types.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-mips64/sn/CVS/Entries.Log linux-2.4-xfs/linux/include/asm-mips64/sn/CVS/Entries.Log --- linux-2.4.7/linux/include/asm-mips64/sn/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/sn/CVS/Entries.Log Thu Jul 5 12:05:39 2001 @@ -0,0 +1 @@ +A D/sn0//// diff -rNu linux-2.4.7/linux/include/asm-mips64/sn/CVS/Repository linux-2.4-xfs/linux/include/asm-mips64/sn/CVS/Repository --- linux-2.4.7/linux/include/asm-mips64/sn/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/sn/CVS/Repository Thu Jul 5 12:05:38 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-mips64/sn diff -rNu linux-2.4.7/linux/include/asm-mips64/sn/CVS/Root linux-2.4-xfs/linux/include/asm-mips64/sn/CVS/Root --- linux-2.4.7/linux/include/asm-mips64/sn/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/sn/CVS/Root Thu Jul 5 12:05:38 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-mips64/sn/sn0/CVS/Entries linux-2.4-xfs/linux/include/asm-mips64/sn/sn0/CVS/Entries --- linux-2.4.7/linux/include/asm-mips64/sn/sn0/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/sn/sn0/CVS/Entries Thu Jul 5 12:05:40 2001 @@ -0,0 +1,10 @@ +/addrs.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/arch.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/hub.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/hubio.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/hubmd.h/1.2/Fri Mar 3 01:42:02 2000/-ko/ +/hubni.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/hubpi.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/ip27.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/sn0_fru.h/1.2/Fri May 26 01:52:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-mips64/sn/sn0/CVS/Repository linux-2.4-xfs/linux/include/asm-mips64/sn/sn0/CVS/Repository --- linux-2.4.7/linux/include/asm-mips64/sn/sn0/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/sn/sn0/CVS/Repository Thu Jul 5 12:05:39 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-mips64/sn/sn0 diff -rNu linux-2.4.7/linux/include/asm-mips64/sn/sn0/CVS/Root linux-2.4-xfs/linux/include/asm-mips64/sn/sn0/CVS/Root --- linux-2.4.7/linux/include/asm-mips64/sn/sn0/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/sn/sn0/CVS/Root Thu Jul 5 12:05:39 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-mips64/xtalk/CVS/Entries linux-2.4-xfs/linux/include/asm-mips64/xtalk/CVS/Entries --- linux-2.4.7/linux/include/asm-mips64/xtalk/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/xtalk/CVS/Entries Thu Jul 5 12:05:40 2001 @@ -0,0 +1,3 @@ +/xtalk.h/1.2/Fri May 26 01:52:46 2000/-ko/ +/xwidget.h/1.2/Fri May 26 01:52:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-mips64/xtalk/CVS/Repository linux-2.4-xfs/linux/include/asm-mips64/xtalk/CVS/Repository --- linux-2.4.7/linux/include/asm-mips64/xtalk/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/xtalk/CVS/Repository Thu Jul 5 12:05:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-mips64/xtalk diff -rNu linux-2.4.7/linux/include/asm-mips64/xtalk/CVS/Root linux-2.4-xfs/linux/include/asm-mips64/xtalk/CVS/Root --- linux-2.4.7/linux/include/asm-mips64/xtalk/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-mips64/xtalk/CVS/Root Thu Jul 5 12:05:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-parisc/CVS/Entries linux-2.4-xfs/linux/include/asm-parisc/CVS/Entries --- linux-2.4.7/linux/include/asm-parisc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-parisc/CVS/Entries Thu Jul 5 12:05:43 2001 @@ -0,0 +1,92 @@ +/a.out.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/asmregs.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/assembly.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/atomic.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/bitops.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/bootdata.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/bugs.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/byteorder.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/cache.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/checksum.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/current.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/delay.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/div64.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/elf.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/errno.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/fcntl.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/fixmap.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/gsc.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/hardirq.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/hardware.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/hdreg.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/hil.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/hw_irq.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ide.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/io.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ioctl.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ioctls.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/iosapic.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ipcbuf.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/irq.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/keyboard.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/led.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/linux_logo.h/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/machdep.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/mc146818rtc.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/md.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/mman.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/mmu.h/1.2/Thu Dec 21 05:48:12 2000/-ko/ +/mmu_context.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/msgbuf.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/namei.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/page.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/param.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/parport.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/parport_gsc.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/pci.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/pdc.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/pdcpat.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/pgalloc.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/pgtable.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/poll.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/posix_types.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/processor.h/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/psw.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ptrace.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/real.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/resource.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/runway.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/scatterlist.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/segment.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/semaphore-helper.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/semaphore.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/sembuf.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/serial.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/setup.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/shmbuf.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/shmparam.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/sigcontext.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/siginfo.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/signal.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/smp.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/smplock.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/socket.h/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/sockios.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/softirq.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/som.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/spinlock.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/stat.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/statfs.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/string.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/system.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/termbits.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/termios.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/timex.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/traps.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/types.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/uaccess.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/ucontext.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/unaligned.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/unistd.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/user.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-parisc/CVS/Repository linux-2.4-xfs/linux/include/asm-parisc/CVS/Repository --- linux-2.4.7/linux/include/asm-parisc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-parisc/CVS/Repository Thu Jul 5 12:05:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-parisc diff -rNu linux-2.4.7/linux/include/asm-parisc/CVS/Root linux-2.4-xfs/linux/include/asm-parisc/CVS/Root --- linux-2.4.7/linux/include/asm-parisc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-parisc/CVS/Root Thu Jul 5 12:05:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-ppc/CVS/Entries linux-2.4-xfs/linux/include/asm-ppc/CVS/Entries --- linux-2.4.7/linux/include/asm-ppc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ppc/CVS/Entries Thu Jul 5 12:05:49 2001 @@ -0,0 +1,138 @@ +/8xx_immap.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/a.out.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/amigahw.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/amigaints.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/amigappc.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/amigayle.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/amipcmcia.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/atomic.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/backlight.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/bitops.h/1.10/Sat Jun 9 02:44:24 2001/-ko/ +/board.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/bootinfo.h/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/bootx.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/bseip.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/bugs.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/byteorder.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/cache.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/checksum.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/cpm_8260.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/current.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/dbdma.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/delay.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/div64.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/dma.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/elf.h/1.9/Tue May 29 19:53:13 2001/-ko/ +/errno.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/est8260.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/fads.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/fcntl.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/feature.h/1.10/Tue May 29 19:53:13 2001/-ko/ +/floppy.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/gemini.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/gemini_serial.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/gg2.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/hardirq.h/1.13/Wed Jun 13 03:24:09 2001/-ko/ +/hdreg.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/heathrow.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/highmem.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/hw_irq.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/hydra.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/ide.h/1.11/Tue May 29 19:53:13 2001/-ko/ +/immap_8260.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/init.h/1.9/Tue May 29 19:53:13 2001/-ko/ +/io.h/1.13/Tue May 29 19:53:13 2001/-ko/ +/ioctl.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/ioctls.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/ipc.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/ipcbuf.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/irq.h/1.14/Tue May 29 19:53:13 2001/-ko/ +/ivms8.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/kdb.h/1.2/Wed Oct 4 11:42:46 2000/-ko/ +/keyboard.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/keylargo.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/kgdb.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/kmap_types.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/linux_logo.h/1.8/Sat Jun 9 02:44:24 2001/-ko/ +/m48t35.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/machdep.h/1.16/Tue Jul 3 02:33:57 2001/-ko/ +/mbx.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/mc146818rtc.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/md.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/mediabay.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/mk48t59.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/mman.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/mmu.h/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/mmu_context.h/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/module.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/mpc8260.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/mpc8xx.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/msgbuf.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/namei.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/nvram.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/oak.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/ohare.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/page.h/1.12/Tue May 29 19:53:13 2001/-ko/ +/param.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/parport.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/pci-bridge.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/pci.h/1.11/Tue May 29 19:53:13 2001/-ko/ +/pgalloc.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/pgtable.h/1.26/Tue Jul 3 02:33:57 2001/-ko/ +/pnp.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/poll.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/posix_types.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/ppc4xx.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/ppc4xx_serial.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/prep_nvram.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/processor.h/1.25/Tue Jul 3 02:33:57 2001/-ko/ +/prom.h/1.11/Tue Jul 3 02:33:57 2001/-ko/ +/ptrace.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/raven.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/residual.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/resource.h/1.9/Tue May 29 19:53:13 2001/-ko/ +/rpxclassic.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/rpxhiox.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/rpxlite.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/rwsem.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/scatterlist.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/segment.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/semaphore.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/sembuf.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/serial.h/1.9/Tue May 29 19:53:13 2001/-ko/ +/setup.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/shmbuf.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/shmparam.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/sigcontext.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/siginfo.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/signal.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/smp.h/1.12/Tue May 29 19:53:13 2001/-ko/ +/smplock.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/socket.h/1.7/Thu Jun 21 15:45:04 2001/-ko/ +/sockios.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/softirq.h/1.11/Wed Jun 13 03:24:09 2001/-ko/ +/spd8xx.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/spinlock.h/1.10/Tue May 29 19:53:13 2001/-ko/ +/stat.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/statfs.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/string.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/system.h/1.18/Tue May 29 19:53:13 2001/-ko/ +/termbits.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/termios.h/1.8/Sat Jun 9 02:44:24 2001/-ko/ +/time.h/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/timex.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/tlb.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/tqm8xx.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/traps.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/types.h/1.9/Tue May 29 19:53:13 2001/-ko/ +/uaccess.h/1.9/Tue May 29 19:53:13 2001/-ko/ +/ucontext.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/unaligned.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/uninorth.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/unistd.h/1.15/Tue May 29 19:53:13 2001/-ko/ +/user.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/vc_ioctl.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/vga.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/walnut.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/xor.h/1.2/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-ppc/CVS/Repository linux-2.4-xfs/linux/include/asm-ppc/CVS/Repository --- linux-2.4.7/linux/include/asm-ppc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ppc/CVS/Repository Thu Jul 5 12:05:43 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-ppc diff -rNu linux-2.4.7/linux/include/asm-ppc/CVS/Root linux-2.4-xfs/linux/include/asm-ppc/CVS/Root --- linux-2.4.7/linux/include/asm-ppc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ppc/CVS/Root Thu Jul 5 12:05:43 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-ppc/fcntl.h linux-2.4-xfs/linux/include/asm-ppc/fcntl.h --- linux-2.4.7/linux/include/asm-ppc/fcntl.h Mon May 21 17:02:06 2001 +++ linux-2.4-xfs/linux/include/asm-ppc/fcntl.h Tue May 29 14:53:13 2001 @@ -23,6 +23,7 @@ #define O_NOFOLLOW 0100000 /* don't follow links */ #define O_LARGEFILE 0200000 #define O_DIRECT 0400000 /* direct disk access hint - currently ignored */ +#define O_INVISIBLE 01000000 /* invisible I/O, for DMAPI/XDSM */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff -rNu linux-2.4.7/linux/include/asm-ppc/kdb.h linux-2.4-xfs/linux/include/asm-ppc/kdb.h --- linux-2.4.7/linux/include/asm-ppc/kdb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-ppc/kdb.h Wed Oct 4 06:42:46 2000 @@ -0,0 +1,10 @@ +/* + * Dummy include/asm/kdb.h for ppc. + */ +#if !defined(_ASM_KDB_H) +#define _ASM_KDB_H +#define KDB_ENTER() +struct pt_regs; +typedef struct pt_regs *kdb_eframe_t; +typedef unsigned long kdb_machreg_t; +#endif /* ASM_KDB_H */ diff -rNu linux-2.4.7/linux/include/asm-s390/CVS/Entries linux-2.4-xfs/linux/include/asm-s390/CVS/Entries --- linux-2.4.7/linux/include/asm-s390/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-s390/CVS/Entries Thu Jul 5 12:05:56 2001 @@ -0,0 +1,92 @@ +/a.out.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/atomic.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/bitops.h/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/bugs.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/byteorder.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/cache.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/ccwcache.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/chandev.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/checksum.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/cpcmd.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/current.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/dasd.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/debug.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/delay.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/div64.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/dma.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/ebcdic.h/1.4/Thu Jul 5 05:29:17 2001/-ko/ +/elf.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/errno.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/fcntl.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/gdb-stub.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/hardirq.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/hdreg.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/idals.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ide.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/init.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/io.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/ioctl.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/ioctls.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/ipc.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/ipcbuf.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/irq.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/kdb.h/1.2/Wed Oct 4 11:42:46 2000/-ko/ +/lowcore.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/mathemu.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/mman.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/mmu.h/1.1/Thu Dec 21 05:48:12 2000/-ko/ +/mmu_context.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/module.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/msgbuf.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/namei.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/page.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/param.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/pci.h/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/pgalloc.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/pgtable.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/poll.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/posix_types.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/processor.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/ptrace.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/queue.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/resource.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/s390-gdbregs.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/s390_ext.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/s390dyn.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/s390io.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/s390mach.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/scatterlist.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/segment.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/semaphore.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/sembuf.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/setup.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/sfp-machine.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/shmbuf.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/shmparam.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/sigcontext.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/siginfo.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/signal.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/sigp.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/smp.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/smplock.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/socket.h/1.4/Thu Jun 21 15:45:04 2001/-ko/ +/sockios.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/softirq.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/spinlock.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/stat.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/statfs.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/string.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/system.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/termbits.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/termios.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/timex.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/todclk.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/types.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/uaccess.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/ucontext.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/unaligned.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/unistd.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/user.h/1.1/Fri May 26 01:26:22 2000/-ko/ +/vtoc.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/xor.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-s390/CVS/Repository linux-2.4-xfs/linux/include/asm-s390/CVS/Repository --- linux-2.4.7/linux/include/asm-s390/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-s390/CVS/Repository Thu Jul 5 12:05:49 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-s390 diff -rNu linux-2.4.7/linux/include/asm-s390/CVS/Root linux-2.4-xfs/linux/include/asm-s390/CVS/Root --- linux-2.4.7/linux/include/asm-s390/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-s390/CVS/Root Thu Jul 5 12:05:49 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-s390/fcntl.h linux-2.4-xfs/linux/include/asm-s390/fcntl.h --- linux-2.4.7/linux/include/asm-s390/fcntl.h Tue Feb 13 16:13:44 2001 +++ linux-2.4-xfs/linux/include/asm-s390/fcntl.h Thu Feb 22 15:09:04 2001 @@ -27,6 +27,7 @@ #define O_LARGEFILE 0100000 #define O_DIRECTORY 0200000 /* must be a directory */ #define O_NOFOLLOW 0400000 /* don't follow links */ +#define O_INVISIBLE 01000000 /* invisible I/O, for DMAPI/XDSM */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff -rNu linux-2.4.7/linux/include/asm-s390/kdb.h linux-2.4-xfs/linux/include/asm-s390/kdb.h --- linux-2.4.7/linux/include/asm-s390/kdb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-s390/kdb.h Wed Oct 4 06:42:46 2000 @@ -0,0 +1,10 @@ +/* + * Dummy include/asm/kdb.h for s390. + */ +#if !defined(_ASM_KDB_H) +#define _ASM_KDB_H +#define KDB_ENTER() +struct pt_regs; +typedef struct pt_regs *kdb_eframe_t; +typedef unsigned long kdb_machreg_t; +#endif /* ASM_KDB_H */ diff -rNu linux-2.4.7/linux/include/asm-s390x/CVS/Entries linux-2.4-xfs/linux/include/asm-s390x/CVS/Entries --- linux-2.4.7/linux/include/asm-s390x/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-s390x/CVS/Entries Thu Jul 5 12:06:00 2001 @@ -0,0 +1,90 @@ +/a.out.h/1.2/Wed Feb 28 15:36:10 2001/-ko/ +/atomic.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/bitops.h/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/bugs.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/byteorder.h/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/cache.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ccwcache.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/chandev.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/checksum.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/cpcmd.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/current.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/dasd.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/debug.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/delay.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/div64.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/dma.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ebcdic.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/elf.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/errno.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/fcntl.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/gdb-stub.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/hardirq.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/hdreg.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/idals.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ide.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/init.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/io.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ioctl.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ioctls.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ipc.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ipcbuf.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/irq.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/lowcore.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/mathemu.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/mman.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/mmu.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/mmu_context.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/module.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/msgbuf.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/namei.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/page.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/param.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/pgalloc.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/pgtable.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/poll.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/posix_types.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/processor.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/ptrace.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/queue.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/resource.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/s390-gdbregs.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/s390-regs-common.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/s390_ext.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/s390dyn.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/s390io.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/s390mach.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/scatterlist.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/segment.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/semaphore.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/sembuf.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/setup.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/shmbuf.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/shmparam.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/sigcontext.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/siginfo.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/signal.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/sigp.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/smp.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/smplock.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/socket.h/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/sockios.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/softirq.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/spinlock.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/stat.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/statfs.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/string.h/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/system.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/termbits.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/termios.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/timex.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/todclk.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/types.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/uaccess.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/ucontext.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/unaligned.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/unistd.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/user.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/vtoc.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/xor.h/1.1/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-s390x/CVS/Repository linux-2.4-xfs/linux/include/asm-s390x/CVS/Repository --- linux-2.4.7/linux/include/asm-s390x/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-s390x/CVS/Repository Thu Jul 5 12:05:56 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-s390x diff -rNu linux-2.4.7/linux/include/asm-s390x/CVS/Root linux-2.4-xfs/linux/include/asm-s390x/CVS/Root --- linux-2.4.7/linux/include/asm-s390x/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-s390x/CVS/Root Thu Jul 5 12:05:56 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-sh/CVS/Entries linux-2.4-xfs/linux/include/asm-sh/CVS/Entries --- linux-2.4.7/linux/include/asm-sh/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-sh/CVS/Entries Thu Jul 5 12:06:03 2001 @@ -0,0 +1,104 @@ +/a.out.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/addrspace.h/1.2/Sat Oct 23 02:22:05 1999/-ko/ +/atomic.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/bigsur.h/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/bitops.h/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/bugs.h/1.8/Thu Jun 28 05:21:16 2001/-ko/ +/byteorder.h/1.3/Fri Apr 21 16:16:46 2000/-ko/ +/cache.h/1.4/Fri May 26 01:52:46 2000/-ko/ +/checksum.h/1.7/Mon Oct 23 18:56:35 2000/-ko/ +/current.h/1.4/Thu Feb 1 17:10:24 2001/-ko/ +/dc_sysasic.h/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/delay.h/1.7/Fri Jan 5 18:42:30 2001/-ko/ +/div64.h/1.1/Wed Mar 8 01:44:14 2000/-ko/ +/dma.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/ec3104.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/elf.h/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/errno.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/fcntl.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/hardirq.h/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/hd64461.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/hd64465.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/hd64465_gpio.h/1.3/Thu Jun 28 05:21:16 2001/-ko/ +/hdreg.h/1.2/Wed Mar 8 01:44:14 2000/-ko/ +/hitachi_se.h/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/hw_irq.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/ide.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/init.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/io.h/1.10/Thu Jun 28 05:21:16 2001/-ko/ +/io_bigsur.h/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/io_cat68701.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/io_dc.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/io_ec3104.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/io_generic.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/io_hd64461.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/io_hd64465.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/io_se.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/io_sh2000.h/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/io_unknown.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/ioctl.h/1.2/Sat Oct 23 02:22:05 1999/-ko/ +/ioctls.h/1.3/Mon Nov 8 22:55:41 1999/-ko/ +/ipc.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/ipcbuf.h/1.1/Wed Mar 8 01:44:14 2000/-ko/ +/irq.h/1.10/Thu Jun 28 05:21:16 2001/-ko/ +/kdb.h/1.2/Wed Oct 4 11:42:46 2000/-ko/ +/keyboard-ec3104.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/keyboard.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/linux_logo.h/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/machvec.h/1.3/Thu Jun 28 05:21:16 2001/-ko/ +/machvec_init.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/mc146818rtc.h/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/mman.h/1.2/Fri Apr 21 16:16:46 2000/-ko/ +/mmu.h/1.1/Thu Dec 21 05:48:12 2000/-ko/ +/mmu_context.h/1.9/Fri Jan 5 18:42:30 2001/-ko/ +/module.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/msgbuf.h/1.1/Wed Mar 8 01:44:14 2000/-ko/ +/namei.h/1.3/Fri Apr 21 16:16:46 2000/-ko/ +/page.h/1.10/Sun Dec 17 19:15:00 2000/-ko/ +/param.h/1.2/Fri Jan 5 18:42:30 2001/-ko/ +/pci-sh7751.h/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/pci.h/1.8/Thu Jun 28 05:21:16 2001/-ko/ +/pgalloc.h/1.4/Thu Jun 28 05:21:16 2001/-ko/ +/pgtable-2level.h/1.6/Thu Jun 28 05:21:16 2001/-ko/ +/pgtable.h/1.18/Thu Jun 28 05:21:16 2001/-ko/ +/poll.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/posix_types.h/1.2/Wed Mar 8 01:44:14 2000/-ko/ +/processor.h/1.13/Thu Jun 28 05:21:16 2001/-ko/ +/ptrace.h/1.6/Fri Jan 5 18:42:30 2001/-ko/ +/resource.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/rtc.h/1.2/Thu Jun 28 05:21:16 2001/-ko/ +/scatterlist.h/1.1/Wed Mar 8 01:44:14 2000/-ko/ +/semaphore-helper.h/1.2/Wed Mar 8 01:44:14 2000/-ko/ +/semaphore.h/1.5/Thu Jun 28 05:21:16 2001/-ko/ +/sembuf.h/1.1/Wed Mar 8 01:44:14 2000/-ko/ +/serial-bigsur.h/1.1/Thu Jun 28 05:21:16 2001/-ko/ +/serial-ec3104.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/serial.h/1.3/Thu Jun 28 05:21:16 2001/-ko/ +/sh_bios.h/1.2/Thu Feb 1 17:10:24 2001/-ko/ +/shmbuf.h/1.1/Wed Mar 8 01:44:14 2000/-ko/ +/shmparam.h/1.2/Mon Nov 8 22:55:41 1999/-ko/ +/sigcontext.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/siginfo.h/1.4/Fri Jan 5 18:42:30 2001/-ko/ +/signal.h/1.3/Wed Nov 24 20:36:16 1999/-ko/ +/smc37c93x.h/1.1/Fri May 26 01:52:46 2000/-ko/ +/smp.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/smplock.h/1.2/Tue May 2 22:18:18 2000/-ko/ +/socket.h/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/sockios.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/softirq.h/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/spinlock.h/1.4/Mon Nov 8 22:55:41 1999/-ko/ +/stat.h/1.2/Wed Mar 8 01:44:14 2000/-ko/ +/statfs.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/string.h/1.6/Thu Jun 28 05:21:16 2001/-ko/ +/system.h/1.10/Thu Feb 1 17:10:24 2001/-ko/ +/termbits.h/1.2/Sat Oct 23 02:22:05 1999/-ko/ +/termios.h/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/timex.h/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/types.h/1.3/Wed Mar 8 01:44:14 2000/-ko/ +/uaccess.h/1.8/Fri Jan 5 18:42:30 2001/-ko/ +/ucontext.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/unaligned.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/unistd.h/1.11/Thu Feb 1 04:38:20 2001/-ko/ +/user.h/1.4/Thu Jun 28 05:21:16 2001/-ko/ +/xor.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-sh/CVS/Repository linux-2.4-xfs/linux/include/asm-sh/CVS/Repository --- linux-2.4.7/linux/include/asm-sh/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-sh/CVS/Repository Thu Jul 5 12:06:00 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-sh diff -rNu linux-2.4.7/linux/include/asm-sh/CVS/Root linux-2.4-xfs/linux/include/asm-sh/CVS/Root --- linux-2.4.7/linux/include/asm-sh/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-sh/CVS/Root Thu Jul 5 12:06:00 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-sh/fcntl.h linux-2.4-xfs/linux/include/asm-sh/fcntl.h --- linux-2.4.7/linux/include/asm-sh/fcntl.h Mon Oct 2 13:57:34 2000 +++ linux-2.4-xfs/linux/include/asm-sh/fcntl.h Mon Oct 23 13:56:35 2000 @@ -20,6 +20,7 @@ #define O_LARGEFILE 0100000 #define O_DIRECTORY 0200000 /* must be a directory */ #define O_NOFOLLOW 0400000 /* don't follow links */ +#define O_INVISIBLE 01000000 /* invisible I/O, for DMAPI/XDSM */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff -rNu linux-2.4.7/linux/include/asm-sh/kdb.h linux-2.4-xfs/linux/include/asm-sh/kdb.h --- linux-2.4.7/linux/include/asm-sh/kdb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-sh/kdb.h Wed Oct 4 06:42:46 2000 @@ -0,0 +1,10 @@ +/* + * Dummy include/asm/kdb.h for sh. + */ +#if !defined(_ASM_KDB_H) +#define _ASM_KDB_H +#define KDB_ENTER() +struct pt_regs; +typedef struct pt_regs *kdb_eframe_t; +typedef unsigned long kdb_machreg_t; +#endif /* ASM_KDB_H */ diff -rNu linux-2.4.7/linux/include/asm-sparc/CVS/Entries linux-2.4-xfs/linux/include/asm-sparc/CVS/Entries --- linux-2.4.7/linux/include/asm-sparc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-sparc/CVS/Entries Thu Jul 5 12:06:06 2001 @@ -0,0 +1,143 @@ +/a.out.h/1.3/Fri Jan 21 19:20:14 2000/-ko/ +/asi.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/asmmacro.h/1.3/Tue Jan 11 18:48:48 2000/-ko/ +/atomic.h/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/audioio.h/1.10/Sat Jun 9 02:44:24 2001/-ko/ +/auxio.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/bitops.h/1.8/Mon Oct 23 18:56:35 2000/-ko/ +/bpp.h/1.3/Sat Nov 25 08:05:45 2000/-ko/ +/bsderrno.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/btfixup.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/bugs.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/byteorder.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cache.h/1.3/Mon Sep 6 21:49:56 1999/-ko/ +/checksum.h/1.4/Tue Feb 1 23:02:54 2000/-ko/ +/clock.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/contregs.h/1.4/Fri Jan 5 18:42:30 2001/-ko/ +/cprefix.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/current.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cypress.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/delay.h/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/div64.h/1.1/Wed Dec 29 19:17:52 1999/-ko/ +/dma.h/1.6/Thu Jan 6 19:50:16 2000/-ko/ +/ebus.h/1.3/Wed Dec 29 19:17:52 1999/-ko/ +/ecc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/eeprom.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/elf.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/errno.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbio.h/1.3/Mon Sep 6 21:49:56 1999/-ko/ +/fcntl.h/1.10/Tue Feb 27 16:13:07 2001/-ko/ +/floppy.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/hardirq.h/1.11/Tue Jul 3 02:33:57 2001/-ko/ +/hdreg.h/1.2/Sun Dec 17 19:15:00 2000/-ko/ +/head.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/highmem.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/ide.h/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/idprom.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/init.h/1.3/Mon Sep 6 21:49:56 1999/-ko/ +/io-unit.h/1.4/Wed Dec 29 19:17:52 1999/-ko/ +/io.h/1.8/Mon Oct 23 18:56:35 2000/-ko/ +/ioctl.h/1.3/Wed Dec 29 19:17:52 1999/-ko/ +/ioctls.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/iommu.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ipc.h/1.3/Wed Dec 29 19:17:52 1999/-ko/ +/ipcbuf.h/1.1/Fri Jan 21 19:20:14 2000/-ko/ +/irq.h/1.8/Thu Sep 28 22:42:39 2000/-ko/ +/jsflash.h/1.2/Tue May 2 22:18:18 2000/-ko/ +/kbio.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/kdb.h/1.2/Wed Oct 4 11:42:46 2000/-ko/ +/kdebug.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/keyboard.h/1.4/Wed Dec 29 19:17:52 1999/-ko/ +/kgdb.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/kmap_types.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/linux_logo.h/1.4/Wed Jun 13 03:24:09 2001/-ko/ +/machines.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mbus.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mc146818rtc.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/memreg.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mman.h/1.3/Mon Mar 20 18:07:46 2000/-ko/ +/mmu.h/1.1/Thu Dec 21 05:48:12 2000/-ko/ +/mmu_context.h/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/module.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/mostek.h/1.5/Thu Feb 1 17:10:24 2001/-ko/ +/mpmbox.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/msgbuf.h/1.1/Fri Jan 21 19:20:14 2000/-ko/ +/msi.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mxcc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/namei.h/1.4/Tue May 2 22:18:18 2000/-ko/ +/obio.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/openprom.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/openpromio.h/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/oplib.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/page.h/1.13/Wed Nov 1 21:35:42 2000/-ko/ +/param.h/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/pbm.h/1.3/Wed Dec 29 19:17:52 1999/-ko/ +/pci.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/pcic.h/1.3/Wed Dec 29 19:17:52 1999/-ko/ +/pconf.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/perfctr.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/pgalloc.h/1.9/Wed May 2 06:22:13 2001/-ko/ +/pgtable.h/1.17/Sat Nov 25 08:05:45 2000/-ko/ +/pgtsrmmu.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/pgtsun4.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/pgtsun4c.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/poll.h/1.3/Wed Dec 29 19:17:52 1999/-ko/ +/posix_types.h/1.3/Fri Jan 21 19:20:14 2000/-ko/ +/processor.h/1.13/Wed May 2 06:22:13 2001/-ko/ +/psr.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ptrace.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/reg.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/resource.h/1.9/Wed Nov 1 21:35:42 2000/-ko/ +/ross.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/rtc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sbi.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sbus.h/1.7/Wed Feb 23 18:55:15 2000/-ko/ +/scatterlist.h/1.5/Tue Feb 1 23:02:54 2000/-ko/ +/segment.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/semaphore.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/sembuf.h/1.2/Sat Jan 29 23:15:44 2000/-ko/ +/sfp-machine.h/1.3/Fri May 26 01:14:50 2000/-ko/ +/shmbuf.h/1.1/Fri Jan 21 19:20:14 2000/-ko/ +/shmparam.h/1.4/Wed Dec 29 19:17:52 1999/-ko/ +/sigcontext.h/1.3/Wed Sep 15 22:45:13 1999/-ko/ +/siginfo.h/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/signal.h/1.3/Wed Sep 15 22:45:13 1999/-ko/ +/smp.h/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/smplock.h/1.4/Fri Mar 24 21:32:44 2000/-ko/ +/smpprim.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/socket.h/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/sockios.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/softirq.h/1.8/Wed Jun 13 03:24:09 2001/-ko/ +/solerrno.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/spinlock.h/1.7/Thu Sep 28 22:42:39 2000/-ko/ +/stat.h/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/statfs.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/string.h/1.3/Fri May 26 01:14:50 2000/-ko/ +/sun4paddr.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sun4prom.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sunbpp.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/svr4.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/swift.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sysen.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/system.h/1.9/Mon Oct 23 18:56:35 2000/-ko/ +/termbits.h/1.4/Sun Feb 27 23:06:35 2000/-ko/ +/termios.h/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/timer.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/timex.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/traps.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/tsunami.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/turbosparc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/types.h/1.3/Tue Feb 1 23:02:54 2000/-ko/ +/uaccess.h/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/ultra.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/unaligned.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/unistd.h/1.11/Thu Feb 1 04:38:20 2001/-ko/ +/user.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/vac-ops.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/vaddrs.h/1.6/Tue Jul 3 02:33:57 2001/-ko/ +/vfc_ioctls.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/viking.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/vuid_event.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/winmacro.h/1.5/Fri May 26 01:52:46 2000/-ko/ +/xor.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-sparc/CVS/Repository linux-2.4-xfs/linux/include/asm-sparc/CVS/Repository --- linux-2.4.7/linux/include/asm-sparc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-sparc/CVS/Repository Thu Jul 5 12:06:03 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-sparc diff -rNu linux-2.4.7/linux/include/asm-sparc/CVS/Root linux-2.4-xfs/linux/include/asm-sparc/CVS/Root --- linux-2.4.7/linux/include/asm-sparc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-sparc/CVS/Root Thu Jul 5 12:06:03 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-sparc/fcntl.h linux-2.4-xfs/linux/include/asm-sparc/fcntl.h --- linux-2.4.7/linux/include/asm-sparc/fcntl.h Tue Oct 10 12:33:52 2000 +++ linux-2.4-xfs/linux/include/asm-sparc/fcntl.h Tue Feb 27 10:13:07 2001 @@ -20,6 +20,8 @@ #define O_DIRECTORY 0x10000 /* must be a directory */ #define O_NOFOLLOW 0x20000 /* don't follow links */ #define O_LARGEFILE 0x40000 +#define O_DIRECT 0x100000 +#define O_INVISIBLE 0x200000 /* invisible I/O, for DMAPI/XDSM */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff -rNu linux-2.4.7/linux/include/asm-sparc/kdb.h linux-2.4-xfs/linux/include/asm-sparc/kdb.h --- linux-2.4.7/linux/include/asm-sparc/kdb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-sparc/kdb.h Wed Oct 4 06:42:46 2000 @@ -0,0 +1,10 @@ +/* + * Dummy include/asm/kdb.h for sparc. + */ +#if !defined(_ASM_KDB_H) +#define _ASM_KDB_H +#define KDB_ENTER() +struct pt_regs; +typedef struct pt_regs *kdb_eframe_t; +typedef unsigned long kdb_machreg_t; +#endif /* ASM_KDB_H */ diff -rNu linux-2.4.7/linux/include/asm-sparc64/CVS/Entries linux-2.4-xfs/linux/include/asm-sparc64/CVS/Entries --- linux-2.4.7/linux/include/asm-sparc64/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-sparc64/CVS/Entries Thu Jul 5 12:06:13 2001 @@ -0,0 +1,131 @@ +/a.out.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/apb.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/asi.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/atomic.h/1.6/Wed Nov 1 21:35:42 2000/-ko/ +/audioio.h/1.9/Sat Jun 9 02:44:24 2001/-ko/ +/auxio.h/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/bbc.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/bitops.h/1.10/Thu Jun 21 15:45:04 2001/-ko/ +/bpp.h/1.3/Sat Nov 25 08:05:45 2000/-ko/ +/bsderrno.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/bugs.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/byteorder.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cache.h/1.3/Sun Aug 29 02:28:51 1999/-ko/ +/chafsr.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/checksum.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/chmctrl.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/current.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dcr.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/dcu.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/delay.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/display7seg.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/div64.h/1.1/Wed Dec 29 19:17:52 1999/-ko/ +/dma.h/1.8/Tue Feb 1 23:02:54 2000/-ko/ +/ebus.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/elf.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/envctrl.h/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/errno.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/estate.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/fbio.h/1.3/Mon Sep 6 21:49:56 1999/-ko/ +/fcntl.h/1.10/Tue Feb 27 16:13:07 2001/-ko/ +/fhc.h/1.3/Wed Dec 29 19:17:52 1999/-ko/ +/floppy.h/1.12/Tue May 29 19:53:13 2001/-ko/ +/fpumacro.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/hardirq.h/1.11/Wed Jun 13 03:24:09 2001/-ko/ +/hdreg.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/head.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ide.h/1.8/Mon Jul 31 16:16:28 2000/-ko/ +/idprom.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/init.h/1.3/Sun Aug 29 02:28:51 1999/-ko/ +/io.h/1.14/Mon Oct 23 18:56:35 2000/-ko/ +/ioctl.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ioctls.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/iommu.h/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/ipc.h/1.3/Wed Dec 29 19:17:52 1999/-ko/ +/ipcbuf.h/1.1/Fri Jan 21 19:20:14 2000/-ko/ +/irq.h/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/isa.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/kbio.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/kdb.h/1.2/Wed Oct 4 11:42:46 2000/-ko/ +/kdebug.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/keyboard.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/linux_logo.h/1.4/Wed Jun 13 03:24:09 2001/-ko/ +/lsu.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mc146818rtc.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/mman.h/1.3/Mon Mar 20 18:07:46 2000/-ko/ +/mmu.h/1.1/Thu Dec 21 05:48:12 2000/-ko/ +/mmu_context.h/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/module.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +/mostek.h/1.4/Thu Feb 1 17:10:24 2001/-ko/ +/msgbuf.h/1.1/Fri Jan 21 19:20:14 2000/-ko/ +/namei.h/1.4/Tue May 2 22:18:18 2000/-ko/ +/ns87303.h/1.3/Fri Jan 21 19:20:14 2000/-ko/ +/openprom.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/openpromio.h/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/oplib.h/1.6/Fri May 26 01:52:46 2000/-ko/ +/page.h/1.11/Thu Sep 28 22:42:39 2000/-ko/ +/param.h/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/parport.h/1.10/Tue May 29 19:53:13 2001/-ko/ +/pbm.h/1.11/Tue May 29 19:53:13 2001/-ko/ +/pci.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/pconf.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/perfctr.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/pgalloc.h/1.11/Wed May 2 06:22:13 2001/-ko/ +/pgtable.h/1.19/Wed May 2 06:22:13 2001/-ko/ +/poll.h/1.3/Wed Dec 29 19:17:52 1999/-ko/ +/posix_types.h/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/processor.h/1.17/Wed May 2 06:22:13 2001/-ko/ +/psrcompat.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/pstate.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ptrace.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/reg.h/1.4/Wed Sep 15 22:45:13 1999/-ko/ +/resource.h/1.8/Wed Nov 1 21:35:42 2000/-ko/ +/rtc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/rwsem.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/sab82532.h/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/sbus.h/1.6/Wed Feb 23 18:55:15 2000/-ko/ +/scatterlist.h/1.4/Wed Dec 29 19:17:52 1999/-ko/ +/segment.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/semaphore.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/sembuf.h/1.1/Fri Jan 21 19:20:14 2000/-ko/ +/sfp-machine.h/1.2/Wed Dec 29 19:17:52 1999/-ko/ +/shmbuf.h/1.1/Fri Jan 21 19:20:14 2000/-ko/ +/shmparam.h/1.4/Wed Dec 29 19:17:52 1999/-ko/ +/sigcontext.h/1.3/Wed Sep 15 22:45:13 1999/-ko/ +/siginfo.h/1.6/Fri Jun 2 00:22:59 2000/-ko/ +/signal.h/1.3/Wed Sep 15 22:45:13 1999/-ko/ +/smp.h/1.11/Wed May 2 06:22:13 2001/-ko/ +/smplock.h/1.4/Fri Mar 24 21:32:44 2000/-ko/ +/socket.h/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/sockios.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/softirq.h/1.7/Wed Jun 13 03:24:09 2001/-ko/ +/solerrno.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/spinlock.h/1.9/Wed May 2 06:22:13 2001/-ko/ +/spitfire.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/starfire.h/1.2/Tue Jul 3 02:33:57 2001/-ko/ +/stat.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/statfs.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/string.h/1.7/Wed Jun 13 03:24:09 2001/-ko/ +/sunbpp.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/svr4.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/system.h/1.12/Wed May 2 06:22:13 2001/-ko/ +/termbits.h/1.4/Sun Feb 27 23:06:35 2000/-ko/ +/termios.h/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/timer.h/1.4/Fri May 26 01:52:46 2000/-ko/ +/timex.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ttable.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/types.h/1.4/Tue Feb 1 23:02:54 2000/-ko/ +/uaccess.h/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/uctx.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/unaligned.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/unistd.h/1.13/Thu Feb 1 04:38:20 2001/-ko/ +/upa.h/1.3/Wed Dec 29 19:17:52 1999/-ko/ +/user.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/utrap.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/vaddrs.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/vga.h/1.3/Tue May 2 22:18:18 2000/-ko/ +/visasm.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/vuid_event.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/watchdog.h/1.1/Thu Feb 1 17:10:24 2001/-ko/ +/xor.h/1.1/Sat Nov 25 08:05:45 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/asm-sparc64/CVS/Repository linux-2.4-xfs/linux/include/asm-sparc64/CVS/Repository --- linux-2.4.7/linux/include/asm-sparc64/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-sparc64/CVS/Repository Thu Jul 5 12:06:06 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/asm-sparc64 diff -rNu linux-2.4.7/linux/include/asm-sparc64/CVS/Root linux-2.4-xfs/linux/include/asm-sparc64/CVS/Root --- linux-2.4.7/linux/include/asm-sparc64/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-sparc64/CVS/Root Thu Jul 5 12:06:06 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/asm-sparc64/fcntl.h linux-2.4-xfs/linux/include/asm-sparc64/fcntl.h --- linux-2.4.7/linux/include/asm-sparc64/fcntl.h Tue Oct 10 12:33:52 2000 +++ linux-2.4-xfs/linux/include/asm-sparc64/fcntl.h Tue Feb 27 10:13:07 2001 @@ -20,6 +20,8 @@ #define O_DIRECTORY 0x10000 /* must be a directory */ #define O_NOFOLLOW 0x20000 /* don't follow links */ #define O_LARGEFILE 0x40000 +#define O_DIRECT 0x100000 +#define O_INVISIBLE 0x200000 /* invisible I/O, for DMAPI/XDSM */ #define F_DUPFD 0 /* dup */ #define F_GETFD 1 /* get close_on_exec */ diff -rNu linux-2.4.7/linux/include/asm-sparc64/kdb.h linux-2.4-xfs/linux/include/asm-sparc64/kdb.h --- linux-2.4.7/linux/include/asm-sparc64/kdb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/asm-sparc64/kdb.h Wed Oct 4 06:42:46 2000 @@ -0,0 +1,10 @@ +/* + * Dummy include/asm/kdb.h for sparc64. + */ +#if !defined(_ASM_KDB_H) +#define _ASM_KDB_H +#define KDB_ENTER() +struct pt_regs; +typedef struct pt_regs *kdb_eframe_t; +typedef unsigned long kdb_machreg_t; +#endif /* ASM_KDB_H */ diff -rNu linux-2.4.7/linux/include/linux/CVS/Entries linux-2.4-xfs/linux/include/linux/CVS/Entries --- linux-2.4.7/linux/include/linux/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/CVS/Entries Thu Jul 5 12:06:45 2001 @@ -0,0 +1,496 @@ +/802_11.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/a.out.h/1.3/Fri Jul 2 09:56:47 1999/-ko/ +/ac97_codec.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/acct.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/acpi.h/1.21/Thu Jun 21 15:45:04 2001/-ko/ +/adb.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/adb_mouse.h/1.1/Mon Oct 18 06:25:48 1999/-ko/ +/adfs_fs.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/adfs_fs_i.h/1.4/Mon Feb 14 19:32:36 2000/-ko/ +/adfs_fs_sb.h/1.3/Fri Feb 11 01:00:06 2000/-ko/ +/affs_fs.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/affs_fs_i.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/affs_fs_sb.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/affs_hardblocks.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/agp_backend.h/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/agpgart.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/amifd.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/amifdreg.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/amigaffs.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/apm_bios.h/1.10/Thu Jul 5 05:29:17 2001/-ko/ +/arcdevice.h/1.9/Mon Oct 23 18:56:35 2000/-ko/ +/atalk.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/atari_rootsec.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/atm.h/1.3/Fri Feb 11 01:00:06 2000/-ko/ +/atm_eni.h/1.2/Fri Feb 11 01:00:06 2000/-ko/ +/atm_idt77105.h/1.2/Fri Mar 24 21:32:44 2000/-ko/ +/atm_nicstar.h/1.2/Fri Feb 11 01:00:06 2000/-ko/ +/atm_suni.h/1.2/Fri Mar 24 21:32:44 2000/-ko/ +/atm_tcp.h/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/atm_zatm.h/1.2/Fri Feb 11 01:00:06 2000/-ko/ +/atmapi.h/1.1/Fri Feb 11 01:00:06 2000/-ko/ +/atmarp.h/1.2/Fri Feb 11 01:00:06 2000/-ko/ +/atmclip.h/1.1/Mon Aug 30 00:31:27 1999/-ko/ +/atmdev.h/1.8/Tue Jul 3 02:33:57 2001/-ko/ +/atmioc.h/1.2/Fri Feb 11 01:00:06 2000/-ko/ +/atmlec.h/1.2/Fri Feb 11 01:00:06 2000/-ko/ +/atmmpc.h/1.2/Fri Feb 11 01:00:06 2000/-ko/ +/atmsap.h/1.2/Fri Feb 11 01:00:06 2000/-ko/ +/atmsvc.h/1.2/Fri Feb 11 01:00:06 2000/-ko/ +/attributes.h/1.5/Wed Apr 25 05:02:25 2001/-ko/ +/auto_fs.h/1.6/Wed Feb 23 18:55:15 2000/-ko/ +/auto_fs4.h/1.2/Wed Nov 1 21:35:42 2000/-ko/ +/avl.h/1.5/Fri Sep 29 06:06:57 2000/-ko/ +/awe_voice.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/ax25.h/1.3/Thu Feb 17 20:46:04 2000/-ko/ +/b1lli.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/b1pcmcia.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/baycom.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/behavior.h/1.1/Fri Jun 9 06:40:03 2000/-ko/ +/bfs_fs.h/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/bfs_fs_i.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/bfs_fs_sb.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/binfmts.h/1.10/Thu Sep 28 22:42:39 2000/-ko/ +/bitops.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/blk.h/1.20/Wed May 2 06:22:13 2001/-ko/ +/blkdev.h/1.31/Wed May 2 06:22:13 2001/-ko/ +/blkpg.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/bootmem.h/1.7/Wed Nov 1 21:35:42 2000/-ko/ +/bpqether.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/brlock.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/cache.h/1.1/Tue Dec 7 07:08:23 1999/-ko/ +/capability.h/1.9/Mon Oct 23 18:56:35 2000/-ko/ +/capi.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/cciss_ioctl.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/cd1400.h/1.3/Wed Sep 15 20:42:56 1999/-ko/ +/cdk.h/1.3/Wed Sep 15 20:42:56 1999/-ko/ +/cdrom.h/1.18/Wed May 2 06:22:13 2001/-ko/ +/circ_buf.h/1.1/Fri Mar 24 21:32:44 2000/-ko/ +/coda.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/coda_cache.h/1.5/Wed Jun 13 03:24:09 2001/-ko/ +/coda_fs_i.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/coda_linux.h/1.11/Wed May 2 06:22:13 2001/-ko/ +/coda_proc.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/coda_psdev.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/coff.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/com20020.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/compatmac.h/1.2/Sun Dec 17 19:15:00 2000/-ko/ +/comstats.h/1.3/Wed Sep 15 20:42:56 1999/-ko/ +/concap.h/1.5/Fri Nov 12 18:56:11 1999/-ko/ +/config.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/console.h/1.6/Wed Nov 1 21:35:42 2000/-ko/ +/console_struct.h/1.3/Wed Nov 1 21:35:42 2000/-ko/ +/consolemap.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ctype.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cuda.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/cyclades.h/1.7/Fri May 26 01:26:22 2000/-ko/ +/cyclomx.h/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/cycx_cfm.h/1.2/Tue Jan 11 18:48:48 2000/-ko/ +/cycx_drv.h/1.5/Tue Jan 11 18:48:48 2000/-ko/ +/cycx_x25.h/1.3/Fri Apr 21 16:16:46 2000/-ko/ +/dcache.h/1.18/Sat Jun 9 02:44:24 2001/-ko/ +/delay.h/1.4/Fri Jan 5 18:42:30 2001/-ko/ +/devfs_fs.h/1.1/Thu Feb 17 20:46:04 2000/-ko/ +/devfs_fs_kernel.h/1.5/Wed Jun 13 03:24:09 2001/-ko/ +/devpts_fs.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/dio.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dirent.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/dis-asm.h/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/divert.h/1.2/Sat Nov 25 08:05:45 2000/-ko/ +/dmapi.h/1.5/Tue Oct 24 18:08:31 2000/-ko/ +/dmapi_kern.h/1.6/Wed Jan 17 04:01:25 2001/-ko/ +/dn.h/1.3/Thu Feb 1 17:10:24 2001/-ko/ +/dnotify.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/dtlk.h/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/efs_dir.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/efs_fs.h/1.5/Wed Mar 15 18:20:34 2000/-ko/ +/efs_fs_i.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/efs_fs_sb.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/efs_vh.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/elevator.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/elf.h/1.13/Wed May 2 06:22:13 2001/-ko/ +/elfcore.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/errno.h/1.3/Fri Apr 21 16:16:46 2000/-ko/ +/errqueue.h/1.3/Sun Jan 9 23:56:19 2000/-ko/ +/etherdevice.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/ethtool.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/ext2_fs.h/1.14/Wed Jun 6 03:10:14 2001/-ko/ +/ext2_fs_i.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ext2_fs_sb.h/1.5/Wed Jan 3 01:43:05 2001/-ko/ +/fat_cvf.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/fb.h/1.20/Sat Nov 25 08:05:45 2000/-ko/ +/fcdevice.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/fcntl.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/fd.h/1.3/Sun Aug 29 03:09:59 1999/-ko/ +/fd1772.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/fddidevice.h/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/fdreg.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/file.h/1.10/Thu Sep 28 22:42:39 2000/-ko/ +/filter.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/fs.h/1.100/Mon Jul 2 15:59:04 2001/-ko/ +/fs_struct.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/ftape-header-segment.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ftape-vendors.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ftape.h/1.3/Wed Nov 24 20:36:16 1999/-ko/ +/gameport.h/1.2/Mon Oct 23 18:56:35 2000/-ko/ +/generic_serial.h/1.2/Wed Jan 3 01:43:05 2001/-ko/ +/genhd.h/1.12/Tue Apr 3 23:07:43 2001/-ko/ +/ghash.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/grio.h/1.5/Fri Mar 23 21:13:53 2001/-ko/ +/hayesesp.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/hdlc.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/hdlcdrv.h/1.9/Sun Dec 17 19:15:00 2000/-ko/ +/hdreg.h/1.13/Thu Jul 5 05:29:17 2001/-ko/ +/hdsmart.h/1.3/Fri May 26 01:52:46 2000/-ko/ +/hfs_fs.h/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/hfs_fs_i.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/hfs_fs_sb.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/hfs_sysdep.h/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/highmem.h/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/highuid.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/hippidevice.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/hpfs_fs.h/1.3/Wed Mar 15 18:20:34 2000/-ko/ +/hpfs_fs_i.h/1.3/Fri Feb 11 01:00:06 2000/-ko/ +/hpfs_fs_sb.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/hysdn_if.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/i2c-algo-bit.h/1.2/Thu Jan 6 19:50:16 2000/-ko/ +/i2c-algo-pcf.h/1.3/Mon Mar 20 18:07:46 2000/-ko/ +/i2c-dev.h/1.5/Wed Jan 3 01:43:05 2001/-ko/ +/i2c-elektor.h/1.3/Tue Feb 1 23:02:54 2000/-ko/ +/i2c-id.h/1.8/Wed Jan 3 01:43:05 2001/-ko/ +/i2c-old.h/1.2/Wed Dec 29 19:17:52 1999/-ko/ +/i2c.h/1.12/Mon Apr 2 17:13:32 2001/-ko/ +/i2o-dev.h/1.1/Tue May 2 22:18:18 2000/-ko/ +/i2o.h/1.12/Tue May 29 19:53:13 2001/-ko/ +/ibmtr.h/1.3/Thu Jul 5 05:29:17 2001/-ko/ +/icmp.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/icmpv6.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/ide.h/1.29/Tue May 29 19:53:13 2001/-ko/ +/if.h/1.3/Sun Jan 9 23:56:19 2000/-ko/ +/if_arcnet.h/1.3/Thu Jan 6 19:50:16 2000/-ko/ +/if_arp.h/1.10/Thu Jun 21 15:45:04 2001/-ko/ +/if_bonding.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/if_bridge.h/1.1/Wed Feb 23 18:55:15 2000/-ko/ +/if_cablemodem.h/1.1/Mon Aug 30 00:31:27 1999/-ko/ +/if_ec.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/if_eql.h/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/if_ether.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/if_fc.h/1.1/Mon Aug 30 00:31:27 1999/-ko/ +/if_fddi.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/if_frad.h/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/if_hippi.h/1.3/Thu Jun 21 15:45:04 2001/-ko/ +/if_ltalk.h/1.3/Sun Aug 29 03:09:59 1999/-ko/ +/if_packet.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/if_plip.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/if_ppp.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/if_pppox.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/if_pppvar.h/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/if_shaper.h/1.4/Sun Aug 29 03:09:59 1999/-ko/ +/if_slip.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/if_strip.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/if_tr.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/if_tun.h/1.2/Sat Jun 9 02:44:24 2001/-ko/ +/if_tunnel.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/if_wanpipe.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/if_wanpipe_common.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/igmp.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/in.h/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/in6.h/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/in_route.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/in_systm.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/inet.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/inetdevice.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/init.h/1.13/Tue May 29 19:53:13 2001/-ko/ +/input.h/1.13/Thu Sep 28 22:42:39 2000/-ko/ +/interrupt.h/1.13/Sat Jun 9 02:44:24 2001/-ko/ +/iobuf.h/1.14/Wed May 9 20:54:27 2001/-ko/ +/ioctl.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ioport.h/1.11/Sun Dec 17 19:15:00 2000/-ko/ +/ip.h/1.3/Sun Jan 9 23:56:19 2000/-ko/ +/ipc.h/1.6/Tue Jan 11 18:48:48 2000/-ko/ +/ipsec.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ipv6.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ipv6_route.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ipx.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/irda.h/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/irq.h/1.8/Thu Jun 21 15:45:04 2001/-ko/ +/irq_cpustat.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/isapnp.h/1.9/Wed Nov 1 21:35:42 2000/-ko/ +/isdn.h/1.17/Tue Jul 3 02:33:57 2001/-ko/ +/isdn_divertif.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/isdn_lzscomp.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/isdn_ppp.h/1.9/Tue May 29 19:53:13 2001/-ko/ +/isdnif.h/1.11/Tue Jul 3 02:33:57 2001/-ko/ +/isicom.h/1.3/Sun Aug 29 02:28:51 1999/-ko/ +/iso_fs.h/1.10/Tue May 29 19:53:13 2001/-ko/ +/iso_fs_i.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/iso_fs_sb.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/istallion.h/1.3/Wed Sep 15 20:42:56 1999/-ko/ +/ixjuser.h/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/jffs.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/joystick.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/kallsyms.h/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/kbd_diacr.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/kbd_kern.h/1.5/Thu Feb 17 20:46:04 2000/-ko/ +/kbd_ll.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/kd.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/kdb.h/1.16/Mon Apr 2 17:13:32 2001/-ko/ +/kdbprivate.h/1.11/Mon Jun 18 17:43:14 2001/-ko/ +/kdev_t.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/kernel.h/1.18/Wed Jun 13 03:24:09 2001/-ko/ +/kernel_stat.h/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/kernelcapi.h/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/keyboard.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/kmod.h/1.9/Sat Nov 25 08:05:45 2000/-ko/ +/lapb.h/1.3/Sat Nov 25 08:05:45 2000/-ko/ +/limits.h/1.3/Fri Aug 27 23:14:48 1999/-ko/ +/linkage.h/1.7/Wed Nov 1 21:35:42 2000/-ko/ +/linux_logo.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/list.h/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/locks.h/1.4/Tue May 29 19:53:13 2001/-ko/ +/logibusmouse.h/1.1/Sun Aug 29 02:28:51 1999/-ko/ +/loop.h/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/lp.h/1.6/Thu Feb 17 20:46:04 2000/-ko/ +/lvm.h/1.7/Tue Mar 20 20:10:08 2001/-ko/ +/major.h/1.26/Wed May 2 06:22:13 2001/-ko/ +/malloc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/matroxfb.h/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/mc146818rtc.h/1.5/Fri Jan 5 18:42:30 2001/-ko/ +/mc6821.h/1.1/Sun Aug 29 03:09:59 1999/-ko/ +/mca.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/meye.h/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/mii.h/1.2/Thu Jun 28 05:21:16 2001/-ko/ +/minix_fs.h/1.9/Mon Oct 23 18:56:35 2000/-ko/ +/minix_fs_i.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/minix_fs_sb.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/miscdevice.h/1.10/Wed May 2 06:22:13 2001/-ko/ +/mm.h/1.57/Mon Jul 2 15:59:04 2001/-ko/ +/mman.h/1.3/Thu Dec 9 03:05:16 1999/-ko/ +/mmzone.h/1.15/Wed Jun 6 03:10:14 2001/-ko/ +/modsetver.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/module.h/1.19/Thu Feb 22 21:09:04 2001/-ko/ +/mount.h/1.15/Sat Jun 9 02:44:24 2001/-ko/ +/mpp.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mroute.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/msdos_fs.h/1.10/Tue May 29 19:53:13 2001/-ko/ +/msdos_fs_i.h/1.4/Fri Feb 11 01:00:06 2000/-ko/ +/msdos_fs_sb.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/msg.h/1.8/Tue Jan 11 18:48:48 2000/-ko/ +/mtio.h/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/n_r3964.h/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/nbd.h/1.8/Tue May 29 19:53:13 2001/-ko/ +/ncp.h/1.3/Tue Oct 12 19:12:19 1999/-ko/ +/ncp_fs.h/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/ncp_fs_i.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/ncp_fs_sb.h/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/ncp_mount.h/1.4/Fri Jan 21 19:20:14 2000/-ko/ +/ncp_no.h/1.1/Tue Oct 12 19:12:19 1999/-ko/ +/net.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/netbeui.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/netdevice.h/1.22/Wed May 2 06:22:13 2001/-ko/ +/netfilter.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/netfilter_bridge.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/netfilter_ddp.h/1.1/Mon Aug 30 00:31:27 1999/-ko/ +/netfilter_decnet.h/1.3/Sat Nov 25 08:05:45 2000/-ko/ +/netfilter_ipv4.h/1.5/Mon Mar 20 18:07:46 2000/-ko/ +/netfilter_ipv6.h/1.3/Fri Jan 5 18:42:30 2001/-ko/ +/netfilter_ipx.h/1.1/Mon Aug 30 00:31:27 1999/-ko/ +/netfilter_x25.h/1.1/Mon Aug 30 00:31:27 1999/-ko/ +/netlink.h/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/netrom.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/nfs.h/1.6/Fri Apr 21 16:16:46 2000/-ko/ +/nfs2.h/1.1/Fri Apr 21 16:16:46 2000/-ko/ +/nfs3.h/1.4/Fri Apr 21 16:16:46 2000/-ko/ +/nfs_flushd.h/1.2/Fri Jun 2 00:22:59 2000/-ko/ +/nfs_fs.h/1.15/Tue May 29 19:53:13 2001/-ko/ +/nfs_fs_i.h/1.7/Sun Dec 17 19:15:00 2000/-ko/ +/nfs_fs_sb.h/1.5/Tue May 2 22:18:18 2000/-ko/ +/nfs_mount.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/nfs_page.h/1.5/Thu Dec 21 05:48:12 2000/-ko/ +/nfs_xdr.h/1.5/Thu Feb 1 17:10:24 2001/-ko/ +/nfsiod.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/nls.h/1.6/Thu Jul 5 06:13:42 2001/-ko/ +/notifier.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/ntfs_fs.h/1.3/Wed Mar 15 18:20:34 2000/-ko/ +/ntfs_fs_i.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/ntfs_fs_sb.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/nubus.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/nvram.h/1.3/Tue Nov 2 22:58:37 1999/-ko/ +/openprom_fs.h/1.1/Wed Dec 29 19:17:52 1999/-ko/ +/page_buf.h/1.96/Tue Jul 3 02:29:39 2001/-ko/ +/page_buf_trace.h/1.10/Fri Sep 29 06:06:57 2000/-ko/ +/pagemap.h/1.25/Wed May 2 06:22:13 2001/-ko/ +/param.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/parport.h/1.17/Tue May 29 19:53:13 2001/-ko/ +/parport_pc.h/1.8/Sat Jun 9 02:44:24 2001/-ko/ +/pc_keyb.h/1.1/Tue Oct 12 19:12:19 1999/-ko/ +/pci.h/1.47/Thu Jul 5 06:13:42 2001/-ko/ +/pci_ids.h/1.39/Thu Jul 5 03:57:00 2001/-ko/ +/personality.h/1.8/Tue May 2 22:18:18 2000/-ko/ +/pg.h/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/phonedev.h/1.1/Thu Jan 6 19:50:16 2000/-ko/ +/pipe_fs_i.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/pkt_cls.h/1.3/Sun Jan 9 23:56:19 2000/-ko/ +/pkt_sched.h/1.5/Fri Mar 3 01:42:02 2000/-ko/ +/pm.h/1.7/Fri Jun 29 22:21:45 2001/-ko/ +/pmu.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/poll.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/posix_types.h/1.3/Fri Jan 21 19:20:14 2000/-ko/ +/ppdev.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/ppp-comp.h/1.3/Sun Aug 29 02:28:51 1999/-ko/ +/ppp.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ppp_channel.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/ppp_defs.h/1.3/Wed Mar 15 18:20:34 2000/-ko/ +/prctl.h/1.6/Mon Mar 20 18:07:46 2000/-ko/ +/proc_fs.h/1.30/Thu Jul 5 06:13:42 2001/-ko/ +/proc_fs_i.h/1.2/Fri Apr 21 16:16:46 2000/-ko/ +/ps2esdi.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ptrace.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/qic117.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/qnx4_fs.h/1.9/Mon Jul 31 16:16:28 2000/-ko/ +/qnx4_fs_i.h/1.5/Fri Feb 11 01:00:06 2000/-ko/ +/qnx4_fs_sb.h/1.4/Tue Jan 11 18:48:48 2000/-ko/ +/qnxtypes.h/1.4/Tue Jan 11 18:48:48 2000/-ko/ +/quota.h/1.5/Mon Mar 20 18:07:46 2000/-ko/ +/quotaops.h/1.8/Wed Jun 13 03:24:09 2001/-ko/ +/random.h/1.5/Sat Jan 29 23:15:44 2000/-ko/ +/raw.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/reboot.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/reiserfs_fs.h/1.4/Wed Jun 13 03:24:09 2001/-ko/ +/reiserfs_fs_i.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/reiserfs_fs_sb.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/resource.h/1.4/Wed Dec 15 00:05:45 1999/-ko/ +/rocket.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/romfs_fs.h/1.3/Wed Mar 15 18:20:34 2000/-ko/ +/romfs_fs_i.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/romfs_fs_sb.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/rose.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/route.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/rpcsock.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/rtc.h/1.5/Thu Feb 1 17:10:24 2001/-ko/ +/rtnetlink.h/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/rwsem-spinlock.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/rwsem.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/sc26198.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/scc.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/sched.h/1.39/Wed May 2 06:22:13 2001/-ko/ +/sdla.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sdla_asy.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/sdla_chdlc.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/sdla_fr.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/sdla_ppp.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/sdla_x25.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/sdladrv.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/sdlapci.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/sdlasfm.h/1.3/Sat Jan 29 23:15:44 2000/-ko/ +/securebits.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/selection.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sem.h/1.6/Tue Jan 11 18:48:48 2000/-ko/ +/serial.h/1.12/Mon Apr 2 17:13:32 2001/-ko/ +/serial167.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/serialP.h/1.13/Wed May 2 06:22:13 2001/-ko/ +/serial_reg.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/serio.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/shm.h/1.12/Wed Jan 3 01:43:05 2001/-ko/ +/shmem_fs.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/signal.h/1.5/Sun Dec 17 19:15:00 2000/-ko/ +/sisfb.h/1.2/Sat Nov 25 08:05:45 2000/-ko/ +/skbuff.h/1.19/Tue May 29 19:53:13 2001/-ko/ +/slab.h/1.15/Mon Jul 2 15:59:04 2001/-ko/ +/smb.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/smb_fs.h/1.14/Thu Jun 21 15:45:04 2001/-ko/ +/smb_fs_i.h/1.6/Thu Jun 21 15:45:04 2001/-ko/ +/smb_fs_sb.h/1.5/Tue May 29 19:53:13 2001/-ko/ +/smb_mount.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/smbno.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/smp.h/1.8/Thu Sep 28 22:42:39 2000/-ko/ +/smp_lock.h/1.4/Tue May 2 22:18:18 2000/-ko/ +/socket.h/1.9/Sat Jun 9 02:44:24 2001/-ko/ +/sockios.h/1.6/Thu Jun 28 05:21:16 2001/-ko/ +/sonet.h/1.3/Fri Mar 24 21:32:44 2000/-ko/ +/sonypi.h/1.1/Thu Jul 5 06:13:42 2001/-ko/ +/sound.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/soundcard.h/1.5/Sat Nov 25 08:05:45 2000/-ko/ +/soundmodem.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/spinlock.h/1.9/Thu Jul 5 06:13:42 2001/-ko/ +/stallion.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/stat.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/stddef.h/1.3/Fri Jan 21 19:20:14 2000/-ko/ +/string.h/1.9/Wed May 2 06:22:13 2001/-ko/ +/swap.h/1.30/Thu Jul 5 06:13:42 2001/-ko/ +/swapctl.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/synclink.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/sys.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sysctl.h/1.33/Tue May 29 19:53:13 2001/-ko/ +/sysrq.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/sysv_fs.h/1.9/Tue Jul 3 02:33:57 2001/-ko/ +/sysv_fs_i.h/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/sysv_fs_sb.h/1.3/Tue Jul 3 02:33:57 2001/-ko/ +/tcp.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/telephony.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/termios.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/threads.h/1.2/Tue May 2 22:18:18 2000/-ko/ +/time.h/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/timer.h/1.9/Tue May 29 19:53:13 2001/-ko/ +/times.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/timex.h/1.4/Thu Jul 5 06:13:42 2001/-ko/ +/toshiba.h/1.1/Mon Oct 23 19:17:46 2000/-ko/ +/tpqic02.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/tqueue.h/1.9/Mon Apr 2 17:13:32 2001/-ko/ +/trdevice.h/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/tty.h/1.16/Thu Jul 5 06:13:42 2001/-ko/ +/tty_driver.h/1.3/Thu Feb 17 20:46:04 2000/-ko/ +/tty_flip.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/tty_ldisc.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/types.h/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/udf_167.h/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/udf_fs.h/1.11/Tue Jul 3 02:33:57 2001/-ko/ +/udf_fs_i.h/1.5/Tue Jul 3 02:33:57 2001/-ko/ +/udf_fs_sb.h/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/udf_udf.h/1.4/Tue Jul 3 02:33:57 2001/-ko/ +/udp.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ufs_fs.h/1.10/Thu Sep 28 22:42:39 2000/-ko/ +/ufs_fs_i.h/1.3/Tue Jan 11 18:48:48 2000/-ko/ +/ufs_fs_sb.h/1.3/Thu Jan 6 19:50:16 2000/-ko/ +/uio.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ultrasound.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/umsdos_fs.h/1.8/Wed Mar 15 18:20:34 2000/-ko/ +/umsdos_fs.p/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/umsdos_fs_i.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/un.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/unistd.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/usb.h/1.16/Thu Jul 5 06:13:42 2001/-ko/ +/usbdev_fs_i.h/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/usbdev_fs_sb.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/usbdevice_fs.h/1.5/Thu Jul 5 06:13:42 2001/-ko/ +/user.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/utime.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/uts.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/utsname.h/1.3/Sat Jan 29 23:15:44 2000/-ko/ +/vfs.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/video_decoder.h/1.1/Fri Jul 9 06:55:26 1999/-ko/ +/video_encoder.h/1.1/Fri Jul 9 06:55:26 1999/-ko/ +/videodev.h/1.16/Thu Jul 5 06:13:42 2001/-ko/ +/videotext.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/vmalloc.h/1.14/Thu May 31 05:16:19 2001/-ko/ +/vnode.h/1.4/Fri Sep 29 06:06:57 2000/-ko/ +/vt.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/vt_buffer.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/vt_kern.h/1.4/Thu Feb 1 17:10:24 2001/-ko/ +/wait.h/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/wanpipe.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/wanrouter.h/1.9/Wed May 2 06:22:13 2001/-ko/ +/watchdog.h/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/wavefront.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/wireless.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/wrapper.h/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/x25.h/1.3/Tue May 2 22:18:18 2000/-ko/ +/xfs_fs.h/1.24/Thu May 17 02:58:46 2001// +/xfs_fs_i.h/1.6/Fri Sep 29 06:06:57 2000// +/xfs_fs_sb.h/1.6/Fri Sep 29 06:06:57 2000// +/xqm.h/1.5/Tue Apr 3 02:52:38 2001/-ko/ +/yam.h/1.1/Sun Aug 29 02:28:51 1999/-ko/ +/zftape.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/zorro.h/1.6/Wed Jan 3 01:43:05 2001/-ko/ +/zorro_ids.h/1.2/Fri Jan 5 18:42:30 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/linux/CVS/Entries.Log linux-2.4-xfs/linux/include/linux/CVS/Entries.Log --- linux-2.4.7/linux/include/linux/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/CVS/Entries.Log Thu Jul 5 12:06:48 2001 @@ -0,0 +1,9 @@ +A D/byteorder//// +A D/isdn//// +A D/lockd//// +A D/mtd//// +A D/netfilter_ipv4//// +A D/netfilter_ipv6//// +A D/nfsd//// +A D/raid//// +A D/sunrpc//// diff -rNu linux-2.4.7/linux/include/linux/CVS/Repository linux-2.4-xfs/linux/include/linux/CVS/Repository --- linux-2.4.7/linux/include/linux/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/CVS/Repository Thu Jul 5 12:06:13 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/linux diff -rNu linux-2.4.7/linux/include/linux/CVS/Root linux-2.4-xfs/linux/include/linux/CVS/Root --- linux-2.4.7/linux/include/linux/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/CVS/Root Thu Jul 5 12:06:13 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/linux/attributes.h linux-2.4-xfs/linux/include/linux/attributes.h --- linux-2.4.7/linux/include/linux/attributes.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/attributes.h Wed Apr 25 00:02:25 2001 @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __ATTRIBUTES_H__ +#define __ATTRIBUTES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * An IRIX-compatible extended attributes API + */ + +/* + * Valid command flags, may be used with all API calls. + * Multiple flags should be bitwise OR'ed together. + */ +#define ATTR_ROOT 0x0001 /* use attrs in root namespace, not user */ +#define ATTR_CREATE 0x0002 /* pure create: fail if attr already exists */ +#define ATTR_REPLACE 0x0004 /* pure set: fail if attr does not exist */ +#define ATTR_SHIFT 16 /* for supporting extensions */ + +/* + * Additional API specific opcodes & flags + */ +#define ATTR_DONTFOLLOW (0x0001 << ATTR_SHIFT) /* do not follow symlinks */ +#define ATTR_TRUST (0x0002 << ATTR_SHIFT) + /* tell server we are trusted to properly handle extended attributes */ + +#define ATTR_KERNOTIME (0x0004 << ATTR_SHIFT) + /* don't update inode timestamps. + * The DMI needs a way to update attributes without affecting the + * inode timestamps. Note that this flag is not set-able from user + * mode - it is kernel internal only, but it must not conflict with + * the user flags either. + */ + +/* + * Generic extended attribute operation structure + */ +typedef struct attr_op { + int opcode; /* which operation to perform */ + int error; /* result (an errno) of this operation [out] */ + char *name; /* attribute name */ + char *value; /* attribute value [in/out] */ + int length; /* value length [in/out] */ + int flags; /* bitwise OR of #defines below */ + void *aux; /* optional cmd specific data */ +} attr_op_t; + +/* + * Valid attr_op, attr_multi_op opcodes + */ +#define ATTR_OP_GET 1 /* return the indicated attr's value */ +#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */ +#define ATTR_OP_REMOVE 3 /* remove the indicated attr */ +#define ATTR_OP_LIST 4 /* list attributes associated with a file */ + +#define ATTR_OP_EXT 32 /* for supporting extensions */ +#define ATTR_OP_IRIX_LIST (ATTR_OP_EXT + 0) /* IRIX attr_list semantics */ + +/* + * The maximum size (into the kernel or returned from the kernel) of an + * attribute value or the buffer used for an attr_list() call. Larger + * sizes will result in an E2BIG return code. + */ +#define ATTR_MAX_VALUELEN (64*1024) /* max length of a value */ + +/* + * Define how lists of attribute names are returned to the user from + * the attr_list() call. A large, 32bit aligned, buffer is passed in + * along with its size. We put an array of offsets at the top that each + * reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom. + */ +typedef struct attrlist { + __s32 al_count; /* number of entries in attrlist */ + __s32 al_more; /* T/F: more attrs (do call again) */ + __s32 al_offset[1]; /* byte offsets of attrs [var-sized] */ +} attrlist_t; + +/* + * Show the interesting info about one attribute. This is what the + * al_offset[i] entry points to. + */ +typedef struct attrlist_ent { /* data from attr_list() */ + __u32 a_valuelen; /* number bytes in value of attr */ + char a_name[1]; /* attr name (NULL terminated) */ +} attrlist_ent_t; + +/* + * Given a pointer to the (char*) buffer containing the attr_list() result, + * and an index, return a pointer to the indicated attribute in the buffer. + */ +#define ATTR_ENTRY(buffer, index) \ + ((attrlist_ent_t *) \ + &((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ]) + + +/* + * Implement a "cursor" for use in successive attr_list() calls. + * It provides a way to find the last attribute that was returned in the + * last attr_list() call so that we can get the next one without missing + * any. This should be bzero()ed before use and whenever it is desired to + * start over from the beginning of the attribute list. The only valid + * operation on a cursor is to bzero() it. + */ +typedef struct attrlist_cursor { + __u32 opaque[4]; /* an opaque cookie */ +} attrlist_cursor_t; + +/* + * Multi-attribute operation vector. + */ +typedef struct attr_multiop { + int am_opcode; /* operation to perform (ATTR_OP_GET, etc.) */ + int am_error; /* [out arg] result of this sub-op (an errno) */ + char *am_attrname; /* attribute name to work with */ + char *am_attrvalue; /* [in/out arg] attribute value (raw bytes) */ + int am_length; /* [in/out arg] length of value */ + int am_flags; /* bitwise OR of attr API flags defined above */ +} attr_multiop_t; +#define ATTR_MAX_MULTIOPS 128 /* max number ops in an oplist array */ + +/* + * Get the value of an attribute. + * Valuelength must be set to the maximum size of the value buffer, it will + * be set to the actual number of bytes used in the value buffer upon return. + * The return value is -1 on error (w/errno set appropriately), 0 on success. + */ +extern int attr_get (const char *__path, const char *__attrname, + char *__attrvalue, int *__valuelength, int __flags); +extern int attr_getf (int __fd, const char *__attrname, char *__attrvalue, + int *__valuelength, int __flags); + +/* + * Set the value of an attribute, creating the attribute if necessary. + * The return value is -1 on error (w/errno set appropriately), 0 on success. + */ +extern int attr_set (const char *__path, const char *__attrname, + const char *__attrvalue, const int __valuelength, + int __flags); +extern int attr_setf (int __fd, const char *__attrname, + const char *__attrvalue, const int __valuelength, + int __flags); + +/* + * Remove an attribute. + * The return value is -1 on error (w/errno set appropriately), 0 on success. + */ +extern int attr_remove (const char *__path, const char *__attrname, + int __flags); +extern int attr_removef (int __fd, const char *__attrname, int __flags); + +/* + * List the names and sizes of the values of all the attributes of an object. + * "Cursor" must be allocated and zeroed before the first call, it is used + * to maintain context between system calls if all the attribute names won't + * fit into the buffer on the first system call. + * The return value is -1 on error (w/errno set appropriately), 0 on success. + */ +extern int attr_list (const char *__path, char *__buffer, + const int __buffersize, int __flags, + attrlist_cursor_t *__cursor); +extern int attr_listf (int __fd, char *__buffer, const int __buffersize, + int __flags, attrlist_cursor_t *__cursor); + +/* + * Operate on multiple attributes of the same object simultaneously. + * + * This call will save on system call overhead when many attributes are + * going to be operated on. + * + * The return value is -1 on error (w/errno set appropriately), 0 on success. + * Note that this call will not return -1 as a result of failure of any + * of the sub-operations, their return value is stored in each element + * of the operation array. This call will return -1 for a failure of the + * call as a whole, eg: if the pathname doesn't exist, or the fd is bad. + * + * The semantics and allowable values for the fields in a attr_multiop_t + * are the same as the semantics and allowable values for the arguments to + * the corresponding "simple" attribute interface. For example: the args + * to a ATTR_OP_GET are the same as the args to an attr_get() call. + */ +extern int attr_multi (const char *__path, attr_multiop_t *__oplist, + int __count, int __flags); +extern int attr_multif (int __fd, attr_multiop_t *__oplist, + int __count, int __flags); + +#ifdef __cplusplus +} +#endif + +#endif /* __ATTRIBUTES_H__ */ diff -rNu linux-2.4.7/linux/include/linux/avl.h linux-2.4-xfs/linux/include/linux/avl.h --- linux-2.4.7/linux/include/linux/avl.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/avl.h Fri Sep 29 01:06:57 2000 @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Written by William J. Earl at SGI + */ + +#ifndef _LINUX_AVL_H +#define _LINUX_AVL_H + +#include +#if defined(CONFIG_PAGE_BUF) || defined(CONFIG_PAGE_BUF_MODULE) + +#include + +/* + * Key and value types + */ + +typedef unsigned long avl_key_t; +typedef unsigned long avl_value_t; + +/* + * AVL tree handle + */ + +typedef void *avl_handle_t; + +/* + * Option flags + */ + +typedef enum { + avl_opt_nowait = (1 << 0), /* do not sleep */ + avl_opt_nolock = (1 << 1) /* caller handles synchronization */ +} avl_opt_t; + +/* + * Comparison function + */ + +typedef int (*avl_comparison_t)(avl_key_t,avl_key_t); + +/* + * Increment function + */ + +typedef void (*avl_increment_t)(avl_key_t *,avl_key_t); + + +/* + * Interface Routines + * + * For each routine with a return value: + * + * Returns 0 on normal completion. + * Returns -EAGAIN if memory cannot be allocated. + * Returns -EWOULDBLOCK if avl_opt_nowait was specified and + * sleeping would be required. + */ + +/* + * avl_create + * + * Allocate an AVL tree object, to be returned in the + * avl_handle_t variable passed by reference. + * The avl_comparison_t value may be NULL, in which case a + * default (integer) comparison is used. + */ + +extern int avl_create(avl_handle_t *,avl_opt_t,avl_comparison_t,avl_increment_t); + +/* + * avl_destroy + * + * Destroy (deallocate) an AVL tree object. + */ + +extern void avl_destroy(avl_handle_t); + +/* + * avl_insert + * + * Insert the key-value pair into the give AVL tree. + * + * Returns -EEXIST if there is already an entry for the key. + */ + +extern int avl_insert(avl_handle_t,avl_key_t,avl_value_t); + +/* + * avl_replace + * + * Replace (or insert) the key-value pair into the give AVL tree. + */ + +extern int avl_replace(avl_handle_t,avl_key_t,avl_value_t); + +/* + * avl_delete + * + * Delete the key-value pair from the give AVL tree. + * + * Returns -ENOENT if the key is not present in the tree. + * Returns -EINVAL if the value supplied does not match the + * value stored in the tree. + */ + +extern int avl_delete(avl_handle_t,avl_key_t,avl_value_t); + +/* + * avl_lookup + * + * Lookup the key in the give AVL tree, and return the + * associated value in the avl_value_t variable passed by + * reference. + * + * Returns -ENOENT if the key is not present in the tree. + */ + +extern int avl_lookup(avl_handle_t,avl_key_t,avl_value_t *); + +/* + * avl_lookup_next + * + * Lookup the first key equal to or greater than the key + * in the first avl_key_t variable passed by reference, returning + * the associated key and value in the remaining variables passed + * by reference, and update the first variable to be the next key value + * greater than the key of the entry found. + * + * If the starting key is set to the lowest possible key value, + * this may be used to search for all entries in the tree in a loop. + * + * Returns -ENOENT if no matching key is present in the tree. + */ + +extern int avl_lookup_next(avl_handle_t,avl_key_t *,avl_key_t *,avl_value_t *); + +extern int avl_init(void); +extern void avl_terminate(void); + +#ifdef CONFIG_AVL_DEBUG +/* + * avl_check + * + * Perform consistency check on an AVL tree. + */ + +extern void avl_check(avl_handle_t,char *); + +#endif /* CONFIG_AVL_DEBUG */ + +#endif /* defined(CONFIG_PAGEBUF) || defined(CONFIG_PAGEBUF_MODULE) */ + +#endif /* _LINUX_AVL_H */ diff -rNu linux-2.4.7/linux/include/linux/behavior.h linux-2.4-xfs/linux/include/linux/behavior.h --- linux-2.4.7/linux/include/linux/behavior.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/behavior.h Fri Jun 9 01:40:03 2000 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef _LINUX_BEHAVIOR_I +#define _LINUX_BEHAVIOR_I + +#if defined(CELL_CAPABLE) || defined(CELL_PREPARE) +/* + * Behavior head lock structure. + * This structure contains the mrlock for the behavior head + * as well as the deferred callout info. A pointer to + * this structure is located in the behavior head. + */ +struct bhv_head_lock; +typedef struct { + mrlock_t bhl_lock; /* MUST BE FIRST - behavior head lock */ + kcallouthead_t bhl_ucallout; /* deferred update callout queue */ + lock_t bhl_ucqlock; /* update callout queue lock */ +#ifdef BLALOG + struct bhv_head *bhl_headp; /* pointer to behavior head */ +#endif +} bhv_head_lock_t; + +#define MR_TO_BHVL(mrp) ((bhv_head_lock_t*) (mrp)) + +#endif /* defined(CELL_CAPABLE) || defined(CELL_PREPARE) */ + + +/* + * Behavior head. Head of the chain of behaviors. + * Contained within each virtualized object data structure. + */ +typedef struct bhv_head { + struct bhv_desc *bh_first; /* first behavior in chain */ +#if defined(CELL_CAPABLE) || defined(CELL_PREPARE) + bhv_head_lock_t *bh_lockp; /* pointer to lock info struct */ + void *bh_unused1; + __u64 bh_unused2; +#endif +} bhv_head_t; + +/* + * Behavior descriptor. Descriptor associated with each behavior. + * Contained within the behavior's private data structure. + */ +typedef struct bhv_desc { + void *bd_pdata; /* private data for this behavior */ + void *bd_vobj; /* virtual object associated with */ + void *bd_ops; /* ops for this behavior */ + struct bhv_desc *bd_next; /* next behavior in chain */ +} bhv_desc_t; + +/* + * Behavior identity field. A behavior's identity determines the position + * where it lives within a behavior chain, and it's always the first field + * of the behavior's ops vector. The optional id field further identifies the + * subsystem responsible for the behavior. + */ +typedef struct bhv_identity { + __u16 bi_id; /* owning subsystem id */ + __u16 bi_position; /* position in chain */ +} bhv_identity_t; + +typedef bhv_identity_t bhv_position_t; + +#ifdef CELL_CAPABLE +#define BHV_IDENTITY_INIT(id,pos) {id, pos} +#else +#define BHV_IDENTITY_INIT(id,pos) {0, pos} +#endif + +#define BHV_IDENTITY_INIT_POSITION(pos) BHV_IDENTITY_INIT(0, pos) + + +/* + * Define boundaries of position values. + */ +#define BHV_POSITION_INVALID 0 /* invalid position number */ +#define BHV_POSITION_BASE 1 /* base (last) implementation layer */ +#define BHV_POSITION_TOP 63 /* top (first) implementation layer */ + + +#endif /* _LINUX_BEHAVIOR_I */ diff -rNu linux-2.4.7/linux/include/linux/byteorder/CVS/Entries linux-2.4-xfs/linux/include/linux/byteorder/CVS/Entries --- linux-2.4.7/linux/include/linux/byteorder/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/byteorder/CVS/Entries Thu Jul 5 12:06:45 2001 @@ -0,0 +1,7 @@ +/big_endian.h/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/generic.h/1.3/Fri Jan 21 19:20:14 2000/-ko/ +/little_endian.h/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/pdp_endian.h/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/swab.h/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/swabb.h/1.4/Sat Nov 25 08:05:45 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/linux/byteorder/CVS/Repository linux-2.4-xfs/linux/include/linux/byteorder/CVS/Repository --- linux-2.4.7/linux/include/linux/byteorder/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/byteorder/CVS/Repository Thu Jul 5 12:06:45 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/linux/byteorder diff -rNu linux-2.4.7/linux/include/linux/byteorder/CVS/Root linux-2.4-xfs/linux/include/linux/byteorder/CVS/Root --- linux-2.4.7/linux/include/linux/byteorder/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/byteorder/CVS/Root Thu Jul 5 12:06:45 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/linux/dis-asm.h linux-2.4-xfs/linux/include/linux/dis-asm.h --- linux-2.4.7/linux/include/linux/dis-asm.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/dis-asm.h Mon Apr 2 12:13:32 2001 @@ -0,0 +1,304 @@ +/* Interface between the opcode library and its callers. + Written by Cygnus Support, 1993. + + The opcode library (libopcodes.a) provides instruction decoders for + a large variety of instruction sets, callable with an identical + interface, for making instruction-processing programs more independent + of the instruction set being processed. */ + +/* Hacked by Scott Lurndal at SGI (02/1999) for linux kernel debugger */ +/* Upgraded to cygnus CVS Keith Owens 30 Oct 2000 */ + +#ifndef DIS_ASM_H +#define DIS_ASM_H + +#ifdef __cplusplus +extern "C" { +#endif + + /* + * Misc definitions + */ +#define PARAMS(x) x +#define PTR void * +#define FILE int +#if !defined(NULL) +#define NULL 0 +#endif + +#define abort() dis_abort(__LINE__) + +extern inline void +dis_abort(int line) +{ + panic("Aborting dissembler in %s @ line %d\n", __FILE__, line); +} + +#include +#include +#define xstrdup(string) ({ char *res = kdb_strdup(string, GFP_KERNEL); if (!res) BUG(); res; }) +#define xmalloc(size) ({ void *res = kmalloc(size, GFP_KERNEL); if (!res) BUG(); res; }) +#define free(address) kfree(address) + +#include + +typedef int (*fprintf_ftype) PARAMS((PTR, const char*, ...)); + +enum dis_insn_type { + dis_noninsn, /* Not a valid instruction */ + dis_nonbranch, /* Not a branch instruction */ + dis_branch, /* Unconditional branch */ + dis_condbranch, /* Conditional branch */ + dis_jsr, /* Jump to subroutine */ + dis_condjsr, /* Conditional jump to subroutine */ + dis_dref, /* Data reference instruction */ + dis_dref2 /* Two data references in instruction */ +}; + +/* This struct is passed into the instruction decoding routine, + and is passed back out into each callback. The various fields are used + for conveying information from your main routine into your callbacks, + for passing information into the instruction decoders (such as the + addresses of the callback functions), or for passing information + back from the instruction decoders to their callers. + + It must be initialized before it is first passed; this can be done + by hand, or using one of the initialization macros below. */ + +typedef struct disassemble_info { + fprintf_ftype fprintf_func; + PTR stream; + PTR application_data; + + /* Target description. We could replace this with a pointer to the bfd, + but that would require one. There currently isn't any such requirement + so to avoid introducing one we record these explicitly. */ + /* The bfd_flavour. This can be bfd_target_unknown_flavour. */ + enum bfd_flavour flavour; + /* The bfd_arch value. */ + enum bfd_architecture arch; + /* The bfd_mach value. */ + unsigned long mach; + /* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */ + enum bfd_endian endian; + + /* An array of pointers to symbols either at the location being disassembled + or at the start of the function being disassembled. The array is sorted + so that the first symbol is intended to be the one used. The others are + present for any misc. purposes. This is not set reliably, but if it is + not NULL, it is correct. */ + asymbol **symbols; + /* Number of symbols in array. */ + int num_symbols; + + /* For use by the disassembler. + The top 16 bits are reserved for public use (and are documented here). + The bottom 16 bits are for the internal use of the disassembler. */ + unsigned long flags; +#define INSN_HAS_RELOC 0x80000000 + PTR private_data; + + /* Function used to get bytes to disassemble. MEMADDR is the + address of the stuff to be disassembled, MYADDR is the address to + put the bytes in, and LENGTH is the number of bytes to read. + INFO is a pointer to this struct. + Returns an errno value or 0 for success. */ + int (*read_memory_func) + PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, unsigned int length, + struct disassemble_info *info)); + + /* Function which should be called if we get an error that we can't + recover from. STATUS is the errno value from read_memory_func and + MEMADDR is the address that we were trying to read. INFO is a + pointer to this struct. */ + void (*memory_error_func) + PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info)); + + /* Function called to print ADDR. */ + void (*print_address_func) + PARAMS ((bfd_vma addr, struct disassemble_info *info)); + + /* Function called to determine if there is a symbol at the given ADDR. + If there is, the function returns 1, otherwise it returns 0. + This is used by ports which support an overlay manager where + the overlay number is held in the top part of an address. In + some circumstances we want to include the overlay number in the + address, (normally because there is a symbol associated with + that address), but sometimes we want to mask out the overlay bits. */ + int (* symbol_at_address_func) + PARAMS ((bfd_vma addr, struct disassemble_info * info)); + + /* These are for buffer_read_memory. */ + bfd_byte *buffer; + bfd_vma buffer_vma; + unsigned int buffer_length; + + /* This variable may be set by the instruction decoder. It suggests + the number of bytes objdump should display on a single line. If + the instruction decoder sets this, it should always set it to + the same value in order to get reasonable looking output. */ + int bytes_per_line; + + /* the next two variables control the way objdump displays the raw data */ + /* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */ + /* output will look like this: + 00: 00000000 00000000 + with the chunks displayed according to "display_endian". */ + int bytes_per_chunk; + enum bfd_endian display_endian; + + /* Number of octets per incremented target address + Normally one, but some DSPs have byte sizes of 16 or 32 bits + */ + unsigned int octets_per_byte; + + /* Results from instruction decoders. Not all decoders yet support + this information. This info is set each time an instruction is + decoded, and is only valid for the last such instruction. + + To determine whether this decoder supports this information, set + insn_info_valid to 0, decode an instruction, then check it. */ + + char insn_info_valid; /* Branch info has been set. */ + char branch_delay_insns; /* How many sequential insn's will run before + a branch takes effect. (0 = normal) */ + char data_size; /* Size of data reference in insn, in bytes */ + enum dis_insn_type insn_type; /* Type of instruction */ + bfd_vma target; /* Target address of branch or dref, if known; + zero if unknown. */ + bfd_vma target2; /* Second target address for dref2 */ + + /* Command line options specific to the target disassembler. */ + char * disassembler_options; + +} disassemble_info; + + +/* Standard disassemblers. Disassemble one instruction at the given + target address. Return number of bytes processed. */ +typedef int (*disassembler_ftype) + PARAMS((bfd_vma, disassemble_info *)); + +extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i386_att PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i386_intel PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_ia64 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i370 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68hc11 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68hc12 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8001 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8002 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300h PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300s PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*)); +extern disassembler_ftype arc_get_disassembler PARAMS ((int, int)); +extern int print_insn_big_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i860 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i960 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sh PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_shl PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_hppa PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_fr30 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m32r PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m88k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mcore PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mn10200 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mn10300 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_ns32k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_powerpc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_powerpc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_rs6000 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_w65 PARAMS ((bfd_vma, disassemble_info*)); +extern disassembler_ftype cris_get_disassembler PARAMS ((bfd *)); +extern int print_insn_d10v PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_d30v PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_vax PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic54x PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic80 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_pj PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_avr PARAMS ((bfd_vma, disassemble_info*)); + +extern void print_arm_disassembler_options PARAMS ((FILE *)); +extern void parse_arm_disassembler_option PARAMS ((char *)); +extern int get_arm_regname_num_options PARAMS ((void)); +extern int set_arm_regname_option PARAMS ((int)); +extern int get_arm_regnames PARAMS ((int, const char **, const char **, const char ***)); + +/* Fetch the disassembler for a given BFD, if that support is available. */ +extern disassembler_ftype disassembler PARAMS ((bfd *)); + +/* Document any target specific options available from the disassembler. */ +extern void disassembler_usage PARAMS ((FILE *)); + + +/* This block of definitions is for particular callers who read instructions + into a buffer before calling the instruction decoder. */ + +/* Here is a function which callers may wish to use for read_memory_func. + It gets bytes from a buffer. */ +extern int buffer_read_memory + PARAMS ((bfd_vma, bfd_byte *, unsigned int, struct disassemble_info *)); + +/* This function goes with buffer_read_memory. + It prints a message using info->fprintf_func and info->stream. */ +extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *)); + + +/* Just print the address in hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ +extern void generic_print_address + PARAMS ((bfd_vma, struct disassemble_info *)); + +/* Always true. */ +extern int generic_symbol_at_address + PARAMS ((bfd_vma, struct disassemble_info *)); + +/* Macro to initialize a disassemble_info struct. This should be called + by all applications creating such a struct. */ +#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).flavour = bfd_target_unknown_flavour, \ + (INFO).arch = bfd_arch_unknown, \ + (INFO).mach = 0, \ + (INFO).endian = BFD_ENDIAN_UNKNOWN, \ + (INFO).octets_per_byte = 1, \ + INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) + +/* Call this macro to initialize only the internal variables for the + disassembler. Architecture dependent things such as byte order, or machine + variant are not touched by this macro. This makes things much easier for + GDB which must initialize these things separately. */ + +#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).fprintf_func = (fprintf_ftype)(FPRINTF_FUNC), \ + (INFO).stream = (PTR)(STREAM), \ + (INFO).symbols = NULL, \ + (INFO).num_symbols = 0, \ + (INFO).buffer = NULL, \ + (INFO).buffer_vma = 0, \ + (INFO).buffer_length = 0, \ + (INFO).read_memory_func = buffer_read_memory, \ + (INFO).memory_error_func = perror_memory, \ + (INFO).print_address_func = generic_print_address, \ + (INFO).symbol_at_address_func = generic_symbol_at_address, \ + (INFO).flags = 0, \ + (INFO).bytes_per_line = 0, \ + (INFO).bytes_per_chunk = 0, \ + (INFO).display_endian = BFD_ENDIAN_UNKNOWN, \ + (INFO).insn_info_valid = 0 + +#ifdef __cplusplus +}; +#endif + +#endif /* ! defined (DIS_ASM_H) */ diff -rNu linux-2.4.7/linux/include/linux/dmapi.h linux-2.4-xfs/linux/include/linux/dmapi.h --- linux-2.4.7/linux/include/linux/dmapi.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/dmapi.h Tue Oct 24 13:08:31 2000 @@ -0,0 +1,1033 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef _SYS_DMAPI_H +#define _SYS_DMAPI_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/************************************************************************** + * * + * The SGI implementation of DMAPI is based upon the X/Open document * + * Systems Management: Data Storage Managment (XDSM) API * + * dated February 1997. Not all DMAPI functions and structure fields * + * have been implemented. Most importantly, the DMAPI functions * + * dm_request_right, dm_release_right, dm_query_right, dm_upgrade_right * + * and dm_downgrade_right do not work as described in the specification. * + * * + * The XFS filesystem currently does not allow its locking mechanisms to * + * be externally accessed from user space. While the above-mentioned * + * dm_xxx_right functions exist and can be called by applications, they * + * always return successfully without actually obtaining any locks * + * within the filesystem. * + * * + * Applications which do not need full rights support and which only * + * make dm_xxx_right calls in order to satisfy the input requirements of * + * other DMAPI calls should be able to use these routines to avoid * + * having to implement special-case code for SGI platforms. Applications * + * which truely need the capabilities of a full implementation of rights * + * will unfortunately have to come up with alternate software solutions * + * until such time as rights can be completely implemented. * + * * + * Functions and structure fields defined within this file which are not * + * supported in the SGI implementation of DMAPI are indicated by comments * + * following their definitions such as "not supported", or "not * + * completely supported". Any function or field not so marked may be * + * assumed to work exactly according to the spec. * + * * + **************************************************************************/ + + + +/* The first portion of this file contains defines and typedefs that are + DMAPI implementation-dependent, and could be different on other platforms. +*/ + +typedef __s64 dm_attrloc_t; +typedef unsigned int dm_boolean_t; +typedef __u64 dm_eventset_t; +typedef __u64 dm_fsid_t; +typedef __u64 dm_ino_t; +typedef __u32 dm_igen_t; +typedef __s64 dm_off_t; +typedef unsigned int dm_sequence_t; +typedef int dm_sessid_t; +typedef __u64 dm_size_t; +typedef __s64 dm_ssize_t; +typedef int dm_token_t; + +/* XXX dev_t, mode_t, and nlink_t are not the same size in kernel space + and user space. This affects the field offsets for dm_stat_t. + The following solution is temporary. + + user space sizes: dev_t=8 mode_t=4 nlink_t=4 + kernel space : dev_t=2 mode_t=2 nlink_t=2 + +*/ +typedef __s64 dm_dev_t; +typedef int dm_mode_t; +typedef int dm_nlink_t; + + +#define DM_REGION_NOEVENT 0x0 +#define DM_REGION_READ 0x1 +#define DM_REGION_WRITE 0x2 +#define DM_REGION_TRUNCATE 0x4 + +/* Values for the mask argument used with dm_get_fileattr, dm_get_bulkattr, + dm_get_dirattrs, and dm_set_fileattr. +*/ + +#define DM_AT_MODE 0x0001 +#define DM_AT_UID 0x0002 +#define DM_AT_GID 0x0004 +#define DM_AT_ATIME 0x0008 +#define DM_AT_MTIME 0x0010 +#define DM_AT_CTIME 0x0020 +#define DM_AT_SIZE 0x0040 +#define DM_AT_DTIME 0x0080 +#define DM_AT_HANDLE 0x0100 +#define DM_AT_EMASK 0x0200 +#define DM_AT_PMANR 0x0400 +#define DM_AT_PATTR 0x0800 +#define DM_AT_STAT 0x1000 +#define DM_AT_CFLAG 0x2000 + +#define DM_EV_WAIT 0x1 /* used in dm_get_events() */ + +#define DM_MOUNT_RDONLY 0x1 /* me_mode field in dm_mount_event_t */ + +#define DM_RR_WAIT 0x1 + +#define DM_UNMOUNT_FORCE 0x1 /* ne_mode field in dm_namesp_event_t */ + +#define DM_WRITE_SYNC 0x1 /* used in dm_write_invis() */ + +#define DM_SESSION_INFO_LEN 256 +#define DM_NO_SESSION 0 +#define DM_TRUE 1 +#define DM_FALSE 0 +#define DM_INVALID_TOKEN 0 +#define DM_NO_TOKEN (-1) +#define DM_INVALID_HANP NULL +#define DM_INVALID_HLEN 0 +#define DM_GLOBAL_HANP ((void *)(1LL)) +#define DM_GLOBAL_HLEN ((size_t)(1)) +#define DM_VER_STR_CONTENTS "SGI DMAPI (XDSM) API, Release 1.0." + + +#define DMEV_SET(event_type, event_list) \ + ((event_list) |= (1 << (event_type))) +#define DMEV_CLR(event_type, event_list) \ + ((event_list) &= ~(1 << (event_type))) +#define DMEV_ISSET(event_type, event_list) \ + (int)(((event_list) & (1 << (event_type))) != 0) +#define DMEV_ZERO(event_list) \ + (event_list) = 0 + + +typedef struct { + int vd_offset; /* offset from start of containing struct */ + unsigned int vd_length; /* length of data starting at vd_offset */ +} dm_vardata_t; + +#define DM_GET_VALUE(p, field, type) \ + ((type) ((char *)(p) + (p)->field.vd_offset)) + +#define DM_GET_LEN(p, field) \ + ((p)->field.vd_length) + +#define DM_STEP_TO_NEXT(p, type) \ + ((type) ((p)->_link ? (char *)(p) + (p)->_link : NULL)) + + + + +/* The remainder of this include file contains defines, typedefs, and + structures which are strictly defined by the DMAPI 2.3 specification. + + (The _link field which appears in several structures is an + implementation-specific way to implement DM_STEP_TO_NEXT, and + should not be referenced directly by application code.) +*/ + + +#define DM_ATTR_NAME_SIZE 8 + + +struct dm_attrname { + unsigned char an_chars[DM_ATTR_NAME_SIZE]; +}; +typedef struct dm_attrname dm_attrname_t; + + +struct dm_attrlist { + int _link; + dm_attrname_t al_name; + dm_vardata_t al_data; +}; +typedef struct dm_attrlist dm_attrlist_t; + + +typedef enum { + DM_CONFIG_INVALID, + DM_CONFIG_BULKALL, + DM_CONFIG_CREATE_BY_HANDLE, + DM_CONFIG_DTIME_OVERLOAD, + DM_CONFIG_LEGACY, + DM_CONFIG_LOCK_UPGRADE, + DM_CONFIG_MAX_ATTR_ON_DESTROY, + DM_CONFIG_MAX_ATTRIBUTE_SIZE, + DM_CONFIG_MAX_HANDLE_SIZE, + DM_CONFIG_MAX_MANAGED_REGIONS, + DM_CONFIG_MAX_MESSAGE_DATA, + DM_CONFIG_OBJ_REF, + DM_CONFIG_PENDING, + DM_CONFIG_PERS_ATTRIBUTES, + DM_CONFIG_PERS_EVENTS, + DM_CONFIG_PERS_INHERIT_ATTRIBS, + DM_CONFIG_PERS_MANAGED_REGIONS, + DM_CONFIG_PUNCH_HOLE, + DM_CONFIG_TOTAL_ATTRIBUTE_SPACE, + DM_CONFIG_WILL_RETRY +} dm_config_t; + + +struct dm_dioinfo { /* non-standard SGI addition */ + unsigned int d_mem; + unsigned int d_miniosz; + unsigned int d_maxiosz; + dm_boolean_t d_dio_only; +}; +typedef struct dm_dioinfo dm_dioinfo_t; + + +struct dm_dispinfo { + int _link; + unsigned int di_pad1; /* reserved; do not reference */ + dm_vardata_t di_fshandle; + dm_eventset_t di_eventset; +}; +typedef struct dm_dispinfo dm_dispinfo_t; + + +typedef enum { + DM_EVENT_INVALID = -1, + DM_EVENT_CANCEL = 0, /* not supported */ + DM_EVENT_MOUNT = 1, + DM_EVENT_PREUNMOUNT = 2, + DM_EVENT_UNMOUNT = 3, + DM_EVENT_DEBUT = 4, /* not supported */ + DM_EVENT_CREATE = 5, + DM_EVENT_CLOSE = 6, /* not supported */ + DM_EVENT_POSTCREATE = 7, + DM_EVENT_REMOVE = 8, + DM_EVENT_POSTREMOVE = 9, + DM_EVENT_RENAME = 10, + DM_EVENT_POSTRENAME = 11, + DM_EVENT_LINK = 12, + DM_EVENT_POSTLINK = 13, + DM_EVENT_SYMLINK = 14, + DM_EVENT_POSTSYMLINK = 15, + DM_EVENT_READ = 16, + DM_EVENT_WRITE = 17, + DM_EVENT_TRUNCATE = 18, + DM_EVENT_ATTRIBUTE = 19, + DM_EVENT_DESTROY = 20, + DM_EVENT_NOSPACE = 21, + DM_EVENT_USER = 22, + DM_EVENT_MAX = 23 +} dm_eventtype_t; + + +struct dm_eventmsg { + int _link; + dm_eventtype_t ev_type; + dm_token_t ev_token; + dm_sequence_t ev_sequence; + dm_vardata_t ev_data; +}; +typedef struct dm_eventmsg dm_eventmsg_t; + + +struct dm_cancel_event { /* not supported */ + dm_sequence_t ce_sequence; + dm_token_t ce_token; +}; +typedef struct dm_cancel_event dm_cancel_event_t; + + +struct dm_data_event { + dm_vardata_t de_handle; + dm_off_t de_offset; + dm_size_t de_length; +}; +typedef struct dm_data_event dm_data_event_t; + +struct dm_destroy_event { + dm_vardata_t ds_handle; + dm_attrname_t ds_attrname; + dm_vardata_t ds_attrcopy; +}; +typedef struct dm_destroy_event dm_destroy_event_t; + +struct dm_mount_event { + mode_t me_mode; + dm_vardata_t me_handle1; + dm_vardata_t me_handle2; + dm_vardata_t me_name1; + dm_vardata_t me_name2; + dm_vardata_t me_roothandle; +}; +typedef struct dm_mount_event dm_mount_event_t; + +struct dm_namesp_event { + mode_t ne_mode; + dm_vardata_t ne_handle1; + dm_vardata_t ne_handle2; + dm_vardata_t ne_name1; + dm_vardata_t ne_name2; + int ne_retcode; +}; +typedef struct dm_namesp_event dm_namesp_event_t; + + +typedef enum { + DM_EXTENT_INVALID, + DM_EXTENT_RES, + DM_EXTENT_HOLE +} dm_extenttype_t; + + +struct dm_extent { + dm_extenttype_t ex_type; + unsigned int ex_pad1; /* reserved; do not reference */ + dm_off_t ex_offset; + dm_size_t ex_length; +}; +typedef struct dm_extent dm_extent_t; + +struct dm_fileattr { + mode_t fa_mode; + uid_t fa_uid; + gid_t fa_gid; + time_t fa_atime; + time_t fa_mtime; + time_t fa_ctime; + time_t fa_dtime; + unsigned int fa_pad1; /* reserved; do not reference */ + dm_off_t fa_size; +}; +typedef struct dm_fileattr dm_fileattr_t; + + +struct dm_inherit { /* not supported */ + dm_attrname_t ih_name; + mode_t ih_filetype; +}; +typedef struct dm_inherit dm_inherit_t; + + +typedef enum { + DM_MSGTYPE_INVALID, + DM_MSGTYPE_SYNC, + DM_MSGTYPE_ASYNC +} dm_msgtype_t; + + +struct dm_region { + dm_off_t rg_offset; + dm_size_t rg_size; + unsigned int rg_flags; + unsigned int rg_pad1; /* reserved; do not reference */ +}; +typedef struct dm_region dm_region_t; + + +typedef enum { + DM_RESP_INVALID, + DM_RESP_CONTINUE, + DM_RESP_ABORT, + DM_RESP_DONTCARE +} dm_response_t; + + +typedef enum { + DM_RIGHT_NULL, + DM_RIGHT_SHARED, + DM_RIGHT_EXCL +} dm_right_t; + + +struct dm_stat { + int _link; + dm_vardata_t dt_handle; + dm_vardata_t dt_compname; + int dt_nevents; + dm_eventset_t dt_emask; + int dt_pers; /* field not supported */ + int dt_pmanreg; + time_t dt_dtime; + unsigned int dt_change; /* field not supported */ + unsigned int dt_pad1; /* reserved; do not reference */ + dm_dev_t dt_dev; + dm_ino_t dt_ino; + dm_mode_t dt_mode; + dm_nlink_t dt_nlink; + uid_t dt_uid; + gid_t dt_gid; + dm_dev_t dt_rdev; + unsigned int dt_pad2; /* reserved; do not reference */ + dm_off_t dt_size; + time_t dt_atime; + time_t dt_mtime; + time_t dt_ctime; + unsigned int dt_blksize; + dm_size_t dt_blocks; + + /* Non-standard filesystem-specific fields. Currently XFS is the only + supported filesystem type. + */ + + __u64 dt_pad3; /* reserved; do not reference */ + int dt_fstype; /* filesystem index; see sysfs(2) */ + union { + struct { + dm_igen_t igen; + unsigned int xflags; + unsigned int extsize; + unsigned int extents; + unsigned short aextents; + unsigned short dmstate; + } sgi_xfs; + } fsys_dep; +}; +typedef struct dm_stat dm_stat_t; + +#define dt_xfs_igen fsys_dep.sgi_xfs.igen +#define dt_xfs_xflags fsys_dep.sgi_xfs.xflags +#define dt_xfs_extsize fsys_dep.sgi_xfs.extsize +#define dt_xfs_extents fsys_dep.sgi_xfs.extents +#define dt_xfs_aextents fsys_dep.sgi_xfs.aextents +#define dt_xfs_dmstate fsys_dep.sgi_xfs.dmstate + +/* Flags for the non-standard dt_xfs_xflags field. */ + +#define DM_XFLAG_REALTIME 0x1 +#define DM_XFLAG_PREALLOC 0x2 +#define DM_XFLAG_HASATTR 0x80000000 + + +struct dm_timestruct { + time_t dm_tv_sec; + int dm_tv_nsec; +}; +typedef struct dm_timestruct dm_timestruct_t; + + +struct dm_xstat { /* not supported */ + dm_stat_t dx_statinfo; + dm_vardata_t dx_attrdata; +}; +typedef struct dm_xstat dm_xstat_t; + + + +/* The following list provides the prototypes for all functions defined in + the DMAPI interface. +*/ + +extern int +dm_clear_inherit( /* not supported */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep); + +extern int +dm_create_by_handle( /* not supported */ + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname); + +extern int +dm_create_session( + dm_sessid_t oldsid, + char *sessinfop, + dm_sessid_t *newsidp); + +extern int +dm_create_userevent( + dm_sessid_t sid, + size_t msglen, + void *msgdatap, + dm_token_t *tokenp); + +extern int +dm_destroy_session( + dm_sessid_t sid); + +extern int +dm_downgrade_right( /* not completely supported; see caveat above */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern int +dm_fd_to_handle( + int fd, + void **hanpp, + size_t *hlenp); + +extern int +dm_find_eventmsg( + dm_sessid_t sid, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_allocinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t *offp, + unsigned int nelem, + dm_extent_t *extentp, + unsigned int *nelemp); + +extern int +dm_get_bulkall( /* not supported */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int mask, + dm_attrname_t *attrnamep, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_bulkattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_config( + void *hanp, + size_t hlen, + dm_config_t flagname, + dm_size_t *retvalp); + +extern int +dm_get_config_events( + void *hanp, + size_t hlen, + unsigned int nelem, + dm_eventset_t *eventsetp, + unsigned int *nelemp); + +extern int +dm_get_dirattrs( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int nelem, + dm_eventset_t *eventsetp, + unsigned int *nelemp); + +extern int +dm_get_events( + dm_sessid_t sid, + unsigned int maxmsgs, + unsigned int flags, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_fileattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int mask, + dm_stat_t *statp); + +extern int +dm_get_mountinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_get_region( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int nelem, + dm_region_t *regbufp, + unsigned int *nelemp); + +extern int +dm_getall_disp( + dm_sessid_t sid, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_getall_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern int +dm_getall_inherit( /* not supported */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int nelem, + dm_inherit_t *inheritbufp, + unsigned int *nelemp); + +extern int +dm_getall_sessions( + unsigned int nelem, + dm_sessid_t *sidbufp, + unsigned int *nelemp); + +extern int +dm_getall_tokens( + dm_sessid_t sid, + unsigned int nelem, + dm_token_t *tokenbufp, + unsigned int *nelemp); + +extern int +dm_handle_cmp( + void *hanp1, + size_t hlen1, + void *hanp2, + size_t hlen2); + +extern void +dm_handle_free( + void *hanp, + size_t hlen); + +extern u_int +dm_handle_hash( + void *hanp, + size_t hlen); + +extern dm_boolean_t +dm_handle_is_valid( + void *hanp, + size_t hlen); + +extern int +dm_handle_to_fshandle( + void *hanp, + size_t hlen, + void **fshanpp, + size_t *fshlenp); + +extern int +dm_handle_to_fsid( + void *hanp, + size_t hlen, + dm_fsid_t *fsidp); + +extern int +dm_handle_to_igen( + void *hanp, + size_t hlen, + dm_igen_t *igenp); + +extern int +dm_handle_to_ino( + void *hanp, + size_t hlen, + dm_ino_t *inop); + +extern int +dm_handle_to_path( + void *dirhanp, + size_t dirhlen, + void *targhanp, + size_t targhlen, + size_t buflen, + char *pathbufp, + size_t *rlenp); + +extern int +dm_init_attrloc( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrloc_t *locp); + +extern int +dm_init_service( + char **versionstrpp); + +extern int +dm_make_handle( + dm_fsid_t *fsidp, + dm_ino_t *inop, + dm_igen_t *igenp, + void **hanpp, + size_t *hlenp); + +extern int +dm_make_fshandle( + dm_fsid_t *fsidp, + void **hanpp, + size_t *hlenp); + +extern int +dm_mkdir_by_handle( /* not supported */ + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname); + +extern int +dm_move_event( + dm_sessid_t srcsid, + dm_token_t token, + dm_sessid_t targetsid, + dm_token_t *rtokenp); + +extern int +dm_obj_ref_hold( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +extern int +dm_obj_ref_query( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +extern int +dm_obj_ref_rele( + dm_sessid_t sid, + dm_token_t token, + void *hanp, + size_t hlen); + +extern int +dm_path_to_fshandle( + char *path, + void **hanpp, + size_t *hlenp); + +extern int +dm_path_to_handle( + char *path, + void **hanpp, + size_t *hlenp); + +extern int +dm_pending( + dm_sessid_t sid, + dm_token_t token, + dm_timestruct_t *delay); + +extern int +dm_probe_hole( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + dm_off_t *roffp, + dm_size_t *rlenp); + +extern int +dm_punch_hole( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len); + +extern int +dm_query_right( /* not completely supported; see caveat above */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_right_t *rightp); + +extern int +dm_query_session( + dm_sessid_t sid, + size_t buflen, + void *bufp, + size_t *rlenp); + +extern dm_ssize_t +dm_read_invis( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_off_t off, + dm_size_t len, + void *bufp); + +extern int +dm_release_right( /* not completely supported; see caveat above */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern int +dm_remove_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int setdtime, + dm_attrname_t *attrnamep); + +extern int +dm_request_right( /* not completely supported; see caveat above */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int flags, + dm_right_t right); + +extern int +dm_respond_event( + dm_sessid_t sid, + dm_token_t token, + dm_response_t response, + int reterror, + size_t buflen, + void *respbufp); + +extern int +dm_send_msg( + dm_sessid_t targetsid, + dm_msgtype_t msgtype, + size_t buflen, + void *bufp); + +extern int +dm_set_disp( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + unsigned int maxevent); + +extern int +dm_set_dmattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + int setdtime, + size_t buflen, + void *bufp); + +extern int +dm_set_eventlist( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_eventset_t *eventsetp, + unsigned int maxevent); + +extern int +dm_set_fileattr( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int mask, + dm_fileattr_t *attrp); + +extern int +dm_set_inherit( /* not supported */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + mode_t mode); + +extern int +dm_set_region( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + unsigned int nelem, + dm_region_t *regbufp, + dm_boolean_t *exactflagp); + +extern int +dm_set_return_on_destroy( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_attrname_t *attrnamep, + dm_boolean_t enable); + +extern int +dm_symlink_by_handle( /* not supported */ + dm_sessid_t sid, + void *dirhanp, + size_t dirhlen, + dm_token_t token, + void *hanp, + size_t hlen, + char *cname, + char *path); + +extern int +dm_sync_by_handle( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern int +dm_upgrade_right( /* not completely supported; see caveat above */ + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token); + +extern dm_ssize_t +dm_write_invis( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + int flags, + dm_off_t off, + dm_size_t len, + void *bufp); + +/* Non-standard SGI additions to the DMAPI interface. */ + +extern int +dm_get_dioinfo( + dm_sessid_t sid, + void *hanp, + size_t hlen, + dm_token_t token, + dm_dioinfo_t *diop); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_DMAPI_H */ + diff -rNu linux-2.4.7/linux/include/linux/dmapi_kern.h linux-2.4-xfs/linux/include/linux/dmapi_kern.h --- linux-2.4.7/linux/include/linux/dmapi_kern.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/dmapi_kern.h Tue Jan 16 22:01:25 2001 @@ -0,0 +1,575 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef __DMAPI_KERN_H__ +#define __DMAPI_KERN_H__ + + +struct sys_dmapi_args { + long arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11; +}; +typedef struct sys_dmapi_args sys_dmapi_args_t; + + +#ifdef __KERNEL__ + +struct xfs_handle_t; + +/* The first group of definitions and prototypes define the filesystem's + interface into the DMAPI code. +*/ + + +/* Definitions used for the flags field on dm_send_data_event(), + dm_send_unmount_event(), and dm_send_namesp_event() calls. +*/ + +#define DM_FLAGS_NDELAY 0x001 /* return EAGAIN after dm_pending() */ +#define DM_FLAGS_UNWANTED 0x002 /* event not in fsys dm_eventset_t */ + +/* Possible code levels reported by dm_code_level(). */ + +#define DM_CLVL_INIT 0 /* DMAPI prior to X/Open compliance */ +#define DM_CLVL_XOPEN 1 /* X/Open compliant DMAPI */ + + +/* Prototypes used outside of the DMI module/directory. */ + +int dm_send_data_event( + dm_eventtype_t event, + struct bhv_desc *bdp, + dm_right_t vp_right, + off_t off, + size_t len, + int flags); + +int dm_send_destroy_event( + struct bhv_desc *bdp, + dm_right_t vp_right); + +int dm_send_mount_event( + struct vfs *vfsp, + dm_right_t vfsp_right, + struct bhv_desc *bdp, + dm_right_t vp_right, + struct bhv_desc *rootbdp, + dm_right_t rootvp_right, + char *name1, + char *name2); + +int dm_send_namesp_event( + dm_eventtype_t event, + struct bhv_desc *bdp1, + dm_right_t vp1_right, + struct bhv_desc *bdp2, + dm_right_t vp2_right, + char *name1, + char *name2, + mode_t mode, + int retcode, + int flags); + +void dm_send_unmount_event( + struct vfs *vfsp, + struct vnode *vp, + dm_right_t vfsp_right, + mode_t mode, + int retcode, + int flags); + +int dm_code_level(void); + +int dm_vp_to_handle ( + struct vnode *vp, + xfs_handle_t *handlep); + +/* The following prototypes and definitions are used by DMAPI as its + interface into the filesystem code. Communication between DMAPI and the + filesystem are established as follows: + 1. DMAPI uses the F_DMAPI command in VOP_FCNTL() to ask for the addresses + of all the functions within the filesystem that it may need to call. + 2. The filesystem returns an array of function name/address pairs which + DMAPI builds into a function vector. + The VOP_FCNTL() call is only made one time for a particular filesystem + type. From then on, DMAPI uses its function vector to call the filesystem + functions directly. Functions in the array which DMAPI doesn't recognize + are ignored. A dummy function which returns ENOSYS is used for any function + that DMAPI needs but which was not provided by the filesystem. If XFS + doesn't recognize the F_DMAPI fcntl, DMAPI assumes that it doesn't have the + X/Open support code; in this case DMAPI uses the XFS-code originally bundled + within DMAPI. + + The goal of this interface is allow incremental changes to be made to + both the filesystem and to DMAPI while minimizing inter-patch dependencies, + and to eventually allow DMAPI to support multiple filesystem types at the + same time should that become necessary. +*/ + +typedef enum { + DM_FSYS_CLEAR_INHERIT = 0, + DM_FSYS_CREATE_BY_HANDLE = 1, + DM_FSYS_DOWNGRADE_RIGHT = 2, + DM_FSYS_GET_ALLOCINFO_RVP = 3, + DM_FSYS_GET_BULKALL_RVP = 4, + DM_FSYS_GET_BULKATTR_RVP = 5, + DM_FSYS_GET_CONFIG = 6, + DM_FSYS_GET_CONFIG_EVENTS = 7, + DM_FSYS_GET_DESTROY_DMATTR = 8, + DM_FSYS_GET_DIOINFO = 9, + DM_FSYS_GET_DIRATTRS_RVP = 10, + DM_FSYS_GET_DMATTR = 11, + DM_FSYS_GET_EVENTLIST = 12, + DM_FSYS_GET_FILEATTR = 13, + DM_FSYS_GET_REGION = 14, + DM_FSYS_GETALL_DMATTR = 15, + DM_FSYS_GETALL_INHERIT = 16, + DM_FSYS_INIT_ATTRLOC = 17, + DM_FSYS_MKDIR_BY_HANDLE = 18, + DM_FSYS_PROBE_HOLE = 19, + DM_FSYS_PUNCH_HOLE = 20, + DM_FSYS_READ_INVIS_RVP = 21, + DM_FSYS_RELEASE_RIGHT = 22, + DM_FSYS_REMOVE_DMATTR = 23, + DM_FSYS_REQUEST_RIGHT = 24, + DM_FSYS_SET_DMATTR = 25, + DM_FSYS_SET_EVENTLIST = 26, + DM_FSYS_SET_FILEATTR = 27, + DM_FSYS_SET_INHERIT = 28, + DM_FSYS_SET_REGION = 29, + DM_FSYS_SYMLINK_BY_HANDLE = 30, + DM_FSYS_SYNC_BY_HANDLE = 31, + DM_FSYS_UPGRADE_RIGHT = 32, + DM_FSYS_WRITE_INVIS_RVP = 33, + DM_FSYS_MAX = 34 +} dm_fsys_switch_t; + + +#define DM_FSYS_OBJ 0x1 /* object refers to a fsys handle */ + + +/* + * Prototypes for filesystem-specific functions. + */ + +typedef int (*dm_fsys_clear_inherit_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrname_t *attrnamep); + +typedef int (*dm_fsys_create_by_handle_t)( + bhv_desc_t *bdp, + dm_right_t right, + void *hanp, + size_t hlen, + char *cname); + +typedef int (*dm_fsys_downgrade_right_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int type); /* DM_FSYS_OBJ or zero */ + +typedef int (*dm_fsys_get_allocinfo_rvp_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_off_t *offp, + u_int nelem, + dm_extent_t *extentp, + u_int *nelemp, + int *rvalp); + +typedef int (*dm_fsys_get_bulkall_rvp_t)( + bhv_desc_t *bdp, /* root vnode */ + dm_right_t right, + u_int mask, + dm_attrname_t *attrnamep, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvalp); + +typedef int (*dm_fsys_get_bulkattr_rvp_t)( + bhv_desc_t *bdp, /* root vnode */ + dm_right_t right, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvalp); + +typedef int (*dm_fsys_get_config_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_config_t flagname, + dm_size_t *retvalp); + +typedef int (*dm_fsys_get_config_events_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_eventset_t *eventsetp, + u_int *nelemp); + +typedef int (*dm_fsys_get_destroy_dmattr_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrname_t *attrnamep, + char **valuepp, + int *vlenp); + +typedef int (*dm_fsys_get_dioinfo_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_dioinfo_t *diop); + +typedef int (*dm_fsys_get_dirattrs_rvp_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int mask, + dm_attrloc_t *locp, + size_t buflen, + void *bufp, + size_t *rlenp, + int *rvalp); + +typedef int (*dm_fsys_get_dmattr_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrname_t *attrnamep, + size_t buflen, + void *bufp, + size_t *rlenp); + +typedef int (*dm_fsys_get_eventlist_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int type, + u_int nelem, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int *nelemp); /* in kernel space! */ + +typedef int (*dm_fsys_get_fileattr_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int mask, + dm_stat_t *statp); + +typedef int (*dm_fsys_get_region_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_region_t *regbufp, + u_int *nelemp); + +typedef int (*dm_fsys_getall_dmattr_t)( + bhv_desc_t *bdp, + dm_right_t right, + size_t buflen, + void *bufp, + size_t *rlenp); + +typedef int (*dm_fsys_getall_inherit_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_inherit_t *inheritbufp, + u_int *nelemp); + +typedef int (*dm_fsys_init_attrloc_t)( + bhv_desc_t *bdp, /* sometimes root vnode */ + dm_right_t right, + dm_attrloc_t *locp); + +typedef int (*dm_fsys_mkdir_by_handle_t)( + bhv_desc_t *bdp, + dm_right_t right, + void *hanp, + size_t hlen, + char *cname); + +typedef int (*dm_fsys_probe_hole_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_off_t off, + dm_size_t len, + dm_off_t *roffp, + dm_size_t *rlenp); + +typedef int (*dm_fsys_punch_hole_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_off_t off, + dm_size_t len); + +typedef int (*dm_fsys_read_invis_rvp_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp); + +typedef int (*dm_fsys_release_right_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int type); + +typedef int (*dm_fsys_remove_dmattr_t)( + bhv_desc_t *bdp, + dm_right_t right, + int setdtime, + dm_attrname_t *attrnamep); + +typedef int (*dm_fsys_request_right_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int type, /* DM_FSYS_OBJ or zero */ + u_int flags, + dm_right_t newright); + +typedef int (*dm_fsys_set_dmattr_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrname_t *attrnamep, + int setdtime, + size_t buflen, + void *bufp); + +typedef int (*dm_fsys_set_eventlist_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int type, + dm_eventset_t *eventsetp, /* in kernel space! */ + u_int maxevent); + +typedef int (*dm_fsys_set_fileattr_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int mask, + dm_fileattr_t *attrp); + +typedef int (*dm_fsys_set_inherit_t)( + bhv_desc_t *bdp, + dm_right_t right, + dm_attrname_t *attrnamep, + mode_t mode); + +typedef int (*dm_fsys_set_region_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int nelem, + dm_region_t *regbufp, + dm_boolean_t *exactflagp); + +typedef int (*dm_fsys_symlink_by_handle_t)( + bhv_desc_t *bdp, + dm_right_t right, + void *hanp, + size_t hlen, + char *cname, + char *path); + +typedef int (*dm_fsys_sync_by_handle_t)( + bhv_desc_t *bdp, + dm_right_t right); + +typedef int (*dm_fsys_upgrade_right_t)( + bhv_desc_t *bdp, + dm_right_t right, + u_int type); /* DM_FSYS_OBJ or zero */ + +typedef int (*dm_fsys_write_invis_rvp_t)( + bhv_desc_t *bdp, + dm_right_t right, + int flags, + dm_off_t off, + dm_size_t len, + void *bufp, + int *rvp); + +/* Structure definitions used by the F_DMAPI fcntl() call. */ + +typedef struct { + dm_fsys_switch_t func_no; /* function number */ + union { + dm_fsys_clear_inherit_t clear_inherit; + dm_fsys_create_by_handle_t create_by_handle; + dm_fsys_downgrade_right_t downgrade_right; + dm_fsys_get_allocinfo_rvp_t get_allocinfo_rvp; + dm_fsys_get_bulkall_rvp_t get_bulkall_rvp; + dm_fsys_get_bulkattr_rvp_t get_bulkattr_rvp; + dm_fsys_get_config_t get_config; + dm_fsys_get_config_events_t get_config_events; + dm_fsys_get_destroy_dmattr_t get_destroy_dmattr; + dm_fsys_get_dioinfo_t get_dioinfo; + dm_fsys_get_dirattrs_rvp_t get_dirattrs_rvp; + dm_fsys_get_dmattr_t get_dmattr; + dm_fsys_get_eventlist_t get_eventlist; + dm_fsys_get_fileattr_t get_fileattr; + dm_fsys_get_region_t get_region; + dm_fsys_getall_dmattr_t getall_dmattr; + dm_fsys_getall_inherit_t getall_inherit; + dm_fsys_init_attrloc_t init_attrloc; + dm_fsys_mkdir_by_handle_t mkdir_by_handle; + dm_fsys_probe_hole_t probe_hole; + dm_fsys_punch_hole_t punch_hole; + dm_fsys_read_invis_rvp_t read_invis_rvp; + dm_fsys_release_right_t release_right; + dm_fsys_remove_dmattr_t remove_dmattr; + dm_fsys_request_right_t request_right; + dm_fsys_set_dmattr_t set_dmattr; + dm_fsys_set_eventlist_t set_eventlist; + dm_fsys_set_fileattr_t set_fileattr; + dm_fsys_set_inherit_t set_inherit; + dm_fsys_set_region_t set_region; + dm_fsys_symlink_by_handle_t symlink_by_handle; + dm_fsys_sync_by_handle_t sync_by_handle; + dm_fsys_upgrade_right_t upgrade_right; + dm_fsys_write_invis_rvp_t write_invis_rvp; + } u_fc; +} fsys_function_vector_t; + +typedef struct { + int code_level; + int count; /* Number of functions in the vector */ + fsys_function_vector_t *vecp; +} dm_fcntl_vector_t; + +typedef struct { + size_t length; /* length of transfer */ + dm_eventtype_t max_event; /* Maximum (WRITE or READ) event */ + int error; /* returned error code */ +} dm_fcntl_mapevent_t; + +typedef struct { + size_t length; /* length of transfer */ + dm_eventtype_t max_event; /* Maximum (WRITE or READ) event */ + dm_eventtype_t issue_event; /* Event needed to be issued */ + int error; /* returned error code */ +} dm_fcntl_testevent_t; + +typedef struct { + int fsd_dmevmask; /* di_devmask */ + unsigned short fsd_padding; + unsigned short fsd_dmstate; /* di_dmstate */ +} dm_fcntl_fssetdm_t; + +typedef struct dm_fcntl { + int dmfc_subfunc; + union { + dm_fcntl_vector_t vecrq; + dm_fcntl_mapevent_t maprq; + dm_fcntl_testevent_t testrq; + dm_fcntl_fssetdm_t setdmrq; + } u_fcntl; +} dm_fcntl_t; + +#define DM_FCNTL_FSYSVECTOR 1 +#define DM_FCNTL_MAPEVENT 2 +#define DM_FCNTL_TESTEVENT 3 +#define DM_FCNTL_FSSETDM 4 + + +#endif /* __KERNEL__ */ + + +/* The following definitions are needed both by the kernel and by the + library routines. +*/ + +#define DM_MAX_HANDLE_SIZE 56 /* maximum size for a file handle */ + + +/* + * Opcodes for dmapi ioctl. + */ + +#define DM_CLEAR_INHERIT 1 +#define DM_CREATE_BY_HANDLE 2 +#define DM_CREATE_SESSION 3 +#define DM_CREATE_USEREVENT 4 +#define DM_DESTROY_SESSION 5 +#define DM_DOWNGRADE_RIGHT 6 +#define DM_FD_TO_HANDLE 7 +#define DM_FIND_EVENTMSG 8 +#define DM_GET_ALLOCINFO 9 +#define DM_GET_BULKALL 10 +#define DM_GET_BULKATTR 11 +#define DM_GET_CONFIG 12 +#define DM_GET_CONFIG_EVENTS 13 +#define DM_GET_DIOINFO 14 +#define DM_GET_DIRATTRS 15 +#define DM_GET_DMATTR 16 +#define DM_GET_EVENTLIST 17 +#define DM_GET_EVENTS 18 +#define DM_GET_FILEATTR 19 +#define DM_GET_MOUNTINFO 20 +#define DM_GET_REGION 21 +#define DM_GETALL_DISP 22 +#define DM_GETALL_DMATTR 23 +#define DM_GETALL_INHERIT 24 +#define DM_GETALL_SESSIONS 25 +#define DM_GETALL_TOKENS 26 +#define DM_INIT_ATTRLOC 27 +#define DM_MKDIR_BY_HANDLE 28 +#define DM_MOVE_EVENT 29 +#define DM_OBJ_REF_HOLD 30 +#define DM_OBJ_REF_QUERY 31 +#define DM_OBJ_REF_RELE 32 +#define DM_PATH_TO_FSHANDLE 33 +#define DM_PATH_TO_HANDLE 34 +#define DM_PENDING 35 +#define DM_PROBE_HOLE 36 +#define DM_PUNCH_HOLE 37 +#define DM_QUERY_RIGHT 38 +#define DM_QUERY_SESSION 39 +#define DM_READ_INVIS 40 +#define DM_RELEASE_RIGHT 41 +#define DM_REMOVE_DMATTR 42 +#define DM_REQUEST_RIGHT 43 +#define DM_RESPOND_EVENT 44 +#define DM_SEND_MSG 45 +#define DM_SET_DISP 46 +#define DM_SET_DMATTR 47 +#define DM_SET_EVENTLIST 48 +#define DM_SET_FILEATTR 49 +#define DM_SET_INHERIT 50 +#define DM_SET_REGION 51 +#define DM_SET_RETURN_ON_DESTROY 52 +#define DM_SYMLINK_BY_HANDLE 53 +#define DM_SYNC_BY_HANDLE 54 +#define DM_UPGRADE_RIGHT 55 +#define DM_WRITE_INVIS 56 + + +#endif /* __DMAPI_KERN_H__ */ diff -rNu linux-2.4.7/linux/include/linux/elf.h linux-2.4-xfs/linux/include/linux/elf.h --- linux-2.4.7/linux/include/linux/elf.h Tue Jul 3 17:45:56 2001 +++ linux-2.4-xfs/linux/include/linux/elf.h Wed May 2 01:22:13 2001 @@ -16,8 +16,10 @@ typedef __u16 Elf64_Half; typedef __s16 Elf64_SHalf; typedef __u64 Elf64_Off; -typedef __s64 Elf64_Sword; -typedef __u64 Elf64_Word; +typedef __s32 Elf64_Sword; +typedef __u32 Elf64_Word; +typedef __u64 Elf64_Xword; +typedef __s64 Elf64_Sxword; /* These constants are for the segment types stored in the image headers */ #define PT_NULL 0 @@ -180,10 +182,10 @@ } Elf32_Dyn; typedef struct { - Elf64_Word d_tag; /* entry tag value */ + Elf64_Sxword d_tag; /* entry tag value */ union { - Elf64_Word d_val; - Elf64_Word d_ptr; + Elf64_Xword d_val; + Elf64_Addr d_ptr; } d_un; } Elf64_Dyn; @@ -374,7 +376,7 @@ typedef struct elf64_rel { Elf64_Addr r_offset; /* Location at which to apply the action */ - Elf64_Word r_info; /* index and type of relocation */ + Elf64_Xword r_info; /* index and type of relocation */ } Elf64_Rel; typedef struct elf32_rela{ @@ -385,8 +387,8 @@ typedef struct elf64_rela { Elf64_Addr r_offset; /* Location at which to apply the action */ - Elf64_Word r_info; /* index and type of relocation */ - Elf64_Word r_addend; /* Constant addend used to compute value */ + Elf64_Xword r_info; /* index and type of relocation */ + Elf64_Sxword r_addend; /* Constant addend used to compute value */ } Elf64_Rela; typedef struct elf32_sym{ @@ -399,12 +401,12 @@ } Elf32_Sym; typedef struct elf64_sym { - Elf32_Word st_name; /* Symbol name, index in string tbl (yes, Elf32) */ + Elf64_Word st_name; /* Symbol name, index in string tbl */ unsigned char st_info; /* Type and binding attributes */ unsigned char st_other; /* No defined meaning, 0 */ Elf64_Half st_shndx; /* Associated section index */ Elf64_Addr st_value; /* Value of the symbol */ - Elf64_Word st_size; /* Associated symbol size */ + Elf64_Xword st_size; /* Associated symbol size */ } Elf64_Sym; @@ -429,19 +431,19 @@ typedef struct elf64_hdr { unsigned char e_ident[16]; /* ELF "magic number" */ - Elf64_SHalf e_type; + Elf64_Half e_type; Elf64_Half e_machine; - __s32 e_version; + Elf64_Word e_version; Elf64_Addr e_entry; /* Entry point virtual address */ Elf64_Off e_phoff; /* Program header table file offset */ Elf64_Off e_shoff; /* Section header table file offset */ - __s32 e_flags; - Elf64_SHalf e_ehsize; - Elf64_SHalf e_phentsize; - Elf64_SHalf e_phnum; - Elf64_SHalf e_shentsize; - Elf64_SHalf e_shnum; - Elf64_SHalf e_shstrndx; + Elf64_Word e_flags; + Elf64_Half e_ehsize; + Elf64_Half e_phentsize; + Elf64_Half e_phnum; + Elf64_Half e_shentsize; + Elf64_Half e_shnum; + Elf64_Half e_shstrndx; } Elf64_Ehdr; /* These constants define the permissions on sections in the program @@ -462,14 +464,14 @@ } Elf32_Phdr; typedef struct elf64_phdr { - __s32 p_type; - __s32 p_flags; + Elf64_Word p_type; + Elf64_Word p_flags; Elf64_Off p_offset; /* Segment file offset */ Elf64_Addr p_vaddr; /* Segment virtual address */ Elf64_Addr p_paddr; /* Segment physical address */ - Elf64_Word p_filesz; /* Segment size in file */ - Elf64_Word p_memsz; /* Segment size in memory */ - Elf64_Word p_align; /* Segment alignment, file & memory */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment, file & memory */ } Elf64_Phdr; /* sh_type */ @@ -526,16 +528,16 @@ } Elf32_Shdr; typedef struct elf64_shdr { - Elf32_Word sh_name; /* Section name, index in string tbl (yes Elf32) */ - Elf32_Word sh_type; /* Type of section (yes Elf32) */ - Elf64_Word sh_flags; /* Miscellaneous section attributes */ + Elf64_Word sh_name; /* Section name, index in string tbl */ + Elf64_Word sh_type; /* Type of section */ + Elf64_Xword sh_flags; /* Miscellaneous section attributes */ Elf64_Addr sh_addr; /* Section virtual addr at execution */ Elf64_Off sh_offset; /* Section file offset */ - Elf64_Word sh_size; /* Size of section in bytes */ - Elf32_Word sh_link; /* Index of another section (yes Elf32) */ - Elf32_Word sh_info; /* Additional section information (yes Elf32) */ - Elf64_Word sh_addralign; /* Section alignment */ - Elf64_Word sh_entsize; /* Entry size if section holds table */ + Elf64_Xword sh_size; /* Size of section in bytes */ + Elf64_Word sh_link; /* Index of another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ } Elf64_Shdr; #define EI_MAG0 0 /* e_ident[] indexes */ @@ -582,15 +584,10 @@ } Elf32_Nhdr; /* Note header in a PT_NOTE section */ -/* - * For now we use the 32 bit version of the structure until we figure - * out whether we need anything better. Note - on the Alpha, "unsigned int" - * is only 32 bits. - */ typedef struct elf64_note { - Elf32_Word n_namesz; /* Name size */ - Elf32_Word n_descsz; /* Content size */ - Elf32_Word n_type; /* Content type */ + Elf64_Word n_namesz; /* Name size */ + Elf64_Word n_descsz; /* Content size */ + Elf64_Word n_type; /* Content type */ } Elf64_Nhdr; #if ELF_CLASS == ELFCLASS32 diff -rNu linux-2.4.7/linux/include/linux/fs.h linux-2.4-xfs/linux/include/linux/fs.h --- linux-2.4.7/linux/include/linux/fs.h Tue Jul 3 17:42:55 2001 +++ linux-2.4-xfs/linux/include/linux/fs.h Mon Jul 2 10:59:04 2001 @@ -116,6 +116,14 @@ #define MS_BIND 4096 /* + * For s_posix_acl_flag + */ +#define IS_POSIX_ACL(inode) \ + ((inode)->i_sb && \ + (inode)->i_sb->s_posix_acl_flag) + + +/* * Flags that can be altered by MS_REMOUNT */ #define MS_RMT_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|\ @@ -188,7 +196,8 @@ /* This was here just to show that the number is taken - probably all these _IO(0x12,*) ioctls should be moved to blkpg.h. */ #endif - +#define BLKBSZSET _IO(0x12,110)/* set logical block size */ +#define BLKBSZGET _IO(0x12,111)/* get logical block size */ #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ #define FIBMAP _IO(0x00,1) /* bmap access */ @@ -215,12 +224,14 @@ BH_Mapped, /* 1 if the buffer has a disk mapping */ BH_New, /* 1 if the buffer is new and not yet written out */ BH_Protected, /* 1 if the buffer is protected */ + BH_Delay, /* 1 if the buffer is delayed allocate */ BH_PrivateStart,/* not a state bit, but the first bit available * for private allocation by other entities */ }; + /* * Try to keep the most commonly used fields in single cache lines (16 * bytes) to improve performance. This ordering should be @@ -275,6 +286,7 @@ #define buffer_mapped(bh) __buffer_state(bh,Mapped) #define buffer_new(bh) __buffer_state(bh,New) #define buffer_protected(bh) __buffer_state(bh,Protected) +#define buffer_delay(bh) __buffer_state(bh,Delay) #define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) @@ -309,6 +321,7 @@ #include #include #include +#include /* * Attribute flags. These should be or-ed together to figure out what @@ -484,6 +497,7 @@ struct proc_inode_info proc_i; struct socket socket_i; struct usbdev_inode_info usbdev_i; + struct xfs_inode_info xfs_i; void *generic_ip; } u; }; @@ -660,6 +674,7 @@ #include #include #include +#include extern struct list_head super_blocks; @@ -670,6 +685,7 @@ unsigned long s_blocksize; unsigned char s_blocksize_bits; unsigned char s_dirt; + unsigned char s_posix_acl_flag; unsigned long long s_maxbytes; /* Max file size */ struct file_system_type *s_type; struct super_operations *s_op; @@ -711,6 +727,7 @@ struct udf_sb_info udf_sb; struct ncp_sb_info ncpfs_sb; struct usbdev_sb_info usbdevfs_sb; + struct xfs_sb_info xfs_sb; void *generic_sbp; } u; /* @@ -796,6 +813,9 @@ unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); }; +struct acl; +struct attr_op; + struct inode_operations { int (*create) (struct inode *,struct dentry *,int); struct dentry * (*lookup) (struct inode *,struct dentry *); @@ -814,6 +834,9 @@ int (*revalidate) (struct dentry *); int (*setattr) (struct dentry *, struct iattr *); int (*getattr) (struct dentry *, struct iattr *); + int (*attrctl) (struct inode *, struct attr_op *, int); + int (*acl_get) (struct dentry *, struct acl *, struct acl *); + int (*acl_set) (struct dentry *, struct acl *, struct acl *); }; /* @@ -867,6 +890,8 @@ */ struct dentry * (*fh_to_dentry)(struct super_block *sb, __u32 *fh, int len, int fhtype, int parent); int (*dentry_to_fh)(struct dentry *, __u32 *fh, int *lenp, int need_parent); + int (*dmapi_mount_event) (struct super_block *, char *); + int (*quotactl) (struct super_block *, int, int, int, caddr_t); }; /* Inode state bits.. */ @@ -876,6 +901,7 @@ #define I_LOCK 8 #define I_FREEING 16 #define I_CLEAR 32 +#define I_NEW 64 #define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES) @@ -1265,6 +1291,13 @@ return iget4(sb, ino, NULL, NULL); } +extern struct inode * icreate4(struct super_block *, unsigned long, find_inode_t, void *); +static inline struct inode *icreate(struct super_block *sb, unsigned long ino) +{ + return icreate4(sb, ino, NULL, NULL); +} +extern void unlock_new_inode(struct inode *); + extern void clear_inode(struct inode *); extern struct inode * get_empty_inode(void); static inline struct inode * new_inode(struct super_block *sb) @@ -1309,6 +1342,7 @@ typedef int (get_block_t)(struct inode*,long,struct buffer_head*,int); /* Generic buffer handling for block filesystems.. */ +extern void create_empty_buffers(struct page *, kdev_t, unsigned long); extern int block_flushpage(struct page *, unsigned long); extern int block_symlink(struct inode *, const char *, int); extern int block_write_full_page(struct page*, get_block_t*); diff -rNu linux-2.4.7/linux/include/linux/grio.h linux-2.4-xfs/linux/include/linux/grio.h --- linux-2.4.7/linux/include/linux/grio.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/grio.h Fri Mar 23 15:13:53 2001 @@ -0,0 +1,724 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * This include file contains the definitions and structures + * used by the guaranteed rate IO subsystem + */ + +#ifndef _LINUX_GRIO_H_ +#define _LINUX_GRIO_H_ + +#include + +/* ioctl interface to GRIO on /dev/grio (10,160) */ + +#define XFS_GRIO_MAJOR 10 /* MAJOR number - misc device */ +#define XFS_GRIO_MINOR 160 /* MINOR number */ +#define XFS_GRIO_CMD 113 /* IOCTL command */ + +typedef struct xfs_grio_ioctl { /* structure to pass to ioctl */ + __u64 cmd; + __u64 arg1, arg2, arg3, arg4, arg5, arg6, arg7; +} xfs_grio_ioctl_t; + +/* cast between 64 bit number and pointer */ + +#define I64_TO_PTR(A) ((void*)(int)(A)) +#define PTR_TO_I64(A) ((__u64)(int)(void*)(A)) + +/* cast between sysarg_t and pointers */ + +#define SYSARG_TO_PTR(A) (I64_TO_PTR(A)) +#define PTR_TO_SYSARG(A) (PTR_TO_I64(A)) + +/* + * redefine type definitions + */ + +typedef __uint64_t gr_ino_t; +typedef uuid_t stream_id_t; +#ifndef _ASM_SN_TYPES_H +typedef dev_t vertex_hdl_t; +typedef signed short cnodeid_t; +#endif +typedef int toid_t; + +/* + * Global defines that determine the amount of resources used + * by the GRIO subsystem. + */ + + +/* + * maximum number of disks used by the GRIO subsystem + */ +#define MAX_NUM_DISKS 512 + +/* + * maximum number of disks in a single stripped volume used by GRIO + */ +#define MAX_ROTOR_SLOTS 256 + +/* + * maximum number of reservations allowed in GRIO subsystem + */ +#define MAX_NUM_RESERVATIONS 3000 + +/* + * maximum depth of ggd/grio command queue + */ +#define MAX_GRIO_QUEUE_COUNT 200 + +/* + * maximum number of streams returned by a single STAT call + */ +#define MAX_STREAM_STAT_COUNT MAX_NUM_RESERVATIONS + +/* + * maximum size of a GRIO device name (as recorded in the /etc/grio_config file) + */ +#define DEV_NMLEN PATH_MAX + +/* + * grio_resv structure is filled in by the user process and is sent to the + * library routine grio_request() along with the file descriptor of the + * resouce for which the I/O rate guarantee is being requested. + * + * The grio_request() call will return 0 if there are no errors. If there + * is an error the routine will return -1 and the gr_error field will + * contain the error number. In addition, if the guarantee request is + * denied due to lack of device bandwidth, then gr_optime, and gr_opsize + * will contain values describing the maximum remaining bandwidth. + * + * + * Return errors are: + * The first two errors indicate an error in the library. + * EINVAL - could not communicate to daemon + * ESRCH - invalid procid + * + * These errors indicate an error in the calling process. + * EBADF - could not stat file or file already + * has a guarantee + * EIO - error in guarantee request structure + * * start or duration time is incorrect + * * invalid flags in gr_flags field + * EPERM - invalid I/O size for file system + * ENOSPC - bandwidth could not be allocated + * ENOENT - file does not contain any extents. + * EACCES - cannot provide desired level of + * guarantee (i.e HARD vs SOFT) + */ + +typedef struct grio_resv { + char gr_action; /* RESV_UNRESV action */ + time_t gr_start; /* when to start in secs */ + time_t gr_duration; /* len of guarantee in secs*/ + time_t gr_optime; /* time of one op in usecs */ + int gr_opsize; /* size of each op in bytes*/ + stream_id_t gr_stream_id; /* stream id */ + int gr_flags; /* flags field */ + union { + dev_t gr_fsdev; /* FS being reserved */ + int gr_fd; /* fd being reserved */ + } gr_object_u; + __uint64_t gr_memloc; /* Opaque memory handle */ + int gr_error; /* returned: error code */ + char gr_errordev[DEV_NMLEN]; /* device that caused error*/ +} grio_resv_t; + + +#define gr_fsid gr_object_u.gr_fsdev +#define gr_fid gr_object_u.gr_fd + +/* + * Action values for the gr_action field + */ +#define GRIO_RESV_ACTION 0x1 +#define GRIO_UNRESV_ACTION 0x2 + +/* Define for gr_duration field. This is assumed to be the default if + * no duration is specified. (2 yrs in seconds) + */ +#define GRIO_RESV_DURATION_INFINITE (2*365*24*60*60) + +/* + * This structure is used to return statistics info to the caller. + * It is used with GRIO_GET_INFO resv_type. + * subcommands are: + * GRIO_DEV_RESVS: + * return number of reservations on the device + * identified by ( device_name) in grio_blk_t + * structure. + * GRIO_FILE_RESVS: + * return number of reservations on the file + * identified by ( fs_dev, ino) pair in grio_blk_t + * structure. + * GRIO_PROC_RESVS: + * return number of reservations for the process + * identified by ( procid ) in grio_blk_t structure. + */ +typedef struct grio_stats { + /* + * value dependent on the subcommand and grio_blk_t parameters. + */ + u_long gs_count; /* current number of reservations + * active on the device/file/proc + */ + u_long gs_maxresv; /* maximum number of reservations + * allowed on the device. + * for file/proc this is the number + * of licensed streams. + */ + u_long gs_optiosize; /* size of the optimal i/o size + * in bytes for this device. + * not defined for file/proc. + */ + char devname[DEV_NMLEN]; +} grio_stats_t; + +/* info returned to user by libgrio when MLD stuff is done */ +typedef struct grio_mem_locality_s { + cnodeid_t grio_cnode; +} grio_mem_locality_t; + +/* + * Defines for the gr_flags field. + * Set the user process or by the grio_lib + */ +#define PER_FILE_GUAR 0x00000008 +#define PER_FILE_SYS_GUAR 0x00000010 + +#define PROC_PRIVATE_GUAR 0x00000020 +#define PROC_SHARE_GUAR 0x00000040 + +#define FIXED_ROTOR_GUAR 0x00000100 +#define SLIP_ROTOR_GUAR 0x00000200 +#define NON_ROTOR_GUAR 0x00000400 + +#define REALTIME_SCHED_GUAR 0x00002000 +#define NON_SCHED_GUAR 0x00004000 + +#define SYSTEM_GUAR 0x00008000 + +#define READ_GUAR 0x00010000 +#define WRITE_GUAR 0x00020000 + +#define GUARANTEE_MASK 0x0003FFFF + +/* + * Defines for the types of reservations + * Set by the ggd daemon + */ +#define RESERVATION_STARTED 0x10000000 +#define RESERVATION_TYPE_VOD 0x20000000 + +/* + * Defines for stream states. + * Set by the grio driver. + */ +#define STREAM_REMOVE_IN_PROGRESS 0x01000000 +#define STREAM_INITIATE_IN_PROGRESS 0x02000000 + +#define STREAM_SLIPPED_ONCE 0x04000000 + +#define STREAM_ASSOCIATED 0x08000000 + +#define STREAM_STATE_MASK 0xFF000000 + +/* + * backwards compatability + */ +#define VOD_LAYOUT SLIP_ROTOR_GUAR + +#define IS_VOD_GUAR( griorp ) \ + ( (griorp->gr_flags & FIXED_ROTOR_GUAR) || \ + (griorp->gr_flags & SLIP_ROTOR_GUAR) ) + +#define IS_FILESYS_GUAR( griorp ) \ + ( griorp->gr_flags & PER_FILE_SYS_GUAR ) + +#define IS_FILE_GUAR( griorp ) \ + ( griorp->gr_flags & PER_FILE_GUAR ) + +/* This structure has information about the end object to which we are + * allocating bandwidth. + */ +struct end_info { + char gr_end_type; + char gr_dummy1[3]; + dev_t gr_dev; /* dev_t/file system dev_t */ + gr_ino_t gr_ino; /* inode number */ +}; + +/* + * Values for the gr_end_type field + */ +#define END_TYPE_NONE 0x0 /* nothing at this end */ +#define END_TYPE_REG 0x1 /* regular XFS file/fs */ +#define END_TYPE_SPECIAL 0x2 /* device special file */ + +typedef struct grio_command { + int gr_cmd; /* grio command */ + int gr_subcmd; /* grio subcommand */ + pid_t gr_procid; /* process id of requestor */ + __uint64_t gr_fp; /* file pointer */ + struct end_info one_end; /* one end info */ + struct end_info other_end; /* other end info. This is + * normally END_TYPE_NONE + * except for peer-to-peer + * cases. + */ + __uint64_t memloc; /* memory location */ + union { + grio_resv_t gr_resv; /* grio request info */ + grio_stats_t gr_stats; /* grio stats info */ + } cmd_info; + int gr_bytes_bw; /* returned bandwidth */ + int gr_usecs_bw; /* returned bandwidth */ + int gr_time_to_wait; /* kernel wait time */ +} grio_cmd_t; + +/* + * Structure definitions with fields defined as known sizes. + * This is done to have a layer of abstraction between the kernel and the + * ggd daemon. The kernel can have 32 bit inumber, file sizes, and file + * system sizes, but the ggd will always view them as 64 bit quantities. + */ +typedef struct grio_file_id { + gr_ino_t ino; + dev_t fs_dev; + pid_t procid; + __uint64_t fp; +} grio_file_id_t; + +typedef struct grio_disk_id { + int num_iops; + int opt_io_size; + time_t iops_time; +} grio_disk_id_t; + +typedef struct grio_bmbt_irec { + __uint64_t br_startoff; + __uint64_t br_startblock; + __uint64_t br_blockcount; +} grio_bmbt_irec_t; + + +/* + * defines for the gr_cmd field. + */ +#define GRIO_UNKNOWN 0 +#define GRIO_RESV 1 +#define GRIO_UNRESV 2 +#define GRIO_UNRESV_ASYNC 3 +#define GRIO_PURGE_VDEV_ASYNC 4 +#define GRIO_GET_STATS 5 +#define GRIO_GET_BW 6 +#define GRIO_GET_FILE_RESVD_BW 7 +#define GRIO_ACTIVE_COMMANDS GRIO_GET_FILE_RESVD_BW + 1 +#define GRIO_MAX_COMMANDS 20 + + +#define GRIO_ASYNC_CMD(griocp) \ + (( (griocp)->gr_cmd == GRIO_UNRESV_ASYNC ) || \ + ( (griocp)->gr_cmd == GRIO_PURGE_VDEV_ASYNC) ) + +#define GRIO_STATS_REQ(grioreq) \ + ( (grioreq)->gr_cmd == GRIO_GET_STATS ) + +#define GRIO_GET_RESV_DATA( griocp ) (&(griocp->cmd_info.gr_resv)) +#define GRIO_GET_STATS_DATA( griocp ) (&(griocp->cmd_info.gr_stats)) + +/* + * syssgi SGI_GRIO commands + */ +#define GRIO_ADD_DISK_INFO 21 +#define GRIO_UPDATE_DISK_INFO 22 +#define GRIO_ADD_STREAM_INFO 23 +#define GRIO_ADD_STREAM_DISK_INFO 24 +#define GRIO_ASSOCIATE_FILE_WITH_STREAM 25 +#define GRIO_REMOVE_STREAM_INFO 26 +#define GRIO_REMOVE_ALL_STREAMS_INFO 27 +#define GRIO_GET_FILE_EXTENTS 28 +#define GRIO_GET_FS_BLOCK_SIZE 29 +#define GRIO_GET_FILE_RT 30 +#define GRIO_WRITE_GRIO_REQ 31 +#define GRIO_READ_GRIO_REQ 32 +#define GRIO_WRITE_GRIO_RESP 33 +#define GRIO_GET_STREAM_ID 34 +#define GRIO_GET_ALL_STREAMS 35 +#define GRIO_GET_VOD_DISK_INFO 36 + +#define GRIO_MONITOR_START 37 +#define GRIO_MONITOR_GET 38 +#define GRIO_MONITOR_END 39 + +#define GRIO_READ_NUM_CMDS 40 +#define GRIO_GET_HWGRAPH_PATH 41 +#define GRIO_GET_MLD_CNODE 42 +#define GRIO_GET_FP 43 +#define GRIO_DISSOCIATE_STREAM 44 + + +#define COPY_STREAM_ID(from, to) ( bcopy(&(from),&(to), sizeof(uuid_t)) ) +#define EQUAL_STREAM_ID(one, two) ( uuid_equal( &one, &two, &status) ) +#define SET_GRIO_IOPRI(bp, iopri) BUF_GRIO_PRIVATE(bp)->grio_iopri = iopri +#define GET_GRIO_IOPRI(bp, iopri) iopri = BUF_GRIO_PRIVATE(bp)->grio_iopri + +typedef struct grio_add_disk_info_struct { + dev_t gdev; + int num_iops_rsv; + int num_iops_max; + int opt_io_size; + int rotation_slot; + int realtime_disk; +} grio_add_disk_info_struct_t; + + +typedef struct grio_stream_stat { + stream_id_t stream_id; + gr_ino_t ino; + dev_t fs_dev; + pid_t procid; +} grio_stream_stat_t; + +typedef struct grio_vod_info { + int num_rotor_slots; + int rotor_position; + int num_rotor_streams; + int num_nonrotor_streams; + int rotor_slot[MAX_ROTOR_SLOTS]; +} grio_vod_info_t; + + +#ifdef __KERNEL__ +/* + * Kernel buffer scheduling structure. + */ +/* + * grio disk information + * the kernel allocates and maintains one such structure for + * each disk used by the grio subsystem + */ +typedef struct grio_disk_info { + int num_iops_max; + int num_iops_rsv; + int opt_io_size; + int active; + lock_t lock; + struct grio_stream_disk_info *diskstreams; + + int ops_issued; + int ops_complete; + int subops_issued; + int subops_complete; + int rotate_position; + int realtime_disk; + + time_t time_start; + int opcount; + time_t reset_time; + time_t timeout_time; + toid_t timeout_id; + dev_t diskdev; +} grio_disk_info_t; + + +/* + * grio disk information used by grioidbg for global op + */ +typedef struct grio_idbg_disk_info { + grio_disk_info_t *griodp_ptr; + struct grio_idbg_disk_info *next; +} grio_idbg_disk_info_t; + + +#define GRIO_STREAM_TABLE_SIZE 50 +#define GRIO_STREAM_TABLE_INDEX( id ) ( (id / 8) % GRIO_STREAM_TABLE_SIZE ) + +/* + * grio stream information + * the kernel allocates and maintains one such structure for + * each active grio stream + */ +typedef struct grio_stream_info { + struct grio_stream_info *nextstream; + struct grio_stream_disk_info *diskstreams; + lock_t lock; + stream_id_t stream_id; + __uint64_t fp; + pid_t procid; + gr_ino_t ino; + dev_t fs_dev; + int flags; + int total_slots; + int max_count_per_slot; + int rotate_slot; + time_t last_stream_op; +} grio_stream_info_t; + + + +/* + * Macros to access the per stream flags. + */ +#define MARK_STREAM_AS_BEING_REMOVED(griosp) \ + (griosp->flags |= STREAM_REMOVE_IN_PROGRESS) + +#define MARK_STREAM_AS_INITIATING_IO(griosp) \ + (griosp->flags |= STREAM_INITIATE_IN_PROGRESS) + +#define CLEAR_STREAM_AS_INITIATING_IO(griosp) \ + (griosp->flags &= ~STREAM_INITIATE_IN_PROGRESS) + +#define STREAM_BEING_REMOVED(griosp) \ + (griosp->flags & STREAM_REMOVE_IN_PROGRESS) + +#define STREAM_INITIATE_IO(griosp) \ + (griosp->flags & STREAM_INITIATE_IN_PROGRESS) + + +#define PER_FILE_SYS_STREAM(griosp) \ + (griosp->flags & PER_FILE_SYS_GUAR) + +#define PER_FILE_STREAM(griosp) \ + (griosp->flags & PER_FILE_GUAR) + + +#define FIXED_ROTOR_STREAM( griosp ) \ + (griosp->flags & FIXED_ROTOR_GUAR) + +#define SLIP_ROTOR_STREAM( griosp ) \ + (griosp->flags & SLIP_ROTOR_GUAR) + +#define ROTOR_STREAM(griosp) \ + (FIXED_ROTOR_STREAM( griosp) || SLIP_ROTOR_STREAM(griosp)) + +#define NON_ROTOR_STREAM(griosp) \ + (griosp->flags & NON_ROTOR_GUAR) + + + +#define RT_SCHED_STREAM(griosp) \ + (griosp->flags & REALTIME_SCHED_GUAR) + +#define NS_SCHED_STREAM(griosp) \ + (griosp->flags & NON_SCHED_GUAR) + + +#define SLIPPED_ONCE_STREAM(griosp) \ + (griosp->flags & STREAM_SLIPPED_ONCE) + +#define MARK_SLIPPED_ONCE_STREAM(griosp) \ + (griosp->flags |= STREAM_SLIPPED_ONCE) + +#define CLEAR_SLIPPED_ONCE_STREAM(griosp) \ + (griosp->flags &= ~STREAM_SLIPPED_ONCE) + +#define MARK_STREAM_AS_ASSOCIATED(griosp) \ + (griosp->flags |= STREAM_ASSOCIATED) + +#define MARK_STREAM_AS_DISSOCIATED(griosp) \ + (griosp->flags &= ~STREAM_ASSOCIATED) + +#define STREAM_IS_ASSOCIATED(griosp) \ + (griosp->flags & STREAM_ASSOCIATED) + +/* + * per disk stream information + * the kernel allocates and maintaines one such structure for + * each (stream id, disk used by that stream) pair. + */ +typedef struct grio_stream_disk_info { + struct grio_stream_disk_info *nextdiskinstream; + grio_stream_info_t *thisstream; + struct grio_stream_disk_info *nextstream; + grio_disk_info_t *griodp; + + lock_t lock; /* lock to protect structure */ + time_t period_end; /* time current period will end */ + time_t iops_time; /* length of period for this stream */ + xfs_buf_t *realbp; /* orignal bp from xlv for this request */ + xfs_buf_t *bp_list; /* list of sub bps for this request */ + xfs_buf_t *issued_bp_list; /* list of issued sub bps for this request */ + xfs_buf_t *queuedbps_front; /* ptrs to queue of bps using this */ + xfs_buf_t *queuedbps_back; /* stream id */ + int iops_remaining_this_period; /* num grios left for this req this prd */ + time_t time_priority_start; + time_t last_op_time; /* time last out of band op */ + int num_iops; /* num grios for this req this period */ + int opt_io_size; /* size of grio request */ +} grio_stream_disk_info_t; + +/* This structure defines a linked list of rate guaranteed requests which + * have been issued by clients but not yet satisfied by the daemon. + */ +typedef struct grio_cmd_queue { + sema_t sema; + int num_cmds; + grio_cmd_t *griocmd; + struct grio_cmd_queue *forw; + struct grio_cmd_queue *back; +} grio_cmd_queue_t; + +#define GRIO_NONGUARANTEED_STREAM(griosp) \ + ( EQUAL_STREAM_ID( griosp->stream_id, non_guaranteed_id ) ) + +/* + * Private data attached to the buffer structures. + * This structure may NOT contain any data unique specific to a + * per disk I/O request. It is common to all the bps generated from + * a single user I/O request. + */ +typedef struct grio_buf_data { + uuid_t grio_id; /* stream id of stream associated */ + short grio_iopri; /* priority of the io, b_iopri */ +#ifdef GRIO_DEBUG /* with this I/O request */ + time_t start_time; + time_t enter_queue_time; +#endif +} grio_buf_data_t; + + + +#ifdef GRIO_DEBUG +#define INIT_GRIO_TIMESTAMP( bp ) { \ + if ( BUF_IS_GRIO( bp ) ) { \ + BUF_GRIO_PRIVATE(bp)->start_time = lbolt; \ + } \ +} + +#define CHECK_GRIO_TIMESTAMP( bp, maxtime ) { \ + if ( BUF_IS_GRIO( bp ) ) { \ + if ((lbolt - BUF_GRIO_PRIVATE(bp)->start_time) > maxtime) {\ + printf("GRIO TIMESTAMP %d TICKS: file %s, line %d\n", \ + lbolt - BUF_GRIO_PRIVATE(bp)->start_time,\ + __FILE__,__LINE__); \ + } \ + } \ +} + +#else +#define INIT_GRIO_TIMESTAMP( bp ) +#define CHECK_GRIO_TIMESTAMP( bp, maxtime ) +#endif + + +#define BUF_GRIO_PRIVATE(bp) ((grio_buf_data_t *)((bp)->b_grio_private)) + +/* + * Global lock and unlock macros + */ +#define GRIO_GLOB_LOCK() mutex_spinlock(&grio_global_lock) +#define GRIO_GLOB_UNLOCK(s) mutex_spinunlock(&grio_global_lock, s) + +#define GRIO_STABLE_LOCK() mutex_spinlock(&grio_stream_table_lock) +#define GRIO_STABLE_UNLOCK(s) \ + mutex_spinunlock(&grio_stream_table_lock, s) + +#define GRIO_DISK_LOCK(griodp) mutex_spinlock(&griodp->lock) +#define GRIO_DISK_UNLOCK(griodp,s) mutex_spinunlock(&griodp->lock, s) + +#define GRIO_STREAM_LOCK(griosp) mutex_spinlock(&griosp->lock) +#define GRIO_STREAM_UNLOCK(griosp,s) mutex_spinunlock(&griosp->lock, s) + +#define GRIO_STREAM_DISK_LOCK(griosdp) mutex_spinlock(&griosdp->lock) +#define GRIO_STREAM_DISK_UNLOCK(griosdp,s) mutex_spinunlock(&griosdp->lock,s) + + +/* Function to convert the device number to an pointer to + * structure containing grio_info + */ +grio_disk_info_t *grio_disk_info(dev_t gdev); + +/* + * Macros to set or clear the bits in the b_flags field of the buf structure. + */ +#define BUF_IS_GRIO( bp ) (XFS_BUF_BFLAGS(bp) & B_GR_BUF) +#define BUF_IS_GRIO_ISSUED( bp ) (XFS_BUF_BFLAGS(bp) & B_GR_ISD) +#define CLR_BUF_GRIO_ISSUED(bp) (XFS_BUF_BFLAGS(bp) &= ~B_GR_ISD) +#define MARK_BUF_GRIO_ISSUED(bp) (XFS_BUF_BFLAGS(bp) |= B_GR_ISD) + + +#ifdef DEBUG +#define dbg1printf(_x) if (grio_dbg_level > 1 ) { printf _x ; } +#define dbg2printf(_x) if (grio_dbg_level > 2 ) { printf _x ; } +#define dbg3printf(_x) if (grio_dbg_level > 3 ) { printf _x ; } +#else +#define dbg1printf(_x) +#define dbg2printf(_x) +#define dbg3printf(_x) +#endif + +#endif /* __KERNEL__ */ + + +#define GRIO_MONITOR_COUNT 100 + +typedef struct grio_monitor_times { + time_t starttime; + time_t endtime; + __int64_t size; +} grio_monitor_times_t; + +typedef struct grio_monitor { + grio_monitor_times_t times[GRIO_MONITOR_COUNT]; + int start_index; + int end_index; + stream_id_t stream_id; + int monitoring; +} grio_monitor_t; + + +/* + * syssgi GRIO_GET_HWGRAPH_PATH returns an array of these structures. + * The class and type are akin to inventory records. For hardware + * components which do not have actual inventory records associated + * with the hwgfs vertices, grio determines the class, type and state + * fields. This structure can be extended to return unit/controller etc. + */ + +typedef struct grio_dev_info { + int grio_dev_class; + int grio_dev_type; + int grio_dev_state; + dev_t devnum; +} grio_dev_info_t; + +typedef struct grio_ioctl_info { + vertex_hdl_t prev_vhdl; + vertex_hdl_t next_vhdl; + unsigned long long reqbw; +} grio_ioctl_info_t; + +#endif /* _LINUX_GRIO_H_ */ diff -rNu linux-2.4.7/linux/include/linux/isdn/CVS/Entries linux-2.4-xfs/linux/include/linux/isdn/CVS/Entries --- linux-2.4.7/linux/include/linux/isdn/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/isdn/CVS/Entries Thu Jul 5 12:06:45 2001 @@ -0,0 +1,2 @@ +/tpam.h/1.1/Tue Jul 3 02:33:57 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/linux/isdn/CVS/Repository linux-2.4-xfs/linux/include/linux/isdn/CVS/Repository --- linux-2.4.7/linux/include/linux/isdn/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/isdn/CVS/Repository Thu Jul 5 12:06:45 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/linux/isdn diff -rNu linux-2.4.7/linux/include/linux/isdn/CVS/Root linux-2.4-xfs/linux/include/linux/isdn/CVS/Root --- linux-2.4.7/linux/include/linux/isdn/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/isdn/CVS/Root Thu Jul 5 12:06:45 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/linux/kallsyms.h linux-2.4-xfs/linux/include/linux/kallsyms.h --- linux-2.4.7/linux/include/linux/kallsyms.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/kallsyms.h Mon Apr 2 12:13:32 2001 @@ -0,0 +1,141 @@ +/* kallsyms headers + Copyright 2000 Keith Owens + + This file is part of the Linux modutils. It is exported to kernel + space so debuggers can access the kallsyms data. + + The kallsyms data contains all the non-stack symbols from a kernel + or a module. The kernel symbols are held between __start___kallsyms + and __stop___kallsyms. The symbols for a module are accessed via + the struct module chain which is based at module_list. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ident "$Id$" + +#ifndef MODUTILS_KALLSYMS_H +#define MODUTILS_KALLSYMS_H 1 + +/* Have to (re)define these ElfW entries here because external kallsyms + * code does not have access to modutils/include/obj.h. This code is + * included from user spaces tools (modutils) and kernel, they need + * different includes. + */ + +#ifndef ELFCLASS32 +#ifdef __KERNEL__ +#include +#else /* __KERNEL__ */ +#include +#endif /* __KERNEL__ */ +#endif /* ELFCLASS32 */ + +#ifndef ELFCLASSM +#define ELFCLASSM ELF_CLASS +#endif + +#ifndef ElfW +# if ELFCLASSM == ELFCLASS32 +# define ElfW(x) Elf32_ ## x +# define ELFW(x) ELF32_ ## x +# else +# define ElfW(x) Elf64_ ## x +# define ELFW(x) ELF64_ ## x +# endif +#endif + +/* Format of data in the kallsyms section. + * Most of the fields are small numbers but the total size and all + * offsets can be large so use the 32/64 bit types for these fields. + * + * Do not use sizeof() on these structures, modutils may be using extra + * fields. Instead use the size fields in the header to access the + * other bits of data. + */ + +struct kallsyms_header { + int size; /* Size of this header */ + ElfW(Word) total_size; /* Total size of kallsyms data */ + int sections; /* Number of section entries */ + ElfW(Off) section_off; /* Offset to first section entry */ + int section_size; /* Size of one section entry */ + int symbols; /* Number of symbol entries */ + ElfW(Off) symbol_off; /* Offset to first symbol entry */ + int symbol_size; /* Size of one symbol entry */ + ElfW(Off) string_off; /* Offset to first string */ + ElfW(Addr) start; /* Start address of first section */ + ElfW(Addr) end; /* End address of last section */ +}; + +struct kallsyms_section { + ElfW(Addr) start; /* Start address of section */ + ElfW(Word) size; /* Size of this section */ + ElfW(Off) name_off; /* Offset to section name */ + ElfW(Word) flags; /* Flags from section */ +}; + +struct kallsyms_symbol { + ElfW(Off) section_off; /* Offset to section that owns this symbol */ + ElfW(Addr) symbol_addr; /* Address of symbol */ + ElfW(Off) name_off; /* Offset to symbol name */ +}; + +#define KALLSYMS_SEC_NAME "__kallsyms" +#define KALLSYMS_IDX 2 /* obj_kallsyms creates kallsyms as section 2 */ + +#define kallsyms_next_sec(h,s) \ + ((s) = (struct kallsyms_section *)((char *)(s) + (h)->section_size)) +#define kallsyms_next_sym(h,s) \ + ((s) = (struct kallsyms_symbol *)((char *)(s) + (h)->symbol_size)) + +int kallsyms_symbol_to_address( + const char *name, /* Name to lookup */ + unsigned long *token, /* Which module to start with */ + const char **mod_name, /* Set to module name or "kernel" */ + unsigned long *mod_start, /* Set to start address of module */ + unsigned long *mod_end, /* Set to end address of module */ + const char **sec_name, /* Set to section name */ + unsigned long *sec_start, /* Set to start address of section */ + unsigned long *sec_end, /* Set to end address of section */ + const char **sym_name, /* Set to full symbol name */ + unsigned long *sym_start, /* Set to start address of symbol */ + unsigned long *sym_end /* Set to end address of symbol */ + ); + +int kallsyms_address_to_symbol( + unsigned long address, /* Address to lookup */ + const char **mod_name, /* Set to module name */ + unsigned long *mod_start, /* Set to start address of module */ + unsigned long *mod_end, /* Set to end address of module */ + const char **sec_name, /* Set to section name */ + unsigned long *sec_start, /* Set to start address of section */ + unsigned long *sec_end, /* Set to end address of section */ + const char **sym_name, /* Set to full symbol name */ + unsigned long *sym_start, /* Set to start address of symbol */ + unsigned long *sym_end /* Set to end address of symbol */ + ); + +int kallsyms_sections(void *token, + int (*callback)(void *, /* token */ + const char *, /* module name */ + const char *, /* section name */ + ElfW(Addr), /* Section start */ + ElfW(Addr), /* Section end */ + ElfW(Word) /* Section flags */ + ) + ); + +#endif /* kallsyms.h */ diff -rNu linux-2.4.7/linux/include/linux/kdb.h linux-2.4-xfs/linux/include/linux/kdb.h --- linux-2.4.7/linux/include/linux/kdb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/kdb.h Mon Apr 2 12:13:32 2001 @@ -0,0 +1,229 @@ +/* + * Minimalist Kernel Debugger + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * Copyright (C) 2000 Stephane Eranian + * + * See the file LIA-COPYRIGHT for additional information. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Richard Bass 1999/07/20 + * Many bug fixes and enhancements. + * Scott Foehner + * Port to ia64 + * Scott Lurndal 1999/12/12 + * v1.0 restructuring. + * Keith Owens 2000/05/23 + * KDB v1.2 + * Stephane Eranian 2000/06/05 + * move to v1.2 + * Keith Owens 2000/09/16 + * KDB v1.4 + * kdb=on/off/early at boot, /proc/sys/kernel/kdb. + * Env BTAPROMPT. + */ + + +#if !defined(__KDB_H) +#define __KDB_H + +#include +#include + +#define KDB_MAJOR_VERSION 1 +#define KDB_MINOR_VERSION 8 +#define KDB_TEST_VERSION "" + + /* + * kdb_initial_cpu is initialized to -1, and is set to the cpu + * number whenever the kernel debugger is entered. + */ +extern volatile int kdb_initial_cpu; +#ifdef CONFIG_KDB +#define KDB_IS_RUNNING() (kdb_initial_cpu != -1) +#else +#define KDB_IS_RUNNING() (0) +#endif /* CONFIG_KDB */ + + /* + * kdb_on + * + * Defines whether kdb is on or not. Default value + * is set by CONFIG_KDB_OFF. Boot with kdb=on/off + * or echo "[01]" > /proc/sys/kernel/kdb to change it. + */ +extern int kdb_on; + + /* + * kdb_port is initialized to zero, and is set to the I/O port + * address of the serial port when the console is setup in + * serial_console_setup. + */ +extern int kdb_port; + + /* + * KDB_FLAG_EARLYKDB is set when the 'kdb' option is specified + * as a boot parameter (e.g. via lilo). It indicates that the + * kernel debugger should be entered as soon as practical. + */ +#define KDB_FLAG_EARLYKDB 0x00000001 + + /* + * Internal debug flags + */ +#define KDB_DEBUG_FLAG_BT 0x0001 /* Stack traceback debug */ +#define KDB_DEBUG_FLAG_BP 0x0002 /* Breakpoint subsystem debug */ +#define KDB_DEBUG_FLAG_LBR 0x0004 /* Print last branch register */ +#define KDB_DEBUG_FLAG_AR 0x0008 /* Activation record, generic */ +#define KDB_DEBUG_FLAG_ARA 0x0010 /* Activation record, arch specific */ +#define KDB_DEBUG_FLAG_CALLBACK 0x0020 /* Event callbacks to kdb */ +#define KDB_DEBUG_FLAG_STATE 0x0040 /* State flags */ +#define KDB_DEBUG_FLAG_MASK 0xffff /* All debug flags */ +#define KDB_DEBUG_FLAG_SHIFT 16 /* Shift factor for dbflags */ + +extern volatile int kdb_flags; /* Global flags, see kdb_state for per cpu state */ + +#define KDB_FLAG(flag) (kdb_flags & KDB_FLAG_##flag) +#define KDB_FLAG_SET(flag) ((void)(kdb_flags |= KDB_FLAG_##flag)) +#define KDB_FLAG_CLEAR(flag) ((void)(kdb_flags &= ~KDB_FLAG_##flag)) +#define KDB_DEBUG(flag) (kdb_flags & (KDB_DEBUG_FLAG_##flag << KDB_DEBUG_FLAG_SHIFT)) +#define KDB_DEBUG_STATE(text,value) if (KDB_DEBUG(STATE)) kdb_print_state(text, value) + + /* + * Per cpu kdb state. A cpu can be under kdb control but outside kdb, + * for example when doing single step. + */ +volatile extern int kdb_state[ /*NR_CPUS*/ ]; +#define KDB_STATE_KDB 0x00000001 /* Cpu is inside kdb */ +#define KDB_STATE_LEAVING 0x00000002 /* Cpu is leaving kdb */ +#define KDB_STATE_CMD 0x00000004 /* Running a kdb command */ +#define KDB_STATE_KDB_CONTROL 0x00000008 /* This cpu is under kdb control */ +#define KDB_STATE_HOLD_CPU 0x00000010 /* Hold this cpu inside kdb */ +#define KDB_STATE_DOING_SS 0x00000020 /* Doing ss command */ +#define KDB_STATE_DOING_SSB 0x00000040 /* Doing ssb command, DOING_SS is also set */ +#define KDB_STATE_SSBPT 0x00000080 /* Install breakpoint after one ss, independent of DOING_SS */ +#define KDB_STATE_REENTRY 0x00000100 /* Valid re-entry into kdb */ +#define KDB_STATE_SUPPRESS 0x00000200 /* Suppress error messages */ +#define KDB_STATE_LONGJMP 0x00000400 /* longjmp() data is available */ +#define KDB_STATE_NO_WATCHDOG 0x00000800 /* Ignore watchdog */ +#define KDB_STATE_PRINTF_LOCK 0x00001000 /* Holds kdb_printf lock */ +#define KDB_STATE_WAIT_IPI 0x00002000 /* Waiting for kdb_ipi() NMI */ +#define KDB_STATE_RECURSE 0x00004000 /* Recursive entry to kdb */ +#define KDB_STATE_IP_ADJUSTED 0x00008000 /* Restart IP has been adjusted */ +#define KDB_STATE_NO_BP_DELAY 0x00010000 /* No need to delay breakpoints */ +#define KDB_STATE_ARCH 0xff000000 /* Reserved for arch specific use */ + +#define KDB_STATE_CPU(flag,cpu) (kdb_state[cpu] & KDB_STATE_##flag) +#define KDB_STATE_SET_CPU(flag,cpu) ((void)(kdb_state[cpu] |= KDB_STATE_##flag)) +#define KDB_STATE_CLEAR_CPU(flag,cpu) ((void)(kdb_state[cpu] &= ~KDB_STATE_##flag)) + +#define KDB_STATE(flag) KDB_STATE_CPU(flag,smp_processor_id()) +#define KDB_STATE_SET(flag) KDB_STATE_SET_CPU(flag,smp_processor_id()) +#define KDB_STATE_CLEAR(flag) KDB_STATE_CLEAR_CPU(flag,smp_processor_id()) + + /* + * External entry point for the kernel debugger. The pt_regs + * at the time of entry are supplied along with the reason for + * entry to the kernel debugger. + */ + +typedef enum { + KDB_REASON_CALL = 1, /* Call kdb() directly - regs invalid */ + KDB_REASON_FAULT, /* Kernel fault - regs valid */ + KDB_REASON_BREAK, /* Breakpoint inst. - regs valid */ + KDB_REASON_DEBUG, /* Debug Fault - regs valid */ + KDB_REASON_OOPS, /* Kernel Oops - regs valid */ + KDB_REASON_SWITCH, /* CPU switch - regs valid*/ + KDB_REASON_ENTER, /* KDB_ENTER() trap/fault - regs valid */ + KDB_REASON_KEYBOARD, /* Keyboard entry - regs valid */ + KDB_REASON_NMI, /* Non-maskable interrupt; regs valid */ + KDB_REASON_WATCHDOG, /* Watchdog interrupt; regs valid */ + KDB_REASON_RECURSE, /* Recursive entry to kdb; regs probably valid */ + KDB_REASON_SILENT, /* Silent entry/exit to kdb; regs invalid */ + KDB_REASON_PANIC, /* From panic() routine; regs invalid */ +} kdb_reason_t; + + +#ifdef CONFIG_KDB +extern int kdb(kdb_reason_t, int, kdb_eframe_t); +#else +#define kdb(reason,error_code,frame) (0) +#endif + +typedef int (*kdb_func_t)(int, const char **, const char **, kdb_eframe_t); + + /* + * Symbol table format returned by kallsyms. + */ + +typedef struct __ksymtab { + unsigned long value; /* Address of symbol */ + const char *mod_name; /* Module containing symbol or "kernel" */ + unsigned long mod_start; + unsigned long mod_end; + const char *sec_name; /* Section containing symbol */ + unsigned long sec_start; + unsigned long sec_end; + const char *sym_name; /* Full symbol name, including any version */ + unsigned long sym_start; + unsigned long sym_end; + } kdb_symtab_t; + + /* + * Exported Symbols for kernel loadable modules to use. + */ +extern int kdb_register(char *, kdb_func_t, char *, char *, short); +extern int kdb_unregister(char *); + +extern unsigned long kdba_getword(unsigned long, size_t); +extern unsigned long kdba_putword(unsigned long, size_t, unsigned long); + +extern int kdbgetularg(const char *, unsigned long *); +extern char *kdbgetenv(const char *); +extern int kdbgetintenv(const char *, int *); +extern int kdbgetaddrarg(int, const char**, int*, unsigned long *, + long *, char **, kdb_eframe_t); +extern int kdbgetsymval(const char *, kdb_symtab_t *); +extern int kdbnearsym(unsigned long, kdb_symtab_t *); +extern void kdb_printf(const char *,...) + __attribute__ ((format (printf, 1, 2))); +extern void kdb_init(void); +extern void kdb_symbol_print(kdb_machreg_t, const kdb_symtab_t *, unsigned int); +extern char *kdb_read(char *buffer, size_t bufsize); +extern char *kdb_strdup(const char *str, int type); + +#if defined(CONFIG_SMP) + /* + * Kernel debugger non-maskable IPI handler. + */ +extern int kdb_ipi(kdb_eframe_t, void (*ack_interrupt)(void)); +extern void smp_kdb_stop(void); +#else /* CONFIG_SMP */ +#define smp_kdb_stop() +#endif /* CONFIG_SMP */ + + /* + * Interface from general kernel to enable any hardware + * error reporting mechanisms. Such as the Intel Machine + * Check Architecture, for example. + */ +extern void kdb_enablehwfault(void); + + /* + * Determine if a kernel address is valid or not. + */ + +extern int kdb_vmlist_check(unsigned long, unsigned long); + + /* + * Routine for debugging the debugger state. + */ + +extern void kdb_print_state(const char *, int); + +#endif /* __KDB_H */ diff -rNu linux-2.4.7/linux/include/linux/kdbprivate.h linux-2.4-xfs/linux/include/linux/kdbprivate.h --- linux-2.4.7/linux/include/linux/kdbprivate.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/kdbprivate.h Mon Jun 18 12:43:14 2001 @@ -0,0 +1,318 @@ +/* + * Minimalist Kernel Debugger + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * + * See the file LIA-COPYRIGHT for additional information. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Richard Bass 1999/07/20 + * Many bug fixes and enhancements. + * Scott Foehner + * Port to ia64 + * Scott Lurndal 1999/12/12 + * v1.0 restructuring. + * Keith Owens 2000/05/23 + * KDB v1.2 + */ +#if !defined(_KDBPRIVATE_H) +#define _KDBPRIVATE_H + +#include +#include + +#include + +/* + * Kernel Debugger Error codes. Must not overlap with command codes. + */ + +#define KDB_NOTFOUND -1 +#define KDB_ARGCOUNT -2 +#define KDB_BADWIDTH -3 +#define KDB_BADRADIX -4 +#define KDB_NOTENV -5 +#define KDB_NOENVVALUE -6 +#define KDB_NOTIMP -7 +#define KDB_ENVFULL -8 +#define KDB_ENVBUFFULL -9 +#define KDB_TOOMANYBPT -10 +#define KDB_TOOMANYDBREGS -11 +#define KDB_DUPBPT -12 +#define KDB_BPTNOTFOUND -13 +#define KDB_BADMODE -14 +#define KDB_BADINT -15 +#define KDB_INVADDRFMT -16 +#define KDB_BADREG -17 +#define KDB_BADCPUNUM -18 +#define KDB_BADLENGTH -19 +#define KDB_NOBP -20 + +/* + * Kernel Debugger Command codes. Must not overlap with error codes. + */ +#define KDB_CMD_GO -1001 +#define KDB_CMD_CPU -1002 +#define KDB_CMD_SS -1003 +#define KDB_CMD_SSB -1004 + + /* + * kdb_nextline + * + * Contains the current line number on the screen. Used + * to handle the built-in pager (LINES env variable) + */ +extern volatile int kdb_nextline; + + /* + * kdb_diemsg + * + * Contains a pointer to the last string supplied to the + * kernel 'die' panic function. + */ +extern char *kdb_diemsg; + + /* + * Breakpoint state + * + * Each active and inactive breakpoint is represented by + * an instance of the following data structure. + */ + +typedef struct _kdb_bp { + bfd_vma bp_addr; /* Address breakpoint is present at */ + kdb_machinst_t bp_inst; /* Replaced instruction */ + + unsigned int bp_free:1; /* This entry is available */ + + unsigned int bp_enabled:1; /* Breakpoint is active in register */ + unsigned int bp_global:1; /* Global to all processors */ + + unsigned int bp_hardtype:1; /* Uses hardware register */ + unsigned int bp_forcehw:1; /* Force hardware register */ + unsigned int bp_instvalid:1; /* 0=bp_inst invalid, 1=bp_inst valid */ + unsigned int bp_installed:1; /* Breakpoint is installed */ + unsigned int bp_delay:1; /* Do delayed bp handling */ + unsigned int bp_delayed:1; /* Delayed breakpoint */ + + int bp_cpu; /* Cpu # (if bp_global == 0) */ + kdbhard_bp_t bp_template; /* Hardware breakpoint template */ + kdbhard_bp_t *bp_hard; /* Hardware breakpoint structure */ + int bp_adjust; /* Adjustment to PC for real instruction */ +} kdb_bp_t; + + /* + * Breakpoint handling subsystem global variables + */ +extern kdb_bp_t kdb_breakpoints[/* KDB_MAXBPT */]; + + /* + * Breakpoint architecture dependent functions. Must be provided + * in some form for all architectures. + */ +extern void kdba_initbp(void); +extern void kdba_printbp(kdb_bp_t *); +extern void kdba_printbpreg(kdbhard_bp_t *); +extern kdbhard_bp_t *kdba_allocbp(kdbhard_bp_t *, int *); +extern void kdba_freebp(kdbhard_bp_t *); +extern int kdba_parsebp(int, const char**, int *, kdb_bp_t*); +extern char *kdba_bptype(kdbhard_bp_t *); +extern void kdba_setsinglestep(kdb_eframe_t); +extern void kdba_clearsinglestep(kdb_eframe_t); + + /* + * Adjust instruction pointer architecture dependent function. Must be + * provided in some form for all architectures. + */ +extern void kdba_adjust_ip(kdb_reason_t, int, kdb_eframe_t); + + /* + * KDB-only global function prototypes. + */ +extern void kdb_id1(unsigned long); +extern void kdb_id_init(void); + + /* + * Architecture dependent function to enable any + * processor machine check exception handling modes. + */ +extern void kdba_enable_mce(void); + +extern void kdba_enable_lbr(void); +extern void kdba_disable_lbr(void); +extern void kdba_print_lbr(void); + + /* + * Initialization functions. + */ +extern void kdba_init(void); +extern void kdb_io_init(void); + + /* + * Architecture specific function to read a string. + */ +extern char * kdba_read(char *, size_t); + + /* + * Data for a single activation record on stack. + */ + +typedef struct __kdb_activation_record { + kdb_machreg_t start; /* -> start of activation record */ + kdb_machreg_t end; /* -> end+1 of activation record */ + kdb_machreg_t ret; /* Return address to caller */ + kdb_machreg_t oldfp; /* Frame pointer for caller's frame */ + kdb_machreg_t fp; /* Frame pointer for callee's frame */ + kdb_machreg_t arg0; /* -> First argument on stack (in previous ar) */ + int locals; /* Bytes allocated for local variables */ + int regs; /* Bytes allocated for saved registers */ + int args; /* Bytes allocated for arguments (in previous ar) */ + int setup; /* Bytes allocated for setup data */ +} kdb_ar_t; + + /* + * General Stack Traceback functions. + */ + +extern int kdb_get_next_ar(kdb_machreg_t, kdb_machreg_t, + kdb_machreg_t, kdb_machreg_t, + kdb_machreg_t, + kdb_ar_t *, kdb_symtab_t *); + + /* + * Architecture specific Stack Traceback functions. + */ + +struct task_struct; + +extern int kdba_bt_stack(struct pt_regs *, kdb_machreg_t *, + int, struct task_struct *); +extern int kdba_bt_process(struct task_struct *, int); +extern int kdba_prologue(const kdb_symtab_t *, kdb_machreg_t, + kdb_machreg_t, kdb_machreg_t, kdb_machreg_t, + int, kdb_ar_t *); + /* + * KDB Command Table + */ + +typedef struct _kdbtab { + char *cmd_name; /* Command name */ + kdb_func_t cmd_func; /* Function to execute command */ + char *cmd_usage; /* Usage String for this command */ + char *cmd_help; /* Help message for this command */ + short cmd_flags; /* Parsing flags */ + short cmd_minlen; /* Minimum legal # command chars required */ +} kdbtab_t; + + /* + * External command function declarations + */ + +extern int kdb_id(int, const char **, const char **, kdb_eframe_t); +extern int kdb_bp(int, const char **, const char **, kdb_eframe_t); +extern int kdb_bc(int, const char **, const char **, kdb_eframe_t); +extern int kdb_bt(int, const char **, const char **, kdb_eframe_t); +extern int kdb_ss(int, const char **, const char **, kdb_eframe_t); + + /* + * External utility function declarations + */ +extern char* kdb_getstr(char *, size_t, char *); + + /* + * Register contents manipulation + */ +extern int kdba_getregcontents(const char *, kdb_eframe_t, kdb_machreg_t *); +extern int kdba_setregcontents(const char *, kdb_eframe_t, kdb_machreg_t); +extern int kdba_dumpregs(struct pt_regs *, const char *, const char *); +extern int kdba_setpc(kdb_eframe_t, kdb_machreg_t); +extern kdb_machreg_t kdba_getpc(kdb_eframe_t); + + /* + * Debug register handling. + */ +extern void kdba_installdbreg(kdb_bp_t*); +extern void kdba_removedbreg(kdb_bp_t*); + + /* + * Breakpoint handling - External interfaces + */ +extern void kdb_initbptab(void); +extern void kdb_bp_install_global(kdb_eframe_t); +extern void kdb_bp_install_local(kdb_eframe_t); +extern void kdb_bp_remove_global(void); +extern void kdb_bp_remove_local(void); + + /* + * Breakpoint handling - Internal to kdb_bp.c/kdba_bp.c + */ +extern void kdba_installbp(kdb_eframe_t ef, kdb_bp_t *); +extern void kdba_removebp(kdb_bp_t *); + + +typedef enum { + KDB_DB_BPT, /* Breakpoint */ + KDB_DB_SS, /* Single-step trap */ + KDB_DB_SSB, /* Single step to branch */ + KDB_DB_SSBPT, /* Single step over breakpoint */ + KDB_DB_NOBPT /* Spurious breakpoint */ +} kdb_dbtrap_t; + +extern kdb_dbtrap_t kdba_db_trap(kdb_eframe_t, int); /* DEBUG trap/fault handler */ +extern kdb_dbtrap_t kdba_bp_trap(kdb_eframe_t, int); /* Breakpoint trap/fault hdlr */ + + /* + * Interrupt Handling + */ +typedef int kdb_intstate_t; + +extern void kdba_disableint(kdb_intstate_t *); +extern void kdba_restoreint(kdb_intstate_t *); + + /* + * SMP and process stack manipulation routines. + */ +extern int kdba_ipi(kdb_eframe_t, void (*)(void)); +extern int kdba_main_loop(kdb_reason_t, kdb_reason_t, int, kdb_dbtrap_t, kdb_eframe_t); +extern int kdb_main_loop(kdb_reason_t, kdb_reason_t, int, kdb_dbtrap_t, kdb_eframe_t); + + /* + * General Disassembler interfaces + */ +extern int kdb_dis_fprintf_dummy(PTR, const char *, ...) __attribute__ ((format (printf, 2, 3))); +extern disassemble_info kdb_di; + + /* + * Architecture Dependent Disassembler interfaces + */ +extern void kdba_printaddress(kdb_machreg_t, disassemble_info *, int); +extern int kdba_id_printinsn(kdb_machreg_t, disassemble_info *); +extern int kdba_id_parsemode(const char *, disassemble_info*); +extern void kdba_id_init(disassemble_info *); +extern void kdba_check_pc(kdb_machreg_t *); + + /* + * Miscellaneous functions and data areas + */ +extern int kdb_getcurrentframe(kdb_eframe_t); +extern void kdb_resetkeyboard(void); +extern char *kdb_cmds[]; + + /* + * Defines for kdb_symbol_print. + */ +#define KDB_SP_SPACEB 0x0001 /* Space before string */ +#define KDB_SP_SPACEA 0x0002 /* Space after string */ +#define KDB_SP_PAREN 0x0004 /* Parenthesis around string */ +#define KDB_SP_VALUE 0x0008 /* Print the value of the address */ +#define KDB_SP_SYMSIZE 0x0010 /* Print the size of the symbol */ +#define KDB_SP_NEWLINE 0x0020 /* Newline after string */ +#define KDB_SP_DEFAULT (KDB_SP_VALUE|KDB_SP_PAREN) + +#endif /* !_KDBPRIVATE_H */ + diff -rNu linux-2.4.7/linux/include/linux/lockd/CVS/Entries linux-2.4-xfs/linux/include/linux/lockd/CVS/Entries --- linux-2.4.7/linux/include/linux/lockd/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/lockd/CVS/Entries Thu Jul 5 12:06:45 2001 @@ -0,0 +1,9 @@ +/bind.h/1.3/Sat Mar 11 02:39:30 2000/-ko/ +/debug.h/1.3/Wed Feb 23 18:55:15 2000/-ko/ +/lockd.h/1.5/Fri Apr 21 16:16:46 2000/-ko/ +/nlm.h/1.4/Fri Apr 21 16:16:46 2000/-ko/ +/share.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sm_inter.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/xdr.h/1.3/Sat Mar 11 02:39:30 2000/-ko/ +/xdr4.h/1.2/Sat Mar 11 02:39:30 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/linux/lockd/CVS/Repository linux-2.4-xfs/linux/include/linux/lockd/CVS/Repository --- linux-2.4.7/linux/include/linux/lockd/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/lockd/CVS/Repository Thu Jul 5 12:06:45 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/linux/lockd diff -rNu linux-2.4.7/linux/include/linux/lockd/CVS/Root linux-2.4-xfs/linux/include/linux/lockd/CVS/Root --- linux-2.4.7/linux/include/linux/lockd/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/lockd/CVS/Root Thu Jul 5 12:06:45 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/linux/lvm.h linux-2.4-xfs/linux/include/linux/lvm.h --- linux-2.4.7/linux/include/linux/lvm.h Fri Feb 16 18:06:17 2001 +++ linux-2.4-xfs/linux/include/linux/lvm.h Tue Mar 20 14:10:08 2001 @@ -3,28 +3,28 @@ * kernel/lvm.h * tools/lib/lvm.h * - * Copyright (C) 1997 - 2000 Heinz Mauelshagen, Sistina Software + * Copyright (C) 1997 - 2001 Heinz Mauelshagen, Sistina Software * * February-November 1997 * May-July 1998 * January-March,July,September,October,Dezember 1999 * January,February,July,November 2000 - * January 2001 + * January-March 2001 * * lvm is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. - * + * * lvm is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Boston, MA 02111-1307, USA. * */ @@ -52,7 +52,7 @@ * 08/12/1999 - changed LVM_LV_SIZE_MAX macro to reflect current 1TB limit * 01/01/2000 - extended lv_v2 core structure by wait_queue member * 12/02/2000 - integrated Andrea Arcagnelli's snapshot work - * 18/02/2000 - seperated user and kernel space parts by + * 18/02/2000 - seperated user and kernel space parts by * #ifdef them with __KERNEL__ * 08/03/2000 - implemented cluster/shared bits for vg_access * 26/06/2000 - implemented snapshot persistency and resizing support @@ -60,6 +60,13 @@ * 12/11/2000 - removed unneeded timestamp definitions * 24/12/2000 - removed LVM_TO_{CORE,DISK}*, use cpu_{from, to}_le* * instead - Christoph Hellwig + * 22/01/2001 - Change ulong to uint32_t + * 14/02/2001 - changed LVM_SNAPSHOT_MIN_CHUNK to 1 page + * 20/02/2001 - incremented IOP version to 11 because of incompatible + * change in VG activation (in order to support devfs better) + * 01/03/2001 - Revert to IOP10 and add VG_CREATE_OLD call for compatibility + * 08/03/2001 - new lv_t (in core) version number 5: changed page member + * to (struct kiobuf *) to use for COW exception table io * */ @@ -67,9 +74,11 @@ #ifndef _LVM_H_INCLUDE #define _LVM_H_INCLUDE -#define _LVM_KERNEL_H_VERSION "LVM 0.9.1_beta2 (18/01/2001)" +#define LVM_RELEASE_NAME "0.9.1_beta6" +#define LVM_RELEASE_DATE "12/03/2001" + +#define _LVM_KERNEL_H_VERSION "LVM "LVM_RELEASE_NAME" ("LVM_RELEASE_DATE")" -#include #include /* @@ -90,13 +99,20 @@ #define DEBUG_READ #define DEBUG_GENDISK #define DEBUG_VG_CREATE - #define DEBUG_LVM_BLK_OPEN + #define DEBUG_DEVICE #define DEBUG_KFREE */ #endif /* #ifdef __KERNEL__ */ +#ifndef __KERNEL__ +#define __KERNEL__ +#include +#include +#undef __KERNEL__ +#else #include #include +#endif /* #ifndef __KERNEL__ */ #include #include @@ -117,10 +133,10 @@ #undef BLOCK_SIZE #endif -#ifdef CONFIG_ARCH_S390 +#ifdef CONFIG_ARCH_S390 #define BLOCK_SIZE 4096 #else -#define BLOCK_SIZE 1024 +#define BLOCK_SIZE 512 #endif #ifndef SECTOR_SIZE @@ -141,7 +157,7 @@ /* set the default structure version */ #if ( LVM_STRUCT_VERSION == 1) #define pv_t pv_v2_t -#define lv_t lv_v4_t +#define lv_t lv_v5_t #define vg_t vg_v3_t #define pv_disk_t pv_disk_v2_t #define lv_disk_t lv_disk_v3_t @@ -299,7 +315,7 @@ #define LVM_SNAPSHOT_MAX_CHUNK 1024 /* 1024 KB */ #define LVM_SNAPSHOT_DEF_CHUNK 64 /* 64 KB */ -#define LVM_SNAPSHOT_MIN_CHUNK 1 /* 1 KB */ +#define LVM_SNAPSHOT_MIN_CHUNK (PAGE_SIZE/1024) /* 4 or 8 KB */ #define UNDEF -1 #define FALSE 0 @@ -323,7 +339,7 @@ * ioctls */ /* volume group */ -#define VG_CREATE _IOW ( 0xfe, 0x00, 1) +#define VG_CREATE_OLD _IOW ( 0xfe, 0x00, 1) #define VG_REMOVE _IOW ( 0xfe, 0x01, 1) #define VG_EXTEND _IOW ( 0xfe, 0x03, 1) @@ -336,6 +352,8 @@ #define VG_SET_EXTENDABLE _IOW ( 0xfe, 0x08, 1) #define VG_RENAME _IOW ( 0xfe, 0x09, 1) +/* Since 0.9beta6 */ +#define VG_CREATE _IOW ( 0xfe, 0x0a, 1) /* logical volume */ #define LV_CREATE _IOW ( 0xfe, 0x20, 1) @@ -418,6 +436,9 @@ #define PV_ALLOCATABLE 0x02 /* pv_allocatable */ +/* misc */ +#define LVM_SNAPSHOT_DROPPED_SECTOR 1 + /* * Structure definitions core/disk follow * @@ -440,10 +461,10 @@ /* remap physical sector/rdev pairs including hash */ typedef struct { struct list_head hash; - ulong rsector_org; - kdev_t rdev_org; - ulong rsector_new; - kdev_t rdev_new; + uint32_t rsector_org; + kdev_t rdev_org; + uint32_t rsector_new; + kdev_t rdev_new; } lv_block_exception_v1_t; /* disk stored pe information */ @@ -571,21 +592,21 @@ /* core PE information */ typedef struct { kdev_t dev; - ulong pe; /* to be changed if > 2TB */ - ulong reads; - ulong writes; + uint32_t pe; /* to be changed if > 2TB */ + uint32_t reads; + uint32_t writes; } pe_t; typedef struct { char lv_name[NAME_LEN]; kdev_t old_dev; kdev_t new_dev; - ulong old_pe; - ulong new_pe; + uint32_t old_pe; + uint32_t new_pe; } le_remap_req_t; typedef struct lv_bmap { - ulong lv_block; + uint32_t lv_block; dev_t lv_dev; } lv_bmap_t; @@ -627,11 +648,11 @@ uint lv_snapshot_minor; #ifdef __KERNEL__ struct kiobuf *lv_iobuf; + struct kiobuf *lv_COW_table_iobuf; struct semaphore lv_snapshot_sem; struct list_head *lv_snapshot_hash_table; - ulong lv_snapshot_hash_table_size; - ulong lv_snapshot_hash_mask; - struct page *lv_COW_table_page; + uint32_t lv_snapshot_hash_table_size; + uint32_t lv_snapshot_hash_mask; wait_queue_head_t lv_snapshot_wait; int lv_snapshot_use_rate; void *vg; @@ -640,7 +661,7 @@ #else char dummy[200]; #endif -} lv_v4_t; +} lv_v5_t; /* disk */ typedef struct { @@ -791,7 +812,7 @@ struct { kdev_t lv_dev; kdev_t pv_dev; - ulong pv_offset; + uint32_t pv_offset; } data; } pe_lock_req_t; @@ -804,7 +825,7 @@ /* Request structure LV_STATUS_BYINDEX */ typedef struct { - ulong lv_index; + uint32_t lv_index; lv_t *lv; /* Transfer size because user space and kernel space differ */ ushort size; @@ -813,7 +834,7 @@ /* Request structure LV_STATUS_BYDEV... */ typedef struct { dev_t dev; - pv_t *lv; + lv_t *lv; } lv_status_bydev_req_t; diff -rNu linux-2.4.7/linux/include/linux/miscdevice.h linux-2.4-xfs/linux/include/linux/miscdevice.h --- linux-2.4.7/linux/include/linux/miscdevice.h Tue Jul 3 17:43:41 2001 +++ linux-2.4-xfs/linux/include/linux/miscdevice.h Wed May 2 01:22:13 2001 @@ -18,6 +18,7 @@ #define RTC_MINOR 135 #define EFI_RTC_MINOR 136 /* EFI Time services */ #define SUN_OPENPROM_MINOR 139 +#define DMAPI_MINOR 140 /* DMAPI */ #define NVRAM_MINOR 144 #define I2O_MINOR 166 #define MICROCODE_MINOR 184 diff -rNu linux-2.4.7/linux/include/linux/mm.h linux-2.4-xfs/linux/include/linux/mm.h --- linux-2.4.7/linux/include/linux/mm.h Tue Jul 3 17:42:55 2001 +++ linux-2.4-xfs/linux/include/linux/mm.h Mon Jul 2 10:59:04 2001 @@ -298,6 +298,7 @@ #define TryLockPage(page) test_and_set_bit(PG_locked, &(page)->flags) #define PageChecked(page) test_bit(PG_checked, &(page)->flags) #define SetPageChecked(page) set_bit(PG_checked, &(page)->flags) +#define DelallocPage(page) (page->buffers && test_bit(BH_Delay, &(page)->buffers->b_state)) extern void __set_page_dirty(struct page *); diff -rNu linux-2.4.7/linux/include/linux/mtd/CVS/Entries linux-2.4-xfs/linux/include/linux/mtd/CVS/Entries --- linux-2.4.7/linux/include/linux/mtd/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/mtd/CVS/Entries Thu Jul 5 12:06:46 2001 @@ -0,0 +1,17 @@ +/cfi.h/1.4/Wed Jun 13 03:24:09 2001/-ko/ +/cfi_endian.h/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/compatmac.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/doc2000.h/1.3/Wed Jun 13 03:24:09 2001/-ko/ +/flashchip.h/1.2/Wed Jun 13 03:24:09 2001/-ko/ +/ftl.h/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/iflash.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/jedec.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/map.h/1.6/Wed Jun 13 03:24:09 2001/-ko/ +/mtd.h/1.4/Wed Jun 13 03:24:09 2001/-ko/ +/nand.h/1.2/Sun Dec 17 19:15:00 2000/-ko/ +/nand_ecc.h/1.1/Wed Jun 13 03:24:09 2001/-ko/ +/nand_ids.h/1.1/Sun Dec 17 19:15:00 2000/-ko/ +/nftl.h/1.3/Wed Jun 13 03:24:09 2001/-ko/ +/partitions.h/1.2/Wed Jun 13 03:24:09 2001/-ko/ +/pmc551.h/1.2/Sun Dec 17 19:15:00 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/linux/mtd/CVS/Repository linux-2.4-xfs/linux/include/linux/mtd/CVS/Repository --- linux-2.4.7/linux/include/linux/mtd/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/mtd/CVS/Repository Thu Jul 5 12:06:45 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/linux/mtd diff -rNu linux-2.4.7/linux/include/linux/mtd/CVS/Root linux-2.4-xfs/linux/include/linux/mtd/CVS/Root --- linux-2.4.7/linux/include/linux/mtd/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/mtd/CVS/Root Thu Jul 5 12:06:45 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/linux/netfilter_ipv4/CVS/Entries linux-2.4-xfs/linux/include/linux/netfilter_ipv4/CVS/Entries --- linux-2.4.7/linux/include/linux/netfilter_ipv4/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/netfilter_ipv4/CVS/Entries Thu Jul 5 12:06:47 2001 @@ -0,0 +1,34 @@ +/compat_firewall.h/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ip_conntrack.h/1.7/Wed May 2 06:22:13 2001/-ko/ +/ip_conntrack_core.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/ip_conntrack_ftp.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/ip_conntrack_helper.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/ip_conntrack_icmp.h/1.1/Wed May 2 06:22:13 2001/-ko/ +/ip_conntrack_protocol.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/ip_conntrack_tcp.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/ip_conntrack_tuple.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/ip_nat.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/ip_nat_core.h/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/ip_nat_helper.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/ip_nat_protocol.h/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ip_nat_rule.h/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ip_queue.h/1.3/Thu Sep 28 22:42:39 2000/-ko/ +/ip_tables.h/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/ipchains_core.h/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ipfwadm_core.h/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ipt_LOG.h/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ipt_MARK.h/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ipt_REJECT.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/ipt_TCPMSS.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/ipt_TOS.h/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ipt_limit.h/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ipt_mac.h/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ipt_mark.h/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ipt_multiport.h/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ipt_owner.h/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ipt_state.h/1.2/Tue May 2 22:18:18 2000/-ko/ +/ipt_tcpmss.h/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/ipt_tos.h/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/listhelp.h/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/lockhelp.h/1.2/Fri Jan 5 18:42:30 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/linux/netfilter_ipv4/CVS/Repository linux-2.4-xfs/linux/include/linux/netfilter_ipv4/CVS/Repository --- linux-2.4.7/linux/include/linux/netfilter_ipv4/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/netfilter_ipv4/CVS/Repository Thu Jul 5 12:06:46 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/linux/netfilter_ipv4 diff -rNu linux-2.4.7/linux/include/linux/netfilter_ipv4/CVS/Root linux-2.4-xfs/linux/include/linux/netfilter_ipv4/CVS/Root --- linux-2.4.7/linux/include/linux/netfilter_ipv4/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/netfilter_ipv4/CVS/Root Thu Jul 5 12:06:46 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/linux/netfilter_ipv6/CVS/Entries linux-2.4-xfs/linux/include/linux/netfilter_ipv6/CVS/Entries --- linux-2.4.7/linux/include/linux/netfilter_ipv6/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/netfilter_ipv6/CVS/Entries Thu Jul 5 12:06:47 2001 @@ -0,0 +1,10 @@ +/ip6_tables.h/1.2/Mon Jul 31 16:16:28 2000/-ko/ +/ip6t_LOG.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/ip6t_MARK.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/ip6t_REJECT.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/ip6t_limit.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/ip6t_mac.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/ip6t_mark.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/ip6t_multiport.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/ip6t_owner.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/linux/netfilter_ipv6/CVS/Repository linux-2.4-xfs/linux/include/linux/netfilter_ipv6/CVS/Repository --- linux-2.4.7/linux/include/linux/netfilter_ipv6/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/netfilter_ipv6/CVS/Repository Thu Jul 5 12:06:47 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/linux/netfilter_ipv6 diff -rNu linux-2.4.7/linux/include/linux/netfilter_ipv6/CVS/Root linux-2.4-xfs/linux/include/linux/netfilter_ipv6/CVS/Root --- linux-2.4.7/linux/include/linux/netfilter_ipv6/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/netfilter_ipv6/CVS/Root Thu Jul 5 12:06:47 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/linux/nfsd/CVS/Entries linux-2.4-xfs/linux/include/linux/nfsd/CVS/Entries --- linux-2.4.7/linux/include/linux/nfsd/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/nfsd/CVS/Entries Thu Jul 5 12:06:47 2001 @@ -0,0 +1,13 @@ +/auth.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cache.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/const.h/1.4/Fri Apr 21 16:16:46 2000/-ko/ +/debug.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/export.h/1.9/Mon Oct 23 18:56:35 2000/-ko/ +/interface.h/1.1/Thu Sep 28 22:42:39 2000/-ko/ +/nfsd.h/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/nfsfh.h/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/stats.h/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/syscall.h/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/xdr.h/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/xdr3.h/1.5/Thu Sep 28 22:42:39 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/linux/nfsd/CVS/Repository linux-2.4-xfs/linux/include/linux/nfsd/CVS/Repository --- linux-2.4.7/linux/include/linux/nfsd/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/nfsd/CVS/Repository Thu Jul 5 12:06:47 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/linux/nfsd diff -rNu linux-2.4.7/linux/include/linux/nfsd/CVS/Root linux-2.4-xfs/linux/include/linux/nfsd/CVS/Root --- linux-2.4.7/linux/include/linux/nfsd/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/nfsd/CVS/Root Thu Jul 5 12:06:47 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/linux/page_buf.h linux-2.4-xfs/linux/include/linux/page_buf.h --- linux-2.4.7/linux/include/linux/page_buf.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/page_buf.h Mon Jul 2 21:29:39 2001 @@ -0,0 +1,704 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +/* + * Written by Steve Lord, Jim Mostek, Russell Cattelan at SGI + */ + +#ifndef _LINUX_PAGE_BUF_H +#define _LINUX_PAGE_BUF_H + +#include +/* Tracing only makes sense when you have kdb support - there is no + * other way to read the trace. +#ifdef CONFIG_KDB +#define PAGEBUF_TRACE 1 +#endif + + * Turn this on to get pagebuf lock owner ship +#define PAGEBUF_LOCK_TRACKING + +#define dprintk(x, y) { if (x) printk y; } + */ + +#define dprintk(x, y) + + +#include +#if defined(CONFIG_PAGE_BUF) || defined(CONFIG_PAGE_BUF_MODULE) + +#include +#include +#ifdef _PAGE_BUF_INTERNAL_ +#include +#include +#include +#include +#include +#include +#else /* _PAGE_BUF_INTERNAL_ */ +struct inode; +struct page; +struct file; +struct dentry; +struct iovec; +#endif /* _PAGE_BUF_INTERNAL_ */ + +/* + * Base types + */ + +/* daddr must be signed since -1 is used for bmaps that are not yet allocated */ +typedef loff_t page_buf_daddr_t; + +#define PAGE_BUF_DADDR_NULL ((page_buf_daddr_t) (-1LL)) + +typedef size_t page_buf_dsize_t; /* size of buffer in blocks */ + +#define page_buf_ctob(pp) ((pp) * PAGE_CACHE_SIZE) +#define page_buf_btoc(dd) (((dd) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) +#define page_buf_btoct(dd) ((dd) >> PAGE_CACHE_SHIFT) +#define page_buf_poff(aa) ((aa) & ~PAGE_CACHE_MASK) + +typedef enum page_buf_rw_e { + PBRW_READ = 1, /* transfer into target memory */ + PBRW_WRITE = 2, /* transfer from target memory */ + PBRW_ZERO = 3 /* Zero target memory */ +} page_buf_rw_t; + +/* + * page_buf_bmap_t: File system I/O map + * + * The pbm_bn, pbm_offset and pbm_length fields are expressed in disk blocks. + * The pbm_length field specifies the size of the underlying backing store + * for the particular mapping. + * + * The pbm_bsize, pbm_size and pbm_delta fields are expressed in bytes and indicate + * the size of the mapping, the number of bytes that are valid to access + * (read or write), and the offset into the mapping, given the offset + * supplied to the file I/O map routine. pbm_delta is the offset of the + * desired data from the beginning of the mapping. + * + * When a request is made to read beyond the logical end of the object, + * pbm_size may be set to 0, but pbm_offset and pbm_length should be set to reflect + * the actual amount of underlying storage that has been allocated, if any. + */ + +/* pbm_flags values */ +typedef enum { + PBMF_EOF = 0x01, /* mapping contains EOF */ + PBMF_HOLE = 0x02, /* mapping covers a hole */ + PBMF_DELAY = 0x04, /* mapping covers delalloc region */ + PBMF_UNWRITTEN = 0x20, /* mapping covers allocated */ + /* but uninitialized XFS data */ +} bmap_flags_t; + +typedef struct page_buf_bmap_s { + page_buf_daddr_t pbm_bn; /* block number in file system */ + kdev_t pbm_dev; /* device for I/O */ + loff_t pbm_offset; /* byte offset of mapping in file */ + size_t pbm_delta; /* offset of request into bmap */ + size_t pbm_bsize; /* size of this mapping in bytes */ + bmap_flags_t pbm_flags; /* options flags for mapping */ +} page_buf_bmap_t; + +typedef page_buf_bmap_t pb_bmap_t; + +/* + * page_buf_t: Buffer structure for page cache-based buffers + * + * This buffer structure is used by the page cache buffer management routines + * to refer to an assembly of pages forming a logical buffer. The actual + * I/O is performed with kiobuf or buffer_head structures, as required by + * drivers, for drivers which do not understand this structure. + * The buffer structure is used on temporary basis only, and + * discarded when released. + * + * The real data storage is recorded in the page cache. Metadata is + * hashed to inode for the block device on which the file system resides. + * File data is hashed to the inode for the file. Pages which are only + * partially filled with data have bits set in their block_map entry + * to indicate which disk blocks in the page are not valid. + * + * The real data storage is recorded in the page cache. Metadata is + * hashed to the inode for the block device on which the file system resides. + * File data is hashed to the inode for the file. Pages which are only + * partially filled with data have bits set in their block_map entry + * to indicate which disk blocks in the page are not valid. + * + * The list of pages is stored either in a kiovec, which is + * an array of pointers to one or more kiobuf structures. + * The intent is that the kiovec and the kiobuf structures + * to which it points will not be deallocated in the life of the + * page_buf_t, thereby simplifying updates. Individual pages + * in the kiobuf lists may be absent (page number set to + * PAGE_BUF_PGNO_NULL), and later supplied by storing the page + * number and, if applicable the mem_map_t * in the kiobuf. + */ + +typedef enum page_buf_flags_e { + PBF_READ = (1 << 0), /* buffer intended for reading from device */ + PBF_WRITE = (1 << 1), /* buffer intended for writing to device */ + PBF_MAPPED = (1 << 2), /* buffer mapped (pb_addr valid) */ + PBF_PARTIAL = (1 << 3), /* buffer partially read */ + PBF_ASYNC = (1 << 4), /* initiator will not wait for completion */ + PBF_NONE = (1 << 5), /* buffer not read at all */ + PBF_DELWRI = (1 << 6), /* buffer has dirty pages */ + PBF_FREED = (1 << 7), /* buffer has been freed and is invalid */ + PBF_SYNC = (1 << 8), /* force updates to disk */ + PBF_MAPPABLE = (1 << 9), /* use pages which can be directly addressed */ + + PBF_FS_RESERVED_1 = (1 << 10), /* reserved for client use NOTUSED*/ + PBF_FS_RESERVED_2 = (1 << 11), /* reserved for client use NOTUSED*/ + + PBF_RELEASE = (1 << 12), /* buffer to be released after I/O is done */ + + /* flags used only as arguments to access routines */ + PBF_LOCK = (1 << 13), /* lock requested */ + PBF_TRYLOCK = (1 << 14), /* lock requested, but do not wait */ + PBF_ALLOCATE = (1 << 15), /* allocate all pages NOTUSED*/ + PBF_FILE_ALLOCATE = (1 << 16), /* allocate all file space */ + PBF_DONT_BLOCK = (1 << 17), /* do not block in current thread */ + PBF_DIRECT = (1 << 18), /* direct I/O desired */ + PBF_ENTER_PAGES = (1 << 21), /* create invalid pages for all */ + /* pages in the range of the buffer */ + /* not already associated with buffer */ +#ifdef _PAGE_BUF_INTERNAL_ + /* flags used only internally */ + _PBF_LOCKABLE = (1 << 19), /* page_buf_t may be locked */ + _PBF_NEXT_KEY = (1 << 20), /* page_buf_t is a dummy used as a key */ + _PBF_ALL_PAGES_MAPPED = (1 << 22), + /* all pages in rage are mapped */ + _PBF_SOME_INVALID_PAGES = (1 << 23), + /* some mapped pages are not valid */ + _PBF_ADDR_ALLOCATED = (1 << 24), + /* pb_addr space was allocated */ + _PBF_MEM_ALLOCATED = (1 << 25), + /* pb_mem and underlying pages allocated */ +#endif /* _PAGE_BUF_INTERNAL_ */ + PBF_GRIO = (1 << 26), + PBF_FORCEIO = (1 << 27) + /* XFS internal XFS_B_STALE (1 << 31) */ + +} page_buf_flags_t; + +#define PBF_UPDATE (PBF_READ | PBF_WRITE) +#define PBF_NOT_DONE(pb) (((pb)->pb_flags & (PBF_PARTIAL|PBF_NONE)) != 0) +#define PBF_DONE(pb) (((pb)->pb_flags & (PBF_PARTIAL|PBF_NONE)) == 0) + +#ifdef _PAGE_BUF_INTERNAL_ +#define _PBF_INTERNAL (_PBF_LOCKABLE | \ + _PBF_NEXT_KEY | \ + _PBF_ENTER_PAGES | \ + _PBF_ALL_PAGES_MAPPED | \ + _PBF_SOME_INVALID_PAGES | \ + _PBF_ADDR_ALLOCATED | \ + _PBF_MEM_ALLOCATED) + +#include +#else +typedef void *avl_handle_t; +#endif /* _PAGE_BUF_INTERNAL_ */ + +typedef struct pb_target { + kdev_t pbr_device; + unsigned short pbr_sector; + unsigned short pbr_sector_bits; + struct address_space pbr_addrspace; + avl_handle_t pbr_buffers; + spinlock_t pbr_lock; +} pb_target_t; + +struct page_buf_s; + +typedef void (*page_buf_iodone_t)(struct page_buf_s *); + /* call-back function on I/O completion */ +typedef void (*page_buf_relse_t)(struct page_buf_s *); + /* call-back function on I/O completion */ +typedef int (*page_buf_bdstrat_t)(struct page_buf_s *); +typedef int (pagebuf_bmap_fn_t) (struct inode *, loff_t, ssize_t, + page_buf_bmap_t *, int, int *, int); + +#define PB_PAGES 4 + + +typedef struct page_buf_s { + struct list_head pb_list; + page_buf_flags_t pb_flags; /* status flags */ + struct pb_target *pb_target; /* logical object */ + unsigned int pb_hold; /* reference count */ + page_buf_daddr_t pb_bn; /* block number for I/O */ + kdev_t pb_dev; + unsigned char pb_sector_bits; /* bit version of size */ + loff_t pb_file_offset; /* offset in file */ + size_t pb_buffer_length; /* size of buffer in bytes */ + size_t pb_count_desired; /* desired transfer size */ + void *pb_addr; /* virtual address of buffer */ + page_buf_iodone_t pb_iodone; /* function to call when I/O done */ + page_buf_relse_t pb_relse; /* function to call when releasing */ + page_buf_bdstrat_t pb_strat; /* function to call before write */ + int pb_error; /* error code on I/O */ + void *pb_fspriv; + void *pb_fspriv2; + void *pb_fspriv3; + int pb_page_count; /* size of page array */ + int pb_locked; /* page array is locked */ + int pb_offset; /* page offset in first page */ + struct page **pb_pages; /* array of page pointers */ + struct page *pb_page_array[PB_PAGES]; /* static array of pages */ +} page_buf_t; + +#ifdef _PAGE_BUF_INTERNAL_ +typedef struct page_buf_private_s { + page_buf_t pb_common; /* public part of structure */ + spinlock_t pb_lock; + struct semaphore pb_sema; /* semaphore for lockables */ + unsigned long pb_flushtime; /* time to flush pagebuf */ + atomic_t pb_io_remaining; /* count of outstanding I/O requests */ + struct semaphore pb_iodonesema; /* Semaphore for I/O waiters */ + atomic_t pb_pin_count; /* pin count */ + wait_queue_head_t pb_waiters; /* unpin waiters */ +#ifdef PAGEBUF_LOCK_TRACKING + void *pb_last_holder; +#endif +} page_buf_private_t; + +#define PBC(pb) (&((pb)->pb_common)) +#define PBP(pb) ((page_buf_private_t *) (pb)) + +#define PB_SECTOR_SIZE(pb) ((pb)->pb_sector) +#define PB_SECTOR_BITS(pb) ((pb)->pb_sector_bits) +#define PB_ADDR_SPACE(pb) (&(pb)->pb_target->pbr_addrspace) + + +#ifdef PAGEBUF_LOCK_TRACKING +#define PB_SET_OWNER(pb) (PBP(pb)->pb_last_holder = current) +#define PB_CLEAR_OWNER(pb) (PBP(pb)->pb_last_holder = NULL) +#define PB_GET_OWNER(pb) (PBP(pb)->pb_last_holder) +#else +#define PB_SET_OWNER(pb) +#define PB_CLEAR_OWNER(pb) +#define PB_GET_OWNER(pb) +#endif + +/* Tracing utilities for pagebuf */ +typedef struct { + int event; + unsigned long pb; + page_buf_flags_t flags; + unsigned short hold; + unsigned short lock_value; + void *task; + void *misc; + void *ra; + loff_t offset; + size_t size; +} pagebuf_trace_t; + +struct pagebuf_trace_buf { + pagebuf_trace_t *buf; + volatile int start; + volatile int end; +}; + +#define PB_TRACE_BUFSIZE 1024 +#define CIRC_INC(i) (((i) + 1) & (PB_TRACE_BUFSIZE - 1)) + +typedef struct pagebuf_daemon { + int active; + spinlock_t pb_delwrite_lock; + struct list_head pb_delwrite_l; + int pb_delwri_cnt; +} pagebuf_daemon_t; + +typedef struct pagebuf_marker_s { + struct list_head pb_list; + page_buf_flags_t pb_flags; +} pagebuf_marker_t; + +/* + * Tunable pagebuf parameters + */ + +#define P_PARAM 4 + +typedef union pagebuf_param { + struct { + ulong flush_interval; /* interval between runs of the + * delwri flush daemon. */ + ulong age_buffer; /* time for buffer to age before + * we flush it. */ + ulong max_dio; /* maximum pages locked in a dio call */ + ulong debug; /* debug tracing on or off */ + } p_un; + ulong data[P_PARAM]; +} pagebuf_param_t; + +enum +{ + PB_FLUSH_INT = 1, + PB_FLUSH_AGE = 2, + PB_DIO_MAX = 3, + PB_DEBUG = 4 +}; + +extern pagebuf_param_t pb_params; + +/* + * Pagebuf statistics + */ + +struct pbstats { + u_int32_t pb_get; + u_int32_t pb_create; + u_int32_t pb_get_locked; + u_int32_t pb_get_locked_waited; + u_int32_t pb_busy_locked; + u_int32_t pb_miss_locked; + u_int32_t pb_page_alloc; + u_int32_t pb_page_found; +}; + +extern struct pbstats pbstats; + +# define PB_STATS_INC(count) ( count ++ ) + + +#endif /* _PAGE_BUF_INTERNAL_ */ + +/* + * Page_buf_apply_t + * + * Type of function pointer supplied to pagebuf_segment_apply. + */ + +typedef int (*page_buf_apply_t)( /* function to apply to segment */ + page_buf_t *, /* buffer to examine */ + loff_t, /* offset in file of segment */ + struct page *, /* page (NULL if not in mem_map[]) */ + size_t, /* offset in page */ + size_t); /* length of segment */ + +/* + * page_buf module entry points + */ + +/* Finding and Reading Buffers */ + +extern page_buf_t *pagebuf_find( /* find buffer for block if */ + /* the block is in memory */ + struct pb_target *, /* inode for block */ + loff_t, /* starting offset of range */ + size_t, /* length of range */ + page_buf_flags_t); /* PBF_LOCK, PBF_ALWAYS_ALLOC */ + +extern page_buf_t *pagebuf_get( /* allocate a buffer */ + struct pb_target *, /* inode for buffer (or NULL) */ + loff_t, /* starting offset of range */ + size_t, /* length of range */ + page_buf_flags_t); /* PBF_LOCK, PBF_READ, PBF_ALLOCATE, */ + /* PBF_ASYNC, PBF_SEQUENTIAL */ + +extern page_buf_t *pagebuf_lookup( + struct inode *, + loff_t, size_t, int); + +extern page_buf_t *pagebuf_get_empty( /* allocate pagebuf struct with no memory or disk address */ + struct pb_target *); /* mount point "fake" inode */ + +extern page_buf_t *pagebuf_get_no_daddr( /* allocate pagebuf struct without disk address */ + size_t len, + struct pb_target *); /* mount point "fake" inode */ + +extern int pagebuf_associate_memory( + page_buf_t *, + void *, + size_t); + + +extern void pagebuf_hold( /* increment reference count */ + page_buf_t *); /* buffer to hold */ + +extern void pagebuf_readahead( /* read ahead into cache */ + struct pb_target *, /* target for buffer (or NULL) */ + loff_t, /* starting offset of range */ + size_t, /* length of range */ + int); /* additional read flags */ + +/* Writing and Releasing Buffers */ + +extern void pagebuf_free( /* deallocate a buffer */ + page_buf_t *); /* buffer to deallocate */ + +extern void pagebuf_rele( /* release hold on a buffer */ + page_buf_t *); /* buffer to release */ + +/* Locking and Unlocking Buffers */ + +extern int pagebuf_cond_lock( /* lock buffer, if not locked */ + /* (returns -EBUSY if locked) */ + page_buf_t *); /* buffer to lock */ + +extern int pagebuf_is_locked( /* test if buffer is locked */ + /* (0 if unlocked, 1 if locked) */ + page_buf_t *); /* buffer to test */ + +extern int pagebuf_lock_value( /* return count on lock */ + page_buf_t *); /* buffer to check */ + +extern int pagebuf_lock( /* lock buffer */ + /* (returns -EDEADLK if would */ + /* deadlock) */ + page_buf_t *); /* buffer to lock */ + +extern int pagebuf_lock_disable( /* disable buffer locking */ + struct pb_target *); /* inode for buffers */ + +extern struct pb_target *pagebuf_lock_enable( + kdev_t, + struct super_block *); + +extern int pagebuf_target_clear(struct pb_target *); + +extern void pagebuf_unlock( /* unlock buffer */ + page_buf_t *); /* buffer to unlock */ + +/* Buffer Management for Inodes */ + +extern void pagebuf_flush( /* write buffered storage */ + struct inode *, /* inode for range */ + loff_t, /* first location in range */ + page_buf_flags_t); /* PBF_ASYNC */ + +extern void pagebuf_inval( /* invalidate buffered data for */ + /* inode */ + struct inode *, /* inode for range */ + loff_t, /* first location in range */ + page_buf_flags_t); /* PBF_ASYNC */ + +extern void pagebuf_flushinval( /* write and invalidate */ + /* buffered data for inode */ + struct inode *, /* inode for range */ + loff_t, /* first location in range */ + page_buf_flags_t); /* PBF_ASYNC */ + +/* Buffer Utility Routines */ + +extern int pagebuf_geterror( /* return buffer error */ + page_buf_t *); /* buffer */ + +extern void pagebuf_iodone( /* mark buffer I/O complete */ + page_buf_t *); /* buffer to mark */ + +extern void pagebuf_ioerror( /* mark buffer in error (or not) */ + page_buf_t *, /* buffer to mark */ + int); /* error to store (0 if none) */ + +extern int pagebuf_iostart( /* start I/O on a buffer */ + page_buf_t *, /* buffer to start */ + page_buf_flags_t); /* PBF_LOCK, PBF_ASYNC, PBF_READ, */ + /* PBF_WRITE, PBF_ALLOCATE, */ + /* PBF_DELWRI, PBF_SEQUENTIAL, */ + /* PBF_SYNC */ + +extern int pagebuf_iorequest( /* start real I/O */ + page_buf_t *); /* buffer to convey to device */ + + /* + * pagebuf_iorequest is the core I/O request routine. + * It assumes that the buffer is well-formed and + * mapped and ready for physical I/O, unlike + * pagebuf_iostart() and pagebuf_iophysio(). Those + * routines call the inode pagebuf_ioinitiate routine to start I/O, + * if it is present, or else call pagebuf_iorequest() + * directly if the inode pagebuf_ioinitiate routine is not present. + */ + +extern int pagebuf_iowait( /* wait for buffer I/O done */ + page_buf_t *); /* buffer to wait on */ + +extern int pagebuf_iozero( /* zero contents of buffer */ + struct inode *, /* inode owning pages */ + page_buf_t *, /* buffer to zero */ + off_t, /* offset in buffer */ + size_t); /* size of data to zero */ + +extern caddr_t pagebuf_offset(page_buf_t *, off_t); + +extern int pagebuf_segment( /* return next segment of buffer */ + page_buf_t *, /* buffer to examine */ + loff_t *, /* offset in buffer of next */ + /* segment (updated) */ + struct page **, /* page (updated) */ + /* (NULL if not in mem_map[]) */ + size_t *, /* offset in page (updated) */ + size_t *, /* length of segment (updated) */ + page_buf_flags_t); /* PBF_ALWAYS_ALLOC */ + +extern int pagebuf_iomove( /* move data in/out of pagebuf */ + page_buf_t *, /* buffer to manipulate */ + off_t, /* starting buffer offset */ + size_t, /* length in buffer */ + caddr_t, /* data pointer */ + page_buf_rw_t); /* direction */ + +extern int pagebuf_segment_apply( /* apply function to segments */ + page_buf_apply_t, /* function to call */ + page_buf_t *); /* buffer to examine */ + +/* Pinning Buffer Storage in Memory */ + +extern void pagebuf_pin( /* pin buffer in memory */ + page_buf_t *); /* buffer to pin */ + +extern void pagebuf_unpin( /* unpin buffered data */ + page_buf_t *); /* buffer to unpin */ + +extern void pagebuf_wait_unpin( /* wait for buffer to be unpinned */ + page_buf_t *); /* buffer for which to wait */ + +extern int pagebuf_ispin( page_buf_t *); /* check to see if pagebuf is pinned */ + +/* Reading and writing pages */ + +extern ssize_t pagebuf_direct_file_read( + struct file *, /* file to read */ + char *, /* buffer address */ + size_t, /* size of buffer */ + loff_t *, /* file offset to use and update */ + pagebuf_bmap_fn_t); /* bmap function */ + + /* + * pagebuf_generic_file_read reads data from the specified file + * at the loff_t referenced, updating the loff_t to point after the + * data read and returning the count of bytes read. + * The data is read into the supplied buffer, up to a maximum of the + * specified size. + */ + + +extern ssize_t pagebuf_generic_file_write( + struct file *, /* file to write */ + char *, /* buffer address */ + size_t, /* size of buffer */ + loff_t *, /* file offset to use and update */ + pagebuf_bmap_fn_t); /* bmap function */ + + /* + * pagebuf_generic_file_write writes data from the specified file + * at the loff_t referenced, updating the loff_t to point after the + * data written and returning the count of bytes written. + * The data is written from the supplied buffer, up to a maximum of the + * specified size. Normally all of the data is written, unless there + * is an error. + */ + +extern int pagebuf_read_full_page( /* read a page via pagebuf */ + struct file *, /* file to read */ + struct page *, /* page to read */ + pagebuf_bmap_fn_t); /* bmap function */ + +extern int pagebuf_write_full_page( /* write a page via pagebuf */ + struct page *, /* page to write */ + pagebuf_bmap_fn_t); /* bmap function */ + +extern int pagebuf_commit_write( + struct file *file, + struct page *page, + unsigned from, + unsigned to); + +extern int pagebuf_prepare_write( + struct file *, + struct page *, + unsigned, + unsigned, + pagebuf_bmap_fn_t); + +extern void pagebuf_delwri_queue(page_buf_t *, int); +extern void pagebuf_delwri_dequeue(page_buf_t *); +extern void pagebuf_daemon_wakeup(int); +#define PBDF_WAIT 0x01 +#define PBDF_TRYLOCK 0x02 +extern void pagebuf_delwri_flush(struct pb_target *, u_long, int *); + + +#ifdef _PAGE_BUF_INTERNAL_ + +extern int _pagebuf_get_object(struct pb_target *, + loff_t, + size_t, + page_buf_flags_t, + page_buf_t **); + +extern void _pagebuf_free_object( /* deallocate a buffer */ + page_buf_t *, /* buffer to deallocate */ + unsigned long); /* interrupt flags */ + +extern int _pagebuf_lookup_pages(page_buf_t *pb, + struct address_space *aspace, + page_buf_flags_t flags); + +extern int pagebuf_locking_init(void); +extern void pagebuf_locking_terminate(void); + +#define assert(x) do { } while (0) +#define bzero(loc,size) memset(loc,0,size) +#define min(a,b) ((a) < (b) ? (a) : (b)) + + +#endif /* _PAGE_BUF_INTERNAL_ */ + +/* XXX + * special note: this really is backwards wrt. the internal/external + * convention. As there are still places pagebuf_iorequest() is still + * called, just reversing pagebuf_iorequest() and __page_iorequest() + * won't really work. + */ +static __inline__ int __pagebuf_iorequest(page_buf_t *pb) +{ + /* If the filesystem wants to intervene in the process then + * let it, this function will typically call pagebuf_iorequest() + * after some checks. + */ + + if (pb->pb_strat) + return pb->pb_strat(pb); + + return pagebuf_iorequest(pb); +} + +extern size_t pagebuf_max_direct(void); + +#endif /* defined(CONFIG_PAGE_BUF) || defined(CONFIG_PAGE_BUF_MODULE) */ + +#endif /* _LINUX_PAGE_BUF_H */ diff -rNu linux-2.4.7/linux/include/linux/page_buf_trace.h linux-2.4-xfs/linux/include/linux/page_buf_trace.h --- linux-2.4.7/linux/include/linux/page_buf_trace.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/page_buf_trace.h Fri Sep 29 01:06:57 2000 @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef _PAGEBUF_TRACE_INC_ +#define _PAGEBUF_TRACE_INC_ + +#ifdef PB_DEFINE_TRACES +#define PB_TRACE_START typedef enum { +#define PB_TRACE_REC(x) pb_trace_point_##x +#define PB_TRACE_END } pb_trace_var_t; +#else +#define PB_TRACE_START static char *event_names[] = { +#define PB_TRACE_REC(x) #x +#define PB_TRACE_END }; +#endif + +PB_TRACE_START +PB_TRACE_REC(get), +PB_TRACE_REC(get_obj), +PB_TRACE_REC(free_obj), +PB_TRACE_REC(look_pg), +PB_TRACE_REC(get_read), +PB_TRACE_REC(no_daddr), +PB_TRACE_REC(hold), +PB_TRACE_REC(rele), +PB_TRACE_REC(done), +PB_TRACE_REC(ioerror), +PB_TRACE_REC(iostart), +PB_TRACE_REC(end_io), +PB_TRACE_REC(do_io), +PB_TRACE_REC(ioreq), +PB_TRACE_REC(iowait), +PB_TRACE_REC(iowaited), +PB_TRACE_REC(free_lk), +PB_TRACE_REC(freed_l), +PB_TRACE_REC(cmp), +PB_TRACE_REC(get_lk), +PB_TRACE_REC(got_lk), +PB_TRACE_REC(skip), +PB_TRACE_REC(lock), +PB_TRACE_REC(locked), +PB_TRACE_REC(unlock), +PB_TRACE_REC(avl_ret), +PB_TRACE_REC(condlck), +PB_TRACE_REC(avl_ins), +PB_TRACE_REC(walkq1), +PB_TRACE_REC(walkq2), +PB_TRACE_REC(walkq3), +PB_TRACE_REC(delwri_q), +PB_TRACE_REC(delwri_uq), +PB_TRACE_REC(pin), +PB_TRACE_REC(unpin), +PB_TRACE_REC(file_write), +PB_TRACE_END + +extern void pb_trace_func(page_buf_t *, int, void *, void *); +#ifdef PAGEBUF_TRACE +#ifdef _PAGE_BUF_INTERNAL_ +#define PB_TRACE(pb, event, misc) \ + pb_trace_func(pb, event, (void *) misc, \ + (void *)__builtin_return_address(0)) +#else +#define PB_TRACE(pb, misc) \ + pb_trace_func(pb, pb_trace_point_external, (void *) misc, NULL) +#endif + +#define pb_trace_point_external 1000 + +#else + +#define PB_TRACE(pb, event, misc) + +#endif + + +#endif diff -rNu linux-2.4.7/linux/include/linux/pagemap.h linux-2.4-xfs/linux/include/linux/pagemap.h --- linux-2.4.7/linux/include/linux/pagemap.h Tue Jul 3 17:42:57 2001 +++ linux-2.4-xfs/linux/include/linux/pagemap.h Wed May 2 01:22:13 2001 @@ -75,6 +75,8 @@ unsigned long offset, struct page **hash); extern struct page * __find_lock_page (struct address_space * mapping, unsigned long index, struct page **hash); +extern struct page * find_get_page_simple (struct address_space * mapping, + unsigned long index); extern void lock_page(struct page *page); #define find_lock_page(mapping, index) \ __find_lock_page(mapping, index, page_hash(mapping, index)) @@ -85,6 +87,7 @@ __find_get_swapcache_page(mapping, index, page_hash(mapping, index)) extern void __add_page_to_hash_queue(struct page * page, struct page **p); +extern int add_to_page_cache_unique(struct page * page, struct address_space *mapping, unsigned long index, struct page **hash); extern void add_to_page_cache(struct page * page, struct address_space *mapping, unsigned long index); extern void add_to_page_cache_locked(struct page * page, struct address_space *mapping, unsigned long index); diff -rNu linux-2.4.7/linux/include/linux/raid/CVS/Entries linux-2.4-xfs/linux/include/linux/raid/CVS/Entries --- linux-2.4.7/linux/include/linux/raid/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/raid/CVS/Entries Thu Jul 5 12:06:48 2001 @@ -0,0 +1,11 @@ +/linear.h/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/md.h/1.6/Tue May 29 19:53:13 2001/-ko/ +/md_compatible.h/1.3/Sat Nov 25 08:05:45 2000/-ko/ +/md_k.h/1.10/Tue May 29 19:53:13 2001/-ko/ +/md_p.h/1.3/Sat Nov 25 08:05:45 2000/-ko/ +/md_u.h/1.5/Thu Feb 1 17:10:24 2001/-ko/ +/raid0.h/1.3/Sun Dec 17 19:15:00 2000/-ko/ +/raid1.h/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/raid5.h/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/xor.h/1.2/Sat Nov 25 08:05:45 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/linux/raid/CVS/Repository linux-2.4-xfs/linux/include/linux/raid/CVS/Repository --- linux-2.4.7/linux/include/linux/raid/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/raid/CVS/Repository Thu Jul 5 12:06:47 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/linux/raid diff -rNu linux-2.4.7/linux/include/linux/raid/CVS/Root linux-2.4-xfs/linux/include/linux/raid/CVS/Root --- linux-2.4.7/linux/include/linux/raid/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/raid/CVS/Root Thu Jul 5 12:06:47 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/linux/slab.h linux-2.4-xfs/linux/include/linux/slab.h --- linux-2.4.7/linux/include/linux/slab.h Tue Jul 3 17:42:55 2001 +++ linux-2.4-xfs/linux/include/linux/slab.h Mon Jul 2 10:59:04 2001 @@ -54,6 +54,7 @@ extern int kmem_cache_destroy(kmem_cache_t *); extern int kmem_cache_shrink(kmem_cache_t *); extern void *kmem_cache_alloc(kmem_cache_t *, int); +extern void *kmem_cache_zalloc(kmem_cache_t *, int); extern void kmem_cache_free(kmem_cache_t *, void *); extern void *kmalloc(size_t, int); diff -rNu linux-2.4.7/linux/include/linux/sunrpc/CVS/Entries linux-2.4-xfs/linux/include/linux/sunrpc/CVS/Entries --- linux-2.4.7/linux/include/linux/sunrpc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/sunrpc/CVS/Entries Thu Jul 5 12:06:48 2001 @@ -0,0 +1,13 @@ +/auth.h/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/clnt.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/debug.h/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/msg_prot.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sched.h/1.8/Wed May 2 06:22:13 2001/-ko/ +/stats.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/svc.h/1.4/Fri Apr 21 16:16:46 2000/-ko/ +/svcauth.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/svcsock.h/1.3/Fri Feb 11 01:00:06 2000/-ko/ +/types.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/xdr.h/1.4/Fri Apr 21 16:16:46 2000/-ko/ +/xprt.h/1.8/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/linux/sunrpc/CVS/Repository linux-2.4-xfs/linux/include/linux/sunrpc/CVS/Repository --- linux-2.4.7/linux/include/linux/sunrpc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/sunrpc/CVS/Repository Thu Jul 5 12:06:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/linux/sunrpc diff -rNu linux-2.4.7/linux/include/linux/sunrpc/CVS/Root linux-2.4-xfs/linux/include/linux/sunrpc/CVS/Root --- linux-2.4.7/linux/include/linux/sunrpc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/sunrpc/CVS/Root Thu Jul 5 12:06:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/linux/sysctl.h linux-2.4-xfs/linux/include/linux/sysctl.h --- linux-2.4.7/linux/include/linux/sysctl.h Tue Jul 3 17:42:55 2001 +++ linux-2.4-xfs/linux/include/linux/sysctl.h Tue May 29 14:53:13 2001 @@ -118,7 +118,9 @@ KERN_SHMPATH=48, /* string: path to shm fs */ KERN_HOTPLUG=49, /* string: path to hotplug policy agent */ KERN_IEEE_EMULATION_WARNINGS=50, /* int: unimplemented ieee instructions */ - KERN_S390_USER_DEBUG_LOGGING=51 /* int: dumps of user faults */ + KERN_S390_USER_DEBUG_LOGGING=51, /* int: dumps of user faults */ + KERN_NMI_WATCHDOG=52, /* int: nmi_watchdog on/off */ + KERN_KDB=53, /* int: kdb on/off */ }; @@ -134,7 +136,8 @@ VM_PAGECACHE=7, /* struct: Set cache memory thresholds */ VM_PAGERDAEMON=8, /* struct: Control kswapd behaviour */ VM_PGT_CACHE=9, /* struct: Set page table cache parameters */ - VM_PAGE_CLUSTER=10 /* int: set number of pages to swap together */ + VM_PAGE_CLUSTER=10, /* int: set number of pages to swap together */ + VM_PAGEBUF=11 /* struct: Control pagebuf parameters */ }; diff -rNu linux-2.4.7/linux/include/linux/vmalloc.h linux-2.4-xfs/linux/include/linux/vmalloc.h --- linux-2.4.7/linux/include/linux/vmalloc.h Tue Jul 3 17:42:55 2001 +++ linux-2.4-xfs/linux/include/linux/vmalloc.h Thu May 31 00:16:19 2001 @@ -26,6 +26,7 @@ extern int vmalloc_area_pages(unsigned long address, unsigned long size, int gfp_mask, pgprot_t prot); +void * remap_page_array(struct page **, int, int); /* * Allocate any pages */ diff -rNu linux-2.4.7/linux/include/linux/vnode.h linux-2.4-xfs/linux/include/linux/vnode.h --- linux-2.4.7/linux/include/linux/vnode.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/vnode.h Fri Sep 29 01:06:57 2000 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef _LINUX_VNODE_I +#define _LINUX_VNODE_I + +#include +#include + +/* + * Vnode types (unrelated to on-disk inodes). VNON means no type. + */ + +typedef enum vtype { + VNON = 0, + VREG = 1, + VDIR = 2, + VBLK = 3, + VCHR = 4, + VLNK = 5, + VFIFO = 6, + VBAD = 7, + VSOCK = 8 +} vtype_t; + +/* + * The prefix of a vnode struct is its freelist linkage. The freelist + * header has two pointers so we can insert at either end. + */ +typedef struct vnlist { + struct vnode *vl_next; + struct vnode *vl_prev; +} vnlist_t; + +typedef __u64 vnumber_t; + +struct inode; +struct pregion; + +/* + * Define the type of behavior head used by vnodes. + */ +#define vn_bhv_head_t bhv_head_t + +/* + * MP locking protocols: + * v_flag, v_count VN_LOCK/VN_UNLOCK + * v_vfsp VN_LOCK/VN_UNLOCK + * v_type read-only or fs-dependent + * v_list, v_hashp, v_hashn freelist lock + */ +typedef struct vnode { + __u32 v_flag; /* vnode flags (see below) */ + enum vtype v_type; /* vnode type */ + struct vfs *v_vfsp; /* ptr to containing VFS*/ + vnumber_t v_number; /* in-core vnode number */ + vn_bhv_head_t v_bh; /* behavior head */ + + spinlock_t v_lock; /* don't use VLOCK on Linux */ + struct inode *v_inode; /* linux inode */ +#ifdef CONFIG_XFS_VNODE_TRACING + struct ktrace *v_trace; /* trace header structure */ +#endif /* CONFIG_XFS_VNODE_TRACING */ +} vnode_t; + +#endif /* _LINUX_VNODE_I */ diff -rNu linux-2.4.7/linux/include/linux/xfs_fs.h linux-2.4-xfs/linux/include/linux/xfs_fs.h --- linux-2.4.7/linux/include/linux/xfs_fs.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/xfs_fs.h Wed May 16 21:58:46 2001 @@ -0,0 +1,485 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef _LINUX_XFS_FS_H +#define _LINUX_XFS_FS_H + +#include +#include + + +/* + * SGI's XFS filesystem's major stuff (constants, structures) + */ + +#define XFS_SUPER_MAGIC 0x58465342 +#define XFS_NAME "xfs" + +struct biosize { + __u32 biosz_flags; + __s32 biosz_read; + __s32 biosz_write; + __s32 dfl_biosz_read; + __s32 dfl_biosz_write; +}; + +/* + * direct I/O attribute record used with F_DIOINFO + * d_miniosz is the min xfer size, xfer size multiple and file seek offset + * alignment. + */ +struct dioattr { + __u32 d_mem; /* data buffer memory alignment */ + __u32 d_miniosz; /* min xfer size */ + __u32 d_maxiosz; /* max xfer size */ +}; + +/* + * Structure for F_FSGETXATTR[A] and F_FSSETXATTR. + */ +struct fsxattr { + __u32 fsx_xflags; /* xflags field value (get/set) */ + __u32 fsx_extsize; /* extsize field value (get/set)*/ + __u32 fsx_nextents; /* nextents field value (get) */ + unsigned char fsx_pad[16]; +}; + +/* + * Flags for the bs_xflags/fsx_xflags field + * There should be a one-to-one correspondence between these flags and the + * XFS_DIFLAG_s. + */ +#define XFS_XFLAG_REALTIME 0x00000001 +#define XFS_XFLAG_PREALLOC 0x00000002 +#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ +#define XFS_XFLAG_ALL \ + ( XFS_XFLAG_REALTIME|XFS_XFLAG_PREALLOC|XFS_XFLAG_HASATTR ) + + +/* + * Structure for F_GETBMAP. + * On input, fill in bmv_offset and bmv_length of the first structure + * to indicate the area of interest in the file, and bmv_entry with the + * number of array elements given. The first structure is updated on + * return to give the offset and length for the next call. + */ +struct getbmap { + __s64 bmv_offset; /* file offset of segment in blocks */ + __s64 bmv_block; /* starting block (64-bit daddr_t) */ + __s64 bmv_length; /* length of segment, blocks */ + __s32 bmv_count; /* # of entries in array incl. 1st */ + __s32 bmv_entries; /* # of entries filled in (output) */ +}; + +/* + * Structure for F_GETBMAPX. The fields bmv_offset through bmv_entries + * are used exactly as in the getbmap structure. The getbmapx structure + * has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field + * is only used for the first structure. It contains input flags + * specifying F_GETBMAPX actions. The bmv_oflags field is filled in + * by the F_GETBMAPX command for each returned structure after the first. + */ +struct getbmapx { + __s64 bmv_offset; /* file offset of segment in blocks */ + __s64 bmv_block; /* starting block (64-bit daddr_t) */ + __s64 bmv_length; /* length of segment, blocks */ + __s32 bmv_count; /* # of entries in array incl. 1st */ + __s32 bmv_entries; /* # of entries filled in (output). */ + __s32 bmv_iflags; /* input flags (1st structure) */ + __s32 bmv_oflags; /* output flags (after 1st structure)*/ + __s32 bmv_unused1; /* future use */ + __s32 bmv_unused2; /* future use */ +}; + +/* bmv_iflags values - set by F_GETBMAPX caller. */ + +#define BMV_IF_ATTRFORK 0x1 /* return attr fork rather than data */ +#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */ +#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */ + +#define BMV_IF_VALID (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC) + +/* bmv_oflags values - returned from F_GETBMAPX for each non-header segment */ + +#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ + +/* Convert getbmap <-> getbmapx - move fields from p1 to p2. */ + +#define GETBMAP_CONVERT(p1,p2) { \ + p2.bmv_offset = p1.bmv_offset; \ + p2.bmv_block = p1.bmv_block; \ + p2.bmv_length = p1.bmv_length; \ + p2.bmv_count = p1.bmv_count; \ + p2.bmv_entries = p1.bmv_entries; } + +#ifdef __KERNEL__ + +/* Kernel only bmv_iflags value. */ +#define BMV_IF_EXTENDED 0x40000000 /* getpmapx if set */ + +#endif /* __KERNEL__ */ + +/* + * Structure for F_FSSETDM. + * For use by backup and restore programs to set the XFS on-disk inode + * fields di_dmevmask and di_dmstate. These must be set to exactly and + * only values previously obtained via xfs_bulkstat! (Specifically the + * xfs_bstat_t fields bs_dmevmask and bs_dmstate.) + */ +struct fsdmidata { + __s32 fsd_dmevmask; /* corresponds to di_dmevmask */ + __u16 fsd_padding; + __u16 fsd_dmstate; /* corresponds to di_dmstate */ +}; + +/* + * File segment locking set data type for 64 bit access. + * Also used for all the RESV/FREE interfaces. + */ +typedef struct xfs_flock64 { + __s16 l_type; + __s16 l_whence; + __s64 l_start; + __s64 l_len; /* len == 0 means until end of file */ + __s32 l_sysid; + pid_t l_pid; + __s32 l_pad[4]; /* reserve area */ +} xfs_flock64_t; + +/* + * Output for XFS_IOC_FSGEOMETRY + */ +typedef struct xfs_fsop_geom { + __u32 blocksize; /* filesystem (data) block size */ + __u32 rtextsize; /* realtime extent size */ + __u32 agblocks; /* fsblocks in an AG */ + __u32 agcount; /* number of allocation groups */ + __u32 logblocks; /* fsblocks in the log */ + __u32 sectsize; /* (data) sector size, bytes */ + __u32 inodesize; /* inode size in bytes */ + __u32 imaxpct; /* max allowed inode space(%) */ + __u64 datablocks; /* fsblocks in data subvolume */ + __u64 rtblocks; /* fsblocks in realtime subvol */ + __u64 rtextents; /* rt extents in realtime subvol*/ + __u64 logstart; /* starting fsblock of the log */ + unsigned char uuid[16]; /* unique id of the filesystem */ + __u32 sunit; /* stripe unit, fsblocks */ + __u32 swidth; /* stripe width, fsblocks */ + __s32 version; /* structure version */ + __u32 flags; /* superblock version flags */ + __u32 logsectsize; /* log sector size, bytes */ + __u32 rtsectsize; /* realtime sector size, bytes */ + __u32 dirblocksize; /* directory block size, bytes */ +} xfs_fsop_geom_t; + +/* Output for XFS_FS_COUNTS */ +typedef struct xfs_fsop_counts { + __u64 freedata; /* free data section blocks */ + __u64 freertx; /* free rt extents */ + __u64 freeino; /* free inodes */ + __u64 allocino; /* total allocated inodes */ +} xfs_fsop_counts_t; + +/* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */ +typedef struct xfs_fsop_resblks { + __u64 resblks; + __u64 resblks_avail; +} xfs_fsop_resblks_t; + +#define XFS_FSOP_GEOM_VERSION 0 + +#define XFS_FSOP_GEOM_FLAGS_ATTR 0x01 /* attributes in use */ +#define XFS_FSOP_GEOM_FLAGS_NLINK 0x02 /* 32-bit nlink values */ +#define XFS_FSOP_GEOM_FLAGS_QUOTA 0x04 /* quotas enabled */ +#define XFS_FSOP_GEOM_FLAGS_IALIGN 0x08 /* inode alignment */ +#define XFS_FSOP_GEOM_FLAGS_DALIGN 0x10 /* large data alignment */ +#define XFS_FSOP_GEOM_FLAGS_SHARED 0x20 /* read-only shared */ +#define XFS_FSOP_GEOM_FLAGS_EXTFLG 0x40 /* special extent flag */ +#define XFS_FSOP_GEOM_FLAGS_DIRV2 0x80 /* directory version 2 */ + + +/* + * Minimum and maximum sizes need for growth checks + */ +#define XFS_MIN_AG_BLOCKS 64 +#define XFS_MIN_LOG_BLOCKS 512 +#define XFS_MAX_LOG_BLOCKS (64 * 1024) +#define XFS_MIN_LOG_BYTES (256 * 1024) +#define XFS_MAX_LOG_BYTES (128 * 1024 * 1024) + +/* + * XFS_IOC_FSGROWFSDATA + */ +typedef struct xfs_growfs_data { + __u64 newblocks; /* new data subvol size, fsblocks */ + __u32 imaxpct; /* new inode space percentage limit */ +} xfs_growfs_data_t; + +/* + * XFS_IOC_FSGROWFSLOG + */ +typedef struct xfs_growfs_log { + __u32 newblocks; /* new log size, fsblocks */ + __u32 isint; /* 1 if new log is internal */ +} xfs_growfs_log_t; + +/* + * XFS_IOC_FSGROWFSRT + */ +typedef struct xfs_growfs_rt { + __u64 newblocks; /* new realtime size, fsblocks */ + __u32 extsize; /* new realtime extent size, fsblocks */ +} xfs_growfs_rt_t; + + +/* + * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE + */ +typedef struct xfs_bstime { + time_t tv_sec; /* seconds */ + __s32 tv_nsec; /* and nanoseconds */ +} xfs_bstime_t; + +typedef struct xfs_bstat { + __u64 bs_ino; /* inode number */ + __u16 bs_mode; /* type and mode */ + __u16 bs_nlink; /* number of links */ + __u32 bs_uid; /* user id */ + __u32 bs_gid; /* group id */ + __u32 bs_rdev; /* device value */ + __s32 bs_blksize; /* block size */ + __s64 bs_size; /* file size */ + xfs_bstime_t bs_atime; /* access time */ + xfs_bstime_t bs_mtime; /* modify time */ + xfs_bstime_t bs_ctime; /* inode change time */ + int64_t bs_blocks; /* number of blocks */ + __u32 bs_xflags; /* extended flags */ + __s32 bs_extsize; /* extent size */ + __s32 bs_extents; /* number of extents */ + __u32 bs_gen; /* generation count */ + __u16 bs_projid; /* project id */ + unsigned char bs_pad[14]; /* pad space, unused */ + __u32 bs_dmevmask; /* DMIG event mask */ + __u16 bs_dmstate; /* DMIG state info */ + __u16 bs_aextents; /* attribute number of extents */ +} xfs_bstat_t; + +/* + * The user-level BulkStat Request interface structure. + */ +typedef struct xfs_fsop_bulkreq { + __u64 *lastip; /* last inode # pointer */ + __s32 icount; /* count of entries in buffer */ + void *ubuffer; /* user buffer for inode desc. */ + __s32 *ocount; /* output count pointer */ +} xfs_fsop_bulkreq_t; + + +/* + * Structures returned from xfs_inumbers syssgi routine. + */ +typedef struct xfs_inogrp { + __u64 xi_startino; /* starting inode number */ + __s32 xi_alloccount; /* # bits set in allocmask */ + __u64 xi_allocmask; /* mask of allocated inodes */ +} xfs_inogrp_t; + + +/* + * The user-level Handle Request interface structure. + */ +typedef struct xfs_fsop_handlereq { + __u32 fd; /* fd for FD_TO_HANDLE */ + void *path; /* user pathname */ + __u32 oflags; /* open flags */ + void *ihandle; /* user supplied handle */ + __u32 ihandlen; /* user supplied length */ + void *ohandle; /* user buffer for handle */ + __u32 *ohandlen; /* user buffer length */ +} xfs_fsop_handlereq_t; + +/* + * Error injection can be turned on ethier by DEBUG or by INDUCE_IO_ERROR + * below since relying only on DEBUG will undoubtedly be a different + * code path. + */ +/*#define INDUCE_IO_ERROR*/ + +#if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) +/* + * Error injection. + */ +typedef struct xfs_error_injection { + __s32 fd; + __s32 errtag; +} xfs_error_injection_t; +#endif /* DEBUG || INDUCE_IO_ERROR */ + +/* + * Compound structure for passing args through ioctl to xfs_attrctl_by_handle + */ +typedef struct xfs_fsop_attr_handlereq { + struct xfs_fsop_handlereq *hreq;/* handle request interface */ + /* structure */ + struct attr_op *ops; /* array of attribute ops */ + int count; /* number of attribute ops */ +} xfs_fsop_attr_handlereq_t; + +/* + * File system identifier. Should be unique (at least per machine). + */ +typedef struct { + __u32 val[2]; /* file system id type */ +} xfs_fsid_t; + +/* + * File identifier. Should be unique per filesystem on a single machine. + * This is typically called by a stateless file server in order to generate + * "file handles". + */ +#define MAXFIDSZ 46 + +typedef struct fid { + __u16 fid_len; /* length of data in bytes */ + unsigned char fid_data[MAXFIDSZ]; /* data (variable length) */ +} fid_t; + +typedef struct xfs_fid { + __u16 xfs_fid_len; /* length of remainder */ + __u16 xfs_fid_pad; + __u32 xfs_fid_gen; /* generation number */ + __u64 xfs_fid_ino; /* 64 bits inode number */ +} xfs_fid_t; + +typedef struct xfs_fid2 { + __u16 fid_len; /* length of remainder */ + __u16 fid_pad; /* padding, must be zero */ + __u32 fid_gen; /* generation number */ + __u64 fid_ino; /* inode number */ +} xfs_fid2_t; + +typedef struct xfs_handle { + union { + __s64 align; /* force alignment of ha_fid */ + xfs_fsid_t _ha_fsid; /* unique file system identifier */ + } ha_u; + xfs_fid_t ha_fid; /* file system specific file ID */ +} xfs_handle_t; + +#define ha_fsid ha_u._ha_fsid + +#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.xfs_fid_pad \ + - (char *) &(handle)) \ + + (handle).ha_fid.xfs_fid_len) + +#define XFS_HANDLE_CMP(h1, h2) bcmp(h1, h2, sizeof (xfs_handle_t)) + +#define FSHSIZE sizeof (fsid_t) + + +/* + * ioctl commands that replace IRIX fcntl()'s + * For 'documentation' purposed more than anything else, + * the "cmd #" field reflects the IRIX fcntl number. + */ +#define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64) +#define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64) +#define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr) +#define XFS_IOC_FSGETXATTR _IOR ('X', 31, struct fsxattr) +#define XFS_IOC_FSSETXATTR _IOW ('X', 32, struct fsxattr) +#define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64) +#define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64) +#define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap) +#define XFS_IOC_FSSETDM _IOW ('X', 39, struct fsdmidata) +#define XFS_IOC_RESVSP _IOW ('X', 40, struct xfs_flock64) +#define XFS_IOC_UNRESVSP _IOW ('X', 41, struct xfs_flock64) +#define XFS_IOC_RESVSP64 _IOW ('X', 42, struct xfs_flock64) +#define XFS_IOC_UNRESVSP64 _IOW ('X', 43, struct xfs_flock64) +#define XFS_IOC_GETBMAPA _IOWR('X', 44, struct getbmap) +#define XFS_IOC_FSGETXATTRA _IOR ('X', 45, struct fsxattr) +#define XFS_IOC_SETBIOSIZE _IOW ('X', 46, struct biosize) +#define XFS_IOC_GETBIOSIZE _IOR ('X', 47, struct biosize) +#define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap) + +/* + * ioctl commands that replace IRIX syssgi()'s + */ +#define XFS_IOC_FSGEOMETRY _IOR ('X', 100, struct xfs_fsop_geom) +#define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct xfs_fsop_bulkreq) +#define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct xfs_fsop_bulkreq) +#define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct xfs_fsop_bulkreq) +#define XFS_IOC_PATH_TO_FSHANDLE _IOWR('X', 104, struct xfs_fsop_handlereq) +#define XFS_IOC_PATH_TO_HANDLE _IOWR('X', 105, struct xfs_fsop_handlereq) +#define XFS_IOC_FD_TO_HANDLE _IOWR('X', 106, struct xfs_fsop_handlereq) +#define XFS_IOC_OPEN_BY_HANDLE _IOWR('X', 107, struct xfs_fsop_handlereq) +#define XFS_IOC_READLINK_BY_HANDLE _IOWR('X', 108, struct xfs_fsop_handlereq) +#define XFS_IOC_SWAPEXT _IOWR('X', 109, struct xfs_swapext) +#define XFS_IOC_FSGROWFSDATA _IOW('X', 110, struct xfs_growfs_data) +#define XFS_IOC_FSGROWFSLOG _IOW('X', 111, struct xfs_growfs_log) +#define XFS_IOC_FSGROWFSRT _IOW('X', 112, struct xfs_growfs_rt) +#define XFS_IOC_FSCOUNTS _IOR ('X', 113, struct xfs_fsop_counts) +#define XFS_IOC_SET_RESBLKS _IOR ('X', 114, struct xfs_fsop_resblks) +#define XFS_IOC_GET_RESBLKS _IOR ('X', 115, struct xfs_fsop_resblks) +#if (defined(DEBUG) || defined(INDUCE_IO_ERROR)) +#define XFS_IOC_ERROR_INJECTION _IOW('X', 116, struct xfs_error_injection) +#define XFS_IOC_ERROR_CLEARALL _IOW('X', 117, struct xfs_error_injection) +#endif /* DEBUG || INDUCE_IO_ERROR */ +#define XFS_IOC_ATTRCTL_BY_HANDLE _IOWR('X', 118, struct xfs_fsop_attr_handlereq) +#define XFS_IOC_FREEZE _IOWR('X', 119, int) +#define XFS_IOC_THAW _IOWR('X', 120, int) +/* + * ioctl command to export information not in standard interfaces + * 140: IRIX statvfs.f_fstr field - UUID from the superblock + */ +#define XFS_IOC_GETFSUUID _IOR ('X', 140, unsigned char[16]) + + +/* + * Block I/O parameterization. A basic block (BB) is the lowest size of + * filesystem allocation, and must == NBPSCTR. Length units given to bio + * routines are in BB's. + */ +#define BBSHIFT 9 +#define BBSIZE (1<> BBSHIFT) +#define BTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT) +#define BBTOB(bbs) ((bbs) << BBSHIFT) +#define OFFTOBB(bytes) (((__u64)(bytes) + BBSIZE - 1) >> BBSHIFT) +#define OFFTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT) +#define BBTOOFF(bbs) ((__u64)(bbs) << BBSHIFT) + +#define SEEKLIMIT32 0x7fffffff +#define BBSEEKLIMIT32 BTOBBT(SEEKLIMIT32) +#define SEEKLIMIT 0x7fffffffffffffffLL +#define BBSEEKLIMIT OFFTOBBT(SEEKLIMIT) + +#endif /* _LINUX_XFS_FS_H */ diff -rNu linux-2.4.7/linux/include/linux/xfs_fs_i.h linux-2.4-xfs/linux/include/linux/xfs_fs_i.h --- linux-2.4.7/linux/include/linux/xfs_fs_i.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/xfs_fs_i.h Fri Sep 29 01:06:57 2000 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ + +#ifndef _LINUX_XFS_FS_I +#define _LINUX_XFS_FS_I + +#include +#include + +#include + +/* + * xfs fs inode data + */ +struct xfs_inode_info { + vnode_t vnode; /* vnode */ +}; + + +#define LINVFS_GET_VN_ADDRESS(ip) (vnode_t *)(&((ip)->u.xfs_i.vnode)) + +#define LINVFS_GET_VP(ip) vn_address(ip) + +#define LINVFS_GET_IP(vp) (vp->v_inode) + +#endif /* _LINUX_XFS_FS_I */ diff -rNu linux-2.4.7/linux/include/linux/xfs_fs_sb.h linux-2.4-xfs/linux/include/linux/xfs_fs_sb.h --- linux-2.4.7/linux/include/linux/xfs_fs_sb.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/xfs_fs_sb.h Fri Sep 29 01:06:57 2000 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +/* + * include/linux/xfs_fs_sb.h + * + */ + +#ifndef _LINUX_XFS_FS_SB +#define _LINUX_XFS_FS_SB + +#include + +/* + * xfs' super-block + */ + +struct xfs_sb_info { + void *s_vfs; /* pointer to the vfs which points to the bhv */ + void *s_cvp; /* The fake Vnode that this FS covers */ +}; + +#define LINVFS_GET_VFS(s) (vfs_t *)((s)->u.xfs_sb.s_vfs) +#define LINVFS_SET_VFS(s, vfsp) ((s)->u.xfs_sb.s_vfs = vfsp) +#define LINVFS_GET_CVP(s) (vnode_t *)((s)->u.xfs_sb.s_cvp) +#define LINVFS_SET_CVP(s, vp) ((s)->u.xfs_sb.s_cvp = vp) + +#endif /* _LINUX_XFS_FS_SB */ diff -rNu linux-2.4.7/linux/include/linux/xqm.h linux-2.4-xfs/linux/include/linux/xqm.h --- linux-2.4.7/linux/include/linux/xqm.h Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/linux/xqm.h Mon Apr 2 21:52:38 2001 @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef __XQM_H__ +#define __XQM_H__ + +#include + +#define XQM_CMD(cmd) ( ('X'<<8)+(cmd) ) +#define IS_XQM_CMD(cmd) ( ((int)(cmd)>>8) == 'X' ) + +/* + * Disk quota - quotactl(2) commands for XFS Quota Manager (XQM). + */ +#define Q_XQUOTAON XQM_CMD(0x1) /* enable quota accounting/enforcement */ +#define Q_XQUOTAOFF XQM_CMD(0x2) /* disable quota accounting/enforcement */ +#define Q_XGETQUOTA XQM_CMD(0x3) /* get disk limits & usage */ +#define Q_XSETQLIM XQM_CMD(0x4) /* set disk limits only */ +#define Q_XGETQSTAT XQM_CMD(0x5) /* returns fs_quota_stat_t struct */ +#define Q_XQUOTARM XQM_CMD(0x6) /* free quota files' space */ + +/* + * fs_disk_quota structure: + * + * This contains the current quota information regarding a user/proj/group. + * It is 64-bit aligned, and all the blk units are in BBs (Basic Blocks) of + * 512 bytes. + */ +#define FS_DQUOT_VERSION 1 /* fs_disk_quota.d_version */ +typedef struct fs_disk_quota { + __s8 d_version; /* version of this structure */ + __s8 d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */ + __u16 d_fieldmask; /* field specifier */ + __u32 d_id; /* user, project, or group ID */ + __u64 d_blk_hardlimit;/* absolute limit on disk blks */ + __u64 d_blk_softlimit;/* preferred limit on disk blks */ + __u64 d_ino_hardlimit;/* maximum # allocated inodes */ + __u64 d_ino_softlimit;/* preferred inode limit */ + __u64 d_bcount; /* # disk blocks owned by the user */ + __u64 d_icount; /* # inodes owned by the user */ + __s32 d_itimer; /* zero if within inode limits */ + /* if not, we refuse service */ + __s32 d_btimer; /* similar to above; for disk blocks */ + __u16 d_iwarns; /* # warnings issued wrt num inodes */ + __u16 d_bwarns; /* # warnings issued wrt disk blocks */ + __s32 d_padding2; /* padding2 - for future use */ + __u64 d_rtb_hardlimit;/* absolute limit on realtime blks */ + __u64 d_rtb_softlimit;/* preferred limit on RT disk blks */ + __u64 d_rtbcount; /* # realtime blocks owned */ + __s32 d_rtbtimer; /* similar to above; for RT disk blks */ + __u16 d_rtbwarns; /* # warnings issued wrt RT disk blks */ + __s16 d_padding3; /* padding3 - for future use */ + char d_padding4[8]; /* yet more padding */ +} fs_disk_quota_t; + +/* + * These fields are sent to Q_XSETQLIM to specify fields that need to change. + */ +#define FS_DQ_ISOFT (1<<0) +#define FS_DQ_IHARD (1<<1) +#define FS_DQ_BSOFT (1<<2) +#define FS_DQ_BHARD (1<<3) +#define FS_DQ_RTBSOFT (1<<4) +#define FS_DQ_RTBHARD (1<<5) +#define FS_DQ_LIMIT_MASK (FS_DQ_ISOFT | FS_DQ_IHARD | FS_DQ_BSOFT | \ + FS_DQ_BHARD | FS_DQ_RTBSOFT | FS_DQ_RTBHARD) +/* + * These timers can only be set in super user's dquot. For others, timers are + * automatically started and stopped. Superusers timer values set the limits + * for the rest. In case these values are zero, the DQ_{F,B}TIMELIMIT values + * defined below are used. + * These values also apply only to the d_fieldmask field for Q_XSETQLIM. + */ +#define FS_DQ_BTIMER (1<<6) +#define FS_DQ_ITIMER (1<<7) +#define FS_DQ_RTBTIMER (1<<8) +#define FS_DQ_TIMER_MASK (FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER) + +/* + * The following constants define the default amount of time given a user + * before the soft limits are treated as hard limits (usually resulting + * in an allocation failure). These may be modified by the quotactl(2) + * system call with the Q_XSETQLIM command. + */ +#define DQ_FTIMELIMIT (7 * 24*60*60) /* 1 week */ +#define DQ_BTIMELIMIT (7 * 24*60*60) /* 1 week */ + +/* + * Various flags related to quotactl(2). Only relevant to XFS filesystems. + */ +#define XFS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */ +#define XFS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */ +#define XFS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */ +#define XFS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */ + +#define XFS_USER_QUOTA (1<<0) /* user quota type */ +#define XFS_PROJ_QUOTA (1<<1) /* (IRIX) project quota type */ +#define XFS_GROUP_QUOTA (1<<2) /* group quota type */ + +/* + * fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system. + * Provides a centralized way to get meta infomation about the quota subsystem. + * eg. space taken up for user and group quotas, number of dquots currently + * incore. + */ +#define FS_QSTAT_VERSION 1 /* fs_quota_stat.qs_version */ + +/* + * Some basic infomation about 'quota files'. + */ +typedef struct fs_qfilestat { + __u64 qfs_ino; /* inode number */ + __u64 qfs_nblks; /* number of BBs 512-byte-blks */ + __u32 qfs_nextents; /* number of extents */ +} fs_qfilestat_t; + +typedef struct fs_quota_stat { + __s8 qs_version; /* version number for future changes */ + __u16 qs_flags; /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */ + __s8 qs_pad; /* unused */ + fs_qfilestat_t qs_uquota; /* user quota storage information */ + fs_qfilestat_t qs_gquota; /* group quota storage information */ + __u32 qs_incoredqs; /* number of dquots incore */ + __s32 qs_btimelimit; /* limit for blks timer */ + __s32 qs_itimelimit; /* limit for inodes timer */ + __s32 qs_rtbtimelimit;/* limit for rt blks timer */ + __u16 qs_bwarnlimit; /* limit for num warnings */ + __u16 qs_iwarnlimit; /* limit for num warnings */ +} fs_quota_stat_t; + +#endif /* __XQM_H__ */ diff -rNu linux-2.4.7/linux/include/math-emu/CVS/Entries linux-2.4-xfs/linux/include/math-emu/CVS/Entries --- linux-2.4.7/linux/include/math-emu/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/math-emu/CVS/Entries Thu Jul 5 12:06:49 2001 @@ -0,0 +1,11 @@ +/double.h/1.2/Tue Dec 7 07:08:23 1999/-ko/ +/extended.h/1.2/Tue Dec 7 07:08:23 1999/-ko/ +/op-1.h/1.2/Wed Dec 29 19:17:52 1999/-ko/ +/op-2.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/op-4.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/op-8.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/op-common.h/1.2/Tue Dec 7 07:08:23 1999/-ko/ +/quad.h/1.2/Tue Dec 7 07:08:23 1999/-ko/ +/single.h/1.2/Tue Dec 7 07:08:23 1999/-ko/ +/soft-fp.h/1.2/Tue Dec 7 07:08:23 1999/-ko/ +D diff -rNu linux-2.4.7/linux/include/math-emu/CVS/Repository linux-2.4-xfs/linux/include/math-emu/CVS/Repository --- linux-2.4.7/linux/include/math-emu/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/math-emu/CVS/Repository Thu Jul 5 12:06:48 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/math-emu diff -rNu linux-2.4.7/linux/include/math-emu/CVS/Root linux-2.4-xfs/linux/include/math-emu/CVS/Root --- linux-2.4.7/linux/include/math-emu/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/math-emu/CVS/Root Thu Jul 5 12:06:48 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/net/CVS/Entries linux-2.4-xfs/linux/include/net/CVS/Entries --- linux-2.4.7/linux/include/net/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/net/CVS/Entries Thu Jul 5 12:06:54 2001 @@ -0,0 +1,60 @@ +/addrconf.h/1.7/Tue May 29 19:53:13 2001/-ko/ +/af_unix.h/1.4/Tue May 2 22:18:18 2000/-ko/ +/arp.h/1.3/Sun Aug 29 03:09:59 1999/-ko/ +/atmclip.h/1.5/Fri May 26 01:14:50 2000/-ko/ +/ax25.h/1.7/Wed Jan 3 01:43:05 2001/-ko/ +/checksum.h/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/datalink.h/1.3/Sun Aug 29 03:09:59 1999/-ko/ +/dn.h/1.6/Thu Feb 1 17:10:24 2001/-ko/ +/dn_dev.h/1.4/Tue Jan 11 18:48:48 2000/-ko/ +/dn_fib.h/1.4/Tue Jan 11 18:48:48 2000/-ko/ +/dn_neigh.h/1.4/Fri Mar 3 01:42:02 2000/-ko/ +/dn_nsp.h/1.4/Thu Feb 1 17:10:24 2001/-ko/ +/dn_route.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/dsfield.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/dst.h/1.7/Mon Oct 23 18:56:35 2000/-ko/ +/flow.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/icmp.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/if_inet6.h/1.7/Mon Oct 23 18:56:35 2000/-ko/ +/inet_common.h/1.3/Mon Aug 30 00:31:27 1999/-ko/ +/inet_ecn.h/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/inetpeer.h/1.1/Thu Jan 6 21:20:23 2000/-ko/ +/ip.h/1.15/Wed May 2 06:22:13 2001/-ko/ +/ip6_fib.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/ip6_fw.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ip6_route.h/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/ip_fib.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/ipconfig.h/1.3/Tue May 29 19:53:13 2001/-ko/ +/ipip.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/ipv6.h/1.9/Wed May 2 06:22:13 2001/-ko/ +/ipx.h/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/lapb.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/llc.h/1.3/Sun Aug 29 03:09:59 1999/-ko/ +/llc_frame.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/llc_name.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/llc_state.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/ndisc.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/neighbour.h/1.7/Mon Oct 23 18:56:35 2000/-ko/ +/netrom.h/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/p8022.h/1.3/Sun Aug 29 03:09:59 1999/-ko/ +/pkt_cls.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/pkt_sched.h/1.8/Mon Oct 23 18:56:35 2000/-ko/ +/profile.h/1.4/Mon Oct 23 18:56:35 2000/-ko/ +/protocol.h/1.7/Thu Jun 21 15:45:04 2001/-ko/ +/psnap.h/1.3/Sun Aug 29 03:09:59 1999/-ko/ +/raw.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/rawv6.h/1.4/Wed May 2 06:22:13 2001/-ko/ +/rose.h/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/route.h/1.10/Mon Oct 23 18:56:35 2000/-ko/ +/scm.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/slhc_vj.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/snmp.h/1.9/Thu Jun 21 15:45:04 2001/-ko/ +/sock.h/1.22/Wed May 2 06:22:13 2001/-ko/ +/spx.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/syncppp.h/1.2/Tue May 29 19:53:13 2001/-ko/ +/tcp.h/1.22/Wed May 2 06:22:13 2001/-ko/ +/tcp_ecn.h/1.2/Wed Jan 3 01:43:05 2001/-ko/ +/transp_v6.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/udp.h/1.6/Wed May 2 06:22:13 2001/-ko/ +/x25.h/1.9/Thu Feb 1 17:10:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/net/CVS/Entries.Log linux-2.4-xfs/linux/include/net/CVS/Entries.Log --- linux-2.4.7/linux/include/net/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/net/CVS/Entries.Log Thu Jul 5 12:06:54 2001 @@ -0,0 +1,2 @@ +A D/bluetooth//// +A D/irda//// diff -rNu linux-2.4.7/linux/include/net/CVS/Repository linux-2.4-xfs/linux/include/net/CVS/Repository --- linux-2.4.7/linux/include/net/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/net/CVS/Repository Thu Jul 5 12:06:49 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/net diff -rNu linux-2.4.7/linux/include/net/CVS/Root linux-2.4-xfs/linux/include/net/CVS/Root --- linux-2.4.7/linux/include/net/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/net/CVS/Root Thu Jul 5 12:06:49 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/net/bluetooth/CVS/Entries linux-2.4-xfs/linux/include/net/bluetooth/CVS/Entries --- linux-2.4.7/linux/include/net/bluetooth/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/net/bluetooth/CVS/Entries Thu Jul 5 12:06:54 2001 @@ -0,0 +1,10 @@ +/bluetooth.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/bluez.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/hci.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/hci_core.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/hci_emu.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/hci_uart.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/hci_usb.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/l2cap.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/l2cap_core.h/1.1/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/net/bluetooth/CVS/Repository linux-2.4-xfs/linux/include/net/bluetooth/CVS/Repository --- linux-2.4.7/linux/include/net/bluetooth/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/net/bluetooth/CVS/Repository Thu Jul 5 12:06:54 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/net/bluetooth diff -rNu linux-2.4.7/linux/include/net/bluetooth/CVS/Root linux-2.4-xfs/linux/include/net/bluetooth/CVS/Root --- linux-2.4.7/linux/include/net/bluetooth/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/net/bluetooth/CVS/Root Thu Jul 5 12:06:54 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/net/irda/CVS/Entries linux-2.4-xfs/linux/include/net/irda/CVS/Entries --- linux-2.4.7/linux/include/net/irda/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/net/irda/CVS/Entries Thu Jul 5 12:06:56 2001 @@ -0,0 +1,43 @@ +/ali-ircc.h/1.1/Thu Jul 5 05:29:17 2001/-ko/ +/crc.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/discovery.h/1.5/Sat Nov 25 08:05:45 2000/-ko/ +/ircomm_core.h/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/ircomm_event.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/ircomm_lmp.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/ircomm_param.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/ircomm_ttp.h/1.1/Mon Sep 6 21:49:56 1999/-ko/ +/ircomm_tty.h/1.7/Sat Nov 25 08:05:45 2000/-ko/ +/ircomm_tty_attach.h/1.3/Wed Dec 29 19:17:52 1999/-ko/ +/irda-usb.h/1.1/Tue May 29 19:53:13 2001/-ko/ +/irda.h/1.13/Tue May 29 19:53:13 2001/-ko/ +/irda_device.h/1.13/Thu Feb 22 21:09:04 2001/-ko/ +/iriap.h/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/iriap_event.h/1.3/Mon Nov 8 22:55:41 1999/-ko/ +/irias_object.h/1.6/Sat Nov 25 08:05:45 2000/-ko/ +/irlan_client.h/1.3/Sat Nov 25 08:05:45 2000/-ko/ +/irlan_common.h/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/irlan_eth.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/irlan_event.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/irlan_filter.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/irlan_provider.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/irlap.h/1.11/Thu Jul 5 05:29:17 2001/-ko/ +/irlap_event.h/1.5/Thu Jan 6 19:50:16 2000/-ko/ +/irlap_frame.h/1.7/Thu Feb 22 21:09:04 2001/-ko/ +/irlmp.h/1.6/Sat Nov 25 08:05:45 2000/-ko/ +/irlmp_event.h/1.3/Mon Sep 6 21:49:56 1999/-ko/ +/irlmp_frame.h/1.4/Thu Jan 6 19:50:16 2000/-ko/ +/irmod.h/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/irport.h/1.10/Tue Feb 1 23:02:54 2000/-ko/ +/irqueue.h/1.6/Sat Nov 25 08:05:45 2000/-ko/ +/irttp.h/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/irtty.h/1.8/Sat Nov 25 08:05:45 2000/-ko/ +/nsc-ircc.h/1.2/Fri Feb 11 01:00:06 2000/-ko/ +/parameters.h/1.3/Fri Mar 24 21:32:44 2000/-ko/ +/qos.h/1.8/Thu Jul 5 05:29:17 2001/-ko/ +/smc-ircc.h/1.6/Fri Feb 11 01:00:06 2000/-ko/ +/timer.h/1.5/Sat Nov 25 08:05:45 2000/-ko/ +/toshoboe.h/1.5/Tue Feb 1 23:02:54 2000/-ko/ +/w83977af.h/1.3/Wed Dec 29 19:17:52 1999/-ko/ +/w83977af_ir.h/1.5/Tue Feb 1 23:02:54 2000/-ko/ +/wrapper.h/1.6/Tue Feb 1 23:02:54 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/net/irda/CVS/Repository linux-2.4-xfs/linux/include/net/irda/CVS/Repository --- linux-2.4.7/linux/include/net/irda/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/net/irda/CVS/Repository Thu Jul 5 12:06:54 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/net/irda diff -rNu linux-2.4.7/linux/include/net/irda/CVS/Root linux-2.4-xfs/linux/include/net/irda/CVS/Root --- linux-2.4.7/linux/include/net/irda/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/net/irda/CVS/Root Thu Jul 5 12:06:54 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/pcmcia/CVS/Entries linux-2.4-xfs/linux/include/pcmcia/CVS/Entries --- linux-2.4.7/linux/include/pcmcia/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/pcmcia/CVS/Entries Thu Jul 5 12:06:57 2001 @@ -0,0 +1,15 @@ +/bulkmem.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/bus_ops.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/ciscode.h/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/cisreg.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/cistpl.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/cs.h/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/cs_types.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/driver_ops.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/ds.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/ftl.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/mem_op.h/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/memory.h/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/ss.h/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/version.h/1.7/Wed Nov 1 21:35:42 2000/-ko/ +D diff -rNu linux-2.4.7/linux/include/pcmcia/CVS/Repository linux-2.4-xfs/linux/include/pcmcia/CVS/Repository --- linux-2.4.7/linux/include/pcmcia/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/pcmcia/CVS/Repository Thu Jul 5 12:06:56 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/pcmcia diff -rNu linux-2.4.7/linux/include/pcmcia/CVS/Root linux-2.4-xfs/linux/include/pcmcia/CVS/Root --- linux-2.4.7/linux/include/pcmcia/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/pcmcia/CVS/Root Thu Jul 5 12:06:56 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/scsi/CVS/Entries linux-2.4-xfs/linux/include/scsi/CVS/Entries --- linux-2.4.7/linux/include/scsi/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/scsi/CVS/Entries Thu Jul 5 12:06:57 2001 @@ -0,0 +1,5 @@ +/scsi.h/1.5/Wed May 2 06:22:13 2001/-ko/ +/scsi_ioctl.h/1.3/Mon Oct 23 18:56:35 2000/-ko/ +/scsicam.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sg.h/1.10/Thu Jul 5 06:13:42 2001/-ko/ +D diff -rNu linux-2.4.7/linux/include/scsi/CVS/Repository linux-2.4-xfs/linux/include/scsi/CVS/Repository --- linux-2.4.7/linux/include/scsi/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/scsi/CVS/Repository Thu Jul 5 12:06:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/scsi diff -rNu linux-2.4.7/linux/include/scsi/CVS/Root linux-2.4-xfs/linux/include/scsi/CVS/Root --- linux-2.4.7/linux/include/scsi/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/scsi/CVS/Root Thu Jul 5 12:06:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/include/video/CVS/Entries linux-2.4-xfs/linux/include/video/CVS/Entries --- linux-2.4.7/linux/include/video/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/video/CVS/Entries Thu Jul 5 12:06:58 2001 @@ -0,0 +1,23 @@ +/fbcon-afb.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbcon-cfb16.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbcon-cfb2.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbcon-cfb24.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbcon-cfb32.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbcon-cfb4.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbcon-cfb8.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbcon-hga.h/1.1/Wed Mar 8 01:44:14 2000/-ko/ +/fbcon-ilbm.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbcon-iplan2p2.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbcon-iplan2p4.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbcon-iplan2p8.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbcon-mac.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbcon-mfb.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbcon-vga-planes.h/1.1/Fri Jun 25 17:32:48 1999/-ko/ +/fbcon-vga.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/fbcon.h/1.10/Sun Dec 17 19:15:00 2000/-ko/ +/font.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/macmodes.h/1.5/Thu Jun 28 05:21:16 2001/-ko/ +/newport.h/1.2/Wed May 2 06:22:13 2001/-ko/ +/s3blit.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/sbusfb.h/1.4/Wed Dec 29 19:17:52 1999/-ko/ +D diff -rNu linux-2.4.7/linux/include/video/CVS/Repository linux-2.4-xfs/linux/include/video/CVS/Repository --- linux-2.4.7/linux/include/video/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/video/CVS/Repository Thu Jul 5 12:06:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/include/video diff -rNu linux-2.4.7/linux/include/video/CVS/Root linux-2.4-xfs/linux/include/video/CVS/Root --- linux-2.4.7/linux/include/video/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/include/video/CVS/Root Thu Jul 5 12:06:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/init/CVS/Entries linux-2.4-xfs/linux/init/CVS/Entries --- linux-2.4.7/linux/init/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/init/CVS/Entries Thu Jul 5 12:06:59 2001 @@ -0,0 +1,3 @@ +/main.c/1.56/Thu Jul 5 06:13:42 2001/-ko/ +/version.c/1.3/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/init/CVS/Repository linux-2.4-xfs/linux/init/CVS/Repository --- linux-2.4.7/linux/init/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/init/CVS/Repository Thu Jul 5 12:06:58 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/init diff -rNu linux-2.4.7/linux/init/CVS/Root linux-2.4-xfs/linux/init/CVS/Root --- linux-2.4.7/linux/init/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/init/CVS/Root Thu Jul 5 12:06:58 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/init/main.c linux-2.4-xfs/linux/init/main.c --- linux-2.4.7/linux/init/main.c Thu Jul 5 10:49:39 2001 +++ linux-2.4-xfs/linux/init/main.c Thu Jul 5 01:13:42 2001 @@ -70,6 +70,10 @@ #include #endif +#if defined(CONFIG_KDB) +#include +#endif + /* * Versions of gcc older than that listed below may actually compile * and link okay, but the end product can have subtle run time bugs. @@ -441,6 +445,34 @@ } if (next != NULL) *next++ = 0; +#if defined(CONFIG_KDB) + /* kdb, kdb=on, kdb=off, kdb=early */ + if (strncmp(line, "kdb", 3) == 0) { + if (line[3] == '\0') { + /* Backward compatibility, kdb with no option means early activation */ + printk("Boot flag kdb with no options is obsolete, use kdb=early\n"); + kdb_on = 1; + kdb_flags |= KDB_FLAG_EARLYKDB; + continue; + } + if (line[3] == '=') { + if (strcmp(line+4, "on") == 0) { + kdb_on = 1; + continue; + } + if (strcmp(line+4, "off") == 0) { + kdb_on = 0; + continue; + } + if (strcmp(line+4, "early") == 0) { + kdb_on = 1; + kdb_flags |= KDB_FLAG_EARLYKDB; + continue; + } + printk("Boot flag %s not recognised, assumed to be environment variable\n", line); + } + } +#endif if (!strncmp(line,"init=",5)) { line += 5; execute_command = line; @@ -573,6 +605,12 @@ #endif mem_init(); kmem_cache_sizes_init(); +#if defined(CONFIG_KDB) + kdb_init(); + if (KDB_FLAG(EARLYKDB)) { + KDB_ENTER(); + } +#endif mempages = num_physpages; fork_init(mempages); diff -rNu linux-2.4.7/linux/ipc/CVS/Entries linux-2.4-xfs/linux/ipc/CVS/Entries --- linux-2.4.7/linux/ipc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/ipc/CVS/Entries Thu Jul 5 12:06:59 2001 @@ -0,0 +1,7 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/msg.c/1.11/Thu Feb 22 21:09:04 2001/-ko/ +/sem.c/1.14/Thu Feb 22 21:09:04 2001/-ko/ +/shm.c/1.48/Tue May 29 19:53:13 2001/-ko/ +/util.c/1.18/Thu Feb 22 21:09:04 2001/-ko/ +/util.h/1.7/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/ipc/CVS/Repository linux-2.4-xfs/linux/ipc/CVS/Repository --- linux-2.4.7/linux/ipc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/ipc/CVS/Repository Thu Jul 5 12:06:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/ipc diff -rNu linux-2.4.7/linux/ipc/CVS/Root linux-2.4-xfs/linux/ipc/CVS/Root --- linux-2.4.7/linux/ipc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/ipc/CVS/Root Thu Jul 5 12:06:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/kdb/CVS/Entries linux-2.4-xfs/linux/kdb/CVS/Entries --- linux-2.4.7/linux/kdb/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/CVS/Entries Thu Jul 5 12:07:01 2001 @@ -0,0 +1,10 @@ +/ChangeLog/1.6/Tue Feb 27 05:07:04 2001/-ko/ +/Makefile/1.9/Thu Dec 21 21:12:17 2000/-ko/ +/kdb_bp.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/kdb_bt.c/1.8/Sat Nov 25 17:31:48 2000/-ko/ +/kdb_cmds/1.2/Wed Oct 4 11:42:46 2000/-ko/ +/kdb_id.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +/kdb_io.c/1.7/Sat Nov 25 08:05:45 2000/-ko/ +/kdbmain.c/1.19/Mon Apr 2 17:13:32 2001/-ko/ +/kdbsupport.c/1.10/Mon Apr 2 17:13:32 2001/-ko/ +D diff -rNu linux-2.4.7/linux/kdb/CVS/Entries.Log linux-2.4-xfs/linux/kdb/CVS/Entries.Log --- linux-2.4.7/linux/kdb/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/CVS/Entries.Log Thu Jul 5 12:07:01 2001 @@ -0,0 +1 @@ +A D/modules//// diff -rNu linux-2.4.7/linux/kdb/CVS/Repository linux-2.4-xfs/linux/kdb/CVS/Repository --- linux-2.4.7/linux/kdb/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/CVS/Repository Thu Jul 5 12:06:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/kdb diff -rNu linux-2.4.7/linux/kdb/CVS/Root linux-2.4-xfs/linux/kdb/CVS/Root --- linux-2.4.7/linux/kdb/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/CVS/Root Thu Jul 5 12:06:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/kdb/ChangeLog linux-2.4-xfs/linux/kdb/ChangeLog --- linux-2.4.7/linux/kdb/ChangeLog Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/ChangeLog Mon Feb 26 23:07:04 2001 @@ -0,0 +1,343 @@ +2001-02-27 Keith Owens + + * Update kdb v1.8 to kernel 2.4.2, sync kdb/modules with XFS. + + * Hook into panic() call. + +2000-12-18 Keith Owens + + * Update kdb v1.7 to kernel 2.4.0-test13-pre3, sync kdb/modules with + XFS. + +2000-11-18 Keith Owens + + * Update to kernel 2.4.0-test11-pre7, including forward port of + bug fixes from WIP 2.4.0-test9 tree. + + * Update to Cygnus CVS trees for disassembly code. + + * Bump to kdb v1.6. + +2000-10-19 Keith Owens + + * Update to kernel 2.4.0-test10-pre4. + +2000-10-15 Keith Owens + + * kdb/kdbmain.c (kdb_parse): Correctly handle blank input. + + * kdb/kdbmain.c (kdb_local, kdb): Reason SILENT can have NULL ef. + +2000-10-13 Keith Owens + + * kdb/kdbmain.c: Reduce CMD_LEN to avoid overflowing kdb_printf buffer. + +2000-10-11 Keith Owens + + * kdb/kdbmain.c (kdb): Test for userspace breakpoints before driving + other cpus into kdb. Speeds up gdb and avoids SMP race. + + * arch/i386/kdb/kdba_io.c (get_serial_char, get_kbd_char): Ignore + unprintable characters. + + * arch/i386/kdb/kdba_io.c (kdba_read): Better handling of buffer size. + +2000-10-04 Keith Owens + + * arch/i386/kdb/kdba_bt.c (kdba_bt_process): Verify that esp is inside + task_struct. Original patch by Mike Galbraith. + + * kdb/kdb_io.c (kdb_getstr): Reset output line counter, remove + unnecessary prompts. + + * arch/i386/kdb/kdbasupport.c (kdb_getregcontents): Change " cs" to + "xcs", ditto ss, ds, es. gdb2kdb does not like leading spaces. + + * include/asm-xxx/kdb.h: Add dummy kdb.h for all architectures except + ix86. This allows #include to appear in arch independent + code without causing compile errors. + + * kdb/modules/kdbm_pg: Sync with XFS. + +2000-10-03 Keith Owens + + * kdb/kdb_io.c (kdb_read): Ignore NMI while waiting for input. + + * kdb/kdb_io.c, kdb/Makefile: Export kdb_read. + +2000-10-02 Keith Owens + + * arch/i386/kernel/smpboot.c (do_boot_cpu): Set nmi_watchdog_source to 2 + to avoid premature NMI oops during cpu bring up. We have to assume that + a box with more than 1 cpu has a working IO-APIC. + + * Documentation/kdb/{kdb.mm,kdb_md.man}: Add mdr command. + + * kdb/kdbmain.c (kdb_md): Add mdr command. + + * Release as kdb v1.5 against 2.4.0-test9-pre8. + + * arch/i386/kdb/kdba_io.c, arch/i386/kdb/kdbasupport.c, kdb/kdbmain.c, + kdb/kdb_io.c, kdb/kdb_id.c: Remove zero initializers for static + variables. + +2000-09-28 Keith Owens + + * various: Add nmi_watchdog_source, 1 local APIC, 2 IO-APIC. + Test nmi_watchdog_source instead of nr_ioapics so UP works on SMP hardware. + + * arch/i386/kernel/io_apic.c: Rename setup_nmi to setup_nmi_io for clarity. + + * kdb/kdbmain.c (kdb_parse): Only set NO_WATCHDOG if it was already set. + + * kdb/kdbmain.c (kdb): Clear NO_WATCHDOG on all exit paths. + + * include/linux/kdb.h: Add KDB_REASON_SILENT. + + * kdb/kdbmain.c (kdb_local): Treat reason SILENT as immediate 'go'. + + * kdb/kdbmain.c (kdb_init): Invoke kdb with reason SILENT to instantiate + any breakpoints on boot cpu. + + * arch/i386/kernel/smpboot.c (smp_callin): Invoke kdb with reason SILENT + to instantiate any global breakpoints on this cpu. + + * kdb/kdb_cmds: Remove comment that said initial commands only worked on + boot cpu. + +2000-09-27 Keith Owens + + * arch/i386/kernel/msr.c: Move {rd,wr}msr_eio to include/asm-i386/apic.h. + + * include/asm-i386/apic.h: Define NMI interfaces. + + * kernel/sysctl.c (kern_table): + * kernel/sysctl.c (do_proc_set_nmi_watchdog): + Add /proc/sys/kernel/nmi_watchdog. + + * arch/i386/kernel/apic.c: New routines set_nmi_counter_local, + setup_apic_nmi_watchdog. + + * arch/i386/kernel/traps.c: New routine set_nmi_watchdog(). Call apic + routines to set/clear local apic timer. + +2000-09-26 Keith Owens + + * include/linux/sysctl.h (enum): Add NMI_WATCHDOG. + + * arch/i386/kernel/traps.c (nmi_watchdog_tick): Check nmi_watchdog is + still on. + + * arch/i386/config.in: Add CONFIG_UP_NMI_WATCHDOG. + + * Documentation/Configure.help: Add CONFIG_UP_NMI_WATCHDOG. + + * Documentation/nmi_watchdog.txt: Update for UP NMI watchdog. + +2000-09-25 Keith Owens + + * arch/i386/kernel/apic.c (init_apic_mappings): + * arch/i386/kernel/io_apic.c (IO_APIC_init_uniprocessor): + Merge Keir Fraser's local APIC for uniprocessors patch. + +2000-09-24 Keith Owens + + * Various: Declare initialization routines as __init. + + * Makefile: Define and export AWK. + + * kdb/Makefile: Generate gen-kdb_cmds.c from kdb/kdb_cmds. + + * kdb/kdbmain.c (kdb_init): Call new routine kdb_cmds_init to execute + whatever the user put in kdb/kdb_cmds. + + * arch/i386/kdb/kdba_bt.c (kdba_bt_stack): New parameter to + indicate if esp in regs is known to be valid or not. + + * kdb/kdb_bp.c, arch/i386/kdb/kdba_bp.c: More trace prints for + breakpoint handling. + + * arch/i386/kdb/kdba_bp.c (kdba_installbp): Finally found and fixed the + annoying breakpoint bug where breakpoints where not always installed + after 'go'. + + * Documentation/kdb: Update man pages kdb.mm, kdb_env.man, kdb_ss.man. + + * Released as kdb-v1.5-beta1-2.4.0-test8. + + * Sync to 2.4.0-test9-pre6 and release as kdb-v1.5-beta1-2.4.0-test9-pre6. + +2000-09-23 Keith Owens + + * arch/i386/kdb/kdbasupport.c (kdba_getregcontents): New pseudo + registers cesp and ceflags to help with debugging the debugger. + + * kdb/kdbmain.c (kdb_local, kdb): Add KDB_REASON_RECURSE. Add + environment variable RECURSE. Add code to cope with some types of + recursion. + + * kdb/kdbmain.c (kdb), arch/i386/kdba/kdba_bp.c: Add + kdba_clearsinglestep. + +2000-09-22 Keith Owens + + * drivers/video/vgacon.c (write_vga): No cli() if kdb is running, avoid + console deadlock. + + * arch/i386/kernel/irq.c (get_irqlock): Warn if kdb is running, may hang. + + * include/linux/kdb.h: Define KDB_IS_RUNNING as (0) if no CONFIG_KDB. + + * arch/i386/kdb/kdba_bt.c (kdba_bt_stack): Do not attempt a backtrace if + the code segment is not in the kernel. + + * kdb/modules: Change modules from MX_OBJS to M_OBJS. Remove EXPORT_NOSYMBOLS. + +2000-09-21 Keith Owens + + * arch/i386/kernel/i386_ksyms.c: Move EXPORT_SYMBOLS for kdb to kdb/kdbmain.c. + + * kdb/Makefile: Change kdb/kdbmain.o from O_OBJS to OX_OBJS. + + * arch/i386/kernel/smp.c: Remove some #ifdef CONFIG_KDB. Remove kdbprivate.h. + + * include/linux/kdb.h: Add kdb_print_state. Add KDB_STATE_WAIT_IPI. + + * kdb/kdbmain.c (kdb): Only mark cpu as leaving if it is in KDB state. Maintain + WAIT_IPI state so a cpu is only driven through NMI once. + + * arch/i386/kernel/smp.c (smp_kdb_stop): All state fiddling moved to kdb(). + +2000-09-20 Keith Owens + + * include/linux/kdb.h: #define kdb() as (0) if kdb is not configured. + + * arch/i386/kernel/traps.c: Remove some #ifdef CONFIG_KDB. + + * include/linux/kdbprivate.h: Move per cpu state to kdb.h. + + * include/linux/kdb.h: Add KDB_STATE_NO_WATCHDOG, KDB_STATE_PRINTF_LOCK. + Rename KDB_DEBUG_xxx to KDB_DEBUG_FLAG_xxx. Clean up debug flag + definitions. + + * arch/i386/kernel/traps.c (nmi_watchdog_tick): Check no watchdog. + + * kdb/kdbmain.c (kdb): Set no watchdog in normal kdb code. + + * kdb/kdbmain.c (kdb_parse): Allow watchdog in commands. + + * kdb/kdb_io.c (kdb_printf): No watchdog during printing. Clean up lock handling. + + * kdb/kdbmain.c (kdb_set): Clean up debug flag handling. + +2000-09-19 Juan J. Quintela + + * kdb/arch/i386/kdb/kdba_io.c: Allow kdb to compile without CONFIG_VT and/or + serial console. + +2000-09-19 Keith Owens + + * include/linux/kdb.h: Define KDB_DEBUG_STATE(). + + * kdb/kdbmain.c (kdb): Add kdb_print_state(), calls to KDB_DEBUG_STATE(). + +2000-09-16 Keith Owens + + * Move to finer grained control over individual processors in kdb with + per cpu kdb state. Needed to allow ss[b] to only release one processor, + previously ss[b] released all processors. Also need to recover from + errors inside kdb commands, e.g. oops in kdbm_pg code. + + * various: + Move global flags KDB_FLAG_SSB, KDB_FLAG_SUPRESS, KDB_FLAG_FAULT, + KDB_FLAG_SS, KDB_FLAG_SSBPT, kdb_active, to per cpu state and macros + KDB_STATE(xxx). + Replace kdb_flags & KDB_FLAG_xxx with KDB_FLAG(xxx). + Replace kdb_flags & KDB_DEBUG_xxx with KDB_DEBUG(xxx). + Replace specific tests with wrapper KDB_IS_RUNNING(). + + * various: Remove #ifdef CONFIG_SMP from kdb code wherever + possible. Simplifies the code and makes it much more readable. + + * arch/i386/kdb/kdbasupport.c (kdb_setjmp): Record if we have reliable + longjmp data instead of assuming it is always set. + + * various: Replace smp_kdb_wait with per cpu state, HOLD_CPU. + + * init/main.c : Replace #ifdef KDB_DEBUG with KDB_DEBUG(CALLBACK). + + * include/linux/kdbprivate.h: Separate command return codes from error + codes. Add more detailed command codes. + + * arch/i386/kernel/traps.c (die): Change spin_lock_irq to + spin_lock_irqsave. Why did I do this? + + * kdb/kdbmain.c (kdb_parse): Set per cpu flag CMD before executing kdb + command. More detailed return codes for commands that affect + processors. + + * kdb/kdbmain.c (kdb_previous_event): New, check if any processors are + still executing the previous kdb event. Removes a race window where a + second event could enter kdb before the first had completely ended. + + * kdb/kdbmain.c (kdb): Document all the concurrency conditions and how + kdb handles them. ss[b] now releases only the current cpu. Do not set + breakpoints when releasing for ss[b]. Recover from errors in kdb + commands. Check that we have reliable longjmp data before using it. + + * various: Update return code documentation. + + * kdb/kdb_bp.c (kdb_ss): Separate ss and ssb return codes. + + * kdb/kdbsupport.c (kdb_ipi): Finer grained algorithm for deciding + whether to call send a stop signal to a cpu. + + * arch/i386/kdb/kdba_bp.c (kdba_db_trap): Separate ss and ssb return + codes. Reinstall delayed software breakpoints per cpu instead of + globally. Changed algorithm for handling ss[b]. + + * arch/i386/kdb/kdba_bp.c (kdba_bp_trap): Match software breakpoints per + cpu instead of globally. + + * include/linux/kdb.h: Bump version to kdb v1.5. + +2000-09-16 Keith Owens + + * kernel/sysctl.c (kern_table): add /proc/sys/kernel/kdb. + + * init/main.c (parse_options): add boot flags kdb=on, kdb=off, + kdb=early. + + * include/linux/sysctl.h (enum): add KERN_KDB. + + * drivers/char/serial.c (receive_chars): check kdb_on. + + * drivers/char/keyboard.c (handle_scancode): check kdb_on. + + * arch/i386/kernel/traps.c (nmi_watchdog_tick): check kdb_on. + + * arch/i386/config.in: add CONFIG_KDB_OFF. + + * Documentation/Configure.help: add CONFIG_KDB_OFF. + + * kdb/kdbmain.c: add kdb_initial_cpu, kdb_on. + + * kdb/kdbmain.c (kdb): check kdb_on, set kdb_initial_cpu. + + * kdb/kdbmain.c (kdb_init): add Keith Owens to kdb banner. + + * kdb/kdb_io.c (kdb_printf): serialize kdb_printf output. + + * kdb/kdb_bt.c (kdb_bt): check environment variable BTAPROMPT. + + * kdb/kdbsupport.c (kdb_ipi): ignore NMI for kdb_initial_cpu. + + * kdb/modules/kdbm_pg.c (kdbm_page): merge updates from 2.4.0-test5-xfs. + + * kdb/kdb_bt.man: add btp, bta, BTAPROMPT. + + * kdb/kdb.mm: add CONFIG_KDB_OFF, boot flags, btp, bta. + + * include/linux/kdbprivate.h: add kdb_initial_cpu. + + * include/linux/kdb.h: add kdb_on, bump version to kdb v1.4. diff -rNu linux-2.4.7/linux/kdb/Makefile linux-2.4-xfs/linux/kdb/Makefile --- linux-2.4.7/linux/kdb/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/Makefile Thu Dec 21 15:12:17 2000 @@ -0,0 +1,17 @@ +O_TARGET := kdb.o +export-objs := kdbmain.o kdb_io.o +obj-y := kdb_bt.o kdb_bp.o kdb_id.o kdbsupport.o gen-kdb_cmds.o kdbmain.o kdb_io.o + +subdir-m := modules + +override CFLAGS := $(CFLAGS:%-pg=% ) + +include $(TOPDIR)/Rules.make + +gen-kdb_cmds.c: kdb_cmds Makefile + $(AWK) 'BEGIN {print "#include "} \ + /^ *#/{next} \ + /^[ \t]*$$/{next} \ + {print "static __initdata char kdb_cmd" cmds++ "[] = \"" $$0 "\\n\";"} \ + END {print "char __initdata *kdb_cmds[] = {"; for (i = 0; i < cmds; ++i) {print " kdb_cmd" i ","}; print(" 0\n};");}' \ + kdb_cmds > gen-kdb_cmds.c diff -rNu linux-2.4.7/linux/kdb/kdb_bp.c linux-2.4-xfs/linux/kdb/kdb_bp.c --- linux-2.4.7/linux/kdb/kdb_bp.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/kdb_bp.c Thu Feb 22 15:09:04 2001 @@ -0,0 +1,622 @@ +/* + * Kernel Debugger Breakpoint Handler + * + * Copyright 1999, Silicon Graphics, Inc. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Keith Owens 2000/05/23 + * KDB v1.2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Table of kdb_breakpoints + */ +kdb_bp_t kdb_breakpoints[KDB_MAXBPT]; + +/* + * kdb_bp_install_global + * + * Install global kdb_breakpoints prior to returning from the + * kernel debugger. This allows the kdb_breakpoints to be set + * upon functions that are used internally by kdb, such as + * printk(). + * + * Parameters: + * ef Execution frame. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * + * This function is only called once per kdb session. + */ + +void +kdb_bp_install_global(kdb_eframe_t ef) +{ + int i; + + for(i=0; ibp_forcehw) { + kdb_printf("Forced "); + } + + if (!bp->bp_template.bph_free) { + kdb_printf("%s ", kdba_bptype(&bp->bp_template)); + } else { + kdb_printf("Instruction(i) "); + } + + kdb_printf("BP #%d at ", i); + kdb_symbol_print(bp->bp_addr, NULL, KDB_SP_DEFAULT); + + if (bp->bp_enabled) { + kdba_printbp(bp); + if (bp->bp_global) + kdb_printf(" globally"); + else + kdb_printf(" on cpu %d", bp->bp_cpu); + if (bp->bp_adjust) + kdb_printf(" adjust %d", bp->bp_adjust); + } else { + kdb_printf("\n is disabled"); + } + + kdb_printf("\n"); +} + +/* + * kdb_bp + * + * Handle the bp, and bpa commands. + * + * [bp|bpa|bph] [DATAR|DATAW|IO [length]] + * + * Parameters: + * argc Count of arguments in argv + * argv Space delimited command line arguments + * envp Environment value + * regs Exception frame at entry to kernel debugger + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic if failure. + * Locking: + * None. + * Remarks: + * + * bp Set breakpoint. Only use hardware assist if necessary. + * bpa Set breakpoint on all cpus, only use hardware regs if necessary + * bph Set breakpoint - force hardware register + * bpha Set breakpoint on all cpus, force hardware register + */ + +int +kdb_bp(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + kdb_bp_t *bp; + int diag; + int free, same; + kdb_machreg_t addr; + char *symname = NULL; + long offset = 0ul; + int nextarg; + int hardware; + int global; + + if (argc == 0) { + /* + * Display breakpoint table + */ + for(i=0,bp=kdb_breakpoints; ibp_free) continue; + + kdb_printbp(bp, i); + } + + return 0; + } + + global = ((strcmp(argv[0], "bpa") == 0) + || (strcmp(argv[0], "bpha") == 0)); + hardware = ((strcmp(argv[0], "bph") == 0) + || (strcmp(argv[0], "bpha") == 0)); + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, &symname, regs); + if (diag) + return diag; + + /* + * Allocate a new bp structure + */ + free = same = KDB_MAXBPT; + for(i=0,bp=kdb_breakpoints; ibp_free) { + break; + } + } + + if (i == KDB_MAXBPT) + return KDB_TOOMANYBPT; + + kdba_check_pc(&addr); + bp->bp_addr = addr; + bp->bp_adjust = 0; + + bp->bp_forcehw = hardware; + if (KDB_DEBUG(BP)) + kdb_printf("kdb_bp: forcehw is %d hardware is %d\n", bp->bp_forcehw, hardware); + + /* + * Handle architecture dependent parsing + */ + diag = kdba_parsebp(argc, argv, &nextarg, bp); + if (diag) { + return diag; + } + + bp->bp_enabled = 1; + bp->bp_free = 0; + bp->bp_global = 1; /* Most breakpoints are global */ + + if (hardware && !global) { + bp->bp_global = 0; + bp->bp_cpu = smp_processor_id(); + } + + /* + * Allocate a hardware breakpoint. If one is not available, + * disable the breakpoint, but leave it in the breakpoint + * table. When the breakpoint is re-enabled (via 'be'), we'll + * attempt to allocate a hardware register for it. + */ + if (!bp->bp_template.bph_free) { + bp->bp_hard = kdba_allocbp(&bp->bp_template, &diag); + if (diag) { + bp->bp_enabled = 0; + return diag; + } + bp->bp_hardtype = 1; + } + + kdb_printbp(bp, i); + + return 0; +} + +/* + * kdb_bc + * + * Handles the 'bc', 'be', and 'bd' commands + * + * [bd|bc|be] + * + * Parameters: + * argc Count of arguments in argv + * argv Space delimited command line arguments + * envp Environment value + * regs Exception frame at entry to kernel debugger + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic for failure + * Locking: + * None. + * Remarks: + */ + +#define KDBCMD_BC 0 +#define KDBCMD_BE 1 +#define KDBCMD_BD 2 + +int +kdb_bc(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + kdb_machreg_t addr; + kdb_bp_t *bp = 0; + int lowbp = KDB_MAXBPT; + int highbp = 0; + int done = 0; + int i; + int diag; + int cmd; /* KDBCMD_B? */ + + if (strcmp(argv[0], "be") == 0) { + cmd = KDBCMD_BE; + } else if (strcmp(argv[0], "bd") == 0) { + cmd = KDBCMD_BD; + } else + cmd = KDBCMD_BC; + + if (argc != 1) + return KDB_ARGCOUNT; + + if (strcmp(argv[1], "*") == 0) { + lowbp = 0; + highbp = KDB_MAXBPT; + } else { + diag = kdbgetularg(argv[1], &addr); + if (diag) + return diag; + + /* + * For addresses less than the maximum breakpoint number, + * assume that the breakpoint number is desired. + */ + if (addr < KDB_MAXBPT) { + bp = &kdb_breakpoints[addr]; + lowbp = highbp = addr; + highbp++; + } else { + for(i=0, bp=kdb_breakpoints; ibp_addr == addr) { + lowbp = highbp = i; + highbp++; + break; + } + } + } + } + + /* + * Now operate on the set of breakpoints matching the input + * criteria (either '*' for all, or an individual breakpoint). + */ + for(bp=&kdb_breakpoints[lowbp], i=lowbp; + i < highbp; + i++, bp++) { + if (bp->bp_free) + continue; + + done++; + + switch (cmd) { + case KDBCMD_BC: + if (bp->bp_hardtype) { + kdba_freebp(bp->bp_hard); + bp->bp_hard = 0; + bp->bp_hardtype = 0; + } + + bp->bp_enabled = 0; + bp->bp_global = 0; + + kdb_printf("Breakpoint %d at " kdb_bfd_vma_fmt " cleared\n", + i, bp->bp_addr); + + bp->bp_addr = 0; + bp->bp_free = 1; + + break; + case KDBCMD_BE: + /* + * Allocate a hardware breakpoint. If one is not + * available, don't enable the breakpoint. + */ + if (!bp->bp_template.bph_free + && !bp->bp_hardtype) { + bp->bp_hard = kdba_allocbp(&bp->bp_template, &diag); + if (diag) { + bp->bp_enabled = 0; + return diag; + } + bp->bp_hardtype = 1; + } + + bp->bp_enabled = 1; + + kdb_printf("Breakpoint %d at " kdb_bfd_vma_fmt " in enabled", + i, bp->bp_addr); + + kdb_printf("\n"); + break; + case KDBCMD_BD: + if (!bp->bp_enabled) { + return 0; + } + + /* + * Since this breakpoint is now disabled, we can + * give up the hardware register which is allocated + * to it. + */ + if (bp->bp_hardtype) { + kdba_freebp(bp->bp_hard); + bp->bp_hard = 0; + bp->bp_hardtype = 0; + } + + bp->bp_enabled = 0; + + kdb_printf("Breakpoint %d at " kdb_bfd_vma_fmt " disabled\n", + i, bp->bp_addr); + + break; + } + } + + return (!done)?KDB_BPTNOTFOUND:0; +} + +/* + * kdb_ss + * + * Process the 'ss' (Single Step) and 'ssb' (Single Step to Branch) + * commands. + * + * ss [] + * ssb + * + * Parameters: + * argc Argument count + * argv Argument vector + * envp Environment vector + * regs Registers at time of entry to kernel debugger + * Outputs: + * None. + * Returns: + * KDB_CMD_SS[B] for success, a kdb error if failure. + * Locking: + * None. + * Remarks: + * + * Set the arch specific option to trigger a debug trap after the next + * instruction. + * + * For 'ssb', set the trace flag in the debug trap handler + * after printing the current insn and return directly without + * invoking the kdb command processor, until a branch instruction + * is encountered or SSCOUNT lines are printed. + */ + +int +kdb_ss(int argc, const char **argv, const char **envp, kdb_eframe_t ef) +{ + int ssb = 0; + + ssb = (strcmp(argv[0], "ssb") == 0); + if ((ssb && (argc != 0)) + || (!ssb && (argc > 1))) { + return KDB_ARGCOUNT; + } + +#if 0 + /* + * Fetch provided count + */ + diag = kdbgetularg(argv[1], &sscount); + if (diag) + return diag; +#endif + + /* + * Set trace flag and go. + */ + KDB_STATE_SET(DOING_SS); + if (ssb) + KDB_STATE_SET(DOING_SSB); + + kdba_setsinglestep(ef); /* Enable single step */ + + if (ssb) + return KDB_CMD_SSB; + return KDB_CMD_SS; +} + +/* + * kdb_initbptab + * + * Initialize the breakpoint table. Register breakpoint commands. + * + * Parameters: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + */ + +void __init +kdb_initbptab(void) +{ + int i; + kdb_bp_t *bp; + + /* + * First time initialization. + */ + memset(&kdb_breakpoints, '\0', sizeof(kdb_breakpoints)); + + for (i=0, bp=kdb_breakpoints; ibp_free = 1; + /* + * The bph_free flag is architecturally required. It + * is set by architecture-dependent code to false (zero) + * in the event a hardware breakpoint register is required + * for this breakpoint. + * + * The rest of the template is reserved to the architecture + * dependent code and _must_ not be touched by the architecture + * independent code. + */ + bp->bp_template.bph_free = 1; + } + + kdb_register("bp", kdb_bp, "[]", "Set/Display breakpoints", 0); + kdb_register("bl", kdb_bp, "[]", "Display breakpoints", 0); + kdb_register("bpa", kdb_bp, "[]", "Set/Display global breakpoints", 0); + kdb_register("bph", kdb_bp, "[]", "Set hardware breakpoint", 0); + kdb_register("bpha", kdb_bp, "[]", "Set global hardware breakpoint", 0); + kdb_register("bc", kdb_bc, "", "Clear Breakpoint", 0); + kdb_register("be", kdb_bc, "", "Enable Breakpoint", 0); + kdb_register("bd", kdb_bc, "", "Disable Breakpoint", 0); + + kdb_register("ss", kdb_ss, "[<#steps>]", "Single Step", 1); + kdb_register("ssb", kdb_ss, "", "Single step to branch/call", 0); + /* + * Architecture dependent initialization. + */ + kdba_initbp(); +} + diff -rNu linux-2.4.7/linux/kdb/kdb_bt.c linux-2.4-xfs/linux/kdb/kdb_bt.c --- linux-2.4.7/linux/kdb/kdb_bt.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/kdb_bt.c Sat Nov 25 11:31:48 2000 @@ -0,0 +1,138 @@ +/* + * Minimalist Kernel Debugger - Architecture independent stack traceback + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * + * See the file LIA-COPYRIGHT for additional information. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Richard Bass 1999/07/20 + * Many bug fixes and enhancements. + * Scott Foehner + * Port to ia64 + * Srinivasa Thirumalachar + * RSE support for ia64 + * Masahiro Adegawa 1999/12/01 + * 'sr' command, active flag in 'ps' + * Scott Lurndal 1999/12/12 + * Significantly restructure for linux2.3 + * Keith Owens 2000/05/23 + * KDB v1.2 + * Keith Owens 2000/09/16 + * KDB v1.4 + * Env BTAPROMPT. + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +/* + * kdb_bt + * + * This function implements the 'bt' command. Print a stack + * traceback. + * + * bt [] (addr-exp is for alternate stacks) + * btp (Kernel stack for ) + * + * address expression refers to a return address on the stack. It + * is expected to be preceeded by a frame pointer. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * ef registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Backtrack works best when the code uses frame pointers. But + * even without frame pointers we should get a reasonable trace. + * + * mds comes in handy when examining the stack to do a manual + * traceback. + */ + +int +kdb_bt(int argc, const char **argv, const char **envp, kdb_eframe_t ef) +{ + int diag; + int argcount = 5; + int btaprompt = 1; + char buffer[80]; + int nextarg; + unsigned long addr; + long offset; + + kdbgetintenv("BTARGS", &argcount); /* Arguments to print */ + kdbgetintenv("BTAPROMPT", &btaprompt); /* Prompt after each proc in bta */ + + if (strcmp(argv[0], "bta") == 0) { + struct task_struct *p; + + for_each_task(p) { + kdb_printf("Stack traceback for pid %d\n", p->pid); + + diag = kdba_bt_process(p, argcount); + + if (btaprompt) { + kdb_getstr(buffer, sizeof(buffer), + "Enter to end, to continue:"); + + if (buffer[0] == 'q') { + return 0; + } + } + } + } else if (strcmp(argv[0], "btp") == 0) { + struct task_struct *p; + int pid; + + if (argc < 1) + return KDB_ARGCOUNT; + + diag = kdbgetularg((char *)argv[1], (unsigned long*)&pid); + if (diag) + return diag; + + for_each_task(p) { + if (p->pid == pid) { + return kdba_bt_process(p, argcount); + } + } + + kdb_printf("No process with pid == %d found\n", pid); + return 0; + } else { + if (argc) { + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, + &offset, NULL, ef); + if (diag) + return diag; + + return kdba_bt_stack(ef, &addr, argcount, current); + } else { + return kdba_bt_stack(ef, NULL, argcount, current); + } + } + + /* NOTREACHED */ + return 0; +} diff -rNu linux-2.4.7/linux/kdb/kdb_cmds linux-2.4-xfs/linux/kdb/kdb_cmds --- linux-2.4.7/linux/kdb/kdb_cmds Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/kdb_cmds Wed Oct 4 06:42:46 2000 @@ -0,0 +1,6 @@ +# Initial commands for kdb, alter to suit your needs. +# These commands are executed in kdb_init() context, no SMP, no +# processes. Commands that require process data (including stack or +# registers) are not reliable this early. set and bp commands should +# be safe. Global breakpoint commands affect each cpu as it is booted. + diff -rNu linux-2.4.7/linux/kdb/kdb_id.c linux-2.4-xfs/linux/kdb/kdb_id.c --- linux-2.4.7/linux/kdb/kdb_id.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/kdb_id.c Thu Feb 22 15:09:04 2001 @@ -0,0 +1,252 @@ +/* + * Minimalist Kernel Debugger - Architecture Independent Instruction Disassembly + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * + * See the file LIA-COPYRIGHT for additional information. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Richard Bass 1999/07/20 + * Many bug fixes and enhancements. + * Scott Foehner + * Port to ia64 + * Srinivasa Thirumalachar + * RSE support for ia64 + * Masahiro Adegawa 1999/12/01 + * 'sr' command, active flag in 'ps' + * Scott Lurndal 1999/12/12 + * Significantly restructure for linux2.3 + * Keith Owens 2000/05/23 + * KDB v1.2 + * + */ + +#include +#include +#include +#include +#include +#include +#include + +disassemble_info kdb_di; + +/* + * kdb_id + * + * Handle the id (instruction display) command. + * + * id [] + * + * Parameters: + * argc Count of arguments in argv + * argv Space delimited command line arguments + * envp Environment value + * regs Exception frame at entry to kernel debugger + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic if failure. + * Locking: + * None. + * Remarks: + */ + +int +kdb_id(int argc, const char **argv, const char **envp, struct pt_regs* regs) +{ + kdb_machreg_t pc; + int icount; + int diag; + int i; + char * mode; + int nextarg; + long offset = 0; + static kdb_machreg_t lastpc; + struct disassemble_info *dip = &kdb_di; + + if (argc != 1) { + if (lastpc == 0) { + return KDB_ARGCOUNT; + } else { + char lastbuf[50]; + sprintf(lastbuf, "0x%lx", lastpc); + argv[1] = lastbuf; + argc = 1; + } + } + + + /* + * Fetch PC. First, check to see if it is a symbol, if not, + * try address. + */ + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &pc, &offset, NULL, regs); + if (diag) + return diag; + kdba_check_pc(&pc); + + /* + * Number of lines to display + */ + diag = kdbgetintenv("IDCOUNT", &icount); + if (diag) + return diag; + + mode = kdbgetenv("IDMODE"); + diag = kdba_id_parsemode(mode, dip); + if (diag) { + return diag; + } + + for(i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct console *kdbcons; + +/* + * kdb_read + * + * This function reads a string of characters, terminated by + * a newline, or by reaching the end of the supplied buffer, + * from the current kernel debugger console device. + * Parameters: + * buffer - Address of character buffer to receive input characters. + * bufsize - size, in bytes, of the character buffer + * Returns: + * Returns a pointer to the buffer containing the received + * character string. This string will be terminated by a + * newline character. + * Locking: + * No locks are required to be held upon entry to this + * function. It is not reentrant - it relies on the fact + * that while kdb is running on any one processor all other + * processors will be spinning at the kdb barrier. + * Remarks: + * + * Davidm asks, why doesn't kdb use the console abstraction; + * here are some reasons: + * - you cannot debug the console abstraction with kdb if + * kdb uses it. + * - you rely on the correct functioning of the abstraction + * in the presence of general system failures. + * - You must acquire the console spinlock thus restricting + * the usability - what if the kernel fails with the spinlock + * held - one still wishes to debug such situations. + * - How about debugging before the console(s) are registered? + * - None of the current consoles (sercons, vt_console_driver) + * have read functions defined. + * - The standard pc keyboard and terminal drivers are interrupt + * driven. We cannot enable interrupts while kdb is active, + * so the standard input functions cannot be used by kdb. + * + * An implementation could be improved by removing the need for + * lock acquisition - just keep a 'struct console *kdbconsole;' global + * variable which refers to the preferred kdb console. + * + * The bulk of this function is architecture dependent. + */ + +char * +kdb_read(char *buffer, size_t bufsize) +{ + int no_watchdog; + char *ret; + no_watchdog = KDB_STATE(NO_WATCHDOG); + KDB_STATE_SET(NO_WATCHDOG); + ret = kdba_read(buffer, bufsize); + if (!no_watchdog) + KDB_STATE_CLEAR(NO_WATCHDOG); + return(ret); +} + +/* + * kdb_getstr + * + * Print the prompt string and read a command from the + * input device. + * + * Parameters: + * buffer Address of buffer to receive command + * bufsize Size of buffer in bytes + * prompt Pointer to string to use as prompt string + * Returns: + * Pointer to command buffer. + * Locking: + * None. + * Remarks: + * For SMP kernels, the processor number will be + * substituted for %d, %x or %o in the prompt. + */ + +char * +kdb_getstr(char *buffer, size_t bufsize, char *prompt) +{ +#if defined(CONFIG_SMP) + kdb_printf(prompt, smp_processor_id()); +#else + kdb_printf("%s", prompt); +#endif + kdb_nextline = 1; /* Prompt and input resets line number */ + return kdb_read(buffer, bufsize); +} + +/* + * kdb_printf + * + * Print a string to the output device(s). + * + * Parameters: + * printf-like format and optional args. + * Returns: + * 0 + * Locking: + * None. + * Remarks: + * use 'kdbcons->write()' to avoid polluting 'log_buf' with + * kdb output. + */ + +void +kdb_printf(const char *fmt, ...) +{ + char buffer[256]; + va_list ap; + int diag; + int linecount; + int logging, saved_loglevel = 0; + int no_watchdog, do_longjmp = 0; + struct console *c = console_drivers; + static spinlock_t kdb_printf_lock = SPIN_LOCK_UNLOCKED; + + /* Output is slow, especially over serial lines or while waiting + * for user response. No watchdogs wanted. + */ + no_watchdog = KDB_STATE(NO_WATCHDOG); + KDB_STATE_SET(NO_WATCHDOG); + + /* Serialize kdb_printf if multiple cpus try to write at once. + * But if any cpu goes recursive in kdb, just print the output, + * even if it is interleaved with any other text. + */ + if (!KDB_STATE(PRINTF_LOCK)) { + KDB_STATE_SET(PRINTF_LOCK); + spin_lock(&kdb_printf_lock); + } + + diag = kdbgetintenv("LINES", &linecount); + if (diag) + linecount = 22; + + diag = kdbgetintenv("LOGGING", &logging); + if (diag) + logging = 0; + + va_start(ap, fmt); + vsprintf(buffer, fmt, ap); + va_end(ap); + + /* + * Write to all consoles. + */ + while (c) { + c->write(c, buffer, strlen(buffer)); + c = c->next; + } + if (logging) { + spin_lock_irq(&console_lock); + saved_loglevel = console_loglevel; + console_loglevel = 0; + spin_unlock_irq(&console_lock); + printk("%s", buffer); + } + + if (strchr(buffer, '\n') != NULL) { + kdb_nextline++; + } + + if (kdb_nextline == linecount) { +#ifdef KDB_HAVE_LONGJMP + char buf1[16]; +#if defined(CONFIG_SMP) + char buf2[32]; +#endif + char *moreprompt; + + /* Watch out for recursion here. Any routine that calls + * kdb_printf will come back through here. And kdb_read + * uses kdb_printf to echo on serial consoles ... + */ + kdb_nextline = 1; /* In case of recursion */ + + /* + * Pause until cr. + */ + moreprompt = kdbgetenv("MOREPROMPT"); + if (moreprompt == NULL) { + moreprompt = "more> "; + } + +#if defined(CONFIG_SMP) + if (strchr(moreprompt, '%')) { + sprintf(buf2, moreprompt, smp_processor_id()); + moreprompt = buf2; + } +#endif + + c = console_drivers; + while (c) { + c->write(c, moreprompt, strlen(moreprompt)); + c = c->next; + } + if (logging) + printk("%s", moreprompt); + + kdb_read(buf1, sizeof(buf1)); + kdb_nextline = 1; /* Really set output line 1 */ + + if ((buf1[0] == 'q') + || (buf1[0] == 'Q')) { + do_longjmp = 1; + } +#endif /* KDB_HAVE_LONGJMP */ + } + + if (logging) { + spin_lock_irq(&console_lock); + console_loglevel = saved_loglevel; + spin_unlock_irq(&console_lock); + } + if (!no_watchdog) + KDB_STATE_CLEAR(NO_WATCHDOG); + if (KDB_STATE(PRINTF_LOCK)) { + spin_unlock(&kdb_printf_lock); + KDB_STATE_CLEAR(PRINTF_LOCK); + } + if (do_longjmp) +#ifdef KDB_HAVE_LONGJMP + kdb_longjmp(&kdbjmpbuf[smp_processor_id()], 1); +#else + ; +#endif /* KDB_HAVE_LONGJMP */ +} + +/* + * kdb_io_init + * + * Initialize kernel debugger output environment. + * + * Parameters: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * Select a console device. + */ + +void __init +kdb_io_init(void) +{ + /* + * Select a console. + */ + struct console *c = console_drivers; + + while (c) { + if ((c->flags & CON_CONSDEV)) { + kdbcons = c; + break; + } + c = c->next; + } + + if (kdbcons == NULL) { + long long i; + + printk("kdb: Initialization failed - no console\n"); + while (1) i++; + } + return; +} + +EXPORT_SYMBOL(kdb_read); diff -rNu linux-2.4.7/linux/kdb/kdbmain.c linux-2.4-xfs/linux/kdb/kdbmain.c --- linux-2.4.7/linux/kdb/kdbmain.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/kdbmain.c Mon Apr 2 12:13:32 2001 @@ -0,0 +1,2791 @@ +/* + * Minimalist Kernel Debugger + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * Copyright (C) 2000 Stephane Eranian + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Richard Bass 1999/07/20 + * Many bug fixes and enhancements. + * Scott Foehner + * Port to ia64 + * Srinivasa Thirumalachar + * RSE support for ia64 + * Masahiro Adegawa 1999/12/01 + * 'sr' command, active flag in 'ps' + * Scott Lurndal 1999/12/12 + * Significantly restructure for linux2.3 + * Keith Owens 2000/05/23 + * KDB v1.2 + * Keith Owens 2000/06/09 + * KDB v1.3. + * Rewrite SMP handling. + * Add NMI watchdog from Ted Kline, + * lsmod/rmmod commands from Marc Esipovich + * Stephane Eranian 2000/06/05 + * Enabled disassembler support. Added command history support. + * + * Keith Owens 2000/09/16 + * KDB v1.4 + * kdb=on/off/early at boot, /proc/sys/kernel/kdb. + * Env BTAPROMPT. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined(CONFIG_MODULES) +extern struct module *module_list; +#endif + + /* + * Kernel debugger state flags + */ +volatile int kdb_flags; + + /* + * kdb_lock protects updates to kdb_initial_cpu. Used to + * single thread processors through the kernel debugger. + */ +spinlock_t kdb_lock = SPIN_LOCK_UNLOCKED; +volatile int kdb_initial_cpu = -1; /* cpu number that owns kdb */ + +volatile int kdb_nextline = 1; +static volatile int kdb_new_cpu; /* Which cpu to switch to */ + +volatile int kdb_state[NR_CPUS]; /* Per cpu state */ + +#ifdef CONFIG_KDB_OFF +int kdb_on = 0; /* Default is off */ +#else +int kdb_on = 1; /* Default is on */ +#endif /* CONFIG_KDB_OFF */ + +#ifdef KDB_HAVE_LONGJMP + /* + * Must have a setjmp buffer per CPU. Switching cpus will + * cause the jump buffer to be setup for the new cpu, and + * subsequent switches (and pager aborts) will use the + * appropriate per-processor values. + */ +kdb_jmp_buf kdbjmpbuf[NR_CPUS]; +#endif /* KDB_HAVE_LONGJMP */ + + /* + * kdb_commands describes the available commands. + */ +static kdbtab_t kdb_commands[KDB_MAX_COMMANDS]; + +typedef struct _kdbmsg { + int km_diag; /* kdb diagnostic */ + char *km_msg; /* Corresponding message text */ +} kdbmsg_t; + +#define KDBMSG(msgnum, text) \ + { KDB_##msgnum, text } + +static kdbmsg_t kdbmsgs[] = { + KDBMSG(NOTFOUND,"Command Not Found"), + KDBMSG(ARGCOUNT, "Improper argument count, see usage."), + KDBMSG(BADWIDTH, "Illegal value for BYTESPERWORD use 1, 2 or 4"), + KDBMSG(BADRADIX, "Illegal value for RADIX use 8, 10 or 16"), + KDBMSG(NOTENV, "Cannot find environment variable"), + KDBMSG(NOENVVALUE, "Environment variable should have value"), + KDBMSG(NOTIMP, "Command not implemented"), + KDBMSG(ENVFULL, "Environment full"), + KDBMSG(ENVBUFFULL, "Environment buffer full"), + KDBMSG(TOOMANYBPT, "Too many breakpoints defined"), + KDBMSG(TOOMANYDBREGS, "More breakpoints than db registers defined"), + KDBMSG(DUPBPT, "Duplicate breakpoint address"), + KDBMSG(BPTNOTFOUND, "Breakpoint not found"), + KDBMSG(BADMODE, "Invalid IDMODE"), + KDBMSG(BADINT, "Illegal numeric value"), + KDBMSG(INVADDRFMT, "Invalid symbolic address format"), + KDBMSG(BADREG, "Invalid register name"), + KDBMSG(BADCPUNUM, "Invalid cpu number"), + KDBMSG(BADLENGTH, "Invalid length field"), + KDBMSG(NOBP, "No Breakpoint exists"), +}; +#undef KDBMSG + +static const int __nkdb_err = sizeof(kdbmsgs) / sizeof(kdbmsg_t); + + +/* + * Initial environment. This is all kept static and local to + * this file. We don't want to rely on the memory allocation + * mechanisms in the kernel, so we use a very limited allocate-only + * heap for new and altered environment variables. The entire + * environment is limited to a fixed number of entries (add more + * to __env[] if required) and a fixed amount of heap (add more to + * KDB_ENVBUFSIZE if required). + */ + +static char *__env[] = { +#if defined(CONFIG_SMP) + "PROMPT=[%d]kdb> ", + "MOREPROMPT=[%d]more> ", +#else + "PROMPT=kdb> ", + "MOREPROMPT=more> ", +#endif + "RADIX=16", + "LINES=24", + "COLUMNS=80", + "MDCOUNT=8", /* lines of md output */ + "BTARGS=5", /* 5 possible args in bt */ + "SSCOUNT=20", /* lines of ssb output */ + KDB_PLATFORM_ENV, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, +}; + +static const int __nenv = (sizeof(__env) / sizeof(char *)); + +/* + * kdbgetenv + * + * This function will return the character string value of + * an environment variable. + * + * Parameters: + * match A character string representing an environment variable. + * Outputs: + * None. + * Returns: + * NULL No environment variable matches 'match' + * char* Pointer to string value of environment variable. + * Locking: + * No locking considerations required. + * Remarks: + */ +char * +kdbgetenv(const char *match) +{ + char **ep = __env; + int matchlen = strlen(match); + int i; + + for(i=0; i<__nenv; i++) { + char *e = *ep++; + + if (!e) continue; + + if ((strncmp(match, e, matchlen) == 0) + && ((e[matchlen] == '\0') + ||(e[matchlen] == '='))) { + char *cp = strchr(e, '='); + return (cp)?++cp:""; + } + } + return (char *)0; +} + +/* + * kdballocenv + * + * This function is used to allocate bytes for environment entries. + * + * Parameters: + * match A character string representing a numeric value + * Outputs: + * *value the unsigned long represntation of the env variable 'match' + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. Must be called with all + * processors halted. + * Remarks: + * We use a static environment buffer (envbuffer) to hold the values + * of dynamically generated environment variables (see kdb_set). Buffer + * space once allocated is never free'd, so over time, the amount of space + * (currently 512 bytes) will be exhausted if env variables are changed + * frequently. + */ +static char * +kdballocenv(size_t bytes) +{ +#define KDB_ENVBUFSIZE 512 + static char envbuffer[KDB_ENVBUFSIZE]; + static int envbufsize; + char *ep = (char *)0; + + if ((KDB_ENVBUFSIZE - envbufsize) >= bytes) { + ep = &envbuffer[envbufsize]; + envbufsize += bytes; + } + return ep; +} + +/* + * kdbgetulenv + * + * This function will return the value of an unsigned long-valued + * environment variable. + * + * Parameters: + * match A character string representing a numeric value + * Outputs: + * *value the unsigned long represntation of the env variable 'match' + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. + * Remarks: + */ + +int +kdbgetulenv(const char *match, unsigned long *value) +{ + char *ep; + + ep = kdbgetenv(match); + if (!ep) return KDB_NOTENV; + if (strlen(ep) == 0) return KDB_NOENVVALUE; + + *value = simple_strtoul(ep, 0, 0); + + return 0; +} + +/* + * kdbgetintenv + * + * This function will return the value of an integer-valued + * environment variable. + * + * Parameters: + * match A character string representing an integer-valued env variable + * Outputs: + * *value the integer representation of the environment variable 'match' + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. + * Remarks: + */ + +int +kdbgetintenv(const char *match, int *value) { + unsigned long val; + int diag; + + diag = kdbgetulenv(match, &val); + if (!diag) { + *value = (int) val; + } + return diag; +} + +/* + * kdbgetularg + * + * This function will convert a numeric string + * into an unsigned long value. + * + * Parameters: + * arg A character string representing a numeric value + * Outputs: + * *value the unsigned long represntation of arg. + * Returns: + * Zero on success, a kdb diagnostic on failure. + * Locking: + * No locking considerations required. + * Remarks: + */ + +int +kdbgetularg(const char *arg, unsigned long *value) +{ + char *endp; + unsigned long val; + + val = simple_strtoul(arg, &endp, 0); + + if (endp == arg) { + /* + * Try base 16, for us folks too lazy to type the + * leading 0x... + */ + val = simple_strtoul(arg, &endp, 16); + if (endp == arg) + return KDB_BADINT; + } + + *value = val; + + return 0; +} + +/* + * kdbgetaddrarg + * + * This function is responsible for parsing an + * address-expression and returning the value of + * the expression, symbol name, and offset to the caller. + * + * The argument may consist of a numeric value (decimal or + * hexidecimal), a symbol name, a register name (preceeded + * by the percent sign), an environment variable with a numeric + * value (preceeded by a dollar sign) or a simple arithmetic + * expression consisting of a symbol name, +/-, and a numeric + * constant value (offset). + * + * Parameters: + * argc - count of arguments in argv + * argv - argument vector + * *nextarg - index to next unparsed argument in argv[] + * regs - Register state at time of KDB entry + * Outputs: + * *value - receives the value of the address-expression + * *offset - receives the offset specified, if any + * *name - receives the symbol name, if any + * *nextarg - index to next unparsed argument in argv[] + * + * Returns: + * zero is returned on success, a kdb diagnostic code is + * returned on error. + * + * Locking: + * No locking requirements. + * + * Remarks: + * + */ + +int +kdbgetaddrarg(int argc, const char **argv, int *nextarg, + kdb_machreg_t *value, long *offset, + char **name, kdb_eframe_t ef) +{ + kdb_machreg_t addr; + long off = 0; + int positive; + int diag; + int found = 0; + char *symname; + char symbol = '\0'; + char *cp; + kdb_symtab_t symtab; + + /* + * Process arguments which follow the following syntax: + * + * symbol | numeric-address [+/- numeric-offset] + * %register + * $environment-variable + */ + + if (*nextarg > argc) { + return KDB_ARGCOUNT; + } + + symname = (char *)argv[*nextarg]; + + /* + * If there is no whitespace between the symbol + * or address and the '+' or '-' symbols, we + * remember the character and replace it with a + * null so the symbol/value can be properly parsed + */ + if ((cp = strpbrk(symname, "+-")) != NULL) { + symbol = *cp; + *cp++ = '\0'; + } + + if (symname[0] == '$') { + diag = kdbgetulenv(&symname[1], &addr); + if (diag) + return diag; + } else if (symname[0] == '%') { + diag = kdba_getregcontents(&symname[1], ef, &addr); + if (diag) + return diag; + } else { + found = kdbgetsymval(symname, &symtab); + if (found) { + addr = symtab.sym_start; + } else { + diag = kdbgetularg(argv[*nextarg], &addr); + if (diag) + return diag; + } + } + + if (!found) + found = kdbnearsym(addr, &symtab); + + (*nextarg)++; + + if (name) + *name = symname; + if (value) + *value = addr; + if (offset && name && *name) + *offset = addr - symtab.sym_start; + + if ((*nextarg > argc) + && (symbol == '\0')) + return 0; + + /* + * check for +/- and offset + */ + + if (symbol == '\0') { + if ((argv[*nextarg][0] != '+') + && (argv[*nextarg][0] != '-')) { + /* + * Not our argument. Return. + */ + return 0; + } else { + positive = (argv[*nextarg][0] == '+'); + (*nextarg)++; + } + } else + positive = (symbol == '+'); + + /* + * Now there must be an offset! + */ + if ((*nextarg > argc) + && (symbol == '\0')) { + return KDB_INVADDRFMT; + } + + if (!symbol) { + cp = (char *)argv[*nextarg]; + (*nextarg)++; + } + + diag = kdbgetularg(cp, &off); + if (diag) + return diag; + + if (!positive) + off = -off; + + if (offset) + *offset += off; + + if (value) + *value += off; + + return 0; +} + +static void +kdb_cmderror(int diag) +{ + int i; + + if (diag >= 0) { + kdb_printf("no error detected\n"); + return; + } + + for(i=0; i<__nkdb_err; i++) { + if (kdbmsgs[i].km_diag == diag) { + kdb_printf("diag: %d: %s\n", diag, kdbmsgs[i].km_msg); + return; + } + } + + kdb_printf("Unknown diag %d\n", -diag); +} + +/* + * kdb_parse + * + * Parse the command line, search the command table for a + * matching command and invoke the command function. + * + * Parameters: + * cmdstr The input command line to be parsed. + * regs The registers at the time kdb was entered. + * Outputs: + * None. + * Returns: + * Zero for success, a kdb diagnostic if failure. + * Locking: + * None. + * Remarks: + * Limited to 20 tokens. + * + * Real rudimentary tokenization. Basically only whitespace + * is considered a token delimeter (but special consideration + * is taken of the '=' sign as used by the 'set' command). + * + * The algorithm used to tokenize the input string relies on + * there being at least one whitespace (or otherwise useless) + * character between tokens as the character immediately following + * the token is altered in-place to a null-byte to terminate the + * token string. + */ + +#define MAXARGC 20 + +static int +kdb_parse(char *cmdstr, kdb_eframe_t ef) +{ + char *argv[MAXARGC]; + int argc=0; + char *cp; + kdbtab_t *tp; + int i; + + /* + * First tokenize the command string. + */ + cp = cmdstr; + + /* + * If a null statement is provided, do nothing. + */ + if ((*cp == '\n') || (*cp == '\0')) + return 0; + + while (*cp) { + /* skip whitespace */ + while (isspace(*cp)) cp++; + if ((*cp == '\0') || (*cp == '\n')) + break; + argv[argc++] = cp; + /* Skip to next whitespace */ + for(; *cp && (!isspace(*cp) && (*cp != '=')); cp++); + *cp++ = '\0'; /* Squash a ws or '=' character */ + } + if (!argc) + return 0; + + for(tp=kdb_commands, i=0; i < KDB_MAX_COMMANDS; i++,tp++) { + if (tp->cmd_name) { + /* + * If this command is allowed to be abbreviated, + * check to see if this is it. + */ + + if (tp->cmd_minlen + && (strlen(argv[0]) <= tp->cmd_minlen)) { + if (strncmp(argv[0], + tp->cmd_name, + tp->cmd_minlen) == 0) { + break; + } + } + + if (strcmp(argv[0], tp->cmd_name)==0) { + break; + } + } + } + + if (i < KDB_MAX_COMMANDS) { + int result, no_watchdog; + KDB_STATE_SET(CMD); + no_watchdog = KDB_STATE(NO_WATCHDOG); + KDB_STATE_CLEAR(NO_WATCHDOG); + result = (*tp->cmd_func)(argc-1, + (const char**)argv, + (const char**)__env, + ef); + if (no_watchdog) + KDB_STATE_SET(NO_WATCHDOG); + KDB_STATE_CLEAR(CMD); + return result; + } + + /* + * If the input with which we were presented does not + * map to an existing command, attempt to parse it as an + * address argument and display the result. Useful for + * obtaining the address of a variable, or the nearest symbol + * to an address contained in a register. + */ + { + kdb_machreg_t value; + char *name = NULL; + long offset; + int nextarg = 0; + + if (kdbgetaddrarg(0, (const char **)argv, &nextarg, + &value, &offset, &name, ef)) { + return KDB_NOTFOUND; + } + + kdb_printf("%s = ", argv[0]); + kdb_symbol_print(value, NULL, KDB_SP_DEFAULT); + kdb_printf("\n"); + return 0; + } +} + +/* The command history feature is not functional at the moment. It + * will be replaced by something that understands editting keys, + * including left, right, insert, delete as well as up, down. + * Keith Owens, November 18 2000 + */ +#define KDB_CMD_HISTORY_COUNT 32 +#define CMD_BUFLEN 200 /* kdb_printf: max printline size == 256 */ +static unsigned int cmd_head, cmd_tail; +static unsigned int cmdptr; +static char cmd_hist[KDB_CMD_HISTORY_COUNT][CMD_BUFLEN]; + + +static int +handle_ctrl_cmd(char *cmd) +{ +#define CTRL_P 16 +#define CTRL_N 14 + + /* initial situation */ + if (cmd_head == cmd_tail) return 1; + + switch(*cmd) { + case '\n': + case CTRL_P: + if (cmdptr != cmd_tail) + cmdptr = (cmdptr-1) % KDB_CMD_HISTORY_COUNT; + strcpy(cmd, cmd_hist[cmdptr]); + return 0; + case CTRL_N: + if (cmdptr != (cmd_head-1)) + cmdptr = (cmdptr+1) % KDB_CMD_HISTORY_COUNT; + strcpy(cmd, cmd_hist[cmdptr]); + return 0; + } + return 1; +} + + +/* + * kdb_local + * + * The main code for kdb. This routine is invoked on a specific + * processor, it is not global. The main kdb() routine ensures + * that only one processor at a time is in this routine. This + * code is called with the real reason code on the first entry + * to a kdb session, thereafter it is called with reason SWITCH, + * even if the user goes back to the original cpu. + * + * Inputs: + * reason The reason KDB was invoked + * error The hardware-defined error code + * ef The exception frame at time of fault/breakpoint. NULL + * for reason SILENT, otherwise valid. + * db_result Result code from the break or debug point. + * Returns: + * 0 KDB was invoked for an event which it wasn't responsible + * 1 KDB handled the event for which it was invoked. + * KDB_CMD_GO User typed 'go'. + * KDB_CMD_CPU User switched to another cpu. + * KDB_CMD_SS Single step. + * KDB_CMD_SSB Single step until branch. + * Locking: + * none + * Remarks: + * none + */ + +static int +kdb_local(kdb_reason_t reason, int error, kdb_eframe_t ef, kdb_dbtrap_t db_result) +{ + char *cmdbuf; + char cmd[CMD_BUFLEN]; + int diag; + int parsed_once=0; /* if false don't repeat last cmd on CR */ + typeof (*ef) local_ef; + + if (reason != KDB_REASON_DEBUG && + reason != KDB_REASON_SILENT) { + kdb_printf("\nEntering kdb (current=0x%p, pid %d) ", (void *)current, current->pid); +#if defined(CONFIG_SMP) + kdb_printf("on processor %d ", smp_processor_id()); +#endif + } + + switch (reason) { + case KDB_REASON_DEBUG: + { + /* + * If re-entering kdb after a single step + * command, don't print the message. + */ + switch(db_result) { + case KDB_DB_BPT: + kdb_printf("\nEntering kdb (0x%p) ", (void *)current); +#if defined(CONFIG_SMP) + kdb_printf("on processor %d ", smp_processor_id()); +#endif + kdb_printf("due to Debug @ " kdb_machreg_fmt "\n", kdba_getpc(ef)); + break; + case KDB_DB_SSB: + /* + * In the midst of ssb command. Just return. + */ + return KDB_CMD_SSB; /* Continue with SSB command */ + + break; + case KDB_DB_SS: + break; + case KDB_DB_SSBPT: + return 1; /* kdba_db_trap did the work */ + default: + kdb_printf("kdb: Bad result from kdba_db_trap: %d\n", + db_result); + break; + } + + } + break; + case KDB_REASON_FAULT: + break; + case KDB_REASON_ENTER: + kdb_printf("due to KDB_ENTER()\n"); + break; + case KDB_REASON_KEYBOARD: + kdb_printf("due to Keyboard Entry\n"); + break; + case KDB_REASON_SWITCH: + kdb_printf("due to cpu switch\n"); + break; + case KDB_REASON_CALL: /* drop through */ + case KDB_REASON_PANIC: + if (reason == KDB_REASON_CALL) + kdb_printf("due to direct function call\n"); + else + kdb_printf("due to panic\n"); + /* + * Get a set of registers that defines the current + * context (as of the call to kdb). + */ + memset(&local_ef, 0, sizeof(local_ef)); + ef = &local_ef; + kdb_getcurrentframe(ef); + kdba_setpc(ef, (kdb_machreg_t)(&kdb)); /* for traceback */ + break; + case KDB_REASON_OOPS: + kdb_printf("Oops: %s\n", kdb_diemsg); + kdb_printf("due to oops @ " kdb_machreg_fmt "\n", kdba_getpc(ef)); + kdba_dumpregs(ef, NULL, NULL); + break; + case KDB_REASON_NMI: + kdb_printf("due to NonMaskable Interrupt @ " kdb_machreg_fmt "\n", + kdba_getpc(ef)); + kdba_dumpregs(ef, NULL, NULL); + break; + case KDB_REASON_WATCHDOG: + kdb_printf("due to WatchDog Interrupt @ " kdb_machreg_fmt "\n", + kdba_getpc(ef)); + kdba_dumpregs(ef, NULL, NULL); + break; + case KDB_REASON_BREAK: + kdb_printf("due to Breakpoint @ " kdb_machreg_fmt "\n", kdba_getpc(ef)); + /* + * Determine if this breakpoint is one that we + * are interested in. + */ + if (db_result != KDB_DB_BPT) { + kdb_printf("kdb: error return from kdba_bp_trap: %d\n", db_result); + return 0; /* Not for us, dismiss it */ + } + break; + case KDB_REASON_RECURSE: + kdb_printf("due to Recursion @ " kdb_machreg_fmt "\n", kdba_getpc(ef)); + break; + case KDB_REASON_SILENT: + return KDB_CMD_GO; /* Silent entry, silent exit */ + break; + default: + kdb_printf("kdb: unexpected reason code: %d\n", reason); + return 0; /* Not for us, dismiss it */ + } + + while (1) { + /* + * Initialize pager context. + */ + kdb_nextline = 1; +#ifdef KDB_HAVE_LONGJMP + /* + * Use kdb_setjmp/kdb_longjmp to break out of + * the pager early. + */ + if (kdb_setjmp(&kdbjmpbuf[smp_processor_id()])) { + /* + * Command aborted (usually in pager) + */ + + /* + * XXX - need to abort a SSB ? + */ + continue; + } +#endif /* KDB_HAVE_LONGJMP */ + +do_full_getstr: +#if defined(CONFIG_SMP) + kdb_printf(kdbgetenv("PROMPT"), smp_processor_id()); +#else + kdb_printf(kdbgetenv("PROMPT")); +#endif + + + cmdbuf = cmd_hist[cmd_head]; + *cmdbuf = '\0'; +get_again: + /* + * Fetch command from keyboard + */ + cmdbuf = kdb_getstr(cmdbuf, CMD_BUFLEN,""); + if (*cmdbuf < 32) { + int not_cr = *cmdbuf == '\n' ? 0 : 1; + + if (!(not_cr || parsed_once) + || handle_ctrl_cmd(cmdbuf)) goto do_full_getstr; + + if (not_cr) goto get_again; + } + + if (*cmdbuf != '\n') { + cmd_head = (cmd_head+1) % KDB_CMD_HISTORY_COUNT; + if (cmd_head == cmd_tail) cmd_tail = (cmd_tail+1) % KDB_CMD_HISTORY_COUNT; + + parsed_once = 1; + } + + cmdptr = cmd_head; + strcpy(cmd, cmdbuf); /* copy because of destructive parsing */ + diag = kdb_parse(cmd, ef); + if (diag == KDB_NOTFOUND) { + kdb_printf("Unknown kdb command: '%s'\n", cmd); + diag = 0; + } + if (diag == KDB_CMD_GO + || diag == KDB_CMD_CPU + || diag == KDB_CMD_SS + || diag == KDB_CMD_SSB) + break; + + if (diag) + kdb_cmderror(diag); + } + + return(diag); +} + + +/* + * kdb_print_state + * + * Print the state data for the current processor for debugging. + * + * Inputs: + * text Identifies the debug point + * value Any integer value to be printed, e.g. reason code. + * Returns: + * None. + * Locking: + * none + * Remarks: + * none + */ + +void kdb_print_state(const char *text, int value) +{ + kdb_printf("state: %s cpu %d value %d initial %d state %x\n", + text, smp_processor_id(), value, kdb_initial_cpu, kdb_state[smp_processor_id()]); +} + +/* + * kdb_previous_event + * + * Return a count of cpus that are leaving kdb, i.e. the number + * of processors that are still handling the previous kdb event. + * + * Inputs: + * None. + * Returns: + * Count of cpus in previous event. + * Locking: + * none + * Remarks: + * none + */ + +static int +kdb_previous_event(void) +{ + int i, leaving = 0; + for (i = 0; i < NR_CPUS; ++i) { + if (KDB_STATE_CPU(LEAVING, i)) + ++leaving; + } + return(leaving); +} + +/* + * kdb_main_loop + * + * The main kdb loop. After initial setup and assignment of the controlling + * cpu, all cpus are in this loop. One cpu is in control and will issue the kdb + * prompt, the others will spin until 'go' or cpu switch. + * + * To get a consistent view of the kernel stacks for all processes, this routine + * is invoked from the main kdb code via an architecture specific routine. + * kdba_main_loop is responsible for making the kernel stacks consistent for all + * processes, there should be no difference between a blocked process and a + * running process as far as kdb is concerned. + * + * Inputs: + * reason The reason KDB was invoked + * error The hardware-defined error code + * reason2 kdb's current reason code. Initially error but can change + * acording to kdb state. + * db_result Result code from break or debug point. + * ef The exception frame at time of fault/breakpoint. If reason + * is KDB_REASON_SILENT or KDB_REASON_PANIC then ef is NULL, + * otherwise it should always be valid. + * Returns: + * 0 KDB was invoked for an event which it wasn't responsible + * 1 KDB handled the event for which it was invoked. + * Locking: + * none + * Remarks: + * none + */ + +int +kdb_main_loop(kdb_reason_t reason, kdb_reason_t reason2, int error, + kdb_dbtrap_t db_result, kdb_eframe_t ef) +{ + int result = 1; + /* Stay in kdb() until 'go', 'ss[b]' or an error */ + while (1) { + int i; + /* + * All processors except the one that is in control + * will spin here. + */ + KDB_DEBUG_STATE("kdb_main_loop 1", reason); + while (KDB_STATE(HOLD_CPU)) + ; + KDB_DEBUG_STATE("kdb_main_loop 2", reason); + if (KDB_STATE(LEAVING)) + break; /* Another cpu said 'go' */ + + /* Still using kdb, this processor is in control */ + result = kdb_local(reason2, error, ef, db_result); + KDB_DEBUG_STATE("kdb_main_loop 3", result); + + if (result == KDB_CMD_CPU) { + /* Cpu switch, hold the current cpu, release the target one. */ + reason2 = KDB_REASON_SWITCH; + KDB_STATE_SET(HOLD_CPU); + KDB_STATE_CLEAR_CPU(HOLD_CPU, kdb_new_cpu); + continue; + } + + if (result == KDB_CMD_SS) { + KDB_STATE_SET(DOING_SS); + break; + } + + if (result == KDB_CMD_SSB) { + KDB_STATE_SET(DOING_SS); + KDB_STATE_SET(DOING_SSB); + break; + } + + if (result && result != 1 && result != KDB_CMD_GO) + kdb_printf("\nUnexpected kdb_local return code %d\n", result); + + /* + * All other return codes (including KDB_CMD_GO) from + * kdb_local will end kdb(). Release all other cpus + * which will see KDB_STATE(LEAVING) is set. + */ + for (i = 0; i < NR_CPUS; ++i) { + if (KDB_STATE_CPU(KDB, i)) + KDB_STATE_SET_CPU(LEAVING, i); + KDB_STATE_CLEAR_CPU(WAIT_IPI, i); + KDB_STATE_CLEAR_CPU(HOLD_CPU, i); + } + KDB_DEBUG_STATE("kdb_main_loop 4", reason); + break; + } + return(result != 0); +} + +/* + * kdb + * + * This function is the entry point for the kernel debugger. It + * provides a command parser and associated support functions to + * allow examination and control of an active kernel. + * + * This function may be invoked directly from any + * point in the kernel by calling with reason == KDB_REASON_CALL + * (XXX - note that the regs aren't set up this way - could + * use a software interrupt to enter kdb to get regs...) + * + * The breakpoint trap code should invoke this function with + * one of KDB_REASON_BREAK (int 03) or KDB_REASON_DEBUG (debug register) + * + * the die_if_kernel function should invoke this function with + * KDB_REASON_OOPS. + * + * the panic function should invoke this function with KDB_REASON_PANIC. + * + * The kernel fault handler should invoke this function with + * reason == KDB_REASON_FAULT and error == trap vector #. + * + * In single step mode, one cpu is released to run without + * breakpoints. Interrupts and NMI are reset to their original values, + * the cpu is allowed to do one instruction which causes a trap + * into kdb with KDB_REASON_DEBUG. + * + * Inputs: + * reason The reason KDB was invoked + * error The hardware-defined error code + * ef The exception frame at time of fault/breakpoint. If reason + * is KDB_REASON_SILENT or KDB_REASON_PANIC then ef is NULL, + * otherwise it should always be valid. + * Returns: + * 0 KDB was invoked for an event which it wasn't responsible + * 1 KDB handled the event for which it was invoked. + * Locking: + * none + * Remarks: + * No assumptions of system state. This function may be invoked + * with arbitrary locks held. It will stop all other processors + * in an SMP environment, disable all interrupts and does not use + * the operating systems keyboard driver. + * + * This code is reentrant but only for cpu switch. Any other + * reentrancy is an error, although kdb will attempt to recover. + * + * At the start of a kdb session the initial processor is running + * kdb() and the other processors can be doing anything. When the + * initial processor calls smp_kdb_stop() the other processors are + * driven through kdb_ipi which calls kdb() with reason SWITCH. + * That brings all processors into this routine, one with a "real" + * reason code, the other with SWITCH. + * + * Because the other processors are driven via smp_kdb_stop(), + * they enter here from the NMI handler. Until the other + * processors exit from here and exit from kdb_ipi, they will not + * take any more NMI requests. The initial cpu will still take NMI. + * + * Multiple race and reentrancy conditions, each with different + * advoidance mechanisms. + * + * Two cpus hit debug points at the same time. + * + * kdb_lock and kdb_initial_cpu ensure that only one cpu gets + * control of kdb. The others spin on kdb_initial_cpu until + * they are driven through NMI into kdb_ipi. When the initial + * cpu releases the others from NMI, they resume trying to get + * kdb_initial_cpu to start a new event. + * + * A cpu is released from kdb and starts a new event before the + * original event has completely ended. + * + * kdb_previous_event() prevents any cpu from entering + * kdb_initial_cpu state until the previous event has completely + * ended on all cpus. + * + * An exception occurs inside kdb. + * + * kdb_initial_cpu detects recursive entry to kdb and attempts + * to recover. The recovery uses longjmp() which means that + * recursive calls to kdb never return. Beware of assumptions + * like + * + * ++depth; + * kdb(); + * --depth; + * + * If the kdb call is recursive then longjmp takes over and + * --depth is never executed. + * + * NMI handling. + * + * NMI handling is tricky. The initial cpu is invoked by some kdb event, + * this event could be NMI driven but usually is not. The other cpus are + * driven into kdb() via kdb_ipi which uses NMI so at the start the other + * cpus will not accept NMI. Some operations such as SS release one cpu + * but hold all the others. Releasing a cpu means it drops back to + * whatever it was doing before the kdb event, this means it drops out of + * kdb_ipi and hence out of NMI status. But the software watchdog uses + * NMI and we do not want spurious watchdog calls into kdb. + * KDB_STATE(NO_WATCHDOG) prevents the software watchdog calling kdb. + * This flag is set while the cpu is inside mainline kdb, it is not set + * during a kdb command, in order to detect looping commands. + * + * Another problem with NMI handling is the NMI used to drive the other + * cpus into kdb cannot be distinguished from the watchdog NMI. State + * flag WAIT_IPI indicates that a cpu is waiting for NMI via kdb_ipi, + * if not set then software NMI is ignored by kdb_ipi. + * + * Cpu switching. + * + * All cpus are in kdb (or they should be), all but one are + * spinning on KDB_STATE(HOLD_CPU). Only one cpu is not in + * HOLD_CPU state, only that cpu can handle commands. + * + */ + +int +kdb(kdb_reason_t reason, int error, kdb_eframe_t ef) +{ + kdb_intstate_t int_state; /* Interrupt state */ + kdb_reason_t reason2 = reason; + int result = 1; /* Default is kdb handled it */ + int ss_event; + kdb_dbtrap_t db_result=KDB_DB_NOBPT; + + if (!kdb_on) + return 0; + + KDB_DEBUG_STATE("kdb 1", reason); + + /* Filter out userspace breakpoints first, no point in doing all + * the kdb smp fiddling when it is really a gdb trap. + * Save the single step status first, kdba_db_trap clears ss status. + */ + ss_event = (KDB_STATE(DOING_SS) || KDB_STATE(SSBPT)); + if (reason == KDB_REASON_BREAK) + db_result = kdba_bp_trap(ef, error); /* Only call this once */ + if (reason == KDB_REASON_DEBUG) + db_result = kdba_db_trap(ef, error); /* Only call this once */ + + if ((reason == KDB_REASON_BREAK || reason == KDB_REASON_DEBUG) + && db_result == KDB_DB_NOBPT) { + KDB_DEBUG_STATE("kdb 2", reason); + return 0; /* Not one of mine */ + } + + /* Turn off single step if it was being used */ + if (ss_event) { + kdba_clearsinglestep(ef); + /* Single step after a breakpoint removes the need for a delayed reinstall */ + if (reason == KDB_REASON_BREAK || reason == KDB_REASON_DEBUG) { + KDB_STATE_SET(NO_BP_DELAY); + } + } + + /* kdb can validly reenter but only for certain well defined conditions */ + if (reason == KDB_REASON_DEBUG + && !KDB_STATE(HOLD_CPU) + && ss_event) + KDB_STATE_SET(REENTRY); + else + KDB_STATE_CLEAR(REENTRY); + + /* Wait for previous kdb event to completely exit before starting + * a new event. + */ + KDB_STATE_SET(NO_WATCHDOG); + while (kdb_previous_event()) + ; + KDB_DEBUG_STATE("kdb 3", reason); + + /* + * If kdb is already active, print a message and try to recover. + * If recovery is not possible and recursion is allowed or + * forced recursion without recovery is set then try to recurse + * in kdb. Not guaranteed to work but it makes an attempt at + * debugging the debugger. + */ + if (reason != KDB_REASON_SWITCH) { + if (KDB_IS_RUNNING() && !KDB_STATE(REENTRY)) { + int recover = 1; + unsigned long recurse = 0; + kdb_printf("kdb: Debugger re-entered on cpu %d, new reason = %d\n", + smp_processor_id(), reason); + /* Should only re-enter from released cpu */ + if (KDB_STATE(HOLD_CPU)) { + kdb_printf(" Strange, cpu %d should not be running\n", smp_processor_id()); + recover = 0; + } + if (!KDB_STATE(CMD)) { + kdb_printf(" Not executing a kdb command\n"); + recover = 0; + } + if (!KDB_STATE(LONGJMP)) { + kdb_printf(" No longjmp available for recovery\n"); + recover = 0; + } + kdbgetulenv("RECURSE", &recurse); + if (recurse > 1) { + kdb_printf(" Forced recursion is set\n"); + recover = 0; + } + if (recover) { + kdb_printf(" Attempting to abort command and recover\n"); +#ifdef KDB_HAVE_LONGJMP + kdb_longjmp(&kdbjmpbuf[smp_processor_id()], 0); +#endif + } + if (recurse) { + if (KDB_STATE(RECURSE)) { + kdb_printf(" Already in recursive mode\n"); + } else { + kdb_printf(" Attempting recursive mode\n"); + KDB_STATE_SET(RECURSE); + KDB_STATE_SET(REENTRY); + reason2 = KDB_REASON_RECURSE; + recover = 1; + } + } + if (!recover) { + kdb_printf(" Cannot recover, allowing event to proceed\n"); + KDB_STATE_CLEAR(NO_WATCHDOG); + return(0); + } + } + } else if (!KDB_IS_RUNNING()) { + kdb_printf("kdb: CPU switch without kdb running, I'm confused\n"); + KDB_STATE_CLEAR(NO_WATCHDOG); + return(0); + } + + /* + * Disable interrupts, breakpoints etc. on this processor + * during kdb command processing + */ + KDB_STATE_SET(KDB); + kdba_disableint(&int_state); + if (!KDB_STATE(KDB_CONTROL)) { + kdb_bp_remove_local(); + kdba_disable_lbr(); + KDB_STATE_SET(KDB_CONTROL); + } + else if (KDB_DEBUG(LBR)) + kdba_print_lbr(); + + /* + * If not entering the debugger due to CPU switch or single step + * reentry, serialize access here. + * The processors may race getting to this point - if, + * for example, more than one processor hits a breakpoint + * at the same time. We'll serialize access to kdb here - + * other processors will loop here, and the NMI from the stop + * IPI will take them into kdb as switch candidates. Once + * the initial processor releases the debugger, the rest of + * the processors will race for it. + */ + if (reason == KDB_REASON_SWITCH + || KDB_STATE(REENTRY)) + ; /* drop through */ + else { + KDB_DEBUG_STATE("kdb 4", reason); + spin_lock(&kdb_lock); + + while (KDB_IS_RUNNING() || kdb_previous_event()) { + spin_unlock(&kdb_lock); + + while (KDB_IS_RUNNING() || kdb_previous_event()) + ; + + spin_lock(&kdb_lock); + } + KDB_DEBUG_STATE("kdb 5", reason); + + kdb_initial_cpu = smp_processor_id(); + spin_unlock(&kdb_lock); + } + + if (smp_processor_id() == kdb_initial_cpu + && !KDB_STATE(REENTRY)) { + KDB_STATE_CLEAR(HOLD_CPU); + KDB_STATE_CLEAR(WAIT_IPI); + /* + * Remove the global breakpoints. This is only done + * once from the initial processor on initial entry. + */ + kdb_bp_remove_global(); + + /* + * If SMP, stop other processors. The other processors + * will enter kdb() with KDB_REASON_SWITCH and spin + * below. + */ + KDB_DEBUG_STATE("kdb 6", reason); + if (smp_num_cpus > 1) { + int i; + for (i = 0; i < NR_CPUS; ++i) { + if (i != kdb_initial_cpu) { + KDB_STATE_SET_CPU(HOLD_CPU, i); + KDB_STATE_SET_CPU(WAIT_IPI, i); + } + } + KDB_DEBUG_STATE("kdb 7", reason); + smp_kdb_stop(); + KDB_DEBUG_STATE("kdb 8", reason); + } + } + + /* Set up a consistent set of process stacks before talking to the user */ + KDB_DEBUG_STATE("kdb 9", result); + result = kdba_main_loop(reason, reason2, error, db_result, ef); + + KDB_DEBUG_STATE("kdb 10", result); + kdba_adjust_ip(reason, error, ef); + KDB_STATE_CLEAR(LONGJMP); + KDB_DEBUG_STATE("kdb 11", result); + + /* No breakpoints installed for SS */ + if (!KDB_STATE(DOING_SS) && + !KDB_STATE(SSBPT) && + !KDB_STATE(RECURSE)) { + KDB_DEBUG_STATE("kdb 12", result); + kdba_enable_lbr(); + kdb_bp_install_local(ef); + KDB_STATE_CLEAR(NO_BP_DELAY); + KDB_STATE_CLEAR(KDB_CONTROL); + } + + KDB_DEBUG_STATE("kdb 13", result); + kdba_restoreint(&int_state); + + KDB_STATE_CLEAR(KDB); /* Main kdb state has been cleared */ + KDB_STATE_CLEAR(LEAVING); /* Elvis has left the building ... */ + KDB_DEBUG_STATE("kdb 14", result); + + if (smp_processor_id() == kdb_initial_cpu && + !KDB_STATE(DOING_SS) && + !KDB_STATE(RECURSE)) { + /* + * (Re)install the global breakpoints. This is only done + * once from the initial processor on final exit. + */ + KDB_DEBUG_STATE("kdb 15", reason); + kdb_bp_install_global(ef); + /* Wait until all the other processors leave kdb */ + while (kdb_previous_event()) + ; + kdb_initial_cpu = -1; /* release kdb control */ + KDB_DEBUG_STATE("kdb 16", reason); + } + + KDB_STATE_CLEAR(NO_WATCHDOG); + KDB_STATE_CLEAR(RECURSE); + KDB_DEBUG_STATE("kdb 17", reason); + return(result != 0); +} + +/* + * kdb_mdr + * + * This function implements the guts of the 'mdr' command. + * + * mdr , + * + * Inputs: + * addr Start address + * count Number of bytes + * Outputs: + * None. + * Returns: + * Always 0. Any errors are detected and printed by kdba_getword. + * Locking: + * none. + * Remarks: + */ + +static int +kdb_mdr(kdb_machreg_t addr, unsigned int count) +{ + kdb_machreg_t addr2 = addr; + unsigned int count2 = count; + + KDB_STATE_CLEAR(SUPPRESS); + while (count2--) { + kdba_getword(addr2++, 1); + if (KDB_STATE(SUPPRESS)) { + KDB_STATE_CLEAR(SUPPRESS); + return(0); /* Error message already printed */ + } + } + + while (count--) + kdb_printf("%02lx", kdba_getword(addr++, 1)); + kdb_printf("\n"); + return(0); +} + +/* + * kdb_md + * + * This function implements the 'md', 'mdr' and 'mds' commands. + * + * md|mds [ [ []]] + * mdr , + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_md(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + char fmtchar; + char fmtstr[64]; + int radix, count, width; + kdb_machreg_t addr; + unsigned long word; + long offset = 0; + kdb_symtab_t symtab; + int diag; + int nextarg; + int nosect = 0; + static kdb_machreg_t lastaddr; + static unsigned long lastcount; + static unsigned long lastradix; + char lastbuf[50]; + int symbolic = 0; + + /* + * Defaults in case the relevent environment variables are unset + */ + radix = 16; + count = 8; + width = sizeof(kdb_machreg_t); + + if (strcmp(argv[0], "mdr") == 0 && argc != 2) + return KDB_ARGCOUNT; + + if (argc == 0) { + if (lastaddr == 0) + return KDB_ARGCOUNT; + sprintf(lastbuf, kdb_machreg_fmt, lastaddr); + argv[1] = lastbuf; + argc = 1; + count = lastcount; + radix = lastradix; + } else { + kdb_machreg_t val; + + if (argc >= 2) { + + diag = kdbgetularg(argv[2], &val); + if (!diag) + count = (int) val; + } else { + diag = kdbgetintenv("MDCOUNT", &count); + } + + if (argc >= 3) { + diag = kdbgetularg(argv[3], &val); + if (!diag) + radix = (int) val; + } else { + diag = kdbgetintenv("RADIX",&radix); + } + } + + switch (radix) { + case 10: + fmtchar = 'd'; + break; + case 16: + fmtchar = 'x'; + break; + case 8: + fmtchar = 'o'; + break; + default: + return KDB_BADRADIX; + } + + kdbgetintenv("BYTESPERWORD", &width); + kdbgetintenv("NOSECT", &nosect); + + if (strcmp(argv[0], "mds") == 0) { + symbolic = 1; + width = sizeof(kdb_machreg_t); + } + + switch (width) { + case 8: + sprintf(fmtstr, "%%16.16l%c ", fmtchar); + break; + case 4: + sprintf(fmtstr, "%%8.8l%c ", fmtchar); + break; + case 2: + sprintf(fmtstr, "%%4.4l%c ", fmtchar); + break; + case 1: + sprintf(fmtstr, "%%2.2l%c ", fmtchar); + break; + default: + return KDB_BADWIDTH; + } + + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + if (strcmp(argv[0], "mdr") == 0) { + return(kdb_mdr(addr, count)); + } + + /* Round address down modulo BYTESPERWORD */ + + addr &= ~(width-1); + + /* + * Remember count and radix for next 'md' + */ + lastcount = count; + lastradix = radix; + + while (count--) { + int num = (symbolic?1 :(16 / width)); + char cbuf[32]; + char *c = cbuf; + char t; + int i; + + for(i=0; i argc) + return KDB_ARGCOUNT; + + diag = kdbgetaddrarg(argc, argv, &nextarg, &contents, NULL, NULL, regs); + if (diag) + return diag; + + if (nextarg != argc + 1) + return KDB_ARGCOUNT; + + /* + * To prevent modification of invalid addresses, check first. + */ + word = kdba_getword(addr, sizeof(word)); + if (KDB_STATE(SUPPRESS)) { + KDB_STATE_CLEAR(SUPPRESS); + return 0; + } + + diag = kdba_putword(addr, sizeof(contents), contents); + + kdb_printf(kdb_machreg_fmt " = " kdb_machreg_fmt "\n", addr, contents); + + return 0; +} + +/* + * kdb_go + * + * This function implements the 'go' command. + * + * go [address-expression] + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * KDB_CMD_GO for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_go(int argc, const char **argv, const char **envp, kdb_eframe_t ef) +{ + kdb_machreg_t addr; + int diag; + int nextarg; + long offset; + + if (argc == 1) { + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, + &addr, &offset, NULL, ef); + if (diag) + return diag; + + kdba_setpc(ef, addr); + } else if (argc) + return KDB_ARGCOUNT; + + return KDB_CMD_GO; +} + +/* + * kdb_rd + * + * This function implements the 'rd' command. + * + * rd display all general registers. + * rd c display all control registers. + * rd d display all debug registers. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_rd(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + /* + */ + + if (argc == 0) { + return kdba_dumpregs(regs, NULL, NULL); + } + + if (argc > 2) { + return KDB_ARGCOUNT; + } + + return kdba_dumpregs(regs, argv[1], argv[2]); +} + +/* + * kdb_rm + * + * This function implements the 'rm' (register modify) command. + * + * rm register-name new-contents + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Currently doesn't allow modification of control or + * debug registers, nor does it allow modification + * of model-specific registers (MSR). + */ + +int +kdb_rm(int argc, const char **argv, const char **envp, kdb_eframe_t ef) +{ + int diag; + int ind = 0; + kdb_machreg_t contents; + + if (argc != 2) { + return KDB_ARGCOUNT; + } + + /* + * Allow presence or absence of leading '%' symbol. + */ + + if (argv[1][0] == '%') + ind = 1; + + diag = kdbgetularg(argv[2], &contents); + if (diag) + return diag; + + diag = kdba_setregcontents(&argv[1][ind], ef, contents); + if (diag) + return diag; + + return 0; +} + +#if defined(CONFIG_MAGIC_SYSRQ) +/* + * kdb_sr + * + * This function implements the 'sr' (SYSRQ key) command which + * interfaces to the soi-disant MAGIC SYSRQ functionality. + * + * sr + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * None. + */ +int +kdb_sr(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + if (argc != 1) { + return KDB_ARGCOUNT; + } + + handle_sysrq(*argv[1], regs, 0, 0); + + return 0; +} +#endif /* CONFIG_MAGIC_SYSRQ */ + +/* + * kdb_ef + * + * This function implements the 'ef' (display exception frame) + * command. This command takes an address and expects to find + * an exception frame at that address, formats and prints it. + * + * ef address-expression + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Not done yet. + */ + +int +kdb_ef(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + kdb_machreg_t addr; + long offset; + int nextarg; + + if (argc == 1) { + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + return kdba_dumpregs((struct pt_regs *)addr, NULL, NULL); + } + + return KDB_ARGCOUNT; +} + +/* + * kdb_reboot + * + * This function implements the 'reboot' command. Reboot the system + * immediately. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Shouldn't return from this function. + */ + +int +kdb_reboot(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + machine_restart(0); + /* NOTREACHED */ + return 0; +} + + +#if defined(CONFIG_MODULES) +extern struct module *find_module(const char *); +extern void free_module(struct module *, int); + +/* + * kdb_lsmod + * + * This function implements the 'lsmod' command. Lists currently + * loaded kernel modules. + * + * Mostly taken from userland lsmod. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * + */ + +int +kdb_lsmod(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct module *mod; + struct module_ref *mr; + + if (argc != 0) + return KDB_ARGCOUNT; + + kdb_printf("Module Size modstruct Used by\n"); + for (mod = module_list; mod && mod->next ;mod = mod->next) { + kdb_printf("%-20s%8lu 0x%p %4ld ", mod->name, mod->size, (void *)mod, + (long)atomic_read(&mod->uc.usecount)); + + if (mod->flags & MOD_DELETED) + kdb_printf(" (deleted)"); + else if (mod->flags & MOD_INITIALIZING) + kdb_printf(" (initializing)"); + else if (!(mod->flags & MOD_RUNNING)) + kdb_printf(" (uninitialized)"); + else { + if (mod->flags & MOD_AUTOCLEAN) + kdb_printf(" (autoclean)"); + if (!(mod->flags & MOD_USED_ONCE)) + kdb_printf(" (unused)"); + } + + if (mod->refs) { + kdb_printf(" [ "); + + mr = mod->refs; + while (mr) { + kdb_printf("%s ", mr->ref->name); + mr = mr->next_ref; + } + + kdb_printf("]"); + } + + kdb_printf("\n"); + } + + return 0; +} + +/* + * kdb_rmmod + * + * This function implements the 'rmmod' command. Removes a given + * kernel module. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * Danger: free_module() calls mod->cleanup(). If the cleanup routine + * relies on interrupts then it will hang, kdb has interrupts disabled. + */ + +int +kdb_rmmod(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct module *mod; + + + if (argc != 1) + return KDB_ARGCOUNT; + + kdb_printf("Attempting to remove module: [%s]\n", argv[1]); + if ((mod = find_module(argv[1])) == NULL) { + kdb_printf("Unable to find a module by that name\n"); + return 0; + } + + if (mod->refs != NULL || __MOD_IN_USE(mod)) { + kdb_printf("Module is in use, unable to unload\n"); + return 0; + } + + free_module(mod, 0); + kdb_printf("Module successfully unloaded\n"); + + return 0; +} +#endif /* CONFIG_MODULES */ + +/* + * kdb_env + * + * This function implements the 'env' command. Display the current + * environment variables. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_env(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + + for(i=0; i<__nenv; i++) { + if (__env[i]) { + kdb_printf("%s\n", __env[i]); + } + } + + if (KDB_DEBUG(MASK)) + kdb_printf("KDBFLAGS=0x%x\n", kdb_flags); + + return 0; +} + +/* + * kdb_set + * + * This function implements the 'set' command. Alter an existing + * environment variable or create a new one. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_set(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + char *ep; + size_t varlen, vallen; + + /* + * we can be invoked two ways: + * set var=value argv[1]="var", argv[2]="value" + * set var = value argv[1]="var", argv[2]="=", argv[3]="value" + * - if the latter, shift 'em down. + */ + if (argc == 3) { + argv[2] = argv[3]; + argc--; + } + + if (argc != 2) + return KDB_ARGCOUNT; + + /* + * Check for internal variables + */ + if (strcmp(argv[1], "KDBDEBUG") == 0) { + unsigned int debugflags; + char *cp; + + debugflags = simple_strtoul(argv[2], &cp, 0); + if (cp == argv[2] || debugflags & ~KDB_DEBUG_FLAG_MASK) { + kdb_printf("kdb: illegal debug flags '%s'\n", + argv[2]); + return 0; + } + kdb_flags = (kdb_flags & ~(KDB_DEBUG_FLAG_MASK << KDB_DEBUG_FLAG_SHIFT)) + | (debugflags << KDB_DEBUG_FLAG_SHIFT); + + return 0; + } + + /* + * Tokenizer squashed the '=' sign. argv[1] is variable + * name, argv[2] = value. + */ + varlen = strlen(argv[1]); + vallen = strlen(argv[2]); + ep = kdballocenv(varlen + vallen + 2); + if (ep == (char *)0) + return KDB_ENVBUFFULL; + + sprintf(ep, "%s=%s", argv[1], argv[2]); + + ep[varlen+vallen+1]='\0'; + + for(i=0; i<__nenv; i++) { + if (__env[i] + && ((strncmp(__env[i], argv[1], varlen)==0) + && ((__env[i][varlen] == '\0') + || (__env[i][varlen] == '=')))) { + __env[i] = ep; + return 0; + } + } + + /* + * Wasn't existing variable. Fit into slot. + */ + for(i=0; i<__nenv-1; i++) { + if (__env[i] == (char *)0) { + __env[i] = ep; + return 0; + } + } + + return KDB_ENVFULL; +} + +/* + * kdb_cpu + * + * This function implements the 'cpu' command. + * + * cpu [] + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * KDB_CMD_CPU for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + * All cpu's should be spinning in kdb(). However just in case + * a cpu did not take the smp_kdb_stop NMI, check that a cpu + * entered kdb() before passing control to it. + */ + +int +kdb_cpu(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + unsigned long cpunum; + int diag; + + if (argc == 0) { + int i; + + kdb_printf("Currently on cpu %d\n", smp_processor_id()); + kdb_printf("Available cpus: "); + for (i=0; i NR_CPUS) + || !(cpu_online_map & (1UL << cpunum)) + || !KDB_STATE_CPU(KDB, cpunum)) + return KDB_BADCPUNUM; + + kdb_new_cpu = cpunum; + + /* + * Switch to other cpu + */ + return KDB_CMD_CPU; +} + +/* + * kdb_ps + * + * This function implements the 'ps' command which shows + * a list of the active processes. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_ps(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct task_struct *p; + + kdb_printf("%-*s Pid Parent [*] cpu State %-*s Command\n", + (int)(2*sizeof(void *))+2, "Task Addr", + (int)(2*sizeof(void *))+2, "Thread"); + for_each_task(p) { + kdb_printf("0x%p %08d %08d %1.1d %3.3d %s 0x%p%c%s\n", + (void *)p, p->pid, p->p_pptr->pid, + p->has_cpu, p->processor, + (p->state == 0)?"run ":(p->state>0)?"stop":"unrn", + (void *)(&p->thread), + (p == current) ? '*': ' ', + p->comm); + } + + return 0; +} + +/* + * kdb_ll + * + * This function implements the 'll' command which follows a linked + * list and executes an arbitrary command for each element. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_ll(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int diag; + kdb_machreg_t addr; + long offset = 0; + kdb_machreg_t va; + unsigned long linkoffset; + int nextarg; + + if (argc != 3) { + return KDB_ARGCOUNT; + } + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + diag = kdbgetularg(argv[2], &linkoffset); + if (diag) + return diag; + + /* + * Using the starting address as + * the first element in the list, and assuming that + * the list ends with a null pointer. + */ + + va = addr; + + while (va) { + char buf[80]; + + sprintf(buf, "%s " kdb_machreg_fmt "\n", argv[3], va); + diag = kdb_parse(buf, regs); + if (diag) + return diag; + + addr = va + linkoffset; + va = kdba_getword(addr, sizeof(va)); + if (KDB_STATE(SUPPRESS)) { + KDB_STATE_CLEAR(SUPPRESS); + return 0; + } + } + + return 0; +} + +/* + * kdb_sections_callback + * + * Invoked from kallsyms_sections for each section. + * + * Inputs: + * prevmod Previous module name + * modname Module name + * secname Section name + * secstart Start of section + * secend End of section + * secflags Section flags + * Outputs: + * None. + * Returns: + * Always zero + * Locking: + * none. + * Remarks: + */ + +static int +kdb_sections_callback(void *token, const char *modname, const char *secname, + ElfW(Addr) secstart, ElfW(Addr) secend, ElfW(Word) secflags) +{ + const char **prevmod = (const char **)token; + if (*prevmod != modname) { + *prevmod = modname; + kdb_printf("\n%s", modname); + } + kdb_printf(" %s " kdb_elfw_addr_fmt0 " " kdb_elfw_addr_fmt0 " 0x%x", + secname, secstart, secend, secflags); + return(0); +} + +/* + * kdb_sections + * + * This function implements the 'sections' command which prints the + * kernel and module sections. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * Always zero + * Locking: + * none. + * Remarks: + */ + +int +kdb_sections(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + char *prev_mod = NULL; + if (argc != 0) { + return KDB_ARGCOUNT; + } + kallsyms_sections(&prev_mod, kdb_sections_callback); + kdb_printf("\n"); /* End last module */ + return(0); +} + +/* + * kdb_help + * + * This function implements the 'help' and '?' commands. + * + * Inputs: + * argc argument count + * argv argument vector + * envp environment vector + * regs registers at time kdb was entered. + * Outputs: + * None. + * Returns: + * zero for success, a kdb diagnostic if error + * Locking: + * none. + * Remarks: + */ + +int +kdb_help(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + kdbtab_t *kt; + + kdb_printf("%-15.15s %-20.20s %s\n", "Command", "Usage", "Description"); + kdb_printf("----------------------------------------------------------\n"); + for(kt=kdb_commands; kt->cmd_name; kt++) { + kdb_printf("%-15.15s %-20.20s %s\n", kt->cmd_name, + kt->cmd_usage, kt->cmd_help); + } + return 0; +} + +/* + * kdb_register + * + * This function is used to register a kernel debugger command. + * + * Inputs: + * cmd Command name + * func Function to execute the command + * usage A simple usage string showing arguments + * help A simple help string describing command + * Outputs: + * None. + * Returns: + * zero for success, one if a duplicate command. + * Locking: + * none. + * Remarks: + * + */ + +int +kdb_register(char *cmd, + kdb_func_t func, + char *usage, + char *help, + short minlen) +{ + int i; + kdbtab_t *kp; + + /* + * Brute force method to determine duplicates + */ + for (i=0, kp=kdb_commands; icmd_name && (strcmp(kp->cmd_name, cmd)==0)) { + kdb_printf("Duplicate kdb command registered: '%s'\n", + cmd); + return 1; + } + } + + /* + * Insert command into first available location in table + */ + for (i=0, kp=kdb_commands; icmd_name == NULL) { + kp->cmd_name = cmd; + kp->cmd_func = func; + kp->cmd_usage = usage; + kp->cmd_help = help; + kp->cmd_flags = 0; + kp->cmd_minlen = minlen; + break; + } + } + return 0; +} + +/* + * kdb_unregister + * + * This function is used to unregister a kernel debugger command. + * It is generally called when a module which implements kdb + * commands is unloaded. + * + * Inputs: + * cmd Command name + * Outputs: + * None. + * Returns: + * zero for success, one command not registered. + * Locking: + * none. + * Remarks: + * + */ + +int +kdb_unregister(char *cmd) +{ + int i; + kdbtab_t *kp; + + /* + * find the command. + */ + for (i=0, kp=kdb_commands; icmd_name && (strcmp(kp->cmd_name, cmd)==0)) { + kp->cmd_name = NULL; + return 0; + } + } + + /* + * Couldn't find it. + */ + return 1; +} + +/* + * kdb_inittab + * + * This function is called by the kdb_init function to initialize + * the kdb command table. It must be called prior to any other + * call to kdb_register. + * + * Inputs: + * None. + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * + */ + +static void __init +kdb_inittab(void) +{ + int i; + kdbtab_t *kp; + + for(i=0, kp=kdb_commands; i < KDB_MAX_COMMANDS; i++,kp++) { + kp->cmd_name = NULL; + } + + kdb_register("md", kdb_md, "", "Display Memory Contents", 1); + kdb_register("mdr", kdb_md, " ", "Display Raw Memory", 0); + kdb_register("mds", kdb_md, "", "Display Memory Symbolically", 0); + kdb_register("mm", kdb_mm, " ", "Modify Memory Contents", 0); + kdb_register("id", kdb_id, "", "Display Instructions", 1); + kdb_register("go", kdb_go, "[]", "Continue Execution", 1); + kdb_register("rd", kdb_rd, "", "Display Registers", 1); + kdb_register("rm", kdb_rm, " ", "Modify Registers", 0); + kdb_register("ef", kdb_ef, "", "Display exception frame", 0); + kdb_register("bt", kdb_bt, "[]", "Stack traceback", 1); + kdb_register("btp", kdb_bt, "", "Display stack for process ", 0); + kdb_register("bta", kdb_bt, "", "Display stack all processes", 0); + kdb_register("ll", kdb_ll, " ", "Execute cmd for each element in linked list", 0); + kdb_register("env", kdb_env, "", "Show environment variables", 0); + kdb_register("set", kdb_set, "", "Set environment variables", 0); + kdb_register("help", kdb_help, "", "Display Help Message", 1); + kdb_register("?", kdb_help, "", "Display Help Message", 0); + kdb_register("cpu", kdb_cpu, "","Switch to new cpu", 0); + kdb_register("ps", kdb_ps, "", "Display active task list", 0); + kdb_register("reboot", kdb_reboot, "", "Reboot the machine immediately", 0); + kdb_register("sections", kdb_sections, "", "List kernel and module sections", 0); +#if defined(CONFIG_MODULES) + kdb_register("lsmod", kdb_lsmod, "", "List loaded kernel modules", 0); + kdb_register("rmmod", kdb_rmmod, "", "Remove a kernel module", 1); +#endif +#if defined(CONFIG_MAGIC_SYSRQ) + kdb_register("sr", kdb_sr, "", "Magic SysRq key", 0); +#endif +} + +/* + * kdb_cmd_init + * + * This function is called by the kdb_init function to execute any + * commands defined in kdb_cmds. + * + * Inputs: + * Commands in *kdb_cmds[]; + * Outputs: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * + */ + +static void __init +kdb_cmd_init(void) +{ + int i, diag; + for (i = 0; kdb_cmds[i]; ++i) { + kdb_printf("kdb_cmd[%d]: %s", i, kdb_cmds[i]); + diag = kdb_parse(kdb_cmds[i], NULL); + if (diag) + kdb_printf("command failed, kdb diag %d\n", diag); + } +} + +/* + * kdb_panic + * + * Invoked via the panic_notifier_list. + * + * Inputs: + * None. + * Outputs: + * None. + * Returns: + * Zero. + * Locking: + * None. + * Remarks: + * When this function is called from panic(), the other cpus have already + * been stopped. + * + */ + +static int +kdb_panic(struct notifier_block *self, unsigned long command, void *ptr) +{ + kdb(KDB_REASON_PANIC, 0, NULL); + return(0); +} + +static struct notifier_block kdb_block = { kdb_panic, NULL, 0 }; + +/* + * kdb_init + * + * Initialize the kernel debugger environment. + * + * Parameters: + * None. + * Returns: + * None. + * Locking: + * None. + * Remarks: + * None. + */ + +void __init +kdb_init(void) +{ + /* + * This must be called before any calls to kdb_printf. + */ + kdb_io_init(); + + kdb_inittab(); /* Initialize Command Table */ + kdb_initbptab(); /* Initialize Breakpoint Table */ + kdb_id_init(); /* Initialize Disassembler */ + kdba_init(); /* Architecture Dependent Initialization */ + + /* + * Use printk() to get message in log_buf[]; + */ + printk("kdb version %d.%d%s by Scott Lurndal, Keith Owens. "\ + "Copyright SGI, All Rights Reserved\n", + KDB_MAJOR_VERSION, KDB_MINOR_VERSION, KDB_TEST_VERSION); + + kdb_cmd_init(); /* Preset commands from kdb_cmds */ + kdb(KDB_REASON_SILENT, 0, 0); /* Activate any preset breakpoints on boot cpu */ + notifier_chain_register(&panic_notifier_list, &kdb_block); +} + +EXPORT_SYMBOL(kdb_register); +EXPORT_SYMBOL(kdb_unregister); +EXPORT_SYMBOL(kdba_getword); +EXPORT_SYMBOL(kdba_putword); +EXPORT_SYMBOL(kdbgetularg); +EXPORT_SYMBOL(kdbgetenv); +EXPORT_SYMBOL(kdbgetintenv); +EXPORT_SYMBOL(kdbgetaddrarg); +EXPORT_SYMBOL(kdb); +EXPORT_SYMBOL(kdb_on); +EXPORT_SYMBOL(kdbgetsymval); +EXPORT_SYMBOL(kdbnearsym); +EXPORT_SYMBOL(kdb_printf); +EXPORT_SYMBOL(kdb_symbol_print); diff -rNu linux-2.4.7/linux/kdb/kdbsupport.c linux-2.4-xfs/linux/kdb/kdbsupport.c --- linux-2.4.7/linux/kdb/kdbsupport.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/kdbsupport.c Mon Apr 2 12:13:32 2001 @@ -0,0 +1,472 @@ +/* + * Kernel Debugger Architecture Independent Support Functions + * + * Copyright (C) 1999 Silicon Graphics, Inc. + * Copyright (C) Scott Lurndal (slurn@engr.sgi.com) + * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com) + * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com) + * + * See the file LIA-COPYRIGHT for additional information. + * + * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc. + * + * Modifications from: + * Richard Bass 1999/07/20 + * Many bug fixes and enhancements. + * Scott Foehner + * Port to ia64 + * Scott Lurndal 1999/12/12 + * v1.0 restructuring. + * Keith Owens 2000/05/23 + * KDB v1.2 + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * Symbol table functions. + */ + +/* + * kdbgetsymval + * + * Return the address of the given symbol. + * + * Parameters: + * symname Character string containing symbol name + * symtab Structure to receive results + * Outputs: + * Returns: + * 0 Symbol not found, symtab zero filled + * 1 Symbol mapped to module/symbol/section, data in symtab + * Locking: + * None. + * Remarks: + */ + +int +kdbgetsymval(const char *symname, kdb_symtab_t *symtab) +{ + memset(symtab, 0, sizeof(*symtab)); + return(kallsyms_symbol_to_address( + symname, + NULL, + &symtab->mod_name, + &symtab->mod_start, + &symtab->mod_end, + &symtab->sec_name, + &symtab->sec_start, + &symtab->sec_end, + &symtab->sym_name, + &symtab->sym_start, + &symtab->sym_end)); +} + +/* + * kdbnearsym + * + * Return the name of the symbol with the nearest address + * less than 'addr'. + * + * Parameters: + * addr Address to check for symbol near + * symtab Structure to receive results + * Outputs: + * Returns: + * 0 No sections contain this address, symtab zero filled + * 1 Address mapped to module/symbol/section, data in symtab + * Locking: + * None. + * Remarks: + */ + +int +kdbnearsym(unsigned long addr, kdb_symtab_t *symtab) +{ + memset(symtab, 0, sizeof(*symtab)); + return(kallsyms_address_to_symbol( + addr, + &symtab->mod_name, + &symtab->mod_start, + &symtab->mod_end, + &symtab->sec_name, + &symtab->sec_start, + &symtab->sec_end, + &symtab->sym_name, + &symtab->sym_start, + &symtab->sym_end)); +} + +#if defined(CONFIG_SMP) +/* + * kdb_ipi + * + * This function is called from the non-maskable interrupt + * handler to handle a kdb IPI instruction. + * + * Inputs: + * ef = Exception frame pointer + * Outputs: + * None. + * Returns: + * 0 - Did not handle NMI + * 1 - Handled NMI + * Locking: + * None. + * Remarks: + * Initially one processor is invoked in the kdb() code. That + * processor sends an ipi which drives this routine on the other + * processors. All this does is call kdb() with reason SWITCH. + * This puts all processors into the kdb() routine and all the + * code for breakpoints etc. is in one place. + * One problem with the way the kdb NMI is sent, the NMI has no + * identification that says it came from kdb. If the cpu's kdb state is + * marked as "waiting for kdb_ipi" then the NMI is treated as coming from + * kdb, otherwise it is assumed to be for another reason and is ignored. + */ + +int +kdb_ipi(kdb_eframe_t ef, void (*ack_interrupt)(void)) +{ + /* Do not print before checking and clearing WAIT_IPI, IPIs are + * going all the time. + */ + if (KDB_STATE(WAIT_IPI)) { + /* + * Stopping other processors via smp_kdb_stop(). + */ + if (ack_interrupt) + (*ack_interrupt)(); /* Acknowledge the interrupt */ + KDB_STATE_CLEAR(WAIT_IPI); + KDB_DEBUG_STATE("kdb_ipi 1", 0); + kdb(KDB_REASON_SWITCH, 0, ef); /* Spin in kdb() */ + KDB_DEBUG_STATE("kdb_ipi 2", 0); + return 1; + } + return 0; +} +#endif /* CONFIG_SMP */ + +void +kdb_enablehwfault(void) +{ + kdba_enable_mce(); +} + +/* + * kdb_get_next_ar + * + * Get the next activation record from the stack. + * + * Inputs: + * arend Last byte +1 of the activation record. sp for the first + * frame, start of callee's activation record otherwise. + * func Start address of function. + * pc Current program counter within this function. pc for + * the first frame, caller's return address otherwise. + * fp Current frame pointer. Register fp for the first + * frame, oldfp otherwise. 0 if not known. + * ss Start of stack for the current process. + * Outputs: + * ar Activation record. + * symtab kallsyms symbol table data for the calling function. + * Returns: + * 1 if ar is usable, 0 if not. + * Locking: + * None. + * Remarks: + * Activation Record format, assuming a stack that grows down + * (KDB_STACK_DIRECTION == -1). + * + * +-----------------------------+ ^ ===================== + * | Return address, frame 3 | | + * +-----------------------------+ | + * | Frame Pointer, frame 3 |>--' + * +-----------------------------+<--. + * | Locals and automatics, | | + * | frame 2. (variable size) | | AR 2 + * +-----------------------------+ | + * | Save registers, | | + * | frame 2. (variable size) | | + * +-----------------------------+ | + * | Arguments to frame 1, | | + * | (variable size) | | + * +-----------------------------+ | ===================== + * | Return address, frame 2 | | + * +-----------------------------+ | + * | Frame Pointer, frame 2 |>--' + * +-----------------------------+<--. + * | Locals and automatics, | | + * | frame 1. (variable size) | | AR 1 + * +-----------------------------+ | + * | Save registers, | | + * | frame 1. (variable size) | | + * +-----------------------------+ | + * | Arguments to frame 0, | | + * | (variable size) | | + * +-----------------------------+ | -- (5) ===================== + * | Return address, frame 1 | | + * +-----------------------------+ | -- (0) + * | Frame Pointer, frame 1 |>--' + * +-----------------------------+ -- (1), (2) + * | Locals and automatics, | + * | frame 0. (variable size) | AR 0 + * +-----------------------------+ -- (3) + * | Save registers, | + * | frame 0. (variable size) | + * +-----------------------------+ -- (4) ===================== + * + * The stack for the top frame can be in one of several states. + * (0) Immediately on entry to the function, stack pointer (sp) is + * here. + * (1) If the function was compiled with frame pointers and the 'push + * fp' instruction has been executed then the pointer to the + * previous frame is on the stack. However there is no guarantee + * that this saved pointer is valid, the calling function might + * not have frame pointers. sp is adjusted by wordsize after + * 'push fp'. + * (2) If the function was compiled with frame pointers and the 'copy + * sp to fp' instruction has been executed then fp points here. + * (3) If the function startup has 'adjust sp by 0xnn bytes' and that + * instruction has been executed then sp has been adjusted by + * 0xnn bytes for local and automatic variables. + * (4) If the function startup has one or more 'push reg' instructions + * and any have been executed then sp has been adjusted by + * wordsize bytes for each register saved. + * + * As the function exits it rewinds the stack, typically to (1) then (0). + * + * The stack entries for the lower frames is normally are in state (5). + * (5) Arguments for the called frame are on to the stack. + * However lower frames can be incomplete if there is an interrupt in + * progress. + * + * An activation record runs from the return address for a function + * through to the return address for the next function or sp, whichever + * comes first. For each activation record we extract :- + * + * start Address of the activation record. + * end Address of the last byte+1 in the activation record. + * ret Return address to caller. + * oldfp Frame pointer to previous frame, 0 if this function was + * not compiled with frame pointers. + * fp Frame pointer for the current frame, 0 if this function + * was not compiled with frame pointers or fp has not been + * set yet. + * arg0 Address of the first argument (in the previous activation + * record). + * locals Bytes allocated to locals and automatics. + * regs Bytes allocated to saved registers. + * args Bytes allocated to arguments (in the previous activation + * record). + * setup Bytes allocated to setup data on stack (return address, + * frame pointer). + * + * Although the kernel might be compiled with frame pointers, we still + * have to assume the worst and validate the frame. Some calls from + * asm code to C code might not use frame pointers. Third party binary + * only modules might be compiled without frame pointers, even when the + * rest of the kernel has frame pointers. Some routines are always + * compiled with frame pointers, even if the overall kernel is not. A + * routine compiled with frame pointers can be called from a routine + * without frame pointers, the previous "frame pointer" is saved on + * stack but it contains garbage. + * + * We check the object code to see if it saved a frame pointer and we + * validate that pointer. Basically frame pointers are hints. + */ + +#define FORCE_ARG(ar,n) (ar)->setup = (ar)->locals = (ar)->regs = \ + (ar)->fp = (ar)->oldfp = (ar)->ret = 0; \ + (ar)->start = (ar)->end - KDB_STACK_DIRECTION*(n)*sizeof(unsigned long); + +int +kdb_get_next_ar(kdb_machreg_t arend, kdb_machreg_t func, + kdb_machreg_t pc, kdb_machreg_t fp, kdb_machreg_t ss, + kdb_ar_t *ar, kdb_symtab_t *symtab) +{ + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: arend=0x%lx func=0x%lx pc=0x%lx fp=0x%lx\n", + arend, func, pc, fp); + } + + memset(ar, 0, sizeof(*ar)); + if (!kdbnearsym(pc, symtab)) { + symtab->sym_name = symtab->sec_name = ""; + symtab->mod_name = "kernel"; + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: callee not in kernel\n"); + } + pc = 0; + } + + if (!kdba_prologue(symtab, pc, arend, fp, ss, 0, ar)) { + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: callee prologue failed\n"); + } + return(0); + } + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: callee activation record\n"); + kdb_printf(" start=0x%lx end=0x%lx ret=0x%lx oldfp=0x%lx fp=0x%lx\n", + ar->start, ar->end, ar->ret, ar->oldfp, ar->fp); + kdb_printf(" locals=%d regs=%d setup=%d\n", + ar->locals, ar->regs, ar->setup); + } + + if (ar->ret) { + /* Run the caller code to get arguments to callee function */ + kdb_symtab_t caller_symtab; + kdb_ar_t caller_ar; + memset(&caller_ar, 0, sizeof(caller_ar)); + if (!kdbnearsym(ar->ret, &caller_symtab)) { + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: caller not in kernel\n"); + } + } else if (kdba_prologue(&caller_symtab, ar->ret, + ar->start, ar->oldfp, ss, 1, &caller_ar)) { + /* some caller data extracted */ ; + } else if (strcmp(symtab->sym_name, "do_exit") == 0) { + /* non-standard caller, force one argument */ + FORCE_ARG(&caller_ar, 1); + } else if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: caller prologue failed\n"); + } + if (KDB_DEBUG(AR)) { + kdb_printf("kdb_get_next_ar: caller activation record\n"); + kdb_printf(" start=0x%lx end=0x%lx ret=0x%lx" + " oldfp=0x%lx fp=0x%lx\n", + caller_ar.start, caller_ar.end, caller_ar.ret, + caller_ar.oldfp, caller_ar.fp); + kdb_printf(" locals=%d regs=%d args=%d setup=%d\n", + caller_ar.locals, caller_ar.regs, + caller_ar.args, caller_ar.setup); + } + if (caller_ar.start) { + ar->args = KDB_STACK_DIRECTION*(caller_ar.end - caller_ar.start) - + (caller_ar.setup + caller_ar.locals + caller_ar.regs); + if (ar->args < 0) + ar->args = 0; + if (ar->args) { + ar->arg0 = ar->start - + KDB_STACK_DIRECTION*(ar->args - 4); + if (KDB_DEBUG(AR)) { + kdb_printf(" callee arg0=0x%lx args=%d\n", + ar->arg0, ar->args); + } + } + } + } + + return(1); +} + +/* + * kdb_symbol_print + * + * Standard method for printing a symbol name and offset. + * Inputs: + * addr Address to be printed. + * symtab Address of symbol data, if NULL this routine does its + * own lookup. + * punc Punctuation for string, bit field. + * Outputs: + * None. + * Returns: + * Always 0. + * Locking: + * none. + * Remarks: + * The string and its punctuation is only printed if the address + * is inside the kernel, except that the value is always printed + * when requested. + */ + +void +kdb_symbol_print(kdb_machreg_t addr, const kdb_symtab_t *symtab_p, unsigned int punc) +{ + kdb_symtab_t symtab, *symtab_p2; + if (symtab_p) { + symtab_p2 = (kdb_symtab_t *)symtab_p; + } + else { + symtab_p2 = &symtab; + kdbnearsym(addr, symtab_p2); + } + if (symtab_p2->sym_name || (punc & KDB_SP_VALUE)) { + ; /* drop through */ + } + else { + return; + } + if (punc & KDB_SP_SPACEB) { + kdb_printf(" "); + } + if (punc & KDB_SP_VALUE) { + kdb_printf(kdb_machreg_fmt0, addr); + } + if (!symtab_p2->sym_name) { + return; + } + if (punc & KDB_SP_VALUE) { + kdb_printf(" "); + } + if (punc & KDB_SP_PAREN) { + kdb_printf("("); + } + if (strcmp(symtab_p2->mod_name, "kernel")) { + kdb_printf("[%s]", symtab_p2->mod_name); + } + kdb_printf("%s", symtab_p2->sym_name); + if (addr != symtab_p2->sym_start) { + kdb_printf("+0x%lx", addr - symtab_p2->sym_start); + } + if (punc & KDB_SP_SYMSIZE) { + kdb_printf("/0x%lx", symtab_p2->sym_end - symtab_p2->sym_start); + } + if (punc & KDB_SP_PAREN) { + kdb_printf(")"); + } + if (punc & KDB_SP_SPACEA) { + kdb_printf(" "); + } + if (punc & KDB_SP_NEWLINE) { + kdb_printf("\n"); + } +} + +/* + * kdb_strdup + * + * kdb equivalent of strdup, for disasm code. + * Inputs: + * str The string to duplicate. + * type Flags to kmalloc for the new string. + * Outputs: + * None. + * Returns: + * Address of the new string, NULL if storage could not be allocated. + * Locking: + * none. + * Remarks: + * This is not in lib/string.c because it uses kmalloc which is not + * available when string.o is used in boot loaders. + */ + +char *kdb_strdup(const char *str, int type) +{ + int n = strlen(str)+1; + char *s = kmalloc(n, type); + if (!s) return NULL; + return strcpy(s, str); +} diff -rNu linux-2.4.7/linux/kdb/modules/CVS/Entries linux-2.4-xfs/linux/kdb/modules/CVS/Entries --- linux-2.4.7/linux/kdb/modules/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/modules/CVS/Entries Thu Jul 5 12:07:01 2001 @@ -0,0 +1,4 @@ +/Makefile/1.9/Thu Dec 21 05:48:12 2000/-ko/ +/kdbm_pg.c/1.38/Tue May 29 19:53:13 2001/-ko/ +/kdbm_vm.c/1.9/Wed Oct 4 11:42:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/kdb/modules/CVS/Repository linux-2.4-xfs/linux/kdb/modules/CVS/Repository --- linux-2.4.7/linux/kdb/modules/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/modules/CVS/Repository Thu Jul 5 12:07:01 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/kdb/modules diff -rNu linux-2.4.7/linux/kdb/modules/CVS/Root linux-2.4-xfs/linux/kdb/modules/CVS/Root --- linux-2.4.7/linux/kdb/modules/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/modules/CVS/Root Thu Jul 5 12:07:01 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/kdb/modules/Makefile linux-2.4-xfs/linux/kdb/modules/Makefile --- linux-2.4.7/linux/kdb/modules/Makefile Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/modules/Makefile Wed Dec 20 23:48:12 2000 @@ -0,0 +1,15 @@ +# +# Makefile for i386-specific kdb files.. +# +# Copyright 1999, Silicon Graphics Inc. +# +# Written April 1999 by Scott Lurndal at Silicon Graphics, Inc. +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +obj-m := kdbm_vm.o kdbm_pg.o + +include $(TOPDIR)/Rules.make diff -rNu linux-2.4.7/linux/kdb/modules/kdbm_pg.c linux-2.4-xfs/linux/kdb/modules/kdbm_pg.c --- linux-2.4.7/linux/kdb/modules/kdbm_pg.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/modules/kdbm_pg.c Tue May 29 14:53:13 2001 @@ -0,0 +1,876 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef KDB_DO_PAGEBUF +#if defined(CONFIG_PAGE_BUF) || defined(CONFIG_PAGE_BUF_MODULE) +#define KDB_DO_PAGEBUF +#define _PAGE_BUF_INTERNAL_ 1 +#include +#endif /* CONFIG_PAGE_BUF || CONFIG_PAGE_BUF_MODULE */ + +/* Standard Linux page stuff */ + +static char *pg_flag_vals[] = { + "PG_locked", "PG_error", "PG_referenced", "PG_uptodate", "PG_dirty", + "PG_decr_after", "PG_active", "PG_inactive_dirty", + "PG_Slab", "PG_swap_cache", "PG_skip", "PG_inactive_clean", + "PG_highmem", "PG_delalloc", + "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", + NULL }; + +static char *bh_state_vals[] = { + "Uptodate", "Dirty", "Lock", "Req", "Mapped", "New", + "Protected", "Delay", NULL }; + +static char *inode_flag_vals[] = { + "I_DIRTY_SYNC", "I_DIRTY_DATASYNC", "I_DIRTY_PAGES", "I_LOCK", "I_FREEING", "I_CLEAR", "I_NEW", NULL}; + +static char *map_flags(unsigned long flags, char *mapping[]) +{ + static char buffer[256]; + int index; + int offset = 12; + + buffer[0] = '\0'; + + for (index = 0; flags && mapping[index]; flags >>= 1, index++) { + if (flags & 1) { + if ((offset + strlen(mapping[index]) + 1) >= 80) { + strcat(buffer, "\n "); + offset = 12; + } else if (offset > 12) { + strcat(buffer, " "); + offset++; + } + strcat(buffer, mapping[index]); + offset += strlen(mapping[index]); + } + } + + return (buffer); +} + +static char *page_flags(unsigned long flags) +{ + return(map_flags(flags, pg_flag_vals)); +} + +static int +kdbm_buffers(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct buffer_head bh; + unsigned char *p = (unsigned char *)&bh; + unsigned long addr; + long offset=0; + int nextarg; + int diag; + int i; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + for (i = 0; i < sizeof(struct buffer_head); i++) { + *p++ = kdba_getword(addr+i, 1); + } + + kdb_printf("buffer_head at 0x%lx\n", addr); + kdb_printf(" next 0x%p bno %ld rsec %ld size %d dev 0x%x rdev 0x%x\n", + bh.b_next, bh.b_blocknr, bh.b_rsector, + bh.b_size, bh.b_dev, bh.b_rdev); + kdb_printf(" count %d state 0x%lx [%s] ftime 0x%lx b_list %d b_reqnext 0x%p b_data 0x%p\n", + bh.b_count.counter, bh.b_state, map_flags(bh.b_state, bh_state_vals), + bh.b_flushtime, bh.b_list, bh.b_reqnext, bh.b_data); + kdb_printf(" b_page 0x%p b_this_page 0x%p b_private 0x%p\n", + bh.b_page, bh.b_this_page, bh.b_private); + + return 0; +} + +static int +kdbm_page(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct page page; + unsigned char *p = (unsigned char *)&page; + unsigned long addr; + long offset=0; + int nextarg; + int diag; + int i; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + if (addr < PAGE_OFFSET) { + printk("Treating 0x%lx as page index, page at 0x%p\n", + addr, &mem_map[addr]); + addr = (unsigned long) &mem_map[addr]; + } + + for (i = 0; i < sizeof(struct page); i++) { + *p++ = kdba_getword(addr+i, 1); + } + + kdb_printf("struct page at 0x%lx\n", addr); + kdb_printf(" next 0x%p prev 0x%p addr space 0x%p index %lu (offset 0x%x)\n", + page.list.next, page.list.prev, page.mapping, page.index, + (int)(page.index << PAGE_CACHE_SHIFT)); + kdb_printf(" count %d age %ld flags %s virtual 0x%p\n", + page.count.counter, page.age, page_flags(page.flags), + page.virtual); + kdb_printf(" buffers 0x%p\n", page.buffers); + + return 0; +} + +unsigned long +print_request(unsigned long addr) +{ + struct request rq; + unsigned char *p = (unsigned char *)&rq; + int i; + + for (i = 0; i < sizeof(struct request); i++) { + *p++ = kdba_getword(addr+i, 1); + } + + kdb_printf("struct request at 0x%lx\n", addr); + kdb_printf(" rq_dev 0x%x cmd %d errors %d sector %ld nr_sectors %ld\n", + rq.rq_dev, rq.cmd, rq.errors, rq.sector, + rq.nr_sectors); + + kdb_printf(" hsect %ld hnrsect %ld nrseg %d nrhwseg %d currnrsect %ld seq %d\n", + rq.hard_sector, rq.hard_nr_sectors, + rq.nr_segments, rq.nr_hw_segments, + rq.current_nr_sectors, rq.elevator_sequence); + kdb_printf(" "); +#ifdef STRUCT_REQUEST_HAS_KIOBUF + kdb_printf("kiobuf 0x%p ", rq.kiobuf); +#endif /* STRUCT_REQUEST_HAS_KIOBUF */ + kdb_printf("bh 0x%p bhtail 0x%p req_q 0x%p\n\n", + rq.bh, rq.bhtail, rq.q); + + return (unsigned long) rq.queue.next; +} + +#ifdef KDB_DO_PAGEBUF +static int +kdbm_request(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + long offset=0; + unsigned long addr; + int nextarg; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + print_request(addr); + return 0; +} + + +static int +kdbm_rqueue(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct request_queue rq; + unsigned char *p = (unsigned char *)&rq; + unsigned long addr, head_addr, next; + long offset=0; + int nextarg; + int diag; + int i; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + for (i = 0; i < sizeof(struct request_queue); i++) { + *p++ = kdba_getword(addr+i, 1); + } + + kdb_printf("struct request_queue at 0x%lx [%s]\n", addr, + rq.plugged ? "plugged" : "running"); + kdb_printf(" read free_list [0x%p, 0x%p]\n", + rq.request_freelist[READ].prev, + rq.request_freelist[READ].next); + kdb_printf(" write free_list [0x%p, 0x%p]\n", + rq.request_freelist[WRITE].prev, + rq.request_freelist[WRITE].next); + + i = 0; + next = (unsigned long)rq.queue_head.next; + head_addr = addr + offsetof(struct request_queue, queue_head); + kdb_printf(" request queue: %s\n", next == head_addr ? + "empty" : ""); + while (next != head_addr) { + i++; + next = print_request(next); + } + + if (i) + kdb_printf("%d requests found\n", i); + + return 0; +} +#endif /* KDB_DO_PAGEBUF */ + + +static void +do_buffer(unsigned long addr) +{ + struct buffer_head bh; + unsigned char *p = (unsigned char *)&bh; + int i; + + for (i = 0; i < sizeof(struct buffer_head); i++) { + *p++ = kdba_getword(addr+i, 1); + } + + kdb_printf("buffer 0x%lx bno %ld [ %s ]\n", addr, bh.b_blocknr, + map_flags(bh.b_state, bh_state_vals)); +} + +static int +kdbm_inode_pages(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct inode inode; + struct address_space ap; + unsigned char *p = (unsigned char *)&inode; + unsigned long addr, addr1 = 0; + long offset=0; + int nextarg; + int diag; + int i, j; + int which=0; + + struct list_head *head, *curr; + + if (argc < 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + if (argc == 2) { + nextarg = 2; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr1, + &offset, NULL, regs); + if (diag) + return diag; + kdb_printf("Looking for page index 0x%lx ... \n", addr1); + } + + for (i = 0; i < sizeof(struct inode); i++) { + *p++ = kdba_getword(addr+i, 1); + } + + addr = (unsigned long) inode.i_mapping; + p = (unsigned char *)≈ + + for (i = 0; i < sizeof(struct address_space); i++) { + *p++ = kdba_getword(addr+i, 1); + } + + if (!&inode.i_mapping) goto out; + again: + if (which == 0){ + which=1; + head = &inode.i_mapping->clean_pages; + kdb_printf("clean page_struct index cnt flags\n"); + } else if (which == 1) { + which=2; + head = &inode.i_mapping->dirty_pages; + kdb_printf("dirty page_struct index cnt flags\n"); + } else if (which == 2) { + which=3; + head = &inode.i_mapping->locked_pages; + kdb_printf("locked page_struct index cnt flags\n"); + } else { + goto out; + } + + if(!head) goto again; + curr = head->next; + while (curr != head) { + struct page page; + struct list_head curr_struct; + + addr = (unsigned long) list_entry(curr, struct page, list); + p = (unsigned char *)&page; + + for (j = 0; j < sizeof(struct page); j++) + *p++ = kdba_getword(addr+j, 1); + + if (!addr1 || page.index == addr1 || + (addr1 == -1 && (page.flags & ( 1 << PG_locked)))) + { + kdb_printf(" 0x%lx %lu %d 0x%lx ", + addr, page.index, page.count.counter, + page.flags); + if (page.buffers) + do_buffer((unsigned long) page.buffers); + else + kdb_printf("UNMAPPED\n"); + } + + addr = (unsigned long) curr; + p = (unsigned char *)&curr_struct; + for (j = 0; j < sizeof(struct list_head); j++) + *p++ = kdba_getword(addr+j, 1); + + curr = curr_struct.next; + } + goto again; + out: + return 0; +} + +static int +kdbm_inode(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct inode inode; + unsigned char *p = (unsigned char *)&inode; + unsigned long addr; + unsigned char *iaddr; + long offset=0; + int nextarg; + int diag; + int i; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + for (i = 0; i < sizeof(struct inode); i++) { + *p++ = kdba_getword(addr+i, 1); + } + + kdb_printf("struct inode at 0x%lx\n", addr); + + kdb_printf(" i_ino = %lu i_count = %u i_dev = 0x%x i_size %Ld\n", + inode.i_ino, atomic_read(&inode.i_count), + inode.i_dev, inode.i_size); + + kdb_printf(" i_mode = 0x%x i_nlink = %d i_rdev = 0x%x\n", + inode.i_mode, inode.i_nlink, + inode.i_rdev); + + kdb_printf(" i_hash.nxt = 0x%p i_hash.prv = 0x%p\n", + inode.i_hash.next, inode.i_hash.prev); + + kdb_printf(" i_list.nxt = 0x%p i_list.prv = 0x%p\n", + inode.i_list.next, inode.i_list.prev); + + kdb_printf(" i_dentry.nxt = 0x%p i_dentry.prv = 0x%p\n", + inode.i_dentry.next, + inode.i_dentry.prev); + + kdb_printf(" i_dirty_buffers.nxt = 0x%p i_dirty_buffers.prv = 0x%p\n", + inode.i_dirty_buffers.next, + inode.i_dirty_buffers.prev); + + kdb_printf(" i_sb = 0x%p i_op = 0x%p i_data = 0x%lx nrpages = %lu\n", + inode.i_sb, inode.i_op, + addr + offsetof(struct inode, i_data), + inode.i_data.nrpages); + kdb_printf(" i_mapping = 0x%p\n i_flags 0x%x i_state 0x%lx [%s]", + inode.i_mapping, inode.i_flags, + inode.i_state, + map_flags(inode.i_state, inode_flag_vals)); + + iaddr = (char *)addr; + iaddr += offsetof(struct inode, u); + + kdb_printf(" fs specific info @ 0x%p\n", iaddr); + + return (0); +} + +static int +kdbm_kiobuf(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + struct kiobuf kiobuf; + struct page page; + unsigned char *p = (unsigned char *)&kiobuf; + struct page *page_array[64]; + unsigned long addr; + long offset=0; + int nextarg; + int diag; + int i, j; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + for (i=0; imap_array)) { + p = (char *)page_array; + for (i=0; i < (kiobuf.nr_pages * sizeof(struct page *)); i++) { + *p++ = kdba_getword((kdb_machreg_t)kiobuf.maplist + i, 1); + } + kiobuf.maplist = page_array; + } + kdb_printf(" errno %d", kiobuf.errno); +#ifdef KDB_DO_PAGEBUF +#ifdef KIOBUF_IO + kdb_printf(" pb 0x%p", (page_buf_t *)kiobuf.k_dev_id); +#endif +#endif /* KDB_DO_PAGEBUF */ + kdb_printf("\n"); + kdb_printf(" page_struct page_addr cnt flags\n"); + for (i = 0; i < kiobuf.nr_pages; i++) { + addr = (unsigned long) kiobuf.maplist[i]; + p = (unsigned char *)&page; + + for (j = 0; j < sizeof(struct page); j++) { + *p++ = kdba_getword(addr+j, 1); + } + kdb_printf(" 0x%p 0x%p %d 0x%lx\n", + kiobuf.maplist[i], page.virtual, + page.count.counter, page.flags); + } + + return (0); +} + +#ifdef KDB_DO_PAGEBUF + +/* pagebuf stuff */ + +static char *pb_flag_vals[] = { + "READ", "WRITE", "MAPPED", "PARTIAL", + "ASYNC", "NONE", "DELWRI", "FREED", "SYNC", + "MAPPABLE", "FS_RESERVED_1", "FS_RESERVED_2", "RELEASE", + "LOCK", "TRYLOCK", "ALLOCATE", "FILE_ALLOCATE", "DONT_BLOCK", + "DIRECT", "LOCKABLE", "NEXT_KEY", "ENTER_PAGES", + "ALL_PAGES_MAPPED", "SOME_INVALID_PAGES", "ADDR_ALLOCATED", + "MEM_ALLOCATED", "GRIO", "FORCEIO", "SHUTDOWN", + NULL }; + +static char *pbm_flag_vals[] = { + "EOF", "HOLE", "DELAY", "FLUSH_OVERLAPS", + "READAHEAD", "UNWRITTEN", "DONTALLOC", "NEW", + NULL }; + +static char *pb_flags(page_buf_flags_t pb_flag) +{ + return(map_flags((unsigned long) pb_flag, pb_flag_vals)); +} + +static int +kdbm_pb_flags(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + unsigned long flags; + int diag; + + if (argc != 1) + return KDB_ARGCOUNT; + + diag = kdbgetularg(argv[1], &flags); + if (diag) + return diag; + + kdb_printf("pb flags 0x%lx = %s\n", flags, pb_flags(flags)); + + return 0; +} + +static int +kdbm_pb(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + page_buf_private_t bp; + unsigned char *p = (unsigned char *)&bp; + unsigned long addr; + long offset=0; + int nextarg; + int diag; + int i; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + for (i=0; i + +#define EV_SIZE (sizeof(event_names)/sizeof(char *)) + +void +pb_trace_core( + unsigned long match, + char *event_match, + unsigned long long offset, + long long mask) +{ + extern struct pagebuf_trace_buf pb_trace; + int i, total, end; + pagebuf_trace_t *trace; + char *event; + char value[10]; + + end = pb_trace.start - 1; + if (end < 0) + end = PB_TRACE_BUFSIZE - 1; + + if (match && (match < PB_TRACE_BUFSIZE)) { + for (i = pb_trace.start, total = 0; i != end; i = CIRC_INC(i)) { + trace = &pb_trace.buf[i]; + if (trace->pb == 0) + continue; + total++; + } + total = total - match; + for (i = pb_trace.start; i != end && total; i = CIRC_INC(i)) { + trace = &pb_trace.buf[i]; + if (trace->pb == 0) + continue; + total--; + } + match = 0; + } else + i = pb_trace.start; + for ( ; i != end; i = CIRC_INC(i)) { + trace = &pb_trace.buf[i]; + + if (offset) { + if ((trace->offset & ~mask) != offset) + continue; + } + + if (trace->pb == 0) + continue; + + if ((match != 0) && (trace->pb != match)) + continue; + + if ((trace->event < EV_SIZE) && event_names[trace->event]) { + event = event_names[trace->event]; + } else if (trace->event == 1000) { + event = (char *)trace->misc; + } else { + event = value; + sprintf(value, "%8d", trace->event); + } + + if (event_match && strcmp(event, event_match)) { + continue; + } + + + kdb_printf("pb 0x%lx [%s] (hold %u lock %d) misc 0x%p", + trace->pb, event, + trace->hold, trace->lock_value, + trace->misc); + kdb_symbol_print((unsigned int)trace->ra, NULL, + KDB_SP_SPACEB|KDB_SP_PAREN|KDB_SP_NEWLINE); + kdb_printf(" offset 0x%Lx size 0x%x task 0x%p\n", + trace->offset, trace->size, trace->task); + kdb_printf(" flags: %s\n", + pb_flags(trace->flags)); + } +} + + +static int +kdbm_pbtrace_offset(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + long mask = 0; + unsigned long offset = 0; + int diag; + + if (argc > 2) + return KDB_ARGCOUNT; + + if (argc > 0) { + diag = kdbgetularg(argv[1], &offset); + if (diag) + return diag; + } + + if (argc > 1) { + diag = kdbgetularg(argv[1], &mask); + if (diag) + return diag; + } + + pb_trace_core(0, NULL, (unsigned long long)offset, + (long long)mask); /* sign extent mask */ + return 0; +} + +static int +kdbm_pbtrace(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + unsigned long addr = 0; + int diag, nextarg; + long offset = 0; + char *event_match = NULL; + + if (argc > 1) + return KDB_ARGCOUNT; + + if (argc == 1) { + if (isupper(argv[1][0]) || islower(argv[1][0])) { + event_match = (char *)argv[1]; + printk("event match on \"%s\"\n", event_match); + argc = 0; + } else { + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) { + printk("failed to parse %s as a number\n", + argv[1]); + return diag; + } + } + } + + pb_trace_core(addr, event_match, 0LL, 0LL); + return 0; +} + +#else /* PAGEBUF_TRACE */ +static int +kdbm_pbtrace(int argc, const char **argv, const char **envp, + struct pt_regs *regs) +{ + kdb_printf("pagebuf tracing not compiled in\n"); + + return 0; +} +#endif /* PAGEBUF_TRACE */ +#endif /* KDB_DO_PAGEBUF */ + +int +init_module(void) +{ + kdb_register("kiobuf", kdbm_kiobuf, "", "Display kiobuf", 0); + kdb_register("page", kdbm_page, "", "Display page", 0); + kdb_register("inode", kdbm_inode, "", "Display inode", 0); + kdb_register("bh", kdbm_buffers, "", "Display buffer", 0); + kdb_register("inode_pages", kdbm_inode_pages, "", "Display pages in an inode", 0); +#ifdef KDB_DO_PAGEBUF + kdb_register("pb", kdbm_pb, "", "Display page_buf_t", 0); + kdb_register("pbflags", kdbm_pb_flags, "", "Display page buf flags", 0); + kdb_register("pbiodesc", kdbm_pbiodesc, "", "Display I/O Descriptor", 0); + kdb_register("pbmap", kdbm_pbmap, "", "Display Bmap", 0); + kdb_register("pbtrace", kdbm_pbtrace, "|", "page_buf_t trace", 0); +#ifdef PAGEBUF_TRACE + kdb_register("pboffset", kdbm_pbtrace_offset, " []", "page_buf_t trace", 0); +#endif + kdb_register("req", kdbm_request, "", "dump request struct", 0); + kdb_register("rqueue", kdbm_rqueue, "", "dump request queue", 0); + +#endif /* KDB_DO_PAGEBUF */ + + return 0; +} + + +void +cleanup_module(void) +{ + kdb_unregister("kiobuf"); + kdb_unregister("page"); + kdb_unregister("inode"); + kdb_unregister("bh"); + kdb_unregister("inode_pages"); + kdb_unregister("pb"); + kdb_unregister("pbflags"); + kdb_unregister("pbmap"); + kdb_unregister("pbiodesc"); + kdb_unregister("pbtrace"); +#ifdef PAGEBUF_TRACE + kdb_unregister("pboffset"); +#endif + kdb_unregister("req"); + kdb_unregister("rqueue"); +} diff -rNu linux-2.4.7/linux/kdb/modules/kdbm_vm.c linux-2.4-xfs/linux/kdb/modules/kdbm_vm.c --- linux-2.4.7/linux/kdb/modules/kdbm_vm.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kdb/modules/kdbm_vm.c Wed Oct 4 06:42:46 2000 @@ -0,0 +1,583 @@ +#include +#include +#include +#include +#include +#include + +#include <../drivers/scsi/scsi.h> +#include <../drivers/scsi/hosts.h> + +/* The request printing worked under 2.3.42 but not 2.3.99-pre2. + * Feel free to rework it for 2.3.99-pre2 and submit a patch to SGI. + * Look for DO_REQUEST_PRINTING, remove the #ifdef and this comment + * when you get it working. Keith Owens + */ + +struct __vmflags { + unsigned long mask; + char *name; +} vmflags[] = { + { VM_READ, "READ" }, + { VM_WRITE, "WRITE" }, + { VM_EXEC, "EXEC" }, + { VM_SHARED, "SHARED" }, + { VM_MAYREAD, "MAYREAD" }, + { VM_MAYWRITE, "MAYWRITE" }, + { VM_MAYEXEC, "MAYEXEC" }, + { VM_MAYSHARE, "MAYSHARE" }, + { VM_GROWSDOWN, "GROWSDOWN" }, + { VM_GROWSUP, "GROWSUP" }, + { VM_SHM, "SHM" }, + { VM_DENYWRITE, "DENYWRITE" }, + { VM_EXECUTABLE, "EXECUTABLE" }, + { VM_LOCKED, "LOCKED" }, + { VM_IO , "IO " }, + { 0, "" } +}; + +static int +kdbm_vm(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct vm_area_struct vp; + unsigned char *bp = (unsigned char *)&vp; + unsigned long addr; + long offset=0; + int nextarg; + int diag; + struct __vmflags *tp; + int i; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + for (i=0; imask; tp++) { + if (vp.vm_flags & tp->mask) { + kdb_printf("%s ", tp->name); + } + } + kdb_printf("\n"); + + return 0; +} + +static int +kdbm_fp(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct file f; + unsigned char *fp = (unsigned char *)&f; + struct inode i; + unsigned char *ip = (unsigned char *)&i; + struct dentry d; + unsigned char *dp = (unsigned char *)&d; +#if 0 + unsigned char namebuf[80]; + unsigned char *np = namebuf; +#endif + int nextarg; + unsigned long addr; + unsigned long filpaddr; + long offset; + int diag; + int j; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + filpaddr = addr; + for (j=0; j\n", + d.d_name.len, d.d_name.name); + + kdb_printf(" d_count = %d d_flags = 0x%x d_inode = 0x%p\n", + atomic_read(&d.d_count), d.d_flags, d.d_inode); + +#ifdef FIXME_for_2_4_0_test1 + kdb_printf(" d_parent = 0x%p d_mounts = 0x%p d_covers = 0x%p\n", + d.d_parent, d.d_mounts, d.d_covers); +#endif + + kdb_printf(" d_hash.nxt = 0x%p d_hash.prv = 0x%p\n", + d.d_hash.next, d.d_hash.prev); + + kdb_printf(" d_lru.nxt = 0x%p d_lru.prv = 0x%p\n", + d.d_lru.next, d.d_lru.prev); + + kdb_printf(" d_child.nxt = 0x%p d_child.prv = 0x%p\n", + d.d_child.next, d.d_child.prev); + + kdb_printf(" d_subdirs.nxt = 0x%p d_subdirs.prv = 0x%p\n", + d.d_subdirs.next, d.d_subdirs.prev); + + kdb_printf(" d_alias.nxt = 0x%p d_alias.prv = 0x%p\n", + d.d_alias.next, d.d_alias.prev); + + kdb_printf(" d_op = 0x%p d_sb = 0x%p\n\n", + d.d_op, d.d_sb); + + + kdb_printf("\nInode Entry at 0x%p\n", d.d_inode); + + kdb_printf(" i_mode = 0x%x i_nlink = %d i_rdev = 0x%x\n", + i.i_mode, i.i_nlink, i.i_rdev); + + kdb_printf(" i_ino = %ld i_count = %d i_dev = 0x%x\n", + i.i_ino, atomic_read(&i.i_count), i.i_dev); + + kdb_printf(" i_hash.nxt = 0x%p i_hash.prv = 0x%p\n", + i.i_hash.next, i.i_hash.prev); + + kdb_printf(" i_list.nxt = 0x%p i_list.prv = 0x%p\n", + i.i_list.next, i.i_list.prev); + + kdb_printf(" i_dentry.nxt = 0x%p i_dentry.prv = 0x%p\n", + i.i_dentry.next, i.i_dentry.prev); + + return 0; +} + +static int +kdbm_dentry(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + struct dentry d; + unsigned char *dp = (unsigned char *)&d; +#if 0 + unsigned char namebuf[80]; + unsigned char *np = namebuf; +#endif + int nextarg; + unsigned long addr; + unsigned long dentryaddr; + long offset; + int diag; + int j; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + dentryaddr = addr; + + for (j=0; j\n", + d.d_name.len, d.d_name.name); +#if 0 + kdb_printf(" d_name: %s\n", namebuf); +#endif + + kdb_printf(" d_count = %d d_flags = 0x%x d_inode = 0x%p\n", + atomic_read(&d.d_count), d.d_flags, d.d_inode); + +#ifdef FIXME_for_2_4_0_test1 + kdb_printf(" d_parent = 0x%p d_mounts = 0x%p d_covers = 0x%p\n", + d.d_parent, d.d_mounts, d.d_covers); +#endif + + kdb_printf(" d_hash.nxt = 0x%p d_hash.prv = 0x%p\n", + d.d_hash.next, d.d_hash.prev); + + kdb_printf(" d_lru.nxt = 0x%p d_lru.prv = 0x%p\n", + d.d_lru.next, d.d_lru.prev); + + kdb_printf(" d_child.nxt = 0x%p d_child.prv = 0x%p\n", + d.d_child.next, d.d_child.prev); + + kdb_printf(" d_subdirs.nxt = 0x%p d_subdirs.prv = 0x%p\n", + d.d_subdirs.next, d.d_subdirs.prev); + + kdb_printf(" d_alias.nxt = 0x%p d_alias.prv = 0x%p\n", + d.d_alias.next, d.d_alias.prev); + + kdb_printf(" d_op = 0x%p d_sb = 0x%p\n\n", + d.d_op, d.d_sb); + + return 0; +} + +static int +kdbm_sh(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + int diag; + int nextarg; + unsigned long addr; + long offset =0L; + struct Scsi_Host sh; + unsigned char *shp = (unsigned char *)&sh; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + for (i=0; i < sizeof(struct Scsi_Host); i++) + *shp++ = kdba_getword(addr+i, 1); + + kdb_printf("Scsi_Host at 0x%lx\n", addr); + kdb_printf("next = 0x%p host_queue = 0x%p\n", + sh.next, sh.host_queue); + kdb_printf("ehandler = 0x%p eh_wait = 0x%p en_notify = 0x%p eh_action = 0x%p\n", + sh.ehandler, sh.eh_wait, sh.eh_notify, sh.eh_action); + kdb_printf("eh_active = 0x%d host_wait = 0x%p hostt = 0x%p host_busy = %d\n", + sh.eh_active, &sh.host_wait, sh.hostt, sh.host_active.counter); + kdb_printf("host_failed = %d extra_bytes = %d host_no = %d resetting = %d\n", + sh.host_failed, sh.extra_bytes, sh.host_no, sh.resetting); + kdb_printf("max id/lun/channel = [%d/%d/%d] this_id = %d\n", + sh.max_id, sh.max_lun, sh.max_channel, sh.this_id); + kdb_printf("can_queue = %d cmd_per_lun = %d sg_tablesize = %d u_isa_dma = %d\n", + sh.can_queue, sh.cmd_per_lun, sh.sg_tablesize, sh.unchecked_isa_dma); + kdb_printf("host_blocked = %d reverse_ordering = %d \n", + sh.host_blocked, sh.reverse_ordering); + + return 0; +} + +static int +kdbm_sd(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + int diag; + int nextarg; + unsigned long addr; + long offset =0L; + struct scsi_device sd; + unsigned char *sdp = (unsigned char *)&sd; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + for (i=0; i < sizeof(struct scsi_device); i++) + *sdp++ = kdba_getword(addr+i, 1); + + kdb_printf("scsi_device at 0x%lx\n", addr); + kdb_printf("next = 0x%p prev = 0x%p host = 0x%p\n", + sd.next, sd.prev, sd.host); + kdb_printf("device_busy = %d device_queue 0x%p\n", + sd.device_busy, sd.device_queue); + kdb_printf("id/lun/chan = [%d/%d/%d] single_lun = %d device_blocked = %d\n", + sd.id, sd.lun, sd.channel, sd.single_lun, sd.device_blocked); + kdb_printf("queue_depth = %d current_tag = %d scsi_level = %d\n", + sd.queue_depth, sd.current_tag, sd.scsi_level); + kdb_printf("%8.8s %16.16s %4.4s\n", sd.vendor, sd.model, sd.rev); + + return 0; +} + +static char * +str_rq_status(int rq_status) +{ + switch (rq_status) { + case RQ_INACTIVE: + return "RQ_INACTIVE"; + case RQ_ACTIVE: + return "RQ_ACTIVE"; + case RQ_SCSI_BUSY: + return "RQ_SCSI_BUSY"; + case RQ_SCSI_DONE: + return "RQ_SCSI_DONE"; + case RQ_SCSI_DISCONNECTING: + return "RQ_SCSI_DISCONNECTING"; + default: + return "UNKNOWN"; + } +} + +#ifdef DO_REQUEST_PRINTING +static char * +rq_cmds[] = { + "READ", + "WRITE", + "READA", + "", + "SPECIAL", + "WRITERAW" +}; +static unsigned int num_rq_cmds = sizeof(rq_cmds) / sizeof(char *); + +static void +show_request(unsigned long addr, struct request *rq) +{ + kdb_printf("struct request at 0x%lx\n", addr); + kdb_printf("cmd: %s\n", + ((rq->cmd >=0) && (rq->cmd <= num_rq_cmds))? + rq_cmds[rq->cmd]: ""); + kdb_printf("rq_status = %s rq_dev = [%d/%d] errors = %d\n", + str_rq_status(rq->rq_status), + MAJOR(rq->rq_dev), + MINOR(rq->rq_dev), + rq->errors); + kdb_printf("sector = %d nr_sectors = %d\n", + rq->sector, rq->nr_sectors); + kdb_printf("nr_segments = %d nr_hw_segments = %d current_nr_sectors = %d\n", + rq->nr_segments, rq->nr_hw_segments, rq->current_nr_sectors); + kdb_printf("special = 0x%lx buffer = 0x%lx semaphore = 0x%lx\n", + rq->special, rq->buffer, rq->sem); + kdb_printf("bh = 0x%lx bhtail = 0x%lx next = 0x%lx\n", + rq->bh, rq->bhtail, rq->next); +} +#endif /* DO_REQUEST_PRINTING */ + +static int +kdbm_sc(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + int diag; + int nextarg; + unsigned long addr; + long offset =0L; + struct scsi_cmnd sc; + unsigned char *scp = (unsigned char *)≻ + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + for (i=0; i < sizeof(struct scsi_cmnd); i++) + *scp++ = kdba_getword(addr+i, 1); + + kdb_printf("scsi_cmnd at 0x%lx\n", addr); + kdb_printf("host = 0x%p state = %d owner = %d device = 0x%p\nb", + sc.host, sc.state, sc.owner, sc.device); + kdb_printf("next = 0x%p reset_chain = 0x%p eh_state = %d done = 0x%p\n", + sc.next, sc.reset_chain, sc.eh_state, sc.done); + kdb_printf("serial_number = %ld serial_num_at_to = %ld retries = %d timeout = %d\n", + sc.serial_number, sc.serial_number_at_timeout, sc.retries, sc.timeout); + kdb_printf("id/lun/cmnd = [%d/%d/%d] cmd_len = %d old_cmd_len = %d\n", + sc.target, sc.lun, sc.channel, sc.cmd_len, sc.old_cmd_len); + kdb_printf("cmnd = [%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x]\n", + sc.cmnd[0], sc.cmnd[1], sc.cmnd[2], sc.cmnd[3], sc.cmnd[4], + sc.cmnd[5], sc.cmnd[6], sc.cmnd[7], sc.cmnd[8], sc.cmnd[9], + sc.cmnd[10], sc.cmnd[11]); + kdb_printf("data_cmnd = [%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x/%2.2x]\n", + sc.data_cmnd[0], sc.data_cmnd[1], sc.data_cmnd[2], sc.data_cmnd[3], sc.data_cmnd[4], + sc.data_cmnd[5], sc.data_cmnd[6], sc.data_cmnd[7], sc.data_cmnd[8], sc.data_cmnd[9], + sc.data_cmnd[10], sc.data_cmnd[11]); + kdb_printf("request_buffer = 0x%p bh_next = 0x%p request_bufflen = %d\n", + sc.request_buffer, sc.bh_next, sc.request_bufflen); + kdb_printf("use_sg = %d old_use_sg = %d sglist_len = %d abore_reason = %d\n", + sc.use_sg, sc.old_use_sg, sc.sglist_len, sc.abort_reason); + kdb_printf("bufflen = %d buffer = 0x%p underflow = %d transfersize = %d\n", + sc.bufflen, sc.buffer, sc.underflow, sc.transfersize); + kdb_printf("tag = %d pid = %ld\n", + sc.tag, sc.pid); + kdb_printf("request struct\n"); + kdb_printf("rq_status = %s rq_dev = [%d/%d] errors = %d cmd = %d\n", + str_rq_status(sc.request.rq_status), + MAJOR(sc.request.rq_dev), + MINOR(sc.request.rq_dev), sc.request.cmd, + sc.request.errors); + kdb_printf("sector = %ld nr_sectors = %ld current_nr_sectors = %ld\n", + sc.request.sector, sc.request.nr_sectors, sc.request.current_nr_sectors); + kdb_printf("buffer = 0x%p sem = 0x%p bh = 0x%p bhtail = 0x%p\n", + sc.request.buffer, sc.request.sem, sc.request.bh, sc.request.bhtail); +#ifdef DO_REQUEST_PRINTING + show_request(0, &sc.request); +#endif /* DO_REQUEST_PRINTING */ + + return 0; +} + +#ifdef DO_REQUEST_PRINTING +static int +kdbm_req(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + int diag; + int nextarg; + unsigned long addr; + long offset =0L; + struct request req; + unsigned char *rqp = (unsigned char *)&req; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + for (i=0; i < sizeof(struct request); i++) + *rqp++ = kdba_getword(addr+i, 1); + + show_request(addr, &req); + + return 0; +} + +static int +kdbm_rq(int argc, const char **argv, const char **envp, struct pt_regs *regs) +{ + int i; + int diag; + int nextarg; + unsigned long addr; + long offset =0L; + request_queue_t rq; + struct request req; + unsigned char *rqp = (unsigned char *)&rq; + kdb_symtab_t symtab1, symtab2; + + if (argc != 1) + return KDB_ARGCOUNT; + + nextarg = 1; + diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs); + if (diag) + return diag; + + for (i=0; i < sizeof(request_queue_t); i++) + *rqp++ = kdba_getword(addr+i, 1); + kdb_printf("request queue @ 0x%lx\n", addr); + kdbnearsym((unsigned long)rq.request_fn, &symtab1), + kdbnearsym((unsigned long)rq.merge_fn), &symtab2); + kdb_printf("current_request = 0x%p request_fn = '%s'\n merge_fn = '%s'", + rq.current_request, + symtab1.sym_name, + symtab2.sym_name); + kdbnearsym((unsigned long)rq.merge_requests_fn, &symtab1), + kdb_printf("merge_requests_fn = '%s'\n queuedata= 0x%p plugged = %d\n", + symtab1.sym_name, + rq.queuedata, rq.plugged); + kdb_printf("head_active = %d use_plug = %d\n", + rq.head_active, rq.use_plug); + kdb_printf("queue:\n"); + addr = (unsigned long)rq.current_request; + while (addr) { + rqp = (unsigned char *)&req; + for (i=0; i < sizeof(struct request); i++) + *rqp++ = kdba_getword(addr+i, 1); + show_request(addr, &req); + addr = req.next; + } + + return 0; +} +#endif /* DO_REQUEST_PRINTING */ + +int +init_module(void) +{ + kdb_register("vm", kdbm_vm, "", "Display vm_area_struct", 0); + kdb_register("dentry", kdbm_dentry, "", "Display interesting dentry stuff", 0); + kdb_register("filp", kdbm_fp, "", "Display interesting filp stuff", 0); + kdb_register("sh", kdbm_sh, "", "Show scsi_host", 0); + kdb_register("sd", kdbm_sd, "", "Show scsi_device", 0); + kdb_register("sc", kdbm_sc, "", "Show scsi_cmnd", 0); +#ifdef DO_REQUEST_PRINTING + kdb_register("req", kdbm_req, "", "Show struct request", 0); + kdb_register("rq", kdbm_rq, "", "Show request queue", 0); +#endif /* DO_REQUEST_PRINTING */ + + return 0; +} + +void +cleanup_module(void) +{ + kdb_unregister("vm"); + kdb_unregister("dentry"); + kdb_unregister("filp"); + kdb_unregister("sh"); + kdb_unregister("sd"); + kdb_unregister("sc"); +#ifdef DO_REQUEST_PRINTING + kdb_unregister("req"); + kdb_unregister("rq"); +#endif /* DO_REQUEST_PRINTING */ +} diff -rNu linux-2.4.7/linux/kernel/CVS/Entries linux-2.4-xfs/linux/kernel/CVS/Entries --- linux-2.4.7/linux/kernel/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kernel/CVS/Entries Thu Jul 5 12:07:04 2001 @@ -0,0 +1,29 @@ +/Makefile/1.23/Wed Jan 3 01:43:05 2001/-ko/ +/acct.c/1.14/Mon Apr 2 17:13:32 2001/-ko/ +/capability.c/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/context.c/1.4/Tue May 29 19:53:13 2001/-ko/ +/dma.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/exec_domain.c/1.11/Mon Jul 31 16:16:28 2000/-ko/ +/exit.c/1.28/Tue May 29 19:53:13 2001/-ko/ +/fork.c/1.32/Tue May 29 19:53:13 2001/-ko/ +/info.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/itimer.c/1.6/Mon Jul 31 16:16:28 2000/-ko/ +/kallsyms.c/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/kmod.c/1.14/Tue May 29 19:53:13 2001/-ko/ +/ksyms.c/1.94/Mon Jun 11 21:21:15 2001/-ko/ +/module.c/1.22/Tue May 29 19:53:13 2001/-ko/ +/panic.c/1.13/Wed Nov 1 21:35:42 2000/-ko/ +/pm.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/printk.c/1.12/Thu Feb 22 21:09:04 2001/-ko/ +/ptrace.c/1.12/Mon Apr 2 17:13:32 2001/-ko/ +/resource.c/1.15/Tue May 29 19:53:13 2001/-ko/ +/sched.c/1.36/Thu Jun 28 05:21:16 2001/-ko/ +/signal.c/1.17/Fri Jan 5 18:42:30 2001/-ko/ +/softirq.c/1.10/Sat Jun 9 02:44:24 2001/-ko/ +/sys.c/1.21/Thu Jul 5 05:29:17 2001/-ko/ +/sysctl.c/1.37/Wed May 2 06:22:13 2001/-ko/ +/time.c/1.6/Wed Nov 1 21:35:42 2000/-ko/ +/timer.c/1.13/Wed Jun 13 03:24:09 2001/-ko/ +/uid16.c/1.1/Tue Jan 11 18:48:48 2000/-ko/ +/user.c/1.3/Sun Dec 17 19:15:00 2000/-ko/ +D diff -rNu linux-2.4.7/linux/kernel/CVS/Repository linux-2.4-xfs/linux/kernel/CVS/Repository --- linux-2.4.7/linux/kernel/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kernel/CVS/Repository Thu Jul 5 12:07:01 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/kernel diff -rNu linux-2.4.7/linux/kernel/CVS/Root linux-2.4-xfs/linux/kernel/CVS/Root --- linux-2.4.7/linux/kernel/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kernel/CVS/Root Thu Jul 5 12:07:01 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/kernel/Makefile linux-2.4-xfs/linux/kernel/Makefile --- linux-2.4.7/linux/kernel/Makefile Fri Dec 29 16:07:24 2000 +++ linux-2.4-xfs/linux/kernel/Makefile Tue Jan 2 19:43:05 2001 @@ -19,6 +19,7 @@ obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_PM) += pm.o +obj-$(CONFIG_KALLSYMS) += kallsyms.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra , the -fno-omit-frame-pointer is diff -rNu linux-2.4.7/linux/kernel/kallsyms.c linux-2.4-xfs/linux/kernel/kallsyms.c --- linux-2.4.7/linux/kernel/kallsyms.c Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/kernel/kallsyms.c Mon Apr 2 12:13:32 2001 @@ -0,0 +1,306 @@ +/* An example of using kallsyms data in a kernel debugger. + + Copyright 2000 Keith Owens April 2000 + + This file is part of the Linux modutils. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ident "$Id$" + +/* + This code uses the list of all kernel and module symbols to :- + + * Find any non-stack symbol in a kernel or module. Symbols do + not have to be exported for debugging. + + * Convert an address to the module (or kernel) that owns it, the + section it is in and the nearest symbol. This finds all non-stack + symbols, not just exported ones. + + You need modutils >= 2.3.11 and a kernel with the kallsyms patch + which was compiled with CONFIG_KALLSYMS. + */ + +#include +#include +#include +#include +#include + +/* These external symbols are only set on kernels compiled with + * CONFIG_KALLSYMS. + */ + +extern const char __start___kallsyms[]; +extern const char __stop___kallsyms[]; + +static struct module **kallsyms_module_list; + +static void kallsyms_get_module_list(void) +{ + const struct kallsyms_header *ka_hdr; + const struct kallsyms_section *ka_sec; + const struct kallsyms_symbol *ka_sym; + const char *ka_str; + int i; + const char *p; + + if (__start___kallsyms >= __stop___kallsyms) + return; + ka_hdr = (struct kallsyms_header *)__start___kallsyms; + ka_sec = (struct kallsyms_section *) + ((char *)(ka_hdr) + ka_hdr->section_off); + ka_sym = (struct kallsyms_symbol *) + ((char *)(ka_hdr) + ka_hdr->symbol_off); + ka_str = + ((char *)(ka_hdr) + ka_hdr->string_off); + + for (i = 0; i < ka_hdr->symbols; kallsyms_next_sym(ka_hdr, ka_sym), ++i) { + p = ka_str + ka_sym->name_off; + if (strcmp(p, "module_list") == 0) { + if (ka_sym->symbol_addr) + kallsyms_module_list = (struct module **)(ka_sym->symbol_addr); + break; + } + } +} + +static void __inline__ kallsyms_do_first_time(void) +{ + static int first_time = 1; + if (first_time) + kallsyms_get_module_list(); + first_time = 0; +} + +/* A symbol can appear in more than one module. A token is used to + * restart the scan at the next module, set the token to 0 for the + * first scan of each symbol. + */ + +int kallsyms_symbol_to_address( + const char *name, /* Name to lookup */ + unsigned long *token, /* Which module to start at */ + const char **mod_name, /* Set to module name */ + unsigned long *mod_start, /* Set to start address of module */ + unsigned long *mod_end, /* Set to end address of module */ + const char **sec_name, /* Set to section name */ + unsigned long *sec_start, /* Set to start address of section */ + unsigned long *sec_end, /* Set to end address of section */ + const char **sym_name, /* Set to full symbol name */ + unsigned long *sym_start, /* Set to start address of symbol */ + unsigned long *sym_end /* Set to end address of symbol */ + ) +{ + const struct kallsyms_header *ka_hdr = NULL; /* stupid gcc */ + const struct kallsyms_section *ka_sec; + const struct kallsyms_symbol *ka_sym = NULL; + const char *ka_str = NULL; + const struct module *m; + int i = 0, l; + const char *p, *pt_R; + char *p2; + + kallsyms_do_first_time(); + if (!kallsyms_module_list) + return(0); + + /* Restart? */ + m = *kallsyms_module_list; + if (token && *token) { + for (; m; m = m->next) + if ((unsigned long)m == *token) + break; + if (m) + m = m->next; + } + + for (; m; m = m->next) { + if (!mod_member_present(m, kallsyms_start) || + !mod_member_present(m, kallsyms_end) || + m->kallsyms_start >= m->kallsyms_end) + continue; + ka_hdr = (struct kallsyms_header *)m->kallsyms_start; + ka_sym = (struct kallsyms_symbol *) + ((char *)(ka_hdr) + ka_hdr->symbol_off); + ka_str = + ((char *)(ka_hdr) + ka_hdr->string_off); + for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) { + p = ka_str + ka_sym->name_off; + if (strcmp(p, name) == 0) + break; + /* Unversioned requests match versioned names */ + if (!(pt_R = strstr(p, "_R"))) + continue; + l = strlen(pt_R); + if (l < 10) + continue; /* Not _R.*xxxxxxxx */ + (void)simple_strtoul(pt_R+l-8, &p2, 16); + if (*p2) + continue; /* Not _R.*xxxxxxxx */ + if (strncmp(p, name, pt_R-p) == 0) + break; /* Match with version */ + } + if (i < ka_hdr->symbols) + break; + } + + if (token) + *token = (unsigned long)m; + if (!m) + return(0); /* not found */ + + ka_sec = (const struct kallsyms_section *) + ((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off); + *mod_name = *(m->name) ? m->name : "kernel"; + *mod_start = ka_hdr->start; + *mod_end = ka_hdr->end; + *sec_name = ka_sec->name_off + ka_str; + *sec_start = ka_sec->start; + *sec_end = ka_sec->start + ka_sec->size; + *sym_name = ka_sym->name_off + ka_str; + *sym_start = ka_sym->symbol_addr; + if (i < ka_hdr->symbols-1) { + const struct kallsyms_symbol *ka_symn = ka_sym; + kallsyms_next_sym(ka_hdr, ka_symn); + *sym_end = ka_symn->symbol_addr; + } + else + *sym_end = *sec_end; + return(1); +} + +int kallsyms_address_to_symbol( + unsigned long address, /* Address to lookup */ + const char **mod_name, /* Set to module name */ + unsigned long *mod_start, /* Set to start address of module */ + unsigned long *mod_end, /* Set to end address of module */ + const char **sec_name, /* Set to section name */ + unsigned long *sec_start, /* Set to start address of section */ + unsigned long *sec_end, /* Set to end address of section */ + const char **sym_name, /* Set to full symbol name */ + unsigned long *sym_start, /* Set to start address of symbol */ + unsigned long *sym_end /* Set to end address of symbol */ + ) +{ + const struct kallsyms_header *ka_hdr = NULL; /* stupid gcc */ + const struct kallsyms_section *ka_sec = NULL; + const struct kallsyms_symbol *ka_sym; + const char *ka_str; + const struct module *m; + int i; + unsigned long end; + + kallsyms_do_first_time(); + if (!kallsyms_module_list) + return(0); + + for (m = *kallsyms_module_list; m; m = m->next) { + if (!mod_member_present(m, kallsyms_start) || + !mod_member_present(m, kallsyms_end) || + m->kallsyms_start >= m->kallsyms_end) + continue; + ka_hdr = (struct kallsyms_header *)m->kallsyms_start; + ka_sec = (const struct kallsyms_section *) + ((char *)ka_hdr + ka_hdr->section_off); + /* Is the address in any section in this module? */ + for (i = 0; i < ka_hdr->sections; ++i, kallsyms_next_sec(ka_hdr, ka_sec)) { + if (ka_sec->start <= address && + (ka_sec->start + ka_sec->size) > address) + break; + } + if (i < ka_hdr->sections) + break; /* Found a matching section */ + } + + if (!m) + return(0); /* not found */ + + ka_sym = (struct kallsyms_symbol *) + ((char *)(ka_hdr) + ka_hdr->symbol_off); + ka_str = + ((char *)(ka_hdr) + ka_hdr->string_off); + *mod_name = *(m->name) ? m->name : "kernel"; + *mod_start = ka_hdr->start; + *mod_end = ka_hdr->end; + *sec_name = ka_sec->name_off + ka_str; + *sec_start = ka_sec->start; + *sec_end = ka_sec->start + ka_sec->size; + *sym_name = *sec_name; /* In case we find no matching symbol */ + *sym_start = *sec_start; + *sym_end = *sec_end; + + for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) { + if (ka_sym->symbol_addr > address) + continue; + if (i < ka_hdr->symbols-1) { + const struct kallsyms_symbol *ka_symn = ka_sym; + kallsyms_next_sym(ka_hdr, ka_symn); + end = ka_symn->symbol_addr; + } + else + end = *sec_end; + if (end <= address) + continue; + if ((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off + != (char *)ka_sec) + continue; /* wrong section */ + *sym_name = ka_str + ka_sym->name_off; + *sym_start = ka_sym->symbol_addr; + *sym_end = end; + break; + } + return(1); +} + +/* List all sections in all modules. The callback routine is invoked with + * token, module name, section name, section start, section end, section flags. + */ +int kallsyms_sections(void *token, + int (*callback)(void *, const char *, const char *, ElfW(Addr), ElfW(Addr), ElfW(Word))) +{ + const struct kallsyms_header *ka_hdr = NULL; /* stupid gcc */ + const struct kallsyms_section *ka_sec = NULL; + const char *ka_str; + const struct module *m; + int i; + + kallsyms_do_first_time(); + if (!kallsyms_module_list) + return(0); + + for (m = *kallsyms_module_list; m; m = m->next) { + if (!mod_member_present(m, kallsyms_start) || + !mod_member_present(m, kallsyms_end) || + m->kallsyms_start >= m->kallsyms_end) + continue; + ka_hdr = (struct kallsyms_header *)m->kallsyms_start; + ka_sec = (const struct kallsyms_section *) ((char *)ka_hdr + ka_hdr->section_off); + ka_str = ((char *)(ka_hdr) + ka_hdr->string_off); + for (i = 0; i < ka_hdr->sections; ++i, kallsyms_next_sec(ka_hdr, ka_sec)) { + if (callback( + token, + *(m->name) ? m->name : "kernel", + ka_sec->name_off + ka_str, + ka_sec->start, + ka_sec->start + ka_sec->size, + ka_sec->flags)) + return(0); + } + } + return(1); +} diff -rNu linux-2.4.7/linux/kernel/ksyms.c linux-2.4-xfs/linux/kernel/ksyms.c --- linux-2.4.7/linux/kernel/ksyms.c Mon Jun 11 21:15:27 2001 +++ linux-2.4-xfs/linux/kernel/ksyms.c Mon Jun 11 16:21:15 2001 @@ -55,6 +55,9 @@ #ifdef CONFIG_KMOD #include #endif +#ifdef CONFIG_KALLSYMS +#include +#endif extern void set_device_ro(kdev_t dev,int flag); @@ -80,6 +83,15 @@ EXPORT_SYMBOL(inter_module_put); EXPORT_SYMBOL(try_inc_mod_count); +#ifdef CONFIG_KALLSYMS +extern const char __start___kallsyms[]; +extern const char __stop___kallsyms[]; +EXPORT_SYMBOL(__start___kallsyms); +EXPORT_SYMBOL(__stop___kallsyms); +EXPORT_SYMBOL(kallsyms_symbol_to_address); +EXPORT_SYMBOL(kallsyms_address_to_symbol); +#endif + /* process memory management */ EXPORT_SYMBOL(do_mmap_pgoff); EXPORT_SYMBOL(do_munmap); @@ -97,12 +109,14 @@ EXPORT_SYMBOL(get_zeroed_page); EXPORT_SYMBOL(__free_pages); EXPORT_SYMBOL(free_pages); +EXPORT_SYMBOL(free_shortage); EXPORT_SYMBOL(num_physpages); EXPORT_SYMBOL(kmem_find_general_cachep); EXPORT_SYMBOL(kmem_cache_create); EXPORT_SYMBOL(kmem_cache_destroy); EXPORT_SYMBOL(kmem_cache_shrink); EXPORT_SYMBOL(kmem_cache_alloc); +EXPORT_SYMBOL(kmem_cache_zalloc); EXPORT_SYMBOL(kmem_cache_free); EXPORT_SYMBOL(kmalloc); EXPORT_SYMBOL(kfree); @@ -110,6 +124,7 @@ EXPORT_SYMBOL(__vmalloc); EXPORT_SYMBOL(mem_map); EXPORT_SYMBOL(remap_page_range); +EXPORT_SYMBOL(remap_page_array); EXPORT_SYMBOL(max_mapnr); EXPORT_SYMBOL(high_memory); EXPORT_SYMBOL(vmtruncate); @@ -136,6 +151,8 @@ EXPORT_SYMBOL(igrab); EXPORT_SYMBOL(iunique); EXPORT_SYMBOL(iget4); +EXPORT_SYMBOL(icreate4); +EXPORT_SYMBOL(unlock_new_inode); EXPORT_SYMBOL(iput); EXPORT_SYMBOL(force_delete); EXPORT_SYMBOL(follow_up); @@ -203,8 +220,10 @@ EXPORT_SYMBOL(cont_prepare_write); EXPORT_SYMBOL(generic_commit_write); EXPORT_SYMBOL(block_truncate_page); +EXPORT_SYMBOL(block_flushpage); EXPORT_SYMBOL(generic_block_bmap); EXPORT_SYMBOL(waitfor_one_page); +EXPORT_SYMBOL(create_empty_buffers); EXPORT_SYMBOL(generic_file_read); EXPORT_SYMBOL(do_generic_file_read); EXPORT_SYMBOL(generic_file_write); @@ -228,9 +247,12 @@ EXPORT_SYMBOL(prune_dcache); EXPORT_SYMBOL(shrink_dcache_sb); EXPORT_SYMBOL(shrink_dcache_parent); +EXPORT_SYMBOL(shrink_dcache_memory); +EXPORT_SYMBOL(shrink_icache_memory); EXPORT_SYMBOL(find_inode_number); EXPORT_SYMBOL(is_subdir); EXPORT_SYMBOL(get_unused_fd); +EXPORT_SYMBOL(put_unused_fd); EXPORT_SYMBOL(vfs_create); EXPORT_SYMBOL(vfs_mkdir); EXPORT_SYMBOL(vfs_mknod); @@ -245,6 +267,7 @@ EXPORT_SYMBOL(poll_freewait); EXPORT_SYMBOL(ROOT_DEV); EXPORT_SYMBOL(__find_lock_page); +EXPORT_SYMBOL(find_get_page_simple); EXPORT_SYMBOL(grab_cache_page); EXPORT_SYMBOL(read_cache_page); EXPORT_SYMBOL(vfs_readlink); @@ -268,6 +291,11 @@ EXPORT_SYMBOL(filemap_fdatasync); EXPORT_SYMBOL(filemap_fdatawait); EXPORT_SYMBOL(lock_page); + +/* for page_buf cache */ +EXPORT_SYMBOL(add_to_page_cache_unique); +EXPORT_SYMBOL(balance_dirty); +EXPORT_SYMBOL(set_bh_page); /* device registration */ EXPORT_SYMBOL(register_chrdev); diff -rNu linux-2.4.7/linux/kernel/sysctl.c linux-2.4-xfs/linux/kernel/sysctl.c --- linux-2.4.7/linux/kernel/sysctl.c Thu Apr 12 14:20:31 2001 +++ linux-2.4-xfs/linux/kernel/sysctl.c Wed May 2 01:22:13 2001 @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -138,6 +139,11 @@ static void unregister_proc_table(ctl_table *, struct proc_dir_entry *); #endif +#ifdef CONFIG_X86_LOCAL_APIC +#include +static int do_proc_set_nmi_watchdog(ctl_table *, int, struct file *, void *, size_t *); +#endif + /* The default sysctl tables: */ static ctl_table root_table[] = { @@ -249,6 +255,14 @@ {KERN_S390_USER_DEBUG_LOGGING,"userprocess_debug", &sysctl_userprocess_debug,sizeof(int),0644,NULL,&proc_dointvec}, #endif +#ifdef CONFIG_X86_LOCAL_APIC + {KERN_NMI_WATCHDOG, "nmi_watchdog", &proc_nmi_watchdog, sizeof(int), + 0644, NULL, &do_proc_set_nmi_watchdog}, +#endif +#ifdef CONFIG_KDB + {KERN_KDB, "kdb", &kdb_on, sizeof(int), + 0644, NULL, &proc_dointvec}, +#endif /* CONFIG_KDB */ {0} }; @@ -934,6 +948,24 @@ { return do_proc_dointvec(table,write,filp,buffer,lenp,1,OP_SET); } + +#ifdef CONFIG_X86_LOCAL_APIC +/* nmi_watchdog must be processed here, no event will detect that it has + * been turned on. set_nmi_watchdog() can reject the change, /proc sees + * an external copy of nmi_watchdog. + */ +static int do_proc_set_nmi_watchdog(ctl_table *table, + int write, struct file *filp, + void *buffer, size_t *lenp) +{ + int ret; + if ((ret = proc_dointvec(table,write,filp,buffer,lenp))) + return(ret); + if (write) + ret = set_nmi_watchdog(proc_nmi_watchdog); + return ret; +} +#endif /* CONFIG_X86_LOCAL_APIC */ /* * init may raise the set. diff -rNu linux-2.4.7/linux/lib/CVS/Entries linux-2.4-xfs/linux/lib/CVS/Entries --- linux-2.4.7/linux/lib/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/lib/CVS/Entries Thu Jul 5 12:07:05 2001 @@ -0,0 +1,12 @@ +/Makefile/1.6/Wed May 2 06:22:13 2001/-ko/ +/brlock.c/1.4/Mon Jul 2 15:59:04 2001/-ko/ +/cmdline.c/1.3/Wed May 2 06:22:13 2001/-ko/ +/ctype.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dec_and_lock.c/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/errno.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/inflate.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/rwsem-spinlock.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/rwsem.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/string.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/vsprintf.c/1.10/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/lib/CVS/Repository linux-2.4-xfs/linux/lib/CVS/Repository --- linux-2.4.7/linux/lib/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/lib/CVS/Repository Thu Jul 5 12:07:04 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/lib diff -rNu linux-2.4.7/linux/lib/CVS/Root linux-2.4-xfs/linux/lib/CVS/Root --- linux-2.4.7/linux/lib/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/lib/CVS/Root Thu Jul 5 12:07:04 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/lib/vsprintf.c linux-2.4-xfs/linux/lib/vsprintf.c --- linux-2.4.7/linux/lib/vsprintf.c Fri Apr 13 22:26:07 2001 +++ linux-2.4-xfs/linux/lib/vsprintf.c Wed May 2 01:22:13 2001 @@ -266,6 +266,10 @@ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') { qualifier = *fmt; ++fmt; + if (qualifier == 'l' && *fmt == 'l') { + qualifier = 'L'; + ++fmt; + } } /* default base */ diff -rNu linux-2.4.7/linux/mm/CVS/Entries linux-2.4-xfs/linux/mm/CVS/Entries --- linux-2.4.7/linux/mm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/mm/CVS/Entries Thu Jul 5 12:07:09 2001 @@ -0,0 +1,22 @@ +/Makefile/1.7/Thu Dec 21 05:48:12 2000/-ko/ +/bootmem.c/1.15/Tue Jul 3 02:33:57 2001/-ko/ +/filemap.c/1.77/Wed Jun 13 03:24:09 2001/-ko/ +/highmem.c/1.21/Mon Jul 2 15:59:04 2001/-ko/ +/memory.c/1.49/Sat Jun 9 02:44:24 2001/-ko/ +/mlock.c/1.14/Mon Apr 2 17:13:32 2001/-ko/ +/mmap.c/1.38/Thu Jul 5 03:57:00 2001/-ko/ +/mmap_avl.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/mprotect.c/1.15/Mon Apr 2 17:13:32 2001/-ko/ +/mremap.c/1.22/Wed May 2 06:22:13 2001/-ko/ +/numa.c/1.8/Tue Jul 3 02:33:57 2001/-ko/ +/oom_kill.c/1.3/Tue May 29 19:53:13 2001/-ko/ +/page_alloc.c/1.45/Mon Jul 2 15:59:04 2001/-ko/ +/page_io.c/1.15/Wed May 2 06:22:13 2001/-ko/ +/shmem.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/slab.c/1.24/Tue May 29 19:53:13 2001/-ko/ +/swap.c/1.8/Thu Feb 1 17:10:24 2001/-ko/ +/swap_state.c/1.25/Sat Jun 9 02:44:24 2001/-ko/ +/swapfile.c/1.33/Thu Jul 5 05:29:17 2001/-ko/ +/vmalloc.c/1.31/Tue May 29 19:53:13 2001/-ko/ +/vmscan.c/1.61/Mon Jul 2 15:59:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/mm/CVS/Repository linux-2.4-xfs/linux/mm/CVS/Repository --- linux-2.4.7/linux/mm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/mm/CVS/Repository Thu Jul 5 12:07:05 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/mm diff -rNu linux-2.4.7/linux/mm/CVS/Root linux-2.4-xfs/linux/mm/CVS/Root --- linux-2.4.7/linux/mm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/mm/CVS/Root Thu Jul 5 12:07:05 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/mm/filemap.c linux-2.4-xfs/linux/mm/filemap.c --- linux-2.4.7/linux/mm/filemap.c Tue Jun 12 13:16:41 2001 +++ linux-2.4-xfs/linux/mm/filemap.c Tue Jun 12 22:24:09 2001 @@ -106,6 +106,12 @@ */ void __remove_inode_page(struct page *page) { + + if (DelallocPage(page)) { + printk("Delalloc page %p removed from inode\n", page); + BUG(); + } + if (PageDirty(page)) BUG(); remove_page_from_inode_queue(page); remove_page_from_hash_queue(page); @@ -553,7 +559,7 @@ spin_unlock(&pagecache_lock); } -static int add_to_page_cache_unique(struct page * page, +int add_to_page_cache_unique(struct page * page, struct address_space *mapping, unsigned long offset, struct page **hash) { @@ -710,6 +716,22 @@ } /* + * Similar to find_get_page but with no VM side-effects such as aging. + */ +struct page * find_get_page_simple(struct address_space *mapping, + unsigned long index) +{ + struct page *page; + + spin_lock(&pagecache_lock); + page = __find_page_simple(mapping, index); + if (page) + page_cache_get(page); + spin_unlock(&pagecache_lock); + return page; +} + +/* * Find a swapcache page (and get a reference) or return NULL. * The SwapCache check is protected by the pagecache lock. */ diff -rNu linux-2.4.7/linux/mm/slab.c linux-2.4-xfs/linux/mm/slab.c --- linux-2.4.7/linux/mm/slab.c Tue May 22 12:23:16 2001 +++ linux-2.4-xfs/linux/mm/slab.c Tue May 29 14:53:13 2001 @@ -1542,6 +1542,23 @@ local_irq_restore(flags); } +void * +kmem_cache_zalloc(kmem_cache_t *cachep, int flags) +{ + void *ptr; + ptr = __kmem_cache_alloc(cachep, flags); + if (ptr) +#if DEBUG + memset(ptr, 0, cachep->objsize - + (cachep->flags & SLAB_RED_ZONE ? 2*BYTES_PER_WORD : 0)); +#else + memset(ptr, 0, cachep->objsize); +#endif + + return ptr; +} + + /** * kfree - free previously allocated memory * @objp: pointer returned by kmalloc. diff -rNu linux-2.4.7/linux/mm/vmalloc.c linux-2.4-xfs/linux/mm/vmalloc.c --- linux-2.4.7/linux/mm/vmalloc.c Tue May 22 21:54:04 2001 +++ linux-2.4-xfs/linux/mm/vmalloc.c Tue May 29 14:53:13 2001 @@ -6,6 +6,7 @@ * SMP-safe vmalloc/vfree/ioremap, Tigran Aivazian , May 2000 */ +#include #include #include #include @@ -18,6 +19,53 @@ rwlock_t vmlist_lock = RW_LOCK_UNLOCKED; struct vm_struct * vmlist; +#if defined(CONFIG_KDB) +/* kdb_vmlist_check + * Check to determine if an address is within a vmalloced range. + * Parameters: + * starta -- Starting address of region to check + * enda -- Ending address of region to check + * Returns: + * 0 -- [starta,enda] not within a vmalloc area + * 1 -- [starta,enda] within a vmalloc area + * Locking: + * None. + * Remarks: + * Shouldn't acquire locks. Always called with all interrupts + * disabled and other cpus halted. Yet, if a breakpoint or fault + * occurs while the vmlist is in an indeterminate state, this + * function could fail. + */ +int +kdb_vmlist_check(unsigned long starta, unsigned long enda) +{ + struct vm_struct *vp; + + if (vmlist) { + for(vp=vmlist; vp; vp = vp->next) { + unsigned long end = (unsigned long)vp->addr + vp->size; + + end -= PAGE_SIZE; /* Unbias for guard page */ + + if ((starta >= (unsigned long)vp->addr) + && (starta < end) + && (enda < end)) { + return 1; + } + } + } + else { + /* early kdb, no vmlist yet */ + extern char _text, _end; + if (starta >= (unsigned long) &_text && + enda < (unsigned long) &_end && + starta <= enda) + return 1; + } + return 0; +} +#endif + static inline void free_area_pte(pmd_t * pmd, unsigned long address, unsigned long size) { pte_t * pte; @@ -92,7 +140,8 @@ } static inline int alloc_area_pte (pte_t * pte, unsigned long address, - unsigned long size, int gfp_mask, pgprot_t prot) + unsigned long size, int gfp_mask, + pgprot_t prot, struct page ***pages) { unsigned long end; @@ -102,9 +151,17 @@ end = PMD_SIZE; do { struct page * page; - spin_unlock(&init_mm.page_table_lock); - page = alloc_page(gfp_mask); - spin_lock(&init_mm.page_table_lock); + if (!pages) { + spin_unlock(&init_mm.page_table_lock); + page = alloc_page(gfp_mask); + spin_lock(&init_mm.page_table_lock); + } else { + page = (*pages)[0]; + (*pages)++; + /* Add a reference to the page so we can free later */ + if (page) atomic_inc(&page->count); + + } if (!pte_none(*pte)) printk(KERN_ERR "alloc_area_pte: page already exists\n"); if (!page) @@ -116,7 +173,9 @@ return 0; } -static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, int gfp_mask, pgprot_t prot) +static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, + unsigned long size, int gfp_mask, + pgprot_t prot, struct page ***pages) { unsigned long end; @@ -128,7 +187,8 @@ pte_t * pte = pte_alloc(&init_mm, pmd, address); if (!pte) return -ENOMEM; - if (alloc_area_pte(pte, address, end - address, gfp_mask, prot)) + if (alloc_area_pte(pte, address, end - address, + gfp_mask, prot, pages)) return -ENOMEM; address = (address + PMD_SIZE) & PMD_MASK; pmd++; @@ -136,8 +196,10 @@ return 0; } -inline int vmalloc_area_pages (unsigned long address, unsigned long size, - int gfp_mask, pgprot_t prot) +static inline int _vmalloc_area_pages (unsigned long address, + unsigned long size, + int gfp_mask, pgprot_t prot, + struct page ***pages) { pgd_t * dir; unsigned long end = address + size; @@ -155,7 +217,7 @@ break; ret = -ENOMEM; - if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot)) + if (alloc_area_pmd(pmd, address, end - address, gfp_mask, prot, pages)) break; address = (address + PGDIR_SIZE) & PGDIR_MASK; @@ -168,6 +230,13 @@ return ret; } +inline int vmalloc_area_pages (unsigned long address, + unsigned long size, + int gfp_mask, pgprot_t prot) +{ + return _vmalloc_area_pages(address, size, gfp_mask, prot, NULL); +} + struct vm_struct * get_vm_area(unsigned long size, unsigned long flags) { unsigned long addr; @@ -240,7 +309,29 @@ if (!area) return NULL; addr = area->addr; - if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, gfp_mask, prot)) { + if (vmalloc_area_pages(VMALLOC_VMADDR(addr), size, + gfp_mask, prot)) { + vfree(addr); + return NULL; + } + return addr; +} + +void * remap_page_array(struct page **page_array, int count, int gfp_mask) +{ + void * addr; + struct vm_struct *area; + unsigned long size = count << PAGE_SHIFT; + + if (!size || size > (max_mapnr << PAGE_SHIFT)) + return NULL; + area = get_vm_area(size, VM_ALLOC); + if (!area) { + return NULL; + } + addr = area->addr; + if (_vmalloc_area_pages(VMALLOC_VMADDR(addr), size, + gfp_mask, PAGE_KERNEL, &page_array)) { vfree(addr); return NULL; } diff -rNu linux-2.4.7/linux/mm/vmscan.c linux-2.4-xfs/linux/mm/vmscan.c --- linux-2.4.7/linux/mm/vmscan.c Fri Jun 29 18:35:36 2001 +++ linux-2.4-xfs/linux/mm/vmscan.c Mon Jul 2 10:59:04 2001 @@ -515,6 +515,7 @@ unsigned int buffer_mask; int clearedbuf; int freed_page = 0; + int do_unlock = 1; /* * Since we might be doing disk IO, we have to * drop the spinlock and take an extra reference @@ -532,8 +533,19 @@ else buffer_mask = gfp_mask & ~(__GFP_WAIT | __GFP_IO); /* Don't even start IO */ - /* Try to free the page buffers. */ - clearedbuf = try_to_free_buffers(page, buffer_mask); + /* Do not push delalloc pages if we are calling in + * from a sensitive location. + */ + if (DelallocPage(page)) { + if (CAN_DO_FS && (buffer_mask & __GFP_WAIT)) { + page->mapping->a_ops->writepage(page); + do_unlock = 0; + } + clearedbuf = 0; + } else { + /* Try to free the page buffers. */ + clearedbuf = try_to_free_buffers(page, buffer_mask); + } /* * Re-take the spinlock. Note that we cannot @@ -567,7 +579,9 @@ * We can only do it here because we are accessing * the page struct above. */ - UnlockPage(page); + if (do_unlock) { + UnlockPage(page); + } page_cache_release(page); /* diff -rNu linux-2.4.7/linux/net/802/CVS/Entries linux-2.4-xfs/linux/net/802/CVS/Entries --- linux-2.4.7/linux/net/802/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/802/CVS/Entries Thu Jul 5 12:07:10 2001 @@ -0,0 +1,16 @@ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/TODO/1.3/Wed May 2 06:22:13 2001/-ko/ +/cl2llc.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/cl2llc.pre/1.3/Wed May 2 06:22:13 2001/-ko/ +/fc.c/1.3/Mon Nov 15 18:18:49 1999/-ko/ +/fddi.c/1.4/Sun Dec 17 19:15:00 2000/-ko/ +/hippi.c/1.4/Thu Jun 21 15:45:04 2001/-ko/ +/llc_macinit.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/llc_sendpdu.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/llc_utility.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/p8022.c/1.6/Wed Nov 1 21:35:42 2000/-ko/ +/p8023.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/psnap.c/1.6/Wed Nov 1 21:35:42 2000/-ko/ +/sysctl_net_802.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/tr.c/1.10/Wed Nov 1 21:35:42 2000/-ko/ +D diff -rNu linux-2.4.7/linux/net/802/CVS/Entries.Log linux-2.4-xfs/linux/net/802/CVS/Entries.Log --- linux-2.4.7/linux/net/802/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/802/CVS/Entries.Log Thu Jul 5 12:07:10 2001 @@ -0,0 +1,2 @@ +A D/pseudo//// +A D/transit//// diff -rNu linux-2.4.7/linux/net/802/CVS/Repository linux-2.4-xfs/linux/net/802/CVS/Repository --- linux-2.4.7/linux/net/802/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/802/CVS/Repository Thu Jul 5 12:07:09 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/802 diff -rNu linux-2.4.7/linux/net/802/CVS/Root linux-2.4-xfs/linux/net/802/CVS/Root --- linux-2.4.7/linux/net/802/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/802/CVS/Root Thu Jul 5 12:07:09 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/802/pseudo/CVS/Entries linux-2.4-xfs/linux/net/802/pseudo/CVS/Entries --- linux-2.4.7/linux/net/802/pseudo/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/802/pseudo/CVS/Entries Thu Jul 5 12:07:10 2001 @@ -0,0 +1,10 @@ +/Makefile/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/actionnm.awk/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/actionnm.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/compile.awk/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/opcd2num.sed/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/opcodes/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/opcodesnm.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/pseudocode/1.3/Wed May 2 06:22:13 2001/-ko/ +/pseudocode.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/net/802/pseudo/CVS/Repository linux-2.4-xfs/linux/net/802/pseudo/CVS/Repository --- linux-2.4.7/linux/net/802/pseudo/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/802/pseudo/CVS/Repository Thu Jul 5 12:07:10 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/802/pseudo diff -rNu linux-2.4.7/linux/net/802/pseudo/CVS/Root linux-2.4-xfs/linux/net/802/pseudo/CVS/Root --- linux-2.4.7/linux/net/802/pseudo/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/802/pseudo/CVS/Root Thu Jul 5 12:07:10 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/802/transit/CVS/Entries linux-2.4-xfs/linux/net/802/transit/CVS/Entries --- linux-2.4.7/linux/net/802/transit/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/802/transit/CVS/Entries Thu Jul 5 12:07:11 2001 @@ -0,0 +1,7 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/compile.awk/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/pdutr.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/pdutr.pre/1.3/Wed May 2 06:22:13 2001/-ko/ +/timertr.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/timertr.pre/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/net/802/transit/CVS/Repository linux-2.4-xfs/linux/net/802/transit/CVS/Repository --- linux-2.4.7/linux/net/802/transit/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/802/transit/CVS/Repository Thu Jul 5 12:07:10 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/802/transit diff -rNu linux-2.4.7/linux/net/802/transit/CVS/Root linux-2.4-xfs/linux/net/802/transit/CVS/Root --- linux-2.4.7/linux/net/802/transit/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/802/transit/CVS/Root Thu Jul 5 12:07:10 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/CVS/Entries linux-2.4-xfs/linux/net/CVS/Entries --- linux-2.4.7/linux/net/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/CVS/Entries Thu Jul 5 12:07:09 2001 @@ -0,0 +1,8 @@ +/Config.in/1.17/Mon Apr 2 17:13:32 2001/-ko/ +/Makefile/1.15/Sat Jun 9 02:44:24 2001/-ko/ +/README/1.9/Sat Jun 9 02:44:24 2001/-ko/ +/TUNABLE/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/netsyms.c/1.32/Thu Jun 21 15:45:04 2001/-ko/ +/socket.c/1.22/Sat Jun 9 02:44:24 2001/-ko/ +/sysctl_net.c/1.7/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/CVS/Entries.Log linux-2.4-xfs/linux/net/CVS/Entries.Log --- linux-2.4.7/linux/net/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/CVS/Entries.Log Thu Jul 5 12:08:09 2001 @@ -0,0 +1,25 @@ +A D/802//// +A D/appletalk//// +A D/atm//// +A D/ax25//// +A D/bluetooth//// +A D/bridge//// +A D/core//// +A D/decnet//// +A D/econet//// +A D/ethernet//// +A D/ipv4//// +A D/ipv6//// +A D/ipx//// +A D/irda//// +A D/khttpd//// +A D/lapb//// +A D/netlink//// +A D/netrom//// +A D/packet//// +A D/rose//// +A D/sched//// +A D/sunrpc//// +A D/unix//// +A D/wanrouter//// +A D/x25//// diff -rNu linux-2.4.7/linux/net/CVS/Repository linux-2.4-xfs/linux/net/CVS/Repository --- linux-2.4.7/linux/net/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/CVS/Repository Thu Jul 5 12:07:09 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net diff -rNu linux-2.4.7/linux/net/CVS/Root linux-2.4-xfs/linux/net/CVS/Root --- linux-2.4.7/linux/net/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/CVS/Root Thu Jul 5 12:07:09 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/appletalk/CVS/Entries linux-2.4-xfs/linux/net/appletalk/CVS/Entries --- linux-2.4.7/linux/net/appletalk/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/appletalk/CVS/Entries Thu Jul 5 12:07:13 2001 @@ -0,0 +1,5 @@ +/Makefile/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/aarp.c/1.11/Mon Jul 2 15:59:04 2001/-ko/ +/ddp.c/1.16/Wed May 2 06:22:13 2001/-ko/ +/sysctl_net_atalk.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/net/appletalk/CVS/Repository linux-2.4-xfs/linux/net/appletalk/CVS/Repository --- linux-2.4.7/linux/net/appletalk/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/appletalk/CVS/Repository Thu Jul 5 12:07:11 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/appletalk diff -rNu linux-2.4.7/linux/net/appletalk/CVS/Root linux-2.4-xfs/linux/net/appletalk/CVS/Root --- linux-2.4.7/linux/net/appletalk/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/appletalk/CVS/Root Thu Jul 5 12:07:11 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/atm/CVS/Entries linux-2.4-xfs/linux/net/atm/CVS/Entries --- linux-2.4.7/linux/net/atm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/atm/CVS/Entries Thu Jul 5 12:07:16 2001 @@ -0,0 +1,27 @@ +/Makefile/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/addr.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/addr.h/1.3/Wed May 2 06:22:13 2001/-ko/ +/atm_misc.c/1.4/Fri Mar 24 21:32:44 2000/-ko/ +/clip.c/1.11/Thu Jun 28 05:21:16 2001/-ko/ +/common.c/1.11/Thu Jun 28 05:21:16 2001/-ko/ +/common.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/ipcommon.c/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/ipcommon.h/1.3/Mon Jul 31 16:16:28 2000/-ko/ +/lec.c/1.13/Thu Jun 28 05:21:16 2001/-ko/ +/lec.h/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/lec_arpc.h/1.1/Mon Aug 30 00:31:27 1999/-ko/ +/mpc.c/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/mpc.h/1.2/Wed Sep 15 22:45:13 1999/-ko/ +/mpoa_caches.c/1.3/Tue May 2 22:18:18 2000/-ko/ +/mpoa_caches.h/1.2/Tue May 2 22:18:18 2000/-ko/ +/mpoa_proc.c/1.8/Thu Jul 5 05:29:17 2001/-ko/ +/proc.c/1.13/Thu Jul 5 05:29:17 2001/-ko/ +/protocols.h/1.1/Mon Aug 30 00:31:27 1999/-ko/ +/pvc.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/raw.c/1.6/Tue May 2 22:18:18 2000/-ko/ +/resources.c/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/resources.h/1.2/Wed Nov 24 20:36:16 1999/-ko/ +/signaling.c/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/signaling.h/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/svc.c/1.10/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/atm/CVS/Repository linux-2.4-xfs/linux/net/atm/CVS/Repository --- linux-2.4.7/linux/net/atm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/atm/CVS/Repository Thu Jul 5 12:07:13 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/atm diff -rNu linux-2.4.7/linux/net/atm/CVS/Root linux-2.4-xfs/linux/net/atm/CVS/Root --- linux-2.4.7/linux/net/atm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/atm/CVS/Root Thu Jul 5 12:07:13 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/ax25/CVS/Entries linux-2.4-xfs/linux/net/ax25/CVS/Entries --- linux-2.4.7/linux/net/ax25/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ax25/CVS/Entries Thu Jul 5 12:07:17 2001 @@ -0,0 +1,21 @@ +/Config.in/1.5/Wed Nov 1 21:35:42 2000/-ko/ +/Makefile/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/af_ax25.c/1.19/Wed May 2 06:22:13 2001/-ko/ +/ax25_addr.c/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/ax25_dev.c/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/ax25_ds_in.c/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/ax25_ds_subr.c/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/ax25_ds_timer.c/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/ax25_iface.c/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/ax25_in.c/1.9/Mon Jul 2 15:59:04 2001/-ko/ +/ax25_ip.c/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/ax25_out.c/1.7/Wed Jan 3 01:43:05 2001/-ko/ +/ax25_route.c/1.7/Wed Jan 3 01:43:05 2001/-ko/ +/ax25_std_in.c/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/ax25_std_subr.c/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/ax25_std_timer.c/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/ax25_subr.c/1.6/Mon Jul 2 15:59:04 2001/-ko/ +/ax25_timer.c/1.5/Wed Jan 3 01:43:05 2001/-ko/ +/ax25_uid.c/1.6/Wed Jan 3 01:43:05 2001/-ko/ +/sysctl_net_ax25.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/ax25/CVS/Repository linux-2.4-xfs/linux/net/ax25/CVS/Repository --- linux-2.4.7/linux/net/ax25/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ax25/CVS/Repository Thu Jul 5 12:07:16 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/ax25 diff -rNu linux-2.4.7/linux/net/ax25/CVS/Root linux-2.4-xfs/linux/net/ax25/CVS/Root --- linux-2.4.7/linux/net/ax25/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ax25/CVS/Root Thu Jul 5 12:07:16 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/bluetooth/CVS/Entries linux-2.4-xfs/linux/net/bluetooth/CVS/Entries --- linux-2.4.7/linux/net/bluetooth/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/bluetooth/CVS/Entries Thu Jul 5 12:07:18 2001 @@ -0,0 +1,10 @@ +/Config.in/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/Makefile/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/af_bluetooth.c/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/hci_core.c/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/hci_sock.c/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/l2cap_core.c/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/l2cap_proc.c/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/lib.c/1.1/Sat Jun 9 02:44:24 2001/-ko/ +/syms.c/1.1/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/bluetooth/CVS/Repository linux-2.4-xfs/linux/net/bluetooth/CVS/Repository --- linux-2.4.7/linux/net/bluetooth/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/bluetooth/CVS/Repository Thu Jul 5 12:07:17 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/bluetooth diff -rNu linux-2.4.7/linux/net/bluetooth/CVS/Root linux-2.4-xfs/linux/net/bluetooth/CVS/Root --- linux-2.4.7/linux/net/bluetooth/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/bluetooth/CVS/Root Thu Jul 5 12:07:17 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/bridge/CVS/Entries linux-2.4-xfs/linux/net/bridge/CVS/Entries --- linux-2.4.7/linux/net/bridge/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/bridge/CVS/Entries Thu Jul 5 12:07:19 2001 @@ -0,0 +1,17 @@ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/br.c/1.18/Wed Nov 1 21:35:42 2000/-ko/ +/br_device.c/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/br_fdb.c/1.3/Sat Nov 25 08:05:45 2000/-ko/ +/br_forward.c/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/br_if.c/1.5/Sat Nov 25 08:05:45 2000/-ko/ +/br_input.c/1.7/Sat Jun 9 02:44:24 2001/-ko/ +/br_ioctl.c/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/br_notify.c/1.2/Sun Feb 27 23:06:35 2000/-ko/ +/br_private.h/1.6/Sat Jun 9 02:44:24 2001/-ko/ +/br_private_stp.h/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/br_private_timer.h/1.1/Wed Feb 23 18:55:15 2000/-ko/ +/br_stp.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/br_stp_bpdu.c/1.2/Sun Feb 27 23:06:35 2000/-ko/ +/br_stp_if.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/br_stp_timer.c/1.3/Fri May 26 01:14:50 2000/-ko/ +D diff -rNu linux-2.4.7/linux/net/bridge/CVS/Repository linux-2.4-xfs/linux/net/bridge/CVS/Repository --- linux-2.4.7/linux/net/bridge/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/bridge/CVS/Repository Thu Jul 5 12:07:18 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/bridge diff -rNu linux-2.4.7/linux/net/bridge/CVS/Root linux-2.4-xfs/linux/net/bridge/CVS/Root --- linux-2.4.7/linux/net/bridge/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/bridge/CVS/Root Thu Jul 5 12:07:18 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/core/CVS/Entries linux-2.4-xfs/linux/net/core/CVS/Entries --- linux-2.4.7/linux/net/core/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/core/CVS/Entries Thu Jul 5 12:07:22 2001 @@ -0,0 +1,18 @@ +/Makefile/1.5/Thu Dec 21 05:48:12 2000/-ko/ +/datagram.c/1.10/Wed May 2 06:22:13 2001/-ko/ +/dev.c/1.35/Thu Jun 21 15:45:04 2001/-ko/ +/dev_mcast.c/1.8/Wed Nov 1 21:35:42 2000/-ko/ +/dst.c/1.8/Sun Dec 17 19:15:00 2000/-ko/ +/dv.c/1.3/Mon Apr 2 17:13:32 2001/-ko/ +/filter.c/1.8/Tue May 29 19:53:13 2001/-ko/ +/iovec.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/neighbour.c/1.11/Sat Jun 9 02:44:24 2001/-ko/ +/netfilter.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/profile.c/1.7/Mon Jul 31 16:16:28 2000/-ko/ +/rtnetlink.c/1.7/Fri Mar 3 01:42:02 2000/-ko/ +/scm.c/1.6/Sat Nov 25 08:05:45 2000/-ko/ +/skbuff.c/1.19/Wed May 2 06:22:13 2001/-ko/ +/sock.c/1.20/Mon Jul 2 15:59:04 2001/-ko/ +/sysctl_net_core.c/1.4/Wed Nov 1 21:35:42 2000/-ko/ +/utils.c/1.3/Mon Aug 30 00:31:27 1999/-ko/ +D diff -rNu linux-2.4.7/linux/net/core/CVS/Repository linux-2.4-xfs/linux/net/core/CVS/Repository --- linux-2.4.7/linux/net/core/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/core/CVS/Repository Thu Jul 5 12:07:19 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/core diff -rNu linux-2.4.7/linux/net/core/CVS/Root linux-2.4-xfs/linux/net/core/CVS/Root --- linux-2.4.7/linux/net/core/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/core/CVS/Root Thu Jul 5 12:07:19 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/decnet/CVS/Entries linux-2.4-xfs/linux/net/decnet/CVS/Entries --- linux-2.4.7/linux/net/decnet/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/decnet/CVS/Entries Thu Jul 5 12:07:24 2001 @@ -0,0 +1,16 @@ +/Config.in/1.7/Sat Nov 25 08:05:45 2000/-ko/ +/Makefile/1.7/Thu Feb 1 17:10:24 2001/-ko/ +/README/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/TODO/1.8/Thu Feb 1 17:10:24 2001/-ko/ +/af_decnet.c/1.25/Thu Jun 28 05:21:16 2001/-ko/ +/dn_dev.c/1.11/Thu Feb 1 17:10:24 2001/-ko/ +/dn_fib.c/1.9/Thu Feb 1 17:10:24 2001/-ko/ +/dn_neigh.c/1.10/Thu Feb 1 17:10:24 2001/-ko/ +/dn_nsp_in.c/1.13/Thu Feb 1 17:10:24 2001/-ko/ +/dn_nsp_out.c/1.9/Thu Feb 1 17:10:24 2001/-ko/ +/dn_route.c/1.17/Thu Feb 1 17:10:24 2001/-ko/ +/dn_rules.c/1.2/Thu Feb 1 17:10:24 2001/-ko/ +/dn_table.c/1.5/Thu Feb 1 17:10:24 2001/-ko/ +/dn_timer.c/1.6/Thu Feb 1 17:10:24 2001/-ko/ +/sysctl_net_decnet.c/1.10/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/decnet/CVS/Repository linux-2.4-xfs/linux/net/decnet/CVS/Repository --- linux-2.4.7/linux/net/decnet/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/decnet/CVS/Repository Thu Jul 5 12:07:22 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/decnet diff -rNu linux-2.4.7/linux/net/decnet/CVS/Root linux-2.4-xfs/linux/net/decnet/CVS/Root --- linux-2.4.7/linux/net/decnet/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/decnet/CVS/Root Thu Jul 5 12:07:22 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/econet/CVS/Entries linux-2.4-xfs/linux/net/econet/CVS/Entries --- linux-2.4.7/linux/net/econet/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/econet/CVS/Entries Thu Jul 5 12:07:24 2001 @@ -0,0 +1,3 @@ +/Makefile/1.6/Wed May 2 06:22:13 2001/-ko/ +/af_econet.c/1.8/Mon Jul 2 15:59:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/econet/CVS/Repository linux-2.4-xfs/linux/net/econet/CVS/Repository --- linux-2.4.7/linux/net/econet/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/econet/CVS/Repository Thu Jul 5 12:07:24 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/econet diff -rNu linux-2.4.7/linux/net/econet/CVS/Root linux-2.4-xfs/linux/net/econet/CVS/Root --- linux-2.4.7/linux/net/econet/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/econet/CVS/Root Thu Jul 5 12:07:24 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/ethernet/CVS/Entries linux-2.4-xfs/linux/net/ethernet/CVS/Entries --- linux-2.4.7/linux/net/ethernet/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ethernet/CVS/Entries Thu Jul 5 12:07:24 2001 @@ -0,0 +1,5 @@ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/eth.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/pe2.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/sysctl_net_ether.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/net/ethernet/CVS/Repository linux-2.4-xfs/linux/net/ethernet/CVS/Repository --- linux-2.4.7/linux/net/ethernet/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ethernet/CVS/Repository Thu Jul 5 12:07:24 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/ethernet diff -rNu linux-2.4.7/linux/net/ethernet/CVS/Root linux-2.4-xfs/linux/net/ethernet/CVS/Root --- linux-2.4.7/linux/net/ethernet/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ethernet/CVS/Root Thu Jul 5 12:07:24 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/ipv4/CVS/Entries linux-2.4-xfs/linux/net/ipv4/CVS/Entries --- linux-2.4.7/linux/net/ipv4/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipv4/CVS/Entries Thu Jul 5 12:07:34 2001 @@ -0,0 +1,38 @@ +/Config.in/1.10/Tue May 29 19:53:13 2001/-ko/ +/Makefile/1.6/Thu Dec 21 05:48:12 2000/-ko/ +/af_inet.c/1.26/Thu Jun 21 15:45:04 2001/-ko/ +/arp.c/1.18/Tue May 29 19:53:13 2001/-ko/ +/devinet.c/1.12/Tue May 29 19:53:13 2001/-ko/ +/fib_frontend.c/1.10/Sat Jun 9 02:44:24 2001/-ko/ +/fib_hash.c/1.4/Mon Sep 6 21:49:56 1999/-ko/ +/fib_rules.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/fib_semantics.c/1.6/Thu Sep 28 22:42:39 2000/-ko/ +/icmp.c/1.18/Thu Jun 21 15:45:04 2001/-ko/ +/igmp.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/inetpeer.c/1.5/Mon Jul 2 15:59:04 2001/-ko/ +/ip_forward.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/ip_fragment.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/ip_gre.c/1.16/Tue May 29 19:53:13 2001/-ko/ +/ip_input.c/1.12/Wed May 2 06:22:13 2001/-ko/ +/ip_nat_dumb.c/1.5/Wed May 2 06:22:13 2001/-ko/ +/ip_options.c/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/ip_output.c/1.21/Sat Jun 9 02:44:24 2001/-ko/ +/ip_sockglue.c/1.13/Wed May 2 06:22:13 2001/-ko/ +/ipconfig.c/1.17/Tue May 29 19:53:13 2001/-ko/ +/ipip.c/1.16/Tue May 29 19:53:13 2001/-ko/ +/ipmr.c/1.16/Mon Jul 2 15:59:04 2001/-ko/ +/proc.c/1.11/Tue May 29 19:53:13 2001/-ko/ +/protocol.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/raw.c/1.19/Thu Jun 21 15:45:04 2001/-ko/ +/route.c/1.22/Tue May 29 19:53:13 2001/-ko/ +/syncookies.c/1.10/Tue May 29 19:53:13 2001/-ko/ +/sysctl_net_ipv4.c/1.11/Mon Apr 2 17:13:32 2001/-ko/ +/tcp.c/1.27/Tue May 29 19:53:13 2001/-ko/ +/tcp_input.c/1.26/Sat Jun 9 02:44:24 2001/-ko/ +/tcp_ipv4.c/1.32/Wed May 2 06:22:13 2001/-ko/ +/tcp_minisocks.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/tcp_output.c/1.18/Mon Jul 2 15:59:04 2001/-ko/ +/tcp_timer.c/1.18/Wed May 2 06:22:13 2001/-ko/ +/udp.c/1.23/Wed May 2 06:22:13 2001/-ko/ +/utils.c/1.4/Wed Nov 1 21:35:42 2000/-ko/ +D diff -rNu linux-2.4.7/linux/net/ipv4/CVS/Entries.Log linux-2.4-xfs/linux/net/ipv4/CVS/Entries.Log --- linux-2.4.7/linux/net/ipv4/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipv4/CVS/Entries.Log Thu Jul 5 12:07:34 2001 @@ -0,0 +1 @@ +A D/netfilter//// diff -rNu linux-2.4.7/linux/net/ipv4/CVS/Repository linux-2.4-xfs/linux/net/ipv4/CVS/Repository --- linux-2.4.7/linux/net/ipv4/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipv4/CVS/Repository Thu Jul 5 12:07:24 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/ipv4 diff -rNu linux-2.4.7/linux/net/ipv4/CVS/Root linux-2.4-xfs/linux/net/ipv4/CVS/Root --- linux-2.4.7/linux/net/ipv4/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipv4/CVS/Root Thu Jul 5 12:07:24 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/ipv4/netfilter/CVS/Entries linux-2.4-xfs/linux/net/ipv4/netfilter/CVS/Entries --- linux-2.4.7/linux/net/ipv4/netfilter/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipv4/netfilter/CVS/Entries Thu Jul 5 12:07:40 2001 @@ -0,0 +1,45 @@ +/Config.in/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/Makefile/1.8/Wed May 2 06:22:13 2001/-ko/ +/ip_conntrack_core.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/ip_conntrack_ftp.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/ip_conntrack_proto_generic.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/ip_conntrack_proto_icmp.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/ip_conntrack_proto_tcp.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/ip_conntrack_proto_udp.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/ip_conntrack_standalone.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/ip_fw_compat.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/ip_fw_compat_masq.c/1.5/Mon Oct 23 18:56:35 2000/-ko/ +/ip_fw_compat_redir.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/ip_nat_core.c/1.6/Tue May 29 19:53:13 2001/-ko/ +/ip_nat_ftp.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/ip_nat_helper.c/1.1/Wed May 2 06:22:13 2001/-ko/ +/ip_nat_proto_icmp.c/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ip_nat_proto_tcp.c/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ip_nat_proto_udp.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/ip_nat_proto_unknown.c/1.1/Mon Mar 20 18:07:46 2000/-ko/ +/ip_nat_rule.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/ip_nat_standalone.c/1.10/Wed May 2 06:22:13 2001/-ko/ +/ip_queue.c/1.8/Sun Dec 17 19:15:00 2000/-ko/ +/ip_tables.c/1.9/Tue May 29 19:53:13 2001/-ko/ +/ipchains_core.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/ipfwadm_core.c/1.5/Sat Jun 9 02:44:24 2001/-ko/ +/ipt_LOG.c/1.6/Fri Jan 5 18:42:30 2001/-ko/ +/ipt_MARK.c/1.3/Fri May 26 01:14:50 2000/-ko/ +/ipt_MASQUERADE.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/ipt_MIRROR.c/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/ipt_REDIRECT.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/ipt_REJECT.c/1.10/Sat Jun 9 02:44:24 2001/-ko/ +/ipt_TCPMSS.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/ipt_TOS.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/ipt_limit.c/1.4/Thu Sep 28 22:42:39 2000/-ko/ +/ipt_mac.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/ipt_mark.c/1.3/Fri May 26 01:14:50 2000/-ko/ +/ipt_multiport.c/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/ipt_owner.c/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/ipt_state.c/1.3/Fri May 26 01:14:50 2000/-ko/ +/ipt_tcpmss.c/1.1/Mon Apr 2 17:13:32 2001/-ko/ +/ipt_tos.c/1.3/Fri May 26 01:14:50 2000/-ko/ +/ipt_unclean.c/1.4/Thu Jun 21 15:45:04 2001/-ko/ +/iptable_filter.c/1.3/Fri May 26 01:26:22 2000/-ko/ +/iptable_mangle.c/1.5/Thu Feb 1 17:10:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/ipv4/netfilter/CVS/Repository linux-2.4-xfs/linux/net/ipv4/netfilter/CVS/Repository --- linux-2.4.7/linux/net/ipv4/netfilter/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipv4/netfilter/CVS/Repository Thu Jul 5 12:07:34 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/ipv4/netfilter diff -rNu linux-2.4.7/linux/net/ipv4/netfilter/CVS/Root linux-2.4-xfs/linux/net/ipv4/netfilter/CVS/Root --- linux-2.4.7/linux/net/ipv4/netfilter/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipv4/netfilter/CVS/Root Thu Jul 5 12:07:34 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/ipv6/CVS/Entries linux-2.4-xfs/linux/net/ipv6/CVS/Entries --- linux-2.4.7/linux/net/ipv6/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipv6/CVS/Entries Thu Jul 5 12:07:46 2001 @@ -0,0 +1,26 @@ +/Config.in/1.6/Tue May 29 19:53:13 2001/-ko/ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/README/1.3/Mon Nov 8 22:55:41 1999/-ko/ +/addrconf.c/1.17/Thu Jun 21 15:45:04 2001/-ko/ +/af_inet6.c/1.17/Thu Jun 21 15:45:04 2001/-ko/ +/datagram.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/exthdrs.c/1.5/Thu Jun 21 15:45:04 2001/-ko/ +/icmp.c/1.11/Thu Jun 21 15:45:04 2001/-ko/ +/ip6_fib.c/1.9/Thu Jun 21 15:45:04 2001/-ko/ +/ip6_flowlabel.c/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/ip6_fw.c/1.5/Mon Sep 6 21:49:56 1999/-ko/ +/ip6_input.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/ip6_output.c/1.9/Wed May 2 06:22:13 2001/-ko/ +/ipv6_sockglue.c/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/mcast.c/1.14/Wed May 2 06:22:13 2001/-ko/ +/ndisc.c/1.13/Tue May 29 19:53:13 2001/-ko/ +/proc.c/1.8/Mon Jul 31 16:16:28 2000/-ko/ +/protocol.c/1.7/Tue May 29 19:53:13 2001/-ko/ +/raw.c/1.18/Thu Jun 21 15:45:04 2001/-ko/ +/reassembly.c/1.10/Wed May 2 06:22:13 2001/-ko/ +/route.c/1.17/Tue May 29 19:53:13 2001/-ko/ +/sit.c/1.15/Tue May 29 19:53:13 2001/-ko/ +/sysctl_net_ipv6.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/tcp_ipv6.c/1.24/Thu Jun 21 15:45:04 2001/-ko/ +/udp.c/1.21/Thu Jun 21 15:45:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/ipv6/CVS/Entries.Log linux-2.4-xfs/linux/net/ipv6/CVS/Entries.Log --- linux-2.4.7/linux/net/ipv6/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipv6/CVS/Entries.Log Thu Jul 5 12:07:46 2001 @@ -0,0 +1 @@ +A D/netfilter//// diff -rNu linux-2.4.7/linux/net/ipv6/CVS/Repository linux-2.4-xfs/linux/net/ipv6/CVS/Repository --- linux-2.4.7/linux/net/ipv6/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipv6/CVS/Repository Thu Jul 5 12:07:40 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/ipv6 diff -rNu linux-2.4.7/linux/net/ipv6/CVS/Root linux-2.4-xfs/linux/net/ipv6/CVS/Root --- linux-2.4.7/linux/net/ipv6/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipv6/CVS/Root Thu Jul 5 12:07:40 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/ipv6/netfilter/CVS/Entries linux-2.4-xfs/linux/net/ipv6/netfilter/CVS/Entries --- linux-2.4.7/linux/net/ipv6/netfilter/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipv6/netfilter/CVS/Entries Thu Jul 5 12:07:47 2001 @@ -0,0 +1,11 @@ +/Config.in/1.2/Fri Jun 2 00:22:59 2000/-ko/ +/Makefile/1.5/Wed May 2 06:22:13 2001/-ko/ +/ip6_tables.c/1.5/Tue May 29 19:53:13 2001/-ko/ +/ip6t_MARK.c/1.2/Thu Feb 1 17:10:24 2001/-ko/ +/ip6t_limit.c/1.1/Fri May 26 01:52:46 2000/-ko/ +/ip6t_mac.c/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/ip6t_mark.c/1.2/Thu Feb 1 17:10:24 2001/-ko/ +/ip6t_multiport.c/1.1/Mon Jul 31 16:16:28 2000/-ko/ +/ip6table_filter.c/1.2/Thu Sep 28 22:42:39 2000/-ko/ +/ip6table_mangle.c/1.1/Thu Feb 1 17:10:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/ipv6/netfilter/CVS/Repository linux-2.4-xfs/linux/net/ipv6/netfilter/CVS/Repository --- linux-2.4.7/linux/net/ipv6/netfilter/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipv6/netfilter/CVS/Repository Thu Jul 5 12:07:46 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/ipv6/netfilter diff -rNu linux-2.4.7/linux/net/ipv6/netfilter/CVS/Root linux-2.4-xfs/linux/net/ipv6/netfilter/CVS/Root --- linux-2.4.7/linux/net/ipv6/netfilter/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipv6/netfilter/CVS/Root Thu Jul 5 12:07:46 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/ipx/CVS/Entries linux-2.4-xfs/linux/net/ipx/CVS/Entries --- linux-2.4.7/linux/net/ipx/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipx/CVS/Entries Thu Jul 5 12:07:50 2001 @@ -0,0 +1,6 @@ +/Config.in/1.4/Sat Nov 25 08:05:45 2000/-ko/ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/af_ipx.c/1.20/Tue May 29 19:53:13 2001/-ko/ +/af_spx.c/1.14/Tue Jul 3 02:33:57 2001/-ko/ +/sysctl_net_ipx.c/1.5/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/ipx/CVS/Repository linux-2.4-xfs/linux/net/ipx/CVS/Repository --- linux-2.4.7/linux/net/ipx/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipx/CVS/Repository Thu Jul 5 12:07:47 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/ipx diff -rNu linux-2.4.7/linux/net/ipx/CVS/Root linux-2.4-xfs/linux/net/ipx/CVS/Root --- linux-2.4.7/linux/net/ipx/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/ipx/CVS/Root Thu Jul 5 12:07:47 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/irda/CVS/Entries linux-2.4-xfs/linux/net/irda/CVS/Entries --- linux-2.4.7/linux/net/irda/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/irda/CVS/Entries Thu Jul 5 12:07:55 2001 @@ -0,0 +1,25 @@ +/Config.in/1.7/Sat Nov 25 08:05:45 2000/-ko/ +/Makefile/1.7/Thu Jul 5 05:29:17 2001/-ko/ +/af_irda.c/1.21/Thu Jul 5 05:29:17 2001/-ko/ +/crc.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/discovery.c/1.7/Sat Nov 25 08:05:45 2000/-ko/ +/irda_device.c/1.18/Wed May 2 06:22:13 2001/-ko/ +/iriap.c/1.10/Sat Nov 25 08:05:45 2000/-ko/ +/iriap_event.c/1.8/Fri Mar 3 01:42:02 2000/-ko/ +/irias_object.c/1.9/Thu Jul 5 05:29:17 2001/-ko/ +/irlap.c/1.12/Thu Jul 5 05:29:17 2001/-ko/ +/irlap_event.c/1.14/Thu Jul 5 05:29:17 2001/-ko/ +/irlap_frame.c/1.13/Thu Jul 5 05:29:17 2001/-ko/ +/irlmp.c/1.12/Thu Jul 5 05:29:17 2001/-ko/ +/irlmp_event.c/1.10/Thu Jul 5 05:29:17 2001/-ko/ +/irlmp_frame.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/irproc.c/1.10/Thu Jul 5 05:29:17 2001/-ko/ +/irqueue.c/1.8/Thu Jul 5 05:29:17 2001/-ko/ +/irsyms.c/1.2/Thu Jul 5 05:29:17 2001/-ko/ +/irsysctl.c/1.5/Thu Jul 5 05:29:17 2001/-ko/ +/irttp.c/1.14/Thu Jul 5 05:29:17 2001/-ko/ +/parameters.c/1.7/Sat Nov 25 08:05:45 2000/-ko/ +/qos.c/1.12/Thu Jul 5 05:29:17 2001/-ko/ +/timer.c/1.7/Sat Nov 25 08:05:45 2000/-ko/ +/wrapper.c/1.10/Tue May 29 19:53:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/irda/CVS/Entries.Log linux-2.4-xfs/linux/net/irda/CVS/Entries.Log --- linux-2.4.7/linux/net/irda/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/irda/CVS/Entries.Log Thu Jul 5 12:07:57 2001 @@ -0,0 +1,3 @@ +A D/ircomm//// +A D/irlan//// +A D/irnet//// diff -rNu linux-2.4.7/linux/net/irda/CVS/Repository linux-2.4-xfs/linux/net/irda/CVS/Repository --- linux-2.4.7/linux/net/irda/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/irda/CVS/Repository Thu Jul 5 12:07:50 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/irda diff -rNu linux-2.4.7/linux/net/irda/CVS/Root linux-2.4-xfs/linux/net/irda/CVS/Root --- linux-2.4.7/linux/net/irda/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/irda/CVS/Root Thu Jul 5 12:07:50 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/irda/ircomm/CVS/Entries linux-2.4-xfs/linux/net/irda/ircomm/CVS/Entries --- linux-2.4.7/linux/net/irda/ircomm/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/irda/ircomm/CVS/Entries Thu Jul 5 12:07:56 2001 @@ -0,0 +1,11 @@ +/Config.in/1.3/Wed Oct 6 23:00:36 1999/-ko/ +/Makefile/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/ircomm_core.c/1.10/Mon Apr 2 17:13:32 2001/-ko/ +/ircomm_event.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/ircomm_lmp.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/ircomm_param.c/1.6/Fri Mar 24 21:32:44 2000/-ko/ +/ircomm_ttp.c/1.5/Mon Apr 2 17:13:32 2001/-ko/ +/ircomm_tty.c/1.12/Mon Apr 2 17:13:32 2001/-ko/ +/ircomm_tty_attach.c/1.7/Sat Nov 25 08:05:45 2000/-ko/ +/ircomm_tty_ioctl.c/1.6/Thu Jul 5 05:29:17 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/irda/ircomm/CVS/Repository linux-2.4-xfs/linux/net/irda/ircomm/CVS/Repository --- linux-2.4.7/linux/net/irda/ircomm/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/irda/ircomm/CVS/Repository Thu Jul 5 12:07:55 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/irda/ircomm diff -rNu linux-2.4.7/linux/net/irda/ircomm/CVS/Root linux-2.4-xfs/linux/net/irda/ircomm/CVS/Root --- linux-2.4.7/linux/net/irda/ircomm/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/irda/ircomm/CVS/Root Thu Jul 5 12:07:55 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/irda/irlan/CVS/Entries linux-2.4-xfs/linux/net/irda/irlan/CVS/Entries --- linux-2.4.7/linux/net/irda/irlan/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/irda/irlan/CVS/Entries Thu Jul 5 12:07:57 2001 @@ -0,0 +1,11 @@ +/Config.in/1.3/Wed Oct 6 23:00:36 1999/-ko/ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/irlan_client.c/1.10/Thu Feb 22 21:09:04 2001/-ko/ +/irlan_client_event.c/1.6/Sun Dec 17 19:15:00 2000/-ko/ +/irlan_common.c/1.15/Thu Jul 5 05:29:17 2001/-ko/ +/irlan_eth.c/1.14/Thu Feb 22 21:09:04 2001/-ko/ +/irlan_event.c/1.3/Mon Nov 8 22:55:41 1999/-ko/ +/irlan_filter.c/1.3/Mon Nov 8 22:55:41 1999/-ko/ +/irlan_provider.c/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/irlan_provider_event.c/1.3/Mon Nov 8 22:55:41 1999/-ko/ +D diff -rNu linux-2.4.7/linux/net/irda/irlan/CVS/Repository linux-2.4-xfs/linux/net/irda/irlan/CVS/Repository --- linux-2.4.7/linux/net/irda/irlan/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/irda/irlan/CVS/Repository Thu Jul 5 12:07:56 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/irda/irlan diff -rNu linux-2.4.7/linux/net/irda/irlan/CVS/Root linux-2.4-xfs/linux/net/irda/irlan/CVS/Root --- linux-2.4.7/linux/net/irda/irlan/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/irda/irlan/CVS/Root Thu Jul 5 12:07:56 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/irda/irnet/CVS/Entries linux-2.4-xfs/linux/net/irda/irnet/CVS/Entries --- linux-2.4.7/linux/net/irda/irnet/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/irda/irnet/CVS/Entries Thu Jul 5 12:07:58 2001 @@ -0,0 +1,8 @@ +/Config.in/1.2/Mon Apr 2 17:13:32 2001/-ko/ +/Makefile/1.2/Thu Dec 21 05:48:12 2000/-ko/ +/irnet.h/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/irnet_irda.c/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/irnet_irda.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +/irnet_ppp.c/1.4/Sat Jun 9 02:44:24 2001/-ko/ +/irnet_ppp.h/1.3/Sat Jun 9 02:44:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/irda/irnet/CVS/Repository linux-2.4-xfs/linux/net/irda/irnet/CVS/Repository --- linux-2.4.7/linux/net/irda/irnet/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/irda/irnet/CVS/Repository Thu Jul 5 12:07:57 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/irda/irnet diff -rNu linux-2.4.7/linux/net/irda/irnet/CVS/Root linux-2.4-xfs/linux/net/irda/irnet/CVS/Root --- linux-2.4.7/linux/net/irda/irnet/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/irda/irnet/CVS/Root Thu Jul 5 12:07:57 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/khttpd/CVS/Entries linux-2.4-xfs/linux/net/khttpd/CVS/Entries --- linux-2.4.7/linux/net/khttpd/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/khttpd/CVS/Entries Thu Jul 5 12:07:59 2001 @@ -0,0 +1,21 @@ +/Config.in/1.2/Mon Oct 18 06:25:48 1999/-ko/ +/Makefile/1.3/Thu Dec 21 05:48:12 2000/-ko/ +/README/1.2/Sat Nov 25 08:05:45 2000/-ko/ +/accept.c/1.3/Sat Jan 29 23:15:44 2000/-ko/ +/datasending.c/1.7/Sat Nov 25 08:05:45 2000/-ko/ +/logging.c/1.1/Sun Aug 29 03:09:59 1999/-ko/ +/main.c/1.8/Mon Apr 2 17:13:32 2001/-ko/ +/make_times_h.c/1.1/Sun Aug 29 03:09:59 1999/-ko/ +/misc.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/prototypes.h/1.1/Sun Aug 29 03:09:59 1999/-ko/ +/rfc.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/rfc_time.c/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/security.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/security.h/1.2/Wed Jun 13 03:24:09 2001/-ko/ +/sockets.c/1.4/Fri Apr 21 16:16:46 2000/-ko/ +/structure.h/1.3/Fri Feb 11 01:00:06 2000/-ko/ +/sysctl.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/sysctl.h/1.1/Sun Aug 29 03:09:59 1999/-ko/ +/userspace.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/waitheaders.c/1.4/Fri Apr 21 16:16:46 2000/-ko/ +D diff -rNu linux-2.4.7/linux/net/khttpd/CVS/Repository linux-2.4-xfs/linux/net/khttpd/CVS/Repository --- linux-2.4.7/linux/net/khttpd/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/khttpd/CVS/Repository Thu Jul 5 12:07:58 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/khttpd diff -rNu linux-2.4.7/linux/net/khttpd/CVS/Root linux-2.4-xfs/linux/net/khttpd/CVS/Root --- linux-2.4.7/linux/net/khttpd/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/khttpd/CVS/Root Thu Jul 5 12:07:58 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/lapb/CVS/Entries linux-2.4-xfs/linux/net/lapb/CVS/Entries --- linux-2.4.7/linux/net/lapb/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/lapb/CVS/Entries Thu Jul 5 12:07:59 2001 @@ -0,0 +1,7 @@ +/Makefile/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/lapb_iface.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/lapb_in.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/lapb_out.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/lapb_subr.c/1.4/Mon Jul 2 15:59:04 2001/-ko/ +/lapb_timer.c/1.4/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/lapb/CVS/Repository linux-2.4-xfs/linux/net/lapb/CVS/Repository --- linux-2.4.7/linux/net/lapb/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/lapb/CVS/Repository Thu Jul 5 12:07:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/lapb diff -rNu linux-2.4.7/linux/net/lapb/CVS/Root linux-2.4-xfs/linux/net/lapb/CVS/Root --- linux-2.4.7/linux/net/lapb/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/lapb/CVS/Root Thu Jul 5 12:07:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/netlink/CVS/Entries linux-2.4-xfs/linux/net/netlink/CVS/Entries --- linux-2.4.7/linux/net/netlink/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/netlink/CVS/Entries Thu Jul 5 12:07:59 2001 @@ -0,0 +1,4 @@ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/af_netlink.c/1.15/Mon Jul 2 15:59:04 2001/-ko/ +/netlink_dev.c/1.9/Thu Feb 22 21:09:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/netlink/CVS/Repository linux-2.4-xfs/linux/net/netlink/CVS/Repository --- linux-2.4.7/linux/net/netlink/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/netlink/CVS/Repository Thu Jul 5 12:07:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/netlink diff -rNu linux-2.4.7/linux/net/netlink/CVS/Root linux-2.4-xfs/linux/net/netlink/CVS/Root --- linux-2.4.7/linux/net/netlink/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/netlink/CVS/Root Thu Jul 5 12:07:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/netrom/CVS/Entries linux-2.4-xfs/linux/net/netrom/CVS/Entries --- linux-2.4.7/linux/net/netrom/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/netrom/CVS/Entries Thu Jul 5 12:08:00 2001 @@ -0,0 +1,11 @@ +/Makefile/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/af_netrom.c/1.17/Wed May 2 06:22:13 2001/-ko/ +/nr_dev.c/1.8/Thu Jun 28 05:21:16 2001/-ko/ +/nr_in.c/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/nr_loopback.c/1.7/Thu Jun 28 05:21:16 2001/-ko/ +/nr_out.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/nr_route.c/1.7/Wed Jan 3 01:43:05 2001/-ko/ +/nr_subr.c/1.4/Thu Jun 28 05:21:16 2001/-ko/ +/nr_timer.c/1.4/Wed Jan 3 01:43:05 2001/-ko/ +/sysctl_net_netrom.c/1.3/Mon Sep 6 21:49:56 1999/-ko/ +D diff -rNu linux-2.4.7/linux/net/netrom/CVS/Repository linux-2.4-xfs/linux/net/netrom/CVS/Repository --- linux-2.4.7/linux/net/netrom/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/netrom/CVS/Repository Thu Jul 5 12:07:59 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/netrom diff -rNu linux-2.4.7/linux/net/netrom/CVS/Root linux-2.4-xfs/linux/net/netrom/CVS/Root --- linux-2.4.7/linux/net/netrom/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/netrom/CVS/Root Thu Jul 5 12:07:59 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/packet/CVS/Entries linux-2.4-xfs/linux/net/packet/CVS/Entries --- linux-2.4.7/linux/net/packet/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/packet/CVS/Entries Thu Jul 5 12:08:00 2001 @@ -0,0 +1,3 @@ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/af_packet.c/1.23/Mon Jul 2 15:59:04 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/packet/CVS/Repository linux-2.4-xfs/linux/net/packet/CVS/Repository --- linux-2.4.7/linux/net/packet/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/packet/CVS/Repository Thu Jul 5 12:08:00 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/packet diff -rNu linux-2.4.7/linux/net/packet/CVS/Root linux-2.4-xfs/linux/net/packet/CVS/Root --- linux-2.4.7/linux/net/packet/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/packet/CVS/Root Thu Jul 5 12:08:00 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/rose/CVS/Entries linux-2.4-xfs/linux/net/rose/CVS/Entries --- linux-2.4.7/linux/net/rose/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/rose/CVS/Entries Thu Jul 5 12:08:01 2001 @@ -0,0 +1,12 @@ +/Makefile/1.4/Thu Feb 22 21:09:04 2001/-ko/ +/af_rose.c/1.18/Wed May 2 06:22:13 2001/-ko/ +/rose_dev.c/1.8/Thu Jun 28 05:21:16 2001/-ko/ +/rose_in.c/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/rose_link.c/1.5/Wed Jan 3 01:43:05 2001/-ko/ +/rose_loopback.c/1.5/Wed Jan 3 01:43:05 2001/-ko/ +/rose_out.c/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/rose_route.c/1.7/Mon Jul 2 15:59:04 2001/-ko/ +/rose_subr.c/1.4/Mon Jul 2 15:59:04 2001/-ko/ +/rose_timer.c/1.3/Wed Jan 3 01:43:05 2001/-ko/ +/sysctl_net_rose.c/1.3/Mon Sep 6 21:49:56 1999/-ko/ +D diff -rNu linux-2.4.7/linux/net/rose/CVS/Repository linux-2.4-xfs/linux/net/rose/CVS/Repository --- linux-2.4.7/linux/net/rose/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/rose/CVS/Repository Thu Jul 5 12:08:00 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/rose diff -rNu linux-2.4.7/linux/net/rose/CVS/Root linux-2.4-xfs/linux/net/rose/CVS/Root --- linux-2.4.7/linux/net/rose/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/rose/CVS/Root Thu Jul 5 12:08:00 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/sched/CVS/Entries linux-2.4-xfs/linux/net/sched/CVS/Entries --- linux-2.4.7/linux/net/sched/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/sched/CVS/Entries Thu Jul 5 12:08:05 2001 @@ -0,0 +1,27 @@ +/Config.in/1.7/Fri Jan 21 19:20:14 2000/-ko/ +/Makefile/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/cls_api.c/1.6/Sun Jan 9 23:56:19 2000/-ko/ +/cls_fw.c/1.4/Mon Mar 20 18:07:46 2000/-ko/ +/cls_route.c/1.3/Sun Aug 29 03:09:59 1999/-ko/ +/cls_rsvp.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cls_rsvp.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cls_rsvp6.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/cls_tcindex.c/1.4/Mon Apr 2 17:13:32 2001/-ko/ +/cls_u32.c/1.4/Thu Feb 1 17:10:24 2001/-ko/ +/estimator.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/police.c/1.3/Mon Aug 30 00:31:27 1999/-ko/ +/sch_api.c/1.10/Fri Jan 5 18:42:30 2001/-ko/ +/sch_atm.c/1.6/Thu Feb 22 21:09:04 2001/-ko/ +/sch_cbq.c/1.9/Sat Jun 9 02:44:24 2001/-ko/ +/sch_csz.c/1.3/Mon Aug 30 00:31:27 1999/-ko/ +/sch_dsmark.c/1.6/Mon Apr 2 17:13:32 2001/-ko/ +/sch_fifo.c/1.3/Mon Aug 30 00:31:27 1999/-ko/ +/sch_generic.c/1.10/Thu Sep 28 22:42:39 2000/-ko/ +/sch_gred.c/1.6/Mon Jul 2 15:59:04 2001/-ko/ +/sch_ingress.c/1.5/Thu Sep 28 22:42:39 2000/-ko/ +/sch_prio.c/1.4/Sun Jan 9 23:56:19 2000/-ko/ +/sch_red.c/1.7/Mon Jul 2 15:59:04 2001/-ko/ +/sch_sfq.c/1.3/Mon Aug 30 00:31:27 1999/-ko/ +/sch_tbf.c/1.7/Mon Apr 2 17:13:32 2001/-ko/ +/sch_teql.c/1.10/Mon Jul 31 16:16:28 2000/-ko/ +D diff -rNu linux-2.4.7/linux/net/sched/CVS/Repository linux-2.4-xfs/linux/net/sched/CVS/Repository --- linux-2.4.7/linux/net/sched/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/sched/CVS/Repository Thu Jul 5 12:08:01 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/sched diff -rNu linux-2.4.7/linux/net/sched/CVS/Root linux-2.4-xfs/linux/net/sched/CVS/Root --- linux-2.4.7/linux/net/sched/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/sched/CVS/Root Thu Jul 5 12:08:01 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/sunrpc/CVS/Entries linux-2.4-xfs/linux/net/sunrpc/CVS/Entries --- linux-2.4.7/linux/net/sunrpc/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/sunrpc/CVS/Entries Thu Jul 5 12:08:07 2001 @@ -0,0 +1,17 @@ +/Makefile/1.4/Thu Dec 21 05:48:12 2000/-ko/ +/auth.c/1.8/Thu Feb 22 21:09:04 2001/-ko/ +/auth_null.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/auth_unix.c/1.5/Thu Feb 22 21:09:04 2001/-ko/ +/clnt.c/1.12/Wed May 2 06:22:13 2001/-ko/ +/pmap_clnt.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/sched.c/1.17/Wed May 2 06:22:13 2001/-ko/ +/stats.c/1.6/Thu Dec 9 03:05:16 1999/-ko/ +/sunrpc_syms.c/1.7/Thu Feb 1 17:10:24 2001/-ko/ +/svc.c/1.7/Thu Jun 21 15:45:04 2001/-ko/ +/svcauth.c/1.3/Fri May 26 01:14:50 2000/-ko/ +/svcauth_des.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/svcsock.c/1.15/Thu Jul 5 05:29:17 2001/-ko/ +/sysctl.c/1.8/Wed May 2 06:22:13 2001/-ko/ +/xdr.c/1.3/Fri Apr 21 16:16:46 2000/-ko/ +/xprt.c/1.16/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/sunrpc/CVS/Repository linux-2.4-xfs/linux/net/sunrpc/CVS/Repository --- linux-2.4.7/linux/net/sunrpc/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/sunrpc/CVS/Repository Thu Jul 5 12:08:05 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/sunrpc diff -rNu linux-2.4.7/linux/net/sunrpc/CVS/Root linux-2.4-xfs/linux/net/sunrpc/CVS/Root --- linux-2.4.7/linux/net/sunrpc/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/sunrpc/CVS/Root Thu Jul 5 12:08:05 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/unix/CVS/Entries linux-2.4-xfs/linux/net/unix/CVS/Entries --- linux-2.4.7/linux/net/unix/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/unix/CVS/Entries Thu Jul 5 12:08:08 2001 @@ -0,0 +1,5 @@ +/Makefile/1.4/Thu Feb 1 17:10:24 2001/-ko/ +/af_unix.c/1.29/Mon Jul 2 15:59:04 2001/-ko/ +/garbage.c/1.9/Mon Jul 2 15:59:04 2001/-ko/ +/sysctl_net_unix.c/1.6/Thu Feb 1 17:10:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/unix/CVS/Repository linux-2.4-xfs/linux/net/unix/CVS/Repository --- linux-2.4.7/linux/net/unix/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/unix/CVS/Repository Thu Jul 5 12:08:07 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/unix diff -rNu linux-2.4.7/linux/net/unix/CVS/Root linux-2.4-xfs/linux/net/unix/CVS/Root --- linux-2.4.7/linux/net/unix/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/unix/CVS/Root Thu Jul 5 12:08:07 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/wanrouter/CVS/Entries linux-2.4-xfs/linux/net/wanrouter/CVS/Entries --- linux-2.4.7/linux/net/wanrouter/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/wanrouter/CVS/Entries Thu Jul 5 12:08:09 2001 @@ -0,0 +1,6 @@ +/Makefile/1.5/Tue May 29 19:53:13 2001/-ko/ +/af_wanpipe.c/1.2/Fri Jun 29 22:21:45 2001/-ko/ +/patchlevel/1.3/Wed May 2 06:22:13 2001/-ko/ +/wanmain.c/1.11/Thu Jun 28 05:21:16 2001/-ko/ +/wanproc.c/1.15/Thu Jun 28 05:21:16 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/wanrouter/CVS/Repository linux-2.4-xfs/linux/net/wanrouter/CVS/Repository --- linux-2.4.7/linux/net/wanrouter/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/wanrouter/CVS/Repository Thu Jul 5 12:08:08 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/wanrouter diff -rNu linux-2.4.7/linux/net/wanrouter/CVS/Root linux-2.4-xfs/linux/net/wanrouter/CVS/Root --- linux-2.4.7/linux/net/wanrouter/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/wanrouter/CVS/Root Thu Jul 5 12:08:08 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/net/x25/CVS/Entries linux-2.4-xfs/linux/net/x25/CVS/Entries --- linux-2.4.7/linux/net/x25/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/x25/CVS/Entries Thu Jul 5 12:08:09 2001 @@ -0,0 +1,12 @@ +/Makefile/1.4/Thu Feb 1 17:10:24 2001/-ko/ +/af_x25.c/1.20/Wed May 2 06:22:13 2001/-ko/ +/sysctl_net_x25.c/1.3/Mon Sep 6 21:49:56 1999/-ko/ +/x25_dev.c/1.8/Thu Feb 1 17:10:24 2001/-ko/ +/x25_facilities.c/1.4/Thu Feb 1 17:10:24 2001/-ko/ +/x25_in.c/1.7/Thu Feb 1 17:10:24 2001/-ko/ +/x25_link.c/1.9/Mon Jul 2 15:59:04 2001/-ko/ +/x25_out.c/1.6/Wed May 2 06:22:13 2001/-ko/ +/x25_route.c/1.6/Thu Feb 1 17:10:24 2001/-ko/ +/x25_subr.c/1.5/Mon Jul 2 15:59:04 2001/-ko/ +/x25_timer.c/1.4/Thu Feb 1 17:10:24 2001/-ko/ +D diff -rNu linux-2.4.7/linux/net/x25/CVS/Repository linux-2.4-xfs/linux/net/x25/CVS/Repository --- linux-2.4.7/linux/net/x25/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/x25/CVS/Repository Thu Jul 5 12:08:09 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/net/x25 diff -rNu linux-2.4.7/linux/net/x25/CVS/Root linux-2.4-xfs/linux/net/x25/CVS/Root --- linux-2.4.7/linux/net/x25/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/net/x25/CVS/Root Thu Jul 5 12:08:09 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/scripts/CVS/Entries linux-2.4-xfs/linux/scripts/CVS/Entries --- linux-2.4.7/linux/scripts/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/scripts/CVS/Entries Thu Jul 5 12:08:12 2001 @@ -0,0 +1,26 @@ +/Configure/1.12/Tue Jul 3 02:33:57 2001/-ko/ +/Lindent/1.1/Thu Feb 22 21:09:04 2001/-ko/ +/MAKEDEV.ide/1.3/Sun Aug 29 02:28:51 1999/-ko/ +/Makefile/1.4/Mon Mar 20 18:07:46 2000/-ko/ +/Menuconfig/1.11/Tue Jul 3 02:33:57 2001/-ko/ +/README.Menuconfig/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/checkconfig.pl/1.5/Tue May 29 19:53:13 2001/-ko/ +/checkhelp.pl/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/checkincludes.pl/1.1/Fri Apr 21 16:16:46 2000/-ko/ +/docgen/1.2/Thu Jun 21 15:45:04 2001/-ko/ +/docproc.c/1.4/Thu Jun 21 15:45:04 2001/-ko/ +/gen-all-syms/1.2/Fri Apr 21 16:16:46 2000/-ko/ +/header.tk/1.7/Tue Jul 3 02:33:57 2001/-ko/ +/kernel-doc/1.10/Tue Jul 3 02:33:57 2001/-ko/ +/makelst/1.2/Thu Feb 22 21:09:04 2001/-ko/ +/mkdep.c/1.12/Tue Feb 27 03:57:03 2001/-ko/ +/patch-kernel/1.3/Wed Dec 15 00:05:45 1999/-ko/ +/pathdown.sh/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/split-include.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/tail.tk/1.5/Mon Jul 31 16:16:28 2000/-ko/ +/tkcond.c/1.5/Wed Feb 23 18:55:15 2000/-ko/ +/tkgen.c/1.7/Wed May 2 06:22:13 2001/-ko/ +/tkparse.c/1.7/Wed Nov 1 21:35:42 2000/-ko/ +/tkparse.h/1.4/Wed Feb 23 18:55:15 2000/-ko/ +/ver_linux/1.8/Wed May 2 06:22:13 2001/-ko/ +D diff -rNu linux-2.4.7/linux/scripts/CVS/Entries.Log linux-2.4-xfs/linux/scripts/CVS/Entries.Log --- linux-2.4.7/linux/scripts/CVS/Entries.Log Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/scripts/CVS/Entries.Log Thu Jul 5 12:08:12 2001 @@ -0,0 +1,3 @@ +A D/cramfs//// +A D/ksymoops//// +A D/lxdialog//// diff -rNu linux-2.4.7/linux/scripts/CVS/Repository linux-2.4-xfs/linux/scripts/CVS/Repository --- linux-2.4.7/linux/scripts/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/scripts/CVS/Repository Thu Jul 5 12:08:09 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/scripts diff -rNu linux-2.4.7/linux/scripts/CVS/Root linux-2.4-xfs/linux/scripts/CVS/Root --- linux-2.4.7/linux/scripts/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/scripts/CVS/Root Thu Jul 5 12:08:09 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/scripts/cramfs/CVS/Entries linux-2.4-xfs/linux/scripts/cramfs/CVS/Entries --- linux-2.4.7/linux/scripts/cramfs/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/scripts/cramfs/CVS/Entries Thu Jul 5 12:08:12 2001 @@ -0,0 +1,3 @@ +/GNUmakefile/1.1/Fri Jan 21 19:20:14 2000/-ko/ +/mkcramfs.c/1.5/Mon Jul 31 16:16:28 2000/-ko/ +D diff -rNu linux-2.4.7/linux/scripts/cramfs/CVS/Repository linux-2.4-xfs/linux/scripts/cramfs/CVS/Repository --- linux-2.4.7/linux/scripts/cramfs/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/scripts/cramfs/CVS/Repository Thu Jul 5 12:08:12 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/scripts/cramfs diff -rNu linux-2.4.7/linux/scripts/cramfs/CVS/Root linux-2.4-xfs/linux/scripts/cramfs/CVS/Root --- linux-2.4.7/linux/scripts/cramfs/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/scripts/cramfs/CVS/Root Thu Jul 5 12:08:12 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/scripts/ksymoops/CVS/Entries linux-2.4-xfs/linux/scripts/ksymoops/CVS/Entries --- linux-2.4.7/linux/scripts/ksymoops/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/scripts/ksymoops/CVS/Entries Thu Jul 5 12:08:12 2001 @@ -0,0 +1,2 @@ +/README/1.4/Mon Oct 23 18:56:35 2000/-ko/ +D diff -rNu linux-2.4.7/linux/scripts/ksymoops/CVS/Repository linux-2.4-xfs/linux/scripts/ksymoops/CVS/Repository --- linux-2.4.7/linux/scripts/ksymoops/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/scripts/ksymoops/CVS/Repository Thu Jul 5 12:08:12 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/scripts/ksymoops diff -rNu linux-2.4.7/linux/scripts/ksymoops/CVS/Root linux-2.4-xfs/linux/scripts/ksymoops/CVS/Root --- linux-2.4.7/linux/scripts/ksymoops/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/scripts/ksymoops/CVS/Root Thu Jul 5 12:08:12 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs diff -rNu linux-2.4.7/linux/scripts/lxdialog/CVS/Entries linux-2.4-xfs/linux/scripts/lxdialog/CVS/Entries --- linux-2.4.7/linux/scripts/lxdialog/CVS/Entries Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/scripts/lxdialog/CVS/Entries Thu Jul 5 12:08:14 2001 @@ -0,0 +1,13 @@ +/BIG.FAT.WARNING/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/Makefile/1.4/Mon Jul 31 16:16:28 2000/-ko/ +/checklist.c/1.4/Wed May 2 06:22:13 2001/-ko/ +/colors.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/dialog.h/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/inputbox.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/lxdialog.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/menubox.c/1.3/Thu Feb 22 21:09:04 2001/-ko/ +/msgbox.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/textbox.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/util.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +/yesno.c/1.2/Fri Jun 25 17:32:48 1999/-ko/ +D diff -rNu linux-2.4.7/linux/scripts/lxdialog/CVS/Repository linux-2.4-xfs/linux/scripts/lxdialog/CVS/Repository --- linux-2.4.7/linux/scripts/lxdialog/CVS/Repository Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/scripts/lxdialog/CVS/Repository Thu Jul 5 12:08:12 2001 @@ -0,0 +1 @@ +linux-2.4-xfs/linux/scripts/lxdialog diff -rNu linux-2.4.7/linux/scripts/lxdialog/CVS/Root linux-2.4-xfs/linux/scripts/lxdialog/CVS/Root --- linux-2.4.7/linux/scripts/lxdialog/CVS/Root Wed Dec 31 18:00:00 1969 +++ linux-2.4-xfs/linux/scripts/lxdialog/CVS/Root Thu Jul 5 12:08:12 2001 @@ -0,0 +1 @@ +:pserver:cvs@oss.sgi.com:/cvs